OSDN Git Service

Initial Import
authorunknown <shira@.(none)>
Sun, 18 Sep 2011 13:35:19 +0000 (22:35 +0900)
committerunknown <shira@.(none)>
Sun, 18 Sep 2011 13:35:19 +0000 (22:35 +0900)
678 files changed:
Files [new file with mode: 0644]
Porting [new file with mode: 0644]
README [new file with mode: 0644]
binary/license [new file with mode: 0644]
build/dgncomp.dsp [new file with mode: 0644]
build/dgnstuff.dsp [new file with mode: 0644]
build/dgnstuff.mak [new file with mode: 0644]
build/dlb_main.dsp [new file with mode: 0644]
build/levcomp.dsp [new file with mode: 0644]
build/levstuff.dsp [new file with mode: 0644]
build/levstuff.mak [new file with mode: 0644]
build/makedefs.dsp [new file with mode: 0644]
build/nethackw.dsp [new file with mode: 0644]
build/recover.dsp [new file with mode: 0644]
build/tile2bmp.dsp [new file with mode: 0644]
build/tilemap.dsp [new file with mode: 0644]
build/tiles.dsp [new file with mode: 0644]
build/tiles.mak [new file with mode: 0644]
build/uudecode.dsp [new file with mode: 0644]
dat/Arch.des [new file with mode: 0644]
dat/Barb.des [new file with mode: 0644]
dat/Caveman.des [new file with mode: 0644]
dat/Healer.des [new file with mode: 0644]
dat/Knight.des [new file with mode: 0644]
dat/Monk.des [new file with mode: 0644]
dat/Priest.des [new file with mode: 0644]
dat/Ranger.des [new file with mode: 0644]
dat/Rogue.des [new file with mode: 0644]
dat/Samurai.des [new file with mode: 0644]
dat/Tourist.des [new file with mode: 0644]
dat/Valkyrie.des [new file with mode: 0644]
dat/Wizard.des [new file with mode: 0644]
dat/bigroom.des [new file with mode: 0644]
dat/castle.des [new file with mode: 0644]
dat/cmdhelp [new file with mode: 0644]
dat/data.base [new file with mode: 0644]
dat/dungeon.def [new file with mode: 0644]
dat/endgame.des [new file with mode: 0644]
dat/gehennom.des [new file with mode: 0644]
dat/help [new file with mode: 0644]
dat/hh [new file with mode: 0644]
dat/history [new file with mode: 0644]
dat/knox.des [new file with mode: 0644]
dat/license [new file with mode: 0644]
dat/medusa.des [new file with mode: 0644]
dat/mines.des [new file with mode: 0644]
dat/opthelp [new file with mode: 0644]
dat/oracle.des [new file with mode: 0644]
dat/oracles.txt [new file with mode: 0644]
dat/quest.txt [new file with mode: 0644]
dat/rumors.fal [new file with mode: 0644]
dat/rumors.tru [new file with mode: 0644]
dat/sokoban.des [new file with mode: 0644]
dat/tower.des [new file with mode: 0644]
dat/wizhelp [new file with mode: 0644]
dat/yendor.des [new file with mode: 0644]
doc/Guidebook.mn [new file with mode: 0644]
doc/Guidebook.tex [new file with mode: 0644]
doc/Guidebook.txt [new file with mode: 0644]
doc/dgn_comp.6 [new file with mode: 0644]
doc/dgn_comp.txt [new file with mode: 0644]
doc/dlb.6 [new file with mode: 0644]
doc/dlb.txt [new file with mode: 0644]
doc/fixes22.0 [new file with mode: 0644]
doc/fixes30.0 [new file with mode: 0644]
doc/fixes31.1 [new file with mode: 0644]
doc/fixes31.2 [new file with mode: 0644]
doc/fixes31.3 [new file with mode: 0644]
doc/fixes32.0 [new file with mode: 0644]
doc/fixes32.1 [new file with mode: 0644]
doc/fixes32.2 [new file with mode: 0644]
doc/fixes32.3 [new file with mode: 0644]
doc/fixes33.0 [new file with mode: 0644]
doc/fixes33.1 [new file with mode: 0644]
doc/fixes34.0 [new file with mode: 0644]
doc/fixes34.1 [new file with mode: 0644]
doc/fixes34.2 [new file with mode: 0644]
doc/fixes34.3 [new file with mode: 0644]
doc/lev_comp.6 [new file with mode: 0644]
doc/lev_comp.txt [new file with mode: 0644]
doc/nethack.6 [new file with mode: 0644]
doc/nethack.txt [new file with mode: 0644]
doc/recover.6 [new file with mode: 0644]
doc/recover.txt [new file with mode: 0644]
doc/tmac.n [new file with mode: 0644]
doc/window.doc [new file with mode: 0644]
include/align.h [new file with mode: 0644]
include/amiconf.h [new file with mode: 0644]
include/artifact.h [new file with mode: 0644]
include/artilist.h [new file with mode: 0644]
include/attrib.h [new file with mode: 0644]
include/beconf.h [new file with mode: 0644]
include/bitmfile.h [new file with mode: 0644]
include/color.h [new file with mode: 0644]
include/config.h [new file with mode: 0644]
include/config1.h [new file with mode: 0644]
include/coord.h [new file with mode: 0644]
include/decl.h [new file with mode: 0644]
include/def_os2.h [new file with mode: 0644]
include/dgn_file.h [new file with mode: 0644]
include/display.h [new file with mode: 0644]
include/dlb.h [new file with mode: 0644]
include/dungeon.h [new file with mode: 0644]
include/edog.h [new file with mode: 0644]
include/emin.h [new file with mode: 0644]
include/engrave.h [new file with mode: 0644]
include/epri.h [new file with mode: 0644]
include/eshk.h [new file with mode: 0644]
include/extern.h [new file with mode: 0644]
include/flag.h [new file with mode: 0644]
include/func_tab.h [new file with mode: 0644]
include/gem_rsc.h [new file with mode: 0644]
include/global.h [new file with mode: 0644]
include/hack.h [new file with mode: 0644]
include/lev.h [new file with mode: 0644]
include/load_img.h [new file with mode: 0644]
include/mac-carbon.h [new file with mode: 0644]
include/mac-qt.h [new file with mode: 0644]
include/mac-term.h [new file with mode: 0644]
include/macconf.h [new file with mode: 0644]
include/macpopup.h [new file with mode: 0644]
include/mactty.h [new file with mode: 0644]
include/macwin.h [new file with mode: 0644]
include/mail.h [new file with mode: 0644]
include/mfndpos.h [new file with mode: 0644]
include/micro.h [new file with mode: 0644]
include/mkroom.h [new file with mode: 0644]
include/monattk.h [new file with mode: 0644]
include/mondata.h [new file with mode: 0644]
include/monflag.h [new file with mode: 0644]
include/monst.h [new file with mode: 0644]
include/monsym.h [new file with mode: 0644]
include/mttypriv.h [new file with mode: 0644]
include/nhlan.h [new file with mode: 0644]
include/ntconf.h [new file with mode: 0644]
include/obj.h [new file with mode: 0644]
include/objclass.h [new file with mode: 0644]
include/os2conf.h [new file with mode: 0644]
include/patchlevel.h [new file with mode: 0644]
include/pcconf.h [new file with mode: 0644]
include/permonst.h [new file with mode: 0644]
include/prop.h [new file with mode: 0644]
include/qt_clust.h [new file with mode: 0644]
include/qt_kde0.h [new file with mode: 0644]
include/qt_win.h [new file with mode: 0644]
include/qt_xpms.h [new file with mode: 0644]
include/qtext.h [new file with mode: 0644]
include/qttableview.h [new file with mode: 0644]
include/quest.h [new file with mode: 0644]
include/rect.h [new file with mode: 0644]
include/region.h [new file with mode: 0644]
include/rm.h [new file with mode: 0644]
include/skills.h [new file with mode: 0644]
include/sp_lev.h [new file with mode: 0644]
include/spell.h [new file with mode: 0644]
include/system.h [new file with mode: 0644]
include/tcap.h [new file with mode: 0644]
include/tile2x11.h [new file with mode: 0644]
include/timeout.h [new file with mode: 0644]
include/tosconf.h [new file with mode: 0644]
include/tradstdc.h [new file with mode: 0644]
include/trampoli.h [new file with mode: 0644]
include/trap.h [new file with mode: 0644]
include/unixconf.h [new file with mode: 0644]
include/vault.h [new file with mode: 0644]
include/vision.h [new file with mode: 0644]
include/vmsconf.h [new file with mode: 0644]
include/wceconf.h [new file with mode: 0644]
include/winGnome.h [new file with mode: 0644]
include/winX.h [new file with mode: 0644]
include/winami.h [new file with mode: 0644]
include/wingem.h [new file with mode: 0644]
include/winprocs.h [new file with mode: 0644]
include/wintty.h [new file with mode: 0644]
include/wintype.h [new file with mode: 0644]
include/xwindow.h [new file with mode: 0644]
include/xwindowp.h [new file with mode: 0644]
include/you.h [new file with mode: 0644]
include/youprop.h [new file with mode: 0644]
nethack.dsw [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/Makefile.bcc [new file with mode: 0644]
src/Makefile.gcc [new file with mode: 0644]
src/allmain.c [new file with mode: 0644]
src/alloc.c [new file with mode: 0644]
src/apply.c [new file with mode: 0644]
src/artifact.c [new file with mode: 0644]
src/attrib.c [new file with mode: 0644]
src/ball.c [new file with mode: 0644]
src/bones.c [new file with mode: 0644]
src/botl.c [new file with mode: 0644]
src/cmd.c [new file with mode: 0644]
src/dbridge.c [new file with mode: 0644]
src/decl.c [new file with mode: 0644]
src/detect.c [new file with mode: 0644]
src/dig.c [new file with mode: 0644]
src/display.c [new file with mode: 0644]
src/dlb.c [new file with mode: 0644]
src/do.c [new file with mode: 0644]
src/do_name.c [new file with mode: 0644]
src/do_wear.c [new file with mode: 0644]
src/dog.c [new file with mode: 0644]
src/dogmove.c [new file with mode: 0644]
src/dokick.c [new file with mode: 0644]
src/dothrow.c [new file with mode: 0644]
src/drawing.c [new file with mode: 0644]
src/dungeon.c [new file with mode: 0644]
src/eat.c [new file with mode: 0644]
src/end.c [new file with mode: 0644]
src/engrave.c [new file with mode: 0644]
src/exper.c [new file with mode: 0644]
src/explode.c [new file with mode: 0644]
src/extralev.c [new file with mode: 0644]
src/files.c [new file with mode: 0644]
src/fountain.c [new file with mode: 0644]
src/hack.c [new file with mode: 0644]
src/hacklib.c [new file with mode: 0644]
src/invent.c [new file with mode: 0644]
src/light.c [new file with mode: 0644]
src/lock.c [new file with mode: 0644]
src/mail.c [new file with mode: 0644]
src/makemon.c [new file with mode: 0644]
src/mapglyph.c [new file with mode: 0644]
src/mcastu.c [new file with mode: 0644]
src/mhitm.c [new file with mode: 0644]
src/mhitu.c [new file with mode: 0644]
src/minion.c [new file with mode: 0644]
src/mklev.c [new file with mode: 0644]
src/mkmap.c [new file with mode: 0644]
src/mkmaze.c [new file with mode: 0644]
src/mkobj.c [new file with mode: 0644]
src/mkroom.c [new file with mode: 0644]
src/mon.c [new file with mode: 0644]
src/mondata.c [new file with mode: 0644]
src/monmove.c [new file with mode: 0644]
src/monst.c [new file with mode: 0644]
src/mplayer.c [new file with mode: 0644]
src/mthrowu.c [new file with mode: 0644]
src/muse.c [new file with mode: 0644]
src/music.c [new file with mode: 0644]
src/o_init.c [new file with mode: 0644]
src/objects.c [new file with mode: 0644]
src/objnam.c [new file with mode: 0644]
src/options.c [new file with mode: 0644]
src/pager.c [new file with mode: 0644]
src/pickup.c [new file with mode: 0644]
src/pline.c [new file with mode: 0644]
src/polyself.c [new file with mode: 0644]
src/potion.c [new file with mode: 0644]
src/pray.c [new file with mode: 0644]
src/priest.c [new file with mode: 0644]
src/quest.c [new file with mode: 0644]
src/questpgr.c [new file with mode: 0644]
src/read.c [new file with mode: 0644]
src/rect.c [new file with mode: 0644]
src/region.c [new file with mode: 0644]
src/restore.c [new file with mode: 0644]
src/rip.c [new file with mode: 0644]
src/rnd.c [new file with mode: 0644]
src/role.c [new file with mode: 0644]
src/rumors.c [new file with mode: 0644]
src/save.c [new file with mode: 0644]
src/shk.c [new file with mode: 0644]
src/shknam.c [new file with mode: 0644]
src/sit.c [new file with mode: 0644]
src/sounds.c [new file with mode: 0644]
src/sp_lev.c [new file with mode: 0644]
src/spell.c [new file with mode: 0644]
src/steal.c [new file with mode: 0644]
src/steed.c [new file with mode: 0644]
src/teleport.c [new file with mode: 0644]
src/timeout.c [new file with mode: 0644]
src/topten.c [new file with mode: 0644]
src/track.c [new file with mode: 0644]
src/trap.c [new file with mode: 0644]
src/u_init.c [new file with mode: 0644]
src/uhitm.c [new file with mode: 0644]
src/vault.c [new file with mode: 0644]
src/version.c [new file with mode: 0644]
src/vision.c [new file with mode: 0644]
src/weapon.c [new file with mode: 0644]
src/were.c [new file with mode: 0644]
src/wield.c [new file with mode: 0644]
src/windows.c [new file with mode: 0644]
src/wizard.c [new file with mode: 0644]
src/worm.c [new file with mode: 0644]
src/worn.c [new file with mode: 0644]
src/write.c [new file with mode: 0644]
src/zap.c [new file with mode: 0644]
sys/amiga/Build.ami [new file with mode: 0644]
sys/amiga/Install.ami [new file with mode: 0644]
sys/amiga/Makefile.agc [new file with mode: 0644]
sys/amiga/Makefile.ami [new file with mode: 0644]
sys/amiga/NetHack.cnf [new file with mode: 0644]
sys/amiga/amidos.c [new file with mode: 0644]
sys/amiga/amidos.p [new file with mode: 0644]
sys/amiga/amifont.uu [new file with mode: 0644]
sys/amiga/amifont8.uu [new file with mode: 0644]
sys/amiga/amigst.c [new file with mode: 0644]
sys/amiga/amii.hlp [new file with mode: 0644]
sys/amiga/amimenu.c [new file with mode: 0644]
sys/amiga/amirip.c [new file with mode: 0644]
sys/amiga/amisnd.c [new file with mode: 0644]
sys/amiga/amistack.c [new file with mode: 0644]
sys/amiga/amitty.c [new file with mode: 0644]
sys/amiga/amiwind.c [new file with mode: 0644]
sys/amiga/amiwind.p [new file with mode: 0644]
sys/amiga/clipwin.c [new file with mode: 0644]
sys/amiga/colorwin.c [new file with mode: 0644]
sys/amiga/cvtsnd.c [new file with mode: 0644]
sys/amiga/grave16.xpm [new file with mode: 0644]
sys/amiga/ifchange [new file with mode: 0644]
sys/amiga/mkdmake [new file with mode: 0644]
sys/amiga/txt2iff.c [new file with mode: 0644]
sys/amiga/winami.c [new file with mode: 0644]
sys/amiga/winami.p [new file with mode: 0644]
sys/amiga/winchar.c [new file with mode: 0644]
sys/amiga/windefs.h [new file with mode: 0644]
sys/amiga/winext.h [new file with mode: 0644]
sys/amiga/winfuncs.c [new file with mode: 0644]
sys/amiga/winkey.c [new file with mode: 0644]
sys/amiga/winmenu.c [new file with mode: 0644]
sys/amiga/winproto.h [new file with mode: 0644]
sys/amiga/winreq.c [new file with mode: 0644]
sys/amiga/winstr.c [new file with mode: 0644]
sys/amiga/xpm2iff.c [new file with mode: 0644]
sys/atari/Install.tos [new file with mode: 0644]
sys/atari/atarifnt.uue [new file with mode: 0644]
sys/atari/nethack.mnu [new file with mode: 0644]
sys/atari/setup.g [new file with mode: 0644]
sys/atari/tos.c [new file with mode: 0644]
sys/atari/unx2atar.sed [new file with mode: 0644]
sys/be/README [new file with mode: 0644]
sys/be/bemain.c [new file with mode: 0644]
sys/mac/Files.r [new file with mode: 0644]
sys/mac/Install.mw [new file with mode: 0644]
sys/mac/MacHelp [new file with mode: 0644]
sys/mac/NHDeflts [new file with mode: 0644]
sys/mac/NHrsrc.hqx [new file with mode: 0644]
sys/mac/NHsound.hqx [new file with mode: 0644]
sys/mac/News [new file with mode: 0644]
sys/mac/README [new file with mode: 0644]
sys/mac/dprintf.c [new file with mode: 0644]
sys/mac/maccurs.c [new file with mode: 0644]
sys/mac/macerrs.c [new file with mode: 0644]
sys/mac/macfile.c [new file with mode: 0644]
sys/mac/machelp.hqx [new file with mode: 0644]
sys/mac/macmain.c [new file with mode: 0644]
sys/mac/macmenu.c [new file with mode: 0644]
sys/mac/macsnd.c [new file with mode: 0644]
sys/mac/mactopl.c [new file with mode: 0644]
sys/mac/mactty.c [new file with mode: 0644]
sys/mac/macunix.c [new file with mode: 0644]
sys/mac/macwin.c [new file with mode: 0644]
sys/mac/mgetline.c [new file with mode: 0644]
sys/mac/mmodal.c [new file with mode: 0644]
sys/mac/mrecover.c [new file with mode: 0644]
sys/mac/mrecover.hqx [new file with mode: 0644]
sys/mac/mttymain.c [new file with mode: 0644]
sys/msdos/Install.dos [new file with mode: 0644]
sys/msdos/Makefile.BC [new file with mode: 0644]
sys/msdos/Makefile.GCC [new file with mode: 0644]
sys/msdos/Makefile.MSC [new file with mode: 0644]
sys/msdos/NHAccess.nh [new file with mode: 0644]
sys/msdos/moveinit.pat [new file with mode: 0644]
sys/msdos/msdos.c [new file with mode: 0644]
sys/msdos/msdoshlp.txt [new file with mode: 0644]
sys/msdos/nhico.uu [new file with mode: 0644]
sys/msdos/nhpif.uu [new file with mode: 0644]
sys/msdos/ovlinit.c [new file with mode: 0644]
sys/msdos/pckeys.c [new file with mode: 0644]
sys/msdos/pctiles.c [new file with mode: 0644]
sys/msdos/pctiles.h [new file with mode: 0644]
sys/msdos/pcvideo.h [new file with mode: 0644]
sys/msdos/portio.h [new file with mode: 0644]
sys/msdos/schema1.BC [new file with mode: 0644]
sys/msdos/schema2.BC [new file with mode: 0644]
sys/msdos/schema3.MSC [new file with mode: 0644]
sys/msdos/setup.bat [new file with mode: 0644]
sys/msdos/sound.c [new file with mode: 0644]
sys/msdos/tile2bin.c [new file with mode: 0644]
sys/msdos/video.c [new file with mode: 0644]
sys/msdos/vidtxt.c [new file with mode: 0644]
sys/msdos/vidvga.c [new file with mode: 0644]
sys/os2/Install.os2 [new file with mode: 0644]
sys/os2/Makefile.os2 [new file with mode: 0644]
sys/os2/nhpmico.uu [new file with mode: 0644]
sys/os2/os2.c [new file with mode: 0644]
sys/share/Makefile.lib [new file with mode: 0644]
sys/share/NetHack.cnf [new file with mode: 0644]
sys/share/dgn_comp.h [new file with mode: 0644]
sys/share/dgn_lex.c [new file with mode: 0644]
sys/share/dgn_yacc.c [new file with mode: 0644]
sys/share/ioctl.c [new file with mode: 0644]
sys/share/lev_comp.h [new file with mode: 0644]
sys/share/lev_lex.c [new file with mode: 0644]
sys/share/lev_yacc.c [new file with mode: 0644]
sys/share/nhlan.c [new file with mode: 0644]
sys/share/pcmain.c [new file with mode: 0644]
sys/share/pcsys.c [new file with mode: 0644]
sys/share/pctty.c [new file with mode: 0644]
sys/share/pcunix.c [new file with mode: 0644]
sys/share/random.c [new file with mode: 0644]
sys/share/sounds/README [new file with mode: 0644]
sys/share/sounds/bell.uu [new file with mode: 0644]
sys/share/sounds/bugle.uu [new file with mode: 0644]
sys/share/sounds/erthdrum.uu [new file with mode: 0644]
sys/share/sounds/firehorn.uu [new file with mode: 0644]
sys/share/sounds/frsthorn.uu [new file with mode: 0644]
sys/share/sounds/lethdrum.uu [new file with mode: 0644]
sys/share/sounds/mgcflute.uu [new file with mode: 0644]
sys/share/sounds/mgcharp.uu [new file with mode: 0644]
sys/share/sounds/toolhorn.uu [new file with mode: 0644]
sys/share/sounds/wdnflute.uu [new file with mode: 0644]
sys/share/sounds/wdnharp.uu [new file with mode: 0644]
sys/share/tclib.c [new file with mode: 0644]
sys/share/termcap [new file with mode: 0644]
sys/share/termcap.uu [new file with mode: 0644]
sys/share/unixtty.c [new file with mode: 0644]
sys/share/uudecode.c [new file with mode: 0644]
sys/unix/Install.unx [new file with mode: 0644]
sys/unix/Makefile.dat [new file with mode: 0644]
sys/unix/Makefile.doc [new file with mode: 0644]
sys/unix/Makefile.src [new file with mode: 0644]
sys/unix/Makefile.top [new file with mode: 0644]
sys/unix/Makefile.utl [new file with mode: 0644]
sys/unix/README.linux [new file with mode: 0644]
sys/unix/cpp1.shr [new file with mode: 0644]
sys/unix/cpp2.shr [new file with mode: 0644]
sys/unix/cpp3.shr [new file with mode: 0644]
sys/unix/depend.awk [new file with mode: 0644]
sys/unix/nethack.sh [new file with mode: 0644]
sys/unix/setup.sh [new file with mode: 0644]
sys/unix/snd86unx.shr [new file with mode: 0644]
sys/unix/unixmain.c [new file with mode: 0644]
sys/unix/unixres.c [new file with mode: 0644]
sys/unix/unixunix.c [new file with mode: 0644]
sys/vms/Install.vms [new file with mode: 0644]
sys/vms/Makefile.dat [new file with mode: 0644]
sys/vms/Makefile.doc [new file with mode: 0644]
sys/vms/Makefile.src [new file with mode: 0644]
sys/vms/Makefile.top [new file with mode: 0644]
sys/vms/Makefile.utl [new file with mode: 0644]
sys/vms/install.com [new file with mode: 0644]
sys/vms/lev_lex.h [new file with mode: 0644]
sys/vms/nethack.com [new file with mode: 0644]
sys/vms/oldcrtl.c [new file with mode: 0644]
sys/vms/spec_lev.com [new file with mode: 0644]
sys/vms/vmsbuild.com [new file with mode: 0644]
sys/vms/vmsfiles.c [new file with mode: 0644]
sys/vms/vmsmail.c [new file with mode: 0644]
sys/vms/vmsmain.c [new file with mode: 0644]
sys/vms/vmsmisc.c [new file with mode: 0644]
sys/vms/vmstty.c [new file with mode: 0644]
sys/vms/vmsunix.c [new file with mode: 0644]
sys/wince/Install.ce [new file with mode: 0644]
sys/wince/bootstrp.mak [new file with mode: 0644]
sys/wince/ceinc/assert.h [new file with mode: 0644]
sys/wince/ceinc/errno.h [new file with mode: 0644]
sys/wince/ceinc/fcntl.h [new file with mode: 0644]
sys/wince/ceinc/sys/stat.h [new file with mode: 0644]
sys/wince/celib.c [new file with mode: 0644]
sys/wince/cesetup.bat [new file with mode: 0644]
sys/wince/cesound.c [new file with mode: 0644]
sys/wince/defaults.nh [new file with mode: 0644]
sys/wince/keypad.uu [new file with mode: 0644]
sys/wince/menubar.uu [new file with mode: 0644]
sys/wince/mhaskyn.c [new file with mode: 0644]
sys/wince/mhaskyn.h [new file with mode: 0644]
sys/wince/mhcmd.c [new file with mode: 0644]
sys/wince/mhcmd.h [new file with mode: 0644]
sys/wince/mhcolor.c [new file with mode: 0644]
sys/wince/mhcolor.h [new file with mode: 0644]
sys/wince/mhdlg.c [new file with mode: 0644]
sys/wince/mhdlg.h [new file with mode: 0644]
sys/wince/mhfont.c [new file with mode: 0644]
sys/wince/mhfont.h [new file with mode: 0644]
sys/wince/mhinput.c [new file with mode: 0644]
sys/wince/mhinput.h [new file with mode: 0644]
sys/wince/mhmain.c [new file with mode: 0644]
sys/wince/mhmain.h [new file with mode: 0644]
sys/wince/mhmap.c [new file with mode: 0644]
sys/wince/mhmap.h [new file with mode: 0644]
sys/wince/mhmenu.c [new file with mode: 0644]
sys/wince/mhmenu.h [new file with mode: 0644]
sys/wince/mhmsg.h [new file with mode: 0644]
sys/wince/mhmsgwnd.c [new file with mode: 0644]
sys/wince/mhmsgwnd.h [new file with mode: 0644]
sys/wince/mhrip.c [new file with mode: 0644]
sys/wince/mhrip.h [new file with mode: 0644]
sys/wince/mhstatus.c [new file with mode: 0644]
sys/wince/mhstatus.h [new file with mode: 0644]
sys/wince/mhtext.c [new file with mode: 0644]
sys/wince/mhtext.h [new file with mode: 0644]
sys/wince/mhtxtbuf.c [new file with mode: 0644]
sys/wince/mhtxtbuf.h [new file with mode: 0644]
sys/wince/mswproc.c [new file with mode: 0644]
sys/wince/newres.h [new file with mode: 0644]
sys/wince/resource.h [new file with mode: 0644]
sys/wince/winMS.h [new file with mode: 0644]
sys/wince/winhack.c [new file with mode: 0644]
sys/wince/winhack.rc [new file with mode: 0644]
sys/wince/winhcksp.rc [new file with mode: 0644]
sys/wince/winmain.c [new file with mode: 0644]
sys/winnt/Install.nt [new file with mode: 0644]
sys/winnt/Makefile.bcc [new file with mode: 0644]
sys/winnt/Makefile.gcc [new file with mode: 0644]
sys/winnt/Makefile.msc [new file with mode: 0644]
sys/winnt/console.rc [new file with mode: 0644]
sys/winnt/defaults.nh [new file with mode: 0644]
sys/winnt/mapimail.c [new file with mode: 0644]
sys/winnt/nethack.def [new file with mode: 0644]
sys/winnt/nh340key.c [new file with mode: 0644]
sys/winnt/nhdefkey.c [new file with mode: 0644]
sys/winnt/nhico.uu [new file with mode: 0644]
sys/winnt/nhraykey.c [new file with mode: 0644]
sys/winnt/nhsetup.bat [new file with mode: 0644]
sys/winnt/ntsound.c [new file with mode: 0644]
sys/winnt/nttty.c [new file with mode: 0644]
sys/winnt/porthelp [new file with mode: 0644]
sys/winnt/win32api.h [new file with mode: 0644]
sys/winnt/winnt.c [new file with mode: 0644]
util/dgn_comp.l [new file with mode: 0644]
util/dgn_comp.y [new file with mode: 0644]
util/dgn_main.c [new file with mode: 0644]
util/dlb_main.c [new file with mode: 0644]
util/lev_comp.l [new file with mode: 0644]
util/lev_comp.y [new file with mode: 0644]
util/lev_main.c [new file with mode: 0644]
util/makedefs.c [new file with mode: 0644]
util/panic.c [new file with mode: 0644]
util/recover.c [new file with mode: 0644]
win/Qt/Info.plist [new file with mode: 0644]
win/Qt/Install.Qt [new file with mode: 0644]
win/Qt/knethack.lnk [new file with mode: 0644]
win/Qt/knh-mini.xpm [new file with mode: 0644]
win/Qt/knh.xpm [new file with mode: 0644]
win/Qt/nhicns.uu [new file with mode: 0644]
win/Qt/nhsplash.xpm [new file with mode: 0644]
win/Qt/qpe-nethack.control [new file with mode: 0644]
win/Qt/qt_clust.cpp [new file with mode: 0644]
win/Qt/qt_win.cpp [new file with mode: 0644]
win/Qt/qttableview.cpp [new file with mode: 0644]
win/Qt/tileedit.cpp [new file with mode: 0644]
win/Qt/tileedit.h [new file with mode: 0644]
win/X11/Install.X11 [new file with mode: 0644]
win/X11/NetHack.ad [new file with mode: 0644]
win/X11/Window.c [new file with mode: 0644]
win/X11/dialogs.c [new file with mode: 0644]
win/X11/ibm.bdf [new file with mode: 0644]
win/X11/nethack.rc [new file with mode: 0644]
win/X11/nh10.bdf [new file with mode: 0644]
win/X11/nh32icon [new file with mode: 0644]
win/X11/nh56icon [new file with mode: 0644]
win/X11/nh72icon [new file with mode: 0644]
win/X11/nh_icon.xpm [new file with mode: 0644]
win/X11/pet_mark.xbm [new file with mode: 0644]
win/X11/rip.xpm [new file with mode: 0644]
win/X11/tile2x11.c [new file with mode: 0644]
win/X11/winX.c [new file with mode: 0644]
win/X11/winmap.c [new file with mode: 0644]
win/X11/winmenu.c [new file with mode: 0644]
win/X11/winmesg.c [new file with mode: 0644]
win/X11/winmisc.c [new file with mode: 0644]
win/X11/winstat.c [new file with mode: 0644]
win/X11/wintext.c [new file with mode: 0644]
win/X11/winval.c [new file with mode: 0644]
win/gem/Install.gem [new file with mode: 0644]
win/gem/bitmfile.c [new file with mode: 0644]
win/gem/gem_rsc.uu [new file with mode: 0644]
win/gem/gem_rso.uu [new file with mode: 0644]
win/gem/gr_rect.c [new file with mode: 0644]
win/gem/gr_rect.h [new file with mode: 0644]
win/gem/load_img.c [new file with mode: 0644]
win/gem/tile2img.c [new file with mode: 0644]
win/gem/title.uu [new file with mode: 0644]
win/gem/wingem.c [new file with mode: 0644]
win/gem/wingem1.c [new file with mode: 0644]
win/gem/xpm2img.c [new file with mode: 0644]
win/gnome/README [new file with mode: 0644]
win/gnome/gn_xpms.h [new file with mode: 0644]
win/gnome/gnaskstr.c [new file with mode: 0644]
win/gnome/gnaskstr.h [new file with mode: 0644]
win/gnome/gnbind.c [new file with mode: 0644]
win/gnome/gnbind.h [new file with mode: 0644]
win/gnome/gnglyph.c [new file with mode: 0644]
win/gnome/gnglyph.h [new file with mode: 0644]
win/gnome/gnmain.c [new file with mode: 0644]
win/gnome/gnmain.h [new file with mode: 0644]
win/gnome/gnmap.c [new file with mode: 0644]
win/gnome/gnmap.h [new file with mode: 0644]
win/gnome/gnmenu.c [new file with mode: 0644]
win/gnome/gnmenu.h [new file with mode: 0644]
win/gnome/gnmesg.c [new file with mode: 0644]
win/gnome/gnmesg.h [new file with mode: 0644]
win/gnome/gnomeprv.h [new file with mode: 0644]
win/gnome/gnopts.c [new file with mode: 0644]
win/gnome/gnopts.h [new file with mode: 0644]
win/gnome/gnplayer.c [new file with mode: 0644]
win/gnome/gnplayer.h [new file with mode: 0644]
win/gnome/gnsignal.c [new file with mode: 0644]
win/gnome/gnsignal.h [new file with mode: 0644]
win/gnome/gnstatus.c [new file with mode: 0644]
win/gnome/gnstatus.h [new file with mode: 0644]
win/gnome/gntext.c [new file with mode: 0644]
win/gnome/gntext.h [new file with mode: 0644]
win/gnome/gnworn.c [new file with mode: 0644]
win/gnome/gnworn.h [new file with mode: 0644]
win/gnome/gnyesno.c [new file with mode: 0644]
win/gnome/gnyesno.h [new file with mode: 0644]
win/gnome/mapbg.xpm [new file with mode: 0644]
win/share/gifread.c [new file with mode: 0644]
win/share/monsters.txt [new file with mode: 0644]
win/share/objects.txt [new file with mode: 0644]
win/share/other.txt [new file with mode: 0644]
win/share/ppmwrite.c [new file with mode: 0644]
win/share/thintile.c [new file with mode: 0644]
win/share/tile.doc [new file with mode: 0644]
win/share/tile.h [new file with mode: 0644]
win/share/tile2bmp.c [new file with mode: 0644]
win/share/tilemap.c [new file with mode: 0644]
win/share/tiletext.c [new file with mode: 0644]
win/tty/getline.c [new file with mode: 0644]
win/tty/termcap.c [new file with mode: 0644]
win/tty/topl.c [new file with mode: 0644]
win/tty/wintty.c [new file with mode: 0644]
win/win32/dgncomp.dsp [new file with mode: 0644]
win/win32/dgnstuff.dsp [new file with mode: 0644]
win/win32/dgnstuff.mak [new file with mode: 0644]
win/win32/dlb_main.dsp [new file with mode: 0644]
win/win32/levcomp.dsp [new file with mode: 0644]
win/win32/levstuff.dsp [new file with mode: 0644]
win/win32/levstuff.mak [new file with mode: 0644]
win/win32/makedefs.dsp [new file with mode: 0644]
win/win32/mhaskyn.c [new file with mode: 0644]
win/win32/mhaskyn.h [new file with mode: 0644]
win/win32/mhdlg.c [new file with mode: 0644]
win/win32/mhdlg.h [new file with mode: 0644]
win/win32/mhfont.c [new file with mode: 0644]
win/win32/mhfont.h [new file with mode: 0644]
win/win32/mhinput.c [new file with mode: 0644]
win/win32/mhinput.h [new file with mode: 0644]
win/win32/mhmain.c [new file with mode: 0644]
win/win32/mhmain.h [new file with mode: 0644]
win/win32/mhmap.c [new file with mode: 0644]
win/win32/mhmap.h [new file with mode: 0644]
win/win32/mhmenu.c [new file with mode: 0644]
win/win32/mhmenu.h [new file with mode: 0644]
win/win32/mhmsg.h [new file with mode: 0644]
win/win32/mhmsgwnd.c [new file with mode: 0644]
win/win32/mhmsgwnd.h [new file with mode: 0644]
win/win32/mhrip.c [new file with mode: 0644]
win/win32/mhrip.h [new file with mode: 0644]
win/win32/mhsplash.c [new file with mode: 0644]
win/win32/mhsplash.h [new file with mode: 0644]
win/win32/mhstatus.c [new file with mode: 0644]
win/win32/mhstatus.h [new file with mode: 0644]
win/win32/mhtext.c [new file with mode: 0644]
win/win32/mhtext.h [new file with mode: 0644]
win/win32/mnsel.uu [new file with mode: 0644]
win/win32/mnselcnt.uu [new file with mode: 0644]
win/win32/mnunsel.uu [new file with mode: 0644]
win/win32/mswproc.c [new file with mode: 0644]
win/win32/nethack.dsw [new file with mode: 0644]
win/win32/nethackw.dsp [new file with mode: 0644]
win/win32/petmark.uu [new file with mode: 0644]
win/win32/recover.dsp [new file with mode: 0644]
win/win32/resource.h [new file with mode: 0644]
win/win32/rip.uu [new file with mode: 0644]
win/win32/splash.uu [new file with mode: 0644]
win/win32/tile2bmp.dsp [new file with mode: 0644]
win/win32/tilemap.dsp [new file with mode: 0644]
win/win32/tiles.dsp [new file with mode: 0644]
win/win32/tiles.mak [new file with mode: 0644]
win/win32/uudecode.dsp [new file with mode: 0644]
win/win32/winMS.h [new file with mode: 0644]
win/win32/winhack.c [new file with mode: 0644]
win/win32/winhack.rc [new file with mode: 0644]

diff --git a/Files b/Files
new file mode 100644 (file)
index 0000000..1c1fdd9
--- /dev/null
+++ b/Files
@@ -0,0 +1,319 @@
+This is a listing of all files in a full NetHack 3.4 distribution, organized
+in their standard manner on a UNIX system.  It indicates which files are
+necessary for which versions, so that you can tell which files may be deleted
+from or not transferred to your system if you wish.
+
+
+.:
+(files in top directory)
+Files           Porting         README
+
+dat:
+(files for all versions)
+Arch.des        Barb.des        Caveman.des     Healer.des      Knight.des
+Monk.des        Priest.des      Ranger.des      Rogue.des       Samurai.des
+Tourist.des     Valkyrie.des    Wizard.des      bigroom.des     castle.des
+cmdhelp         data.base       dungeon.def     endgame.des     gehennom.des
+help            hh              history         knox.des        license
+medusa.des      mines.des       opthelp         oracle.des      oracles.txt
+quest.txt       rumors.fal      rumors.tru      sokoban.des     tower.des
+wizhelp         yendor.des
+
+doc:
+(files for all versions)
+Guidebook.mn    Guidebook.tex   Guidebook.txt   dgn_comp.6      dgn_comp.txt
+dlb.6           dlb.txt         fixes22.0       fixes30.0       fixes31.1
+fixes31.2       fixes31.3       fixes32.0       fixes32.1       fixes32.2
+fixes32.3       fixes33.0       fixes33.1       fixes34.0       fixes34.1
+fixes34.2       fixes34.3       lev_comp.6      lev_comp.txt    nethack.6
+nethack.txt     recover.6       recover.txt     tmac.n          window.doc
+
+include:
+(files for all versions)
+align.h         amiconf.h       artifact.h      artilist.h      attrib.h
+beconf.h        color.h         config.h        config1.h       coord.h
+decl.h          def_os2.h       dgn_file.h      display.h       dlb.h
+dungeon.h       edog.h          emin.h          engrave.h       epri.h
+eshk.h          extern.h        flag.h          func_tab.h      global.h
+hack.h          lev.h           mail.h          mfndpos.h       micro.h
+mkroom.h        monattk.h       mondata.h       monflag.h       monst.h
+monsym.h        nhlan.h         ntconf.h        obj.h           objclass.h
+os2conf.h       patchlevel.h    pcconf.h        permonst.h      prop.h
+qtext.h         quest.h         rect.h          region.h        rm.h
+skills.h        sp_lev.h        spell.h         system.h        tcap.h
+timeout.h       tosconf.h       tradstdc.h      trampoli.h      trap.h
+unixconf.h      vault.h         vision.h        vmsconf.h       wceconf.h
+winami.h        winprocs.h      wintype.h       you.h           youprop.h
+(file for tty versions)
+wintty.h
+(files for X versions)
+tile2x11.h      winX.h          xwindow.h       xwindowp.h
+(files for Qt versions)
+qt_clust.h      qt_kde0.h       qt_win.h        qt_xpms.h       qttableview.h
+(files for Gem versions)
+bitmfile.h      gem_rsc.h       load_img.h      wingem.h
+(file for GNOME versions)
+winGnome.h
+(files for various Macintosh versions)
+mac-carbon.h    mac-qt.h        mac-term.h      macconf.h       macpopup.h
+mactty.h        macwin.h        mttypriv.h
+
+src:
+(files for all versions)
+allmain.c       alloc.c         apply.c         artifact.c      attrib.c
+ball.c          bones.c         botl.c          cmd.c           dbridge.c
+decl.c          detect.c        dig.c           display.c       dlb.c
+do.c            do_name.c       do_wear.c       dog.c           dogmove.c
+dokick.c        dothrow.c       drawing.c       dungeon.c       eat.c
+end.c           engrave.c       exper.c         explode.c       extralev.c
+files.c         fountain.c      hack.c          hacklib.c       invent.c
+light.c         lock.c          mail.c          makemon.c       mapglyph.c
+mcastu.c        mhitm.c         mhitu.c         minion.c        mklev.c
+mkmap.c         mkmaze.c        mkobj.c         mkroom.c        mon.c
+mondata.c       monmove.c       monst.c         mplayer.c       mthrowu.c
+muse.c          music.c         o_init.c        objects.c       objnam.c
+options.c       pager.c         pickup.c        pline.c         polyself.c
+potion.c        pray.c          priest.c        quest.c         questpgr.c
+read.c          rect.c          region.c        restore.c       rip.c
+rnd.c           role.c          rumors.c        save.c          shk.c
+shknam.c        sit.c           sounds.c        sp_lev.c        spell.c
+steal.c         steed.c         teleport.c      timeout.c       topten.c
+track.c         trap.c          u_init.c        uhitm.c         vault.c
+version.c       vision.c        weapon.c        were.c          wield.c
+windows.c       wizard.c        worm.c          worn.c          write.c
+zap.c
+
+sys/amiga:
+(files for Amiga versions)
+Build.ami       Install.ami     Makefile.agc    Makefile.ami    NetHack.cnf
+amidos.c        amidos.p        amifont.uu      amifont8.uu     amigst.c
+amii.hlp        amimenu.c       amirip.c        amisnd.c        amistack.c
+amitty.c        amiwind.c       amiwind.p       clipwin.c       colorwin.c
+cvtsnd.c        grave16.xpm     ifchange        mkdmake         txt2iff.c
+winami.c        winami.p        winchar.c       windefs.h       winext.h
+winfuncs.c      winkey.c        winmenu.c       winproto.h      winreq.c
+winstr.c        xpm2iff.c
+
+sys/atari:
+(files for Atari version)
+Install.tos     atarifnt.uue    nethack.mnu     setup.g         tos.c
+unx2atar.sed
+
+sys/be:
+(files for BeOS version)
+README          bemain.c
+
+sys/mac:
+(files for Macintosh versions)
+Files.r         Install.mw      MacHelp         NHDeflts        NHrsrc.hqx
+NHsound.hqx     News            README          dprintf.c       maccurs.c
+macerrs.c       macfile.c       machelp.hqx     macmain.c       macmenu.c
+macsnd.c        mactopl.c       mactty.c        macunix.c       macwin.c
+mgetline.c      mmodal.c        mrecover.c      mrecover.hqx    mttymain.c
+
+sys/msdos:
+(files for MSDOS version)
+Install.dos     Makefile.BC     Makefile.GCC    Makefile.MSC    NHAccess.nh
+moveinit.pat    msdos.c         msdoshlp.txt    ovlinit.c       pckeys.c
+pctiles.c       pctiles.h       pcvideo.h       portio.h        schema1.BC
+schema2.BC      schema3.MSC     setup.bat       sound.c         tile2bin.c
+video.c         vidtxt.c        vidvga.c
+(files for running MSDOS binary under Windows)
+nhico.uu        nhpif.uu
+
+sys/os2:
+(files for OS/2 version)
+Install.os2     Makefile.os2    nhpmico.uu      os2.c
+
+sys/share:
+(files for MSDOS and OS/2 versions)
+Makefile.lib    termcap.uu
+(file for MSDOS, OS/2, NT, Amiga, and Atari versions)
+pcmain.c
+(files for MSDOS, OS/2, NT, and Atari versions)
+pcsys.c         pcunix.c
+(file for MSDOS, OS/2, and Atari versions)
+NetHack.cnf     pctty.c
+(files for UNIX and Be versions)
+ioctl.c         unixtty.c
+(file for NT version)
+nhlan.c
+(Berkeley random number file, which may be included in any version)
+random.c
+(Berkeley uudecode file, which may be used in build process of any version)
+uudecode.c
+(file for VMS version)
+tclib.c
+(file for MSDOS, OS/2, and VMS versions)
+termcap
+(lex/yacc output for special level and dungeon compilers)
+dgn_comp.h      dgn_lex.c       dgn_yacc.c      lev_comp.h      lev_lex.c
+lev_yacc.c
+
+sys/share/sounds:
+(files for Amiga and Macintosh versions)
+README          bell.uu         bugle.uu        erthdrum.uu     firehorn.uu
+frsthorn.uu     lethdrum.uu     mgcflute.uu     mgcharp.uu      toolhorn.uu
+wdnflute.uu     wdnharp.uu
+
+sys/unix:
+(files for UNIX versions)
+Install.unx     Makefile.dat    Makefile.doc    Makefile.src    Makefile.top
+Makefile.utl    README.linux    depend.awk      nethack.sh      setup.sh
+unixmain.c      unixres.c       unixunix.c
+(files for replacement cpp, apparently only needed by some UNIX systems)
+cpp1.shr        cpp2.shr        cpp3.shr
+(file for sound driver for 386 UNIX)
+snd86unx.shr
+
+sys/vms:
+(files for VMS version)
+Install.vms     Makefile.dat    Makefile.doc    Makefile.src    Makefile.top
+Makefile.utl    install.com     lev_lex.h       nethack.com     oldcrtl.c
+spec_lev.com    vmsbuild.com    vmsfiles.c      vmsmail.c       vmsmain.c
+vmsmisc.c       vmstty.c        vmsunix.c
+
+sys/wince:
+(files for Windows CE and PocketPC)
+Install.ce      bootstrp.mak    celib.c         cesetup.bat     cesound.c
+defaults.nh     keypad.uu       menubar.uu      mhaskyn.c       mhaskyn.h
+mhcmd.c         mhcmd.h         mhcolor.c       mhcolor.h       mhdlg.c
+mhdlg.h         mhfont.c        mhfont.h        mhinput.c       mhinput.h
+mhmain.c        mhmain.h        mhmap.c         mhmap.h         mhmenu.c
+mhmenu.h        mhmsg.h         mhmsgwnd.c      mhmsgwnd.h      mhrip.c
+mhrip.h         mhstatus.c      mhstatus.h      mhtext.c        mhtext.h
+mhtxtbuf.c      mhtxtbuf.h      mswproc.c       newres.h        resource.h
+winMS.h         winhack.c       winhack.rc      winhcksp.rc     winmain.c
+
+sys/wince/ceinc:
+(header files for Windows CE and PocketPC)
+assert.h        errno.h         fcntl.h
+
+sys/wince/ceinc/sys:
+(sys/stat.h for Windows CE and PocketPC)
+stat.h
+
+sys/winnt:
+(files for Windows 9x, NT and Windows2000 version)
+Install.nt      Makefile.bcc    Makefile.gcc    Makefile.msc    console.rc
+defaults.nh     mapimail.c      nethack.def     nh340key.c      nhdefkey.c
+nhico.uu        nhraykey.c      nhsetup.bat     ntsound.c       nttty.c
+porthelp        win32api.h      winnt.c
+
+util:
+(files for all versions)
+dgn_main.c      dlb_main.c      lev_main.c      makedefs.c      panic.c
+recover.c
+(lex/yacc input for special level and dungeon compilers)
+dgn_comp.l      dgn_comp.y      lev_comp.l      lev_comp.y
+
+win/Qt:
+(files for the Qt widget library - X11, Windows, Mac OS X, or Qtopia)
+Info.plist      Install.Qt      knethack.lnk    knh-mini.xpm    knh.xpm
+nhicns.uu       nhsplash.xpm    qt_clust.cpp    qt_win.cpp      qttableview.cpp
+tileedit.cpp    tileedit.h      qpe-nethack.control
+
+win/X11:
+(files for X versions)
+Install.X11     NetHack.ad      Window.c        dialogs.c       ibm.bdf
+nethack.rc      nh10.bdf        nh32icon        nh56icon        nh72icon
+nh_icon.xpm     pet_mark.xbm    rip.xpm         tile2x11.c      winX.c
+winmap.c        winmenu.c       winmesg.c       winmisc.c       winstat.c
+wintext.c       winval.c
+
+win/gem:
+(files for GEM versions)
+Install.gem     bitmfile.c      gem_rsc.uu      gem_rso.uu      gr_rect.c
+gr_rect.h       load_img.c      tile2img.c      title.uu        wingem.c
+wingem1.c       xpm2img.c
+
+win/gnome:
+(files for GNOME versions)
+README          gn_xpms.h       gnaskstr.c      gnaskstr.h      gnbind.c
+gnbind.h        gnglyph.c       gnglyph.h       gnmain.c        gnmain.h
+gnmap.c         gnmap.h         gnmenu.c        gnmenu.h        gnmesg.c
+gnmesg.h        gnomeprv.h      gnopts.c        gnopts.h        gnplayer.c
+gnplayer.h      gnsignal.c      gnsignal.h      gnstatus.c      gnstatus.h
+gntext.c        gntext.h        gnworn.c        gnworn.h        gnyesno.c
+gnyesno.h       mapbg.xpm
+
+win/share:
+(files for versions using optional tiles)
+gifread.c       monsters.txt    objects.txt     other.txt       ppmwrite.c
+thintile.c      tile.doc        tile.h          tile2bmp.c      tilemap.c
+tiletext.c
+
+win/tty:
+(files for tty versions)
+getline.c       termcap.c       topl.c          wintty.c
+
+win/win32:
+(files for Windows 9x, NT, Windows 2000, and Windows XP version)
+dgncomp.dsp     dgnstuff.dsp    dgnstuff.mak    dlb_main.dsp    levcomp.dsp
+levstuff.dsp    levstuff.mak    makedefs.dsp    mhaskyn.c       mhaskyn.h
+mhdlg.c         mhdlg.h         mhfont.c        mhfont.h        mhinput.c
+mhinput.h       mhmain.c        mhmain.h        mhmap.c         mhmap.h
+mhmenu.c        mhmenu.h        mhmsg.h         mhmsgwnd.c      mhmsgwnd.h
+mhrip.c         mhrip.h         mhsplash.c      mhsplash.h      mhstatus.c
+mhstatus.h      mhtext.c        mhtext.h        mnsel.uu        mnselcnt.uu
+mnunsel.uu      mswproc.c       nethack.dsw     nethackw.dsp    petmark.uu
+recover.dsp     resource.h      rip.uu          splash.uu       tile2bmp.dsp
+tilemap.dsp     tiles.dsp       tiles.mak       uudecode.dsp    winMS.h
+winhack.c       winhack.rc
+
+
+
+This is a list of files produced by auxiliary programs.  They can all be
+regenerated from the files in the distribution.
+
+dat:
+(files generated by makedefs at playground creation time)
+data            dungeon.pdf     options         oracles         quest.dat
+rumors
+(file generated by dgn_comp at playground creation time)
+dungeon
+(files generated by lev_comp at playground creation time)
+Arc-fila.lev    Arc-filb.lev    Arc-goal.lev    Arc-loca.lev    Arc-strt.lev
+Bar-fila.lev    Bar-filb.lev    Bar-goal.lev    Bar-loca.lev    Bar-strt.lev
+Cav-fila.lev    Cav-filb.lev    Cav-goal.lev    Cav-loca.lev    Cav-strt.lev
+Hea-fila.lev    Hea-filb.lev    Hea-goal.lev    Hea-loca.lev    Hea-strt.lev
+Kni-fila.lev    Kni-filb.lev    Kni-goal.lev    Kni-loca.lev    Kni-strt.lev
+Mon-fila.lev    Mon-filb.lev    Mon-goal.lev    Mon-loca.lev    Mon-strt.lev
+Pri-fila.lev    Pri-filb.lev    Pri-goal.lev    Pri-loca.lev    Pri-strt.lev
+Ran-fila.lev    Ran-filb.lev    Ran-goal.lev    Ran-loca.lev    Ran-strt.lev
+Rog-fila.lev    Rog-filb.lev    Rog-goal.lev    Rog-loca.lev    Rog-strt.lev
+Sam-fila.lev    Sam-filb.lev    Sam-goal.lev    Sam-loca.lev    Sam-strt.lev
+Tou-fila.lev    Tou-filb.lev    Tou-goal.lev    Tou-loca.lev    Tou-strt.lev
+Val-fila.lev    Val-filb.lev    Val-goal.lev    Val-loca.lev    Val-strt.lev
+Wiz-fila.lev    Wiz-filb.lev    Wiz-goal.lev    Wiz-loca.lev    Wiz-strt.lev
+air.lev         asmodeus.lev    astral.lev      baalz.lev       bigrm-1.lev
+bigrm-2.lev     bigrm-3.lev     bigrm-4.lev     bigrm-5.lev     castle.lev
+earth.lev       fakewiz1.lev    fakewiz2.lev    fire.lev        juiblex.lev
+knox.lev        medusa-1.lev    medusa-2.lev    minefill.lev    minend-1.lev
+minend-2.lev    minetn-1.lev    minetn-2.lev    oracle.lev      orcus.lev
+sanctum.lev     soko1-1.lev     soko1-2.lev     soko2-1.lev     soko2-2.lev
+soko3-1.lev     soko3-2.lev     soko4-1.lev     soko4-2.lev     tower1.lev
+tower2.lev      tower3.lev      valley.lev      water.lev       wizard1.lev
+wizard2.lev     wizard3.lev
+(tile files optionally generated for X ports at playground creation time)
+pet_mark.xbm    rip.xpm         x11tiles
+(files generated for Qt interface on Mac OS X)
+nethack.icns    Info.plist
+
+include:
+(files generated by makedefs at compile time)
+date.h          onames.h        pm.h            vis_tab.h
+
+src:
+(files generated by makedefs at compile time)
+monstr.c        vis_tab.c
+(file optionally generated by tilemap at compile time)
+tile.c
+(files generated by 'moc' for Qt interface at compile time)
+qt_kde0.moc     qt_win.moc      qttableview.moc
+
+NOTE: If your binaries were compiled with the data librarian (DLB) option,
+      your playground will not contain all of the files listed here.  All
+      of the files listed as being required for the playground must still
+      have been built by your compiler, but the DLB code will roll them up
+      into another file (or files).
diff --git a/Porting b/Porting
new file mode 100644 (file)
index 0000000..16f9cc2
--- /dev/null
+++ b/Porting
@@ -0,0 +1,172 @@
+  NetHack Porting Guidelines           v 3.4                   1999-11-29
+
+
+     1.0       Introduction
+
+       This document goes through the steps required to port NetHack to a
+new machine.  The basic steps in porting the program are:
+
+       1.  Get the code onto your machine.  The parts of the current
+           directory setup you definitely need include src (NetHack code
+           shared by all systems), include (include files), util (code
+           for utility programs), and dat (various data files).  The
+           documentation in doc is strongly recommended.  You already
+           have the files in the top directory since you're reading this
+           one. :-)
+
+           A full list of the distribution files and their associated
+           OSes may be found in the top-level file "Files".
+
+           If your machine uses an OS already supported, you need the sys
+           subdirectory for that OS and possibly sys/share.  Otherwise,
+           get the closest match (say sys/msdos for single-tasking OSes
+           and sys/unix for multi-user OSes, along with sys/share, if
+           nothing else comes to mind).  You may want others for
+           comparison.
+
+           If your machine uses a windowing system already supported,
+           you need the win subdirectory for that system (or the
+           appropriate sys subdirectory if the windowing system was
+           previously considered restricted to one OS).
+
+       2.  Modify the appropriate include files to customize NetHack to
+           your system.  You may need to add a new OS-specific "*conf.h"
+           file (see unixconf.h, pcconf.h, tosconf.h, etc. as examples).
+
+       3.  If your machine uses a new OS instead of a variant of existing
+           OSes, add a new sys subdirectory.  Add, if required, a OS-
+           specific copy of "main.c", "tty.c" and "unix.c".  Possibly
+           add an OS-specific library (see "msdos.c" and "tos.c" as
+           examples) to provide functions NetHack wants and your OS lacks.
+
+       4.  If your machine uses a new windowing system, follow doc/window.doc
+           carefully.  Put files implementing these routines in a win or
+           sys subdirectory as appropriate.
+
+       5.  If your compilation environment isn't close to one already
+           supported, try starting from the UNIX makefiles.  Modify the
+           top level makefile and the src makefile as required.  Then run
+           an initial compile.  You are bound to get some errors.  You
+           should be able to fix them in a fairly simple fashion.  If
+           things seem to be getting too complex, take a step back, and
+           possibly send us some mail.  We might be able to help.
+
+       6.  Mail all of your fixes to us in a contextual form so that we can
+           easily integrate them into the code.
+
+       One general rule of thumb exists.  Always add code.  Don't delete
+somebody else's code for yours -- it won't work on their machine if you do.
+Always add your OS specific code inside #ifdef / #else / #endif constructs
+so that it will be able to be folded back into the original code easily.
+
+
+     2.0       Include Files
+
+     2.1       config.h
+
+       The file "config.h" is a master configuration file that determines
+the basic features of the game, as well as many of the security options.
+It is intended that end users configure the game by editing "config.h" and
+an appropriate "*conf.h" file, so any #defines for individual preferences
+should be added to those files.  OS-specific #defines that are not intended
+to be changed should also go in "*conf.h"; try to find the most appropriate
+place for other #defines.
+
+       The following sections may require modification:
+
+     - Section 1:      OS and window system selection.
+                       You may have to put a #define for your OS here.
+                       If your OS is yet another UNIX variant, put the
+                       #define in unixconf.h instead.
+                       An unfortunately large amount of stuff shares
+                       this section because the #definitions have to
+                       be seen before *conf.h is reached.  Don't add
+                       to this unless necessary.
+
+     - Section 2:      Global parameters and filenames.
+                       These will have to be customized to your system.
+
+     - Section 3:      Type definitions and other compiler behavior.
+                       These will have to be matched to your compiler.
+
+     2.2       global.h
+
+       This file defines things specific to NetHack that should not
+require modification by an end user.  For a new port, you may have to add
+automatic inclusion of another auxiliary config file (*conf.h) which you
+wrote for your system.
+
+     2.3       extern.h
+
+       If you create any new source modules or new functions in old modules,
+you must enter the names of the new external references (the functions defined
+there for external use) in this file.
+
+     2.4       system.h
+
+       This file contains references for all hooks into the OS (via the
+standard "C" libraries).  Depending on what your standard library looks like,
+you may have to put new entries into this file.
+
+
+     3.0       Source files
+
+       The first step in getting the game up is to get the "makedefs"
+program running.  This program is used to create configuration-specific
+files for the game.
+
+       Once "makedefs" has been built, the rest of the game can be compiled.
+You may have to create an OS-specific module to handle things you want to
+use, like a mouse or a ram-disk.
+
+       The utility compilers "dgn_comp" and "lev_comp" may be a better
+place to start.  They also require "makedefs" but are independent of
+"nethack".  They are usually the last programs made, but since they are
+much smaller they may be more tractable when first arguing with the include
+files.  These programs create binary data files that "nethack" uses to
+guide its dungeon creation.
+
+     3.1       Makefiles
+
+       This distribution provides makefiles for several kinds of systems.
+There are joint makefiles for the various varieties of UNIX, makefiles for
+MSDOS, a makefile for NT, and so on.  You may have to create a new
+makefile for your specific machine.  You may even have to translate some
+makefiles into a form more congenial to your system.  If possible, however,
+add to one of those provided.
+
+     3.2       termcap.c
+
+       If your system wants to use tty windowing and it doesn't run off
+of a termcap or terminfo database, you may have to put the appropriate
+terminal control strings into termcap.c.  This has already been done for
+MSDOS, and these mods can be used as an example.  You can also consider
+using the termcap code from sys/share/tclib.c or sys/share/termcap.uu,
+especially if your system supports multiple kinds of terminals.
+
+     3.3       main.c
+
+       You may need to create a new "main.c" module.  If you do, call it
+[OS]main.c where the [OS] is replaced with the name of the OS you are porting
+to.  This file contains the mainline module, which reads options from the
+command line (or wherever) and processes them.  It also contains various
+functions associated with game startup.
+
+     3.4       tty.c
+
+       You may need to create a new "tty.c" module.  If you do, call it
+[OS]tty.c where the [OS] is replaced with the name of the OS you are porting
+to.  This file contains the routines that configure the terminal/console
+for raw I/O, etc.
+
+     3.5       unix.c
+
+       You may need to create a new "unix.c" module.  If you do, call it
+[OS]unix.c where the [OS] is replaced with the name of the OS you are porting
+to.  This file contains some OS dependencies concerning time and filename
+creation.
+
+
+       An object of the NetHack development project is to get the game
+working on as many different types of hardware and under as many different
+operating systems as is practical.  Any assistance will be appreciated.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..8c16d3e
--- /dev/null
+++ b/README
@@ -0,0 +1,226 @@
+                NetHack 3.4.3 -- General information
+
+NetHack 3.4 is an enhancement to the dungeon exploration game NetHack.
+It is a distant descendent of Rogue and Hack, and a direct descendent of
+NetHack 3.3.
+
+NetHack 3.4.3 is a bugfix release for NetHack 3.4.2.
+ *  Several dozen general bug fixes including at least one fatal bug
+ *  Correct several inconsistencies
+ *  Handle level completely filled with monsters better
+ *  win32tty performance enhancements when playing on Windows 98 and Windows Me
+ *  win32gui player selection fixes
+ *  X11 player selection fixes, one of which could be fatal
+ *  Eliminated a gold-in-shop-container cheat
+ *  Include bones file version compatibility info in options file
+
+A fuller list of changes for this release can be found in the file 
+doc/fixes34.3 in the source distribution.  The text in there was written 
+for the development team's own use and is provided "as is", so please do 
+not ask us to further explain the entries in that file.
+
+The internal structure of bones and save files has not changed between 
+NetHack 3.4.0, 3.4.1, 3.4.2 and now 3.4.3. That means that if you use the 
+same compiler, the same compiler version and compiler switches, the same 
+NetHack compile-time options, and you have not incorporated any additional 
+source code patches that altered the save file format on your system, then 
+bones and save files from 3.4.0 through 3.4.3 should be compatible.
+
+
+                        - - - - - - - - - - -
+
+Please read items (1), (2) and (3) BEFORE doing anything with your new code.
+
+1.  Unpack the code in a dedicated new directory.  We will refer to that
+    directory as the 'Top' directory.  It makes no difference what you
+    call it.
+
+2.  If there is no flaw in the packaging, many sub-directories will be
+    automatically created, and files will be deposited in them:
+
+    a.  A 'dat' directory, which contains a variety of data files.
+    b.  A 'doc' directory, which contains various documentation.
+    c.  An 'include' directory, which contains *.h files.
+    d.  A 'src' directory, which contains game *.c files used by all versions.
+    e.  A 'util' directory, which contains files for utility programs.
+    f.  A 'sys' directory, which contains subdirectories for files that
+        are operating-system specific.
+    g.  A 'sys/share' subdirectory, which contains files shared by some OSs.
+    h.  A 'sys/share/sounds' subsubdirectory, which contains sound files
+        shared by some OSs.
+    i.  A 'sys/amiga' subdirectory, which contains files specific to AmigaDOS.
+    j.  A 'sys/amiga/ship' subsubdirectory
+    k.  A 'sys/atari' subdirectory, which contains files specific to TOS.
+    l.  A 'sys/be' subdirectory, which contains files specific to Be OS.
+    m.  A 'sys/mac' subdirectory, which contains files specific to MacOS.
+    n.  A 'sys/msdos' subdirectory, which contains files specific to MS-DOS.
+    o.  A 'sys/os2' subdirectory, which contains files specific to OS/2.
+    p.  A 'sys/unix' subdirectory, which contains files specific to UNIX.
+    q.  A 'sys/vms' subdirectory, which contains files specific to VMS.
+    r.  A 'sys/wince' subdirectory, which contains files specific to Windows CE.
+    s.  A 'sys/winnt' subdirectory, which contains files specific to Windows NT.
+    t.  A 'win' directory, which contains subdirectories for files that
+        are windowing-system specific (but not operating-system specific).
+    u.  A 'win/share' subdirectory, which contains files shared by some
+        windowing systems.
+    v.  A 'win/Qt' subdirectory, which contains files specific to Qt.
+    w.  A 'win/X11' subdirectory, which contains files specific to X11.
+    x.  A 'win/gem' subdirectory, which contains files specific to GEM.
+    y.  A 'win/gnome' subdirectory, which contains files specific to GNOME.
+    z.  A 'win/tty' subdirectory, which contains files specific to ttys.
+    A.  A 'win/win32' subdirectory, which contains files specific to the
+        Windows Win32 API.
+
+    The names of these directories should not be changed unless you are
+    ready to go through the makefiles and the makedefs program and change
+    all the directory references in them.
+
+3.  Having unpacked, you should have a file called 'Files' in your Top
+    directory.  This file contains the list of all the files you now SHOULD
+    have in each directory.  Please check the files in each directory
+    against this list to make sure that you have a complete set.
+
+4.  Before you do anything else, please read carefully the file called
+    "license" in the 'dat' subdirectory.  It is expected that you comply
+    with the terms of that license, and we are very serious about it.
+
+5.  If everything is in order, you can now turn to trying to get the program
+    to compile and run on your particular system.  It is worth mentioning
+    that the default configuration is SysV/Sun/Solaris2.x (simply because
+    the code was housed on such a system).  It is also worth mentioning
+    here that NetHack 3.4 is a huge program.  If you intend to run it on a
+    small machine, you'll have to make hard choices among the options
+    available in config.h.
+
+    The files sys/*/Install.* were written to guide you in configuring the
+    program for your operating system.  The files win/*/Install.* are
+    available, where necessary, to help you in configuring the program
+    for particular windowing environments.  Reading them, and the man pages,
+    should answer most of your questions.
+
+    At the time of this release, NetHack 3.4 is known to run/compile on:
+
+        Apple Macintosh running MacOS 7.5 or higher, LinuxPPC, BeOS 4.0
+        Atari ST/TT/Falcon running TOS (or MultiTOS) with GCC
+        Commodore Amiga running AmigaDOS 3.0 or higher with SAS/C 6.x
+                (but see Makefile.ami about DICE and Manx)
+        DEC Alpha/VMS (aka OpenVMS AXP), running V1.x through V7.1
+        DEC VAX/VMS, running V4.6 through V7.1
+        HP 9000s700 running HP-UX 10.x, 11.x
+        IBM PS/2 and AT compatibles running OS/2 - 2.0 and up with GCC emx
+        Intel 80386 or greater (or clone) boxes running MS-DOS with DPMI.
+        Intel 80386 or greater (or clone) boxes running Linux, or BSDI.
+        Intel 80386 or greater (or clone) boxes running Windows 95/98/Me.
+        Intel 80386 or greater (or clone) boxes running Windows NT/2000/XP/2003.
+        Intel Pentium or better (or clone) running BeOS 4.5
+        Sun SPARC based machine running SunOS 4.x, Solaris 2.x, or Solaris 7
+
+    NetHack 3.4 will also run on the following, but a cross-compiler hosted
+    on another platform, such as win32, is required to build from source.
+
+        Pocket PC devices running Windows CE 3.0 and higher
+        H/PC Pro devices running Windows CE 2.11 and higher.
+       Palm Size PC 1.1 devices running Windows CE 2.11
+
+    Previous versions of NetHack were tested on the following systems,
+    and we expect that NetHack 3.4 will work on them as well:
+
+        AT&T 3B1 running System V (3.51)
+        AT&T 3B2/600 & 3B2/622 running System V R3.2.1
+        AT&T 3B2/1000 Model 80 running System V R3.2.2
+        AT&T 3B4000 running System V
+        AT&T 6386 running System V R3.2
+        Data General AViiON systems running DG/UX
+        DEC vaxen running BSD, Ultrix
+        Decstations running Ultrix 3.1, 4.x
+        Encore Multimax running UMAX 4.2
+        Gould NP1 running UTX 3/2
+        HP 9000s300 running HP-UX
+        HP 9000s700 running HP-UX 9.x
+        IBM PC/RT and RS/6000 running AIX 3.x
+        IBM PS/2 and AT compatibles running OS/2 1.1 - 2.0 (and probably
+           Warp) with Microsoft 6.0, and OS/2 2.0 and up with IBM CSet++ 2.0.
+        Intel 80386 or greater (or clone) running 386BSD
+        Mips M2000 running RiscOS 4.1
+        NeXT running Mach (using BSD configuration)
+        Pyramid 9820x running OSx 4.4c
+        SGI Iris running IRIX
+        Stardent Vistra 800 running SysV R4.0
+        Stride 460 running UniStride 2.1
+        Sun-3s, -4s, and -386is running SunOS 3.x
+        Sun-3s and -386is running SunOS 4.x
+        Valid Logic Systems SCALD-System
+
+    Unless otherwise mentioned, the compiler used was the OS-vendor's
+    C compiler.
+
+    With the demise of Windows NT on the DEC Alpha, no attempt has been
+    made to build NetHack 3.4.3 on that platform.
+
+    Windows 98/Me have been the most problematic Windows platforms for
+    running NetHack so far. Patches for 3.4.2 (courtesy Michael Lehotay)
+    have been incorporated into 3.4.3 to help make them work better. Your
+    results may vary.
+
+    A build for Intel 80286 machines and DOS "real mode" overlaid versions 
+    has not been produced for 3.4.3.  Nobody on the porting team has
+    the time or the software to attempt the necessary tuning that will allow 
+    it to achieve the balance of having just the right amount of available 
+    memory, and still have acceptable performance.  The sources necessary 
+    to do so are still included in the source distribution, so if someone 
+    has access to a real-mode compiler and lots of spare time on their hands, 
+    you may be able to get things working. Of course you do so at your own risk.
+
+                        - - - - - - - - - - -
+
+If you have problems building the game, or you find bugs in it, we recommend 
+filing a bug report from our "Contact Us" web page at:
+    http://www.nethack.org/ 
+
+When sending correspondence, please observe the following:
+o Please be sure to include your machine type, OS, and patchlevel.
+o Never send us binary files (e.g. save files or bones files). Whichever 
+  platform you are using, only a small minority of the development team has 
+  access to it, and you will rapidly annoy the others.  If you have found 
+  a bug and think that your save file would aid in solving the problem, 
+  send us a description in words of the problem, your machine type, your 
+  operating system, and the version of NetHack.  Tell us that you have a 
+  save file, but do not actually send it.
+  In the rare case that we think your save file would be helpful, you will
+  be contacted by a member of the development team with the address of a
+  specific person to send the save file to.
+o Though we make an effort to reply to each bug report, it may take some
+  time before you receive feedback.  This is especially true during the
+  period immediately after a new release, when we get the most bug reports.
+o We don't give hints for playing the game.
+o Don't bother to ask when the next version will be out.  You will not get
+  a reply.
+
+If you don't have access to the world wide web, or if you want to submit
+a patch for the NetHack source code via email directly, you can direct it 
+to this address:
+    nethack-bugs (at) nethack.org
+
+If you've changed something to get NetHack to run on your system, it's likely
+that others have done it by making slightly different modifications.  By routing 
+your patches through the development team, we should be able to avoid making 
+everyone else choose among variant patches claiming to do the same thing, to keep
+most of the copies of 3.4 synchronized by means of official patches, and to 
+maintain the painfully-created file organization.  (This process has been working
+since the time when everyone just posted their own patches to 2.3.  At that time,
+there were no archived bug-fixes to give to people who got 2.3 after its initial
+release, so the same bugs kept being discovered by new batches of people.)
+We have been successful in preventing this from happening since the 3.0
+release.  Please cooperate to keep this from happening to 3.4.
+
+It is inevitable that we will reject some proposed additions of new features
+either because they do not fit our conception of the game, or because they
+require more code than we consider they're worth.  If we reject your feature,
+you are free, of course, to post the patches to the net yourself and let the
+marketplace decide their worth.
+
+All of this amounts to the following:  If you decide to apply a free-lanced
+patch to your 3.4 code, you are on your own.  In our own patches, we will
+assume that your code is synchronized with ours.
+
+                  -- Good luck, and happy Hacking --
diff --git a/binary/license b/binary/license
new file mode 100644 (file)
index 0000000..5ad7e34
--- /dev/null
@@ -0,0 +1,95 @@
+                    NETHACK GENERAL PUBLIC LICENSE
+                    (Copyright 1989 M. Stephenson)
+
+               (Based on the BISON general public license,
+                   copyright 1988 Richard M. Stallman)
+
+ Everyone is permitted to copy and distribute verbatim copies of this
+ license, but changing it is not allowed.  You can also use this wording to
+ make the terms for other programs.
+
+  The license agreements of most software companies keep you at the mercy of
+those companies.  By contrast, our general public license is intended to give
+everyone the right to share NetHack.  To make sure that you get the rights we
+want you to have, we need to make restrictions that forbid anyone to deny you
+these rights or to ask you to surrender the rights.  Hence this license
+agreement.
+
+  Specifically, we want to make sure that you have the right to give away
+copies of NetHack, that you receive source code or else can get it if you
+want it, that you can change NetHack or use pieces of it in new free
+programs, and that you know you can do these things.
+
+  To make sure that everyone has such rights, we have to forbid you to
+deprive anyone else of these rights.  For example, if you distribute copies
+of NetHack, you must give the recipients all the rights that you have.  You
+must make sure that they, too, receive or can get the source code.  And you
+must tell them their rights.
+
+  Also, for our own protection, we must make certain that everyone finds out
+that there is no warranty for NetHack.  If NetHack is modified by someone
+else and passed on, we want its recipients to know that what they have is
+not what we distributed.
+
+  Therefore we (Mike Stephenson and other holders of NetHack copyrights) make
+the following terms which say what you must do to be allowed to distribute or
+change NetHack.
+
+
+                        COPYING POLICIES
+
+  1. You may copy and distribute verbatim copies of NetHack source code as
+you receive it, in any medium, provided that you keep intact the notices on
+all files that refer to copyrights, to this License Agreement, and to the
+absence of any warranty; and give any other recipients of the NetHack
+program a copy of this License Agreement along with the program.
+
+  2. You may modify your copy or copies of NetHack or any portion of it, and
+copy and distribute such modifications under the terms of Paragraph 1 above
+(including distributing this License Agreement), provided that you also do the
+following:
+
+    a) cause the modified files to carry prominent notices stating that you
+    changed the files and the date of any change; and
+
+    b) cause the whole of any work that you distribute or publish, that in
+    whole or in part contains or is a derivative of NetHack or any part
+    thereof, to be licensed at no charge to all third parties on terms
+    identical to those contained in this License Agreement (except that you
+    may choose to grant more extensive warranty protection to some or all
+    third parties, at your option)
+
+    c) You may charge a distribution fee for the physical act of
+    transferring a copy, and you may at your option offer warranty protection
+    in exchange for a fee.
+
+  3. You may copy and distribute NetHack (or a portion or derivative of it,
+under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 1 and 2 above provided that you also do one of the following:
+
+    a) accompany it with the complete machine-readable source code, which
+    must be distributed under the terms of Paragraphs 1 and 2 above; or,
+
+    b) accompany it with full information as to how to obtain the complete
+    machine-readable source code from an appropriate archive site.  (This
+    alternative is allowed only for noncommercial distribution.)
+
+For these purposes, complete source code means either the full source
+distribution as originally released over Usenet or updated copies of the
+files in this distribution used to create the object code or executable.
+
+  4. You may not copy, sublicense, distribute or transfer NetHack except as
+expressly provided under this License Agreement.  Any attempt otherwise to
+copy, sublicense, distribute or transfer NetHack is void and your rights to
+use the program under this License agreement shall be automatically
+terminated.  However, parties who have received computer software programs
+from you with this License Agreement will not have their licenses terminated
+so long as such parties remain in full compliance.
+
+
+Stated plainly:  You are permitted to modify NetHack, or otherwise use parts
+of NetHack, provided that you comply with the conditions specified above;
+in particular, your modified NetHack or program containing parts of NetHack
+must remain freely available as provided in this License Agreement.  In
+other words, go ahead and share NetHack, but don't try to stop anyone else
+from sharing it farther.
diff --git a/build/dgncomp.dsp b/build/dgncomp.dsp
new file mode 100644 (file)
index 0000000..815384c
--- /dev/null
@@ -0,0 +1,297 @@
+# Microsoft Developer Studio Project File - Name="dgncomp" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=dgncomp - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "dgncomp.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "dgncomp.mak" CFG="dgncomp - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "dgncomp - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "dgncomp - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "dgncomp - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "..\util"\r
+# PROP BASE Intermediate_Dir "dgncomp___Win32_Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\util"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"\r
+# ADD RSC /l 0x1009 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\dgn_comp.exe"\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=dgncomp\r
+PostBuild_Cmds=echo Building dungeon   echo chdir ..\dat       chdir ..\dat    echo ..\util\dgn_comp.exe dungeon.pdf   ..\util\dgn_comp.exe dungeon.pdf        echo chdir ..\build     chdir ..\build\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "dgncomp - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "dgncomp___Win32_Debug"\r
+# PROP BASE Intermediate_Dir "dgncomp___Win32_Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\util"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"\r
+# ADD RSC /l 0x1009 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"..\util\dgn_comp.exe" /pdbtype:sept\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=dgncomp\r
+PostBuild_Cmds=echo Building dungeon   echo chdir ..\dat       chdir ..\dat    echo ..\util\dgn_comp.exe dungeon.pdf   ..\util\dgn_comp.exe dungeon.pdf        echo chdir ..\build     chdir ..\build\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "dgncomp - Win32 Release"\r
+# Name "dgncomp - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\src\alloc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\dgn_lex.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\dgn_main.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\dgn_yacc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\panic.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\align.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\attrib.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\color.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config1.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\coord.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\decl.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dgn_comp.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dgn_file.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\display.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dungeon.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\engrave.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\flag.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\global.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mkroom.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monattk.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monst.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monsym.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\nhlan.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\ntconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\obj.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\objclass.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\onames.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\permonst.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\pm.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\prop.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\quest.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\rect.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\region.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\rm.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\skills.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\spell.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\timeout.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tradstdc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\trampoli.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\trap.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\vision.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\winprocs.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wintty.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wintype.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\you.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\youprop.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/build/dgnstuff.dsp b/build/dgnstuff.dsp
new file mode 100644 (file)
index 0000000..ab1e95a
--- /dev/null
@@ -0,0 +1,97 @@
+# Microsoft Developer Studio Project File - Name="dgnstuff" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) External Target" 0x0106\r
+\r
+CFG=dgnstuff - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "dgnstuff.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "dgnstuff.mak" CFG="dgnstuff - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "dgnstuff - Win32 Release" (based on "Win32 (x86) External Target")\r
+!MESSAGE "dgnstuff - Win32 Debug" (based on "Win32 (x86) External Target")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+\r
+!IF  "$(CFG)" == "dgnstuff - Win32 Release"\r
+\r
+# PROP BASE Use_MFC\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Cmd_Line "NMAKE /f dgnstuff.mak"\r
+# PROP BASE Rebuild_Opt "/a"\r
+# PROP BASE Target_File "dgnstuff.exe"\r
+# PROP BASE Bsc_Name "dgnstuff.bsc"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Cmd_Line "nmake /f "dgnstuff.mak""\r
+# PROP Rebuild_Opt "/a"\r
+# PROP Target_File "..\util\dgncomp.exe"\r
+# PROP Bsc_Name ""\r
+# PROP Target_Dir ""\r
+\r
+!ELSEIF  "$(CFG)" == "dgnstuff - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Cmd_Line "NMAKE /f dgnstuff.mak"\r
+# PROP BASE Rebuild_Opt "/a"\r
+# PROP BASE Target_File "dgnstuff.exe"\r
+# PROP BASE Bsc_Name "dgnstuff.bsc"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "dgnstuff___Win32_Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Cmd_Line "nmake /f "dgnstuff.mak""\r
+# PROP Rebuild_Opt "/a"\r
+# PROP Target_File "..\util\dgncomp.exe"\r
+# PROP Bsc_Name ""\r
+# PROP Target_Dir ""\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "dgnstuff - Win32 Release"\r
+# Name "dgnstuff - Win32 Debug"\r
+\r
+!IF  "$(CFG)" == "dgnstuff - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "dgnstuff - Win32 Debug"\r
+\r
+!ENDIF \r
+\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/build/dgnstuff.mak b/build/dgnstuff.mak
new file mode 100644 (file)
index 0000000..8e5aa81
--- /dev/null
@@ -0,0 +1,59 @@
+#Set all of these or none of them
+#YACC   = byacc.exe
+#LEX   = flex.exe
+#YTABC   = y_tab.c
+#YTABH   = y_tab.h
+#LEXYYC  = lexyy.c
+
+!IF "$(YACC)"!=""
+@echo Yacc-alike set to $(YACC)
+@echo YTABC set to $(YTABC)
+@echo YTABH set to $(YTABH)
+!ENDIF
+
+!IF "$(LEX)"!=""
+@echo Lex-alike set to $(LEX)
+@echo LEXYYC set to $(LEXYYC)
+!ENDIF
+
+default: all
+
+all: ..\util\dgn_yacc.c ..\util\dgn_lex.c
+
+rebuild: clean all
+
+clean:
+       -del ..\util\dgn_lex.c
+       -del ..\util\dgn_yacc.c
+       -del ..\include\dgn_comp.h
+
+#==========================================
+# Dungeon Compiler Stuff
+#==========================================
+
+..\util\dgn_yacc.c ..\include\dgn_comp.h : ..\util\dgn_comp.y
+!IF "$(YACC)"==""
+          @echo Using pre-built dgn_yacc.c and dgn_comp.h
+          @copy ..\sys\share\dgn_yacc.c ..\util\dgn_yacc.c
+          @copy ..\sys\share\dgn_comp.h ..\include\dgn_comp.h
+!ELSE
+          chdir ..\util
+          $(YACC) -d dgn_comp.y
+          copy $(YTABC) $@
+          copy $(YTABH) ..\include\dgn_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+          chdir ..\build
+!ENDIF
+
+..\util\dgn_lex.c: ..\util\dgn_comp.l
+!IF "$(LEX)"==""
+          @echo Using pre-built dgn_lex.c
+          @copy ..\sys\share\dgn_lex.c $@
+!ELSE
+          chdir ..\util
+          $(LEX) dgn_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+          chdir ..\build
+!ENDIF
diff --git a/build/dlb_main.dsp b/build/dlb_main.dsp
new file mode 100644 (file)
index 0000000..8dff70f
--- /dev/null
@@ -0,0 +1,179 @@
+# Microsoft Developer Studio Project File - Name="dlb_main" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=dlb_main - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "dlb_main.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "dlb_main.mak" CFG="dlb_main - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "dlb_main - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "dlb_main - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "dlb_main - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /I "..\win\share" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "DLB" /D "WIN32CON" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"\r
+# ADD RSC /l 0x1009 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\dlb_main.exe"\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Packaging via DLB\r
+PostBuild_Cmds=echo chdir ..\dat       \\r
+chdir ..\dat   \\r
+chdir  \\r
+ echo data >dlb.lst    \\r
+ echo oracles >>dlb.lst        \\r
+ if exist options echo options >>dlb.lst       \\r
+ if exist ttyoptions echo ttyoptions >>dlb.lst \\r
+ if exist guioptions echo guioptions >>dlb.lst \\r
+ if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp     \\r
+ if exist porthelp echo porthelp >>dlb.lst     \\r
+ echo quest.dat >>dlb.lst      \\r
+ echo rumors >>dlb.lst \\r
+ echo help >>dlb.lst   \\r
+ echo hh >>dlb.lst     \\r
+ echo cmdhelp >>dlb.lst        \\r
+ echo history >>dlb.lst        \\r
+ echo opthelp >>dlb.lst        \\r
+ echo wizhelp >>dlb.lst        \\r
+ echo dungeon >>dlb.lst        \\r
+ echo license >>dlb.lst        \\r
+ for %%N in (*.lev) do echo %%N >>dlb.lst      \\r
+ ..\util\dlb_main.exe cIf dlb.lst nhdat        \\r
+ echo chdir ..\build   \\r
+chdir ..\build \\r
+echo if NOT exist ..\binary\*.* mkdir ..\binary        \\r
+ if NOT exist ..\binary\*.* mkdir ..\binary\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "dlb_main - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt" /I "..\win\share" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "DLB" /D "WIN32CON" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"\r
+# ADD RSC /l 0x1009 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"..\util\dlb_main.exe" /pdbtype:sept\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Packaging via dlb\r
+PostBuild_Cmds=echo chdir ..\dat       \\r
+chdir ..\dat   \\r
+chdir  \\r
+ echo data >dlb.lst    \\r
+ echo oracles >>dlb.lst        \\r
+ if exist options echo options >>dlb.lst       \\r
+ if exist ttyoptions echo ttyoptions >>dlb.lst \\r
+ if exist guioptions echo guioptions >>dlb.lst \\r
+ if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp     \\r
+ if exist porthelp echo porthelp >>dlb.lst     \\r
+ echo quest.dat >>dlb.lst      \\r
+ echo rumors >>dlb.lst \\r
+ echo help >>dlb.lst   \\r
+ echo hh >>dlb.lst     \\r
+ echo cmdhelp >>dlb.lst        \\r
+ echo history >>dlb.lst        \\r
+ echo opthelp >>dlb.lst        \\r
+ echo wizhelp >>dlb.lst        \\r
+ echo dungeon >>dlb.lst        \\r
+ echo license >>dlb.lst        \\r
+ for %%N in (*.lev) do echo %%N >>dlb.lst      \\r
+ ..\util\dlb_main.exe cIf dlb.lst nhdat        \\r
+echo chdir ..\build    \\r
+chdir ..\build \\r
+echo if NOT exist ..\binary\*.* mkdir ..\binary        \\r
+if NOT exist ..\binary\*.* mkdir ..\binary\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "dlb_main - Win32 Release"\r
+# Name "dlb_main - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\src\alloc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dlb.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\dlb_main.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\panic.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dlb.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/build/levcomp.dsp b/build/levcomp.dsp
new file mode 100644 (file)
index 0000000..7c1486e
--- /dev/null
@@ -0,0 +1,198 @@
+# Microsoft Developer Studio Project File - Name="levcomp" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=levcomp - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "levcomp.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "levcomp.mak" CFG="levcomp - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "levcomp - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "levcomp - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "levcomp - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\util"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"\r
+# ADD RSC /l 0x1009 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=levcomp\r
+PostBuild_Cmds=echo Building special levels    echo chdir ..\dat       chdir ..\dat     \\r
+echo arch.des  ..\util\levcomp.exe arch.des     \\r
+echo barb.des  ..\util\levcomp.exe barb.des     \\r
+echo bigroom.des       ..\util\levcomp.exe bigroom.des  \\r
+echo castle.des        ..\util\levcomp.exe castle.des   \\r
+echo caveman.des       ..\util\levcomp.exe caveman.des  \\r
+echo endgame.des       ..\util\levcomp.exe endgame.des  \\r
+echo gehennom.des      ..\util\levcomp.exe gehennom.des         \\r
+echo healer.des        ..\util\levcomp.exe healer.des   \\r
+echo knight.des        ..\util\levcomp.exe knight.des   \\r
+echo knox.des  ..\util\levcomp.exe knox.des     \\r
+echo medusa.des        ..\util\levcomp.exe medusa.des   \\r
+echo mines.des ..\util\levcomp.exe mines.des    \\r
+echo monk.des  ..\util\levcomp.exe monk.des     \\r
+echo oracle.des        ..\util\levcomp.exe oracle.des   \\r
+echo priest.des        ..\util\levcomp.exe priest.des   \\r
+echo ranger.des        ..\util\levcomp.exe ranger.des   \\r
+echo rogue.des ..\util\levcomp.exe rogue.des    \\r
+echo samurai.des       ..\util\levcomp.exe samurai.des  \\r
+echo sokoban.des       ..\util\levcomp.exe sokoban.des  \\r
+echo tourist.des       ..\util\levcomp.exe tourist.des  \\r
+echo tower.des ..\util\levcomp.exe tower.des    \\r
+echo valkyrie.des      ..\util\levcomp.exe valkyrie.des         \\r
+echo wizard .des       ..\util\levcomp.exe wizard.des   \\r
+echo yendor.des        ..\util\levcomp.exe yendor.des   \\r
+echo chdir ..\build    chdir ..\build\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "levcomp - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\util"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"\r
+# ADD RSC /l 0x1009 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /pdbtype:sept\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=levcomp\r
+PostBuild_Cmds=echo Building special levels    echo chdir ..\dat       chdir ..\dat     \\r
+echo arch.des  ..\util\levcomp.exe arch.des     \\r
+echo barb.des  ..\util\levcomp.exe barb.des     \\r
+echo bigroom.des       ..\util\levcomp.exe bigroom.des  \\r
+echo castle.des        ..\util\levcomp.exe castle.des   \\r
+echo caveman.des       ..\util\levcomp.exe caveman.des  \\r
+echo endgame.des       ..\util\levcomp.exe endgame.des  \\r
+echo gehennom.des      ..\util\levcomp.exe gehennom.des         \\r
+echo healer.des        ..\util\levcomp.exe healer.des   \\r
+echo knight.des        ..\util\levcomp.exe knight.des   \\r
+echo knox.des  ..\util\levcomp.exe knox.des     \\r
+echo medusa.des        ..\util\levcomp.exe medusa.des   \\r
+echo mines.des ..\util\levcomp.exe mines.des    \\r
+echo monk.des  ..\util\levcomp.exe monk.des     \\r
+echo oracle.des        ..\util\levcomp.exe oracle.des   \\r
+echo priest.des        ..\util\levcomp.exe priest.des   \\r
+echo ranger.des        ..\util\levcomp.exe ranger.des   \\r
+echo rogue.des ..\util\levcomp.exe rogue.des    \\r
+echo samurai.des       ..\util\levcomp.exe samurai.des  \\r
+echo sokoban.des       ..\util\levcomp.exe sokoban.des  \\r
+echo tourist.des       ..\util\levcomp.exe tourist.des  \\r
+echo tower.des ..\util\levcomp.exe tower.des    \\r
+echo valkyrie.des      ..\util\levcomp.exe valkyrie.des         \\r
+echo wizard .des       ..\util\levcomp.exe wizard.des   \\r
+echo yendor.des        ..\util\levcomp.exe yendor.des   \\r
+echo chdir ..\build    chdir ..\build\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "levcomp - Win32 Release"\r
+# Name "levcomp - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\src\alloc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\decl.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\drawing.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\lev_lex.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\lev_main.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\lev_yacc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\monst.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\objects.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\panic.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\lev_comp.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/build/levstuff.dsp b/build/levstuff.dsp
new file mode 100644 (file)
index 0000000..276ad81
--- /dev/null
@@ -0,0 +1,97 @@
+# Microsoft Developer Studio Project File - Name="levstuff" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) External Target" 0x0106\r
+\r
+CFG=levstuff - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "levstuff.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "levstuff.mak" CFG="levstuff - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "levstuff - Win32 Release" (based on "Win32 (x86) External Target")\r
+!MESSAGE "levstuff - Win32 Debug" (based on "Win32 (x86) External Target")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+\r
+!IF  "$(CFG)" == "levstuff - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Cmd_Line "NMAKE /f levstuff.mak"\r
+# PROP BASE Rebuild_Opt "/a"\r
+# PROP BASE Target_File "levstuff.exe"\r
+# PROP BASE Bsc_Name "levstuff.bsc"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Cmd_Line "nmake /f "levstuff.mak""\r
+# PROP Rebuild_Opt "/a"\r
+# PROP Target_File "..\util\lev_lex.c"\r
+# PROP Bsc_Name ""\r
+# PROP Target_Dir ""\r
+\r
+!ELSEIF  "$(CFG)" == "levstuff - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "levstuff___Win32_Debug0"\r
+# PROP BASE Intermediate_Dir "levstuff___Win32_Debug0"\r
+# PROP BASE Cmd_Line "NMAKE /f levstuff.mak"\r
+# PROP BASE Rebuild_Opt "/a"\r
+# PROP BASE Target_File "levstuff.exe"\r
+# PROP BASE Bsc_Name "levstuff.bsc"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "levstuff___Win32_Debug0"\r
+# PROP Intermediate_Dir "levstuff___Win32_Debug0"\r
+# PROP Cmd_Line "nmake /f "levstuff.mak""\r
+# PROP Rebuild_Opt "/a"\r
+# PROP Target_File "..\util\lev_lex.c"\r
+# PROP Bsc_Name ""\r
+# PROP Target_Dir ""\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "levstuff - Win32 Release"\r
+# Name "levstuff - Win32 Debug"\r
+\r
+!IF  "$(CFG)" == "levstuff - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "levstuff - Win32 Debug"\r
+\r
+!ENDIF \r
+\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/build/levstuff.mak b/build/levstuff.mak
new file mode 100644 (file)
index 0000000..c7540c4
--- /dev/null
@@ -0,0 +1,59 @@
+#YACC   = byacc.exe
+#LEX   = flex.exe
+#YTABC   = y_tab.c
+#YTABH   = y_tab.h
+#LEXYYC  = lexyy.c
+
+!IF "$(YACC)"!=""
+@echo Yacc-alike set to $(YACC)
+@echo YTABC set to $(YTABC)
+@echo YTABH set to $(YTABH)
+!ENDIF
+
+!IF "$(LEX)"!=""
+@echo Lex-alike set to $(LEX)
+@echo LEXYYC set to $(LEXYYC)
+!ENDIF
+
+
+default: all
+
+all: ..\util\lev_yacc.c ..\util\lev_lex.c
+
+rebuild: clean all
+
+clean:
+       -del ..\util\lev_lex.c
+       -del ..\util\lev_yacc.c
+       -del ..\include\lev_comp.h
+
+#==========================================
+# Level Compiler Stuff
+#==========================================
+..\util\lev_yacc.c ..\include\lev_comp.h: ..\util\lev_comp.y
+!IF "$(YACC)"==""
+          @echo Using pre-built lev_yacc.c and lev_comp.h
+          @copy ..\sys\share\lev_yacc.c ..\util\lev_yacc.c
+          @copy ..\sys\share\lev_comp.h ..\include\lev_comp.h
+!ELSE
+          chdir ..\util
+          $(YACC) -d lev_comp.y
+          copy $(YTABC) $@
+          copy $(YTABH) ..\include\lev_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+          chdir ..\build
+!ENDIF
+
+..\util\lev_lex.c: ..\util\lev_comp.l
+!IF "$(LEX)"==""
+          @echo Using pre-built lev_lex.c
+          @copy ..\sys\share\lev_lex.c $@
+!ELSE
+          chdir ..\util
+          $(LEX) lev_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+          chdir ..\build
+!ENDIF
+
diff --git a/build/makedefs.dsp b/build/makedefs.dsp
new file mode 100644 (file)
index 0000000..5ecdc88
--- /dev/null
@@ -0,0 +1,198 @@
+# Microsoft Developer Studio Project File - Name="makedefs" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=makedefs - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "makedefs.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "makedefs.mak" CFG="makedefs - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "makedefs - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "makedefs - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "makedefs - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\util"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "." /I "..\include" /I "..\sys\winnt" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Running makedefs\r
+PostBuild_Cmds=echo chdir ..\util      chdir ..\util   chdir   \\r
+echo makedefs.exe -v   makedefs.exe -v \\r
+echo makedefs.exe -o   makedefs.exe  -o        \\r
+echo makedefs.exe -p   makedefs.exe -p \\r
+echo makedefs.exe -m   makedefs.exe -m \\r
+echo makedefs.exe -z   makedefs.exe -z \\r
+echo chdir ..\dat      chdir ..\dat    chdir   \\r
+echo Generating NetHack database       echo ..\util\makedefs.exe -d    ..\util\makedefs.exe -d \\r
+echo Generating rumors echo ..\util\makedefs.exe -r    ..\util\makedefs.exe -r \\r
+echo Generating quests echo ..\util\makedefs.exe -q    ..\util\makedefs.exe -q \\r
+echo Generating oracles        echo ..\util\makedefs.exe -h    ..\util\makedefs.exe -h \\r
+echo Generating dungeon.pdf    echo ..\util\makedefs.exe -e    ..\util\makedefs.exe -e \\r
+echo chdir ..\build    chdir ..\build  \\r
+copy ..\win\share\tilemap.c ..\win\share\tiletxt.c\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "makedefs - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\util"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "." /I "..\include" /I "..\sys\winnt" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /pdbtype:sept\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Running makedefs\r
+PostBuild_Cmds=echo chdir ..\util      chdir ..\util   chdir   \\r
+echo makedefs.exe -v   makedefs.exe -v \\r
+echo makedefs.exe -o   makedefs.exe  -o        \\r
+echo makedefs.exe -p   makedefs.exe -p \\r
+echo makedefs.exe -m   makedefs.exe -m \\r
+echo makedefs.exe -z   makedefs.exe -z \\r
+echo chdir ..\dat      chdir ..\dat    chdir   \\r
+echo Generating NetHack database       echo ..\util\makedefs.exe -d    ..\util\makedefs.exe -d \\r
+echo Generating rumors echo ..\util\makedefs.exe -r    ..\util\makedefs.exe -r \\r
+echo Generating quests echo ..\util\makedefs.exe -q    ..\util\makedefs.exe -q \\r
+echo Generating oracles        echo ..\util\makedefs.exe -h    ..\util\makedefs.exe -h \\r
+echo Generating dungeon.pdf    echo ..\util\makedefs.exe -e    ..\util\makedefs.exe -e \\r
+echo chdir ..\build    chdir ..\build  \\r
+copy ..\win\share\tilemap.c ..\win\share\tiletxt.c\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "makedefs - Win32 Release"\r
+# Name "makedefs - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\util\makedefs.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\monst.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\objects.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config1.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\coord.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\global.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monattk.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monflag.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monsym.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\nhlan.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\ntconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\objclass.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\patchlevel.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\qtext.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tradstdc.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/build/nethackw.dsp b/build/nethackw.dsp
new file mode 100644 (file)
index 0000000..03521aa
--- /dev/null
@@ -0,0 +1,1107 @@
+# Microsoft Developer Studio Project File - Name="NetHackW" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Application" 0x0101\r
+\r
+CFG=NetHackW - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "NetHackW.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "NetHackW.mak" CFG="NetHackW - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "NetHackW - Win32 Release" (based on "Win32 (x86) Application")\r
+!MESSAGE "NetHackW - Win32 Debug" (based on "Win32 (x86) Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "NetHackW - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /Og /Oy /Ob1 /Gs /Gf /Gy /Oi- /Ot  /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /W3 /GX /Og /Oy /Ob1 /Gs /Gf /Gy /Oi- /Ot  /I "..\win\win32" /I "..\include" /I "..\sys\winnt" /I "..\sys\share" /I "..\win\share" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib advapi32.lib winmm.lib /nologo /subsystem:windows /map /debug /machine:I386 /MAPINFO:EXPORTS /MAPINFO:LINES\r
+# SUBTRACT LINK32 /pdb:none\r
+# Begin Special Build Tool\r
+OutDir=.\Release\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Install exe\r
+PostBuild_Cmds=copy $(OutDir)\NetHackW.exe ..\binary   \\r
+copy ..\dat\nhdat ..\binary    \\r
+copy ..\dat\license ..\binary  \\r
+if exist tiles.bmp copy tiles.bmp ..\binary    \\r
+if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt        \\r
+if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt      \\r
+copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "NetHackW - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\win\win32" /I "..\include" /I "..\sys\winnt" /I "..\sys\share" /I "..\win\share" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib advapi32.lib winmm.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept\r
+# Begin Special Build Tool\r
+OutDir=.\Debug\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Install exe\r
+PostBuild_Cmds=if NOT exist ..\binary\*.* mkdir ..\binary      \\r
+copy $(OutDir)\NetHackW.exe ..\binary  \\r
+copy ..\dat\nhdat ..\binary    \\r
+copy ..\dat\license ..\binary  \\r
+if exist tiles.bmp copy tiles.bmp ..\binary    \\r
+if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt        \\r
+if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt      \\r
+copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "NetHackW - Win32 Release"\r
+# Name "NetHackW - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\src\allmain.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\alloc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\apply.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\artifact.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\attrib.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\ball.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\bones.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\botl.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\cmd.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dbridge.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\decl.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\detect.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dig.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\display.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dlb.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\do.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\do_name.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\do_wear.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dog.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dogmove.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dokick.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dothrow.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\drawing.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dungeon.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\eat.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\end.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\engrave.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\exper.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\explode.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\extralev.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\files.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\fountain.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\tty\getline.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\hack.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\hacklib.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\invent.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\light.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\lock.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mail.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\makemon.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mapglyph.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mcastu.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mhitm.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mhitu.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\minion.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mklev.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mkmap.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mkmaze.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mkobj.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mkroom.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mon.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mondata.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\monmove.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\monst.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\monstr.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mplayer.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mthrowu.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\muse.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\music.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\winnt\ntsound.c\r
+# End Source File\r
+# Begin Source File\r
\r
+SOURCE=..\src\o_init.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\objects.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\objnam.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\options.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\pager.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\share\pcmain.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\share\pcsys.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\share\pcunix.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\pickup.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\pline.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\polyself.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\potion.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\pray.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\priest.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\quest.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\questpgr.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\share\random.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\read.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rect.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\region.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\restore.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rip.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rnd.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\role.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rumors.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\save.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\shk.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\shknam.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\sit.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\sounds.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\sp_lev.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\spell.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\steal.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\steed.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\teleport.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\tile.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\timeout.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\topten.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\track.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\trap.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\u_init.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\uhitm.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\vault.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\version.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\vision.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\weapon.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\were.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\wield.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\windows.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\winnt\winnt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\tty\wintty.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\wizard.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\worm.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\worn.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\write.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\zap.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\align.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\amiconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\artifact.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\artilist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\attrib.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\beconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\bitmfile.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\color.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config1.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\coord.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\decl.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\def_os2.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dgn_file.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\display.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dlb.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dungeon.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\edog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\emin.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\engrave.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\epri.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\eshk.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\extern.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\flag.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\func_tab.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\gem_rsc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\global.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\hack.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\lev.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\load_img.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\macconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\macpopup.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mactty.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\macwin.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mail.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mfndpos.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\micro.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mkroom.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monattk.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mondata.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monflag.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monst.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monsym.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mttypriv.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\nhlan.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\ntconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\obj.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\objclass.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\os2conf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\patchlevel.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\pcconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\permonst.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\prop.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\qt_clust.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\qt_kde0.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\qt_win.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\qt_xpms.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\qtext.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\quest.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\rect.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\region.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\rm.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\skills.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\sp_lev.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\spell.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\system.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tcap.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tile2x11.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\timeout.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tosconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tradstdc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\trampoli.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\trap.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\unixconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\vault.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\vision.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\vmsconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\winami.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wingem.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\winGnome.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\winprocs.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wintty.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wintype.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\winX.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\xwindow.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\xwindowp.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\you.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\youprop.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\bitmap1.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\bitmap2.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mnsel.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mnunsel.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\NETHACK.ICO\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\small.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\tiles.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\winhack.ico\r
+# End Source File\r
+# End Group\r
+# Begin Group "wnd"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhaskyn.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhaskyn.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhdlg.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhdlg.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhfont.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhfont.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhinput.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhinput.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmain.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmain.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmap.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmap.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmenu.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmenu.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmsg.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmsgwnd.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmsgwnd.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhsplash.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhrip.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhsplash.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhrip.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhstatus.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhstatus.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhtext.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhtext.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mswproc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\resource.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\winhack.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\winhack.rc\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\winMS.h\r
+# End Source File\r
+# End Group\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\ReadMe.txt\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/build/recover.dsp b/build/recover.dsp
new file mode 100644 (file)
index 0000000..7052afa
--- /dev/null
@@ -0,0 +1,148 @@
+# Microsoft Developer Studio Project File - Name="recover" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=recover - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "recover.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "recover.mak" CFG="recover - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "recover - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "recover - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "recover - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"\r
+# ADD RSC /l 0x1009 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# Begin Special Build Tool\r
+OutDir=.\Release\r
+SOURCE="$(InputPath)"\r
+PostBuild_Cmds=copy $(OutDir)\recover.exe ..\binary    \\r
+if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "recover - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\include" /I "..\sys\winnt" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"\r
+# ADD RSC /l 0x1009 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# Begin Special Build Tool\r
+OutDir=.\Debug\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=install exe\r
+PostBuild_Cmds=copy $(OutDir)\recover.exe ..\binary    \\r
+if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "recover - Win32 Release"\r
+# Name "recover - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\util\recover.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config1.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\coord.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\global.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\nhlan.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\ntconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tradstdc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\winnt\win32api.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/build/tile2bmp.dsp b/build/tile2bmp.dsp
new file mode 100644 (file)
index 0000000..5a534e2
--- /dev/null
@@ -0,0 +1,146 @@
+# Microsoft Developer Studio Project File - Name="tile2bmp" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=tile2bmp - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "tile2bmp.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "tile2bmp.mak" CFG="tile2bmp - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "tile2bmp - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "tile2bmp - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "tile2bmp - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /I "..\win\share" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"\r
+# ADD RSC /l 0x1009 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\tile2bmp.exe"\r
+\r
+!ELSEIF  "$(CFG)" == "tile2bmp - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt" /I "..\win\share" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"\r
+# ADD RSC /l 0x1009 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\util\tile2bmp.exe" /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "tile2bmp - Win32 Release"\r
+# Name "tile2bmp - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\src\decl.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\drawing.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\monst.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\objects.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\share\tile2bmp.c\r
+\r
+!IF  "$(CFG)" == "tile2bmp - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "tile2bmp - Win32 Debug"\r
+\r
+# ADD CPP /D "PACKED_FILE"\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\share\tiletext.c\r
+\r
+!IF  "$(CFG)" == "tile2bmp - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "tile2bmp - Win32 Debug"\r
+\r
+# ADD CPP /Zi\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\share\tiletxt.c\r
+# ADD CPP /D "TILETEXT"\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/build/tilemap.dsp b/build/tilemap.dsp
new file mode 100644 (file)
index 0000000..37d71ef
--- /dev/null
@@ -0,0 +1,281 @@
+# Microsoft Developer Studio Project File - Name="tilemap" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=tilemap - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "tilemap.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "tilemap.mak" CFG="tilemap - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "tilemap - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "tilemap - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "tilemap - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt\include" /I "..\win\share" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"\r
+# ADD RSC /l 0x1009 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\tilemap.exe"\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Generating src\tile.c\r
+PostBuild_Cmds=echo chdir ..\src       chdir ..\src    ..\util\tilemap.exe     echo chdir ..\build     chdir ..\build\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "tilemap - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt\include" /I "..\win\share" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"\r
+# ADD RSC /l 0x1009 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"..\util\tilemap.exe" /pdbtype:sept\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Generating src\tile.c\r
+PostBuild_Cmds=echo chdir ..\src       chdir ..\src    ..\util\tilemap.exe     echo chdir ..\build     chdir ..\build\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "tilemap - Win32 Release"\r
+# Name "tilemap - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\win\share\tilemap.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\align.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\attrib.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\color.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config1.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\coord.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\decl.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dgn_comp.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dgn_file.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\display.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dungeon.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\engrave.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\flag.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\global.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mkroom.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monattk.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monst.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monsym.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\nhlan.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\ntconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\obj.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\objclass.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\onames.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\permonst.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\pm.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\prop.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\quest.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\rect.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\region.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\rm.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\skills.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\spell.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\timeout.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tradstdc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\trampoli.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\trap.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\vision.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\winprocs.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wintty.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wintype.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\you.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\youprop.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/build/tiles.dsp b/build/tiles.dsp
new file mode 100644 (file)
index 0000000..ab2207a
--- /dev/null
@@ -0,0 +1,97 @@
+# Microsoft Developer Studio Project File - Name="tiles" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) External Target" 0x0106\r
+\r
+CFG=tiles - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "tiles.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "tiles.mak" CFG="tiles - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "tiles - Win32 Release" (based on "Win32 (x86) External Target")\r
+!MESSAGE "tiles - Win32 Debug" (based on "Win32 (x86) External Target")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+\r
+!IF  "$(CFG)" == "tiles - Win32 Release"\r
+\r
+# PROP BASE Use_MFC\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Cmd_Line "NMAKE /f tiles.mak"\r
+# PROP BASE Rebuild_Opt "/a"\r
+# PROP BASE Target_File "tiles.exe"\r
+# PROP BASE Bsc_Name "tiles.bsc"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Cmd_Line "nmake /f "tiles.mak""\r
+# PROP Rebuild_Opt "/a"\r
+# PROP Target_File "..\win\win32\tiles.bmp"\r
+# PROP Bsc_Name ""\r
+# PROP Target_Dir ""\r
+\r
+!ELSEIF  "$(CFG)" == "tiles - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Cmd_Line "NMAKE /f tiles.mak"\r
+# PROP BASE Rebuild_Opt "/a"\r
+# PROP BASE Target_File "tiles.exe"\r
+# PROP BASE Bsc_Name "tiles.bsc"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Cmd_Line "nmake /f "tiles.mak""\r
+# PROP Rebuild_Opt "/a"\r
+# PROP Target_File "..\win\win32\tiles.bmp"\r
+# PROP Bsc_Name ""\r
+# PROP Target_Dir ""\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "tiles - Win32 Release"\r
+# Name "tiles - Win32 Debug"\r
+\r
+!IF  "$(CFG)" == "tiles - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "tiles - Win32 Debug"\r
+\r
+!ENDIF \r
+\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/build/tiles.mak b/build/tiles.mak
new file mode 100644 (file)
index 0000000..26af1ea
--- /dev/null
@@ -0,0 +1,21 @@
+default: all
+
+all: ..\win\win32\tiles.bmp
+
+clean:
+       -del ..\src\win\win32\tiles.bmp
+       -del ..\win\win32\tiles.bmp
+
+#==========================================
+# Building the tiles file tile.bmp
+#==========================================
+
+..\src\tiles.bmp : ..\win\share\monsters.txt ..\win\share\objects.txt \
+                        ..\win\share\other.txt
+          chdir ..\src
+          ..\util\tile2bmp.exe tiles.bmp
+          chdir ..\build
+
+..\win\win32\tiles.bmp: ..\src\tiles.bmp
+       @copy ..\src\tiles.bmp ..\win\win32\tiles.bmp
+
diff --git a/build/uudecode.dsp b/build/uudecode.dsp
new file mode 100644 (file)
index 0000000..a9cf1be
--- /dev/null
@@ -0,0 +1,146 @@
+# Microsoft Developer Studio Project File - Name="uudecode" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=uudecode - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "uudecode.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "uudecode.mak" CFG="uudecode - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "uudecode - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "uudecode - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "uudecode - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\uudecode.exe"\r
+# SUBTRACT LINK32 /nodefaultlib\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Cmds=echo chdir ..\win\win32 chdir ..\win\win32      \\r
+echo decoding icon (nhico.uu to NetHack.ico)   \\r
+..\..\util\uudecode.exe ../../sys/winnt/nhico.uu       \\r
+echo decoding mnsel (mnsel.uu to mnsel.bmp)    \\r
+..\..\util\uudecode.exe mnsel.uu       \\r
+echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp)   \\r
+..\..\util\uudecode.exe mnselcnt.uu    \\r
+echo decoding mnunsel (mnunsel.uu to mnunsel.bmp)      \\r
+..\..\util\uudecode.exe mnunsel.uu     \\r
+echo decoding petmark (petmark.uu to petmark.bmp)      \\r
+..\..\util\uudecode.exe petmark.uu     \\r
+echo decoding splash (splash.uu to splash.bmp) \\r
+..\..\util\uudecode.exe splash.uu      \\r
+echo decoding tombstone (rip.uu to rip.bmp)    \\r
+..\..\util\uudecode.exe rip.uu \\r
+chdir ..\..\binary\r
+\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "uudecode - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ  /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ  /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\util\uudecode.exe" /pdbtype:sept\r
+# SUBTRACT LINK32 /nodefaultlib\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Cmds=echo chdir ..\win\win32 chdir ..\win\win32      \\r
+echo decoding icon (nhico.uu to NetHack.ico)   \\r
+..\..\util\uudecode.exe ../../sys/winnt/nhico.uu       \\r
+echo decoding mnsel (mnsel.uu to mnsel.bmp)    \\r
+..\..\util\uudecode.exe mnsel.uu       \\r
+echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp)   \\r
+..\..\util\uudecode.exe mnselcnt.uu    \\r
+echo decoding mnunsel (mnunsel.uu to mnunsel.bmp)      \\r
+..\..\util\uudecode.exe mnunsel.uu     \\r
+echo decoding petmark (petmark.uu to petmark.bmp)      \\r
+..\..\util\uudecode.exe petmark.uu     \\r
+echo decoding splash (splash.uu to splash.bmp) \\r
+..\..\util\uudecode.exe splash.uu      \\r
+echo decoding tombstone (rip.uu to rip.bmp)    \\r
+..\..\util\uudecode.exe rip.uu \\r
+chdir ..\..\binary\r
+\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "uudecode - Win32 Release"\r
+# Name "uudecode - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\share\uudecode.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/dat/Arch.des b/dat/Arch.des
new file mode 100644 (file)
index 0000000..414cf50
--- /dev/null
@@ -0,0 +1,460 @@
+#      SCCS Id: @(#)Arch.des   3.4     1997/01/31
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1991 by M. Stephenson
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The "start" level for the quest.
+#
+#      Here you meet your (besieged) class leader, Lord Carnarvon
+#      and receive your quest assignment.
+#
+MAZE: "Arc-strt",' '
+FLAGS: noteleport,hardfloor
+GEOMETRY:center,center
+MAP
+............................................................................
+............................................................................
+............................................................................
+............................................................................
+....................}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}.................
+....................}-------------------------------------}.................
+....................}|..S......+.................+.......|}.................
+....................}-S---------------+----------|.......|}.................
+....................}|.|...............|.......+.|.......|}.................
+....................}|.|...............---------.---------}.................
+....................}|.S.\.............+.................+..................
+....................}|.|...............---------.---------}.................
+....................}|.|...............|.......+.|.......|}.................
+....................}-S---------------+----------|.......|}.................
+....................}|..S......+.................+.......|}.................
+....................}-------------------------------------}.................
+....................}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}.................
+............................................................................
+............................................................................
+............................................................................
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+REGION: (22,06,23,06),unlit,"ordinary"
+REGION: (25,06,30,06),unlit,"ordinary"
+REGION: (32,06,48,06),unlit,"ordinary"
+REGION: (50,06,56,08),lit,"ordinary"
+REGION: (40,08,46,08),unlit,"ordinary"
+REGION: (22,08,22,12),unlit,"ordinary"
+REGION: (24,08,38,12),unlit,"ordinary"
+REGION: (48,08,48,08),lit,"ordinary"
+REGION: (40,10,56,10),lit,"ordinary"
+REGION: (48,12,48,12),lit,"ordinary"
+REGION: (40,12,46,12),unlit,"ordinary"
+REGION: (50,12,56,14),lit,"ordinary"
+REGION: (22,14,23,14),unlit,"ordinary"
+REGION: (25,14,30,14),unlit,"ordinary"
+REGION: (32,14,48,14),unlit,"ordinary"
+# Stairs
+STAIR:(55,07),down
+# Portal arrival point
+BRANCH:(63,06,63,06),(0,0,0,0)
+# Doors
+DOOR:closed,(22,07)
+DOOR:closed,(38,07)
+DOOR:locked,(47,08)
+DOOR:locked,(23,10)
+DOOR:locked,(39,10)
+DOOR:locked,(57,10)
+DOOR:locked,(47,12)
+DOOR:closed,(22,13)
+DOOR:closed,(38,13)
+DOOR:locked,(24,14)
+DOOR:closed,(31,14)
+DOOR:locked,(49,14)
+# Lord Carnarvon
+MONSTER:'@',"Lord Carnarvon",(25,10)
+# The treasure of Lord Carnarvon
+OBJECT:'(',"chest",(25,10)
+# student guards for the audience chamber
+MONSTER:'@',"student",(26,09)
+MONSTER:'@',"student",(27,09)
+MONSTER:'@',"student",(28,09)
+MONSTER:'@',"student",(26,10)
+MONSTER:'@',"student",(28,10)
+MONSTER:'@',"student",(26,11)
+MONSTER:'@',"student",(27,11)
+MONSTER:'@',"student",(28,11)
+# city watch guards in the antechambers
+MONSTER:'@',"watchman",(50,06)
+MONSTER:'@',"watchman",(50,14)
+# Eels in the moat
+MONSTER:';',"giant eel",(20,10)
+MONSTER:';',"giant eel",(45,04)
+MONSTER:';',"giant eel",(33,16)
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Monsters on siege duty.
+MONSTER: 'S',random,(60,09)
+MONSTER: 'M',random,(60,10)
+MONSTER: 'S',random,(60,11)
+MONSTER: 'S',random,(60,12)
+MONSTER: 'M',random,(60,13)
+MONSTER: 'S',random,(61,10)
+MONSTER: 'S',random,(61,11)
+MONSTER: 'S',random,(61,12)
+MONSTER: 'S',random,(30,03)
+MONSTER: 'M',random,(20,17)
+MONSTER: 'S',random,(67,02)
+MONSTER: 'S',random,(10,19)
+
+#
+#      The "locate" level for the quest.
+#
+#      Here you have to find the Entrance to the Tomb of the Toltec Kings
+#      to go further towards your assigned quest.
+#
+
+MAZE: "Arc-loca",' '
+FLAGS: hardfloor
+GEOMETRY:center,center
+MAP
+............................................................................
+............................................................................
+............................................................................
+........................-------------------------------.....................
+........................|....|.S......................|.....................
+........................|....|.|.|+------------------.|.....................
+........................|....|.|.|.|.........|......|.|.....................
+........................|....|.|.|.|.........|......|.|.....................
+........................|---+-.|.|.|..---....+......|.|.....................
+........................|....|.|.|.---|.|....|......|.|.....................
+........................|....S.|.|.+..S.|--S-----S--|.|.....................
+........................|....|.|.|.---|.|....|......+.|.....................
+........................|---+-.|.|.|..---....|.------.|.....................
+........................|....|.|.|.|.........|.|....+.|.....................
+........................|....|.|.|.|.........|+|....|-|.....................
+........................|....|.|.|------------+------.S.....................
+........................|....|.S......................|.....................
+........................-------------------------------.....................
+............................................................................
+............................................................................
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+REGION:(25,04,28,07),lit,"temple"
+REGION:(25,09,28,11),unlit,"temple"
+REGION:(25,13,28,16),lit,"temple"
+REGION:(30,04,30,16),lit,"ordinary"
+REGION:(32,04,32,16),unlit,"ordinary"
+REGION:(33,04,53,04),unlit,"ordinary",unfilled,true
+REGION:(36,10,37,10),unlit,"ordinary"
+REGION:(39,09,39,11),unlit,"ordinary"
+REGION:(36,06,42,08),unlit,"ordinary",unfilled,true
+REGION:(36,12,42,14),unlit,"ordinary",unfilled,true
+REGION:(46,06,51,09),unlit,"ordinary"
+REGION:(46,11,49,11),unlit,"ordinary",unfilled,true
+REGION:(48,13,51,14),unlit,"ordinary"
+# Doors
+DOOR:closed,(31,04)
+DOOR:closed,(28,08)
+DOOR:locked,(29,10)
+DOOR:closed,(28,12)
+DOOR:closed,(31,16)
+DOOR:locked,(34,05)
+DOOR:locked,(35,10)
+DOOR:locked,(38,10)
+DOOR:closed,(43,10)
+DOOR:closed,(45,08)
+DOOR:locked,(46,14)
+DOOR:locked,(46,15)
+DOOR:locked,(49,10)
+DOOR:locked,(52,11)
+DOOR:closed,(52,13)
+DOOR:closed,(54,15)
+# Stairs
+STAIR:(03,17),up
+STAIR:(39,10),down
+# Altars - three types.  All are unattended.
+ALTAR:(26,05),align[0],altar
+ALTAR:(26,10),align[1],altar
+ALTAR:(26,15),align[2],altar
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Treasure?
+ENGRAVING:random,engrave,"X marks the spot."
+ENGRAVING:random,engrave,"X marks the spot."
+ENGRAVING:random,engrave,"X marks the spot."
+ENGRAVING:random,engrave,"X marks the spot."
+# Random traps
+TRAP:"spiked pit",(24,02)
+TRAP:"spiked pit",(37,00)
+TRAP:"spiked pit",(23,05)
+TRAP:"spiked pit",(26,19)
+TRAP:"spiked pit",(55,10)
+TRAP:"spiked pit",(55,08)
+TRAP:"pit",(51,01)
+TRAP:"pit",(23,18)
+TRAP:"pit",(31,18)
+TRAP:"pit",(48,19)
+TRAP:"pit",(55,15)
+TRAP:"magic",(60,04)
+TRAP:"statue",(72,07)
+TRAP:"statue",random
+TRAP:"statue",random
+TRAP:"anti magic",(64,12)
+TRAP:"sleep gas",random
+TRAP:"sleep gas",random
+TRAP:"dart",random
+TRAP:"dart",random
+TRAP:"dart",random
+TRAP:"rolling boulder",(32,10)
+TRAP:"rolling boulder",(40,16)
+# Random monsters.
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'M',random,random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',random,random
+
+#
+#      The "goal" level for the quest.
+#
+#      Here you meet Minion of Huhetotl your nemesis monster.  You have to
+#      defeat Minion of Huhetotl in combat to gain the artifact you have
+#      been assigned to retrieve.
+#
+
+MAZE: "Arc-goal", ' '
+GEOMETRY:center,center
+MAP
+                                                                            
+                                  ---------                                 
+                                  |..|.|..|                                 
+                       -----------|..S.S..|-----------                      
+                       |.|........|+-|.|-+|........|.|                      
+                       |.S........S..|.|..S........S.|                      
+                       |.|........|..|.|..|........|.|                      
+                    ------------------+------------------                   
+                    |..|..........|.......|..........|..|                   
+                    |..|..........+.......|..........S..|                   
+                    |..S..........|.......+..........|..|                   
+                    |..|..........|.......|..........|..|                   
+                    ------------------+------------------                   
+                       |.|........|..|.|..|........|.|                      
+                       |.S........S..|.|..S........S.|                      
+                       |.|........|+-|.|-+|........|.|                      
+                       -----------|..S.S..|-----------                      
+                                  |..|.|..|                                 
+                                  ---------                                 
+                                                                            
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+REGION:(35,02,36,03),unlit,"ordinary"
+REGION:(40,02,41,03),unlit,"ordinary"
+REGION:(24,04,24,06),unlit,"ordinary"
+REGION:(26,04,33,06),lit,"ordinary"
+REGION:(38,02,38,06),unlit,"ordinary"
+REGION:(43,04,50,06),lit,"ordinary"
+REGION:(52,04,52,06),unlit,"ordinary"
+REGION:(35,05,36,06),unlit,"ordinary"
+REGION:(40,05,41,06),unlit,"ordinary"
+REGION:(21,08,22,11),unlit,"ordinary"
+REGION:(24,08,33,11),lit,"ordinary"
+REGION:(35,08,41,11),unlit,"ordinary"
+REGION:(43,08,52,11),lit,"ordinary"
+REGION:(54,08,55,11),unlit,"ordinary"
+REGION:(24,13,24,15),unlit,"ordinary"
+REGION:(26,13,33,15),unlit,"ordinary"
+REGION:(35,13,36,14),unlit,"ordinary"
+REGION:(35,16,36,17),unlit,"ordinary"
+REGION:(38,13,38,17),unlit,"ordinary"
+REGION:(40,13,41,14),unlit,"ordinary"
+REGION:(40,16,41,17),unlit,"ordinary"
+REGION:(43,13,50,15),unlit,"temple"
+REGION:(52,13,52,15),unlit,"ordinary"
+# Stairs
+STAIR:(38,10),up
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# The altar of Huhetotl.  Unattended.
+ALTAR:(50,14),chaos,altar
+# Objects
+OBJECT:'(',"crystal ball",(50,14),blessed,5,"The Orb of Detection"
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:"rolling boulder",(46,14)
+# Random monsters.
+MONSTER:'&',"Minion of Huhetotl",(50,14)
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'S',random,random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',"human mummy",random
+MONSTER:'M',random,random
+
+#
+#      The "fill" levels for the quest.
+#
+#      These levels are used to fill out any levels not occupied by specific
+#      levels as defined above. "filla" is the upper filler, between the
+#      start and locate levels, and "fillb" the lower between the locate
+#      and goal levels.
+#
+
+LEVEL: "Arc-fila"
+#
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+OBJECT: random,random,random
+MONSTER: 'S', random, random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random,random,random
+MONSTER: 'S', random, random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+OBJECT: random,random,random
+MONSTER: 'S', random, random
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'S', random, random
+MONSTER: 'M', "human mummy", random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'S', random, random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'S', random, random
+
+RANDOM_CORRIDORS
+
+LEVEL: "Arc-filb"
+#
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+OBJECT: random,random,random
+MONSTER: 'M', random, random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random,random,random
+MONSTER: 'M', random, random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+OBJECT: random,random,random
+MONSTER: 'M', random, random
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'S', random, random
+MONSTER: 'M', "human mummy", random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'S', random, random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'S', random, random
+
+RANDOM_CORRIDORS
diff --git a/dat/Barb.des b/dat/Barb.des
new file mode 100644 (file)
index 0000000..c746295
--- /dev/null
@@ -0,0 +1,368 @@
+#      SCCS Id: @(#)Barb.des   3.4     1991/12/22
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1991 by M. Stephenson
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The "start" level for the quest.
+#
+#      Here you meet your (besieged) class leader, Pelias,
+#      and receive your quest assignment.
+#
+MAZE: "Bar-strt",' '
+FLAGS: noteleport,hardfloor
+GEOMETRY:center,center
+MAP
+..................................PP........................................
+...................................PP.......................................
+...................................PP.......................................
+....................................PP......................................
+........--------------......-----....PPP....................................
+........|...S........|......+...|...PPP.....................................
+........|----........|......|...|....PP.....................................
+........|.\..........+......-----...........................................
+........|----........|...............PP.....................................
+........|...S........|...-----.......PPP....................................
+........--------------...+...|......PPPPP...................................
+.........................|...|.......PPP....................................
+...-----......-----......-----........PP....................................
+...|...+......|...+..--+--.............PP...................................
+...|...|......|...|..|...|..............PP..................................
+...-----......-----..|...|.............PPPP.................................
+.....................-----............PP..PP................................
+.....................................PP...PP................................
+....................................PP...PP.................................
+....................................PP....PP................................
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+REGION:(09,05,11,05),unlit,"ordinary"
+REGION:(09,07,11,07),lit,"ordinary"
+REGION:(09,09,11,09),unlit,"ordinary"
+REGION:(13,05,20,09),lit,"ordinary"
+REGION:(29,05,31,06),lit,"ordinary"
+REGION:(26,10,28,11),lit,"ordinary"
+REGION:(04,13,06,14),lit,"ordinary"
+REGION:(15,13,17,14),lit,"ordinary"
+REGION:(22,14,24,15),lit,"ordinary"
+# Stairs
+STAIR:(09,09),down
+# Portal arrival point
+BRANCH:(62,02,62,02),(0,0,0,0)
+# Doors
+DOOR:locked,(12,05)
+DOOR:locked,(12,09)
+DOOR:closed,(21,07)
+DOOR:open,(07,13)
+DOOR:open,(18,13)
+DOOR:open,(23,13)
+DOOR:open,(25,10)
+DOOR:open,(28,05)
+# Elder
+MONSTER:'@',"Pelias",(10,07)
+# The treasure of Pelias
+OBJECT:'(',"chest",(09,05)
+# chieftain guards for the audience chamber
+MONSTER:'@',"chieftain",(10,05)
+MONSTER:'@',"chieftain",(10,09)
+MONSTER:'@',"chieftain",(11,05)
+MONSTER:'@',"chieftain",(11,09)
+MONSTER:'@',"chieftain",(14,05)
+MONSTER:'@',"chieftain",(14,09)
+MONSTER:'@',"chieftain",(16,05)
+MONSTER:'@',"chieftain",(16,09)
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# One trap to keep the ogres at bay.
+TRAP:"spiked pit",(37,07)
+# Eels in the river
+MONSTER:';',"giant eel",(36,01)
+MONSTER:';',"giant eel",(37,09)
+MONSTER:';',"giant eel",(39,15)
+# Monsters on siege duty.
+MONSTER:'O',"ogre",(40,08),hostile
+MONSTER:'O',"ogre",(41,06),hostile
+MONSTER:'O',"ogre",(41,07),hostile
+MONSTER:'O',"ogre",(41,08),hostile
+MONSTER:'O',"ogre",(41,09),hostile
+MONSTER:'O',"ogre",(41,10),hostile
+MONSTER:'O',"ogre",(42,06),hostile
+MONSTER:'O',"ogre",(42,07),hostile
+MONSTER:'O',"ogre",(42,08),hostile
+MONSTER:'O',"ogre",(42,09),hostile
+MONSTER:'O',"ogre",(42,10),hostile
+
+#
+#      The "locate" level for the quest.
+#
+#      Here you have to infiltrate the Duali Oasis to go
+#      further towards your assigned quest.
+#
+
+MAZE: "Bar-loca",' '
+FLAGS: hardfloor
+GEOMETRY:center,center
+MAP
+..........PPP.........................................                      
+...........PP..........................................        .......      
+..........PP...........-----..........------------------     ..........     
+...........PP..........+...|..........|....S...........|..  ............    
+..........PPP..........|...|..........|-----...........|...  .............  
+...........PPP.........-----..........+....+...........|...  .............  
+..........PPPPPPPPP...................+....+...........S.................   
+........PPPPPPPPPPPPP.........-----...|-----...........|................    
+......PPPPPPPPPPPPPP..P.......+...|...|....S...........|          ...       
+.....PPPPPPP......P..PPPP.....|...|...------------------..         ...      
+....PPPPPPP.........PPPPPP....-----........................      ........   
+...PPPPPPP..........PPPPPPP..................................   ..........  
+....PPPPPPP........PPPPPPP....................................  ..........  
+.....PPPPP........PPPPPPP.........-----........................   ........  
+......PPP..PPPPPPPPPPPP...........+...|.........................    .....   
+..........PPPPPPPPPPP.............|...|.........................     ....   
+..........PPPPPPPPP...............-----.........................       .    
+..............PPP.................................................          
+...............PP....................................................       
+................PPP...................................................      
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+REGION:(24,03,26,04),unlit,"ordinary"
+REGION:(31,08,33,09),unlit,"ordinary"
+REGION:(35,14,37,15),unlit,"ordinary"
+REGION:(39,03,54,08),lit,"ordinary"
+REGION:(56,00,75,08),unlit,"ordinary"
+REGION:(64,09,75,16),unlit,"ordinary"
+# Doors
+DOOR:open,(23,03)
+DOOR:open,(30,08)
+DOOR:open,(34,14)
+DOOR:locked,(38,05)
+DOOR:locked,(38,06)
+DOOR:closed,(43,03)
+DOOR:closed,(43,05)
+DOOR:closed,(43,06)
+DOOR:closed,(43,08)
+DOOR:locked,(55,06)
+# Stairs
+STAIR:(05,02),up
+STAIR:(70,13),down
+# Objects
+OBJECT:random,random,(42,03)
+OBJECT:random,random,(42,03)
+OBJECT:random,random,(42,03)
+OBJECT:random,random,(41,03)
+OBJECT:random,random,(41,03)
+OBJECT:random,random,(41,03)
+OBJECT:random,random,(41,03)
+OBJECT:random,random,(41,08)
+OBJECT:random,random,(41,08)
+OBJECT:random,random,(42,08)
+OBJECT:random,random,(42,08)
+OBJECT:random,random,(42,08)
+OBJECT:random,random,(71,13)
+OBJECT:random,random,(71,13)
+OBJECT:random,random,(71,13)
+# Random traps
+TRAP:"spiked pit",(10,13)
+TRAP:"spiked pit",(21,07)
+TRAP:"spiked pit",(67,08)
+TRAP:"spiked pit",(68,09)
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'O',"ogre",(12,09),hostile
+MONSTER:'O',"ogre",(18,11),hostile
+MONSTER:'O',"ogre",(45,05),hostile
+MONSTER:'O',"ogre",(45,06),hostile
+MONSTER:'O',"ogre",(47,05),hostile
+MONSTER:'O',"ogre",(46,05),hostile
+MONSTER:'O',"ogre",(56,03),hostile
+MONSTER:'O',"ogre",(56,04),hostile
+MONSTER:'O',"ogre",(56,05),hostile
+MONSTER:'O',"ogre",(56,06),hostile
+MONSTER:'O',"ogre",(57,03),hostile
+MONSTER:'O',"ogre",(57,04),hostile
+MONSTER:'O',"ogre",(57,05),hostile
+MONSTER:'O',"ogre",(57,06),hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',random,random,hostile
+MONSTER:'T',random,random,hostile
+MONSTER:'T',"rock troll",(46,06),hostile
+MONSTER:'T',"rock troll",(47,06),hostile
+MONSTER:'T',"rock troll",(56,07),hostile
+MONSTER:'T',"rock troll",(57,07),hostile
+MONSTER:'T',"rock troll",(70,13),hostile
+MONSTER:'T',"rock troll",random,hostile
+MONSTER:'T',"rock troll",random,hostile
+MONSTER:'T',random,random,hostile
+
+#
+#      The "goal" level for the quest.
+#
+#      Here you meet Thoth Amon, your nemesis monster.  You have to
+#      defeat Thoth Amon in combat to gain the artifact you have
+#      been assigned to retrieve.
+#
+
+MAZE: "Bar-goal", ' '
+GEOMETRY:center,center
+MAP
+                                                                            
+                               .............                                
+                             ..................                             
+        ....              .........................          ....           
+      .......          ..........................           .......         
+      ......             ........................          .......          
+      ..  ......................................             ..             
+       ..                 .....................             ..              
+        ..                 ..................              ..               
+         ..         ..S...S..............   ................                
+          ..                   ........                ...                  
+       .........                                         ..                 
+       ......  ..                                         ...  ....         
+      .. ...    ..                             ......       ........        
+   ....          .. ..................        ........       ......         
+  ......          ......................       ......         ..            
+   ....             ..................              ...........             
+                      ..............                                        
+                        ...........                                         
+                                                                            
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),unlit,"ordinary"
+# Secret doors
+DOOR:locked,(22,09)
+DOOR:locked,(26,09)
+# Stairs
+STAIR:(36,05),up
+# The altar.  Unattended.
+ALTAR:(63,04),noncoaligned,altar
+NON_DIGGABLE:(00,00,75,19)
+# Objects
+OBJECT:'*',"luckstone",(63,04),blessed,0,"The Heart of Ahriman"
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'@',"Thoth Amon",(63,04),hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',"ogre",random,hostile
+MONSTER:'O',random,random,hostile
+MONSTER:'O',random,random,hostile
+MONSTER:'T',"rock troll",random,hostile
+MONSTER:'T',"rock troll",random,hostile
+MONSTER:'T',"rock troll",random,hostile
+MONSTER:'T',"rock troll",random,hostile
+MONSTER:'T',"rock troll",random,hostile
+MONSTER:'T',"rock troll",random,hostile
+MONSTER:'T',"rock troll",random,hostile
+MONSTER:'T',"rock troll",random,hostile
+MONSTER:'T',random,random,hostile
+WALLIFY
+
+#
+#      The "fill" levels for the quest.
+#
+#      These levels are used to fill out any levels not occupied by specific
+#      levels as defined above. "filla" is the upper filler, between the
+#      start and locate levels, and "fillb" the lower between the locate
+#      and goal levels.
+#
+
+MAZE: "Bar-fila" , ' '
+INIT_MAP: '.' , '.' , true , true , unlit , false
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+#
+MONSTER: 'O', "ogre", random, hostile
+MONSTER: 'O', "ogre", random, hostile
+MONSTER: 'O', random, random, hostile
+MONSTER: 'T', "rock troll", random, hostile
+
+MAZE: "Bar-filb" , ' '
+INIT_MAP: '.' , ' ' , true , true , unlit , true
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+#
+MONSTER: 'O', "ogre", random, hostile
+MONSTER: 'O', "ogre", random, hostile
+MONSTER: 'O', "ogre", random, hostile
+MONSTER: 'O', "ogre", random, hostile
+MONSTER: 'O', "ogre", random, hostile
+MONSTER: 'O', "ogre", random, hostile
+MONSTER: 'O', "ogre", random, hostile
+MONSTER: 'O', random , random, hostile
+MONSTER: 'T', "rock troll", random, hostile
+MONSTER: 'T', "rock troll", random, hostile
+MONSTER: 'T', "rock troll", random, hostile
+MONSTER: 'T', random , random, hostile
diff --git a/dat/Caveman.des b/dat/Caveman.des
new file mode 100644 (file)
index 0000000..3f408fe
--- /dev/null
@@ -0,0 +1,316 @@
+#      SCCS Id: @(#)Caveman.des        3.4     1995/10/07
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1991 by M. Stephenson
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The "start" level for the quest.
+#
+#      Here you meet your (besieged) class leader, Shaman Karnov
+#      and receive your quest assignment.
+#
+MAZE: "Cav-strt",' '
+FLAGS: noteleport,hardfloor
+GEOMETRY:center,center
+MAP
+                                                                            
+  ......     ..........................       ...        ....  ......       
+ ......       ..........................     ........       ....    .....   
+  ..BB      .............................    .........            ....  ..  
+     ..    ......................              .......      ..     ....  .. 
+     ..     ....................                     ..  .......    ..  ... 
+   ..              S   BB                .....     .......   ....      .... 
+    ..        ...  .   ..               ........  ..     ..   ..       ...  
+     ..      ......     ..             ............       ..          ...   
+       .      ....       ..             ........           ..  ...........  
+  ...   ..     ..        .............                  ................... 
+ .....   .....            ...............................      ...........  
+  .....B................            ...                               ...   
+  .....     .  ..........        .... .      ...  ..........           ...  
+   ...     ..          .............  ..    ...................        .... 
+          BB       ..   .........      BB    ...  ..........  ..   ...  ... 
+       ......    .....  B          ........         ..         .. ....  ... 
+     ..........  ..........         ..... ...      .....        ........    
+       ..  ...    .  .....         ....    ..       ...            ..       
+                                                                            
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),unlit,"ordinary"
+REGION:(13,01,40,05),lit,"temple",unfilled,true
+# The occupied rooms.
+REGION:(02,01,08,03),lit,"ordinary",unfilled,true
+REGION:(01,11,06,14),lit,"ordinary",unfilled,true
+REGION:(13,08,18,10),lit,"ordinary",unfilled,true
+REGION:(05,17,14,18),lit,"ordinary",unfilled,true
+REGION:(17,16,23,18),lit,"ordinary",unfilled,true
+REGION:(35,16,44,18),lit,"ordinary",unfilled,true
+# Stairs
+STAIR:(02,03),down
+# Portal arrival point
+BRANCH:(71,09,71,09),(0,0,0,0)
+# Doors
+DOOR:locked,(19,06)
+# The temple altar (this will force a priest(ess) to be created)
+ALTAR:(36,02),coaligned,shrine
+# Shaman Karnov
+MONSTER:'@',"Shaman Karnov",(35,02)
+# The treasure of Shaman Karnov
+OBJECT:'(',"chest",(34,02)
+# neanderthal guards for the audience chamber
+MONSTER:'@',"neanderthal",(20,03)
+MONSTER:'@',"neanderthal",(20,02)
+MONSTER:'@',"neanderthal",(20,01)
+MONSTER:'@',"neanderthal",(21,03)
+MONSTER:'@',"neanderthal",(21,02)
+MONSTER:'@',"neanderthal",(21,01)
+MONSTER:'@',"neanderthal",(22,01)
+MONSTER:'@',"neanderthal",(26,09)
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Random traps
+TRAP:"pit",(47,11)
+TRAP:"pit",(57,10)
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Monsters on siege duty (in the outer caves).
+MONSTER: 'h',"bugbear",(47,02),hostile
+MONSTER: 'h',"bugbear",(48,03),hostile
+MONSTER: 'h',"bugbear",(49,04),hostile
+MONSTER: 'h',"bugbear",(67,03),hostile
+MONSTER: 'h',"bugbear",(69,04),hostile
+MONSTER: 'h',"bugbear",(51,13),hostile
+MONSTER: 'h',"bugbear",(53,14),hostile
+MONSTER: 'h',"bugbear",(55,15),hostile
+MONSTER: 'h',"bugbear",(63,10),hostile
+MONSTER: 'h',"bugbear",(65,09),hostile
+MONSTER: 'h',"bugbear",(67,10),hostile
+MONSTER: 'h',"bugbear",(69,11),hostile
+WALLIFY
+
+#
+#      The "locate" level for the quest.
+#
+#      Here you have to find the lair of Tiamat to go
+#      further towards your assigned quest.
+#
+
+MAZE: "Cav-loca",' '
+FLAGS: hardfloor
+GEOMETRY:center,center
+MAP
+                                                                            
+    .............                     ...........                           
+   ...............                   .............                          
+    .............                  ...............        ..........        
+     ...........                    .............      ...............      
+        ...                                    ...   ..................     
+         ...                ..........          ... ..................      
+          ...              ............          BBB...................     
+           ...              ..........          ......................      
+            .....                 ..      .....B........................    
+  ....       ...............      .    ........B..........................  
+ ......     .. .............S..............         ..................      
+  ....     ..                ...........             ...............        
+     ..  ...                                    ....................        
+      ....                                      BB...................       
+         ..                 ..                 ..  ...............          
+          ..   .......     ....  .....  ....  ..     .......   S            
+           ............     ....... ..  .......       .....    ...  ....    
+               .......       .....   ......                      .......    
+                                                                            
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),unlit,"ordinary"
+REGION:(52,06,73,15),lit,"ordinary",unfilled,true
+# Doors
+DOOR:locked,(28,11)
+# Stairs
+STAIR:(04,03),up
+STAIR:(73,10),down
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'h',"bugbear",(02,10),hostile
+MONSTER:'h',"bugbear",(03,11),hostile
+MONSTER:'h',"bugbear",(04,12),hostile
+MONSTER:'h',"bugbear",(02,11),hostile
+MONSTER:'h',"bugbear",(16,16),hostile
+MONSTER:'h',"bugbear",(17,17),hostile
+MONSTER:'h',"bugbear",(18,18),hostile
+MONSTER:'h',"bugbear",(19,16),hostile
+MONSTER:'h',"bugbear",(30,06),hostile
+MONSTER:'h',"bugbear",(31,07),hostile
+MONSTER:'h',"bugbear",(32,08),hostile
+MONSTER:'h',"bugbear",(33,06),hostile
+MONSTER:'h',"bugbear",(34,07),hostile
+MONSTER:'h',"bugbear",random,hostile
+MONSTER:'h',"bugbear",random,hostile
+MONSTER:'h',"bugbear",random,hostile
+MONSTER:'h',"bugbear",random,hostile
+MONSTER:'h',random,random,hostile
+MONSTER:'H',random,random,hostile
+MONSTER:'H',"hill giant",(03,12),hostile
+MONSTER:'H',"hill giant",(20,17),hostile
+MONSTER:'H',"hill giant",(35,08),hostile
+MONSTER:'H',"hill giant",random,hostile
+MONSTER:'H',"hill giant",random,hostile
+MONSTER:'H',"hill giant",random,hostile
+MONSTER:'H',"hill giant",random,hostile
+MONSTER:'H',random,random,hostile
+WALLIFY
+
+#
+#      The "goal" level for the quest.
+#
+#      Here you meet Tiamat your nemesis monster.  You have to
+#      defeat Tiamat in combat to gain the artifact you have
+#      been assigned to retrieve.
+#
+
+MAZE: "Cav-goal", ' '
+GEOMETRY:center,center
+MAP
+                                                                            
+                          .....................                             
+                         .......................                            
+                        .........................                           
+                       ...........................                          
+                      .............................                         
+                     ...............................                        
+                    .................................                       
+                   ...................................                      
+                  .....................................                     
+                 .......................................                    
+                  .....................................                     
+                   ...................................                      
+                    .................................                       
+                     ...............................                        
+                      .............................                         
+                       ...........................                          
+                        .........................                           
+                         .......................                            
+                                                                            
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+# Stairs
+STAIR:random,up
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Objects
+OBJECT:')',"mace",(23,10),blessed,0,"The Sceptre of Might"
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# monsters.
+MONSTER:'D',"Chromatic Dragon",(23,10),asleep
+MONSTER:'F',"shrieker",(26,13)
+MONSTER:'F',"shrieker",(25,8)
+MONSTER:'F',"shrieker",(45,11)
+WALLIFY
+
+#
+#      The "fill" levels for the quest.
+#
+#      These levels are used to fill out any levels not occupied by specific
+#      levels as defined above. "filla" is the upper filler, between the
+#      start and locate levels, and "fillb" the lower between the locate
+#      and goal levels.
+#
+
+MAZE: "Cav-fila" , ' '
+INIT_MAP: '.' , ' ' , true , true , random , true
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+#
+MONSTER: 'h', "bugbear", random, hostile
+MONSTER: 'h', "bugbear", random, hostile
+MONSTER: 'h', "bugbear", random, hostile
+MONSTER: 'h', "bugbear", random, hostile
+MONSTER: 'h', "bugbear", random, hostile
+MONSTER: 'h', random, random, hostile
+MONSTER: 'H', "hill giant", random, hostile
+
+MAZE: "Cav-filb" , ' '
+INIT_MAP: '.' , ' ' , true , true , random , true
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+#
+MONSTER: 'h', "bugbear", random, hostile
+MONSTER: 'h', "bugbear", random, hostile
+MONSTER: 'h', "bugbear", random, hostile
+MONSTER: 'h', "bugbear", random, hostile
+MONSTER: 'h', random, random, hostile
+MONSTER: 'h', random, random, hostile
+MONSTER: 'H', "hill giant", random, hostile
+MONSTER: 'H', "hill giant", random, hostile
diff --git a/dat/Healer.des b/dat/Healer.des
new file mode 100644 (file)
index 0000000..9142ba7
--- /dev/null
@@ -0,0 +1,377 @@
+#      SCCS Id: @(#)Healer.des 3.4     1995/04/16
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1991, 1993 by M. Stephenson, P. Winner
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The "start" level for the quest.
+#
+#      Here you meet your (besieged) class leader, Hippocrates
+#      and receive your quest assignment.
+#
+MAZE: "Hea-strt",' '
+FLAGS: noteleport,hardfloor
+GEOMETRY:center,center
+MAP
+PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
+PPPP........PPPP.....PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP.P..PPPPP......PPPPPPPP
+PPP..........PPPP...PPPPP.........................PPPP..PPPPP........PPPPPPP
+PP............PPPPPPPP..............................PPP...PPPP......PPPPPPPP
+P.....PPPPPPPPPPPPPPP................................PPPPPPPPPPPPPPPPPPPPPPP
+PPPP....PPPPPPPPPPPP...................................PPPPP.PPPPPPPPPPPPPPP
+PPPP........PPPPP.........-----------------------........PP...PPPPPPP.....PP
+PPP............PPPPP....--|.|......S..........S.|--.....PPPP.PPPPPPP.......P
+PPPP..........PPPPP.....|.S.|......-----------|S|.|......PPPPPP.PPP.......PP
+PPPPPP......PPPPPP......|.|.|......|...|......|.|.|.....PPPPPP...PP.......PP
+PPPPPPPPPPPPPPPPPPP.....+.|.|......S.\.S......|.|.+......PPPPPP.PPPP.......P
+PPP...PPPPP...PPPP......|.|.|......|...|......|.|.|.......PPPPPPPPPPP.....PP
+PP.....PPP.....PPP......|.|S|-----------......|.S.|......PPPPPPPPPPPPPPPPPPP
+PPP..PPPPP...PPPP.......--|.S..........S......|.|--.....PPPPPPPPP....PPPPPPP
+PPPPPPPPPPPPPPPP..........-----------------------..........PPPPP..........PP
+PPPPPPPPPPPPPPPPP........................................PPPPPP............P
+PPP.............PPPP...................................PPP..PPPP..........PP
+PP...............PPPPP................................PPPP...PPPP........PPP
+PPP.............PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP....PPPPPP
+PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+# Stairs
+STAIR:(37,9),down
+# Portal arrival point
+BRANCH:(04,12,04,12),(0,0,0,0)
+# altar for the Temple
+ALTAR:(32,09),neutral,altar
+# Doors
+DOOR:locked,(24,10)
+DOOR:closed,(26,08)
+DOOR:closed,(27,12)
+DOOR:locked,(28,13)
+DOOR:closed,(35,07)
+DOOR:locked,(35,10)
+DOOR:locked,(39,10)
+DOOR:closed,(39,13)
+DOOR:locked,(46,07)
+DOOR:closed,(47,08)
+DOOR:closed,(48,12)
+DOOR:locked,(50,10)
+# Hippocrates
+MONSTER:'@',"Hippocrates",(37,10)
+# The treasure of Hippocrates
+OBJECT:'(',"chest",(37,10)
+# intern guards for the audience chamber
+MONSTER:'@',"attendant",(29,08)
+MONSTER:'@',"attendant",(29,09)
+MONSTER:'@',"attendant",(29,10)
+MONSTER:'@',"attendant",(29,11)
+MONSTER:'@',"attendant",(40,09)
+MONSTER:'@',"attendant",(40,10)
+MONSTER:'@',"attendant",(40,11)
+MONSTER:'@',"attendant",(40,13)
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Monsters on siege duty.
+MONSTER: 'r',"rabid rat",random
+MONSTER: 'r',"rabid rat",random
+MONSTER: 'r',"rabid rat",random
+MONSTER: 'r',"rabid rat",random
+MONSTER: 'r',"rabid rat",random
+MONSTER: 'r',"rabid rat",random
+MONSTER: 'r',"rabid rat",random
+MONSTER: 'r',"rabid rat",random
+MONSTER: 'r',"rabid rat",random
+MONSTER: 'r',"rabid rat",random
+MONSTER: ';',"giant eel",random
+MONSTER: ';',"shark",random
+MONSTER: ';', random, random
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+#
+#      The "locate" level for the quest.
+#
+#      Here you have to find the Temple of Coeus to go
+#      further towards your assigned quest.
+#
+
+MAZE: "Hea-loca",' '
+FLAGS: hardfloor
+#
+INIT_MAP: '.' , 'P', true , true , lit , false
+GEOMETRY:center,center
+MAP
+PPPPPPPPPPPPP.......PPPPPPPPPPP
+PPPPPPPP...............PPPPPPPP
+PPPP.....-------------...PPPPPP
+PPPPP....|.S.........|....PPPPP
+PPP......+.|.........|...PPPPPP
+PPP......+.|.........|..PPPPPPP
+PPPP.....|.S.........|..PPPPPPP
+PPPPP....-------------....PPPPP
+PPPPPPPP...............PPPPPPPP
+PPPPPPPPPPP........PPPPPPPPPPPP
+ENDMAP
+# Dungeon Description
+REGION:(00,00,30,09),lit,"ordinary"
+REGION:(12,03,20,06),lit,"temple"
+# Doors
+DOOR:closed,(09,04)
+DOOR:closed,(09,05)
+DOOR:locked,(11,03)
+DOOR:locked,(11,06)
+# Stairs
+STAIR:(04,04),up
+STAIR:(20,06),down
+# Non diggable walls
+NON_DIGGABLE:(11,02,21,07)
+# Altar in the temple.
+ALTAR:(13,05), chaos, shrine
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'r',"rabid rat",random
+MONSTER:'r',"rabid rat",random
+MONSTER:'r',"rabid rat",random
+MONSTER:'r',"rabid rat",random
+MONSTER:'r',"rabid rat",random
+MONSTER:'r',"rabid rat",random
+MONSTER:'r',"rabid rat",random
+MONSTER:'r',"rabid rat",random
+MONSTER:'r',random,random,hostile
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"electric eel",random
+MONSTER:';',"electric eel",random
+MONSTER:';',"kraken",random
+MONSTER:';',"shark",random
+MONSTER:';',"shark",random
+MONSTER:';',random, random,hostile
+MONSTER:';',random, random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+
+#
+#      The "goal" level for the quest.
+#
+#      Here you meet Cyclops your nemesis monster.  You have to
+#      defeat Cyclops in combat to gain the artifact you have
+#      been assigned to retrieve.
+#
+
+MAZE: "Hea-goal", 'P'
+#
+INIT_MAP: '.' , 'P' , false , true , lit , false
+GEOMETRY:center,center
+MAP
+.P....................................PP.
+PP.......PPPPPPP....PPPPPPP....PPPP...PP.
+...PPPPPPP....PPPPPPP.....PPPPPP..PPP...P
+...PP..............................PPP...
+..PP..............................PP.....
+..PP..............................PPP....
+..PPP..............................PP....
+.PPP..............................PPPP...
+...PP............................PPP...PP
+..PPPP...PPPPP..PPPP...PPPPP.....PP...PP.
+P....PPPPP...PPPP..PPPPP...PPPPPPP...PP..
+PPP..................................PPP.
+ENDMAP
+# Dungeon Description
+REGION:(00,00,40,11),lit,"ordinary"
+# Stairs
+STAIR:(39,10),up
+# Non diggable walls
+NON_DIGGABLE:(00,00,40,11)
+# Objects
+OBJECT:')',"quarterstaff",(20,06),blessed,0,"The Staff of Aesculapius"
+OBJECT:'/',"lightning",(20,06)
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'H',"Cyclops",(20,06),hostile
+MONSTER:'r',"rabid rat",random
+MONSTER:'r',"rabid rat",random
+MONSTER:'r',"rabid rat",random
+MONSTER:'r',random,random,hostile
+MONSTER:'r',random,random,hostile
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"electric eel",random
+MONSTER:';',"electric eel",random
+MONSTER:';',"shark",random
+MONSTER:';',"shark",random
+MONSTER:';',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+
+#
+#      The "fill" levels for the quest.
+#
+#      These levels are used to fill out any levels not occupied by specific
+#      levels as defined above. "filla" is the upper filler, between the
+#      start and locate levels, and "fillb" the lower between the locate
+#      and goal levels.
+#
+
+MAZE: "Hea-fila" , 'P'
+INIT_MAP: '.' , 'P' , false , true , lit , false
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+MONSTER: 'r', "rabid rat", random
+MONSTER: 'r', random, random,hostile
+MONSTER: 'r', random, random,hostile
+MONSTER: ';', "giant eel", random
+MONSTER: ';', "giant eel", random
+MONSTER: ';', "electric eel", random
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+
+MAZE: "Hea-filb" , 'P'
+INIT_MAP: '.' , 'P' , false , true , lit , false
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+MONSTER: 'r', "rabid rat", random
+MONSTER: 'r', "rabid rat", random
+MONSTER: 'r', random, random,hostile
+MONSTER: 'r', random, random,hostile
+MONSTER: ';', "giant eel", random
+MONSTER: ';', "giant eel", random
+MONSTER: ';', "giant eel", random
+MONSTER: ';', "giant eel", random
+MONSTER: ';', "giant eel", random
+MONSTER: ';', "electric eel", random
+MONSTER: ';', "electric eel", random
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'D',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+MONSTER: 'S',random,random,hostile
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
diff --git a/dat/Knight.des b/dat/Knight.des
new file mode 100644 (file)
index 0000000..ba63140
--- /dev/null
@@ -0,0 +1,408 @@
+#      SCCS Id: @(#)Knight.des 3.4     1995/04/16
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1991,92 by M. Stephenson
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The "start" level for the quest.
+#
+#      Here you meet your (besieged) class leader, King Arthur
+#      and receive your quest assignment.
+#
+MAZE: "Kni-strt",'.'
+FLAGS: noteleport,hardfloor
+# This is a kludge to init the level as a lit field.
+INIT_MAP: '.' , '.' , false , false , lit , false
+GEOMETRY:center,center
+MAP
+..................................................
+.-----......................................-----.
+.|...|......................................|...|.
+.--|+-------------------++-------------------+|--.
+...|...................+..+...................|...
+...|.|-----------------|++|-----------------|.|...
+...|.|.................|..|.........|.......|.|...
+...|.|...\.............+..+.........|.......|.|...
+...|.|.................+..+.........+.......|.|...
+...|.|.................|..|.........|.......|.|...
+...|.|--------------------------------------|.|...
+...|..........................................|...
+.--|+----------------------------------------+|--.
+.|...|......................................|...|.
+.-----......................................-----.
+..................................................
+ENDMAP
+# Dungeon Description
+REGION:(00,00,49,15),lit,"ordinary"
+REGION:(04,04,45,11),unlit,"ordinary"
+REGION:(06,06,22,09),lit,"throne" , unfilled
+REGION:(27,06,43,09),lit,"ordinary"
+# Portal arrival point
+BRANCH:(20,14,20,14),(0,0,0,0)
+# Stairs
+STAIR:(40,7),down
+# Doors
+# Outside Doors
+DOOR:locked,(24,03)
+DOOR:locked,(25,03)
+# Inside Doors
+DOOR:closed,(23,04)
+DOOR:closed,(26,04)
+DOOR:locked,(24,05)
+DOOR:locked,(25,05)
+DOOR:closed,(23,07)
+DOOR:closed,(26,07)
+DOOR:closed,(23,08)
+DOOR:closed,(26,08)
+DOOR:closed,(36,08)
+# Watchroom Doors
+DOOR:closed,(04,03)
+DOOR:closed,(45,03)
+DOOR:closed,(04,12)
+DOOR:closed,(45,12)
+# King Arthur
+MONSTER:'@',"King Arthur",(09,07)
+# The treasure of King Arthur
+OBJECT:'(',"chest",(09,07)
+# knight guards for the watchrooms
+MONSTER:'@',"knight",(04,02),peaceful
+MONSTER:'@',"knight",(04,13),peaceful
+MONSTER:'@',"knight",(45,02),peaceful
+MONSTER:'@',"knight",(45,13),peaceful
+# page guards for the audience chamber
+MONSTER:'@',"page",(16,06)
+MONSTER:'@',"page",(18,06)
+MONSTER:'@',"page",(20,06)
+MONSTER:'@',"page",(16,09)
+MONSTER:'@',"page",(18,09)
+MONSTER:'@',"page",(20,09)
+# Non diggable walls
+NON_DIGGABLE:(00,00,49,15)
+# Random traps
+TRAP:"sleep gas",(24,04)
+TRAP:"sleep gas",(25,04)
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Monsters on siege duty.
+MONSTER: 'i',"quasit",(14,00),hostile
+MONSTER: 'i',"quasit",(16,00),hostile
+MONSTER: 'i',"quasit",(18,00),hostile
+MONSTER: 'i',"quasit",(20,00),hostile
+MONSTER: 'i',"quasit",(22,00),hostile
+MONSTER: 'i',"quasit",(24,00),hostile
+MONSTER: 'i',"quasit",(26,00),hostile
+MONSTER: 'i',"quasit",(28,00),hostile
+MONSTER: 'i',"quasit",(30,00),hostile
+MONSTER: 'i',"quasit",(32,00),hostile
+MONSTER: 'i',"quasit",(34,00),hostile
+MONSTER: 'i',"quasit",(36,00),hostile
+
+#
+#      The "locate" level for the quest.
+#
+#      Here you have to find your way to the Isle of Glass to go
+#      further towards your assigned quest.
+#
+
+MAZE: "Kni-loca",' '
+FLAGS: hardfloor
+INIT_MAP: '.' , 'P' , false , true , lit , false
+GEOMETRY:center,center
+MAP
+...PPP.........PPPP..............PPPP...
+.PPPP...........PP................PPPP..
+PP.................................PPP..
+....................................PPP.
+.....................................PP.
+.......................................P
+........................................
+PP...................................PPP
+.PPP...............................PPP..
+..PP.............................PPPP...
+..PPP...........................PPPPPP..
+....PPPP.........PPP.........PPPP..PP...
+ENDMAP
+# Dungeon Description
+# The Isle of Glass is a Tor rising out of the swamps surrounding it.
+REGION:(00,00,39,11),lit,"ordinary"
+# The top area of the Tor is a holy site.
+REGION:(09,02,27,09),lit,"temple"
+# Stairs
+STAIR:(38,0),up
+STAIR:(18,05),down
+# The altar atop the Tor and its attendant (creating altar makes the priest).
+ALTAR:(17,05),neutral,shrine
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+# All of the avenues are guarded by magic except for the East.
+# South
+TRAP:"magic",(08,11)
+TRAP:"magic",(09,11)
+TRAP:"magic",(10,11)
+TRAP:"magic",(11,11)
+TRAP:"magic",(12,11)
+TRAP:"magic",(13,11)
+TRAP:"magic",(14,11)
+TRAP:"magic",(15,11)
+TRAP:"magic",(16,11)
+TRAP:"magic",(20,11)
+TRAP:"magic",(21,11)
+TRAP:"magic",(22,11)
+TRAP:"magic",(23,11)
+TRAP:"magic",(24,11)
+TRAP:"magic",(25,11)
+TRAP:"magic",(26,11)
+TRAP:"magic",(27,11)
+TRAP:"magic",(28,11)
+# West
+TRAP:"magic",(00,03)
+TRAP:"magic",(00,04)
+TRAP:"magic",(00,05)
+TRAP:"magic",(00,06)
+# North
+TRAP:"magic",(06,00)
+TRAP:"magic",(07,00)
+TRAP:"magic",(08,00)
+TRAP:"magic",(09,00)
+TRAP:"magic",(10,00)
+TRAP:"magic",(11,00)
+TRAP:"magic",(12,00)
+TRAP:"magic",(13,00)
+TRAP:"magic",(14,00)
+TRAP:"magic",(19,00)
+TRAP:"magic",(20,00)
+TRAP:"magic",(21,00)
+TRAP:"magic",(22,00)
+TRAP:"magic",(23,00)
+TRAP:"magic",(24,00)
+TRAP:"magic",(25,00)
+TRAP:"magic",(26,00)
+TRAP:"magic",(27,00)
+TRAP:"magic",(28,00)
+TRAP:"magic",(29,00)
+TRAP:"magic",(30,00)
+TRAP:"magic",(31,00)
+TRAP:"magic",(32,00)
+# Even so, there are magic "sinkholes" around.
+TRAP:"anti magic",random
+TRAP:"anti magic",random
+TRAP:"anti magic",random
+TRAP:"anti magic",random
+TRAP:"anti magic",random
+TRAP:"anti magic",random
+TRAP:"anti magic",random
+# Random monsters.
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'j',random,random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',random,random,hostile
+
+#
+#      The "goal" level for the quest.
+#
+#      Here you meet Ixoth your nemesis monster.  You have to
+#      defeat Ixoth in combat to gain the artifact you have
+#      been assigned to retrieve.
+#
+
+MAZE: "Kni-goal", ' '
+GEOMETRY:center,center
+MAP
+....PPPP..PPP..                                                             
+.PPPPP...PP..     ..........     .................................          
+..PPPPP...P..    ...........    ...................................         
+..PPP.......   ...........    ......................................        
+...PPP.......    .........     ...............   .....................      
+...........    ............    ............     ......................      
+............   .............      .......     .....................         
+..............................            .........................         
+...............................   ..................................        
+.............................    ....................................       
+.........    ......................................................         
+.....PP...    .....................................................         
+.....PPP....    ....................................................        
+......PPP....   ..............   ....................................       
+.......PPP....  .............    .....................................      
+........PP...    ............    ......................................     
+...PPP........     ..........     ..................................        
+..PPPPP........     ..........     ..............................           
+....PPPPP......       .........     ..........................              
+.......PPPP...                                                              
+ENDMAP
+# Dungeon Description
+REGION:(00,00,14,19),lit,"ordinary"
+REGION:(15,00,75,19),unlit,"ordinary"
+# Stairs
+STAIR:(03,08),up
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Objects
+OBJECT:'(',"mirror",(50,06),blessed,0,"The Magic Mirror of Merlin"
+OBJECT:random,random,(33,01)
+OBJECT:random,random,(33,02)
+OBJECT:random,random,(33,03)
+OBJECT:random,random,(33,04)
+OBJECT:random,random,(33,05)
+OBJECT:random,random,(34,01)
+OBJECT:random,random,(34,02)
+OBJECT:random,random,(34,03)
+OBJECT:random,random,(34,04)
+OBJECT:random,random,(34,05)
+OBJECT:random,random,(35,01)
+OBJECT:random,random,(35,02)
+OBJECT:random,random,(35,03)
+OBJECT:random,random,(35,04)
+OBJECT:random,random,(35,05)
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:"spiked pit",(13,07)
+TRAP:"spiked pit",(12,08)
+TRAP:"spiked pit",(12,09)
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'D',"Ixoth",(50,06),hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',"quasit",random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',"ochre jelly",random,hostile
+MONSTER:'j',random,random,hostile
+
+#
+#      The "fill" levels for the quest.
+#
+#      These levels are used to fill out any levels not occupied by specific
+#      levels as defined above. "filla" is the upper filler, between the
+#      start and locate levels, and "fillb" the lower between the locate
+#      and goal levels.
+#
+
+MAZE: "Kni-fila" , '.'
+INIT_MAP: '.' , 'P' , false , true , lit , false
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+MONSTER: 'i', "quasit", random, hostile
+MONSTER: 'i', "quasit", random, hostile
+MONSTER: 'i', "quasit", random, hostile
+MONSTER: 'i', "quasit", random, hostile
+MONSTER: 'i', random, random, hostile
+MONSTER: 'j', "ochre jelly", random, hostile
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+
+MAZE: "Kni-filb" , '.'
+INIT_MAP: '.' , 'P' , false , true , lit , false
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+MONSTER: 'i', "quasit", random, hostile
+MONSTER: 'i', "quasit", random, hostile
+MONSTER: 'i', "quasit", random, hostile
+MONSTER: 'i', "quasit", random, hostile
+MONSTER: 'i', random, random, hostile
+MONSTER: 'j', "ochre jelly", random, hostile
+MONSTER: 'j', "ochre jelly", random, hostile
+MONSTER: 'j', "ochre jelly", random, hostile
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
diff --git a/dat/Monk.des b/dat/Monk.des
new file mode 100644 (file)
index 0000000..14d7695
--- /dev/null
@@ -0,0 +1,353 @@
+#      SCCS Id: @(#)Monk.des   3.4     2002/04/08
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1991-2 by M. Stephenson
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The "start" level for the quest.
+#
+#      Here you meet your (besieged) class leader, the Grand Master
+#      and receive your quest assignment.
+#
+MAZE: "Mon-strt",' '
+FLAGS: noteleport,hardfloor
+GEOMETRY:center,center
+MAP
+............................................................................
+............................................................................
+............................................................................
+....................------------------------------------....................
+....................|................|.....|.....|.....|....................
+....................|..------------..|--+-----+-----+--|....................
+....................|..|..........|..|.................|....................
+....................|..|..........|..|+---+---+-----+--|....................
+..................---..|..........|......|...|...|.....|....................
+..................+....|..........+......|...|...|.....|....................
+..................+....|..........+......|...|...|.....|....................
+..................---..|..........|......|...|...|.....|....................
+....................|..|..........|..|+-----+---+---+--|....................
+....................|..|..........|..|.................|....................
+....................|..------------..|--+-----+-----+--|....................
+....................|................|.....|.....|.....|....................
+....................------------------------------------....................
+............................................................................
+............................................................................
+............................................................................
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+REGION:(24,06,33,13),lit,"temple"
+# Portal arrival point
+BRANCH:(05,04,05,04),(0,0,0,0)
+# Stairs
+STAIR:(52,09),down
+# Doors
+DOOR:locked,(18,09)
+DOOR:locked,(18,10)
+DOOR:closed,(34,09)
+DOOR:closed,(34,10)
+DOOR:closed,(40,05)
+DOOR:closed,(46,05)
+DOOR:closed,(52,05)
+DOOR:locked,(38,07)
+DOOR:closed,(42,07)
+DOOR:closed,(46,07)
+DOOR:closed,(52,07)
+DOOR:locked,(38,12)
+DOOR:closed,(44,12)
+DOOR:closed,(48,12)
+DOOR:closed,(52,12)
+DOOR:closed,(40,14)
+DOOR:closed,(46,14)
+DOOR:closed,(52,14)
+# Unattended Altar - unaligned due to conflict - player must align it.
+ALTAR:(28,09),noalign,altar
+# The Grand Master
+MONSTER:'@',"Grand Master",(28,10)
+# No treasure chest!
+# guards for the audience chamber
+MONSTER:'@',"abbot",(32,07)
+MONSTER:'@',"abbot",(32,08)
+MONSTER:'@',"abbot",(32,11)
+MONSTER:'@',"abbot",(32,12)
+MONSTER:'@',"abbot",(33,07)
+MONSTER:'@',"abbot",(33,08)
+MONSTER:'@',"abbot",(33,11)
+MONSTER:'@',"abbot",(33,12)
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Random traps
+TRAP:"dart",(20,09)
+TRAP:"dart",(20,10)
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Monsters on siege duty.
+MONSTER: 'E',"earth elemental",(37,01)
+MONSTER: 'E',"earth elemental",(37,18)
+MONSTER: 'E',"earth elemental",(03,03)
+MONSTER: 'E',"earth elemental",(65,04)
+MONSTER: 'E',"earth elemental",(12,11)
+MONSTER: 'E',"earth elemental",(60,12)
+MONSTER: 'E',"earth elemental",(14,08)
+MONSTER: 'E',"earth elemental",(55,00)
+MONSTER: 'X',"xorn",(18,18)
+MONSTER: 'X',"xorn",(59,10)
+MONSTER: 'X',"xorn",(13,09)
+MONSTER: 'X',"xorn",(01,17)
+
+#
+#      The "locate" level for the quest.
+#
+#      Here you have to locate the Monastery of the Earth-Lord to
+#      go further towards your assigned quest.
+#
+
+MAZE: "Mon-loca",' '
+GEOMETRY:center,center
+#         1         2         3         4         5         6         7 
+#123456789012345678901234567890123456789012345678901234567890123456789012345
+MAP
+             ----------------------------------------------------   --------
+           ---.................................................-    --.....|
+         ---...--------........------........................---     ---...|
+       ---.....-      --.......-    ----..................----         --.--
+     ---.....----      ---------       --..................--         --..|
+   ---...-----                       ----.----.....----.....---      --..||
+----..----                       -----..---  |...---  |.......---   --...|
+|...---                       ----....---    |.---    |.........-- --...||
+|...-                      ----.....---     ----      |..........---....|
+|...----                ----......---       |         |...|.......-....||
+|......-----          ---.........-         |     -----...|............|
+|..........-----   ----...........---       -------......||...........||
+|..............-----................---     |............|||..........|
+|-S----...............................---   |...........|| |.........||
+|.....|..............------.............-----..........||  ||........|
+|.....|.............--    ---.........................||    |.......||
+|.....|.............-       ---.....................--|     ||......|
+|---S--------.......----      --.................----        |.....||
+|...........|..........--------..............-----           ||....|
+|...........|............................-----                |....|
+------------------------------------------                    ------
+ENDMAP
+# Random Monsters
+RANDOM_MONSTERS: 'E', 'X'
+# Dungeon Description
+REGION:(00,00,75,20),lit,"ordinary"
+# Stairs
+STAIR:random,up
+STAIR:random,down
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,20)
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+
+#
+#      The "goal" level for the quest.
+#
+#      Here you meet Master Kaen, your nemesis monster.  You have to
+#      defeat Master Kaen in combat to gain the artifact you have
+#      been assigned to retrieve.
+#
+
+MAZE: "Mon-goal", ' '
+INIT_MAP: 'L' , '.' , false , false , unlit , false
+GEOMETRY:center,center
+MAP
+.L......L.LLL.......LL....
+.LLL.......L......LL......
+LL.LL.............L.LL....
+..........................
+......................LL..
+......................LLL.
+LL........................
+.LL.......................
+.LL................LL.L...
+..LL.....L.LL.......LLL...
+.........LLL.........L....
+ENDMAP
+# Dungeon Description
+RANDOM_PLACES:(14,04),(13,07)
+REGION:(00,00,25,10),unlit,"ordinary"
+# Stairs
+STAIR:(20,05),up
+# Objects
+OBJECT:'(',"lenses",place[0],blessed,0,"The Eyes of the Overworld"
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'@',"Master Kaen",place[0]
+ALTAR:place[0],noalign,altar
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'E',"earth elemental",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+MONSTER: 'X',"xorn",random
+
+#
+#      The "fill" levels for the quest.
+#
+#      These levels are used to fill out any levels not occupied by specific
+#      levels as defined above. "fila" is the upper filler, between the
+#      start and locate levels, and "filb" the lower between the locate
+#      and goal levels.
+#
+
+LEVEL: "Mon-fila"
+# Random Monsters
+RANDOM_MONSTERS: 'E', 'X'
+#
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+OBJECT: random,random,random
+MONSTER: 'E', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random,random,random
+MONSTER: 'E', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+OBJECT: random,random,random
+MONSTER: 'X', "xorn", random
+MONSTER: 'E', "earth elemental", random
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'E', random, random, hostile
+MONSTER: 'E', "earth elemental", random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'X', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'E', "earth elemental", random
+
+RANDOM_CORRIDORS
+
+LEVEL: "Mon-filb"
+# Random Monsters
+RANDOM_MONSTERS: 'E', 'X'
+#
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+OBJECT: random,random,random
+MONSTER: 'X', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random,random,random
+MONSTER: 'X', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+OBJECT: random,random,random
+MONSTER: 'E', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'E', random, random, hostile
+MONSTER: 'E', "earth elemental", random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'X', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'E', "earth elemental", random
+
+RANDOM_CORRIDORS
+
diff --git a/dat/Priest.des b/dat/Priest.des
new file mode 100644 (file)
index 0000000..86f2d36
--- /dev/null
@@ -0,0 +1,337 @@
+#      SCCS Id: @(#)Priest.des 3.4     2002/04/08
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1991-2 by M. Stephenson
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The "start" level for the quest.
+#
+#      Here you meet your (besieged) class leader, High Priest
+#      and receive your quest assignment.
+#
+MAZE: "Pri-strt",' '
+FLAGS: noteleport,hardfloor
+GEOMETRY:center,center
+MAP
+............................................................................
+............................................................................
+............................................................................
+....................------------------------------------....................
+....................|................|.....|.....|.....|....................
+....................|..------------..|--+-----+-----+--|....................
+....................|..|..........|..|.................|....................
+....................|..|..........|..|+---+---+-----+--|....................
+..................---..|..........|......|...|...|.....|....................
+..................+....|..........+......|...|...|.....|....................
+..................+....|..........+......|...|...|.....|....................
+..................---..|..........|......|...|...|.....|....................
+....................|..|..........|..|+-----+---+---+--|....................
+....................|..|..........|..|.................|....................
+....................|..------------..|--+-----+-----+--|....................
+....................|................|.....|.....|.....|....................
+....................------------------------------------....................
+............................................................................
+............................................................................
+............................................................................
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+REGION:(24,06,33,13),lit,"temple"
+# Portal arrival point
+BRANCH:(05,04,05,04),(0,0,0,0)
+# Stairs
+STAIR:(52,09),down
+# Doors
+DOOR:locked,(18,09)
+DOOR:locked,(18,10)
+DOOR:closed,(34,09)
+DOOR:closed,(34,10)
+DOOR:closed,(40,05)
+DOOR:closed,(46,05)
+DOOR:closed,(52,05)
+DOOR:locked,(38,07)
+DOOR:closed,(42,07)
+DOOR:closed,(46,07)
+DOOR:closed,(52,07)
+DOOR:locked,(38,12)
+DOOR:closed,(44,12)
+DOOR:closed,(48,12)
+DOOR:closed,(52,12)
+DOOR:closed,(40,14)
+DOOR:closed,(46,14)
+DOOR:closed,(52,14)
+# Unattended Altar - unaligned due to conflict - player must align it.
+ALTAR:(28,09),noalign,altar
+# High Priest
+MONSTER:'@',"Arch Priest",(28,10)
+# The treasure of High Priest
+OBJECT:'(',"chest",(27,10)
+# knight guards for the audience chamber
+MONSTER:'@',"acolyte",(32,07)
+MONSTER:'@',"acolyte",(32,08)
+MONSTER:'@',"acolyte",(32,11)
+MONSTER:'@',"acolyte",(32,12)
+MONSTER:'@',"acolyte",(33,07)
+MONSTER:'@',"acolyte",(33,08)
+MONSTER:'@',"acolyte",(33,11)
+MONSTER:'@',"acolyte",(33,12)
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Random traps
+TRAP:"dart",(20,09)
+TRAP:"dart",(20,10)
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Monsters on siege duty.
+MONSTER: 'Z',"human zombie",(37,01)
+MONSTER: 'Z',"human zombie",(37,18)
+MONSTER: 'Z',"human zombie",(03,03)
+MONSTER: 'Z',"human zombie",(65,04)
+MONSTER: 'Z',"human zombie",(12,11)
+MONSTER: 'Z',"human zombie",(60,12)
+MONSTER: 'Z',"human zombie",(14,08)
+MONSTER: 'Z',"human zombie",(55,00)
+MONSTER: 'Z',"human zombie",(18,18)
+MONSTER: 'Z',"human zombie",(59,10)
+MONSTER: 'Z',"human zombie",(13,09)
+MONSTER: 'Z',"human zombie",(01,17)
+
+#
+#      The "locate" level for the quest.
+#
+#      Here you have to locate the Temple of Nalzok to go
+#      further towards your assigned quest.
+#
+
+MAZE: "Pri-loca",' '
+FLAGS: hardfloor
+# This is a kludge to init the level as a lit field.
+INIT_MAP: '.' , '.' , false , false , lit , false
+GEOMETRY:center,center
+MAP
+........................................
+........................................
+..........----------+----------.........
+..........|........|.|........|.........
+..........|........|.|........|.........
+..........|----.----.----.----|.........
+..........+...................+.........
+..........+...................+.........
+..........|----.----.----.----|.........
+..........|........|.|........|.........
+..........|........|.|........|.........
+..........----------+----------.........
+........................................
+........................................
+ENDMAP
+# Dungeon Description
+REGION:(00,00,09,13),unlit,"morgue"
+REGION:(09,00,30,01),unlit,"morgue"
+REGION:(09,12,30,13),unlit,"morgue"
+REGION:(31,00,39,13),unlit,"morgue"
+REGION:(11,03,29,10),lit,"temple",filled,true
+# The altar inside the temple
+ALTAR:(20,07),noalign,shrine
+MONSTER:'@',"aligned priest",(20,07),noalign,hostile
+# Doors
+DOOR:locked,(10,06)
+DOOR:locked,(10,07)
+DOOR:locked,(20,02)
+DOOR:locked,(20,11)
+DOOR:locked,(30,06)
+DOOR:locked,(30,07)
+# Stairs
+# Note:  The up stairs are *intentionally* off of the map.
+STAIR:(43,05),up
+STAIR:(20,06),down
+# Non diggable walls
+NON_DIGGABLE:(10,02,30,13)
+# Objects (inside the antechambers).
+OBJECT:random,random,(14,03)
+OBJECT:random,random,(15,03)
+OBJECT:random,random,(16,03)
+OBJECT:random,random,(14,10)
+OBJECT:random,random,(15,10)
+OBJECT:random,random,(16,10)
+OBJECT:random,random,(17,10)
+OBJECT:random,random,(24,03)
+OBJECT:random,random,(25,03)
+OBJECT:random,random,(26,03)
+OBJECT:random,random,(27,03)
+OBJECT:random,random,(24,10)
+OBJECT:random,random,(25,10)
+OBJECT:random,random,(26,10)
+OBJECT:random,random,(27,10)
+# Random traps
+TRAP:random,(15,04)
+TRAP:random,(25,04)
+TRAP:random,(15,09)
+TRAP:random,(25,09)
+TRAP:random,random
+TRAP:random,random
+# No random monsters - the morgue generation will put them in.
+
+#
+#      The "goal" level for the quest.
+#
+#      Here you meet Nalzok your nemesis monster.  You have to
+#      defeat Nalzok in combat to gain the artifact you have
+#      been assigned to retrieve.
+#
+
+MAZE: "Pri-goal", ' '
+INIT_MAP: 'L' , '.' , false , false , unlit , false
+GEOMETRY:center,center
+MAP
+.L......L.LLL.......LL....
+.LLL.......L......LL......
+LL.LL.............L.LL....
+..........................
+......................LL..
+......................LLL.
+LL........................
+.LL.......................
+.LL................LL.L...
+..LL.....L.LL.......LLL...
+.........LLL.........L....
+ENDMAP
+# Dungeon Description
+RANDOM_PLACES:(14,04),(13,07)
+REGION:(00,00,25,10),unlit,"ordinary"
+# Stairs
+STAIR:(20,05),up
+# Objects
+OBJECT:'[',"helm of brilliance",place[0],blessed,0,"The Mitre of Holiness"
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'&',"Nalzok",place[0]
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',random,random
+MONSTER:'Z',random,random
+MONSTER:'W',"wraith",random
+MONSTER:'W',"wraith",random
+MONSTER:'W',"wraith",random
+MONSTER:'W',"wraith",random
+MONSTER:'W',"wraith",random
+MONSTER:'W',"wraith",random
+MONSTER:'W',"wraith",random
+MONSTER:'W',"wraith",random
+MONSTER:'W',random,random
+
+#
+#      The "fill" levels for the quest.
+#
+#      These levels are used to fill out any levels not occupied by specific
+#      levels as defined above. "filla" is the upper filler, between the
+#      start and locate levels, and "fillb" the lower between the locate
+#      and goal levels.
+#
+
+LEVEL: "Pri-fila"
+#
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+OBJECT: random,random,random
+MONSTER: 'Z', "human zombie", random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random,random,random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+OBJECT: random,random,random
+MONSTER: 'Z', "human zombie", random
+
+ROOM: "morgue" , random, random, random, random
+STAIR: random, down
+OBJECT: random, random, random
+TRAP: random, random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'W', "wraith", random
+
+ROOM: "morgue" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+
+RANDOM_CORRIDORS
+
+LEVEL: "Pri-filb"
+#
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+OBJECT: random,random,random
+MONSTER: 'Z', "human zombie", random
+MONSTER: 'W', "wraith", random
+
+ROOM: "morgue" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random,random,random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+OBJECT: random,random,random
+MONSTER: 'Z', "human zombie", random
+MONSTER: 'W', "wraith", random
+
+ROOM: "morgue" , random, random, random, random
+STAIR: random, down
+OBJECT: random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'Z', "human zombie", random
+MONSTER: 'W', "wraith", random
+
+ROOM: "morgue" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+
+RANDOM_CORRIDORS
diff --git a/dat/Ranger.des b/dat/Ranger.des
new file mode 100644 (file)
index 0000000..78df233
--- /dev/null
@@ -0,0 +1,355 @@
+#      SCCS Id: @(#)Ranger.des 3.4     2001/02/01
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1991 by M. Stephenson
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The "start" level for the quest.
+#
+#      Here you meet your (besieged) class leader, Orion,
+#      and receive your quest assignment.
+#
+MAZE: "Ran-strt",'.'
+FLAGS: noteleport,hardfloor,arboreal
+INIT_MAP:'.','.',true,true,lit,false
+GEOMETRY:left,center
+#1234567890123456789012345678901234567890123456789012345678901234567890
+MAP
+                                       ..
+   ...................................  .
+  ..                                 ..  
+ ..  ...............F...............  .. 
+ .  ..             .F.             ..  . 
+ . ..  .............F.............  .. . 
+ . .  ..                         ..  . . 
+ . . ..  .......................  .. ... 
+ . . .  ..                     ..  .     
+ ... . ..  .|..................... ......
+ FFF . .  ..S..................          
+ ... . ..  .|.................  .... ... 
+ . . .  ..                     ..  . . . 
+ . . ..  .......................  .. . . 
+ . .  ..                         ..  . . 
+ . ..  .............F.............  .. . 
+ .  ..             .F.             ..  . 
+ ..  ...............F...............  .. 
+  ..                                 ..  
+   ...................................  .
+                                       ..
+ENDMAP
+# Dungeon Description
+REGION:(00,00,40,20),lit,"ordinary"
+# Stairs
+STAIR:(10,10),down
+# Portal arrival point; just about anywhere on the right hand side of the map
+BRANCH:levregion(51,2,77,18),(0,0,40,20)
+# Orion
+MONSTER:'@',"Orion",(20,10)
+# The treasure of Orion
+OBJECT:'(',"chest",(20,10)
+# Guards for the audience chamber
+MONSTER:'@',"hunter",(19,09)
+MONSTER:'@',"hunter",(20,09)
+MONSTER:'@',"hunter",(21,09)
+MONSTER:'@',"hunter",(19,10)
+MONSTER:'@',"hunter",(21,10)
+MONSTER:'@',"hunter",(19,11)
+MONSTER:'@',"hunter",(20,11)
+MONSTER:'@',"hunter",(21,11)
+# Non diggable walls
+NON_DIGGABLE:(00,00,40,20)
+# Traps
+TRAP:"arrow",(30,09)
+TRAP:"arrow",(30,10)
+TRAP:"pit",(40,09)
+TRAP:"spiked pit",random
+TRAP:"bear",random
+TRAP:"bear",random
+# Monsters on siege duty.
+MONSTER: 'H',"minotaur",(33,09),hostile,asleep
+MONSTER: 'C',"forest centaur",(19,03),hostile
+MONSTER: 'C',"forest centaur",(19,04),hostile
+MONSTER: 'C',"forest centaur",(19,05),hostile
+MONSTER: 'C',"forest centaur",(21,03),hostile
+MONSTER: 'C',"forest centaur",(21,04),hostile
+MONSTER: 'C',"forest centaur",(21,05),hostile
+MONSTER: 'C',"forest centaur",(01,09),hostile
+MONSTER: 'C',"forest centaur",(02,09),hostile
+MONSTER: 'C',"forest centaur",(03,09),hostile
+MONSTER: 'C',"forest centaur",(01,11),hostile
+MONSTER: 'C',"forest centaur",(02,11),hostile
+MONSTER: 'C',"forest centaur",(03,11),hostile
+MONSTER: 'C',"forest centaur",(19,15),hostile
+MONSTER: 'C',"forest centaur",(19,16),hostile
+MONSTER: 'C',"forest centaur",(19,17),hostile
+MONSTER: 'C',"forest centaur",(21,15),hostile
+MONSTER: 'C',"forest centaur",(21,16),hostile
+MONSTER: 'C',"forest centaur",(21,17),hostile
+MONSTER: 'C',"plains centaur",random,hostile
+MONSTER: 'C',"plains centaur",random,hostile
+MONSTER: 'C',"plains centaur",random,hostile
+MONSTER: 'C',"plains centaur",random,hostile
+MONSTER: 'C',"plains centaur",random,hostile
+MONSTER: 'C',"plains centaur",random,hostile
+MONSTER: 's',"scorpion",random,hostile
+MONSTER: 's',"scorpion",random,hostile
+
+
+#
+#      The "locate" level for the quest.
+#
+#      Here you have to infiltrate the Cave of the Wumpus to go
+#      further towards your assigned quest.
+#
+
+MAZE: "Ran-loca",' '
+FLAGS: hardfloor
+GEOMETRY:center,center
+#1234567890123456789012345678901234567890123456789012345678901234567890
+MAP
+              .......  .........  .......              
+     ...................       ...................     
+  ....        .......             .......        ....  
+...    .....     .       .....       .     .....    ...
+.   .......... .....  ...........  ..... ..........   .
+.  ..  ..... ..........  .....  .......... .....  ..  .
+.  .     .     .....       .       .....     .     .  .
+.  .   .....         .............         .....   .  .
+.  .  ................  .......  ................  .  .
+.  .   .....            .......            .....   .  .
+.  .     .    ......               ......    .     .  .
+.  .     ...........   .........   ...........     .  .
+.  .          ..........       ..........          .  .
+.  ..  .....     .       .....       .     .....  ..  .
+.   .......... .....  ...........  ..... ..........   .
+.      ..... ..........  .....  .......... .....      .
+.        .     .....       .       .....     .        .
+...   .......           .......           .......   ...
+  ..............     .............     ..............  
+      .......  .......  .......  .......  .......      
+ENDMAP
+# Dungeon Description
+REGION:(00,00,54,19),lit,"ordinary"
+# Stairs
+STAIR:(25,05),up
+STAIR:(27,18),down
+# Non diggable walls
+NON_DIGGABLE:(00,00,54,19)
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:"spiked pit",random
+TRAP:"spiked pit",random
+TRAP:"teleport",random
+TRAP:"teleport",random
+TRAP:"arrow",random
+TRAP:"arrow",random
+# Random monsters.
+MONSTER:'q',"wumpus",(27,18),hostile,asleep
+MONSTER:'B',"giant bat",random,hostile
+MONSTER:'B',"giant bat",random,hostile
+MONSTER:'B',"giant bat",random,hostile
+MONSTER:'B',"giant bat",random,hostile
+MONSTER:'C',"forest centaur",random,hostile
+MONSTER:'C',"forest centaur",random,hostile
+MONSTER:'C',"forest centaur",random,hostile
+MONSTER:'C',"forest centaur",random,hostile
+MONSTER:'C',"mountain centaur",random,hostile
+MONSTER:'C',"mountain centaur",random,hostile
+MONSTER:'C',"mountain centaur",random,hostile
+MONSTER:'C',"mountain centaur",random,hostile
+MONSTER:'C',"mountain centaur",random,hostile
+MONSTER:'C',"mountain centaur",random,hostile
+MONSTER:'C',"mountain centaur",random,hostile
+MONSTER:'C',"mountain centaur",random,hostile
+MONSTER:'s',"scorpion",random,hostile
+MONSTER:'s',"scorpion",random,hostile
+MONSTER:'s',"scorpion",random,hostile
+MONSTER:'s',"scorpion",random,hostile
+MONSTER:'s',random,random,hostile
+MONSTER:'s',random,random,hostile
+
+
+#
+#      The "goal" level for the quest.
+#
+#      Here you meet Scorpius, your nemesis monster.  You have to
+#      defeat Scorpius in combat to gain the artifact you have
+#      been assigned to retrieve.
+#
+
+MAZE: "Ran-goal", ' '
+GEOMETRY:center,center
+MAP
+                                                                            
+  ...                                                                  ...  
+ .......................................................................... 
+  ...                                +                                 ...  
+   .     ............     .......    .                   .......        .   
+   .  .............................  .       ........   .........S..    .   
+   .   ............    .  ......     .       .      .    .......   ..   .   
+   .     .........     .   ....      +       . ...  .               ..  .   
+   .        S          .         .........   .S.    .S...............   .   
+   .  ...   .     ...  .         .........          .                   .   
+   . ........    .....S.+.......+....\....+........+.                   .   
+   .  ...         ...    S       .........           ..      .....      .   
+   .                    ..       .........            ..      ......    .   
+   .      .......     ...            +       ....    ....    .......... .   
+   . ..............  ..              .      ......  ..  .............   .   
+   .     .............               .     ..........          ......   .   
+  ...                                +                                 ...  
+ .......................................................................... 
+  ...                                                                  ...  
+                                                                            
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+# Stairs
+STAIR:(19,10),up
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Objects
+OBJECT:')',"bow",(37,10),blessed,0,"The Longbow of Diana"
+OBJECT:'(',"chest",(37,10)
+OBJECT:random,random,(36,09)
+OBJECT:random,random,(36,10)
+OBJECT:random,random,(36,11)
+OBJECT:random,random,(37,09)
+OBJECT:random,random,(37,11)
+OBJECT:random,random,(38,09)
+OBJECT:random,random,(38,10)
+OBJECT:random,random,(38,11)
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# doors
+DOOR:locked,(12,08)
+DOOR:closed,(22,10)
+DOOR:locked,(24,10)
+DOOR:closed,(25,11)
+DOOR:closed,(32,10)
+DOOR:closed,(37,03)
+DOOR:closed,(37,07)
+DOOR:closed,(37,13)
+DOOR:closed,(37,16)
+DOOR:closed,(42,10)
+DOOR:locked,(46,08)
+DOOR:closed,(51,10)
+DOOR:locked,(53,08)
+DOOR:closed,(65,05)
+# Random monsters.
+MONSTER:'s',"Scorpius",(37,10),hostile
+MONSTER:'C',"forest centaur",(36,09),hostile
+MONSTER:'C',"forest centaur",(36,10),hostile
+MONSTER:'C',"forest centaur",(36,11),hostile
+MONSTER:'C',"forest centaur",(37,09),hostile
+MONSTER:'C',"forest centaur",(37,11),hostile
+MONSTER:'C',"forest centaur",(38,09),hostile
+MONSTER:'C',"mountain centaur",(38,10),hostile
+MONSTER:'C',"mountain centaur",(38,11),hostile
+MONSTER:'C',"mountain centaur",(02,02),hostile
+MONSTER:'C',"mountain centaur",(71,02),hostile
+MONSTER:'C',"mountain centaur",(02,16),hostile
+MONSTER:'C',"mountain centaur",(71,16),hostile
+MONSTER:'C',"forest centaur",random,hostile
+MONSTER:'C',"forest centaur",random,hostile
+MONSTER:'C',"mountain centaur",random,hostile
+MONSTER:'C',"mountain centaur",random,hostile
+MONSTER:'C',random,random,hostile
+MONSTER:'C',random,random,hostile
+MONSTER:'s',"scorpion",(03,02),hostile
+MONSTER:'s',"scorpion",(72,02),hostile
+MONSTER:'s',"scorpion",(03,17),hostile
+MONSTER:'s',"scorpion",(72,17),hostile
+MONSTER:'s',"scorpion",(41,10),hostile
+MONSTER:'s',"scorpion",(33,09),hostile
+MONSTER:'s',"scorpion",random,hostile
+MONSTER:'s',"scorpion",random,hostile
+MONSTER:'s',random,random,hostile
+
+WALLIFY
+
+#
+#      The "fill" levels for the quest.
+#
+#      These levels are used to fill out any levels not occupied by specific
+#      levels as defined above. "fila" is the upper filler, between the
+#      start and locate levels, and "filb" the lower between the locate
+#      and goal levels.
+#
+
+MAZE: "Ran-fila" , ' '
+INIT_MAP: '.' , 'T', true, true, random, true
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+#
+MONSTER: 'C', "mountain centaur", random, hostile
+MONSTER: 'C', "mountain centaur", random, hostile
+MONSTER: 'C', "forest centaur", random, hostile
+MONSTER: 'C', "forest centaur", random, hostile
+MONSTER: 'C', "forest centaur", random, hostile
+MONSTER: 'C', random, random, hostile
+MONSTER: 's', "scorpion", random, hostile
+
+MAZE: "Ran-filb" , ' '
+INIT_MAP: '.' , ' ', true, true, random, true
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+#
+MONSTER: 'C', "mountain centaur", random, hostile
+MONSTER: 'C', "mountain centaur", random, hostile
+MONSTER: 'C', "mountain centaur", random, hostile
+MONSTER: 'C', "mountain centaur", random, hostile
+MONSTER: 'C', random, random, hostile
+MONSTER: 's', "scorpion", random, hostile
+MONSTER: 's', "scorpion", random, hostile
+
diff --git a/dat/Rogue.des b/dat/Rogue.des
new file mode 100644 (file)
index 0000000..cd38a97
--- /dev/null
@@ -0,0 +1,479 @@
+#      SCCS Id: @(#)Rogue.des  3.4     2002/02/15
+#      Copyright (c) 1992 by Dean Luick
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The "start" level for the quest.
+#
+#      Here you meet your (besieged) class leader, Master of Thieves
+#      and receive your quest assignment.
+#
+MAZE: "Rog-strt",' '
+FLAGS: noteleport, hardfloor, nommap
+GEOMETRY:center,center
+#         1         2         3         4         5         6         7
+#123456789012345678901234567890123456789012345678901234567890123456789012345
+MAP
+---------------------------------.------------------------------------------
+|.....|.||..........|....|......|.|.........|.......+............---.......|
+|.....|..+..........+....---....S.|...-S-----.-----.|............+.+.......|
+|.....+.||........---......|....|.|...|.....|.|...|.---.....------.--------|
+|-----|.-------|..|........------.-----.....|.--..|...-------..............|
+|.....|........------+------..........+.....|..--S---.........------.-----..
+|.....|.------...............-----.}}.--------.|....-------.---....|.+...--|
+|..-+--.|....|-----.--------.|...|.....+.....|.|....|.....+.+......|.--....|
+|..|....|....|....+.|......|.|...-----.|.....|.--...|.....|.|......|..|....|
+|..|.-----S----...|.+....-----...|...|.----..|..|.---....--.---S-----.|----|
+|..|.|........|...------.|.S.....|...|....-----.+.|......|..|.......|.|....|
+|---.-------..|...|....|.|.|.....|...----.|...|.|---.....|.|-.......|.---..|
+...........|..S...|....---.----S----..|...|...+.|..-------.---+-....|...--+|
+|---------.---------...|......|....S..|.---...|.|..|...........----.---....|
+|........|.........|...+.------....|---.---...|.--+-.----.----....|.+...--+|
+|........|.---+---.|----.--........|......-----......|..|..|.--+-.|.-S-.|..|
+|........|.|.....|........----------.----.......---.--..|-.|....|.-----.|..|
+|----....+.|.....----+---............|..|--------.+.|...SS.|....|.......|..|
+|...--+-----.....|......|.------------............---...||.------+--+----..|
+|..........S.....|......|.|..........S............|.....||...|.....|....|..|
+-------------------------.--------------------------------------------------
+ENDMAP
+# Dungeon Description
+#REGION:(00,00,75,20),lit,"ordinary"
+# The down stairs is at one of the 4 "exits".  The others are mimics,
+# mimicing stairwells.
+RANDOM_PLACES: (33,0), (0,12), (25,20), (75,05)
+STAIR:place[0],down
+MONSTER:'m',"giant mimic", place[1], m_feature "staircase down"
+MONSTER:'m',"large mimic", place[2], m_feature "staircase down"
+MONSTER:'m',"small mimic", place[3], m_feature "staircase down"
+# Portal arrival point
+BRANCH:(19,09,19,09),(0,0,0,0)
+# Doors (secret)
+#DOOR:locked|closed|open,(xx,yy)
+DOOR: locked, (32, 2)
+DOOR: locked, (63, 9)
+DOOR: locked, (27,10)
+DOOR: locked, (31,12)
+DOOR: locked, (35,13)
+DOOR: locked, (69,15)
+DOOR: locked, (56,17)
+DOOR: locked, (57,17)
+DOOR: locked, (11,19)
+DOOR: locked, (37,19)
+DOOR: locked, (39, 2)
+DOOR: locked, (49, 5)
+DOOR: locked, (10, 9)
+DOOR: locked, (14,12)
+# Doors (regular)
+DOOR: closed, (52, 1)
+DOOR: closed, ( 9, 2)
+DOOR: closed, (20, 2)
+DOOR: closed, (65, 2)
+DOOR: closed, (67, 2)
+DOOR: closed, ( 6, 3)
+DOOR: closed, (21, 5)
+DOOR: closed, (38, 5)
+DOOR: closed, (69, 6)
+DOOR: closed, ( 4, 7)
+DOOR: closed, (39, 7)
+DOOR: closed, (58, 7)
+DOOR: closed, (60, 7)
+DOOR: closed, (18, 8)
+DOOR: closed, (20, 9)
+DOOR: closed, (48,10)
+DOOR: closed, (46,12)
+DOOR: closed, (62,12)
+DOOR: closed, (74,12)
+DOOR: closed, (23,14)
+DOOR: closed, (23,14)
+DOOR: closed, (50,14)
+DOOR: closed, (68,14)
+DOOR: closed, (74,14)
+DOOR: closed, (14,15)
+DOOR: closed, (63,15)
+DOOR: closed, ( 9,17)
+DOOR: closed, (21,17)
+DOOR: closed, (50,17)
+DOOR: closed, ( 6,18)
+DOOR: closed, (65,18)
+DOOR: closed, (68,18)
+# Master of Thieves
+MONSTER:'@',"Master of Thieves",(36,11)
+# The treasure of Master of Thieves
+OBJECT:'(',"chest",(36,11)
+# thug guards, room #1
+MONSTER:'@',"thug",(28,10)
+MONSTER:'@',"thug",(29,11)
+MONSTER:'@',"thug",(30,09)
+MONSTER:'@',"thug",(31,07)
+# thug guards, room #2
+MONSTER:'@',"thug",(31,13)
+MONSTER:'@',"thug",(33,14)
+MONSTER:'@',"thug",(30,15)
+#thug guards, room #3
+MONSTER:'@',"thug",(35,09)
+MONSTER:'@',"thug",(36,13)
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,20)
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+#
+# Monsters to get in the way.
+#
+# West exit
+MONSTER: 'l',"leprechaun",(01,12),hostile
+MONSTER: 'n',"water nymph",(02,12),hostile
+# North exit
+MONSTER: 'n',"water nymph",(33,01),hostile
+MONSTER: 'l',"leprechaun",(33,02),hostile
+# East exit
+MONSTER: 'n',"water nymph",(74,05),hostile
+MONSTER: 'l',"leprechaun",(74,04),hostile
+# South exit
+MONSTER: 'l',"leprechaun",(25,19),hostile
+MONSTER: 'n',"water nymph",(25,18),hostile
+# Wandering the streets.  What I'd really like for this is a random
+# location, but make sure we're on a given type, e.g. street (if they
+# existed, of course).
+MONSTER: 'n',"water nymph",(07,05),hostile
+MONSTER: 'l',"leprechaun",(28,06),hostile
+MONSTER: 'n',"water nymph",(38,07),hostile
+MONSTER: 'l',"leprechaun",(45,01),hostile
+MONSTER: 'n',"water nymph",(59,07),hostile
+MONSTER: 'l',"leprechaun",(62,14),hostile
+MONSTER: 'n',"water nymph",(71,14),hostile
+MONSTER: 'l',"leprechaun",(39,13),hostile
+MONSTER: 'n',"water nymph",(18,14),hostile
+MONSTER: ':',"chameleon",(19,08),hostile
+MONSTER: ':',"chameleon",(22,08),hostile
+MONSTER: ':',"chameleon",(16,08),hostile
+MONSTER: ':',"chameleon",random,hostile
+MONSTER: ':',"chameleon",random,hostile
+MONSTER: ':',"chameleon",random,hostile
+MONSTER: ':',"chameleon",random,hostile
+MONSTER: ':',"chameleon",random,hostile
+
+#
+#      The "locate" level for the quest.
+#
+#      Here you have to find the entrance to the Assassins' Guild to go
+#      further towards your assigned quest.
+#
+
+MAZE: "Rog-loca",' '
+GEOMETRY:center,center
+#         1         2         3         4         5         6         7
+#123456789012345678901234567890123456789012345678901234567890123456789012345
+MAP
+             ----------------------------------------------------   --------
+           ---.................................................-    --.....|
+         ---...--------........-------.......................---     ---...|
+       ---.....-      ---......-     ---..................----         --.--
+     ---.....----       --------       --..................--         --..|
+   ---...-----                       ----.----.....----.....---      --..||
+----..----                       -----..---  |...---  |.......---   --...|
+|...---                       ----....---    |.---    |.........-- --...||
+|...-                      ----.....---     ----      |..........---....|
+|...----                ----......---       |         |...|.......-....||
+|......-----          ---.........-         |     -----...|............|
+|..........-----   ----...........---       -------......||...........||
+|..............-----................---     |............|||..........|
+|------...............................---   |...........|| |.........||
+|.....|..............------.............-----..........||  ||........|
+|.....|.............--    ---.........................||    |.......||
+|.....|.............-       ---.....................--|     ||......|
+|-S----------.......----      --.................----        |.....||
+|...........|..........--------..............-----           ||....|
+|...........|............................-----                |....|
+------------------------------------------                    ------
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,20),lit,"ordinary"
+# Doors
+#DOOR:locked|closed|open,(xx,yy)
+# Stairs
+STAIR:random,up
+STAIR:random,down
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,20)
+# Objects
+OBJECT:'?',"teleportation",(11,18),cursed,0
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',random,random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',random,random,hostile
+MONSTER:'N',random,random,hostile
+MONSTER:'N',random,random,hostile
+MONSTER: ':',"chameleon",random,hostile
+MONSTER: ':',"chameleon",random,hostile
+MONSTER: ':',"chameleon",random,hostile
+MONSTER: ':',"chameleon",random,hostile
+MONSTER: ':',"chameleon",random,hostile
+
+#
+#      The "goal" level for the quest.  Teleportation and digging are
+#      disallowed.
+#
+#      You have to reach The Master Assassin via some means other than
+#      simple searching or digging since there is no path between your
+#      arrival point and his location.
+#
+MAZE: "Rog-goal", ' '
+FLAGS: noteleport
+GEOMETRY:center,center
+#         1         2         3         4         5         6         7
+#123456789012345678901234567890123456789012345678901234567890123456789012345
+MAP
+-----      -------.......................................|-----------------|
+|...|  -----.....|.......................................|.................|
+|...----...|.....|.......................................|....---------....|
+|.---......---..--.................................------------.......|....|
+|...............|..................................|..|...|...----........-|
+|.....-----....--.................................|-..--..-|.....----S----|
+|--S---...|....|.................................|-........-|....|........|
+|.........---------.............................|-....}}....-|...|...|....|
+|....|.....S......|............................|-.....}}.....-|..--.------|
+|-----.....--.....|...........................|-...}}}}}}}}...-|....|.....--
+|...........--....------S-----...............|-....}}}}}}}}....-|..........|
+|............--........|...| |..............--.....}}.}}........----------S-
+|.............|........|...| |..............|......}}}}}}}}......|...|.....|
+|S-.---.---.---.---.---|...| ------------...--........}}.}}.....--..---....|
+|.---.---.---.---.-S-..----- |....|.....|....|-....}}}}}}}}....---..S.|--..|
+|...|.......|..........|...---....---...S.....|-...}}}}}}}}...-|.S..|...|..|
+|...|..|....|..........|............|..--..----|-.....}}.....-|..----...-S--
+|...|---....----.......|----- ......|...---|    |-....}}....-|...|..--.--..|
+-----.....---.....--.---....--...--------..|     |-........-|....|.........|
+    |.............|..........|.............S...   |S-------|.....|..-----..|
+    ----------------------------------------  ......       ----------   ----
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,20),lit,"ordinary"
+# Stairs
+STAIR:levregion(01,00,15,20),(01,18,04,20),up
+# Doors
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,20)
+# One trap to keep the gnomes at bay.
+TRAP:"spiked pit",(37,07)
+# Objects
+OBJECT:'(',"skeleton key",(38,10),blessed,0,"The Master Key of Thievery"
+OBJECT:'%',"tin",(26,12),"chameleon",0
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'@',"Master Assassin",(38,10),hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',"leprechaun",random,hostile
+MONSTER:'l',random,random,hostile
+MONSTER:'l',random,random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',"guardian naga",random,hostile
+MONSTER:'N',random,random,hostile
+MONSTER:'N',random,random,hostile
+MONSTER:'N',random,random,hostile
+MONSTER: ':',"chameleon",random,hostile
+MONSTER: ':',"chameleon",random,hostile
+MONSTER: ':',"chameleon",random,hostile
+MONSTER: ':',"chameleon",random,hostile
+MONSTER: ':',"chameleon",random,hostile
+MONSTER:';',"shark",(51,14),hostile
+MONSTER:';',"shark",(53,09),hostile
+MONSTER:';',"shark",(55,15),hostile
+MONSTER:';',"shark",(58,10),hostile
+
+#
+#      The "fill" level for the quest.
+#
+#      This level is used to fill out any levels not occupied by specific
+#      levels as defined above.
+#
+LEVEL: "Rog-fila"
+#
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+OBJECT: random,random,random
+MONSTER: 'l', "leprechaun", random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random,random,random
+MONSTER: 'l', "leprechaun", random, hostile
+MONSTER: 'N', "guardian naga", random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+TRAP: random, random
+OBJECT: random,random,random
+MONSTER: 'n', "water nymph", random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+OBJECT: random, random, random
+TRAP: random, random
+TRAP: random, random
+MONSTER: 'l', random, random, hostile
+MONSTER: 'N', "guardian naga", random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+TRAP: random, random
+MONSTER: 'l', "leprechaun", random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+TRAP: random, random
+MONSTER: 'l', "leprechaun", random, hostile
+MONSTER: 'n', "water nymph", random, hostile
+
+RANDOM_CORRIDORS
+
+#
+# currently a & b are the same.
+#
+LEVEL: "Rog-filb"
+#
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+OBJECT: random,random,random
+MONSTER: 'l', "leprechaun", random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random,random,random
+MONSTER: 'l', "leprechaun", random, hostile
+MONSTER: 'N', "guardian naga", random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+TRAP: random, random
+OBJECT: random,random,random
+MONSTER: 'n', "water nymph", random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+OBJECT: random, random, random
+TRAP: random, random
+TRAP: random, random
+MONSTER: 'l', random, random, hostile
+MONSTER: 'N', "guardian naga", random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+TRAP: random, random
+MONSTER: 'l', "leprechaun", random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+TRAP: random, random
+MONSTER: 'l', "leprechaun", random, hostile
+MONSTER: 'n', "water nymph", random, hostile
+
+RANDOM_CORRIDORS
diff --git a/dat/Samurai.des b/dat/Samurai.des
new file mode 100644 (file)
index 0000000..5cb513f
--- /dev/null
@@ -0,0 +1,426 @@
+#      SCCS Id: @(#)Samurai.des        3.4     2002/04/08
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1991-92 by M. Stephenson, P. Winner
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The "start" level for the quest.
+#
+#      Here you meet your (besieged) class leader, Lord Sato
+#      and receive your quest assignment.
+#
+MAZE: "Sam-strt",' '
+FLAGS: noteleport,hardfloor
+GEOMETRY:center,center
+MAP
+..............................................................PP............
+...............................................................PP...........
+..........---------------------------------------------------...PPP.........
+..........|......|.........|...|..............|...|.........|....PPPPP......
+......... |......|.........S...|..............|...S.........|.....PPPP......
+..........|......|.........|---|..............|---|.........|.....PPP.......
+..........+......|.........+...-------++-------...+.........|......PP.......
+..........+......|.........|......................|.........|......PP.......
+......... |......---------------------++--------------------|........PP.....
+..........|.................................................|.........PP....
+..........|.................................................|...........PP..
+..........----------------------------------------...-------|............PP.
+..........................................|.................|.............PP
+.............. ................. .........|.................|..............P
+............. } ............... } ........|.................|...............
+.............. ........PP....... .........|.................|...............
+.....................PPP..................|.................|...............
+......................PP..................-------------------...............
+............................................................................
+............................................................................
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+REGION:(18,03,26,07),lit,"throne",unfilled
+# Portal arrival zone
+BRANCH:(62,12,70,17),(0,0,0,0)
+# Stairs
+STAIR:(29,04),down
+# Doors
+DOOR:locked,(10,06)
+DOOR:locked,(10,07)
+DOOR:closed,(27,04)
+DOOR:closed,(27,06)
+DOOR:closed,(38,06)
+DOOR:locked,(38,08)
+DOOR:closed,(39,06)
+DOOR:locked,(39,08)
+DOOR:closed,(50,04)
+DOOR:closed,(50,06)
+# Lord Sato
+MONSTER:'@',"Lord Sato",(20,04)
+# The treasure of Lord Sato
+OBJECT:'(',"chest",(20,04)
+# roshi guards for the audience chamber
+MONSTER:'@',"roshi",(18,04)
+MONSTER:'@',"roshi",(18,05)
+MONSTER:'@',"roshi",(18,06)
+MONSTER:'@',"roshi",(18,07)
+MONSTER:'@',"roshi",(26,04)
+MONSTER:'@',"roshi",(26,05)
+MONSTER:'@',"roshi",(26,06)
+MONSTER:'@',"roshi",(26,07)
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Monsters on siege duty.
+MONSTER: '@',"ninja",(64,00),hostile
+MONSTER: 'd',"wolf",(65,01)
+MONSTER: '@',"ninja",(67,02),hostile
+MONSTER: '@',"ninja",(69,05),hostile
+MONSTER: '@',"ninja",(69,06),hostile
+MONSTER: 'd',"wolf",(69,07)
+MONSTER: '@',"ninja",(70,06),hostile
+MONSTER: '@',"ninja",(70,07),hostile
+MONSTER: '@',"ninja",(72,01),hostile
+MONSTER: 'd',"wolf",(75,09)
+MONSTER: '@',"ninja",(73,05),hostile
+MONSTER: '@',"ninja",(68,02),hostile
+MONSTER:'E',"stalker",random
+
+#
+#      The "locate" level for the quest.
+#
+#      Here you have to invade the Shogun's Castle to go
+#      further towards your assigned quest.
+#
+
+MAZE: "Sam-loca",' '
+FLAGS: hardfloor
+GEOMETRY:center,center
+MAP
+............................................................................
+............................................................................
+........-----..................................................-----........
+........|...|..................................................|...|........
+........|...---..}..--+------------------------------+--..}..---...|........
+........|-|...|.....|...|....|....|....|....|....|.|...|.....|...|-|........
+..........|...-------...|....|....|....|....|....S.|...-------...|..........
+..........|-|.........------+----+-+-------+-+--------.........|-|..........
+............|..--------.|}........................}|.--------..|............
+............|..+........+..........................+........+..|............
+............|..+........+..........................+........+..|............
+............|..--------.|}........................}|.--------..|............
+..........|-|.........--------+-+-------+-+----+------.........|-|..........
+..........|...-------...|.S....|....|....|....|....|...-------...|..........
+........|-|...|.....|...|.|....|....|....|....|....|...|.....|...|-|........
+........|...---..}..--+------------------------------+--..}..---...|........
+........|...|..................................................|...|........
+........-----..................................................-----........
+............................................................................
+............................................................................
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+# Doors
+DOOR:locked,(22,04)
+DOOR:locked,(22,15)
+DOOR:locked,(53,04)
+DOOR:locked,(53,15)
+DOOR:locked,(49,06)
+DOOR:locked,(26,13)
+DOOR:locked,(28,07)
+DOOR:locked,(30,12)
+DOOR:locked,(33,07)
+DOOR:locked,(32,12)
+DOOR:locked,(35,07)
+DOOR:locked,(40,12)
+DOOR:locked,(43,07)
+DOOR:locked,(42,12)
+DOOR:locked,(45,07)
+DOOR:locked,(47,12)
+DOOR:closed,(15,09)
+DOOR:closed,(15,10)
+DOOR:closed,(24,09)
+DOOR:closed,(24,10)
+DOOR:closed,(51,09)
+DOOR:closed,(51,10)
+DOOR:closed,(60,09)
+DOOR:closed,(60,10)
+# Stairs
+STAIR:(10,10),up
+STAIR:(25,14),down
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Objects
+OBJECT:'*',random,(25,05)
+OBJECT:'*',random,(26,05)
+OBJECT:'*',random,(27,05)
+OBJECT:'*',random,(28,05)
+OBJECT:'*',random,(25,06)
+OBJECT:'*',random,(26,06)
+OBJECT:'*',random,(27,06)
+OBJECT:'*',random,(28,06)
+#
+OBJECT:'[',random,(40,05)
+OBJECT:'[',random,(41,05)
+OBJECT:'[',random,(42,05)
+OBJECT:'[',random,(43,05)
+OBJECT:'[',random,(40,06)
+OBJECT:'[',random,(41,06)
+OBJECT:'[',random,(42,06)
+OBJECT:'[',random,(43,06)
+#
+OBJECT:')',random,(27,13)
+OBJECT:')',random,(28,13)
+OBJECT:')',random,(29,13)
+OBJECT:')',random,(30,13)
+OBJECT:')',random,(27,14)
+OBJECT:')',random,(28,14)
+OBJECT:')',random,(29,14)
+OBJECT:')',random,(30,14)
+#
+OBJECT:'(',random,(37,13)
+OBJECT:'(',random,(38,13)
+OBJECT:'(',random,(39,13)
+OBJECT:'(',random,(40,13)
+OBJECT:'(',random,(37,14)
+OBJECT:'(',random,(38,14)
+OBJECT:'(',random,(39,14)
+OBJECT:'(',random,(40,14)
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'@',"ninja",(15,05),hostile
+MONSTER:'@',"ninja",(16,05),hostile
+MONSTER:'d',"wolf",(17,05)
+MONSTER:'d',"wolf",(18,05)
+MONSTER:'@',"ninja",(19,05),hostile
+MONSTER:'d',"wolf",(15,14)
+MONSTER:'d',"wolf",(16,14)
+MONSTER:'@',"ninja",(17,14),hostile
+MONSTER:'@',"ninja",(18,14),hostile
+MONSTER:'d',"wolf",(56,05)
+MONSTER:'@',"ninja",(57,05),hostile
+MONSTER:'d',"wolf",(58,05)
+MONSTER:'d',"wolf",(59,05)
+MONSTER:'@',"ninja",(56,14),hostile
+MONSTER:'d',"wolf",(57,14)
+MONSTER:'@',"ninja",(58,14),hostile
+MONSTER:'d',random,(59,14)
+MONSTER:'d',"wolf",(60,14)
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+#      "guards" for the central courtyard.
+MONSTER:'@',"samurai",(30,05),hostile
+MONSTER:'@',"samurai",(31,05),hostile
+MONSTER:'@',"samurai",(32,05),hostile
+MONSTER:'@',"samurai",(32,14),hostile
+MONSTER:'@',"samurai",(33,14),hostile
+MONSTER:'@',"samurai",(34,14),hostile
+
+#
+#      The "goal" level for the quest.
+#
+#      Here you meet Takauji, your nemesis monster.  You have to
+#      defeat him in combat to gain the artifact you have been
+#      assigned to retrieve.
+#
+
+MAZE: "Sam-goal", ' '
+FLAGS: noteleport
+GEOMETRY:center,center
+MAP
+                                             
+           .......................           
+       ......---------.---------......       
+    ......----.................----......    
+   ....----.....-------------.....----....   
+  ....--.....----...........----.....--....  
+  ...||....---....---------....---....||...  
+  ...|....--....---.......---....--....|...  
+ ....|...||...---...--+--...---...||...|.... 
+ ....|...|....|....|-...-|....|....|...|.... 
+ ....|...|....|....+.....+....|........|.... 
+ ....|...|....|....|-...-|....|....|...|.... 
+ ....|...||...---...--+--...---...||...|.... 
+  ...|....--....---.......---....--....|...  
+  ...||....---....----.----....---....||...  
+  ....--.....----...........----.....--....  
+   ....----.....-------------.....----....   
+    ......----.................----......    
+       ......-------------------......       
+           .......................           
+ENDMAP
+# Dungeon Description
+RANDOM_PLACES:(02,11),(42,09)
+REGION:(00,00,44,19),unlit,"ordinary"
+# Doors
+DOOR:closed,(19,10)
+DOOR:closed,(22,08)
+DOOR:closed,(22,12)
+DOOR:closed,(25,10)
+# Stairs
+STAIR:place[0],up
+# Non diggable walls
+NON_DIGGABLE:(00,00,44,19)
+# Objects
+OBJECT:')',"tsurugi",(22,10),blessed,0,"The Tsurugi of Muramasa"
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+#
+TRAP:"board",(22,09)
+TRAP:"board",(24,10)
+TRAP:"board",(22,11)
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'@',"Ashikaga Takauji",(22,10)
+MONSTER:'@',"samurai",random,hostile
+MONSTER:'@',"samurai",random,hostile
+MONSTER:'@',"samurai",random,hostile
+MONSTER:'@',"samurai",random,hostile
+MONSTER:'@',"samurai",random,hostile
+MONSTER:'@',"ninja",random,hostile
+MONSTER:'@',"ninja",random,hostile
+MONSTER:'@',"ninja",random,hostile
+MONSTER:'@',"ninja",random,hostile
+MONSTER:'@',"ninja",random,hostile
+MONSTER:'d',"wolf",random
+MONSTER:'d',"wolf",random
+MONSTER:'d',"wolf",random
+MONSTER:'d',"wolf",random
+MONSTER:'d',random,random
+MONSTER:'d',random,random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+MONSTER:'E',"stalker",random
+
+
+#
+#      The "fill" levels for the quest.
+#
+#      These levels are used to fill out any levels not occupied by specific
+#      levels as defined above. "filla" is the upper filler, between the
+#      start and locate levels, and "fillb" the lower between the locate
+#      and goal levels.
+#
+
+MAZE: "Sam-fila", ' '
+INIT_MAP: '.' , 'P', true, true, random, true
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+MONSTER: 'd', random, random
+MONSTER: 'd', "wolf", random
+MONSTER: 'd', "wolf", random
+MONSTER: 'd', "wolf", random
+MONSTER: 'd', "wolf", random
+MONSTER: 'd', "wolf", random
+MONSTER: 'E', "stalker", random
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+
+MAZE: "Sam-filb", ' '
+GEOMETRY:center,center
+MAP
+-------------                                  -------------
+|...........|                                  |...........|
+|...-----...|----------------------------------|...-----...|
+|...|   |...|..................................|...|   |...|
+|...-----..........................................-----...|
+|...........|--S----------------------------S--|...........|
+----...--------.|..........................|.--------...----
+   |...|........+..........................+........|...|   
+   |...|........+..........................+........|...|   
+----...--------.|..........................|.--------...----
+|...........|--S----------------------------S--|...........|
+|...-----..........................................-----...|
+|...|   |...|..................................|...|   |...|
+|...-----...|----------------------------------|...-----...|
+|...........|                                  |...........|
+-------------                                  -------------
+ENDMAP
+REGION:(00,00,59,15),unlit,"ordinary"
+# Doors
+DOOR:closed,(16,07)
+DOOR:closed,(16,08)
+DOOR:closed,(43,07)
+DOOR:closed,(43,08)
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+MONSTER: 'd', random, random
+MONSTER: 'd', "wolf", random
+MONSTER: 'd', "wolf", random
+MONSTER: 'd', "wolf", random
+MONSTER: 'd', "wolf", random
+MONSTER: 'E', "stalker", random
+MONSTER: 'E', "stalker", random
+MONSTER: 'E', "stalker", random
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
diff --git a/dat/Tourist.des b/dat/Tourist.des
new file mode 100644 (file)
index 0000000..348b9b7
--- /dev/null
@@ -0,0 +1,519 @@
+#      SCCS Id: @(#)Tourist.des        3.4     1992/09/26
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1991,92 by M. Stephenson, P. Winner
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The "start" level for the quest.
+#
+#      Here you meet your (besieged) class leader, Twoflower
+#      and receive your quest assignment.
+#
+MAZE: "Tou-strt",' '
+FLAGS: noteleport,hardfloor
+GEOMETRY:center,center
+MAP
+.......}}....---------..-------------------------------------------------...
+........}}...|.......|..|.-------------------------------------------...|...
+.........}}..|.......|..|.|......|......|.............|......|......|...|...
+..........}}.|.......|..|.|......+......+.............+......+..\...|...|...
+...........}}}..........|.|......|......|.............|......|......|...|...
+.............}}.........|.|----S-|--S---|S----------S-|---S--|------|...|...
+..............}}}.......|...............................................|...
+................}}}.....----S------++--S----------S----------S-----------...
+..................}}...........    ..    ...................................
+......-------......}}}}........}}}}..}}}}..}}}}..}}}}.......................
+......|.....|.......}}}}}}..}}}}   ..   }}}}..}}}}..}}}.....................
+......|.....+...........}}}}}}........................}}}..}}}}..}}}..}}}...
+......|.....|...........................................}}}}..}}}..}}}}.}}}}
+......-------...............................................................
+............................................................................
+...-------......-------.....................................................
+...|.....|......|.....|.....................................................
+...|.....+......+.....|.....................................................
+...|.....|......|.....|.....................................................
+...-------......-------.....................................................
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+REGION:(14,01,20,03),unlit,"morgue"
+REGION:(07,10,11,12),unlit,"ordinary"
+REGION:(04,16,08,18),unlit,"ordinary"
+REGION:(17,16,21,18),unlit,"ordinary"
+REGION:(27,02,32,04),unlit,"ordinary"
+REGION:(34,02,39,04),unlit,"ordinary"
+REGION:(41,02,53,04),unlit,"ordinary"
+REGION:(55,02,60,04),unlit,"ordinary"
+REGION:(62,02,67,04),lit,"ordinary"
+# Stairs
+STAIR:(66,03),down
+# Portal arrival point
+BRANCH:(68,14,68,14),(0,0,0,0)
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Doors
+DOOR:locked,(31,05)
+DOOR:locked,(36,05)
+DOOR:locked,(41,05)
+DOOR:locked,(52,05)
+DOOR:locked,(58,05)
+DOOR:locked,(28,07)
+DOOR:locked,(39,07)
+DOOR:locked,(50,07)
+DOOR:locked,(61,07)
+DOOR:closed,(33,03)
+DOOR:closed,(40,03)
+DOOR:closed,(54,03)
+DOOR:closed,(61,03)
+DOOR:open,(12,11)
+DOOR:open,(09,17)
+DOOR:open,(16,17)
+DOOR:locked,(35,07)
+DOOR:locked,(36,07)
+# Monsters on siege duty.
+MONSTER: 's',"giant spider",random
+MONSTER: 's',"giant spider",random
+MONSTER: 's',"giant spider",random
+MONSTER: 's',"giant spider",random
+MONSTER: 's',"giant spider",random
+MONSTER: 's',"giant spider",random
+MONSTER: 's',"giant spider",random
+MONSTER: 's',"giant spider",random
+MONSTER: 's',"giant spider",random
+MONSTER: 's',"giant spider",random
+MONSTER: 's',"giant spider",random
+MONSTER: 's',"giant spider",random
+MONSTER: 's',random,random
+MONSTER: 's',random,random
+MONSTER: 'C',"forest centaur",random
+MONSTER: 'C',"forest centaur",random
+MONSTER: 'C',"forest centaur",random
+MONSTER: 'C',"forest centaur",random
+MONSTER: 'C',"forest centaur",random
+MONSTER: 'C',"forest centaur",random
+MONSTER: 'C',"forest centaur",random
+MONSTER: 'C',"forest centaur",random
+MONSTER: 'C',random,random
+# Twoflower
+MONSTER:'@',"Twoflower",(64,03)
+# The treasure of Twoflower
+OBJECT:'(',"chest",(64,03)
+# guides for the audience chamber
+MONSTER:'@',"guide",(29,03)
+MONSTER:'@',"guide",(32,04)
+MONSTER:'@',"guide",(35,02)
+MONSTER:'@',"guide",(38,03)
+MONSTER:'@',"guide",(45,03)
+MONSTER:'@',"guide",(48,02)
+MONSTER:'@',"guide",(49,04)
+MONSTER:'@',"guide",(51,03)
+MONSTER:'@',"guide",(57,03)
+MONSTER:'@',"guide",(62,04)
+MONSTER:'@',"guide",(66,04)
+# path guards
+MONSTER:'@',"watchman",(35,08)
+MONSTER:'@',"watchman",(36,08)
+# river monsters
+MONSTER:';',"giant eel",(62,12)
+MONSTER:';',"piranha",(47,10)
+MONSTER:';',"piranha",(29,11)
+MONSTER:';',"kraken",(34,09)
+MONSTER:';',"kraken",(37,09)
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+
+#
+#      The "locate" level for the quest.
+#
+#      Here you have to find the Thieves' Guild Hall to go
+#      further towards your assigned quest.
+#
+
+MAZE: "Tou-loca",' '
+FLAGS: hardfloor
+GEOMETRY:center,center
+MAP
+----------------------------------------------------------------------------
+|....|......|..........|......|......|...|....|.....|......|...............|
+|....|......|.|------|.|......|......|.|.|....|..}..|......|.|----------|..|
+|....|--+----.|......|.|-S---+|+-----|.|.S....|.....|---+--|.|..........+..|
+|....|........|......|.|...|.........|.|------|..............|..........|-+|
+|....+...}}...+......|.|...|.|-----|.|..............|--+----------------|..|
+|----|........|------|.|---|.|.....|......|-----+-|.|.......|...........|--|
+|............................|.....|.|--+-|.......|.|.......|...........|..|
+|----|.....|-------------|...|--+--|.|....|.......|.|-----------+-------|..|
+|....+.....+.........S...|...........|....|-------|........................|
+|....|.....|.........|...|.|---------|....|.........|-------|.|----------|.|
+|....|.....|---------|---|.|......|..+....|-------|.|.......|.+......S.\.|.|
+|....|.....+.........S...|.|......|..|....|.......|.|.......|.|......|...|.|
+|-------|..|.........|---|.|+-------------------+-|.|.......+.|----------|.|
+|.......+..|---------|.........|.........|..........|.......|.|..........|.|
+|.......|..............|--+--|.|.........|.|----+-----------|.|..........|.|
+|---------+-|--+-----|-|.....|.|.........|.|........|.|.....+.|..........+.|
+|...........|........|.S.....|.|----+----|.|--------|.|.....|.|----------|.|
+|...........|........|.|.....|........................|.....|..............|
+----------------------------------------------------------------------------
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+NON_DIGGABLE:(00,00,75,19)
+#
+REGION:(01,01,04,05),unlit,"morgue"
+REGION:(15,03,20,05),lit,"shop"
+REGION:(62,03,71,04),lit,"shop"
+REGION:(01,17,11,18),lit,"barracks"
+REGION:(12,09,20,10),lit,"barracks"
+REGION:(53,11,59,14),lit,"zoo"
+REGION:(63,14,72,16),lit,"barracks"
+REGION:(32,14,40,16),lit,"temple"
+#
+REGION:(06,01,11,02),random,"ordinary"
+REGION:(24,01,29,02),random,"ordinary"
+REGION:(31,01,36,02),random,"ordinary"
+REGION:(42,01,45,03),random,"ordinary"
+REGION:(53,01,58,02),random,"ordinary"
+REGION:(24,04,26,05),random,"ordinary"
+REGION:(30,06,34,07),random,"ordinary"
+REGION:(73,05,74,05),unlit,"ordinary"
+REGION:(01,09,04,12),random,"ordinary"
+REGION:(01,14,07,15),random,"ordinary"
+REGION:(12,12,20,13),random,"ordinary"
+REGION:(13,17,20,18),random,"ordinary"
+REGION:(22,09,24,10),random,"ordinary"
+REGION:(22,12,24,12),random,"ordinary"
+REGION:(24,16,28,18),random,"ordinary"
+REGION:(28,11,33,12),random,"ordinary"
+REGION:(35,11,36,12),lit,"ordinary"
+REGION:(38,08,41,12),random,"ordinary"
+REGION:(43,07,49,08),random,"ordinary"
+REGION:(43,12,49,12),random,"ordinary"
+REGION:(44,16,51,16),random,"ordinary"
+REGION:(53,06,59,07),random,"ordinary"
+REGION:(61,06,71,07),random,"ordinary"
+REGION:(55,16,59,18),random,"ordinary"
+REGION:(63,11,68,12),random,"ordinary"
+REGION:(70,11,72,12),random,"ordinary"
+# Stairs
+STAIR:(10,04),up
+STAIR:(73,05),down
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+DOOR:closed,(05,05)
+DOOR:closed,(05,09)
+DOOR:closed,(08,14)
+DOOR:closed,(08,03)
+DOOR:closed,(11,09)
+DOOR:closed,(11,12)
+DOOR:closed,(10,16)
+DOOR:closed,(14,05)
+DOOR:closed,(15,16)
+DOOR:locked,(21,09)
+DOOR:locked,(21,12)
+DOOR:closed,(23,17)
+DOOR:closed,(25,03)
+DOOR:closed,(26,15)
+DOOR:closed,(29,03)
+DOOR:closed,(28,13)
+DOOR:closed,(31,03)
+DOOR:closed,(32,08)
+DOOR:closed,(37,11)
+DOOR:closed,(36,17)
+DOOR:locked,(41,03)
+DOOR:closed,(40,07)
+DOOR:closed,(48,06)
+DOOR:closed,(48,13)
+DOOR:closed,(48,15)
+DOOR:closed,(56,03)
+DOOR:closed,(55,05)
+DOOR:closed,(72,03)
+DOOR:locked,(74,04)
+DOOR:closed,(64,08)
+DOOR:closed,(62,11)
+DOOR:closed,(69,11)
+DOOR:closed,(60,13)
+DOOR:closed,(60,16)
+DOOR:closed,(73,16)
+
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Toilet paper
+OBJECT:'?',"blank paper",(71,12)
+OBJECT:'?',"blank paper",(71,12)
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',random,random
+MONSTER:'s',random,random
+
+#
+#      The "goal" level for the quest.
+#
+#      Here you meet the Master of Thieves your nemesis monster.  You have to
+#      defeat the Master of Thieves in combat to gain the artifact you have
+#      been assigned to retrieve.
+#
+
+MAZE: "Tou-goal", ' '
+GEOMETRY:center,center
+MAP
+----------------------------------------------------------------------------
+|.........|.........|..........|..| |.................|........|........|..|
+|.........|.........|..........|..| |....--------.....|........|........|..|
+|------S--|--+-----------+------..| |....|......|.....|........|........|..|
+|.........|.......................| |....|......+.....--+-------------+--..|
+|.........|.......................| |....|......|..........................|
+|-S-----S-|......----------.......| |....|......|..........................|
+|..|..|...|......|........|.......| |....-----------.........----..........|
+|..+..+...|......|........|.......| |....|.........|.........|}}|..........|
+|..|..|...|......+........|.......| |....|.........+.........|}}|..........|
+|..|..|...|......|........|.......S.S....|.........|.........----..........|
+|---..----|......|........|.......| |....|.........|.......................|
+|.........+......|+F-+F-+F|.......| |....-----------.......................|
+|---..----|......|..|..|..|.......| |......................--------------..|
+|..|..|...|......--F-F--F--.......| |......................+............|..|
+|..+..+...|.......................| |--.---...-----+-----..|............|..|
+|--|..----|--+-----------+------..| |.....|...|.........|..|------------|..|
+|..+..+...|.........|..........|..| |.....|...|.........|..+............|..|
+|..|..|...|.........|..........|..| |.....|...|.........|..|............|..|
+----------------------------------------------------------------------------
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+# The Inn
+REGION:(01,01,09,02),lit,"ordinary"
+REGION:(01,04,09,05),lit,"barracks"
+REGION:(01,07,02,10),unlit,"ordinary"
+REGION:(07,07,09,10),unlit,"ordinary"
+REGION:(01,14,02,15),unlit,"ordinary"
+REGION:(07,14,09,15),unlit,"ordinary"
+REGION:(01,17,02,18),unlit,"ordinary"
+REGION:(07,17,09,18),unlit,"ordinary"
+#
+REGION:(11,01,19,02),unlit,"barracks"
+REGION:(21,01,30,02),unlit,"ordinary"
+REGION:(11,17,19,18),unlit,"barracks"
+REGION:(21,17,30,18),unlit,"ordinary"
+# Police Station
+REGION:(18,07,25,11),lit,"ordinary"
+REGION:(18,13,19,13),unlit,"ordinary"
+REGION:(21,13,22,13),unlit,"ordinary"
+REGION:(24,13,25,13),unlit,"ordinary"
+# The town itself
+REGION:(42,03,47,06),unlit,"ordinary"
+REGION:(42,08,50,11),unlit,"ordinary"
+REGION:(37,16,41,18),unlit,"morgue"
+REGION:(47,16,55,18),unlit,"ordinary"
+REGION:(55,01,62,03),unlit,"ordinary"
+REGION:(64,01,71,03),unlit,"ordinary"
+REGION:(60,14,71,15),lit,"shop"
+REGION:(60,17,71,18),lit,"shop"
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Stairs
+STAIR:(70,08),up
+# Doors
+DOOR:locked,(07,03)
+DOOR:locked,(02,06)
+DOOR:locked,(08,06)
+DOOR:closed,(03,08)
+DOOR:closed,(06,08)
+DOOR:open,(10,12)
+DOOR:closed,(03,15)
+DOOR:closed,(06,15)
+DOOR:closed,(03,17)
+DOOR:closed,(06,17)
+DOOR:closed,(13,03)
+DOOR:random,(25,03)
+DOOR:closed,(13,16)
+DOOR:random,(25,16)
+DOOR:locked,(17,09)
+DOOR:locked,(18,12)
+DOOR:locked,(21,12)
+DOOR:locked,(24,12)
+DOOR:locked,(34,10)
+DOOR:locked,(36,10)
+DOOR:random,(48,04)
+DOOR:random,(56,04)
+DOOR:random,(70,04)
+DOOR:random,(51,09)
+DOOR:random,(51,15)
+DOOR:open,(59,14)
+DOOR:open,(59,17)
+# Objects
+OBJECT:'(',"credit card",(04,01),blessed,0,"The Platinum Yendorian Express Card"
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'@',"Master of Thieves",(04,01),hostile
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',"giant spider",random
+MONSTER:'s',random,random
+MONSTER:'s',random,random
+# ladies of the evening
+MONSTER:'&',"succubus",(02,08)
+MONSTER:'&',"succubus",(08,08)
+MONSTER:'&',"incubus",(02,14)
+MONSTER:'&',"incubus",(08,14)
+MONSTER:'&',"incubus",(02,17)
+MONSTER:'&',"incubus",(08,17)
+# Police station (with drunken prisoners)
+MONSTER:'K',"Kop Kaptain",(24,09),hostile
+MONSTER:'K',"Kop Lieutenant",(20,09),hostile
+MONSTER:'K',"Kop Lieutenant",(22,11),hostile
+MONSTER:'K',"Kop Lieutenant",(22,07),hostile
+MONSTER:'K',"Keystone Kop",(19,07),hostile
+MONSTER:'K',"Keystone Kop",(19,08),hostile
+MONSTER:'K',"Keystone Kop",(22,09),hostile
+MONSTER:'K',"Keystone Kop",(24,11),hostile
+MONSTER:'K',"Keystone Kop",(19,11),hostile
+MONSTER:'@',"prisoner",(19,13)
+MONSTER:'@',"prisoner",(21,13)
+MONSTER:'@',"prisoner",(24,13)
+#
+MONSTER:'@',"watchman",(33,10),hostile
+
+WALLIFY
+
+#
+#      The "fill" level for the quest.
+#
+#      This level is used to fill out any levels not occupied by specific
+#      levels as defined above.
+#
+
+MAZE: "Tou-fila" , ' '
+INIT_MAP: '.' , ' ', true, true, random, true
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+#
+MONSTER: '@', "soldier", random, hostile
+MONSTER: '@', "soldier", random, hostile
+MONSTER: '@', "soldier", random, hostile
+MONSTER: '@', "soldier", random, hostile
+MONSTER: '@', "soldier", random, hostile
+MONSTER: 'H', random, random, hostile
+MONSTER: 'C', random, random, hostile
+
+MAZE: "Tou-filb" , ' '
+INIT_MAP: '.' , ' ', true, true, random, true
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+#
+MONSTER: '@', "soldier", random, hostile
+MONSTER: '@', "captain", random, hostile
+MONSTER: '@', "captain", random, hostile
+MONSTER: 'H', random, random, hostile
+MONSTER: 'H', random, random, hostile
+MONSTER: 'C', random, random, hostile
+MONSTER: 's', random, random
diff --git a/dat/Valkyrie.des b/dat/Valkyrie.des
new file mode 100644 (file)
index 0000000..58116d5
--- /dev/null
@@ -0,0 +1,332 @@
+#      SCCS Id: @(#)Valkyrie.des       3.4     2002/05/02
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1991-2 by M. Stephenson
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The "start" level for the quest.
+#
+#      Here you meet your (besieged) class leader, the Norn,
+#      and receive your quest assignment.
+#
+MAZE: "Val-strt",' '
+FLAGS: noteleport,hardfloor
+GEOMETRY:center,center
+MAP
+IIIIIIPPPIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
+IIIIPPPPPIIIIIIII..IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...IIIIIIIIIIIIIIIIIIIII
+IIIIPLLPPIIIIIII..IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII..{..IIIIIIIIIIIIIIIIIIII
+IIIIPLPPIIIIIII..IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII.....IIIIIIPPPIIIIIIIIII
+IIIPPPPPIIIIII..IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII.IIIIIPPLPIIIIIIIIII
+IIIIPIIIIIIII..IIIIPPPIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII.IIIIIPLPPIIIIIIIIII
+IIIIIIIIIIII..IIIIIPLPPIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII..IIIIIPPPIIIIIIIIIII
+IIIIIIII.....IIIIIIPPPIIII|----------------|IIIIIPPPIII.IIIIIIIIIIIIIIIIIIII
+IIIIIII..III...IIIIIIIIIII|................|IIIIIPLPII..IIIIIIIIIIIIIIIIIIII
+IIIIII..IIIIII......IIIII.|................|.IIIIPPPII.IIIIIIIIIIIIIIIIIIIII
+IIIII..IIIIIIIIIIII.......+................+...IIIIIII.IIIIIIIIIIIIIIIIIIIII
+IIII..IIIIIIIII.....IIIII.|................|.I...IIIII.IIIIIIIIIIIIIIIIIIIII
+III..IIIIIIIII..IIIIIIIIII|................|IIII.......IIIIIIIIIIIIIIIIIIIII
+IIII..IIIIIII..IIIIIIIIIII|----------------|IIIIIIIIII...IIIIIIIIIIIIIIIIIII
+IIIIII..IIII..IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIPPPPIIII...IIIIIIIIIIIIIIIII
+IIIIIII......IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIPLLPPIIIII...IIIIIIIIIIIIIII
+IIIIPPPIP...IIIIIIIIIIIPIIIIIIIIIIIIIIIIIIIIIIIIPPPPIIIIIIII...I......IIIIII
+IIIPPLPPIIIIIIIIIIIIIIPPPIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII.........IIIII
+IIIIPPPIIIIIIIIIIIIIIPPLPIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII.......IIIIII
+IIIIIIIIIIIIIIIIIIIIIIPPPIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+REGION:(27,08,42,12),lit,"ordinary"
+# Portal arrival point
+BRANCH:(66,17,66,17),(0,0,0,0)
+# Stairs
+STAIR:(18,01),down
+FOUNTAIN:(53,02)
+# Doors
+DOOR:locked,(26,10)
+DOOR:locked,(43,10)
+# Norn
+MONSTER:'@',"Norn",(35,10)
+# The treasure of the Norn
+OBJECT:'(',"chest",(36,10)
+# valkyrie guards for the audience chamber
+MONSTER:'@',"warrior",(27,08)
+MONSTER:'@',"warrior",(27,09)
+MONSTER:'@',"warrior",(27,11)
+MONSTER:'@',"warrior",(27,12)
+MONSTER:'@',"warrior",(42,08)
+MONSTER:'@',"warrior",(42,09)
+MONSTER:'@',"warrior",(42,11)
+MONSTER:'@',"warrior",(42,12)
+# Non diggable walls
+NON_DIGGABLE:(26,07,43,13)
+# Random traps
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+# Monsters on siege duty.
+MONSTER: 'a',"fire ant",(04,12)
+MONSTER: 'a',"fire ant",(08,08)
+MONSTER: 'a',"fire ant",(14,04)
+MONSTER: 'a',"fire ant",(17,11)
+MONSTER: 'a',"fire ant",(24,10)
+MONSTER: 'a',"fire ant",(45,10)
+MONSTER: 'a',"fire ant",(54,02)
+MONSTER: 'a',"fire ant",(55,07)
+MONSTER: 'a',"fire ant",(58,14)
+MONSTER: 'a',"fire ant",(63,17)
+MONSTER: 'H',"fire giant",(18,01),hostile
+MONSTER: 'H',"fire giant",(10,16),hostile
+
+#
+#      The "locate" level for the quest.
+#
+#      Here you have to find the cave of Surtur to go
+#      further towards your assigned quest.
+#
+
+MAZE: "Val-loca",' '
+FLAGS: hardfloor
+INIT_MAP: '.' , 'I' , true , true , lit , false
+GEOMETRY:center,center
+MAP
+PPPP....                      ....PPPPP.
+PLP...                          .PPLLLPP
+PPP    .......................    PPPLLP
+..   ............................   PPPP
+.  ...............................  ....
+  .................................   ..
+....................................   .
+  ...................................   
+.  ..................................  .
+..   ..............................   PP
+.PPP  ..........................     PLP
+.PLLP                             ..PLLP
+.PPPP..                         ....PPPP
+ENDMAP
+# Dungeon Description
+REGION:(00,00,39,12),lit,"ordinary"
+# Stairs
+STAIR:(48,14),up
+STAIR:(20,06),down
+# Non diggable walls
+NON_DIGGABLE:(00,00,39,12)
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',random,random
+MONSTER:'H',random,random,hostile
+MONSTER:'H',"fire giant",random,hostile
+MONSTER:'H',"fire giant",random,hostile
+MONSTER:'H',"fire giant",random,hostile
+MONSTER:'H',"fire giant",random,hostile
+MONSTER:'H',"fire giant",random,hostile
+MONSTER:'H',"fire giant",random,hostile
+MONSTER:'H',"fire giant",random,hostile
+MONSTER:'H',random,random,hostile
+
+#
+#      The "goal" level for the quest.
+#
+#      Here you meet Lord Surtur your nemesis monster.  You have to
+#      defeat Lord Surtur in combat to gain the artifact you have
+#      been assigned to retrieve.
+#
+
+MAZE: "Val-goal", 'L'
+INIT_MAP: '.' , 'L' , true , true , lit , false
+GEOMETRY:center,center
+MAP
+.L............................LLLLL
+LLL.........LLLLL.LLLLL.........LLL
+.LLL......LLLLLLLLLLLLLLL.......LL.
+.LLL.....LLL|---------|LLL.....L...
+..LL....LL|--.........--|LL.....LLL
+.......LL|-...LLLLLLL...-|LL.....L.
+.......LL|...LL.....LL...|LL.......
+......LL|-..LL.......LL..-|LL......
+......LL|.................|LL......
+......LL|-..LL.......LL..-|LL......
+.......LL|...LL.....LL...|LL.......
+.......LL|-...LLLLLLL...-|LL.......
+..L.....LL|--.........--|LL.....LL.
+..LL.....LLL|---------|LLL....LLLL.
+..LLL.....LLLLLLLLLLLLLLL...LLLLL..
+.LLLL.......LLLLL.LLLLL.....LLLL...
+..LL...............................
+ENDMAP
+# Dungeon Description
+REGION:(00,00,34,16),lit,"ordinary"
+# Stairs
+# Note:  The up stairs are *intentionally* off of the map.
+STAIR:(45,10),up
+# Non diggable walls
+NON_DIGGABLE:(00,00,34,16)
+# Drawbridges
+DRAWBRIDGE:(17,02),south,open
+DRAWBRIDGE:(17,14),north,open
+# Objects
+OBJECT:'(',"crystal ball",(17,08),blessed,5,"The Orb of Fate"
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Traps
+TRAP:"board",(13,08)
+TRAP:"board",(21,08)
+# Random traps
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"board",random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'H',"Lord Surtur",(17,08)
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',"fire ant",random
+MONSTER:'a',random,random
+MONSTER:'a',random,random
+MONSTER:'H',"fire giant",(10,06),hostile
+MONSTER:'H',"fire giant",(10,07),hostile
+MONSTER:'H',"fire giant",(10,08),hostile
+MONSTER:'H',"fire giant",(10,09),hostile
+MONSTER:'H',"fire giant",(10,10),hostile
+MONSTER:'H',"fire giant",(24,06),hostile
+MONSTER:'H',"fire giant",(24,07),hostile
+MONSTER:'H',"fire giant",(24,08),hostile
+MONSTER:'H',"fire giant",(24,09),hostile
+MONSTER:'H',"fire giant",(24,10),hostile
+MONSTER:'H',"fire giant",random,hostile
+MONSTER:'H',"fire giant",random,hostile
+MONSTER:'H',random,random,hostile
+
+#
+#      The "fill" levels for the quest.
+#
+#      These levels are used to fill out any levels not occupied by specific
+#      levels as defined above. "filla" is the upper filler, between the
+#      start and locate levels, and "fillb" the lower between the locate
+#      and goal levels.
+#
+
+MAZE: "Val-fila" , 'I'
+INIT_MAP: '.' , 'I' , true , true , lit, false
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+MONSTER: 'a', "fire ant", random
+MONSTER: 'a', "fire ant", random
+MONSTER: 'a', "fire ant", random
+MONSTER: 'a', "fire ant", random
+MONSTER: 'a', "fire ant", random
+MONSTER: 'a', random, random
+MONSTER: 'H', "fire giant", random, hostile
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+
+MAZE: "Val-filb" , 'L'
+INIT_MAP: '.' , 'L' , true , true , lit, false
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+MONSTER: 'a', "fire ant", random
+MONSTER: 'a', "fire ant", random
+MONSTER: 'a', "fire ant", random
+MONSTER: 'a', random, random
+MONSTER: 'H', "fire giant", random, hostile
+MONSTER: 'H', "fire giant", random, hostile
+MONSTER: 'H', "fire giant", random, hostile
+#
+TRAP: "fire", random
+TRAP: "fire", random
+TRAP: "fire", random
+TRAP: "fire", random
+TRAP: "fire", random
+TRAP: random, random
+TRAP: random, random
diff --git a/dat/Wizard.des b/dat/Wizard.des
new file mode 100644 (file)
index 0000000..14f99c9
--- /dev/null
@@ -0,0 +1,439 @@
+#      SCCS Id: @(#)Wizard.des 3.4     1992/07/11
+#      Copyright (c) 1992 by David Cohrs
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The "start" level for the quest.
+#
+#      Here you meet your (besieged) class leader, Neferet the Green
+#      and receive your quest assignment.
+#
+MAZE: "Wiz-strt",' '
+FLAGS: noteleport,hardfloor
+GEOMETRY:center,center
+MAP
+............................................................................
+.....................C....CC.C........................C.....................
+..........CCC.....................CCC.......................................
+........CC........-----------.......C.C...C...C....C........................
+.......C.....---------------------...C..C..C..C.............................
+......C..C...------....\....------....C.....C...............................
+........C...||....|.........|....||.........................................
+.......C....||....|.........+....||.........................................
+.......C...||---+--.........|....|||........................................
+......C....||...............|--S--||........................................
+...........||--+--|++----|---|..|.SS..........C......C......................
+........C..||.....|..|...|...|--|.||..CC..C.....C..........C................
+.......C...||.....|..|.--|.|.|....||.................C..C...................
+.....C......||....|..|.....|.|.--||..C..C..........C...........}}}..........
+......C.C...||....|..-----.|.....||...C.C.C..............C....}}}}}}........
+.........C...------........|------....C..C.....C..CC.C......}}}}}}}}}}}.....
+.........CC..---------------------...C.C..C.....CCCCC.C.......}}}}}}}}......
+.........C........-----------..........C.C.......CCC.........}}}}}}}}}......
+..........C.C.........................C............C...........}}}}}........
+......................CCC.C.................................................
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,19),lit,"ordinary"
+REGION:(35,00,49,03),unlit,"ordinary"
+REGION:(43,12,49,16),unlit,"ordinary"
+REGION:(19,11,33,15),unlit,"ordinary",unfilled,true
+REGION:(30,10,31,10),unlit,"ordinary"
+# Stairs
+STAIR:(30,10),down
+# Portal arrival point
+BRANCH:(63,06,63,06),(0,0,0,0)
+# Doors
+DOOR:closed,(31,09)
+DOOR:closed,(16,08)
+DOOR:closed,(28,07)
+DOOR:locked,(34,10)
+DOOR:locked,(35,10)
+DOOR:closed,(15,10)
+DOOR:locked,(19,10)
+DOOR:locked,(20,10)
+# Neferet the Green, the quest leader
+MONSTER:'@',"Neferet the Green",(23,05)
+# The treasure of the quest leader
+OBJECT:'(',"chest",(24,05)
+# apprentice guards for the audience chamber
+MONSTER:'@',"apprentice",(30,07)
+MONSTER:'@',"apprentice",(24,06)
+MONSTER:'@',"apprentice",(15,06)
+MONSTER:'@',"apprentice",(15,12)
+MONSTER:'@',"apprentice",(26,11)
+MONSTER:'@',"apprentice",(27,11)
+MONSTER:'@',"apprentice",(19,09)
+MONSTER:'@',"apprentice",(20,09)
+# Eels in the pond
+MONSTER:';',"giant eel",(62,14)
+MONSTER:';',"giant eel",(69,15)
+MONSTER:';',"giant eel",(67,17)
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Monsters on siege duty.
+MONSTER: 'B',random,(60,09),hostile
+MONSTER: 'W',random,(60,10),hostile
+MONSTER: 'B',random,(60,11),hostile
+MONSTER: 'B',random,(60,12),hostile
+MONSTER: 'i',random,(60,13),hostile
+MONSTER: 'B',random,(61,10),hostile
+MONSTER: 'B',random,(61,11),hostile
+MONSTER: 'B',random,(61,12),hostile
+MONSTER: 'B',random,(35,03),hostile
+MONSTER: 'i',random,(35,17),hostile
+MONSTER: 'B',random,(36,17),hostile
+MONSTER: 'B',random,(34,16),hostile
+MONSTER: 'i',random,(34,17),hostile
+MONSTER: 'W',random,(67,02),hostile
+MONSTER: 'B',random,(10,19),hostile
+
+#
+#      The "locate" level for the quest.
+#
+#      Here you have to find the Entrance to the Tower of Darkness to go
+#      further towards your assigned quest.
+#
+
+MAZE: "Wiz-loca",' '
+FLAGS: hardfloor
+GEOMETRY:center,center
+MAP
+.............        .......................................................
+..............       .............}}}}}}}.}}}}}}}}}}}}}}}}}}}.}}}}}}}.......
+..............      ..............}.................................}.......
+..............      ..............}.---------S---------------------.}.......
+...............     .........C....}.|.............................|.}.......
+...............    ..........C....}.|.---------------------------.|.}.......
+...............    .........CCC.....|.|.........................|.|.........
+................   ....C....CCC...}.|.|.---S-------------------.|.|.}.......
+.......C..C.....  .....C....CCC...}.|.|.|......+.......+......|.|.|.}.......
+.............C..CC.....C....CCC...}.|.|.|......|-------|......|.|.|.}.......
+................   ....C....CCC...}.|.|.|......|.......S......|.|.|.}.......
+......C..C.....    ....C....CCC...}.|.|.|......|-------|......|.|.|.}.......
+............C..     ...C....CCC...}.|.|.|......+.......+......|.|.|.}.......
+........C......    ....C....CCC...}.|.|.-----------------------.|.|.}.......
+....C......C...     ........CCC.....|.|.........................|.|.........
+......C..C....      .........C....}.|.--------------------S------.|.}.......
+..............      .........C....}.|.............................|.}.......
+.............       ..............}.-------------------------------.}.......
+.............        .............}.................................}.......
+.............        .............}}}}}}}.}}}}}}}}}}}}}}}}}}}.}}}}}}}.......
+.............        .......................................................
+ENDMAP
+# Dungeon Description
+REGION:(00,00,75,20),lit,"ordinary"
+REGION:(37,04,65,16),unlit,"ordinary"
+REGION:(41,08,46,12),lit,"ordinary"
+REGION:(56,08,61,12),lit,"ordinary"
+REGION:(48,08,54,08),unlit,"ordinary"
+REGION:(48,12,54,12),unlit,"ordinary"
+REGION:(48,10,54,10),unlit,"ordinary"
+
+# Doors
+DOOR:locked,(45,03)
+DOOR:locked,(43,07)
+DOOR:locked,(58,15)
+DOOR:locked,(55,10)
+DOOR:locked,(55,08)
+DOOR:locked,(55,12)
+DOOR:locked,(47,08)
+DOOR:locked,(47,12)
+# Stairs
+STAIR:(03,17),up
+STAIR:(48,10),down
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,20)
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:"spiked pit",(24,02)
+TRAP:"spiked pit",(07,10)
+TRAP:"spiked pit",(23,05)
+TRAP:"spiked pit",(26,19)
+TRAP:"spiked pit",(72,02)
+TRAP:"spiked pit",(72,12)
+TRAP:"falling rock",(45,16)
+TRAP:"falling rock",(65,13)
+TRAP:"falling rock",(55,06)
+TRAP:"falling rock",(39,11)
+TRAP:"falling rock",(57,09)
+TRAP:"magic",random
+TRAP:"statue",random
+TRAP:"statue",random
+TRAP:"polymorph",random
+TRAP:"anti magic",(53,10)
+TRAP:"sleep gas",random
+TRAP:"sleep gas",random
+TRAP:"dart",random
+TRAP:"dart",random
+TRAP:"dart",random
+# Random monsters.
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'i',random,random,hostile
+
+#
+#      The "goal" level for the quest.
+#
+#      Here you meet the Dark One, your nemesis monster.  You have to
+#      defeat the Dark One in combat to gain the artifact you have
+#      been assigned to retrieve.
+#
+
+MAZE: "Wiz-goal", ' '
+GEOMETRY:center,center
+MAP
+                                                                            
+                                                                            
+                                                                            
+                   -------------                 -------------              
+                   |...........|                 |...........|              
+            -------|...........-------------------...........|              
+            |......S...........|..|..|..|..|..|..|...........|              
+            |......|...........|..|..|..|..|..|..|...........|              
+            |......|...........-F+-F+-F+-F+-F+-F+-...........|              
+            --S----|...........S.................+...........|              
+            |......|...........-F+-F+-F+-F+-F+-F+-...........|              
+            |......|...........|..|..|..|..|..|..|...........|              
+            |......|...........|..|..|..|..|..|..|...........|              
+            -------|...........-------------------...........|              
+                   |...........|                 |...........|              
+                   -------------                 -------------              
+                                                                            
+                                                                            
+                                                                            
+                                                                            
+ENDMAP
+# Dungeon Description
+REGION:(13,10,18,12),unlit,"temple"
+REGION:(13,06,18,08),lit,"ordinary"
+REGION:(20,04,30,14),unlit,"ordinary"
+REGION:(32,06,33,07),unlit,"ordinary"
+REGION:(35,06,36,07),unlit,"ordinary"
+REGION:(38,06,39,07),unlit,"ordinary"
+REGION:(41,06,42,07),unlit,"ordinary"
+REGION:(44,06,45,07),unlit,"ordinary"
+REGION:(47,06,48,07),unlit,"ordinary"
+REGION:(32,09,48,09),unlit,"ordinary"
+REGION:(32,11,33,12),unlit,"ordinary"
+REGION:(35,11,36,12),unlit,"ordinary"
+REGION:(38,11,39,12),unlit,"ordinary"
+REGION:(41,11,42,12),unlit,"ordinary"
+REGION:(44,11,45,12),unlit,"ordinary"
+REGION:(47,11,48,12),unlit,"ordinary"
+REGION:(50,04,60,14),lit,"ordinary"
+# Doors
+DOOR:locked,(19,06)
+DOOR:locked,(14,09)
+DOOR:locked,(31,09)
+DOOR:locked,(33,08)
+DOOR:locked,(36,08)
+DOOR:locked,(39,08)
+DOOR:locked,(42,08)
+DOOR:locked,(45,08)
+DOOR:locked,(48,08)
+DOOR:locked,(33,10)
+DOOR:locked,(36,10)
+DOOR:locked,(39,10)
+DOOR:locked,(42,10)
+DOOR:locked,(45,10)
+DOOR:locked,(48,10)
+DOOR:locked,(49,09)
+# Stairs
+STAIR:(55,05),up
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# The altar.  This is not a shrine.
+ALTAR:(16,11),noncoaligned,altar
+# Objects
+OBJECT:'"',"amulet of ESP",(16,11),blessed,0,"The Eye of the Aethiopica"
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'@',"Dark One",(16,11)
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'B',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'i',random,random,hostile
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'i',random,random,hostile
+# Captive Monsters in the dungeon
+MONSTER:'@',"rogue",(35,06),peaceful,"Pug"
+MONSTER:'Y',"owlbear",(47,06),peaceful,asleep
+MONSTER:'@',"wizard",(32,11),peaceful,asleep,"Newt"
+MONSTER:'@',"Grey-elf",(44,11),peaceful
+MONSTER:'H',"hill giant",(47,11),peaceful,asleep
+MONSTER:'G',"gnomish wizard",(38,06),peaceful
+MONSTER:'@',"prisoner",(35,11),peaceful
+MONSTER:'@',"prisoner",(41,11),peaceful,asleep
+
+#
+#      The "fill" levels for the quest.
+#
+#      These levels are used to fill out any levels not occupied by specific
+#      levels as defined above. "filla" is the upper filler, between the
+#      start and locate levels, and "fillb" the lower between the locate
+#      and goal levels.
+#
+
+LEVEL: "Wiz-fila"
+#
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+OBJECT: random,random,random
+MONSTER: 'i', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random,random,random
+MONSTER: 'i', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+OBJECT: random,random,random
+MONSTER: 'B', "vampire bat", random
+MONSTER: 'B', "vampire bat", random
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'i', random, random, hostile
+MONSTER: 'B', "vampire bat", random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'i', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'B', "vampire bat", random
+
+RANDOM_CORRIDORS
+
+LEVEL: "Wiz-filb"
+#
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+OBJECT: random,random,random
+MONSTER: 'X', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random,random,random
+MONSTER: 'i', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+OBJECT: random,random,random
+MONSTER: 'X', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'i', random, random, hostile
+MONSTER: 'B', "vampire bat", random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'i', random, random, hostile
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: 'B', "vampire bat", random
+
+RANDOM_CORRIDORS
diff --git a/dat/bigroom.des b/dat/bigroom.des
new file mode 100644 (file)
index 0000000..142ca85
--- /dev/null
@@ -0,0 +1,436 @@
+#      SCCS Id: @(#)bigroom.des        3.4     1990/04/15
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1990 by M. Stephenson
+# NetHack may be freely redistributed.  See license for details.
+#
+# These are the bigroom levels:
+#
+
+MAZE:"bigrm-1",' '
+GEOMETRY:center,center
+MAP
+---------------------------------------------------------------------------
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+---------------------------------------------------------------------------
+ENDMAP
+# Dungeon Description
+REGION:(01,01,73,16),lit,"ordinary"
+# Stairs
+STAIR:random,up
+STAIR:random,down
+# Non diggable walls
+NON_DIGGABLE:(00,00,74,17)
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+
+#      Here, just play with the lighting...
+
+MAZE:"bigrm-2",' '
+GEOMETRY:center,center
+MAP
+---------------------------------------------------------------------------
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+---------------------------------------------------------------------------
+ENDMAP
+# Dungeon Description
+REGION:(01,01,23,06),lit,"ordinary"
+REGION:(01,07,23,10),unlit,"ordinary"
+REGION:(01,11,23,16),lit,"ordinary"
+REGION:(24,01,50,06),unlit,"ordinary"
+REGION:(24,07,50,10),lit,"ordinary"
+REGION:(24,11,50,16),unlit,"ordinary"
+REGION:(51,01,73,06),lit,"ordinary"
+REGION:(51,07,73,10),unlit,"ordinary"
+REGION:(51,11,73,16),lit,"ordinary"
+# Stairs
+STAIR:random,up
+STAIR:random,down
+# Non diggable walls
+NON_DIGGABLE:(00,00,74,17)
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+
+#      Now, let's get fancy...
+
+MAZE:"bigrm-3",' '
+GEOMETRY:center,center
+MAP
+---------------------------------------------------------------------------
+|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|..............---.......................................---..............|
+|...............|.........................................|...............|
+|.....|.|.|.|.|---|.|.|.|.|...................|.|.|.|.|.|---|.|.|.|.|.....|
+|.....|--------   --------|...................|----------   --------|.....|
+|.....|.|.|.|.|---|.|.|.|.|...................|.|.|.|.|.|---|.|.|.|.|.....|
+|...............|.........................................|...............|
+|..............---.......................................---..............|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.........................................................................|
+|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|
+---------------------------------------------------------------------------
+ENDMAP
+# Dungeon Description
+REGION:(01,01,73,16),lit,"ordinary"
+# Stairs
+STAIR:random,up
+STAIR:random,down
+# Non diggable walls
+NON_DIGGABLE:(00,00,74,17)
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:random,random,(01,01)
+MONSTER:random,random,(13,01)
+MONSTER:random,random,(25,01)
+MONSTER:random,random,(37,01)
+MONSTER:random,random,(49,01)
+MONSTER:random,random,(61,01)
+MONSTER:random,random,(73,01)
+MONSTER:random,random,(07,07)
+MONSTER:random,random,(13,07)
+MONSTER:random,random,(25,07)
+MONSTER:random,random,(37,07)
+MONSTER:random,random,(49,07)
+MONSTER:random,random,(61,07)
+MONSTER:random,random,(67,07)
+MONSTER:random,random,(07,09)
+MONSTER:random,random,(13,09)
+MONSTER:random,random,(25,09)
+MONSTER:random,random,(37,09)
+MONSTER:random,random,(49,09)
+MONSTER:random,random,(61,09)
+MONSTER:random,random,(67,09)
+MONSTER:random,random,(01,16)
+MONSTER:random,random,(13,16)
+MONSTER:random,random,(25,16)
+MONSTER:random,random,(37,16)
+MONSTER:random,random,(49,16)
+MONSTER:random,random,(61,16)
+MONSTER:random,random,(73,16)
+MAZE:"bigrm-4",' '
+GEOMETRY:center,center
+MAP
+-----------                                                     -----------
+|.........|                                                     |.........|
+|.........|-----------|                             |-----------|.........|
+|-|...................|----------|       |----------|...................|-|
+  -|.............................|-------|.............................|-  
+   -|.................................................................|-   
+    -|...............................................................|-    
+     -|.............................................................|-     
+      -|...........................................................|-      
+      -|...........................................................|-      
+     -|.............................................................|-     
+    -|...............................................................|-    
+   -|.................................................................|-   
+  -|.............................|-------|.............................|-  
+|-|...................|----------|       |----------|...................|-|
+|.........|-----------|                             |-----------|.........|
+|.........|                                                     |.........|
+-----------                                                     -----------
+ENDMAP
+# Dungeon Description
+REGION:(01,01,73,16),lit,"ordinary"
+# Stairs
+STAIR:random,up
+STAIR:random,down
+# Non diggable walls
+NON_DIGGABLE:(00,00,74,17)
+# Fountains
+FOUNTAIN:(05,02)
+FOUNTAIN:(05,15)
+FOUNTAIN:(69,02)
+FOUNTAIN:(69,15)
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+
+#      Try an oval room...
+
+MAZE:"bigrm-5",' '
+GEOMETRY:center,center
+MAP
+                            ------------------                            
+                    ---------................---------                    
+              -------................................-------              
+         ------............................................------         
+      ----......................................................----      
+    ---............................................................---    
+  ---................................................................---  
+---....................................................................---
+|........................................................................|
+|........................................................................|
+|........................................................................|
+---....................................................................---
+  ---................................................................---  
+    ---............................................................---    
+      ----......................................................----      
+         ------............................................------         
+              -------................................-------              
+                    ---------................---------                    
+                            ------------------                            
+ENDMAP
+# Dungeon Description
+REGION:(00,00,72,18),lit,"ordinary"
+# Stairs
+STAIR:random,up
+STAIR:random,down
+# Non diggable walls
+NON_DIGGABLE:(00,00,72,18)
+# Objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
diff --git a/dat/castle.des b/dat/castle.des
new file mode 100644 (file)
index 0000000..346eecc
--- /dev/null
@@ -0,0 +1,241 @@
+#      SCCS Id: @(#)castle.des 3.4     2002/05/02
+#      Copyright (c) 1989 by Jean-Christophe Collet
+# NetHack may be freely redistributed.  See license for details.
+#
+# This is the stronghold level :
+# there are several ways to enter it :
+#      - opening the drawbridge (wand of opening, knock spell, playing
+#        the appropriate tune)
+#
+#      - enter via the back entry (this suppose a ring of levitation, boots
+#        of water walking, etc.)
+#
+# Note : If you don't play the right tune, you get indications like in the
+#       MasterMind game...
+#
+# To motivate the player : there are 4 storerooms (armors, weapons, food and
+# gems) and a wand of wishing in one of the 4 towers...
+
+MAZE:"castle",random
+FLAGS: noteleport
+GEOMETRY:center,center
+MAP
+}}}}}}}}}.............................................}}}}}}}}}
+}-------}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}-------}
+}|.....|-----------------------------------------------|.....|}
+}|.....+...............................................+.....|}
+}-------------------------------+-----------------------------}
+}}}}}}|........|..........+...........|.......S.S.......|}}}}}}
+.....}|........|..........|...........|.......|.|.......|}.....
+.....}|........------------...........---------S---------}.....
+.....}|...{....+..........+.........\.S.................+......
+.....}|........------------...........---------S---------}.....
+.....}|........|..........|...........|.......|.|.......|}.....
+}}}}}}|........|..........+...........|.......S.S.......|}}}}}}
+}-------------------------------+-----------------------------}
+}|.....+...............................................+.....|}
+}|.....|-----------------------------------------------|.....|}
+}-------}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}-------}
+}}}}}}}}}.............................................}}}}}}}}}
+ENDMAP
+
+# Random registers initialisation
+RANDOM_OBJECTS:'[',')','*','%'
+RANDOM_PLACES:(04,02),(58,02),(04,14),(58,14)
+RANDOM_MONSTERS:'L','N','E','H','M','O','R','T','X','Z'
+
+TELEPORT_REGION:levregion(01,00,10,20),(1,1,61,15),down
+TELEPORT_REGION:levregion(69,00,79,20),(1,1,61,15),up
+STAIR:levregion(01,00,10,20),(0,0,62,16),up
+FOUNTAIN:(10,08)
+# Doors
+DOOR:closed,(07,03)
+DOOR:closed,(55,03)
+DOOR:locked,(32,04)
+DOOR:locked,(26,05)
+DOOR:locked,(46,05)
+DOOR:locked,(48,05)
+DOOR:locked,(47,07)
+DOOR:closed,(15,08)
+DOOR:closed,(26,08)
+DOOR:locked,(38,08)
+DOOR:locked,(56,08)
+DOOR:locked,(47,09)
+DOOR:locked,(26,11)
+DOOR:locked,(46,11)
+DOOR:locked,(48,11)
+DOOR:locked,(32,12)
+DOOR:closed,(07,13)
+DOOR:closed,(55,13)
+# The drawbridge
+DRAWBRIDGE:(05,08),east,closed
+# Storeroom number 1
+OBJECT:object[0],random,(39,05)
+OBJECT:object[0],random,(40,05)
+OBJECT:object[0],random,(41,05)
+OBJECT:object[0],random,(42,05)
+OBJECT:object[0],random,(43,05)
+OBJECT:object[0],random,(44,05)
+OBJECT:object[0],random,(45,05)
+OBJECT:object[0],random,(39,06)
+OBJECT:object[0],random,(40,06)
+OBJECT:object[0],random,(41,06)
+OBJECT:object[0],random,(42,06)
+OBJECT:object[0],random,(43,06)
+OBJECT:object[0],random,(44,06)
+OBJECT:object[0],random,(45,06)
+# Storeroom number 2
+OBJECT:object[1],random,(49,05)
+OBJECT:object[1],random,(50,05)
+OBJECT:object[1],random,(51,05)
+OBJECT:object[1],random,(52,05)
+OBJECT:object[1],random,(53,05)
+OBJECT:object[1],random,(54,05)
+OBJECT:object[1],random,(55,05)
+OBJECT:object[1],random,(49,06)
+OBJECT:object[1],random,(50,06)
+OBJECT:object[1],random,(51,06)
+OBJECT:object[1],random,(52,06)
+OBJECT:object[1],random,(53,06)
+OBJECT:object[1],random,(54,06)
+OBJECT:object[1],random,(55,06)
+# Storeroom number 3
+OBJECT:object[2],random,(39,10)
+OBJECT:object[2],random,(40,10)
+OBJECT:object[2],random,(41,10)
+OBJECT:object[2],random,(42,10)
+OBJECT:object[2],random,(43,10)
+OBJECT:object[2],random,(44,10)
+OBJECT:object[2],random,(45,10)
+OBJECT:object[2],random,(39,11)
+OBJECT:object[2],random,(40,11)
+OBJECT:object[2],random,(41,11)
+OBJECT:object[2],random,(42,11)
+OBJECT:object[2],random,(43,11)
+OBJECT:object[2],random,(44,11)
+OBJECT:object[2],random,(45,11)
+# Storeroom number 4
+OBJECT:object[3],random,(49,10)
+OBJECT:object[3],random,(50,10)
+OBJECT:object[3],random,(51,10)
+OBJECT:object[3],random,(52,10)
+OBJECT:object[3],random,(53,10)
+OBJECT:object[3],random,(54,10)
+OBJECT:object[3],random,(55,10)
+OBJECT:object[3],random,(49,11)
+OBJECT:object[3],random,(50,11)
+OBJECT:object[3],random,(51,11)
+OBJECT:object[3],random,(52,11)
+OBJECT:object[3],random,(53,11)
+OBJECT:object[3],random,(54,11)
+OBJECT:object[3],random,(55,11)
+# THE WAND OF WISHING in 1 of the 4 towers
+CONTAINER:'(',"chest",place[0]
+OBJECT:'/',"wishing",contained
+# Prevent monsters from eating it.  (@'s never eat objects)
+ENGRAVING:place[0],burn,"Elbereth"
+# The treasure of the lord
+OBJECT:'(',"chest",(37,08)
+# Traps
+TRAP:"trap door",(40,08)
+TRAP:"trap door",(44,08)
+TRAP:"trap door",(48,08)
+TRAP:"trap door",(52,08)
+TRAP:"trap door",(55,08)
+# Soldiers guarding the entry hall
+MONSTER:'@',"soldier",(08,06)
+MONSTER:'@',"soldier",(09,05)
+MONSTER:'@',"soldier",(11,05)
+MONSTER:'@',"soldier",(12,06)
+MONSTER:'@',"soldier",(08,10)
+MONSTER:'@',"soldier",(09,11)
+MONSTER:'@',"soldier",(11,11)
+MONSTER:'@',"soldier",(12,10)
+MONSTER:'@',"lieutenant",(09,08)
+# Soldiers guarding the towers
+MONSTER:'@',"soldier",(03,02)
+MONSTER:'@',"soldier",(05,02)
+MONSTER:'@',"soldier",(57,02)
+MONSTER:'@',"soldier",(59,02)
+MONSTER:'@',"soldier",(03,14)
+MONSTER:'@',"soldier",(05,14)
+MONSTER:'@',"soldier",(57,14)
+MONSTER:'@',"soldier",(59,14)
+# The four dragons that are guarding the storerooms
+MONSTER:'D',random,(47,05)
+MONSTER:'D',random,(47,06)
+MONSTER:'D',random,(47,10)
+MONSTER:'D',random,(47,11)
+# Sea monsters in the moat
+MONSTER:';',"giant eel",(05,07)
+MONSTER:';',"giant eel",(05,09)
+MONSTER:';',"giant eel",(57,07)
+MONSTER:';',"giant eel",(57,09)
+MONSTER:';',"shark",(05,00)
+MONSTER:';',"shark",(05,16)
+MONSTER:';',"shark",(57,00)
+MONSTER:';',"shark",(57,16)
+# The throne room and the court monsters
+MONSTER:monster[0],random,(27,05)
+MONSTER:monster[1],random,(30,05)
+MONSTER:monster[2],random,(33,05)
+MONSTER:monster[3],random,(36,05)
+MONSTER:monster[4],random,(28,06)
+MONSTER:monster[5],random,(31,06)
+MONSTER:monster[6],random,(34,06)
+MONSTER:monster[7],random,(37,06)
+MONSTER:monster[8],random,(27,07)
+MONSTER:monster[9],random,(30,07)
+MONSTER:monster[0],random,(33,07)
+MONSTER:monster[1],random,(36,07)
+MONSTER:monster[2],random,(28,08)
+MONSTER:monster[3],random,(31,08)
+MONSTER:monster[4],random,(34,08)
+MONSTER:monster[5],random,(27,09)
+MONSTER:monster[6],random,(30,09)
+MONSTER:monster[7],random,(33,09)
+MONSTER:monster[8],random,(36,09)
+MONSTER:monster[9],random,(28,10)
+MONSTER:monster[0],random,(31,10)
+MONSTER:monster[1],random,(34,10)
+MONSTER:monster[2],random,(37,10)
+MONSTER:monster[3],random,(27,11)
+MONSTER:monster[4],random,(30,11)
+MONSTER:monster[5],random,(33,11)
+MONSTER:monster[6],random,(36,11)
+# MazeWalks
+MAZEWALK:(00,10),west
+MAZEWALK:(62,06),east
+# Non diggable walls
+NON_DIGGABLE:(00,00,62,16)
+# Subrooms:
+#   Entire castle area
+REGION:(00,00,62,16),unlit,"ordinary"
+#   Courtyards
+REGION:(00,05,05,11),lit,"ordinary"
+REGION:(57,05,62,11),lit,"ordinary"
+#   Throne room
+REGION:(27,05,37,11),lit,"throne",unfilled
+#   Antechamber
+REGION:(07,05,14,11),lit,"ordinary"
+#   Storerooms
+REGION:(39,05,45,06),lit,"ordinary"
+REGION:(39,10,45,11),lit,"ordinary"
+REGION:(49,05,55,06),lit,"ordinary"
+REGION:(49,10,55,11),lit,"ordinary"
+#   Corners
+REGION:(02,02,06,03),lit,"ordinary"
+REGION:(56,02,60,03),lit,"ordinary"
+REGION:(02,13,06,14),lit,"ordinary"
+REGION:(56,13,60,14),lit,"ordinary"
+#   Barracks
+REGION:(16,05,25,06),lit,"barracks"
+REGION:(16,10,25,11),lit,"barracks"
+#   Hallways
+REGION:(08,03,54,03),unlit,"ordinary"
+REGION:(08,13,54,13),unlit,"ordinary"
+REGION:(16,08,25,08),unlit,"ordinary"
+REGION:(39,08,55,08),unlit,"ordinary"
+#   Storeroom alcoves
+REGION:(47,05,47,06),unlit,"ordinary"
+REGION:(47,10,47,11),unlit,"ordinary"
diff --git a/dat/cmdhelp b/dat/cmdhelp
new file mode 100644 (file)
index 0000000..af4b50e
--- /dev/null
@@ -0,0 +1,121 @@
+^       Show the type of a trap
+^[      Cancel command
+^A      Redo the previous command
+^C      Quit the game
+^D      Kick something (usually a door, chest, or box)
+^E      Search a room (available in debug mode only)
+^F      Map the level (available in debug mode only)
+^G      Create a monster (available in debug mode only)
+^I      Identify all items (available in debug mode only)
+^O      Show location of special levels (available in debug mode only)
+^P      Toggle through previously displayed game messages
+^R      Redraw screen
+^T      Teleport around level
+^V      Teleport between levels (available in debug mode only)
+^W      Wish (available in debug mode only)
+^X      Show your attributes (intrinsic ones included in debug or explore mode)
+^Z      Suspend game (only if defined)
+a       Apply (use) a tool
+A       Remove all armor
+b       Go southwest 1 space
+B       Go southwest until you are on top of something
+^B      Go southwest until you are near something
+c       Close a door
+C       Call (name) a particular monster
+d       Drop an item
+D       Drop specific item types
+e       Eat something
+E       Engrave writing on the floor
+f       Fire ammunition from quiver
+F       Followed by direction, fight a monster (even if you don't sense it)
+g       Followed by direction, move until you are near something
+G       Followed by direction, same as control-direction
+h       Go west 1 space (if number_pad is on, display help message)
+H       Go west until you are on top of something
+^H      Go west until you are near something
+i       Show your inventory
+I       Inventory specific item types
+j       Go south 1 space (or if number_pad is on, jump to another location)
+J       Go south until you are on top of something
+^J      Go south until you are near something
+k       Go north 1 space (or if number_pad is on, kick something)
+K       Go north until you are on top of something
+^K      Go north until you are near something
+l       Go east 1 space (or if number_pad is on, loot a box on the floor)
+L       Go east until you are on top of something
+^L      Go east until you are near something
+m       Followed by direction, move without picking anything up or fighting
+M       Followed by direction, move a distance without picking anything up
+n       Go southeast 1 space
+N       Go southeast until you are on something (if number_pad, name an object)
+^N      Go southeast until you are near something
+o       Open a door
+O       Show option settings, possibly change them
+p       Pay your shopping bill
+P       Put on an accessory (ring, amulet, etc)
+q       Quaff (drink) something (potion, water, etc)
+Q       Select ammunition for quiver
+r       Read a scroll or spellbook
+R       Remove an accessory (ring, amulet, etc)
+s       Search for traps and secret doors
+S       Save the game
+t       Throw something
+T       Take off one piece of armor
+u       Go northeast 1 space (or if number_pad is on, untrap something)
+U       Go northeast until you are on top of something
+^U      Go northeast until you are near something
+v       Show version
+V       Show long version and game history
+w       Wield (put in use) a weapon
+W       Wear a piece of armor
+x       Swap wielded and secondary weapons
+X       Enter explore (discovery) mode (only if defined)
+y       Go northwest 1 space
+Y       Go northwest until you are on top of something
+^Y      Go northwest until you are near something
+z       Zap a wand
+Z       Zap (cast) a spell
+<       Go up a staircase
+>       Go down a staircase
+/       Show what type of thing a symbol corresponds to
+?       Give a help message
+&       Tell what a command does
+!       Do a shell escape (only if defined)
+\       Show what object types have been discovered
+_       Travel via a shortest-path algorithm to a point on the map 
+.       Rest one move while doing nothing
+        Rest one move while doing nothing (if rest_on_space option is on)
+:       Look at what is on the floor
+;       Show what type of thing a map symbol on the level corresponds to
+,       Pick up things at the current location
+@       Toggle the pickup option on/off
+)       Show the weapon currently wielded
+[       Show the armor currently worn
+=       Show the ring(s) currently worn
+"       Show the amulet currently worn
+(       Show the tools currently in use
+*       Show all equipment in use (combination of the ),[,=,",( commands)
+$       Count your gold
++       List known spells
+#       Perform an extended command
+M-?     Display extended command help (if the platform allows this)
+M-2     Toggle two-weapon combat (unless number_pad is enabled)
+M-a     Adjust inventory letters
+M-c     Talk to someone
+M-d     Dip an object into something
+M-e     Advance or check weapons skills
+M-f     Force a lock
+M-i     Invoke an object's special powers
+M-j     Jump to another location
+M-l     Loot a box on the floor
+M-m     Use a monster's special ability
+M-n     Name an item or type of object
+M-o     Offer a sacrifice to the gods
+M-p     Pray to the gods for help
+M-q     Quit
+M-r     Rub a lamp
+M-s     Sit down
+M-t     Turn undead
+M-u     Untrap something (trap, door, or chest)
+M-v     Print compile time options for this version of NetHack
+M-w     Wipe off your face
diff --git a/dat/data.base b/dat/data.base
new file mode 100644 (file)
index 0000000..6fc8604
--- /dev/null
@@ -0,0 +1,4411 @@
+#      SCCS Id: @(#)data.base  3.4     2003/07/23
+#      Copyright (c) 1994, 1995, 1996 by the NetHack Development Team
+#      Copyright (c) 1994 by Boudewijn Wayers
+#      NetHack may be freely redistributed.  See license for details.
+#
+# This is the source file for the "data" file generated by `makedefs -d'.
+# A line starting with a # is a comment and is ignored by makedefs.
+# Any other line not starting with whitespace is a creature or an item.
+#
+# Each entry should be comprised of:
+# the thing/person being described on a line by itself, in lowercase;
+# on each succeeding line a <TAB> description.
+#
+# If the first character of a key field is "~", then anything which matches
+# the rest of that key will be treated as if it did not match any of the
+# following keys for that entry.  For instance, `~orc ??m*' preceding `orc*'
+# prevents "orc mummy" and "orc zombie" from matching.
+#
+abbot
+       For it had been long apparent to Count Landulf that nothing
+       could be done with his seventh son Thomas, except to make him
+       an Abbot or something of that kind.  Born in 1226, he had from
+       childhood a mysterious objection to becoming a predatory eagle,
+       or even to taking an ordinary interest in falconry or tilting
+       or any other gentlemanly pursuits.  He was a large and heavy and
+       quiet boy, and phenomenally silent, scarcely opening his mouth
+       except to say suddenly to his schoolmaster in an explosive
+       manner, "What is God?"  The answer is not recorded but it is
+       probable that the asker went on worrying out answers for himself.
+               [ The Runaway Abbot, by G. K. Chesterton ]
+aclys
+aklys
+       A short studded or spiked club attached to a cord allowing
+       it to be drawn back to the wielder after having been thrown.
+       It should not be confused with the atlatl, which is a device
+       used to throw spears for longer distances.
+aleax
+       Said to be a doppelganger sent to inflict divine punishment
+       for alignment violations.
+*altar
+       Altars are of three types:
+       1.  In Temples.  These are for Sacrifices [...].  The stone
+       top will have grooves for blood, and the whole will be covered
+       with _dry brown stains of a troubling kind_ from former
+       Sacrifices.
+       [ The Tough Guide to Fantasyland, by Diana Wynne Jones ]
+
+       To every man upon this earth
+       Death cometh soon or late;
+       And how can man die better
+       Than facing fearful odds
+       For the ashes of his fathers
+       And the temples of his gods?
+               [ Lays of Ancient Rome, by Thomas B. Macaulay ]
+amaterasu omikami
+       The Shinto sun goddess, Amaterasu Omikami is the central
+       figure of Shintoism and the ancestral deity of the imperial
+       house.  One of the daughters of the primordial god Izanagi
+       and said to be his favourite offspring, she was born from
+       his left eye.
+               [ Encyclopedia of Gods, by Michael Jordan ]
+amber*
+       "Tree sap," Wu explained, "often flows over insects and traps
+       them.  The insects are then perfectly preserved within the
+       fossil.  One finds all kinds of insects in amber - including
+       biting insects that have sucked blood from larger animals."
+               [ Jurassic Park, by Michael Crichton ]
+*amnesia
+maud
+       Get thee hence, nor come again,
+       Mix not memory with doubt,
+       Pass, thou deathlike type of pain,
+       Pass and cease to move about!
+       'Tis the blot upon the brain
+       That will show itself without.
+               ...
+       For, Maud, so tender and true,
+       As long as my life endures
+       I feel I shall owe you a debt,
+       That I never can hope to pay;
+       And if ever I should forget
+       That I owe this debt to you
+       And for your sweet sake to yours;
+       O then, what then shall I say? -
+       If ever I should forget,
+       May God make me more wretched
+       Than ever I have been yet!
+               [ Maud, And Other Poems by Alfred, Lord Tennyson ]
+~amulet of yendor
+*amulet
+amulet of *
+       "The complete Amulet can keep off all the things that make
+       people unhappy -- jealousy, bad temper, pride, disagreeableness,
+       greediness, selfishness, laziness.  Evil spirits, people called
+       them when the Amulet was made.  Don't you think it would be nice
+       to have it?"
+       "Very," said the children, quite without enthusiasm.
+       "And it can give you strength and courage."
+       "That's better," said Cyril.
+       "And virtue."
+       "I suppose it's nice to have that," said Jane, but not with much
+       interest.
+       "And it can give you your heart's desire."
+       "Now you're talking," said Robert.
+               [ The Story of the Amulet, by Edith Nesbit ]
+amulet of yendor
+       This mysterious talisman is the object of your quest.  It is
+       said to possess powers which mere mortals can scarcely
+       comprehend, let alone utilize.  The gods will grant the gift of
+       immortality to the adventurer who can deliver it from the
+       depths of Moloch's Sanctum and offer it on the appropriate high
+       altar on the Astral Plane.
+angel*
+       He answered and said unto them, he that soweth the good seed
+       is the Son of man; the field is the world, and the good seed
+       are the children of the kingdom; but the weeds are the
+       children of the wicked one; the enemy that sowed them is the
+       devil; the harvest is the end of the world; and the reapers
+       are the angels.  As therefore the weeds are gathered and
+       burned in the fire; so shall it be in the end of this world.
+       [...]  So shall it be at the end of the world; the angels
+       shall come forth, and sever the wicked from among the just,
+       and shall cast them into the furnace of fire; there shall be
+       wailing and gnashing of teeth.
+               [ The Gospel According to Matthew, 13:37-42, 49-50 ]
+anhur
+       An Egyptian god of war and a great hunter, few gods can match
+       his fury.  Unlike many gods of war, he is a force for good.
+       The wrath of Anhur is slow to come, but it is inescapable
+       once earned.  Anhur is a mighty figure with four arms.  He
+       is often seen with a powerful lance that requires both of
+       his right arms to wield and which is tipped with a fragment
+       of the sun.  He is married to Mehut, a lion-headed goddess.
+ankh-morpork
+       The twin city of Ankh-Morpork, foremost of all the cities
+       bounding the Circle Sea, was as a matter of course the home
+       of a large number of gangs, thieves' guilds, syndicates and
+       similar organisations.  This was one of the reasons for its
+       wealth.  Most of the humbler folk on the widdershin side of
+       the river, in Morpork's mazy alleys, supplemented their
+       meagre incomes by filling some small role for one or other
+       of the competing gangs.
+           [ The Colour of Magic by Terry Pratchett ]
+anshar
+       A primordial Babylonian-Akkadian deity, Anshar is mentioned
+       in the Babylonian creation epic _Enuma Elish_ as one of a
+       pair of offspring (with Kishar) of Lahmu and Lahamu.  Anshar
+       is linked with heaven while Kishar is identified with earth.
+           [ Encyclopedia of Gods, by Michael Jordan ]
+ant
+* ant
+       This giant variety of the ordinary ant will fight just as
+       fiercely as its small, distant cousin.  Various varieties
+       exist, and they are known and feared for their relentless
+       persecution of their victims.
+anu
+       Anu was the Babylonian god of the heavens, the monarch of
+       the north star.  He was the oldest of the Babylonian gods,
+       the father of all gods, and the ruler of heaven and destiny.
+       Anu features strongly in the _atiku_ festival in
+       Babylon, Uruk and other cities.
+ape
+* ape
+       The most highly evolved of all the primates, as shown by
+       all their anatomical characters and particularly the
+       development of the brain.  Both arboreal and terrestrial,
+       the apes have the forelimbs much better developed than
+       the hind limbs.  Tail entirely absent.  Growth is slow
+       and sexual maturity reached at quite an advanced age.
+       [ A Field Guide to the Larger Mammals of Africa by Dorst ]
+
+       Aldo the gorilla had a plan.  It was a good plan.  It was
+       right.  He knew it.  He smacked his lips in anticipation as
+       he thought of it.  Yes.  Apes should be strong.  Apes should
+       be masters.  Apes should be proud.  Apes should make the
+       Earth shake when they walked.  Apes should _rule_ the Earth.
+               [ Battle for the Planet of the Apes,
+                       by David Gerrold ]
+apple
+       NEWTONIAN, adj.  Pertaining to a philosophy of the universe
+       invented by Newton, who discovered that an apple will fall
+       to the ground, but was unable to say why.  His successors
+       and disciples have advanced so far as to be able to say
+       when.
+               [ The Devil's Dictionary, by Ambrose Bierce ]
+archeologist
+* archeologist
+       Archeology is the search for fact, not truth. [...] 
+       So forget any ideas you've got about lost cities, exotic travel, 
+       and digging up the world. We do not follow maps to buried 
+       treasure, and X never, ever, marks the spot.
+               [ Indiana Jones and the Last Crusade ]
+archon
+       Archons are the predominant inhabitants of the heavens.
+       However unusual their appearance, they are not generally
+       evil.  They are beings at peace with themselves and their
+       surroundings.
+arioch
+       Arioch, the patron demon of Elric's ancestors; one of the most
+       powerful of all the Dukes of Hell, who was called Knight of
+       the Swords, Lord of the Seven Darks, Lord of the Higher Hell
+       and many more names besides.
+               [ Elric of Melnibone, by Michael Moorcock ]
+*arrow
+       I shot an arrow into the air,
+       It fell to earth, I knew not where;
+       For, so swiftly it flew, the sight
+       Could not follow it in its flight.
+
+       I breathed a song into the air,
+       It fell to earth, I knew not where;
+       For who has sight so keen and strong
+       That it can follow the flight of song?
+
+       Long, long afterward, in an oak
+       I found the arrow still unbroke;
+       And the song, from beginning to end,
+       I found again in the heart of a friend.
+               [ The Arrow and the Song,
+                 by Henry Wadsworth Longfellow ]
+ashikaga takauji
+       Ashikaga Takauji was a daimyo of the Minamoto clan who
+       joined forces with the Go-Daigo to defeat the Hojo armies.
+       Later when Go-Daigo attempted to reduce the powers of the
+       samurai clans he rebelled against him.  He defeated Go-
+       Daigo and established the emperor Komyo on the throne.
+       Go-Daigo eventually escaped and established another
+       government in the town of Yoshino.  This period of dual
+       governments was known as the Nambokucho.
+       [ Samurai - The Story of a Warrior Tradition, by Cook ]
+asmodeus
+       It is said that Asmodeus is the overlord over all of hell.
+       His appearance, unlike many other demons and devils, is
+       human apart from his horns and tail.  He can freeze flesh
+       with a touch.
+athame
+       The consecrated ritual knife of a Wiccan initiate (one of
+       four basic tools, together with the wand, chalice and
+       pentacle).  Traditionally, the athame is a double-edged,
+       black-handled, cross-hilted dagger of between six and
+       eighteen inches length.
+athen*
+       Athene was the offspring of Zeus, and without a mother.  She
+       sprang forth from his head completely armed.  Her favourite
+       bird was the owl, and the plant sacred to her is the olive.
+           [ Bulfinch's Mythology by Thomas Bulfinch ]
+axolotl
+       A mundane salamander, harmless.
+bag
+bag of *
+sack
+       "Now, this third handkerchief," Mein Herr proceeded, "has also
+       four edges, which you can trace continuously round and round:
+       all you need do is to join its four edges to the four edges of
+       the opening.  The Purse is then complete, and its outer
+       surface--"
+       "I see!" Lady Muriel eagerly interrupted.  "Its outer surface
+       will be continuous with its inner surface!  But it will take
+       time. I'll sew it up after tea."  She laid aside the bag, and
+       resumed her cup of tea.  "But why do you call it Fortunatus's
+       Purse, Mein Herr?"
+       The dear old man beamed upon her, with a jolly smile, looking
+       more exactly like the Professor than ever.  "Don't you see,
+       my child--I should say Miladi?  Whatever is inside that Purse,
+       is outside it; and whatever is outside it, is inside it.  So
+       you have all the wealth of the world in that leetle Purse!"
+               [ Sylvie and Bruno Concluded, by Lewis Carroll ]
+b*lzebub
+       The "lord of the flies" is a translation of the Hebrew
+       Ba'alzevuv (Beelzebub in Greek).  It has been suggested that
+       it was a mistranslation of a mistransliterated word which
+       gave us this pungent and suggestive name of the Devil, a
+       devil whose name suggests that he is devoted to decay,
+       destruction, demoralization, hysteria and panic...
+               [ Notes on _Lord of the Flies_, by E. L. Epstein ]
+balrog
+       ...  It came to the edge of the fire and the light faded as
+       if a cloud had bent over it.  Then with a rush it leaped
+       the fissure.  The flames roared up to greet it, and wreathed
+       about it; and a black smoke swirled in the air.  Its streaming
+       mane kindled, and blazed behind it.  In its right hand
+       was a blade like a stabbing tongue of fire; in its left it
+       held a whip of many thongs.
+       'Ai, ai!' wailed Legolas.  'A Balrog!  A Balrog is come!'
+                  [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+baluchitherium
+titanothere
+       Extinct rhinos include a variety of forms, the most
+       spectacular being _Baluchitherium_ from the Oligocene of
+       Asia, which is the largest known land mammal.  Its body, 18
+       feet high at the shoulder and carried on massive limbs,
+       allowed the 4-foot-long head to browse on the higher branches
+       of trees.  Though not as enormous, the titanotheres of the
+       early Tertiary were also large perissodactyls, _Brontotherium_
+       of the Oligocene being 8 feet high at the shoulder.
+               [ Prehistoric Animals, by Barry Cox ]
+banana
+       He took another step and she cocked her right wrist in
+       viciously.  She heard the spring click.  Weight slapped into
+       her hand.
+       "Here!" she shrieked hysterically, and brought her arm up in
+       a hard sweep, meaning to gut him, leaving him to blunder
+       around the room with his intestines hanging out in steaming
+       loops.  Instead he roared laughter, hands on his hips,
+       flaming face cocked back, squeezing and contorting with great
+       good humor.
+       "Oh, my dear!" he cried, and went off into another gale of
+       laughter.
+       She looked stupidly down at her hand.  It held a firm yellow
+       banana with a blue and white Chiquita sticker on it.  She
+       dropped it, horrified, to the carpet, where it became a
+       sickly yellow grin, miming Flagg's own.
+       "You'll tell," he whispered.  "Oh yes indeed you will."
+       And Dayna knew he was right.
+               [ The Stand, by Stephen King ]
+barbarian
+* barbarian
+       They dressed alike -- in buckskin boots, leathern breeks and
+       deerskin shirts, with broad girdles that held axes and short
+       swords; and they were all gaunt and scarred and hard-eyed;
+       sinewy and taciturn.
+       They were wild men, of a sort, yet there was still a wide
+       gulf between them and the Cimmerian.  They were sons of
+       civilization, reverted to a semi-barbarism.  He was a
+       barbarian of a thousand generations of barbarians.  They had
+       acquired stealth and craft, but he had been born to these
+       things.  He excelled them even in lithe economy of motion.
+       They were wolves, but he was a tiger.
+               [ Conan - The Warrior, by Robert E. Howard ]
+barbed devil
+       Barbed devils lack any real special abilities, though they
+       are quite difficult to kill.
+*bat
+       A bat, flitting in the darkness outside, took the wrong turn
+       as it made its nightly rounds and came in through the window
+       which had been left healthfully open.  It then proceeded to
+       circle the room in the aimless fat-headed fashion habitual
+       with bats, who are notoriously among the less intellectually
+       gifted of God's creatures.  Show me a bat, says the old
+       proverb, and I will show you something that ought to be in
+       some kind of a home.
+               [ A Pelican at Blandings, by P. G. Wodehouse ]
+*bee
+       This giant variety of its useful normal cousin normally
+       appears in small groups, looking for raw material to produce
+       the royal jelly needed to feed their queen.  On rare
+       occasions, one may stumble upon a bee-hive, in which the
+       queen bee is being well provided for, and guarded against
+       intruders.
+*beetle
+       [ The Creator ] has an inordinate fondness for beetles.
+               [ attributed to biologist J.B.S. Haldane ]
+
+       The common name for the insects with wings shaped like
+       shields (_Coleoptera_), one of the ten sub-species into
+       which the insects are divided.  They are characterized by
+       the shields (the front pair of wings) under which the back
+       wings are folded.
+               [ Van Dale's Groot Woordenboek der Nederlandse Taal ]
+bell of opening
+       "A bell, book and candle job."
+       The Bursar sighed.  "We tried that, Archchancellor."
+       The Archchancellor leaned towards him.
+       "Eh?" he said.
+       "I _said_, we tried that Archchancellor," said the Bursar loudly,
+       directing his voice at the old man's ear.  "After dinner, you
+       remember?  We used Humptemper's _Names of the Ants_ and rang Old
+       Tom."*
+       "Did we, indeed.  Worked, did it?"
+       "_No_, Archchancellor."
+
+       * Old Tom was the single cracked bronze bell in the University
+       bell tower.
+               [ Eric, by Terry Pratchett ]
+blindfold
+       The blindfolding was performed by binding a piece of the
+       yellowish linen whereof those of the Amahagger who condescended
+       to wear anything in particular made their dresses tightly round
+       the eyes.  This linen I afterwards discovered was taken from the
+       tombs, and was not, as I had first supposed, of native
+       manufacture.  The bandage was then knotted at the back of the
+       head, and finally brought down again and the ends bound under
+       the chin to prevent its slipping.  Ustane was, by the way, also
+       blindfolded, I do not know why, unless it was from fear that she
+       should impart the secrets of the route to us.
+               [ She, by H. Rider Haggard ]
+blind io
+       On this particular day Blind Io, by dint of constant vigilance
+       the chief of the gods, sat with his chin on his hand
+       and looked at the gaming board on the red marble table in
+       front of him.  Blind Io had got his name because, where his
+       eye sockets should have been, there were nothing but two
+       areas of blank skin.  His eyes, of which he had an impressively
+       large number, led a semi-independent life of their
+       own.  Several were currently hovering above the table.
+           [ The Colour of Magic, by Terry Pratchett ]
+* blob
+gelatinous cube
+ooze
+* ooze
+*pudding
+* slime
+       These giant amoeboid creatures look like nothing more than
+       puddles of slime, but they both live and move, feeding on
+       metal or wood as well as the occasional dungeon explorer to
+       supplement their diet.
+
+       But we were not on a station platform.  We were on the track ahead
+       as the nightmare, plastic column of fetid black iridescence oozed
+       tightly onward through its fifteen-foot sinus, gathering unholy
+       speed and driving before it a spiral, re-thickening cloud of the
+       pallid abyss vapor.  It was a terrible, indescribable thing vaster
+       than any subway train -- a shapeless congeries of protoplasmic
+       bubbles, faintly self-luminous, and with myriads of temporary eyes
+       forming and unforming as pustules of greenish light all over the
+       tunnel-filling front that bore down upon us, crushing the frantic
+       penguins and slithering over the glistening floor that it and its
+       kind had swept so evilly free of all litter.
+               [ At the Mountains of Madness, by H.P. Lovecraft ]
+bone devil
+       Bone devils attack with weapons and with a great hooked tail
+       which causes a loss of strength to those they sting.
+book of the dead
+candelabrum*
+*candle
+       Faustus: Come on Mephistopheles.  What shall we do?
+       Mephistopheles: Nay, I know not.  We shall be cursed with bell,
+       book, and candle.
+       Faustus: How?  Bell, book, and candle, candle, book, and bell,
+       Forward and backward, to curse Faustus to hell.
+       Anon you shall hear a hog grunt, a calf bleat, and an ass bray,
+       Because it is Saint Peter's holy day.
+       (Enter all the Friars to sing the dirge)
+               [ Doctor Faustus and Other Plays, by Christopher Marlowe ]
+*boot*
+       In Fantasyland these are remarkable in that they seldom or
+       never wear out and are suitable for riding or walking in
+       without the need of Socks.  Boots never pinch, rub, or get
+       stones in them; nor do nails stick upwards into the feet from
+       the soles.  They are customarily mid-calf length or knee-high,
+       slip on and off easily and never smell of feet.  Unfortunately,
+       the formula for making this splendid footwear is a closely
+       guarded secret, possibly derived from nonhumans (see Dwarfs,
+       Elves, and Gnomes).
+       [ The Tough Guide to Fantasyland, by Diana Wynne Jones ]
+boulder
+       I worked the lever well under, and stretched my back; the end
+       of the stone rose up, and I kicked the fulcrum under.  Then,
+       when I was going to bear down, I remembered there was
+       something to get out from below; when I let go of the lever,
+       the stone would fall again.  I sat down to think, on the root
+       of the oak tree; and, seeing it stand about the ground, I saw
+       my way.  It was lucky I had brought a longer lever.  It would
+       just reach to wedge under the oak root.
+       Bearing it down so far would have been easy for a heavy man,
+       but was a hard fight for me.  But this time I meant to do it
+       if it killed me, because I knew it could be done.  Twice I
+       got it nearly there, and twice the weight bore it up again;
+       but when I flung myself on it the third time, I heard in my
+       ears the sea-sound of Poseidon.  Then I knew this time I
+       would do it; and so I did.
+               [ The King Must Die, by Mary Renault ]
+~*longbow of diana
+bow
+* bow
+       "Stand to it, my hearts of gold," said the old bowman as he
+       passed from knot to knot.  "By my hilt! we are in luck this
+       journey.  Bear in mind the old saying of the Company."
+       "What is that, Aylward?" cried several, leaning on their bows
+       and laughing at him.
+       "'Tis the master-bowyer's rede: 'Every bow well bent.  Every
+       shaft well sent.  Every stave well nocked.  Every string well
+       locked.'  There, with that jingle in his head, a bracer on
+       his left hand, a shooting glove on his right, and a
+       farthing's-worth of wax in his girdle, what more doth a
+       bowman need?"
+       "It would not be amiss," said Hordle John, "if under his
+       girdle he had four farthings'-worth of wine."
+               [ The White Company, by Sir Arthur Conan Doyle ]
+brigit
+       Brigit (Brigid, Bride, Banfile), which means the Exalted One,
+       was the Celtic (continental European and Irish) fertility
+       goddess.  She was originally celebrated on February first in
+       the festival of Imbolc, which coincided with the beginning
+       of lactation in ewes and was regarded in Scotland as the date
+       on which Brigit deposed the blue-faced hag of winter.  The
+       Christian calendar adopted the same date for the Feast of St.
+       Brigit.  There is no record that a Christian saint ever
+       actually existed, but in Irish mythology she became the
+       midwife to the Virgin Mary.
+               [ Encyclopedia of Gods, by Michael Jordan ]
+~stormbringer
+*broadsword
+       Bring me my broadsword
+       And clear understanding.
+       Bring me my cross of gold,
+       As a talisman.
+               [ "Broadsword" (refrain) by Ian Anderson ]
+bugbear
+       Bugbears are relatives of goblins, although they tend to be
+       larger and more hairy.  They are aggressive carnivores and
+       sometimes kill just for the treasure their victims may be
+       carrying.
+bugle
+       'I read you by your bugle horn
+       And by your palfrey good,
+       I read you for a Ranger sworn
+       To keep the King's green-wood.'
+       'A Ranger, Lady, winds his horn,
+       And 'tis at peep of light;
+       His blast is heard at merry morn,
+       And mine at dead of night.'
+               [ Brignall Banks, by Sir Walter Scott ]
+*camaxtli
+       A classical Mesoamerican Aztec god, also known as Mixcoatl-
+       Camaxtli (the Cloud Serpent), Camaxtli is the god of war.  He
+       is also a deity of hunting and fire who received human
+       sacrifice of captured prisoners.  According to tradition, the
+       sun god Tezcatlipoca transformed himself into Mixcoatl-Camaxtli
+       to make fire by twirling the sacred fire sticks.
+               [ Encyclopedia of Gods, by Michael Jordan ]
+candy bar
+       Only once a year, on his birthday, did Charlie Bucket ever
+       get to taste a bit of chocolate.  The whole family saved up
+       their money for that special occasion, and when the great
+       day arrived, Charlie was always presented with one small
+       chocolate bar to eat all by himself.  And each time he
+       received it, on those marvelous birthday mornings, he would
+       place it carefully in a small wooden box that he owned, and
+       treasure it as though it were a bar of solid gold; and for
+       the next few days, he would allow himself only to look at it,
+       but never to touch it.  Then at last, when he could stand it
+       no longer, he would peel back a tiny bit of the paper
+       wrapping at one corner to expose a tiny bit of chocolate, and
+       then he would take a tiny nibble - just enough to allow the
+       lovely sweet taste to spread out slowly over his tongue.  The
+       next day, he would take another tiny nibble, and so on, and
+       so on.  And in this way, Charlie would make his ten-cent bar
+       of birthday chocolate last him for more than a month.
+               [ Charlie and the Chocolate Factory, by Roald Dahl ]
+s*d*g*r* cat
+       Imagine a sealed container, so perfectly constructed that no
+       physical influence can pass either inwards or outwards across its
+       walls.  Imagine that inside the container is a cat, and also a
+       device that can be triggered by some quantum event.  If that event
+       takes place, then the device smashes a phial containing cyanide and
+       the cat is killed.  If the event does not take place, the cat lives
+       on.  In Schroedinger's original version, the quantum event was the
+       decay of a radioactive atom.  ...  To the outside observer, the cat
+       is indeed in a linear combination of being alive and dead, and only
+       when the container is finally opened would the cat's state vector
+       collapse into one or the other.  On the other hand, to a (suitably
+       protected) observer inside the container, the cat's state-vector
+       would have collapsed much earlier, and the outside observer's
+       linear combination has no relevance.
+               [ The Emperor's New Mind, by Roger Penrose ]
+*cat
+kitten
+       Well-known quadruped domestic animal from the family of
+       predatory felines (_Felis ochreata domestica_), with a thick,
+       soft pelt; often kept as a pet.  Various folklores have the
+       cat associated with magic and the gods of ancient Egypt.
+
+       So Ulthar went to sleep in vain anger; and when the people
+       awakened at dawn - behold!  Every cat was back at his
+       accustomed hearth!  Large and small, black, grey, striped,
+       yellow and white, none was missing.  Very sleek and fat did
+       the cats appear, and sonorous with purring content.
+               [ The Cats of Ulthar, by H.P. Lovecraft ]
+# this one doesn't work very well for dwarven and gnomish cavemen
+cave*man
+human cave*man
+       Now it was light enough to leave.  Moon-Watcher picked up
+       the shriveled corpse and dragged it after him as he bent
+       under the low overhang of the cave.  Once outside, he
+       threw the body over his shoulder and stood upright - the
+       only animal in all this world able to do so.
+       Among his kind, Moon-Watcher was almost a giant.  He was
+       nearly five feet high, and though badly undernourished
+       weighed over a hundred pounds.  His hairy, muscular body
+       was halfway between ape and man, but his head was already
+       much nearer to man than ape.  The forehead was low, and
+       there were ridges over the eye sockets, yet he unmistakably
+       held in his genes the promise of humanity.
+               [ 2001: A Space Odyssey, by Arthur C. Clarke ]
+*centaur
+       Of all the monsters put together by the Greek imagination
+       the Centaurs (Kentauroi) constituted a class in themselves.
+       Despite a strong streak of sensuality, in their make-up,
+       their normal behaviour was moral, and they took a kindly
+       thought of man's welfare.  The attempted outrage of Nessos on
+       Deianeira, and that of the whole tribe of Centaurs on the
+       Lapith women, are more than offset by the hospitality of
+       Pholos and by the wisdom of Cheiron, physician, prophet,
+       lyrist, and the instructor of Achilles.  Further, the
+       Centaurs were peculiar in that their nature, which united the
+       body of a horse with the trunk and head of a man, involved
+       an unthinkable duplication of vital organs and important
+       members.  So grotesque a combination seems almost un-Greek.
+       These strange creatures were said to live in the caves and
+       clefts of the mountains, myths associating them especially
+       with the hills of Thessaly and the range of Erymanthos.
+                    [ Mythology of all races, Vol. 1, pp. 270-271 ]
+centipede
+       I observed here, what I had often seen before, that certain
+       districts abound in centipedes.  Here they have light
+       reddish bodies and blue legs; great myriapedes are seen
+       crawling every where.  Although they do no harm, they excite
+       in man a feeling of loathing.  Perhaps our appearance
+       produces a similar feeling in the elephant and other large
+       animals.  Where they have been much disturbed, they
+       certainly look upon us with great distrust, as the horrid
+       biped that ruins their peace.
+               [ Travels and Researches in South Africa,
+                       by Dr. David Livingstone ]
+cerberus
+kerberos
+       Cerberus, (or Kerberos in Greek), was the three-headed dog
+       that guarded the Gates of Hell.  He allowed any dead to enter,
+       and likewise prevented them all from ever leaving.  He was
+       bested only twice:  once when Orpheus put him to sleep by
+       playing bewitching music on his lyre, and the other time when
+       Hercules confronted him and took him to the world of the
+       living (as his twelfth and last labor).
+chameleon
+       Name of a family (_Chameleonidae_) and race (_Chameleo_) of
+       scaly lizards, especially the _Chameleo vulgaris_ species,
+       with a short neck, claws, a grasping tail, a long, extendible
+       tongue and mutually independent moving eyes.  When it is
+       scared or angry, it inflates itself and its transparent skin
+       shows its blood:  the skin first appears greenish, then
+       gradually changes color until it is a spotted red.  The final
+       color depends on the background color as well, hence the
+       (figurative) implication of unreliability.  [Capitalized:]
+       a constellation of the southern hemisphere (Chameleo).
+           [ Van Dale's Groot Woordenboek der Nederlandse Taal ]
+charo*n
+       When an ancient Greek died, his soul went to the nether world:
+       the Hades.  To reach the nether world, the souls had to cross
+       the river Styx, the river that separated the living from the
+       dead.  The Styx could be crossed by ferry, whose shabby ferry-
+       man, advanced in age, was called Charon.  The deceased's next-
+       of-kin would place a coin under his tongue, to pay the ferry-
+       man.
+chest
+large box
+       Dantes rapidly cleared away the earth around the chest.  Soon
+       the center lock appeared, then the handles at each end, all
+       delicately wrought in the manner of that period when art made
+       precious even the basest of metals.  He took the chest by the
+       two handles and tried to lift it, but it was impossible.  He
+       tried to open it; it was locked.  He inserted the sharp end
+       of his pickaxe between the chest and the lid and pushed down
+       on the handle.  The lid creaked, then flew open.
+       Dantes was seized with a sort of giddy fever.  He cocked his
+       gun and placed it beside him.  The he closed his eyes like a
+       child, opened them and stood dumbfounded.
+       The chest was divided into three compartments.  In the first
+       were shining gold coins.  In the second, unpolished gold
+       ingots packed in orderly stacks.  From the third compartment,
+       which was half full, Dantes picked up handfuls of diamonds,
+       pearls and rubies.  As they fell through his fingers in a
+       glittering cascade, they gave forth the sound of hail beating
+       against the windowpanes.
+               [ The Count of Monte Cristo, by Alexandre Dumas ]
+chih*sung*tzu
+       A Chinese rain god.
+chromatic dragon
+tiamat
+       Tiamat is said to be the mother of evil dragonkind.  She is
+       extremely vain.
+~elven cloak
+~oilskin cloak
+*cloak*
+       Cloaks are the universal outer garb of everyone who is not a
+       Barbarian.  It is hard to see why.  They are open in front
+       and require you at most times to use one hand to hold them
+       shut.  On horseback they leave the shirt-sleeved arms and
+       most of the torso exposed to wind and Weather.  The OMTs
+       [ Official Management Terms ] for Cloaks well express their
+       difficulties.  They are constantly _swirling and dripping_
+       and becoming _heavy with water_ in rainy Weather, _entangling
+       with trees_ or _swords_, or needing to be _pulled close
+       around her/his shivering body_.  This seems to suggest they
+       are less than practical for anyone on an arduous Tour.
+       [ The Tough Guide to Fantasyland, by Diana Wynne Jones ]
+cloud*
+       I wandered lonely as a cloud
+       That floats on high o'er vales and hills,
+       When all at once I saw a crowd,
+       A host, of golden daffodils;
+       Beside the lake, beneath the trees,
+       Fluttering and dancing in the breeze.
+               [ I Wandered Lonely as a Cloud, by William Wordsworth ]
+cobra
+       Darzee and his wife only cowered down in the nest without
+       answering, for from the thick grass at the foot of the bush
+       there came a low hiss -- a horrid cold sound that made
+       Rikki-tikki jump back two clear feet.  Then inch by inch out of
+       the grass rose up the head and spread hood of Nag, the big
+       black cobra, and he was five feet long from tongue to tail.
+       When he had lifted one-third of himself clear of the ground,
+       he stayed balancing to and fro exactly as a dandelion-tuft
+       balances in the wind, and he looked at Rikki-tikki with the
+       wicked snake's eyes that never change their expression,
+       whatever the snake may be thinking of.
+       'Who is Nag?' said he.  '_I_ am Nag.  The great God Brahm put
+       his mark upon all our people, when the first cobra spread his
+       hood to keep the sun off Brahm as he slept.  Look, and be
+       afraid!'
+               [ Rikki-tikki-tavi, by Rudyard Kipling ]
+c*ckatrice
+       Once in a great while, when the positions of the stars are
+       just right, a seven-year-old rooster will lay an egg.  Then,
+       along will come a snake, to coil around the egg, or a toad,
+       to squat upon the egg, keeping it warm and helping it to
+       hatch.  When it hatches, out comes a creature called basilisk,
+       or cockatrice, the most deadly of all creatures.  A single
+       glance from its yellow, piercing toad's eyes will kill both
+       man and beast.  Its power of destruction is said to be so
+       great that sometimes simply to hear its hiss can prove fatal.
+       Its breath is so venomous that it causes all vegetation
+       to wither.
+
+       There is, however, one creature which can withstand the
+       basilisk's deadly gaze, and this is the weasel.  No one knows
+       why this is so, but although the fierce weasel can slay the
+       basilisk, it will itself be killed in the struggle.  Perhaps
+       the weasel knows the basilisk's fatal weakness:  if it ever
+       sees its own reflection in a mirror it will perish instantly.
+       But even a dead basilisk is dangerous, for it is said that
+       merely touching its lifeless body can cause a person to
+       sicken and die.
+       [ Mythical Beasts by Deirdre Headon (The Leprechaun Library)
+         and other sources ]
+cornuthaum
+       He was dressed in a flowing gown with fur tippets which had
+       the signs of the zodiac embroidered over it, with various
+       cabalistic signs, such as triangles with eyes in them, queer
+       crosses, leaves of trees, bones of birds and animals, and a
+       planetarium whose stars shone like bits of looking-glass with
+       the sun on them.  He had a pointed hat like a dunce's cap, or
+       like the headgear worn by ladies of that time, except that
+       the ladies were accustomed to have a bit of veil floating
+       from the top of it.
+                       [ The Once and Future King, by T.H. White ]
+
+               "A wizard!" Dooley exclaimed, astounded.
+               "At your service, sirs," said the wizard.  "How
+       perceptive of you to notice.  I suppose my hat rather gives me
+       away.  Something of a beacon, I don't doubt."  His hat was
+       pretty much that, tall and cone-shaped with stars and crescent
+       moons all over it.  All in all, it couldn't have been more
+       wizardish.
+                       [ The Elfin Ship, James P. Blaylock ]
+couatl
+       A mythical feathered serpent.  The couatl are very rare.
+coyote
+       This carnivore is known for its voracious appetite and
+       inflated view of its own intelligence.
+cram*
+       If you want to know what cram is, I can only say that I don't
+       know the recipe; but it is biscuitish, keeps good indefinitely,
+       is supposed to be sustaining, and is certainly not entertaining,
+       being in fact very uninteresting except as a chewing
+       exercise.  It was made by the Lake-men for long journeys.
+               [ The Hobbit, by J.R.R. Tolkien ]
+*crocodile
+       A big animal with the appearance of a lizard, constituting
+       an order of the reptiles (_Loricata_ or _Crocodylia_), the
+       crocodile is a large, dangerous predator native to tropical
+       and subtropical climes.  It spends most of its time in large
+       bodies of water.
+croesus
+kroisos
+creosote
+       Croesus (in Greek: Kroisos), the wealthy last king of Lydia;
+       his empire was destroyed when he attacked Cyrus in 549, after
+       the Oracle of Delphi (q.v.) had told him:  "if you attack the
+       Persians, you will destroy a mighty empire".  Herodotus
+       relates of his legendary conversation with Solon of Athens,
+       who impressed upon him that being rich does not imply being
+       happy and that no one should be considered fortunate before
+       his death.
+crom
+       Warily Conan scanned his surroundings, all of his senses alert
+       for signs of possible danger.  Off in the distance, he could
+       see the familiar shapes of the Camp of the Duali tribe.
+       Suddenly, the hairs on his neck stand on end as he detects the
+       aura of evil magic in the air.  Without thought, he readies
+       his weapon, and mutters under his breath:
+       "By Crom, there will be blood spilt today."
+
+       [ Conan the Avenger by Robert E. Howard, Bjorn Nyberg, and
+         L. Sprague de Camp ]
+crossbow*
+       "God save thee, ancient Mariner!
+       From the fiends, that plague thee thus! -
+       Why look'st thou so?" - With my cross-bow
+       I shot the Albatross.
+               [ The Rime of the Ancient Mariner, by Samuel Taylor
+                 Coleridge ]
+crystal ball
+       You look into one of these and see _vapours swirling like
+       clouds_.  These shortly clear away to show a sort of video
+       without sound of something that is going to happen to you
+       soon.  It is seldom good news.
+       [ The Tough Guide to Fantasyland, by Diana Wynne Jones ]
+curse*
+       Curses are longstanding ill-wishings which, in Fantasyland,
+       often manifest as semisentient.  They have to be broken or
+       dispelled.  The method varies according to the type and
+       origin of the Curse:
+       [...]
+       4.  Curses on Rings and Swords.  You have problems.  Rings
+       have to be returned whence they came, preferably at over a
+       thousand degrees Fahrenheit, and the Curse means you won't
+       want to do this.  Swords usually resist all attempts to
+       raise their Curses.  Your best source is to hide the Sword
+       or give it to someone you dislike.
+       [ The Tough Guide to Fantasyland, by Diana Wynne Jones ]
+cwn*n
+       A pack of snow-white, red-eared spectral hounds which
+       sometimes took part in the kidnappings and raids the
+       inhabitants of the underworld sometimes make on this world
+       (the Wild Hunt).  They are associated in Wales with the sounds
+       of migrating wild geese, and are said to be leading the souls
+       of the damned to hell.  The phantom chase is usually heard or
+       seen in midwinter and is accompanied by a howling wind.
+               [ Encyclopedia Mythica, ed. M.F. Lindemans ]
+cyclops
+       And after he had milked his cattle swiftly,
+       he again took hold of two of my men
+       and had them as his supper.
+       Then I went, with a tub of red wine,
+       to stand before the Cyclops, saying:
+       "A drop of wine after all this human meat,
+       so you can taste the delicious wine
+       that is stored in our ship, Cyclops."
+       He took the tub and emptied it.
+       He appreciated the priceless wine that much
+       that he promptly asked me for a second tub.
+       "Give it", he said, "and give me your name as well".
+                       ...
+       Thrice I filled the tub,
+       and after the wine had clouded his mind,
+       I said to him, in a tone as sweet as honey:
+       "You have asked my name, Cyclops?  Well,
+       my name is very well known.  I'll give it to you,
+       if you give me the gift you promised me as a guest.
+       My name is Nobody.  All call me thus:
+       my father and my mother and my friends."
+       Ruthlessly he answered to this:
+       "Nobody, I will eat you last of all;
+       your host of friends will completely precede you.
+       That will be my present to you, my friend."
+       And after these words he fell down backwards,
+       restrained by the all-restrainer Hupnos.
+       His monstrous neck slid into the dust;
+       the red wine squirted from his throat;
+       the drunk vomited lumps of human flesh.
+               [ The Odyssey, (chapter Epsilon), by Homer ]
+~sting
+*dagger
+       Is this a dagger which I see before me,
+       The handle toward my hand? Come, let me clutch thee.
+       I have thee not, and yet I see thee still.
+       Art thou not, fatal vision, sensible
+       To feeling as to sight? or art thou but
+       A dagger of the mind, a false creation,
+       Proceeding from the heat-oppressed brain?
+       I see thee yet, in form as palpable
+       As this which now I draw.
+                [ Macbeth, by William Shakespeare ]
+dark one
+       ... But he ruled rather by force and fear, if they might
+       avail; and those who perceived his shadow spreading over the
+       world called him the Dark Lord and named him the Enemy; and
+       he gathered again under his government all the evil things of
+       the days of Morgoth that remained on earth or beneath it,
+       and the Orcs were at his command and multiplied like flies.
+       Thus the Black Years began ...
+               [ The Silmarillion, by J.R.R. Tolkien ]
+demogorgon
+       Demogorgon, the prince of demons, wallows in filth and can
+       spread a quickly fatal illness to his victims while rending
+       them.  He is a mighty spellcaster, and he can drain the life
+       of mortals with a touch of his tail.
+demon
+       It is often very hard to discover what any given Demon looks
+       like, apart from a general impression of large size, huge
+       fangs, staring eyes, many limbs, and an odd color; but all
+       accounts agree that Demons are very powerful, very Magic (in
+       a nonhuman manner), and made of some substance that can squeeze
+       through a keyhole yet not be pierced with a Sword.  This makes
+       them difficult to deal with, even on the rare occasions when
+       they are friendly.
+       [ The Tough Guide to Fantasyland, by Diana Wynne Jones ]
+dingo
+       A wolflike wild dog, Canis dingo, of Australia, having a
+       reddish- or yellowish-brown coat, believed to have been
+       introduced by the aborigines.
+       [Webster's Encyclopedic Unabridged Dictionary of the English Language]
+disenchanter
+       Ask not, what your magic can do to it. Ask what it can do to your magic.
+dispater
+       Dispater is an arch-devil who rules the city of Dis.  He is
+       a powerful mage.
+djinn*
+       The djinn are genies from the elemental plane of Air.  There,
+       among their kind, they have their own societies.  They are
+       sometimes encountered on earth and may even be summoned here
+       to perform some service for powerful wizards.  The wizards
+       often leave them about for later service, safely tucked away
+       in a flask or lamp.  Once in a while, such a tool is found by
+       a lucky rogue, and some djinn are known to be so grateful
+       when released that they might grant their rescuer a wish.
+~hachi
+~slasher
+~sirius
+*dog
+pup*
+       A domestic animal, the _tame dog_ (_Canis familiaris_), of
+       which numerous breeds exist.  The male is called a dog,
+       while the female is called a bitch.  Because of its known
+       loyalty to man and gentleness with children, it is the
+       world's most popular domestic animal.  It can easily be
+       trained to perform various tasks.
+~trap*door
+*door
+doorway
+       Through me you pass into the city of woe:
+       Through me you pass into eternal pain:
+       Through me among the people lost for aye.
+       Justice the founder of my fabric mov'd:
+       To rear me was the task of power divine,
+       Supremest wisdom, and primeval love.
+       Before me things create were none, save things
+       Eternal, and eternal I endure.
+       All hope abandon ye who enter here.
+               [ The Inferno, from The Divine Comedy of Dante
+                       Alighieri, translated by H.F. Cary ]
+doppelganger
+       "Then we can only give thanks that this is Antarctica, where
+       there is not one, single, solitary, living thing for it to
+       imitate, except these animals in camp."
+
+       "Us," Blair giggled. "It can imitate us. Dogs can't make four
+       hundred miles to the sea; there's no food. There aren't any
+       skua gulls to imitate at this season. There aren't any
+       penguins this far inland. There's nothing that can reach the
+       sea from this point - except us. We've got brains. We can do
+       it. Don't you see - it's got to imitate us - it's got to be one
+       of us - that's the only way it can fly an airplane - fly a plane
+       for two hours, and rule - be - all Earth's inhabitants. A world
+       for the taking - if it imitates us!
+               [ Who Goes There?, by John W. Campbell ]
+
+       Xander: Let go!  I have to kill the demon bot!
+       Xander Double (grabbing the gun): Anya, get out of the way.
+       Buffy: Xander!
+       Xander Double: That's all right, Buffy.  I have him.
+       Xander: No, Buffy, I'm me.  Help me!
+       Anya: My gun, he's got my gun.
+       Riley: You own a gun?
+       Buffy: Xander, gun holding Xander, give it to me.
+       Anya: Buffy, which one's real?
+       Xander: I am.
+       Xander Double: No, _I_ am.
+           [ Buffy the Vampire Slayer, Episode 5.03, "The Replacement" ]
+*dragon
+*xoth
+       In the West the dragon was the natural enemy of man.  Although
+       preferring to live in bleak and desolate regions, whenever it
+       was seen among men it left in its wake a trail of destruction
+       and disease.  Yet any attempt to slay this beast was a perilous
+       undertaking.  For the dragon's assailant had to contend
+       not only with clouds of sulphurous fumes pouring from its fire
+       breathing nostrils, but also with the thrashings of its tail,
+       the most deadly part of its serpent-like body.
+       [ Mythical Beasts by Deirdre Headon (The Leprechaun Library) ]
+
+       "One whom the dragons will speak with," he said, "that is a
+       dragonlord, or at least that is the center of the matter.  It's
+       not a trick of mastering the dragons, as most people think.
+       Dragons have no masters.  The question is always the same, with
+       a dragon:  will he talk to you or will he eat you?  If you can
+       count upon his doing the former, and not doing the latter, why
+       then you're a dragonlord."
+               [ The Tombs of Atuan, by Ursula K. Le Guin ]
+*drum*
+       Many travelers have seen the drums of the great apes, and
+       some have heard the sounds of their beating and the noise of
+       the wild, weird revelry of these first lords of the jungle,
+       but Tarzan, Lord Greystoke, is, doubtless, the only human
+       being who ever joined in the fierce, mad, intoxicating revel
+       of the Dum-Dum.
+               [ Tarzan of the Apes, by Edgar Rice Burroughs ]
+~dwarf ??m*
+dwarf*
+dwar* cave*man
+       Dwarfs have faces like men (ugly men, with wrinkled, leathery
+       skins), but are generally either flat-footed, duck-footed, or
+       have feet pointing backwards.  They are of the earth, earthy,
+       living in the darkest of caverns and venturing forth only
+       with the cloaks by which they can make themselves invisible,
+       and others disguised as toads.  Miners often come across them,
+       and sometimes establish reasonably close relations with them.
+       ... The miners of Cornwall were always delighted to hear a
+       bucca busily mining away, for all dwarfs have an infallible
+       nose for precious metals.
+       Among other things, dwarfs are rightly valued for their skill
+       as blacksmiths and jewellers: they made Odin his famous spear
+       Gungnir, and Thor his hammer; for Freya they designed a
+       magnificent necklace, and for Frey a golden boar.  And in their
+       spare time they are excellent bakers.  Ironically, despite
+       their odd feet, they are particularly fond of dancing.  They
+       can also see into the future, and consequently are excellent
+       meteorologists.  They can be free with presents to people
+       they like, and a dwarvish gift is likely to turn to gold in
+       the hand.  But on the whole they are a snappish lot.
+           [ The Immortals, by Derek and Julia Parker ]
+earendil
+elwing
+       In after days, when because of the triumph of Morgoth Elves and
+       Men became estranged, as he most wished, those of the Elven-race
+       that lived still in Middle-earth waned and faded, and Men usurped
+       the sunlight.  Then the Quendi wandered in the lonely places of the
+       great lands and the isles, and took to the moonlight and the
+       starlight, and to the woods and the caves, becoming as shadows
+       and memories, save those who ever and anon set sail into the West
+       and vanished from Middle-earth.  But in the dawn of years Elves
+       and Men were allies and held themselves akin, and there were some
+       among Men that learned the wisdom of the Eldar, and became great
+       and valiant among the captains of the Noldor.  And in the glory
+       and beauty of the Elves, and in their fate, full share had the
+       offspring of elf and mortal, Earendil, and Elwing, and Elrond
+       their child.
+               [ The Silmarillion, by J.R.R. Tolkien ]
+eel
+giant eel
+       The behaviour of eels in fresh water extends the air of
+       mystery surrounding them.  They move freely into muddy, silty
+       bottoms of lakes, lying buried in the daylight hours in summer.
+       [...]  Eels are voracious carnivores, feeding mainly at
+       night and consuming a wide variety of fishes and invertebrate
+       creatures.  Contrary to earlier thinking, eels seek living
+       rather than dead creatures and are not habitual eaters of
+       carrion.
+           [ Freshwater Fishes of Canada, by Scott and Crossman ]
+egg
+       But I asked why not keep it and let the hen sit on it till it
+       hatched, and then we could see what would come out of it.
+       "Nothing good, I'm certain of that," Mom said.  "It would
+       probably be something horrible.  But just remember, if it's a
+       crocodile or a dragon or something like that, I won't have it
+       in my house for one minute."
+               [ The Enormous Egg, by Oliver Butterworth ]
+elbereth
+       ... Even as they stepped over the threshold a single clear
+       voice rose in song.
+
+               A Elbereth Gilthoniel,
+               silivren penna miriel
+               o menel aglar elenath!
+               Na-chaered palan-diriel
+               o galadhremmin ennorath,
+               Fanuilos, le linnathon
+               nef aear, si nef aearon!
+
+       Frodo halted for a moment, looking back.  Elrond was in his
+       chair and the fire was on his face like summer-light upon the
+       trees.  Near him sat the Lady Arwen.  [...]
+       He stood still enchanted, while the sweet syllables of the
+       elvish song fell like clear jewels of blended word and melody.
+       "It is a song to Elbereth," said Bilbo.  "They will sing that,
+       and other songs of the Blessed Realm, many times tonight.
+       Come on!"
+          [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+electric eel
+       South-American fish (_Gymnotus electricus_), living in fresh
+       water.  Shaped like a serpent, it can grow up to 2 metres.
+       This eel is known for its electrical organ which enables it
+       to paralyse creatures up to the size of a horse.
+          [ Van Dale's Groot Woordenboek der Nederlandse Taal ]
+*elemental
+       Elementals are manifestations of the basic nature of the
+       universe.  There are four known forms of elementals:  air, fire,
+       water, and earth.  Some mystics have postulated the necessity
+       for a fifth type, the spirit elemental, but none have ever
+       been encountered, at least on this plane of existence.
+~elf ??m*
+*elf*
+elvenking
+       The Elves sat round the fire upon the grass or upon the sawn
+       rings of old trunks.  Some went to and fro bearing cups and
+       pouring drinks; others brought food on heaped plates and
+       dishes.
+       "This is poor fare," they said to the hobbits; "for we are
+       lodging in the greenwood far from our halls.  If ever you are
+       our guests at home, we will treat you better."
+       "It seems to me good enough for a birthday-party," said Frodo.
+       Pippin afterwards recalled little of either food or drink, for
+       his mind was filled with the light upon the elf-faces, and the
+       sound of voices so various and so beautiful that he felt in a
+       waking dream.  [...]
+       Sam could never describe in words, nor picture clearly to
+       himself, what he felt or thought that night, though it remained
+       in his memory as one of the chief events of his life.  The
+       nearest he ever got was to say: "Well, sir, if I could grow
+       apples like that, I would call myself a gardener.  But it was
+       the singing that went to my heart, if you know what I mean."
+          [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+elven cloak
+       The Elves next unwrapped and gave to each of the Company the
+       clothes they had brought.  For each they had provided a hood
+       and cloak, made according to his size, of the light but warm
+       silken stuff that the Galadrim wove.  It was hard to say of
+       what colour they were: grey with the hue of twilight under
+       the trees they seemed to be; and yet if they were moved, or
+       set in another light, they were green as shadowed leaves, or
+       brown as fallow fields by night, dusk-silver as water under
+       the stars.
+               [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+emerald
+       'Put off that mask of burning gold
+       With emerald eyes.'
+       'O no, my dear, you make so bold
+       To find if hearts be wild and wise,
+       And yet not cold.'
+
+       'I would but find what's there to find,
+       Love or deceit.'
+       'It was the mask engaged your mind,
+       And after set your heart to beat,
+       Not what's behind.'
+
+       'But lest you are my enemy,
+       I must enquire.'
+       'O no, my dear, let all that be;
+       What matter, so there is but fire
+       In you, in me?'
+               [ The Mask, by W.B. Yeats ]
+erinys
+erinyes
+       These female-seeming devils named after the Furies of mythology
+       attack hand to hand and poison their unwary victims as well.
+ettin
+       The two-headed giant, or ettin, is a vicious and unpredictable
+       hunter that stalks by night and eats any meat it can catch.
+excalibur
+       At first only its tip was visible, but then it rose, straight,
+       proud, all that was noble and great and wondrous.  The tip of
+       the blade pointed toward the moon, as if it would cleave it
+       in two.  The blade itself gleamed like a beacon in the night.
+       There was no light source for the sword to be reflecting
+       from, for the moon had darted behind a cloud in fear.  The
+       sword was glowing from the intensity of its strength and
+       power and knowledge that it was justice incarnate, and that
+       after a slumber of uncounted years its time had again come.
+       After the blade broke the surface, the hilt was visible, and
+       holding the sword was a single strong, yet feminine hand,
+       wearing several rings that bore jewels sparkling with the
+       blue-green color of the ocean.
+               [ Knight Life, by Peter David ]
+expensive camera
+       There was a time when Rincewind had quite liked the iconoscope.
+       He believed, against all experience, that the world was
+       fundamentally understandable, and that if he could only equip
+       himself with the right mental toolbox he could take the back off
+       and see how it worked.  He was, of course, dead wrong.  The
+       iconoscope didn't take pictures by letting light fall onto
+       specially treated paper, as he had surmised, but by the far
+       simpler method of imprisoning a small demon with a good eye for
+       colour and a speedy hand with a paintbrush.  He had been very
+       upset to find that out.
+               [ The Light Fantastic, by Terry Pratchett ]
+eye of the aethiopica
+       This is a powerful amulet of ESP.  In addition to its standard
+       powers, it regenerates the energy of anyone who carries
+       it, allowing them to cast spells more often.  It also reduces
+       any spell damage to the person who carries it by half, and
+       protects from magic missiles.  Finally, when invoked it has
+       the power to instantly open a portal to any other area of the
+       dungeon, allowing its invoker to travel quickly between
+       areas.
+eyes of the overworld
+       ... and finally there is "the Eyes of the Overworld".  This
+       obscure artifact pushes the wearer's view sense into the
+       "overworld" -- another name for a segment of the Astral Plane.
+       Usually, there is nothing to be seen.  However, the wearer
+       is also able to look back and see the area around herself,
+       much like looking on a map.  Why anyone would want to ...
+figurine*
+       Then it appeared in Paris at just about the time that Paris
+       was full of Carlists who had to get out of Spain.  One of
+       them must have brought it with him, but, whoever he was, it's
+       likely he knew nothing about its real value.  It had been --
+       no doubt as a precaution during the Carlist trouble in Spain
+       -- painted or enameled over to look like nothing more than a
+       fairly interesting black statuette.  And in that disguise,
+       sir, it was, you might say, kicked around Paris for seventy
+       years by private owners and dealers too stupid to see what
+       it was under the skin.
+               [ The Maltese Falcon, by Dashiell Hammett ]
+floating eye
+       Floating eyes, not surprisingly, are large, floating eyeballs
+       which drift about the dungeon.  Though not dangerous in and
+       of themselves, their power to paralyse those who gaze at
+       their large eye in combat is widely feared.  Many are the
+       tales of those who struck a floating eye, were paralysed by
+       its mystic powers, and then nibbled to death by some other
+       creature that lurked around nearby.
+flesh golem
+       With an anxiety that almost amounted to agony, I collected
+       the instruments of life around me, that I might infuse a spark
+       of being into the lifeless thing that lay at my feet.  It was
+       already one in the morning; the rain pattered dismally against
+       the panes, and my candle was nearly burnt out, when, by the
+       glimmer of the half-extinguished light, I saw the dull yellow
+       eye of the creature open; it breathed hard, and a convulsive
+       motion agitated its limbs.
+
+       How can I describe my emotions at this catastrophe, or how
+       delineate the wretch whom with such infinite pains and care I
+       had endeavoured to form?  His limbs were in proportion, and I
+       had selected his features as beautiful.  Beautiful!--Great God!
+       His yellow skin scarcely covered the work of muscles and
+       arteries beneath; his hair was of a lustrous black, and
+       flowing; his teeth of a pearly whiteness; but these luxuriances
+       only formed a more horrid contrast with his watery eyes, that
+       seemed almost of the same colour as the dun white sockets in
+       which they were set, his shrivelled complexion and straight
+       black lips.
+               [ Frankenstein, by Mary Wollstonecraft Shelley ]
+*flute
+       With this thou canst do mighty deeds
+       And change men's passions for thy needs:
+       A man's despair with joy allay,
+       Turn bachelors old to lovers gay.
+               [ The Magic Flute, by Wolfgang Amadeus Mozart ]
+fog cloud
+       The fog comes
+       on little cat feet.
+
+       It sits looking
+       over harbor and city
+       on silent haunches
+       and then moves on.
+            [ Fog, by Carl Sandburg ]
+fountain
+       Rest! This little Fountain runs
+       Thus for aye: -- It never stays
+       For the look of summer suns,
+       Nor the cold of winter days.
+       Whose'er shall wander near,
+       When the Syrian heat is worst,
+       Let him hither come, nor fear
+       Lest he may not slake his thirst:
+       He will find this little river
+       Running still, as bright as ever.
+       Let him drink, and onward hie,
+       Bearing but in thought, that I,
+       Erotas, bade the Naiad fall,
+       And thank the great god Pan for all!
+               [ For a Fountain, by Bryan Waller Procter ]
+fox
+       One hot summer's day a Fox was strolling through an orchard
+       till he came to a bunch of Grapes just ripening on a vine
+       which had been trained over a lofty branch. "Just the thing
+       to quench my thirst," quoth he. Drawing back a few paces, he
+       took a run and a jump, and just missed the bunch. Turning
+       round again with a One, Two, Three, he jumped up, but with
+       no greater success. Again and again he tried after the
+       tempting morsel, but at last had to give it up, and walked
+       away with his nose in the air, saying: "I am sure they are
+       sour."
+               [ Aesop's Fables ]
+*fung*
+       Fungi, division of simple plants that lack chlorophyll, true
+       stems, roots, and leaves.  Unlike algae, fungi cannot
+       photosynthesize, and live as parasites or saprophytes.  The
+       division comprises the slime molds and true fungi.  True
+       fungi are multicellular (with the exception of yeasts); the
+       body of most true fungi consists of slender cottony
+       filaments, or hyphae.  All fungi are capable of asexual
+       reproduction by cell division, budding, fragmentation, or
+       spores.  Those that reproduce sexually alternate a sexual
+       generation (gametophyte) with a spore-producing one.  The
+       four classes of true fungi are the algaelike fungi (e.g.,
+       black bread mold and downy mildew), sac fungi (e.g., yeasts,
+       powdery mildews, truffles, and blue and green molds such as
+       Penicillium), basidium fungi (e.g., mushrooms and puffballs)
+       and imperfect fungi (e.g., species that cause athlete's foot
+       and ringworm).  Fungi help decompose organic matter (important
+       in soil renewal); are valuable as a source of antibiotics,
+       vitamins, and various chemicals; and for their role in
+       fermentation, e.g., in bread and alcoholic beverage
+       production.
+               [ The Concise Columbia Encyclopedia ]
+*gargoyle
+       And so it came to pass that while Man ruled on Earth, the
+       gargoyles waited, lurking, hidden from the light.  Reborn
+       every 600 years in Man's reckoning of time, the gargoyles
+       joined battle against Man to gain dominion over the Earth.
+
+       In each coming, the gargoyles were nearly destroyed by Men
+       who flourished in greater numbers.  Now it has been so many
+       hundreds of years that it seems the ancient statues and
+       paintings of gargoyles are just products of Man's
+       imagination.  In this year, with Man's thoughts turned toward
+       the many ills he has brought among himself, Man has forgotten
+       his most ancient adversary, the gargoyles.
+       [ Excerpt from the opening narration to the movie
+               _Gargoyles_, written by Stephen and Elinor Karpf ]
+*garlic
+       1 November - All day long we have travelled, and at a good
+       speed.  The horses seem to know that they are being kindly
+       treated, for they go willingly their full stage at best
+       speed.  We have now had so many changes and find the same
+       thing so constantly that we are encouraged to think that the
+       journey will be an easy one.  Dr. Van Helsing is laconic, he
+       tells the farmers that he is hurrying to Bistritz, and pays
+       them well to make the exchange of horses.  We get hot soup,
+       or coffee, or tea, and off we go.  It is a lovely country.
+       Full of beauties of all imaginable kinds, and the people are
+       brave, and strong, and simple, and seem full of nice
+       qualities.  They are very, very superstitious.  In the first
+       house where we stopped, when the woman who served us saw the
+       scar on my forehead, she crossed herself and put out two
+       fingers towards me, to keep off the evil eye.  I believe they
+       went to the trouble of putting an extra amount of garlic into
+       our food, and I can't abide garlic.  Ever since then I have
+       taken care not to take off my hat or veil, and so have
+       escaped their suspicions.
+               [ Dracula, by Bram Stoker ]
+# gas spore -- see *spore
+geryon
+       Geryon is an arch-devil sometimes called the Wild Beast,
+       attacking with his claws and poison sting.  His ranking in
+       Hell is rumored to be quite low.
+*ghost
+       And now the souls of the dead who had gone below came swarming
+       up from Erebus -- fresh brides, unmarried youths, old men
+       with life's long suffering behind them, tender young girls
+       still nursing this first anguish in their hearts, and a great
+       throng of warriors killed in battle, their spear-wounds gaping
+       yet and all their armour stained with blood.  From this
+       multitude of souls, as they fluttered to and fro by the
+       trench, there came a moaning that was horrible to hear.
+       Panic drained the blood from my cheeks.
+            [ The Odyssey, (chapter Lambda), by Homer ]
+ghoul
+       The forces of the gloom know each other, and are strangely
+       balanced by each other.  Teeth and claws fear what they cannot
+       grasp.  Blood-drinking bestiality, voracious appetites, hunger
+       in search of prey, the armed instincts of nails and jaws which
+       have for source and aim the belly, glare and smell out
+       uneasily the impassive spectral forms straying beneath a
+       shroud, erect in its vague and shuddering robe, and which seem
+       to them to live with a dead and terrible life.  These
+       brutalities, which are only matter, entertain a confused fear
+       of having to deal with the immense obscurity condensed into an
+       unknown being.  A black figure barring the way stops the wild
+       beast short.  That which emerges from the cemetery intimidates
+       and disconcerts that which emerges from the cave; the
+       ferocious fear the sinister; wolves recoil when they encounter
+       a ghoul.
+               [ Les Miserables, by Victor Hugo ]
+*giant
+giant humanoid
+       Giants have always walked the earth, though they are rare in
+       these times.  They range in size from little over nine feet
+       to a towering twenty feet or more.  The larger ones use huge
+       boulders as weapons, hurling them over large distances.  All
+       types of giants share a love for men - roasted, boiled, or
+       fried.  Their table manners are legendary.
+# note: "gnomish wizard" is a monster; cave*man entry doesn't fit nonhumans
+~gnome ??m*
+gnome*
+gnomish wizard
+gnom* cave*man
+       ...  And then a gnome came by, carrying a bundle, an old
+       fellow three times as large as an imp and wearing clothes of
+       a sort, especially a hat.  And he was clearly just as frightened
+       as the imps though he could not go so fast.  Ramon Alonzo
+       saw that there must be some great trouble that was vexing
+       magical things; and, since gnomes speak the language of men, and
+       will answer if spoken to gently, he raised his hat, and asked
+       of the gnome his name.  The gnome did not stop his hasty
+       shuffle a moment as he answered 'Alaraba' and grabbed the rim
+       of his hat but forgot to doff it.
+       'What is the trouble, Alaraba?'  said Ramon Alonzo.
+       'White magic.  Run!'  said the gnome ..
+               [ The Charwoman's Shadow, by Lord Dunsany ]
+
+       "Muggles have garden gnomes, too, you know," Harry told Ron as
+       they crossed the lawn.
+       "Yeah, I've seen those things they think are gnomes," said Ron,
+       bent double with his head in a peony bush, "like fat little
+       Santa Clauses with fishing rods..."
+       There was a violent scuffling noise, the peony bush shuddered,
+       and Ron straightened up.  "This is a gnome," he said grimly.
+       "Geroff me! Gerroff me!" squealed the gnome.
+       It was certainly nothing like Santa Claus.  It was small and
+       leathery looking, with a large, knobby, bald head exactly like
+       a potato.  Ron held it at arm's length as it kicked out at him
+       with its horny little feet; he grasped it around the ankles
+       and turned it upside down.
+         [ Harry Potter and the Chamber of Secrets, by J. K. Rowling ]
+goblin
+       Now goblins are cruel, wicked, and bad-hearted.  They make
+       no beautiful things, but they make many clever ones.  They
+       can tunnel and mine as well as any but the most skilled
+       dwarves, when they take the trouble, though they are usually
+       untidy and dirty.  Hammers, axes, swords, daggers, pickaxes,
+       tongs, and also instruments of torture, they make very well,
+       or get other people to make to their design, prisoners and
+       slaves that have to work till they die for want of air and
+       light.
+            [ The Hobbit, by J.R.R. Tolkien ]
+god
+goddess
+       Goddesses and Gods operate in ones, threesomes, or whole
+       pantheons of nine or more (see Religion).  Most of them claim
+       to have made the world, and this is indeed a likely claim in
+       the case of threesomes or pantheons:  Fantasyland does have
+       the air of having been made by a committee.  But all Goddesses
+       and Gods, whether they say they made the world or not, have
+       very detailed short-term plans for it which they are determined
+       to carry out.  Consequently they tend to push people into the
+       required actions by the use of coincidence or Prophecy, or just
+       by narrowing down your available choices of what to do next:
+       if a deity is pushing you, things will go miserably badly until
+       there is only one choice left to you.
+       [ The Tough Guide to Fantasyland, by Diana Wynne Jones ]
+gold
+gold piece
+zorkmid
+       A metal of characteristic yellow colour, the most precious
+       metal used as a common commercial medium of exchange.  Symbol,
+       Au; at. no. 79; at. wt. 197.2.  It is the most malleable
+       and ductile of all metals, and very heavy (sp. gr., 19.3).
+       It is quite unalterable by heat, moisture, and most
+       corrosive agents, and therefore well suited for its use in
+       coin and jewelry.
+            [ Webster's New International Dictionary
+                 of the English Language, Second Edition ]
+gold golem
+       The bellows he set away from the fire, and gathered all the tools
+       wherewith he wrought into a silver chest; and with a sponge wiped
+       he his face and his two hands withal, and his mighty neck and
+       shaggy breast, and put upon him a tunic, and grasped a stout staff,
+       and went forth halting; but there moved swiftly to support their
+       lord handmaidens wrought of gold in the semblance of living maids.
+       In them is understanding in their hearts, and in them speech and
+       strength, and they know cunning handiwork by gift of the immortal
+       gods.
+               [ The Iliad, by Homer ]
+~gold golem
+~flesh golem
+*golem
+       "The original story harks back, so they say, to the sixteenth
+       century.  Using long-lost formulas from the Kabbala, a rabbi is
+       said to have made an artificial man -- the so-called Golem -- to
+       help ring the bells in the Synagogue and for all kinds of other
+       menial work.
+       "But he hadn't made a full man, and it was animated by some sort
+       of vegetable half-life.  What life it had, too, so the story
+       runs, was only derived from the magic charm placed behind its
+       teeth each day, that drew down to itself what was known as the
+       `free sidereal strength of the universe.'
+       "One evening, before evening prayers, the rabbi forgot to take
+       the charm out of the Golem's mouth, and it fell into a frenzy.
+       It raged through the dark streets, smashing everything in its
+       path, until the rabbi caught up with it, removed the charm, and
+       destroyed it.  Then the Golem collapsed, lifeless.  All that was
+       left of it was a small clay image, which you can still see in
+       the Old Synagogue." ...
+           [ The Golem, by Gustav Meyrink ]
+grave
+       "Who'd care to dig 'em," said the old, old man,
+       "Those six feet marked in chalk?
+       Much I talk, more I walk;
+       Time I were buried," said the old, old man.
+               [ Three Songs to the Same Tune, by W.B. Yeats ]
+grayswandir
+       Why had I been wearing Grayswandir?  Would another weapon have
+       affected a Logrus-ghost as strongly?  Had it really been my
+       father, then, who had brought me here?  And had he felt I might
+       need the extra edge his weapon could provide?  I wanted to
+       think so, to believe that he had been more than a Pattern-ghost.
+               [ Knight of Shadows, by Roger Zelazny ]
+*grease
+       ANOINT, v.t.  To grease a king or other great functionary
+       already sufficiently slippery.
+               [ The Devil's Dictionary, by Ambrose Bierce ]
+gremlin
+       The gremlin is a highly intelligent and completely evil
+       creature.  It lives to torment other creatures and will go
+       to great lengths to inflict pain or cause injury.
+
+       Suddenly, Wilson thought about war, about the newspaper
+       stories which recounted the alleged existence of creatures in
+       the sky who plagued the Allied pilots in their duties.  They
+       called them gremlins, he remembered.  Were there, actually,
+       such beings?  Did they, truly, exist up here, never falling,
+       riding on the wind, apparently of bulk and weight, yet
+       impervious to gravity?
+       He was thinking that when the man appeared again.
+               [ Nightmare at 20,000 Feet, by Richard Matheson ]
+grid bug
+       These electronically based creatures are not native to this
+       universe.  They appear to come from a world whose laws of
+       motion are radically different from ours.
+
+       Tron looked to his mate and pilot.  "I'm going to check on
+       the beam connection, Yori.  You two can keep a watch out for
+       grid bugs."  Tron paced forward along the slender catwalk
+       that still seemed awfully insubstantial to Flynn, though he
+       knew it to be amazingly sturdy.  He gazed after Tron, asking
+       himself what in the world a grid bug was, and hoping that the
+       beam connection -- to which he'd given no thought whatsoever
+       until this moment -- was healthy and sound."
+           [ Tron, novel by Brian Daley, story by Steven Lisberger ]
+gunyoki
+       The samurai's last meal before battle.  It was usually made
+       up of cooked chestnuts, dried seaweed, and sake.
+hachi
+       Hachi was a dog that went with his master, a professor, to
+       the Shibuya train station every morning.  In the afternoon,
+       when his master was to return from work Hachi would be there
+       waiting.  One day his master died at the office, and did not
+       return.  For over ten years Hachi returned to the station
+       every afternoon to wait for his master.  When Hachi died a
+       statue was erected on the station platform in his honor.  It
+       is said to bring you luck if you touch his statue.
+*harp
+       A triangular stringed instrument, often Magic.  Even when not
+       Magic, a Harp is surprisingly portable and tough and can be
+       carried everywhere on the back of the Bard or Harper in all
+       weathers.  A Harp seldom goes out of tune and never warps.
+       Its strings break only in very rare instances, usually
+       because the Harper is sulking or crossed in love.  This is
+       just as well as no one seems to make or sell spare strings.
+       [ The Tough Guide to Fantasyland, by Diana Wynne Jones ]
+
+       After breakfast was over, the ogre called out: "Wife, wife,
+       bring me my golden harp."  So she brought it and put it on
+       the table before him.  Then he said: "Sing!" and the golden
+       harp sang most beautifully.  And it went on singing till the
+       ogre fell asleep, and commenced to snore like thunder.
+       Then Jack lifted up the copper-lid very quietly and got down
+       like a mouse and crept on hands and knees till he came to the
+       table, when up he crawled, caught hold of the golden harp and
+       dashed with it towards the door.  But the harp called out
+       quite loud: "Master!  Master!" and the ogre woke up just in
+       time to see Jack running off with his harp.
+               [ Jack and the Beanstalk, from English Fairy Tales,
+                 by Joseph Jacobs ]
+healer
+* healer
+attendant
+doctor
+physician
+       I swear by Apollo the physician, and Aesculapius, and Health,
+       and All-heal, and all the gods and goddesses, that, according
+       to my ability and judgment, I will keep this Oath and this
+       stipulation -- to reckon him who taught me this Art equally dear
+       to me as my parents, to share my substance with him, and relieve
+       his necessities if required; to look upon his offspring in the
+       same footing as my own brothers, and to teach them this art, if
+       they shall wish to learn it, without fee or stipulation; and
+       that by precept, lecture, and every other mode of instruction,
+       I will impart a knowledge of the Art to my own sons, and those
+       of my teachers, and to disciples bound by a stipulation and oath
+       according to the law of medicine, but to none others.  I will
+       follow that system of regimen which, according to my ability and
+       judgment, I consider for the benefit of my patients, and abstain
+       from whatever is deleterious and mischievous.  [...]
+               [ Hippocrates' Oath, translated by Francis Adams ]
+
+       PHYSICIAN, n.  One upon whom we set our hopes when ill and our
+       dogs when well.
+               [ The Devil's Dictionary, by Ambrose Bierce ]
+heart of ahriman
+       The other three drew in their breath sharply, and the dark,
+       powerful man who stood at the head of the sarcophagus whispered:
+       "The Heart of Ahriman!"  The other lifted a quick hand
+       for silence.  Somewhere a dog began howling dolefully, and a
+       stealthy step padded outside the barred and bolted door. ...
+       But none looked aside from the mummy case over which the man
+       in the ermine-trimmed robe was now moving the great flaming
+       jewel, while he muttered an incantation that was old when
+       Atlantis sank.  The glare of the gem dazzled their eyes, so
+       that they could not be sure what they saw; but with a
+       splintering crash, the carven lid of the sarcophagus burst
+       outward as if from some irresistible pressure applied from
+       within and the four men, bending eagerly forward, saw the
+       occupant -- a huddled, withered, wizened shape, with dried
+       brown limbs like dead wood showing through moldering bandages.
+       "Bring that thing back?" muttered the small dark man who
+       stood on the right, with a short, sardonic laugh.  "It is
+       ready to crumble at a touch.  We are fools ---"
+               [ Conan The Conqueror, by Robert E. Howard ]
+hell hound*
+       Hell hounds are fire-breathing canines from another plane of
+       existence brought here in the service of evil beings.  A hell
+       hound resembles a large hound with rust-red or red-brown fur,
+       and red, glowing eyes.  The markings, teeth, and tongue are
+       soot black.  It stands two to three feet high at the shoulder
+       and has a distinct odour of smoke and sulphur.  The baying
+       sounds it makes have an eerie, hollow tone that sends a shiver
+       through any who hear them.
+hermes
+       Messenger and herald of the Olympians.  Being required to do
+       a great deal of travelling and speaking in public, he became
+       the god of eloquence, travellers, merchants, and thieves.  He
+       was one of the most energetic of the Greek gods, a
+       Machiavellian character full of trickery and sexual vigour.
+       Like other Greek gods, he is endowed with not-inconsiderable
+       sexual prowess which he directs towards countryside nymphs.
+       He is a god of boundaries, guardian of graves and patron deity
+       of shepherds.  He is usually depicted as a handsome young
+       man wearing winged golden sandals and holding a magical
+       herald's staff consisting of intertwined serpents, the
+       kerykeion.  He is reputedly the only being able to find his way
+       to the underworld ferry of Charon and back again.  He is said
+       to have invented, among other things, the lyre, Pan's Pipes,
+       numbers, the alphabet, weights and measures, and sacrificing.
+hezrou
+       "Hezrou" is the common name for the type II demon.  It is
+       among the weaker of demons, but still quite formidable.
+hippocrates
+       Greek physician, recognized as the father of medicine.  He
+       is believed to have been born on the island of Cos, to have
+       studied under his father, a physician, to have traveled for
+       some time, perhaps studying in Athens, and to have then
+       returned to practice, teach, and write at Cos.  The
+       Hippocratic or Coan school that formed around him was of
+       enormous importance in separating medicine from superstition
+       and philosophic speculation, placing it on a strictly
+       scientific plane based on objective observation and critical
+       deductive reasoning.
+               [ The Columbia Encyclopedia, Sixth Edition ]
+hobbit
+       Hobbits are an unobtrusive but very ancient people, more
+       numerous formerly than they are today; for they love peace
+       and quiet and good tilled earth:  a well-ordered and well-
+       farmed countryside was their favourite haunt.  They do not
+       and did not understand or like machines more complicated
+       than a forge-bellows, a water-mill, or a handloom, although
+       they were skillful with tools.  Even in ancient days they
+       were, as a rule, shy of "the Big Folk", as they call us, and
+       now they avoid us with dismay and are becoming hard to find.
+               [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+hobgoblin
+       Hobgoblin.  Used by the Puritans and in later times for
+       wicked goblin spirits, as in Bunyan's "Hobgoblin nor foul
+       friend", but its more correct use is for the friendly spirits
+       of the brownie type.  In "A midsummer night's dream" a
+       fairy says to Shakespeare's Puck:
+               Those that Hobgoblin call you, and sweet Puck,
+               You do their work, and they shall have good luck:
+               Are you not he?
+       and obviously Puck would not wish to be called a hobgoblin
+       if that was an ill-omened word.
+       Hobgoblins are on the whole, good-humoured and ready to be
+       helpful, but fond of practical joking, and like most of the
+       fairies rather nasty people to annoy.  Boggarts hover on the
+       verge of hobgoblindom.  Bogles are just over the edge.
+       One Hob mentioned by Henderson, was Hob Headless who haunted
+       the road between Hurworth and Neasham, but could not cross
+       the little river Kent, which flowed into the Tess.  He was
+       exorcised and laid under a large stone by the roadside for
+       ninety-nine years and a day.  If anyone was so unwary as to
+       sit on that stone, he would be unable to quit it for ever.
+       The ninety-nine years is nearly up, so trouble may soon be
+       heard of on the road between Hurworth and Neasham.
+               [ A Dictionary of Fairies, by Katharine Briggs ]
+holy water
+       "We want a word with you," said Ligur (in a tone of voice
+       intended to imply that "word" was synonymous with "horrifically
+       painful eternity"), and the squat demon pushed open the office
+       door.
+       The bucket teetered, then fell neatly on Ligur's head.
+       Drop a lump of sodium in water.  Watch it flame and burn and
+       spin around crazily, flaring and sputtering.  This was like
+       that, just nastier.
+       The demon peeled and flared and flickered.  Oily brown smoke
+       oozed from it, and it screamed and it screamed and it screamed.
+       Then it crumpled, folded in on itself, and what was left lay
+       glistening on the burnt and blackened circle of carpet, looking
+       like a handful of mashed slugs.
+       "Hi," said Crowley to Hastur, who had been walking behind Ligur,
+       and had unfortunately not been so much as splashed.
+       There are some things that are unthinkable; there are some
+       depths that not even demons would believe other demons would
+       stoop to.
+       ". . . Holy water.  You bastard," said Hastur.  "You complete
+       _bastard_.  He hadn't never done nothing to _you_."
+       "Yet," corrected Crowley.
+               [ Good Omens, by Neil Gaiman and Terry Pratchett ]
+hom*nculus
+       A homunculus is a creature summoned by a mage to perform some
+       particular task.  They are particularly good at spying.  They
+       are smallish creatures, but very agile.  They can put their
+       victims to sleep with a venomous bite, but due to their size,
+       the effect does not last long on humans.
+
+       "Tothapis cut him off.  'Be still and hearken.  You will travel
+       aboard the sacred wingboat.  Of it you may not have heard; but
+       it will bear you thither in a night and a day and a night.
+       With you will go a homunculus that can relay your words to me,
+       and mine to you, across the leagues between at the speed of
+       thought.'"
+               [ Conan the Rebel, by Poul Anderson ]
+# also gets 'pruning hook' aka guisarme
+*hook
+       But as for Queequeg -- why, Queequeg sat there among them --
+       at the head of the table, too, it so chanced; as cool as an
+       icicle.  To be sure I cannot say much for his breeding.  His
+       greatest admirer could not have cordially justified his
+       bringing his harpoon into breakfast with him, and using it
+       there without ceremony; reaching over the table with it, to
+       the imminent jeopardy of many heads, and grappling the
+       beefsteaks towards him.
+               [ Moby Dick, by Herman Melville ]
+~unicorn horn
+*horn
+       Roland hath set the Olifant to his mouth,
+       He grasps it well, and with great virtue sounds.
+       High are those peaks, afar it rings and loud,
+       Thirty great leagues they hear its echoes mount.
+       So Charles heard, and all his comrades round;
+       Then said that King: "Battle they do, our counts!"
+       And Guenelun answered, contrarious:
+       "That were a lie, in any other mouth."
+               [ The Song of Roland ]
+horned devil
+       Horned devils lack any real special abilities, though they
+       are quite difficult to kill.
+~horsem*
+*horse
+       King Richard III: A horse! a horse! my kingdom for a horse!
+       Catesby: Withdraw, my lord; I'll help you to a horse.
+       King Richard III: Slave, I have set my life upon a cast,
+                         And I will stand the hazard of the die:
+                         I think there be six Richmonds in the field;
+                         Five have I slain to-day instead of him.
+                         A horse! a horse! my kingdom for a horse!
+               [ King Richard III, by William Shakespeare ]
+*horsem*
+rider*
+death
+famine
+pestilence
+war
+hunger
+       [Pestilence:] And I saw when the Lamb opened one of the seals,
+       and I heard, as it were the noise of thunder, one of the four
+       beasts saying, Come and see.  And I saw, and behold a white
+       horse: and he that sat on him had a bow; and a crown was given
+       unto him: and he went forth conquering, and to conquer.
+
+       [War:] And when he had opened the second seal, I heard the
+       second beast say, Come and see.  And there went out another
+       horse that was red: and power was given to him that sat thereon
+       to take peace from the earth, and that they should kill one
+       another: and there was given unto him a great sword.
+
+       [Famine:] And when he had opened the third seal, I heard the
+       third beast say, Come and see.  And I beheld, and lo a black
+       horse; and he that sat on him had a pair of balances in his
+       hand.  And I heard a voice in the midst of the four beasts say,
+       A measure of wheat for a penny, and three measures of barley
+       for a penny; and see thou hurt not the oil and the wine.
+
+       [Death:] And when he had opened the fourth seal, I heard the
+       voice of the fourth beast say, Come and see.  And I looked, and
+       behold a pale horse: and his name that sat on him was Death,
+       and Hell followed with him.  And power was given unto them over
+       the fourth part of the earth, to kill with sword, and with
+       hunger, and with death, and with the beasts of the earth.
+            [ Revelations of John, 6:1-8 ]
+huan*ti
+       The first of five mythical Chinese emperors, Huan Ti is known
+       as the yellow emperor.  He rules the _moving_ heavens, as
+       opposed to the _dark_ heavens.  He is an inventor, said to
+       have given mankind among other things, the wheel, armour, and
+       the compass.  He is the god of fortune telling and war.
+hu*h*eto*l
+minion of huhetotl
+       Huehuetotl, or Huhetotl, which means Old God, was the Aztec
+       (classical Mesoamerican) god of fire.  He is generally
+       associated with paternalism and one of the group classed
+       as the Xiuhtecuhtli complex.  He is known to send his
+       minions to wreak havoc upon ordinary humans.
+            [ after the Encyclopedia of Gods, by Michael Jordan ]
+humanoid
+       Humanoids are all approximately the size of a human, and may
+       be mistaken for one at a distance.  They are usually of a
+       tribal nature, and will fiercely defend their lairs.  Usually
+       hostile, they may even band together to raid and pillage
+       human settlements.
+human
+chieftain
+guard
+ninja
+nurse
+page
+ronin
+shopkeeper
+student
+thug
+warrior
+*watch*
+player
+       These strange creatures live mostly on the surface of the
+       earth, gathering together in societies of various forms, but
+       occasionally a stray will descend into the depths and commit
+       mayhem among the dungeon residents who, naturally, often
+       resent the intrusion of such beasts.  They are capable of
+       using weapons and magic, and it is even rumored that the
+       Wizard of Yendor is a member of this species.
+hunter
+       What of the hunting, hunter bold?
+       Brother, the watch was long and cold.
+       What of the quarry ye went to kill?
+       Brother, he crops in the jungle still.
+       Where is the power that made your pride?
+       Brother, it ebbs from my flank and side.
+       Where is the haste that ye hurry by?
+       Brother, I go to my lair to die.
+               [ The Jungle Book, by Rudyard Kipling ]
+ice devil
+       Ice devils are large semi-insectoid creatures, who are
+       equally at home in the fires of Hell and the cold of Limbo,
+       and who can cause the traveller to feel the latter with just
+       a touch of their tail.
+imp
+        ... imps ... little creatures of two feet high that could
+       gambol and jump prodigiously; ...
+               [ The Charwoman's Shadow, by Lord Dunsany ]
+
+       An 'imp' is an off-shoot or cutting.  Thus an 'ymp tree' was
+       a grafted tree, or one grown from a cutting, not from seed.
+       'Imp' properly means a small devil, an off-shoot of Satan,
+       but the distinction between goblins or bogles and imps from
+       hell is hard to make, and many in the Celtic countries as
+       well as the English Puritans regarded all fairies as devils.
+       The fairies of tradition often hover uneasily between the
+       ghostly and the diabolic state.
+               [ A Dictionary of Fairies, by Katharine Briggs ]
+incubus
+succubus
+       The incubus and succubus are male and female versions of the
+       same demon, one who lies with a human for its own purposes,
+       usually to the detriment of the mortals who are unwise in
+       their dealings with them.
+*iron ball
+*iron chain
+       "You are fettered, " said Scrooge, trembling.  "Tell me why?"
+       "I wear the chain I forged in life," replied the Ghost.  "I
+       made it link by link, and yard by yard; I girded it on of my
+       own free will, and of my own free will I wore it.  Is its
+       pattern strange to you?"
+       Scrooge trembled more and more.
+       "Or would you know," pursued the Ghost, "the weight and
+       length of the strong coil you bear yourself?  It was full as
+       heavy and as long as this, seven Christmas Eves ago.  You
+       have laboured on it, since.  It is a ponderous chain!"
+               [ A Christmas Carol, by Charles Dickens ]
+ishtar
+       Ishtar (the star of heaven) is the Mesopotamian goddess of
+       fertility and war.  She is usually depicted with wings and
+       weapon cases at her shoulders, carrying a ceremonial double-
+       headed mace-scimitar embellished with lion heads, frequently
+       being accompanied by a lion.  She is symbolized by an eight-
+       pointed star.
+               [ Encyclopedia of Gods, by Michael Jordan ]
+issek
+       Now Issek of the Jug, whom Fafhrd chose to serve, was once
+       of the most lowly and unsuccessful of the gods, godlets
+       rather, in Lankhmar.  He had dwelt there for about thirteen
+       years, during which time he had traveled only two squares up
+       the Street of the Gods and was now back again, ready for
+       oblivion.  He is not to be confused with Issek the Armless,
+       Issek of the Burnt Legs, Flayed Issek, or any other of the
+       numerous and colorfully mutilated divinities of that name.
+       Indeed, his unpopularity may have been due in part to the
+       fact that the manner of his death -- racking -- was not
+       deemed particularly spectacular. ... However, after Fafhrd
+       became his acolyte, things somehow began to change.
+               [ Swords In The Mist, by Fritz Leiber ]
+izchak
+       The shopkeeper of the lighting shop in the town level of the
+       gnomish mines is a tribute to Izchak Miller, a founding member
+       of the NetHack development team and a personal friend of a large
+       number of us.  Izchak contributed greatly to the game, coding a
+       large amount of the shopkeep logic (hence the nature of the tribute)
+       as well as a good part of the alignment system, the prayer code and
+       the rewrite of "hell" in the 3.1 release.  Izchak was a professor
+       of Philosophy, who taught at many respected institutions, including
+       MIT and Stanford, and who also worked, for a period of time, at
+       Xerox PARC.  Izchak was the first "librarian" of the NetHack project,
+       and was a founding member of the DevTeam, joining in 1986 while he
+       was working at the University of Pennsylvania (hence our former
+       mailing list address).  Until the 3.1.3 release, Izchak carefully
+       kept all of the code synchronized and arbitrated disputes between
+       members of the development teams.  Izchak Miller passed away at the
+       age of 58, in the early morning hours of April 1, 1994 from
+       complications due to cancer.  We then dedicated NetHack 3.2 in his
+       memory.
+                       [ Mike Stephenson, for the NetHack DevTeam ]
+jabberwock
+vorpal*
+       "Beware the Jabberwock, my son!
+         The jaws that bite, the claws that catch!
+       Beware the Jubjub bird, and shun
+         The frumious Bandersnatch!"
+
+       He took his vorpal sword in hand;
+         Long time the manxome foe he sought --
+       So rested he by the Tumtum tree,
+         And stood awhile in thought.
+
+       And, as in uffish thought he stood,
+         The Jabberwock, with eyes of flame,
+       Came whiffling through the tulgey wood,
+         And burbled as it came!
+
+       One, two! One, two! And through and through
+         The vorpal blade went snicker-snack!
+       He left it dead, and with its head
+         He went galumphing back.
+                               [ Jabberwocky, by Lewis Carroll ]
+jackal
+       In Asiatic folktale, jackal provides for the lion; he scares
+       up game, which the lion kills and eats, and receives what is
+       left as reward.  In stories from northern India he is
+       sometimes termed "minister to the king," i.e. to the lion.
+       From the legend that he does not kill his own food has arisen
+       the legend of his cowardice.  Jackal's heart must never be
+       eaten, for instance, in the belief of peoples indigenous to
+       the regions where the jackal abounds. ... In Hausa Negro
+       folktale Jackal plays the role of sagacious judge and is
+       called "O Learned One of the Forest."  The Bushmen say that
+       Jackal goes around behaving the way he does "because he is
+       Jackal".
+               [ Funk & Wagnalls Standard Dictionary of Folklore ]
+jade*
+       Nothing grew among the ruins of the city.  The streets were
+       broken and the walls of the houses had fallen, but there were
+       no weeds flowering in the cracks and it seemed that the city
+       had but recently been brought down by an earthquake.  Only
+       one thing still stood intact, towering over the ruins.  It
+       was a gigantic statue of white, gray and green jade - the
+       statue of a naked youth with a face of almost feminine beauty
+       that turned sightless eyes toward the north.
+       "The eyes!" Duke Avan Astran said.  "They're gone!"
+               [ The Jade Man's Eyes, by Michael Moorcock ]
+jaguar
+       Large, flesh-eating animal of the cat family, of Central and
+       South America.  This feline predator (_Panthera onca_) is
+       sometimes incorrectly called a panther.
+        [ Van Dale's Groot Woordenboek der Nederlandse Taal ]
+jellyfish
+       I do not care to share the seas
+       With jellyfishes such as these;
+       Particularly Portuguese.
+               [ Lines on Meeting a Portuguese Man-o'-war while
+                       Bathing, by Michael Flanders ]
+juiblex
+jubilex
+       Little is known about the Faceless Lord, even the correct
+       spelling of his name.  He does not have a physical form as
+       we know it, and those who have peered into his realm claim
+       he is a slime-like creature who swallows other creatures
+       alive, spits acidic secretions, and causes disease in his
+       victims which can be almost instantly fatal.
+kabuto
+       The kabuto is the helmet worn by the samurai.  It was
+       characterized by a prominent beaked front which jutted out over
+       the brow to protect the wearer's face; a feature that gives
+       rise to their modern Japanese name of 'shokaku tsuki kabuto'
+       (battering-ram helmet).  Their main constructional element
+       was an oval plate, the shokaku bo, slightly domed for the
+       head with a narrow prolongation in front that curved forwards
+       and downwards where it developed a pronounced central
+       fold.  Two horizontal strips encircling the head were riveted
+       to this frontal strip:  the lower one, the koshimaki (hip
+       wrap), formed the lower edge of the helmet bowl; the other,
+       the do maki (body wrap), was set at about the level of the
+       temples.  Filling the gaps between these strips and the shokaku
+       bo were small plates, sometimes triangular but more commonly
+       rectangular in shape.  Because the front projected so
+       far from the head, the triangular gap beneath was filled by
+       a small plate, the shoshaku tei ita, whose rear edge bent
+       downwards into a flange that rested against the forehead.
+          [ Arms & Armour of the Samurai, by Bottomley & Hopson ]
+katana
+       The katana is a long, single-edged samurai sword with a
+       slightly curved blade.  Its long handle is designed to allow
+       it to be wielded with either one or two hands.
+ki-rin
+       The ki-rin is a strange-looking flying creature.  It has
+       scales, a mane like a lion, a tail, hooves, and a horn.  It
+       is brightly colored, and can usually be found flying in the
+       sky looking for good deeds to reward.
+king arthur
+*arthur
+       Ector took both his sons to the church before which the
+       anvil had been placed.  There, standing before the anvil, he
+       commanded Kay:  "Put the sword back into the steel if you
+       really think the throne is yours!"  But the sword glanced
+       off the steel.  "Now it is your turn", Ector said facing
+       Arthur.
+       The young man lifted the sword and thrust with both arms; the
+       blade whizzed through the air with a flash and drilled the
+       metal as if it were mere butter.  Ector and Kay dropped to
+       their knees before Arthur.
+       "Why, father and brother, do you bow before me?", Arthur asked
+       with wonder in his voice.
+       "Because now I know for sure that you are the king, not only
+       by birth but also by law", Ector said.  "You are no son of
+       mine nor are you Kay's brother.  Immediately after your birth,
+       Merlin the Wise brought you to me to be raised safely.  And
+       though it was me that named you Arthur when you were baptized,
+       you are really the son of brave king Uther Pendragon and queen
+       Igraine..."
+       And after these words, the lord rose and went to see the arch-
+       bishop to impart to him what had passed.
+          [ Van Gouden Tijden Zingen de Harpen, by Vladimir Hulpach,
+               Emanuel Frynta, and Vackav Cibula ]
+knife
+stiletto
+       Possibly perceiving an expression of dubiosity on their
+       faces, the globetrotter went on adhering to his adventures.
+
+       -- And I seen a man killed in Trieste by an Italian chap.
+       Knife in his back.  Knife like that.
+
+       Whilst speaking he produced a dangerous looking clasp knife,
+       quite in keeping with his character, and held it in the
+       striking position.
+
+       -- In a knockingshop it was count of a tryon between two
+       smugglers.  Fellow hid behind a door, come up behind him.
+       Like that.  Prepare to meet your God, says he.  Chuck!  It
+       went into his back up to the butt.
+               [ Ulysses, by James Joyce ]
+knight
+* knight
+       Here lies the noble fearless knight,
+       Whose valour rose to such a height;
+       When Death at last had struck him down,
+       His was the victory and renown.
+       He reck'd the world of little prize,
+       And was a bugbear in men's eyes;
+       But had the fortune in his age
+       To live a fool and die a sage.
+               [ Don Quixote of La Mancha by Miquel de
+                 Cervantes Saavedra ]
+~kobold ??m*
+*kobold*
+       The race of kobolds are reputed to be an artificial creation
+       of a master wizard (demi-god?).  They are about 3' tall with
+       a vaguely dog-like face.  They bear a violent dislike of the
+       Elven race, and will go out of their way to cause trouble
+       for Elves at any time.
+*kop*
+       The Kops are a brilliant concept.  To take a gaggle of inept
+       policemen and display them over and over again in a series of
+       riotously funny physical punishments plays equally well to the
+       peanut gallery and the expensive box seats.  People hate cops.
+       Even people who have never had anything to do with cops hate
+       them.  Of course, we count on them to keep order and to protect
+       us when we need protecting, and we love them on television shows
+       in which they have nerves of steel and hearts of gold, but in
+       the abstract, as a nation, collectively we hate them.  They are
+       too much like high school principals.  We're very happy to see
+       their pants fall down, and they look good to us with pie on
+       their faces.  The Keystone Kops turn up--and they get punished
+       for it, as they crash into each other, fall down, and suffer
+       indignity after indignity.  Here is pure movie satisfaction.
+
+       The Kops are very skillfully presented.  The comic originality
+       and timing in one of their chase scenes requires imagination
+       to think up, talent to execute, understanding of the medium,
+       and, of course, raw courage to perform.  The Kops are madmen
+       presented as incompetents, and they're madmen rushing around
+       in modern machines.  What's more, the machines they were operating
+       in their routines were newly invented and not yet experienced
+       by the average moviegoer.  (In the early days of automobiles,
+       it was reported that there were only two cars registered in all
+       of Kansas City, and they ran into each other.  There is both
+       poetry and philosophy in this fact, but most of all, there is
+       humor.  Sennett got the humor.)
+               [ Silent Stars, by Jeanine Basinger ]
+kos
+       "I am not a coward!" he cried.  "I'll dare Thieves' House
+       and fetch you Krovas' head and toss it with blood a-drip at
+       Vlana's feet.  I swear that, witness me, Kos the god of
+       dooms, by the brown bones of Nalgron my father and by his
+       sword Graywand here at my side!"
+          [ Swords and Deviltry, by Fritz Leiber ]
+koto
+       A Japanese harp.
+kraken
+       Out from the water a long sinuous tentacle had crawled; it
+       was pale-green and luminous and wet.  Its fingered end had
+       hold of Frodo's foot, and was dragging him into the water.
+       Sam on his knees was now slashing at it with a knife.  The
+       arm let go of Frodo, and Sam pulled him away, crying out
+       for help.  Twenty other arms came rippling out.  The dark
+       water boiled, and there was a hideous stench.
+          [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+*lady
+offler
+       Blind Io took up the dice-box, which was a skull whose various
+       orifices had been stoppered with rubies, and with several of
+       his eyes on the Lady he rolled three fives.  She smiled.  This
+       was the nature of the Lady's eyes:  they were bright green,
+       lacking iris or pupil, and they glowed from within.
+
+       The room was silent as she scrabbled in her box of pieces and,
+       from the very bottom, produced a couple that she set down on
+       the board with two decisive clicks.  The rest of the players,
+       as one God, craned forward to peer at them.
+
+       "A wenegade wiffard and fome fort of clerk," said Offler the
+       Crocodile God, hindered as usual by his tusks.  "Well,
+       weally!"  With one claw he pushed a pile of bone-white tokens
+       into the centre of the table.
+
+       The Lady nodded slightly.  She picked up the dice-cup and held
+       it as steady as a rock, yet all the Gods could hear the three
+       cubes rattling about inside.  And then she sent them bouncing
+       across the table.
+
+       A six.  A three.  A five.
+
+       Something was happening to the five, however.  Battered by the
+       chance collision of several billion molecules, the die flipped
+       onto a point, spun gently and came down a seven.  Blind Io
+       picked up the cube and counted the sides.
+
+       "Come _on_," he said wearily, "Play fair."
+               [ The Colour of Magic, by Terry Pratchett ]
+*lamp
+       When he came to himself he told his mother what had passed,
+       and showed her the lamp and the fruits he had gathered in the
+       garden, which were in reality precious stones.  He then asked
+       for some food.
+
+       "Alas! child," she said, "I have nothing in the house, but I
+       have spun a little cotton and will go and sell it."
+
+       Aladdin bade her keep her cotton, for he would sell the lamp
+       instead.  As it was very dirty she began to rub it, that it
+       might fetch a higher price.  Instantly a hideous genie
+       appeared, and asked what she would have.  She fainted away,
+       but Aladdin, snatching the lamp, said boldly:
+       "Fetch me something to eat!"
+               [ Aladdin, from The Arabian Nights, by Andrew Lang ]
+lance
+       With this the wind increased, and the mill sails began to turn 
+       about; which Don Quixote espying, said, 'Although thou movest
+       more arms than the giant Briareus thou shalt stoop to me.'
+       And, after saying this, and commending himself most devoutly
+       to his Lady Dulcinea, desiring her to succor him in that trance,
+       covering himself well with his buckler, and setting his lance
+       on his rest, he spurred on Rozinante, and encountered with the
+       first mill that was before him, and, striking his lance into
+       the sail, the wind swung it about with such fury, that it broke
+       his lance into shivers, carrying him and his horse after it,
+       and finally tumbled him a good way off from it on the field in 
+       evil plight.
+               [ Don Quixote of La Mancha by Miquel de
+                 Cervantes Saavedra ]
+leash
+       They had splendid heads, fine shoulders, strong legs, and
+       straight tails.  The spots on their bodies were jet-black and
+       mostly the size of a two-shilling piece; they had smaller
+       spots on their heads, legs, and tails.  Their noses and eye-
+       rims were black.  Missis had a most winning expression.
+       Pongo, though a dog born to command, had a twinkle in his
+       eye.  They walked side by side with great dignity, only
+       putting the Dearlys on the leash to lead them over crossings.
+               [ The Hundred and One Dalmatians, by Dodie Smith ]
+lembas*
+       In the morning, as they were beginning to pack their slender
+       goods, Elves that could speak their tongue came to them and
+       brought them many gifts of food and clothing for their
+       journey.  The food was mostly in the form of very thin cakes,
+       made of a meal that was baked a light brown on the outside,
+       and inside was the colour of cream.  Gimli took up one of the
+       cakes and looked at it with a doubtful eye.
+       'Cram,' he said under his breath, as he broke off a crisp
+       corner and nibbled at it.  His expression quickly changed,
+       and he ate all the rest of the cake with relish.
+       'No more, no more!' cried the Elves laughing.  'You have
+       eaten enough already for a long day's march.'
+       'I thought it was only a kind of cram, such as the Dalemen
+       make for journeys in the wild,' said the Dwarf.
+       'So it is,' they answered.  'But we call it lembas or
+       waybread, and it is more strengthening than any foods made by
+       Men, and it is more pleasant than cram, by all accounts.'
+               [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+lemure
+       The lowliest of the inhabitants of hell.
+leocrotta
+leu*otta
+       ... the leucrocotta, a wild beast of extraordinary swiftness,
+       the size of the wild ass, with the legs of a Stag, the neck,
+       tail, and breast of a lion, the head of a badger, a cloven
+       hoof, the mouth slit up as far as the ears, and one continuous
+       bone instead of teeth; it is said, too, that this animal can
+       imitate the human voice.
+               [ Curious Creatures in Zoology, by John Ashton ]
+leprechaun
+       The Irish Leprechaun is the Faeries' shoemaker and is known
+       under various names in different parts of Ireland:
+       Cluricaune in Cork, Lurican in Kerry, Lurikeen in Kildare
+       and Lurigadaun in Tipperary.  Although he works for the
+       Faeries, the Leprechaun is not of the same species.  He is
+       small, has dark skin and wears strange clothes.  His nature
+       has something of the manic-depressive about it:  first he
+       is quite happy, whistling merrily as he nails a sole on to a
+       shoe; a few minutes later, he is sullen and morose, drunk
+       on his home-made heather ale.  The Leprechaun's two great
+       loves are tobacco and whiskey, and he is a first-rate con-man,
+       impossible to out-fox.  No one, no matter how clever, has ever
+       managed to cheat him out of his hidden pot of gold or his
+       magic shilling.  At the last minute he always thinks of some
+       way to divert his captor's attention and vanishes in the
+       twinkling of an eye.
+               [ A Field Guide to the Little People
+                              by Nancy Arrowsmith & George Moorse ]
+*lich
+       But on its heels ere the sunset faded, there came a second
+       apparition, striding with incredible strides and halting when
+       it loomed almost upon me in the red twilight-the monstrous mummy
+       of some ancient king still crowned with untarnished gold but
+       turning to my gaze a visage that more than time or the worm had
+       wasted. Broken swathings flapped about the skeleton legs, and
+       above the crown that was set with sapphires and orange rubies, a
+       black something swayed and nodded horribly; but, for an instant,
+       I did not dream what it was.  Then, in its middle, two oblique
+       and scarlet eyes opened and glowed like hellish coals, and two
+       ophidian fangs glittered in an ape-like mouth.  A squat, furless,
+       shapeless head on a neck of disproportionate extent leaned
+       unspeakably down and whispered in the mummy's ear. Then, with
+       one stride, the titanic lich took half the distance between us,
+       and from out the folds of the tattered sere-cloth a gaunt arm
+       arose, and fleshless, taloned fingers laden with glowering gems,
+       reached out and fumbled for my throat . . .
+               [ The Abominations of Yondo, Clark Ashton Smith, 1926 ]
+lichen
+       The chamber was of unhewn rock, round, as near as might
+       be, eighteen or twenty feet across, and gay with rich
+       variety of fern and moss and lichen.  The fern was in
+       its winter still, or coiling for the spring-tide; but
+       moss was in abundant life, some feathering, and some
+       gobleted, and some with fringe of red to it.
+               [ Lorna Doone, by R.D. Blackmore ]
+~* of light
+* light
+       Strange creatures formed from energy rather than matter,
+       lights are given to self-destructive behavior when battling
+       foes.
+gecko
+iguana
+lizard
+       Lizards, snakes and the burrowing amphisbaenids make up the
+       order Squamata, meaning the scaly ones.  The elongate, slim,
+       long-tailed bodies of lizards have become modified to enable
+       them to live in a wide range of habitats.  Lizards can be
+       expert burrowers, runners, swimmers and climbers, and a few
+       can manage crude, short-distance gliding on rib-supported
+       "wings".  Most are carnivores, feeding on invertebrate and
+       small vertebrate prey, but others feed on vegetation.
+               [ Macmillan Illustrated Animal Encyclopedia ]
+loki
+       Loki, or Lopt, is described in Snorri's _Edda_ as being
+       "pleasing and handsome in appearance, evil in character, and
+       very capricious in behaviour".  He is the son of the giant
+       Farbauti and of Laufey.
+       Loki is the Norse god of cunning, evil, thieves, and fire.
+       He hated the other gods and wanted to ruin them and overthrow
+       the universe.  He committed many murders.  As a thief, he
+       stole Freyja's necklace, Thor's belt and gauntlets of power,
+       and the apples of youth.  Able to shapechange at will, he is
+       said to have impersonated at various times a mare, flea, fly,
+       falcon, seal, and an old crone.  As a mare he gave birth to
+       Odin's horse Sleipnir.  He also allegedly sired the serpent
+       Midgard, the mistress of the netherworld, Hel, and the wolf
+       Fenrir, who will devour the sun at Ragnarok.
+*longbow of diana
+       This legendary bow grants ESP when carried and can reflect magical
+       attacks when wielded.  When invoked it provides a supply of arrows.
+# long worm -- see "worm"
+looking glass
+mirror
+       But as Snow White grew, she became more and more beautiful,
+       and by the time she was seven years old she was as beautiful
+       as the day and more beautiful than the queen herself.  One
+       day when the queen said to her mirror:
+
+               "Mirror, Mirror, here I stand.
+               Who is the fairest in the land?" -
+
+       the mirror replied:
+
+               "You, O Queen, are the fairest here,
+               But Snow White is a thousand times more fair."
+               [ Snow White, by Jakob and Wilhelm Grimm ]
+lord carnarvon
+       Lord Carnarvon was a personality who could have been produced
+       nowhere but in England, a mixture of sportsman and collector,
+       gentleman and world traveler, a realist in action and a
+       romantic in feeling.  ...  In 1903 he went for the first time
+       to Egypt in search of a mild climate and while there visited
+       the excavation sites of several archaeological expeditions.
+       ...  In 1906 he began his own excavations.
+               [ Gods, Graves, and Scholars, by C. W. Ceram ]
+lord sato
+       Lord Sato was the family head of the Taro Clan, and a mighty
+       daimyo.  He is a loyal servant of the Emperor, and will do
+       everything in his power to further the imperial cause.
+lord surt*
+       Yet first was the world in the southern region, which was
+       named Muspell; it is light and hot; that region is glowing
+       and burning, and impassable to such as are outlanders and
+       have not their holdings there.  He who sits there at the
+       land's-end, to defend the land, is called Surtr; he brandishes
+       a flaming sword, and at the end of the world he shall go forth
+       and harry, and overcome all the gods, and burn all the
+       world with fire.
+                       [ The Prose Edda, by Snorri Sturluson ]
+lug*
+       Lugh, or Lug, was the sun god of the Irish Celts.  One of his
+       weapons was a rod-sling which worshippers sometimes saw in
+       the sky as a rainbow.  As a tribal god, he was particularly
+       skilled in the use of his massive, invincible spear, which
+       fought on its own accord.  One of his epithets is _lamfhada_
+       (of the long arm).  He was a young and apparently more
+       attractive deity than Dagda, the father of the gods.  Being
+       able to shapeshift, his name translates as lynx.
+lurker*
+       These dungeon scavengers are very adept at blending into the
+       surrounding walls and ceilings of the dungeon due to the
+       stone-like coloring of their skin.
+lycanthrope
+were*
+human were*
+*were
+       In 1573, the Parliament of Dole published a decree, permitting
+       the inhabitants of the Franche-Comte to pursue and kill a
+       were-wolf or loup-garou, which infested that province,
+       "notwithstanding the existing laws concerning the chase."
+       The people were empowered to "assemble with javelins,
+       halberds, pikes, arquebuses and clubs, to hunt and pursue the
+       said were-wolf in all places where they could find it, and to
+       take, burn, and kill it, without incurring any fine or other
+       penalty."  The hunt seems to have been successful, if we may
+       judge from the fact that the same tribunal in the following
+       year condemned to be burned a man named Giles Garnier, who
+       ran on all fours in the forest and fields and devoured little
+       children, "even on Friday."  The poor lycanthrope, it appears,
+       had as slight respect for ecclesiastical feasts as the French
+       pig, which was not restrained by any feeling of piety from
+       eating infants on a fast day.
+               [ The History of Vampires, by Dudley Wright ]
+lynx
+       To dream of seeing a lynx, enemies are undermining your
+       business and disrupting your home affairs.  For a woman,
+       this dream indicates that she has a wary woman rivaling her
+       in the affections of her lover. If she kills the lynx, she
+       will overcome her rival.
+               [ 10,000 Dreams Interpreted, by Gustavus Hindman Miller ]
+magic marker
+       The pen is mightier than the sword.
+               [ Richelieu, by Edward Bulwer-Lytton ]
+magic mirror of merlin
+       This powerful mirror was created by Merlin, the druid, in ages
+       past, when trees sang and rocks danced.  It protects all who
+       carry it from magic missiles, and gives them ESP.
+mail d*emon
+       It is rumoured that these strange creatures can be harmed by
+       domesticated canines only.
+ma*annan*
+       Normally called Manannan, Ler's son was the patron of
+       merchants and sailors.  Manannan had a sword which never
+       failed to slay, a boat which propelled itself wherever its
+       owner wished, a horse which was swifter than the wind, and
+       magic armour which no sword could pierce.  He later became
+       god of the sea, beneath which he lived in Tir na nOc, the
+       underworld.
+manes
+       The gnats of the dungeon, these swarming monsters are rarely
+       seen alone.
+marduk
+       First insisting on recognition as supreme commander, Marduk
+       defeated the Dragon, cut her body in two, and from it created
+       heaven and earth, peopling the world with human beings who not
+       unnaturally showed intense gratitude for their lives.  The
+       gods were also properly grateful, invested him with many
+       titles, and eventually permitted themselves to be embodied in
+       him, so that he became supreme god, plotting the whole course
+       of known life from the paths of the planets to the daily
+       events in the lives of men.
+               [ The Immortals, by Derek and Julia Parker ]
+marilith
+       The marilith has a torso shaped like that of a human female,
+       and the lower body of a great snake.  It has multiple arms,
+       and can freely attack with all of them.  Since it is
+       intelligent enough to use weapons, this means it can cause
+       great damage.
+mars
+       The god of war, and one of the most prominent and worshipped
+       gods.  In early Roman history he was a god of spring, growth in
+       nature, and fertility, and the protector of cattle.  Mars is
+       also mentioned as a chthonic god (earth-god) and this could
+       explain why he became a god of death and finally a god of war.
+       He is the son of Jupiter and Juno.
+               [ Encyclopedia Mythica, ed. M.F. Lindemans ]
+master assassin
+       He strolled down the stairs, followed by a number of assassins.
+       When he was directly in front of Ymor he said: "I've come for
+       the tourist." ...
+       "One step more and you'll leave here with fewer eyeballs than
+       you came with," said the thiefmaster.  "So sit down and have
+       a drink, Zlorf, and let's talk about this sensibly.  _I_
+       thought we had an agreement.  You don't rob -- I don't kill.
+       Not for payment, that is," he added after a pause.
+       Zlorf took the proffered beer.
+       "So?" he said.  "I'll kill him.  Then you rob him.  Is he that
+       funny looking one over there?"
+       "Yes."
+       Zlorf stared at Twoflower, who grinned at him.  He shrugged.
+       He seldom wasted time wondering why people wanted other people
+       dead.  It was just a living.
+       "Who is your client, may I ask?" said Ymor.
+       Zlorf held up a hand.  "Please!" he protested.  "Professional
+       etiquette."
+               [ The Colour of Magic, by Terry Pratchett ]
+master key of thievery
+       This skeleton key was fashioned in ages past and imbued with
+       a powerful magic which allows it to open any lock.  When
+       carried, it grants its owner warning, teleport control, and
+       reduces all physical damage by half.  Finally, when invoked,
+       it has the ability to disarm any trap.
+master of thieves
+       There was a flutter of wings at the window.  Ymor shifted his
+       bulk out of the chair and crossed the room, coming back with
+       a large raven.  After he'd unfastened the message capsule from
+       its leg it flew up to join its fellows lurking among the
+       rafters.  Withel regarded it without love.  Ymor's ravens were
+       notoriously loyal to their master, to the extent that Withel's
+       one attempt to promote himself to the rank of greatest thief
+       in Ankh-Morpork had cost their master's right hand man his
+       left eye.  But not his life, however.  Ymor never grudged a
+       man his ambitions.
+               [ The Colour of Magic, by Terry Pratchett ]
+mastodon
+       Any large, elephantlike mammal of the genera Mammut, Mastodon,
+       etc., from the Oligocene and Pleistocene epochs, having
+       conical projections on the molar teeth.
+               [ Webster's Encyclopedic Unabridged Dictionary
+                       of the English Language ]
+meat*
+huge chunk of meat
+       Some hae meat and canna eat,
+       And some would eat that want it;
+       But we hae meat, and we can eat,
+       Sae let the Lord be thankit.
+               [ Grace Before Meat, by Robert Burns ]
+medusa
+       Medusa, one of the three Gorgons or Graeae, is the only one
+       of her sisters to have assumed mortal form and inhabited the
+       dungeon world.
+
+       When Perseus was grown up Polydectes sent him to attempt the
+       conquest of Medusa, a terrible monster who had laid waste the
+       country.  She was once a beautiful maiden whose hair was her
+       chief glory, but as she dared to vie in beauty with Minerva,
+       the goddess deprived her of her charms and changed her
+       beautiful ringlets into hissing serpents.  She became a cruel
+       monster of so frightful an aspect that no living thing could
+       behold her without being turned into stone.  All around the
+       cavern where she dwelt might be seen the stony figures of men
+       and animals which had chanced to catch a glimpse of her and
+       had been petrified with the sight.  Perseus, favoured by
+       Minerva and Mercury, the former of whom lent him her shield
+       and the latter his winged shoes, approached Medusa while she
+       slept and taking care not to look directly at her, but guided
+       by her image reflected in the bright shield which he bore, he
+       cut off her head and gave it to Minerva, who fixed it in the
+       middle of her Aegis.
+               [ Bulfinch's Mythology, by Thomas Bulfinch ]
+melon
+       "What is it, Umbopa, son of a fool?" I shouted in Zulu.
+       "It is food and water, Macumazahn," and again he waved the
+       green thing.
+       Then I saw what he had got.  It was a melon.  We had hit upon
+       a patch of wild melons, thousands of them, and dead ripe.
+       "Melons!" I yelled to Good, who was next me; and in another
+       second he had his false teeth fixed in one.
+       I think we ate about six each before we had done, and, poor
+       fruit as they were, I doubt if I ever thought anything nicer.
+               [ King Solomon's Mines, by H. Rider Haggard ]
+mercury
+       Roman god of commerce, trade and travellers.  He is commonly
+       depicted carrying a caduceus (a staff with two snakes
+       intertwining around it) and a purse.
+*mimic
+       The ancestors of the modern day chameleon, these creatures can
+       assume the form of anything in their surroundings.  They may
+       assume the shape of objects or dungeon features.  Unlike the
+       chameleon though, which assumes the shape of another creature
+       and goes in hunt of food, the mimic waits patiently for its
+       meals to come in search of it.
+*mind flayer
+       This creature has a humanoid body, tentacles around its
+       covered mouth, and three long fingers on each hand.  Mind
+       flayers are telepathic, and love to devour intelligent beings,
+       especially humans.  If they hit their victim with a tentacle,
+       the mind flayer will slowly drain it of all intelligence,
+       eventually killing its victim.
+mine*
+       Made by Dwarfs.  The Rule here is that the Mine is either long
+       deserted or at most is inhabited by a few survivors who will
+       make confused claims to have been driven out/decimated by humans/
+       other Dwarfs/Minions of the Dark Lord.  Inhabited or not, this
+       Mine will be very complex, with many levels of galleries,
+       beautifully carved and engineered.  What was being mined here
+       is not always evident, but at least some of the time it will
+       appear to have been Jewels, since it is customary to find
+       unwanted emeralds, etc., still embedded in the rock of the
+       walls.  Metal will also be present, but only when made up into
+       armor and weapons (_wondrous_).
+       [ The Tough Guide to Fantasyland, by Diana Wynne Jones ]
+minotaur
+       The Minotaur was a monster, half bull, half human, the
+       offspring of Minos' wife Pasiphae and a wonderfully beautiful
+       bull. ...  When the Minotaur was born Minos did not kill him.
+       He had Daedalus, a great architect and inventor, construct a
+       place of confinement for him from which escape was impossible.
+       Daedalus built the Labyrinth, famous throughout the world.
+       Once inside, one would go endlessly along its twisting paths
+       without ever finding the exit.
+               [ Mythology, by Edith Hamilton ]
+mit*ra*
+       Originating in India (Mitra), Mithra is a god of light who
+       was translated into the attendant of the god Ahura Mazda in
+       the light religion of Persia; from this he was adopted as
+       the Roman deity Mithras.  He is not generally regarded as a
+       sky god but a personification of the fertilizing power of
+       warm, light air.  According to the _Avesta_, he possesses
+       10,000 eyes and ears and rides in a chariot drawn by white
+       horses.  Mithra, according to Zarathustra, is concerned with
+       the endless battle between light and dark forces:  he
+       represents truth.  He is responsible for the keeping of oaths
+       and contracts.  He is attributed with the creation of both
+       plants and animals.  His chief adversary is Ahriman, the
+       power of darkness.
+               [ The Encyclopaedia of Myths and Legends of All
+                       Nations, by Herbert Spencer Robinson and
+                       Knox Wilson ]
+*mithril*
+       _Mithril_!  All folk desired it.  It could be beaten like
+       copper, and polished like glass; and the Dwarves could make
+       of it a metal, light and yet harder than tempered steel.
+       Its beauty was like to that of common silver, but the beauty
+       of _mithril_ did not tarnish or grow dim.
+               [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+*mitre of holiness
+       This helm of brilliance performs all of the normal functions
+       of a helm of brilliance, but also has the ability to protect
+       anyone who carries it from fire.  When invoked, it boosts
+       the energy of the invoker, allowing them to cast more spells.
+mjollnir
+       Forged by the dwarves Eitri and Brokk, in response to Loki's
+       challenge, Mjollnir is an indestructible war hammer.  It has
+       two magical properties:  when thrown it always returned to
+       Thor's hand; and it could be made to shrink in size until it
+       could fit inside Thor's shirt.  Its only flaw is that it has
+       a short handle.  The other gods judged Mjollnir the winner of
+       the contest because, of all the treasures created, it alone had
+       the power to protect them from the giants.  As the legends
+       surrounding Mjollnir grew, it began to take on the quality of
+       "vigja", or consecration.  Thor used it to consecrate births,
+       weddings, and even to raise his goats from the dead.  In the
+       Norse mythologies Mjollnir is considered to represent Thor's
+       governance over the entire cycle of life - fertility, birth,
+       destruction, and resurrection.
+~slime mold
+*mold
+       Mold, multicellular organism of the division Fungi, typified
+       by plant bodies composed of a network of cottony filaments.
+       The colors of molds are due to spores borne on the filaments.
+       Most molds are saprophytes.  Some species (e.g., penicillium)
+       are used in making cheese and antibiotics.
+               [ The Concise Columbia Encyclopedia ]
+mol?ch
+       And the Lord spake unto Moses, saying,
+       Again, thou shalt say to the children of Israel, Whosoever
+       he be of the children of Israel, or of the strangers that
+       sojourn in Israel, that giveth any of his seed unto Molech;
+       he shall surely be put to death: the people of the land shall
+       stone him with stones.
+       And I will set my face against that man, and will cut him off
+       from among his people; because he hath given of his seed unto
+       Molech, to defile my sanctuary, and to profane my holy name.
+       And if the people of the land do any ways hide their eyes
+       from the man, when he giveth of his seed unto Molech, and kill
+       him not:
+       Then I will set my face against that man, and against his
+       family, and will cut him off, and all that go a whoring after
+       him, to commit whoredom with Molech, from among their people.
+               [ Leviticus 20:1-5 ]
+monk
+* monk
+grand master
+master kaen
+       One day, an army general invited the Buddhist monk I-Hsiu
+       (literally, "One Rest") to his military head office for a
+       dinner.  I-Hsiu was not accustomed to wearing luxurious
+       clothings and so he just put on an old ordinary casual
+       robe to go to the military base.  To him, "form is void".
+
+       As he approached the base, two soldiers appeared before him
+       and shouted, "Where does this beggar came from?  Identify
+       yourself!  You do not have permission to be around here!"
+
+       "My name is I-Hsiu Dharma Master.  I am invited by your
+       general for a supper."
+
+       The two soldiers examined the monk closely and said, "You
+       liar.  How come my general invites such a shabby monk to
+       dinner?  He invites the very solemn venerable I-Hsiu to our
+       base for a great ceremony today, not you.  Now, get out!"
+
+       I-Hsiu was unable to convince the soldiers that he was
+       indeed the invited guest, so he returned to the temple
+       and changed to a very formal solemn ceremonial robe for
+       the dinner.  And as he returned to the military base, the
+       soldiers observed that he was such a great Buddhist monk,
+       let him in with honour.
+
+       At the dinner, I-Hsiu sat in front of the table full of
+       food but, instead of putting the food into his month, he
+       picked up the food with his chopsticks and put it into
+       his sleeves.  The general was curious, and whispered to
+       him, "This is very embarrassing.  Do you want to take
+       some food back to the temple?  I will order the cook to
+       prepare some take out orders for you."  "No" replied the
+       monk.  "When I came here, I was not allowed into the
+       base by your soldiers until I wear this ceremonial robe.
+       You do not invite me for a dinner.  You invite my robe.
+       Therefore, my robe is eating the food, not me."
+               [ Dining with a General - a Zen Buddhism Koan ]
+monkey
+       "Listen, man-cub," said the Bear, and his voice rumbled like
+       thunder on a hot night.  "I have taught thee all the Law of
+       the Jungle for all the peoples of the jungle--except the
+       Monkey-Folk who live in the trees.  They have no law.  They
+       are outcasts.  They have no speech of their own, but use the
+       stolen words which they overhear when they listen, and peep,
+       and wait up above in the branches.  Their way is not our way.
+       They are without leaders.  They have no remembrance.  They
+       boast and chatter and pretend that they are a great people
+       about to do great affairs in the jungle, but the falling of
+       a nut turns their minds to laughter and all is forgotten.
+       We of the jungle have no dealings with them.  We do not drink
+       where the monkeys drink; we do not go where the monkeys go;
+       we do not hunt where they hunt; we do not die where they die...."
+               [ The Jungle Book, by Rudyard Kipling ]
+mumak*
+       ... the Mumak of Harad was indeed a beast of vast bulk, and
+       the like of him does not walk now in Middle-Earth; his kin
+       that live still in latter days are but memories of his girth
+       and majesty.  On he came, ... his great legs like trees,
+       enormous sail-like ears spread out, long snout upraised like
+       a huge serpent about to strike, his small red eyes raging.
+       His upturned hornlike tusks ... dripped with blood.
+               [ The Two Towers, by J.R.R. Tolkien ]
+*mummy
+       But for an account of the manner in which the body was
+       bandaged, and a list of the unguents and other materials
+       employed in the process, and the words of power which were
+       spoken as each bandage was laid in its place, we must have
+       recourse to a very interesting papyrus which has been edited
+       and translated by M. Maspero under the title of Le Rituel de
+       l'Embaumement. ...
+       Everything that could be done to preserve the body was now
+       done, and every member of it was, by means of the words of
+       power which changed perishable substances into imperishable,
+       protected to all eternity; when the final covering of purple
+       or white linen had been fastened upon it, the body was ready
+       for the tomb.
+               [ Egyptian Magic, by E.A. Wallis Budge ]
+mummy wrapping
+       He held a white cloth -- it was a serviette he had brought
+       with him -- over the lower part of his face, so that his
+       mouth and jaws were completely hidden, and that was the
+       reason for his muffled voice.  But it was not that which
+       startled Mrs. Hall.  It was the fact that all his forehead
+       above his blue glasses was covered by a white bandage, and
+       that another covered his ears, leaving not a scrap of his
+       face exposed excepting only his pink, peaked nose.  It was
+       bright, pink, and shiny just as it had been at first.  He
+       wore a dark-brown velvet jacket with a high, black, linen-
+       lined collar turned up about his neck.  The thick black
+       hair, escaping as it could below and between the cross
+       bandages, project in curious tails and horns, giving him
+       the strangest appearance conceivable.
+               [ The Invisible Man, by H.G. Wells ]
+*naga*
+*naja*
+       The naga is a mystical creature with the body of a snake and
+       the head of a man or woman.  They will fiercely protect the
+       territory they consider their own.  Some nagas can be forced
+       to serve as guardians by a spellcaster of great power.
+naginata
+       A Japanese pole-arm, fitted with a curved single-edged blade.
+       The blades ranged in length from two to four feet, mounted on
+       shafts about four to five feet long.  The naginata were cut
+       with a series of short grooves near to the tang, above which
+       the back edge was thinned, but not sharpened, so that the
+       greater part of the blade was a flattened diamond shape in
+       section.  Seen in profile, the curve is slight or non-
+       existent near the tang, becoming more pronounced towards the
+       point.
+
+       "With his naginata he killed five, but with the sixth it
+       snapped asunder in the midst and, flinging it away, he drew
+       his sword, wielding it in the zigzag style, the interlacing,
+       cross, reversed dragonfly, waterwheel, and eight-sides-at-
+       once styles of fencing and cutting down eight men; but as he
+       brought down the ninth with a mighty blow on the helmet, the
+       blade snapped at the hilt."
+       [ Story of Tsutsui no Jomio Meishu from Tales of Heike ]
+nalfeshnee
+       Not only do these demons do physical damage with their claws
+       and bite, but they are capable of using magic as well.
+nalzok
+       Nalzok is Moloch's cunning and unfailingly loyal battle
+       lieutenant, to whom he trusts the command of warfare when he
+       does not wish to exercise it himself.  Nalzok is a major
+       demon, known to command the undead.  He is hungry for power,
+       and secretly covets Moloch's position.  Moloch doesn't trust
+       him, but, trusting his own power enough, chooses to allow
+       Nalzok his position because he is useful.
+neanderthal*
+       1.  Valley between Duesseldorf and Elberfeld in Germany,
+       where an ancient skull of a prehistoric ancestor to modern
+       man was found.  2.  Human(oid) of the race mentioned above.
+neferet
+neferet the green
+       Neferet the Green holds office in her hidden tower, only
+       reachable by magical means, where she teaches her apprentices
+       the enigmatic skills of occultism.  Despite her many years, she
+       continues to investigate new spells, especially those involving
+       translocation.  It is further rumored that when she was an
+       apprentice herself, she accidentally turned her skin green, and
+       has kept it that way ever since.
+newt
+       (kinds of) small animal, like a lizard, which spends most of
+       its time in the water.
+               [ Oxford's Student's Dictionary of Current English ]
+
+       "Fillet of a fenny snake,
+       In the cauldron boil and bake;
+       Eye of newt and toe of frog,
+       Wool of bat and tongue of dog,
+       Adder's fork and blind-worm's sting,
+       Lizard's leg and howlet's wing,
+       For a charm of powerful trouble,
+       Like a hell-broth boil and bubble."
+               [ Macbeth, by William Shakespeare ]
+ninja-to
+       A Japanese broadsword.
+*norn
+       The Norns were the three Norse Fates, or the goddesses of fate.
+       Female giants, they brought the wonderful Golden Age to an end.
+       They cast lots over the cradle of every child that was born,
+       and placed gifts in the cradle.  Their names were Urda,
+       Verdandi, and Skuld, representing the past, the present, and
+       the future.  Urda and Verdandi were kindly disposed, but Skuld
+       was cruel and savage.  Their tasks were to sew the web of
+       fate, to water the sacred ash, Yggdrasil, and to keep it in
+       good condition by placing fresh earth around it daily.  In her
+       fury, Skuld often spoiled the work of her sisters by tearing
+       the web to shreds.
+               [ The Encyclopedia of Myths and Legends of All
+                       Nations by Herbert Spencer Robinson and Knox
+                       Wilson ]
+nunchaku
+       A Japanese flail.
+*nymph
+       A female creature from Roman and Greek mythology, the nymph
+       occupied rivers, forests, ponds, etc.  A nymph's beauty is
+       beyond words:  an ever-young woman with sleek figure and
+       long, thick hair, radiant skin and perfect teeth, full lips
+       and gentle eyes.  A nymph's scent is delightful, and her
+       long robe glows, hemmed with golden threads and embroidered
+       with rainbow hues of unearthly magnificence.  A nymph's
+       demeanour is graceful and charming, her mind quick and witty.
+
+       "Theseus felt her voice pulling him down into fathoms of
+       sleep.  The song was the skeleton of his dream, and the dream
+       was full of terror.  Demon girls were after him, and a bull-
+       man was goring him.  Everywhere there was blood.  There was
+       pain.  There was fear.  But his head was in the nymph's lap
+       and her musk was about him, her voice weaving the dream.  He
+       knew then that she had been sent to tell him of something
+       dreadful that was to happen to him later.  Her song was a
+       warning.  But she had brought him a new kind of joy, one that
+       made him see everything differently.  The boy, who was to
+       become a hero, suddenly knew then what most heroes learn
+       later -- and some too late -- that joy blots suffering and
+       that the road to nymphs is beset by monsters."
+           [ The Minotaur by Bernard Evslin ]
+odin
+       Also called Sigtyr (god of Victory), Val-father (father of
+       the slain), One-Eyed, Hanga-god (god of the hanged), Farma-
+       god (god of cargoes), Hapta-god (god of prisoners), and
+       Othin.  He is the prime god of the Norsemen:  god of war and
+       victory, wisdom and prophecy, poetry, the dead, air and wind,
+       hospitality, and magic.
+       As the god of war and victory, Odin is ruler of the Valkyries,
+       warrior-maidens who lived in the halls of Valhalla in Asgard,
+       the hall of dead heroes where he held his court.
+       These chosen ones will defend the realm of the gods against
+       the Frost Giants on the final day of reckoning, Ragnarok.
+       As god of the wind, Odin rides through the air on his eight-
+       footed horse, Sleipnir, wielding Gungner, his spear, normally
+       accompanied by his ravens, Hugin and Munin, who he would also
+       use as his spies.
+       As a god of hospitality, he enjoys visiting the earth in
+       disguise to see how people were behaving and to see how they
+       would treat him, not knowing who he was.
+       Odin is usually represented as a one-eyed wise old man with a
+       long white beard and a wide-brimmed hat (he gave one of his
+       eyes to Mimir, the guardian of the well of wisdom in Hel, in
+       exchange for a draught of knowledge).
+ogre*
+       Anyone who has met a gluttonous, nude, angry ogre, will not
+       easily forget this encounter -- if he survives it at all.
+       Both male and female ogres can easily grow as tall as three
+       metres.  Build and facial expressions would remind one of a
+       Neanderthal.  Its small, pointy, keen teeth are striking.
+       Since ogres avoid direct sunlight, their ragged, unfurry
+       skin is as white as a sheet.  They enjoy coating their body
+       with lard and usually wear nothing but a loin-cloth.  An elf
+       would smell its rancid stench at ten metres distance.
+       Ogres are solitary creatures:  very rarely one may encounter
+       a female with two or three young.  They are the only real
+       carnivores among the humanoids, and its favourite meal is --
+       not surprisingly -- human flesh.  They sometimes ally with
+       orcs or goblins, but only when they anticipate a good meaty
+       meal.
+               [ het Boek van de Regels; Het Oog des Meesters ]
+oilskin cloak
+       During our watches below we overhauled our clothes, and made
+       and mended everything for bad weather.  Each of us had made
+       for himself a suit of oil-cloth or tarpaulin, and these we
+       got out, and gave thorough coatings of oil or tar, and hung
+       upon the stays to dry.  Our stout boots, too, we covered
+       over with a thick mixture of melted grease and tar.  Thus we
+       took advantage of the warm sun and fine weather of the
+       Pacific to prepare for its other face.
+               [ Two Years Before the Mast, by Richard Henry Dana ]
+oilskin sack
+       Summer passed all too quickly.  On the last day of camp, Mr.
+       Brickle called his counselors together and paid them what he
+       owed them.  Louis received one hundred dollars - the first
+       money he had ever earned.  He had no wallet and no pockets,
+       so Mr. Brickle placed the money in a waterproof bag that had
+       a drawstring.  He hung this moneybag around Louis' neck,
+       along with the trumpet, the slate, the chalk pencil, and the
+       lifesaving medal.
+               [ The Trumpet of the Swan, by E.B. White ]
+olog-hai
+       But at the end of the Third Age a troll-race not before seen
+       appeared in southern Mirkwood and in the mountain borders of
+       Mordor.  Olog-hai they were called in the Black Speech.  That
+       Sauron bred them none doubted, though from what stock was not
+       known.  Some held that they were not Trolls but giant Orcs;
+       but the Olog-hai were in fashion of body and mind quite unlike
+       even the largest of Orc-kind, whom they far surpassed in size
+       and power.  Trolls they were, but filled with the evil will
+       of their master:  a fell race, strong, agile, fierce and
+       cunning, but harder than stone.  Unlike the older race of the
+       Twilight they could endure the Sun....  They spoke little,
+       and the only tongue they knew was the Black Speech of Barad-dur.
+               [ The Return of the King, by J.R.R. Tolkien ]
+oracle
+delphi
+p*thia
+       Delphi under towering Parnassus, where Apollo's oracle was,
+       plays an important part in mythology.  Castalia was its
+       sacred spring; Cephissus its river.  It was held to be the
+       center of the world, so many pilgrims came to it, from
+       foreign countries as well as Greece.  No other shrine rivaled
+       it.  The answers to the questions asked by the anxious
+       seekers for Truth were delivered by a priestess who went into
+       a trance before she spoke.
+               [ Mythology, by Edith Hamilton ]
+orange
+pear
+       What was the fruit like?  Unfortunately, no one can describe
+       a taste.  All I can say is that, compared with those fruits,
+       the freshest grapefruit you've ever eaten was dull, and the
+       juiciest orange was dry, and the most melting pear was hard
+       and woody, and the sweetest wild strawberry was sour.  And
+       there were no seeds or stones, and no wasps.  If you had once
+       eaten that fruit, all the nicest things in this world would
+       taste like medicines after it.  But I can't describe it.  You
+       can't find out what it is like unless you can get to that
+       country and taste it for yourself.
+               [ The Last Battle, by C.S. Lewis ]
+pyrolisk
+       At first glance around the corner, I thought it was another 
+       cockatrice. I had encountered the wretched creatures two or
+       three times since leaving the open area. I quickly ducked my 
+       head back and considered what to do next. My heart had begun
+       to thump audibly as I patted my pack to make sure I still had 
+       the dead lizards at close reach. A check of my attire showed
+       no obvious holes or damage. I had to keep moving. One deep
+       breath, and a count of three, two, one, and around the corner 
+       I bolted. But it was no cockatrice! I felt a sudden intense 
+       searing of the skin around my face, and flames began to leap
+       from my pack. I tossed it to the ground, and quickly retreated
+       back, around that corner, desperately striving to get out of 
+       its sight.
+*orb of detection
+       This Orb is a crystal ball of exceptional powers.  When
+       carried, it grants ESP, limits damage done by spells, and
+       protects the carrier from magic missiles.  When invoked it
+       allows the carrier to become invisible.
+orb of fate
+       Some say that Odin himself created this ancient crystal ball,
+       although others argue that Loki created it and forged Odin's
+       signature on the bottom.  In any case, it is a powerful
+       artifact.  Anyone who carries it is granted the gift of
+       warning, and damage, both spell and physical, is partially
+       absorbed by the orb itself.  When invoked it has the power
+       to teleport the invoker between levels.
+goblin king
+orcrist
+       The Great Goblin gave a truly awful howl of rage when he
+       looked at it, and all his soldiers gnashed their teeth,
+       clashed their shields, and stamped.  They knew the sword at
+       once.  It had killed hundreds of goblins in its time, when
+       the fair elves of Gondolin hunted them in the hills or did
+       battle before their walls.  They had called it Orcrist,
+       Goblin-cleaver, but the goblins called it simply Biter.
+       They hated it and hated worse any one that carried it.
+               [ The Hobbit, by J.R.R. Tolkien ]
+orcus
+       Orcus, Prince of the Undead, has a ram's head and a poison
+       stinger.  He is most feared, though, for his powerful magic
+       abilities.  His wand causes death to those he chooses.
+~orc ??m*
+~orcish barbarian
+~orcish ranger
+~orcish rogue
+~orcish wizard
+orc*
+* orc
+uruk*hai
+       Orcs, bipeds with a humanoid appearance, are related to the
+       goblins, but much bigger and more dangerous.  The average orc
+       is only moderately intelligent, has broad, muscled shoulders,
+       a short neck, a sloping forehead and a thick, dark fur.
+       Their lower eye-teeth are pointing forward, like a boar's.
+       Female orcs are more lightly built and bare-chested.  Not
+       needing any clothing, they do like to dress in variegated
+       apparels.  Suspicious by nature, orcs live in tribes or
+       hordes.  They tend to live underground as well as above
+       ground (but they dislike sunlight).  Orcs can use all weapons,
+       tools and armours that are used by men.  Since they don't have
+       the talent to fashion these themselves, they are constantly
+       hunting for them.  There is nothing a horde of orcs cannot
+       use.
+               [ het Boek van de Regels; Het Oog des Meesters ]
+orion
+sirius
+       Orion was the son of Neptune. He was a handsome giant and a
+       mighty hunter. His father gave him the power of wading
+       through the depths of the sea, or, as others say, of
+       walking on its surface.
+
+       He dwelt as a hunter with Diana (Artemis), with whom he
+       was a favourite, and it is even said she was about to marry
+       him. Her brother was highly displeased and often chid her,
+       but to no purpose. One day, observing Orion wading through
+       the sea with his head just above the water, Apollo pointed
+       it out to his sister and maintained that she could not hit
+       that black thing on the sea. The archer-goddess discharged
+       a shaft with fatal aim. The waves rolled the dead body of
+       Orion to the land, and bewailing her fatal error with many
+       tears, Diana placed him among the stars, where he appears
+       as a giant, with a girdle, sword, lion's skin, and
+       club. Sirius, his dog, follows him, and the Pleiads fly
+       before him.
+               [ Bulfinch's Mythology, by Thomas Bulfinch ]
+osaku
+       The osaku is a small tool for picking locks.
+owlbear
+       Owlbears are probably the crossbreed creation of a demented
+       wizard; given the lethal nature of this creation, it is quite
+       likely the wizard who created them is no longer alive.  As
+       the name might already suggest, owlbears are a cross between
+       a giant owl and a bear.  They are covered with fur and
+       feathers.
+panther
+       And lo! almost where the ascent began,
+       A panther light and swift exceedingly,
+       Which with a spotted skin was covered o'er!
+
+       And never moved she from before my face,
+       Nay, rather did impede so much my way,
+       That many times I to return had turned.
+               [ Dante's Inferno, as translated
+                       by Henry Wadsworth Longfellow ]
+pelias
+       Conan cried out sharply and recoiled, thrusting his companion
+       back.  Before them rose the great shimmering white form of Satha,
+       an ageless hate in its eyes.  Conan tensed himself for one mad
+       berserker onslaught -- to thrust the glowing faggot into that
+       fiendish countenance and throw his life into the ripping sword-
+       stroke.  But the snake was not looking at him.  It was glaring
+       over his shoulder at the man called Pelias, who stood with his
+       arms folded, smiling.  And in the great, cold, yellow eyes
+       slowly the hate died out in a glitter of pure fear -- the only
+       time Conan ever saw such an expression in a reptile's eyes.
+       With a swirling rush like the sweep of a strong wind, the great
+       snake was gone.
+       "What did he see to frighten him?" asked Conan, eyeing his
+       companion uneasily.
+       "The scaled people see what escapes the mortal eye," answered
+       Pelias cryptically.  "You see my fleshy guise, he saw my naked
+       soul."
+           [ Conan the Usurper, by Robert E. Howard and L. Sprague de Camp ]
+pick*ax*
+       The mine is full of holes;
+       With the wound of pickaxes.
+       But look at the goldsmith's store.
+       There, there is gold everywhere.
+               [ Divan-i Kebir Meter 2, by Mevlana Celaleddin Rumi ]
+*piercer
+       Ye Piercer doth look like unto a stalactyte, and hangeth
+       from the roofs of caves and caverns.  Unto the height of a
+       man, and thicker than a man's thigh do they grow, and in
+       groups do they hang.  If a creature doth pass beneath them,
+       they will by its heat and noise perceive it, and fall upon
+       it to kill and devour it, though in any other way they move
+       but exceeding slow.
+               [ the Bestiary of Xygag ]
+piranha
+       They live in "schools." Many times they will wait for prey 
+       to come to the shallow water of the river. Then the large 
+       group of piranhas will attack. These large groups are able 
+       to kill large animals... Their lower teeth fit perfectly 
+       into the spaces of their upper teeth, creating a tremendous 
+       vice-like bite... Piranhas are attracted to any disturbance 
+       in the water. 
+               [ http://www.animalsoftherainforest.com ]
+pit
+spiked pit
+       Amid the thought of the fiery destruction that impended, the
+       idea of the coolness of the well came over my soul like balm.
+       I rushed to its deadly brink.  I threw my straining vision
+       below.  The glare from the enkindled roof illumined its inmost
+       recesses.  Yet, for a wild moment, did my spirit refuse to
+       comprehend the meaning of what I saw.  At length it forced --
+       it wrestled its way into my soul -- it burned itself in upon my
+       shuddering reason.  Oh! for a voice to speak! -- oh! horror! --
+       oh! any horror but this!
+               [ The Pit and the Pendulum, by Edgar Allan Poe ]
+pit fiend
+       Pit fiends are among the more powerful of devils, capable of
+       attacking twice with weapons as well as grabbing and crushing
+       the life out of those unwary enough to enter their
+       domains.
+platinum yendorian express card
+       This is an ancient artifact made of an unknown material.  It
+       is rectangular in shape, very thin, and inscribed with
+       unreadable ancient runes.  When carried, it grants the one
+       who carries it ESP, and reduces all spell induced damage done to
+       the carrier by half.  It also protects from magic missile
+       attacks.  Finally, its power is such that when invoked, it
+       can charge other objects.
+pony
+               Hey! now! Come hoy now! Whither do you wander?
+               Up, down, near or far, here, there or yonder?
+               Sharp-ears, Wise-nose, Swish-tail and Bumpkin,
+               White-socks my little lad, and old Fatty Lumpkin!
+
+       [...]
+       Tom called them one by one and they climbed over the brow and
+       stood in a line.  Then Tom bowed to the hobbits.
+
+       "Here are your ponies, now!" he said.  "They've more sense (in some
+       ways) than you wandering hobbits have -- more sense in their noses.
+       For they sniff danger ahead which you walk right into; and if they
+       run to save themselves, then they run the right way."
+               [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+*portal
+       Portals can be Mirrors, Pictures, Standing Stones, Stone
+       Circles, Windows, and special gates set up for the purpose.
+       You will travel through them both to distant parts of the
+       continent and to and from our own world.  The precise manner
+       of their working is a Management secret.
+       [ The Tough Guide to Fantasyland, by Diana Wynne Jones ]
+poseido*n
+       Poseido(o)n, lord of the seas and father of rivers and
+       fountains, was the son of Chronos and Rhea, brother of Zeus,
+       Hades, Hera, Hestia and Demeter.  His rank of ruler of the
+       waves he received by lot at the Council Meeting of the Gods,
+       at which Zeus took the upper world for himself and gave
+       dominion over the lower world to Hades.
+       Poseidon is associated in many ways with horses and thus is
+       the god of horses.  He taught men how to ride and manage the
+       animal he invented and is looked upon as the originator and
+       guardian deity of horse races.
+       His symbol is the familiar trident or three-pronged spear
+       with which he can split rocks, cause or quell storms, and
+       shake the earth, a power which makes him the god of
+       earthquakes as well.  Physically, he is shown as a strong and
+       powerful ruler, every inch a king.
+               [ The Encyclopedia of Myths and Legends of All
+                 Nations, by Herbert Robinson and Knox Wilson ]
+*potion*
+       POTABLE, n.  Suitable for drinking.  Water is said to be
+       potable; indeed, some declare it our natural beverage,
+       although even they find it palatable only when suffering
+       from the recurrent disorder known as thirst, for which it
+       is a medicine.  Upon nothing has so great and diligent
+       ingenuity been brought to bear in all ages and in all
+       countries, except the most uncivilized, as upon the
+       invention of substitutes for water.  To hold that this
+       general aversion to that liquid has no basis in the
+       preservative instinct of the race is to be unscientific --
+       and without science we are as the snakes and toads.
+               [ The Devil's Dictionary, by Ambrose Bierce ]
+priest*
+* priest*
+acolyte
+       [...]  For the two priests were talking exactly like priests,
+       piously, with learning and leisure, about the most aerial
+       enigmas of theology.  The little Essex priest spoke the more
+       simply, with his round face turned to the strengthening stars;
+       the other talked with his head bowed, as if he were not even
+       worthy to look at them.  But no more innocently clerical
+       conversation could have been heard in any white Italian cloister
+       or black Spanish cathedral.  The first he heard was the tail of
+       one of Father Brown's sentences, which ended:  "... what they
+       really meant in the Middle Ages by the heavens being
+       incorruptible."  The taller priest nodded his bowed head and
+       said:  "Ah, yes, these modern infidels appeal to their reason;
+       but who can look at those millions of worlds and not feel that
+       there may well be wonderful universes above us where reason is
+       utterly unreasonable?"
+               [ The Innocence of Father Brown, by G.K. Chesterton ]
+prisoner
+       Where am I?
+               In the Village.
+       What do you want?
+               Information.
+       Whose side are you on?
+               That would be telling.  We want information ...
+               information ...
+       You won't get it.
+               By hook or by crook, we will.
+       Who are you?
+               The new Number 2.
+       Who is Number 1?
+               You are Number 6.
+       I am not a number!  I am a free man! 
+               [ The Prisoner, by Patrick McGoohan ]
+ptah
+       Known under various names (Nu, Neph, Cenubis, Amen-Kneph,
+       Khery-Bakef), Ptah is the creator god and god of craftsmen.
+       He is usually depicted as wearing a closely fitting robe
+       with only his hands free.  His most distinctive features are
+       the invariable skull-cap exposing only his face and ears,
+       and the _was_ or rod of domination which he holds,
+       consisting of a staff surmounted by the _ankh_ symbol of
+       life.  He is otherwise symbolized by his sacred animal, the
+       bull.
+*purple worm
+       A gargantuan version of the harmless rain-worm, the purple
+       worm poses a huge threat to the ordinary adventurer.  It is
+       known to swallow whole and digest its victims within only a
+       few minutes.  These worms are always on guard, sensitive
+       to the most minute vibrations in the earth, but may also
+       be awakened by a remote shriek.
+quadruped
+       The woodlands and other regions are inhabited by multitudes
+       of four-legged creatures which cannot be simply classified.
+       They might not have fiery breath or deadly stings, but
+       adventurers have nevertheless met their end numerous times
+       due to the claws, hooves, or bites of such animals.
+quantum mechanic
+       These creatures are not native to this universe; they seem
+       to have strangely derived powers, and unknown motives.
+quasit
+       Quasits are small, evil creatures, related to imps.  Their
+       talons release a very toxic poison when used in an attack.
+quest
+       Many, possibly most, Tours are organized as a Quest.  This
+       is like a large-scale treasure hunt, with clues scattered
+       all over the continent, a few false leads, Mystical Masters
+       as game-show hosts, and the Dark Lord and the Terrain to
+       make the Quest interestingly difficult.  [...]
+       In order to be assured of your future custom, the Management
+       has a further Rule:  Tourists, far from being rewarded for
+       achieving their Quest Object, must then go on to conquer
+       the Dark Lord or set about Saving the World, or both.  And
+       why not?  By then you will have had a lot of practice in
+       that sort of thing and, besides, the Quest Object is usually
+       designed to help you do it.
+       [ The Tough Guide to Fantasyland, by Diana Wynne Jones ]
+quetzalcoatl
+       One of the principal Aztec-Toltec gods was the great and wise
+       Quetzalcoatl, who was called Kukumatz in Guatemala, and
+       Kukulcan in Yucatan.  His image, the plumed serpent, is found
+       on both the oldest and the most recent Indian edifices. ...
+       The legend tells how the Indian deity Quetzalcoatl came from
+       the "Land of the Rising Sun".  He wore a long white robe and
+       had a beard; he taught the people crafts and customs and laid
+       down wise laws.  He created an empire in which the ears of
+       corn were as long as men are tall, and caused bolls of colored
+       cotton to grow on cotton plants.  But for some reason or other
+       he had to leave his empire. ...  But all the legends of
+       Quetzalcoatl unanimously agree that he promised to come again.
+               [ Gods, Graves, and Scholars, by C. W. Ceram ]
+quit*
+       Maltar: [...]  I remembered a little saying I learned my first
+       day at the academy.
+       Natalie: Yeah, yeah, I know.  Winners never quit and quitters
+       never win.
+       Maltar: What?  No!  Winners never quit and quitters should be
+       cast into the flaming pit of death.
+               [ Snow Day, directed by Chris Koch,
+                 written by Will McRobb and Chris Viscardi ]
+raijin
+raiden
+       The god of thunder.
+ranger
+* ranger
+       "Lonely men are we, Rangers of the wild, hunters -- but hunters
+       ever of the servants of the Enemy; for they are found in many
+       places, not in Mordor only.
+       If Gondor, Boromir, has been a stalwart tower, we have played
+       another part.  Many evil things there are that your strong walls
+       and bright swords do not stay.  You know little of the lands
+       beyond your bounds.  Peace and freedom, do you say?  The North
+       would have known them little but for us.  Fear would have
+       destroyed them.  But when dark things come from the houseless
+       hills, or creep from sunless woods, they fly from us.  What
+       roads would any dare to tread, what safety would there be in
+       quiet lands, or in the homes of simple men at night, if the
+       Dunedain were asleep, or were all gone into the grave?"
+               [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+rat
+* rat
+       Rats are long-tailed rodents.  They are aggressive,
+       omnivorous, and adaptable, often carrying diseases.
+
+       "The rat," said O'Brien, still addressing his invisible
+       audience, "although a rodent, is carnivorous.  You are aware
+       of that.  You will have heard of the things that happen in
+       the poor quarters of this town.  In some streets a woman dare
+       not leave her baby alone in the house, even for five minutes.
+       The rats are certain to attack it.  Within quite a small time
+       they will strip it to the bones.  They also attack sick or
+       dying people.  They show astonishing intelligence in knowing
+       when a human being is helpless."
+               [ 1984, by George Orwell ]
+raven
+       But the raven, sitting lonely on the placid bust, spoke only
+       That one word, as if his soul in that one word he did outpour.
+       Nothing further then he uttered -- not a feather then he fluttered--
+       Till I scarcely more than muttered, 'other friends have flown before--
+       On the morrow *he* will leave me, as my hopes have flown before.'
+               Then the bird said, 'Nevermore.'
+                               [ The Raven - Edgar Allan Poe ]
+*ring
+ring of *
+       Three Rings for the Elven-kings under the sky,
+       Seven for the Dwarf-lords in their halls of stone,
+       Nine for Mortal Men doomed to die,
+       One for the Dark Lord on his dark throne,
+       In the Land of Mordor where the Shadows lie.
+       One Ring to rule them all, One Ring to find them,
+       One Ring to bring them all and in the darkness bind them
+       In the Land of Mordor where the Shadows lie.
+               [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+robe
+       Robes are the only garments, apart from Shirts, ever to have
+       sleeves.  They have three uses:
+       1.  As the official uniform of Priests, Priestesses, Monks,
+       Nuns (see Nunnery), and Wizards.  The OMT [ Official Management
+       Term ] prescribed for the Robes of Priests and Nuns is that
+       they _fall in severe folds_; of Priestesses that they _float_;
+       and of Wizards that they _swirl_.  You can thus see who you
+       are dealing with.
+       2.  For Kings.  The OMT here is _falling in stately folds_.
+       3.  As the garb of Desert Nomads.  [...]
+       [ The Tough Guide to Fantasyland, by Diana Wynne Jones ]
+rock
+       Bilbo saw that the moment had come when he must do something.
+       He could not get up at the brutes and he had nothing to shoot
+       with; but looking about he saw that in this place there were
+       many stones lying in what appeared to be a now dry little
+       watercourse.  Bilbo was a pretty fair shot with a stone, and
+       it did not take him long to find a nice smooth egg-shaped one
+       that fitted his hand cosily.  As a boy he used to practise
+       throwing stones at things, until rabbits and squirrels, and
+       even birds, got out of his way as quick as lightning if they
+       saw him stoop; and even grownup he had still spent a deal of
+       his time at quoits, dart-throwing, shooting at the wand,
+       bowls, ninepins and other quiet games of the aiming and
+       throwing sort - indeed he could do lots of things, besides
+       blowing smoke-rings, asking riddles and cooking, that I
+       haven't time to tell you about.  There is no time now.  While
+       he was picking up stones, the spider had reached Bombur, and
+       soon he would have been dead.  At that moment Bilbo threw.
+       The stone struck the spider plunk on the head, and it dropped
+       senseless off the tree, flop to the ground, with all its legs
+       curled up.
+               [ The Hobbit, by J.R.R. Tolkien ]
+rock mole
+       A rock mole is a member of the rodent family.  They get their
+       name from their ability to tunnel through rock in the same
+       fashion that a mole tunnels through earth.  They are known to
+       eat anything they come across in their diggings, although it
+       is still unknown how they convert some of these things into
+       something of nutritional value.
+rogue
+* rogue
+       I understand the business, I hear it: to have an open ear, a
+       quick eye, and a nimble hand, is necessary for a cut-purse; a
+       good nose is requisite also, to smell out work for the other
+       senses.  I see this is the time that the unjust man doth
+       thrive. <...> The prince himself is about a piece of iniquity,
+       stealing away from his father with his clog at his heels:  if
+       I thought it were a piece of honesty to acquaint the king
+       withal, I would not do't:  I hold it the more knavery to
+       conceal it; and therein am I constant to my profession.
+               [ Autolycus the Rogue, from The Winter's Tale by
+                       William Shakespeare ]
+rothe
+       The rothe (pronounced roth-AY) is a musk ox-like creature with
+       an aversion to light.  It prefers to live underground near
+       lichen and moss.
+*royal jelly
+       "'Royal Jelly,'" he read aloud, "'must be a substance of
+       tremendous nourishing power, for on this diet alone, the
+       honey-bee larva increases in weight fifteen hundred times in
+       five days!'"
+
+       "How much?"
+
+       "Fifteen hundred times, Mabel.  And you know what that means
+       if you put it in terms of a human being?  It means," he said,
+       lowering his voice, leaning forward, fixing her with those
+       small pale eyes, "it means that in five days a baby weighing
+       seven and a half pounds to start off with would increase in
+       weight to five tons!"
+               [ Royal Jelly, by Roald Dahl ]
+rust monster
+       These strange creatures live on a diet of metals.  They can
+       turn a suit of armour into so much useless rusted scrap in no
+       time at all.
+*saber
+*sabre
+       Flashed all their sabres bare,
+       Flashed as they turned in air,
+       Sab'ring the gunners there,
+       Charging an army, while
+       All the world wondered:
+       Plunged in the battery smoke,
+       Right through the line they broke;
+       Cossack and Russian
+       Reeled from the sabre-stroke
+       Shattered and sundered.
+       Then they rode back, but not--
+       Not the six hundred.
+               [ The Charge of the Light Brigade,
+                 by Alfred, Lord Tennyson ]
+saddle
+       The horseman serves the horse,
+       The neat-herd serves the neat,
+       The merchant serves the purse,
+       The eater serves his meat;
+       'Tis the day of the chattel,
+       Web to weave, and corn to grind,
+       Things are in the saddle,
+       And ride mankind.
+               [ Ode, by Ralph Waldo Emerson ]
+sake
+       Japanese rice wine.
+salamander
+       For hundreds of years, many people believed that salamanders
+       were magical.  In England in the Middle Ages, people thought
+       that fire created salamanders.  When they set fire to damp
+       logs, dozens of the slimy creatures scurried out.  The word
+       salamander, in fact, comes from a Greek word meaning "fire
+       animal".
+               [ Salamanders, by Cherie Winner ]
+samurai
+* samurai
+       By that time, Narahara had already slipped his arm from the
+       sleeve of his outer robe, drew out his two-and-a-half-foot
+       Fujiwara Tadahiro sword, and, brandishing it over his head,
+       began barreling toward the foreigners.  In less than a minute,
+       he had charged upon them and cut one of them through the torso.
+       The man fled, clutching his bulging guts, finally to fall from
+       his horse at the foot of a pine tree about a thousand yards
+       away.  Kaeda Takeji finished him off.  The other two Englishmen
+       were severely wounded as they tried to flee.  Only the woman
+       managed to escape virtually unscathed.
+               [ The Fox-horse, from Drunk as a Lord, by Ryotaro Shiba ]
+sandestin
+       Ildefonse left the terrace and almost immediately sounds
+       of contention came from the direction of the work-room.
+       Ildefonse presently returned to the terrace, followed by
+       Osherl and a second sandestin using the guise of a gaunt blue
+       bird-like creature, some six feet in height.
+
+       Ildefonse spoke in scathing tones:  "Behold these two
+       creatures!  They can roam the chronoplex as easily as you
+       or I can walk around the table; yet neither has the wit to
+       announce his presence upon arrival.  I found Osherl asleep
+       in his fulgurite and Sarsem perched in the rafters."
+               [...]
+       "No matter," said Rhialto.  "He has brought Sarsem, and this
+       was his requirement.  In the main, Osherl, you have done well!"
+
+       "And my indenture point?"
+
+       "Much depends upon Sarsem's testimony.  Sarsem, will you sit?"
+
+       "In this guise, I find it more convenient to stand."
+
+       "Then why not alter to human form and join us in comfort at
+       the table?"
+
+       "That is a good idea."  Sarsem became a naked young epicene
+       in an integument of lavender scales with puffs of purple hair
+       like pom-poms growing down his back.  He seated himself at
+       the table but declined refreshment.  "This human semblance,
+       though typical, is after all, only a guise.  If I were to put
+       such things inside myself, I might well become uneasy."
+               [ Rhialto the Marvellous, by Jack Vance ]
+sasquatch
+       The name _Sasquatch_ doesn't really become important in Canada
+       until the 1930s, when it appeared in the works of J. W. Burns,
+       a British Columbian writer who used a great deal of Indian
+       lore in his stories.  Burn's Sasquatch was a giant Indian who
+       lived in the wilderness.  He was hairy only in the sense that
+       he had long hair on his head, and while this Sasquatch lived a
+       wild and primitive life, he was fully human.
+       Burns's character proved to be quite popular.  There was a
+       Sasquatch Inn near the town of Harrison, British Columbia, and
+       Harrison even had a local celebration called "Sasquatch Days."
+       The celebration which had been dormant for years was revived
+       as part of British Columbia's centennial, and one of the
+       events was to be a Sasquatch hunt.  The hunt never took place,
+       perhaps it was never supposed to, but the publicity about it
+       did bring out a number of people who said they had encountered
+       a Sasquatch -- not Burns's giant Indian, but the hairy apelike
+       creature that we have all come to know.
+               [ The Encyclopedia of Monsters, by Daniel Cohen ]
+*sceptre of might
+       This mace was created aeons ago in some unknown cave,
+       and has been passed down from generation to generation of
+       cave dwellers.  It is a very mighty mace indeed, and in
+       addition will protect anyone who carries it from magic
+       missile attacks.  When invoked, it causes conflict in the
+       area around it.
+scimitar
+       Oh, how handsome, how noble was the Vizier Ali Tebelin,
+       my father, as he stood there in the midst of the shot, his
+       scimitar in his hand, his face black with powder!  How his
+       enemies fled before him!
+               [ The Count of Monte Cristo, by Alexandre Dumas ]
+scorpio*
+       A sub-species of the spider (_Scorpionidae_), the scorpion
+       distinguishes itself from them by having a lower body that
+       ends in a long, jointed tail tapering to a poisonous stinger.
+       They have eight legs and pincers.
+               [ Van Dale's Groot Woordenboek der Nederlandse Taal ]
+scorpius
+       Since early times, the Scorpion has represented death, darkness,
+       and evil.  Scorpius is the reputed slayer of Orion the Hunter.
+       [...]  The gods put both scorpion and hunter among the stars, but
+       on opposite sides of the sky so they would never fight again.
+       As Scorpius rises in the east, Orion sets in the west.
+               [ 365 Starry Nights, by Chet Raymo ]
+*scroll
+scroll *
+       And I was gazing on the surges prone,
+       With many a scalding tear and many a groan,
+       When at my feet emerg'd an old man's hand,
+       Grasping this scroll, and this same slender wand.
+       I knelt with pain--reached out my hand--had grasp'd
+       Those treasures--touch'd the knuckles--they unclasp'd--
+       I caught a finger: but the downward weight
+       O'erpowered me--it sank. Then 'gan abate
+       The storm, and through chill aguish gloom outburst
+       The comfortable sun. I was athirst
+       To search the book, and in the warming air
+       Parted its dripping leaves with eager care.
+       Strange matters did it treat of, and drew on
+       My soul page after page, till well-nigh won
+       Into forgetfulness; when, stupefied,
+       I read these words, and read again, and tried
+       My eyes against the heavens, and read again.
+               [ Endymion, by John Keats ]
+shad*
+       Shades are undead creatures.  They differ from zombies in
+       that a zombie is an undead animation of a corpse, while a
+       shade is an undead creature magically created by the use
+       of black magic.
+shaman karnov
+       Making his quarters in the Caves of the Ancestors, Shaman
+       Karnov unceasingly tries to shield his neanderthal people
+       from Tiamat's minions' harassments.
+shan*lai*ching
+       The Chinese god of Mountains and Seas, also the name of an
+       old book (also Shan Hai Tjing), the book of mountains and
+       seas - which deals with the monster Kung Kung trying to
+       seize power from Yao, the fourth emperor.
+               [ Spectrum Atlas van de Mythologie ]
+shark
+       As the shark moved, its dark top reflected virtually no
+       light.  The denticles on its skin muted the whoosh of its
+       movements as the shark rose, driven by the power of the
+       great tail sweeping from side to side, like a scythe.  
+       The fish exploded upward.
+       Charles Bruder felt a slight vacuum tug in the motion of
+       the sea, noted it as a passing current, the pull of a wave,
+       the tickle of undertow.  He could not have heard the faint
+       sucking rush of water not far beneath him.  He couldn't
+       have seen or heard what was hurtling from the murk at
+       astonishing speed, jaws unhinging, widening, for the
+       enormous first bite.  It was the classic attack
+       that no other creature in nature could make -- a bomb from
+       the depths.
+               [ Close to Shore, by Michael Capuzzo ]
+shito
+       A Japanese stabbing knife.
+shrieker
+       With a single, savage thrust of her spear, the warrior-woman 
+       impaled the fungus, silencing it.  However, it was too late:  
+       the alarm had been raised[...]
+       Suddenly, a large, dark shape rose from the abyss before them, 
+       its fetid bulk looming overhead...The monster was some kind of
+       great dark worm, but that was about all they were sure of.  
+               [ The Adventurers, Epic IV, by Thomas A. Miller ]
+skeleton
+       A skeleton is a magically animated undead creature.  Unlike
+       shades, only a humanoid creature can be used to create a
+       skeleton.  No one knows why this is true, but it has become
+       an accepted fact amongst the practitioners of the black arts.
+slasher
+       "That dog belonged to a settler who tried to build his cabin
+       on the bank of the river a few miles south of the fort,"
+       grunted Conan. ...  "We took him to the fort and dressed his
+       wounds, but after he recovered he took to the woods and turned
+       wild.  -- What now, Slasher, are you hunting the men who
+       killed your master?" ...  "Let him come," muttered Conan.
+       "He can smell the devils before we can see them." ...
+       Slasher cleared the timbers with a bound and leaped into the
+       bushes.  They were violently shaken and then the dog slunk
+       back to Balthus' side, his jaws crimson. ...  "He was a man,"
+       said Conan.  "I drink to his shade, and to the shade of the
+       dog, who knew no fear."  He quaffed part of the wine, then
+       emptied the rest upon the floor, with a curious heathen
+       gesture, and smashed the goblet.  "The heads of ten Picts
+       shall pay for this, and seven heads for the dog, who was a
+       better warrior than many a man."
+               [ Conan The Warrior, by Robert E Howard ]
+slime mold
+       Slime mold or slime fungus, organism usually classified with
+       the fungi, but showing equal affinity to the protozoa.  Slime
+       molds have complex life cycles with an animal-like motile
+       phase, in which feeding and growth occur, and a plant-like
+       immotile reproductive phase.  The motile phase, commonly
+       found under rotting logs and damp leaves, consists of either
+       solitary amoebalike cells or a brightly colored multinucleate
+       mass of protoplasm called a plasmodium, which creeps about
+       and feeds by amoeboid movement.
+               [ The Concise Columbia Encyclopedia ]
+sling
+       And it came to pass, when the Philistine arose, and came and
+       drew nigh to meet David, that David hasted, and ran toward
+       the army to meet the Philistine.
+       And David put his hand in his bag, and took thence a stone,
+       and slang it, and smote the Philistine in his forehead, that
+       the stone sunk into his forehead; and he fell upon his face
+       to the earth.
+       So David prevailed over the Philistine with a sling and with
+       a stone, and smote the Philistine, and slew him; but there
+       was no sword in the hand of David.
+               [ 1 Samuel 17:48-50 ]
+*snake
+serpent
+water moccasin
+python
+pit viper
+       Now the serpent was more subtle than any beast of the field
+       which the Lord God had made.  And he said unto the woman, Yea,
+       hath God said, Ye shall not eat of every tree of the garden?
+       And the woman said unto the serpent, We may eat of the fruit of
+       the trees of the garden:  but of the fruit of the tree which is
+       in the midst of the garden, God hath said, Ye shall not eat of
+       it, neither shall ye touch it, lest ye die.  And the serpent
+       said unto the woman, Ye shall not surely die:  for God doth
+       know that in the day ye eat thereof, then your eyes shall be
+       opened, and ye shall be as gods, knowing good and evil.  And
+       when the woman saw that the tree was good for food, and that it
+       was pleasant to the eyes, and a tree to be desired to make one
+       wise, she took of the fruit thereof, and did eat, and gave also
+       unto her husband with her; and he did eat.
+
+       And the Lord God said unto the woman, What is this that thou
+       hast done?  And the woman said, The serpent beguiled me, and I
+       did eat.  And the Lord God said unto the serpent, Because thou
+       hast done this, thou art cursed above all cattle, and above
+       every beast of the field; upon thy belly shalt thou go, and
+       dust shalt thou eat all the days of thy life:  And I will put
+       enmity between thee and the woman, and between thy seed and her
+       seed; it shall bruise thy head, and thou shalt bruise his heel.
+               [ Genesis 3:1-6,13-15 ]
+snickersnee
+       Ah, never shall I forget the cry,
+           or the shriek that shrieked he,
+       As I gnashed my teeth, and from my sheath
+           I drew my Snickersnee!
+       --Koko, Lord high executioner of Titipu
+               [ The Mikado, by Sir W.S. Gilbert ]
+sokoban
+       Sokoban (Japanese for "warehouse person") is a puzzle-type
+       game where the player must push around treasure to a goal
+       area.  It apparently won first prize in a Japanese programming
+       contest.
+               [ Xsokoban web site ]
+*soldier
+sergeant
+lieutenant
+captain
+       The soldiers of Yendor are well-trained in the art of war,
+       many trained by the Wizard himself.  Some say the soldiers
+       are explorers who were unfortunate enough to be captured,
+       and put under the Wizard's spell.  Those who have survived
+       encounters with soldiers say they travel together in platoons,
+       and are fierce fighters.  Because of the load of their combat
+       gear, however, one can usually run away from them, and doing
+       so is considered a wise thing.
+*spear
+javelin
+       - they come together with great random, and a spear is brast,
+       and one party brake his shield and the other one goes down,
+       horse and man, over his horse-tail and brake his neck, and
+       then the next candidate comes randoming in, and brast his
+       spear, and the other man brast his shield, and down he goes,
+       horse and man, over his horse-tail, and brake his neck, and
+       then there's another elected, and another and another and
+       still another, till the material is all used up; and when you
+       come to figure up results, you can't tell one fight from
+       another, nor who whipped; and as a picture of living, raging,
+       roaring battle, sho! why it's pale and noiseless - just
+       ghosts scuffling in a fog.  Dear me, what would this barren
+       vocabulary get out of the mightiest spectacle? - the burning
+       of Rome in Nero's time, for instance?  Why, it would merely
+       say 'Town burned down; no insurance; boy brast a window,
+       fireman brake his neck!'  Why, that ain't a picture!
+               [ A Connecticut Yankee in King Arthur's Court, by Mark
+                 Twain ]
+*spellbook*
+       The Book of Three lay closed on the table.  Taran had never
+       been allowed to read the volume for himself; now he was sure
+       it held more than Dallben chose to tell him.  In the sun-
+       filled room, with Dallben still meditating and showing no
+       sign of stopping, Taran rose and moved through the shimmering
+       beams.  From the forest came the monotonous tick of a beetle.
+       His hands reached for the cover.  Taran gasped in pain and
+       snatched them away.  They smarted as if each of his fingers
+       had been stung by hornets.  He jumped back, stumbled against
+       the bench, and dropped to the floor, where he put his fingers
+       woefully into his mouth.
+       Dallben's eyes blinked open.  He peered at Taran and yawned
+       slowly.  "You had better see Coll about a lotion for those
+       hands," he advised.  "Otherwise, I shouldn't be surprised if
+       they blistered."
+               [ The Book of Three, by Lloyd Alexander ]
+*spider
+       Eight legged creature capable of spinning webs to trap prey.
+
+       "You mean you eat flies?" gasped Wilbur.
+       "Certainly.  Flies, bugs, grasshoppers, choice beetles,
+       moths, butterflies, tasty cockroaches, gnats, midges, daddy
+       longlegs, centipedes, mosquitoes, crickets - anything that is
+       careless enough to get caught in my web.  I have to live,
+       don't I?"
+       "Why, yes, of course," said Wilbur.
+               [ Charlotte's Web, by E.B. White ]
+*spore
+*sphere
+       The attack by those who want to die -- this is the attack
+       against which you cannot prepare a perfect defense.
+                                       --Human aphorism
+               [ The Dosadi Experiment, by Frank Herbert ]
+~*aesculapius
+*staff
+       So they stood, each in his place, neither moving a finger's
+       breadth back, for one good hour, and many blows were given
+       and received by each in that time, till here and there were
+       sore bones and bumps, yet neither thought of crying "Enough,"
+       or seemed likely to fall from off the bridge.  Now and then
+       they stopped to rest, and each thought that he never had seen
+       in all his life before such a hand at quarterstaff.  At last
+       Robin gave the stranger a blow upon the ribs that made his
+       jacket smoke like a damp straw thatch in the sun.  So shrewd
+       was the stroke that the stranger came within a hair's breadth
+       of falling off the bridge; but he regained himself right
+       quickly, and, by a dexterous blow, gave Robin a crack on the
+       crown that caused the blood to flow.  Then Robin grew mad
+       with anger, and smote with all his might at the other; but
+       the stranger warded the blow, and once again thwacked Robin,
+       and this time so fairly that he fell heels over head into the
+       water, as the queen pin falls in a game of bowls.
+               [ The Merry Adventures of Robin Hood, by Howard Pyle ]
+*staff of aesculapius
+       This staff is considered sacred to all healers, as it truly
+       holds the powers of life and death.  When wielded, it
+       protects its user from all life draining attacks, and
+       additionally gives the wielder the power of regeneration.
+       When invoked it performs healing magic.
+stair*
+       Up he went -- very quickly at first -- then more slowly -- then
+       in a little while even more slowly than that -- and finally,
+       after many minutes of climbing up the endless stairway, one
+       weary foot was barely able to follow the other.  Milo suddenly
+       realized that with all his effort he was no closer to the top
+       than when he began, and not a great deal further from the
+       bottom.  But he struggled on for a while longer, until at last,
+       completely exhausted, he collapsed onto one of the steps.
+       "I should have known it," he mumbled, resting his tired legs
+       and filling his lungs with air.  "This is just like the line
+       that goes on forever, and I'll never get there."
+       "You wouldn't like it much anyway," someone replied gently.
+       "Infinity is a dreadfully poor place.  They can never manage to
+       make ends meet."
+               [ The Phantom Tollbooth, by Norton Juster ]
+
+       Dr. Ray Stantz: Hey, where do those stairs go?
+       Dr. Peter Venkman: They go up.
+               [ Ghostbusters, directed by Ivan Reitman,
+                 written by Dan Ackroyd and Harold Ramis ]
+~statue trap
+statue*
+       Then at last he began to wonder why the lion was standing so
+       still - for it hadn't moved one inch since he first set eyes
+       on it.  Edmund now ventured a little nearer, still keeping in
+       the shadow of the arch as much as he could.  He now saw from
+       the way the lion was standing that it couldn't have been
+       looking at him at all.  ("But supposing it turns its head?"
+       thought Edmund.)  In fact it was staring at something else -
+       namely a little dwarf who stood with his back to it about
+       four feet away.  "Aha!" thought Edmund.  "When it springs at
+       the dwarf then will be my chance to escape."  But still the
+       lion never moved, nor did the dwarf.  And now at last Edmund
+       remembered what the others had said about the White Witch
+       turning people into stone.  Perhaps this was only a stone
+       lion.  And as soon as he had thought of that he noticed that
+       the lion's back and the top of its head were covered with
+       snow.  Of course it must be only a statue!
+               [ The Lion, the Witch and the Wardrobe by C.S. Lewis ]
+sting
+       There was the usual dim grey light of the forest-day about
+       him when he came to his senses.  The spider lay dead beside
+       him, and his sword-blade was stained black.  Somehow the
+       killing of the giant spider, all alone and by himself in the
+       dark without the help of the wizard or the dwarves or of
+       anyone else, made a great difference to Mr. Baggins.  He felt
+       a different person, and much fiercer and bolder in spite of
+       an empty stomach, as he wiped his sword on the grass and put
+       it back into its sheath.
+       "I will give you a name," he said to it, "and I shall call
+       you Sting."
+               [ The Hobbit, by J.R.R. Tolkien ]
+stormbringer
+       There were sounds in the distance, incongruent with the
+       sounds of even this nameless, timeless sea: thin sounds,
+       agonized and terrible, for all that they remained remote -
+       yet the ship followed them, as if drawn by them; they grew
+       louder - pain and despair were there, but terror was
+       predominant.
+       Elric had heard such sounds echoing from his cousin Yyrkoon's
+       sardonically named 'Pleasure Chambers' in the days before he
+       had fled the responsibilities of ruling all that remained of
+       the old Melnibonean Empire.  These were the voices of men
+       whose very souls were under siege; men to whom death meant
+       not mere extinction, but a continuation of existence, forever
+       in thrall to some cruel and supernatural master.  He had
+       heard men cry so when his salvation and his nemesis, his
+       great black battle-blade Stormbringer, drank their souls.
+               [ The Lands Beyond the World, by Michael Moorcock ]
+susano*o
+       The Shinto chthonic and weather god and brother of the sun
+       goddess Amaterasu, he was born from the nose of the
+       primordial creator god Izanagi and represents the physical,
+       material world.  He has been expelled from heaven and taken
+       up residence on earth.
+               [ Encyclopedia of Gods, by Michael Jordan ]
+tanko
+       Samurai plate armor of the Yamato period (AD 300 - 710).
+tengu
+       The tengu was the most troublesome creature of Japanese
+       legend.  Part bird and part man, with red beak for a nose
+       and flashing eyes, the tengu was notorious for stirring up
+       feuds and prolonging enmity between families.  Indeed, the
+       belligerent tengu were supposed to have been man's first
+       instructors in the use of arms.
+       [ Mythical Beasts, by Deirdre Headon (The Leprechaun Library) ]
+thoth
+       The Egyptian god of the moon and wisdom, Thoth is the patron
+       deity of scribes and of knowledge, including scientific,
+       medical and mathematical writing, and is said to have given
+       mankind the art of hieroglyphic writing.  He is important as
+       a mediator and counsellor amongst the gods and is the scribe
+       of the Heliopolis Ennead pantheon.  According to mythology,
+       he was born from the head of the god Seth.  He may be
+       depicted in human form with the head of an ibis, wholly as an
+       ibis, or as a seated baboon sometimes with its torso covered
+       in feathers.  His attributes include a crown which consists
+       of a crescent moon surmounted by a moon disc.
+       Thoth is generally regarded as a benign deity.  He is also
+       scrupulously fair and is responsible not only for entering
+       in the record the souls who pass to afterlife, but of
+       adjudicating in the Hall of the Two Truths.  The Pyramid
+       Texts reveal a violent side of his nature by which he
+       decapitates the adversaries of truth and wrenches out their
+       hearts.
+               [ Encyclopedia of Gods, by Michael Jordan ]
+thoth*amon
+       Men say that he [Thutothmes] has opposed Thoth-Amon, who is
+       master of all priests of Set, and dwells in Luxor, and that
+       Thutothmes seeks hidden power [The Heart of Ahriman] to
+       overthrow the Great One.
+               [ Conan the Conqueror, by Robert E. Howard ]
+*throne
+       Methought I saw the footsteps of a throne
+       Which mists and vapours from mine eyes did shroud--
+       Nor view of who might sit thereon allowed;
+       But all the steps and ground about were strown
+       With sights the ruefullest that flesh and bone
+       Ever put on; a miserable crowd,
+       Sick, hale, old, young, who cried before that cloud,
+       "Thou art our king,
+       O Death! to thee we groan."
+       Those steps I clomb; the mists before me gave
+       Smooth way; and I beheld the face of one
+       Sleeping alone within a mossy cave,
+       With her face up to heaven; that seemed to have
+       Pleasing remembrance of a thought foregone;
+       A lovely Beauty in a summer grave!
+               [ Sonnet, by William Wordsworth ]
+tiger
+       1.  A well-known tropical predator (_Felis tigris_): a
+       feline.  It has a yellowish skin with darker spots or
+       stripes.  2.  Figurative: _a paper tiger_, something that is
+       meant to scare, but has no really scaring effect whatsoever,
+       (after a statement by Mao Ze Dong, August 1946).
+               [ Van Dale's Groot Woordenboek der Nederlandse Taal ]
+
+       Tyger! Tyger! burning bright
+       In the forests of the night,
+       What immortal hand or eye
+       Could frame thy fearful symmetry?
+               [ The Tyger, by William Blake ]
+tin
+tin of *
+tinning kit
+       "You know salmon, Sarge," said Nobby.
+       "It is a fish of which I am aware, yes."
+       "You know they sell kind of slices of it in tins..."
+       "So I am given to understand, yes."
+       "Weell...how come all the tins are the same size?  Salmon
+       gets thinner at both ends."
+       "Interesting point, Nobby.  I think-"
+               [ Soul Music, by Terry Pratchett ]
+tin opener
+       Less than thirty Cat tribes now survived, roaming the cargo
+       decks on their hind legs in a desperate search for food.
+       But the food had gone.
+       The supplies were finished.
+       Weak and ailing, they prayed at the supply hold's silver
+       mountains: huge towering acres of metal rocks which, in their
+       pagan way, the mutant Cats believed watched over them.
+       Amid the wailing and the screeching one Cat stood up and held
+       aloft the sacred icon.  The icon which had been passed down
+       as holy, and one day would make its use known.
+       It was a piece of V-shaped metal with a revolving handle on
+       its head.
+       He took down a silver rock from the silver mountain, while
+       the other Cats cowered and screamed at the blasphemy.
+       He placed the icon on the rim of the rock, and turned the
+       handle.
+       And the handle turned.
+       And the rock opened.
+       And inside the rock was Alphabetti spaghetti in tomato sauce.
+               [ Red Dwarf, by Rob Grant and Doug Naylor ]
+titan
+       Gaea, mother earth, arose from the Chaos and gave birth to
+       Uranus, heaven, who became her consort.  Uranus hated all
+       their children, because he feared they might challenge his
+       own authority.  Those children, the Titans, the Gigantes,
+       and the Cyclops, were banished to the nether world.  Their
+       enraged mother eventually released the youngest titan,
+       Chronos (time), and encouraged him to castrate his father and
+       rule in his place.  Later, he too was challenged by his own
+       son, Zeus, and he and his fellow titans were ousted from
+       Mount Olympus.
+               [ Greek Mythology, by Richard Patrick ]
+touch*stone
+       "Gold is tried by a touchstone, men by gold."
+               [ Chilon (c. 560 BC) ]
+tourist
+* tourist
+       The road from Ankh-Morpork to Chrim is high, white and
+       winding, a thirty-league stretch of potholes and half-buried
+       rocks that spirals around mountains and dips into cool green
+       valleys of citrus trees, crosses liana-webbed gorges on
+       creaking rope bridges and is generally more picturesque than
+       useful.
+       Picturesque.  That was a new word to Rincewind the wizard
+       (BMgc, Unseen University [failed]).  It was one of a number
+       he had picked up since leaving the charred ruins of
+       Ankh-Morpork.  Quaint was another one.  Picturesque meant --
+       he decided after careful observation of the scenery that
+       inspired Twoflower to use the word -- that the landscape was
+       horribly precipitous.  Quaint, when used to describe the
+       occasional village through which they passed, meant fever-
+       ridden and tumbledown.
+       Twoflower was a tourist, the first ever seen on the discworld.
+       Tourist, Rincewind had decided, meant "idiot".
+               [ The Colour of Magic, by Terry Pratchett ]
+towel
+       The Hitchhiker's Guide to the Galaxy has a few things to say
+       on the subject of towels.
+       A towel, it says, is about the most massively useful thing
+       an interstellar hitchhiker can have.  Partly it has great
+       practical value.  You can wrap it around you for warmth as
+       you bound across the cold moons of Jaglan Beta; you can lie
+       on it on the brilliant marble-sanded beaches of Santraginus
+       V, inhaling the heady sea vapors; you can sleep under it
+       beneath the stars which shine so redly on the desert world of
+       Kakrafoon; use it to sail a miniraft down down the slow heavy
+       River Moth; wet it for use in hand-to-hand combat; wrap it
+       round your head to ward off noxious fumes or avoid the gaze
+       of the Ravenous Bugblatter Beast of Traal (a mind-bogglingly
+       stupid animal, it assumes that if you can't see it, it can't
+       see you - daft as a brush, but very very ravenous); you can
+       wave your towel in emergencies as a distress signal, and of
+       course dry yourself off with it if it still seems to be clean
+       enough.
+               [ The Hitchhiker's Guide to the Galaxy,
+                 by Douglas Adams ]
+*tower
+       Towers (_brooding_, _dark_) stand alone in Waste Areas and
+       almost always belong to Wizards.  All are several stories high,
+       round, doorless, virtually windowless, and composed of smooth
+       blocks of masonry that make them very hard to climb. [...]
+       You will have to go to a Tower and then break into it at some
+       point towards the end of your Tour.
+       [ The Tough Guide to Fantasyland, by Diana Wynne Jones ]
+trap*door
+       I knew my Erik too well to feel at all comfortable on jumping
+       into his house.  I knew what he had made of a certain palace at
+       Mazenderan.  From being the most honest building conceivable, he
+       soon turned it into a house of the very devil, where you could
+       not utter a word but it was overheard or repeated by an echo.
+       With his trap-doors the monster was responsible for endless
+       tragedies of all kinds.
+               [ The Phantom of the Opera, by Gaston Leroux ]
+trapper
+       The trapper is a creature which has evolved a chameleon-like
+       ability to blend into the dungeon surroundings.  It captures
+       its prey by remaining very still and blending into the
+       surrounding dungeon features, until an unsuspecting creature
+       passes by.  It wraps itself around its prey and digests it.
+tree
+       I think that I shall never see
+       A poem lovely as a tree.
+       A tree whose hungry mouth is prest
+       Against the earth's sweet flowing breast;
+       A tree that looks at God all day,
+       And lifts her leafy arms to pray;
+       A tree that may in Summer wear
+       A nest of robins in her hair;
+       Upon whose bosom snow has lain;
+       Who intimately lives with rain.
+       Poems are made by fools like me,
+       But only God can make a tree.
+               [ Trees - Joyce Kilmer ]
+tripe
+tripe ration
+       If you start from scratch, cooking tripe is a long-drawn-out
+       affair.  Fresh whole tripe calls for a minimum of 12 hours of
+       cooking, some time-honored recipes demanding as much as 24.
+       To prepare fresh tripe, trim if necessary.  Wash it thoroughly,
+       soaking overnight, and blanch, for 1/2 hour in salted water.
+       Wash well again, drain and cut for cooking.  When cooked, the
+       texture of tripe should be like that of soft gristle.  More
+       often, alas, because the heat has not been kept low enough,
+       it has the consistency of wet shoe leather.
+               [ Joy of Cooking, by I Rombauer and M Becker ]
+*troll
+       The troll shambled closer.  He was perhaps eight feet tall,
+       perhaps more.  His forward stoop, with arms dangling past
+       thick claw-footed legs to the ground, made it hard to tell.
+       The hairless green skin moved upon his body.  His head was a
+       gash of a mouth, a yard-long nose, and two eyes which drank
+       the feeble torchlight and never gave back a gleam.
+       [...]
+       Like a huge green spider, the troll's severed hand ran on its
+       fingers.  Across the mounded floor, up onto a log with one
+       taloned forefinger to hook it over the bark, down again it
+       scrambled, until it found the cut wrist.  And there it grew
+       fast.  The troll's smashed head seethed and knit together.
+       He clambered back on his feet and grinned at them.  The
+       waning faggot cast red light over his fangs.
+               [ Three Hearts and Three Lions, by Poul Anderson ]
+*tsurugi of muramasa
+       This most ancient of swords has been passed down through the
+       leadership of the Samurai legions for hundreds of years.  It
+       is said to grant luck to its wielder, but its main power is
+       terrible to behold.  It has the capability to cut in half any
+       creature it is wielded against, instantly killing them.
+~*muramasa
+tsurugi
+       The tsurugi, also known as the long samurai sword, is an
+       extremely sharp, two-handed blade favored by the samurai.
+       It is made of hardened steel, and is manufactured using a
+       special process, causing it to never rust.  The tsurugi is
+       rumored to be so sharp that it can occasionally cut
+       opponents in half!
+twoflower
+guide
+       "Rincewind!"
+       Twoflower sprang off the bed.  The wizard jumped back,
+       wrenching his features into a smile.
+       "My dear chap, right on time!  We'll just have lunch, and
+       then I'm sure you've got a wonderful programme lined up for
+       this afternoon!"
+       "Er --"
+       "That's great!"
+       Rincewind took a deep breath.  "Look," he said desperately,
+       "let's eat somewhere else.  There's been a bit of a fight
+       down below."
+       "A tavern brawl?  Why didn't you wake me up?"
+       "Well, you see, I - _what_?"
+       "I thought I made myself clear this morning, Rincewind.  I
+       want to see genuine Morporkian life - the slave market, the
+       Whore Pits, the Temple of Small Gods, the Beggar's Guild...
+       and a genuine tavern brawl."  A faint note of suspicion
+       entered Twoflower's voice.  "You _do_ have them, don't you?
+       You know, people swinging on chandeliers, swordfights over
+       the table, the sort of thing Hrun the Barbarian and the
+       Weasel are always getting involved in.  You know --
+       _excitement_."
+               [ The Colour of Magic, by Terry Pratchett ]
+tyr
+       Yet remains that one of the Aesir who is called Tyr:
+       he is most daring, and best in stoutness of heart, and he
+       has much authority over victory in battle; it is good for
+       men of valor to invoke him.  It is a proverb, that he is
+       Tyr-valiant, who surpasses other men and does not waver.
+       He is wise, so that it is also said, that he that is wisest
+       is Tyr-prudent.  This is one token of his daring:  when the
+       Aesir enticed Fenris-Wolf to take upon him the fetter Gleipnir,
+       the wolf did not believe them, that they would loose him,
+       until they laid Tyr's hand into his mouth as a pledge.  But
+       when the Aesir would not loose him, then he bit off the hand
+       at the place now called 'the wolf's joint;' and Tyr is one-
+       handed, and is not called a reconciler of men.
+                       [ The Prose Edda, by Snorri Sturluson ]
+*hulk
+       Umber hulks are powerful subterranean predators whose
+       iron-like claws allow them to burrow through solid stone in
+       search of prey.  They are tremendously strong; muscles bulge
+       beneath their thick, scaly hides and their powerful arms and
+       legs all end in great claws.
+*unicorn
+unicorn horn
+       Men have always sought the elusive unicorn, for the single
+       twisted horn which projected from its forehead was thought to
+       be a powerful talisman.  It was said that the unicorn had
+       simply to dip the tip of its horn in a muddy pool for the water
+       to become pure.  Men also believed that to drink from this horn
+       was a protection against all sickness, and that if the horn was
+       ground to a powder it would act as an antidote to all poisons.
+       Less than 200 years ago in France, the horn of a unicorn was
+       used in a ceremony to test the royal food for poison.
+
+       Although only the size of a small horse, the unicorn is a very
+       fierce beast, capable of killing an elephant with a single
+       thrust from its horn.  Its fleetness of foot also makes this
+       solitary creature difficult to capture.  However, it can be
+       tamed and captured by a maiden.  Made gentle by the sight of a
+       virgin, the unicorn can be lured to lay its head in her lap, and
+       in this docile mood, the maiden may secure it with a golden rope.
+       [ Mythical Beasts, by Deirdre Headon (The Leprechaun Library) ]
+
+       Martin took a small sip of beer.  "Almost ready," he said.
+       "You hold your beer awfully well."
+       Tlingel laughed.  "A unicorn's horn is a detoxicant.  Its
+       possession is a universal remedy.  I wait until I reach the
+       warm glow stage, then I use my horn to burn off any excess and
+       keep me right there."
+               [ Unicorn Variations, by Roger Zelazny ]
+valkyrie
+* valkyrie
+       The Valkyries were the thirteen choosers of the slain, the
+       beautiful warrior-maids of Odin who rode through the air and
+       over the sea.  They watched the progress of the battle and
+       selected the heroes who were to fall fighting.  After they
+       were dead, the maidens rewarded the heroes by kissing them
+       and then led their souls to Valhalla, where the warriors
+       lived happily in an ideal existence, drinking and eating
+       without restraint and fighting over again the battles in
+       which they died and in which they had won their deathless
+       fame.
+               [ The Encyclopaedia of Myths and Legends of All
+                       Nations, by Herbert Robinson and Knox
+                       Wilson ]
+vampire
+vampire bat
+vampire lord
+       The Oxford English Dictionary is quite unequivocal:
+       _vampire_ - "a preternatural being of a malignant nature (in
+       the original and usual form of the belief, a reanimated
+       corpse), supposed to seek nourishment, or do harm, by sucking
+       the blood of sleeping persons. ..."
+venus
+       Venus, the goddess of love and beauty, was the daughter of
+       Jupiter and Dione.  Others say that Venus sprang from the
+       foam of the sea.  The zephyr wafted her along the waves to
+       the Isle of Cyprus, where she was received and attired by
+       the Seasons, and then led to the assembly of the gods.  All
+       were charmed with her beauty, and each one demanded her
+       for his wife.  Jupiter gave her to Vulcan, in gratitude for
+       the service he had rendered in forging thunderbolts.  So
+       the most beautiful of the goddesses became the wife of the
+       most ill-favoured of gods.
+               [ Bulfinch's Mythology, by Thomas Bulfinch ]
+vlad*
+       Vlad Dracula the Impaler was a 15th-Century monarch of the
+       Birgau region of the Carpathian Mountains, in what is now
+       Romania.  In Romanian history he is best known for two things.
+       One was his skilled handling of the Ottoman Turks, which kept
+       them from making further inroads into Christian Europe.  The
+       other was the ruthless manner in which he ran his fiefdom.
+       He dealt with perceived challengers to his rule by impaling
+       them upright on wooden stakes.  Visiting dignitaries who
+       failed to doff their hats had them nailed to their head.
+*vortex
+vortices
+       Swirling clouds of pure elemental energies, the vortices are
+       thought to be related to the larger elementals.  Though the
+       vortices do no damage when touched, they are noted for being
+       able to envelop unwary travellers.  The hapless fool thus
+       swallowed by a vortex will soon perish from exposure to the
+       element the vortex is composed of.
+vrock
+       The vrock is one of the weaker forms of demon.  It resembles
+       a cross between a human being and a vulture and does physical
+       damage by biting and by using the claws on both its arms and
+       feet.
+wakizashi
+       The samurai warrior traditionally wears two swords; the
+       wakizashi is the shorter of the two.  See also katana.
+wand of *
+*wand
+       'Saruman!' he cried, and his voice grew in power and authority.
+       'Behold, I am not Gandalf the Grey, whom you betrayed.  I am
+       Gandalf the White, who has returned from death.  You have no
+       colour now, and I cast you from the order and from the Council.'
+       He raised his hand, and spoke slowly in a clear cold voice.
+       'Saruman, your staff is broken.'  There was a crack, and the
+       staff split asunder in Saruman's hand, and the head of it
+       fell down at Gandalf's feet.  'Go!' said Gandalf.  With a cry
+       Saruman fell back and crawled away.
+               [ The Two Towers, by J.R.R. Tolkien ]
+warg
+       Suddenly Aragorn leapt to his feet.  "How the wind howls!"
+       he cried.  "It is howling with wolf-voices.  The Wargs have
+       come west of the Mountains!"
+       "Need we wait until morning then?" said Gandalf.  "It is as I
+       said.  The hunt is up!  Even if we live to see the dawn, who
+       now will wish to journey south by night with the wild wolves
+       on his trail?"
+       "How far is Moria?" asked Boromir.
+       "There was a door south-west of Caradhras, some fifteen miles
+       as the crow flies, and maybe twenty as the wolf runs,"
+       answered Gandalf grimly.
+       "Then let us start as soon as it is light tomorrow, if we can,"
+       said Boromir.  "The wolf that one hears is worse than the orc
+       that one fears."
+       "True!" said Aragorn, loosening his sword in its sheath.  "But
+       where the warg howls, there also the orc prowls."
+               [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+~mjollnir
+war*hammer
+       They had come together at the ford of the Trident while the
+       battle crashed around them, Robert with his warhammer and his
+       great antlered helm, the Targaryen prince armored all in
+       black.  On his breastplate was the three-headed dragon of his
+       House, wrought all in rubies that flashed like fire in the
+       sunlight.  The waters of the Trident ran red around the
+       hooves of their destriers as they circled and clashed, again
+       and again, until at last a crushing blow from Robert's hammer
+       stove in the dragon and the chest behind it.  When Ned had
+       finally come on the scene, Rhaegar lay dead in the stream,
+       while men of both armies scrambled in the swirling waters for
+       rubies knocked free of his armor.
+               [ A Game of Thrones, by George R.R. Martin ]
+water
+       Day after day, day after day,
+       We stuck, nor breath nor motion;
+       As idle as a painted ship
+       Upon a painted ocean.
+
+       Water, water, everywhere,
+       And all the boards did shrink;
+       Water, water, everywhere
+       Nor any drop to drink.
+               [ The Rime of the Ancient Mariner, by Samuel Taylor
+                 Coleridge ]
+web
+       Oh what a tangled web we weave,
+       When first we practise to deceive!
+               [ Marmion, by Sir Walter Scott ]
+# werecritter -- see "lycanthrope"
+*wight
+       When he came to himself again, for a moment he could recall
+       nothing except a sense of dread.  Then suddenly he knew that
+       he was imprisoned, caught hopelessly; he was in a barrow.  A
+       Barrow-wight had taken him, and he was probably already under
+       the dreadful spells of the Barrow-wights about which whispered
+       tales spoke.  He dared not move, but lay as he found himself:
+       flat on his back upon a cold stone with his hands on his
+       breast.
+               [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+# note: need to convert player character "gnomish wizard" into just "wizard"
+# in the lookup code to avoid conflict with the monster of that same name
+~gnomish wizard
+wizard
+* wizard
+apprentice
+       Ebenezum walked before me along the closest thing we could
+       find to a path in these overgrown woods.  Every few paces he
+       would pause, so that I, burdened with a pack stuffed with
+       arcane and heavy paraphernalia, could catch up with his
+       wizardly strides.  He, as usual, carried nothing, preferring,
+       as he often said, to keep his hands free for quick conjuring
+       and his mind free for the thoughts of a mage.
+               [ A Dealing with Demons, by Craig Shaw Gardner ]
+wizard of yendor
+       No one knows how old this mighty wizard is, or from whence he
+       came.  It is known that, having lived a span far greater than
+       any normal man's, he grew weary of lesser mortals; and so,
+       spurning all human company, he forsook the dwellings of men
+       and went to live in the depths of the Earth.  He took with
+       him a dreadful artifact, the Book of the Dead, which is said
+       to hold great power indeed.  Many have sought to find the
+       wizard and his treasure, but none have found him and lived to
+       tell the tale.  Woe be to the incautious adventurer who
+       disturbs this mighty sorcerer!
+wolf
+*wolf
+*wolf cub
+       The ancestors of the modern day domestic dog, wolves are
+       powerful muscular animals with bushy tails.  Intelligent,
+       social animals, wolves live in family groups or packs made
+       up of multiple family units.  These packs cooperate in hunting
+       down prey.
+woodchuck
+       The Usenet Oracle requires an answer to this question!
+
+       > How much wood could a woodchuck chuck if a woodchuck could
+       > chuck wood?
+
+       "Oh, heck!  I'll handle *this* one!"  The Oracle spun the terminal
+       back toward himself, unlocked the ZOT-guard lock, and slid the
+       glass guard away from the ZOT key.  "Ummmm....could you turn around
+       for a minute?  ZOTs are too graphic for the uninitiated.  Even *I*
+       get a little squeamish sometimes..."  The neophyte turned around,
+       and heard the Oracle slam his finger on a computer key, followed
+       by a loud ZZZZOTTTTT and the smell of ozone.
+               [ Excerpted from Internet Oracularity 576.6 ]
+*worm
+long worm tail
+worm tooth
+crysknife
+       [The crysknife] is manufactured in two forms from teeth taken
+       from dead sandworms.  The two forms are "fixed" and "unfixed".
+       An unfixed knife requires proximity to a human body's
+       electrical field to prevent disintegration.  Fixed knives
+       are treated for storage.  All are about 20 centimeters long.
+               [ Dune, by Frank Herbert ]
+wraith
+nazgul
+       Immediately, though everything else remained as before, dim
+       and dark, the shapes became terribly clear.  He was able to
+       see beneath their black wrappings.  There were five tall
+       figures:  two standing on the lip of the dell, three advancing.
+       In their white faces burned keen and merciless eyes; under
+       their mantles were long grey robes; upon their grey hairs
+       were helms of silver; in their haggard hands were swords of
+       steel.  Their eyes fell on him and pierced him, as they
+       rushed towards him.  Desperate, he drew his own sword, and
+       it seemed to him that it flickered red, as if it was a
+       firebrand.  Two of the figures halted.  The third was taller
+       than the others:  his hair was long and gleaming and on his
+       helm was a crown.  In one hand he held a long sword, and in
+       the other a knife; both the knife and the hand that held it
+       glowed with a pale light.  He sprang forward and bore down
+       on Frodo.
+               [ The Fellowship of the Ring, by J.R.R. Tolkien ]
+wumpus
+       The Wumpus, by the way, is not bothered by the hazards since
+       he has sucker feet and is too big for a bat to lift.  If you
+       try to shoot him and miss, there's also a chance that he'll
+       up and move himself into another cave, though by nature the
+       Wumpus is a sedentary creature.
+               [ wump (6) -- "Hunt the Wumpus" ]
+xan
+       They sent their friend the mosquito [xan] ahead of them to
+       find out what lay ahead.  "Since you are the one who sucks
+       the blood of men walking along paths," they told the mosquito,
+       "go and sting the men of Xibalba."  The mosquito flew
+       down the dark road to the Underworld.  Entering the house of
+       the Lords of Death, he stung the first person that he saw...
+
+       The mosquito stung this man as well, and when he yelled, the
+       man next to him asked, "Gathered Blood, what's wrong?"  So
+       he flew along the row stinging all the seated men until he
+       knew the names of all twelve.
+                       [ Popul Vuh, as translated by Ralph Nelson ]
+xorn
+       A distant cousin of the earth elemental, the xorn has the
+       ability to shift the cells of its body around in such a way
+       that it becomes porous to inert material.  This gives it the
+       ability to pass through any obstacle that might be between it
+       and its next meal.
+ya
+       The arrow of choice of the samurai, ya are made of very
+       straight bamboo, and are tipped with hardened steel.
+yeenoghu
+       Yeenoghu, the demon lord of gnolls, still exists although
+       all his followers have been wiped off the face of the earth.
+       He casts magic projectiles at those close to him, and a mere
+       gaze into his piercing eyes may hopelessly confuse the
+       battle-weary adventurer.
+yeti
+       The Abominable Snowman, or yeti, is one of the truly great
+       unknown animals of the twentieth century.  It is a large hairy
+       biped that lives in the Himalayan region of Asia ... The story
+       of the Abominable Snowman is filled with mysteries great and
+       small, and one of the most difficult of all is how it got that
+       awful name.  The creature is neither particularly abominable,
+       nor does it necessarily live in the snows.  _Yeti_ is a Tibetan
+       word which may apply either to a real, but unknown animal of
+       the Himalayas, or to a mountain spirit or demon -- no one is
+       quite sure which.  And after nearly half a century in which
+       Westerners have trampled around looking for the yeti, and
+       asking all sorts of questions, the original native traditions
+       concerning the creature have become even more muddled and
+       confused.
+               [ The Encyclopedia of Monsters, by Daniel Cohen ]
+*yugake
+       Japanese leather archery gloves.  Gloves made for use while
+       practicing had thumbs reinforced with horn.  Those worn into
+       battle had thumbs reinforced with a double layer of leather.
+yumi
+       The samurai is highly trained with a special type of bow,
+       the yumi.  Like the ya, the yumi is made of bamboo.  With
+       the yumi-ya, the bow and arrow, the samurai is an extremely
+       accurate and deadly warrior.
+*zombie
+       The zombi... is a soulless human corpse, still dead, but
+       taken from the grave and endowed by sorcery with a
+       mechanical semblance of life, -- it is a dead body which is
+       made to walk and act and move as if it were alive.
+               [ W. B. Seabrook ]
+zruty
+       The zruty are wild and gigantic beings, living in the
+       wildernesses of the Tatra mountains.
diff --git a/dat/dungeon.def b/dat/dungeon.def
new file mode 100644 (file)
index 0000000..fbb17bc
--- /dev/null
@@ -0,0 +1,138 @@
+#      SCCS Id: @(#)dungeon.def        3.4     1996/03/10
+#      Copyright (c) 1990-95 by M. Stephenson
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The dungeon description file for the "standard" 3.1 NetHack.
+#
+#      Note:   The order of the definition of dungeons in this file
+#              reflects in their order of creation in the real dungeon.
+#              The "Main" branch must *always* be first.
+#              Also note that the order of the dungeons in this file
+#              determines the order in which branch levels are assigned.
+#              If two dungeons have overlapping ranges for their entry
+#              points, then you should list the dungeon with the _least_
+#              number of choices for its branch level _first_.
+#
+
+DUNGEON:       "The Dungeons of Doom" "D" (25, 5)
+ALIGNMENT:     unaligned
+BRANCH:                "The Gnomish Mines" @ (2, 3)
+%REINCARNATION LEVEL:          "rogue" "R" @ (15, 4)
+LEVEL:         "oracle" "O" @ (5, 5)
+LEVALIGN:      neutral
+CHAINBRANCH:   "Sokoban" "oracle" + (1, 0) up
+RNDLEVEL:      "bigrm" "B" @ (10, 3) 40 5
+CHAINBRANCH:   "The Quest" "oracle" + (6, 2) portal
+BRANCH:                "Fort Ludios" @ (18, 4) portal
+RNDLEVEL:      "medusa" "none" @ (-5, 4) 2
+LEVALIGN:      chaotic
+LEVEL:         "castle" "none" @ (-1, 0)
+CHAINBRANCH:   "Gehennom" "castle" + (0, 0) no_down
+BRANCH:                "The Elemental Planes" @ (1, 0) no_down up
+
+#
+#      Gehennom
+#
+#      Now re-worked for 3.1, hell is hopefully going to be a little
+#      less boring.  Also, in 3.1, the tower is not considered as a
+#      part of hell, but is set up as a separate dungeon.
+#
+#      Gehennom is no longer considered "hellish" as a complete dungeon.
+#      That is, fire resistance is no longer a condition for survival in
+#      it.  However, Gehennom, and the special levels in it in particular,
+#      is abundant with fire traps.  As a result, fire resistance is still
+#      a prudent survival strategy in Gehennom.
+#
+#      Note:   Gehennom *must* be the second dungeon defined so that
+#              monsters can properly migrate here under certain
+#              circumstances.
+#
+DUNGEON:       "Gehennom" "G" (20, 5)
+DESCRIPTION:   mazelike
+DESCRIPTION:   hellish
+ALIGNMENT:     noalign
+BRANCH:                "Vlad's Tower" @ (9, 5) up
+LEVEL:         "valley" "V" @ (1, 0)
+LEVEL:         "sanctum" "none" @ (-1, 0)
+LEVEL:         "juiblex" "J" @ (4, 4)
+LEVEL:         "baalz" "B" @ (6, 4)
+LEVEL:         "asmodeus" "A" @ (2, 6)
+LEVEL:         "wizard1" "none" @ (11, 6)
+CHAINLEVEL:    "wizard2" "X" "wizard1" + (1, 0)
+CHAINLEVEL:    "wizard3" "Y" "wizard1" + (2, 0)
+LEVEL:         "orcus" "O" @ (10, 6)
+LEVEL:         "fakewiz1" "F" @ (-6,4)
+LEVEL:         "fakewiz2" "G" @ (-6,4)
+
+#
+#      The Mines of the Gnomes of Zurich.
+#
+DUNGEON:       "The Gnomish Mines" "M" (8, 2)
+ALIGNMENT:     lawful
+DESCRIPTION:   mazelike
+RNDLEVEL:      "minetn" "T" @ (3, 2) 7
+LEVELDESC:     town
+RNDLEVEL:      "minend" "E" @ (-1, 0) 3
+
+#
+#      The Questdungeon
+#
+#      This is a proto-dungeon.  The level file names will be prepended with
+#      the first letter of the character name during initialization.
+#      A special "x-fill" level must be defined in the levels description
+#      file.  It will be used for all levels not defined explicitly below.
+#
+DUNGEON:       "The Quest" "Q" (5, 2)
+LEVEL: "x-strt" "none" @ (1, 1)
+LEVEL: "x-loca" "L" @ (3, 1)
+LEVEL: "x-goal" "none" @ (-1, 0)
+
+#
+# Sokoban
+#
+DUNGEON:               "Sokoban" "none" (4, 0)
+DESCRIPTION:    mazelike
+ALIGNMENT:      neutral
+ENTRY:          -1
+RNDLEVEL:              "soko1" "none" @ (1, 0) 2
+RNDLEVEL:              "soko2" "none" @ (2, 0) 2
+RNDLEVEL:              "soko3" "none" @ (3, 0) 2
+RNDLEVEL:              "soko4" "none" @ (4, 0) 2
+
+#
+#      The Central Vault of Croesus.
+#
+DUNGEON:       "Fort Ludios" "K" (1, 0)
+DESCRIPTION:   mazelike
+ALIGNMENT:     unaligned
+LEVEL:         "knox" "K" @ (-1, 0)
+#
+#      Vlad's Tower
+#
+#      It has been removed from Gehennom, and it is surrounded by stone.
+#      Must not allow bones files for its top level.
+#
+DUNGEON:       "Vlad's Tower" "T" (3, 0)
+PROTOFILE:     "tower"
+DESCRIPTION:   mazelike
+ALIGNMENT:     chaotic
+ENTRY:         -1
+LEVEL:         "tower1" "none" @ (1, 0)
+
+#
+#      The Endgame levels
+#
+#      Enter on 2nd level from bottom; 1st (from bottom) is a
+#      placeholder for surface level, and should be unreachable.
+#      [Note: the name "dummy" is checked for in init_dungeons().]
+#
+DUNGEON:       "The Elemental Planes" "E" (6, 0)
+DESCRIPTION:   mazelike
+ALIGNMENT:     unaligned
+ENTRY:         -2
+LEVEL:         "astral" "none" @ (1, 0)
+LEVEL:         "water"  "none" @ (2, 0)
+LEVEL:         "fire"   "none" @ (3, 0)
+LEVEL:         "air"    "none" @ (4, 0)
+LEVEL:         "earth"  "none" @ (5, 0)
+LEVEL:         "dummy"  "none" @ (6, 0)
diff --git a/dat/endgame.des b/dat/endgame.des
new file mode 100644 (file)
index 0000000..60500e1
--- /dev/null
@@ -0,0 +1,616 @@
+#      SCCS Id: @(#)endgame.des        3.4     2002/01/19
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1992,1993 by Izchak Miller, David Cohrs,
+#                      and Timo Hakulinen
+# NetHack may be freely redistributed.  See license for details.
+#
+# These are the ENDGAME levels: earth, air, fire, water, and astral.
+# The top-most level, the Astral Level, has 3 temples and shrines.
+# Players are supposed to sacrifice the Amulet of Yendor on the appropriate
+# shrine.
+
+MAZE:"earth",' '
+FLAGS: noteleport,hardfloor,shortsighted
+MESSAGE: "Well done, mortal!"
+MESSAGE: "But now thou must face the final Test..."
+MESSAGE: "Prove thyself worthy or perish!"
+
+GEOMETRY:center,center
+# The player lands, upon arrival, in the
+# lower-right cavern.  The location of the
+# portal to the next level is randomly chosen.
+# This map has no visible outer boundary, and
+# is mostly diggable "rock".
+MAP
+                                                                            
+  ...                                                                       
+ ....                ..                                                     
+ .....             ...                                      ..              
+  ....              ....                                     ...            
+   ....              ...                ....                 ...      .     
+    ..                ..              .......                 .      ..     
+                                      ..  ...                        .      
+              .                      ..    .                         ...    
+             ..  ..                  .     ..                         .     
+            ..   ...                        .                               
+            ...   ...                                                       
+              .. ...                                 ..                     
+               ....                                 ..                      
+                          ..                                       ...      
+                         ..                                       .....     
+  ...                                                              ...      
+ ....                                                                       
+   ..                                                                       
+                                                                            
+ENDMAP
+#  Since there are no stairs, this forces the hero's initial placement
+TELEPORT_REGION:(69,16,69,16),(0,0,0,0)
+PORTAL:(0,0,75,19),(65,13,75,19),"air"
+#  Some helpful monsters.  Making sure a
+#  pick axe and at least one wand of digging
+#  are available.
+MONSTER:'@',"Elvenking",(67,16)
+MONSTER:'H',"minotaur",(67,14)
+#  An assortment of earth-appropriate nasties
+#  in each cavern.
+MONSTER:'E',"earth elemental",(52,13),hostile
+MONSTER:'E',"earth elemental",(53,13),hostile
+MONSTER:'T',"rock troll",(53,12)
+MONSTER:'H',"stone giant",(54,12)
+#
+MONSTER:'S',"pit viper",(70,05)
+MONSTER:'&',"barbed devil",(69,06)
+MONSTER:'H',"stone giant",(69,08)
+MONSTER:''',"stone golem",(71,08)
+MONSTER:'&',"pit fiend",(70,09)
+MONSTER:'E',"earth elemental",(70,08),hostile
+#
+MONSTER:'E',"earth elemental",(60,03),hostile
+MONSTER:'H',"stone giant",(61,04)
+MONSTER:'E',"earth elemental",(62,04),hostile
+MONSTER:'E',"earth elemental",(61,05),hostile
+MONSTER:'s',"scorpion",(62,05)
+MONSTER:'p',"rock piercer",(63,05)
+#
+MONSTER:'U',"umber hulk",(40,05)
+MONSTER:'v',"dust vortex",(42,05)
+MONSTER:'T',"rock troll",(38,06)
+MONSTER:'E',"earth elemental",(39,06),hostile
+MONSTER:'E',"earth elemental",(41,06),hostile
+MONSTER:'E',"earth elemental",(38,07),hostile
+MONSTER:'H',"stone giant",(39,07)
+MONSTER:'E',"earth elemental",(43,07),hostile
+MONSTER:''',"stone golem",(37,08)
+MONSTER:'S',"pit viper",(43,08)
+MONSTER:'S',"pit viper",(43,09)
+MONSTER:'T',"rock troll",(44,10)
+#
+MONSTER:'E',"earth elemental",(02,01),hostile
+MONSTER:'E',"earth elemental",(03,01),hostile
+MONSTER:''',"stone golem",(01,02)
+MONSTER:'E',"earth elemental",(02,02),hostile
+MONSTER:'T',"rock troll",(04,03)
+MONSTER:'T',"rock troll",(03,03)
+MONSTER:'&',"pit fiend",(03,04)
+MONSTER:'E',"earth elemental",(04,05),hostile
+MONSTER:'S',"pit viper",(05,06)
+#
+MONSTER:'E',"earth elemental",(21,02),hostile
+MONSTER:'E',"earth elemental",(21,03),hostile
+MONSTER:'H',"minotaur",(21,04)
+MONSTER:'E',"earth elemental",(21,05),hostile
+MONSTER:'T',"rock troll",(22,05)
+MONSTER:'E',"earth elemental",(22,06),hostile
+MONSTER:'E',"earth elemental",(23,06),hostile
+#
+MONSTER:'S',"pit viper",(14,08)
+MONSTER:'&',"barbed devil",(14,09)
+MONSTER:'E',"earth elemental",(13,10),hostile
+MONSTER:'T',"rock troll",(12,11)
+MONSTER:'E',"earth elemental",(14,12),hostile
+MONSTER:'E',"earth elemental",(15,13),hostile
+MONSTER:'H',"stone giant",(17,13)
+MONSTER:''',"stone golem",(18,13)
+MONSTER:'&',"pit fiend",(18,12)
+MONSTER:'E',"earth elemental",(18,11),hostile
+MONSTER:'E',"earth elemental",(18,10),hostile
+#
+MONSTER:'&',"barbed devil",(02,16)
+MONSTER:'E',"earth elemental",(03,16),hostile
+MONSTER:'T',"rock troll",(02,17)
+MONSTER:'E',"earth elemental",(04,17),hostile
+MONSTER:'E',"earth elemental",(04,18),hostile
+
+OBJECT:'`',"boulder",random
+
+
+MAZE:"air",' '
+FLAGS: noteleport,hardfloor,shortsighted
+# The following messages are somewhat obtuse, to make then
+# equally meaningful if the player can see or not.
+MESSAGE: "What a strange feeling!"
+MESSAGE: "You notice that there is no gravity here."
+GEOMETRY:center,center
+# The player lands, upon arrival, in the
+# lower-left area.  The location of the
+# portal to the next level is randomly chosen.
+# This map has no visible outer boundary, and
+# is all "air".
+MAP
+AAAAAAAAAAAAAAAAAAAAAAAACCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAACCCCCCAAAAAAAACCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAACCAACCCCCAAAAAACCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAACCACCCCCCCAAAAACCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAACCCCCCCCCCAAAAACCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAACCCCAAACCAAACCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAACCCCAAAAAACCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAACCCCCCCAAAACCACCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAACCCCAAAAAAACCACAACCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCAACCCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAACCCCAAACCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACACACCCCCAAACCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAACAACCCCCCCAAAACCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACACCCCCCCCAAACCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCCCCCCCCCAACCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAACACCCCCCCCCCACCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAACAACCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAACCCCCCAAACCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAACCAAAAAACCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ENDMAP
+# Use up and down regions to partition the level into three parts;
+# teleportation can't cross from one part into another.
+# The up region is where you'll arrive after activating the portal from
+# the preceding level; the exit portal is placed inside the down region.
+TELEPORT_REGION:levregion(01,00,24,20),levregion(25,00,79,20),up
+TELEPORT_REGION:levregion(56,00,79,20),levregion(01,00,55,20),down
+PORTAL:levregion(57,01,78,19),(0,0,0,0),"fire"
+REGION:(00,00,75,19),lit,"ordinary"
+MONSTER:'E',"air elemental",random,hostile
+MONSTER:'E',"air elemental",random,hostile
+MONSTER:'E',"air elemental",random,hostile
+MONSTER:'E',"air elemental",random,hostile
+MONSTER:'E',"air elemental",random,hostile
+MONSTER:'E',"air elemental",random,hostile
+MONSTER:'E',"air elemental",random,hostile
+MONSTER:'E',"air elemental",random,hostile
+MONSTER:'E',"air elemental",random,hostile
+MONSTER:'E',"air elemental",random,hostile
+MONSTER:'E',"air elemental",random,hostile
+
+MONSTER:'e',"floating eye",random,hostile
+MONSTER:'e',"floating eye",random,hostile
+MONSTER:'e',"floating eye",random,hostile
+
+MONSTER:'y',"yellow light",random,hostile
+MONSTER:'y',"yellow light",random,hostile
+MONSTER:'y',"yellow light",random,hostile
+
+MONSTER:'A',"couatl",random
+
+MONSTER:'D',random,random
+MONSTER:'D',random,random
+MONSTER:'D',random,random
+MONSTER:'D',random,random
+MONSTER:'D',random,random
+
+MONSTER:'E',random,random
+MONSTER:'E',random,random
+MONSTER:'E',random,random
+MONSTER:'J',random,random
+MONSTER:'J',random,random
+
+MONSTER:'&',"djinni",random,hostile
+MONSTER:'&',"djinni",random,hostile
+MONSTER:'&',"djinni",random,hostile
+
+MONSTER:'v',"fog cloud",random,hostile
+MONSTER:'v',"fog cloud",random,hostile
+MONSTER:'v',"fog cloud",random,hostile
+MONSTER:'v',"fog cloud",random,hostile
+MONSTER:'v',"fog cloud",random,hostile
+MONSTER:'v',"fog cloud",random,hostile
+MONSTER:'v',"fog cloud",random,hostile
+MONSTER:'v',"fog cloud",random,hostile
+MONSTER:'v',"fog cloud",random,hostile
+MONSTER:'v',"energy vortex",random,hostile
+MONSTER:'v',"energy vortex",random,hostile
+MONSTER:'v',"energy vortex",random,hostile
+MONSTER:'v',"energy vortex",random,hostile
+MONSTER:'v',"energy vortex",random,hostile
+MONSTER:'v',"steam vortex",random,hostile
+MONSTER:'v',"steam vortex",random,hostile
+MONSTER:'v',"steam vortex",random,hostile
+MONSTER:'v',"steam vortex",random,hostile
+MONSTER:'v',"steam vortex",random,hostile
+
+
+MAZE:"fire",' '
+FLAGS: noteleport,hardfloor,shortsighted
+GEOMETRY:center,center
+# The player lands, upon arrival, in the
+# lower-right.  The location of the
+# portal to the next level is randomly chosen.
+# This map has no visible outer boundary, and
+# is mostly open area, with lava lakes and bunches of fire traps.
+MAP
+............................................................................
+....LLLLLLLL............L.......................LLL.........................
+...LL...................L......................LLLL................LL.......
+...L.............LLLL...LL....LL...............LLLLL.............LLL........
+.LLLL..............LL....L.....LLL..............LLLL..............LLLL......
+..........LLLL...LLLL...LLL....LLL......L........LLLL....LL........LLL......
+........LLLLLLL...LL.....L......L......LL.........LL......LL........LL...L..
+........LL..LLL..LL......LL......LLLL..L.........LL......LLL............LL..
+....L..LL....LLLLL.................LLLLLLL.......L......LL............LLLLLL
+....L..L.....LL.LLLL.......L............L........LLLLL.LL......LL.........LL
+....LL........L...LL......LL.............LLL.....L...LLL.......LLL.........L
+.....LLLLLL........L.......LLL.............L....LL...L.LLL......LLLLLLL.....
+..........LLLL............LL.L.............L....L...LL.........LLL..LLL.....
+...........................LLLLL...........LL...L...L........LLLL..LLLLLL...
+.....LLLL.............LL....LL.......LLL...LL.......L..LLL....LLLLLLL.......
+.......LLL.........LLLLLLLLLLL......LLLLL...L...........LL...LL...LL........
+.........LL.......LL.........LL.......LLL....L..LLL....LL.........LL........
+..........LLLLLLLLL...........LL....LLL.......LLLLL.....LL........LL........
+.................L.............LLLLLL............LL...LLLL.........LL.......
+.................................LL....................LL...................
+ENDMAP
+TELEPORT_REGION:(69,16,69,16),(0,0,0,0)
+PORTAL:(0,0,75,19),(65,13,75,19),"water"
+
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+TRAP:"fire",random
+#  An assortment of fire-appropriate nasties
+MONSTER:'D',"red dragon",random
+MONSTER:'&',"balrog",random
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'v',"fire vortex",random
+MONSTER:'d',"hell hound",random
+#
+MONSTER:'H',"fire giant",random
+MONSTER:'&',"barbed devil",random
+MONSTER:'d',"hell hound",random
+MONSTER:''',"stone golem",random
+MONSTER:'&',"pit fiend",random
+MONSTER:'E',"fire elemental",random,hostile
+#
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'d',"hell hound",random
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'s',"scorpion",random
+MONSTER:'H',"fire giant",random
+#
+MONSTER:'d',"hell hound",random
+MONSTER:'v',"dust vortex",random
+MONSTER:'v',"fire vortex",random
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'d',"hell hound",random
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:''',"stone golem",random
+MONSTER:'S',"pit viper",random
+MONSTER:'S',"pit viper",random
+MONSTER:'v',"fire vortex",random
+#
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'H',"fire giant",random
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'v',"fire vortex",random
+MONSTER:'v',"fire vortex",random
+MONSTER:'&',"pit fiend",random
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'S',"pit viper",random
+#
+MONSTER:':',"salamander",random,hostile
+MONSTER:':',"salamander",random,hostile
+MONSTER:'H',"minotaur",random
+MONSTER:':',"salamander",random,hostile
+MONSTER:'v',"steam vortex",random
+MONSTER:':',"salamander",random,hostile
+MONSTER:':',"salamander",random,hostile
+#
+MONSTER:'H',"fire giant",random
+MONSTER:'&',"barbed devil",random
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'v',"fire vortex",random
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'d',"hell hound",random
+MONSTER:'H',"fire giant",random
+MONSTER:'&',"pit fiend",random
+MONSTER:'E',"fire elemental",random,hostile
+MONSTER:'E',"fire elemental",random,hostile
+#
+MONSTER:'&',"barbed devil",random
+MONSTER:':',"salamander",random,hostile
+MONSTER:'v',"steam vortex",random
+MONSTER:':',"salamander",random,hostile
+MONSTER:':',"salamander",random,hostile
+
+OBJECT:'`',"boulder",random
+OBJECT:'`',"boulder",random
+OBJECT:'`',"boulder",random
+OBJECT:'`',"boulder",random
+OBJECT:'`',"boulder",random
+
+
+MAZE:"water",' '
+FLAGS: noteleport,hardfloor,shortsighted
+MESSAGE: "You find yourself suspended in an air bubble surrounded by water."
+GEOMETRY:center,center
+# The player lands upon arrival to an air bubble
+# within the leftmost third of the level.  The
+# portal to the next level is randomly located in an air
+# bubble within the rightmost third of the level.
+# Bubbles are generated by special code in mkmaze.c for now.
+MAP
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
+ENDMAP
+TELEPORT_REGION:(0,0,25,19),(0,0,0,0)
+PORTAL:(51,0,75,19),(0,0,0,0),"astral"
+# A fisherman's dream...
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"giant eel",random
+MONSTER:';',"electric eel",random
+MONSTER:';',"electric eel",random
+MONSTER:';',"electric eel",random
+MONSTER:';',"electric eel",random
+MONSTER:';',"electric eel",random
+MONSTER:';',"electric eel",random
+MONSTER:';',"electric eel",random
+MONSTER:';',"electric eel",random
+MONSTER:';',"kraken",random
+MONSTER:';',"kraken",random
+MONSTER:';',"kraken",random
+MONSTER:';',"kraken",random
+MONSTER:';',"kraken",random
+MONSTER:';',"kraken",random
+MONSTER:';',"kraken",random
+MONSTER:';',"kraken",random
+MONSTER:';',"kraken",random
+MONSTER:';',"shark",random
+MONSTER:';',"shark",random
+MONSTER:';',"shark",random
+MONSTER:';',"shark",random
+MONSTER:';',"piranha",random
+MONSTER:';',"piranha",random
+MONSTER:';',"piranha",random
+MONSTER:';',"piranha",random
+MONSTER:';',"jellyfish",random
+MONSTER:';',"jellyfish",random
+MONSTER:';',"jellyfish",random
+MONSTER:';',"jellyfish",random
+MONSTER:';',random,random
+MONSTER:';',random,random
+MONSTER:';',random,random
+MONSTER:';',random,random
+# These guys feel like home here
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+MONSTER:'E',"water elemental",random,hostile
+
+
+MAZE:"astral",' '
+FLAGS: noteleport,hardfloor,nommap,shortsighted
+MESSAGE: "You arrive on the Astral Plane!"
+MESSAGE: "Here the High Temples of the aligned gods are located."
+MESSAGE: "You sense alarm, hostility, and excitement in the air!"
+GEOMETRY:center,center
+MAP
+                              ---------------                              
+                              |.............|                              
+                              |..---------..|                              
+                              |..|.......|..|                              
+---------------               |..|.......|..|               ---------------
+|.............|               |..|.......|..|               |.............|
+|..---------..-|   |-------|  |..|.......|..|  |-------|   |-..---------..|
+|..|.......|...-| |-.......-| |..|.......|..| |-.......-| |-...|.......|..|
+|..|.......|....-|-.........-||..----+----..||-.........-|-....|.......|..|
+|..|.......+.....+...........||.............||...........+.....+.......|..|
+|..|.......|....-|-.........-|--|.........|--|-.........-|-....|.......|..|
+|..|.......|...-| |-.......-|   -|---+---|-   |-.......-| |-...|.......|..|
+|..---------..-|   |---+---|    |-.......-|    |---+---|   |-..---------..|
+|.............|      |...|-----|-.........-|-----|...|      |.............|
+---------------      |.........|...........|.........|      ---------------
+                     -------...|-.........-|...-------                     
+                           |....|-.......-|....|                           
+                           ---...|---+---|...---                           
+                             |...............|                             
+                             -----------------                             
+ENDMAP
+# Rider locations
+RANDOM_PLACES:(23,9),(37,14),(51,9)
+# Where the player will land on arrival
+TELEPORT_REGION:(29,15,45,15),(30,15,44,15)
+# Lit courts
+REGION:(01,05,16,14),lit,"ordinary",filled,true
+REGION:(31,01,44,10),lit,"ordinary",filled,true
+REGION:(61,05,74,14),lit,"ordinary",filled,true
+# A Sanctum for each alignment
+# The shrines' alignments are shuffled for
+# each game
+REGION:(04,07,10,11),lit,"temple"
+REGION:(34,03,40,07),lit,"temple"
+REGION:(64,07,70,11),lit,"temple"
+ALTAR:(07,09),align[0],sanctum
+ALTAR:(37,05),align[1],sanctum
+ALTAR:(67,09),align[2],sanctum
+# Doors
+DOOR:closed,(11,09)
+DOOR:closed,(17,09)
+DOOR:locked,(23,12)
+DOOR:locked,(37,08)
+DOOR:closed,(37,11)
+DOOR:closed,(37,17)
+DOOR:locked,(51,12)
+DOOR:locked,(57,09)
+DOOR:closed,(63,09)
+# Non diggable and phazeable everywhere
+NON_DIGGABLE:(00,00,74,19)
+NON_PASSWALL:(00,00,74,19)
+# Moloch's horde
+# West round room
+MONSTER:'@',"aligned priest",(18,09),noalign,hostile
+MONSTER:'@',"aligned priest",(19,08),noalign,hostile
+MONSTER:'@',"aligned priest",(19,09),noalign,hostile
+MONSTER:'@',"aligned priest",(19,10),noalign,hostile
+MONSTER:'A',"Angel",(20,09),noalign,hostile
+MONSTER:'A',"Angel",(20,10),noalign,hostile
+MONSTER:'&',"Pestilence",place[0],hostile
+# South-central round room
+MONSTER:'@',"aligned priest",(36,12),noalign,hostile
+MONSTER:'@',"aligned priest",(37,12),noalign,hostile
+MONSTER:'@',"aligned priest",(38,12),noalign,hostile
+MONSTER:'@',"aligned priest",(36,13),noalign,hostile
+MONSTER:'A',"Angel",(38,13),noalign,hostile
+MONSTER:'A',"Angel",(37,13),noalign,hostile
+MONSTER:'&',"Death",place[1],hostile
+# East round room
+MONSTER:'@',"aligned priest",(56,09),noalign,hostile
+MONSTER:'@',"aligned priest",(55,08),noalign,hostile
+MONSTER:'@',"aligned priest",(55,09),noalign,hostile
+MONSTER:'@',"aligned priest",(55,10),noalign,hostile
+MONSTER:'A',"Angel",(54,09),noalign,hostile
+MONSTER:'A',"Angel",(54,10),noalign,hostile
+MONSTER:'&',"Famine",place[2],hostile
+#
+# The aligned horde
+#
+# We do not know in advance the alignment of the
+# player.  The mpeaceful bit will need resetting
+# when the level is created.  The setting here is
+# but a place holder.
+#
+# West court
+MONSTER:'@',"aligned priest",(12,07),chaos,hostile
+MONSTER:'@',"aligned priest",(13,07),chaos,peaceful
+MONSTER:'@',"aligned priest",(14,07),law,hostile
+MONSTER:'@',"aligned priest",(12,11),law,peaceful
+MONSTER:'@',"aligned priest",(13,11),neutral,hostile
+MONSTER:'@',"aligned priest",(14,11),neutral,peaceful
+MONSTER:'A',"Angel",(11,05),chaos,hostile
+MONSTER:'A',"Angel",(12,05),chaos,peaceful
+MONSTER:'A',"Angel",(13,05),law,hostile
+MONSTER:'A',"Angel",(11,13),law,peaceful
+MONSTER:'A',"Angel",(12,13),neutral,hostile
+MONSTER:'A',"Angel",(13,13),neutral,peaceful
+# Central court
+MONSTER:'@',"aligned priest",(32,09),chaos,hostile
+MONSTER:'@',"aligned priest",(33,09),chaos,peaceful
+MONSTER:'@',"aligned priest",(34,09),law,hostile
+MONSTER:'@',"aligned priest",(40,09),law,peaceful
+MONSTER:'@',"aligned priest",(41,09),neutral,hostile
+MONSTER:'@',"aligned priest",(42,09),neutral,peaceful
+MONSTER:'A',"Angel",(31,08),chaos,hostile
+MONSTER:'A',"Angel",(32,08),chaos,peaceful
+MONSTER:'A',"Angel",(31,09),law,hostile
+MONSTER:'A',"Angel",(42,08),law,peaceful
+MONSTER:'A',"Angel",(43,08),neutral,hostile
+MONSTER:'A',"Angel",(43,09),neutral,peaceful
+# East court
+MONSTER:'@',"aligned priest",(60,07),chaos,hostile
+MONSTER:'@',"aligned priest",(61,07),chaos,peaceful
+MONSTER:'@',"aligned priest",(62,07),law,hostile
+MONSTER:'@',"aligned priest",(60,11),law,peaceful
+MONSTER:'@',"aligned priest",(61,11),neutral,hostile
+MONSTER:'@',"aligned priest",(62,11),neutral,peaceful
+MONSTER:'A',"Angel",(61,05),chaos,hostile
+MONSTER:'A',"Angel",(62,05),chaos,peaceful
+MONSTER:'A',"Angel",(63,05),law,hostile
+MONSTER:'A',"Angel",(61,13),law,peaceful
+MONSTER:'A',"Angel",(62,13),neutral,hostile
+MONSTER:'A',"Angel",(63,13),neutral,peaceful
+#
+# Assorted nasties
+MONSTER:'L',random,random,hostile
+MONSTER:'L',random,random,hostile
+MONSTER:'L',random,random,hostile
+MONSTER:'V',random,random,hostile
+MONSTER:'V',random,random,hostile
+MONSTER:'V',random,random,hostile
+MONSTER:'D',random,random,hostile
+MONSTER:'D',random,random,hostile
+MONSTER:'D',random,random,hostile
diff --git a/dat/gehennom.des b/dat/gehennom.des
new file mode 100644 (file)
index 0000000..bee336f
--- /dev/null
@@ -0,0 +1,674 @@
+#      SCCS Id: @(#)gehennom.des       3.4     1996/11/09
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1992 by M. Stephenson and Izchak Miller
+# NetHack may be freely redistributed.  See license for details.
+#
+
+MAZE: "valley", ' '
+FLAGS: noteleport,hardfloor,nommap
+GEOMETRY:center,center
+MAP
+----------------------------------------------------------------------------
+|...S.|..|.....|  |.....-|      |................|   |...............| |...|
+|---|.|.--.---.|  |......--- ----..........-----.-----....---........---.-.|
+|   |.|.|..| |.| --........| |.............|   |.......---| |-...........--|
+|   |...S..| |.| |.......-----.......------|   |--------..---......------- |
+|----------- |.| |-......| |....|...-- |...-----................----       |
+|.....S....---.| |.......| |....|...|  |..............-----------          |
+|.....|.|......| |.....--- |......---  |....---.......|                    |
+|.....|.|------| |....--   --....-- |-------- ----....---------------      |
+|.....|--......---BBB-|     |...--  |.......|    |..................|      |
+|..........||........-|    --...|   |.......|    |...||.............|      |
+|.....|...-||-........------....|   |.......---- |...||.............--     |
+|.....|--......---...........--------..........| |.......---------...--    |
+|.....| |------| |--.......--|   |..B......----- -----....| |.|  |....---  |
+|.....| |......--| ------..| |----..B......|       |.--------.-- |-.....---|
+|------ |........|  |.|....| |.....----BBBB---------...........---.........|
+|       |........|  |...|..| |.....|  |-.............--------...........---|
+|       --.....-----------.| |....-----.....----------     |.........----  |
+|        |..|..B...........| |.|..........|.|              |.|........|    |
+----------------------------------------------------------------------------
+ENDMAP
+# Dungeon Description
+# The shrine to Moloch.
+REGION:(01,06,05,14),lit,"temple"
+# The Morgues
+REGION:(19,01,24,08),unlit,"morgue",filled,true
+REGION:(09,14,16,18),unlit,"morgue",filled,true
+REGION:(37,09,43,14),unlit,"morgue",filled,true
+# Stairs
+STAIR:(01,01),down
+# Branch location
+BRANCH:(66,17,66,17),(0,0,0,0)
+TELEPORT_REGION:(58,09,72,18),(0,0,0,0),down
+
+# Secret Doors
+DOOR:locked,(04,01)
+DOOR:locked,(08,04)
+DOOR:locked,(06,06)
+
+# The altar of Moloch.
+ALTAR:(03,10),noalign,shrine
+
+# Non diggable walls - everywhere!
+NON_DIGGABLE:(00,00,75,19)
+
+# Objects
+# **LOTS** of dead bodies (all human).
+# note: no priest(esse)s or monks - maybe Moloch has a *special*
+#       fate reserved for members of *those* classes.
+#
+OBJECT:'%',"corpse",random,"archeologist",0
+OBJECT:'%',"corpse",random,"archeologist",0
+OBJECT:'%',"corpse",random,"barbarian",0
+OBJECT:'%',"corpse",random,"barbarian",0
+OBJECT:'%',"corpse",random,"caveman",0
+OBJECT:'%',"corpse",random,"cavewoman",0
+OBJECT:'%',"corpse",random,"healer",0
+OBJECT:'%',"corpse",random,"healer",0
+OBJECT:'%',"corpse",random,"knight",0
+OBJECT:'%',"corpse",random,"knight",0
+OBJECT:'%',"corpse",random,"ranger",0
+OBJECT:'%',"corpse",random,"ranger",0
+OBJECT:'%',"corpse",random,"rogue",0
+OBJECT:'%',"corpse",random,"rogue",0
+OBJECT:'%',"corpse",random,"samurai",0
+OBJECT:'%',"corpse",random,"samurai",0
+OBJECT:'%',"corpse",random,"tourist",0
+OBJECT:'%',"corpse",random,"tourist",0
+OBJECT:'%',"corpse",random,"valkyrie",0
+OBJECT:'%',"corpse",random,"valkyrie",0
+OBJECT:'%',"corpse",random,"wizard",0
+OBJECT:'%',"corpse",random,"wizard",0
+#
+# Some random weapons and armor.
+#
+OBJECT:'[',random,random
+OBJECT:'[',random,random
+OBJECT:'[',random,random
+OBJECT:'[',random,random
+OBJECT:')',random,random
+OBJECT:')',random,random
+OBJECT:')',random,random
+OBJECT:')',random,random
+#
+# Some random loot.
+#
+OBJECT:'*',"ruby",random
+OBJECT:'*',random,random
+OBJECT:'*',random,random
+OBJECT:'!',random,random
+OBJECT:'!',random,random
+OBJECT:'!',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'/',random,random
+OBJECT:'/',random,random
+OBJECT:'=',random,random
+OBJECT:'=',random,random
+OBJECT:'+',random,random
+OBJECT:'+',random,random
+OBJECT:'(',random,random
+OBJECT:'(',random,random
+OBJECT:'(',random,random
+
+# (Not so) Random traps.
+TRAP:"spiked pit", (05,02)
+TRAP:"spiked pit", (14,05)
+TRAP:"sleep gas", (03,01)
+TRAP:"board", (21,12)
+TRAP:"board", random
+TRAP:"dart", (60,01)
+TRAP:"dart", (26,17)
+TRAP:"anti magic", random
+TRAP:"anti magic", random
+TRAP:"magic", random
+TRAP:"magic", random
+
+# Random monsters.
+# The ghosts.
+MONSTER:' ',"ghost",random
+MONSTER:' ',"ghost",random
+MONSTER:' ',"ghost",random
+MONSTER:' ',"ghost",random
+MONSTER:' ',"ghost",random
+MONSTER:' ',"ghost",random
+# Add a few bats for atmosphere.
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+MONSTER:'B',"vampire bat",random
+# And a lich for good measure.
+MONSTER:'L',random,random
+# Some undead nasties for good measure
+MONSTER:'V',random,random
+MONSTER:'V',random,random
+MONSTER:'V',random,random
+MONSTER:'Z',random,random
+MONSTER:'Z',random,random
+MONSTER:'Z',random,random
+MONSTER:'Z',random,random
+MONSTER:'M',random,random
+MONSTER:'M',random,random
+MONSTER:'M',random,random
+MONSTER:'M',random,random
+#
+# The Juiblex level
+#
+MAZE:"juiblex",' '
+FLAGS:noteleport,shortsighted
+INIT_MAP:'.','}',true,true,unlit,false
+# guarantee at least one open spot to ensure successful stair placement
+GEOMETRY:left,bottom
+MAP
+}}}}}}}}
+}}...}}}
+}}}...}}
+}}}}.}}}
+}}}}}}}}
+ENDMAP
+OBJECT:'`',"boulder",random
+GEOMETRY:right,top
+MAP
+}}}}}}}}
+}}}}.}}}
+}}}...}}
+}}...}}}
+}}}}}}}}
+ENDMAP
+OBJECT:'`',"boulder",random
+# lair
+GEOMETRY:center,center
+MAP
+..}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.}}}}}..
+.}}}.}}}}}..}}}..}}}}}..}}}..}}}}}..}}}..}}}}}.}}}.
+}}}...}}..}}.}.}}.}}.}}}...}}}.}}}..}}}..}}}}...}}}
+.}}}.}}.}}}.}}.}}.}}...}}.}}.....}}.....}....}.}}}.
+..}}}..}}}.}}.}}.}}..}}.....}}.}}}.}}.}}}}}}}}}}}..
+.}}}..}}}}}.}}.}}.}}...}}}}}.....}}.}}}}}}.....}}}.
+}}}..}}...}}..}}.}}}.}}}...}}}.}}}.}.}}}}..P.P..}}}
+}}.}}}}...}}}}}.}...}}}..P..}}}.}.}}}.}}}}.....}}}}
+}.}}}}.}}.}..}.}}}}}}}..P.P..}}}.}}}.}}..}}...}}}}.
+.}}}}.}}}}....}}}}}.}}}..P..}}}.}}}}.}}..}}...}}}.}
+}}}}..}}.}}..}}}}...}}}}...}}}.}}}}}.}}}}.}}}}}}.}}
+}}}...}}...}}}..}}}}}}}}}}}}.....}}}}.}}...}..}.}}}
+.}}}..}}.}}}}....}}..}}}..}}.....}}}}.}}}.}....}}}.
+..}}}.}}}}..}}..}}..}}..}}..}}.}}}..}.}..}}}..}}}..
+.}}}.}}}}....}}}}..}}....}}}}}}}...}}}....}}}}.}}}.
+}}}...}}}....}}}..}}}....}}}..}}...}}}....}}}...}}}
+.}}}.}}}}}..}}}..}}}}}..}}}..}}}}}..}}}..}}}}}.}}}.
+..}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.}}}}}..
+ENDMAP
+# Random registers
+RANDOM_MONSTERS:'j','b','P','F'
+RANDOM_PLACES:(04,02),(46,02),(04,15),(46,15)
+# Dungeon description
+REGION:(00,00,50,17),unlit,"swamp"
+MAZEWALK:(00,09),west
+MAZEWALK:(50,08),east
+STAIR:levregion(01,00,11,20),(0,0,50,17),down
+STAIR:levregion(69,00,79,20),(0,0,50,17),up
+BRANCH:levregion(01,00,11,20),(0,0,50,17)
+TELEPORT_REGION:levregion(01,00,11,20),(0,0,50,17),up
+TELEPORT_REGION:levregion(69,00,79,20),(0,0,50,17),down
+FOUNTAIN:place[0]
+MONSTER:'m',"giant mimic",place[1],m_feature "fountain"
+MONSTER:'m',"giant mimic",place[2],m_feature "fountain"
+MONSTER:'m',"giant mimic",place[3],m_feature "fountain"
+# The demon of the swamp
+MONSTER:'&',"Juiblex",(25,08)
+# And a couple demons
+MONSTER:'i',"lemure",(43,08)
+MONSTER:'i',"lemure",(44,08)
+MONSTER:'i',"lemure",(45,08)
+# Some liquids and gems
+OBJECT:'*',random,(43,06)
+OBJECT:'*',random,(45,06)
+OBJECT:'!',random,(43,09)
+OBJECT:'!',random,(44,09)
+OBJECT:'!',random,(45,09)
+# And lots of blobby monsters
+MONSTER:monster[0],random,(25,06)
+MONSTER:monster[1],random,(24,07)
+MONSTER:monster[2],random,(26,07)
+MONSTER:monster[3],random,(23,08)
+MONSTER:monster[3],random,(27,08)
+MONSTER:monster[2],random,(24,09)
+MONSTER:monster[1],random,(26,09)
+MONSTER:monster[0],random,(25,10)
+MONSTER:'j',random,random
+MONSTER:'j',random,random
+MONSTER:'j',random,random
+MONSTER:'j',random,random
+MONSTER:'P',random,random
+MONSTER:'P',random,random
+MONSTER:'P',random,random
+MONSTER:'P',random,random
+MONSTER:'b',random,random
+MONSTER:'b',random,random
+MONSTER:'b',random,random
+MONSTER:'F',random,random
+MONSTER:'F',random,random
+MONSTER:'F',random,random
+MONSTER:'m',random,random
+MONSTER:'m',random,random
+MONSTER:';',"jellyfish",random
+MONSTER:';',"jellyfish",random
+# Some random objects
+OBJECT:'!',random,random
+OBJECT:'!',random,random
+OBJECT:'!',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'`',"boulder",random
+# Some traps
+TRAP:"sleep gas",random
+TRAP:"sleep gas",random
+TRAP:"anti magic",random
+TRAP:"anti magic",random
+TRAP:"magic",random
+TRAP:"magic",random
+#
+# The Orcus Level
+#
+MAZE:"orcus",random
+FLAGS: noteleport,shortsighted
+GEOMETRY:right,center
+# A ghost town
+MAP
+.|....|....|....|..............|....|........
+.|....|....|....|..............|....|........
+.|....|....|....|--...-+-------|.............
+.|....|....|....|..............+.............
+.|.........|....|..............|....|........
+.--+-...-+----+--....-------...--------.-+---
+.....................|.....|.................
+.....................|.....|.................
+.--+----....-+---....|.....|...----------+---
+.|....|....|....|....---+---...|......|......
+.|.........|....|..............|......|......
+.----...---------.....-----....+......|......
+.|........................|....|......|......
+.----------+-...--+--|....|....----------+---
+.|....|..............|....+....|.............
+.|....+.......|......|....|....|.............
+.|....|.......|......|....|....|.............
+ENDMAP
+MAZEWALK:(00,06),west
+# Entire main area
+REGION:(01,00,44,16),unlit,"ordinary"
+STAIR:(33,15),down
+STAIR:levregion(01,00,12,20),levregion(20,01,70,20),up
+BRANCH:levregion(01,00,12,20),levregion(20,01,70,20)
+TELEPORT_REGION:levregion(01,00,12,20),levregion(20,01,70,20)
+# Wall "ruins"
+OBJECT:'`',"boulder",(19,02)
+OBJECT:'`',"boulder",(20,02)
+OBJECT:'`',"boulder",(21,02)
+OBJECT:'`',"boulder",(36,02)
+OBJECT:'`',"boulder",(36,03)
+OBJECT:'`',"boulder",(06,04)
+OBJECT:'`',"boulder",(05,05)
+OBJECT:'`',"boulder",(06,05)
+OBJECT:'`',"boulder",(07,05)
+OBJECT:'`',"boulder",(39,05)
+OBJECT:'`',"boulder",(08,08)
+OBJECT:'`',"boulder",(09,08)
+OBJECT:'`',"boulder",(10,08)
+OBJECT:'`',"boulder",(11,08)
+OBJECT:'`',"boulder",(06,10)
+OBJECT:'`',"boulder",(05,11)
+OBJECT:'`',"boulder",(06,11)
+OBJECT:'`',"boulder",(07,11)
+OBJECT:'`',"boulder",(21,11)
+OBJECT:'`',"boulder",(21,12)
+OBJECT:'`',"boulder",(13,13)
+OBJECT:'`',"boulder",(14,13)
+OBJECT:'`',"boulder",(15,13)
+OBJECT:'`',"boulder",(14,14)
+# Doors
+DOOR:closed,(23,02)
+DOOR:open,(31,03)
+DOOR:nodoor,(03,05)
+DOOR:closed,(09,05)
+DOOR:closed,(14,05)
+DOOR:closed,(41,05)
+DOOR:open,(03,08)
+DOOR:nodoor,(13,08)
+DOOR:open,(41,08)
+DOOR:closed,(24,09)
+DOOR:closed,(31,11)
+DOOR:open,(11,13)
+DOOR:closed,(18,13)
+DOOR:closed,(41,13)
+DOOR:open,(26,14)
+DOOR:closed,(06,15)
+# Special rooms
+ALTAR:(24,07),noalign,sanctum
+REGION:(22,12,25,16),unlit,"morgue"
+REGION:(32,09,37,12),lit,"shop"
+REGION:(12,00,15,04),lit,"shop"
+# Some traps.
+TRAP:"spiked pit", random
+TRAP:"sleep gas", random
+TRAP:"anti magic", random
+TRAP:"fire", random
+TRAP:"fire", random
+TRAP:"fire", random
+TRAP:"magic", random
+TRAP:"magic", random
+# Some random objects
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# The resident nasty
+MONSTER:'&',"Orcus",(33,15)
+# And its preferred companions
+MONSTER:'Z',"human zombie",(32,15)
+MONSTER:' ',"shade",(32,14)
+MONSTER:' ',"shade",(32,16)
+MONSTER:'V',"vampire",(35,16)
+MONSTER:'V',"vampire",(35,14)
+MONSTER:'V',"vampire lord",(36,14)
+MONSTER:'V',"vampire lord",(36,15)
+# Randomly placed companions
+MONSTER:'Z',"skeleton",random
+MONSTER:'Z',"skeleton",random
+MONSTER:'Z',"skeleton",random
+MONSTER:'Z',"skeleton",random
+MONSTER:'Z',"skeleton",random
+MONSTER:' ',"shade",random
+MONSTER:' ',"shade",random
+MONSTER:' ',"shade",random
+MONSTER:' ',"shade",random
+MONSTER:'Z',"giant zombie",random
+MONSTER:'Z',"giant zombie",random
+MONSTER:'Z',"giant zombie",random
+MONSTER:'Z',"ettin zombie",random
+MONSTER:'Z',"ettin zombie",random
+MONSTER:'Z',"ettin zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'Z',"human zombie",random
+MONSTER:'V',"vampire",random
+MONSTER:'V',"vampire",random
+MONSTER:'V',"vampire",random
+MONSTER:'V',"vampire lord",random
+MONSTER:'V',"vampire lord",random
+# A few more for the party
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+#
+# The Asmodeus Level
+#
+MAZE:"asmodeus",random
+FLAGS: noteleport
+# First part
+GEOMETRY:half-left,center
+MAP
+---------------------
+|.............|.....|
+|.............S.....|
+|---+------------...|
+|.....|.........|-+--
+|..---|.........|....
+|..|..S.........|....
+|..|..|.........|....
+|..|..|.........|-+--
+|..|..-----------...|
+|..S..........|.....|
+---------------------
+ENDMAP
+STAIR:levregion(01,00,6,20),levregion(6,1,70,16),up
+BRANCH:levregion(01,00,6,20),levregion(6,1,70,16)
+TELEPORT_REGION:levregion(01,00,6,20),levregion(6,1,70,16)
+
+# Doors
+DOOR:closed,(04,03)
+DOOR:locked,(18,04)
+DOOR:closed,(18,08)
+#
+STAIR:(13,07),down
+# Non diggable walls
+NON_DIGGABLE:(00,00,20,11)
+# Entire main area
+REGION:(01,01,20,10),unlit,"ordinary"
+# The fellow in residence
+MONSTER:'&',"Asmodeus",(12,07)
+# Some random weapons and armor.
+OBJECT:'[',random,random
+OBJECT:'[',random,random
+OBJECT:')',random,random
+OBJECT:')',random,random
+OBJECT:'*',random,random
+OBJECT:'!',random,random
+OBJECT:'!',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+# Some traps.
+TRAP:"spiked pit", (05,02)
+TRAP:"fire", (08,06)
+TRAP:"sleep gas", random
+TRAP:"anti magic", random
+TRAP:"fire", random
+TRAP:"magic", random
+TRAP:"magic", random
+# Random monsters.
+MONSTER:' ',"ghost",(11,07)
+MONSTER:'&',"horned devil",(10,05)
+MONSTER:'L',random,random
+# Some Vampires for good measure
+MONSTER:'V',random,random
+MONSTER:'V',random,random
+MONSTER:'V',random,random
+# Second part
+GEOMETRY:half-right,center
+MAP
+---------------------------------
+................................|
+................................+
+................................|
+---------------------------------
+ENDMAP
+MAZEWALK:(32,02),east
+# Non diggable walls
+NON_DIGGABLE:(00,00,32,04)
+DOOR:closed,(32,02)
+MONSTER:'&',random,random
+MONSTER:'&',random,random
+MONSTER:'&',random,random
+TRAP:"anti magic", random
+TRAP:"fire", random
+TRAP:"magic", random
+
+#
+# The Baalzebub level
+#
+MAZE:"baalz",random
+FLAGS: noteleport
+GEOMETRY:right,center
+MAP
+-------------------------------------------------
+|                    ---               ----      
+|          ----      |   ------------  |         
+| ------      |  --------|..........|---         
+| |....|  -------|...........--------------      
+---....|--|..................S............|----  
+....--....S..----------------|............S...|  
+---....|--|..................|............|----  
+| |....|  -------|...........-----S--------      
+| ------      |  --------|..........|---         
+|          ----     |    ------------  |         
+|                   ---                ----      
+-------------------------------------------------
+ENDMAP
+STAIR:levregion(01,00,15,20),levregion(15,1,70,16),up
+BRANCH:levregion(01,00,15,20),levregion(15,1,70,16)
+TELEPORT_REGION:levregion(01,00,15,20),levregion(15,1,70,16)
+NON_DIGGABLE:(00,00,46,12)
+MAZEWALK:(00,06),west
+STAIR:(44,06),down
+# The fellow in residence
+MONSTER:'&',"Baalzebub",(35,06)
+# Some random weapons and armor.
+OBJECT:'[',random,random
+OBJECT:'[',random,random
+OBJECT:')',random,random
+OBJECT:')',random,random
+OBJECT:'*',random,random
+OBJECT:'!',random,random
+OBJECT:'!',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+# Some traps.
+TRAP:"spiked pit", random
+TRAP:"fire", random
+TRAP:"sleep gas", random
+TRAP:"anti magic", random
+TRAP:"fire", random
+TRAP:"magic", random
+TRAP:"magic", random
+# Random monsters.
+MONSTER:' ',"ghost",(37,07)
+MONSTER:'&',"horned devil",(32,05)
+MONSTER:'&',"barbed devil",(38,07)
+MONSTER:'L',random,random
+# Some Vampires for good measure
+MONSTER:'V',random,random
+MONSTER:'V',random,random
+MONSTER:'V',random,random
+#
+# The Sanctum Level
+#
+MAZE:"sanctum", ' '
+FLAGS: noteleport,hardfloor,nommap
+GEOMETRY:center,center
+MAP
+----------------------------------------------------------------------------
+|             --------------                                               |
+|             |............|             -------                           |
+|       -------............-----         |.....|                           |
+|       |......................|        --.....|            ---------      |
+|    ----......................---------|......----         |.......|      |
+|    |........---------..........|......+.........|     ------+---..|      |
+|  ---........|.......|..........--S----|.........|     |........|..|      |
+|  |..........|.......|.............|   |.........-------..----------      |
+|  |..........|.......|..........----   |..........|....|..|......|        |
+|  |..........|.......|..........|      --.......----+---S---S--..|        |
+|  |..........---------..........|       |.......|.............|..|        |
+|  ---...........................|       -----+-------S---------S---       |
+|    |...........................|          |...| |......|    |....|--     |
+|    ----.....................----          |...---....---  ---......|     |
+|       |.....................|             |..........|    |.....----     |
+|       -------...........-----             --...-------    |.....|        |
+|             |...........|                  |...|          |.....|        |
+|             -------------                  -----          -------        |
+----------------------------------------------------------------------------
+ENDMAP
+REGION:(15,07,21,10),lit,"temple"
+ALTAR:(18,08),noalign,sanctum
+REGION:(41,06,48,11),unlit,"morgue",filled,true
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Invisible barrier separating the left & right halves of the level
+NON_PASSWALL:(37,00,39,19)
+# Doors
+DOOR:closed,(40,06)
+DOOR:locked,(62,06)
+DOOR:closed,(46,12)
+DOOR:closed,(53,10)
+# Surround the temple with fire
+TRAP:"fire",(13,05)
+TRAP:"fire",(14,05)
+TRAP:"fire",(15,05)
+TRAP:"fire",(16,05)
+TRAP:"fire",(17,05)
+TRAP:"fire",(18,05)
+TRAP:"fire",(19,05)
+TRAP:"fire",(20,05)
+TRAP:"fire",(21,05)
+TRAP:"fire",(22,05)
+TRAP:"fire",(23,05)
+TRAP:"fire",(13,12)
+TRAP:"fire",(14,12)
+TRAP:"fire",(15,12)
+TRAP:"fire",(16,12)
+TRAP:"fire",(17,12)
+TRAP:"fire",(18,12)
+TRAP:"fire",(19,12)
+TRAP:"fire",(20,12)
+TRAP:"fire",(21,12)
+TRAP:"fire",(22,12)
+TRAP:"fire",(23,12)
+TRAP:"fire",(13,06)
+TRAP:"fire",(13,07)
+TRAP:"fire",(13,08)
+TRAP:"fire",(13,09)
+TRAP:"fire",(13,10)
+TRAP:"fire",(13,11)
+TRAP:"fire",(23,06)
+TRAP:"fire",(23,07)
+TRAP:"fire",(23,08)
+TRAP:"fire",(23,09)
+TRAP:"fire",(23,10)
+TRAP:"fire",(23,11)
+# Some traps.
+TRAP:"spiked pit", random
+TRAP:"fire", random
+TRAP:"sleep gas", random
+TRAP:"anti magic", random
+TRAP:"fire", random
+TRAP:"magic", random
+# Some random objects
+OBJECT:'[',random,random
+OBJECT:'[',random,random
+OBJECT:'[',random,random
+OBJECT:'[',random,random
+OBJECT:')',random,random
+OBJECT:')',random,random
+OBJECT:'*',random,random
+OBJECT:'!',random,random
+OBJECT:'!',random,random
+OBJECT:'!',random,random
+OBJECT:'!',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+# Some monsters.
+MONSTER:'&',"horned devil",(14,12),hostile
+MONSTER:'&',"barbed devil",(18,08),hostile
+MONSTER:'&',"erinys",(10,04),hostile
+MONSTER:'&',"marilith",(07,09),hostile
+MONSTER:'&',"nalfeshnee",(27,08),hostile
+# Moloch's horde
+MONSTER:'@',"aligned priest",(20,03),noalign,hostile
+MONSTER:'@',"aligned priest",(15,04),noalign,hostile
+MONSTER:'@',"aligned priest",(11,05),noalign,hostile
+MONSTER:'@',"aligned priest",(11,07),noalign,hostile
+MONSTER:'@',"aligned priest",(11,09),noalign,hostile
+MONSTER:'@',"aligned priest",(11,12),noalign,hostile
+MONSTER:'@',"aligned priest",(15,13),noalign,hostile
+MONSTER:'@',"aligned priest",(17,13),noalign,hostile
+MONSTER:'@',"aligned priest",(21,13),noalign,hostile
+# A few nasties
+MONSTER:'L',random,random
+MONSTER:'L',random,random
+MONSTER:'V',random,random
+MONSTER:'V',random,random
+MONSTER:'V',random,random
+STAIR:(63,15),up
diff --git a/dat/help b/dat/help
new file mode 100644 (file)
index 0000000..00abe24
--- /dev/null
+++ b/dat/help
@@ -0,0 +1,198 @@
+        Welcome to NetHack!                ( description of version 3.4 )
+
+        NetHack is a Dungeons and Dragons like game where you (the adventurer)
+descend into the depths of the dungeon in search of the Amulet of Yendor,
+reputed to be hidden somewhere below the twentieth level.  You begin your
+adventure with a pet that can help you in many ways, and can be trained
+to do all sorts of things.  On the way you will find useful (or useless)
+items, quite possibly with magic properties, and assorted monsters.  You can
+attack a monster by trying to move onto the space a monster is on (but often
+it is much wiser to leave it alone).
+
+        Unlike most adventure games, which give you a verbal description of
+your location, NetHack gives you a visual image of the dungeon level you are
+on.
+
+        NetHack uses the following symbols:
+
+        - and |  The walls of a room, possibly also open doors or a grave.
+        .        The floor of a room or a doorway.
+        #        A corridor, or iron bars, or a tree, or possibly a kitchen
+                 sink (if your dungeon has sinks), or a drawbridge.
+        >        Stairs down: a way to the next level.
+        <        Stairs up: a way to the previous level.
+        @        You (usually), or another human.
+        )        A weapon of some sort.
+        [        A suit or piece of armor.
+        %        Something edible (not necessarily healthy).
+        /        A wand.
+        =        A ring.
+        ?        A scroll.
+        !        A potion.
+        (        Some other useful object (pick-axe, key, lamp...)
+        $        A pile of gold.
+        *        A gem or rock (possibly valuable, possibly worthless).
+        +        A closed door, or a spellbook containing a spell
+                 you can learn.
+        ^        A trap (once you detect it).
+        "        An amulet, or a spider web.
+        0        An iron ball.
+        _        An altar, or an iron chain.
+        {        A fountain.
+        }        A pool of water or moat or a pool of lava.
+        \        An opulent throne.
+        `        A boulder or statue.
+        A to Z, a to z, and several others:  Monsters.
+        I        Invisible or unseen monster's last known location
+
+                 You can find out what a symbol represents by typing
+                 '/' and following the directions to move the cursor
+                 to the symbol in question.  For instance, a 'd' may
+                 turn out to be a dog.
+
+
+y k u   7 8 9   Move commands:
+ \|/     \|/            yuhjklbn: go one step in specified direction
+h-.-l   4-.-6           YUHJKLBN: go in specified direction until you
+ /|\     /|\                        hit a wall or run into something
+b j n   1 2 3           g<dir>:   run in direction <dir> until something
+      numberpad                     interesting is seen
+                        G<dir>,   same, except a branching corridor isn't
+ <  up                  ^<dir>:     considered interesting (the ^ in this
+                                    case means the Control key, not a caret)
+ >  down                m<dir>:   move without picking up objects
+                        F<dir>:   fight even if you don't sense a monster
+                If the number_pad option is set, the number keys move instead.
+                Depending on the platform, Shift number (on the numberpad),
+                Meta number, or Alt number will invoke the YUHJKLBN commands.
+                Control <dir> may or may not work when number_pad is enabled,
+                depending on the platform's capabilities.
+
+Commands:
+        NetHack knows the following commands:
+        ?       Help menu.
+        /       Tell what a symbol represents.  You may choose to specify
+                a location or give a symbol argument.
+        &       Tell what a command does.
+        <       Go up a staircase (if you are standing on it).
+        >       Go down a staircase (if you are standing on it).
+        .       Rest, do nothing for one turn.
+        _       Travel via a shortest-path algorithm to a point on the map 
+        a       Apply (use) a tool (pick-axe, key, lamp...)
+        A       Remove all armor.
+        ^A      Redo the previous command
+        c       Close a door.
+        C       Call (name) an individual monster.
+        d       Drop something.  d7a:  drop seven items of object a.
+        D       Drop multiple items.  This command is implemented in two
+                different ways.  One way is:
+                "D" displays a list of all of your items, from which you can
+                pick and choose what to drop.  A "+" next to an item means
+                that it will be dropped, a "-" means that it will not be
+                dropped.  Toggle an item to be selected/deselected by typing
+                the letter adjacent to its description.  Select all items
+                with "+", deselect all items with "=".  The <SPACEBAR> moves
+                you from one page of the listing to the next.
+                The other way is:
+                "D" will ask the question "What kinds of things do you want
+                to drop? [!%= au]".  You should type zero or more object
+                symbols possibly followed by 'a' and/or 'u'.
+                Da - drop all objects, without asking for confirmation.
+                Du - drop only unpaid objects (when in a shop).
+                D%u - drop only unpaid food.
+        ^D      Kick (for doors, usually).
+        e       Eat food.
+        E       Engrave a message on the floor.
+                E- - write in the dust with your fingers.
+        f       Fire ammunition from quiver.
+        F       Followed by direction, fight a monster (even if you don't
+                sense it).
+        i       Display your inventory.
+        I       Display selected parts of your inventory, as in
+                I* - list all gems in inventory.
+                Iu - list all unpaid items.
+                Ix - list all used up items that are on your shopping bill.
+                I$ - count your money.
+        o       Open a door.
+        O       Review current options and possibly change them.
+                A menu displaying the option settings will be displayed
+                and most can be changed by simply selecting their entry.
+                Options are usually set before the game with a NETHACKOPTIONS
+                environment variable, or via a config file (defaults.nh,
+                NetHack Defaults, nethack.cnf, .nethackrc, etc.), not with 
+                the 'O' command.
+        p       Pay your shopping bill.
+        P       Put on an accessory (ring, amulet, etc).
+        ^P      Repeat last message (subsequent ^P's repeat earlier messages).
+                The behavior can be varied via the msg_window option.
+        q       Drink (quaff) something (potion, water, etc).
+        Q       Select ammunition for quiver.
+        r       Read a scroll or spellbook.
+        R       Remove an accessory (ring, amulet, etc).
+        ^R      Redraw the screen.
+        s       Search for secret doors and traps around you.
+        S       Save the game.
+        t       Throw an object or shoot a projectile.
+        T       Take off armor.
+        ^T      Teleport, if you are able.
+        v       Displays the version number.
+        V       Display a longer identification of the version, including the
+                history of the game.
+        w       Wield weapon.  w- means wield nothing, use bare hands.
+        W       Wear armor.
+        x       Swap wielded and secondary weapons.
+        X       Switch the game to explore (discovery) mode.
+        ^X      Show your attributes.
+        z       Zap a wand.
+        Z       Cast a spell.
+        ^Z      Suspend the game.
+        :       Look at what is here.
+        ;       Look at what is somewhere else.
+        ,       Pick up some things.
+        @       Toggle the pickup option.
+        ^       Ask for the type of a trap you found earlier.
+        )       Tell what weapon you are wielding.
+        [       Tell what armor you are wearing.
+        =       Tell what rings you are wearing.
+        "       Tell what amulet you are wearing.
+        (       Tell what tools you are using.
+        *       Tell what equipment you are using; combines the preceding five.
+        $       Count your gold pieces.
+        +       List the spells you know; also rearrange them if desired.
+        \       Show what types of objects have been discovered.
+        !       Escape to a shell, if supported in your version and OS.
+        #       Introduces one of the "extended" commands.  To get a list of
+                the commands you can use with "#" type "#?".  The extended
+                commands you can use depends upon what options the game was
+                compiled with, along with your class and what type of monster
+                you most closely resemble at a given moment.  If your keyboard
+                has a meta key (which, when pressed in combination with another
+                key, modifies it by setting the 'meta' (8th, or 'high') bit),
+                these extended commands can be invoked by meta-ing the first
+                letter of the command.  An alt key may have a similar effect.
+
+        If the "number_pad" option is on, some additional letter commands
+        are available:
+
+        h       displays the help menu, like '?'
+        j       Jump to another location.
+        k       Kick (for doors, usually).
+        l       Loot a box on the floor.
+        n       followed by number of times to repeat the next command
+        N       Name an object or type of object.
+        u       Untrap a trapped object or door.
+
+        You can put a number before a command to repeat it that many times,
+        as in "40." or "20s.".  If you have the number_pad option set, you
+        must type 'n' to prefix the count, as in "n40." or "n20s".
+
+
+        Some information is displayed on the bottom line or perhaps in a
+        box, depending on the platform you are using.  You see your
+        attributes, your alignment, what dungeon level you are on, how many
+        hit points you have now (and will have when fully recovered), what
+        your armor class is (the lower the better), your experience level,
+        and the state of your stomach.  Optionally, you may or may not see
+        other information such as spell points, how much gold you have, etc.
+
+        Have Fun, and Happy Hacking!
diff --git a/dat/hh b/dat/hh
new file mode 100644 (file)
index 0000000..e61f564
--- /dev/null
+++ b/dat/hh
@@ -0,0 +1,116 @@
+y k u   7 8 9   Move commands:
+ \|/     \|/            yuhjklbn: go one step in specified direction
+h-.-l   4-.-6           YUHJKLBN: go in specified direction until you
+ /|\     /|\                        hit a wall or run into something
+b j n   1 2 3           g<dir>:   run in direction <dir> until something
+      numberpad                     interesting is seen
+                        G<dir>,   same, except a branching corridor isn't
+ <  up                  ^<dir>:     considered interesting (the ^ in this
+                                    case means the Control key, not a caret)
+ >  down                m<dir>:   move without picking up objects/fighting
+                        F<dir>:   fight even if you don't sense a monster
+                If the number_pad option is set, the number keys move instead.
+                Depending on the platform, Shift number (on the numberpad),
+                Meta number, or Alt number will invoke the YUHJKLBN commands.
+                Control <dir> may or may not work when number_pad is enabled,
+                depending on the platform's capabilities.
+
+General commands:
+?       help    display one of several informative texts
+#quit   quit    end the game without saving current game
+S       save    save the game (to be continued later) and exit
+!       sh      escape to some SHELL (if allowed)
+^Z      suspend suspend the game (independent of your current suspend char)
+O       options set options
+/       whatis  tell what a map symbol represents
+\       known   display list of what's been discovered
+v       version display version number
+V       history display game history
+X       explore switch the game to explore (discovery) mode
+^A      again   redo the previous command (^A denotes the keystroke CTRL-A)
+^R      redraw  redraw the screen
+^P      prevmsg repeat previous message (subsequent ^P's repeat earlier ones)
+#               introduces an extended command (#? for a list of them)
+
+Game commands:
+^D      kick    kick (a door, or something else)
+^T      'port   teleport (if you can)
+^X      show    show your attributes
+a       apply   apply or use a tool (pick-axe, key, camera, etc.)
+A       armor   take off all armor
+c       close   close a door
+C       call    name an individual monster (ex. baptize your dog)
+d       drop    drop an object.  d7a:  drop seven items of object 'a'
+D       Drop    drop selected types of objects
+e       eat     eat something
+E       engrave write a message in the dust on the floor  (E-  use fingers)
+f       fire    fire ammunition from quiver
+F       fight   followed by direction, fight a monster
+i       invent  list your inventory (all objects you are carrying)
+I       Invent  list selected parts of your inventory
+                Iu: list unpaid objects
+                Ix: list unpaid but used up items
+                I$: count your money
+o       open    open a door
+p       pay     pay your bill (in a shop)
+P       puton   put on an accessory (ring, amulet, etc)
+q       quaff   drink something (potion, water, etc)
+Q       quiver  select ammunition for quiver
+r       read    read a scroll or spellbook
+R       remove  remove an accessory (ring, amulet, etc)
+s       search  search for secret doors, hidden traps and monsters
+t       throw   throw or shoot a weapon
+T       takeoff take off some armor
+w       wield   wield a weapon  (w-  wield nothing)
+W       wear    put on some armor
+x       xchange swap wielded and secondary weapons
+z       zap     zap a wand
+Z       Zap     cast a spell
+<       up      go up the stairs
+>       down    go down the stairs
+^       trap_id identify a previously found trap
+),[,=,",(       ask for current items of specified symbol in use
+*               ask for combination of ),[,=,",( all at once
+$       gold    count your gold
++       spells  list the spells you know; also rearrange them if desired
+_       travel  move via a shortest-path algorithm to a point on the map 
+.       rest    wait a moment
+,       pickup  pick up all you can carry
+@               toggle "pickup" (auto pickup) option on and off
+:       look    look at what is here
+;       farlook look at what is somewhere else by selecting a map symbol
+
+Keyboards that have a meta key can also use these extended commands
+via the meta modifier instead of the # prefix:
+
+M-?             Display extended command help (if the platform allows this)
+M-2     twoweapon toggle two-weapon combat (unless number_pad is enabled)
+M-a     adjust  adjust inventory letters
+M-c     chat    talk to someone
+M-d     dip     dip an object into something
+M-e     enhance advance or check weapons skills
+M-f     force   force a lock
+M-i     invoke  invoke an object's special powers
+M-j     jump    jump to another location
+M-l     loot    loot a box on the floor
+M-m     monster use a monster's special ability
+M-n     name    name an item or type of object
+M-o     offer   offer a sacrifice to the gods
+M-p     pray    pray to the gods for help
+M-q     quit    stop playing
+M-r     rub     rub a lamp or a stone
+M-s     sit     sit down
+M-t     turn    turn undead
+M-u     untrap  untrap something
+M-v     version print compile time options for this version
+M-w     wipe    wipe off your face
+
+If the "number_pad" option is on, these additional variants are available:
+
+n               followed by number of times to repeat the next command
+h       help    display one of several informative texts, like '?'
+j       jump    jump to another location
+k       kick    kick something (usually a door)
+l       loot    loot a box on the floor
+N       name    name an item or type of object
+u       untrap  untrap something (usually a trapped object)
diff --git a/dat/history b/dat/history
new file mode 100644 (file)
index 0000000..0f6ef01
--- /dev/null
@@ -0,0 +1,199 @@
+NetHack History file for release 3.4
+
+Behold, mortal, the origins of NetHack...
+
+Jay Fenlason wrote the original Hack with help from Kenny Woodland,
+Mike Thome, and Jon Payne.
+
+Andries Brouwer did a major re-write, transforming Hack into a very different
+game, and published (at least) three versions (1.0.1, 1.0.2, and 1.0.3) for
+UNIX(tm) machines to the Usenet.
+
+Don G. Kneller ported Hack 1.0.3 to Microsoft(tm) C and MS-DOS(tm), producing
+PC HACK 1.01e, added support for DEC Rainbow graphics in version 1.03g, and
+went on to produce at least four more versions (3.0, 3.2, 3.51, and 3.6).
+
+R. Black ported PC HACK 3.51 to Lattice(tm) C and the Atari 520/1040ST,
+producing ST Hack 1.03.
+
+Mike Stephenson merged these various versions back together, incorporating
+many of the added features, and produced NetHack version 1.4.  He then
+coordinated a cast of thousands in enhancing and debugging NetHack 1.4 and
+released NetHack versions 2.2 and 2.3.
+Later, Mike coordinated a major rewrite of the game, heading a team which
+included Ken Arromdee, Jean-Christophe Collet, Steve Creps, Eric Hendrickson,
+Izchak Miller, Eric S. Raymond, John Rupley, Mike Threepoint, and Janet Walz,
+to produce NetHack 3.0c.  The same group subsequently released ten patch-
+level revisions and updates of 3.0.
+
+NetHack 3.0 was ported to the Atari by Eric R. Smith, to OS/2 by Timo
+Hakulinen, and to VMS by David Gentzel.  The three of them and Kevin Darcy
+later joined the main development team to produce subsequent revisions of
+3.0.
+
+Olaf Seibert ported NetHack 2.3 and 3.0 to the Amiga.  Norm Meluch, Stephen
+Spackman and Pierre Martineau designed overlay code for PC NetHack 3.0.
+Johnny Lee ported NetHack 3.0 to the Macintosh.  Along with various other
+Dungeoneers, they continued to enhance the PC, Macintosh, and Amiga ports
+through the later revisions of 3.0.
+Headed by Mike Stephenson and coordinated by Izchak Miller and Janet Walz,
+the development team which now included Ken Arromdee, David Cohrs,
+Jean-Christophe Collet, Kevin Darcy, Matt Day, Timo Hakulinen, Steve Linhart,
+Dean Luick, Pat Rankin, Eric Raymond, and Eric Smith undertook a radical
+revision of 3.0.  They re-structured the game's design, and re-wrote major
+parts of the code.  They added multiple dungeons, a new display, special
+individual character quests, a new endgame and many other new features, and
+produced NetHack 3.1.
+
+Ken Lorber, Gregg Wonderly and Greg Olson, with help from Richard Addison,
+Mike Passaretti, and Olaf Seibert, developed NetHack 3.1 for the Amiga.
+
+Norm Meluch and Kevin Smolkowski, with help from Carl Schelin, Stephen
+Spackman, Steve VanDevender, and Paul Winner, ported NetHack 3.1 to the PC.
+
+Jon W{tte and Hao-yang Wang, with help from Ross Brown, Mike Engber, David
+Hairston, Michael Hamel, Jonathan Handler, Johnny Lee, Tim Lennan, Rob Menke,
+and Andy Swanson developed NetHack 3.1 for the Macintosh, porting it for
+MPW.  Building on their development, Barton House added a Think C port.  
+
+Timo Hakulinen ported NetHack 3.1 to OS/2.  Eric Smith ported NetHack 3.1
+to the Atari.  Pat Rankin, with help from Joshua Delahunty, is responsible
+for the VMS version of NetHack 3.1.  Michael Allison ported NetHack 3.1 to
+Windows NT.
+
+Dean Luick, with help from David Cohrs, developed NetHack 3.1 for X11.
+Warwick Allison wrote a tiled version of NetHack for the Atari;
+he later contributed the tiles to the DevTeam and tile support was
+then added to other platforms.
+
+The 3.2 development team, comprised of Michael Allison, Ken Arromdee, David
+Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, Timo Hakulinen, Steve
+Linhart, Dean Luick, Pat Rankin, Eric Smith, Mike Stephenson, Janet Walz, and
+Paul Winner, released version 3.2 in April of 1996.
+
+Version 3.2 marked the tenth anniversary of the formation of the development
+team.  In a testament to their dedication to the game, all thirteen members
+of the original development team remained on the team at the start of work
+on that release.  During the interval between the release of 3.1.3 and 3.2,
+one of the founding members of the development team, Dr. Izchak Miller,
+passed away.  That release of the game was dedicated to him by the
+development and porting teams.
+
+Version 3.2 proved to be more stable than previous versions.  Many bugs
+were fixed, abuses eliminated, and game features tuned for better game
+play.
+
+During the lifespan of NetHack 3.1 and 3.2, several enthusiasts of the game
+added their own modifications to the game and made these "variants" publicly
+available:
+
+Tom Proudfoot and Yuval Oren created NetHack++, which was quickly renamed
+NetHack--.  Working independently, Stephen White wrote NetHack Plus.
+Tom Proudfoot later merged NetHack Plus and his own NetHack-- to produce
+SLASH.  Larry Stewart-Zerba and Warwick Allison improved the spellcasting
+system with the Wizard Patch.  Warwick Allison also ported NetHack to use
+the Qt interface.
+
+Warren Cheung combined SLASH with the Wizard Patch to produce Slash'em, and
+with the help of Kevin Hugo, added more features.  Kevin later joined the
+DevTeam and incorporated the best of these ideas in NetHack 3.3.
+
+The final update to 3.2 was the bug fix release 3.2.3, which was released
+simultaneously with 3.3.0 in December 1999 just in time for the Year 2000.
+
+The 3.3 development team, consisting of Michael Allison, Ken Arromdee, 
+David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, Timo Hakulinen, 
+Kevin Hugo, Steve Linhart, Ken Lorber, Dean Luick, Pat Rankin, Eric Smith, 
+Mike Stephenson, Janet Walz, and Paul Winner, released 3.3.0 in 
+December 1999 and 3.3.1 in August of 2000.
+
+Version 3.3 offered many firsts. It was the first version to separate race 
+and profession. The Elf class was removed in preference to an elf race, 
+and the races of dwarves, gnomes, and orcs made their first appearance in 
+the game alongside the familiar human race.  Monk and Ranger roles joined 
+Archeologists, Barbarians, Cavemen, Healers, Knights, Priests, Rogues, 
+Samurai, Tourists, Valkyries and of course, Wizards.  It was also the first
+version to allow you to ride a steed, and was the first version to have a
+publicly available web-site listing all the bugs that had been discovered.
+Despite that constantly growing bug list, 3.3 proved stable enough to last
+for more than a year and a half.
+
+
+The 3.4 development team initially consisted of Michael Allison, Ken Arromdee,
+David Cohrs, Jessie Collet, Kevin Hugo, Ken Lorber, Dean Luick, Pat Rankin,
+Mike Stephenson, Janet Walz, and Paul Winner, with Warwick Allison joining
+just before the release of NetHack 3.4.0 in March 2002.
+
+As with version 3.3, various people contributed to the game as a whole as
+well as supporting ports on the different platforms that NetHack runs on:
+
+Pat Rankin maintained 3.4 for VMS.
+
+Michael Allison maintained NetHack 3.4 for the MS-DOS platform.  
+Paul Winner and Yitzhak Sapir provided encouragement.
+
+Dean Luick, Mark Modrall, and Kevin Hugo maintained and enhanced the
+Macintosh port of 3.4.
+
+Michael Allison, David Cohrs, Alex Kompel, Dion Nicolaas, and Yitzhak Sapir 
+maintained and enhanced 3.4 for the Microsoft Windows platform. Alex Kompel 
+contributed a new graphical interface for the Windows port. Alex Kompel also
+contributed a Windows CE port for 3.4.1.
+
+Ron Van Iwaarden maintained 3.4 for OS/2.
+
+Janne Salmijarvi and Teemu Suikki maintained and enhanced the 
+Amiga port of 3.4 after Janne Salmijarvi resurrected it for 3.3.1.
+
+Christian `Marvin' Bressler maintained 3.4 for the Atari after he
+resurrected it for 3.3.1.
+
+There is a NetHack web site maintained by Ken Lorber at http://www.nethack.org/.
+
+                          - - - - - - - - - -
+
+From time to time, some depraved individual out there in netland sends a
+particularly intriguing modification to help out with the game.  The Gods of
+the Dungeon sometimes make note of the names of the worst of these miscreants
+in this, the list of Dungeoneers:
+
+    Adam Aronow               Izchak Miller             Mike Stephenson
+    Alex Kompel               J. Ali Harlow             Norm Meluch
+    Andreas Dorn              Janet Walz                Olaf Seibert
+    Andy Church               Janne Salmijarvi          Pasi Kallinen
+    Andy Swanson              Jean-Christophe Collet    Pat Rankin
+    Ari Huttunen              Jochen Erwied             Paul Winner
+    Barton House              John Kallen               Pierre Martineau
+    Benson I. Margulies       John Rupley               Ralf Brown
+    Bill Dyer                 John S. Bien              Ray Chason
+    Boudewijn Waijers         Johnny Lee                Richard Addison
+    Bruce Cox                 Jon W{tte                 Richard Beigel
+    Bruce Holloway            Jonathan Handler          Richard P. Hughey
+    Bruce Mewborne            Joshua Delahunty          Rob Menke
+    Carl Schelin              Keizo Yamamoto            Robin Johnson
+    Chris Russo               Ken Arnold                Roderick Schertler
+    David Cohrs               Ken Arromdee              Roland McGrath
+    David Damerell            Ken Lorber                Ron Van Iwaarden
+    David Gentzel             Ken Washikita             Ronnen Miller
+    David Hairston            Kevin Darcy               Ross Brown
+    Dean Luick                Kevin Hugo                Sascha Wostmann
+    Del Lamb                  Kevin Sitze               Scott Bigham
+    Deron Meranda             Kevin Smolkowski          Scott R. Turner
+    Dion Nicolaas             Kevin Sweet               Stephen Spackman
+    Dylan O'Donnell           Lars Huttar               Stephen White
+    Eric Backus               Malcolm Ryan              Steve Creps
+    Eric Hendrickson          Mark Gooderum             Steve Linhart
+    Eric R. Smith             Mark Modrall              Steve VanDevender
+    Eric S. Raymond           Marvin Bressler           Teemu Suikki
+    Erik Andersen             Matthew Day               Tim Lennan
+    Frederick Roeber          Merlyn LeRoy              Timo Hakulinen
+    Gil Neiger                Michael Allison           Tom Almy
+    Greg Laskin               Michael Feir              Tom West
+    Greg Olson                Michael Hamel             Warren Cheung
+    Gregg Wonderly            Michael Sokolov           Warwick Allison
+    Hao-yang Wang             Mike Engber               Yitzhak Sapir
+    Helge Hafting             Mike Gallop               
+    Irina Rempt-Drijfhout     Mike Passaretti           
+
diff --git a/dat/knox.des b/dat/knox.des
new file mode 100644 (file)
index 0000000..8ff123a
--- /dev/null
@@ -0,0 +1,104 @@
+#      SCCS Id: @(#)knox.des   3.4     1994/08/20
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1992 by Izchak Miller
+# NetHack may be freely redistributed.  See license for details.
+#
+MAZE:"knox",' '
+FLAGS: noteleport
+GEOMETRY:center,center
+MAP
+----------------------------------------------------------------------------
+| |........|...............................................................|
+| |........|.................................................------------..|
+| -------+--.................................................|..........|..|
+|       |........}}}}}}}....................}}}}}}}..........|..........|..|
+|       |........}-----}....................}-----}..........--+--+--...|..|
+|     ---........}|...|}}}}}}}}}}}}}}}}}}}}}}|...|}.................|...|..|
+|     |..........}---S------------------------S---}.................|...|..|
+|     |..........}}}|...............|..........|}}}.................+...|..|
+| -------..........}|...............S..........|}...................|...|..|
+| |.....|..........}|...............|......\...S}...................|...|..|
+| |.....+........}}}|...............|..........|}}}.................+...|..|
+| |.....|........}---S------------------------S---}.................|...|..|
+| |.....|........}|...|}}}}}}}}}}}}}}}}}}}}}}|...|}.................|...|..|
+| |..-S----......}-----}....................}-----}..........--+--+--...|..|
+| |..|....|......}}}}}}}....................}}}}}}}..........|..........|..|
+| |..|....|..................................................|..........|..|
+| -----------................................................------------..|
+|           |..............................................................|
+----------------------------------------------------------------------------
+ENDMAP
+# Non diggable walls
+NON_DIGGABLE:(00,00,75,19)
+# Portal arrival point
+BRANCH:(08,16,08,16),(0,0,0,0)
+#   Throne room, with Croesus on the throne
+REGION:(37,08,46,11),lit,"throne"
+MONSTER:'@',"Croesus",(43,10),hostile
+#   The Vault
+#   Using unfilled morgue for
+#   identification in mkmaze.c
+REGION:(21,08,35,11),lit,"morgue",unfilled
+#   Corner towers
+REGION:(19,06,21,06),lit,"ordinary"
+REGION:(46,06,48,06),lit,"ordinary"
+REGION:(19,13,21,13),lit,"ordinary"
+REGION:(46,13,48,13),lit,"ordinary"
+#   A welcoming committee
+REGION:(03,10,07,13),lit,"zoo",filled,true
+#   arrival chamber; needs to be a real room to control migrating monsters,
+#   and `unfilled' is a kludge to force an ordinary room to remain a room
+REGION:(06,15,09,16),unlit,"ordinary",unfilled
+#   Barracks
+REGION:(62,03,71,04),lit,"barracks",filled,true
+# Doors
+DOOR:closed,(06,14)
+DOOR:closed,(09,03)
+DOOR:open,(63,05)
+DOOR:open,(66,05)
+DOOR:open,(68,08)
+DOOR:locked,(08,11)
+DOOR:open,(68,11)
+DOOR:closed,(63,14)
+DOOR:closed,(66,14)
+# Soldiers guarding the fort
+MONSTER:'@',"soldier",(12,14)
+MONSTER:'@',"soldier",(12,13)
+MONSTER:'@',"soldier",(11,10)
+MONSTER:'@',"soldier",(13,02)
+MONSTER:'@',"soldier",(14,03)
+MONSTER:'@',"soldier",(20,02)
+MONSTER:'@',"soldier",(30,02)
+MONSTER:'@',"soldier",(40,02)
+MONSTER:'@',"soldier",(30,16)
+MONSTER:'@',"soldier",(32,16)
+MONSTER:'@',"soldier",(40,16)
+MONSTER:'@',"soldier",(54,16)
+MONSTER:'@',"soldier",(54,14)
+MONSTER:'@',"soldier",(54,13)
+MONSTER:'@',"soldier",(57,10)
+MONSTER:'@',"soldier",(57,09)
+MONSTER:'@',"lieutenant",(15,08)
+# Four dragons guarding each side
+MONSTER:'D',random,(18,09)
+MONSTER:'D',random,(49,10)
+MONSTER:'D',random,(33,05)
+MONSTER:'D',random,(33,14)
+# Eels in the moat
+MONSTER:';',"giant eel",(17,08)
+MONSTER:';',"giant eel",(17,11)
+MONSTER:';',"giant eel",(48,08)
+MONSTER:';',"giant eel",(48,11)
+# The corner rooms treasures
+OBJECT:'*',"diamond",(19,06)
+OBJECT:'*',"diamond",(20,06)
+OBJECT:'*',"diamond",(21,06)
+OBJECT:'*',"emerald",(19,13)
+OBJECT:'*',"emerald",(20,13)
+OBJECT:'*',"emerald",(21,13)
+OBJECT:'*',"ruby",(46,06)
+OBJECT:'*',"ruby",(47,06)
+OBJECT:'*',"ruby",(48,06)
+OBJECT:'*',"amethyst",(46,13)
+OBJECT:'*',"amethyst",(47,13)
+OBJECT:'*',"amethyst",(48,13)
diff --git a/dat/license b/dat/license
new file mode 100644 (file)
index 0000000..5ad7e34
--- /dev/null
@@ -0,0 +1,95 @@
+                    NETHACK GENERAL PUBLIC LICENSE
+                    (Copyright 1989 M. Stephenson)
+
+               (Based on the BISON general public license,
+                   copyright 1988 Richard M. Stallman)
+
+ Everyone is permitted to copy and distribute verbatim copies of this
+ license, but changing it is not allowed.  You can also use this wording to
+ make the terms for other programs.
+
+  The license agreements of most software companies keep you at the mercy of
+those companies.  By contrast, our general public license is intended to give
+everyone the right to share NetHack.  To make sure that you get the rights we
+want you to have, we need to make restrictions that forbid anyone to deny you
+these rights or to ask you to surrender the rights.  Hence this license
+agreement.
+
+  Specifically, we want to make sure that you have the right to give away
+copies of NetHack, that you receive source code or else can get it if you
+want it, that you can change NetHack or use pieces of it in new free
+programs, and that you know you can do these things.
+
+  To make sure that everyone has such rights, we have to forbid you to
+deprive anyone else of these rights.  For example, if you distribute copies
+of NetHack, you must give the recipients all the rights that you have.  You
+must make sure that they, too, receive or can get the source code.  And you
+must tell them their rights.
+
+  Also, for our own protection, we must make certain that everyone finds out
+that there is no warranty for NetHack.  If NetHack is modified by someone
+else and passed on, we want its recipients to know that what they have is
+not what we distributed.
+
+  Therefore we (Mike Stephenson and other holders of NetHack copyrights) make
+the following terms which say what you must do to be allowed to distribute or
+change NetHack.
+
+
+                        COPYING POLICIES
+
+  1. You may copy and distribute verbatim copies of NetHack source code as
+you receive it, in any medium, provided that you keep intact the notices on
+all files that refer to copyrights, to this License Agreement, and to the
+absence of any warranty; and give any other recipients of the NetHack
+program a copy of this License Agreement along with the program.
+
+  2. You may modify your copy or copies of NetHack or any portion of it, and
+copy and distribute such modifications under the terms of Paragraph 1 above
+(including distributing this License Agreement), provided that you also do the
+following:
+
+    a) cause the modified files to carry prominent notices stating that you
+    changed the files and the date of any change; and
+
+    b) cause the whole of any work that you distribute or publish, that in
+    whole or in part contains or is a derivative of NetHack or any part
+    thereof, to be licensed at no charge to all third parties on terms
+    identical to those contained in this License Agreement (except that you
+    may choose to grant more extensive warranty protection to some or all
+    third parties, at your option)
+
+    c) You may charge a distribution fee for the physical act of
+    transferring a copy, and you may at your option offer warranty protection
+    in exchange for a fee.
+
+  3. You may copy and distribute NetHack (or a portion or derivative of it,
+under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 1 and 2 above provided that you also do one of the following:
+
+    a) accompany it with the complete machine-readable source code, which
+    must be distributed under the terms of Paragraphs 1 and 2 above; or,
+
+    b) accompany it with full information as to how to obtain the complete
+    machine-readable source code from an appropriate archive site.  (This
+    alternative is allowed only for noncommercial distribution.)
+
+For these purposes, complete source code means either the full source
+distribution as originally released over Usenet or updated copies of the
+files in this distribution used to create the object code or executable.
+
+  4. You may not copy, sublicense, distribute or transfer NetHack except as
+expressly provided under this License Agreement.  Any attempt otherwise to
+copy, sublicense, distribute or transfer NetHack is void and your rights to
+use the program under this License agreement shall be automatically
+terminated.  However, parties who have received computer software programs
+from you with this License Agreement will not have their licenses terminated
+so long as such parties remain in full compliance.
+
+
+Stated plainly:  You are permitted to modify NetHack, or otherwise use parts
+of NetHack, provided that you comply with the conditions specified above;
+in particular, your modified NetHack or program containing parts of NetHack
+must remain freely available as provided in this License Agreement.  In
+other words, go ahead and share NetHack, but don't try to stop anyone else
+from sharing it farther.
diff --git a/dat/medusa.des b/dat/medusa.des
new file mode 100644 (file)
index 0000000..6134470
--- /dev/null
@@ -0,0 +1,215 @@
+#      SCCS Id: @(#)medusa.des 3.4     1996/05/11
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1990, 1991 by M. Stephenson
+# NetHack may be freely redistributed.  See license for details.
+#
+# These are the Medusa's levels :
+#
+
+MAZE:"medusa-1",' '
+FLAGS: noteleport
+GEOMETRY:center,center
+MAP
+}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+}}.}}}}}..}}}}}......}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}....}}}...}}}}}
+}...}}.....}}}}}....}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}...............}
+}....}}}}}}}}}}....}}}..}}}}}}}}}}}.......}}}}}}}}}}}}}}}}..}}.....}}}...}}
+}....}}}}}}}}.....}}}}..}}}}}}.................}}}}}}}}}}}.}}}}.....}}...}}
+}....}}}}}}}}}}}}.}}}}.}}}}}}.-----------------.}}}}}}}}}}}}}}}}}.........}
+}....}}}}}}}}}}}}}}}}}}.}}}...|...............S...}}}}}}}}}}}}}}}}}}}....}}
+}.....}.}}....}}}}}}}}}.}}....--------+--------....}}}}}}..}}}}}}}}}}}...}}
+}......}}}}..}}}}}}}}}}}}}........|.......|........}}}}}....}}}}}}}}}}}}}}}
+}.....}}}}}}}}}}}}}}}}}}}}........|.......|........}}}}}...}}}}}}}}}.}}}}}}
+}.....}}}}}}}}}}}}}}}}}}}}....--------+--------....}}}}}}.}.}}}}}}}}}}}}}}}
+}......}}}}}}}}}}}}}}}}}}}}...S...............|...}}}}}}}}}}}}}}}}}.}}}}}}}
+}.......}}}}}}}..}}}}}}}}}}}}.-----------------.}}}}}}}}}}}}}}}}}....}}}}}}
+}........}}.}}....}}}}}}}}}}}}.................}}}}}..}}}}}}}}}.......}}}}}
+}.......}}}}}}}......}}}}}}}}}}}}}}.......}}}}}}}}}.....}}}}}}...}}..}}}}}}
+}.....}}}}}}}}}}}.....}}}}}}}}}}}}}}}}}}}}}}.}}}}}}}..}}}}}}}}}}....}}}}}}}
+}}..}}}}}}}}}}}}}....}}}}}}}}}}}}}}}}}}}}}}...}}..}}}}}}}.}}.}}}}..}}}}}}}}
+}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+ENDMAP
+# Dungeon Description
+# (must maintain one room definition; `unfilled' forces its room to be kept)
+REGION:(00,00,74,19),lit,"ordinary"
+REGION:(31,07,45,07),unlit,"ordinary"
+REGION:(35,09,41,10),unlit,"ordinary",unfilled
+REGION:(31,12,45,12),unlit,"ordinary"
+# Teleport: down to up stairs island, up to Medusa's island
+TELEPORT_REGION:(01,01,05,17),(0,0,0,0),down
+TELEPORT_REGION:(26,04,50,15),(0,0,0,0),up
+# Stairs
+STAIR:(05,14),up
+STAIR:(36,10),down
+# Doors
+DOOR:closed,(46,07)
+DOOR:locked,(38,08)
+DOOR:locked,(38,11)
+DOOR:closed,(30,12)
+# Branch, not allowed inside Medusa's building.
+BRANCH:levregion(01,00,79,20),(30,06,46,13)
+# Non diggable walls
+NON_DIGGABLE:(30,06,46,13)
+# Objects
+CONTAINER:'`',"statue",(36,10),uncursed,"knight",3,"Perseus"
+OBJECT[75%]:'[',"shield of reflection",contained,cursed,+0
+OBJECT[25%]:'[',"levitation boots",contained,random,+0
+OBJECT[50%]:')',"scimitar",contained,blessed,+2
+OBJECT[50%]:'(',"sack",contained
+# These aren't really containers, but specifying CONTAINER forces them to be
+# empty, since CONTAINERs contain only what is explicitly specified.
+CONTAINER:'`',"statue",random
+CONTAINER:'`',"statue",random
+CONTAINER:'`',"statue",random
+CONTAINER:'`',"statue",random
+CONTAINER:'`',"statue",random
+CONTAINER:'`',"statue",random
+CONTAINER:'`',"statue",random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:"board",(38,07)
+TRAP:"board",(38,12)
+# Random monsters
+MONSTER:'@',"Medusa",(36,10),asleep
+MONSTER:';',"giant eel",(11,06)
+MONSTER:';',"giant eel",(23,13)
+MONSTER:';',"giant eel",(29,02)
+MONSTER:';',"jellyfish",(02,02)
+MONSTER:';',"jellyfish",(00,08)
+MONSTER:';',"jellyfish",(04,18)
+MONSTER:'T',"water troll",(51,03)
+MONSTER:'T',"water troll",(64,11)
+MONSTER:'S',random,(38,07)
+MONSTER:'S',random,(38,12)
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+
+MAZE:"medusa-2",' '
+FLAGS: noteleport
+GEOMETRY:center,center
+MAP
+}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+}------}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}-------}}}}}}}}--------------}
+}|....|}}}}}}}}}..}.}}..}}}}}}}}}}}}}..}}}}}}-.....--}}}}}}}|............|}
+}|....|.}}}}}}}}}}}.}...}}..}}}}}}}}}}}}}}}}}---......}}}}}.|............|}
+}S....|.}}}}}}---}}}}}}}}}}}}}}}}}}}}}}}}}}---...|..-}}}}}}.S..----------|}
+}|....|.}}}}}}-...}}}}}}}}}.}}...}.}}}}.}}}......----}}}}}}.|............|}
+}|....|.}}}}}}-....--}}}}}}}}}}}}}}}}}}}}}}----...--}}}}}}}.|..--------+-|}
+}|....|.}}}}}}}......}}}}...}}}}}}.}}}}}}}}}}}---..---}}}}}.|..|..S...|..|}
+}|....|.}}}}}}-....-}}}}}}}------}}}}}}}}}}}}}}-...|.-}}}}}.|..|..|...|..|}
+}|....|.}}}}}}}}}---}}}}}}}........}}}}}}}}}}---.|....}}}}}.|..|..|...|..|}
+}|....|.}}}}}}}}}}}}}}}}}}-....|...-}}}}}}}}--...----.}}}}}.|..|..|...|..|}
+}|....|.}}}}}}..}}}}}}}}}}---..--------}}}}}-..---}}}}}}}}}.|..|..-------|}
+}|...}|...}}}.}}}}}}...}}}}}--..........}}}}..--}}}}}}}}}}}.|..|.........|}
+}|...}S...}}.}}}}}}}}}}}}}}}-..--------}}}}}}}}}}}}}}...}}}.|..--------..S}
+}|...}|...}}}}}}}..}}}}}}----..|....-}}}}}}}}}}}}}}}}}..}}}.|............|}
+}|....|}}}}}....}}}}..}}.-.......----}}......}}}}}}.......}}|............|}
+}------}}}}}}}}}}}}}}}}}}---------}}}}}}}}}}}}}}}}}}}}}}}}}}--------------}
+}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+ENDMAP
+# Dungeon Description
+REGION:(00,00,74,19),lit,"ordinary"
+REGION:(02,03,05,16),unlit,"ordinary"
+REGION:(61,03,72,16),unlit,"ordinary",unfilled,true
+REGION:(71,08,72,11),unlit,"ordinary"
+REGION:(67,08,69,11),lit,"ordinary"
+# Teleport: down to up stairs island, up to Medusa's island
+TELEPORT_REGION:(02,03,05,16),(0,0,0,0),down
+TELEPORT_REGION:(61,03,72,16),(0,0,0,0),up
+# Stairs
+STAIR:(04,09),up
+STAIR:(68,10),down
+# Doors
+DOOR:locked,(71,07)
+# Branch, not allowed on Medusa's island.
+BRANCH:levregion(01,00,79,20),(59,01,73,17)
+# Non diggable walls
+NON_DIGGABLE:(01,02,06,17)
+NON_DIGGABLE:(60,02,73,17)
+# Objects
+CONTAINER:'`',"statue",(68,10),uncursed,"knight",3,"Perseus"
+OBJECT[25%]:'[',"shield of reflection",contained,cursed,+0
+OBJECT[75%]:'[',"levitation boots",contained,random,+0
+OBJECT[50%]:')',"scimitar",contained,blessed,+2
+OBJECT[50%]:'(',"sack",contained
+CONTAINER:'`',"statue",(64,08)
+CONTAINER:'`',"statue",(65,08)
+CONTAINER:'`',"statue",(64,09)
+CONTAINER:'`',"statue",(65,09)
+CONTAINER:'`',"statue",(64,10)
+CONTAINER:'`',"statue",(65,10)
+CONTAINER:'`',"statue",(64,11)
+CONTAINER:'`',"statue",(65,11)
+OBJECT:'`',"boulder",(04,04)
+OBJECT:'/',random,(52,09)
+OBJECT:'`',"boulder",(52,09)
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Traps
+TRAP:"magic",(03,12)
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Monsters.
+MONSTER:'@',"Medusa",(68,10),asleep
+MONSTER:'g',"gremlin",(02,14)
+MONSTER:'H',"titan",(02,05)
+MONSTER:';',"electric eel",(10,13)
+MONSTER:';',"electric eel",(11,13)
+MONSTER:';',"electric eel",(10,14)
+MONSTER:';',"electric eel",(11,14)
+MONSTER:';',"electric eel",(10,15)
+MONSTER:';',"electric eel",(11,15)
+MONSTER:';',"jellyfish",(01,01)
+MONSTER:';',"jellyfish",(00,08)
+MONSTER:';',"jellyfish",(04,19)
+MONSTER:''',"stone golem",(64,08),asleep
+MONSTER:''',"stone golem",(65,08),asleep
+MONSTER:''',"stone golem",(64,09),asleep
+MONSTER:''',"stone golem",(65,09),asleep
+MONSTER:'S',"cobra",(64,10),asleep
+MONSTER:'S',"cobra",(65,10),asleep
+MONSTER:'A',random,(72,08)
+MONSTER:'y',"yellow light",(72,11),asleep
+MONSTER:random,random,(17,07)
+MONSTER:random,random,(28,11)
+MONSTER:random,random,(32,13)
+MONSTER:random,random,(49,09)
+MONSTER:random,random,(48,07)
+MONSTER:random,random,(65,03)
+MONSTER:random,random,(70,04)
+MONSTER:random,random,(70,15)
+MONSTER:random,random,(65,16)
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
diff --git a/dat/mines.des b/dat/mines.des
new file mode 100644 (file)
index 0000000..81f3a02
--- /dev/null
@@ -0,0 +1,1021 @@
+#      SCCS Id: @(#)mines.des  3.4     2002/05/02
+#      Copyright (c) 1989-95 by Jean-Christophe Collet
+#      Copyright (c) 1991-95 by M. Stephenson
+# NetHack may be freely redistributed.  See license for details.
+#
+
+#      The "fill" level for the mines.
+#
+#      This level is used to fill out any levels not occupied by
+#      specific levels as defined below.
+#
+MAZE: "minefill" , ' '
+INIT_MAP: '.' , ' ' , true , true , random , true
+NOMAP
+#
+STAIR: random, up
+STAIR: random, down
+#
+OBJECT: '*', random, random
+OBJECT: '*', random, random
+OBJECT: '*', random, random
+OBJECT: '(', random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+#
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome lord", random
+MONSTER: 'h', "dwarf", random
+MONSTER: 'h', "dwarf", random
+MONSTER: 'G', random, random
+MONSTER: 'G', random, random
+MONSTER: 'h', random, random
+#
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+TRAP: random, random
+
+
+# Minetown variant 1
+# "Frontier Town"
+#
+LEVEL: "minetn-1"
+
+ROOM: "ordinary" , lit, (3,3), (center,center), (31,15)
+NAME: "town"
+FOUNTAIN: (13, 7)
+FOUNTAIN: (20, 7)
+
+# The Town Watch
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watch captain", random, peaceful
+
+SUBROOM: "shop" , lit, (2,2), (3,4), "town"
+CHANCE: 90
+DOOR: false, closed, south, random
+
+SUBROOM: "tool shop", lit, (2,9), (3,4), "town"
+CHANCE: 90
+DOOR: false, closed, north, random
+
+SUBROOM: "ordinary", unlit, (6,2), (3,4), "town"
+DOOR: false, closed, south, random
+
+SUBROOM: "ordinary", lit, (6,9), (3,4), "town"
+DOOR: false, closed, north, random
+
+SUBROOM: "food shop", lit, (10,2), (2,3), "town"
+CHANCE: 90
+DOOR: false, closed, south, random
+
+SUBROOM: "candle shop", lit, (22,2), (3,3), "town"
+DOOR: false, closed, south, random
+
+SUBROOM: "ordinary", unlit, (10,10), (2,3), "town"
+DOOR: false, locked, east, random
+MONSTER: 'G', "gnome", random
+
+SUBROOM: "ordinary", lit, (19,2),  (2,3), "town"
+DOOR: false, locked, west, random
+MONSTER: 'G', "gnome", random
+
+SUBROOM: "temple", lit, (15,9), (4,4), "town"
+DOOR: false, closed, north, random
+ALTAR:(02,02),align[0],shrine
+MONSTER: 'G', "gnomish wizard", random
+MONSTER: 'G', "gnomish wizard", random
+
+SUBROOM: "ordinary", lit, (22,10), (2,3), "town"
+DOOR: false, locked, west, random
+
+SUBROOM: "ordinary", lit, (26,2), (3,3), "town"
+DOOR: false, closed, south, random
+MONSTER: 'G', "gnome lord", random
+
+SUBROOM: "ordinary", unlit, (25,10), (4,3), "town"
+DOOR: false, closed, north, random
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+TRAP: random, random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+
+ROOM: "ordinary" , random, random, random, random
+MONSTER: 'h', "dwarf", random
+
+ROOM: "ordinary" , random, random, random, random
+TRAP: random, random
+MONSTER: 'G', "gnome", random
+
+RANDOM_CORRIDORS
+
+
+# Minetown variant 2
+# "Town Square"
+#
+LEVEL: "minetn-2"
+ROOM: "ordinary" , lit, (3,3), (center,center), (31,15)
+NAME: "town"
+FOUNTAIN: (17, 5)
+FOUNTAIN: (13, 8)
+
+# The Town Watch
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watch captain", random, peaceful
+
+SUBROOM: "ordinary", random, (2,0), (2,2), "town"
+DOOR: false, closed, west, random
+
+SUBROOM: "ordinary", unlit, (5,0), (2,2), "town"
+DOOR: false, closed, south, random
+
+SUBROOM: "ordinary", random, (8,0), (2,2), "town"
+DOOR: false, closed, east, random
+
+SUBROOM: "ordinary", lit, (16,0), (2,2), "town"
+DOOR: false, closed, west, random
+
+SUBROOM: "ordinary", unlit, (19,0), (2,2), "town"
+DOOR: false, closed, south, random
+
+SUBROOM: "ordinary", random, (22,0), (2,2), "town"
+DOOR: false, locked, south, random
+MONSTER: 'G', "gnome", random
+
+SUBROOM: "ordinary", unlit, (25,0), (2,2), "town"
+DOOR: false, closed, east, random
+
+SUBROOM: "ordinary", lit, (2,5), (2,2), "town"
+DOOR: false, closed, north, random
+
+SUBROOM: "ordinary", lit, (5,5), (2,2), "town"
+DOOR: false, closed, south, random
+
+SUBROOM: "ordinary", random, (8,5), (2,2), "town"
+DOOR: false, locked, north, random
+MONSTER: 'G', "gnome", random
+
+SUBROOM: "shop" , lit, (2,10), (4,3), "town"
+CHANCE: 90
+DOOR: false, closed, west, random
+
+SUBROOM: "tool shop", lit, (23,10), (4,3), "town"
+CHANCE: 90
+DOOR: false, closed, east, random
+
+SUBROOM: "food shop", lit, (24,5), (3,4), "town"
+CHANCE: 90
+DOOR: false, closed, north, random
+
+SUBROOM: "candle shop", lit, (11,10), (4,3), "town"
+DOOR: false, closed, east, random
+
+SUBROOM: "ordinary", unlit, (7,10), (3,3), "town"
+DOOR: false, locked, north, random
+MONSTER: 'G', "gnome", random
+
+SUBROOM: "temple", lit, (19,5), (4,4), "town"
+DOOR: false, closed, north, random
+ALTAR:(02,02),align[0],shrine
+MONSTER: 'G', "gnomish wizard", random
+MONSTER: 'G', "gnomish wizard", random
+
+SUBROOM: "ordinary", lit, (18,10), (4,3), "town"
+DOOR: false, locked, west, random
+MONSTER: 'G', "gnome lord", random
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+TRAP: random, random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+
+ROOM: "ordinary" , random, random, random, random
+MONSTER: 'h', "dwarf", random
+
+ROOM: "ordinary" , random, random, random, random
+TRAP: random, random
+MONSTER: 'G', "gnome", random
+
+RANDOM_CORRIDORS
+
+
+# Minetown variant 3 by Kelly Bailey
+# "Alley Town"
+#
+LEVEL: "minetn-3"
+ROOM: "ordinary",lit,(3,3),(center,center),(31,15)
+NAME: "town"
+FOUNTAIN:(01,06)
+FOUNTAIN:(29,13)
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watch captain", random, peaceful
+
+SUBROOM:"ordinary",random,(2,2),(2,2),"town"
+DOOR: false,closed,south,random
+
+SUBROOM:"tool shop",lit,(5,3),(2,3),"town"
+CHANCE: 30
+DOOR: false,closed,south,random
+
+SUBROOM:"ordinary",random,(2,10),(2,3),"town"
+DOOR: false, locked, north, random
+MONSTER: 'G',random,random
+
+SUBROOM:"ordinary",random,(5,9),(2,2),"town"
+DOOR: false,closed,north,random
+
+SUBROOM:"temple",lit,(10,2),(3,4),"town"
+DOOR: false,closed,east,random
+ALTAR:(1,1),align[0],shrine
+MONSTER: 'G', "gnomish wizard", random
+MONSTER: 'G', "gnomish wizard", random
+
+SUBROOM:"ordinary",random,(11,7),(2,2),"town"
+DOOR: false,closed,west,random
+
+SUBROOM:"shop",lit,(10,10),(3,3),"town"
+DOOR:false,closed,west,random
+
+SUBROOM:"ordinary",random,(14,8),(2,2),"town"
+DOOR:false,locked,north,random
+MONSTER: 'G',random,random
+
+SUBROOM:"ordinary",random,(14,11),(2,2),"town"
+DOOR:false,closed,south,random
+
+SUBROOM:"tool shop",lit,(17,10),(3,3),"town"
+CHANCE:40
+DOOR:false,closed,north,random
+
+SUBROOM:"ordinary",random,(21,11),(2,2),"town"
+DOOR:false,locked,east,random
+MONSTER:'G',random,random
+
+SUBROOM:"food shop",lit,(26,8),(3,2),"town"
+CHANCE:90
+DOOR:false,closed,west,random
+
+SUBROOM:"ordinary",random,(16,2),(2,2),"town"
+DOOR:false,closed,west,random
+
+SUBROOM:"ordinary",random,(19,2),(2,2),"town"
+DOOR:false,closed,north,random
+
+SUBROOM:"wand shop",lit,(19,5),(3,2),"town"
+CHANCE:30
+DOOR:false,closed,west,random
+
+SUBROOM: "candle shop",lit,(25,2),(3,3),"town"
+DOOR:false,closed,south,random
+
+ROOM: "ordinary", random, random, random, random
+STAIR: random, up
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+TRAP: random, random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+
+ROOM: "ordinary" , random, random, random, random
+MONSTER: 'h', "dwarf", random
+
+ROOM: "ordinary" , random, random, random, random
+TRAP: random, random
+MONSTER: 'G', "gnome", random
+
+RANDOM_CORRIDORS
+
+
+# Minetown variant 4 by Kelly Bailey
+# "College Town"
+#
+LEVEL: "minetn-4"
+ROOM: "ordinary",lit,(3,3),(center,center),(30,15)
+NAME: "town"
+FOUNTAIN:(08,07)
+FOUNTAIN:(18,07)
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watch captain", random, peaceful
+
+SUBROOM:"book shop",lit,(4,2),(3,3),"town"
+DOOR: false,closed,south,random
+
+SUBROOM:"ordinary",random,(8,2),(2,2),"town"
+DOOR: false,closed,south,random
+
+SUBROOM:"temple",lit,(11,3),(5,4),"town"
+DOOR: false,closed,south,random
+ALTAR:(2,1),align[0],shrine
+MONSTER: 'G', "gnomish wizard", random
+MONSTER: 'G', "gnomish wizard", random
+
+SUBROOM:"ordinary",random,(19,2),(2,2),"town"
+DOOR: false,closed,south,random
+MONSTER: 'G', random, random
+
+SUBROOM:"candle shop",lit,(22,2),(3,3),"town"
+DOOR:false,closed,south,random
+
+SUBROOM:"ordinary",random,(26,2),(2,2),"town"
+DOOR:false,locked,east,random
+MONSTER: 'G',random,random
+
+SUBROOM:"tool shop",lit,(4,10),(3,3),"town"
+CHANCE:90
+DOOR:false,closed,north,random
+
+SUBROOM:"ordinary",random,(8,11),(2,2),"town"
+DOOR:false,locked,south,random
+MONSTER: 'k',"kobold shaman",random
+MONSTER: 'k',"kobold shaman",random
+MONSTER: 'f',"kitten",random
+MONSTER: 'f',random,random
+
+SUBROOM:"food shop",lit,(11,11),(3,2),"town"
+CHANCE:90
+DOOR:false,closed,east,random
+
+SUBROOM:"ordinary",random,(17,11),(2,2),"town"
+DOOR:false,closed,west,random
+
+SUBROOM:"ordinary",random,(20,10),(2,2),"town"
+DOOR:false,locked,north,random
+MONSTER:'G',random,random
+
+SUBROOM:"shop",lit,(23,10),(3,3),"town"
+CHANCE:90
+DOOR:false,closed,north,random
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+TRAP: random, random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+
+ROOM: "ordinary" , random, random, random, random
+MONSTER: 'h', "dwarf", random
+
+ROOM: "ordinary" , random, random, random, random
+TRAP: random, random
+MONSTER: 'G', "gnome", random
+
+RANDOM_CORRIDORS
+
+
+# "Grotto Town" by Kelly Bailey
+#
+MAZE: "minetn-5",' '
+GEOMETRY:center,center
+MAP
+-----         ---------                                                    
+|...---  ------.......--    -------                       ---------------  
+|.....----.........--..|    |.....|          -------      |.............|  
+--..-....-.----------..|    |.....|          |.....|     --+---+--.----+-  
+ --.--.....----     ----    |.....|  ------  --....----  |..-...--.-.+..|  
+  ---.........----  -----   ---+---  |..+.|   ---..-..----..---+-..---..|  
+    ----.-....|..----...--    |.|    |..|.|    ---+-.....-+--........--+-  
+       -----..|....-.....---- |.|    |..|.------......--................|  
+    ------ |..|.............---.--   ----.+..|-.......--..--------+--..--  
+    |....| --......---...........-----  |.|..|-...{....---|.........|..--  
+    |....|  |........-...-...........----.|..|--.......|  |.........|...|  
+    ---+--------....-------...---......--.-------....---- -----------...|  
+ ------.---...--...--..-..--...-..---...|.--..-...-....------- |.......--  
+ |..|-.........-..---..-..---.....--....|........---...-|....| |.-------   
+ |..+...............-+---+-----..--..........--....--...+....| |.|...S.    
+-----.....{....----...............-...........--...-...-|....| |.|...|     
+|..............-- --+--.---------.........--..-........------- |.--+-------
+-+-----.........| |...|.|....|  --.......------...|....---------.....|....|
+|...| --..------- |...|.+....|   ---...---    --..|...--......-...{..+..-+|
+|...|  ----       ------|....|     -----       -----.....----........|..|.|
+-----                   ------                     -------  ---------------
+ENDMAP
+
+STAIR:(01,01),up
+STAIR:(46,03),down
+FOUNTAIN:(50,09)
+FOUNTAIN:(10,15)
+FOUNTAIN:(66,18)
+
+REGION:(00,00,74,20),unlit,"ordinary"
+REGION:(09,13,11,17),lit,"ordinary"
+REGION:(08,14,12,16),lit,"ordinary"
+REGION:(49,07,51,11),lit,"ordinary"
+REGION:(48,08,52,10),lit,"ordinary"
+REGION:(64,17,68,19),lit,"ordinary"
+REGION:(37,13,39,17),lit,"ordinary"
+REGION:(36,14,40,17),lit,"ordinary"
+REGION:(59,02,72,10),lit,"ordinary"
+
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watch captain", random, peaceful
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome lord", random
+MONSTER: 'G', "gnome lord", random
+MONSTER: 'h', "dwarf", random
+MONSTER: 'h', "dwarf", random
+MONSTER: 'h', "dwarf", random
+
+# The shops
+REGION:(25,17,28,19),lit,"candle shop"
+DOOR:closed,(24,18)
+REGION:(59,9,67,10),lit,"shop"
+DOOR:closed,(66,08)
+REGION:(57,13,60,15),lit,"tool shop"
+DOOR:closed,(56,14)
+REGION:(05,09,08,10),lit,"food shop"
+DOOR:closed,(07,11)
+# Gnome homes
+DOOR:closed,(04,14)
+DOOR:locked,(01,17)
+MONSTER: 'G', "gnomish wizard", (02,19)
+DOOR:locked,(20,16)
+MONSTER: 'G', random, (20,18)
+DOOR:random,(21,14)
+DOOR:random,(25,14)
+DOOR:random,(42,08)
+DOOR:locked,(40,05)
+MONSTER: 'G', random, (38,07)
+DOOR:random,(59,03)
+DOOR:random,(58,06)
+DOOR:random,(63,03)
+DOOR:random,(63,05)
+DOOR:locked,(71,03)
+DOOR:locked,(71,06)
+DOOR:closed,(69,04)
+DOOR:closed,(67,16)
+MONSTER: 'G', "gnomish wizard", (67,14)
+OBJECT: '=', random, (70,14)
+DOOR:locked,(69,18)
+MONSTER: 'G', "gnome lord", (71,19)
+DOOR:locked,(73,18)
+OBJECT: '(', "chest", (73,19)
+DOOR:locked,(50,06)
+OBJECT: '(', random, (50,03)
+OBJECT: '`', "statue", (38,15), "gnome king", 1
+# Temple
+REGION:(29,02,33,04),lit,"temple"
+DOOR:closed,(31,05)
+ALTAR:(31,03),align[0],shrine
+
+
+# "Bustling Town" by Kelly Bailey
+#
+MAZE: "minetn-6",' '
+INIT_MAP:'.','-',true,true,lit,true
+GEOMETRY:center,top
+MAP
+.-----................----------------.-
+.|...|................|...|..|...|...|..
+.|...+..--+--.........|...|..|...|...|..
+.|...|..|...|..-----..|...|..|-+---+--..
+.-----..|...|--|...|..--+---+-.........|
+........|...|..|...+.............-----..
+........-----..|...|......--+-...|...|..
+.----...|...|+------..{...|..|...+...|..
+.|..+...|...|.............|..|...|...|..
+.|..|...|...|-+-.....---+-------------.|
+.----...--+--..|..-+-|..................
+...|........|..|..|..|----....---------.
+...|..T.....----..|..|...+....|......|-.
+...|-....{........|..|...|....+......|-.
+...--..-....T.....--------....|......|-.
+.......--.....................----------
+ENDMAP
+
+REGION:(00,00,38,15),lit,"ordinary"
+STAIR:levregion(01,03,20,19),(0,0,39,15),up
+STAIR:levregion(61,03,75,19),(0,0,39,15),down
+FOUNTAIN:(22,07)
+FOUNTAIN:(09,13)
+REGION:(13,5,14,6),unlit,"ordinary"
+REGION:(9,7,11,9),lit,"candle shop"
+REGION:(16,4,18,6),lit,"tool shop"
+REGION:(23,1,25,3),lit,"shop"
+REGION:(22,12,24,13),lit,"food shop"
+REGION:(31,12,36,14),lit,"temple"
+ALTAR:(35,13),align[0],shrine
+
+DOOR:closed,(5,2)
+DOOR:locked,(4,8)
+DOOR:closed,(10,2)
+DOOR:closed,(10,10)
+DOOR:locked,(13,7)
+DOOR:locked,(14,9)
+DOOR:closed,(19,5)
+DOOR:closed,(19,10)
+DOOR:closed,(24,4)
+DOOR:closed,(24,9)
+DOOR:closed,(25,12)
+DOOR:closed,(28,4)
+DOOR:locked,(28,6)
+DOOR:closed,(30,13)
+DOOR:closed,(31,3)
+DOOR:closed,(35,3)
+DOOR:closed,(33,7)
+
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", (14,6)
+MONSTER: 'G', "gnome lord", (14,5)
+MONSTER: 'G', "gnome", (27,8)
+MONSTER: 'G', "gnome lord", random
+MONSTER: 'G', "gnome lord", random
+MONSTER: 'h', "dwarf", random
+MONSTER: 'h', "dwarf", random
+MONSTER: 'h', "dwarf", random
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watch captain", random, peaceful
+MONSTER: '@', "watch captain", random, peaceful
+
+
+# "Bazaar Town" by Kelly Bailey
+#
+LEVEL: "minetn-7"
+ROOM: "ordinary" , lit, (3,3), (center,center), (30,15)
+NAME: "town"
+FOUNTAIN: (12, 07)
+FOUNTAIN: (11, 13)
+
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watchman", random, peaceful
+MONSTER: '@', "watch captain", random, peaceful
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome lord",random
+MONSTER:'Y',"monkey",random
+MONSTER:'Y',"monkey",random
+
+SUBROOM: "ordinary", random, (2,2), (4,2), "town"
+DOOR: false, closed, south, random
+
+SUBROOM: "ordinary", random, (7,2), (2,2), "town"
+DOOR: false, closed, north, random
+
+SUBROOM: "ordinary", random, (7,5), (2,2), "town"
+DOOR: false, closed, south, random
+
+SUBROOM: "ordinary", lit, (10,2), (3,4), "town"
+MONSTER:'G',"gnome",random
+MONSTER:'Y',"monkey",random
+MONSTER:'Y',"monkey",random
+MONSTER:'Y',"monkey",random
+DOOR: false, closed, south, random
+
+SUBROOM: "ordinary", random, (14,2), (4,2), "town"
+DOOR: false, closed, south, 0
+MONSTER: 'n', random, random
+
+SUBROOM: "ordinary", random, (16,5), (2,2), "town"
+DOOR: false, closed, south, random
+
+SUBROOM: "ordinary", unlit, (19,2), (2,2), "town"
+DOOR: false, locked, east, random
+MONSTER: 'G',"gnome king",random
+
+SUBROOM: "food shop", lit, (19,5), (2,3), "town"
+CHANCE: 50
+DOOR: false, closed, south, random
+
+SUBROOM: "ordinary", random, (2,7), (2,2), "town"
+DOOR: false, closed, east, random
+
+SUBROOM: "tool shop", lit, (2,10), (2,3), "town"
+CHANCE: 50
+DOOR: false, closed, south, random
+
+SUBROOM: "candle shop", lit, (5,10),(3,3), "town"
+DOOR: false, closed, north, random
+
+SUBROOM: "ordinary", random, (11,10), (2,2), "town"
+DOOR: false, locked, west, random
+MONSTER: 'G',random,random
+
+SUBROOM: "shop", lit, (14,10), (2,3), "town"
+CHANCE: 60
+DOOR: false, closed, north, random
+
+SUBROOM: "ordinary", random, (17,11), (4,2), "town"
+DOOR: false, closed, north, random
+
+SUBROOM: "ordinary", random, (22,11), (2,2), "town"
+DOOR: false, closed, south, random
+SINK: (00,00)
+
+SUBROOM: "food shop", lit, (25,11), (3,2), "town"
+CHANCE: 50
+DOOR: false, closed, east, random
+
+SUBROOM: "tool shop", lit, (25,2), (3,3), "town"
+CHANCE: 30
+DOOR: false, closed, west, random
+
+SUBROOM: "temple", lit, (24,6), (4,4), "town"
+DOOR: false, closed, west, random
+ALTAR:(02,01),align[0],shrine
+MONSTER: 'G', "gnomish wizard", random
+MONSTER: 'G', "gnomish wizard", random
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+TRAP: random, random
+MONSTER: 'G', "gnome", random
+MONSTER: 'G', "gnome", random
+
+ROOM: "ordinary" , random, random, random, random
+MONSTER: 'h', "dwarf", random
+  
+ROOM: "ordinary" , random, random, random, random
+TRAP: random, random
+MONSTER: 'G', "gnome", random
+
+RANDOM_CORRIDORS
+  
+
+# Mine end level variant 1
+# "Mimic of the Mines"
+#
+MAZE: "minend-1", ' '
+GEOMETRY:center,center
+#1234567890123456789012345678901234567890123456789012345678901234567890
+MAP
+------------------------------------------------------------------   ------
+|                        |.......|     |.......-...|       |.....|.       |
+|    ---------        ----.......-------...........|       ---...-S-      |
+|    |.......|        |..........................-S-      --.......|      |
+|    |......-------   ---........................|.       |.......--      |
+|    |..--........-----..........................|.       -.-..----       |
+|    --..--.-----........-.....................---        --..--          |
+|     --..--..| -----------..................---.----------..--           |
+|      |...--.|    |..S...S..............---................--            |
+|     ----..-----  ------------........--- ------------...---             |
+|     |.........--            ----------              ---...-- -----      |
+|    --.....---..--                           --------  --...---...--     |
+| ----..-..-- --..---------------------      --......--  ---........|     |
+|--....-----   --..-..................---    |........|    |.......--     |
+|.......|       --......................S..  --......--    ---..----      |
+|--.--.--        ----.................---     ------..------...--         |
+| |....S..          |...............-..|         ..S...........|          |
+--------            --------------------           ------------------------
+ENDMAP
+
+# Dungeon Description
+RANDOM_PLACES:(08,16),(13,07),(21,08),(41,14),(50,04),(50,16),(66,01)
+REGION:(26,01,32,01),unlit,"ordinary",filled,true
+REGION:(20,08,21,08),unlit,"ordinary"
+REGION:(23,08,25,08),unlit,"ordinary"
+# Secret doors
+DOOR:locked,(07,16)
+DOOR:locked,(22,08)
+DOOR:locked,(26,08)
+DOOR:locked,(40,14)
+DOOR:locked,(50,03)
+DOOR:locked,(51,16)
+DOOR:locked,(66,02)
+# Stairs
+STAIR:(36,04),up
+# Non diggable walls
+NON_DIGGABLE:(00,00,74,17)
+# Niches
+# Note: place[6] empty
+OBJECT:'*',"diamond",place[0]
+OBJECT:'*',"emerald",place[0]
+OBJECT:'*',"worthless piece of violet glass",place[0]
+MONSTER:'m',random,place[0], m_object "luckstone"
+OBJECT:'*',"worthless piece of white glass",place[1]
+OBJECT:'*',"emerald",place[1]
+OBJECT:'*',"amethyst",place[1]
+MONSTER:'m',random,place[1], m_object "loadstone"
+OBJECT:'*',"diamond",place[2]
+OBJECT:'*',"worthless piece of green glass",place[2]
+OBJECT:'*',"amethyst",place[2]
+MONSTER:'m',random,place[2], m_object "flint"
+OBJECT:'*',"worthless piece of white glass",place[3]
+OBJECT:'*',"emerald",place[3]
+OBJECT:'*',"worthless piece of violet glass",place[3]
+MONSTER:'m',random,place[3], m_object "touchstone"
+OBJECT:'*',"worthless piece of red glass",place[4]
+OBJECT:'*',"ruby",place[4]
+OBJECT:'*',"loadstone",place[4]
+OBJECT:'*',"ruby",place[5]
+OBJECT:'*',"worthless piece of red glass",place[5]
+OBJECT:'*',"luckstone",place[5]
+# Random objects
+OBJECT:'*',random,random
+OBJECT:'*',random,random
+OBJECT:'*',random,random
+OBJECT:'*',random,random
+OBJECT:'*',random,random
+OBJECT:'*',random,random
+OBJECT:'*',random,random
+OBJECT:'(',random,random
+OBJECT:'(',random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters
+MONSTER:'G',"gnome king",random
+MONSTER:'G',"gnome lord",random
+MONSTER:'G',"gnome lord",random
+MONSTER:'G',"gnome lord",random
+MONSTER:'G',"gnomish wizard",random
+MONSTER:'G',"gnomish wizard",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'h',"hobbit",random
+MONSTER:'h',"hobbit",random
+MONSTER:'h',"dwarf",random
+MONSTER:'h',"dwarf",random
+MONSTER:'h',"dwarf",random
+MONSTER:'h',random,random
+
+
+# Mine end level variant 2
+# "Gnome King's Wine Cellar"
+#
+MAZE: "minend-2", ' '
+GEOMETRY:center,center
+MAP
+---------------------------------------------------------------------------
+|...................................................|                     |
+|.|---------S--.--|...|--------------------------|..|                     |
+|.||---|   |.||-| |...|..........................|..|                     |
+|.||...| |-|.|.|---...|.............................|                ..   |
+|.||...|-|.....|....|-|..........................|..|.               ..   |
+|.||.....|-S|..|....|............................|..|..                   |
+|.||--|..|..|..|-|..|----------------------------|..|-.                   |
+|.|   |..|..|....|..................................|...                  |
+|.|   |..|..|----|..-----------------------------|..|....                 |
+|.|---|..|--|.......|----------------------------|..|.....                |
+|...........|----.--|......................|     |..|.......              |
+|-----------|...|.| |------------------|.|.|-----|..|.....|..             |
+|-----------|.{.|.|--------------------|.|..........|.....|....           |
+|...............|.S......................|-------------..-----...         |
+|.--------------|.|--------------------|.|.........................       |
+|.................|                    |.....................|........    |
+---------------------------------------------------------------------------
+ENDMAP
+
+# Dungeon Description
+FOUNTAIN:(14,13)
+REGION:(23,03,48,06),lit,"ordinary"
+REGION:(21,06,22,06),lit,"ordinary"
+REGION:(14,04,14,04),unlit,"ordinary"
+REGION:(10,05,14,08),unlit,"ordinary"
+REGION:(10,09,11,09),unlit,"ordinary"
+REGION:(15,08,16,08),unlit,"ordinary"
+# Secret doors
+DOOR:locked,(12,02)
+DOOR:locked,(11,06)
+# Stairs
+STAIR:(36,04),up
+# Non diggable walls
+NON_DIGGABLE:(00,00,52,17)
+NON_DIGGABLE:(53,00,74,00)
+NON_DIGGABLE:(53,17,74,17)
+NON_DIGGABLE:(74,01,74,16)
+NON_DIGGABLE:(53,07,55,07)
+NON_DIGGABLE:(53,14,61,14)
+# The Gnome King's wine cellar.
+ENGRAVING:(12,03),engrave,"You are now entering the Gnome King's wine cellar."
+ENGRAVING:(12,04),engrave,"Trespassers will be persecuted!"
+OBJECT:'!',"booze",(10,07)
+OBJECT:'!',"booze",(10,07)
+OBJECT:'!',random,(10,07)
+OBJECT:'!',"booze",(10,08)
+OBJECT:'!',"booze",(10,08)
+OBJECT:'!',random,(10,08)
+OBJECT:'!',"booze",(10,09)
+OBJECT:'!',"booze",(10,09)
+OBJECT:'!',"object detection",(10,09)
+# Objects
+# The Treasure chamber...
+OBJECT:'*',"diamond",(69,04)
+OBJECT:'*',random,(69,04)
+OBJECT:'*',"diamond",(69,04)
+OBJECT:'*',random,(69,04)
+OBJECT:'*',"emerald",(70,04)
+OBJECT:'*',random,(70,04)
+OBJECT:'*',"emerald",(70,04)
+OBJECT:'*',random,(70,04)
+OBJECT:'*',"emerald",(69,05)
+OBJECT:'*',random,(69,05)
+OBJECT:'*',"ruby",(69,05)
+OBJECT:'*',random,(69,05)
+OBJECT:'*',"ruby",(70,05)
+OBJECT:'*',"amethyst",(70,05)
+OBJECT:'*',random,(70,05)
+OBJECT:'*',"amethyst",(70,05)
+OBJECT:'*',"luckstone",(70,05)
+# Scattered gems...
+OBJECT:'*',random,random
+OBJECT:'*',random,random
+OBJECT:'*',random,random
+OBJECT:'*',random,random
+OBJECT:'*',random,random
+OBJECT:'*',random,random
+OBJECT:'*',random,random
+OBJECT:'(',random,random
+OBJECT:'(',random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+# Random traps
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# Random monsters.
+MONSTER:'G',"gnome king",random
+MONSTER:'G',"gnome lord",random
+MONSTER:'G',"gnome lord",random
+MONSTER:'G',"gnome lord",random
+MONSTER:'G',"gnomish wizard",random
+MONSTER:'G',"gnomish wizard",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'G',"gnome",random
+MONSTER:'h',"hobbit",random
+MONSTER:'h',"hobbit",random
+MONSTER:'h',"dwarf",random
+MONSTER:'h',"dwarf",random
+MONSTER:'h',"dwarf",random
+MONSTER:'h',random,random
+
+
+# "Catacombs" by Kelly Bailey
+# Relies on some very specific behavior of MAZEWALK.
+#
+MAZE:"minend-3",'-'
+FLAGS:nommap
+GEOMETRY:center,bottom
+MAP
+ - - - - - - - - - - -- -- - - . - - - - - - - - - -- - - -- - - - - . - - |
+------...---------.-----------...-----.-------.-------     ----------------|
+ - - - - - - - - - - - . - - - . - - - - - - - - - - -- - -- - . - - - - - |
+------------.---------...-------------------------.---   ------------------|
+ - - - - - - - - - - . . - - --- - . - - - - - - - - -- -- - - - - |.....| |
+--.---------------.......------------------------------- ----------|.....S-|
+ - - - - |.. ..| - ....... . - - - - |.........| - - - --- - - - - |.....| |
+----.----|.....|------.......--------|.........|--------------.------------|
+ - - - - |..{..| - - -.... . --- - -.S.........S - - - - - - - - - - - - - |
+---------|.....|--.---...------------|.........|---------------------------|
+ - - - - |.. ..| - - - . - - - - - - |.........| - --- . - - - - - - - - - |
+----------------------...-------.---------------------...------------------|
+---..| - - - - - - - - . --- - - - - - - - - - - - - - . - - --- - - --- - |
+-.S..|----.-------.------- ---------.-----------------...----- -----.-------
+---..| - - - - - - - -- - - -- . - - - - - . - - - . - . - - -- -- - - - -- 
+-.S..|--------.---.---       -...---------------...{.---------   ---------  
+--|. - - - - - - - -- - - - -- . - - - --- - - - . . - - - - -- - - - - - - 
+ENDMAP
+
+RANDOM_PLACES:(1,15),(68,6),(1,13)
+NON_DIGGABLE:(67,3,73,7)
+NON_DIGGABLE:(0,12,2,16)
+FOUNTAIN:(12,08)
+FOUNTAIN:(51,15)
+REGION:(0,0,75,16),unlit,"ordinary"
+REGION:(38,6,46,10),lit,"ordinary"
+DOOR:closed,(37,8)
+DOOR:closed,(47,8)
+DOOR:closed,(73,5)
+DOOR:closed,(2,15)
+MAZEWALK:(36,8),west
+STAIR:(42,8),up
+
+# Objects
+OBJECT:'*',"diamond",random
+OBJECT:'*',random,random
+OBJECT:'*',"diamond",random
+OBJECT:'*',random,random
+OBJECT:'*',"emerald",random
+OBJECT:'*',random,random
+OBJECT:'*',"emerald",random
+OBJECT:'*',random,random
+OBJECT:'*',"emerald",random
+OBJECT:'*',random,random
+OBJECT:'*',"ruby",random
+OBJECT:'*',random,random
+OBJECT:'*',"ruby",random
+OBJECT:'*',"amethyst",random
+OBJECT:'*',random,random
+OBJECT:'*',"amethyst",random
+OBJECT:'*',"luckstone",place[0]
+OBJECT:'*',"flint",place[1]
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'+',random,random
+OBJECT:'+',random,random
+OBJECT:'+',random,random
+OBJECT:'+',random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+OBJECT:random,random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+TRAP:random,random
+# One-time annoyance factor
+TRAP:"level teleport",place[0]
+TRAP:"level teleport",place[1]
+MONSTER:'M',random,random
+MONSTER:'M',random,random
+MONSTER:'M',random,random
+MONSTER:'M',random,random
+MONSTER:'M',random,random
+MONSTER:'M',"ettin mummy",random
+MONSTER:'V',random,random
+MONSTER:'Z',random,random
+MONSTER:'Z',random,random
+MONSTER:'Z',random,random
+MONSTER:'Z',random,random
+MONSTER:'Z',random,random
+MONSTER:'V',random,random
+MONSTER:'e',random,random
+MONSTER:'e',random,random
+MONSTER:'e',random,random
+MONSTER:'e',random,random
+
+
+# end mines.des
diff --git a/dat/opthelp b/dat/opthelp
new file mode 100644 (file)
index 0000000..4dade58
--- /dev/null
@@ -0,0 +1,226 @@
+Boolean options not under specific compile flags (with default values in []):
+(You can learn which options exist in your version by checking your current
+option setting, which is reached via the 'O' cmd.)
+
+autodig        dig if moving and wielding digging tool            [FALSE]
+autopickup     automatically pick up objects you move over        [TRUE]
+autoquiver     when firing with an empty quiver, select some
+               suitable inventory weapon to fill the quiver       [FALSE]
+BIOS           allow the use of IBM ROM BIOS calls                [FALSE]
+cmdassist      give help for errors on direction & other commands [TRUE]
+confirm        ask before hitting tame or peaceful monsters       [TRUE]
+DECgraphics    use DEC/VT line-drawing characters for the dungeon [FALSE]
+eight_bit_tty  send 8-bit characters straight to terminal         [FALSE]
+extmenu        use a menu for selecting extended commands (#)     [FALSE]
+fixinv         try to retain the same letter for the same object  [TRUE]
+help           print all available info when using the / command  [TRUE]
+IBMgraphics    use IBM extended characters for the dungeon        [FALSE]
+ignintr        ignore interrupt signal, including breaks          [FALSE]
+legacy         print introductory message                         [TRUE]
+lit_corridor   show a dark corridor as lit if in sight            [FALSE]
+lootabc        use a/b/c rather than o/i/b when looting           [FALSE]
+mail           enable the mail daemon                             [TRUE]
+null           allow nulls to be sent to your terminal            [TRUE]
+               try turning this option off (forcing NetHack to use its own
+               delay code) if moving objects seem to teleport across rooms
+number_pad     use the number keys to move instead of yuhjklbn    [FALSE]
+perm_invent    keep inventory in a permanent window               [FALSE]
+prayconfirm    use confirmation prompt when #pray command issued  [TRUE]
+pushweapon     when wielding a new weapon, put your previously
+               wielded weapon into the secondary weapon slot      [FALSE]
+rawio          allow the use of raw I/O                           [FALSE]
+rest_on_space  count the space bar as a rest character            [FALSE]
+safe_pet       prevent you from (knowingly) attacking your pet(s) [TRUE]
+showrace       show yourself by your race rather than by role     [FALSE]
+silent         don't use your terminal's bell sound               [TRUE]
+sortpack       group similar kinds of objects in inventory        [TRUE]
+sound          enable messages about what your character hears    [TRUE]
+               (note: this has nothing to do with your computer's audio
+               capabilities, and the game resets it periodically)
+sparkle        display sparkly effect for resisted magical        [TRUE]
+               attacks (e.g. fire attack on fire-resistant monster)
+standout       use standout mode for --More-- on messages         [FALSE]
+time           display elapsed game time, in moves                [FALSE]
+tombstone      print tombstone when you die                       [TRUE]
+toptenwin      print topten in a window rather than stdout        [FALSE]
+travel         enable the command to travel to a map location via [TRUE]
+               a shortest-path algorithm, usually invoked by '_'.
+verbose        print more commentary during the game              [TRUE]
+
+
+
+There are further boolean options controlled by compilation flags.
+
+Boolean option if INSURANCE was set at compile time:
+checkpoint save game state after each level change, for possible  [TRUE]
+           recovery after program crash
+
+Boolean option if NEWS was set at compile time:
+news       print any news from game administrator on startup      [TRUE]
+
+Boolean option if MFLOPPY was set at compile time:
+checkspace check free disk space before writing files to disk     [TRUE]
+
+Boolean option if EXP_ON_BOTL was set at compile time:
+showexp    display your accumulated experience points             [FALSE]
+
+Boolean option if SCORE_ON_BOTL was set at compile time:
+showscore  display your approximate accumulated score             [FALSE]
+
+Boolean options if TEXTCOLOR was set at compile time:
+color      use different colors for objects on screen   [TRUE for micros]
+hilite_pet display pets in a highlighted manner                   [FALSE]
+
+Boolean option if TIMED_DELAY was set at compile time (tty interface only):
+timed_delay    on unix and VMS, use a timer instead of sending
+               extra screen output when attempting to pause for
+               display effect.  on MSDOS without the termcap
+               lib, whether or not to pause for visual effect.    [TRUE]
+
+Boolean option if USE_TILES was set at compile time (MSDOS protected mode only):
+preload_tiles  control whether tiles get pre-loaded into RAM at the
+               start of the game.  Doing so enhances performance
+               of the tile graphics, but uses more memory.        [TRUE]
+
+Any Boolean option can be negated by prefixing it with a '!' or 'no'.
+
+
+Compound options are written as option_name:option_value.
+
+Compound options which can be set during the game are:
+
+boulder       override the default boulder symbol with another default: [`]
+disclose      the types of information you want offered at the end of the
+              game  [ni na nv ng nc]
+fruit         the name of a fruit you enjoy eating  [slime mold]
+              (basically a whimsy which NetHack uses from time to time).
+menustyle     user interface for selection of multiple objects:
+              Traditional -- one object at a time prompting;
+              Combination -- prompt for classes of interest, then menu;
+              Partial     -- skip class prompt, use menu of all objects;
+              Full        -- menu for classes of interest, then object menu;
+              only the first letter ('T','C','P','F') matters; 'N' (None)
+              is a synonym for 'T', as is boolean style negation  [Full]
+packorder     a list of default symbols for kinds of objects that gives the
+              order in which your pack will be displayed  [")[%?+!=/(*`0_]
+              (If you specify only some kinds of items, the others from the
+              default order will be appended to the end.)
+pickup_burden when you pick up an item that exceeds this encumberance
+              level (Unburdened, Burdened, streSsed, straiNed, overTaxed,
+              or overLoaded), you will be asked if you want to continue. [S]
+pickup_types  a list of default symbols for kinds of objects to autopickup
+              when that option is on  [all]
+runmode       controls how often the map window is updated when performing
+              multi-step movement (various running modes or travel command):
+              teleport -- don't update map until movement stops;
+              run      -- periodically update map (interval is seven steps);
+              walk     -- update map after every step;
+              crawl    -- like walk, but delay after making each step.
+              (This only affects screen display, not actual movement.)  [run]
+scores        the parts of the score list you wish to see when the game ends
+              You choose a combination of top scores, scores around the top
+              scores, and all of your own scores.  [!own/3 top/2 around]
+suppress_alert disable various version-specific warnings about changes
+              in game play or the user interface, such as notification given
+              for the 'Q' command that quitting is now done via #quit
+              (e.g., use suppress_alert:3.3.1 to stop that and any other
+              notifications added in that version or earlier) default: [(none)]
+
+Compound options which may be set only on startup are:
+
+align      Your starting alignment (align:lawful, align:neutral,
+           or align:chaotic).  You may specify just the first letter.  [RANDOM]
+catname    the name of your first cat  [NONE]
+dogname    the name of your first dog  [NONE]
+dungeon    a list of symbols to be used in place of the default ones for
+           drawing the dungeon.
+           The symbols are subjected to a fair amount of processing, so
+           that you can use C-style escapes such as \n or \081 as well as
+           indicate control characters by ^x or meta characters by \Mx.
+           As usual, \ can force the next character to be taken literally.
+           Since many of the default symbols are overloaded, they are
+           given here by name instead of symbol, with some added notes:
+           stone                               (solid rock, normally ' ')
+           vwall hwall tlcorn trcorn blcorn brcorn      (room boundaries)
+           crwall tuwall tdwall tlwall trwall (wallified maze characters)
+           nodoor vodoor hodoor      (no, vertical, horizontal open door)
+           vcdoor hcdoor               (vertical, horizontal closed door)
+           ironbars tree room darkcorr litcorr
+           upstair dnstair upladder dnladder
+           altar grave throne sink fountain pool ice lava
+           vodbridge hodbridge     (vertical, horizontal open drawbridge)
+           vcdbridge hcdbridge   (vertical, horizontal closed drawbridge)
+           air cloud water
+           default:  \ |--------||.-|++##.##<><>_\\#{}.}..##\ #}
+effects    like dungeon, but for special effects symbols
+           vbeam hbeam lslant rslant                  (generic zap beams)
+           digbeam flashbeam      (special beams for digging and cameras)
+           boomleft boomright                                (boomerangs)
+           ss1 ss2 ss3 ss4                           (shielding sequence)
+           sw_topl, sw_topm, sw_topr,                  (swallow, top row)
+           sw_midl, sw_midr,            (swallow, middle row [no center])
+           sw_botl, sw_botm, sw_botr                (swallow, bottom row)
+           extl extm extr                      (explosion matrix top row)
+           exml exmm exmr                   (explosion matrix middle row)
+           exbl exbm exbr                   (explosion matrix bottom row)
+           default:  |-\\/*!)(0#@*/-\\||\\-//-\\|\ |\\-/
+gender     Your starting gender (gender:male or gender:female).
+           You may specify just the first letter.  Although you can
+           still denote your gender using the "male" and "female"
+           options, the "gender" option will take precedence.  [RANDOM]
+horsename  the name of your first horse  [NONE]
+menu_*     create single character accelerators for menu commands.  Below
+           is a list of all commands.  Each is followed by a list of window-
+           ports that implement them:  'x' is X11, 't' is tty, 'g' is Gem,
+           'a' is Amiga.
+           menu_deselect_all  deselect all items in a menu [-](gxta)
+           menu_deselect_page deselect all items on this page of a menu [\](gta)
+           menu_first_page    jump to the first page in a menu [^](gta)
+           menu_invert_all    invert all items in a menu [@](gxta)
+           menu_invert_page   invert all items on this page of a menu [~](gta)
+           menu_last_page     jump to the last page in a menu [|](gta)
+           menu_next_page     goto the next menu page [>](gta)
+           menu_previous_page goto the previous menu page [<](gta)
+           menu_search        search for a menu item [:](gxa)
+           menu_select_all    select all items in a menu [.](gxta)
+           menu_select_page   select all items on this page of a menu [,](gta)
+monsters   like dungeon, but for monster symbols
+           default:  abcdefghijklmnopqrstuvwxyz
+                     ABCDEFGHIJKLMNOPQRSTUVWXYZ@\ \\&;:~]
+msghistory number of top line messages to save [20]
+name       the name of your character  [obtained by asking the system or
+           the player]
+objects    like dungeon, but for object symbols
+           default:  ])[="(%!?+/$*`0_.
+pettype    your preferred type of pet (cat or dog), if your character
+           class uses both types; or none for no pet  [RANDOM]
+race       Your starting race (e.g., race:Human, race:Elf).  [RANDOM]
+role       Your starting role (e.g., role:Barbarian, role:Valk).
+           Although you can specify just the first letter(s), it will
+           choose only the first role it finds that matches; thus, it
+           is recommended that you spell out as much of the role name
+           as possible.  You can also still denote your role by
+           appending it to the "name" option (e.g., name:Vic-V), but the
+           "role" option will take precedence.  [RANDOM]
+traps      like dungeon, but for trap symbols
+           arrow_trap dart_trap falling_rock_trap squeaky_board
+           bear_trap land_mine rolling_boulder_trap sleeping_gas_trap
+           rust_trap fire_trap pit spiked_pit hole trap_door
+           teleportation_trap level_teleporter magic_portal web statue_trap
+           magic_trap anti_magic_trap polymorph_trap
+           default:  ^^^^^^^^^^^^^^^^^"^^^^
+
+windowtype windowing system to be used  [depends on operating system]
+
+Compound option if TTY_GRAPHICS was set at compile time:
+msg_window the type of message window to use:
+           single      -- One message at a time
+           full        -- Full window with all saved top line messages
+           reverse     -- Same as full, but messages printed most-recent-first
+           combination -- Two single messages, then as full
+           default:  single
+
+Some sample options lists are:
+!autopickup,!tombstone,name:Gandalf,scores:own/3 top/2 around
+female,nonews,dogname:Rover,dungeon: |--------||.-|++.##<><>_\\#{}.}..## #}
+rest_on_space,!verbose,menustyle:traditional
diff --git a/dat/oracle.des b/dat/oracle.des
new file mode 100644 (file)
index 0000000..0e8f176
--- /dev/null
@@ -0,0 +1,56 @@
+#      SCCS Id: @(#)oracle.des 3.4     1995/10/07
+# NetHack may be freely redistributed.  See license for details.
+#
+# Oracle level
+#
+
+LEVEL: "oracle"
+
+ROOM: "ordinary" , lit, (3,3), (center,center), (11,9)
+NAME: "central"
+OBJECT:'`',"statue",(0,0),"forest centaur",1
+OBJECT:'`',"statue",(0,8),"mountain centaur",1
+OBJECT:'`',"statue",(10,0),"mountain centaur",1
+OBJECT:'`',"statue",(10,8),"forest centaur",1
+OBJECT:'`',"statue",(5,1),"plains centaur",1
+OBJECT:'`',"statue",(5,7),"plains centaur",1
+OBJECT:'`',"statue",(2,4),"plains centaur",1
+OBJECT:'`',"statue",(8,4),"plains centaur",1
+MONSTER: random, random, random
+MONSTER: random, random, random
+
+SUBROOM: "delphi" , lit , (4,3) , (3,3), "central"
+FOUNTAIN: (0, 1)
+FOUNTAIN: (1, 0)
+FOUNTAIN: (1, 2)
+FOUNTAIN: (2, 1)
+MONSTER: '@', "Oracle", (1,1)
+DOOR: false , nodoor , random, random
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, up
+OBJECT: random,random,random
+
+ROOM: "ordinary" , random, random, random, random
+STAIR: random, down
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: random, random, random
+MONSTER: random, random, random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+OBJECT: random, random, random
+MONSTER: random, random, random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: random, random, random
+
+ROOM: "ordinary" , random, random, random, random
+OBJECT: random, random, random
+TRAP: random, random
+MONSTER: random, random, random
+
+RANDOM_CORRIDORS
diff --git a/dat/oracles.txt b/dat/oracles.txt
new file mode 100644 (file)
index 0000000..8a37a4f
--- /dev/null
@@ -0,0 +1,99 @@
+-----
+If thy wand hath run out of charges, thou mayst zap it again and again; though
+naught will happen at first, verily, thy persistence shall be rewarded, as
+one last charge may yet be wrested from it!
+-----
+Though the shopkeepers be wary, thieves have nevertheless stolen much by using
+their digging wands to hasten exits through the pavement.
+-----
+If thou hast had trouble with rust on thine armor or weapons, thou shouldst
+know that thou canst prevent this by, while in a confused state, reading the
+magical parchments which normally are used to cause their enchantment.
+Unguents of lubrication may provide similar protection, albeit of a
+transitory nature.
+-----
+Behold the cockatrice, whose diminutive stature belies its hidden might.  The
+cockatrice can petrify any ordinary being it contacts--save those wise
+adventurers who eat a dead lizard or blob of acid when they feel themselves
+slowly turning to stone.
+-----
+While some wayfarers rely on scrounging finished armour in the dungeon, the
+resourceful know the mystical means by which mail may be fashioned out of
+scales from a dragon's hide.
+-----
+It is customarily known among travelers that extra-healing draughts may clear
+thy senses when thou art addled by delusory visions.  But never forget, the
+lowly potion which makes one sick may be used for the same purpose.
+-----
+While the consumption of lizard flesh or water beloved of the gods may clear
+the muddled head, the application of the horn of a creature of utmost purity
+can alleviate many other afflictions as well.
+-----
+If thou wouldst travel quickly between distant locations, thou must be
+able to control thy teleports, and in a confused state misread the scroll
+which usually teleports thyself locally.  Daring adventurers have also
+performed the same feat sans need for scrolls or potions by stepping into
+a particular ambuscade.
+-----
+Almost all adventurers who come this way hope to pass the dread Medusa.  To
+do this, the best advice is to keep thine eyes blindfolded and to cause the
+creature to espy its own reflection in a mirror.
+-----
+And where it is written "ad aerarium", diligent searching will often reveal
+the way to a trap which sends one to the Magic Memory Vault, where the riches
+of Croesus are stored; however, escaping from the vault with its gold is much
+harder than getting in.
+-----
+It is well known that wily shopkeepers raise their prices whene'er they
+espy the garish apparel of the approaching tourist or the countenance of a
+disfavored patron.  They favor the gentle of manner and the fair of face.
+The boor may expect unprofitable transactions.
+----- SINKS
+The cliche of the kitchen sink swallowing any unfortunate rings that contact
+its pernicious surface reflecteth greater truth than many homilies, yet
+even so, few have developed the skill to identify enchanted rings by the
+transfigurations effected upon the voracious device's frame.
+-----
+The meat of enchanted creatures ofttimes conveyeth magical properties
+unto the consumer.  A fresh corpse of floating eye doth fetch a high
+price among wizards for its utility in conferring Telepathy, by which
+the sightless may locate surrounding minds.
+-----
+The detection of blessings and curses is in the domain of the gods.  They will
+make this information available to mortals who request it at their places of
+worship, or elsewhere for those mortals who devote themselves to the service
+of the gods.
+-----
+At times, the gods may favor worthy supplicants with named blades whose
+powers echo throughout legend.  Learned wayfarers can reproduce blades of
+elven lineage, hated of the orcs, without the need for such intervention.
+-----
+There are many stories of a mighty amulet, the origins of which are said
+to be ancient Yendor.  This amulet doth have awesome power, and the gods
+desire it greatly.  Mortals mayst tap only portions of its terrible
+abilities.  The stories tell of mortals seeing what their eyes cannot
+see and seeking places of magical transportation, while having this
+amulet in their possession.  Others say a mortal must wear the amulet to
+obtain these powers.  But verily, such power comes at great cost, to
+preserve the balance.
+-----
+It is said that thou mayst gain entry to Moloch's sanctuary, if thou
+darest, from a place where the ground vibrateth in the deepest depths of
+Gehennom.  Thou needs must have the aid of three magical items.  The
+pure sound of a silver bell shall announce thee.  The terrible runes,
+read from Moloch's book, shall cause the earth to tremble mightily.  The
+light of an enchanted candelabrum shall show thee the way.
+-----
+In the deepest recesses of the Dungeons of Doom, guarding access to the
+nether regions, there standeth a castle, wherein lieth a wand of wishes.
+If thou wouldst gain entry, bear with thee an instrument of music, for the
+pontlevis may be charmed down with the proper melody.  What notes comprise
+it only the gods know, but a musical mastermind may yet succeed by witful
+improvisation.  However, the less perspicacious are not without recourse,
+should they be prepared to circumambulate the castle to the postern.
+----- ELBERETH
+The name of Elbereth may strike fear into the hearts of thine enemies, if
+thou dost write it upon the ground at thy feet.  If thou maintainest the
+utmost calm, thy safety will be aided greatly, but beware lest thy clumsy
+feet scuff the inscription, cancelling its potence.
+-----
diff --git a/dat/quest.txt b/dat/quest.txt
new file mode 100644 (file)
index 0000000..7cfb724
--- /dev/null
@@ -0,0 +1,3507 @@
+#      SCCS Id: @(#)quest.txt  3.4     2002/01/30
+#      Copyright (c) 1991 by M. Stephenson
+# NetHack may be freely redistributed.  See license for details.
+#
+#      The quest text file for NetHack 3.4
+#
+#      These are the "standard" message numbers from qtext.h.  All class
+#      dialogue must have at least these entries.
+#
+#      QT_FIRSTTIME     1
+#      QT_NEXTTIME      2
+#      QT_OTHERTIME     3
+#
+#      QT_GUARDTALK     5      /* 5 random things guards say before quest */
+#      QT_GUARDTALK2   10      /* 5 random things guards say after quest */
+#
+#      QT_FIRSTLEADER  15
+#      QT_NEXTLEADER   16
+#      QT_OTHERLEADER  17
+#      QT_LASTLEADER   18
+#      QT_BADLEVEL     19
+#      QT_BADALIGN     20
+#      QT_ASSIGNQUEST  21
+#
+#      QT_ENCOURAGE    25      /* 1-10 random encouragement messages */
+#
+#      QT_FIRSTLOCATE  35
+#      QT_NEXTLOCATE   36
+#
+#      QT_FIRSTACQUIRE 40
+#      QT_NEXTACQUIRE  41
+#
+#      QT_FIRSTNEMESIS 50
+#      QT_NEXTNEMESIS  51
+#      QT_OTHERNEMESIS 52
+#      QT_NEMWANTSIT   53      /* you somehow got the artifact */
+#
+#      QT_DISCOURAGE   60      /* 1-10 random maledictive messages */
+#
+#      QT_GOTIT        70
+#
+#      QT_KILLEDNEM    80
+#      QT_OFFEREDIT    81
+#      QT_OFFEREDIT2   82      /* if you throw artifact to leader after #81 */
+#
+#      QT_POSTHANKS    90
+#      QT_HASAMULET    91
+#
+#
+#      Archeologist
+#
+%Cc Arc 00001
+You are suddenly in familiar surroundings.  The buildings in the distance
+appear to be those of your old alma mater, but something is wrong.  It looks
+as if there has been a riot recently, or %H has
+been under siege.
+
+All of the windows are boarded up, and there are objects scattered around
+the entrance.
+
+Strange forbidding shapes seem to be moving in the distance.
+%E
+%Cp Arc 00002
+Once again, you are back at %H.
+%E
+%Cp Arc 00003
+You are back at %H.
+You have an odd feeling this may be the last time you ever come here.
+%E
+%Cp Arc 00005
+"Did you see Lash LaRue in 'Song of Old Wyoming' the other night?"
+%E
+%Cp Arc 00006
+"Hey man, got any potions of hallucination for sale?"
+%E
+%Cp Arc 00007
+"Did you see the artifact %l brought back from the last dig?"
+%E
+%Cp Arc 00008
+"So what species do *you* think we evolved from?"
+%E
+%Cp Arc 00009
+"So you're %ls prize pupil!  I don't know what he sees in you."
+%E
+%Cp Arc 00010
+"Did you see Lash LaRue in 'Song of Old Wyoming' the other night?"
+%E
+%Cp Arc 00011
+"Hey man, got any potions of hallucination for sale?"
+%E
+%Cp Arc 00012
+"I guess you are guaranteed to make full professor now."
+%E
+%Cp Arc 00013
+"So, what was worse, %n or your entrance exams?"
+%E
+%Cp Arc 00014
+"%oC is impressive, but nothing like the bones I dug up!"
+%E
+%Cc Arc 00015
+"Finally you have returned, %p.  You were always
+my most promising student.  Allow me to see if you are ready for the
+most difficult task of your career."
+%E
+%Cp Arc 00016
+"Again, %p, you stand before me.
+Let me see if you have gained experience in the interim."
+%E
+%Cp Arc 00017
+"Once more, %p, you have returned from the field.
+Are you finally ready for the task that must be accomplished?"
+%E
+%Cc Arc 00018
+"%p, you have failed us.  All of my careful training has been in
+vain.  Begone!  Your tenure at this college has been revoked!
+
+"You are a disgrace to the profession!"
+%E
+%Cc Arc 00019
+"%p, you are yet too inexperienced to undertake such a demanding
+quest.  A mere %r could not possibly face the rigors demanded and
+survive.  Go forth, and come here again when your adventures have further
+taught you."
+%E
+%Cc Arc 00020
+"%pC!  I've heard that you've been using sloppy techniques.  Your
+results lately can hardly be called suitable for %ra!
+
+"How could you have strayed from the %a path?  Go from here, and come
+back only when you have purified yourself."
+%E
+%Cc Arc 00021
+"Grave times have befallen the college, for %na has
+stolen %o.  Without it, the board of directors of
+the university will soon have no choice but to revoke our research grants.
+
+"You must locate the entrance to %i.  Within it,
+you will find %n.
+
+"You must then defeat %n and return %o
+to me.
+
+"Only in this way will we be able to prevent the budget cuts that could
+close this college.
+
+"May the wisdom of %d be your guide."
+%E
+%Cp Arc 00025
+"Beware, for %n is powerful and cunning."
+%E
+%Cp Arc 00026
+"To locate the entrance to %i, you must pass
+many traps."
+%E
+%Cp Arc 00027
+"A %nt may be vulnerable to attacks by magical cold."
+%E
+%Cp Arc 00028
+"Call upon %d when you encounter %n."
+%E
+%Cp Arc 00029
+"You must destroy %n.  It will pursue you otherwise."
+%E
+%Cp Arc 00030
+"%oC is a mighty talisman.  With it you
+can destroy %n."
+%E
+%Cp Arc 00031
+"Go forth with the blessings of %d."
+%E
+%Cp Arc 00032
+"I will have my %gP watch for your return."
+%E
+%Cp Arc 00033
+"Remember not to stray from the true %a path."
+%E
+%Cp Arc 00034
+"You may be able to sense %o when you are near."
+%E
+%Cc Arc 00035
+A plain opens before you.  Beyond the plain lies a foreboding edifice.
+
+You have the feeling that you will soon find the entrance to
+%i.
+%E
+%Cp Arc 00036
+Once again, you are near the entrance to %i.
+%E
+%Cc Arc 00040
+A strange feeling washes over you, and you think back to things you
+learned during the many lectures of %l.
+
+You realize the feeling must be the presence of %o.
+%E
+%Cp Arc 00041
+The familiar presence of %o is in the ether.
+%E
+%Cc Arc 00050
+"So, %p, you think that you can succeed in recovering
+%o, when your teacher, %l, has already failed.
+
+"Come, try your best!  I shall destroy you, and gnaw on your bones."
+%E
+%Cc Arc 00051
+"Again you try to best me, eh %p?  Well, you shall fail again.
+
+"You shall never recover %o.
+
+"I shall bear your soul to the Plane of Origins for my master's pleasure."
+%E
+%Cp Arc 00052
+"You persist yet %p!  Good.  Now, you shall die!"
+%E
+%Cp Arc 00053
+"I shall have %o from you, %p, then feast
+upon your entrails!"
+%E
+%Cp Arc 00060
+"Try your best, %p.  You cannot defeat me."
+%E
+%Cp Arc 00061
+"I shall rend the flesh from your body whilst you still breathe!"
+%E
+%Cp Arc 00062
+"First you, %p, then I shall destroy your mentor, %l."
+%E
+%Cp Arc 00063
+"Tiring yet, %p?  I draw my power from my master and cannot
+falter!"
+%E
+%Cp Arc 00064
+"I shall rend thy soul from thy body and consume it!"
+%E
+%Cp Arc 00065
+"You are far too %a -- it weakens you.  You shall die in this place."
+%E
+%Cp Arc 00066
+"%d has forsaken you!  You are lost now!"
+%E
+%Cp Arc 00067
+"A mere %r cannot hope to defeat me!"
+%E
+%Cp Arc 00068
+"If you are the best %l can send, I have nothing to fear."
+%E
+%Cp Arc 00069
+"Die %c!  I shall exhibit your carcass as a trophy."
+%E
+%Cc Arc 00070
+The power of %o flows through your body!  You feel
+as if you could now take on the Wizard of Yendor himself and win, but
+you know you must return %o to %l.
+%E
+%Cp Arc 00080
+The body of %n dissipates in a cloud of noxious fumes.
+%E
+%Cc Arc 00081
+%lC touches %o briefly, gazes into it,
+then smiles at you and says:
+
+"Well done, %p.  You have defeated %n and
+recovered %o.  But I fear that it shall never be safe
+here.
+
+Please take %o with you.  You, %p, can
+guard it now far better than I.
+
+May the blessings of %d follow you and guard you."
+%E
+# assumes Orb of Detection (glass object)
+%Cc Arc 00082
+"Careful, %p!  %oC might break, and that would be
+a tragic loss.  You are its keeper now, and the time has come to
+resume your search for the Amulet.  %Z await your
+return through the magic portal that brought you here."
+%E
+%Cc Arc 00090
+"Welcome back, %p.  Have you progressed with your quest to
+regain the Amulet of Yendor for %d?"
+%E
+%Cc Arc 00091
+"Congratulations, %p.  I wondered if anyone could prevail against
+the Wizard and the minions of Moloch.  Now, you must embark on one
+final adventure.
+
+"Take the Amulet, and find your way onto the astral plane.
+There you must find the altar of %d and sacrifice the
+Amulet on that altar to fulfill your destiny.
+
+"Remember, your path now should always be upwards."
+%E
+#
+#      Barbarian
+#
+%Cc Bar 00001
+Warily you scan your surroundings, all of your senses alert for signs
+of possible danger.  Off in the distance, you can %x the familiar shapes
+of %H.
+
+But why, you think, should %l be there?
+
+Suddenly, the hairs on your neck stand on end as you detect the aura of
+evil magic in the air.
+
+Without thought, you ready your weapon, and mutter under your breath:
+
+    "By %d, there will be blood spilt today."
+%E
+%Cp Bar 00002
+Once again, you near %H.  You know that %l
+will be waiting.
+%E
+%Cp Bar 00003
+Again, and you think possibly for the last time, you approach
+%H.
+%E
+%Cp Bar 00005
+"The battles here have been good -- our enemies' blood soaks the soil!"
+%E
+%Cp Bar 00006
+"Remember that glory is crushing your enemies beneath your feet!"
+%E
+%Cp Bar 00007
+"There has been little treasure to loot, since the horde arrived."
+%E
+%Cp Bar 00008
+"The horde is mighty in numbers, but they have little courage."
+%E
+%Cp Bar 00009
+"%lC is a strange one, but he has helped defend us."
+%E
+%Cp Bar 00010
+"The battles here have been good -- our enemies' blood soaks the soil!"
+%E
+%Cp Bar 00011
+"Remember that glory is crushing your enemies beneath your feet!"
+%E
+%Cp Bar 00012
+"Times will be good again, now that the horde is vanquished."
+%E
+%Cp Bar 00013
+"You have brought our clan much honor in defeating %n."
+%E
+%Cp Bar 00014
+"You will be a worthy successor to %l."
+%E
+%Cc Bar 00015
+"Ah, %p.  You have returned at last.  The world is in dire
+need of your help.  There is a great quest you must undertake.
+
+"But first, I must see if you are ready to take on such a challenge."
+%E
+%Cp Bar 00016
+"%p, you are back.  Are you ready now for the challenge?"
+%E
+%Cp Bar 00017
+"Again, you stand before me, %p.  Surely you have prepared yourself."
+%E
+%Cc Bar 00018
+"Pah!  You have betrayed the gods, %p.  You will never attain
+the glory which you aspire to.  Your failure to follow the true path has
+closed this future to you.
+
+"I will protect these people as best I can, but soon %n will overcome
+me and destroy all who once called you %s.  Now begone!"
+%E
+%Cc Bar 00019
+"%p, I fear that you are as yet too inexperienced to face
+%n.  Only %Ra with the help of %d could ever hope to
+defeat him."
+%E
+%Cc Bar 00020
+"%pC!  You have wandered from the path of the %a!
+If you attempt to overcome %n in this state, he will surely
+enslave your soul.  Your only hope, and ours, lies in your purification.
+Go forth, and return when you feel ready."
+%E
+%Cc Bar 00021
+"The world is in great need of your assistance, %p.
+
+"About six months ago, I learned that a mysterious sorcerer, known
+as %n, had begun to gather a large group of cutthroats and brigands
+about him.
+
+"At about the same time, these people you once rode with `liberated' a
+potent magical talisman, %o, from a Turanian caravan.
+
+"%nC and his Black Horde swept down upon %i and defeated
+the people there, driving them out into the desert.  He has taken
+%o, and seeks to bend it to his will.  I detected the
+subtle changes in the currents of fate, and joined these people.
+Then I sent forth a summons for you.
+
+"If %n can bend %o to his will, he will become
+almost indestructible.  He will then be able to enslave the minds of
+men across the world.  You are the only hope.  The gods smile upon you,
+and with %d behind you, you alone can defeat %n.
+
+"You must go to %i.  From there, you can track down
+%n, defeat him, and return %o to us.  Only
+then will the world be safe."
+%E
+%Cp Bar 00025
+"%nC is strong in the dark arts, but not immune to cold steel."
+%E
+%Cp Bar 00026
+"Remember that %n is a great sorcerer.  He lived in the time
+of Atlantis."
+%E
+%Cp Bar 00027
+"If you fail, %p, I will not be able to protect these people long."
+%E
+%Cp Bar 00028
+"To enter %i, you must be very stealthy.  The horde will be on
+guard."
+%E
+%Cp Bar 00029
+"Call upon %d in your time of need."
+%E
+%Cp Bar 00030
+"May %d protect you, and guide your steps."
+%E
+%Cp Bar 00031
+"If you can lay hands upon %o, carry it for good fortune."
+%E
+%Cp Bar 00032
+"I cannot stand against %ns sorcery.  But %d will help you."
+%E
+%Cp Bar 00033
+"Do not fear %n.  I know you can defeat him."
+%E
+%Cp Bar 00034
+"You have a great road to travel, %p, but only after you defeat
+%n."
+%E
+%Cc Bar 00035
+The scent of water comes to you in the desert breeze.  You know that
+you have located %i.
+%E
+%Cp Bar 00036
+Yet again you have a chance to infiltrate %i.
+%E
+%Cc Bar 00040
+The hairs on the nape of your neck lift as you sense an energy in the
+very air around you.  You fight down a primordial panic that seeks to
+make you turn and run.  This is surely the lair of %n.
+%E
+%Cp Bar 00041
+Yet again you feel the air around you heavy with malevolent magical energy.
+%E
+%Cc Bar 00050
+"So.  This is what that second rate sorcerer %l sends to do his bidding.
+I have slain many before you.  You shall give me little sport.
+
+"Prepare to die, %c."
+%E
+%Cp Bar 00051
+"I have wasted too much time on you already.  Now, you shall die."
+%E
+%Cp Bar 00052
+"You return yet again, %c!  Are you prepared for death now?"
+%E
+%Cp Bar 00053
+"I shall have %o back, you pitiful excuse for %ca.
+And your life as well."
+%E
+%Cp Bar 00060
+"My pets will dine on your carcass tonight!"
+%E
+%Cp Bar 00061
+"You are a sorry excuse for %ra."
+%E
+%Cp Bar 00062
+"Run while you can, %c.  My next spell will be your last."
+%E
+%Cp Bar 00063
+"I shall use your very skin to bind my next grimoire."
+%E
+%Cp Bar 00064
+"%d cannot protect you now.  Here, you die."
+%E
+%Cp Bar 00065
+"Your %a nature makes you weak.  You cannot defeat me."
+%E
+%Cp Bar 00066
+"Come, %c.  I shall kill you, then unleash the horde on your tribe."
+%E
+%Cp Bar 00067
+"Once you are dead, my horde shall finish off %l, and your tribe."
+%E
+%Cp Bar 00068
+"Fight, %c, or are you afraid of the mighty %n?"
+%E
+%Cp Bar 00069
+"You have failed, %c.  Now, my victory is complete."
+%E
+%Cc Bar 00070
+As you pick up %o, you feel the power of it
+flowing through your hands.  It seems to be in two or more places
+at once, even though you are holding it.
+%E
+%Cc Bar 00080
+%nC falls to the ground, and utters a last curse at you.  Then his
+body fades slowly, seemingly dispersing into the air around you.  You
+slowly become aware that the overpowering aura of magic in the air has
+begun to fade.
+%E
+%Cc Bar 00081
+When %l sees %o, he smiles, and says:
+
+    Well done, %p.  You have saved the world from certain doom.
+    What, now, should be done with %o?
+
+    These people, brave as they are, cannot hope to guard it from
+    other sorcerers who will detect it, as surely as %n did.
+
+    Take %o with you, %p.  It will guard you in
+    your adventures, and you can best guard it.  You embark on a
+    quest far greater than you realize.
+
+    Remember me, %p, and return when you have triumphed.  I
+    will tell you then of what you must do.  You will understand when the
+    time comes.
+%E
+%Cc Bar 00082
+%l gazes reverently at %o, then back at you.
+
+"You are its keeper now, and the time has come to resume your search
+for the Amulet.  %Z await your return through the
+magic portal which brought you here."
+%E
+%Cp Bar 00090
+"Tell us, %p, have you fared well on your great quest?"
+%E
+%Cc Bar 00091
+"This is wondrous, %p.  I feared that you could not possibly
+succeed in your quest, but here you are in possession of the Amulet
+of Yendor!
+
+"I have studied the texts of the magi constantly since you left.  In
+the Book of Skelos, I found this:
+
+    %d will cause a child to be sent into the world.  This child is to
+    be made strong by trial of battle and magic, for %d has willed it so.
+    It is said that the child of %d will recover the Amulet of Yendor
+    that was stolen from the Creator at the beginning of time.
+
+"As you now possess the amulet, %p, I suspect that the Book
+speaks of you.
+
+    The child of %d will take the Amulet, and travel to the Astral
+    Plane, where the Great Temple of %d is to be found.  The Amulet
+    will be sacrificed to %d, there on His altar.  Then the child will
+    stand by %d as champion of all %cP for eternity.
+
+"This is all I know, %p.  I hope it will help you."
+%E
+#
+#      Cave(wo)man
+#
+%Cc Cav 00001
+You descend through a barely familiar stairwell that you remember
+%l showing you when you embarked upon your vision quest.
+
+You arrive back at %H, but something seems
+wrong here.  The usual smoke and glowing light of the fires of the
+outer caves are absent, and an uneasy quiet fills the damp air.
+%E
+%Cp Cav 00002
+Once again, you arrive back at %H.
+%E
+%Cp Cav 00003
+For some reason, you think that this may be the last time you will
+enter %H.
+%E
+%Cp Cav 00005
+"We have not been able to gather as much food since the Giants sealed
+off our access to the outer world."
+%E
+%Cp Cav 00006
+"Since %n sent her minions, we have been constantly fighting."
+%E
+%Cp Cav 00007
+"I have heard your vision quest was successful.  Is this so?"
+%E
+%Cp Cav 00008
+"So, tell me, %p, how have you fared?"
+%E
+%Cp Cav 00009
+"%lC grows old.  We know not who will guide us after he ascends."
+%E
+%Cp Cav 00010
+"The rains have returned and the land grows lush again."
+%E
+%Cp Cav 00011
+"Peace has returned, give thanks to %d!"
+%E
+%Cp Cav 00012
+"Welcome back!  Did you find %o?"
+%E
+%Cp Cav 00013
+"So, %p, tell us the story of your fight with %n."
+%E
+%Cp Cav 00014
+"%lC grows old.  Perhaps you will guide us after he ascends."
+%E
+%Cc Cav 00015
+"You have returned from your vision quest, %p.  Thank %d.
+
+"We are in dire need of your help, my %S.
+
+"But first, I must see if you are yet capable of the quest I would
+ask you to undertake."
+%E
+%Cp Cav 00016
+"Again, you return to us, %p.  Let me see if you are ready now."
+%E
+%Cp Cav 00017
+"Ah, %p.  Are you finally ready?"
+%E
+%Cc Cav 00018
+"%pC!  You have sealed our fate.  You seem unable to reform yourself,
+so I must select another to take your place.
+
+"Begone from %H!  You have betrayed us by choosing
+the path of the %C over the true path of the %L.
+
+"You no longer live in our eyes."
+%E
+%Cc Cav 00019
+"Alas, %p, you are as yet too inexperienced to embark upon such
+a difficult quest as that I propose to give you.
+
+"%rA could not possibly survive the rigors demanded to find
+%i, never mind to confront %n herself.
+
+"Adventure some more, and you will learn the skills you will require.
+%d decrees it."
+%E
+%Cc Cav 00020
+"%pC!  You have deviated from my teachings.  You no longer follow
+the path of the %a as you should.  I banish you from these caves, to
+go forth and purify yourself.  Then, you might be able to accomplish this
+quest."
+%E
+%Cc Cav 00021
+"You are indeed ready now, %p.  I shall tell you a tale of
+great suffering among your people:
+
+"Shortly after you left on your vision quest, the caves were invaded by
+the creatures sent against us by %n.
+
+"She, herself, could not attack us due to her great size, but her minions
+have harassed us ever since.  In the first attacks, many died, and the
+minions of %n managed to steal %o.
+They took it to %i and there, none of our
+%g warriors have been able to go.
+
+"You must find %i, and within it wrest
+%o from %n.  She guards it as
+jealously as she guards all treasures she attains.  But with it,
+we can make our caves safe once more.
+
+"Please, %p, recover %o for us, and return it here."
+%E
+%Cp Cav 00025
+"%nC is immune to her own breath weapons.
+You should use magic upon her that she does not use herself."
+%E
+%Cp Cav 00026
+"When you encounter %n, call upon %d for assistance."
+%E
+%Cp Cav 00027
+"There will be nowhere to hide inside %ns inner sanctum."
+%E
+%Cp Cav 00028
+"Your best chance with %n will be to keep moving."
+%E
+%Cp Cav 00029
+"Do not be distracted by the great treasures in %ns lair.
+Concentrate on %o."
+%E
+%Cp Cav 00030
+"%oC is the only object that %n truly fears."
+%E
+%Cp Cav 00031
+"Do not be fooled by %ns size.  She is fast, and it is
+rumored that she uses magic."
+%E
+%Cp Cav 00032
+"I would send a party of %gP with you, but we will need all
+of our strength to defend ourselves."
+%E
+%Cp Cav 00033
+"Remember, be %a at all times.  This is your strength."
+%E
+%Cp Cav 00034
+"If only we had an amulet of reflection, this would not have happened."
+%E
+%Cc Cav 00035
+You %x many large claw marks on the ground.  The tunnels ahead
+of you are larger than most of those in any cave complex you have
+ever been in before.
+
+Your nose detects the smell of carrion from within, and bones litter
+the sides of the tunnels.
+%E
+%Cp Cav 00036
+Once again, you approach %i.
+%E
+%Cc Cav 00040
+You find yourself in a large cavern, with neatly polished walls, that
+nevertheless show signs of being scorched by fire.
+
+Bones litter the floor, and there are objects scattered everywhere.
+The air is close with the stench of sulphurous fumes.
+
+%nC is clearly visible, but she seems to be asleep.
+%E
+%Cp Cav 00041
+Once again, you find yourself in the lair of %n.
+%E
+%Cc Cav 00050
+"So, follower of %l, you seek to invade the lair of %n.
+Only my meals are allowed down here.  Prepare to be eaten!"
+%E
+%Cp Cav 00051
+"So, again you face me, %c.  No one has ever before escaped me.
+Now I shall kill you."
+%E
+%Cp Cav 00052
+"You are getting annoying, %c.  Prepare to die."
+%E
+%Cp Cav 00053
+"I'll have %o from you, %c.  You shall die."
+%E
+%Cp Cav 00060
+"You are weak, %c.  No challenge for the Mother of all Dragons."
+%E
+%Cp Cav 00061
+"I grow hungry, %r.  You look like a nice appetizer!"
+%E
+%Cp Cav 00062
+"Join me for lunch?  You're the main course, %c."
+%E
+%Cp Cav 00063
+"With %o, I am invincible!  You cannot succeed."
+%E
+%Cp Cav 00064
+"Your mentor, %l has failed.  You are nothing to fear."
+%E
+%Cp Cav 00065
+"You shall die here, %c.  %rA cannot hope to defeat me."
+%E
+%Cp Cav 00066
+"You, a mere %r challenge the might of %n?  Hah!"
+%E
+%Cp Cav 00067
+"I am the Mother of all Dragons!  You cannot hope to defeat me."
+%E
+%Cp Cav 00068
+"My claws are sharp now.  I shall rip you to shreds!"
+%E
+%Cp Cav 00069
+"%d has deserted you, %c.  This is my domain."
+%E
+%Cc Cav 00070
+As you pick up %o it seems heavy at first, but as you
+hold it strength flows into your arms.
+
+You suddenly feel full of power, as if nothing could possibly stand
+in your path.
+%E
+%Cp Cav 00080
+%nC sinks to the ground, her heads flailing about.
+As she dies, a cloud of noxious fumes billows about her.
+%E
+%Cc Cav 00081
+%lC glimpses %o in your possession.
+He smiles and says:
+
+    You have done it!  We are saved.  But I fear that %o
+    will always be a target for %C forces who will want it for their
+    own.
+
+    To prevent further trouble, I would like you, %p,
+    to take %o away with you.  It will help you as you
+    quest for the Amulet of Yendor.
+%E
+%Cc Cav 00082
+%l grasps %o proudly for a moment, then looks at you.
+
+"You are its keeper now, and the time has come to resume your search
+for the Amulet.  %Z await your return through the
+magic portal which brought you here."
+%E
+%Cp Cav 00090
+"%pC!  Welcome back.
+How goes your quest to recover the Amulet for %d?"
+%E
+%Cc Cav 00091
+"You have been successful, I see, %p.
+
+"Now that the Amulet of Yendor is yours, here is what you must do:
+
+"Journey upwards to the open air.  The Amulet you carry will then
+take you into the Astral Planes, where the Great Temple of %d
+casts its influence throughout our world.
+
+"Sacrifice the Amulet on the altar.  Thus shall %d become supreme!"
+%E
+#
+#      Healer
+#
+%Cc Hea 00001
+What sorcery has brought you back to %H?  The smell
+of fresh funeral pyres tells you that something is amiss with the healing
+powers that used to practice here.
+
+No rhizotomists are tending the materia medica gardens, and where are the
+common folk who used to come for the cures?
+
+You know that you must quickly make your way to the collegium, and
+%ls iatreion, and find out what has happened in your
+absence.
+%E
+%Cp Hea 00002
+After your last experience you expected to be here, but you certainly
+did not expect to see things so much worse.  This time you must
+succeed.
+%E
+%Cp Hea 00003
+Again, you %x %H in the distance.
+
+The smell of death and disease permeates the air.  You do not have
+to be %Ra to know that %n is on the verge of victory.
+%E
+%Cp Hea 00005
+"Did you read that new treatise on the therapeutic use of leeches?"
+%E
+%Cp Hea 00006
+"Paint a red caduceus on your shield and monsters won't hit you."
+%E
+%Cp Hea 00007
+"I passed handwriting so they are demoting me a rank."
+%E
+%Cp Hea 00008
+"I've heard that even %l has not been able to cure Chiron."
+%E
+%Cp Hea 00009
+"We think %n has used his alchemists, and %o,
+to unleash a new disease we call 'the cold' on Gehennom."
+%E
+%Cp Hea 00010
+"Did you read that new treatise on the therapeutic use of leeches?"
+%E
+%Cp Hea 00011
+"Paint a red caduceus on your shield and monsters won't hit you."
+%E
+%Cp Hea 00012
+"How are you feeling?  Perhaps a good bleeding will improve your sprits."
+%E
+%Cp Hea 00013
+"Have you heard the absurd new theory that diseases are caused by
+microscopic organisms, and not ill humors?"
+%E
+%Cp Hea 00014
+"I see that you bring %o, now you can cure this plague!"
+%E
+%Cc Hea 00015
+Feebly, %l raises his head to look at you.
+
+"It is good to see you again, %p.  I see the concern in your
+eyes, but do not worry for me.  I am not ready for Hades yet.  We have
+exhausted much of our healing powers holding off %n.
+I need your fresh strength to carry on our work.
+
+"Come closer and let me lay hands on you, and determine if you have
+the skills necessary to accomplish this mission."
+%E
+%Cp Hea 00016
+"Again you return to me, %p.  I sense that each trip back
+the pleurisy and maladies of our land begin to infect you.  Let us
+hope and pray to %d that you become ready for your task before
+you fall victim to the bad humors."
+%E
+%Cp Hea 00017
+"Chiron has fallen, Hermes has fallen, what else must I tell you to
+impress upon you the importance of your mission!  I hope that you
+have come prepared this time."
+%E
+%Cc Hea 00018
+"You have failed us, %p.  You are a quack!  A charlatan!
+
+"Hades will be happy to hear that you are once again practicing your
+arts on the unsuspecting."
+%E
+%Cc Hea 00019
+"Alas, %p, you are yet too inexperienced to deal with the rigors
+of such a task.  You must be able to draw on the knowledge of botany,
+vetenary, and alchemy before I can send you on this quest with good
+conscience.
+
+"Return when you wear %Ra's caduceus."
+%E
+%Cc Hea 00020
+"You have learned much of the remedies that benefit, but you must also
+know which physic for which ail.  That is why %ds teachings are a
+part of your training.
+
+"Return to us when you have healed thyself."
+%E
+%Cc Hea 00021
+For the first time, you sense a smile on %ls face.
+
+    You have indeed learned as much as we can teach you in preparation
+    for this task.  Let me tell you what I know of the symptoms and hope
+    that you can provide a cure.
+
+    A short while ago, the dreaded %nt was fooled by the gods
+    into thinking that he could use %o to find a
+    cure for old age.  Think of it, eternal youth!  But his good
+    health is accomplished by drawing the health from those around him.
+
+    He has exhausted his own supply of healthy people and now he seeks to
+    extend his influence into our world.  You must recover from him
+    %o and break the spell.
+
+    You must travel into the swamps to %i, and from there
+    follow the trail to %ns island lair.  Be careful.
+%E
+%Cp Hea 00025
+"Remember, %p, to always wash your hands before operating."
+%E
+%Cp Hea 00026
+"%nC has no real magic of his own.  To this he is vulnerable."
+%E
+%Cp Hea 00027
+"If you have been true to %d, you can draw on the power of
+%o."
+%E
+%Cp Hea 00028
+"Bring with you antidotes for poisons."
+%E
+%Cp Hea 00029
+"Remember this, %n can twist the powers of %o
+to hurt instead of heal."
+%E
+%Cp Hea 00030
+"I have sent for Chiron, but I am afraid he will come too late."
+%E
+%Cp Hea 00031
+"Maybe when you return the snakes will once again begin to shed."
+%E
+%Cp Hea 00032
+"The plague grows worse as we speak.  Hurry, %p!"
+%E
+%Cp Hea 00033
+"Many times %n has caused trouble in these lands.  It is
+time that he was eradicated like the diseases he has caused."
+%E
+%Cp Hea 00034
+"With but one eye, %n should be easy to blind.  Remember this."
+%E
+%Cc Hea 00035
+You stand before the entrance to %i.  Strange
+scratching noises come from within the building.
+
+The swampy ground around you seems to stink with disease.
+%E
+%Cp Hea 00036
+Once again you stand at the entrance to %i.
+%E
+%Cc Hea 00040
+You stand within sight of the infamous Isle of %n.  Even
+the words of %l had not prepared you for this.
+
+Steeling yourself against the wails of the ill that pierce your ears,
+you hurry on your task.  Maybe with %o you can
+heal them on your return, but not now.
+%E
+%Cp Hea 00041
+Once again, you %x the Isle of %n in the distance.
+%E
+%Cc Hea 00050
+"They have made a mistake in sending you, %p.
+
+"When I add your youth to mine, it will just make it easier for me
+to defeat %l."
+%E
+%Cp Hea 00051
+"Unlike your patients, you seem to keep coming back, %p!"
+%E
+%Cp Hea 00052
+"Which would you like, %p?  Boils, pleurisy, convulsions?"
+%E
+%Cp Hea 00053
+"I'll have %o back from you, %r.  You are
+not going to live to escape this place."
+%E
+%Cp Hea 00060
+"They might as well give scalpels to wizards as to let you try to
+use %o!"
+%E
+%Cp Hea 00061
+"If I could strike %l, surrounded by his %gP, imagine what I
+can do to you here by yourself."
+%E
+%Cp Hea 00062
+"I will put my %Rp to work making a physic out of your ashes."
+%E
+%Cp Hea 00063
+"As we speak, Hades gathers your patients to join you."
+%E
+%Cp Hea 00064
+"After I'm done with you, I'll destroy %l as well."
+%E
+%Cp Hea 00065
+"You will have to kill me if you ever hope to leave this place."
+%E
+%Cp Hea 00066
+"I will impale your head on my caduceus for all to see."
+%E
+%Cp Hea 00067
+"There is no materia medica in your sack which will cure you of me!"
+%E
+%Cp Hea 00068
+"Do not fight too hard, I want your soul strong, not weakened!"
+%E
+%Cp Hea 00069
+"You should have stopped studying at vetenary."
+%E
+%Cc Hea 00070
+As you pick up %o, you feel its healing begin to
+warm your soul.  You curse Zeus for taking it from its rightful owner,
+but at least you hope that %l can put it to good use once
+again.
+%E
+%Cc Hea 00080
+The battered body of %n slumps to the ground and gasps
+out one last curse:
+
+    You have defeated me, %p, but I shall have my revenge.
+    How, I shall not say, but this curse shall be like a
+    cancer on you.
+
+With that %n dies.
+%E
+%Cc Hea 00081
+As soon as %l sees %o he summons his %gP.
+
+Gently, %l reaches out and touches %o.
+He instructs each of the assembled to do the same.  When everyone
+has finished he speaks to you.
+
+    Now that we have been replenished we can defeat this plague.  You must
+    take %o with you and replenish the worlds you have
+    been called upon to travel next.  I wish you could ride Chiron to the
+    end of your journey, but I need him to help me spread the cure.  Go
+    now and continue your journey.
+%E
+%Cc Hea 00082
+%l cautiously handles %o while watching you.
+
+"You are its keeper now, and the time has come to resume your search
+for the Amulet.  %Z await your return through the
+magic portal which brought you here."
+%E
+%Cp Hea 00090
+"You have again returned to us, %p.  We have done well in your
+absence, yes?  How fare you upon your quest for the Amulet?"
+%E
+%Cc Hea 00091
+"Ah, you have recovered the Amulet, %p.  Well done!
+
+"Now, you should know that you must travel through the elemental planes
+to the astral, and there return the Amulet to %d.  Go forth and
+may our prayers be as a wind upon your back."
+%E
+#
+#      Knight
+#
+%Cc Kni 00001
+You materialize in the shadows of %H.  Immediately, you notice
+that something is wrong.  The fields around the castle are trampled and
+withered, as if some great battle has been recently fought.
+
+Looking closer, you %x long gouges in the walls of %H.
+You know of only one creature that makes those kinds of marks...
+%E
+%Cp Kni 00002
+Once again you stand in the shadows of %H.
+%E
+%Cp Kni 00003
+Again, you stand before %H.  You vaguely sense that this
+may be the last time you stand before %l.
+%E
+%Cp Kni 00005
+"Hail, %p!  Verily, thou lookest well."
+%E
+%Cp Kni 00006
+"There is word, %p, that %n hath been sighted in the fens
+near %i."
+%E
+%Cp Kni 00007
+"Thou art our only hope now, %p."
+%E
+%Cp Kni 00008
+"Verily, %l could have no better champion, %p."
+%E
+%Cp Kni 00009
+"Many brave %cP died when %n attacked."
+%E
+%Cp Kni 00010
+"Hail, %p!  Verily, thou lookest well."
+%E
+%Cp Kni 00011
+"So, %p, didst thou find %n in the fens
+near %i?"
+%E
+%Cp Kni 00012
+"Worthy %p, hast thou proven thy right purpose on the body of %n?"
+%E
+%Cp Kni 00013
+"Verily, %l could have no better champion, %p."
+%E
+%Cp Kni 00014
+"Hast thou indeed recovered %o?"
+%E
+%Cc Kni 00015
+"Ah, %p.  We see thou hast received Our summons.
+We are in dire need of thy prowess.  But first, We must needs
+decide if thou art ready for this great undertaking."
+%E
+%Cp Kni 00016
+"Welcome again, %p.  We hope thou art ready now."
+%E
+%Cp Kni 00017
+"Once again, thou standest before Us, %p.  Art thou ready now?"
+%E
+%Cc Kni 00018
+"Thou disgracest this noble court with thine impure presence.  We have been
+lenient with thee, but no more.  Thy name shall be spoken no more.  We
+hereby strip thee of thy title, thy lands, and thy standing as %ca.
+Begone from Our sight!"
+%E
+%Cc Kni 00019
+"Verily, %p, thou hast done well.  That thou hast survived thus
+far is a credit to thy valor, but thou art yet unprepared for
+the demands required as Our Champion.  %rA, no matter how
+pure, could never hope to defeat the foul %n.
+
+"Journey forth from this place, and hone thy skills.  Return to
+Our presence when thou hast attained the noble title of %R."
+%E
+%Cc Kni 00020
+"Thou dishonourest Us, %p!  Thou hast strayed from the path of
+chivalry! Go from Our presence and do penance.  Only when thou art again
+pure mayst thou return hence."
+%E
+%Cc Kni 00021
+"Ah, %p.  Thou art truly ready, as no %c before thee hath
+been.  Hear now Our words:
+
+"As thou noticed as thou approached %H, a great battle hath
+been fought recently in these fields.  Know thou that Merlin himself
+came to aid Us here as We battled the foul %n.  In the midst of that
+battle, %n struck Merlin a great blow, felling him.  Then, as Our
+forces were pressed back, %n stole %o.
+
+"We eventually turned the tide, but lost many %cP in doing so.
+Merlin was taken off by his apprentice, but hath not recovered.  We have
+been told that so long as %n possesseth %o,
+Merlin will not regain his health.
+
+"We hereby charge thee with this most important of duties:
+
+"Go forth from this place, to the fens, and there thou wilt find
+%i.  From there, thou must track down %n.  Destroy the
+beast, and return to Us %o.  Only then can
+We restore Merlin to health."
+%E
+%Cp Kni 00025
+"Remember, %p, follow always the path of %d."
+%E
+%Cp Kni 00026
+"Though %n is verily a mighty foe, We have confidence in thy victory."
+%E
+%Cp Kni 00027
+"Beware, for %n hath surrounded himself with hordes of foul creatures."
+%E
+%Cp Kni 00028
+"Great treasure, 'tis said, is hoarded in the lair of %n."
+%E
+%Cp Kni 00029
+"If thou possessest %o, %p, %ns magic
+shall therewith be thwarted."
+%E
+%Cp Kni 00030
+"The gates of %i are guarded by forces unseen, %p.
+Go carefully."
+%E
+%Cp Kni 00031
+"Return %o to Us quickly, %p."
+%E
+%Cp Kni 00032
+"Destroy %n, %p, else %H shall surely fall."
+%E
+%Cp Kni 00033
+"Call upon %d when thou art in need."
+%E
+%Cp Kni 00034
+"To find %i, thou must keep thy heart pure."
+%E
+%Cc Kni 00035
+You stand at the foot of %i.  Atop, you can %x a shrine.
+Strange energies seem to be focused here, and the hair on the back
+of your neck stands on end.
+%E
+%Cp Kni 00036
+Again, you stand at the foot of %i.
+%E
+%Cc Kni 00040
+As you exit the swamps, you %x before you a huge, gaping hole in the
+side of a hill.  From within, you smell the foul stench of carrion.
+
+The pools on either side of the entrance are fouled with blood, and
+pieces of rusted metal and broken weapons show above the surface.
+%E
+%Cp Kni 00041
+Again, you stand at the entrance to %ns lair.
+%E
+%Cc Kni 00050
+"Hah!  Another puny %c seeks death.  I shall dine well tonight,
+then tomorrow, %H shall fall!"
+%E
+%Cp Kni 00051
+"Again, thou challengest me, %r?  So be it.  Thou wilt die here."
+%E
+%Cp Kni 00052
+"Thou art truly foolish, %r.  I shall dispatch thee anon."
+%E
+%Cp Kni 00053
+"So, thou darest touch MY property!  I shall have that bauble back,
+puny %r.  Thou wilt die in agony!"
+%E
+%Cp Kni 00060
+"A mere %r can never withstand me!"
+%E
+%Cp Kni 00061
+"I shall kill thee now, and feast!"
+%E
+%Cp Kni 00062
+"Puny %c.  What manner of death dost thou wish?"
+%E
+%Cp Kni 00063
+"First thee, %p, then I shall feast upon %l."
+%E
+%Cp Kni 00064
+"Hah!  Thou hast failed, %r.  Now thou shalt die."
+%E
+%Cp Kni 00065
+"Die, %c.  Thou art as nothing against my might."
+%E
+%Cp Kni 00066
+"I shall suck the marrow from thy bones, %c."
+%E
+%Cp Kni 00067
+"Let's see...  Broiled?  No.  Fried?  Nay.  Baked?  Yea verily,
+that is the way I like my %c for dinner."
+%E
+%Cp Kni 00068
+"Thy strength waneth, %p.  The time of thy death draweth near."
+%E
+%Cp Kni 00069
+"Call upon thy precious %d, %p.  It shall not avail thee."
+%E
+%Cc Kni 00070
+As you pick up %o, you feel its protective fields
+form around your body.  You also feel a faint stirring in your mind,
+as if you are in two places at once, and in the second, you are waking
+from a long sleep.
+%E
+%Cc Kni 00080
+As %n sinks to the ground, blood gushing from his open mouth, he
+defiantly curses you and %l:
+
+    Thou hast not won yet, %r.  By the gods, I shall return and dog
+    thy steps to the grave!
+
+His tail flailing madly, %n tries to crawl towards you, but slumps
+to the ground and dies in a pool of his own blood.
+%E
+%Cc Kni 00081
+As you approach %l, he beams at you and says:
+
+    Well done!  Thou art truly the Champion of %H.  We
+    have received word that Merlin is recovering, and shall soon
+    rejoin Us.
+
+    He hath instructed Us that thou art now to be the guardian of
+    %o.  He feeleth that thou mayst have need of
+    its powers in thine adventures.  It is Our wish that thou keepest
+    %o with thee as thou searchest for the fabled
+    Amulet of Yendor.
+%E
+# assumes Magic Mirror of Merlin (glass object)
+%Cc Kni 00082
+"Careful, %p!  %oC might break, and that would
+be a tragic loss.  Thou art its keeper now, and the time hath come
+to resume thy search for the Amulet.  %Z await thy
+return through the magic portal that brought thee here."
+%E
+%Cp Kni 00090
+"Well met, %p.  How goeth thy search for the Amulet of Yendor?"
+%E
+%Cc Kni 00091
+"Thou hast succeeded, We see, %p!  Now thou art commanded to take
+the Amulet to be sacrificed to %d in the plane of the astral.
+
+"Merlin hath counseled Us that thou must travel always upwards through
+the planes of the elements, to achieve this goal.
+
+"Go with %d, %p."
+%E
+#
+#       Monk
+#
+# The quest artifact is "The Eyes of the Overworld", hence needs
+# to be treated as plural by messages which use %o.
+#
+%Cc Mon 00001
+You find yourself standing in sight of %H.  Something
+is obviously wrong here. Strange shapes lumber around
+outside %H!
+
+You realize that the %l needs your assistance!
+%E
+%Cp Mon 00002
+Once again, you stand before %H.
+%E
+%Cp Mon 00003
+Again you face %H.  Your intuition hints that this may be
+the final time you come here.
+%E
+%Cp Mon 00005
+"Greetings, honorable %r.  It is good to see you."
+%E
+%Cp Mon 00006
+"Ah, %p!  Surely you can help us in our hour of need."
+%E
+%Cp Mon 00007
+"Greetings, %s.  %lC has great need of your help."
+%E
+%Cp Mon 00008
+"Alas, it seems as if even %d has deserted us."
+%E
+%Cp Mon 00009
+"May %d be with you, %s."
+%E
+%Cp Mon 00010
+"Greetings, honorable %r.  It is good to see you again."
+%E
+%Cp Mon 00011
+"Ah, %p!  Our deepest gratitude for all of your help."
+%E
+%Cp Mon 00012
+"Greetings, %s.  Perhaps you will take some time to meditate with us?"
+%E
+%Cp Mon 00013
+"With this test behind you, may %d bring you enlightenment."
+%E
+%Cp Mon 00014
+"May %d be with you, %s."
+%E
+%Cc Mon 00015
+"Ah, %p, my %S.  You have returned to us at last.
+A great blow has befallen our order; perhaps you can help us.
+First, however, I must determine if you are prepared for this
+great challenge."
+%E
+%Cp Mon 00016
+"Again, my %S, you stand before me.  Are you ready now to help us?"
+%E
+%Cp Mon 00017
+"Once more, %p, you stand within the sanctum.  Are you ready now?"
+%E
+%Cc Mon 00018
+"You are a heretic, %p!  How can you, %ra, deviate so from the
+teachings of %d?  Begone from this temple.  You are no longer
+%sa to this order.  We will pray to %d for other assistance,
+as you have failed us utterly."
+%E
+%Cc Mon 00019
+"Alas, %p, it is not yet to be.  A mere %r could never
+withstand the might of %n.  Go forth, again into the world, and return
+when you have attained the post of %R."
+%E
+%Cc Mon 00020
+"This is terrible, %p.  You have deviated from the true path!
+You know that %d requires the most strident devotion of this
+order.  The %shood must stand for utmost piety.
+
+"Go from here, atone for your sins against %d.  Return only when
+you have purified yourself."
+%E
+%Cc Mon 00021
+"Yes, %p.  You are truly ready now.  Attend to me and I shall
+tell you of what has transpired:
+
+"During one of the Great Meditations a short time ago, %n and
+a legion of elementals invaded %H.  Many %gP were
+killed, including the one bearing %o.
+
+Now, there are barely enough %gP left to keep the
+elementals at bay.
+
+"We need you to find %i, then, from there, travel
+to %ns lair.  If you can manage to defeat %n
+and return %o here, we can then drive off the
+legions of elementals that slay our students.
+
+"Go with %d as your guide, %p."
+%E
+%Cp Mon 00025
+"You can prevail, if you rely on %d."
+%E
+%Cp Mon 00026
+"Remember that %n has great magic at his command."
+%E
+%Cp Mon 00027
+"Be pure, my %S."
+%E
+%Cp Mon 00028
+"Beware, %i is surrounded by hordes of earth elementals."
+%E
+%Cp Mon 00029
+"Remember your studies, and you will prevail!"
+%E
+%Cp Mon 00030
+"Acquire and wear %o if you can.  They will aid you
+against %n."
+%E
+%Cp Mon 00031
+"Call upon %d when your need is greatest.  You will be answered."
+%E
+%Cp Mon 00032
+"Remember to use the elementals' strength against them!"
+%E
+%Cp Mon 00033
+"Do not lose faith, %p.  If you do so, %n will grow stronger."
+%E
+%Cp Mon 00034
+"Wear %o.  They will assist you in your efforts."
+%E
+%Cc Mon 00035
+You remember the descriptions of %i, given to you
+by the %l.  It is ahead that you will find %n's trail.
+%E
+%Cp Mon 00036
+Again, you stand before %i.
+%E
+%Cc Mon 00040
+The stench of brimstone is all about you, and the elementals close in
+from all sides!
+
+Ahead, there is a small clearing amidst the bubbling pits of lava...
+%E
+%Cp Mon 00041
+Again, you have invaded %ns domain.
+%E
+%Cc Mon 00050
+"Ah, so %l has sent another %g to retrieve
+%o.
+
+"No, I see you are no %g.  Perhaps I shall have some fun today
+after all.  Prepare to die, %r!  You shall never regain
+%o."
+%E
+%Cp Mon 00051
+"So, %r.  Again you challenge me."
+%E
+%Cp Mon 00052
+"Die now, %r.  %d has no power here to aid you."
+%E
+%Cp Mon 00053
+"You shall die, %r, and I will have %o back."
+%E
+%Cp Mon 00060
+"Submit to my will, %c, and I shall spare you."
+%E
+%Cp Mon 00061
+"Your puny powers are no match for me, %c."
+%E
+%Cp Mon 00062
+"I shall have you turned into a zombie for my pleasure!"
+%E
+%Cp Mon 00063
+"Despair now, %r.  %d cannot help you."
+%E
+%Cp Mon 00064
+"I shall feast upon your soul for many days, %c."
+%E
+%Cp Mon 00065
+"Your death will be slow and painful.  That I promise!"
+%E
+%Cp Mon 00066
+"You cannot defeat %n, you fool.  I shall kill you now."
+%E
+%Cp Mon 00067
+"Your precious %lt will be my next victim."
+%E
+%Cp Mon 00068
+"I feel your powers failing you, %r.  You shall die now."
+%E
+%Cp Mon 00069
+"With %o, nothing can stand in my way."
+%E
+%Cc Mon 00070
+As you pick up %o, you feel the essence of
+%d fill your soul.  You know now why %n stole them from
+%H, for with them, %ca of %d could
+easily defeat his plans.
+
+You sense a message from %d.  Though not verbal, you
+get the impression that you must return to %l as soon
+as possible.
+%E
+%Cc Mon 00080
+%nC gasps:
+
+    "You have only defeated this mortal body.  Know this: my spirit
+    is strong.  I shall return and reclaim what is mine!"
+
+With that, %n expires.
+%E
+%Cc Mon 00081
+"You have returned, %p.  And with %o, I see.
+Congratulations.
+
+"I have been in meditation, and have received direction from
+a minion of %d.  %d commands that you retain
+%o.  With them, you must recover the Amulet
+of Yendor.
+
+"Go forth, and let %d guide your steps."
+%E
+%Cc Mon 00082
+%lC studies %o for a moment,
+then returns his gaze to you.
+
+"%oC must remain with you.  Use them
+as you resume your search for the Amulet.
+%Z await your return through the magic portal
+that brought you here."
+%E
+%Cp Mon 00090
+"Welcome back, %p.  How is your quest for the Amulet going?"
+%E
+%Cc Mon 00091
+"You have prevailed, %p!  %d is surely with you.  Now,
+you must take the amulet, and sacrifice it on %ds altar on
+the Astral plane.  I suspect that I shall never see you again in this
+life, but I hope to at %ds feet."
+%E
+#
+#      Priest
+#
+%Cc Pri 00001
+You find yourself standing in sight of %H.  Something
+is obviously wrong here.  The doors to %H, which usually
+stand open, are closed.  Strange human shapes shamble around
+outside.
+
+You realize that %l needs your assistance!
+%E
+%Cp Pri 00002
+Once again, you stand before %H.
+%E
+%Cp Pri 00003
+Again you face %H.  Your intuition hints that this may be
+the final time you come here.
+%E
+%Cp Pri 00005
+"Greetings, honored %r.  It is good to see you."
+%E
+%Cp Pri 00006
+"Ah, %p!  Surely you can help us in our hour of need."
+%E
+%Cp Pri 00007
+"Greetings, %s.  %lC has great need of your help."
+%E
+%Cp Pri 00008
+"Alas, it seems as if even %d has deserted us."
+%E
+%Cp Pri 00009
+"May %d be with you, %s."
+%E
+%Cp Pri 00010
+"Greetings, %r.  It is good to see you again."
+%E
+%Cp Pri 00011
+"Ah, %p!  Our deepest gratitude for all of your help."
+%E
+%Cp Pri 00012
+"Welcome back, %s!  With %o, no undead can stand against us."
+%E
+%Cp Pri 00013
+"Praise be to %d, for delivering us from %n."
+%E
+%Cp Pri 00014
+"May %d be with you, %s."
+%E
+%Cc Pri 00015
+"Ah, %p, my %S.  You have returned to us at last.
+A great blow has befallen our order; perhaps you can help us.
+First, however, I must determine if you are prepared for this
+great challenge."
+%E
+%Cp Pri 00016
+"Again, my %S, you stand before me.  Are you ready now to help us?"
+%E
+%Cp Pri 00017
+"Once more, %p, you stand within the sanctum.  Are you ready now?"
+%E
+%Cc Pri 00018
+"You are a heretic, %p!  How can you, %ra, deviate so from the
+teachings of %d?  Begone from this temple.  You are no longer
+%sa to this order.  We will pray to %d for other assistance,
+as you have failed us utterly."
+%E
+%Cc Pri 00019
+"Alas, %p, it is not yet to be.  A mere %r could never
+withstand the might of %n.  Go forth, again into the world, and return
+when you have attained the post of %R."
+%E
+%Cc Pri 00020
+"This is terrible, %p.  You have deviated from the true path!
+You know that %d requires the most strident devotion of this
+order.  The %shood must stand for utmost piety.
+
+"Go from here, atone for your sins against %d.  Return only when
+you have purified yourself."
+%E
+%Cc Pri 00021
+"Yes, %p.  You are truly ready now.  Attend to me and I shall
+tell you of what has transpired:
+
+"At one of the Great Festivals a short time ago, %n and a legion
+of undead invaded %H.  Many %gP were killed, including
+the one carrying %o.
+
+"As a final act of vengefulness, %n desecrated the altar here.
+Without it, we could not mount a counter-attack.  Now, there are
+barely enough %gP left to keep the undead at bay.
+
+"We need you to find %i, then, from there, travel
+to %ns lair.  If you can manage to defeat %n and return
+%o here, we can then drive off the legions of
+undead that befoul the land.
+
+"Go with %d as your guide, %p."
+%E
+%Cp Pri 00025
+"You can prevail, if you rely on %d."
+%E
+%Cp Pri 00026
+"Remember that %n has great magic at his command."
+%E
+%Cp Pri 00027
+"Be pure, my %S."
+%E
+%Cp Pri 00028
+"Beware, %i is surrounded by a great graveyard."
+%E
+%Cp Pri 00029
+"You may be able to affect %n with magical cold."
+%E
+%Cp Pri 00030
+"Acquire and wear %o if you can.  It will aid you
+against %n."
+%E
+%Cp Pri 00031
+"Call upon %d when your need is greatest.  You will be answered."
+%E
+%Cp Pri 00032
+"The undead legions are weakest during the daylight hours."
+%E
+%Cp Pri 00033
+"Do not lose faith, %p.  If you do so, %n will grow stronger."
+%E
+%Cp Pri 00034
+"Wear %o.  It will assist you against the undead."
+%E
+%Cc Pri 00035
+You stand facing a large graveyard.  The sky above is filled with clouds
+that seem to get thicker closer to the center.  You sense the presence of
+undead in larger numbers than you have ever encountered before.
+
+You remember the descriptions of %i, given to you by
+%lC.  It is ahead that you will find %ns trail.
+%E
+%Cp Pri 00036
+Again, you stand before %i.
+%E
+%Cc Pri 00040
+The stench of brimstone is all about you, and the shrieks and moans
+of tortured souls assault your psyche.
+
+Ahead, there is a small clearing amidst the bubbling pits of lava...
+%E
+%Cp Pri 00041
+Again, you have invaded %ns domain.
+%E
+%Cc Pri 00050
+"Ah, so %lC has sent another %g to retrieve
+%o.
+
+"No, I see you are no %g.  Perhaps I shall have some fun today
+after all.  Prepare to die, %r!  You shall never regain
+%o."
+%E
+%Cp Pri 00051
+"So, %r.  Again you challenge me."
+%E
+%Cp Pri 00052
+"Die now, %r.  %d has no power here to aid you."
+%E
+%Cp Pri 00053
+"You shall die, %r, and I will have %o back."
+%E
+%Cp Pri 00060
+"Submit to my will, %c, and I shall spare you."
+%E
+%Cp Pri 00061
+"Your puny powers are no match for me, %c."
+%E
+%Cp Pri 00062
+"I shall have you turned into a zombie for my pleasure!"
+%E
+%Cp Pri 00063
+"Despair now, %r.  %d cannot help you."
+%E
+%Cp Pri 00064
+"I shall feast upon your soul for many days, %c."
+%E
+%Cp Pri 00065
+"Your death will be slow and painful.  That I promise!"
+%E
+%Cp Pri 00066
+"You cannot defeat %n, you fool.  I shall kill you now."
+%E
+%Cp Pri 00067
+"Your precious %lt will be my next victim."
+%E
+%Cp Pri 00068
+"I feel your powers failing you, %r.  You shall die now."
+%E
+%Cp Pri 00069
+"With %o, nothing can stand in my way."
+%E
+%Cc Pri 00070
+As you pick up %o, you feel the essence of
+%d fill your soul.  You know now why %n stole it from
+%H, for with it, %ca of %d could
+easily defeat his plans.
+
+You sense a message from %d.  Though not verbal, you
+get the impression that you must return to %lC as soon
+as possible.
+%E
+%Cc Pri 00080
+You feel a wrenching shift in the ether as %ns body dissolves
+into a cloud of noxious gas.
+
+Suddenly, a voice booms out:
+
+    Thou hast defeated the least of my minions, %r.
+    Know now that Moloch is aware of thy presence.
+    As for thee, %n, I shall deal with thy failure
+    at my leisure.
+
+You then hear the voice of %n, screaming in terror...
+%E
+%Cc Pri 00081
+"You have returned, %p.  And with %o, I see.
+Congratulations.
+
+"I have been in meditation, and have received direction from
+a minion of %d.  %d commands that you retain
+%o.  With it, you must recover the Amulet
+of Yendor.
+
+"Go forth, and let %d guide your steps."
+%E
+%Cc Pri 00082
+%l reiterates that %o is yours now.
+
+"The time has come to resume your search for the Amulet.
+%Z await your return through the magic portal
+that brought you here."
+%E
+%Cp Pri 00090
+"Welcome back, %p.  How is your quest for the Amulet going?"
+%E
+%Cc Pri 00091
+"You have prevailed, %p!  %d is surely with you.  Now,
+you must take the amulet, and sacrifice it on %ds altar on
+the Astral plane.  I suspect that I shall never see you again in this
+life, but I hope to at %ds feet."
+%E
+#
+#      Ranger
+#
+%Cc Ran 00001
+You arrive in familiar surroundings.  In the distance, you %x the
+ancient forest grove, the place of worship to %d.
+
+Something is wrong, though.  Surrounding the grove are centaurs!
+And they've noticed you!
+%E
+%Cp Ran 00002
+Once again, you stand before %H.
+%E
+%Cp Ran 00003
+You have the oddest feeling that this may be the last time you
+are to enter %H.
+%E
+%Cp Ran 00005
+"%pC!  I have not seen you in many moons.  How do you fare?"
+%E
+%Cp Ran 00006
+"%nC continues to threaten the grove.  But we hold fast."
+%E
+%Cp Ran 00007
+"%lC is growing weak.  The magic required to defend the grove drains us."
+%E
+%Cp Ran 00008
+"Remember %i is hard to enter.  Beware the
+distraction of leatherwings."
+%E
+%Cp Ran 00009
+"We must regain %o.  Without it we will be overrun."
+%E
+%Cp Ran 00010
+"%pC!  I have not seen you in many moons.  How do you fare?"
+%E
+%Cp Ran 00011
+"Birdsong has returned to the grove, surely this means you have defeated %n."
+%E
+%Cp Ran 00012
+"%lC seems to have regained some of his strength."
+%E
+%Cp Ran 00013
+"So, tell us how you entered %i, in case some new evil arises there."
+%E
+%Cp Ran 00014
+"Is that truely %o that I see you carrying?"
+%E
+%Cc Ran 00015
+"%pC!  You have returned!  Thank %d.
+
+"We have great need of you.  But first, I must see if you have the
+required abilities to take on this responsibility."
+%E
+%Cp Ran 00016
+"Once again, %p, you stand in our midst.  Are you ready now?"
+%E
+%Cp Ran 00017
+"Ah, you are here again, %p.  Allow me to determine your readiness..."
+%E
+%Cc Ran 00018
+"%pC!  You have doomed us all.  You fairly radiate %L influences
+and weaken the power we have raised in this grove as a result!
+
+"Begone!  We renounce your %shood with us!  You are an outcast now!"
+%E
+%Cc Ran 00019
+"%p, you are yet too inexperienced to withstand the demands of that
+which we need you to do.  %RA might just be able to do this thing.
+
+"Return to us when you have learned more, my %S."
+%E
+%Cc Ran 00020
+"You have strayed, %p!  You know that %d requires that
+we maintain a pure devotion to things %a!
+
+"You must go from us.  Return when you have purified yourself."
+%E
+%Cc Ran 00021
+"You are indeed ready, %p.  I shall tell you what has transpired,
+and why we so desperately need your help:
+
+"A short time ago, the mountain centaurs to the east invaded
+and enslaved the plains centaurs in this area.  The local
+leader is now only a figurehead, and serves %n.
+
+"During our last gathering of worship here, we were beset by hordes of
+hostile centaurs, as you witnessed.  In the first onslaught a group,
+headed by %n himself, managed to breach the grove and
+steal %o.
+
+"Since then, we have been besieged.  We do not know how much longer
+we will be able to maintain our magical barriers.
+
+"If we are to survive, you, %p, must infiltrate
+%i.  There, you will find a pathway down, to the
+underground cavern of %n.  He has always coveted
+%o, and will surely keep it.
+
+"Recover %o for us, %p!  Only then will %d be safe."
+%E
+%Cp Ran 00025
+"It is rumored that the Forest and Mountain Centaurs have resolved
+their ancient feud and now band together against us."
+%E
+%Cp Ran 00026
+"%nC is strong, and very smart."
+%E
+%Cp Ran 00027
+"Use %o, when you find it.  It will help you survive
+to reach us."
+%E
+%Cp Ran 00028
+"Remember, let %d be your guide."
+%E
+%Cp Ran 00029
+"Call upon %d when you face %n.
+The very act of doing so will infuriate him, and give you advantage."
+%E
+%Cp Ran 00030
+"%n and his kind have always hated us."
+%E
+%Cp Ran 00031
+"We cannot hold the grove much longer, %p.  Hurry!"
+%E
+%Cp Ran 00032
+"To infiltrate %i, you must be very stealthy."
+%E
+%Cp Ran 00033
+"Remember that %n is a braggart.  Trust not what he says."
+%E
+%Cp Ran 00034
+"You can triumph, %p, if you trust in %d."
+%E
+%Cc Ran 00035
+This must be %i.
+
+You are in a cave built of many different rooms, all interconnected
+by tunnels.  Your quest is to find and shoot the evil wumpus that
+resides elsewhere in the cave without running into any bottomless
+pits or using up your limited supply of arrows.  Good luck.
+
+You are in room 9 of the cave.  There are tunnels to rooms
+5, 8, and 10.
+*rustle* *rustle* (must be bats nearby)
+*sniff* (I can smell the evil wumpus nearby!)
+%E
+%Cc Ran 00036
+Once again, you descend into %i.
+
+*whoosh* (I feel a draft from some pits).
+*rustle* *rustle* (must be bats nearby)
+%E
+%Cc Ran 00040
+You descend into a weird place, in which roughly cut cave-like walls
+join with smooth, finished ones, as if someone was in the midst of
+finishing off the construction of a subterranean complex.
+
+Off in the distance, you hear a sound like the clattering of many
+hooves on rock.
+%E
+%Cp Ran 00041
+Once again, you enter the distorted castle of %n.
+%E
+%Cc Ran 00050
+"So, %c.  %lC has sent you to recover %o.
+
+"Well, I shall keep that bauble.  It pleases me.  You, %c, shall die."
+%E
+%Cp Ran 00051
+"Back again, eh?  Well, a mere %r is no threat to me!  Die, %c!"
+%E
+%Cp Ran 00052
+"You haven't learned your lesson, %c.  You can't kill me!  You shall die now."
+%E
+%Cp Ran 00053
+"I shall have %o from you, %r.  Then I shall
+kill you."
+%E
+%Cp Ran 00060
+"Your %d is nothing, %c.  You are mine now!"
+%E
+%Cp Ran 00061
+"Run away little %c!  You can never hope to defeat %n!"
+%E
+%Cp Ran 00062
+"My servants will rip you to shreds!"
+%E
+%Cp Ran 00063
+"I shall display your head as a trophy.  What do you think about that wall?"
+%E
+%Cp Ran 00064
+"I shall break your %ls grove, and destroy all the %gP!"
+%E
+%Cp Ran 00065
+"%d has abandoned you, %c.  You are doomed."
+%E
+%Cp Ran 00066
+"%rA?  %lC sends a mere %r against me?  Hah!"
+%E
+%Cp Ran 00067
+"%lC has failed, %c.  %oC will never leave here."
+%E
+%Cp Ran 00068
+"You really think you can defeat me, eh %c?  You are wrong!"
+%E
+%Cp Ran 00069
+"You weaken, %c.  I shall kill you now."
+%E
+%Cc Ran 00070
+As you pick up %o, it seems to glow, and a warmth
+fills you completely.  You realize that its power is what has protected
+your %sp against their enemies for so long.
+
+You must now return it to %l without delay -- their lives depend
+on your speed.
+%E
+%Cc Ran 00080
+%nC collapses to the ground, cursing you and %l, then says:
+
+    You have defeated me, %r!  But I curse you one final time, with my
+    dying breath!  You shall die before you leave my castle!
+%E
+%Cc Ran 00081
+"%pC!  You have succeeded!  I feared it was not possible!
+
+"You have returned with %o!
+
+"I fear, now, that the Centaurs will regroup and plot yet another raid.
+This will take some time, but if you can recover the Amulet of Yendor
+for %d before that happens, we will be eternally safe.
+
+"Take %o with you.  It will aid in your quest for
+the Amulet."
+%E
+# assumes The Longbow of Diana
+%Cc Ran 00082
+%l flexs %o reverently.
+
+"With this wondrous bow, one need never run out of arrows.
+You are its keeper now, and the time has come to resume your
+search for the Amulet.  %Z await your return
+through the magic portal that brought you here."
+%E
+%Cp Ran 00090
+"Welcome, %p.  How have you fared on your quest for the Amulet
+of Yendor?"
+%E
+%Cc Ran 00091
+"You have it!  You have recovered the Amulet of Yendor!
+Now attend to me, %p, and I will tell you what must be done:
+
+"The Amulet has within it magic, the capability to transport you to
+the Astral Plane, where the primary circle of %d resides.
+
+"To activate this magic, you must travel upwards as far as you can.
+When you reach the temple, sacrifice the Amulet to %d.
+
+"Thus will you fulfill your destiny."
+%E
+#
+#      Rogue (with apologies to all Norsk speakers -dean)
+#
+%Cc Rog 00001
+Unexpectedly, you find yourself back in Ransmannsby, where you trained to
+be a thief.  Quickly you make the guild sign, hoping that you AND word
+of your arrival reach %ls den.
+%E
+%Cp Rog 00002
+Once again, you find yourself back in Ransmannsby.  Fond memories are
+replaced by fear, knowing that %l is waiting for you.
+%E
+%Cp Rog 00003
+You rub your hands through your hair, hoping that the little ones on
+the back of your neck stay down, and prepare yourself for your meeting
+with %l.
+%E
+%Cp Rog 00005
+"I hear that Lady Tyvefelle's household is lightly guarded."
+%E
+%Cp Rog 00006
+"You're back?  Even the Twain don't come back anymore."
+%E
+%Cp Rog 00007
+"Can you spare an old cutpurse a zorkmid for some grog?"
+%E
+%Cp Rog 00008
+"Fritz tried to join the other side, and now he's hell-hound chow."
+%E
+%Cp Rog 00009
+"Be careful what you steal, I hear the boss has perfected turning
+rocks into worthless pieces of glass."
+%E
+%Cp Rog 00010
+"I was sure wrong about Lady Tyvefelle's house; I barely got away with my
+life and lost my lock pick in the process."
+%E
+%Cp Rog 00011
+"You're back?  Even the Twain don't come back anymore."
+%E
+%Cp Rog 00012
+"Can you spare an old cutpurse a zorkmid for some grog?"
+%E
+%Cp Rog 00013
+"Fritz tried to join the other side, and now he's hell-hound chow."
+%E
+%Cp Rog 00014
+"Be careful what you steal, I hear the boss has perfected turning
+rocks into worthless pieces of glass."
+%E
+%Cc Rog 00015
+"Well, look who it is boys -- %p has come home.  You seem to have
+fallen behind in your dues.  I should kill you as an example to these
+other worthless cutpurses, but I have a better plan.  If you are ready
+maybe you could work off your back dues by performing a little job for
+me.  Let us just see if you are ready..."
+%E
+%Cp Rog 00016
+"Well, I didn't expect to see you back.  It shows that you are either stupid,
+or you are finally ready to accept my offer.  Let us hope for your sake it
+isn't stupidity that brings you back."
+%E
+%Cp Rog 00017
+"Did you perhaps mistake me for some other %lt?  You must
+think me as stupid as your behavior.  I warn you not to try my patience."
+%E
+%Cc Rog 00018
+"Well %gp, it looks like our friend has forgotten who is the boss
+around here.  Our friend seems to think that %rp have been put in
+charge.  Wrong.  DEAD WRONG!"
+
+Your sudden shift in surroundings prevents you from hearing the end
+of %ls curse.
+%E
+%Cc Rog 00019
+"In the time that you've been gone you've only been able to master the
+arts of %ra?  I've trained ten times again as many %Rp
+in that time.  Maybe I should send one of them, no?  Where would that
+leave you, %p?  Oh yeah, I remember, I was going to kill you!"
+%E
+%Cc Rog 00020
+"Maybe I should chain you to my perch here for a while.  Perhaps watching
+real %a men at work will bring some sense back to you.  I don't
+think I could stand the sight of you for that long though.  Come back
+when you can be trusted to act properly."
+%E
+%Cc Rog 00021
+"Will everyone not going to retrieve %o from that
+jerk, %n, take one step backwards.  Good choice,
+%p, because I was going to send you anyway.  My other %gp
+are too valuable to me.
+
+"Here's the deal.  I want %o, %n
+has %o.  You are going to get %o
+and bring it back to me.  So simple an assignment even you can understand
+it."
+%E
+%Cp Rog 00025
+"You don't seem to understand,
+%o isn't here so neither should you be!"
+%E
+%Cp Rog 00026
+"May %d curse you with lead fingers.  Get going!"
+%E
+%Cp Rog 00027
+"We don't have all year.  GET GOING!"
+%E
+%Cp Rog 00028
+"How would you like a scar necklace?  I'm just the jeweler to do it!"
+%E
+%Cp Rog 00029
+"Lazy S.O.B.  Maybe I should call up someone else..."
+%E
+%Cp Rog 00030
+"Maybe I should open your skull and see if my instructions are inside?"
+%E
+%Cp Rog 00031
+"This is not a task you can complete in the afterlife, you know."
+%E
+%Cp Rog 00032
+"Inside every living person is a dead person trying to get out,
+and I have your key!"
+%E
+%Cp Rog 00033
+"We're almost out of hell-hound chow, so why don't you just get moving!"
+%E
+%Cp Rog 00034
+"You know, %o isn't going to come when you
+whistle.  You must get it yourself."
+%E
+%Cc Rog 00035
+Those damn little hairs tell you that you are nearer to
+%o.
+%E
+%Cp Rog 00036
+Not wanting to face %l without having stolen
+%o, you continue.
+%E
+%Cc Rog 00040
+You feel a great swelling up of courage, sensing the presence of
+%o.  Or is it fear?
+%E
+%Cp Rog 00041
+The hairs on the back of your neck whisper -- it's fear.
+%E
+%Cc Rog 00050
+"Ah!  You must be %ls ... er, `hero'.  A pleasure
+to meet you."
+%E
+%Cp Rog 00051
+"We meet again.  Please reconsider your actions."
+%E
+%Cp Rog 00052
+"Surely, %p, you have learned that you cannot trust any bargains
+that %l has made.  I can show you how to continue on
+your quest without having to run into him again."
+%E
+%Cp Rog 00053
+"Please, think for a moment about what you are doing.  Do you truly
+believe that %d would want %l to have
+%o?"
+%E
+%Cp Rog 00060
+"May I suggest a compromise.  Are you interested in gold or gems?"
+%E
+%Cp Rog 00061
+"Please don't force me to kill you."
+%E
+%Cp Rog 00062
+"Grim times are upon us all.  Will you not see reason?"
+%E
+%Cp Rog 00063
+"I knew %l, and you're no %lt, thankfully."
+%E
+%Cp Rog 00064
+"It is a shame that we are not meeting under more pleasant circumstances."
+%E
+%Cp Rog 00065
+"I was once like you are now, %p.  Believe in me -- our way
+is better."
+%E
+%Cp Rog 00066
+"Stay with me, and I will make you %os guardian."
+%E
+%Cp Rog 00067
+"When you return, with or without %o,
+%l will have you killed."
+%E
+%Cp Rog 00068
+"Do not be fooled; I am prepared to kill to defend %o."
+%E
+%Cp Rog 00069
+"I can reunite you with the Twain.  Oh, the stories you can swap."
+%E
+%Cc Rog 00070
+As you pick up %o, the hairs on the back of your
+neck fall out.  At once you realize why %n was
+willing to die to keep it out of %ls hands.  Somehow
+you know that you must do likewise.
+%E
+%Cc Rog 00080
+"I know what you are thinking, %p.  It is not too late for you
+to use %o wisely.  For the sake of your guild
+%sp, do what is right."
+
+You sit and wait for death to come for %n, and then you
+brace yourself for your next meeting with %l!
+%E
+%Cc Rog 00081
+"Well, I'll be damned.  You got it.  I am proud of you, a fine %r
+you've turned out to be.
+
+"While you were gone I got to thinking, you and %o
+together could bring me more treasure than either of you apart, so why don't
+you take it with you.  All I ask is a cut of whatever loot you come by.
+That is a better deal than I offered %n.
+
+"But, you see what happened to %n when he refused.
+Don't make me find another to send after you this time."
+%E
+# assumes Master Key of Thievery (small object)
+%Cc Rog 00082
+%l seems tempted to swap %o for
+the mundane one you detect in his pocket, but noticing your alertness,
+evidently chickens out.
+
+"Go filch the Amulet before someone else beats you to it.
+%Z are back the way you came, through the magic portal."
+%E
+%Cc Rog 00090
+"Quite the little thief, aren't we, %p.  Can I interest you in a
+swap for %o.  Look around, anything in the keep
+is yours for the asking."
+%E
+%Cc Rog 00091
+"I see that with your abilities, and my brains, we could rule this world.
+
+"All that we would need to be all-powerful is for you to take that little
+trinket you've got there up to the Astral plane.  From there, %d will
+show you what to do with it.  Once that's done, we will be invincible!"
+%E
+#
+#      Samurai
+#
+%Cc Sam 00001
+Even before your senses adjust, you recognize the kami of
+%H.
+
+You %x the standard of your teki, %n, flying above
+the town.  How could such a thing have happened?  Why are ninja
+wandering freely; where are the samurai of your daimyo, %l?
+
+You quickly say a prayer to Izanagi and Izanami and walk towards
+town.
+%E
+%Cp Sam 00002
+Once again, you are back at %H.
+%E
+%Cp Sam 00003
+You are back at %H.
+
+Instantly you sense a subtle change in your karma.  You seem to know that
+if you do not succeed in your quest, %n will have destroyed
+the kami of %H before you return again.
+%E
+%Cp Sam 00005
+"To succeed, you must walk like a butterfly on the wind."
+%E
+%Cp Sam 00006
+"Ikaga desu ka?"
+%E
+%Cp Sam 00007
+"I fear for The Land of The Gods."
+%E
+%Cp Sam 00008
+"%nC has hired the Ninja -- be careful."
+%E
+%Cp Sam 00009
+"If %o is not returned, we will all be ninja."
+%E
+%Cp Sam 00010
+"Come, join us in celebrating with some sake."
+%E
+%Cp Sam 00011
+"Ikaga desu ka?"
+%E
+%Cp Sam 00012
+"You have brought our clan and %l much honor."
+%E
+%Cp Sam 00013
+"Please %r, sit for a while and tell us how you overcame the Ninja."
+%E
+%Cp Sam 00014
+"%lC still lives!  You have saved us from becoming ronin."
+%E
+%Cc Sam 00015
+"Ah, %p-san, it is good to see you again.  I need someone who can
+lead my samurai against %n.  If you are ready, you will be
+that person."
+%E
+%Cp Sam 00016
+"Once again, %p-san, you kneel before me.  Are you yet capable of
+being my vassal?"
+%E
+%Cp Sam 00017
+"You begin to test my matsu, %p-san.
+If you cannot determine what I want in a samurai, how can I rely on you
+to figure out what I need from a samurai?"
+%E
+%Cc Sam 00018
+"You are no longer my samurai, %p.
+
+"Hara-kiri is denied.  You are ordered to shave your head and then to
+become a monk.  Your fief and family are forfeit.  Wakarimasu?"
+%E
+%Cc Sam 00019
+"%p-san, you have learned well and honored your family.
+I require the skills of %Ra in order to defeat %n.
+Go and seek out teachers.  Learn what they have learned.  When you
+are ready, return to me."
+%E
+%Cc Sam 00020
+"%p-san, you would do better to join the kyokaku.
+
+"You have skills, but until you can call upon the bushido to know when and
+how to use them you are not samurai.  When you can think %a and
+act %a then return."
+%E
+%Cc Sam 00021
+"Domo %p-san, indeed you are ready.  I can now tell you what
+it is that I require of you.
+
+"The daimyo, %n, has betrayed us.  He has stolen from us
+%o and taken it to his donjon deep within
+%i.
+
+"If I cannot show the emperor %o when he comes
+for the festival he will know that I have failed in my duty, and
+request that I commit seppuku.
+
+"You must gain entrance to %i and retrieve the
+emperor's property.  Be quick!  The emperor will be here for the
+cha-no-you in 5 sticks.
+
+"Wakarimasu?"
+%E
+%Cp Sam 00025
+"To defeat %n you must overcome the seven emotions:
+hate, adoration, joy, anxiety, anger, grief, and fear."
+%E
+%Cp Sam 00026
+"Remember your honor is my honor, you perform in my name."
+%E
+%Cp Sam 00027
+"I will go to the temple and burn incense for your safe return."
+%E
+%Cp Sam 00028
+"Sayonara."
+%E
+%Cp Sam 00029
+"There can be honor in defeat, but no gain."
+%E
+%Cp Sam 00030
+"Your kami must be strong in order to succeed."
+%E
+%Cp Sam 00031
+"You are indeed a worthy %R, but now you must be a worthy samurai."
+%E
+%Cp Sam 00032
+"If you fail, %n will be like a tai-fun on the land."
+%E
+%Cp Sam 00033
+"If you are truly %a, %d will listen."
+%E
+%Cp Sam 00034
+"Sharpen your swords and your wits for the task before you."
+%E
+%Cc Sam 00035
+You instinctively reach for your swords.  You do not recognize the
+lay of this land, but you know that your teki are everywhere.
+%E
+%Cp Sam 00036
+Thankful that your %sp at %H cannot see
+your fear, you prepare again to advance.
+%E
+%Cc Sam 00040
+In your mind, you hear the taunts of %n.
+
+You become like the rice plant and bend to the ground, offering a
+prayer to %d.  But when the wind has passed, you stand
+proudly again.  Putting your kami in the hands of fate, you advance.
+%E
+%Cp Sam 00041
+As you arrive once again at the home of %n, your thoughts
+turn only to %o.
+%E
+%Cc Sam 00050
+"Ah, so it is to be you, %p-san.  I offer you seppuku.
+I will be your second if you wish."
+%E
+%Cp Sam 00051
+"I have offered you the honorable exit.  Now I will have your
+head to send unwashed to %l."
+%E
+%Cp Sam 00052
+"After I have dispatched you, I will curse your kami."
+%E
+%Cp Sam 00053
+"You have fought my samurai; surely you must know that you
+will not be able to take %o back to
+%H."
+%E
+%Cp Sam 00060
+"Ahh, I finally meet the daimyo of the kyokaku!"
+%E
+%Cp Sam 00061
+"There is no honor for me in your death."
+%E
+%Cp Sam 00062
+"You know that I cannot resash my swords until they have killed."
+%E
+%Cp Sam 00063
+"Your presence only compounds the dishonor of %l in not coming himself."
+%E
+%Cp Sam 00064
+"I will make tea with your hair and serve it to %l."
+%E
+%Cp Sam 00065
+"Your fear shows in your eyes, coward!"
+%E
+%Cp Sam 00066
+"I have not heard of you, %p-san; has your life been that unworthy?"
+%E
+%Cp Sam 00067
+"If you will not obey me, you will die."
+%E
+%Cp Sam 00068
+"Kneel now and make the two cuts of honor.  I will tell your %sp
+of your honorable death."
+%E
+%Cp Sam 00069
+"Your master was a poor teacher.  You will pay for his mistakes in
+your teaching."
+%E
+%Cc Sam 00070
+As you pick up %o, you feel the strength of its karma.
+You realize at once why so many good samurai had to die to defend it.
+You are humbled knowing that you hold one of the artifacts of the
+sun goddess.
+%E
+%Cc Sam 00080
+Your healing skills tell you that %ns wounds are mortal.
+
+You know that the bushido tells you to finish him and let his kami
+die with honor, but the thought of so many samurai dead due to this
+man's dishonor prevents you from giving the final blow.
+
+You order that his unwashed head be given to the crows and his body
+thrown into the sea.
+%E
+%Cc Sam 00081
+As you bow before %l, he welcomes you:
+
+    You have brought your family great honor, %p-sama.
+
+    While you have been gone the emperor's advisors have discovered in
+    the ancient texts that the karma of the samurai who seeks to recover
+    the amulet and the karma of %o are joined
+    as the seasons join to make a year.
+
+    Because you have shown such fidelity, the emperor requests
+    that you take leave of other obligations and continue on the
+    road that fate has set your feet upon.  I would consider it
+    an honor if you would allow me to watch your household until
+    you return with the amulet.
+
+With that, %l bows, and places his sword atop
+%o.
+%E
+%Cc Sam 00082
+%l holds %o tightly for a moment, then returns
+his gaze to you.
+
+"The time is ripe to recover the Amulet.  Return to %Z
+through the magic portal that transported you here so that you may
+achieve the destiny which awaits you."
+%E
+%Cp Sam 00090
+%lC bows.  "%p-sama, tell us of your search for the Amulet."
+%E
+%Cc Sam 00091
+"Ah, %p-sama.  You have wasted your efforts returning home.
+Now that you are in possession of the Amulet, you are honor-bound to
+finish the quest you have undertaken.  There will be plenty of time
+for saki and stories when you have finished.
+
+"Go now, and may our prayers be a wind at your back."
+%E
+#
+#      Tourist
+#
+%Cc Tou 00001
+You breathe a sigh of relief as you find yourself back in the familiar
+surroundings of %H.
+
+You quickly notice that things do not appear the way they did when you
+left.  The town is dark and quiet.  There are no sounds coming from
+behind the town walls, and no campfires burning in the fields.  As a
+matter of fact, you do not %x any movement in the fields at all, and
+the crops look as though they have been untended for many weeks.
+%E
+%Cp Tou 00002
+Once again, you are back at %H.
+%E
+%Cp Tou 00003
+You are back at %H.
+Things appear to have become so bad that you fear that soon
+%H will not be here to return to.
+%E
+%Cp Tou 00005
+"Gehennom on 5 zorkmids a day -- more like 500 a day if you ask me."
+%E
+%Cp Tou 00006
+"Do you know where I could find some nice postcards of The Gnomish Mines?"
+%E
+%Cp Tou 00007
+"Have you tried the weird toilets?"
+%E
+%Cp Tou 00008
+"Don't stay at the Inn, I hear the food is terrible and it has rats."
+%E
+%Cp Tou 00009
+"They told me that this was the off season!"
+%E
+%Cp Tou 00010
+"Gehennom on 5 zorkmids a day -- more like 500 a day if you ask me."
+%E
+%Cp Tou 00011
+"Do you know where I could find some nice postcards of The Gnomish Mines?"
+%E
+%Cp Tou 00012
+"Have you tried the weird toilets?"
+%E
+%Cp Tou 00013
+"If you stick around, I'll show you the pictures from my latest trip."
+%E
+%Cp Tou 00014
+"Did you bring me back any souvenirs?"
+%E
+%Cc Tou 00015
+"Is it really you, %p!  I had given up hope for your return.
+As you can %x, we are desperately in need of your talents.  Someone must
+defeat %n if our town is become what it once was.
+
+"Let me see if you are ready to be that someone."
+%E
+%Cp Tou 00016
+"Things are getting worse, %p.
+I hope that this time you are ready."
+%E
+%Cp Tou 00017
+"I hope that for the sake of %H you have prepared
+yourself this time."
+%E
+%Cc Tou 00018
+"It is too late, %p.  You are not even worthy to die amongst us.
+Leave %H and never return."
+%E
+%Cc Tou 00019
+"There is still too much that you have to learn before you can undertake
+the next step.  Return to us as a proven %R, and perhaps then
+you will be ready.
+
+"Go back now, and may the teachings of %d serve you well."
+%E
+%Cc Tou 00020
+"It would be an affront to %d to have one not true to the
+%a path undertake her bidding.
+
+"You must not return to us until you have purified yourself of these
+bad influences on your actions.  Remember, only by following the %a
+path can you hope to overcome the obstacles you will face."
+%E
+%Cc Tou 00021
+"You have indeed proven yourself a worthy %c, %p.
+
+"But now your kinfolk and I must ask you to put aside your travels and
+help us in our time of need.  After you left us we elected a new mayor,
+%n.  He proved to be a most heinous and vile creature.
+
+"Soon after taking office he absconded with %o
+and fled town, leaving behind his henchmen to rule over us.  In order
+for us to regain control of our town, you must enter %i
+and recover %o.
+
+"Do not be distracted on your quest.  If you do not return quickly I fear
+that all will be lost.  Let us both pray now that %d will guide you
+and keep you safe."
+%E
+%Cp Tou 00025
+"Do not be fooled by the false promises of %n."
+%E
+%Cp Tou 00026
+"To enter %i you must pass many traps."
+%E
+%Cp Tou 00027
+"If you do not return with %o, your quest
+will be in vain."
+%E
+%Cp Tou 00028
+"Do not be afraid to call upon %d if you truly need help."
+%E
+%Cp Tou 00029
+"If you do not destroy %n, he will follow you back here!"
+%E
+%Cp Tou 00030
+"Take %o from %n
+and you may be able to defeat him."
+%E
+%Cp Tou 00031
+"You must hurry, %p!"
+%E
+%Cp Tou 00032
+"You are like %Sa to me, %p.  Do not let me down."
+%E
+%Cp Tou 00033
+"If you are %a at all times you may succeed, %p."
+%E
+%Cp Tou 00034
+"Let all who meet you on your journey know that you are on an quest for
+%l and grant safe passage."
+%E
+%Cc Tou 00035
+Only your faith in %d keeps you from trembling.  You %x
+the handiwork of %ns henchlings everywhere.
+%E
+%Cp Tou 00036
+You know that this time you must find and destroy %n.
+%E
+%Cc Tou 00040
+You sense the presence of %o.
+%E
+%Cp Tou 00041
+You gain confidence, knowing that you may soon be united with
+%o.
+%E
+%Cc Tou 00050
+"So, %p, %l thinks that you can wrest
+%o from me!
+
+"It only proves how desperate he has become that he sends %ra to
+try and defeat me.  When this day is over, I will have you enslaved
+in the mines where you will rue the day that you ever entered
+%i."
+%E
+%Cp Tou 00051
+"I let you live the last time because it gave me pleasure.
+This time I will destroy you, %p."
+%E
+%Cc Tou 00052
+"These meetings come to bore me.  You disturb my workings with
+%o.
+
+"If you do not run away now, I will inflict so much suffering on you that
+%l will feel guilty for ever having sent his %S to me!"
+%E
+%Cc Tou 00053
+"You fool.  You do not know how to call upon the powers of
+%o.
+
+"Return it to me and I will teach you how to use it, and together we
+will rule %H.  But do so now, as my patience
+grows thin."
+%E
+%Cp Tou 00060
+"I defeated %l and I will defeat you, %p."
+%E
+%Cp Tou 00061
+"Where is %d now!  You must realize no one can help you here."
+%E
+%Cp Tou 00062
+"Beg for mercy now and I may be lenient on you."
+%E
+%Cp Tou 00063
+"If you were not so %a, you might have stood a chance."
+%E
+%Cp Tou 00064
+"Vengeance is mine at last, %p."
+%E
+%Cp Tou 00065
+"I only wish that %l had a more worthy %r to send against me."
+%E
+%Cp Tou 00066
+"With %o in my possession you cannot
+hope to defeat me."
+%E
+%Cp Tou 00067
+"%nC has never been defeated, NEVER!"
+%E
+%Cp Tou 00068
+"Are you truly the best %H has to send against me?
+I pity %l."
+%E
+%Cp Tou 00069
+"How do you spell %p?  I want to ensure the marker on your grave is
+correct as a warning to your %sp."
+%E
+%Cc Tou 00070
+As you pick up %o, you feel a great
+weight has been lifted from your shoulders.  Your only thoughts are
+to quickly return to %H and find %l.
+%E
+%Cc Tou 00080
+You turn in the direction of %n.  As his earthly body begins
+to vanish before your eyes, you hear him curse:
+
+    You shall never be rid of me, %p!
+    I will find you where ever you go and regain what is rightly mine.
+%E
+%Cc Tou 00081
+As %l detects the presence of %o,
+he almost smiles for the first time in many a full moon.
+
+As he looks up from %o he says:
+
+    You have recovered %o.  You are its
+    owner now, but not its master.  Let it work with you as you continue
+    your journey.  With its help, and %d to guide you on the
+    %a path, you may yet recover the Amulet of Yendor.
+%E
+%Cc Tou 00082
+"%oC is yours now.  %Z await your
+return through the magic portal that brought you here."
+%E
+%Cp Tou 00090
+"I could not be more proud than if you were my own %S, %p!
+Tell me of your adventures in quest of the Amulet of Yendor."
+%E
+%Cc Tou 00091
+"Stand back and let me look at you, %p.
+Now that you have recovered the Amulet of Yendor, I'm afraid living
+out your days in %H would seem pretty tame.
+
+"You have come too far to stop now, for there are still more tasks that
+our oral history foretells for you.  Forever more, though, your name shall
+be spoken by the %gP with awe.  You are truly an inspiration to your
+%sp!"
+%E
+#
+#      Valkyrie
+#
+%Cc Val 00001
+You materialize at the base of a snowy hill.  Atop the hill sits
+a place you know well, %H.  You immediately realize
+that something here is very wrong!
+
+In places, the snow and ice have been melted into steaming pools of
+water.  Fumaroles and pools of bubbling lava surround the hill.
+The stench of sulphur is carried through the air, and you %x creatures
+that should not be able to live in this environment moving towards you.
+%E
+%Cp Val 00002
+Once again, you are near the abode of %l.
+%E
+%Cp Val 00003
+Again you materialize near %ls abode.  You have a nagging feeling
+that this may be the last time you come here.
+%E
+%Cp Val 00005
+"Hail, and well met, brave %c."
+%E
+%Cp Val 00006
+"May %d guide your steps, %p."
+%E
+%Cp Val 00007
+"%lC weakens.  Without %o, her foresight is dim."
+%E
+%Cp Val 00008
+"You must hurry, %p, else Ragnarok may well come."
+%E
+%Cp Val 00009
+"I would deal with this foul %n myself, but %d forbids it."
+%E
+%Cp Val 00010
+"Hail, and well met, brave %c."
+%E
+%Cp Val 00011
+"May %d guide your steps, %p."
+%E
+%Cp Val 00012
+"%lC told us you had succeeded!"
+%E
+%Cp Val 00013
+"You recovered %o just in time, %p."
+%E
+%Cp Val 00014
+"Hail %d, for delivering %o back to us."
+%E
+%Cc Val 00015
+"Ah, %p, my %S.  You have returned to %H
+at last.  We are in dire need of your aid, but I must determine if you
+are yet ready for such an undertaking.
+
+"Let me read your fate..."
+%E
+%Cp Val 00016
+"Let me read the future for you now, %p, perhaps you have managed to
+change it enough..."
+%E
+%Cp Val 00017
+"Again, I shall read your fate, my %S.  Let us both hope that you have
+made changes to become ready for this task..."
+%E
+%Cc Val 00018
+"No, %p.  Your fate is sealed.  I must cast about for another
+champion.  Begone from my presence, and never return.  Know this, that
+you shall never succeed in this life, and Valhalla is denied to you."
+%E
+%Cc Val 00019
+"I see you and %n fighting, %p.  But you are not prepared and
+shall die at %ns hand if you proceed.  No.  This will not do.
+Go back out into the world, and grow more experienced at the ways of
+war.  Only when you have returned %Ra will you be able to defeat
+%n."
+%E
+%Cc Val 00020
+"NO!  This is terrible.  I see you becoming an ally of %n, and
+leading his armies in the final great battles.  This must not come to
+pass!  You have strayed from the %a path.  You must purge yourself,
+and return here only when you have regained a state of purity."
+%E
+%Cc Val 00021
+"It is not clear, %p, for my sight is limited without
+%o.  But it is now likely that you can defeat %n,
+and recover %o.
+
+"A short time ago, %n and his minions attacked this place.  They
+opened the huge volcanic vents you %x about the hill, and attacked.
+I knew that this was to come to pass, and had asked %d for a group
+of %gP to help defend this place.  The few you %x here are the
+mightiest of Valhalla's own, and are all that are left of one hundred
+%d sent.
+
+"Despite the great and glorious battle we fought, %n managed at last
+to steal %o.  This has upset the balance of the universe, and
+unless %o is returned into my care, %n may start Ragnarok.
+
+"You must find the entrance to %i.  Travel downward
+from there and you will find %ns lair.  Defeat him and
+return %o to me."
+%E
+%Cp Val 00025
+"Go with the blessings of %d."
+%E
+%Cp Val 00026
+"Call upon %d when you are in need."
+%E
+%Cp Val 00027
+"Use %o if you can.  It will protect you."
+%E
+%Cp Val 00028
+"Magical cold is very effective against %n."
+%E
+%Cp Val 00029
+"To face %n, you will need to be immune to fire."
+%E
+%Cp Val 00030
+"May %d strengthen your sword-arm."
+%E
+%Cp Val 00031
+"Trust in %d.  He will not desert you."
+%E
+%Cp Val 00032
+"It becomes more likely that Ragnarok will come with every passing moment.
+You must hurry, %p."
+%E
+%Cp Val 00033
+"If %n can master %o, he will be powerful enough to
+face %d far earlier than is fated.  This must not be!"
+%E
+%Cp Val 00034
+"Remember your training, %p.  You can succeed."
+%E
+%Cc Val 00035
+The ice and snow gives way to a valley floor.  You %x ahead of you
+a huge round hill surrounded by pools of lava.  This then is the entrance
+to %i.  It looks like you're not going to get in without
+a fight though.
+%E
+%Cp Val 00036
+Once again, you stand before the entrance to %i.
+%E
+%Cc Val 00040
+Through clouds of sulphurous gasses, you %x a rock palisade
+surrounded with a moat of bubbling lava.  You remember the description
+from something that %l said.  This is the lair of %n.
+%E
+%Cp Val 00041
+Once again, you stand in sight of %ns lair.
+%E
+%Cc Val 00050
+"So!  %lC has finally sent %ca to challenge me!
+
+"I thought that mastering %o would enable me to challenge %d,
+but it has shown me that first I must kill you!
+So come, little %s.  Once I defeat you, I can at last begin
+the final battle with %d."
+%E
+%Cp Val 00051
+"Again you challenge me, %r.  Good.  I will kill you now."
+%E
+%Cp Val 00052
+"Have you not learned yet?  You cannot defeat %n!"
+%E
+%Cp Val 00053
+"I will kill you, %c, and wrest %o from your mangled hands."
+%E
+%Cp Val 00060
+"I am your death, %c."
+%E
+%Cp Val 00061
+"You cannot prevail, %r.  I have foreseen your every move."
+%E
+%Cp Val 00062
+"With you out of the way, Valhalla will be mine for the taking."
+%E
+%Cp Val 00063
+"I killed scores of %ds best when I took %o.
+Do you really think that one %c can stand against me?"
+%E
+%Cp Val 00064
+"Who bears the souls of %cP to Valhalla, %r?"
+%E
+%Cp Val 00065
+"No, %d cannot help you here."
+%E
+%Cp Val 00066
+"Some instrument of %d you are, %p.  You are a weakling!"
+%E
+%Cp Val 00067
+"Never have I seen %ca so clumsy in battle."
+%E
+%Cp Val 00068
+"You die now, little %s."
+%E
+%Cp Val 00069
+"Your body I destroy now, your soul when my hordes overrun Valhalla!"
+%E
+%Cc Val 00070
+As you pick up %o, your mind is suddenly filled with images,
+and you perceive all of the possibilities of each potential choice you
+could make.  As you begin to control and channel your thoughts, you
+realize that you must return %o to %lC immediately.
+%E
+%Cc Val 00080
+A look of surprise and horror appears on %ns face.
+
+    No!!!  %o has lied to me!  I have been misled!
+
+Suddenly, %n grasps his head and screams in agony, then dies.
+%E
+%Cc Val 00081
+As you approach, %lC rises and touches %o.
+
+"You may take %o with you, %p.  I have removed from
+it the power to foretell the future, for that power no mortal should
+have.  Its other abilities, however, you have at your disposal.
+
+"You must now begin in %ds name to search for the Amulet of Yendor.
+May your steps be guided by %d, my %S."
+%E
+# assumes Orb of Fate (glass object)
+%Cc Val 00082
+"Careful, %p!  %oC might break, and that would be
+a tragic loss.  You are its keeper now, and the time has come to
+resume your search for the Amulet.  %Z await your
+return through the magic portal that brought you here."
+%E
+%Cp Val 00090
+"Greetings, %p.  I have not been able to pay as much attention to
+your search for the Amulet as I have wished.  How do you fare?"
+%E
+%Cc Val 00091
+"Excellent, %p.  I see you have recovered the Amulet!
+
+"You must take the Amulet to the Great Temple of %d, on the Astral
+plane.  There you must offer the Amulet to %d.
+
+"Go now, my %S.  I cannot tell you your fate, as the power of the
+Amulet interferes with mine.  I hope for your success."
+%E
+#
+#      Wizard
+#
+%Cc Wiz 00001
+You are suddenly in familiar surroundings.  You notice what appears to
+be a large, squat stone structure nearby.  Wait!  That looks like the
+tower of your former teacher, %l.
+
+However, things are not the same as when you were last here.  Mists and
+areas of unexplained darkness surround the tower.  There is movement in
+the shadows.
+
+Your teacher would never allow such unaesthetic forms to surround the
+tower...  unless something were dreadfully wrong!
+%E
+%Cp Wiz 00002
+Once again, you are back at %H.
+%E
+%Cp Wiz 00003
+You are back at %H.
+You have an odd feeling this may be the last time you ever come here.
+%E
+%Cp Wiz 00005
+"Would you happen to have some eye of newt in that overstuffed pack, %s?"
+%E
+%Cp Wiz 00006
+"Ah, the spell to create the magic portal worked.  Outstanding!"
+%E
+%Cp Wiz 00007
+"Hurry!  %lC may not survive that casting of the
+portal spell!!"
+%E
+%Cp Wiz 00008
+"The spells of %n were just too powerful for us to withstand."
+%E
+%Cp Wiz 00009
+"I, too, will venture into the world, because %n is but one of
+many evils to be vanquished."
+%E
+%Cp Wiz 00010
+"I have some eye of newt to trade, do you have a spare blind-worm's sting?"
+%E
+%Cp Wiz 00011
+"The magic portal now seems like it will remain stable for quite some time."
+%E
+%Cp Wiz 00012
+"Have you noticed how much stronger %l is since %o was recovered?"
+%E
+%Cp Wiz 00013
+"Thank %d!  We weren't positive you would defeat %n."
+%E
+%Cp Wiz 00014
+"I, too, will venture into the world, because %n was but one of
+many evils to be vanquished."
+%E
+%Cc Wiz 00015
+"Come closer, %p, for my voice falters in my old age.
+Yes, I see that you have come a long way since you went out into the
+world, leaving the safe confines of this tower.  However, I must first
+determine if you have all of the skills required to take on the task
+I require of you."
+%E
+%Cp Wiz 00016
+"Well, %p, you have returned.  Perhaps you are now ready..."
+%E
+%Cp Wiz 00017
+"This is getting tedious, %p, but perseverance is a sign of a true mage.
+I certainly hope that you are truly ready this time!"
+%E
+%Cc Wiz 00018
+"You fool, %p!  Why did I waste all of those years teaching you
+the esoteric arts?  Get out of here!  I shall find another."
+%E
+%Cc Wiz 00019
+"Alas, %p, you have not yet shown your proficiency as a worthy
+spellcaster.  As %ra, you would surely be overcome in the challenge
+ahead.  Go, now, expand your horizons, and return when you have attained
+renown as %Ra."
+%E
+%Cc Wiz 00020
+"You amaze me, %p!  How many times did I tell you that the way of a mage
+is an exacting one.  One must use the world with care, lest one leave it
+in ruins and simplify the task of %n.
+
+"You must go back and show your worthiness.  Do not return until you are
+truly ready for this quest.  May %d guide you in this task."
+%E
+%Cc Wiz 00021
+"Yes, %p, you truly are ready for this dire task.  Listen,
+carefully, for what I tell you now will be of vital importance.
+
+"Since you left us to hone your skills in the world, we unexpectedly came
+under attack by the forces of %n.  As you know, we thought
+%n had perished at the end of the last age, but, alas, this was
+not the case.
+
+"%nC sent an army of abominations against us.  Among them was a
+minion, mindless and ensorcelled, and thus, in the confusion, it was able
+to penetrate our defenses.  Alas, this creature has stolen
+%o and I fear it has delivered %o
+to %n.
+
+"Over the years, I had woven most of my power into this amulet, and thus,
+without it, I have but a shadow of my former power, and I fear that I
+shall soon perish.
+
+"You must travel to %i, and within its dungeons,
+find and overcome %n, and return %o to me.
+
+"Go now, with %d, and complete this quest before it is too late."
+%E
+%Cp Wiz 00025
+"Beware, for %n is immune to most magical attacks."
+%E
+%Cp Wiz 00026
+"To enter %i you must pass many traps."
+%E
+%Cp Wiz 00027
+"%nC may be vulnerable to physical attacks."
+%E
+%Cp Wiz 00028
+"%d will come to your aid when you call."
+%E
+%Cp Wiz 00029
+"You must utterly destroy %n.  He will pursue you otherwise."
+%E
+%Cp Wiz 00030
+"%oC is a mighty artifact.  With it you can
+destroy %n."
+%E
+%Cp Wiz 00031
+"Go forth with the blessings of %d."
+%E
+%Cp Wiz 00032
+"I will have my %gP watch for your return."
+%E
+%Cp Wiz 00033
+"Feel free to take any items in that chest that might aid you."
+%E
+%Cp Wiz 00034
+"You will know when %o is near.  Proceed with care!"
+%E
+%Cc Wiz 00035
+Wisps of fog swirl nearby.  You feel that %ns lair is close.
+%E
+%Cp Wiz 00036
+You believe that you may once again invade %i.
+%E
+%Cc Wiz 00040
+You feel your mentor's presence; perhaps %o is nearby.
+%E
+%Cp Wiz 00041
+The aura of %o tingles at the edge of your perception.
+%E
+%Cc Wiz 00050
+"Ah, I recognize you, %p.  So, %l has sent you to steal
+%o from me, hmmm?  Well, %l is a
+fool to send such a mental weakling against me.
+
+"Your destruction, however, should make for good sport.  In the end, you
+shall beg me to kill you!"
+%E
+%Cc Wiz 00051
+"How nice of you to return, %p!  I enjoyed our last meeting.  Are you
+still hungry for more pain?
+
+"Come!  Your soul, like %o, shall soon be mine to
+command."
+%E
+%Cp Wiz 00052
+"I'm sure that your perseverance shall be the subject of innumerable
+ballads, but you shall not be around to hear them, I fear!"
+%E
+%Cp Wiz 00053
+"Thief!  %o belongs to me, now.  I shall feed
+your living flesh to my minions."
+%E
+%Cp Wiz 00060
+"Your puny powers are no match for me, fool!"
+%E
+%Cp Wiz 00061
+"When you are defeated, your torment will last for a thousand years."
+%E
+%Cp Wiz 00062
+"After your downfall, %p, I shall devour %l
+for dessert!"
+%E
+%Cp Wiz 00063
+"Are you ready yet to beg for mercy?  I could be lenient..."
+%E
+%Cp Wiz 00064
+"Your soul shall join the enslaved multitude I command!"
+%E
+%Cp Wiz 00065
+"Your lack of will is evident, and you shall die as a result."
+%E
+%Cp Wiz 00066
+"Your faith in %d is for naught!  Come, submit to me now!"
+%E
+%Cp Wiz 00067
+"A mere %r is nothing compared to my skill!"
+%E
+%Cp Wiz 00068
+"So, you are the best hope of %l?  How droll."
+%E
+%Cp Wiz 00069
+"Feel my power, %c!  My victory is imminent!"
+%E
+%Cc Wiz 00070
+As you touch %o, its comforting power infuses you
+with new energy.  You feel as if you can detect others' thoughts flowing
+through it.  Although you yearn to wear %o
+and attack the Wizard of Yendor, you know you must return it to its
+rightful owner, %l.
+%E
+%Cc Wiz 00080
+%nC croaks out, as his body begins to shrivel up:
+
+    I shall haunt your progress until the end of time.  A thousand
+    curses on you and %l.
+
+Then, the body bursts into a cloud of choking dust, and blows away.
+%E
+%Cc Wiz 00081
+%lC notices %o in your possession,
+beams at you and says:
+
+    I knew you could defeat %n and retrieve
+    %o.  We shall never forget this
+    brave service.
+
+    Take %o with you in your quest for
+    the Amulet of Yendor.  I can sense that it has attuned
+    itself to you already.
+
+    May %d guide you in your quest, and keep you from harm.
+%E
+%Cc Wiz 00082
+"You are the keeper of %o now.  It is time to
+recover the /other/ Amulet.  %Z await your return through
+the magic portal which brought you here."
+%E
+%Cp Wiz 00090
+"Come near, my %S, and share your adventures with me.
+So, have you succeeded in your quest for the Amulet of Yendor?"
+%E
+%Cc Wiz 00091
+"Congratulations, %p.  I always knew that if anyone could succeed
+in defeating the Wizard of Yendor and his minions, it would be you.
+
+"Go now, and take the Amulet to the astral plane.  Once there, present
+the Amulet on the altar of %d.  Along the way you shall pass through the
+four elemental planes.  These planes are like nothing you have ever
+experienced before, so be prepared!
+
+"For this you were born, %s!  I am very proud of you."
+%E
+#
+#      General
+#
+%Cc - 00001
+It is written in the Book of %d:
+
+    After the Creation, the cruel god Moloch rebelled
+    against the authority of Marduk the Creator.
+    Moloch stole from Marduk the most powerful of all
+    the artifacts of the gods, the Amulet of Yendor,
+    and he hid it in the dark cavities of Gehennom, the
+    Under World, where he now lurks, and bides his time.
+
+Your %G %d seeks to possess the Amulet, and with it
+to gain deserved ascendance over the other gods.
+
+You, a newly trained %r, have been heralded
+from birth as the instrument of %d.  You are destined
+to recover the Amulet for your deity, or die in the
+attempt.  Your hour of destiny has come.  For the sake
+of us all:  Go bravely with %d!
+%E
+%Cp - 00002
+You receive a faint telepathic message from %l:
+Your help is urgently needed at %H!
+Look for a ...ic transporter.
+You couldn't quite make out that last message.
+%E
+%Cp - 00003
+You again sense %l pleading for help.
+%E
+%Cp - 00004
+You again sense %l demanding your attendance.
+%E
+# Completed the quest by returning with artifact, but not carrying
+# the Bell of Opening; quest leader lets you know that it is needed.
+#[ Should this be role-specific so that each leader has variant text? ]
+%Cp - 00005
+"The silver bell which was hoarded by %n will be
+essential in locating the Amulet of Yendor."
+%E
+#
+#      Angelic maledictions.
+#
+%Cp - 00010
+"Repent, and thou shalt be saved!"
+%E
+%Cp - 00011
+"Thou shalt pay for thine insolence!"
+%E
+%Cp - 00012
+"Very soon, my child, thou shalt meet thy maker."
+%E
+%Cp - 00013
+"The great %D has sent me to make you pay for your sins!"
+%E
+%Cp - 00014
+"The wrath of %D is now upon you!"
+%E
+%Cp - 00015
+"Thy life belongs to %D now!"
+%E
+%Cp - 00016
+"Dost thou wish to receive thy final blessing?"
+%E
+%Cp - 00017
+"Thou art but a godless void."
+%E
+%Cp - 00018
+"Thou art not worthy to seek the Amulet."
+%E
+%Cp - 00019
+"No one expects the Spanish Inquisition!"
+%E
+#
+#      Demonic maledictions.
+#
+%Cp - 00030
+"I first mistook thee for a statue, when I regarded thy head of stone."
+%E
+%Cp - 00031
+"Come here often?"
+%E
+%Cp - 00032
+"Doth pain excite thee?  Wouldst thou prefer the whip?"
+%E
+%Cp - 00033
+"Thinkest thou it shall tickle as I rip out thy lungs?"
+%E
+%Cp - 00034
+"Eat slime and die!"
+%E
+%Cp - 00035
+"Go ahead, fetch thy mama!  I shall wait."
+%E
+%Cp - 00036
+"Go play leapfrog with a herd of unicorns!"
+%E
+%Cp - 00037
+"Hast thou been drinking, or art thou always so clumsy?"
+%E
+%Cp - 00038
+"This time I shall let thee off with a spanking, but let it not happen again."
+%E
+%Cp - 00039
+"I've met smarter (and prettier) acid blobs."
+%E
+%Cp - 00040
+"Look!  Thy bootlace is undone!"
+%E
+%Cp - 00041
+"Mercy!  Dost thou wish me to die of laughter?"
+%E
+%Cp - 00042
+"Run away!  Live to flee another day!"
+%E
+%Cp - 00043
+"Thou hadst best fight better than thou canst dress!"
+%E
+%Cp - 00044
+"Twixt thy cousin and thee, Medusa is the prettier."
+%E
+%Cp - 00045
+"Methinks thou wert unnaturally stirred by yon corpse back there, eh, varlet?"
+%E
+%Cp - 00046
+"Up thy nose with a rubber hose!"
+%E
+%Cp - 00047
+"Verily, thy corpse could not smell worse!"
+%E
+%Cp - 00048
+"Wait!  I shall polymorph into a grid bug to give thee a fighting chance!"
+%E
+%Cp - 00049
+"Why search for the Amulet?  Thou wouldst but lose it, cretin."
+%E
+#
+#      Banishment message (for converted hero)
+#
+%Cc - 00060
+"You have betrayed all those who hold allegiance to %d, as you once did.
+My allegiance to %d holds fast and I cannot condone or accept what you 
+have done.
+
+Leave this place.  You shall never set foot at %H again.
+That which you seek is now lost forever, for without the Bell of Opening, 
+you will never be able to enter the place where he who has the Amulet 
+resides.
+
+Go now!  You are banished from this place.
+%E
+#
+#      TEST PATTERN
+#
+%Cc - 00099
+ %p:   return(plname);
+ %c:   return(pl_character);
+ %r:   return((char *)rank_of(u.ulevel));
+ %R:   return((char *)rank_of(MIN_QUEST_LEVEL));
+ %s:   return((flags.female) ? "sister" : "brother" );
+ %S:   return((flags.female) ? "daughter" : "son" );
+ %l:   return((char *)ldrname());
+ %i:   return(intermed());
+ %o:   return(artiname());
+ %n:   return((char *)neminame());
+ %g:   return((char *)guardname());
+ %G:   return((char *)align_gtitle(u.ualignbase[1]));
+ %H:   return((char *)homebase());
+ %a:   return(Alignnam(u.ualignbase[1]));
+ %A:   return(Alignnam(u.ualign.type));
+ %d:   return((char *)align_gname(u.ualignbase[1]));
+ %D:   return((char *)align_gname(A_LAWFUL));
+ %C:   return("chaotic");
+ %N:   return("neutral");
+ %L:   return("lawful");
+ %x:   return((Blind) ? "sense" : "see");
+ %Z:   return("The Dungeons of Doom");
+ %%:   return(percent_sign);
+ a suffix:     return an(root);
+ A suffix:     return An(root);
+ C suffix:     return capitalized(root);
+ p suffix:     return makeplural(root);
+ P suffix:     return makeplural(capitalized(root));
+ s suffix:     return s_suffix(root);
+ S suffix:     return s_suffix(capitalized(root));
+ t suffix:     return strip_the_prefix(root);
+%E
diff --git a/dat/rumors.fal b/dat/rumors.fal
new file mode 100644 (file)
index 0000000..90675fb
--- /dev/null
@@ -0,0 +1,392 @@
+"So when I die, the first thing I will see in heaven is a score list?"
+1st Law of Hacking:  leaving is much more difficult than entering.
+2nd Law of Hacking:  first in, first out.
+3rd Law of Hacking:  the last blow counts most.
+4th Law of Hacking:  you will find the exit at the entrance.
+A chameleon imitating a mail daemon often delivers scrolls of fire.
+A cockatrice corpse is guaranteed to be untainted!
+A dead cockatrice is just a dead lizard.
+A dragon is just a snake that ate a scroll of fire.
+A fading corridor enlightens your insight.
+A glowing potion is too hot to drink.
+A good amulet may protect you against guards.
+A lizard corpse is a good thing to turn undead.
+A long worm can be defined recursively.  So how should you attack it?
+A monstrous mind is a toy forever.
+A nymph will be very pleased if you call her by her real name:  Lorelei.
+A ring of dungeon master control is a great find.
+A ring of extra ring finger is useless if not enchanted.
+A rope may form a trail in a maze.
+A staff may recharge if you drop it for awhile.
+A visit to the Zoo is very educational; you meet interesting animals.
+A wand of deaf is a more dangerous weapon than a wand of sheep.
+A wand of vibration might bring the whole cave crashing about your ears.
+A winner never quits.  A quitter never wins.
+A wish?  Okay, make me a fortune cookie!
+Afraid of mimics?  Try to wear a ring of true seeing.
+All monsters are created evil, but some are more evil than others.
+Always attack a floating eye from behind!
+An elven cloak is always the height of fashion.
+Any small object that is accidentally dropped will hide under a larger object.
+Archeologists find more bones piles.
+Austin Powers says: My Mojo is back!  Yeah, baby!
+Balrogs do not appear above level 20.
+Banana peels work especially well against Keystone Kops.
+Be careful when eating bananas.  Monsters might slip on the peels.
+Better leave the dungeon; otherwise you might get hurt badly.
+Beware of the potion of nitroglycerin -- it's not for the weak of heart.
+Beware:  there's always a chance that your wand explodes as you try to zap it!
+Beyond the 23rd level lies a happy retirement in a room of your own.
+Changing your suit without dropping your sword?  You must be kidding!
+Close the door!  You're letting the heat out!
+Cockatrices might turn themselves to stone faced with a mirror.
+Consumption of home-made food is strictly forbidden in this dungeon.
+Dark room?  Your chance to develop your photographs!
+Dark rooms are not *completely* dark:  just wait and let your eyes adjust...
+David London sez, "Hey guys, *WIELD* a lizard corpse against a cockatrice!"
+Death is just life's way of telling you you've been fired.
+Demi-gods don't need any help from the gods.
+Demons *HATE* Priests and Priestesses.
+Didn't you forget to pay?
+Didn't your mother tell you not to eat food off the floor?
+Direct a direct hit on your direct opponent, directing in the right direction.
+Do you want to make more money?  Sure, we all do!  Join the Fort Ludios guard!
+Does your boss know what you're doing right now?
+Don't bother wishing for things.  You'll probably find one on the next level.
+Don't eat too much:  you might start hiccoughing!
+Don't play NetHack at your work; your boss might hit you!
+Don't tell a soul you found a secret door, otherwise it isn't a secret anymore.
+Drinking potions of booze may land you in jail if you are under 21.
+Drop your vanity and get rid of your jewels!  Pickpockets about!
+Eat 10 cloves of garlic and keep all humans at a two-square distance.
+Eels hide under mud.  Use a unicorn to clear the water and make them visible.
+Elf has extra speed.
+Engrave your wishes with a wand of wishing.
+Eventually you will come to admire the swift elegance of a retreating nymph.
+Ever heard hissing outside?  I *knew* you hadn't!
+Ever lifted a dragon corpse?
+Ever seen a leocrotta dancing the tengu?
+Ever seen your weapon glow plaid?
+Ever tamed a shopkeeper?
+Ever tried digging through a Vault Guard?
+Ever tried enchanting a rope?
+Floating eyes can't stand Hawaiian shirts.
+For any remedy there is a misery.
+Giant bats turn into giant vampires.
+Good day for overcoming obstacles.  Try a steeplechase.
+Half Moon tonight.  (At least it's better than no Moon at all.)
+Help!  I'm being held prisoner in a fortune cookie factory!
+Housecats have nine lives, kittens only one.
+How long can you tread water?
+Hungry?  There is an abundance of food on the next level.
+I guess you've never hit a mail daemon with the Amulet of Yendor...
+If you are the shopkeeper, you can take things for free.
+If you ask really nicely, the Wizard will give you the Amulet.
+If you can't learn to do it well, learn to enjoy doing it badly.
+If you thought the Wizard was bad, just wait till you meet the Warlord!
+If you turn blind, don't expect your dog to be turned into a seeing-eye dog.
+If you want to feel great, you must eat something real big.
+If you want to float, you'd better eat a floating eye.
+If your ghost kills a player, it increases your score.
+Increase mindpower:  Tame your own ghost!
+It furthers one to see the great man.
+It's easy to overlook a monster in a wood.
+Just below any trap door there may be another one.  Just keep falling!
+Katanas are very sharp; watch you don't cut yourself.
+Keep a clear mind:  quaff clear potions.
+Kicking the terminal doesn't hurt the monsters.
+Killer bees keep appearing till you kill their queen.
+Killer bunnies can be tamed with carrots only.
+Latest news?  Put `rec.games.roguelike.nethack' in your .newsrc!
+Learn how to spell.  Play NetHack!
+Leprechauns hide their gold in a secret room.
+Let your fingers do the walking on the yulkjhnb keys.
+Let's face it:  this time you're not going to win.
+Let's have a party, drink a lot of booze.
+Liquor sellers do not drink; they hate to see you twice.
+Lunar eclipse tonight.  May as well quit now!
+Meeting your own ghost decreases your luck considerably!
+Money to invest?  Take it to the local branch of the Magic Memory Vault!
+Monsters come from nowhere to hit you everywhere.
+Monsters sleep because you are boring, not because they ever get tired.
+Most monsters prefer minced meat.  That's why they are hitting you!
+Most of the bugs in NetHack are on the floor.
+Much ado Nothing Happens.
+Multi-player NetHack is a myth.
+NetHack is addictive.  Too late, you're already hooked.
+Never ask a shopkeeper for a price list.
+Never burn a tree, unless you like getting whacked with a +5 shovel.
+Never eat with glowing hands!
+Never mind the monsters hitting you:  they just replace the charwomen.
+Never play leapfrog with a unicorn.
+Never step on a cursed engraving.
+Never swim with a camera:  there's nothing to take pictures of.
+Never teach your pet rust monster to fetch.
+Never trust a random generator in magic fields.
+Never use a wand of death.
+No level contains two shops.  The maze is no level.  So...
+No part of this fortune may be reproduced, stored in a retrieval system, ...
+Not all rumors are as misleading as this one.
+Nymphs and nurses like beautiful rings.
+Nymphs are blondes.  Are you a gentleman?
+Offering a unicorn a worthless piece of glass might prove to be fatal!
+Old hackers never die:  young ones do.
+One has to leave shops before closing time.
+One homunculus a day keeps the doctor away.
+One level further down somebody is getting killed, right now.
+Only a wizard can use a magic whistle.
+Only adventurers of evil alignment think of killing their dog.
+Only chaotic evils kill sleeping monsters.
+Only real trappers escape traps.
+Only real wizards can write scrolls.
+Operation OVERKILL has started now.
+Ouch.  I hate when that happens.
+PLEASE ignore previous rumor.
+Polymorph into an ettin; meet your opponents face to face to face.
+Praying will frighten demons.
+Row (3x) that boat gently down the stream, Charon (4x), death is but a dream.
+Running is good for your legs.
+Screw up your courage!  You've screwed up everything else.
+Seepage?  Leaky pipes?  Rising damp?  Summon the plumber!
+Segmentation fault (core dumped).
+Shopkeepers are insured by Croesus himself!
+Shopkeepers sometimes die from old age.
+Some mazes (especially small ones) have no solutions, says man 6 maze.
+Some questions the Sphynx asks just *don't* have any answers.
+Sometimes "mu" is the answer.
+Sorry, no fortune this time.  Better luck next cookie!
+Spare your scrolls of make-edible until it's really necessary!
+Stormbringer doesn't steal souls.  People steal souls.
+Suddenly, the dungeon will collapse...
+Taming a mail daemon may cause a system security violation.
+The crowd was so tough, the Stooges won't play the Dungeon anymore, nyuk nyuk.
+The leprechauns hide their treasure in a small hidden room.
+The longer the wand the better.
+The magic word is "XYZZY".
+The meek shall inherit your bones files.
+The mines are dark and deep, and I have levels to go before I sleep.
+The use of dynamite is dangerous.
+There are no worms in the UNIX version.
+There is a trap on this level!
+They say that Demogorgon, Asmodeus, Orcus, Yeenoghu & Juiblex is no law firm.
+They say that Geryon has an evil twin, beware!
+They say that Medusa would make a terrible pet.
+They say that NetHack bugs are Seldon planned.
+They say that NetHack comes in 256 flavors.
+They say that NetHack is just a computer game.
+They say that NetHack is more than just a computer game.
+They say that NetHack is never what it used to be.
+They say that a baby dragon is too small to hurt or help you.
+They say that a black pudding is simply a brown pudding gone bad.
+They say that a black sheep has 3 bags full of wool.
+They say that a blank scroll is like a blank check.
+They say that a cat named Morris has nine lives.
+They say that a desperate shopper might pay any price in a shop.
+They say that a diamond dog is everybody's best friend.
+They say that a dwarf lord can carry a pick-axe because his armor is light.
+They say that a floating eye can defeat Medusa.
+They say that a fortune only has 1 line and you can't read between it.
+They say that a fortune only has 1 line, but you can read between it.
+They say that a fountain looks nothing like a regularly erupting geyser.
+They say that a gold doubloon is worth more than its weight in gold.
+They say that a grid bug won't pay a shopkeeper for zapping you in a shop.
+They say that a gypsy could tell your fortune for a price.
+They say that a hacker named Alice once level teleported by using a mirror.
+They say that a hacker named David once slew a giant with a sling and a rock.
+They say that a hacker named Dorothy once rode a fog cloud to Oz.
+They say that a hacker named Mary once lost a white sheep in the mazes.
+They say that a helm of brilliance is not to be taken lightly.
+They say that a hot dog and a hell hound are the same thing.
+They say that a lamp named Aladdin's Lamp contains a djinni with 3 wishes.
+They say that a large dog named Lassie will lead you to the amulet.
+They say that a long sword is not a light sword.
+They say that a manes won't mince words with you.
+They say that a mind is a terrible thing to waste.
+They say that a plain nymph will only wear a wire ring in one ear.
+They say that a plumed hat could be a previously used crested helmet.
+They say that a potion of oil is difficult to grasp.
+They say that a potion of yogurt is a cancelled potion of sickness.
+They say that a purple worm is not a baby purple dragon.
+They say that a quivering blob tastes different than a gelatinous cube.
+They say that a runed broadsword named Stormbringer attracts vortices.
+They say that a scroll of summoning has other names.
+They say that a shaman can bestow blessings but usually doesn't.
+They say that a shaman will bless you for an eye of newt and wing of bat.
+They say that a shimmering gold shield is not a polished silver shield.
+They say that a spear will hit a neo-otyugh.  (Do YOU know what that is?)
+They say that a spotted dragon is the ultimate shape changer.
+They say that a stethoscope is no good if you can only hear your heartbeat.
+They say that a succubus named Suzy will sometimes warn you of danger.
+They say that a wand of cancellation is not like a wand of polymorph.
+They say that a wood golem named Pinocchio would be easy to control.
+They say that after killing a dragon it's time for a change of scenery.
+They say that an amulet of strangulation is worse than ring around the collar.
+They say that an attic is the best place to hide your toys.
+They say that an axe named Cleaver once belonged to a hacker named Beaver.
+They say that an eye of newt and a wing of bat are double the trouble.
+They say that an incubus named Izzy sometimes makes women feel sensitive.
+They say that an opulent throne room is rarely a place to wish you'd be in.
+They say that an unlucky hacker once had a nose bleed at an altar and died.
+They say that and they say this but they never say never, never!
+They say that any quantum mechanic knows that speed kills.
+They say that applying a unicorn horn means you've missed the point.
+They say that blue stones are radioactive, beware.
+They say that building a dungeon is a team effort.
+They say that chaotic characters never get a kick out of altars.
+They say that collapsing a dungeon often creates a panic.
+They say that counting your eggs before they hatch shows that you care.
+They say that dipping a bag of tricks in a fountain won't make it an icebox.
+They say that dipping an eel and brown mold in hot water makes bouillabaisse.
+They say that donating a doubloon is extremely pious charity.
+They say that dungeoneers prefer dark chocolate.
+They say that eating royal jelly attracts grizzly owlbears.
+They say that eggs, pancakes and juice are just a mundane breakfast.
+They say that everyone knows why Medusa stands alone in the dark.
+They say that everyone wanted rec.games.hack to undergo a name change.
+They say that finding a winning strategy is a deliberate move on your part.
+They say that finding worthless glass is worth something.
+They say that fortune cookies are food for thought.
+They say that gold is only wasted on a pet dragon.
+They say that good things come to those that wait.
+They say that greased objects will slip out of monsters' hands.
+They say that if you can't spell then you'll wish you had a spellbook.
+They say that if you live by the sword, you'll die by the sword.
+They say that if you play like a monster you'll have a better game.
+They say that if you sleep with a demon you might awake with a headache.
+They say that if you step on a crack you could break your mother's back.
+They say that if you're invisible you can still be heard!
+They say that if you're lucky you can feel the runes on a scroll.
+They say that in the big picture gold is only small change.
+They say that in the dungeon it's not what you know that really matters.
+They say that in the dungeon moon rocks are really dilithium crystals.
+They say that in the dungeon the boorish customer is never right.
+They say that in the dungeon you don't need a watch to tell time.
+They say that in the dungeon you need something old, new, burrowed and blue.
+They say that in the dungeon you should always count your blessings.
+They say that iron golem plate mail isn't worth wishing for.
+They say that it takes four quarterstaffs to make one staff.
+They say that it's not over till the fat ladies sing.
+They say that it's not over till the fat lady shouts `Off with its head'.
+They say that kicking a heavy statue is really a dumb move.
+They say that kicking a valuable gem doesn't seem to make sense.
+They say that leprechauns know Latin and you should too.
+They say that minotaurs get lost outside of the mazes.
+They say that most trolls are born again.
+They say that naming your cat Garfield will make you more attractive.
+They say that no one knows everything about everything in the dungeon.
+They say that no one plays NetHack just for the fun of it.
+They say that no one really subscribes to rec.games.roguelike.nethack.
+They say that no one will admit to starting a rumor.
+They say that nurses sometimes carry scalpels and never use them.
+They say that once you've met one wizard you've met them all.
+They say that one troll is worth 10,000 newts.
+They say that only David can find the zoo!
+They say that only angels play their harps for their pets.
+They say that only big spenders carry gold.
+They say that orc shamans are healthy, wealthy and wise.
+They say that playing NetHack is like walking into a death trap.
+They say that problem breathing is best treated by a proper diet.
+They say that quaffing many potions of levitation can give you a headache.
+They say that queen bees get that way by eating royal jelly.
+They say that reading a scare monster scroll is the same as saying Elbereth.
+They say that real hackers always are controlled.
+They say that real hackers never sleep.
+They say that shopkeepers are insured by Croesus himself!
+They say that shopkeepers never carry more than 20 gold pieces, at night.
+They say that shopkeepers never sell blessed potions of invisibility.
+They say that soldiers wear kid gloves and silly helmets.
+They say that some Kops are on the take.
+They say that some guards' palms can be greased.
+They say that some monsters may kiss your boots to stop your drum playing.
+They say that sometimes you can be the hit of the party when playing a horn.
+They say that the NetHack gods generally welcome your sacrifices.
+They say that the Three Rings are named Vilya, Nenya and Narya.
+They say that the Wizard of Yendor has a death wish.
+They say that the `hair of the dog' is sometimes an effective remedy.
+They say that the best time to save your game is now before it's too late.
+They say that the biggest obstacle in NetHack is your mind.
+They say that the gods are angry when they hit you with objects.
+They say that the priesthood are specially favored by the gods.
+They say that the way to make a unicorn happy is to give it what it wants.
+They say that there are no black or white stones, only gray.
+They say that there are no skeletons hence there are no skeleton keys.
+They say that there is a clever rogue in every hacker just dying to escape.
+They say that there is no such thing as free advice.
+They say that there is only one way to win at NetHack.
+They say that there once was a fearsome chaotic samurai named Luk No.
+They say that there was a time when cursed holy water wasn't water.
+They say that there's no point in crying over a gray ooze.
+They say that there's only hope left after you've opened Pandora's box.
+They say that trap doors should always be marked `Caution:  Trap Door'.
+They say that using an amulet of change isn't a difficult operation.
+They say that water walking boots are better if you are fast like Hermes.
+They say that when you wear a circular amulet you might resemble a troll.
+They say that when you're hungry you can get a pizza in 30 moves or it's free.
+They say that when your god is angry you should try another one.
+They say that wielding a unicorn horn takes strength.
+They say that with speed boots you never worry about hit and run accidents.
+They say that you can defeat a killer bee with a unicorn horn.
+They say that you can only cross the River Styx in Charon's boat.
+They say that you can only kill a lich once and then you'd better be careful.
+They say that you can only wish for things you've already had.
+They say that you can train a cat by talking gently to it.
+They say that you can train a dog by talking firmly to it.
+They say that you can trust your gold with the king.
+They say that you can't wipe your greasy bare hands on a blank scroll.
+They say that you cannot trust scrolls of rumor.
+They say that you could fall head over heels for an energy vortex.
+They say that you need a key in order to open locked doors.
+They say that you need a mirror to notice a mimic in an antique shop.
+They say that you really can use a pick-axe unless you really can't.
+They say that you should always store your tools in the cellar.
+They say that you should be careful while climbing the ladder to success.
+They say that you should call your armor `rustproof'.
+They say that you should name your dog Spuds to have a cool pet.
+They say that you should name your weapon after your first monster kill.
+They say that you should never introduce a rope golem to a succubus.
+They say that you should never sleep near invisible ring wraiths.
+They say that you should never try to leave the dungeon with a bag of gems.
+They say that you should remove your armor before sitting on a throne.
+This fortune cookie is copy protected.
+This fortune cookie is the property of Fortune Cookies, Inc.
+This release contains 10% recycled material.
+Time stands still as the succubus changes her calendar to January 1, 2000.
+Tired?  Try a scroll of charging on yourself.
+To achieve the next higher rating, you need 3 more points.
+To reach heaven, escape the dungeon while wearing a ring of levitation.
+Tourists wear shirts loud enough to wake the dead.
+Try calling your katana Moulinette.
+Ulch!  That meat was painted!
+Unfortunately, this message was left intentionally blank.
+Using a morning star in the evening has no effect.
+Waltz, dumb nymph, for quick jigs vex.
+Want a hint?  Zap a wand of make invisible on your weapon!
+Want to ascend in a hurry?  Apply at Gizmonic Institute.
+Wanted: shopkeepers.  Send a scroll of mail to Mage of Yendor/Level 35/Dungeon.
+Warning:  fortune reading can be hazardous to your health.
+We have new ways of detecting treachery...
+Wet towels make great weapons!
+What a pity, you cannot read it!
+Whatever can go wrong, will go wrong.
+When a piercer drops in on you, you will be tempted to hit the ceiling!
+When in a maze follow the right wall and you will never get lost.
+When you have a key, you don't have to wait for the guard.
+Why are you wasting time reading fortunes?
+Wish for a master key and open the Magic Memory Vault!
+Wizard expects every monster to do its duty.
+Wow!  You could've had a potion of fruit juice!
+Yet Another Silly Message (YASM).
+You are destined to be misled by a fortune.
+You can get a genuine Amulet of Yendor by doing the following:  --More--
+You can make holy water by boiling the hell out of it.
+You can protect yourself from black dragons by doing the following:  --More--
+You can't get by the snake.
+You choke on the fortune cookie.  --More--
+You feel like someone is pulling your leg.
+You have to outwit the Sphynx or pay her.
+You hear the fortune cookie's hissing!
+You may get rich selling letters, but beware of being blackmailed!
+You offend Shai-Hulud by sheathing your crysknife without having drawn blood.
+You swallowed the fortune!
+You want to regain strength?  Two levels ahead is a guesthouse!
+You will encounter a tall, dark, and gruesome creature...
diff --git a/dat/rumors.tru b/dat/rumors.tru
new file mode 100644 (file)
index 0000000..cfbdb8b
--- /dev/null
@@ -0,0 +1,359 @@
+A blindfold can be very useful if you're telepathic.
+A candelabrum affixed with seven candles shows the way with a magical light.
+A crystal plate mail will not rust.
+A katana might slice a worm in two.
+A magic vomit pump could be useful for gourmands.
+A nymph knows how to unlock chains.
+A potion of blindness lets you see invisible things.
+A priest can get the gods to listen easily.
+A priestess and a virgin you might be, but that unicorn won't care.
+A ring of conflict is a bad thing if there is a nurse in the room.
+A short sword is not as good as a long sword.
+A succubus will go farther than a nymph.
+A wand can exorcize a past explorer's ghost.
+Acid blobs should be attacked bare-handed.
+Affairs with nymphs are often very expensive.
+Afraid of nymphs?  Wear a ring of adornment.
+Afraid of your valuables being stolen?  Carry more junk!
+Always be aware of the phase of the moon!
+Always sweep the floor before engraving important messages.
+Amulets of Yendor are hard to make.  Even for a wand of wishing.
+An elven cloak protects against magic.
+An umber hulk can be a confusing sight.
+As Crom is my witness, I'll never go hungry again!
+Asking about monsters may be very useful.
+Attack long worms from the rear -- that is so much safer!
+Attacking an eel where there is none is usually a fatal mistake!
+Bandaging wounds helps keep up appearances.
+Bashing monsters with a bow is not such a good idea.
+Be careful!  The Wizard may plan an ambush!
+Be nice to a nurse:  Put away your weapon and take off your clothes.
+Being digested is a painfully slow process.
+Blank scrolls make more interesting reading.
+Blind?  Catch a floating eye!
+Booksellers never read scrolls; they might get carried away.
+Chemistry 101: Never pour water into acid.
+Concise conquest:  Control, confuse, conjure, condemn.
+Conserve energy, turn off the lights.
+Digging up a grave could be a bad idea...
+Dilithium crystals are rare indeed.
+Dogs are attracted by the smell of tripe.
+Dogs are superstitious; they never step on cursed items.
+Dogs of ghosts aren't angry, just hungry.
+Don't forget!  Large dogs are MUCH harder to kill than little dogs.
+Don't mess with shopkeepers, or you'll get the Guild after you.
+Dragons never whip their children; they wouldn't feel it!
+Eat your carrots.  They're good for your eyes.
+Eating a freezing sphere is like eating a yeti.
+Eating a killer bee is like eating a scorpion.
+Eating a tengu is like eating a nymph.
+Eating a wraith is a rewarding experience!
+Eating unpaid leprechauns may be advantageous.
+Elbereth has quite a reputation around these parts.
+Elf corpses are incompatible with the sandman, and at times the gods as well.
+Elven cloaks cannot rust.
+Even evil players have a guardian angel.
+Ever fought with an enchanted tooth?
+Ever tried reading while confused?
+Ever tried to put a troll into a large box?
+Ever wondered why one would want to dip something in a potion?
+Expensive cameras have penetrating flash lights.
+Extra staircases lead to extra levels.
+Fiery letters might deter monsters.
+For a good time engrave `Elbereth'.
+Gems are too precious to be thrown away carelessly.
+Getting hungry?  Stop wearing rings!
+Getting too warm?  Take off that Amulet of Yendor and stay away from the exit!
+Gods expect the best from their priesthood.
+Gods look down their noses at demigods.
+Got a question?  Try rec.games.roguelike.nethack.
+Grave robbers sometimes get rich.
+Guy Montag keeps his scrolls in a bag.
+Handle your flasks carefully -- there might be a ghost inside!
+Holy water has many uses.
+Horses trust their riders, even when not so deserved.
+Hunger is a confusing experience for a dog!
+I once knew a hacker who ate too fast and choked to death.
+I smell a maze of twisty little passages.
+I wish I never wished a wand of wishing.  (Wishful thinking.)
+I wouldn't advise playing catch with a giant.
+I'm watching you.  -- The Wizard of Yendor
+Ice boxes keep your food fresh.
+If you are being punished, it's done with a deadly weapon.
+If you kill the Wizard, you get promoted to demi-god.
+If you need a wand of digging, kindly ask the minotaur.
+If you want to hit, use a dagger.
+If you want to rob a shop, train your dog.
+If you're lost, try buying a map next time you're in a shop.
+Inside a shop you better take a look at the price tags before buying anything.
+It is bad manners to use a wand in a shop.
+It is dangerous to visit a graveyard at midnight.
+It is not always a good idea to whistle for your dog.
+It is rumored that the Wizard has hired some help.
+It is the letter 'c' and not 'e' that changes status to statue.
+It might be a good idea to offer the unicorn a ruby.
+It would be peculiarly sad were your dog turned to stone.
+It's a `d' eats `d' world.
+Keep your armors away from rust.
+Keep your weaponry away from acids.
+Kill a unicorn of your color and you kill your luck.
+Leather is waterproof.  Ever see a cow with an umbrella?
+Leprechauns are the most skilled cutpurses in this dungeon.
+Lizard corpses protect against cockatrices.
+Money lost, little lost; honor lost, much lost; pluck lost, all lost.
+Most monsters can't swim.
+Music hath charms to affect the stubborn drawbridge.
+Music hath charms to soothe the savage beast.
+Never attack a guard.
+Never ride a long worm.
+Never use your best weapon to engrave a curse.
+No easy fighting with a heavy load!
+Nurses are trained to touch naked persons:  they don't harm them.
+Nymphs can unlink more than your chain mail.
+Once your little dog will be a big dog, and you will be proud of it.
+Only female monsters can lay eggs.
+Opening a tin is difficult, especially when you attempt it bare handed!
+Orcs and killer bees share their lifestyle.
+Orcs do not procreate in dark rooms.
+Plain nymphs are harmless.
+Playing AD&D may be helpful.
+Playing Gauntlet might be enlightening in some situations.
+Playing billiards pays when you are in a shop.
+Polymorphing a shopkeeper might make you safer.
+Polymorphing your dog probably makes you safer.
+Potions don't usually mix, but sometimes...
+Psst!  It's done with mirrors!
+Put on a ring of teleportation:  it will take you away from onslaught.
+Rays aren't boomerangs, of course, but still...
+Read the manual before entering the cave -- you might get killed otherwise.
+Reading Herbert might be enlightening in one case.
+Reading Tolkien might help you.
+Reading scrolls after drinking booze can give confusing results.
+Riding a dragon can be an uplifting experience.
+Rust monsters love water.  There are potions they hate, however.
+Sacks protect contents from temperatures up to 452 degrees fahrenheit.
+Scrolls fading?  It's not the heat, it's the humidity.
+Shopkeepers accept credit cards, as long as you pay cash.
+Shopkeepers can spot a tourist a mile away with those Hawaiian shirts.
+Shopkeepers can't tell identical twins apart.
+Shopkeepers don't read, so what use is engraving in a shop?
+Shopkeepers have incredible patience.
+Shopkeepers might raise their prices for tourists.
+Shopkeepers value money more than revenge.
+Some monsters can be tamed.  I once saw a hacker with a tame dragon!
+Someone once said that what goes up < might come down >.
+Someone's been spiking the pits!
+Sometimes monsters are more likely to fight each other than attack you.
+Spinach, carrot, and jelly -- a meal fit for a nurse!
+Tainted meat is even more sickening than poison!
+Telepathy is just a trick:  once you know how to do it, it's easy.
+The Leprechaun Gold Tru$t is no division of the Magic Memory Vault.
+The Wizard finds death to be quite an experience.
+The best equipment for your work is, of course, the most expensive.
+The gods don't appreciate pesky priesthood.
+The gods will get angry if you kill your dog.
+The magic marker is mightier than the sword.
+The moon is not the only heavenly body to influence this game.
+The orc swings his orcish broadsword named Elfrist at you.  You die...
+The secret of wands of Nothing Happens:  try again!
+There has always been something mystical about mirrors.
+There is a Mastermind deep in the dungeon.
+There is a big treasure hidden in the zoo!
+There is more magic in this cave than meets the eye.
+There is no harm in praising a large dog.
+There is nothing like eating a mimic.
+There once was a Knight named Lancelot who liked to ride with his lance a lot.
+They say a gelatinous cube can paralyze you...
+They say that Juiblex is afraid of a wand of digging.
+They say that Medusa would like to put you on a pedestal.
+They say that Vlad lives!!! ... in the mazes.
+They say that `Elbereth' is often written about.
+They say that a bag of holding can't hold everything.
+They say that a blessed tin of quasit meat is a quick meal.
+They say that a cat avoids traps.
+They say that a cave spider will occasionally eat cave spider eggs.
+They say that a clever wizard can have stats:  18/** 24 18 24 24 24.
+They say that a clove of garlic makes a good talisman if handled right.
+They say that a cursed scroll of teleportation could land you in trouble.
+They say that a diamond is another kind of luck stone.
+They say that a dog can be trained to fetch objects.
+They say that a gelatinous cube makes a healthy breakfast.
+They say that a giant gets strong by eating right, try it!
+They say that a grid bug won't hit you when you cross it.
+They say that a lembas wafer is a very light snack.
+They say that a loadstone has a strange attraction and is not bad luck.
+They say that a lock pick by any other name is still a lock pick.
+They say that a lucky amulet will block poisoned arrows.
+They say that a mirror will freeze a floating eye but you can still see it.
+They say that a neutral character might get Giantslayer.
+They say that a polymorph trap is magic and magic protection prevents it.
+They say that a potion of healing can cancel a potion of sickness.
+They say that a potion of monster detection sometimes works both ways.
+They say that a sink looks different from high above the floor.
+They say that a summoned demon could improve your game.
+They say that a tin of wraith meat is a rare dining experience.
+They say that a unicorn might bring you luck.
+They say that a wand of cancellation is like a wand of polymorph.
+They say that a wand of locking can close more than just doors.
+They say that a wand of polymorph can change your game.
+They say that a wizard is even more powerful the second time around.
+They say that a xorn knows of no obstacles when pursuing you.
+They say that abusing a credit card could shock you sooner or later.
+They say that amulets, like most things, can be deadly or life saving.
+They say that an altar can identify blessings.
+They say that an ooze will bite your boots and a rockmole will eat them.
+They say that an unlucky hacker was once killed by an exploding tin.
+They say that antique dealers are always interested in precious stones.
+They say that bandaging one's wounds helps to keep up one's appearance.
+They say that booze can be diluted but not cancelled.
+They say that by listening carefully, you can hear a secret door!
+They say that carrots and carrot juice may improve your vision.
+They say that cave spiders are not considered expensive health food.
+They say that demigods must leave behind their prized earthly possessions.
+They say that disturbing a djinni can be a costly mistake.
+They say that dragon scales can be quite enchanting.
+They say that dropping coins into a fountain will not grant you a wish.
+They say that dwarves lawfully mind their own business.
+They say that eating a bat corpse will make you batty, for a while.
+They say that eating a cram ration is a smart move.
+They say that eating blue jelly is cool if you don't fight the feeling.
+They say that escaping a dungeon is only the beginning of the end.
+They say that feeling an unexpected draft of air is sort of a breakthrough.
+They say that finding a cursed gray stone is always bad luck.
+They say that gaining a level is an experience that can raise your sights.
+They say that garter snake meat rarely tastes good but it's still healthy.
+They say that gauntlets of dexterity have a hidden enchanted touch.
+They say that going to heaven is just another way of escaping the dungeon.
+They say that golden nagas are law-abiding denizens as long as you are too.
+They say that gremlins can make you feel cooler than you are now.
+They say that grid bugs only exist in a strictly Cartesian sense.
+They say that hackers often feel jumpy about eating nymphs.
+They say that having polymorph control won't shock you.
+They say that if it's hard getting your food down another bite could kill.
+They say that if you don't wear glasses why bother with carrots?
+They say that if you notice a loose board beneath you, don't step on it.
+They say that if you start at the bottom the only place to go is up.
+They say that if you teleport to heaven you're presumed to be dead already.
+They say that in a shop you can be charged for old charges.
+They say that in lighter moments you could think of ways to pass a stone.
+They say that in the dungeon breaking a mirror can be seven years bad luck.
+They say that in the dungeon you don't usually have any luck at all.
+They say that in time a blessed luckstone can make your god happy.
+They say that it is easier to kill the Wizard than to make him stand still.
+They say that it only takes 1 zorkmid to meet the Kops.
+They say that it's a blast when you mix the right potions together.
+They say that it's not blind luck if you catch a glimpse of Medusa.
+They say that killing a shopkeeper brings bad luck.
+They say that monsters never step on a scare monster scroll.
+They say that most monsters find flute recitals extremely boring.
+They say that mummy corpses are not well preserved.
+They say that naturally a wand of wishing would be heavily guarded.
+They say that no one notices the junk underneath a boulder.
+They say that nobody expects a unicorn horn to rust.
+They say that nobody knows if an explorer can live forever.  Do you?
+They say that nothing can change the fact that some potions contain a djinni.
+They say that nothing can change the fact that some potions contain a ghost.
+They say that nymphs always fall for rock'n'roll, try it!
+They say that once an Olog-Hai is canned it never shows its face again.
+They say that once upon a time xans would never scratch your boots.
+They say that only an experienced wizard can do the tengu shuffle.
+They say that only chaotics can kill shopkeepers and get away with it.
+They say that only female monsters can lay eggs.
+They say that playing a horn really bad is really good.
+They say that rubbing a glowing potion does not make it a magic lamp.
+They say that scalpels become dull because they're not athames.
+They say that shopkeepers don't like pick-axes.
+They say that shopkeepers don't mind you bringing your pets in the shop.
+They say that shopkeepers don't usually mind if you sneak into a shop.
+They say that shopkeepers often have a large amount of money in their purses.
+They say that shopkeepers often remember things that you might forget.
+They say that sinks and armor don't mix, take your cloak off now!
+They say that sinks run hot and cold and many flavors in between.
+They say that snake charmers aren't charismatic, just musical.
+They say that soldiers are always prepared and usually protected.
+They say that some eggs could hatch in your pack, lucky or not.
+They say that some fire ants will make you a hot meal.
+They say that some horns play hot music and others are too cool for words.
+They say that some humanoids are nonetheless quite human.
+They say that some shopkeepers consider gems to be family heirlooms.
+They say that some shopkeepers recognize gems but they won't tell you.
+They say that some stones are much much heavier than others.
+They say that some yetis are full of hot air.
+They say that something very special would be in a well-protected place.
+They say that speed boots aren't fast enough to let you walk on water.
+They say that teleport traps are the devil's work.
+They say that tengu don't wear rings, why should you?
+They say that tengu never steal gold although they would be good at it.
+They say that that which was stolen once can be stolen again, ask any nymph.
+They say that the Delphic Oracle knows that lizard corpses aren't confusing.
+They say that the Hand of Elbereth can hold up your prayers.
+They say that the Leprechaun King is rich as Croesus.
+They say that the Wizard of Yendor is schizophrenic and suicidal.
+They say that the experienced character knows how to convert an altar.
+They say that the gods are happy when they drop objects at your feet.
+They say that the idea of invisible Nazguls has a certain ring to it.
+They say that the lady of the lake now lives in a fountain somewhere.
+They say that the local shopkeeper frowns upon the rude tourist.
+They say that the only door to the vampire's tower is on its lowest level.
+They say that the only good djinni is a grateful djinni.
+They say that the thing about genocide is that it works both ways.
+They say that the unicorn horn rule is if it ain't broke then don't fix it.
+They say that the view from a fog cloud is really very moving.
+They say that the walls in shops are made of extra hard material.
+They say that there are at least 15 ways to lose a pair of levitation boots.
+They say that throwing glass gems is the same as throwing rocks.
+They say that trespassing a boulder is probably beneath you.
+They say that unicorns are fond of precious gems.
+They say that prayer at an altar can sometimes make the water there holy.
+They say that what goes down the drain might come back up.
+They say that wielded, a long sword named Fire Brand makes you feel cooler.
+They say that wielded, a long sword named Frost Brand makes you hot stuff.
+They say that wiping its face is impossible for a floating eye.
+They say that with a floating eye you could see in the dark.
+They say that you are lucky if you can get a unicorn to catch a ruby.
+They say that you are what you eat.
+They say that you can find named weapons at an altar if you're lucky.
+They say that you can safely touch cockatrice eggs but why bother?
+They say that you can't break an amulet of reflection.
+They say that you don't always get what you wish for.
+They say that you should always be prepared for a final challenge.
+They say that you should ask a dwarf to let you into a locked shop.
+They say that you should pray for divine inspiration.
+They say that you should religiously give your gold away.
+They say that you will never get healthy by eating geckos.
+They say that zapping yourself with a wand of undead turning is stupid.
+They say the Wizard's castle is booby-trapped!
+They say the gods get angry if you kill your dog.
+They say the gods get angry if you pray too much.
+They say there is a powerful magic item hidden in a castle deep down!
+Those who wield a cockatrice corpse have a rocky road ahead of them.
+Throwing food at a wild dog might tame him.
+To a full belly all food is bad.
+Trolls are described as rubbery:  they keep bouncing back.
+Try the fall-back end-run play against ghosts.
+Try using your magic marker on wet scrolls.
+Two wrongs don't make a right, but three lefts do.
+Valkyries come from the north, and have commensurate abilities.
+Vampires hate garlic.
+Vault guards never disturb their Lords.
+Vegetarians enjoy lichen and seaweed.
+Visitors are requested not to apply genocide to shopkeepers.
+Watch out, the Wizard might come back.
+Water traps have no effect on dragons.
+What is a cockatrice going to eat when it gets hungry?
+Who needs an apron if they're made of glass?
+Why do you suppose they call them MAGIC markers?
+Why do you think they call them mercenaries?
+Why would anybody in his sane mind engrave "Elbereth"?
+Wishing too much may bring you too little.
+You can't bribe soldier ants.
+You can't leave a shop through the back door:  there isn't one!
+You may discover a fine spirit inside a potion bottle.
+You may want to dip into a potion of bottled blessings.
+You might be able to bribe a demon lord.
+You might trick a shopkeeper if you're invisible.
+You should certainly learn about quantum mechanics.
+You're going into the morgue at midnight???
+Your dog knows what to eat; maybe you should take lessons.
+Zap yourself and see what happens...
+Zapping a wand of undead turning might bring your dog back to life.
diff --git a/dat/sokoban.des b/dat/sokoban.des
new file mode 100644 (file)
index 0000000..2e1fd0e
--- /dev/null
@@ -0,0 +1,623 @@
+#      SCCS Id: @(#)sokoban.des        3.4     1999/03/15
+#      Copyright (c) 1998-1999 by Kevin Hugo
+# NetHack may be freely redistributed.  See license for details.
+#
+# In case you haven't played the game Sokoban, you'll learn
+# quickly.  This branch isn't particularly difficult, just time
+# consuming.  Some players may wish to skip this branch.
+#
+# The following actions are currently permitted without penalty:
+#   Carrying or throwing a boulder already in inventory
+#     (player or nonplayer).
+#   Teleporting boulders.
+#   Digging in the floor.
+# The following actions are permitted, but with a luck penalty:
+#   Breaking boulders.
+#   Stone-to-fleshing boulders.
+#   Creating new boulders (e.g., with a scroll of earth).
+#   Jumping.
+#   Being pulled by a thrown iron ball.
+#   Hurtling through the air from Newton's 3rd law.
+#   Squeezing past boulders when naked or as a giant.
+# These actions are not permitted:
+#   Moving diagonally between two boulders and/or walls.
+#   Pushing a boulder diagonally.
+#   Picking up boulders (player or nonplayer).
+#   Digging or walking through walls.
+#   Teleporting within levels or between levels of this branch.
+#   Using cursed potions of gain level.
+#   Escaping a pit/hole (e.g., by flying, levitation, or
+#     passing a dexterity check).
+#   Bones files are not permitted.
+
+
+### Bottom (first) level of Sokoban ###
+MAZE:"soko4-1",' '
+FLAGS:noteleport,hardfloor
+GEOMETRY:center,center
+#12345678901234567890123456789012345678901234567890
+MAP
+------  ----- 
+|....|  |...| 
+|....----...| 
+|...........| 
+|..|-|.|-|..| 
+---------|.---
+|......|.....|
+|..----|.....|
+--.|   |.....|
+ |.|---|.....|
+ |...........|
+ |..|---------
+ ----         
+ENDMAP
+BRANCH:(06,04,06,04),(0,0,0,0)
+STAIR:(06,06),up
+REGION:(00,00,13,12),lit,"ordinary"
+NON_DIGGABLE:(00,00,13,12)
+NON_PASSWALL:(00,00,13,12)
+
+# Boulders
+OBJECT:'`',"boulder",(02,02)
+OBJECT:'`',"boulder",(02,03)
+#
+OBJECT:'`',"boulder",(10,02)
+OBJECT:'`',"boulder",(09,03)
+OBJECT:'`',"boulder",(10,04)
+#
+OBJECT:'`',"boulder",(08,07)
+OBJECT:'`',"boulder",(09,08)
+OBJECT:'`',"boulder",(09,09)
+OBJECT:'`',"boulder",(08,10)
+OBJECT:'`',"boulder",(10,10)
+
+# Traps
+TRAP:"pit",(03,06)
+TRAP:"pit",(04,06)
+TRAP:"pit",(05,06)
+TRAP:"pit",(02,08)
+TRAP:"pit",(02,09)
+TRAP:"pit",(04,10)
+TRAP:"pit",(05,10)
+TRAP:"pit",(06,10)
+TRAP:"pit",(07,10)
+
+# A little help
+OBJECT:'?',"earth",(02,11)
+OBJECT:'?',"earth",(03,11)
+
+# Random objects
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'=',random,random
+OBJECT:'/',random,random
+
+
+MAZE:"soko4-2",' '
+FLAGS:noteleport,hardfloor
+GEOMETRY:center,center
+#12345678901234567890123456789012345678901234567890
+MAP
+-------- ------
+|.|....|-|....|
+|.|-..........|
+|.||....|.....|
+|.||....|.....|
+|.|-----|.-----
+|.|    |......|
+|.-----|......|
+|.............|
+|..|---|......|
+----   --------
+ENDMAP
+BRANCH:(03,01,03,01),(0,0,0,0)
+STAIR:(01,01),up
+REGION:(00,00,14,10),lit,"ordinary"
+NON_DIGGABLE:(00,00,14,10)
+NON_PASSWALL:(00,00,14,10)
+
+# Boulders
+OBJECT:'`',"boulder",(05,02)
+OBJECT:'`',"boulder",(06,02)
+OBJECT:'`',"boulder",(06,03)
+OBJECT:'`',"boulder",(07,03)
+#
+OBJECT:'`',"boulder",(09,05)
+OBJECT:'`',"boulder",(10,03)
+OBJECT:'`',"boulder",(11,02)
+OBJECT:'`',"boulder",(12,03)
+#
+OBJECT:'`',"boulder",(07,08)
+OBJECT:'`',"boulder",(08,08)
+OBJECT:'`',"boulder",(09,08)
+OBJECT:'`',"boulder",(10,08)
+
+# Traps
+TRAP:"pit",(01,02)
+TRAP:"pit",(01,03)
+TRAP:"pit",(01,04)
+TRAP:"pit",(01,05)
+TRAP:"pit",(01,06)
+TRAP:"pit",(01,07)
+TRAP:"pit",(03,08)
+TRAP:"pit",(04,08)
+TRAP:"pit",(05,08)
+TRAP:"pit",(06,08)
+
+# A little help
+OBJECT:'?',"earth",(01,09)
+OBJECT:'?',"earth",(02,09)
+
+# Random objects
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'=',random,random
+OBJECT:'/',random,random
+
+
+### Second level ###
+MAZE:"soko3-1",' '
+FLAGS:noteleport
+GEOMETRY:center,center
+#12345678901234567890123456789012345678901234567890
+MAP
+-----------       -----------
+|....|....|--     |.........|
+|....|......|     |.........|
+|.........|--     |.........|
+|....|....|       |.........|
+|-.---------      |.........|
+|....|.....|      |.........|
+|....|.....|      |.........|
+|..........|      |.........|
+|....|.....|---------------+|
+|....|......................|
+-----------------------------
+ENDMAP
+STAIR:(11,02),down
+STAIR:(23,04),up
+DOOR:locked,(27,09)
+REGION:(00,00,28,11),lit,"ordinary"
+NON_DIGGABLE:(00,00,28,11)
+NON_PASSWALL:(00,00,28,11)
+
+# Boulders
+OBJECT:'`',"boulder",(03,02)
+OBJECT:'`',"boulder",(04,02)
+#
+OBJECT:'`',"boulder",(06,02)
+OBJECT:'`',"boulder",(06,03)
+OBJECT:'`',"boulder",(07,02)
+#
+OBJECT:'`',"boulder",(03,06)
+OBJECT:'`',"boulder",(02,07)
+OBJECT:'`',"boulder",(03,07)
+OBJECT:'`',"boulder",(03,08)
+OBJECT:'`',"boulder",(02,09)
+OBJECT:'`',"boulder",(03,09)
+OBJECT:'`',"boulder",(04,09)
+#
+OBJECT:'`',"boulder",(06,07)
+OBJECT:'`',"boulder",(06,09)
+OBJECT:'`',"boulder",(08,07)
+OBJECT:'`',"boulder",(08,10)
+OBJECT:'`',"boulder",(09,08)
+OBJECT:'`',"boulder",(09,09)
+OBJECT:'`',"boulder",(10,07)
+OBJECT:'`',"boulder",(10,10)
+
+# Traps
+TRAP:"hole",(12,10)
+TRAP:"hole",(13,10)
+TRAP:"hole",(14,10)
+TRAP:"hole",(15,10)
+TRAP:"hole",(16,10)
+TRAP:"hole",(17,10)
+TRAP:"hole",(18,10)
+TRAP:"hole",(19,10)
+TRAP:"hole",(20,10)
+TRAP:"hole",(21,10)
+TRAP:"hole",(22,10)
+TRAP:"hole",(23,10)
+TRAP:"hole",(24,10)
+TRAP:"hole",(25,10)
+TRAP:"hole",(26,10)
+
+# Random objects
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'=',random,random
+OBJECT:'/',random,random
+
+
+MAZE:"soko3-2",' '
+FLAGS:noteleport
+GEOMETRY:center,center
+#12345678901234567890123456789012345678901234567890
+MAP
+ ----          -----------
+-|..|-------   |.........|
+|..........|   |.........|
+|..-----.-.|   |.........|
+|..|...|...|   |.........|
+|.........-|   |.........|
+|.......|..|   |.........|
+|.----..--.|   |.........|
+|........|.--  |.........|
+|.---.-.....------------+|
+|...|...-................|
+|.........----------------
+----|..|..|               
+    -------               
+ENDMAP
+STAIR:(03,01),down
+STAIR:(20,04),up
+DOOR:locked,(24,09)
+REGION:(00,00,25,13),lit,"ordinary"
+NON_DIGGABLE:(00,00,25,13)
+NON_PASSWALL:(00,00,25,13)
+
+# Boulders
+OBJECT:'`',"boulder",(02,03)
+OBJECT:'`',"boulder",(08,03)
+OBJECT:'`',"boulder",(09,04)
+OBJECT:'`',"boulder",(02,05)
+OBJECT:'`',"boulder",(04,05)
+OBJECT:'`',"boulder",(09,05)
+OBJECT:'`',"boulder",(02,06)
+OBJECT:'`',"boulder",(05,06)
+OBJECT:'`',"boulder",(06,07)
+OBJECT:'`',"boulder",(03,08)
+OBJECT:'`',"boulder",(07,08)
+OBJECT:'`',"boulder",(05,09)
+OBJECT:'`',"boulder",(10,09)
+OBJECT:'`',"boulder",(07,10)
+OBJECT:'`',"boulder",(10,10)
+OBJECT:'`',"boulder",(03,11)
+
+# Traps
+TRAP:"hole",(12,10)
+TRAP:"hole",(13,10)
+TRAP:"hole",(14,10)
+TRAP:"hole",(15,10)
+TRAP:"hole",(16,10)
+TRAP:"hole",(17,10)
+TRAP:"hole",(18,10)
+TRAP:"hole",(19,10)
+TRAP:"hole",(20,10)
+TRAP:"hole",(21,10)
+TRAP:"hole",(22,10)
+TRAP:"hole",(23,10)
+
+# Random objects
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'=',random,random
+OBJECT:'/',random,random
+
+
+### Third level ###
+MAZE:"soko2-1",' '
+FLAGS:noteleport
+GEOMETRY:center,center
+#12345678901234567890123456789012345678901234567890
+MAP
+--------------------
+|........|...|.....|
+|.....-..|.-.|.....|
+|..|.....|...|.....|
+|-.|..-..|.-.|.....|
+|...--.......|.....|
+|...|...-...-|.....|
+|...|..|...--|.....|
+|-..|..|----------+|
+|..................|
+|...|..|------------
+--------            
+ENDMAP
+STAIR:(06,10),down
+STAIR:(16,04),up
+DOOR:locked,(18,08)
+REGION:(00,00,19,11),lit,"ordinary"
+NON_DIGGABLE:(00,00,19,11)
+NON_PASSWALL:(00,00,19,11)
+
+# Boulders
+OBJECT:'`',"boulder",(02,02)
+OBJECT:'`',"boulder",(03,02)
+#
+OBJECT:'`',"boulder",(05,03)
+OBJECT:'`',"boulder",(07,03)
+OBJECT:'`',"boulder",(07,02)
+OBJECT:'`',"boulder",(08,02)
+#
+OBJECT:'`',"boulder",(10,03)
+OBJECT:'`',"boulder",(11,03)
+#
+OBJECT:'`',"boulder",(02,07)
+OBJECT:'`',"boulder",(02,08)
+OBJECT:'`',"boulder",(03,09)
+#
+OBJECT:'`',"boulder",(05,07)
+OBJECT:'`',"boulder",(06,06)
+
+# Traps
+TRAP:"hole",(08,09)
+TRAP:"hole",(09,09)
+TRAP:"hole",(10,09)
+TRAP:"hole",(11,09)
+TRAP:"hole",(12,09)
+TRAP:"hole",(13,09)
+TRAP:"hole",(14,09)
+TRAP:"hole",(15,09)
+TRAP:"hole",(16,09)
+TRAP:"hole",(17,09)
+
+# Random objects
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'=',random,random
+OBJECT:'/',random,random
+
+
+MAZE:"soko2-2",' '
+FLAGS:noteleport
+GEOMETRY:center,center
+#12345678901234567890123456789012345678901234567890
+MAP
+  --------          
+--|.|....|          
+|........|----------
+|.-...-..|.|.......|
+|...-......|.......|
+|.-....|...|.......|
+|....-.--.-|.......|
+|..........|.......|
+|.--...|...|.......|
+|....-.|---|.......|
+--|....|----------+|
+  |................|
+  ------------------
+ENDMAP
+STAIR:(06,11),down
+STAIR:(15,06),up
+DOOR:locked,(18,10)
+REGION:(00,00,19,12),lit,"ordinary"
+NON_DIGGABLE:(00,00,19,12)
+NON_PASSWALL:(00,00,19,12)
+
+# Boulders
+OBJECT:'`',"boulder",(04,02)
+OBJECT:'`',"boulder",(04,03)
+OBJECT:'`',"boulder",(05,03)
+OBJECT:'`',"boulder",(07,03)
+OBJECT:'`',"boulder",(08,03)
+OBJECT:'`',"boulder",(02,04)
+OBJECT:'`',"boulder",(03,04)
+OBJECT:'`',"boulder",(05,05)
+OBJECT:'`',"boulder",(06,06)
+OBJECT:'`',"boulder",(09,06)
+OBJECT:'`',"boulder",(03,07)
+OBJECT:'`',"boulder",(04,07)
+OBJECT:'`',"boulder",(07,07)
+OBJECT:'`',"boulder",(06,09)
+OBJECT:'`',"boulder",(05,10)
+OBJECT:'`',"boulder",(05,11)
+
+# Traps
+TRAP:"hole",(07,11)
+TRAP:"hole",(08,11)
+TRAP:"hole",(09,11)
+TRAP:"hole",(10,11)
+TRAP:"hole",(11,11)
+TRAP:"hole",(12,11)
+TRAP:"hole",(13,11)
+TRAP:"hole",(14,11)
+TRAP:"hole",(15,11)
+TRAP:"hole",(16,11)
+TRAP:"hole",(17,11)
+
+# Random objects
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'=',random,random
+OBJECT:'/',random,random
+
+
+### Top (last) level of Sokoban ###
+MAZE:"soko1-1",' '
+FLAGS:noteleport
+GEOMETRY:center,center
+#12345678901234567890123456789012345678901234567890
+MAP
+--------------------------
+|........................|
+|.......|---------------.|
+-------.------         |.|
+ |...........|         |.|
+ |...........|         |.|
+--------.-----         |.|
+|............|         |.|
+|............|         |.|
+-----.--------   ------|.|
+ |..........|  --|.....|.|
+ |..........|  |.+.....|.|
+ |.........|-  |-|.....|.|
+-------.----   |.+.....+.|
+|........|     |-|.....|--
+|........|     |.+.....|  
+|...|-----     --|.....|  
+-----            -------  
+ENDMAP
+RANDOM_PLACES:(16,11),(16,13),(16,15)
+STAIR:(01,01),down
+REGION:(00,00,25,17),lit,"ordinary"
+NON_DIGGABLE:(00,00,25,17)
+NON_PASSWALL:(00,00,25,17)
+
+# Boulders
+OBJECT:'`',"boulder",(03,05)
+OBJECT:'`',"boulder",(05,05)
+OBJECT:'`',"boulder",(07,05)
+OBJECT:'`',"boulder",(09,05)
+OBJECT:'`',"boulder",(11,05)
+#
+OBJECT:'`',"boulder",(04,07)
+OBJECT:'`',"boulder",(04,08)
+OBJECT:'`',"boulder",(06,07)
+OBJECT:'`',"boulder",(09,07)
+OBJECT:'`',"boulder",(11,07)
+#
+OBJECT:'`',"boulder",(03,12)
+OBJECT:'`',"boulder",(04,10)
+OBJECT:'`',"boulder",(05,12)
+OBJECT:'`',"boulder",(06,10)
+OBJECT:'`',"boulder",(07,11)
+OBJECT:'`',"boulder",(08,10)
+OBJECT:'`',"boulder",(09,12)
+#
+OBJECT:'`',"boulder",(03,14)
+
+# Traps
+TRAP:"hole",(08,01)
+TRAP:"hole",(09,01)
+TRAP:"hole",(10,01)
+TRAP:"hole",(11,01)
+TRAP:"hole",(12,01)
+TRAP:"hole",(13,01)
+TRAP:"hole",(14,01)
+TRAP:"hole",(15,01)
+TRAP:"hole",(16,01)
+TRAP:"hole",(17,01)
+TRAP:"hole",(18,01)
+TRAP:"hole",(19,01)
+TRAP:"hole",(20,01)
+TRAP:"hole",(21,01)
+TRAP:"hole",(22,01)
+TRAP:"hole",(23,01)
+
+MONSTER:'m',"giant mimic", random, m_object "boulder"
+MONSTER:'m',"giant mimic", random, m_object "boulder"
+
+# Random objects
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'=',random,random
+OBJECT:'/',random,random
+
+# Rewards
+DOOR:locked,(23,13)
+DOOR:closed,(17,11)
+DOOR:closed,(17,13)
+DOOR:closed,(17,15)
+REGION:(18,10,22,16),lit,"zoo",filled,true
+OBJECT:'(',"bag of holding",place[0]
+ENGRAVING:place[0],burn,"Elbereth"
+
+
+MAZE:"soko1-2",' '
+FLAGS:noteleport
+GEOMETRY:center,center
+#12345678901234567890123456789012345678901234567890
+MAP
+  ------------------------
+  |......................|
+  |..-------------------.|
+----.|    -----        |.|
+|..|.--  --...|        |.|
+|.....|--|....|        |.|
+|.....|..|....|        |.|
+--....|......--        |.|
+ |.......|...|   ------|.|
+ |....|..|...| --|.....|.|
+ |....|--|...| |.+.....|.|
+ |.......|..-- |-|.....|.|
+ ----....|.--  |.+.....+.|
+    ---.--.|   |-|.....|--
+     |.....|   |.+.....|  
+     |..|..|   --|.....|  
+     -------     -------  
+ENDMAP
+RANDOM_PLACES:(16,10),(16,12),(16,14)
+STAIR:(06,15),down
+REGION:(00,00,25,16),lit,"ordinary"
+NON_DIGGABLE:(00,00,25,16)
+NON_PASSWALL:(00,00,25,16)
+
+# Boulders
+OBJECT:'`',"boulder",(04,04)
+OBJECT:'`',"boulder",(02,06)
+OBJECT:'`',"boulder",(03,06)
+OBJECT:'`',"boulder",(04,07)
+OBJECT:'`',"boulder",(05,07)
+OBJECT:'`',"boulder",(02,08)
+OBJECT:'`',"boulder",(05,08)
+OBJECT:'`',"boulder",(03,09)
+OBJECT:'`',"boulder",(04,09)
+OBJECT:'`',"boulder",(03,10)
+OBJECT:'`',"boulder",(05,10)
+OBJECT:'`',"boulder",(06,12)
+#
+OBJECT:'`',"boulder",(07,14)
+#
+OBJECT:'`',"boulder",(11,05)
+OBJECT:'`',"boulder",(12,06)
+OBJECT:'`',"boulder",(10,07)
+OBJECT:'`',"boulder",(11,07)
+OBJECT:'`',"boulder",(10,08)
+OBJECT:'`',"boulder",(12,09)
+OBJECT:'`',"boulder",(11,10)
+
+# Traps
+TRAP:"hole",(05,01)
+TRAP:"hole",(06,01)
+TRAP:"hole",(07,01)
+TRAP:"hole",(08,01)
+TRAP:"hole",(09,01)
+TRAP:"hole",(10,01)
+TRAP:"hole",(11,01)
+TRAP:"hole",(12,01)
+TRAP:"hole",(13,01)
+TRAP:"hole",(14,01)
+TRAP:"hole",(15,01)
+TRAP:"hole",(16,01)
+TRAP:"hole",(17,01)
+TRAP:"hole",(18,01)
+TRAP:"hole",(19,01)
+TRAP:"hole",(20,01)
+TRAP:"hole",(21,01)
+TRAP:"hole",(22,01)
+
+MONSTER:'m',"giant mimic", random, m_object "boulder"
+MONSTER:'m',"giant mimic", random, m_object "boulder"
+
+# Random objects
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'%',random,random
+OBJECT:'=',random,random
+OBJECT:'/',random,random
+
+# Rewards
+DOOR:locked,(23,12)
+DOOR:closed,(17,10)
+DOOR:closed,(17,12)
+DOOR:closed,(17,14)
+REGION:(18,09,22,15),lit,"zoo",filled,true
+OBJECT:'"',"amulet of reflection",place[0]
+ENGRAVING:place[0],burn,"Elbereth"
diff --git a/dat/tower.des b/dat/tower.des
new file mode 100644 (file)
index 0000000..f5cc292
--- /dev/null
@@ -0,0 +1,136 @@
+#      SCCS Id: @(#)tower.des  3.4     1990/02/26
+#      Copyright (c) 1989 by Jean-Christophe Collet
+# NetHack may be freely redistributed.  See license for details.
+#
+# Upper stage of Vlad's tower
+MAZE:"tower1",' '
+FLAGS: noteleport,hardfloor
+GEOMETRY:half-left,center
+MAP
+  --- --- ---  
+  |.| |.| |.|  
+---S---S---S---
+|.......+.+...|
+---+-----.-----
+  |...\.|.+.|  
+---+-----.-----
+|.......+.+...|
+---S---S---S---
+  |.| |.| |.|  
+  --- --- ---  
+ENDMAP
+LADDER:(11,05),down
+# The lord and his court
+MONSTER:'V',"Vlad the Impaler",(06,05)
+MONSTER:'V',random,(03,09)
+MONSTER:'V',random,(07,09)
+MONSTER:'V',random,(11,09)
+MONSTER:'V',random,(03,01)
+MONSTER:'V',random,(07,01)
+MONSTER:'V',random,(11,01)
+# The doors
+DOOR:closed,(08,03)
+DOOR:closed,(10,03)
+DOOR:closed,(03,04)
+DOOR:locked,(10,05)
+DOOR:locked,(08,07)
+DOOR:locked,(10,07)
+DOOR:closed,(03,06)
+# treasures
+OBJECT:'(',"chest",(07,05)
+OBJECT:'(',"chest",(03,09)
+OBJECT:'(',"chest",(07,09)
+OBJECT:'(',"chest",(11,09)
+OBJECT:'(',"chest",(03,01)
+OBJECT:'(',"chest",(07,01)
+OBJECT:'(',"chest",(11,01)
+# We have to protect the tower against outside attacks
+NON_DIGGABLE:(00,00,14,10)
+
+
+# Intermediate stage of Vlad's tower
+MAZE:"tower2",' '
+FLAGS: noteleport,hardfloor
+GEOMETRY:half-left,center
+MAP
+  --- --- ---  
+  |.| |.| |.|  
+---S---S---S---
+|.S.........S.|
+---.------+----
+  |......|..|  
+--------.------
+|.S......+..S.|
+---S---S---S---
+  |.| |.| |.|  
+  --- --- ---  
+ENDMAP
+# Random places are the 10 niches
+RANDOM_PLACES:(03,01),(07,01),(11,01),(01,03),(13,03),
+             (01,07),(13,07),(03,09),(07,09),(11,09)
+LADDER:(11,05),up
+LADDER:(03,07),down
+DOOR:locked,(10,04)
+DOOR:locked,(09,07)
+MONSTER:'&',random,place[0]
+MONSTER:'&',random,place[1]
+MONSTER:'d',"hell hound pup",place[2]
+MONSTER:'d',"hell hound pup",place[3]
+MONSTER:'d',"winter wolf",place[4]
+CONTAINER:'(',"chest",place[5]
+OBJECT:'"',"amulet of life saving",contained
+CONTAINER:'(',"chest",place[6]
+OBJECT:'"',"amulet of strangulation",contained
+OBJECT:'[',"water walking boots",place[7]
+OBJECT:'[',"crystal plate mail",place[8]
+OBJECT:'+',"invisibility",place[9]
+# Walls in the tower are non diggable
+NON_DIGGABLE:(00,00,14,10)
+
+
+# Bottom most stage of Vlad's tower
+MAZE:"tower3",' '
+FLAGS: noteleport,hardfloor
+GEOMETRY:half-left,center
+MAP
+    --- --- ---  
+    |.| |.| |.|    
+  ---S---S---S---
+  |.S.........S.|  
+-----.........-----
+|...|.........+...|
+|.---.........---.|
+|.|.S.........S.|.|
+|.---S---S---S---.|
+|...|.|.|.|.|.|...|
+---.---.---.---.---
+  |.............|  
+  ---------------  
+ENDMAP
+# Random places are the 10 niches
+RANDOM_PLACES:(05,01),(09,01),(13,01),(03,03),(15,03),
+             (03,07),(15,07),(05,09),(09,09),(13,09)
+BRANCH:(02,05,02,05),(00,00,00,00)
+LADDER:(05,07),up
+# Entry door is, of course, locked
+DOOR:locked,(14,05)
+# Let's put a dragon behind the door, just for the fun...
+MONSTER:'D',random,(13,05)
+MONSTER:random,random,(12,04)
+MONSTER:random,random,(12,06)
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+MONSTER:random,random,random
+OBJECT:')',"long sword",place[0]
+TRAP:random,place[0]
+OBJECT:'(',"lock pick",place[1]
+TRAP:random,place[1]
+OBJECT:'[',"elven cloak",place[2]
+TRAP:random,place[2]
+OBJECT:'(',"blindfold",place[3]
+TRAP:random,place[3]
+# Walls in the tower are non diggable
+NON_DIGGABLE:(00,00,18,12)
diff --git a/dat/wizhelp b/dat/wizhelp
new file mode 100644 (file)
index 0000000..6b38bc8
--- /dev/null
@@ -0,0 +1,23 @@
+Debug-Mode Quick Reference:
+
+^E  ==  detect secret doors and traps.
+^F  ==  do magic mapping.
+^G  ==  create monster.
+^I  ==  identify items in pack.
+^O  ==  tell locations of special levels.
+^T  ==  do intra-level teleport.
+^V  ==  do trans-level teleport.
+^W  ==  make wish.
+^X  ==  show attributes including intrinsic attributes.
+
+#levelchange == change experience level
+#lightsources == show mobile light sources
+#monpolycontrol == control monster polymorphs
+#panic == panic test
+#polyself == polymorph self
+#seenv == show seen vectors
+#stats == show memory statistics
+#timeout == look at timeout queue
+#vision == show vision array
+#wmode == show wall modes
+
diff --git a/dat/yendor.des b/dat/yendor.des
new file mode 100644 (file)
index 0000000..8583457
--- /dev/null
@@ -0,0 +1,276 @@
+#      SCCS Id: @(#)yendor.des 3.4     1996/10/20
+#      Copyright (c) 1989 by Jean-Christophe Collet
+#      Copyright (c) 1992 by M. Stephenson and Izchak Miller
+# NetHack may be freely redistributed.  See license for details.
+#
+# The top (real) wizard level.
+# Keeping the Moat for old-time's sake
+MAZE:"wizard1",random
+FLAGS:noteleport,hardfloor
+GEOMETRY:center,center
+MAP
+----------------------------.
+|.......|..|.........|.....|.
+|.......S..|.}}}}}}}.|.....|.
+|..--S--|..|.}}---}}.|---S-|.
+|..|....|..|.}--.--}.|..|..|.
+|..|....|..|.}|...|}.|..|..|.
+|..--------|.}--.--}.|..|..|.
+|..|.......|.}}---}}.|..|..|.
+|..S.......|.}}}}}}}.|..|..|.
+|..|.......|.........|..|..|.
+|..|.......|-----------S-S-|.
+|..|.......S...............|.
+----------------------------.
+ENDMAP
+STAIR:levregion(01,00,79,20),(0,0,28,12),up
+STAIR:levregion(01,00,79,20),(0,0,28,12),down
+BRANCH:levregion(01,00,79,20),(0,0,28,12)
+TELEPORT_REGION:levregion(01,00,79,20),(0,0,27,12)
+# Make it a morgue for rm id in mkmaze.c
+# for the purpose of random sdoor placement
+REGION:(12,01,20,09),unlit,"morgue",unfilled
+MAZEWALK:(28,05),east
+LADDER:(06,05),down
+# Non diggable walls
+# Walls inside the moat stay diggable
+NON_DIGGABLE:(00,00,11,12)
+NON_DIGGABLE:(11,00,21,00)
+NON_DIGGABLE:(11,10,27,12)
+NON_DIGGABLE:(21,00,27,10)
+# Non passable walls
+NON_PASSWALL:(00,00,11,12)
+NON_PASSWALL:(11,00,21,00)
+NON_PASSWALL:(11,10,27,12)
+NON_PASSWALL:(21,00,27,10)
+# The wizard and his guards
+MONSTER:'@',"Wizard of Yendor",(16,05),asleep
+MONSTER:'d',"hell hound",(15,05)
+MONSTER:'V',"vampire lord",(17,05)
+# The local treasure
+OBJECT:'+',"Book of the Dead",(16,05)
+# Surrounding terror
+MONSTER:';',"kraken",(14,02)
+MONSTER:';',"giant eel",(17,02)
+MONSTER:';',"kraken",(13,04)
+MONSTER:';',"giant eel",(13,06)
+MONSTER:';',"kraken",(19,04)
+MONSTER:';',"giant eel",(19,06)
+MONSTER:';',"kraken",(15,08)
+MONSTER:';',"giant eel",(17,08)
+MONSTER:';',"piranha",(15,02)
+MONSTER:';',"piranha",(19,08)
+# Random monsters
+MONSTER:'D',random,random
+MONSTER:'H',random,random
+MONSTER:'&',random,random
+MONSTER:'&',random,random
+MONSTER:'&',random,random
+MONSTER:'&',random,random
+# And to make things a little harder.
+TRAP:"board",(16,04)
+TRAP:"board",(16,06)
+TRAP:"board",(15,05)
+TRAP:"board",(17,05)
+# Random traps.
+TRAP:"spiked pit",random
+TRAP:"sleep gas",random
+TRAP:"anti magic",random
+TRAP:"magic",random
+# Some random loot.
+OBJECT:'*',"ruby",random
+OBJECT:'!',random,random
+OBJECT:'!',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'+',random,random
+OBJECT:'+',random,random
+OBJECT:'+',random,random
+
+
+# The middle wizard level.
+MAZE:"wizard2",random
+FLAGS:noteleport,hardfloor
+GEOMETRY:center,center
+MAP
+----------------------------.
+|.....|.S....|.............|.
+|.....|.-------S--------S--|.
+|.....|.|.........|........|.
+|..-S--S|.........|........|.
+|..|....|.........|------S-|.
+|..|....|.........|.....|..|.
+|-S-----|.........|.....|..|.
+|.......|.........|S--S--..|.
+|.......|.........|.|......|.
+|-----S----S-------.|......|.
+|............|....S.|......|.
+----------------------------.
+ENDMAP
+STAIR:levregion(01,00,79,20),(0,0,28,12),up
+STAIR:levregion(01,00,79,20),(0,0,28,12),down
+BRANCH:levregion(01,00,79,20),(0,0,28,12)
+TELEPORT_REGION:levregion(01,00,79,20),(0,0,27,12)
+REGION:(09,03,17,09),unlit,"zoo"
+DOOR:closed,(15,02)
+DOOR:closed,(11,10)
+MAZEWALK:(28,05),east
+LADDER:(12,01),up
+LADDER:(14,11),down
+# Non diggable walls everywhere
+NON_DIGGABLE:(00,00,27,12)
+#
+NON_PASSWALL:(00,00,06,12)
+NON_PASSWALL:(06,00,27,02)
+NON_PASSWALL:(16,02,27,12)
+NON_PASSWALL:(06,12,16,12)
+# Random traps.
+TRAP:"spiked pit",random
+TRAP:"sleep gas",random
+TRAP:"anti magic",random
+TRAP:"magic",random
+# Some random loot.
+OBJECT:'!',random,random
+OBJECT:'!',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'+',random,random
+# treasures
+OBJECT:'"',random,(04,06)
+
+
+# The bottom wizard level.
+# Memorialize the fakewiz setup.
+MAZE:"wizard3",random
+FLAGS:noteleport,hardfloor
+GEOMETRY:center,center
+MAP
+----------------------------.
+|..|............S..........|.
+|..|..------------------S--|.
+|..|..|.........|..........|.
+|..S..|.}}}}}}}.|..........|.
+|..|..|.}}---}}.|-S--------|.
+|..|..|.}--.--}.|..|.......|.
+|..|..|.}|...|}.|..|.......|.
+|..---|.}--.--}.|..|.......|.
+|.....|.}}---}}.|..|.......|.
+|.....S.}}}}}}}.|..|.......|.
+|.....|.........|..S.......|.
+----------------------------.
+ENDMAP
+STAIR:levregion(01,00,79,20),(0,0,28,12),up
+STAIR:levregion(01,00,79,20),(0,0,28,12),down
+BRANCH:levregion(01,00,79,20),(0,0,28,12)
+TELEPORT_REGION:levregion(01,00,79,20),(0,0,27,12)
+PORTAL:(25,11,25,11),(0,0,0,0),"fakewiz1"
+MAZEWALK:(28,09),east
+REGION:(07,03,15,11),unlit,"morgue",unfilled
+REGION:(17,06,18,11),unlit,"beehive"
+# make the entry chamber a real room; it affects monster arrival;
+# `unfilled' is a kludge to force an ordinary room to remain a room
+REGION:(20,06,26,11),unlit,"ordinary",unfilled
+DOOR:closed,(18,05)
+DOOR:closed,(19,11)
+LADDER:(11,07),up
+# Non diggable walls
+# Walls inside the moat stay diggable
+NON_DIGGABLE:(00,00,06,12)
+NON_DIGGABLE:(06,00,27,02)
+NON_DIGGABLE:(16,02,27,12)
+NON_DIGGABLE:(06,12,16,12)
+#
+NON_PASSWALL:(00,00,06,12)
+NON_PASSWALL:(06,00,27,02)
+NON_PASSWALL:(16,02,27,12)
+NON_PASSWALL:(06,12,16,12)
+#
+MONSTER:'L',random,(10,07)
+MONSTER:'V',"vampire lord",(12,07)
+# Some surrounding horrors
+MONSTER:';',"kraken",(08,05)
+MONSTER:';',"giant eel",(08,08)
+MONSTER:';',"kraken",(14,05)
+MONSTER:';',"giant eel",(14,08)
+# Other monsters
+MONSTER:'L',random,random
+MONSTER:'D',random,random
+MONSTER:'D',random,(26,09)
+MONSTER:'&',random,random
+MONSTER:'&',random,random
+MONSTER:'&',random,random
+# And to make things a little harder.
+TRAP:"board",(10,07)
+TRAP:"board",(12,07)
+TRAP:"board",(11,06)
+TRAP:"board",(11,08)
+# Some loot
+OBJECT:')',random,random
+OBJECT:'!',random,random
+OBJECT:'?',random,random
+OBJECT:'?',random,random
+OBJECT:'(',random,random
+# treasures
+OBJECT:'"',random,(11,07)
+
+
+# The former decoy wizard levels.
+# There are two of these, and we need to
+# distinguish between them for the portal.
+MAZE:"fakewiz1",random
+GEOMETRY:center,center
+MAP
+.........
+.}}}}}}}.
+.}}---}}.
+.}--.--}.
+.}|...|}.
+.}--.--}.
+.}}---}}.
+.}}}}}}}.
+ENDMAP
+STAIR:levregion(01,00,79,20),(0,0,8,7),up
+STAIR:levregion(01,00,79,20),(0,0,8,7),down
+BRANCH:levregion(01,00,79,20),(0,0,8,7)
+TELEPORT_REGION:levregion(01,00,79,20),(2,2,6,6)
+PORTAL:(4,4,4,4),(0,0,0,0),"wizard3"
+MAZEWALK:(08,05),east
+REGION:(04,03,06,06),unlit,"ordinary",unfilled,true
+MONSTER:'L',random,(04,04)
+MONSTER:'V',"vampire lord",(03,04)
+MONSTER:';',"kraken",(06,06)
+# And to make things a little harder.
+TRAP:"board",(04,03)
+TRAP:"board",(04,05)
+TRAP:"board",(03,04)
+TRAP:"board",(05,04)
+
+
+MAZE:"fakewiz2",random
+GEOMETRY:center,center
+MAP
+.........
+.}}}}}}}.
+.}}---}}.
+.}--.--}.
+.}|...|}.
+.}--.--}.
+.}}---}}.
+.}}}}}}}.
+ENDMAP
+STAIR:levregion(01,00,79,20),(0,0,8,7),up
+STAIR:levregion(01,00,79,20),(0,0,8,7),down
+BRANCH:levregion(01,00,79,20),(0,0,8,7)
+TELEPORT_REGION:levregion(01,00,79,20),(2,2,6,6)
+MAZEWALK:(08,05),east
+REGION:(04,03,06,06),unlit,"ordinary",unfilled,true
+MONSTER:'L',random,(04,04)
+MONSTER:'V',"vampire lord",(03,04)
+MONSTER:';',"kraken",(06,06)
+# And to make things a little harder.
+TRAP:"board",(04,03)
+TRAP:"board",(04,05)
+TRAP:"board",(03,04)
+TRAP:"board",(05,04)
+# treasures
+OBJECT:'"',random,(04,04)
diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn
new file mode 100644 (file)
index 0000000..f67f02f
--- /dev/null
@@ -0,0 +1,2746 @@
+.\" $Revision: 1.61.2.20 $ $Date: 2003/12/03 03:00:47 $
+.ds h0 "NetHack Guidebook
+.ds h1
+.ds h2 %
+.ds vr "NetHack 3.4
+.ds f0 "\*(vr
+.ds f1
+.ds f2 "December 2, 2003
+.mt
+A Guide to the Mazes of Menace
+(Guidebook for NetHack)
+.au
+Eric S. Raymond
+(Extensively edited and expanded for 3.4)
+.hn 1
+Introduction
+
+Recently, you have begun to find yourself unfulfilled and distant 
+in your daily occupation.  Strange dreams of prospecting, stealing, 
+crusading, and combat have haunted you in your sleep for many months, 
+but you aren't sure of the reason.  You wonder whether you have in 
+fact been having those dreams all your life, and somehow managed to 
+forget about them until now.  Some nights you awaken suddenly
+and cry out, terrified at the vivid recollection of the strange and 
+powerful creatures that seem to be lurking behind every corner of the 
+dungeon in your dream.  Could these details haunting your dreams be real?  
+As each night passes, you feel the desire to enter the mysterious caverns 
+near the ruins grow stronger.  Each morning, however, you quickly put 
+the idea out of your head as you recall the tales of those who entered 
+the caverns before you and did not return.  Eventually you can resist 
+the yearning to seek out the fantastic place in your dreams no longer.  
+After all, when other adventurers came back this way after spending time 
+in the caverns, they usually seemed better off than when they passed 
+through the first time.  And who was to say that all of those who did 
+not return had not just kept going?
+
+.pg
+Asking around, you hear about a bauble, called the Amulet of Yendor by some,
+which, if you can find it, will bring you great wealth.  One legend you were
+told even mentioned that the one who finds the amulet will be granted
+immortality by the gods.  The amulet is rumored to be somewhere beyond the
+Valley of Gehennom, deep within the Mazes of Menace.  Upon hearing the
+legends, you immediately realize that there is some profound and 
+undiscovered reason that you are to descend into the caverns and seek 
+out that amulet of which they spoke.  Even if the rumors of the amulet's 
+powers are untrue, you decide that you should at least be able to sell the 
+tales of your adventures to the local minstrels for a tidy sum, especially 
+if you encounter any of the terrifying and magical creatures of 
+your dreams along the way.  You spend one last night fortifying yourself 
+at the local inn, becoming more and more depressed as you watch the odds 
+of your success being posted on the inn's walls getting lower and lower.  
+
+.pg
+  In the morning you awake, collect your belongings, and 
+set off for the dungeon.  After several days of uneventful 
+travel, you see the ancient ruins that mark the entrance to the 
+Mazes of Menace.  It is late at night, so you make camp at the entrance 
+and spend the night sleeping under the open skies.  In the morning, you 
+gather your gear, eat what may be your last meal outside, and enter the 
+dungeon...
+
+.hn 1
+What is going on here?
+.pg
+You have just begun a game of NetHack.  Your goal is to grab as much
+treasure as you can, retrieve the Amulet of Yendor, and escape the
+Mazes of Menace alive.
+.pg
+Your abilities and strengths for dealing with the hazards of adventure
+will vary with your background and training:
+.pg
+\fIArcheologists\fP understand dungeons pretty well; this enables them
+to move quickly and sneak up on the local nasties.  They start equipped
+with the tools for a proper scientific expedition.
+.pg
+\fIBarbarians\fP are warriors out of the hinterland, hardened to battle.
+They begin their quests with naught but uncommon strength, a trusty hauberk,
+and a great two-handed sword.
+.pg
+\fICavemen\fP and \fICavewomen\fP start with exceptional strength but,
+unfortunately, with neolithic weapons.
+.pg
+\fIHealers\fP are wise in medicine and apothecary.  They know the
+herbs and simples that can restore vitality, ease pain, anesthetize,
+and neutralize poisons; and with their instruments, they can divine a
+being's state of health or sickness.  Their medical practice earns them
+quite reasonable amounts of money, with which they enter the dungeon.
+.pg
+\fIKnights\fP are distinguished from the common skirmisher by their
+devotion to the ideals of chivalry and by the surpassing excellence of
+their armor.
+.pg
+\fIMonks\fP are ascetics, who by rigorous practice of physical and mental
+disciplines have become capable of fighting as effectively without weapons
+as with.  They wear no armor but make up for it with increased mobility.
+.pg
+\fIPriests\fP and \fIPriestesses\fP are clerics militant, crusaders
+advancing the cause of righteousness with arms, armor, and arts
+thaumaturgic.  Their ability to commune with deities via prayer
+occasionally extricates them from peril, but can also put them in it.
+.pg
+\fIRangers\fP are most at home in the woods, and some say slightly out
+of place in a dungeon.  They are, however, experts in archery as well
+as tracking and stealthy movement.
+.pg
+\fIRogues\fP are agile and stealthy thieves, with knowledge of locks,
+traps, and poisons.  Their advantage lies in surprise, which they employ
+to great advantage.
+.pg
+\fISamurai\fP are the elite warriors of feudal Nippon.  They are lightly
+armored and quick, and wear the \fIdai-sho\fP, two swords of the deadliest
+keenness.
+.pg
+\fITourists\fP start out with lots of gold (suitable for shopping with),
+a credit card, lots of food, some maps, and an expensive camera.  Most
+monsters don't like being photographed.
+.pg
+\fIValkyries\fP are hardy warrior women.  Their upbringing in the harsh
+Northlands makes them strong, inures them to extremes of cold, and instills
+in them stealth and cunning.
+.pg
+\fIWizards\fP start out with a knowledge of magic, a selection of magical
+items, and a particular affinity for dweomercraft.  Although seemingly weak
+and easy to overcome at first sight, an experienced Wizard is a deadly foe.
+.pg
+You may also choose the race of your character:
+.pg
+\fIDwarves\fP are smaller than humans or elves, but are stocky and solid
+individuals.  Dwarves' most notable trait is their great expertise in mining
+and metalwork.  Dwarvish armor is said to be second in quality not even to the
+mithril armor of the Elves.
+.pg
+\fIElves\fP are agile, quick, and perceptive; very little of what goes
+on will escape an Elf.  The quality of Elven craftsmanship often gives
+them an advantage in arms and armor.
+.pg
+\fIGnomes\fP are smaller than but generally similar to dwarves.  Gnomes are
+known to be expert miners, and it is known that a secret underground mine
+complex built by this race exists within the Mazes of Menace, filled with
+both riches and danger.
+.pg
+\fIHumans\fP are by far the most common race of the surface world, and
+are thus the norm by which other races are often compared.  Although
+they have no special abilities, they can succeed in any role.
+.pg
+\fIOrcs\fP are a cruel and barbaric race that hate every living thing
+(including other orcs).  Above all others, Orcs hate Elves with a passion
+unequalled, and will go out of their way to kill one at any opportunity.
+The armor and weapons fashioned by the Orcs are typically of inferior quality.
+.hn 1
+What do all those things on the screen mean?
+.pg
+On the screen is kept a map of where you have
+been and what you have seen on the current dungeon level; as you
+explore more of the level, it appears on the screen in front of you.
+.pg
+When NetHack's ancestor \fIrogue\fP first appeared, its screen
+orientation was almost unique among computer fantasy games.  Since
+then, screen orientation has become the norm rather than the
+exception; NetHack continues this fine tradition.  Unlike text
+adventure games that accept commands in pseudo-English sentences and
+explain the results in words, NetHack commands are all one or two
+keystrokes and the results are displayed graphically on the screen.  A
+minimum screen size of 24 lines by 80 columns is recommended; if the
+screen is larger, only a 21x80 section will be used for the map.
+.pg
+NetHack can even be played by blind players, with the assistance of Braille
+readers or speech synthesisers.  Instructions for configuring NetHack for
+the blind are included later in this document.
+.pg
+NetHack generates a new dungeon every time you play it; even the
+authors still find it an entertaining and exciting game despite
+having won several times.
+.pg
+NetHack offers a variety of display options.  The options available to you
+will vary from port to port, depending on the capabilities of your
+hardware and software, and whether various compile-time options were
+enabled when your executable was created.  The three possible display
+options are: a monochrome character interface, a color character interface,
+and a graphical interface using small pictures called tiles.  The two
+character interfaces allow fonts with other characters to be substituted,
+but the default assignments use standard ASCII characters to represent
+everything.  There is no difference between the various display options
+with respect to game play.  Because we cannot reproduce the tiles or
+colors in the Guidebook, and because it is common to all ports, we will
+use the default ASCII characters from the monochrome character display
+when referring to things you might see on the screen during your game.
+.pg
+In order to understand what is going on in NetHack, first you must
+understand what NetHack is doing with the screen.  The NetHack screen
+replaces the ``You see ...'' descriptions of text adventure games.
+Figure 1 is a sample of what a NetHack screen might look like.
+The way the screen looks for you depends on your platform.
+
+.TS S
+center tab(~);
+a.
+_
+The bat bites!
+
+    ------
+    |....|    ----------
+    |.<..|####...@...$.|
+    |....-#   |...B....+
+    |....|    |.d......|
+    ------    -------|--
+
+
+
+Player the Rambler     St:12 Dx:7 Co:18 In:11 Wi:9 Ch:15  Neutral
+Dlvl:1 $:0  HP:9(12) Pw:3(3) AC:10 Exp:1/19 T:257 Weak
+
+_
+.TE
+.ce 1
+Figure 1
+
+.hn 2
+The status lines (bottom)
+.pg
+The bottom two lines of the screen contain several cryptic pieces of
+information describing your current status.  If either status line
+becomes longer than the width of the screen, you might not see all of
+it.  Here are explanations of what the various status items mean
+(though your configuration may not have all the status items listed
+below):
+.lp "Rank  "
+Your character's name and professional ranking (based on the
+experience level, see below).
+.lp Strength
+A measure of your character's strength; one of your six basic
+attributes.  A human character's attributes can range from 3 to 18 inclusive;
+non-humans may exceed these limits
+(occasionally you may get super-strengths of the form 18/xx, and magic can
+also cause attributes to exceed the normal limits).  The
+higher your strength, the stronger you are.  Strength affects how
+successfully you perform physical tasks, how much damage you do in
+combat, and how much loot you can carry.
+.lp Dexterity
+Dexterity affects your chances to hit in combat, to avoid traps, and
+do other tasks requiring agility or manipulation of objects.
+.lp Constitution
+Constitution affects your ability to recover from injuries and other
+strains on your stamina.
+.lp Intelligence
+Intelligence affects your ability to cast spells and read spellbooks.
+.lp Wisdom
+Wisdom comes from your practical experience (especially when dealing with
+magic).  It affects your magical energy.
+.lp Charisma
+Charisma affects how certain creatures react toward you.  In
+particular, it can affect the prices shopkeepers offer you.
+.lp Alignment
+\fBLawful\fP, \fBNeutral\fP, or \fBChaotic\fP.  Often, Lawful is
+taken as good and Chaotic as evil, but legal and ethical do not always
+coincide.  Your alignment influences how other
+monsters react toward you.  Monsters of a like alignment are more likely
+to be non-aggressive, while those of an opposing alignment are more likely
+to be seriously offended at your presence.
+.lp "Dungeon Level
+How deep you are in the dungeon.  You start at level one and the number
+increases as you go deeper into the dungeon.  Some levels are special,
+and are identified by a name and not a number.  The Amulet of Yendor is
+reputed to be somewhere beneath the twentieth level.
+.lp "Gold  "
+The number of gold pieces you are openly carrying.  Gold which you have
+concealed in containers is not counted.
+.lp "Hit Points
+Your current and maximum hit points.  Hit points indicate how much
+damage you can take before you die.  The more you get hit in a fight,
+the lower they get.  You can regain hit points by resting, or by using
+certain magical items or spells.  The number in parentheses is the maximum
+number your hit points can reach.
+.lp Power
+Spell points.  This tells you how much mystic energy (\fImana\fP)
+you have available for spell casting.  Again, resting will regenerate the
+amount available.
+.lp "Armor Class
+A measure of how effectively your armor stops blows from unfriendly
+creatures.  The lower this number is, the more effective the armor; it
+is quite possible to have negative armor class. 
+.lp Experience
+Your current experience level and experience points.  As you
+adventure, you gain experience points.  At certain experience point
+totals, you gain an experience level.  The more experienced you are,
+the better you fight and withstand magical attacks.  Many dungeons
+show only your experience level here.
+.lp "Time  "
+The number of turns elapsed so far, displayed if you have the
+.op time
+option set.
+.lp "Hunger status
+Your current hunger status, ranging from \fBSatiated\fP down to
+\fBFainting\fP.  If your hunger status is normal, it is not displayed.
+.pg
+Additional status flags may appear after the hunger status:  \fBConf\fP
+when you're confused, \fBFoodPois\fP or \fBIll\fP
+when sick, \fBBlind\fP when you can't
+see, \fBStun\fP when stunned, and \fBHallu\fP when hallucinating.
+.hn 2
+The message line (top)
+.pg
+The top line of the screen is reserved for messages that describe
+things that are impossible to represent visually.  If you see a
+``\fB--More--\fP'' on the top line, this means that NetHack has
+another message to display on the screen, but it wants to make certain
+that you've read the one that is there first.  To read the next message,
+just press the space bar.
+.hn 2
+The map (rest of the screen)
+.pg
+The rest of the screen is the map of the level as you have explored it
+so far.  Each symbol on the screen represents something.  You can set
+various graphics options to change some of the symbols the game uses;
+otherwise, the game will use default symbols.  Here is a list of what the
+default symbols mean:
+.lp "- and |
+The walls of a room, or an open door.  Or a grave (|).
+.lp .
+The floor of a room, ice, or a doorless doorway.
+.lp #
+A corridor, or iron bars, or a tree, or possibly a kitchen sink (if
+your dungeon has sinks), or a drawbridge.
+.lp >
+Stairs down: a way to the next level.
+.lp <
+Stairs up: a way to the previous level.
+.lp +
+A closed door, or a spellbook containing a spell you may be able to learn.
+.lp @
+Your character or a human.
+.lp $
+A pile of gold.
+.lp ^
+A trap (once you have detected it).
+.lp )
+A weapon.
+.lp [
+A suit or piece of armor.
+.lp %
+Something edible (not necessarily healthy).
+.lp ?
+A scroll.
+.lp /
+A wand.
+.lp =
+A ring.
+.lp !
+A potion.
+.lp (
+A useful item (pick-axe, key, lamp...).
+.lp """
+An amulet or a spider web.
+.lp *
+A gem or rock (possibly valuable, possibly worthless).
+.lp `
+A boulder or statue.
+.lp 0
+An iron ball.
+.lp _
+An altar, or an iron chain.
+.lp {
+A fountain.
+.lp }
+A pool of water or moat or a pool of lava.
+.lp "\e
+An opulent throne.
+.lp "a-zA-Z and other symbols
+Letters and certain other symbols represent the various inhabitants
+of the Mazes of Menace.  Watch out, they can be nasty and vicious.
+Sometimes, however, they can be helpful.
+.lp I
+This marks the last known location of an invisible or otherwise unseen
+monster.  Note that the monster could have moved.  The 'F' and 'm' commands
+may be useful here.
+.pg
+You need not memorize all these symbols; you can ask the game what any
+symbol represents with the `/' command (see the next section for
+more info).
+
+.hn 1
+Commands
+.pg
+Commands are initiated by typing one or two characters.  Some commands,
+like ``search'', do not require that any more information be collected by
+NetHack.  Other commands might require additional information, for
+example a direction, or an object to be used.  For those commands that
+require additional information, NetHack will present you with either a
+menu of choices or with a command line prompt requesting information.  Which
+you are presented with will depend chiefly on how you have set the
+.op menustyle
+option.
+.pg
+For example, a common question, in the form ``What do you want to
+use?\ [a-zA-Z\ ?*]'', asks you to choose an object you are carrying.
+Here, ``a-zA-Z'' are the inventory letters of your possible choices.
+Typing `?' gives you an inventory list of these items, so you can see
+what each letter refers to.  In this example, there is also a `*'
+indicating that you may choose an object not on the list, if you
+wanted to use something unexpected.  Typing a `*' lists your entire
+inventory, so you can see the inventory letters of every object you're
+carrying.  Finally, if you change your mind and decide you don't want
+to do this command after all, you can press the ESC key to abort the
+command.
+.pg
+You can put a number before some commands to repeat them that many
+times; for example, ``10s'' will search ten times.  If you have the
+.op number_pad
+option set, you must type `n' to prefix a count, so the example above
+would be typed ``n10s'' instead.  Commands for which counts make no
+sense ignore them.  In addition, movement commands can be prefixed for
+greater control (see below).  To cancel a count or a prefix, press the
+ESC key.
+.pg
+The list of commands is rather long, but it can be read at any time
+during the game through the `?' command, which accesses a menu of
+helpful texts.  Here are the commands for your reference:
+.lp ?
+Help menu:  display one of several help texts available.
+.lp /
+Tell what a symbol represents.  You may choose to specify a location
+or type a symbol (or even a whole word) to explain.
+Specifying a location is done by moving the cursor to a particular spot
+on the map and then pressing one of `.', `,', `;',
+or `:'.  `.' will explain the symbol at the chosen location,
+conditionally check for ``More info?'' depending upon whether the
+.op help
+option is on, and then you will be asked to pick another location;
+`,' will explain the symbol but skip any additional
+information; `;' will skip additional info and also not bother asking
+you to choose another location to examine; `:' will show additional
+info, if any, without asking for confirmation.  When picking a location,
+pressing the ESC key will terminate this command, or pressing `?'
+will give a brief reminder about how it works.
+.pg
+Specifying a name rather than a location
+always gives any additional information available about that name.
+.lp &
+Tell what a command does.
+.lp <
+Go up to the previous level (if you are on a staircase or ladder).
+.lp >
+Go down to the next level (if you are on a staircase or ladder).
+.lp [yuhjklbn]
+Go one step in the direction indicated (see Figure 2).  If you sense
+or remember
+a monster there, you will fight the monster instead.  Only these
+one-step movement commands cause you to fight monsters; the others
+(below) are ``safe.''
+.sd
+.TS S
+center;
+c c.
+y  k  u        7  8  9
+\e | / \e | /
+h- . -l        4- . -6
+/ | \e / | \e
+b  j  n        1  2  3
+       (if \fBnumber_pad\fP is set)
+.TE
+.ed
+.ce 1
+Figure 2
+
+.lp [YUHJKLBN]
+Go in that direction until you hit a wall or run into something.
+.lp m[yuhjklbn]
+Prefix:  move without picking up objects or fighting (even if you remember
+a monster there)
+.lp F[yuhjklbn]
+Prefix:  fight a monster (even if you only guess one is there)
+.lp M[yuhjklbn]
+Prefix:  move far, no pickup.
+.lp "g[yuhjklbn]
+Prefix:  move until something interesting is found.
+.lp "G[yuhjklbn] or <CONTROL->[yuhjklbn]
+Prefix:  same as `g', but forking of corridors is not considered interesting.
+.lp _
+Travel to a map location via a shortest-path algorithm.  The shortest path
+is computed over map locations the hero knows about (e.g. seen or
+previously traversed).  If there is no known path, a guess is made instead.
+Stops on most of
+the same conditions as the `G' command, but without picking up
+objects, similar to the `M' command.  For ports with mouse 
+support, the command is also invoked when a mouse-click takes place on a 
+location other than the current position.
+.lp .
+Rest, do nothing for one turn.
+.lp a
+Apply (use) a tool (pick-axe, key, lamp...).
+.lp A
+Remove one or more worn items, such as armor.
+Use `T' (take off) to take off only one piece of armor 
+or `R' (remove) to take off only one accessory.
+.lp ^A
+Redo the previous command.
+.lp c
+Close a door.
+.lp C
+Call (name) an individual monster.
+.lp ^C
+Panic button.  Quit the game.
+.lp d
+Drop something.  Ex. ``d7a'' means drop seven items of object \fIa\fP.
+.lp D
+Drop several things.  In answer to the question
+``What kinds of things do you want to drop? [!%= BUCXaium]''
+you should type zero or more object symbols possibly followed by 
+`a' and/or `i' and/or `u' and/or `m'.  In addition, one or more of
+the blessed/uncursed/cursed groups may be typed.
+.sd
+.si
+DB  - drop all objects known to be blessed.
+DU  - drop all objects known to be uncursed.
+DC  - drop all objects known to be cursed.
+DX  - drop all objects of unknown B/U/C status.
+Da  - drop all objects, without asking for confirmation.
+Di  - examine your inventory before dropping anything.
+Du  - drop only unpaid objects (when in a shop).
+Dm  - use a menu to pick which object(s) to drop.
+D%u - drop only unpaid food.
+.ei
+.ed
+.lp ^D
+Kick something (usually a door).
+.lp e
+Eat food.
+.\" Make sure Elbereth is not hyphenated below, the exact spelling matters
+.hw Elbereth
+.lp E
+Engrave a message on the floor.
+Engraving the word ``Elbereth'' will cause most monsters to not attack
+you hand-to-hand (but if you attack, you will rub it out); this is
+often useful to give yourself a breather.  (This feature may be compiled out
+of the game, so your version might not have it.)
+.sd
+.si
+E- - write in the dust with your fingers.  
+.ei
+.ed
+.lp f
+Fire one of the objects placed in your quiver.  You may select
+ammunition with a previous `Q' command, or let the computer pick
+something appropriate if
+.op autoquiver
+is true.
+.lp i
+List your inventory (everything you're carrying).
+.lp I
+List selected parts of your inventory.
+.sd
+.si
+I* - list all gems in inventory;
+Iu - list all unpaid items;
+Ix - list all used up items that are on your shopping bill;
+I$ - count your money.
+.ei
+.ed
+.lp o
+Open a door.
+.lp O
+Set options.  A menu showing the current option values will be
+displayed.  You can change most values simply by selecting the menu
+entry for the given option (ie, by typing its letter or clicking upon
+it, depending on your user interface).  For the non-boolean choices,
+a further menu or prompt will appear once you've closed this menu.
+The available options
+are listed later in this Guidebook.  Options are usually set before the
+game rather than with the `O' command; see the section on options below.
+.lp p
+Pay your shopping bill.
+.lp P
+Put on a ring or other accessory (amulet, blindfold).
+.lp ^P
+Repeat previous message.  Subsequent ^P's repeat earlier messages.
+The behavior can be varied via the msg_window option.
+.lp q
+Quaff (drink) something (potion, water, etc).
+.lp Q
+Select an object for your quiver.  You can then throw this using
+the `f' command.  (In versions prior to 3.3 this was the command to quit
+the game, which has now been moved to `#quit'.)
+.lp r
+Read a scroll or spellbook.
+.lp R
+Remove an accessory (ring, amulet, etc).
+.lp ^R
+Redraw the screen.
+.lp s
+Search for secret doors and traps around you.  It usually takes several
+tries to find something.
+.lp S
+Save (and suspend) the game.  The game will be restored automatically the
+next time you play.
+.lp t
+Throw an object or shoot a projectile.
+.lp T
+Take off armor.
+.lp ^T
+Teleport, if you have the ability.
+.lp v
+Display version number.
+.lp V
+Display the game history.
+.lp w
+Wield weapon.
+.sd
+.si
+w- - wield nothing, use your bare hands.
+.ei
+.ed
+.lp W
+Wear armor.
+.lp x
+Exchange your wielded weapon with the item in your alternate
+weapon slot.  The latter is used as your secondary weapon when engaging in
+two-weapon combat.  Note that if one of these slots is empty,
+the exchange still takes place.
+.lp X
+Enter explore (discovery) mode, explained in its own section later.
+.lp ^X
+Display your name, role, race, gender, and alignment as well as
+the various deities in your game.
+.lp z
+Zap a wand.  To aim at yourself, use `.' for the direction.
+.lp Z
+Zap (cast) a spell.  To cast at yourself, use `.' for the direction.
+.lp ^Z
+Suspend the game
+.ux " versions with job control only)." (
+.lp :
+Look at what is here.
+.lp ;
+Show what type of thing a visible symbol corresponds to.
+.lp ,
+Pick up some things. May be preceded by `m' to force a selection menu.
+.lp @
+Toggle the
+.op autopickup
+option on and off.
+.lp ^
+Ask for the type of a trap you found earlier.
+.lp )
+Tell what weapon you are wielding.
+.lp [
+Tell what armor you are wearing.
+.lp =
+Tell what rings you are wearing.
+.lp """
+Tell what amulet you are wearing.
+.lp (
+Tell what tools you are using.
+.lp *
+Tell what equipment you are using; combines the preceding five type-specific
+commands into one.
+.lp $
+Count your gold pieces.
+.lp +
+List the spells you know.  Using this command, you can also rearrange
+the order in which your spells are listed.  They are shown via a menu,
+and if you select a spell in that menu, you'll be re-prompted for
+another spell to swap places with it, and then have opportunity to
+make further exchanges.
+.lp "\e
+Show what types of objects have been discovered.
+.lp !
+Escape to a shell.
+.lp #
+Perform an extended command.  As you can see, the authors of NetHack
+used up all the letters, so this is a way to introduce the less frequently
+used commands.
+What extended commands are available depends on what features the game was
+compiled with.
+.lp #adjust
+Adjust inventory letters (most useful when the
+.op fixinv
+option is ``on'').
+.lp #chat
+Talk to someone.
+.lp #conduct
+List which challenges you have adhered to.  See the section below entitled
+``Conduct'' for details.
+.lp #dip
+Dip an object into something.
+.lp #enhance
+Advance or check weapons and spell skills.
+.lp #force
+Force a lock.
+.lp #invoke
+Invoke an object's special powers.
+.lp #jump
+Jump to another location.
+.lp #loot
+Loot a box or bag on the floor beneath you, or the saddle 
+from a horse standing next to you.
+.lp #monster
+Use a monster's special ability (when polymorphed into monster form).
+.lp #name
+Name an item or type of object.
+.lp #offer
+Offer a sacrifice to the gods.
+.lp #pray
+Pray to the gods for help.
+.lp #quit
+Quit the program without saving your game.
+.lp #ride
+Ride (or stop riding) a monster.
+.lp #rub
+Rub a lamp or a stone.
+.lp #sit
+Sit down.
+.lp #turn
+Turn undead.
+.lp #twoweapon
+Toggle two-weapon combat on or off.  Note that you must
+use suitable weapons for this type of combat, or it will
+be automatically turned off.
+.lp #untrap
+Untrap something (trap, door, or chest).
+.lp #version
+Print compile time options for this version of NetHack.
+.lp #wipe
+Wipe off your face.
+.lp #?
+Help menu:  get the list of available extended commands.
+.pg
+If your keyboard has a meta key (which, when pressed in combination
+with another key, modifies it by setting the `meta' [8th, or `high']
+bit), you can invoke many extended commands by meta-ing the first
+letter of the command.
+.\" In {\it NT, OS/2, PC\/ {\rm and} ST NetHack},
+.\" the `Alt' key can be used in this fashion;
+.\" on the Amiga set the {\it altmeta\/} option to get this behavior.
+In NT, OS/2, and PC NetHack, the `Alt' key
+can be used in this fashion.
+.lp M-?
+#? (not supported by all platforms)
+.lp M-2
+#twoweapon (unless the number_pad option is enabled)
+.lp M-a
+#adjust
+.lp M-c
+#chat
+.lp M-d
+#dip
+.lp M-e
+#enhance
+.lp M-f
+#force
+.lp M-i
+#invoke
+.lp M-j
+#jump
+.lp M-l
+#loot
+.lp M-m
+#monster
+.lp M-n
+#name
+.lp M-o
+#offer
+.lp M-p
+#pray
+.lp M-q
+#quit
+.lp M-r
+#rub
+.lp M-s
+#sit
+.lp M-t
+#turn
+.lp M-u
+#untrap
+.lp M-v
+#version
+.lp M-w
+#wipe
+.pg
+If the
+.op number_pad
+option is on, some additional letter commands are available:
+.lp h
+Help menu:  display one of several help texts available, like ``?''.
+.lp j
+Jump to another location.  Same as ``#jump'' or ``M-j''.
+.lp k
+Kick something (usually a door).  Same as `^D'.
+.lp l
+Loot a box or bag on the floor beneath you, or the saddle 
+from a horse standing next to you.  Same as ``#loot'' or ``M-l''.
+.lp N
+Name an item or type of object.  Same as ``#name'' or ``M-n''.
+.lp u
+Untrap a trap, door, or chest.  Same as ``#untrap'' or ``M-u''.
+
+.hn 1
+Rooms and corridors
+.pg
+Rooms and corridors in the dungeon are either lit or dark.
+Any lit areas within your line of sight will be displayed;  
+dark areas are only displayed if they are within one space of you.
+Walls and corridors remain on the map as you explore them.
+.pg
+Secret corridors are hidden.  You can find them with the `s' (search)
+command.
+.hn 2
+Doorways
+.pg
+Doorways connect rooms and corridors.  Some doorways have no doors;
+you can walk right through.  Others have doors in them, which may be
+open, closed, or locked.  To open a closed door, use the `o' (open)
+command; to close it again, use the `c' (close) command.
+.pg
+You can get through a locked door by using a tool to pick the lock
+with the `a' (apply) command, or by kicking it open with the `^D'
+(kick) command.
+.pg
+Open doors cannot be entered diagonally; you must approach them
+straight on, horizontally or vertically.  Doorways without doors are
+not restricted in this fashion.
+.pg
+Doors can be useful for shutting out monsters.  Most monsters cannot
+open doors, although a few don't need to (ex. ghosts can walk through
+doors).
+.pg
+Secret doors are hidden.  You can find them with the `s' (search)
+command.  Once found they are in all ways equivalent to normal doors.
+.hn 2
+Traps (`^')
+.pg
+There are traps throughout the dungeon to snare the unwary delver.
+For example, you may suddenly fall into a pit and be stuck for a few
+turns trying to climb out.  Traps don't appear on your map until you
+see one triggered by moving onto it, see something fall into it, or you
+discover it with the `s' (search) command.  Monsters can fall prey to
+traps, too, which can be a very useful defensive strategy.
+.pg
+There is a special pre-mapped branch of the dungeon based on the
+classic computer game ``Sokoban.''  The goal is to push the boulders
+into the pits or holes.  With careful foresight, it is possible to
+complete all of the levels according to the traditional rules of
+Sokoban.  Some allowances are permitted in case the player gets stuck;
+however, they will lower your luck.
+.hn 2
+Stairs (`<', `>')
+.pg
+In general, each level in the dungeon will have a staircase going up
+(`<') to the previous level and another going down (`>') to the next
+level.  There are some exceptions though.  For instance, fairly early
+in the dungeon you will find a level with two down staircases, one
+continuing into the dungeon and the other branching into an area
+known as the Gnomish Mines.  Those mines eventually hit a dead end,
+so after exploring them (if you choose to do so), you'll need to
+climb back up to the main dungeon.
+.pg
+When you traverse a set of stairs, or trigger a trap which sends you
+to another level, the level you're leaving will be deactivated and
+stored in a file on disk.  If you're moving to a previously visited
+level, it will be loaded from its file on disk and reactivated.  If
+you're moving to a level which has not yet been visited, it will be
+created (from scratch for most random levels, from a template for
+some ``special'' levels, or loaded from the remains of an earlier game
+for a ``bones'' level as briefly described below).  Monsters are only
+active on the current level; those on other levels are essentially
+placed into stasis.
+.pg
+Ordinarily when you climb a set of stairs, you will arrive on the
+corresponding staircase at your destination.  However, pets (see below)
+and some other monsters will follow along if they're close enough when
+you travel up or down stairs, and occasionally one of these creatures
+will displace you during the climb.  When that occurs, the pet or other
+monster will arrive on the staircase and you will end up nearby.
+.hn 2
+Ladders (`<', `>')
+.pg
+Ladders serve the same purpose as staircases, and the two types of
+inter-level connections are nearly indistinguishable during game play.
+.hn 2
+Shops and shopping
+.pg
+Occasionally you will run across a room with a shopkeeper near the door
+and many items lying on the floor.  You can buy items by picking them
+up and then using the `p' command.  You can inquire about the price
+of an item prior to picking it up by using the ``#chat'' command
+while standing on it.  Using an item prior to paying for it will incur a
+charge, and the shopkeeper won't allow you to leave the shop until you
+have paid any debt you owe.
+.pg
+You can sell items to a shopkeeper by dropping them to the floor while
+inside a shop.  You will either be offered an amount of gold and asked
+whether you're willing to sell, or you'll be told that the shopkeeper
+isn't interested (generally, your item needs to be compatible with the
+type of merchandise carried by the shop).
+.pg
+If you drop something in a shop by accident, the shopkeeper will usually
+claim ownership without offering any compensation.  You'll have to buy
+it back if you want to reclaim it.
+.pg
+Shopkeepers sometimes run out of money.  When that happens, you'll be
+offered credit instead of gold when you try to sell something.  Credit
+can be used to pay for purchases, but it is only good in the shop where
+it was obtained; other shopkeepers won't honor it.  (If you happen to
+find a "credit card" in the dungeon, don't bother trying to use it in
+shops; shopkeepers will not accept it.)
+.pg
+The `$' command, which reports the amount of gold you are carrying
+(in inventory, not inside bags or boxes), will also show current shop
+debt or credit, if any.  The `Iu' command lists unpaid items
+(those which still belong to the shop) if you are carrying any.
+The `Ix' command shows an inventory-like display of any unpaid
+items which have been used up, along with other shop fees, if any.
+.hn 3
+Shop idiosyncracies
+.pg
+Several aspects of shop behavior might be unexpected.
+.\" note: using * instead of \(bu is better for plain text output
+.lp * 2
+The price of a given item can vary due to a variety of factors.
+.lp * 2
+A shopkeeper treats the spot immediately inside the door as if it were
+outside the shop.
+.lp * 2
+While the shopkeeper watches you like a hawk, he will generally ignore
+any other customers.
+.lp * 2
+If a shop is "closed for inventory", it will not open of its own accord.
+.lp * 2
+Shops do not get restocked with new items, regardless of inventory depletion.
+
+.hn 1
+Monsters
+.pg
+Monsters you cannot see are not displayed on the screen.  Beware!
+You may suddenly come upon one in a dark place.  Some magic items can
+help you locate them before they locate you (which some monsters can do
+very well).
+.pg
+The commands `/' and `;' may be used to obtain information about those
+monsters who are displayed on the screen.  The command `C' allows you
+to assign a name to a monster, which may be useful to help distinguish
+one from another when multiple monsters are present.  Assigning a name
+which is just a space will remove any prior name.
+.pg
+The extended command ``#chat'' can be used to interact with an adjacent
+monster.  There is no actual dialog (in other words, you don't get to
+choose what you'll say), but chatting with some monsters such as a
+shopkeeper or the Oracle of Delphi can produce useful results.
+.hn 2
+Fighting
+.pg
+If you see a monster and you wish to fight it, just attempt to walk
+into it.  Many monsters you find will mind their own business unless
+you attack them.  Some of them are very dangerous when angered.
+Remember:  discretion is the better part of valor.
+.pg
+If you can't see a monster (if it is invisible, or if you are blinded),
+the symbol `I' will be shown when you learn of its presence.
+If you attempt to walk into it, you will try to fight it just like
+a monster that you can see; of course,
+if the monster has moved, you will attack empty air.  If you guess
+that the monster has moved and you don't wish to fight, you can use the `m'
+command to move without fighting; likewise, if you don't remember a monster
+but want to try fighting anyway, you can use the `F' command.
+.hn 2
+Your pet
+.pg
+You start the game with a little dog (`d'), cat (`f'), or pony (`u'), which
+follows you about the dungeon and fights monsters with you.  Like you, your
+pet needs food to survive.  It usually feeds itself on fresh carrion
+and other meats.  If you're worried about it or want to train it, you
+can feed it, too, by throwing it food.  A properly trained pet can be
+very useful under certain circumstances.
+.pg
+Your pet also gains experience from killing monsters, and can grow
+over time, gaining hit points and doing more damage.  Initially, your
+pet may even be better at killing things than you, which makes pets
+useful for low-level characters.
+.pg
+Your pet will follow you up and down staircases if it is next to you
+when you move.  Otherwise your pet will be stranded and may become
+wild.  Similarly, when you trigger certain types of traps which alter
+your location (for instance, a trap door which drops you to a lower
+dungeon level), any adjacent pet will accompany you and any non-adjacent
+pet will be left behind.  Your pet may trigger such traps itself; you
+will not be carried along with it even if adjacent at the time.
+.hn 2
+Steeds
+.pg
+Some types of creatures in the dungeon can actually be ridden if you
+have the right equipment and skill.  Convincing a wild beast to let
+you saddle it up is difficult to say the least.  Many a dungeoneer 
+has had to resort to magic and wizardry in order to forge the alliance.
+Once you do have the beast under your control however, you can 
+easily climb in and out of the saddle with the `#ride' command.  Lead
+the beast around the dungeon when riding, in the same manner as 
+you would move yourself.  It is the beast that you will see displayed
+on the map.
+.pg
+Riding skill is managed by the `#enhance' command.  See the section
+on Weapon proficiency for more information about that.
+.hn 2
+Bones levels
+.pg
+You may encounter the shades and corpses of other adventurers (or even
+former incarnations of yourself!) and their personal effects.  Ghosts
+are hard to kill, but easy to avoid, since they're slow and do little
+damage.  You can plunder the deceased adventurer's possessions;
+however, they are likely to be cursed.  Beware of whatever killed the
+former player; it is probably still lurking around, gloating over its
+last victory.
+
+.hn 1
+Objects 
+.pg
+When you find something in the dungeon, it is common to want to pick
+it up.  In NetHack, this is accomplished automatically by walking over
+the object (unless you turn off the
+.op autopickup
+option (see below), or move with the `m' prefix (see above)), or
+manually by using the `,' command.
+.pg
+If you're carrying too many items, NetHack will tell you so and you won't 
+be able to pick
+up anything more.  Otherwise, it will add the object(s) to your pack and tell
+you what you just picked up.
+.pg
+As you add items to your inventory, you also add the weight of that object
+to your load.  The amount that you can carry depends on your strength and
+your constitution.  The
+stronger you are, the less the additional load will affect you.  There comes
+a point, though, when the weight of all of that stuff you are carrying around
+with you through the dungeon will encumber you.  Your reactions
+will get slower and you'll burn calories faster, requiring food more frequently
+to cope with it.  Eventually, you'll be so overloaded that you'll either have
+to discard some of what you're carrying or collapse under its weight.
+.pg
+NetHack will tell you how badly you have loaded yourself.  The symbols
+`Burdened', `Stressed', `Strained', `Overtaxed' and `Overloaded' are
+displayed on the bottom line display to indicate your condition.
+.pg
+When you pick up an object, it is assigned an inventory letter.  Many
+commands that operate on objects must ask you to find out which object
+you want to use.  When NetHack asks you to choose a particular object
+you are carrying, you are usually presented with a list of inventory
+letters to choose from (see Commands, above).
+.pg
+Some objects, such as weapons, are easily differentiated.  Others, like
+scrolls and potions, are given descriptions which vary according to
+type.  During a game, any two objects with the same description are
+the same type.  However, the descriptions will vary from game to game.
+.pg
+When you use one of these objects, if its effect is obvious, NetHack
+will remember what it is for you.  If its effect isn't extremely
+obvious, you will be asked what you want to call this type of object
+so you will recognize it later.  You can also use the ``#name''
+command for the same purpose at any time, to name all objects of a
+particular type or just an individual object.
+When you use ``#name'' on an object which has already been named,
+specifying a space as the value will remove the prior name instead
+of assigning a new one.
+.hn 2
+Curses and Blessings
+.pg
+Any object that you find may be cursed, even if the object is
+otherwise helpful.  The most common effect of a curse is being stuck
+with (and to) the item.  Cursed weapons weld themselves to your hand
+when wielded, so you cannot unwield them.  Any cursed item you wear
+is not removable by ordinary means.  In addition, cursed arms and armor
+usually, but not always, bear negative enchantments that make them
+less effective in combat.  Other cursed objects may act poorly or
+detrimentally in other ways.
+.pg
+Objects can also be blessed.  Blessed items usually work better or
+more beneficially than normal uncursed items.  For example, a blessed
+weapon will do more damage against demons.
+.pg
+There are magical means of bestowing or removing curses upon objects,
+so even if you are stuck with one, you can still have the curse
+lifted and the item removed.  Priests and Priestesses have an innate
+sensitivity to this property in any object, so they can more easily avoid
+cursed objects than other character roles.
+.pg
+An item with unknown status will be reported in your inventory with no prefix.
+An item which you know the state of will be distinguished in your inventory
+by the presence of the word ``cursed'', ``uncursed'' or ``blessed'' in the
+description of the item.
+.hn 2
+Weapons (`)')
+.pg
+Given a chance, most monsters in the Mazes of Menace will gratuitously try to
+kill you.  You need weapons for self-defense (killing them first).  Without a
+weapon, you do only 1-2 hit points of damage (plus bonuses, if any).
+Monk characters are an exception; they normally do much more damage with
+bare hands than they do with weapons.
+.pg
+There are wielded weapons, like maces and swords, and thrown weapons,
+like arrows and spears.  To hit monsters with a weapon, you must wield it and
+attack them, or throw it at them.  You can simply elect to throw a spear.
+To shoot an arrow, you should first wield a bow, then throw the arrow.
+Crossbows shoot crossbow bolts.  Slings hurl rocks and (other) stones
+(like gems).
+.pg
+Enchanted weapons have a ``plus'' (or ``to hit enhancement'' which can be
+either positive or negative) that adds to your chance to
+hit and the damage you do to a monster.  The only way to determine a weapon's
+enchantment is to have it magically identified somehow.
+Most weapons are subject to some type of damage like rust.  Such
+``erosion'' damage can be repaired.
+.pg
+The chance that an attack will successfully hit a monster, and the amount
+of damage such a hit will do, depends upon many factors.  Among them are:
+type of weapon, quality of weapon (enchantment and/or erosion), experience
+level, strength, dexterity, encumbrance, and proficiency (see below).  The
+monster's armor class - a general defense rating, not necessarily due to
+wearing of armor - is a factor too; also, some monsters are particularly
+vulnerable to certain types of weapons.
+.pg
+Many weapons can be wielded in one hand; some require both hands.
+When wielding a two-handed weapon, you can not wear a shield, and
+vice versa.  When wielding a one-handed weapon, you can have another
+weapon ready to use by setting things up with the `x' command, which
+exchanges your primary (the one being wielded) and alternate weapons.
+And if you have proficiency in the ``two weapon combat'' skill, you
+may wield both weapons simultaneously as primary and secondary; use the
+`#twoweapon' extended command to engage or disengage that.  Only
+some types of characters (barbarians, for instance) have the necessary
+skill available.  Even with that skill, using two weapons at once incurs
+a penalty in the chance to hit your target compared to using just one
+weapon at a time.
+.pg
+There might be times when you'd rather not wield any weapon at all.
+To accomplish that, wield `-', or else use the `A' command which
+allows you to unwield the current weapon in addition to taking off
+other worn items.
+.pg
+Those of you in the audience who are AD&D players, be aware that each
+weapon which existed in AD&D does roughly the same damage to monsters in
+NetHack.  Some of the more obscure weapons (such as the \fIaklys\fP,
+\fIlucern hammer\fP, and \fIbec-de-corbin\fP) are defined in an
+appendix to \fIUnearthed Arcana\fP, an AD&D supplement.
+.pg
+The commands to use weapons are `w' (wield), `t' (throw),
+`f' (fire, an alternative way of throwing), `Q' (quiver),
+`x' (exchange), `#twoweapon', and `#enhance' (see below).
+.hn 3
+Throwing and shooting
+.pg
+You can throw just about anything via the `t' command.  It will prompt
+for the item to throw; picking `?' will list things in your inventory
+which are considered likely to be thrown, or picking `*' will list
+your entire inventory.  After you've chosen what to throw, you will
+be prompted for a direction rather than for a specific target.  The
+distance something can be thrown depends mainly on the type of object
+and your strength.  Arrows can be thrown by hand, but can be thrown
+much farther and will be more likely to hit when thrown while you are
+wielding a bow.
+.pg
+You can simplify the throwing operation by using the `Q' command to
+select your preferred ``missile'', then using the `f' command to
+throw it.  You'll be prompted for a direction as above, but you don't
+have to specify which item to throw each time you use `f'.  There is
+also an option,
+.op autoquiver,
+which has NetHack choose another item to automatically fill your
+quiver when the inventory slot used for `Q' runs out.
+.pg
+Some characters have the ability to fire a volley of multiple items in a
+single turn.  Knowing how to load several rounds of ammunition at
+once -- or hold several missiles in your hand -- and still hit a
+target is not an easy task.  Rangers are among those who are adept
+at this task, as are those with a high level of proficiency in the
+relevant weapon skill (in bow skill if you're wielding one to
+shoot arrows, in crossbow skill if you're wielding one to shoot bolts,
+or in sling skill if you're wielding one to shoot stones).
+The number of items that the character has a chance to fire varies from
+turn to turn.  You can explicitly limit the number of shots by using a
+numeric prefix before the `t' or `f' command.
+For example, ``2f'' (or ``n2f'' if using
+.op number_pad
+mode) would ensure that at most 2 arrows are shot
+even if you could have fired 3.  If you specify
+a larger number than would have been shot (``4f'' in this example),
+you'll just end up shooting the same number (3, here) as if no limit
+had been specified.  Once the volley is in motion, all of the items
+will travel in the same direction; if the first ones kill a monster,
+the others can still continue beyond that spot.
+.hn 3
+Weapon proficiency
+.pg
+You will have varying degrees of skill in the weapons available.
+Weapon proficiency, or weapon skills, affect how well you can use
+particular types of weapons, and you'll be able to improve your skills
+as you progress through a game, depending on your role, your experience
+level, and use of the weapons.
+.pg
+For the purposes of proficiency, weapons have
+been divided up into various groups such as daggers, broadswords, and
+polearms.  Each role has a limit on what level of proficiency a character
+can achieve for each group.  For instance, wizards can become highly
+skilled in daggers or staves but not in swords or bows.
+.pg
+The `#enhance' extended command is used to review current weapons proficiency
+(also spell proficiency) and to choose which skill(s) to improve when
+you've used one or more skills enough to become eligible to do so.  The
+skill rankings are ``none'' (sometimes also referred to as ``restricted'',
+because you won't be able to advance), ``unskilled'', ``basic'', ``skilled'',
+and ``expert''.  Restricted skills simply will not appear in the list
+shown by `#enhance'.  (Divine intervention might unrestrict a particular
+skill, in which case it will start at unskilled and be limited to basic.)
+Some characters can enhance their barehanded combat or martial arts skill
+beyond expert to ``master'' or ``grand master''.
+.pg
+Use of a weapon in which you're restricted or unskilled
+will incur a modest penalty in the chance to hit a monster and also in
+the amount of damage done when you do hit; at basic level, there is no
+penalty or bonus; at skilled level, you receive a modest bonus in the
+chance to hit and amount of damage done; at expert level, the bonus is
+higher.  A successful hit has a chance to boost your training towards
+the next skill level (unless you've already reached the limit for this
+skill).  Once such training reaches the threshold for that next level,
+you'll be told that you feel more confident in your skills.  At that
+point you can use `#enhance' to increase one or more skills.  Such skills
+are not increased automatically because there is a limit to your total
+overall skills, so you need to actively choose which skills to enhance
+and which to ignore.
+.hn 2
+Armor (`[')
+.pg
+Lots of unfriendly things lurk about; you need armor to protect
+yourself from their blows.  Some types of armor offer better
+protection than others.  Your armor class is a measure of this
+protection.  Armor class (AC) is measured as in AD&D, with 10 being
+the equivalent of no armor, and lower numbers meaning better armor.
+Each suit of armor which exists in AD&D gives the same protection in
+NetHack.  Here is an (incomplete) list of the armor classes provided by
+various suits of armor:
+
+.TS S
+center;
+a n.
+dragon scale mail      1
+plate mail     3
+crystal plate mail     3
+bronze plate mail      4
+splint mail    4
+banded mail    4
+dwarvish mithril-coat  4
+elven mithril-coat     5
+chain mail     5
+orcish chain mail      6
+scale mail     6
+studded leather armor  7
+ring mail      7
+orcish ring mail       8
+leather armor  8
+leather jacket 9
+no armor       10
+.TE
+.pg
+You can also wear other pieces of armor (ex. helmets, boots, shields, cloaks)
+to lower your armor class even further, but you can only wear one item
+of each category (one suit of armor, one cloak, one helmet, one
+shield, and so on) at a time.
+.pg
+If a piece of armor is enchanted, its armor protection will be better
+(or worse) than normal, and its ``plus'' (or minus) will subtract from
+your armor class.  For example, a +1 chain mail would give you
+better protection than normal chain mail, lowering your armor class one
+unit further to 4.  When you put on a piece of armor, you immediately
+find out the armor class and any ``plusses'' it provides.  Cursed
+pieces of armor usually have negative enchantments (minuses) in
+addition to being unremovable.
+.pg
+Many types of armor are subject to some kind of damage like rust.  Such
+damage can be repaired.  Some types of armor may inhibit spell casting.
+.pg
+The commands to use armor are `W' (wear) and `T' (take off).
+The `A' command can also be used to take off armor as well as other
+worn items.
+.hn 2
+Food (`%')
+.pg
+Food is necessary to survive.  If you go too long without eating you
+will faint, and eventually die of starvation.  Some types of food will
+spoil, and become unhealthy to eat, if not protected.  Food stored in
+ice boxes or tins (``cans'') will usually stay fresh, but
+ice boxes are heavy, and tins take a while to open.
+.pg
+When you kill monsters, they usually leave corpses which are also
+``food.''  Many, but not all, of these are edible; some also give you
+special powers when you eat them.  A good rule of thumb is ``you are
+what you eat.''
+.pg
+Some character roles and some monsters are vegetarian.  Vegetarian monsters
+will typically never eat animal corpses, while vegetarian players can,
+but with some rather unpleasant side-effects.
+.pg
+You can name one food item after something you like to eat with the
+.op fruit
+option.
+.pg
+The command to eat food is `e'.
+.hn 2
+Scrolls (`?')
+.pg
+Scrolls are labeled with various titles, probably chosen by ancient wizards
+for their amusement value (ex. ``READ ME,'' or ``THANX MAUD'' backwards).
+Scrolls disappear after you read them (except for blank ones, without
+magic spells on them).
+.pg
+One of the most useful of these is the \fIscroll of identify\fP, which
+can be used to determine what another object is, whether it is cursed or
+blessed, and how many uses it has left.  Some objects of subtle
+enchantment are difficult to identify without these.
+.pg
+A mail daemon may run up and deliver mail to you as a
+\fIscroll of mail\fP (on versions compiled with this feature).
+To use this feature on versions where NetHack mail delivery is triggered
+by electronic mail appearing in your system mailbox,
+you must let NetHack know where to look for new mail by setting
+the ``MAIL'' environment variable to the file name of your mailbox.
+You may also want to set the ``MAILREADER'' environment
+variable to the file name of your favorite reader, so NetHack can shell to it
+when you read the scroll.
+On versions of NetHack where mail is randomly generated internal to the game,
+these environment variables are ignored.
+You can disable the mail daemon by turning off the
+.op mail
+option.
+.pg
+The command to read a scroll is `r'.
+.hn 2
+Potions (`!')
+.pg
+Potions are distinguished by the color of the liquid inside the flask.
+They disappear after you quaff them.
+.pg
+Clear potions are potions of water.  Sometimes these are blessed or cursed,
+resulting in holy or unholy water.  Holy water is the bane of the undead, so
+potions of holy water are good things to throw (`t') at them.  It is also
+sometimes very useful to dip (``#dip'') an object into a potion.
+.pg
+The command to drink a potion is `q' (quaff).
+.hn 2
+Wands (`/')
+.pg
+Magic wands usually have multiple magical charges.  Some wands are
+directional\(emyou must give a direction in which to zap them.  You can also
+zap them at yourself (just give a `.' or `s' for the direction). Be warned,
+however, for this is often unwise.  Other wands are nondirectional\(emthey
+don't require a direction.  The number of charges in a wand is random and
+decreases by one whenever you use it.
+.pg
+When the number of charges left in a wand becomes zero, attempts to use the
+wand will usually result in nothing happening.  Occasionally, however, it may
+be possible to squeeze the last few mana points from an otherwise spent wand,
+destroying it in the process.  A wand may be recharged by using suitable
+magic, but doing so runs the risk of causing it to explode.  The chance
+for such an explosion starts out very small and increases each time the
+wand is recharged.
+.pg
+In a truly desperate situation, when your back is up against the wall, you
+might decide to go for broke and break your wand.  This is not for the faint
+of heart.  Doing so will almost certainly cause a catastrophic release of
+magical energies.
+.pg
+When you have fully identified a particular wand, inventory display will
+include additional information in parentheses: the number of times it has
+been recharged followed by a colon and then by its current number of charges.
+A current charge count of -1 is a special case indicating that the wand
+has been cancelled.
+.pg
+The command to use a wand is `z' (zap).  To break one, use the `a' (apply)
+command.
+.hn 2
+Rings (`=')
+.pg
+Rings are very useful items, since they are relatively permanent
+magic, unlike the usually fleeting effects of potions, scrolls, and
+wands.
+.pg
+Putting on a ring activates its magic.  You can wear only two
+rings, one on each ring finger.
+.pg
+Most rings also cause you to grow hungry more rapidly, the rate
+varying with the type of ring.  
+.pg
+The commands to use rings are `P' (put on) and `R' (remove).
+.hn 2
+Spellbooks (`+')
+.pg
+Spellbooks are tomes of mighty magic.  When studied with the `r' (read)
+command, they transfer to the reader the knowledge of a spell (and
+therefore eventually become unreadable) \(em unless the attempt backfires.
+Reading a cursed spellbook or one with mystic runes beyond
+your ken can be harmful to your health!
+.pg
+A spell (even when learned) can also backfire when you cast it.  If you
+attempt to cast a spell well above your experience level, or if you have
+little skill with the appropriate spell type, or cast it at
+a time when your luck is particularly bad, you can end up wasting both the
+energy and the time required in casting.
+.pg
+Casting a spell calls forth magical energies and focuses them with
+your naked mind.  Some of the magical energy released comes from within
+you, and casting several spells in a row may tire you.
+Casting of spells also requires practice.  With practice, your
+skill in each category of spell casting will improve.  Over time, however,
+your memory of each spell will dim, and you will need to relearn it.
+.pg
+Some spells are
+directional\(emyou must give a direction in which to cast them.  You can also
+cast them at yourself (just give a `.' or `s' for the direction). Be warned,
+however, for this is often unwise.  Other spells are nondirectional\(emthey
+don't require a direction.
+.pg
+Just as weapons are divided into groups in which a character can become
+proficient (to varying degrees), spells are similarly grouped.
+Successfully casting a spell exercises the skill group; sufficient skill
+may increase the potency of the spell and reduce the risk of spell failure.
+Skill slots are shared with weapons skills.  (See also the section on
+``Weapon proficiency''.)
+.pg
+Casting a spell also requires flexible movement, and wearing various types
+of armor may interfere with that.
+.pg
+The command to read a spellbook is the same as for scrolls, `r'
+(read).  The `+' command lists your current spells, their levels,
+categories, and chances for failure.  
+The `Z' (cast) command casts a spell.
+.hn 2
+Tools (`(')
+.pg
+Tools are miscellaneous objects with various purposes.  Some tools
+have a limited number of uses, akin to wand charges.  For example, lamps burn
+out after a while.  Other tools are containers, which objects can
+be placed into or taken out of.
+.pg
+The command to use tools is `a' (apply).
+.hn 3
+Containers
+.pg
+You may encounter bags, boxes, and chests in your travels.  A tool of
+this sort can be opened with the ``#loot'' extended command when
+you are standing on top of it (that is, on the same floor spot),
+or with the `a' (apply) command when you are carrying it.  However,
+chests are often locked, and are in any case unwieldy objects.
+You must set one down before unlocking it by
+using a key or lock-picking tool with the `a' (apply) command,
+by kicking it with the `^D' command,
+or by using a weapon to force the lock with the ``#force'' extended command.
+.pg
+Some chests are trapped, causing nasty things to happen when you
+unlock or open them.  You can check for and try to deactivate traps
+with the ``#untrap'' extended command.
+.hn 2
+Amulets (`"')
+.pg
+Amulets are very similar to rings, and often more powerful.  Like
+rings, amulets have various magical properties, some beneficial,
+some harmful, which are activated by putting them on.
+.pg
+Only one amulet may be worn at a time, around your neck.
+.pg
+The commands to use amulets are the same as for rings, `P' (put on)
+and `R' (remove).
+.hn 2
+Gems (`*')
+.pg
+Some gems are valuable, and can be sold for a lot of gold.  They are also
+a far more efficient way of carrying your riches.  Valuable gems increase
+your score if you bring them with you when you exit.
+.pg
+Other small rocks are also categorized as gems, but they are much less
+valuable.  All rocks, however, can be used as projectile weapons (if you
+have a sling).  In the most desperate of cases, you can still throw them
+by hand.
+.hn 2
+Large rocks (`\`')
+.pg
+Statues and boulders are not particularly useful, and are generally
+heavy.  It is rumored that some statues are not what they seem.
+.pg
+Very large humanoids (giants and their ilk) have been known to use boulders
+as weapons.
+.hn 2
+Gold (`$')
+.pg
+Gold adds to your score, and you can buy things in shops with it.
+There are a number
+of monsters in the dungeon that may be influenced by the amount of gold
+you are carrying (shopkeepers aside).
+
+.hn 1
+Conduct
+.pg
+As if winning NetHack were not difficult enough, certain players
+seek to challenge themselves by imposing restrictions on the
+way they play the game.  The game automatically tracks some of
+these challenges, which can be checked at any time with the #conduct
+command or at the end of the game.  When you perform an action which
+breaks a challenge, it will no longer be listed.  This gives
+players extra ``bragging rights'' for winning the game with these
+challenges.  Note that it is perfectly acceptable to win the game
+without resorting to these restrictions and that it is unusual for
+players to adhere to challenges the first time they win the game.
+.pg
+Several of the challenges are related to eating behavior.  The most
+difficult of these is the foodless challenge.  Although creatures
+can survive long periods of time without food, there is a physiological
+need for water; thus there is no restriction on drinking beverages,
+even if they provide some minor food benefits.
+Calling upon your god for help with starvation does
+not violate any food challenges either.
+.pg
+A strict vegan diet is one which avoids any food derived from animals.
+The primary source of nutrition is fruits and vegetables.  The
+corpses and tins of blobs (`b'), jellies (`j'), and fungi (`F') are
+also considered to be vegetable matter.  Certain human
+food is prepared without animal products; namely, lembas wafers, cram
+rations, food rations (gunyoki), K-rations, and C-rations.
+Metal or another normally indigestible material eaten while polymorphed
+into a creature that can digest it is also considered vegan food.
+Note however that eating such items still counts against foodless conduct.
+.pg
+Vegetarians do not eat animals;
+however, they are less selective about eating animal byproducts than vegans.
+In addition to the vegan items listed above, they may eat any kind
+of pudding (`P') other than the black puddings,
+eggs and food made from eggs (fortune cookies and pancakes),
+food made with milk (cream pies and candy bars), and lumps of
+royal jelly.  Monks are expected to observe a vegetarian diet.
+.pg
+Eating any kind of meat violates the vegetarian, vegan, and foodless
+conducts.  This includes tripe rations, the corpses or tins of any
+monsters not mentioned above, and the various other chunks of meat
+found in the dungeon.  Swallowing and digesting a monster while polymorphed
+is treated as if you ate the creature's corpse.
+Eating leather, dragon hide, or bone items while
+polymorphed into a creature that can digest it, or eating monster brains
+while polymorphed into a mind flayer, is considered eating
+an animal, although wax is only an animal byproduct.
+.pg
+Regardless of conduct, there will be some items which are indigestible,
+and others which are hazardous to eat.  Using a swallow-and-digest
+attack against a monster is equivalent to eating the monster's corpse.
+Please note that the term ``vegan'' is used here only in the context of
+diet.  You are still free to choose not to use or wear items derived
+from animals (e.g. leather, dragon hide, bone, horns, coral), but the
+game will not keep track of this for you.  Also note that ``milky''
+potions may be a translucent white, but they do not contain milk,
+so they are compatible with a vegan diet.  Slime molds or
+player-defined ``fruits'', although they could be anything
+from ``cherries'' to ``pork chops'', are also assumed to be vegan.
+.pg
+An atheist is one who rejects religion.  This means that you cannot
+#pray, #offer sacrifices to any god, #turn undead, or #chat with a priest.
+Particularly selective readers may argue that playing Monk or Priest
+characters should violate this conduct; that is a choice left to the
+player.  Offering the Amulet of Yendor to your god is necessary to
+win the game and is not counted against this conduct.  You are also
+not penalized for being spoken to by an angry god, priest(ess), or
+other religious figure; a true atheist would hear the words but
+attach no special meaning to them.
+.pg
+Most players fight with a wielded weapon (or tool intended to be
+wielded as a weapon).  Another challenge is to win the game without
+using such a wielded weapon.  You are still permitted to throw,
+fire, and kick weapons; use a wand, spell, or other type of item;
+or fight with your hands and feet.
+.pg
+In NetHack, a pacifist refuses to cause the death of any other monster
+(i.e. if you would get experience for the death).  This is a particularly
+difficult challenge, although it is still possible to gain experience
+by other means.
+.pg
+An illiterate character cannot read or write.  This includes reading
+a scroll, spellbook, fortune cookie message, or t-shirt; writing a
+scroll; or making an engraving of anything other than a single ``x'' (the
+traditional signature of an illiterate person).  Reading an engraving,
+or any item that is absolutely necessary to win the game, is not counted
+against this conduct.  The identity of scrolls and spellbooks (and
+knowledge of spells) in your starting inventory is assumed to be
+learned from your teachers prior to the start of the game and isn't
+counted.
+.pg
+There are several other challenges tracked by the game.  It is possible
+to eliminate one or more species of monsters by genocide; playing without
+this feature is considered a challenge.  When the game offers you an
+opportunity to genocide monsters, you may respond with the monster type
+``none'' if you want to decline.  You can change the form of an item into
+another item of the same type (``polypiling'') or the form of your own
+body into another creature (``polyself'') by wand, spell, or potion of
+polymorph; avoiding these effects are each considered challenges.
+Polymorphing monsters, including pets, does not break either of these
+challenges.
+Finally, you may sometimes receive wishes; a game without an attempt to
+wish for any items is a challenge, as is a game without wishing for
+an artifact (even if the artifact immediately disappears).  When the
+game offers you an opportunity to make a wish for an item, you may
+choose ``nothing'' if you want to decline.
+
+.hn 1
+Options
+.pg
+Due to variations in personal tastes and conceptions of how NetHack
+should do things, there are options you can set to change how NetHack
+behaves.
+.hn 2
+Setting the options
+.pg
+Options may be set in a number of ways.  Within the game, the `O'
+command allows you to view all options and change most of them.
+You can also set options automatically by placing them in the
+NETHACKOPTIONS environment variable or in a configuration file.
+Some versions of NetHack also have front-end programs that allow
+you to set options before starting the game.
+.hn 2
+Using the NETHACKOPTIONS environment variable
+.pg
+The NETHACKOPTIONS variable is a comma-separated list of initial
+values for the various options.  Some can only be turned on or off.
+You turn one of these on by adding the name of the option to the list,
+and turn it off by typing a `!' or ``no'' before the name.  Others take a 
+character string as a value.  You can set string options by typing
+the option name, a colon or equals sign, and then the value of the string.
+The value is terminated by the next comma or the end of string.
+.pg
+For example, to set up an environment variable so that ``autoquiver'' is on,
+``autopickup'' is off, the name is set to ``Blue Meanie'', and the fruit
+is set to ``papaya'', you would enter the command
+.sd
+% \fBsetenv NETHACKOPTIONS "autoquiver,\e!autopickup,name:Blue Meanie,fruit:papaya"\fP
+.ed
+in \fIcsh\fP (note the need to escape the ! since it's special to the shell), or
+.sd
+$ \fBNETHACKOPTIONS="autoquiver,!autopickup,name:Blue Meanie,fruit:papaya"\fP
+$ \fBexport NETHACKOPTIONS\fP
+.ed
+in \fIsh\fP or \fIksh\fP.
+.hn 2
+Using a configuration file
+.pg
+Any line in the configuration file starting with `#' is treated as a comment.
+Any line in the configuration file starting with ``OPTIONS='' may be
+filled out with options in the same syntax as in NETHACKOPTIONS.
+Any line starting with ``DUNGEON='', ``EFFECTS='', ``MONSTERS='',
+``OBJECTS='', ``TRAPS='', or ``BOULDER=''
+is taken as defining the corresponding
+.op dungeon,
+.op effects,
+.op monsters,
+.op objects
+.op traps
+or
+.op boulder
+option in a different syntax,
+a sequence of decimal numbers giving the character position
+in the current font to be used in displaying each entry.
+A zero in any entry in such a sequence leaves the display of that
+entry unchanged; this feature is not available using the option syntax.
+Such a sequence can be continued to multiple lines by putting a `\e'
+at the end of each line to be continued.
+.pg
+If your copy of the game included the compile time AUTOPICKUP_EXCEPTIONS
+option, then any line starting with ``AUTOPICKUP_EXCEPTION='' is taken
+as defining an exception to the 
+.op pickup_types
+option. 
+There is a section of this Guidebook that discusses that.
+.pg
+The default name of the configuration file varies on different
+operating systems, but NETHACKOPTIONS can also be set to
+the full name of a file you want to use (possibly preceded by an `@').
+.hn 2
+Customization options
+.pg
+Here are explanations of what the various options do.
+Character strings that are too long may be truncated.
+Some of the options listed may be inactive in your dungeon.
+.lp align
+Your starting alignment (align:lawful, align:neutral,
+or align:chaotic).  You may specify just the first letter.
+The default is to randomly pick an appropriate alignment.
+Cannot be set with the `O' command.
+.lp autodig
+Automatically dig if you are wielding a digging tool and moving into a place
+that can be dug (default false).
+.lp "autopickup  "
+Automatically pick up things onto which you move (default on). 
+See
+.op pickup_types
+to refine the behavior.
+.lp "autoquiver  "
+This option controls what happens when you attempt the `f' (fire)
+command with an empty quiver.  When true, the computer will fill
+your quiver with some suitable weapon.  Note that it will not take
+into account the blessed/cursed status, enchantment, damage, or
+quality of the weapon; you are free to manually fill your quiver with
+the `Q' command instead.  If no weapon is found or the option is
+false, the `t' (throw) command is executed instead.  (default false)
+.lp boulder
+Set the character used to display boulders (default is rock class symbol).
+.lp catname
+Name your starting cat (ex. ``catname:Morris'').
+Cannot be set with the `O' command.
+.lp character
+Pick your type of character (ex. ``character:Monk'');
+synonym for ``role''.  See ``name'' for an alternate method
+of specifying your role.  Normally only the first letter of
+the value is examined; the string ``random'' is an exception.
+.lp checkpoint
+Save game state after each level change, for possible recovery after
+program crash (default on).
+.lp checkspace
+Check free disk space before writing files to disk (default on).
+You may have to turn this off if you have more than 2 GB free space
+on the partition used for your save and level files.
+Only applies when MFLOPPY was defined during compilation.
+.lp cmdassist
+Have the game provide some additional command assistance for 
+new players if it detects some anticipated mistakes (default on).
+.lp "confirm "
+Have user confirm attacks on pets, shopkeepers, and other
+peaceable creatures (default on).
+.lp DECgraphics
+Use a predefined selection of characters from the DEC VT-xxx/DEC
+Rainbow/ANSI line-drawing character set to display the dungeon/effects/traps
+instead of having to define a full graphics set yourself (default off).
+This option also sets up proper handling of graphics
+characters for such terminals, so you should specify it when appropriate
+even if you override the selections with your own graphics strings.
+.lp disclose
+Controls options for disclosing various information when the game ends (defaults
+to all possibilities being disclosed).
+The possibilities are:
+.sd
+.si
+i - disclose your inventory.
+a - disclose your attributes.
+v - summarize monsters that have been vanquished.
+g - list monster species that have been genocided.
+c - display your conduct.
+.ei
+.ed
+Each disclosure possibility can optionally be preceded by a prefix which
+let you refine how it behaves. Here are the valid prefixes:
+.sd
+.si
+y - prompt you and default to yes on the prompt.
+n - prompt you and default to no on the prompt.
++ - disclose it without prompting.
+- - do not disclose it and do not prompt.
+.ei
+.ed
+(ex. ``disclose:yi na +v -g -c'')
+The example sets 
+.op inventory
+to prompt and default to yes,
+.op attributes
+to prompt and default to no,
+.op vanquished
+to disclose without prompting,
+.op genocided
+to not disclose and not to prompt,
+.op conduct
+to not disclose and not to prompt.
+Note that the vanquished monsters list includes all monsters killed by
+traps and each other as well as by you.
+.lp dogname
+Name your starting dog (ex. ``dogname:Fang'').
+Cannot be set with the `O' command.
+.lp dungeon
+Set the graphics symbols for displaying the dungeon
+(default \&``\ |--------||.-|++##.##<><>_|\e\e#{}.}..##\ #}'').
+The
+.op dungeon
+option should be followed by a string of 1-41
+characters to be used instead of the default map-drawing characters.
+The dungeon map will use the characters you specify instead of the
+default symbols, and default symbols for any you do not specify.
+Remember that you may need to escape some of these characters
+on a command line if they are special to your shell.
+
+Note that NetHack escape-processes this option string in conventional C
+fashion.  This means that `\e' is a prefix to take the following
+character literally.  Thus `\e' needs to be represented as `\e\e'.
+The special escape
+form `\em' switches on the meta bit in the following character, and the `^'
+prefix causes the following character to be treated as a control
+character.
+
+The order of the symbols is:  solid rock, vertical wall, horizontal
+wall, upper left corner, upper right corner, lower left corner, lower
+right corner, cross wall, upward T wall, downward T wall, leftward T
+wall, rightward T wall, no door, vertical open door, horizontal open
+door, vertical closed door, horizontal closed door, iron bars, tree,
+floor of a room, dark corridor, lit corridor, stairs up, stairs down,
+ladder up, ladder down, altar, grave, throne, kitchen sink, fountain, pool or moat,
+ice, lava, vertical lowered drawbridge, horizontal lowered drawbridge,
+vertical raised drawbridge, horizontal raised drawbridge, air, cloud,
+under water.
+
+You might want to use `+' for the corners and T walls for a more
+aesthetic, boxier display.  Note that in the next release, new symbols
+may be added, or the present ones rearranged.
+
+Cannot be set with the `O' command.
+.lp effects
+Set the graphics symbols for displaying special effects
+(default \&``|-\e\e/*!)(0#@*/-\e\e||\e\e-//-\e\e|\ |\e\e-/'').
+The
+.op effects
+option should be followed by a string of 1-29
+characters to be used instead of the default special-effects characters.
+This string is subjected to the same processing as the
+.op dungeon
+option.
+
+The order of the symbols is:  vertical beam, horizontal beam, left slant,
+right slant, digging beam, camera flash beam, left boomerang, right boomerang,
+four glyphs giving the sequence for magic resistance displays,
+the eight surrounding glyphs for swallowed display,
+nine glyphs for explosions.
+An explosion consists of three rows (top, middle, and bottom) of three
+characters.  The explosion is centered in the center of this 3 by 3
+array.
+
+Note that in the next release, new symbols may be added,
+or the present ones rearranged.
+
+Cannot be set with the `O' command.
+.lp extmenu
+Changes the extended commands interface to pop-up a menu of available commands.  
+It is keystroke compatible with the traditional interface except that it does
+not require that you hit Enter. It is implemented only by the tty port 
+(default off), when the game has been compiled to support tty graphics.
+.lp female
+An obsolete synonym for ``gender:female''.
+Cannot be set with the `O' command.
+.lp fixinv
+An object's inventory letter sticks to it when it's dropped (default on).
+If this is off, dropping an object shifts all the remaining inventory letters.
+.lp "fruit   "
+Name a fruit after something you enjoy eating (ex. ``fruit:mango'')
+(default ``slime mold'').  Basically a nostalgic whimsy that NetHack uses
+from time to time.  You should set this to something you find more
+appetizing than slime mold.  Apples, oranges, pears, bananas, and melons
+already exist in NetHack, so don't use those.
+.lp gender
+Your starting gender (gender:male or gender:female).
+You may specify just the first letter.  Although you can
+still denote your gender using the ``male'' and ``female''
+options, the ``gender'' option will take precedence.
+The default is to randomly pick an appropriate gender.
+Cannot be set with the `O' command.
+.lp help
+If more information is available for an object looked at
+with the `/' command, ask if you want to see it (default on). Turning help
+off makes just looking at things faster, since you aren't interrupted with the
+``More info?'' prompt, but it also means that you might miss some
+interesting and/or important information.
+.lp horsename
+Name your starting horse (ex. ``horsename:Trigger'').
+Cannot be set with the `O' command.
+.lp IBMgraphics
+Use a predefined selection of IBM extended ASCII characters to display the
+dungeon/effects/traps instead of having to define a full graphics set
+yourself (default off).
+This option also sets up proper handling of graphics
+characters for such terminals, so you should specify it when appropriate
+even if you override the selections with your own graphics strings.
+.lp ignintr
+Ignore interrupt signals, including breaks (default off).
+.lp legacy
+Display an introductory message when starting the game (default on).
+.lp lit_corridor
+Show corridor squares seen by night vision or a light source held by your
+character as lit (default off).
+.lp lootabc
+Use the old `a', `b', and `c' keyboard shortcuts when
+looting, rather than the mnemonics `o', `i', and `b' (default off).
+.lp "mail    "
+Enable mail delivery during the game (default on).
+.lp "male    "
+An obsolete synonym for ``gender:male''.
+Cannot be set with the `O' command.
+.lp menustyle
+Controls the interface used when you need to choose various objects (in
+response to the Drop command, for instance).  The value specified should
+be the first letter of one of the following:  traditional, combination,
+partial, or full.  Traditional was the only interface available for
+earlier versions; it consists of a prompt for object class characters,
+followed by an object-by-object prompt for all items matching the selected
+object class(es).  Combination starts with a prompt for object class(es)
+of interest, but then displays a menu of matching objects rather than
+prompting one-by-one.  Partial skips the object class filtering and
+immediately displays a menu of all objects.  Full displays a menu of
+object classes rather than a character prompt, and then a menu of matching
+objects for selection.
+.lp menu_deselect_all
+Menu character accelerator to deselect all items in a menu.
+Implemented by the Amiga, Gem, X11 and tty ports.
+Default '-'.
+.lp menu_deselect_page
+Menu character accelerator to deselect all items on this page of a menu.
+Implemented by the Amiga, Gem and tty ports.
+Default '\e'.
+.lp menu_first_page
+Menu character accelerator to jump to the first page in a menu.
+Implemented by the Amiga, Gem and tty ports.
+Default '^'.
+.lp menu_headings
+Controls how the headings in a menu are highlighted.
+Values are 'bold', 'inverse', or 'underline'.
+Not all ports can actually display all three types.
+.lp menu_invert_all
+Menu character accelerator to invert all items in a menu.
+Implemented by the Amiga, Gem, X11 and tty ports.
+Default '@'.
+.lp menu_invert_page
+Menu character accelerator to invert all items on this page of a menu.
+Implemented by the Amiga, Gem and tty ports.
+Default '~'.
+.lp menu_last_page
+Menu character accelerator to jump to the last page in a menu.
+Implemented by the Amiga, Gem and tty ports.
+Default '|'.
+.lp menu_next_page
+Menu character accelerator to goto the next menu page.
+Implemented by the Amiga, Gem and tty ports.
+Default '>'.
+.lp menu_previous_page 
+Menu character accelerator to goto the previous menu page.
+Implemented by the Amiga, Gem and tty ports.
+Default '<'.
+.lp menu_search
+Menu character accelerator to search for a menu item.
+Implemented by the Amiga, Gem and X11 ports.
+Default ':'.
+.lp menu_select_all
+Menu character accelerator to select all items in a menu.
+Implemented by the Amiga, Gem, X11 and tty ports.
+Default '.'.
+.lp menu_select_page
+Menu character accelerator to select all items on this page of a menu.
+Implemented by the Amiga, Gem and tty ports.
+Default ','.
+.lp monsters
+Set the characters used to display monster classes (default
+``abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@\ \'&;:~]'').
+This string is subjected to the same processing as the
+.op dungeon
+option.
+The order of the symbols is
+ant or other insect, blob, cockatrice,
+dog or other canine, eye or sphere, feline,
+gremlin, humanoid, imp or minor demon,
+jelly, kobold, leprechaun,
+mimic, nymph, orc,
+piercer, quadruped, rodent,
+arachnid or centipede, trapper or lurker above, horse or unicorn,
+vortex, worm, xan or other mythical/fantastic insect,
+light, zruty,
+angelic being, bat or bird, centaur,
+dragon, elemental, fungus or mold,
+gnome, giant humanoid, invisible monster,
+jabberwock, Keystone Kop, lich,
+mummy, naga, ogre,
+pudding or ooze, quantum mechanic, rust monster,
+snake, troll, umber hulk,
+vampire, wraith, xorn,
+apelike creature, zombie,
+human, ghost, golem,
+demon, sea monster, lizard,
+long worm tail, and mimic.
+Cannot be set with the `O' command.
+.lp msghistory
+The number of top line messages to save (and recall with ^P) (default 20).
+Cannot be set with the `O' command.
+.lp msg_window
+Allows you to change the way recalled messages are displayed.
+(It is currently implemented for tty only.)
+The possible values are:
+.sd
+.si
+s - single message (default, this was the behavior before 3.4.0).
+c - combination, two messages as `single', then as `full'.
+f - full window, oldest message first.
+r - full window, newest message first.
+.ei
+.ed
+For backward compatibility, no value needs to be specified (which
+defaults to `full'), or it can be negated (which defaults to `single').
+.lp "name    "
+Set your character's name (defaults to your user name).  You can also
+set your character's role by appending a dash and one or more letters of
+the role (that is, by suffixing one of
+.op "-A -B -C -H -K -M -P -Ra -Ro -S -T -V -W" ).
+If
+.op "-@"
+is used for the role, then a random one will be automatically chosen.
+Cannot be set with the `O' command.
+.lp "news    "
+Read the NetHack news file, if present (default on).
+Since the news is shown at the beginning of the game, there's no point
+in setting this with the `O' command.
+.lp "null    "
+Send padding nulls to the terminal (default off).
+.lp number_pad
+Use the number keys to move instead of [yuhjklbn] (default 0 or off).
+(number_pad:2 invokes the old DOS behavior where `5' means `g', meta-`5'
+means `G',  and meta-`0' means `I'.)
+.lp objects
+Set the characters used to display object classes
+(default ``])[="(%!?+/$*`0_.'').
+This string is subjected to the same processing as the
+.op dungeon
+option.
+The order of the symbols is
+illegal-object (should never be seen), weapon, armor, ring, amulet, tool,
+food, potion, scroll, spellbook, wand, gold, gem or rock, boulder or statue,
+iron ball, chain, and venom.
+Cannot be set with the `O' command.
+.lp packorder
+Specify the order to list object types in (default ``")[%?+!=/(*`0_'').
+The value of this option should be a string containing the
+symbols for the various object types.  Any omitted types are filled in
+at the end from the previous order.
+.lp perm_invent
+If true, always display your current inventory in a window.  This only
+makes sense for windowing system interfaces that implement this feature.
+.lp pettype
+Specify the type of your initial pet, if you are playing a character class
+that uses multiple types of pets; or choose to have no initial pet at all.
+Possible values are ``cat'', ``dog'' and ``none''.
+Cannot be set with the `O' command.
+.lp pickup_burden
+When you pick up an item that would exceed this encumbrance
+level (Unburdened, Burdened, streSsed, straiNed, overTaxed,
+or overLoaded), you will be asked if you want to continue.
+(Default `S').
+.lp pickup_types
+Specify the object types to be picked up when
+.op autopickup
+is on.  Default is all types.  If your copy of the game has the experimental
+compile time option AUTOPICKUP_EXCEPTIONS included, you may be able to use 
+.op autopickup_exception
+configuration file lines to further refine
+.op autopickup
+behavior.
+.lp prayconfirm
+Prompt for confirmation before praying (default on).
+.lp pushweapon
+Using the `w' (wield) command when already wielding
+something pushes the old item into your alternate weapon slot (default off).
+.lp race
+Selects your race (for example, ``race:human'').  Default is random.
+Cannot be set with the `O' command.
+.lp rest_on_space
+Make the space bar a synonym for the `.' (rest) command (default off).
+.lp "role    "
+Pick your type of character (ex. ``role:Samurai'');
+synonym for ``character''.  See ``name'' for an alternate method
+of specifying your role.  Normally only the first letter of the
+value is examined; `r' is an exception with ``Rogue'', ``Ranger'',
+and ``random'' values.
+.lp runmode
+Controls the amount of screen updating for the map window when engaged
+in multi-turn movement (running via shift+direction or control+direction
+and so forth, or via the travel command or mouse click).
+The possible values are:
+.sd
+.si
+teleport - update the map after movement has finished;
+run - update the map after every seven or so steps;
+walk - update the map after each step;
+crawl - like walk, but pause briefly after each step.
+.ei
+.ed
+This option only affects the game's screen display, not the actual
+results of moving.  The default is `run'; versions prior to 3.4.1 
+used `teleport' only.  Whether or not the effect is noticeable will
+depend upon the window port used or on the type of terminal.
+.lp safe_pet
+Prevent you from (knowingly) attacking your pets (default on).
+.lp scores
+Control what parts of the score list you are shown at the end (ex.
+``scores:5 top scores/4 around my score/own scores'').  Only the first
+letter of each category (`t', `a', or `o') is necessary.
+.lp showexp
+Show your accumulated experience points on bottom line (default off).
+.lp showrace
+Display yourself as the glyph for your race, rather than the glyph
+for your role (default off).  Note that this setting affects only
+the appearance of the display, not the way the game treats you.
+.lp showscore
+Show your approximate accumulated score on bottom line (default off).
+.lp "silent  "
+Suppress terminal beeps (default on).
+.lp sortpack
+Sort the pack contents by type when displaying inventory (default on).
+.lp sound
+Enable messages about what your character hears (default on).
+Note that this has nothing to do with your computer's audio capabilities.
+This option is only partly under player control.  The game toggles it
+off and on during and after sleep, for example.
+.lp sparkle
+Display a sparkly effect when a monster (including yourself) is hit by an
+attack to which it is resistant (default on).
+.lp standout
+Boldface monsters and ``\fB--More--\fP'' (default off).
+.lp suppress_alert
+This option may be set to a NetHack version level to suppress
+alert notification messages about feature changes for that 
+and prior versions (ex. ``suppress_alert:3.3.1'').
+.lp "time    "
+Show the elapsed game time in turns on bottom line (default off).
+.lp timed_delay
+When pausing momentarily for display effect, such as with explosions and
+moving objects, use a timer rather than sending extra characters to the
+screen.  (Applies to ``tty'' interface only; ``X11'' interface always
+uses a timer based delay.  The default is on if configured into the
+program.)
+.lp tombstone
+Draw a tombstone graphic upon your death (default on).
+.lp toptenwin
+Put the ending display in a NetHack window instead of on stdout (default off).
+Setting this option makes the score list visible when a windowing version
+of NetHack is started without a parent window, but it no longer leaves
+the score list around after game end on a terminal or emulating window.
+.lp traps
+Set the graphics symbols for displaying traps
+(default \&``^^^^^^^^^^^^^^^^^"^^^^'').
+The
+.op traps
+option should be followed by a string of 1-22
+characters to be used instead of the default traps characters.
+This string is subjected to the same processing as the
+.op dungeon
+option.
+
+The order of the symbols is: 
+arrow trap, dart trap, falling rock trap, squeaky board, bear trap,
+land mine, rolling boulder trap, sleeping gas trap, rust trap, fire trap,
+pit, spiked pit, hole, trap door, teleportation trap, level teleporter,
+magic portal, web, statue trap, magic trap, anti-magic field, polymorph trap.
+
+Cannot be set with the `O' command.
+.lp travel
+Allow the travel command (default on).  Turning this option off will
+prevent the game from attempting unintended moves if you make inadvertent
+mouse clicks on the map window.
+.lp verbose
+Provide more commentary during the game (default on).
+.lp windowtype
+Select which windowing system to use, such as ``tty'' or ``X11''
+(default depends on version).
+Cannot be set with the `O' command.
+.hn 2
+Window Port Customization options
+.pg
+Here are explanations of the various options that are
+used to customize and change the characteristics of the
+windowtype that you have chosen.
+Character strings that are too long may be truncated.
+Not all window ports will adjust for all settings listed
+here.  You can safely add any of these options to your config
+file, and if the window port is capable of adjusting to
+suit your preferences, it will attempt to do so. If it
+can't it will silently ignore it.  You can find out if an
+option is supported by the window port that you are currently
+using by checking to see if it shows up in the Options list.
+Some options are dynamic and can be specified during the game
+with the `O' command.
+.lp align_message
+Where to align or place the message window (top, bottom, left, or right)
+.lp align_status
+Where to align or place the status window (top, bottom, left, or right).
+.lp ascii_map
+NetHack should display an ascii character map if it can.
+.lp color              
+NetHack should display color if it can for different monsters, 
+objects, and dungeon features
+.lp eight_bit_tty      
+NetHack should pass eight-bit character values (for example, specified with the
+.op traps
+option) straight through to your terminal (default off).
+.lp font_map   
+NetHack should use a font by the chosen name for the map window.
+.lp font_menu  
+NetHack should use a font by the chosen name for menu windows.
+.lp font_message       
+NetHack should use a font by the chosen name for the message window.
+.lp font_status        
+NetHack should use a font by the chosen name for the status window.
+.lp font_text  
+NetHack should use a font by the chosen name for text windows.
+.lp font_size_map      
+NetHack should use this size font for the map window.
+.lp font_size_menu     
+NetHack should use this size font for menu windows.
+.lp font_size_message 
+NetHack should use this size font for the message window.
+.lp font_size_status
+NetHack should use this size font for the status window.
+.lp font_size_text     
+NetHack should use this size font for text windows.
+.lp fullscreen
+NetHack should try and display on the entire screen rather than in a window.
+.lp hilite_pet
+Visually distinguish pets from similar animals (default off).
+The behavior of this option depends on the type of windowing you use.
+In text windowing, text highlighting or inverse video is often used;
+with tiles, generally displays a heart symbol near pets.
+.lp large_font 
+NetHack should use a large font.
+.lp map_mode   
+NetHack should display the map in the manner specified.
+.lp mouse_support
+Allow use of the mouse for input and travel.
+.lp player_selection
+NetHack should pop up dialog boxes, or use prompts for character selection.
+.lp popup_dialog       
+NetHack should pop up dialog boxes for input.
+.lp preload_tiles
+NetHack should preload tiles into memory.
+For example, in the protected mode MSDOS version, control whether tiles
+get pre-loaded into RAM at the start of the game.  Doing so
+enhances performance of the tile graphics, but uses more memory. (default on).
+Cannot be set with the `O' command.
+.lp scroll_amount
+NetHack should scroll the display by this number of cells
+when the hero reaches the scroll_margin.
+.lp scroll_margin
+NetHack should scroll the display when the hero or cursor
+is this number of cells away from the edge of the window.
+.lp softkeyboard
+Display an onscreen keyboard.  Handhelds are most likely to support this option.
+.lp splash_screen
+NetHack should display an opening splash screen when it starts up (default yes).
+.lp tiled_map  
+NetHack should display a tiled map if it can.
+.lp tile_file
+Specify the name of an alternative tile file to override the default.
+.lp tile_height
+Specify the preferred height of each tile in a tile capable port.
+.lp tile_width
+Specify the preferred width of each tile in a tile capable port
+.lp use_inverse
+NetHack should display inverse when the game specifies it.
+.lp vary_msgcount
+NetHack should display this number of messages at a time in
+the message window.
+.lp windowcolors
+NetHack should display windows with the specified foreground/background
+colors if it can.
+.lp wraptext
+NetHack port should wrap long lines of text if they don't fit in 
+the visible area of the window.
+.hn 2
+Platform-specific Customization options
+.pg
+Here are explanations of options that are used by specific platforms or ports 
+to customize and change the port behavior.
+.lp altkeyhandler
+Select an alternate keystroke handler dll to load (Win32 tty NetHack only).
+The name of the handler is specified without the .dll extension and without any
+path information.
+Cannot be set with the `O' command.
+.lp altmeta
+(default on, AMIGA NetHack only).
+.lp "BIOS    "
+Use BIOS calls to update the screen
+display quickly and to read the keyboard (allowing the use of arrow
+keys to move) on machines with an IBM PC compatible BIOS ROM (default off,
+OS/2, PC, and ST NetHack only).
+.lp flush
+(default off, AMIGA NetHack only).
+.lp "MACgraphics"
+(default on, Mac NetHack only).
+.lp page_wait
+(default on, Mac NetHack only).
+.lp "rawio   "
+Force raw (non-cbreak) mode for faster output and more
+bulletproof input (MS-DOS sometimes treats `^P' as a printer toggle
+without it) (default off, OS/2, PC, and ST NetHack only).
+Note:  DEC Rainbows hang if this is turned on.
+Cannot be set with the `O' command.
+.lp soundcard
+(default on, PC NetHack only).
+Cannot be set with the `O' command.
+.lp subkeyvalue
+(Win32 tty NetHack only).
+May be used to alter the value of keystrokes that the operating system
+returns to NetHack to help compensate for international keyboard issues.
+OPTIONS=subkeyvalue:171/92
+will return 92 to NetHack, if 171 was originally going to be returned.
+You can use multiple subkeyvalue statements in the config file if needed.
+Cannot be set with the `O' command.
+.lp video
+Set the video mode used (PC NetHack only).
+Values are `autodetect', `default', or `vga'.
+Setting `vga' (or `autodetect' with vga hardware present) will cause
+the game to display tiles. 
+Cannot be set with the `O' command.
+.lp videocolors
+Set the color palette for PC systems using NO_TERMS
+(default 4-2-6-1-5-3-15-12-10-14-9-13-11, (PC NetHack only).
+The order of colors is red, green, brown, blue, magenta, cyan,
+bright.white, bright.red, bright.green, yellow, bright.blue,
+bright.magenta, and bright.cyan.
+Cannot be set with the `O' command.
+.lp videoshades
+Set the intensity level of the three gray scales available
+(default dark normal light, PC NetHack only).
+If the game display is difficult to read, try adjusting these scales;
+if this does not correct the problem, try !color.
+Cannot be set with the `O' command.
+.hn 2
+Configuring autopickup exceptions
+.pg
+There is an experimental compile time option called AUTOPICKUP_EXCEPTIONS.  
+If your copy of the game was built with that option defined, you can 
+further refine the behavior of the
+.op autopickup
+option beyond what is available through the 
+.op pickup_types
+option. 
+.pg
+By placing 
+.op autopickup_exception
+lines in your configuration
+file, you can define patterns to be checked when the game is about to
+autopickup something.
+.lp autopickup_exception
+Sets an exception to the 
+.op pickup_types
+option.
+The
+.op autopickup_exception
+option should be followed by a string of 1-80 characters to be used as a 
+pattern to match against the singular form of the description of an 
+object at your location.
+.pg
+You may use the following special characters in a pattern:
+.sd
+.si
+  *--- matches 0 or more characters.
+  ?--- matches any single character.
+.ei
+.ed
+.pg
+In addition, some characters are treated specially if they occur as the first 
+character in the string pattern, specifically:
+.sd
+.si
+< - always pickup an object that matches the pattern that follows.
+> - never pickup an object that matches the pattern that follows.
+.ei
+.ed
+.pg
+Can be set with the `O' command, but the setting is not preserved
+across saves and restores.
+.pg
+Here's a couple of examples of autopickup_exceptions:
+.sd
+.si
+autopickup_exception="<*arrow"
+autopickup_exception=">*corpse"
+autopickup_exception=">* cursed*"
+.ei
+.ed
+The first example above will result in autopickup of any type of arrow.
+The second example results in the exclusion of any corpse from autopickup.
+The last example results in the exclusion of items known to be cursed from autopickup.
+A `never pickup' rule takes precedence over an `always pickup' rule if both match.
+.hn 2
+Configuring User Sounds
+.pg
+Some platforms allow you to define sound files to be played when a message 
+that matches a user-defined pattern is delivered to the message window.
+At this time the Qt port and the win32tty and win32gui ports support the
+use of user sounds.
+.pg
+The following config file entries are relevant to mapping user sounds
+to messages:
+.lp SOUNDDIR
+The directory that houses the sound files to be played.
+.lp SOUND
+An entry that maps a sound file to a user-specified message pattern.
+Each SOUND entry is broken down into the following parts:
+.sd
+.si
+MESG       - message window mapping (the only one supported in 3.4).
+pattern    - the pattern to match.
+sound file - the sound file to play.
+volume     - the volume to be set while playing the sound file.
+.ei
+.ed
+.pg
+The exact format for the pattern depends on whether the platform is
+built to use ``regular expressions'' or NetHack's own internal pattern 
+matching facility. The ``regular expressions'' matching can be much more 
+sophisticated than the internal NetHack pattern matching, but requires 
+3rd party libraries on some platforms.  There are plenty of references 
+available elsewhere for explaining ``regular expressions''. You can verify 
+which pattern matching is used by your port with the #version command.  
+.pg
+NetHack's internal pattern matching routine uses the following
+special characters in its pattern matching:
+.sd
+.si
+  *--- matches 0 or more characters.
+  ?--- matches any single character.
+.ei
+.ed
+.pg
+Here's an example of a sound mapping using NetHack's internal
+pattern matching facility:
+.sd
+    SOUND=MESG "*chime of a cash register*" "gong.wav" 50
+.ed
+specifies that any message with "chime of a cash register" contained
+in it will trigger the playing of "gong.wav".  You can have multiple
+SOUND entries in your config file.
+.pg
+.hn 2
+Configuring NetHack for Play by the Blind
+.pg
+NetHack can be set up to use only standard ASCII characters for making
+maps of the dungeons. This makes the MS-DOS versions of NetHack completely
+accessible to the blind who use speech and/or Braille access technologies.
+Players will require a good working knowledge of their screen-reader's
+review features, and will have to know how to navigate horizontally and
+vertically character by character. They will also find the search
+capabilities of their screen-readers to be quite valuable. Be certain to
+examine this Guidebook before playing so you have an idea what the screen
+layout is like. You'll also need to be able to locate the PC cursor. It is
+always where your character is located. Merely searching for an @-sign will
+not always find your character since there are other humanoids represented
+by the same sign. Your screen-reader should also have a function which
+gives you the row and column of your review cursor and the PC cursor.
+These co-ordinates are often useful in giving players a better sense of the
+overall location of items on the screen.
+.pg
+While it is not difficult for experienced users to edit the \fBdefaults.nh\fP
+file to accomplish this, novices may find this task somewhat daunting.
+Included in all official distributions of NetHack is a file called
+\fBNHAccess.nh\fP.  Replacing \fBdefaults.nh\fP with this file will cause
+the game to run in a manner accessible to the blind. After you have gained
+some experience with the game and with editing files, you may want to alter
+settings to better suit your preferences. Instructions on how to do this
+are included in the \fBNHAccess.nh\fP file itself. The most crucial settings to
+make the game accessible are:
+.pg
+.lp IBMgraphics
+Disable IBMgraphics by commenting out this option.
+.lp menustyle:traditional
+This will assist in the interface to speech synthesizers.
+.lp number_pad
+A lot of speech access programs use the number-pad to review the screen.
+If this is the case, disable the number_pad option and use the traditional
+Rogue-like commands.
+.lp "Character graphics"
+Comment out all character graphics sets found near the bottom of the
+\fBdefaults.nh\fP file.  Most of these replace \fBNetHack\fP's
+default representation of the dungeon using standard ASCII characters
+with fancier characters from extended character sets, and these fancier
+characters can annoy screen-readers.
+.hn 1
+Scoring
+.pg
+NetHack maintains a list of the top scores or scorers on your machine,
+depending on how it is set up.  In the latter case, each account on
+the machine can post only one non-winning score on this list.  If
+you score higher than someone else on this list, or better your
+previous score, you will be inserted in the proper place under your
+current name.  How many scores are kept can also be set up when
+NetHack is compiled.
+.pg
+Your score is chiefly based upon how much experience you gained, how
+much loot you accumulated, how deep you explored, and how the game
+ended.  If you quit the game, you escape with all of your gold intact.
+If, however, you get killed in the Mazes of Menace, the guild will
+only hear about 90% of your gold when your corpse is discovered
+(adventurers have been known to collect finder's fees).  So, consider
+whether you want to take one last hit at that monster and possibly
+live, or quit and stop with whatever you have.  If you quit, you keep
+all your gold, but if you swing and live, you might find more.
+.pg
+If you just want to see what the current top players/games list is, you
+can type \fBnethack -s all\fP on most versions.
+
+.hn 1
+Explore mode
+.pg
+NetHack is an intricate and difficult game.  Novices might falter
+in fear, aware of their ignorance of the means to survive.  Well, fear
+not.  Your dungeon may come equipped with an ``explore'' or ``discovery''
+mode that enables you to keep old save files and cheat death, at the
+paltry cost of not getting on the high score list.
+.pg
+There are two ways of enabling explore mode.  One is to start the game
+with the
+.op -X
+switch.  The other is to issue the `X' command while already playing
+the game.  The other benefits of explore mode are left for the trepid
+reader to discover.
+
+.hn
+Credits
+.pg
+The original \fIhack\fP game was modeled on the Berkeley 
+.ux
+\fIrogue\fP game.  Large portions of this paper were shamelessly
+cribbed from \fIA Guide to the Dungeons of Doom\fP, by Michael C. Toy
+and Kenneth C. R. C. Arnold.  Small portions were adapted from
+\fIFurther Exploration of the Dungeons of Doom\fP, by Ken Arromdee.
+.pg
+NetHack is the product of literally dozens of people's work.
+Main events in the course of the game development are described below:
+
+.pg
+\fBJay Fenlason\fP wrote the original Hack, with help from
+\fBKenny Woodland\fP, \fBMike Thome\fP and \fBJon Payne\fP.
+.pg
+\fBAndries Brouwer\fP did a major re-write, transforming Hack into a
+very different game, and published (at least) three versions (1.0.1,
+1.0.2, and 1.0.3) for
+.ux
+machines to the Usenet.
+.pg
+\fBDon G. Kneller\fP ported Hack 1.0.3 to Microsoft C and MS-DOS, producing PC
+HACK 1.01e, added support for DEC Rainbow graphics in version 1.03g, and went
+on to produce at least four more versions (3.0, 3.2, 3.51, and 3.6).
+.pg
+\fBR. Black\fP ported PC HACK 3.51 to Lattice C and the Atari 520/1040ST,
+producing ST Hack 1.03.
+.pg
+\fBMike Stephenson\fP merged these various versions back together,
+incorporating many of the added features, and produced NetHack 1.4.
+He then coordinated a cast of thousands in enhancing and debugging
+NetHack 1.4 and released NetHack versions 2.2 and 2.3.
+.pg
+Later, Mike coordinated a major rewrite of the game, heading a
+team which included \fBKen Arromdee\fP, \fBJean-Christophe Collet\fP, \fBSteve
+Creps\fP, \fBEric Hendrickson\fP, \fBIzchak Miller\fP, \fBJohn Rupley\fP,
+\fBMike Threepoint\fP, and \fBJanet Walz\fP, to produce NetHack 3.0c.
+.pg
+NetHack 3.0 was ported to the Atari by \fBEric R. Smith\fP, to OS/2 by
+\fBTimo Hakulinen\fP, and to VMS by \fBDavid Gentzel\fP.  The three of them
+and \fBKevin Darcy\fP later joined the main development team to produce
+subsequent revisions of 3.0.
+.pg
+\fBOlaf Seibert\fP ported NetHack 2.3 and 3.0 to the Amiga.
+\fBNorm Meluch\fP, \fBStephen Spackman\fP and \fBPierre Martineau\fP designed
+overlay code for PC NetHack 3.0.  \fBJohnny Lee\fP ported
+NetHack 3.0 to the Macintosh.  Along with various other Dungeoneers, they
+continued to enhance the PC, Macintosh, and Amiga ports through the later
+revisions of 3.0.
+.pg
+Headed by \fBMike Stephenson\fP and coordinated by \fBIzchak Miller\fP and
+\fBJanet Walz\fP, the development team which now included \fBKen Arromdee\fP,
+\fBDavid Cohrs\fP, \fBJean-Christophe Collet\fP, \fBKevin Darcy\fP,
+\fBMatt Day\fP, \fBTimo Hakulinen\fP, \fBSteve Linhart\fP, \fBDean Luick\fP,
+\fBPat Rankin\fP, \fBEric Raymond\fP, and \fBEric Smith\fP undertook a radical
+revision of 3.0.  They re-structured the game's design, and re-wrote major
+parts of the code.  They added multiple dungeons, a new display, special
+individual character quests, a new endgame and many other new features, and
+produced NetHack 3.1.
+.pg
+\fBKen Lorber\fP, \fBGregg Wonderly\fP and \fBGreg Olson\fP, with help
+from \fBRichard Addison\fP, \fBMike Passaretti\fP, and \fBOlaf Seibert\fP,
+developed NetHack 3.1 for the Amiga.
+.pg
+\fBNorm Meluch\fP and \fBKevin Smolkowski\fP, with help from
+\fBCarl Schelin\fP, \fBStephen Spackman\fP, \fBSteve VanDevender\fP,
+and \fBPaul Winner\fP, ported NetHack 3.1 to the PC.
+.pg
+\fBJon W{tte\fP and \fBHao-yang Wang\fP, with help from \fBRoss Brown\fP,
+\fBMike Engber\fP, \fBDavid Hairston\fP, \fBMichael Hamel\fP,
+\fBJonathan Handler\fP, \fBJohnny Lee\fP, \fBTim Lennan\fP, \fBRob Menke\fP,
+and \fBAndy Swanson\fP, developed NetHack 3.1 for the Macintosh,
+porting it for MPW.  Building on their development, \fBBarton House\fP
+added a Think C port.
+.pg
+\fBTimo Hakulinen\fP ported NetHack 3.1 to OS/2.  \fBEric Smith\fP
+ported NetHack 3.1 to the Atari.  \fBPat Rankin\fP, with help from
+\fBJoshua Delahunty\fP, was responsible for the VMS version of NetHack 3.1.
+\fBMichael Allison\fP ported NetHack 3.1 to Windows NT.
+.pg
+\fBDean Luick\fP, with help from \fBDavid Cohrs\fP, developed NetHack
+3.1 for X11.
+\fBWarwick Allison\fP wrote a tiled version of NetHack for the Atari;
+he later contributed the tiles to the DevTeam and tile support was
+then added to other platforms.
+.pg
+The 3.2 development team, comprised of \fBMichael Allison\fP, \fBKen
+Arromdee\fP, \fBDavid Cohrs\fP, \fBJessie Collet\fP, \fBSteve Creps\fP,
+\fBKevin Darcy\fP, \fBTimo Hakulinen\fP, \fBSteve Linhart\fP, \fBDean
+Luick\fP, \fBPat Rankin\fP, \fBEric Smith\fP, \fBMike Stephenson\fP,
+\fBJanet Walz\fP, and \fBPaul Winner\fP, released version 3.2 in April of
+1996.
+.pg
+Version 3.2 marked the tenth anniversary of the formation of the development
+team.  In a testament to their dedication to the game, all thirteen members
+of the original development team remained on the team at the start of work
+on that release.  During the interval between the release of 3.1.3
+and 3.2, one of the founding members of the development team, \fBDr. Izchak
+Miller\fP, was diagnosed with cancer and passed away.  That release of the
+game was dedicated to him by the development and porting teams.
+.pg
+During the lifespan of NetHack 3.1 and 3.2, several enthusiasts
+of the game added
+their own modifications to the game and made these ``variants'' publicly
+available:
+.pg
+\fBTom Proudfoot\fP and \fBYuval Oren\fP created NetHack++,
+which was quickly renamed NetHack--.
+Working independently, \fBStephen White\fP wrote NetHack Plus.
+\fBTom Proudfoot\fP later merged NetHack Plus
+and his own NetHack-- to produce SLASH.
+\fBLarry Stewart-Zerba\fP and \fBWarwick Allison\fP improved the spell
+casting system with the Wizard Patch.
+\fBWarwick Allison\fP also ported NetHack to use the Qt interface.
+.pg
+\fBWarren Cheung\fP combined SLASH with the Wizard Patch to produce Slash'em,
+and with the help of \fBKevin Hugo\fP, added more features.
+Kevin later joined the
+DevTeam and incorporated the best of these ideas in NetHack 3.3.
+.pg
+The final update to 3.2 was the bug fix release 3.2.3, which was released
+simultaneously with 3.3.0 in December 1999 just in time for the Year 2000.
+.pg
+The 3.3 development team, consisting of \fBMichael Allison\fP, \fBKen Arromdee\fP, 
+\fBDavid Cohrs\fP, \fBJessie Collet\fP, \fBSteve Creps\fP, \fBKevin Darcy\fP, 
+\fBTimo Hakulinen\fP, \fBKevin Hugo\fP, \fBSteve Linhart\fP, \fBKen Lorber\fP, 
+\fBDean Luick\fP, \fBPat Rankin\fP, \fBEric Smith\fP, \fBMike Stephenson\fP, 
+\fBJanet Walz\fP, and \fBPaul Winner\fP, released 3.3.0 in 
+December 1999 and 3.3.1 in August of 2000.
+.pg
+Version 3.3 offered many firsts. It was the first version to separate race 
+and profession. The Elf class was removed in preference to an elf race, 
+and the races of dwarves, gnomes, and orcs made their first appearance in 
+the game alongside the familiar human race.  Monk and Ranger roles joined 
+Archeologists, Barbarians, Cavemen, Healers, Knights, Priests, Rogues, Samurai, 
+Tourists, Valkyries and of course, Wizards.  It was also the first version
+to allow you to ride a steed, and was the first version to have a publicly 
+available web-site listing all the bugs that had been discovered.  Despite 
+that constantly growing bug list, 3.3 proved stable enough to last for
+more than a year and a half.
+.pg
+The 3.4 development team initially consisted of
+\fBMichael Allison\fP, \fBKen Arromdee\fP,
+\fBDavid Cohrs\fP, \fBJessie Collet\fP, \fBKevin Hugo\fP, \fBKen Lorber\fP,
+\fBDean Luick\fP, \fBPat Rankin\fP, \fBMike Stephenson\fP, 
+\fBJanet Walz\fP, and \fBPaul Winner\fP, with \fB Warwick Allison\fP joining 
+just before the release of NetHack 3.4.0 in March 2002.
+.pg
+As with version 3.3, various people contributed to the game as a whole as
+well as supporting ports on the different platforms that NetHack runs on:
+.pg
+\fBPat Rankin\fP maintained 3.4 for VMS.
+.pg
+\fBMichael Allison\fP maintained NetHack 3.4 for the MS-DOS platform.  \fBPaul Winner\fP
+and \fBYitzhak Sapir\fP provided encouragement.
+.pg
+\fBDean Luick\fP, \fBMark Modrall\fP, and \fBKevin Hugo\fP maintained and enhanced the
+Macintosh port of 3.4.
+.pg
+\fBMichael Allison\fP, \fBDavid Cohrs\fP, \fBAlex Kompel\fP, \fBDion Nicolaas\fP, and 
+\fBYitzhak Sapir\fP maintained and enhanced 3.4 for the Microsoft Windows platform.
+\fBAlex Kompel\fP contributed a new graphical interface for the Windows port. 
+\fBAlex Kompel\fP also contributed a Windows CE port for 3.4.1.
+.pg
+\fBRon Van Iwaarden\fP maintained 3.4 for OS/2.
+.pg
+\fBJanne Salmijarvi\fP and \fBTeemu Suikki\fP maintained and 
+enhanced the Amiga port of 3.4 after \fBJanne Salmijarvi\fP resurrected 
+it for 3.3.1.
+.pg
+\fBChristian ``Marvin'' Bressler\fP maintained 3.4 for the Atari after he 
+resurrected it for 3.3.1.
+.pg
+There is a NetHack web site maintained by \fBKen Lorber\fP at http://www.nethack.org/.
+.pg
+                          - - - - - - - - - -
+.pg
+From time to time, some depraved individual out there in netland sends a
+particularly intriguing modification to help out with the game.  The Gods of
+the Dungeon sometimes make note of the names of the worst of these miscreants
+in this, the list of Dungeoneers:
+
+.sd
+.TS S
+center;
+c c c.
+.\"TABLE_START
+Adam Aronow    Izchak Miller   Mike Stephenson
+Alex Kompel    J. Ali Harlow   Norm Meluch
+Andreas Dorn   Janet Walz      Olaf Seibert
+Andy Church    Janne Salmijarvi        Pasi Kallinen
+Andy Swanson   Jean-Christophe Collet  Pat Rankin
+Ari Huttunen   Jochen Erwied   Paul Winner
+Barton House   John Kallen     Pierre Martineau
+Benson I. Margulies    John Rupley     Ralf Brown
+Bill Dyer      John S. Bien    Ray Chason
+Boudewijn Waijers      Johnny Lee      Richard Addison
+Bruce Cox      Jon W{tte       Richard Beigel
+Bruce Holloway Jonathan Handler        Richard P. Hughey
+Bruce Mewborne Joshua Delahunty        Rob Menke
+Carl Schelin   Keizo Yamamoto  Robin Johnson
+Chris Russo    Ken Arnold      Roderick Schertler
+David Cohrs    Ken Arromdee    Roland McGrath
+David Damerell Ken Lorber      Ron Van Iwaarden
+David Gentzel  Ken Washikita   Ronnen Miller
+David Hairston Kevin Darcy     Ross Brown
+Dean Luick     Kevin Hugo      Sascha Wostmann
+Del Lamb       Kevin Sitze     Scott Bigham
+Deron Meranda  Kevin Smolkowski        Scott R. Turner
+Dion Nicolaas  Kevin Sweet     Stephen Spackman
+Dylan O'Donnell        Lars Huttar     Stephen White
+Eric Backus    Malcolm Ryan    Steve Creps
+Eric Hendrickson       Mark Gooderum   Steve Linhart
+Eric R. Smith  Mark Modrall    Steve VanDevender
+Eric S. Raymond        Marvin Bressler Teemu Suikki
+Erik Andersen  Matthew Day     Tim Lennan
+Frederick Roeber       Merlyn LeRoy    Timo Hakulinen
+Gil Neiger     Michael Allison Tom Almy
+Greg Laskin    Michael Feir    Tom West
+Greg Olson     Michael Hamel   Warren Cheung
+Gregg Wonderly Michael Sokolov Warwick Allison
+Hao-yang Wang  Mike Engber     Yitzhak Sapir
+Helge Hafting  Mike Gallop
+Irina Rempt-Drijfhout  Mike Passaretti
+.\"TABLE_END  Do not delete this line.
+.TE
+.ed
+
+.\"Microsoft and MS-DOS are registered trademarks of Microsoft Corporation.
+.\"Lattice is a trademark of Lattice, Inc.
+.\"Atari and 1040ST are trademarks of Atari, Inc.
+.\"AMIGA is a trademark of Commodore-Amiga, Inc.
+.sm "Brand and product names are trademarks or registered trademarks \
+of their respective holders."
diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex
new file mode 100644 (file)
index 0000000..f76398f
--- /dev/null
@@ -0,0 +1,3395 @@
+\documentstyle[titlepage]{article}
+
+\textheight 220mm
+\textwidth 160mm
+\oddsidemargin 0mm
+\evensidemargin 0mm
+\topmargin 0mm
+
+\newcommand{\nd}{\noindent}
+
+\newcommand{\tb}[1]{\tt #1 \hfill}
+\newcommand{\bb}[1]{\bf #1 \hfill}
+\newcommand{\ib}[1]{\it #1 \hfill}
+
+\newcommand{\blist}[1]
+{\begin{list}{$\bullet$}
+    {\leftmargin 30mm \topsep 2mm \partopsep 0mm \parsep 0mm \itemsep 1mm
+     \labelwidth 28mm \labelsep 2mm
+     #1}}
+
+\newcommand{\elist}{\end{list}}
+
+% this will make \tt underscores look better, but requires that
+% math subscripts will never be used in this document
+\catcode`\_=12
+
+\begin{document}
+%
+% input file: guidebook.mn
+% $Revision: 1.61.2.19 $ $Date: 2003/12/03 03:00:50 $
+%
+%.ds h0 "
+%.ds h1 %.ds h2 \%
+%.ds f0 "
+
+%.mt
+\title{\LARGE A Guide to the Mazes of Menace:\\
+\Large Guidebook for {\it NetHack\/}}
+
+%.au
+\author{Eric S. Raymond\\
+(Extensively edited and expanded for 3.4)}
+\date{December 2, 2003}
+
+\maketitle
+
+%.hn 1
+\section{Introduction}
+
+%.pg
+
+Recently, you have begun to find yourself unfulfilled and distant 
+in your daily occupation.  Strange dreams of prospecting, stealing, 
+crusading, and combat have haunted you in your sleep for many months, 
+but you aren't sure of the reason.  You wonder whether you have in 
+fact been having those dreams all your life, and somehow managed to 
+forget about them until now.  Some nights you awaken suddenly
+and cry out, terrified at the vivid recollection of the strange and 
+powerful creatures that seem to be lurking behind every corner of the 
+dungeon in your dream.  Could these details haunting your dreams be real?  
+As each night passes, you feel the desire to enter the mysterious caverns 
+near the ruins grow stronger.  Each morning, however, you quickly put 
+the idea out of your head as you recall the tales of those who entered 
+the caverns before you and did not return.  Eventually you can resist 
+the yearning to seek out the fantastic place in your dreams no longer.  
+After all, when other adventurers came back this way after spending time 
+in the caverns, they usually seemed better off than when they passed 
+through the first time.  And who was to say that all of those who did 
+not return had not just kept going?
+%.pg
+
+Asking around, you hear about a bauble, called the Amulet of Yendor by some,
+which, if you can find it, will bring you great wealth.  One legend you were
+told even mentioned that the one who finds the amulet will be granted
+immortality by the gods.  The amulet is rumored to be somewhere beyond the
+Valley of Gehennom, deep within the Mazes of Menace.  Upon hearing the
+legends, you immediately realize that there is some profound and 
+undiscovered reason that you are to descend into the caverns and seek 
+out that amulet of which they spoke.  Even if the rumors of the amulet's 
+powers are untrue, you decide that you should at least be able to sell the 
+tales of your adventures to the local minstrels for a tidy sum, especially 
+if you encounter any of the terrifying and magical creatures of 
+your dreams along the way.  You spend one last night fortifying yourself 
+at the local inn, becoming more and more depressed as you watch the odds 
+of your success being posted on the inn's walls getting lower and lower.  
+
+%.pg
+\nd In the morning you awake, collect your belongings, and 
+set off for the dungeon.  After several days of uneventful 
+travel, you see the ancient ruins that mark the entrance to the 
+Mazes of Menace.  It is late at night, so you make camp at the entrance 
+and spend the night sleeping under the open skies.  In the morning, you 
+gather your gear, eat what may be your last meal outside, and enter the 
+dungeon\ldots
+
+%.hn 1
+\section{What is going on here?}
+
+%.pg
+You have just begun a game of {\it NetHack}.  Your goal is to grab as much
+treasure as you can, retrieve the Amulet of Yendor, and escape the
+Mazes of Menace alive.  
+
+%.pg
+Your abilities and strengths for dealing with the hazards of adventure
+will vary with your background and training:
+
+%.pg
+%
+\blist{}
+\item[\bb{Archeologists}]%
+understand dungeons pretty well; this enables them
+to move quickly and sneak up on the local nasties.  They start equipped
+with the tools for a proper scientific expedition.
+%.pg
+%
+\item[\bb{Barbarians}]%
+are warriors out of the hinterland, hardened to battle.
+They begin their quests with naught but uncommon strength, a trusty hauberk,
+and a great two-handed sword.
+%.pg
+%
+\item[\bb{Cavemen {\rm and} Cavewomen}]
+start with exceptional strength, but unfortunately, neolithic weapons.
+%.pg
+%
+\item[\bb{Healers}]%
+are wise in medicine and apothecary.  They know the
+herbs and simples that can restore vitality, ease pain, anesthetize,
+and neutralize
+poisons; and with their instruments, they can divine a being's state
+of health or sickness.  Their medical practice earns them quite reasonable
+amounts of money, with which they enter the dungeon.
+%.pg
+%
+\item[\bb{Knights}]%
+are distinguished from the common skirmisher by their
+devotion to the ideals of chivalry and by the surpassing excellence of
+their armor.
+%.pg
+%
+\item[\bb{Monks}]%
+are ascetics, who by rigorous practice of physical and mental
+disciplines have become capable of fighting as effectively without weapons
+as with.  They wear no armor but make up for it with increased mobility.
+%.pg
+%
+\item[\bb{Priests {\rm and} Priestesses}]%
+are clerics militant, crusaders
+advancing the cause of righteousness with arms, armor, and arts
+thaumaturgic.  Their ability to commune with deities via prayer
+occasionally extricates them from peril, but can also put them in it.
+%.pg
+%
+\item[\bb{Rangers}]%
+are most at home in the woods, and some say slightly out
+of place in a dungeon.  They are, however, experts in archery as well
+as tracking and stealthy movement.
+%.pg
+%
+\item[\bb{Rogues}]%
+are agile and stealthy thieves, with knowledge of locks,
+traps, and poisons.  Their advantage lies in surprise, which they employ
+to great advantage.
+%.pg
+%
+\item[\bb{Samurai}]%
+are the elite warriors of feudal Nippon.  They are lightly
+armored and quick, and wear the %
+{\it dai-sho}, two swords of the deadliest
+keenness.
+%.pg
+%
+\item[\bb{Tourists}]%
+start out with lots of gold (suitable for shopping with),
+a credit card, lots of food, some maps, and an expensive camera.  Most
+monsters don't like being photographed.
+%.pg
+%
+\item[\bb{Valkyries}]%
+are hardy warrior women.  Their upbringing in the harsh
+Northlands makes them strong, inures them to extremes of cold, and instills
+in them stealth and cunning.
+%.pg
+%
+\item[\bb{Wizards}]%
+start out with a knowledge of magic, a selection of magical
+items, and a particular affinity for dweomercraft.  Although seemingly weak
+and easy to overcome at first sight, an experienced Wizard is a deadly foe.
+\elist
+
+%.pg
+You may also choose the race of your character:
+
+%.pg
+%
+\blist{}
+\item[\bb{Dwarves}]%
+are smaller than humans or elves, but are stocky and solid
+individuals.  Dwarves' most notable trait is their great expertise in mining
+and metalwork.  Dwarvish armor is said to be second in quality not even to the
+mithril armor of the Elves.
+%.pg
+%
+\item[\bb{Elves}]%
+are agile, quick, and perceptive; very little of what goes
+on will escape an Elf.  The quality of Elven craftsmanship often gives
+them an advantage in arms and armor.
+%.pg
+%
+\item[\bb{Gnomes}]%
+are smaller than but generally similar to dwarves.  Gnomes are
+known to be expert miners, and it is known that a secret underground mine
+complex built by this race exists within the Mazes of Menace, filled with
+both riches and danger.
+%.pg
+%
+\item[\bb{Humans}]%
+are by far the most common race of the surface world, and
+are thus the norm by which other races are often compared.  Although
+they have no special abilities, they can succeed in any role.
+%.pg
+%
+\item[\bb{Orcs}]%
+are a cruel and barbaric race that hate every living thing
+(including other orcs).  Above all others, Orcs hate Elves with a passion
+unequalled, and will go out of their way to kill one at any opportunity.
+The armor and weapons fashioned by the Orcs are typically of inferior quality.
+\elist
+
+%.hn 1
+\section{What do all those things on the screen mean?}
+%.pg
+On the screen is kept a map of where you have been and what you have 
+seen on the current dungeon level; as you explore more of the level, 
+it appears on the screen in front of you.
+
+%.pg
+When {\it NetHack\/}'s ancestor {\it rogue\/} first appeared, its screen
+orientation was almost unique among computer fantasy games.  Since
+then, screen orientation has become the norm rather than the
+exception; {\it NetHack\/} continues this fine tradition.  Unlike text
+adventure games that accept commands in pseudo-English sentences and
+explain the results in words, {\it NetHack\/} commands are all one or two
+keystrokes and the results are displayed graphically on the screen.  A
+minimum screen size of 24 lines by 80 columns is recommended; if the
+screen is larger, only a $21\times80$ section will be used for the map.
+
+%.pg
+{\it NetHack\/} can even be played by blind players, with the assistance of
+Braille readers or speech synthesisers.  Instructions for configuring
+{\it NetHack\/} for the blind are included later in this document.
+
+%.pg
+{\it NetHack\/} generates a new dungeon every time you play it; even the
+authors still find it an entertaining and exciting game despite
+having won several times.
+
+%.pg
+{\it NetHack\/} offers a variety of display options.  The options available to
+you will vary from port to port, depending on the capabilities of your
+hardware and software, and whether various compile-time options were
+enabled when your executable was created.  The three possible display
+options are: a monochrome character interface, a color character interface,
+and a graphical interface using small pictures called tiles.  The two
+character interfaces allow fonts with other characters to be substituted,
+but the default assignments use standard ASCII characters to represent
+everything.  There is no difference between the various display options
+with respect to game play.  Because we cannot reproduce the tiles or
+colors in the Guidebook, and because it is common to all ports, we will
+use the default ASCII characters from the monochrome character display
+when referring to things you might see on the screen during your game.
+%.pg
+In order to understand what is going on in {\it NetHack}, first you must
+understand what {\it NetHack\/} is doing with the screen.  The {\it NetHack\/}
+screen replaces the ``You see \ldots'' descriptions of text adventure games.
+Figure 1 is a sample of what a {\it NetHack\/} screen might look like.
+The way the screen looks for you depends on your platform.
+
+\vbox{
+\begin{verbatim}
+        The bat bites!
+
+                ------
+                |....|    ----------
+                |.<..|####...@...$.|
+                |....-#   |...B....+
+                |....|    |.d......|
+                ------    -------|--
+
+
+
+        Player the Rambler     St:12 Dx:7 Co:18 In:11 Wi:9 Ch:15  Neutral
+        Dlvl:1  $:0  HP:9(12) Pw:3(3) AC:10 Exp:1/19 T:257 Weak
+\end{verbatim}
+\begin{center}
+Figure 1
+\end{center}
+}
+
+%.hn 2
+\subsection*{The status lines (bottom)}
+
+%.pg
+The bottom two lines of the screen contain several cryptic pieces of
+information describing your current status.  If either status line
+becomes longer than the width of the screen, you might not see all of
+it.  Here are explanations of what the various status items mean
+(though your configuration may not have all the status items listed
+below):
+
+%.lp
+\blist{}
+\item[\bb{Rank}]
+Your character's name and professional ranking (based on the
+experience level, see below).
+%.lp
+\item[\bb{Strength}]
+A measure of your character's strength; one of your six basic
+attributes.  A human character's attributes can range from 3 to 18 inclusive;
+non-humans may exceed these limits
+(occasionally you may get super-strengths of the form 18/xx, and magic can
+also cause attributes to exceed the normal limits).  The
+higher your strength, the stronger you are.  Strength affects how
+successfully you perform physical tasks, how much damage you do in
+combat, and how much loot you can carry.
+%.lp
+\item[\bb{Dexterity}]
+Dexterity affects your chances to hit in combat, to avoid traps, and
+do other tasks requiring agility or manipulation of objects.
+%.lp
+\item[\bb{Constitution}]
+Constitution affects your ability to recover from injuries and other
+strains on your stamina.
+%.lp
+\item[\bb{Intelligence}]
+Intelligence affects your ability to cast spells and read spellbooks.
+%.lp
+\item[\bb{Wisdom}]
+Wisdom comes from your practical experience (especially when dealing with
+magic).  It affects your magical energy.
+%.lp
+\item[\bb{Charisma}]
+Charisma affects how certain creatures react toward you.  In
+particular, it can affect the prices shopkeepers offer you.
+%.lp
+\item[\bb{Alignment}]
+%
+{\it Lawful}, {\it Neutral\/} or {\it Chaotic}.  Often, Lawful is
+taken as good and Chaotic is evil, but legal and ethical do not always
+coincide.  Your alignment influences how other
+monsters react toward you.  Monsters of a like alignment are more likely
+to be non-aggressive, while those of an opposing alignment are more likely
+to be seriously offended at your presence.
+%.lp
+\item[\bb{Dungeon Level}]
+How deep you are in the dungeon.  You start at level one and the number
+increases as you go deeper into the dungeon.  Some levels are special,
+and are identified by a name and not a number.  The Amulet of Yendor is
+reputed to be somewhere beneath the twentieth level.
+%.lp
+\item[\bb{Gold}]
+The number of gold pieces you are openly carrying.  Gold which you have
+concealed in containers is not counted.
+%.lp
+\item[\bb{Hit Points}]
+Your current and maximum hit points.  Hit points indicate how much
+damage you can take before you die.  The more you get hit in a fight,
+the lower they get.  You can regain hit points by resting, or by using
+certain magical items or spells.  The number in parentheses is the maximum
+number your hit points can reach.
+%.lp
+\item[\bb{Power}]
+Spell points.  This tells you how much mystic energy ({\it mana\/})
+you have available for spell casting.  Again, resting will regenerate the
+amount available.
+%.lp
+\item[\bb{Armor Class}]
+A measure of how effectively your armor stops blows from unfriendly
+creatures.  The lower this number is, the more effective the armor; it
+is quite possible to have negative armor class.
+%.lp
+\item[\bb{Experience}]
+Your current experience level and experience points.  As you
+adventure, you gain experience points.  At certain experience point
+totals, you gain an experience level.  The more experienced you are,
+the better you fight and withstand magical attacks.  Many dungeons
+show only your experience level here.
+%.lp
+\item[\bb{Time}]
+The number of turns elapsed so far, displayed if you have the
+{\it time\/} option set.
+%.lp
+\item[\bb{Hunger Status}]
+Your current hunger status, ranging from %
+{\it Satiated\/} down to {\it Fainting}.  If your hunger status is normal,
+it is not displayed.
+%.pg
+Additional status flags may appear after the hunger status:
+{\it Conf\/} when you're confused, {\it FoodPois\/} or {\it Ill\/}
+when sick, {\it Blind\/}
+when you can't see, {\it Stun\/} when stunned, and {\it Hallu\/} when
+hallucinating.
+\elist
+
+%.hn 2
+\subsection*{The message line (top)}
+
+%.pg
+The top line of the screen is reserved for messages that describe
+things that are impossible to represent visually.  If you see a
+``{\tt --More--}'' on the top line, this means that {\it NetHack\/} has
+another message to display on the screen, but it wants to make certain
+that you've read the one that is there first.  To read the next message,
+just press the space bar.
+
+%.hn 2
+\subsection*{The map (rest of the screen)}
+
+%.pg
+The rest of the screen is the map of the level as you have explored it
+so far.  Each symbol on the screen represents something.  You can set
+various graphics
+options to change some of the symbols the game uses; otherwise, the
+game will use default symbols.  Here is a list of what the default
+symbols mean:
+
+\blist{}
+%.lp
+\item[\tb{- {\rm and} |}]
+The walls of a room, or an open door.  Or a grave ({\tt |}).
+%.lp
+\item[\tb{.}]
+The floor of a room, ice, or a doorless doorway.
+%.lp
+\item[\tb{\#}]
+A corridor, or iron bars, or a tree, or possibly a kitchen sink (if
+your dungeon has sinks), or a drawbridge.
+%.lp
+\item[\tb{>}]
+Stairs down: a way to the next level.
+%.lp
+\item[\tb{<}]
+Stairs up: a way to the previous level.
+%.lp
+\item[\tb{+}]
+A closed door, or a spellbook containing a spell you may be able to learn.
+%.lp
+\item[\tb{@}]
+Your character or a human.
+%.lp
+\item[\tb{\$}]
+A pile of gold.
+%.lp
+\item[\tb{\^}]
+A trap (once you have detected it).
+%.lp
+\item[\tb{)}]
+A weapon.
+%.lp
+\item[\tb{[}]
+A suit or piece of armor.
+%.lp
+\item[\tb{\%}]
+Something edible (not necessarily healthy).
+%.lp
+\item[\tb{?}]
+A scroll.
+%.lp
+\item[\tb{/}]
+A wand.
+%.lp
+\item[\tb{=}]
+A ring.
+%.lp
+\item[\tb{!}]
+A potion.
+%.lp
+\item[\tb{(}]
+A useful item (pick-axe, key, lamp \ldots).
+%.lp
+\item[\tb{"}]
+An amulet or a spider web.
+%.lp
+\item[\tb{*}]
+A gem or rock (possibly valuable, possibly worthless).
+%.lp
+\item[\tb{`}]
+A boulder or statue.
+%.lp
+\item[\tb{0}]
+An iron ball.
+%.lp
+\item[\tb{_}]
+An altar, or an iron chain.
+%.lp
+\item[\tb{\{}]
+A fountain.
+%.lp
+\item[\tb{\}}]
+A pool of water or moat or a pool of lava.
+%.lp
+\item[\tb{$\backslash$}]
+An opulent throne.
+%.lp
+\item[\tb{a-zA-Z {\rm \& other symbols}}]
+Letters and certain other symbols represent the various inhabitants
+of the Mazes of Menace.  Watch out, they can be nasty and vicious.
+Sometimes, however, they can be helpful.
+%.lp
+\item[\tb{I}]
+This marks the last known location of an invisible or otherwise unseen
+monster.  Note that the monster could have moved.  The `F' and `m' commands
+may be useful here.
+
+\elist
+%.pg
+You need not memorize all these symbols; you can ask the game what any
+symbol represents with the `{\tt /}' command (see the next section for
+more info).
+
+%.hn 1
+\section{Commands}
+
+%.pg
+Commands are initiated by typing one or two characters.  Some commands,
+like ``{\tt search}'', do not require that any more information be collected
+by {\it NetHack\/}.  Other commands might require additional information, for
+example a direction, or an object to be used.  For those commands that
+require additional information, {\it NetHack\/} will present you with either 
+a menu of choices, or with a command line prompt requesting information.  Which
+you are presented with will depend chiefly on how you have set the
+`{\it menustyle\/}'
+option.
+
+%.pg
+For example, a common question in the form ``{\tt What do you want to
+use? [a-zA-Z\ ?*]}'', asks you to choose an object you are carrying.
+Here, ``{\tt a-zA-Z}'' are the inventory letters of your possible choices.
+Typing `{\tt ?}' gives you an inventory list of these items, so you can see
+what each letter refers to.  In this example, there is also a `{\tt *}'
+indicating that you may choose an object not on the list, if you
+wanted to use something unexpected.  Typing a `{\tt *}' lists your entire
+inventory, so you can see the inventory letters of every object you're
+carrying.  Finally, if you change your mind and decide you don't want
+to do this command after all, you can press the `ESC' key to abort the
+command.
+
+%.pg
+You can put a number before some commands to repeat them that many
+times; for example, ``{\tt 10s}'' will search ten times.  If you have the
+{\it number\_pad\/}
+option set, you must type `{\tt n}' to prefix a count, so the example above
+would be typed ``{\tt n10s}'' instead.  Commands for which counts make no
+sense ignore them.  In addition, movement commands can be prefixed for
+greater control (see below).  To cancel a count or a prefix, press the
+`ESC' key.
+
+%.pg
+The list of commands is rather long, but it can be read at any time
+during the game through the `{\tt ?}' command, which accesses a menu of
+helpful texts.  Here are the commands for your reference:
+
+\blist{}
+%.lp
+\item[\tb{?}]
+Help menu:  display one of several help texts available.
+%.lp
+\item[\tb{/}]
+Tell what a symbol represents.  You may choose to specify a location
+or type a symbol (or even a whole word) to explain.
+Specifying a location is done by moving the cursor to a particular spot
+on the map and then pressing one of `{\tt .}', `{\tt ,}', `{\tt ;}',
+or `{\tt :}'.  `{\tt .}' will explain the symbol at the chosen location,
+conditionally check for ``{\tt More info?}'' depending upon whether the
+{\it help\/}
+option is on, and then you will be asked to pick another location;
+`{\tt ,}' will explain the symbol but skip any additional
+information; `{\tt ;}' will skip additional info and also not bother asking
+you to choose another location to examine; `{\tt :}' will show additional
+info, if any, without asking for confirmation.  When picking a location,
+pressing the {\tt ESC} key will terminate this command, or pressing `{\tt ?}'
+will give a brief reminder about how it works.
+
+%.pg
+Specifying a name rather than a location
+always gives any additional information available about that name.
+%.lp
+\item[\tb{\&}]
+Tell what a command does.
+%.lp
+\item[\tb{<}]
+Go up to the previous level (if you are on a staircase or ladder).
+%.lp
+\item[\tb{>}]
+Go down to the next level (if you are on a staircase or ladder).
+%.lp
+\item[\tb{[yuhjklbn]}]
+Go one step in the direction indicated (see Figure 2).  If you sense
+or remember
+a monster there, you will fight the monster instead.  Only these
+one-step movement commands cause you to fight monsters; the others
+(below) are ``safe.''
+%.sd
+\begin{center}
+\begin{tabular}{cc}
+\verb+   y  k  u   + & \verb+   7  8  9   +\\
+\verb+    \ | /    + & \verb+    \ | /    +\\
+\verb+   h- . -l   + & \verb+   4- . -6   +\\
+\verb+    / | \    + & \verb+    / | \    +\\
+\verb+   b  j  n   + & \verb+   1  2  3   +\\
+                     & (if {\it number\_pad\/} set)
+\end{tabular}
+\end{center}
+%.ed
+\begin{center}
+Figure 2
+\end{center}
+%.lp
+\item[\tb{[YUHJKLBN]}]
+Go in that direction until you hit a wall or run into something.
+%.lp
+\item[\tb{m[yuhjklbn]}]
+Prefix:  move without picking up objects or fighting (even if you remember
+a monster there)
+%.lp
+\item[\tb{F[yuhjklbn]}]
+Prefix:  fight a monster (even if you only guess one is there)
+%.lp
+\item[\tb{M[yuhjklbn]}]
+Prefix:  Move far, no pickup.
+%.lp
+\item[\tb{g[yuhjklbn]}]
+Prefix:  Move until something interesting is found.
+%.lp
+\item[\tb{G[yuhjklbn] {\rm or} <CONTROL->[yuhjklbn]}]
+Prefix:  Same as `{\tt g}', but forking of corridors is not considered
+interesting.
+%.lp
+\item[\tb{_}]
+Travel to a map location via a shortest-path algorithm.  The shortest path
+is computed over map locations the hero knows about (e.g. seen or
+previously traversed).  If there is no known path, a guess is made instead.
+Stops on most of 
+the same conditions as the `G' command, but without picking up
+objects, similar to the `M' command.  For ports with mouse 
+support, the command is also invoked when a mouse-click takes place on a 
+location other than the current position.
+%.lp
+\item[\tb{.}]
+Rest, do nothing for one turn.
+%.lp
+\item[\tb{a}]
+Apply (use) a tool (pick-axe, key, lamp \ldots).
+%.lp
+\item[\tb{A}]
+Remove one or more worn items, such as armor.
+Use `{\tt T}' (take off) to take off only one piece of armor 
+or `{\tt R}' (remove) to take off only one accessory.
+%.lp
+\item[\tb{\^{}A}]
+Redo the previous command.
+%.lp
+\item[\tb{c}]
+Close a door.
+%.lp
+\item[\tb{C}]
+Call (name) an individual monster.
+%.lp
+\item[\tb{\^{}C}]
+Panic button.  Quit the game.
+%.lp
+\item[\tb{d}]
+Drop something.\\
+{\tt d7a} --- drop seven items of object
+{\it a}.
+%.lp
+\item[\tb{D}]
+Drop several things.  In answer to the question
+``{\tt What kinds of things do you want to drop? [!\%= BUCXaium]}''
+you should type zero or more object symbols possibly followed by
+`{\tt a}' and/or `{\tt i}' and/or `{\tt u}' and/or `{\tt m}'.
+In addition, one or more of
+the blessed/uncursed/cursed groups may be typed.\\
+%.sd
+%.si
+{\tt DB}  --- drop all objects known to be blessed.\\
+{\tt DU}  --- drop all objects known to be uncursed.\\
+{\tt DC}  --- drop all objects known to be cursed.\\
+{\tt DX}  --- drop all objects of unknown B/U/C status.\\
+{\tt Da}  --- drop all objects, without asking for confirmation.\\
+{\tt Di}  --- examine your inventory before dropping anything.\\
+{\tt Du}  --- drop only unpaid objects (when in a shop).\\
+{\tt Dm}  --- use a menu to pick which object(s) to drop.\\
+{\tt D\%u} --- drop only unpaid food.
+%.ei
+%.ed
+%.lp
+\item[\tb{\^{}D}]
+Kick something (usually a door).
+%.lp
+\item[\tb{e}]
+Eat food.
+%.lp
+% Make sure Elbereth is not hyphenated below, the exact spelling matters.
+% (Only specified here to parallel Guidebook.mn; use of \tt font implicity
+% prevents automatic hyphenation in TeX and LaTeX.)
+\hyphenation{Elbereth}         %override the deduced syllable breaks
+\item[\tb{E}]
+Engrave a message on the floor.
+Engraving the word ``{\tt Elbereth}'' will cause most monsters to not attack
+you hand-to-hand (but if you attack, you will rub it out); this is
+often useful to give yourself a breather.  (This feature may be compiled out
+of the game, so your version might not have it.)\\
+%.sd
+%.si
+{\tt E-} --- write in the dust with your fingers.
+%.ei
+%.ed
+%.Ip
+\item[\tb{f}]
+Fire one of the objects placed in your quiver.  You may select
+ammunition with a previous `{\tt Q}' command, or let the computer pick
+something appropriate if {\it autoquiver\/} is true.
+%.lp
+\item[\tb{i}]
+List your inventory (everything you're carrying).
+%.lp
+\item[\tb{I}]
+List selected parts of your inventory.\\
+%.sd
+%.si
+{\tt I*} --- list all gems in inventory;\\
+{\tt Iu} --- list all unpaid items;\\
+{\tt Ix} --- list all used up items that are on your shopping bill;\\
+{\tt I\$} --- count your money.
+%.ei
+%.ed
+%.lp
+\item[\tb{o}]
+Open a door.
+%.lp
+\item[\tb{O}]
+Set options.  A menu showing the current option values will be
+displayed.  You can change most values simply by selecting the menu
+entry for the given option (ie, by typing its letter or clicking upon
+it, depending on your user interface).  For the non-boolean choices,
+a further menu or prompt will appear once you've closed this menu.
+The available options
+are listed later in this Guidebook.  Options are usually set before the
+game rather than with the `{\tt O}' command; see the section on options below.
+%.lp
+\item[\tb{p}]
+Pay your shopping bill.
+%.lp
+\item[\tb{P}]
+Put on a ring or other accessory (amulet, blindfold).
+%.lp
+\item[\tb{\^{}P}]
+Repeat previous message.  Subsequent {\tt \^{}P}'s repeat earlier messages.
+The behavior can be varied via the msg_window option.
+%.lp
+\item[\tb{q}]
+Quaff (drink) something (potion, water, etc).
+%.lp
+\item[\tb{Q}]
+Select an object for your quiver.  You can then throw this using
+the `f' command.  (In versions prior to 3.3 this was the command to quit
+the game, which has now been moved to `{\tt \#quit}'.)
+%.lp
+\item[\tb{r}]
+Read a scroll or spellbook.
+%.lp
+\item[\tb{R}]
+Remove an accessory (ring, amulet, etc).
+%.lp
+\item[\tb{\^{}R}]
+Redraw the screen.
+%.lp
+\item[\tb{s}]
+Search for secret doors and traps around you.  It usually takes several
+tries to find something.
+%.lp
+\item[\tb{S}]
+Save (and suspend) the game.  The game will be restored automatically the
+next time you play.
+%.lp
+\item[\tb{t}]
+Throw an object or shoot a projectile.
+%.lp
+\item[\tb{T}]
+Take off armor.
+%.lp
+\item[\tb{\^{}T}]
+Teleport, if you have the ability.
+%.lp
+\item[\tb{v}]
+Display version number.
+%.lp
+\item[\tb{V}]
+Display the game history.
+%.lp
+\item[\tb{w}]
+Wield weapon.\\
+%.sd
+%.si
+{\tt w-} --- wield nothing, use your bare hands.
+%.ei
+%.ed
+%.lp
+\item[\tb{W}]
+Wear armor.
+%.lp
+\item[\tb{x}]
+Exchange your wielded weapon with the item in your alternate
+weapon slot.  The latter is used as your secondary weapon when engaging in
+two-weapon combat.  Note that if one of these slots is empty,
+the exchange still takes place.
+%.lp
+\item[\tb{X}]
+Enter explore (discovery) mode, explained in its own section later.
+%.lp
+\item[\tb{\^{}X}]
+Display your name, role, race, gender, and alignment as well as
+the various deities in your game.
+%.lp
+\item[\tb{z}]
+Zap a wand.  To aim at yourself, use `{\tt .}' for the direction.
+%.lp
+\item[\tb{Z}]
+Zap (cast) a spell.  To cast at yourself, use `{\tt .}' for the direction.
+%.lp
+\item[\tb{\^{}Z}]
+Suspend the game (UNIX versions with job control only).
+%.lp
+\item[\tb{:}]
+Look at what is here.
+%.lp
+\item[\tb{;}]
+Show what type of thing a visible symbol corresponds to.
+%.lp
+\item[\tb{,}]
+Pick up some things. May be preceded by `{\tt m}' to force a selection menu.
+%.lp
+\item[\tb{@}]
+Toggle the {\it autopickup\/} option on and off.
+%.lp
+\item[\tb{\^{}}]
+Ask for the type of a trap you found earlier.
+%.lp
+\item[\tb{)}]
+Tell what weapon you are wielding.
+%.lp
+\item[\tb{[}]
+Tell what armor you are wearing.
+%.lp
+\item[\tb{=}]
+Tell what rings you are wearing.
+%.lp
+\item[\tb{"}]
+Tell what amulet you are wearing.
+%.lp
+\item[\tb{(}]
+Tell what tools you are using.
+%.lp
+\item[\tb{*}]
+Tell what equipment you are using; combines the preceding five type-specific
+commands into one.
+%.lp
+\item[\tb{\$}]
+Count your gold pieces.
+%.lp
+\item[\tb{+}]
+List the spells you know.  Using this command, you can also rearrange
+the order in which your spells are listed.  They are shown via a menu,
+and if you select a spell in that menu, you'll be re-prompted for
+another spell to swap places with it, and then have opportunity to
+make further exchanges.
+%.lp
+\item[\tb{$\backslash$}]
+Show what types of objects have been discovered.
+%.lp
+\item[\tb{!}]
+Escape to a shell.
+%.lp
+\item[\tb{\#}]
+Perform an extended command.  As you can see, the authors of {\it NetHack\/}
+used up all the letters, so this is a way to introduce the less frequently
+used commands.
+What extended commands are available depends on what features
+the game was compiled with.
+%.lp
+\item[\tb{\#adjust}]
+Adjust inventory letters (most useful when the
+{\it fixinv\/}
+option is ``on'').
+%.lp
+\item[\tb{\#chat}]
+Talk to someone.
+%.lp
+\item[\tb{\#conduct}]
+List which challenges you have adhered to.  See the section below entitled
+``Conduct'' for details.
+%.lp
+\item[\tb{\#dip}]
+Dip an object into something.
+%.lp
+\item[\tb{\#enhance}]
+Advance or check weapons and spell skills.
+%.lp
+\item[\tb{\#force}]
+Force a lock.
+%.lp
+\item[\tb{\#invoke}]
+Invoke an object's special powers.
+%.lp
+\item[\tb{\#jump}]
+Jump to another location.
+%.lp
+\item[\tb{\#loot}]
+Loot a box or bag on the floor beneath you, or the saddle 
+from a horse standing next to you.
+%.lp
+\item[\tb{\#monster}]
+Use a monster's special ability (when polymorphed into monster form).
+%.lp
+\item[\tb{\#name}]
+Name an item or type of object.
+%.lp
+\item[\tb{\#offer}]
+Offer a sacrifice to the gods.
+%.lp
+\item[\tb{\#pray}]
+Pray to the gods for help.
+%.lp
+\item[\tb{\#quit}]
+Quit the program without saving your game.
+%.lp
+\item[\tb{\#ride}]
+Ride (or stop riding) a monster.
+%.lp
+\item[\tb{\#rub}]
+Rub a lamp or a stone.
+%.lp
+\item[\tb{\#sit}]
+Sit down.
+%.lp
+\item[\tb{\#turn}]
+Turn undead.
+%.lp
+\item[\tb{\#twoweapon}]
+Toggle two-weapon combat on or off.  Note that you must
+use suitable weapons for this type of combat, or it will
+be automatically turned off.
+%.lp
+\item[\tb{\#untrap}]
+Untrap something (trap, door, or chest).
+%.lp
+\item[\tb{\#version}]
+Print compile time options for this version of {\it NetHack}.
+%.lp
+\item[\tb{\#wipe}]
+Wipe off your face.
+%.lp
+\item[\tb{\#?}]
+Help menu:  get the list of available extended commands.
+\elist
+
+%.pg
+\nd If your keyboard has a meta key (which, when pressed in combination
+with another key, modifies it by setting the `meta' [8th, or `high']
+bit), you can invoke many extended commands by meta-ing the first
+letter of the command.
+%- In {\it NT, OS/2, PC\/ {\rm and} ST NetHack},
+%- the `Alt' key can be used in this fashion;
+%- on the Amiga set the {\it altmeta\/} option to get this behavior.
+In {\it NT, OS/2, {\rm and} PC NetHack},
+the `Alt' key can be used in this fashion.
+\blist{}
+%.lp 
+\item[\tb{M-?}]
+{\tt\#?} (not supported by all platforms)
+%.lp
+\item[\tb{M-2}]
+{\tt\#twoweapon} (unless the {\it number\_pad\/} option is enabled)
+%.lp
+\item[\tb{M-a}]
+{\tt\#adjust}
+%.lp
+\item[\tb{M-c}]
+{\tt\#chat}
+%.lp
+\item[\tb{M-d}]
+{\tt\#dip}
+%.lp
+\item[\tb{M-e}]
+{\tt\#enhance}
+%.lp
+\item[\tb{M-f}]
+{\tt\#force}
+%.lp
+\item[\tb{M-i}]
+{\tt\#invoke}
+%.lp
+\item[\tb{M-j}]
+{\tt\#jump}
+%.lp
+\item[\tb{M-l}]
+{\tt\#loot}
+%.lp
+\item[\tb{M-m}]
+{\tt\#monster}
+%.lp
+\item[\tb{M-n}]
+{\tt\#name}
+%.lp
+\item[\tb{M-o}]
+{\tt\#offer}
+%.lp
+\item[\tb{M-p}]
+{\tt\#pray}
+%.Ip
+\item[\tb{M-q}]
+{\tt\#quit}
+%.lp
+\item[\tb{M-r}]
+{\tt\#rub}
+%.lp
+\item[\tb{M-s}]
+{\tt\#sit}
+%.lp
+\item[\tb{M-t}]
+{\tt\#turn}
+%.lp
+\item[\tb{M-u}]
+{\tt\#untrap}
+%.lp
+\item[\tb{M-v}]
+{\tt\#version}
+%.lp
+\item[\tb{M-w}]
+{\tt\#wipe}
+\elist
+
+%.pg
+\nd If the {\it number\_pad\/} option is on, some additional letter commands
+are available:
+\blist{}
+%.lp 
+\item[\tb{h}]
+Help menu:  display one of several help texts available, like ``{\tt ?}''.
+%.lp
+\item[\tb{j}]
+Jump to another location.  Same as ``{\tt \#jump}'' or ``{\tt M-j}''.
+%.lp
+\item[\tb{k}]
+Kick something (usually a door).  Same as `{\tt \^{}D}'.
+%.lp
+\item[\tb{l}]
+Loot a box or bag on the floor beneath you, or the saddle 
+from a horse standing next to you.  Same as ``{\tt \#loot}'' or ``{\tt M-l}''.
+%.lp
+\item[\tb{N}]
+Name an object or type of object.  Same as ``{\tt \#name}'' or ``{\tt M-n}''.
+%.lp
+\item[\tb{u}]
+Untrap a trap, door, or chest.  Same as ``{\tt \#untrap}'' or ``{\tt M-u}''.
+\elist
+
+%.hn 1
+\section{Rooms and corridors}
+
+%.pg
+Rooms and corridors in the dungeon are either lit or dark.
+Any lit areas within your line of sight will be displayed;
+dark areas are only displayed if they are within one space of you. 
+Walls and corridors remain on the map as you explore them.
+
+%.pg
+Secret corridors are hidden.  You can find them with the `{\tt s}' (search)
+command.
+
+%.hn 2
+\subsection*{Doorways}
+
+%.pg
+Doorways connect rooms and corridors.  Some doorways have no doors;
+you can walk right through.  Others have doors in them, which may be
+open, closed, or locked.  To open a closed door, use the `{\tt o}' (open)
+command; to close it again, use the `{\tt c}' (close) command.
+
+%.pg
+You can get through a locked door by using a tool to pick the lock
+with the `{\tt a}' (apply) command, or by kicking it open with the
+`{\tt \^{}D}' (kick) command.
+
+%.pg
+Open doors cannot be entered diagonally; you must approach them
+straight on, horizontally or vertically.  Doorways without doors are
+not restricted in this fashion.
+
+%.pg
+Doors can be useful for shutting out monsters.  Most monsters cannot
+open doors, although a few don't need to (ex.\ ghosts can walk through
+doors).
+
+%.pg
+Secret doors are hidden.  You can find them with the `{\tt s}' (search)
+command.  Once found they are in all ways equivalent to normal doors.
+
+%.hn 2
+\subsection*{Traps (`{\tt \^{}}')}
+
+%.pg
+There are traps throughout the dungeon to snare the unwary delver.
+For example, you may suddenly fall into a pit and be stuck for a few
+turns trying to climb out.  Traps don't appear on your map until you
+see one triggered by moving onto it, see something fall into it, or you
+discover it with the `{\tt s}' (search) command.  Monsters can fall prey to
+traps, too, which can be a very useful defensive strategy.
+
+%.pg
+There is a special pre-mapped branch of the dungeon based on the
+classic computer game ``{\tt Sokoban}.''  The goal is to push the boulders
+into the pits or holes.  With careful foresight, it is possible to
+complete all of the levels according to the traditional rules of
+Sokoban.  Some allowances are permitted in case the player gets stuck;
+however, they will lower your luck.
+
+\subsection*{Stairs (`{\tt <}', `{\tt >}')}
+
+%.pg
+In general, each level in the dungeon will have a staircase going up
+(`{\tt <}') to the previous level and another going down (`{\tt >}')
+to the next
+level.  There are some exceptions though.  For instance, fairly early
+in the dungeon you will find a level with two down staircases, one
+continuing into the dungeon and the other branching into an area
+known as the Gnomish Mines.  Those mines eventually hit a dead end,
+so after exploring them (if you choose to do so), you'll need to
+climb back up to the main dungeon.
+
+%.pg
+When you traverse a set of stairs, or trigger a trap which sends you
+to another level, the level you're leaving will be deactivated and
+stored in a file on disk.  If you're moving to a previously visited
+level, it will be loaded from its file on disk and reactivated.  If
+you're moving to a level which has not yet been visited, it will be
+created (from scratch for most random levels, from a template for
+some ``special'' levels, or loaded from the remains of an earlier game
+for a ``bones'' level as briefly described below).  Monsters are only
+active on the current level; those on other levels are essentially
+placed into stasis.
+%.pg
+Ordinarily when you climb a set of stairs, you will arrive on the
+corresponding staircase at your destination.  However, pets (see below)
+and some other monsters will follow along if they're close enough when
+you travel up or down stairs, and occasionally one of these creatures
+will displace you during the climb.  When that occurs, the pet or other
+monster will arrive on the staircase and you will end up nearby.
+
+\subsection*{Ladders (`{\tt <}', `{\tt >}')}
+
+%.pg
+Ladders serve the same purpose as staircases, and the two types of
+inter-level connections are nearly indistinguishable during game play.
+
+%.hn 2
+\subsection*{Shops and shopping}
+
+%.pg
+Occasionally you will run across a room with a shopkeeper near the door
+and many items lying on the floor.  You can buy items by picking them
+up and then using the `{\tt p}' command.  You can inquire about the price
+of an item prior to picking it up by using the ``{\tt \#chat}'' command
+while standing on it.  Using an item prior to paying for it will incur a
+charge, and the shopkeeper won't allow you to leave the shop until you
+have paid any debt you owe.
+
+%.pg
+You can sell items to a shopkeeper by dropping them to the floor while
+inside a shop.  You will either be offered an amount of gold and asked
+whether you're willing to sell, or you'll be told that the shopkeeper
+isn't interested (generally, your item needs to be compatible with the
+type of merchandise carried by the shop).
+
+%.pg
+If you drop something in a shop by accident, the shopkeeper will usually
+claim ownership without offering any compensation.  You'll have to buy
+it back if you want to reclaim it.
+
+%.pg
+Shopkeepers sometimes run out of money.  When that happens, you'll be
+offered credit instead of gold when you try to sell something.  Credit
+can be used to pay for purchases, but it is only good in the shop where
+it was obtained; other shopkeepers won't honor it.  (If you happen to
+find a ``credit card'' in the dungeon, don't bother trying to use it in
+shops; shopkeepers will not accept it.)
+
+%.pg
+The {\tt \$} command, which reports the amount of gold you are carrying
+(in inventory, not inside bags or boxes), will also show current shop
+debt or credit, if any.  The {\tt Iu} command lists unpaid items
+(those which still belong to the shop) if you are carrying any.
+The {\tt Ix} command shows an inventory-like display of any unpaid
+items which have been used up, along with other shop fees, if any.
+
+%.hn 3
+\subsubsection*{Shop idiosyncracies}
+
+%.pg
+Several aspects of shop behavior might be unexpected.
+
+\begin{itemize}
+% note: a bullet is the default item label so we could omit [$\bullet$] here
+%.lp \(bu 2
+\item[$\bullet$]
+The price of a given item can vary due to a variety of factors.
+%.lp \(bu 2
+\item[$\bullet$]
+A shopkeeper treats the spot immediately inside the door as if it were
+outside the shop.
+%.lp \(bu 2
+\item[$\bullet$]
+While the shopkeeper watches you like a hawk, he will generally ignore
+any other customers.
+%.lp \(bu 2
+\item[$\bullet$]
+If a shop is ``closed for inventory'', it will not open of its own accord.
+%.lp \(bu 2
+\item[$\bullet$]
+Shops do not get restocked with new items, regardless of inventory depletion.
+\end{itemize}
+
+%.hn 1
+\section{Monsters}
+
+%.pg
+Monsters you cannot see are not displayed on the screen.  Beware!
+You may suddenly come upon one in a dark place.  Some magic items can
+help you locate them before they locate you (which some monsters can do
+very well).
+
+%.pg
+The commands `{\tt /}' and `{\tt ;}' may be used to obtain information
+about those
+monsters who are displayed on the screen.  The command `{\tt C}' allows you
+to assign a name to a monster, which may be useful to help distinguish
+one from another when multiple monsters are present.  Assigning a name
+which is just a space will remove any prior name.
+
+%.pg
+The extended command ``{\tt \#chat}'' can be used to interact with an adjacent
+monster.  There is no actual dialog (in other words, you don't get to
+choose what you'll say), but chatting with some monsters such as a
+shopkeeper or the Oracle of Delphi can produce useful results.
+
+%.hn 2
+\subsection*{Fighting}
+
+%.pg
+If you see a monster and you wish to fight it, just attempt to walk
+into it.  Many monsters you find will mind their own business unless
+you attack them.  Some of them are very dangerous when angered.
+Remember:  discretion is the better part of valor.
+
+%.pg
+If you can't see a monster (if it is invisible, or if you are blinded),
+the symbol `I' will be shown when you learn of its presence.
+If you attempt to walk into it, you will try to fight it just like
+a monster that you can see; of course,
+if the monster has moved, you will attack empty air.  If you guess
+that the monster has moved and you don't wish to fight, you can use the `m'
+command to move without fighting; likewise, if you don't remember a monster
+but want to try fighting anyway, you can use the `F' command.
+
+%.hn 2
+\subsection*{Your pet}
+
+%.pg
+You start the game with a little dog (`{\tt d}'), cat (`{\tt f}'),
+or pony (`{\tt u}'), which follows
+you about the dungeon and fights monsters with you.  Like you, your
+pet needs food to survive.  It usually feeds itself on fresh carrion
+and other meats.  If you're worried about it or want to train it, you
+can feed it, too, by throwing it food.  A properly trained pet can be
+very useful under certain circumstances.
+
+%.pg
+Your pet also gains experience from killing monsters, and can grow
+over time, gaining hit points and doing more damage.  Initially, your
+pet may even be better at killing things than you, which makes pets
+useful for low-level characters.
+
+%.pg
+Your pet will follow you up and down staircases if it is next to you
+when you move.  Otherwise your pet will be stranded and may become
+wild.  Similarly, when you trigger certain types of traps which alter
+your location (for instance, a trap door which drops you to a lower
+dungeon level), any adjacent pet will accompany you and any non-adjacent
+pet will be left behind.  Your pet may trigger such traps itself; you
+will not be carried along with it even if adjacent at the time.
+
+%.hn 2
+\subsection*{Steeds}
+
+%.pg
+Some types of creatures in the dungeon can actually be ridden if you
+have the right equipment and skill.  Convincing a wild beast to let
+you saddle it up is difficult to say the least.  Many a dungeoneer
+has had to resort to magic and wizardry in order to forge the alliance.
+Once you do have the beast under your control however, you can
+easily climb in and out of the saddle with the `{\tt \#ride}' command.  Lead
+the beast around the dungeon when riding, in the same manner as
+you would move yourself.  It is the beast that you will see displayed
+on the map.
+
+%.pg
+Riding skill is managed by the `{\tt \#enhance}' command.  See the section
+on Weapon proficiency for more information about that.
+
+%.hn 2
+\subsection*{Bones levels}
+
+%.pg
+You may encounter the shades and corpses of other adventurers (or even
+former incarnations of yourself!) and their personal effects.  Ghosts
+are hard to kill, but easy to avoid, since they're slow and do little
+damage.  You can plunder the deceased adventurer's possessions;
+however, they are likely to be cursed.  Beware of whatever killed the
+former player; it is probably still lurking around, gloating over its
+last victory.
+
+%.hn 1
+\section{Objects}
+
+%.pg
+When you find something in the dungeon, it is common to want to pick
+it up.  In {\it NetHack}, this is accomplished automatically by walking over
+the object (unless you turn off the {\it autopickup\/}
+option (see below), or move with the `{\tt m}' prefix (see above)), or
+manually by using the `{\tt ,}' command.
+%.pg
+If you're carrying too many items, {\it NetHack\/} will tell you so and you
+won't be able to pick up anything more.  Otherwise, it will add the object(s)
+to your pack and tell you what you just picked up.
+%.pg
+As you add items to your inventory, you also add the weight of that object
+to your load.  The amount that you can carry depends on your strength and
+your constitution.  The
+stronger you are, the less the additional load will affect you.  There comes
+a point, though, when the weight of all of that stuff you are carrying around
+with you through the dungeon will encumber you.  Your reactions
+will get slower and you'll burn calories faster, requiring food more frequently
+to cope with it.  Eventually, you'll be so overloaded that you'll either have
+to discard some of what you're carrying or collapse under its weight.
+%.pg
+NetHack will tell you how badly you have loaded yourself.  The symbols
+`Burdened', `Stressed', `Strained', `Overtaxed' and `Overloaded' are
+displayed on the bottom line display to indicate your condition.
+
+%.pg
+When you pick up an object, it is assigned an inventory letter.  Many
+commands that operate on objects must ask you to find out which object
+you want to use.  When {\it NetHack\/} asks you to choose a particular object
+you are carrying, you are usually presented with a list of inventory
+letters to choose from (see Commands, above).
+
+%.pg
+Some objects, such as weapons, are easily differentiated.  Others, like
+scrolls and potions, are given descriptions which vary according to
+type.  During a game, any two objects with the same description are
+the same type.  However, the descriptions will vary from game to game.
+
+%.pg
+When you use one of these objects, if its effect is obvious, {\it NetHack\/}
+will remember what it is for you.  If its effect isn't extremely
+obvious, you will be asked what you want to call this type of object
+so you will recognize it later.  You can also use the ``{\tt \#name}''
+command for the same purpose at any time, to name all objects of a
+particular type or just an individual object.
+When you use ``{\tt \#name}'' on an object which has already been named,
+specifying a space as the value will remove the prior name instead
+of assigning a new one.
+
+%.hn 2
+\subsection*{Curses and Blessings}
+
+%.pg
+Any object that you find may be cursed, even if the object is
+otherwise helpful.  The most common effect of a curse is being stuck
+with (and to) the item.  Cursed weapons weld themselves to your hand
+when wielded, so you cannot unwield them.  Any cursed item you wear
+is not removable by ordinary means.  In addition, cursed arms and armor
+usually, but not always, bear negative enchantments that make them
+less effective in combat.  Other cursed objects may act poorly or
+detrimentally in other ways.
+
+%.pg
+Objects can also be blessed.  Blessed items usually work better or
+more beneficially than normal uncursed items.  For example, a blessed
+weapon will do more damage against demons.
+
+%.pg
+There are magical means of bestowing or removing curses upon objects,
+so even if you are stuck with one, you can still have the curse
+lifted and the item removed.  Priests and Priestesses have an innate
+sensitivity to this property in any object, so they can more easily avoid
+cursed objects than other character roles.
+
+%.pg
+An item with unknown status will be reported in your inventory with no prefix.
+An item which you know the state of will be distinguished in your inventory
+by the presence of the word ``cursed'', ``uncursed'' or ``blessed'' in the
+description of the item.
+
+%.hn 2
+\subsection*{Weapons (`{\tt )}')}
+
+%.pg
+Given a chance, most monsters in the Mazes of Menace will gratuitously try to
+kill you.  You need weapons for self-defense (killing them first).  Without a
+weapon, you do only 1--2 hit points of damage (plus bonuses, if any).
+Monk characters are an exception; they normally do much more damage with
+bare hands than they do with weapons.
+
+%.pg
+There are wielded weapons, like maces and swords, and thrown weapons,
+like arrows and spears.  To hit monsters with a weapon, you must wield it and
+attack them, or throw it at them.  You can simply elect to throw a spear.
+To shoot an arrow, you should first wield a bow, then throw the arrow.
+Crossbows shoot crossbow bolts.  Slings hurl rocks and (other) stones
+(like gems).
+
+%.pg
+Enchanted weapons have a ``plus'' (or ``to hit enhancement'' which can be
+either positive or negative) that adds to your chance to
+hit and the damage you do to a monster.  The only way to determine a weapon's
+enchantment is to have it magically identified somehow.
+Most weapons are subject to some type of damage like rust.  Such
+``erosion'' damage can be repaired.
+
+%.pg
+The chance that an attack will successfully hit a monster, and the amount
+of damage such a hit will do, depends upon many factors.  Among them are:
+type of weapon, quality of weapon (enchantment and/or erosion), experience
+level, strength, dexterity, encumbrance, and proficiency (see below).  The
+monster's armor class---a general defense rating, not necessarily due to
+wearing of armor---is a factor too; also, some monsters are particularly
+vulnerable to certain types of weapons.
+
+%.pg
+Many weapons can be wielded in one hand; some require both hands.
+When wielding a two-handed weapon, you can not wear a shield, and
+vice versa.  When wielding a one-handed weapon, you can have another
+weapon ready to use by setting things up with the `{\tt x}' command, which
+exchanges your primary (the one being wielded) and alternate weapons.
+And if you have proficiency in the ``two weapon combat'' skill, you
+may wield both weapons simultaneously as primary and secondary; use the
+`{\tt \#twoweapon}' extended command to engage or disengage that.  Only
+some types of characters (barbarians, for instance) have the necessary
+skill available.  Even with that skill, using two weapons at once incurs
+a penalty in the chance to hit your target compared to using just one
+weapon at a time.
+
+%.pg
+There might be times when you'd rather not wield any weapon at all.
+To accomplish that, wield `{\tt -}', or else use the `{\tt A}' command which
+allows you to unwield the current weapon in addition to taking off
+other worn items.
+
+%.pg
+Those of you in the audience who are AD\&D players, be aware that each
+weapon which existed in AD\&D does roughly the same damage to monsters in
+{\it NetHack}.  Some of the more obscure weapons (such as the %
+{\it aklys}, {\it lucern hammer}, and {\it bec-de-corbin\/}) are defined
+in an appendix to {\it Unearthed Arcana}, an AD\&D supplement.
+
+%.pg
+The commands to use weapons are `{\tt w}' (wield), `{\tt t}' (throw),
+`{\tt f}' (fire, an alternative way of throwing), `{\tt Q}' (quiver),
+`{\tt x}' (exchange), `{\tt \#twoweapon}', and `{\tt \#enhance}' (see below).
+
+%.hn 3
+\subsection*{Throwing and shooting}
+
+%.pg
+You can throw just about anything via the `{\tt t}' command.  It will prompt
+for the item to throw; picking `{\tt ?}' will list things in your inventory
+which are considered likely to be thrown, or picking `{\tt *}' will list
+your entire inventory.  After you've chosen what to throw, you will
+be prompted for a direction rather than for a specific target.  The
+distance something can be thrown depends mainly on the type of object
+and your strength.  Arrows can be thrown by hand, but can be thrown
+much farther and will be more likely to hit when thrown while you are
+wielding a bow.
+
+%.pg
+You can simplify the throwing operation by using the `{\tt Q}' command to
+select your preferred ``missile'', then using the `{\tt f}' command to
+throw it.  You'll be prompted for a direction as above, but you don't
+have to specify which item to throw each time you use `{\tt f}'.  There is
+also an option,
+{\it autoquiver},
+which has {\it NetHack\/} choose another item to automatically fill your
+quiver when the inventory slot used for `{\tt Q}' runs out.
+
+%.pg
+Some characters have the ability to fire a volley of multiple items in a
+single turn.  Knowing how to load several rounds of ammunition at
+once---or hold several missiles in your hand---and still hit a
+target is not an easy task.  Rangers are among those who are adept
+at this task, as are those with a high level of proficiency in the
+relevant weapon skill (in bow skill if you're wielding one to
+shoot arrows, in crossbow skill if you're wielding one to shoot bolts,
+or in sling skill if you're wielding one to shoot stones).
+The number of items that the character has a chance to fire varies from
+turn to turn.  You can explicitly limit the number of shots by using a
+numeric prefix before the `{\tt t}' or `{\tt f}' command.
+For example, ``{\tt 2f}'' (or ``{\tt n2f}'' if using
+{\it number\_pad\/}
+mode) would ensure that at most 2 arrows are shot
+even if you could have fired 3.  If you specify
+a larger number than would have been shot (``{\tt 4f}'' in this example),
+you'll just end up shooting the same number (3, here) as if no limit
+had been specified.  Once the volley is in motion, all of the items
+will travel in the same direction; if the first ones kill a monster,
+the others can still continue beyond that spot.
+
+%.hn 3
+\subsection*{Weapon proficiency}
+
+%.pg
+You will have varying degrees of skill in the weapons available.
+Weapon proficiency, or weapon skills, affect how well you can use
+particular types of weapons, and you'll be able to improve your skills
+as you progress through a game, depending on your role, your experience
+level, and use of the weapons.
+
+%.pg
+For the purposes of proficiency, weapons have
+been divided up into various groups such as daggers, broadswords, and
+polearms.  Each role has a limit on what level of proficiency a character
+can achieve for each group.  For instance, wizards can become highly
+skilled in daggers or staves but not in swords or bows.
+
+%.pg
+The `{\tt \#enhance}' extended command is used to review current weapons proficiency
+(also spell proficiency) and to choose which skill(s) to improve when
+you've used one or more skills enough to become eligible to do so.  The
+skill rankings are ``none'' (sometimes also referred to as ``restricted'',
+because you won't be able to advance), ``unskilled'', ``basic'', ``skilled'',
+and ``expert''.  Restricted skills simply will not appear in the list
+shown by `{\tt \#enhance}'.  (Divine intervention might unrestrict a particular
+skill, in which case it will start at unskilled and be limited to basic.)
+Some characters can enhance their barehanded combat or martial arts skill
+beyond expert to ``master'' or ``grand master''.
+
+%.pg
+Use of a weapon in which you're restricted or unskilled
+will incur a modest penalty in the chance to hit a monster and also in
+the amount of damage done when you do hit; at basic level, there is no
+penalty or bonus; at skilled level, you receive a modest bonus in the
+chance to hit and amount of damage done; at expert level, the bonus is
+higher.  A successful hit has a chance to boost your training towards
+the next skill level (unless you've already reached the limit for this
+skill).  Once such training reaches the threshold for that next level,
+you'll be told that you feel more confident in your skills.  At that
+point you can use `{\tt \#enhance}' to increase one or more skills.  Such skills
+are not increased automatically because there is a limit to your total
+overall skills, so you need to actively choose which skills to enhance
+and which to ignore.
+
+%.hn 2
+\subsection*{Armor (`{\tt [}')}
+
+%.pg
+Lots of unfriendly things lurk about; you need armor to protect
+yourself from their blows.  Some types of armor offer better
+protection than others.  Your armor class is a measure of this
+protection.  Armor class (AC) is measured as in AD\&D, with 10 being
+the equivalent of no armor, and lower numbers meaning better armor.
+Each suit of armor which exists in AD\&D gives the same protection in
+{\it NetHack}.  Here is an (incomplete) list of the armor classes provided by
+various suits of armor:
+
+\begin{center}
+\begin{tabular}{lllll}
+dragon scale mail      & 1 & \makebox[20mm]{}  & plate mail            & 3\\
+crystal plate mail     & 3 &                   & bronze plate mail     & 4\\
+splint mail            & 4 &                   & banded mail           & 4\\
+dwarvish mithril-coat  & 4 &                   & elven mithril-coat    & 5\\
+chain mail             & 5 &                   & orcish chain mail     & 6\\
+scale mail             & 6 &                   & studded leather armor & 7\\
+ring mail              & 7 &                   & orcish ring mail      & 8\\
+leather armor          & 8 &                   & leather jacket        & 9\\
+no armor               & 10
+\end{tabular}
+\end{center}
+
+%.pg
+\nd You can also wear other pieces of armor (ex.\ helmets, boots,
+shields, cloaks)
+to lower your armor class even further, but you can only wear one item
+of each category (one suit of armor, one cloak, one helmet, one
+shield, and so on) at a time.
+
+%.pg
+If a piece of armor is enchanted, its armor protection will be better
+(or worse) than normal, and its ``plus'' (or minus) will subtract from
+your armor class.  For example, a +1 chain mail would give you
+better protection than normal chain mail, lowering your armor class one
+unit further to 4.  When you put on a piece of armor, you immediately
+find out the armor class and any ``plusses'' it provides.  Cursed
+pieces of armor usually have negative enchantments (minuses) in
+addition to being unremovable.
+
+%.pg
+Many types of armor are subject to some kind of damage like rust.  Such
+damage can be repaired.  Some types of armor may inhibit spell casting.
+
+%.pg
+The commands to use armor are `{\tt W}' (wear) and `{\tt T}' (take off).
+The `{\tt A}' command can also be used to take off armor as well as other
+worn items.
+
+%.hn 2
+\subsection*{Food (`{\tt \%}')}
+
+%.pg
+Food is necessary to survive.  If you go too long without eating you
+will faint, and eventually die of starvation.
+Some types of food will spoil, and become unhealthy to eat,
+if not protected.
+Food stored in ice boxes or tins (``cans'')
+will usually stay fresh, but ice boxes are heavy, and tins
+take a while to open.
+
+%.pg
+When you kill monsters, they usually leave corpses which are also
+``food.''  Many, but not all, of these are edible; some also give you
+special powers when you eat them.  A good rule of thumb is ``you are
+what you eat.''
+
+%.pg
+Some character roles and some monsters are vegetarian.  Vegetarian monsters
+will typically never eat animal corpses, while vegetarian players can,
+but with some rather unpleasant side-effects.
+
+%.pg
+You can name one food item after something you like to eat with the
+{\it fruit\/} option.
+
+%.pg
+The command to eat food is `{\tt e}'.
+
+%.hn 2
+\subsection*{Scrolls (`{\tt ?}')}
+
+%.pg
+Scrolls are labeled with various titles, probably chosen by ancient wizards
+for their amusement value (ex.\ ``READ ME,'' or ``THANX MAUD'' backwards).
+Scrolls disappear after you read them (except for blank ones, without
+magic spells on them).
+
+%.pg
+One of the most useful of these is the %
+{\it scroll of identify}, which
+can be used to determine what another object is, whether it is cursed or
+blessed, and how many uses it has left.  Some objects of subtle
+enchantment are difficult to identify without these.
+
+%.pg
+A mail daemon may run up and deliver mail to you as a %
+{\it scroll of mail} (on versions compiled with this feature).
+To use this feature on versions where {\it NetHack\/}
+mail delivery is triggered by electronic mail appearing in your system mailbox,
+you must let {\it NetHack\/} know where to look for new mail by setting the
+``MAIL'' environment variable to the file name of your mailbox.
+You may also want to set the ``MAILREADER'' environment variable to the
+file name of your favorite reader, so {\it NetHack\/} can shell to it when you
+read the scroll.
+On versions of {\it NetHack\/} where mail is randomly
+generated internal to the game, these environment variables are ignored.
+You can disable the mail daemon by turning off the
+{\it mail\/} option.
+
+%.pg
+The command to read a scroll is `{\tt r}'.
+
+%.hn 2
+\subsection*{Potions (`{\tt !}')}
+
+%.pg
+Potions are distinguished by the color of the liquid inside the flask.
+They disappear after you quaff them.
+
+%.pg
+Clear potions are potions of water.  Sometimes these are
+blessed or cursed, resulting in holy or unholy water.  Holy water is
+the bane of the undead, so potions of holy water are good things to
+throw (`{\tt t}') at them.  It is also sometimes very useful to dip
+(``{\tt \#dip}'') an object into a potion.
+
+%.pg
+The command to drink a potion is `{\tt q}' (quaff).
+
+%.hn 2
+\subsection*{Wands (`{\tt /}')}
+
+%.pg
+Magic wands usually have multiple magical charges.  Some wands are
+directional---you must give a direction in which to zap them.  You can also
+zap them at yourself (just give a `{\tt .}' or `{\tt s}' for the direction).
+Be warned, however, for this is often unwise.  Other wands are
+nondirectional---they don't require a direction.  The number of charges in a
+wand is random and decreases by one whenever you use it.
+
+%.pg
+When the number of charges left in a wand becomes zero, attempts to use the
+wand will usually result in nothing happening.  Occasionally, however, it may
+be possible to squeeze the last few mana points from an otherwise spent wand,
+destroying it in the process.  A wand may be recharged by using suitable
+magic, but doing so runs the risk of causing it to explode.  The chance
+for such an explosion starts out very small and increases each time the
+wand is recharged.
+
+%.pg
+In a truly desperate situation, when your back is up against the wall, you
+might decide to go for broke and break your wand.  This is not for the faint
+of heart.  Doing so will almost certainly cause a catastrophic release of
+magical energies.
+
+%.pg
+When you have fully identified a particular wand, inventory display will
+include additional information in parentheses: the number of times it has
+been recharged followed by a colon and then by its current number of charges.
+A current charge count of {\tt -1} is a special case indicating that the wand
+has been cancelled.
+
+%.pg
+The command to use a wand is `{\tt z}' (zap).  To break one, use the `{\tt a}'
+(apply) command.
+
+%.hn 2
+\subsection*{Rings (`{\tt =}')}
+
+%.pg
+Rings are very useful items, since they are relatively permanent
+magic, unlike the usually fleeting effects of potions, scrolls, and
+wands.
+
+%.pg
+Putting on a ring activates its magic.  You can wear only two
+rings, one on each ring finger.
+
+%.pg
+Most rings also cause you to grow hungry more rapidly, the rate
+varying with the type of ring.
+
+%.pg
+The commands to use rings are `{\tt P}' (put on) and `{\tt R}' (remove).
+
+%.hn 2
+\subsection*{Spellbooks (`{\tt +}')}
+
+%.pg
+Spellbooks are tomes of mighty magic.  When studied with the `{\tt r}' (read)
+command, they transfer to the reader the knowledge of a spell (and
+therefore eventually become unreadable) --- unless the attempt backfires.
+Reading a cursed spellbook or one with mystic runes beyond
+your ken can be harmful to your health!
+
+%.pg
+A spell (even when learned) can also backfire when you cast it.  If you
+attempt to cast a spell well above your experience level, or if you have
+little skill with the appropriate spell type, or cast it at
+a time when your luck is particularly bad, you can end up wasting both the
+energy and the time required in casting.
+
+%.pg
+Casting a spell calls forth magical energies and focuses them with
+your naked mind.  Some of the magical energy released comes from within
+you, and casting several spells in a row may tire you.
+Casting of spells also requires practice.  With practice, your
+skill in each category of spell casting will improve.  Over time, however,
+your memory of each spell will dim, and you will need to relearn it.
+
+%.pg
+Some spells are
+directional---you must give a direction in which to cast them.  You can also
+cast them at yourself (just give a `{\tt .}' or `{\tt s}' for the direction).
+Be warned, however, for this is often unwise.  Other spells are
+nondirectional---they don't require a direction.
+
+%.pg
+Just as weapons are divided into groups in which a character can become
+proficient (to varying degrees), spells are similarly grouped.
+Successfully casting a spell exercises the skill group; sufficient skill
+may increase the potency of the spell and reduce the risk of spell failure.
+Skill slots are shared with weapons skills.  (See also the section on
+``Weapon proficiency''.)
+
+%.pg
+Casting a spell also requires flexible movement, and wearing various types
+of armor may interfere with that.
+
+%.pg
+The command to read a spellbook is the same as for scrolls, `{\tt r}'
+(read).  The `{\tt +}' command lists your current spells, their levels,
+categories, and chances for failure.
+The `{\tt Z}' (cast) command casts a spell.
+
+%.hn 2
+\subsection*{Tools (`{\tt (}')}
+
+%.pg
+Tools are miscellaneous objects with various purposes.  Some tools
+have a limited number of uses, akin to wand charges.  For example, lamps burn
+out after a while.  Other tools are containers, which objects can
+be placed into or taken out of.
+
+%.pg
+The command to use tools is `{\tt a}' (apply).
+
+%.hn 3
+\subsection*{Containers}
+
+%.pg
+You may encounter bags, boxes, and chests in your travels.  A tool of
+this sort can be opened with the ``{\tt \#loot}'' extended command when
+you are standing on top of it (that is, on the same floor spot),
+or with the `{\tt a}' (apply) command when you are carrying it.  However,
+chests are often locked, and are in any case unwieldy objects.
+You must set one down before unlocking it by
+using a key or lock-picking tool with the `{\tt a}' (apply) command,
+by kicking it with the `{\tt \^{}D}' command,
+or by using a weapon to force the lock with the ``{\tt \#force}''
+extended command.
+
+%.pg
+Some chests are trapped, causing nasty things to happen when you
+unlock or open them.  You can check for and try to deactivate traps
+with the ``{\tt \#untrap}'' extended command.
+
+%.hn 2
+\subsection*{Amulets (`{\tt "}')}
+
+%.pg
+Amulets are very similar to rings, and often more powerful.  Like
+rings, amulets have various magical properties, some beneficial,
+some harmful, which are activated by putting them on.
+
+%.pg
+Only one amulet may be worn at a time, around your neck.
+
+%.pg
+The commands to use amulets are the same as for rings, `{\tt P}' (put on)
+and `{\tt R}' (remove).
+
+%.hn 2
+\subsection*{Gems (`{\tt *}')}
+
+%.pg
+Some gems are valuable, and can be sold for a lot of gold.  They are also
+a far more efficient way of carrying your riches.  Valuable gems increase
+your score if you bring them with you when you exit.
+
+%.pg
+Other small rocks are also categorized as gems, but they are much less
+valuable.  All rocks, however, can be used as projectile weapons (if you
+have a sling).  In the most desperate of cases, you can still throw them
+by hand.
+
+%.hn 2
+\subsection*{Large rocks (`{\tt `}')}
+%.pg
+Statues and boulders are not particularly useful, and are generally
+heavy.  It is rumored that some statues are not what they seem.
+
+%.pg
+Very large humanoids (giants and their ilk) have been known to use boulders
+as weapons.
+
+%.hn 2
+\subsection*{Gold (`{\tt \$}')}
+
+%.pg
+Gold adds to your score, and you can buy things in shops with it.
+There are a number
+of monsters in the dungeon that may be influenced by the amount of gold
+you are carrying (shopkeepers aside).
+
+%.hn 1
+\section{Conduct}
+
+%.pg
+As if winning {\it NetHack\/} were not difficult enough, certain players
+seek to challenge themselves by imposing restrictions on the
+way they play the game.  The game automatically tracks some of
+these challenges, which can be checked at any time with the {\tt \#conduct}
+command or at the end of the game.  When you perform an action which
+breaks a challenge, it will no longer be listed.  This gives
+players extra ``bragging rights'' for winning the game with these
+challenges.  Note that it is perfectly acceptable to win the game
+without resorting to these restrictions and that it is unusual for
+players to adhere to challenges the first time they win the game.
+
+%.pg
+Several of the challenges are related to eating behavior.  The most
+difficult of these is the foodless challenge.  Although creatures
+can survive long periods of time without food, there is a physiological
+need for water; thus there is no restriction on drinking beverages,
+even if they provide some minor food benefits.
+Calling upon your god for help with starvation does
+not violate any food challenges either.
+
+%.pg
+A strict vegan diet is one which avoids any food derived from animals.
+The primary source of nutrition is fruits and vegetables.  The
+corpses and tins of blobs (`b'), jellies (`j'), and fungi (`F') are
+also considered to be vegetable matter.  Certain human
+food is prepared without animal products; namely, lembas wafers, cram
+rations, food rations (gunyoki), K-rations, and C-rations.
+Metal or another normally indigestible material eaten while polymorphed
+into a creature that can digest it is also considered vegan food.
+Note however that eating such items still counts against foodless conduct.
+
+%.pg
+Vegetarians do not eat animals;
+however, they are less selective about eating animal byproducts than vegans.
+In addition to the vegan items listed above, they may eat any kind
+of pudding (`P') other than the black puddings,
+eggs and food made from eggs (fortune cookies and pancakes),
+food made with milk (cream pies and candy bars), and lumps of
+royal jelly.  Monks are expected to observe a vegetarian diet.
+
+%.pg
+Eating any kind of meat violates the vegetarian, vegan, and foodless
+conducts.  This includes tripe rations, the corpses or tins of any
+monsters not mentioned above, and the various other chunks of meat
+found in the dungeon.  Swallowing and digesting a monster while polymorphed
+is treated as if you ate the creature's corpse.
+Eating leather, dragon hide, or bone items while
+polymorphed into a creature that can digest it, or eating monster brains
+while polymorphed into a mind flayer, is considered eating
+an animal, although wax is only an animal byproduct.
+
+%.pg
+Regardless of conduct, there will be some items which are indigestible,
+and others which are hazardous to eat.  Using a swallow-and-digest
+attack against a monster is equivalent to eating the monster's corpse.
+Please note that the term ``vegan'' is used here only in the context of
+diet.  You are still free to choose not to use or wear items derived
+from animals (e.g. leather, dragon hide, bone, horns, coral), but the
+game will not keep track of this for you.  Also note that ``milky''
+potions may be a translucent white, but they do not contain milk,
+so they are compatible with a vegan diet.  Slime molds or
+player-defined ``fruits'', although they could be anything
+from ``cherries'' to ``pork chops'', are also assumed to be vegan.
+
+%.pg
+An atheist is one who rejects religion.  This means that you cannot
+{\tt \#pray}, {\tt \#offer} sacrifices to any god,
+{\tt \#turn} undead, or {\tt \#chat} with a priest.
+Particularly selective readers may argue that playing Monk or Priest
+characters should violate this conduct; that is a choice left to the
+player.  Offering the Amulet of Yendor to your god is necessary to
+win the game and is not counted against this conduct.  You are also
+not penalized for being spoken to by an angry god, priest(ess), or
+other religious figure; a true atheist would hear the words but
+attach no special meaning to them.
+
+%.pg
+Most players fight with a wielded weapon (or tool intended to be
+wielded as a weapon).  Another challenge is to win the game without
+using such a wielded weapon.  You are still permitted to throw,
+fire, and kick weapons; use a wand, spell, or other type of item;
+or fight with your hands and feet.
+
+%.pg
+In {\it NetHack\/}, a pacifist refuses to cause the death of any other monster
+(i.e. if you would get experience for the death).  This is a particularly
+difficult challenge, although it is still possible to gain experience
+by other means.
+
+%.pg
+An illiterate character cannot read or write.  This includes reading
+a scroll, spellbook, fortune cookie message, or t-shirt; writing a
+scroll; or making an engraving of anything other than a single ``x'' (the
+traditional signature of an illiterate person).  Reading an engraving,
+or any item that is absolutely necessary to win the game, is not counted
+against this conduct.  The identity of scrolls and spellbooks (and
+knowledge of spells) in your starting inventory is assumed to be
+learned from your teachers prior to the start of the game and isn't
+counted.
+
+%.pg
+There are several other challenges tracked by the game.  It is possible
+to eliminate one or more species of monsters by genocide; playing without
+this feature is considered a challenge.  When the game offers you an
+opportunity to genocide monsters, you may respond with the monster type
+``none'' if you want to decline.  You can change the form of an item into
+another item of the same type (``polypiling'') or the form of your own
+body into another creature (``polyself'') by wand, spell, or potion of
+polymorph; avoiding these effects are each considered challenges.
+Polymorphing monsters, including pets, does not break either of these
+challenges.
+Finally, you may sometimes receive wishes; a game without an attempt to
+wish for any items is a challenge, as is a game without wishing for
+an artifact (even if the artifact immediately disappears).  When the
+game offers you an opportunity to make a wish for an item, you may
+choose ``nothing'' if you want to decline.
+
+%.hn 1
+\section{Options}
+
+%.pg
+Due to variations in personal tastes and conceptions of how {\it NetHack\/}
+should do things, there are options you can set to change how {\it NetHack\/}
+behaves.
+
+%.hn 2
+\subsection*{Setting the options}
+
+%.pg
+Options may be set in a number of ways.  Within the game, the `{\tt O}'
+command allows you to view all options and change most of them.
+You can also set options automatically by placing them in the
+``NETHACKOPTIONS'' environment variable or in a configuration file.
+Some versions of {\it NetHack\/} also have front-end programs that allow
+you to set options before starting the game.
+
+%.hn 2
+\subsection*{Using the NETHACKOPTIONS environment variable}
+
+%.pg
+The NETHACKOPTIONS variable is a comma-separated list of initial
+values for the various options.  Some can only be turned on or off.
+You turn one of these on by adding the name of the option to the list,
+and turn it off by typing a `{\tt !}' or ``{\tt no}'' before the name.
+Others take a
+character string as a value.  You can set string options by typing
+the option name, a colon or equals sign, and then the value of the string.
+The value is terminated by the next comma or the end of string.
+
+%.pg
+For example, to set up an environment variable so that {\it autoquiver\/}
+is on, {\it autopickup\/} is off, the {\it name\/} is set to ``Blue Meanie'',
+and the {\it fruit\/} is set to ``papaya'', you would enter the command
+%.sd
+\begin{verbatim}
+    setenv NETHACKOPTIONS "autoquiver,\!autopickup,name:Blue Meanie,fruit:papaya"
+\end{verbatim}
+%.ed
+
+\nd in {\it csh}
+(note the need to escape the ! since it's special to the shell), or
+%.sd
+\begin{verbatim}
+    NETHACKOPTIONS="autoquiver,!autopickup,name:Blue Meanie,fruit:papaya"
+    export NETHACKOPTIONS
+\end{verbatim}
+%.ed
+
+\nd in {\it sh\/} or {\it ksh}.
+
+%.hn 2
+\subsection*{Using a configuration file}
+
+%.pg
+Any line in the configuration file starting with `{\tt \#}' is treated as a comment.
+Any line in the configuration file starting with ``{\tt OPTIONS=}'' may be
+filled out with options in the same syntax as in NETHACKOPTIONS.
+Any line starting with ``{\tt DUNGEON=}'', ``{\tt EFFECTS=}'',
+``{\tt MONSTERS=}'', ``{\tt OBJECTS=}'', ``{\tt TRAPS=}'', 
+or ``{\tt BOULDER=}''
+is taken as defining the corresponding {\it dungeon},
+{\it effects}, {\it monsters}, {\it objects}, {\it traps\/} or
+{\it boulder\/} option in a different syntax,
+a sequence of decimal numbers giving the character position
+in the current font to be used in displaying each entry.
+A zero in any entry in such a sequence leaves the display of that
+entry unchanged; this feature is not available using the option syntax.
+Such a sequence can be continued to multiple lines by putting a
+`{\tt \verb+\+}' at the end of each line to be continued.
+
+%.pg
+If your copy of the game included the compile time AUTOPICKUP\_EXCEPTIONS 
+option, then any line starting with ``{\tt AUTOPICKUP\_EXCEPTION=}'' 
+is taken as defining an exception to the ``{\tt pickup\_types}'' option.
+There is a section of this Guidebook that discusses that.
+
+%.pg
+The default name of the configuration file varies on different
+operating systems, but NETHACKOPTIONS can also be set to
+the full name of a file you want to use (possibly preceded by an `{\tt @}').
+
+%.hn 2
+\subsection*{Customization options}
+
+%.pg
+Here are explanations of what the various options do.
+Character strings that are too long may be truncated.
+Some of the options listed may be inactive in your dungeon.
+
+\blist{}
+%.lp
+\item[\ib{align}]
+Your starting alignment ({\tt align:lawful}, {\tt align:neutral},
+or {\tt align:chaotic}).  You may specify just the first letter.
+The default is to randomly pick an appropriate alignment.
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{autodig}]
+Automatically dig if you are wielding a digging tool and moving into a place
+that can be dug (default false).
+%.lp
+\item[\ib{autopickup}]
+Automatically pick up things onto which you move (default on).
+See ``{\it pickup\_types\/}'' to refine the behavior.
+%.lp
+\item[\ib{autoquiver}]
+This option controls what happens when you attempt the `f' (fire)
+command with an empty quiver.  When true, the computer will fill
+your quiver with some suitable weapon.  Note that it will not take
+into account the blessed/cursed status, enchantment, damage, or
+quality of the weapon; you are free to manually fill your quiver with
+the `Q' command instead.  If no weapon is found or the option is
+false, the `t' (throw) command is executed instead.  (default false)
+%.lp
+\item[\ib{boulder}]
+Set the character used to display boulders (default is rock class symbol).
+%.lp
+\item[\ib{catname}]
+Name your starting cat (ex.\ ``{\tt catname:Morris}'').
+Cannot be set with the `{\tt O}' command.
+%.lp character
+\item[\ib{character}]
+Pick your type of character (ex.\ ``{\tt character:Monk}'');
+synonym for ``{\it role\/}''.  See ``{\it name\/}'' for an alternate method
+of specifying your role.  Normally only the first letter of
+the value is examined; the string ``{\tt random}'' is an exception.
+%.lp
+\item[\ib{checkpoint}]
+Save game state after each level change, for possible recovery after
+program crash (default on).
+%.lp
+\item[\ib{checkspace}]
+Check free disk space before writing files to disk (default on).
+You may have to turn this off if you have more than 2 GB free space
+on the partition used for your save and level files.
+Only applies when MFLOPPY was defined during compilation.
+%.lp
+\item[\ib{cmdassist}]
+Have the game provide some additional command assistance for new 
+players if it detects some anticipated mistakes (default on).
+%.lp
+\item[\ib{confirm}]
+Have user confirm attacks on pets, shopkeepers, and other
+peaceable creatures (default on).
+%.lp
+\item[\ib{DECgraphics}]
+Use a predefined selection of characters from the DEC VT-xxx/DEC
+Rainbow/ANSI line-drawing character set to display the dungeon/effects/traps
+instead of having to define a full graphics set yourself (default off).
+This option also sets up proper handling of graphics
+characters for such terminals, so you should specify it when appropriate
+even if you override the selections with your own graphics strings.
+%.lp
+\item[\ib{disclose}]
+Controls options for disclosing various information when the game ends (defaults
+to all possibilities being disclosed).
+The possibilities are:
+
+%.sd
+%.si
+{\tt i} --- disclose your inventory.\\
+{\tt a} --- disclose your attributes.\\
+{\tt v} --- summarize monsters that have been vanquished.\\
+{\tt g} --- list monster species that have been genocided.\\
+{\tt c} --- display your conduct.
+%.ei
+%.ed
+
+Each disclosure possibility can optionally be preceded by a prefix which
+let you refine how it behaves. Here are the valid prefixes:
+
+%.sd
+%.si
+{\tt y} --- prompt you and default to yes on the prompt.\\
+{\tt n} --- prompt you and default to no on the prompt.\\
+{\tt +} --- disclose it without prompting.\\
+{\tt -} --- do not disclose it and do not prompt.
+%.ei
+%.ed
+
+(ex.\ ``{\tt disclose:yi na +v -g -c}'')
+The example sets {\it inventory\/} to {\it prompt\/} and default to {\it yes\/}, 
+{\it attributes\/} to {\it prompt\/} and default to {\it no\/}, 
+{\it vanquished\/} to {\it disclose without prompting\/}, 
+{\it genocided\/} to {\it not disclose\/} and not to {\it prompt\/}, and 
+{\it conduct\/} to {\it not disclose\/} and not to {\it prompt\/}.
+Note that the vanquished monsters list includes all monsters killed by
+traps and each other as well as by you. 
+%.lp
+\item[\ib{dogname}]
+Name your starting dog (ex.\ ``{\tt dogname:Fang}'').
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{dungeon}]
+Set the graphics symbols for displaying the dungeon (default
+``\verb& |--------||.-|++##& \verb&.##<><>_|\\#{}.}..## #}&'').
+The {\it dungeon\/} option should be
+followed by a string of 1--41
+characters to be used instead of the default map-drawing characters.
+The dungeon map will use the characters you specify instead of the
+default symbols, and default symbols for any you do not specify.
+Remember that you may need to escape some of these characters
+on a command line if they are special to your shell.
+
+Note that {\it NetHack\/} escape-processes this option string in conventional C
+fashion.  This means that `\verb+\+' is a prefix to take the following
+character literally.  Thus `\verb+\+' needs to be represented as `\verb+\\+'.
+The special escape form
+`\verb+\m+' switches on the meta bit in the following character, and the
+`{\tt \^{}}' prefix causes the following character to be treated as a control
+character.
+
+The order of the symbols is:  solid rock, vertical wall, horizontal
+wall, upper left corner, upper right corner, lower left corner, lower
+right corner, cross wall, upward T wall, downward T wall, leftward T
+wall, rightward T wall, no door, vertical open door, horizontal open
+door, vertical closed door, horizontal closed door, iron bars, tree,
+floor of a room, dark corridor, lit corridor, stairs up, stairs down,
+ladder up, ladder down, altar, grave, throne, kitchen sink, fountain, pool or moat,
+ice, lava, vertical lowered drawbridge, horizontal lowered drawbridge,
+vertical raised drawbridge, horizontal raised drawbridge, air, cloud,
+under water.
+
+You might want to use `{\tt +}' for the corners and T walls for a more
+aesthetic, boxier display.  Note that in the next release, new symbols
+may be added, or the present ones rearranged.
+
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{effects}]
+Set the graphics symbols for displaying special effects (default
+``\verb&|-\\/*!)(0#@*/-\\& \verb&||\\-//-\\| |\\-/&'').
+The {\it effects\/} option should be
+followed by a string of 1--29
+characters to be used instead of the default special-effects characters.
+This string is subjected to the same processing as the {\it dungeon\/} option.
+
+The order of the symbols is:  vertical beam, horizontal beam, left slant,
+right slant, digging beam, camera flash beam, left boomerang, right boomerang,
+four glyphs giving the sequence for magic resistance displays,
+the eight surrounding glyphs for swallowed display,
+nine glyphs for explosions.
+An explosion consists of three rows (top, middle, and bottom) of three
+characters.  The explosion is centered in the center of this $3 \times 3$
+array.
+
+Note that in the next release, new symbols may be added,
+or the present ones rearranged.
+
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{extmenu}]
+Changes the extended commands interface to pop-up a menu of available commands.
+It is keystroke compatible with the traditional interface except that it does
+not require that you hit Enter.  It is implemented only by the tty port 
+(default off), when the game has been compiled to support tty graphics.
+%.lp
+\item[\ib{female}]
+An obsolete synonym for ``{\tt gender:female}''.  Cannot be set with the
+`{\tt O}' command.
+%.lp
+\item[\ib{fixinv}]
+An object's inventory letter sticks to it when it's dropped (default on).
+If this is off, dropping an object shifts all the remaining inventory letters.
+%.lp
+\item[\ib{fruit}]
+Name a fruit after something you enjoy eating (ex.\ ``{\tt fruit:mango}'')
+(default ``{\tt slime mold}''). Basically a nostalgic whimsy that
+{\it NetHack\/} uses from time to time.  You should set this to something you
+find more appetizing than slime mold.  Apples, oranges, pears, bananas, and
+melons already exist in {\it NetHack}, so don't use those.
+%.Ip
+\item[\ib{gender}]
+Your starting gender ({\tt gender:male} or {\tt gender:female}).
+You may specify just the first letter.  Although you can
+still denote your gender using the ``{\tt male}'' and ``{\tt female}''
+options, the ``{\tt gender}'' option will take precedence.
+The default is to randomly pick an appropriate gender.
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{help}]
+If more information is available for an object looked at
+with the `{\tt /}' command, ask if you want to see it (default on).
+Turning help off makes just looking at things faster, since you aren't
+interrupted with the ``{\tt More info?}'' prompt, but it also means that you
+might miss some interesting and/or important information.
+%.lp
+\item[\ib{horsename}]
+Name your starting horse (ex.\ ``{\tt horsename:Trigger}'').
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{IBMgraphics}]
+Use a predefined selection of IBM extended ASCII characters to display the
+dungeon/effects/traps instead of having to define a full graphics set
+yourself (default off).
+This option also sets up proper handling of graphics
+characters for such terminals, so you should specify it when appropriate
+even if you override the selections with your own graphics strings.
+%.lp
+\item[\ib{ignintr}]
+Ignore interrupt signals, including breaks (default off).
+%.lp
+\item[\ib{legacy}]
+Display an introductory message when starting the game (default on).
+%.lp
+\item[\ib{lit\_corridor}]
+Show corridor squares seen by night vision or a light source held by your
+character as lit (default off).
+%.lp
+\item[\ib{lootabc}]
+Use the old `{\tt a}', `{\tt b}', and `{\tt c}' keyboard shortcuts when
+looting, rather than the mnemonics `{\tt o}', `{\tt i}', and `{\tt b}' (default off).
+%.lp
+\item[\ib{mail}]
+Enable mail delivery during the game (default on).
+%.lp
+\item[\ib{male}]
+An obsolete synonym for ``{\tt gender:male}''.  Cannot be set with the
+`{\tt O}' command.
+%.lp
+\item[\ib{menustyle}]
+Controls the interface used when you need to choose various objects (in
+response to the Drop command, for instance).  The value specified should
+be the first letter of one of the following:  traditional, combination,
+partial, or full.  Traditional was the only interface available for
+earlier versions; it consists of a prompt for object class characters,
+followed by an object-by-object prompt for all items matching the selected
+object class(es).  Combination starts with a prompt for object class(es)
+of interest, but then displays a menu of matching objects rather than
+prompting one-by-one.  Partial skips the object class filtering and
+immediately displays a menu of all objects.  Full displays a menu of
+object classes rather than a character prompt, and then a menu of matching
+objects for selection.
+\item[\ib{menu\_deselect\_all}]
+Menu character accelerator to deselect all items in a menu.
+Implemented by the Amiga, Gem, X11 and tty ports.
+Default `-'.
+\item[\ib{menu\_deselect\_page}]
+Menu character accelerator to deselect all items on this page of a menu.
+Implemented by the Amiga, Gem and tty ports.
+Default `\verb+\+'.
+\item[\ib{menu\_first\_page}]
+Menu character accelerator to jump to the first page in a menu.
+Implemented by the Amiga, Gem and tty ports.
+Default `\verb+^+'.
+\item[\ib{menu\_headings}]
+Controls how the headings in a menu are highlighted.
+Values are ``{\tt bold}'', ``{\tt inverse}'', or ``{\tt underline}''.
+Not all ports can actually display all three types.
+\item[\ib{menu\_invert\_all}]
+Menu character accelerator to invert all items in a menu.
+Implemented by the Amiga, Gem, X11 and tty ports.
+Default `@'.
+\item[\ib{menu\_invert\_page}]
+Menu character accelerator to invert all items on this page of a menu.
+Implemented by the Amiga, Gem and tty ports.
+Default `\verb+~+'.
+\item[\ib{menu\_last\_page}]
+Menu character accelerator to jump to the last page in a menu.
+Implemented by the Amiga, Gem and tty ports.
+Default `\verb+|+'.
+\item[\ib{menu\_next\_page}]
+Menu character accelerator to goto the next menu page.
+Implemented by the Amiga, Gem and tty ports.
+Default `\verb+>+'.
+\item[\ib{menu\_previous\_page}]
+Menu character accelerator to goto the previous menu page.
+Implemented by the Amiga, Gem and tty ports.
+Default `\verb+<+'.
+\item[\ib{menu\_search}]
+Menu character accelerator to search for a menu item.
+Implemented by the Amiga, Gem and X11 ports.
+Default `:'.
+\item[\ib{menu\_select\_all}]
+Menu character accelerator to select all items in a menu.
+Implemented by the Amiga, Gem, X11 and tty ports.
+Default `.'.
+\item[\ib{menu\_select\_page}]
+Menu character accelerator to select all items on this page of a menu.
+Implemented by the Amiga, Gem and tty ports.
+Default `,'.
+%.lp
+\item[\ib{monsters}]
+Set the characters used to display monster classes (default
+``\verb+abcdefghijklmnopqrstuv+
+\verb+wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@ '&;:~]+'').
+This string is subjected to the same processing as the {\it dungeon\/} option.
+The order of the symbols is
+ant or other insect, blob, cockatrice,
+dog or other canine, eye or sphere, feline,
+gremlin, humanoid, imp or minor demon,
+jelly, kobold, leprechaun,
+mimic, nymph, orc,
+piercer, quadruped, rodent,
+arachnid or centipede, trapper or lurker above, horse or unicorn,
+vortex, worm, xan or other mythical/fantastic insect,
+light, zruty,
+angelic being, bat or bird, centaur,
+dragon, elemental, fungus or mold,
+gnome, giant humanoid, invisible monster,
+jabberwock, Keystone Kop, lich,
+mummy, naga, ogre,
+pudding or ooze, quantum mechanic, rust monster,
+snake, troll, umber hulk,
+vampire, wraith, xorn,
+apelike creature, zombie,
+human, ghost, golem,
+demon, sea monster, lizard,
+long worm tail, and mimic.
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{msghistory}]
+The number of top line messages to save (and recall with `{\tt \^{}P}')
+(default 20). Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{msg\_window}]
+Allows you to change the way recalled messages are displayed.
+(It is currently implemented for tty only.) The possible values are:
+
+%.sd
+%.si
+{\tt s} --- single message (default, this was the behavior before 3.4.0).\\
+{\tt c} --- combination, two messages as {\it single\/}, then as {\it full\/}.\\
+{\tt f} --- full window, oldest message first.\\
+{\tt r} --- full window, newest message first.
+%.ei
+%.ed
+
+For backward compatibility, no value needs to be specified (which
+defaults to {\it full\/}), or it can be negated (which defaults
+to {\it single\/}). 
+%.lp
+\item[\ib{name}]
+Set your character's name (defaults to your user name).  You can also
+set your character's role by appending a dash and one or more letters of
+the role (that is, by suffixing one of
+``{\tt -A -B -C -H -K -M -P -Ra -Ro -S -T -V -W}'').
+If ``{\tt -@}'' is used for the role, then a random one will be
+automatically chosen.
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{news}]
+Read the {\it NetHack\/} news file, if present (default on).
+Since the news is shown at the beginning of the game, there's no point
+in setting this with the `{\tt O}' command.
+%.lp
+\item[\ib{null}]
+Send padding nulls to the terminal (default off).
+%.lp
+\item[\ib{number\_pad}]
+Use the number keys to move instead of {\tt [yuhjklbn]} (default 0 or off).
+(number\_pad:2 invokes the old DOS behavior where `{\tt 5}' means `{\tt g}', 
+meta-`{\tt 5}' means `{\tt G}',  and meta-`{\tt 0}' means `{\tt I}'.)
+%.lp
+\item[\ib{objects}]
+Set the characters used to display object classes (default
+``\verb&])[="(%!?+/$*`0_.&'').
+This string is subjected to the same processing as the {\it dungeon\/} option.
+The order of the symbols is
+illegal-object (should never be seen), weapon, armor, ring, amulet, tool,
+food, potion, scroll, spellbook, wand, gold, gem or rock, boulder or statue,
+iron ball, chain, and venom.
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{packorder}]
+Specify the order to list object types in (default
+``\verb&")[%?+!=/(*`0_&''). The value of this option should be a string
+containing the symbols for the various object types.  Any omitted types
+are filled in at the end from the previous order.
+%.lp
+\item[\ib{perm\_invent}]
+If true, always display your current inventory in a window.  This only
+makes sense for windowing system interfaces that implement this feature.
+%.lp
+\item[\ib{pettype}]
+Specify the type of your initial pet, if you are playing a character class
+that uses multiple types of pets; or choose to have no initial pet at all.
+Possible values are ``{\tt cat}'', ``{\tt dog}'' and ``{\tt none}''.
+Cannot be set with the `{\tt O}' command.
+%.Ip
+\item[\ib{pickup\_burden}]
+When you pick up an item that would exceed this encumbrance
+level (Unburdened, Burdened, streSsed, straiNed, overTaxed,
+or overLoaded), you will be asked if you want to continue.
+(Default `S').
+%.lp
+\item[\ib{pickup\_types}]
+Specify the object types to be picked up when ``{\it autopickup\/}'' 
+is on.  Default is all types.  If your copy of the game has the
+experimental compile time option AUTOPICKUP\_EXCEPTIONS included,
+you may be able to use ``{\it autopickup\_exception\/}'' configuration
+file lines to further refine ``{\it autopickup\/}'' behavior.
+%.lp
+\item[\ib{prayconfirm}]
+Prompt for confirmation before praying (default on).
+%.lp
+\item[\ib{pushweapon}]
+Using the `w' (wield) command when already wielding
+something pushes the old item into your alternate weapon slot (default off).
+%.Ip
+\item[\ib{race}]
+Selects your race (for example, ``{\tt race:human}'').  Default is random.
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{rest\_on\_space}]
+Make the space bar a synonym for the `{\tt .}' (rest) command (default off).
+%.lp
+\item[\ib{role}]
+Pick your type of character (ex.\ ``{\tt role:Samurai}'');
+synonym for ``{\it character\/}''.  See ``{\it name\/}'' for an alternate method
+of specifying your role.  Normally only the first letter of the
+value is examined; `r' is an exception with ``{\tt Rogue}'', {\tt Ranger}'',
+and ``{\tt random}'' values.
+%.lp
+\item[\ib{runmode}]
+Controls the amount of screen updating for the map window when engaged
+in multi-turn movement (running via {\tt shift}+direction
+or {\tt control}+direction
+and so forth, or via the travel command or mouse click).
+The possible values are:
+
+%.sd
+%.si
+{\tt teleport} --- update the map after movement has finished;\\
+{\tt run} --- update the map after every seven or so steps;\\
+{\tt walk} --- update the map after each step;\\
+{\tt crawl} --- like {\it walk\/}, but pause briefly after each step.
+%.ei
+%.ed
+
+This option only affects the game's screen display, not the actual
+results of moving.  The default is {\it run\/}; versions prior to 3.4.1 
+used {\it teleport\/} only.  Whether or not the effect is noticeable will
+depend upon the window port used or on the type of terminal.
+%.lp
+\item[\ib{safe\_pet}]
+Prevent you from (knowingly) attacking your pets (default on).
+%.lp
+\item[\ib{scores}]
+Control what parts of the score list you are shown at the end (ex.\
+``{\tt scores:5top scores/4around my score/own scores}'').  Only the first
+letter of each category (`{\tt t}', `{\tt a}' or `{\tt o}') is necessary.
+%.lp
+\item[\ib{showexp}]
+Show your accumulated experience points on bottom line (default off).
+%.lp
+\item[\ib{showrace}]
+Display yourself as the glyph for your race, rather than the glyph
+for your role (default off).  Note that this setting affects only
+the appearance of the display, not the way the game treats you.
+%.lp
+\item[\ib{showscore}]
+Show your approximate accumulated score on bottom line (default off).
+%.lp
+\item[\ib{silent}]
+Suppress terminal beeps (default on).
+%.lp
+\item[\ib{sortpack}]
+Sort the pack contents by type when displaying inventory (default on).
+%.lp
+\item[\ib{sound}]
+Enable messages about what your character hears (default on).
+Note that this has nothing to do with your computer's audio capabilities.
+This option is only partly under player control.  The game toggles it
+off and on during and after sleep, for example.
+%.lp
+\item[\ib{standout}]
+Boldface monsters and ``{\tt --More--}'' (default off).
+%.lp
+\item[\ib{sparkle}]
+Display a sparkly effect when a monster (including yourself) is hit by an
+attack to which it is resistant (default on).
+%.lp
+\item[\ib{suppress\_alert}]
+This option may be set to a NetHack version level to suppress
+alert notification messages about feature changes for that 
+and prior versions (ex.\ ``{\tt suppress\_alert:3.3.1}'')
+%.lp
+\item[\ib{time}]
+Show the elapsed game time in turns on bottom line (default off).
+%.lp
+\item[\ib{timed\_delay}]
+When pausing momentarily for display effect, such as with explosions and
+moving objects, use a timer rather than sending extra characters to the
+screen.  (Applies to ``tty'' interface only; ``X11'' interface always
+uses a timer based delay.  The default is on if configured into the
+program.)
+%.lp
+\item[\ib{tombstone}]
+Draw a tombstone graphic upon your death (default on).
+%.lp
+\item[\ib{toptenwin}]
+Put the ending display in a NetHack window instead of on stdout (default off).
+Setting this option makes the score list visible when a windowing version
+of NetHack is started without a parent window, but it no longer leaves
+the score list around after game end on a terminal or emulating window.
+%.lp
+\item[\ib{traps}]
+Set the graphics symbols for displaying traps (default
+``\verb&^^^^^^^^^^^^^^^^^"^^^^&'').
+The {\it traps\/} option should be followed by a string of 1--22
+characters to be used instead of the default traps characters.
+This string is subjected to the same processing as the {\it dungeon\/} option.
+
+The order of the symbols is:
+arrow trap, dart trap, falling rock trap, squeaky board, bear trap,
+land mine, rolling boulder trap, sleeping gas trap, rust trap, fire trap,
+pit, spiked pit, hole, trap door, teleportation trap, level teleporter,
+magic portal, web, statue trap, magic trap, anti-magic field, polymorph trap.
+
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{travel}]
+Allow the travel command (default on).  Turning this option off will
+prevent the game from attempting unintended moves if you make inadvertent
+mouse clicks on the map window.
+%.lp
+\item[\ib{verbose}]
+Provide more commentary during the game (default on).
+%.lp
+\item[\ib{windowtype}]
+Select which windowing system to use, such as ``{\tt tty}'' or ``{\tt X11}''
+(default depends on version).
+Cannot be set with the `{\tt O}' command.
+\elist
+
+%.hn 2
+\subsection*{Window Port Customization options}
+
+%.pg
+Here are explanations of the various options that are
+used to customize and change the characteristics of the
+windowtype that you have chosen.
+Character strings that are too long may be truncated.
+Not all window ports will adjust for all settings listed
+here.  You can safely add any of these options to your 
+config file, and if the window port is capable of adjusting 
+to suit your preferences, it will attempt to do so. If it
+can't it will silently ignore it.  You can find out if an 
+option is supported by the window port that you are currently
+using by checking to see if it shows up in the Options list.
+Some options are dynamic and can be specified during the game
+with the `{\tt O}' command.
+
+\blist{}
+%.lp
+\item[\ib{align\_message}]
+ Where to align or place the message window (top, bottom, left, or right)
+%.lp
+\item[\ib{align\_status}]
+ Where to align or place the status window (top, bottom, left, or right).
+%.lp
+\item[\ib{ascii\_map}]
+NetHack should display an ascii map if it can.
+%.lp
+\item[\ib{color}]
+NetHack should display color if it can for different monsters, 
+objects, and dungeon features
+%.lp
+\item[\ib{eight\_bit\_tty}]
+Pass eight-bit character values (for example, specified with the {\it
+traps \/} option) straight through to your terminal (default off).
+%.lp
+\item[\ib{font\_map}]
+NetHack should use a font by the chosen name for the map window.
+%.lp
+\item[\ib{font\_menu}]
+NetHack should use a font by the chosen name for menu windows.
+%.lp
+\item[\ib{font\_message}]
+NetHack should use a font by the chosen name for the message window.
+%.lp
+\item[\ib{font\_status}]
+NetHack should use a font by the chosen name for the status window.
+%.lp
+\item[\ib{font\_text}]
+NetHack should use a font by the chosen name for text windows.
+%.lp
+\item[\ib{font\_size\_map}]
+NetHack should use this size font for the map window.
+%.lp
+\item[\ib{font\_size\_menu}]
+NetHack should use this size font for menu windows.
+%.lp
+\item[\ib{font\_size\_message}]
+NetHack should use this size font for the message window.
+%.lp
+\item[\ib{font\_size\_status}]
+NetHack should use this size font for the status window.
+%.lp
+\item[\ib{font\_size\_text}]
+NetHack should use this size font for text windows.
+%.lp
+\item[\ib{fullscreen}]
+NetHack should try and display on the entire screen rather than in a window.
+%.lp
+\item[\ib{hilite\_pet}]
+Visually distinguish pets from similar animals (default off).
+The behavior of this option depends on the type of windowing you use.
+In text windowing, text highlighting or inverse video is often used;
+with tiles, generally displays a heart symbol near pets.
+%.lp
+\item[\ib{large\_font}]
+NetHack should use a large font.
+%.lp
+\item[\ib{map\_mode}]
+NetHack should display the map in the manner specified.
+%.lp
+\item[\ib{mouse\_support}]
+Allow use of the mouse for input and travel.
+%.lp
+\item[\ib{player\_selection}]
+NetHack should pop up dialog boxes or use prompts for character selection.
+%.lp
+\item[\ib{popup\_dialog}]
+NetHack should pop up dialog boxes for input.
+%.lp
+\item[\ib{preload\_tiles}]
+NetHack should preload tiles into memory.
+For example, in the protected mode MSDOS version, control whether tiles
+get pre-loaded into RAM at the start of the game.  Doing so
+enhances performance of the tile graphics, but uses more memory. (default on).
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{scroll\_amount}]
+NetHack should scroll the display by this number of cells
+when the hero reaches the scroll\_margin.
+%.lp
+\item[\ib{scroll\_margin}]
+NetHack should scroll the display when the hero or cursor
+is this number of cells away from the edge of the window.
+%.lp
+\item[\ib{softkeyboard}]
+Display an onscreen keyboard.  Handhelds are most likely to support this option.
+%.lp
+\item[\ib{splash\_screen}]
+NetHack should display an opening splash screen when it starts up (default yes).
+%.lp
+\item[\ib{tiled\_map}]
+NetHack should display a tiled map if it can.
+%.lp
+\item[\ib{tile\_file}]
+Specify the name of an alternative tile file to override the default.
+%.lp
+\item[\ib{tile\_height}]
+Specify the preferred height of each tile in a tile capable port.
+%.lp
+\item[\ib{tile\_width}]
+Specify the preferred width of each tile in a tile capable port
+%.lp
+\item[\ib{use\_inverse}]
+NetHack should display inverse when the game specifies it.
+%.lp
+\item[\ib{vary\_msgcount}]
+NetHack should display this number of messages at a time in the message window.
+%.lp
+\item[\ib{windowcolors}]
+NetHack should display windows with the specified foreground/background 
+colors if it can.
+%.lp
+\item[\ib{wraptext}]
+NetHack port should wrap long lines of text if they don't fit in 
+the visible area of the window.
+\elist
+
+%.hn 2
+\subsection*{Platform-specific Customization options}
+
+%.pg
+Here are explanations of options that are used by specific platforms 
+or ports to customize and change the port behavior.
+
+\blist{}
+%.lp
+\item[\ib{altkeyhandler}]
+Select an alternate keystroke handler dll to load ({\it Win32 tty\/ NetHack\/} only).
+The name of the handler is specified without the .dll extension and without any
+path information.
+Cannot be set with the `{\tt O}' command.
+%.lp 
+\item[\ib{altmeta}]
+(default on, {\it Amiga NetHack \/} only).
+%.lp
+\item[\ib{BIOS}]
+Use BIOS calls to update the screen display quickly and to read the keyboard
+(allowing the use of arrow keys to move) on machines with an IBM PC
+compatible BIOS ROM (default off, {\it OS/2, PC\/ {\rm and} ST NetHack\/} only).
+%.lp 
+\item[\ib{flush}]
+(default off, {\it Amiga NetHack \/} only).
+%.lp 
+\item[\ib{Macgraphics}]
+(default on, {\it Mac NetHack \/} only).
+%.lp 
+\item[\ib{page\_wait}]
+(default off, {\it Mac NetHack \/} only).
+%.lp
+\item[\ib{rawio}]
+Force raw (non-cbreak) mode for faster output and more
+bulletproof input (MS-DOS sometimes treats `{\tt \^{}P}' as a printer toggle
+without it) (default off, {\it OS/2, PC\/ {\rm and} ST NetHack\/} only).  
+Note:  DEC Rainbows hang if this is turned on.
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{soundcard}]
+(default off, {\it PC NetHack \/} only).
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{subkeyvalue}]
+({\it Win32 tty NetHack \/} only).
+May be used to alter the value of keystrokes that the operating system
+returns to NetHack to help compensate for international keyboard issues.
+OPTIONS=subkeyvalue:171/92
+will return 92 to NetHack, if 171 was originally going to be returned.
+You can use multiple subkeyvalue statements in the config file if needed.
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{video}]
+Set the video mode used ({\it PC\/ NetHack\/} only).
+Values are {\it autodetect\/}, {\it default\/}, or {\it vga\/}. 
+Setting {\it vga\/} (or {\it autodetect\/} with vga hardware present) will cause
+the game to display tiles. 
+Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{videocolors}]
+\begin{sloppypar}
+Set the color palette for PC systems using NO\_TERMS
+(default 4-2-6-1-5-3-15-12-10-14-9-13-11, {\it PC\/ NetHack\/} only).
+The order of colors is red, green, brown, blue, magenta, cyan,
+bright.white, bright.red, bright.green, yellow, bright.blue,
+bright.magenta, and bright.cyan.
+Cannot be set with the `{\tt O}' command.
+\end{sloppypar}
+%.lp
+\item[\ib{videoshades}]
+Set the intensity level of the three gray scales available
+(default dark normal light, {\it PC\/ NetHack\/} only).
+If the game display is difficult to read, try adjusting these scales;
+if this does not correct the problem, try {\tt !color}.
+Cannot be set with the `{\tt O}' command.
+\elist
+
+%.lp
+%.hn 2
+\subsection*{Configuring autopickup exceptions}
+
+%.pg
+There is an experimental compile time option called AUTOPICKUP_EXCEPTIONS.  
+If your copy of the game was built with that option defined, you can 
+further refine the behavior of the ``{\tt autopickup}'' option beyond 
+what is available through the ``{\tt pickup\_types}'' option.
+
+%.pg
+By placing ``{\tt autopickup\_exception}'' lines in your configuration
+file, you can define patterns to be checked when the game is about to
+autopickup something.
+
+\blist{}
+%.lp
+\item[\ib{autopickup\_exception}]
+Sets an exception to the `{\it pickup\_types}' option.
+The {\it autopickup\_exception\/} option should be followed by a string of 1--80
+characters to be used as a pattern to match against the singular form
+of the description of an object at your location.
+
+%.pg
+You may use the following special characters in a pattern:
+
+\begin{verbatim}
+    *--- matches 0 or more characters.
+    ?--- matches any single character.
+\end{verbatim}
+
+In addition, some characters are treated specially if they occur as the first 
+character in the specified string pattern, specifically:
+
+%.sd
+%.si
+{\tt <} --- always pickup an object that matches the pattern that follows.\\
+{\tt >} --- never pickup an object that matches the pattern that follows.
+%.ei
+%.ed
+
+Can be set with the `{\tt O}' command, but the setting is not preserved
+across saves and restores.
+\elist
+
+%.pg
+Here's a couple of examples of autopickup\_exceptions:
+\begin{verbatim}
+    autopickup_exception="<*arrow"
+    autopickup_exception=">*corpse"
+    autopickup_exception=">* cursed*"
+\end{verbatim}
+
+The first example above will result in autopickup of any type of arrow.
+The second example results in the exclusion of any corpse from autopickup.
+The last example results in the exclusion of items known to be cursed from autopickup.
+A `never pickup' rule takes precedence over an `always pickup' rule if both match.
+
+%.lp
+%.hn 2
+\subsection*{Configuring User Sounds}
+
+%.pg
+Some platforms allow you to define sound files to be played when a message 
+that matches a user-defined pattern is delivered to the message window.
+At this time the Qt port and the win32tty and win32gui ports support the
+use of user sounds.
+
+%.pg
+The following config file entries are relevant to mapping user sounds
+to messages:
+
+\blist{}
+%.lp
+\item[\ib{SOUNDDIR}]
+The directory that houses the sound files to be played.
+%.lp
+\item[\ib{SOUND}]
+An entry that maps a sound file to a user-specified message pattern.
+Each SOUND entry is broken down into the following parts:
+
+%.sd
+%.si
+{\tt MESG      } --- message window mapping (the only one supported in 3.4).\\
+{\tt pattern   } --- the pattern to match.\\
+{\tt sound file} --- the sound file to play.\\
+{\tt volume    } --- the volume to be set while playing the sound file.
+%.ei
+%.ed
+\elist
+
+%.pg
+The exact format for the pattern depends on whether the platform is
+built to use {\it regular expressions \/} or NetHack's own internal pattern 
+matching facility. The {\it regular expressions \/} matching can be much more 
+sophisticated than the internal NetHack pattern matching, but requires 
+3rd party libraries on some platforms.  There are plenty of references 
+available elsewhere for explaining {\it regular expressions \/}. You can verify 
+which pattern matching is used by your port with the 
+\#version command.  
+
+%.pg
+NetHack's internal pattern matching routine uses the following
+special characters in its pattern matching:
+
+\begin{verbatim}
+    *--- matches 0 or more characters.
+    ?--- matches any single character.
+\end{verbatim}
+
+%.pg
+Here's an example of a sound mapping using NetHack's internal
+pattern matching facility:
+\begin{verbatim}
+    SOUND=MESG "*chime of a cash register*" "gong.wav" 50
+\end{verbatim}
+specifies that any message with "chime of a cash register" contained
+in it will trigger the playing of "gong.wav".  You can have multiple
+SOUND entries in your config file.
+
+%.lp
+%.hn 2
+\subsection*{Configuring NetHack for Play by the Blind}
+
+%.pg
+NetHack can be set up to use only standard ASCII characters for making
+maps of the dungeons. This makes the MS-DOS versions of NetHack completely
+accessible to the blind who use speech and/or Braille access technologies.
+Players will require a good working knowledge of their screen-reader's
+review features, and will have to know how to navigate horizontally and
+vertically character by character. They will also find the search
+capabilities of their screen-readers to be quite valuable. Be certain to
+examine this Guidebook before playing so you have an idea what the screen
+layout is like. You'll also need to be able to locate the PC cursor. It is
+always where your character is located. Merely searching for an @-sign will
+not always find your character since there are other humanoids represented
+by the same sign. Your screen-reader should also have a function which
+gives you the row and column of your review cursor and the PC cursor.
+These co-ordinates are often useful in giving players a better sense of the
+overall location of items on the screen.
+%.pg
+While it is not difficult for experienced users to edit the {\it defaults.nh\/}
+file to accomplish this, novices may find this task somewhat daunting.
+Included in all official distributions of NetHack is a file called
+{\it NHAccess.nh\/}.  Replacing {\it defaults.nh\/} with this file will cause
+the game to run in a manner accessible to the blind. After you have gained
+some experience with the game and with editing files, you may want to alter
+settings to better suit your preferences. Instructions on how to do this
+are included in the {\it NHAccess.nh\/} file itself. The most crucial
+settings to make the game accessible are:
+%.pg
+\blist{}
+%.lp
+\item[\ib{IBMgraphics}]
+Disable IBMgraphics by commenting out this option.
+%.lp
+\item[\ib{menustyle:traditional}]
+This will assist in the interface to speech synthesizers.
+%.lp
+\item[\ib{number\_pad}]
+A lot of speech access programs use the number-pad to review the screen.
+If this is the case, disable the number\_pad option and use the traditional
+Rogue-like commands.
+%.lp
+\item[\ib{Character graphics}]
+Comment out all character graphics sets found near the bottom of the
+{\it defaults.nh\/} file.  Most of these replace {\it NetHack\/}'s
+default representation of the dungeon using standard ASCII characters
+with fancier characters from extended character sets, and these fancier
+characters can annoy screen-readers.
+\elist
+
+%.hn 1
+\section{Scoring}
+
+%.pg
+{\it NetHack\/} maintains a list of the top scores or scorers on your machine,
+depending on how it is set up.  In the latter case, each account on
+the machine can post only one non-winning score on this list.  If
+you score higher than someone else on this list, or better your
+previous score, you will be inserted in the proper place under your
+current name.  How many scores are kept can also be set up when
+{\it NetHack\/} is compiled.
+
+%.pg
+Your score is chiefly based upon how much experience you gained, how
+much loot you accumulated, how deep you explored, and how the game
+ended.  If you quit the game, you escape with all of your gold intact.
+If, however, you get killed in the Mazes of Menace, the guild will
+only hear about 90\,\% of your gold when your corpse is discovered
+(adventurers have been known to collect finder's fees).  So, consider
+whether you want to take one last hit at that monster and possibly
+live, or quit and stop with whatever you have.  If you quit, you keep
+all your gold, but if you swing and live, you might find more.
+
+%.pg
+If you just want to see what the current top players/games list is, you
+can type
+\begin{verbatim}
+    nethack -s all
+\end{verbatim}
+on most versions.
+
+%.hn 1
+\section{Explore mode}
+
+%.pg
+{\it NetHack\/} is an intricate and difficult game.  Novices might falter
+in fear, aware of their ignorance of the means to survive.  Well, fear
+not.  Your dungeon may come equipped with an ``explore'' or ``discovery''
+mode that enables you to keep old save files and cheat death, at the
+paltry cost of not getting on the high score list.
+
+%.pg
+There are two ways of enabling explore mode.  One is to start the game
+with the {\tt -X}
+switch.  The other is to issue the `{\tt X}' command while already playing
+the game.  The other benefits of explore mode are left for the trepid
+reader to discover.
+
+%.hn
+\section{Credits}
+%.pg
+The original %
+{\it hack\/} game was modeled on the Berkeley
+%.ux
+UNIX
+{\it rogue\/} game.  Large portions of this paper were shamelessly
+cribbed from %
+{\it A Guide to the Dungeons of Doom}, by Michael C. Toy
+and Kenneth C. R. C. Arnold.  Small portions were adapted from
+{\it Further Exploration of the Dungeons of Doom}, by Ken Arromdee.
+
+%.pg
+{\it NetHack\/} is the product of literally dozens of people's work.
+Main events in the course of the game development are described below:
+
+%.pg
+\bigskip
+\nd {\it Jay Fenlason\/} wrote the original {\it Hack\/} with help from {\it
+Kenny Woodland}, {\it Mike Thome}, and {\it Jon Payne}.
+
+%.pg
+\medskip
+\nd {\it Andries Brouwer\/} did a major re-write, transforming {\it Hack\/}
+into a very different game, and published (at least) three versions (1.0.1,
+1.0.2, and 1.0.3) for UNIX machines to the Usenet.
+
+%.pg
+\medskip
+\nd {\it Don G. Kneller\/} ported {\it Hack\/} 1.0.3 to Microsoft C and MS-DOS,
+producing {\it PC Hack\/} 1.01e, added support for DEC Rainbow graphics in
+version 1.03g, and went on to produce at least four more versions (3.0, 3.2,
+3.51, and 3.6).
+
+%.pg
+\medskip
+\nd {\it R. Black\/} ported {\it PC Hack\/} 3.51 to Lattice C and the Atari
+520/1040ST, producing {\it ST Hack\/} 1.03.
+
+%.pg
+\medskip
+\nd {\it Mike Stephenson\/} merged these various versions back together,
+incorporating many of the added features, and produced {\it NetHack\/} version
+1.4.  He then coordinated a cast of thousands in enhancing and debugging
+{\it NetHack\/} 1.4 and released {\it NetHack\/} versions 2.2 and 2.3.
+
+%.pg
+\medskip
+\nd Later, Mike coordinated a major rewrite of the game, heading a team which
+included {\it Ken Arromdee}, {\it Jean-Christophe Collet}, {\it Steve Creps},
+{\it Eric Hendrickson}, {\it Izchak Miller}, {\it Eric S. Raymond}, {\it John
+Rupley}, {\it Mike Threepoint}, and {\it Janet Walz}, to produce {\it
+NetHack\/} 3.0c.
+
+%.pg
+\medskip
+\nd {\it NetHack\/} 3.0 was ported to the Atari by {\it Eric R. Smith}, to OS/2 by
+{\it Timo Hakulinen}, and to VMS by {\it David Gentzel}.  The three of them
+and {\it Kevin Darcy\/} later joined the main development team to produce
+subsequent revisions of 3.0.
+
+%.pg
+\medskip
+\nd {\it Olaf Seibert\/} ported {\it NetHack\/} 2.3 and 3.0 to the Amiga.  {\it
+Norm Meluch}, {\it Stephen Spackman\/} and {\it Pierre Martineau\/} designed
+overlay code for {\it PC NetHack\/} 3.0.  {\it Johnny Lee\/} ported {\it
+NetHack\/} 3.0 to the Macintosh.  Along with various other Dungeoneers, they
+continued to enhance the PC, Macintosh, and Amiga ports through the later
+revisions of 3.0.
+
+%.pg
+\medskip
+\nd Headed by {\it Mike Stephenson\/} and coordinated by {\it Izchak Miller\/} and
+{\it Janet Walz}, the development team which now included {\it Ken Arromdee},
+{\it David Cohrs}, {\it Jean-Christophe Collet}, {\it Kevin Darcy},
+{\it Matt Day}, {\it Timo Hakulinen}, {\it Steve Linhart}, {\it Dean Luick},
+{\it Pat Rankin}, {\it Eric Raymond}, and {\it Eric Smith\/} undertook a radical
+revision of 3.0.  They re-structured the game's design, and re-wrote major
+parts of the code.  They added multiple dungeons, a new display, special
+individual character quests, a new endgame and many other new features, and
+produced {\it NetHack\/} 3.1.
+
+%.pg
+\medskip
+\nd {\it Ken Lorber}, {\it Gregg Wonderly\/} and {\it Greg Olson}, with help
+from {\it Richard Addison}, {\it Mike Passaretti}, and {\it Olaf Seibert},
+developed {\it NetHack\/} 3.1 for the Amiga.
+
+%.pg
+\medskip
+\nd {\it Norm Meluch\/} and {\it Kevin Smolkowski}, with help from
+{\it Carl Schelin}, {\it Stephen Spackman}, {\it Steve VanDevender},
+and {\it Paul Winner}, ported {\it NetHack\/} 3.1 to the PC.
+
+%.pg
+\medskip
+\nd {\it Jon W\{tte} and {\it Hao-yang Wang},
+with help from {\it Ross Brown}, {\it Mike Engber}, {\it David Hairston},
+{\it Michael Hamel}, {\it Jonathan Handler}, {\it Johnny Lee},
+{\it Tim Lennan}, {\it Rob Menke}, and {\it Andy Swanson},
+developed {\it NetHack\/} 3.1 for the Macintosh, porting it for MPW.
+Building on their development, {\it Barton House} added a Think C port.
+
+%.pg
+\medskip
+\nd {\it Timo Hakulinen\/} ported {\it NetHack\/} 3.1 to OS/2.
+{\it Eric Smith\/} ported {\it NetHack\/} 3.1 to the Atari.
+{\it Pat Rankin}, with help from {\it Joshua Delahunty},
+was responsible for the VMS version of {\it NetHack\/} 3.1.
+{\it Michael Allison} ported {\it NetHack\/} 3.1 to Windows NT.
+
+%.pg
+\medskip
+\nd {\it Dean Luick}, with help from {\it David Cohrs}, developed {\it NetHack\/}
+3.1 for X11.
+{\it Warwick Allison} wrote a tiled version of NetHack for the Atari;
+he later contributed the tiles to the DevTeam and tile support was
+then added to other platforms.
+
+%.pg
+\medskip
+\nd The 3.2 development team, comprised of {\it Michael Allison}, {\it Ken
+Arromdee}, {\it David Cohrs}, {\it Jessie Collet}, {\it Steve Creps}, {\it
+Kevin Darcy}, {\it Timo Hakulinen}, {\it Steve Linhart}, {\it Dean Luick},
+{\it Pat Rankin}, {\it Eric Smith}, {\it Mike Stephenson}, {\it Janet Walz},
+and {\it Paul Winner}, released version 3.2 in April of 1996.
+
+%.pg
+\medskip
+\nd Version 3.2 marked the tenth anniversary of the formation of the development
+team.  In a testament to their dedication to the game, all thirteen members
+of the original development team remained on the team at the start of work on
+that release.  During the interval between the release of 3.1.3 and 3.2,
+one of the founding members of the development team, {\it Dr. Izchak Miller},
+was diagnosed with cancer and passed away.  That release of the game was
+dedicated to him by the development and porting teams.
+
+%.pg
+\medskip
+During the lifespan of {\it NetHack\/} 3.1 and 3.2, several enthusiasts
+of the game added
+their own modifications to the game and made these ``variants'' publicly
+available:
+
+%.pg
+\medskip
+{\it Tom Proudfoot} and {\it Yuval Oren} created {\it NetHack++},
+which was quickly renamed {\it NetHack$--$}.
+Working independently, {\it Stephen White} wrote {\it NetHack Plus}.
+{\it Tom Proudfoot} later merged {\it NetHack Plus}
+and his own {\it NetHack$--$} to produce {\it SLASH}.
+{\it Larry Stewart-Zerba} and {\it Warwick Allison} improved the spell
+casting system with the Wizard Patch.
+{\it Warwick Allison} also ported NetHack to use the Qt interface.
+
+%.pg
+\medskip
+{\it Warren Cheung} combined {\it SLASH} with the Wizard Patch
+to produce {\it Slash'em\/}, and
+with the help of {\it Kevin Hugo}, added more features.
+Kevin later joined the
+DevTeam and incorporated the best of these ideas into NetHack 3.3.
+
+%.pg
+\medskip
+The final update to 3.2 was the bug fix release 3.2.3, which was released
+simultaneously with 3.3.0 in December 1999 just in time for the Year 2000.
+
+%.pg
+\medskip
+The 3.3 development team, consisting of {\it Michael Allison}, {\it Ken Arromdee}, 
+{\it David Cohrs}, {\it Jessie Collet}, {\it Steve Creps}, {\it Kevin Darcy}, 
+{\it Timo Hakulinen}, {\it Kevin Hugo}, {\it Steve Linhart}, {\it Ken Lorber}, 
+{\it Dean Luick}, {\it Pat Rankin}, {\it Eric Smith}, {\it Mike Stephenson}, 
+{\it Janet Walz}, and {\it Paul Winner}, released 3.3.0 in 
+December 1999 and 3.3.1 in August of 2000.
+
+%.pg
+\medskip
+Version 3.3 offered many firsts. It was the first version to separate race 
+and profession. The Elf class was removed in preference to an elf race, 
+and the races of dwarves, gnomes, and orcs made their first appearance in 
+the game alongside the familiar human race.  Monk and Ranger roles joined 
+Archeologists, Barbarians, Cavemen, Healers, Knights, Priests, Rogues, Samurai, 
+Tourists, Valkyries and of course, Wizards.  It was also the first version
+to allow you to ride a steed, and was the first version to have a publicly 
+available web-site listing all the bugs that had been discovered.  Despite 
+that constantly growing bug list, 3.3 proved stable enough to last for
+more than a year and a half.
+
+%.pg
+\medskip
+The 3.4 development team initially consisted of 
+{\it Michael Allison}, {\it Ken Arromdee},
+{\it David Cohrs}, {\it Jessie Collet}, {\it Kevin Hugo}, {\it Ken Lorber},
+{\it Dean Luick}, {\it Pat Rankin}, {\it Mike Stephenson}, 
+{\it Janet Walz}, and {\it Paul Winner}, with {\it  Warwick Allison} joining 
+just before the release of NetHack 3.4.0 in March 2002.
+
+%.pg
+\medskip
+As with version 3.3, various people contributed to the game as a whole as
+well as supporting ports on the different platforms that {\it NetHack\/}
+runs on:
+
+%.pg
+\medskip
+\nd{\it Pat Rankin} maintained 3.4 for VMS.
+
+%.pg
+\medskip
+\nd {\it Michael Allison} maintained NetHack 3.4 for the MS-DOS platform.
+{\it Paul Winner} and {\it Yitzhak Sapir} provided encouragement.
+
+%.pg
+\medskip
+\nd {\it Dean Luick}, {\it Mark Modrall}, and {\it Kevin Hugo} maintained and
+enhanced the Macintosh port of 3.4.
+
+%.pg
+\medskip
+\nd {\it Michael Allison}, {\it David Cohrs}, {\it Alex Kompel}, {\it Dion Nicolaas}, and 
+{\it Yitzhak Sapir} maintained and enhanced 3.4 for the Microsoft Windows platform.
+{\it Alex Kompel} contributed a new graphical interface for the Windows port. 
+{\it Alex Kompel} also contributed a Windows CE port for 3.4.1.
+
+%.pg
+\medskip
+\nd {\it Ron Van Iwaarden} maintained 3.4 for OS/2.
+
+%.pg
+\medskip
+\nd {\it Janne Salmij\"{a}rvi} and {\it Teemu Suikki} maintained
+and enhanced the Amiga port of 3.4 after {\it Janne Salmij\"{a}rvi} resurrected
+it for 3.3.1.
+
+%.pg
+\medskip
+\nd {\it Christian ``Marvin'' Bressler} maintained 3.4 for the Atari after he
+resurrected it for 3.3.1.
+
+%.pg
+\medskip
+\nd There is a NetHack web site maintained by {\it Ken Lorber} at 
+http:{\tt /}{\tt /}www.nethack.org{\tt /}.
+
+%.pg
+\bigskip
+\nd From time to time, some depraved individual out there in netland sends a
+particularly intriguing modification to help out with the game.  The Gods of
+the Dungeon sometimes make note of the names of the worst of these miscreants
+in this, the list of Dungeoneers:
+
+%.sd
+\begin{center}
+\begin{tabular}{lll}
+%TABLE_START
+Adam Aronow & Izchak Miller & Mike Stephenson\\
+Alex Kompel & J. Ali Harlow & Norm Meluch\\
+Andreas Dorn & Janet Walz & Olaf Seibert\\
+Andy Church & Janne Salmij\"{a}rvi & Pasi Kallinen\\
+Andy Swanson & Jean-Christophe Collet & Pat Rankin\\
+Ari Huttunen & Jochen Erwied & Paul Winner\\
+Barton House & John Kallen & Pierre Martineau\\
+Benson I. Margulies & John Rupley & Ralf Brown\\
+Bill Dyer & John S. Bien & Ray Chason\\
+Boudewijn Waijers & Johnny Lee & Richard Addison\\
+Bruce Cox & Jon W\{tte & Richard Beigel\\
+Bruce Holloway & Jonathan Handler & Richard P. Hughey\\
+Bruce Mewborne & Joshua Delahunty & Rob Menke\\
+Carl Schelin & Keizo Yamamoto & Robin Johnson\\
+Chris Russo & Ken Arnold & Roderick Schertler\\
+David Cohrs & Ken Arromdee & Roland McGrath\\
+David Damerell & Ken Lorber & Ron Van Iwaarden\\
+David Gentzel & Ken Washikita & Ronnen Miller\\
+David Hairston & Kevin Darcy & Ross Brown\\
+Dean Luick & Kevin Hugo & Sascha Wostmann\\
+Del Lamb & Kevin Sitze & Scott Bigham\\
+Deron Meranda & Kevin Smolkowski & Scott R. Turner\\
+Dion Nicolaas & Kevin Sweet & Stephen Spackman\\
+Dylan O'Donnell & Lars Huttar & Stephen White\\
+Eric Backus & Malcolm Ryan & Steve Creps\\
+Eric Hendrickson & Mark Gooderum & Steve Linhart\\
+Eric R. Smith & Mark Modrall & Steve VanDevender\\
+Eric S. Raymond & Marvin Bressler & Teemu Suikki\\
+Erik Andersen & Matthew Day & Tim Lennan\\
+Frederick Roeber & Merlyn LeRoy & Timo Hakulinen\\
+Gil Neiger & Michael Allison & Tom Almy\\
+Greg Laskin & Michael Feir & Tom West\\
+Greg Olson & Michael Hamel & Warren Cheung\\
+Gregg Wonderly & Michael Sokolov & Warwick Allison\\
+Hao-yang Wang & Mike Engber & Yitzhak Sapir\\
+Helge Hafting & Mike Gallop\\
+Irina Rempt-Drijfhout & Mike Passaretti
+%TABLE_END  Do not delete this line.
+\end{tabular}
+\end{center}
+%.ed
+
+%\vfill
+%\begin{flushleft}
+%\small
+%Microsoft and MS-DOS are registered trademarks of Microsoft Corporation.\\
+%%%Don't need next line if a UNIX macro automatically inserts footnotes.
+%UNIX is a registered trademark of AT\&T.\\
+%Lattice is a trademark of Lattice, Inc.\\
+%Atari and 1040ST are trademarks of Atari, Inc.\\
+%AMIGA is a trademark of Commodore-Amiga, Inc.\\
+%%.sm
+%Brand and product names are trademarks or registered trademarks
+%of their respective holders.
+%\end{flushleft}
+
+\end{document}
diff --git a/doc/Guidebook.txt b/doc/Guidebook.txt
new file mode 100644 (file)
index 0000000..f0f9f7d
--- /dev/null
@@ -0,0 +1,3630 @@
+
+
+
+
+
+
+
+
+
+
+                           A Guide to the Mazes of Menace
+                               (Guidebook for NetHack)
+
+
+                                   Eric S. Raymond
+                      (Extensively edited and expanded for 3.4)
+
+
+
+          1.  Introduction
+
+          Recently, you have begun to find yourself unfulfilled and distant
+          in your daily occupation.  Strange dreams of prospecting,  steal-
+          ing,  crusading,  and  combat  have haunted you in your sleep for
+          many months, but you aren't  sure  of  the  reason.   You  wonder
+          whether  you have in fact been having those dreams all your life,
+          and somehow managed to forget about them until now.  Some  nights
+          you awaken suddenly and cry out, terrified at the vivid recollec-
+          tion of the strange and powerful creatures that seem to be  lurk-
+          ing  behind  every  corner  of  the dungeon in your dream.  Could
+          these details haunting your dreams be real?  As each night  pass-
+          es,  you feel the desire to enter the mysterious caverns near the
+          ruins grow stronger.  Each morning, however, you quickly put  the
+          idea  out  of  your head as you recall the tales of those who en-
+          tered the caverns before you and did not return.  Eventually  you
+          can  resist  the yearning to seek out the fantastic place in your
+          dreams no longer.  After all, when other  adventurers  came  back
+          this  way after spending time in the caverns, they usually seemed
+          better off than when they passed through the first time.  And who
+          was to say that all of those who did not return had not just kept
+          going?
+
+
+               Asking around, you hear about a bauble, called the Amulet of
+          Yendor  by  some, which, if you can find it, will bring you great
+          wealth.  One legend you were told even mentioned that the one who
+          finds  the  amulet  will be granted immortality by the gods.  The
+          amulet is rumored to be somewhere beyond the Valley of  Gehennom,
+          deep  within  the Mazes of Menace.  Upon hearing the legends, you
+          immediately realize that there is some profound and  undiscovered
+          reason that you are to descend into the caverns and seek out that
+          amulet of which they spoke.  Even if the rumors of  the  amulet's
+          powers are untrue, you decide that you should at least be able to
+          sell the tales of your adventures to the local  minstrels  for  a
+          tidy  sum,  especially if you encounter any of the terrifying and
+          magical creatures of your dreams along the way.   You  spend  one
+          last  night  fortifying  yourself at the local inn, becoming more
+          and more depressed as you watch the odds of  your  success  being
+          posted on the inn's walls getting lower and lower.
+
+
+
+          NetHack Guidebook                                               1
+
+
+
+
+
+          NetHack Guidebook                                               2
+
+
+
+                 In the morning you awake, collect your belongings, and set
+          off for the dungeon.  After several days  of  uneventful  travel,
+          you  see the ancient ruins that mark the entrance to the Mazes of
+          Menace.  It is late at night, so you make camp  at  the  entrance
+          and  spend the night sleeping under the open skies.  In the morn-
+          ing, you gather your gear, eat what may be your  last  meal  out-
+          side, and enter the dungeon...
+
+
+          2.  What is going on here?
+
+               You have just begun a game of NetHack.  Your goal is to grab
+          as much treasure as you can, retrieve the Amulet of  Yendor,  and
+          escape the Mazes of Menace alive.
+
+               Your abilities and strengths for dealing with the hazards of
+          adventure will vary with your background and training:
+
+               Archeologists understand dungeons pretty well; this  enables
+          them  to  move  quickly  and sneak up on the local nasties.  They
+          start equipped with the tools for a proper scientific expedition.
+
+               Barbarians  are  warriors out of the hinterland, hardened to
+          battle.   They  begin  their  quests  with  naught  but  uncommon
+          strength, a trusty hauberk, and a great two-handed sword.
+
+               Cavemen  and  Cavewomen start with exceptional strength but,
+          unfortunately, with neolithic weapons.
+
+               Healers are wise in medicine and apothecary.  They know  the
+          herbs  and  simples  that  can restore vitality, ease pain, anes-
+          thetize, and neutralize poisons; and with their instruments, they
+          can  divine a being's state of health or sickness.  Their medical
+          practice earns them quite reasonable amounts of money, with which
+          they enter the dungeon.
+
+               Knights  are  distinguished  from  the  common skirmisher by
+          their devotion to the ideals of chivalry and  by  the  surpassing
+          excellence of their armor.
+
+               Monks are ascetics, who by rigorous practice of physical and
+          mental disciplines have become capable of fighting as effectively
+          without  weapons  as with.  They wear no armor but make up for it
+          with increased mobility.
+
+               Priests and Priestesses are clerics militant, crusaders  ad-
+          vancing  the  cause  of  righteousness with arms, armor, and arts
+          thaumaturgic.  Their ability to commune with deities  via  prayer
+          occasionally extricates them from peril, but can also put them in
+          it.
+
+               Rangers are most at home in the woods, and some say slightly
+          out of place in a dungeon.  They are, however, experts in archery
+          as well as tracking and stealthy movement.
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                               3
+
+
+
+               Rogues are agile and stealthy  thieves,  with  knowledge  of
+          locks,  traps,  and  poisons.   Their advantage lies in surprise,
+          which they employ to great advantage.
+
+               Samurai are the elite warriors of feudal Nippon.   They  are
+          lightly  armored  and  quick, and wear the dai-sho, two swords of
+          the deadliest keenness.
+
+               Tourists start out with lots of gold (suitable for  shopping
+          with),  a  credit card, lots of food, some maps, and an expensive
+          camera.  Most monsters don't like being photographed.
+
+               Valkyries are hardy warrior women.  Their upbringing in  the
+          harsh  Northlands  makes  them strong, inures them to extremes of
+          cold, and instills in them stealth and cunning.
+
+               Wizards start out with a knowledge of magic, a selection  of
+          magical  items,  and a particular affinity for dweomercraft.  Al-
+          though seemingly weak and easy to overcome at first sight, an ex-
+          perienced Wizard is a deadly foe.
+
+               You may also choose the race of your character:
+
+               Dwarves are smaller than humans or elves, but are stocky and
+          solid individuals.  Dwarves' most notable trait  is  their  great
+          expertise  in mining and metalwork.  Dwarvish armor is said to be
+          second in quality not even to the mithril armor of the Elves.
+
+               Elves are agile, quick, and perceptive; very little of  what
+          goes  on  will escape an Elf.  The quality of Elven craftsmanship
+          often gives them an advantage in arms and armor.
+
+               Gnomes are smaller than but generally  similar  to  dwarves.
+          Gnomes  are known to be expert miners, and it is known that a se-
+          cret underground mine complex built by this  race  exists  within
+          the Mazes of Menace, filled with both riches and danger.
+
+               Humans are by far the most common race of the surface world,
+          and are thus the norm by which other races  are  often  compared.
+          Although  they have no special abilities, they can succeed in any
+          role.
+
+               Orcs are a cruel and barbaric race that  hate  every  living
+          thing  (including other orcs).  Above all others, Orcs hate Elves
+          with a passion unequalled, and will go out of their way  to  kill
+          one  at  any opportunity.  The armor and weapons fashioned by the
+          Orcs are typically of inferior quality.
+
+          3.  What do all those things on the screen mean?
+
+               On the screen is kept a map of where you have been and  what
+          you  have  seen on the current dungeon level; as you explore more
+          of the level, it appears on the screen in front of you.
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                               4
+
+
+
+               When NetHack's ancestor rogue  first  appeared,  its  screen
+          orientation  was  almost  unique  among  computer  fantasy games.
+          Since then, screen orientation has become the  norm  rather  than
+          the  exception;  NetHack  continues  this fine tradition.  Unlike
+          text adventure games that accept commands in pseudo-English  sen-
+          tences and explain the results in words, NetHack commands are all
+          one or two keystrokes and the results are  displayed  graphically
+          on  the  screen.  A minimum screen size of 24 lines by 80 columns
+          is recommended; if the screen is larger,  only  a  21x80  section
+          will be used for the map.
+
+               NetHack can even be played by blind players, with the assis-
+          tance of Braille readers or  speech  synthesisers.   Instructions
+          for  configuring NetHack for the blind are included later in this
+          document.
+
+               NetHack generates a new dungeon every time you play it; even
+          the  authors  still find it an entertaining and exciting game de-
+          spite having won several times.
+
+               NetHack offers a variety of display  options.   The  options
+          available  to  you  will vary from port to port, depending on the
+          capabilities of your hardware and software, and  whether  various
+          compile-time options were enabled when your executable was creat-
+          ed.  The three possible display options are: a monochrome charac-
+          ter  interface,  a color character interface, and a graphical in-
+          terface using small pictures called tiles.  The two character in-
+          terfaces allow fonts with other characters to be substituted, but
+          the default assignments use standard ASCII characters  to  repre-
+          sent everything.  There is no difference between the various dis-
+          play options with respect to game play.  Because we cannot repro-
+          duce the tiles or colors in the Guidebook, and because it is com-
+          mon to all ports, we will use the default ASCII  characters  from
+          the  monochrome  character  display  when referring to things you
+          might see on the screen during your game.
+
+               In order to understand what is going on  in  NetHack,  first
+          you  must  understand what NetHack is doing with the screen.  The
+          NetHack screen replaces the ``You see ...'' descriptions of  text
+          adventure  games.   Figure 1 is a sample of what a NetHack screen
+          might look like.  The way the screen looks  for  you  depends  on
+          your platform.
+
+          --------------------------------------------------------------------
+           The bat bites!
+
+               ------
+               |....|    ----------
+               |.<..|####...@...$.|
+               |....-#   |...B....+
+               |....|    |.d......|
+               ------    -------|--
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                               5
+
+
+
+
+
+           Player the Rambler     St:12 Dx:7 Co:18 In:11 Wi:9 Ch:15  Neutral
+           Dlvl:1 $:0  HP:9(12) Pw:3(3) AC:10 Exp:1/19 T:257 Weak
+
+          --------------------------------------------------------------------
+                                      Figure 1
+
+
+          3.1.  The status lines (bottom)
+
+               The  bottom  two lines of the screen contain several cryptic
+          pieces of information describing your current status.  If  either
+          status  line  becomes  longer  than  the width of the screen, you
+          might not see all of it.  Here are explanations of what the vari-
+          ous status items mean (though your configuration may not have all
+          the status items listed below):
+
+          Rank
+               Your character's name and professional ranking (based on the
+               experience level, see below).
+
+          Strength
+               A  measure of your character's strength; one of your six ba-
+               sic attributes.  A human character's  attributes  can  range
+               from  3  to 18 inclusive; non-humans may exceed these limits
+               (occasionally you may get super-strengths of the form 18/xx,
+               and  magic  can  also  cause attributes to exceed the normal
+               limits).  The higher your strength, the  stronger  you  are.
+               Strength  affects  how  successfully  you  perform  physical
+               tasks, how much damage you do in combat, and how  much  loot
+               you can carry.
+
+          Dexterity
+               Dexterity  affects  your  chances to hit in combat, to avoid
+               traps, and do other tasks requiring agility or  manipulation
+               of objects.
+
+          Constitution
+               Constitution  affects  your ability to recover from injuries
+               and other strains on your stamina.
+
+          Intelligence
+               Intelligence affects your ability to cast  spells  and  read
+               spellbooks.
+
+          Wisdom
+               Wisdom comes from your practical experience (especially when
+               dealing with magic).  It affects your magical energy.
+
+          Charisma
+               Charisma affects how certain creatures react toward you.  In
+               particular,  it can affect the prices shopkeepers offer you.
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                               6
+
+
+
+          Alignment
+               Lawful, Neutral, or Chaotic.  Often, Lawful is taken as good
+               and Chaotic as evil, but legal and ethical do not always co-
+               incide.  Your alignment influences how other monsters  react
+               toward you.  Monsters of a like alignment are more likely to
+               be non-aggressive, while those of an opposing alignment  are
+               more likely to be seriously offended at your presence.
+
+          Dungeon Level
+               How deep you are in the dungeon.  You start at level one and
+               the number increases as you  go  deeper  into  the  dungeon.
+               Some  levels  are  special, and are identified by a name and
+               not a number.  The Amulet of Yendor is reputed to  be  some-
+               where beneath the twentieth level.
+
+          Gold
+               The  number  of  gold  pieces you are openly carrying.  Gold
+               which you have concealed in containers is not counted.
+
+          Hit Points
+               Your current and maximum hit points.   Hit  points  indicate
+               how  much  damage you can take before you die.  The more you
+               get hit in a fight, the lower they get.  You can regain  hit
+               points  by  resting,  or  by  using certain magical items or
+               spells.  The number in parentheses  is  the  maximum  number
+               your hit points can reach.
+
+          Power
+               Spell  points.  This tells you how much mystic energy (mana)
+               you have available for spell casting.  Again,  resting  will
+               regenerate the amount available.
+
+          Armor Class
+               A measure of how effectively your armor stops blows from un-
+               friendly creatures.  The lower this number is, the more  ef-
+               fective the armor; it is quite possible to have negative ar-
+               mor class.
+
+          Experience
+               Your current experience level and experience points.  As you
+               adventure,  you  gain experience points.  At certain experi-
+               ence point totals, you gain an experience level.   The  more
+               experienced you are, the better you fight and withstand mag-
+               ical attacks.  Many dungeons show only your experience level
+               here.
+
+          Time
+               The  number  of  turns elapsed so far, displayed if you have
+               the time option set.
+
+          Hunger status
+               Your current hunger status, ranging from  Satiated  down  to
+               Fainting.   If  your hunger status is normal, it is not dis-
+               played.
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                               7
+
+
+
+               Additional status flags may appear after the hunger  status:
+          Conf  when you're confused, FoodPois or Ill when sick, Blind when
+          you can't see, Stun when stunned, and Hallu when hallucinating.
+
+          3.2.  The message line (top)
+
+               The top line of the screen is reserved for messages that de-
+          scribe  things that are impossible to represent visually.  If you
+          see a ``--More--'' on the top line, this means that  NetHack  has
+          another  message  to  display on the screen, but it wants to make
+          certain that you've read the one that is there  first.   To  read
+          the next message, just press the space bar.
+
+          3.3.  The map (rest of the screen)
+
+               The  rest  of the screen is the map of the level as you have
+          explored it so far.  Each symbol on the screen  represents  some-
+          thing.   You  can  set various graphics options to change some of
+          the symbols the game uses; otherwise, the game will  use  default
+          symbols.  Here is a list of what the default symbols mean:
+
+          - and |
+               The walls of a room, or an open door.  Or a grave (|).
+
+          .    The floor of a room, ice, or a doorless doorway.
+
+          #    A  corridor,  or iron bars, or a tree, or possibly a kitchen
+               sink (if your dungeon has sinks), or a drawbridge.
+
+          >    Stairs down: a way to the next level.
+
+          <    Stairs up: a way to the previous level.
+
+          +    A closed door, or a spellbook containing a spell you may  be
+               able to learn.
+
+          @    Your character or a human.
+
+          $    A pile of gold.
+
+          ^    A trap (once you have detected it).
+
+          )    A weapon.
+
+          [    A suit or piece of armor.
+
+          %    Something edible (not necessarily healthy).
+
+          ?    A scroll.
+
+          /    A wand.
+
+          =    A ring.
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                               8
+
+
+
+          !    A potion.
+
+          (    A useful item (pick-axe, key, lamp...).
+
+          "    An amulet or a spider web.
+
+          *    A gem or rock (possibly valuable, possibly worthless).
+
+          `    A boulder or statue.
+
+          0    An iron ball.
+
+          _    An altar, or an iron chain.
+
+          {    A fountain.
+
+          }    A pool of water or moat or a pool of lava.
+
+          \    An opulent throne.
+
+          a-zA-Z and other symbols
+               Letters  and certain other symbols represent the various in-
+               habitants of the Mazes of Menace.  Watch out,  they  can  be
+               nasty and vicious.  Sometimes, however, they can be helpful.
+
+          I    This marks the last known location of an invisible or other-
+               wise  unseen  monster.   Note  that  the  monster could have
+               moved.  The 'F' and 'm' commands may be useful here.
+
+               You need not memorize all these symbols;  you  can  ask  the
+          game  what  any  symbol  represents with the `/' command (see the
+          next section for more info).
+
+
+          4.  Commands
+
+               Commands are initiated by  typing  one  or  two  characters.
+          Some  commands, like ``search'', do not require that any more in-
+          formation be collected by NetHack.  Other commands might  require
+          additional  information, for example a direction, or an object to
+          be used.  For those commands that require additional information,
+          NetHack  will present you with either a menu of choices or with a
+          command line prompt requesting information.  Which you  are  pre-
+          sented with will depend chiefly on how you have set the menustyle
+          option.
+
+               For example, a common question, in the form  ``What  do  you
+          want  to use? [a-zA-Z ?*]'', asks you to choose an object you are
+          carrying.  Here, ``a-zA-Z'' are the  inventory  letters  of  your
+          possible  choices.   Typing  `?'  gives  you an inventory list of
+          these items, so you can see what each letter refers to.  In  this
+          example,  there  is  also a `*' indicating that you may choose an
+          object not on the list, if you wanted to use something  unexpect-
+          ed.  Typing a `*' lists your entire inventory, so you can see the
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                               9
+
+
+
+          inventory letters of every object you're carrying.   Finally,  if
+          you change your mind and decide you don't want to do this command
+          after all, you can press the ESC key to abort the command.
+
+               You can put a number before some  commands  to  repeat  them
+          that  many times; for example, ``10s'' will search ten times.  If
+          you have the number_pad option set, you must type `n' to prefix a
+          count,  so  the  example  above  would be typed ``n10s'' instead.
+          Commands for which counts make no sense ignore  them.   In  addi-
+          tion,  movement commands can be prefixed for greater control (see
+          below).  To cancel a count or a prefix, press the ESC key.
+
+               The list of commands is rather long, but it can be  read  at
+          any  time during the game through the `?' command, which accesses
+          a menu of helpful texts.  Here are the commands for  your  refer-
+          ence:
+
+          ?    Help menu:  display one of several help texts available.
+
+          /    Tell  what a symbol represents.  You may choose to specify a
+               location or type a symbol (or even a whole word) to explain.
+               Specifying a location is done by moving the cursor to a par-
+               ticular spot on the map and then pressing one of  `.',  `,',
+               `;',  or `:'.  `.' will explain the symbol at the chosen lo-
+               cation, conditionally check for ``More info?'' depending up-
+               on whether the help option is on, and then you will be asked
+               to pick another location; `,' will explain  the  symbol  but
+               skip  any  additional  information; `;' will skip additional
+               info and also not bother asking you to choose another  loca-
+               tion  to  examine;  `:'  will  show additional info, if any,
+               without asking for confirmation.  When picking  a  location,
+               pressing  the ESC key will terminate this command, or press-
+               ing `?'  will give a brief reminder about how it works.
+
+               Specifying a name rather than a location  always  gives  any
+          additional information available about that name.
+
+          &    Tell what a command does.
+
+          <    Go  up  to  the previous level (if you are on a staircase or
+               ladder).
+
+          >    Go down to the next level (if you are on a staircase or lad-
+               der).
+
+          [yuhjklbn]
+               Go  one  step in the direction indicated (see Figure 2).  If
+               you sense or remember a monster there, you  will  fight  the
+               monster  instead.   Only  these  one-step  movement commands
+               cause  you  to  fight  monsters;  the  others  (below)   are
+               ``safe.''
+
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              10
+
+
+
+                                    y  k  u          7  8  9
+                                     \ | /            \ | /
+                                    h- . -l          4- . -6
+                                     / | \            / | \
+                                    b  j  n          1  2  3
+                                              (if number_pad is set)
+
+                                         Figure 2
+
+
+          [YUHJKLBN]
+               Go  in that direction until you hit a wall or run into some-
+               thing.
+
+          m[yuhjklbn]
+               Prefix:  move without picking up objects or  fighting  (even
+               if you remember a monster there)
+
+          F[yuhjklbn]
+               Prefix:   fight  a  monster  (even  if you only guess one is
+               there)
+
+          M[yuhjklbn]
+               Prefix:  move far, no pickup.
+
+          g[yuhjklbn]
+               Prefix:  move until something interesting is found.
+
+          G[yuhjklbn] or <CONTROL->[yuhjklbn]
+               Prefix:  same as `g', but forking of corridors is  not  con-
+               sidered interesting.
+
+          _    Travel to a map location via a shortest-path algorithm.  The
+               shortest path is computed over map locations the hero  knows
+               about  (e.g.  seen or previously traversed).  If there is no
+               known path, a guess is made instead.  Stops on most  of  the
+               same  conditions  as the `G' command, but without picking up
+               objects, similar to the `M' command.  For ports  with  mouse
+               support,  the  command  is  also  invoked when a mouse-click
+               takes place on a location other than the current position.
+
+          .    Rest, do nothing for one turn.
+
+          a    Apply (use) a tool (pick-axe, key, lamp...).
+
+          A    Remove one or more worn items, such as armor.  Use `T' (take
+               off)  to take off only one piece of armor or `R' (remove) to
+               take off only one accessory.
+
+          ^A   Redo the previous command.
+
+          c    Close a door.
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              11
+
+
+
+          C    Call (name) an individual monster.
+
+          ^C   Panic button.  Quit the game.
+
+          d    Drop something.  Ex. ``d7a'' means drop seven items  of  ob-
+               ject a.
+
+          D    Drop several things.  In answer to the question ``What kinds
+               of things do you want to drop? [!%= BUCXaium]''  you  should
+               type  zero  or  more object symbols possibly followed by `a'
+               and/or `i' and/or `u' and/or `m'.  In addition, one or  more
+               of the blessed/uncursed/cursed groups may be typed.
+
+                    DB  - drop all objects known to be blessed.
+                    DU  - drop all objects known to be uncursed.
+                    DC  - drop all objects known to be cursed.
+                    DX  - drop all objects of unknown B/U/C status.
+                    Da  - drop all objects, without asking for confirmation.
+                    Di  - examine your inventory before dropping anything.
+                    Du  - drop only unpaid objects (when in a shop).
+                    Dm  - use a menu to pick which object(s) to drop.
+                    D%u - drop only unpaid food.
+
+          ^D   Kick something (usually a door).
+
+          e    Eat food.
+
+          E    Engrave   a  message  on  the  floor.   Engraving  the  word
+               ``Elbereth'' will cause most  monsters  to  not  attack  you
+               hand-to-hand  (but if you attack, you will rub it out); this
+               is often useful to give yourself a breather.  (This  feature
+               may  be  compiled out of the game, so your version might not
+               have it.)
+
+                    E- - write in the dust with your fingers.
+
+          f    Fire one of the objects placed in your quiver.  You may  se-
+               lect ammunition with a previous `Q' command, or let the com-
+               puter pick something appropriate if autoquiver is true.
+
+          i    List your inventory (everything you're carrying).
+
+          I    List selected parts of your inventory.
+
+                    I* - list all gems in inventory;
+                    Iu - list all unpaid items;
+                    Ix - list all used up items that are on your shopping bill;
+                    I$ - count your money.
+
+          o    Open a door.
+
+          O    Set options.  A menu showing the current option values  will
+               be  displayed.  You can change most values simply by select-
+               ing the menu entry for the given option (ie, by  typing  its
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              12
+
+
+
+               letter  or  clicking  upon it, depending on your user inter-
+               face).  For the  non-boolean  choices,  a  further  menu  or
+               prompt will appear once you've closed this menu.  The avail-
+               able options are listed later in  this  Guidebook.   Options
+               are  usually  set  before  the game rather than with the `O'
+               command; see the section on options below.
+
+          p    Pay your shopping bill.
+
+          P    Put on a ring or other accessory (amulet, blindfold).
+
+          ^P   Repeat previous message.   Subsequent  ^P's  repeat  earlier
+               messages.  The behavior can be varied via the msg_window op-
+               tion.
+
+          q    Quaff (drink) something (potion, water, etc).
+
+          Q    Select an object for your quiver.  You can then  throw  this
+               using  the  `f' command.  (In versions prior to 3.3 this was
+               the command to quit the game, which has now  been  moved  to
+               `#quit'.)
+
+          r    Read a scroll or spellbook.
+
+          R    Remove an accessory (ring, amulet, etc).
+
+          ^R   Redraw the screen.
+
+          s    Search  for  secret  doors and traps around you.  It usually
+               takes several tries to find something.
+
+          S    Save (and suspend) the game.  The game will be restored  au-
+               tomatically the next time you play.
+
+          t    Throw an object or shoot a projectile.
+
+          T    Take off armor.
+
+          ^T   Teleport, if you have the ability.
+
+          v    Display version number.
+
+          V    Display the game history.
+
+          w    Wield weapon.
+
+                    w- - wield nothing, use your bare hands.
+
+          W    Wear armor.
+
+          x    Exchange your wielded weapon with the item in your alternate
+               weapon slot.  The latter is used as  your  secondary  weapon
+               when  engaging  in  two-weapon  combat.  Note that if one of
+               these slots is empty, the exchange still takes place.
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              13
+
+
+
+          X    Enter explore (discovery) mode, explained in its own section
+               later.
+
+          ^X   Display your name, role, race, gender, and alignment as well
+               as the various deities in your game.
+
+          z    Zap a wand.  To aim at yourself, use `.' for the  direction.
+
+          Z    Zap  (cast)  a  spell.  To cast at yourself, use `.' for the
+               direction.
+
+          ^Z   Suspend the game (UNIX(R) versions with job control only).
+
+          :    Look at what is here.
+
+          ;    Show what type of thing a visible symbol corresponds to.
+
+          ,    Pick up some things. May be preceded by `m' to force  a  se-
+               lection menu.
+
+          @    Toggle the autopickup option on and off.
+
+          ^    Ask for the type of a trap you found earlier.
+
+          )    Tell what weapon you are wielding.
+
+          [    Tell what armor you are wearing.
+
+          =    Tell what rings you are wearing.
+
+          "    Tell what amulet you are wearing.
+
+          (    Tell what tools you are using.
+
+          *    Tell  what  equipment  you are using; combines the preceding
+               five type-specific commands into one.
+
+          $    Count your gold pieces.
+
+          +    List the spells you know.  Using this command, you can  also
+               rearrange  the  order in which your spells are listed.  They
+               are shown via a menu, and if you  select  a  spell  in  that
+               menu, you'll be re-prompted for another spell to swap places
+               with it, and then  have  opportunity  to  make  further  ex-
+               changes.
+
+          \    Show what types of objects have been discovered.
+
+          !    Escape to a shell.
+
+
+
+          __________
+          (R)UNIX is a registered trademark of AT&T.
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              14
+
+
+
+          #    Perform an extended command.  As you can see, the authors of
+               NetHack used up all the letters, so this is a way to  intro-
+               duce  the less frequently used commands.  What extended com-
+               mands are available depends on what features  the  game  was
+               compiled with.
+
+          #adjust
+               Adjust inventory letters (most useful when the fixinv option
+               is ``on'').
+
+          #chat
+               Talk to someone.
+
+          #conduct
+               List which challenges you have adhered to.  See the  section
+               below entitled ``Conduct'' for details.
+
+          #dip Dip an object into something.
+
+          #enhance
+               Advance or check weapons and spell skills.
+
+          #force
+               Force a lock.
+
+          #invoke
+               Invoke an object's special powers.
+
+          #jump
+               Jump to another location.
+
+          #loot
+               Loot  a  box  or bag on the floor beneath you, or the saddle
+               from a horse standing next to you.
+
+          #monster
+               Use a monster's special ability (when polymorphed into  mon-
+               ster form).
+
+          #name
+               Name an item or type of object.
+
+          #offer
+               Offer a sacrifice to the gods.
+
+          #pray
+               Pray to the gods for help.
+
+          #quit
+               Quit the program without saving your game.
+
+          #ride
+               Ride (or stop riding) a monster.
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              15
+
+
+
+          #rub Rub a lamp or a stone.
+
+          #sit Sit down.
+
+          #turn
+               Turn undead.
+
+          #twoweapon
+               Toggle  two-weapon combat on or off.  Note that you must use
+               suitable weapons for this type of combat, or it will be  au-
+               tomatically turned off.
+
+          #untrap
+               Untrap something (trap, door, or chest).
+
+          #version
+               Print compile time options for this version of NetHack.
+
+          #wipe
+               Wipe off your face.
+
+          #?   Help menu:  get the list of available extended commands.
+
+               If your keyboard has a meta key (which, when pressed in com-
+          bination with another key, modifies  it  by  setting  the  `meta'
+          [8th,  or  `high'] bit), you can invoke many extended commands by
+          meta-ing the first letter of the command.  In NT,  OS/2,  and  PC
+          NetHack, the `Alt' key can be used in this fashion.
+
+          M-?  #? (not supported by all platforms)
+
+          M-2  #twoweapon (unless the number_pad option is enabled)
+
+          M-a  #adjust
+
+          M-c  #chat
+
+          M-d  #dip
+
+          M-e  #enhance
+
+          M-f  #force
+
+          M-i  #invoke
+
+          M-j  #jump
+
+          M-l  #loot
+
+          M-m  #monster
+
+          M-n  #name
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              16
+
+
+
+          M-o  #offer
+
+          M-p  #pray
+
+          M-q  #quit
+
+          M-r  #rub
+
+          M-s  #sit
+
+          M-t  #turn
+
+          M-u  #untrap
+
+          M-v  #version
+
+          M-w  #wipe
+
+               If  the number_pad option is on, some additional letter com-
+          mands are available:
+
+          h    Help menu:  display one of  several  help  texts  available,
+               like ``?''.
+
+          j    Jump to another location.  Same as ``#jump'' or ``M-j''.
+
+          k    Kick something (usually a door).  Same as `^D'.
+
+          l    Loot  a  box  or bag on the floor beneath you, or the saddle
+               from a horse standing next to you.   Same  as  ``#loot''  or
+               ``M-l''.
+
+          N    Name  an  item or type of object.  Same as ``#name'' or ``M-
+               n''.
+
+          u    Untrap a trap, door, or chest.  Same as ``#untrap'' or  ``M-
+               u''.
+
+
+          5.  Rooms and corridors
+
+               Rooms  and  corridors in the dungeon are either lit or dark.
+          Any lit areas within your line of sight will be  displayed;  dark
+          areas  are  only  displayed  if they are within one space of you.
+          Walls and corridors remain on the map as you explore them.
+
+               Secret corridors are hidden.  You can find them with the `s'
+          (search) command.
+
+          5.1.  Doorways
+
+               Doorways connect rooms and corridors.  Some doorways have no
+          doors; you can walk right through.  Others have  doors  in  them,
+          which may be open, closed, or locked.  To open a closed door, use
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              17
+
+
+
+          the `o' (open) command; to close it again, use  the  `c'  (close)
+          command.
+
+               You  can  get  through a locked door by using a tool to pick
+          the lock with the `a' (apply) command, or by kicking it open with
+          the `^D' (kick) command.
+
+               Open  doors  cannot be entered diagonally; you must approach
+          them straight on, horizontally or vertically.   Doorways  without
+          doors are not restricted in this fashion.
+
+               Doors  can  be  useful for shutting out monsters.  Most mon-
+          sters cannot open doors, although a few don't need to (ex. ghosts
+          can walk through doors).
+
+               Secret  doors  are  hidden.   You can find them with the `s'
+          (search) command.  Once found they are in all ways equivalent  to
+          normal doors.
+
+          5.2.  Traps (`^')
+
+               There  are  traps throughout the dungeon to snare the unwary
+          delver.  For example, you may suddenly fall into  a  pit  and  be
+          stuck for a few turns trying to climb out.  Traps don't appear on
+          your map until you see one triggered by moving onto it, see some-
+          thing fall into it, or you discover it with the `s' (search) com-
+          mand.  Monsters can fall prey to traps, too, which can be a  very
+          useful defensive strategy.
+
+               There is a special pre-mapped branch of the dungeon based on
+          the classic computer game ``Sokoban.''  The goal is to  push  the
+          boulders  into  the pits or holes.  With careful foresight, it is
+          possible to complete all of the levels according  to  the  tradi-
+          tional  rules  of Sokoban.  Some allowances are permitted in case
+          the player gets stuck; however, they will lower your luck.
+
+          5.3.  Stairs (`<', `>')
+
+               In general, each level in the dungeon will have a  staircase
+          going up (`<') to the previous level and another going down (`>')
+          to the next level.  There are some exceptions  though.   For  in-
+          stance,  fairly  early  in the dungeon you will find a level with
+          two down staircases, one continuing into the dungeon and the oth-
+          er  branching  into  an  area  known as the Gnomish Mines.  Those
+          mines eventually hit a dead end, so after exploring them (if  you
+          choose  to  do so), you'll need to climb back up to the main dun-
+          geon.
+
+               When you traverse a set of stairs, or trigger a  trap  which
+          sends  you to another level, the level you're leaving will be de-
+          activated and stored in a file on disk.  If you're  moving  to  a
+          previously visited level, it will be loaded from its file on disk
+          and reactivated.  If you're moving to a level which has  not  yet
+          been  visited,  it  will be created (from scratch for most random
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              18
+
+
+
+          levels, from a template for some ``special''  levels,  or  loaded
+          from  the  remains  of  an  earlier game for a ``bones'' level as
+          briefly described below).  Monsters are only active on  the  cur-
+          rent  level;  those  on  other levels are essentially placed into
+          stasis.
+
+               Ordinarily when you climb a set of stairs, you  will  arrive
+          on  the  corresponding  staircase  at your destination.  However,
+          pets (see below) and some other monsters  will  follow  along  if
+          they're close enough when you travel up or down stairs, and occa-
+          sionally one of these creatures  will  displace  you  during  the
+          climb.  When that occurs, the pet or other monster will arrive on
+          the staircase and you will end up nearby.
+
+          5.4.  Ladders (`<', `>')
+
+               Ladders serve the same purpose as staircases,  and  the  two
+          types  of  inter-level  connections  are nearly indistinguishable
+          during game play.
+
+          5.5.  Shops and shopping
+
+               Occasionally you will run across a room  with  a  shopkeeper
+          near  the  door  and  many items lying on the floor.  You can buy
+          items by picking them up and then using the `p' command.  You can
+          inquire  about the price of an item prior to picking it up by us-
+          ing the ``#chat'' command while standing on it.   Using  an  item
+          prior  to  paying  for it will incur a charge, and the shopkeeper
+          won't allow you to leave the shop until you have  paid  any  debt
+          you owe.
+
+               You  can  sell items to a shopkeeper by dropping them to the
+          floor while inside a shop.  You will either be offered an  amount
+          of  gold  and  asked whether you're willing to sell, or you'll be
+          told that the shopkeeper isn't interested (generally,  your  item
+          needs  to  be  compatible with the type of merchandise carried by
+          the shop).
+
+               If you drop something in a shop by accident, the  shopkeeper
+          will  usually  claim ownership without offering any compensation.
+          You'll have to buy it back if you want to reclaim it.
+
+               Shopkeepers sometimes run out of money.  When that  happens,
+          you'll  be  offered  credit  instead of gold when you try to sell
+          something.  Credit can be used to pay for purchases,  but  it  is
+          only  good  in  the shop where it was obtained; other shopkeepers
+          won't honor it.  (If you happen to find a "credit  card"  in  the
+          dungeon, don't bother trying to use it in shops; shopkeepers will
+          not accept it.)
+
+               The `$' command, which reports the amount of  gold  you  are
+          carrying (in inventory, not inside bags or boxes), will also show
+          current shop debt or credit, if any.  The `Iu' command lists  un-
+          paid  items  (those  which  still  belong to the shop) if you are
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              19
+
+
+
+          carrying any.  The `Ix' command shows an  inventory-like  display
+          of  any  unpaid  items  which have been used up, along with other
+          shop fees, if any.
+
+          5.5.1.  Shop idiosyncracies
+
+               Several aspects of shop behavior might be unexpected.
+
+          * The price of a given item can vary due to a variety of factors.
+
+          * A  shopkeeper treats the spot immediately inside the door as if
+            it were outside the shop.
+
+          * While the shopkeeper watches you like a hawk, he will generally
+            ignore any other customers.
+
+          * If  a  shop  is "closed for inventory", it will not open of its
+            own accord.
+
+          * Shops do not get restocked with new items, regardless of inven-
+            tory depletion.
+
+
+          6.  Monsters
+
+               Monsters  you  cannot  see  are not displayed on the screen.
+          Beware!  You may suddenly come upon one in a  dark  place.   Some
+          magic  items  can  help  you  locate  them before they locate you
+          (which some monsters can do very well).
+
+               The commands `/' and `;' may be used to  obtain  information
+          about  those  monsters who are displayed on the screen.  The com-
+          mand `C' allows you to assign a name to a monster, which  may  be
+          useful  to  help  distinguish one from another when multiple mon-
+          sters are present.  Assigning a name which is just a  space  will
+          remove any prior name.
+
+               The  extended command ``#chat'' can be used to interact with
+          an adjacent monster.  There is no actual dialog (in other  words,
+          you  don't get to choose what you'll say), but chatting with some
+          monsters such as a shopkeeper or the Oracle of Delphi can produce
+          useful results.
+
+          6.1.  Fighting
+
+               If  you see a monster and you wish to fight it, just attempt
+          to walk into it.  Many monsters you  find  will  mind  their  own
+          business unless you attack them.  Some of them are very dangerous
+          when angered.  Remember:  discretion is the better part of valor.
+
+               If  you  can't  see a monster (if it is invisible, or if you
+          are blinded), the symbol `I' will be shown when you learn of  its
+          presence.   If you attempt to walk into it, you will try to fight
+          it just like a monster that  you  can  see;  of  course,  if  the
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              20
+
+
+
+          monster  has moved, you will attack empty air.  If you guess that
+          the monster has moved and you don't wish to fight,  you  can  use
+          the  `m' command to move without fighting; likewise, if you don't
+          remember a monster but want to try fighting anyway, you  can  use
+          the `F' command.
+
+          6.2.  Your pet
+
+               You  start  the  game with a little dog (`d'), cat (`f'), or
+          pony (`u'), which follows you about the dungeon and  fights  mon-
+          sters  with  you.   Like you, your pet needs food to survive.  It
+          usually feeds itself on fresh carrion and other meats.  If you're
+          worried  about  it  or want to train it, you can feed it, too, by
+          throwing it food.  A properly trained pet can be very useful  un-
+          der certain circumstances.
+
+               Your  pet  also  gains experience from killing monsters, and
+          can grow over time, gaining hit points  and  doing  more  damage.
+          Initially,  your  pet  may  even be better at killing things than
+          you, which makes pets useful for low-level characters.
+
+               Your pet will follow you up and down  staircases  if  it  is
+          next  to  you when you move.  Otherwise your pet will be stranded
+          and may become wild.  Similarly, when you trigger  certain  types
+          of  traps  which  alter  your location (for instance, a trap door
+          which drops you to a lower dungeon level), any adjacent pet  will
+          accompany you and any non-adjacent pet will be left behind.  Your
+          pet may trigger such traps itself; you will not be carried  along
+          with it even if adjacent at the time.
+
+          6.3.  Steeds
+
+               Some  types of creatures in the dungeon can actually be rid-
+          den if you have the right equipment and skill.  Convincing a wild
+          beast  to  let  you  saddle  it up is difficult to say the least.
+          Many a dungeoneer has had to resort to magic and wizardry in  or-
+          der to forge the alliance.  Once you do have the beast under your
+          control however, you can easily climb in and out  of  the  saddle
+          with the `#ride' command.  Lead the beast around the dungeon when
+          riding, in the same manner as you would move yourself.  It is the
+          beast that you will see displayed on the map.
+
+               Riding  skill is managed by the `#enhance' command.  See the
+          section on Weapon proficiency for more information about that.
+
+          6.4.  Bones levels
+
+               You may encounter the shades and corpses of other  adventur-
+          ers (or even former incarnations of yourself!) and their personal
+          effects.  Ghosts are hard to  kill,  but  easy  to  avoid,  since
+          they're  slow and do little damage.  You can plunder the deceased
+          adventurer's possessions; however, they are likely to be  cursed.
+          Beware of whatever killed the former player; it is probably still
+          lurking around, gloating over its last victory.
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              21
+
+
+
+          7.  Objects
+
+               When you find something in the dungeon, it is common to want
+          to pick it up.  In NetHack, this is accomplished automatically by
+          walking over the object (unless you turn off the  autopickup  op-
+          tion  (see  below),  or move with the `m' prefix (see above)), or
+          manually by using the `,' command.
+
+               If you're carrying too many items, NetHack will tell you  so
+          and  you  won't  be able to pick up anything more.  Otherwise, it
+          will add the object(s) to your pack and tell you  what  you  just
+          picked up.
+
+               As  you add items to your inventory, you also add the weight
+          of that object to your load.  The amount that you can  carry  de-
+          pends  on  your strength and your constitution.  The stronger you
+          are, the less the additional load will affect you.  There comes a
+          point,  though, when the weight of all of that stuff you are car-
+          rying around with you through  the  dungeon  will  encumber  you.
+          Your  reactions  will get slower and you'll burn calories faster,
+          requiring food more frequently  to  cope  with  it.   Eventually,
+          you'll  be  so overloaded that you'll either have to discard some
+          of what you're carrying or collapse under its weight.
+
+               NetHack will tell you how badly you  have  loaded  yourself.
+          The  symbols  `Burdened', `Stressed', `Strained', `Overtaxed' and
+          `Overloaded' are displayed on the bottom line display to indicate
+          your condition.
+
+               When you pick up an object, it is assigned an inventory let-
+          ter.  Many commands that operate on objects must ask you to  find
+          out  which  object  you  want  to  use.  When NetHack asks you to
+          choose a particular object you are carrying, you are usually pre-
+          sented  with a list of inventory letters to choose from (see Com-
+          mands, above).
+
+               Some objects, such as weapons,  are  easily  differentiated.
+          Others,  like  scrolls  and potions, are given descriptions which
+          vary according to type.  During a game, any two objects with  the
+          same  description  are  the same type.  However, the descriptions
+          will vary from game to game.
+
+               When you use one of these objects, if its effect is obvious,
+          NetHack  will  remember  what it is for you.  If its effect isn't
+          extremely obvious, you will be asked what you want to  call  this
+          type  of object so you will recognize it later.  You can also use
+          the ``#name'' command for the same purpose at any time,  to  name
+          all  objects  of  a particular type or just an individual object.
+          When you use ``#name'' on an object which has already been named,
+          specifying  a  space  as the value will remove the prior name in-
+          stead of assigning a new one.
+
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              22
+
+
+
+          7.1.  Curses and Blessings
+
+               Any object that you find may be cursed, even if  the  object
+          is otherwise helpful.  The most common effect of a curse is being
+          stuck with (and to) the item.  Cursed weapons weld themselves  to
+          your  hand  when wielded, so you cannot unwield them.  Any cursed
+          item you wear is not removable by ordinary means.   In  addition,
+          cursed  arms and armor usually, but not always, bear negative en-
+          chantments that make them less effective in combat.  Other cursed
+          objects may act poorly or detrimentally in other ways.
+
+               Objects  can  also  be  blessed.  Blessed items usually work
+          better or more beneficially than normal uncursed items.  For  ex-
+          ample, a blessed weapon will do more damage against demons.
+
+               There are magical means of bestowing or removing curses upon
+          objects, so even if you are stuck with one, you  can  still  have
+          the  curse  lifted and the item removed.  Priests and Priestesses
+          have an innate sensitivity to this property  in  any  object,  so
+          they  can  more  easily avoid cursed objects than other character
+          roles.
+
+               An item with unknown status will be reported in your  inven-
+          tory with no prefix.  An item which you know the state of will be
+          distinguished in your inventory  by  the  presence  of  the  word
+          ``cursed'', ``uncursed'' or ``blessed'' in the description of the
+          item.
+
+          7.2.  Weapons (`)')
+
+               Given a chance, most monsters in the Mazes  of  Menace  will
+          gratuitously  try to kill you.  You need weapons for self-defense
+          (killing them first).  Without a weapon,  you  do  only  1-2  hit
+          points  of damage (plus bonuses, if any).  Monk characters are an
+          exception; they normally do much more damage with bare hands than
+          they do with weapons.
+
+               There are wielded weapons, like maces and swords, and thrown
+          weapons, like arrows and spears.  To hit monsters with a  weapon,
+          you  must wield it and attack them, or throw it at them.  You can
+          simply elect to throw a spear.  To shoot  an  arrow,  you  should
+          first  wield a bow, then throw the arrow.  Crossbows shoot cross-
+          bow bolts.  Slings hurl rocks and (other) stones (like gems).
+
+               Enchanted weapons have a ``plus'' (or ``to hit enhancement''
+          which  can  be  either  positive  or  negative) that adds to your
+          chance to hit and the damage you do to a monster.  The  only  way
+          to determine a weapon's enchantment is to have it magically iden-
+          tified somehow.  Most weapons are subject to some type of  damage
+          like rust.  Such ``erosion'' damage can be repaired.
+
+               The  chance  that an attack will successfully hit a monster,
+          and the amount of damage such a hit will do,  depends  upon  many
+          factors.   Among  them  are:  type  of  weapon, quality of weapon
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              23
+
+
+
+          (enchantment and/or erosion), experience level, strength, dexter-
+          ity, encumbrance, and proficiency (see below).  The monster's ar-
+          mor class - a general defense  rating,  not  necessarily  due  to
+          wearing  of armor - is a factor too; also, some monsters are par-
+          ticularly vulnerable to certain types of weapons.
+
+               Many weapons can be wielded in one hand; some  require  both
+          hands.   When  wielding  a  two-handed weapon, you can not wear a
+          shield, and vice versa.  When wielding a one-handed  weapon,  you
+          can  have  another  weapon ready to use by setting things up with
+          the `x' command, which exchanges  your  primary  (the  one  being
+          wielded)  and  alternate weapons.  And if you have proficiency in
+          the ``two weapon combat'' skill, you may wield both  weapons  si-
+          multaneously  as  primary and secondary; use the `#twoweapon' ex-
+          tended command to engage or disengage that.  Only some  types  of
+          characters  (barbarians,  for  instance) have the necessary skill
+          available.  Even with that skill, using two weapons at  once  in-
+          curs a penalty in the chance to hit your target compared to using
+          just one weapon at a time.
+
+               There might be times when you'd rather not wield any  weapon
+          at  all.  To accomplish that, wield `-', or else use the `A' com-
+          mand which allows you to unwield the current weapon  in  addition
+          to taking off other worn items.
+
+               Those  of you in the audience who are AD&D players, be aware
+          that each weapon which existed in AD&D does roughly the same dam-
+          age  to  monsters  in  NetHack.  Some of the more obscure weapons
+          (such as the aklys, lucern hammer, and bec-de-corbin) are defined
+          in an appendix to Unearthed Arcana, an AD&D supplement.
+
+               The  commands  to  use weapons are `w' (wield), `t' (throw),
+          `f' (fire, an alternative way of  throwing),  `Q'  (quiver),  `x'
+          (exchange), `#twoweapon', and `#enhance' (see below).
+
+          7.2.1.  Throwing and shooting
+
+               You  can  throw just about anything via the `t' command.  It
+          will prompt for the item to throw; picking `?' will  list  things
+          in  your  inventory  which are considered likely to be thrown, or
+          picking `*' will list your entire inventory.  After you've chosen
+          what  to  throw, you will be prompted for a direction rather than
+          for a specific target.  The distance something can be thrown  de-
+          pends mainly on the type of object and your strength.  Arrows can
+          be thrown by hand, but can be thrown much  farther  and  will  be
+          more likely to hit when thrown while you are wielding a bow.
+
+               You  can  simplify  the  throwing operation by using the `Q'
+          command to select your preferred ``missile'', then using the  `f'
+          command  to  throw  it.   You'll  be  prompted for a direction as
+          above, but you don't have to specify which  item  to  throw  each
+          time you use `f'.  There is also an option, autoquiver, which has
+          NetHack choose another item to  automatically  fill  your  quiver
+          when the inventory slot used for `Q' runs out.
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              24
+
+
+
+               Some  characters have the ability to fire a volley of multi-
+          ple items in a single turn.  Knowing how to load  several  rounds
+          of ammunition at once -- or hold several missiles in your hand --
+          and still hit a target is not an easy task.   Rangers  are  among
+          those  who are adept at this task, as are those with a high level
+          of proficiency in the relevant weapon  skill  (in  bow  skill  if
+          you're  wielding one to shoot arrows, in crossbow skill if you're
+          wielding one to shoot bolts, or in sling skill if you're wielding
+          one to shoot stones).  The number of items that the character has
+          a chance to fire varies from turn to turn.   You  can  explicitly
+          limit  the  number  of shots by using a numeric prefix before the
+          `t' or `f' command.  For example, ``2f''  (or  ``n2f''  if  using
+          number_pad mode) would ensure that at most 2 arrows are shot even
+          if you could have fired 3.  If you specify a larger  number  than
+          would have been shot (``4f'' in this example), you'll just end up
+          shooting the same number (3, here) as if no limit had been speci-
+          fied.  Once the volley is in motion, all of the items will travel
+          in the same direction; if the first ones kill a monster, the oth-
+          ers can still continue beyond that spot.
+
+          7.2.2.  Weapon proficiency
+
+               You will have varying degrees of skill in the weapons avail-
+          able.  Weapon proficiency, or weapon skills, affect how well  you
+          can  use  particular  types of weapons, and you'll be able to im-
+          prove your skills as you progress through a  game,  depending  on
+          your role, your experience level, and use of the weapons.
+
+               For  the  purposes of proficiency, weapons have been divided
+          up  into  various  groups  such  as  daggers,  broadswords,   and
+          polearms.   Each  role has a limit on what level of proficiency a
+          character can achieve for each group.  For instance, wizards  can
+          become  highly  skilled in daggers or staves but not in swords or
+          bows.
+
+               The `#enhance' extended command is used  to  review  current
+          weapons  proficiency (also spell proficiency) and to choose which
+          skill(s) to improve when you've used one or more skills enough to
+          become eligible to do so.  The skill rankings are ``none'' (some-
+          times also referred to as ``restricted'', because  you  won't  be
+          able  to  advance),  ``unskilled'',  ``basic'',  ``skilled'', and
+          ``expert''.  Restricted skills simply will not appear in the list
+          shown  by  `#enhance'.   (Divine  intervention might unrestrict a
+          particular skill, in which case it will start at unskilled and be
+          limited  to basic.)  Some characters can enhance their barehanded
+          combat or martial arts  skill  beyond  expert  to  ``master''  or
+          ``grand master''.
+
+               Use of a weapon in which you're restricted or unskilled will
+          incur a modest penalty in the chance to hit a monster and also in
+          the  amount of damage done when you do hit; at basic level, there
+          is no penalty or bonus; at skilled level, you  receive  a  modest
+          bonus  in  the chance to hit and amount of damage done; at expert
+          level, the bonus is higher.  A successful hit  has  a  chance  to
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              25
+
+
+
+          boost  your  training towards the next skill level (unless you've
+          already reached the limit for this skill).   Once  such  training
+          reaches  the  threshold  for that next level, you'll be told that
+          you feel more confident in your skills.  At that  point  you  can
+          use  `#enhance'  to increase one or more skills.  Such skills are
+          not increased automatically because there is a limit to your  to-
+          tal  overall  skills, so you need to actively choose which skills
+          to enhance and which to ignore.
+
+          7.3.  Armor (`[')
+
+               Lots of unfriendly things lurk about; you need armor to pro-
+          tect yourself from their blows.  Some types of armor offer better
+          protection than others.  Your armor class is a  measure  of  this
+          protection.  Armor class (AC) is measured as in AD&D, with 10 be-
+          ing the equivalent of no armor, and lower numbers meaning  better
+          armor.   Each  suit  of armor which exists in AD&D gives the same
+          protection in NetHack.  Here is an (incomplete) list of the armor
+          classes provided by various suits of armor:
+
+                             dragon scale mail         1
+                             plate mail                3
+                             crystal plate mail        3
+                             bronze plate mail         4
+                             splint mail               4
+                             banded mail               4
+                             dwarvish mithril-coat     4
+                             elven mithril-coat        5
+                             chain mail                5
+                             orcish chain mail         6
+                             scale mail                6
+                             studded leather armor     7
+                             ring mail                 7
+                             orcish ring mail          8
+                             leather armor             8
+                             leather jacket            9
+                             no armor                 10
+
+               You can also wear other pieces of armor (ex. helmets, boots,
+          shields, cloaks) to lower your armor class even further, but  you
+          can  only  wear one item of each category (one suit of armor, one
+          cloak, one helmet, one shield, and so on) at a time.
+
+               If a piece of armor is enchanted, its armor protection  will
+          be  better  (or  worse)  than normal, and its ``plus'' (or minus)
+          will subtract from your armor class.  For  example,  a  +1  chain
+          mail  would  give  you  better protection than normal chain mail,
+          lowering your armor class one unit further to 4.  When you put on
+          a  piece  of  armor, you immediately find out the armor class and
+          any ``plusses'' it provides.  Cursed pieces of armor usually have
+          negative enchantments (minuses) in addition to being unremovable.
+
+               Many types of armor are subject to some kind of damage  like
+          rust.   Such  damage  can  be  repaired.  Some types of armor may
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              26
+
+
+
+          inhibit spell casting.
+
+               The commands to use armor are `W' (wear) and `T' (take off).
+          The  `A'  command  can  also be used to take off armor as well as
+          other worn items.
+
+          7.4.  Food (`%')
+
+               Food is necessary to survive.  If you go  too  long  without
+          eating  you  will  faint, and eventually die of starvation.  Some
+          types of food will spoil, and become unhealthy  to  eat,  if  not
+          protected.  Food stored in ice boxes or tins (``cans'') will usu-
+          ally stay fresh, but ice boxes are heavy, and tins take  a  while
+          to open.
+
+               When you kill monsters, they usually leave corpses which are
+          also ``food.''  Many, but not all, of these are edible; some also
+          give  you special powers when you eat them.  A good rule of thumb
+          is ``you are what you eat.''
+
+               Some character roles and some monsters are vegetarian.  Veg-
+          etarian  monsters  will typically never eat animal corpses, while
+          vegetarian players can, but with some rather unpleasant  side-ef-
+          fects.
+
+               You  can  name one food item after something you like to eat
+          with the fruit option.
+
+               The command to eat food is `e'.
+
+          7.5.  Scrolls (`?')
+
+               Scrolls are labeled with various titles, probably chosen  by
+          ancient  wizards  for  their amusement value (ex. ``READ ME,'' or
+          ``THANX MAUD'' backwards).  Scrolls disappear after you read them
+          (except for blank ones, without magic spells on them).
+
+               One  of  the most useful of these is the scroll of identify,
+          which can be used to determine what another object is, whether it
+          is  cursed  or  blessed, and how many uses it has left.  Some ob-
+          jects of subtle enchantment are  difficult  to  identify  without
+          these.
+
+               A mail daemon may run up and deliver mail to you as a scroll
+          of mail (on versions compiled with this feature).   To  use  this
+          feature  on  versions where NetHack mail delivery is triggered by
+          electronic mail appearing in your system mailbox,  you  must  let
+          NetHack  know  where to look for new mail by setting the ``MAIL''
+          environment variable to the file name of your mailbox.   You  may
+          also  want  to set the ``MAILREADER'' environment variable to the
+          file name of your favorite reader, so NetHack  can  shell  to  it
+          when  you  read the scroll.  On versions of NetHack where mail is
+          randomly generated internal to the game, these environment  vari-
+          ables  are  ignored.   You can disable the mail daemon by turning
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              27
+
+
+
+          off the mail option.
+
+               The command to read a scroll is `r'.
+
+          7.6.  Potions (`!')
+
+               Potions are distinguished by the color of the liquid  inside
+          the flask.  They disappear after you quaff them.
+
+               Clear  potions  are  potions  of water.  Sometimes these are
+          blessed or cursed, resulting in holy or unholy water.  Holy water
+          is  the  bane  of  the  undead, so potions of holy water are good
+          things to throw (`t') at them.  It is also sometimes very  useful
+          to dip (``#dip'') an object into a potion.
+
+               The command to drink a potion is `q' (quaff).
+
+          7.7.  Wands (`/')
+
+               Magic  wands  usually  have  multiple magical charges.  Some
+          wands are directional--you must give a direction in which to  zap
+          them.   You can also zap them at yourself (just give a `.' or `s'
+          for the direction). Be warned, however, for this is often unwise.
+          Other  wands  are nondirectional--they don't require a direction.
+          The number of charges in a wand is random and  decreases  by  one
+          whenever you use it.
+
+               When  the number of charges left in a wand becomes zero, at-
+          tempts to use the wand will usually result in nothing  happening.
+          Occasionally, however, it may be possible to squeeze the last few
+          mana points from an otherwise spent wand, destroying  it  in  the
+          process.   A  wand  may be recharged by using suitable magic, but
+          doing so runs the risk of causing it to explode.  The chance  for
+          such  an  explosion starts out very small and increases each time
+          the wand is recharged.
+
+               In a truly desperate situation, when your back is up against
+          the  wall,  you might decide to go for broke and break your wand.
+          This is not for the faint of heart.  Doing so  will  almost  cer-
+          tainly cause a catastrophic release of magical energies.
+
+               When  you have fully identified a particular wand, inventory
+          display will include additional information in  parentheses:  the
+          number  of  times  it  has been recharged followed by a colon and
+          then by its current number of charges.  A current charge count of
+          -1 is a special case indicating that the wand has been cancelled.
+
+               The command to use a wand is `z' (zap).  To break  one,  use
+          the `a' (apply) command.
+
+          7.8.  Rings (`=')
+
+               Rings  are very useful items, since they are relatively per-
+          manent magic, unlike the usually  fleeting  effects  of  potions,
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              28
+
+
+
+          scrolls, and wands.
+
+               Putting  on  a  ring activates its magic.  You can wear only
+          two rings, one on each ring finger.
+
+               Most rings also cause you to grow hungry more  rapidly,  the
+          rate varying with the type of ring.
+
+               The commands to use rings are `P' (put on) and `R' (remove).
+
+          7.9.  Spellbooks (`+')
+
+               Spellbooks are tomes of mighty magic.  When studied with the
+          `r'  (read) command, they transfer to the reader the knowledge of
+          a spell (and therefore eventually become  unreadable)  --  unless
+          the  attempt  backfires.   Reading a cursed spellbook or one with
+          mystic runes beyond your ken can be harmful to your health!
+
+               A spell (even when learned) can also backfire when you  cast
+          it.   If  you  attempt to cast a spell well above your experience
+          level, or if you have little skill  with  the  appropriate  spell
+          type,  or  cast  it at a time when your luck is particularly bad,
+          you can end up wasting both the energy and the time  required  in
+          casting.
+
+               Casting  a  spell  calls  forth magical energies and focuses
+          them with your naked mind.  Some of the magical  energy  released
+          comes  from  within  you, and casting several spells in a row may
+          tire you.  Casting of spells also requires practice.  With  prac-
+          tice,  your skill in each category of spell casting will improve.
+          Over time, however, your memory of each spell will dim,  and  you
+          will need to relearn it.
+
+               Some  spells  are  directional--you must give a direction in
+          which to cast them.  You can also cast  them  at  yourself  (just
+          give  a  `.'  or  `s' for the direction). Be warned, however, for
+          this is often  unwise.   Other  spells  are  nondirectional--they
+          don't require a direction.
+
+               Just as weapons are divided into groups in which a character
+          can become proficient (to varying degrees), spells are  similarly
+          grouped.  Successfully casting a spell exercises the skill group;
+          sufficient skill may increase the potency of the spell and reduce
+          the  risk  of spell failure.  Skill slots are shared with weapons
+          skills.  (See also the section on ``Weapon proficiency''.)
+
+               Casting a spell also requires flexible movement, and wearing
+          various types of armor may interfere with that.
+
+               The  command to read a spellbook is the same as for scrolls,
+          `r' (read).  The `+' command lists  your  current  spells,  their
+          levels, categories, and chances for failure.  The `Z' (cast) com-
+          mand casts a spell.
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              29
+
+
+
+          7.10.  Tools (`(')
+
+               Tools are miscellaneous objects with various purposes.  Some
+          tools  have  a limited number of uses, akin to wand charges.  For
+          example, lamps burn out after a while.  Other tools are  contain-
+          ers, which objects can be placed into or taken out of.
+
+               The command to use tools is `a' (apply).
+
+          7.10.1.  Containers
+
+               You  may  encounter bags, boxes, and chests in your travels.
+          A tool of this sort can be opened  with  the  ``#loot''  extended
+          command  when you are standing on top of it (that is, on the same
+          floor spot), or with the `a' (apply) command when you are  carry-
+          ing  it.   However,  chests are often locked, and are in any case
+          unwieldy objects.  You must set one down before unlocking  it  by
+          using a key or lock-picking tool with the `a' (apply) command, by
+          kicking it with the `^D' command, or by using a weapon  to  force
+          the lock with the ``#force'' extended command.
+
+               Some chests are trapped, causing nasty things to happen when
+          you unlock or open them.  You can check for and try to deactivate
+          traps with the ``#untrap'' extended command.
+
+          7.11.  Amulets (`"')
+
+               Amulets  are very similar to rings, and often more powerful.
+          Like rings, amulets have various magical properties, some benefi-
+          cial, some harmful, which are activated by putting them on.
+
+               Only one amulet may be worn at a time, around your neck.
+
+               The  commands  to use amulets are the same as for rings, `P'
+          (put on) and `R' (remove).
+
+          7.12.  Gems (`*')
+
+               Some gems are valuable, and can be sold for a lot  of  gold.
+          They  are  also a far more efficient way of carrying your riches.
+          Valuable gems increase your score if you bring them with you when
+          you exit.
+
+               Other small rocks are also categorized as gems, but they are
+          much less valuable.  All rocks, however, can be used  as  projec-
+          tile  weapons  (if  you  have a sling).  In the most desperate of
+          cases, you can still throw them by hand.
+
+          7.13.  Large rocks (``')
+
+               Statues and boulders are not particularly  useful,  and  are
+          generally  heavy.   It  is rumored that some statues are not what
+          they seem.
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              30
+
+
+
+               Very large humanoids (giants and their ilk) have been  known
+          to use boulders as weapons.
+
+          7.14.  Gold (`$')
+
+               Gold  adds  to  your  score, and you can buy things in shops
+          with it.  There are a number of monsters in the dungeon that  may
+          be influenced by the amount of gold you are carrying (shopkeepers
+          aside).
+
+
+          8.  Conduct
+
+               As if winning NetHack were  not  difficult  enough,  certain
+          players  seek to challenge themselves by imposing restrictions on
+          the way they play the game.  The game automatically  tracks  some
+          of  these  challenges,  which can be checked at any time with the
+          #conduct command or at the end of the game.  When you perform  an
+          action  which  breaks  a  challenge, it will no longer be listed.
+          This gives players extra ``bragging rights'' for winning the game
+          with  these  challenges.  Note that it is perfectly acceptable to
+          win the game without resorting to these restrictions and that  it
+          is  unusual  for  players  to adhere to challenges the first time
+          they win the game.
+
+               Several of the challenges are related  to  eating  behavior.
+          The  most difficult of these is the foodless challenge.  Although
+          creatures can survive long periods of time without food, there is
+          a  physiological  need for water; thus there is no restriction on
+          drinking beverages, even if they provide some  minor  food  bene-
+          fits.   Calling  upon  your god for help with starvation does not
+          violate any food challenges either.
+
+               A strict vegan diet is one which  avoids  any  food  derived
+          from animals.  The primary source of nutrition is fruits and veg-
+          etables.  The corpses and tins of blobs (`b'), jellies (`j'), and
+          fungi  (`F') are also considered to be vegetable matter.  Certain
+          human food is prepared without animal  products;  namely,  lembas
+          wafers,  cram  rations, food rations (gunyoki), K-rations, and C-
+          rations.  Metal or another normally indigestible  material  eaten
+          while polymorphed into a creature that can digest it is also con-
+          sidered vegan food.  Note however that eating  such  items  still
+          counts against foodless conduct.
+
+               Vegetarians  do  not eat animals; however, they are less se-
+          lective about eating animal byproducts than vegans.  In  addition
+          to the vegan items listed above, they may eat any kind of pudding
+          (`P') other than the black puddings, eggs and food made from eggs
+          (fortune  cookies  and pancakes), food made with milk (cream pies
+          and candy bars), and lumps of royal jelly.  Monks are expected to
+          observe a vegetarian diet.
+
+               Eating  any kind of meat violates the vegetarian, vegan, and
+          foodless conducts.  This includes tripe rations, the  corpses  or
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              31
+
+
+
+          tins  of  any monsters not mentioned above, and the various other
+          chunks of meat found in the dungeon.  Swallowing and digesting  a
+          monster while polymorphed is treated as if you ate the creature's
+          corpse.  Eating leather, dragon hide, or bone items  while  poly-
+          morphed  into  a  creature  that can digest it, or eating monster
+          brains while polymorphed into a mind flayer, is considered eating
+          an animal, although wax is only an animal byproduct.
+
+               Regardless  of  conduct,  there will be some items which are
+          indigestible, and others which are hazardous  to  eat.   Using  a
+          swallow-and-digest attack against a monster is equivalent to eat-
+          ing the monster's corpse.  Please note that the term ``vegan'' is
+          used  here  only  in  the context of diet.  You are still free to
+          choose not to use  or  wear  items  derived  from  animals  (e.g.
+          leather,  dragon hide, bone, horns, coral), but the game will not
+          keep track of this for you.  Also note that ``milky'' potions may
+          be a translucent white, but they do not contain milk, so they are
+          compatible with a vegan  diet.   Slime  molds  or  player-defined
+          ``fruits'',  although they could be anything from ``cherries'' to
+          ``pork chops'', are also assumed to be vegan.
+
+               An atheist is one who rejects religion.  This means that you
+          cannot  #pray,  #offer  sacrifices  to  any god, #turn undead, or
+          #chat with a priest.  Particularly selective  readers  may  argue
+          that  playing  Monk or Priest characters should violate this con-
+          duct; that is a choice left to the player.  Offering  the  Amulet
+          of  Yendor  to  your  god is necessary to win the game and is not
+          counted against this conduct.  You are also not penalized for be-
+          ing  spoken  to  by an angry god, priest(ess), or other religious
+          figure; a true atheist would hear the words but attach no special
+          meaning to them.
+
+               Most  players  fight with a wielded weapon (or tool intended
+          to be wielded as a weapon).  Another challenge is to win the game
+          without  using such a wielded weapon.  You are still permitted to
+          throw, fire, and kick weapons; use a wand, spell, or  other  type
+          of item; or fight with your hands and feet.
+
+               In  NetHack,  a  pacifist  refuses to cause the death of any
+          other monster (i.e. if you would get experience for  the  death).
+          This  is a particularly difficult challenge, although it is still
+          possible to gain experience by other means.
+
+               An illiterate character cannot read or write.  This includes
+          reading  a scroll, spellbook, fortune cookie message, or t-shirt;
+          writing a scroll; or making an engraving of anything other than a
+          single ``x'' (the traditional signature of an illiterate person).
+          Reading an engraving, or any item that is absolutely necessary to
+          win  the game, is not counted against this conduct.  The identity
+          of scrolls and spellbooks  (and  knowledge  of  spells)  in  your
+          starting  inventory  is  assumed to be learned from your teachers
+          prior to the start of the game and isn't counted.
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              32
+
+
+
+               There are several other challenges tracked by the game.   It
+          is possible to eliminate one or more species of monsters by geno-
+          cide; playing without this feature  is  considered  a  challenge.
+          When the game offers you an opportunity to genocide monsters, you
+          may respond with the monster type ``none'' if  you  want  to  de-
+          cline.   You  can change the form of an item into another item of
+          the same type (``polypiling'') or the form of your own body  into
+          another  creature  (``polyself'')  by  wand,  spell, or potion of
+          polymorph; avoiding these effects are each considered challenges.
+          Polymorphing  monsters,  including pets, does not break either of
+          these challenges.  Finally, you may sometimes receive  wishes;  a
+          game  without an attempt to wish for any items is a challenge, as
+          is a game without wishing for an artifact (even if  the  artifact
+          immediately disappears).  When the game offers you an opportunity
+          to make a wish for an item, you may  choose  ``nothing''  if  you
+          want to decline.
+
+
+          9.  Options
+
+               Due  to variations in personal tastes and conceptions of how
+          NetHack should do things, there are options you can set to change
+          how NetHack behaves.
+
+          9.1.  Setting the options
+
+               Options  may  be  set in a number of ways.  Within the game,
+          the `O' command allows you to view all options and change most of
+          them.   You can also set options automatically by placing them in
+          the NETHACKOPTIONS environment variable  or  in  a  configuration
+          file.  Some versions of NetHack also have front-end programs that
+          allow you to set options before starting the game.
+
+          9.2.  Using the NETHACKOPTIONS environment variable
+
+               The NETHACKOPTIONS variable is  a  comma-separated  list  of
+          initial  values for the various options.  Some can only be turned
+          on or off.  You turn one of these on by adding the  name  of  the
+          option to the list, and turn it off by typing a `!' or ``no'' be-
+          fore the name.  Others take a character string as a  value.   You
+          can  set  string  options  by  typing the option name, a colon or
+          equals sign, and then the value of the string.  The value is ter-
+          minated by the next comma or the end of string.
+
+               For example, to set up an environment variable so that ``au-
+          toquiver'' is on, ``autopickup'' is  off,  the  name  is  set  to
+          ``Blue  Meanie'',  and  the fruit is set to ``papaya'', you would
+          enter the command
+
+               % setenv NETHACKOPTIONS "autoquiver,\!autopickup,name:Blue Meanie,fruit:papaya"
+
+          in csh (note the need to escape the ! since it's special  to  the
+          shell), or
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              33
+
+
+
+               $ NETHACKOPTIONS="autoquiver,!autopickup,name:Blue Meanie,fruit:papaya"
+               $ export NETHACKOPTIONS
+
+          in sh or ksh.
+
+          9.3.  Using a configuration file
+
+               Any  line  in  the  configuration  file starting with `#' is
+          treated as a comment.  Any line in the configuration file  start-
+          ing  with ``OPTIONS='' may be filled out with options in the same
+          syntax as in  NETHACKOPTIONS.   Any  line  starting  with  ``DUN-
+          GEON='',  ``EFFECTS='',  ``MONSTERS='', ``OBJECTS='', ``TRAPS='',
+          or ``BOULDER='' is taken as defining the  corresponding  dungeon,
+          effects, monsters, objects traps or boulder option in a different
+          syntax, a sequence of decimal numbers giving the character  posi-
+          tion  in the current font to be used in displaying each entry.  A
+          zero in any entry in such a sequence leaves the display  of  that
+          entry  unchanged;  this feature is not available using the option
+          syntax.  Such a sequence can be continued to  multiple  lines  by
+          putting a `\' at the end of each line to be continued.
+
+               If your copy of the game included the compile time AUTOPICK-
+          UP_EXCEPTIONS option, then any  line  starting  with  ``AUTOPICK-
+          UP_EXCEPTION=''  is  taken  as defining an exception to the pick-
+          up_types option.  There is a section of this Guidebook that  dis-
+          cusses that.
+
+               The default name of the configuration file varies on differ-
+          ent operating systems, but NETHACKOPTIONS can also be set to  the
+          full  name  of  a  file  you want to use (possibly preceded by an
+          `@').
+
+          9.4.  Customization options
+
+               Here are explanations of what the various options do.  Char-
+          acter  strings  that  are too long may be truncated.  Some of the
+          options listed may be inactive in your dungeon.
+
+          align
+            Your  starting  alignment  (align:lawful,   align:neutral,   or
+            align:chaotic).   You  may  specify just the first letter.  The
+            default is to randomly pick an appropriate  alignment.   Cannot
+            be set with the `O' command.
+
+          autodig
+            Automatically dig if you are wielding a digging tool and moving
+            into a place that can be dug (default false).
+
+          autopickup
+            Automatically pick up things onto which you move (default  on).
+            See pickup_types to refine the behavior.
+
+          autoquiver
+            This  option  controls  what  happens  when you attempt the `f'
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              34
+
+
+
+            (fire) command with an empty quiver.  When true,  the  computer
+            will  fill your quiver with some suitable weapon.  Note that it
+            will not take into account the blessed/cursed status,  enchant-
+            ment, damage, or quality of the weapon; you are free to manual-
+            ly fill your quiver with the `Q' command instead.  If no weapon
+            is found or the option is false, the `t' (throw) command is ex-
+            ecuted instead.  (default false)
+
+          boulder
+            Set the character used to display  boulders  (default  is  rock
+            class symbol).
+
+          catname
+            Name your starting cat (ex. ``catname:Morris'').  Cannot be set
+            with the `O' command.
+
+          character
+            Pick your type of character (ex.  ``character:Monk'');  synonym
+            for ``role''.  See ``name'' for an alternate method of specify-
+            ing your role.  Normally only the first letter of the value  is
+            examined; the string ``random'' is an exception.
+
+          checkpoint
+            Save  game state after each level change, for possible recovery
+            after program crash (default on).
+
+          checkspace
+            Check free disk space before writing  files  to  disk  (default
+            on).   You may have to turn this off if you have more than 2 GB
+            free space on the partition used for your save and level files.
+            Only applies when MFLOPPY was defined during compilation.
+
+          cmdassist
+            Have  the  game  provide some additional command assistance for
+            new players if it detects some  anticipated  mistakes  (default
+            on).
+
+          confirm
+            Have  user  confirm  attacks  on  pets,  shopkeepers, and other
+            peaceable creatures (default on).
+
+          DECgraphics
+            Use a predefined selection  of  characters  from  the  DEC  VT-
+            xxx/DEC  Rainbow/ANSI line-drawing character set to display the
+            dungeon/effects/traps instead of having to define a full graph-
+            ics set yourself (default off).  This option also sets up prop-
+            er handling of graphics characters for such terminals,  so  you
+            should specify it when appropriate even if you override the se-
+            lections with your own graphics strings.
+
+          disclose
+            Controls options for disclosing various  information  when  the
+            game ends (defaults to all possibilities being disclosed).  The
+            possibilities are:
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              35
+
+
+
+                 i - disclose your inventory.
+                 a - disclose your attributes.
+                 v - summarize monsters that have been vanquished.
+                 g - list monster species that have been genocided.
+                 c - display your conduct.
+
+            Each disclosure possibility can optionally  be  preceded  by  a
+            prefix  which let you refine how it behaves. Here are the valid
+            prefixes:
+
+                 y - prompt you and default to yes on the prompt.
+                 n - prompt you and default to no on the prompt.
+                 + - disclose it without prompting.
+                 - - do not disclose it and do not prompt.
+
+            (ex. ``disclose:yi na +v -g -c'') The example sets inventory to
+            prompt  and default to yes, attributes to prompt and default to
+            no, vanquished to disclose without prompting, genocided to  not
+            disclose  and not to prompt, conduct to not disclose and not to
+            prompt.  Note that the vanquished monsters  list  includes  all
+            monsters killed by traps and each other as well as by you.
+
+          dogname
+            Name  your  starting dog (ex. ``dogname:Fang'').  Cannot be set
+            with the `O' command.
+
+          dungeon
+            Set the graphics symbols for displaying  the  dungeon  (default
+            `` |--------||.-|++##.##<><>_|\\#{}.}..## #}'').   The  dungeon
+            option should be followed by a string of 1-41 characters to  be
+            used  instead  of the default map-drawing characters.  The dun-
+            geon map will use the characters you specify instead of the de-
+            fault  symbols, and default symbols for any you do not specify.
+            Remember that you may need to escape some of  these  characters
+            on a command line if they are special to your shell.
+
+            Note  that  NetHack escape-processes this option string in con-
+            ventional C fashion.  This means that `\' is a prefix  to  take
+            the following character literally.  Thus `\' needs to be repre-
+            sented as `\\'.  The special escape form `\m' switches  on  the
+            meta  bit in the following character, and the `^' prefix causes
+            the following character to be treated as a control character.
+
+            The order of the symbols is:  solid rock, vertical wall,  hori-
+            zontal  wall, upper left corner, upper right corner, lower left
+            corner, lower right corner, cross wall, upward T wall, downward
+            T  wall,  leftward  T wall, rightward T wall, no door, vertical
+            open door, horizontal open door, vertical closed door, horizon-
+            tal  closed door, iron bars, tree, floor of a room, dark corri-
+            dor, lit corridor, stairs up, stairs down,  ladder  up,  ladder
+            down,  altar,  grave,  throne,  kitchen sink, fountain, pool or
+            moat, ice, lava, vertical lowered drawbridge,  horizontal  low-
+            ered  drawbridge, vertical raised drawbridge, horizontal raised
+            drawbridge, air, cloud, under water.
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              36
+
+
+
+            You might want to use `+' for the corners and  T  walls  for  a
+            more aesthetic, boxier display.  Note that in the next release,
+            new symbols may be added, or the present ones rearranged.
+
+            Cannot be set with the `O' command.
+
+          effects
+            Set the graphics symbols for displaying  special  effects  (de-
+            fault ``|-\\/*!)(0#@*/-\\||\\-//-\\| |\\-/'').  The effects op-
+            tion should be followed by a string of 1-29  characters  to  be
+            used  instead  of the default special-effects characters.  This
+            string is subjected to the same processing as the  dungeon  op-
+            tion.
+
+            The  order  of the symbols is:  vertical beam, horizontal beam,
+            left slant, right slant, digging beam, camera flash beam,  left
+            boomerang, right boomerang, four glyphs giving the sequence for
+            magic resistance displays, the  eight  surrounding  glyphs  for
+            swallowed  display,  nine  glyphs for explosions.  An explosion
+            consists of three rows (top, middle, and bottom) of three char-
+            acters.  The explosion is centered in the center of this 3 by 3
+            array.
+
+            Note that in the next release, new symbols may be added, or the
+            present ones rearranged.
+
+            Cannot be set with the `O' command.
+
+          extmenu
+            Changes  the  extended  commands  interface to pop-up a menu of
+            available commands.  It is keystroke compatible with the tradi-
+            tional  interface  except that it does not require that you hit
+            Enter. It is implemented only by the tty  port  (default  off),
+            when the game has been compiled to support tty graphics.
+
+          female
+            An  obsolete synonym for ``gender:female''.  Cannot be set with
+            the `O' command.
+
+          fixinv
+            An object's inventory letter sticks to  it  when  it's  dropped
+            (default  on).   If  this is off, dropping an object shifts all
+            the remaining inventory letters.
+
+          fruit
+            Name a fruit after something you enjoy eating (ex. ``fruit:man-
+            go'')  (default  ``slime mold'').  Basically a nostalgic whimsy
+            that NetHack uses from time to time.  You should  set  this  to
+            something  you  find  more appetizing than slime mold.  Apples,
+            oranges, pears, bananas, and melons already exist  in  NetHack,
+            so don't use those.
+
+          gender
+            Your  starting  gender (gender:male or gender:female).  You may
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              37
+
+
+
+            specify just the first letter.  Although you can  still  denote
+            your  gender  using  the  ``male''  and ``female'' options, the
+            ``gender'' option will take precedence.  The default is to ran-
+            domly  pick  an appropriate gender.  Cannot be set with the `O'
+            command.
+
+          help
+            If more information is available for an object looked  at  with
+            the  `/' command, ask if you want to see it (default on). Turn-
+            ing help off makes just looking at  things  faster,  since  you
+            aren't  interrupted with the ``More info?'' prompt, but it also
+            means that you might miss some interesting and/or important in-
+            formation.
+
+          horsename
+            Name  your  starting horse (ex. ``horsename:Trigger'').  Cannot
+            be set with the `O' command.
+
+          IBMgraphics
+            Use a predefined selection of IBM extended ASCII characters  to
+            display the dungeon/effects/traps instead of having to define a
+            full graphics set yourself (default  off).   This  option  also
+            sets  up proper handling of graphics characters for such termi-
+            nals, so you should specify it when  appropriate  even  if  you
+            override the selections with your own graphics strings.
+
+          ignintr
+            Ignore interrupt signals, including breaks (default off).
+
+          legacy
+            Display an introductory message when starting the game (default
+            on).
+
+          lit_corridor
+            Show corridor squares seen by night vision or  a  light  source
+            held by your character as lit (default off).
+
+          lootabc
+            Use  the old `a', `b', and `c' keyboard shortcuts when looting,
+            rather than the mnemonics `o', `i', and `b' (default off).
+
+          mail
+            Enable mail delivery during the game (default on).
+
+          male
+            An obsolete synonym for ``gender:male''.  Cannot  be  set  with
+            the `O' command.
+
+          menustyle
+            Controls the interface used when you need to choose various ob-
+            jects (in response to the Drop  command,  for  instance).   The
+            value  specified  should be the first letter of one of the fol-
+            lowing:  traditional, combination, partial,  or  full.   Tradi-
+            tional  was  the only interface available for earlier versions;
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              38
+
+
+
+            it consists of a prompt for object class  characters,  followed
+            by  an  object-by-object  prompt for all items matching the se-
+            lected object class(es).  Combination starts with a prompt  for
+            object  class(es)  of  interest,  but  then  displays a menu of
+            matching objects rather  than  prompting  one-by-one.   Partial
+            skips  the  object  class  filtering and immediately displays a
+            menu of all objects.  Full displays a menu  of  object  classes
+            rather than a character prompt, and then a menu of matching ob-
+            jects for selection.
+
+          menu_deselect_all
+            Menu character accelerator to deselect all  items  in  a  menu.
+            Implemented by the Amiga, Gem, X11 and tty ports.  Default '-'.
+
+          menu_deselect_page
+            Menu character accelerator to deselect all items on  this  page
+            of  a  menu.  Implemented by the Amiga, Gem and tty ports.  De-
+            fault '\'.
+
+          menu_first_page
+            Menu character accelerator to jump to the first page in a menu.
+            Implemented by the Amiga, Gem and tty ports.  Default '^'.
+
+          menu_headings
+            Controls  how  the  headings in a menu are highlighted.  Values
+            are 'bold', 'inverse', or 'underline'.  Not all ports can actu-
+            ally display all three types.
+
+          menu_invert_all
+            Menu  character accelerator to invert all items in a menu.  Im-
+            plemented by the Amiga, Gem, X11 and tty ports.  Default '@'.
+
+          menu_invert_page
+            Menu character accelerator to invert all items on this page  of
+            a  menu.  Implemented by the Amiga, Gem and tty ports.  Default
+            '~'.
+
+          menu_last_page
+            Menu character accelerator to jump to the last page in a  menu.
+            Implemented by the Amiga, Gem and tty ports.  Default '|'.
+
+          menu_next_page
+            Menu  character accelerator to goto the next menu page.  Imple-
+            mented by the Amiga, Gem and tty ports.  Default '>'.
+
+          menu_previous_page
+            Menu character accelerator to goto the previous menu page.  Im-
+            plemented by the Amiga, Gem and tty ports.  Default '<'.
+
+          menu_search
+            Menu  character  accelerator to search for a menu item.  Imple-
+            mented by the Amiga, Gem and X11 ports.  Default ':'.
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              39
+
+
+
+          menu_select_all
+            Menu character accelerator to select all items in a menu.   Im-
+            plemented by the Amiga, Gem, X11 and tty ports.  Default '.'.
+
+          menu_select_page
+            Menu  character accelerator to select all items on this page of
+            a menu.  Implemented by the Amiga, Gem and tty ports.   Default
+            ','.
+
+          monsters
+            Set  the  characters  used  to display monster classes (default
+            ``abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU-
+            VWXYZ@ '&;:~]'').   This  string  is subjected to the same pro-
+            cessing as the dungeon option.  The order of the symbols is ant
+            or  other insect, blob, cockatrice, dog or other canine, eye or
+            sphere, feline, gremlin, humanoid, imp or minor  demon,  jelly,
+            kobold,  leprechaun, mimic, nymph, orc, piercer, quadruped, ro-
+            dent, arachnid or centipede, trapper or lurker above, horse  or
+            unicorn,  vortex, worm, xan or other mythical/fantastic insect,
+            light, zruty, angelic being, bat or bird, centaur, dragon, ele-
+            mental,  fungus  or mold, gnome, giant humanoid, invisible mon-
+            ster, jabberwock, Keystone Kop, lich, mummy, naga,  ogre,  pud-
+            ding or ooze, quantum mechanic, rust monster, snake, troll, um-
+            ber hulk, vampire, wraith, xorn, apelike creature, zombie,  hu-
+            man,  ghost, golem, demon, sea monster, lizard, long worm tail,
+            and mimic.  Cannot be set with the `O' command.
+
+          msghistory
+            The number of top line messages to save (and  recall  with  ^P)
+            (default 20).  Cannot be set with the `O' command.
+
+          msg_window
+            Allows  you  to change the way recalled messages are displayed.
+            (It is currently implemented for tty only.)  The possible  val-
+            ues are:
+
+                 s - single message (default, this was the behavior before 3.4.0).
+                 c - combination, two messages as `single', then as `full'.
+                 f - full window, oldest message first.
+                 r - full window, newest message first.
+
+            For  backward  compatibility,  no  value  needs to be specified
+            (which defaults to `full'), or it can  be  negated  (which  de-
+            faults to `single').
+
+          name
+            Set  your  character's  name (defaults to your user name).  You
+            can also set your character's role by appending a dash and  one
+            or more letters of the role (that is, by suffixing one of -A -B
+            -C -H -K -M -P -Ra -Ro -S -T -V -W).  If -@  is  used  for  the
+            role,  then  a random one will be automatically chosen.  Cannot
+            be set with the `O' command.
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              40
+
+
+
+          news
+            Read the NetHack news file, if present (default on).  Since the
+            news is shown at the beginning of the game, there's no point in
+            setting this with the `O' command.
+
+          null
+            Send padding nulls to the terminal (default off).
+
+          number_pad
+            Use the number keys to move instead of [yuhjklbn] (default 0 or
+            off).   (number_pad:2  invokes  the  old DOS behavior where `5'
+            means `g', meta-`5' means `G',  and meta-`0' means `I'.)
+
+          objects
+            Set the characters used  to  display  object  classes  (default
+            ``])[="(%!?+/$*`0_.'').   This  string is subjected to the same
+            processing as the dungeon option.  The order of the symbols  is
+            illegal-object  (should  never  be  seen), weapon, armor, ring,
+            amulet, tool, food, potion, scroll, spellbook, wand, gold,  gem
+            or  rock, boulder or statue, iron ball, chain, and venom.  Can-
+            not be set with the `O' command.
+
+          packorder
+            Specify  the  order  to   list   object   types   in   (default
+            ``")[%?+!=/(*`0_'').   The  value  of  this  option should be a
+            string containing the symbols for  the  various  object  types.
+            Any  omitted  types  are filled in at the end from the previous
+            order.
+
+          perm_invent
+            If true, always display your current  inventory  in  a  window.
+            This  only makes sense for windowing system interfaces that im-
+            plement this feature.
+
+          pettype
+            Specify the type of your initial pet,  if  you  are  playing  a
+            character  class that uses multiple types of pets; or choose to
+            have no initial pet  at  all.   Possible  values  are  ``cat'',
+            ``dog'' and ``none''.  Cannot be set with the `O' command.
+
+          pickup_burden
+            When  you  pick  up  an item that would exceed this encumbrance
+            level (Unburdened, Burdened, streSsed, straiNed, overTaxed,  or
+            overLoaded),  you  will be asked if you want to continue.  (De-
+            fault `S').
+
+          pickup_types
+            Specify the object types to be picked up when autopickup is on.
+            Default is all types.  If your copy of the game has the experi-
+            mental compile time option AUTOPICKUP_EXCEPTIONS included,  you
+            may  be  able  to  use  autopickup_exception configuration file
+            lines to further refine autopickup behavior.
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              41
+
+
+
+          prayconfirm
+            Prompt for confirmation before praying (default on).
+
+          pushweapon
+            Using the `w' (wield) command when already  wielding  something
+            pushes  the  old  item into your alternate weapon slot (default
+            off).
+
+          race
+            Selects your race (for example,  ``race:human'').   Default  is
+            random.  Cannot be set with the `O' command.
+
+          rest_on_space
+            Make  the  space  bar a synonym for the `.' (rest) command (de-
+            fault off).
+
+          role
+            Pick your type of character (ex. ``role:Samurai''); synonym for
+            ``character''.   See ``name'' for an alternate method of speci-
+            fying your role.  Normally only the first letter of  the  value
+            is  examined;  `r'  is an exception with ``Rogue'', ``Ranger'',
+            and ``random'' values.
+
+          runmode
+            Controls the amount of screen updating for the map window  when
+            engaged  in multi-turn movement (running via shift+direction or
+            control+direction and so forth, or via the  travel  command  or
+            mouse click).  The possible values are:
+
+                 teleport - update the map after movement has finished;
+                 run - update the map after every seven or so steps;
+                 walk - update the map after each step;
+                 crawl - like walk, but pause briefly after each step.
+
+            This option only affects the game's screen display, not the ac-
+            tual results of moving.  The default is `run';  versions  prior
+            to  3.4.1  used  `teleport' only.  Whether or not the effect is
+            noticeable will depend upon the window port used or on the type
+            of terminal.
+
+          safe_pet
+            Prevent  you from (knowingly) attacking your pets (default on).
+
+          scores
+            Control what parts of the score list you are shown at  the  end
+            (ex.   ``scores:5  top  scores/4 around my score/own scores'').
+            Only the first letter of each category (`t', `a',  or  `o')  is
+            necessary.
+
+          showexp
+            Show your accumulated experience points on bottom line (default
+            off).
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              42
+
+
+
+          showrace
+            Display yourself as the glyph for your race,  rather  than  the
+            glyph  for your role (default off).  Note that this setting af-
+            fects only the appearance of the display, not the way the  game
+            treats you.
+
+          showscore
+            Show your approximate accumulated score on bottom line (default
+            off).
+
+          silent
+            Suppress terminal beeps (default on).
+
+          sortpack
+            Sort the pack contents by type when displaying  inventory  (de-
+            fault on).
+
+          sound
+            Enable  messages  about what your character hears (default on).
+            Note that this has nothing to do with your computer's audio ca-
+            pabilities.   This  option is only partly under player control.
+            The game toggles it off and on during and after sleep, for  ex-
+            ample.
+
+          sparkle
+            Display a sparkly effect when a monster (including yourself) is
+            hit by an attack to which it is resistant (default on).
+
+          standout
+            Boldface monsters and ``--More--'' (default off).
+
+          suppress_alert
+            This option may be set to a NetHack version level  to  suppress
+            alert  notification messages about feature changes for that and
+            prior versions (ex. ``suppress_alert:3.3.1'').
+
+          time
+            Show the elapsed game time in turns  on  bottom  line  (default
+            off).
+
+          timed_delay
+            When  pausing  momentarily for display effect, such as with ex-
+            plosions and moving objects, use a timer  rather  than  sending
+            extra  characters to the screen.  (Applies to ``tty'' interface
+            only; ``X11'' interface always uses a timer based  delay.   The
+            default is on if configured into the program.)
+
+          tombstone
+            Draw a tombstone graphic upon your death (default on).
+
+          toptenwin
+            Put the ending display in a NetHack window instead of on stdout
+            (default off).  Setting this option makes the score list  visi-
+            ble  when  a  windowing version of NetHack is started without a
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              43
+
+
+
+            parent window, but it no longer leaves the  score  list  around
+            after game end on a terminal or emulating window.
+
+          traps
+            Set   the   graphics  symbols  for  displaying  traps  (default
+            ``^^^^^^^^^^^^^^^^^"^^^^'').  The traps option should  be  fol-
+            lowed  by a string of 1-22 characters to be used instead of the
+            default traps characters.  This string is subjected to the same
+            processing as the dungeon option.
+
+            The  order  of  the  symbols is: arrow trap, dart trap, falling
+            rock trap, squeaky board, bear trap, land mine, rolling boulder
+            trap, sleeping gas trap, rust trap, fire trap, pit, spiked pit,
+            hole, trap door, teleportation trap,  level  teleporter,  magic
+            portal,  web,  statue trap, magic trap, anti-magic field, poly-
+            morph trap.
+
+            Cannot be set with the `O' command.
+
+          travel
+            Allow the travel command (default on).  Turning this option off
+            will  prevent  the game from attempting unintended moves if you
+            make inadvertent mouse clicks on the map window.
+
+          verbose
+            Provide more commentary during the game (default on).
+
+          windowtype
+            Select which windowing  system  to  use,  such  as  ``tty''  or
+            ``X11''  (default  depends on version).  Cannot be set with the
+            `O' command.
+
+          9.5.  Window Port Customization options
+
+               Here are explanations of the various options that  are  used
+          to  customize  and  change  the characteristics of the windowtype
+          that you have chosen.  Character strings that are too long may be
+          truncated.   Not  all  window  ports will adjust for all settings
+          listed here.  You can safely add any of  these  options  to  your
+          config  file,  and  if the window port is capable of adjusting to
+          suit your preferences, it will attempt to do so. If it  can't  it
+          will  silently  ignore it.  You can find out if an option is sup-
+          ported by the window port that you are currently using by  check-
+          ing  to see if it shows up in the Options list.  Some options are
+          dynamic and can be specified during the game with  the  `O'  com-
+          mand.
+
+          align_message
+            Where  to align or place the message window (top, bottom, left,
+            or right)
+
+          align_status
+            Where to align or place the status window (top,  bottom,  left,
+            or right).
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              44
+
+
+
+          ascii_map
+            NetHack should display an ascii character map if it can.
+
+          color
+            NetHack  should display color if it can for different monsters,
+            objects, and dungeon features
+
+          eight_bit_tty
+            NetHack should pass eight-bit character  values  (for  example,
+            specified  with the traps option) straight through to your ter-
+            minal (default off).
+
+          font_map
+            NetHack should use a font by the chosen name for the  map  win-
+            dow.
+
+          font_menu
+            NetHack  should use a font by the chosen name for menu windows.
+
+          font_message
+            NetHack should use a font by the chosen name  for  the  message
+            window.
+
+          font_status
+            NetHack  should  use  a  font by the chosen name for the status
+            window.
+
+          font_text
+            NetHack should use a font by the chosen name for text  windows.
+
+          font_size_map
+            NetHack should use this size font for the map window.
+
+          font_size_menu
+            NetHack should use this size font for menu windows.
+
+          font_size_message
+            NetHack should use this size font for the message window.
+
+          font_size_status
+            NetHack should use this size font for the status window.
+
+          font_size_text
+            NetHack should use this size font for text windows.
+
+          fullscreen
+            NetHack should try and display on the entire screen rather than
+            in a window.
+
+          hilite_pet
+            Visually distinguish pets from similar animals  (default  off).
+            The  behavior  of  this option depends on the type of windowing
+            you use.  In text windowing, text highlighting or inverse video
+            is  often  used;  with tiles, generally displays a heart symbol
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              45
+
+
+
+            near pets.
+
+          large_font
+            NetHack should use a large font.
+
+          map_mode
+            NetHack should display the map in the manner specified.
+
+          mouse_support
+            Allow use of the mouse for input and travel.
+
+          player_selection
+            NetHack should pop up dialog boxes, or use prompts for  charac-
+            ter selection.
+
+          popup_dialog
+            NetHack should pop up dialog boxes for input.
+
+          preload_tiles
+            NetHack  should preload tiles into memory.  For example, in the
+            protected mode MSDOS version, control whether  tiles  get  pre-
+            loaded  into  RAM  at the start of the game.  Doing so enhances
+            performance of the tile graphics, but uses  more  memory.  (de-
+            fault on).  Cannot be set with the `O' command.
+
+          scroll_amount
+            NetHack  should scroll the display by this number of cells when
+            the hero reaches the scroll_margin.
+
+          scroll_margin
+            NetHack should scroll the display when the hero  or  cursor  is
+            this number of cells away from the edge of the window.
+
+          softkeyboard
+            Display  an  onscreen  keyboard.   Handhelds are most likely to
+            support this option.
+
+          splash_screen
+            NetHack should display an opening splash screen when it  starts
+            up (default yes).
+
+          tiled_map
+            NetHack should display a tiled map if it can.
+
+          tile_file
+            Specify  the  name  of an alternative tile file to override the
+            default.
+
+          tile_height
+            Specify the preferred height of each tile  in  a  tile  capable
+            port.
+
+          tile_width
+            Specify the preferred width of each tile in a tile capable port
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              46
+
+
+
+          use_inverse
+            NetHack should display inverse when the game specifies it.
+
+          vary_msgcount
+            NetHack should display this number of messages at a time in the
+            message window.
+
+          windowcolors
+            NetHack   should  display  windows  with  the  specified  fore-
+            ground/background colors if it can.
+
+          wraptext
+            NetHack port should wrap long lines of text if they  don't  fit
+            in the visible area of the window.
+
+          9.6.  Platform-specific Customization options
+
+               Here  are  explanations of options that are used by specific
+          platforms or ports to customize and change the port behavior.
+
+          altkeyhandler
+            Select an alternate keystroke handler dll to  load  (Win32  tty
+            NetHack  only).   The  name of the handler is specified without
+            the .dll extension and without any path information.  Cannot be
+            set with the `O' command.
+
+          altmeta
+            (default on, AMIGA NetHack only).
+
+          BIOS
+            Use BIOS calls to update the screen display quickly and to read
+            the keyboard (allowing the use of arrow keys to  move)  on  ma-
+            chines  with  an IBM PC compatible BIOS ROM (default off, OS/2,
+            PC, and ST NetHack only).
+
+          flush
+            (default off, AMIGA NetHack only).
+
+          MACgraphics
+            (default on, Mac NetHack only).
+
+          page_wait
+            (default on, Mac NetHack only).
+
+          rawio
+            Force raw (non-cbreak) mode for faster output and more  bullet-
+            proof  input  (MS-DOS sometimes treats `^P' as a printer toggle
+            without it) (default off,  OS/2,  PC,  and  ST  NetHack  only).
+            Note:   DEC  Rainbows hang if this is turned on.  Cannot be set
+            with the `O' command.
+
+          soundcard
+            (default on, PC NetHack only).  Cannot be set with the `O' com-
+            mand.
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              47
+
+
+
+          subkeyvalue
+            (Win32  tty  NetHack  only).  May be used to alter the value of
+            keystrokes that the operating system returns to NetHack to help
+            compensate  for international keyboard issues.  OPTIONS=subkey-
+            value:171/92 will return 92 to NetHack, if 171  was  originally
+            going  to be returned.  You can use multiple subkeyvalue state-
+            ments in the config file if needed.  Cannot be set with the `O'
+            command.
+
+          video
+            Set the video mode used (PC NetHack only).  Values are `autode-
+            tect', `default', or `vga'.   Setting  `vga'  (or  `autodetect'
+            with  vga  hardware  present)  will  cause  the game to display
+            tiles.  Cannot be set with the `O' command.
+
+          videocolors
+            Set the color palette for PC systems  using  NO_TERMS  (default
+            4-2-6-1-5-3-15-12-10-14-9-13-11,  (PC NetHack only).  The order
+            of  colors  is  red,  green,  brown,   blue,   magenta,   cyan,
+            bright.white,  bright.red,  bright.green,  yellow, bright.blue,
+            bright.magenta, and bright.cyan.  Cannot be set  with  the  `O'
+            command.
+
+          videoshades
+            Set the intensity level of the three gray scales available (de-
+            fault dark normal light, PC NetHack only).  If the game display
+            is  difficult to read, try adjusting these scales; if this does
+            not correct the problem, try !color.  Cannot be  set  with  the
+            `O' command.
+
+          9.7.  Configuring autopickup exceptions
+
+               There  is  an  experimental  compile  time option called AU-
+          TOPICKUP_EXCEPTIONS.  If your copy of the  game  was  built  with
+          that  option  defined, you can further refine the behavior of the
+          autopickup option beyond what  is  available  through  the  pick-
+          up_types option.
+
+               By  placing autopickup_exception lines in your configuration
+          file, you can define patterns to be  checked  when  the  game  is
+          about to autopickup something.
+
+          autopickup_exception
+            Sets  an  exception  to the pickup_types option.  The autopick-
+            up_exception option should be followed  by  a  string  of  1-80
+            characters  to be used as a pattern to match against the singu-
+            lar form of the description of an object at your location.
+
+               You may use the following special characters in a pattern:
+
+                 *--- matches 0 or more characters.
+                 ?--- matches any single character.
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              48
+
+
+
+               In addition, some characters are treated specially  if  they
+          occur as the first character in the string pattern, specifically:
+
+               < - always pickup an object that matches the pattern that follows.
+               > - never pickup an object that matches the pattern that follows.
+
+               Can be set with the `O' command, but the setting is not pre-
+          served across saves and restores.
+
+               Here's a couple of examples of autopickup_exceptions:
+
+               autopickup_exception="<*arrow"
+               autopickup_exception=">*corpse"
+               autopickup_exception=">* cursed*"
+
+          The  first example above will result in autopickup of any type of
+          arrow.  The second example results in the exclusion of any corpse
+          from  autopickup.   The  last example results in the exclusion of
+          items known to be cursed from autopickup.  A `never pickup'  rule
+          takes precedence over an `always pickup' rule if both match.
+
+          9.8.  Configuring User Sounds
+
+               Some  platforms allow you to define sound files to be played
+          when a message that matches a user-defined pattern  is  delivered
+          to the message window.  At this time the Qt port and the win32tty
+          and win32gui ports support the use of user sounds.
+
+               The following config file entries are  relevant  to  mapping
+          user sounds to messages:
+
+          SOUNDDIR
+            The directory that houses the sound files to be played.
+
+          SOUND
+            An  entry  that  maps  a sound file to a user-specified message
+            pattern.  Each SOUND entry is broken down  into  the  following
+            parts:
+
+                 MESG       - message window mapping (the only one supported in 3.4).
+                 pattern    - the pattern to match.
+                 sound file - the sound file to play.
+                 volume     - the volume to be set while playing the sound file.
+
+               The  exact  format  for  the  pattern depends on whether the
+          platform is built to use ``regular expressions'' or NetHack's own
+          internal  pattern  matching facility. The ``regular expressions''
+          matching can be much more sophisticated than the internal NetHack
+          pattern  matching, but requires 3rd party libraries on some plat-
+          forms.  There are plenty of references  available  elsewhere  for
+          explaining  ``regular expressions''. You can verify which pattern
+          matching is used by your port with the #version command.
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              49
+
+
+
+               NetHack's internal pattern matching routine uses the follow-
+          ing special characters in its pattern matching:
+
+                 *--- matches 0 or more characters.
+                 ?--- matches any single character.
+
+               Here's  an example of a sound mapping using NetHack's inter-
+          nal pattern matching facility:
+
+                   SOUND=MESG "*chime of a cash register*" "gong.wav" 50
+
+          specifies that any message with "chime of a cash  register"  con-
+          tained  in  it  will  trigger the playing of "gong.wav".  You can
+          have multiple SOUND entries in your config file.
+
+          9.9.  Configuring NetHack for Play by the Blind
+
+               NetHack can be set up to use only standard ASCII  characters
+          for  making  maps of the dungeons. This makes the MS-DOS versions
+          of NetHack completely accessible to  the  blind  who  use  speech
+          and/or  Braille access technologies.  Players will require a good
+          working knowledge of their screen-reader's review  features,  and
+          will  have  to  know  how to navigate horizontally and vertically
+          character by character. They will also find the search  capabili-
+          ties  of their screen-readers to be quite valuable. Be certain to
+          examine this Guidebook before playing so you have  an  idea  what
+          the  screen layout is like. You'll also need to be able to locate
+          the PC cursor. It is always  where  your  character  is  located.
+          Merely  searching for an @-sign will not always find your charac-
+          ter since there are other humanoids represented by the same sign.
+          Your  screen-reader  should  also have a function which gives you
+          the row and column of your  review  cursor  and  the  PC  cursor.
+          These  co-ordinates  are  often useful in giving players a better
+          sense of the overall location of items on the screen.
+
+               While it is not difficult for experienced users to edit  the
+          defaults.nh  file  to accomplish this, novices may find this task
+          somewhat daunting.  Included in  all  official  distributions  of
+          NetHack is a file called NHAccess.nh.  Replacing defaults.nh with
+          this file will cause the game to run in a  manner  accessible  to
+          the  blind.  After  you have gained some experience with the game
+          and with editing files, you may want to alter settings to  better
+          suit your preferences. Instructions on how to do this are includ-
+          ed in the NHAccess.nh file itself. The most crucial  settings  to
+          make the game accessible are:
+
+          IBMgraphics
+            Disable IBMgraphics by commenting out this option.
+
+          menustyle:traditional
+            This will assist in the interface to speech synthesizers.
+
+          number_pad
+            A  lot  of  speech access programs use the number-pad to review
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              50
+
+
+
+            the screen.  If this is the case, disable the number_pad option
+            and use the traditional Rogue-like commands.
+
+          Character graphics
+            Comment  out  all character graphics sets found near the bottom
+            of the defaults.nh file.  Most of these replace  NetHack's  de-
+            fault  representation of the dungeon using standard ASCII char-
+            acters with fancier characters from  extended  character  sets,
+            and these fancier characters can annoy screen-readers.
+
+          10.  Scoring
+
+               NetHack  maintains  a  list  of the top scores or scorers on
+          your machine, depending on how it is set up.  In the latter case,
+          each  account  on the machine can post only one non-winning score
+          on this list.  If you score higher  than  someone  else  on  this
+          list,  or better your previous score, you will be inserted in the
+          proper place under your current name.  How many scores  are  kept
+          can also be set up when NetHack is compiled.
+
+               Your  score  is  chiefly  based upon how much experience you
+          gained, how much loot you accumulated, how deep you explored, and
+          how the game ended.  If you quit the game, you escape with all of
+          your gold intact.  If, however, you get killed in  the  Mazes  of
+          Menace, the guild will only hear about 90% of your gold when your
+          corpse is discovered (adventurers  have  been  known  to  collect
+          finder's  fees).   So, consider whether you want to take one last
+          hit at that monster and possibly live,  or  quit  and  stop  with
+          whatever  you  have.  If you quit, you keep all your gold, but if
+          you swing and live, you might find more.
+
+               If you just want to see what the current  top  players/games
+          list is, you can type nethack -s all on most versions.
+
+
+          11.  Explore mode
+
+               NetHack  is  an intricate and difficult game.  Novices might
+          falter in fear, aware of their ignorance of the means to survive.
+          Well,  fear  not.   Your  dungeon may come equipped with an ``ex-
+          plore'' or ``discovery'' mode that enables you to keep  old  save
+          files  and  cheat death, at the paltry cost of not getting on the
+          high score list.
+
+               There are two ways of enabling  explore  mode.   One  is  to
+          start the game with the -X switch.  The other is to issue the `X'
+          command while already playing the game.  The  other  benefits  of
+          explore mode are left for the trepid reader to discover.
+
+
+          12.  Credits
+
+               The  original  hack  game  was  modeled on the Berkeley UNIX
+          rogue game.   Large  portions  of  this  paper  were  shamelessly
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              51
+
+
+
+          cribbed  from  A Guide to the Dungeons of Doom, by Michael C. Toy
+          and Kenneth C. R. C. Arnold.  Small portions  were  adapted  from
+          Further Exploration of the Dungeons of Doom, by Ken Arromdee.
+
+               NetHack is the product of literally dozens of people's work.
+          Main events in the course of the game development  are  described
+          below:
+
+
+               Jay  Fenlason  wrote the original Hack, with help from Kenny
+          Woodland, Mike Thome and Jon Payne.
+
+               Andries Brouwer did a major re-write, transforming Hack into
+          a  very  different  game, and published (at least) three versions
+          (1.0.1, 1.0.2, and 1.0.3) for UNIX machines to the Usenet.
+
+               Don G. Kneller ported Hack 1.0.3 to Microsoft C and  MS-DOS,
+          producing  PC  HACK 1.01e, added support for DEC Rainbow graphics
+          in version 1.03g, and went on to produce at least four more  ver-
+          sions (3.0, 3.2, 3.51, and 3.6).
+
+               R.  Black  ported  PC  HACK  3.51 to Lattice C and the Atari
+          520/1040ST, producing ST Hack 1.03.
+
+               Mike Stephenson merged these various versions back together,
+          incorporating  many  of  the added features, and produced NetHack
+          1.4.  He then coordinated a cast of thousands  in  enhancing  and
+          debugging  NetHack 1.4 and released NetHack versions 2.2 and 2.3.
+
+               Later, Mike coordinated a major rewrite of the game, heading
+          a team which included Ken Arromdee, Jean-Christophe Collet, Steve
+          Creps, Eric Hendrickson, Izchak Miller, John Rupley, Mike Threep-
+          oint, and Janet Walz, to produce NetHack 3.0c.
+
+               NetHack  3.0  was  ported  to the Atari by Eric R. Smith, to
+          OS/2 by Timo Hakulinen, and to VMS by David Gentzel.   The  three
+          of them and Kevin Darcy later joined the main development team to
+          produce subsequent revisions of 3.0.
+
+               Olaf Seibert ported NetHack 2.3 and 3.0 to the Amiga.   Norm
+          Meluch,  Stephen  Spackman  and Pierre Martineau designed overlay
+          code for PC NetHack 3.0.  Johnny Lee ported NetHack  3.0  to  the
+          Macintosh.   Along with various other Dungeoneers, they continued
+          to enhance the PC, Macintosh, and Amiga ports through  the  later
+          revisions of 3.0.
+
+               Headed  by  Mike Stephenson and coordinated by Izchak Miller
+          and Janet Walz, the development team which now included  Ken  Ar-
+          romdee,  David  Cohrs,  Jean-Christophe Collet, Kevin Darcy, Matt
+          Day, Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin,  Eric
+          Raymond,  and  Eric  Smith  undertook  a radical revision of 3.0.
+          They re-structured the game's design, and re-wrote major parts of
+          the  code.   They added multiple dungeons, a new display, special
+          individual character quests, a new endgame  and  many  other  new
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              52
+
+
+
+          features, and produced NetHack 3.1.
+
+               Ken  Lorber,  Gregg  Wonderly and Greg Olson, with help from
+          Richard Addison, Mike Passaretti,  and  Olaf  Seibert,  developed
+          NetHack 3.1 for the Amiga.
+
+               Norm  Meluch and Kevin Smolkowski, with help from Carl Sche-
+          lin, Stephen Spackman, Steve VanDevender, and Paul Winner, ported
+          NetHack 3.1 to the PC.
+
+               Jon W{tte and Hao-yang Wang, with help from Ross Brown, Mike
+          Engber, David Hairston, Michael Hamel, Jonathan  Handler,  Johnny
+          Lee,  Tim  Lennan, Rob Menke, and Andy Swanson, developed NetHack
+          3.1 for the Macintosh, porting it for MPW.  Building on their de-
+          velopment, Barton House added a Think C port.
+
+               Timo Hakulinen ported NetHack 3.1 to OS/2.  Eric Smith port-
+          ed NetHack 3.1 to the Atari.  Pat Rankin, with help  from  Joshua
+          Delahunty,  was  responsible  for the VMS version of NetHack 3.1.
+          Michael Allison ported NetHack 3.1 to Windows NT.
+
+               Dean Luick, with help from David  Cohrs,  developed  NetHack
+          3.1  for  X11.   Warwick Allison wrote a tiled version of NetHack
+          for the Atari; he later contributed the tiles to the DevTeam  and
+          tile support was then added to other platforms.
+
+               The  3.2 development team, comprised of Michael Allison, Ken
+          Arromdee, David Cohrs, Jessie Collet, Steve Creps,  Kevin  Darcy,
+          Timo  Hakulinen,  Steve  Linhart,  Dean  Luick,  Pat Rankin, Eric
+          Smith, Mike Stephenson, Janet Walz,  and  Paul  Winner,  released
+          version 3.2 in April of 1996.
+
+               Version 3.2 marked the tenth anniversary of the formation of
+          the development team.  In a testament to their dedication to  the
+          game,  all  thirteen members of the original development team re-
+          mained on the team at the start of work on that release.   During
+          the  interval  between  the  release of 3.1.3 and 3.2, one of the
+          founding members of the development team, Dr. Izchak Miller,  was
+          diagnosed  with cancer and passed away.  That release of the game
+          was dedicated to him by the development and porting teams.
+
+               During the lifespan of NetHack 3.1 and 3.2, several enthusi-
+          asts  of  the  game added their own modifications to the game and
+          made these ``variants'' publicly available:
+
+               Tom Proudfoot and Yuval Oren created  NetHack++,  which  was
+          quickly  renamed NetHack--.  Working independently, Stephen White
+          wrote NetHack Plus.  Tom Proudfoot later merged NetHack Plus  and
+          his own NetHack-- to produce SLASH.  Larry Stewart-Zerba and War-
+          wick Allison improved the spell casting system  with  the  Wizard
+          Patch.   Warwick Allison also ported NetHack to use the Qt inter-
+          face.
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              53
+
+
+
+               Warren Cheung combined SLASH with the Wizard Patch  to  pro-
+          duce  Slash'em,  and with the help of Kevin Hugo, added more fea-
+          tures.  Kevin later joined the DevTeam and incorporated the  best
+          of these ideas in NetHack 3.3.
+
+               The final update to 3.2 was the bug fix release 3.2.3, which
+          was released simultaneously with 3.3.0 in December 1999  just  in
+          time for the Year 2000.
+
+               The 3.3 development team, consisting of Michael Allison, Ken
+          Arromdee, David Cohrs, Jessie Collet, Steve Creps,  Kevin  Darcy,
+          Timo  Hakulinen,  Kevin  Hugo,  Steve  Linhart,  Ken Lorber, Dean
+          Luick, Pat Rankin, Eric Smith, Mike Stephenson, Janet  Walz,  and
+          Paul  Winner, released 3.3.0 in December 1999 and 3.3.1 in August
+          of 2000.
+
+               Version 3.3 offered many firsts. It was the first version to
+          separate  race and profession. The Elf class was removed in pref-
+          erence to an elf race, and the races of dwarves, gnomes, and orcs
+          made  their  first  appearance in the game alongside the familiar
+          human race.  Monk and Ranger roles joined Archeologists,  Barbar-
+          ians,   Cavemen,  Healers,  Knights,  Priests,  Rogues,  Samurai,
+          Tourists, Valkyries and of course,  Wizards.   It  was  also  the
+          first  version  to  allow  you to ride a steed, and was the first
+          version to have a publicly available  web-site  listing  all  the
+          bugs  that  had been discovered.  Despite that constantly growing
+          bug list, 3.3 proved stable enough to last for more than  a  year
+          and a half.
+
+               The  3.4 development team initially consisted of Michael Al-
+          lison, Ken Arromdee, David Cohrs, Jessie Collet, Kevin Hugo,  Ken
+          Lorber,  Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and
+          Paul Winner, with  Warwick Allison joining just  before  the  re-
+          lease of NetHack 3.4.0 in March 2002.
+
+               As  with version 3.3, various people contributed to the game
+          as a whole as well as supporting ports on the different platforms
+          that NetHack runs on:
+
+               Pat Rankin maintained 3.4 for VMS.
+
+               Michael  Allison maintained NetHack 3.4 for the MS-DOS plat-
+          form.  Paul Winner and Yitzhak Sapir provided encouragement.
+
+               Dean Luick, Mark Modrall, and Kevin Hugo maintained and  en-
+          hanced the Macintosh port of 3.4.
+
+               Michael  Allison,  David  Cohrs, Alex Kompel, Dion Nicolaas,
+          and Yitzhak Sapir maintained and enhanced 3.4 for  the  Microsoft
+          Windows platform.  Alex Kompel contributed a new graphical inter-
+          face for the Windows port.  Alex Kompel also contributed  a  Win-
+          dows CE port for 3.4.1.
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              54
+
+
+
+               Ron Van Iwaarden maintained 3.4 for OS/2.
+
+               Janne  Salmijarvi  and  Teemu Suikki maintained and enhanced
+          the Amiga port of 3.4 after Janne Salmijarvi resurrected  it  for
+          3.3.1.
+
+               Christian  ``Marvin''  Bressler maintained 3.4 for the Atari
+          after he resurrected it for 3.3.1.
+
+               There is a NetHack web site  maintained  by  Ken  Lorber  at
+          http://www.nethack.org/.
+
+                    - - - - - - - - - -
+
+               From  time  to  time,  some depraved individual out there in
+          netland sends a particularly intriguing modification to help  out
+          with  the  game.   The Gods of the Dungeon sometimes make note of
+          the names of the worst of these miscreants in this, the  list  of
+          Dungeoneers:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
+
+
+          NetHack Guidebook                                              55
+
+
+
+                    Adam Aronow            Izchak Miller         Mike Stephenson
+                    Alex Kompel            J. Ali Harlow           Norm Meluch
+                   Andreas Dorn              Janet Walz            Olaf Seibert
+                    Andy Church           Janne Salmijarvi        Pasi Kallinen
+                   Andy Swanson        Jean-Christophe Collet       Pat Rankin
+                   Ari Huttunen            Jochen Erwied           Paul Winner
+                   Barton House             John Kallen          Pierre Martineau
+                Benson I. Margulies         John Rupley             Ralf Brown
+                     Bill Dyer              John S. Bien            Ray Chason
+                 Boudewijn Waijers           Johnny Lee          Richard Addison
+                     Bruce Cox               Jon W{tte            Richard Beigel
+                  Bruce Holloway          Jonathan Handler      Richard P. Hughey
+                  Bruce Mewborne          Joshua Delahunty          Rob Menke
+                   Carl Schelin            Keizo Yamamoto         Robin Johnson
+                    Chris Russo              Ken Arnold         Roderick Schertler
+                    David Cohrs             Ken Arromdee          Roland McGrath
+                  David Damerell             Ken Lorber          Ron Van Iwaarden
+                   David Gentzel           Ken Washikita          Ronnen Miller
+                  David Hairston            Kevin Darcy             Ross Brown
+                    Dean Luick               Kevin Hugo          Sascha Wostmann
+                     Del Lamb               Kevin Sitze            Scott Bigham
+                   Deron Meranda          Kevin Smolkowski       Scott R. Turner
+                   Dion Nicolaas            Kevin Sweet          Stephen Spackman
+                  Dylan O'Donnell           Lars Huttar           Stephen White
+                    Eric Backus             Malcolm Ryan           Steve Creps
+                 Eric Hendrickson          Mark Gooderum          Steve Linhart
+                   Eric R. Smith            Mark Modrall        Steve VanDevender
+                  Eric S. Raymond         Marvin Bressler          Teemu Suikki
+                   Erik Andersen            Matthew Day             Tim Lennan
+                 Frederick Roeber           Merlyn LeRoy          Timo Hakulinen
+                    Gil Neiger            Michael Allison            Tom Almy
+                    Greg Laskin             Michael Feir             Tom West
+                    Greg Olson             Michael Hamel          Warren Cheung
+                  Gregg Wonderly          Michael Sokolov        Warwick Allison
+                   Hao-yang Wang            Mike Engber           Yitzhak Sapir
+                   Helge Hafting            Mike Gallop
+               Irina Rempt-Drijfhout      Mike Passaretti
+
+          Brand  and  product names are trademarks or registered trademarks
+          of their respective holders.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+          NetHack 3.4                                      December 2, 2003
+
+
+
diff --git a/doc/dgn_comp.6 b/doc/dgn_comp.6
new file mode 100644 (file)
index 0000000..530942e
--- /dev/null
@@ -0,0 +1,402 @@
+.TH DGN_COMP 6 "12 Dec 1995"
+.UC 4
+.SH NAME
+dgn_comp \- NetHack dungeon compiler
+.SH SYNOPSIS
+.B dgn_comp
+[
+.I file
+]
+.PP
+If no arguments are given, it reads standard input.
+.SH DESCRIPTION
+.PP
+.I Dgn_comp
+is a dungeon compiler for NetHack version 3.2 and higher.  It
+takes a description file as an argument and produces a dungeon "script" 
+that is to be loaded by NetHack at runtime.
+.PP
+The purpose of this tool is to provide NetHack administrators and
+implementors with a convenient way to create a custom dungeon for the
+game, without having to recompile the entire world.
+.SH GRAMMAR
+.PP
+DUNGEON: 
+.B name
+.B bonesmarker
+(
+.B base
+,
+.B rand
+) [
+.B %age
+]
+.PP
+where
+.B name
+is the dungeon name,
+.B bonesmarker
+is a letter for marking bones files, (
+.B base
+, 
+.B rand
+) is the number of levels, and
+.B %age
+is its percentage chance of being generated (if absent, 100% chance).
+
+DESCRIPTION:
+.B tag
+.PP
+where
+.B tag
+is currently one of
+.BR HELLISH ,
+.BR MAZELIKE ,
+or
+.BR ROGUELIKE .
+
+ALIGNMENT | LEVALIGN: [
+.B lawful
+|
+.B neutral
+|
+.B chaotic
+|
+.B unaligned
+]
+.PP
+gives the alignment of the dungeon/level (default is unaligned).
+
+ENTRY:
+.B level
+.PP
+the dungeon entry point.  The dungeon connection attaches at this
+level of the given dungeon.
+If the value of
+.B level
+is negative, the entry level is calculated from the bottom of the
+dungeon, with -1 being the last level.
+If this line is not present in a dungeon description, the entry level
+defaults to 1.
+
+PROTOFILE:
+.B name
+.PP
+the prototypical name for dungeon level files in this dungeon.
+For example, the PROTOFILE name for the dungeon
+.I Vlad's Tower
+is
+.IR tower .
+
+LEVEL:
+.B name
+.B bonesmarker
+@ (
+.B base
+,
+.B rand
+) [
+.B %age
+]
+.PP
+where
+.B name
+is the level name,
+.B bonesmarker
+is a letter for marking bones files, (
+.B base
+, 
+.B rand
+) is the location and
+.B %age
+is the generation percentage, as above.
+
+RNDLEVEL:
+.B name
+.B bonesmarker
+@ (
+.B base
+,
+.B rand
+)
+[
+.B %age
+]
+.B rndlevs
+.PP
+where
+.B name
+is the level name,
+.B bonesmarker
+is a letter for marking bones files, (
+.B base
+, 
+.B rand
+) is the location,
+.B %age
+is the generation percentage, as above, and
+.B rndlevs
+is the number of similar levels available to choose from.
+
+CHAINLEVEL:
+.B name
+.B bonesmarker
+.B prev_name
++ (
+.B base
+,
+.B rand
+) [
+.B %age
+]
+.PP
+where
+.B name
+is the level name,
+.B bonesmarker
+is a letter for marking bones files,
+.B prev_name
+is the name of a level defined previously, (
+.B base
+,
+.B rand
+) is the
+.I offset
+from the level being chained from, and
+.B %age
+is the generation percentage.
+
+RNDCHAINLEVEL:
+.B name
+.B bonesmarker
+.B prev_name
++ (
+.B base
+,
+.B rand
+) [
+.B %age
+]
+.B rndlevs
+.PP
+where
+.B name
+is the level name,
+.B bonesmarker
+is a letter for marking bones files,
+.B prev_name
+is the name of a level defined previously, (
+.B base
+,
+.B rand
+) is the
+.I offset
+from the level being chained from,
+.B %age
+is the generation percentage, and
+.B rndlevs
+is the number of similar levels available to choose from.
+
+LEVELDESC:
+.B type
+.PP
+where
+.B type
+is the level type, (see DESCRIPTION, above). The
+.B type
+is used to override any pre-set value used to describe the entire dungeon,
+for this level only.
+
+BRANCH:
+.B name
+@ (
+.B base
+,
+.B rand
+) [
+.B stair
+|
+.B no_up
+|
+.B no_down
+|
+.B portal
+] [
+.B up
+|
+.B down
+]
+.PP
+where
+.B name
+is the name of the dungeon to branch to, and (
+.B base
+,
+.B rand
+) is the location of the branch.
+The last two optional arguments are
+the branch type and branch direction.
+The type of a branch can be a two-way stair connection,
+a one-way stair connection, or a magic portal.
+A one-way stair is described by the types
+.B no_up
+and
+.B no_down
+which specify which stair direction is missing.
+The default branch type is
+.BR stair .
+The direction for a stair can be either up or down; direction is not
+applicable to portals.  The default direction is
+.BR down .
+
+CHAINBRANCH:
+.B name
+.B prev_name
++ (
+.B base
+,
+.B rand
+) [
+.B stair
+|
+.B no_up
+|
+.B no_down
+|
+.B portal
+] [
+.B up
+|
+.B down
+]
+.PP
+where
+.B name
+is the name of the dungeon to branch to,
+.B prev_name
+is the name of a previously defined
+.B level
+and (
+.B base
+,
+.B rand
+) is the
+.I offset
+from the level being chained from.
+The optional branch type and direction are the same as described above.
+.SH GENERIC RULES
+.PP
+Each dungeon must have a unique
+.B bonesmarker ,
+and each special level must have a
+.B bonesmarker
+unique within its dungeon (letters may be reused in different dungeons).
+If the
+.B bonesmarker
+has the special value "none", no bones files will be created for that
+level or dungeon.
+.PP
+The value
+.B base
+may be in the range of 1 to
+.B MAXLEVEL
+(as defined in
+.I global.h
+).
+.PP
+The value
+.B rand
+may be in the range of -1 to
+.BR MAXLEVEL .
+.PP
+If
+.B rand
+is -1 it will be replaced with the value (num_dunlevs(dungeon) - base)
+during the load process (ie. from here to the end of the dungeon).
+.PP
+If
+.B rand
+is 0 the level is located absolutely at
+.BR base .
+.PP
+Branches don't have a probability.  Dungeons do.  If a dungeon fails
+to be generated during load, all its levels and branches are skipped.
+.PP
+No level or branch may be chained from a level with a percentage generation
+probability.  This is to prevent non-resolution during the load.
+In addition, no branch may be made from a dungeon with a percentage
+generation probability for the same reason.
+.PP
+As a general rule using the dungeon compiler:
+.PP
+If a dungeon has a
+.B protofile
+name associated with it
+.RI ( eg.
+.BR tower )
+that file will be used.
+.PP
+If a special level is present, it will override the above rule and
+the appropriate file will be loaded.
+.PP
+If neither of the above are present, the standard generator will
+take over and make a "normal" level.
+.PP
+A level alignment, if present, will override
+the alignment of the dungeon that it exists within.
+.SH EXAMPLE
+.PP
+Here is the current syntax of the dungeon compiler's "language":
+
+.LP
+.nf
+.ta +8n +8n +8n
+#
+#      The dungeon description file for the "standard" original
+#      3.0 NetHack.
+#
+DUNGEON:       "The Dungeons of Doom" "D" (25, 5)
+LEVEL:         "rogue" "none" @ (15, 4)
+LEVEL:         "oracle" "none" @ (5, 7)
+LEVEL:         "bigroom" "B" @ (12, 3) 15
+LEVEL:         "medusa" "none" @ (20, 5)
+CHAINLEVEL:    "castle" "medusa" + (1, 4)
+CHAINBRANCH:   "Hell" "castle" + (0, 0) no_down
+BRANCH:                "The Astral Plane" @ (1, 0) no_down up
+
+DUNGEON:       "Hell" "H" (25, 5)
+DESCRIPTION:   mazelike
+DESCRIPTION:   hellish
+BRANCH:                "Vlad's Tower" @ (13, 5) up
+LEVEL:         "wizard" "none" @ (15, 10)
+LEVEL:         "fakewiz" "A" @ (5, 5)
+LEVEL:         "fakewiz" "B" @ (10, 5)
+LEVEL:         "fakewiz" "C" @ (15, 5)
+LEVEL:         "fakewiz" "D" @ (20, 5)
+LEVEL:         "fakewiz" "E" @ (25, 5)
+
+DUNGEON:       "Vlad's Tower" "T" (3, 0)
+PROTOFILE:     "tower"
+DESCRIPTION:   mazelike
+ENTRY:         -1
+
+DUNGEON:       "The Astral Plane" "A" (1, 0)
+DESCRIPTION:   mazelike
+PROTOFILE:     "endgame"
+.fi
+.PP
+.I NOTES:
+.br
+Lines beginning with '#' are considered comments.
+.br
+A special level must be explicitly aligned.  The alignment of the dungeon
+it is in only applies to non-special levels within that dungeon.
+.SH AUTHOR
+.PP
+M. Stephenson (from the level compiler by Jean-Christophe Collet).
+.SH "SEE ALSO"
+.PP
+lev_comp(6), nethack(6)
+.SH BUGS
+.PP
+Probably infinite.
diff --git a/doc/dgn_comp.txt b/doc/dgn_comp.txt
new file mode 100644 (file)
index 0000000..907a4f0
--- /dev/null
@@ -0,0 +1,330 @@
+
+
+
+DGN_COMP(6)                   1995                    DGN_COMP(6)
+
+
+
+NAME
+     dgn_comp - NetHack dungeon compiler
+
+SYNOPSIS
+     dgn_comp [ file ]
+
+     If no arguments are given, it reads standard input.
+
+DESCRIPTION
+     Dgn_comp is a dungeon compiler for NetHack version  3.2  and
+     higher.  It takes a description file as an argument and pro-
+     duces a dungeon "script" that is to be loaded by NetHack  at
+     runtime.
+
+     The purpose of this tool is to provide  NetHack  administra-
+     tors and implementors with a convenient way to create a cus-
+     tom dungeon for the game, without having  to  recompile  the
+     entire world.
+
+GRAMMAR
+     DUNGEON: name bonesmarker ( base , rand ) [ %age ]
+
+     where name is the dungeon name, bonesmarker is a letter  for
+     marking  bones  files, ( base , rand ) is the number of lev-
+     els, and %age is its percentage chance  of  being  generated
+     (if absent, 100% chance).
+
+     DESCRIPTION: tag
+
+     where tag is currently one of HELLISH, MAZELIKE,  or  ROGUE-
+     LIKE.
+
+     ALIGNMENT |  LEVALIGN:  [  lawful  |  neutral  |  chaotic  |
+     unaligned ]
+
+     gives  the  alignment  of  the  dungeon/level  (default   is
+     unaligned).
+
+     ENTRY: level
+
+     the dungeon entry point.  The dungeon connection attaches at
+     this  level  of the given dungeon.  If the value of level is
+     negative, the entry level is calculated from the  bottom  of
+     the  dungeon, with -1 being the last level.  If this line is
+     not present  in  a  dungeon  description,  the  entry  level
+     defaults to 1.
+
+     PROTOFILE: name
+
+     the prototypical  name  for  dungeon  level  files  in  this
+     dungeon.   For  example,  the PROTOFILE name for the dungeon
+     Vlad's Tower is tower.
+
+
+
+Dec                      Last change: 12                        1
+
+
+
+
+
+
+DGN_COMP(6)                   1995                    DGN_COMP(6)
+
+
+
+     LEVEL: name bonesmarker @ ( base , rand ) [ %age ]
+
+     where name is the level name, bonesmarker is  a  letter  for
+     marking  bones  files,  (  base , rand ) is the location and
+     %age is the generation percentage, as above.
+
+     RNDLEVEL: name bonesmarker @ (  base  ,  rand  )  [  %age  ]
+     rndlevs
+
+     where name is the level name, bonesmarker is  a  letter  for
+     marking  bones  files, ( base , rand ) is the location, %age
+     is the generation percentage, as above, and rndlevs  is  the
+     number of similar levels available to choose from.
+
+     CHAINLEVEL: name bonesmarker prev_name + ( base , rand  )  [
+     %age ]
+
+     where name is the level name, bonesmarker is  a  letter  for
+     marking  bones  files,  prev_name  is  the  name  of a level
+     defined previously, ( base , rand ) is the offset  from  the
+     level being chained from, and %age is the generation percen-
+     tage.
+
+     RNDCHAINLEVEL: name bonesmarker prev_name + ( base , rand  )
+     [ %age ] rndlevs
+
+     where name is the level name, bonesmarker is  a  letter  for
+     marking  bones  files,  prev_name  is  the  name  of a level
+     defined previously, ( base , rand ) is the offset  from  the
+     level being chained from, %age is the generation percentage,
+     and rndlevs is the number of  similar  levels  available  to
+     choose from.
+
+     LEVELDESC: type
+
+     where type is the level type, (see DESCRIPTION, above).  The
+     type  is used to override any pre-set value used to describe
+     the entire dungeon, for this level only.
+
+     BRANCH: name @ ( base , rand ) [ stair | no_up |  no_down  |
+     portal ] [ up | down ]
+
+     where name is the name of the dungeon to branch  to,  and  (
+     base  ,  rand ) is the location of the branch.  The last two
+     optional arguments are the branch type and branch direction.
+     The  type  of  a branch can be a two-way stair connection, a
+     one-way stair connection, or  a  magic  portal.   A  one-way
+     stair  is  described  by  the  types no_up and no_down which
+     specify which  stair  direction  is  missing.   The  default
+     branch  type  is  stair.   The  direction for a stair can be
+     either up or down; direction is not applicable  to  portals.
+     The default direction is down.
+
+
+
+Dec                      Last change: 12                        2
+
+
+
+
+
+
+DGN_COMP(6)                   1995                    DGN_COMP(6)
+
+
+
+     CHAINBRANCH: name prev_name + ( base ,  rand  )  [  stair  |
+     no_up | no_down | portal ] [ up | down ]
+
+     where name  is  the  name  of  the  dungeon  to  branch  to,
+     prev_name  is  the  name of a previously defined level and (
+     base , rand ) is the offset from  the  level  being  chained
+     from.   The  optional branch type and direction are the same
+     as described above.
+
+GENERIC RULES
+     Each dungeon must have a unique bonesmarker , and each  spe-
+     cial level must have a bonesmarker unique within its dungeon
+     (letters may be  reused  in  different  dungeons).   If  the
+     bonesmarker  has  the  special  value "none", no bones files
+     will be created for that level or dungeon.
+
+     The value base may be in the range  of  1  to  MAXLEVEL  (as
+     defined in global.h ).
+
+     The value rand may be in the range of -1 to MAXLEVEL.
+
+     If  rand  is  -1  it  will  be  replaced  with   the   value
+     (num_dunlevs(dungeon)  -  base) during the load process (ie.
+     from here to the end of the dungeon).
+
+     If rand is 0 the level is located absolutely at base.
+
+     Branches don't have  a  probability.   Dungeons  do.   If  a
+     dungeon  fails  to  be generated during load, all its levels
+     and branches are skipped.
+
+     No level or branch may be chained from a level with  a  per-
+     centage  generation  probability.   This  is to prevent non-
+     resolution during the load.  In addition, no branch  may  be
+     made from a dungeon with a percentage generation probability
+     for the same reason.
+
+     As a general rule using the dungeon compiler:
+
+     If a dungeon has a protofile name associated  with  it  (eg.
+     tower) that file will be used.
+
+     If a special level is present, it will  override  the  above
+     rule and the appropriate file will be loaded.
+
+     If neither of the above are present, the standard  generator
+     will take over and make a "normal" level.
+
+     A level alignment, if present, will override  the  alignment
+     of the dungeon that it exists within.
+
+
+
+
+
+Dec                      Last change: 12                        3
+
+
+
+
+
+
+DGN_COMP(6)                   1995                    DGN_COMP(6)
+
+
+
+EXAMPLE
+     Here  is  the  current  syntax  of  the  dungeon  compiler's
+     "language":
+
+
+     #
+     #       The dungeon description file for the "standard" original
+     #       3.0 NetHack.
+     #
+     DUNGEON:        "The Dungeons of Doom" "D" (25, 5)
+     LEVEL:          "rogue" "none" @ (15, 4)
+     LEVEL:          "oracle" "none" @ (5, 7)
+     LEVEL:          "bigroom" "B" @ (12, 3) 15
+     LEVEL:          "medusa" "none" @ (20, 5)
+     CHAINLEVEL:     "castle" "medusa" + (1, 4)
+     CHAINBRANCH:    "Hell" "castle" + (0, 0) no_down
+     BRANCH:         "The Astral Plane" @ (1, 0) no_down up
+
+     DUNGEON:        "Hell" "H" (25, 5)
+     DESCRIPTION:    mazelike
+     DESCRIPTION:    hellish
+     BRANCH:         "Vlad's Tower" @ (13, 5) up
+     LEVEL:          "wizard" "none" @ (15, 10)
+     LEVEL:          "fakewiz" "A" @ (5, 5)
+     LEVEL:          "fakewiz" "B" @ (10, 5)
+     LEVEL:          "fakewiz" "C" @ (15, 5)
+     LEVEL:          "fakewiz" "D" @ (20, 5)
+     LEVEL:          "fakewiz" "E" @ (25, 5)
+
+     DUNGEON:        "Vlad's Tower" "T" (3, 0)
+     PROTOFILE:      "tower"
+     DESCRIPTION:    mazelike
+     ENTRY:          -1
+
+     DUNGEON:        "The Astral Plane" "A" (1, 0)
+     DESCRIPTION:    mazelike
+     PROTOFILE:      "endgame"
+
+     NOTES:
+     Lines beginning with '#' are considered comments.
+     A special level must be explicitly aligned.   The  alignment
+     of  the  dungeon it is in only applies to non-special levels
+     within that dungeon.
+
+AUTHOR
+     M. Stephenson (from the level  compiler  by  Jean-Christophe
+     Collet).
+
+SEE ALSO
+     lev_comp(6), nethack(6)
+
+
+
+
+
+Dec                      Last change: 12                        4
+
+
+
+
+
+
+DGN_COMP(6)                   1995                    DGN_COMP(6)
+
+
+
+BUGS
+     Probably infinite.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dec                      Last change: 12                        5
+
+
+
diff --git a/doc/dlb.6 b/doc/dlb.6
new file mode 100644 (file)
index 0000000..eb018b2
--- /dev/null
+++ b/doc/dlb.6
@@ -0,0 +1,83 @@
+.TH DLB 6 "28 Oct 1993"
+.UC 4
+.SH NAME
+dlb \- NetHack data librarian
+.SH SYNOPSIS
+.B dlb
+{
+.B xct
+}
+[
+.B vfIC
+]
+arguments...
+[
+.B files...
+]
+.SH DESCRIPTION
+.PP
+.I Dlb
+is a file archiving tool in the spirit (and tradition) of tar for
+NetHack version 3.1 and higher.  It is used to maintain the
+archive files from which NetHack reads special level files and other
+read-only information.  Note that like tar the command and option
+specifiers are specified as a continuous string and are followed
+by any arguments required in the same order as the option specifiers.
+.PP
+This facility is optional and may be excluded during NetHack
+configuration.
+.SH COMMANDS
+The
+.B x
+command causes
+.I dlb
+to extract the contents of the archive into the current directory.
+.PP
+The
+.B c
+command causes
+.I dlb
+to create a new archive from files in the current directory.
+.PP
+The
+.B t
+command lists the files in the archive.
+.SH OPTIONS AND ARGUMENTS
+.DT
+.ta \w'f archive\ \ \ 'u
+v      verbose output
+.br
+.sp 1
+f archive      specify the archive.  Default if f not specified is
+LIBFILE (usually the nhdat file in the playground).
+.br
+.sp 1
+I lfile        specify the file containing the list of files to
+put in to or extract from the archive if no files are listed
+on the command line.  Default for archive creation if no files
+are listed is LIBLISTFILE.
+.br
+.sp 1
+C dir  change directory.  Changes directory before trying to
+read any files (including the archive and the lfile).
+.br
+.SH EXAMPLES
+Create the default archive from the default file list:
+.br
+       dlb c
+.sp 1
+List the contents of the archive 'foo':
+.br
+       dlb tf foo
+.SH AUTHOR
+.PP
+Kenneth Lorber
+.SH "SEE ALSO"
+.PP
+nethack(6), tar(1)
+.SH BUGS
+.PP
+Not a good tar emulation; - does not mean stdin or stdout.
+Should include an optional compression facility.
+Not all read-only files for NetHack can be read out of an archive;
+examining the source is the only way to know which files can be. 
diff --git a/doc/dlb.txt b/doc/dlb.txt
new file mode 100644 (file)
index 0000000..afc09c2
--- /dev/null
@@ -0,0 +1,132 @@
+
+
+
+DLB(6)                        1993                         DLB(6)
+
+
+
+NAME
+     dlb - NetHack data librarian
+
+SYNOPSIS
+     dlb { xct } [ vfIC ] arguments...  [ files... ]
+
+DESCRIPTION
+     Dlb is a file archiving tool in the spirit  (and  tradition)
+     of  tar  for  NetHack version 3.1 and higher.  It is used to
+     maintain the archive files from which NetHack reads  special
+     level files and other read-only information.  Note that like
+     tar the command and option specifiers  are  specified  as  a
+     continuous string and are followed by any arguments required
+     in the same order as the option specifiers.
+
+     This facility is optional and may be excluded during NetHack
+     configuration.
+
+COMMANDS
+     The x command causes dlb to  extract  the  contents  of  the
+     archive into the current directory.
+
+     The c command causes dlb to create a new archive from  files
+     in the current directory.
+
+     The t command lists the files in the archive.
+
+OPTIONS AND ARGUMENTS
+     v           verbose output
+
+     f archive   specify the archive.  Default if f not specified
+     is LIBFILE (usually the nhdat file in the playground).
+
+     I lfile     specify the file containing the list of files to
+     put in to or extract from the archive if no files are listed
+     on the command line.  Default for  archive  creation  if  no
+     files are listed is LIBLISTFILE.
+
+     C dir       change directory.  Changes directory before try-
+     ing to read any files (including the archive and the lfile).
+
+EXAMPLES
+     Create the default archive from the default file list:
+                 dlb c
+
+     List the contents of the archive 'foo':
+                 dlb tf foo
+
+AUTHOR
+     Kenneth Lorber
+
+
+
+
+
+Oct                      Last change: 28                        1
+
+
+
+
+
+
+DLB(6)                        1993                         DLB(6)
+
+
+
+SEE ALSO
+     nethack(6), tar(1)
+
+BUGS
+     Not a good tar emulation; - does not mean stdin  or  stdout.
+     Should  include  an  optional compression facility.  Not all
+     read-only files for NetHack can be read out of  an  archive;
+     examining the source is the only way to know which files can
+     be.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Oct                      Last change: 28                        2
+
+
+
diff --git a/doc/fixes22.0 b/doc/fixes22.0
new file mode 100644 (file)
index 0000000..decc0b9
--- /dev/null
@@ -0,0 +1,353 @@
+               NetHack Fixes List      Revision 2.2
+
+Fixes and Modified Features
+---------------------------
+Guidebook.mn   New file "Guide to the Mazes of Menace". By Eric Raymond.
+Guidebook      A file for preparation using the "mn" macros supplied with
+               the 2.11 news release, as well as an ascii version of the
+               same. 
+
+NetHack.cnf    Sample configuration file for the PC. (creps@silver)
+
+Makefiles      Corrected problem in which the linking was done on build and
+(unix/xenix)   on install. (Contributed by Janet Walz - walz@mimsy)
+
+Makefile.att   Added a makefile for the AT&T Unix PC using shared libraries.
+               (Contributed by ahby@umn-cs)
+
+Makefile.pc    Streamlined compilation of main.o, tty.o, and unix.o
+Makefile.tcc   (Contributed by polder@cs.vu.nl).
+
+data.base      deletion of duplicate lines and spelling fixes. (sweet@scubed)
+
+invent.c       REDO problem with "What do you want to..." text fixed.
+               down stairway identification fixed.
+               Alloc "buf" to allow for variable length HI/HE. (tom@uw-warp)
+
+engrave.c      Correction to "feel" code. (mike@genat)
+               Corrected switch for message determination. (patrickm@hpisof0)
+               BURN'ed engravings made un-erasable again. (kyrimis@princeton)
+
+pri.c          Added colour highliting functions (sweet@scubed)
+
+prisym.c       changed "symbol.room" to "ROOM_SYM" (one I missed)
+               (Ralf.Brown@b.gp.cs.cmu.edu)
+               Changed "dirlet()" to return an int. (maartenj@cs.vu.nl)
+
+msdos.c                Changed "symbol" to "showsyms" (Ralf.Brown@b.gp.cs.cmu.edu)
+               Fixed up REDO & IBMBIOS stuff. (Kevin Sweet - sweet@scubed)
+
+do.c           Dropping gold asked for only when gold posessed. (walz@mimsy)
+               Potential unsigned value problem fixed (u.ucreamed)
+               Added leash dropping code. (maartenj@cs.vu.nl)
+               Blind modifications for blindfolding.  (eric@snark)
+               Value wrap fixed for u.ucreamed
+
+fight.c                Dog's name now used in hitting avoidence message. (walz@mimsy)
+               Variable initialization fixed w.r.t. #ifdef / #else.
+               (Reported by Erwin Unruh - unruh@infbs)
+               Added giant rats and kobolds back into code. (sweet@scubed)
+
+spell.c                Potential unsigned value problem fixed (u.ulevel).
+               Typos corrected. (Tom May - tom@uw-warp)
+               Blind modifications for blindfolding.  (eric@snark)
+
+shk.c          "inshop" crash bug corrected (many sources).
+               extern declaration of carrying() moved to avoid a Turbo-C
+               type mismatch msg. (Ralf.Brown@b.gp.cs.cmu.edu)
+               Added new "online()" which executes faster. (tom@uw-warp)
+               Blind modifications for blindfolding.  (eric@snark)
+               Added item pricing shopkeeper talk.
+               (Idea from a hacked up 1.0.1 source sent in by michael@stb)
+               Cleaned up Kops code. (sweet@scubed)
+
+mhitu.c                Argument mismatches fixed. (walz@mimsy)
+               Scorpion/spider mixup fix. (William LeFebvre - phil@rice.edu)
+               Blind modifications for blindfolding.  (eric@snark)
+
+potion.c       Argument mismatch fixed. (walz@mimsy)
+               Blind modifications for blindfolding.  (eric@snark)
+               Poison handling made more dependant on poison resistance.
+               (From an idea by Steve Creps - creps@silver)
+
+mklev.c                Fixed up installation of vamp traps. (sweet@scubed)
+
+makemon.c      Monster creation location bug fixed. (walz@mimsy)
+               Monster creation crash fixed. (many sources)
+               Monster posessions bug fixed. (S. Wrammerfors stewr@obelix)
+               Added giant rats and kobolds back into code. (sweet@scubed)
+
+hack.c         "Elbereth" effectiveness increased under "HARD" option to
+               be reasonable. (walz@mimsy)
+               Declaration of "register struct monst *m_at()" fixed. (many)
+               Typo fixed. (tom@uw-warp)
+               Fixed scroll of scare monster pickup problems (and giveaway)
+               (polder@cs.vu.nl)
+               Documentation modifications for blindfolding.  (eric@snark)
+
+ioctl.c                ioctl call for SET changed to function properly under
+
+unixtty.c      Sys V R3 mods.  (tom@uw-warp)
+
+decl.c         in_doagain initialized. (many sources)
+
+wield.c                Ability to remove cursed weapons w. w- removed. (many sources)
+
+options.c      Major rewrite of options help.  Now uses pager.  (mike@genat)
+               Rewrote GRAPHICS setup. (maartenj@cs.vu.nl)
+               Allowed reassignment of inventory order #ifdef DGK
+               (polder@cs.vu.nl)
+
+pray.c         Fixed mk_obj of spellbook under all conditions to make book
+               if "SPELLS" defined, and scroll otherwise. (unruh@infbs)
+               Fixed typo in "gods angry" text. (tom@uw-warp)
+               Fixed blessing code. (Simon Brown - simon@its63b)
+               Blind modifications for blindfolding.  (eric@snark)
+
+zap.c          Potion of invis. breakage message improved. (unruh@infbs)
+               Added WAN_PROBING to "zapyourself".
+               Changed "dirlet()" to return an int. (maartenj@cs.vu.nl)
+               Fixed cancellation code to work properly on wands (spe
+               set to -1 instead of 0) this means no infinite wands of
+               wishing. (Ron Wessels - ron@utcsri)
+               Fixed bug in "buzz()" causing crash when destroying a
+               trapper from inside with a wand/spell.  (mike@genat)
+               Added fcn to destroy wands with zero charges. (sweet@scubed)
+
+pcmain.c       Added a routine to zero out the fileinfo array in order to
+               prevent crashes on level change. (ralf@b.gp.cs.cmu.edu)
+               Added chdir to HACKDIR before looking for .CNF file.
+               Added call "uptodate(savefile)". (polder@cs.vu.nl)
+
+pager.c                changed "cornline()" to use xputs for HI/HE. (tom@uw-warp)
+               added choice for dowhatis() to allow letter or cursor object
+               selection. (polder@cs.vu.nl)
+
+cmd.c          Added ^W (wish) and ^I (ident-all) commands for WIZARD-mode.
+               (Paul Polderman - polder@cs.vu.nl)
+               Added "Z" as alternate to "# cast" (Eric Raymond - eric@snark)
+
+u_init.c       Expanded a tab which didn't show in raw mode.
+               Changed trobj.trotyp to "unsigned short" to avoid >255
+               problems. (Maarten Jan Huisjes - maartenj@cs.vu.nl)
+               Removed wand of wishing from WIZARD's inventory (due to
+               the above cmd additions). (polder@cs.vu.nl)
+               Fixed declaration of leash. (simon@its63b)
+               Beefed up Wizard class.
+               Added Wakizashi for Samurai.
+               Added holy water for Priest(ess)es.
+               Modifications to provide blindfolds.  (eric@snark)
+
+end.c          changed inventory identification on death to list form.
+               (polder@cs.vu.nl)
+               added hallucination effects to done_in_by()
+               added posession of amulet flag for scoreboard (sweet@scubed)
+
+wizard.c       corrected "nasties" decl. (maartenj@cs.vu.nl)
+               Blind modifications for blindfolding.  (eric@snark)
+
+do_wear.c      Prot. from shape changers logic fixed. (maartenj@cs.vu.nl)
+
+lev.c          Prot. from shape changers logic fixed. (maartenj@cs.vu.nl)
+
+mon.c          Inserted cast to fix compiler warning. (maartenj@cs.vu.nl)
+               Nymphs now leave potions of object detection when killed.
+               Kops now don't leave treasure behind. (sweet@scubed)
+
+topl.c         Changed size of "toplines" to avoid overflow in "parseoptions"
+               when help is asked for. (probably n/a) (maartenj@cs.vu.nl)
+
+topten.c       Added longer death descriptions, including name of
+               shopkeeper who killed character.  (many sources)
+
+termcap.c      Changed allocation of HI/HO for copying SI/SO to allow room
+               for null.  (maartenj@cs.vu.nl)
+               Added PCHack 3.61 termcap stuff.
+               Added colour highliting code. (sweet@scubed)
+
+version.c      Expanded a tab for rawmode io. (maartenj@cs.vu.nl)
+
+objnam.c       Allow the WIZARD to wish for really excessive objects.
+               (polder@cs.vu.nl)
+
+makedefs.c     Added "freopen" which works (MSC 4.0 drops first couple
+               of lines).  Solves missing #define AMULET... problem.
+               (Nathan Glasser - nathan@mit-eddie)
+
+rnd.c          Changed around random number generation:
+               BSD uses "random()". (Paul Eggert - eggert@grand)
+               SYSV uses "lrand48()". (mike@genat from above)
+
+eat.c          Changed "choke()" code to waste food rather than choke on
+               it #ifndef HARD. (Allan Pratt - apratt@atari)
+               Blind modifications for blindfolding.  (eric@snark)
+
+objects.h      added blindfold object (tool).  (eric@snark)
+
+you.h          changed Blind/BLIND to Blinded/Blinded
+               added Blindfolded/BLINDFOLDED
+               redefined Blind in terms of above parameters.  (eric@snark)
+
+apply.c                added blindfold code.  (eric@snark)
+
+timeout.c      Blind modifications for blindfolding.  (eric@snark)
+
+sit.c          Blind modifications for blindfolding.  (eric@snark)
+
+trap.c         Blind modifications for blindfolding.  (eric@snark)
+               Level teleportation to hell fixed so that it will not
+               do so unless character has Fire_resistance. (many sources)
+               Added polymorph trap. (many sources)
+
+monmove.c      added check on presence of "fobj" before atl() call
+               to avoid potential segmentation problem with ROCKMOLE.
+               (Reported by Doug Rudoff - doug@wiley)
+
+various files  Fixed typos.  Also converted British English words to
+               American English for uniformity.  (Original list of typos
+               submitted by Steve Creps - creps@silver)
+
+
+New Features
+------------
+  1)   New flags in "config.h" (some of these were included in 1.4f):
+
+       COM_COMPL       Command line completion by John S. Bien
+       GRAPHICS        Funky screen character support (Eric S. Raymond)
+       HACKOPTIONS     Support DGK-style HACKOPTIONS processing (ESR)
+       RPH             Various hacks by Richard P. Hughey
+       KJSMODS         Various changes made by Kevin Sweet
+       BVH             Additions by Bruce Holloway
+
+       In addition, in an MSDOS enviornment, when GRAPHICS is defined:
+
+       MSDOSCOLOR      Colour highlighting of monsters, etc.
+
+       Of the above, I haven't tested HACKOPTIONS and MSDOSCOLOR.  If you
+       find bugs in these, send me the reports.
+
+  2)   New objects:
+
+       blindfold - allows you to avoid the gaze of a Floating Eye and to
+                   use your telepathy on command if you have it.
+
+       mirror - scares monsters if you use it on them (and other uses).
+
+       ring of polymorph - (usually cursed) forces random polymorphs.
+
+       ring of polymorph control - prevents system shock and allows choice of
+                                   creature to polymorph into.
+
+  3)   New Files:
+
+       - A new set of documentation, the "Guidebook to the Mazes of Menace"
+       has been supplied by Eric S. Raymond.  The guidebook is written for
+       nroff using the "mn" macro set supplied with Bnews 2.11 or greater.
+       Since not everyone has these macros, I have run the guidebook through
+       nroff, and supplied it in flat ascii format as well.  [Moderator's
+       note: because of past problems, I ran the formatted version
+       through "col -b" before passing it on to remove ^H's, etc.  -br]
+
+       - A copy of "HACK.CNF" which has been renamed "NetHack.cnf" was
+       supplied by Steve Creps. The file decl.c has been updated to reflect
+       this change.
+
+       - A new "Makefile" for the AT&T Unix machines has been added.
+
+       - I was hoping to get documentation on "NANSI.SYS" as well, but got
+       no responses to the mail I sent the author, direct and via Bill
+       Randle at tekred.  As per usual, I will gladly publish any relevant
+       documentation I get.
+
+  4)   Major game changes:
+
+       - Shop generation has been significantly changed.  A new structure
+       has been introduced which allows shops (except the "general" type)
+       to have up to three different types of object inside.  There is also
+       a new "distribution pattern" parameter which tells the generation
+       code how to lay out the shop (this is preliminary to the addition of
+       two new types of shop, the temple and barracks - more on this later).
+
+       - Shopkeepers will now tell you how much they expect for each object
+       you pick up.  This gives you the ability to haggle with the merchant
+       in question by dropping and picking up objects until you are more or
+       less satisfied with the price.  I have re-written "getprice()" in
+       shk.c in an attempt to make sure that you cannot actually sell any
+       particular object for more than the shopkeeper will charge for it.
+
+       - Another change to shopkeepers has them potentially getting angry if
+       you stay beside them after not paying your bill.  Each they time they
+       ask you to pay up, there is a chance they will decide they don't like
+       people who don't pay...
+
+       - A new monster, the hydra, has been added (as you have probably seen
+       on the net).  I haven't had much chance to test out this feature of
+       the game.  Mirrors have also been added, and seem to work quite well.
+
+       - Changes have been made to the object ocurrence chances in objects.h,
+       so that the relatively rare tools, etc. have at least a 1% chance of
+       showing up.
+
+       - Throwing and zapping code has been modified so that there is a
+       chance that said can be done through a doorway.  Bolts can still
+       bounce however...
+
+       - The infamous and dreaded makemon() bug has been eliminated.  In
+       addition to this, "r"ats and "K"obolds have been added back into the
+       game.  "K"ops no longer leave treasure (just what they were carrying,
+       plus maybe a club or whistle).
+
+       - Two new "super"swords have been added.  They are the katana named
+       "Snickersnee" which is +5 on damage (due to sharpness), and the long
+       sword "Excalibur" which is +rnd(10) to hit, +5 on damage, and has a
+       couple of other features I won't go into right now.  The only way
+       for a character to get "Excalibur" is as a gift from someone.  You
+       cannot write the word "Excalibur" on things for some reason...
+
+       - There have been two additions to disallow infinite wand charges.
+       First of all, wands with less than zero charges will automatically
+       turn to dust (thanks to Kevin Sweet).  Next, a wand of cancellation
+       will set the number of charges in the wand to -1, which will make it
+       forever useless, (thanks to Ron Wessels).
+
+  5)   Minor game changes:
+
+       - The fountain code has been tightened slightly so you can no longer
+       dip objects into a fountain or drink from one while you are floating
+       in mid-air due to levitation.
+
+       - Teleporting to hell via a teleportation trap will no longer occur
+       if the character does not have fire resistance.  I found this just
+       too arbitrary a way to die (and so did several other people who com-
+       plained about it).
+
+       - A new trap, the "polymorph" trap has been added by Richard Hughey.
+       It's inclusion is dependant on having "KAA" defined.
+
+       - In wizard mode, the wizard player has infinite wishes, and the
+       ability to instantly identify everything (s)he is carrying. The wizard
+       player is also no longer limited by the standard multiple / bonus res-
+       trictions on objects wished for.
+
+       - Random number generation has been changed around to make it (I hope)
+       more unpredictable.
+
+       - A large number of typos have been fixed, and all of the British
+       spellings converted to American.  I would like to see a shell script
+       to allow conversion back (or something like that) in the future.
+
+       - I have done a "make depend" for the makefiles to reflect a slight
+       restructuring in the order of inclusion of header files.
+
+  6)   Future additions:
+
+       - Steve Creps is working on "barracks" and "soldier" code which is
+       now ready for addition.  I have added the "soldier" side into the
+       game, but haven't really tested it.  Steve will be adding the
+       "barracks" section in and sending me the resulting patches.  There
+       will be a minor (read patch) release as soon as he can get the code
+       integrated into this release and sent up here to me.
+
+       - There are also several other new room projects in the works which
+       should be able to be included in that minor release, along with any
+       bug reports that are made in the interim.
diff --git a/doc/fixes30.0 b/doc/fixes30.0
new file mode 100644 (file)
index 0000000..737d504
--- /dev/null
@@ -0,0 +1,164 @@
+$RCSfile: fixes30.0,v $ $Revision: 1.1.2.2 $ $Date: 2003/05/11 15:10:00 $
+
+[This is a partial list supplied by Ken Arromdee long after the fact]
+
+General Fixes and Modified Features
+-----------------------------------
+dropping a weapon, then picking it up while blind causes it to become 
+       unidentified but it remains that way after your vision returns
+when blind and feeling the floor, the objects then on the floor should
+       have their characteristics become unknown
+zapping a wand of probing at yourself works, however using a stethoscope
+       on yourself does not
+trolls that come back to life don't retain their names
+if you look at what is on the ground and there is more than a screenful,
+       quantities are not printed (i.e. "food rations")
+if pickup was off and you moved onto a spot with both engraving and objects,
+       you got told what the engraving was twice
+if a Keystone Kop threw a pie and the pie hit a shopkeeper, the shopkeeper
+       became angry
+"two handed sword" is spelled with and without a hyphen in various places
+trying to descend stairs while levitating gives a message where "You're"
+       is misspelled as "Your"
+the 'V' command gives a history that is not quite correct; it wasn't 
+       Ken Arromdee that merged PC Hack and Unix Hack; rather, PC Hack 
+       was derived from Unix Hack by Don Kneller.  It was (I think) 
+       Mike Stephenson who merged the many Hack versions.
+the uranium wand gets described as "an" uranium wand
+potions which have been both called and identified have the called instead
+       of the identified name printed out
+status line at the bottom of the screen is formatted strangely for the
+       first 10 moves; after 10 moves it becomes normal
+if you polymorph yourself into a rockmole, you are unable to dig through
+       rock
+a stethoscope or wand of probing, used on a monster, printed out a format
+       with spaces in it (such as %-3d instead of %d) causing such messages
+       to be longer than necessary
+the number printed out for damage by stethoscope or wand of probing is 
+       completely incorrect
+sometimes your dog would turn into a bat (retaining the same name and 
+       tameness) when saving and restoring,going down and back up
+       and in bones levels
+ghosts on bones levels are replaced by little dogs
+if you are polymorphed and drink a potion of healing which raises your
+       maximum monster hit points, your current hit points only are raised, so
+       you may have (for instance) 37 out of 36 hit points
+when you pick up something from a shop, the message is something like
+       "For you, kind sir, only 5 for this <garbage>" on systems where
+       pointer is not the same size as integer
+removing a leash from a dog produces garbage, and also can sometimes
+       crash the game
+when the Wizard is mentioned, you get garbage
+if you tame a wild dog, and then try to hit it, the safe-attack routine
+       says "You stop to avoid hitting .", or sometimes garbage
+when you are invisible but can see invisible, drinking at a fountain which
+       dries up causes your symbol to be erased from the screen.
+pushing an enormous rock onto a teleport trap deletes it instead of 
+       teleporting it
+sometimes returning to human form from a polymorph would leave you with 
+       only 1 current hit point left
+sometimes polymorphing would leave you with an 18/** strength
+if you used a stethoscope on a wall and a creature moved into the revealed
+       door before you did, when creature moved off, the door was replaced
+       by a wall symbol again, until you walked through it
+playing a game with fountain symbols set to one character, and restoring it
+       using a configuration file having them set to a different character,
+       leaves the fountain symbols as the old character
+problem with food poisoning and blindness where you could end up permanently 
+       blind, not even reversible by healing etc.
+you could not wish for a C-ration or K-ration due to lowercase conversion
+zapping a wand of death at yourself, and the death touch of a demon
+       prince, killed you even if you were polymorphed into an undead,
+       but bouncing death rays didn't
+if you threw an object in a shop, it landed on the floor still unpaid
+       zapping a wand of cancellation at yourself turned all your objects to
+       -1 instead of +0; -1 was only needed for wands (since cancelling wands 
+       to +0 allowed a sneaky way of getting infinite wishes)
+#remove command is incorrectly described as removing a cursed
+       object, but it actually removes only iron balls
+at least some messages given for special abilities when you are polymorphed
+       printed out the monster type even if you were blind
+wishing for a scroll of mail, with MAIL undefined, is permitted but
+       reading the scroll gave an "impossible" error message; change it to
+       read: "This seems to be junk mail directed to the finder of the Eye 
+       of Larn."
+if you were blind, effects of scrolls, et al, still said things such as
+       "Your mace glows green for a moment," "Your left ring glows white"
+the message "The xan pricks your ___ leg" still mentions the type of
+       monster (xan) when you are blind
+polymorphing could change your gender, but when the game ended you were 
+       still described as a "Cave-man" or "Priest" instead of 
+       "Cave-woman" or "Priestess"
+if you got rocks by using a pick-axe on an enormous rock, the rocks 
+       started out blessed
+if you escaped from a shop by throwing your iron ball to the exit, the ball
+       would stay unpaid
+any object thrown in a shop stayed unpaid, and you had to
+       pick the object up again and then drop it for it to become paid
+if you were invisible but could see invisible, when you drank from a fountain
+       that dried up, your symbol got erased from the screen
+several times colors were mentioned (i.e. black glows when you pray too much)
+       but the colors weren't always changed for hallucination
+if punished and your chain and 1 other object is on the floor, you
+       get asked if you want to pick up a specific type of object, 
+       and the chain is given as one of the possible objects
+if you polymorph into a "new man", your energy points never change
+trolls, when killed, can leave bodies or objects, but they should
+       always leave bodies so they can regenerate back to life, 
+       whether or not they left objects
+demon prince demanding bribe gets randomly relocated instead of being placed 
+       next to you
+if you polymorph another tool into a magic marker, the marker always starts
+       out dried out
+hallucination has the problem that if you do something which takes no time,
+       the monsters still change
+if you tried drinking at a fountain while levitating, you got asked if you 
+       wanted to drink, and then you weren't allowed to do it, and 
+       the fountain could still dry up
+if you were fire resistant and a magic trap produced a tower of flame, you 
+       also get a second message (a shiver...)
+when restoring a game, if there was an error, your saved game still vanishd
+       for some errors
+pets were always referred to as "him" in the leash code
+stethoscope in the up or down direction while swallowed referred to "floor" 
+       and "ceiling" instead of to the monster that swallowed you
+if you could not save a game, the screen cleared and you were told to 
+       "Continue or Quit", but if you typed C, the game thought you just 
+       gave it a Call command
+you could get told "that spellbook was a mimic" even if mimic was on a wall
+if you were turning to stone and you polymorphed yourself into a 'c', you 
+       still died from the stoning
+if you interrupted the program before it finished loading a saved game,
+       you were asked if you want your possessions identified
+"ctmp" was mistakenly used in MHITU.C when being hit by a rust monster
+       rusting your helmet but it should have been "!mtmp->mcan"
+
+
+Platform- and/or Interface-Specific Fixes
+-----------------------------------------
+PC: often the same character class, and same player name, will end up
+       getting 2 scores on the high score list
+PC: if your name contained a period and you were playing on a PC, you would
+        have problems saving games since your save-file name still contained
+        2 periods and would thus be illegal; change periods to underscores 
+       when figuring out what the save file should be called
+PC: if you polymorphed into a "new man", and changed your name, when you saved
+       your game the game was still saved under a filename derived from your
+       old name, and to restore that game you had to specify your old name
+
+General New Features
+--------------------
+when polymorphed into a giant you are now able to pick up and
+       throw rocks by giving infinite carrying capacity
+give the Healer a pair of gloves (the most logical piece of armor
+       for a physician to start out with)
+give the Healer a lot of money to start with (doctors are supposedly
+       rich, you see)
+have the Healer start out with the healing, cure blindness spells 
+       already known
+create a "trial mode", similar to Wizard Mode where you get a wand of wishing
+       with charges and you can't get on the high score list
+if you are standing on a trapdoor and you type a '>' symbol,
+       print "You jump down the hole." and go down to the next level
+
+
diff --git a/doc/fixes31.1 b/doc/fixes31.1
new file mode 100644 (file)
index 0000000..402166f
--- /dev/null
@@ -0,0 +1,110 @@
+Makefile.utl vs. GNU make (*_lex.o needs explicit *_lex.c dependency)
+defining MAKE in more makefiles (symptom is "sh: makedefs: not found")
+finding test in makefiles (needs shell meta-char, >/dev/null or || exit 1)
+splitter hunk sizes with SAS 6.x (wouldn't fit on floppy)
+
+OpenWindows 2.x documentation (?)
+',' and ';' in help files, including Guidebook
+Guidebook date (nroff and pre-processed versions)
+VMS options syntax (config file description omitted "OPTIONS=" requirement)
+
+phase of moon for Mac and MSDOS ports -- revert to old, portable phase of
+       moon code
+polymorphing into bees (divide by zero core dump, reported as 
+       floating point error on Sparcs)
+monster throwing boulder into pool could free object twice
+candle burn-out accessing free'd object while traversing list (Mac core dump)
+inappropriate candle merging (lit with unlit)
+several levelflags (fountains, etc.) not being handled on special levels
+subrooms[] not initialized
+coredump on messed DEFAULT_WIN_SYS
+deleting lock.0 files on early quit
+number_pad/mouse coexistence
+jumping onto doors or boulders
+tombstone gold neglected gold in containers, although score was correct
+initial gold record neglected gold in containers
+reeling monsters leaving ghosts (missing newsym)
+display getobj prompt for non-REDO
+packorder option parsing
+inconsisent option parsing with IBM vs. IBMg, etc.
+throwing Mjollnir at adjacent hard things causes panic/core dump
+throwing at ghosts in walls left objects stuck in walls
+throwing unpaid objects in shops (donated to player by shk)
+Shopkeeper administration out of order (buying group of used up items)
+pricing chains, uball, or other nocharge objects, when they couldn't be sold
+knocking uball down a hole by dropping another object caused crash
+kicking monsters while levitating (core dump if monster "reels" or killed)
+kicking empty space while levitating could give free move (recoil)
+panic when nurse is fixing your damage and disappears
+core dump 'D'ropping everything with gold but no inventory (null pointer access)
+core dump using getpos() "move to feature" response when map shows something
+       covering furniture (displayed glyph leads to invalid subscript use)
+deity gender reference in opening legacy message
+makeplural() said "poisoned yas" instead of "poisoned ya"
+zapping on entry to water left trails
+allow level teleports to be cancelled
+excess choking when eating corpses
+funny death message (or coredump) when you choke on a tin of spinach
+       after partially eating something else
+Magicbane expulsion confused cutworm()
+charging for several overlooked items (mainly magical instruments)
+taming a sticking monster (e.g mimic) wouldn't set you free
+panic when tinning while standing on stairs with a full pack and object drops
+zapping down into ice with wand of digging (core dump)
+rust monsters wouldn't ever hurt armor, even non-rustproof armor.  conversely,
+       unrustable things rusted.
+mysterious rust damage on damp levels (improper object chain traversal
+       when any item landed in pool after being thrown or dropped)
+very eroded nonrustable/corrodable/flammable objects displayed as "very +0..."
+map window wasn't being initialized correctly, causing some 'a'filled screens
+using magic marker with full pack leaves you with an item in the '#' slot
+spellbook merging caused multiple books to fade away when you re-read
+       them enough times
+Master of Thieves in Tourist quest not created with Bell of Opening, making
+       game virtually un-winnable
+could wish for quest items
+If an eel managed to drown you, it would say "Drowned by a drowning"
+stop making bones from non-branch portal levels
+reading blank scrolls exercised wisdom
+inverted use of crystal ball "vision in unclear" feedback message
+special room entry messages (shop welcome) given before level change map update
+limbless blobs like gelatinous cubes could not pick up
+The level compiler missed first level flag if more than one was specified.
+The level compiler accumulated level flags when compiling multiple files.
+make the 32-bit monster flags fields unsigned long rather than just long
+mksobj() created gold a factor of 10 too light
+indefinite articles in quest text
+Alt-n didn't execute #name on some ports, made Alt-? do #?
+correct tense and grammar of various messages
+obsolete oracle about using mirror to locate Wizard & Medusa removed
+Nurses would zap you with wands, et al, instead of healing you
+Shopkeepers residence was sometimes wrong on bones level, esp. in the minetown
+Some zaps, esp. by monsters, at the map edge could cause core dumps
+panic relmon bug possible when #turn'ing multiple monsters at once
+it wasn't possible to get underwater when polymorphed to a swimmer
+total digestion wasn't working
+lycanthropy could change sex
+interrupting dosinkring() allowed free ring identification
+killing some hostile humans (like Croesus and priests) lost telepathy, etc.
+
+tty specific: long input lines and improved interrupt handling
+X11: NetHack.ad: "*map*grey" should be "*map*gray"
+X11: NetHack.ad: remove excess quotes
+HPs and X (SYSV conflict caused by X11 headers)
+Handle WM_DELETE_WINDOW protocol in X11 window-port.
+X11 popups are now positioned so that the cursor is bottom center.
+Both X11 fonts now have a pool symbol that coveres the whole rectangle.
+X11_getlin will now allow empty strings to be returned.
+X11: implement score in the status window.
+X11: make displaying experience optional.
+X11: position getline and yn popups center,bottom instead of center,center.
+X11: autofocus mode made more reliable at program startup
+X11: number of objects removed from containers could wrap negative
+X11: allow translation tables
+X11: initial window would "sweep" shut and reopen
+micros: save and restore progress reports weren't appearing during save
+       and restore (they would appear immediately afterwards)
+       also error messages from dots aimed off right edge of screen
+Atari: colors were not properly set in medium resolution
+Atari: terminal size was set incorrectly after a ^Z
+OS/2: HPFS support was incomplete
diff --git a/doc/fixes31.2 b/doc/fixes31.2
new file mode 100644 (file)
index 0000000..8a790f4
--- /dev/null
@@ -0,0 +1,92 @@
+revived barbarians didn't gain levels from potions
+pets wouldn't keep their armor or weapons (blessed figurine of Archon)
+avoid "rot" v. "burn" damage for organics
+identify +/- known rings/armor as "uncursed"
+loop through identification as long as additional "charges" are available
+successive disease attacks made you less sick, also make nurses cure sickness
+NO_MAILREADER non-mail daemon message fix
+make fortune cookies, pancakes yellow and lightning white
+cavemen were red while cavewomen and all other characters were "domestic"
+monsters might not change color when growing up
+redisplay cancelled objects in case their color changed (potions, spellbooks)
+ask if you want to play heard passtune
+add: make ^T intrinsic teleports use magical energy
+don't encase the Amulet (or invocation tools) inside cockatrice induced statues
+fix eating taking 1 turn less than number necessary, cheating you of nutrition
+fix inventory to avoid % in user-supplied names [pline(xprname())]
+fix crash when #force destroys unpaid chest in shop
+fix crash when movement reaches edge of screen on rogue level
+fix crash when two items in a row vanish from magic bag
+set bknown when Priests see item, fixing missing checks elsewhere
+set alignment of priest's quest artifact to match priest's starting alignment
+if the Mitre of Holiness gets stolen by the Wizard, reset int & wis stats
+always unlock quest stairs whenever leader acknowledges quest completion
+make mysterious force which locks quest stairs block objects as well as player
+duplicate shopkeeper names were possible on town level
+trying to rename shopkeepers left dangling pointers
+credit balance can prevent Kop summoning when player leaves shop suddenly
+suppress several shopkeeper messages (and buy|sell) is shk is asleep|paralyzed
+using charged objects ((engrave) wands, horns of plenty, etc.) in shops was free
+don't double bill for food eaten off shop floor (multi-turn to eat only)
+fix to prevent unpaid objects differing only in price from merging (only in
+       inventory; they're not "unpaid" any more when dropped, so might merge)
+missing #ifdef SOUNDS in vault.c
+inconsistent MFLOPPY/MICRO use of dotcnt for saving
+add: wands of striking break potions
+add: directional healing spells
+add: pickup_types option, pickup -> autopickup
+disclosure option takes optional string value; killed counts and genocide list
+give better message when trying to set options which are compiled out
+add: hungry pets make begging noises
+centaurs and mariliths could wear inappropriate armor
+remove Medusa's tail and give her wings
+separate creatures that don't breathe from creatures that can breathe water
+you can't choke if you don't breathe
+Fort Knox eels were placed outside moat
+jellies for Juiblex, not Jabberwocks
+don't heal while praying, so that gods are more likely to heal you
+fix fireballs burning fire resistant players
+floating eyes could paralyze monsters indefinitely
+fix monster sleep/wakeup induced my musical instruments
+players hit by wands of sleep get chance to wake up when attacked by monster
+iron balls keep their "very heavy" weight
+fix vorpal blade/long worm misses
+allow monsters to kill players with vorpal blade and tsurugi
+fix objects falling through trapdoors; "shipping destination"'s overloaded use
+       of obj coordinates could cause bogus screen update attempt (y >= ROWNO)
+prevent bad argument to rnl() from prayer_done() when praying in gehennom
+display message when boulder is pushed into pit
+avoid monsters deciding displaced or invisible characters were off the screen
+kicking embedded objects loose would break fobj chain (-> freeobj() panic)
+when using the cursor to look at remote objects, if the target object is
+       embedded in something, mention that fact
+dropping gold inside a monster -> freeobj() panic
+gold picked up by pets wasn't in mgold and thus didn't show up on probing
+fix "stop *opening* the lock" even when you were locking it
+succubus stealing ring of adornment caused crash if she already had one
+monsters created by monster reading create monster didn't appear for scroll ID
+monsters explicitly casting spells of sleep or cold had messages reversed
+elf character could get impossible("snow boots not found?") stepping onto ice
+accept gray/grey except for spellbooks
+keep monsters from teleporting on no-teleport levels
+don't allow digging of trapdoors on the three wizard levels
+don't allow digging down (including drum of earthquake) to destroy portals
+fix digging down from within walls and solid rock; monsters could enter
+       the resulting trapdoor/pit, but players couldn't
+fix digging down while flying; don't fall through
+destroy any engraving if a hole is dug down thru it, or ice it's in gets melted
+change many hardcoded "floor"s and a few "ground"s to use actual surface type
+fix blessed unicorn horn's restore ability feature (strength gain when weak)
+underwater: prevent turbulence from placing character inside solid wall
+underwater: suppress "you inhale water" message when removing amulet of
+       magical breathing if you're polymorphed into a swimmer or nonbreather
+when using the 'A' command to take off armor from underneath other armor,
+       account for time needed to take off and put back on outer garment(s)
+don't create doors over pits and trap doors when using a wand of locking
+fix mapping when you drop objects while following the guard out of a vault
+
+X11: some status didn't show up after restore
+UNIX: fix potential security hole accessing file through NETHACKOPTIONS setuid
+VMS: disable installed privileges when assigning i/o channel to terminal,
+       opening termcap, or accessing user-specified config file
+Amiga: invalid showscore and numberpad options inserted by frontend
diff --git a/doc/fixes31.3 b/doc/fixes31.3
new file mode 100644 (file)
index 0000000..c700d51
--- /dev/null
@@ -0,0 +1,22 @@
+avoid divide by zero crash for eggs produced from horn of plenty
+prevent monsters from eating the invocation tools or Rider corpses
+make artifacts much less likely to be destroyed
+fix freezing lava in front a raised drawbridge
+fix digging pits in front of raised drawbridge; improve digging next to pools
+since random teleports have no --More-- prompt, have them purge REDO data
+       to avoid repeating previous command before noticing changed context
+make magic portals function for monsters
+make numerous priest blessings increasingly rare, with an upper limit
+fix missing quotation marks in quest speech
+prevent monsters like killer bees from opening tins
+add: keep track of # player deaths, save game start time in struct u
+don't used "uncursed" with gold in containers in ending inventory display
+
+PC: Fix black/gray/white display problem
+
+X11: set input text portion of the dialog box so it is the width of the box
+X11: fix message window seperator redraw problem (thanks to
+     Ivan D. Brawley <ivanbraw@ist.flinders.edu.au>)
+VMS: avoid false "trickery" detection for bonesX#.##;1 levels
+VMS: prevent display of really long broadcast messages from clobbering stack
+VMS: prevent endless input loop upon remote terminal disconnect
diff --git a/doc/fixes32.0 b/doc/fixes32.0
new file mode 100644 (file)
index 0000000..d811b7b
--- /dev/null
@@ -0,0 +1,344 @@
+protect the Amulet and invocation tools from being destroyed when a
+       disintegrated monster's inventory gets deleted
+prevent the Amulet and invocation tools from being buried, similar to box
+       behavior (Book of the Dead would rot away as paper when buried)
+don't let polymorphed players eat any of the invocation tools
+pets are no longer highlighted when hallucinating
+keep glass gems from shattering in chests
+return errors from dgn_comp and lev_comp when called for
+fix hallucinated fruit juice message
+fix several monsters conveying inappropriate resistances
+fix misspellings of "Assassins' Guild" and "Minion of Huhetotl"
+set personal name flag for Pelias and Thoth Amon; clear it for Chromatic Dragon
+don't say "Picking the lock..." when using a skeleton key
+give feedback when applying key to current location but no boxes are present
+can't manipulate floor locks (chests) while levitating
+don't crash onto sink if permanently levitating due to eating a ring
+avoid resuming interrupted lock operation on chest that's been polymorphed
+wide-angle disintegration Beams O' Wrath disintegrate non-resistant
+       shields and armor
+don't access zapped wand after it's been destroyed by divine lightning bolt
+separate graphics symbols for each trap, differently-colored traps
+allow wishes for greased objects, correct wishes for "poisoned
+       rustproof" objects
+damage was calculated incorrectly when hitting with statues and boulders
+allow digging to finish when digging statues embedded in undiggable walls
+list identified invocation tools as "the item" instead of "a item"
+ignore rknown for unerodable objects when determining if it's fully identified
+flush output after eating mimic so '$' appears right away
+update botl for spell power after ^T or #invoke of "energy boost" artifact
+correct hunger check when casting spells
+correct various messages
+fix deliberately jumping into Stronghold trap doors
+make random level changes while escaping with Amulet more equitable
+when mysterious force randomly picks a location on the current level, send
+       player into Wizard's tower if and only if already inside that tower
+any level change from one tower level to another preserves occupancy state
+mysterious force won't kick in when using portal to go up into Wizard's tower
+avoid "bad cursor position" situation when mystery force or cursed gain
+       level potion causes level change within the Wizard's tower
+don't allow the Wizard to be resurrected on the Astral level
+only list "likely" objects when prompting for what to #invoke
+reset encumbrance and movement rate during successful prayer, in case it
+       cures lycanthropy
+prevent cursed weapon that slips when thrown by monster from embedding in stone
+ki-rin is not humanoid
+all elves can see invisible
+gain intrinisics from eating amulets
+lose divine protection by killing co-aligned priests or converting alignment
+have quest leader check for absolute alignment as well as for piousness
+fix tombstone message when dying from kicking door while levitating
+bite, &c. attacks on displaced images said "swings wildly and misses"
+calculate score before creating bones, otherwise gold in bags gets overlooked
+Unique monsters no longer placed in bones files
+for blessed genocide, don't report failure for other classes' quest monsters
+could get both compressed and uncompressed explore mode save files
+ZEROCOMP's bwrite ignored possibility of write failure
+mimics imitating fruit caused "Bad fruit #0" on help commands
+fix off by one bug in level teleport trap destination for monsters
+if g.cube eats a non-empty container, engulf contents rather than devour them
+allow wizard to use blessed genocide of '*' to wipe out all monsters on level
+when digging a hole in ice, don't describe it as digging in the "floor"
+       and unearth any objects buried there even when it refills with water
+when digging in a pit trap which ends up filling with water instead of
+       becoming trap door, remove the trap; likewise for overflowing fountains
+can't dig pits under drawbridge portcullis; break bridge if hole would be made
+can't dig while caught in a web
+don't "swing your pick-axe through thin air" if target location is a web
+mark webs as seen when "monster is caught in a web" message is given
+whirly monsters pass through webs; some huge monsters tear them
+Sting cuts through webs
+have shk use plural if called for when referring to player's pick-axe(s)
+fix price stated by shk when picking up container holding merged items
+fix price stated by shk for #chat when standing on a container
+don't adjust food price due to hunger when player is selling, only when buying
+don't double bill shop corpses turned into tins
+don't make mundane objects known when they're outside the shk's expertise
+change to have shks possibly identify items sold for credit just like for cash
+when player sells something to broke shk for credit, don't offer more for it
+       in credit than will be charged for it if player buys the item back
+when selling items in shop, don't try to adjust message/prompt based on COLNO
+when dying in shop entrance, make sure inventory in bones data is placed all
+       the way inside the shop, hence owned by the shk
+make shk notice when shop door destroyed by wand or spell or digging downward
+reset unpaid objects if shk poly'd into jumpy monster teleports out of shop
+fix handling for shop objects kicked or thrown from one shop into another
+       and for shop objects hit by cancellation beam
+add potions of oil; lamps can be refilled with them
+dipping rusty weapons in potions of oil removes rust
+allowing drinking from surrounding water if you are underwater
+fix non-merging potions of water due to water damage's incompatible dilution
+fix mon-merging scrolls of blank paper due to SCR_SCARE_MONSTER's spe usage
+fix D(ropping) subset of wielded darts,&c (worn mask got out of synch)
+fix #adjust merging wielded darts,&c into non-wielded ones
+allow #adjust when fixinv option disabled
+fix getobj's '?' help displaying one item when fixinv option disabled
+don't give characters with maxed out luck complete immunity to water damage
+don't allow AC -17 or better to provide invulnerability to zap attacks
+kicking cockatrices while barefooted will stone you
+change to inhibit displacement from operating through solid walls
+fix mblinded assignment for monsters hit by potion fumes
+give runesword same damage adjustments as broadsword
+extra verbosity for attacks caused by Stormbringer
+allow ghosts to step on garlic
+don't let vampires step on altars
+don't let monsters jump into polymorph traps covered by boulders, unless
+       they can carry such, pass through, or squeeze under
+giants polymorphed into something else must drop any boulders being carried
+giants in pits become untrapped if a boulder is pushed in
+prevent traps from being generated on ladders
+don't "detect trigger hidden in soil" for previously detected land mine
+exploding and crashing doors wake up nearby monsters
+factor rings of increase damage into kicking damage
+handle omitted case for ball movement that would leave chain in odd position
+returning to stairs on top row of map is valid (fixes rogue quest bug)
+avoid giving "sad feeling" message for pet if lifesaving prevents its death
+don't rot away Rider's corpse if something is standing on it at revival time
+kill any engulfer (including poly'd player) trying to digest a Rider
+give Riders non-zero nutritional value so tinning kit doesn't ignore them
+save & restore u.usick_cause properly
+an eating pet can continue & finish eating while you're off its level
+fix object names: "a Dark One corpse", "statue of a Wizard of Yendor"
+killer_format: poisoned "by Pestilence", not "by a Pestilence"; ditto Juiblex
+killer prefix might be wrong after having been life-saved
+fix to avoid "invisible invisible {Priest|Minion of Whoever}" on tombstone
+fix bug with cold-resistant monsters attacking jellies (etc.)
+fix possible panics when restoring while swallowed or held
+when taming, make holder/swallower let go even if it just becomes peaceful
+reset area of visibility when hurtling backwards from recoil while levitating
+don't let hostile monsters who follow up/down stairs share final ascension
+add bodypart(HAIR) to correct some inappropriate messages
+display monsters inventory (if any) when mon zapped with wand of probing
+display inventory of encased items in statues zapped with wand of probing
+display inventory of buried items below, by zapping wand of probing downwards
+set dknown bit for all objects hit by probing beam
+add ceiling function to alter the ceiling messages appropriately
+fix 3.1.2's fix for reseting certain class-specific artifact properties
+add selection menus to pickup and some apply functions
+pre-menu container interface:  don't let "%a" select all objects if no food
+       is present; make user's "<missing class(es)> a" become "A" instead
+wake up monsters hit by potions thrown by other monsters
+suppress vault hint messages if player is in the vault
+make lev_comp check full object and monster names ([ring of] "protection" in
+       objects[] was matching "protection from shape changers" in .des file)
+guarantee that stairs down from Juiblex swamp level always get created
+       [sometimes got impossible("couldn't place lregion type 0")]
+prevent a three room level which has the stairs to the mines from also having
+       a special room [so that those stairs can't end up placed in a shop]
+allow quest nemeses and other invocation tool guardians to wield artifacts
+Mitre of Holiness is not a weapon
+don't give "heat and smoke are gone" message when entering Vlad's tower if
+       arriving from somewhere other than Gehennom (portal via W's quest arti)
+when a wielded cockatrice corpse rots away, set `unweapon' so that
+       further combat will elicit "bashing with gloved hands" message
+fix behaviour of wielded eggs (breaking, stoning, etc)
+tiny chance for "queen bee" eggs, rather than always killer bee eggs
+change Tourist quest home base to Ankh-Morpork
+prevent activated statue traps from creating hidden monsters
+handle activated statue being the only object poly'd player is hiding under
+prevent reference to unseen underwater object when hiding monster attacks
+don't pluralize name when smelling opened tin of unique monster's meat
+make tins of unique monster's meat be empty in bones file
+don't leave a corpse in bones file if killed by disintegration breath
+don't leave a corpse when monsters disintegrate other monsters
+any food could be tinned (yielding giant ant meat) when corpse in inventory
+destroy all boulders in invocation area when creating stairs down to sanctum
+boulders landing on previously seen trapdoors will plug them instead of
+       falling through or settling on top
+boulders on ice which gets melted will fill pool as if dropped
+don't let dead or sleeping priests give temple greetings
+chatting wakes up sleeping priests
+don't exercise wisdom when making prediscovered objects known during init
+don't generate any generic giants (mummy/zombie placeholder) on castle level
+pets and g.cubes will polymorph if they eat chameleon corpses
+slippery ice (temporary fumbling) only lasts until the next move
+avoid leash limbo if quest leader ejects you while leashed pet's not adjacent
+       (ditto other unconventional level changes, like W's quest artifact)
+release attached leash if poly'd player eats it
+crash fix:  handle other forms of monster-induced level change besides quest
+       ejection (swallower expels onto portal, level teleporter, trap door)
+fix magic mapping of previously mapped maze walls dug away out of view
+assorted drawbridge fixes (kill credit, auto-pickup, drown survival handling)
+passtune becomes fully known once successfully played
+wiping out engravings leaves partial letters
+wipe random letters of trap engravings ("ad aerarium", "Vlad was here")
+eating wolfsbane while in werecritter form rehumanizes in addition to purifying
+don't penalize player (shop charges in general; bad luck for mirror) when
+       a monster breaks something with a wand of striking
+when loading bones, keep track of unique monsters to avoid their duplication
+don't allow a demon prince to summon two copies of a unique demon lord
+enlightenment luck display ("extra", "reduced") did not agree with actual luck
+avoid duplicate spellbooks in character's initial inventory (affects priest)
+fix pets moving reluctantly onto cursed objects
+can't #loot while overtaxed
+time passes when items disappear on use of a cursed bag of holding
+#offer cannot convert or destroy an unaligned altar
+MUSEr's reflecting shield or amulet shouldn't become known when not seen
+fix check for wearing shield when monsters wield two-handed weapons
+don't restrict MUSE scimitar usage to strong monsters
+make dwarves less eager to switch back and forth between weapon and pick-axe
+clip swallow display at left & right map borders
+prevent recoil [hurtle() while levitating] when caught in a trap
+downward zap which freezes water or lava shouldn't bounce back up
+Vorpal Blade: don't let damage penalty (very low strength, negatively charged
+       ring of increase damage) prevent beheaded monster from dying
+make sure player polymorphed into jabberwock is vulnerable to beheading
+make sure that when "The fiery blade burns the shade!" that it actually does
+       damage (double-damage for non-silver must do at least 1hp damage)
+prevent divide by zero crash when hitting tame shade with non-silver weapon
+don't lose alignment when throwing gems to/at peaceful unicorns
+don't apply grease to worn armor if it's covered by other armor
+fix unnaming monsters via `C <space(s)>'
+fix calling object types via `#name n <anything w/ trailing space(s)>'
+fix off by one problem when shuffling some descriptions (scroll label "KIRJE"
+       and "thick" spellbook never used; breathing amulet always "octagonal")
+exploding land mines can scatter or destroy objects at the trap location
+add rolling boulder traps
+try harder to make monster hit point and level gain avoid anomalous losses
+reduce odds of undead corpses on castle level and priest quest home level,
+       to make it harder to lure wraiths to more favorable spot
+can't polymorph large piles of rocks into gems
+hit point gain from nurse healing throttled substantially
+make cursed bells be much less effective as instruments of abuse
+fully implement object charges for Bell of Opening
+allow '%' as destination on rogue level when specifying position by map feature
+fire traps can burn up scrolls and spellbooks on the floor
+fix inverted cancellation check for AD_SLOW and AD_DREN damage
+bullwhips can be applied to disarm monsters and hero
+bullwhips can be applied by hero to haul themself out of a pit
+ensure that thrown potions hit their mark if you are swallowed
+attempting to engrave on an altar causes altar_wrath
+differentiate between a hole and a trapdoor, digging always makes a hole
+check the right hit point values when polymorphed and encumbered
+improve guard behaviour in vaults when player is blind
+prevent dwarves from digging while wielding cursed weapons
+displacing a pet mimic unhides it
+'(' shows the proper tools as in use
+improve shk's handling of pick-axe damage and taming
+aging of items in ice boxes left in bones files
+fix genocide of '@' while polymorphed
+add gender to some unique monsters
+disallow digging down while phasing through non-diggable walls
+general fixes to various message sequencing problems
+prevent shopkeeper names from showing up while you are hallucinating
+prevent paralyzed pets from picking up items
+jellies for Juiblex, not Jabberwocks (done properly this time)
+rust monsters can't eat rustproofed objects
+general fixes to inventory merging of items
+monster inventory undergoes merging too; potentially affects probing and theft
+monsters ignore items they want to pick up that are on 'Elbereth'
+bows wielded by monsters now do proper (low) damage
+even nymphs may not pick up rider corpses
+treat cockatrice corpses in multiple item piles the same as one item piles
+"PACKORDER" feedback incorrect on parsing failure
+you can no longer choke on liquid
+stethoscope on secret doors displays properly when blind
+monster-hurled potions no longer produce quaff messages (or djinn)
+giant eels now hide with mundetected, not invisibility
+eels on the plane of water don't hide and aren't negatively impacted by being
+       out of water
+don't give the big point bonus for eels if player is wearing breathing amulet
+fix display bug (newsym after Wait! message)
+temple priests now wear their cloaks
+Orcus is no longer peaceful (had been made so by bad bribery check)
+'uskin' save and restore done properly
+don't improperly adjust int & wis for stolen non-worn P quest artifact
+don't allow Vorpal Blade to behead a monster when it swallowed you
+golems are not living and don't "die" in messages
+fix "Rocky solidifies.  Now it's Rocky!"
+polymorphing into a flesh golem, which gets petrified by turning into a stone
+       golem, now works when stoned
+correct "killed by a died"
+allow the Wizard to come back and harass at his next reincarnation time even
+       if he's been left alive on some other level (fixes "paralysis" cheat)
+make monsters subject to "mysterious force" in Gehnnom while climbing stairs
+       with the Amulet, so that once the Wizard has stolen it, his retreat
+       when wounded doesn't become an easy way to carry it up
+changing attributes immediately checks encumber messages
+confused monsters get confused SCR_TELEPORTATION effects
+fixed "choked on eating too rich a meal"
+kicked objects won't stop at stairs if they don't fall
+general fixes to stealing from monster carrying cockatrice corpse
+a nymph who polymorphs herself while you're frozen during a multi-turn armor
+       theft can't complete the theft if transformed into non-stealer monster
+consistent corpse probability no matter what killed monster (also removes a
+       loophole allowing permanent rider death)
+MUSE monsters no longer wield weapon same as (not better than) current one
+incubi/succubi have hands, not claws
+make #jump be ineffective on air and water levels
+allow multiple sickness causes; vomiting only cures those involving food
+#prayer reward: give books for not-yet-known spells preference to known ones
+marker use no longer uses wishing interface, fixing several obscure bugs
+archeologists' and rogues' initial sack starts out empty
+candelabra "has now" 7 candles fixed.
+kicked objects would set dknown when the kick caused an injury, even though
+       safely kicked objects wouldn't
+make cloaks subject to burning
+make exposed shirts subject to burning and rotting; greased ones defend
+       against wrap attacks
+all types of fire damage affect worn armor [adds explosions, fire traps, and
+       zapping yourself to previously handled zap/breath attacks by monsters]
+for explosions, destroy carried objects before killing player [affects bones]
+replace triggered land mine with pit before doing damage [bones]
+black dragon breath no longer referred to as "death" instead of disintegration
+don't make ring of gain strength known when gauntlets of power mask its effect
+can't have "slippery minor currents" or similar silly nohands body parts
+proper support for polymorphed players using wrap attacks
+cannibalism reduces luck as well as causing aggravation
+picking up an item which will merge works even when all 52 slots in use
+moving through diagonal openings checks how much you're carrying, not how much
+       free space you have left
+monsters have same restrictions as players moving through diagonal openings
+picking up subset of heavy group works for picking one and gets feedback right
+taking subset of heavy merged group out of containers works the same as
+       picking up subset of heavy merged group from floor
+when putting gold into containers, don't count its weight twice, thereby
+       messing up the status line's encumbrance feedback
+fix the option parser's handling of attempting to negate string values
+teleporting a monster on a trap with a magic whistle sets the trap off
+iron ball dragging no longer confuses autopickup
+cumulative temporary intrinsic increments can't spill over into permanent bits
+eating food shouldn't give messages for intermediate states
+don't make wand of death become known after casting finger of death at yourself
+ignore case when checking artifacts against wish- or #name-specified name
+ignore confusion when reading scrolls of mail
+exploding runes for spellbook read failure doesn't imply that book explodes
+divine rescue from strangling destroys worn amulet of strangulation
+boulders pushed on level teleporters will level teleport; also, make one random
+       level teleport function to keep all level teleports consistent
+
+MSDOS: add fake mail daemon
+MSDOS: add VGA tiles to tty port
+VMS: switch to lint-free, non-GPL'd termcap support code
+X11: map behind popup edges was occasionally not refreshed
+X11: allow permanent inventory window
+X11: when using tiles, highlight pets with "heart" overlay (should be changed
+       to honor the `hilite_pet' run-time option)
+X11: click-in-message-windows crash fixed
+tty: fix panic when freeing endwin
+tty: fix <ctrl/P> behavior when recalled text needs to wrap beyond top line
+tty: allow selection from single line "help menu" (getobj's '?' response)
+tty: don't format data.base with hardcoded tabs that are ugly on non-tty ports
+tty: get rid of extra NHW_MENU space (improperly added when the menu was longer
+       than the screen)
+tty: fix repeated "who are you?" prompting at game startup
diff --git a/doc/fixes32.1 b/doc/fixes32.1
new file mode 100644 (file)
index 0000000..f30afef
--- /dev/null
@@ -0,0 +1,133 @@
+General Fixes and Modified Features
+-----------------------------------
+give invocation message when teleporting onto invocation position
+flying players with water breathing may retrieve things from water
+remove message inconsistently assuming players can be mindless
+monsters wear best armor (not first armor) and may switch armors
+god doesn't give "strayed" message when your god is angry but a different god
+       is the one giving the message
+divine wrath can hit engulfer if you are swallowed
+plug minor topten and oracle memory leaks
+monster throwing must allow for 0 damage (cream pies, non-silver vs. shades)
+break drawbridge if wand of striking is zapped down at open bridge or either
+       up or down at its portcullis
+wand of striking zapped at ceiling might cause a rock to drop (like digging)
+wand of striking hitting a secret door with expose and break it
+zapping {teleportation,cancellation,make invisible,polymorph} down affects
+       any existing engraving similarly to writing with such wands
+monsters may use fire horns and frost horns
+Guidebook.mn now formats backslashes correctly when using GNU groff tools
+Add missing trident case to weapon type categorization.
+Fix weapon proficiency handling for missiles.
+accept "armour" spelling again for marker use (when writing was disconnected
+       from wishing, this got lost)
+restrict writing scrolls and books by description
+give better feedback for some writing results
+whirly/wall-passing monsters should not be immune to falling rocks
+relearn spellbook even when spell already known (object amnesia fix)
+objects that have been called something but not ID'd are subject to amnesia
+ask what to call unknown spellbook which crumbles to dust when mis-read
+bullwhip only tries to get you out of a pit when you're in a pit
+humanoids, gnomes, and ogres now eat; fungi and jellies don't
+centaurs, giants, and various others can respond to #chat
+potion of paralysis doesn't inherit prior nomovemsg
+#naming a nameable artifact when the object already had a name of the same
+       length didn't create an artifact
+applying unID'd potion of oil is possible even not carrying any other items
+       eligible to be applied
+make potion of oil become known after lighting it via apply
+fix remaining inconsistency which allowed diluted water
+don't let breaking a wand of digging on castle level produce holes, just pits
+make Nazgul's sleep gas actually put victims temporarily to sleep
+applying a carried, unlocked, trapped chest will set off the trap
+explosion due to #untrap failure on trapped door destroys it
+shouldn't hear curse/bless status of unseen scroll being read by monster
+give some variation in the amount of time it takes a corpse to rot away
+breakable objects hitting the ceiling or the hero's head will now break
+undead turning now gives credit to player for destroyed monsters
+undead turning now brings dead eggs back to hatchable status
+code added to support hatching of all eggs in a merged group of eggs
+fix display updating at egg's former location when floor egg hatches
+fix learning of egg type for hatched eggs
+statue traps created with monster inventory inside them
+probing shows contents of everything with contents, not just statues
+spells of healing and extra healing don't make target monster angry
+use cornuthaum cancellation factor
+can't kick underwater objects from land or vice versa
+objects falling through holes/trapdoors to random destinations obey arrival
+       restrictions imposed by special levels
+being bare-handed counts as wrong projector when throwing projectiles
+reduce the range that Mjollnir can be thrown
+keep Medusa from continuing to move after she's been killed by reflection
+       of her own gaze (fixes relmon panic)
+medusa's reflected gaze won't affect it if it has amulet/shield of reflection
+eating amulet of strangulation can choke when not satiated; also not gluttony
+intelligent pets hold onto one pick-axe and one unicorn horn
+keep exploding boulders from land mines from hitting you with "a rocks"
+objects carried by migrating monsters have no location
+more robust parsing of user-supplied option names; trailing characters matter
+don't generate spellbooks inside statues of tiny monsters
+treat Medusa level statues as petrified monsters (can't be stone-resistant,
+       and have inventory)
+Medusa doesn't gaze more than once per round
+data.base: eliminate duplication of Orcrist/goblin king entry
+handle luck conferring artifacts correctly (both inventory and enlightenment)
+prevent arming land mines and bear traps in various inappropriate locations
+prevent easy shop exit by having shopkeeper disarm and pick up trap objects
+oilskin cloaks allow defender to slip away from grabbing attacker
+make reading the cursed Book of the Dead riskier
+enchanting stat-affecting armor now identifies it
+fix crash caused by specifying "pickup_types" without a value in config file
+       or NETHACKOPTIONS (avoid attempt to use menu prior to interface init)
+kicking at empty lit corridor with lit_corridor enabled doesn't redraw as unlit
+when starting out with an oil lamp, make pre-discovered potions of oil show up
+       in the discoveries list so that their varying description is available
+being crowned Hand of Elbereth enables minimal longsword proficiency even when
+       Excalibur isn't bestowed
+bare-handed and martial arts weapon skill rankings use names instead of numbers
+
+
+Platform- and/or Interface-Specific Fixes
+-----------------------------------------
+tty: reduce alloc/free activity done for message history
+tty: windowtype:unsupported_value pauses between listing allowed value(s)
+       and proceding under default interface
+X11: free allocated memory during pre-exit cleanup
+X11: display help when DLB is enabled
+X11: fix popup inventory window shown for 'i' response to "what type of
+       object?" prompt with menustyle={T,C}
+DLB: avoid excessive fseek calls (major performance hit for MSDOS)
+MFLOPPY: wasn't safe to enter endgame!  traps, timers, and other level-
+       specific data ended up being inherited from level 1
+MSDOS: now can re-enter game after chdir'ing in shell from "!"
+MSDOS: fix it so -H allows starting a healer game, rather than usage statement
+MSDOS: display cursor during input prompts, not just when in the map
+MSDOS: fix several cursor-related glitches when moving the display
+MSDOS: prevent the use of F3,F4, and F5 before the map window is ready
+MSDOS: make flags.BIOS and flags.rawio the default when VGA tiles are used
+TERMINFO: colors were wrong for some systems, such as Linux
+Amiga: count substitute tiles properly
+MAC: avoid MW 68K struct copy optimization bug (in all developer releases up
+       to and including DR9) by adjusting our structures so it doesn't
+       occur
+MAC: fix crash when trying to drag scrollbar
+MAC: add UPP setup for UserItem FrameItem()
+MAC: boost partitions to 2M minimum
+
+
+General New Features
+--------------------
+#qualifications command eliminated; subsumed into #enhance
+OEXTRA temporary compile-time option
+menu support for group accelerators to choose objects by class
+lev_comp supports specification of percentage chance for monsters and objects
+wielding Sunsword provides protection from light-induced blindness
+interactive setting of options via menu (Per Liboriussen, liborius@daimi.aau.dk)
+
+
+Platform- and/or Interface-Specific New Features
+------------------------------------------------
+MSDOS: Add support for preloading all tiles in protected mode environments
+MSDOS: Add support and initial tty Makefile for yet another compiler (Symantec)
+BeOS: preliminary support for new BeBox platform; initially tty only
+
diff --git a/doc/fixes32.2 b/doc/fixes32.2
new file mode 100644 (file)
index 0000000..ad79094
--- /dev/null
@@ -0,0 +1,128 @@
+General Fixes and Modified Features
+-----------------------------------
+make `recover' work with the additional element of version info added in 3.2.1
+floating eyes cannot escape down stairs and ladders
+do not use body_part() inappropriately when snatching monster's weapon
+fix feedback for a confused long worm attacking itself
+avoid converting locked secret door into closed+locked normal door;
+       doors should be flagged as either locked or closed but not both
+kicking a locked secret door mustn't yield an open normal door
+fixes for dipping weapons into potions of oil
+fix crash triggered when knocking off worn blindfold by applying cursed towel
+update screen display for vault guard picking up gold from fake corridor
+Chromatic Dragon was missing appropriate resistances for orange (sleep) and
+       yellow (acid + stoning) dragons
+when triggering a chest trap, clear the trap flag immediately [bones fodder]
+when a boulder gets pushed into a pit where a monster is trapped, immediately
+       redisplay the monster after giving messages
+rings of hunger dropped in sinks should have an effect even if player is blind
+player #offering a cockatrice corpse must pass a touch check
+hitting a rust monster with a pick-axe, iron ball, or chain will trigger rust
+       damage to the weapon; ditto for rust traps when wielding such items
+cosmetic martial arts and bare-handed changes to skill arrays in u_init.c
+gain or lose weapon skill slots appropriately when polymorph into new person
+fix crash occuring when self-hit by uncaught boomerang
+when delivering a pline message during level change, don't display areas of
+       the new level using line-of-sight data from the old one
+heavy iron balls may be thrown multiple spaces (presumably they roll),
+       restoring old ball behavior
+get rid of "non-null minvent despite MM_NOINVENT" warning
+prevent a negative damage adjustment from boosting a target monster's HP
+give "bashing" message when first attacking something with unconventional
+       wielded items besides just throwing weapons and non-weapon tools
+when restoring, reset weapon so that "bashing" message can be given again
+hole traps in bones data shouldn't be marked as unseen
+when carrying 52 items, don't check shop goods for mergability with invent
+       because it will give false matches, yielding non-gold in slot '#'
+kicking a cockatrice corpse is now as dangerous as kicking a live cockatrice
+fix set_apparxy() crash when the Wizard returns via migrating monster list
+monster wearing armor is protected from disintegration breath like player
+monster wearing amulet of life saving survives disintegration breath
+greased helmets will block AD_DRIN attacks
+get rid of ancient check for welded weapons, which arbitrarily named or didn't
+       name the weapon for no particular reason.
+levitation: sitting makes you tumble, kicking requires bracing
+empty bag of tricks won't cause bag of holding to explode
+prevent "force bolt" from hitting false match on *orc* data.base entry
+prevent "{wand,scroll,spellbook} of light" from matching "* light" entry
+non-confused genocide of player should not kill by "genocidal confusion"
+re-word message for monster grasping already-wielded unicorn horn
+fix various killer reasons
+when pushing boulders, make sure current is always top object at its location
+always clear unpaid items off shop bill when shk is teleported away, even
+       if shk was already angry
+don't let broken wand of digging create traps at locations which already
+       have traps (prevent it from turning a hole into a pit)
+don't give messages about unseen objects falling down holes
+fix to prevent kicked objects which stop on holes/downstairs from becoming
+       unattached from any object list
+don't let flying creatures set off a rolling boulder trap
+fix to prevent seeing into a room by kicking an undiscovered locked secret 
+       door from outside
+account for case of monster throwing gem at PC unicorn
+schedule repair for shop door smashed by big monster
+update status line for energy used when "you fail to cast the spell correctly"
+polymorphed character will mimic gold after eating mimic corpse
+fix relmon panic when bashing weak undead with wielded potion of holy water
+holy and unholy water can trigger transformation in werecritters
+call update_inventory() when discovering or undiscovering (call " ") an object
+fix goto_level panic: if quest leader seals portal, delete portal trap from
+       quest home level as well as from main dungeon's branch level [possible
+       return to quest via 'W' quest artifact]
+prefix quest leader and/or nemesis name with "the" when appropriate at
+       run-time rather than using hard-coded text in quest.txt
+fix endgame crash caused by string overflow when formatting priest|minion names
+dokick.c compiles when WEAPON_SKILLS is disabled
+burning objects go out when kicked
+monsters with arms but not legs (salamander, marilith) can't kick
+knights can't jump while poly'd into anything without legs
+try harder to get names for corpses of unique monsters right
+very high dexterity doesn't guarantee a hit for thrown potions and eggs
+blinding ammo thrown from inside an engulfer can't blind it
+monsters going through endgame portals arrive in same area as the player
+       instead of ending up at the portal to the next level
+treat most of the moat on fakewiz levels as outside the special central
+       area, so that falling or wading into the water and auto-teleporting
+       out of it can't strand the character inside the room
+monsters created by animating a named figurine will inherit that name
+prevent possible player-controlled creation of unique monsters via tossing
+       statues of such onto statue trap locations
+activating a statue trap with wand or pick-axe won't discard statue contents
+cursed non-weapons can't slip when thrown, as it was in 3.1.x
+don't reveal patron deity of high priests with the 'C' command's prompt
+two flags structures now, flags and iflags, the latter not saved with the game
+object name prefix buffer wasn't big enough for biggest possible case
+negatively enchanted weapons thrown by monsters could do negative damage
+prevent xorns from phazing through walls on astral level
+live Wizard won't teleport to your level if he's carrying the Amulet
+can't use 'C' to give the Wizard a name
+fix charging for shop goods broken via striking/force bolt
+prevent disintegration breath from destroying Famine and Pestilence
+       and from triggering impossible("monster with zero hp?") for Death
+prevent attached ball and/or chain from becoming part of iron golem formed
+       during polypiling (ball & chain movement later accessed freed memory,
+      which either crashed or got "remove_object: obj not on floor" panic)
+
+
+Platform- and/or Interface-Specific Fixes
+-----------------------------------------
+Mac: update `mrecover'
+Mac: handle `-@' character name suffix for explicitly requesting random role
+msdos: suppress tiles on rogue level when restoring games that were saved there
+tty: support group accelerators for PICK_ONE menus
+tty: after <ctrl/P> at a yn() prompt, don't blindly accept the character
+       used to get back to the prompt as the yn() result [could trigger
+       impossible("invalid sell response")]
+Unix+tty: guard against <curses.h> problems with delay_output,TRUE/FALSE macros
+X11: fix group accelerators and support them for PICK_ONE menus
+X11: implement tty-style counts for menu selections
+X11: proper pop-up placement with old-style window managers (eg X11R6 twm)
+
+
+General New Features
+--------------------
+
+
+Platform- and/or Interface-Specific New Features
+------------------------------------------------
+
diff --git a/doc/fixes32.3 b/doc/fixes32.3
new file mode 100644 (file)
index 0000000..9a33655
--- /dev/null
@@ -0,0 +1,30 @@
+General Fixes and Modified Features
+-----------------------------------
+Y2K fix: use 4 digit year values for the dates in the score file
+updated COPYRIGHT_BANNER_A to reflect year of release
+prevent "late" pline calls from triggering a crash when the RIP window was
+       displayed at end of game (observed when bones file rename failure
+       under Win95 was reported to wizard mode users)
+being punished on the Plane of Water doesn't trigger a panic when air bubbles
+       try to move the ball&chain or you around
+avoid rn2(0) divide by 0 for empty inventory when trying to crawl out of water
+don't let randomly placed monsters on special levels prevent explicitly
+       placed monsters who target that location from being created (a web
+       trap's spider resulted in no quest nemesis)
+don't let randomly placed stairs on special levels be covered by explicitly
+       placed features such as fountains
+pager: guard against '%' in output from being treated as a printf formatting
+       directive (using '/' or ';' to look at food yields "% blah blah")
+prayer result of ``escape from solid rock'' isn't inhibited by teleport
+       restrictions (attempting to fix all troubles got stuck in a loop)
+report "file empty?" rather than "version mismatch" when that's the reason
+       why a data file fails its validation check
+drum of earthquake can't destroy the high altars
+
+
+Platform- and/or Interface-Specific Fixes
+-----------------------------------------
+micro (assorted): readmail()--don't show fake mail text when blind; also,
+       update the "report bugs to" message to specify <nethack-bugs@nethack.org>
+msdos: fix missing $(INCL) in dependency in djgpp Makefile
+mac: Will only dispatch events if the window system is initialized
diff --git a/doc/fixes33.0 b/doc/fixes33.0
new file mode 100644 (file)
index 0000000..119de07
--- /dev/null
@@ -0,0 +1,372 @@
+General Fixes and Modified Features
+-----------------------------------
+objects falling down a level don't cause everything at destination to scatter
+randomize visible trap glyphs during hallucination
+don't match statue entry when looking up statue trap [after trap detection]
+do match statue entry when looking up "statue of a <foo>" when foo happens
+       to precede statue in the database; likewise for figurines
+initialize random number generator before processing user configuration file
+       (random role selection always selected tourist)
+support "character:X" and "role:X" in NETHACKOPTIONS as well as in config file
+allow colon as an alternative to equals sign for `OPTIONS:whatever' and
+       equals sign as an alternative to colon for `pickup_types=?!="$'
+make rndexp (blessed gain level) be safe for 16 bit integer configurations
+don't add player's weapon proficiency bonus for weapon attacks by monsters
+create quest artifact crystal balls with 5 charges instead of 0
+store ghost names in the same manner as other monster names (fix pet bug)
+boost kobold shaman level to 2 (was 1, too low to ever cast a spell)
+boost ogre king level to 9 (was 7, same as ogre lord)
+throwing quest artifact to quest leader won't cause anger; also, artifact
+       will be caught and thrown back instead of being explicitly ignored
+boost level of fake players in endgame to match their rank titles
+don't lose odd hit points (integer division truncation) when splitting HP
+       for cloned monsters
+update status line when cloning yourself halves your hit points
+suppress clone's initial inventory for poly'd player just as for monsters
+update the documention describing the O command
+polyself: immediately update vision when reverting to human from eyeless form
+use right pronoun when a mind flayer's attack is blocked by a monster's helmet
+tins of lizard meat are never rotten, just like the corresponding corpses
+tattered capes should not match ape entry in database
+booze should not match ooze entry in database
+lowered drawbridge should not match werecritter entry
+lengthen option file line length to 4*BUFSZ
+make zaps of death at polymorphed players work properly
+change way invisibility works, add remembered invis monsters and 'F' command
+don't list pick-axe and unicorn horn as likely candidates for charging
+give more accurate message when nymph steals multi-turn armor from female char
+fix splitting merged group of wielded weapons for menu mode version of #loot
+if a buried container rots away, bury rather than destroy any contents
+the 'W'ear command now only shows armor you can actually wear at this instant,
+       instead of all armor you're not currently wearing
+wishing for a genocided monster egg gets a dead egg, not a generic egg
+"Unfortunately it is still genocided" printed only if monster is in range
+       (particularly important for lifesaved monster genocided off-level).
+message for monster growing into genocided monster only printed if in range
+include number of attached candles when formatting candelabrum's name
+support attaching already lit candles to candelabrum
+range of candlelight varies with number of candles
+dropping ring of hunger onto sink won't falsely claim that undestroyed objects
+       like the Amulet have vanished
+winged gargoyle can't wear body armor
+self probing and stethoscope display speed with same detail as enlightenment
+throwing attacks can trigger reprisals similar to hand-to-hand and zap attacks
+'A' now works in dropping like when picking up
+make setting bear traps and land mines be a multi-turn occupation
+make lava be properly lit on special levels
+add orig.female flag to handle E quest monster situation
+clean up inconsistent quest text
+in initial legacy message, use "goddess" when appropriate
+allow FIRSTNEMESIS message to actually be printed
+taking a peaceful monster's weapon with applied bullwhip will anger victim
+applying an unpaid magic lamp will charge a low lighting fee instead of the
+       djinni release fee
+teleporting a Rider will usually bring it near you instead of sending it away
+Riders can open locked doors without a key, just like the Wizard
+Riders, angels, and elves won't avoid stepping on Elbereth/scare monster when
+       deciding where to walk
+Riders and angels will ignore the sanctuary effect of temples
+mind flayers cannot suck out brains by hitting long worm tails
+don't ignore object age when #offering a partially eaten corpse
+inability to pick up is not as general as nolimbs (blobs may pick up with
+       pseudopods and purple worms by swallowing)
+wishing for a magic lamp produces an oil lamp, not a no-charges, possibly lit,
+       magic lamp
+blobs may not ooze under doors if their inventory can't be squeezed through
+peaceful/tame monsters will not use bullwhips on the player
+ghosts were not inheriting player gender in bones files
+cannot wish for tins of untinnable (due to insubstantiality) monsters
+flying monsters cannot fall down stairs
+prevent divine retribution from destroying a wand which is being broken
+fix resuming to read a spellbook which has become blank since the prior read
+       attempt got interrupted
+make recharging cancelled wands behave like recharging other cancelled objects
+prevent "late" pline calls from triggering a crash when the RIP window was
+       displayed at end of game (observed when bones file rename failure
+       under Win95 was reported to wizard mode users)
+cannot shatter soft weapons (whips, rubber hoses)
+being punished on the Plane of Water doesn't trigger a panic when air bubbles
+       try to move the ball&chain or you around
+seen-invisible monsters are consistently visible but transparent, rather
+       than looking like normal monsters
+kicked object message for hitting another object no longer claims it "stops"
+kicked object hits objects (plural) if quan>1 but there is nothing else there
+kicking an object which is embedded in a closed door behaves like one in rock
+can't kick object out of a known pit, but could when pit hadn't been seen yet
+pets, shopkeepers, unique monsters, trolls, and Riders retain
+       their characteristics when killed and brought back to life
+being polymorphed into a black light makes you hallucination resistant
+don't attempt to perform panic save if the game is already over
+don't leave old game's timers, light sources, and shop data in place if
+       aborted restore attempt reverts to starting new game [eventual panic]
+Magicbane carried by mplayers has a lower enchantment than other artifacts
+if pets take longer to untame than to starve, make them go wild anyway
+split up erosion to allow both rust and acid (or fire and rot)
+rust/fire/corrosion/rot now work in all cases (monster/monster, monster/you)
+upon arrival to quest, mark return portal as seen
+can't be blinded by light while asleep
+can't put boulders or big statues into containers
+engulfers which engulf a pile engulf 'several objects'
+polyself: use right set of hit points for hunger and strength loss
+polyself: likewise when checking for troubles during prayer
+polyself: stop mimicking gold immediately if shape change occurs
+polyself: change monster type when sex change occurs for succubus or incubus
+Y2K fix: use 4 digit year values for the dates in the score file
+when changing levels, update the screen to show the new level sooner
+when changing levels, a monster might displace you from the stairs upon arrival
+petrify polymorphed player who has protected hands but is using a non-hand
+       attack on a cockatrice
+fix bug where barehanded AT_WEAP by polymorphed player on cockatrice worked
+prevent multiple purchases of clairvoyance at temple from overflowing the
+       intrinsic's timed subfield and becoming permanent
+when cursed, greased or oilskin cloak might fail to protect against grabbing
+when any corpse wielded by a monster rots away, unwield it to avoid "bad
+       monster weapon restore"
+hallucination affects priest and minion names
+don't try to make the word "aklys" singular
+bullwhip can't yank welded weapon from target
+eroded T-shirts now display the eroded shirt text consistently
+fix "killed by kicking something weird" when kicking a fountain
+disallow fruit names whose prefixes are valid for food (uncursed, numbers, etc.)
+properly handle wishing for fruits which start with other prefixes
+avoid rn2(0) divide by 0 for empty inventory when trying to crawl out of water
+don't let randomly placed monsters on special levels prevent explicitly
+       placed monsters who target that location from being created (a web
+       trap's spider resulted in no quest nemesis)
+don't let randomly placed stairs on special levels be covered by explicitly
+       placed features such as fountains
+substitute random monsters when special level monsters have been genocided
+fix intrinsic blockage by worn items so that wielding a mummy wrapping or
+       cornuthaum won't have the same special effect as wearing one
+magic markers created via polymorphing tools are flagged as being recharged
+unseen rust monster eating messages, and make tame rust monsters consistent
+       with wild ones with regard to rustproofed items
+pager: guard against '%' in output from being treated as a printf formatting
+       directive (using '/' or ';' to look at food yields "% blah blah")
+getpos: support shifted movement letters in number_pad as per help text
+getpos: properly truncate diagonal movements at map edge
+using #name to call an object type something could be used to distinguish
+       fake amulet of yendor (appeared in discoveries list) from real (didn't)
+upon quest completion, leader now IDs quest artifact and also tells player
+       that Bell of Opening is necessary if character doesn't already have it
+remove unwanted quote marks from quest message R 70
+make polymorphed objects be likely to retain magic state: non-magic items
+       usually yield other non-magic items, magic items yield magic ones
+make artifact mirrors unlikely to break when used to hit monsters
+make sure that nemeses don't leave corpses if the message says there's no body
+fix wizard-mode problem with generating Master of Thieves (was singularizing it)
+allow weapon-using monsters who ignore gems to throw darts
+make flint stones be the preferred ammo for sling wielding monsters
+gaining/losing telepathy via polymorph (i.e. mind flayer) redisplays monsters
+prayer result of ``escape from solid rock'' isn't inhibited by teleport
+       restrictions (attempting to fix all troubles got stuck in a loop)
+fix surviving level teleport to a negative destination from somewhere other
+       than the main dungeon (was corrupting the level maps)
+surviving level teleport to a negative destination ("you float down to earth")
+       escapes the dungeon instead of arriving on level 1
+dying due to level teleport directly to heaven won't leave bones
+kicking shades with blessed boots, punching with blessed gloves or when wearing
+       silver rings, does the appropriate damage to them
+add artifacts to ending score and display
+prevent used objects like scrolls and potions which immediately cause the
+       character's death from remaining in final inventory (disclosure+bones)
+blessed genocide of '@' will list the player's role during genocide disclosure
+moved skill definitions to their own file (skills.h) and embedded them in
+       the object table.
+increased the maximum number of branches supported by dgn_comp.
+increased the number of characters permitted in a role name.
+the number of bits available for properties are expanded.
+water demons should not chat about being freed.
+since hallucinating players see monsters constantly change anyway, don't print
+       message when werecritter changes
+artifacts which do fire/cold/electric damage to their targets can destroy
+       carried objects which are susceptible to that type of damage
+some artifacts are now unaligned in order to be more accessible to all types
+       of characters
+wizard mode ^F command reveals floor traps along with the map
+pager: '/' was not finding data.base entries for shopkeepers, mimics, or
+       race/role spit when picking from the screen
+small monsters like hobbits and gnome zombies couldn't wear cloaks/wraps
+make sure non-erodable objects aren't eroded or erodeproof (could happen by
+       wishing or object polymorph)
+consistently let iron non-weapons rust, etc.
+handle more spelling variations ("boots of speed",&c) when granting wishes
+fix 3.2.0 change which flags the castle and priest quest levels as graveyards
+when stepping on a spot where "there are several objects here" (so many
+       objects that they aren't automatically shown to the user), report any
+       dungeon feature such as stairs just like when there are fewer objects
+report "file empty?" rather than "version mismatch" when that's the reason
+       why a data file fails its validation check
+to-hit bonuses don't accumulate for monsters with multiple weapon
+       attacks
+skill definitions moved to skills.h
+skills are stored in the objects[] table.
+intrinsics and extrinsics are now >32 bit
+number of roles no longer limited to 26 letters
+renamed typename() to obj_typename()
+add "You hear a nearby zap" when monster is close
+fixed a bug that would print of "a Book of the Dead" instead of "The"
+fixed a bug so there is no delay when a rolling boulder trap is
+       triggered completely out of sight
+fixed emergency_disrobe() so it will drop gold
+fixed a missing case that occurs (rarely) when praying during a
+       full moon and your god is very pleased
+ask for confirmation before praying;  no more accidental Alt-P
+more guilt messages when you do something which lowers alignment
+mplayers get more suitable equipment for their role
+allow spaces before <option-name>= in the options file
+dragon scales/scale mail of all colors now work when worn by monsters (in
+       3.2.x, only gray conferred any special benefit)
+when shopkeeper takes cash from dead player's corpse, clear `been robbed'
+       status if there's enough gold to cover the amount so that next
+       player who loads level as bones data won't start out owing money
+merged scrolls of scare monster crumble to dust together, matching the
+       existing feedback (was destroying one and leaving the rest)
+properly disallow wishing for venom and allow wishing for iron balls by class
+drum of earthquake can't destroy the high altars
+potion of oil can't be ignited while underwater
+zapping a wand of digging upwards while underwater won't dislodge a rock
+       from the ceiling
+add "born" field so monster extinction limits the number created, not killed
+allow "okonomiyaki", etc. to pluralize properly (Ranma 1/2 is popular)
+fix off-by-one bug that disabled the check to see if you tried to name your
+       fruit after a previously existing corpse or egg
+avoid a "glorkum" message if an object conveying a warning is stolen before 
+       the warning message is delivered
+flags.made_amulet flag was never being set
+make sure proper message is given when tinning cockatrice while a flesh golem
+fix punctuation on cancelled cobra's dry rattle message
+leash cannot choke monsters that do not breathe
+rothes are now brown, harder to confuse with much more powerful grey quadrupeds
+defer level change for every schedule_goto() call, not just while monsters
+       are moving (player's move could cause an engulfer to expel character
+       onto a level changing trap, then attempt to access stale monster and
+       possibly trigger relmon panic or crash)
+fix obscure worm bug which did not consider the tail tip to be visible.  Bug
+    produced "You miss it" on 3.2 and a blatantly obvious 'I' in prerelease 3.3.
+water prayer: treat already blessed potions as `other' rather than as `water'
+water prayer: potions being blessed glow light blue rather than amber;
+       hallucination affects the color seen when changed potions glow
+fix Death/Sandman #9 joke (should be 8) and make sure the message can be seen
+zapping Death with wand of death multiple times could cause hit points to wrap
+when pet attacks monster that attacks back, be sure it's in range (could be a
+       worm attacked on the tail)
+
+
+Platform- and/or Interface-Specific Fixes
+-----------------------------------------
+micro: -uwizard-{class} counts as -uwizard when allowing debug mode
+micro (assorted): readmail()--don't show fake mail text when blind; also,
+       update the "report bugs to" message to specify devteam@nethack.org
+msdos: fix overlay separations in weapon.c
+msdos: fix problem breaking compile without REINCARNATION
+msdos: fix dependency in djgpp Makefile (wintty.c -> hack.h)
+tty: try to use terminfo sgr0 (aka termcap me) attribute to turn off all
+       text attributes, instead of just using "rmso" (aka "se") attribute.
+tty: change name of nethack's termcap.h to be tcap.h
+tty: ^P at a long prompt printed an extra newline (and then wrapped oddly)
+tty: get repeat to work properly on extended commands
+tty/ASCIIGRAPH: rogue level uses PC Rogue colors and symbols
+nt: in TTY port, non-English keyboard layouts that depended on AltGr-+ sequence
+       were getting "Unknown command 'M-\'" for '\','@','$','{','[',']','}'.
+tty and X11: avoid crashing trying to display long (>128 char) menu items
+X11: avoid setuid install problems by changing uid to real uid while
+       opening the X11 connection.
+unix: compress/uncompress detects failure of the compressor, such as for
+       filesystem full or missing compressor, and no longer deletes the
+       valid file.  In the uncompress case, such as uncompressing the save
+       file, a message is generated as well.
+dlb: handle situation where lseek(,,SEEK_END) doesn't yield the size of the
+       contents of a file (specifically, VMS "variable length" record format)
+vms: install.com couldn't handle the `copy readonly files' step when DLB
+       wasn't enabled
+mac: added unix tty-ish menu flexability
+mac: stoped using OLDROUTINENAMES
+mac: added dlb support
+mac: Increased the maximum number of menu items, so the inventory
+       won't get cut off at the bottom.
+mac: Changed the behavior of Cmd-Q so it uses the new #quit command.
+mac: Will only dispatch events if the window system is initialized.
+       This fixes a bug that would crash the system if the user had an
+       invalid option in the NetHack Defaults file.
+mac: Added an appropriate message when eating an apple.
+mac: Change the askname dialog for the new role patch.
+mac: Add a gray background to all dialogs.
+mac: Replace some improper calls to InitCursor().
+mac: Remove a whole bunch of unused code.
+mac: Added Balloon Help messages.
+mac: Pop-up menus display the 3-letter file code instead of a single
+       letter.
+mac: Pop-up menus and text item have a 3-dimensional look.
+
+
+General New Features
+--------------------
+incorporate the "wizard patch"
+`#quit' command added
+`*' command added; displays inventory of all equipment currently in use
+add Stone To Flesh spell
+wands eventually explode if rechaged too many times
+show IDed Amulet of Yendor + invocation tools in own section of discoveries
+       list; likewise for IDed artifacts
+add infravision
+add Eyes of the Overworld
+add lenses
+split players race from role in life
+cursed figurines cam spontaneously transform when carried
+`in_use' struct obj field is unconditional rather than just #if !NO_SIGNAL
+add the secondary weapon slot, e(x)change command, #twoweapon
+       command, and "pushweapon" option.
+add the quiver slot, (Q)uiver command, (f)ire command, and
+       "autoquiver" option (defaults to false).
+add the "pickup_burden" option which controls when the user
+       is asked for confirmation when picking up an item.
+pole-weapons can be applied at a distance, and similarly used by monsters.
+'/' command's pick-a-location input (getpos) supports shortcuts to bypass the
+       "more info?" prompt; ':' for '.'+'y', ',' for '.'+'n', ';' for ','+ESC
+monsters can throw cockatrice eggs at players
+prayer trouble "stuck in wall" takes boulders into consideration
+crysknives can be "fixed"
+vampires now #chat back
+new monsters: chickatrice,pyrolisk,fox,coyote,winter wolf cub,dingo, 
+       gas spore,flaming sphere,shocking sphere,lynx,panther,raven, 
+       glass piercer,mastodon,woodchuck,centipede,master mind flayer, 
+       pony,horse,warhorse,silver dragon,lichen,storm giant,arch-lich,
+       dwarf mummy,green slime,disenchanter,monkey,dwarf zombie,ghoul, 
+       paper golem, gold golem,glass golem,prisoner,jellyfish,piranha,
+       shark
+new objects: amulet of unchanging,silver dagger,silver spear, 
+       silver dragon scales/mail,robe,alchemy smock,kicking boots, 
+       kelp frond,eucalyptus leaf,scroll of earth,spell of drain life,
+       potion of acid,potion of full healing,potion of polymorph,
+       potion of sleeping,ring of free action,ring of gain constitution,
+       ring of increase accuracy,ring of slow digestion,grappling hook,
+       ring of sustain ability,wand of enlightenment,saddle,various gems
+add Monk role
+the old Elf role is replaced by the Ranger
+add Human, Elf, Dwarf, Gnome, and Orc races
+add multishot ammunition
+add graves, iron bars, trees, and arboreal levels
+dwarvish mattocks can be used to dig
+add leprechaun, cockatrice, and anthole special rooms
+add the Sokoban dungeon
+implement talking artifacts
+members of the clergy (aligned/high/player priests and monks) are 
+       generated with a robe instead of chain mail.
+new tin of meat types
+tinning kits and cameras have charges
+blessed magic mapping detects secret doors
+starting spells are known at start of game
+pre-discoveries are listed with an *
+voluntary challenges with #conduct
+add a funny message when eating tridents and flint stones
+allow debug-mode level teleport to the sanctum
+some #monster commands now consume energy
+trees can be kicked as a possible source of fruit
+Wile E. Coyote references when using '/' on a coyote
+
+Platform- and/or Interface-Specific New Features
+------------------------------------------------
+WinNT: implement mail support
+WinNT: console mouse support added to TTY port
+
diff --git a/doc/fixes33.1 b/doc/fixes33.1
new file mode 100644 (file)
index 0000000..4b4a1c3
--- /dev/null
@@ -0,0 +1,444 @@
+General Fixes and Modified Features
+-----------------------------------
+discarding a tin without eating should not count towards food conduct
+expand 'nethack.cnf' in dat/help to include new names on some platforms
+using 'C' to name a steed produces a "pony tail"
+stopping reading a spellbook when "too much to comprehend" left in_use set
+conduct: eating meat{ball,stick,ring,huge chunk} counts as eating meat
+don't select gems--aside from rocks and known glass or flint--via autoquiver
+skilled slingers can shoot multiple rocks with one shot, like other archers
+orcs shooting orcish arrows from orcish bows get multishot bonus, like elves
+have 'Q' offer gems/stones as likely quiver candidates when wielding a sling
+'Q' command--don't offer tools as likely quiver candidates
+spell hunger effect for wizards of high intelligence was not computed correctly
+fix "killed by the [master] mind flayer" bug
+redisplay correct trap glyphs when hallucination ends
+monsters under Conflict cannot attack other monsters that are already dead
+monsters that steal gold from monsters should teleport
+fix mummy wrappings worn by monsters to block invisibility
+applying a weapon or wieldable tool would sometimes give spurious messages
+       about two-weapon combat
+applying a weapon or wieldable tool might not always end two-weapon combat
+receiving a divine gift artifact while wielding two weapons would unrestrict
+       two-weapon skill instead of the skill for the artifact's type
+throwing and kicking while wielding two weapons exercised two-weapon skill
+when wielding two weapons, ')' command should show both
+giants cannot "easily pick up" boulders on the Sokoban level
+W command would let you wear an arbitrary item in your body armor slot if that
+       was empty & uncovered and you carried extra armor for any filled slot
+W command would list entire inventory if you answered '?' to the "what do
+       you want to wear?" prompt when all unworn armor couldn't be worn
+#looting and applying containers with menustyle != traditional would do bad
+       things if you split a merged stack in quiver or secondary weapon slot
+save/restore while mounted or stuck could cause a game crash or other errors
+baby gray dragons should not be visible to infravision
+dying from a failed saddle attempt should name the monster without using
+       hallucination
+spurious "Bummer, you've hit the ground" when hallucinating and dismounting
+constitution of <3 and >18 (possible in 3.3 because the ring of gain
+       constitution was added) was not handled properly
+potion and wand of invisibility (on yourself) should not print message if you
+       are already invisible, even if you can see invisible
+reviving tame monsters ended up tame but not peaceful and would attack you
+wishing for "rotproof" item is recognized as synonym for erodeproof
+your pair of boots "are" not affected when kicking rust monster should be "is"
+use article "a", not "an", with "eucalyptus leaf"
+fix crash if reviving troll has been genocided
+shouldn't see candles flicker when blind
+gas clouds use cloud symbol
+unchanging suppresses amulet of change, intrinsic lost by life-saving
+missing lucern hammer, silver dagger, silver spear in monster weapons
+buckled boots are brown
+Scorpius and centipedes are not web-makers
+race placeholders are M2_NOPOLY
+Monk species/leader/guardians are M1_HERBIVORE
+leader/nemesis flags fixed with |= instead of =
+freezing spheres won't leave corpses
+artifacts should add to ending score even if they are inside a bag
+being killed by a gas spore should not be treated as burning (most noticeable
+       problem was that the death message did not include "killed by")
+remove a double period from "Caught himself in his own fireball.."
+automatic dog names restricted to dogs
+chatting with a monster that teleports after the chat (succubus, bribable
+       demon) would put an 'I' symbol at the monster's destination
+stethoscope/probing should reveal identity of invisible monster, not use "it"
+wand of probing zapped at 'I' square with no monster should clear the 'I'
+cursed potion of invisibility drunk by monster should reveal 'I'
+kicked monster that evades kick by moving to unseen square should not leave
+       'I' in original position of monster
+closing a door on an invisible monster reveals the 'I'
+gas spores are recognized as having passive damage for purposes of pet attack
+since iron armor can now corrode, don't call all corroded armor "bronze armor"
+properly handle attacking a black pudding with a corrodeable weapon
+do not print "You still cannot see" when blind and removing lenses
+remove possibility of crashes when unseen monster engulfs items
+object shattered by wand should use plural verb when object is plural
+don't anger monsters when hitting them with invisibility or helpful unholy water
+for initial inventory, don't give out spellbooks in restricted spell skills
+for tourists' initial inventory, put darts in quiver rather than wield them
+artifact discoveries sometimes showed undiscovered object types (for example,
+       Snickersnee as "katana" when katana was still known as "samurai sword")
+"iron bars" singularization exception should not also catch "candy bars"
+if a monster kills a monster by throwing acid, don't credit the kill to you
+leave two-weapon combat mode if either weapon is stolen or otherwise unwielded
+use worse of (two weapon skill, current weapon skill) when figuring skill
+       bonuses and penaltys while fighting with two weapons
+never give back-stabbing or weapon-shattering bonus when using two weapons
+engulfing monster will not engulf your pony while you are riding
+arch-lich usually starts with an athame or quarterstaff
+do not say that "an" Asmodeus reads a scroll
+'?' command--short options help sometimes included garbage output
+'?' command--longer options help omitted several recent options
+eating an amulet of restful sleep now works properly
+getting hit by a potion of sleeping now works properly
+sleeping is reported by enlightenment
+detect unseen / secret door detection refreshes unseen monster (`I') glyphs
+monsters won't pick up objects in water (especially kelp)
+unseen check for monsters in explosions
+fixed "petrified by an "
+silver arrows cost a little more than other arrows
+javelin back in its own class
+dipping weapons in potion of oil now works properly
+freed prisoners become peaceful
+monk titles shortened so they aren't cut off
+elven Priests get their starting musical instrument
+you can now correctly ride centaurs
+fixed steed getting teleported (e.g. by Quantum mechanic)
+fix stethoscope/probing speed reporting, and slowing attack on player
+blessed detect monsters increments (not sets) the timeout, and produces a
+       message if no monsters are on the level
+put "Elbereth" under the sokoban prize so that monsters don't eat it
+a weak race can still have a high strength if polymorphed into a strong monster
+make dingos non barking canines
+suppress zap up/down message for stone to flesh on non-stone levels
+fix missing spaces on sokoban level that made level impossible without cheating
+use case-insensitive comparison for wishing (needed for Master Key of Thievery)
+avoid commas in the player name because they confuse the record file
+note Sliming when using probing/stethoscope on yourself
+fix inconsistency: reflecting medusa's gaze while invisible didn't work,
+       reflecting floating eye's gaze did
+Medusa should not drink potion of invisibility (the code only checked for wands)
+restore confirmation prompt for kicking pets and peaceful monsters
+ask for confirmation about kicking steed when kicking while mounted
+converting secondary weapon into an artifact (naming, dipping) stops #twoweapon
+a fully ID'd object converted into an artifact is no longer fully ID'd
+polymorphing an object by dipping in potion while inside a shop will only
+       anger the shopkeeper if the object is shop merchandize
+make {wand,spellbook,potion} of polymorph immune to being polymorphed
+turning undead should count as calling on a deity for purposes of conduct
+fix "monster trail" problem caused by reading a scroll of magic mapping while
+       engulfed
+don't give Slow_digestion-related message when non-digesting engulfer expels you
+vary vampire's chat responses according to time of day, tameness, and player
+       form
+added fish_parts to mbodypart/body_part
+fixed do-while loop test criteria in create_mplayers()
+fix crash if reviving troll has been completely drained by Stormbringer, et al
+a stinking cloud should not kill a monster more than once
+player stops riding when nymph steals saddle
+don't ask for name for eaten ring of slow digestion if already identified
+don't let engulfed lifesaved monster beat you up while supposedly being
+       totally digested
+lev_comp: honor class in OBJECT entries (user's '+',"identify" made scroll)
+fix uninitialized buffer/unprintable characters error when eggs hatch
+accept "aluminium" as variant spelling for "aluminum"
+don't die from lava while praying
+correctly display gems for the final score even when blinded
+throwing a boomerang from {wielded,secondary,quiver} weapon slot will have
+       it be restored to that slot if caught upon return
+don't allow iron balls to pass through iron bars
+fix "What weird role is this? (E)" for names taken from 3.2.x score records
+make spell of jumping work properly when restricted in escape spells
+save traits of petrified monsters; animated statues are like revived corpses
+unmoving monsters seen by infrared are removed from/displayed on the screen
+       when they leave/enter direct line-of-sight
+Sting and Orcrist get their anti-orc bonus against orc player characters
+buffer overrun caused by many long names in a single message
+polymorph can't indirectly transform scrolls of mail into blank scrolls via
+       paper golem creation
+don't let savebones() name a ghost without checking for sufficient space
+don't report "killed by ghost of Foo called Foo" on tombstone or in record
+when breaking create monster wands, don't place monsters inside solid rock
+don't allow tainted cockatrice corpses to prevent stoning if you eat one
+oil isn't seen as dimly glowing if you're blind
+properly consider hallucination and blindness when printing sliming messages
+don't allow the player to jump through iron bars or walls (the latter only
+       when wearing the Eyes of the Overworld)
+don't allow the player to hurtle through iron bars
+work around race condition between breaking a wand of teleportation,
+       teleport control and autopickup
+rust traps should affect scrolls
+lev_comp returns error if level cannot be fully written out
+blank scrolls/spellbooks don't count as reading material
+fix seduction attacks to treat characters polymorphed into golems as neuter
+chaotic sacrificing on a chaotic altar may crash if demon creation fails
+failed demon summoning might cause monsndx panic
+avoid possible crash when casting fireball spell while engulfed or near the
+       edge of the map
+prevent observation of dust clouds in rogue level doorways when blind
+cans of grease will no longer rust
+skip already dead monsters when scanning the full monster list; avoids
+       monsndx panic and other potential trouble
+skip already dead shopkeepers when checking for tended shops
+level teleport high in the air while lifesaved should result in an escape
+the "stoned" flag wasn't reset when a monster was lifesaved from turning to
+       stone, so the next monster you killed would always turn to stone
+wooden harp is not a magical object
+player characters got left at 10 when "normal" speed was increased to 12
+time it takes a monster to change armor doesn't depend on whether you see it
+character can't be totally digested on first turn of being swallowed
+level 25 engulfer would trigger divide by 0 crash via evaluating rnd(0)
+wielded egg that hatched wasn't cleaning up worn objects and might cause crash
+mirror shouldn't show location of unseen monsters
+cloth headwear was being reported as leather when fire damaged
+modify moveloop so that time (moves) is not relative to the player's speed
+fix moveloop to account for player not accumulating enough movement points
+       to move in a turn -- this fixes the reported "time is wrong when
+       burdened" problem
+monsters should not teleport on levels that disallow teleportation
+consider existing poison resistance when printing message while eating
+don't allow various spells/effects to turn monsters into genocided species
+don't crash on abusing guardian angel (accessing edog)
+call useupall() rather than useup() for organic items burned by lava
+revive any Rider corpse which gets teleported
+wishing for gold should affect conduct
+gold detection should detect gold golems
+grease should affect the secondary weapon in two-weapon mode
+falling drawbridge, eating cockatrice eggs, delayed self-genocide all caused
+       monsters to be fully named instead of using "it".       
+change the You_hear message if hero is asleep
+various inventory changes did not immediately update when perm_invent was set
+avoid crash when multiple, cascading explosions occur
+pets are no longer permanently weakened by a brush with starvation
+doeat() doesn't leave rotten food half-set-up for resumption
+don't allow trying to resume eating a revived rider corpse
+shopkeepers, priests and peaceful monsters should get angry when you cast
+       stinking cloud on them
+when crowning a neutral wizard who knows finger of death but isn't carrying
+       its spellbook, don't drop his weapon (crash likely)
+similar greased and non-greased objects would merge together into one stack
+monster reading scroll of earth may be allowed an extra attack
+change message for failed attempt to mount steed while punished
+fix multi-shot throwing for darts and shuriken
+update monster multi-shot throwing to match player throwing
+prevent inappropriate use of "lungs" in creatures that have none
+change several instances of 'pline("The ' to 'pline_The("'
+monk characters kick as characters rather than as kicking monsters
+fix kicking shades by character polymorphed into kicking monster
+fix articles in some Sokoban trap messages and eliminate some
+       superfluous messages
+restoring with damaged subroom shops on non-current level could dereference
+       stale shk pointer
+prevent removal of levitation in sokoban pits from causing you to
+       "float gently to the ground" 
+peaceful/tame mindflayer now mindblasts hostile monsters and vice versa (the
+       check was backwards)
+fix suppression of stone-to-flesh on unique monster statues
+kill player when drain life induces negative HPs
+rumors used as engravings should not refer to fortune cookies
+magic-resistant players/monsters unhurt by monsters zapping wands of striking
+fix time problem where disrobing took too long
+saddle that comes with a knight's initial horse should be known to player
+iron golems are sensitive to more ways of getting wet with water
+prevent odd contents of initial tourist tins and eggs (the contents were
+       mostly from the quest level, producing many cave spider eggs)
+breaking a wielded wand doesn't leave it wielded
+if nymph hits monster on first attack and teleports away, suppress second attack
+kicking a mimic should reveal its presence
+using 'F' command on a pet with safepet should not produce "thin air" message
+polymorphing into slime or fire creature removes Slimed; becoming a new man
+       resets the Slimed timer
+throwing cockatrice corpse barehanded should stone the player
+avoid "petrified by petrification" on tombstone
+avoid "turning into green slime" on tombstone (KILLED_BY didn't work if Slimed)
+since unchanging prevents sliming, make it reset any sliming already present
+avoid "You turn into a female succubus" redundancy
+player hit by potion of acid should take damage like monster
+"You are protected" in enlightenment display should include u.uspellprot
+chameleons that change into a non-moving, non-attacking form shouldn't get stuck
+fix bug where monsters didn't wield bow (etc.) before shooting arrows (etc.)
+medium size is too large for giant bats (it allows leaving plate mails when
+       killed)
+player polymorphed to a ghoul resists sickness just like a ghoul monster
+player in werecritter beast form shouldn't polymorph into "human"
+player wearing scales of genocided dragon was getting duplicate "you feel
+       dragon-ish" messages when polymorphing
+fix luck timeout for full moon and friday 13th
+monsters must wield polearms before using them, just like players
+when saving bones data, shopkeepers will claim dropped objects inside shops
+pets will now wear objects they pick up
+pets will now wield pick-axes when necessary
+limbless pets are no longer able to carry objects
+monsters cannot consider a mattock for digging if they are wearing a shield
+avoid a case where monsters keep switching between pick-axe and weapon
+override hallucination when reporting pets that ascended or escaped with player
+avoid duplicate pickup() calls when landing after falling through a hole
+added squeaky board traps to Lord Surtur's lair entrances
+cursed lenses no longer considered a major problem by deity
+prevent "seeing an image of someone stalking you" when Blind
+disallow potion of polymorph / ring of polymorph control starting combo
+disallow starting with blank paper
+tools shouldn't charge beyond 127 charges
+getting money from a fountain should set the looted flag
+pole-weapons won't bash and will advance skill when on steed
+blessed genocide of polymorphed unchanging player should kill
+picking up nothing should take no time
+quiver command should take no time
+potions should not be autoquivered as worthless glass
+players should not get double-billed when using or altering items
+silver dragons should have same resistance as other dragons
+golems should be un (reverse-)genocidable
+player should get blamed for destroying Minetown fountains by Excalibur dipping
+player should not get blamed for others destroying Minetown fountains
+digesting ghosts and shades as a purple worm should be nonvegan but vegetarian
+eating brains as a mind flayer should be nonvegetarian
+eating eggs should be nonvegan but vegetarian
+eating tripe, meat sticks, chunks of meat should be nonvegetarian
+headstones now implemented through engraving
+luck penalty for the remaining forms of "creative NetHacking" in sokoban
+don't penalize a turn if player cancels #ride direction
+Ranger quest is no longer a rip-off of the old Elf quest
+several Hello() messages were inappropriate for various monsters
+storm giants should talk
+monk leader and guardians should use clerical spells
+monks shouldn't start with scrolls of enchant weapon
+movement rate when saddled was miscalculated
+items under lava shouldn't been seen or picked up
+clicking in status line during `/' shouldn't cause getpos error
+huge chunk of meat should count as dogfood
+"Pardon me" when moving directly into peaceful monster
+shouldn't glow amulet and save life of digested monsters
+"<monster> gets angry!" only when you can see the square
+"Never hit with a wielded weapon" conduct should only count
+       weapons and weptools
+lynxes should not have cold attacks
+Naming a specific object asks "What do you want to name *this* ___"
+"Having fun sitting on the floor" shouldn't over fountain
+"ball lightning" changed to "ball of lightning"
+"poisoned by a poisoned crude arrow" should be "killed by a poisoned
+       orcish arrow"
+shouldn't see invisible monsters oozing under a door
+fix apostrophe for invisible seen-invisible crumbling-to-dust liches
+amulet of change when polymorphed into single-gender monster could produce
+       inconsistent role name for Priest(ess) and Cave(wo)man
+prevent Fire Brand from "burning" a water elemental
+snatching cockatrice corpse gloveless by applying bullwhip will now stone
+inventory description of wielded two-handed weapon uses "weapon in hands"
+inventory description of secondary weapon explicitly lists it as non-wielded
+       to reduce confusion about two weapon combat
+Bell of Opening removes attached iron ball when performing opening magic
+chatting to a monster who responds with "I'm trapped" reveals the trap
+Make tmp_at() work when called in the midst of a previous tmp_at() sequence
+Make the messages for attempting to wear lenses over a blindfold more clear
+Prevent buffer overflow when reading engravings that are BUFSZ in length
+paralyzation message on steed should not say your feet are frozen to the floor
+avoid buffer overflows and associated security problems from getenv(),
+       program name, and user name
+
+
+Platform- and/or Interface-Specific Fixes
+-----------------------------------------
+Mac: legacy message was being truncated
+Mac: black background left mess on backspace
+Mac: backgrounds set too early on game startup
+Mac: tty window positions not remembered after move
+Mac: tty window turned B&W when moved to bottom of screen
+Mac: tty quit command fixed
+Mac: remnants of previous hunger status now cleared
+MFLOPPY: add checkspace option to avoid problems with >2GB free space
+MSDOS: fix clearlocks() to look for the right file names, 
+       and not LEVELS.* (MFLOPPY only)
+MSDOS: remove djgpp stuff from the Microsoft C Makefile
+MSDOS: change NetHack.cnf to defaults.nh in NHAccess.nh comments
+MSDOS: add missing files to gcc 'make spotless'
+NT: WIN32 specific code in tty_nh_poskey() was missing the
+       necessary code to clear window flags so after hitting ESC 
+       messages that should have displayed did not
+Linux: set MAILPATH properly
+Linux: don't use control characters on Rogue level with IBM graphics
+DEC UNIX: set MAILPATH properly, type lex functions properly, avoid conflict
+       with curses over naming
+Qt: remove intermediate files on 'make spotless'
+Qt: modify makefile to allow use with BSD make and FreeBSD
+Qt: have player selection dialog come up when name specified
+Qt: use default menu accelerators and allow remapping
+X11: fix memory leaks is reading from dialogs
+X11, tty: avoid crashing when displaying empty menus, as from 'i' with
+       perm_invent and no inventory
+tty: when given the choice of ANSI color (AF) vs standard color (Sf), choose
+       ANSI since there is some disagreement as to the correct color order
+       for Sf, but no such disagreement for AF.
+tty: add workaround for termcap misfeature in some Linux distributions which
+       affects DECgraphics display
+Amiga: minimal functionality restored
+Amiga: recover created empty (and unused) save.info files
+Amiga: ^P works properly
+Amiga: windowcreating modified for better adaptivity
+Amiga: changed from intuition menus to gadtools menus
+Amiga: changed default colors in tilemode to those of gfxfile
+Amiga: window backfill works
+Amiga: playerselection adopted from tty-port
+Amiga: linesplitting in msg/inv/menu windows fixed
+Amiga: obey user configured pens in nethack.cnf
+Atari: tty port rescued from oblivion, Gem windowing added
+
+
+General New Features
+--------------------
+gold/glass golems, glass piercers now resist acid
+added sharks, piranha, jellyfish, prisoners, and iron bars to special levels
+piranha can appear in swamp rooms
+hero falls off steed when fumbling or falling down stairs
+artifacts speak when applied
+engraving "x" is not literacy
+demons and vampires engrave in blood
+shopkeepers don't like riding customers
+can #chat down to steed
+own race in Gnomish Mines replaced with random monsters
+differentiate between light/gaze-induced blindness and other causes of blindness
+yellow dragon scale mail provides acid resistance
+polymorphed player digests engulf victims more slowly if Slow_digestion
+Conflict now affects steed's desire to keep its rider
+undead turning of bones level player corpse causes ghost to reunite with
+       the corpse
+control-x in regular mode displays name, role, race, gender, and your deities.
+wizard mode can wish for pools of lava
+pythons now have infravision to emulate real pythons heat sense organ
+M-2 added as a shortcut for #twoweapon
+general file location mechanism
+you can choose to #loot the saddle from something now
+message changes for silver dragon scale mail glowing silver and pit vipers
+       falling into pits
+support explicit `race=random', `alignment=random', and `gender=random'
+       in startup options
+manes now grow up into lemures
+potions of healing and sickness affect Pestilence in the opposite way to
+       their effect on other monsters
+introduction of a new method of warning where you sense the danger level of
+       monsters on the level by displaying it at the monster's location
+introduction of a new method of warning for specific monsters the way Sting
+       does for Orcs; you sense their presence anywhere on the current level
+artifacts can belong to specific races and won't be given as gift when "hated"
+Archeologists get a penalty for breaking "historic" statues
+hatching eggs in male player's inventory have chance of "Daddy?"
+steeds affected by more types of wands zapped down
+opening/knock versus steed drops saddle
+unwearing your steed's saddle (e.g. stolen, opening) causes dismount
+yet another funny message when whipping a horse corpse
+yet another funny message when mounting when hallucinating
+Bell, Book, and Candelabrum added to final score like artifacts
+new keywords coaligned and noncoaligned for altars (and monsters/priests) 
+       in special level descriptions
+quest start levels get coaligned altars if their roles have multiple 
+       alignments, and goal levels get noncoaligned altars
+ice vortices and freezing spheres are infravisible
+
+
+Platform- and/or Interface-Specific New Features
+------------------------------------------------
+X11, tty, Amiga: offer for player selection only choices consistent with those
+       already made by config file/command line (e.g., only offer roles that
+       are compatible with specified race)
+tty: eight_bit_tty option
+Amiga: implement menu_* accelerators and counting
+mac: the "record" file is created if it does not exist
diff --git a/doc/fixes34.0 b/doc/fixes34.0
new file mode 100644 (file)
index 0000000..ea3fb77
--- /dev/null
@@ -0,0 +1,595 @@
+General Fixes and Modified Features
+-----------------------------------
+prevent an extraneous selection prompt when a role with only a single 
+       possible gender, race, or align is specified
+be consistent with the use of twice and thrice in end of game reports
+use "kill" vs "destroy" more consistently
+looting bag of tricks on the floor doesn't then prompt for direction
+suppress "the" in "you kill the poor Fido"
+iron bars added to the Dark One's prison
+shouldn't be able to #loot without hands
+level compiler can specify cockatrice nests, leprechaun halls, antholes
+fix level compiler to allow specifying golems via '\'' in MONSTER directives
+fix bug where excalibur blasted lawful non-Knights
+unification of the strings "he"/"him"/"his"
+conflict caused vanishing vault guards to be killed with player getting
+       credit/blame (also dmonsfree warning for double removal from map)
+monsters' conflict resistance check was unintentionally being affected by
+       character's experience level
+stone-to-flesh was accessing freed memory, passing bad map coordinates
+       to newsym that might be harmless but could trigger a crash
+prevent spurious "placing steed on map?" impossibles during save/restore
+prevent real "placing steed on map?" impossibility [sic] when creating bones
+dropping secondary or quivered weapon to lighten load in order to crawl
+       out of water left the item flagged as still worn
+if #adjust combined two or more of main weapon, alternate weapon, and quiver
+       the resulting stack would be flagged as worn in multiple slots and
+       eventually trigger "Setworn: mask = ##." impossibility
+remove curse operated on secondary weapon even though it wasn't wielded
+update conduct immediately when eating corpses (character killed by eating
+       poisonous corpse as first meal was described as "strict vegan")
+fix problem with amulets of change when polymorphed into succubus/incubus
+YAFM for pit fiends/pit vipers and pits should require seeing the monster
+woodchucks, cockatrices, and vampire bats should eat
+specifying a non-numeric value for amount when donating to temple priest or
+       bribing demon prince produced random result
+mastodons can tear through webs
+praying on wrong deity's altar cursed holy water but ignored uncursed water
+polymorphed player's gaze now works properly as a pyrolisk
+fix "You drop the Wizard of Yendor's corpse into Wizard of Yendor's interior."
+make sure status line gets updated when turning-into-slime state changes
+when eating green slime, don't reset slime countdown if already infected
+stop current activity when you noticed you're turning into slime
+message given when displacing an unnamed pet into a polymorph trapped referred
+       to it by its new monster type rather than by what you displaced
+player killed by ghoul turns into one in the bones file
+slings are not made of wood
+for post-amnesia deja vu messages, use "seems" rather than "looks" when blind
+avoid encumberance messages during startup attribute adjusting
+even a wumpus cannot escape the pits in Sokoban
+when a steed dies in a shop, don't charge for the saddle
+shopkeeper did not charge for use of an unpaid camera
+shopkeeper did not charge for items burned by breaking a wand of fire
+shopkeeper should charge when you transmute a potion
+shk notices if you use a grappling hook to remove an item from the shop
+adjust robbed shopkeeper's feedback when he or she plunders hero's corpse
+avoid giving away which monsters are saddled while hallucinating
+when polymorphed into a herbivorous monster, you should prefer vegan "corpses"
+when polymorphed into a hider, stop hiding after picking up the last object
+       at a location
+throwing a wielded, returning weapon should not disable twoweapon mode
+monster should not wield cockatrice corpse without gloves on
+sharks have thick skin
+better message when killed by drinking a potion of sickness from a sink
+telepathically detected monsters will be described by name if they try
+       to attack praying character
+taking cockatrice from or putting it into a container should stone you
+       if you are unprotected
+don't fall into pits (or other traps) twice when dismounting
+fix two weapon combat bonus/penalty to avoid "weapon_hit_bonus: bad skill 2"
+unicorns were at a disadvantage on a noteleport level
+missing a cockatrice when polymorphed into a weapon-using monster but
+       fighting hand-to-hand would stone the player
+eliminate ghoul creation abuse when engraving on a headstone
+loss of levitation due to a sink will result in touching a wielded cockatrice
+       corpse, just like falling down stairs while burdened
+falling into a sink when constitution is greater than 20 won't raise hit points
+stinking cloud should not affect migrating monsters, causes dmonsfree error
+only display message about monster using a weapon against another monster
+       if you can see the monster
+don't count artifact amulets (wizard's quest artifact) twice in final score
+prevent pets from picking up Rider corpses
+when polymorphed into a centaur, don't keep kicking monsters after they die
+when throwing at a monster that you see with infravision, don't say "it"
+avoid "the arrow misses the mimic" which left the mimic concealed
+#sit while water walking over a submerged object should sit on the water's
+       surface rather than on that unreachable object
+suppress extra "the" when printing the names of certain mplayers
+do not try to engulf green slimes (same as for cockatrices)
+trying to eat the brains of a green slime is now properly handled for players
+monsters touching cockatrices check boots for feet and nothing for tentacles
+if being petrified, don't disable messages from further petrify attacks
+trap detection would generally not find trapped doors
+avoid spurious done eating message after choking and vomiting
+attribute distribution for several player types did not add up
+monsters shouldn't try to eat green slime as a cure for stoning
+lighting of arboreal levels should not be stopped by trees
+need to recalculate visible locations immediately when monster blinds player
+monsters shouldn't see through walls because player wears Eyes of the Overworld
+when pricing glass the same as valuable gems, be sure to use gems of same color
+nymph stealing armor from a fainted player should wake the player
+ensure status line updates when you stop running when time is shown
+repairing a trap in a shop doorway must replace the broken door or wall as well
+sleeping steed cannot climb stairs/ladders
+can't change levels when mounted on a steed which is carrying the Amulet
+more artifacts granted by a deity are rustproof
+monster name feedback when using the m movement prefix allowed player to
+       distinguish between peaceful and hostile monsters while hallucinating
+scrolls should not fade when hitting rust monsters, only from rust traps
+blank scrolls should not fade even from rust traps
+can't eat or #offer food off the floor under circumstances other than
+       encumbrance where you couldn't have picked it up off the floor first
+ensure correct message after passive freeze attack by gelatinous cube
+avoid buffer overwrite when several weapons slip from your hands at once
+prevent portal placement on Ranger quest from stranding player in left margin
+avoid crash when a trouble gets fixed before you finish praying
+sensed hidden monsters should fight back when attacked
+mindless monsters won't be grateful after unsuccessful #untrap attempts
+turning affects your religious conduct, even if your god does not help you
+rolling boulder trap's boulder will knock another one that it collides 
+       with into motion in its place
+make it harder to abuse detect monster and confusion spells
+prevent D[a from producing odd message sequence in (c)ombination mode
+avoid messages like "the silver bell" after being drained by mind flayer
+after polymorph, actually drop both weapons when a message says this happened
+curb unicorn horn creation abuse by limiting the chance of a unicorn
+       leaving one if it has been revived
+accept -p and -r options with nethack -s, as documented
+avoid printing "spellbook of" Book of the Dead in list of discoveries
+eating non-food items made of leather or other animal parts now violates
+       vegan/vegetarian conduct 
+use correct skill when throwing something while in twoweapon mode
+secondary weapon can rust when hitting a rustmonster in twoweapon mode 
+extra healing spell cures monster's blindness
+add missing quest message for throwing the quest artifact to the Monk leader
+pits, arrow and dart traps, webs, polymorph traps and sleeping gas 
+       traps can affect the steed
+allow game restoration while polymorphed and your race is genocided
+ensure that crysknives revert to worm teeth, even in containers
+do not print gas spore's name if you cannot see a gas spore explosion
+cursed two-handed weapons now keep you from changing body armor
+trapped pets cannot follow you to another level
+no corpse when unchanging hero dies while polymorphed into a G_NOCORPSE monster
+A-removing armour under cursed stuff no longer fails silently
+grease protects gloves from contact poison on books
+items picked up from an abandoned shop sometimes wouldn't merge with other
+       compatible items in inventory ("no charge" bit wasn't being cleared)
+prevent cut-off death message by increasing DTHSZ
+check to not control teleports when unconscious should now work properly
+if armor the hero is donning is stolen or seduced off, attributes
+       can be left permanently mis-adjusted
+ensure a message is printed in all non-obvious cases where a monster flees
+a fleeing monster that is holding you always results in a "get released" message
+ensure a monster flees for at least one "turn"
+explosion type can now be one of dark, noxious, muddy, wet, magical,
+       fiery, or frosty
+flying (jumping or throwing recoil) over some traps (magic portals, fire traps)
+       will now trigger the trap
+displacement does not work through walls
+you can't trip and fall or trip over rocks while riding
+reduce the chances of a monkey successfully stealing armor you are wearing
+monkeys can't steal cursed items that you're unable to remove or attached
+       iron ball or items too heavy for them to carry
+trapped doors are not always detected after returning to a previous level
+trap detection sometimes showed non-trap locations to be traps
+eucalyptus was never chosen in random tree fruits due to an off-by-one bug
+allow knights to pursue and attack thieving monkeys without alignment penalty
+gaining levitation while over on sink causes an immediate fall
+quest leader should avoid leaving the quest start level voluntarily
+blind Medusa cannot gaze
+prevent dipping attached iron ball or embedded dragon scales into a potion
+       of polymorph from confusing the game about what items are in use
+should not be able to cut down trees on Ranger quest start level
+arrow traps are not currently intended to shoot poisoned arrows
+fall off the horse if you mimic a pile of gold while riding
+martial attacks will not remove monsters from traps and will cause
+       monsters to set off traps they land on while reeling/staggering
+prevent topten from using alloc after alloc failure
+Nazgul and erinyes are nopoly to ensure their numbers are never exceeded
+"player-@" randomly selects a race and "player -@" randomly selects 
+       everything that is not specified
+prevent spurious "quest portal already gone" when you use an artifact to
+       return to the quest after being previously expelled
+prevent limbless shopkeepers from "leaping" and "grabbing" your backpack
+       by changing the messages that you get
+prevent panic when riding while punished and falling down the stairs
+armor class shouldn't wrap from very negative to very positive
+searching should only credit you with finding an undetected monster if
+       you couldn't sense it or spot it already
+monsters should not generally lose invisibility when polymorphing
+monster must have eyes or breathe to be affected by potion vapors
+stop dungeon file open failure from causing vision-related crash
+wishing for {statue,figurine,corpse} of long worm tail yields long worm instead
+chatting to an arbitrary shopkeeper (not a petrified one) who was created
+       via statue animation produced strange results
+Yeenoghu's confusion attack is not a touch of death
+an eating steed should not be able to go up or down stairs, etc.
+you don't feel "great" when recovering with a unicorn horn but Slimed; also,
+       make the same check for potions that make you feel "great"
+avoid panic during player-as-demon demon summoning when no demon is available
+change "Ouch! You bump into a door" message when riding
+prevent voluntary dismount of steed from passing you through walls in
+       tight spots
+prevent throwing boulders, boxes, and chests and medium-to-large
+       corpses and statues through iron bars
+only living eggs which touch cockatrices get turned to stone
+since monsters already refuse to zap empty wands, they shouldn't pick them up
+after praying, try to give a spellbook for which the player is not restricted
+after #dipping your weapon in hand or quiver into a potion of polymorph,
+       leave it where it was
+message from rust trap states "robe" instead of "cloak" when applicable
+gas spore explosions were affecting your human hitpoints even if you were 
+       polyd and consequently you did not rehumanize
+prevent "You attack empty water" when attacking a spot on land while 
+       underwater
+prevent spurious "But you aren't drowning. You touch bottom." message when
+       removing an amulet of magical breathing as an amphibious creature
+fix message given when a monster tries to disarm your multiple welded daggers
+        with a bullwhip
+camera flash no longer stops at invisible monster
+monsters inside a stinking cloud should be blinded, just like the hero is
+vault guard shouldn't initiate conversation with you when you're hidden
+adult wolves are not small but lynxes are small
+turn off vision during a save operation to prevent impossible() from
+       triggering a crash
+rolling boulder trap's boulder susceptible to land mines and teleport traps
+polymorphing below level 1 should kill player (needed to fix max-HP abuse)
+prevent "obj not free" panic when shopkeeper cannot get to a thrown pick-axe
+give feedback if Sokoban prevents polymorphed player from passing through walls
+eliminate Wounded_legs enlightenment message when riding since it refers to
+       the steed's legs, not the hero's
+adjust the fumbling pick-axe message to reflect that the steed's
+       legs got damaged, not the hero's
+quaffing a noncursed potion of speed no longer heals the steed's wounded legs
+prevent mounting of steed when you have Wounded_legs to prevent abuse;
+       dismount does an unconditional healing of Wounded_legs during the
+       Wounded_legs context switch
+wounded legs on a steed doesn't count as a prayer trouble
+wounded legs on a steed doesn't abuse dexterity
+make wounded legs gained by falling off a steed consistent (dexterity loss)
+land mines while mounted should hurt the steed
+self-genocide while sitting on a throne should not refer to scroll of genocide
+eating dogfood or fixing a squeaky board conveys experience but didn't
+       check for gaining a new level
+demon bribes are 4x larger than they should be for co-aligned players
+specific monster warning no longer reveals the true monster name when you
+       use the '/' command while hallucinating
+start_corpse_timeout() now takes corpse age into consideration rather than 
+       always assuming a fresh corpse, thus fixing potential icebox abuse
+player on an immediate diagonal from a monster reading a scroll of earth
+       should be affected, just like monsters in similar locations
+objects that fall from monster's minvent as a result of monster polymorph
+       are not polymorphed, consistent with items that remain in minvent
+quaffing a potion of gain ability while wearing ring of sustain ability
+       displayed no message and identified the potion
+monsters still with WAITFORU strategy should not follow up/downstairs
+messages should reflect the fact that the Eyes of the Overworld mask the
+       effects of blindness
+Amulet of life saving should save you from sickness that will kick in this turn
+player should stop waiting when a monster uses a polearm from a distance
+avoid stone-to-flesh blood pooling message when zapping ice and not stone
+when polymorphed into a silent creature, do not "pronounce" scroll formula
+ensure hilite turns off immediately when pet stops being tame
+hitting with a polearm counts as hitting with a weapon for conduct
+traps detected while blind and levitating were not displayed
+when a mind flayer uses its mind attack, it should wake the victim
+shapechangers restored from disk would no longer change shape
+allow "tame" prefix when using the wizmode C-g command to create new monster(s)
+display a more appropriate name for a high priestess when using ;/ commands
+change "The water elemental is on fire" to "The water elemental is boiling"
+blind, cancelled or nonseen invisible Medusa cannot gaze at other monsters
+fix impossible when spinning web on falling rock, rolling boulder and fire traps
+rust monsters can only eat items made of rustable material
+wands of fire are no longer flammable no matter what material they are
+displacing you pet into a trap which kills it affects killer conduct
+pets can now be displaced in untended shops
+only show lit walls if, like doors, the position next to them is lit too
+charge for an unpaid weapon used for engraving
+shopkeeper should charge for unpaid balls and used candles in containers
+when swallowed you could drop or throw a cockatrice corpse into a 
+       monster's stomach without stoning it despite the guaranteed hit
+steed would often not respond to an attack, even if you didn't move that turn
+after stepping in a polymorph trap, a monster may pick up the wrong items
+breaking an unpaid wand of teleportation wouldn't result in the proper charge
+next_shkp() was used inconsistently, potentially triggering an endless loop
+chaotic wizards usually get a spellbook when crowned, just like neutral ones
+monk quest: fix the two inaccessible chambers on the locate level
+rogue quest: fix the four inaccessible chambers on the home level;
+       link the two inaccessible chambers on the locate level and provide
+       a means of escaping from them; on the goal level, link most
+       chambers together, resulting in just four disconnected regions,
+       and force stairs to be in a different region from the nemesis
+angels can fly
+under #twoweapon fix it so that only Stormbringer carries out the
+       blood-thirsty attacks, not both
+booby-trapped doors shouldn't make you stagger if you're riding
+encumbrance exertion checks should happen each time player moves
+mksobj_at: add way to suppress the chance of a new object being an artifact
+steed should be the one caught in a bear trap, even if player is polymorphed
+use a more appropriate message than "being held" when using < or > while 
+       swallowed or engulfed on stairs
+stinking cloud isn't useless and shouldn't be excluded from initial inventory
+shopkeeper will not try to buy food you are eating when inventory is full
+don't duplicate any gold inside containers when saving bones data
+can't tell between acid and holy/unholy water that burns like acid
+tame stuck monsters should release you after regaining their senses
+engraving Elbereth exercises wisdom, engraving anything else does not
+artifact bows get any special attack bonus added to missile to-hit roll
+monsters with gaze attacks should not try to blind the hero with potions
+players polymorphed into umber hulks should not try to eat boulders in Sokoban
+when a monster uses up a partially eaten food item, cleanup was not performed
+temple priests shouldn't be created with two robes
+give some quest leaders and nemeses equipment appropriate for their class
+mis-engraving "X" or "x" shouldn't violate illiterate conduct
+Heart of Ahriman now explicitly does double damage
+prevent NO_ATTK artifacts from accidentally doing double damage
+player polymorphed into monster that loses hp out of water should lose hp too
+make sure that all leashed monsters get released when bones data is saved
+eating a ring of levitation doesn't confer permanent intrinsic levitation
+silver hating monster using a bullwhip shouldn't snatch silver weapons into
+       its inventory
+fracturing one of several boulders at a location should not unblock vision
+don't hide stairs, thrones, &c under spider webs when creating levels
+rediscovering forgotten object types behaved differently depending upon
+       whether they had user assigned names at the time of amnesia
+taming while engulfed is limited to the engulfer
+restore blindness resistance to Archons
+if a shk is polymorphed into monster form which has Wizard-style tactics,
+       don't let him teleport to the stairs if he's inside his shop
+when the player digs a hole through a shop's floor, don't let shopkeeper
+       wander out of that shop while multi-turn digging is in progress
+don't protect alternate weapon and quivered objects against being taken
+       by shk who grabs your pack when you dig a hole through his shop floor
+add missing break to POT_WATER case in potionbreath()
+keep monster from forgetting its weapon is cursed every other round
+multiple shot throwing stops immediately whenever you hurtle backwards
+don't panic if being billed for a burning or other timed object
+food that makes a monster peaceful should not re-anger it at the same time
+abusing a leashed pet could result in a leashed peaceful monster
+couldn't unleash steed while mounted
+trying and failing to wield an item could leave current weapon flagged as both
+       "weapon in hand" and "alternate weapon" when `pushweapon' option is set
+handle OBJ_CONTAINED case for corpse revival so that trolls can revive 
+       from inside containers
+eating one of several merged partly eaten food items should take nutrition
+       from only one of them
+coyote names should not disable printing of "tame" or "peaceful"
+Eyes of the Overworld protect from stun effect of Archon's radiance attack
+give feedback when putting on or taking off the Eyes of the Overworld causes
+       blindness state to be toggled
+avoid spurious "you can see again" when temporary blindness being overridden
+       by the Eyes of the Overworld times out
+removing blindfold or lenses via 'A(' gives same results as via 'R'
+make blindness with just 1 turn remaining be a candicate for repair by
+       unicorn horn and healing potions/spells
+healing potions/spells shouldn't fix being creamed
+make pie throwing and venom spitting by the player be consistent with the
+       effects of those attacks by monsters
+offering & tinning corpses on altars should work even while riding
+It was possible to faint after eating a fortune cookie and still read
+       the fortune's text despite being unconscious
+when filling a pit containing a vortex, a surviving vortex gets untrapped
+teleporting no longer moves the iron ball to under you if that's not necessary;
+       prevents odd ball movement when crawling out of water
+monsters now prefer to wear speed boots over other boots
+prevent crash when loading a special level specifying a mimic using m_object
+prevent crashes caused by dropping or shipping quivered or secondary weapons
+don't trigger spurious encumbrance messages on last turn of a multi-turn meal
+prevent food being restored to untouched status if interrupted while eating
+troll revival shouldn't increment the troll creation counter
+breaking mirrors and your eggs should be bad luck when kicking chests as well
+       as throwing
+vampires should be G_NOCORPSE so you can't wish for them
+glass objects should break when thrown, just like when kicked in chests
+rocks/gems shouldn't be hard to throw by hand because they are ammo
+avoid all cases where splitting an object would result in two objects being
+       quivered, wielded or otherwise having its owornflag set
+allow 'a' prompt when dropping many objects in shop for credit (Wingnut)
+monsters who get polymorphed while wearing dragon armor turn into dragons
+shape changers can't be killed by system shock when hit by polymorph
+Chromatic Dragon has silver scales too (she reflects)
+being killed when wishing for an artifact should retain that item in bones data
+the drain life spell should not wipe out engravings (especially not using a
+       function that requires you to be able to reach the floor)
+monsters who can cast undirected spells don't need to be in combat with you
+       to do so
+messages consistent for all monster spells
+monsters casting spells at your displaced image now set mspec_used
+monsters without ranged spells don't print curse messages for ranged spells
+going down to floor using > should set Heart of Ahriman invocation timeout
+riding a steed into water kills the steed if it cannot swim, with penalties
+gaze attacks now stop occupation
+proper death message when killed by "plain" high priest
+don't conceal the identity of Moloch's high priest
+blessed full healing can't recover levels lost when polymorphing into new man
+blessed full healing can recover at most half of other lost levels
+golden glow when praying will recover lost level if blessed full healing could
+gaining a level while polymorphed increases current monst hit points as well
+       as latent human (or whatever) hit points
+pets should not try to go after food that they can't reach
+monsters shouldn't use wands of digging in Sokoban
+objects dropped in or travelling across lava pools can take damage
+monsters that enter lava can take damage
+eating an unpaid tin should calculate cost before not after eating
+spells shouldn't do negative damage
+when reading spellbooks, don't "continue studying" wrong book if original one
+       gets destroyed after previous reading attempt has been interrupted
+correctly handle polymorphed quest leader
+swallowing zombies/mummies whole makes you sick, like when eating them normally
+impose additional teleport restrictions on the no-teleport Plane of Air
+landmines set off by pushed boulders have same effects as stepping on them
+secret corridor detected out of vision range is still displayed (prevents bug
+       where wand of secret door detection found nothing but still identified)
+getobj can now see user-specified count when using inventory to make selection
+scalpel is stainless steel (i.e. METAL) not regular steel (IRON)
+eggs, potions & other breakables may break when they fall down stairs
+hurtling via grappling hook does not apply effects of destination location
+consider vortexes to be nonliving
+dragons have scales, not fur
+if player teleports a monster while swallowed on a noteleport level, the
+       player should not teleport along with the monster
+prefixes that can appear in any order when wishing should include +/- and empty
+don't allow untrapping of adjacent traps in locations you can't move to
+summoning should summon any alignment if summoner's base alignment is A_NONE
+when dipping unicorn horn in potion, the potion might change bless status, so
+       set bknown to FALSE
+grammar fixes such as "Eyes of the Overworld resists" and others
+score bonus was missing from scrolls of identify and fire 
+make wands of speed or slow monster known if their effect
+       on monsters is observed; likewise for speed boots
+gold detection "materially poor" message inappropriate if you have hidden_gold()
+cannot reflect back an invisible umber hulk or medusa's attack
+monsters with M3_WANTSBOOK often couldn't move in the Wizard-level
+Vlad should want the Candelabrum
+if you float_down on a trap in which you're already trapped, don't retrap
+applying whip toward hidden mimic displays mimic name before "Wait!" message
+stealing a container didn't multiply cost of stolen contained objects by quan
+halve air elemental damage to compensate for side effect of speed system
+strengthen Death; weaken Famine, Pestilence, and Demogorgon
+pet purple worms get nutrition from engulfing attack
+throwing an artifact upwards will trigger artifact hit effects when it falls
+being hit by Fire Brand stops the turning-into-slime process
+monsters hitting other monsters can split puddings with weapons
+be consistent with checking for iron weapons when splitting puddings
+prevent corpses of undead creatures just killed by undead turning from being
+       instantly revived by the same undead turning attack
+allow fake player monsters to handle artifacts that don't match alignment/role
+chaotic monsters can use Stormbringer; lawful monsters can use Excalibur
+No "corridor disappears" message if Vault guard dies off-level
+slip while mounting and levitating at will should not cause damage
+if you see a monster jump into a trap in a secret corridor, it's not secret
+fixed a few places where unblock_point wasn't called but should have been
+cloned monsters should have the same name and tameness as the original
+you should stop eating (etc.) if a monster attacks you and misses
+half physical damage should apply to gas spores
+iron bars should affect wall corner wallification
+potion of polymorph shouldn't be identified if object being dipped into
+       it ends up as the same type of object after polymorphing
+don't slap against the floor while riding and eating bad food
+got rid of "nori" (since it doesn't really translate "kelp frond" accurately)
+engraving in fog-covered location on in the Wizard quest said you
+       engraved in air, not dust
+dipping non-weapons into burning potions of oil had no effect
+dipping arrows into burning potions resulted in rust damage
+
+
+Platform- and/or Interface-Specific Fixes
+-----------------------------------------
+amiga: random crashes when opening menu window in fontmode eliminated
+amiga: proper action taken (cancel) when closing the menu window
+       with closegadget or escape
+amiga: allow #/altmeta combination on foreign keymaps
+amiga: prevent plname[] overflow from askname()
+amiga: prevent writing outside basewindow (bottom)
+amiga: tilemode tombstone corrected on cybergfx screen
+amiga: don't clutter levels/ with foo.0 when quitting at playerselection
+micro: prevent a guaranteed impossible() if we ever have more than (COLNO - 1) 
+       levels in the game
+micro: fix out of bounds memory modification for file opens via PATH
+msdos: placeholder tiles accepted by the thin tile builder
+tiles: use pixel-accurate grid bug tile for grid bugs
+tty: correctly dismiss 1-line menus
+tty: clear screen before version incompatibility message so it doesn't just
+    print the message overwriting previous screen text
+tty: pet was not always hilited
+tty: don't crash if the news file is present but empty
+unix/tty: give user a chance to see any error produced by (de)compression
+win32/tty: menus can take advantage of consoles larger than 80x25
+win32/tty: add support for inverse attribute
+Gnome: workaround for GTK+ attempts to disallow setgid executables
+Qt: honor user preferences in startup dialog
+X11: map not displayed in color when using X11 windowtype w/o tiles
+X11: viewport scrolling could scroll the the wrong place with resized window
+X11: allow extra space added to map widget to be removed if widget shrinks
+X11: general solution to the problem that the meaning of font height varies
+       among different implementations of X11
+X11: make "slow" mode the default since it seems to be very prevalent
+
+
+General New Features
+--------------------
+added travel command via '_' or mouse click
+config file processing detects multiple use of the same OPTION and 
+       prints a warning when it does
+make the player selection prompt more explicit in the information
+       that it is going to request
+remove curse now operates on cursed leashes that are in active use
+give feedback when shooting/throwing more than one missile at a time
+monsters can now deliberately eat dead lizards to cure confusion
+general warning now allows you to attack unseen monsters, as long as you can
+       see the warning glyph on the screen
+wand of fire & fireballs now burn webs
+wand of locking / wizard lock zapped down will close and remove trap doors
+exploding monsters wake nearby monsters
+various mindless, sphere monsters no longer need to breath
+sleeping gas no longer affects nonbreathing monsters
+vault guard doesn't notice you if you're mimicking gold
+good chance of untrapping monsters and pets caught in webs if you are 
+       polymorphed into a spider, and extremely small chance even if not
+stamina affects ability to throw heavy things
+objects merge in containers
+wishing for "nothing" yields no object and preserves wishless conduct
+genociding "none" destroys no monsters and preserves genocideless conduct
+coyote id naming shows only the true latin name if coyote is cancelled
+xorns can "speak" and can smell valuable metal
+if you find a trap but there is too much clutter to see it, have the
+       game display it temporarily until a keypress
+rename the Wizard of Balance to Neferet the Green
+double the number of messages that apprentices/guards utter, with 5 for
+       before the quest, and 5 after
+wizard mode ^G command can create monster by class, not just by name
+wizard mode ^G command takes a count
+kicking a sleeping/paralyzed steed now causes special effects
+allow overriding of the default boulder symbol via BOULDER option
+blessed scroll of detect food provides you with a one time ability to 
+       recognize food that may be harmful to you
+wizard mode WIZKIT config file option added to ease adding items to 
+       starting inventory for a debug session
+helping a sleeping/frozen monster from a trap might wake/unfreeze monster
+if the hero comes upon an obviously trapped monster the trap is considered seen
+thrown weapons that hit are now subject to passive damage
+locomotion-specific use of words, rather than just using "stagger"
+if you come upon a physically trapped, visible monster, you see the trap
+       too, without searching for it
+allow looking and pickup inside monster's stomach or interior when swallowed
+add body_part(STOMACH)
+pets like tame nymphs, et al, now only steal non-cursed items
+monks usually get a spellbook rather than a weapon when crowned
+blessed gold detection now detects anything made of gold, not just 
+       coins, including candelabrum and gold rings
+new T-shirt messages from Scott Bigham
+option to get rid of resistance 'sparkle' (shieldeffect) (Scott Bigham)
+option for autodig (Malcolm Ryan)
+glowing Sunsword (inspired by Slashem)
+msg_window option for ^P in TTY mode (Jay Tilton)
+ninjas should get multishot bonus with yumi and ya (Dylan O'Donnell)
+put prisoners in the Dark One's dungeon (Dylan O'Donnell)
+touchstones; Archeologists start with one
+add leather cloak so soldiers don't have elven cloaks
+add Tom Friedetzky's BUC-patch with some alterations to the original
+add wizard #poly and #levelchange (originally levelgain; Dylan O'Donnell),
+add Jason Short's additional lenses use patch
+add new Gnomish Mines levels from Kelly Bailey's patch
+add Ken Arnold's patch to show unpaid item prices in inventory
+jousting by players wielding a lance while riding
+Knights start with lance rather than spear
+can start game without a pet via pettype:none (Dylan O'Donnell)
+allow disclose options to be more finally tuned, including being able
+       to specify the default response for being prompted
+debug mode SPLEVTYPE environment variable to choose specific levels from
+       when there are random selections
+artifacts have individual prices
+new window-port preference options added, and some existing options
+       moved into the window-port preferences section
+made each of the end disclosure options customizable to "prompt;default no",
+       "prompt;default yes", "show it without prompt", and 
+       "don't show it and don't prompt"
+add female role level names "Medica ossium", "Magistra", "Chevaliere", "Dame"
+more feedback about skill advancement from #enhance command
+USER_SOUNDS compilation option to enable use of SOUND and SOUNDDIR variables
+       in the config file for user-specified sound clips for
+       user-specified, regex-based message patterns
+resistance does not protect inventory from artifacts (cold vs Frost Brand,&c)
+phrase the prompts for P and R commands using "put on" and "remove" as the
+       actions rather than repeating W and T commands' "wear" and "take off"
+dipping candles, et al, into burning potions lights them
+
+
+Platform- and/or Interface-Specific New Features
+------------------------------------------------
+amiga: screenmode requester
+amiga: 16 color font mode
+mac: command-key shortcuts in the player selection dialog
+vms: default compiler configuration in sys/vms/Makefile.* switched to DEC C
+win32: new graphical port contribution by Alex Kompel
+
diff --git a/doc/fixes34.1 b/doc/fixes34.1
new file mode 100644 (file)
index 0000000..9dfc5f7
--- /dev/null
@@ -0,0 +1,471 @@
+$RCSfile: fixes34.1,v $ $Revision: 1.331 $ $Date: 2003/02/20 00:19:46 $
+
+General Fixes and Modified Features
+-----------------------------------
+prevent panic() obj_not_free when pushing a boulder over a landmine
+there was no feedback when successfully hitting shock resistant monsters
+       with Mjollnir via hand-to-hand attack
+unbought single-bite food eaten in shops was not billed properly
+charge for shop contents inside "no charge" containers
+add wishing for "nothing" and genociding "none" to the conduct section
+       of the Guidebook
+allow both wishing and genocide to accept either "none" or "nothing" when
+       the player wants to decline
+left word in format string in get_wet() causing "The spellbook fadefades"
+two bad wizkit items in a row shouldn't make the user hit space many times
+kicking thrones no longer loosens rocks
+wall symbol not replaced when digging while blind and levitating
+increment FQN_NUMBUF from 2 to 3 to prevent premature reuse of a buffer
+       that caused a level creation error to be reported as a lock file error
+print regular death message when leashed, mounted steed dies of starvation
+fix more funny messages, new and old
+restore the behavior of bumping into closed doors when moving while impaired
+fix iron ball cases that could put the chain in solid rock
+discovering a mimic on a closed door location should not unblock the location
+don't drop corpse when a monster kills another monster on an inaccessible
+       location (i.e. behave like xkilled behaves)
+half-physical-damage from gas spore explosion should only affect you
+Sunsword didn't stop glowing when hero killed a monster wielding it
+mimics caught in explosions with messages printed about them are discovered
+let lev_comp and dgn_comp accept optional carriage return character prior to
+       the terminating newline in special level and dungeon description files
+Wizard of Yendor will start harassing you after the invocation if you've
+       managed to get that far without ever killing him
+characters polymorphed into centaurs can't wear boots
+if an unknown rolling boulder trap kills a monster, you shouldn't be a murderer
+touchstone entry in data.base
+specific message for engraving headstone with wand of digging
+wielded/quivered chained ball should be unwielded when thrown
+polymorphing into a form that cannot twoweapon should immediately disable
+       twoweapon mode; likewise when reverting from a monster form which
+       can use two weapons to a normal form which can't
+taking partial count of merged objects from a container while your pack
+       was full split the object and did not re-merge
+animal_parts are not always appropriate for ravens
+prevent panic if tombstone window cannot be created
+clarify travel command behavior in the Guidebook
+touch_artifact checks needed when snagging w/bullwhip and stealing
+cannot trip over submerged objects if you're water walking
+wand of striking was not identified if it activated a statue trap
+cannot sacrifice while you're swallowed
+player polymorphed into an eel cannot drown breathless/amphibious monsters
+avoid dmonsfree impossible message due to migrating a dead monster via
+       mhurtle causing the monster to end up in a hole or other trap
+avoid temporary disappearing Burdened message due to updating status line
+       midway thru in_container
+don't credit player's wisdom when makelevel creates random Elbereth engravings
+reduce insect/monster creation from monster spells and limit chain summons
+avoid "couldn't place lregion type 5" warning when arriving at Plane of Fire
+avoid crash due to delayed poly or were change no longer being valid
+ensure that Priest's ability to recognize B/U/C is considered in B/U/C menus
+can't push boulders through iron bars; traps can't roll such through either;
+       likewise for objects thrown by monsters
+thrown objects susceptible to breaking might do so when they hit iron bars
+assorted monsters can pass through iron bars; ditto for polymorphed character
+attempting to dig iron bars will wake nearby monsters instead of yielding
+       "you swing your pick-axe through thin air"
+autodig won't accept iron bars as candidate location
+allow knight to retaliate for all thefts except those "you gladly hand over..."
+randomize starting position on goal level for M, P, and S quests
+prevent the Wizard of Yendor from displacing the high priest of Moloch out of
+       the Sanctum's temple
+ATR_BOLD on spell menu header
+travel command should restrict its shortest paths to areas of the map the
+       hero knows about or might reasonably guess
+non-altar prayer should limit god action, not maximize it
+potions of acid explode, not dilute, so make water_damage behave this way
+lookat monster notes if you see monster is trapped
+don't crash when angry shopkeeper re-enters the shop and you pick up something
+monsters with WAITFORU strategy should act if successfully attacked by
+       non-damaging attacks (e.g. seduction, rust damage)
+don't summon kops if credit covers cost of unpaid goods taken out of shop
+update swallowed display immediately if an engulfing monster polymorphs
+       into another engulfing monster
+undo xname FAKE_AMULET_OF_YENDOR AD_DRIN check, the_unique_obj checks this case
+axes should chop trees; picks shouldn't
+chance to aim grappling hook when skilled or better
+level limit of monsters like naga hatchlings should be high enough to grow up
+scroll of enchant weapon will become discovered when read in some cases
+don't crash when using lookat on a boulder an BOULDER sym is unique
+attaching a single candle to fill candelabrum's last slot gave message with
+       poor grammar: "The candelabrum now has seven candle attached."
+vault guards won't ask who you are if you're unconscious or paralyzed
+monsters should not repeatedly try to teleport on noteleport levels
+crocodiles legs are not designed for kicking open doors, chests, et al.
+walls of one of the luckstone locations in minend-3 were diggable
+minetn-6 could place downstairs in a cut-off location
+corpses in bones files don't retain their role characteristic
+boulder was not displayed if blind and discovered with a monster known via
+       ESP behind it
+don't claim that statue comes to life if the monster it turns into is invisible
+fix goodpos() so worm segments don't get placed on top of each other (causing
+       a possible display problem if the worm is cut in two)
+fix fountain noises on some special levels (castle, valk home, various mines)
+disallow mounting a trapped steed to avoid inappropriate trap effects
+#chat with meditating monster will rouse it
+suppress redundant message when stoning effect transforms a golem
+clear worn bits of any object grabbed by shopkeeper to avoid extract_nobj panic
+looting any container on a location should suppress looting nearby monsters
+give more specific message when forbidden role attempts to use twoweapon mode
+avoid double billing if #loot causes a shop's bag of holding to explode
+when polymorphed, player killing a paper or straw golem via fire damage
+       would kill the golem twice, resulting in an impossible error
+usually stop mimicing if you polymorph while using #monster mimic capability
+under !GOLDOBJ, gold shouldn't disappear if you try to throw it at yourself
+under !GOLDOBJ, remove temp gold from inventory during restore
+Staff of Aesculapius did not always cure sliming
+correct singularization of fungi, liches, vortices
+prevent "remove_object: obj not on floor" panic for iron ball placement if
+       riding while punished leads to a fall off steed when changing levels
+specifying -D (or -X) to enter explore mode while restarting from a save
+       file was lost in the restore process
+fix crash when using lookat on an known invisible monster with monster syms set
+prevent getting stuck in infinite loop when using wizard mode #levelchange
+       command to reduce level while having level-drain resistance
+naming an already wielded elven dagger "Sting" activates warning against orcs
+naming either of the wielded weapons unintentionally ends two-weapon combat
+Various nemesis monsters must resist stoning so their death messages make sense
+don't call DEBUG impossible in rn2 when a level 0 monster tries to cast a spell
+GOLDOBJ: don't call money2mon with 0 zero when killed by shopkeeper
+headstone writing was using the adjective "weird" when engraving with a wand 
+       of digging.
+don't report "you were riding" if you die as a result of dismounting
+allow #untrapping of chests that are co-located with floor traps and hero
+unmap "I" symbols when searching while blind and levitating
+monsters that are frozen or sleeping cannot be grateful for untrapping
+grammar of blessed-detection eating warning messages when eating 1 of N objects
+message for charging for items lost in a cursed magic bag wasn't always shown
+dropping gold on an altar printed no message and didn't change gnostic conduct
+don't allow cursed daggers thrown by monsters to go thru closed doors
+hero polymorphed into an exploding monster should explode when attacking
+       thin air, just like the monster itself
+don't mark holes/trapdoors as seen if you levitate over them while blind
+player polymorphed as rust monster would lose gold in inventory by
+       attempting to eat it, even though the eat failed
+no messages were printed when dowaterdemon or dowaternymph failed to create
+       a monster doe to the G_GONE check
+knights should be able to avenge attacks from covetous monsters
+eating various rotten food items would not break vegan/vegetarian conduct
+unaligned special levels should inherit alignment from the dungeon
+Samurai quest was missing several doors
+Cancelled while polymorphed and Unchanging should provide feedback
+stone to flesh on a statue with contents would lose the contents if a
+       monster was on the same location as the statue
+steed movement would use your speed if walking step by step
+kicking a known, unseen monster would sometimes leave behind an extra I symbol
+applying a lance against a long worm could cause an impossible
+a knight applying a lance did not do a caitiff check
+blessed gain level when already at level 30 won't reduce experience points
+keep counting spell skill exercise even after expert status is reached
+when a fountain dries up or a throne vanishes, make sure it really happens
+allow player to name polymorph potion if nothing seems to happen
+avoid crash when drinking a potion causes the hero to float up over a fire
+       trap, for example, which might try to destroy the in-use potion
+in some situations, if hero stood still, a hostile dwarf would switch back
+       and forth between weapon and pick-axe and never move
+uncontrolled teleports did not handle leashed pets
+minetown fountain warnings shouldn't prevent finding gems/coins in fountain
+order of container and objects was different for mazelike and roomfilled levels
+minetown guards only enforce town rules inside the town proper
+electric damage heals hero polymorphed into flesh golem rather than iron golem
+fix bug preventing wishing for bear traps (not beartrap objects) in debug mode
+be notified about cessation of hallucinations even if blind and the time
+when using '/' to examine multiple map items in succession, don't mislabel
+       some with "or a splash of venom" after having looked at a '.' item
+martial arts kick that knocks a monster into a trap would result in warning
+       "dmonsfree: 1 removed doesn't match 2 pending" if the trap was fatal
+if you can't see or sense a monster when it dies, don't set dknown on corpse
+effect of wearing or removing the Eyes of the Overworld took effect on the
+       next move, but should take effect immediately.
+dragon scale mail is magic armor
+invoking or applying an artifact must pass a touch_artifact check
+document 'D'rop BUCX behavior in the Guidebook
+remove levitation boots over a portal, the portal teleport is delayed until
+        your next command is typed.
+armor vs cursed two-handed weapon anomalies: with 'T', couldn't remove armor,
+       but with 'A', could remove it, and with 'W', could put it on
+don't print ape data.base description for other words that end in "ape"
+prevent crash after animating a statue via stone_to_flesh by avoiding use
+       of the obj in newsym() after it was deleted
+print "magic spreads" message when eating ring of increase damage, etc.
+grammar tid: "The looking glass miss the <monster>."
+fix wishing for "looking glass" and "<color> glass"
+Archeologists suffer same alignment penalty for statue destruction by
+       stone_to_flesh as they do by other means of statue destruction
+being unable to see a vault guard doesn't prevent him from arriving
+in town, secret doors should be called "wall", not "fountain"
+in town, watch should not allow trees to be cut down
+cancel chat direction cancels the chat
+prevent "the mimic looks better" on an unrecognized mimic hit with
+       healing spell
+after forcefighting a concealed lurker, the lurker wouldn't fight back
+when polymorphed into a hider, cease hiding during level changes
+let mind flayer grow up into master mind flayer; also giant/sewer rat and
+       cave/large spider
+engulfing green slime as a purple worm was causing stoning not sliming
+zero entries in DUNGEON, MONSTERS, et al, of config file are now treated
+       as preserving the default rather than being ignored
+enlightenment: don't misreport polymorphed lycanthrope as "in beast form"
+remove TIMED_DELAY from the features checked for version compatibility
+rolling boulder hitting monster stuck in pit should stop even when mon survives
+don't see chest trap gas colors while Blind
+adjust fruit name in potion juice messages if it has the form "foo of bar"
+wielded camera passes harmlessly through shade
+reading spellbooks while confused should allow tearing the book
+Breaking wand of digging dug through rock which should be undiggable.
+Breaking wand of digging near shop walls wouldn't anger the shopkeeper
+Shop walls wouldn't be restored if there were pits in the way.
+If there were a hole outside a shop, you could kick stuff out of the door
+       into the hole without the shopkeeper noticing.
+curing hallucination while wielding Grayswandir should print a message
+removing unowned pick-axe from container in shop gave inappropriate message
+don't let monster end up with more current HP than max HP after life drain
+make sure that missing file trickery in wizard mode which is discovered during
+       level change doesn't try to keep going after discarding current level
+contribution by Adam Wozniak adds several const & changes some char* to char[]
+fix impossible when hitting/jousting a monster causes it to be killed twice
+fix a GOLDOBJ crash/hang in take_gold() that could be triggered by reading a
+       cursed spellbook, or by sitting on a throne
+kicking a tree could produce 0 to 4 killer bees but it should have been 1 to 5
+mounting a steed allowed hero to make moves that would otherwise be disallowed
+       including mounting diagonally in a shop doorway
+monsters lose intrinsic speed when pertrified
+if you have converted, the quest leader banishes you instead of asking you
+       to come back later, and tells you that you won't succeed without Bell
+don't state that "you narrowly avoid losing all chance" message if you try
+       to put on a helm of opposite alignment in the quest after converting
+fix enlightenment feedback for bonus or penalty on damage and chance to hit
+effects of purple worms consuming special monsters is now more consistent
+       across eating, digesting and dropped corpses while engulfed
+avoid "you finish disrobing" when disarming via the 'A' command
+make sure corpses and statues which remember monster attributes don't keep
+       ones that were conferred by no longer worn items (mainly speed boots)
+elevate the trouble priority of any cursed item which is preventing removal
+       of a ring of levitation
+starving pets will eat more aggressively
+when a pet starves to death, say so instead of just "Fido dies."
+starved pet raised from dead shouldn't immediately starve again
+skilled spell of detected treasure wasn't acting like blessed potion of
+       object detection (from Roderick Schertler)
+fix end of game attribute disclosure for levitation negated by sink
+kicking a box embedded in a wall will knock it free rather than bust it open
+stop running or travelling if the vibrating square message is triggered
+show correct gender in ^X display when polymorphed into non-humanoid form
+for wizard and explore modes, skip second screen of ^X output when first
+       screen is cancelled by ESC
+for wizard mode, override confusion when using ^F to reveal map
+polyself into minotaur causes hard headgear to fall off
+with multiple leashes in use, 2nd had 50/50 chance of having unbounded length
+GOLDOBJ: coins aren't subject to curses/blesses and don't need identification
+can no longer activate a figurine while engulfed
+can't use figurines to get too many erinyes or Nazgul
+include currently wielded weapon among the list of likely choices for 'w'
+likewise for currently quivered ammo among choices for 'Q'
+only include unknown gems as likely choices when applying known touchstone
+prevent mbodypart() from returning animal parts for lights
+removing a ring might relearn what it is after amnesia
+sleeping shopkeeper shouldn't talk to digging player
+give more specific feedback when dipping unicorn horns into potions
+can see self via infravision or ESP or monster detection when invisible
+class genocide that killed polymorphed self while `Unchanging' reported
+       incomplete cause of death and possibly left rest of class in bones
+class genocide of @ by human or elf character polymorphed into non-@ gave
+       "you feel dead inside" message twice
+unskilled rider who can't reach items on floor also can't dip into moat or
+       pool from flying steed
+when summoning nasty monsters, use new monster's type to decide if they can
+       be placed on boulders, et al, not the summoning monster's type
+don't display the "intones:" prefix when !soundok since the message suffix
+       won't be displayed in this case
+document "sound" option in Guidebook
+destroy traps that are buried by boulders dropped in water
+renamed debug commands: light sources -> lightsources,
+       monpoly_control -> monpolycontrol, poly -> polyself
+detect attempt to swap places with big pet through narrow opening
+stinking clouds in bones files do not get their ttl set reasonably
+stinking clouds in bones files may incorrectly set player_inside
+breaking wand of digging on a drawbridge shouldn't dig/hole a pit in the bridge
+avoid mimicking gold when the character has the Unchanging attribute
+handle polearm wielded prior to mounting the same as one wielded while mounted,
+       and one still used after dismounting like one wielded while not mounted
+non-lawful angels don't chat using lawful messages and shouldn't summon
+       lawful help
+cancelled yellow lights should not explode against other monsters, as well as
+       not exploding against you
+becoming confused, eg from nausia, while reading a spellbook should result
+       in the usual confusion effects
+teleports should not be controlled if you're stunned, confusion should have
+       some effect on your ability to control level teleports
+vault wall repair should remove traps subsequently created at affected spots
+don't reveal deity name when a high priest(ess) gives temple entry greeting
+for ordinary remove curse, don't uncurse quivered object unless it is suitable
+       to be used as a quivered weapon (ammo or missile)
+salamanders have no legs and cannot ride
+all objects carried by a monster who's hit by a polymorph zap are protected
+       from that zap, not just worn armor which falls off due to shape change
+sparkle option for display effects was ignored on explosions
+level teleport while on a sleeping steed caused panic and possible crash
+breaking wand of digging causing a shopkeeper to fall left unpaid items unpaid
+use get_adjacent_loc() rather than getdir() directly for some things where
+       you want to ensure valid adjacent coordinates are returned
+minor experience calculation tweaks
+level telporting out of the dungeon while carrying unpaid shop goods would
+       trigger "not on any bill" warnings during final inventory disclosure
+only hard helmets protect against falling piercers
+don't crash teleporting out of a monster while engulfed, punished but not
+       carrying the ball
+web breaking should consider steed strength and other characteristics
+various missing or inappropriate "killed by" death messages
+second attack for two-weapon combat will miss if first knocks target away
+jousting effect no longer occurs every time riding character hits with lance
+skeletons should be able to wear the armor they're created with
+bouncing zaps should not bounce around the edge of closed doors
+mimics that are detected but not seen should not display as their mimiced
+       form when the detection ends
+not all cavemen are human, so avoid using human in quest messages
+tengu is singular and plural, some rumors were incorrect
+don't let leader or nemesis be renamed
+non-moving monster are not affected by liquid
+'A' command wouldn't remove cursed item from quiver or alternate weapon slot
+'A' command behaved differently depending on menustyle when non-weapons were
+       present in the quiver or alternate weapon inventory slots
+most cases of the hero dropping things need to check for dropping on an altar
+zapping undiggable trees with wand or spell of dig gave feedback about rock
+being able to see invisible shouldn't cause you to not notice when potion
+       or spell of invisibility wears off
+can't successfully bribe a demon who happens to be carrying the Amulet
+while over water, killing a monster that had engulfed you does not result
+       in the usual water effects
+removing a ring of levitation while engulfed should not invoke spoteffects
+feedback from invoking Orb of Detection was sometimes misleading or wrong
+ranger quest artifact (Longbow of Diana) confers reflection when wielded by
+       monsters like it does for the player
+avoid discrepancies in size and associated armor-wearing ability between 
+       wizard gnome player and same player polymorphed into gnomish wizard 
+       by forcing newman() if poly-target matches your_race()
+add missing data.base entries for caveman, healer, monk, priest, and samurai
+allow "grey spellbook" as alternative spelling of "gray spellbook"
+handle attacks by cancelled monsters more consistently
+armor worn by monsters might negate some magic attacks like it does for hero
+give feedback and discovery when visible monster puts on cloak of invisibility
+really add artifacts inside carried containers to final score (3.3.1 fix
+       displayed them them but didn't include any points for them)
+drop alternate weapon to terminate twoweapon combat if the alternate 
+       weapon gets cursed
+restore monster creation sanity checks to wizard mode ^G command
+prevent recoil from hurtling you through narrow areas that you wouldn't
+       be able to move through intentionally
+grammar in cause of death when killed by slipping while mounting named steed
+ensure `m'enu is still an available traditional menu choice for 
+       menu-upon-request even when there is only one class of object present
+engraving on headstone will appropriately dull your weapon
+certain types of golems should not "catch fire" so adjust the messages
+no longer need to manually examine inventory after regaining sight in order
+       to give a type name to an object picked up while blind
+when adding an object to inventory, it is possible for it to becomed both
+       wielded and quivered if it merges with weapon and autoquiver is enabled
+include rocks as likely candidates for quivering if alternate weapon is a sling
+Asmodeus fails an is_armed() check, so code in m_initweap() to give him wands 
+       of fire and cold never got called; move the code to m_initinv()
+#rub would wield the target tool even when already being worn as eyewear
+monks lose their to-hit bonus for bare-handed attacking if wearing a shield
+fix case on leading character in "Crunched in the head..." in ball.c
+using travel mode to move next to a known trap and then trying to step onto
+       that trap required an extra step; the first one ended up as a no-op
+punished with ball and chain on the same floor square as a trapped chest
+       when it exploded resulted in panic "remove_object: obj not on floor"
+see_monsters() wasn't called when you lost the innate warning intrinsic due
+       to level loss
+xorns sink if the drawbridge they're standing on is raised
+applying figurines to an adjacent spot over water does drowning checks
+fix sequencing of Magicbane's hit messages
+avoid buffer overflow from long or too many -s params
+wake up first if trying to crawl out of water while asleep
+while waiting, don't try to change into were form when already in were form
+steed should remember traps encountered while mounted
+killing shopkeeper by throwing unpaid things would result in
+       "item not on bill" impossible error
+choking pet to death with cursed leash incurs various pet-killing penalties
+wielding Werebane prevents catching lycanthropy via monster attack (but not
+       via eating, nor does it cure an existing case)
+character inflicted with lycanthropy is vulnerable to Werebane when in
+       human/elf/&c form as well as when in beast form
+shopkeeper could get angry without remembering the customer name
+any object held by ghost during recorporealization would cease to exist
+       including the Amulet of Yendor
+harassing monsters will be less likely to teleport to your location while
+       they're running away from you
+randomize warning symbols during hallucination
+
+
+Platform- and/or Interface-Specific Fixes
+-----------------------------------------
+wince: added Windows CE port from Alex Kompel
+win32: win32 build no longer defines MICRO
+win32: allow error save files to be generated
+win32: strip illegal file name characters from plname and replace with '_'
+win32: don't let recover build a save file out of level files belonging 
+       to an active NetHack.exe or NetHackw.exe process
+win32,winCE: SELF_RECOVER to let NetHack itself recover aborted games
+win32gui: make error() work; it was essentially non-operative in 3.4.0
+win32gui: fix alignment of columns in menu windows
+win32gui: Window menu File|Save worked during #quit disclosure processing
+win32gui: make mswin_yn_function() case insensitive like the tty version
+win32gui: In msg window, gray out lines that are old and concatenate msgs
+win32gui: --More-- prompt if there are more messages than can fit this turn
+win32gui: flicker reduction because clear_nhwindow no longer redraws window
+win32gui: A caret bug was fixed
+win32gui: fix bug that caused two lines too many to be drawn on each paint
+win32gui: last line no longer highlighted
+win32gui: reduce the number of popups and support for !popup
+win32tty: honour the use_inverse option and default to ATR_BOLD if disabled
+win32tty: respond only to mouse clicks not mouse movement
+win32tty: allow ^C to abort the game at the "Who are you?" prompt
+win32tty: fix truncated score list
+win32tty: prevent ALT+CTRL from sending NUL to core with the meta bit set
+win32tty: international keyboard handling improved by letting ToAscii()
+       generate input char based on VK and state of shift and caps lock
+Gnome: add support for non-square tiles
+Gnome: destroy main game windows correctly
+Gnome: Dylan Alex Simon's port of KDE-style worn window
+Gnome: Dylan Alex Simon's port of KDE-style hero cursor color
+Gnome/Linux: more portable getres*id workaround
+X11: restore support for non-square tiles when USE_XPM is defined
+X11: getlin dialog got steadily narrower each time it was used
+msdos: compiling without NO_TERMS resulted in a link-time error
+msdos: reworked Makefile.GCC to get rid of need to duplicate source files
+msdos,win32: stop doing chdir when NOCWD_ASSUMPTIONS is defined
+tty: remove #define DEBUG that forced debug behavior in production builds
+tty: correctly handle an empty TERM environment variable
+tty: don't lose messages when ESC has canceled their display
+tty: clear topl after pickup_burden prompt
+tty: support terms where turning off inverse video turns off color too
+tty: object selection at --More-- prompt after '?' didn't work anymore
+tty: ext command autocomplete now lets you enter auto-completed characters
+non-tty: silently ignore tty msg_window option to allow sharing of config file
+unix: install recover command into GAMEDIR by default
+vms: prevent error() from indirectly triggering hangup save during forced exit
+
+
+General New Features
+--------------------
+lootabc option
+runmode option
+showrace option
+travel option
+cmdassist option to provide additional error feedback for some commands
+mouse_support wincap option
+scroll_amount wincap option to adjust how many cells to scroll at scroll_margin
+debug mode: #panic routine to test panic() and panic save file generation
+a new PANICLOG optional file to log the reason for panic and impossible messages
+added validate_prefix_locations() for early directory prefix validation
+fire traps are particularly bad for paper and straw golems
+cream pies can be 'a'pplied to cause direct temporary blindness
+eating newt corpse or tin of same can boost magical energy (Malcolm Ryan)
+applying a eucalyptus leaf produces a whistle effect (Malcolm Ryan)
+hobbits can wear elven mithril-coats
+eating mimics now has an hallucination effect
+prefix pickup command with 'm' to force menu of all objects present
+provide feedback which states the correct command when players try to use 
+       'R' or 'P' for armour, or use 'W' or 'T' for accessories
+optional #portdebug wizard mode command to invoke port-specific debug routines
diff --git a/doc/fixes34.2 b/doc/fixes34.2
new file mode 100644 (file)
index 0000000..a9e0c85
--- /dev/null
@@ -0,0 +1,180 @@
+$RCSfile: fixes34.2,v $ $Revision: 1.2.2.130 $ $Date: 2003/08/26 15:13:56 $
+
+General Fixes and Modified Features
+-----------------------------------
+avoid panic when secondary weapon is cursed while generating bones level
+don't crash when applying a figurine, candle, or bell that gets used up
+grammar bits
+two invisible monsters hitting one another should not be visible
+if only one monster in a monster-vs-monster fight is visible, show an I symbol
+       for the other one whether it is an attacker or defender
+display "It" and not "The invisible <pet>" when an invisible pet eats food.
+include a hint about expected input when prompting for musical notes
+don't report "program initialization failed" if a panic occurs after the
+       game is over
+include statue contents in end of game inventory disclosure
+treat handlessness as a major problem when deciding prayer outcome
+perform artifact touch checks when putting on accessories
+missing noun in message when horns pierce through your helmet
+don't use hcolor() for trapped chest gases when you aren't hallucinating
+the age of a potion of oil from a bones file wasn't being handled correctly
+putting gold in a container on the shop floor wasn't credited the way
+       gold already in the container when dropped was credited
+avoid integer division rounding error when calculating carrying capacity
+don't lock/unlock a door while in a pit, to be consistent with door opening
+infravision should not make invisible player "visible" (it doesn't for monsters)
+Perseus statue should always be male
+charge correctly when breaking multiple objects with the same zap, avoids
+       a dopay: not to shopkeeper impossible
+clean up funny lighting on the healer locate level
+allow all tame monsters that eat to consider food thrown to them
+the screen display wasn't always up to date after map topology changes
+jumping over a sokobon pit would result in the player next to, not in, the pit
+don't let arrow, rock or dart traps provide an infinite number of objects
+make enhanced ammo harder to break to make lesser number last longer
+dropping from height or throwing a normal container may damage contents
+some Magicbane messages treated "erinys" as plural
+initialize artifacts before processing $WIZKIT
+clean up inconsistency between various places quaff is documented
+is_damageable was using is_rottable incorrectly
+charge for use of an unpaid tinning kit
+avoid impossible when water freezes while hero is hiding under water
+avoid impossible after eating the object the hero is hiding under
+failed attempt to eat floor gold while polymorphed would lose the gold
+running that stops for closed doors should stop at mimics mimicking closed doors
+allow wishing for magenta potions (ignoring the rank name 'mage')
+fix an uninitialized memory access in non-quick dolookup
+fix were changing message that wasn't being displayed
+immediate encumbrance feedback when removing gauntlets of power
+make deliberately flying down the Castle's trap doors consistent with falling
+give more explicit feedback for exploding bag of holding
+help display for "list of game options" misformats runmode and scroll_amount
+pit created by land mine explosion doesn't start out concealed
+update map display sooner when pushed boulder triggers land mine explosion
+prevent several QBUFSZ sized buffers from overflowing and triggering fatal 
+       errors inside window port prompt routines
+make sure that leashed monsters are released prior to shopkeeper inheriting
+       dead character's inventory
+attaching long named candle to long named candelabrum caused buffer overflow
+when polymorhed, only hand/weapon attack on disenchanter should result in
+       damage to weapon, gloves, etc.
+killer should say "the" when choking on unique monster's corpse
+allow applying polearm on monster you can see via infravision
+killer reason shouldn't use "a" or "an" prefix for multiple projectiles
+       scattered by land mine explosion
+killer reason for named missile could end up with garbage instead of the name
+make killer reason for various poisioning deaths be more consistent
+poison missiles were unintentionally more likely to inflict "deadly poison"
+       than in pre-3.4.1 releases
+provide feedback when going invisible after eating a stalker
+killer on tombstone had no prefix for starvation/exhaustion case
+ensure proper message ordering for boulder trap messages
+clean up data set by join_map that is overlaid by MAPs on special levels
+clarify disclose option default in opthelp, and support "all" as old help said
+add more calls to update_inventory as the inventory changes
+don't charge for items picked up from monster's interior while swallowed
+choking while eating non-food always called the food "quick snack"
+short swords are not throwing weapons
+several sit-in-trap cases were unreachable
+curse candelabrum in bones, like other similar artifacts
+detecting a trap in a chest while confused should not exercise wisdom
+any golem statue hit with stone-to-flesh spell animates as flesh golem
+correct invalid startup gender selection
+can no longer untrap floor containers during unskilled riding
+can no longer easily set land mines and bear traps during unskilled riding
+refine cmdassist handling for armor vs accessories
+prevent monsters from level teleporting out of the quest into the main dungeon
+prevent monsters from level teleporting into the Sanctum prior to invocation
+"m," command sequence would let you see all objects at a location even when 
+       they included a cockatrice corpse which hero was unequipped to handle
+use correct pronoun for unique monsters
+hostile monsters who follow you between levels won't do so if they're fleeing
+options for font_size for map, menu, message, status, and text all had the 
+       same description of "the size of the map font" in options.c
+when dismounting by choice and unimpaired, try not to land in a known trap
+when jousting a pudding into a polymorh trap, it was possible to end up
+       with two of the new type of monster
+don't allow polymorphed player to web over the stairs
+geographical shopkeeper updates
+stethoscope use should be free the first time it's use per player move
+travel command caches last position to make non-mouse less painful
+update pit trapped time when polymorphing to or from a monster that passes_walls
+show artifact hit message which affect the monster that swallowed the hero
+revived pet corpse from bones file should not be loyal to current player
+finding a statue trap you are about to dig should stop your occupation
+try to keep saddle at the same location as the steed corpse
+never display I symbol on the mounted hero/steed location
+pit digging is no longer stopped by a sleeping monster next to you
+ensure mksobj() always attaches timer to corpse, even if called with init FALSE
+only charge for eating one stacked tin, not all at once
+add flag to makemon() to allow monster to be created adjacent to the supplied 
+       coordinates if there is already a monster at the target location
+stone-to-flesh of spot with multiple statues can animate more than one
+use of stethoscope now deliberately impacted when hero is engulfed by whirly 
+       monster but fixed so it can sometimes work on your steed there too
+typos fixed in data.base
+add looting freehand() check to able_to_loot() to prevent opening container
+       only to be told that you can't loot anything
+Schroedinger's Cat could be placed at wrong location when its box is carried
+travel while polymorphed into a grid bug should not move diagonally
+refine cmdassist handling for grid bugs
+when casting force bolt spell while engulfed go ahead and use the engulfers 
+       name in the hit message rather than "it"
+a fog cloud shouldn't pummel you with debris
+do not let an attached iron ball drag the hero through a location that the hero
+       could not move normally
+hero's appearance should change immediately after mimicing completes
+avoid some uses of "it" in killer messages
+avoid "singular of null?" warning for info lookup of obscure user input
+there was no check for iron bars in dokick() so it defaulted to "empty space"
+if you couldn't see the rat created in a sink for some reason other than
+       blindness, you would get "Eek there's it in the sink."
+digging a pit while stuck in the floor should always free the player
+quest guardians can no longer be created via stone-to-flesh on their statue
+stone-to-flesh no longer silently ignored by a statue of a unique monster
+wishing for quest guardian corpse now gives a generic corpse of the species
+prevent quest guardians from other classes from talking to you as if they 
+       were your quest guardian
+wake up shopkeeper if a shop transaction is attempted while he's immobilized 
+statues created from monsters remember more monster attributes
+
+
+Platform- and/or Interface-Specific Fixes
+-----------------------------------------
+Gnome: compilation problems on Redhat 7.2 and 8.0
+unix: Makefile.utl would put OBJDIR objects in the wrong directory
+vms: create an empty paniclog file during playground installation
+win32tty: add subkeyvalue option to alter key values; Finnish keyboard fix
+win32tty: distinguish between black/gray/white (by Quietust)
+win32gui: prevent male Valkyrie and other incorrect startup settings
+win32gui: allow numeric quantity count on item selection during loot
+win32: some code in files.c was incorrectly assuming that a file
+       descriptor return value of 0 from open() was invalid but it 
+       could be valid on win32gui where stdin, stdout, stderr aren't open;
+       now it correctly checks for return value < 0 from open() 
+tiles: high priest tile had a couple bad pixels
+tiles: bad pixels in Croesus and Yeenoghu tiles
+FreeBSD: incorrect srandom declaration
+unix: don't autosave if hangup occurs after game is over
+linux: add example use of nroff on recent Linux distros
+linux: use random() by default instead of lrand48()
+OpenBSD: time() prototype and correct default Mail program
+Gnome: compilation problems on Solaris
+unix: better error message for .nethackrc access problems
+vms: during installation, warn if dlb file creation or non-dlb playground
+       setup is missing expected data files
+
+
+General New Features
+--------------------
+debug mode level teleport menu via '?'
+
+
+Platform- and/or Interface-Specific New Features
+------------------------------------------------
+win32tty: keystroke handlers can be dynamically loaded to assist in resolving
+       internationalization issues
+win32tty: add Ray Chason's code for international keyboard handling
+Solaris (and other SystemV variants): TIMED_DELAY support
+X11: NetHack.ad is now installed and used w/o user intervention
+
diff --git a/doc/fixes34.3 b/doc/fixes34.3
new file mode 100644 (file)
index 0000000..e63f65b
--- /dev/null
@@ -0,0 +1,146 @@
+$RCSfile: fixes34.3,v $ $Revision: 1.1.2.99 $ $Date: 2003/12/06 14:07:57 $
+
+General Fixes and Modified Features
+-----------------------------------
+monster draining the player using Stormbringer decreased monster's hitpoints
+polymorphing to a flaming sphere should cure slime like other flaming monsters
+grammar, spelling and other typos
+wishing for student corpse yielded a valkyrie one, not an archeologist one
+fix typo in bustling town down stairs declaration
+you could exceed the limits on nazgul and erinys counts via bones files
+fix inconsistency where you can't kick something out of a pit, but you can
+       escape the pit and still pick it up; items are now assumed to be at 
+       the bottom of pit
+room cleanup, eg on Bustling Town, could incorrectly truncate room bounds
+       for rooms that become L shared due to partial overlap with the MAP
+approaching Medusa while having reflection+invisibility+esp would cause her
+       to turn herself to stone if you happened to be blind at the time
+Master Kaen's death message was not appropriate
+missing fountain tag in minend-3
+do not pacify shopkeeper when the hero enters a shop if that hero previously
+       angered the shopkeeper without ever visibly entering the shop
+attempting to place migrating monsters onto a monster-saturated level no
+       longer triggers impossible()
+open_levelfile_exclusively() was showing the return value -1 in a panic message,
+       even though that was the only possible value; show errno instead
+it was inappropriate to have a ghost "appear" in desecrated temple when 
+       you were blind and without telepathy
+accept wish for "grey spell book" not just "grey spellbook"
+do not double credit when putting gold into an unpaid container
+manes are nonliving
+poles and grappling hook worked thru walls when wearing Eyes of the Overworld
+more tweaks to fog cloud behavior
+when dismounting by choice and unimpaired, try not to land on a boulder
+casting stone-to-flesh on self while wielding a statue caused problems
+add tab support to menu strings for control-x minimal_enlightenment()
+if the monster that a statue represents is not made of flesh then don't
+       allow stone_to_flesh to animate it, make a meatball instead
+attempting to saddle a cockatrice while wearing gloves shouldn't stone you
+kicking a closed drawbridge and dieing should not say "kicking a wall"
+cannot get blessed potions from sink, remove unreachable message
+couldn't insert gold into a container using full menu style if no other
+       objects in inventory unless compiling with GOLDOBJ
+nagas eat
+always have warriors on the Valkyrie quest be female
+be more consistent with sounds when dropping into water
+surface() returns "bottom" when Underwater
+bill for all discarded, opened tins
+monsters that cannot pick things up cannot throw things either
+eating an amulet of unchanging un-changes you
+Vlad won't waste time trying to use wand of digging in his own tower
+non-weapon iron objects should rust when dipped in fountains since
+       iron weapons rust
+suppress "turn to flee" message if monster is mfrozen
+don't silently interrupt monster's hold on you if Levitation/Flying ends
+       while over water
+you could specifiy '~' with crystal ball and have it try to detect monsters, 
+       but it never revealed anything; show the entire long worm now
+allow a crystal ball to detect ghosts-and-shades via space key,  and display
+       the results using detected_mon_to_glyph() so that they show up in 
+       inverse video
+allow a crystal ball to detect boulders using the user-defined boulder symbol
+allow a crystal ball to detect mimics via ']'
+prevent boulder option from accepting a symbol that matches a monster symbol
+traveling while standing on a trap would sometime step in the wrong direction
+avoid traveling into water/lava, using usual running rules
+unchanging iron golem would still rehumanize in a rust trap
+fix an impossible rndmonst: bad `mndx' bug
+pets should not try to go after objects that they can't reach
+cutting a shopkeeper polymorphed in to a long worm would generate strange
+       messages and could cause a crash
+reading a cursed scroll of light in a corridor wouldn't display correctly
+       if lit_corridor option was disabled
+barbarians can become export in short sword skill
+samurai are now limited to master in martial arts skill; barbarians and
+       cavemen are now limited to master in bare-handed combat skill
+tweak messages when werefoo summons help
+when polymorphed into a quantum mechanic, it was possible to jump into
+       the water on a no teleport level and instinctively teleport
+when polymorphed into a quantum mechanic on a no teleport level and swallowed,
+       no feedback was given when you teleported the swallower away
+allow Conflict-resistant monsters to respond to conflict attacks rather than
+       sitting there and taking the attacks until they die
+prefer herbivorous stone-to-flesh message when hero is a vegitarian
+try even harder to avoid incorrect map display while changing levels
+no "freaked" message by exploding black light, unless you really are
+sleeping monster could respond to attacks by other monsters
+sleeping shopkeeper responds to various events without waking
+rotting corpses grammar fix
+allow successful teleport to more locations on debug mode level teleport menu
+trapped monster repeatedly switched between ranged and hand-to-hand weapon
+silver items such as wands avoided all the silver checks in hmon_hitmon()
+resuming an interrupted 'A' command could cause crash if pending worn item(s)
+       were stolen or destroyed
+resuming interrupted 'A' sometimes ended with "You finished disrobing" twice
+when you're asleep you shouldn't "notice" monsters that have become undetected
+must be able to reach floor in order to use stethoscope on corpse or statue
+fix a few coordinate (y,y) -> (x,y) typos in apply.c, mon.c, and wizard.c
+killing a long worm on a drawbridge could produce a panic
+prevent "see it drop from your pack" when figurine monster becomes undetected
+attempting to drop a subset of a stack of multiple cursed loadstones could
+       corrupt inventory or cause a crash
+"miss" message was missing for thrown or kicked gold not caught by a monster
+prevent recursive impossible() and panic() calls from leading to a stack overflow
+tainted meat didn't invoke cannibalism
+shopkeepers can't act as porters for the Amulet
+dismissed monsters can't remove special items from play
+
+
+Platform- and/or Interface-Specific Fixes
+-----------------------------------------
+win32tty: fix visible CRLF characters during lockfile error message
+win32tty: switch to low level console routines
+win32tty: refrain from cursor movement until an input is pending (M. Lehotay)
+win32tty: distinguish blue, bright blue, cyan, and bright cyan (Nicholas Webb)
+win32tty: fix hanging problem when you ctrl-C at "Who are you?" prompt
+win32gui: you couldn't specify an alignment in defaults.nh and have it stick
+win32gui: allow race/gender/alignment selections beyond those specified in
+       defaults.nh, while still honoring defaults.nh choices
+unix: don't define errno if NHSTDC
+unix: save file permissions could be wrong in explore/debug mode
+X11: avoid a possible crash when using window manger to close a player
+       selection window
+Gnome: add Quiver menu item, fix outdated Quit menu item
+Gnome: key values on unsigned char platform could fail to compare correctly
+Gnome: real extended command menu so all extended commands can be entered
+Gnome: ignore interrupts to avoid infinite loop in gnome library
+tty: avoid crash displaying quit inventory if inventory was already displayed
+tty: use "bold" in menu heading if available and requested
+tty: differentiate between default unlit and lit corridor symbols
+winCE: ensure orphaned lockfile is always deleted on single-user handhelds
+
+
+General New Features
+--------------------
+bones file compatibility info is now written into the dat/options file
+extend autodig to work downwards via '>'
+make attribute that is used to distinguish headings in a menu configurable
+add experimental build option AUTOPICKUP_EXCEPTIONS for filtering pickup of
+       items by pattern matching against their doname() description
+include version number in paniclog entries
+add a section on "shops and shopping" to the Guidebook
+
+
+Platform- and/or Interface-Specific New Features
+------------------------------------------------
+
diff --git a/doc/lev_comp.6 b/doc/lev_comp.6
new file mode 100644 (file)
index 0000000..c661582
--- /dev/null
@@ -0,0 +1,572 @@
+.TH LEV_COMP 6 "16 May 1996"
+.UC 4
+.SH NAME
+lev_comp \- NetHack special levels compiler
+.SH SYNOPSIS
+.B lev_comp
+[
+.B \-w
+]
+[
+.I files
+]
+.PP
+If no arguments are given, it reads standard input.
+.SH DESCRIPTION
+.PP
+.I Lev_comp
+is a special level compiler for NetHack version 3.2 and higher.  It
+takes description files as arguments and produces level files that can
+be loaded by NetHack at runtime.
+.PP
+The purpose of this tool is to provide NetHack administrators and
+implementors with a convenient way for adding special levels to the
+game, or modifying existing ones, without having to recompile the
+entire world.
+.PP
+The
+.B \-w
+option causes
+.I lev_comp
+to perform extra checks on the level and display extra warnings, however
+these warnings are sometimes superfluous, so they are not normally displayed.
+
+.SH GRAMMAR
+.PP
+.LP
+.nf
+.ta +8n +8n +8n +8n
+
+file           : /* nothing */
+               | levels
+               ;
+
+levels         : level
+               | level levels
+               ;
+
+level          : maze_level
+               | room_level
+               ;
+
+maze_level     : maze_def flags lev_init messages regions
+               ;
+
+room_level     : level_def flags lev_init messages rreg_init rooms corridors_def
+               ;
+
+level_def      : LEVEL_ID ':' string
+               ;
+
+lev_init       : /* nothing */
+               | LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled
+               ;
+
+walled         : BOOLEAN
+               | RANDOM_TYPE
+               ;
+
+flags          : /* nothing */
+               | FLAGS_ID ':' flag_list
+               ;
+
+flag_list      : FLAG_TYPE ',' flag_list
+               | FLAG_TYPE
+               ;
+
+messages       : /* nothing */
+               | message messages
+               ;
+
+message                : MESSAGE_ID ':' STRING
+               ;
+
+rreg_init      : /* nothing */
+               | rreg_init init_rreg
+               ;
+
+init_rreg      : RANDOM_OBJECTS_ID ':' object_list
+               | RANDOM_MONSTERS_ID ':' monster_list
+               ;
+
+rooms          : /* Nothing  -  dummy room for use with INIT_MAP */
+               | roomlist
+               ;
+
+roomlist       : aroom
+               | aroom roomlist
+               ;
+
+corridors_def  : random_corridors
+               | corridors
+               ;
+
+random_corridors: RAND_CORRIDOR_ID
+               ;
+
+corridors      : /* nothing */
+               | corridors corridor
+               ;
+
+corridor       : CORRIDOR_ID ':' corr_spec ',' corr_spec
+               | CORRIDOR_ID ':' corr_spec ',' INTEGER
+               ;
+
+corr_spec      : '(' INTEGER ',' DIRECTION ',' door_pos ')'
+               ;
+
+aroom          : room_def room_details
+               | subroom_def room_details
+               ;
+
+subroom_def    : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill
+               ;
+
+room_def       : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill
+               ;
+
+roomfill       : /* nothing */
+               | ',' BOOLEAN
+               ;
+
+room_pos       : '(' INTEGER ',' INTEGER ')'
+               | RANDOM_TYPE
+               ;
+
+subroom_pos    : '(' INTEGER ',' INTEGER ')'
+               | RANDOM_TYPE
+               ;
+
+room_align     : '(' h_justif ',' v_justif ')'
+               | RANDOM_TYPE
+               ;
+
+room_size      : '(' INTEGER ',' INTEGER ')'
+               | RANDOM_TYPE
+               ;
+
+room_details   : /* nothing */
+               | room_details room_detail
+               ;
+
+room_detail    : room_name
+               | room_chance
+               | room_door
+               | monster_detail
+               | object_detail
+               | trap_detail
+               | altar_detail
+               | fountain_detail
+               | sink_detail
+               | pool_detail
+               | gold_detail
+               | engraving_detail
+               | stair_detail
+               ;
+
+room_name      : NAME_ID ':' string
+               ;
+
+room_chance    : CHANCE_ID ':' INTEGER
+               ;
+
+room_door      : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos
+               ;
+
+secret         : BOOLEAN
+               | RANDOM_TYPE
+               ;
+
+door_wall      : DIRECTION
+               | RANDOM_TYPE
+               ;
+
+door_pos       : INTEGER
+               | RANDOM_TYPE
+               ;
+
+maze_def       : MAZE_ID ':' string ',' filling
+               ;
+
+filling                : CHAR
+               | RANDOM_TYPE
+               ;
+
+regions                : aregion
+               | aregion regions
+               ;
+
+aregion                : map_definition reg_init map_details
+               ;
+
+map_definition : NOMAP_ID
+               | map_geometry MAP_ID
+               ;
+
+map_geometry   : GEOMETRY_ID ':' h_justif ',' v_justif
+               ;
+
+h_justif       : LEFT_OR_RIGHT
+               | CENTER
+               ;
+
+v_justif       : TOP_OR_BOT
+               | CENTER
+               ;
+
+reg_init       : /* nothing */
+               | reg_init init_reg
+               ;
+
+init_reg       : RANDOM_OBJECTS_ID ':' object_list
+               | RANDOM_PLACES_ID ':' place_list
+               | RANDOM_MONSTERS_ID ':' monster_list
+               ;
+
+object_list    : object
+               | object ',' object_list
+               ;
+
+monster_list   : monster
+               | monster ',' monster_list
+               ;
+
+place_list     : place
+               | place ',' place_list
+               ;
+
+map_details    : /* nothing */
+               | map_details map_detail
+               ;
+
+map_detail     : monster_detail
+               | object_detail
+               | door_detail
+               | trap_detail
+               | drawbridge_detail
+               | region_detail
+               | stair_region
+               | portal_region
+               | teleprt_region
+               | branch_region
+               | altar_detail
+               | fountain_detail
+               | mazewalk_detail
+               | wallify_detail
+               | ladder_detail
+               | stair_detail
+               | gold_detail
+               | engraving_detail
+               | diggable_detail
+               | passwall_detail
+               ;
+
+monster_detail : MONSTER_ID chance ':' monster_c ',' m_name ',' coordinate
+                monster_infos
+               ;
+
+monster_infos  : /* nothing */
+               | monster_infos monster_info
+               ;
+
+monster_info   : ',' string
+               | ',' MON_ATTITUDE
+               | ',' MON_ALERTNESS
+               | ',' alignment
+               | ',' MON_APPEARANCE string
+               ;
+
+object_detail  : OBJECT_ID object_desc
+               | COBJECT_ID object_desc
+               ;
+
+object_desc    : chance ':' object_c ',' o_name ',' object_where object_infos
+               ;
+
+object_where   : coordinate
+               | CONTAINED
+               ;
+
+object_infos   : /* nothing */
+               | ',' curse_state ',' monster_id ',' enchantment optional_name
+               | ',' curse_state ',' enchantment optional_name
+               | ',' monster_id ',' enchantment optional_name
+               ;
+
+curse_state    : RANDOM_TYPE
+               | CURSE_TYPE
+               ;
+
+monster_id     : STRING
+               ;
+
+enchantment    : RANDOM_TYPE
+               | INTEGER
+               ;
+
+optional_name  : /* nothing */
+               | ',' NONE
+               | ',' STRING
+               ;
+
+door_detail    : DOOR_ID ':' door_state ',' coordinate
+               ;
+
+trap_detail    : TRAP_ID chance ':' trap_name ',' coordinate
+               ;
+
+drawbridge_detail: DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state
+               ;
+
+mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION
+               ;
+
+wallify_detail : WALLIFY_ID
+               ;
+
+ladder_detail  : LADDER_ID ':' coordinate ',' UP_OR_DOWN
+               ;
+
+stair_detail   : STAIR_ID ':' coordinate ',' UP_OR_DOWN
+               ;
+
+stair_region   : STAIR_ID ':' lev_region ',' lev_region ',' UP_OR_DOWN
+               ;
+
+portal_region  : PORTAL_ID ':' lev_region ',' lev_region ',' string
+               ;
+
+teleprt_region : TELEPRT_ID ':' lev_region ',' lev_region teleprt_detail
+               ;
+
+branch_region  : BRANCH_ID ':' lev_region ',' lev_region
+               ;
+
+teleprt_detail : /* empty */
+               | ',' UP_OR_DOWN
+               ;
+
+lev_region     : region
+               | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
+               ;
+
+fountain_detail : FOUNTAIN_ID ':' coordinate
+               ;
+
+sink_detail : SINK_ID ':' coordinate
+               ;
+
+pool_detail : POOL_ID ':' coordinate
+               ;
+
+diggable_detail : NON_DIGGABLE_ID ':' region
+               ;
+
+passwall_detail : NON_PASSWALL_ID ':' region
+               ;
+
+region_detail  : REGION_ID ':' region ',' light_state ',' room_type prefilled
+               ;
+
+altar_detail   : ALTAR_ID ':' coordinate ',' alignment ',' altar_type
+               ;
+
+gold_detail    : GOLD_ID ':' amount ',' coordinate
+               ;
+
+engraving_detail: ENGRAVING_ID ':' coordinate ',' engraving_type ',' string
+               ;
+
+monster_c      : monster
+               | RANDOM_TYPE
+               | m_register
+               ;
+
+object_c       : object
+               | RANDOM_TYPE
+               | o_register
+               ;
+
+m_name         : string
+               | RANDOM_TYPE
+               ;
+
+o_name         : string
+               | RANDOM_TYPE
+               ;
+
+trap_name      : string
+               | RANDOM_TYPE
+               ;
+
+room_type      : string
+               | RANDOM_TYPE
+               ;
+
+prefilled      : /* empty */
+               | ',' FILLING
+               | ',' FILLING ',' BOOLEAN
+               ;
+
+coordinate     : coord
+               | p_register
+               | RANDOM_TYPE
+               ;
+
+door_state     : DOOR_STATE
+               | RANDOM_TYPE
+               ;
+
+light_state    : LIGHT_STATE
+               | RANDOM_TYPE
+               ;
+
+alignment      : ALIGNMENT
+               | a_register
+               | RANDOM_TYPE
+               ;
+
+altar_type     : ALTAR_TYPE
+               | RANDOM_TYPE
+               ;
+
+p_register     : P_REGISTER '[' INTEGER ']'
+               ;
+
+o_register     : O_REGISTER '[' INTEGER ']'
+               ;
+
+m_register     : M_REGISTER '[' INTEGER ']'
+               ;
+
+a_register     : A_REGISTER '[' INTEGER ']'
+               ;
+
+place          : coord
+               ;
+
+monster                : CHAR
+               ;
+
+object         : CHAR
+               ;
+
+string         : STRING
+               ;
+
+amount         : INTEGER
+               | RANDOM_TYPE
+               ;
+
+chance         : /* empty */
+               | PERCENT
+               ;
+
+engraving_type : ENGRAVING_TYPE
+               | RANDOM_TYPE
+               ;
+
+coord          : '(' INTEGER ',' INTEGER ')'
+               ;
+
+region         : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
+               ;
+.fi
+.PP
+.I NOTE:
+.br
+Lines beginning with '#' are considered comments.
+.PP
+The contents of a "MAP" description of a maze is a rectangle showing the exact
+level map that should be used for the given part of a maze.
+Each character in the map corresponds to a location on the screen.
+Different location types are denoted using different ASCII characters.
+The following characters are recognized.
+To give an idea of how these are used, see the EXAMPLE, below.
+The maximum size of a map is normally 76 columns by 21 rows.
+.LP
+.nf
+.ta +8n +8n +8n
+\&'-'  horizontal wall
+\&'|'  vertical wall
+\&'+'  a doorway (state is specified in a DOOR declaration)
+\&'A'  open air
+\&'B'  boundary room location (for bounding unwalled irregular regions)
+\&'C'  cloudy air
+\&'I'  ice
+\&'S'  a secret door
+\&'H'  a secret corridor
+\&'{'  a fountain
+\&'\\' a throne
+\&'K'  a sink (if SINKS is defined, else a room location)
+\&'}'  a part of a moat or other deep water
+\&'P'  a pool
+\&'L'  lava
+\&'W'  water (yes, different from a pool)
+\&'T'  a tree
+\&'F'  iron bars
+\&'#'  a corridor
+\&'.'  a normal room location (unlit unless lit in a REGION declaration)
+\&' '  stone
+.fi
+.SH EXAMPLE
+.PP
+Here is an example of a description file (a very simple one):
+.LP
+.nf
+.ta +8n +8n +8n
+MAZE : "fortress", random
+GEOMETRY : center , center
+MAP
+}}}}}}}}}
+}}}|-|}}}
+}}|-.-|}}
+}|-...-|}
+}|.....|}
+}|-...-|}
+}}|-.-|}}
+}}}|-|}}}
+}}}}}}}}}
+ENDMAP
+MONSTER: '@', "Wizard of Yendor", (4,4)
+OBJECT: '"', "Amulet of Yendor", (4,4)
+# a hell hound flanking the Wiz on a random side
+RANDOM_PLACES: (4,3), (4,5), (3,4), (5,4)
+MONSTER: 'd', "hell hound", place[0]
+# a chest on another random side
+OBJECT: '(', "chest", place[1]
+# a sack on a random side, with a diamond and maybe a ruby in it
+CONTAINER: '(', "sack", place[2]
+OBJECT: '*', "diamond", contained
+OBJECT[50%]: '*', "ruby", contained
+# a random dragon somewhere
+MONSTER: 'D', random, random
+# 3 out of 4 chance for a random trap in the EAST end
+TRAP[75%]: random, (6,4)
+# an electric eel below the SOUTH end
+MONSTER: ';', "electric eel", (4,8)
+# make the walls non-diggable
+NON_DIGGABLE: (0,0,8,8)
+TELEPORT_REGION: levregion(0,0,79,20), (0,0,8,8)
+.fi
+.PP
+This example will produce a file named "fortress" that can be integrated into
+one of the numerous mazes of the game.
+.PP
+Note especially the final, TELEPORT_REGION specification.  This says
+that level teleports or other non-stairway arrivals on this level can
+land anywhere on the level except the area of the map.  This shows the
+use of the ``levregion'' prefix allowed in certain region specifications.
+Normally, regions apply only to the most recent MAP specification, but
+when prefixed with ``levregion'', one can refer to any area of the
+level, regardless of the placement of the current MAP in the level.
+.SH AUTHOR
+.PP
+Jean-Christophe Collet, David Cohrs.
+.SH "SEE ALSO"
+.PP
+dgn_comp(6), nethack(6)
+.SH BUGS
+.PP
+Probably infinite.
+Most importantly, still needs additional bounds checking.
diff --git a/doc/lev_comp.txt b/doc/lev_comp.txt
new file mode 100644 (file)
index 0000000..4a28fce
--- /dev/null
@@ -0,0 +1,726 @@
+
+
+
+LEV_COMP(6)                   1996                    LEV_COMP(6)
+
+
+
+NAME
+     lev_comp - NetHack special levels compiler
+
+SYNOPSIS
+     lev_comp [ -w ] [ files ]
+
+     If no arguments are given, it reads standard input.
+
+DESCRIPTION
+     Lev_comp is a special level compiler for NetHack version 3.2
+     and  higher.   It  takes  description files as arguments and
+     produces level files that can be loaded by NetHack  at  run-
+     time.
+
+     The purpose of this tool is to provide  NetHack  administra-
+     tors  and implementors with a convenient way for adding spe-
+     cial levels to the game, or modifying existing ones, without
+     having to recompile the entire world.
+
+     The -w option causes lev_comp to perform extra checks on the
+     level and display extra warnings, however these warnings are
+     sometimes superfluous, so they are not normally displayed.
+
+
+GRAMMAR
+     file            : /* nothing */
+                     | levels
+                     ;
+
+     levels          : level
+                     | level levels
+                     ;
+
+     level           : maze_level
+                     | room_level
+                     ;
+
+     maze_level      : maze_def flags lev_init messages regions
+                     ;
+
+     room_level      : level_def flags lev_init messages rreg_init rooms corridors_def
+                     ;
+
+     level_def       : LEVEL_ID ':' string
+                     ;
+
+     lev_init        : /* nothing */
+                     | LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled
+                     ;
+
+     walled          : BOOLEAN
+                     | RANDOM_TYPE
+
+
+
+May                      Last change: 16                        1
+
+
+
+
+
+
+LEV_COMP(6)                   1996                    LEV_COMP(6)
+
+
+
+                     ;
+
+     flags           : /* nothing */
+                     | FLAGS_ID ':' flag_list
+                     ;
+
+     flag_list       : FLAG_TYPE ',' flag_list
+                     | FLAG_TYPE
+                     ;
+
+     messages        : /* nothing */
+                     | message messages
+                     ;
+
+     message         : MESSAGE_ID ':' STRING
+                     ;
+
+     rreg_init       : /* nothing */
+                     | rreg_init init_rreg
+                     ;
+
+     init_rreg       : RANDOM_OBJECTS_ID ':' object_list
+                     | RANDOM_MONSTERS_ID ':' monster_list
+                     ;
+
+     rooms           : /* Nothing  -  dummy room for use with INIT_MAP */
+                     | roomlist
+                     ;
+
+     roomlist        : aroom
+                     | aroom roomlist
+                     ;
+
+     corridors_def   : random_corridors
+                     | corridors
+                     ;
+
+     random_corridors: RAND_CORRIDOR_ID
+                     ;
+
+     corridors       : /* nothing */
+                     | corridors corridor
+                     ;
+
+     corridor        : CORRIDOR_ID ':' corr_spec ',' corr_spec
+                     | CORRIDOR_ID ':' corr_spec ',' INTEGER
+                     ;
+
+     corr_spec       : '(' INTEGER ',' DIRECTION ',' door_pos ')'
+                     ;
+
+     aroom           : room_def room_details
+
+
+
+May                      Last change: 16                        2
+
+
+
+
+
+
+LEV_COMP(6)                   1996                    LEV_COMP(6)
+
+
+
+                     | subroom_def room_details
+                     ;
+
+     subroom_def     : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill
+                     ;
+
+     room_def        : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill
+                     ;
+
+     roomfill        : /* nothing */
+                     | ',' BOOLEAN
+                     ;
+
+     room_pos        : '(' INTEGER ',' INTEGER ')'
+                     | RANDOM_TYPE
+                     ;
+
+     subroom_pos     : '(' INTEGER ',' INTEGER ')'
+                     | RANDOM_TYPE
+                     ;
+
+     room_align      : '(' h_justif ',' v_justif ')'
+                     | RANDOM_TYPE
+                     ;
+
+     room_size       : '(' INTEGER ',' INTEGER ')'
+                     | RANDOM_TYPE
+                     ;
+
+     room_details    : /* nothing */
+                     | room_details room_detail
+                     ;
+
+     room_detail     : room_name
+                     | room_chance
+                     | room_door
+                     | monster_detail
+                     | object_detail
+                     | trap_detail
+                     | altar_detail
+                     | fountain_detail
+                     | sink_detail
+                     | pool_detail
+                     | gold_detail
+                     | engraving_detail
+                     | stair_detail
+                     ;
+
+     room_name       : NAME_ID ':' string
+                     ;
+
+     room_chance     : CHANCE_ID ':' INTEGER
+
+
+
+May                      Last change: 16                        3
+
+
+
+
+
+
+LEV_COMP(6)                   1996                    LEV_COMP(6)
+
+
+
+                     ;
+
+     room_door       : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos
+                     ;
+
+     secret          : BOOLEAN
+                     | RANDOM_TYPE
+                     ;
+
+     door_wall       : DIRECTION
+                     | RANDOM_TYPE
+                     ;
+
+     door_pos        : INTEGER
+                     | RANDOM_TYPE
+                     ;
+
+     maze_def        : MAZE_ID ':' string ',' filling
+                     ;
+
+     filling         : CHAR
+                     | RANDOM_TYPE
+                     ;
+
+     regions         : aregion
+                     | aregion regions
+                     ;
+
+     aregion         : map_definition reg_init map_details
+                     ;
+
+     map_definition  : NOMAP_ID
+                     | map_geometry MAP_ID
+                     ;
+
+     map_geometry    : GEOMETRY_ID ':' h_justif ',' v_justif
+                     ;
+
+     h_justif        : LEFT_OR_RIGHT
+                     | CENTER
+                     ;
+
+     v_justif        : TOP_OR_BOT
+                     | CENTER
+                     ;
+
+     reg_init        : /* nothing */
+                     | reg_init init_reg
+                     ;
+
+     init_reg        : RANDOM_OBJECTS_ID ':' object_list
+                     | RANDOM_PLACES_ID ':' place_list
+
+
+
+May                      Last change: 16                        4
+
+
+
+
+
+
+LEV_COMP(6)                   1996                    LEV_COMP(6)
+
+
+
+                     | RANDOM_MONSTERS_ID ':' monster_list
+                     ;
+
+     object_list     : object
+                     | object ',' object_list
+                     ;
+
+     monster_list    : monster
+                     | monster ',' monster_list
+                     ;
+
+     place_list      : place
+                     | place ',' place_list
+                     ;
+
+     map_details     : /* nothing */
+                     | map_details map_detail
+                     ;
+
+     map_detail      : monster_detail
+                     | object_detail
+                     | door_detail
+                     | trap_detail
+                     | drawbridge_detail
+                     | region_detail
+                     | stair_region
+                     | portal_region
+                     | teleprt_region
+                     | branch_region
+                     | altar_detail
+                     | fountain_detail
+                     | mazewalk_detail
+                     | wallify_detail
+                     | ladder_detail
+                     | stair_detail
+                     | gold_detail
+                     | engraving_detail
+                     | diggable_detail
+                     | passwall_detail
+                     ;
+
+     monster_detail  : MONSTER_ID chance ':' monster_c ',' m_name ',' coordinate
+                      monster_infos
+                     ;
+
+     monster_infos   : /* nothing */
+                     | monster_infos monster_info
+                     ;
+
+     monster_info    : ',' string
+                     | ',' MON_ATTITUDE
+                     | ',' MON_ALERTNESS
+
+
+
+May                      Last change: 16                        5
+
+
+
+
+
+
+LEV_COMP(6)                   1996                    LEV_COMP(6)
+
+
+
+                     | ',' alignment
+                     | ',' MON_APPEARANCE string
+                     ;
+
+     object_detail   : OBJECT_ID object_desc
+                     | COBJECT_ID object_desc
+                     ;
+
+     object_desc     : chance ':' object_c ',' o_name ',' object_where object_infos
+                     ;
+
+     object_where    : coordinate
+                     | CONTAINED
+                     ;
+
+     object_infos    : /* nothing */
+                     | ',' curse_state ',' monster_id ',' enchantment optional_name
+                     | ',' curse_state ',' enchantment optional_name
+                     | ',' monster_id ',' enchantment optional_name
+                     ;
+
+     curse_state     : RANDOM_TYPE
+                     | CURSE_TYPE
+                     ;
+
+     monster_id      : STRING
+                     ;
+
+     enchantment     : RANDOM_TYPE
+                     | INTEGER
+                     ;
+
+     optional_name   : /* nothing */
+                     | ',' NONE
+                     | ',' STRING
+                     ;
+
+     door_detail     : DOOR_ID ':' door_state ',' coordinate
+                     ;
+
+     trap_detail     : TRAP_ID chance ':' trap_name ',' coordinate
+                     ;
+
+     drawbridge_detail: DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state
+                     ;
+
+     mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION
+                     ;
+
+     wallify_detail  : WALLIFY_ID
+                     ;
+
+
+
+
+May                      Last change: 16                        6
+
+
+
+
+
+
+LEV_COMP(6)                   1996                    LEV_COMP(6)
+
+
+
+     ladder_detail   : LADDER_ID ':' coordinate ',' UP_OR_DOWN
+                     ;
+
+     stair_detail    : STAIR_ID ':' coordinate ',' UP_OR_DOWN
+                     ;
+
+     stair_region    : STAIR_ID ':' lev_region ',' lev_region ',' UP_OR_DOWN
+                     ;
+
+     portal_region   : PORTAL_ID ':' lev_region ',' lev_region ',' string
+                     ;
+
+     teleprt_region  : TELEPRT_ID ':' lev_region ',' lev_region teleprt_detail
+                     ;
+
+     branch_region   : BRANCH_ID ':' lev_region ',' lev_region
+                     ;
+
+     teleprt_detail  : /* empty */
+                     | ',' UP_OR_DOWN
+                     ;
+
+     lev_region      : region
+                     | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
+                     ;
+
+     fountain_detail : FOUNTAIN_ID ':' coordinate
+                     ;
+
+     sink_detail : SINK_ID ':' coordinate
+                     ;
+
+     pool_detail : POOL_ID ':' coordinate
+                     ;
+
+     diggable_detail : NON_DIGGABLE_ID ':' region
+                     ;
+
+     passwall_detail : NON_PASSWALL_ID ':' region
+                     ;
+
+     region_detail   : REGION_ID ':' region ',' light_state ',' room_type prefilled
+                     ;
+
+     altar_detail    : ALTAR_ID ':' coordinate ',' alignment ',' altar_type
+                     ;
+
+     gold_detail     : GOLD_ID ':' amount ',' coordinate
+                     ;
+
+     engraving_detail: ENGRAVING_ID ':' coordinate ',' engraving_type ',' string
+                     ;
+
+
+
+May                      Last change: 16                        7
+
+
+
+
+
+
+LEV_COMP(6)                   1996                    LEV_COMP(6)
+
+
+
+     monster_c       : monster
+                     | RANDOM_TYPE
+                     | m_register
+                     ;
+
+     object_c        : object
+                     | RANDOM_TYPE
+                     | o_register
+                     ;
+
+     m_name          : string
+                     | RANDOM_TYPE
+                     ;
+
+     o_name          : string
+                     | RANDOM_TYPE
+                     ;
+
+     trap_name       : string
+                     | RANDOM_TYPE
+                     ;
+
+     room_type       : string
+                     | RANDOM_TYPE
+                     ;
+
+     prefilled       : /* empty */
+                     | ',' FILLING
+                     | ',' FILLING ',' BOOLEAN
+                     ;
+
+     coordinate      : coord
+                     | p_register
+                     | RANDOM_TYPE
+                     ;
+
+     door_state      : DOOR_STATE
+                     | RANDOM_TYPE
+                     ;
+
+     light_state     : LIGHT_STATE
+                     | RANDOM_TYPE
+                     ;
+
+     alignment       : ALIGNMENT
+                     | a_register
+                     | RANDOM_TYPE
+                     ;
+
+     altar_type      : ALTAR_TYPE
+                     | RANDOM_TYPE
+                     ;
+
+
+
+May                      Last change: 16                        8
+
+
+
+
+
+
+LEV_COMP(6)                   1996                    LEV_COMP(6)
+
+
+
+     p_register      : P_REGISTER '[' INTEGER ']'
+                     ;
+
+     o_register      : O_REGISTER '[' INTEGER ']'
+                     ;
+
+     m_register      : M_REGISTER '[' INTEGER ']'
+                     ;
+
+     a_register      : A_REGISTER '[' INTEGER ']'
+                     ;
+
+     place           : coord
+                     ;
+
+     monster         : CHAR
+                     ;
+
+     object          : CHAR
+                     ;
+
+     string          : STRING
+                     ;
+
+     amount          : INTEGER
+                     | RANDOM_TYPE
+                     ;
+
+     chance          : /* empty */
+                     | PERCENT
+                     ;
+
+     engraving_type  : ENGRAVING_TYPE
+                     | RANDOM_TYPE
+                     ;
+
+     coord           : '(' INTEGER ',' INTEGER ')'
+                     ;
+
+     region          : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
+                     ;
+
+     NOTE:
+     Lines beginning with '#' are considered comments.
+
+     The contents of a "MAP" description of a maze is a rectangle
+     showing  the  exact  level  map  that should be used for the
+     given part of a maze.  Each character in the map corresponds
+     to  a  location on the screen.  Different location types are
+     denoted using different  ASCII  characters.   The  following
+     characters are recognized.  To give an idea of how these are
+     used, see the EXAMPLE, below.  The maximum size of a map  is
+
+
+
+May                      Last change: 16                        9
+
+
+
+
+
+
+LEV_COMP(6)                   1996                    LEV_COMP(6)
+
+
+
+     normally 76 columns by 21 rows.
+
+     '-'     horizontal wall
+     '|'     vertical wall
+     '+'     a doorway (state is specified in a DOOR declaration)
+     'A'     open air
+     'B'     boundary room location (for bounding unwalled irregular regions)
+     'C'     cloudy air
+     'I'     ice
+     'S'     a secret door
+     'H'     a secret corridor
+     '{'     a fountain
+     '\'     a throne
+     'K'     a sink (if SINKS is defined, else a room location)
+     '}'     a part of a moat or other deep water
+     'P'     a pool
+     'L'     lava
+     'W'     water (yes, different from a pool)
+     'T'     a tree
+     'F'     iron bars
+     '#'     a corridor
+     '.'     a normal room location (unlit unless lit in a REGION declaration)
+     ' '     stone
+
+EXAMPLE
+     Here is an example of a  description  file  (a  very  simple
+     one):
+
+     MAZE : "fortress", random
+     GEOMETRY : center , center
+     MAP
+     }}}}}}}}}
+     }}}|-|}}}
+     }}|-.-|}}
+     }|-...-|}
+     }|.....|}
+     }|-...-|}
+     }}|-.-|}}
+     }}}|-|}}}
+     }}}}}}}}}
+     ENDMAP
+     MONSTER: '@', "Wizard of Yendor", (4,4)
+     OBJECT: '"', "Amulet of Yendor", (4,4)
+     # a hell hound flanking the Wiz on a random side
+     RANDOM_PLACES: (4,3), (4,5), (3,4), (5,4)
+     MONSTER: 'd', "hell hound", place[0]
+     # a chest on another random side
+     OBJECT: '(', "chest", place[1]
+     # a sack on a random side, with a diamond and maybe a ruby in it
+     CONTAINER: '(', "sack", place[2]
+     OBJECT: '*', "diamond", contained
+     OBJECT[50%]: '*', "ruby", contained
+
+
+
+May                      Last change: 16                       10
+
+
+
+
+
+
+LEV_COMP(6)                   1996                    LEV_COMP(6)
+
+
+
+     # a random dragon somewhere
+     MONSTER: 'D', random, random
+     # 3 out of 4 chance for a random trap in the EAST end
+     TRAP[75%]: random, (6,4)
+     # an electric eel below the SOUTH end
+     MONSTER: ';', "electric eel", (4,8)
+     # make the walls non-diggable
+     NON_DIGGABLE: (0,0,8,8)
+     TELEPORT_REGION: levregion(0,0,79,20), (0,0,8,8)
+
+     This example will produce a file named "fortress"  that  can
+     be integrated into one of the numerous mazes of the game.
+
+     Note especially the  final,  TELEPORT_REGION  specification.
+     This   says  that  level  teleports  or  other  non-stairway
+     arrivals on this level can land anywhere on the level except
+     the  area  of  the  map.  This shows the use of the ``levre-
+     gion'' prefix  allowed  in  certain  region  specifications.
+     Normally, regions apply only to the most recent MAP specifi-
+     cation, but when prefixed with ``levregion'', one can  refer
+     to any area of the level, regardless of the placement of the
+     current MAP in the level.
+
+AUTHOR
+     Jean-Christophe Collet, David Cohrs.
+
+SEE ALSO
+     dgn_comp(6), nethack(6)
+
+BUGS
+     Probably infinite.  Most importantly, still needs additional
+     bounds checking.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+May                      Last change: 16                       11
+
+
+
diff --git a/doc/nethack.6 b/doc/nethack.6
new file mode 100644 (file)
index 0000000..7bc2f94
--- /dev/null
@@ -0,0 +1,305 @@
+.TH NETHACK 6 "9 August 2002"
+.UC 4
+.SH NAME
+nethack \- Exploring The Mazes of Menace
+.SH SYNOPSIS
+.na
+.hy 0
+.B nethack
+[
+.B \-d
+.I directory
+]
+[
+.B \-n
+]
+[
+.B \-p
+.I profession (role)
+]
+[
+.B \-r
+.I race
+]
+[
+.B \-[DX]
+]
+[
+.B \-u
+.I playername
+]
+[
+.B \-dec
+]
+[
+.B \-ibm
+]
+.PP
+.B nethack
+[
+.B \-d
+.I directory
+]
+.B \-s
+[
+.B \-v
+]
+[
+.B \-p
+.I profession (role)
+]
+[
+.B \-r
+.I race
+]
+[
+.I playernames
+]
+.ad
+.hy 14
+.SH DESCRIPTION
+.PP
+.I NetHack
+is a display oriented Dungeons & Dragons(tm) - like game.
+The standard tty display and command structure resemble rogue.
+.PP
+Other, more graphical display options exist if you are using either a PC,
+or an X11 interface.
+.PP
+To get started you really only need to know two commands.  The command
+.B ?
+will give you a list of the available commands (as well as other information)
+and the command
+.B /
+will identify the things you see on the screen.
+.PP
+To win the game (as opposed to merely playing to beat other people's high
+scores) you must locate the Amulet of Yendor which is somewhere below
+the 20th level of the dungeon and get it out.
+Nobody has achieved this yet; anybody who does will probably go down
+in history as a hero among heros.
+.PP
+When the game ends, whether by your dying, quitting, or escaping
+from the caves,
+.I NetHack
+will give you (a fragment of) the list of top scorers.
+The scoring is based on many aspects of your behavior, but a rough estimate
+is obtained by taking the amount of gold you've found in the cave plus four
+times your (real) experience.
+Precious stones may be worth a lot of gold when brought to the exit.
+There is a 10% penalty for getting yourself killed.
+.PP
+The environment variable NETHACKOPTIONS can be used to initialize many
+run-time options.
+The ? command provides a description of these options and syntax.
+(The
+.B \-dec
+and
+.B \-ibm
+command line options are equivalent to the
+.B decgraphics
+and
+.B ibmgraphics
+run-time options described there,
+and are provided purely for convenience on systems
+supporting multiple types of terminals.)
+.PP
+Because the option list can be very long (particularly when specifying
+graphics characters), options may also be included in a configuration
+file.
+The default is located in your home directory and
+named .nethackrc on Unix systems.  On other systems, the default may be
+different, usually NetHack.cnf.  On DOS or Windows, the name is
+defaults.nh, while on the Macintosh or BeOS, it is NetHack Defaults.
+The configuration file's location may be specified by setting NETHACKOPTIONS
+to a string consisting of an @ character followed by the filename.
+.PP
+The
+.B \-u
+.I playername
+option supplies the answer to the question "Who are you?".
+It overrides any name from the options or configuration file, USER, LOGNAME,
+or getlogin(), which will otherwise be tried in order.
+If none of these provides a useful name, the player will be asked for one.
+Player names (in conjunction with uids) are used to identify save files,
+so you can have several saved games under different names.
+Conversely, you must use the appropriate player name to restore a saved game.
+.PP
+A
+.I playername
+suffix can be used to specify the profession, race, alignment and/or gender
+of the character.  The full syntax of the playername that includes a
+suffix is "name-ppp-rrr-aaa-ggg".  "ppp" are at least the first three letters
+of the profession (this can also be specified using a separate 
+.B \-p
+.I profession
+option).  "rrr" are at least the first three letters of the character's
+race (this can also be specified using a separate 
+.B \-r
+.I race
+option).  "aaa" are at last the first three letters of the character's
+alignment, and "ggg" are at least the first three letters of the
+character's gender.  Any of the parts of the suffix may be left out.
+.PP
+.B \-p
+.I profession
+can be used to determine the character role.  You can specify either the
+male or female name for the character role, or the first three characters
+of the role as an abbreviation.
+.B "\-p \@"
+has been retained to explicitly request that a random role be chosen.
+It may need to be quoted with a backslash (\\@) if @
+is the "kill" character (see "stty") for the terminal, in order
+to prevent the current input line from being cleared.
+.PP
+Likewise,
+.B \-r
+.I race
+can be used to explicitly request that a race be chosen.
+.PP
+Leaving out any of these characteristics will result in you being prompted
+during the game startup for the information.
+.PP
+.PP
+The
+.B \-s
+option alone will print out the list of your scores on the current version.
+An immediately following
+.B \-v
+reports on all versions present in the score file.
+The
+.B \-s
+may also be followed by arguments
+.B \-p
+and
+.B \-r
+to print the scores of particular roles and races only.
+It may also be followed by one or more player names to print the scores of the
+players mentioned, by 'all' to print out all scores, or by a number to print
+that many top scores.
+.PP
+The
+.B \-n
+option suppresses printing of any news from the game administrator.
+.PP
+The
+.B \-D
+or
+.B \-X
+option will start the game in a special non-scoring discovery mode.
+.B \-D
+will, if the player is the game administrator, start in debugging (wizard)
+mode instead.
+.PP
+The
+.B \-d
+option, which must be the first argument if it appears,
+supplies a directory which is to serve as the playground.
+It overrides the value from NETHACKDIR, HACKDIR,
+or the directory specified by the game administrator during compilation
+(usually /usr/games/lib/nethackdir).
+This option is usually only useful to the game administrator.
+The playground must contain several auxiliary files such as help files,
+the list of top scorers, and a subdirectory
+.I save
+where games are saved.
+.SH AUTHORS
+.PP
+Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon Payne) wrote the
+original hack, very much like rogue (but full of bugs).
+.PP
+Andries Brouwer continuously deformed their sources into an entirely
+different game.
+.PP
+Mike Stephenson has continued the perversion of sources, adding various
+warped character classes and sadistic traps with the help of many strange
+people who reside in that place between the worlds, the Usenet Zone.
+A number of these miscreants are immortalized in the historical
+roll of dishonor and various other places.
+.PP
+The resulting mess is now called NetHack, to denote its
+development by the Usenet.  Andries Brouwer has made this request for the
+distinction, as he may eventually release a new version of his own.
+.SH FILES
+.PP
+All files are in the playground, normally /usr/games/lib/nethackdir.
+If DLB was defined during the compile, the data files and special levels
+will be inside a larger file, normally nhdat, instead of being separate
+files.
+.br
+.DT
+.ta \w'cmdhelp, opthelp, wizhelp\ \ \ 'u
+nethack                The program itself.
+.br
+data, oracles, rumors  Data files used by NetHack.
+.br
+options, quest.dat     More data files.
+.br
+help, hh       Help data files.
+.br
+cmdhelp, opthelp, wizhelp      More help data files.
+.br
+*.lev  Predefined special levels.
+.br
+dungeon        Control file for special levels.
+.br
+history        A short history of NetHack.
+.br
+license        Rules governing redistribution.
+.br
+record The list of top scorers.
+.br
+logfile        An extended list of games
+.br
+       played.
+.br
+xlock.nnn      Description of a dungeon level.
+.br
+perm   Lock file for xlock.dd.
+.br
+bonesDD.nn     Descriptions of the ghost and
+.br
+       belongings of a deceased
+.br
+       adventurer.
+.br
+save   A subdirectory containing the
+.br
+       saved games.
+.SH ENVIRONMENT
+.DT
+.ta \w'HACKPAGER or PAGER\ \ \ 'u
+USER or LOGNAME        Your login name.
+.br
+HOME           Your home directory.
+.br
+SHELL          Your shell.
+.br
+TERM           The type of your terminal.
+.br
+HACKPAGER or PAGER     Replacement for default pager.
+.br
+MAIL   Mailbox file.
+.br
+MAILREADER     Replacement for default reader
+.br
+       (probably /bin/mail or /usr/ucb/mail).
+.br
+NETHACKDIR     Playground.
+.br
+NETHACKOPTIONS String predefining several NetHack
+.br
+       options.
+.br
+
+In addition, SHOPTYPE is used in debugging (wizard) mode.
+.SH "SEE ALSO"
+.PP
+dgn_comp(6), lev_comp(6), recover(6)
+.SH BUGS
+.PP
+Probably infinite.
+
+
+.PP
+Dungeons & Dragons is a Trademark of Wizards of the Coast, Inc.
diff --git a/doc/nethack.txt b/doc/nethack.txt
new file mode 100644 (file)
index 0000000..15a11f9
--- /dev/null
@@ -0,0 +1,208 @@
+NETHACK(6)                                             NETHACK(6)
+
+
+
+NAME
+       nethack - Exploring The Mazes of Menace
+
+SYNOPSIS
+       nethack [ -d directory ] [ -n ] [ -p profession (role) ] [
+       -r race ] [ -[DX] ] [ -u playername ] [ -dec ] [ -ibm ]
+
+       nethack [ -d directory ] -s [ -v ] [ -p profession (role)
+       ] [ -r race ] [ playernames ]
+
+DESCRIPTION
+       NetHack  is  a  display  oriented Dungeons & Dragons(tm) -
+       like game.  The standard tty display and command structure
+       resemble rogue.
+
+       Other,  more  graphical  display  options exist if you are
+       using either a PC, or an X11 interface.
+
+       To get started you really only need to know two  commands.
+       The  command ?  will give you a list of the available com-
+       mands (as well as other information)  and  the  command  /
+       will identify the things you see on the screen.
+
+       To  win  the  game  (as  opposed to merely playing to beat
+       other people's high scores) you must locate the Amulet  of
+       Yendor which is somewhere below the 20th level of the dun-
+       geon and get it out.  Nobody has achieved this  yet;  any-
+       body  who  does will probably go down in history as a hero
+       among heros.
+
+       When the game ends, whether by your  dying,  quitting,  or
+       escaping from the caves, NetHack will give you (a fragment
+       of) the list of top scorers.  The scoring is based on many
+       aspects of your behavior, but a rough estimate is obtained
+       by taking the amount of gold you've found in the cave plus
+       four times your (real) experience.  Precious stones may be
+       worth a lot of gold when brought to the exit.  There is  a
+       10% penalty for getting yourself killed.
+
+       The  environment  variable  NETHACKOPTIONS  can be used to
+       initialize many run-time options.  The ? command  provides
+       a  description of these options and syntax.  (The -dec and
+       -ibm command line options are equivalent to the  decgraph-
+       ics  and ibmgraphics run-time options described there, and
+       are provided purely for convenience on systems  supporting
+       multiple types of terminals.)
+
+       Because  the  option  list  can be very long (particularly
+       when specifying graphics characters), options may also  be
+       included  in a configuration file.  The default is located
+       in your home directory and named .nethackrc on  Unix  sys-
+       tems.   On  other  systems,  the default may be different,
+       usually NetHack.cnf.  On  DOS  or  Windows,  the  name  is
+       defaults.nh, while on the Macintosh or BeOS, it is NetHack
+       Defaults.  The configuration file's location may be speci-
+       fied  by  setting NETHACKOPTIONS to a string consisting of
+       an @ character followed by the filename.
+
+       The -u playername option supplies the answer to the  ques-
+       tion  "Who  are  you?".   It  overrides  any name from the
+       options or configuration file, USER,  LOGNAME,  or  getlo-
+       gin(), which will otherwise be tried in order.  If none of
+       these provides a useful name, the player will be asked for
+       one.   Player names (in conjunction with uids) are used to
+       identify save files, so you can have several  saved  games
+       under  different  names.   Conversely,  you  must  use the
+       appropriate player name to restore a saved game.
+
+       A playername suffix can be used to specify the profession,
+       race,  alignment and/or gender of the character.  The full
+       syntax of the playername that includes a suffix is  "name-
+       ppp-rrr-aaa-ggg".  "ppp" are at least the first three let-
+       ters of the profession (this can also be specified using a
+       separate  -p  profession  option).  "rrr" are at least the
+       first three letters of the character's race (this can also
+       be  specified using a separate -r race option).  "aaa" are
+       at last the first three letters of the character's  align-
+       ment,  and  "ggg"  are at least the first three letters of
+       the character's gender.  Any of the parts  of  the  suffix
+       may be left out.
+
+       -p profession can be used to determine the character role.
+       You can specify either the male or  female  name  for  the
+       character  role, or the first three characters of the role
+       as an abbreviation.  -p @ has been retained to  explicitly
+       request  that  a random role be chosen.  It may need to be
+       quoted with a backslash (\@) if @ is the "kill"  character
+       (see  "stty")  for  the  terminal, in order to prevent the
+       current input line from being cleared.
+
+       Likewise, -r race can be used to explicitly request that a
+       race be chosen.
+
+       Leaving  out  any  of these characteristics will result in
+       you being prompted during the game startup for the  infor-
+       mation.
+
+
+       The -s option alone will print out the list of your scores
+       on the  current  version.   An  immediately  following  -v
+       reports on all versions present in the score file.  The -s
+       may also be followed by arguments -p and -r to  print  the
+       scores of particular roles and races only.  It may also be
+       followed by one or more player names to print  the  scores
+       of  the  players  mentioned,  by  'all'  to  print out all
+       scores, or by a number to print that many top scores.
+
+       The -n option suppresses printing of  any  news  from  the
+       game administrator.
+
+       The  -D or -X option will start the game in a special non-
+       scoring discovery mode.  -D will, if  the  player  is  the
+       game  administrator,  start  in  debugging  (wizard)  mode
+       instead.
+
+       The -d option, which must be  the  first  argument  if  it
+       appears,  supplies  a  directory  which is to serve as the
+       playground.  It overrides the value from NETHACKDIR, HACK-
+       DIR,  or the directory specified by the game administrator
+       during  compilation  (usually  /usr/games/lib/nethackdir).
+       This option is usually only useful to the game administra-
+       tor.  The playground must contain several auxiliary  files
+       such  as help files, the list of top scorers, and a subdi-
+       rectory save where games are saved.
+
+AUTHORS
+       Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon  Payne)
+       wrote the original hack, very much like rogue (but full of
+       bugs).
+
+       Andries Brouwer continuously deformed their  sources  into
+       an entirely different game.
+
+       Mike  Stephenson  has continued the perversion of sources,
+       adding various warped character classes and sadistic traps
+       with  the  help  of many strange people who reside in that
+       place between the worlds, the Usenet Zone.   A  number  of
+       these  miscreants  are immortalized in the historical roll
+       of dishonor and various other places.
+
+       The resulting mess is now called NetHack,  to  denote  its
+       development  by the Usenet.  Andries Brouwer has made this
+       request for the distinction, as he may eventually  release
+       a new version of his own.
+
+FILES
+       All    files    are    in    the    playground,   normally
+       /usr/games/lib/nethackdir.  If DLB was defined during  the
+       compile,  the data files and special levels will be inside
+       a larger file, normally nhdat, instead of  being  separate
+       files.
+       nethack                     The program itself.
+       data, oracles, rumors       Data files used by NetHack.
+       options, quest.dat          More data files.
+       help, hh                    Help data files.
+       cmdhelp, opthelp, wizhelp   More help data files.
+       *.lev                       Predefined special levels.
+       dungeon                     Control  file for special lev-
+       els.
+       history                     A short history of NetHack.
+       license                     Rules  governing   redistribu-
+       tion.
+       record                      The list of top scorers.
+       logfile                     An extended list of games
+                                   played.
+       xlock.nnn                   Description   of   a   dungeon
+       level.
+       perm                        Lock file for xlock.dd.
+       bonesDD.nn                  Descriptions of the ghost and
+                                   belongings of a deceased
+                                   adventurer.
+       save                        A subdirectory containing the
+                                   saved games.
+
+ENVIRONMENT
+       USER or LOGNAME      Your login name.
+       HOME                 Your home directory.
+       SHELL                Your shell.
+       TERM                 The type of your terminal.
+       HACKPAGER or PAGER   Replacement for default pager.
+       MAIL                 Mailbox file.
+       MAILREADER           Replacement for default reader
+                            (probably        /bin/mail         or
+       /usr/ucb/mail).
+       NETHACKDIR           Playground.
+       NETHACKOPTIONS       String predefining several NetHack
+                            options.
+
+       In  addition, SHOPTYPE is used in debugging (wizard) mode.
+
+SEE ALSO
+       dgn_comp(6), lev_comp(6), recover(6)
+
+BUGS
+       Probably infinite.
+
+
+
+       Dungeons & Dragons is a Trademark of Wizards of the Coast,
+       Inc.
+
+
+
+                          9 August 2002                NETHACK(6)
diff --git a/doc/recover.6 b/doc/recover.6
new file mode 100644 (file)
index 0000000..d813264
--- /dev/null
@@ -0,0 +1,116 @@
+.TH RECOVER 6 "9 January 1993"
+.UC 4
+.SH NAME
+recover \- recover a NetHack game interrupted by disaster
+.SH SYNOPSIS
+.B recover
+[
+.B \-d
+.I directory
+]
+.I "base1 base2" ...
+.SH DESCRIPTION
+.PP
+Occasionally, a NetHack game will be interrupted by disaster
+when the game or the system crashes.
+Prior to NetHack v3.1, these games were lost because various information
+like the player's inventory was kept only in memory.
+Now, all pertinent information can be written out to disk,
+so such games can be recovered at the point of the last level change.
+.PP
+The
+.I base
+options tell
+.I recover
+which files to process.
+Each base option specifies recovery of a separate game.
+.PP
+The
+.B \-d
+option, which must be the first argument if it appears,
+supplies a directory which is the NetHack playground.
+It overrides the value from NETHACKDIR, HACKDIR, or the directory
+specified by the game administrator during compilation
+(usually /usr/games/lib/nethackdir).
+.PP
+For recovery to be possible,
+.I nethack
+must have been compiled with the INSURANCE option, and the run-time option
+.I checkpoint
+must also have been on.
+NetHack normally writes out files for levels as the player leaves them,
+so they will be ready for return visits.
+When checkpointing, NetHack also writes out the level entered and
+the current game state on every level change.
+This naturally slows level changes down somewhat.
+.PP
+The level file names are of the form base.nn, where nn is an internal
+bookkeeping number for the level.
+The file base.0 is used for game identity, locking, and, when checkpointing,
+for the game state.
+Various OSes use different strategies for constructing the base name.
+Microcomputers use the character name, possibly truncated and modified
+to be a legal filename on that system.
+Multi-user systems use the (modified) character name prefixed
+by a user number to avoid conflicts,
+or "xlock" if the number of concurrent players is being limited.
+It may be necessary to look in the playground to find the correct
+base name of the interrupted game.
+.I recover
+will transform these level files into a save file of the same name as
+.I nethack
+would have used.
+.PP
+Since
+.I recover
+must be able to read and delete files from the playground
+and create files in the save directory,
+it has interesting interactions with game security.
+Giving ordinary players access to
+.I recover
+through setuid or setgid is tantamount to leaving the playground
+world-writable,
+with respect to both cheating and messing up other players.
+For a single-user system, this of course does not change anything,
+so some of the microcomputer ports install
+.I recover
+by default.
+.PP
+For a multi-user system,
+the game administrator may want to arrange for all .0 files in the
+playground to be fed to recover when the host machine boots,
+and handle game crashes individually.
+If the user population is sufficiently trustworthy,
+.I recover
+can be installed with the same permissions the
+.I nethack
+executable has.
+In either case,
+.I recover
+is easily compiled from the distribution utility directory.
+.SH NOTES
+.PP
+Like
+.I nethack
+itself,
+.I recover
+will overwrite existing savefiles of the same name.
+Savefiles created by
+.I recover
+are uncompressed;
+they may be compressed afterwards if desired,
+but even a compression-using
+.I nethack
+will find them in the uncompressed form.
+.SH "SEE ALSO"
+nethack(6)
+.SH BUGS
+.PP
+.I recover
+makes no attempt to find out if a base name specifies a game in progress.
+If multiple machines share a playground, this would be impossible to
+determine.
+.PP
+.I recover
+should be taught to use the nethack playground locking mechanism to
+avoid conflicts.
diff --git a/doc/recover.txt b/doc/recover.txt
new file mode 100644 (file)
index 0000000..80eeadb
--- /dev/null
@@ -0,0 +1,132 @@
+
+
+
+RECOVER(6)                    1993                     RECOVER(6)
+
+
+
+NAME
+     recover - recover a NetHack game interrupted by disaster
+
+SYNOPSIS
+     recover [ -d directory ] base1 base2 ...
+
+DESCRIPTION
+     Occasionally, a NetHack game will be interrupted by disaster
+     when the game or the system crashes.  Prior to NetHack v3.1,
+     these games were lost because various information  like  the
+     player's  inventory  was kept only in memory.  Now, all per-
+     tinent information can be written out to disk, so such games
+     can be recovered at the point of the last level change.
+
+     The base options tell recover which files to process.   Each
+     base option specifies recovery of a separate game.
+
+     The -d option, which  must  be  the  first  argument  if  it
+     appears,  supplies  a  directory  which is the NetHack play-
+     ground.  It overrides the value from NETHACKDIR, HACKDIR, or
+     the  directory  specified  by  the game administrator during
+     compilation (usually /usr/games/lib/nethackdir).
+
+     For recovery to be possible, nethack must have been compiled
+     with  the  INSURANCE  option, and the run-time option check-
+     point must also have been on.  NetHack normally  writes  out
+     files  for levels as the player leaves them, so they will be
+     ready for return visits.  When checkpointing,  NetHack  also
+     writes  out  the level entered and the current game state on
+     every level change.  This naturally slows level changes down
+     somewhat.
+
+     The level file names are of the form base.nn, where nn is an
+     internal  bookkeeping number for the level.  The file base.0
+     is used for game identity, locking, and, when checkpointing,
+     for  the  game state.  Various OSes use different strategies
+     for constructing the  base  name.   Microcomputers  use  the
+     character  name,  possibly  truncated  and  modified to be a
+     legal filename on that system.  Multi-user systems  use  the
+     (modified) character name prefixed by a user number to avoid
+     conflicts, or "xlock" if the number of concurrent players is
+     being  limited.   It  may  be necessary to look in the play-
+     ground to find the correct  base  name  of  the  interrupted
+     game.   recover will transform these level files into a save
+     file of the same name as nethack would have used.
+
+     Since recover must be able to read and delete files from the
+     playground  and  create  files in the save directory, it has
+     interesting interactions with game security.   Giving  ordi-
+     nary  players  access to recover through setuid or setgid is
+     tantamount to leaving the  playground  world-writable,  with
+     respect  to both cheating and messing up other players.  For
+
+
+
+January                  Last change: 9                         1
+
+
+
+
+
+
+RECOVER(6)                    1993                     RECOVER(6)
+
+
+
+     a single-user system, this of course does  not  change  any-
+     thing, so some of the microcomputer ports install recover by
+     default.
+
+     For a multi-user system, the game administrator may want  to
+     arrange  for  all  .0  files  in the playground to be fed to
+     recover when the host machine boots, and handle game crashes
+     individually.    If  the  user  population  is  sufficiently
+     trustworthy, recover can be installed with the same  permis-
+     sions  the  nethack executable has.  In either case, recover
+     is easily compiled from the distribution utility directory.
+
+NOTES
+     Like nethack itself, recover will overwrite  existing  save-
+     files  of  the  same name.  Savefiles created by recover are
+     uncompressed; they may be compressed afterwards if  desired,
+     but  even  a compression-using nethack will find them in the
+     uncompressed form.
+
+SEE ALSO
+     nethack(6)
+
+BUGS
+     recover makes no attempt to find out if a base  name  speci-
+     fies a game in progress.  If multiple machines share a play-
+     ground, this would be impossible to determine.
+
+     recover should be taught to use the nethack playground lock-
+     ing mechanism to avoid conflicts.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+January                  Last change: 9                         2
+
+
+
diff --git a/doc/tmac.n b/doc/tmac.n
new file mode 100644 (file)
index 0000000..1c8f3f0
--- /dev/null
@@ -0,0 +1,764 @@
+\" @(#)$Id: tmac.n,v 1.3 2000/02/02 18:49:05 dean Exp $
+.\" The News macro package
+.\"
+.\" This  is  the macro package that is used to format news documents.  It
+.\" was written because many sites do not have one of the -mm or -ms pack-
+.\" ages that the documents use.   This is NOT compatible with EITHER, but
+.\" (I hope) will become the standard for all news  documents  (man  pages
+.\" excepted, since everyone seems to have -man.)
+.\"
+.\" This package was written using  only  the  "NROFF/TROFF Users' Guide",
+.\" and  therefore  if  you  can run NROFF/TROFF, you can legitimately use
+.\" this package.  However, because NROFF/TROFF are proprietary  programs,
+.\" I  cannot  place  this  package in the public domain.  This should not
+.\" matter, because if you legitimately have  NROFF/TROFF,  you  have  the
+.\" documentation; if not, you can't run off the documentation anyway.
+.\"
+.\" This  package may be circulated freely with the news documentation; it
+.\" may not be sold, but is to be distributed with  the  unformatted  news
+.\" documents.  However,  the name of the author and the place at which it
+.\" was written (in the author's own  time,  of  course)  are  not  to  be
+.\" removed  from the package regardless of how it is modified or altered.
+.\" Further, please do not distribute this package if you make any changes
+.\" because  I  don't want to get bug reports of macros I haven't written;
+.\" if you have a goodie you want me to add, send it to me and we'll talk.
+.\" (I really do like feedback!)  I'd really appreciate your cooperation.
+.\"
+.\" Author:    Matt Bishop
+.\"            Research Institute for Advanced Computer Science
+.\"            Mail Stop 230-5
+.\"            NASA Ames Research Center
+.\"            Moffett Field, CA  94035
+.\"
+.\" version 1.0                September 28, 1985      mab@riacs.arpa
+.\"    initial version
+.\" version 1.1                October 25, 1985        mab@riacs.arpa
+.\"    fixed an incredibly obscure footnote bug (that occurred twice in
+.\"    the news documentation!) which put footnoted words on  one  page
+.\"    and the footnote on the next if the word was in the next-to-last
+.\"    or last line; commented it, and generally cleaned up
+.\" Version 1.2                October 27, 1985        mab@riacs.arpa
+.\"    Added a few more comments and a check to keep footnotes lined up
+.\"    with the bottom margin.
+.\" Version 1.3                February 12, 1986       mab@riacs.arpa
+.\"    Added an error check to catch unmatched ef's and ed's
+.\" Version 1.4                December 29, 1986       mab@riacs.edu
+.\"    Changed footnote for ux, pd, and vx macros and  added  a  string
+.\"    for rg ("Registered Trademark")
+.\" Version 1.5                January 2, 1989         Matt.Bishop@dartmouth.edu
+.\"    Minor modifications for nroff compatibility
+.\" Version 1.6                March 15, 1989          Matt.Bishop@dartmouth.edu
+.\"                                            ..!bear.dartmouth.edu!bishop
+.\"    Fixed a bug in footnote handling (again, sigh ...)  This one
+.\"    occurred when the the "fo" trap position was reset just beneath
+.\"    the current line; the footnote overflow trap would kick in and
+.\"    never be closed.
+.\"
+.\"
+.\" **********
+.\" these preserve and restore various things
+.\" they are used to shorten other macros
+.de yf                                 \" restore fonts
+.ft \\n(f2                             \" previous font
+.ft \\n(f1                             \" current font
+..
+.de yi                                 \" restore indents
+'in \\n(i2u                            \" previous indent
+'in \\n(i1u                            \" current indent
+..
+.de ys                                 \" restore point sizes
+.ps \\n(s2                             \" previous point size
+.ps \\n(s1                             \" current point size
+..
+.de yv                                 \" restore vertical spacings
+.vs \\n(v2u                            \" previous vertical spacing
+.vs \\n(v1u                            \" current vertical spacing
+..
+.de ya                                 \" restore everything
+.yf                                    \" restore fonts
+.yi                                    \" restore indents
+.ys                                    \" restore point sizes
+.yv                                    \" restore vertical spacing
+..
+.de zf                                 \" preserve fonts
+.nr f1 \\n(.f                          \" current font
+.ft                                    \" switch to previous font
+.nr f2 \\n(.f                          \" previous font
+.ft                                    \" back to current font
+..
+.de zi                                 \" preserve indents
+.nr i1 \\n(.iu                         \" current indent
+'in                                    \" switch to previous indent
+.nr i2 \\n(.iu                         \" previous indent
+'in                                    \" back to current indent
+..
+.de zs                                 \" preserve point sizes
+.nr s1 \\n(.su                         \" current point size
+.ps                                    \" switch to previous point size
+.nr s2 \\n(.su                         \" previous point size
+.ps                                    \" back to current point size
+..
+.de zv                                 \" preserve vertical spacings
+.nr v1 \\n(.vu                         \" current vertical spacing
+.vs                                    \" switch to previous vertical spacing
+.nr v2 \\n(.vu                         \" previous vertical spacing
+.vs                                    \" back to current vertical spacing
+..
+.de za                                 \" save everything
+.zf                                    \" save fonts
+.zi                                    \" save indents
+.zs                                    \" save point sizes
+.zv                                    \" save vertical spacings
+..
+.\" **********
+.\" these actually print the header and footer titles
+.\" they are defined separately from the "hd" and "fo" macros
+.\" to make user redefinition easy
+.de pt                                 \" print header title
+.                                      \" omit header on first page
+.if \\n%>1 \{\
+'      sp |\\$1u                       \" move to proper position
+.      ft 1                            \" change to default font
+.      ps \\n(ps                       \" change to default point size
+.      vs \\n(vs                       \" change to default spacing
+.      tl '\\*(h0'\\*(h1'\\*(h2'       \" center title
+.      vs                              \" restore current vertical spacing
+.      ps                              \" restore current point size
+.      ft                              \" restore current font
+.\}
+..
+.de pf                                 \" print footer title
+.ft 1                                  \" change to default font
+.ps \\n(ps                             \" change to default point size
+.vs \\n(vs                             \" change to default spacing
+.ie \\n%=1 .tl '\\*(h0'\\*(h1'\\*(h2'  \" on first page, print the header here
+.el        .tl '\\*(f0'\\*(f1'\\*(f2'  \" on other pages, print the footer
+.vs                                    \" restore current vertical spacing
+.ps                                    \" restore current point size
+.ft                                    \" restore current font
+..
+.\" **********
+.\" these are the top of page (header) and bottom of page (footer) macros
+.\" they don't actually print anything, just call the right macros
+.de hd                                 \" header -- do top of page processing
+.if t .if \\n(cm .tl '\(rn'''          \" drop cut mark if needed
+.pt \\n(ttu                            \" print header
+.nr fc 0 1                             \" init footnote count
+.nr fs \\n(.pu-\\n(bmu-1u              \" if any footnotes, start print here
+.nr fp 0-\\n(bmu                       \" reset current footer place
+.ch fo -\\n(bmu                                \" reset footer trap
+.if \\n(dn .fz                         \" put leftover footnotes st bottom
+.ya                                    \" restore font, etc.
+'sp |\\n(tmu                           \" move to top of body
+.ns                                    \" don't allow any more space
+..
+.de fo                                 \" footer -- do bottom of page processing
+.za                                    \" save font, etc.
+.rs                                    \" you want motions here
+.nr dn 0                               \" clobber diversion size register
+.if \\n(fc .fd                         \" now print the footnotes, if any
+'bp                                    \" force out page
+..
+.\" **********
+.\" these are the footnote macros
+.\" here's an overview:
+.\"    Footnotes are processed in environment #1, which is  initialized
+.\"    at the bottom of this package.  When "fn" is called, nroff/troff
+.\"    switches to this environment.  The body of the footnote is saved
+.\"    in  the  diversion  "tf" (for "temporary footnote"), so you will
+.\"    NEVER spring a trap during the first reading of a footnote. When
+.\"    "ef" ("end footnote") is called,  the diversion  is  closed.  If
+.\"    this  is the first footnote on the page (ie, the number register
+.\"    "fc" is 1), and the footnote height (plus the height of 1  line)
+.\"    crosses  the  bottom  margin,  you get the footnoted word on one
+.\"    page and the footnote on the other.  In this case we  just  call
+.\"    "fo"  manually  (taking case it cannot be re-invoked on the same
+.\"    page!)  If this situation does not occur,  we  just  adjust  the
+.\"    footer  trap's  position upwards (we'll get to how far in a min-
+.\"    ute); if this puts the trap above the current line,  we  reposi-
+.\"    tion  the trap just beneath the current line to be sure of trig-
+.\"    triggering it once the current line is forced out.
+.\"     To reposition the footer trap, we proceed as  follows.  Because
+.\"    the  trap  may be sprung in the middle of a line, it is possible
+.\"    that the footnote will not fit on the page (regardless of  where
+.\"    on the page the footnoted word occurs -- really!) if we move the
+.\"    trap up by the size of  the  footnote  diversion  "tf".  So,  we
+.\"    fudge things a little bit -- for the first footnote on each page
+.\"    we move the footer trap up 1 extra line ("line" being 1v in env-
+.\"    ironment  #0).   Unless  the point size and vertical spacing are
+.\"    increased between the first footnote and the footer trap's being
+.\"    sprung,  this  will  keep  the footnotes on the same page as the
+.\"    footnoted word.  But as there may be now as much as 1v of  space
+.\"    between the footnote and the bottom margin, which looks HIDEOUS,
+.\"    we use the number register "fs" to mark where  the  footer  trap
+.\"    would  REALLY go, and just space to it when it comes time to put
+.\"    out the footnotes.
+.de fd                                 \" dump footnotes
+.nr gs 1v                              \" get a measure of 1 line in env #0
+.ev 1                                  \" switch to footnote environment
+.nr gs +2v                             \" min of 2 lines of footnotes
+.                                      \" if the number register ns > 0,
+.                                      \" the last text line may contain a
+.                                      \" footnote that is too big to fit;
+.                                      \" this checks for such a note and
+.                                      \" if so, forces the footnote into
+.                                      \" the "fy" diversion that carries
+.                                      \" it onto the next text page
+.ie (\\n(nsu>0)&(\\n(gsu>=\\n(.tu) 'sp \\n(gsu \" be sure you can get it down
+.el .if \\n(fsu>\\n(nlu 'sp \\n(fsu-\\n(nlu    \" move to footnote start position
+'nf                                    \" don't reprocess footnotes
+'in 0                                  \" don't indent them any more either
+.tf                                    \" drop text of footnotes
+.rm tf
+.if '\\n(.z'fy' .di                    \" end overflow diversion, if any
+.nr fc 0                               \" re-init footnote count
+.ev                                    \" return to usual environment
+..
+.de fn                                 \" start footnote
+.                                      \" look for nested footnotes -- ILLEGAL
+.ie \\n(if>0 .er "footnote within footnote"
+.el .da tf                             \" append footnote to footnote diversion
+.nr if +1                              \" increment level of footnoting
+.nr fc +1                              \" one more footnote on this page
+.if \\n(fc=1 .nr fp -1v                        \" The reason for this "fudge factor"
+.                                      \" is that there is no way to force
+.                                      \" NROFF/TROFF to invoke a macro at
+.                                      \" the end of each line.  At times,
+.                                      \" the trap boundary will not match up
+.                                      \" with the bottom of a line, so the
+.                                      \" "fo" trap which is set at 2320 may
+.                                      \" not be triggered until 2340 -- and
+.                                      \" then the footnote won't fit.  This
+.                                      \" gives some slack so the footnote is
+.                                      \" more likely to fit. *sigh*
+.ev 1                                  \" enter footnote environment
+.if \\n(fc=1 .fs                       \" drop separator if first footnote
+.br                                    \" flush out any previous line in footnote
+.fi                                    \" process footnote in fill mode
+..
+.de ef                                 \" end footnote
+.br                                    \" flush out the line in footnote
+.ie \\n(if<=0 .er "end footnote has no corresponding begin footnote"
+.el \{\
+.      nr if -1                        \" decrement level of footnoting
+.      nr fg 2v                        \" remember this for repositioning fo
+.      ev                              \" back to usual environment
+.      if \\n(if=0 \{\
+.              di                      \" end of footnote proper
+.              nr fp -\\n(dnu          \" "fo" will be moved at least up this far
+.              nr fs -\\n(dnu          \" increase size of footnote
+.              ch fo \\n(fpu           \" reposition "fo" trap (first guess)
+.                                      \" the first part of the "ie" clause
+.                                      \" is taken in the special case
+.                                      \" described above
+.              ie (\\n(fc=1)&((\\n(nlu+1v+\\n(fgu)>=(\\n(.pu-\\n(bmu)) \{\
+.                      nr ns \\n(dnu   \" suppress footnote separator
+.                                      \" since this footnote contains it
+.                                      \" keep "fo" from being invoked twice
+.                      ch fo \\n(.pu+1i
+.                      fo              \" force the page out AT ONCE
+.                      nr ns 0         \" re-enable footnote separator
+.              \}
+.                                      \" footnote won't fit completely
+.                                      \" invoke the footer trap but
+.                                      \" don't worry about the footnote
+.                                      \" separator (it's already there)
+.              el .if (\\n(nlu+1v)>=(\\n(.pu+\\n(fpu) \{\
+.                                      \" as before we must reposition the
+.                                      \" "fo" trap to prevent "fo" from
+.                                      \" being invoked twice
+.                      ch fo \\n(.pu+1i
+.                      fo              \" force the page out AT ONCE
+.              \}
+.      \}
+.\}
+..
+.de fs                                 \" drop footnote separator
+.                                      \" only if not already dropped
+.if \\n(ns=0 \l'1i'
+.nr ns 0                               \" in case footnotes are over 1 page long
+..
+.de fx                                 \" process footnote overflow
+.if \\n(fc .di fy                      \" stuff them in the right place
+..
+.de fz                                 \" deposit footnote overflow
+.fn                                    \" treat it as a footnote
+.nf                                    \" it's already been processed
+.in 0                                  \"   and indented
+.fy                                    \" "fx" put it here
+.ef                                    \" end the footnote
+..
+.\" **********
+.\" the ones after here are user-invoked (like "fn" and "ef" above)
+.\" title, author, etc.
+.de mt                                 \" main title
+\&
+.sp |\\n(mtu                           \" space
+.ft 3                                  \" in bold
+.ps \\n(ps+2p                          \" large point size and
+.vs \\n(vs+2p                          \" vertical spacing
+.ce 1000                               \" center the title
+.nr t2 1                               \" space it
+..
+.de au                                 \" author
+.nr t2 0                               \" spacing here
+.sp 2v                                 \" space
+.ft 2                                  \" in italics
+.ps \\n(ps                             \" usual point size and
+.vs \\n(vs                             \" vertical spacing
+.ce 1000                               \" center the name(s)
+..
+.de ai                                 \" author's institution
+.if \\n(t2 .sp 2v                      \" space after a title
+.nr t2 0                               \" institution
+.ft 2                                  \" in italics
+.ps \\n(ps                             \" usual point size and
+.vs \\n(vs                             \" vertical spacing
+.ce 1000                               \" center the name(s)
+..
+.de bt                                 \" begin text macro
+.nr t2 0                               \" hold it here
+.nr it +1                              \" mark as called
+.ce 0                                  \" end any centering
+.sn 3v                                 \" a little bit of space
+..
+.\" paragraph
+.de si                                 \" start indented section
+.nr lo \\n(lm                          \" remember the current level
+.nr lm +1                              \" go to the next level
+.ie '\\$1'' .nr l\\n(lm \\n(l\\n(lo+5n \" if no arg, indent 5n
+.el         .nr l\\n(lm \\$1n          \" otherwise, indent that much
+..
+.de ei                                 \" end indent
+.nr lm -1                              \" down one level
+.if \\n(lm<0 .nr lm 0                  \" make sure you don't go too far
+..
+.de pg                                 \" plain old paragraph
+.if !\\n(it .bt                                \" end the title and such
+.sn \\n(pdu                            \" inter-paragraph spacing
+.ft 1                                  \" reset a few things (paranoia)
+.                                      \" these ONLY if not in footnote
+.ie \\n(if=0 \{\
+.      ps \\n(ps                       \" reset point size
+.      vs \\n(vs                       \" reset vertical spacing
+.      ne 1v+\\n(.Vu                   \" slightly more than 1 line
+.\}
+.el \{\
+.      ps \\n(ps-2p                    \" reset point size
+.      vs \\n(vs-2p                    \" reset vertical spacing
+.\}
+.in \\n(l\\n(lmu                       \" stop any indenting
+.ce 0                                  \" stop any centering
+.if !'\\$1'L' .if !'\\$1'l' .ti +\\n(piu       \" indent the sucker
+..
+.de lp                                 \" labelled paragraph
+.pg l                                  \" reset paragraph
+.if \\n(.$>1 .nr li \\$2n              \" if indent given use it
+.in +\\n(liu                           \" indent for paragraph
+.ti -\\n(liu                           \" force first line NOT to indent
+.ta +\\n(liu                           \" for the label
+\&\\$1\t\c
+.if \\w'\\$1'u>=(\\n(l\\n(lmu+\\n(liu) .br     \" don't overwrite
+..
+.\" The following two macros (hu & hn) have been modified for ELM usage.
+.\" If the macros have text as part of the macro call, the text will be
+.\" increased in size by two points.  After printing the text, the font
+.\" will be returned to normal, otherwise the font will be left bold.
+.\"
+.\" section
+.de hu                                 \" header, unnumbered
+.                                      \" format: .hu [text]
+.if !\\n(it .bt                                \" end the title and such
+.br                                    \" force out previous line
+.b
+.ie \\n(hP .ps \\n(hP
+.el        .ps \\n(ps
+.ie \\n(hv .vs \\n(hv
+.el        .vs \\n(vs
+.in \\n(l\\n(lmu                       \" stop any indenting
+.sn \\n(hsu                            \" inter-section spacing
+.ne 3v+\\n(.Vu                         \" slightly more than 3 lines
+.fi                                    \" process the text, too
+.if \\n(.$>=1 \{\
+.ps +2
+\\$1
+.\}
+.if \\n(.$>=2 \\$2
+.if \\n(.$>=3 \\$3
+.if \\n(.$>=4 \\$4
+.if \\n(.$>=5 \\$5
+.if \\n(.$>=6 \\$6
+.if \\n(.$>=7 \\$7
+.if \\n(.$>=8 \\$8
+.if \\n(.$=9 \\$9
+.if \\n(.$>=1 \{\
+.ps -2
+.br
+.ft 1
+.\}
+..
+.de hn                                 \" header, numbered
+.                                      \" format: .hn [level] [text]
+.if !\\n(it .bt                                \" end the title and such
+.br                                    \" force out previous line
+.b
+.ie \\n(hP .ps \\n(hP
+.el        .ps \\n(ps
+.ie \\n(hv .vs \\n(hv
+.el        .vs \\n(vs
+.in \\n(l\\n(lmu                       \" stop any indenting
+.sn \\n(hsu                            \" inter-section spacing
+.ne 3v+\\n(.Vu                         \" slightly more than 3 lines
+.fi                                    \" process the text, too
+.ie !'\\$1'' .nr hn \\$1
+.el          .nr hn 1
+.ie \\n(hn>0 .nr hn -1
+.el          .nr hn 0
+.ie \\n(hn=0 \{\
+.      nr h0 +1                        \" add 1 to main section header
+.      nr h1 0                         \" zap remaining section numbers
+.      nr h2 0                         \" zap remaining section numbers
+.      nr h3 0                         \" zap remaining section numbers
+.ie \\n(.$>=2 \{\
+.ps +2
+\\n(h0.
+.ps -2
+.\}
+.el \\n(h0.
+.\}
+.el .ie \\n(hn=1 \{\
+.      nr h1 +1                        \" add 1 to the section header
+.      nr h2 0                         \" zap remaining section numbers
+.      nr h3 0                         \" zap remaining section numbers
+.ie \\n(.$>=2 \{\
+.ps +2
+\\n(h0.\\n(h1.
+.ps -2
+.\}
+.el \\n(h0.\\n(h1.
+.\}
+.el .ie \\n(hn=2 \{\
+.      nr h2 +1                        \" add 1 to the section header
+.      nr h3 0                         \" zap remaining section numbers
+.ie \\n(.$>=2 \{\
+.ps +2
+\\n(h0.\\n(h1.\\n(h2.
+.ps -2
+.\}
+.el \\n(h0.\\n(h1.\\n(h2.
+.\}
+.el \{\
+.      nr h3 +1                        \" add 1 to the section number
+.ie \\n(.$>=2 \{\
+.ps +2
+\\n(h0.\\n(h1.\\n(h2.\\n(h3.
+.ps -2
+.\}
+.el \\n(h0.\\n(h1.\\n(h2.\\n(h3.
+.\}
+.if \\n(.$>=2 \{\
+.ps +2
+\\$2
+.\}
+.if \\n(.$>=3 \\$3
+.if \\n(.$>=4 \\$4
+.if \\n(.$>=5 \\$5
+.if \\n(.$>=6 \\$6
+.if \\n(.$>=7 \\$7
+.if \\n(.$>=8 \\$8
+.if \\n(.$>=9 \\$9
+.if \\n(.$>=2 \{\
+.br
+.ft 1
+.ps -2
+.\}
+..
+.\" displays (no floats, thank God!)
+.de sd                                 \" start display
+.                                      \" look for nested displays -- ILLEGAL
+.ie \\n(id>0 .er "display within display"
+.el \{\
+.      ie '\\$1'c' .nr sf 1            \" center the sucker
+.      el          .nr sf 0            \" don't center it
+.\}
+.sn \\n(pdu                            \" a little bit of space
+.ev 2                                  \" switch to display environment
+.nf                                    \" what you type is what you get
+.if \\n(id=0 .di dd                    \" start saving text
+.rs                                    \" don't eat leading space
+.nr id +1                              \" increment level of display
+..
+.de ed                                 \" end display
+.br                                    \" flush line
+.ie \\n(id<=0 .er "end display has no corresponding begin display"
+.el \{\
+.      nr id -1                        \" decrement level of display
+.      if \\n(id=0 \{\
+.              di                      \" end diversion
+.              fi                      \" resume filling
+.              in -\\n(piu             \" dedent
+.              ev                      \" pop environment
+.              ne \\n(dnu              \" be sure you have room
+.              nf                      \" don't reprocess display
+.              rs                      \" don't eat leading space
+.              zi                      \" save indents
+.              ie \\n(sf .in (\\n(llu-\\n(dlu)/2u      \" center on the line length
+.              el .in +\\n(piu         \" indent the sucker
+.              dd                      \" drop display
+.              yi                      \" restore indents
+.      \}
+.\}
+.fi                                    \" resume filling
+.sn \\n(pdu                            \" a little bit of space
+..
+.\" **********
+.\" fonts -- if argument(s), apply only to first
+.de b                                  \" bold (font 3)
+.ie \\n(.$>0 \\&\\$3\\f3\\$1\\fP\\$2
+.el .ft 3
+..
+.de i                                  \" italics (font 2)
+.ie \\n(.$>0 \\&\\$3\\f2\\$1\\fP\\$2
+.el .ft 2
+..
+.de r                                  \" roman (font 1)
+.ft 1                                  \" just restore it
+..
+.de bi                                 \" bold italics (embolden font 2)
+\\&\\$3\c
+\\kb\\f2\\$1\\fP\\h'|\\nbu+2u'\\f2\\$1\\fP\\$2
+..
+.\" **********
+.\" point sizes -- if argument(s), apply only to first
+.de sm                                 \" reduce point size by 2
+.ie \\n(.$>0 \\&\\$3\\s-2\\$1\\s0\\$2
+.el .ps -2
+..
+.de is                                 \" increase point size by 2
+.ie \\n(.$>0 \\&\\$3\\s+2\\$1\\s0\\$2
+.el .ps +2
+..
+.de nl                                 \" return to normal size
+.ps \\n(ps                             \" just reset the point size
+..
+.\" **********
+.\" handy force space/inhibit more space macros
+.de sn                                 \" space, then turn on nospace mode
+.sp \\$1                               \" space
+.ns                                    \" ignore any more space requests
+..
+.de sr                                 \" force out space
+.rs                                    \" turn on spacing mode
+.sp \\$1                               \" space
+..
+.\" **********
+.\" end of text and error macros
+.de et                                 \" end of text macro
+.                                      \" this: (1) flushes rest of line
+.                                      \" (2) trips the footer, taking
+.                                      \" care of footnotes
+.sp \\n(.pu
+.                                      \" check for open displays or footnotes
+.if \\n(id>0 .er "unfinished display"
+.if \\n(if>0 .er "unfinished footnote"
+.                                      \" this one means an -mn bug (*sigh*)
+.if !'\\n(.z'' .er "diversion \\n(.z not closed"
+..
+.de er                                 \" print error message
+.                                      \" flag it as an error
+.ds ws "** ERROR **
+.                                      \" if you have it, give the file name
+.if !'\\*(.f'' .as ws " file \\*(.f,
+.                                      \" put out the line number
+.as ws " line \\n(.c
+.                                      \" and finally the error message
+.tm \\*(ws: \\$1
+..
+.\" **********
+.\" macros in this section are VERY specific to the news documentation
+.de pa                                 \" protocol appellation (darn names!)
+\\&\\$3\\f2\\$1\\fP\\$2
+..
+.de ng                                 \" news group name
+\\&\\$3\\f3\\$1\\fP\\$2
+..
+.de cn                                 \" computer name
+\\&\\$3\\f2\\$1\\fP\\$2
+..
+.de hf                                 \" header field
+\\&\\$3\\*(lq\\$1\\*(rq\\$2
+..
+.de cf                                 \" contents of field
+\\&\\$3\\*(lq\\$1\\*(rq\\$2
+..
+.de qc                                 \" quote control char (command)
+\\&\\$3\\f3<\\s-2\\$1\\s0>\\fP\\$2
+..
+.de qp                                 \" quote printing char (command)
+\\&\\$3\\f3\\$1\\fP\\$2
+..
+.de op                                 \" option
+\\&\\$3\\f3\\$1\\fP\\$2
+..
+.\" **********
+.\" trademarked names
+.de pd                                 \" print "PDP-11"
+.ie \\n(p1 \\&\\$2\\s-1PDP\\s0-11\\$1
+.el \{\
+.      nr p1 +1                        \" mark footnote as dropped
+\\&\\$2\\s-1PDP\\s0-11\\*(rg\\$1
+.      fn                              \" put out the footnote
+\\&\\*(rgPDP-11 is a registered trademark of Digital Equipment Corporation.
+.      ef                              \" short and sweet ...
+.\}
+..
+.de ux                                 \" print "UNIX"
+.ie \\n(ux \\&\\$2\\s-1UNIX\\s0\\$1
+.el \{\
+.      nr ux +1                        \" mark footnote as dropped
+\\&\\$2\\s-1UNIX\\s0\\*(rg\\$1
+.      fn                              \" put out the footnote
+\\&\\*(rgUNIX is a registered trademark of AT&T.
+.      ef                              \" short and sweet ...
+.\}
+..
+.de vx                                 \" print "VAX"
+.ie \\n(vx \\&\\$2\\s-1VAX\\s0\\$1
+.el \{\
+.      nr vx +1                        \" mark footnote as dropped
+\\&\\$2\\s-1VAX\\s0\\*(rg\\$1
+.      fn                              \" put out the footnote
+\\&\\*(rgVAX is a trademark of Digital Equipment Corporation.
+.      ef                              \" short and sweet ...
+.\}
+..
+.\" **********
+.\" set up string and number registers
+.                                      \" set up for the date
+.if \n(mo=1  .ds mo January
+.if \n(mo=2  .ds mo February
+.if \n(mo=3  .ds mo March
+.if \n(mo=4  .ds mo April
+.if \n(mo=5  .ds mo May
+.if \n(mo=6  .ds mo June
+.if \n(mo=7  .ds mo July
+.if \n(mo=8  .ds mo August
+.if \n(mo=9  .ds mo September
+.if \n(mo=10 .ds mo October
+.if \n(mo=11 .ds mo November
+.if \n(mo=12 .ds mo December
+.nr Yr \n(yr+1900
+.ds dy "\*(mo \n(dy, \n(Yr
+.if \n(dw=1  .ds dw Sunday
+.if \n(dw=2  .ds dw Monday
+.if \n(dw=3  .ds dw Tuesday
+.if \n(dw=4  .ds dw Wednesday
+.if \n(dw=5  .ds dw Thursday
+.if \n(dw=6  .ds dw Friday
+.if \n(dw=7  .ds dw Saturday
+.                                      \" NROFF dependencies
+.if n \{\
+.                                      \" string registers
+.      ds rg (R)
+.      ds lq ""
+.      ds rq ""
+.      ds f1 "\*(dy
+.                                      \" number registers
+.      nr hs 1v                        \" space before section header
+.      nr pd 1v                        \" inter-paragraph spacing
+.      nr bm 1.0i                      \" height of bottom margin
+.\}
+.                                      \" NROFF dependencies
+.if t \{\
+.                                      \" string registers
+.      ds rg \\u\\s-2\\(rg\\s0\\d
+.      ds lq ``
+.      ds rq ''
+.                                      \" number registers
+.      nr hs 1v                        \" space before section header
+.      nr pd 0.3v                      \" inter-paragraph spacing
+.      nr bm 1.0i+1v                   \" height of bottom margin (wacky laser)
+.\}
+.                                      \" these are the same for [NT]ROFF
+.ds dg \(dg
+.ds vr "News Version B2.11
+.ds pv "News macros 1.5
+.ds h1 - % -
+.nr bt 0.5i+1v                         \" bottom of page to footer
+.nr cm 0                               \" no cut marks
+.nr fc 0 1                             \" init footnote count
+.nr fl 5.5i                            \" footnote line length
+.nr fp 0-\n(bmu                                \" fo macro trap location
+.nr h0 0                               \" init section header level 0
+.nr h1 0                               \" init section header level 1
+.nr h2 0                               \" init section header level 2
+.nr h3 0                               \" init section header level 3
+.nr id 0                               \" 1 in display
+.nr if 0                               \" 1 in keep
+.nr it 0                               \" 1 when beyond title, etc.
+.nr li 5n                              \" indent for labelled paragraph
+.nr ll 6.5i                            \" line length
+.nr lm 0                               \" left margin
+.nr l0 0                               \" first indent level
+.nr mt 1.5i+1v                         \" title goes down this far
+.nr pi 5n                              \" regular paragraph indent
+.nr po 1.0i                            \" page offset
+.nr ps 10                              \" point size
+.nr tm 1.0i                            \" height of top margin
+.nr tt 0.5i-0.5v                       \" top of page to header
+.nr p1 0                               \" no PDP-TM message yet
+.nr ux 0                               \" no UNIX-TM message yet
+.nr vx 0                               \" no VAX-TM message yet
+.nr vs 12                              \" vertical spacing
+.\" set things up
+.\" DSINC changes for XROFF
+.nr f1 1
+.nr f2 1
+.nr s1 10
+.nr s2 10
+.nr v1 12
+.nr v2 12
+.ps 10
+.vs 12
+.\" DSINC end changes for XROFF
+.po \n(pou                             \" set page offset
+.ps \n(ps                              \" set previous, current
+.ps \n(ps                              \"   point sizes
+.vs \n(vs                              \" set previous, current
+.vs \n(vs                              \"   vertical spacings
+.ll \n(llu                             \" set line length
+.lt \n(llu                             \" set title line length
+.ev 1                                  \" *** footnote environment
+.ps \n(ps-2p                           \" set previous, current
+.ps \n(ps-2p                           \"   point sizes
+.vs \n(vs-2p                           \" set previous, current
+.vs \n(vs-2p                           \"   vertical spacings
+.ll \n(flu                             \" set line length
+.lt \n(flu                             \" set title line length
+.ev                                    \" *** pop environment
+.ev 2                                  \" *** footnote environment
+.ps \n(ps                              \" set previous, current
+.ps \n(ps                              \"   point sizes
+.vs \n(vs                              \" set previous, current
+.vs \n(vs                              \"   vertical spacings
+.ll \n(llu                             \" set line length
+.lt \n(llu                             \" set title line length
+.ev                                    \" *** pop environment
+.\" now set internal registers (for the first header section)
+.nr f1 \n(.f                           \" saved font #1
+.nr f2 \n(.f                           \" saved font #2
+.nr s1 \n(.s                           \" saved point size #1
+.nr s2 \n(.s                           \" saved point size #2
+.nr v1 \n(.v                           \" saved vertical spacing #1
+.nr v2 \n(.v                           \" saved vertical spacing #2
+.\" install traps
+.wh 0i hd                              \" position header trap
+.wh -\n(bmu fo                         \" position footer trap
+.wh \n(.pu+1i fx                       \" put footnote overflow trap here
+.ch fx -\n(bmu                         \" move it over fo
+.wh -\n(btu pf                         \" print the bottom margin here
+.em et                                 \" at end of file, call et
+.\" couple of miscellaneous requests
+.bd S 3 3                              \" embolden special font chars if B
+.hy 2                                  \" don't hyphenate last lines
+
diff --git a/doc/window.doc b/doc/window.doc
new file mode 100644 (file)
index 0000000..cbfc571
--- /dev/null
@@ -0,0 +1,805 @@
+Introduction
+
+This file documents the support for various windowing systems in
+NetHack.  The support is through a standard interface, separating the
+main NetHack code from window-system specific code.  The implementation
+supports multiple window systems in the same binary.  Even if you only
+wish to support one window-port on your port, you will need to follow
+the instructions in Section IX to get a compilable binary.
+
+Contents:
+       I.    Window Types and Terminology
+       II.   Interface Specification
+       III.  Global variables
+       IV.   WINCAP preferences support
+       V.    New or respecified common, high level routines
+       VI.   Helper routines
+       VII.  Game startup
+       VIII. Conventions
+       IX.   Implementation and Multi-window support
+
+I.  Window Types and Terminology
+
+There are 5 basic window types, used to call create_nhwindow():
+
+       NHW_MESSAGE     (top line)
+       NHW_STATUS      (bottom lines)
+       NHW_MAP         (main dungeon)
+       NHW_MENU        (inventory or other "corner" windows)
+       NHW_TEXT        (help/text, full screen paged window)
+
+The tty window-port also uses NHW_BASE (the base display) internally.
+
+NHW_MENU windows can be used for either menu or text display.  Their
+basic feature is that for the tty-port, if the window is small enough,
+it appears in the corner of the tty display instead of overwriting
+the whole screen.  The first call to add information to the window
+will decide if it is going to be used to display a menu or text.
+If start_menu() is called, then it will be used as a menu.  If
+putstr() is called, it will be used as text.  Once decided, there
+is no turning back.  For the tty-port, if the data is too large for
+a single screen then the data is paged (with --more--) between pages.
+Only NHW_MENU type windows can be used for menus.
+
+NHW_TEXT windows are used to display a large amount of textual data.
+This is the type of window one would use for displaying a help file,
+for example.  In the tty window-port, windows of type NHW_TEXT can
+page using the DEF_PAGER, if DEF_PAGER is defined.  There exists an
+assumption that the font for text windows is monospaced.  The help
+files are all formatted accordingly.
+
+"window" is always of type winid.  This is currently implemented as an
+integer, but doesn't necessarily have to be done that way.  There are
+a few fixed window names that are known throughout the code:
+
+       WIN_MESSAGE     (top line)
+       WIN_STATUS      (bottom lines)
+       WIN_MAP         (main dungeon)
+       WIN_INVEN       (inventory)
+
+Other windows are created and destroyed as needed.
+
+"Port" in this document refers to a CPU/OS/hardware platform (UNIX, MSDOS
+TOS, etc.)  "window-port" refers to the windowing platform.  This is
+orthogonal (e.g.  UNIX might use either a tty window-port or an X11
+window-port).
+
+
+II.  Interface Specification
+
+All functions below are void unless otherwise noted.
+
+A.  Low-level routines:
+
+raw_print(str) -- Print directly to a screen, or otherwise guarantee that
+                  the user sees str.  raw_print() appends a newline to str.
+                  It need not recognize ASCII control characters.  This is
+                  used during startup (before windowing system initialization
+                  -- maybe this means only error startup messages are raw),
+                  for error messages, and maybe other "msg" uses.  E.g.
+                  updating status for micros (i.e, "saving").
+raw_print_bold(str)
+               -- Like raw_print(), but prints in bold/standout (if possible).
+curs(window, x, y)
+               -- Next output to window will start at (x,y), also moves
+                  displayable cursor to (x,y).  For backward compatibility,
+                  1 <= x < cols, 0 <= y < rows, where cols and rows are
+                  the size of window.
+               -- For variable sized windows, like the status window, the
+                  behavior when curs() is called outside the window's limits
+                  is unspecified. The mac port wraps to 0, with the status
+                  window being 2 lines high and 80 columns wide.
+               -- Still used by curs_on_u(), status updates, screen locating
+                  (identify, teleport).
+               -- NHW_MESSAGE, NHW_MENU and NHW_TEXT windows do not
+                  currently support curs in the tty window-port.
+putstr(window, attr, str)
+               -- Print str on the window with the given attribute.  Only
+                  printable ASCII characters (040-0126) must be supported.
+                  Multiple putstr()s are output on separate lines.  Attributes
+                  can be one of
+                       ATR_NONE (or 0)
+                       ATR_ULINE
+                       ATR_BOLD
+                       ATR_BLINK
+                       ATR_INVERSE
+                  If a window-port does not support all of these, it may map
+                  unsupported attributes to a supported one (e.g. map them
+                  all to ATR_INVERSE).  putstr() may compress spaces out of
+                  str, break str, or truncate str, if necessary for the
+                  display.  Where putstr() breaks a line, it has to clear
+                  to end-of-line.
+               -- putstr should be implemented such that if two putstr()s
+                  are done consecutively the user will see the first and
+                  then the second.  In the tty port, pline() achieves this
+                  by calling more() or displaying both on the same line.
+get_nh_event() -- Does window event processing (e.g. exposure events).
+                  A noop for the tty and X window-ports.
+int nhgetch()  -- Returns a single character input from the user.
+               -- In the tty window-port, nhgetch() assumes that tgetch()
+                  will be the routine the OS provides to read a character.
+                  Returned character _must_ be non-zero and it must be
+                   non meta-zero too (zero with the meta-bit set).
+int nh_poskey(int *x, int *y, int *mod)
+               -- Returns a single character input from the user or a
+                  a positioning event (perhaps from a mouse).  If the
+                  return value is non-zero, a character was typed, else,
+                  a position in the MAP window is returned in x, y and mod.
+                  mod may be one of
+
+                       CLICK_1         /* mouse click type 1 */
+                       CLICK_2         /* mouse click type 2 */
+
+                  The different click types can map to whatever the
+                  hardware supports.  If no mouse is supported, this
+                  routine always returns a non-zero character.
+
+B.  High-level routines:
+
+print_glyph(window, x, y, glyph)
+               -- Print the glyph at (x,y) on the given window.  Glyphs are
+                  integers at the interface, mapped to whatever the window-
+                  port wants (symbol, font, color, attributes, ...there's
+                  a 1-1 map between glyphs and distinct things on the map).
+char yn_function(const char *ques, const char *choices, char default)
+               -- Print a prompt made up of ques, choices and default.
+                  Read a single character response that is contained in
+                  choices or default.  If choices is NULL, all possible
+                  inputs are accepted and returned.  This overrides
+                  everything else.  The choices are expected to be in
+                  lower case.  Entering ESC always maps to 'q', or 'n',
+                  in that order, if present in choices, otherwise it maps
+                  to default.  Entering any other quit character (SPACE,
+                  RETURN, NEWLINE) maps to default.
+               -- If the choices string contains ESC, then anything after
+                  it is an acceptable response, but the ESC and whatever
+                  follows is not included in the prompt.
+               -- If the choices string contains a '#' then accept a count.
+                  Place this value in the global "yn_number" and return '#'.
+               -- This uses the top line in the tty window-port, other
+                  ports might use a popup.
+               -- If choices is NULL, all possible inputs are accepted and
+                  returned, preserving case (upper or lower.) This means that
+                  if the calling function needs an exact match, it must handle
+                  user input correctness itself.
+getlin(const char *ques, char *input)
+               -- Prints ques as a prompt and reads a single line of text,
+                  up to a newline.  The string entered is returned without the
+                  newline.  ESC is used to cancel, in which case the string
+                  "\033\000" is returned.
+               -- getlin() must call flush_screen(1) before doing anything.
+               -- This uses the top line in the tty window-port, other
+                  ports might use a popup.
+               -- getlin() can assume the input buffer is at least BUFSZ
+                  bytes in size and must truncate inputs to fit, including
+                  the nul character.
+int get_ext_cmd(void)
+               -- Get an extended command in a window-port specific way.
+                  An index into extcmdlist[] is returned on a successful
+                  selection, -1 otherwise.
+player_selection()
+               -- Do a window-port specific player type selection.  If
+                  player_selection() offers a Quit option, it is its
+                  responsibility to clean up and terminate the process.
+                  You need to fill in pl_character[0].
+display_file(str, boolean complain)
+               -- Display the file named str.  Complain about missing files
+                  iff complain is TRUE.
+update_inventory()
+               -- Indicate to the window port that the inventory has been
+                  changed.
+               -- Merely calls display_inventory() for window-ports that
+                  leave the window up, otherwise empty.
+doprev_message()
+               -- Display previous messages.  Used by the ^P command.
+               -- On the tty-port this scrolls WIN_MESSAGE back one line.
+
+update_positionbar(char *features)
+               -- Optional, POSITIONBAR must be defined. Provide some 
+                  additional information for use in a horizontal
+                  position bar (most useful on clipped displays).
+                  Features is a series of char pairs.  The first char
+                  in the pair is a symbol and the second char is the
+                  column where it is currently located.
+                  A '<' is used to mark an upstairs, a '>'
+                  for a downstairs, and an '@' for the current player
+                  location. A zero char marks the end of the list.
+                       
+
+C.  Window Utility Routines
+
+init_nhwindows(int* argcp, char** argv)
+               -- Initialize the windows used by NetHack.  This can also
+                  create the standard windows listed at the top, but does
+                  not display them.
+               -- Any commandline arguments relevant to the windowport
+                  should be interpreted, and *argcp and *argv should
+                  be changed to remove those arguments.
+               -- When the message window is created, the variable
+                  iflags.window_inited needs to be set to TRUE.  Otherwise
+                  all plines() will be done via raw_print().
+               ** Why not have init_nhwindows() create all of the "standard"
+               ** windows?  Or at least all but WIN_INFO?      -dean
+exit_nhwindows(str)
+               -- Exits the window system.  This should dismiss all windows,
+                  except the "window" used for raw_print().  str is printed
+                  if possible.
+window = create_nhwindow(type)
+               -- Create a window of type "type."
+clear_nhwindow(window)
+               -- Clear the given window, when appropriate.
+display_nhwindow(window, boolean blocking)
+               -- Display the window on the screen.  If there is data
+                  pending for output in that window, it should be sent.
+                  If blocking is TRUE, display_nhwindow() will not
+                  return until the data has been displayed on the screen,
+                  and acknowledged by the user where appropriate.
+               -- All calls are blocking in the tty window-port.
+               -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
+                  --more--, if necessary, in the tty window-port.
+destroy_nhwindow(window)
+               -- Destroy will dismiss the window if the window has not
+                  already been dismissed.
+start_menu(window)
+               -- Start using window as a menu.  You must call start_menu()
+                  before add_menu().  After calling start_menu() you may not
+                  putstr() to the window.  Only windows of type NHW_MENU may
+                  be used for menus.
+add_menu(windid window, int glyph, const anything identifier,
+                               char accelerator, char groupacc,
+                               int attr, char *str, boolean preselected)
+               -- Add a text line str to the given menu window.  If identifier
+                  is 0, then the line cannot be selected (e.g. a title).
+                  Otherwise, identifier is the value returned if the line is
+                  selected.  Accelerator is a keyboard key that can be used
+                  to select the line.  If the accelerator of a selectable
+                  item is 0, the window system is free to select its own
+                  accelerator.  It is up to the window-port to make the
+                  accelerator visible to the user (e.g. put "a - " in front
+                  of str).  The value attr is the same as in putstr().
+                  Glyph is an optional glyph to accompany the line.  If
+                  window port cannot or does not want to display it, this
+                  is OK.  If there is no glyph applicable, then this
+                  value will be NO_GLYPH.
+               -- All accelerators should be in the range [A-Za-z],
+                  but there are a few exceptions such as the tty player
+                  selection code which uses '*'.
+               -- It is expected that callers do not mix accelerator
+                  choices.  Either all selectable items have an accelerator
+                  or let the window system pick them.  Don't do both.
+               -- Groupacc is a group accelerator.  It may be any character
+                  outside of the standard accelerator (see above) or a
+                  number.  If 0, the item is unaffected by any group
+                  accelerator.  If this accelerator conflicts with
+                  the menu command (or their user defined alises), it loses.
+                  The menu commands and aliases take care not to interfere
+                  with the default object class symbols.
+               -- If you want this choice to be preselected when the
+                  menu is displayed, set preselected to TRUE.
+
+end_menu(window, prompt)
+               -- Stop adding entries to the menu and flushes the window
+                  to the screen (brings to front?).  Prompt is a prompt
+                  to give the user.  If prompt is NULL, no prompt will
+                  be printed.
+               ** This probably shouldn't flush the window any more (if
+               ** it ever did).  That should be select_menu's job.  -dean
+int select_menu(windid window, int how, menu_item **selected)
+               -- Return the number of items selected; 0 if none were chosen,
+                  -1 when explicitly cancelled.  If items were selected, then
+                  selected is filled in with an allocated array of menu_item
+                  structures, one for each selected line.  The caller must
+                  free this array when done with it.  The "count" field
+                  of selected is a user supplied count.  If the user did
+                  not supply a count, then the count field is filled with
+                  -1 (meaning all).  A count of zero is equivalent to not
+                  being selected and should not be in the list.  If no items
+                  were selected, then selected is NULL'ed out.  How is the
+                  mode of the menu.  Three valid values are PICK_NONE,
+                  PICK_ONE, and PICK_ANY, meaning: nothing is selectable,
+                  only one thing is selectable, and any number valid items
+                  may selected.  If how is PICK_NONE, this function should
+                  never return anything but 0 or -1.
+               -- You may call select_menu() on a window multiple times --
+                  the menu is saved until start_menu() or destroy_nhwindow()
+                  is called on the window.
+               -- Note that NHW_MENU windows need not have select_menu()
+                  called for them. There is no way of knowing whether
+                  select_menu() will be called for the window at
+                  create_nhwindow() time.
+char message_menu(char let, int how, const char *mesg)
+               -- tty-specific hack to allow single line context-sensitive
+                  help to behave compatibly with multi-line help menus.
+               -- This should only be called when a prompt is active; it
+                  sends `mesg' to the message window.  For tty, it forces
+                  a --More-- prompt and enables `let' as a viable keystroke
+                  for dismissing that prompt, so that the original prompt
+                  can be answered from the message line "help menu".
+               -- Return value is either `let', '\0' (no selection was made),
+                  or '\033' (explicit cancellation was requested).
+               -- Interfaces which issue prompts and messages to separate
+                  windows typically won't need this functionality, so can
+                  substitute genl_message_menu (windows.c) instead.
+
+D.  Misc. Routines
+
+make_sound(???) -- To be determined later.  THIS IS CURRENTLY UN-IMPLEMENTED.
+nhbell()       -- Beep at user.  [This will exist at least until sounds are
+                  redone, since sounds aren't attributable to windows anyway.]
+mark_synch()   -- Don't go beyond this point in I/O on any channel until
+                  all channels are caught up to here.  Can be an empty call
+                  for the moment
+wait_synch()   -- Wait until all pending output is complete (*flush*() for
+                  streams goes here).
+               -- May also deal with exposure events etc. so that the
+                  display is OK when return from wait_synch().
+delay_output() -- Causes a visible delay of 50ms in the output.
+                  Conceptually, this is similar to wait_synch() followed
+                  by a nap(50ms), but allows asynchronous operation.
+askname()      -- Ask the user for a player name.
+cliparound(x, y)-- Make sure that the user is more-or-less centered on the
+                  screen if the playing area is larger than the screen.
+               -- This function is only defined if CLIPPING is defined.
+number_pad(state)
+               -- Initialize the number pad to the given state.
+suspend_nhwindows(str)
+               -- Prepare the window to be suspended.
+resume_nhwindows()
+               -- Restore the windows after being suspended.
+
+start_screen() -- Only used on Unix tty ports, but must be declared for
+                  completeness.  Sets up the tty to work in full-screen
+                  graphics mode.  Look at win/tty/termcap.c for an
+                  example.  If your window-port does not need this function
+                  just declare an empty function.
+end_screen()   -- Only used on Unix tty ports, but must be declared for
+                  completeness.  The complement of start_screen().
+
+outrip(winid, int)
+               -- The tombstone code.  If you want the traditional code use
+                  genl_outrip for the value and check the #if in rip.c.
+
+preference_update(preference)
+               -- The player has just changed one of the wincap preference
+                  settings, and the NetHack core is notifying your window
+                  port of that change.  If your window-port is capable of
+                  dynamically adjusting to the change then it should do so.
+                  Your window-port will only be notified of a particular
+                  change if it indicated that it wants to be by setting the 
+                  corresponding bit in the wincap mask.
+
+III.  Global variables
+
+The following global variables are defined in decl.c and must be used by
+the window interface to the rest of NetHack.
+
+char toplines[BUFSZ]   Contains the last message printed to the WIN_MESSAGE
+                       window, used by Norep().
+winid WIN_MESSAGE, WIN_MAP, WIN_STATUS, WIN_INVEN
+                       The four standard windows.
+char *AE, *AS;         Checked in options.c to see if we should switch
+                       to DEC_GRAPHICS.  It is #ifdefed VMS and UNIX.
+int LI, CO;            Set in sys/unix/ioctl.c.
+
+The following appears to be Unix specific.  Other ports using the tty
+window-port should also declare this variable in one of your sys/*.c files.
+
+short ospeed;          Set and declared in sys/unix/unixtty.c (don't
+                       know about other sys files).
+
+The following global variable is defined in options.c. It equates a 
+list of wincap option names with their associated bit-mask [see
+section IV WINCAP preferences support].  The array is zero-terminated.
+
+struct wc_Opt wc_options[];
+                       One entry for each available WINCAP option.
+                       Each entry has a wc_name field and a wc_bit
+                       field.  
+
+IV. WINCAP preferences support
+
+Starting with NetHack 3.4.0, the window interface was enhanced to provide
+a common way of setting window port user preferences from the config file, 
+and from the command line for some settings.
+
+The wincap preference settings all have their underlying values stored
+in iflags fields.  The names of the wincap related fields are all pre-
+fixed with wc_ or wc2_ to make it easy to identify them.  Your window 
+port can access the fields directly.
+
+Your window port identifies what options it will react to and support
+by setting bits in the window_procs wincap mask and/or wincap2 mask. 
+See section IX for details of where the wincap masks reside. 
+
+Two things control whether any preference setting appears in the 
+'O' command options menu during the game:
+ 1. The option must be marked as being supported by having its 
+    bit set in the window_procs wincap or wincap2 mask.
+ 2. The option must have its optflag field set to SET_IN_GAME in order
+    to be able to set the option, or marked DISP_IN_GAME if you just
+    want to reveal what the option is set to. 
+Both conditions must be true to be able to see or set the option from
+within NetHack.  
+
+The default values for the optflag field for all the options are 
+hard-coded into the option in options.c.  The default value for 
+the wc_ options can be altered by calling 
+       set_wc_option_mod_status(optmask, status)
+The default value for the wc2_ options can be altered by calling 
+       set_wc2_option_mod_status(optmask, status)
+In each case, set the option modification status to one of SET_IN_FILE, 
+DISP_IN_GAME, or SET_IN_GAME.
+
+The setting of any wincap or wincap2 option is handled by the NetHack 
+core option processing code. You do not have to provide a parser in 
+your window port, nor should you set the values for the 
+iflags.wc_* and iflags.wc2_* fields directly within the port code. 
+The port code should honor whatever values were put there by the core 
+when processing options, either in the config file, or by the 'O' command.  
+
+You may be wondering what values your window port will find in the 
+iflags.wc_* and iflags.wc2_* fields for options that the user has not 
+specified in his/her config file. Put another way, how does you port code
+tell if an option has not been set? The next paragraph explains that.
+
+If the core does not set an option, it will still be initialized 
+to its default value. Those default values for the 
+iflags.wc_* and iflags.wc_* fields are:
+
+ o All boolean fields are initialized to the starting 
+   value specified for that option in the boolopt array in 
+   options.c.  The window-port should respect that setting 
+   unless it has a very good reason for not doing so. 
+ o All int fields are initialized to zero. Zero is not a valid
+   setting for any of the int options, so if your port code
+   encounters a zero there, it can assume that the preference
+   option was not specified.  In that case, the window-port code
+   should use a default setting that the port is comfortable with.  
+   It should write the default setting back into the iflags.wc_*
+   field.  That is the only time that your window-port could should
+   update those fields.
+ o All "char *" fields will be null pointers. Be sure to check for
+   that in your window-port code before using such a pointer, or 
+   you'll end up triggering a nasty fault.
+
+Here are the wincap and wincap2 preference settings that your port can choose
+to support:
+
+  wincap
+  +--------------------+--------------------+--------------------+--------+
+  |                    |                    | iflags field       | data   |
+  | player option      | bit in wincap mask |   for value        | type   |
+  |--------------------+--------------------+--------------------+--------+
+  |  align_message     | WC_ALIGN_MESSAGE   | wc_align_message   |int     |
+  |  align_status      | WC_ALIGN_STATUS    | wc_align_status    |int     |
+  |  ascii_map         | WC_ASCII_MAP       | wc_ascii_map       |boolean |
+  |  color             | WC_COLOR           | wc_color           |boolean |
+  |  eight_bit_tty     | WC_EIGHT_BIT_IN    | wc_eight_bit_input |boolean |
+  |  font_map          | WC_FONT_MAP        | wc_font_map        |char *  |
+  |  font_menu         | WC_FONT_MENU       | wc_font_menu       |char *  |
+  |  font_message      | WC_FONT_MESSAGE    | wc_font_message    |char *  |
+  |  font_status       | WC_FONT_STATUS     | wc_font_status     |char *  |
+  |  font_text         | WC_FONT_TEXT       | wc_font_text       |char *  |
+  |  font_size_map     | WC_FONTSIZ_MAP     | wc_fontsiz_map     |int     |
+  |  font_size_menu    | WC_FONTSIZ_MENU    | wc_fontsiz_menu    |int     |
+  |  font_size_message | WC_FONTSIZ_MESSAGE | wc_fontsiz_message |int     |
+  |  font_size_status  | WC_FONTSIZ_STATUS  | wc_fontsiz_status  |int     |
+  |  font_size_text    | WC_FONTSIZ_TEXT    | wc_fontsiz_text    |int     |
+  |  hilite_pet        | WC_HILITE_PET      | wc_hilite_pet      |boolean |
+  |  map_mode          | WC_MAP_MODE        | wc_map_mode        |int     |
+  |  player_selection  | WC_PLAYER_SELECTION| wc_player_selection|int     |
+  |  popup_dialog      | WC_POPUP_DIALOG    | wc_popup_dialog    |boolean |
+  |  preload_tiles     | WC_PRELOAD_TILES   | wc_preload_tiles   |boolean |
+  |  scroll_amount     | WC_SCROLL_AMOUNT   | wc_scroll_amount   |int     |
+  |  scroll_margin     | WC_SCROLL_MARGIN   | wc_scroll_margin   |int     |
+  |  splash_screen     | WC_SPLASH_SCREEN   | wc_splash_screen   |boolean |
+  |  tiled_map         | WC_TILED_MAP       | wc_tiled_map       |boolean |
+  |  tile_width        | WC_TILE_WIDTH      | wc_tile_width      |int     |
+  |  tile_height       | WC_TILE_HEIGHT     | wc_tile_height     |int     |
+  |  tile_file         | WC_TILE_FILE       | wc_tile_file       |char *  |
+  |  use_inverse       | WC_INVERSE         | wc_inverse         |boolean |
+  |  vary_msgcount     | WC_VARY_MSGCOUNT   | wc_vary_msgcount   |int     |
+  |  windowcolors      | WC_WINDOWCOLORS    | wc_foregrnd_menu   |char *  |
+  |                    |                    | wc_backgrnd_menu   |char *  |
+  |                    |                    | wc_foregrnd_message|char *  |
+  |                    |                    | wc_backgrnd_message|char *  |
+  |                    |                    | wc_foregrnd_status |char *  |
+  |                    |                    | wc_backgrnd_status |char *  |
+  |                    |                    | wc_foregrnd_text   |char *  |
+  |                    |                    | wc_backgrnd_text   |char *  |
+  |  mouse             | WC_MOUSE_SUPPORT   | wc_mouse_support   |boolean |
+  +--------------------+--------------------+--------------------+--------+
+
+  wincap2
+  +--------------------+--------------------+--------------------+--------+
+  |                    |                    | iflags field       | data   |
+  | player option      | bit in wincap mask |   for value        | type   |
+  |--------------------+--------------------+--------------------+--------+
+  |  fullscreen        | WC2_FULLSCREEN     | wc2_fullscreen     |boolean |
+  |  softkeyboard      | WC2_SOFTKEYBOARD   | wc2_softkeyboard   |boolean |
+  |  wraptext          | WC2_WRAPTEXT       | wc2_wraptext       |boolean |
+  +--------------------+--------------------+--------------------+--------+
+
+align_message  -- where to place message window (top, bottom, left, right)
+align_status   -- where to place status window (top, bottom, left, right).
+ascii_map      -- port should display an ascii map if it can.
+color          -- port should display color if it can.
+eight_bit_tty  -- port should allow eight bit input.
+font_map       -- port should use a font by this name for map window.
+font_menu      -- port should use a font by this name for menu windows.
+font_message   -- port should use a font by this name for message window.
+font_size_map  -- port should use this size font for the map window.
+font_size_menu -- port should use this size font for menu windows.
+font_size_message 
+               -- port should use this size font for the message window.
+font_size_status-- port should use this size font for the status window.
+font_size_text -- port should use this size font for text windows.
+font_status    -- port should use a font by this name for status window.
+font_text      -- port should use a font by this name for text windows.
+fullscreen      -- port should try to use the whole screen.
+hilite_pet     -- port should mark pets in some special way on the map.
+map_mode       -- port should display the map in the manner specified.
+player_selection
+               -- dialog or prompts for choosing character.
+popup_dialog   -- port should pop up dialog boxes for input.
+preload_tiles  -- port should preload tiles into memory.
+scroll_amount   -- scroll this amount when scroll_margin is reached.
+scroll_margin  -- port should scroll the display when the hero or cursor
+                  is this number of cells away from the edge of the window.
+softkeyboard    -- handhelds should display an on-screen keyboard if possible.
+splash_screen   -- port should/should not display an opening splashscreen.
+tiled_map      -- port should display a tiled map if it can.
+tile_width     -- port should display tiles with this width or round to closest
+                  if it can.
+tile_height    -- port should display tiles with this height or round to closest
+                  if it can.
+tile_file      -- open this alternative tile file. The file name is likely to be
+                  window-port or platform specific.
+use_inverse    -- port should display inverse when NetHack asks for it.
+vary_msgcount  -- port should display this number of messages at a time in
+                  the message window.
+windowcolors
+               -- port should use these colors for window foreground/background
+                  colors.  Syntax:
+                    menu fore/back message fore/back status fore/back text fore/back
+wraptext       -- port should wrap long lines of text if they don't fit in 
+                  the visible area of the window
+mouse_support  -- port should enable mouse support if possible
+
+Whenever one of these settings is adjusted, the port is notified of a change
+to the setting by calling the port's preference_update() routine. The port
+is only notified if it has indicated that it supports that option by setting
+the option's bit in the port's wincap mask.  The port can choose to adjust 
+for the change to an option that it receives notification about, or ignore it.
+The former approach is recommended.  If you don't want to deal with a
+user-initiated setting change, then the port should call 
+set_wc_option_mod_status(mask, SET_IN_FILE) to make the option invisible to 
+the user.
+
+Functions available for the window port to call:
+
+set_wc_option_mod_status(optmask, status)
+               -- Adjust the optflag field for a set of wincap options to 
+                  specify whether the port wants the option to appear 
+                  in the 'O' command options menu, The second parameter,
+                  "status" can be set to SET_IN_FILE, DISP_IN_GAME,
+                  or SET_IN_GAME (SET_IN_FILE implies that the option
+                  is completely hidden during the game).
+
+set_wc2_option_mod_status(optmask, status)
+               -- Adjust the optflag field for a set of wincap2 options to 
+                  specify whether the port wants the option to appear 
+                  in the 'O' command options menu, The second parameter,
+                  "status" can be set to SET_IN_FILE, DISP_IN_GAME,
+                  or SET_IN_GAME (SET_IN_FILE implies that the option
+                  is completely hidden during the game).
+
+set_option_mod_status(optnam, status)
+               -- Adjust the optflag field for one of the core options
+                  that is not part of the wincap suite.  A port might use
+                  this to override the default initialization setting for
+                  status specified in options.c.  Note that you have to
+                  specify the option by name and that you can only set 
+                  one option per call unlike set_wc_option_mod_status().
+
+
+Adding a new wincap option:
+
+To add a new wincap option, please follow all these steps:
+       1. Add the option to the wincap preference settings table above. Since
+          wincap is full, your option will likely target wincap2 field.
+       2. Add the description to the paragraph below the chart.
+       3. Add the WC_ or WC2_ to the bit list in include/winprocs.h 
+          (in wincap2 if there is no room in wincap).
+       4. Add the wc_ or wc2_ field(s) to the iflags structure in flag.h.
+       5. Add the name and value to wc_options[] or wc2_options[] in options.c
+       6. Add an appropriate parser to parseoptions() in options.c.
+       7. Add code to display current value to get_compopt_value() in options.c.
+       8. Document the option in Guidebook.mn and Guidebook.tex.
+       9. Add the bit name to the OR'd values in your window port's winprocs struct
+          wincap mask if your port supports the option.
+
+V.  New or respecified common, high level routines
+
+These are not part of the interface, but mentioned here for your information.
+
+char display_inventory(lets, want_reply)
+               -- Calls a start_menu()/add_menu()/select_menu() sequence.
+                  It returns the item selected, or '\0' if none is selected.
+                  Returns '\033' if the menu was canceled.
+raw_printf(str, ...)
+               -- Like raw_print(), but accepts arguments like printf().  This
+                  routine processes the arguments and then calls raw_print().
+               -- The mac version #defines error raw_printf.  I think this
+                  is a reasonable thing to do for most ports.
+pline(str, ...)
+               -- Prints a string to WIN_MESSAGE using a printf() interface.
+                  It has the variants You(), Your(), Norep(), and others
+                  in pline.c which all use the same mechanism.  pline()
+                  requires the variable "char toplines[]" be defined; Every
+                  putstr() on WIN_MESSAGE must copy str to toplines[] for use
+                  by Norep() and pline().  If the window system is not active
+                  (!iflags.window_inited) pline() uses raw_print().
+
+VI.  Helper Routines
+
+These are not part of the interface. They may be called by your
+window port routines to perform the desired task, instead of duplicating
+the necessary code in each window port.
+
+mapglyph(int glyph, int *ochar, int *ocolor, unsigned *special, int x, int y)
+               -- Maps glyph at x,y to NetHack ascii character and color.
+                  If it represents something special such as a pet, that
+                  information is returned as set bits in "special." 
+                  Usually called from the window port's print_glyph() 
+                  routine.
+
+VII.  Game startup
+
+The following is the general order in which calls from main() should be made,
+as they relate to the window system.  The actual code may differ, but the
+order of the calls should be the same.
+
+
+choose_windows(DEFAULT_WINDOW_SYS) /* choose a default window system */
+initoptions()                     /* read the resource file */
+init_nhwindows()                  /* initialize the window system */
+process_options(argc, argv)       /* process command line options or equiv */
+if(save file is present) {
+  display_gamewindows()                   /* create & display the game windows */
+  dorestore()                     /* restore old game; pline()s are OK */
+} else {
+  player_selection()              /* select a player type using a window */
+  display_gamewindows()                   /* create & display the game windows */
+}
+pline("Hello, welcome...");
+
+Choose_windows() is a common routine, and calling it in main() is necessary
+to initialize the function pointer table to _something_ so that calls to
+raw_print() will not fail.  Choose_windows() should be called almost
+immediately upon entering main().  Look at unixmain.c for an example.
+
+Display_gamewindows() is a common routine that displays the three standard
+game windows (WIN_MESSAGE, WIN_MAP, and WIN_STATUS).  It is normally called
+just before the "Hello, welcome" message.
+
+Process_options() is currently still unique to each port.  There may be need
+in the future to make it possible to replace this on a per window-port basis.
+
+
+VIII.  Conventions
+
+init_nhwindows() is expected to display a gee-whiz banner window, including
+the Copyright message.  It is recommended that the COPYRIGHT_BANNER_A,
+COPYRIGHT_BANNER_B, and COPYRIGHT_BANNER_C macros from patchlevel.h be used
+for constructing the Copyright message.  COPYRIGHT_BANNER_A is a 
+quoted string that has the NetHack copyright declaration, 
+COPYRIGHT_BANNER_B is a quoted string that states who the copyright 
+belongs to, and COPYRIGHT_BANNER_C simply says "See License for
+details." Be sure to #include "patchlevel.h" to define these macros.
+Using the macros will prevent having to update the Copyright information
+in each window-port prior to each release.
+
+Ports (MSDOS, TOS, MAC, etc) _may_ use window-port specific routines in
+their port specific files, _AT_THEIR_OWN_RISK_.  Since "port" and
+"window-port" are orthogonal, you make your "port" code less portable by
+using "window-port" specific routines.  Every effort should be made to
+use window-port interface routines, unless there is something port
+specific that is better suited (e.g. msmsg() for MSDOS).
+
+The tty window-port is contained in win/tty, the X window port is contained
+in win/X11.  The files in these directories contain _only_ window port code,
+and may be replaced completely by other window ports.
+
+
+IX.  Implementation and Multi-window support
+
+NetHack 3.2 and higher support multiple window systems in the same binary.
+When writing a new window-port, you need to follow the following guidelines:
+
+1) Pick a unique prefix to identify your window-port.  For example, the tty
+   window port uses "tty"; the X11 window-port uses "X11".
+2) When declaring your interface function, precede the function names with
+   your unique prefix.  E.g:
+
+       void tty_init_nhwindows()
+       {
+               /* code for initializing windows in the tty port */
+       }
+
+   When calling window functions from within your port code, we suggest
+   calling the prefixed version to avoid unnecessary overhead.  However,
+   you may safely call the non-prefixed version (e.g. putstr() rather than
+   tty_putstr()) as long as you #include "hack.h".  If you do not
+   include hack.h and use the non-prefixed names, you will get compile
+   or link-time errors.
+
+   We also suggest declaring all functions and port-specific data with
+   this prefix to avoid unexpected overlaps with other window-ports.
+   The tty and X11 ports do not currently follow this suggestion, but do
+   use separate non-overlapping convention for naming data and internal
+   functions.
+
+3) Declare a structure, "struct window_procs prefix_procs", (with your
+   prefix instead of "prefix") and fill in names of all of your
+   interface functions.  The first entry in this structure is the name
+   of your window-port, which should be the prefix.  The second entry
+   is the wincap mask that identifies what window port preference
+   settings your port will react to and support.  The other entries
+   are the function addresses.
+
+   Assuming that you followed the convention in (2), you can safely copy
+   the structure definition from an existing window-port and just change
+   the prefixes.  That will guarantee that you get the order of your
+   initializations correct (not all compilers will catch out-of-order
+   function pointer declarations).
+
+4) Add a #define to config.h identifying your window-port in the
+   "Windowing systems" section.  Follow the "prefix_GRAPHICS" convention
+   for your window-port.
+
+5) Add your prefix to the list of valid prefixes listed in the "Known
+   systems are" comment.
+
+6) Edit makedefs.c and add a string for your windowing system to window_opts
+   inside an #ifdef prefix_GRAPHICS.
+
+7) Edit windows.c and add an external reference to your prefix_procs inside
+   an #ifdef prefix_GRAPHICS.  Also add an entry to the win_choices
+   structure for your window-port of the form:
+
+    #ifdef prefix_GRAPHICS
+       { &prefix_procs, prefix_init_function },
+    #endif
+
+   The init_function is necessary for some compilers and systems to force
+   correct linking.  If your system does not need such massaging, you
+   may put a null pointer here.
+
+   You should declare prefix_procs and prefix_init_function as extern's
+   in your win*.h file, and #include that file at the beginning of
+   windows.c, also inside an #ifdef prefix_GRAPHICS.  Some win*.h files
+   are rather sensitive, and you might have to duplicate your
+   prefix_procs and prefix_init_function's instead of including win*.h.
+   The tty port includes wintty.h, the X11 port duplicates the declarations.
+
+8) If your port uses Makefile.src, add the .c and .o files and an
+   appropriate comment in the section on "WINSRC" and "WINOBJ".  See
+   Makefile.src for the style to use.  If you don't use Makefile.src,
+   we suggest using a similar convention for the make-equivalent used
+   on your system.  Also add your new source and binaries to WINSRC and
+   WINOBJ (if you want the NetHack binary to include them, that is).
+
+9) Look at your port's portmain.c (the file containing main()) and make
+   sure that all of the calls match the the requirements laid out in
+   Section VII.
+
+Now, proceed with compilation and installation as usual.  Don't forget
+to edit Makefile.src (or its equivalent) and config.h to set the
+window-ports you want in your binary, the default window-port to use,
+and the .o's needed to build a valid game.
+
+One caveat.  Unfortunately, if you incorrectly specify the
+DEFAULT_WINDOW_SYS, NetHack will dump core (or whatever) without
+printing any message, because raw_print() cannot function without first
+setting the window-port.
diff --git a/include/align.h b/include/align.h
new file mode 100644 (file)
index 0000000..1925f14
--- /dev/null
@@ -0,0 +1,42 @@
+/*     SCCS Id: @(#)align.h    3.4     1991/12/29      */
+/* Copyright (c) Mike Stephenson, Izchak Miller  1991.           */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef ALIGN_H
+#define ALIGN_H
+
+typedef schar  aligntyp;       /* basic alignment type */
+
+typedef struct align {         /* alignment & record */
+       aligntyp        type;
+       int             record;
+} align;
+
+/* bounds for "record" -- respect initial alignments of 10 */
+#define ALIGNLIM       (10L + (moves/200L))
+
+#define A_NONE       (-128)    /* the value range of type */
+
+#define A_CHAOTIC      (-1)
+#define A_NEUTRAL       0
+#define A_LAWFUL        1
+
+#define A_COALIGNED     1
+#define A_OPALIGNED    (-1)
+
+#define AM_NONE                 0
+#define AM_CHAOTIC      1
+#define AM_NEUTRAL      2
+#define AM_LAWFUL       4
+
+#define AM_MASK                 7
+
+#define AM_SPLEV_CO     3
+#define AM_SPLEV_NONCO  7
+
+#define Amask2align(x) ((aligntyp) ((!(x)) ? A_NONE \
+                        : ((x) == AM_LAWFUL) ? A_LAWFUL : ((int)x) - 2))
+#define Align2amask(x) (((x) == A_NONE) ? AM_NONE \
+                        : ((x) == A_LAWFUL) ? AM_LAWFUL : (x) + 2)
+
+#endif /* ALIGN_H */
diff --git a/include/amiconf.h b/include/amiconf.h
new file mode 100644 (file)
index 0000000..6b36c4f
--- /dev/null
@@ -0,0 +1,190 @@
+/*     SCCS Id: @(#)amiconf.h  3.4     2000/01/12      */
+/* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1990, 1991, 1992, 1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef AMICONF_H
+#define AMICONF_H
+
+#undef abs             /* avoid using macro form of abs */
+#ifndef __SASC_60
+# undef min            /* this gets redefined */
+# undef max            /* this gets redefined */
+#endif
+
+#include <time.h>      /* get time_t defined before use! */
+
+#ifdef __SASC_60       /* since SAS can prevent re-inclusion */
+#include <stdlib.h>    /* general things, including builtins */
+#include <string.h>
+#endif
+
+#ifdef AZTEC_50
+#include <stdlib.h>
+# define AZTEC_C_WORKAROUND /* Bug which turns up in sounds.c. Bummer... */
+# define NO_SIGNAL     /* 5.0 signal handling doesn't like SIGINT... */
+#endif
+
+#ifdef _DCC
+#include <stdlib.h>
+# define _SIZE_T
+# define DCC30_BUG     /* A bitfield bug (from dog.c, others) in DICE 3.0. */
+#endif
+
+#ifndef __GNUC__
+typedef long off_t;
+#endif
+
+#define MICRO          /* must be defined to allow some inclusions */
+
+#define NOCWD_ASSUMPTIONS      /* Allow paths to be specified for HACKDIR,
+                                  LEVELDIR, SAVEDIR, BONESDIR, DATADIR,
+                                  SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */
+
+/* data librarian defs */
+#ifndef NOCWD_ASSUMPTIONS
+# define DLBFILE       "NetHack:nhdat"         /* main library */
+# define DLBFILE2      "NetHack:nhsdat"        /* sound library */
+#else
+# define DLBFILE       "nhdat"                 /* main library */
+# define DLBFILE2      "nhsdat"                /* sound library */
+#endif
+
+#define FILENAME_CMP   stricmp                 /* case insensitive */
+
+#ifndef __SASC_60
+# define O_BINARY      0
+#endif
+
+/* Compile in New Intuition look for 2.0 */
+#ifdef IDCMP_CLOSEWINDOW
+# ifndef INTUI_NEW_LOOK
+#  define      INTUI_NEW_LOOK  1
+# endif
+#endif
+
+#define MFLOPPY                /* You'll probably want this; provides assistance
+                        * for typical personal computer configurations
+                        */
+#define RANDOM
+
+/* ### amidos.c ### */
+
+extern void  FDECL(nethack_exit, (int));
+
+/* ### amiwbench.c ### */
+
+extern void NDECL(ami_wbench_init);
+extern void NDECL(ami_wbench_args);
+extern int FDECL(ami_wbench_getsave, (int));
+extern void FDECL(ami_wbench_unlink, (char *));
+extern int FDECL(ami_wbench_iconsize, (char *));
+extern void FDECL(ami_wbench_iconwrite, (char *));
+extern int FDECL(ami_wbench_badopt, (const char *));
+extern void NDECL(ami_wbench_cleanup);
+extern void FDECL(getlind, (const char *,char *,const char *));
+
+/* ### winreq.c ### */
+
+extern void amii_setpens(int);
+
+extern void FDECL(exit, (int));
+extern void NDECL(CleanUp);
+extern void FDECL(Abort, (long));
+extern int NDECL(getpid);
+extern char *FDECL(CopyFile, (const char *, const char *));
+extern int NDECL(kbhit);
+extern int NDECL(WindowGetchar);
+extern void FDECL(ami_argset, (int *, char *[]));
+extern void FDECL(ami_mkargline, (int *, char **[]));
+extern void ami_wininit_data(void);
+
+#define FromWBench 0 /* A hint for compiler ... */
+/* extern boolean FromWBench;  /* how were we run? */
+extern int ami_argc;
+extern char **ami_argv;
+
+#ifndef MICRO_H
+#include "micro.h"
+#endif
+
+#ifndef PCCONF_H
+#include "pcconf.h"    /* remainder of stuff is almost same as the PC */
+#endif
+
+#define remove(x)      unlink(x)
+
+/* DICE wants rewind() to return void. We want it to return int. */
+#if defined(_DCC) || defined(__GNUC__)
+# define rewind(f)     fseek(f, 0, 0)
+#endif
+
+#ifdef AZTEC_C
+extern FILE *FDECL(freopen, (const char *, const char *, FILE *));
+extern char *FDECL(gets, (char *));
+#endif
+
+#define msmsg          printf
+
+/*
+ * If AZTEC_C  we can't use the long cpath in vision.c....
+ */
+#ifdef AZTEC_C
+# undef MACRO_CPATH
+#endif
+
+/*
+ *  (Possibly) configurable Amiga options:
+ */
+
+#define TEXTCOLOR              /* Use colored monsters and objects */
+#define HACKFONT               /* Use special hack.font */
+#define SHELL                  /* Have a shell escape command (!) */
+#define MAIL                   /* Get mail at unexpected occasions */
+#define DEFAULT_ICON "NetHack:default.icon"    /* private icon */
+#define AMIFLUSH               /* toss typeahead (select flush in .cnf) */
+/* #define OPT_DISPMAP         /* enable fast_map option */
+
+/* new window system options */
+                       /* WRONG - AMIGA_INTUITION should go away */
+#ifdef AMII_GRAPHICS
+# define AMIGA_INTUITION       /* high power graphics interface (amii) */
+#endif
+
+#define CHANGE_COLOR   1
+
+#ifdef TEXTCOLOR
+#  define      DEPTH   6       /* Maximum depth of the screen allowed */
+#else
+# define       DEPTH   2       /* Four colors...sigh... */
+#endif
+
+#define AMII_MAXCOLORS (1L<<DEPTH)
+typedef unsigned short AMII_COLOR_TYPE;
+
+#define PORT_HELP      "nethack:amii.hlp"
+
+#undef TERMLIB
+
+#define AMII_MUFFLED_VOLUME    40
+#define AMII_SOFT_VOLUME       50
+#define AMII_OKAY_VOLUME       60
+#define AMII_LOUDER_VOLUME     80
+
+#ifdef TTY_GRAPHICS
+# define ANSI_DEFAULT
+#endif
+
+extern int amibbs;     /* BBS mode? */
+
+#ifdef AMII_GRAPHICS
+extern int amii_numcolors;
+void FDECL( amii_setpens, (int) );
+#endif
+
+/* for cmd.c: override version in micro.h */
+#ifdef __SASC_60
+# undef M
+# define M(c) ((c) - 128 )
+#endif
+
+#endif /* AMICONF_H */
diff --git a/include/artifact.h b/include/artifact.h
new file mode 100644 (file)
index 0000000..88dd223
--- /dev/null
@@ -0,0 +1,64 @@
+/*     SCCS Id: @(#)artifact.h 3.4     1995/05/31      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef ARTIFACT_H
+#define ARTIFACT_H
+
+#define SPFX_NONE   0x0000000L /* no special effects, just a bonus */
+#define SPFX_NOGEN  0x0000001L /* item is special, bequeathed by gods */
+#define SPFX_RESTR  0x0000002L /* item is restricted - can't be named */
+#define SPFX_INTEL  0x0000004L /* item is self-willed - intelligent */
+#define SPFX_SPEAK  0x0000008L /* item can speak (not implemented) */
+#define SPFX_SEEK   0x0000010L /* item helps you search for things */
+#define SPFX_WARN   0x0000020L /* item warns you of danger */
+#define SPFX_ATTK   0x0000040L /* item has a special attack (attk) */
+#define SPFX_DEFN   0x0000080L /* item has a special defence (defn) */
+#define SPFX_DRLI   0x0000100L /* drains a level from monsters */
+#define SPFX_SEARCH 0x0000200L /* helps searching */
+#define SPFX_BEHEAD 0x0000400L /* beheads monsters */
+#define SPFX_HALRES 0x0000800L /* blocks hallucinations */
+#define SPFX_ESP    0x0001000L /* ESP (like amulet of ESP) */
+#define SPFX_STLTH  0x0002000L /* Stealth */
+#define SPFX_REGEN  0x0004000L /* Regeneration */
+#define SPFX_EREGEN 0x0008000L /* Energy Regeneration */
+#define SPFX_HSPDAM 0x0010000L /* 1/2 spell damage (on player) in combat */
+#define SPFX_HPHDAM 0x0020000L /* 1/2 physical damage (on player) in combat */
+#define SPFX_TCTRL  0x0040000L /* Teleportation Control */
+#define SPFX_LUCK   0x0080000L /* Increase Luck (like Luckstone) */
+#define SPFX_DMONS  0x0100000L /* attack bonus on one monster type */
+#define SPFX_DCLAS  0x0200000L /* attack bonus on monsters w/ symbol mtype */
+#define SPFX_DFLAG1 0x0400000L /* attack bonus on monsters w/ mflags1 flag */
+#define SPFX_DFLAG2 0x0800000L /* attack bonus on monsters w/ mflags2 flag */
+#define SPFX_DALIGN 0x1000000L /* attack bonus on non-aligned monsters  */
+#define SPFX_DBONUS 0x1F00000L /* attack bonus mask */
+#define SPFX_XRAY   0x2000000L /* gives X-RAY vision to player */
+#define SPFX_REFLECT 0x4000000L /* Reflection */
+
+
+struct artifact {
+       short       otyp;
+       const char  *name;
+       unsigned long spfx;     /* special effect from wielding/wearing */
+       unsigned long cspfx;    /* special effect just from carrying obj */
+       unsigned long mtype;    /* monster type, symbol, or flag */
+       struct attack attk, defn, cary;
+       uchar       inv_prop;   /* property obtained by invoking artifact */
+       aligntyp    alignment;  /* alignment of bequeathing gods */
+       short       role;       /* character role associated with */
+       short       race;       /* character race associated with */
+       long        cost;       /* price when sold to hero (default 100 x base cost) */
+};
+
+/* invoked properties with special powers */
+#define TAMING         (LAST_PROP+1)
+#define HEALING                (LAST_PROP+2)
+#define ENERGY_BOOST   (LAST_PROP+3)
+#define UNTRAP         (LAST_PROP+4)
+#define CHARGE_OBJ     (LAST_PROP+5)
+#define LEV_TELE       (LAST_PROP+6)
+#define CREATE_PORTAL  (LAST_PROP+7)
+#define ENLIGHTENING   (LAST_PROP+8)
+#define CREATE_AMMO    (LAST_PROP+9)
+
+#endif /* ARTIFACT_H */
diff --git a/include/artilist.h b/include/artilist.h
new file mode 100644 (file)
index 0000000..1682e39
--- /dev/null
@@ -0,0 +1,255 @@
+/*     SCCS Id: @(#)artilist.h 3.4     2003/02/12      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifdef MAKEDEFS_C
+/* in makedefs.c, all we care about is the list of names */
+
+#define A(nam,typ,s1,s2,mt,atk,dfn,cry,inv,al,cl,rac,cost) nam
+
+static const char *artifact_names[] = {
+#else
+/* in artifact.c, set up the actual artifact list structure */
+
+#define A(nam,typ,s1,s2,mt,atk,dfn,cry,inv,al,cl,rac,cost) \
+ { typ, nam, s1, s2, mt, atk, dfn, cry, inv, al, cl, rac, cost }
+
+#define     NO_ATTK    {0,0,0,0}               /* no attack */
+#define     NO_DFNS    {0,0,0,0}               /* no defense */
+#define     NO_CARY    {0,0,0,0}               /* no carry effects */
+#define     DFNS(c)    {0,c,0,0}
+#define     CARY(c)    {0,c,0,0}
+#define     PHYS(a,b)  {0,AD_PHYS,a,b}         /* physical */
+#define     DRLI(a,b)  {0,AD_DRLI,a,b}         /* life drain */
+#define     COLD(a,b)  {0,AD_COLD,a,b}
+#define     FIRE(a,b)  {0,AD_FIRE,a,b}
+#define     ELEC(a,b)  {0,AD_ELEC,a,b}         /* electrical shock */
+#define     STUN(a,b)  {0,AD_STUN,a,b}         /* magical attack */
+
+STATIC_OVL NEARDATA struct artifact artilist[] = {
+#endif /* MAKEDEFS_C */
+
+/* Artifact cost rationale:
+ * 1.  The more useful the artifact, the better its cost.
+ * 2.  Quest artifacts are highly valued.
+ * 3.  Chaotic artifacts are inflated due to scarcity (and balance).
+ */
+
+
+/*  dummy element #0, so that all interesting indices are non-zero */
+A("",                          STRANGE_OBJECT,
+       0, 0, 0, NO_ATTK, NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 0L ),
+
+A("Excalibur",                 LONG_SWORD,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_SEEK|SPFX_DEFN|SPFX_INTEL|SPFX_SEARCH),0,0,
+       PHYS(5,10),     DRLI(0,0),      NO_CARY,        0, A_LAWFUL, PM_KNIGHT, NON_PM, 4000L ),
+/*
+ *     Stormbringer only has a 2 because it can drain a level,
+ *     providing 8 more.
+ */
+A("Stormbringer",              RUNESWORD,
+       (SPFX_RESTR|SPFX_ATTK|SPFX_DEFN|SPFX_INTEL|SPFX_DRLI), 0, 0,
+       DRLI(5,2),      DRLI(0,0),      NO_CARY,        0, A_CHAOTIC, NON_PM, NON_PM, 8000L ),
+/*
+ *     Mjollnir will return to the hand of the wielder when thrown
+ *     if the wielder is a Valkyrie wearing Gauntlets of Power.
+ */
+A("Mjollnir",                  WAR_HAMMER,             /* Mjo:llnir */
+       (SPFX_RESTR|SPFX_ATTK),  0, 0,
+       ELEC(5,24),     NO_DFNS,        NO_CARY,        0, A_NEUTRAL, PM_VALKYRIE, NON_PM, 4000L ),
+
+A("Cleaver",                   BATTLE_AXE,
+       SPFX_RESTR, 0, 0,
+       PHYS(3,6),      NO_DFNS,        NO_CARY,        0, A_NEUTRAL, PM_BARBARIAN, NON_PM, 1500L ),
+
+A("Grimtooth",                 ORCISH_DAGGER,
+       SPFX_RESTR, 0, 0,
+       PHYS(2,6),      NO_DFNS,        NO_CARY,        0, A_CHAOTIC, NON_PM, PM_ORC, 300L ),
+/*
+ *     Orcrist and Sting have same alignment as elves.
+ */
+A("Orcrist",                   ELVEN_BROADSWORD,
+       SPFX_DFLAG2, 0, M2_ORC,
+       PHYS(5,0),      NO_DFNS,        NO_CARY,        0, A_CHAOTIC, NON_PM, PM_ELF, 2000L ),
+
+/*
+ *     The combination of SPFX_WARN and M2_something on an artifact
+ *     will trigger EWarn_of_mon for all monsters that have the appropriate
+ *     M2_something flags.  In Sting's case it will trigger EWarn_of_mon
+ *     for M2_ORC monsters.
+ */
+A("Sting",                     ELVEN_DAGGER,
+       (SPFX_WARN|SPFX_DFLAG2), 0, M2_ORC,
+       PHYS(5,0),      NO_DFNS,        NO_CARY,        0, A_CHAOTIC, NON_PM, PM_ELF, 800L ),
+/*
+ *     Magicbane is a bit different!  Its magic fanfare
+ *     unbalances victims in addition to doing some damage.
+ */
+A("Magicbane",                 ATHAME,
+       (SPFX_RESTR|SPFX_ATTK|SPFX_DEFN), 0, 0,
+       STUN(3,4),      DFNS(AD_MAGM),  NO_CARY,        0, A_NEUTRAL, PM_WIZARD, NON_PM, 3500L ),
+
+A("Frost Brand",               LONG_SWORD,
+       (SPFX_RESTR|SPFX_ATTK|SPFX_DEFN), 0, 0,
+       COLD(5,0),      COLD(0,0),      NO_CARY,        0, A_NONE, NON_PM, NON_PM, 3000L ),
+
+A("Fire Brand",                        LONG_SWORD,
+       (SPFX_RESTR|SPFX_ATTK|SPFX_DEFN), 0, 0,
+       FIRE(5,0),      FIRE(0,0),      NO_CARY,        0, A_NONE, NON_PM, NON_PM, 3000L ),
+
+A("Dragonbane",                        BROADSWORD,
+       (SPFX_RESTR|SPFX_DCLAS), 0, S_DRAGON,
+       PHYS(5,0),      NO_DFNS,        NO_CARY,        0, A_NONE, NON_PM, NON_PM, 500L ),
+
+A("Demonbane",                 LONG_SWORD,
+       (SPFX_RESTR|SPFX_DFLAG2), 0, M2_DEMON,
+       PHYS(5,0),      NO_DFNS,        NO_CARY,        0, A_LAWFUL, NON_PM, NON_PM, 2500L ),
+
+A("Werebane",                  SILVER_SABER,
+       (SPFX_RESTR|SPFX_DFLAG2), 0, M2_WERE,
+       PHYS(5,0),      DFNS(AD_WERE),  NO_CARY,        0, A_NONE, NON_PM, NON_PM, 1500L ),
+
+A("Grayswandir",               SILVER_SABER,
+       (SPFX_RESTR|SPFX_HALRES), 0, 0,
+       PHYS(5,0),      NO_DFNS,        NO_CARY,        0, A_LAWFUL, NON_PM, NON_PM, 8000L ),
+
+A("Giantslayer",               LONG_SWORD,
+       (SPFX_RESTR|SPFX_DFLAG2), 0, M2_GIANT,
+       PHYS(5,0),      NO_DFNS,        NO_CARY,        0, A_NEUTRAL, NON_PM, NON_PM, 200L ),
+
+A("Ogresmasher",               WAR_HAMMER,
+       (SPFX_RESTR|SPFX_DCLAS), 0, S_OGRE,
+       PHYS(5,0),      NO_DFNS,        NO_CARY,        0, A_NONE, NON_PM, NON_PM, 200L ),
+
+A("Trollsbane",                        MORNING_STAR,
+       (SPFX_RESTR|SPFX_DCLAS), 0, S_TROLL,
+       PHYS(5,0),      NO_DFNS,        NO_CARY,        0, A_NONE, NON_PM, NON_PM, 200L ),
+/*
+ *     Two problems:  1) doesn't let trolls regenerate heads,
+ *     2) doesn't give unusual message for 2-headed monsters (but
+ *     allowing those at all causes more problems than worth the effort).
+ */
+A("Vorpal Blade",              LONG_SWORD,
+       (SPFX_RESTR|SPFX_BEHEAD), 0, 0,
+       PHYS(5,1),      NO_DFNS,        NO_CARY,        0, A_NEUTRAL, NON_PM, NON_PM, 4000L ),
+/*
+ *     Ah, never shall I forget the cry,
+ *             or the shriek that shrieked he,
+ *     As I gnashed my teeth, and from my sheath
+ *             I drew my Snickersnee!
+ *                     --Koko, Lord high executioner of Titipu
+ *                       (From Sir W.S. Gilbert's "The Mikado")
+ */
+A("Snickersnee",               KATANA,
+       SPFX_RESTR, 0, 0,
+       PHYS(0,8),      NO_DFNS,        NO_CARY,        0, A_LAWFUL, PM_SAMURAI, NON_PM, 1200L ),
+
+A("Sunsword",                  LONG_SWORD,
+       (SPFX_RESTR|SPFX_DFLAG2), 0, M2_UNDEAD,
+       PHYS(5,0),      DFNS(AD_BLND),  NO_CARY,        0, A_LAWFUL, NON_PM, NON_PM, 1500L ),
+
+/*
+ *     The artifacts for the quest dungeon, all self-willed.
+ */
+
+A("The Orb of Detection",      CRYSTAL_BALL,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL), (SPFX_ESP|SPFX_HSPDAM), 0,
+       NO_ATTK,        NO_DFNS,        CARY(AD_MAGM),
+       INVIS,          A_LAWFUL, PM_ARCHEOLOGIST, NON_PM, 2500L ),
+
+A("The Heart of Ahriman",      LUCKSTONE,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL), SPFX_STLTH, 0,
+       /* this stone does double damage if used as a projectile weapon */
+       PHYS(5,0),      NO_DFNS,        NO_CARY,
+       LEVITATION,     A_NEUTRAL, PM_BARBARIAN, NON_PM, 2500L ),
+
+A("The Sceptre of Might",      MACE,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_DALIGN), 0, 0,
+       PHYS(5,0),      NO_DFNS,        CARY(AD_MAGM),
+       CONFLICT,       A_LAWFUL, PM_CAVEMAN, NON_PM, 2500L ),
+
+#if 0  /* OBSOLETE */
+A("The Palantir of Westernesse",       CRYSTAL_BALL,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL),
+               (SPFX_ESP|SPFX_REGEN|SPFX_HSPDAM), 0,
+       NO_ATTK,        NO_DFNS,        NO_CARY,
+       TAMING,         A_CHAOTIC, NON_PM , PM_ELF, 8000L ),
+#endif
+
+A("The Staff of Aesculapius",  QUARTERSTAFF,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_ATTK|SPFX_INTEL|SPFX_DRLI|SPFX_REGEN), 0,0,
+       DRLI(0,0),      DRLI(0,0),      NO_CARY,
+       HEALING,        A_NEUTRAL, PM_HEALER, NON_PM, 5000L ),
+
+A("The Magic Mirror of Merlin", MIRROR,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_SPEAK), SPFX_ESP, 0,
+       NO_ATTK,        NO_DFNS,        CARY(AD_MAGM),
+       0,              A_LAWFUL, PM_KNIGHT, NON_PM, 1500L ),
+
+A("The Eyes of the Overworld", LENSES,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_XRAY), 0, 0,
+       NO_ATTK,        NO_DFNS,        CARY(AD_MAGM),
+       ENLIGHTENING,   A_NEUTRAL,       PM_MONK, NON_PM, 2500L ),
+
+A("The Mitre of Holiness",     HELM_OF_BRILLIANCE,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_DFLAG2|SPFX_INTEL), 0, M2_UNDEAD,
+       NO_ATTK,        NO_DFNS,        CARY(AD_FIRE),
+       ENERGY_BOOST,   A_LAWFUL, PM_PRIEST, NON_PM, 2000L ),
+
+A("The Longbow of Diana", BOW,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_REFLECT), SPFX_ESP, 0,
+       PHYS(5,0),      NO_DFNS,        NO_CARY,
+       CREATE_AMMO, A_CHAOTIC, PM_RANGER, NON_PM, 4000L ),
+
+A("The Master Key of Thievery", SKELETON_KEY,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_SPEAK),
+               (SPFX_WARN|SPFX_TCTRL|SPFX_HPHDAM), 0,
+       NO_ATTK,        NO_DFNS,        NO_CARY,
+       UNTRAP,         A_CHAOTIC, PM_ROGUE, NON_PM, 3500L ),
+
+A("The Tsurugi of Muramasa",   TSURUGI,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_BEHEAD|SPFX_LUCK), 0, 0,
+       PHYS(0,8),      NO_DFNS,        NO_CARY,
+       0,              A_LAWFUL, PM_SAMURAI, NON_PM, 4500L ),
+
+#ifdef TOURIST
+A("The Platinum Yendorian Express Card", CREDIT_CARD,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_DEFN),
+               (SPFX_ESP|SPFX_HSPDAM), 0,
+       NO_ATTK,        NO_DFNS,        CARY(AD_MAGM),
+       CHARGE_OBJ,     A_NEUTRAL, PM_TOURIST, NON_PM, 7000L ),
+#endif
+
+A("The Orb of Fate",           CRYSTAL_BALL,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_LUCK),
+               (SPFX_WARN|SPFX_HSPDAM|SPFX_HPHDAM), 0,
+       NO_ATTK,        NO_DFNS,        NO_CARY,
+       LEV_TELE,       A_NEUTRAL, PM_VALKYRIE, NON_PM, 3500L ),
+
+A("The Eye of the Aethiopica", AMULET_OF_ESP,
+       (SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL), (SPFX_EREGEN|SPFX_HSPDAM), 0,
+       NO_ATTK,        NO_DFNS,        CARY(AD_MAGM),
+       CREATE_PORTAL,  A_NEUTRAL, PM_WIZARD, NON_PM, 4000L ),
+
+/*
+ *  terminator; otyp must be zero
+ */
+A(0, 0, 0, 0, 0, NO_ATTK, NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 0L )
+
+};     /* artilist[] (or artifact_names[]) */
+
+#undef A
+
+#ifndef MAKEDEFS_C
+#undef NO_ATTK
+#undef NO_DFNS
+#undef DFNS
+#undef PHYS
+#undef DRLI
+#undef COLD
+#undef FIRE
+#undef ELEC
+#undef STUN
+#endif
+
+/*artilist.h*/
diff --git a/include/attrib.h b/include/attrib.h
new file mode 100644 (file)
index 0000000..7148191
--- /dev/null
@@ -0,0 +1,44 @@
+/*     SCCS Id: @(#)attrib.h   3.4     1990/22/02      */
+/* Copyright 1988, Mike Stephenson                               */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*     attrib.h - Header file for character class processing. */
+
+#ifndef ATTRIB_H
+#define ATTRIB_H
+
+#define A_STR  0
+#define A_INT  1
+#define A_WIS  2
+#define A_DEX  3
+#define A_CON  4
+#define A_CHA  5
+
+#define A_MAX  6       /* used in rn2() selection of attrib */
+
+#define ABASE(x)       (u.acurr.a[x])
+#define ABON(x)                (u.abon.a[x])
+#define AEXE(x)                (u.aexe.a[x])
+#define ACURR(x)       (acurr(x))
+#define ACURRSTR       (acurrstr())
+/* should be: */
+/* #define ACURR(x) (ABON(x) + ATEMP(x) + (Upolyd  ? MBASE(x) : ABASE(x)) */
+#define MCURR(x)       (u.macurr.a[x])
+#define AMAX(x)                (u.amax.a[x])
+#define MMAX(x)                (u.mamax.a[x])
+
+#define ATEMP(x)       (u.atemp.a[x])
+#define ATIME(x)       (u.atime.a[x])
+
+/* KMH -- Conveniences when dealing with strength constants */
+#define STR18(x)       (18+(x))        /* 18/xx */
+#define STR19(x)       (100+(x))       /* For 19 and above */
+
+struct attribs {
+       schar   a[A_MAX];
+};
+
+#define ATTRMAX(x) ((x == A_STR && Upolyd && strongmonst(youmonst.data)) ? STR18(100) : urace.attrmax[x])
+#define ATTRMIN(x) (urace.attrmin[x])
+
+#endif /* ATTRIB_H */
diff --git a/include/beconf.h b/include/beconf.h
new file mode 100644 (file)
index 0000000..56df16e
--- /dev/null
@@ -0,0 +1,36 @@
+/*     SCCS Id: @(#)beconf.h   3.4     1998/07/08      */
+/* Copyright (c) Dean Luick 1996.      */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* Configuration for Be Inc.'s BeOS */
+
+#ifndef BECONF_H
+#define BECONF_H
+
+/*
+ * We must use UNWIDENED_PROTOTYPES because we mix C++ and C.
+ */
+
+#define index strchr
+#define rindex strrchr
+#define Rand rand      /* Be should have a better rand function! */
+#define tgetch getchar
+#define FCMASK 0666
+#define PORT_ID "BeOS"
+#define TEXTCOLOR
+#define POSIX_TYPES
+#define SIG_RET_TYPE __signal_func_ptr
+
+#include <time.h>      /* for time_t */
+#include <unistd.h>    /* for lseek() */
+
+/* could go in extern.h, under bemain.c (or something..) */
+void regularize(char *);
+
+
+/* instead of including system.h... */
+#include <string.h>
+#include <stdlib.h>
+#include <termcap.h>
+
+#endif /* BECONF_H */
diff --git a/include/bitmfile.h b/include/bitmfile.h
new file mode 100644 (file)
index 0000000..cef1cf9
--- /dev/null
@@ -0,0 +1,37 @@
+/****************************\
+* Bitmap mit Farbtabelle als *
+* Graphik-Datei speichern               *
+* Autor: Gabriel Schmidt                *
+* (c} 1992 by MAXON-Computer *
+* -> Header-Datei                                               *
+\****************************/
+
+#ifndef H_TO_FILE
+#define H_TO_FILE
+
+/*     #include <portab.h>     */
+#define UWORD unsigned short
+#define ULONG unsigned long
+#define UBYTE unsigned char
+
+#define XIMG_MAGIC     0x58494D47
+
+
+typedef enum { IMG, XIMG } FILE_TYP;
+
+const char *get_file_ext(FILE_TYP typ);
+
+struct RGB
+       {
+       UWORD r, g, b;
+       };
+
+int bitmap_to_file(FILE_TYP typ, int ww, int wh,
+                                                                        unsigned int pwx, unsigned int pwy,
+                                                                        unsigned int planes, unsigned int colors,
+                                                                        const char *filename,
+                                                                        void (*get_color) (unsigned int colind, struct RGB *rgb) ,
+                                                                        void (*get_pixel) (int x, int y, unsigned int *colind) ) ;
+
+#endif
+
diff --git a/include/color.h b/include/color.h
new file mode 100644 (file)
index 0000000..2fe85d1
--- /dev/null
@@ -0,0 +1,52 @@
+/*     SCCS Id: @(#)color.h    3.4     1992/02/02      */
+/* Copyright (c) Steve Linhart, Eric Raymond, 1989. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef COLOR_H
+#define COLOR_H
+
+/*
+ * The color scheme used is tailored for an IBM PC.  It consists of the
+ * standard 8 colors, folowed by their bright counterparts.  There are
+ * exceptions, these are listed below. Bright black doesn't mean very
+ * much, so it is used as the "default" foreground color of the screen.
+ */
+#define CLR_BLACK              0
+#define CLR_RED                        1
+#define CLR_GREEN              2
+#define CLR_BROWN              3 /* on IBM, low-intensity yellow is brown */
+#define CLR_BLUE               4
+#define CLR_MAGENTA            5
+#define CLR_CYAN               6
+#define CLR_GRAY               7 /* low-intensity white */
+#define NO_COLOR               8
+#define CLR_ORANGE             9
+#define CLR_BRIGHT_GREEN       10
+#define CLR_YELLOW             11
+#define CLR_BRIGHT_BLUE                12
+#define CLR_BRIGHT_MAGENTA     13
+#define CLR_BRIGHT_CYAN                14
+#define CLR_WHITE              15
+#define CLR_MAX                        16
+
+/* The "half-way" point for tty based color systems.  This is used in */
+/* the tty color setup code.  (IMHO, it should be removed - dean).    */
+#define BRIGHT         8
+
+/* these can be configured */
+#define HI_OBJ         CLR_MAGENTA
+#define HI_METAL       CLR_CYAN
+#define HI_COPPER      CLR_YELLOW
+#define HI_SILVER      CLR_GRAY
+#define HI_GOLD                CLR_YELLOW
+#define HI_LEATHER     CLR_BROWN
+#define HI_CLOTH       CLR_BROWN
+#define HI_ORGANIC     CLR_BROWN
+#define HI_WOOD                CLR_BROWN
+#define HI_PAPER       CLR_WHITE
+#define HI_GLASS       CLR_BRIGHT_CYAN
+#define HI_MINERAL     CLR_GRAY
+#define DRAGON_SILVER  CLR_BRIGHT_CYAN
+#define HI_ZAP         CLR_BRIGHT_BLUE
+
+#endif /* COLOR_H */
diff --git a/include/config.h b/include/config.h
new file mode 100644 (file)
index 0000000..3efbfa2
--- /dev/null
@@ -0,0 +1,358 @@
+/*     SCCS Id: @(#)config.h   3.4     2003/12/06      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef CONFIG_H /* make sure the compiler does not see the typedefs twice */
+#define CONFIG_H
+
+
+/*
+ * Section 1:  Operating and window systems selection.
+ *             Select the version of the OS you are using.
+ *             For "UNIX" select BSD, ULTRIX, SYSV, or HPUX in unixconf.h.
+ *             A "VMS" option is not needed since the VMS C-compilers
+ *             provide it (no need to change sec#1, vmsconf.h handles it).
+ */
+
+#define UNIX           /* delete if no fork(), exec() available */
+
+/* #define MSDOS */    /* in case it's not auto-detected */
+
+/* #define OS2 */      /* define for OS/2 */
+
+/* #define TOS */      /* define for Atari ST/TT */
+
+/* #define STUPID */   /* avoid some complicated expressions if
+                          your C compiler chokes on them */
+/* #define MINIMAL_TERM */
+                       /* if a terminal handles highlighting or tabs poorly,
+                          try this define, used in pager.c and termcap.c */
+/* #define ULTRIX_CC20 */
+                       /* define only if using cc v2.0 on a DECstation */
+/* #define ULTRIX_PROTO */
+                       /* define for Ultrix 4.0 (or higher) on a DECstation;
+                        * if you get compiler errors, don't define this. */
+                       /* Hint: if you're not developing code, don't define
+                          ULTRIX_PROTO. */
+
+#include "config1.h"   /* should auto-detect MSDOS, MAC, AMIGA, and WIN32 */
+
+
+/* Windowing systems...
+ * Define all of those you want supported in your binary.
+ * Some combinations make no sense.  See the installation document.
+ */
+#define TTY_GRAPHICS   /* good old tty based graphics */
+/* #define X11_GRAPHICS */     /* X11 interface */
+/* #define QT_GRAPHICS */      /* Qt interface */
+/* #define GNOME_GRAPHICS */   /* Gnome interface */
+/* #define MSWIN_GRAPHICS */   /* Windows NT, CE, Graphics */
+
+/*
+ * Define the default window system.  This should be one that is compiled
+ * into your system (see defines above).  Known window systems are:
+ *
+ *     tty, X11, mac, amii, BeOS, Qt, Gem, Gnome
+ */
+
+/* MAC also means MAC windows */
+#ifdef MAC
+# ifndef       AUX
+#  define DEFAULT_WINDOW_SYS "mac"
+# endif
+#endif
+
+/* Amiga supports AMII_GRAPHICS and/or TTY_GRAPHICS */
+#ifdef AMIGA
+# define AMII_GRAPHICS                 /* (optional) */
+# define DEFAULT_WINDOW_SYS "amii"     /* "amii", "amitile" or "tty" */
+#endif
+
+/* Atari supports GEM_GRAPHICS and/or TTY_GRAPHICS */
+#ifdef TOS
+# define GEM_GRAPHICS                  /* Atari GEM interface (optional) */
+# define DEFAULT_WINDOW_SYS "Gem"      /* "Gem" or "tty" */
+#endif
+
+#ifdef __BEOS__
+#define BEOS_GRAPHICS /* (optional) */
+#define DEFAULT_WINDOW_SYS "BeOS"  /* "tty" */
+#ifndef HACKDIR        /* override the default hackdir below */
+# define HACKDIR "/boot/apps/NetHack"
+#endif
+#endif
+
+#ifdef QT_GRAPHICS
+# define DEFAULT_WC_TILED_MAP   /* Default to tiles if users doesn't say wc_ascii_map */
+# define USER_SOUNDS           /* Use sounds */
+# ifndef __APPLE__
+#  define USER_SOUNDS_REGEX
+# endif
+# define USE_XPM               /* Use XPM format for images (required) */
+# define GRAPHIC_TOMBSTONE     /* Use graphical tombstone (rip.ppm) */
+# ifndef DEFAULT_WINDOW_SYS
+#  define DEFAULT_WINDOW_SYS "Qt"
+# endif
+#endif
+
+#ifdef GNOME_GRAPHICS
+# define USE_XPM               /* Use XPM format for images (required) */
+# define GRAPHIC_TOMBSTONE     /* Use graphical tombstone (rip.ppm) */
+# ifndef DEFAULT_WINDOW_SYS
+#  define DEFAULT_WINDOW_SYS "Gnome"
+# endif
+#endif
+
+#ifdef MSWIN_GRAPHICS
+# ifdef TTY_GRAPHICS
+# undef TTY_GRAPHICS
+# endif
+# ifndef DEFAULT_WINDOW_SYS
+#  define DEFAULT_WINDOW_SYS "mswin"
+# endif
+# define HACKDIR "\\nethack"
+#endif
+
+#ifndef DEFAULT_WINDOW_SYS
+# define DEFAULT_WINDOW_SYS "tty"
+#endif
+
+#ifdef X11_GRAPHICS
+/*
+ * There are two ways that X11 tiles may be defined.  (1) using a custom
+ * format loaded by NetHack code, or (2) using the XPM format loaded by
+ * the free XPM library.  The second option allows you to then use other
+ * programs to generate tiles files.  For example, the PBMPlus tools
+ * would allow:
+ *  xpmtoppm <x11tiles.xpm | pnmscale 1.25 | ppmquant 90 >x11tiles_big.xpm
+ */
+/* # define USE_XPM */         /* Disable if you do not have the XPM library */
+# ifdef USE_XPM
+#  define GRAPHIC_TOMBSTONE    /* Use graphical tombstone (rip.xpm) */
+# endif
+#endif
+
+
+/*
+ * Section 2:  Some global parameters and filenames.
+ *             Commenting out WIZARD, LOGFILE, NEWS or PANICLOG removes that
+ *             feature from the game; otherwise set the appropriate wizard
+ *             name.  LOGFILE, NEWS and PANICLOG refer to files in the
+ *             playground.
+ */
+
+#ifndef WIZARD         /* allow for compile-time or Makefile changes */
+# ifndef KR1ED
+#  define WIZARD  "wizard" /* the person allowed to use the -D option */
+# else
+#  define WIZARD
+#  define WIZARD_NAME "wizard"
+# endif
+#endif
+
+#define LOGFILE "logfile"      /* larger file for debugging purposes */
+#define NEWS "news"            /* the file containing the latest hack news */
+#define PANICLOG "paniclog"    /* log of panic and impossible events */
+
+/*
+ *     If COMPRESS is defined, it should contain the full path name of your
+ *     'compress' program.  Defining INTERNAL_COMP causes NetHack to do
+ *     simpler byte-stream compression internally.  Both COMPRESS and
+ *     INTERNAL_COMP create smaller bones/level/save files, but require
+ *     additional code and time.  Currently, only UNIX fully implements
+ *     COMPRESS; other ports should be able to uncompress save files a
+ *     la unixmain.c if so inclined.
+ *     If you define COMPRESS, you must also define COMPRESS_EXTENSION
+ *     as the extension your compressor appends to filenames after
+ *     compression.
+ */
+
+#ifdef UNIX
+/* path and file name extension for compression program */
+#define COMPRESS "/usr/bin/compress"   /* Lempel-Ziv compression */
+#define COMPRESS_EXTENSION ".Z"                /* compress's extension */
+/* An example of one alternative you might want to use: */
+/* #define COMPRESS "/usr/local/bin/gzip" */   /* FSF gzip compression */
+/* #define COMPRESS_EXTENSION ".gz" */         /* normal gzip extension */
+#endif
+
+#ifndef COMPRESS
+# define INTERNAL_COMP /* control use of NetHack's compression routines */
+#endif
+
+/*
+ *     Data librarian.  Defining DLB places most of the support files into
+ *     a tar-like file, thus making a neater installation.  See *conf.h
+ *     for detailed configuration.
+ */
+/* #define DLB */      /* not supported on all platforms */
+
+/*
+ *     Defining INSURANCE slows down level changes, but allows games that
+ *     died due to program or system crashes to be resumed from the point
+ *     of the last level change, after running a utility program.
+ */
+#define INSURANCE      /* allow crashed game recovery */
+
+#ifndef MAC
+# define CHDIR         /* delete if no chdir() available */
+#endif
+
+#ifdef CHDIR
+/*
+ * If you define HACKDIR, then this will be the default playground;
+ * otherwise it will be the current directory.
+ */
+# ifndef HACKDIR
+#  define HACKDIR "/usr/games/lib/nethackdir"
+# endif
+
+/*
+ * Some system administrators are stupid enough to make Hack suid root
+ * or suid daemon, where daemon has other powers besides that of reading or
+ * writing Hack files. In such cases one should be careful with chdir's
+ * since the user might create files in a directory of his choice.
+ * Of course SECURE is meaningful only if HACKDIR is defined.
+ */
+/* #define SECURE */   /* do setuid(getuid()) after chdir() */
+
+/*
+ * If it is desirable to limit the number of people that can play Hack
+ * simultaneously, define HACKDIR, SECURE and MAX_NR_OF_PLAYERS.
+ * #define MAX_NR_OF_PLAYERS 6
+ */
+#endif /* CHDIR */
+
+
+
+/*
+ * Section 3:  Definitions that may vary with system type.
+ *             For example, both schar and uchar should be short ints on
+ *             the AT&T 3B2/3B5/etc. family.
+ */
+
+/*
+ * Uncomment the following line if your compiler doesn't understand the
+ * 'void' type (and thus would give all sorts of compile errors without
+ * this definition).
+ */
+/* #define NOVOID */                   /* define if no "void" data type. */
+
+/*
+ * Uncomment the following line if your compiler falsely claims to be
+ * a standard C compiler (i.e., defines __STDC__ without cause).
+ * Examples are Apollo's cc (in some versions) and possibly SCO UNIX's rcc.
+ */
+/* #define NOTSTDC */                  /* define for lying compilers */
+
+#include "tradstdc.h"
+
+/*
+ * type schar: small signed integers (8 bits suffice) (eg. TOS)
+ *
+ *     typedef char    schar;
+ *
+ *     will do when you have signed characters; otherwise use
+ *
+ *     typedef short int schar;
+ */
+#ifdef AZTEC
+# define schar char
+#else
+typedef signed char    schar;
+#endif
+
+/*
+ * type uchar: small unsigned integers (8 bits suffice - but 7 bits do not)
+ *
+ *     typedef unsigned char   uchar;
+ *
+ *     will be satisfactory if you have an "unsigned char" type;
+ *     otherwise use
+ *
+ *     typedef unsigned short int uchar;
+ */
+#ifndef _AIX32         /* identical typedef in system file causes trouble */
+typedef unsigned char  uchar;
+#endif
+
+/*
+ * Various structures have the option of using bitfields to save space.
+ * If your C compiler handles bitfields well (e.g., it can initialize structs
+ * containing bitfields), you can define BITFIELDS.  Otherwise, the game will
+ * allocate a separate character for each bitfield.  (The bitfields used never
+ * have more than 7 bits, and most are only 1 bit.)
+ */
+#define BITFIELDS      /* Good bitfield handling */
+
+/* #define STRNCMPI */ /* compiler/library has the strncmpi function */
+
+/*
+ * There are various choices for the NetHack vision system.  There is a
+ * choice of two algorithms with the same behavior.  Defining VISION_TABLES
+ * creates huge (60K) tables at compile time, drastically increasing data
+ * size, but runs slightly faster than the alternate algorithm.  (MSDOS in
+ * particular cannot tolerate the increase in data size; other systems can
+ * flip a coin weighted to local conditions.)
+ *
+ * If VISION_TABLES is not defined, things will be faster if you can use
+ * MACRO_CPATH.  Some cpps, however, cannot deal with the size of the
+ * functions that have been macroized.
+ */
+
+/* #define VISION_TABLES */ /* use vision tables generated at compile time */
+#ifndef VISION_TABLES
+# ifndef NO_MACRO_CPATH
+#  define MACRO_CPATH  /* use clear_path macros instead of functions */
+# endif
+#endif
+
+/*
+ * Section 4:  THE FUN STUFF!!!
+ *
+ * Conditional compilation of special options are controlled here.
+ * If you define the following flags, you will add not only to the
+ * complexity of the game but also to the size of the load module.
+ */
+
+/* dungeon features */
+#define SINKS          /* Kitchen sinks - Janet Walz */
+/* dungeon levels */
+#define WALLIFIED_MAZE /* Fancy mazes - Jean-Christophe Collet */
+#define REINCARNATION  /* Special Rogue-like levels */
+/* monsters & objects */
+#define KOPS           /* Keystone Kops by Scott R. Turner */
+#define SEDUCE         /* Succubi/incubi seduction, by KAA, suggested by IM */
+#define STEED          /* Riding steeds */
+#define TOURIST                /* Tourist players with cameras and Hawaiian shirts */
+/* difficulty */
+#define ELBERETH       /* Engraving the E-word repels monsters */
+/* I/O */
+#define REDO           /* support for redoing last command - DGK */
+#if !defined(MAC)
+# define CLIPPING      /* allow smaller screens -- ERS */
+#endif
+
+#ifdef REDO
+# define DOAGAIN '\001' /* ^A, the "redo" key used in cmd.c and getline.c */
+#endif
+
+#define EXP_ON_BOTL    /* Show experience on bottom line */
+/* #define SCORE_ON_BOTL */    /* added by Gary Erickson (erickson@ucivax) */
+
+/*
+ * Section 5:  EXPERIMENTAL STUFF
+ *
+ * Conditional compilation of new or experimental options are controlled here.
+ * Enable any of these at your own risk -- there are almost certainly
+ * bugs left here.
+ */
+
+/*#define GOLDOBJ */   /* Gold is kept on obj chains - Helge Hafting */
+/*#define AUTOPICKUP_EXCEPTIONS */ /* exceptions to autopickup */
+
+/* End of Section 5 */
+
+#include "global.h"    /* Define everything else according to choices above */
+
+#endif /* CONFIG_H */
diff --git a/include/config1.h b/include/config1.h
new file mode 100644 (file)
index 0000000..d17225f
--- /dev/null
@@ -0,0 +1,204 @@
+/*     SCCS Id: @(#)config1.h  3.4     1999/12/05      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef CONFIG1_H
+#define CONFIG1_H
+
+/*
+ * MS DOS - compilers
+ *
+ * Microsoft C auto-defines MSDOS,
+ * Borland C   auto-defines __MSDOS__,
+ * DJGPP       auto-defines MSDOS.
+ */
+
+/* #define MSDOS */    /* use if not defined by compiler or cases below */
+
+#ifdef __MSDOS__       /* for Borland C */
+# ifndef MSDOS
+# define MSDOS
+# endif
+#endif
+
+#ifdef __TURBOC__
+# define __MSC         /* increase Borland C compatibility in libraries */
+#endif
+
+#ifdef MSDOS
+# undef UNIX
+#endif
+
+/*
+ * Mac Stuff.
+ */
+#ifdef macintosh       /*      Auto-defined symbol for MPW compilers (sc and mrc) */
+# define MAC
+#endif
+
+#ifdef THINK_C         /* Think C auto-defined symbol */
+# define MAC
+# define NEED_VARARGS
+#endif
+
+#ifdef __MWERKS__      /* defined by Metrowerks' Codewarrior compiler */
+# ifndef __BEOS__      /* BeOS */
+#  define MAC
+# endif
+# define NEED_VARARGS
+# define USE_STDARG
+#endif
+
+#if defined(MAC) || defined(__BEOS__)
+# define DLB
+# undef UNIX
+#endif
+
+#ifdef __BEOS__
+# define NEED_VARARGS
+#endif
+
+
+/*
+ * Amiga setup.
+ */
+#ifdef AZTEC_C /* Manx auto-defines this */
+# ifdef MCH_AMIGA      /* Manx auto-defines this for AMIGA */
+#  ifndef AMIGA
+#define AMIGA          /* define for Commodore-Amiga */
+#  endif               /* (SAS/C auto-defines AMIGA) */
+#define AZTEC_50       /* define for version 5.0 of manx */
+# endif
+#endif
+#ifdef __SASC_60
+# define NEARDATA __near /* put some data close */
+#else
+# ifdef _DCC
+# define NEARDATA __near /* put some data close */
+# else
+# define NEARDATA
+# endif
+#endif
+#ifdef AMIGA
+# define NEED_VARARGS
+# undef UNIX
+# define DLB
+# define HACKDIR "NetHack:"
+# define NO_MACRO_CPATH
+#endif
+
+/*
+ * Atari auto-detection
+ */
+
+#ifdef atarist
+# undef UNIX
+# ifndef TOS
+# define TOS
+# endif
+#else
+# ifdef __MINT__
+#  undef UNIX
+#  ifndef TOS
+#  define TOS
+#  endif
+# endif
+#endif
+
+/*
+ * Windows NT Autodetection
+ */
+#ifdef _WIN32_WCE
+#define WIN_CE
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+
+#ifdef WIN32
+# undef UNIX
+# undef MSDOS
+# define NHSTDC
+# define USE_STDARG
+# define NEED_VARARGS
+
+#ifndef WIN_CE
+# define STRNCMPI
+# define STRCMPI
+#endif
+
+#endif
+
+
+#if defined(__linux__) && defined(__GNUC__) && !defined(_GNU_SOURCE)
+/* ensure _GNU_SOURCE is defined before including any system headers */
+# define _GNU_SOURCE
+#endif
+
+#ifdef VMS     /* really old compilers need special handling, detected here */
+# undef UNIX
+# ifdef __DECC
+#  ifndef __DECC_VER   /* buggy early versions want widened prototypes */
+#   define NOTSTDC     /* except when typedefs are involved            */
+#   define USE_VARARGS
+#  else
+#   define NHSTDC
+#   define USE_STDARG
+#   define POSIX_TYPES
+#   define _DECC_V4_SOURCE     /* avoid some incompatible V5.x changes */
+#  endif
+#  undef __HIDE_FORBIDDEN_NAMES /* need non-ANSI library support functions */
+# else
+#  ifdef VAXC  /* must use CC/DEFINE=ANCIENT_VAXC for vaxc v2.2 or older */
+#   ifdef ANCIENT_VAXC /* vaxc v2.2 and earlier [lots of warnings to come] */
+#    define KR1ED      /* simulate defined() */
+#    define USE_VARARGS
+#   else               /* vaxc v2.3,2.4,or 3.x, or decc in vaxc mode */
+#     if defined(USE_PROTOTYPES) /* this breaks 2.2 (*forces* use of ANCIENT)*/
+#      define __STDC__ 0 /* vaxc is not yet ANSI compliant, but close enough */
+#      define signed   /* well, almost close enough */
+#include <stddef.h>
+#      define UNWIDENED_PROTOTYPES
+#     endif
+#     define USE_STDARG
+#   endif
+#  endif /*VAXC*/
+# endif /*__DECC*/
+# ifdef VERYOLD_VMS    /* v4.5 or earlier; no longer available for testing */
+#  define USE_OLDARGS  /* <varargs.h> is there, vprintf & vsprintf aren't */
+#  ifdef USE_VARARGS
+#   undef USE_VARARGS
+#  endif
+#  ifdef USE_STDARG
+#   undef USE_STDARG
+#  endif
+# endif
+#endif /*VMS*/
+
+#ifdef vax
+/* just in case someone thinks a DECstation is a vax. It's not, it's a mips */
+# ifdef ULTRIX_PROTO
+#  undef ULTRIX_PROTO
+# endif
+# ifdef ULTRIX_CC20
+#  undef ULTRIX_CC20
+# endif
+#endif
+
+#ifdef KR1ED           /* For compilers which cannot handle defined() */
+#define defined(x) (-x-1 != -1)
+/* Because:
+ * #define FOO => FOO={} => defined( ) => (-1 != - - 1) => 1
+ * #define FOO 1 or on command-line -DFOO
+ *     => defined(1) => (-1 != - 1 - 1) => 1
+ * if FOO isn't defined, FOO=0. But some compilers default to 0 instead of 1
+ * for -DFOO, oh well.
+ *     => defined(0) => (-1 != - 0 - 1) => 0
+ *
+ * But:
+ * defined("") => (-1 != - "" - 1)
+ *   [which is an unavoidable catastrophe.]
+ */
+#endif
+
+#endif /* CONFIG1_H */
diff --git a/include/coord.h b/include/coord.h
new file mode 100644 (file)
index 0000000..3322820
--- /dev/null
@@ -0,0 +1,12 @@
+/*     SCCS Id: @(#)coord.h    3.4     1990/02/22      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef COORD_H
+#define COORD_H
+
+typedef struct nhcoord {
+       xchar x,y;
+} coord;
+
+#endif /* COORD_H */
diff --git a/include/decl.h b/include/decl.h
new file mode 100644 (file)
index 0000000..76f9533
--- /dev/null
@@ -0,0 +1,390 @@
+/*     SCCS Id: @(#)decl.h     3.4     2001/12/10      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef DECL_H
+#define DECL_H
+
+#define E extern
+
+E int NDECL((*occupation));
+E int NDECL((*afternmv));
+
+E const char *hname;
+E int hackpid;
+#if defined(UNIX) || defined(VMS)
+E int locknum;
+#endif
+#ifdef DEF_PAGER
+E char *catmore;
+#endif /* DEF_PAGER */
+
+E char SAVEF[];
+#ifdef MICRO
+E char SAVEP[];
+#endif
+
+E NEARDATA int bases[MAXOCLASSES];
+
+E NEARDATA int multi;
+#if 0
+E NEARDATA int warnlevel;
+#endif
+E NEARDATA int nroom;
+E NEARDATA int nsubroom;
+E NEARDATA int occtime;
+
+#define WARNCOUNT 6                    /* number of different warning levels */
+E uchar warnsyms[WARNCOUNT];
+
+E int x_maze_max, y_maze_max;
+E int otg_temp;
+
+#ifdef REDO
+E NEARDATA int in_doagain;
+#endif
+
+E struct dgn_topology {                /* special dungeon levels for speed */
+    d_level    d_oracle_level;
+    d_level    d_bigroom_level;        /* unused */
+#ifdef REINCARNATION
+    d_level    d_rogue_level;
+#endif
+    d_level    d_medusa_level;
+    d_level    d_stronghold_level;
+    d_level    d_valley_level;
+    d_level    d_wiz1_level;
+    d_level    d_wiz2_level;
+    d_level    d_wiz3_level;
+    d_level    d_juiblex_level;
+    d_level    d_orcus_level;
+    d_level    d_baalzebub_level;      /* unused */
+    d_level    d_asmodeus_level;       /* unused */
+    d_level    d_portal_level;         /* only in goto_level() [do.c] */
+    d_level    d_sanctum_level;
+    d_level    d_earth_level;
+    d_level    d_water_level;
+    d_level    d_fire_level;
+    d_level    d_air_level;
+    d_level    d_astral_level;
+    xchar      d_tower_dnum;
+    xchar      d_sokoban_dnum;
+    xchar      d_mines_dnum, d_quest_dnum;
+    d_level    d_qstart_level, d_qlocate_level, d_nemesis_level;
+    d_level    d_knox_level;
+} dungeon_topology;
+/* macros for accesing the dungeon levels by their old names */
+#define oracle_level           (dungeon_topology.d_oracle_level)
+#define bigroom_level          (dungeon_topology.d_bigroom_level)
+#ifdef REINCARNATION
+#define rogue_level            (dungeon_topology.d_rogue_level)
+#endif
+#define medusa_level           (dungeon_topology.d_medusa_level)
+#define stronghold_level       (dungeon_topology.d_stronghold_level)
+#define valley_level           (dungeon_topology.d_valley_level)
+#define wiz1_level             (dungeon_topology.d_wiz1_level)
+#define wiz2_level             (dungeon_topology.d_wiz2_level)
+#define wiz3_level             (dungeon_topology.d_wiz3_level)
+#define juiblex_level          (dungeon_topology.d_juiblex_level)
+#define orcus_level            (dungeon_topology.d_orcus_level)
+#define baalzebub_level                (dungeon_topology.d_baalzebub_level)
+#define asmodeus_level         (dungeon_topology.d_asmodeus_level)
+#define portal_level           (dungeon_topology.d_portal_level)
+#define sanctum_level          (dungeon_topology.d_sanctum_level)
+#define earth_level            (dungeon_topology.d_earth_level)
+#define water_level            (dungeon_topology.d_water_level)
+#define fire_level             (dungeon_topology.d_fire_level)
+#define air_level              (dungeon_topology.d_air_level)
+#define astral_level           (dungeon_topology.d_astral_level)
+#define tower_dnum             (dungeon_topology.d_tower_dnum)
+#define sokoban_dnum           (dungeon_topology.d_sokoban_dnum)
+#define mines_dnum             (dungeon_topology.d_mines_dnum)
+#define quest_dnum             (dungeon_topology.d_quest_dnum)
+#define qstart_level           (dungeon_topology.d_qstart_level)
+#define qlocate_level          (dungeon_topology.d_qlocate_level)
+#define nemesis_level          (dungeon_topology.d_nemesis_level)
+#define knox_level             (dungeon_topology.d_knox_level)
+
+E NEARDATA stairway dnstair, upstair;          /* stairs up and down */
+#define xdnstair       (dnstair.sx)
+#define ydnstair       (dnstair.sy)
+#define xupstair       (upstair.sx)
+#define yupstair       (upstair.sy)
+
+E NEARDATA stairway dnladder, upladder;                /* ladders up and down */
+#define xdnladder      (dnladder.sx)
+#define ydnladder      (dnladder.sy)
+#define xupladder      (upladder.sx)
+#define yupladder      (upladder.sy)
+
+E NEARDATA stairway sstairs;
+
+E NEARDATA dest_area updest, dndest;   /* level-change destination areas */
+
+E NEARDATA coord inv_pos;
+E NEARDATA dungeon dungeons[];
+E NEARDATA s_level *sp_levchn;
+#define dunlev_reached(x)      (dungeons[(x)->dnum].dunlev_ureached)
+
+#include "quest.h"
+E struct q_score quest_status;
+
+E NEARDATA char pl_character[PL_CSIZ];
+E NEARDATA char pl_race;               /* character's race */
+
+E NEARDATA char pl_fruit[PL_FSIZ];
+E NEARDATA int current_fruit;
+E NEARDATA struct fruit *ffruit;
+
+E NEARDATA char tune[6];
+
+#define MAXLINFO (MAXDUNGEON * MAXLEVEL)
+E struct linfo level_info[MAXLINFO];
+
+E NEARDATA struct sinfo {
+       int gameover;           /* self explanatory? */
+       int stopprint;          /* inhibit further end of game disclosure */
+#if defined(UNIX) || defined(VMS) || defined (__EMX__) || defined(WIN32)
+       int done_hup;           /* SIGHUP or moral equivalent received
+                                * -- no more screen output */
+#endif
+       int something_worth_saving;     /* in case of panic */
+       int panicking;          /* `panic' is in progress */
+#if defined(VMS) || defined(WIN32)
+       int exiting;            /* an exit handler is executing */
+#endif
+       int in_impossible;
+#ifdef PANICLOG
+       int in_paniclog;
+#endif
+} program_state;
+
+E boolean restoring;
+
+E const char quitchars[];
+E const char vowels[];
+E const char ynchars[];
+E const char ynqchars[];
+E const char ynaqchars[];
+E const char ynNaqchars[];
+E NEARDATA long yn_number;
+
+E const char disclosure_options[];
+
+E NEARDATA int smeq[];
+E NEARDATA int doorindex;
+E NEARDATA char *save_cm;
+#define KILLED_BY_AN    0
+#define KILLED_BY       1
+#define NO_KILLER_PREFIX 2
+E NEARDATA int killer_format;
+E const char *killer;
+E const char *delayed_killer;
+#ifdef GOLDOBJ
+E long done_money;
+#endif
+E char killer_buf[BUFSZ];
+E const char *configfile;
+E NEARDATA char plname[PL_NSIZ];
+E NEARDATA char dogname[];
+E NEARDATA char catname[];
+E NEARDATA char horsename[];
+E char preferred_pet;
+E const char *occtxt;                  /* defined when occupation != NULL */
+E const char *nomovemsg;
+E const char nul[];
+E char lock[];
+
+E const char sdir[], ndir[];
+E const schar xdir[], ydir[], zdir[];
+
+E NEARDATA schar tbx, tby;             /* set in mthrowu.c */
+
+E NEARDATA struct multishot { int n, i; short o; boolean s; } m_shot;
+
+E NEARDATA struct dig_info {           /* apply.c, hack.c */
+       int     effort;
+       d_level level;
+       coord   pos;
+       long lastdigtime;
+       boolean down, chew, warned, quiet;
+} digging;
+
+E NEARDATA long moves, monstermoves;
+E NEARDATA long wailmsg;
+
+E NEARDATA boolean in_mklev;
+E NEARDATA boolean stoned;
+E NEARDATA boolean unweapon;
+E NEARDATA boolean mrg_to_wielded;
+E NEARDATA struct obj *current_wand;
+
+E NEARDATA boolean in_steed_dismounting;
+
+E const int shield_static[];
+
+#include "spell.h"
+E NEARDATA struct spell spl_book[];    /* sized in decl.c */
+
+#include "color.h"
+#ifdef TEXTCOLOR
+E const int zapcolors[];
+#endif
+
+E const char def_oc_syms[MAXOCLASSES]; /* default class symbols */
+E uchar oc_syms[MAXOCLASSES];          /* current class symbols */
+E const char def_monsyms[MAXMCLASSES]; /* default class symbols */
+E uchar monsyms[MAXMCLASSES];          /* current class symbols */
+
+#include "obj.h"
+E NEARDATA struct obj *invent,
+       *uarm, *uarmc, *uarmh, *uarms, *uarmg, *uarmf,
+#ifdef TOURIST
+       *uarmu,                         /* under-wear, so to speak */
+#endif
+       *uskin, *uamul, *uleft, *uright, *ublindf,
+       *uwep, *uswapwep, *uquiver;
+
+E NEARDATA struct obj *uchain;         /* defined only when punished */
+E NEARDATA struct obj *uball;
+E NEARDATA struct obj *migrating_objs;
+E NEARDATA struct obj *billobjs;
+E NEARDATA struct obj zeroobj;         /* init'd and defined in decl.c */
+
+#include "you.h"
+E NEARDATA struct you u;
+
+#include "onames.h"
+#ifndef PM_H           /* (pm.h has already been included via youprop.h) */
+#include "pm.h"
+#endif
+
+E NEARDATA struct monst youmonst;      /* init'd and defined in decl.c */
+E NEARDATA struct monst *mydogs, *migrating_mons;
+
+E NEARDATA struct mvitals {
+       uchar   born;
+       uchar   died;
+       uchar   mvflags;
+} mvitals[NUMMONS];
+
+E NEARDATA struct c_color_names {
+    const char *const c_black, *const c_amber, *const c_golden,
+               *const c_light_blue,*const c_red, *const c_green,
+               *const c_silver, *const c_blue, *const c_purple,
+               *const c_white;
+} c_color_names;
+#define NH_BLACK               c_color_names.c_black
+#define NH_AMBER               c_color_names.c_amber
+#define NH_GOLDEN              c_color_names.c_golden
+#define NH_LIGHT_BLUE          c_color_names.c_light_blue
+#define NH_RED                 c_color_names.c_red
+#define NH_GREEN               c_color_names.c_green
+#define NH_SILVER              c_color_names.c_silver
+#define NH_BLUE                        c_color_names.c_blue
+#define NH_PURPLE              c_color_names.c_purple
+#define NH_WHITE               c_color_names.c_white
+
+/* The names of the colors used for gems, etc. */
+E const char *c_obj_colors[];
+
+E struct c_common_strings {
+    const char *const c_nothing_happens, *const c_thats_enough_tries,
+               *const c_silly_thing_to, *const c_shudder_for_moment,
+               *const c_something, *const c_Something,
+               *const c_You_can_move_again,
+               *const c_Never_mind, *c_vision_clears,
+               *const c_the_your[2];
+} c_common_strings;
+#define nothing_happens    c_common_strings.c_nothing_happens
+#define thats_enough_tries c_common_strings.c_thats_enough_tries
+#define silly_thing_to    c_common_strings.c_silly_thing_to
+#define shudder_for_moment c_common_strings.c_shudder_for_moment
+#define something         c_common_strings.c_something
+#define Something         c_common_strings.c_Something
+#define You_can_move_again c_common_strings.c_You_can_move_again
+#define Never_mind        c_common_strings.c_Never_mind
+#define vision_clears     c_common_strings.c_vision_clears
+#define the_your          c_common_strings.c_the_your
+
+/* material strings */
+E const char *materialnm[];
+
+/* Monster name articles */
+#define ARTICLE_NONE   0
+#define ARTICLE_THE    1
+#define ARTICLE_A      2
+#define ARTICLE_YOUR   3
+
+/* Monster name suppress masks */
+#define SUPPRESS_IT            0x01
+#define SUPPRESS_INVISIBLE     0x02
+#define SUPPRESS_HALLUCINATION  0x04
+#define SUPPRESS_SADDLE                0x08
+#define EXACT_NAME             0x0F
+
+/* Vision */
+E NEARDATA boolean vision_full_recalc; /* TRUE if need vision recalc */
+E NEARDATA char **viz_array;           /* could see/in sight row pointers */
+
+/* Window system stuff */
+E NEARDATA winid WIN_MESSAGE, WIN_STATUS;
+E NEARDATA winid WIN_MAP, WIN_INVEN;
+E char toplines[];
+#ifndef TCAP_H
+E struct tc_gbl_data { /* also declared in tcap.h */
+    char *tc_AS, *tc_AE;       /* graphics start and end (tty font swapping) */
+    int   tc_LI,  tc_CO;       /* lines and columns */
+} tc_gbl_data;
+#define AS tc_gbl_data.tc_AS
+#define AE tc_gbl_data.tc_AE
+#define LI tc_gbl_data.tc_LI
+#define CO tc_gbl_data.tc_CO
+#endif
+
+/* xxxexplain[] is in drawing.c */
+E const char * const monexplain[], invisexplain[], * const objexplain[], * const oclass_names[];
+
+/* Some systems want to use full pathnames for some subsets of file names,
+ * rather than assuming that they're all in the current directory.  This
+ * provides all the subclasses that seem reasonable, and sets up for all
+ * prefixes being null.  Port code can set those that it wants.
+ */
+#define HACKPREFIX     0
+#define LEVELPREFIX    1
+#define SAVEPREFIX     2
+#define BONESPREFIX    3
+#define DATAPREFIX     4       /* this one must match hardcoded value in dlb.c */
+#define SCOREPREFIX    5
+#define LOCKPREFIX     6
+#define CONFIGPREFIX   7
+#define TROUBLEPREFIX  8
+#define PREFIX_COUNT   9
+/* used in files.c; xxconf.h can override if needed */
+# ifndef FQN_MAX_FILENAME
+#define FQN_MAX_FILENAME 512
+# endif
+
+#if defined(NOCWD_ASSUMPTIONS) || defined(VAR_PLAYGROUND)
+/* the bare-bones stuff is unconditional above to simplify coding; for
+ * ports that actually use prefixes, add some more localized things
+ */
+#define PREFIXES_IN_USE
+#endif
+
+E char *fqn_prefix[PREFIX_COUNT];
+#ifdef PREFIXES_IN_USE
+E char *fqn_prefix_names[PREFIX_COUNT];
+#endif
+
+#ifdef AUTOPICKUP_EXCEPTIONS
+struct autopickup_exception {
+       char *pattern;
+       boolean grab;
+       struct autopickup_exception *next;
+};
+#endif /* AUTOPICKUP_EXCEPTIONS */
+
+#undef E
+
+#endif /* DECL_H */
diff --git a/include/def_os2.h b/include/def_os2.h
new file mode 100644 (file)
index 0000000..7ba40e4
--- /dev/null
@@ -0,0 +1,212 @@
+/*     SCCS Id: @(#)def_os2.h  3.4     1993/01/19      */
+/* Copyright (c) Timo Hakulinen, 1990, 1991, 1992, 1993.         */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *     Only a small portion of all OS/2 defines are needed, so the
+ *     actual include files often need not be used.  In fact,
+ *     including the full headers may stall the compile in DOS.
+ */
+
+#ifdef OS2_USESYSHEADERS
+
+# define INCL_NOPMAPI
+# define INCL_DOSFILEMGR
+# define INCL_DOS
+# define INCL_SUB
+
+#include <os2.h>
+
+#else
+
+typedef char CHAR;
+typedef void VOID;
+
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned int UINT;
+typedef unsigned long ULONG;
+typedef unsigned char BYTE;
+
+# ifdef OS2_32BITAPI
+
+typedef unsigned long SHANDLE;
+typedef USHORT HKBD;
+typedef USHORT HVIO;
+
+#  define CCHMAXPATHCOMP 256
+
+#  ifdef OS2_CSET2
+#   define API16 _Far16 _Pascal
+#   define DAT16
+#   define API32 _System
+#   define KbdGetStatus KBD16GETSTATUS
+#   define KbdSetStatus KBD16SETSTATUS
+#   define KbdCharIn    KBD16CHARIN
+#   define KbdPeek      KBD16PEEK
+#   define VioGetMode   VIO16GETMODE
+#   define VioSetCurPos VIO16SETCURPOS
+#  else
+#   define API16
+#   define DAT16
+#   define API32
+#  endif
+
+#  define DAT
+
+# else /* OS2_32BITAPI */
+
+typedef unsigned short SHANDLE;
+typedef SHANDLE HKBD;
+typedef SHANDLE HVIO;
+
+#  define CCHMAXPATHCOMP 13
+
+#  ifdef OS2_MSC
+#   define API16 pascal far
+#   define DAT16
+#  endif
+
+#  define DAT DAT16
+
+# endif /* OS2_32BITAPI */
+
+typedef USHORT * DAT16 PUSHORT;
+typedef BYTE * DAT16 PBYTE;
+typedef ULONG * DAT PULONG;
+typedef VOID * DAT PVOID;
+
+typedef SHANDLE HDIR;
+typedef HDIR * DAT PHDIR;
+
+typedef char * DAT16 PCH;
+typedef char * DAT PSZ;
+
+/* all supported compilers understand this */
+
+# pragma pack(2)
+
+typedef struct {
+       UCHAR  chChar;
+       UCHAR  chScan;
+       UCHAR  fbStatus;
+       UCHAR  bNlsShift;
+       USHORT fsState;
+       ULONG  time;
+} KBDKEYINFO;
+
+typedef KBDKEYINFO * DAT16 PKBDKEYINFO;
+
+/* File time and date types */
+
+typedef struct {
+       UINT twosecs : 5;
+       UINT minutes : 6;
+       UINT hours   : 5;
+} FTIME;
+
+typedef struct {
+       UINT day     : 5;
+       UINT month   : 4;
+       UINT year    : 7;
+} FDATE;
+
+# ifdef OS2_32BITAPI
+
+typedef struct {
+       ULONG oNextEntryOffset;
+       FDATE fdateCreation;
+       FTIME ftimeCreation;
+       FDATE fdateLastAccess;
+       FTIME ftimeLastAccess;
+       FDATE fdateLastWrite;
+       FTIME ftimeLastWrite;
+       ULONG cbFile;
+       ULONG cbFileAlloc;
+       ULONG attrFile;
+       UCHAR cchName;
+       CHAR  achName[CCHMAXPATHCOMP];
+} FILEFINDBUF3;
+
+# else
+
+typedef struct {
+       FDATE  fdateCreation;
+       FTIME  ftimeCreation;
+       FDATE  fdateLastAccess;
+       FTIME  ftimeLastAccess;
+       FDATE  fdateLastWrite;
+       FTIME  ftimeLastWrite;
+       ULONG  cbFile;
+       ULONG  cbFileAlloc;
+       USHORT attrFile;
+       UCHAR  cchName;
+       CHAR   achName[CCHMAXPATHCOMP];
+} FILEFINDBUF;
+
+typedef FILEFINDBUF * DAT16 PFILEFINDBUF;
+
+# endif /* OS2_32BITAPI */
+
+typedef struct {
+       ULONG  idFileSystem;
+       ULONG  cSectorUnit;
+       ULONG  cUnit;
+       ULONG  cUnitAvail;
+       USHORT cbSector;
+} FSALLOCATE;
+
+typedef struct {
+       USHORT cb;
+       USHORT fsMask;
+       USHORT chTurnAround;
+       USHORT fsInterim;
+       USHORT fsState;
+} KBDINFO;
+
+typedef KBDINFO * DAT16 PKBDINFO;
+
+typedef struct {
+       USHORT cb;
+       UCHAR  fbType;
+       UCHAR  color;
+       USHORT col;
+       USHORT row;
+       USHORT hres;
+       USHORT vres;
+       UCHAR  fmt_ID;
+       UCHAR  attrib;
+       ULONG  buf_addr;
+       ULONG  buf_length;
+       ULONG  full_length;
+       ULONG  partial_length;
+       PCH    ext_data_addr;
+} VIOMODEINFO;
+
+typedef VIOMODEINFO * DAT16 PVIOMODEINFO;
+
+# pragma pack()
+
+/* OS2 API functions */
+
+USHORT API16 KbdGetStatus(PKBDINFO, HKBD);
+USHORT API16 KbdSetStatus(PKBDINFO, HKBD);
+USHORT API16 KbdCharIn(PKBDKEYINFO, USHORT, HKBD);
+USHORT API16 KbdPeek(PKBDKEYINFO, HKBD);
+
+USHORT API16 VioGetMode(PVIOMODEINFO, HVIO);
+USHORT API16 VioSetCurPos(USHORT, USHORT, HVIO);
+
+# ifdef OS2_32BITAPI
+ULONG API32 DosQueryFSInfo(ULONG, ULONG, PVOID, ULONG);
+ULONG API32 DosFindFirst(PSZ, PHDIR, ULONG, PVOID, ULONG, PULONG, ULONG);
+ULONG API32 DosFindNext(HDIR, PVOID, ULONG, PULONG);
+ULONG API32 DosSetDefaultDisk(ULONG);
+# else
+USHORT API16 DosQFSInfo(USHORT, USHORT, PBYTE, USHORT);
+USHORT API16 DosFindFirst(PSZ, PHDIR, USHORT, PFILEFINDBUF, USHORT, PUSHORT, ULONG);
+USHORT API16 DosFindNext(HDIR, PFILEFINDBUF, USHORT, PUSHORT);
+USHORT API16 DosSelectDisk(USHORT);
+# endif /* OS2_32BITAPI */
+
+#endif /* OS2_USESYSHEADERS */
diff --git a/include/dgn_file.h b/include/dgn_file.h
new file mode 100644 (file)
index 0000000..2fa3214
--- /dev/null
@@ -0,0 +1,76 @@
+/*     SCCS Id: @(#)dgn_file.h 3.4     1993/01/17      */
+/* Copyright (c) 1989 by M. Stephenson                           */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef DGN_FILE_H
+#define DGN_FILE_H
+
+#ifndef ALIGN_H
+#include "align.h"
+#endif
+
+/*
+ * Structures manipulated by the dungeon loader & compiler
+ */
+
+struct couple {
+       short   base, rand;
+};
+
+struct tmpdungeon {
+       char    name[24],
+               protoname[24];
+       struct  couple  lev;
+       int     flags,
+               chance,
+               levels,
+               branches,
+               entry_lev;              /* entry level for this dungeon */
+       char    boneschar;
+};
+
+struct tmplevel {
+       char    name[24];
+       struct  couple  lev;
+       int     chance, rndlevs, chain, flags;
+       char    boneschar;
+};
+
+struct tmpbranch {
+       char    name[24];       /* destination dungeon name */
+       struct  couple  lev;
+       int     chain;          /* index into tmplevel array (chained branch)*/
+       int     type;           /* branch type (see below) */
+       int     up;             /* branch is up or down */
+};
+
+/*
+ *     Values for type for tmpbranch structure.
+ */
+#define TBR_STAIR   0  /* connection with both ends having a staircase */
+#define TBR_NO_UP   1  /* connection with no up staircase */
+#define TBR_NO_DOWN 2  /* connection with no down staircase */
+#define TBR_PORTAL  3  /* portal connection */
+
+/*
+ *     Flags that map into the dungeon flags bitfields.
+ */
+#define TOWN       1   /* levels only */
+#define HELLISH     2
+#define MAZELIKE    4
+#define ROGUELIKE   8
+
+#define D_ALIGN_NONE   0
+#define D_ALIGN_CHAOTIC        (AM_CHAOTIC << 4)
+#define D_ALIGN_NEUTRAL        (AM_NEUTRAL << 4)
+#define D_ALIGN_LAWFUL (AM_LAWFUL << 4)
+
+#define D_ALIGN_MASK   0x70
+
+/*
+ *     Max number of prototype levels and branches.
+ */
+#define LEV_LIMIT      50
+#define BRANCH_LIMIT   32
+
+#endif /* DGN_FILE_H */
diff --git a/include/display.h b/include/display.h
new file mode 100644 (file)
index 0000000..d457e4e
--- /dev/null
@@ -0,0 +1,390 @@
+/*     SCCS Id: @(#)display.h  3.4     1999/11/30      */
+/* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */
+/* and Dave Cohrs, 1990.                                         */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef DISPLAY_H
+#define DISPLAY_H
+
+#ifndef VISION_H
+#include "vision.h"
+#endif
+
+#ifndef MONDATA_H
+#include "mondata.h"   /* for mindless() */
+#endif
+
+#ifndef INVISIBLE_OBJECTS
+#define vobj_at(x,y) (level.objects[x][y])
+#endif
+
+/*
+ * sensemon()
+ *
+ * Returns true if the hero can sense the given monster.  This includes
+ * monsters that are hiding or mimicing other monsters.
+ */
+#define tp_sensemon(mon) (     /* The hero can always sense a monster IF:  */\
+    (!mindless(mon->data)) &&  /* 1. the monster has a brain to sense AND  */\
+      ((Blind && Blind_telepat) ||     /* 2a. hero is blind and telepathic OR      */\
+                               /* 2b. hero is using a telepathy inducing   */\
+                               /*       object and in range                */\
+      (Unblind_telepat &&                                            \
+       (distu(mon->mx, mon->my) <= (BOLT_LIM * BOLT_LIM))))                  \
+)
+
+#define sensemon(mon) (tp_sensemon(mon) || Detect_monsters || MATCH_WARN_OF_MON(mon))
+
+/*
+ * mon_warning() is used to warn of any dangerous monsters in your
+ * vicinity, and a glyph representing the warning level is displayed.
+ */
+
+#define mon_warning(mon) (Warning && !(mon)->mpeaceful &&                              \
+                        (distu((mon)->mx, (mon)->my) < 100) &&                         \
+                        (((int) ((mon)->m_lev / 4)) >= flags.warnlevel))
+
+/*
+ * mon_visible()
+ *
+ * Returns true if the hero can see the monster.  It is assumed that the
+ * hero can physically see the location of the monster.  The function
+ * vobj_at() returns a pointer to an object that the hero can see there.
+ * Infravision is not taken into account.
+ */
+#define mon_visible(mon) (             /* The hero can see the monster     */\
+                                       /* IF the monster                   */\
+    (!mon->minvis || See_invisible) && /* 1. is not invisible AND          */\
+    (!mon->mundetected) &&             /* 2. not an undetected hider       */\
+    (!(mon->mburied || u.uburied))     /* 3. neither you or it is buried   */\
+)
+
+/*
+ * see_with_infrared()
+ *
+ * This function is true if the player can see a monster using infravision.
+ * The caller must check for invisibility (invisible monsters are also
+ * invisible to infravision), because this is usually called from within
+ * canseemon() or canspotmon() which already check that.
+ */
+#define see_with_infrared(mon) (!Blind && Infravision && infravisible(mon->data) && couldsee(mon->mx, mon->my))
+
+
+/*
+ * canseemon()
+ *
+ * This is the globally used canseemon().  It is not called within the display
+ * routines.  Like mon_visible(), but it checks to see if the hero sees the
+ * location instead of assuming it.  (And also considers worms.)
+ */
+#define canseemon(mon) ((mon->wormno ? worm_known(mon) : \
+           (cansee(mon->mx, mon->my) || see_with_infrared(mon))) \
+       && mon_visible(mon))
+
+
+/*
+ * canspotmon(mon)
+ *
+ * This function checks whether you can either see a monster or sense it by
+ * telepathy, and is what you usually call for monsters about which nothing is
+ * known.
+ */
+#define canspotmon(mon) \
+       (canseemon(mon) || sensemon(mon))
+
+/* knowninvisible(mon)
+ * This one checks to see if you know a monster is both there and invisible.
+ * 1) If you can see the monster and have see invisible, it is assumed the
+ * monster is transparent, but visible in some manner. (Earlier versions of
+ * Nethack were really inconsistent on this.)
+ * 2) If you can't see the monster, but can see its location and you have
+ * telepathy that works when you can see, you can tell that there is a
+ * creature in an apparently empty spot.
+ * Infravision is not relevant; we assume that invisible monsters are also
+ * invisible to infravision.
+ */
+#define knowninvisible(mon) \
+       (mtmp->minvis && \
+           ((cansee(mon->mx, mon->my) && (See_invisible || Detect_monsters)) || \
+               (!Blind && (HTelepat & ~INTRINSIC) && \
+                   distu(mon->mx, mon->my) <= (BOLT_LIM * BOLT_LIM) \
+               ) \
+           ) \
+       )
+
+/*
+ * is_safepet(mon)
+ *
+ * A special case check used in attack() and domove(). Placing the
+ * definition here is convenient.
+ */
+#define is_safepet(mon) \
+       (mon && mon->mtame && canspotmon(mon) && flags.safe_dog \
+               && !Confusion && !Hallucination && !Stunned)
+
+
+/*
+ * canseeself()
+ * senseself()
+ *
+ * This returns true if the hero can see her/himself.
+ *
+ * The u.uswallow check assumes that you can see yourself even if you are
+ * invisible.  If not, then we don't need the check.
+ */
+#define canseeself()   (Blind || u.uswallow || (!Invisible && !u.uundetected))
+#define senseself()    (canseeself() || Unblind_telepat || Detect_monsters)
+
+/*
+ * random_monster()
+ * random_object()
+ * random_trap()
+ *
+ * Respectively return a random monster, object, or trap number.
+ */
+#define random_monster() rn2(NUMMONS)
+#define random_object()  rn1(NUM_OBJECTS-1,1)
+#define random_trap()   rn1(TRAPNUM-1,1)
+
+/*
+ * what_obj()
+ * what_mon()
+ * what_trap()
+ *
+ * If hallucinating, choose a random object/monster, otherwise, use the one
+ * given.
+ */
+#define what_obj(obj)  (Hallucination ? random_object()  : obj)
+#define what_mon(mon)  (Hallucination ? random_monster() : mon)
+#define what_trap(trp) (Hallucination ? random_trap()    : trp)
+
+/*
+ * covers_objects()
+ * covers_traps()
+ *
+ * These routines are true if what is really at the given location will
+ * "cover" any objects or traps that might be there.
+ */
+#define covers_objects(xx,yy)                                                \
+    ((is_pool(xx,yy) && !Underwater) || (levl[xx][yy].typ == LAVAPOOL))
+
+#define covers_traps(xx,yy)    covers_objects(xx,yy)
+
+
+/*
+ * tmp_at() control calls.
+ */
+#define DISP_BEAM    (-1)  /* Keep all glyphs showing & clean up at end. */
+#define DISP_FLASH   (-2)  /* Clean up each glyph before displaying new one. */
+#define DISP_ALWAYS  (-3)  /* Like flash, but still displayed if not visible. */
+#define DISP_CHANGE  (-4)  /* Change glyph. */
+#define DISP_END     (-5)  /* Clean up. */
+#define DISP_FREEMEM (-6)  /* Free all memory during exit only. */
+
+
+/* Total number of cmap indices in the sheild_static[] array. */
+#define SHIELD_COUNT 21
+
+
+/*
+ * display_self()
+ *
+ * Display the hero.  It is assumed that all checks necessary to determine
+ * _if_ the hero can be seen have already been done.
+ */
+#ifdef STEED
+#define maybe_display_usteed   (u.usteed && mon_visible(u.usteed)) ? \
+                                       ridden_mon_to_glyph(u.usteed) :
+#else
+#define maybe_display_usteed   /* empty */
+#endif
+
+#define display_self()                                                 \
+    show_glyph(u.ux, u.uy,                                             \
+       maybe_display_usteed                    /* else */              \
+       youmonst.m_ap_type == M_AP_NOTHING ?                            \
+                               hero_glyph :                            \
+       youmonst.m_ap_type == M_AP_FURNITURE ?                          \
+                               cmap_to_glyph(youmonst.mappearance) :   \
+       youmonst.m_ap_type == M_AP_OBJECT ?                             \
+                               objnum_to_glyph(youmonst.mappearance) : \
+       /* else M_AP_MONSTER */ monnum_to_glyph(youmonst.mappearance))
+
+/*
+ * A glyph is an abstraction that represents a _unique_ monster, object,
+ * dungeon part, or effect.  The uniqueness is important.  For example,
+ * It is not enough to have four (one for each "direction") zap beam glyphs,
+ * we need a set of four for each beam type.  Why go to so much trouble?
+ * Because it is possible that any given window dependent display driver
+ * [print_glyph()] can produce something different for each type of glyph.
+ * That is, a beam of cold and a beam of fire would not only be different
+ * colors, but would also be represented by different symbols.
+ *
+ * Glyphs are grouped for easy accessibility:
+ *
+ * monster     Represents all the wild (not tame) monsters.  Count: NUMMONS.
+ *
+ * pet         Represents all of the tame monsters.  Count: NUMMONS
+ *
+ * invisible   Invisible monster placeholder.  Count: 1
+ *
+ * detect      Represents all detected monsters.  Count: NUMMONS
+ *
+ * corpse      One for each monster.  Count: NUMMONS
+ *
+ * ridden      Represents all monsters being ridden.  Count: NUMMONS 
+ *
+ * object      One for each object.  Count: NUM_OBJECTS
+ *
+ * cmap                One for each entry in the character map.  The character map
+ *             is the dungeon features and other miscellaneous things.
+ *             Count: MAXPCHARS
+ *
+ * explosions  A set of nine for each of the following seven explosion types:
+ *                   dark, noxious, muddy, wet, magical, fiery, frosty.
+ *              The nine positions represent those surrounding the hero.
+ *             Count: MAXEXPCHARS * EXPL_MAX (EXPL_MAX is defined in hack.h)
+ *
+ * zap beam    A set of four (there are four directions) for each beam type.
+ *             The beam type is shifted over 2 positions and the direction
+ *             is stored in the lower 2 bits.  Count: NUM_ZAP << 2
+ *
+ * swallow     A set of eight for each monster.  The eight positions rep-
+ *             resent those surrounding the hero.  The monster number is
+ *             shifted over 3 positions and the swallow position is stored
+ *             in the lower three bits.  Count: NUMMONS << 3
+ *
+ * warning     A set of six representing the different warning levels.
+ *
+ * The following are offsets used to convert to and from a glyph.
+ */
+#define NUM_ZAP 8      /* number of zap beam types */
+
+#define GLYPH_MON_OFF          0
+#define GLYPH_PET_OFF          (NUMMONS        + GLYPH_MON_OFF)
+#define GLYPH_INVIS_OFF                (NUMMONS        + GLYPH_PET_OFF)
+#define GLYPH_DETECT_OFF       (1              + GLYPH_INVIS_OFF)
+#define GLYPH_BODY_OFF         (NUMMONS        + GLYPH_DETECT_OFF)
+#define GLYPH_RIDDEN_OFF       (NUMMONS        + GLYPH_BODY_OFF)
+#define GLYPH_OBJ_OFF          (NUMMONS        + GLYPH_RIDDEN_OFF)
+#define GLYPH_CMAP_OFF         (NUM_OBJECTS    + GLYPH_OBJ_OFF)
+#define GLYPH_EXPLODE_OFF      ((MAXPCHARS - MAXEXPCHARS) + GLYPH_CMAP_OFF)
+#define GLYPH_ZAP_OFF          ((MAXEXPCHARS * EXPL_MAX) + GLYPH_EXPLODE_OFF)
+#define GLYPH_SWALLOW_OFF      ((NUM_ZAP << 2) + GLYPH_ZAP_OFF)
+#define GLYPH_WARNING_OFF      ((NUMMONS << 3) + GLYPH_SWALLOW_OFF)
+#define MAX_GLYPH              (WARNCOUNT      + GLYPH_WARNING_OFF)
+
+#define NO_GLYPH MAX_GLYPH
+
+#define GLYPH_INVISIBLE GLYPH_INVIS_OFF
+
+#define warning_to_glyph(mwarnlev) ((mwarnlev)+GLYPH_WARNING_OFF)
+#define mon_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_MON_OFF)
+#define detected_mon_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_DETECT_OFF)
+#define ridden_mon_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_RIDDEN_OFF)
+#define pet_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_PET_OFF)
+
+/* This has the unfortunate side effect of needing a global variable   */
+/* to store a result. 'otg_temp' is defined and declared in decl.{ch}. */
+#define obj_to_glyph(obj)                                                    \
+    (Hallucination ?                                                         \
+       ((otg_temp = random_object()) == CORPSE ?                             \
+           random_monster() + GLYPH_BODY_OFF :                               \
+           otg_temp + GLYPH_OBJ_OFF)   :                                     \
+       ((obj)->otyp == CORPSE ?                                              \
+           (int) (obj)->corpsenm + GLYPH_BODY_OFF :                          \
+           (int) (obj)->otyp + GLYPH_OBJ_OFF))
+
+#define cmap_to_glyph(cmap_idx) ((int) (cmap_idx)   + GLYPH_CMAP_OFF)
+#define explosion_to_glyph(expltype,idx)       \
+               ((((expltype) * MAXEXPCHARS) + ((idx) - S_explode1)) + GLYPH_EXPLODE_OFF)
+
+#define trap_to_glyph(trap)    \
+                       cmap_to_glyph(trap_to_defsym(what_trap((trap)->ttyp)))
+
+/* Not affected by hallucination.  Gives a generic body for CORPSE */
+#define objnum_to_glyph(onum)  ((int) (onum) + GLYPH_OBJ_OFF)
+#define monnum_to_glyph(mnum)  ((int) (mnum) + GLYPH_MON_OFF)
+#define detected_monnum_to_glyph(mnum) ((int) (mnum) + GLYPH_DETECT_OFF)
+#define ridden_monnum_to_glyph(mnum)   ((int) (mnum) + GLYPH_RIDDEN_OFF)
+#define petnum_to_glyph(mnum)  ((int) (mnum) + GLYPH_PET_OFF)
+
+/* The hero's glyph when seen as a monster.
+ */
+#define hero_glyph \
+       monnum_to_glyph((Upolyd || !iflags.showrace) ? u.umonnum : \
+                       (flags.female && urace.femalenum != NON_PM) ? urace.femalenum : \
+                       urace.malenum)
+
+
+/*
+ * Change the given glyph into it's given type.  Note:
+ *     1) Pets, detected, and ridden monsters are animals and are converted
+ *        to the proper monster number.
+ *     2) Bodies are all mapped into the generic CORPSE object
+ *     3) If handed a glyph out of range for the type, these functions
+ *        will return NO_GLYPH (see exception below)
+ *     4) glyph_to_swallow() does not return a showsyms[] index, but an
+ *        offset from the first swallow symbol.  If handed something
+ *        out of range, it will return zero (for lack of anything better
+ *        to return).
+ */
+#define glyph_to_mon(glyph)                                            \
+       (glyph_is_normal_monster(glyph) ? ((glyph)-GLYPH_MON_OFF) :     \
+       glyph_is_pet(glyph) ? ((glyph)-GLYPH_PET_OFF) :                 \
+       glyph_is_detected_monster(glyph) ? ((glyph)-GLYPH_DETECT_OFF) : \
+       glyph_is_ridden_monster(glyph) ? ((glyph)-GLYPH_RIDDEN_OFF) :   \
+       NO_GLYPH)
+#define glyph_to_obj(glyph)                                            \
+       (glyph_is_body(glyph) ? CORPSE :                                \
+       glyph_is_normal_object(glyph) ? ((glyph)-GLYPH_OBJ_OFF) :       \
+       NO_GLYPH)
+#define glyph_to_trap(glyph)                                           \
+       (glyph_is_trap(glyph) ?                                         \
+               ((int) defsym_to_trap((glyph) - GLYPH_CMAP_OFF)) :      \
+       NO_GLYPH)
+#define glyph_to_cmap(glyph)                                           \
+       (glyph_is_cmap(glyph) ? ((glyph) - GLYPH_CMAP_OFF) :            \
+       NO_GLYPH)
+#define glyph_to_swallow(glyph)                                                \
+       (glyph_is_swallow(glyph) ? (((glyph) - GLYPH_SWALLOW_OFF) & 0x7) : \
+       0)
+#define glyph_to_warning(glyph)                                                \
+       (glyph_is_warning(glyph) ? ((glyph) - GLYPH_WARNING_OFF) :      \
+       NO_GLYPH);
+
+/*
+ * Return true if the given glyph is what we want.  Note that bodies are
+ * considered objects.
+ */
+#define glyph_is_monster(glyph)                                                \
+               (glyph_is_normal_monster(glyph)                         \
+               || glyph_is_pet(glyph)                                  \
+               || glyph_is_ridden_monster(glyph)                       \
+               || glyph_is_detected_monster(glyph))
+#define glyph_is_normal_monster(glyph)                                 \
+    ((glyph) >= GLYPH_MON_OFF && (glyph) < (GLYPH_MON_OFF+NUMMONS))
+#define glyph_is_pet(glyph)                                            \
+    ((glyph) >= GLYPH_PET_OFF && (glyph) < (GLYPH_PET_OFF+NUMMONS))
+#define glyph_is_body(glyph)                                           \
+    ((glyph) >= GLYPH_BODY_OFF && (glyph) < (GLYPH_BODY_OFF+NUMMONS))
+#define glyph_is_ridden_monster(glyph)                                 \
+    ((glyph) >= GLYPH_RIDDEN_OFF && (glyph) < (GLYPH_RIDDEN_OFF+NUMMONS))
+#define glyph_is_detected_monster(glyph)                               \
+    ((glyph) >= GLYPH_DETECT_OFF && (glyph) < (GLYPH_DETECT_OFF+NUMMONS))
+#define glyph_is_invisible(glyph) ((glyph) == GLYPH_INVISIBLE)
+#define glyph_is_normal_object(glyph)                                  \
+    ((glyph) >= GLYPH_OBJ_OFF && (glyph) < (GLYPH_OBJ_OFF+NUM_OBJECTS))
+#define glyph_is_object(glyph)                                         \
+               (glyph_is_normal_object(glyph)                          \
+               || glyph_is_body(glyph))
+#define glyph_is_trap(glyph)                                           \
+    ((glyph) >= (GLYPH_CMAP_OFF+trap_to_defsym(1)) &&                  \
+     (glyph) < (GLYPH_CMAP_OFF+trap_to_defsym(1)+TRAPNUM))
+#define glyph_is_cmap(glyph)                                           \
+    ((glyph) >= GLYPH_CMAP_OFF && (glyph) < (GLYPH_CMAP_OFF+MAXPCHARS))
+#define glyph_is_swallow(glyph) \
+    ((glyph) >= GLYPH_SWALLOW_OFF && (glyph) < (GLYPH_SWALLOW_OFF+(NUMMONS << 3)))
+#define glyph_is_warning(glyph)        \
+    ((glyph) >= GLYPH_WARNING_OFF && (glyph) < (GLYPH_WARNING_OFF + WARNCOUNT))
+#endif /* DISPLAY_H */
diff --git a/include/dlb.h b/include/dlb.h
new file mode 100644 (file)
index 0000000..ca45809
--- /dev/null
@@ -0,0 +1,141 @@
+/*     SCCS Id: @(#)dlb.h      3.4     1997/07/29      */
+/* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef DLB_H
+#define DLB_H
+/* definitions for data library */
+
+#ifdef DLB
+
+/* implementations */
+#ifdef MAC
+# define DLBRSRC       /* use Mac resources */
+#else
+# define DLBLIB                /* use a set of external files */
+#endif
+
+#ifdef DLBLIB
+/* directory structure in memory */
+typedef struct dlb_directory {
+    char *fname;       /* file name as seen from calling code */
+    long foffset;      /* offset in lib file to start of this file */
+    long fsize;                /* file size */
+    char handling;     /* how to handle the file (compression, etc) */
+} libdir;
+
+/* information about each open library */
+typedef struct dlb_library {
+    FILE *fdata;       /* opened data file */
+    long fmark;                /* current file mark */
+    libdir *dir;       /* directory of library file */
+    char *sspace;      /* pointer to string space */
+    long nentries;     /* # of files in directory */
+    long rev;          /* dlb file revision */
+    long strsize;      /* dlb file string size */
+} library;
+
+/* library definitions */
+# ifndef DLBFILE
+#  define DLBFILE      "nhdat"                 /* name of library */
+# endif
+# ifndef FILENAME_CMP
+#  define FILENAME_CMP strcmp                  /* case sensitive */
+# endif
+
+#endif /* DLBLIB */
+
+
+typedef struct dlb_handle {
+    FILE *fp;          /* pointer to an external file, use if non-null */
+#ifdef DLBLIB
+    library *lib;      /* pointer to library structure */
+    long start;                /* offset of start of file */
+    long size;         /* size of file */
+    long mark;         /* current file marker */
+#endif
+#ifdef DLBRSRC
+    int fd;            /* HandleFile file descriptor */
+#endif
+} dlb;
+
+#if defined(ULTRIX_PROTO) && !defined(__STDC__)
+ /* buggy old Ultrix compiler wants this for the (*dlb_fread_proc)
+    and (*dlb_fgets_proc) prototypes in struct dlb_procs (dlb.c);
+    we'll use it in all the declarations for consistency */
+#define DLB_P struct dlb_handle *
+#else
+#define DLB_P dlb *
+#endif
+
+boolean NDECL(dlb_init);
+void NDECL(dlb_cleanup);
+
+dlb *FDECL(dlb_fopen, (const char *,const char *));
+int FDECL(dlb_fclose, (DLB_P));
+int FDECL(dlb_fread, (char *,int,int,DLB_P));
+int FDECL(dlb_fseek, (DLB_P,long,int));
+char *FDECL(dlb_fgets, (char *,int,DLB_P));
+int FDECL(dlb_fgetc, (DLB_P));
+long FDECL(dlb_ftell, (DLB_P));
+
+
+/* Resource DLB entry points */
+#ifdef DLBRSRC
+       boolean rsrc_dlb_init(void);
+       void rsrc_dlb_cleanup(void);
+       boolean rsrc_dlb_fopen(dlb *dp, const char *name, const char *mode);
+       int rsrc_dlb_fclose(dlb *dp);
+       int rsrc_dlb_fread(char *buf, int size, int quan, dlb *dp);
+       int rsrc_dlb_fseek(dlb *dp, long pos, int whence);
+       char *rsrc_dlb_fgets(char *buf, int len, dlb *dp);
+       int rsrc_dlb_fgetc(dlb *dp);
+       long rsrc_dlb_ftell(dlb *dp);
+#endif
+
+
+#else /* DLB */
+
+# define dlb FILE
+
+# define dlb_init()
+# define dlb_cleanup()
+
+# define dlb_fopen     fopen
+# define dlb_fclose    fclose
+# define dlb_fread     fread
+# define dlb_fseek     fseek
+# define dlb_fgets     fgets
+# define dlb_fgetc     fgetc
+# define dlb_ftell     ftell
+
+#endif /* DLB */
+
+
+/* various other I/O stuff we don't want to replicate everywhere */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+#ifndef SEEK_CUR
+# define SEEK_CUR 1
+#endif
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif
+
+#define RDTMODE "r"
+#if (defined(MSDOS) || defined(WIN32) || defined(TOS) || defined(OS2)) && defined(DLB)
+#define WRTMODE "w+b"
+#else
+#define WRTMODE "w+"
+#endif
+#if (defined(MICRO) && !defined(AMIGA)) || defined(THINK_C) || defined(__MWERKS__) || defined(WIN32)
+# define RDBMODE "rb"
+# define WRBMODE "w+b"
+#else
+# define RDBMODE "r"
+# define WRBMODE "w+"
+#endif
+
+#endif /* DLB_H */
diff --git a/include/dungeon.h b/include/dungeon.h
new file mode 100644 (file)
index 0000000..24ba413
--- /dev/null
@@ -0,0 +1,169 @@
+/*     SCCS Id: @(#)dungeon.h  3.4     1999/07/02      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef DUNGEON_H
+#define DUNGEON_H
+
+typedef struct d_flags {       /* dungeon/level type flags */
+       Bitfield(town, 1);      /* is this a town? (levels only) */
+       Bitfield(hellish, 1);   /* is this part of hell? */
+       Bitfield(maze_like, 1); /* is this a maze? */
+       Bitfield(rogue_like, 1); /* is this an old-fashioned presentation? */
+       Bitfield(align, 3);     /* dungeon alignment. */
+       Bitfield(unused, 1);    /* etc... */
+} d_flags;
+
+typedef struct d_level {       /* basic dungeon level element */
+       xchar   dnum;           /* dungeon number */
+       xchar   dlevel;         /* level number */
+} d_level;
+
+typedef struct s_level {       /* special dungeon level element */
+       struct  s_level *next;
+       d_level dlevel;         /* dungeon & level numbers */
+       char    proto[15];      /* name of prototype file (eg. "tower") */
+       char    boneid;         /* character to id level in bones files */
+       uchar   rndlevs;        /* no. of randomly available similar levels */
+       d_flags flags;          /* type flags */
+} s_level;
+
+typedef struct stairway {      /* basic stairway identifier */
+       xchar   sx, sy;         /* x / y location of the stair */
+       d_level tolev;          /* where does it go */
+       char    up;             /* what type of stairway (up/down) */
+} stairway;
+
+/* level region types */
+#define LR_DOWNSTAIR 0
+#define LR_UPSTAIR 1
+#define LR_PORTAL 2
+#define LR_BRANCH 3
+#define LR_TELE 4
+#define LR_UPTELE 5
+#define LR_DOWNTELE 6
+
+typedef struct dest_area {     /* non-stairway level change indentifier */
+       xchar   lx, ly;         /* "lower" left corner (near [0,0]) */
+       xchar   hx, hy;         /* "upper" right corner (near [COLNO,ROWNO]) */
+       xchar   nlx, nly;       /* outline of invalid area */
+       xchar   nhx, nhy;       /* opposite corner of invalid area */
+} dest_area;
+
+typedef struct dungeon {       /* basic dungeon identifier */
+       char    dname[24];      /* name of the dungeon (eg. "Hell") */
+       char    proto[15];      /* name of prototype file (eg. "tower") */
+       char    boneid;         /* character to id dungeon in bones files */
+       d_flags flags;          /* dungeon flags */
+       xchar   entry_lev;      /* entry level */
+       xchar   num_dunlevs;    /* number of levels in this dungeon */
+       xchar   dunlev_ureached; /* how deep you have been in this dungeon */
+       int     ledger_start,   /* the starting depth in "real" terms */
+               depth_start;    /* the starting depth in "logical" terms */
+} dungeon;
+
+/*
+ * A branch structure defines the connection between two dungeons.  They
+ * will be ordered by the dungeon number/level number of 'end1'.  Ties
+ * are resolved by 'end2'.  'Type' uses 'end1' arbitrarily as the primary
+ * point.
+ */
+typedef struct branch {
+    struct branch *next;       /* next in the branch chain */
+    int                  id;           /* branch identifier */
+    int                  type;         /* type of branch */
+    d_level      end1;         /* "primary" end point */
+    d_level      end2;         /* other end point */
+    boolean      end1_up;      /* does end1 go up? */
+} branch;
+
+/* branch types */
+#define BR_STAIR   0   /* "Regular" connection, 2 staircases. */
+#define BR_NO_END1 1   /* "Regular" connection.  However, no stair from  */
+                       /*      end1 to end2.  There is a stair from end2 */
+                       /*      to end1.                                  */
+#define BR_NO_END2 2   /* "Regular" connection.  However, no stair from  */
+                       /*      end2 to end1.  There is a stair from end1 */
+                       /*      to end2.                                  */
+#define BR_PORTAL  3   /* Connection by magic portals (traps) */
+
+
+/* A particular dungeon contains num_dunlevs d_levels with dlevel 1..
+ * num_dunlevs.  Ledger_start and depth_start are bases that are added
+ * to the dlevel of a particular d_level to get the effective ledger_no
+ * and depth for that d_level.
+ *
+ * Ledger_no is a bookkeeping number that gives a unique identifier for a
+ * particular d_level (for level.?? files, e.g.).
+ *
+ * Depth corresponds to the number of floors below the surface.
+ */
+#define Is_astralevel(x)       (on_level(x, &astral_level))
+#define Is_earthlevel(x)       (on_level(x, &earth_level))
+#define Is_waterlevel(x)       (on_level(x, &water_level))
+#define Is_firelevel(x)                (on_level(x, &fire_level))
+#define Is_airlevel(x)         (on_level(x, &air_level))
+#define Is_medusa_level(x)     (on_level(x, &medusa_level))
+#define Is_oracle_level(x)     (on_level(x, &oracle_level))
+#define Is_valley(x)           (on_level(x, &valley_level))
+#define Is_juiblex_level(x)    (on_level(x, &juiblex_level))
+#define Is_asmo_level(x)       (on_level(x, &asmodeus_level))
+#define Is_baal_level(x)       (on_level(x, &baalzebub_level))
+#define Is_wiz1_level(x)       (on_level(x, &wiz1_level))
+#define Is_wiz2_level(x)       (on_level(x, &wiz2_level))
+#define Is_wiz3_level(x)       (on_level(x, &wiz3_level))
+#define Is_sanctum(x)          (on_level(x, &sanctum_level))
+#define Is_portal_level(x)     (on_level(x, &portal_level))
+#define Is_rogue_level(x)      (on_level(x, &rogue_level))
+#define Is_stronghold(x)       (on_level(x, &stronghold_level))
+#define Is_bigroom(x)          (on_level(x, &bigroom_level))
+#define Is_qstart(x)           (on_level(x, &qstart_level))
+#define Is_qlocate(x)          (on_level(x, &qlocate_level))
+#define Is_nemesis(x)          (on_level(x, &nemesis_level))
+#define Is_knox(x)             (on_level(x, &knox_level))
+
+#define In_sokoban(x)          ((x)->dnum == sokoban_dnum)
+#define Inhell                 In_hell(&u.uz)  /* now gehennom */
+#define In_endgame(x)          ((x)->dnum == astral_level.dnum)
+
+#define within_bounded_area(X,Y,LX,LY,HX,HY) \
+               ((X) >= (LX) && (X) <= (HX) && (Y) >= (LY) && (Y) <= (HY))
+
+/* monster and object migration codes */
+
+#define MIGR_NOWHERE         (-1)      /* failure flag for down_gate() */
+#define MIGR_RANDOM            0
+#define MIGR_APPROX_XY         1       /* approximate coordinates */
+#define MIGR_EXACT_XY          2       /* specific coordinates */
+#define MIGR_STAIRS_UP         3
+#define MIGR_STAIRS_DOWN       4
+#define MIGR_LADDER_UP         5
+#define MIGR_LADDER_DOWN       6
+#define MIGR_SSTAIRS           7       /* dungeon branch */
+#define MIGR_PORTAL            8       /* magic portal */
+#define MIGR_NEAR_PLAYER       9       /* mon: followers; obj: trap door */
+
+/* level information (saved via ledger number) */
+
+struct linfo {
+       unsigned char   flags;
+#define VISITED                0x01    /* hero has visited this level */
+#define FORGOTTEN      0x02    /* hero will forget this level when reached */
+#define LFILE_EXISTS   0x04    /* a level file exists for this level */
+/*
+ * Note:  VISITED and LFILE_EXISTS are currently almost always set at the
+ * same time.  However they _mean_ different things.
+ */
+
+#ifdef MFLOPPY
+# define FROMPERM       1      /* for ramdisk use */
+# define TOPERM                 2      /* for ramdisk use */
+# define ACTIVE                 1
+# define SWAPPED        2
+       int     where;
+       long    time;
+       long    size;
+#endif /* MFLOPPY */
+};
+
+#endif /* DUNGEON_H */
diff --git a/include/edog.h b/include/edog.h
new file mode 100644 (file)
index 0000000..eadc5b3
--- /dev/null
@@ -0,0 +1,33 @@
+/*     SCCS Id: @(#)edog.h     3.4     1997/10/23      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef EDOG_H
+#define EDOG_H
+
+/*     various types of food, the lower, the better liked.     */
+
+#define DOGFOOD 0
+#define CADAVER 1
+#define ACCFOOD 2
+#define MANFOOD 3
+#define APPORT 4
+#define POISON 5
+#define UNDEF  6
+#define TABU   7
+
+struct edog {
+       long droptime;                  /* moment dog dropped object */
+       unsigned dropdist;              /* dist of drpped obj from @ */
+       int apport;                     /* amount of training */
+       long whistletime;               /* last time he whistled */
+       long hungrytime;                /* will get hungry at this time */
+       coord ogoal;                    /* previous goal location */
+       int abuse;                      /* track abuses to this pet */
+       int revivals;                   /* count pet deaths */
+       int mhpmax_penalty;             /* while starving, points reduced */
+       Bitfield(killed_by_u, 1);       /* you attempted to kill him */
+};
+#define EDOG(mon)      ((struct edog *)&(mon)->mextra[0])
+
+#endif /* EDOG_H */
diff --git a/include/emin.h b/include/emin.h
new file mode 100644 (file)
index 0000000..811bf23
--- /dev/null
@@ -0,0 +1,14 @@
+/*     SCCS Id: @(#)emin.h     3.4     1997/05/01      */
+/* Copyright (c) David Cohrs, 1990.                              */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef EMIN_H
+#define EMIN_H
+
+struct emin {
+       aligntyp min_align;     /* alignment of minion */
+};
+
+#define EMIN(mon)      ((struct emin *)&(mon)->mextra[0])
+
+#endif /* EMIN_H */
diff --git a/include/engrave.h b/include/engrave.h
new file mode 100644 (file)
index 0000000..02c5d9e
--- /dev/null
@@ -0,0 +1,27 @@
+/*     SCCS Id: @(#)engrave.h  3.4     1991/07/31      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef ENGRAVE_H
+#define ENGRAVE_H
+
+struct engr {
+       struct engr *nxt_engr;
+       char *engr_txt;
+       xchar engr_x, engr_y;
+       unsigned engr_lth;      /* for save & restore; not length of text */
+       long engr_time;         /* moment engraving was (will be) finished */
+       xchar engr_type;
+#define DUST      1
+#define ENGRAVE    2
+#define BURN      3
+#define MARK      4
+#define ENGR_BLOOD 5
+#define HEADSTONE  6
+#define N_ENGRAVE  6
+};
+
+#define newengr(lth) (struct engr *)alloc((unsigned)(lth) + sizeof(struct engr))
+#define dealloc_engr(engr) free((genericptr_t) (engr))
+
+#endif /* ENGRAVE_H */
diff --git a/include/epri.h b/include/epri.h
new file mode 100644 (file)
index 0000000..56b14ac
--- /dev/null
@@ -0,0 +1,24 @@
+/*     SCCS Id: @(#)epri.h     3.4     1997/05/01      */
+/* Copyright (c) Izchak Miller, 1989.                            */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef EPRI_H
+#define EPRI_H
+
+struct epri {
+       aligntyp shralign;      /* alignment of priest's shrine */
+                               /* leave as first field to match emin */
+       schar shroom;           /* index in rooms */
+       coord shrpos;           /* position of shrine */
+       d_level shrlevel;       /* level (& dungeon) of shrine */
+};
+
+#define EPRI(mon)      ((struct epri *)&(mon)->mextra[0])
+
+/* A priest without ispriest is a roaming priest without a shrine, so
+ * the fields (except shralign, which becomes only the priest alignment)
+ * are available for reuse.
+ */
+#define renegade shroom
+
+#endif /* EPRI_H */
diff --git a/include/eshk.h b/include/eshk.h
new file mode 100644 (file)
index 0000000..72a30e3
--- /dev/null
@@ -0,0 +1,45 @@
+/*     SCCS Id: @(#)eshk.h     3.4     1997/05/01      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef ESHK_H
+#define ESHK_H
+
+#define REPAIR_DELAY   5       /* minimum delay between shop damage & repair */
+
+#define BILLSZ 200
+
+struct bill_x {
+       unsigned bo_id;
+       boolean useup;
+       long price;             /* price per unit */
+       long bquan;             /* amount used up */
+};
+
+struct eshk {
+       long robbed;            /* amount stolen by most recent customer */
+       long credit;            /* amount credited to customer */
+       long debit;             /* amount of debt for using unpaid items */
+       long loan;              /* shop-gold picked (part of debit) */
+       int shoptype;           /* the value of rooms[shoproom].rtype */
+       schar shoproom;         /* index in rooms; set by inshop() */
+       schar unused;           /* to force alignment for stupid compilers */
+       boolean following;      /* following customer since he owes us sth */
+       boolean surcharge;      /* angry shk inflates prices */
+       coord shk;              /* usual position shopkeeper */
+       coord shd;              /* position shop door */
+       d_level shoplevel;      /* level (& dungeon) of his shop */
+       int billct;             /* no. of entries of bill[] in use */
+       struct bill_x bill[BILLSZ];
+       struct bill_x *bill_p;
+       int visitct;            /* nr of visits by most recent customer */
+       char customer[PL_NSIZ]; /* most recent customer */
+       char shknam[PL_NSIZ];
+};
+
+#define ESHK(mon)      ((struct eshk *)&(mon)->mextra[0])
+
+#define NOTANGRY(mon)  ((mon)->mpeaceful)
+#define ANGRY(mon)     (!NOTANGRY(mon))
+
+#endif /* ESHK_H */
diff --git a/include/extern.h b/include/extern.h
new file mode 100644 (file)
index 0000000..4e2314d
--- /dev/null
@@ -0,0 +1,2387 @@
+/*     SCCS Id: @(#)extern.h   3.4     2003/03/10      */
+/* Copyright (c) Steve Creps, 1988.                              */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef EXTERN_H
+#define EXTERN_H
+
+#define E extern
+
+/* ### alloc.c ### */
+
+#if 0
+E long *FDECL(alloc, (unsigned int));
+#endif
+E char *FDECL(fmt_ptr, (const genericptr,char *));
+
+/* This next pre-processor directive covers almost the entire file,
+ * interrupted only occasionally to pick up specific functions as needed. */
+#if !defined(MAKEDEFS_C) && !defined(LEV_LEX_C)
+
+/* ### allmain.c ### */
+
+E void NDECL(moveloop);
+E void NDECL(stop_occupation);
+E void NDECL(display_gamewindows);
+E void NDECL(newgame);
+E void FDECL(welcome, (BOOLEAN_P));
+
+/* ### apply.c ### */
+
+E int NDECL(doapply);
+E int NDECL(dorub);
+E int NDECL(dojump);
+E int FDECL(jump, (int));
+E int NDECL(number_leashed);
+E void FDECL(o_unleash, (struct obj *));
+E void FDECL(m_unleash, (struct monst *,BOOLEAN_P));
+E void NDECL(unleash_all);
+E boolean NDECL(next_to_u);
+E struct obj *FDECL(get_mleash, (struct monst *));
+E void FDECL(check_leash, (XCHAR_P,XCHAR_P));
+E boolean FDECL(um_dist, (XCHAR_P,XCHAR_P,XCHAR_P));
+E boolean FDECL(snuff_candle, (struct obj *));
+E boolean FDECL(snuff_lit, (struct obj *));
+E boolean FDECL(catch_lit, (struct obj *));
+E void FDECL(use_unicorn_horn, (struct obj *));
+E boolean FDECL(tinnable, (struct obj *));
+E void NDECL(reset_trapset);
+E void FDECL(fig_transform, (genericptr_t, long));
+E int FDECL(unfixable_trouble_count,(BOOLEAN_P));
+
+/* ### artifact.c ### */
+
+E void NDECL(init_artifacts);
+E void FDECL(save_artifacts, (int));
+E void FDECL(restore_artifacts, (int));
+E const char *FDECL(artiname, (int));
+E struct obj *FDECL(mk_artifact, (struct obj *,ALIGNTYP_P));
+E const char *FDECL(artifact_name, (const char *,short *));
+E boolean FDECL(exist_artifact, (int,const char *));
+E void FDECL(artifact_exists, (struct obj *,const char *,BOOLEAN_P));
+E int NDECL(nartifact_exist);
+E boolean FDECL(spec_ability, (struct obj *,unsigned long));
+E boolean FDECL(confers_luck, (struct obj *));
+E boolean FDECL(arti_reflects, (struct obj *));
+E boolean FDECL(restrict_name, (struct obj *,const char *));
+E boolean FDECL(defends, (int,struct obj *));
+E boolean FDECL(protects, (int,struct obj *));
+E void FDECL(set_artifact_intrinsic, (struct obj *,BOOLEAN_P,long));
+E int FDECL(touch_artifact, (struct obj *,struct monst *));
+E int FDECL(spec_abon, (struct obj *,struct monst *));
+E int FDECL(spec_dbon, (struct obj *,struct monst *,int));
+E void FDECL(discover_artifact, (XCHAR_P));
+E boolean FDECL(undiscovered_artifact, (XCHAR_P));
+E int FDECL(disp_artifact_discoveries, (winid));
+E boolean FDECL(artifact_hit, (struct monst *,struct monst *,
+                               struct obj *,int *,int));
+E int NDECL(doinvoke);
+E void FDECL(arti_speak, (struct obj *));
+E boolean FDECL(artifact_light, (struct obj *));
+E long FDECL(spec_m2, (struct obj *));
+E boolean FDECL(artifact_has_invprop, (struct obj *,UCHAR_P));
+E long FDECL(arti_cost, (struct obj *));
+
+/* ### attrib.c ### */
+
+E boolean FDECL(adjattrib, (int,int,int));
+E void FDECL(change_luck, (SCHAR_P));
+E int FDECL(stone_luck, (BOOLEAN_P));
+E void NDECL(set_moreluck);
+E void FDECL(gainstr, (struct obj *,int));
+E void FDECL(losestr, (int));
+E void NDECL(restore_attrib);
+E void FDECL(exercise, (int,BOOLEAN_P));
+E void NDECL(exerchk);
+E void NDECL(reset_attribute_clock);
+E void FDECL(init_attr, (int));
+E void NDECL(redist_attr);
+E void FDECL(adjabil, (int,int));
+E int NDECL(newhp);
+E schar FDECL(acurr, (int));
+E schar NDECL(acurrstr);
+E void FDECL(adjalign, (int));
+
+/* ### ball.c ### */
+
+E void NDECL(ballfall);
+E void NDECL(placebc);
+E void NDECL(unplacebc);
+E void FDECL(set_bc, (int));
+E void FDECL(move_bc, (int,int,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
+E boolean FDECL(drag_ball, (XCHAR_P,XCHAR_P,
+               int *,xchar *,xchar *,xchar *,xchar *, boolean *,BOOLEAN_P));
+E void FDECL(drop_ball, (XCHAR_P,XCHAR_P));
+E void NDECL(drag_down);
+
+/* ### bones.c ### */
+
+E boolean NDECL(can_make_bones);
+E void FDECL(savebones, (struct obj *));
+E int NDECL(getbones);
+
+/* ### botl.c ### */
+
+E int FDECL(xlev_to_rank, (int));
+E int FDECL(title_to_mon, (const char *,int *,int *));
+E void NDECL(max_rank_sz);
+#ifdef SCORE_ON_BOTL
+E long NDECL(botl_score);
+#endif
+E int FDECL(describe_level, (char *));
+E const char *FDECL(rank_of, (int,SHORT_P,BOOLEAN_P));
+E void NDECL(bot);
+
+/* ### cmd.c ### */
+
+#ifdef USE_TRAMPOLI
+E int NDECL(doextcmd);
+E int NDECL(domonability);
+E int NDECL(doprev_message);
+E int NDECL(timed_occupation);
+E int NDECL(wiz_attributes);
+E int NDECL(enter_explore_mode);
+# ifdef WIZARD
+E int NDECL(wiz_detect);
+E int NDECL(wiz_genesis);
+E int NDECL(wiz_identify);
+E int NDECL(wiz_level_tele);
+E int NDECL(wiz_map);
+E int NDECL(wiz_where);
+E int NDECL(wiz_wish);
+# endif /* WIZARD */
+#endif /* USE_TRAMPOLI */
+E void NDECL(reset_occupations);
+E void FDECL(set_occupation, (int (*)(void),const char *,int));
+#ifdef REDO
+E char NDECL(pgetchar);
+E void FDECL(pushch, (CHAR_P));
+E void FDECL(savech, (CHAR_P));
+#endif
+#ifdef WIZARD
+E void NDECL(add_debug_extended_commands);
+#endif /* WIZARD */
+E void FDECL(rhack, (char *));
+E int NDECL(doextlist);
+E int NDECL(extcmd_via_menu);
+E void FDECL(enlightenment, (int));
+E void FDECL(show_conduct, (int));
+E int FDECL(xytod, (SCHAR_P,SCHAR_P));
+E void FDECL(dtoxy, (coord *,int));
+E int FDECL(movecmd, (CHAR_P));
+E int FDECL(getdir, (const char *));
+E void NDECL(confdir);
+E int FDECL(isok, (int,int));
+E int FDECL(get_adjacent_loc, (const char *, const char *, XCHAR_P, XCHAR_P, coord *));
+E const char *FDECL(click_to_cmd, (int,int,int));
+E char NDECL(readchar);
+#ifdef WIZARD
+E void NDECL(sanity_check);
+#endif
+E char FDECL(yn_function, (const char *, const char *, CHAR_P));
+
+/* ### dbridge.c ### */
+
+E boolean FDECL(is_pool, (int,int));
+E boolean FDECL(is_lava, (int,int));
+E boolean FDECL(is_ice, (int,int));
+E int FDECL(is_drawbridge_wall, (int,int));
+E boolean FDECL(is_db_wall, (int,int));
+E boolean FDECL(find_drawbridge, (int *,int*));
+E boolean FDECL(create_drawbridge, (int,int,int,BOOLEAN_P));
+E void FDECL(open_drawbridge, (int,int));
+E void FDECL(close_drawbridge, (int,int));
+E void FDECL(destroy_drawbridge, (int,int));
+
+/* ### decl.c ### */
+
+E void NDECL(decl_init);
+
+/* ### detect.c ### */
+
+E struct obj *FDECL(o_in, (struct obj*,CHAR_P));
+E struct obj *FDECL(o_material, (struct obj*,unsigned));
+E int FDECL(gold_detect, (struct obj *));
+E int FDECL(food_detect, (struct obj *));
+E int FDECL(object_detect, (struct obj *,int));
+E int FDECL(monster_detect, (struct obj *,int));
+E int FDECL(trap_detect, (struct obj *));
+E const char *FDECL(level_distance, (d_level *));
+E void FDECL(use_crystal_ball, (struct obj *));
+E void NDECL(do_mapping);
+E void NDECL(do_vicinity_map);
+E void FDECL(cvt_sdoor_to_door, (struct rm *));
+#ifdef USE_TRAMPOLI
+E void FDECL(findone, (int,int,genericptr_t));
+E void FDECL(openone, (int,int,genericptr_t));
+#endif
+E int NDECL(findit);
+E int NDECL(openit);
+E void FDECL(find_trap, (struct trap *));
+E int FDECL(dosearch0, (int));
+E int NDECL(dosearch);
+E void NDECL(sokoban_detect);
+
+/* ### dig.c ### */
+
+E boolean NDECL(is_digging);
+#ifdef USE_TRAMPOLI
+E int NDECL(dig);
+#endif
+E int NDECL(holetime);
+E boolean FDECL(dig_check, (struct monst *, BOOLEAN_P, int, int));
+E void FDECL(digactualhole, (int,int,struct monst *,int));
+E boolean FDECL(dighole, (BOOLEAN_P));
+E int FDECL(use_pick_axe, (struct obj *));
+E int FDECL(use_pick_axe2, (struct obj *));
+E boolean FDECL(mdig_tunnel, (struct monst *));
+E void FDECL(watch_dig, (struct monst *,XCHAR_P,XCHAR_P,BOOLEAN_P));
+E void NDECL(zap_dig);
+E struct obj *FDECL(bury_an_obj, (struct obj *));
+E void FDECL(bury_objs, (int,int));
+E void FDECL(unearth_objs, (int,int));
+E void FDECL(rot_organic, (genericptr_t, long));
+E void FDECL(rot_corpse, (genericptr_t, long));
+#if 0
+E void FDECL(bury_monst, (struct monst *));
+E void NDECL(bury_you);
+E void NDECL(unearth_you);
+E void NDECL(escape_tomb);
+E void FDECL(bury_obj, (struct obj *));
+#endif
+
+/* ### display.c ### */
+
+#ifdef INVISIBLE_OBJECTS
+E struct obj * FDECL(vobj_at, (XCHAR_P,XCHAR_P));
+#endif /* INVISIBLE_OBJECTS */
+E void FDECL(magic_map_background, (XCHAR_P,XCHAR_P,int));
+E void FDECL(map_background, (XCHAR_P,XCHAR_P,int));
+E void FDECL(map_trap, (struct trap *,int));
+E void FDECL(map_object, (struct obj *,int));
+E void FDECL(map_invisible, (XCHAR_P,XCHAR_P));
+E void FDECL(unmap_object, (int,int));
+E void FDECL(map_location, (int,int,int));
+E void FDECL(feel_location, (XCHAR_P,XCHAR_P));
+E void FDECL(newsym, (int,int));
+E void FDECL(shieldeff, (XCHAR_P,XCHAR_P));
+E void FDECL(tmp_at, (int,int));
+E void FDECL(swallowed, (int));
+E void FDECL(under_ground, (int));
+E void FDECL(under_water, (int));
+E void NDECL(see_monsters);
+E void NDECL(set_mimic_blocking);
+E void NDECL(see_objects);
+E void NDECL(see_traps);
+E void NDECL(curs_on_u);
+E int NDECL(doredraw);
+E void NDECL(docrt);
+E void FDECL(show_glyph, (int,int,int));
+E void NDECL(clear_glyph_buffer);
+E void FDECL(row_refresh, (int,int,int));
+E void NDECL(cls);
+E void FDECL(flush_screen, (int));
+E int FDECL(back_to_glyph, (XCHAR_P,XCHAR_P));
+E int FDECL(zapdir_to_glyph, (int,int,int));
+E int FDECL(glyph_at, (XCHAR_P,XCHAR_P));
+E void NDECL(set_wall_state);
+
+/* ### do.c ### */
+
+#ifdef USE_TRAMPOLI
+E int FDECL(drop, (struct obj *));
+E int NDECL(wipeoff);
+#endif
+E int NDECL(dodrop);
+E boolean FDECL(boulder_hits_pool, (struct obj *,int,int,BOOLEAN_P));
+E boolean FDECL(flooreffects, (struct obj *,int,int,const char *));
+E void FDECL(doaltarobj, (struct obj *));
+E boolean FDECL(canletgo, (struct obj *,const char *));
+E void FDECL(dropx, (struct obj *));
+E void FDECL(dropy, (struct obj *));
+E void FDECL(obj_no_longer_held, (struct obj *));
+E int NDECL(doddrop);
+E int NDECL(dodown);
+E int NDECL(doup);
+#ifdef INSURANCE
+E void NDECL(save_currentstate);
+#endif
+E void FDECL(goto_level, (d_level *,BOOLEAN_P,BOOLEAN_P,BOOLEAN_P));
+E void FDECL(schedule_goto, (d_level *,BOOLEAN_P,BOOLEAN_P,int,
+                            const char *,const char *));
+E void NDECL(deferred_goto);
+E boolean FDECL(revive_corpse, (struct obj *));
+E void FDECL(revive_mon, (genericptr_t, long));
+E int NDECL(donull);
+E int NDECL(dowipe);
+E void FDECL(set_wounded_legs, (long,int));
+E void NDECL(heal_legs);
+
+/* ### do_name.c ### */
+
+E int FDECL(getpos, (coord *,BOOLEAN_P,const char *));
+E struct monst *FDECL(christen_monst, (struct monst *,const char *));
+E int NDECL(do_mname);
+E struct obj *FDECL(oname, (struct obj *,const char *));
+E int NDECL(ddocall);
+E void FDECL(docall, (struct obj *));
+E const char *NDECL(rndghostname);
+E char *FDECL(x_monnam, (struct monst *,int,const char *,int,BOOLEAN_P));
+E char *FDECL(l_monnam, (struct monst *));
+E char *FDECL(mon_nam, (struct monst *));
+E char *FDECL(noit_mon_nam, (struct monst *));
+E char *FDECL(Monnam, (struct monst *));
+E char *FDECL(noit_Monnam, (struct monst *));
+E char *FDECL(m_monnam, (struct monst *));
+E char *FDECL(y_monnam, (struct monst *));
+E char *FDECL(Adjmonnam, (struct monst *,const char *));
+E char *FDECL(Amonnam, (struct monst *));
+E char *FDECL(a_monnam, (struct monst *));
+E char *FDECL(distant_monnam, (struct monst *,int,char *));
+E const char *NDECL(rndmonnam);
+E const char *FDECL(hcolor, (const char *));
+E const char *NDECL(rndcolor);
+#ifdef REINCARNATION
+E const char *NDECL(roguename);
+#endif
+E struct obj *FDECL(realloc_obj,
+               (struct obj *, int, genericptr_t, int, const char *));
+E char *FDECL(coyotename, (struct monst *,char *));
+
+/* ### do_wear.c ### */
+
+#ifdef USE_TRAMPOLI
+E int NDECL(Armor_on);
+E int NDECL(Boots_on);
+E int NDECL(Gloves_on);
+E int NDECL(Helmet_on);
+E int FDECL(select_off, (struct obj *));
+E int NDECL(take_off);
+#endif
+E void FDECL(off_msg, (struct obj *));
+E void NDECL(set_wear);
+E boolean FDECL(donning, (struct obj *));
+E void NDECL(cancel_don);
+E int NDECL(Armor_off);
+E int NDECL(Armor_gone);
+E int NDECL(Helmet_off);
+E int NDECL(Gloves_off);
+E int NDECL(Boots_off);
+E int NDECL(Cloak_off);
+E int NDECL(Shield_off);
+#ifdef TOURIST
+E int NDECL(Shirt_off);
+#endif
+E void NDECL(Amulet_off);
+E void FDECL(Ring_on, (struct obj *));
+E void FDECL(Ring_off, (struct obj *));
+E void FDECL(Ring_gone, (struct obj *));
+E void FDECL(Blindf_on, (struct obj *));
+E void FDECL(Blindf_off, (struct obj *));
+E int NDECL(dotakeoff);
+E int NDECL(doremring);
+E int FDECL(cursed, (struct obj *));
+E int FDECL(armoroff, (struct obj *));
+E int FDECL(canwearobj, (struct obj *, long *, BOOLEAN_P));
+E int NDECL(dowear);
+E int NDECL(doputon);
+E void NDECL(find_ac);
+E void NDECL(glibr);
+E struct obj *FDECL(some_armor,(struct monst *));
+E void FDECL(erode_armor, (struct monst *,BOOLEAN_P));
+E struct obj *FDECL(stuck_ring, (struct obj *,int));
+E struct obj *NDECL(unchanger);
+E void NDECL(reset_remarm);
+E int NDECL(doddoremarm);
+E int FDECL(destroy_arm, (struct obj *));
+E void FDECL(adj_abon, (struct obj *,SCHAR_P));
+
+/* ### dog.c ### */
+
+E void FDECL(initedog, (struct monst *));
+E struct monst *FDECL(make_familiar, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P));
+E struct monst *NDECL(makedog);
+E void NDECL(update_mlstmv);
+E void NDECL(losedogs);
+E void FDECL(mon_arrive, (struct monst *,BOOLEAN_P));
+E void FDECL(mon_catchup_elapsed_time, (struct monst *,long));
+E void FDECL(keepdogs, (BOOLEAN_P));
+E void FDECL(migrate_to_level, (struct monst *,XCHAR_P,XCHAR_P,coord *));
+E int FDECL(dogfood, (struct monst *,struct obj *));
+E struct monst *FDECL(tamedog, (struct monst *,struct obj *));
+E void FDECL(abuse_dog, (struct monst *));
+E void FDECL(wary_dog, (struct monst *, BOOLEAN_P));
+
+/* ### dogmove.c ### */
+
+E int FDECL(dog_nutrition, (struct monst *,struct obj *));
+E int FDECL(dog_eat, (struct monst *,struct obj *,int,int,BOOLEAN_P));
+E int FDECL(dog_move, (struct monst *,int));
+#ifdef USE_TRAMPOLI
+E void FDECL(wantdoor, (int,int,genericptr_t));
+#endif
+
+/* ### dokick.c ### */
+
+E boolean FDECL(ghitm, (struct monst *,struct obj *));
+E void FDECL(container_impact_dmg, (struct obj *));
+E int NDECL(dokick);
+E boolean FDECL(ship_object, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P));
+E void NDECL(obj_delivery);
+E schar FDECL(down_gate, (XCHAR_P,XCHAR_P));
+E void FDECL(impact_drop, (struct obj *,XCHAR_P,XCHAR_P,XCHAR_P));
+
+/* ### dothrow.c ### */
+
+E int NDECL(dothrow);
+E int NDECL(dofire);
+E void FDECL(hitfloor, (struct obj *));
+E void FDECL(hurtle, (int,int,int,BOOLEAN_P));
+E void FDECL(mhurtle, (struct monst *,int,int,int));
+E void FDECL(throwit, (struct obj *,long,BOOLEAN_P));
+E int FDECL(omon_adj, (struct monst *,struct obj *,BOOLEAN_P));
+E int FDECL(thitmonst, (struct monst *,struct obj *));
+E int FDECL(hero_breaks, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P));
+E int FDECL(breaks, (struct obj *,XCHAR_P,XCHAR_P));
+E boolean FDECL(breaktest, (struct obj *));
+E boolean FDECL(walk_path, (coord *, coord *, boolean (*)(genericptr_t,int,int), genericptr_t));
+E boolean FDECL(hurtle_step, (genericptr_t, int, int));
+
+/* ### drawing.c ### */
+#endif /* !MAKEDEFS_C && !LEV_LEX_C */
+E int FDECL(def_char_to_objclass, (CHAR_P));
+E int FDECL(def_char_to_monclass, (CHAR_P));
+#if !defined(MAKEDEFS_C) && !defined(LEV_LEX_C)
+E void FDECL(assign_graphics, (uchar *,int,int,int));
+E void FDECL(switch_graphics, (int));
+#ifdef REINCARNATION
+E void FDECL(assign_rogue_graphics, (BOOLEAN_P));
+#endif
+
+/* ### dungeon.c ### */
+
+E void FDECL(save_dungeon, (int,BOOLEAN_P,BOOLEAN_P));
+E void FDECL(restore_dungeon, (int));
+E void FDECL(insert_branch, (branch *,BOOLEAN_P));
+E void NDECL(init_dungeons);
+E s_level *FDECL(find_level, (const char *));
+E s_level *FDECL(Is_special, (d_level *));
+E branch *FDECL(Is_branchlev, (d_level *));
+E xchar FDECL(ledger_no, (d_level *));
+E xchar NDECL(maxledgerno);
+E schar FDECL(depth, (d_level *));
+E xchar FDECL(dunlev, (d_level *));
+E xchar FDECL(dunlevs_in_dungeon, (d_level *));
+E xchar FDECL(ledger_to_dnum, (XCHAR_P));
+E xchar FDECL(ledger_to_dlev, (XCHAR_P));
+E xchar FDECL(deepest_lev_reached, (BOOLEAN_P));
+E boolean FDECL(on_level, (d_level *,d_level *));
+E void FDECL(next_level, (BOOLEAN_P));
+E void FDECL(prev_level, (BOOLEAN_P));
+E void FDECL(u_on_newpos, (int,int));
+E void NDECL(u_on_sstairs);
+E void NDECL(u_on_upstairs);
+E void NDECL(u_on_dnstairs);
+E boolean FDECL(On_stairs, (XCHAR_P,XCHAR_P));
+E void FDECL(get_level, (d_level *,int));
+E boolean FDECL(Is_botlevel, (d_level *));
+E boolean FDECL(Can_fall_thru, (d_level *));
+E boolean FDECL(Can_dig_down, (d_level *));
+E boolean FDECL(Can_rise_up, (int,int,d_level *));
+E boolean FDECL(In_quest, (d_level *));
+E boolean FDECL(In_mines, (d_level *));
+E branch *FDECL(dungeon_branch, (const char *));
+E boolean FDECL(at_dgn_entrance, (const char *));
+E boolean FDECL(In_hell, (d_level *));
+E boolean FDECL(In_V_tower, (d_level *));
+E boolean FDECL(On_W_tower_level, (d_level *));
+E boolean FDECL(In_W_tower, (int,int,d_level *));
+E void FDECL(find_hell, (d_level *));
+E void FDECL(goto_hell, (BOOLEAN_P,BOOLEAN_P));
+E void FDECL(assign_level, (d_level *,d_level *));
+E void FDECL(assign_rnd_level, (d_level *,d_level *,int));
+E int FDECL(induced_align, (int));
+E boolean FDECL(Invocation_lev, (d_level *));
+E xchar NDECL(level_difficulty);
+E schar FDECL(lev_by_name, (const char *));
+#ifdef WIZARD
+E schar FDECL(print_dungeon, (BOOLEAN_P,schar *,xchar *));
+#endif
+
+/* ### eat.c ### */
+
+#ifdef USE_TRAMPOLI
+E int NDECL(eatmdone);
+E int NDECL(eatfood);
+E int NDECL(opentin);
+E int NDECL(unfaint);
+#endif
+E boolean FDECL(is_edible, (struct obj *));
+E void NDECL(init_uhunger);
+E int NDECL(Hear_again);
+E void NDECL(reset_eat);
+E int NDECL(doeat);
+E void NDECL(gethungry);
+E void FDECL(morehungry, (int));
+E void FDECL(lesshungry, (int));
+E boolean NDECL(is_fainted);
+E void NDECL(reset_faint);
+E void NDECL(violated_vegetarian);
+#if 0
+E void NDECL(sync_hunger);
+#endif
+E void FDECL(newuhs, (BOOLEAN_P));
+E struct obj *FDECL(floorfood, (const char *,int));
+E void NDECL(vomit);
+E int FDECL(eaten_stat, (int,struct obj *));
+E void FDECL(food_disappears, (struct obj *));
+E void FDECL(food_substitution, (struct obj *,struct obj *));
+E void NDECL(fix_petrification);
+E void FDECL(consume_oeaten, (struct obj *,int));
+E boolean FDECL(maybe_finished_meal, (BOOLEAN_P));
+
+/* ### end.c ### */
+
+E void FDECL(done1, (int));
+E int NDECL(done2);
+#ifdef USE_TRAMPOLI
+E void FDECL(done_intr, (int));
+#endif
+E void FDECL(done_in_by, (struct monst *));
+#endif /* !MAKEDEFS_C && !LEV_LEX_C */
+E void VDECL(panic, (const char *,...)) PRINTF_F(1,2);
+#if !defined(MAKEDEFS_C) && !defined(LEV_LEX_C)
+E void FDECL(done, (int));
+E void FDECL(container_contents, (struct obj *,BOOLEAN_P,BOOLEAN_P));
+E void FDECL(terminate, (int));
+E int NDECL(num_genocides);
+
+/* ### engrave.c ### */
+
+E char *FDECL(random_engraving, (char *));
+E void FDECL(wipeout_text, (char *,int,unsigned));
+E boolean NDECL(can_reach_floor);
+E const char *FDECL(surface, (int,int));
+E const char *FDECL(ceiling, (int,int));
+E struct engr *FDECL(engr_at, (XCHAR_P,XCHAR_P));
+#ifdef ELBERETH
+E int FDECL(sengr_at, (const char *,XCHAR_P,XCHAR_P));
+#endif
+E void FDECL(u_wipe_engr, (int));
+E void FDECL(wipe_engr_at, (XCHAR_P,XCHAR_P,XCHAR_P));
+E void FDECL(read_engr_at, (int,int));
+E void FDECL(make_engr_at, (int,int,const char *,long,XCHAR_P));
+E void FDECL(del_engr_at, (int,int));
+E int NDECL(freehand);
+E int NDECL(doengrave);
+E void FDECL(save_engravings, (int,int));
+E void FDECL(rest_engravings, (int));
+E void FDECL(del_engr, (struct engr *));
+E void FDECL(rloc_engr, (struct engr *));
+E void FDECL(make_grave, (int,int,const char *));
+
+/* ### exper.c ### */
+
+E int FDECL(experience, (struct monst *,int));
+E void FDECL(more_experienced, (int,int));
+E void FDECL(losexp, (const char *));
+E void NDECL(newexplevel);
+E void FDECL(pluslvl, (BOOLEAN_P));
+E long FDECL(rndexp, (BOOLEAN_P));
+
+/* ### explode.c ### */
+
+E void FDECL(explode, (int,int,int,int,CHAR_P,int));
+E long FDECL(scatter, (int, int, int, unsigned int, struct obj *));
+E void FDECL(splatter_burning_oil, (int, int));
+
+/* ### extralev.c ### */
+
+#ifdef REINCARNATION
+E void NDECL(makeroguerooms);
+E void FDECL(corr, (int,int));
+E void NDECL(makerogueghost);
+#endif
+
+/* ### files.c ### */
+
+E char *FDECL(fname_encode, (const char *, CHAR_P, char *, char *, int));
+E char *FDECL(fname_decode, (CHAR_P, char *, char *, int));
+E const char *FDECL(fqname, (const char *, int, int));
+E FILE *FDECL(fopen_datafile, (const char *,const char *,int));
+E boolean FDECL(uptodate, (int,const char *));
+E void FDECL(store_version, (int));
+#ifdef MFLOPPY
+E void NDECL(set_lock_and_bones);
+#endif
+E void FDECL(set_levelfile_name, (char *,int));
+E int FDECL(create_levelfile, (int,char *));
+E int FDECL(open_levelfile, (int,char *));
+E void FDECL(delete_levelfile, (int));
+E void NDECL(clearlocks);
+E int FDECL(create_bonesfile, (d_level*,char **, char *));
+#ifdef MFLOPPY
+E void NDECL(cancel_bonesfile);
+#endif
+E void FDECL(commit_bonesfile, (d_level *));
+E int FDECL(open_bonesfile, (d_level*,char **));
+E int FDECL(delete_bonesfile, (d_level*));
+E void NDECL(compress_bonesfile);
+E void NDECL(set_savefile_name);
+#ifdef INSURANCE
+E void FDECL(save_savefile_name, (int));
+#endif
+#if defined(WIZARD) && !defined(MICRO)
+E void NDECL(set_error_savefile);
+#endif
+E int NDECL(create_savefile);
+E int NDECL(open_savefile);
+E int NDECL(delete_savefile);
+E int NDECL(restore_saved_game);
+E void FDECL(compress, (const char *));
+E void FDECL(uncompress, (const char *));
+E boolean FDECL(lock_file, (const char *,int,int));
+E void FDECL(unlock_file, (const char *));
+#ifdef USER_SOUNDS
+E boolean FDECL(can_read_file, (const char *));
+#endif
+E void FDECL(read_config_file, (const char *));
+E void FDECL(check_recordfile, (const char *));
+#if defined(WIZARD)
+E void NDECL(read_wizkit);
+#endif
+E void FDECL(paniclog, (const char *, const char *));
+E int FDECL(validate_prefix_locations, (char *));
+E char** NDECL(get_saved_games);
+E void FDECL(free_saved_games, (char**));
+#ifdef SELF_RECOVER
+E boolean NDECL(recover_savefile);
+#endif
+#ifdef HOLD_LOCKFILE_OPEN
+E void NDECL(really_close);
+#endif
+
+/* ### fountain.c ### */
+
+E void FDECL(floating_above, (const char *));
+E void FDECL(dogushforth, (int));
+# ifdef USE_TRAMPOLI
+E void FDECL(gush, (int,int,genericptr_t));
+# endif
+E void FDECL(dryup, (XCHAR_P,XCHAR_P, BOOLEAN_P));
+E void NDECL(drinkfountain);
+E void FDECL(dipfountain, (struct obj *));
+#ifdef SINKS
+E void FDECL(breaksink, (int,int));
+E void NDECL(drinksink);
+#endif
+
+/* ### hack.c ### */
+
+E boolean FDECL(revive_nasty, (int,int,const char*));
+E void FDECL(movobj, (struct obj *,XCHAR_P,XCHAR_P));
+E boolean FDECL(may_dig, (XCHAR_P,XCHAR_P));
+E boolean FDECL(may_passwall, (XCHAR_P,XCHAR_P));
+E boolean FDECL(bad_rock, (struct permonst *,XCHAR_P,XCHAR_P));
+E boolean FDECL(invocation_pos, (XCHAR_P,XCHAR_P));
+E boolean FDECL(test_move, (int, int, int, int, int));
+E void NDECL(domove);
+E void NDECL(invocation_message);
+E void FDECL(spoteffects, (BOOLEAN_P));
+E char *FDECL(in_rooms, (XCHAR_P,XCHAR_P,int));
+E boolean FDECL(in_town, (int,int));
+E void FDECL(check_special_room, (BOOLEAN_P));
+E int NDECL(dopickup);
+E void NDECL(lookaround);
+E int NDECL(monster_nearby);
+E void FDECL(nomul, (int));
+E void FDECL(unmul, (const char *));
+E void FDECL(losehp, (int,const char *,BOOLEAN_P));
+E int NDECL(weight_cap);
+E int NDECL(inv_weight);
+E int NDECL(near_capacity);
+E int FDECL(calc_capacity, (int));
+E int NDECL(max_capacity);
+E boolean FDECL(check_capacity, (const char *));
+E int NDECL(inv_cnt);
+#ifdef GOLDOBJ
+E long FDECL(money_cnt, (struct obj *));
+#endif
+
+/* ### hacklib.c ### */
+
+E boolean FDECL(digit, (CHAR_P));
+E boolean FDECL(letter, (CHAR_P));
+E char FDECL(highc, (CHAR_P));
+E char FDECL(lowc, (CHAR_P));
+E char *FDECL(lcase, (char *));
+E char *FDECL(upstart, (char *));
+E char *FDECL(mungspaces, (char *));
+E char *FDECL(eos, (char *));
+E char *FDECL(strkitten, (char *,CHAR_P));
+E char *FDECL(s_suffix, (const char *));
+E char *FDECL(xcrypt, (const char *,char *));
+E boolean FDECL(onlyspace, (const char *));
+E char *FDECL(tabexpand, (char *));
+E char *FDECL(visctrl, (CHAR_P));
+E const char *FDECL(ordin, (int));
+E char *FDECL(sitoa, (int));
+E int FDECL(sgn, (int));
+E int FDECL(rounddiv, (long,int));
+E int FDECL(dist2, (int,int,int,int));
+E int FDECL(distmin, (int,int,int,int));
+E boolean FDECL(online2, (int,int,int,int));
+E boolean FDECL(pmatch, (const char *,const char *));
+#ifndef STRNCMPI
+E int FDECL(strncmpi, (const char *,const char *,int));
+#endif
+#ifndef STRSTRI
+E char *FDECL(strstri, (const char *,const char *));
+#endif
+E boolean FDECL(fuzzymatch, (const char *,const char *,const char *,BOOLEAN_P));
+E void NDECL(setrandom);
+E int NDECL(getyear);
+#if 0
+E char *FDECL(yymmdd, (time_t));
+#endif
+E long FDECL(yyyymmdd, (time_t));
+E int NDECL(phase_of_the_moon);
+E boolean NDECL(friday_13th);
+E int NDECL(night);
+E int NDECL(midnight);
+
+/* ### invent.c ### */
+
+E void FDECL(assigninvlet, (struct obj *));
+E struct obj *FDECL(merge_choice, (struct obj *,struct obj *));
+E int FDECL(merged, (struct obj **,struct obj **));
+#ifdef USE_TRAMPOLI
+E int FDECL(ckunpaid, (struct obj *));
+#endif
+E void FDECL(addinv_core1, (struct obj *));
+E void FDECL(addinv_core2, (struct obj *));
+E struct obj *FDECL(addinv, (struct obj *));
+E struct obj *FDECL(hold_another_object,
+                       (struct obj *,const char *,const char *,const char *));
+E void FDECL(useupall, (struct obj *));
+E void FDECL(useup, (struct obj *));
+E void FDECL(consume_obj_charge, (struct obj *,BOOLEAN_P));
+E void FDECL(freeinv_core, (struct obj *));
+E void FDECL(freeinv, (struct obj *));
+E void FDECL(delallobj, (int,int));
+E void FDECL(delobj, (struct obj *));
+E struct obj *FDECL(sobj_at, (int,int,int));
+E struct obj *FDECL(carrying, (int));
+E boolean NDECL(have_lizard);
+E struct obj *FDECL(o_on, (unsigned int,struct obj *));
+E boolean FDECL(obj_here, (struct obj *,int,int));
+E boolean NDECL(wearing_armor);
+E boolean FDECL(is_worn, (struct obj *));
+E struct obj *FDECL(g_at, (int,int));
+E struct obj *FDECL(mkgoldobj, (long));
+E struct obj *FDECL(getobj, (const char *,const char *));
+E int FDECL(ggetobj, (const char *,int (*)(OBJ_P),int,BOOLEAN_P,unsigned *));
+E void FDECL(fully_identify_obj, (struct obj *));
+E int FDECL(identify, (struct obj *));
+E void FDECL(identify_pack, (int));
+E int FDECL(askchain, (struct obj **,const char *,int,int (*)(OBJ_P),
+                       int (*)(OBJ_P),int,const char *));
+E void FDECL(prinv, (const char *,struct obj *,long));
+E char *FDECL(xprname, (struct obj *,const char *,CHAR_P,BOOLEAN_P,long,long));
+E int NDECL(ddoinv);
+E char FDECL(display_inventory, (const char *,BOOLEAN_P));
+E int FDECL(display_binventory, (int,int,BOOLEAN_P));
+E struct obj *FDECL(display_cinventory,(struct obj *));
+E struct obj *FDECL(display_minventory,(struct monst *,int,char *));
+E int NDECL(dotypeinv);
+E const char *FDECL(dfeature_at, (int,int,char *));
+E int FDECL(look_here, (int,BOOLEAN_P));
+E int NDECL(dolook);
+E boolean FDECL(will_feel_cockatrice, (struct obj *,BOOLEAN_P));
+E void FDECL(feel_cockatrice, (struct obj *,BOOLEAN_P));
+E void FDECL(stackobj, (struct obj *));
+E int NDECL(doprgold);
+E int NDECL(doprwep);
+E int NDECL(doprarm);
+E int NDECL(doprring);
+E int NDECL(dopramulet);
+E int NDECL(doprtool);
+E int NDECL(doprinuse);
+E void FDECL(useupf, (struct obj *,long));
+E char *FDECL(let_to_name, (CHAR_P,BOOLEAN_P));
+E void NDECL(free_invbuf);
+E void NDECL(reassign);
+E int NDECL(doorganize);
+E int FDECL(count_unpaid, (struct obj *));
+E int FDECL(count_buc, (struct obj *,int));
+E void FDECL(carry_obj_effects, (struct obj *));
+E const char *FDECL(currency, (long));
+E void FDECL(silly_thing, (const char *,struct obj *));
+
+/* ### ioctl.c ### */
+
+#if defined(UNIX) || defined(__BEOS__)
+E void NDECL(getwindowsz);
+E void NDECL(getioctls);
+E void NDECL(setioctls);
+# ifdef SUSPEND
+E int NDECL(dosuspend);
+# endif /* SUSPEND */
+#endif /* UNIX || __BEOS__ */
+
+/* ### light.c ### */
+
+E void FDECL(new_light_source, (XCHAR_P, XCHAR_P, int, int, genericptr_t));
+E void FDECL(del_light_source, (int, genericptr_t));
+E void FDECL(do_light_sources, (char **));
+E struct monst *FDECL(find_mid, (unsigned, unsigned));
+E void FDECL(save_light_sources, (int, int, int));
+E void FDECL(restore_light_sources, (int));
+E void FDECL(relink_light_sources, (BOOLEAN_P));
+E void FDECL(obj_move_light_source, (struct obj *, struct obj *));
+E boolean NDECL(any_light_source);
+E void FDECL(snuff_light_source, (int, int));
+E boolean FDECL(obj_sheds_light, (struct obj *));
+E boolean FDECL(obj_is_burning, (struct obj *));
+E void FDECL(obj_split_light_source, (struct obj *, struct obj *));
+E void FDECL(obj_merge_light_sources, (struct obj *,struct obj *));
+E int FDECL(candle_light_range, (struct obj *));
+#ifdef WIZARD
+E int NDECL(wiz_light_sources);
+#endif
+
+/* ### lock.c ### */
+
+#ifdef USE_TRAMPOLI
+E int NDECL(forcelock);
+E int NDECL(picklock);
+#endif
+E boolean FDECL(picking_lock, (int *,int *));
+E boolean FDECL(picking_at, (int,int));
+E void NDECL(reset_pick);
+E int FDECL(pick_lock, (struct obj *));
+E int NDECL(doforce);
+E boolean FDECL(boxlock, (struct obj *,struct obj *));
+E boolean FDECL(doorlock, (struct obj *,int,int));
+E int NDECL(doopen);
+E int NDECL(doclose);
+
+#ifdef MAC
+/* These declarations are here because the main code calls them. */
+
+/* ### macfile.c ### */
+
+E int FDECL(maccreat, (const char *,long));
+E int FDECL(macopen, (const char *,int,long));
+E int FDECL(macclose, (int));
+E int FDECL(macread, (int,void *,unsigned));
+E int FDECL(macwrite, (int,void *,unsigned));
+E long FDECL(macseek, (int,long,short));
+E int FDECL(macunlink, (const char *));
+
+/* ### macsnd.c ### */
+
+E void FDECL(mac_speaker, (struct obj *,char *));
+
+/* ### macunix.c ### */
+
+E void FDECL(regularize, (char *));
+E void NDECL(getlock);
+
+/* ### macwin.c ### */
+
+E void FDECL(lock_mouse_cursor, (Boolean));
+E int NDECL(SanePositions);
+
+/* ### mttymain.c ### */
+
+E void FDECL(getreturn, (char *));
+E void VDECL(msmsg, (const char *,...));
+E void NDECL(gettty);
+E void NDECL(setftty);
+E void FDECL(settty, (const char *));
+E int NDECL(tgetch);
+E void FDECL(cmov, (int x, int y));
+E void FDECL(nocmov, (int x, int y));
+
+#endif /* MAC */
+
+/* ### mail.c ### */
+
+#ifdef MAIL
+# ifdef UNIX
+E void NDECL(getmailstatus);
+# endif
+E void NDECL(ckmailstatus);
+E void FDECL(readmail, (struct obj *));
+#endif /* MAIL */
+
+/* ### makemon.c ### */
+
+E boolean FDECL(is_home_elemental, (struct permonst *));
+E struct monst *FDECL(clone_mon, (struct monst *,XCHAR_P,XCHAR_P));
+E struct monst *FDECL(makemon, (struct permonst *,int,int,int));
+E boolean FDECL(create_critters, (int,struct permonst *));
+E struct permonst *NDECL(rndmonst);
+E void FDECL(reset_rndmonst, (int));
+E struct permonst *FDECL(mkclass, (CHAR_P,int));
+E int FDECL(adj_lev, (struct permonst *));
+E struct permonst *FDECL(grow_up, (struct monst *,struct monst *));
+E int FDECL(mongets, (struct monst *,int));
+E int FDECL(golemhp, (int));
+E boolean FDECL(peace_minded, (struct permonst *));
+E void FDECL(set_malign, (struct monst *));
+E void FDECL(set_mimic_sym, (struct monst *));
+E int FDECL(mbirth_limit, (int));
+E void FDECL(mimic_hit_msg, (struct monst *, SHORT_P));
+#ifdef GOLDOBJ
+E void FDECL(mkmonmoney, (struct monst *, long));
+#endif
+E void FDECL(bagotricks, (struct obj *));
+E boolean FDECL(propagate, (int, BOOLEAN_P,BOOLEAN_P));
+
+/* ### mapglyph.c ### */
+
+E void FDECL(mapglyph, (int, int *, int *, unsigned *, int, int));
+
+/* ### mcastu.c ### */
+
+E int FDECL(castmu, (struct monst *,struct attack *,BOOLEAN_P,BOOLEAN_P));
+E int FDECL(buzzmu, (struct monst *,struct attack *));
+
+/* ### mhitm.c ### */
+
+E int FDECL(fightm, (struct monst *));
+E int FDECL(mattackm, (struct monst *,struct monst *));
+E int FDECL(noattacks, (struct permonst *));
+E int FDECL(sleep_monst, (struct monst *,int,int));
+E void FDECL(slept_monst, (struct monst *));
+E long FDECL(attk_protection, (int));
+
+/* ### mhitu.c ### */
+
+E const char *FDECL(mpoisons_subj, (struct monst *,struct attack *));
+E void NDECL(u_slow_down);
+E struct monst *NDECL(cloneu);
+E void FDECL(expels, (struct monst *,struct permonst *,BOOLEAN_P));
+E struct attack *FDECL(getmattk, (struct permonst *,int,int *,struct attack *));
+E int FDECL(mattacku, (struct monst *));
+E int FDECL(magic_negation, (struct monst *));
+E int FDECL(gazemu, (struct monst *,struct attack *));
+E void FDECL(mdamageu, (struct monst *,int));
+E int FDECL(could_seduce, (struct monst *,struct monst *,struct attack *));
+#ifdef SEDUCE
+E int FDECL(doseduce, (struct monst *));
+#endif
+
+/* ### minion.c ### */
+
+E void FDECL(msummon, (struct monst *));
+E void FDECL(summon_minion, (ALIGNTYP_P,BOOLEAN_P));
+E int FDECL(demon_talk, (struct monst *));
+E long FDECL(bribe, (struct monst *));
+E int FDECL(dprince, (ALIGNTYP_P));
+E int FDECL(dlord, (ALIGNTYP_P));
+E int NDECL(llord);
+E int FDECL(ndemon, (ALIGNTYP_P));
+E int NDECL(lminion);
+
+/* ### mklev.c ### */
+
+#ifdef USE_TRAMPOLI
+E int FDECL(do_comp, (genericptr_t,genericptr_t));
+#endif
+E void NDECL(sort_rooms);
+E void FDECL(add_room, (int,int,int,int,BOOLEAN_P,SCHAR_P,BOOLEAN_P));
+E void FDECL(add_subroom, (struct mkroom *,int,int,int,int,
+                          BOOLEAN_P,SCHAR_P,BOOLEAN_P));
+E void NDECL(makecorridors);
+E void FDECL(add_door, (int,int,struct mkroom *));
+E void NDECL(mklev);
+#ifdef SPECIALIZATION
+E void FDECL(topologize, (struct mkroom *,BOOLEAN_P));
+#else
+E void FDECL(topologize, (struct mkroom *));
+#endif
+E void FDECL(place_branch, (branch *,XCHAR_P,XCHAR_P));
+E boolean FDECL(occupied, (XCHAR_P,XCHAR_P));
+E int FDECL(okdoor, (XCHAR_P,XCHAR_P));
+E void FDECL(dodoor, (int,int,struct mkroom *));
+E void FDECL(mktrap, (int,int,struct mkroom *,coord*));
+E void FDECL(mkstairs, (XCHAR_P,XCHAR_P,CHAR_P,struct mkroom *));
+E void NDECL(mkinvokearea);
+
+/* ### mkmap.c ### */
+
+void FDECL(flood_fill_rm, (int,int,int,BOOLEAN_P,BOOLEAN_P));
+void FDECL(remove_rooms, (int,int,int,int));
+
+/* ### mkmaze.c ### */
+
+E void FDECL(wallification, (int,int,int,int));
+E void FDECL(walkfrom, (int,int));
+E void FDECL(makemaz, (const char *));
+E void FDECL(mazexy, (coord *));
+E void NDECL(bound_digging);
+E void FDECL(mkportal, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
+E boolean FDECL(bad_location, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
+E void FDECL(place_lregion, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,
+                            XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,
+                            XCHAR_P,d_level *));
+E void NDECL(movebubbles);
+E void NDECL(water_friction);
+E void FDECL(save_waterlevel, (int,int));
+E void FDECL(restore_waterlevel, (int));
+E const char *FDECL(waterbody_name, (XCHAR_P,XCHAR_P));
+
+/* ### mkobj.c ### */
+
+E struct obj *FDECL(mkobj_at, (CHAR_P,int,int,BOOLEAN_P));
+E struct obj *FDECL(mksobj_at, (int,int,int,BOOLEAN_P,BOOLEAN_P));
+E struct obj *FDECL(mkobj, (CHAR_P,BOOLEAN_P));
+E int NDECL(rndmonnum);
+E struct obj *FDECL(splitobj, (struct obj *,long));
+E void FDECL(replace_object, (struct obj *,struct obj *));
+E void FDECL(bill_dummy_object, (struct obj *));
+E struct obj *FDECL(mksobj, (int,BOOLEAN_P,BOOLEAN_P));
+E int FDECL(bcsign, (struct obj *));
+E int FDECL(weight, (struct obj *));
+E struct obj *FDECL(mkgold, (long,int,int));
+E struct obj *FDECL(mkcorpstat,
+               (int,struct monst *,struct permonst *,int,int,BOOLEAN_P));
+E struct obj *FDECL(obj_attach_mid, (struct obj *, unsigned));
+E struct monst *FDECL(get_mtraits, (struct obj *, BOOLEAN_P));
+E struct obj *FDECL(mk_tt_object, (int,int,int));
+E struct obj *FDECL(mk_named_object,
+                       (int,struct permonst *,int,int,const char *));
+E struct obj *FDECL(rnd_treefruit_at, (int, int));
+E void FDECL(start_corpse_timeout, (struct obj *));
+E void FDECL(bless, (struct obj *));
+E void FDECL(unbless, (struct obj *));
+E void FDECL(curse, (struct obj *));
+E void FDECL(uncurse, (struct obj *));
+E void FDECL(blessorcurse, (struct obj *,int));
+E boolean FDECL(is_flammable, (struct obj *));
+E boolean FDECL(is_rottable, (struct obj *));
+E void FDECL(place_object, (struct obj *,int,int));
+E void FDECL(remove_object, (struct obj *));
+E void FDECL(discard_minvent, (struct monst *));
+E void FDECL(obj_extract_self, (struct obj *));
+E void FDECL(extract_nobj, (struct obj *, struct obj **));
+E void FDECL(extract_nexthere, (struct obj *, struct obj **));
+E int FDECL(add_to_minv, (struct monst *, struct obj *));
+E struct obj *FDECL(add_to_container, (struct obj *, struct obj *));
+E void FDECL(add_to_migration, (struct obj *));
+E void FDECL(add_to_buried, (struct obj *));
+E void FDECL(dealloc_obj, (struct obj *));
+E void FDECL(obj_ice_effects, (int, int, BOOLEAN_P));
+E long FDECL(peek_at_iced_corpse_age, (struct obj *));
+#ifdef WIZARD
+E void NDECL(obj_sanity_check);
+#endif
+
+/* ### mkroom.c ### */
+
+E void FDECL(mkroom, (int));
+E void FDECL(fill_zoo, (struct mkroom *));
+E boolean FDECL(nexttodoor, (int,int));
+E boolean FDECL(has_dnstairs, (struct mkroom *));
+E boolean FDECL(has_upstairs, (struct mkroom *));
+E int FDECL(somex, (struct mkroom *));
+E int FDECL(somey, (struct mkroom *));
+E boolean FDECL(inside_room, (struct mkroom *,XCHAR_P,XCHAR_P));
+E boolean FDECL(somexy, (struct mkroom *,coord *));
+E void FDECL(mkundead, (coord *,BOOLEAN_P,int));
+E struct permonst *NDECL(courtmon);
+E void FDECL(save_rooms, (int));
+E void FDECL(rest_rooms, (int));
+E struct mkroom *FDECL(search_special, (SCHAR_P));
+
+/* ### mon.c ### */
+
+E int FDECL(undead_to_corpse, (int));
+E int FDECL(genus, (int,int));
+E int FDECL(pm_to_cham, (int));
+E int FDECL(minliquid, (struct monst *));
+E int NDECL(movemon);
+E int FDECL(meatmetal, (struct monst *));
+E int FDECL(meatobj, (struct monst *));
+E void FDECL(mpickgold, (struct monst *));
+E boolean FDECL(mpickstuff, (struct monst *,const char *));
+E int FDECL(curr_mon_load, (struct monst *));
+E int FDECL(max_mon_load, (struct monst *));
+E boolean FDECL(can_carry, (struct monst *,struct obj *));
+E int FDECL(mfndpos, (struct monst *,coord *,long *,long));
+E boolean FDECL(monnear, (struct monst *,int,int));
+E void NDECL(dmonsfree);
+E int FDECL(mcalcmove, (struct monst*));
+E void NDECL(mcalcdistress);
+E void FDECL(replmon, (struct monst *,struct monst *));
+E void FDECL(relmon, (struct monst *));
+E struct obj *FDECL(mlifesaver, (struct monst *));
+E boolean FDECL(corpse_chance,(struct monst *,struct monst *,BOOLEAN_P));
+E void FDECL(mondead, (struct monst *));
+E void FDECL(mondied, (struct monst *));
+E void FDECL(mongone, (struct monst *));
+E void FDECL(monstone, (struct monst *));
+E void FDECL(monkilled, (struct monst *,const char *,int));
+E void FDECL(unstuck, (struct monst *));
+E void FDECL(killed, (struct monst *));
+E void FDECL(xkilled, (struct monst *,int));
+E void FDECL(mon_to_stone, (struct monst*));
+E void FDECL(mnexto, (struct monst *));
+E boolean FDECL(mnearto, (struct monst *,XCHAR_P,XCHAR_P,BOOLEAN_P));
+E void FDECL(poisontell, (int));
+E void FDECL(poisoned, (const char *,int,const char *,int));
+E void FDECL(m_respond, (struct monst *));
+E void FDECL(setmangry, (struct monst *));
+E void FDECL(wakeup, (struct monst *));
+E void NDECL(wake_nearby);
+E void FDECL(wake_nearto, (int,int,int));
+E void FDECL(seemimic, (struct monst *));
+E void NDECL(rescham);
+E void NDECL(restartcham);
+E void FDECL(restore_cham, (struct monst *));
+E void FDECL(mon_animal_list, (BOOLEAN_P));
+E int FDECL(newcham, (struct monst *,struct permonst *,BOOLEAN_P,BOOLEAN_P));
+E int FDECL(can_be_hatched, (int));
+E int FDECL(egg_type_from_parent, (int,BOOLEAN_P));
+E boolean FDECL(dead_species, (int,BOOLEAN_P));
+E void NDECL(kill_genocided_monsters);
+E void FDECL(golemeffects, (struct monst *,int,int));
+E boolean FDECL(angry_guards, (BOOLEAN_P));
+E void NDECL(pacify_guards);
+
+/* ### mondata.c ### */
+
+E void FDECL(set_mon_data, (struct monst *,struct permonst *,int));
+E struct attack *FDECL(attacktype_fordmg, (struct permonst *,int,int));
+E boolean FDECL(attacktype, (struct permonst *,int));
+E boolean FDECL(poly_when_stoned, (struct permonst *));
+E boolean FDECL(resists_drli, (struct monst *));
+E boolean FDECL(resists_magm, (struct monst *));
+E boolean FDECL(resists_blnd, (struct monst *));
+E boolean FDECL(can_blnd, (struct monst *,struct monst *,UCHAR_P,struct obj *));
+E boolean FDECL(ranged_attk, (struct permonst *));
+E boolean FDECL(hates_silver, (struct permonst *));
+E boolean FDECL(passes_bars, (struct permonst *));
+E boolean FDECL(can_track, (struct permonst *));
+E boolean FDECL(breakarm, (struct permonst *));
+E boolean FDECL(sliparm, (struct permonst *));
+E boolean FDECL(sticks, (struct permonst *));
+E int FDECL(num_horns, (struct permonst *));
+/* E boolean FDECL(canseemon, (struct monst *)); */
+E struct attack *FDECL(dmgtype_fromattack, (struct permonst *,int,int));
+E boolean FDECL(dmgtype, (struct permonst *,int));
+E int FDECL(max_passive_dmg, (struct monst *,struct monst *));
+E int FDECL(monsndx, (struct permonst *));
+E int FDECL(name_to_mon, (const char *));
+E int FDECL(gender, (struct monst *));
+E int FDECL(pronoun_gender, (struct monst *));
+E boolean FDECL(levl_follower, (struct monst *));
+E int FDECL(little_to_big, (int));
+E int FDECL(big_to_little, (int));
+E const char *FDECL(locomotion, (const struct permonst *,const char *));
+E const char *FDECL(stagger, (const struct permonst *,const char *));
+E const char *FDECL(on_fire, (struct permonst *,struct attack *));
+E const struct permonst *FDECL(raceptr, (struct monst *));
+
+/* ### monmove.c ### */
+
+E boolean FDECL(itsstuck, (struct monst *));
+E boolean FDECL(mb_trapped, (struct monst *));
+E void FDECL(mon_regen, (struct monst *,BOOLEAN_P));
+E int FDECL(dochugw, (struct monst *));
+E boolean FDECL(onscary, (int,int,struct monst *));
+E void FDECL(monflee, (struct monst *, int, BOOLEAN_P, BOOLEAN_P));
+E int FDECL(dochug, (struct monst *));
+E int FDECL(m_move, (struct monst *,int));
+E boolean FDECL(closed_door, (int,int));
+E boolean FDECL(accessible, (int,int));
+E void FDECL(set_apparxy, (struct monst *));
+E boolean FDECL(can_ooze, (struct monst *));
+
+/* ### monst.c ### */
+
+E void NDECL(monst_init);
+
+/* ### monstr.c ### */
+
+E void NDECL(monstr_init);
+
+/* ### mplayer.c ### */
+
+E struct monst *FDECL(mk_mplayer, (struct permonst *,XCHAR_P,
+                                  XCHAR_P,BOOLEAN_P));
+E void FDECL(create_mplayers, (int,BOOLEAN_P));
+E void FDECL(mplayer_talk, (struct monst *));
+
+#if defined(MICRO) || defined(WIN32)
+
+/* ### msdos.c,os2.c,tos.c,winnt.c ### */
+
+#  ifndef WIN32
+E int NDECL(tgetch);
+#  endif
+#  ifndef TOS
+E char NDECL(switchar);
+#  endif
+# ifndef __GO32__
+E long FDECL(freediskspace, (char *));
+#  ifdef MSDOS
+E int FDECL(findfirst_file, (char *));
+E int NDECL(findnext_file);
+E long FDECL(filesize_nh, (char *));
+#  else
+E int FDECL(findfirst, (char *));
+E int NDECL(findnext);
+E long FDECL(filesize, (char *));
+#  endif /* MSDOS */
+E char *NDECL(foundfile_buffer);
+# endif /* __GO32__ */
+E void FDECL(chdrive, (char *));
+# ifndef TOS
+E void NDECL(disable_ctrlP);
+E void NDECL(enable_ctrlP);
+# endif
+# if defined(MICRO) && !defined(WINNT)
+E void NDECL(get_scr_size);
+#  ifndef TOS
+E void FDECL(gotoxy, (int,int));
+#  endif
+# endif
+# ifdef TOS
+E int FDECL(_copyfile, (char *,char *));
+E int NDECL(kbhit);
+E void NDECL(set_colors);
+E void NDECL(restore_colors);
+#  ifdef SUSPEND
+E int NDECL(dosuspend);
+#  endif
+# endif /* TOS */
+# ifdef WIN32
+E char *FDECL(get_username, (int *));
+E void FDECL(nt_regularize, (char *));
+E int NDECL((*nt_kbhit));
+E void FDECL(Delay, (int));
+# endif /* WIN32 */
+#endif /* MICRO || WIN32 */
+
+/* ### mthrowu.c ### */
+
+E int FDECL(thitu, (int,int,struct obj *,const char *));
+E int FDECL(ohitmon, (struct monst *,struct obj *,int,BOOLEAN_P));
+E void FDECL(thrwmu, (struct monst *));
+E int FDECL(spitmu, (struct monst *,struct attack *));
+E int FDECL(breamu, (struct monst *,struct attack *));
+E boolean FDECL(linedup, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
+E boolean FDECL(lined_up, (struct monst *));
+E struct obj *FDECL(m_carrying, (struct monst *,int));
+E void FDECL(m_useup, (struct monst *,struct obj *));
+E void FDECL(m_throw, (struct monst *,int,int,int,int,int,struct obj *));
+E boolean FDECL(hits_bars, (struct obj **,int,int,int,int));
+
+/* ### muse.c ### */
+
+E boolean FDECL(find_defensive, (struct monst *));
+E int FDECL(use_defensive, (struct monst *));
+E int FDECL(rnd_defensive_item, (struct monst *));
+E boolean FDECL(find_offensive, (struct monst *));
+#ifdef USE_TRAMPOLI
+E int FDECL(mbhitm, (struct monst *,struct obj *));
+#endif
+E int FDECL(use_offensive, (struct monst *));
+E int FDECL(rnd_offensive_item, (struct monst *));
+E boolean FDECL(find_misc, (struct monst *));
+E int FDECL(use_misc, (struct monst *));
+E int FDECL(rnd_misc_item, (struct monst *));
+E boolean FDECL(searches_for_item, (struct monst *,struct obj *));
+E boolean FDECL(mon_reflects, (struct monst *,const char *));
+E boolean FDECL(ureflects, (const char *,const char *));
+E boolean FDECL(munstone, (struct monst *,BOOLEAN_P));
+
+/* ### music.c ### */
+
+E void NDECL(awaken_soldiers);
+E int FDECL(do_play_instrument, (struct obj *));
+
+/* ### nhlan.c ### */
+#ifdef LAN_FEATURES
+E void NDECL(init_lan_features);
+E char *NDECL(lan_username);
+# ifdef LAN_MAIL
+E boolean NDECL(lan_mail_check);
+E void FDECL(lan_mail_read, (struct obj *));
+E void NDECL(lan_mail_init);
+E void NDECL(lan_mail_finish);
+E void NDECL(lan_mail_terminate);
+# endif
+#endif
+
+/* ### nttty.c ### */
+
+#ifdef WIN32CON
+E void NDECL(get_scr_size);
+E int NDECL(nttty_kbhit);
+E void NDECL(nttty_open);
+E void NDECL(nttty_rubout);
+E int NDECL(tgetch);
+E int FDECL(ntposkey,(int *, int *, int *));
+E void FDECL(set_output_mode, (int));
+E void NDECL(synch_cursor);
+#endif
+
+/* ### o_init.c ### */
+
+E void NDECL(init_objects);
+E int NDECL(find_skates);
+E void NDECL(oinit);
+E void FDECL(savenames, (int,int));
+E void FDECL(restnames, (int));
+E void FDECL(discover_object, (int,BOOLEAN_P,BOOLEAN_P));
+E void FDECL(undiscover_object, (int));
+E int NDECL(dodiscovered);
+
+/* ### objects.c ### */
+
+E void NDECL(objects_init);
+
+/* ### objnam.c ### */
+
+E char *FDECL(obj_typename, (int));
+E char *FDECL(simple_typename, (int));
+E boolean FDECL(obj_is_pname, (struct obj *));
+E char *FDECL(distant_name, (struct obj *,char *(*)(OBJ_P)));
+E char *FDECL(fruitname, (BOOLEAN_P));
+E char *FDECL(xname, (struct obj *));
+E char *FDECL(mshot_xname, (struct obj *));
+E boolean FDECL(the_unique_obj, (struct obj *obj));
+E char *FDECL(doname, (struct obj *));
+E boolean FDECL(not_fully_identified, (struct obj *));
+E char *FDECL(corpse_xname, (struct obj *,BOOLEAN_P));
+E char *FDECL(cxname, (struct obj *));
+E char *FDECL(killer_xname, (struct obj *));
+E const char *FDECL(singular, (struct obj *,char *(*)(OBJ_P)));
+E char *FDECL(an, (const char *));
+E char *FDECL(An, (const char *));
+E char *FDECL(The, (const char *));
+E char *FDECL(the, (const char *));
+E char *FDECL(aobjnam, (struct obj *,const char *));
+E char *FDECL(Tobjnam, (struct obj *,const char *));
+E char *FDECL(otense, (struct obj *,const char *));
+E char *FDECL(vtense, (const char *,const char *));
+E char *FDECL(Doname2, (struct obj *));
+E char *FDECL(yname, (struct obj *));
+E char *FDECL(Yname2, (struct obj *));
+E char *FDECL(ysimple_name, (struct obj *));
+E char *FDECL(Ysimple_name2, (struct obj *));
+E char *FDECL(makeplural, (const char *));
+E char *FDECL(makesingular, (const char *));
+E struct obj *FDECL(readobjnam, (char *,struct obj *,BOOLEAN_P));
+E int FDECL(rnd_class, (int,int));
+E const char *FDECL(cloak_simple_name, (struct obj *));
+E const char *FDECL(mimic_obj_name, (struct monst *));
+
+/* ### options.c ### */
+
+E boolean FDECL(match_optname, (const char *,const char *,int,BOOLEAN_P));
+E void NDECL(initoptions);
+E void FDECL(parseoptions, (char *,BOOLEAN_P,BOOLEAN_P));
+E int NDECL(doset);
+E int NDECL(dotogglepickup);
+E void NDECL(option_help);
+E void FDECL(next_opt, (winid,const char *));
+E int FDECL(fruitadd, (char *));
+E int FDECL(choose_classes_menu, (const char *,int,BOOLEAN_P,char *,char *));
+E void FDECL(add_menu_cmd_alias, (CHAR_P, CHAR_P));
+E char FDECL(map_menu_cmd, (CHAR_P));
+E void FDECL(assign_warnings, (uchar *));
+E char *FDECL(nh_getenv, (const char *));
+E void FDECL(set_duplicate_opt_detection, (int));
+E void FDECL(set_wc_option_mod_status, (unsigned long, int));
+E void FDECL(set_wc2_option_mod_status, (unsigned long, int));
+E void FDECL(set_option_mod_status, (const char *,int));
+#ifdef AUTOPICKUP_EXCEPTIONS
+E int FDECL(add_autopickup_exception, (const char *));
+E void NDECL(free_autopickup_exceptions);
+#endif /* AUTOPICKUP_EXCEPTIONS */
+
+/* ### pager.c ### */
+
+E int NDECL(dowhatis);
+E int NDECL(doquickwhatis);
+E int NDECL(doidtrap);
+E int NDECL(dowhatdoes);
+E char *FDECL(dowhatdoes_core,(CHAR_P, char *));
+E int NDECL(dohelp);
+E int NDECL(dohistory);
+
+/* ### pcmain.c ### */
+
+#if defined(MICRO) || defined(WIN32)
+# ifdef CHDIR
+E void FDECL(chdirx, (char *,BOOLEAN_P));
+# endif /* CHDIR */
+#endif /* MICRO || WIN32 */
+
+/* ### pcsys.c ### */
+
+#if defined(MICRO) || defined(WIN32)
+E void NDECL(flushout);
+E int NDECL(dosh);
+# ifdef MFLOPPY
+E void FDECL(eraseall, (const char *,const char *));
+E void FDECL(copybones, (int));
+E void NDECL(playwoRAMdisk);
+E int FDECL(saveDiskPrompt, (int));
+E void NDECL(gameDiskPrompt);
+# endif
+E void FDECL(append_slash, (char *));
+E void FDECL(getreturn, (const char *));
+# ifndef AMIGA
+E void VDECL(msmsg, (const char *,...));
+# endif
+E FILE *FDECL(fopenp, (const char *,const char *));
+#endif /* MICRO || WIN32 */
+
+/* ### pctty.c ### */
+
+#if defined(MICRO) || defined(WIN32)
+E void NDECL(gettty);
+E void FDECL(settty, (const char *));
+E void NDECL(setftty);
+E void VDECL(error, (const char *,...));
+#if defined(TIMED_DELAY) && defined(_MSC_VER)
+E void FDECL(msleep, (unsigned));
+#endif
+#endif /* MICRO || WIN32 */
+
+/* ### pcunix.c ### */
+
+#if defined(MICRO)
+E void FDECL(regularize, (char *));
+#endif /* MICRO */
+#if defined(PC_LOCKING)
+E void NDECL(getlock);
+#endif
+
+/* ### pickup.c ### */
+
+#ifdef GOLDOBJ
+E int FDECL(collect_obj_classes,
+       (char *,struct obj *,BOOLEAN_P,boolean FDECL((*),(OBJ_P)), int *));
+#else
+E int FDECL(collect_obj_classes,
+       (char *,struct obj *,BOOLEAN_P,BOOLEAN_P,boolean FDECL((*),(OBJ_P)), int *));
+#endif
+E void FDECL(add_valid_menu_class, (int));
+E boolean FDECL(allow_all, (struct obj *));
+E boolean FDECL(allow_category, (struct obj *));
+E boolean FDECL(is_worn_by_type, (struct obj *));
+#ifdef USE_TRAMPOLI
+E int FDECL(ck_bag, (struct obj *));
+E int FDECL(in_container, (struct obj *));
+E int FDECL(out_container, (struct obj *));
+#endif
+E int FDECL(pickup, (int));
+E int FDECL(pickup_object, (struct obj *, long, BOOLEAN_P));
+E int FDECL(query_category, (const char *, struct obj *, int,
+                               menu_item **, int));
+E int FDECL(query_objlist, (const char *, struct obj *, int,
+                               menu_item **, int, boolean (*)(OBJ_P)));
+E struct obj *FDECL(pick_obj, (struct obj *));
+E int NDECL(encumber_msg);
+E int NDECL(doloot);
+E int FDECL(use_container, (struct obj *,int));
+E int FDECL(loot_mon, (struct monst *,int *,boolean *));
+E const char *FDECL(safe_qbuf, (const char *,unsigned,
+                               const char *,const char *,const char *));
+E boolean FDECL(is_autopickup_exception, (struct obj *, BOOLEAN_P));
+
+/* ### pline.c ### */
+
+E void VDECL(pline, (const char *,...)) PRINTF_F(1,2);
+E void VDECL(Norep, (const char *,...)) PRINTF_F(1,2);
+E void NDECL(free_youbuf);
+E void VDECL(You, (const char *,...)) PRINTF_F(1,2);
+E void VDECL(Your, (const char *,...)) PRINTF_F(1,2);
+E void VDECL(You_feel, (const char *,...)) PRINTF_F(1,2);
+E void VDECL(You_cant, (const char *,...)) PRINTF_F(1,2);
+E void VDECL(You_hear, (const char *,...)) PRINTF_F(1,2);
+E void VDECL(pline_The, (const char *,...)) PRINTF_F(1,2);
+E void VDECL(There, (const char *,...)) PRINTF_F(1,2);
+E void VDECL(verbalize, (const char *,...)) PRINTF_F(1,2);
+E void VDECL(raw_printf, (const char *,...)) PRINTF_F(1,2);
+E void VDECL(impossible, (const char *,...)) PRINTF_F(1,2);
+E const char *FDECL(align_str, (ALIGNTYP_P));
+E void FDECL(mstatusline, (struct monst *));
+E void NDECL(ustatusline);
+E void NDECL(self_invis_message);
+
+/* ### polyself.c ### */
+
+E void NDECL(set_uasmon);
+E void NDECL(change_sex);
+E void FDECL(polyself, (BOOLEAN_P));
+E int FDECL(polymon, (int));
+E void NDECL(rehumanize);
+E int NDECL(dobreathe);
+E int NDECL(dospit);
+E int NDECL(doremove);
+E int NDECL(dospinweb);
+E int NDECL(dosummon);
+E int NDECL(dogaze);
+E int NDECL(dohide);
+E int NDECL(domindblast);
+E void FDECL(skinback, (BOOLEAN_P));
+E const char *FDECL(mbodypart, (struct monst *,int));
+E const char *FDECL(body_part, (int));
+E int NDECL(poly_gender);
+E void FDECL(ugolemeffects, (int,int));
+
+/* ### potion.c ### */
+
+E void FDECL(set_itimeout, (long *,long));
+E void FDECL(incr_itimeout, (long *,int));
+E void FDECL(make_confused, (long,BOOLEAN_P));
+E void FDECL(make_stunned, (long,BOOLEAN_P));
+E void FDECL(make_blinded, (long,BOOLEAN_P));
+E void FDECL(make_sick, (long, const char *, BOOLEAN_P,int));
+E void FDECL(make_vomiting, (long,BOOLEAN_P));
+E boolean FDECL(make_hallucinated, (long,BOOLEAN_P,long));
+E int NDECL(dodrink);
+E int FDECL(dopotion, (struct obj *));
+E int FDECL(peffects, (struct obj *));
+E void FDECL(healup, (int,int,BOOLEAN_P,BOOLEAN_P));
+E void FDECL(strange_feeling, (struct obj *,const char *));
+E void FDECL(potionhit, (struct monst *,struct obj *,BOOLEAN_P));
+E void FDECL(potionbreathe, (struct obj *));
+E boolean FDECL(get_wet, (struct obj *));
+E int NDECL(dodip);
+E void FDECL(djinni_from_bottle, (struct obj *));
+E struct monst *FDECL(split_mon, (struct monst *,struct monst *));
+E const char *NDECL(bottlename);
+
+/* ### pray.c ### */
+
+#ifdef USE_TRAMPOLI
+E int NDECL(prayer_done);
+#endif
+E int NDECL(dosacrifice);
+E boolean FDECL(can_pray, (BOOLEAN_P));
+E int NDECL(dopray);
+E const char *NDECL(u_gname);
+E int NDECL(doturn);
+E const char *NDECL(a_gname);
+E const char *FDECL(a_gname_at, (XCHAR_P x,XCHAR_P y));
+E const char *FDECL(align_gname, (ALIGNTYP_P));
+E const char *FDECL(halu_gname, (ALIGNTYP_P));
+E const char *FDECL(align_gtitle, (ALIGNTYP_P));
+E void FDECL(altar_wrath, (int,int));
+
+
+/* ### priest.c ### */
+
+E int FDECL(move_special, (struct monst *,BOOLEAN_P,SCHAR_P,BOOLEAN_P,BOOLEAN_P,
+                          XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
+E char FDECL(temple_occupied, (char *));
+E int FDECL(pri_move, (struct monst *));
+E void FDECL(priestini, (d_level *,struct mkroom *,int,int,BOOLEAN_P));
+E char *FDECL(priestname, (struct monst *,char *));
+E boolean FDECL(p_coaligned, (struct monst *));
+E struct monst *FDECL(findpriest, (CHAR_P));
+E void FDECL(intemple, (int));
+E void FDECL(priest_talk, (struct monst *));
+E struct monst *FDECL(mk_roamer, (struct permonst *,ALIGNTYP_P,
+                                 XCHAR_P,XCHAR_P,BOOLEAN_P));
+E void FDECL(reset_hostility, (struct monst *));
+E boolean FDECL(in_your_sanctuary, (struct monst *,XCHAR_P,XCHAR_P));
+E void FDECL(ghod_hitsu, (struct monst *));
+E void NDECL(angry_priest);
+E void NDECL(clearpriests);
+E void FDECL(restpriest, (struct monst *,BOOLEAN_P));
+
+/* ### quest.c ### */
+
+E void NDECL(onquest);
+E void NDECL(nemdead);
+E void NDECL(artitouch);
+E boolean NDECL(ok_to_quest);
+E void FDECL(leader_speaks, (struct monst *));
+E void NDECL(nemesis_speaks);
+E void FDECL(quest_chat, (struct monst *));
+E void FDECL(quest_talk, (struct monst *));
+E void FDECL(quest_stat_check, (struct monst *));
+E void FDECL(finish_quest, (struct obj *));
+
+/* ### questpgr.c ### */
+
+E void NDECL(load_qtlist);
+E void NDECL(unload_qtlist);
+E short FDECL(quest_info, (int));
+E const char *NDECL(ldrname);
+E boolean FDECL(is_quest_artifact, (struct obj*));
+E void FDECL(com_pager, (int));
+E void FDECL(qt_pager, (int));
+E struct permonst *NDECL(qt_montype);
+
+/* ### random.c ### */
+
+#if defined(RANDOM) && !defined(__GO32__) /* djgpp has its own random */
+E void FDECL(srandom, (unsigned));
+E char *FDECL(initstate, (unsigned,char *,int));
+E char *FDECL(setstate, (char *));
+E long NDECL(random);
+#endif /* RANDOM */
+
+/* ### read.c ### */
+
+E int NDECL(doread);
+E boolean FDECL(is_chargeable, (struct obj *));
+E void FDECL(recharge, (struct obj *,int));
+E void FDECL(forget_objects, (int));
+E void FDECL(forget_levels, (int));
+E void NDECL(forget_traps);
+E void FDECL(forget_map, (int));
+E int FDECL(seffects, (struct obj *));
+#ifdef USE_TRAMPOLI
+E void FDECL(set_lit, (int,int,genericptr_t));
+#endif
+E void FDECL(litroom, (BOOLEAN_P,struct obj *));
+E void FDECL(do_genocide, (int));
+E void FDECL(punish, (struct obj *));
+E void NDECL(unpunish);
+E boolean FDECL(cant_create, (int *, BOOLEAN_P));
+#ifdef WIZARD
+E boolean NDECL(create_particular);
+#endif
+
+/* ### rect.c ### */
+
+E void NDECL(init_rect);
+E NhRect *FDECL(get_rect, (NhRect *));
+E NhRect *NDECL(rnd_rect);
+E void FDECL(remove_rect, (NhRect *));
+E void FDECL(add_rect, (NhRect *));
+E void FDECL(split_rects, (NhRect *,NhRect *));
+
+/* ## region.c ### */
+E void NDECL(clear_regions);
+E void NDECL(run_regions);
+E boolean FDECL(in_out_region, (XCHAR_P,XCHAR_P));
+E boolean FDECL(m_in_out_region, (struct monst *,XCHAR_P,XCHAR_P));
+E void NDECL(update_player_regions);
+E void FDECL(update_monster_region, (struct monst *));
+E NhRegion *FDECL(visible_region_at, (XCHAR_P,XCHAR_P));
+E void FDECL(show_region, (NhRegion*, XCHAR_P, XCHAR_P));
+E void FDECL(save_regions, (int,int));
+E void FDECL(rest_regions, (int,BOOLEAN_P));
+E NhRegion* FDECL(create_gas_cloud, (XCHAR_P, XCHAR_P, int, int));
+
+/* ### restore.c ### */
+
+E void FDECL(inven_inuse, (BOOLEAN_P));
+E int FDECL(dorecover, (int));
+E void FDECL(trickery, (char *));
+E void FDECL(getlev, (int,int,XCHAR_P,BOOLEAN_P));
+E void NDECL(minit);
+E boolean FDECL(lookup_id_mapping, (unsigned, unsigned *));
+#ifdef ZEROCOMP
+E int FDECL(mread, (int,genericptr_t,unsigned int));
+#else
+E void FDECL(mread, (int,genericptr_t,unsigned int));
+#endif
+
+/* ### rip.c ### */
+
+E void FDECL(genl_outrip, (winid,int));
+
+/* ### rnd.c ### */
+
+E int FDECL(rn2, (int));
+E int FDECL(rnl, (int));
+E int FDECL(rnd, (int));
+E int FDECL(d, (int,int));
+E int FDECL(rne, (int));
+E int FDECL(rnz, (int));
+
+/* ### role.c ### */
+
+E boolean FDECL(validrole, (int));
+E boolean FDECL(validrace, (int, int));
+E boolean FDECL(validgend, (int, int, int));
+E boolean FDECL(validalign, (int, int, int));
+E int NDECL(randrole);
+E int FDECL(randrace, (int));
+E int FDECL(randgend, (int, int));
+E int FDECL(randalign, (int, int));
+E int FDECL(str2role, (char *));
+E int FDECL(str2race, (char *));
+E int FDECL(str2gend, (char *));
+E int FDECL(str2align, (char *));
+E boolean FDECL(ok_role, (int, int, int, int));
+E int FDECL(pick_role, (int, int, int, int));
+E boolean FDECL(ok_race, (int, int, int, int));
+E int FDECL(pick_race, (int, int, int, int));
+E boolean FDECL(ok_gend, (int, int, int, int));
+E int FDECL(pick_gend, (int, int, int, int));
+E boolean FDECL(ok_align, (int, int, int, int));
+E int FDECL(pick_align, (int, int, int, int));
+E void NDECL(role_init);
+E void NDECL(rigid_role_checks);
+E void NDECL(plnamesuffix);
+E const char *FDECL(Hello, (struct monst *));
+E const char *NDECL(Goodbye);
+E char *FDECL(build_plselection_prompt, (char *, int, int, int, int, int));
+E char *FDECL(root_plselection_prompt, (char *, int, int, int, int, int));
+
+/* ### rumors.c ### */
+
+E char *FDECL(getrumor, (int,char *, BOOLEAN_P));
+E void FDECL(outrumor, (int,int));
+E void FDECL(outoracle, (BOOLEAN_P, BOOLEAN_P));
+E void FDECL(save_oracles, (int,int));
+E void FDECL(restore_oracles, (int));
+E int FDECL(doconsult, (struct monst *));
+
+/* ### save.c ### */
+
+E int NDECL(dosave);
+#if defined(UNIX) || defined(VMS) || defined(__EMX__) || defined(WIN32)
+E void FDECL(hangup, (int));
+#endif
+E int NDECL(dosave0);
+#ifdef INSURANCE
+E void NDECL(savestateinlock);
+#endif
+#ifdef MFLOPPY
+E boolean FDECL(savelev, (int,XCHAR_P,int));
+E boolean FDECL(swapin_file, (int));
+E void NDECL(co_false);
+#else
+E void FDECL(savelev, (int,XCHAR_P,int));
+#endif
+E void FDECL(bufon, (int));
+E void FDECL(bufoff, (int));
+E void FDECL(bflush, (int));
+E void FDECL(bwrite, (int,genericptr_t,unsigned int));
+E void FDECL(bclose, (int));
+E void FDECL(savefruitchn, (int,int));
+E void NDECL(free_dungeons);
+E void NDECL(freedynamicdata);
+
+/* ### shk.c ### */
+
+#ifdef GOLDOBJ
+E long FDECL(money2mon, (struct monst *, long));
+E void FDECL(money2u, (struct monst *, long));
+#endif
+E char *FDECL(shkname, (struct monst *));
+E void FDECL(shkgone, (struct monst *));
+E void FDECL(set_residency, (struct monst *,BOOLEAN_P));
+E void FDECL(replshk, (struct monst *,struct monst *));
+E void FDECL(restshk, (struct monst *,BOOLEAN_P));
+E char FDECL(inside_shop, (XCHAR_P,XCHAR_P));
+E void FDECL(u_left_shop, (char *,BOOLEAN_P));
+E void FDECL(remote_burglary, (XCHAR_P,XCHAR_P));
+E void FDECL(u_entered_shop, (char *));
+E boolean FDECL(same_price, (struct obj *,struct obj *));
+E void NDECL(shopper_financial_report);
+E int FDECL(inhishop, (struct monst *));
+E struct monst *FDECL(shop_keeper, (CHAR_P));
+E boolean FDECL(tended_shop, (struct mkroom *));
+E void FDECL(delete_contents, (struct obj *));
+E void FDECL(obfree, (struct obj *,struct obj *));
+E void FDECL(home_shk, (struct monst *,BOOLEAN_P));
+E void FDECL(make_happy_shk, (struct monst *,BOOLEAN_P));
+E void FDECL(hot_pursuit, (struct monst *));
+E void FDECL(make_angry_shk, (struct monst *,XCHAR_P,XCHAR_P));
+E int NDECL(dopay);
+E boolean FDECL(paybill, (int));
+E void NDECL(finish_paybill);
+E struct obj *FDECL(find_oid, (unsigned));
+E long FDECL(contained_cost, (struct obj *,struct monst *,long,BOOLEAN_P, BOOLEAN_P));
+E long FDECL(contained_gold, (struct obj *));
+E void FDECL(picked_container, (struct obj *));
+E long FDECL(unpaid_cost, (struct obj *));
+E void FDECL(addtobill, (struct obj *,BOOLEAN_P,BOOLEAN_P,BOOLEAN_P));
+E void FDECL(splitbill, (struct obj *,struct obj *));
+E void FDECL(subfrombill, (struct obj *,struct monst *));
+E long FDECL(stolen_value, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P,BOOLEAN_P));
+E void FDECL(sellobj_state, (int));
+E void FDECL(sellobj, (struct obj *,XCHAR_P,XCHAR_P));
+E int FDECL(doinvbill, (int));
+E struct monst *FDECL(shkcatch, (struct obj *,XCHAR_P,XCHAR_P));
+E void FDECL(add_damage, (XCHAR_P,XCHAR_P,long));
+E int FDECL(repair_damage, (struct monst *,struct damage *,BOOLEAN_P));
+E int FDECL(shk_move, (struct monst *));
+E void FDECL(after_shk_move, (struct monst *));
+E boolean FDECL(is_fshk, (struct monst *));
+E void FDECL(shopdig, (int));
+E void FDECL(pay_for_damage, (const char *,BOOLEAN_P));
+E boolean FDECL(costly_spot, (XCHAR_P,XCHAR_P));
+E struct obj *FDECL(shop_object, (XCHAR_P,XCHAR_P));
+E void FDECL(price_quote, (struct obj *));
+E void FDECL(shk_chat, (struct monst *));
+E void FDECL(check_unpaid_usage, (struct obj *,BOOLEAN_P));
+E void FDECL(check_unpaid, (struct obj *));
+E void FDECL(costly_gold, (XCHAR_P,XCHAR_P,long));
+E boolean FDECL(block_door, (XCHAR_P,XCHAR_P));
+E boolean FDECL(block_entry, (XCHAR_P,XCHAR_P));
+E char *FDECL(shk_your, (char *,struct obj *));
+E char *FDECL(Shk_Your, (char *,struct obj *));
+
+/* ### shknam.c ### */
+
+E void FDECL(stock_room, (int,struct mkroom *));
+E boolean FDECL(saleable, (struct monst *,struct obj *));
+E int FDECL(get_shop_item, (int));
+
+/* ### sit.c ### */
+
+E void NDECL(take_gold);
+E int NDECL(dosit);
+E void NDECL(rndcurse);
+E void NDECL(attrcurse);
+
+/* ### sounds.c ### */
+
+E void NDECL(dosounds);
+E const char *FDECL(growl_sound, (struct monst *));
+E void FDECL(growl, (struct monst *));
+E void FDECL(yelp, (struct monst *));
+E void FDECL(whimper, (struct monst *));
+E void FDECL(beg, (struct monst *));
+E int NDECL(dotalk);
+#ifdef USER_SOUNDS
+E int FDECL(add_sound_mapping, (const char *));
+E void FDECL(play_sound_for_message, (const char *));
+#endif
+
+/* ### sys/msdos/sound.c ### */
+
+#ifdef MSDOS
+E int FDECL(assign_soundcard, (char *));
+#endif
+
+/* ### sp_lev.c ### */
+
+E boolean FDECL(check_room, (xchar *,xchar *,xchar *,xchar *,BOOLEAN_P));
+E boolean FDECL(create_room, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,
+                             XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
+E void FDECL(create_secret_door, (struct mkroom *,XCHAR_P));
+E boolean FDECL(dig_corridor, (coord *,coord *,BOOLEAN_P,SCHAR_P,SCHAR_P));
+E void FDECL(fill_room, (struct mkroom *,BOOLEAN_P));
+E boolean FDECL(load_special, (const char *));
+
+/* ### spell.c ### */
+
+#ifdef USE_TRAMPOLI
+E int NDECL(learn);
+#endif
+E int FDECL(study_book, (struct obj *));
+E void FDECL(book_disappears, (struct obj *));
+E void FDECL(book_substitution, (struct obj *,struct obj *));
+E void NDECL(age_spells);
+E int NDECL(docast);
+E int FDECL(spell_skilltype, (int));
+E int FDECL(spelleffects, (int,BOOLEAN_P));
+E void NDECL(losespells);
+E int NDECL(dovspell);
+E void FDECL(initialspell, (struct obj *));
+
+/* ### steal.c ### */
+
+#ifdef USE_TRAMPOLI
+E int NDECL(stealarm);
+#endif
+#ifdef GOLDOBJ
+E long FDECL(somegold, (long));
+#else
+E long NDECL(somegold);
+#endif
+E void FDECL(stealgold, (struct monst *));
+E void FDECL(remove_worn_item, (struct obj *,BOOLEAN_P));
+E int FDECL(steal, (struct monst *, char *));
+E int FDECL(mpickobj, (struct monst *,struct obj *));
+E void FDECL(stealamulet, (struct monst *));
+E void FDECL(mdrop_special_objs, (struct monst *));
+E void FDECL(relobj, (struct monst *,int,BOOLEAN_P));
+#ifdef GOLDOBJ
+E struct obj *FDECL(findgold, (struct obj *));
+#endif
+
+/* ### steed.c ### */
+
+#ifdef STEED
+E void NDECL(rider_cant_reach);
+E boolean FDECL(can_saddle, (struct monst *));
+E int FDECL(use_saddle, (struct obj *));
+E boolean FDECL(can_ride, (struct monst *));
+E int NDECL(doride);
+E boolean FDECL(mount_steed, (struct monst *, BOOLEAN_P));
+E void NDECL(exercise_steed);
+E void NDECL(kick_steed);
+E void FDECL(dismount_steed, (int));
+E void FDECL(place_monster, (struct monst *,int,int));
+#endif
+
+/* ### teleport.c ### */
+
+E boolean FDECL(goodpos, (int,int,struct monst *,unsigned));
+E boolean FDECL(enexto, (coord *,XCHAR_P,XCHAR_P,struct permonst *));
+E boolean FDECL(enexto_core, (coord *,XCHAR_P,XCHAR_P,struct permonst *,unsigned));
+E void FDECL(teleds, (int,int,BOOLEAN_P));
+E boolean FDECL(safe_teleds, (BOOLEAN_P));
+E boolean FDECL(teleport_pet, (struct monst *,BOOLEAN_P));
+E void NDECL(tele);
+E int NDECL(dotele);
+E void NDECL(level_tele);
+E void FDECL(domagicportal, (struct trap *));
+E void FDECL(tele_trap, (struct trap *));
+E void FDECL(level_tele_trap, (struct trap *));
+E void FDECL(rloc_to, (struct monst *,int,int));
+E boolean FDECL(rloc, (struct monst *, BOOLEAN_P));
+E boolean FDECL(tele_restrict, (struct monst *));
+E void FDECL(mtele_trap, (struct monst *, struct trap *,int));
+E int FDECL(mlevel_tele_trap, (struct monst *, struct trap *,BOOLEAN_P,int));
+E void FDECL(rloco, (struct obj *));
+E int NDECL(random_teleport_level);
+E boolean FDECL(u_teleport_mon, (struct monst *,BOOLEAN_P));
+
+/* ### tile.c ### */
+#ifdef USE_TILES
+E void FDECL(substitute_tiles, (d_level *));
+#endif
+
+/* ### timeout.c ### */
+
+E void NDECL(burn_away_slime);
+E void NDECL(nh_timeout);
+E void FDECL(fall_asleep, (int, BOOLEAN_P));
+E void FDECL(attach_egg_hatch_timeout, (struct obj *));
+E void FDECL(attach_fig_transform_timeout, (struct obj *));
+E void FDECL(kill_egg, (struct obj *));
+E void FDECL(hatch_egg, (genericptr_t, long));
+E void FDECL(learn_egg_type, (int));
+E void FDECL(burn_object, (genericptr_t, long));
+E void FDECL(begin_burn, (struct obj *, BOOLEAN_P));
+E void FDECL(end_burn, (struct obj *, BOOLEAN_P));
+E void NDECL(do_storms);
+E boolean FDECL(start_timer, (long, SHORT_P, SHORT_P, genericptr_t));
+E long FDECL(stop_timer, (SHORT_P, genericptr_t));
+E void NDECL(run_timers);
+E void FDECL(obj_move_timers, (struct obj *, struct obj *));
+E void FDECL(obj_split_timers, (struct obj *, struct obj *));
+E void FDECL(obj_stop_timers, (struct obj *));
+E boolean FDECL(obj_is_local, (struct obj *));
+E void FDECL(save_timers, (int,int,int));
+E void FDECL(restore_timers, (int,int,BOOLEAN_P,long));
+E void FDECL(relink_timers, (BOOLEAN_P));
+#ifdef WIZARD
+E int NDECL(wiz_timeout_queue);
+E void NDECL(timer_sanity_check);
+#endif
+
+/* ### topten.c ### */
+
+E void FDECL(topten, (int));
+E void FDECL(prscore, (int,char **));
+E struct obj *FDECL(tt_oname, (struct obj *));
+
+/* ### track.c ### */
+
+E void NDECL(initrack);
+E void NDECL(settrack);
+E coord *FDECL(gettrack, (int,int));
+
+/* ### trap.c ### */
+
+E boolean FDECL(burnarmor,(struct monst *));
+E boolean FDECL(rust_dmg, (struct obj *,const char *,int,BOOLEAN_P,struct monst *));
+E void FDECL(grease_protect, (struct obj *,const char *,struct monst *));
+E struct trap *FDECL(maketrap, (int,int,int));
+E void FDECL(fall_through, (BOOLEAN_P));
+E struct monst *FDECL(animate_statue, (struct obj *,XCHAR_P,XCHAR_P,int,int *));
+E struct monst *FDECL(activate_statue_trap,
+                       (struct trap *,XCHAR_P,XCHAR_P,BOOLEAN_P));
+E void FDECL(dotrap, (struct trap *, unsigned));
+E void FDECL(seetrap, (struct trap *));
+E int FDECL(mintrap, (struct monst *));
+E void FDECL(instapetrify, (const char *));
+E void FDECL(minstapetrify, (struct monst *,BOOLEAN_P));
+E void FDECL(selftouch, (const char *));
+E void FDECL(mselftouch, (struct monst *,const char *,BOOLEAN_P));
+E void NDECL(float_up);
+E void FDECL(fill_pit, (int,int));
+E int FDECL(float_down, (long, long));
+E int FDECL(fire_damage, (struct obj *,BOOLEAN_P,BOOLEAN_P,XCHAR_P,XCHAR_P));
+E void FDECL(water_damage, (struct obj *,BOOLEAN_P,BOOLEAN_P));
+E boolean NDECL(drown);
+E void FDECL(drain_en, (int));
+E int NDECL(dountrap);
+E int FDECL(untrap, (BOOLEAN_P));
+E boolean FDECL(chest_trap, (struct obj *,int,BOOLEAN_P));
+E void FDECL(deltrap, (struct trap *));
+E boolean FDECL(delfloortrap, (struct trap *));
+E struct trap *FDECL(t_at, (int,int));
+E void FDECL(b_trapped, (const char *,int));
+E boolean NDECL(unconscious);
+E boolean NDECL(lava_effects);
+E void FDECL(blow_up_landmine, (struct trap *));
+E int FDECL(launch_obj,(SHORT_P,int,int,int,int,int));
+
+/* ### u_init.c ### */
+
+E void NDECL(u_init);
+
+/* ### uhitm.c ### */
+
+E void FDECL(hurtmarmor,(struct monst *,int));
+E boolean FDECL(attack_checks, (struct monst *,struct obj *));
+E void FDECL(check_caitiff, (struct monst *));
+E schar FDECL(find_roll_to_hit, (struct monst *));
+E boolean FDECL(attack, (struct monst *));
+E boolean FDECL(hmon, (struct monst *,struct obj *,int));
+E int FDECL(damageum, (struct monst *,struct attack *));
+E void FDECL(missum, (struct monst *,struct attack *));
+E int FDECL(passive, (struct monst *,BOOLEAN_P,int,UCHAR_P));
+E void FDECL(passive_obj, (struct monst *,struct obj *,struct attack *));
+E void FDECL(stumble_onto_mimic, (struct monst *));
+E int FDECL(flash_hits_mon, (struct monst *,struct obj *));
+
+/* ### unixmain.c ### */
+
+#ifdef UNIX
+# ifdef PORT_HELP
+E void NDECL(port_help);
+# endif
+#endif /* UNIX */
+
+
+/* ### unixtty.c ### */
+
+#if defined(UNIX) || defined(__BEOS__)
+E void NDECL(gettty);
+E void FDECL(settty, (const char *));
+E void NDECL(setftty);
+E void NDECL(intron);
+E void NDECL(introff);
+E void VDECL(error, (const char *,...)) PRINTF_F(1,2);
+#endif /* UNIX || __BEOS__ */
+
+/* ### unixunix.c ### */
+
+#ifdef UNIX
+E void NDECL(getlock);
+E void FDECL(regularize, (char *));
+# if defined(TIMED_DELAY) && !defined(msleep) && defined(SYSV)
+E void FDECL(msleep, (unsigned));
+# endif
+# ifdef SHELL
+E int NDECL(dosh);
+# endif /* SHELL */
+# if defined(SHELL) || defined(DEF_PAGER) || defined(DEF_MAILREADER)
+E int FDECL(child, (int));
+# endif
+#endif /* UNIX */
+
+/* ### unixres.c ### */
+
+#ifdef UNIX
+# ifdef GNOME_GRAPHICS 
+E int FDECL(hide_privileges, (BOOLEAN_P));
+# endif
+#endif /* UNIX */
+
+/* ### vault.c ### */
+
+E boolean FDECL(grddead, (struct monst *));
+E char FDECL(vault_occupied, (char *));
+E void NDECL(invault);
+E int FDECL(gd_move, (struct monst *));
+E void NDECL(paygd);
+E long NDECL(hidden_gold);
+E boolean NDECL(gd_sound);
+
+/* ### version.c ### */
+
+E char *FDECL(version_string, (char *));
+E char *FDECL(getversionstring, (char *));
+E int NDECL(doversion);
+E int NDECL(doextversion);
+#ifdef MICRO
+E boolean FDECL(comp_times, (long));
+#endif
+E boolean FDECL(check_version, (struct version_info *,
+                               const char *,BOOLEAN_P));
+E unsigned long FDECL(get_feature_notice_ver, (char *));
+E unsigned long NDECL(get_current_feature_ver);
+#ifdef RUNTIME_PORT_ID
+E void FDECL(append_port_id, (char *));
+#endif
+
+/* ### video.c ### */
+
+#ifdef MSDOS
+E int FDECL(assign_video, (char *));
+# ifdef NO_TERMS
+E void NDECL(gr_init);
+E void NDECL(gr_finish);
+# endif
+E void FDECL(tileview,(BOOLEAN_P));
+#endif
+#ifdef VIDEOSHADES
+E int FDECL(assign_videoshades, (char *));
+E int FDECL(assign_videocolors, (char *));
+#endif
+
+/* ### vis_tab.c ### */
+
+#ifdef VISION_TABLES
+E void NDECL(vis_tab_init);
+#endif
+
+/* ### vision.c ### */
+
+E void NDECL(vision_init);
+E int FDECL(does_block, (int,int,struct rm*));
+E void NDECL(vision_reset);
+E void FDECL(vision_recalc, (int));
+E void FDECL(block_point, (int,int));
+E void FDECL(unblock_point, (int,int));
+E boolean FDECL(clear_path, (int,int,int,int));
+E void FDECL(do_clear_area, (int,int,int,
+                            void (*)(int,int,genericptr_t),genericptr_t));
+
+#ifdef VMS
+
+/* ### vmsfiles.c ### */
+
+E int FDECL(vms_link, (const char *,const char *));
+E int FDECL(vms_unlink, (const char *));
+E int FDECL(vms_creat, (const char *,unsigned int));
+E int FDECL(vms_open, (const char *,int,unsigned int));
+E boolean FDECL(same_dir, (const char *,const char *));
+E int FDECL(c__translate, (int));
+E char *FDECL(vms_basename, (const char *));
+
+/* ### vmsmail.c ### */
+
+E unsigned long NDECL(init_broadcast_trapping);
+E unsigned long NDECL(enable_broadcast_trapping);
+E unsigned long NDECL(disable_broadcast_trapping);
+# if 0
+E struct mail_info *NDECL(parse_next_broadcast);
+# endif /*0*/
+
+/* ### vmsmain.c ### */
+
+E int FDECL(main, (int, char **));
+# ifdef CHDIR
+E void FDECL(chdirx, (const char *,BOOLEAN_P));
+# endif /* CHDIR */
+
+/* ### vmsmisc.c ### */
+
+E void NDECL(vms_abort);
+E void FDECL(vms_exit, (int));
+
+/* ### vmstty.c ### */
+
+E int NDECL(vms_getchar);
+E void NDECL(gettty);
+E void FDECL(settty, (const char *));
+E void FDECL(shuttty, (const char *));
+E void NDECL(setftty);
+E void NDECL(intron);
+E void NDECL(introff);
+E void VDECL(error, (const char *,...)) PRINTF_F(1,2);
+#ifdef TIMED_DELAY
+E void FDECL(msleep, (unsigned));
+#endif
+
+/* ### vmsunix.c ### */
+
+E void NDECL(getlock);
+E void FDECL(regularize, (char *));
+E int NDECL(vms_getuid);
+E boolean FDECL(file_is_stmlf, (int));
+E int FDECL(vms_define, (const char *,const char *,int));
+E int FDECL(vms_putenv, (const char *));
+E char *NDECL(verify_termcap);
+# if defined(CHDIR) || defined(SHELL) || defined(SECURE)
+E void NDECL(privoff);
+E void NDECL(privon);
+# endif
+# ifdef SHELL
+E int NDECL(dosh);
+# endif
+# if defined(SHELL) || defined(MAIL)
+E int FDECL(vms_doshell, (const char *,BOOLEAN_P));
+# endif
+# ifdef SUSPEND
+E int NDECL(dosuspend);
+# endif
+
+#endif /* VMS */
+
+/* ### weapon.c ### */
+
+E int FDECL(hitval, (struct obj *,struct monst *));
+E int FDECL(dmgval, (struct obj *,struct monst *));
+E struct obj *FDECL(select_rwep, (struct monst *));
+E struct obj *FDECL(select_hwep, (struct monst *));
+E void FDECL(possibly_unwield, (struct monst *,BOOLEAN_P));
+E int FDECL(mon_wield_item, (struct monst *));
+E int NDECL(abon);
+E int NDECL(dbon);
+E int NDECL(enhance_weapon_skill);
+E void FDECL(unrestrict_weapon_skill, (int));
+E void FDECL(use_skill, (int,int));
+E void FDECL(add_weapon_skill, (int));
+E void FDECL(lose_weapon_skill, (int));
+E int FDECL(weapon_type, (struct obj *));
+E int NDECL(uwep_skill_type);
+E int FDECL(weapon_hit_bonus, (struct obj *));
+E int FDECL(weapon_dam_bonus, (struct obj *));
+E void FDECL(skill_init, (const struct def_skill *));
+
+/* ### were.c ### */
+
+E void FDECL(were_change, (struct monst *));
+E void FDECL(new_were, (struct monst *));
+E int FDECL(were_summon, (struct permonst *,BOOLEAN_P,int *,char *));
+E void NDECL(you_were);
+E void FDECL(you_unwere, (BOOLEAN_P));
+
+/* ### wield.c ### */
+
+E void FDECL(setuwep, (struct obj *));
+E void FDECL(setuqwep, (struct obj *));
+E void FDECL(setuswapwep, (struct obj *));
+E int NDECL(dowield);
+E int NDECL(doswapweapon);
+E int NDECL(dowieldquiver);
+E boolean FDECL(wield_tool, (struct obj *,const char *));
+E int NDECL(can_twoweapon);
+E void NDECL(drop_uswapwep);
+E int NDECL(dotwoweapon);
+E void NDECL(uwepgone);
+E void NDECL(uswapwepgone);
+E void NDECL(uqwepgone);
+E void NDECL(untwoweapon);
+E void FDECL(erode_obj, (struct obj *,BOOLEAN_P,BOOLEAN_P));
+E int FDECL(chwepon, (struct obj *,int));
+E int FDECL(welded, (struct obj *));
+E void FDECL(weldmsg, (struct obj *));
+E void FDECL(setmnotwielded, (struct monst *,struct obj *));
+
+/* ### windows.c ### */
+
+E void FDECL(choose_windows, (const char *));
+E char FDECL(genl_message_menu, (CHAR_P,int,const char *));
+E void FDECL(genl_preference_update, (const char *));
+
+/* ### wizard.c ### */
+
+E void NDECL(amulet);
+E int FDECL(mon_has_amulet, (struct monst *));
+E int FDECL(mon_has_special, (struct monst *));
+E int FDECL(tactics, (struct monst *));
+E void NDECL(aggravate);
+E void NDECL(clonewiz);
+E int NDECL(pick_nasty);
+E int FDECL(nasty, (struct monst*));
+E void NDECL(resurrect);
+E void NDECL(intervene);
+E void NDECL(wizdead);
+E void FDECL(cuss, (struct monst *));
+
+/* ### worm.c ### */
+
+E int NDECL(get_wormno);
+E void FDECL(initworm, (struct monst *,int));
+E void FDECL(worm_move, (struct monst *));
+E void FDECL(worm_nomove, (struct monst *));
+E void FDECL(wormgone, (struct monst *));
+E void FDECL(wormhitu, (struct monst *));
+E void FDECL(cutworm, (struct monst *,XCHAR_P,XCHAR_P,struct obj *));
+E void FDECL(see_wsegs, (struct monst *));
+E void FDECL(detect_wsegs, (struct monst *,BOOLEAN_P));
+E void FDECL(save_worm, (int,int));
+E void FDECL(rest_worm, (int));
+E void FDECL(place_wsegs, (struct monst *));
+E void FDECL(remove_worm, (struct monst *));
+E void FDECL(place_worm_tail_randomly, (struct monst *,XCHAR_P,XCHAR_P));
+E int FDECL(count_wsegs, (struct monst *));
+E boolean FDECL(worm_known, (struct monst *));
+
+/* ### worn.c ### */
+
+E void FDECL(setworn, (struct obj *,long));
+E void FDECL(setnotworn, (struct obj *));
+E void FDECL(mon_set_minvis, (struct monst *));
+E void FDECL(mon_adjust_speed, (struct monst *,int,struct obj *));
+E void FDECL(update_mon_intrinsics,
+               (struct monst *,struct obj *,BOOLEAN_P,BOOLEAN_P));
+E int FDECL(find_mac, (struct monst *));
+E void FDECL(m_dowear, (struct monst *,BOOLEAN_P));
+E struct obj *FDECL(which_armor, (struct monst *,long));
+E void FDECL(mon_break_armor, (struct monst *,BOOLEAN_P));
+E void FDECL(bypass_obj, (struct obj *));
+E void NDECL(clear_bypasses);
+E int FDECL(racial_exception, (struct monst *, struct obj *));
+
+/* ### write.c ### */
+
+E int FDECL(dowrite, (struct obj *));
+
+/* ### zap.c ### */
+
+E int FDECL(bhitm, (struct monst *,struct obj *));
+E void FDECL(probe_monster, (struct monst *));
+E boolean FDECL(get_obj_location, (struct obj *,xchar *,xchar *,int));
+E boolean FDECL(get_mon_location, (struct monst *,xchar *,xchar *,int));
+E struct monst *FDECL(get_container_location, (struct obj *obj, int *, int *));
+E struct monst *FDECL(montraits, (struct obj *,coord *));
+E struct monst *FDECL(revive, (struct obj *));
+E int FDECL(unturn_dead, (struct monst *));
+E void FDECL(cancel_item, (struct obj *));
+E boolean FDECL(drain_item, (struct obj *));
+E struct obj *FDECL(poly_obj, (struct obj *, int));
+E boolean FDECL(obj_resists, (struct obj *,int,int));
+E boolean FDECL(obj_shudders, (struct obj *));
+E void FDECL(do_osshock, (struct obj *));
+E int FDECL(bhito, (struct obj *,struct obj *));
+E int FDECL(bhitpile, (struct obj *,int (*)(OBJ_P,OBJ_P),int,int));
+E int FDECL(zappable, (struct obj *));
+E void FDECL(zapnodir, (struct obj *));
+E int NDECL(dozap);
+E int FDECL(zapyourself, (struct obj *,BOOLEAN_P));
+E boolean FDECL(cancel_monst, (struct monst *,struct obj *,
+                              BOOLEAN_P,BOOLEAN_P,BOOLEAN_P));
+E void FDECL(weffects, (struct obj *));
+E int NDECL(spell_damage_bonus);
+E const char *FDECL(exclam, (int force));
+E void FDECL(hit, (const char *,struct monst *,const char *));
+E void FDECL(miss, (const char *,struct monst *));
+E struct monst *FDECL(bhit, (int,int,int,int,int (*)(MONST_P,OBJ_P),
+                            int (*)(OBJ_P,OBJ_P),struct obj *));
+E struct monst *FDECL(boomhit, (int,int));
+E int FDECL(burn_floor_paper, (int,int,BOOLEAN_P,BOOLEAN_P));
+E void FDECL(buzz, (int,int,XCHAR_P,XCHAR_P,int,int));
+E void FDECL(melt_ice, (XCHAR_P,XCHAR_P));
+E int FDECL(zap_over_floor, (XCHAR_P,XCHAR_P,int,boolean *));
+E void FDECL(fracture_rock, (struct obj *));
+E boolean FDECL(break_statue, (struct obj *));
+E void FDECL(destroy_item, (int,int));
+E int FDECL(destroy_mitem, (struct monst *,int,int));
+E int FDECL(resist, (struct monst *,CHAR_P,int,int));
+E void NDECL(makewish);
+
+#endif /* !MAKEDEFS_C && !LEV_LEX_C */
+
+#undef E
+
+#endif /* EXTERN_H */
diff --git a/include/flag.h b/include/flag.h
new file mode 100644 (file)
index 0000000..1807a0b
--- /dev/null
@@ -0,0 +1,313 @@
+/*     SCCS Id: @(#)flag.h     3.4     2002/08/22      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* If you change the flag structure make sure you increment EDITLEVEL in   */
+/* patchlevel.h if needed.  Changing the instance_flags structure does    */
+/* not require incrementing EDITLEVEL.                                    */
+
+#ifndef FLAG_H
+#define FLAG_H
+
+/*
+ * Persistent flags that are saved and restored with the game.
+ *
+ */
+
+struct flag {
+#ifdef AMIFLUSH
+       boolean  altmeta;       /* use ALT keys as META */
+       boolean  amiflush;      /* kill typeahead */
+#endif
+#ifdef MFLOPPY
+       boolean  asksavedisk;
+#endif
+       boolean  autodig;       /* MRKR: Automatically dig */
+       boolean  autoquiver;    /* Automatically fill quiver */
+       boolean  beginner;
+#ifdef MAIL
+       boolean  biff;          /* enable checking for mail */
+#endif
+       boolean  botl;          /* partially redo status line */
+       boolean  botlx;         /* print an entirely new bottom line */
+       boolean  confirm;       /* confirm before hitting tame monsters */
+       boolean  debug;         /* in debugging mode */
+#define wizard  flags.debug
+       boolean  end_own;       /* list all own scores */
+       boolean  explore;       /* in exploration mode */
+#ifdef OPT_DISPMAP
+       boolean  fast_map;      /* use optimized, less flexible map display */
+#endif
+#define discover flags.explore
+       boolean  female;
+       boolean  forcefight;
+       boolean  friday13;      /* it's Friday the 13th */
+       boolean  help;          /* look in data file for info about stuff */
+       boolean  ignintr;       /* ignore interrupts */
+#ifdef INSURANCE
+       boolean  ins_chkpt;     /* checkpoint as appropriate */
+#endif
+       boolean  invlet_constant; /* let objects keep their inventory symbol */
+       boolean  legacy;        /* print game entry "story" */
+       boolean  lit_corridor;  /* show a dark corr as lit if it is in sight */
+       boolean  made_amulet;
+       boolean  mon_moving;    /* monsters' turn to move */
+       boolean  move;
+       boolean  mv;
+       boolean  bypasses;      /* bypass flag is set on at least one fobj */
+       boolean  nap;           /* `timed_delay' option for display effects */
+       boolean  nopick;        /* do not pickup objects (as when running) */
+       boolean  null;          /* OK to send nulls to the terminal */
+#ifdef MAC
+       boolean  page_wait;     /* put up a --More-- after a page of messages */
+#endif
+       boolean  perm_invent;   /* keep full inventories up until dismissed */
+       boolean  pickup;        /* whether you pickup or move and look */
+
+       boolean  pushweapon;    /* When wielding, push old weapon into second slot */
+       boolean  rest_on_space; /* space means rest */
+       boolean  safe_dog;      /* give complete protection to the dog */
+#ifdef EXP_ON_BOTL
+       boolean  showexp;       /* show experience points */
+#endif
+#ifdef SCORE_ON_BOTL
+       boolean  showscore;     /* show score */
+#endif
+       boolean  silent;        /* whether the bell rings or not */
+       boolean  sortpack;      /* sorted inventory */
+       boolean  soundok;       /* ok to tell about sounds heard */
+       boolean  sparkle;       /* show "resisting" special FX (Scott Bigham) */
+       boolean  standout;      /* use standout for --More-- */
+       boolean  time;          /* display elapsed 'time' */
+       boolean  tombstone;     /* print tombstone */
+       boolean  toptenwin;     /* ending list in window instead of stdout */
+       boolean  verbose;       /* max battle info */
+       boolean  prayconfirm;   /* confirm before praying */
+       int      end_top, end_around;   /* describe desired score list */
+       unsigned ident;         /* social security number for each monster */
+       unsigned moonphase;
+       unsigned long suppress_alert;
+#define NEW_MOON       0
+#define FULL_MOON      4
+       unsigned no_of_wizards; /* 0, 1 or 2 (wizard and his shadow) */
+       boolean  travel;        /* find way automatically to u.tx,u.ty */
+       unsigned run;           /* 0: h (etc), 1: H (etc), 2: fh (etc) */
+                               /* 3: FH, 4: ff+, 5: ff-, 6: FF+, 7: FF- */
+                               /* 8: travel */
+       unsigned long warntype; /* warn_of_mon monster type M2 */
+       int      warnlevel;
+       int      djinni_count, ghost_count;     /* potion effect tuning */
+       int      pickup_burden;         /* maximum burden before prompt */
+       char     inv_order[MAXOCLASSES];
+       char     pickup_types[MAXOCLASSES];
+#define NUM_DISCLOSURE_OPTIONS         5
+#define DISCLOSE_PROMPT_DEFAULT_YES    'y'
+#define DISCLOSE_PROMPT_DEFAULT_NO     'n'
+#define DISCLOSE_YES_WITHOUT_PROMPT    '+'
+#define DISCLOSE_NO_WITHOUT_PROMPT     '-'
+       char     end_disclose[NUM_DISCLOSURE_OPTIONS + 1];  /* disclose various info
+                                                               upon exit */
+       char     menu_style;    /* User interface style setting */
+#ifdef AMII_GRAPHICS
+       int numcols;
+       unsigned short amii_dripens[ 20 ]; /* DrawInfo Pens currently there are 13 in v39 */
+       AMII_COLOR_TYPE amii_curmap[ AMII_MAXCOLORS ]; /* colormap */
+#endif
+
+       /* KMH, role patch -- Variables used during startup.
+        *
+        * If the user wishes to select a role, race, gender, and/or alignment
+        * during startup, the choices should be recorded here.  This
+        * might be specified through command-line options, environmental
+        * variables, a popup dialog box, menus, etc.
+        *
+        * These values are each an index into an array.  They are not
+        * characters or letters, because that limits us to 26 roles.
+        * They are not booleans, because someday someone may need a neuter
+        * gender.  Negative values are used to indicate that the user
+        * hasn't yet specified that particular value.  If you determine
+        * that the user wants a random choice, then you should set an
+        * appropriate random value; if you just left the negative value,
+        * the user would be asked again!
+        *
+        * These variables are stored here because the u structure is
+        * cleared during character initialization, and because the
+        * flags structure is restored for saved games.  Thus, we can
+        * use the same parameters to build the role entry for both
+        * new and restored games.
+        *
+        * These variables should not be referred to after the character
+        * is initialized or restored (specifically, after role_init()
+        * is called).
+        */
+       int      initrole;      /* starting role      (index into roles[])   */
+       int      initrace;      /* starting race      (index into races[])   */
+       int      initgend;      /* starting gender    (index into genders[]) */
+       int      initalign;     /* starting alignment (index into aligns[])  */
+       int      randomall;     /* randomly assign everything not specified */
+       int      pantheon;      /* deity selection for priest character */
+};
+
+/*
+ * Flags that are set each time the game is started.
+ * These are not saved with the game.
+ *
+ */
+
+struct instance_flags {
+       boolean  cbreak;        /* in cbreak mode, rogue format */
+       boolean  DECgraphics;   /* use DEC VT-xxx extended character set */
+       boolean  echo;          /* 1 to echo characters */
+       boolean  IBMgraphics;   /* use IBM extended character set */
+       unsigned msg_history;   /* hint: # of top lines to save */
+       boolean  num_pad;       /* use numbers for movement commands */
+       boolean  news;          /* print news */
+       boolean  window_inited; /* true if init_nhwindows() completed */
+       boolean  vision_inited; /* true if vision is ready */
+       boolean  menu_tab_sep;  /* Use tabs to separate option menu fields */
+       boolean  menu_requested; /* Flag for overloaded use of 'm' prefix
+                                 * on some non-move commands */
+       uchar num_pad_mode;
+       int     menu_headings;  /* ATR for menu headings */
+       int      purge_monsters;        /* # of dead monsters still on fmon list */
+       int *opt_booldup;       /* for duplication of boolean opts in config file */
+       int *opt_compdup;       /* for duplication of compound opts in config file */
+       uchar   bouldersym;     /* symbol for boulder display */
+       boolean travel1;        /* first travel step */
+       coord   travelcc;       /* coordinates for travel_cache */
+#ifdef WIZARD
+       boolean  sanity_check;  /* run sanity checks */
+       boolean  mon_polycontrol;       /* debug: control monster polymorphs */
+#endif
+#ifdef TTY_GRAPHICS
+       char prevmsg_window;    /* type of old message window to use */
+       boolean  extmenu;       /* extended commands use menu interface */
+#endif
+#ifdef MFLOPPY
+       boolean  checkspace;    /* check disk space before writing files */
+                               /* (in iflags to allow restore after moving
+                                * to >2GB partition) */
+#endif
+#ifdef MICRO
+       boolean  BIOS;          /* use IBM or ST BIOS calls when appropriate */
+#endif
+#if defined(MICRO) || defined(WIN32)
+       boolean  rawio;         /* whether can use rawio (IOCTL call) */
+#endif
+#ifdef MAC_GRAPHICS_ENV
+       boolean  MACgraphics;   /* use Macintosh extended character set, as
+                                  as defined in the special font HackFont */
+       unsigned  use_stone;            /* use the stone ppats */
+#endif
+#if defined(MSDOS) || defined(WIN32)
+       boolean hassound;       /* has a sound card */
+       boolean usesound;       /* use the sound card */
+       boolean usepcspeaker;   /* use the pc speaker */
+       boolean tile_view;
+       boolean over_view;
+       boolean traditional_view;
+#endif
+#ifdef MSDOS
+       boolean hasvga;         /* has a vga adapter */
+       boolean usevga;         /* use the vga adapter */
+       boolean grmode;         /* currently in graphics mode */
+#endif
+#ifdef LAN_FEATURES
+       boolean lan_mail;       /* mail is initialized */
+       boolean lan_mail_fetched; /* mail is awaiting display */
+#endif
+/*
+ * Window capability support.
+ */
+       boolean wc_color;               /* use color graphics                  */
+       boolean wc_hilite_pet;          /* hilight pets                        */
+       boolean wc_ascii_map;           /* show map using traditional ascii    */
+       boolean wc_tiled_map;           /* show map using tiles                */
+       boolean wc_preload_tiles;       /* preload tiles into memory           */
+       int     wc_tile_width;          /* tile width                          */
+       int     wc_tile_height;         /* tile height                         */
+       char    *wc_tile_file;          /* name of tile file;overrides default */
+       boolean wc_inverse;             /* use inverse video for some things   */
+       int     wc_align_status;        /*  status win at top|bot|right|left   */
+       int     wc_align_message;       /* message win at top|bot|right|left   */
+       int     wc_vary_msgcount;       /* show more old messages at a time    */
+       char    *wc_foregrnd_menu;      /* points to foregrnd color name for menu win   */
+       char    *wc_backgrnd_menu;      /* points to backgrnd color name for menu win   */
+       char    *wc_foregrnd_message;   /* points to foregrnd color name for msg win    */
+       char    *wc_backgrnd_message;   /* points to backgrnd color name for msg win    */
+       char    *wc_foregrnd_status;    /* points to foregrnd color name for status win */
+       char    *wc_backgrnd_status;    /* points to backgrnd color name for status win */
+       char    *wc_foregrnd_text;      /* points to foregrnd color name for text win   */
+       char    *wc_backgrnd_text;      /* points to backgrnd color name for text win   */
+       char    *wc_font_map;           /* points to font name for the map win */
+       char    *wc_font_message;       /* points to font name for message win */
+       char    *wc_font_status;        /* points to font name for status win  */
+       char    *wc_font_menu;          /* points to font name for menu win    */
+       char    *wc_font_text;          /* points to font name for text win    */
+       int     wc_fontsiz_map;         /* font size for the map win           */
+       int     wc_fontsiz_message;     /* font size for the message window    */
+       int     wc_fontsiz_status;      /* font size for the status window     */
+       int     wc_fontsiz_menu;        /* font size for the menu window       */
+       int     wc_fontsiz_text;        /* font size for text windows          */
+       int     wc_scroll_amount;       /* scroll this amount at scroll_margin */
+       int     wc_scroll_margin;       /* scroll map when this far from
+                                               the edge */
+       int     wc_map_mode;            /* specify map viewing options, mostly
+                                               for backward compatibility */
+       int     wc_player_selection;    /* method of choosing character */
+       boolean wc_splash_screen;       /* display an opening splash screen or not */
+       boolean wc_popup_dialog;        /* put queries in pop up dialogs instead of
+                                               in the message window */
+       boolean wc_eight_bit_input;     /* allow eight bit input               */
+       boolean wc_mouse_support;       /* allow mouse support */
+       boolean wc2_fullscreen;         /* run fullscreen */
+       boolean wc2_softkeyboard;       /* use software keyboard */
+       boolean wc2_wraptext;           /* wrap text */
+
+       boolean  cmdassist;     /* provide detailed assistance for some commands */
+       boolean  obsolete;      /* obsolete options can point at this, it isn't used */
+       /* Items which belong in flags, but are here to allow save compatibility */
+       boolean  lootabc;       /* use "a/b/c" rather than "o/i/b" when looting */
+       boolean  showrace;      /* show hero glyph by race rather than by role */
+       boolean  travelcmd;     /* allow travel command */
+       int      runmode;       /* update screen display during run moves */
+#ifdef AUTOPICKUP_EXCEPTIONS
+       struct autopickup_exception *autopickup_exceptions[2];
+#define AP_LEAVE 0
+#define AP_GRAB         1
+#endif
+#ifdef WIN32CON
+#define MAX_ALTKEYHANDLER 25
+       char     altkeyhandler[MAX_ALTKEYHANDLER];
+#endif
+};
+
+/*
+ * Old deprecated names
+ */
+#ifdef TTY_GRAPHICS
+#define eight_bit_tty wc_eight_bit_input
+#endif
+#ifdef TEXTCOLOR
+#define use_color wc_color
+#endif
+#define hilite_pet wc_hilite_pet
+#define use_inverse wc_inverse
+#ifdef MAC_GRAPHICS_ENV
+#define large_font obsolete
+#endif
+#ifdef MAC
+#define popup_dialog wc_popup_dialog
+#endif
+#define preload_tiles wc_preload_tiles
+
+extern NEARDATA struct flag flags;
+extern NEARDATA struct instance_flags iflags;
+
+/* runmode options */
+#define RUN_TPORT      0       /* don't update display until movement stops */
+#define RUN_LEAP       1       /* update display every 7 steps */
+#define RUN_STEP       2       /* update display every single step */
+#define RUN_CRAWL      3       /* walk w/ extra delay after each update */
+
+#endif /* FLAG_H */
diff --git a/include/func_tab.h b/include/func_tab.h
new file mode 100644 (file)
index 0000000..769801d
--- /dev/null
@@ -0,0 +1,23 @@
+/*     SCCS Id: @(#)func_tab.h 3.4     1992/04/03      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef FUNC_TAB_H
+#define FUNC_TAB_H
+
+struct func_tab {
+       char f_char;
+       boolean can_if_buried;
+       int NDECL((*f_funct));
+       const char *f_text;
+};
+
+struct ext_func_tab {
+       const char *ef_txt, *ef_desc;
+       int NDECL((*ef_funct));
+       boolean can_if_buried;
+};
+
+extern struct ext_func_tab extcmdlist[];
+
+#endif /* FUNC_TAB_H */
diff --git a/include/gem_rsc.h b/include/gem_rsc.h
new file mode 100644 (file)
index 0000000..c499d00
--- /dev/null
@@ -0,0 +1,65 @@
+/* resource set indices for GEM_RSC */
+
+#define MENU               0 /* menu */
+#define DOABOUT           12 /* STRING in tree MENU */
+#define DOQUIT            30 /* STRING in tree MENU */
+
+#define STATUSLINE         1 /* form/dialog */
+#define GRABSTATUS         1 /* BOX in tree STATUSLINE */
+
+#define MAPWIN             2 /* form/dialog */
+#define MAPBOX             0 /* BOX in tree MAPWIN */
+#define MAPCURSOR          1 /* IBOX in tree MAPWIN */
+
+#define ABOUT              3 /* form/dialog */
+#define FLYABOUT           0 /* BOX in tree ABOUT */
+#define OKABOUT            1 /* BUTTON in tree ABOUT */
+#define NETHACKIMG0        3 /* ICON in tree ABOUT */
+
+#define LINES              4 /* form/dialog */
+#define FLYLINES           0 /* BOX in tree LINES */
+#define QLINE              1 /* BUTTON in tree LINES */
+#define LINESLIST          2 /* USERDEF in tree LINES */
+
+#define YNCHOICE           5 /* form/dialog */
+#define FLYYNCHOICE        0 /* BOX in tree YNCHOICE */
+#define YNPROMPT           1 /* TEXT in tree YNCHOICE */
+#define SOMECHARS          2 /* BOX in tree YNCHOICE */
+#define YN1                3 /* BUTTON in tree YNCHOICE */
+#define YNN               53 /* BUTTON in tree YNCHOICE */
+#define ANYCHAR           55 /* BOX in tree YNCHOICE */
+#define CHOSENCH          56 /* FBOXTEXT in tree YNCHOICE */
+#define COUNT             58 /* FBOXTEXT in tree YNCHOICE */
+#define YNOK              59 /* BUTTON in tree YNCHOICE */
+
+#define LINEGET            6 /* form/dialog */
+#define FLYLINEGET         0 /* BOX in tree LINEGET */
+#define LGPROMPT           1 /* TEXT in tree LINEGET */
+#define LGREPLY            2 /* FBOXTEXT in tree LINEGET */
+#define QLG                3 /* BUTTON in tree LINEGET */
+#define LGOK               4 /* BUTTON in tree LINEGET */
+
+#define DIRECTION          7 /* form/dialog */
+#define FLYDIRECTION       0 /* BOX in tree DIRECTION */
+#define DIR1               5 /* BOXTEXT in tree DIRECTION */
+#define DIR9              21 /* BOXTEXT in tree DIRECTION */
+#define DIRDOWN           23 /* BOXTEXT in tree DIRECTION */
+#define DIRUP             25 /* BOXTEXT in tree DIRECTION */
+
+#define MSGWIN             8 /* form/dialog */
+#define UPMSG              1 /* BOXCHAR in tree MSGWIN */
+#define GRABMSGWIN         2 /* BOX in tree MSGWIN */
+#define DNMSG              3 /* BOXCHAR in tree MSGWIN */
+#define MSGLINES           4 /* USERDEF in tree MSGWIN */
+
+#define NAMEGET            9 /* form/dialog */
+#define FLYNAMEGET         0 /* BOX in tree NAMEGET */
+#define PLNAME             2 /* FBOXTEXT in tree NAMEGET */
+#define NETHACKPICTURE     4 /* BOXTEXT in tree NAMEGET */
+
+#define PAGER             10 /* form/dialog */
+#define FLYPAGER           0 /* BOX in tree PAGER */
+#define QPAGER             1 /* BUTTON in tree PAGER */
+
+#define NHICON            11 /* form/dialog */
+
diff --git a/include/global.h b/include/global.h
new file mode 100644 (file)
index 0000000..8311246
--- /dev/null
@@ -0,0 +1,345 @@
+/*     SCCS Id: @(#)global.h   3.4     2003/08/31      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+#include <stdio.h>
+
+
+/* #define BETA        */      /* if a beta-test copy  [MRS] */
+
+/*
+ * Files expected to exist in the playground directory.
+ */
+
+#define RECORD       "record"  /* file containing list of topscorers */
+#define HELP         "help"    /* file containing command descriptions */
+#define SHELP        "hh"      /* abbreviated form of the same */
+#define DEBUGHELP     "wizhelp" /* file containing debug mode cmds */
+#define RUMORFILE     "rumors" /* file with fortune cookies */
+#define ORACLEFILE    "oracles" /* file with oracular information */
+#define DATAFILE      "data"   /* file giving the meaning of symbols used */
+#define CMDHELPFILE   "cmdhelp" /* file telling what commands do */
+#define HISTORY       "history" /* file giving nethack's history */
+#define LICENSE       "license" /* file with license information */
+#define OPTIONFILE    "opthelp" /* file explaining runtime options */
+#define OPTIONS_USED  "options" /* compile-time options, for #version */
+
+#define LEV_EXT ".lev"         /* extension for special level files */
+
+
+/* Assorted definitions that may depend on selections in config.h. */
+
+/*
+ * for DUMB preprocessor and compiler, e.g., cpp and pcc supplied
+ * with Microport SysV/AT, which have small symbol tables;
+ * DUMB if needed is defined in CFLAGS
+ */
+#ifdef DUMB
+#ifdef BITFIELDS
+#undef BITFIELDS
+#endif
+#ifndef STUPID
+#define STUPID
+#endif
+#endif /* DUMB */
+
+/*
+ * type xchar: small integers in the range 0 - 127, usually coordinates
+ * although they are nonnegative they must not be declared unsigned
+ * since otherwise comparisons with signed quantities are done incorrectly
+ */
+typedef schar  xchar;
+#ifndef SKIP_BOOLEAN
+typedef xchar  boolean;                /* 0 or 1 */
+#endif
+
+#ifndef TRUE           /* defined in some systems' native include files */
+#define TRUE   ((boolean)1)
+#define FALSE  ((boolean)0)
+#endif
+
+#ifndef STRNCMPI
+# ifndef __SASC_60             /* SAS/C already shifts to stricmp */
+#  define strcmpi(a,b) strncmpi((a),(b),-1)
+# endif
+#endif
+
+/* comment out to test effects of each #define -- these will probably
+ * disappear eventually
+ */
+#ifdef INTERNAL_COMP
+# define RLECOMP       /* run-length compression of levl array - JLee */
+# define ZEROCOMP      /* zero-run compression of everything - Olaf Seibert */
+#endif
+
+/* #define SPECIALIZATION */   /* do "specialized" version of new topology */
+
+
+#ifdef BITFIELDS
+#define Bitfield(x,n)  unsigned x:n
+#else
+#define Bitfield(x,n)  uchar x
+#endif
+
+#ifdef UNWIDENED_PROTOTYPES
+# define CHAR_P char
+# define SCHAR_P schar
+# define UCHAR_P uchar
+# define XCHAR_P xchar
+# define SHORT_P short
+#ifndef SKIP_BOOLEAN
+# define BOOLEAN_P boolean
+#endif
+# define ALIGNTYP_P aligntyp
+#else
+# ifdef WIDENED_PROTOTYPES
+#  define CHAR_P int
+#  define SCHAR_P int
+#  define UCHAR_P int
+#  define XCHAR_P int
+#  define SHORT_P int
+#  define BOOLEAN_P int
+#  define ALIGNTYP_P int
+# endif
+#endif
+#if defined(ULTRIX_PROTO) && !defined(__STDC__)
+/* The ultrix 2.0 and 2.1 compilers (on Ultrix 4.0 and 4.2 respectively) can't
+ * handle "struct obj *" constructs in prototypes.  Their bugs are different,
+ * but both seem to work if we put "void*" in the prototype instead.  This
+ * gives us minimal prototype checking but avoids the compiler bugs.
+ *
+ * OBJ_P and MONST_P should _only_ be used for declaring function pointers.
+ */
+#define OBJ_P void*
+#define MONST_P void*
+#else
+#define OBJ_P struct obj*
+#define MONST_P struct monst*
+#endif
+
+#define SIZE(x) (int)(sizeof(x) / sizeof(x[0]))
+
+
+/* A limit for some NetHack int variables.  It need not, and for comparable
+ * scoring should not, depend on the actual limit on integers for a
+ * particular machine, although it is set to the minimum required maximum
+ * signed integer for C (2^15 -1).
+ */
+#define LARGEST_INT    32767
+
+
+#ifdef REDO
+#define Getchar pgetchar
+#endif
+
+
+#include "coord.h"
+/*
+ * Automatic inclusions for the subsidiary files.
+ * Please don't change the order.  It does matter.
+ */
+
+#ifdef VMS
+#include "vmsconf.h"
+#endif
+
+#ifdef UNIX
+#include "unixconf.h"
+#endif
+
+#ifdef OS2
+#include "os2conf.h"
+#endif
+
+#ifdef MSDOS
+#include "pcconf.h"
+#endif
+
+#ifdef TOS
+#include "tosconf.h"
+#endif
+
+#ifdef AMIGA
+#include "amiconf.h"
+#endif
+
+#ifdef MAC
+#include "macconf.h"
+#endif
+
+#ifdef __BEOS__
+#include "beconf.h"
+#endif
+
+#ifdef WIN32
+#ifdef WIN_CE
+#include "wceconf.h"
+#else
+#include "ntconf.h"
+#endif
+#endif
+
+/* Displayable name of this port; don't redefine if defined in *conf.h */
+#ifndef PORT_ID
+# ifdef AMIGA
+#  define PORT_ID      "Amiga"
+# endif
+# ifdef MAC
+#  define PORT_ID      "Mac"
+# endif
+# ifdef MSDOS
+#  ifdef PC9800
+#  define PORT_ID      "PC-9800"
+#  else
+#  define PORT_ID      "PC"
+#  endif
+#  ifdef DJGPP
+#  define PORT_SUB_ID  "djgpp"
+#  else
+#   ifdef OVERLAY
+#  define PORT_SUB_ID  "overlaid"
+#   else
+#  define PORT_SUB_ID  "non-overlaid"
+#   endif
+#  endif
+# endif
+# ifdef OS2
+#  define PORT_ID      "OS/2"
+# endif
+# ifdef TOS
+#  define PORT_ID      "ST"
+# endif
+# ifdef UNIX
+#  define PORT_ID      "Unix"
+# endif
+# ifdef VMS
+#  define PORT_ID      "VMS"
+# endif
+# ifdef WIN32
+#  define PORT_ID      "Windows"
+#  ifndef PORT_SUB_ID
+#   ifdef MSWIN_GRAPHICS
+#    define PORT_SUB_ID        "graphical"
+#   else
+#    define PORT_SUB_ID        "tty"
+#   endif
+#  endif
+# endif
+#endif
+
+#if defined(MICRO)
+#if !defined(AMIGA) && !defined(TOS) && !defined(OS2_HPFS)
+#define SHORT_FILENAMES                /* filenames are 8.3 */
+#endif
+#endif
+
+#ifdef VMS
+/* vms_exit() (sys/vms/vmsmisc.c) expects the non-VMS EXIT_xxx values below.
+ * these definitions allow all systems to be treated uniformly, provided
+ * main() routines do not terminate with return(), whose value is not
+ * so massaged.
+ */
+# ifdef EXIT_SUCCESS
+#  undef EXIT_SUCCESS
+# endif
+# ifdef EXIT_FAILURE
+#  undef EXIT_FAILURE
+# endif
+#endif
+
+#ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+#endif
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+#if defined(X11_GRAPHICS) || defined(QT_GRAPHICS) || defined(GNOME_GRAPHICS) || defined(MSWIN_GRAPHICS)
+# ifndef USE_TILES
+#  define USE_TILES            /* glyph2tile[] will be available */
+# endif
+#endif
+#if defined(AMII_GRAPHICS) || defined(GEM_GRAPHICS)
+# ifndef USE_TILES
+#  define USE_TILES
+# endif
+#endif
+
+
+#define Sprintf  (void) sprintf
+#define Strcat   (void) strcat
+#define Strcpy   (void) strcpy
+#ifdef NEED_VARARGS
+#define Vprintf  (void) vprintf
+#define Vfprintf (void) vfprintf
+#define Vsprintf (void) vsprintf
+#endif
+
+
+/* primitive memory leak debugging; see alloc.c */
+#ifdef MONITOR_HEAP
+extern long *FDECL(nhalloc, (unsigned int,const char *,int));
+extern void FDECL(nhfree, (genericptr_t,const char *,int));
+# ifndef __FILE__
+#  define __FILE__ ""
+# endif
+# ifndef __LINE__
+#  define __LINE__ 0
+# endif
+# define alloc(a) nhalloc(a,__FILE__,(int)__LINE__)
+# define free(a) nhfree(a,__FILE__,(int)__LINE__)
+#else  /* !MONITOR_HEAP */
+extern long *FDECL(alloc, (unsigned int));             /* alloc.c */
+#endif
+
+/* Used for consistency checks of various data files; declare it here so
+   that utility programs which include config.h but not hack.h can see it. */
+struct version_info {
+       unsigned long   incarnation;    /* actual version number */
+       unsigned long   feature_set;    /* bitmask of config settings */
+       unsigned long   entity_count;   /* # of monsters and objects */
+       unsigned long   struct_sizes;   /* size of key structs */
+};
+
+
+/*
+ * Configurable internal parameters.
+ *
+ * Please be very careful if you are going to change one of these.  Any
+ * changes in these parameters, unless properly done, can render the
+ * executable inoperative.
+ */
+
+/* size of terminal screen is (at least) (ROWNO+3) by COLNO */
+#define COLNO  80
+#define ROWNO  21
+
+#define MAXNROFROOMS   40      /* max number of rooms per level */
+#define MAX_SUBROOMS   24      /* max # of subrooms in a given room */
+#define DOORMAX                120     /* max number of doors per level */
+
+#define BUFSZ          256     /* for getlin buffers */
+#define QBUFSZ         128     /* for building question text */
+#define TBUFSZ         300     /* toplines[] buffer max msg: 3 81char names */
+                               /* plus longest prefix plus a few extra words */
+
+#define PL_NSIZ                32      /* name of player, ghost, shopkeeper */
+#define PL_CSIZ                32      /* sizeof pl_character */
+#define PL_FSIZ                32      /* fruit name */
+#define PL_PSIZ                63      /* player-given names for pets, other
+                                * monsters, objects */
+
+#define MAXDUNGEON     16      /* current maximum number of dungeons */
+#define MAXLEVEL       32      /* max number of levels in one dungeon */
+#define MAXSTAIRS      1       /* max # of special stairways in a dungeon */
+#define ALIGNWEIGHT    4       /* generation weight of alignment */
+
+#define MAXULEV                30      /* max character experience level */
+
+#define MAXMONNO       120     /* extinct monst after this number created */
+#define MHPMAX         500     /* maximum monster hp */
+
+#endif /* GLOBAL_H */
diff --git a/include/hack.h b/include/hack.h
new file mode 100644 (file)
index 0000000..b7b5835
--- /dev/null
@@ -0,0 +1,341 @@
+/*     SCCS Id: @(#)hack.h     3.4     2001/04/12      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef HACK_H
+#define HACK_H
+
+#ifndef CONFIG_H
+#include "config.h"
+#endif
+
+/*     For debugging beta code.        */
+#ifdef BETA
+#define Dpline pline
+#endif
+
+#define TELL           1
+#define NOTELL         0
+#define ON             1
+#define OFF            0
+#define BOLT_LIM       8 /* from this distance ranged attacks will be made */
+#define MAX_CARR_CAP   1000    /* so that boulders can be heavier */
+#define DUMMY { 0 }
+
+/* symbolic names for capacity levels */
+#define UNENCUMBERED   0
+#define SLT_ENCUMBER   1       /* Burdened */
+#define MOD_ENCUMBER   2       /* Stressed */
+#define HVY_ENCUMBER   3       /* Strained */
+#define EXT_ENCUMBER   4       /* Overtaxed */
+#define OVERLOADED     5       /* Overloaded */
+
+/* Macros for how a rumor was delivered in outrumor() */
+#define BY_ORACLE      0
+#define BY_COOKIE      1
+#define BY_PAPER       2
+#define BY_OTHER       9
+
+#ifdef STEED
+/* Macros for why you are no longer riding */
+#define DISMOUNT_GENERIC       0
+#define DISMOUNT_FELL          1
+#define DISMOUNT_THROWN                2
+#define DISMOUNT_POLY          3
+#define DISMOUNT_ENGULFED      4
+#define DISMOUNT_BONES         5
+#define DISMOUNT_BYCHOICE      6
+#endif
+
+/* Special returns from mapglyph() */
+#define MG_CORPSE      0x01
+#define MG_INVIS       0x02
+#define MG_DETECT      0x04
+#define MG_PET         0x08
+#define MG_RIDDEN      0x10
+
+/* sellobj_state() states */
+#define SELL_NORMAL    (0)
+#define SELL_DELIBERATE        (1)
+#define SELL_DONTSELL  (2)
+
+/*
+ * This is the way the game ends.  If these are rearranged, the arrays
+ * in end.c and topten.c will need to be changed.  Some parts of the
+ * code assume that PANIC separates the deaths from the non-deaths.
+ */
+#define DIED            0
+#define CHOKING                 1
+#define POISONING       2
+#define STARVING        3
+#define DROWNING        4
+#define BURNING                 5
+#define DISSOLVED       6
+#define CRUSHING        7
+#define STONING                 8
+#define TURNED_SLIME    9
+#define GENOCIDED      10
+#define PANICKED       11
+#define TRICKED                12
+#define QUIT           13
+#define ESCAPED                14
+#define ASCENDED       15
+
+#include "align.h"
+#include "dungeon.h"
+#include "monsym.h"
+#include "mkroom.h"
+#include "objclass.h"
+#include "youprop.h"
+#include "wintype.h"
+#include "decl.h"
+#include "timeout.h"
+
+NEARDATA extern coord bhitpos; /* place where throw or zap hits or stops */
+
+/* types of calls to bhit() */
+#define ZAPPED_WAND    0
+#define THROWN_WEAPON  1
+#define KICKED_WEAPON  2
+#define FLASHED_LIGHT  3
+#define INVIS_BEAM     4
+
+#define MATCH_WARN_OF_MON(mon)  (Warn_of_mon && flags.warntype && \
+                                (flags.warntype & (mon)->data->mflags2))
+
+#include "trap.h"
+#include "flag.h"
+#include "rm.h"
+#include "vision.h"
+#include "display.h"
+#include "engrave.h"
+#include "rect.h"
+#include "region.h"
+
+#ifdef USE_TRAMPOLI /* This doesn't belong here, but we have little choice */
+#undef NDECL
+#define NDECL(f) f()
+#endif
+
+#include "extern.h"
+#include "winprocs.h"
+
+#ifdef USE_TRAMPOLI
+#include "wintty.h"
+#undef WINTTY_H
+#include "trampoli.h"
+#undef EXTERN_H
+#include "extern.h"
+#endif /* USE_TRAMPOLI */
+
+#define NO_SPELL       0
+
+/* flags to control makemon() */
+#define NO_MM_FLAGS      0x00  /* use this rather than plain 0 */
+#define NO_MINVENT       0x01  /* suppress minvent when creating mon */
+#define MM_NOWAIT        0x02  /* don't set STRAT_WAITMASK flags */
+#define MM_EDOG                  0x04  /* add edog structure */
+#define MM_EMIN                  0x08  /* add emin structure */
+#define MM_ANGRY         0x10  /* monster is created angry */
+#define MM_NONAME        0x20  /* monster is not christened */
+#define MM_NOCOUNTBIRTH          0x40  /* don't increment born counter (for revival) */
+#define MM_IGNOREWATER   0x80  /* ignore water when positioning */
+#define MM_ADJACENTOK    0x100 /* it is acceptable to use adjacent coordinates */
+
+/* special mhpmax value when loading bones monster to flag as extinct or genocided */
+#define DEFUNCT_MONSTER        (-100)
+
+/* flags for special ggetobj status returns */
+#define ALL_FINISHED     0x01  /* called routine already finished the job */
+
+/* flags to control query_objlist() */
+#define BY_NEXTHERE      0x1   /* follow objlist by nexthere field */
+#define AUTOSELECT_SINGLE 0x2  /* if only 1 object, don't ask */
+#define USE_INVLET       0x4   /* use object's invlet */
+#define INVORDER_SORT    0x8   /* sort objects by packorder */
+#define SIGNAL_NOMENU    0x10  /* return -1 rather than 0 if none allowed */
+#define FEEL_COCKATRICE   0x20  /* engage cockatrice checks and react */
+
+/* Flags to control query_category() */
+/* BY_NEXTHERE used by query_category() too, so skip 0x01 */
+#define UNPAID_TYPES 0x02
+#define GOLD_TYPES   0x04
+#define WORN_TYPES   0x08
+#define ALL_TYPES    0x10
+#define BILLED_TYPES 0x20
+#define CHOOSE_ALL   0x40
+#define BUC_BLESSED  0x80
+#define BUC_CURSED   0x100
+#define BUC_UNCURSED 0x200
+#define BUC_UNKNOWN  0x400
+#define BUC_ALLBKNOWN (BUC_BLESSED|BUC_CURSED|BUC_UNCURSED)
+#define ALL_TYPES_SELECTED -2
+
+/* Flags to control find_mid() */
+#define FM_FMON               0x01     /* search the fmon chain */
+#define FM_MIGRATE     0x02    /* search the migrating monster chain */
+#define FM_MYDOGS      0x04    /* search mydogs */
+#define FM_EVERYWHERE  (FM_FMON | FM_MIGRATE | FM_MYDOGS)
+
+/* Flags to control pick_[race,role,gend,align] routines in role.c */
+#define PICK_RANDOM    0
+#define PICK_RIGID     1
+
+/* Flags to control dotrap() in trap.c */
+#define NOWEBMSG       0x01    /* suppress stumble into web message */
+#define FORCEBUNGLE    0x02    /* adjustments appropriate for bungling */
+#define RECURSIVETRAP  0x04    /* trap changed into another type this same turn */
+
+/* Flags to control test_move in hack.c */
+#define DO_MOVE                0       /* really doing the move */
+#define TEST_MOVE      1       /* test a normal move (move there next) */
+#define TEST_TRAV      2       /* test a future travel location */
+
+/*** some utility macros ***/
+#define yn(query) yn_function(query,ynchars, 'n')
+#define ynq(query) yn_function(query,ynqchars, 'q')
+#define ynaq(query) yn_function(query,ynaqchars, 'y')
+#define nyaq(query) yn_function(query,ynaqchars, 'n')
+#define nyNaq(query) yn_function(query,ynNaqchars, 'n')
+#define ynNaq(query) yn_function(query,ynNaqchars, 'y')
+
+/* Macros for scatter */
+#define VIS_EFFECTS    0x01    /* display visual effects */
+#define MAY_HITMON     0x02    /* objects may hit monsters */
+#define MAY_HITYOU     0x04    /* objects may hit you */
+#define MAY_HIT                (MAY_HITMON|MAY_HITYOU)
+#define MAY_DESTROY    0x08    /* objects may be destroyed at random */
+#define MAY_FRACTURE   0x10    /* boulders & statues may fracture */
+
+/* Macros for launching objects */
+#define ROLL           0x01    /* the object is rolling */
+#define FLING          0x02    /* the object is flying thru the air */
+#define LAUNCH_UNSEEN  0x40    /* hero neither caused nor saw it */
+#define LAUNCH_KNOWN   0x80    /* the hero caused this by explicit action */
+
+/* Macros for explosion types */
+#define EXPL_DARK      0
+#define EXPL_NOXIOUS   1
+#define EXPL_MUDDY     2
+#define EXPL_WET       3
+#define EXPL_MAGICAL   4
+#define EXPL_FIERY     5
+#define EXPL_FROSTY    6
+#define EXPL_MAX       7
+
+/* Macros for messages referring to hands, eyes, feet, etc... */
+#define ARM 0
+#define EYE 1
+#define FACE 2
+#define FINGER 3
+#define FINGERTIP 4
+#define FOOT 5
+#define HAND 6
+#define HANDED 7
+#define HEAD 8
+#define LEG 9
+#define LIGHT_HEADED 10
+#define NECK 11
+#define SPINE 12
+#define TOE 13
+#define HAIR 14
+#define BLOOD 15
+#define LUNG 16
+#define NOSE 17
+#define STOMACH 18
+
+/* Flags to control menus */
+#define MENUTYPELEN sizeof("traditional ")
+#define MENU_TRADITIONAL 0
+#define MENU_COMBINATION 1
+#define MENU_PARTIAL    2
+#define MENU_FULL       3
+
+#define MENU_SELECTED  TRUE
+#define MENU_UNSELECTED FALSE
+
+/*
+ * Option flags
+ * Each higher number includes the characteristics of the numbers
+ * below it.
+ */
+#define SET_IN_FILE    0 /* config file option only */
+#define SET_VIA_PROG   1 /* may be set via extern program, not seen in game */
+#define DISP_IN_GAME   2 /* may be set via extern program, displayed in game */
+#define SET_IN_GAME    3 /* may be set via extern program or set in the game */
+
+#define FEATURE_NOTICE_VER(major,minor,patch) (((unsigned long)major << 24) | \
+       ((unsigned long)minor << 16) | \
+       ((unsigned long)patch << 8) | \
+       ((unsigned long)0))
+
+#define FEATURE_NOTICE_VER_MAJ   (flags.suppress_alert >> 24)
+#define FEATURE_NOTICE_VER_MIN   (((unsigned long)(0x0000000000FF0000L & flags.suppress_alert)) >> 16)
+#define FEATURE_NOTICE_VER_PATCH  (((unsigned long)(0x000000000000FF00L & flags.suppress_alert)) >>  8)
+
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef min
+#define min(x,y) ((x) < (y) ? (x) : (y))
+#endif
+#define plur(x) (((x) == 1) ? "" : "s")
+
+#define ARM_BONUS(obj) (objects[(obj)->otyp].a_ac + (obj)->spe \
+                        - min((int)greatest_erosion(obj),objects[(obj)->otyp].a_ac))
+
+#define makeknown(x)   discover_object((x),TRUE,TRUE)
+#define distu(xx,yy)   dist2((int)(xx),(int)(yy),(int)u.ux,(int)u.uy)
+#define onlineu(xx,yy) online2((int)(xx),(int)(yy),(int)u.ux,(int)u.uy)
+
+#define rn1(x,y)       (rn2(x)+(y))
+
+/* negative armor class is randomly weakened to prevent invulnerability */
+#define AC_VALUE(AC)   ((AC) >= 0 ? (AC) : -rnd(-(AC)))
+
+#if defined(MICRO) && !defined(__DJGPP__)
+#define getuid() 1
+#define getlogin() ((char *)0)
+#endif /* MICRO */
+
+#if defined(OVERLAY)&&(defined(OVL0)||defined(OVL1)||defined(OVL2)||defined(OVL3)||defined(OVLB))
+# define USE_OVLx
+# define STATIC_DCL extern
+# define STATIC_OVL
+# ifdef OVLB
+#  define STATIC_VAR
+# else
+#  define STATIC_VAR extern
+# endif
+
+#else  /* !OVERLAY || (!OVL0 && !OVL1 && !OVL2 && !OVL3 && !OVLB) */
+# define STATIC_DCL static
+# define STATIC_OVL static
+# define STATIC_VAR static
+
+/* If not compiling an overlay, compile everything. */
+# define OVL0  /* highest priority */
+# define OVL1
+# define OVL2
+# define OVL3  /* lowest specified priority */
+# define OVLB  /* the base overlay segment */
+#endif /* OVERLAY && (OVL0 || OVL1 || OVL2 || OVL3 || OVLB) */
+
+/* Macro for a few items that are only static if we're not overlaid.... */
+#if defined(USE_TRAMPOLI) || defined(USE_OVLx)
+# define STATIC_PTR
+#else
+# define STATIC_PTR static
+#endif
+
+/* The function argument to qsort() requires a particular
+ * calling convention under WINCE which is not the default
+ * in that environment.
+ */
+#if defined(WIN_CE)
+# define CFDECLSPEC __cdecl
+#else
+# define CFDECLSPEC
+#endif
+#endif /* HACK_H */
diff --git a/include/lev.h b/include/lev.h
new file mode 100644 (file)
index 0000000..afc845a
--- /dev/null
@@ -0,0 +1,49 @@
+/*     SCCS Id: @(#)lev.h      3.4     1994/03/18      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*     Common include file for save and restore routines */
+
+#ifndef LEV_H
+#define LEV_H
+
+#define COUNT_SAVE     0x1
+#define WRITE_SAVE     0x2
+#define FREE_SAVE      0x4
+
+/* operations of the various saveXXXchn & co. routines */
+#define perform_bwrite(mode)   ((mode) & (COUNT_SAVE|WRITE_SAVE))
+#define release_data(mode)     ((mode) & FREE_SAVE)
+
+/* The following are used in mkmaze.c */
+struct container {
+       struct container *next;
+       xchar x, y;
+       short what;
+       genericptr_t list;
+};
+
+#define CONS_OBJ   0
+#define CONS_MON   1
+#define CONS_HERO  2
+#define CONS_TRAP  3
+
+struct bubble {
+       xchar x, y;     /* coordinates of the upper left corner */
+       schar dx, dy;   /* the general direction of the bubble's movement */
+       uchar *bm;      /* pointer to the bubble bit mask */
+       struct bubble *prev, *next; /* need to traverse the list up and down */
+       struct container *cons;
+};
+
+/* used in light.c */
+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 */
+    genericptr_t id;   /* source's identifier */
+} light_source;
+
+#endif /* LEV_H */
diff --git a/include/load_img.h b/include/load_img.h
new file mode 100644 (file)
index 0000000..eb4a27d
--- /dev/null
@@ -0,0 +1,46 @@
+
+/* ------------------------------------------- */
+#define XIMG      0x58494D47
+
+/* Header of GEM Image Files   */
+typedef struct IMG_HEADER{
+  short version;  /* Img file format version (1) */
+  short length;   /* Header length in words  (8) */
+  short planes;   /* Number of bit-planes    (1) */
+  short pat_len;  /* length of Patterns      (2) */
+  short pix_w;    /* Pixel width in 1/1000 mmm  (372)    */
+  short pix_h;    /* Pixel height in 1/1000 mmm (372)    */
+  short img_w;    /* Pixels per line (=(x+7)/8 Bytes)    */
+  short img_h;    /* Total number of lines               */
+  long  magic;    /* Contains "XIMG" if standard color   */
+  short paltype;  /* palette type (0=RGB (short each)) */
+  short *palette;      /* palette etc.                        */
+  char *addr;     /* Address for the depacked bit-planes */
+} IMG_header;
+
+/* ------------------------------------------- */
+/* error codes */
+#define ERR_HEADER      1
+#define ERR_ALLOC       2
+#define ERR_FILE        3
+#define ERR_DEPACK      4
+#define ERR_COLOR       5
+
+/* saves the current colorpalette with col colors in palette */
+void get_colors(int handle, short *palette, int col);
+
+/* sets col colors from palette */
+void img_set_colors(int handle,short *palette, int col);
+
+/* converts MFDB  of size from standard to deviceformat (0 if succeded, else error). */
+int convert(MFDB *, long );
+
+/* transforms image in VDI-Device format */
+int transform_img(MFDB *);
+
+/* Loads & depacks IMG (0 if succeded, else error). */
+/* Bitplanes are one after another in address IMG_HEADER.addr. */
+int depack_img(char *, IMG_header *);
+
+/* Halves IMG in Device-format, dest memory has to be allocated*/
+int half_img(MFDB *,MFDB *);
diff --git a/include/mac-carbon.h b/include/mac-carbon.h
new file mode 100644 (file)
index 0000000..9be633a
--- /dev/null
@@ -0,0 +1,32 @@
+/*     SCCS Id: @(#)mac-carbon.h       3.4     2003/06/01      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 2003. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*     Compiler prefix file for the Macintosh Carbon port.
+ *
+ *     IMPORTANT: This file is intended only as a compiler prefix
+ *     file and must NEVER be included by other source (.c or .h)
+ *     files.
+ *
+ *     Usage for MacOS X Project Builder:
+ *             Project menu -> Edit Active Target '_target_' ->
+ *             target settings dialog -> Settings -> Simple View ->
+ *             GCC Compiler Settings ->
+ *             set "Prefix Header" to include/mac-carbon.h
+ *
+ *     Usage for Metrowerks CodeWarrior:
+ *             Edit menu -> _target_ Settings -> Language Settings ->
+ *             C/C++ Language ->
+ *             set "Prefix File" to include/mac-carbon.h
+ */
+
+#define MAC
+#undef UNIX
+
+/* May already be defined by CodeWarrior as 0 or 1 */
+#ifdef TARGET_API_MAC_CARBON
+# undef TARGET_API_MAC_CARBON
+#endif
+#define TARGET_API_MAC_CARBON 1
+
+#define GCC_WARN
diff --git a/include/mac-qt.h b/include/mac-qt.h
new file mode 100644 (file)
index 0000000..8a5a128
--- /dev/null
@@ -0,0 +1,33 @@
+/*     SCCS Id: @(#)mac-qt.h   3.4     2003/06/01      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 2003. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*     Compiler prefix file for the Macintosh Qt port.
+ *
+ *     IMPORTANT: This file is intended only as a compiler prefix
+ *     file and must NEVER be included by other source (.c or .h)
+ *     files.
+ *
+ *     Usage for MacOS X Project Builder:
+ *             Project menu -> Edit Active Target '_target_' ->
+ *             target settings dialog -> Settings -> Simple View ->
+ *             GCC Compiler Settings ->
+ *             set "Prefix Header" to include/mac-qt.h
+ *
+ *     Usage for Metrowerks CodeWarrior:
+ *             Edit menu -> _target_ Settings -> Language Settings ->
+ *             C/C++ Language ->
+ *             set "Prefix File" to include/mac-qt.h
+ */
+
+#undef MAC
+#define UNIX
+#define BSD
+
+/* May already be defined by CodeWarrior as 0 or 1 */
+#ifdef TARGET_API_MAC_CARBON
+# undef TARGET_API_MAC_CARBON
+#endif
+#define TARGET_API_MAC_CARBON 0
+
+#define GCC_WARN
diff --git a/include/mac-term.h b/include/mac-term.h
new file mode 100644 (file)
index 0000000..f87afa8
--- /dev/null
@@ -0,0 +1,34 @@
+/*     SCCS Id: @(#)mac-term.h 3.4     2003/06/01      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 2003. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*     Compiler prefix file for the MacOS X Terminal.app port.
+ *
+ *     IMPORTANT: This file is intended only as a compiler prefix
+ *     file and must NEVER be included by other source (.c or .h)
+ *     files.
+ *
+ *     Usage for MacOS X Project Builder:
+ *             Project menu -> Edit Active Target '_target_' ->
+ *             target settings dialog -> Settings -> Simple View ->
+ *             GCC Compiler Settings ->
+ *             set "Prefix Header" to include/mac-term.h
+ *
+ *     Usage for Metrowerks CodeWarrior:
+ *             Edit menu -> _target_ Settings -> Language Settings ->
+ *             C/C++ Language ->
+ *             set "Prefix File" to include/mac-term.h
+ */
+
+/* Stuff needed for the core of NetHack */
+#undef MAC
+#define UNIX
+#define BSD
+#define __FreeBSD__    /* Darwin is based on FreeBSD */
+#define GCC_WARN
+
+/* May already be defined by CodeWarrior as 0 or 1 */
+#ifdef TARGET_API_MAC_CARBON
+# undef TARGET_API_MAC_CARBON
+#endif
+#define TARGET_API_MAC_CARBON 0        /* Not Carbon */
diff --git a/include/macconf.h b/include/macconf.h
new file mode 100644 (file)
index 0000000..6bf58fa
--- /dev/null
@@ -0,0 +1,119 @@
+/*     SCCS Id: @(#)macconf.h  3.4     1999/10/25      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifdef MAC
+# ifndef MACCONF_H
+#  define MACCONF_H
+
+/*
+ * Compiler selection is based on the following symbols:
+ *
+ *  __SC__                     sc, a MPW 68k compiler
+ *  __MRC__                    mrc, a MPW PowerPC compiler
+ *     THINK_C                 Think C compiler
+ *     __MWERKS__              Metrowerks' Codewarrior compiler
+ *
+ * We use these early in config.h to define some needed symbols,
+ * including MAC.
+ #
+ # The Metrowerks compiler defines __STDC__ (which sets NHSTC) and uses
+ # WIDENED_PROTOTYPES (defined if UNWIDENED_PROTOTYPES is undefined and
+ # NHSTDC is defined).
+ */
+
+#ifndef __powerc
+# define MAC68K                /* 68K mac (non-powerpc) */
+#endif
+#ifndef TARGET_API_MAC_CARBON
+# define TARGET_API_MAC_CARBON 0
+#endif
+
+
+#ifndef __MACH__
+#define RANDOM
+#endif
+#define NO_SIGNAL              /* You wouldn't believe our signals ... */
+#define FILENAME 256
+#define NO_TERMS               /* For tty port (see wintty.h) */
+
+#define TEXTCOLOR              /* For Mac TTY interface */
+#define CHANGE_COLOR
+
+/* Use these two includes instead of system.h. */
+#include <string.h>
+#include <stdlib.h>
+
+/* Uncomment this line if your headers don't already define off_t */
+/*typedef long off_t;*/
+#include <time.h>      /* for time_t */
+
+/*
+ * Try and keep the number of files here to an ABSOLUTE minimum !
+ * include the relevant files in the relevant .c files instead !
+ */
+#if TARGET_API_MAC_CARBON
+  /* Avoid including <CarbonCore/fp.h> -- it has a conflicting expl() */
+# define __FP__
+# include <Carbon/Carbon.h>
+#else
+# include <MacTypes.h>
+#endif
+
+/*
+ * We could use the PSN under sys 7 here ...
+ * ...but it wouldn't matter...
+ */
+#define getpid() 1
+#define getuid() 1
+#define index strchr
+#define rindex strrchr
+
+#define Rand random
+extern void error(const char *,...);
+
+#if !defined(O_WRONLY)
+# ifdef __MWERKS__
+#  include <unix.h>
+# endif
+# include <fcntl.h>
+#endif
+
+/*
+ * Don't redefine these Unix IO functions when making LevComp or DgnComp for
+ * MPW.  With MPW, we make them into MPW tools, which use unix IO.  SPEC_LEV
+ * and DGN_COMP are defined when compiling for LevComp and DgnComp respectively.
+ */
+#if !((defined(__SC__) || defined(__MRC__) || defined(__MACH__)) && (defined(SPEC_LEV) || defined(DGN_COMP)))
+# define creat maccreat
+# define open macopen
+# define close macclose
+# define read macread
+# define write macwrite
+# define lseek macseek
+#ifdef __MWERKS__
+# define unlink _unlink
+#endif
+#endif
+
+#define YY_NEVER_INTERACTIVE 1
+
+# define TEXT_TYPE 'TEXT'
+# define LEVL_TYPE 'LEVL'
+# define BONE_TYPE 'BONE'
+# define SAVE_TYPE 'SAVE'
+# define PREF_TYPE 'PREF'
+# define DATA_TYPE 'DATA'
+# define MAC_CREATOR 'nh31' /* Registered with DTS ! */
+# define TEXT_CREATOR 'ttxt' /* Something the user can actually edit */
+
+/*
+ * Define PORT_HELP to be the name of the port-specfic help file.
+ * This file is included into the resource fork of the application.
+ */
+#define PORT_HELP "MacHelp"
+
+#define MAC_GRAPHICS_ENV
+
+# endif /* ! MACCONF_H */
+#endif /* MAC */
diff --git a/include/macpopup.h b/include/macpopup.h
new file mode 100644 (file)
index 0000000..bdeb966
--- /dev/null
@@ -0,0 +1,15 @@
+/*     SCCS Id: @(#)macpopup.h 3.4     1999/10/25      */
+/* Copyright (c) Nethack Develpment Team, 1999.                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MACPOPUP_H
+# define MACPOPUP_H
+
+/* ### mmodal.c ### */
+
+extern void FlashButton(DialogRef, short);
+extern char queued_resp(char *resp);
+extern char topl_yn_function(const char *query, const char *resp, char def);
+extern int get_line_from_key_queue(char *bufp);
+
+#endif /* MACPOPUP_H */
diff --git a/include/mactty.h b/include/mactty.h
new file mode 100644 (file)
index 0000000..279e7c0
--- /dev/null
@@ -0,0 +1,347 @@
+/*     SCCS Id: @(#)mactty.h   3.4     1993/03/01      */
+/* Copyright (c) Jon W{tte 1993.                                       */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+/*
+ * This header is the supported external interface for the "tty" window
+ * package. This package sports care-free handling of "dumb" tty windows
+ * (preferrably using monospaced fonts) - it does NOT remember the strings
+ * sent to it; rather, it uses an offscreen bitmap.
+ *
+ * For best performance, make sure it is aligned on a 32-pixel boundary
+ * (or at least a 16-pixel one) in black & white. For 24bit color,
+ * alignment doesn't matter, and for 8-bit color, alignment to every
+ * fourth pixel is most efficient.
+ *
+ * (c) Copyright 1993 Jon W{tte
+ */
+
+/*
+ * You should really not poke in the structures used by the tty window.
+ * However, since it uses the wRefCon of windows (by calling GetWRefCon
+ * and SetWRefCon) you lose that possibility. If you still want to store
+ * information about a window, the FIRST location _pointed to_ by the
+ * wRefCon will be a void * that you can use for whatever reasons. Don't
+ * take the address of this variable and expect it to stay the same
+ * across calls to the tty window.
+ *
+ * void * my_config_ptr = * ( void * * ) GetWRefCon ( tty_window ) ;
+ */
+
+/*
+ * The library uses the window's port temporarily through SetPortBits;
+ * that means you shouldn't do any funky things to the clipping region
+ * etc. Actually, you shouldn't even resize the window, as that will clip
+ * new drawing.
+ *
+ * Also, if you use this library under Pascal, remember that the string
+ * passed to add_tty_string() is a "C" style string with NO length byte,
+ * and a terminating zero byte at the end instead.
+ */
+
+#ifndef _H_tty_public
+# define _H_tty_public
+#undef red                     /* undef internal color const strings from decl */
+#undef green
+#undef blue
+#if !TARGET_API_MAC_CARBON
+# include <windows.h>
+#endif
+
+/*
+ * Error code returned when it's probably our fault, or
+ * bad parameters.
+ */
+#define general_failure 1
+
+/*
+ * Base resource id's for window types
+ */
+#define WIN_BASE_RES 128
+#define WIN_BASE_KIND 128
+
+/*
+ * Commonly used characters
+ */
+#define CHAR_ENTER ((char)3)
+#define CHAR_BELL ((char)7)
+#define CHAR_BS ((char)8)
+#define CHAR_LF ((char)10)
+#define CHAR_CR ((char)13)
+#define CHAR_ESC ((char)27)
+#define CHAR_BLANK ((char)32)
+#define CHAR_DELETE ((char)127)
+
+extern char game_active;       /* flag to window rendering routines not to use ppat */
+/*
+ * If you want some fancy operations that not a normal TTY device normally
+ * supports, use EXTENDED_SUPPORT. For frames, area erases and area scrolls,
+ * plus bitmap graphics - RESOLUTION DEPENDENT, be sure to call
+ * get_tty_metrics and use those limits.
+ */
+#define EXTENDED_SUPPORT 0
+/*
+ * if you print a lot of single characters, accumulating each one in a
+ * clipping region will take too much time. Instead, define this, which
+ * will clip in rects.
+ */
+#define CLIP_RECT_ONLY 1
+
+typedef enum tty_attrib {
+
+/*
+ * Flags relating to the general functioning of the window.
+ * These flags are passed at create_tty time, and changing them
+ * later will clear the screen.
+ */
+       TTY_ATTRIB_FLAGS ,
+/*
+ * When using proportional fonts, this will place each character
+ * separately, ensuring aligned columns (but looking ugly and taking
+ * time)
+ */
+# define TA_MOVE_EACH_CHAR 1L
+/*
+ * This means draw each change as it occurs instead of collecting the area
+ * and draw it all at once at update_tty() - slower, but more reliable.
+ */
+# define TA_ALWAYS_REFRESH 2L
+/*
+ * When reaching the right end, we either just stop drawing, or wrap to the
+ * next line.
+ */
+# define TA_WRAP_AROUND 4L
+/*
+ * Overstrike means that characters are added on top of each other; i e don't
+ * clear the letter beneath. This is faster, using srcOr under QuickDraw
+ */
+# define TA_OVERSTRIKE 8L
+/*
+ * We may want the window not to scroll when we reach the end line,
+ * but stop drawing instead.
+ */
+# define TA_INHIBIT_VERT_SCROLL 16L
+
+/*
+ * Foreground and background colors. These only affect characters
+ * drawn by subsequent calls; not what's already there (but it does
+ * affect clears)
+ * On b/w screens these do nothing.
+ */
+       TTY_ATTRIB_FOREGROUND ,
+       TTY_ATTRIB_BACKGROUND ,
+# define TA_RGB_TO_TTY(r) ((((long)((r).red>>8)&0xff)<<16)+\
+       (((long)((r).green>>8)&0xff)<<8)+((long)((r).blue>>8)&0xff))
+
+/*
+ * Attributes relating to the cursor, and character set mappings
+ */
+       TTY_ATTRIB_CURSOR ,
+/*
+ * Blinking cursor is more noticeable when it's idle
+ */
+# define TA_BLINKING_CURSOR 1L
+/*
+ * When handling input, do we echo characters as they are typed?
+ */
+# define TA_ECHO_INPUT 2L
+/*
+ * Do we return each character code separately, or map delete etc? Note
+ * that non-raw input means getchar won't return anything until the user
+ * has typed a return.
+ */
+# define TA_RAW_INPUT 4L
+/*
+ * Do we print every character as it is (including BS, NL and CR!) or do
+ * do we interpret characters such as NL, BS and CR?
+ */
+# define TA_RAW_OUTPUT 8L
+/*
+ * When getting a NL, do we also move to the left?
+ */
+# define TA_NL_ADD_CR 16L
+/*
+ * When getting a CR, do we also move down?
+ */
+# define TA_CR_ADD_NL 32L
+/*
+ * Wait for input or return what we've got?
+ */
+# define TA_NONBLOCKING_IO 64L
+
+/*
+ * Use this macro to cast a function pointer to a tty attribute; this will help
+ * portability to systems where a function pointer doesn't fit in a long
+ */
+# define TA_ATTRIB_FUNC(x) ((long)(x))
+
+/*
+ * This symbolic constant is used to check the number of attributes
+ */
+       TTY_NUMBER_ATTRIBUTES
+
+} tty_attrib ;
+
+/*
+ * Character returned by end-of-file condition
+ */
+# define TTY_EOF -1
+
+
+/*
+ * Create the window according to a resource WIND template.
+ * The window pointer pointed to by window should be NULL to
+ * allocate the window record dynamically, or point to a
+ * WindowRecord structure already allocated.
+ *
+ * Passing in_color means you have to be sure there's color support;
+ * on the Mac, this means 32bit QuickDraw present, else it will
+ * crash. Not passing in_color means everything's rendered in
+ * black & white.
+ */
+extern short create_tty ( WindowPtr * window , short resource_id ,
+       Boolean in_color ) ;
+
+/*
+ * Use init_tty_name or init_tty_number to initialize a window
+ * once allocated by create_tty. Size parameters are in characters.
+ */
+
+extern short init_tty_number ( WindowPtr window , short font_number ,
+       short font_size , short x_size , short y_size ) ;
+
+/*
+ * Close and deallocate a window and its data
+ */
+extern short destroy_tty ( WindowPtr window ) ;
+
+/*
+ * Change the font and font size used in the window for drawing after
+ * the calls are made. To change the coordinate system, be sure to call
+ * force_tty_coordinate_system_recalc() - else it may look strange if
+ * the new font doesn't match the old one.
+ */
+extern short set_tty_font_name (winid window_type , char * name ) ;
+extern short force_tty_coordinate_system_recalc ( WindowPtr window ) ;
+
+/*
+ * Getting some metrics about the tty and its drawing.
+ */
+extern short get_tty_metrics ( WindowPtr window , short * x_size ,
+       short * y_size , short * x_size_pixels , short * y_size_pixels ,
+       short * font_number , short * font_size ,
+       short * char_width , short * row_height ) ;
+
+/*
+ * The basic move cursor function. 0,0 is topleft.
+ */
+extern short move_tty_cursor ( WindowPtr window , short x_pos ,
+       short y_pos ) ;
+
+/*
+ * Flush all changes done to a tty to the screen (see TA_ALWAYS_UPDATE above)
+ */
+extern short update_tty ( WindowPtr window ) ;
+
+/*
+ * Add a character to the tty and update the cursor position
+ */
+extern short add_tty_char ( WindowPtr window , short character ) ;
+
+/*
+ * Add a string of characters to the tty and update the cursor
+ * position. The string is 0-terminated!
+ */
+extern short add_tty_string ( WindowPtr window , const char * string ) ;
+
+/*
+ * Change or read an attribute of the tty. Note that some attribute changes
+ * may clear the screen. See the above enum and defines for values.
+ * Attributes can be both function pointers and special flag values.
+ */
+extern short get_tty_attrib ( WindowPtr window , tty_attrib attrib ,
+       long * value ) ;
+extern short set_tty_attrib ( WindowPtr window , tty_attrib attrib ,
+       long value ) ;
+
+/*
+ * Scroll the actual TTY image, in characters, positive means up/left
+ * scroll_tty ( my_tty , 0 , 1 ) means a linefeed. Is always carried out
+ * directly, regardless of the wait-update setting. Does updates before
+ * scrolling.
+ */
+extern short scroll_tty ( WindowPtr window , short delta_x ,
+       short delta_y ) ;
+
+/*
+ * Erase the offscreen bitmap and move the cursor to 0,0. Re-init some window
+ * values (font etc) Is always carried out directly on-screen, regardless of
+ * the wait-for-update setting. Clears update area.
+ */
+extern short clear_tty ( WindowPtr window ) ;
+
+/*
+ * Call this routine with a window (always _mt_window) and a time (usually
+ * from most recent event) to determine if cursor in window should be blinked
+ */
+extern short blink_cursor ( WindowPtr window , long when ) ;
+
+/*
+ * For screen dumps, open the printer port and call this function. Can be used
+ * for clipboard as well (only for a PICT, though; this library doesn't concern
+ * itself with characters, just bitmaps)
+ */
+extern short image_tty ( EventRecord *theEvent, WindowPtr window ) ;
+
+/*
+ * For erasing just an area of characters
+ */
+extern short clear_tty_window ( WindowPtr window , short from_row ,
+       short from_col , short to_row , short to_col ) ;
+
+/*
+ * get and set the invalid region of the main window
+ */
+ extern short get_invalid_region (WindowPtr window, Rect *inval_rect);
+ extern short set_invalid_region (WindowPtr window, Rect *inval_rect);
+/*
+ * Now in macsnd.c, which seemed like a good place
+ */
+extern void tty_nhbell ();
+
+#if EXTENDED_SUPPORT
+
+/*
+ * Various versions of delete character/s, insert line/s etc can be handled by
+ * this general-purpose function. Negative num_ means delete, positive means
+ * insert, and you can never be sure which of row and col operations come first
+ * if you specify both...
+ */
+extern short mangle_tty_rows_columns ( WindowPtr window ,
+       short from_row , short num_rows , short from_col , short num_cols ) ;
+
+/*
+ * For framing an area without using grahpics characters.
+ * Note that the given limits are those used for framing, you should not
+ * draw in them. frame_fatness should typically be 1-5, and may be clipped
+ * if it is too large.
+ */
+extern short frame_tty_window ( WindowPtr window , short from_row ,
+       short from_col , short to_row , short to_col , short frame_fatness ) ;
+
+/*
+ * For inverting specific characters after the fact. May look funny in color.
+ */
+extern short invert_tty_window ( WindowPtr window , short from_row ,
+       short from_col , short to_row , short to_col ) ;
+
+/*
+ * For drawing lines on the tty - VERY DEVICE DEPENDENT. Use get_tty_metrics.
+ */
+extern short draw_tty_line ( WindowPtr window , short from_x ,
+       short from_y , short to_x , short to_y ) ;
+
+#endif /* EXTENDED_SUPPORT */
+
+#endif /* _H_tty_public */
diff --git a/include/macwin.h b/include/macwin.h
new file mode 100644 (file)
index 0000000..92c1934
--- /dev/null
@@ -0,0 +1,246 @@
+/*     SCCS Id: @(#)macwin.h   3.4     1996/01/15      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MACWIN_H
+# define MACWIN_H
+#undef red                     /* undef internal color const strings from decl */
+#undef green
+#undef blue
+
+#ifndef __MACH__
+#include <windows.h>
+#include <dialogs.h>
+#endif
+
+/* more headers */
+#ifdef THINK_C
+#include <pascal.h>    /* for CtoPStr and PtoCStr */
+#endif
+
+/* resources */
+#define PLAYER_NAME_RES_ID     1001
+
+/* fake some things if we don't have universal headers.. */
+#if 0  /*ndef NewUserItemProc*/
+typedef pascal void (*UserItemProcPtr)(WindowPtr theWindow, short itemNo);
+typedef UserItemProcPtr UserItemUPP;
+#define NewUserItemProc(p)     (UserItemUPP)(p)
+
+typedef pascal void (*ControlActionProcPtr)(ControlHandle theControl, short partCode);
+typedef ControlActionProcPtr ControlActionUPP;
+#define NewControlActionProc(p) (ControlActionUPP)(p)
+
+typedef ModalFilterProcPtr ModalFilterUPP;
+#define DisposeRoutineDescriptor(p)
+#endif
+
+/* misc */
+#ifdef __MWERKS__
+# define ResumeProcPtr long            /* for call to InitDialogs */
+#endif
+
+/* working dirs structure */
+typedef struct macdirs {
+       Str32           dataName;
+       short           dataRefNum;
+       long            dataDirID;
+
+       Str32           saveName;
+       short           saveRefNum;
+       long            saveDirID;
+
+       Str32           levelName;
+       short           levelRefNum;
+       long            levelDirID;
+} MacDirs;
+
+typedef struct macflags {
+       Bitfield (processes, 1);
+       Bitfield (color, 1);
+       Bitfield (folders, 1);
+       Bitfield (tempMem, 1);
+       Bitfield (help, 1);
+       Bitfield (fsSpec, 1);
+       Bitfield (trueType, 1);
+       Bitfield (aux, 1);
+       Bitfield (alias, 1);
+       Bitfield (standardFile, 1);
+       Bitfield (hasDebugger, 1);
+       Bitfield (hasAE, 1);
+       Bitfield (gotOpen, 1);
+} MacFlags;
+
+extern MacDirs theDirs;                /* used in macfile.c */
+extern MacFlags macFlags;
+
+/*
+ * Mac windows
+ */
+#define NUM_MACWINDOWS 15
+#define TEXT_BLOCK 512L
+
+/* Window constants */
+#define kMapWindow 0
+#define kStatusWindow 1
+#define kMessageWindow 2
+#define kTextWindow 3
+#define kMenuWindow 4
+#define kLastWindowKind kMenuWindow
+
+/*
+ * This determines the minimum logical line length in text windows
+ * That is; even if physical width is less, this is where line breaks
+ * go at the minimum. 350 is about right for score lines with a
+ * geneva 10 pt font.
+ */
+#define MIN_RIGHT 350
+
+typedef struct {
+       anything id;
+       char accelerator;
+       char groupAcc;
+       short line;
+} MacMHMenuItem;
+
+typedef struct NhWindow {
+       WindowPtr               its_window;
+
+       short                   font_number;
+       short                   font_size;
+       short                   char_width;
+       short                   row_height;
+       short                   ascent_height;
+       
+       short                   x_size;
+       short                   y_size;
+       short                   x_curs;
+       short                   y_curs;
+       
+       short           last_more_lin; /* Used by message window */
+       short           save_lin;               /* Used by message window */
+
+       short                   miSize;         /* size of menu items arrays */
+       short                   miLen;          /* number of menu items in array */
+       MacMHMenuItem   **menuInfo;             /* Used by menus (array handle) */
+       char            menuChar;               /* next menu accelerator to use */
+       short                   **menuSelected; /* list of selected elements from list */
+       short                   miSelLen;       /* number of items selected */
+       short                   how;            /* menu mode */
+
+       char                    drawn;
+       Handle                  windowText;
+       long                    windowTextLen;
+       short           scrollPos;
+       ControlHandle   scrollBar;
+} NhWindow;
+
+extern Boolean CheckNhWin(WindowPtr mac_win);
+
+
+#define NUM_STAT_ROWS 2
+#define NUM_ROWS 22
+#define NUM_COLS 80 /* We shouldn't use column 0 */
+#define QUEUE_LEN 24
+
+extern NhWindow * theWindows;
+
+extern struct window_procs mac_procs;
+
+#define NHW_BASE 0
+extern winid BASE_WINDOW, WIN_MAP, WIN_MESSAGE, WIN_INVEN, WIN_STATUS;
+
+
+/*
+ * External declarations for the window routines.
+ */
+
+#define E extern
+
+/* ### dprintf.c ### */
+
+extern void dprintf (char *, ...);
+
+/* ### maccurs.c ### */
+
+extern Boolean RetrievePosition (short, short *, short *);
+extern Boolean RetrieveSize (short, short, short, short *, short *);
+extern void SaveWindowPos (WindowPtr);
+extern void SaveWindowSize (WindowPtr);
+extern Boolean FDECL(RetrieveWinPos, (WindowPtr,short *,short *));
+
+/* ### macerrs.c ### */
+
+extern void showerror(char *,const char *);
+extern Boolean itworked(short);
+extern void mustwork(short);
+extern void attemptingto(char *);
+/* appear to be unused 
+extern void comment(char *,long);
+extern void pushattemptingto(char *);
+extern void popattempt(void);
+*/
+/* ### macfile.c ### */
+
+/* extern char *macgets(int fd, char *ptr, unsigned len); unused */
+extern void FDECL(C2P,(const char *c, unsigned char *p));
+extern void FDECL(P2C,(const unsigned char *p, char *c));
+
+/* ### macmenu.c ### */
+
+extern void DoMenuEvt (long);
+extern void InitMenuRes(void);
+extern void AdjustMenus(short);
+#define DimMenuBar() AdjustMenus(1)
+#define UndimMenuBar() AdjustMenus(0)
+
+/* ### macmain.c ### */
+
+extern void FDECL (process_openfile, (short s_vol, long s_dir, Str255 fNm, OSType ft));
+
+/* ### macwin.c ### */
+
+extern void AddToKeyQueue(unsigned char, Boolean);
+extern unsigned char GetFromKeyQueue (void);
+void trans_num_keys (EventRecord *);
+extern void NDECL (InitMac);
+int FDECL (try_key_queue, (char *));
+void FDECL (enter_topl_mode, (char *));
+void FDECL (leave_topl_mode, (char *));
+void FDECL (topl_set_resp, (char *, char));
+Boolean FDECL (topl_key, (unsigned char, Boolean));
+E void FDECL(HandleEvent, (EventRecord *));    /* used in mmodal.c */
+extern void NDECL(port_help);
+
+extern Boolean small_screen;
+
+E void FDECL(mac_init_nhwindows, (int *, char **));
+E void NDECL(mac_askname);
+E void NDECL(mac_get_nh_event);
+E void FDECL(mac_exit_nhwindows, (const char *));
+E winid FDECL(mac_create_nhwindow, (int));
+E void FDECL(mac_clear_nhwindow, (winid));
+E void FDECL(mac_display_nhwindow, (winid, BOOLEAN_P));
+E void FDECL(mac_destroy_nhwindow, (winid));
+E void FDECL(mac_curs, (winid,int,int));
+E void FDECL(mac_putstr, (winid, int, const char *));
+E void FDECL(mac_start_menu, (winid));
+E void FDECL(mac_add_menu, (winid,int,const anything *,
+               CHAR_P,CHAR_P,int,const char *, BOOLEAN_P));
+E void FDECL(mac_end_menu, (winid, const char *));
+E int FDECL(mac_select_menu, (winid, int, menu_item **));
+#ifdef CLIPPING
+E void FDECL(mac_cliparound, (int, int));
+#endif
+E int NDECL(mac_nhgetch);
+E int FDECL(mac_nh_poskey, (int *, int *, int *));
+E int NDECL(mac_doprev_message);
+E char FDECL(mac_yn_function, (const char *, const char *, CHAR_P));
+E void FDECL(mac_getlin, (const char *,char *));
+E int NDECL(mac_get_ext_cmd);
+E void FDECL(mac_number_pad, (int));
+E void NDECL(mac_delay_output);
+
+#undef E
+
+#endif /* ! MACWIN_H */
diff --git a/include/mail.h b/include/mail.h
new file mode 100644 (file)
index 0000000..daa8b30
--- /dev/null
@@ -0,0 +1,20 @@
+/*     SCCS Id: @(#)mail.h     3.4     1991/10/11      */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* used by ckmailstatus() to pass information to the mail-daemon in newmail() */
+
+#ifndef MAIL_H
+#define MAIL_H
+
+#define MSG_OTHER 0    /* catch-all; none of the below... */
+#define MSG_MAIL  1    /* unimportant, uninteresting mail message */
+#define MSG_CALL  2    /* annoying phone/talk/chat-type interruption */
+
+struct mail_info {
+       int      message_typ;           /* MSG_foo value */
+       const char *display_txt;        /* text for daemon to verbalize */
+       const char *object_nam;         /* text to tag object with */
+       const char *response_cmd;       /* command to eventually execute */
+};
+
+#endif /* MAIL_H */
diff --git a/include/mfndpos.h b/include/mfndpos.h
new file mode 100644 (file)
index 0000000..01a4bb5
--- /dev/null
@@ -0,0 +1,29 @@
+/*     SCCS Id: @(#)mfndpos.h  3.4     2002/04/06      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MFNDPOS_H
+#define MFNDPOS_H
+
+#define ALLOW_TRAPS    0x00020000L     /* can enter traps */
+#define ALLOW_U                0x00040000L     /* can attack you */
+#define ALLOW_M                0x00080000L     /* can attack other monsters */
+#define ALLOW_TM       0x00100000L     /* can attack tame monsters */
+#define ALLOW_ALL      (ALLOW_U | ALLOW_M | ALLOW_TM | ALLOW_TRAPS)
+#define NOTONL         0x00200000L     /* avoids direct line to player */
+#define OPENDOOR       0x00400000L     /* opens closed doors */
+#define UNLOCKDOOR     0x00800000L     /* unlocks locked doors */
+#define BUSTDOOR       0x01000000L     /* breaks any doors */
+#define ALLOW_ROCK     0x02000000L     /* pushes rocks */
+#define ALLOW_WALL     0x04000000L     /* walks thru walls */
+#define ALLOW_DIG      0x08000000L     /* digs */
+#define ALLOW_BARS     0x10000000L     /* may pass thru iron bars */
+#define ALLOW_SANCT    0x20000000L     /* enters temples */
+#define ALLOW_SSM      0x40000000L     /* ignores scare monster */
+#ifdef NHSTDC
+#define NOGARLIC       0x80000000UL    /* hates garlic */
+#else
+#define NOGARLIC       0x80000000L     /* hates garlic */
+#endif
+
+#endif /* MFNDPOS_H */
diff --git a/include/micro.h b/include/micro.h
new file mode 100644 (file)
index 0000000..38cd737
--- /dev/null
@@ -0,0 +1,21 @@
+/*     SCCS Id: @(#)micro.h    3.4     1990/02/22      */
+/* micro.h - function declarations for various microcomputers */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MICRO_H
+#define MICRO_H
+
+extern const char *alllevels, *allbones;
+extern char levels[], bones[], permbones[], hackdir[];
+
+extern int ramdisk;
+
+#ifndef C
+#define C(c)   (0x1f & (c))
+#endif
+#ifndef M
+#define M(c)   (((char)0x80) | (c))
+#endif
+#define ABORT C('a')
+
+#endif /* MICRO_H */
diff --git a/include/mkroom.h b/include/mkroom.h
new file mode 100644 (file)
index 0000000..b1363bd
--- /dev/null
@@ -0,0 +1,103 @@
+/*     SCCS Id: @(#)mkroom.h   3.4     1992/11/14      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MKROOM_H
+#define MKROOM_H
+
+/* mkroom.h - types and structures for room and shop initialization */
+
+struct mkroom {
+       schar lx,hx,ly,hy;      /* usually xchar, but hx may be -1 */
+       schar rtype;            /* type of room (zoo, throne, etc...) */
+       schar rlit;             /* is the room lit ? */
+       schar doorct;           /* door count */
+       schar fdoor;            /* index for the first door of the room */
+       schar nsubrooms;        /* number of subrooms */
+       boolean irregular;      /* true if room is non-rectangular */
+       struct mkroom *sbrooms[MAX_SUBROOMS];  /* Subrooms pointers */
+       struct monst *resident; /* priest/shopkeeper/guard for this room */
+};
+
+struct shclass {
+       const char *name;       /* name of the shop type */
+       char    symb;           /* this identifies the shop type */
+       int     prob;           /* the shop type probability in % */
+       schar   shdist;         /* object placement type */
+#define D_SCATTER      0       /* normal placement */
+#define D_SHOP         1       /* shop-like placement */
+#define D_TEMPLE       2       /* temple-like placement */
+       struct itp {
+           int iprob;          /* probability of an item type */
+           int itype;  /* item type: if >=0 a class, if < 0 a specific item */
+       } iprobs[5];
+       const char * const *shknms;     /* list of shopkeeper names for this type */
+};
+
+extern NEARDATA struct mkroom rooms[(MAXNROFROOMS+1)*2];
+extern NEARDATA struct mkroom* subrooms;
+/* the normal rooms on the current level are described in rooms[0..n] for
+ * some n<MAXNROFROOMS
+ * the vault, if any, is described by rooms[n+1]
+ * the next rooms entry has hx -1 as a flag
+ * there is at most one non-vault special room on a level
+ */
+
+extern struct mkroom *dnstairs_room, *upstairs_room, *sstairs_room;
+
+extern NEARDATA coord doors[DOORMAX];
+
+/* values for rtype in the room definition structure */
+#define OROOM           0      /* ordinary room */
+#define COURT           2      /* contains a throne */
+#define SWAMP           3      /* contains pools */
+#define VAULT           4      /* contains piles of gold */
+#define BEEHIVE                 5      /* contains killer bees and royal jelly */
+#define MORGUE          6      /* contains corpses, undead and ghosts */
+#define BARRACKS        7      /* contains soldiers and their gear */
+#define ZOO             8      /* floor covered with treasure and monsters */
+#define DELPHI          9      /* contains Oracle and peripherals */
+#define TEMPLE         10      /* contains a shrine */
+#define LEPREHALL      11      /* leprechaun hall (Tom Proudfoot) */
+#define COCKNEST       12      /* cockatrice nest (Tom Proudfoot) */
+#define ANTHOLE                13      /* ants (Tom Proudfoot) */
+#define SHOPBASE       14      /* everything above this is a shop */
+#define ARMORSHOP      15      /* specific shop defines for level compiler */
+#define SCROLLSHOP     16
+#define POTIONSHOP     17
+#define WEAPONSHOP     18
+#define FOODSHOP       19
+#define RINGSHOP       20
+#define WANDSHOP       21
+#define TOOLSHOP       22
+#define BOOKSHOP       23
+#define UNIQUESHOP     24      /* shops here & above not randomly gen'd. */
+#define CANDLESHOP     24
+#define MAXRTYPE       24      /* maximum valid room type */
+
+/* Special type for search_special() */
+#define ANY_TYPE       (-1)
+#define ANY_SHOP       (-2)
+
+#define NO_ROOM                0       /* indicates lack of room-occupancy */
+#define SHARED         1       /* indicates normal shared boundary */
+#define SHARED_PLUS    2       /* indicates shared boundary - extra adjacent-
+                                * square searching required */
+
+#define ROOMOFFSET     3       /*
+                                * (levl[x][y].roomno - ROOMOFFSET) gives
+                                * rooms[] index, for inside-squares and
+                                * non-shared boundaries.
+                                */
+
+#define IS_ROOM_PTR(x)         ((x) >= rooms && (x) < rooms + MAXNROFROOMS)
+#define IS_ROOM_INDEX(x)       ((x) >= 0 && (x) < MAXNROFROOMS)
+#define IS_SUBROOM_PTR(x)      ((x) >= subrooms && \
+                                (x) < subrooms + MAXNROFROOMS)
+#define IS_SUBROOM_INDEX(x)    ((x) > MAXNROFROOMS && (x) < (MAXNROFROOMS*2))
+#define ROOM_INDEX(x)          ((x) - rooms)
+#define SUBROOM_INDEX(x)       ((x) - subrooms)
+#define IS_LAST_ROOM_PTR(x)    (ROOM_INDEX(x) == nroom)
+#define IS_LAST_SUBROOM_PTR(x) (!nsubroom || SUBROOM_INDEX(x) == nsubroom)
+
+#endif /* MKROOM_H */
diff --git a/include/monattk.h b/include/monattk.h
new file mode 100644 (file)
index 0000000..02ee881
--- /dev/null
@@ -0,0 +1,100 @@
+/*     SCCS Id: @(#)monattk.h  3.4     2002/03/24      */
+/* NetHack may be freely redistributed.  See license for details. */
+/* Copyright 1988, M. Stephenson */
+
+#ifndef MONATTK_H
+#define MONATTK_H
+
+/*     Add new attack types below - ordering affects experience (exper.c).
+ *     Attacks > AT_BUTT are worth extra experience.
+ */
+#define AT_ANY         (-1)    /* fake attack; dmgtype_fromattack wildcard */
+#define AT_NONE                0       /* passive monster (ex. acid blob) */
+#define AT_CLAW                1       /* claw (punch, hit, etc.) */
+#define AT_BITE                2       /* bite */
+#define AT_KICK                3       /* kick */
+#define AT_BUTT                4       /* head butt (ex. a unicorn) */
+#define AT_TUCH                5       /* touches */
+#define AT_STNG                6       /* sting */
+#define AT_HUGS                7       /* crushing bearhug */
+#define AT_SPIT                10      /* spits substance - ranged */
+#define AT_ENGL                11      /* engulf (swallow or by a cloud) */
+#define AT_BREA                12      /* breath - ranged */
+#define AT_EXPL                13      /* explodes - proximity */
+#define AT_BOOM                14      /* explodes when killed */
+#define AT_GAZE                15      /* gaze - ranged */
+#define AT_TENT                16      /* tentacles */
+
+#define AT_WEAP                254     /* uses weapon */
+#define AT_MAGC                255     /* uses magic spell(s) */
+
+/*     Add new damage types below.
+ *
+ *     Note that 1-10 correspond to the types of attack used in buzz().
+ *     Please don't disturb the order unless you rewrite the buzz() code.
+ */
+#define AD_ANY         (-1)    /* fake damage; attacktype_fordmg wildcard */
+#define AD_PHYS                0       /* ordinary physical */
+#define AD_MAGM                1       /* magic missiles */
+#define AD_FIRE                2       /* fire damage */
+#define AD_COLD                3       /* frost damage */
+#define AD_SLEE                4       /* sleep ray */
+#define AD_DISN                5       /* disintegration (death ray) */
+#define AD_ELEC                6       /* shock damage */
+#define AD_DRST                7       /* drains str (poison) */
+#define AD_ACID                8       /* acid damage */
+#define AD_SPC1                9       /* for extension of buzz() */
+#define AD_SPC2                10      /* for extension of buzz() */
+#define AD_BLND                11      /* blinds (yellow light) */
+#define AD_STUN                12      /* stuns */
+#define AD_SLOW                13      /* slows */
+#define AD_PLYS                14      /* paralyses */
+#define AD_DRLI                15      /* drains life levels (Vampire) */
+#define AD_DREN                16      /* drains magic energy */
+#define AD_LEGS                17      /* damages legs (xan) */
+#define AD_STON                18      /* petrifies (Medusa, cockatrice) */
+#define AD_STCK                19      /* sticks to you (mimic) */
+#define AD_SGLD                20      /* steals gold (leppie) */
+#define AD_SITM                21      /* steals item (nymphs) */
+#define AD_SEDU                22      /* seduces & steals multiple items */
+#define AD_TLPT                23      /* teleports you (Quantum Mech.) */
+#define AD_RUST                24      /* rusts armour (Rust Monster)*/
+#define AD_CONF                25      /* confuses (Umber Hulk) */
+#define AD_DGST                26      /* digests opponent (trapper, etc.) */
+#define AD_HEAL                27      /* heals opponent's wounds (nurse) */
+#define AD_WRAP                28      /* special "stick" for eels */
+#define AD_WERE                29      /* confers lycanthropy */
+#define AD_DRDX                30      /* drains dexterity (quasit) */
+#define AD_DRCO                31      /* drains constitution */
+#define AD_DRIN                32      /* drains intelligence (mind flayer) */
+#define AD_DISE                33      /* confers diseases */
+#define AD_DCAY                34      /* decays organics (brown Pudding) */
+#define AD_SSEX                35      /* Succubus seduction (extended) */
+                               /* If no SEDUCE then same as AD_SEDU */
+#define AD_HALU                36      /* causes hallucination */
+#define AD_DETH                37      /* for Death only */
+#define AD_PEST                38      /* for Pestilence only */
+#define AD_FAMN                39      /* for Famine only */
+#define AD_SLIM                40      /* turns you into green slime */
+#define AD_ENCH                41      /* remove enchantment (disenchanter) */
+#define AD_CORR                42      /* corrode armor (black pudding) */
+
+#define AD_CLRC                240     /* random clerical spell */
+#define AD_SPEL                241     /* random magic spell */
+#define AD_RBRE                242     /* random breath weapon */
+
+#define AD_SAMU                252     /* hits, may steal Amulet (Wizard) */
+#define AD_CURS                253     /* random curse (ex. gremlin) */
+
+
+/*
+ *  Monster to monster attacks.  When a monster attacks another (mattackm),
+ *  any or all of the following can be returned.  See mattackm() for more
+ *  details.
+ */
+#define MM_MISS                0x0     /* aggressor missed */
+#define MM_HIT         0x1     /* aggressor hit defender */
+#define MM_DEF_DIED    0x2     /* defender died */
+#define MM_AGR_DIED    0x4     /* aggressor died */
+
+#endif /* MONATTK_H */
diff --git a/include/mondata.h b/include/mondata.h
new file mode 100644 (file)
index 0000000..7d86d59
--- /dev/null
@@ -0,0 +1,193 @@
+/*     SCCS Id: @(#)mondata.h  3.4     2003/01/08      */
+/* Copyright (c) 1989 Mike Threepoint                            */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MONDATA_H
+#define MONDATA_H
+
+#define verysmall(ptr)         ((ptr)->msize < MZ_SMALL)
+#define bigmonst(ptr)          ((ptr)->msize >= MZ_LARGE)
+
+#define pm_resistance(ptr,typ) (((ptr)->mresists & (typ)) != 0)
+
+#define resists_fire(mon)      (((mon)->mintrinsics & MR_FIRE) != 0)
+#define resists_cold(mon)      (((mon)->mintrinsics & MR_COLD) != 0)
+#define resists_sleep(mon)     (((mon)->mintrinsics & MR_SLEEP) != 0)
+#define resists_disint(mon)    (((mon)->mintrinsics & MR_DISINT) != 0)
+#define resists_elec(mon)      (((mon)->mintrinsics & MR_ELEC) != 0)
+#define resists_poison(mon)    (((mon)->mintrinsics & MR_POISON) != 0)
+#define resists_acid(mon)      (((mon)->mintrinsics & MR_ACID) != 0)
+#define resists_ston(mon)      (((mon)->mintrinsics & MR_STONE) != 0)
+
+#define is_lminion(mon)                (is_minion((mon)->data) && \
+                                (mon)->data->maligntyp >= A_COALIGNED && \
+                                ((mon)->data != &mons[PM_ANGEL] || \
+                                 EPRI(mon)->shralign > 0))
+
+#define is_flyer(ptr)          (((ptr)->mflags1 & M1_FLY) != 0L)
+#define is_floater(ptr)                ((ptr)->mlet == S_EYE)
+#define is_clinger(ptr)                (((ptr)->mflags1 & M1_CLING) != 0L)
+#define is_swimmer(ptr)                (((ptr)->mflags1 & M1_SWIM) != 0L)
+#define breathless(ptr)                (((ptr)->mflags1 & M1_BREATHLESS) != 0L)
+#define amphibious(ptr)                (((ptr)->mflags1 & (M1_AMPHIBIOUS | M1_BREATHLESS)) != 0L)
+#define passes_walls(ptr)      (((ptr)->mflags1 & M1_WALLWALK) != 0L)
+#define amorphous(ptr)         (((ptr)->mflags1 & M1_AMORPHOUS) != 0L)
+#define noncorporeal(ptr)      ((ptr)->mlet == S_GHOST)
+#define tunnels(ptr)           (((ptr)->mflags1 & M1_TUNNEL) != 0L)
+#define needspick(ptr)         (((ptr)->mflags1 & M1_NEEDPICK) != 0L)
+#define hides_under(ptr)       (((ptr)->mflags1 & M1_CONCEAL) != 0L)
+#define is_hider(ptr)          (((ptr)->mflags1 & M1_HIDE) != 0L)
+#define haseyes(ptr)           (((ptr)->mflags1 & M1_NOEYES) == 0L)
+#define eyecount(ptr)          (!haseyes(ptr) ? 0 : \
+                                ((ptr) == &mons[PM_CYCLOPS] || \
+                                 (ptr) == &mons[PM_FLOATING_EYE]) ? 1 : 2)
+#define nohands(ptr)           (((ptr)->mflags1 & M1_NOHANDS) != 0L)
+#define nolimbs(ptr)           (((ptr)->mflags1 & M1_NOLIMBS) == M1_NOLIMBS)
+#define notake(ptr)            (((ptr)->mflags1 & M1_NOTAKE) != 0L)
+#define has_head(ptr)          (((ptr)->mflags1 & M1_NOHEAD) == 0L)
+#define has_horns(ptr)         (num_horns(ptr) > 0)
+#define is_whirly(ptr)         ((ptr)->mlet == S_VORTEX || \
+                                (ptr) == &mons[PM_AIR_ELEMENTAL])
+#define flaming(ptr)           ((ptr) == &mons[PM_FIRE_VORTEX] || \
+                                (ptr) == &mons[PM_FLAMING_SPHERE] || \
+                                (ptr) == &mons[PM_FIRE_ELEMENTAL] || \
+                                (ptr) == &mons[PM_SALAMANDER])
+#define is_silent(ptr)         ((ptr)->msound == MS_SILENT)
+#define unsolid(ptr)           (((ptr)->mflags1 & M1_UNSOLID) != 0L)
+#define mindless(ptr)          (((ptr)->mflags1 & M1_MINDLESS) != 0L)
+#define humanoid(ptr)          (((ptr)->mflags1 & M1_HUMANOID) != 0L)
+#define is_animal(ptr)         (((ptr)->mflags1 & M1_ANIMAL) != 0L)
+#define slithy(ptr)            (((ptr)->mflags1 & M1_SLITHY) != 0L)
+#define is_wooden(ptr)         ((ptr) == &mons[PM_WOOD_GOLEM])
+#define thick_skinned(ptr)     (((ptr)->mflags1 & M1_THICK_HIDE) != 0L)
+#define lays_eggs(ptr)         (((ptr)->mflags1 & M1_OVIPAROUS) != 0L)
+#define regenerates(ptr)       (((ptr)->mflags1 & M1_REGEN) != 0L)
+#define perceives(ptr)         (((ptr)->mflags1 & M1_SEE_INVIS) != 0L)
+#define can_teleport(ptr)      (((ptr)->mflags1 & M1_TPORT) != 0L)
+#define control_teleport(ptr)  (((ptr)->mflags1 & M1_TPORT_CNTRL) != 0L)
+#define telepathic(ptr)                ((ptr) == &mons[PM_FLOATING_EYE] || \
+                                (ptr) == &mons[PM_MIND_FLAYER] || \
+                                (ptr) == &mons[PM_MASTER_MIND_FLAYER])
+#define is_armed(ptr)          attacktype(ptr, AT_WEAP)
+#define acidic(ptr)            (((ptr)->mflags1 & M1_ACID) != 0L)
+#define poisonous(ptr)         (((ptr)->mflags1 & M1_POIS) != 0L)
+#define carnivorous(ptr)       (((ptr)->mflags1 & M1_CARNIVORE) != 0L)
+#define herbivorous(ptr)       (((ptr)->mflags1 & M1_HERBIVORE) != 0L)
+#define metallivorous(ptr)     (((ptr)->mflags1 & M1_METALLIVORE) != 0L)
+#define polyok(ptr)            (((ptr)->mflags2 & M2_NOPOLY) == 0L)
+#define is_undead(ptr)         (((ptr)->mflags2 & M2_UNDEAD) != 0L)
+#define is_were(ptr)           (((ptr)->mflags2 & M2_WERE) != 0L)
+#define is_elf(ptr)            (((ptr)->mflags2 & M2_ELF) != 0L)
+#define is_dwarf(ptr)          (((ptr)->mflags2 & M2_DWARF) != 0L)
+#define is_gnome(ptr)          (((ptr)->mflags2 & M2_GNOME) != 0L)
+#define is_orc(ptr)            (((ptr)->mflags2 & M2_ORC) != 0L)
+#define is_human(ptr)          (((ptr)->mflags2 & M2_HUMAN) != 0L)
+#define your_race(ptr)         (((ptr)->mflags2 & urace.selfmask) != 0L)
+#define is_bat(ptr)            ((ptr) == &mons[PM_BAT] || \
+                                (ptr) == &mons[PM_GIANT_BAT] || \
+                                (ptr) == &mons[PM_VAMPIRE_BAT])
+#define is_bird(ptr)           ((ptr)->mlet == S_BAT && !is_bat(ptr))
+#define is_giant(ptr)          (((ptr)->mflags2 & M2_GIANT) != 0L)
+#define is_golem(ptr)          ((ptr)->mlet == S_GOLEM)
+#define is_domestic(ptr)       (((ptr)->mflags2 & M2_DOMESTIC) != 0L)
+#define is_demon(ptr)          (((ptr)->mflags2 & M2_DEMON) != 0L)
+#define is_mercenary(ptr)      (((ptr)->mflags2 & M2_MERC) != 0L)
+#define is_male(ptr)           (((ptr)->mflags2 & M2_MALE) != 0L)
+#define is_female(ptr)         (((ptr)->mflags2 & M2_FEMALE) != 0L)
+#define is_neuter(ptr)         (((ptr)->mflags2 & M2_NEUTER) != 0L)
+#define is_wanderer(ptr)       (((ptr)->mflags2 & M2_WANDER) != 0L)
+#define always_hostile(ptr)    (((ptr)->mflags2 & M2_HOSTILE) != 0L)
+#define always_peaceful(ptr)   (((ptr)->mflags2 & M2_PEACEFUL) != 0L)
+#define race_hostile(ptr)      (((ptr)->mflags2 & urace.hatemask) != 0L)
+#define race_peaceful(ptr)     (((ptr)->mflags2 & urace.lovemask) != 0L)
+#define extra_nasty(ptr)       (((ptr)->mflags2 & M2_NASTY) != 0L)
+#define strongmonst(ptr)       (((ptr)->mflags2 & M2_STRONG) != 0L)
+#define can_breathe(ptr)       attacktype(ptr, AT_BREA)
+#define cantwield(ptr)         (nohands(ptr) || verysmall(ptr))
+#define could_twoweap(ptr)     ((ptr)->mattk[1].aatyp == AT_WEAP)
+#define cantweararm(ptr)       (breakarm(ptr) || sliparm(ptr))
+#define throws_rocks(ptr)      (((ptr)->mflags2 & M2_ROCKTHROW) != 0L)
+#define type_is_pname(ptr)     (((ptr)->mflags2 & M2_PNAME) != 0L)
+#define is_lord(ptr)           (((ptr)->mflags2 & M2_LORD) != 0L)
+#define is_prince(ptr)         (((ptr)->mflags2 & M2_PRINCE) != 0L)
+#define is_ndemon(ptr)         (is_demon(ptr) && \
+                                (((ptr)->mflags2 & (M2_LORD|M2_PRINCE)) == 0L))
+#define is_dlord(ptr)          (is_demon(ptr) && is_lord(ptr))
+#define is_dprince(ptr)                (is_demon(ptr) && is_prince(ptr))
+#define is_minion(ptr)         ((ptr)->mflags2 & M2_MINION)
+#define likes_gold(ptr)                (((ptr)->mflags2 & M2_GREEDY) != 0L)
+#define likes_gems(ptr)                (((ptr)->mflags2 & M2_JEWELS) != 0L)
+#define likes_objs(ptr)                (((ptr)->mflags2 & M2_COLLECT) != 0L || \
+                                is_armed(ptr))
+#define likes_magic(ptr)       (((ptr)->mflags2 & M2_MAGIC) != 0L)
+#define webmaker(ptr)          ((ptr) == &mons[PM_CAVE_SPIDER] || \
+                                (ptr) == &mons[PM_GIANT_SPIDER])
+#define is_unicorn(ptr)                ((ptr)->mlet == S_UNICORN && likes_gems(ptr))
+#define is_longworm(ptr)       (((ptr) == &mons[PM_BABY_LONG_WORM]) || \
+                                ((ptr) == &mons[PM_LONG_WORM]) || \
+                                ((ptr) == &mons[PM_LONG_WORM_TAIL]))
+#define is_covetous(ptr)       ((ptr->mflags3 & M3_COVETOUS))
+#define infravision(ptr)       ((ptr->mflags3 & M3_INFRAVISION))
+#define infravisible(ptr)      ((ptr->mflags3 & M3_INFRAVISIBLE))
+#define is_mplayer(ptr)                (((ptr) >= &mons[PM_ARCHEOLOGIST]) && \
+                                ((ptr) <= &mons[PM_WIZARD]))
+#define is_rider(ptr)          ((ptr) == &mons[PM_DEATH] || \
+                                (ptr) == &mons[PM_FAMINE] || \
+                                (ptr) == &mons[PM_PESTILENCE])
+#define is_placeholder(ptr)    ((ptr) == &mons[PM_ORC] || \
+                                (ptr) == &mons[PM_GIANT] || \
+                                (ptr) == &mons[PM_ELF] || \
+                                (ptr) == &mons[PM_HUMAN])
+/* return TRUE if the monster tends to revive */
+#define is_reviver(ptr)                (is_rider(ptr) || (ptr)->mlet == S_TROLL)
+
+/* this returns the light's range, or 0 if none; if we add more light emitting
+   monsters, we'll likely have to add a new light range field to mons[] */
+#define emits_light(ptr)       (((ptr)->mlet == S_LIGHT || \
+                                 (ptr) == &mons[PM_FLAMING_SPHERE] || \
+                                 (ptr) == &mons[PM_SHOCKING_SPHERE] || \
+                                 (ptr) == &mons[PM_FIRE_VORTEX]) ? 1 : \
+                                ((ptr) == &mons[PM_FIRE_ELEMENTAL]) ? 1 : 0)
+/*     [note: the light ranges above were reduced to 1 for performance...] */
+#define likes_lava(ptr)                (ptr == &mons[PM_FIRE_ELEMENTAL] || \
+                                ptr == &mons[PM_SALAMANDER])
+#define pm_invisible(ptr) ((ptr) == &mons[PM_STALKER] || \
+                          (ptr) == &mons[PM_BLACK_LIGHT])
+
+/* could probably add more */
+#define likes_fire(ptr)                ((ptr) == &mons[PM_FIRE_VORTEX] || \
+                                 (ptr) == &mons[PM_FLAMING_SPHERE] || \
+                                likes_lava(ptr))
+
+#define touch_petrifies(ptr)   ((ptr) == &mons[PM_COCKATRICE] || \
+                                (ptr) == &mons[PM_CHICKATRICE])
+
+#define is_mind_flayer(ptr)    ((ptr) == &mons[PM_MIND_FLAYER] || \
+                                (ptr) == &mons[PM_MASTER_MIND_FLAYER])
+
+#define nonliving(ptr)         (is_golem(ptr) || is_undead(ptr) || \
+                                (ptr)->mlet == S_VORTEX || \
+                                (ptr) == &mons[PM_MANES])
+
+/* Used for conduct with corpses, tins, and digestion attacks */
+/* G_NOCORPSE monsters might still be swallowed as a purple worm */
+/* Maybe someday this could be in mflags... */
+#define vegan(ptr)             ((ptr)->mlet == S_BLOB || \
+                                (ptr)->mlet == S_JELLY ||            \
+                                (ptr)->mlet == S_FUNGUS ||           \
+                                (ptr)->mlet == S_VORTEX ||           \
+                                (ptr)->mlet == S_LIGHT ||            \
+                               ((ptr)->mlet == S_ELEMENTAL &&        \
+                                (ptr) != &mons[PM_STALKER]) ||       \
+                               ((ptr)->mlet == S_GOLEM &&            \
+                                (ptr) != &mons[PM_FLESH_GOLEM] &&    \
+                                (ptr) != &mons[PM_LEATHER_GOLEM]) || \
+                                noncorporeal(ptr))
+#define vegetarian(ptr)                (vegan(ptr) || \
+                               ((ptr)->mlet == S_PUDDING &&         \
+                                (ptr) != &mons[PM_BLACK_PUDDING]))
+
+#define befriend_with_obj(ptr, obj) ((obj)->oclass == FOOD_CLASS && \
+                                    is_domestic(ptr))
+
+#endif /* MONDATA_H */
diff --git a/include/monflag.h b/include/monflag.h
new file mode 100644 (file)
index 0000000..8ea8c15
--- /dev/null
@@ -0,0 +1,201 @@
+/*     SCCS Id: @(#)monflag.h  3.4     1996/05/04      */
+/* Copyright (c) 1989 Mike Threepoint                            */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MONFLAG_H
+#define MONFLAG_H
+
+#define MS_SILENT      0       /* makes no sound */
+#define MS_BARK                1       /* if full moon, may howl */
+#define MS_MEW         2       /* mews or hisses */
+#define MS_ROAR                3       /* roars */
+#define MS_GROWL       4       /* growls */
+#define MS_SQEEK       5       /* squeaks, as a rodent */
+#define MS_SQAWK       6       /* squawks, as a bird */
+#define MS_HISS                7       /* hisses */
+#define MS_BUZZ                8       /* buzzes (killer bee) */
+#define MS_GRUNT       9       /* grunts (or speaks own language) */
+#define MS_NEIGH       10      /* neighs, as an equine */
+#define MS_WAIL                11      /* wails, as a tortured soul */
+#define MS_GURGLE      12      /* gurgles, as liquid or through saliva */
+#define MS_BURBLE      13      /* burbles (jabberwock) */
+#define MS_ANIMAL      13      /* up to here are animal noises */
+#define MS_SHRIEK      15      /* wakes up others */
+#define MS_BONES       16      /* rattles bones (skeleton) */
+#define MS_LAUGH       17      /* grins, smiles, giggles, and laughs */
+#define MS_MUMBLE      18      /* says something or other */
+#define MS_IMITATE     19      /* imitates others (leocrotta) */
+#define MS_ORC         MS_GRUNT        /* intelligent brutes */
+#define MS_HUMANOID    20      /* generic traveling companion */
+#ifdef KOPS
+#define MS_ARREST      21      /* "Stop in the name of the law!" (Kops) */
+#endif
+#define MS_SOLDIER     22      /* army and watchmen expressions */
+#define MS_GUARD       23      /* "Please drop that gold and follow me." */
+#define MS_DJINNI      24      /* "Thank you for freeing me!" */
+#define MS_NURSE       25      /* "Take off your shirt, please." */
+#define MS_SEDUCE      26      /* "Hello, sailor." (Nymphs) */
+#define MS_VAMPIRE     27      /* vampiric seduction, Vlad's exclamations */
+#define MS_BRIBE       28      /* asks for money, or berates you */
+#define MS_CUSS                29      /* berates (demons) or intimidates (Wiz) */
+#define MS_RIDER       30      /* astral level special monsters */
+#define MS_LEADER      31      /* your class leader */
+#define MS_NEMESIS     32      /* your nemesis */
+#define MS_GUARDIAN    33      /* your leader's guards */
+#define MS_SELL                34      /* demand payment, complain about shoplifters */
+#define MS_ORACLE      35      /* do a consultation */
+#define MS_PRIEST      36      /* ask for contribution; do cleansing */
+#define MS_SPELL       37      /* spellcaster not matching any of the above */
+#define MS_WERE                38      /* lycanthrope in human form */
+#define MS_BOAST       39      /* giants */
+
+
+#define MR_FIRE                0x01    /* resists fire */
+#define MR_COLD                0x02    /* resists cold */
+#define MR_SLEEP       0x04    /* resists sleep */
+#define MR_DISINT      0x08    /* resists disintegration */
+#define MR_ELEC                0x10    /* resists electricity */
+#define MR_POISON      0x20    /* resists poison */
+#define MR_ACID                0x40    /* resists acid */
+#define MR_STONE       0x80    /* resists petrification */
+/* other resistances: magic, sickness */
+/* other conveyances: teleport, teleport control, telepathy */
+
+/* individual resistances */
+#define MR2_SEE_INVIS  0x0100  /* see invisible */
+#define MR2_LEVITATE   0x0200  /* levitation */
+#define MR2_WATERWALK  0x0400  /* water walking */
+#define MR2_MAGBREATH  0x0800  /* magical breathing */
+#define MR2_DISPLACED  0x1000  /* displaced */
+#define MR2_STRENGTH   0x2000  /* gauntlets of power */
+#define MR2_FUMBLING   0x4000  /* clumsy */
+
+
+#define M1_FLY         0x00000001L     /* can fly or float */
+#define M1_SWIM                0x00000002L     /* can traverse water */
+#define M1_AMORPHOUS   0x00000004L     /* can flow under doors */
+#define M1_WALLWALK    0x00000008L     /* can phase thru rock */
+#define M1_CLING       0x00000010L     /* can cling to ceiling */
+#define M1_TUNNEL      0x00000020L     /* can tunnel thru rock */
+#define M1_NEEDPICK    0x00000040L     /* needs pick to tunnel */
+#define M1_CONCEAL     0x00000080L     /* hides under objects */
+#define M1_HIDE                0x00000100L     /* mimics, blends in with ceiling */
+#define M1_AMPHIBIOUS  0x00000200L     /* can survive underwater */
+#define M1_BREATHLESS  0x00000400L     /* doesn't need to breathe */
+#define M1_NOTAKE      0x00000800L     /* cannot pick up objects */
+#define M1_NOEYES      0x00001000L     /* no eyes to gaze into or blind */
+#define M1_NOHANDS     0x00002000L     /* no hands to handle things */
+#define M1_NOLIMBS     0x00006000L     /* no arms/legs to kick/wear on */
+#define M1_NOHEAD      0x00008000L     /* no head to behead */
+#define M1_MINDLESS    0x00010000L     /* has no mind--golem, zombie, mold */
+#define M1_HUMANOID    0x00020000L     /* has humanoid head/arms/torso */
+#define M1_ANIMAL      0x00040000L     /* has animal body */
+#define M1_SLITHY      0x00080000L     /* has serpent body */
+#define M1_UNSOLID     0x00100000L     /* has no solid or liquid body */
+#define M1_THICK_HIDE  0x00200000L     /* has thick hide or scales */
+#define M1_OVIPAROUS   0x00400000L     /* can lay eggs */
+#define M1_REGEN       0x00800000L     /* regenerates hit points */
+#define M1_SEE_INVIS   0x01000000L     /* can see invisible creatures */
+#define M1_TPORT       0x02000000L     /* can teleport */
+#define M1_TPORT_CNTRL 0x04000000L     /* controls where it teleports to */
+#define M1_ACID                0x08000000L     /* acidic to eat */
+#define M1_POIS                0x10000000L     /* poisonous to eat */
+#define M1_CARNIVORE   0x20000000L     /* eats corpses */
+#define M1_HERBIVORE   0x40000000L     /* eats fruits */
+#define M1_OMNIVORE    0x60000000L     /* eats both */
+#ifdef NHSTDC
+#define M1_METALLIVORE 0x80000000UL    /* eats metal */
+#else
+#define M1_METALLIVORE 0x80000000L     /* eats metal */
+#endif
+
+#define M2_NOPOLY      0x00000001L     /* players mayn't poly into one */
+#define M2_UNDEAD      0x00000002L     /* is walking dead */
+#define M2_WERE                0x00000004L     /* is a lycanthrope */
+#define M2_HUMAN       0x00000008L     /* is a human */
+#define M2_ELF         0x00000010L     /* is an elf */
+#define M2_DWARF       0x00000020L     /* is a dwarf */
+#define M2_GNOME       0x00000040L     /* is a gnome */
+#define M2_ORC         0x00000080L     /* is an orc */
+#define M2_DEMON       0x00000100L     /* is a demon */
+#define M2_MERC                0x00000200L     /* is a guard or soldier */
+#define M2_LORD                0x00000400L     /* is a lord to its kind */
+#define M2_PRINCE      0x00000800L     /* is an overlord to its kind */
+#define M2_MINION      0x00001000L     /* is a minion of a deity */
+#define M2_GIANT       0x00002000L     /* is a giant */
+#define M2_MALE                0x00010000L     /* always male */
+#define M2_FEMALE      0x00020000L     /* always female */
+#define M2_NEUTER      0x00040000L     /* neither male nor female */
+#define M2_PNAME       0x00080000L     /* monster name is a proper name */
+#define M2_HOSTILE     0x00100000L     /* always starts hostile */
+#define M2_PEACEFUL    0x00200000L     /* always starts peaceful */
+#define M2_DOMESTIC    0x00400000L     /* can be tamed by feeding */
+#define M2_WANDER      0x00800000L     /* wanders randomly */
+#define M2_STALK       0x01000000L     /* follows you to other levels */
+#define M2_NASTY       0x02000000L     /* extra-nasty monster (more xp) */
+#define M2_STRONG      0x04000000L     /* strong (or big) monster */
+#define M2_ROCKTHROW   0x08000000L     /* throws boulders */
+#define M2_GREEDY      0x10000000L     /* likes gold */
+#define M2_JEWELS      0x20000000L     /* likes gems */
+#define M2_COLLECT     0x40000000L     /* picks up weapons and food */
+#ifdef NHSTDC
+#define M2_MAGIC       0x80000000UL    /* picks up magic items */
+#else
+#define M2_MAGIC       0x80000000L     /* picks up magic items */
+#endif
+
+#define M3_WANTSAMUL   0x0001          /* would like to steal the amulet */
+#define M3_WANTSBELL   0x0002          /* wants the bell */
+#define M3_WANTSBOOK   0x0004          /* wants the book */
+#define M3_WANTSCAND   0x0008          /* wants the candelabrum */
+#define M3_WANTSARTI   0x0010          /* wants the quest artifact */
+#define M3_WANTSALL    0x001f          /* wants any major artifact */
+#define M3_WAITFORU    0x0040          /* waits to see you or get attacked */
+#define M3_CLOSE       0x0080          /* lets you close unless attacked */
+
+#define M3_COVETOUS    0x001f          /* wants something */
+#define M3_WAITMASK    0x00c0          /* waiting... */
+
+/* Infravision is currently implemented for players only */
+#define M3_INFRAVISION 0x0100          /* has infravision */
+#define M3_INFRAVISIBLE 0x0200         /* visible by infravision */
+
+#define MZ_TINY                0               /* < 2' */
+#define MZ_SMALL       1               /* 2-4' */
+#define MZ_MEDIUM      2               /* 4-7' */
+#define MZ_HUMAN       MZ_MEDIUM       /* human-sized */
+#define MZ_LARGE       3               /* 7-12' */
+#define MZ_HUGE                4               /* 12-25' */
+#define MZ_GIGANTIC    7               /* off the scale */
+
+
+/* Monster races -- must stay within ROLE_RACEMASK */
+/* Eventually this may become its own field */
+#define MH_HUMAN       M2_HUMAN
+#define MH_ELF         M2_ELF
+#define MH_DWARF       M2_DWARF
+#define MH_GNOME       M2_GNOME
+#define MH_ORC         M2_ORC
+
+
+/* for mons[].geno (constant during game) */
+#define G_UNIQ         0x1000          /* generated only once */
+#define G_NOHELL       0x0800          /* not generated in "hell" */
+#define G_HELL         0x0400          /* generated only in "hell" */
+#define G_NOGEN                0x0200          /* generated only specially */
+#define G_SGROUP       0x0080          /* appear in small groups normally */
+#define G_LGROUP       0x0040          /* appear in large groups normally */
+#define G_GENO         0x0020          /* can be genocided */
+#define G_NOCORPSE     0x0010          /* no corpse left ever */
+#define G_FREQ         0x0007          /* creation frequency mask */
+
+/* for mvitals[].mvflags (variant during game), along with G_NOCORPSE */
+#define G_KNOWN                0x0004          /* have been encountered */
+#define G_GONE         (G_GENOD|G_EXTINCT)
+#define G_GENOD                0x0002          /* have been genocided */
+#define G_EXTINCT      0x0001          /* have been extinguished as
+                                          population control */
+#define MV_KNOWS_EGG   0x0008          /* player recognizes egg of this
+                                          monster type */
+
+#endif /* MONFLAG_H */
diff --git a/include/monst.h b/include/monst.h
new file mode 100644 (file)
index 0000000..af2bb78
--- /dev/null
@@ -0,0 +1,181 @@
+/*     SCCS Id: @(#)monst.h    3.4     1999/01/04      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MONST_H
+#define MONST_H
+
+/* The weapon_check flag is used two ways:
+ * 1) When calling mon_wield_item, is 2-6 depending on what is desired.
+ * 2) Between calls to mon_wield_item, is 0 or 1 depending on whether or not
+ *    the weapon is known by the monster to be cursed (so it shouldn't bother
+ *    trying for another weapon).
+ * I originally planned to also use 0 if the monster already had its best
+ * weapon, to avoid the overhead of a call to mon_wield_item, but it turns out
+ * that there are enough situations which might make a monster change its
+ * weapon that this is impractical.  --KAA
+ */
+# define NO_WEAPON_WANTED 0
+# define NEED_WEAPON 1
+# define NEED_RANGED_WEAPON 2
+# define NEED_HTH_WEAPON 3
+# define NEED_PICK_AXE 4
+# define NEED_AXE 5
+# define NEED_PICK_OR_AXE 6
+
+/* The following flags are used for the second argument to display_minventory
+ * in invent.c:
+ *
+ * MINV_NOLET  If set, don't display inventory letters on monster's inventory.
+ * MINV_ALL    If set, display all items in monster's inventory, otherwise
+ *            just display wielded weapons and worn items.
+ */
+#define MINV_NOLET 0x01
+#define MINV_ALL   0x02
+
+#ifndef ALIGN_H
+#include "align.h"
+#endif
+
+struct monst {
+       struct monst *nmon;
+       struct permonst *data;
+       unsigned m_id;
+       short mnum;             /* permanent monster index number */
+       short movement;         /* movement points (derived from permonst definition and added effects */
+       uchar m_lev;            /* adjusted difficulty level of monster */
+       aligntyp malign;        /* alignment of this monster, relative to the
+                                  player (positive = good to kill) */
+       xchar mx, my;
+       xchar mux, muy;         /* where the monster thinks you are */
+#define MTSZ   4
+       coord mtrack[MTSZ];     /* monster track */
+       int mhp, mhpmax;
+       unsigned mappearance;   /* for undetected mimics and the wiz */
+       uchar    m_ap_type;     /* what mappearance is describing: */
+#define M_AP_NOTHING   0       /* mappearance is unused -- monster appears
+                                  as itself */
+#define M_AP_FURNITURE 1       /* stairs, a door, an altar, etc. */
+#define M_AP_OBJECT    2       /* an object */
+#define M_AP_MONSTER   3       /* a monster */
+
+       schar mtame;            /* level of tameness, implies peaceful */
+       unsigned short mintrinsics;     /* low 8 correspond to mresists */
+       int mspec_used;         /* monster's special ability attack timeout */
+
+       Bitfield(female,1);     /* is female */
+       Bitfield(minvis,1);     /* currently invisible */
+       Bitfield(invis_blkd,1); /* invisibility blocked */
+       Bitfield(perminvis,1);  /* intrinsic minvis value */
+       Bitfield(cham,3);       /* shape-changer */
+/* note: lychanthropes are handled elsewhere */
+#define CHAM_ORDINARY          0       /* not a shapechanger */
+#define CHAM_CHAMELEON         1       /* animal */
+#define CHAM_DOPPELGANGER      2       /* demi-human */
+#define CHAM_SANDESTIN         3       /* demon */
+#define CHAM_MAX_INDX          CHAM_SANDESTIN
+       Bitfield(mundetected,1);        /* not seen in present hiding place */
+                               /* implies one of M1_CONCEAL or M1_HIDE,
+                                * but not mimic (that is, snake, spider,
+                                * trapper, piercer, eel)
+                                */
+
+       Bitfield(mcan,1);       /* has been cancelled */
+       Bitfield(mburied,1);    /* has been buried */
+       Bitfield(mspeed,2);     /* current speed */
+       Bitfield(permspeed,2);  /* intrinsic mspeed value */
+       Bitfield(mrevived,1);   /* has been revived from the dead */
+       Bitfield(mavenge,1);    /* did something to deserve retaliation */
+
+       Bitfield(mflee,1);      /* fleeing */
+       Bitfield(mfleetim,7);   /* timeout for mflee */
+
+       Bitfield(mcansee,1);    /* cansee 1, temp.blinded 0, blind 0 */
+       Bitfield(mblinded,7);   /* cansee 0, temp.blinded n, blind 0 */
+
+       Bitfield(mcanmove,1);   /* paralysis, similar to mblinded */
+       Bitfield(mfrozen,7);
+
+       Bitfield(msleeping,1);  /* asleep until woken */
+       Bitfield(mstun,1);      /* stunned (off balance) */
+       Bitfield(mconf,1);      /* confused */
+       Bitfield(mpeaceful,1);  /* does not attack unprovoked */
+       Bitfield(mtrapped,1);   /* trapped in a pit, web or bear trap */
+       Bitfield(mleashed,1);   /* monster is on a leash */
+       Bitfield(isshk,1);      /* is shopkeeper */
+       Bitfield(isminion,1);   /* is a minion */
+
+       Bitfield(isgd,1);       /* is guard */
+       Bitfield(ispriest,1);   /* is a priest */
+       Bitfield(iswiz,1);      /* is the Wizard of Yendor */
+       Bitfield(wormno,5);     /* at most 31 worms on any level */
+#define MAX_NUM_WORMS  32      /* should be 2^(wormno bitfield size) */
+
+       long mstrategy;         /* for monsters with mflag3: current strategy */
+#define STRAT_ARRIVE   0x40000000L     /* just arrived on current level */
+#define STRAT_WAITFORU 0x20000000L
+#define STRAT_CLOSE    0x10000000L
+#define STRAT_WAITMASK 0x30000000L
+#define STRAT_HEAL     0x08000000L
+#define STRAT_GROUND   0x04000000L
+#define STRAT_MONSTR   0x02000000L
+#define STRAT_PLAYER   0x01000000L
+#define STRAT_NONE     0x00000000L
+#define STRAT_STRATMASK 0x0f000000L
+#define STRAT_XMASK    0x00ff0000L
+#define STRAT_YMASK    0x0000ff00L
+#define STRAT_GOAL     0x000000ffL
+#define STRAT_GOALX(s) ((xchar)((s & STRAT_XMASK) >> 16))
+#define STRAT_GOALY(s) ((xchar)((s & STRAT_YMASK) >> 8))
+
+       long mtrapseen;         /* bitmap of traps we've been trapped in */
+       long mlstmv;            /* for catching up with lost time */
+#ifndef GOLDOBJ
+       long mgold;
+#endif
+       struct obj *minvent;
+
+       struct obj *mw;
+       long misc_worn_check;
+       xchar weapon_check;
+
+       uchar mnamelth;         /* length of name (following mxlth) */
+       short mxlth;            /* length of following data */
+       /* in order to prevent alignment problems mextra should
+          be (or follow) a long int */
+       int meating;            /* monster is eating timeout */
+       long mextra[1]; /* monster dependent info */
+};
+
+/*
+ * Note that mextra[] may correspond to any of a number of structures, which
+ * are indicated by some of the other fields.
+ *     isgd     ->     struct egd
+ *     ispriest ->     struct epri
+ *     isshk    ->     struct eshk
+ *     isminion ->     struct emin
+ *                     (struct epri for roaming priests and angels, which is
+ *                      compatible with emin for polymorph purposes)
+ *     mtame    ->     struct edog
+ *                     (struct epri for guardian angels, which do not eat
+ *                      or do other doggy things)
+ * Since at most one structure can be indicated in this manner, it is not
+ * possible to tame any creatures using the other structures (the only
+ * exception being the guardian angels which are tame on creation).
+ */
+
+#define newmonst(xl) (struct monst *)alloc((unsigned)(xl) + sizeof(struct monst))
+#define dealloc_monst(mon) free((genericptr_t)(mon))
+
+/* these are in mspeed */
+#define MSLOW 1                /* slow monster */
+#define MFAST 2                /* speeded monster */
+
+#define NAME(mtmp)     (((char *)(mtmp)->mextra) + (mtmp)->mxlth)
+
+#define MON_WEP(mon)   ((mon)->mw)
+#define MON_NOWEP(mon) ((mon)->mw = (struct obj *)0)
+
+#define DEADMONSTER(mon)       ((mon)->mhp < 1)
+
+#endif /* MONST_H */
diff --git a/include/monsym.h b/include/monsym.h
new file mode 100644 (file)
index 0000000..7bf393c
--- /dev/null
@@ -0,0 +1,147 @@
+/*     SCCS Id: @(#)monsym.h   3.4     1992/10/18      */
+/*     Monster symbols and creation information rev 1.0          */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MONSYM_H
+#define MONSYM_H
+
+/*
+ * Monster classes.  Below, are the corresponding default characters for
+ * them.  Monster class 0 is not used or defined so we can use it as a
+ * NULL character.
+ */
+#define S_ANT          1
+#define S_BLOB         2
+#define S_COCKATRICE   3
+#define S_DOG          4
+#define S_EYE          5
+#define S_FELINE       6
+#define S_GREMLIN      7
+#define S_HUMANOID     8
+#define S_IMP          9
+#define S_JELLY                10
+#define S_KOBOLD       11
+#define S_LEPRECHAUN   12
+#define S_MIMIC                13
+#define S_NYMPH                14
+#define S_ORC          15
+#define S_PIERCER      16
+#define S_QUADRUPED    17
+#define S_RODENT       18
+#define S_SPIDER       19
+#define S_TRAPPER      20
+#define S_UNICORN      21
+#define S_VORTEX       22
+#define S_WORM         23
+#define S_XAN          24
+#define S_LIGHT                25
+#define S_ZRUTY                26
+#define S_ANGEL                27
+#define S_BAT          28
+#define S_CENTAUR      29
+#define S_DRAGON       30
+#define S_ELEMENTAL    31
+#define S_FUNGUS       32
+#define S_GNOME                33
+#define S_GIANT                34
+#define S_JABBERWOCK   36
+#define S_KOP          37
+#define S_LICH         38
+#define S_MUMMY                39
+#define S_NAGA         40
+#define S_OGRE         41
+#define S_PUDDING      42
+#define S_QUANTMECH    43
+#define S_RUSTMONST    44
+#define S_SNAKE                45
+#define S_TROLL                46
+#define S_UMBER                47
+#define S_VAMPIRE      48
+#define S_WRAITH       49
+#define S_XORN         50
+#define S_YETI         51
+#define S_ZOMBIE       52
+#define S_HUMAN                53
+#define S_GHOST                54
+#define S_GOLEM                55
+#define S_DEMON                56
+#define S_EEL          57
+#define S_LIZARD       58
+
+#define S_WORM_TAIL    59
+#define S_MIMIC_DEF    60
+
+#define MAXMCLASSES 61 /* number of monster classes */
+
+#if 0  /* moved to decl.h so that makedefs.c won't see them */
+extern const char def_monsyms[MAXMCLASSES];    /* default class symbols */
+extern uchar monsyms[MAXMCLASSES];             /* current class symbols */
+#endif
+
+/*
+ * Default characters for monsters.  These correspond to the monster classes
+ * above.
+ */
+#define DEF_ANT                'a'
+#define DEF_BLOB       'b'
+#define DEF_COCKATRICE 'c'
+#define DEF_DOG                'd'
+#define DEF_EYE                'e'
+#define DEF_FELINE     'f'
+#define DEF_GREMLIN    'g'
+#define DEF_HUMANOID   'h'
+#define DEF_IMP                'i'
+#define DEF_JELLY      'j'
+#define DEF_KOBOLD     'k'
+#define DEF_LEPRECHAUN 'l'
+#define DEF_MIMIC      'm'
+#define DEF_NYMPH      'n'
+#define DEF_ORC                'o'
+#define DEF_PIERCER    'p'
+#define DEF_QUADRUPED  'q'
+#define DEF_RODENT     'r'
+#define DEF_SPIDER     's'
+#define DEF_TRAPPER    't'
+#define DEF_UNICORN    'u'
+#define DEF_VORTEX     'v'
+#define DEF_WORM       'w'
+#define DEF_XAN                'x'
+#define DEF_LIGHT      'y'
+#define DEF_ZRUTY      'z'
+#define DEF_ANGEL      'A'
+#define DEF_BAT                'B'
+#define DEF_CENTAUR    'C'
+#define DEF_DRAGON     'D'
+#define DEF_ELEMENTAL  'E'
+#define DEF_FUNGUS     'F'
+#define DEF_GNOME      'G'
+#define DEF_GIANT      'H'
+#define DEF_JABBERWOCK 'J'
+#define DEF_KOP                'K'
+#define DEF_LICH       'L'
+#define DEF_MUMMY      'M'
+#define DEF_NAGA       'N'
+#define DEF_OGRE       'O'
+#define DEF_PUDDING    'P'
+#define DEF_QUANTMECH  'Q'
+#define DEF_RUSTMONST  'R'
+#define DEF_SNAKE      'S'
+#define DEF_TROLL      'T'
+#define DEF_UMBER      'U'
+#define DEF_VAMPIRE    'V'
+#define DEF_WRAITH     'W'
+#define DEF_XORN       'X'
+#define DEF_YETI       'Y'
+#define DEF_ZOMBIE     'Z'
+#define DEF_HUMAN      '@'
+#define DEF_GHOST      ' '
+#define DEF_GOLEM      '\''
+#define DEF_DEMON      '&'
+#define DEF_EEL                ';'
+#define DEF_LIZARD     ':'
+
+#define DEF_INVISIBLE  'I'
+#define DEF_WORM_TAIL  '~'
+#define DEF_MIMIC_DEF  ']'
+
+#endif /* MONSYM_H */
diff --git a/include/mttypriv.h b/include/mttypriv.h
new file mode 100644 (file)
index 0000000..ab148cb
--- /dev/null
@@ -0,0 +1,60 @@
+/*     SCCS Id: @(#)mttypriv.h 3.4     1993/03/01      */
+/* Copyright (c) Jon W{tte 1993.                                       */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+/*
+ * This file contains private structures used to implement the
+ * tty windows - note that these structures may change between
+ * minor releases!
+ */
+
+#ifndef _H_tty_private
+# define _H_tty_private
+
+# ifndef _H_tty_public
+#include "mactty.h"
+# endif
+
+#if !TARGET_API_MAC_CARBON
+# include <QDOffscreen.h>
+# include <Gestalt.h>
+# include <Errors.h>
+#endif
+
+#define TA_TO_RGB(ta,rgb) (((rgb).red=(((ta)>>16)&0xff)*257),((rgb).green=(((ta)>>8)&0xff)*257),\
+       ((rgb).blue=((ta)&0xff)*257)),rgb
+
+typedef struct tty_record {
+       WindowPtr       its_window ;
+
+       short           font_number ;
+       short           font_size ;
+       short           char_width ;
+       short           row_height ;
+       short           ascent_height ;
+
+       short           x_size ;
+       short           y_size ;
+       short           x_curs ;
+       short           y_curs ;
+
+       GWorldPtr               its_window_world ;
+       BitMap                  its_bits ;
+       GrafPtr                 offscreen_port ;
+       GWorldPtr               offscreen_world ;
+#if CLIP_RECT_ONLY
+       Rect                    invalid_rect ;
+#else
+       RgnHandle               invalid_part ;
+#endif
+
+       long            attribute [ TTY_NUMBER_ATTRIBUTES ] ;
+       long            last_cursor ;
+
+       Boolean         was_allocated ;
+       Boolean         curs_state ;
+       Boolean         uses_gworld ;
+} tty_record ;
+
+
+#endif /* _H_tty_private */
diff --git a/include/nhlan.h b/include/nhlan.h
new file mode 100644 (file)
index 0000000..1cb9bf1
--- /dev/null
@@ -0,0 +1,48 @@
+/*     SCCS Id: @(#)nhlan.h    3.4     1997/04/12      */
+/* Copyright (c) Michael Allison, 1997                 */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef NHLAN_H
+#define NHLAN_H
+/*
+ * Here are the LAN features currently implemented:
+ * LAN_MAIL            Mail facility allowing receipt and
+ *                     reading of mail.
+ * LAN_SHARED_BONES    Allows bones files to be stored on a
+ *                     network share. (Does NOT imply compatibiliy
+ *                     between unlike platforms)
+ */
+
+# ifdef LAN_FEATURES
+#  ifdef LAN_MAIL
+#define MAIL
+#ifndef WIN32
+#define MAILCKFREQ       50
+#else
+/*
+ * WIN32 port does the real mail lookups in a separate thread
+ * and the NetHack core code really just checks a flag,
+ * so that part of it can be done more often.  The throttle
+ * for how often the mail thread should contact the mail
+ * system is controlled by MAILTHREADFREQ and is expressed
+ * in milliseconds.
+ */
+#define MAILCKFREQ       5
+#define MAILTHREADFREQ   50000
+#endif
+
+#ifndef MAX_BODY_SIZE
+#define MAX_BODY_SIZE 1024
+#endif
+
+struct lan_mail_struct {
+       char sender[120];
+       char subject[120];
+       boolean body_in_ram;    /* TRUE means body in memory not file */
+       char filename[_MAX_PATH];
+       char body[MAX_BODY_SIZE];
+};
+#  endif
+
+# endif /*LAN_FEATURES*/
+#endif /*NHLAN_H*/
diff --git a/include/ntconf.h b/include/ntconf.h
new file mode 100644 (file)
index 0000000..dea4733
--- /dev/null
@@ -0,0 +1,201 @@
+/*     SCCS Id: @(#)ntconf.h   3.4     2002/03/10      */
+/* Copyright (c) NetHack PC Development Team 1993, 1994.  */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef NTCONF_H
+#define NTCONF_H
+
+/* #define SHELL       /* nt use of pcsys routines caused a hang */
+
+#define RANDOM         /* have Berkeley random(3) */
+#define TEXTCOLOR      /* Color text */
+
+#define EXEPATH                        /* Allow .exe location to be used as HACKDIR */
+#define TRADITIONAL_GLYPHMAP   /* Store glyph mappings at level change time */
+#ifdef WIN32CON
+#define LAN_FEATURES           /* Include code for lan-aware features. Untested in 3.4.0*/
+#endif
+
+#define PC_LOCKING             /* Prevent overwrites of aborted or in-progress games */
+                               /* without first receiving confirmation. */
+
+#define HOLD_LOCKFILE_OPEN     /* Keep an exclusive lock on the .0 file */
+
+#define SELF_RECOVER           /* Allow the game itself to recover from an aborted game */
+
+#define USER_SOUNDS
+/*
+ * -----------------------------------------------------------------
+ *  The remaining code shouldn't need modification.
+ * -----------------------------------------------------------------
+ */
+/* #define SHORT_FILENAMES     /* All NT filesystems support long names now */
+
+#ifdef MICRO
+#undef MICRO                   /* never define this! */
+#endif
+
+#define NOCWD_ASSUMPTIONS      /* Always define this. There are assumptions that
+                                   it is defined for WIN32.
+                                  Allow paths to be specified for HACKDIR,
+                                  LEVELDIR, SAVEDIR, BONESDIR, DATADIR,
+                                  SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */
+#define NO_TERMS
+#define ASCIIGRAPH
+
+#ifdef OPTIONS_USED
+#undef OPTIONS_USED
+#endif
+#ifdef MSWIN_GRAPHICS
+#define OPTIONS_USED   "guioptions"
+#else
+#define OPTIONS_USED   "ttyoptions"
+#endif
+#define OPTIONS_FILE OPTIONS_USED
+
+#define PORT_HELP      "porthelp"
+
+#ifdef WIN32CON
+#define PORT_DEBUG     /* include ability to debug international keyboard issues */
+#endif
+
+/* Stuff to help the user with some common, yet significant errors */
+#define INTERJECT_PANIC                0
+#define INTERJECTION_TYPES     (INTERJECT_PANIC + 1)
+extern void FDECL(interject_assistance, (int,int,genericptr_t,genericptr_t));
+extern void FDECL(interject, (int));
+
+/* The following is needed for prototypes of certain functions */
+#if defined(_MSC_VER)
+#include <process.h>   /* Provides prototypes of exit(), spawn()      */
+#endif
+
+#include <string.h>    /* Provides prototypes of strncmpi(), etc.     */
+#ifdef STRNCMPI
+#define strncmpi(a,b,c) strnicmp(a,b,c)
+#endif
+
+#include <sys/types.h>
+#include <stdlib.h>
+#ifdef __BORLANDC__
+#undef randomize
+#undef random
+#endif
+
+#define PATHLEN                BUFSZ /* maximum pathlength */
+#define FILENAME       BUFSZ /* maximum filename length (conservative) */
+
+#if defined(_MAX_PATH) && defined(_MAX_FNAME)
+# if (_MAX_PATH < BUFSZ) && (_MAX_FNAME < BUFSZ)
+#undef PATHLEN
+#undef FILENAME
+#define PATHLEN                _MAX_PATH
+#define FILENAME       _MAX_FNAME
+# endif
+#endif
+
+
+#define NO_SIGNAL
+#define index  strchr
+#define rindex strrchr
+#include <time.h>
+#define USE_STDARG
+#ifdef RANDOM
+/* Use the high quality random number routines. */
+#define Rand() random()
+#else
+#define Rand() rand()
+#endif
+
+#define FCMASK 0660    /* file creation mask */
+#define regularize     nt_regularize
+#define HLOCK "NHPERM"
+
+#ifndef M
+#define M(c)           ((char) (0x80 | (c)))
+/* #define M(c)                ((c) - 128) */
+#endif
+
+#ifndef C
+#define C(c)           (0x1f & (c))
+#endif
+
+#if defined(DLB)
+#define FILENAME_CMP  stricmp                /* case insensitive */
+#endif
+
+#if 0
+extern char levels[], bones[], permbones[],
+#endif /* 0 */
+
+/* this was part of the MICRO stuff in the past */
+extern const char *alllevels, *allbones;
+extern char hackdir[];
+#define ABORT C('a')
+#define getuid() 1
+#define getlogin() ((char *)0)
+extern void NDECL(win32_abort);
+#ifdef WIN32CON
+extern void FDECL(nttty_preference_update, (const char *));
+extern void NDECL(toggle_mouse_support);
+extern void FDECL(map_subkeyvalue, (char *));
+extern void NDECL(load_keyboard_handler);
+#endif
+
+#include <fcntl.h>
+#ifndef __BORLANDC__
+#include <io.h>
+#include <direct.h>
+#else
+int  _RTLENTRY _EXPFUNC access  (const char _FAR *__path, int __amode);
+int  _RTLENTRY _EXPFUNC _chdrive(int __drive);
+int  _RTLENTRYF _EXPFUNC32   chdir( const char _FAR *__path );
+char _FAR * _RTLENTRY  _EXPFUNC     getcwd( char _FAR *__buf, int __buflen );
+int  _RTLENTRY _EXPFUNC write (int __handle, const void _FAR *__buf, unsigned __len);
+int  _RTLENTRY _EXPFUNC creat   (const char _FAR *__path, int __amode);
+int  _RTLENTRY _EXPFUNC close   (int __handle);
+int  _RTLENTRY _EXPFUNC _close  (int __handle);
+int  _RTLENTRY _EXPFUNC open  (const char _FAR *__path, int __access,... /*unsigned mode*/);
+long _RTLENTRY _EXPFUNC lseek  (int __handle, long __offset, int __fromwhere);
+int  _RTLENTRY _EXPFUNC read  (int __handle, void _FAR *__buf, unsigned __len);
+#endif
+#include <conio.h>
+#undef kbhit           /* Use our special NT kbhit */
+#define kbhit (*nt_kbhit)
+
+#ifdef LAN_FEATURES
+#define MAX_LAN_USERNAME 20
+#define LAN_RO_PLAYGROUND      /* not implemented in 3.3.0 */
+#define LAN_SHARED_BONES       /* not implemented in 3.3.0 */
+#include "nhlan.h"
+#endif
+
+#ifndef alloca
+#define ALLOCA_HACK    /* used in util/panic.c */
+#endif
+
+#ifndef REDO
+#undef Getchar
+#define Getchar nhgetch
+#endif
+
+#ifdef _MSC_VER
+#if 0
+#pragma warning(disable:4018)  /* signed/unsigned mismatch */
+#pragma warning(disable:4305)  /* init, conv from 'const int' to 'char' */
+#endif
+#pragma warning(disable:4761)  /* integral size mismatch in arg; conv supp*/
+#ifdef YYPREFIX
+#pragma warning(disable:4102)  /* unreferenced label */
+#endif
+#endif
+
+extern int FDECL(set_win32_option, (const char *, const char *));
+#ifdef WIN32CON
+#define LEFTBUTTON  FROM_LEFT_1ST_BUTTON_PRESSED
+#define RIGHTBUTTON RIGHTMOST_BUTTON_PRESSED
+#define MIDBUTTON   FROM_LEFT_2ND_BUTTON_PRESSED
+#define MOUSEMASK (LEFTBUTTON | RIGHTBUTTON | MIDBUTTON)
+#endif /* WIN32CON */
+
+#endif /* NTCONF_H */
diff --git a/include/obj.h b/include/obj.h
new file mode 100644 (file)
index 0000000..516fc35
--- /dev/null
@@ -0,0 +1,306 @@
+/*     SCCS Id: @(#)obj.h      3.4     2002/01/07      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef OBJ_H
+#define OBJ_H
+
+/* #define obj obj_nh */ /* uncomment for SCO UNIX, which has a conflicting
+                         * typedef for "obj" in <sys/types.h> */
+
+union vptrs {
+           struct obj *v_nexthere;     /* floor location lists */
+           struct obj *v_ocontainer;   /* point back to container */
+           struct monst *v_ocarry;     /* point back to carrying monst */
+};
+
+struct obj {
+       struct obj *nobj;
+       union vptrs v;
+#define nexthere       v.v_nexthere
+#define ocontainer     v.v_ocontainer
+#define ocarry         v.v_ocarry
+
+       struct obj *cobj;       /* contents list for containers */
+       unsigned o_id;
+       xchar ox,oy;
+       short otyp;             /* object class number */
+       unsigned owt;
+       long quan;              /* number of items */
+
+       schar spe;              /* quality of weapon, armor or ring (+ or -)
+                                  number of charges for wand ( >= -1 )
+                                  marks your eggs, spinach tins
+                                  royal coffers for a court ( == 2)
+                                  tells which fruit a fruit is
+                                  special for uball and amulet
+                                  historic and gender for statues */
+#define STATUE_HISTORIC 0x01
+#define STATUE_MALE     0x02
+#define STATUE_FEMALE   0x04
+       char    oclass;         /* object class */
+       char    invlet;         /* designation in inventory */
+       char    oartifact;      /* artifact array index */
+
+       xchar where;            /* where the object thinks it is */
+#define OBJ_FREE       0               /* object not attached to anything */
+#define OBJ_FLOOR      1               /* object on floor */
+#define OBJ_CONTAINED  2               /* object in a container */
+#define OBJ_INVENT     3               /* object in the hero's inventory */
+#define OBJ_MINVENT    4               /* object in a monster inventory */
+#define OBJ_MIGRATING  5               /* object sent off to another level */
+#define OBJ_BURIED     6               /* object buried */
+#define OBJ_ONBILL     7               /* object on shk bill */
+#define NOBJ_STATES    8
+       xchar timed;            /* # of fuses (timers) attached to this obj */
+
+       Bitfield(cursed,1);
+       Bitfield(blessed,1);
+       Bitfield(unpaid,1);     /* on some bill */
+       Bitfield(no_charge,1);  /* if shk shouldn't charge for this */
+       Bitfield(known,1);      /* exact nature known */
+       Bitfield(dknown,1);     /* color or text known */
+       Bitfield(bknown,1);     /* blessing or curse known */
+       Bitfield(rknown,1);     /* rustproof or not known */
+
+       Bitfield(oeroded,2);    /* rusted/burnt weapon/armor */
+       Bitfield(oeroded2,2);   /* corroded/rotted weapon/armor */
+#define greatest_erosion(otmp) (int)((otmp)->oeroded > (otmp)->oeroded2 ? (otmp)->oeroded : (otmp)->oeroded2)
+#define MAX_ERODE 3
+#define orotten oeroded                /* rotten food */
+#define odiluted oeroded       /* diluted potions */
+#define norevive oeroded2
+       Bitfield(oerodeproof,1); /* erodeproof weapon/armor */
+       Bitfield(olocked,1);    /* object is locked */
+       Bitfield(obroken,1);    /* lock has been broken */
+       Bitfield(otrapped,1);   /* container is trapped */
+                               /* or accidental tripped rolling boulder trap */
+#define opoisoned otrapped     /* object (weapon) is coated with poison */
+
+       Bitfield(recharged,3);  /* number of times it's been recharged */
+       Bitfield(lamplit,1);    /* a light-source -- can be lit */
+#ifdef INVISIBLE_OBJECTS
+       Bitfield(oinvis,1);     /* invisible */
+#endif
+       Bitfield(greased,1);    /* covered with grease */
+       Bitfield(oattached,2);  /* obj struct has special attachment */
+#define OATTACHED_NOTHING 0
+#define OATTACHED_MONST   1    /* monst struct in oextra */
+#define OATTACHED_M_ID    2    /* monst id in oextra */
+#define OATTACHED_UNUSED3 3
+
+       Bitfield(in_use,1);     /* for magic items before useup items */
+       Bitfield(bypass,1);     /* mark this as an object to be skipped by bhito() */
+       /* 6 free bits */
+
+       int     corpsenm;       /* type of corpse is mons[corpsenm] */
+#define leashmon  corpsenm     /* gets m_id of attached pet */
+#define spestudied corpsenm    /* # of times a spellbook has been studied */
+#define fromsink  corpsenm     /* a potion from a sink */
+       unsigned oeaten;        /* nutrition left in food, if partly eaten */
+       long age;               /* creation date */
+
+       uchar onamelth;         /* length of name (following oxlth) */
+       short oxlth;            /* length of following data */
+       /* in order to prevent alignment problems oextra should
+          be (or follow) a long int */
+       long owornmask;
+       long oextra[1];         /* used for name of ordinary objects - length
+                                  is flexible; amount for tmp gold objects */
+};
+
+#define newobj(xl)     (struct obj *)alloc((unsigned)(xl) + sizeof(struct obj))
+#define ONAME(otmp)    (((char *)(otmp)->oextra) + (otmp)->oxlth)
+
+/* Weapons and weapon-tools */
+/* KMH -- now based on skill categories.  Formerly:
+ *     #define is_sword(otmp)  (otmp->oclass == WEAPON_CLASS && \
+ *                      objects[otmp->otyp].oc_wepcat == WEP_SWORD)
+ *     #define is_blade(otmp)  (otmp->oclass == WEAPON_CLASS && \
+ *                      (objects[otmp->otyp].oc_wepcat == WEP_BLADE || \
+ *                       objects[otmp->otyp].oc_wepcat == WEP_SWORD))
+ *     #define is_weptool(o)   ((o)->oclass == TOOL_CLASS && \
+ *                      objects[(o)->otyp].oc_weptool)
+ *     #define is_multigen(otyp) (otyp <= SHURIKEN)
+ *     #define is_poisonable(otyp) (otyp <= BEC_DE_CORBIN)
+ */
+#define is_blade(otmp) (otmp->oclass == WEAPON_CLASS && \
+                        objects[otmp->otyp].oc_skill >= P_DAGGER && \
+                        objects[otmp->otyp].oc_skill <= P_SABER)
+#define is_axe(otmp)   ((otmp->oclass == WEAPON_CLASS || \
+                        otmp->oclass == TOOL_CLASS) && \
+                        objects[otmp->otyp].oc_skill == P_AXE)
+#define is_pick(otmp)  ((otmp->oclass == WEAPON_CLASS || \
+                        otmp->oclass == TOOL_CLASS) && \
+                        objects[otmp->otyp].oc_skill == P_PICK_AXE)
+#define is_sword(otmp) (otmp->oclass == WEAPON_CLASS && \
+                        objects[otmp->otyp].oc_skill >= P_SHORT_SWORD && \
+                        objects[otmp->otyp].oc_skill <= P_SABER)
+#define is_pole(otmp)  ((otmp->oclass == WEAPON_CLASS || \
+                       otmp->oclass == TOOL_CLASS) && \
+                        (objects[otmp->otyp].oc_skill == P_POLEARMS || \
+                        objects[otmp->otyp].oc_skill == P_LANCE))
+#define is_spear(otmp) (otmp->oclass == WEAPON_CLASS && \
+                        objects[otmp->otyp].oc_skill >= P_SPEAR && \
+                        objects[otmp->otyp].oc_skill <= P_JAVELIN)
+#define is_launcher(otmp)      (otmp->oclass == WEAPON_CLASS && \
+                        objects[otmp->otyp].oc_skill >= P_BOW && \
+                        objects[otmp->otyp].oc_skill <= P_CROSSBOW)
+#define is_ammo(otmp)  ((otmp->oclass == WEAPON_CLASS || \
+                        otmp->oclass == GEM_CLASS) && \
+                        objects[otmp->otyp].oc_skill >= -P_CROSSBOW && \
+                        objects[otmp->otyp].oc_skill <= -P_BOW)
+#define ammo_and_launcher(otmp,ltmp) \
+                        (is_ammo(otmp) && (ltmp) && \
+                        objects[(otmp)->otyp].oc_skill == -objects[(ltmp)->otyp].oc_skill)
+#define is_missile(otmp)       ((otmp->oclass == WEAPON_CLASS || \
+                        otmp->oclass == TOOL_CLASS) && \
+                        objects[otmp->otyp].oc_skill >= -P_BOOMERANG && \
+                        objects[otmp->otyp].oc_skill <= -P_DART)
+#define is_weptool(o)  ((o)->oclass == TOOL_CLASS && \
+                        objects[(o)->otyp].oc_skill != P_NONE)
+#define bimanual(otmp) ((otmp->oclass == WEAPON_CLASS || \
+                        otmp->oclass == TOOL_CLASS) && \
+                        objects[otmp->otyp].oc_bimanual)
+#define is_multigen(otmp)      (otmp->oclass == WEAPON_CLASS && \
+                        objects[otmp->otyp].oc_skill >= -P_SHURIKEN && \
+                        objects[otmp->otyp].oc_skill <= -P_BOW)
+#define is_poisonable(otmp)    (otmp->oclass == WEAPON_CLASS && \
+                        objects[otmp->otyp].oc_skill >= -P_SHURIKEN && \
+                        objects[otmp->otyp].oc_skill <= -P_BOW)
+#define uslinging()    (uwep && objects[uwep->otyp].oc_skill == P_SLING)
+
+/* Armor */
+#define is_shield(otmp) (otmp->oclass == ARMOR_CLASS && \
+                        objects[otmp->otyp].oc_armcat == ARM_SHIELD)
+#define is_helmet(otmp) (otmp->oclass == ARMOR_CLASS && \
+                        objects[otmp->otyp].oc_armcat == ARM_HELM)
+#define is_boots(otmp) (otmp->oclass == ARMOR_CLASS && \
+                        objects[otmp->otyp].oc_armcat == ARM_BOOTS)
+#define is_gloves(otmp) (otmp->oclass == ARMOR_CLASS && \
+                        objects[otmp->otyp].oc_armcat == ARM_GLOVES)
+#define is_cloak(otmp) (otmp->oclass == ARMOR_CLASS && \
+                        objects[otmp->otyp].oc_armcat == ARM_CLOAK)
+#define is_shirt(otmp) (otmp->oclass == ARMOR_CLASS && \
+                        objects[otmp->otyp].oc_armcat == ARM_SHIRT)
+#define is_suit(otmp)  (otmp->oclass == ARMOR_CLASS && \
+                        objects[otmp->otyp].oc_armcat == ARM_SUIT)
+#define is_elven_armor(otmp)   ((otmp)->otyp == ELVEN_LEATHER_HELM\
+                               || (otmp)->otyp == ELVEN_MITHRIL_COAT\
+                               || (otmp)->otyp == ELVEN_CLOAK\
+                               || (otmp)->otyp == ELVEN_SHIELD\
+                               || (otmp)->otyp == ELVEN_BOOTS)
+#define is_orcish_armor(otmp)  ((otmp)->otyp == ORCISH_HELM\
+                               || (otmp)->otyp == ORCISH_CHAIN_MAIL\
+                               || (otmp)->otyp == ORCISH_RING_MAIL\
+                               || (otmp)->otyp == ORCISH_CLOAK\
+                               || (otmp)->otyp == URUK_HAI_SHIELD\
+                               || (otmp)->otyp == ORCISH_SHIELD)
+#define is_dwarvish_armor(otmp)        ((otmp)->otyp == DWARVISH_IRON_HELM\
+                               || (otmp)->otyp == DWARVISH_MITHRIL_COAT\
+                               || (otmp)->otyp == DWARVISH_CLOAK\
+                               || (otmp)->otyp == DWARVISH_ROUNDSHIELD)
+#define is_gnomish_armor(otmp) (FALSE)
+
+                               
+/* Eggs and other food */
+#define MAX_EGG_HATCH_TIME 200 /* longest an egg can remain unhatched */
+#define stale_egg(egg) ((monstermoves - (egg)->age) > (2*MAX_EGG_HATCH_TIME))
+#define ofood(o) ((o)->otyp == CORPSE || (o)->otyp == EGG || (o)->otyp == TIN)
+#define polyfodder(obj) (ofood(obj) && \
+                        pm_to_cham((obj)->corpsenm) != CHAM_ORDINARY)
+#define mlevelgain(obj) (ofood(obj) && (obj)->corpsenm == PM_WRAITH)
+#define mhealup(obj)   (ofood(obj) && (obj)->corpsenm == PM_NURSE)
+
+/* Containers */
+#define carried(o)     ((o)->where == OBJ_INVENT)
+#define mcarried(o)    ((o)->where == OBJ_MINVENT)
+#define Has_contents(o) (/* (Is_container(o) || (o)->otyp == STATUE) && */ \
+                        (o)->cobj != (struct obj *)0)
+#define Is_container(o) ((o)->otyp >= LARGE_BOX && (o)->otyp <= BAG_OF_TRICKS)
+#define Is_box(otmp)   (otmp->otyp == LARGE_BOX || otmp->otyp == CHEST)
+#define Is_mbag(otmp)  (otmp->otyp == BAG_OF_HOLDING || \
+                        otmp->otyp == BAG_OF_TRICKS)
+
+/* dragon gear */
+#define Is_dragon_scales(obj)  ((obj)->otyp >= GRAY_DRAGON_SCALES && \
+                                (obj)->otyp <= YELLOW_DRAGON_SCALES)
+#define Is_dragon_mail(obj)    ((obj)->otyp >= GRAY_DRAGON_SCALE_MAIL && \
+                                (obj)->otyp <= YELLOW_DRAGON_SCALE_MAIL)
+#define Is_dragon_armor(obj)   (Is_dragon_scales(obj) || Is_dragon_mail(obj))
+#define Dragon_scales_to_pm(obj) &mons[PM_GRAY_DRAGON + (obj)->otyp \
+                                      - GRAY_DRAGON_SCALES]
+#define Dragon_mail_to_pm(obj) &mons[PM_GRAY_DRAGON + (obj)->otyp \
+                                     - GRAY_DRAGON_SCALE_MAIL]
+#define Dragon_to_scales(pm)   (GRAY_DRAGON_SCALES + (pm - mons))
+
+/* Elven gear */
+#define is_elven_weapon(otmp)  ((otmp)->otyp == ELVEN_ARROW\
+                               || (otmp)->otyp == ELVEN_SPEAR\
+                               || (otmp)->otyp == ELVEN_DAGGER\
+                               || (otmp)->otyp == ELVEN_SHORT_SWORD\
+                               || (otmp)->otyp == ELVEN_BROADSWORD\
+                               || (otmp)->otyp == ELVEN_BOW)
+#define is_elven_obj(otmp)     (is_elven_armor(otmp) || is_elven_weapon(otmp))
+
+/* Orcish gear */
+#define is_orcish_obj(otmp)    (is_orcish_armor(otmp)\
+                               || (otmp)->otyp == ORCISH_ARROW\
+                               || (otmp)->otyp == ORCISH_SPEAR\
+                               || (otmp)->otyp == ORCISH_DAGGER\
+                               || (otmp)->otyp == ORCISH_SHORT_SWORD\
+                               || (otmp)->otyp == ORCISH_BOW)
+
+/* Dwarvish gear */
+#define is_dwarvish_obj(otmp)  (is_dwarvish_armor(otmp)\
+                               || (otmp)->otyp == DWARVISH_SPEAR\
+                               || (otmp)->otyp == DWARVISH_SHORT_SWORD\
+                               || (otmp)->otyp == DWARVISH_MATTOCK)
+
+/* Gnomish gear */
+#define is_gnomish_obj(otmp)   (is_gnomish_armor(otmp))
+
+/* Light sources */
+#define Is_candle(otmp) (otmp->otyp == TALLOW_CANDLE || \
+                        otmp->otyp == WAX_CANDLE)
+#define MAX_OIL_IN_FLASK 400   /* maximum amount of oil in a potion of oil */
+
+/* MAGIC_LAMP intentionally excluded below */
+/* age field of this is relative age rather than absolute */
+#define age_is_relative(otmp)  ((otmp)->otyp == BRASS_LANTERN\
+                               || (otmp)->otyp == OIL_LAMP\
+                               || (otmp)->otyp == CANDELABRUM_OF_INVOCATION\
+                               || (otmp)->otyp == TALLOW_CANDLE\
+                               || (otmp)->otyp == WAX_CANDLE\
+                               || (otmp)->otyp == POT_OIL)
+/* object can be ignited */
+#define ignitable(otmp)        ((otmp)->otyp == BRASS_LANTERN\
+                               || (otmp)->otyp == OIL_LAMP\
+                               || (otmp)->otyp == CANDELABRUM_OF_INVOCATION\
+                               || (otmp)->otyp == TALLOW_CANDLE\
+                               || (otmp)->otyp == WAX_CANDLE\
+                               || (otmp)->otyp == POT_OIL)
+
+/* special stones */
+#define is_graystone(obj)      ((obj)->otyp == LUCKSTONE || \
+                                (obj)->otyp == LOADSTONE || \
+                                (obj)->otyp == FLINT     || \
+                                (obj)->otyp == TOUCHSTONE)
+
+/* misc */
+#ifdef KOPS
+#define is_flimsy(otmp)                (objects[(otmp)->otyp].oc_material <= LEATHER || \
+                                (otmp)->otyp == RUBBER_HOSE)
+#else
+#define is_flimsy(otmp)                (objects[(otmp)->otyp].oc_material <= LEATHER)
+#endif
+
+/* helpers, simple enough to be macros */
+#define is_plural(o)   ((o)->quan > 1 || \
+                        (o)->oartifact == ART_EYES_OF_THE_OVERWORLD)
+
+/* Flags for get_obj_location(). */
+#define CONTAINED_TOO  0x1
+#define BURIED_TOO     0x2
+
+#endif /* OBJ_H */
diff --git a/include/objclass.h b/include/objclass.h
new file mode 100644 (file)
index 0000000..0af21a4
--- /dev/null
@@ -0,0 +1,186 @@
+/*     SCCS Id: @(#)objclass.h 3.4     1996/06/16      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef OBJCLASS_H
+#define OBJCLASS_H
+
+/* definition of a class of objects */
+
+struct objclass {
+       short   oc_name_idx;            /* index of actual name */
+       short   oc_descr_idx;           /* description when name unknown */
+       char *  oc_uname;               /* called by user */
+       Bitfield(oc_name_known,1);
+       Bitfield(oc_merge,1);   /* merge otherwise equal objects */
+       Bitfield(oc_uses_known,1); /* obj->known affects full decription */
+                               /* otherwise, obj->dknown and obj->bknown */
+                               /* tell all, and obj->known should always */
+                               /* be set for proper merging behavior */
+       Bitfield(oc_pre_discovered,1);  /* Already known at start of game; */
+                                       /* won't be listed as a discovery. */
+       Bitfield(oc_magic,1);   /* inherently magical object */
+       Bitfield(oc_charged,1); /* may have +n or (n) charges */
+       Bitfield(oc_unique,1);  /* special one-of-a-kind object */
+       Bitfield(oc_nowish,1);  /* cannot wish for this object */
+
+       Bitfield(oc_big,1);
+#define oc_bimanual    oc_big  /* for weapons & tools used as weapons */
+#define oc_bulky       oc_big  /* for armor */
+       Bitfield(oc_tough,1);   /* hard gems/rings */
+
+       Bitfield(oc_dir,2);
+#define NODIR          1       /* for wands/spells: non-directional */
+#define IMMEDIATE      2       /*                   directional */
+#define RAY            3       /*                   zap beams */
+
+#define PIERCE         1       /* for weapons & tools used as weapons */
+#define SLASH          2       /* (latter includes iron ball & chain) */
+#define WHACK          0
+
+       /*Bitfield(oc_subtyp,3);*/      /* Now too big for a bitfield... see below */
+
+       Bitfield(oc_material,5);
+#define LIQUID         1       /* currently only for venom */
+#define WAX            2
+#define VEGGY          3       /* foodstuffs */
+#define FLESH          4       /*   ditto    */
+#define PAPER          5
+#define CLOTH          6
+#define LEATHER                7
+#define WOOD           8
+#define BONE           9
+#define DRAGON_HIDE    10      /* not leather! */
+#define IRON           11      /* Fe - includes steel */
+#define METAL          12      /* Sn, &c. */
+#define COPPER         13      /* Cu - includes brass */
+#define SILVER         14      /* Ag */
+#define GOLD           15      /* Au */
+#define PLATINUM       16      /* Pt */
+#define MITHRIL                17
+#define PLASTIC                18
+#define GLASS          19
+#define GEMSTONE       20
+#define MINERAL                21
+
+#define is_organic(otmp)       (objects[otmp->otyp].oc_material <= WOOD)
+#define is_metallic(otmp)      (objects[otmp->otyp].oc_material >= IRON && \
+                                objects[otmp->otyp].oc_material <= MITHRIL)
+
+/* primary damage: fire/rust/--- */
+/* is_flammable(otmp), is_rottable(otmp) in mkobj.c */
+#define is_rustprone(otmp)     (objects[otmp->otyp].oc_material == IRON)
+
+/* secondary damage: rot/acid/acid */
+#define is_corrodeable(otmp)   (objects[otmp->otyp].oc_material == COPPER || objects[otmp->otyp].oc_material == IRON)
+
+#define is_damageable(otmp) (is_rustprone(otmp) || is_flammable(otmp) || \
+                               is_rottable(otmp) || is_corrodeable(otmp))
+
+       schar   oc_subtyp;
+#define oc_skill       oc_subtyp   /* Skills of weapons, spellbooks, tools, gems */
+#define oc_armcat      oc_subtyp   /* for armor */
+#define ARM_SHIELD     1       /* needed for special wear function */
+#define ARM_HELM       2
+#define ARM_GLOVES     3
+#define ARM_BOOTS      4
+#define ARM_CLOAK      5
+#define ARM_SHIRT      6
+#define ARM_SUIT       0
+
+       uchar   oc_oprop;               /* property (invis, &c.) conveyed */
+       char    oc_class;               /* object class */
+       schar   oc_delay;               /* delay when using such an object */
+       uchar   oc_color;               /* color of the object */
+
+       short   oc_prob;                /* probability, used in mkobj() */
+       unsigned short  oc_weight;      /* encumbrance (1 cn = 0.1 lb.) */
+       short   oc_cost;                /* base cost in shops */
+/* Check the AD&D rules!  The FIRST is small monster damage. */
+/* for weapons, and tools, rocks, and gems useful as weapons */
+       schar   oc_wsdam, oc_wldam;     /* max small/large monster damage */
+       schar   oc_oc1, oc_oc2;
+#define oc_hitbon      oc_oc1          /* weapons: "to hit" bonus */
+
+#define a_ac           oc_oc1  /* armor class, used in ARM_BONUS in do.c */
+#define a_can          oc_oc2          /* armor: used in mhitu.c */
+#define oc_level       oc_oc2          /* books: spell level */
+
+       unsigned short  oc_nutrition;   /* food value */
+};
+
+struct objdescr {
+       const char *oc_name;            /* actual name */
+       const char *oc_descr;           /* description when name unknown */
+};
+
+extern NEARDATA struct objclass objects[];
+extern NEARDATA struct objdescr obj_descr[];
+
+/*
+ * All objects have a class. Make sure that all classes have a corresponding
+ * symbol below.
+ */
+#define RANDOM_CLASS    0      /* used for generating random objects */
+#define ILLOBJ_CLASS    1
+#define WEAPON_CLASS    2
+#define ARMOR_CLASS     3
+#define RING_CLASS      4
+#define AMULET_CLASS    5
+#define TOOL_CLASS      6
+#define FOOD_CLASS      7
+#define POTION_CLASS    8
+#define SCROLL_CLASS    9
+#define SPBOOK_CLASS   10      /* actually SPELL-book */
+#define WAND_CLASS     11
+#define COIN_CLASS     12
+#define GEM_CLASS      13
+#define ROCK_CLASS     14
+#define BALL_CLASS     15
+#define CHAIN_CLASS    16
+#define VENOM_CLASS    17
+#define MAXOCLASSES    18
+
+#define ALLOW_COUNT    (MAXOCLASSES+1) /* Can be used in the object class */
+#define ALL_CLASSES    (MAXOCLASSES+2) /* input to getobj().              */
+#define ALLOW_NONE     (MAXOCLASSES+3) /*                                 */
+
+#define BURNING_OIL    (MAXOCLASSES+1) /* Can be used as input to explode. */
+#define MON_EXPLODE    (MAXOCLASSES+2) /* Exploding monster (e.g. gas spore) */
+
+#if 0  /* moved to decl.h so that makedefs.c won't see them */
+extern const char def_oc_syms[MAXOCLASSES];    /* default class symbols */
+extern uchar oc_syms[MAXOCLASSES];             /* current class symbols */
+#endif
+
+/* Default definitions of all object-symbols (must match classes above). */
+
+#define ILLOBJ_SYM     ']'     /* also used for mimics */
+#define WEAPON_SYM     ')'
+#define ARMOR_SYM      '['
+#define RING_SYM       '='
+#define AMULET_SYM     '"'
+#define TOOL_SYM       '('
+#define FOOD_SYM       '%'
+#define POTION_SYM     '!'
+#define SCROLL_SYM     '?'
+#define SPBOOK_SYM     '+'
+#define WAND_SYM       '/'
+#define GOLD_SYM       '$'
+#define GEM_SYM                '*'
+#define ROCK_SYM       '`'
+#define BALL_SYM       '0'
+#define CHAIN_SYM      '_'
+#define VENOM_SYM      '.'
+
+struct fruit {
+       char fname[PL_FSIZ];
+       int fid;
+       struct fruit *nextf;
+};
+#define newfruit() (struct fruit *)alloc(sizeof(struct fruit))
+#define dealloc_fruit(rind) free((genericptr_t) (rind))
+
+#define OBJ_NAME(obj)  (obj_descr[(obj).oc_name_idx].oc_name)
+#define OBJ_DESCR(obj) (obj_descr[(obj).oc_descr_idx].oc_descr)
+#endif /* OBJCLASS_H */
diff --git a/include/os2conf.h b/include/os2conf.h
new file mode 100644 (file)
index 0000000..b706df1
--- /dev/null
@@ -0,0 +1,107 @@
+/*     SCCS Id: @(#)os2conf.h  3.4     1996/10/29      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* Copyright (c) Timo Hakulinen, 1990, 1991, 1992, 1993, 1996. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifdef OS2
+#ifndef OS2CONF_H
+#define OS2CONF_H
+
+/*
+ * Compiler configuration.  Compiler may be
+ * selected either here or in Makefile.os2.
+ */
+
+/* #define OS2_MSC             /* Microsoft C 5.1 and 6.0 */
+#define OS2_GCC                /* GCC emx 0.8f */
+/* #define OS2_CSET2           /* IBM C Set/2 (courtesy Jeff Urlwin) */
+/* #define OS2_CSET2_VER_1     /* CSet/2 version selection */
+/* #define OS2_CSET2_VER_2     /* - " - */
+
+/*
+ * System configuration.
+ */
+
+#define OS2_USESYSHEADERS      /* use compiler's own system headers */
+/* #define OS2_HPFS            /* use OS/2 High Performance File System */
+
+#if defined(OS2_GCC) || defined(OS2_CSET2)
+# define OS2_32BITAPI          /* enable for compilation in OS/2 2.0 */
+#endif
+
+/*
+ * Other configurable options.  Generally no
+ * reason to touch the defaults, I think.
+ */
+
+/*#define MFLOPPY                      /* floppy and ramdisk support */
+#define RANDOM                 /* Berkeley random(3) */
+#define SHELL                  /* shell escape */
+/* #define TERMLIB             /* use termcap file */
+#define ANSI_DEFAULT           /* allows NetHack to run without termcap file */
+#define TEXTCOLOR              /* allow color */
+
+/*
+ * The remaining code shouldn't need modification.
+ */
+
+#ifdef MSDOS
+# undef MSDOS                  /* MSC autodefines this but we don't want it */
+#endif
+
+#ifndef MICRO
+# define MICRO                 /* must be defined to allow some inclusions */
+#endif
+
+#if !defined(TERMLIB) && !defined(ANSI_DEFAULT)
+# define ANSI_DEFAULT  /* have to have one or the other */
+#endif
+
+#define PATHLEN        260     /* maximum pathlength (HPFS) */
+#define FILENAME       260     /* maximum filename length (HPFS) */
+#ifndef MICRO_H
+#include "micro.h"             /* necessary externs for [os_name].c */
+#endif
+
+#ifndef SYSTEM_H
+#include "system.h"
+#endif
+
+#ifndef index
+#define index  strchr
+#endif
+#ifndef rindex
+#define rindex strrchr
+#endif
+
+#include <time.h>
+
+/* the high quality random number routines */
+
+#ifdef RANDOM
+# define Rand()        random()
+#else
+# define Rand()        rand()
+#endif
+
+/* file creation mask */
+
+#include <sys\types.h>
+#include <sys\stat.h>
+
+#define FCMASK (S_IREAD | S_IWRITE)
+
+#include <fcntl.h>
+
+#ifdef __EMX__
+#include <unistd.h>
+#endif
+
+#ifndef REDO
+# undef        Getchar
+# define Getchar nhgetch
+#endif
+
+void hangup(int i);
+#endif /* OS2CONF_H */
+#endif /* OS2 */
diff --git a/include/patchlevel.h b/include/patchlevel.h
new file mode 100644 (file)
index 0000000..5704523
--- /dev/null
@@ -0,0 +1,404 @@
+/*     SCCS Id: @(#)patchlevel.h       3.4     2003/12/06      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* NetHack 3.4.3 */
+#define VERSION_MAJOR  3
+#define VERSION_MINOR  4
+/*
+ * PATCHLEVEL is updated for each release.
+ */
+#define PATCHLEVEL     3
+/*
+ * Incrementing EDITLEVEL can be used to force invalidation of old bones
+ * and save files.
+ */
+#define EDITLEVEL      0
+
+#define COPYRIGHT_BANNER_A \
+"NetHack, Copyright 1985-2003"
+
+#define COPYRIGHT_BANNER_B \
+"         By Stichting Mathematisch Centrum and M. Stephenson."
+
+#define COPYRIGHT_BANNER_C \
+"         See license for details."
+
+/*
+ * If two or more successive releases have compatible data files, define
+ * this with the version number of the oldest such release so that the
+ * new release will accept old save and bones files.  The format is
+ *     0xMMmmPPeeL
+ * 0x = literal prefix "0x", MM = major version, mm = minor version,
+ * PP = patch level, ee = edit level, L = literal suffix "L",
+ * with all four numbers specified as two hexadecimal digits.
+ */
+#define VERSION_COMPATIBILITY 0x03040000L      /* 3.4.0-0 */
+
+
+/*****************************************************************************/
+/* Version 3.4.x */
+
+/*  Patch 3, December 7, 2003
+ *  Several dozen general bug fixes including at least one fatal bug
+ *  Correct several inconsistencies
+ *  Handle level completely filled with monsters better
+ *  Performance enhancements for win32tty port on Windows 98 and Me
+ *  win32gui player selection fixes
+ *  X11 player selection fixes, one of which could be fatal
+ *  Eliminated a gold-in-shop-container cheat
+ *  Include bones file version compatibility info in options file
+ */
+
+/*  Patch 2, August 30, 2003
+ *  Fix a fatal bug that caused a crash when applying figurine, candle, or
+ *      bell that gets used up
+ *  Fix a fatal bug that triggered a panic when your secondary weapon was
+ *      cursed during bones file creation
+ *  Several dozen general bug fixes
+ *  Fixed some Gnome compilation problems on Redhat 7.2 and 8.0
+ *  Fixed a problem in the util Makefile
+ *  Use random() by default under linux instead of lrand48()
+ *  win32 tty adjustments and support for loading alternative key handlers
+ */
+
+/*  Patch 1, February 22, 2003
+ *  Fix a few fatal errors including one for reentering shops, one
+ *     involving land mines and boulders/statues, one for delayed
+ *     polymorph, and one from a chest trap exploding ball and chain
+ *  Fix a buffer overflow that could lead to security problems
+ *  Hundreds of general bug fixes
+ *  Several message and other glitches corrected
+ *  Travel command adjustments and ability to disable travel command
+ *  message recall window extensions (by Christian Cooper)
+ *  win32: some interface improvements
+ *  unix: improved tile support
+ *  gnome: some fixes, and some enhancements by Dylan Alex Simon
+ *  winCE: Windows CE port included (by Alex Kompel)
+ */
+
+/*
+ *  NetHack 3.4.0, March 20, 2002
+ *
+ *  Hundreds of general bug fixes including some for sliming, zapping, conduct,
+ *     and several more for riding
+ *  Eliminated a few potentially fatal bugs including one for stone-to-flesh,
+ *     trouble-fixing during prayer, riding down stairs while punished,
+ *     polyd player demon summoning, throwing digging tools into shops, and
+ *     a couple from having the vision system enabled at inappropriate times 
+ *  Corrected some incorrect calculations in final scoring
+ *  Enhanced config file processing and alert to duplication of entries
+ *  Player selection prompt enhancements for TTY and X11
+ *  Objects merge in containers
+ *  Wish for "nothing", and genocide "none" to preserve your conduct
+ *  Changes to Wizard quest
+ *  Added the travel command which works by mouse click or '_' command
+ *  Config file BOULDER option to specify the symbol for displaying boulders
+ *  Incorporate modified versions of several 3.3.1 patches that have been
+ *      in circulation in the NetHack community
+ *  New Gnomish Mines levels (courtesy Kelly Bailey)
+ *  Mac: command-key shortcuts in the player selection dialog
+ *  Amiga: screenmode requester, and several amiga specific bug fixes
+ *  Win32 graphical port contributed by Alex Kompel is now included
+ */
+
+/* Version 3.4 */
+
+/*****************************************************************************/
+/* Version 3.3.x */
+
+/*  Patch 1, August 9, 2000
+ *  Many, many general fixes, including a number for riding, twoweapon,
+ *     and invisible monsters
+ *  A security fix for a couple of potentially exploitable buffer overflows
+ *     in previous versions
+ *  Redo Ranger quest
+ *  Introduction of differentiation between different causes of blindness
+ *  Overhaul of warning
+ *  Functionality restored to Amiga (courtesy Janne Salmijarvi) and Atari
+ *     (courtesy Christian "Marvin" Bressler) ports
+ *  Mac: multiple interface fixes
+ *  win32: fixed bug that caused messages to stop displaying after escape
+ *  tty: use ANSI color (AF) over standard color (Sf) when given the choice
+ *  several ports: offer for player selection only choices consistent with
+ *     those already made by config file/command line (e.g., only offer roles
+ *     that are compatible with specified race)
+ */
+
+/*
+ *  NetHack 3.3.0, December 10, 1999
+ *
+ *  Implement the differentiation of character class or role from the
+ *  character race.
+ *  Removal of the Elf class, in preference to the Elf as a race.
+ *  Introduction of Dwarves, Elves, Gnomes and Orcs as distinct races in
+ *  addition to the Human "norm".
+ *  Addition of the Monk and Ranger classes.
+ *  Integrate some of the features of several branch versions of the game,
+ *  notably NetHack--, NHplus, SLASH, and Slash'em.
+ *  Adopt "the wizard patch" spellcasting system.
+ *  Support for the Qt widget set.
+ *  Y2K fix: use 4 digit year values for the dates in the score file
+ *  updated COPYRIGHT_BANNER_A to reflect year of release.
+ *  Dozens of other bug fixes, and minor improvements.
+ */
+
+/* Version 3.3 */
+
+/*****************************************************************************/
+/* Version 3.2.x */
+
+/*  Patch 3, December 10, 1999
+ *  Released simultaneously with 3.3.0 for the benefit of
+ *  ports and platforms that were unable to get working
+ *  versions of 3.3.0 ready prior to the year 2000. It
+ *  consisted of just a few bug fixes and offered no new
+ *  functionality changes over 3.2.2.
+ *
+ *  Y2K fix: use 4 digit year values for the dates in the score file
+ *  updated COPYRIGHT_BANNER_A to reflect year of release
+ *  Fatal Mac bug removed
+ *  DOS Makefile problem removed
+ *  several bugs that could potentially trigger crashes removed
+ */
+
+/*  Patch 2, December 10, 1996
+ *  fix the `recover' utility
+ *  fix priest/minion name overflow which could cause Astral Plane crashes
+ *  avoid crash when hit by own thrown boomerang
+ *    "     "   "   worn blindfold pushed off by applying cursed towel
+ *  handle returning live Wizard correctly in deep dungeon levels
+ *  don't occasionally display unseen areas of new levels during level change
+ *  other minor display fixes
+ *  fix several minor reason for death inconsistencies and shop bugs
+ *  high dexterity doesn't guarantee that thrown eggs & potions will hit
+ *
+ *  Selected platform- or configuration-specific changes:
+ *  Mac: update `mrecover'
+ *  MSDOS: don't switch into tiles mode when resuming play on rogue level
+ *  tty: support object class characters for 'I' command in menu mode
+ *  Unix: work around several <curses.h> compilation problems
+ *  X11: as tty above, plus implement tty-style count handling in menus;
+ *     better window placement support for old window managers
+ */
+
+/*  Patch 1, May 28, 1996
+ *  eliminate `#qualifications'; fix weapon proficiency handling for missiles
+ *  keep Medusa from continuing to move after she's been killed by reflection
+ *     of her own gaze (fixes relmon panic)
+ *  make monsters a little smarter; assorted eating and chatting changes
+ *  fix object amnesia for spellbooks; fix Nazgul's sleep gas attack
+ *  fix bullwhip usage for case of having recently been in a trap
+ *  egg hatching fixes, oil potion fixes, magic marker fixes
+ *  support object class chars as selection accelerators for some menus
+ *  stricter parsing of run-time options at startup time
+ *  interactive setting of options via menu (courtesy Per Liboriussen)
+ *
+ *  Selected platform- or configuration-specific changes:
+ *  Amiga: fix panic for tiles display in Gnomish mines
+ *  BeOS: preliminary support for new BeBox platform; initially tty only
+ *  DLB: avoid excessive fseek calls (major performance hit for MSDOS)
+ *  HPUX: workaround for gcc-2.6.3 bug adversely affecting monster generation
+ *  Mac: avoid MW 68K struct copy optimization bug which caused crashes;
+ *     fix dragging of scrollbar; boost partitions to 2MB minimum
+ *  MSDOS: wasn't safe to enter endgame for MFLOPPY configuration;
+ *     fix re-entry into game after "!" (shell escape) + chdir + EXIT;
+ *     F3/F4/F5 display interface swapping improvements;
+ *     add support for preloading all tiles in protected mode environment
+ *  TERMINFO: colors were wrong for some systems, such as Linux
+ *  X11: display help files properly
+ */
+
+/*
+ *  NetHack 3.2.0, April 11, 1996
+ *  enhancements to the windowing systems including "tiles" or icons to
+ *     visually represent monsters and objects (courtesy Warwick Allison)
+ *  window based menu system introduced for inventory and selection
+ *  moving light sources besides the player
+ *  improved #untrap (courtesy Helge Hafting)
+ *  spellcasting logic changes to balance spellcasting towards magic-using
+ *     classes (courtesy Stephen White)
+ *  many, many bug fixes and abuse eliminations
+ */
+
+/* Version 3.2 */
+
+/*****************************************************************************/
+/* Version 3.1.x */
+
+/*
+ *  Patch 3, July 12, 1993
+ *  further revise Mac windowing and extend to Think C (courtesy
+ *     Barton House)
+ *  fix confusing black/gray/white display on some MSDOS hardware
+ *  remove fatal bugs dealing with horns of plenty and VMS bones levels,
+ *     as well as more minor ones
+ */
+
+/*
+ *  Patch 2, June 1, 1993
+ *  add tty windowing to Mac and Amiga ports and revise native windowing
+ *  allow direct screen I/O for MS-DOS versions instead of going through
+ *     termcap routines (courtesy Michael Allison and Kevin Smolkowski)
+ *  changes for NEC PC-9800 and various termcap.zip fixes by Yamamoto Keizo
+ *  SYSV 386 music driver ported to 386BSD (courtesy Andrew Chernov) and
+ *     SCO UNIX (courtesy Andreas Arens)
+ *  enhanced pickup and disclosure options
+ *  removed fatal bugs dealing with cursed bags of holding, renaming
+ *     shopkeepers, objects falling through trapdoors on deep levels,
+ *     and kicking embedded objects loose, and many more minor ones
+ */
+
+/*
+ *  Patch 1, February 25, 1993
+ *  add Windows NT console port (courtesy Michael Allison)
+ *  polishing of Amiga, Mac, and X11 windowing
+ *  fixing many small bugs, including the infamous 3.0 nurse relmon bug
+ */
+
+/*
+ *  NetHack 3.1.0, January 25, 1993
+ *  many, many changes and bugfixes -- some of the highlights include:
+ *  display rewrite using line-of-sight vision
+ *  general window interface, with the ability to use multiple interfaces
+ *     in the same executable
+ *  intelligent monsters
+ *  enhanced dungeon mythology
+ *  branching dungeons with more special levels, quest dungeons, and
+ *     multi-level endgame
+ *  more artifacts and more uses for artifacts
+ *  generalization to multiple shops with damage repair
+ *  X11 interface
+ *  ability to recover crashed games
+ *  full rewrite of Macintosh port
+ *  Amiga splitter
+ *  directory rearrangement (dat, doc, sys, win, util)
+ */
+
+/* Version 3.1 */
+
+/*****************************************************************************/
+/* Version 3.0 */
+
+/*
+ *  Patch 10, February 5, 1991
+ *  extend overlay manager to multiple files for easier binary distribution
+ *  allow for more system and compiler variance
+ *  remove more small insects
+ */
+
+/*
+ *  Patch 9, June 26, 1990
+ *  clear up some confusing documentation
+ *  smooth some more rough edges in various ports
+ *  and fix a couple more bugs
+ */
+
+/*
+ *  Patch 8, June 3, 1990
+ *  further debug and refine Macintosh port
+ *  refine the overlay manager, rearrange the OVLx breakdown for better
+ *     efficiency, rename the overlay macros, and split off the overlay
+ *     instructions to Install.ovl
+ *  introduce NEARDATA for better Amiga efficiency
+ *  support for more VMS versions (courtesy Joshua Delahunty and Pat Rankin)
+ *  more const fixes
+ *  better support for common graphics (DEC VT and IBM)
+ *  and a number of simple fixes and consistency extensions
+ */
+
+/*
+ *  Patch 7, February 19, 1990
+ *  refine overlay support to handle portions of .c files through OVLx
+ *     (courtesy above plus Kevin Smolkowski)
+ *  update and extend Amiga port and documentation (courtesy Richard Addison,
+ *     Jochen Erwied, Mark Gooderum, Ken Lorber, Greg Olson, Mike Passaretti,
+ *     and Gregg Wonderly)
+ *  refine and extend Macintosh port and documentation (courtesy Johnny Lee,
+ *     Kevin Sitze, Michael Sokolov, Andy Swanson, Jon Watte, and Tom West)
+ *  refine VMS documentation
+ *  continuing ANSIfication, this time of const usage
+ *  teach '/' about differences within monster classes
+ *  smarter eating code (yet again), death messages, and treatment of
+ *     non-animal monsters, monster unconsciousness, and naming
+ *  extended version command to give compilation options
+ *  and the usual bug fixes and hole plugs
+ */
+
+/*
+ *  Patch 6, November 19, 1989
+ *  add overlay support for MS-DOS (courtesy Pierre Martineau, Stephen
+ *     Spackman, and Norm Meluch)
+ *  refine Macintosh port
+ *  different door states show as different symbols (courtesy Ari Huttunen)
+ *  smarter drawbridges (courtesy Kevin Darcy)
+ *  add CLIPPING and split INFERNO off HARD
+ *  further refine eating code wrt picking up and resumption
+ *  make first few levels easier, by adding :x monsters and increasing initial
+ *     attribute points and hitting probability
+ *  teach '/' about configurable symbols
+ */
+
+/*
+ *  Patch 5, October 15, 1989
+ *  add support for Macintosh OS (courtesy Johnny Lee)
+ *  fix annoying dependency loop via new color.h file
+ *  allow interruption while eating -- general handling of partially eaten food
+ *  smarter treatment of iron balls (courtesy Kevin Darcy)
+ *  a handful of other bug fixes
+ */
+
+/*
+ *  Patch 4, September 27, 1989
+ *  add support for VMS (courtesy David Gentzel)
+ *  move monster-on-floor references into functions and implement the new
+ *     lookup structure for both objects and monsters
+ *  extend the definitions of objects and monsters to provide "living color"
+ *     in the dungeon, instead of a single monster color
+ *  ifdef varargs usage to satisfy ANSI compilers
+ *  standardize on the color 'gray'
+ *  assorted bug fixes
+ */
+
+/*
+ *  Patch 3, September 6, 1989
+ *  add war hammers and revise object prices
+ *  extend prototypes to ANSI compilers in addition to the previous MSDOS ones
+ *  move object-on-floor references into functions in preparation for planned
+ *     data structures to allow faster access and better colors
+ *  fix some more bugs, and extend the portability of things added in earlier
+ *     patches
+ */
+
+/*
+ *  Patch 2, August 16, 1989
+ *  add support for OS/2 (courtesy Timo Hakulinen)
+ *  add a better makefile for MicroSoft C (courtesy Paul Gyugyi)
+ *  more accomodation of compilers and preprocessors
+ *  add better screen-size sensing
+ *  expand color use for PCs and introduce it for SVR3 UNIX machines
+ *  extend '/' to multiple identifications
+ *  allow meta key to be used to invoke extended commands
+ *  fix various minor bugs, and do further code cleaning
+ */
+
+/*
+ *  Patch 1, July 31, 1989
+ *  add support for Atari TOS (courtesy Eric Smith) and Andrew File System
+ *     (courtesy Ralf Brown)
+ *  include the uuencoded version of termcap.arc for the MSDOS versions that
+ *     was included with 2.2 and 2.3
+ *  make a number of simple changes to accommodate various compilers
+ *  fix a handful of bugs, and do some code cleaning elsewhere
+ *  add more instructions for new environments and things commonly done wrong
+ */
+
+/*
+ *  NetHack 3.0 baseline release, July, 1989
+ */
+
+/* Version 3.0 */
+
+/*****************************************************************************/
+
+/*patchlevel.h*/
diff --git a/include/pcconf.h b/include/pcconf.h
new file mode 100644 (file)
index 0000000..1df429e
--- /dev/null
@@ -0,0 +1,338 @@
+/*     SCCS Id: @(#)pcconf.h   3.4     1995/10/11      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef PCCONF_H
+#define PCCONF_H
+
+#define MICRO          /* always define this! */
+
+#ifdef MSDOS           /* some of this material is MS-DOS specific */
+
+/*
+ *  Automatic Defines:
+ *
+ *     __GO32__ is defined automatically by the djgpp port of gcc.
+ *     __DJGPP__ is defined automatically by djgpp version 2 and above.
+ *     _MSC_VER is defined automatically by Microsoft C.
+ *     __BORLANDC__ is defined automatically by Borland C.
+ *     __SC__ is defined automatically by Symantec C.
+ *     Note: 3.4.1 was not verified with Symantec C.
+ */
+
+/*
+ *  The following options are somewhat configurable depending on
+ *  your compiler.
+ */
+
+/*
+ *  For pre-V7.0 Microsoft Compilers only, manually define OVERLAY here.
+ */
+
+/*#define OVERLAY */   /* Manual overlay definition (MSC 6.0ax only) */
+
+# ifndef __GO32__
+#define MFLOPPY                /* Support for floppy drives and ramdisks by dgk */
+# endif
+
+# define SHELL         /* via exec of COMMAND.COM */
+
+# ifdef __BORLANDC__
+#define PCMUSIC                /* Music option, enable very basic pc speaker music notes */
+# endif
+
+/*
+ * Screen control options
+ *
+ * You may uncomment:
+ *                    ANSI_DEFAULT
+ *               or   TERMLIB
+ *               or   ANSI_DEFAULT and TERMLIB
+ *               or   NO_TERMS
+ */
+
+/* # define TERMLIB */    /* enable use of termcap file /etc/termcap */
+                       /* or ./termcap for MSDOS (SAC) */
+                       /* compile and link in Fred Fish's termcap library, */
+                       /* enclosed in TERMCAP.ARC, to use this */
+
+/* # define ANSI_DEFAULT */   /* allows NetHack to run without a ./termcap */
+
+# define NO_TERMS      /* Allows Nethack to run without ansi.sys by linking */
+                       /* screen routines into the .exe     */
+
+# ifdef NO_TERMS       /* if NO_TERMS select one screen package below */
+#define SCREEN_BIOS            /* Use bios calls for all screen control */
+/* #define SCREEN_DJGPPFAST */ /* Use djgpp fast screen routines       */
+# endif
+
+
+/* # define PC9800 */  /* Allows NetHack to run on NEC PC-9800 machines */
+                       /* Yamamoto Keizo */
+
+
+/*
+ * PC video hardware support options (for graphical tile support)
+ *
+ * You may uncomment any/all of the options below.
+ *
+ */
+# ifndef SUPPRESS_GRAPHICS
+#  if (defined(SCREEN_BIOS) || defined(SCREEN_DJGPPFAST)) && !defined(PC9800)
+#   ifdef USE_TILES
+#define SCREEN_VGA     /* Include VGA    graphics routines in the build */
+#   endif
+#  endif
+# else
+# undef NO_TERMS
+# undef SCREEN_BIOS
+# undef SCREEN_DJGPPFAST
+# undef SCREEN_VGA
+# undef TERMLIB
+# define ANSI_DEFAULT
+# endif
+
+# define RANDOM                /* have Berkeley random(3) */
+
+# define MAIL          /* Allows for fake mail daemon to deliver mail */
+                       /* in the MSDOS version.  (For AMIGA MAIL see  */
+                       /* amiconf.h).  In the future this will be the */
+                       /* hook for mail reader implementation.        */
+
+/* The following is needed for prototypes of certain functions */
+
+#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__SC__)
+#include <process.h>   /* Provides prototypes of exit(), spawn()      */
+#endif
+
+#if defined(__BORLANDC__) && defined(STRNCMPI)
+#include <string.h>    /* Provides prototypes of strncmpi(), etc.     */
+#endif
+
+#if defined(__DJGPP__)
+#define _NAIVE_DOS_REGS
+#include <stdlib.h>
+#include <string.h>    /* Provides prototypes of strncmpi(), etc.     */
+# ifndef M
+#define M(c)           ((char) (0x80 | (c)))
+# endif
+#endif
+
+/*
+ * On the VMS and unix, this option controls whether a delay is done by
+ * the clock, or whether it is done by excess output.  On the PC, however,
+ * there is always a clock to use for the delay.  The TIMED_DELAY option
+ * on MSDOS (without the termcap routines) is used to determine whether to
+ * include the delay routines in the code (and thus, provides a compile time
+ * method to turn off napping for visual effect).  However, it is also used
+ * in the music code to wait between different notes.  So it is needed in that
+ * case as well.
+
+ * Whereas on the VMS and unix, flags.nap is a run-time option controlling
+ * whether there is a delay by clock or by excess output, on MSDOS it is
+ * simply a flag to turn on or off napping for visual effects at run-time.
+ */
+
+#define TIMED_DELAY    /* enable the `timed_delay' run-time option */
+
+# ifdef PCMUSIC
+#define TIMED_DELAY    /* need it anyway */
+# endif
+#define NOCWD_ASSUMPTIONS      /* Allow paths to be specified for HACKDIR,
+                                  LEVELDIR, SAVEDIR, BONESDIR, DATADIR,
+                                  SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR. */
+
+#endif /* MSDOS configuration stuff */
+
+#define PATHLEN                64      /* maximum pathlength */
+#define FILENAME       80      /* maximum filename length (conservative) */
+#ifndef MICRO_H
+#include "micro.h"             /* contains necessary externs for [os_name].c */
+#endif
+
+
+/* ===================================================
+ *  The remaining code shouldn't need modification.
+ */
+
+#ifndef SYSTEM_H
+#include "system.h"
+#endif
+
+#ifdef __DJGPP__
+#include <unistd.h> /* close(), etc. */
+/* lock() in io.h interferes with lock[] in decl.h */
+#define lock djlock
+#include <io.h>
+#undef lock
+#include <pc.h> /* kbhit() */
+#define PC_LOCKING
+#define HOLD_LOCKFILE_OPEN
+#define SELF_RECOVER           /* NetHack itself can recover games */
+#endif
+
+# ifdef MSDOS
+#  ifndef EXEPATH
+#define EXEPATH                /* HACKDIR is .exe location if not explicitly defined */
+#  endif
+# endif
+
+# if defined(_MSC_VER) && defined(MSDOS)
+#  if (_MSC_VER >= 700) && !defined(FUNCTION_LEVEL_LINKING)
+#   ifndef MOVERLAY
+#define MOVERLAY       /* Microsoft's MOVE overlay system (MSC >= 7.0) */
+#   endif
+#  endif
+#define PC_LOCKING
+# endif
+
+/* Borland Stuff */
+# if defined(__BORLANDC__)
+#  if defined(__OVERLAY__) && !defined(VROOMM)
+/* __OVERLAY__ is automatically defined by Borland C if overlay option is on */
+#define VROOMM         /* Borland's VROOMM overlay system */
+#  endif
+#  if !defined(STKSIZ)
+#define STKSIZ 5*1024  /* Use a default of 5K stack for Borland C      */
+                       /* This macro is used in any file that contains */
+                       /* a main() function.                           */
+#  endif
+#define PC_LOCKING
+# endif
+
+#ifdef PC_LOCKING
+#define HLOCK "NHPERM"
+#endif
+
+#ifndef index
+# define index strchr
+#endif
+#ifndef rindex
+# define rindex strrchr
+#endif
+
+#ifndef AMIGA
+#include <time.h>
+#endif
+
+#ifdef RANDOM
+/* Use the high quality random number routines. */
+# define Rand() random()
+#else
+# define Rand() rand()
+#endif
+
+#ifndef TOS
+# define FCMASK 0660   /* file creation mask */
+#endif
+
+#include <fcntl.h>
+
+#ifndef REDO
+# undef Getchar
+# define Getchar nhgetch
+#endif
+
+#ifdef MSDOS
+# define TEXTCOLOR /* */
+# define PORT_HELP "msdoshlp.txt" /* msdos port specific help file */
+#endif
+
+
+/* Sanity check, do not modify these blocks. */
+
+/* OVERLAY must be defined with MOVERLAY or VROOMM */
+#if (defined(MOVERLAY) || defined(VROOMM))
+# ifndef OVERLAY
+#  define OVERLAY
+# endif
+#endif
+
+#if defined(FUNCTION_LEVEL_LINKING)
+#define OVERLAY
+#define OVL0
+#define OVL1
+#define OVL2
+#define OVL3
+#define OVLB
+#endif
+
+#if defined(OVERLAY) && !defined(MOVERLAY) && !defined(VROOMM) && !defined(FUNCTION_LEVEL_LINKING)
+#define USE_TRAMPOLI
+#endif
+
+#if defined(MSDOS) && defined(NO_TERMS)
+# ifdef TERMLIB
+#  if defined(_MSC_VER) || defined(__SC__)
+#   pragma message("Warning -- TERMLIB defined with NO_TERMS in pcconf.h")
+#   pragma message("           Forcing undef of TERMLIB")
+#  endif
+#undef TERMLIB
+# endif
+# ifdef ANSI_DEFAULT
+#  if defined(_MSC_VER) || defined(__SC__)
+#   pragma message("Warning -- ANSI_DEFAULT defined with NO_TERMS in pcconf.h")
+#   pragma message("           Forcing undef of ANSI_DEFAULT")
+#  endif
+#undef ANSI_DEFAULT
+# endif
+/* only one screen package is allowed */
+# if defined(SCREEN_BIOS) && defined(SCREEN_DJGPPFAST)
+#  if defined(_MSC_VER) || defined(__SC__)
+#   pragma message("Warning -- More than one screen package defined in pcconf.h")
+#  endif
+#  if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__SC__)
+#   if defined(SCREEN_DJGPPFAST)
+#    if defined(_MSC_VER) || defined(__SC__)
+#    pragma message("           Forcing undef of SCREEN_DJGPPFAST")
+#    endif
+#undef SCREEN_DJGPPFAST   /* Can't use djgpp fast with other compilers anyway */
+#   endif
+#  else
+/* djgpp C compiler    */
+#   if defined(SCREEN_BIOS)
+#undef SCREEN_BIOS
+#   endif
+#  endif
+# endif
+# define ASCIIGRAPH
+# ifdef TEXTCOLOR
+#  define VIDEOSHADES
+# endif
+/* SCREEN_8514, SCREEN_VESA are only placeholders presently - sub VGA instead */
+# if defined(SCREEN_8514) || defined(SCREEN_VESA)
+#  undef SCREEN_8514
+#  undef SCREEN_VESA
+#  define SCREEN_VGA
+# endif
+/* Graphical tile sanity checks */
+# ifdef SCREEN_VGA
+#  define SIMULATE_CURSOR
+#  define POSITIONBAR
+/* Select appropriate tile file format, and map size */
+#  define PLANAR_FILE
+#  define SMALL_MAP
+# endif
+#endif                 /* End of sanity check block */
+
+#if defined(MSDOS) && defined(DLB)
+#define FILENAME_CMP  stricmp                /* case insensitive */
+#endif
+
+#ifdef MSC7_WARN       /* define with cl /DMSC7_WARN   */
+#pragma warning(disable:4131)
+#endif
+
+#ifdef TIMED_DELAY
+# ifdef __DJGPP__
+# define msleep(k) (void) usleep((k)*1000)
+# endif
+# ifdef __BORLANDC__
+# define msleep(k) delay(k)
+# endif
+# ifdef __SC__
+# define msleep(k) (void) usleep((long)((k)*1000))
+# endif
+#endif
+
+#endif /* PCCONF_H */
diff --git a/include/permonst.h b/include/permonst.h
new file mode 100644 (file)
index 0000000..a971f01
--- /dev/null
@@ -0,0 +1,81 @@
+/*     SCCS Id: @(#)permonst.h 3.4     1999/07/02      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef PERMONST_H
+#define PERMONST_H
+
+/*     This structure covers all attack forms.
+ *     aatyp is the gross attack type (eg. claw, bite, breath, ...)
+ *     adtyp is the damage type (eg. physical, fire, cold, spell, ...)
+ *     damn is the number of hit dice of damage from the attack.
+ *     damd is the number of sides on each die.
+ *
+ *     Some attacks can do no points of damage.  Additionally, some can
+ *     have special effects *and* do damage as well.  If damn and damd
+ *     are set, they may have a special meaning.  For example, if set
+ *     for a blinding attack, they determine the amount of time blinded.
+ */
+
+struct attack {
+       uchar           aatyp;
+       uchar           adtyp, damn, damd;
+};
+
+/*     Max # of attacks for any given monster.
+ */
+
+#define NATTK          6
+
+/*     Weight of a human body
+ */
+
+#define WT_HUMAN       1450
+
+#ifndef ALIGN_H
+#include "align.h"
+#endif
+#include "monattk.h"
+#include "monflag.h"
+
+struct permonst {
+       const char      *mname;                 /* full name */
+       char            mlet;                   /* symbol */
+       schar           mlevel,                 /* base monster level */
+                       mmove,                  /* move speed */
+                       ac,                     /* (base) armor class */
+                       mr;                     /* (base) magic resistance */
+       aligntyp        maligntyp;              /* basic monster alignment */
+       unsigned short  geno;                   /* creation/geno mask value */
+       struct  attack  mattk[NATTK];           /* attacks matrix */
+       unsigned short  cwt,                    /* weight of corpse */
+                       cnutrit;                /* its nutritional value */
+       short           pxlth;                  /* length of extension */
+       uchar           msound;                 /* noise it makes (6 bits) */
+       uchar           msize;                  /* physical size (3 bits) */
+       uchar           mresists;               /* resistances */
+       uchar           mconveys;               /* conveyed by eating */
+       unsigned long   mflags1,                /* boolean bitflags */
+                       mflags2;                /* more boolean bitflags */
+       unsigned short  mflags3;                /* yet more boolean bitflags */
+# ifdef TEXTCOLOR
+       uchar           mcolor;                 /* color to use */
+# endif
+};
+
+extern NEARDATA struct permonst
+               mons[];         /* the master list of monster types */
+
+#define VERY_SLOW 3
+#define SLOW_SPEED 9
+#define NORMAL_SPEED 12 /* movement rates */
+#define FAST_SPEED 15
+#define VERY_FAST 24
+
+#define NON_PM         PM_PLAYERMON            /* "not a monster" */
+#define LOW_PM         (NON_PM+1)              /* first monster in mons[] */
+#define SPECIAL_PM     PM_LONG_WORM_TAIL       /* [normal] < ~ < [special] */
+       /* mons[SPECIAL_PM] through mons[NUMMONS-1], inclusive, are
+          never generated randomly and cannot be polymorphed into */
+
+#endif /* PERMONST_H */
diff --git a/include/prop.h b/include/prop.h
new file mode 100644 (file)
index 0000000..f2ce274
--- /dev/null
@@ -0,0 +1,148 @@
+/*     SCCS Id: @(#)prop.h     3.4     1999/07/07      */
+/* Copyright (c) 1989 Mike Threepoint                            */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef PROP_H
+#define PROP_H
+
+/*** What the properties are ***/
+#define FIRE_RES                1
+#define COLD_RES                2
+#define SLEEP_RES               3
+#define DISINT_RES              4
+#define SHOCK_RES               5
+#define POISON_RES              6
+#define ACID_RES                7
+#define STONE_RES               8
+/* note: for the first eight properties, MR_xxx == (1 << (xxx_RES - 1)) */
+#define ADORNED                         9
+#define REGENERATION           10
+#define SEARCHING              11
+#define SEE_INVIS              12
+#define INVIS                  13
+#define TELEPORT               14
+#define TELEPORT_CONTROL       15
+#define POLYMORPH              16
+#define POLYMORPH_CONTROL      17
+#define LEVITATION             18
+#define STEALTH                        19
+#define AGGRAVATE_MONSTER      20
+#define CONFLICT               21
+#define PROTECTION             22
+#define PROT_FROM_SHAPE_CHANGERS 23
+#define WARNING                        24
+#define TELEPAT                        25
+#define FAST                   26
+#define STUNNED                        27
+#define CONFUSION              28
+#define SICK                   29
+#define BLINDED                        30
+#define SLEEPING               31
+#define WOUNDED_LEGS           32
+#define STONED                 33
+#define STRANGLED              34
+#define HALLUC                 35
+#define HALLUC_RES             36
+#define FUMBLING               37
+#define JUMPING                        38
+#define WWALKING               39
+#define HUNGER                 40
+#define GLIB                   41
+#define REFLECTING             42
+#define LIFESAVED              43
+#define ANTIMAGIC              44
+#define DISPLACED              45
+#define CLAIRVOYANT            46
+#define VOMITING               47
+#define ENERGY_REGENERATION    48
+#define MAGICAL_BREATHING      49
+#define HALF_SPDAM             50
+#define HALF_PHDAM             51
+#define SICK_RES               52
+#define DRAIN_RES              53
+#define WARN_UNDEAD            54
+#define INVULNERABLE           55
+#define FREE_ACTION            56
+#define SWIMMING               57
+#define SLIMED                 58
+#define FIXED_ABIL             59
+#define FLYING                 60
+#define UNCHANGING             61
+#define PASSES_WALLS           62
+#define SLOW_DIGESTION         63
+#define INFRAVISION            64
+#define WARN_OF_MON            65
+#define DETECT_MONSTERS                66
+#define LAST_PROP              (DETECT_MONSTERS)
+
+/*** Where the properties come from ***/
+/* Definitions were moved here from obj.h and you.h */
+struct prop {
+       /*** Properties conveyed by objects ***/
+       long extrinsic;
+       /* Armor */
+#      define W_ARM        0x00000001L /* Body armor */
+#      define W_ARMC       0x00000002L /* Cloak */
+#      define W_ARMH       0x00000004L /* Helmet/hat */
+#      define W_ARMS       0x00000008L /* Shield */
+#      define W_ARMG       0x00000010L /* Gloves/gauntlets */
+#      define W_ARMF       0x00000020L /* Footwear */
+#ifdef TOURIST
+#      define W_ARMU       0x00000040L /* Undershirt */
+#      define W_ARMOR       (W_ARM | W_ARMC | W_ARMH | W_ARMS | W_ARMG | W_ARMF | W_ARMU)
+#else
+#      define W_ARMOR       (W_ARM | W_ARMC | W_ARMH | W_ARMS | W_ARMG | W_ARMF)
+#endif
+       /* Weapons and artifacts */
+#      define W_WEP        0x00000100L /* Wielded weapon */
+#      define W_QUIVER     0x00000200L /* Quiver for (f)iring ammo */
+#      define W_SWAPWEP    0x00000400L /* Secondary weapon */
+#      define W_ART        0x00001000L /* Carrying artifact (not really worn) */
+#      define W_ARTI       0x00002000L /* Invoked artifact  (not really worn) */
+       /* Amulets, rings, tools, and other items */
+#      define W_AMUL       0x00010000L /* Amulet */
+#      define W_RINGL      0x00020000L /* Left ring */
+#      define W_RINGR      0x00040000L /* Right ring */
+#      define W_RING       (W_RINGL | W_RINGR)
+#      define W_TOOL       0x00080000L /* Eyewear */
+#ifdef STEED
+#      define W_SADDLE     0x00100000L /* KMH -- For riding monsters */
+#endif
+#      define W_BALL       0x00200000L /* Punishment ball */
+#      define W_CHAIN      0x00400000L /* Punishment chain */
+
+       /*** Property is blocked by an object ***/
+       long blocked;                                   /* Same assignments as extrinsic */
+
+       /*** Timeouts, permanent properties, and other flags ***/
+       long intrinsic;
+       /* Timed properties */
+#      define TIMEOUT      0x00ffffffL /* Up to 16 million turns */
+       /* Permanent properties */
+#      define FROMEXPER    0x01000000L /* Gain/lose with experience, for role */
+#      define FROMRACE     0x02000000L /* Gain/lose with experience, for race */
+#      define FROMOUTSIDE  0x04000000L /* By corpses, prayer, thrones, etc. */
+#      define INTRINSIC    (FROMOUTSIDE|FROMRACE|FROMEXPER)
+       /* Control flags */
+#      define I_SPECIAL    0x10000000L /* Property is controllable */
+};
+
+/*** Definitions for backwards compatibility ***/
+#define LEFT_RING      W_RINGL
+#define RIGHT_RING     W_RINGR
+#define LEFT_SIDE      LEFT_RING
+#define RIGHT_SIDE     RIGHT_RING
+#define BOTH_SIDES     (LEFT_SIDE | RIGHT_SIDE)
+#define WORN_ARMOR     W_ARM
+#define WORN_CLOAK     W_ARMC
+#define WORN_HELMET    W_ARMH
+#define WORN_SHIELD    W_ARMS
+#define WORN_GLOVES    W_ARMG
+#define WORN_BOOTS     W_ARMF
+#define WORN_AMUL      W_AMUL
+#define WORN_BLINDF    W_TOOL
+#ifdef TOURIST
+#define WORN_SHIRT     W_ARMU
+#endif
+
+#endif /* PROP_H */
diff --git a/include/qt_clust.h b/include/qt_clust.h
new file mode 100644 (file)
index 0000000..96fec93
--- /dev/null
@@ -0,0 +1,29 @@
+/*     SCCS Id: @(#)qt_clust.h 3.4     1999/11/19      */
+/* Copyright (c) Warwick Allison, 1999. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef clusterizer_H
+#define clusterizer_H
+
+#include <qrect.h>
+
+class Clusterizer {
+public:
+       Clusterizer(int maxclusters);
+       ~Clusterizer();
+
+       void add(int x, int y); // 1x1 rectangle (point)
+       void add(int x, int y, int w, int h);
+       void add(const QRect& rect);
+
+       void clear();
+       int clusters() { return count; }
+       const QRect& operator[](int i);
+
+private:
+       QRect* cluster;
+       int count;
+       const int max;
+};
+
+#endif
diff --git a/include/qt_kde0.h b/include/qt_kde0.h
new file mode 100644 (file)
index 0000000..4d64a42
--- /dev/null
@@ -0,0 +1,10 @@
+/*     SCCS Id: @(#)qt_kde0.h  3.4     1999/11/19      */
+/* Copyright (c) Warwick Allison, 1999. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef QT_DUMMYKDE
+#define QT_DUMMYKDE
+class KTopLevelWidget : public QMainWindow {
+        Q_OBJECT
+};
+#endif
diff --git a/include/qt_win.h b/include/qt_win.h
new file mode 100644 (file)
index 0000000..2dedce2
--- /dev/null
@@ -0,0 +1,845 @@
+//     SCCS Id: @(#)qt_win.h   3.4     1999/11/19
+// Copyright (c) Warwick Allison, 1999.
+// NetHack may be freely redistributed.  See license for details.
+//
+// Qt Binding for NetHack 3.4
+//
+// Unfortunately, this doesn't use Qt as well as I would like,
+// primarily because NetHack is fundamentally a getkey-type
+// program rather than being event driven (hence the ugly key
+// and click buffer rather), but also because this is my first
+// major application of Qt.
+//
+
+#ifndef qt_win_h
+#define qt_win_h
+
+#define QT_CLEAN_NAMESPACE
+
+#include <qdialog.h>
+#include <qpushbutton.h>
+#include <qbuttongroup.h>
+#include <qlabel.h>
+#include <qlineedit.h> 
+#if defined(QWS)
+#include <qpe/qpeapplication.h> 
+#else
+#include <qapplication.h> 
+#endif
+#include <qspinbox.h>
+#include <qcheckbox.h>
+#include <qfile.h> 
+#include <qlistbox.h> 
+#include <qlistview.h> 
+#include <qmessagebox.h>
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qarray.h>
+#include <qcombobox.h>
+#include <qscrollview.h>
+#if QT_VERSION >= 300
+#include <qttableview.h>
+// Should stop using QTableView
+#define QTableView QtTableView
+#else
+#include <qtableview.h>
+#endif
+#include <qmainwindow.h>
+#include <qwidgetstack.h>
+
+#ifdef KDE
+#include <kapp.h>
+#include <ktopwidget.h>
+#endif 
+
+#include "qt_clust.h"
+
+class QVBox;
+class QMenuBar;
+class QRadioButton;
+class NhPSListView;
+
+//////////////////////////////////////////////////////////////
+//
+//  The beautiful, abstracted and well-modelled classes...
+//
+//////////////////////////////////////////////////////////////
+
+class NetHackQtGlyphs;
+
+class NetHackQtLineEdit : public QLineEdit {
+public:
+       NetHackQtLineEdit();
+       NetHackQtLineEdit(QWidget* parent, const char* name);
+
+       void fakeEvent(int key, int ascii, int state);
+};
+
+class NetHackQtSettings : public QDialog {
+       Q_OBJECT
+public:
+       // Size of window - used to decide default sizes
+       NetHackQtSettings(int width, int height);
+
+       NetHackQtGlyphs& glyphs();
+       const QFont& normalFont();
+       const QFont& normalFixedFont();
+       const QFont& largeFont();
+
+       bool ynInMessages();
+
+signals:
+       void fontChanged();
+       void tilesChanged();
+
+public slots:
+       void toggleGlyphSize();
+       void setGlyphSize(bool);
+
+private:
+       QSpinBox tilewidth;
+       QSpinBox tileheight;
+       QLabel widthlbl;
+       QLabel heightlbl;
+       QCheckBox whichsize;
+       QSize othersize;
+
+       QComboBox fontsize;
+
+       QFont normal, normalfixed, large;
+
+       NetHackQtGlyphs* theglyphs;
+
+private slots:
+       void resizeTiles();
+};
+
+class NetHackQtKeyBuffer {
+public:
+       NetHackQtKeyBuffer();
+
+       bool Empty() const;
+       bool Full() const;
+
+       void Put(int k, int ascii, int state);
+       void Put(char a);
+       void Put(const char* str);
+       int GetKey();
+       int GetAscii();
+       int GetState();
+
+       int TopKey() const;
+       int TopAscii() const;
+       int TopState() const;
+
+private:
+       enum { maxkey=64 };
+       int key[maxkey];
+       int ascii[maxkey];
+       int state[maxkey];
+       int in,out;
+};
+
+class NetHackQtClickBuffer {
+public:
+       NetHackQtClickBuffer();
+
+       bool Empty() const;
+       bool Full() const;
+
+       void Put(int x, int y, int mod);
+
+       int NextX() const;
+       int NextY() const;
+       int NextMod() const;
+
+       void Get();
+
+private:
+       enum { maxclick=64 };
+       struct ClickRec {
+               int x,y,mod;
+       } click[maxclick];
+       int in,out;
+};
+
+
+class NetHackQtSavedGameSelector : public QDialog {
+public:
+       NetHackQtSavedGameSelector(const char** saved);
+
+       int choose();
+};
+
+class NetHackQtPlayerSelector : private QDialog {
+       Q_OBJECT
+public:
+       enum { R_None=-1, R_Quit=-2, R_Rand=-3 };
+
+       NetHackQtPlayerSelector(NetHackQtKeyBuffer&);
+
+protected:
+       virtual void done(int);
+
+public slots:
+       void Quit();
+       void Random();
+
+       void selectName(const QString& n);
+       void selectRole();
+       void selectRace();
+       void setupOthers();
+       void selectGender(int);
+       void selectAlignment(int);
+
+public:
+       bool Choose();
+
+private:
+       NetHackQtKeyBuffer& keysource;
+       NhPSListView* role;
+       NhPSListView* race;
+       QRadioButton **gender;
+       QRadioButton **alignment;
+       bool fully_specified_role;
+};
+
+class NetHackQtStringRequestor : QDialog {
+private:
+       QLabel prompt;
+       NetHackQtLineEdit input;
+       QPushButton* okay;
+       QPushButton* cancel;
+       NetHackQtKeyBuffer& keysource;
+
+       virtual void done(int);
+
+public:
+       NetHackQtStringRequestor(NetHackQtKeyBuffer&, const char* p,const char* cancelstr="Cancel");
+       void SetDefault(const char*);
+       bool Get(char* buffer, int maxchar=80);
+       virtual void resizeEvent(QResizeEvent*);
+};
+
+class NetHackQtExtCmdRequestor : public QDialog {
+    Q_OBJECT
+
+    NetHackQtKeyBuffer& keysource;
+
+public:
+    NetHackQtExtCmdRequestor(NetHackQtKeyBuffer& ks);
+    int get();
+
+private slots:
+    void cancel();
+    void done(int i);
+};
+
+
+class NetHackQtWindow {
+public:
+       NetHackQtWindow();
+       virtual ~NetHackQtWindow();
+
+       virtual QWidget* Widget() =0;
+
+       virtual void Clear();
+       virtual void Display(bool block);
+       virtual bool Destroy();
+       virtual void CursorTo(int x,int y);
+       virtual void PutStr(int attr, const char* text);
+       virtual void StartMenu();
+       virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr,
+                       const char* str, bool presel);
+       virtual void EndMenu(const char* prompt);
+       virtual int SelectMenu(int how, MENU_ITEM_P **menu_list);
+       virtual void ClipAround(int x,int y);
+       virtual void PrintGlyph(int x,int y,int glyph);
+       virtual void UseRIP(int how);
+
+       int nhid;
+};
+
+class NetHackQtGlyphs {
+public:
+       NetHackQtGlyphs();
+
+       int width() const { return size.width(); }
+       int height() const { return size.height(); }
+       void toggleSize();
+       void setSize(int w, int h);
+
+       void drawGlyph(QPainter&, int glyph, int pixelx, int pixely);
+       void drawCell(QPainter&, int glyph, int cellx, int celly);
+
+private:
+       QImage img;
+       QPixmap pm,pm1, pm2;
+       QSize size;
+       int tiles_per_row;
+};
+
+class BlackScrollView : public QScrollView {
+public:
+    BlackScrollView()
+    {
+       viewport()->setBackgroundColor(black);
+    }
+};
+
+class NetHackQtMapWindow : public QWidget, public NetHackQtWindow {
+       Q_OBJECT
+private:
+       NetHackQtClickBuffer& clicksink;
+       unsigned short glyph[ROWNO][COLNO];
+       unsigned short& Glyph(int x, int y) { return glyph[y][x]; }
+       QPoint cursor;
+       BlackScrollView viewport;
+       QPixmap pet_annotation;
+       Clusterizer change;
+       QFont *rogue_font;
+       QString messages;
+       QRect messages_rect;
+
+       void Changed(int x,int y);
+
+signals:
+       void resized();
+
+private slots:
+       void updateTiles();
+       void moveMessages(int x, int y);
+
+protected:
+       virtual void paintEvent(QPaintEvent*);
+       virtual void mousePressEvent(QMouseEvent*);
+
+public:
+       NetHackQtMapWindow(NetHackQtClickBuffer& click_sink);
+       ~NetHackQtMapWindow();
+
+       virtual QWidget* Widget();
+       virtual bool Destroy();
+
+       virtual void Clear();
+       virtual void Display(bool block);
+       virtual void CursorTo(int x,int y);
+       virtual void PutStr(int attr, const char* text);
+       virtual void ClipAround(int x,int y);
+       virtual void PrintGlyph(int x,int y,int glyph);
+
+       void Scroll(int dx, int dy);
+
+       // For messages
+       void displayMessages(bool block);
+       void putMessage(int attr, const char* text);
+       void clearMessages();
+
+       void clickCursor();
+};
+
+class NetHackQtScrollText;
+class NetHackQtMessageWindow : QObject, public NetHackQtWindow {
+       Q_OBJECT
+public:
+       NetHackQtMessageWindow();
+       ~NetHackQtMessageWindow();
+
+       virtual QWidget* Widget();
+       virtual void Clear();
+       virtual void Display(bool block);
+       virtual void PutStr(int attr, const char* text);
+
+       void Scroll(int dx, int dy);
+
+       void setMap(NetHackQtMapWindow*);
+
+private:
+       NetHackQtScrollText* list;
+       bool changed;
+       NetHackQtMapWindow* map;
+
+private slots:
+       void updateFont();
+};
+
+class NetHackQtLabelledIcon : public QWidget {
+public:
+       NetHackQtLabelledIcon(QWidget* parent, const char* label);
+       NetHackQtLabelledIcon(QWidget* parent, const char* label, const QPixmap& icon);
+
+       enum { NoNum=-99999 };
+       void setLabel(const char*, bool lower=TRUE); // a string
+       void setLabel(const char*, long, const char* tail=""); // a number
+       void setLabel(const char*, long show_value, long comparative_value, const char* tail="");
+       void setIcon(const QPixmap&);
+       virtual void setFont(const QFont&);
+
+       void highlightWhenChanging();
+       void lowIsGood();
+       void dissipateHighlight();
+
+       virtual void show();
+
+protected:
+       void resizeEvent(QResizeEvent*);
+
+private:
+       void initHighlight();
+       void setAlignments();
+       void highlight(const QPalette& highlight);
+       void unhighlight();
+
+       bool low_is_good;
+       int prev_value;
+       int turn_count;         /* last time the value changed */
+       QPalette hl_good;
+       QPalette hl_bad;
+
+       QLabel* label;
+       QLabel* icon;
+};
+
+class NetHackQtStatusWindow : QWidget, public NetHackQtWindow {
+       Q_OBJECT
+public:
+       NetHackQtStatusWindow();
+
+       virtual QWidget* Widget();
+
+       virtual void Clear();
+       virtual void Display(bool block);
+       virtual void CursorTo(int x,int y);
+       virtual void PutStr(int attr, const char* text);
+
+       void fadeHighlighting();
+
+protected:
+       void resizeEvent(QResizeEvent*);
+
+private slots:
+       void doUpdate();
+
+private:
+       enum { hilight_time=1 };
+
+       QPixmap p_str;
+       QPixmap p_dex;
+       QPixmap p_con;
+       QPixmap p_int;
+       QPixmap p_wis;
+       QPixmap p_cha;
+
+       QPixmap p_chaotic;
+       QPixmap p_neutral;
+       QPixmap p_lawful;
+
+       QPixmap p_satiated;
+       QPixmap p_hungry;
+
+       QPixmap p_confused;
+       QPixmap p_sick_fp;
+       QPixmap p_sick_il;
+       QPixmap p_blind;
+       QPixmap p_stunned;
+       QPixmap p_hallu;
+
+       QPixmap p_encumber[5];
+
+       NetHackQtLabelledIcon name;
+       NetHackQtLabelledIcon dlevel;
+
+       NetHackQtLabelledIcon str;
+       NetHackQtLabelledIcon dex;
+       NetHackQtLabelledIcon con;
+       NetHackQtLabelledIcon intel;
+       NetHackQtLabelledIcon wis;
+       NetHackQtLabelledIcon cha;
+
+       NetHackQtLabelledIcon gold;
+       NetHackQtLabelledIcon hp;
+       NetHackQtLabelledIcon power;
+       NetHackQtLabelledIcon ac;
+       NetHackQtLabelledIcon level;
+       NetHackQtLabelledIcon exp;
+       NetHackQtLabelledIcon align;
+
+       NetHackQtLabelledIcon time;
+       NetHackQtLabelledIcon score;
+
+       NetHackQtLabelledIcon hunger;
+       NetHackQtLabelledIcon confused;
+       NetHackQtLabelledIcon sick_fp;
+       NetHackQtLabelledIcon sick_il;
+       NetHackQtLabelledIcon blind;
+       NetHackQtLabelledIcon stunned;
+       NetHackQtLabelledIcon hallu;
+       NetHackQtLabelledIcon encumber;
+
+       QFrame hline1;
+       QFrame hline2;
+       QFrame hline3;
+
+       int cursy;
+
+       bool first_set;
+
+       void nullOut();
+       void updateStats();
+       void checkTurnEvents();
+};
+
+class NetHackQtMenuDialog : public QDialog {
+       Q_OBJECT
+public:
+       NetHackQtMenuDialog();
+
+       void Accept();
+       void Reject();
+       void SetResult(int);
+
+       virtual void done(int);
+
+protected:
+       void resizeEvent(QResizeEvent*);
+
+signals:
+       void Resized();
+};
+
+
+class NetHackQtMenuWindow : public QTableView, public NetHackQtWindow {
+       Q_OBJECT
+public:
+       NetHackQtMenuWindow(NetHackQtKeyBuffer&);
+       ~NetHackQtMenuWindow();
+
+       virtual QWidget* Widget();
+
+       virtual void StartMenu();
+       virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr,
+                       const char* str, bool presel);
+       virtual void EndMenu(const char* prompt);
+       virtual int SelectMenu(int how, MENU_ITEM_P **menu_list);
+
+public slots:
+       void All();
+       void ChooseNone();
+       void Invert();
+       void Search();
+
+       void Layout();
+       void ToggleSelect(int);
+
+protected:
+       virtual void keyPressEvent(QKeyEvent*);
+       //virtual void mouseDoubleClickEvent(QMouseEvent*);
+       virtual void mousePressEvent(QMouseEvent*);
+       virtual void mouseReleaseEvent(QMouseEvent*);
+       virtual void mouseMoveEvent(QMouseEvent*);
+       virtual void focusOutEvent(QFocusEvent*);
+       virtual void focusInEvent(QFocusEvent*);
+
+       virtual void paintCell(QPainter*, int, int);
+       virtual int cellWidth(int col);
+
+private:
+       struct MenuItem {
+               MenuItem();
+               ~MenuItem();
+
+               int glyph;
+               ANY_P identifier;
+               int attr;
+               const char* str;
+               int count;
+               char ch;
+               bool selected;
+
+               bool Selectable() const { return identifier.a_void!=0; }
+       };
+
+       QArray<MenuItem> item;
+
+       int itemcount;
+       int str_width;
+       bool str_fixed;
+       int next_accel;
+
+       NetHackQtKeyBuffer& keysource;
+
+       NetHackQtMenuDialog* dialog;
+
+       QPushButton* ok;
+       QPushButton* cancel;
+       QPushButton* all;
+       QPushButton* none;
+       QPushButton* invert;
+       QPushButton* search;
+       QLabel prompt;
+
+       int how;
+
+       bool has_glyphs;
+
+       int pressed;
+       bool was_sel;
+};
+
+class NetHackQtTextListBox;
+
+class NetHackQtRIP : public QWidget {
+private:
+       static QPixmap* pixmap;
+       char** line;
+       int riplines;
+
+public:
+       NetHackQtRIP(QWidget* parent);
+
+       void setLines(char** l, int n);
+
+protected:
+       virtual void paintEvent(QPaintEvent* event);
+       QSize sizeHint() const;
+};
+
+
+class NetHackQtTextWindow : public QDialog, public NetHackQtWindow {
+       Q_OBJECT
+public:
+       NetHackQtTextWindow(NetHackQtKeyBuffer&);
+       ~NetHackQtTextWindow();
+
+       virtual QWidget* Widget();
+
+       virtual void Clear();
+       virtual bool Destroy();
+       virtual void Display(bool block);
+       virtual void PutStr(int attr, const char* text);
+       virtual void UseRIP(int how);
+
+public slots:
+       void Search();
+
+protected:
+       virtual void done(int);
+       virtual void keyPressEvent(QKeyEvent*);
+
+private slots:
+       void doUpdate();
+
+private:
+       NetHackQtKeyBuffer& keysource;
+
+       bool use_rip;
+       bool str_fixed;
+
+       QPushButton ok;
+       QPushButton search;
+       NetHackQtTextListBox* lines;
+
+       NetHackQtRIP rip;
+};
+
+class NetHackQtMenuOrTextWindow : public NetHackQtWindow {
+private:
+       NetHackQtWindow* actual;
+       NetHackQtKeyBuffer& keysource;
+
+public:
+       NetHackQtMenuOrTextWindow(NetHackQtKeyBuffer&);
+
+       virtual QWidget* Widget();
+
+       // Text
+       virtual void Clear();
+       virtual bool Destroy();
+       virtual void Display(bool block);
+       virtual void PutStr(int attr, const char* text);
+
+       // Menu
+       virtual void StartMenu();
+       virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr,
+                       const char* str, bool presel);
+       virtual void EndMenu(const char* prompt);
+       virtual int SelectMenu(int how, MENU_ITEM_P **menu_list);
+
+};
+
+class NetHackQtDelay : QObject {
+private:
+       int msec;
+
+public:
+       NetHackQtDelay(int ms);
+       void wait();
+       virtual void timerEvent(QTimerEvent* timer);
+};
+
+
+class NetHackQtInvUsageWindow : public QWidget {
+public:
+       NetHackQtInvUsageWindow(QWidget* parent);
+       virtual void paintEvent(QPaintEvent*);
+private:
+       void drawWorn(QPainter& painter, obj*, int x, int y, bool canbe=TRUE);
+};
+
+// This class is the main widget for NetHack
+//
+// It is a collection of Message, Map, and Status windows.  In the current
+// version of nethack there is only one of each, and this class makes this
+// assumption, not showing itself until all are inserted.
+//
+// This class simply knows how to layout such children sensibly.
+//
+// Since it is only responsible for layout, the class does not
+// note the actual class of the windows.
+//
+#ifndef KDE
+#include "qt_kde0.h"
+#endif
+
+class NetHackQtMainWindow : public KTopLevelWidget {
+       Q_OBJECT
+public:
+       NetHackQtMainWindow(NetHackQtKeyBuffer&);
+
+       void AddMessageWindow(NetHackQtMessageWindow* window);
+       void AddMapWindow(NetHackQtMapWindow* window);
+       void AddStatusWindow(NetHackQtStatusWindow* window);
+       void RemoveWindow(NetHackQtWindow* window);
+       void updateInventory();
+
+       void fadeHighlighting();
+
+public slots:
+       void doMenuItem(int);
+       void doKeys(const QString&);
+
+protected:
+       virtual void resizeEvent(QResizeEvent*);
+       virtual void keyPressEvent(QKeyEvent*);
+       virtual void keyReleaseEvent(QKeyEvent* event);
+       virtual void closeEvent(QCloseEvent*);
+
+private slots:
+       void layout();
+       void raiseMap();
+       void zoomMap();
+       void raiseMessages();
+       void raiseStatus();
+
+private:
+       void ShowIfReady();
+
+#ifdef KDE
+       KMenuBar* menubar;
+#else
+       QMenuBar* menubar;
+#endif
+       NetHackQtMessageWindow* message;
+       NetHackQtMapWindow* map;
+       NetHackQtStatusWindow* status;
+       NetHackQtInvUsageWindow* invusage;
+
+       NetHackQtKeyBuffer& keysink;
+       QWidgetStack* stack;
+       int dirkey;
+
+       const char* *macro;
+};
+
+class NetHackQtYnDialog : QDialog {
+       Q_OBJECT
+private:
+       const char* question;
+       const char* choices;
+       char def;
+       NetHackQtKeyBuffer& keysource;
+
+protected:
+       virtual void keyPressEvent(QKeyEvent*);
+       virtual void done(int);
+
+private slots:
+       void doneItem(int);
+
+public:
+       NetHackQtYnDialog(NetHackQtKeyBuffer& keysource,const char*,const char*,char);
+
+       char Exec();
+};
+
+#ifdef KDE
+#define NetHackQtBindBase KApplication
+#elif defined(QWS)
+#define NetHackQtBindBase QPEApplication
+#else
+#define NetHackQtBindBase QApplication
+#endif
+
+class NetHackQtBind : NetHackQtBindBase {
+private:
+       // Single-instance preservation...
+       NetHackQtBind(int& argc, char** argv);
+
+       static NetHackQtBind* instance;
+
+       static NetHackQtKeyBuffer keybuffer;
+       static NetHackQtClickBuffer clickbuffer;
+
+       static QWidget* splash;
+       static NetHackQtMainWindow* main;
+
+public:
+       static void qt_init_nhwindows(int* argc, char** argv);
+       static void qt_player_selection();
+       static void qt_askname();
+       static void qt_get_nh_event();
+       static void qt_exit_nhwindows(const char *);
+       static void qt_suspend_nhwindows(const char *);
+       static void qt_resume_nhwindows();
+       static winid qt_create_nhwindow(int type);
+       static void qt_clear_nhwindow(winid wid);
+       static void qt_display_nhwindow(winid wid, BOOLEAN_P block);
+       static void qt_destroy_nhwindow(winid wid);
+       static void qt_curs(winid wid, int x, int y);
+       static void qt_putstr(winid wid, int attr, const char *text);
+       static void qt_display_file(const char *filename, BOOLEAN_P must_exist);
+       static void qt_start_menu(winid wid);
+       static void qt_add_menu(winid wid, int glyph,
+               const ANY_P * identifier, CHAR_P ch, CHAR_P gch, int attr,
+               const char *str, BOOLEAN_P presel);
+       static void qt_end_menu(winid wid, const char *prompt);
+       static int qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list);
+       static void qt_update_inventory();
+       static void qt_mark_synch();
+       static void qt_wait_synch();
+
+       static void qt_cliparound(int x, int y);
+       static void qt_cliparound_window(winid wid, int x, int y);
+       static void qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph);
+       static void qt_raw_print(const char *str);
+       static void qt_raw_print_bold(const char *str);
+       static int qt_nhgetch();
+       static int qt_nh_poskey(int *x, int *y, int *mod);
+       static void qt_nhbell();
+       static int qt_doprev_message();
+       static char qt_yn_function(const char *question, const char *choices, CHAR_P def);
+       static void qt_getlin(const char *prompt, char *line);
+       static int qt_get_ext_cmd();
+       static void qt_number_pad(int);
+       static void qt_delay_output();
+       static void qt_start_screen();
+       static void qt_end_screen();
+
+       static void qt_outrip(winid wid, int how);
+       static int qt_kbhit();
+
+private:
+       virtual bool notify(QObject *receiver, QEvent *event);
+};
+
+#endif
diff --git a/include/qt_xpms.h b/include/qt_xpms.h
new file mode 100644 (file)
index 0000000..fcb4b8d
--- /dev/null
@@ -0,0 +1,1406 @@
+/* XPM */
+static const char *blind_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 5 1",
+/* colors */
+"  c #000000",
+". c None",
+"X c #909090",
+"o c #606060",
+"O c #303030",
+/* pixels */
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"....ooooooooooooooooooooooooooooooooX...",
+"....                                o...",
+"....                                o...",
+"....                                o...",
+"....                                o...",
+"......o            ..o            ......",
+"......X           O..X           O......",
+".......           o...           o......",
+".......o          ....o          .......",
+"........O        X.....O        X.......",
+".........O      X.......O      X........",
+"..........o   OX.........o   OX.........",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................"
+};
+/* XPM */
+static const char *cha_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 14 1",
+/* colors */
+"  c #F85848",
+". c #949E9E",
+"X c #F8B090",
+"o c #E00028",
+"O c #D4D4D4",
+"+ c None",
+"@ c #B0B0B0",
+"# c #F82C24",
+"$ c #F89E6C",
+"% c #FF0000",
+"& c #909090",
+"* c #FFFFFF",
+"= c #CEAA90",
+"- c #DADAB6",
+/* pixels */
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"+++++++++++++++=#%#=+=#%% ++++++++++++++",
+"++++++++++++++ %O%%%#%$$%o%=++++++++++++",
+"+++++++++++++# +#%%o%%o%%%%% +++++++++++",
+"+++++++++++ %%%%%%%%%%%%%%%%o#=+++++++++",
+"+++++++++ o%%%%%%%%%%%%%%%%%%%%# +++++++",
+"++++++ #%%%%%%o%%%o%%o%%o%o%%%%%o%o  +++",
+"++=#%%o%%%#= =*+**O*+**O*+- = =%%%%#@+++",
+"++++ %=++*+*+**O****O****O*O*O*OO%=+++++",
+"+++++.%=OO+*O*OO****+****+*O*+O&%=@+++++",
+"++++++=%=*OO+**O**O*O**O*O*OO+$%=+++++++",
+"+++++++#% +*OOOO****+****@O+*#%=++++++++",
+"++++++++#%#*+**+O+OO+O+OOO*O#o#+++++++++",
+"+++++++++o% O**+****O****O*#%%=+++++++++",
+"+++++++++ %%#O*O****+****+ %o#++++++++++",
+"++++++++++o%% XO*O**O*O**#%%%+++++++++++",
+"++++++++++ %%%o%$-**+**$%%%%=+++++++++++",
+"+++++++++++o%%$X$%%%%%%#= o#++++++++++++",
+"++++++++++@ %%%o#O$$+$$$%%%=++++++++++++",
+"++++++++++++#o%%%%%%%%o%%%=@++++++++++++",
+"+++++++++++++ %%%%%%%%%%o=++++++++++++++",
+"+++++++++++++++= &  &  @++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++"
+};
+/* XPM */
+static const char *chaotic_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 9 1",
+/* colors */
+"  c #000000",
+". c #5C7A7A",
+"X c None",
+"o c #B0B0B0",
+"O c #909090",
+"+ c #788C8C",
+"@ c #606060",
+"# c #FFFFFF",
+"$ c #303030",
+/* pixels */
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXXX@$     @XXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXX$$+#X$    $XXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXX@$#o        @XXXXXXXXX",
+"XXXXXXXXXXXXXXXXXX$XX          OXXXXXXXX",
+"XXXXXXXXXXXXXXXXX@ #   $@$     $XXXXXXXX",
+"XXXXXXXXXXXXXXXXX@.+  $XXXO     @XXXXXXX",
+"XXXXXXXXXXXXXXXXX O@  XXXXX@    @XXXXXXX",
+"XXXXXXXXXXXXXXXXX @O $XXXXX@$   @XXXXXXX",
+"XXXXXXXXXXXXXXXXX O+ @XXXXO++   @XXXXXXX",
+"XXXXXXXXXXXXXXXXX @+ $@OXO$#$   XXXXXXXX",
+"XXXXXXXXXXXXXXXXX O@  $ @$Xo   $XXXXXXXX",
+"XXXXXXXXXXXXXXXXX +O  $X##+   $XXXXXXXXX",
+"XXXXXXXXXXXXXXXXX +@         $XXXXXXXXXX",
+"XXXXXXXXXXXXXXXXX oO        $XXXXXXXXXXX",
+"XXXXXXXXO@@@@@   +#        $XXXXXXXXXXXX",
+"XXXXXXO +o########$          $@XXXXXXXXX",
+"XXXXXX                     +#+.$XXXXXXXX",
+"XXXXXX                       @O @XXXXXXX",
+"XXXXXX$        $@    $@@$       @XXXXXXX",
+"XXXXXXX@@@@XXXXXX +  @XXXX@$    OXXXXXXX",
+"XXXXXXXXXXXXXXXX@ #  @XXXXXXX@@OXXXXXXXX",
+"XXXXXXXXXXXXXXXX@.+  @XXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXX$O@  XXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXX @O  XXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXX #$ @XXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXX #  @XXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXX #  @XXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX@ #  @XXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX@ #  OXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX@.X  XXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX ++  XXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX @+  XXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX O@ @XXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX +O @XXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX    @XXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX$   OXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXX@@OXXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+};
+/* XPM */
+static const char *cns_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 19 1",
+/* colors */
+"  c #000000",
+". c #F85848",
+"X c #949E9E",
+"o c #F8B090",
+"O c #E00028",
+"+ c #7C3400",
+"@ c None",
+"# c #B0B0B0",
+"$ c #F82C24",
+"% c #F89E6C",
+"& c #FF0000",
+"* c #B64700",
+"= c #909090",
+"- c #788C8C",
+"; c #606060",
+": c #C80050",
+"> c #CEAA90",
+", c #303030",
+"< c #FFB691",
+/* pixels */
+"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@.oo.o$ ;@@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@>.o.%%O,@@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@$oo.o. ,@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@.oo$oo+ =@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@..o&oo$ ,@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@#.o.oo.  =@.$%@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@.o..oo& O.%ooo@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@.o.&%o.$oo%O++;@@@@@@@@@@@@",
+"@@@@@@@@@@@@@.o.+$%$o<O+   ,@@@@@@@@@@@@",
+"@@@@@@@@@@@@@.oo+ $o%O   ;@>.@@@@@@@@@@@",
+"@@@@@@@@@@@@@.oo++o%$$ ,@@$.oo@@@@@@@@@@",
+"@@@@@@@@@@@@>.oo+Oo$o%.@@$oo..-@@@@@@@@@",
+"@@@@@@@@@@@@..o%;.o&%.$..o%O ++>@@@@@@@@",
+"@@@@@@@@@@@@>.$O:%o.O::::O* $oooo@@@@@@@",
+"@@@@@@@@@@@@::::::$$:OO&OO::oo%.;=@@@@@@",
+"@@@@@@@@@@@.::::::::O&&&&&O::++  ,@@@@@@",
+"@@@@@@@@@@>:::O&&OO&&&&&&&&::     ;@@@@@",
+"@@@@@@@@@@=::O&&&&&O:O&&&&&O:  ,=@@@@@@@",
+"@@@@@@@@@@:::&&&&&&&&:&&&&&O:  ;@@@@@@@@",
+"@@@@@@@@@@::O&&&&&&&&:&O&&&O:, ;@@@@@@@@",
+"@@@@@@@@@@::O&&&&O&O&OO&O&&O:+ ;@@@@@@@@",
+"@@@@@@@@@@::&&&O&&&&&O:&&&&O:,  @@@@@@@@",
+"@@@@@@@@@@::O&&&&&O&&&:O&O&::+  @@@@@@@@",
+"@@@@@@@@@@::O&&O&&&&O&OO&&&::   @@@@@@@@",
+"@@@@@@@@@@=::O&&&&O&&&O:&&&::   @@@@@@@@",
+"@@@@@@@@@@.:::O&&O&&&&&:&OO::   @@@@@@@@",
+"@@@@@@@@@@@:::::&&&&O&O:&&O:,   @@@@@@@@",
+"@@@@@@@@@@.>:::::O&&&&&:&&::+  ;@@@@@@@@",
+"@@@@@@@@@@>.<::::O&&O&O:&&::   @@@@@@@@@",
+"@@@@@@@@@@@.o%,:::O&&&O:&O:,   @@@@@@@@@",
+"@@@@@@@@@@@$o.  :::OO&OO&::,  ;@@@@@@@@@",
+"@@@@@@@@@@@&o%+ ,::O&OO&O::   =@@@@@@@@@",
+"@@@@@@@@@@@.oo+   :::OO:::   ,@@@@@@@@@@",
+"@@@@@@@@@@@..oO    +:::::    =@@@@@@@@@@",
+"@@@@@@@@@@@@.<.+      ,+,   ,@@@@@@@@@@@",
+"@@@@@@@@@@@@Oo<+  @X,      ,@@@@@@@@@@@@",
+"@@@@@@@@@@@@.%o$  @@@@@;, ;@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@.o., =@@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+};
+/* XPM */
+static const char *confused_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #303030",
+"= c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOO.=.+OO=.+O.OO+O+OO.+OOOOOO",
+"OOOOOOOOOOO++=====O=====+=O+==++=O+OOOOO",
+"OOOOOOOOOOO+=.=====.=++++===OO==+O=+OOOO",
+"OOOOOOOOOOO=+===.+=o==o===+&OoO======OOO",
+"OOOOOOOO+O+====OO+=o&&&&Oo==o&oO+==+=.O.",
+"OOOO+.+=+O==+&&o=oooOo&o&ooo=&oooO==O=+=",
+"OOOOOOOO++O===oo=oo&=&o&&oo=o==&o+==++==",
+"OOOOOOOO=o.=O====o&OO&o&oo&o&&oo=======O",
+"OOOOOOOo===+=O=O=ooO=ooooOOo=o&O=====OOO",
+"OOOOOOOOO+==+=======O=oo====O=o=O===+OOO",
+"OOOOOOOOO.=#=X=+====O========O======OOOO",
+"OOOOOOO.#Xo++.=#%====O==========OO==+OOO",
+"OOOOOO+Xo#+#+.#=.==X====+====O=+=+==+OOO",
+"OOOOO.+.+O===##.#=X.====oX##===o+OO.OOOO",
+"OOOOO#+####O#O##o.#+==#X#O#+...=OOo=+OOO",
+"OOOO++#o+#+X++++#.#O.#+#X.#+X+==+OO=oOOO",
+"OOOO#+.+..X+.##X++#++#..+XX#+##+..OOOOOO",
+"OOOO##....O+#++#+.++#+X+#+#X..+#+#OOOOOO",
+"OOOO++#+.+.#+#O+X#X#XX#.++##.#++.X$OOOOO",
+"OOOOO#+#+.+++#++.+++##+X###+X+X##+**OOOO",
+"OOOOO#..#OO#+.##o###.+..++.+#X+#+#* @OOO",
+"OOOOO+#.#O+#+#O.+++.###+##++###+.#* $OOO",
+"OOOOOOXX+#+#+#o..X##++#+..##.#+###  *OOO",
+"OOOOOOOX#.#X+#+#+#+.#+..+####%XX%%   OOO",
+"OOOOOOOO.%%X.#+#+#.++#+#+#+.X++=.%  *OOO",
+"OOOOOOOOO.* *##+#+.O####.+XX%%%%#%  $OOO",
+"OOOOOOOOOOO.   %X.+.#+++XXX=.+++#X  $OOO",
+"OOOOOOOOOOOO.*   %%X..#X%=.####%X*  $OOO",
+"OOOOOOOOOOOOOO.$ *XX%%%=.#X%###=*   OOOO",
+"OOOOOOOOOOOOOOOOOO+%%%=%%#.+.#=*   @OOOO",
+"OOOOOOOOOOOOOOOOOOo=%%%==X##X%*    OOOOO",
+"OOOOOOOOOOOOOOOOOOO+X%%%%X=%*     @OOOOO",
+"OOOOOOOOOOOOOOOOOOOOX%%%%X      *@OOOOOO",
+"OOOOOOOOOOOOOOOOOOOO=%%%X*   *$$OOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOO+X%%=  .OOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOX%%%  OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOO=%%* $OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOO=%%% $OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOO+%%% $OOOOOOOOOOOOO"
+};
+/* XPM */
+static const char *dex_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 19 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #F8B090",
+"o c #5C7A7A",
+"O c #D4D4D4",
+"+ c #F87A24",
+"@ c #7C3400",
+"# c None",
+"$ c #B0B0B0",
+"% c #F89E6C",
+"& c #B64700",
+"* c #909090",
+"= c #606060",
+"- c #CEAA90",
+"; c #DADAB6",
+": c #303030",
+"> c #F86800",
+", c #FFB691",
+"< c #F88C48",
+/* pixels */
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"###############-%-######################",
+"##############-%X<-#####################",
+"#########-<<-#-%XX+==###################",
+"#########%,X< :<,X%@ :##################",
+"#########-XX%: @;X%+  *#################",
+"##########<,X& :<<%+: :#################",
+"######->+#-%%%: <,XX@  #################",
+"######%X%@ <,,& @XXX+  :++-#############",
+"######-<X+ &,X%:@+<+>:  <X&o############",
+"######$<X<@:<<%& <,XX@ @X,@ =###########",
+"#######-+%< &,,%:&,XX+ @,X+ :###########",
+"####<<-o&,X@:X,,&@,XX< @,X%& :##########",
+"####<X%::%%< &,,X:<%X%@:%XX%@ =#########",
+"####%%X& <X,&@%<%<%<<%& >+XX+  #########",
+"#####+%%@@,X%<,XXXXXXX<:@XXX<: =########",
+"####$%XX< <,<XXXXXXXXXX&@,XXX@ :########",
+"######+X<&@%%XXX%XXXX%<<><,XX&  ########",
+"#####$%<%X@%XXXX<X%XXXX<><%XX<  =#######",
+"#######<;X%XXXXX<<<XXX<XX<,XX%@ =#######",
+"#######-%+XXXXX%+XXXXXXXX%<,XX@ =#######",
+"########<XXXXXX+XX%XXXXXXXX%XX@ =#######",
+"########-%XXX%+%XX<XXXXXXXX%XX@  #######",
+"#########+,XX+XXXX<,XXXXXXXXXX@  #######",
+"#########-<X+%XXXX%,XXXXXXXXXX@  #######",
+"##########>,XXXXXX%,XXXXXXXXX%@  #######",
+"##########-<XXXXXX<,XXXXXXXXX<   #######",
+"###########%%XXXXXX%,,XXXXXXX+   #######",
+"############+,XXXXXX<;,,XXXXX@   #######",
+"############-+,XXXXXX%%%,XXX%@   #######",
+"#############%%XXXXXXXX%<XXXX+  =#######",
+"#############$%<XXXXXXXXXXXXX<: =#######",
+"##############$-<<XXXXXXXXXXXX&  #######",
+"################.&,XXXXXXXXXXX<: =######",
+"#################O######################"
+};
+/* XPM */
+static const char *ext_enc_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #303030",
+"= c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO",
+"OOOOOOOOOOO&&&&&&&&&&&&&&&.OOOOOOOOOOOOO",
+"OOOOOOOOOOOo==============X*OOOOOOOOOOOO",
+"OOOOOOOOOOoO===X====X=====X**OOOOOOOOOOO",
+"OOOOOOOOOO&============X===% $OOOOOOOOOO",
+"OOOOOOOOOoo======X=========%* OOOOOOOOOO",
+"OOOOOOOOOoO===X============X* @OOOOOOOOO",
+"OOOOOOOOO&=========X===%%===% $OOOOOOOOO",
+"OOOOOOOOoo===     ===%   *==X  OOOOOOOOO",
+"OOOOOOOOoO==* %*%*=== *%* *=X* @OOOOOOOO",
+"OOOOOOOO&=== %======% ===% ==% $OOOOOOOO",
+"OOOOOOOoo==* ======= *===% X=%* OOOOOOOO",
+"OOOOOOOoO==%    *%== *==== %=X* @OOOOOOO",
+"OOOOOOO&===%%*%*  == %==== *==% $OOOOOOO",
+"OOOOOOoo========% %=* ===X X==X  OOOOOOO",
+"OOOOOOoO===*====* *=% ===* ===X* @OOOOOO",
+"OOOOOO&===*  %*%  X== **% %====% $OOOOOO",
+"OOOOOoo===%%    *X===%   *=====%* OOOOOO",
+"OOOOOo+========================X* @OOOOO",
+"OOOOOo=========================%* $OOOOO",
+"OOOOOO=XXX%X%XXXXX%X%XXXX%X%X%X%*  OOOOO",
+"OOOOOO.=************************   OOOOO",
+"OOOOOOOO                           OOOOO",
+"OOOOOOOO.                         @OOOOO",
+"OOOOOOOOOOoOOoOOoOOoOoOoOOoOoOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static const char *hallu_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 30 1",
+/* colors */
+"  c #F85848",
+". c #5C7A7A",
+"X c #009100",
+"o c #6CFF00",
+"O c #E00028",
+"+ c #D4D4D4",
+"@ c #FF6C00",
+"# c #F87A24",
+"$ c None",
+"% c #B0B0B0",
+"& c #F82C24",
+"* c #F89E6C",
+"= c #FF00FF",
+"- c #FF0000",
+"; c #B64700",
+": c #909090",
+"> c #788C8C",
+", c #606060",
+"< c #406868",
+"1 c #C80050",
+"2 c #FFFFFF",
+"3 c #FFFF00",
+"4 c #00B6FF",
+"5 c #CEAA90",
+"6 c #DADAB6",
+"7 c #F86800",
+"8 c #FFB691",
+"9 c #6C91B6",
+"0 c #F88C48",
+"q c #0000FF",
+/* pixels */
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$353333335*$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$*33333333#7@3335$$$$$$$$$$$$",
+"$$$$$$$$$65333333333@7777#333*$$$$$$$$$$",
+"$$$$$$$$$3333333333377777733333===%$$$$$",
+"$$$$$$$533333333333#7777777333%=====$$$$",
+"$$$$$$ #3333333333o>7777773330======%$$$",
+"$$$$5---O#33333o3944077777333*=======$$$",
+"$$$$-----O333333>4444.77333330======%$$$",
+"$$$ ---O--;3333344444443333333:====5$$$$",
+"$$$ O-----733333444444433333333 ==035$$$",
+"$$$3--O--O333333>44444>33333333333333$$$",
+"$$533---O33333333944493333#333333333356$",
+"$$33867733333o33333:o333333o3333333333$$",
+"$532+2233333#333333333333oooo3#3333333%$",
+"6522222+33333333333333333oooooo33o3333*$",
+"$+22+22263333333o3333333ooooooo333333356",
+"662222+2533333333333333#ooooooo33333333$",
+"$32+22223333o3#33333o333ooooooo3#333333%",
+"$33222233333333333#333333ooooo333333333$",
+"$33368333333333333330626*oooo#333333o33%",
+"%333335== 33oo333333222223#333333333333$",
+"$3333=====:ooooo333+22+2263333333.>o333%",
+"$5333=====oooooo33322222223333339444935$",
+"$*33 ====>ooooooo3362+222633333.44444>3$",
+"$%330====:ooooooo333222+23333334444444$$",
+"$$333177 =oooXoo#333*626333333;4444444$$",
+"$$53##777&3oooo3333333333333#--,444449$$",
+"$$$3;77777#3o333333333333333O---94449$$$",
+"$$%*@77777#33333333333333337O----O:o3$$$",
+"$$$5777777333  333333333333;---O-O73$$$$",
+"$$$$#7777730====#:.,33333333------3$$$$$",
+"$$$$$577333=====qqqq<0333333#O---35$$$$$",
+"$$$$$%53335====qqqqqq.33o333337735$$$$$$",
+"$$$$$$$533 ====qqqqqqq3333333333%$$$$$$$",
+"$$$$$$$$%33====qqqqqqq333333333%$$$$$$$$",
+"$$$$$$$$$$50===qqqqqq,3333333:$$$$$$$$$$",
+"$$$$$$$$$%6%5503,qqq<333#335%$$$$$$$$$$$",
+"$$$$$$$$$$$$$%$*53,03335o$%%$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$%$$+$$$$$$$$$$$$$$$"
+};
+/* XPM */
+static const char *hungry_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 15 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #CEAA90",
+"= c #DADAB6",
+"- c #303030",
+"; c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO========OOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOO=============OOOOOOOOOOOOO",
+"OO;XX;@OOOOO================OOOOOOOO;XOO",
+"OO;%-;$OOOO==================OOOOOOO;XOO",
+"OO;-%;$OOO========@$#@========OOOOO+;;$O",
+"OO;%-;$OO=======-     -*======*OOOO.;;$O",
+"OO;-%;$O======*  @====.$$&=====@OOO.;;$O",
+"OO;X%;$O====== -========*@=====*.OO+;;$O",
+"OO;;;X$o====* -==========@======$OO;;;$O",
+"OO+;;-+o====- =============o====#@O+;;$O",
+"OOO;%$O===== @=============&====*$O;;;$O",
+"OOO+%OO====@ ==============&=====-OO;;$O",
+"OOo;-Oo====$ ==============o&==== OO;;$O",
+"OOO+%OO====@ ==============&===== O+;;#O",
+"OOO;-Oo====$-==============&&==== O+;;-O",
+"OOO;;+O=====$*============&&====* OO;;%+",
+"OOO;;$o=====$.============&&====X-OO;;$O",
+"OOO;;$O======*.===&======&&=====-$=O;;$O",
+"OOO;;$Oo=====.==========&&=====* @O+;;$O",
+"OOO;;$OO=======oo=====&&&======$-OOO;;$O",
+"OOO;;$OOo=======&o&&&&&&======$ @OOO;;$O",
+"OOO;;$OOOO========&=&========* $OOOO;;$O",
+"OO+;;$OOOOo=================* -OOOOO#;$O",
+"OOO;;$OOOOO=*==============@ -=OOOOO;;$O",
+"OOO;;$OOOOOOO+*==========*- $OOOOOOO;;$O",
+"OOOX-$OOOOOOOO@X@*====*#- -.OOOOOOOOX-$O",
+"OOOOOOOOOOOOOO=*@$-    -$.=OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOO=O==O=O=OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static const char *hvy_enc_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #303030",
+"= c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO",
+"OOOOOOOOOOO&&&&&&&&&&&&&&&.OOOOOOOOOOOOO",
+"OOOOOOOOOOOo==============X*OOOOOOOOOOOO",
+"OOOOOOOOOOoO===X====X=====X**OOOOOOOOOOO",
+"OOOOOOOOOO&============X===% $OOOOOOOOOO",
+"OOOOOOOOOoo===*%====***%===%* OOOOOOOOOO",
+"OOOOOOOOOoO==% %===*    %==X* @OOOOOOOOO",
+"OOOOOOOOO&===% *==% X==**===% $OOOOOOOOO",
+"OOOOOOOOoo===% %==% ===% ===X  OOOOOOOOO",
+"OOOOOOOOoO==== *== *==== *==X* @OOOOOOOO",
+"OOOOOOOO&===== %== %==== %===% $OOOOOOOO",
+"OOOOOOOoo===== *== *==== *===%* OOOOOOOO",
+"OOOOOOOoO===== %==% ===* ====X* @OOOOOOO",
+"OOOOOOO&===X== *==% X==**=====% $OOOOOOO",
+"OOOOOOoo=====   *==*    %=====X  OOOOOOO",
+"OOOOOOoO=====*%%X===*%*X======%* @OOOOOO",
+"OOOOOOo====================X===* $OOOOOO",
+"OOOOOOO=%X%XXXX%XXXXXXXXX%X=%X%   OOOOOO",
+"OOOOOOO.=**********************   OOOOOO",
+"OOOOOOOOO                         OOOOOO",
+"OOOOOOOOO.                       @OOOOOO",
+"OOOOOOOOOOOoOOoOoOoOoOoOoOOoOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static const char *int_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 12 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #303030",
+"* c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOO+#.X.##@#OOOOOOOOOOOOOOOOOO",
+"OOOOOOOO+##@X#O++.#+#.##OOOOOOOOOOOOOOOO",
+"OOOOOO+#Xo++#X#%#+##o#O#.#+OOOOOOOOOOOOO",
+"OOOOO.Xo#+#++##+.XX#..+.+..XOOOOOOOOOOOO",
+"OOOO++.+O.+O##+#.X###..OX#.+X+OOOOOOOOOO",
+"OOOO#+####O#O##o##+###X#+#+.#..OOOOOOOOO",
+"OOO.+#o+#+X++++#.#O+#+#X.#+X++X+OOOOOOOO",
+"OOO.+.+..X+.##X++#++#..+XX#+#X+..OOOOOOO",
+"OOO##....O+#++#+.++#+X+#+#X..+#+#OOOOOOO",
+"OOO++#+.+.#+#O+X#X#XX#.++##.#++.X$OOOOOO",
+"OOOO#+#+.+++#++.+++##+X###+X+X##+&&OOOOO",
+"OOOO#..#OO#+.##o###.+..++.+#X+#+#& @OOOO",
+"OOOO.#.#O+#+#O.+++.###+##++###+.#  $OOOO",
+"OOOOOXX+#+#+#o..X##++#+..##.#+###  &OOOO",
+"OOOOOOX#.#X+#+#+#+.#+..+####XX%X%   OOOO",
+"OOOOOOO.%%X.#+#+#.++#+#+#+.%++*+%  &OOOO",
+"OOOOOOOO@& &##+#+.O####.+XXX%%%#%  $OOOO",
+"OOOOOOOOOO.   %X.+.#+++XXX*.+++#%  $OOOO",
+"OOOOOOOOOOO@&   %%X..#XXX.####%%&  $OOOO",
+"OOOOOOOOOOOOO@$ &XX%%%*.#X%###*&   OOOOO",
+"OOOOOOOOOOOOOOOOO+%%%*%%#.+.#*&   @OOOOO",
+"OOOOOOOOOOOOOOOOOO*%%%*.X##XX&    OOOOOO",
+"OOOOOOOOOOOOOOOOOOOX%%%%X*%&     @OOOOOO",
+"OOOOOOOOOOOOOOOOOOOX%%%%%      &@OOOOOOO",
+"OOOOOOOOOOOOOOOOOOO*%%%X&   &$$OOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOO+%%%*  .OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOO+*%%%  OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOO*%%& $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOO+%%& $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOoOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static const char *lawful_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 10 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #606060",
+"$ c #FFFFFF",
+"% c #303030",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOo$$$$$$oOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOO$$o$$o$$$$$OOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOo$$$$$$$o$$ooOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO$o$$$o$$$$$$$oOOOOOOOO",
+"OOOOOOOOOOOOOOOOOo$$$$+ .o$$$$$oOOOOOOOO",
+"OOOOOOOOOOOOOOOOOo$$$+%OOOO$o$$$oOOOOOOO",
+"OOOOOOOOOOOOOOOOO$$o$X@OOOOo$$$ooOOOOOOO",
+"OOOOOOOOOOOOOOOOO$$$$%OOOOOo$$$..OOOOOOO",
+"OOOOOOOOOOOOOOOOO$$$$@OOOOo$$oo##OOOOOOO",
+"OOOOOOOOOOOOOOOO+$$o$$ooOoo$$$o OOOOOOOO",
+"OOOOOOOOOOOOOOOOO$$$$$$$o$$$$o#%OOOOOOOO",
+"OOOOOOOOOOOOOOOO+$$o$$o$$$$$o@%OOOOOOOOO",
+"OOOOOOOOOOOOOOOOO$$$$$$$$o$o.%OOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOo$$$o$$oo@#%OOOOOOOOOOO",
+"OOOOOOOOoooooo$$$$$$$$$$$% %OOOOOOOOOOOO",
+"OOOOOOO$$$$$$$$$$$$o$$o$$$$$$$oOOOOOOOOO",
+"OOOOOO$$$$$$$$$o$$$$$$$$$$$$o$$oOOOOOOOO",
+"OOOOOO$$o$ooooo##+o$$+##@oo$$$$$oOOOOOOO",
+"OOOOOOo$$#%    %#$$$+%##%%#ooo$O#OOOOOOO",
+"OOOOOOOo@##OOOOO+$$$##OOOO#%%##%@OOOOOOO",
+"OOOOOOOOOOOOOOOOo$$$##OOOOOOO##@OOOOOOOO",
+"OOOOOOOOOOOOOOOOo$$o##OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO$$oo OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO+$$$o OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO$o$##OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo$$$##OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo$$o%@OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo$$o OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO$$oo OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO$$$o OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo$$##OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO$$o##OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo$# @OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO.#@OOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static const char *mod_enc_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #303030",
+"= c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOo&&&&&&&&&oXOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOO+&=========X%@OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOO&=====X====% @OOOOOOOOOOOOO",
+"OOOOOOOOOOOOoO==X=======X* OOOOOOOOOOOOO",
+"OOOOOOOOOOOO&====*%*%*===* $OOOOOOOOOOOO",
+"OOOOOOOOOOO+&===X     ===% *OOOOOOOOOOOO",
+"OOOOOOOOOOOoO===**=======X* OOOOOOOOOOOO",
+"OOOOOOOOOOO&===% %=======X% $OOOOOOOOOOO",
+"OOOOOOOOOOO&===% %*%%=====% *OOOOOOOOOOO",
+"OOOOOOOOOOoO===*      ====X* OOOOOOOOOOO",
+"OOOOOOOOOO&=========* X===X% $OOOOOOOOOO",
+"OOOOOOOOO+&=========% *====% *OOOOOOOOOO",
+"OOOOOOOOOoO===% %===  %====%* OOOOOOOOOO",
+"OOOOOOOOO&====*      *==X===% $OOOOOOOOO",
+"OOOOOOOOO&======*%*%X=======% *OOOOOOOOO",
+"OOOOOOOOOo==X===============%  OOOOOOOOO",
+"OOOOOOOOO=XXXXXXXXXX%X%X%X%%%  $OOOOOOOO",
+"OOOOOOOOOO=%****************   $OOOOOOOO",
+"OOOOOOOOOOO$                   $OOOOOOOO",
+"OOOOOOOOOOOO*                 *OOOOOOOOO",
+"OOOOOOOOOOOOOoOOoOoOoOoOoOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static const char *neutral_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 14 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #00B6FF",
+"= c #303030",
+"- c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOO.------.OOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOO-+O&o.-----OOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO+-&o--------.OOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO-oo----------+OOOOOOOO",
+"OOOOOOOOOOOOOOOOO+-&--% #-------OOOOOOOO",
+"OOOOOOOOOOOOOOOOO-OO-X=OOO.-----+OOOOOOO",
+"OOOOOOOOOOOOOOOOO-oO-%#OOOO.-----OOOOOOO",
+"OOOOOOOOOOOOOOOOO--O-=OOOOO+---X#OOOOOOO",
+"OOOOOOOOOOOOOOOOO-oO-XOOOO+OO--=$OOOOOOO",
+"OOOOOOOOOOOOOOOOO-OO--++OO-&--- OOOOOOOO",
+"OOOOOOOOOOOOOOOOO-OO-----+oo--%=OOOOOOOO",
+"OOOOOOOOOOOOOOOOO--O--+o&&o--%=OOOOOOOOO",
+"OOOOOOOOOOOOOOOOO-oo*-------%=OOOOOOOOOO",
+"OOOOOOOOOOOOOOOOO-oO------%%=OOOOOOOOOOO",
+"OOOOOOOO+.+-+.---O&------= =OOOOOOOOOOOO",
+"OOOOOO+-oo&&&&&&&&------------.OOOOOOOOO",
+"OOOOOO---------------X-----O&Oo-OOOOOOOO",
+"OOOOOO---------%=%---%%=%----OO-.OOOOOOO",
+"OOOOOO---==    =%---%=%%===----%XOOOOOOO",
+"OOOOOOO-#$%OOOOOO-+-%$OOOO%===%=@OOOOOOO",
+"OOOOOOOOOOOOOOOO.-&-=%OOOOOOO%%#OOOOOOOO",
+"OOOOOOOOOOOOOOOo-O+-%$OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO-oO- OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO-OO- OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO-&-%%OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO-&-%$OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO-&-=$OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO--o-%$OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO+-&- .OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO-Oo- OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO-OO- OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO-oO- OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO-OO%%OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO-o-%$OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO---%$OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO--% #OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOX$@OOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static const char *ovr_enc_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #303030",
+"= c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOoO+=+OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOo=#===+OOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo=.OO@X=OOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo#OO* #X @OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO+=.XX+=#* @OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO+=O=.=OO $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOO#.=+OO@ $OOOOOOOOOOOOOO",
+"OOOOOOOOOooooooooo&O.#+#XooooOOOOOOOOOOO",
+"OOOOOOOOO&OOoOoOoOOOOOOOOOoO%@OOOOOOOOOO",
+"OOOOOOOOoO==================X*@OOOOOOOOO",
+"OOOOOOOO&===================X% @OOOOOOOO",
+"OOOOOOOO&==%*%*%*%*%*%*%*%*==% *OOOOOOOO",
+"OOOOOOOoO==%*%%*%%*%%*%*%*%==X* OOOOOOOO",
+"OOOOOOO&======================* $OOOOOOO",
+"OOOOOO+&===                ===% *OOOOOOO",
+"OOOOOOoO======================X* OOOOOOO",
+"OOOOOO&=======================X% $OOOOOO",
+"OOOOOOo========================% *OOOOOO",
+"OOOOOoO===*%X=====%%======%%===X* OOOOOO",
+"OOOOO&==%    %==%   *====    %==* $OOOOO",
+"OOOOO&== *==**== **% *=X% %%* ==% *OOOOO",
+"OOOOoO==%%==* =* ===% == %=== %=X* OOOOO",
+"OOOO&=======% =**===% %X %X==* =X% $OOOO",
+"OOOO&======% %= %==== %% ====* ==% *OOOO",
+"OOOoO=====% *== *==== %* ====% ==X* OOOO",
+"OOO&====XX *===**===% X% X=== *===* $OOO",
+"OO+&====X *====* ===% == *=== %===% *OOO",
+"OOoO===%  %*%*== *** %==% %** ====X* OOO",
+"OO&====%      ==X   *====*   %====X% $OO",
+"OO&================================% *OO",
+"OOo===X============================%  OO",
+"OO=XXXXXXXXXXXX%XXXX%X%X%XXXXX%X%X%%  $O",
+"OOO=%******************************   $O",
+"OOOO$                                 $O",
+"OOOOO*                               *OO",
+"OOOOOOOOOOoOOoOOoOOoOOoOOoOOoOOoOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static const char *pet_mark_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"8 7 2 1",
+/* colors */
+". c None",
+"  c #FF0000",
+/* pixels */
+"........",
+"..  .  .",
+".       ",
+".       ",
+"..     .",
+"...   ..",
+".... ..."
+};
+/* XPM */
+static const char *pet_mark_small_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"5 5 2 1",
+/* colors */
+". c None",
+"X c #FF0000",
+/* pixels */
+".X.X.",
+"XXXXX",
+".XXX.",
+"..X.."
+};
+/* XPM */
+static const char *satiated_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 23 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #F8B090",
+"o c #5C7A7A",
+"O c #D4D4D4",
+"+ c #F87A24",
+"@ c #7C3400",
+"# c None",
+"$ c #B0B0B0",
+"% c #F89E6C",
+"& c #914700",
+"* c #B64700",
+"= c #909090",
+"- c #788C8C",
+"; c #606060",
+": c #406868",
+"> c #FFFFFF",
+", c #CEAA90",
+"< c #DADAB6",
+"1 c #303030",
+"2 c #FFB691",
+"3 c #6C91B6",
+"4 c #F88C48",
+/* pixels */
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"################<<<<<<<<################",
+"##############<<<<<<<<<<$#$$$###########",
+"############<<<<<<<<<<$:31:3:###########",
+"###########<<<<<<%42<<#:3:133-##########",
+"##########<<<<<%<<;;=o$131:33;##########",
+"#########<<<<<<,1     ::31:33;,#########",
+"########<<<<<<,  =<<<<.13:133;<=########",
+"########<<<%2, 1<<<<<<#333:33;<,=#######",
+"#######<<<<X$ 1<<422<<<33313--<<;#######",
+"#######<<<<<1 <<<<<%<<<#31333;<<-=######",
+"#######<<<<< -<<+%,%<<%<31.3-;<<,;######",
+"#######<<<2- <<<+&<%<2+<3o<33o<<<1######",
+"######O<<<%; <<<&,4=4%<<-o<3-=<<< ######",
+"#######<<<%; <2+4,&*,,,<3o<33o<<< ######",
+"######<<<<<-1<<<<,4<4<<<.;<3-1<<< ######",
+"#######<<<<<;,<<4,,4X<<#3-<33o<<, ######",
+"######O<<<<<;.<<<,&%<2<$3:>3-=<<o1######",
+"#######<<<<<<=,<<<<<<4<#31>33;<<@o######",
+"#######O<<<<<,#<<<<<<<<.3:<3-;<, =######",
+"########<<<<2<<<<<<<<<>#31<33o<11#######",
+"########O<<<<44<>O>>>>>#3:<3.;- =#######",
+"##########<<<4<<<<><><<$3:<331 ;<#######",
+"##########<<<<<<<%2<<<<$3:<33 1#########",
+"###########O,<<<<<<<<<<#31<331##########",
+"#############.<<<<<<<<<$3:133;##########",
+"##############=;=,<<<<,o  1;;=##########",
+"###############<=;1    1;=##############",
+"#################<#<O#<#################",
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"########################################"
+};
+/* XPM */
+static const char *sick_fp_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 30 1",
+/* colors */
+"  c #F85848",
+". c #949E9E",
+"X c #F8B090",
+"o c #5C7A7A",
+"O c #009100",
+"+ c #6CFF00",
+"@ c #E00028",
+"# c #D4D4D4",
+"$ c #FF6C00",
+"% c #F87A24",
+"& c #7C3400",
+"* c None",
+"= c #B0B0B0",
+"- c #F89E6C",
+"; c #FF0000",
+": c #914700",
+"> c #B64700",
+", c #909090",
+"< c #788C8C",
+"1 c #606060",
+"2 c #406868",
+"3 c #FFFFFF",
+"4 c #CEAA90",
+"5 c #DADAB6",
+"6 c #303030",
+"7 c #F86800",
+"8 c #FFB691",
+"9 c #6C91B6",
+"0 c #F88C48",
+"q c #0000FF",
+/* pixels */
+"****************************************",
+"*************#333333333#****************",
+"***********##33333#333333#**************",
+"**********#33333#33333#33*==************",
+"*********#33##33-;-3#3333399************",
+"********#33#33#3-@ 33333#33=.***********",
+"********#3*#33-;;;;;-33333#99***********",
+"*******#3*3333-;;;;@ 33#333#9=**********",
+"*******#333#33#3-;-33#*##33399**********",
+"******#3#3333333-@-#333#9933*9=*********",
+"******#333#33#3333333#333*9999=*********",
+"******#333333333#3#33333333*999*********",
+"******#3#33#33333333#33#3333#9=*********",
+"******#333334>&&:&&>::44,3#33#9*********",
+"******#33*::&41OOO6:4O 0::4433=*********",
+"******#3:>,0:O0O1O+O:O<O4-:-:1#*********",
+"******#0&>XO,O+2+OOo4<+1104:>:#*********",
+"******.&:1OOO,14X2O48:O80,440:,*********",
+"******4::>OOO%8-X4O4%O,84+O0X&>=********",
+"******.::>,O 99*X+<$,+.o*1O4&0:*********",
+"******>:0&4O5qq9#10OO3qq9,+X:1:*********",
+"****=>,,::,O4qq9X+O>O-qq9O2X0,>*********",
+"******4:>OOOO48882OOOO+4OOO07*4*********",
+"******4*,4OO+OXX3O<OOOOOOOO:-***********",
+"********0><OO1+O,+1+2OOOOOO%4=**********",
+"********47+OO1O12O:<14OO1OO7=***********",
+"*********-11OO+,+<1004OOOO:-************",
+"**********:OOOOOO-+,4O+OOO%4************",
+"**********04O4O,-OOOOO<OOO>5************",
+"*********=0%,OO,>:>>O +1OO4*************",
+"**********=%+OO:::1:::6+:7**************",
+"***********7&OO:O+O,O1OO+1**************",
+"***********40OO,O4:OOO11O<5*************",
+"**********=4 +O1O2+O2+O0O***************",
+"************72O+1+21-OOO%5**************",
+"************0%1OOOO+O+174***************",
+"*************%%O,OO1407-=***************",
+"**************-$>%0%:74*****************",
+"****************54044*=*****************",
+"*****************=*=********************"
+};
+/* XPM */
+static const char *sick_il_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 23 1",
+/* colors */
+"  c #F85848",
+". c #949E9E",
+"X c #F8B090",
+"o c #E00028",
+"O c #D4D4D4",
+"+ c #F87A24",
+"@ c #7C3400",
+"# c None",
+"$ c #B0B0B0",
+"% c #F89E6C",
+"& c #FF0000",
+"* c #914700",
+"= c #B64700",
+"- c #909090",
+"; c #606060",
+": c #FFFFFF",
+"> c #CEAA90",
+", c #DADAB6",
+"< c #F86800",
+"1 c #FFB691",
+"2 c #6C91B6",
+"3 c #F88C48",
+"4 c #0000FF",
+/* pixels */
+"########################################",
+"#############O:::::::::O################",
+"###########OO:::::O::::::O##############",
+"##########O:::::O:::::O::#$$############",
+"#########O::OO::%&%:O:::::22############",
+"########O::O::O:%o :::::O::$.###########",
+"########O:#O::%&&&&&%:::::O22###########",
+"#######O:#::::%&&&&o ::O:::O2$##########",
+"#######O:::O::O:%&%::O#OO:::22##########",
+"######O:O:::::::%o%O:::O22::#2$#########",
+"######O:::O::O:::::::O:::#2222$#########",
+"######O:::::::::O:O::::::::#222#########",
+"######O:O::O::::::::O::O::::O2$#########",
+"######O:::::>=@@=**=**>>-:O::O2#########",
+"######O::#**@3>%* ;=>=3;<@>>::$#########",
+"######O:** >=>XXXX1X >>+>%*%*;O#########",
+"######O3@*,X%XXXXXXX>X%XX >*=*O#########",
+"######.@@3XXXXXXXXXXXXXXX>X>3*-#########",
+"######>***>X% >XXXXX3XXXXXX%>*=>########",
+"######.***>  22#XXX<%X22#XXX@+;#########",
+"######=*3@X>O442OXX<X:442OXX=;=#########",
+"####$=--;=X1,442XXX<X1442XXX3-*#########",
+"######>==%XX11111O1+%X111XX%<#>#########",
+"######.,;XXXXXX1O1X%3XXXXX%+3###########",
+"########3=XXXXXX:XXXXXXXXX+<>$##########",
+"########>+XXXXXX%-3->XXXX%+<############",
+"#########%3XXXXXX>- -%XXX%<%$###########",
+"#########$<XXXXXX%X%XXXX%3<>############",
+"##########+%XXXXXXXXXXXX%+<#############",
+"##########%3XXX>=****3XX%<%#############",
+"##########>+XXX**=3-*@3>3+##############",
+"###########<%XX >XX%X;%X3+##############",
+"###########%3XX>XX++XXXX<%$#############",
+"##########$>+XXXXXXXXXXX<###############",
+"############<%XXXXXXXXX3+###############",
+"###########$%+XXXXXXXX%<>###############",
+"#############++XXXXXX%<%$###############",
+"#############$%<<3333<%#################",
+"#################%3>>$##################",
+"#################$#$####################"
+};
+/* XPM */
+static const char *slt_enc_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #303030",
+"= c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO&&&&&&&X @OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo======X*OOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOoO======X**OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOO&====X===% $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOoo==%* %==%* OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOoO=%  %  =X* @OOOOOOOOOOOOO",
+"OOOOOOOOOOOOO&==**==% %=% $OOOOOOOOOOOOO",
+"OOOOOOOOOOOOoo==%%==* %=X  OOOOOOOOOOOOO",
+"OOOOOOOOOOOOoO=====* X==X* @OOOOOOOOOOOO",
+"OOOOOOOOOOOO&=====* %====% $OOOOOOOOOOOO",
+"OOOOOOOOOOOoo====  X=====%* OOOOOOOOOOOO",
+"OOOOOOOOOOOo+===* *%*%%==X* @OOOOOOOOOOO",
+"OOOOOOOOOOO&====      %===% $OOOOOOOOOOO",
+"OOOOOOOOOOO&==============%  OOOOOOOOOOO",
+"OOOOOOOOOOO==============X%  @OOOOOOOOOO",
+"OOOOOOOOOOO+%%%%%%%%%%%%%%   $OOOOOOOOOO",
+"OOOOOOOOOOOOO%               $OOOOOOOOOO",
+"OOOOOOOOOOOOO@               @OOOOOOOOOO",
+"OOOOOOOOOOOOOO@$$$$$$$$$$$$$@OOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static const char *str_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 17 1",
+/* colors */
+"  c #000000",
+". c #F8B090",
+"X c #5C7A7A",
+"o c #F87A24",
+"O c #7C3400",
+"+ c None",
+"@ c #B0B0B0",
+"# c #F89E6C",
+"$ c #B64700",
+"% c #909090",
+"& c #606060",
+"* c #CEAA90",
+"= c #DADAB6",
+"- c #303030",
+"; c #F86800",
+": c #FFB691",
+"> c #F88C48",
+/* pixels */
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"+++++++++++++++++++*>*>#++++++++++++++++",
+"++++++++++++++++*#o>..*#o*++++++++++++++",
+"+++++++++++++++o#.#>.....o++++++++++++++",
+"+++++++++++++++;>;#.o.>..#$X++++++++++++",
+"+++++++++++++++o#>.o.>:...o  %++++++++++",
+"++++++++++++++o##>>#o##>..#O -++++++++++",
+"++++++++++++++>#.oo#>..>...O  ++++++++++",
+"++++++++++++++*o##.>>;o#...o  ++++++++++",
+"+++++++++++++++*;o#........>- &+++++++++",
+"+++++++++++++++++#>>;o......O -+++++++++",
+"+++++++++++++++++@+@+o>.....$  +++++++++",
+"+++++++++++++++++++++*;.#...>- %++++++++",
+"++++++++++++++++++++++;>o....$ &++++++++",
+"++++++++++++++++++++++#>>....>- %+++++++",
+"+++++++++++++++++++++++;#>....; -+++++++",
+"+++++++++++++++++++++++o#>....>O %++++++",
+"+++++++++++++++++++++++*>o.....; -++++++",
+"+++++++++++++#>**+++++++;#.....>O %+++++",
+"+o#+++++++*o;>>>>o#+++++o##.....; -+++++",
+"+:#o*++++oo#..*..*>;*+++#>#.....>O %++++",
+"+:=#o#+*;>.:==:....#;*++@o.......; &++++",
+"+::..>;o#.=::::......o*++;.......>O ++++",
+"+.....#o.:.=:.........o#+;........$ ++++",
+"+......#o..:...........#o;>.......o &+++",
+"+........#..............*>o......:o- +++",
+"+..................#o>#...#o.......O +++",
+"+...............>o>#.......#>......O &++",
+"+..................................o -++",
+"+..................................>  ++",
+"+..................................>  ++",
+"+.................................#$  &+",
+"+................................>$   &+",
+"+..#>$o>#..............#>;>>>oOOO-    ++",
+"+...#O  OOOOO$>>>>>>>$OO             %++",
+"+...o                            -&&++++",
+"+..#O                     -&&%++++++++++",
+"++++++++++++++++++++++++++++++++++++++++"
+};
+/* XPM */
+static const char *stunned_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 12 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #303030",
+"* c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOO&$OOOO@OOO@@OO@OOOOOOOOOOOOO",
+"OOOOOOOOOOO@& $OO@&&$$@ O@$$OOOOOOOOOOOO",
+"OOOOOOOOOOOO$$ @@@$  &&OOO@$OOOOOOOOOOOO",
+"OOOOOOOOOOOOO@@&$$$$&O$OO$O &@O@OOOOOOOO",
+"OOOOOO@@@@@@OO@$$O$&$@@OO&  &&$O&OOOOOOO",
+"OOOOOO&&&& & $ &&@$ &O@$& &&&$ & $OOOOOO",
+"OOOOOO$&OO &&&$ $$    $&  $$&$&&&OOOOOOO",
+"OOOOOO@@O@$  &+ #       &O$$  $$&O@OOOOO",
+"OOOOOOOO@X%$ %&   %%    & &&  $$@@@@OOOO",
+"OOOOOOO+$$@+     &%%%&%&   &  &@OOO&&OOO",
+"OOOOOO.Xo%+      &&%%%%%&& &   OO@$&&OOO",
+"OOOOO++ $$&&$     && %&%%&    &O@&$&OOOO",
+"OOOOO####$ X&&& &&     &%&   &    &&OOOO",
+"OOOO++#.+## $&# %& &       &     &$ OOOO",
+"OOOO#+++.@&%&& &#&%&   &       $ @OOOOOO",
+"OOOO##....#+$#@%#& $%$&@&$$% & X##$@OOOO",
+"OOOO.+#+.+@#+#+$&$X#%&%.+& %&#++.$&OOOOO",
+"OOOOO#+#+.+++#$$%&++&X+X#&#+&+&##+ &OOOO",
+"OOOOO#..#OO#+@%#o##X.@..++.+$&+#+#& @OOO",
+"OOOOO+#.#O+#+#O@++@$$##+##++###+.#& $OOO",
+"OOOOOOXX+#+#+#o.@%&$++#+..##.#+###  &OOO",
+"OOOOOOOX#.#X+#+#+##&#+..+####%XX%%   OOO",
+"OOOOOOOO+%%X.#+#+#.++#+#+#+.X++*.%  &OOO",
+"OOOOOOOOO@& &##+#+.O####.+XX%%%%#%  $OOO",
+"OOOOOOOOOOO.   %X.+.#+++XXX*.+++#X  $OOO",
+"OOOOOOOOOOOO@&   %%X..#X%#.####%X&  $OOO",
+"OOOOOOOOOOOOOO@$ &XX%%%*.#X%###*&   OOOO",
+"OOOOOOOOOOOOOOOOOO+%%%*%%#.+.#*&   @OOOO",
+"OOOOOOOOOOOOOOOOOOO*%%%**X##X%&    OOOOO",
+"OOOOOOOOOOOOOOOOOOOOX%%%%X*X&     @OOOOO",
+"OOOOOOOOOOOOOOOOOOOOX%%%%X      &@OOOOOO",
+"OOOOOOOOOOOOOOOOOOOO*%%%X&   &$$OOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOO+X%%*  @OOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOX%%&  OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOO.X%& $OOOOOOOOOOOOO"
+};
+/* XPM */
+static const char *wis_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c None",
+"O c #B0B0B0",
+"+ c #909090",
+"@ c #788C8C",
+"# c #606060",
+"$ c #406868",
+"% c #FFFFFF",
+"& c #303030",
+"* c #6C91B6",
+"= c #0000FF",
+/* pixels */
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooo+#& &#oooooooooooooooooooo",
+"oooooooooooo+&       #oooooooooooooooooo",
+"ooooooooooo+  &====&& &ooooooooooooooooo",
+"oooooooooo+ &==&  ===%& +ooooooooooooooo",
+"ooooooooo+&%===   ===%%o&&oooooooooooooo",
+"oooooooo.&%%===&  ===%o&   #+ooooooooooo",
+"oooo&###&&%%*=======$#&ooo#&  #+oooooooo",
+"ooooo###o+&X$=====& #oo##oooo+######oooo",
+"oooooooooooo######@oo##ooooooooooooooooo",
+"oooooooooooooOoOoOo##ooooooooooooooooooo",
+"ooooooooooooooooo+#+ooo+&#oooooooooooooo",
+"ooooooooooooooooooooooo#oooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo"
+};
diff --git a/include/qtext.h b/include/qtext.h
new file mode 100644 (file)
index 0000000..0b149c2
--- /dev/null
@@ -0,0 +1,112 @@
+/*     SCCS Id: @(#)qtext.h    3.4     1997/02/02      */
+/* Copyright (c) Mike Stephenson 1991.                           */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef QTEXT_H
+#define QTEXT_H
+
+#define N_HDR  16              /* Maximum number of categories */
+                               /* (i.e., num roles + 1) */
+#define LEN_HDR 3              /* Maximum length of a category name */
+
+struct qtmsg {
+       int     msgnum;
+       char    delivery;
+       long    offset,
+               size;
+};
+
+#ifdef MAKEDEFS_C      /***** MAKEDEFS *****/
+
+#define N_MSG  100             /* arbitrary */
+
+struct msghdr {
+       int     n_msg;
+       struct  qtmsg   qt_msg[N_MSG];
+};
+
+struct qthdr {
+       int     n_hdr;
+       char    id[N_HDR][LEN_HDR];
+       long    offset[N_HDR];
+};
+
+/* Error message macros */
+#define CREC_IN_MSG    "Control record encountered during message - line %d\n"
+#define DUP_MSG                "Duplicate message number at line %d\n"
+#define END_NOT_IN_MSG "End record encountered before message - line %d\n"
+#define TEXT_NOT_IN_MSG        "Text encountered outside message - line %d\n"
+#define UNREC_CREC     "Unrecognized Control record at line %d\n"
+#define OUT_OF_HEADERS "Too many message types (line %d)\nAdjust N_HDR in qtext.h and recompile.\n"
+#define OUT_OF_MESSAGES "Too many messages in class (line %d)\nAdjust N_MSG in qtext.h and recompile.\n"
+
+
+#else  /***** !MAKEDEFS *****/
+
+struct qtlists {
+       struct  qtmsg   *common,
+#if 0  /* UNUSED but available */
+                       *chrace,
+#endif
+                       *chrole;
+};
+
+
+/*
+ *     Quest message defines.  Used in quest.c to trigger off "realistic"
+ *     dialogue to the player.
+ */
+#define QT_FIRSTTIME    1
+#define QT_NEXTTIME     2
+#define QT_OTHERTIME    3
+
+#define QT_GUARDTALK    5      /* 5 random things guards say before quest */
+#define QT_GUARDTALK2  10      /* 5 random things guards say after quest */
+
+#define QT_FIRSTLEADER 15
+#define QT_NEXTLEADER  16
+#define QT_OTHERLEADER 17
+#define QT_LASTLEADER  18
+#define QT_BADLEVEL    19
+#define QT_BADALIGN    20
+#define QT_ASSIGNQUEST 21
+
+#define QT_ENCOURAGE   25      /* 1-10 random encouragement messages */
+
+#define QT_FIRSTLOCATE 35
+#define QT_NEXTLOCATE  36
+
+#define QT_FIRSTGOAL   40
+#define QT_NEXTGOAL    41
+
+#define QT_FIRSTNEMESIS 50
+#define QT_NEXTNEMESIS 51
+#define QT_OTHERNEMESIS 52
+#define QT_NEMWANTSIT  53      /* you somehow got the artifact */
+
+#define QT_DISCOURAGE  60      /* 1-10 random maledictive messages */
+
+#define QT_GOTIT       70
+
+#define QT_KILLEDNEM   80
+#define QT_OFFEREDIT   81
+#define QT_OFFEREDIT2  82
+
+#define QT_POSTHANKS   90
+#define QT_HASAMULET   91
+
+/*
+ *     Message defines for common text used in maledictions.
+ */
+#define COMMON_ID      "-"     /* Common message id value */
+
+#define QT_ANGELIC     10
+#define QTN_ANGELIC    10
+
+#define QT_DEMONIC     30
+#define QTN_DEMONIC    20
+
+#define QT_BANISHED    60
+#endif /***** !MAKEDEFS *****/
+
+#endif /* QTEXT_H */
diff --git a/include/qttableview.h b/include/qttableview.h
new file mode 100644 (file)
index 0000000..f6e5e98
--- /dev/null
@@ -0,0 +1,251 @@
+/**********************************************************************
+** $Id: qttableview.h,v 1.2 2002/03/09 03:13:13 jwalz Exp $
+**
+** Definition of QtTableView class
+**
+** Created : 941115
+**
+** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
+**
+** This file contains a class moved out of the Qt GUI Toolkit API. It
+** may be used, distributed and modified without limitation.
+**
+**********************************************************************/
+
+#ifndef QTTABLEVIEW_H
+#define QTTABLEVIEW_H
+
+#ifndef QT_H
+#include <qframe.h>
+#endif // QT_H
+
+#ifndef QT_NO_QTTABLEVIEW
+
+class QScrollBar;
+class QCornerSquare;
+
+
+class QtTableView : public QFrame
+{
+    Q_OBJECT
+public:
+    virtual void setBackgroundColor( const QColor & );
+    virtual void setPalette( const QPalette & );
+    void       show();
+
+    void       repaint( bool erase=TRUE );
+    void       repaint( int x, int y, int w, int h, bool erase=TRUE );
+    void       repaint( const QRect &, bool erase=TRUE );
+
+protected:
+    QtTableView( QWidget *parent=0, const char *name=0, WFlags f=0 );
+   ~QtTableView();
+
+    int                numRows()       const;
+    virtual void setNumRows( int );
+    int                numCols()       const;
+    virtual void setNumCols( int );
+
+    int                topCell()       const;
+    virtual void setTopCell( int row );
+    int                leftCell()      const;
+    virtual void setLeftCell( int col );
+    virtual void setTopLeftCell( int row, int col );
+
+    int                xOffset()       const;
+    virtual void setXOffset( int );
+    int                yOffset()       const;
+    virtual void setYOffset( int );
+    virtual void setOffset( int x, int y, bool updateScrBars = TRUE );
+
+    virtual int cellWidth( int col );
+    virtual int cellHeight( int row );
+    int                cellWidth()     const;
+    int                cellHeight()    const;
+    virtual void setCellWidth( int );
+    virtual void setCellHeight( int );
+
+    virtual int totalWidth();
+    virtual int totalHeight();
+
+    uint       tableFlags()    const;
+    bool       testTableFlags( uint f ) const;
+    virtual void setTableFlags( uint f );
+    void       clearTableFlags( uint f = ~0 );
+
+    bool       autoUpdate()     const;
+    virtual void setAutoUpdate( bool );
+
+    void       updateCell( int row, int column, bool erase=TRUE );
+
+    QRect      cellUpdateRect() const;
+    QRect      viewRect()       const;
+
+    int                lastRowVisible() const;
+    int                lastColVisible() const;
+
+    bool       rowIsVisible( int row ) const;
+    bool       colIsVisible( int col ) const;
+
+    QScrollBar *verticalScrollBar() const;
+    QScrollBar *horizontalScrollBar() const;
+
+private slots:
+    void       horSbValue( int );
+    void       horSbSliding( int );
+    void       horSbSlidingDone();
+    void       verSbValue( int );
+    void       verSbSliding( int );
+    void       verSbSlidingDone();
+
+protected:
+    virtual void paintCell( QPainter *, int row, int col ) = 0;
+    virtual void setupPainter( QPainter * );
+
+    void       paintEvent( QPaintEvent * );
+    void       resizeEvent( QResizeEvent * );
+
+    int                findRow( int yPos ) const;
+    int                findCol( int xPos ) const;
+
+    bool       rowYPos( int row, int *yPos ) const;
+    bool       colXPos( int col, int *xPos ) const;
+
+    int                maxXOffset();
+    int                maxYOffset();
+    int                maxColOffset();
+    int                maxRowOffset();
+
+    int                minViewX()      const;
+    int                minViewY()      const;
+    int                maxViewX()      const;
+    int                maxViewY()      const;
+    int                viewWidth()     const;
+    int                viewHeight()    const;
+
+    void       scroll( int xPixels, int yPixels );
+    void       updateScrollBars();
+    void       updateTableSize();
+
+private:
+    void       coverCornerSquare( bool );
+    void       snapToGrid( bool horizontal, bool vertical );
+    virtual void       setHorScrollBar( bool on, bool update = TRUE );
+    virtual void       setVerScrollBar( bool on, bool update = TRUE );
+    void       updateView();
+    int                findRawRow( int yPos, int *cellMaxY, int *cellMinY = 0,
+                           bool goOutsideView = FALSE ) const;
+    int                findRawCol( int xPos, int *cellMaxX, int *cellMinX = 0,
+                           bool goOutsideView = FALSE ) const;
+    int                maxColsVisible() const;
+
+    void       updateScrollBars( uint );
+    void       updateFrameSize();
+
+    void       doAutoScrollBars();
+    void       showOrHideScrollBars();
+
+    int                nRows;
+    int                nCols;
+    int                xOffs, yOffs;
+    int                xCellOffs, yCellOffs;
+    short      xCellDelta, yCellDelta;
+    short      cellH, cellW;
+
+    uint       eraseInPaint            : 1;
+    uint       verSliding              : 1;
+    uint       verSnappingOff          : 1;
+    uint       horSliding              : 1;
+    uint       horSnappingOff          : 1;
+    uint       coveringCornerSquare    : 1;
+    uint       sbDirty                 : 8;
+    uint       inSbUpdate              : 1;
+
+    uint       tFlags;
+    QRect      cellUpdateR;
+
+    QScrollBar *vScrollBar;
+    QScrollBar *hScrollBar;
+    QCornerSquare *cornerSquare;
+
+private:       // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+    QtTableView( const QtTableView & );
+    QtTableView &operator=( const QtTableView & );
+#endif
+};
+
+
+const uint Tbl_vScrollBar      = 0x00000001;
+const uint Tbl_hScrollBar      = 0x00000002;
+const uint Tbl_autoVScrollBar  = 0x00000004;
+const uint Tbl_autoHScrollBar  = 0x00000008;
+const uint Tbl_autoScrollBars  = 0x0000000C;
+
+const uint Tbl_clipCellPainting = 0x00000100;
+const uint Tbl_cutCellsV       = 0x00000200;
+const uint Tbl_cutCellsH       = 0x00000400;
+const uint Tbl_cutCells                = 0x00000600;
+
+const uint Tbl_scrollLastHCell = 0x00000800;
+const uint Tbl_scrollLastVCell = 0x00001000;
+const uint Tbl_scrollLastCell  = 0x00001800;
+
+const uint Tbl_smoothHScrolling = 0x00002000;
+const uint Tbl_smoothVScrolling = 0x00004000;
+const uint Tbl_smoothScrolling = 0x00006000;
+
+const uint Tbl_snapToHGrid     = 0x00008000;
+const uint Tbl_snapToVGrid     = 0x00010000;
+const uint Tbl_snapToGrid      = 0x00018000;
+
+
+inline int QtTableView::numRows() const
+{ return nRows; }
+
+inline int QtTableView::numCols() const
+{ return nCols; }
+
+inline int QtTableView::topCell() const
+{ return yCellOffs; }
+
+inline int QtTableView::leftCell() const
+{ return xCellOffs; }
+
+inline int QtTableView::xOffset() const
+{ return xOffs; }
+
+inline int QtTableView::yOffset() const
+{ return yOffs; }
+
+inline int QtTableView::cellHeight() const
+{ return cellH; }
+
+inline int QtTableView::cellWidth() const
+{ return cellW; }
+
+inline uint QtTableView::tableFlags() const
+{ return tFlags; }
+
+inline bool QtTableView::testTableFlags( uint f ) const
+{ return (tFlags & f) != 0; }
+
+inline QRect QtTableView::cellUpdateRect() const
+{ return cellUpdateR; }
+
+inline bool QtTableView::autoUpdate() const
+{ return isUpdatesEnabled(); }
+
+inline void QtTableView::repaint( bool erase )
+{ repaint( 0, 0, width(), height(), erase ); }
+
+inline void QtTableView::repaint( const QRect &r, bool erase )
+{ repaint( r.x(), r.y(), r.width(), r.height(), erase ); }
+
+inline void QtTableView::updateScrollBars()
+{ updateScrollBars( 0 ); }
+
+
+#endif // QT_NO_QTTABLEVIEW
+
+#endif // QTTABLEVIEW_H
diff --git a/include/quest.h b/include/quest.h
new file mode 100644 (file)
index 0000000..98b9e3a
--- /dev/null
@@ -0,0 +1,41 @@
+/*     SCCS Id: @(#)quest.h    3.4     1992/11/15      */
+/* Copyright (c) Mike Stephenson 1991.                           */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef QUEST_H
+#define QUEST_H
+
+struct q_score {                       /* Quest "scorecard" */
+       Bitfield(first_start,1);        /* only set the first time */
+       Bitfield(met_leader,1);         /* has met the leader */
+       Bitfield(not_ready,3);          /* rejected due to alignment, etc. */
+       Bitfield(pissed_off,1);         /* got the leader angry */
+       Bitfield(got_quest,1);          /* got the quest assignment */
+
+       Bitfield(first_locate,1);       /* only set the first time */
+       Bitfield(met_intermed,1);       /* used if the locate is a person. */
+       Bitfield(got_final,1);          /* got the final quest assignment */
+
+       Bitfield(made_goal,3);          /* # of times on goal level */
+       Bitfield(met_nemesis,1);        /* has met the nemesis before */
+       Bitfield(killed_nemesis,1);     /* set when the nemesis is killed */
+       Bitfield(in_battle,1);          /* set when nemesis fighting you */
+
+       Bitfield(cheater,1);            /* set if cheating detected */
+       Bitfield(touched_artifact,1);   /* for a special message */
+       Bitfield(offered_artifact,1);   /* offered to leader */
+       Bitfield(got_thanks,1);         /* final message from leader */
+
+       /* keep track of leader presence/absence even if leader is
+          polymorphed, raised from dead, etc */
+       Bitfield(leader_is_dead,1);
+       unsigned leader_m_id;
+};
+
+#define MAX_QUEST_TRIES  7     /* exceed this and you "fail" */
+#define MIN_QUEST_ALIGN 20     /* at least this align.record to start */
+  /* note: align 20 matches "pious" as reported by enlightenment (cmd.c) */
+#define MIN_QUEST_LEVEL 14     /* at least this u.ulevel to start */
+  /* note: exp.lev. 14 is threshold level for 5th rank (class title, role.c) */
+
+#endif /* QUEST_H */
diff --git a/include/rect.h b/include/rect.h
new file mode 100644 (file)
index 0000000..a7deafb
--- /dev/null
@@ -0,0 +1,13 @@
+/*     SCCS Id: @(#)rect.h     3.4     1990/02/22      */
+/* Copyright (c) 1990 by Jean-Christophe Collet                          */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef RECT_H
+#define RECT_H
+
+typedef struct nhrect {
+       xchar lx, ly;
+       xchar hx, hy;
+} NhRect;
+
+#endif /* RECT_H */
diff --git a/include/region.h b/include/region.h
new file mode 100644 (file)
index 0000000..e328956
--- /dev/null
@@ -0,0 +1,67 @@
+/*     SCCS Id: @(#)region.h   3.4     2002/10/15      */
+/* Copyright (c) 1996 by Jean-Christophe Collet                          */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef REGION_H
+#define REGION_H
+
+/* generic callback function */
+
+typedef boolean FDECL((*callback_proc), (genericptr_t, genericptr_t));
+
+/*
+ * Overload the old player_inside field with two values, coded in such
+ * a way as to retain compatibility with 3.4.0 save and bones files;
+ * this relies on the fact that nethack's `boolean' is really stored
+ * in a `char' (or bigger type) rather than in a single bit.
+ *
+ * 3.4.1 save and bones files will be correct.
+ * 3.4.0 save files restored under 3.4.1 will be correct.
+ * 3.4.0 bones files used with 3.4.1 will continue to have the minor
+ *      3.4.0 bug of falsely claiming that the current game's hero is
+ *      responsible for the dead former hero's stinking clouds.
+ */
+#define REG_HERO_INSIDE        1
+#define REG_NOT_HEROS  2
+#define hero_inside(r) ((unsigned)(r)->player_flags & REG_HERO_INSIDE)
+#define heros_fault(r) (!((unsigned)(r)->player_flags & REG_NOT_HEROS))
+#define set_hero_inside(r)     ((r)->player_flags |= REG_HERO_INSIDE)
+#define clear_hero_inside(r)   ((r)->player_flags &= ~REG_HERO_INSIDE)
+#define set_heros_fault(r)     ((r)->player_flags &= ~REG_NOT_HEROS)
+#define clear_heros_fault(r)   ((r)->player_flags |= REG_NOT_HEROS)
+
+typedef struct {
+  NhRect bounding_box;         /* Bounding box of the region */
+  NhRect *rects;               /* Rectangles composing the region */
+  short  nrects;               /* Number of rectangles  */
+  boolean attach_2_u;          /* Region attached to player ? */
+  unsigned int attach_2_m;     /* Region attached to monster ? */
+  /*struct obj *attach_2_o;*/  /* Region attached to object ? UNUSED YET */
+  const char* enter_msg;       /* Message when entering */
+  const char* leave_msg;       /* Message when leaving */
+  short  ttl;                  /* Time to live. -1 is forever */
+  short expire_f;              /* Function to call when region's ttl expire */
+  short can_enter_f;           /* Function to call to check wether the player
+                                  can, or can not, enter the region */
+  short enter_f;               /* Function to call when the player enters*/
+  short can_leave_f;           /* Function to call to check wether the player
+                                  can, or can not, leave the region */
+  short leave_f;               /* Function to call when the player leaves */
+  short inside_f;              /* Function to call every turn if player's
+                                  inside */
+  boolean player_flags;        /* (see above) */
+  unsigned int* monsters;      /* Monsters currently inside this region */
+  short n_monst;               /* Number of monsters inside this region */
+  short max_monst;             /* Maximum number of monsters that can be
+                                  listed without having to grow the array */
+#define MONST_INC      5
+
+  /* Should probably do the same thing about objects */
+
+  boolean visible;             /* Is the region visible ? */
+  int glyph;                   /* Which glyph to use if visible */
+  genericptr_t arg;            /* Optional user argument (Ex: strength of
+                                  force field, damage of a fire zone, ...*/
+} NhRegion;
+
+#endif /* REGION_H */
diff --git a/include/rm.h b/include/rm.h
new file mode 100644 (file)
index 0000000..7996cac
--- /dev/null
@@ -0,0 +1,526 @@
+/*     SCCS Id: @(#)rm.h       3.4     1999/12/12      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef RM_H
+#define RM_H
+
+/*
+ * The dungeon presentation graphics code and data structures were rewritten
+ * and generalized for NetHack's release 2 by Eric S. Raymond (eric@snark)
+ * building on Don G. Kneller's MS-DOS implementation. See drawing.c for
+ * the code that permits the user to set the contents of the symbol structure.
+ *
+ * The door representation was changed by Ari Huttunen(ahuttune@niksula.hut.fi)
+ */
+
+/*
+ * TLCORNER    TDWALL          TRCORNER
+ * +-          -+-             -+
+ * |            |               |
+ *
+ * TRWALL      CROSSWALL       TLWALL          HWALL
+ * |            |               |
+ * +-          -+-             -+              ---
+ * |            |               |
+ *
+ * BLCORNER    TUWALL          BRCORNER        VWALL
+ * |            |               |              |
+ * +-          -+-             -+              |
+ */
+
+/* Level location types */
+#define STONE          0
+#define VWALL          1
+#define HWALL          2
+#define TLCORNER       3
+#define TRCORNER       4
+#define BLCORNER       5
+#define BRCORNER       6
+#define CROSSWALL      7       /* For pretty mazes and special levels */
+#define TUWALL         8
+#define TDWALL         9
+#define TLWALL         10
+#define TRWALL         11
+#define DBWALL         12
+#define TREE           13      /* KMH */
+#define SDOOR          14
+#define SCORR          15
+#define POOL           16
+#define MOAT           17      /* pool that doesn't boil, adjust messages */
+#define WATER          18
+#define DRAWBRIDGE_UP  19
+#define LAVAPOOL       20
+#define IRONBARS       21      /* KMH */
+#define DOOR           22
+#define CORR           23
+#define ROOM           24
+#define STAIRS         25
+#define LADDER         26
+#define FOUNTAIN       27
+#define THRONE         28
+#define SINK           29
+#define GRAVE          30
+#define ALTAR          31
+#define ICE            32
+#define DRAWBRIDGE_DOWN 33
+#define AIR            34
+#define CLOUD          35
+
+#define MAX_TYPE       36
+#define INVALID_TYPE   127
+
+/*
+ * Avoid using the level types in inequalities:
+ * these types are subject to change.
+ * Instead, use one of the macros below.
+ */
+#define IS_WALL(typ)   ((typ) && (typ) <= DBWALL)
+#define IS_STWALL(typ) ((typ) <= DBWALL)       /* STONE <= (typ) <= DBWALL */
+#define IS_ROCK(typ)   ((typ) < POOL)          /* absolutely nonaccessible */
+#define IS_DOOR(typ)   ((typ) == DOOR)
+#define IS_TREE(typ)   ((typ) == TREE || \
+                       (level.flags.arboreal && (typ) == STONE))
+#define ACCESSIBLE(typ) ((typ) >= DOOR)                /* good position */
+#define IS_ROOM(typ)   ((typ) >= ROOM)         /* ROOM, STAIRS, furniture.. */
+#define ZAP_POS(typ)   ((typ) >= POOL)
+#define SPACE_POS(typ) ((typ) > DOOR)
+#define IS_POOL(typ)   ((typ) >= POOL && (typ) <= DRAWBRIDGE_UP)
+#define IS_THRONE(typ) ((typ) == THRONE)
+#define IS_FOUNTAIN(typ) ((typ) == FOUNTAIN)
+#define IS_SINK(typ)   ((typ) == SINK)
+#define IS_GRAVE(typ)  ((typ) == GRAVE)
+#define IS_ALTAR(typ)  ((typ) == ALTAR)
+#define IS_DRAWBRIDGE(typ) ((typ) == DRAWBRIDGE_UP || (typ) == DRAWBRIDGE_DOWN)
+#define IS_FURNITURE(typ) ((typ) >= STAIRS && (typ) <= ALTAR)
+#define IS_AIR(typ)    ((typ) == AIR || (typ) == CLOUD)
+#define IS_SOFT(typ)   ((typ) == AIR || (typ) == CLOUD || IS_POOL(typ))
+
+/*
+ * The screen symbols may be the default or defined at game startup time.
+ * See drawing.c for defaults.
+ * Note: {ibm|dec}_graphics[] arrays (also in drawing.c) must be kept in synch.
+ */
+
+/* begin dungeon characters */
+
+#define S_stone                0
+#define S_vwall                1
+#define S_hwall                2
+#define S_tlcorn       3
+#define S_trcorn       4
+#define S_blcorn       5
+#define S_brcorn       6
+#define S_crwall       7
+#define S_tuwall       8
+#define S_tdwall       9
+#define S_tlwall       10
+#define S_trwall       11
+#define S_ndoor                12
+#define S_vodoor       13
+#define S_hodoor       14
+#define S_vcdoor       15      /* closed door, vertical wall */
+#define S_hcdoor       16      /* closed door, horizontal wall */
+#define S_bars         17      /* KMH -- iron bars */
+#define S_tree         18      /* KMH */
+#define S_room         19
+#define S_corr         20
+#define S_litcorr      21
+#define S_upstair      22
+#define S_dnstair      23
+#define S_upladder     24
+#define S_dnladder     25
+#define S_altar                26
+#define S_grave                27
+#define S_throne       28
+#define S_sink         29
+#define S_fountain     30
+#define S_pool         31
+#define S_ice          32
+#define S_lava         33
+#define S_vodbridge    34
+#define S_hodbridge    35
+#define S_vcdbridge    36      /* closed drawbridge, vertical wall */
+#define S_hcdbridge    37      /* closed drawbridge, horizontal wall */
+#define S_air          38
+#define S_cloud                39
+#define S_water                40
+
+/* end dungeon characters, begin traps */
+
+#define S_arrow_trap           41
+#define S_dart_trap            42
+#define S_falling_rock_trap    43
+#define S_squeaky_board                44
+#define S_bear_trap            45
+#define S_land_mine            46
+#define S_rolling_boulder_trap 47
+#define S_sleeping_gas_trap    48
+#define S_rust_trap            49
+#define S_fire_trap            50
+#define S_pit                  51
+#define S_spiked_pit           52
+#define S_hole                 53
+#define S_trap_door            54
+#define S_teleportation_trap   55
+#define S_level_teleporter     56
+#define S_magic_portal         57
+#define S_web                  58
+#define S_statue_trap          59
+#define S_magic_trap           60
+#define S_anti_magic_trap      61
+#define S_polymorph_trap       62
+
+/* end traps, begin special effects */
+
+#define S_vbeam                63      /* The 4 zap beam symbols.  Do NOT separate. */
+#define S_hbeam                64      /* To change order or add, see function     */
+#define S_lslant       65      /* zapdir_to_glyph() in display.c.          */
+#define S_rslant       66
+#define S_digbeam      67      /* dig beam symbol */
+#define S_flashbeam    68      /* camera flash symbol */
+#define S_boomleft     69      /* thrown boomerang, open left, e.g ')'    */
+#define S_boomright    70      /* thrown boomerand, open right, e.g. '('  */
+#define S_ss1          71      /* 4 magic shield glyphs */
+#define S_ss2          72
+#define S_ss3          73
+#define S_ss4          74
+
+/* The 8 swallow symbols.  Do NOT separate.  To change order or add, see */
+/* the function swallow_to_glyph() in display.c.                        */
+#define S_sw_tl                75      /* swallow top left [1]                 */
+#define S_sw_tc                76      /* swallow top center [2]       Order:  */
+#define S_sw_tr                77      /* swallow top right [3]                */
+#define S_sw_ml                78      /* swallow middle left [4]      1 2 3   */
+#define S_sw_mr                79      /* swallow middle right [6]     4 5 6   */
+#define S_sw_bl                80      /* swallow bottom left [7]      7 8 9   */
+#define S_sw_bc                81      /* swallow bottom center [8]            */
+#define S_sw_br                82      /* swallow bottom right [9]             */
+
+#define S_explode1     83      /* explosion top left                   */
+#define S_explode2     84      /* explosion top center                 */
+#define S_explode3     85      /* explosion top right           Ex.    */
+#define S_explode4     86      /* explosion middle left                */
+#define S_explode5     87      /* explosion middle center       /-\    */
+#define S_explode6     88      /* explosion middle right        |@|    */
+#define S_explode7     89      /* explosion bottom left         \-/    */
+#define S_explode8     90      /* explosion bottom center              */
+#define S_explode9     91      /* explosion bottom right               */
+
+/* end effects */
+
+#define MAXPCHARS      92      /* maximum number of mapped characters */
+#define MAXDCHARS      41      /* maximum of mapped dungeon characters */
+#define MAXTCHARS      22      /* maximum of mapped trap characters */
+#define MAXECHARS      29      /* maximum of mapped effects characters */
+#define MAXEXPCHARS    9       /* number of explosion characters */
+
+struct symdef {
+    uchar sym;
+    const char *explanation;
+#ifdef TEXTCOLOR
+    uchar color;
+#endif
+};
+
+extern const struct symdef defsyms[MAXPCHARS]; /* defaults */
+extern uchar showsyms[MAXPCHARS];
+extern const struct symdef def_warnsyms[WARNCOUNT];
+
+/*
+ * Graphics sets for display symbols
+ */
+#define ASCII_GRAPHICS 0       /* regular characters: '-', '+', &c */
+#define IBM_GRAPHICS   1       /* PC graphic characters */
+#define DEC_GRAPHICS   2       /* VT100 line drawing characters */
+#define MAC_GRAPHICS   3       /* Macintosh drawing characters */
+
+/*
+ * The 5 possible states of doors
+ */
+
+#define D_NODOOR       0
+#define D_BROKEN       1
+#define D_ISOPEN       2
+#define D_CLOSED       4
+#define D_LOCKED       8
+#define D_TRAPPED      16
+
+/*
+ * Some altars are considered as shrines, so we need a flag.
+ */
+#define AM_SHRINE      8
+
+/*
+ * Thrones should only be looted once.
+ */
+#define T_LOOTED       1
+
+/*
+ * Trees have more than one kick result.
+ */
+#define TREE_LOOTED    1
+#define TREE_SWARM     2
+
+/*
+ * Fountains have limits, and special warnings.
+ */
+#define F_LOOTED       1
+#define F_WARNED       2
+#define FOUNTAIN_IS_WARNED(x,y)                (levl[x][y].looted & F_WARNED)
+#define FOUNTAIN_IS_LOOTED(x,y)                (levl[x][y].looted & F_LOOTED)
+#define SET_FOUNTAIN_WARNED(x,y)       levl[x][y].looted |= F_WARNED;
+#define SET_FOUNTAIN_LOOTED(x,y)       levl[x][y].looted |= F_LOOTED;
+#define CLEAR_FOUNTAIN_WARNED(x,y)     levl[x][y].looted &= ~F_WARNED;
+#define CLEAR_FOUNTAIN_LOOTED(x,y)     levl[x][y].looted &= ~F_LOOTED;
+
+/*
+ * Doors are even worse :-) The special warning has a side effect
+ * of instantly trapping the door, and if it was defined as trapped,
+ * the guards consider that you have already been warned!
+ */
+#define D_WARNED       16
+
+/*
+ * Sinks have 3 different types of loot that shouldn't be abused
+ */
+#define S_LPUDDING     1
+#define S_LDWASHER     2
+#define S_LRING                4
+
+/*
+ * The four directions for a DrawBridge.
+ */
+#define DB_NORTH       0
+#define DB_SOUTH       1
+#define DB_EAST                2
+#define DB_WEST                3
+#define DB_DIR         3       /* mask for direction */
+
+/*
+ * What's under a drawbridge.
+ */
+#define DB_MOAT                0
+#define DB_LAVA                4
+#define DB_ICE         8
+#define DB_FLOOR       16
+#define DB_UNDER       28      /* mask for underneath */
+
+/*
+ * Wall information.
+ */
+#define WM_MASK                0x07    /* wall mode (bottom three bits) */
+#define W_NONDIGGABLE  0x08
+#define W_NONPASSWALL  0x10
+
+/*
+ * Ladders (in Vlad's tower) may be up or down.
+ */
+#define LA_UP          1
+#define LA_DOWN                2
+
+/*
+ * Room areas may be iced pools
+ */
+#define ICED_POOL      8
+#define ICED_MOAT      16
+
+/*
+ * The structure describing a coordinate position.
+ * Before adding fields, remember that this will significantly affect
+ * the size of temporary files and save files.
+ */
+struct rm {
+       int glyph;              /* what the hero thinks is there */
+       schar typ;              /* what is really there */
+       uchar seenv;            /* seen vector */
+       Bitfield(flags,5);      /* extra information for typ */
+       Bitfield(horizontal,1); /* wall/door/etc is horiz. (more typ info) */
+       Bitfield(lit,1);        /* speed hack for lit rooms */
+       Bitfield(waslit,1);     /* remember if a location was lit */
+       Bitfield(roomno,6);     /* room # for special rooms */
+       Bitfield(edge,1);       /* marks boundaries for special rooms*/
+};
+
+/*
+ * Add wall angle viewing by defining "modes" for each wall type.  Each
+ * mode describes which parts of a wall are finished (seen as as wall)
+ * and which are unfinished (seen as rock).
+ *
+ * We use the bottom 3 bits of the flags field for the mode.  This comes
+ * in conflict with secret doors, but we avoid problems because until
+ * a secret door becomes discovered, we know what sdoor's bottom three
+ * bits are.
+ *
+ * The following should cover all of the cases.
+ *
+ *     type    mode                            Examples: R=rock, F=finished
+ *     -----   ----                            ----------------------------
+ *     WALL:   0 none                          hwall, mode 1
+ *             1 left/top (1/2 rock)                   RRR
+ *             2 right/bottom (1/2 rock)               ---
+ *                                                     FFF
+ *
+ *     CORNER: 0 none                          trcorn, mode 2
+ *             1 outer (3/4 rock)                      FFF
+ *             2 inner (1/4 rock)                      F+-
+ *                                                     F|R
+ *
+ *     TWALL:  0 none                          tlwall, mode 3
+ *             1 long edge (1/2 rock)                  F|F
+ *             2 bottom left (on a tdwall)             -+F
+ *             3 bottom right (on a tdwall)            R|F
+ *
+ *     CRWALL: 0 none                          crwall, mode 5
+ *             1 top left (1/4 rock)                   R|F
+ *             2 top right (1/4 rock)                  -+-
+ *             3 bottom left (1/4 rock)                F|R
+ *             4 bottom right (1/4 rock)
+ *             5 top left & bottom right (1/2 rock)
+ *             6 bottom left & top right (1/2 rock)
+ */
+
+#define WM_W_LEFT 1                    /* vertical or horizontal wall */
+#define WM_W_RIGHT 2
+#define WM_W_TOP WM_W_LEFT
+#define WM_W_BOTTOM WM_W_RIGHT
+
+#define WM_C_OUTER 1                   /* corner wall */
+#define WM_C_INNER 2
+
+#define WM_T_LONG 1                    /* T wall */
+#define WM_T_BL   2
+#define WM_T_BR   3
+
+#define WM_X_TL   1                    /* cross wall */
+#define WM_X_TR   2
+#define WM_X_BL   3
+#define WM_X_BR   4
+#define WM_X_TLBR 5
+#define WM_X_BLTR 6
+
+/*
+ * Seen vector values. The seen vector is an array of 8 bits, one for each
+ * octant around a given center x:
+ *
+ *                     0 1 2
+ *                     7 x 3
+ *                     6 5 4
+ *
+ * In the case of walls, a single wall square can be viewed from 8 possible
+ * directions. If we know the type of wall and the directions from which
+ * it has been seen, then we can determine what it looks like to the hero.
+ */
+#define SV0 0x1
+#define SV1 0x2
+#define SV2 0x4
+#define SV3 0x8
+#define SV4 0x10
+#define SV5 0x20
+#define SV6 0x40
+#define SV7 0x80
+#define SVALL 0xFF
+
+
+
+#define doormask       flags
+#define altarmask      flags
+#define wall_info      flags
+#define ladder         flags
+#define drawbridgemask flags
+#define looted         flags
+#define icedpool       flags
+
+#define blessedftn     horizontal  /* a fountain that grants attribs */
+#define disturbed      horizontal  /* a grave that has been disturbed */
+
+struct damage {
+       struct damage *next;
+       long when, cost;
+       coord place;
+       schar typ;
+};
+
+struct levelflags {
+       uchar   nfountains;             /* number of fountains on level */
+       uchar   nsinks;                 /* number of sinks on the level */
+       /* Several flags that give hints about what's on the level */
+       Bitfield(has_shop, 1);
+       Bitfield(has_vault, 1);
+       Bitfield(has_zoo, 1);
+       Bitfield(has_court, 1);
+       Bitfield(has_morgue, 1);
+       Bitfield(has_beehive, 1);
+       Bitfield(has_barracks, 1);
+       Bitfield(has_temple, 1);
+
+       Bitfield(has_swamp, 1);
+       Bitfield(noteleport,1);
+       Bitfield(hardfloor,1);
+       Bitfield(nommap,1);
+       Bitfield(hero_memory,1);        /* hero has memory */
+       Bitfield(shortsighted,1);       /* monsters are shortsighted */
+       Bitfield(graveyard,1);          /* has_morgue, but remains set */
+       Bitfield(is_maze_lev,1);
+
+       Bitfield(is_cavernous_lev,1);
+       Bitfield(arboreal, 1);          /* Trees replace rock */
+};
+
+typedef struct
+{
+    struct rm          locations[COLNO][ROWNO];
+#ifndef MICROPORT_BUG
+    struct obj         *objects[COLNO][ROWNO];
+    struct monst       *monsters[COLNO][ROWNO];
+#else
+    struct obj         *objects[1][ROWNO];
+    char               *yuk1[COLNO-1][ROWNO];
+    struct monst       *monsters[1][ROWNO];
+    char               *yuk2[COLNO-1][ROWNO];
+#endif
+    struct obj         *objlist;
+    struct obj         *buriedobjlist;
+    struct monst       *monlist;
+    struct damage      *damagelist;
+    struct levelflags  flags;
+}
+dlevel_t;
+
+extern dlevel_t level; /* structure describing the current level */
+
+/*
+ * Macros for compatibility with old code. Someday these will go away.
+ */
+#define levl           level.locations
+#define fobj           level.objlist
+#define fmon           level.monlist
+
+/*
+ * Covert a trap number into the defsym graphics array.
+ * Convert a defsym number into a trap number.
+ * Assumes that arrow trap will always be the first trap.
+ */
+#define trap_to_defsym(t) (S_arrow_trap+(t)-1)
+#define defsym_to_trap(d) ((d)-S_arrow_trap+1)
+
+#define OBJ_AT(x,y)    (level.objects[x][y] != (struct obj *)0)
+/*
+ * Macros for encapsulation of level.monsters references.
+ */
+#define MON_AT(x,y)    (level.monsters[x][y] != (struct monst *)0 && \
+                        !(level.monsters[x][y])->mburied)
+#define MON_BURIED_AT(x,y)     (level.monsters[x][y] != (struct monst *)0 && \
+                               (level.monsters[x][y])->mburied)
+#ifndef STEED
+#define place_monster(m,x,y)   ((m)->mx=(x),(m)->my=(y),\
+                                level.monsters[(m)->mx][(m)->my]=(m))
+#endif
+#define place_worm_seg(m,x,y)  level.monsters[x][y] = m
+#define remove_monster(x,y)    level.monsters[x][y] = (struct monst *)0
+#define m_at(x,y)              (MON_AT(x,y) ? level.monsters[x][y] : \
+                                               (struct monst *)0)
+#define m_buried_at(x,y)       (MON_BURIED_AT(x,y) ? level.monsters[x][y] : \
+                                                      (struct monst *)0)
+
+#endif /* RM_H */
diff --git a/include/skills.h b/include/skills.h
new file mode 100644 (file)
index 0000000..09bc3be
--- /dev/null
@@ -0,0 +1,121 @@
+/*     SCCS Id: @(#)skills.h   3.4     1999/10/27      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985-1999. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef SKILLS_H
+#define SKILLS_H
+
+/* Much of this code was taken from you.h.  It is now
+ * in a separate file so it can be included in objects.c.
+ */
+
+
+/* Code to denote that no skill is applicable */
+#define P_NONE                         0
+
+/* Weapon Skills -- Stephen White
+ * Order matters and are used in macros.
+ * Positive values denote hand-to-hand weapons or launchers.
+ * Negative values denote ammunition or missiles.
+ * Update weapon.c if you ammend any skills.
+ * Also used for oc_subtyp.
+ */
+#define P_DAGGER             1
+#define P_KNIFE              2
+#define P_AXE                3
+#define P_PICK_AXE           4
+#define P_SHORT_SWORD        5
+#define P_BROAD_SWORD        6
+#define P_LONG_SWORD         7
+#define P_TWO_HANDED_SWORD   8
+#define P_SCIMITAR           9
+#define P_SABER             10
+#define P_CLUB              11 /* Heavy-shafted bludgeon */
+#define P_MACE              12 
+#define P_MORNING_STAR      13 /* Spiked bludgeon */
+#define P_FLAIL             14 /* Two pieces hinged or chained together */
+#define P_HAMMER            15 /* Heavy head on the end */
+#define P_QUARTERSTAFF      16 /* Long-shafted bludgeon */
+#define P_POLEARMS          17
+#define P_SPEAR             18
+#define P_JAVELIN           19
+#define P_TRIDENT           20
+#define P_LANCE             21
+#define P_BOW               22
+#define P_SLING             23
+#define P_CROSSBOW          24
+#define P_DART              25
+#define P_SHURIKEN          26
+#define P_BOOMERANG         27
+#define P_WHIP              28
+#define P_UNICORN_HORN      29 /* last weapon */
+#define P_FIRST_WEAPON      P_DAGGER
+#define P_LAST_WEAPON       P_UNICORN_HORN
+
+/* Spell Skills added by Larry Stewart-Zerba */
+#define P_ATTACK_SPELL      30
+#define P_HEALING_SPELL     31
+#define P_DIVINATION_SPELL  32
+#define P_ENCHANTMENT_SPELL 33
+#define P_CLERIC_SPELL      34
+#define P_ESCAPE_SPELL      35
+#define P_MATTER_SPELL      36
+#define P_FIRST_SPELL          P_ATTACK_SPELL
+#define P_LAST_SPELL           P_MATTER_SPELL
+
+/* Other types of combat */
+#define P_BARE_HANDED_COMBAT   37
+#define P_MARTIAL_ARTS         P_BARE_HANDED_COMBAT    /* Role distinguishes */
+#define P_TWO_WEAPON_COMBAT    38      /* Finally implemented */
+#ifdef STEED
+#define P_RIDING               39      /* How well you control your steed */
+#define P_LAST_H_TO_H          P_RIDING
+#else
+#define P_LAST_H_TO_H          P_TWO_WEAPON_COMBAT
+#endif
+#define P_FIRST_H_TO_H         P_BARE_HANDED_COMBAT
+
+#define P_NUM_SKILLS           (P_LAST_H_TO_H+1)
+
+/* These roles qualify for a martial arts bonus */
+#define martial_bonus()        (Role_if(PM_SAMURAI) || Role_if(PM_MONK))
+
+
+/*
+ * These are the standard weapon skill levels.  It is important that
+ * the lowest "valid" skill be be 1.  The code calculates the
+ * previous amount to practice by calling  practice_needed_to_advance()
+ * with the current skill-1.  To work out for the UNSKILLED case,
+ * a value of 0 needed.
+ */
+#define P_ISRESTRICTED 0
+#define P_UNSKILLED            1
+#define P_BASIC                        2
+#define P_SKILLED              3
+#define P_EXPERT               4
+#define P_MASTER               5       /* Unarmed combat/martial arts only */
+#define P_GRAND_MASTER 6       /* Unarmed combat/martial arts only */
+
+#define practice_needed_to_advance(level) ((level)*(level)*20)
+
+/* The hero's skill in various weapons. */
+struct skills {
+       xchar skill;
+       xchar max_skill;
+       unsigned short advance;
+};
+
+#define P_SKILL(type)          (u.weapon_skills[type].skill)
+#define P_MAX_SKILL(type)      (u.weapon_skills[type].max_skill)
+#define P_ADVANCE(type)                (u.weapon_skills[type].advance)
+#define P_RESTRICTED(type)     (u.weapon_skills[type].skill == P_ISRESTRICTED)
+
+#define P_SKILL_LIMIT 60       /* Max number of skill advancements */
+
+/* Initial skill matrix structure; used in u_init.c and weapon.c */
+struct def_skill {
+       xchar skill;
+       xchar skmax;
+};
+
+#endif  /* SKILLS_H */
diff --git a/include/sp_lev.h b/include/sp_lev.h
new file mode 100644 (file)
index 0000000..f549f53
--- /dev/null
@@ -0,0 +1,246 @@
+/*     SCCS Id: @(#)sp_lev.h   3.4     1996/05/08      */
+/* Copyright (c) 1989 by Jean-Christophe Collet                          */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef SP_LEV_H
+#define SP_LEV_H
+
+    /* wall directions */
+#define W_NORTH                1
+#define W_SOUTH                2
+#define W_EAST         4
+#define W_WEST         8
+#define W_ANY          (W_NORTH|W_SOUTH|W_EAST|W_WEST)
+
+    /* MAP limits */
+#define MAP_X_LIM      76
+#define MAP_Y_LIM      21
+
+    /* Per level flags */
+#define NOTELEPORT     1
+#define HARDFLOOR      2
+#define NOMMAP         4
+#define SHORTSIGHTED   8
+#define ARBOREAL       16
+
+    /* special level types */
+#define SP_LEV_ROOMS   1
+#define SP_LEV_MAZE    2
+
+/*
+ * Structures manipulated by the special levels loader & compiler
+ */
+
+typedef union str_or_len {
+       char *str;
+       int   len;
+} Str_or_Len;
+
+typedef struct {
+       boolean init_present, padding;
+       char    fg, bg;
+       boolean smoothed, joined;
+       xchar   lit, walled;
+} lev_init;
+
+typedef struct {
+       xchar x, y, mask;
+} door;
+
+typedef struct {
+       xchar wall, pos, secret, mask;
+} room_door;
+
+typedef struct {
+       xchar x, y, chance, type;
+} trap;
+
+typedef struct {
+       Str_or_Len name, appear_as;
+       short id;
+       aligntyp align;
+       xchar x, y, chance, class, appear;
+       schar peaceful, asleep;
+} monster;
+
+typedef struct {
+       Str_or_Len name;
+       int   corpsenm;
+       short id, spe;
+       xchar x, y, chance, class, containment;
+       schar curse_state;
+} object;
+
+typedef struct {
+       xchar           x, y;
+       aligntyp        align;
+       xchar           shrine;
+} altar;
+
+typedef struct {
+       xchar x, y, dir, db_open;
+} drawbridge;
+
+typedef struct {
+       xchar x, y, dir;
+} walk;
+
+typedef struct {
+       xchar x1, y1, x2, y2;
+} digpos;
+
+typedef struct {
+       xchar x, y, up;
+} lad;
+
+typedef struct {
+       xchar x, y, up;
+} stair;
+
+typedef struct {
+       xchar x1, y1, x2, y2;
+       xchar rtype, rlit, rirreg;
+} region;
+
+/* values for rtype are defined in dungeon.h */
+typedef struct {
+       struct { xchar x1, y1, x2, y2; } inarea;
+       struct { xchar x1, y1, x2, y2; } delarea;
+       boolean in_islev, del_islev;
+       xchar rtype, padding;
+       Str_or_Len rname;
+} lev_region;
+
+typedef struct {
+       xchar x, y;
+       int   amount;
+} gold;
+
+typedef struct {
+       xchar x, y;
+       Str_or_Len engr;
+       xchar etype;
+} engraving;
+
+typedef struct {
+       xchar x, y;
+} fountain;
+
+typedef struct {
+       xchar x, y;
+} sink;
+
+typedef struct {
+       xchar x, y;
+} pool;
+
+typedef struct {
+       char halign, valign;
+       char xsize, ysize;
+       char **map;
+       char nrobjects;
+       char *robjects;
+       char nloc;
+       char *rloc_x;
+       char *rloc_y;
+       char nrmonst;
+       char *rmonst;
+       char nreg;
+       region **regions;
+       char nlreg;
+       lev_region **lregions;
+       char ndoor;
+       door **doors;
+       char ntrap;
+       trap **traps;
+       char nmonster;
+       monster **monsters;
+       char nobject;
+       object **objects;
+       char ndrawbridge;
+       drawbridge **drawbridges;
+       char nwalk;
+       walk **walks;
+       char ndig;
+       digpos **digs;
+       char npass;
+       digpos **passs;
+       char nlad;
+       lad **lads;
+       char nstair;
+       stair **stairs;
+       char naltar;
+       altar **altars;
+       char ngold;
+       gold **golds;
+       char nengraving;
+       engraving **engravings;
+       char nfountain;
+       fountain **fountains;
+} mazepart;
+
+typedef struct {
+       long flags;
+       lev_init init_lev;
+       schar filling;
+       char numpart;
+       mazepart **parts;
+} specialmaze;
+
+typedef struct _room {
+       char  *name;
+       char  *parent;
+       xchar x, y, w, h;
+       xchar xalign, yalign;
+       xchar rtype, chance, rlit, filled;
+       char ndoor;
+       room_door **doors;
+       char ntrap;
+       trap **traps;
+       char nmonster;
+       monster **monsters;
+       char nobject;
+       object **objects;
+       char naltar;
+       altar **altars;
+       char nstair;
+       stair **stairs;
+       char ngold;
+       gold **golds;
+       char nengraving;
+       engraving **engravings;
+       char nfountain;
+       fountain **fountains;
+       char nsink;
+       sink **sinks;
+       char npool;
+       pool **pools;
+       /* These three fields are only used when loading the level... */
+       int nsubroom;
+       struct _room *subrooms[MAX_SUBROOMS];
+       struct mkroom *mkr;
+} room;
+
+typedef struct {
+       struct {
+               xchar room;
+               xchar wall;
+               xchar door;
+       } src, dest;
+} corridor;
+
+/* used only by lev_comp */
+typedef struct {
+       long flags;
+       lev_init init_lev;
+       char nrobjects;
+       char *robjects;
+       char nrmonst;
+       char *rmonst;
+       xchar nroom;
+       room **rooms;
+       xchar ncorr;
+       corridor **corrs;
+} splev;
+
+#endif /* SP_LEV_H */
diff --git a/include/spell.h b/include/spell.h
new file mode 100644 (file)
index 0000000..6b43e21
--- /dev/null
@@ -0,0 +1,22 @@
+/*     SCCS Id: @(#)spell.h    3.4     1995/06/01      */
+/* Copyright 1986, M. Stephenson                                 */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef SPELL_H
+#define SPELL_H
+
+struct spell {
+    short      sp_id;                  /* spell id (== object.otyp) */
+    xchar      sp_lev;                 /* power level */
+    int                sp_know;                /* knowlege of spell */
+};
+
+/* levels of memory destruction with a scroll of amnesia */
+#define ALL_MAP                0x1
+#define ALL_SPELLS     0x2
+
+#define decrnknow(spell)       spl_book[spell].sp_know--
+#define spellid(spell)         spl_book[spell].sp_id
+#define spellknow(spell)       spl_book[spell].sp_know
+
+#endif /* SPELL_H */
diff --git a/include/system.h b/include/system.h
new file mode 100644 (file)
index 0000000..a4efff9
--- /dev/null
@@ -0,0 +1,551 @@
+/*     SCCS Id: @(#)system.h   3.4     2001/12/07      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef SYSTEM_H
+#define SYSTEM_H
+
+#if !defined(__cplusplus) && !defined(__GO32__)
+
+#define E extern
+
+/* some old <sys/types.h> may not define off_t and size_t; if your system is
+ * one of these, define them by hand below
+ */
+#if (defined(VMS) && !defined(__GNUC__)) || defined(MAC)
+#include <types.h>
+#else
+# ifndef AMIGA
+#include <sys/types.h>
+# endif
+#endif
+
+#if (defined(MICRO) && !defined(TOS)) || defined(ANCIENT_VAXC)
+# if !defined(_SIZE_T) && !defined(__size_t) /* __size_t for CSet/2 */
+#  define _SIZE_T
+#  if !((defined(MSDOS) || defined(OS2)) && defined(_SIZE_T_DEFINED)) /* MSC 5.1 */
+#   if !(defined(__GNUC__) && defined(AMIGA))
+typedef unsigned int   size_t;
+#   endif
+#  endif
+# endif
+#endif /* MICRO && !TOS */
+
+#if defined(__TURBOC__) || defined(MAC)
+#include <time.h>      /* time_t is not in <sys/types.h> */
+#endif
+#if defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))
+/* The Ultrix v3.0 <sys/types.h> seems to be very wrong. */
+# define time_t long
+#endif
+
+#if defined(ULTRIX) || defined(VMS)
+# define off_t long
+#endif
+#if defined(AZTEC) || defined(THINKC4) || defined(__TURBOC__)
+typedef long   off_t;
+#endif
+
+#endif /* !__cplusplus && !__GO32__ */
+
+/* You may want to change this to fit your system, as this is almost
+ * impossible to get right automatically.
+ * This is the type of signal handling functions.
+ */
+#if !defined(OS2) && (defined(_MSC_VER) || defined(__TURBOC__) || defined(__SC__) || defined(WIN32))
+# define SIG_RET_TYPE void (__cdecl *)(int)
+#endif
+#ifndef SIG_RET_TYPE
+# if defined(NHSTDC) || defined(POSIX_TYPES) || defined(OS2) || defined(__DECC)
+#  define SIG_RET_TYPE void (*)()
+# endif
+#endif
+#ifndef SIG_RET_TYPE
+# if defined(ULTRIX) || defined(SUNOS4) || defined(SVR3) || defined(SVR4)
+       /* SVR3 is defined automatically by some systems */
+#  define SIG_RET_TYPE void (*)()
+# endif
+#endif
+#ifndef SIG_RET_TYPE   /* BSD, SIII, SVR2 and earlier, Sun3.5 and earlier */
+# define SIG_RET_TYPE int (*)()
+#endif
+
+#if !defined(__cplusplus) && !defined(__GO32__)
+
+#if defined(BSD) || defined(ULTRIX) || defined(RANDOM)
+# ifdef random
+# undef random
+# endif
+# if !defined(__SC__) && !defined(LINUX)
+E  long NDECL(random);
+# endif
+# if (!defined(SUNOS4) && !defined(bsdi) && !defined(__FreeBSD__)) || defined(RANDOM)
+E void FDECL(srandom, (unsigned int));
+# else
+#  if !defined(bsdi) && !defined(__FreeBSD__)
+E int FDECL(srandom, (unsigned int));
+#  endif
+# endif
+#else
+E long lrand48();
+E void srand48();
+#endif /* BSD || ULTRIX || RANDOM */
+
+#if !defined(BSD) || defined(ultrix)
+                       /* real BSD wants all these to return int */
+# ifndef MICRO
+E void FDECL(exit, (int));
+# endif /* MICRO */
+/* compensate for some CSet/2 bogosities */
+# if defined(OS2_CSET2) && defined(OS2_CSET2_VER_2)
+#  define open   _open
+#  define close   _close
+#  define read   _read
+#  define write   _write
+#  define lseek   _lseek
+#  define chdir   _chdir
+#  define getcwd  _getcwd
+#  define setmode _setmode
+# endif /* OS2_CSET2 && OS2_CSET2_VER_2 */
+/* If flex thinks that we're not __STDC__ it declares free() to return
+   int and we die.  We must use __STDC__ instead of NHSTDC because
+   the former is naturally what flex tests for. */
+# if defined(__STDC__) || !defined(FLEX_SCANNER)
+#  ifndef OS2_CSET2
+#   ifndef MONITOR_HEAP
+E void FDECL(free, (genericptr_t));
+#   endif
+#  endif
+# endif
+#if !defined(__SASC_60) && !defined(_DCC) && !defined(__SC__)
+# if defined(AMIGA) && !defined(AZTEC_50) && !defined(__GNUC__)
+E int FDECL(perror, (const char *));
+# else
+#  if !(defined(ULTRIX_PROTO) && defined(__GNUC__))
+E void FDECL(perror, (const char *));
+#  endif
+# endif
+#endif
+#endif
+#ifndef NeXT
+#ifdef POSIX_TYPES
+E void FDECL(qsort, (genericptr_t,size_t,size_t,
+                    int(*)(const genericptr,const genericptr)));
+#else
+# if defined(BSD) || defined(ULTRIX)
+E  int qsort();
+# else
+#  if !defined(LATTICE) && !defined(AZTEC_50)
+E   void FDECL(qsort, (genericptr_t,size_t,size_t,
+                      int(*)(const genericptr,const genericptr)));
+#  endif
+# endif
+#endif
+#endif /* NeXT */
+
+#ifndef __SASC_60
+#if !defined(AZTEC_50) && !defined(__GNUC__)
+/* may already be defined */
+
+# ifdef ULTRIX
+#  ifdef ULTRIX_PROTO
+E int FDECL(lseek, (int,off_t,int));
+#  else
+E long FDECL(lseek, (int,off_t,int));
+#  endif
+  /* Ultrix 3.0 man page mistakenly says it returns an int. */
+E int FDECL(write, (int,char *,int));
+E int FDECL(link, (const char *, const char*));
+# else
+# ifndef bsdi
+E long FDECL(lseek, (int,long,int));
+# endif
+#  if defined(POSIX_TYPES) || defined(__TURBOC__)
+#   ifndef bsdi
+E int FDECL(write, (int, const void *,unsigned));
+#   endif
+#  else
+#   ifndef __MWERKS__  /* metrowerks defines write via universal headers */
+E int FDECL(write, (int,genericptr_t,unsigned));
+#   endif
+#  endif
+# endif /* ULTRIX */
+
+# ifdef OS2_CSET2      /* IBM CSet/2 */
+#  ifdef OS2_CSET2_VER_1
+E int FDECL(unlink, (char *));
+#  else
+E int FDECL(unlink, (const char *)); /* prototype is ok in ver >= 2 */
+#  endif
+# else
+#  ifndef __SC__
+E int FDECL(unlink, (const char *));
+#  endif
+# endif
+
+#endif /* AZTEC_50 && __GNUC__ */
+
+#ifdef MAC
+#ifndef __CONDITIONALMACROS__  /* universal headers */
+E int FDECL(close, (int));             /* unistd.h */
+E int FDECL(read, (int, char *, int)); /* unistd.h */
+E int FDECL(chdir, (const char *));    /* unistd.h */
+E char *FDECL(getcwd, (char *,int));   /* unistd.h */
+#endif
+
+E int FDECL(open, (const char *,int));
+#endif
+
+#if defined(MICRO)
+E int FDECL(close, (int));
+#ifndef __EMX__
+E int FDECL(read, (int,genericptr_t,unsigned int));
+#endif
+E int FDECL(open, (const char *,int,...));
+E int FDECL(dup2, (int, int));
+E int FDECL(setmode, (int,int));
+E int NDECL(kbhit);
+# if !defined(_DCC)
+#  if defined(__TURBOC__)
+E int FDECL(chdir, (const char *));
+#  else
+#   ifndef __EMX__
+E int FDECL(chdir, (char *));
+#   endif
+#  endif
+#  ifndef __EMX__
+E char *FDECL(getcwd, (char *,int));
+#  endif
+# endif /* !_DCC */
+#endif
+
+#ifdef ULTRIX
+E int FDECL(close, (int));
+E int FDECL(atoi, (const char *));
+E int FDECL(chdir, (const char *));
+# if !defined(ULTRIX_CC20) && !defined(__GNUC__)
+E int FDECL(chmod, (const char *,int));
+E mode_t FDECL(umask, (int));
+# endif
+E int FDECL(read, (int,genericptr_t,unsigned));
+/* these aren't quite right, but this saves including lots of system files */
+E int FDECL(stty, (int,genericptr_t));
+E int FDECL(gtty, (int,genericptr_t));
+E int FDECL(ioctl, (int, int, char*));
+E int FDECL(isatty, (int));    /* 1==yes, 0==no, -1==error */
+#include <sys/file.h>
+# if defined(ULTRIX_PROTO) || defined(__GNUC__)
+E int NDECL(fork);
+# else
+E long NDECL(fork);
+# endif
+#endif /* ULTRIX */
+
+#ifdef VMS
+# ifndef abs
+E int FDECL(abs, (int));
+# endif
+E int FDECL(atexit, (void (*)(void)));
+E int FDECL(atoi, (const char *));
+E int FDECL(chdir, (const char *));
+E int FDECL(chown, (const char *,unsigned,unsigned));
+# ifdef __DECC_VER
+E int FDECL(chmod, (const char *,mode_t));
+E mode_t FDECL(umask, (mode_t));
+# else
+E int FDECL(chmod, (const char *,int));
+E int FDECL(umask, (int));
+# endif
+/* #include <unixio.h> */
+E int FDECL(close, (int));
+E int VDECL(creat, (const char *,unsigned,...));
+E int FDECL(delete, (const char *));
+E int FDECL(fstat, ( /*_ int, stat_t * _*/ ));
+E int FDECL(isatty, (int));    /* 1==yes, 0==no, -1==error */
+E long FDECL(lseek, (int,long,int));
+E int VDECL(open, (const char *,int,unsigned,...));
+E int FDECL(read, (int,genericptr_t,unsigned));
+E int FDECL(rename, (const char *,const char *));
+E int FDECL(stat, ( /*_ const char *,stat_t * _*/ ));
+E int FDECL(write, (int,const genericptr,unsigned));
+#endif
+
+#endif /* __SASC_60 */
+
+/* both old & new versions of Ultrix want these, but real BSD does not */
+#ifdef ultrix
+E void abort();
+E void bcopy();
+# ifdef ULTRIX
+E int FDECL(system, (const char *));
+#  ifndef _UNISTD_H_
+E int FDECL(execl, (const char *, ...));
+#  endif
+# endif
+#endif
+#ifdef MICRO
+E void NDECL(abort);
+E void FDECL(_exit, (int));
+E int FDECL(system, (const char *));
+#endif
+#if defined(HPUX) && !defined(_POSIX_SOURCE)
+E long NDECL(fork);
+#endif
+
+#ifdef POSIX_TYPES
+/* The POSIX string.h is required to define all the mem* and str* functions */
+#include <string.h>
+#else
+#if defined(SYSV) || defined(VMS) || defined(MAC) || defined(SUNOS4)
+# if defined(NHSTDC) || (defined(VMS) && !defined(ANCIENT_VAXC))
+#  if !defined(_AIX32) && !(defined(SUNOS4) && defined(__STDC__))
+                               /* Solaris unbundled cc (acc) */
+E int FDECL(memcmp, (const void *,const void *,size_t));
+E void *FDECL(memcpy, (void *, const void *, size_t));
+E void *FDECL(memset, (void *, int, size_t));
+#  endif
+# else
+#  ifndef memcmp       /* some systems seem to macro these back to b*() */
+E int memcmp();
+#  endif
+#  ifndef memcpy
+E char *memcpy();
+#  endif
+#  ifndef memset
+E char *memset();
+#  endif
+# endif
+#else
+# ifdef HPUX
+E int FDECL(memcmp, (char *,char *,int));
+E void *FDECL(memcpy, (char *,char *,int));
+E void *FDECL(memset, (char*,int,int));
+# endif
+#endif
+#endif /* POSIX_TYPES */
+
+#if defined(MICRO) && !defined(LATTICE)
+# if defined(TOS) && defined(__GNUC__)
+E int FDECL(memcmp, (const void *,const void *,size_t));
+E void *FDECL(memcpy, (void *,const void *,size_t));
+E void *FDECL(memset, (void *,int,size_t));
+# else
+#  if defined(AZTEC_50) || defined(NHSTDC) || defined(WIN32)
+E int  FDECL(memcmp, (const void *, const void *, size_t));
+E void *FDECL(memcpy, (void *, const void *, size_t));
+E void *FDECL(memset, (void *, int, size_t));
+#  else
+E int FDECL(memcmp, (char *,char *,unsigned int));
+E char *FDECL(memcpy, (char *,char *,unsigned int));
+E char *FDECL(memset, (char*,int,int));
+#  endif /* AZTEC_50 || NHSTDC */
+# endif /* TOS */
+#endif /* MICRO */
+
+#if defined(BSD) && defined(ultrix)    /* i.e., old versions of Ultrix */
+E void sleep();
+#endif
+#if defined(ULTRIX) || defined(SYSV)
+E unsigned sleep();
+#endif
+#if defined(HPUX)
+E unsigned int FDECL(sleep, (unsigned int));
+#endif
+#ifdef VMS
+E int FDECL(sleep, (unsigned));
+#endif
+
+E char *FDECL(getenv, (const char *));
+E char *getlogin();
+#if defined(HPUX) && !defined(_POSIX_SOURCE)
+E long NDECL(getuid);
+E long NDECL(getgid);
+E long NDECL(getpid);
+#else
+# ifdef POSIX_TYPES
+E pid_t NDECL(getpid);
+E uid_t NDECL(getuid);
+E gid_t NDECL(getgid);
+#  ifdef VMS
+E pid_t NDECL(getppid);
+#  endif
+# else /*!POSIX_TYPES*/
+#  ifndef getpid               /* Borland C defines getpid() as a macro */
+E int NDECL(getpid);
+#  endif
+#  ifdef VMS
+E int NDECL(getppid);
+E unsigned NDECL(getuid);
+E unsigned NDECL(getgid);
+#  endif
+#  if defined(ULTRIX) && !defined(_UNISTD_H_)
+E unsigned NDECL(getuid);
+E unsigned NDECL(getgid);
+E int FDECL(setgid, (int));
+E int FDECL(setuid, (int));
+#  endif
+# endif        /*?POSIX_TYPES*/
+#endif /*?(HPUX && !_POSIX_SOURCE)*/
+
+/* add more architectures as needed */
+#if defined(HPUX)
+#define seteuid(x) setreuid(-1, (x));
+#endif
+
+/*# string(s).h #*/
+#if !defined(_XtIntrinsic_h) && !defined(POSIX_TYPES)
+/* <X11/Intrinsic.h> #includes <string[s].h>; so does defining POSIX_TYPES */
+
+#if (defined(ULTRIX) || defined(NeXT)) && defined(__GNUC__)
+#include <strings.h>
+#else
+E char *FDECL(strcpy, (char *,const char *));
+E char *FDECL(strncpy, (char *,const char *,size_t));
+E char *FDECL(strcat, (char *,const char *));
+E char *FDECL(strncat, (char *,const char *,size_t));
+E char *FDECL(strpbrk, (const char *,const char *));
+
+# if defined(SYSV) || defined(MICRO) || defined(MAC) || defined(VMS) || defined(HPUX)
+E char *FDECL(strchr, (const char *,int));
+E char *FDECL(strrchr, (const char *,int));
+# else /* BSD */
+E char *FDECL(index, (const char *,int));
+E char *FDECL(rindex, (const char *,int));
+# endif
+
+E int  FDECL(strcmp, (const char *,const char *));
+E int  FDECL(strncmp, (const char *,const char *,size_t));
+# if defined(MICRO) || defined(MAC) || defined(VMS)
+E size_t FDECL(strlen, (const char *));
+# else
+# ifdef HPUX
+E unsigned int FDECL(strlen, (char *));
+#  else
+#   if !(defined(ULTRIX_PROTO) && defined(__GNUC__))
+E int  FDECL(strlen, (const char *));
+#   endif
+#  endif /* HPUX */
+# endif /* MICRO */
+#endif /* ULTRIX */
+
+#endif /* !_XtIntrinsic_h_ && !POSIX_TYPES */
+
+#if defined(ULTRIX) && defined(__GNUC__)
+E char *FDECL(index, (const char *,int));
+E char *FDECL(rindex, (const char *,int));
+#endif
+
+/* Old varieties of BSD have char *sprintf().
+ * Newer varieties of BSD have int sprintf() but allow for the old char *.
+ * Several varieties of SYSV and PC systems also have int sprintf().
+ * If your system doesn't agree with this breakdown, you may want to change
+ * this declaration, especially if your machine treats the types differently.
+ * If your system defines sprintf, et al, in stdio.h, add to the initial
+ * #if.
+ */
+#if defined(ULTRIX) || defined(__DECC) || defined(__SASC_60) || defined(WIN32)
+#define SPRINTF_PROTO
+#endif
+#if (defined(SUNOS4) && defined(__STDC__)) || defined(_AIX32)
+#define SPRINTF_PROTO
+#endif
+#if defined(TOS) || defined(AZTEC_50) || defined(__sgi) || defined(__GNUC__)
+       /* problem with prototype mismatches */
+#define SPRINTF_PROTO
+#endif
+#if defined(__MWERKS__) || defined(__SC__)
+       /* Metrowerks already has a prototype for sprintf() */
+# define SPRINTF_PROTO
+#endif
+
+#ifndef SPRINTF_PROTO
+# if defined(POSIX_TYPES) || defined(DGUX) || defined(NeXT) || !defined(BSD)
+E  int FDECL(sprintf, (char *,const char *,...));
+# else
+#  define OLD_SPRINTF
+E  char *sprintf();
+# endif
+#endif
+#ifdef SPRINTF_PROTO
+# undef SPRINTF_PROTO
+#endif
+
+#ifndef __SASC_60
+#ifdef NEED_VARARGS
+# if defined(USE_STDARG) || defined(USE_VARARGS)
+#  if !defined(SVR4) && !defined(apollo)
+#   if !(defined(ULTRIX_PROTO) && defined(__GNUC__))
+#    if !(defined(SUNOS4) && defined(__STDC__)) /* Solaris unbundled cc (acc) */
+E int FDECL(vsprintf, (char *, const char *, va_list));
+E int FDECL(vfprintf, (FILE *, const char *, va_list));
+E int FDECL(vprintf, (const char *, va_list));
+#    endif
+#   endif
+#  endif
+# else
+#  define vprintf      printf
+#  define vfprintf     fprintf
+#  define vsprintf     sprintf
+# endif
+#endif /* NEED_VARARGS */
+#endif
+
+
+#ifdef MICRO
+E int FDECL(tgetent, (const char *,const char *));
+E void FDECL(tputs, (const char *,int,int (*)()));
+E int FDECL(tgetnum, (const char *));
+E int FDECL(tgetflag, (const char *));
+E char *FDECL(tgetstr, (const char *,char **));
+E char *FDECL(tgoto, (const char *,int,int));
+#else
+# if ! (defined(HPUX) && defined(_POSIX_SOURCE))
+E int FDECL(tgetent, (char *,const char *));
+E void FDECL(tputs, (const char *,int,int (*)()));
+# endif
+E int FDECL(tgetnum, (const char *));
+E int FDECL(tgetflag, (const char *));
+E char *FDECL(tgetstr, (const char *,char **));
+E char *FDECL(tgoto, (const char *,int,int));
+#endif
+
+#ifdef ALLOC_C
+E genericptr_t FDECL(malloc, (size_t));
+#endif
+
+/* time functions */
+
+# ifndef LATTICE
+#  if !(defined(ULTRIX_PROTO) && defined(__GNUC__))
+E struct tm *FDECL(localtime, (const time_t *));
+#  endif
+# endif
+
+# if defined(ULTRIX) || (defined(BSD) && defined(POSIX_TYPES)) || defined(SYSV) || defined(MICRO) || defined(VMS) || defined(MAC) || (defined(HPUX) && defined(_POSIX_SOURCE))
+E time_t FDECL(time, (time_t *));
+# else
+E long FDECL(time, (time_t *));
+# endif /* ULTRIX */
+
+#ifdef VMS
+       /* used in makedefs.c, but missing from gcc-vms's <time.h> */
+E char *FDECL(ctime, (const time_t *));
+#endif
+
+
+#ifdef MICRO
+# ifdef abs
+# undef abs
+# endif
+E int FDECL(abs, (int));
+# ifdef atoi
+# undef atoi
+# endif
+E int FDECL(atoi, (const char *));
+#endif
+
+#undef E
+
+#endif /*  !__cplusplus && !__GO32__ */
+
+#endif /* SYSTEM_H */
diff --git a/include/tcap.h b/include/tcap.h
new file mode 100644 (file)
index 0000000..09cff27
--- /dev/null
@@ -0,0 +1,57 @@
+/*     SCCS Id: @(#)tcap.h     3.4     1992/10/21      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1989. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* not named termcap.h because it may conflict with a system header */
+
+#ifndef TCAP_H
+#define TCAP_H
+
+#ifndef MICRO
+# define TERMLIB       /* include termcap code */
+#endif
+
+/* might display need graphics code? */
+#if !defined(AMIGA) && !defined(TOS) && !defined(MAC)
+# if defined(TERMLIB) || defined(OS2) || defined(MSDOS)
+#  define ASCIIGRAPH
+# endif
+#endif
+
+#ifndef DECL_H
+extern struct tc_gbl_data {   /* also declared in decl.h; defined in decl.c */
+    char *tc_AS, *tc_AE;       /* graphics start and end (tty font swapping) */
+    int   tc_LI,  tc_CO;       /* lines and columns */
+} tc_gbl_data;
+#define AS tc_gbl_data.tc_AS
+#define AE tc_gbl_data.tc_AE
+#define LI tc_gbl_data.tc_LI
+#define CO tc_gbl_data.tc_CO
+#endif
+
+extern struct tc_lcl_data {   /* defined and set up in termcap.c */
+    char *tc_CM, *tc_ND, *tc_CD;
+    char *tc_HI, *tc_HE, *tc_US, *tc_UE;
+    boolean tc_ul_hack;
+} tc_lcl_data;
+/* some curses.h declare CM etc. */
+#define nh_CM tc_lcl_data.tc_CM
+#define nh_ND tc_lcl_data.tc_ND
+#define nh_CD tc_lcl_data.tc_CD
+#define nh_HI tc_lcl_data.tc_HI
+#define nh_HE tc_lcl_data.tc_HE
+#define nh_US tc_lcl_data.tc_US
+#define nh_UE tc_lcl_data.tc_UE
+#define ul_hack tc_lcl_data.tc_ul_hack
+
+extern short ospeed;           /* set up in termcap.c */
+
+#ifdef TEXTCOLOR
+# ifdef TOS
+extern const char *hilites[CLR_MAX];
+# else
+extern NEARDATA char *hilites[CLR_MAX];
+# endif
+#endif
+
+#endif /* TCAP_H */
diff --git a/include/tile2x11.h b/include/tile2x11.h
new file mode 100644 (file)
index 0000000..3f16285
--- /dev/null
@@ -0,0 +1,22 @@
+/*     SCCS Id: @(#)tile2x11.h 3.4     1995/01/25      */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef TILE2X11_H
+#define TILE2X11_H
+
+/*
+ * Header for the x11 tile map.
+ */
+typedef struct {
+    unsigned long version;
+    unsigned long ncolors;
+    unsigned long tile_width;
+    unsigned long tile_height;
+    unsigned long ntiles;
+    unsigned long per_row;
+} x11_header;
+
+/* how wide each row in the tile file is, in tiles */
+#define TILES_PER_ROW (40)
+
+#endif /* TILE2X11_H */
diff --git a/include/timeout.h b/include/timeout.h
new file mode 100644 (file)
index 0000000..481bf95
--- /dev/null
@@ -0,0 +1,44 @@
+/*     SCCS Id: @(#)timeout.h  3.4     1999/02/13      */
+/* Copyright 1994, Dean Luick                                    */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef TIMEOUT_H
+#define TIMEOUT_H
+
+/* generic timeout function */
+typedef void FDECL((*timeout_proc), (genericptr_t, long));
+
+/* kind of timer */
+#define TIMER_LEVEL    0       /* event specific to level */
+#define TIMER_GLOBAL   1       /* event follows current play */
+#define TIMER_OBJECT   2       /* event follows a object */
+#define TIMER_MONSTER  3       /* event follows a monster */
+
+/* save/restore timer ranges */
+#define RANGE_LEVEL  0         /* save/restore timers staying on level */
+#define RANGE_GLOBAL 1         /* save/restore timers following global play */
+
+/*
+ * Timeout functions.  Add a define here, then put it in the table
+ * in timeout.c.  "One more level of indirection will fix everything."
+ */
+#define ROT_ORGANIC    0       /* for buried organics */
+#define ROT_CORPSE     1
+#define REVIVE_MON     2
+#define BURN_OBJECT    3
+#define HATCH_EGG      4
+#define FIG_TRANSFORM  5
+#define NUM_TIME_FUNCS 6
+
+/* used in timeout.c */
+typedef struct fe {
+    struct fe *next;           /* next item in chain */
+    long timeout;              /* when we time out */
+    unsigned long tid;         /* timer ID */
+    short kind;                        /* kind of use */
+    short func_index;          /* what to call when we time out */
+    genericptr_t arg;          /* pointer to timeout argument */
+    Bitfield (needs_fixup,1);  /* does arg need to be patched? */
+} timer_element;
+
+#endif /* TIMEOUT_H */
diff --git a/include/tosconf.h b/include/tosconf.h
new file mode 100644 (file)
index 0000000..090195c
--- /dev/null
@@ -0,0 +1,86 @@
+/*     SCCS Id: @(#)tosconf.h  3.2     90/02/22        */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifdef TOS
+#ifndef TOSCONF_H
+#define TOSCONF_H
+
+#define MICRO          /* must be defined to allow some inclusions */
+
+/*
+   Adjust these options to suit your compiler. The default here is for
+   GNU C with the MiNT library.
+*/
+
+/*#define NO_SIGNAL            /* library doesn't support signals      */
+/*#define NO_FSTAT             /* library doesn't have fstat() call    */
+#define MINT                   /* library supports MiNT extensions to TOS */
+
+#ifdef __MINT__
+#define MINT
+#endif
+
+#ifdef O_BINARY
+#define FCMASK O_BINARY
+#else
+#define FCMASK 0660
+#define O_BINARY 0
+#endif
+
+#ifdef UNIXDEBUG
+#define remove(x)      unlink(x)
+#endif
+
+/* configurable options */
+#define MFLOPPY                        /* floppy support               */
+#define RANDOM                 /* improved random numbers      */
+#define SHELL                  /* allow spawning of shell      */
+#define TERMLIB                        /* use termcap                  */
+#define TEXTCOLOR              /* allow color                  */
+#define MAIL                   /* enable the fake maildemon */
+#ifdef MINT
+#define SUSPEND                        /* allow suspending the game    */
+#endif
+
+#ifndef TERMLIB
+#define ANSI_DEFAULT           /* use vt52 by default          */
+#endif
+
+#if defined(__GNUC__) || defined(__MINT__)
+/* actually, only more recent GNU C libraries have strcmpi
+ * on the other hand, they're free -- if yours is out of
+ * date, grab the most recent from atari.archive.umich.edu
+ */
+#define STRNCMPI
+#undef strcmpi
+extern int FDECL(strcmpi,(const char *, const char *));
+extern int FDECL(strncmpi,(const char *, const char *, size_t));
+#endif
+
+#include <termcap.h>
+#include <unistd.h>
+/* instead of including system.h from pcconf.h */
+#include <string.h>
+#include <stdlib.h>
+#include <types.h>
+#define SIG_RET_TYPE __Sigfunc
+#define SYSTEM_H
+
+#ifndef MICRO_H
+#include "micro.h"
+#endif
+#ifndef PCCONF_H
+#include "pcconf.h"            /* remainder of stuff is same as the PC */
+#endif
+
+#ifdef TEXTCOLOR
+extern boolean colors_changed; /* in tos.c */
+#endif
+
+#ifdef __GNUC__
+#define GCC_BUG                /* correct a gcc bug involving double for loops */
+#endif
+
+#endif /* TOSCONF_H */
+#endif /* TOS */
diff --git a/include/tradstdc.h b/include/tradstdc.h
new file mode 100644 (file)
index 0000000..0c6076a
--- /dev/null
@@ -0,0 +1,273 @@
+/*     SCCS Id: @(#)tradstdc.h 3.4     1993/05/30      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef TRADSTDC_H
+#define TRADSTDC_H
+
+#if defined(DUMB) && !defined(NOVOID)
+#define NOVOID
+#endif
+
+#ifdef NOVOID
+#define void int
+#endif
+
+/*
+ * Borland C provides enough ANSI C compatibility in its Borland C++
+ * mode to warrant this.  But it does not set __STDC__ unless it compiles
+ * in its ANSI keywords only mode, which prevents use of <dos.h> and
+ * far pointer use.
+ */
+#if (defined(__STDC__) || defined(__TURBOC__)) && !defined(NOTSTDC)
+#define NHSTDC
+#endif
+
+#if defined(ultrix) && defined(__STDC__) && !defined(__LANGUAGE_C)
+/* Ultrix seems to be in a constant state of flux.  This check attempts to
+ * set up ansi compatibility if it wasn't set up correctly by the compiler.
+ */
+#ifdef mips
+#define __mips mips
+#endif
+
+#ifdef LANGUAGE_C
+#define __LANGUAGE_C LANGUAGE_C
+#endif
+
+#endif
+
+/*
+ * ANSI X3J11 detection.
+ * Makes substitutes for compatibility with the old C standard.
+ */
+
+/* Decide how to handle variable parameter lists:
+ * USE_STDARG means use the ANSI <stdarg.h> facilities (only ANSI compilers
+ * should do this, and only if the library supports it).
+ * USE_VARARGS means use the <varargs.h> facilities.  Again, this should only
+ * be done if the library supports it. ANSI is *not* required for this.
+ * Otherwise, the kludgy old methods are used.
+ * The defaults are USE_STDARG for ANSI compilers, and USE_OLDARGS for
+ * others.
+ */
+
+/* #define USE_VARARGS */      /* use <varargs.h> instead of <stdarg.h> */
+/* #define USE_OLDARGS */      /* don't use any variable argument facilites */
+
+#if defined(apollo)            /* Apollos have stdarg(3) but not stdarg.h */
+# define USE_VARARGS
+#endif
+
+#if defined(NHSTDC) || defined(ULTRIX_PROTO) || defined(MAC)
+# if !defined(USE_VARARGS) && !defined(USE_OLDARGS) && !defined(USE_STDARG)
+#   define USE_STDARG
+# endif
+#endif
+
+#ifdef NEED_VARARGS            /* only define these if necessary */
+#ifdef USE_STDARG
+#include <stdarg.h>
+# define VA_DECL(typ1,var1)    (typ1 var1, ...) { va_list the_args;
+# define VA_DECL2(typ1,var1,typ2,var2) \
+       (typ1 var1, typ2 var2, ...) { va_list the_args;
+# define VA_INIT(var1,typ1)
+# define VA_NEXT(var1,typ1)    var1 = va_arg(the_args, typ1)
+# define VA_ARGS               the_args
+# define VA_START(x)           va_start(the_args, x)
+# define VA_END()              va_end(the_args)
+# if defined(ULTRIX_PROTO) && !defined(_VA_LIST_)
+#  define _VA_LIST_    /* prevents multiple def in stdio.h */
+# endif
+#else
+# ifdef USE_VARARGS
+#include <varargs.h>
+#  define VA_DECL(typ1,var1)   (va_alist) va_dcl {\
+               va_list the_args; typ1 var1;
+#  define VA_DECL2(typ1,var1,typ2,var2) (va_alist) va_dcl {\
+               va_list the_args; typ1 var1; typ2 var2;
+#  define VA_ARGS              the_args
+#  define VA_START(x)          va_start(the_args)
+#  define VA_INIT(var1,typ1)   var1 = va_arg(the_args, typ1)
+#  define VA_NEXT(var1,typ1)   var1 = va_arg(the_args,typ1)
+#  define VA_END()             va_end(the_args)
+# else
+#   define VA_ARGS     arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9
+#   define VA_DECL(typ1,var1)  (var1,VA_ARGS) typ1 var1; \
+       char *arg1,*arg2,*arg3,*arg4,*arg5,*arg6,*arg7,*arg8,*arg9; {
+#   define VA_DECL2(typ1,var1,typ2,var2)  (var1,var2,VA_ARGS) \
+       typ1 var1; typ2 var2;\
+       char *arg1,*arg2,*arg3,*arg4,*arg5,*arg6,*arg7,*arg8,*arg9; {
+#   define VA_START(x)
+#   define VA_INIT(var1,typ1)
+#   define VA_END()
+# endif
+#endif
+#endif /* NEED_VARARGS */
+
+#if defined(NHSTDC) || defined(MSDOS) || defined(MAC) || defined(ULTRIX_PROTO) || defined(__BEOS__)
+
+/*
+ * Used for robust ANSI parameter forward declarations:
+ * int VDECL(sprintf, (char *, const char *, ...));
+ *
+ * NDECL() is used for functions with zero arguments;
+ * FDECL() is used for functions with a fixed number of arguments;
+ * VDECL() is used for functions with a variable number of arguments.
+ * Separate macros are needed because ANSI will mix old-style declarations
+ * with prototypes, except in the case of varargs, and the OVERLAY-specific
+ * trampoli.* mechanism conflicts with the ANSI <<f(void)>> syntax.
+ */
+
+# define NDECL(f)      f(void) /* overridden later if USE_TRAMPOLI set */
+
+# define FDECL(f,p)    f p
+
+# if defined(MSDOS) || defined(USE_STDARG)
+#  define VDECL(f,p)   f p
+# else
+#  define VDECL(f,p)   f()
+# endif
+
+/* generic pointer, always a macro; genericptr_t is usually a typedef */
+# define genericptr    void *
+
+# if (defined(ULTRIX_PROTO) && !defined(__GNUC__)) || defined(OS2_CSET2)
+/* Cover for Ultrix on a DECstation with 2.0 compiler, which coredumps on
+ *   typedef void * genericptr_t;
+ *   extern void a(void(*)(int, genericptr_t));
+ * Using the #define is OK for other compiler versions too.
+ */
+/* And IBM CSet/2.  The redeclaration of free hoses the compile. */
+#  define genericptr_t genericptr
+# else
+#  if !defined(NHSTDC) && !defined(MAC)
+#   define const
+#   define signed
+#   define volatile
+#  endif
+# endif
+
+/*
+ * Suppress `const' if necessary and not handled elsewhere.
+ * Don't use `#if defined(xxx) && !defined(const)'
+ * because some compilers choke on `defined(const)'.
+ * This has been observed with Lattice, MPW, and High C.
+ */
+# if (defined(ULTRIX_PROTO) && !defined(NHSTDC)) || defined(apollo)
+       /* the system header files don't use `const' properly */
+#  ifndef const
+#   define const
+#  endif
+# endif
+
+#else /* NHSTDC */     /* a "traditional" C  compiler */
+
+# define NDECL(f)      f()
+# define FDECL(f,p)    f()
+# define VDECL(f,p)    f()
+
+# if defined(AMIGA) || defined(HPUX) || defined(POSIX_TYPES) || defined(__DECC) || defined(__BORLANDC__)
+#  define genericptr   void *
+# endif
+# ifndef genericptr
+#  define genericptr   char *
+# endif
+
+/*
+ * Traditional C compilers don't have "signed", "const", or "volatile".
+ */
+# define signed
+# define const
+# define volatile
+
+#endif /* NHSTDC */
+
+
+#ifndef genericptr_t
+typedef genericptr genericptr_t;       /* (void *) or (char *) */
+#endif
+
+
+/*
+ * According to ANSI, prototypes for old-style declarations must widen the
+ * arguments to int.  However, the MSDOS compilers accept shorter arguments
+ * (char, short, etc.) in prototypes and do typechecking with them.  Therefore
+ * this mess to allow the better typechecking while also allowing some
+ * prototypes for the ANSI compilers so people quit trying to fix the
+ * prototypes to match the standard and thus lose the typechecking.
+ */
+#if defined(MSDOS) && !defined(__GO32__)
+#define UNWIDENED_PROTOTYPES
+#endif
+#if defined(AMIGA) && !defined(AZTEC_50)
+#define UNWIDENED_PROTOTYPES
+#endif
+#if defined(macintosh) && (defined(__SC__) || defined(__MRC__))
+#define WIDENED_PROTOTYPES
+#endif
+#if defined(__MWERKS__) && defined(__BEOS__)
+#define UNWIDENED_PROTOTYPES
+#endif
+#if defined(WIN32)
+#define UNWIDENED_PROTOTYPES
+#endif
+
+#if defined(ULTRIX_PROTO) && defined(ULTRIX_CC20)
+#define UNWIDENED_PROTOTYPES
+#endif
+#if defined(apollo)
+#define UNWIDENED_PROTOTYPES
+#endif
+
+#ifndef UNWIDENED_PROTOTYPES
+# if defined(NHSTDC) || defined(ULTRIX_PROTO) || defined(THINK_C)
+# define WIDENED_PROTOTYPES
+# endif
+#endif
+
+#if 0
+/* The problem below is still the case through 4.0.5F, but the suggested
+ * compiler flags in the Makefiles suppress the nasty messages, so we don't
+ * need to be quite so drastic.
+ */
+#if defined(__sgi) && !defined(__GNUC__)
+/*
+ * As of IRIX 4.0.1, /bin/cc claims to be an ANSI compiler, but it thinks
+ * it's impossible for a prototype to match an old-style definition with
+ * unwidened argument types.  Thus, we have to turn off all NetHack
+ * prototypes, and avoid declaring several system functions, since the system
+ * include files have prototypes and the compiler also complains that
+ * prototyped and unprototyped declarations don't match.
+ */
+# undef NDECL
+# undef FDECL
+# undef VDECL
+# define NDECL(f)      f()
+# define FDECL(f,p)    f()
+# define VDECL(f,p)    f()
+#endif
+#endif
+
+
+       /* MetaWare High-C defaults to unsigned chars */
+       /* AIX 3.2 needs this also */
+#if defined(__HC__) || defined(_AIX32)
+# undef signed
+#endif
+
+
+/*
+ * Allow gcc2 to check parameters of printf-like calls with -Wformat;
+ * append this to a prototype declaration (see pline() in extern.h).
+ */
+#ifdef __GNUC__
+# if __GNUC__ >= 2
+#define PRINTF_F(f,v) __attribute__ ((format (printf, f, v)))
+# endif
+#endif
+#ifndef PRINTF_F
+#define PRINTF_F(f,v)
+#endif
+
+#endif /* TRADSTDC_H */
diff --git a/include/trampoli.h b/include/trampoli.h
new file mode 100644 (file)
index 0000000..fde5ab2
--- /dev/null
@@ -0,0 +1,332 @@
+/*     SCCS Id: @(#)trampoli.h 3.4     1995/06/01      */
+/* Copyright (c) 1989, by Norm Meluch and Stephen Spackman       */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef TRAMPOLI_H
+#define TRAMPOLI_H
+
+#ifdef USE_TRAMPOLI
+
+/* ### apply.c ### */
+#define dig()    dig_()
+#define doapply() doapply_()
+#define dojump()  dojump_()
+#define dorub()   dorub_()
+
+
+/* ### artifact.c ### */
+#define doinvoke()     doinvoke_()
+
+
+/* ### cmd.c ### */
+#define doextcmd()        doextcmd_()
+#define doextlist()       doextlist_()
+#define domonability()    domonability_()
+#define enter_explore_mode() enter_explore_mode_()
+#define doprev_message() doprev_message_()
+#define timed_occupation() timed_occupation_()
+#define wiz_attributes()   wiz_attributes_()
+#ifdef WIZARD
+#define wiz_detect()      wiz_detect_()
+#define wiz_genesis()     wiz_genesis_()
+#define wiz_identify()    wiz_identify_()
+#define wiz_level_tele()   wiz_level_tele_()
+#define wiz_map()         wiz_map_()
+#define wiz_where()       wiz_where_()
+#define wiz_wish()        wiz_wish_()
+#endif
+
+/* ### display.c ### */
+#define doredraw() doredraw_()
+
+/* ### do.c ### */
+#define doddrop()  doddrop_()
+#define dodown()   dodown_()
+#define dodrop()   dodrop_()
+#define donull()   donull_()
+#define doup()    doup_()
+#define dowipe()   dowipe_()
+#define drop(x)    drop_(x)
+#define wipeoff()  wipeoff_()
+
+
+/* ### do_name.c ### */
+#define ddocall()  ddocall_()
+#define do_mname() do_mname_()
+
+
+/* ### do_wear.c ### */
+#define Armor_off()   Armor_off_()
+#define Boots_off()   Boots_off_()
+#define Gloves_off()  Gloves_off_()
+#define Helmet_off()  Helmet_off_()
+#define Armor_on()    Armor_on_()
+#define Boots_on()    Boots_on_()
+#define Gloves_on()   Gloves_on_()
+#define Helmet_on()   Helmet_on_()
+#define doddoremarm() doddoremarm_()
+#define doputon()     doputon_()
+#define doremring()   doremring_()
+#define dotakeoff()   dotakeoff_()
+#define dowear()      dowear_()
+#define select_off(x) select_off_(x)
+#define take_off()    take_off_()
+
+
+/* ### dogmove.c ### */
+#define wantdoor(x, y, dummy) wantdoor_(x, y, dummy)
+
+
+/* ### dokick.c ### */
+#define dokick() dokick_()
+
+
+/* ### dothrow.c ### */
+#define dothrow() dothrow_()
+
+
+/* ### eat.c ### */
+#define Hear_again() Hear_again_()
+#define eatmdone()   eatmdone_()
+#define doeat()      doeat_()
+#define eatfood()    eatfood_()
+#define opentin()    opentin_()
+#define unfaint()    unfaint_()
+
+
+/* ### end.c ### */
+#define done1(sig)  done1_(sig)
+#define done2()     done2_()
+#define done_intr(sig) done_intr_(sig)
+#if defined(UNIX) || defined (VMS) || defined(__EMX__)
+#define done_hangup(sig) done_hangup_(sig)
+#endif
+
+
+/* ### engrave.c ### */
+#define doengrave() doengrave_()
+
+
+/* ### fountain.c ### */
+#define gush(x, y, poolcnt) gush_(x, y, poolcnt)
+
+
+/* ### hack.c ### */
+#define dopickup() dopickup_()
+#define identify(x) identify_(x)
+
+
+/* ### invent.c ### */
+#define ckunpaid(x)  ckunpaid_(x)
+#define ddoinv()     ddoinv_()
+#define dolook()     dolook_()
+#define dopramulet() dopramulet_()
+#define doprarm()    doprarm_()
+#define doprgold()   doprgold_()
+#define doprring()   doprring_()
+#define doprtool()   doprtool_()
+#define doprwep()    doprwep_()
+#define dotypeinv()  dotypeinv_()
+#define doorganize() doorganize_()
+
+
+/* ### ioctl.c ### */
+#ifdef UNIX
+# ifdef SUSPEND
+#define dosuspend() dosuspend_()
+# endif /* SUSPEND */
+#endif /* UNIX */
+
+
+/* ### lock.c ### */
+#define doclose()   doclose_()
+#define doforce()   doforce_()
+#define doopen()    doopen_()
+#define forcelock() forcelock_()
+#define picklock()  picklock_()
+
+
+/* ### mklev.c ### */
+#define do_comp(x, y)  comp_(x, y)
+
+
+/* ### mondata.c ### */
+/* See comment in trampoli.c before uncommenting canseemon. */
+/* #define canseemon(x) canseemon_(x) */
+
+
+/* ### muse.c ### */
+#define mbhitm(x, y) mbhitm_(x, y)
+
+
+/* ### o_init.c ### */
+#define dodiscovered() dodiscovered_()
+
+
+/* ### objnam.c ### */
+#define doname(x)   doname_(x)
+#define xname(x)    xname_(x)
+
+
+/* ### options.c ### */
+#define doset()                 doset_()
+#define dotogglepickup() dotogglepickup_()
+
+
+/* ### pager.c ### */
+#define dohelp()     dohelp_()
+#define dohistory()  dohistory_()
+#ifdef UNIX
+#define intruph()    intruph_()
+#endif /* UNIX */
+#define dowhatdoes() dowhatdoes_()
+#define dowhatis()   dowhatis_()
+#define doquickwhatis()   doquickwhatis_()
+
+
+/* ### pcsys.c ### */
+#ifdef SHELL
+#define dosh()      dosh_()
+#endif /* SHELL */
+
+
+/* ### pickup.c ### */
+#define ck_bag(x)       ck_bag_(x)
+#define doloot()        doloot_()
+#define in_container(x)  in_container_(x)
+#define out_container(x) out_container_(x)
+
+
+/* ### potion.c ### */
+#define dodrink() dodrink_()
+#define dodip()   dodip_()
+
+
+/* ### pray.c ### */
+#define doturn()      doturn_()
+#define dopray()      dopray_()
+#define prayer_done() prayer_done_()
+#define dosacrifice() dosacrifice_()
+
+
+/* ### read.c ### */
+#define doread()          doread_()
+#define set_lit(x, y, val) set_lit_(x, y, val)
+
+
+/* ### rip.c ### */
+#define genl_outrip(tmpwin, how) genl_outrip_(tmpwin, how)
+
+
+/* ### save.c ### */
+#define dosave() dosave_()
+#if defined(UNIX) || defined (VMS) || defined(__EMX__)
+#define hangup(sig) hangup_(sig)
+#endif
+
+
+/* ### search.c ### */
+#define doidtrap()          doidtrap_()
+#define dosearch()          dosearch_()
+#define findone(zx, zy, num) findone_(zx, zy, num)
+#define openone(zx, zy, num) openone_(zx, zy, num)
+
+
+/* ### shk.c ### */
+#define dopay() dopay_()
+
+
+/* ### sit.c ### */
+#define dosit() dosit_()
+
+
+/* ### sounds.c ### */
+#define dotalk() dotalk_()
+
+
+/* ### spell.c ### */
+#define learn()    learn_()
+#define docast()   docast_()
+#define dovspell() dovspell_()
+
+
+/* ### steal.c ### */
+#define stealarm() stealarm_()
+
+
+/* ### trap.c ### */
+#define dotele()     dotele_()
+#define dountrap()   dountrap_()
+#define float_down() float_down_()
+
+
+/* ### version.c ### */
+#define doversion()    doversion_()
+#define doextversion() doextversion_()
+
+
+/* ### wield.c ### */
+#define dowield() dowield_()
+
+
+/* ### zap.c ### */
+#define bhitm(x, y) bhitm_(x, y)
+#define bhito(x, y) bhito_(x, y)
+#define dozap()     dozap_()
+
+
+/* ### getline.c ### */
+#define tty_getlin(x,y)                        tty_getlin_(x,y)
+#define tty_get_ext_cmd()              tty_get_ext_cmd_()
+
+
+/* ### termcap.c ### */
+#define tty_nhbell()                   tty_nhbell_()
+#define tty_number_pad(x)              tty_number_pad_(x)
+#define tty_delay_output()             tty_delay_output_()
+#define tty_start_screen()             tty_start_screen_()
+#define tty_end_screen()               tty_end_screen_()
+
+
+/* ### topl.c ### */
+#define tty_doprev_message()           tty_doprev_message_()
+#define tty_yn_function(x,y,z)         tty_yn_function_(x,y,z)
+
+
+/* ### wintty.c ### */
+#define tty_init_nhwindows(x,y)                tty_init_nhwindows_(x,y)
+#define tty_player_selection()         tty_player_selection_()
+#define tty_askname()                  tty_askname_()
+#define tty_get_nh_event()             tty_get_nh_event_()
+#define tty_exit_nhwindows(x)          tty_exit_nhwindows_(x)
+#define tty_suspend_nhwindows(x)       tty_suspend_nhwindows_(x)
+#define tty_resume_nhwindows()         tty_resume_nhwindows_()
+#define tty_create_nhwindow(x)         tty_create_nhwindow_(x)
+#define tty_clear_nhwindow(x)          tty_clear_nhwindow_(x)
+#define tty_display_nhwindow(x,y)      tty_display_nhwindow_(x,y)
+#define tty_destroy_nhwindow(x)                tty_destroy_nhwindow_(x)
+#define tty_curs(x,y,z)                        tty_curs_(x,y,z)
+#define tty_putstr(x,y,z)              tty_putstr_(x,y,z)
+#define tty_display_file(x,y)          tty_display_file_(x,y)
+#define tty_start_menu(x)              tty_start_menu_(x)
+#define tty_add_menu(a,b,c,d,e,f,g,h)  tty_add_menu_(a,b,c,d,e,f,g,h)
+#define tty_end_menu(a,b)              tty_end_menu_(a,b)
+#define tty_select_menu(a,b,c)         tty_select_menu_(a,b,c)
+#define tty_update_inventory()         tty_update_inventory_()
+#define tty_mark_synch()               tty_mark_synch_()
+#define tty_wait_synch()               tty_wait_synch_()
+#ifdef CLIPPING
+#define tty_cliparound(x,y)            tty_cliparound_(x,y)
+#endif
+#ifdef POSITIONBAR
+#define tty_update_positionbar(x)      tty_update_positionbar_(x)
+#endif
+#define tty_print_glyph(a,b,c,d)       tty_print_glyph_(a,b,c,d)
+#define tty_raw_print(x)               tty_raw_print_(x)
+#define tty_raw_print_bold(x)          tty_raw_print_bold_(x)
+#define tty_nhgetch()                  tty_nhgetch_()
+#define tty_nh_poskey(x,y,z)           tty_nh_poskey_(x,y,z)
+
+#endif /* USE_TRAMPOLI */
+
+#endif /* TRAMPOLI_H */
diff --git a/include/trap.h b/include/trap.h
new file mode 100644 (file)
index 0000000..f74f328
--- /dev/null
@@ -0,0 +1,77 @@
+/*     SCCS Id: @(#)trap.h     3.4     2000/08/30      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* note for 3.1.0 and later: no longer manipulated by 'makedefs' */
+
+#ifndef TRAP_H
+#define TRAP_H
+
+union vlaunchinfo {
+       short v_launch_otyp;    /* type of object to be triggered */
+       coord v_launch2;        /* secondary launch point (for boulders) */
+};
+
+struct trap {
+       struct trap *ntrap;
+       xchar tx,ty;
+       d_level dst;    /* destination for portals */
+       coord launch;
+       Bitfield(ttyp,5);
+       Bitfield(tseen,1);
+       Bitfield(once,1);
+       Bitfield(madeby_u,1); /* So monsters may take offence when you trap
+                                them.  Recognizing who made the trap isn't
+                                completely unreasonable, everybody has
+                                their own style.  This flag is also needed
+                                when you untrap a monster.  It would be too
+                                easy to make a monster peaceful if you could
+                                set a trap for it and then untrap it. */
+       union vlaunchinfo vl;
+#define launch_otyp    vl.v_launch_otyp
+#define launch2                vl.v_launch2
+};
+
+extern struct trap *ftrap;
+#define newtrap()      (struct trap *) alloc(sizeof(struct trap))
+#define dealloc_trap(trap) free((genericptr_t) (trap))
+
+/* reasons for statue animation */
+#define ANIMATE_NORMAL 0
+#define ANIMATE_SHATTER 1
+#define ANIMATE_SPELL  2
+
+/* reasons for animate_statue's failure */
+#define AS_OK           0      /* didn't fail */
+#define AS_NO_MON       1      /* makemon failed */
+#define AS_MON_IS_UNIQUE 2     /* statue monster is unique */
+
+/* Note: if adding/removing a trap, adjust trap_engravings[] in mklev.c */
+
+/* unconditional traps */
+#define NO_TRAP                0
+#define ARROW_TRAP     1
+#define DART_TRAP      2
+#define ROCKTRAP       3
+#define SQKY_BOARD     4
+#define BEAR_TRAP      5
+#define LANDMINE       6
+#define ROLLING_BOULDER_TRAP   7
+#define SLP_GAS_TRAP   8
+#define RUST_TRAP      9
+#define FIRE_TRAP      10
+#define PIT            11
+#define SPIKED_PIT     12
+#define HOLE           13
+#define TRAPDOOR       14
+#define TELEP_TRAP     15
+#define LEVEL_TELEP    16
+#define MAGIC_PORTAL   17
+#define WEB            18
+#define STATUE_TRAP    19
+#define MAGIC_TRAP     20
+#define ANTI_MAGIC     21
+#define POLY_TRAP      22
+#define TRAPNUM 23
+
+#endif /* TRAP_H */
diff --git a/include/unixconf.h b/include/unixconf.h
new file mode 100644 (file)
index 0000000..fe1b006
--- /dev/null
@@ -0,0 +1,351 @@
+/*     SCCS Id: @(#)unixconf.h 3.4     1999/07/02      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifdef UNIX
+#ifndef UNIXCONF_H
+#define UNIXCONF_H
+
+/*
+ * Some include files are in a different place under SYSV
+ *     BSD                SYSV
+ * <sys/time.h>                <time.h>
+ * <sgtty.h>           <termio.h>
+ *
+ * Some routines are called differently
+ * index               strchr
+ * rindex              strrchr
+ *
+ */
+
+/* define exactly one of the following four choices */
+/* #define BSD 1 */    /* define for 4.n/Free/Open/Net BSD  */
+                       /* also for relatives like SunOS 4.x, DG/UX, and */
+                       /* older versions of Linux */
+/* #define ULTRIX */   /* define for Ultrix v3.0 or higher (but not lower) */
+                       /* Use BSD for < v3.0 */
+                       /* "ULTRIX" not to be confused with "ultrix" */
+#define SYSV           /* define for System V, Solaris 2.x, newer versions */
+                       /* of Linux */
+/* #define HPUX */     /* Hewlett-Packard's Unix, version 6.5 or higher */
+                       /* use SYSV for < v6.5 */
+
+
+/* define any of the following that are appropriate */
+#define SVR4           /* use in addition to SYSV for System V Release 4 */
+                       /* including Solaris 2+ */
+#define NETWORK                /* if running on a networked system */
+                       /* e.g. Suns sharing a playground through NFS */
+/* #define SUNOS4 */   /* SunOS 4.x */
+/* #define LINUX */    /* Another Unix clone */
+/* #define CYGWIN32 */ /* Unix on Win32 -- use with case sensitive defines */
+/* #define GENIX */    /* Yet Another Unix Clone */
+/* #define HISX */     /* Bull Unix for XPS Machines */
+/* #define BOS */      /* Bull Open Software - Unix for DPX/2 Machines */
+/* #define UNIXPC */   /* use in addition to SYSV for AT&T 7300/3B1 */
+/* #define AIX_31 */   /* In AIX 3.1 (IBM RS/6000) use BSD ioctl's to gain
+                        * job control (note that AIX is SYSV otherwise)
+                        * Also define this for AIX 3.2 */
+
+#define TERMINFO       /* uses terminfo rather than termcap */
+                       /* Should be defined for most SYSV, SVR4 (including
+                        * Solaris 2+), HPUX, and Linux systems.  In
+                        * particular, it should NOT be defined for the UNIXPC
+                        * unless you remove the use of the shared library in
+                        * the Makefile */
+#define TEXTCOLOR      /* Use System V r3.2 terminfo color support */
+                       /* and/or ANSI color support on termcap systems */
+                       /* and/or X11 color */
+#define POSIX_JOB_CONTROL /* use System V / Solaris 2.x / POSIX job control */
+                       /* (e.g., VSUSP) */
+#define POSIX_TYPES    /* use POSIX types for system calls and termios */
+                       /* Define for many recent OS releases, including
+                        * those with specific defines (since types are
+                        * changing toward the standard from earlier chaos).
+                        * For example, platforms using the GNU libraries,
+                        * Linux, Solaris 2.x
+                        */
+
+/* #define OPENWINBUG */       /* avoid a problem using OpenWindows 3.0 for
+                                  X11 on SunOS 4.1.x, x>= 2.  Do not define
+                                  for other X11 implementations. */
+/* #define PYRAMID_BUG */      /* avoid a bug on the Pyramid */
+/* #define BSD_43_BUG */       /* for real 4.3BSD cc's without schain botch fix */
+/* #define MICROPORT_BUG */    /* problems with large arrays in structs */
+/* #define MICROPORT_286_BUG */ /* changes needed in termcap.c to get it to
+                                  run with Microport Sys V/AT version 2.4.
+                                  By Jay Maynard */
+/* #define AIXPS_2BUG */       /* avoid a problem with little_to_big() optimization */
+
+/* #define RANDOM */           /* if neither random/srandom nor lrand48/srand48
+                                  is available from your system */
+
+/* see sys/unix/snd86unx.shr for more information on these */
+/* #define UNIX386MUSIC */     /* play real music through speaker on systems
+                                  with music driver installed */
+/* #define VPIX_MUSIC */       /* play real music through speaker on systems
+                                  with built-in VPIX support */
+
+
+/*
+ * The next two defines are intended mainly for the Andrew File System,
+ * which does not allow hard links.  If NO_FILE_LINKS is defined, lock files
+ * will be created in LOCKDIR using open() instead of in the playground using
+ * link().
+ *             Ralf Brown, 7/26/89 (from v2.3 hack of 10/10/88)
+ */
+
+/* #define NO_FILE_LINKS */    /* if no hard links */
+/* #define LOCKDIR "/usr/games/lib/nethackdir" */      /* where to put locks */
+
+/*
+ * If you want the static parts of your playground on a read-only file
+ * system, define VAR_PLAYGROUND to be where the variable parts are kept.
+ */
+/* #define VAR_PLAYGROUND "/var/lib/games/nethack" */
+
+
+/*
+ * Define DEF_PAGER as your default pager, e.g. "/bin/cat" or "/usr/ucb/more"
+ * If defined, it can be overridden by the environment variable PAGER.
+ * Hack will use its internal pager if DEF_PAGER is not defined.
+ * (This might be preferable for security reasons.)
+ * #define DEF_PAGER   ".../mydir/mypager"
+ */
+
+
+
+/*
+ * Define PORT_HELP to be the name of the port-specfic help file.
+ * This file is found in HACKDIR.
+ * Normally, you shouldn't need to change this.
+ * There is currently no port-specific help for Unix systems.
+ */
+/* #define PORT_HELP "Unixhelp" */
+
+#ifdef TTY_GRAPHICS
+/*
+ * To enable the `timed_delay' option for using a timer rather than extra
+ * screen output when pausing for display effect.  Requires that `msleep'
+ * function be available (with time argument specified in milliseconds).
+ * Various output devices can produce wildly varying delays when the
+ * "extra output" method is used, but not all systems provide access to
+ * a fine-grained timer.
+ */
+/* #define TIMED_DELAY */      /* usleep() */
+#endif
+
+/*
+ * If you define MAIL, then the player will be notified of new mail
+ * when it arrives.  If you also define DEF_MAILREADER then this will
+ * be the default mail reader, and can be overridden by the environment
+ * variable MAILREADER; otherwise an internal pager will be used.
+ * A stat system call is done on the mailbox every MAILCKFREQ moves.
+ */
+
+#define MAIL                   /* Deliver mail during the game */
+
+/* The Andrew Message System does mail a little differently from normal
+ * UNIX.  Mail is deposited in the user's own directory in ~/Mailbox
+ * (another directory).  MAILBOX is the element that will be added on to
+ * the user's home directory path to generate the Mailbox path - just in
+ * case other Andrew sites do it differently from CMU.
+ *
+ *             dan lovinger
+ *             dl2n+@andrew.cmu.edu (dec 19 1989)
+ */
+
+/* #define AMS */              /* use Andrew message system for mail */
+
+/* NO_MAILREADER is for kerberos authenticating filesystems where it is
+ * essentially impossible to securely exec child processes, like mail
+ * readers, when the game is running under a special token.
+ *
+ *            dan
+ */
+
+/* #define NO_MAILREADER */    /* have mail daemon just tell player of mail */
+
+#ifdef MAIL
+# if defined(BSD) || defined(ULTRIX)
+#  ifdef AMS
+#define AMS_MAILBOX    "/Mailbox"
+#  else
+#   if defined(__FreeBSD__) || defined(__OpenBSD__)
+#define DEF_MAILREADER "/usr/bin/mail"
+#   else
+#define DEF_MAILREADER "/usr/ucb/Mail"
+#   endif
+#  endif
+#else
+# if (defined(SYSV) || defined(DGUX) || defined(HPUX)) && !defined(LINUX)
+#  if defined(M_XENIX)
+#define DEF_MAILREADER "/usr/bin/mail"
+#  else
+#   ifdef __sgi
+#define DEF_MAILREADER "/usr/sbin/Mail"
+#   else
+#define DEF_MAILREADER "/usr/bin/mailx"
+#   endif
+#  endif
+# else
+#define DEF_MAILREADER "/bin/mail"
+# endif
+#endif
+
+#define MAILCKFREQ     50
+#endif /* MAIL */
+
+
+
+#ifdef COMPRESS
+/* Some implementations of compress need a 'quiet' option.
+ * If you've got one of these versions, put -q here.
+ * You can also include any other strange options your compress needs.
+ * If you have a normal compress, just leave it commented out.
+ */
+/* #define COMPRESS_OPTIONS "-q" */
+#endif
+
+#define FCMASK 0660    /* file creation mask */
+
+
+/*
+ * The remainder of the file should not need to be changed.
+ */
+
+#ifdef _AUX_SOURCE
+# ifdef AUX /* gcc ? */
+#  define _SYSV_SOURCE
+#  define _BSD_SOURCE
+#else
+#  define AUX
+# endif
+#endif /* _AUX_SOURCE */
+
+#if defined(LINUX) || defined(bsdi)
+# ifndef POSIX_TYPES
+#  define POSIX_TYPES
+# endif
+# ifndef POSIX_JOB_CONTROL
+#  define POSIX_JOB_CONTROL
+# endif
+#endif
+
+/*
+ * BSD/ULTRIX systems are normally the only ones that can suspend processes.
+ * Suspending NetHack processes cleanly should be easy to add to other systems
+ * that have SIGTSTP in the Berkeley sense.  Currently the only such systems
+ * known to work are HPUX and AIX 3.1; other systems will probably require
+ * tweaks to unixtty.c and ioctl.c.
+ *
+ * POSIX defines a slightly different type of job control, which should be
+ * equivalent for NetHack's purposes.  POSIX_JOB_CONTROL should work on
+ * various recent SYSV versions (with possibly tweaks to unixtty.c again).
+ */
+#ifndef POSIX_JOB_CONTROL
+# if defined(BSD) || defined(ULTRIX) || defined(HPUX) || defined(AIX_31)
+#  define BSD_JOB_CONTROL
+# else
+#  if defined(SVR4)
+#   define POSIX_JOB_CONTROL
+#  endif
+# endif
+#endif
+#if defined(BSD_JOB_CONTROL) || defined(POSIX_JOB_CONTROL) || defined(AUX)
+#define SUSPEND                /* let ^Z suspend the game */
+#endif
+
+
+#if defined(BSD) || defined(ULTRIX)
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#define HLOCK  "perm"  /* an empty file used for locking purposes */
+
+#ifndef REDO
+#define Getchar nhgetch
+#endif
+#define tgetch getchar
+
+#define SHELL          /* do not delete the '!' command */
+
+#include "system.h"
+
+#if defined(POSIX_TYPES) || defined(__GNUC__)
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
+#if defined(POSIX_TYPES) || defined(__GNUC__) || defined(BSD) || defined(ULTRIX)
+#include <sys/wait.h>
+#endif
+
+#if defined(BSD) || defined(ULTRIX)
+# if !defined(DGUX) && !defined(SUNOS4)
+#define memcpy(d, s, n)                bcopy(s, d, n)
+#define memcmp(s1, s2, n)      bcmp(s2, s1, n)
+# endif
+# ifdef SUNOS4
+#include <memory.h>
+# endif
+#else  /* therefore SYSV */
+# ifndef index /* some systems seem to do this for you */
+#define index  strchr
+# endif
+# ifndef rindex
+#define rindex strrchr
+# endif
+#endif
+
+/* Use the high quality random number routines. */
+#if defined(BSD) || defined(LINUX) || defined(ULTRIX) || defined(CYGWIN32) || defined(RANDOM) || defined(__APPLE__)
+#define Rand() random()
+#else
+#define Rand() lrand48()
+#endif
+
+#ifdef TIMED_DELAY
+# if defined(SUNOS4) || defined(LINUX) || (defined(BSD) && !defined(ULTRIX))
+# define msleep(k) usleep((k)*1000)
+# endif
+# ifdef ULTRIX
+# define msleep(k) napms(k)
+# endif
+#endif
+
+#ifdef hc      /* older versions of the MetaWare High-C compiler define this */
+# ifdef __HC__
+#  undef __HC__
+# endif
+# define __HC__ hc
+# undef hc
+#endif
+
+#if defined(GNOME_GRAPHICS)
+#if defined(LINUX)
+# include <linux/unistd.h>
+# if defined(__NR_getresuid) && defined(__NR_getresgid)        /* ie., >= v2.1.44 */
+#  define GETRES_SUPPORT
+# endif
+#else
+# if defined(BSD) || defined(SVR4)
+/*
+ * [ALI] We assume that SVR4 means we can safely include syscall.h
+ * (although it's really a BSDism). This is certainly true for Solaris 2.5,
+ * Solaris 7, Solaris 8 and Compaq Tru64 5.1
+ * Later BSD systems will have the getresid system calls.
+ */
+# include <sys/syscall.h>
+# if (defined (SYS_getuid) || defined(SYS_getresuid)) && \
+  (defined(SYS_getgid) || defined(SYS_getresgid))
+#  define GETRES_SUPPORT
+# endif
+# endif        /* BSD || SVR4 */
+#endif /* LINUX */
+#endif /* GNOME_GRAPHICS */
+
+#endif /* UNIXCONF_H */
+#endif /* UNIX */
diff --git a/include/vault.h b/include/vault.h
new file mode 100644 (file)
index 0000000..6e0a162
--- /dev/null
@@ -0,0 +1,27 @@
+/*     SCCS Id: @(#)vault.h    3.4     1997/05/01      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef VAULT_H
+#define VAULT_H
+
+#define FCSIZ  (ROWNO+COLNO)
+struct fakecorridor {
+       xchar fx,fy,ftyp;
+};
+
+struct egd {
+       int fcbeg, fcend;       /* fcend: first unused pos */
+       int vroom;              /* room number of the vault */
+       xchar gdx, gdy;         /* goal of guard's walk */
+       xchar ogx, ogy;         /* guard's last position */
+       d_level gdlevel;        /* level (& dungeon) guard was created in */
+       xchar warncnt;          /* number of warnings to follow */
+       Bitfield(gddone,1);     /* true iff guard has released player */
+       Bitfield(unused,7);
+       struct fakecorridor fakecorr[FCSIZ];
+};
+
+#define EGD(mon)       ((struct egd *)&(mon)->mextra[0])
+
+#endif /* VAULT_H */
diff --git a/include/vision.h b/include/vision.h
new file mode 100644 (file)
index 0000000..29396eb
--- /dev/null
@@ -0,0 +1,58 @@
+/*     SCCS Id: @(#)vision.h   3.4     1995/01/26      */
+/* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990. */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+#ifndef VISION_H
+#define VISION_H
+
+#if 0  /* (moved to decl.h) */
+extern boolean vision_full_recalc;     /* TRUE if need vision recalc */
+extern char **viz_array;               /* could see/in sight row pointers */
+extern char *viz_rmin;                 /* min could see indices */
+extern char *viz_rmax;                 /* max could see indices */
+#endif
+#define COULD_SEE 0x1          /* location could be seen, if it were lit */
+#define IN_SIGHT  0x2          /* location can be seen */
+#define TEMP_LIT  0x4          /* location is temporarily lit */
+
+/*
+ * Light source sources
+ */
+#define LS_OBJECT 0
+#define LS_MONSTER 1
+
+/*
+ *  cansee()   - Returns true if the hero can see the location.
+ *
+ *  couldsee() - Returns true if the hero has a clear line of sight to
+ *               the location.
+ */
+#define cansee(x,y)    (viz_array[y][x] & IN_SIGHT)
+#define couldsee(x,y)  (viz_array[y][x] & COULD_SEE)
+#define templit(x,y)   (viz_array[y][x] & TEMP_LIT)
+
+/*
+ *  The following assume the monster is not blind.
+ *
+ *  m_cansee() - Returns true if the monster can see the given location.
+ *
+ *  m_canseeu() - Returns true if the monster could see the hero.  Assumes
+ *               that if the hero has a clear line of sight to the monster's
+ *               location and the hero is visible, then monster can see the
+ *               hero.
+ */
+#define m_cansee(mtmp,x2,y2)   clear_path((mtmp)->mx,(mtmp)->my,(x2),(y2))
+
+#define m_canseeu(m)   ((!Invis || perceives((m)->data)) && \
+                         !(Underwater || u.uburied || (m)->mburied) ? \
+                            couldsee((m)->mx,(m)->my) : 0)
+
+/*
+ *  Circle information
+ */
+#define MAX_RADIUS 15  /* this is in points from the source */
+
+/* Use this macro to get a list of distances of the edges (see vision.c). */
+#define circle_ptr(z) (&circle_data[(int)circle_start[z]])
+
+#endif /* VISION_H */
diff --git a/include/vmsconf.h b/include/vmsconf.h
new file mode 100644 (file)
index 0000000..421d68a
--- /dev/null
@@ -0,0 +1,265 @@
+/*     SCCS Id: @(#)vmsconf.h  3.4     2003/05/19      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifdef VMS
+#ifndef VMSCONF_H
+#define VMSCONF_H
+
+/*
+ * Edit these to choose values appropriate for your site.
+ * WIZARD is the username allowed to use the debug option of nethack; no harm
+ *   is done by leaving it as a username that doesn't exist at your site.
+ * HACKDIR can be overridden at run-time with the logical name HACKDIR, as in
+ *   $ define hackdir disk$users:[games.nethack]
+ * Trailing NULs are present in the default values in order to make some
+ *   extra room for patching longer values into an existing executable.
+ */
+#define Local_WIZARD   "NHWIZARD\0\0\0\0"
+#define Local_HACKDIR  "DISK$USERS:[GAMES.NETHACK.3_4_X.PLAY]\0\0\0\0\0\0\0\0"
+
+/*
+ * This section cleans up the stuff done in config.h so that it
+ * shouldn't need to be modified.  It's conservative so that if
+ * config.h is actually edited, the changes won't impact us.
+ */
+#ifdef UNIX
+# undef UNIX
+#endif
+#ifdef HACKDIR
+# undef HACKDIR
+#endif
+#ifdef WIZARD
+# undef WIZARD
+#endif
+#ifdef WIZARD_NAME
+# undef WIZARD_NAME
+#endif
+#define HACKDIR Local_HACKDIR
+#ifndef KR1ED
+# define WIZARD Local_WIZARD
+# define WIZARD_NAME WIZARD
+#else
+# define WIZARD 1
+# define WIZARD_NAME Local_WIZARD
+#endif
+
+/* filenames require punctuation to avoid redirection via logical names */
+#undef RECORD
+#define RECORD "record;1"      /* scoreboard file (retains high scores) */
+#undef LOGFILE
+#define LOGFILE "logfile;0"    /* optional file (records all games) */
+
+#define HLOCK  "perm;1"        /* an empty file used for locking purposes */
+
+/* want compression--for level & save files--performed within NetHack itself */
+#ifdef COMPRESS
+# undef COMPRESS
+#endif
+#ifndef INTERNAL_COMP
+# define INTERNAL_COMP
+#endif
+
+/*
+ * If nethack.exe will be installed with privilege so that the playground
+ * won't need to be left unprotected, define SECURE to suppress a couple
+ * of file protection fixups (protection of bones files and ownership of
+ * save files).
+ */
+/* #define SECURE */
+
+/*
+ * Put the readonly data files into a single container rather than into
+ * separate files in the playground directory.
+ */
+#define DLB    /* use data librarian code */
+
+/*
+ * You may define TEXTCOLOR if your system has any terminals that recognize
+ * ANSI color sequences of the form ``<ESCAPE>[#;#m'', where the first # is
+ * a number between 40 and 47 represented background color, and the second
+ * # is a number between 30 and 37 representing the foreground color.
+ * GIGI terminals and DECterm windows on color VAXstations support these
+ * color escape sequences, as do some 3rd party terminals and many micro
+ * computers.
+ */
+/* #define TEXTCOLOR */
+
+/*
+ * If you define USE_QIO_INPUT, then you'll get raw characters from the
+ * keyboard, not unlike those of the unix version of Nethack.  This will
+ * allow you to use the Escape key in normal gameplay, and the appropriate
+ * control characters in Wizard mode.  It will work most like the unix version.
+ * It will also avoid "<interrupt>" being displayed when ^Y is pressed.
+ *
+ * Otherwise, the VMS SMG calls will be used.  These calls block use of
+ * the escape key, as well as certain control keys, so gameplay is not
+ * the same, although the differences are fairly negligible.  You must
+ * then use a VTxxx function key or two <escape>s to give an ESC response.
+ */
+#define USE_QIO_INPUT  /* use SYS$QIOW instead of SMG$READ_KEYSTROKE */
+
+/*
+ * Allow the user to decide whether to pause via timer or excess screen
+ * output for various display effects like explosions and moving objects.
+ */
+#define TIMED_DELAY    /* enable the `timed_delay' run-time option */
+
+/*
+ * If you define MAIL, then NetHack will capture incoming broadcast
+ * messages such as "New mail from so-and-so" and "Print job completed,"
+ * and then deliver them to the player.  For mail and phone broadcasts
+ * a scroll of mail will be created, which when read will cause NetHack
+ * to prompt the player for a command to spawn in order to respond.  The
+ * latter capability will not be available if SHELL is disabled below.
+ * If you undefine MAIL, broadcasts will go straight to the terminal,
+ * resulting in disruption of the screen display; use <ctrl/R> to redraw.
+ */
+#define MAIL           /* enable broadcast trapping */
+
+/*
+ * SHELL enables the player to 'escape' into a spawned subprocess via
+ * the '!' command.  Logout or attach back to the parent to resume play.
+ * If the player attaches back to NetHack, then a subsequent escape will
+ * re-attach to the existing subprocess.  Any such subprocess left over
+ * at game exit will be deleted by an exit handler.
+ * SUSPEND enables someone running NetHack in a subprocess to reconnect
+ * to the parent process with the <ctrl/Z> command; this is not very
+ * close to Unix job control, but it's better than nothing.
+ */
+#define SHELL          /* do not delete the '!' command */
+#define SUSPEND                /* don't delete the ^Z command, such as it is */
+
+#define RANDOM         /* use sys/share/random.c instead of vaxcrtl rand */
+
+#define FCMASK 0660    /* file creation mask */
+
+
+/*
+ * The remainder of the file should not need to be changed.
+ */
+
+/* data librarian defs */
+#ifdef DLB
+# define DLBFILE       "nh-data.dlb"
+       /*
+        * Since we can do without case insensitive filename comparison,
+        * avoid enabling it because that requires compiling and linking
+        * src/hacklib into util/dlb_main.
+        */
+/* # define FILENAME_CMP strcmpi */    /* case insensitive */
+#endif
+
+#if defined(VAXC) && !defined(ANCIENT_VAXC)
+# ifdef volatile
+#  undef volatile
+# endif
+# ifdef const
+#  undef const
+# endif
+#endif
+
+#ifdef __DECC
+# define STRICT_REF_DEF /* used in lev_main.c */
+#endif
+#ifdef STRICT_REF_DEF
+# define DEFINE_OSPEED
+#endif
+
+#ifndef alloca
+       /* bison generated foo_yacc.c might try to use alloca() */
+# ifdef __GNUC__
+#  define alloca __builtin_alloca
+# else
+#  define ALLOCA_HACK  /* used in util/panic.c */
+# endif
+#endif
+
+#ifdef _DECC_V4_SOURCE
+/* <types.h> excludes some necessary typedefs when _DECC_V4_SOURCE is defined */
+#include <types.h>
+# ifndef __PID_T
+# define __PID_T
+typedef __pid_t pid_t;
+# endif
+# ifndef __UID_T
+# define __UID_T
+typedef __uid_t uid_t;
+# endif
+# ifndef __GID_T
+# define __GID_T
+typedef __gid_t gid_t;
+# endif
+# ifndef __MODE_T
+# define __MODE_T
+typedef __mode_t mode_t;
+# endif
+#endif /* _DECC_V4_SOURCE */
+
+#include <time.h>
+#if 0  /* <file.h> is missing for old gcc versions; skip it to save time */
+#include <file.h>
+#else  /* values needed from missing include file */
+# define O_RDONLY 0
+# define O_WRONLY 1
+# define O_RDWR   2
+# define O_CREAT 0x200
+# define O_TRUNC 0x400
+#endif
+
+#ifndef REDO
+# define Getchar nhgetch
+#endif
+#define tgetch vms_getchar
+
+#include "system.h"
+
+#define index  strchr
+#define rindex strrchr
+
+/* Use the high quality random number routines. */
+#if defined(RANDOM)
+#define Rand() random()
+/* VMS V7 adds these entry points to DECC$SHR; stick with the nethack-supplied
+   code to avoid having to deal with version-specific conditionalized builds */
+#define random         nh_random
+#define srandom                nh_srandom
+#define initstate      nh_initstate
+#define setstate       nh_setstate
+#else
+#define Rand() rand()
+#endif
+
+#ifndef __GNUC__
+# ifndef bcopy
+#define bcopy(s,d,n)   memcpy((d),(s),(n))     /* vaxcrtl */
+# endif
+#endif
+#define abort()                vms_abort()             /* vmsmisc.c */
+#define creat(f,m)     vms_creat(f,m)          /* vmsfiles.c */
+#define exit(sts)      vms_exit(sts)           /* vmsmisc.c */
+#define getuid()       vms_getuid()            /* vmsunix.c */
+#define link(f1,f2)    vms_link(f1,f2)         /* vmsfiles.c */
+#define open(f,k,m)    vms_open(f,k,m)         /* vmsfiles.c */
+/* #define unlink(f0)  vms_unlink(f0)          /* vmsfiles.c */
+#ifdef VERYOLD_VMS
+#define unlink(f0)     delete(f0)              /* vaxcrtl */
+#else
+#define unlink(f0)     remove(f0)              /* vaxcrtl, decc$shr */
+#endif
+#define C$$TRANSLATE(n) c__translate(n)                /* vmsfiles.c */
+
+/* VMS global names are case insensitive... */
+#define An vms_an
+#define The vms_the
+#define Shk_Your vms_shk_your
+
+/* avoid global symbol in Alpha/VMS V1.5 STARLET library (link trouble) */
+#define ospeed vms_ospeed
+
+/* used in several files which don't #include "extern.h" */
+extern void FDECL(vms_exit, (int));
+extern int FDECL(vms_open, (const char *,int,unsigned));
+
+#endif /* VMSCONF_H */
+#endif /* VMS */
diff --git a/include/wceconf.h b/include/wceconf.h
new file mode 100644 (file)
index 0000000..0ecbe53
--- /dev/null
@@ -0,0 +1,354 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* Copyright (c) NetHack PC Development Team 1993, 1994.  */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef WCECONF_H
+#define WCECONF_H
+
+#pragma warning(disable:4142) /* benign redefinition of type */
+
+#define WIN32_LEAN_AND_MEAN            // Exclude rarely-used stuff from Windows headers
+
+#include <windows.h>
+
+/* Detect the targe device */
+#if defined(WIN32_PLATFORM_PSPC) 
+#      if _WIN32_WCE >= 300
+#              define WIN_CE_POCKETPC
+#      else
+#              define WIN_CE_PS2xx
+#      endif
+#elif defined(WIN32_PLATFORM_HPCPRO)
+#      define WIN_CE_HPCPRO
+#elif defined(WIN32_PLATFORM_WFSP)
+#      define WIN_CE_SMARTPHONE
+#else
+#      error "Unsupported Windows CE platform"
+#endif
+
+/* #define SHELL       /* nt use of pcsys routines caused a hang */
+
+#define RANDOM         /* have Berkeley random(3) */
+#define TEXTCOLOR      /* Color text */
+
+#define EXEPATH                        /* Allow .exe location to be used as HACKDIR */
+#define TRADITIONAL_GLYPHMAP   /* Store glyph mappings at level change time */
+
+#define PC_LOCKING             /* Prevent overwrites of aborted or in-progress games */
+                               /* without first receiving confirmation. */
+
+#define SELF_RECOVER           /* Allow the game itself to recover from an aborted game */
+
+#define NOTSTDC                /* no strerror() */
+
+#define USER_SOUNDS
+
+#define AUTOPICKUP_EXCEPTIONS
+
+/*
+ * -----------------------------------------------------------------
+ *  The remaining code shouldn't need modification.
+ * -----------------------------------------------------------------
+ */
+/* #define SHORT_FILENAMES     /* All NT filesystems support long names now */
+
+#ifdef MICRO
+#undef MICRO                   /* never define this! */
+#endif
+
+#define NOCWD_ASSUMPTIONS      /* Always define this. There are assumptions that
+                                   it is defined for WIN32.
+                                  Allow paths to be specified for HACKDIR,
+                                  LEVELDIR, SAVEDIR, BONESDIR, DATADIR,
+                                  SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */
+#define NO_TERMS
+#define ASCIIGRAPH
+
+#ifdef OPTIONS_USED
+#undef OPTIONS_USED
+#endif
+#ifdef MSWIN_GRAPHICS
+#define OPTIONS_USED   "guioptions"
+#else
+#define OPTIONS_USED   "ttyoptions"
+#endif
+#define OPTIONS_FILE OPTIONS_USED
+
+#define PORT_HELP      "porthelp"
+
+#if defined(WIN_CE_POCKETPC)
+#      define PORT_CE_PLATFORM "Pocket PC"
+#elif defined(WIN_CE_PS2xx)
+#      define PORT_CE_PLATFORM "Palm-size PC 2.11"
+#elif defined(WIN_CE_HPCPRO)
+#      define PORT_CE_PLATFORM "H/PC Pro 2.11"
+#elif defined(WIN_CE_SMARTPHONE)
+#      define PORT_CE_PLATFORM "Smartphone 2002"
+#endif
+
+#if defined(ARM)
+#      define PORT_CE_CPU "ARM"
+#elif defined(PPC)
+#      define PORT_CE_CPU "PPC"
+#elif defined(ALPHA)
+#      define PORT_CE_CPU "ALPHA"
+#elif defined(SH3)
+#      define PORT_CE_CPU "SH3"
+#elif defined(SH4)
+#      define PORT_CE_CPU "SH4"
+#elif defined(MIPS)
+#      define PORT_CE_CPU "MIPS"
+#elif defined(X86) || defined(_X86_)
+#      define PORT_CE_CPU "X86"
+#else
+#      error Only ARM, PPC, ALPHA, SH3, SH4, MIPS and X86 supported
+#endif
+
+#define RUNTIME_PORT_ID        /* trigger run-time port identification since
+                          Makedefs is bootstrapped on a cross-platform. */
+
+#include <string.h>    /* Provides prototypes of strncmpi(), etc.     */
+#ifdef STRNCMPI
+#define strncmpi(a,b,c) _strnicmp(a,b,c)
+#endif
+
+#ifdef STRCMPI
+#define strcmpi(a,b) _stricmp(a,b)
+#define stricmp(a,b) _stricmp(a,b)
+#endif
+
+#include <stdlib.h>
+
+#define PATHLEN                BUFSZ /* maximum pathlength */
+#define FILENAME       BUFSZ /* maximum filename length (conservative) */
+
+#if defined(_MAX_PATH) && defined(_MAX_FNAME)
+# if (_MAX_PATH < BUFSZ) && (_MAX_FNAME < BUFSZ)
+#undef PATHLEN
+#undef FILENAME
+#define PATHLEN                _MAX_PATH
+#define FILENAME       _MAX_FNAME
+# endif
+#endif
+
+
+#define NO_SIGNAL
+#define index  strchr
+#define rindex strrchr
+#define USE_STDARG
+#ifdef RANDOM
+/* Use the high quality random number routines. */
+#define Rand() random()
+#else
+#define Rand() rand()
+#endif
+
+#define FCMASK 0660    /* file creation mask */
+#define regularize     nt_regularize
+#define HLOCK "NHPERM"
+
+#ifndef M
+#define M(c)           ((char) (0x80 | (c)))
+/* #define M(c)                ((c) - 128) */
+#endif
+
+#ifndef C
+#define C(c)           (0x1f & (c))
+#endif
+
+#if defined(DLB)
+#define FILENAME_CMP  _stricmp               /* case insensitive */
+#endif
+
+#if 0
+extern char levels[], bones[], permbones[],
+#endif /* 0 */
+
+/* this was part of the MICRO stuff in the past */
+extern const char *alllevels, *allbones;
+extern char hackdir[];
+#define ABORT C('a')
+#define getuid() 1
+#define getlogin() ((char *)0)
+extern void NDECL(win32_abort);
+#ifdef WIN32CON
+extern void FDECL(nttty_preference_update, (const char *));
+extern void NDECL(toggle_mouse_support);
+#endif
+
+#ifndef alloca
+#define ALLOCA_HACK    /* used in util/panic.c */
+#endif
+
+#ifndef REDO
+#undef Getchar
+#define Getchar nhgetch
+#endif
+
+#ifdef _MSC_VER
+#if 0
+#pragma warning(disable:4018)  /* signed/unsigned mismatch */
+#pragma warning(disable:4305)  /* init, conv from 'const int' to 'char' */
+#endif
+#pragma warning(disable:4761)  /* integral size mismatch in arg; conv supp*/
+#ifdef YYPREFIX
+#pragma warning(disable:4102)  /* unreferenced label */
+#endif
+#endif
+
+/* UNICODE stuff */
+#define NHSTR_BUFSIZE  255
+#ifdef UNICODE
+       #define NH_W2A(w, a, cb)     ( WideCharToMultiByte(                              \
+                                                                                                  CP_ACP,                      \
+                                                                                                  0,                           \
+                                                                                                  (w),                           \
+                                                                                                  -1,                          \
+                                                                                                  (a),                           \
+                                                                                                  (cb),                          \
+                                                                                                  NULL,                        \
+                                                                                                  NULL), (a) )
+
+       #define NH_A2W(a, w, cb)     ( MultiByteToWideChar(                              \
+                                                                                                  CP_ACP,                      \
+                                                                                                  0,                           \
+                                                                                                  (a),                           \
+                                                                                                  -1,                          \
+                                                                                                  (w),                           \
+                                                                                                  (cb)), (w) )
+#else
+       #define NH_W2A(w, a, cb)     (strncpy((a), (w), (cb)))
+
+       #define NH_A2W(a, w, cb)     (strncpy((w), (a), (cb)))
+#endif
+
+extern int FDECL(set_win32_option, (const char *, const char *));
+
+/* 
+ * 3.4.3 addition - Stuff to help the user with some common, yet significant errors 
+ * Let's make it NOP for now
+ */
+#define interject_assistance(_1,_2,_3,_4)
+#define interject(_1)
+
+/* Missing definitions */
+extern int             mswin_have_input();
+#define kbhit  mswin_have_input
+
+#define getenv(a) ((char*)NULL)
+
+/* __stdio.h__ */
+#define perror(a)
+#define freopen(a, b, c) fopen(a, b)
+extern int isatty(int);
+
+/* __time.h___ */
+#ifndef _TIME_T_DEFINED
+typedef __int64 time_t;        /* time value */
+#define _TIME_T_DEFINED     /* avoid multiple def's of time_t */
+#endif
+
+#ifndef _TM_DEFINED
+struct tm {
+        int tm_sec;     /* seconds after the minute - [0,59] */
+        int tm_min;     /* minutes after the hour - [0,59] */
+        int tm_hour;    /* hours since midnight - [0,23] */
+        int tm_mday;    /* day of the month - [1,31] */
+        int tm_mon;     /* months since January - [0,11] */
+        int tm_year;    /* years since 1900 */
+        int tm_wday;    /* days since Sunday - [0,6] */
+        int tm_yday;    /* days since January 1 - [0,365] */
+        int tm_isdst;   /* daylight savings time flag - - NOT IMPLEMENTED */
+        };
+#define _TM_DEFINED
+#endif
+
+extern struct tm * __cdecl localtime(const time_t *);
+extern time_t __cdecl time(time_t *);
+
+/* __stdio.h__ */
+#ifndef BUFSIZ
+#define BUFSIZ 255
+#endif
+
+#define rewind(stream) (void)fseek( stream, 0L, SEEK_SET )
+
+/* __io.h__ */
+typedef long off_t;
+
+extern int __cdecl close(int);
+extern int __cdecl creat(const char *, int);
+extern int __cdecl eof(int);
+extern long __cdecl lseek(int, long, int);
+extern int __cdecl open(const char *, int, ...);
+extern int __cdecl read(int, void *, unsigned int);
+extern int __cdecl unlink(const char *);
+extern int __cdecl write(int, const void *, unsigned int);
+extern int __cdecl rename(const char *, const char *);
+extern int __cdecl access(const char *, int);
+
+#ifdef DeleteFile
+#undef DeleteFile
+#endif
+#define DeleteFile(a) unlink(a)
+
+int chdir( const char *dirname );
+extern char *getcwd( char *buffer, int maxlen );
+
+/* __stdlib.h__ */
+#define abort()  (void)TerminateProcess(GetCurrentProcess(), 0)
+#ifndef strdup
+#define strdup _strdup
+#endif
+
+/* sys/stat.h */
+#define S_IWRITE  GENERIC_WRITE
+#define S_IREAD   GENERIC_READ
+
+
+/* CE 2.xx is missing even more stuff */
+#if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO)
+#define ZeroMemory(p, s)         memset((p), 0, (s))
+
+extern int __cdecl isupper(int c);
+extern int __cdecl isdigit(int c);
+extern int __cdecl isspace(int c);
+extern int __cdecl isprint(int c);
+
+extern char* __cdecl _strdup(const char* s);
+extern char* __cdecl strrchr( const char *string, int c );
+extern int   __cdecl _stricmp(const char* a, const char* b);
+
+extern FILE * __cdecl fopen(const char* filename, const char *mode);
+extern int    __cdecl fscanf(FILE *f , const char *format, ...);
+extern int __cdecl fprintf(FILE *f , const char *format, ...);
+extern int    __cdecl vfprintf(FILE* f, const char *format, va_list args);
+extern int __cdecl fgetc(FILE * f);
+extern char * __cdecl fgets(char *s, int size, FILE *f);
+extern int    __cdecl printf(const char *format, ...);
+extern int    __cdecl vprintf(const char *format, va_list args);
+extern int    __cdecl puts(const char * s);
+extern FILE*  __cdecl _getstdfilex(int desc);
+extern int __cdecl fclose(FILE * f);
+extern size_t __cdecl fread(void *p, size_t size, size_t count, FILE *f);
+extern size_t __cdecl fwrite(const void *p, size_t size, size_t count, FILE * f);
+extern int    __cdecl fflush(FILE *f);
+extern int    __cdecl feof(FILE *f);
+extern int    __cdecl fseek(FILE *f, long offset, int from);
+extern long   __cdecl ftell(FILE * f);
+
+#endif
+
+/* ARM - the processor; avoids conflict with ARM in hack.h */
+# ifdef ARM
+# undef ARM
+# endif
+
+/* leave - Windows CE defines leave as part of exception handling (__leave)
+   It confilicts with existing sources and since we don't use exceptions it is safe 
+   to undefine it */
+# ifdef leave
+# undef leave
+# endif
+
+#endif /* WCECONF_H */
diff --git a/include/winGnome.h b/include/winGnome.h
new file mode 100644 (file)
index 0000000..b2fad55
--- /dev/null
@@ -0,0 +1,18 @@
+/*     SCCS Id: @(#)winGnome.h 3.4.    2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* Copyright (C) 1998 by Anthony Taylor <tonyt@ptialaska.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef WINGNOME_H
+#define WINGNOME_H
+
+#define E extern
+
+E struct window_procs Gnome_procs;
+
+#undef E
+
+#define NHW_WORN       6
+extern winid WIN_WORN;
+
+#endif /* WINGNOME_H */
diff --git a/include/winX.h b/include/winX.h
new file mode 100644 (file)
index 0000000..7ded018
--- /dev/null
@@ -0,0 +1,411 @@
+/*     SCCS Id: @(#)winX.h     3.4     1996/08/18      */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Definitions for the X11 window-port.  See doc/window.doc for details on
+ * the window interface.
+ */
+#ifndef WINX_H
+#define WINX_H
+
+#ifndef E
+#define E extern
+#endif
+
+#if defined(BOS) || defined(NHSTDC)
+#define DIMENSION_P int
+#else
+# ifdef WIDENED_PROTOTYPES
+#define DIMENSION_P unsigned int
+# else
+#define DIMENSION_P Dimension
+# endif
+#endif
+
+/*
+ * Generic text buffer.
+ */
+#define START_SIZE 512 /* starting text buffer size */
+struct text_buffer {
+    char *text;
+    int  text_size;
+    int  text_last;
+    int  num_lines;
+};
+
+
+/*
+ * Information specific to a map window.
+ */
+struct text_map_info_t {
+    unsigned char   text[ROWNO][COLNO]; /* Actual displayed screen. */
+#ifdef TEXTCOLOR
+    unsigned char   colors[ROWNO][COLNO];      /* Color of each character. */
+    GC             color_gcs[CLR_MAX],         /* GC for each color */
+                   inv_color_gcs[CLR_MAX];     /* GC for each inverse color */
+#define copy_gc     color_gcs[NO_COLOR]
+#define inv_copy_gc inv_color_gcs[NO_COLOR]
+#else
+    GC             copy_gc,                    /* Drawing GC */
+                   inv_copy_gc;                /* Inverse drawing GC */
+#endif
+};
+
+struct tile_map_info_t {
+    unsigned short glyphs[ROWNO][COLNO];       /* Saved glyph numbers. */
+    GC white_gc;
+    GC black_gc;
+    unsigned long image_width;                 /* dimensions of tile image */
+    unsigned long image_height;
+};
+
+struct map_info_t {
+    Dimension      viewport_width,     /* Saved viewport size, so we can */
+                   viewport_height;    /*   clip to cursor on a resize.  */
+    unsigned char   t_start[ROWNO],    /* Starting column for new info. */
+                   t_stop[ROWNO];      /* Ending column for new info. */
+    int                    square_width,       /* Saved font/tile information so */
+                   square_height,      /*   we can calculate the correct */
+                   square_ascent,      /*   placement of changes.        */
+                   square_lbearing;
+    boolean        is_tile;
+    union {
+       struct text_map_info_t *text_map;
+       struct tile_map_info_t *tile_map;
+    } mtype;
+};
+
+
+/*
+ * Information specific to a message window.
+ */
+struct line_element {
+    struct line_element *next;
+    char *line;                        /* char buffer */
+    int  buf_length;           /* length of buffer */
+    int  str_length;           /* length of string in buffer */
+};
+
+struct mesg_info_t {
+    XFontStruct *fs;           /* Font for the window. */
+    int                num_lines;      /* line count */
+    struct line_element *head; /* head of circular line queue */
+    struct line_element *line_here;/* current drawn line position */
+    struct line_element *last_pause;/* point to the line after the prev */
+                               /*     bottom of screen                 */
+    struct line_element *last_pause_head;/* pointer to head of previous */
+                               /* turn                                 */
+    GC         gc;             /* GC for text drawing */
+    int                char_width,     /* Saved font information so we can  */
+               char_height,    /*   calculate the correct placement */
+               char_ascent,    /*   of changes.                     */
+               char_lbearing;
+    Dimension  viewport_width, /* Saved viewport size, so we can adjust */
+               viewport_height;/*   the slider on a resize.             */
+    Boolean    dirty;          /* Lines have been added to the window. */
+};
+
+/*
+ * Information specific to a "text" status window.
+ */
+struct status_info_t {
+    struct text_buffer text;   /* Just a text buffer. */
+};
+
+/*
+ * Information specific to a menu window.  First a structure for each
+ * menu entry, then the structure for each menu window.
+ */
+typedef struct x11_mi {
+    struct x11_mi *next;
+    anything identifier;       /* Opaque type to identify this selection */
+    long pick_count;           /* specific selection count; -1 if none */
+    char *str;                 /* The text of the item. */
+    int  attr;                 /* Attribute for the line. */
+    boolean selected;          /* Been selected? */
+    char selector;             /* Char used to select this entry. */
+    char gselector;            /* Group selector. */
+} x11_menu_item;
+
+struct menu {
+    x11_menu_item *base;       /* Starting pointer for item list. */
+    x11_menu_item *last;       /* End pointer for item list. */
+    const char   *query;       /* Query string. */
+    const char   *gacc;        /* Group accelerators. */
+    int                  count;        /* Number of strings. */
+    String       *list_pointer;/* String list. */
+    Boolean      *sensitive;   /* Active list. */
+    char         curr_selector;/* Next keyboard accelerator to assign, */
+                               /*   if 0, then we're out.              */
+};
+
+struct menu_info_t {
+    struct menu curr_menu;     /* Menu being displayed. */
+    struct menu new_menu;      /* New menu being built. */
+
+    XFontStruct *fs;           /* Font for the window. */
+    long menu_count;           /* number entered by user */
+    Dimension line_height;     /* Total height of a line of text. */
+    Dimension internal_height; /* Internal height between widget & border */
+    Dimension internal_width;  /* Internal width between widget & border */
+    short how;                 /* Menu mode PICK_NONE, PICK_ONE, PICK_ANY */
+    boolean valid_widgets;     /* TRUE if widgets have been created. */
+    boolean is_menu;           /* Has been confirmed to being a menu window. */
+    boolean is_active;         /* TRUE when waiting for user input. */
+    boolean is_up;             /* TRUE when window is popped-up. */
+    boolean cancelled; /* Menu has been explicitly cancelled. */
+    boolean counting;  /* true when menu_count has a valid value */
+};
+
+/*
+ * Information specific to a text window.
+ */
+struct text_info_t {
+    struct text_buffer text;
+    XFontStruct *fs;           /* Font for the text window. */
+    int                max_width;      /* Width of widest line so far. */
+    int                extra_width,    /* Sum of left and right border widths. */
+               extra_height;   /* Sum of top and bottom border widths. */
+    boolean    blocked;        /*  */
+    boolean    destroy_on_ack; /* Destroy this window when acknowleged. */
+#ifdef GRAPHIC_TOMBSTONE
+    boolean    is_rip;         /* This window needs a tombstone. */
+#endif
+};
+
+
+/*
+ * Basic window structure.
+ */
+struct xwindow {
+    int       type;            /* type of nethack window */
+    Widget    popup;           /* direct parent of widget w or viewport */
+    Widget    w;               /* the widget that does things */
+    Dimension pixel_width;     /* window size, in pixels */
+    Dimension pixel_height;
+    int       prevx, cursx;    /* Cursor position, only used by    */
+    int       prevy, cursy;    /*   map and "plain" status windows.*/
+
+    union {
+       struct map_info_t    *Map_info;     /* map window info */
+       struct mesg_info_t   *Mesg_info;    /* message window info */
+       struct status_info_t *Status_info;  /* status window info */
+       struct menu_info_t   *Menu_info;    /* menu window info */
+       struct text_info_t   *Text_info;    /* menu window info */
+    } Win_info;
+    boolean    keep_window;
+};
+
+/* Defines to use for the window information union. */
+#define map_information    Win_info.Map_info
+#define mesg_information   Win_info.Mesg_info
+#define status_information Win_info.Status_info
+#define menu_information   Win_info.Menu_info
+#define text_information   Win_info.Text_info
+
+
+#define MAX_WINDOWS 20         /* max number of open windows */
+
+#define NHW_NONE 0             /* Unallocated window type.  Must be    */
+                               /* different from any other NHW_* type. */
+
+#define NO_CLICK 0             /* No click occured on the map window. Must */
+                               /* be different than CLICK_1 and CLICK_2.   */
+
+#define DEFAULT_MESSAGE_WIDTH 60/* width in chars of the message window */
+
+#define DISPLAY_FILE_SIZE 35   /* Max number of lines in the default   */
+                               /* file display window.                 */
+
+#define MAX_KEY_STRING 64      /* String size for converting a keypress */
+                               /* event into a character(s)             */
+
+#define DEFAULT_LINES_DISPLAYED 12 /* # of lines displayed message window */
+#define MAX_HISTORY 60         /* max history saved on message window */
+
+
+/* Window variables (winX.c). */
+E struct xwindow window_list[MAX_WINDOWS];
+E XtAppContext  app_context;           /* context of application */
+E Widget        toplevel;              /* toplevel widget */
+E Atom          wm_delete_window;      /* delete window protocol */
+E boolean       exit_x_event;          /* exit condition for event loop */
+#define EXIT_ON_KEY_PRESS          0   /* valid values for exit_x_event */
+#define EXIT_ON_KEY_OR_BUTTON_PRESS 1
+#define EXIT_ON_EXIT               2
+#define EXIT_ON_SENT_EVENT         3
+E int click_x, click_y, click_button, updated_inventory;
+
+typedef struct {
+    Boolean slow;
+    Boolean autofocus;
+    Boolean message_line;
+    Boolean double_tile_size;  /* double tile size */
+    String  tile_file;         /* name of file to open for tiles */
+    String  icon;              /* name of desired icon */
+    int     message_lines;     /* number of lines to attempt to show */
+    String  pet_mark_bitmap;   /* X11 bitmap file used to mark pets */
+    Pixel   pet_mark_color;    /* color of pet mark */
+#ifdef GRAPHIC_TOMBSTONE
+    String  tombstone;         /* name of XPM file for tombstone */
+    int     tombtext_x;                /* x-coord of center of first tombstone text */
+    int     tombtext_y;                /* y-coord of center of first tombstone text */
+    int     tombtext_dx;       /* x-displacement between tombstone line */
+    int     tombtext_dy;       /* y-displacement between tombstone line */
+#endif
+} AppResources;
+
+E AppResources appResources;
+E void (*input_func)();
+
+extern struct window_procs X11_procs;
+
+/* Check for an invalid window id. */
+#define check_winid(window)                                    \
+       if ((window) < 0 || (window) >= MAX_WINDOWS) {          \
+           panic("illegal windid [%d] in %s at line %d",       \
+               window, __FILE__, __LINE__);                    \
+       }
+
+
+/* ### dialogs.c ### */
+E Widget FDECL(CreateDialog, (Widget, String, XtCallbackProc, XtCallbackProc));
+E void FDECL(SetDialogPrompt,(Widget, String));
+E String FDECL(GetDialogResponse,(Widget));
+E void FDECL(SetDialogResponse,(Widget, String));
+E void FDECL(positionpopup,(Widget,BOOLEAN_P));
+
+/* ### winX.c ### */
+E struct xwindow *FDECL(find_widget,(Widget));
+E Boolean FDECL(nhApproxColor,(Screen*, Colormap, char*, XColor*));
+E Dimension FDECL(nhFontHeight,(Widget));
+E char FDECL(key_event_to_char,(XKeyEvent*));
+E void FDECL(msgkey, (Widget, XtPointer, XEvent*));
+E void FDECL(nh_XtPopup, (Widget, int, Widget));
+E void FDECL(nh_XtPopdown, (Widget));
+E void NDECL(win_X11_init);
+E void FDECL(nh_keyscroll, (Widget, XEvent*, String*, Cardinal*));
+
+/* ### winmesg.c ### */
+E void FDECL(set_message_slider, (struct xwindow*));
+E void FDECL(create_message_window,(struct xwindow*, BOOLEAN_P, Widget));
+E void FDECL(destroy_message_window,(struct xwindow*));
+E void FDECL(display_message_window, (struct xwindow*));
+E void FDECL(append_message,(struct xwindow*, const char*));
+E void FDECL(set_last_pause, (struct xwindow*));
+
+/* ### winmap.c ### */
+E void NDECL(post_process_tiles);
+E void FDECL(check_cursor_visibility,(struct xwindow*));
+E void FDECL(display_map_window,(struct xwindow*));
+E void FDECL(clear_map_window,(struct xwindow*));
+E void FDECL(map_input, (Widget, XEvent*, String*, Cardinal*));
+E void FDECL(set_map_size,(struct xwindow*, DIMENSION_P, DIMENSION_P));
+E void FDECL(create_map_window,(struct xwindow*, BOOLEAN_P, Widget));
+E void FDECL(destroy_map_window,(struct xwindow*));
+E int  FDECL(x_event,(int));
+
+/* ### winmenu.c ### */
+E void FDECL(menu_delete, (Widget, XEvent*, String*, Cardinal*));
+E void FDECL(menu_key,(Widget, XEvent*, String*, Cardinal*));
+E void FDECL(create_menu_window,(struct xwindow*));
+E void FDECL(destroy_menu_window,(struct xwindow*));
+
+/* ### winmisc.c ### */
+E void FDECL(ps_key,(Widget, XEvent*, String*, Cardinal*)); /* player selection action */
+E void FDECL(race_key,(Widget, XEvent*, String*, Cardinal*)); /* race selection action */
+E void FDECL(gend_key, (Widget,XEvent *,String *,Cardinal *)); /* gender */
+E void FDECL(algn_key, (Widget,XEvent *,String *,Cardinal *)); /* alignment */
+E void FDECL(ec_delete, (Widget, XEvent*, String*, Cardinal*));
+E void FDECL(ec_key,(Widget, XEvent*, String*, Cardinal*)); /* extended command action */
+
+/* ### winstatus.c ### */
+E void FDECL(create_status_window,(struct xwindow*, BOOLEAN_P, Widget));
+E void FDECL(destroy_status_window,(struct xwindow*));
+E void FDECL(adjust_status,(struct xwindow*, const char*));
+E void NDECL(null_out_status);
+E void NDECL(check_turn_events);
+
+/* ### wintext.c ### */
+E void FDECL(delete_text, (Widget, XEvent*, String*, Cardinal*));
+E void FDECL(dismiss_text,(Widget, XEvent*, String*, Cardinal*));
+E void FDECL(key_dismiss_text,(Widget, XEvent*, String*, Cardinal*));
+#ifdef GRAPHIC_TOMBSTONE
+E void FDECL(rip_dismiss_text,(Widget, XEvent*, String*, Cardinal*));
+#endif
+E void FDECL(add_to_text_window,(struct xwindow*, int, const char*));
+E void FDECL(display_text_window,(struct xwindow*, BOOLEAN_P));
+E void FDECL(create_text_window,(struct xwindow*));
+E void FDECL(destroy_text_window,(struct xwindow*));
+E void FDECL(clear_text_window,(struct xwindow*));
+E void FDECL(append_text_buffer,(struct text_buffer*, const char*, BOOLEAN_P)); /* text buffer routines */
+E void FDECL(init_text_buffer,(struct text_buffer*));
+E void FDECL(clear_text_buffer,(struct text_buffer*));
+E void FDECL(free_text_buffer,(struct text_buffer*));
+#ifdef GRAPHIC_TOMBSTONE
+E void FDECL(calculate_rip_text, (int));
+#endif
+
+
+/* ### winval.c ### */
+E Widget FDECL(create_value,(Widget, const char*));
+E void  FDECL(set_name,(Widget, char*));
+E void  FDECL(set_name_width,(Widget, int));
+E int   FDECL(get_name_width,(Widget));
+E void  FDECL(set_value,(Widget, const char*));
+E void  FDECL(set_value_width,(Widget, int));
+E int   FDECL(get_value_width,(Widget));
+E void  FDECL(hilight_value,(Widget));
+E void  FDECL(swap_fg_bg,(Widget));
+
+/* external declarations */
+E void FDECL(X11_init_nhwindows, (int *, char **));
+E void NDECL(X11_player_selection);
+E void NDECL(X11_askname);
+E void NDECL(X11_get_nh_event) ;
+E void FDECL(X11_exit_nhwindows, (const char *));
+E void FDECL(X11_suspend_nhwindows, (const char *));
+E void NDECL(X11_resume_nhwindows);
+E winid FDECL(X11_create_nhwindow, (int));
+E void FDECL(X11_clear_nhwindow, (winid));
+E void FDECL(X11_display_nhwindow, (winid, BOOLEAN_P));
+E void FDECL(X11_destroy_nhwindow, (winid));
+E void FDECL(X11_curs, (winid,int,int));
+E void FDECL(X11_putstr, (winid, int, const char *));
+E void FDECL(X11_display_file, (const char *, BOOLEAN_P));
+E void FDECL(X11_start_menu, (winid));
+E void FDECL(X11_add_menu, (winid,int,const ANY_P *,
+                       CHAR_P, CHAR_P, int, const char *, BOOLEAN_P));
+E void FDECL(X11_end_menu, (winid, const char *));
+E int FDECL(X11_select_menu, (winid, int, MENU_ITEM_P **));
+E void NDECL(X11_update_inventory);
+E void NDECL(X11_mark_synch);
+E void NDECL(X11_wait_synch);
+#ifdef CLIPPING
+E void FDECL(X11_cliparound, (int, int));
+#endif
+E void FDECL(X11_print_glyph, (winid,XCHAR_P,XCHAR_P,int));
+E void FDECL(X11_raw_print, (const char *));
+E void FDECL(X11_raw_print_bold, (const char *));
+E int NDECL(X11_nhgetch);
+E int FDECL(X11_nh_poskey, (int *, int *, int *));
+E void NDECL(X11_nhbell);
+E int NDECL(X11_doprev_message);
+E char FDECL(X11_yn_function, (const char *, const char *, CHAR_P));
+E void FDECL(X11_getlin, (const char *,char *));
+E int NDECL(X11_get_ext_cmd);
+E void FDECL(X11_number_pad, (int));
+E void NDECL(X11_delay_output);
+
+/* other defs that really should go away (they're tty specific) */
+E void NDECL(X11_start_screen);
+E void NDECL(X11_end_screen);
+
+#ifdef GRAPHIC_TOMBSTONE
+E void FDECL(X11_outrip, (winid,int));
+#else
+E void FDECL(genl_outrip, (winid,int));
+#endif
+
+#endif /* WINX_H */
diff --git a/include/winami.h b/include/winami.h
new file mode 100644 (file)
index 0000000..ea2c0ec
--- /dev/null
@@ -0,0 +1,126 @@
+/*     SCCS Id: @(#)winami.h   3.4     1993/01/17      */
+/* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1991. */
+/* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1992, 1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef WINAMI_H
+#define WINAMI_H
+
+#define MAXWINTAGS     5
+
+/*
+ * Information specific to a menu window.  First a structure for each
+ * menu entry, then the structure for each menu window.
+ */
+typedef struct amii_mi {
+    struct amii_mi *next;
+    anything identifier;       /* Opaque type to identify this selection */
+    long glyph;                        /* Glyph for menu item */
+    long count;                 /* Object count */
+    char selected;             /* Been selected? */
+    char selector;             /* Char used to select this entry. */
+    char gselector;            /* Group selector */
+    char canselect;            /* Can user select this entry. */
+    char attr;                 /* Attribute for the line. */
+    char *str;                 /* The text of the item. */
+} amii_menu_item;
+
+struct amii_menu
+{
+    amii_menu_item *items;     /* Starting pointer for item list. */
+    amii_menu_item *last;      /* End pointer for item list. */
+    const char    *query;      /* Query string */
+    int                    count;      /* Number of strings. */
+    char           chr;        /* Character to assign for accelerator */
+};
+
+/* descriptor for Amiga Intuition-based windows.  If we decide to cope with
+ * tty-style windows also, then things will need to change. */
+/* per-window data */
+struct amii_WinDesc {
+    xchar type;                        /* type of window */
+    struct amii_menu menu;
+    boolean active;            /* true if window is active */
+    boolean wasup;             /* true if menu/text window was already open */
+    short disprows;            /* Rows displayed so far (used for paging in message win) */
+    xchar offx, offy;          /* offset from topleft of display */
+    short vwx, vwy, vcx, vcy;  /* View cursor location */
+    short rows, cols;          /* dimensions */
+    short curx, cury;          /* current cursor position */
+    short maxrow, maxcol;      /* the maximum size used -- for INVEN wins */
+                               /* maxcol is also used by WIN_MESSAGE for */
+                               /* tracking the ^P command */
+    char **data;               /* window data [row][column] */
+    menu_item *mi;             /* Menu information */
+    char *resp;                        /* valid menu responses (for NHW_INVEN) */
+    char *canresp;             /* cancel responses; 1st is the return value */
+    char *morestr;             /* string to display instead of default */
+/* amiga stuff */
+    struct Window *win;                /* Intuition window pointer */
+#ifdef INTUI_NEW_LOOK
+    struct ExtNewWindow *newwin;       /* NewWindow alloc'd */
+#else
+    struct NewWindow *newwin;  /* ExtNewWindow alloc'd */
+#endif
+#ifdef INTUI_NEW_LOOK
+    struct TagItem wintags[ MAXWINTAGS ];/* Tag items for this window */
+#else
+    long wintags[ MAXWINTAGS*2 ];
+#endif
+    void *hook;                        /* Hook structure pointer for tiles version */
+#define FLMAP_INGLYPH  1       /* An NHW_MAP window is in glyph mode */
+#define FLMAP_CURSUP   2       /* An NHW_MAP window has the cursor displayed */
+#define FLMAP_SKIP     4
+#define FLMSG_FIRST    1       /* First message in the NHW_MESSAGE window for this turn */
+    long wflags;
+    short cursx, cursy;                /* Where the cursor is displayed at */
+    short curs_apen,           /* Color cursor is displayed in */
+         curs_bpen;
+};
+
+/* descriptor for intuition-based displays -- all the per-display data */
+/* this is a generic thing - think of it as Screen level */
+
+struct amii_DisplayDesc {
+/* we need this for Screen size (which will vary with display mode) */
+    uchar rows, cols;          /* width & height of display in text units */
+    short xpix, ypix;          /* width and height of display in pixels */
+    int toplin;                        /* flag for topl stuff */
+    int rawprint;              /* number of raw_printed lines since synch */
+    winid lastwin;             /* last window used for I/O */
+};
+
+typedef enum {
+    WEUNK, WEKEY, WEMOUSE, WEMENU,
+} WETYPE;
+
+typedef struct WEVENT
+{
+    WETYPE type;
+    union {
+       int key;
+       struct {
+           int x, y;
+           int qual;
+       } mouse;
+       long menucode;
+    } un;
+} WEVENT;
+
+#define MAXWIN 20              /* maximum number of windows, cop-out */
+
+/* port specific variable declarations */
+extern winid WIN_BASE;
+extern winid WIN_OVER;
+#define NHW_BASE       6
+#define NHW_OVER       7               /* overview window */
+
+
+extern struct amii_WinDesc *amii_wins[MAXWIN + 1];
+
+extern struct amii_DisplayDesc *amiIDisplay;   /* the Amiga Intuition descriptor */
+
+extern char morc;              /* last character typed to xwaitforspace */
+extern char defmorestr[];      /* default --more-- prompt */
+
+#endif /* WINAMI_H */
diff --git a/include/wingem.h b/include/wingem.h
new file mode 100644 (file)
index 0000000..cef5418
--- /dev/null
@@ -0,0 +1,112 @@
+/*     SCCS Id: @(#)wingem.h   3.4     1999/12/10      */
+/* Copyright (c) Christian Bressler, 1999                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef WINGEM_H
+#define WINGEM_H
+
+#define E extern
+
+/* menu structure */
+typedef struct Gmi{
+       struct Gmi *Gmi_next;
+       int Gmi_glyph;
+       long Gmi_identifier;
+       char Gmi_accelerator, Gmi_groupacc;
+       int Gmi_attr;
+       char *Gmi_str;
+       long Gmi_count;
+       int Gmi_selected;
+} Gem_menu_item;
+
+#define MAXWIN 20              /* maximum number of windows, cop-out */
+
+extern struct window_procs Gem_procs;
+
+/* ### wingem1.c ### */
+#ifdef CLIPPING
+E void NDECL(setclipped);
+#endif
+E void FDECL(docorner, (int, int));
+E void NDECL(end_glyphout);
+E void FDECL(g_putch, (int));
+E void NDECL(win_Gem_init);
+E int NDECL(mar_gem_init);
+E char NDECL(mar_ask_class);
+E char * NDECL(mar_ask_name);
+E int FDECL(mar_create_window, (int));
+E void FDECL(mar_destroy_nhwindow, (int));
+E void FDECL(mar_print_glyph, (int, int, int, int));
+E void FDECL(mar_print_line, (int, int, int, char *));
+E void FDECL(mar_set_message, (char *, char *, char *));
+E Gem_menu_item *NDECL(mar_hol_inv);
+E void FDECL(mar_set_menu_type,(int));
+E void NDECL(mar_reverse_menu);
+E void FDECL(mar_set_menu_title, (const char *));
+E void NDECL(mar_set_accelerators);
+E void FDECL(mar_add_menu, (winid, Gem_menu_item *));
+E void FDECL(mar_change_menu_2_text, (winid));
+E void FDECL(mar_add_message, (const char *));
+E void NDECL(mar_status_dirty);
+E int FDECL(mar_hol_win_type, (int));
+E void NDECL(mar_clear_messagewin);
+E void FDECL(mar_set_no_glyph, (int));
+E void NDECL(mar_map_curs_weiter);
+
+/* external declarations */
+E void FDECL(Gem_init_nhwindows, (int *, char **));
+E void NDECL(Gem_player_selection);
+E void NDECL(Gem_askname);
+E void NDECL(Gem_get_nh_event) ;
+E void FDECL(Gem_exit_nhwindows, (const char *));
+E void FDECL(Gem_suspend_nhwindows, (const char *));
+E void NDECL(Gem_resume_nhwindows);
+E winid FDECL(Gem_create_nhwindow, (int));
+E void FDECL(Gem_clear_nhwindow, (winid));
+E void FDECL(Gem_display_nhwindow, (winid, BOOLEAN_P));
+E void FDECL(Gem_dismiss_nhwindow, (winid));
+E void FDECL(Gem_destroy_nhwindow, (winid));
+E void FDECL(Gem_curs, (winid,int,int));
+E void FDECL(Gem_putstr, (winid, int, const char *));
+E void FDECL(Gem_display_file, (const char *, BOOLEAN_P));
+E void FDECL(Gem_start_menu, (winid));
+E void FDECL(Gem_add_menu, (winid,int,const ANY_P *,
+                       CHAR_P,CHAR_P,int,const char *, BOOLEAN_P));
+E void FDECL(Gem_end_menu, (winid, const char *));
+E int FDECL(Gem_select_menu, (winid, int, MENU_ITEM_P **));
+E char FDECL(Gem_message_menu, (CHAR_P,int,const char *));
+E void NDECL(Gem_update_inventory);
+E void NDECL(Gem_mark_synch);
+E void NDECL(Gem_wait_synch);
+#ifdef CLIPPING
+E void FDECL(Gem_cliparound, (int, int));
+#endif
+#ifdef POSITIONBAR
+E void FDECL(Gem_update_positionbar, (char *));
+#endif
+E void FDECL(Gem_print_glyph, (winid,XCHAR_P,XCHAR_P,int));
+E void FDECL(Gem_raw_print, (const char *));
+E void FDECL(Gem_raw_print_bold, (const char *));
+E int NDECL(Gem_nhgetch);
+E int FDECL(Gem_nh_poskey, (int *, int *, int *));
+E void NDECL(Gem_nhbell);
+E int NDECL(Gem_doprev_message);
+E char FDECL(Gem_yn_function, (const char *, const char *, CHAR_P));
+E void FDECL(Gem_getlin, (const char *,char *));
+E int NDECL(Gem_get_ext_cmd);
+E void FDECL(Gem_number_pad, (int));
+E void NDECL(Gem_delay_output);
+#ifdef CHANGE_COLOR
+E void FDECL(Gem_change_color,(int color,long rgb,int reverse));
+E char * NDECL(Gem_get_color_string);
+#endif
+
+/* other defs that really should go away (they're tty specific) */
+E void NDECL(Gem_start_screen);
+E void NDECL(Gem_end_screen);
+
+E void FDECL(genl_outrip, (winid,int));
+
+#undef E
+
+#endif /* WINGEM_H */
diff --git a/include/winprocs.h b/include/winprocs.h
new file mode 100644 (file)
index 0000000..2e1f2e9
--- /dev/null
@@ -0,0 +1,220 @@
+/*     SCCS Id: @(#)winprocs.h 3.4     2003/01/08      */
+/* Copyright (c) David Cohrs, 1992                               */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef WINPROCS_H
+#define WINPROCS_H
+
+struct window_procs {
+    const char *name;
+    unsigned long wincap;      /* window port capability options supported */
+    unsigned long wincap2;     /* additional window port capability options supported */
+    void FDECL((*win_init_nhwindows), (int *, char **));
+    void NDECL((*win_player_selection));
+    void NDECL((*win_askname));
+    void NDECL((*win_get_nh_event)) ;
+    void FDECL((*win_exit_nhwindows), (const char *));
+    void FDECL((*win_suspend_nhwindows), (const char *));
+    void NDECL((*win_resume_nhwindows));
+    winid FDECL((*win_create_nhwindow), (int));
+    void FDECL((*win_clear_nhwindow), (winid));
+    void FDECL((*win_display_nhwindow), (winid, BOOLEAN_P));
+    void FDECL((*win_destroy_nhwindow), (winid));
+    void FDECL((*win_curs), (winid,int,int));
+    void FDECL((*win_putstr), (winid, int, const char *));
+    void FDECL((*win_display_file), (const char *, BOOLEAN_P));
+    void FDECL((*win_start_menu), (winid));
+    void FDECL((*win_add_menu), (winid,int,const ANY_P *,
+               CHAR_P,CHAR_P,int,const char *, BOOLEAN_P));
+    void FDECL((*win_end_menu), (winid, const char *));
+    int FDECL((*win_select_menu), (winid, int, MENU_ITEM_P **));
+    char FDECL((*win_message_menu), (CHAR_P,int,const char *));
+    void NDECL((*win_update_inventory));
+    void NDECL((*win_mark_synch));
+    void NDECL((*win_wait_synch));
+#ifdef CLIPPING
+    void FDECL((*win_cliparound), (int, int));
+#endif
+#ifdef POSITIONBAR
+    void FDECL((*win_update_positionbar), (char *));
+#endif
+    void FDECL((*win_print_glyph), (winid,XCHAR_P,XCHAR_P,int));
+    void FDECL((*win_raw_print), (const char *));
+    void FDECL((*win_raw_print_bold), (const char *));
+    int NDECL((*win_nhgetch));
+    int FDECL((*win_nh_poskey), (int *, int *, int *));
+    void NDECL((*win_nhbell));
+    int NDECL((*win_doprev_message));
+    char FDECL((*win_yn_function), (const char *, const char *, CHAR_P));
+    void FDECL((*win_getlin), (const char *,char *));
+    int NDECL((*win_get_ext_cmd));
+    void FDECL((*win_number_pad), (int));
+    void NDECL((*win_delay_output));
+#ifdef CHANGE_COLOR
+    void FDECL((*win_change_color), (int,long,int));
+#ifdef MAC
+    void FDECL((*win_change_background), (int));
+    short FDECL((*win_set_font_name), (winid, char *));
+#endif
+    char * NDECL((*win_get_color_string));
+#endif
+
+    /* other defs that really should go away (they're tty specific) */
+    void NDECL((*win_start_screen));
+    void NDECL((*win_end_screen));
+
+    void FDECL((*win_outrip), (winid,int));
+    void FDECL((*win_preference_update), (const char *));
+};
+
+extern NEARDATA struct window_procs windowprocs;
+
+/*
+ * If you wish to only support one window system and not use procedure
+ * pointers, add the appropriate #ifdef below.
+ */
+
+#define init_nhwindows (*windowprocs.win_init_nhwindows)
+#define player_selection (*windowprocs.win_player_selection)
+#define askname (*windowprocs.win_askname)
+#define get_nh_event (*windowprocs.win_get_nh_event)
+#define exit_nhwindows (*windowprocs.win_exit_nhwindows)
+#define suspend_nhwindows (*windowprocs.win_suspend_nhwindows)
+#define resume_nhwindows (*windowprocs.win_resume_nhwindows)
+#define create_nhwindow (*windowprocs.win_create_nhwindow)
+#define clear_nhwindow (*windowprocs.win_clear_nhwindow)
+#define display_nhwindow (*windowprocs.win_display_nhwindow)
+#define destroy_nhwindow (*windowprocs.win_destroy_nhwindow)
+#define curs (*windowprocs.win_curs)
+#define putstr (*windowprocs.win_putstr)
+#define display_file (*windowprocs.win_display_file)
+#define start_menu (*windowprocs.win_start_menu)
+#define add_menu (*windowprocs.win_add_menu)
+#define end_menu (*windowprocs.win_end_menu)
+#define select_menu (*windowprocs.win_select_menu)
+#define message_menu (*windowprocs.win_message_menu)
+#define update_inventory (*windowprocs.win_update_inventory)
+#define mark_synch (*windowprocs.win_mark_synch)
+#define wait_synch (*windowprocs.win_wait_synch)
+#ifdef CLIPPING
+#define cliparound (*windowprocs.win_cliparound)
+#endif
+#ifdef POSITIONBAR
+#define update_positionbar (*windowprocs.win_update_positionbar)
+#endif
+#define print_glyph (*windowprocs.win_print_glyph)
+#define raw_print (*windowprocs.win_raw_print)
+#define raw_print_bold (*windowprocs.win_raw_print_bold)
+#define nhgetch (*windowprocs.win_nhgetch)
+#define nh_poskey (*windowprocs.win_nh_poskey)
+#define nhbell (*windowprocs.win_nhbell)
+#define nh_doprev_message (*windowprocs.win_doprev_message)
+#define getlin (*windowprocs.win_getlin)
+#define get_ext_cmd (*windowprocs.win_get_ext_cmd)
+#define number_pad (*windowprocs.win_number_pad)
+#define delay_output (*windowprocs.win_delay_output)
+#ifdef CHANGE_COLOR
+#define change_color (*windowprocs.win_change_color)
+#ifdef MAC
+#define change_background (*windowprocs.win_change_background)
+#define set_font_name (*windowprocs.win_set_font_name)
+#endif
+#define get_color_string (*windowprocs.win_get_color_string)
+#endif
+
+/* 3.4.2: There is a real yn_function() in the core now, which does
+ *        some buffer length validation on the parameters prior to
+ *        invoking the window port routine. yn_function() is in cmd.c
+ */
+/* #define yn_function (*windowprocs.win_yn_function) */
+
+/* other defs that really should go away (they're tty specific) */
+#define start_screen (*windowprocs.win_start_screen)
+#define end_screen (*windowprocs.win_end_screen)
+
+#define outrip (*windowprocs.win_outrip)
+#define preference_update (*windowprocs.win_preference_update)
+
+/*
+ * WINCAP
+ * Window port preference capability bits.
+ * Some day this might be better in its own wincap.h file.
+ */
+#define WC_COLOR        0x01L          /* 01 Port can display things in color       */
+#define WC_HILITE_PET   0x02L          /* 02 supports hilite pet                    */
+#define WC_ASCII_MAP    0x04L          /* 03 supports an ascii map                  */
+#define WC_TILED_MAP    0x08L          /* 04 supports a tiled map                   */
+#define WC_PRELOAD_TILES 0x10L         /* 05 supports pre-loading tiles             */
+#define WC_TILE_WIDTH   0x20L          /* 06 prefer this width of tile              */
+#define WC_TILE_HEIGHT  0x40L          /* 07 prefer this height of tile             */
+#define WC_TILE_FILE    0x80L          /* 08 alternative tile file name             */
+#define WC_INVERSE      0x100L         /* 09 Port supports inverse video            */
+#define WC_ALIGN_MESSAGE 0x200L                /* 10 supports message alignmt top|b|l|r     */
+#define WC_ALIGN_STATUS         0x400L         /* 11 supports status alignmt top|b|l|r      */
+#define WC_VARY_MSGCOUNT 0x800L                /* 12 supports varying message window        */
+#define WC_FONT_MAP     0x1000L        /* 13 supports specification of map win font */
+#define WC_FONT_MESSAGE         0x2000L        /* 14 supports specification of msg win font */
+#define WC_FONT_STATUS  0x4000L        /* 15 supports specification of sts win font */
+#define WC_FONT_MENU    0x8000L        /* 16 supports specification of mnu win font */
+#define WC_FONT_TEXT    0x10000L       /* 17 supports specification of txt win font */
+#define WC_FONTSIZ_MAP  0x20000L       /* 18 supports specification of map win font */
+#define WC_FONTSIZ_MESSAGE 0x40000L    /* 19 supports specification of msg win font */
+#define WC_FONTSIZ_STATUS 0x80000L     /* 20 supports specification of sts win font */
+#define WC_FONTSIZ_MENU         0x100000L      /* 21 supports specification of mnu win font */
+#define WC_FONTSIZ_TEXT         0x200000L      /* 22 supports specification of txt win font */
+#define WC_SCROLL_MARGIN 0x400000L     /* 23 supports setting scroll margin for map */
+#define WC_SPLASH_SCREEN 0x800000L     /* 24 supports display of splash screen      */
+#define WC_POPUP_DIALOG         0x1000000L     /* 25 supports queries in pop dialogs        */
+#define WC_SCROLL_AMOUNT 0x2000000L    /* 26 scroll this amount at scroll margin    */
+#define WC_EIGHT_BIT_IN         0x4000000L     /* 27 8-bit character input                  */
+#define WC_PERM_INVENT  0x8000000L     /* 28 8-bit character input                  */
+#define WC_MAP_MODE     0x10000000L    /* 29 map_mode option                        */
+#define WC_WINDOWCOLORS  0x20000000L   /* 30 background color for message window    */
+#define WC_PLAYER_SELECTION  0x40000000L /* 31 background color for message window    */
+#define WC_MOUSE_SUPPORT 0x80000000L   /* 32 mouse support                          */
+                                       /* no free bits */
+
+#define WC2_FULLSCREEN         0x01L   /* 01 display full screen                    */
+#define WC2_SOFTKEYBOARD       0x02L   /* 02 software keyboard                      */
+#define WC2_WRAPTEXT           0x04L   /* 04 wrap long lines of text                */
+                                       /* 29 free bits */
+
+#define ALIGN_LEFT     1
+#define ALIGN_RIGHT    2
+#define ALIGN_TOP      3
+#define ALIGN_BOTTOM   4
+
+/* player_selection */
+#define VIA_DIALOG     0
+#define VIA_PROMPTS    1
+
+/* map_mode settings - deprecated */
+#define MAP_MODE_TILES         0
+#define MAP_MODE_ASCII4x6      1
+#define MAP_MODE_ASCII6x8      2
+#define MAP_MODE_ASCII8x8      3
+#define MAP_MODE_ASCII16x8     4
+#define MAP_MODE_ASCII7x12     5
+#define MAP_MODE_ASCII8x12     6
+#define MAP_MODE_ASCII16x12    7
+#define MAP_MODE_ASCII12x16    8
+#define MAP_MODE_ASCII10x18    9
+#define MAP_MODE_ASCII_FIT_TO_SCREEN 10
+#define MAP_MODE_TILES_FIT_TO_SCREEN 11
+
+#if 0
+#define WC_SND_SOUND    0x01L          /* 01 Port has some sound capabilities       */
+#define WC_SND_SPEAKER  0x02L          /* 02 Sound supported via built-in speaker   */
+#define WC_SND_STEREO   0x04L          /* 03 Stereo sound supported                 */
+#define WC_SND_RAW      0x08L          /* 04 Raw sound supported                    */
+#define WC_SND_WAVE     0x10L          /* 05 Wave support                           */
+#define WC_SND_MIDI     0x20L          /* 06 Midi support                           */
+                                       /* 26 free bits */
+#endif
+
+struct wc_Opt {
+       const char *wc_name;
+       unsigned long wc_bit;
+};
+
+#endif /* WINPROCS_H */
diff --git a/include/wintty.h b/include/wintty.h
new file mode 100644 (file)
index 0000000..fc123d8
--- /dev/null
@@ -0,0 +1,255 @@
+/*     SCCS Id: @(#)wintty.h   3.4     1996/02/18      */
+/* Copyright (c) David Cohrs, 1991,1992                                  */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef WINTTY_H
+#define WINTTY_H
+
+#define E extern
+
+#ifndef WINDOW_STRUCTS
+#define WINDOW_STRUCTS
+
+/* menu structure */
+typedef struct tty_mi {
+    struct tty_mi *next;
+    anything identifier;       /* user identifier */
+    long count;                        /* user count */
+    char *str;                 /* description string (including accelerator) */
+    int attr;                  /* string attribute */
+    boolean selected;          /* TRUE if selected by user */
+    char selector;             /* keyboard accelerator */
+    char gselector;            /* group accelerator */
+} tty_menu_item;
+
+/* descriptor for tty-based windows */
+struct WinDesc {
+    int flags;                 /* window flags */
+    xchar type;                        /* type of window */
+    boolean active;            /* true if window is active */
+    uchar offx, offy;          /* offset from topleft of display */
+    short rows, cols;          /* dimensions */
+    short curx, cury;          /* current cursor position */
+    short maxrow, maxcol;      /* the maximum size used -- for MENU wins */
+                               /* maxcol is also used by WIN_MESSAGE for */
+                               /* tracking the ^P command */
+    short *datlen;             /* allocation size for *data */
+    char **data;               /* window data [row][column] */
+    char *morestr;             /* string to display instead of default */
+    tty_menu_item *mlist;      /* menu information (MENU) */
+    tty_menu_item **plist;     /* menu page pointers (MENU) */
+    short plist_size;          /* size of allocated plist (MENU) */
+    short npages;              /* number of pages in menu (MENU) */
+    short nitems;              /* total number of items (MENU) */
+    short how;                 /* menu mode - pick 1 or N (MENU) */
+    char menu_ch;              /* menu char (MENU) */
+};
+
+/* window flags */
+#define WIN_CANCELLED 1
+#define WIN_STOP 1             /* for NHW_MESSAGE; stops output */
+
+/* descriptor for tty-based displays -- all the per-display data */
+struct DisplayDesc {
+    uchar rows, cols;          /* width and height of tty display */
+    uchar curx, cury;          /* current cursor position on the screen */
+#ifdef TEXTCOLOR
+    int color;                 /* current color */
+#endif
+    int attrs;                 /* attributes in effect */
+    int toplin;                        /* flag for topl stuff */
+    int rawprint;              /* number of raw_printed lines since synch */
+    int inmore;                        /* non-zero if more() is active */
+    int inread;                        /* non-zero if reading a character */
+    int intr;                  /* non-zero if inread was interrupted */
+    winid lastwin;             /* last window used for I/O */
+    char dismiss_more;         /* extra character accepted at --More-- */
+};
+
+#endif /* WINDOW_STRUCTS */
+
+#define MAXWIN 20              /* maximum number of windows, cop-out */
+
+/* tty dependent window types */
+#ifdef NHW_BASE
+#undef NHW_BASE
+#endif
+#define NHW_BASE    6
+
+extern struct window_procs tty_procs;
+
+/* port specific variable declarations */
+extern winid BASE_WINDOW;
+
+extern struct WinDesc *wins[MAXWIN];
+
+extern struct DisplayDesc *ttyDisplay; /* the tty display descriptor */
+
+extern char morc;              /* last character typed to xwaitforspace */
+extern char defmorestr[];      /* default --more-- prompt */
+
+/* port specific external function references */
+
+/* ### getline.c ### */
+E void FDECL(xwaitforspace, (const char *));
+
+/* ### termcap.c, video.c ### */
+
+E void FDECL(tty_startup,(int*, int*));
+#ifndef NO_TERMS
+E void NDECL(tty_shutdown);
+#endif
+#if defined(apollo)
+/* Apollos don't widen old-style function definitions properly -- they try to
+ * be smart and use the prototype, or some such strangeness.  So we have to
+ * define UNWIDENDED_PROTOTYPES (in tradstdc.h), which makes CHAR_P below a
+ * char.  But the tputs termcap call was compiled as if xputc's argument
+ * actually would be expanded. So here, we have to make an exception. */
+E void FDECL(xputc, (int));
+#else
+E void FDECL(xputc, (CHAR_P));
+#endif
+E void FDECL(xputs, (const char *));
+#if defined(SCREEN_VGA) || defined(SCREEN_8514)
+E void FDECL(xputg, (int, int, unsigned));
+#endif
+E void NDECL(cl_end);
+E void NDECL(clear_screen);
+E void NDECL(home);
+E void NDECL(standoutbeg);
+E void NDECL(standoutend);
+# if 0
+E void NDECL(revbeg);
+E void NDECL(boldbeg);
+E void NDECL(blinkbeg);
+E void NDECL(dimbeg);
+E void NDECL(m_end);
+# endif
+E void NDECL(backsp);
+E void NDECL(graph_on);
+E void NDECL(graph_off);
+E void NDECL(cl_eos);
+
+/*
+ * termcap.c (or facsimiles in other ports) is the right place for doing
+ * strange and arcane things such as outputting escape sequences to select
+ * a color or whatever.  wintty.c should concern itself with WHERE to put
+ * stuff in a window.
+ */
+E void FDECL(term_start_attr,(int attr));
+E void FDECL(term_end_attr,(int attr));
+E void NDECL(term_start_raw_bold);
+E void NDECL(term_end_raw_bold);
+
+#ifdef TEXTCOLOR
+E void NDECL(term_end_color);
+E void FDECL(term_start_color,(int color));
+E int FDECL(has_color,(int color));
+#endif /* TEXTCOLOR */
+
+
+/* ### topl.c ### */
+
+E void FDECL(addtopl, (const char *));
+E void NDECL(more);
+E void FDECL(update_topl, (const char *));
+E void FDECL(putsyms, (const char*));
+
+/* ### wintty.c ### */
+#ifdef CLIPPING
+E void NDECL(setclipped);
+#endif
+E void FDECL(docorner, (int, int));
+E void NDECL(end_glyphout);
+E void FDECL(g_putch, (int));
+E void NDECL(win_tty_init);
+
+/* external declarations */
+E void FDECL(tty_init_nhwindows, (int *, char **));
+E void NDECL(tty_player_selection);
+E void NDECL(tty_askname);
+E void NDECL(tty_get_nh_event) ;
+E void FDECL(tty_exit_nhwindows, (const char *));
+E void FDECL(tty_suspend_nhwindows, (const char *));
+E void NDECL(tty_resume_nhwindows);
+E winid FDECL(tty_create_nhwindow, (int));
+E void FDECL(tty_clear_nhwindow, (winid));
+E void FDECL(tty_display_nhwindow, (winid, BOOLEAN_P));
+E void FDECL(tty_dismiss_nhwindow, (winid));
+E void FDECL(tty_destroy_nhwindow, (winid));
+E void FDECL(tty_curs, (winid,int,int));
+E void FDECL(tty_putstr, (winid, int, const char *));
+E void FDECL(tty_display_file, (const char *, BOOLEAN_P));
+E void FDECL(tty_start_menu, (winid));
+E void FDECL(tty_add_menu, (winid,int,const ANY_P *,
+                       CHAR_P,CHAR_P,int,const char *, BOOLEAN_P));
+E void FDECL(tty_end_menu, (winid, const char *));
+E int FDECL(tty_select_menu, (winid, int, MENU_ITEM_P **));
+E char FDECL(tty_message_menu, (CHAR_P,int,const char *));
+E void NDECL(tty_update_inventory);
+E void NDECL(tty_mark_synch);
+E void NDECL(tty_wait_synch);
+#ifdef CLIPPING
+E void FDECL(tty_cliparound, (int, int));
+#endif
+#ifdef POSITIONBAR
+E void FDECL(tty_update_positionbar, (char *));
+#endif
+E void FDECL(tty_print_glyph, (winid,XCHAR_P,XCHAR_P,int));
+E void FDECL(tty_raw_print, (const char *));
+E void FDECL(tty_raw_print_bold, (const char *));
+E int NDECL(tty_nhgetch);
+E int FDECL(tty_nh_poskey, (int *, int *, int *));
+E void NDECL(tty_nhbell);
+E int NDECL(tty_doprev_message);
+E char FDECL(tty_yn_function, (const char *, const char *, CHAR_P));
+E void FDECL(tty_getlin, (const char *,char *));
+E int NDECL(tty_get_ext_cmd);
+E void FDECL(tty_number_pad, (int));
+E void NDECL(tty_delay_output);
+#ifdef CHANGE_COLOR
+E void FDECL(tty_change_color,(int color,long rgb,int reverse));
+#ifdef MAC
+E void FDECL(tty_change_background,(int white_or_black));
+E short FDECL(set_tty_font_name, (winid, char *));
+#endif
+E char * NDECL(tty_get_color_string);
+#endif
+
+/* other defs that really should go away (they're tty specific) */
+E void NDECL(tty_start_screen);
+E void NDECL(tty_end_screen);
+
+E void FDECL(genl_outrip, (winid,int));
+
+#ifdef NO_TERMS
+# ifdef MAC
+#  ifdef putchar
+#   undef putchar
+#   undef putc
+#  endif
+#  define putchar term_putc
+#  define fflush term_flush
+#  define puts term_puts
+E int FDECL(term_putc, (int c));
+E int FDECL(term_flush, (void *desc));
+E int FDECL(term_puts, (const char *str));
+# endif /* MAC */
+# if defined(MSDOS) || defined(WIN32CON)
+#  if defined(SCREEN_BIOS) || defined(SCREEN_DJGPPFAST) || defined(WIN32CON)
+#   undef putchar
+#   undef putc
+#   undef puts
+#   define putchar(x) xputc(x) /* these are in video.c, nttty.c */
+#   define putc(x) xputc(x)
+#   define puts(x) xputs(x)
+#  endif/*SCREEN_BIOS || SCREEN_DJGPPFAST || WIN32CON */
+#  ifdef POSITIONBAR
+E void FDECL(video_update_positionbar, (char *));
+#  endif
+# endif/*MSDOS*/
+#endif/*NO_TERMS*/
+
+#undef E
+
+#endif /* WINTTY_H */
diff --git a/include/wintype.h b/include/wintype.h
new file mode 100644 (file)
index 0000000..b7a4aa1
--- /dev/null
@@ -0,0 +1,71 @@
+/*     SCCS Id: @(#)wintype.h  3.4     1996/02/18      */
+/* Copyright (c) David Cohrs, 1991                               */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef WINTYPE_H
+#define WINTYPE_H
+
+typedef int winid;             /* a window identifier */
+
+/* generic parameter - must not be any larger than a pointer */
+typedef union any {
+    genericptr_t a_void;
+    struct obj *a_obj;
+    int  a_int;
+    char a_char;
+    schar a_schar;
+    /* add types as needed */
+} anything;
+#define ANY_P union any /* avoid typedef in prototypes */
+                       /* (buggy old Ultrix compiler) */
+
+/* menu return list */
+typedef struct mi {
+    anything item;             /* identifier */
+    long count;                        /* count */
+} menu_item;
+#define MENU_ITEM_P struct mi
+
+/* select_menu() "how" argument types */
+#define PICK_NONE 0    /* user picks nothing (display only) */
+#define PICK_ONE  1    /* only pick one */
+#define PICK_ANY  2    /* can pick any amount */
+
+/* window types */
+/* any additional port specific types should be defined in win*.h */
+#define NHW_MESSAGE 1
+#define NHW_STATUS  2
+#define NHW_MAP     3
+#define NHW_MENU    4
+#define NHW_TEXT    5
+
+/* attribute types for putstr; the same as the ANSI value, for convenience */
+#define ATR_NONE    0
+#define ATR_BOLD    1
+#define ATR_DIM     2
+#define ATR_ULINE   4
+#define ATR_BLINK   5
+#define ATR_INVERSE 7
+
+/* nh_poskey() modifier types */
+#define CLICK_1     1
+#define CLICK_2     2
+
+/* invalid winid */
+#define WIN_ERR ((winid) -1)
+
+/* menu window keyboard commands (may be mapped) */
+#define MENU_FIRST_PAGE                '^'
+#define MENU_LAST_PAGE         '|'
+#define MENU_NEXT_PAGE         '>'
+#define MENU_PREVIOUS_PAGE     '<'
+#define MENU_SELECT_ALL                '.'
+#define MENU_UNSELECT_ALL      '-'
+#define MENU_INVERT_ALL                '@'
+#define MENU_SELECT_PAGE       ','
+#define MENU_UNSELECT_PAGE     '\\'
+#define MENU_INVERT_PAGE       '~'
+#define MENU_SEARCH            ':'
+
+
+#endif /* WINTYPE_H */
diff --git a/include/xwindow.h b/include/xwindow.h
new file mode 100644 (file)
index 0000000..94c7d3a
--- /dev/null
@@ -0,0 +1,95 @@
+/*     SCCS Id: @(#)xwindow.h  3.4     1992/03/07      */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef _xwindow_h
+#define _xwindow_h
+
+/****************************************************************
+ *
+ * Window widget
+ *
+ ****************************************************************/
+
+/* Resources:
+
+ Name               Class              RepType         Default Value
+ ----               -----              -------         -------------
+ background         Background         Pixel           XtDefaultBackground
+ border                     BorderColor        Pixel           XtDefaultForeground
+ borderWidth        BorderWidth        Dimension       1
+ destroyCallback     Callback          Pointer         NULL
+ height                     Height             Dimension       0
+ mappedWhenManaged   MappedWhenManaged Boolean         True
+ sensitive          Sensitive          Boolean         True
+ width              Width              Dimension       0
+ x                  Position           Position        0
+ y                  Position           Position        0
+
+ rows               Width              Dimension       21
+ columns            Height             Dimension       80
+ foreground         Color              Pixel           XtDefaultForeground
+
+ black              Color              Pixel           "black"
+ red                Color              Pixel           "red"
+ green              Color              Pixel           "pale green"
+ brown              Color              Pixel           "brown"
+ blue               Color              Pixel           "blue"
+ magenta            Color              Pixel           "magenta"
+ cyan               Color              Pixel           "light cyan"
+ gray               Color              Pixel           "gray"
+ //no color//
+ orange                     Color              Pixel           "orange"
+ bright_green       Color              Pixel           "green"
+ yellow                     Color              Pixel           "yellow"
+ bright_blue        Color              Pixel           "royal blue"
+ bright_magenta      Color             Pixel           "violet"
+ bright_cyan        Color              Pixel           "cyan"
+ white              Color              Pixel           "white"
+
+ font               Font               XFontStruct*    XtDefaultFont
+ exposeCallback      Callback          Callback        NULL
+ callback           Callback           Callback        NULL
+ resizeCallback      Callback          Callback        NULL
+*/
+
+/* define any special resource names here that are not in <X11/StringDefs.h> */
+
+#define XtNrows                        "rows"
+#define XtNcolumns             "columns"
+#define XtNblack               "black"
+#define XtNred                 "red"
+#define XtNgreen               "green"
+#define XtNbrown               "brown"
+#define XtNblue                        "blue"
+#define XtNmagenta             "magenta"
+#define XtNcyan                        "cyan"
+#define XtNgray                        "gray"
+#define XtNorange              "orange"
+#define XtNbright_green                "bright_green"
+#define XtNyellow              "yellow"
+#define XtNbright_blue         "bright_blue"
+#define XtNbright_magenta      "bright_magenta"
+#define XtNbright_cyan         "bright_cyan"
+#define XtNwhite               "white"
+#define XtNexposeCallback      "exposeCallback"
+#define XtNresizeCallback      "resizeCallback"
+
+
+extern XFontStruct *WindowFontStruct(/* Widget */);
+extern Font WindowFont(/* Widget */);
+
+#define XtCWindowResource "WindowResource"
+#define XtCRows                        "Rows"
+#define XtCColumns             "Columns"
+
+/* declare specific WindowWidget class and instance datatypes */
+
+typedef struct _WindowClassRec *WindowWidgetClass;
+typedef struct _WindowRec      *WindowWidget;
+
+/* declare the class constant */
+
+extern WidgetClass windowWidgetClass;
+
+#endif /* _xwindow_h */
diff --git a/include/xwindowp.h b/include/xwindowp.h
new file mode 100644 (file)
index 0000000..bbbe378
--- /dev/null
@@ -0,0 +1,72 @@
+/*     SCCS Id: @(#)xwindowp.h 3.4     1992/03/07      */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef _xwindowp_h
+#define _xwindowp_h
+
+#include "xwindow.h"
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+/* include superclass private header file */
+#include <X11/CoreP.h>
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+/* define unique representation types not found in <X11/StringDefs.h> */
+
+#define XtRWindowResource "WindowResource"
+
+typedef struct {
+    int empty;
+} WindowClassPart;
+
+typedef struct _WindowClassRec {
+    CoreClassPart      core_class;
+    WindowClassPart    window_class;
+} WindowClassRec;
+
+extern WindowClassRec windowClassRec;
+
+typedef struct {
+    /* resources */
+    Dimension     rows;
+    Dimension     columns;
+    Pixel         foreground;
+    Pixel         black;
+    Pixel         red;
+    Pixel         green;
+    Pixel         brown;
+    Pixel         blue;
+    Pixel         magenta;
+    Pixel         cyan;
+    Pixel         gray;
+    Pixel         orange;
+    Pixel         bright_green;
+    Pixel         yellow;
+    Pixel         bright_blue;
+    Pixel         bright_magenta;
+    Pixel         bright_cyan;
+    Pixel         white;
+    XFontStruct    *font;
+    XtCallbackList expose_callback;
+    XtCallbackList input_callback;
+    XtCallbackList resize_callback;
+    /* private state */
+    /* (none) */
+} WindowPart;
+
+typedef struct _WindowRec {
+    CorePart   core;
+    WindowPart window;
+} WindowRec;
+
+#endif /* _xwindowp_h */
diff --git a/include/you.h b/include/you.h
new file mode 100644 (file)
index 0000000..2ca496d
--- /dev/null
@@ -0,0 +1,368 @@
+/*     SCCS Id: @(#)you.h      3.4     2000/05/21      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef YOU_H
+#define YOU_H
+
+#include "attrib.h"
+#include "monst.h"
+#ifndef PROP_H
+#include "prop.h"              /* (needed here for util/makedefs.c) */
+#endif
+#include "skills.h"
+
+/*** Substructures ***/
+
+struct RoleName {
+       const char      *m;     /* name when character is male */
+       const char      *f;     /* when female; null if same as male */
+};
+
+struct RoleAdvance {
+       /* "fix" is the fixed amount, "rnd" is the random amount */
+       xchar infix, inrnd;     /* at character initialization */
+       xchar lofix, lornd;     /* gained per level <  urole.xlev */
+       xchar hifix, hirnd;     /* gained per level >= urole.xlev */
+};
+
+struct u_have {
+       Bitfield(amulet,1);     /* carrying Amulet      */
+       Bitfield(bell,1);       /* carrying Bell        */
+       Bitfield(book,1);       /* carrying Book        */
+       Bitfield(menorah,1);    /* carrying Candelabrum */
+       Bitfield(questart,1);   /* carrying the Quest Artifact */
+       Bitfield(unused,3);
+};
+
+struct u_event {
+       Bitfield(minor_oracle,1);       /* received at least 1 cheap oracle */
+       Bitfield(major_oracle,1);       /*  "  expensive oracle */
+       Bitfield(qcalled,1);            /* called by Quest leader to do task */
+       Bitfield(qexpelled,1);          /* expelled from the Quest dungeon */
+       Bitfield(qcompleted,1);         /* successfully completed Quest task */
+       Bitfield(uheard_tune,2);        /* 1=know about, 2=heard passtune */
+       Bitfield(uopened_dbridge,1);    /* opened the drawbridge */
+
+       Bitfield(invoked,1);            /* invoked Gate to the Sanctum level */
+       Bitfield(gehennom_entered,1);   /* entered Gehennom via Valley */
+#ifdef ELBERETH
+       Bitfield(uhand_of_elbereth,2);  /* became Hand of Elbereth */
+#endif
+       Bitfield(udemigod,1);           /* killed the wiz */
+       Bitfield(ascended,1);           /* has offered the Amulet */
+};
+
+/* KMH, conduct --
+ * These are voluntary challenges.  Each field denotes the number of
+ * times a challenge has been violated.
+ */
+struct u_conduct {             /* number of times... */
+       long    unvegetarian;   /* eaten any animal */
+       long    unvegan;        /* ... or any animal byproduct */
+       long    food;           /* ... or any comestible */
+       long    gnostic;        /* used prayer, priest, or altar */
+       long    weaphit;        /* hit a monster with a weapon */
+       long    killer;         /* killed a monster yourself */
+       long    literate;       /* read something (other than BotD) */
+       long    polypiles;      /* polymorphed an object */
+       long    polyselfs;      /* transformed yourself */
+       long    wishes;         /* used a wish */
+       long    wisharti;       /* wished for an artifact */
+                               /* genocides already listed at end of game */
+};
+
+/*** Unified structure containing role information ***/
+struct Role {
+       /*** Strings that name various things ***/
+       struct RoleName name;   /* the role's name (from u_init.c) */
+       struct RoleName rank[9]; /* names for experience levels (from botl.c) */
+       const char *lgod, *ngod, *cgod; /* god names (from pray.c) */
+       const char *filecode;   /* abbreviation for use in file names */
+       const char *homebase;   /* quest leader's location (from questpgr.c) */
+       const char *intermed;   /* quest intermediate goal (from questpgr.c) */
+
+       /*** Indices of important monsters and objects ***/
+       short malenum,          /* index (PM_) as a male (botl.c) */
+             femalenum,        /* ...or as a female (NON_PM == same) */
+             petnum,           /* PM_ of preferred pet (NON_PM == random) */
+             ldrnum,           /* PM_ of quest leader (questpgr.c) */
+             guardnum,         /* PM_ of quest guardians (questpgr.c) */
+             neminum,          /* PM_ of quest nemesis (questpgr.c) */
+             enemy1num,        /* specific quest enemies (NON_PM == random) */
+             enemy2num;
+       char  enemy1sym,        /* quest enemies by class (S_) */
+             enemy2sym;
+       short questarti;        /* index (ART_) of quest artifact (questpgr.c) */
+
+       /*** Bitmasks ***/
+       short allow;            /* bit mask of allowed variations */
+#define ROLE_RACEMASK  0x0ff8          /* allowable races */
+#define ROLE_GENDMASK  0xf000          /* allowable genders */
+#define ROLE_MALE      0x1000
+#define ROLE_FEMALE    0x2000
+#define ROLE_NEUTER    0x4000
+#define ROLE_ALIGNMASK AM_MASK         /* allowable alignments */
+#define ROLE_LAWFUL    AM_LAWFUL
+#define ROLE_NEUTRAL   AM_NEUTRAL
+#define ROLE_CHAOTIC   AM_CHAOTIC
+
+       /*** Attributes (from attrib.c and exper.c) ***/
+       xchar attrbase[A_MAX];  /* lowest initial attributes */
+       xchar attrdist[A_MAX];  /* distribution of initial attributes */
+       struct RoleAdvance hpadv; /* hit point advancement */
+       struct RoleAdvance enadv; /* energy advancement */
+       xchar xlev;             /* cutoff experience level */
+       xchar initrecord;       /* initial alignment record */
+
+       /*** Spell statistics (from spell.c) ***/
+       int spelbase;           /* base spellcasting penalty */
+       int spelheal;           /* penalty (-bonus) for healing spells */
+       int spelshld;           /* penalty for wearing any shield */
+       int spelarmr;           /* penalty for wearing metal armour */
+       int spelstat;           /* which stat (A_) is used */
+       int spelspec;           /* spell (SPE_) the class excels at */
+       int spelsbon;           /* penalty (-bonus) for that spell */
+
+       /*** Properties in variable-length arrays ***/
+       /* intrinsics (see attrib.c) */
+       /* initial inventory (see u_init.c) */
+       /* skills (see u_init.c) */
+
+       /*** Don't forget to add... ***/
+       /* quest leader, guardians, nemesis (monst.c) */
+       /* quest artifact (artilist.h) */
+       /* quest dungeon definition (dat/Xyz.dat) */
+       /* quest text (dat/quest.txt) */
+       /* dictionary entries (dat/data.bas) */
+};
+
+extern const struct Role roles[];      /* table of available roles */
+extern struct Role urole;
+#define Role_if(X)     (urole.malenum == (X))
+#define Role_switch    (urole.malenum)
+
+/* used during initialization for race, gender, and alignment
+   as well as for character class */
+#define ROLE_NONE      (-1)
+#define ROLE_RANDOM    (-2)
+
+/*** Unified structure specifying race information ***/
+
+struct Race {
+       /*** Strings that name various things ***/
+       const char *noun;       /* noun ("human", "elf") */
+       const char *adj;        /* adjective ("human", "elven") */
+       const char *coll;       /* collective ("humanity", "elvenkind") */
+       const char *filecode;   /* code for filenames */
+       struct RoleName individual; /* individual as a noun ("man", "elf") */
+
+       /*** Indices of important monsters and objects ***/
+       short malenum,          /* PM_ as a male monster */
+             femalenum,        /* ...or as a female (NON_PM == same) */
+             mummynum,         /* PM_ as a mummy */
+             zombienum;        /* PM_ as a zombie */
+
+       /*** Bitmasks ***/
+       short allow;            /* bit mask of allowed variations */
+       short selfmask,         /* your own race's bit mask */
+             lovemask,         /* bit mask of always peaceful */
+             hatemask;         /* bit mask of always hostile */
+
+       /*** Attributes ***/
+       xchar attrmin[A_MAX];   /* minimum allowable attribute */
+       xchar attrmax[A_MAX];   /* maximum allowable attribute */
+       struct RoleAdvance hpadv; /* hit point advancement */
+       struct RoleAdvance enadv; /* energy advancement */
+#if 0  /* DEFERRED */
+       int   nv_range;         /* night vision range */
+       int   xray_range;       /* X-ray vision range */
+#endif
+
+       /*** Properties in variable-length arrays ***/
+       /* intrinsics (see attrib.c) */
+
+       /*** Don't forget to add... ***/
+       /* quest leader, guardians, nemesis (monst.c) */
+       /* quest dungeon definition (dat/Xyz.dat) */
+       /* quest text (dat/quest.txt) */
+       /* dictionary entries (dat/data.bas) */
+};
+
+extern const struct Race races[];      /* Table of available races */
+extern struct Race urace;
+#define Race_if(X)     (urace.malenum == (X))
+#define Race_switch    (urace.malenum)
+
+/*** Unified structure specifying gender information ***/
+struct Gender {
+       const char *adj;        /* male/female/neuter */
+       const char *he;         /* he/she/it */
+       const char *him;        /* him/her/it */
+       const char *his;        /* his/her/its */
+       const char *filecode;   /* file code */
+       short allow;            /* equivalent ROLE_ mask */
+};
+#define ROLE_GENDERS   2       /* number of permitted player genders */
+                               /* increment to 3 if you allow neuter roles */
+
+extern const struct Gender genders[];  /* table of available genders */
+#define uhe()  (genders[flags.female ? 1 : 0].he)
+#define uhim() (genders[flags.female ? 1 : 0].him)
+#define uhis() (genders[flags.female ? 1 : 0].his)
+#define mhe(mtmp)      (genders[pronoun_gender(mtmp)].he)
+#define mhim(mtmp)     (genders[pronoun_gender(mtmp)].him)
+#define mhis(mtmp)     (genders[pronoun_gender(mtmp)].his)
+
+
+/*** Unified structure specifying alignment information ***/
+struct Align {
+       const char *noun;       /* law/balance/chaos */
+       const char *adj;        /* lawful/neutral/chaotic */
+       const char *filecode;   /* file code */
+       short allow;            /* equivalent ROLE_ mask */
+       aligntyp value;         /* equivalent A_ value */
+};
+#define ROLE_ALIGNS    3       /* number of permitted player alignments */
+
+extern const struct Align aligns[];    /* table of available alignments */
+
+
+/*** Information about the player ***/
+struct you {
+       xchar ux, uy;
+       schar dx, dy, dz;       /* direction of move (or zap or ... ) */
+       schar di;               /* direction of FF */
+       xchar tx, ty;           /* destination of travel */
+       xchar ux0, uy0;         /* initial position FF */
+       d_level uz, uz0;        /* your level on this and the previous turn */
+       d_level utolev;         /* level monster teleported you to, or uz */
+       uchar utotype;          /* bitmask of goto_level() flags for utolev */
+       boolean umoved;         /* changed map location (post-move) */
+       int last_str_turn;      /* 0: none, 1: half turn, 2: full turn */
+                               /* +: turn right, -: turn left */
+       int ulevel;             /* 1 to MAXULEV */
+       int ulevelmax;
+       unsigned utrap;         /* trap timeout */
+       unsigned utraptype;     /* defined if utrap nonzero */
+#define TT_BEARTRAP    0
+#define TT_PIT         1
+#define TT_WEB         2
+#define TT_LAVA                3
+#define TT_INFLOOR     4
+       char    urooms[5];      /* rooms (roomno + 3) occupied now */
+       char    urooms0[5];     /* ditto, for previous position */
+       char    uentered[5];    /* rooms (roomno + 3) entered this turn */
+       char    ushops[5];      /* shop rooms (roomno + 3) occupied now */
+       char    ushops0[5];     /* ditto, for previous position */
+       char    ushops_entered[5]; /* ditto, shops entered this turn */
+       char    ushops_left[5]; /* ditto, shops exited this turn */
+
+       int      uhunger;       /* refd only in eat.c and shk.c */
+       unsigned uhs;           /* hunger state - see eat.c */
+
+       struct prop uprops[LAST_PROP+1];
+
+       unsigned umconf;
+       char usick_cause[PL_PSIZ+20]; /* sizeof "unicorn horn named "+1 */
+       Bitfield(usick_type,2);
+#define SICK_VOMITABLE 0x01
+#define SICK_NONVOMITABLE 0x02
+#define SICK_ALL 0x03
+
+       /* These ranges can never be more than MAX_RANGE (vision.h). */
+       int nv_range;           /* current night vision range */
+       int xray_range;         /* current xray vision range */
+
+       /*
+        * These variables are valid globally only when punished and blind.
+        */
+#define BC_BALL  0x01  /* bit mask for ball  in 'bc_felt' below */
+#define BC_CHAIN 0x02  /* bit mask for chain in 'bc_felt' below */
+       int bglyph;     /* glyph under the ball */
+       int cglyph;     /* glyph under the chain */
+       int bc_order;   /* ball & chain order [see bc_order() in ball.c] */
+       int bc_felt;    /* mask for ball/chain being felt */
+
+       int umonster;                   /* hero's "real" monster num */
+       int umonnum;                    /* current monster number */
+
+       int mh, mhmax, mtimedone;       /* for polymorph-self */
+       struct attribs  macurr,         /* for monster attribs */
+                       mamax;          /* for monster attribs */
+       int ulycn;                      /* lycanthrope type */
+
+       unsigned ucreamed;
+       unsigned uswldtim;              /* time you have been swallowed */
+
+       Bitfield(uswallow,1);           /* true if swallowed */
+       Bitfield(uinwater,1);           /* if you're currently in water (only
+                                          underwater possible currently) */
+       Bitfield(uundetected,1);        /* if you're a hiding monster/piercer */
+       Bitfield(mfemale,1);            /* saved human value of flags.female */
+       Bitfield(uinvulnerable,1);      /* you're invulnerable (praying) */
+       Bitfield(uburied,1);            /* you're buried */
+       Bitfield(uedibility,1);         /* blessed food detection; sense unsafe food */
+       /* 1 free bit! */
+
+       unsigned udg_cnt;               /* how long you have been demigod */
+       struct u_event  uevent;         /* certain events have happened */
+       struct u_have   uhave;          /* you're carrying special objects */
+       struct u_conduct uconduct;      /* KMH, conduct */
+       struct attribs  acurr,          /* your current attributes (eg. str)*/
+                       aexe,           /* for gain/loss via "exercise" */
+                       abon,           /* your bonus attributes (eg. str) */
+                       amax,           /* your max attributes (eg. str) */
+                       atemp,          /* used for temporary loss/gain */
+                       atime;          /* used for loss/gain countdown */
+       align   ualign;                 /* character alignment */
+#define CONVERT                2
+#define A_ORIGINAL     1
+#define A_CURRENT      0
+       aligntyp ualignbase[CONVERT];   /* for ualign conversion record */
+       schar uluck, moreluck;          /* luck and luck bonus */
+#define Luck   (u.uluck + u.moreluck)
+#define LUCKADD                3       /* added value when carrying luck stone */
+#define LUCKMAX                10      /* on moonlit nights 11 */
+#define LUCKMIN                (-10)
+       schar   uhitinc;
+       schar   udaminc;
+       schar   uac;
+       uchar   uspellprot;             /* protection by SPE_PROTECTION */
+       uchar   usptime;                /* #moves until uspellprot-- */
+       uchar   uspmtime;               /* #moves between uspellprot-- */
+       int     uhp,uhpmax;
+       int     uen, uenmax;            /* magical energy - M. Stephenson */
+       int ugangr;                     /* if the gods are angry at you */
+       int ugifts;                     /* number of artifacts bestowed */
+       int ublessed, ublesscnt;        /* blessing/duration from #pray */
+#ifndef GOLDOBJ
+       long    ugold, ugold0;
+#else
+       long    umoney0;
+#endif
+       long    uexp, urexp;
+       long    ucleansed;      /* to record moves when player was cleansed */
+       long    usleep;         /* sleeping; monstermove you last started */
+       int uinvault;
+       struct monst *ustuck;
+#ifdef STEED
+       struct monst *usteed;
+       long ugallop;
+       int urideturns;
+#endif
+       int     umortality;             /* how many times you died */
+       int ugrave_arise; /* you die and become something aside from a ghost */
+       time_t  ubirthday;              /* real world time when game began */
+
+       int     weapon_slots;           /* unused skill slots */
+       int     skills_advanced;                /* # of advances made so far */
+       xchar   skill_record[P_SKILL_LIMIT];    /* skill advancements */
+       struct skills weapon_skills[P_NUM_SKILLS];
+       boolean twoweap;                /* KMH -- Using two-weapon combat */
+
+};     /* end of `struct you' */
+
+#define Upolyd (u.umonnum != u.umonster)
+
+#endif /* YOU_H */
diff --git a/include/youprop.h b/include/youprop.h
new file mode 100644 (file)
index 0000000..fb80f63
--- /dev/null
@@ -0,0 +1,342 @@
+/*     SCCS Id: @(#)youprop.h  3.4     1999/07/02      */
+/* Copyright (c) 1989 Mike Threepoint                            */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef YOUPROP_H
+#define YOUPROP_H
+
+#include "prop.h"
+#include "permonst.h"
+#include "mondata.h"
+#include "pm.h"
+
+
+/* KMH, intrinsics patch.
+ * Reorganized and rewritten for >32-bit properties.
+ * HXxx refers to intrinsic bitfields while in human form.
+ * EXxx refers to extrinsic bitfields from worn objects.
+ * BXxx refers to the cause of the property being blocked.
+ * Xxx refers to any source, including polymorph forms.
+ */
+
+
+#define maybe_polyd(if_so,if_not)      (Upolyd ? (if_so) : (if_not))
+
+
+/*** Resistances to troubles ***/
+/* With intrinsics and extrinsics */
+#define HFire_resistance       u.uprops[FIRE_RES].intrinsic
+#define EFire_resistance       u.uprops[FIRE_RES].extrinsic
+#define Fire_resistance                (HFire_resistance || EFire_resistance || \
+                                resists_fire(&youmonst))
+
+#define HCold_resistance       u.uprops[COLD_RES].intrinsic
+#define ECold_resistance       u.uprops[COLD_RES].extrinsic
+#define Cold_resistance                (HCold_resistance || ECold_resistance || \
+                                resists_cold(&youmonst))
+
+#define HSleep_resistance      u.uprops[SLEEP_RES].intrinsic
+#define ESleep_resistance      u.uprops[SLEEP_RES].extrinsic
+#define Sleep_resistance       (HSleep_resistance || ESleep_resistance || \
+                                resists_sleep(&youmonst))
+
+#define HDisint_resistance     u.uprops[DISINT_RES].intrinsic
+#define EDisint_resistance     u.uprops[DISINT_RES].extrinsic
+#define Disint_resistance      (HDisint_resistance || EDisint_resistance || \
+                                resists_disint(&youmonst))
+
+#define HShock_resistance      u.uprops[SHOCK_RES].intrinsic
+#define EShock_resistance      u.uprops[SHOCK_RES].extrinsic
+#define Shock_resistance       (HShock_resistance || EShock_resistance || \
+                                resists_elec(&youmonst))
+
+#define HPoison_resistance     u.uprops[POISON_RES].intrinsic
+#define EPoison_resistance     u.uprops[POISON_RES].extrinsic
+#define Poison_resistance      (HPoison_resistance || EPoison_resistance || \
+                                resists_poison(&youmonst))
+
+#define HDrain_resistance      u.uprops[DRAIN_RES].intrinsic
+#define EDrain_resistance      u.uprops[DRAIN_RES].extrinsic
+#define Drain_resistance       (HDrain_resistance || EDrain_resistance || \
+                                resists_drli(&youmonst))
+
+/* Intrinsics only */
+#define HSick_resistance       u.uprops[SICK_RES].intrinsic
+#define Sick_resistance                (HSick_resistance || \
+                                youmonst.data->mlet == S_FUNGUS || \
+                                youmonst.data == &mons[PM_GHOUL] || \
+                                defends(AD_DISE,uwep))
+#define Invulnerable           u.uprops[INVULNERABLE].intrinsic    /* [Tom] */
+
+/* Extrinsics only */
+#define EAntimagic             u.uprops[ANTIMAGIC].extrinsic
+#define Antimagic              (EAntimagic || \
+                                (Upolyd && resists_magm(&youmonst)))
+
+#define EAcid_resistance       u.uprops[ACID_RES].extrinsic
+#define Acid_resistance                (EAcid_resistance || resists_acid(&youmonst))
+
+#define EStone_resistance      u.uprops[STONE_RES].extrinsic
+#define Stone_resistance       (EStone_resistance || resists_ston(&youmonst))
+
+
+/*** Troubles ***/
+/* Pseudo-property */
+#define Punished               (uball)
+
+/* Those implemented solely as timeouts (we use just intrinsic) */
+#define HStun                  u.uprops[STUNNED].intrinsic
+#define Stunned                        (HStun || u.umonnum == PM_STALKER || \
+                                youmonst.data->mlet == S_BAT)
+               /* Note: birds will also be stunned */
+
+#define HConfusion             u.uprops[CONFUSION].intrinsic
+#define Confusion              HConfusion
+
+#define Blinded                        u.uprops[BLINDED].intrinsic
+#define Blindfolded            (ublindf && ublindf->otyp != LENSES)
+               /* ...means blind because of a cover */
+#define Blind  ((Blinded || Blindfolded || !haseyes(youmonst.data)) && \
+                !(ublindf && ublindf->oartifact == ART_EYES_OF_THE_OVERWORLD))
+               /* ...the Eyes operate even when you really are blind
+                   or don't have any eyes */
+
+#define Sick                   u.uprops[SICK].intrinsic
+#define Stoned                 u.uprops[STONED].intrinsic
+#define Strangled              u.uprops[STRANGLED].intrinsic
+#define Vomiting               u.uprops[VOMITING].intrinsic
+#define Glib                   u.uprops[GLIB].intrinsic
+#define Slimed                 u.uprops[SLIMED].intrinsic      /* [Tom] */
+
+/* Hallucination is solely a timeout; its resistance is extrinsic */
+#define HHallucination         u.uprops[HALLUC].intrinsic
+#define EHalluc_resistance     u.uprops[HALLUC_RES].extrinsic
+#define Halluc_resistance      (EHalluc_resistance || \
+                                (Upolyd && dmgtype(youmonst.data, AD_HALU)))
+#define Hallucination          (HHallucination && !Halluc_resistance)
+
+/* Timeout, plus a worn mask */
+#define HFumbling              u.uprops[FUMBLING].intrinsic
+#define EFumbling              u.uprops[FUMBLING].extrinsic
+#define Fumbling               (HFumbling || EFumbling)
+
+#define HWounded_legs          u.uprops[WOUNDED_LEGS].intrinsic
+#define EWounded_legs          u.uprops[WOUNDED_LEGS].extrinsic
+#define Wounded_legs           (HWounded_legs || EWounded_legs)
+
+#define HSleeping              u.uprops[SLEEPING].intrinsic
+#define ESleeping              u.uprops[SLEEPING].extrinsic
+#define Sleeping               (HSleeping || ESleeping)
+
+#define HHunger                        u.uprops[HUNGER].intrinsic
+#define EHunger                        u.uprops[HUNGER].extrinsic
+#define Hunger                 (HHunger || EHunger)
+
+
+/*** Vision and senses ***/
+#define HSee_invisible         u.uprops[SEE_INVIS].intrinsic
+#define ESee_invisible         u.uprops[SEE_INVIS].extrinsic
+#define See_invisible          (HSee_invisible || ESee_invisible || \
+                                perceives(youmonst.data))
+
+#define HTelepat               u.uprops[TELEPAT].intrinsic
+#define ETelepat               u.uprops[TELEPAT].extrinsic
+#define Blind_telepat          (HTelepat || ETelepat || \
+                                telepathic(youmonst.data))
+#define Unblind_telepat                (ETelepat)
+
+#define HWarning               u.uprops[WARNING].intrinsic
+#define EWarning               u.uprops[WARNING].extrinsic
+#define Warning                        (HWarning || EWarning)
+
+/* Warning for a specific type of monster */
+#define HWarn_of_mon           u.uprops[WARN_OF_MON].intrinsic
+#define EWarn_of_mon           u.uprops[WARN_OF_MON].extrinsic
+#define Warn_of_mon            (HWarn_of_mon || EWarn_of_mon)
+
+#define HUndead_warning                u.uprops[WARN_UNDEAD].intrinsic
+#define Undead_warning         (HUndead_warning)
+
+#define HSearching             u.uprops[SEARCHING].intrinsic
+#define ESearching             u.uprops[SEARCHING].extrinsic
+#define Searching              (HSearching || ESearching)
+
+#define HClairvoyant           u.uprops[CLAIRVOYANT].intrinsic
+#define EClairvoyant           u.uprops[CLAIRVOYANT].extrinsic
+#define BClairvoyant           u.uprops[CLAIRVOYANT].blocked
+#define Clairvoyant            ((HClairvoyant || EClairvoyant) &&\
+                                !BClairvoyant)
+
+#define HInfravision           u.uprops[INFRAVISION].intrinsic
+#define EInfravision           u.uprops[INFRAVISION].extrinsic
+#define Infravision            (HInfravision || EInfravision || \
+                                 infravision(youmonst.data))
+
+#define HDetect_monsters       u.uprops[DETECT_MONSTERS].intrinsic
+#define EDetect_monsters       u.uprops[DETECT_MONSTERS].extrinsic
+#define Detect_monsters                (HDetect_monsters || EDetect_monsters)
+
+
+/*** Appearance and behavior ***/
+#define Adornment              u.uprops[ADORNED].extrinsic
+
+#define HInvis                 u.uprops[INVIS].intrinsic
+#define EInvis                 u.uprops[INVIS].extrinsic
+#define BInvis                 u.uprops[INVIS].blocked
+#define Invis                  ((HInvis || EInvis || \
+                                pm_invisible(youmonst.data)) && !BInvis)
+#define Invisible              (Invis && !See_invisible)
+               /* Note: invisibility also hides inventory and steed */
+
+#define EDisplaced             u.uprops[DISPLACED].extrinsic
+#define Displaced              EDisplaced
+
+#define HStealth               u.uprops[STEALTH].intrinsic
+#define EStealth               u.uprops[STEALTH].extrinsic
+#define BStealth               u.uprops[STEALTH].blocked
+#define Stealth                        ((HStealth || EStealth) && !BStealth)
+
+#define HAggravate_monster     u.uprops[AGGRAVATE_MONSTER].intrinsic
+#define EAggravate_monster     u.uprops[AGGRAVATE_MONSTER].extrinsic
+#define Aggravate_monster      (HAggravate_monster || EAggravate_monster)
+
+#define HConflict              u.uprops[CONFLICT].intrinsic
+#define EConflict              u.uprops[CONFLICT].extrinsic
+#define Conflict               (HConflict || EConflict)
+
+
+/*** Transportation ***/
+#define HJumping               u.uprops[JUMPING].intrinsic
+#define EJumping               u.uprops[JUMPING].extrinsic
+#define Jumping                        (HJumping || EJumping)
+
+#define HTeleportation         u.uprops[TELEPORT].intrinsic
+#define ETeleportation         u.uprops[TELEPORT].extrinsic
+#define Teleportation          (HTeleportation || ETeleportation || \
+                                can_teleport(youmonst.data))
+
+#define HTeleport_control      u.uprops[TELEPORT_CONTROL].intrinsic
+#define ETeleport_control      u.uprops[TELEPORT_CONTROL].extrinsic
+#define Teleport_control       (HTeleport_control || ETeleport_control || \
+                                control_teleport(youmonst.data))
+
+#define HLevitation            u.uprops[LEVITATION].intrinsic
+#define ELevitation            u.uprops[LEVITATION].extrinsic
+#define Levitation             (HLevitation || ELevitation || \
+                                is_floater(youmonst.data))
+       /* Can't touch surface, can't go under water; overrides all others */
+#define Lev_at_will            (((HLevitation & I_SPECIAL) != 0L || \
+                                (ELevitation & W_ARTI) != 0L) && \
+                                (HLevitation & ~(I_SPECIAL|TIMEOUT)) == 0L && \
+                                (ELevitation & ~W_ARTI) == 0L && \
+                                !is_floater(youmonst.data))
+
+#define EFlying                        u.uprops[FLYING].extrinsic
+#ifdef STEED
+# define Flying                        (EFlying || is_flyer(youmonst.data) || \
+                                (u.usteed && is_flyer(u.usteed->data)))
+#else
+# define Flying                        (EFlying || is_flyer(youmonst.data))
+#endif
+       /* May touch surface; does not override any others */
+
+#define Wwalking               (u.uprops[WWALKING].extrinsic && \
+                                !Is_waterlevel(&u.uz))
+       /* Don't get wet, can't go under water; overrides others except levitation */
+       /* Wwalking is meaningless on water level */
+
+#define HSwimming              u.uprops[SWIMMING].intrinsic
+#define ESwimming              u.uprops[SWIMMING].extrinsic    /* [Tom] */
+#ifdef STEED
+# define Swimming              (HSwimming || ESwimming || \
+                                is_swimmer(youmonst.data) || \
+                                (u.usteed && is_swimmer(u.usteed->data)))
+#else
+# define Swimming              (HSwimming || ESwimming || \
+                                is_swimmer(youmonst.data))
+#endif
+       /* Get wet, don't go under water unless if amphibious */
+
+#define HMagical_breathing     u.uprops[MAGICAL_BREATHING].intrinsic
+#define EMagical_breathing     u.uprops[MAGICAL_BREATHING].extrinsic
+#define Amphibious             (HMagical_breathing || EMagical_breathing || \
+                                amphibious(youmonst.data))
+       /* Get wet, may go under surface */
+
+#define Breathless             (HMagical_breathing || EMagical_breathing || \
+                                breathless(youmonst.data))
+
+#define Underwater             (u.uinwater)
+/* Note that Underwater and u.uinwater are both used in code.
+   The latter form is for later implementation of other in-water
+   states, like swimming, wading, etc. */
+
+#define HPasses_walls          u.uprops[PASSES_WALLS].intrinsic
+#define EPasses_walls          u.uprops[PASSES_WALLS].extrinsic
+#define Passes_walls           (HPasses_walls || EPasses_walls || \
+                                passes_walls(youmonst.data))
+
+
+/*** Physical attributes ***/
+#define HSlow_digestion                u.uprops[SLOW_DIGESTION].intrinsic
+#define ESlow_digestion                u.uprops[SLOW_DIGESTION].extrinsic
+#define Slow_digestion         (HSlow_digestion || ESlow_digestion)  /* KMH */
+
+#define HHalf_spell_damage     u.uprops[HALF_SPDAM].intrinsic
+#define EHalf_spell_damage     u.uprops[HALF_SPDAM].extrinsic
+#define Half_spell_damage      (HHalf_spell_damage || EHalf_spell_damage)
+
+#define HHalf_physical_damage  u.uprops[HALF_PHDAM].intrinsic
+#define EHalf_physical_damage  u.uprops[HALF_PHDAM].extrinsic
+#define Half_physical_damage   (HHalf_physical_damage || EHalf_physical_damage)
+
+#define HRegeneration          u.uprops[REGENERATION].intrinsic
+#define ERegeneration          u.uprops[REGENERATION].extrinsic
+#define Regeneration           (HRegeneration || ERegeneration || \
+                                regenerates(youmonst.data))
+
+#define HEnergy_regeneration   u.uprops[ENERGY_REGENERATION].intrinsic
+#define EEnergy_regeneration   u.uprops[ENERGY_REGENERATION].extrinsic
+#define Energy_regeneration    (HEnergy_regeneration || EEnergy_regeneration)
+
+#define HProtection            u.uprops[PROTECTION].intrinsic
+#define EProtection            u.uprops[PROTECTION].extrinsic
+#define Protection             (HProtection || EProtection)
+
+#define HProtection_from_shape_changers \
+                               u.uprops[PROT_FROM_SHAPE_CHANGERS].intrinsic
+#define EProtection_from_shape_changers \
+                               u.uprops[PROT_FROM_SHAPE_CHANGERS].extrinsic
+#define Protection_from_shape_changers \
+                               (HProtection_from_shape_changers || \
+                                EProtection_from_shape_changers)
+
+#define HPolymorph             u.uprops[POLYMORPH].intrinsic
+#define EPolymorph             u.uprops[POLYMORPH].extrinsic
+#define Polymorph              (HPolymorph || EPolymorph)
+
+#define HPolymorph_control     u.uprops[POLYMORPH_CONTROL].intrinsic
+#define EPolymorph_control     u.uprops[POLYMORPH_CONTROL].extrinsic
+#define Polymorph_control      (HPolymorph_control || EPolymorph_control)
+
+#define HUnchanging            u.uprops[UNCHANGING].intrinsic
+#define EUnchanging            u.uprops[UNCHANGING].extrinsic
+#define Unchanging             (HUnchanging || EUnchanging)    /* KMH */
+
+#define HFast                  u.uprops[FAST].intrinsic
+#define EFast                  u.uprops[FAST].extrinsic
+#define Fast                   (HFast || EFast)
+#define Very_fast              ((HFast & ~INTRINSIC) || EFast)
+
+#define EReflecting            u.uprops[REFLECTING].extrinsic
+#define Reflecting             (EReflecting || \
+                                (youmonst.data == &mons[PM_SILVER_DRAGON]))
+
+#define Free_action            u.uprops[FREE_ACTION].extrinsic /* [Tom] */
+
+#define Fixed_abil             u.uprops[FIXED_ABIL].extrinsic  /* KMH */
+
+#define Lifesaved              u.uprops[LIFESAVED].extrinsic
+
+
+#endif /* YOUPROP_H */
diff --git a/nethack.dsw b/nethack.dsw
new file mode 100644 (file)
index 0000000..ff30f52
--- /dev/null
@@ -0,0 +1,212 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "NetHackW"=.\build\NetHackW.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name dgncomp\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name dlb_main\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name levcomp\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name makedefs\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name tilemap\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name tiles\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name uudecode\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "dgncomp"=.\build\dgncomp.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name dgnstuff\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "dgnstuff"=.\build\dgnstuff.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name makedefs\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "dlb_main"=.\build\dlb_main.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name dgncomp\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name levcomp\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name makedefs\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "levcomp"=.\build\levcomp.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name levstuff\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "levstuff"=.\build\levstuff.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name makedefs\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "makedefs"=.\build\makedefs.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "recover"=.\build\recover.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name makedefs\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name dlb_main\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "tile2bmp"=.\build\tile2bmp.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "tilemap"=.\build\tilemap.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "tiles"=.\build\tiles.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name tile2bmp\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "uudecode"=.\build\uudecode.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..832b857
--- /dev/null
@@ -0,0 +1,1419 @@
+#       SCCS Id: @(#)Makefile.msc       3.4     $Date: 2003/11/16 04:50:58 $
+#       Copyright (c) NetHack PC Development Team 1993-2003
+#
+#       NetHack 3.4.x Makefile for MS Visual C++ V6.x and above and MS NMAKE
+#  
+#       Win32 Compilers Tested:
+#                              - Microsoft 32 bit Visual C++ V4.x
+#                              - Microsoft 32 bit Visual C++ V6.0 SP3, SP4
+#
+#   This is used for building two versions of NetHack:
+#   A tty port utilizing the Win32 Console I/O subsystem, Console
+#       NetHack;
+#   A Win32 native port built on the Windows API, Graphical NetHack or
+#       NetHackW.
+#
+#       In addition to your C compiler,
+#
+#       if you want to change           you will need a
+#       files with suffix               workalike for
+#              .y                           yacc   (such as bison)
+#              .l                           lex    (such as flex)
+#
+#
+#       If you have any questions read the sys/winnt/Install.nt file included 
+#       with the distribution.
+#==============================================================================
+# Do not delete the following 3 lines.
+#
+TARGETOS=BOTH
+APPVER=4.0
+!include <win32.mak>
+
+# Graphical interface
+# Set to Y for a graphical version
+
+#GRAPHICAL = Y
+
+#  Set the gamedir according to your preference.  
+#  If not present prior to compilation it gets created.
+
+!IF "$(GRAPHICAL)" == "Y"
+GAME    = NetHackW                # Game Name
+!ELSE
+GAME    = NetHack                 # Game Name
+!ENDIF
+
+GAMEDIR = ..\binary               # Game directory
+
+#
+#  Source directories.    Makedefs hardcodes these, don't change them.
+#
+
+INCL  = ..\include   # NetHack include files
+DAT   = ..\dat       # NetHack data files
+DOC   = ..\doc       # NetHack documentation files
+UTIL  = ..\util      # Utility source
+SRC   = ..\src       # Main source
+SSYS  = ..\sys\share # Shared system files
+NTSYS = ..\sys\winnt # NT Win32 specific files
+TTY   = ..\win\tty   # window port files (tty)
+WIN32 = ..\win\win32 # window port files (Win32)
+WSHR  = ..\win\share # Tile support files 
+
+#
+#  Object directory.
+#
+
+OBJ     = o
+
+
+#
+#==========================================
+# Exe File Info.
+#==========================================
+# Yacc/Lex ... if you got 'em.
+#
+# If you have yacc and lex programs (or work-alike such as bison 
+# and flex), comment out the upper two macros and uncomment 
+# the lower two.
+#
+
+DO_YACC = YACC_MSG
+DO_LEX  = LEX_MSG
+#DO_YACC  = YACC_ACT
+#DO_LEX   = LEX_ACT
+
+# - Specify your yacc and lex programs (or work-alikes) here.
+
+#YACC  = bison -y
+YACC   = byacc
+#YACC  = yacc
+
+#LEX   = lex
+LEX    = flex
+
+#
+# - Specify your flex skeleton file (if needed).
+#
+
+FLEXSKEL =
+#FLEXSKEL = -S../tools/flex.ske
+
+YTABC   = y_tab.c
+YTABH   = y_tab.h
+LEXYYC  = lexyy.c
+
+#
+# Optional high-quality BSD random number generation routines
+# (see pcconf.h). Set to nothing if not used.
+#
+
+RANDOM = $(OBJ)\random.o
+#RANDOM        =
+
+#
+#  Leave the next two lines uncommented _ONLY_ if you do NOT want any
+#  debug capability in the object files, or in the NetHack executable.
+#  Comment them if you want debug capability.
+
+#cdebug =
+#linkdebug =
+
+#
+# Compiler and Linker flags
+#
+
+PRECOMPHEAD = N                        # set to Y if you want to use precomp. headers
+
+#===============================================
+#======= End of Modification Section ===========
+#===============================================
+################################################
+#                                              #
+# Nothing below here should have to be changed.#
+#                                              #
+################################################
+
+!IF "$(GRAPHICAL)" == "Y"
+WINPORT        = $(O)tile.o $(O)mhaskyn.o $(O)mhdlg.o \
+       $(O)mhfont.o $(O)mhinput.o $(O)mhmain.o $(O)mhmap.o \
+       $(O)mhmenu.o $(O)mhmsgwnd.o $(O)mhrip.o $(O)mhsplash.o \
+       $(O)mhstatus.o $(O)mhtext.o $(O)mswproc.o $(O)winhack.o
+WINPHDR        = $(WIN32)\mhaskyn.h $(WIN32)\mhdlg.h $(WIN32)\mhfont.h \
+       $(WIN32)\mhinput.h $(WIN32)\mhmain.h $(WIN32)\mhmap.h $(WIN32)\mhmenu.h \
+       $(WIN32)\mhmsg.h $(WIN32)\mhmsgwnd.h $(WIN32)\mhrip.h $(WIN32)\mhstatus.h \
+       $(WIN32)\mhtext.h $(WIN32)\resource.h $(WIN32)\winMS.h
+WINDLLS =
+WINPFLAG= -DTILES -DMSWIN_GRAPHICS
+NHRES  = $(O)winhack.res
+WINPINC        = -I$(WIN32)
+!ELSE
+WINPORT        = $(O)nttty.o    
+WINPHDR        =
+WINDLLS        = $(GAMEDIR)\nhdefkey.dll $(GAMEDIR)\nh340key.dll $(GAMEDIR)\nhraykey.dll
+WINPFLAG= -DWIN32CON
+NHRES  = $(O)console.res
+WINPINC        =
+!ENDIF
+
+TILEUTIL16  = $(UTIL)\tile2bmp.exe
+TILEBMP16   = $(SRC)\tiles.bmp
+
+TILEUTIL32  = $(UTIL)\til2bm32.exe
+TILEBMP32   = $(SRC)\tiles32.bmp
+
+SOUND = $(OBJ)\ntsound.o
+
+#SOUND =
+
+# To store all the level files,
+# help files, etc. in a single library file.
+# USE_DLB = Y is left uncommented
+
+USE_DLB = Y
+
+! IF ("$(USE_DLB)"=="Y")
+DLBFLG = -DDLB
+! ELSE
+DLBFLG =
+! ENDIF
+
+#==========================================
+# Setting up the compiler and linker
+# macros. All builds include the base ones.
+#==========================================
+
+CFLAGSBASE  = -c $(cflags) $(cvarsmt) -I$(INCL) -nologo $(cdebug) $(WINPINC)
+LFLAGSBASEC = $(linkdebug) /NODEFAULTLIB /INCREMENTAL:NO /RELEASE /NOLOGO -subsystem:console,4.0 $(conlibsmt)
+LFLAGSBASEG = $(linkdebug) $(guiflags) $(guilibsmt) comctl32.lib
+
+#==========================================
+# Util builds
+#==========================================
+
+CFLAGSU = $(CFLAGSBASE) $(WINPFLAG)
+LFLAGSU        = $(LFLAGSBASEC)
+
+#==========================================
+# - Game build
+#==========================================
+LFLAGSBASE = $(linkdebug) /NODEFAULTLIB /INCREMENTAL:NO /RELEASE /NOLOGO -subsystem:console,4.0 $(conlibsmt)
+CFLAGS  = $(CFLAGSBASE) $(WINPFLAG) $(DLBFLG)
+NHLFLAGS1 = /NODEFAULTLIB /INCREMENTAL:NO /PDB:"$(GAME).PDB" /RELEASE /NOLOGO
+NHLFLAGS2 = /MAP:"$(GAME).MAP" /MACHINE:$(CPU) -IGNORE:505 
+!IF ("$(GRAPHICAL)"=="Y")
+LFLAGS = $(LFLAGSBASEG) $(NHLFLAGS1) $(NHLFLAGS2)
+!ELSE
+LFLAGS = $(LFLAGSBASEC) $(NHLFLAGS1) $(NHLFLAGS2)
+!ENDIF
+
+GAMEFILE = $(GAMEDIR)\$(GAME).exe # whole thing
+
+! IF ("$(USE_DLB)"=="Y")
+DLB = nhdat
+! ELSE
+DLB =
+! ENDIF
+
+#==========================================
+#================ RULES ==================
+#==========================================
+
+.SUFFIXES: .exe .o .til .uu .c .y .l
+
+#==========================================
+# Rules for files in src
+#==========================================
+
+.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -Fo$@ $<
+
+{$(SRC)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS)   -Fo$@  $<
+
+#==========================================
+# Rules for files in sys\share
+#==========================================
+
+{$(SSYS)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS)  -Fo$@  $<
+
+#==========================================
+# Rules for files in sys\winnt
+#==========================================
+
+{$(NTSYS)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS)  -Fo$@  $<
+
+{$(NTSYS)}.h{$(INCL)}.h:
+       @copy $< $@
+
+#==========================================
+# Rules for files in util
+#==========================================
+
+{$(UTIL)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGSU) -Fo$@ $<
+
+#==========================================
+# Rules for files in win\share
+#==========================================
+
+{$(WSHR)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS)  -Fo$@ $<
+
+{$(WSHR)}.h{$(INCL)}.h:
+       @copy $< $@
+
+#{$(WSHR)}.txt{$(DAT)}.txt:
+#      @copy $< $@
+
+#==========================================
+# Rules for files in win\tty
+#==========================================
+
+{$(TTY)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS)  -Fo$@  $<
+
+
+#==========================================
+# Rules for files in win\win32
+#==========================================
+
+{$(WIN32)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -Fo$@  $<
+
+#==========================================
+#================ MACROS ==================
+#==========================================
+# This section creates shorthand macros for many objects
+# referenced later on in the Makefile.
+#
+
+DEFFILE = $(NTSYS)\$(GAME).def
+
+#
+# Shorten up the location for some files
+#
+
+O  = $(OBJ)^\
+
+U  = $(UTIL)^\
+
+#
+# Utility Objects.
+#
+
+MAKESRC        = $(U)makedefs.c
+
+SPLEVSRC       = $(U)lev_yacc.c        $(U)lev_$(LEX).c $(U)lev_main.c  $(U)panic.c
+
+DGNCOMPSRC     = $(U)dgn_yacc.c        $(U)dgn_$(LEX).c $(U)dgn_main.c
+
+MAKEOBJS       = $(O)makedefs.o $(O)monst.o $(O)objects.o
+
+SPLEVOBJS      = $(O)lev_yacc.o        $(O)lev_$(LEX).o $(O)lev_main.o \
+                $(O)alloc.o    $(O)decl.o      $(O)drawing.o \
+                $(O)monst.o    $(O)objects.o   $(O)panic.o
+
+DGNCOMPOBJS    = $(O)dgn_yacc.o        $(O)dgn_$(LEX).o $(O)dgn_main.o \
+                $(O)alloc.o    $(O)panic.o
+
+RECOVOBJS      = $(O)recover.o
+
+TILEFILES      = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt
+
+#
+# These are not invoked during a normal game build in 3.4
+#
+TEXT_IO        = $(O)tiletext.o        $(O)tiletxt.o   $(O)drawing.o \
+                $(O)decl.o     $(O)monst.o     $(O)objects.o
+
+TEXT_IO32      = $(O)tilete32.o $(O)tiletx32.o $(O)drawing.o \
+                $(O)decl.o     $(O)monst.o     $(O)objects.o
+
+GIFREADERS     = $(O)gifread.o $(O)alloc.o $(O)panic.o
+GIFREADERS32   = $(O)gifrd32.o $(O)alloc.o $(O)panic.o
+
+PPMWRITERS     = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o
+
+#
+#  Object files for the game itself.
+#
+
+VOBJ01 = $(O)allmain.o  $(O)alloc.o    $(O)apply.o    $(O)artifact.o
+VOBJ02 = $(O)attrib.o   $(O)ball.o     $(O)bones.o    $(O)botl.o    
+VOBJ03 = $(O)cmd.o      $(O)dbridge.o  $(O)decl.o     $(O)detect.o  
+VOBJ04 = $(O)dig.o      $(O)display.o  $(O)do.o       $(O)do_name.o 
+VOBJ05 = $(O)do_wear.o  $(O)dog.o      $(O)dogmove.o  $(O)dokick.o  
+VOBJ06 = $(O)dothrow.o  $(O)drawing.o  $(O)dungeon.o  $(O)eat.o     
+VOBJ07 = $(O)end.o      $(O)engrave.o  $(O)exper.o    $(O)explode.o 
+VOBJ08 = $(O)extralev.o $(O)files.o    $(O)fountain.o $(O)hack.o    
+VOBJ09 = $(O)hacklib.o  $(O)invent.o   $(O)light.o    $(O)lock.o    
+VOBJ10 = $(O)mail.o     $(O)pcmain.o   $(O)makemon.o  $(O)mapglyph.o $(O)mcastu.o  
+VOBJ11 = $(O)mhitm.o    $(O)mhitu.o    $(O)minion.o   $(O)mklev.o   
+VOBJ12 = $(O)mkmap.o    $(O)mkmaze.o   $(O)mkobj.o    $(O)mkroom.o  
+VOBJ13 = $(O)mon.o      $(O)mondata.o  $(O)monmove.o  $(O)monst.o   
+VOBJ14 = $(O)monstr.o   $(O)mplayer.o  $(O)mthrowu.o  $(O)muse.o    
+VOBJ15 = $(O)music.o    $(O)o_init.o   $(O)objects.o  $(O)objnam.o  
+VOBJ16 = $(O)options.o  $(O)pager.o    $(O)pickup.o   $(O)pline.o   
+VOBJ17 = $(O)polyself.o $(O)potion.o   $(O)pray.o     $(O)priest.o  
+VOBJ18 = $(O)quest.o    $(O)questpgr.o $(RANDOM)      $(O)read.o    
+VOBJ19 = $(O)rect.o     $(O)region.o   $(O)restore.o  $(O)rip.o     
+VOBJ20 = $(O)rnd.o      $(O)role.o     $(O)rumors.o   $(O)save.o    
+VOBJ21 = $(O)shk.o      $(O)shknam.o   $(O)sit.o      $(O)sounds.o  
+VOBJ22 = $(O)sp_lev.o   $(O)spell.o    $(O)steal.o    $(O)steed.o   
+VOBJ23 = $(O)teleport.o $(O)timeout.o  $(O)topten.o   $(O)track.o   
+VOBJ24 = $(O)trap.o     $(O)u_init.o   $(O)uhitm.o    $(O)vault.o   
+VOBJ25 = $(O)vis_tab.o  $(O)vision.o   $(O)weapon.o   $(O)were.o    
+VOBJ26 = $(O)wield.o    $(O)windows.o  $(O)wizard.o   $(O)worm.o    
+VOBJ27 = $(O)worn.o     $(O)write.o    $(O)zap.o     
+
+DLBOBJ = $(O)dlb.o
+
+TTYOBJ = $(O)topl.o     $(O)getline.o  $(O)wintty.o
+
+SOBJ   = $(O)winnt.o    $(O)pcsys.o      $(O)pcunix.o  \
+          $(SOUND)     $(O)mapimail.o $(O)nhlan.o
+
+OBJS   = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \
+         $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \
+         $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \
+         $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \
+         $(VOBJ21) $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) \
+         $(VOBJ26) $(VOBJ27)
+
+WINPOBJ = $(WINPORT)
+
+VVOBJ  = $(O)version.o
+
+ALLOBJ  = $(WINPOBJ) $(SOBJ) $(DLBOBJ)  $(TTYOBJ) $(WOBJ) $(OBJS) $(VVOBJ)
+
+!IF "$(GRAPHICAL)" == "Y"
+OPTIONS_FILE = $(DAT)\guioptions
+!ELSE
+OPTIONS_FILE = $(DAT)\ttyoptions
+!ENDIF
+#==========================================
+# Header file macros
+#==========================================
+
+CONFIG_H = $(INCL)\config.h $(INCL)\config1.h $(INCL)\tradstdc.h \
+               $(INCL)\global.h $(INCL)\coord.h $(INCL)\vmsconf.h \
+               $(INCL)\system.h $(INCL)\unixconf.h $(INCL)\os2conf.h \
+               $(INCL)\micro.h $(INCL)\pcconf.h $(INCL)\tosconf.h \
+               $(INCL)\amiconf.h $(INCL)\macconf.h $(INCL)\beconf.h \
+               $(INCL)\ntconf.h $(INCL)\nhlan.h
+
+HACK_H = $(INCL)\hack.h $(CONFIG_H) $(INCL)\align.h \
+               $(INCL)\dungeon.h $(INCL)\monsym.h $(INCL)\mkroom.h \
+               $(INCL)\objclass.h $(INCL)\youprop.h $(INCL)\prop.h \
+               $(INCL)\permonst.h $(INCL)\monattk.h \
+               $(INCL)\monflag.h $(INCL)\mondata.h $(INCL)\pm.h \
+               $(INCL)\wintype.h $(INCL)\decl.h $(INCL)\quest.h \
+               $(INCL)\spell.h $(INCL)\color.h $(INCL)\obj.h \
+               $(INCL)\you.h $(INCL)\attrib.h $(INCL)\monst.h \
+               $(INCL)\skills.h $(INCL)\onames.h $(INCL)\timeout.h \
+               $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \
+               $(INCL)\vision.h $(INCL)\display.h $(INCL)\engrave.h \
+               $(INCL)\rect.h $(INCL)\region.h $(INCL)\winprocs.h \
+               $(INCL)\wintty.h $(INCL)\trampoli.h
+
+LEV_H       = $(INCL)\lev.h
+DGN_FILE_H  = $(INCL)\dgn_file.h
+LEV_COMP_H  = $(INCL)\lev_comp.h
+SP_LEV_H    = $(INCL)\sp_lev.h
+TILE_H      = ..\win\share\tile.h
+
+#==========================================
+# Miscellaneous
+#==========================================
+
+DATABASE = $(DAT)\data.base
+
+#
+#  The name of the game.
+#
+
+GAMEFILE = $(GAMEDIR)\$(GAME).exe
+
+#==========================================
+#=============== TARGETS ==================
+#==========================================
+
+#
+#  The default make target (so just typing 'nmake' is useful).
+#
+default : $(GAMEFILE)
+
+#
+#  The main target.
+#
+
+$(GAME): $(O)obj.tag $(O)utility.tag envchk $(GAMEFILE)
+       @echo $(GAME) is up to date.
+
+#
+#  Everything
+#
+
+all :  install
+
+install: envchk $(GAME) $(O)install.tag
+        @echo Done.
+
+$(O)install.tag:       $(DAT)\data     $(DAT)\rumors    $(DAT)\dungeon \
+               $(DAT)\oracles  $(DAT)\quest.dat $(O)sp_lev.tag $(DLB)
+! IF ("$(USE_DLB)"=="Y")
+       copy nhdat                $(GAMEDIR)
+       copy $(DAT)\license       $(GAMEDIR)
+       copy $(DAT)\opthelp       $(GAMEDIR)
+! ELSE
+       copy $(DAT)\*.            $(GAMEDIR)
+       copy $(DAT)\*.dat         $(GAMEDIR)
+       copy $(DAT)\*.lev         $(GAMEDIR)
+       if exist $(GAMEDIR)\makefile del $(GAMEDIR)\makefile
+! ENDIF
+       if exist $(DOC)\guidebook.txt copy $(DOC)\guidebook.txt $(GAMEDIR)\Guidebook.txt
+       if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt $(GAMEDIR)\NetHack.txt
+       @if exist $(SRC)\$(GAME).PDB copy $(SRC)\$(GAME).pdb $(GAMEDIR)\$(GAME).pdb
+       @if exist $(GAMEDIR)\$(GAME).PDB echo NOTE: You may want to remove $(GAMEDIR)\$(GAME).pdb to conserve space
+       -copy $(NTSYS)\defaults.nh   $(GAMEDIR)\defaults.nh
+       echo install done > $@
+
+#      copy $(NTSYS)\winnt.hlp    $(GAMEDIR)
+
+recover: $(U)recover.exe
+       if exist $(U)recover.exe copy $(U)recover.exe  $(GAMEDIR)
+       if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR)\recover.txt
+
+$(O)sp_lev.tag: $(O)utility.tag $(DAT)\bigroom.des  $(DAT)\castle.des \
+       $(DAT)\endgame.des $(DAT)\gehennom.des $(DAT)\knox.des   \
+       $(DAT)\medusa.des  $(DAT)\oracle.des   $(DAT)\tower.des  \
+       $(DAT)\yendor.des  $(DAT)\arch.des     $(DAT)\barb.des   \
+       $(DAT)\caveman.des $(DAT)\healer.des   $(DAT)\knight.des \
+       $(DAT)\monk.des    $(DAT)\priest.des   $(DAT)\ranger.des \
+       $(DAT)\rogue.des   $(DAT)\samurai.des  $(DAT)\sokoban.des \
+       $(DAT)\tourist.des $(DAT)\valkyrie.des $(DAT)\wizard.des
+       cd $(DAT)
+       $(U)lev_comp bigroom.des
+       $(U)lev_comp castle.des
+       $(U)lev_comp endgame.des
+       $(U)lev_comp gehennom.des
+       $(U)lev_comp knox.des
+       $(U)lev_comp mines.des
+       $(U)lev_comp medusa.des
+       $(U)lev_comp oracle.des
+       $(U)lev_comp sokoban.des
+       $(U)lev_comp tower.des
+       $(U)lev_comp yendor.des
+       $(U)lev_comp arch.des
+       $(U)lev_comp barb.des
+       $(U)lev_comp caveman.des
+       $(U)lev_comp healer.des
+       $(U)lev_comp knight.des
+       $(U)lev_comp monk.des
+       $(U)lev_comp priest.des
+       $(U)lev_comp ranger.des
+       $(U)lev_comp rogue.des
+       $(U)lev_comp samurai.des
+       $(U)lev_comp tourist.des
+       $(U)lev_comp valkyrie.des
+       $(U)lev_comp wizard.des
+       cd $(SRC)
+       echo sp_levs done > $(O)sp_lev.tag
+
+$(O)utility.tag: $(INCL)\date.h $(INCL)\onames.h $(INCL)\pm.h \
+               $(SRC)\monstr.c         $(SRC)\vis_tab.c  \
+               $(U)lev_comp.exe        $(INCL)\vis_tab.h \
+               $(U)dgn_comp.exe
+             @echo utilities made >$@
+            @echo utilities made.
+
+tileutil: $(U)gif2txt.exe $(U)gif2tx32.exe $(U)txt2ppm.exe
+       @echo Optional tile development utilities are up to date.
+
+!IF "$(GRAPHICAL)"=="Y"
+$(NHRES): $(TILEBMP16) $(WIN32)\winhack.rc $(WIN32)\mnsel.bmp \
+       $(WIN32)\mnselcnt.bmp $(WIN32)\mnunsel.bmp \
+       $(WIN32)\petmark.bmp $(WIN32)\NetHack.ico $(WIN32)\rip.bmp \
+       $(WIN32)\splash.bmp
+       @$(rc) -r -fo$@ -i$(WIN32) -dNDEBUG $(WIN32)\winhack.rc
+!ELSE
+$(NHRES): $(NTSYS)\console.rc $(NTSYS)\NetHack.ico
+       @$(rc) -r -fo$@ -i$(NTSYS) -dNDEBUG $(NTSYS)\console.rc
+!ENDIF
+
+#==========================================
+#  The main target.
+#==========================================
+
+#  The section for linking the NetHack image looks a little strange at 
+#  first, especially if you are used to UNIX makes, or NDMAKE.  It is 
+#  Microsoft nmake specific, and it gets around the problem of the 
+#  link command line being too long for the linker.  An "in-line" linker 
+#  response file is generated temporarily.
+#
+#  It takes advantage of the following features of nmake:
+#
+#  Inline files : 
+#                      Specifying the "<<" means to start an inline file.
+#                      Another "<<" at the start of a line closes the 
+#                      inline file.
+#
+#  Substitution within Macros:
+#                       $(mymacro:string1=string2) replaces every
+#                       occurrence of string1 with string2 in the 
+#                       macro mymacro.  Special ascii key codes may be 
+#                       used in the substitution text by preceding it 
+#                       with ^ as we have done below.  Every occurence
+#                       of a <tab> in $(ALLOBJ) is replaced by 
+#                       <+><return><tab>.
+#
+#  DO NOT INDENT THE << below!
+#
+
+$(GAMEFILE) : $(ALLOBJ) $(NHRES) $(O)gamedir.tag $(WINDLLS)
+       @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
+       @echo Linking....
+       $(link) $(LFLAGS) user32.lib winmm.lib -out:$@ @<<$(GAME).lnk
+               $(ALLOBJ:^      =^
+               ) $(NHRES)
+<<
+       @if exist $(O)install.tag del $(O)install.tag
+       @if exist $(GAMEDIR)\$(GAME).bak del $(GAMEDIR)\$(GAME).bak
+
+$(O)gamedir.tag:
+       @if not exist $(GAMEDIR)\*.* echo creating directory $(GAMEDIR)
+       @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
+       @echo directory created > $@
+
+$(O)nhdefkey.def:
+       @echo EXPORTS >$@
+       @echo    ProcessKeystroke >>$@
+       @echo    NHkbhit >>$@
+       @echo    CheckInput >>$@
+       @echo    SourceWhere >>$@
+       @echo    SourceAuthor >>$@
+       @echo    KeyHandlerName >>$@
+
+$(GAMEDIR)\nhdefkey.dll : $(O)$(@B).o $(O)gamedir.tag $(O)$(@B).def
+       @echo Linking $@
+       @$(link) -debug:full -debugtype:cv /RELEASE /NOLOGO /DLL user32.lib \
+               /PDB:"$(@B).PDB" /MAP:"$(@B).map" /DEF:$(O)$(@B).def \
+               /IMPLIB:$(O)$(@B).lib -out:$@ $(O)$(@B).o
+
+$(O)nh340key.def:
+       @echo EXPORTS >$@
+       @echo    ProcessKeystroke >>$@
+       @echo    NHkbhit >>$@
+       @echo    CheckInput >>$@
+       @echo    SourceWhere >>$@
+       @echo    SourceAuthor >>$@
+       @echo    KeyHandlerName >>$@
+
+$(GAMEDIR)\nh340key.dll : $(O)$(@B).o $(O)gamedir.tag $(O)$(@B).def
+       @echo Linking $@
+       @$(link) -debug:full -debugtype:cv /RELEASE /NOLOGO /DLL user32.lib \
+               /PDB:"$(@B).PDB" /MAP:"$(@B).map" /DEF:$(O)$(@B).def \
+               /IMPLIB:$(O)$(@B).lib -out:$@ $(O)$(@B).o
+
+$(O)nhraykey.def:
+       @echo EXPORTS >$@
+       @echo    ProcessKeystroke >>$@
+       @echo    NHkbhit >>$@
+       @echo    CheckInput >>$@
+       @echo    SourceWhere >>$@
+       @echo    SourceAuthor >>$@
+       @echo    KeyHandlerName >>$@
+
+$(GAMEDIR)\nhraykey.dll : $(O)$(@B).o $(O)gamedir.tag $(O)$(@B).def
+       @echo Linking $@
+       @$(link) -debug:full -debugtype:cv /RELEASE /NOLOGO /DLL user32.lib \
+               /PDB:"$(@B).PDB" /MAP:"$(@B).map" /DEF:$(O)$(@B).def \
+               /IMPLIB:$(O)$(@B).lib -out:$@ $(O)$(@B).o
+
+#
+#  Secondary Targets.
+#
+    
+#==========================================
+# Makedefs Stuff
+#==========================================
+
+$(U)makedefs.exe:      $(MAKEOBJS)
+       @$(link) $(LFLAGSU) -out:$@ $(MAKEOBJS)
+
+$(O)makedefs.o: $(CONFIG_H)    $(INCL)\monattk.h $(INCL)\monflag.h   $(INCL)\objclass.h \
+                $(INCL)\monsym.h    $(INCL)\qtext.h    $(INCL)\patchlevel.h \
+                $(U)makedefs.c
+       @if not exist $(OBJ)\*.* echo creating directory $(OBJ)
+       @if not exist $(OBJ)\*.* mkdir $(OBJ)
+       @$(CC) $(CFLAGSU) -Fo$@ $(U)makedefs.c
+
+#
+#  date.h should be remade every time any of the source or include
+#  files is modified.
+#
+
+$(INCL)\date.h $(OPTIONS_FILE) : $(U)makedefs.exe
+       $(U)makedefs -v
+
+$(INCL)\onames.h : $(U)makedefs.exe
+       $(U)makedefs -o
+
+$(INCL)\pm.h : $(U)makedefs.exe
+       $(U)makedefs -p
+
+#$(INCL)\trap.h : $(U)makedefs.exe
+#      $(U)makedefs -t
+
+$(SRC)\monstr.c: $(U)makedefs.exe
+       $(U)makedefs -m
+
+$(INCL)\vis_tab.h: $(U)makedefs.exe
+       $(U)makedefs -z
+
+$(SRC)\vis_tab.c: $(U)makedefs.exe
+       $(U)makedefs -z
+
+#==========================================
+# uudecode utility and uuencoded targets
+#==========================================
+
+$(U)uudecode.exe: $(O)uudecode.o
+       @$(link) $(LFLAGSU) -out:$@ $(O)uudecode.o
+
+$(O)uudecode.o: $(SSYS)\uudecode.c
+
+$(NTSYS)\NetHack.ico : $(U)uudecode.exe $(NTSYS)\nhico.uu 
+       chdir $(NTSYS)
+       ..\..\util\uudecode.exe nhico.uu
+       chdir ..\..\src
+
+$(WIN32)\NetHack.ico : $(U)uudecode.exe $(NTSYS)\nhico.uu 
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu
+       chdir ..\..\src
+
+$(WIN32)\mnsel.bmp: $(U)uudecode.exe $(WIN32)\mnsel.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe mnsel.uu
+       chdir ..\..\src
+
+$(WIN32)\mnselcnt.bmp: $(U)uudecode.exe $(WIN32)\mnselcnt.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe mnselcnt.uu
+       chdir ..\..\src
+
+$(WIN32)\mnunsel.bmp: $(U)uudecode.exe $(WIN32)\mnunsel.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe mnunsel.uu
+       chdir ..\..\src
+
+$(WIN32)\petmark.bmp: $(U)uudecode.exe $(WIN32)\petmark.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe petmark.uu
+       chdir ..\..\src
+
+$(WIN32)\rip.bmp: $(U)uudecode.exe $(WIN32)\rip.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe rip.uu
+       chdir ..\..\src
+
+$(WIN32)\splash.bmp: $(U)uudecode.exe $(WIN32)\splash.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe splash.uu
+       chdir ..\..\src
+
+#==========================================
+# Level Compiler Stuff
+#==========================================
+
+LEVCFLAGS=-c -nologo -DWINVER=0x0400 -DWIN32 -D_WIN32 \
+          -D_MT -MT -I..\include -nologo -Z7 -Od -DDLB
+
+$(U)lev_comp.exe: $(SPLEVOBJS)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(SPLEVOBJS:^   =^
+               )
+<<
+
+$(O)lev_yacc.o: $(HACK_H)   $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c
+       @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_yacc.c
+
+$(O)lev_$(LEX).o: $(HACK_H)   $(INCL)\lev_comp.h $(SP_LEV_H) \
+               $(U)lev_$(LEX).c
+       @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_$(LEX).c
+
+$(O)lev_main.o:        $(U)lev_main.c $(HACK_H)   $(SP_LEV_H)
+       @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_main.c
+
+
+$(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y
+!      IF "$(DO_YACC)"=="YACC_ACT"
+          chdir $(UTIL)
+          $(YACC) -d lev_comp.y
+          copy $(YTABC) lev_yacc.c
+          copy $(YTABH) $(INCL)\lev_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)lev_comp.y has changed.
+          @echo To update $(U)lev_yacc.c and $(INCL)\lev_comp.h run $(YACC).
+          @echo ---
+          @echo For now, we will copy the prebuilt lev_yacc.c and 
+          @echo lev_comp.h from $(SSYS) into $(UTIL) and use them.
+          @copy $(SSYS)\lev_yacc.c $(U)lev_yacc.c >nul
+          @copy $(SSYS)\lev_comp.h $(INCL)\lev_comp.h >nul
+          @echo /**/ >>$(U)lev_yacc.c
+          @echo /**/ >>$(INCL)\lev_comp.h
+!      ENDIF
+
+$(U)lev_$(LEX).c: $(U)lev_comp.l
+!      IF "$(DO_LEX)"=="LEX_ACT"
+          chdir $(UTIL)
+          $(LEX) $(FLEXSKEL) lev_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)lev_comp.l has changed. To update $@ run $(LEX).
+          @echo ---
+          @echo For now, we will copy the prebuilt lev_lex.c 
+          @echo from $(SSYS) into $(UTIL) and use it.
+          @copy $(SSYS)\lev_lex.c $@ >nul
+          @echo /**/ >>$@
+!      ENDIF
+
+#==========================================
+# Dungeon Compiler Stuff
+#==========================================
+
+$(U)dgn_comp.exe: $(DGNCOMPOBJS)
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(DGNCOMPOBJS:^ =^
+               )
+<<
+
+$(O)dgn_yacc.o:        $(HACK_H)   $(DGN_FILE_H) $(INCL)\dgn_comp.h $(U)dgn_yacc.c
+       @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_yacc.c
+
+$(O)dgn_$(LEX).o: $(HACK_H)   $(DGN_FILE_H)  $(INCL)\dgn_comp.h \
+       $(U)dgn_$(LEX).c
+       @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_$(LEX).c
+
+$(O)dgn_main.o:        $(HACK_H) $(U)dgn_main.c
+       @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_main.c
+
+$(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y
+!      IF "$(DO_YACC)"=="YACC_ACT"
+          chdir $(UTIL)
+          $(YACC) -d dgn_comp.y
+          copy $(YTABC) dgn_yacc.c
+          copy $(YTABH) $(INCL)\dgn_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)dgn_comp.y has changed. To update dgn_yacc.c and 
+          @echo $(INCL)\dgn_comp.h run $(YACC).
+          @echo ---
+          @echo For now, we will copy the prebuilt $(U)dgn_yacc.c and 
+          @echo dgn_comp.h from $(SSYS) into $(UTIL) and use them.
+          @copy $(SSYS)\dgn_yacc.c $(U)dgn_yacc.c >nul
+          @copy $(SSYS)\dgn_comp.h $(INCL)\dgn_comp.h >nul
+          @echo /**/ >>$(U)dgn_yacc.c
+          @echo /**/ >>$(INCL)\dgn_comp.h
+!      ENDIF
+
+$(U)dgn_$(LEX).c: $(U)dgn_comp.l
+!      IF "$(DO_LEX)"=="LEX_ACT"
+          chdir $(UTIL)
+          $(LEX) $(FLEXSKEL)  dgn_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX).
+          @echo ---
+          @echo For now, we will copy the prebuilt dgn_lex.c 
+          @echo from $(SSYS) into $(UTIL) and use it.
+          @copy $(SSYS)\dgn_lex.c $@ >nul
+          @echo /**/ >>$@
+!      ENDIF
+
+#==========================================
+# Create directory for holding object files
+#==========================================
+
+$(O)obj.tag:
+       @if not exist $(OBJ)\*.* echo creating directory $(OBJ)
+       @if not exist $(OBJ)\*.* mkdir $(OBJ)
+       @echo directory created >$@
+
+#==========================================
+# Notify of any CL environment variables
+# in effect since they change the compiler
+# options.
+#==========================================
+
+envchk:
+!      IF "$(CL)"!=""
+          @echo Warning, the CL Environment variable is defined:
+          @echo CL=$(CL)
+!      ENDIF
+!   IF "$(GRAPHICAL)"=="Y"
+          @echo ----
+          @echo NOTE: This build will include tile support.
+          @echo ----
+!      ENDIF
+
+#==========================================
+#=========== SECONDARY TARGETS ============
+#==========================================
+
+#===========================================
+# Header files NOT distributed in ..\include
+#===========================================
+
+$(INCL)\win32api.h: $(NTSYS)\win32api.h
+       copy $(NTSYS)\win32api.h $@
+
+
+#==========================================
+# DLB utility and nhdat file creation
+#==========================================
+
+$(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(O)dlb_main.o
+               $(O)dlb.o
+               $(O)alloc.o
+               $(O)panic.o
+<<
+
+$(O)dlb.o:     $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)\dlb.h
+       @$(CC) $(CFLAGS) /Fo$@ $(SRC)\dlb.c
+       
+$(O)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h
+       @$(CC) $(CFLAGS) /Fo$@ $(UTIL)\dlb_main.c
+
+$(DAT)\porthelp: $(NTSYS)\porthelp
+       @copy $(NTSYS)\porthelp $@ >nul
+
+nhdat: $(U)dlb_main.exe $(DAT)\data $(DAT)\oracles $(OPTIONS_FILE) \
+       $(DAT)\quest.dat $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp \
+       $(DAT)\history $(DAT)\opthelp $(DAT)\wizhelp $(DAT)\dungeon $(DAT)\porthelp \
+       $(DAT)\license $(O)sp_lev.tag
+       cd $(DAT)
+       echo data >dlb.lst
+       echo oracles >>dlb.lst
+       if exist options echo options >>dlb.lst
+       if exist ttyoptions echo ttyoptions >>dlb.lst
+       if exist guioptions echo guioptions >>dlb.lst
+       if exist porthelp echo porthelp >>dlb.lst
+       echo quest.dat >>dlb.lst
+       echo rumors >>dlb.lst
+       echo help >>dlb.lst
+       echo hh >>dlb.lst
+       echo cmdhelp >>dlb.lst
+       echo history >>dlb.lst
+       echo opthelp >>dlb.lst
+       echo wizhelp >>dlb.lst
+       echo dungeon >>dlb.lst
+       echo license >>dlb.lst
+       for %%N in (*.lev) do echo %%N >>dlb.lst
+       $(U)dlb_main cIf dlb.lst $(SRC)\nhdat
+       cd $(SRC)
+
+#==========================================
+#  Recover Utility
+#==========================================
+
+$(U)recover.exe: $(RECOVOBJS)
+       $(link) $(LFLAGSU) -out:$@ $(RECOVOBJS)
+
+$(O)recover.o: $(CONFIG_H) $(U)recover.c $(INCL)\win32api.h
+       $(CC) $(CFLAGSU) -Fo$@ $(U)recover.c
+
+#==========================================
+#  Tile Mapping
+#==========================================
+
+$(SRC)\tile.c: $(U)tilemap.exe
+       @echo A new $@ has been created
+       @$(U)tilemap
+
+$(U)tilemap.exe: $(O)tilemap.o
+       @$(link) $(LFLAGSU) -out:$@ $(O)tilemap.o
+
+$(O)tilemap.o: $(WSHR)\tilemap.c $(HACK_H)
+       @$(CC) $(CFLAGSU) -Fo$@ $(WSHR)\tilemap.c
+
+$(O)tiletx32.o: $(WSHR)\tilemap.c $(HACK_H)
+       @$(CC) $(CFLAGS) /DTILETEXT /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tilemap.c
+
+$(O)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H)
+       @$(CC) $(CFLAGS) /DTILETEXT -Fo$@ $(WSHR)\tilemap.c
+
+$(O)gifread.o: $(WSHR)\gifread.c  $(CONFIG_H) $(TILE_H)
+       @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@ $(WSHR)\gifread.c
+
+$(O)gifrd32.o: $(WSHR)\gifread.c  $(CONFIG_H) $(TILE_H)
+       @$(CC) $(CFLAGS) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\gifread.c
+
+$(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(TILE_H)
+       @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@ $(WSHR)\ppmwrite.c
+
+$(O)tiletext.o: $(WSHR)\tiletext.c  $(CONFIG_H) $(TILE_H)
+       @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@ $(WSHR)\tiletext.c
+
+$(O)tilete32.o: $(WSHR)\tiletext.c  $(CONFIG_H) $(TILE_H)
+       @$(CC) $(CFLAGS) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tiletext.c
+
+#==========================================
+# Optional Tile Utilities
+#==========================================
+
+$(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO)
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(GIFREADERS:^  =^
+               )
+               $(TEXT_IO:^     =^
+               )
+<<
+
+$(U)gif2tx32.exe: $(GIFREADERS32) $(TEXT_IO32)
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(GIFREADERS32:^        =^
+               )
+               $(TEXT_IO32:^   =^
+               )
+<<
+
+$(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO)
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(PPMWRITERS:^  =^
+               )
+               $(TEXT_IO:^     =^
+               )
+<<
+
+!IF "$(GRAPHICAL)"=="Y"
+$(TILEBMP16): $(TILEUTIL16) $(TILEFILES)
+       @echo Creating 16x16 binary tile files (this may take some time)
+       @$(U)tile2bmp $(TILEBMP16)
+#$(TILEBMP32): $(TILEUTIL32) $(TILEFILES32)
+#      @echo Creating 32x32 binary tile files (this may take some time)
+#      @$(U)til2bm32 $(TILEBMP32)
+
+!ELSE
+$(TILEBMP16):
+$(TILEBMP32):
+!ENDIF
+
+$(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO)
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(O)tile2bmp.o
+               $(TEXT_IO:^  =^
+               )
+<<
+
+$(U)til2bm32.exe: $(O)til2bm32.o $(TEXT_IO32)
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(O)til2bm32.o
+               $(TEXT_IO32:^  =^
+               )
+<<
+
+$(O)tile2bmp.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h
+       @$(CC) $(CFLAGS) -I$(WSHR) /DPACKED_FILE /Fo$@ $(WSHR)\tile2bmp.c
+
+$(O)til2bm32.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h
+       @$(CC) $(CFLAGS) -I$(WSHR) /DPACKED_FILE /DTILE_X=32 /DTILE_Y=32 /Fo$@ $(WSHR)\tile2bmp.c
+
+#==========================================
+# Housekeeping
+#==========================================
+
+spotless: clean
+! IF ("$(OBJ)"!="")
+       -rmdir $(OBJ) /s /Q
+! ENDIF
+       if exist $(INCL)\date.h    del $(INCL)\date.h
+       if exist $(INCL)\onames.h  del $(INCL)\onames.h
+       if exist $(INCL)\pm.h      del $(INCL)\pm.h
+       if exist $(INCL)\vis_tab.h del $(INCL)\vis_tab.h
+       if exist $(SRC)\vis_tab.c  del $(SRC)\vis_tab.c
+       if exist $(SRC)\tile.c     del $(SRC)\tile.c
+       if exist $(U)*.lnk         del $(U)*.lnk
+       if exist $(U)*.map         del $(U)*.map
+       if exist $(DAT)\data       del $(DAT)\data
+       if exist $(DAT)\rumors     del $(DAT)\rumors
+       if exist $(DAT)\???-fil?.lev    del $(DAT)\???-fil?.lev
+       if exist $(DAT)\???-goal.lev    del $(DAT)\???-goal.lev
+       if exist $(DAT)\???-loca.lev    del $(DAT)\???-loca.lev
+       if exist $(DAT)\???-strt.lev    del $(DAT)\???-strt.lev
+       if exist $(DAT)\air.lev         del $(DAT)\air.lev
+       if exist $(DAT)\asmodeus.lev    del $(DAT)\asmodeus.lev
+       if exist $(DAT)\astral.lev      del $(DAT)\astral.lev
+       if exist $(DAT)\baalz.lev       del $(DAT)\baalz.lev
+       if exist $(DAT)\bigroom.lev     del $(DAT)\bigroom.lev
+       if exist $(DAT)\castle.lev      del $(DAT)\castle.lev
+       if exist $(DAT)\data            del $(DAT)\data
+       if exist $(DAT)\dungeon         del $(DAT)\dungeon
+       if exist $(DAT)\dungeon.pdf     del $(DAT)\dungeon.pdf
+       if exist $(DAT)\earth.lev       del $(DAT)\earth.lev
+       if exist $(DAT)\fakewiz?.lev    del $(DAT)\fakewiz?.lev
+       if exist $(DAT)\fire.lev        del $(DAT)\fire.lev
+       if exist $(DAT)\juiblex.lev     del $(DAT)\juiblex.lev
+       if exist $(DAT)\knox.lev        del $(DAT)\knox.lev
+       if exist $(DAT)\medusa-?.lev    del $(DAT)\medusa-?.lev
+       if exist $(DAT)\mine*.lev       del $(DAT)\mine*.lev
+       if exist $(DAT)\options         del $(DAT)\options
+       if exist $(DAT)\ttyoptions      del $(DAT)\ttyoptions
+       if exist $(DAT)\guioptions      del $(DAT)\guioptions
+       if exist $(DAT)\oracle.lev      del $(DAT)\oracle.lev
+       if exist $(DAT)\oracles         del $(DAT)\oracles
+       if exist $(DAT)\orcus.lev       del $(DAT)\orcus.lev
+       if exist $(DAT)\rumors          del $(DAT)\rumors
+       if exist $(DAT)\quest.dat       del $(DAT)\quest.dat
+       if exist $(DAT)\sanctum.lev     del $(DAT)\sanctum.lev
+       if exist $(DAT)\soko?-?.lev     del $(DAT)\soko?-?.lev
+       if exist $(DAT)\tower?.lev      del $(DAT)\tower?.lev
+       if exist $(DAT)\valley.lev      del $(DAT)\valley.lev
+       if exist $(DAT)\water.lev       del $(DAT)\water.lev
+       if exist $(DAT)\wizard?.lev     del $(DAT)\wizard?.lev
+       if exist $(O)sp_lev.tag         del $(O)sp_lev.tag
+       if exist $(SRC)\monstr.c        del $(SRC)\monstr.c
+       if exist $(SRC)\vis_tab.c       del $(SRC)\vis_tab.c
+       if exist $(U)recover.exe        del $(U)recover.exe
+       if exist nhdat.                 del nhdat.
+       if exist $(O)obj.tag            del $(O)obj.tag
+       if exist $(O)gamedir.tag        del $(O)gamedir.tag
+       if exist $(O)nh*key.lib         del $(O)nh*key.lib
+       if exist $(O)nh*key.exp         del $(O)nh*key.exp
+
+clean:
+       if exist $(O)*.o del $(O)*.o
+       if exist $(O)utility.tag   del $(O)utility.tag
+       if exist $(U)makedefs.exe  del $(U)makedefs.exe
+       if exist $(U)lev_comp.exe  del $(U)lev_comp.exe
+       if exist $(U)dgn_comp.exe  del $(U)dgn_comp.exe
+       if exist $(SRC)\*.lnk      del $(SRC)\*.lnk
+       if exist $(SRC)\*.map      del $(SRC)\*.map
+       if exist $(O)install.tag   del $(O)install.tag
+! IF ("$(WINPFLAG)"!="")
+       if exist $(TILEBMP16)        del $(TILEBMP16)
+       if exist $(TILEBMP32)        del $(TILEBMP32)
+! ENDIF
+
+#===================================================================
+# OTHER DEPENDENCIES
+#===================================================================
+
+#
+# dat dependencies
+#
+
+$(DAT)\data: $(O)utility.tag    $(DATABASE)
+       $(U)makedefs -d
+
+$(DAT)\rumors: $(O)utility.tag    $(DAT)\rumors.tru   $(DAT)\rumors.fal
+       $(U)makedefs -r
+
+$(DAT)\quest.dat: $(O)utility.tag  $(DAT)\quest.txt
+       $(U)makedefs -q
+
+$(DAT)\oracles: $(O)utility.tag    $(DAT)\oracles.txt
+       $(U)makedefs -h
+
+$(DAT)\dungeon: $(O)utility.tag  $(DAT)\dungeon.def
+       $(U)makedefs -e
+       cd $(DAT)
+       $(U)dgn_comp dungeon.pdf
+       cd $(SRC)
+
+#
+# NT dependencies
+#
+
+$(O)nttty.o:   $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nttty.c
+       @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@  $(NTSYS)\nttty.c
+$(O)nhkeys.o:   $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nhkeys.c
+       @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@  $(NTSYS)\nhkeys.c
+$(O)winnt.o: $(HACK_H) $(INCL)\win32api.h $(NTSYS)\winnt.c
+       @$(CC) $(CFLAGS) -Fo$@  $(NTSYS)\winnt.c
+$(O)ntsound.o: $(HACK_H) $(NTSYS)\ntsound.c
+       @$(CC) $(CFLAGS)  -Fo$@ $(NTSYS)\ntsound.c
+$(O)mapimail.o: $(HACK_H) $(INCL)\nhlan.h $(NTSYS)\mapimail.c
+       @$(CC) $(CFLAGS) -DMAPI_VERBOSE  -Fo$@ $(NTSYS)\mapimail.c
+
+# 
+# util dependencies
+#
+
+$(O)panic.o:  $(U)panic.c $(CONFIG_H)
+       @$(CC) $(CFLAGS) -Fo$@ $(U)panic.c
+
+#
+# The rest are stolen from sys/unix/Makefile.src, 
+# with the following changes:
+#   * ../include changed to $(INCL)
+#   * slashes changed to back-slashes 
+#   * -c (which is included in CFLAGS) substituted with -Fo$@
+#   * targets prefixed with $(O)
+# but otherwise untouched.
+# That means that there is some irrelevant stuff
+# in here, but maintenance should be easier.
+#
+$(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\atari\tos.c
+$(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\win32api.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\pcmain.c
+$(O)pcsys.o: ..\sys\share\pcsys.c $(HACK_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\pcsys.c
+$(O)pctty.o: ..\sys\share\pctty.c $(HACK_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\pctty.c
+$(O)pcunix.o: ..\sys\share\pcunix.c $(HACK_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\pcunix.c
+$(O)random.o: ..\sys\share\random.c $(HACK_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\random.c
+$(O)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)\tcap.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\ioctl.c
+$(O)unixtty.o: ..\sys\share\unixtty.c $(HACK_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\unixtty.c
+$(O)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)\dlb.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\unix\unixmain.c
+$(O)unixunix.o: ..\sys\unix\unixunix.c $(HACK_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\unix\unixunix.c
+$(O)unixres.o: ..\sys\unix\unixres.c $(CONFIG_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\unix\unixres.c
+$(O)bemain.o: ..\sys\be\bemain.c $(HACK_H) $(INCL)\dlb.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\be\bemain.c
+$(O)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)\func_tab.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\tty\getline.c
+$(O)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)\tcap.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\tty\termcap.c
+$(O)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)\tcap.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\tty\topl.c
+$(O)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h $(INCL)\tcap.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\tty\wintty.c
+$(O)Window.o: ..\win\X11\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \
+               $(CONFIG_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\Window.c
+$(O)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\dialogs.c
+$(O)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h ..\win\X11\nh72icon \
+               ..\win\X11\nh56icon ..\win\X11\nh32icon
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winX.c
+$(O)winmap.o: ..\win\X11\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\winX.h $(INCL)\tile2x11.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winmap.c
+$(O)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)\winX.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winmenu.c
+$(O)winmesg.o: ..\win\X11\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winmesg.c
+$(O)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)\func_tab.h \
+               $(INCL)\winX.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winmisc.c
+$(O)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)\winX.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winstat.c
+$(O)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\wintext.c
+$(O)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)\winX.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winval.c
+$(O)tile.o: $(SRC)\tile.c $(HACK_H)
+$(O)gnaskstr.o: ..\win\gnome\gnaskstr.c ..\win\gnome\gnaskstr.h \
+               ..\win\gnome\gnmain.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnaskstr.c
+$(O)gnbind.o: ..\win\gnome\gnbind.c ..\win\gnome\gnbind.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gnaskstr.h ..\win\gnome\gnyesno.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnbind.c
+$(O)gnglyph.o: ..\win\gnome\gnglyph.c ..\win\gnome\gnglyph.h $(INCL)\tile2x11.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnglyph.c
+$(O)gnmain.o: ..\win\gnome\gnmain.c ..\win\gnome\gnmain.h ..\win\gnome\gnsignal.h \
+               ..\win\gnome\gnbind.h ..\win\gnome\gnopts.h $(HACK_H) \
+               $(INCL)\date.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmain.c
+$(O)gnmap.o: ..\win\gnome\gnmap.c ..\win\gnome\gnmap.h ..\win\gnome\gnglyph.h \
+               ..\win\gnome\gnsignal.h $(HACK_H)
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmap.c
+$(O)gnmenu.o: ..\win\gnome\gnmenu.c ..\win\gnome\gnmenu.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gnbind.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmenu.c
+$(O)gnmesg.o: ..\win\gnome\gnmesg.c ..\win\gnome\gnmesg.h ..\win\gnome\gnsignal.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmesg.c
+$(O)gnopts.o: ..\win\gnome\gnopts.c ..\win\gnome\gnopts.h ..\win\gnome\gnglyph.h \
+               ..\win\gnome\gnmain.h ..\win\gnome\gnmap.h $(HACK_H)
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnopts.c
+$(O)gnplayer.o: ..\win\gnome\gnplayer.c ..\win\gnome\gnplayer.h \
+               ..\win\gnome\gnmain.h $(HACK_H)
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnplayer.c
+$(O)gnsignal.o: ..\win\gnome\gnsignal.c ..\win\gnome\gnsignal.h \
+               ..\win\gnome\gnmain.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnsignal.c
+$(O)gnstatus.o: ..\win\gnome\gnstatus.c ..\win\gnome\gnstatus.h \
+               ..\win\gnome\gnsignal.h ..\win\gnome\gn_xpms.h \
+               ..\win\gnome\gnomeprv.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnstatus.c
+$(O)gntext.o: ..\win\gnome\gntext.c ..\win\gnome\gntext.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gn_rip.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gntext.c
+$(O)gnworn.o: ..\win\gnome\gnworn.c ..\win\gnome\gnworn.h ..\win\gnome\gnglyph.h \
+               ..\win\gnome\gnsignal.h ..\win\gnome\gnomeprv.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnworn.c
+$(O)gnyesno.o: ..\win\gnome\gnyesno.c ..\win\gnome\gnbind.h ..\win\gnome\gnyesno.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnyesno.c
+$(O)wingem.o: ..\win\gem\wingem.c $(HACK_H) $(INCL)\func_tab.h $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h $(INCL)\wingem.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\gem\wingem.c
+$(O)wingem1.o: ..\win\gem\wingem1.c $(INCL)\gem_rsc.h $(INCL)\load_img.h \
+               $(INCL)\gr_rect.h $(INCL)\wintype.h $(INCL)\wingem.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\gem\wingem1.c
+$(O)load_img.o: ..\win\gem\load_img.c $(INCL)\load_img.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\gem\load_img.c
+$(O)gr_rect.o: ..\win\gem\gr_rect.c $(INCL)\gr_rect.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\gem\gr_rect.c
+$(O)tile.o: tile.c $(HACK_H)
+$(O)qt_win.o: ..\win\Qt\qt_win.cpp $(HACK_H) $(INCL)\func_tab.h \
+               $(INCL)\dlb.h $(INCL)\patchlevel.h $(INCL)\tile2x11.h \
+               $(INCL)\qt_win.h $(INCL)\qt_clust.h $(INCL)\qt_kde0.h \
+               $(INCL)\qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc
+       $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_win.cpp
+$(O)qt_clust.o: ..\win\Qt\qt_clust.cpp $(INCL)\qt_clust.h
+       $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_clust.cpp
+$(O)qttableview.o: ..\win\Qt\qttableview.cpp $(INCL)\qttableview.h
+       $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qttableview.cpp
+$(O)monstr.o: monstr.c $(CONFIG_H)
+$(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)\vis_tab.h
+$(O)allmain.o: allmain.c $(HACK_H)
+$(O)alloc.o: alloc.c $(CONFIG_H)
+$(O)apply.o: apply.c $(HACK_H) $(INCL)\edog.h
+$(O)artifact.o: artifact.c $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h
+$(O)attrib.o: attrib.c $(HACK_H)
+$(O)ball.o: ball.c $(HACK_H)
+$(O)bones.o: bones.c $(HACK_H) $(INCL)\lev.h
+$(O)botl.o: botl.c $(HACK_H)
+$(O)cmd.o: cmd.c $(HACK_H) $(INCL)\func_tab.h
+$(O)dbridge.o: dbridge.c $(HACK_H)
+$(O)decl.o: decl.c $(HACK_H)
+$(O)detect.o: detect.c $(HACK_H) $(INCL)\artifact.h
+$(O)dig.o: dig.c $(HACK_H) $(INCL)\edog.h
+$(O)display.o: display.c $(HACK_H)
+$(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)\dlb.h
+$(O)do.o: do.c $(HACK_H) $(INCL)\lev.h
+$(O)do_name.o: do_name.c $(HACK_H)
+$(O)do_wear.o: do_wear.c $(HACK_H)
+$(O)dog.o: dog.c $(HACK_H) $(INCL)\edog.h
+$(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+$(O)dokick.o: dokick.c $(HACK_H) $(INCL)\eshk.h
+$(O)dothrow.o: dothrow.c $(HACK_H) $(INCL)\edog.h
+$(O)drawing.o: drawing.c $(HACK_H) $(INCL)\tcap.h
+$(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h
+$(O)eat.o: eat.c $(HACK_H)
+$(O)end.o: end.c $(HACK_H) $(INCL)\eshk.h $(INCL)\dlb.h
+$(O)engrave.o: engrave.c $(HACK_H) $(INCL)\lev.h
+$(O)exper.o: exper.c $(HACK_H)
+$(O)explode.o: explode.c $(HACK_H)
+$(O)extralev.o: extralev.c $(HACK_H)
+$(O)files.o: files.c $(HACK_H) $(INCL)\dlb.h
+$(O)fountain.o: fountain.c $(HACK_H)
+$(O)hack.o: hack.c $(HACK_H)
+$(O)hacklib.o: hacklib.c $(HACK_H)
+$(O)invent.o: invent.c $(HACK_H)
+$(O)light.o: light.c $(HACK_H) $(INCL)\lev.h
+$(O)lock.o: lock.c $(HACK_H)
+$(O)mail.o: mail.c $(HACK_H) $(INCL)\mail.h
+$(O)makemon.o: makemon.c $(HACK_H) $(INCL)\epri.h $(INCL)\emin.h \
+               $(INCL)\edog.h
+$(O)mapglyph.o: mapglyph.c $(HACK_H)
+$(O)mcastu.o: mcastu.c $(HACK_H)
+$(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+$(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+$(O)minion.o: minion.c $(HACK_H) $(INCL)\emin.h $(INCL)\epri.h
+$(O)mklev.o: mklev.c $(HACK_H)
+$(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)\sp_lev.h
+$(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev.h
+$(O)mkobj.o: mkobj.c $(HACK_H)
+$(O)mkroom.o: mkroom.c $(HACK_H)
+$(O)mon.o: mon.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+$(O)mondata.o: mondata.c $(HACK_H) $(INCL)\eshk.h $(INCL)\epri.h
+$(O)monmove.o: monmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h \
+               $(INCL)\epri.h
+$(O)monst.o: monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \
+               $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\monsym.h \
+               $(INCL)\dungeon.h $(INCL)\eshk.h $(INCL)\vault.h \
+               $(INCL)\epri.h $(INCL)\color.h
+$(O)mplayer.o: mplayer.c $(HACK_H)
+$(O)mthrowu.o: mthrowu.c $(HACK_H)
+$(O)muse.o: muse.c $(HACK_H) $(INCL)\edog.h
+$(O)music.o: music.c $(HACK_H) #interp.c
+$(O)o_init.o: o_init.c $(HACK_H) $(INCL)\lev.h
+$(O)objects.o: objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \
+               $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h
+$(O)objnam.o: objnam.c $(HACK_H)
+$(O)options.o: options.c $(CONFIG_H) $(INCL)\objclass.h $(INCL)\flag.h \
+               $(HACK_H) $(INCL)\tcap.h
+$(O)pager.o: pager.c $(HACK_H) $(INCL)\dlb.h
+$(O)pickup.o: pickup.c $(HACK_H)
+$(O)pline.o: pline.c $(HACK_H) $(INCL)\epri.h $(INCL)\edog.h
+$(O)polyself.o: polyself.c $(HACK_H)
+$(O)potion.o: potion.c $(HACK_H)
+$(O)pray.o: pray.c $(HACK_H) $(INCL)\epri.h
+$(O)priest.o: priest.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\eshk.h \
+               $(INCL)\epri.h $(INCL)\emin.h
+$(O)quest.o: quest.c $(HACK_H) $(INCL)\qtext.h
+$(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)\dlb.h $(INCL)\qtext.h
+$(O)read.o: read.c $(HACK_H)
+$(O)rect.o: rect.c $(HACK_H)
+$(O)region.o: region.c $(HACK_H) $(INCL)\lev.h
+$(O)restore.o: restore.c $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h
+$(O)rip.o: rip.c $(HACK_H)
+$(O)rnd.o: rnd.c $(HACK_H)
+$(O)role.o: role.c $(HACK_H)
+$(O)rumors.o: rumors.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h
+$(O)save.o: save.c $(HACK_H) $(INCL)\lev.h
+$(O)shk.o: shk.c $(HACK_H) $(INCL)\eshk.h
+$(O)shknam.o: shknam.c $(HACK_H) $(INCL)\eshk.h
+$(O)sit.o: sit.c $(HACK_H) $(INCL)\artifact.h
+$(O)sounds.o: sounds.c $(HACK_H) $(INCL)\edog.h
+$(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)\dlb.h $(INCL)\sp_lev.h
+$(O)spell.o: spell.c $(HACK_H)
+$(O)steal.o: steal.c $(HACK_H)
+$(O)steed.o: steed.c $(HACK_H)
+$(O)teleport.o: teleport.c $(HACK_H)
+$(O)timeout.o: timeout.c $(HACK_H) $(INCL)\lev.h
+$(O)topten.o: topten.c $(HACK_H) $(INCL)\dlb.h $(INCL)\patchlevel.h
+$(O)track.o: track.c $(HACK_H)
+$(O)trap.o: trap.c $(HACK_H)
+$(O)u_init.o: u_init.c $(HACK_H)
+$(O)uhitm.o: uhitm.c $(HACK_H)
+$(O)vault.o: vault.c $(HACK_H) $(INCL)\vault.h
+$(O)version.o: version.c $(HACK_H) $(INCL)\date.h $(INCL)\patchlevel.h
+$(O)vision.o: vision.c $(HACK_H) $(INCL)\vis_tab.h
+$(O)weapon.o: weapon.c $(HACK_H)
+$(O)were.o: were.c $(HACK_H)
+$(O)wield.o: wield.c $(HACK_H)
+$(O)windows.o: windows.c $(HACK_H) $(INCL)\wingem.h $(INCL)\winGnome.h
+$(O)wizard.o: wizard.c $(HACK_H) $(INCL)\qtext.h $(INCL)\epri.h
+$(O)worm.o: worm.c $(HACK_H) $(INCL)\lev.h
+$(O)worn.o: worn.c $(HACK_H)
+$(O)write.o: write.c $(HACK_H)
+$(O)zap.o: zap.c $(HACK_H)
+
+# end of file
diff --git a/src/Makefile.bcc b/src/Makefile.bcc
new file mode 100644 (file)
index 0000000..c734afe
--- /dev/null
@@ -0,0 +1,1378 @@
+#   SCCS Id: @(#)Makefile.bcc       3.4     $Date: 2003/11/16 04:50:56 $
+#   Copyright (c) NetHack PC Development Team 1993-2003
+#
+#
+# IMPORTANT NOTE: This Makefile has not been tested for 3.4.3.
+#
+#
+#   NetHack 3.4.x Makefile for Borland C++ V5.5.1 and above and Borland's MAKE
+#  
+#   Win32 Compilers Tested:
+#                              - Borland C++ 5.5.1 for Win32
+#
+#   If you don't have this compiler, you can get it at:
+#       http://www.borland.com/bcppbuilder/freecompiler/
+#
+#   This makefile is set up to assume the directories are extracted at the
+#   root, but this can be changed by modifying the bccroot and related
+#   variables.
+#
+#   This is used for building two versions of NetHack:
+#   A tty port utilizing the Win32 Console I/O subsystem, Console
+#       NetHack;
+#   A Win32 native port built on the Windows API, Graphical NetHack or
+#       NetHackW.
+#
+#   In addition to your C compiler,
+#
+#     if you want to change     you will need a
+#     files with suffix         workalike for
+#              .y                   yacc   (such as bison)
+#              .l                   lex    (such as flex)
+#
+#
+#   If you have any questions read the sys/winnt/Install.nt file included 
+#   with the distribution.
+#
+#   --
+#   Yitzhak Sapir
+#==============================================================================
+# Do not delete the following 3 lines.
+#
+TARGETOS=BOTH
+APPVER=4.0
+
+bccbin = $(MAKEDIR)
+bccroot = $(MAKEDIR)\..
+bccinc = $(bccroot)\include
+bcclib = $(bccroot)\lib
+
+!IFNDEF APPVER
+APPVER = 4.0
+!ENDIF
+
+# Graphical interface
+# Set to Y for a graphical version
+# Set to anything else (or undefine) for a tty version
+
+#GRAPHICAL = Y
+
+# Debug
+# Set to Y for Debug support (to produce full map files, listing files, and debug information)
+# Set to anything else (or undefine) for a "release" version
+
+DEBUG = Y
+
+!IF "$(APPVER)" == "4.0"
+MAKE_WINVER = 0x0400
+!ELSEIF "$(APPVER)" == "5.0"
+MAKE_WINVER = 0x0500
+!ENDIF
+
+cc     = $(bccbin)\bcc32
+rc     = $(bccbin)\brc32
+link   = $(bccbin)\ilink32
+implib = $(bccbin)\tlib
+
+cflags = -c -D_X86_=1 -DWINVER=$(MAKE_WINVER) -q -I$(bccinc) -w-pia -w-rch -w-csu -w-par -w-aus
+cdebug = -y -v -O2
+cvarsmt  = -DWIN32 -D_WIN32 -D_MT 
+lflags  = 
+!IF "$(DEBUG)" == "Y"
+linkdebug = /v /m /s 
+cdebug = -v -y -Q
+!ELSE
+linkdebug = /C /Gn
+cdebug =
+!ENDIF
+startobj = $(bcclib)\c0x32.obj
+!IF "$(GRAPHICAL)" == "Y"
+verlflags = /Gn /Gz /q -L$(bcclib) /c  /Tpe /V$(APPVER)
+startobjg = $(bcclib)\c0w32.obj
+!ELSE
+verlflags = /Gn /Gz /q -L$(bcclib) /c  /ap /Tpe /V$(APPVER)
+startobjg = $(startobj)
+!ENDIF
+libsmt  = $(bcclib)\cw32mt.lib $(bcclib)\import32.lib 
+
+#
+#  Set the gamedir according to your preference.  
+#  It must be present prior to compilation.
+
+!IF "$(GRAPHICAL)" == "Y"
+GAME    = NetHackW                # Game Name
+!ELSE
+GAME    = NetHack                 # Game Name
+!ENDIF
+GAMEDIR = ..\binary               # Game directory
+
+#
+#  Source directories.    Makedefs hardcodes these, don't change them.
+#
+
+INCL  = ..\include   # NetHack include files
+DAT   = ..\dat       # NetHack data files
+DOC   = ..\doc       # NetHack documentation files
+UTIL  = ..\util      # Utility source
+SRC   = ..\src       # Main source
+SSYS  = ..\sys\share # Shared system files
+NTSYS = ..\sys\winnt # NT Win32 specific files
+TTY   = ..\win\tty   # window port files (tty)
+WIN32 = ..\win\win32 # window port files (Win32)
+WSHR  = ..\win\share # Tile support files 
+
+#
+#  Object directory.
+#
+
+OBJ     = o
+
+
+#
+#==========================================
+# Exe File Info.
+#==========================================
+# Yacc/Lex ... if you got 'em.
+#
+# If you have yacc and lex programs (or work-alike such as bison 
+# and flex), uncomment the upper two macros.
+#
+
+#DO_YACC  = YACC_ACT
+#DO_LEX   = LEX_ACT
+
+!IFNDEF DO_YACC
+DO_YACC = YACC_MSG
+!ENDIF
+!IFNDEF DO_LEX
+DO_LEX  = LEX_MSG
+!ENDIF
+
+# Wilbur Streett's Win32 ports of GNU bison and flex are available at:
+#    http://www.monmouth.com/~wstreett/lex-yacc/lex-yacc.html
+#
+# To use them, download the executables and templates (bison.simple,
+# bison.hairy) to some directory, and set the environment variables
+# BISON_SIMPLE and BISON_HAIRY, and your path to point to this
+# directory.
+#
+# For example, if you placed them in C:\BIN, you should set:
+#   C:> SET BISON_SIMPLE=C:\BIN\BISON.SIMPLE
+#   C:> SET BISON_HAIRY=C:\BIN\BISON.HAIRY
+#
+# Also, make sure your path points to the bison/flex directories.
+#
+# The following settings are configured for Wilbur Streett's ports.
+
+# - Specify your yacc and lex programs (or work-alikes) here.
+
+YACC   = bison -y
+#YACC   = byacc
+#YACC  = yacc
+
+#LEX   = lex
+LEX    = flex
+
+#
+# - Specify your flex skeleton file (if needed).
+#
+
+FLEXSKEL =
+#FLEXSKEL = -S../tools/flex.ske
+
+#YTABC   = y.tab.c
+#YTABH   = y.tab.h
+YTABC   = y_tab.c
+YTABH   = y_tab.h
+LEXYYC  = lex.yy.c
+
+#
+# Optional high-quality BSD random number generation routines
+# (see pcconf.h). Set to nothing if not used.
+#
+
+RANDOM = $(OBJ)\random.o
+#RANDOM        =
+
+#
+# Compiler and Linker flags
+#
+
+PRECOMPHEAD = N                        # set to Y if you want to use precomp. headers
+
+#===============================================
+#======= End of Modification Section ===========
+#===============================================
+################################################
+#                                              #
+# Nothing below here should have to be changed.#
+#                                              #
+################################################
+
+!IF "$(GRAPHICAL)" == "Y"
+WINPORT        = $(O)tile.o $(O)mhaskyn.o $(O)mhdlg.o \
+       $(O)mhfont.o $(O)mhinput.o $(O)mhmain.o $(O)mhmap.o \
+       $(O)mhmenu.o $(O)mhmsgwnd.o $(O)mhrip.o $(O)mhsplash.o \
+       $(O)mhstatus.o $(O)mhtext.o $(O)mswproc.o $(O)winhack.o
+WINPHDR        = $(WIN32)\mhaskyn.h $(WIN32)\mhdlg.h $(WIN32)\mhfont.h \
+       $(WIN32)\mhinput.h $(WIN32)\mhmain.h $(WIN32)\mhmap.h $(WIN32)\mhmenu.h \
+       $(WIN32)\mhmsg.h $(WIN32)\mhmsgwnd.h $(WIN32)\mhrip.h $(WIN32)\mhstatus.h \
+       $(WIN32)\mhtext.h $(WIN32)\resource.h $(WIN32)\winMS.h
+WINDLLS        =
+WINPFLAG= -DTILES -DMSWIN_GRAPHICS
+NHRES  = $(O)winhack.res
+WINPINC        = -I$(WIN32)
+!ELSE
+WINPORT        = $(O)nttty.o    
+WINPHDR        =
+WINDLLS        = $(GAMEDIR)\nhdefkey.dll $(GAMEDIR)\nh340key.dll $(GAMEDIR)\nhraykey.dll
+WINPFLAG= -DWIN32CON
+NHRES  = $(O)console.res
+WINPINC        =
+!ENDIF
+
+TILEUTIL16  = $(UTIL)\tile2bmp.exe
+TILEBMP16   = $(SRC)\tiles.bmp
+
+TILEUTIL32  = $(UTIL)\til2bm32.exe
+TILEBMP32   = $(SRC)\tiles32.bmp
+
+SOUND = $(OBJ)\ntsound.o
+#SOUND =
+
+# To store all the level files,
+# help files, etc. in a single library file.
+# USE_DLB = Y is left uncommented
+
+USE_DLB = Y
+
+! IF ("$(USE_DLB)"=="Y")
+DLBFLG = -DDLB
+! ELSE
+DLBFLG =
+! ENDIF
+
+
+#==========================================
+# Setting up the compiler and linker
+# macros. All builds include the base ones.
+#==========================================
+
+CFLAGSBASE  = -c $(cflags) $(cvarsmt) -I$(INCL) $(WINPINC) -q $(cdebug) -v
+LFLAGSBASE  = $(linkdebug) $(verlflags) -L$(bcclib) -v
+
+#==========================================
+# Util builds
+#==========================================
+
+CFLAGSU = $(CFLAGSBASE) $(WINPFLAG)
+LFLAGSU        = $(LFLAGSBASE)
+
+#==========================================
+# - Game build
+#==========================================
+
+LFLAGSBASE = $(linkdebug) $(conflags) 
+CFLAGS  = $(CFLAGSBASE) $(WINPFLAG) $(DLBFLG)
+NHLFLAGS1 = /Gn /v /m /s /Gz /q /c
+lflags = $(LFLAGSBASE) $(NHLFLAGS1)
+
+GAMEFILE = $(FDIR)\$(GAME).exe # whole thing
+
+! IF ("$(USE_DLB)"=="Y")
+DLB = nhdat
+! ELSE
+DLB =
+! ENDIF
+
+#==========================================
+#================ RULES ==================
+#==========================================
+
+.SUFFIXES: .exe .o .til .uu .c .y .l
+
+#==========================================
+# Rules for files in src
+#==========================================
+
+.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -o$@ $<
+
+{$(SRC)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)   -o$@  $<
+
+#==========================================
+# Rules for files in sys\share
+#==========================================
+
+{$(SSYS)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -o$@  $<
+
+#==========================================
+# Rules for files in sys\winnt
+#==========================================
+
+{$(NTSYS)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -o$@  $<
+
+{$(NTSYS)}.h{$(INCL)}.h:
+       @copy $< $@
+
+#==========================================
+# Rules for files in util
+#==========================================
+
+{$(UTIL)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGSU) -o$@ $<
+
+#==========================================
+# Rules for files in win\share
+#==========================================
+
+{$(WSHR)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -o$@ $<
+
+{$(WSHR)}.h{$(INCL)}.h:
+       @copy $< $@
+
+#{$(WSHR)}.txt{$(DAT)}.txt:
+#      @copy $< $@
+
+#==========================================
+# Rules for files in win\tty
+#==========================================
+
+{$(TTY)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -o$@  $<
+
+#==========================================
+# Rules for files in win\win32
+#==========================================
+
+{$(WIN32)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -o$@  $<
+
+#==========================================
+#================ MACROS ==================
+#==========================================
+# This section creates shorthand macros for many objects
+# referenced later on in the Makefile.
+#
+
+DEFFILE = $(NTSYS)\$(GAME).def
+
+#
+# Shorten up the location for some files
+#
+
+O  = $(OBJ)^\
+
+U  = $(UTIL)^\
+
+#
+# Utility Objects.
+#
+
+MAKESRC        = $(U)makedefs.c
+
+SPLEVSRC       = $(U)lev_yacc.c        $(U)lev_$(LEX).c $(U)lev_main.c  $(U)panic.c
+
+DGNCOMPSRC     = $(U)dgn_yacc.c        $(U)dgn_$(LEX).c $(U)dgn_main.c
+
+MAKEOBJS       = $(O)makedefs.o $(O)monst.o $(O)objects.o
+
+SPLEVOBJS      = $(O)lev_yacc.o        $(O)lev_$(LEX).o $(O)lev_main.o \
+                $(O)alloc.o    $(O)decl.o      $(O)drawing.o \
+                $(O)monst.o    $(O)objects.o   $(O)panic.o
+
+DGNCOMPOBJS    = $(O)dgn_yacc.o        $(O)dgn_$(LEX).o $(O)dgn_main.o \
+                $(O)alloc.o    $(O)panic.o
+
+RECOVOBJS      = $(O)recover.o
+
+TILEFILES      = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt
+
+#
+# These are not invoked during a normal game build in 3.4
+#
+TEXT_IO        = $(O)tiletext.o        $(O)tiletxt.o   $(O)drawing.o \
+                $(O)decl.o     $(O)monst.o     $(O)objects.o
+
+GIFREADERS     = $(O)gifread.o $(O)alloc.o $(O)panic.o
+
+PPMWRITERS     = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o
+
+#
+#  Object files for the game itself.
+#
+
+VOBJ01 = $(O)allmain.o  $(O)alloc.o    $(O)apply.o    $(O)artifact.o
+VOBJ02 = $(O)attrib.o   $(O)ball.o     $(O)bones.o    $(O)botl.o    
+VOBJ03 = $(O)cmd.o      $(O)dbridge.o  $(O)decl.o     $(O)detect.o  
+VOBJ04 = $(O)dig.o      $(O)display.o  $(O)do.o       $(O)do_name.o 
+VOBJ05 = $(O)do_wear.o  $(O)dog.o      $(O)dogmove.o  $(O)dokick.o  
+VOBJ06 = $(O)dothrow.o  $(O)drawing.o  $(O)dungeon.o  $(O)eat.o     
+VOBJ07 = $(O)end.o      $(O)engrave.o  $(O)exper.o    $(O)explode.o 
+VOBJ08 = $(O)extralev.o $(O)files.o    $(O)fountain.o $(O)hack.o    
+VOBJ09 = $(O)hacklib.o  $(O)invent.o   $(O)light.o    $(O)lock.o    
+VOBJ10 = $(O)mail.o     $(O)makemon.o  $(O)mapglyph.o $(O)mcastu.o  
+VOBJ11 = $(O)mhitm.o    $(O)mhitu.o    $(O)minion.o   $(O)mklev.o   
+VOBJ12 = $(O)mkmap.o    $(O)mkmaze.o   $(O)mkobj.o    $(O)mkroom.o  
+VOBJ13 = $(O)mon.o      $(O)mondata.o  $(O)monmove.o  $(O)monst.o   
+VOBJ14 = $(O)monstr.o   $(O)mplayer.o  $(O)mthrowu.o  $(O)muse.o    
+VOBJ15 = $(O)music.o    $(O)o_init.o   $(O)objects.o  $(O)objnam.o  
+VOBJ16 = $(O)options.o  $(O)pager.o    $(O)pickup.o   $(O)pline.o   
+VOBJ17 = $(O)polyself.o $(O)potion.o   $(O)pray.o     $(O)priest.o  
+VOBJ18 = $(O)quest.o    $(O)questpgr.o $(RANDOM)      $(O)read.o    
+VOBJ19 = $(O)rect.o     $(O)region.o   $(O)restore.o  $(O)rip.o     
+VOBJ20 = $(O)rnd.o      $(O)role.o     $(O)rumors.o   $(O)save.o    
+VOBJ21 = $(O)shk.o      $(O)shknam.o   $(O)sit.o      $(O)sounds.o  
+VOBJ22 = $(O)sp_lev.o   $(O)spell.o    $(O)steal.o    $(O)steed.o   
+VOBJ23 = $(O)teleport.o $(O)timeout.o  $(O)topten.o   $(O)track.o   
+VOBJ24 = $(O)trap.o     $(O)u_init.o   $(O)uhitm.o    $(O)vault.o   
+VOBJ25 = $(O)vis_tab.o  $(O)vision.o   $(O)weapon.o   $(O)were.o    
+VOBJ26 = $(O)wield.o    $(O)windows.o  $(O)wizard.o   $(O)worm.o    
+VOBJ27 = $(O)worn.o     $(O)write.o    $(O)zap.o     
+
+DLBOBJ = $(O)dlb.o
+
+TTYOBJ = $(O)topl.o     $(O)getline.o  $(O)wintty.o
+
+SOBJ   = $(O)winnt.o    $(O)pcsys.o      $(O)pcunix.o  \
+          $(SOUND) $(O)pcmain.o        $(O)mapimail.o $(O)nhlan.o
+
+OBJS   = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \
+         $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \
+         $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \
+         $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \
+         $(VOBJ21) $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) \
+         $(VOBJ26) $(VOBJ27)
+
+TILOBJ = $(WINPORT)
+
+VVOBJ  = $(O)version.o
+
+ALLOBJ  = $(TILOBJ) $(SOBJ) $(DLBOBJ)  $(TTYOBJ) $(WOBJ) $(OBJS) $(VVOBJ)
+
+
+!IF "$(GRAPHICAL)" == "Y"
+OPTIONS_FILE = $(DAT)\guioptions
+!ELSE
+OPTIONS_FILE = $(DAT)\ttyoptions
+!ENDIF
+#==========================================
+# Header file macros
+#==========================================
+
+CONFIG_H = $(INCL)\config.h $(INCL)\config1.h $(INCL)\tradstdc.h \
+               $(INCL)\global.h $(INCL)\coord.h $(INCL)\vmsconf.h \
+               $(INCL)\system.h $(INCL)\unixconf.h $(INCL)\os2conf.h \
+               $(INCL)\micro.h $(INCL)\pcconf.h $(INCL)\tosconf.h \
+               $(INCL)\amiconf.h $(INCL)\macconf.h $(INCL)\beconf.h \
+               $(INCL)\ntconf.h $(INCL)\nhlan.h
+
+HACK_H = $(INCL)\hack.h $(CONFIG_H) $(INCL)\align.h \
+               $(INCL)\dungeon.h $(INCL)\monsym.h $(INCL)\mkroom.h \
+               $(INCL)\objclass.h $(INCL)\youprop.h $(INCL)\prop.h \
+               $(INCL)\permonst.h $(INCL)\monattk.h \
+               $(INCL)\monflag.h $(INCL)\mondata.h $(INCL)\pm.h \
+               $(INCL)\wintype.h $(INCL)\decl.h $(INCL)\quest.h \
+               $(INCL)\spell.h $(INCL)\color.h $(INCL)\obj.h \
+               $(INCL)\you.h $(INCL)\attrib.h $(INCL)\monst.h \
+               $(INCL)\skills.h $(INCL)\onames.h $(INCL)\timeout.h \
+               $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \
+               $(INCL)\vision.h $(INCL)\display.h $(INCL)\engrave.h \
+               $(INCL)\rect.h $(INCL)\region.h $(INCL)\winprocs.h \
+               $(INCL)\wintty.h $(INCL)\trampoli.h
+
+LEV_H       = $(INCL)\lev.h
+DGN_FILE_H  = $(INCL)\dgn_file.h
+LEV_COMP_H  = $(INCL)\lev_comp.h
+SP_LEV_H    = $(INCL)\sp_lev.h
+TILE_H      = ..\win\share\tile.h
+
+#==========================================
+# Miscellaneous
+#==========================================
+
+DATABASE = $(DAT)\data.base
+
+#
+#  The name of the game.
+#
+
+GAMEFILE = $(GAMEDIR)\$(GAME).exe
+
+#==========================================
+#=============== TARGETS ==================
+#==========================================
+
+#
+#  The default make target (so just typing 'nmake' is useful).
+#
+default : $(GAMEFILE)
+
+#
+#  The main target.
+#
+
+$(GAME): $(O)obj.tag $(O)utility.tag graphicschk $(GAMEFILE)
+       @echo $(GAME) is up to date.
+
+#
+#  Everything
+#
+
+all :  install
+
+install: graphicschk $(GAME) $(O)install.tag
+        @echo Done.
+
+$(O)install.tag:       $(DAT)\data     $(DAT)\rumors    $(DAT)\dungeon \
+               $(DAT)\oracles  $(DAT)\quest.dat $(O)sp_lev.tag $(DLB)
+! IF ("$(USE_DLB)"=="Y")
+       copy nhdat                $(GAMEDIR)
+       copy $(DAT)\license       $(GAMEDIR)
+       copy $(DAT)\opthelp       $(GAMEDIR)
+! ELSE
+       copy $(DAT)\*.            $(GAMEDIR)
+       copy $(DAT)\*.dat         $(GAMEDIR)
+       copy $(DAT)\*.lev         $(GAMEDIR)
+       if exist $(GAMEDIR)\makefile del $(GAMEDIR)\makefile
+! ENDIF
+       if exist $(DOC)\guidebook.txt copy $(DOC)\guidebook.txt $(GAMEDIR)\Guidebook.txt
+       if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt $(GAMEDIR)\NetHack.txt
+       @if exist $(SRC)\$(GAME).PDB copy $(SRC)\$(GAME).pdb $(GAMEDIR)\$(GAME).pdb
+       @if exist $(GAMEDIR)\$(GAME).PDB echo NOTE: You may want to remove $(GAMEDIR)\$(GAME).pdb to conserve space
+       -copy $(NTSYS)\defaults.nh   $(GAMEDIR)\defaults.nh
+       echo install done > $@
+
+#      copy $(NTSYS)\winnt.hlp    $(GAMEDIR)
+
+recover: $(U)recover.exe
+       if exist $(U)recover.exe copy $(U)recover.exe  $(GAMEDIR)
+       if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR)\recover.txt
+
+$(O)sp_lev.tag: $(O)utility.tag $(DAT)\bigroom.des  $(DAT)\castle.des \
+       $(DAT)\endgame.des $(DAT)\gehennom.des $(DAT)\knox.des   \
+       $(DAT)\medusa.des  $(DAT)\oracle.des   $(DAT)\tower.des  \
+       $(DAT)\yendor.des  $(DAT)\arch.des     $(DAT)\barb.des   \
+       $(DAT)\caveman.des $(DAT)\healer.des   $(DAT)\knight.des \
+       $(DAT)\monk.des    $(DAT)\priest.des   $(DAT)\ranger.des \
+       $(DAT)\rogue.des   $(DAT)\samurai.des  $(DAT)\sokoban.des \
+       $(DAT)\tourist.des $(DAT)\valkyrie.des $(DAT)\wizard.des
+       cd $(DAT)
+       $(U)lev_comp bigroom.des
+       $(U)lev_comp castle.des
+       $(U)lev_comp endgame.des
+       $(U)lev_comp gehennom.des
+       $(U)lev_comp knox.des
+       $(U)lev_comp mines.des
+       $(U)lev_comp medusa.des
+       $(U)lev_comp oracle.des
+       $(U)lev_comp sokoban.des
+       $(U)lev_comp tower.des
+       $(U)lev_comp yendor.des
+       $(U)lev_comp arch.des
+       $(U)lev_comp barb.des
+       $(U)lev_comp caveman.des
+       $(U)lev_comp healer.des
+       $(U)lev_comp knight.des
+       $(U)lev_comp monk.des
+       $(U)lev_comp priest.des
+       $(U)lev_comp ranger.des
+       $(U)lev_comp rogue.des
+       $(U)lev_comp samurai.des
+       $(U)lev_comp tourist.des
+       $(U)lev_comp valkyrie.des
+       $(U)lev_comp wizard.des
+       cd $(SRC)
+       echo sp_levs done > $(O)sp_lev.tag
+
+$(O)utility.tag: $(INCL)\date.h $(INCL)\onames.h $(INCL)\pm.h \
+               $(SRC)\monstr.c         $(SRC)\vis_tab.c  \
+               $(U)lev_comp.exe        $(INCL)\vis_tab.h \
+               $(U)dgn_comp.exe $(TILEUTIL16)
+             @echo utilities made >$@
+            @echo utilities made.
+
+tileutil: $(U)gif2txt.exe $(U)txt2ppm.exe
+       @echo Optional tile development utilities are up to date.
+
+!IF "$(GRAPHICAL)"=="Y"
+$(NHRES): $(TILEBMP16) $(WIN32)\winhack.rc $(WIN32)\mnsel.bmp \
+       $(WIN32)\mnselcnt.bmp $(WIN32)\mnunsel.bmp \
+       $(WIN32)\petmark.bmp $(WIN32)\NetHack.ico $(WIN32)\rip.bmp \
+       $(WIN32)\splash.bmp
+       @$(rc) -r -fo$@ -i$(WIN32) -i$(bccinc) -dNDEBUG $(WIN32)\winhack.rc
+!ELSE
+$(NHRES): $(NTSYS)\console.rc $(NTSYS)\NetHack.ico
+       @$(rc) -r -fo$@ -i$(NTSYS) -i$(bccinc) -dNDEBUG $(NTSYS)\console.rc
+!ENDIF
+
+#==========================================
+#  The main target.
+#==========================================
+
+$(SRC)\uuid.lib: $(bcclib)\uuid.lib
+       @copy $(bcclib)\uuid.lib $@
+
+$(GAMEFILE) : $(ALLOBJ) $(NHRES) $(SRC)\uuid.lib $(O)gamedir.tag $(WINDLLS)
+       @echo Linking....
+       @$(link) $(lflags) $(startobjg) $(ALLOBJ), $@, $(GAME).map,$(libsmt),,$(NHRES)
+       @if exist $(O)install.tag del $(O)install.tag
+       @if exist $(GAMEDIR)\$(GAME).bak del $(GAMEDIR)\$(GAME).bak
+
+$(O)gamedir.tag:
+       @if not exist $(GAMEDIR)\*.* echo creating directory $(GAMEDIR)
+       @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
+       @echo directory created > $@
+
+$(GAME)_.ico : $(NTSYS)\$(GAME).ico
+       @copy $(NTSYS)\$(GAME).ico $@
+
+#==========================================
+# Create directory for holding object files
+#==========================================
+
+$(O)obj.tag:
+       @if not exist $(O)*.* mkdir $(OBJ)
+       @echo directory $(OBJ) created >$@
+
+#==========================================
+# Notify of any CL environment variables
+# in effect since they change the compiler
+# options.
+#==========================================
+
+graphicschk:
+!      IF "$(GRAPHICAL)"=="Y"
+          @echo ----
+          @echo NOTE: This build will include tile support.
+          @echo ----
+!      ENDIF
+       @echo graphicschk > graphicschk
+
+
+$(GAMEDIR)\nhdefkey.dll : $(O)nhdefkey.o
+       @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
+       @echo EXPORTS >nhdefkey.def
+       @echo    ProcessKeystroke >>nhdefkey.def
+       @echo    NHkbhit >>nhdefkey.def
+       @echo    CheckInput >>nhdefkey.def
+       @echo    SourceWhere >>nhdefkey.def
+       @echo    SourceAuthor >>nhdefkey.def
+       @echo    KeyHandlerName >>nhdefkey.def
+       @echo Linking $@
+       $(link) $(linkdebug) /Gn /Gz /q -L$(bcclib) /c  /aa /Tpd /V$(APPVER) -L$(bcclib) -v \
+           c0d32.obj $(O)nhdefkey.o, $@,nhdefkey.map,$(libsmt),nhdefkey.def
+
+$(GAMEDIR)\nh340key.dll : $(O)nh340key.o
+       @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
+       @echo EXPORTS >nh340key.def
+       @echo    ProcessKeystroke >>nh340key.def
+       @echo    NHkbhit >>nh340key.def
+       @echo    CheckInput >>nh340key.def
+       @echo    SourceWhere >>nh340key.def
+       @echo    SourceAuthor >>nh340key.def
+       @echo    KeyHandlerName >>nh340key.def
+       @echo Linking $@
+       $(link) $(linkdebug) /Gn /Gz /q -L$(bcclib) /c  /aa /Tpd /V$(APPVER) -L$(bcclib) -v \
+           c0d32.obj $(O)nh340key.o, $@,nh340key.map,$(libsmt),nh340key.def
+
+$(GAMEDIR)\nhraykey.dll : $(O)nhraykey.o
+       @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
+       @echo EXPORTS >nhraykey.def
+       @echo    ProcessKeystroke >>nhraykey.def
+       @echo    NHkbhit >>nhraykey.def
+       @echo    CheckInput >>nhraykey.def
+       @echo    SourceWhere >>nhraykey.def
+       @echo    SourceAuthor >>nhraykey.def
+       @echo    KeyHandlerName >>nhraykey.def
+       @echo Linking $@
+       $(link) $(linkdebug) /Gn /Gz /q -L$(bcclib) /c  /aa /Tpd /V$(APPVER) -L$(bcclib) -v \
+           c0d32.obj $(O)nhraykey.o, $@,nhraykey.map,$(libsmt),nhraykey.def
+
+#
+#  Secondary Targets.
+#
+    
+#==========================================
+# Makedefs Stuff
+#==========================================
+
+$(U)makedefs.exe:      $(O)obj.tag $(MAKEOBJS) $(SRC)\uuid.lib
+       @$(link) $(LFLAGSU) $(startobj) $(MAKEOBJS), $@,,$(libsmt)
+
+$(O)makedefs.o: $(CONFIG_H)    $(INCL)\monattk.h $(INCL)\monflag.h   $(INCL)\objclass.h \
+                $(INCL)\monsym.h    $(INCL)\qtext.h    $(INCL)\patchlevel.h \
+                $(U)makedefs.c
+       @$(cc) $(CFLAGSU) -o$@ $(U)makedefs.c
+
+#
+#  date.h should be remade every time any of the source or include
+#  files is modified.
+#
+
+$(INCL)\date.h $(OPTIONS_FILE) : $(U)makedefs.exe
+       $(U)makedefs -v
+
+$(INCL)\onames.h : $(U)makedefs.exe
+       $(U)makedefs -o
+
+$(INCL)\pm.h : $(U)makedefs.exe
+       $(U)makedefs -p
+
+#$(INCL)\trap.h : $(U)makedefs.exe
+#      $(U)makedefs -t
+
+$(SRC)\monstr.c: $(U)makedefs.exe
+       $(U)makedefs -m
+
+$(INCL)\vis_tab.h: $(U)makedefs.exe
+       $(U)makedefs -z
+
+$(SRC)\vis_tab.c: $(U)makedefs.exe
+       $(U)makedefs -z
+
+#==========================================
+# uudecode utility and uuencoded targets
+#==========================================
+
+$(U)uudecode.exe: $(O)uudecode.o
+       @$(link) $(LFLAGSU) $(startobj) $(O)uudecode.o, $@,,$(libsmt)
+
+$(O)uudecode.o: $(SSYS)\uudecode.c
+
+$(NTSYS)\NetHack.ico : $(U)uudecode.exe $(NTSYS)\nhico.uu
+       chdir $(NTSYS)
+       ..\..\util\uudecode.exe nhico.uu
+       chdir ..\..\src
+
+$(WIN32)\NetHack.ico : $(U)uudecode.exe $(NTSYS)\nhico.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu
+       chdir ..\..\src
+
+$(WIN32)\mnsel.bmp: $(U)uudecode.exe $(WIN32)\mnsel.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe mnsel.uu
+       chdir ..\..\src
+
+$(WIN32)\mnselcnt.bmp: $(U)uudecode.exe $(WIN32)\mnselcnt.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe mnselcnt.uu
+       chdir ..\..\src
+
+$(WIN32)\mnunsel.bmp: $(U)uudecode.exe $(WIN32)\mnunsel.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe mnunsel.uu
+       chdir ..\..\src
+
+$(WIN32)\petmark.bmp: $(U)uudecode.exe $(WIN32)\petmark.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe petmark.uu
+       chdir ..\..\src
+
+$(WIN32)\rip.bmp: $(U)uudecode.exe $(WIN32)\rip.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe rip.uu
+       chdir ..\..\src
+
+$(WIN32)\splash.bmp: $(U)uudecode.exe $(WIN32)\splash.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe splash.uu
+       chdir ..\..\src
+
+#==========================================
+# Level Compiler Stuff
+#==========================================
+
+LEVCFLAGS=$(cflags) -DWIN32 -D_WIN32 -D_MT -I..\include $(cdebug) -DDLB
+
+$(U)lev_comp.exe: $(SPLEVOBJS) $(SRC)\uuid.lib
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) $(startobj) $(SPLEVOBJS), $@,,$(libsmt)
+
+$(O)lev_yacc.o: $(HACK_H)   $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c
+       @$(cc) $(LEVCFLAGS) -o$@ $(U)lev_yacc.c
+
+$(O)lev_$(LEX).o: $(HACK_H)   $(INCL)\lev_comp.h $(SP_LEV_H) \
+               $(U)lev_$(LEX).c
+       @$(cc) $(LEVCFLAGS) -D__IO_H -o$@ $(U)lev_$(LEX).c
+
+$(O)lev_main.o:        $(U)lev_main.c $(HACK_H)   $(SP_LEV_H)
+       @$(cc) $(LEVCFLAGS) -o$@ $(U)lev_main.c
+
+
+$(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y
+!      IF "$(DO_YACC)"=="YACC_ACT"
+          chdir $(UTIL)
+          $(YACC) -d lev_comp.y
+          copy $(YTABC) lev_yacc.c
+          copy $(YTABH) $(INCL)\lev_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)lev_comp.y has changed.
+          @echo To update $(U)lev_yacc.c and $(INCL)\lev_comp.h run $(YACC).
+          @echo ---
+          @echo For now, we will copy the prebuilt lev_yacc.c and 
+          @echo lev_comp.h from $(SSYS) into $(UTIL) and use them.
+          @copy $(SSYS)\lev_yacc.c $(U)lev_yacc.c >nul
+          @copy $(SSYS)\lev_comp.h $(INCL)\lev_comp.h >nul
+          @echo /**/ >>$(U)lev_yacc.c
+          @echo /**/ >>$(INCL)\lev_comp.h
+!      ENDIF
+
+$(U)lev_$(LEX).c: $(U)lev_comp.l
+!      IF "$(DO_LEX)"=="LEX_ACT"
+          chdir $(UTIL)
+          $(LEX) $(FLEXSKEL) lev_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)lev_comp.l has changed. To update $@ run $(LEX).
+          @echo ---
+          @echo For now, we will copy the prebuilt lev_lex.c 
+          @echo from $(SSYS) into $(UTIL) and use it.
+          @copy $(SSYS)\lev_lex.c $@ >nul
+          @echo /**/ >>$@
+!      ENDIF
+
+#==========================================
+# Dungeon Compiler Stuff
+#==========================================
+
+$(U)dgn_comp.exe: $(DGNCOMPOBJS) $(SRC)\uuid.lib
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) $(startobj) $(DGNCOMPOBJS), $@,,$(libsmt)
+
+
+$(O)dgn_yacc.o:        $(HACK_H)   $(DGN_FILE_H) $(INCL)\dgn_comp.h $(U)dgn_yacc.c
+       @$(cc) $(LEVCFLAGS) -o$@ $(U)dgn_yacc.c
+
+$(O)dgn_$(LEX).o: $(HACK_H)   $(DGN_FILE_H)  $(INCL)\dgn_comp.h \
+       $(U)dgn_$(LEX).c
+       @$(cc) $(LEVCFLAGS) -D__IO_H -o$@ $(U)dgn_$(LEX).c
+
+$(O)dgn_main.o:        $(HACK_H) $(U)dgn_main.c
+       @$(cc) $(LEVCFLAGS) -o$@ $(U)dgn_main.c
+
+$(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y
+!      IF "$(DO_YACC)"=="YACC_ACT"
+          chdir $(UTIL)
+          $(YACC) -d dgn_comp.y
+          copy $(YTABC) dgn_yacc.c
+          copy $(YTABH) $(INCL)\dgn_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)dgn_comp.y has changed. To update dgn_yacc.c and 
+          @echo $(INCL)\dgn_comp.h run $(YACC).
+          @echo ---
+          @echo For now, we will copy the prebuilt $(U)dgn_yacc.c and 
+          @echo dgn_comp.h from $(SSYS) into $(UTIL) and use them.
+          @copy $(SSYS)\dgn_yacc.c $(U)dgn_yacc.c >nul
+          @copy $(SSYS)\dgn_comp.h $(INCL)\dgn_comp.h >nul
+          @echo /**/ >>$(U)dgn_yacc.c
+          @echo /**/ >>$(INCL)\dgn_comp.h
+!      ENDIF
+
+$(U)dgn_$(LEX).c: $(U)dgn_comp.l
+!      IF "$(DO_LEX)"=="LEX_ACT"
+          chdir $(UTIL)
+          $(LEX) $(FLEXSKEL)  dgn_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX).
+          @echo ---
+          @echo For now, we will copy the prebuilt dgn_lex.c 
+          @echo from $(SSYS) into $(UTIL) and use it.
+          @copy $(SSYS)\dgn_lex.c $@ >nul
+          @echo /**/ >>$@
+!      ENDIF
+
+
+#==========================================
+#=========== SECONDARY TARGETS ============
+#==========================================
+
+#===========================================
+# Header files NOT distributed in ..\include
+#===========================================
+
+$(INCL)\win32api.h: $(NTSYS)\win32api.h
+       copy $(NTSYS)\win32api.h $@
+
+
+#==========================================
+# DLB utility and nhdat file creation
+#==========================================
+
+$(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o $(SRC)\uuid.lib
+       @$(link) $(LFLAGSU) $(startobj) $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o, $@,,$(libsmt)
+
+
+$(O)dlb.o:     $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)\dlb.h
+       @$(cc) $(CFLAGS) -o$@ $(SRC)\dlb.c
+       
+$(O)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h
+       @$(cc) $(CFLAGS) -o$@ $(UTIL)\dlb_main.c
+
+$(DAT)\porthelp: $(NTSYS)\porthelp
+       @copy $(NTSYS)\porthelp $@ >nul
+
+nhdat: $(U)dlb_main.exe $(DAT)\data $(DAT)\oracles $(OPTIONS_FILE) \
+       $(DAT)\quest.dat $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp \
+       $(DAT)\history $(DAT)\opthelp $(DAT)\wizhelp $(DAT)\dungeon $(DAT)\porthelp \
+       $(DAT)\license $(O)sp_lev.tag
+       cd $(DAT)
+       echo data >dlb.lst
+       echo oracles >>dlb.lst
+       if exist options echo options >>dlb.lst
+       if exist ttyoptions echo ttyoptions >>dlb.lst
+       if exist guioptions echo guioptions >>dlb.lst
+       if exist porthelp echo porthelp >>dlb.lst
+       echo quest.dat >>dlb.lst
+       echo rumors >>dlb.lst
+       echo help >>dlb.lst
+       echo hh >>dlb.lst
+       echo cmdhelp >>dlb.lst
+       echo history >>dlb.lst
+       echo opthelp >>dlb.lst
+       echo wizhelp >>dlb.lst
+       echo dungeon >>dlb.lst
+       echo license >>dlb.lst
+       for %N in (*.lev) do echo %N >>dlb.lst
+       $(U)dlb_main cIf dlb.lst $(SRC)\nhdat
+       cd $(SRC)
+
+#==========================================
+#  Recover Utility
+#==========================================
+
+$(U)recover.exe: $(RECOVOBJS) $(SRC)\uuid.lib
+       $(link) $(LFLAGSU) $(startobj) $(RECOVOBJS), $@,,$(libsmt)
+
+
+$(O)recover.o: $(CONFIG_H) $(U)recover.c $(INCL)\win32api.h
+       $(cc) $(CFLAGSU) -o$@ $(U)recover.c
+
+#==========================================
+#  Tile Mapping
+#==========================================
+
+$(SRC)\tile.c: $(U)tilemap.exe
+       @echo A new $@ has been created
+       @$(U)tilemap
+
+$(U)tilemap.exe: $(O)tilemap.o $(SRC)\uuid.lib
+       @$(link) $(LFLAGSU) $(startobj) $(O)tilemap.o, $@,,$(libsmt)
+
+
+$(O)tilemap.o: $(WSHR)\tilemap.c $(HACK_H)
+       @$(cc) $(CFLAGSU) -o$@ $(WSHR)\tilemap.c
+
+$(O)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H)
+       @$(cc) $(CFLAGS) /DTILETEXT -o$@ $(WSHR)\tilemap.c
+
+$(O)gifread.o: $(WSHR)\gifread.c  $(CONFIG_H) $(TILE_H)
+       @$(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)\gifread.c
+
+$(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(TILE_H)
+       @$(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)\ppmwrite.c
+
+$(O)tiletext.o: $(WSHR)\tiletext.c  $(CONFIG_H) $(TILE_H)
+       @$(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)\tiletext.c
+
+#==========================================
+# Optional Tile Utilities
+#==========================================
+
+$(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO) $(SRC)\uuid.lib
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) $(startobj) $(GIFREADERS) $(TEXT_IO), $@,,$(libsmt)
+
+
+$(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO) $(SRC)\uuid.lib
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) $(startobj) $(PPMWRITERS) $(TEXT_IO), $@,,$(libsmt)
+
+
+!IF "$(GRAPHICAL)"=="Y"
+$(TILEBMP16): $(TILEUTIL16) $(TILEFILES)
+       @echo Creating 16x16 binary tile files (this may take some time)
+       @$(U)tile2bmp $(TILEBMP16)
+!ENDIF
+
+$(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO) $(SRC)\uuid.lib
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) $(startobj) $(O)tile2bmp.o $(TEXT_IO), $@,,$(libsmt)
+
+
+$(O)tile2bmp.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h
+       @$(cc) $(CFLAGS) -I$(WSHR) /DPACKED_FILE -o$@ $(WSHR)\tile2bmp.c
+
+#==========================================
+# Housekeeping
+#==========================================
+
+spotless: clean
+! IF ("$(OBJ)"!="")
+       -rmdir $(OBJ) /s /Q
+! ENDIF
+       if exist $(INCL)\date.h    del $(INCL)\date.h
+       if exist $(INCL)\onames.h  del $(INCL)\onames.h
+       if exist $(INCL)\pm.h      del $(INCL)\pm.h
+       if exist $(INCL)\vis_tab.h del $(INCL)\vis_tab.h
+       if exist $(SRC)\vis_tab.c  del $(SRC)\vis_tab.c
+       if exist $(SRC)\tile.c     del $(SRC)\tile.c
+       if exist $(U)*.lnk         del $(U)*.lnk
+       if exist $(U)*.map         del $(U)*.map
+       if exist $(DAT)\data       del $(DAT)\data
+       if exist $(DAT)\rumors     del $(DAT)\rumors
+       if exist $(DAT)\???-fil?.lev    del $(DAT)\???-fil?.lev
+       if exist $(DAT)\???-goal.lev    del $(DAT)\???-goal.lev
+       if exist $(DAT)\???-loca.lev    del $(DAT)\???-loca.lev
+       if exist $(DAT)\???-strt.lev    del $(DAT)\???-strt.lev
+       if exist $(DAT)\air.lev         del $(DAT)\air.lev
+       if exist $(DAT)\asmodeus.lev    del $(DAT)\asmodeus.lev
+       if exist $(DAT)\astral.lev      del $(DAT)\astral.lev
+       if exist $(DAT)\baalz.lev       del $(DAT)\baalz.lev
+       if exist $(DAT)\bigroom.lev     del $(DAT)\bigroom.lev
+       if exist $(DAT)\castle.lev      del $(DAT)\castle.lev
+       if exist $(DAT)\data            del $(DAT)\data
+       if exist $(DAT)\dungeon         del $(DAT)\dungeon
+       if exist $(DAT)\dungeon.pdf     del $(DAT)\dungeon.pdf
+       if exist $(DAT)\earth.lev       del $(DAT)\earth.lev
+       if exist $(DAT)\fakewiz?.lev    del $(DAT)\fakewiz?.lev
+       if exist $(DAT)\fire.lev        del $(DAT)\fire.lev
+       if exist $(DAT)\juiblex.lev     del $(DAT)\juiblex.lev
+       if exist $(DAT)\knox.lev        del $(DAT)\knox.lev
+       if exist $(DAT)\medusa-?.lev    del $(DAT)\medusa-?.lev
+       if exist $(DAT)\mine*.lev       del $(DAT)\mine*.lev
+       if exist $(DAT)\options         del $(DAT)\options
+       if exist $(DAT)\ttyoptions      del $(DAT)\ttyoptions
+       if exist $(DAT)\guioptions      del $(DAT)\guioptions
+       if exist $(DAT)\oracle.lev      del $(DAT)\oracle.lev
+       if exist $(DAT)\oracles         del $(DAT)\oracles
+       if exist $(DAT)\orcus.lev       del $(DAT)\orcus.lev
+       if exist $(DAT)\rumors          del $(DAT)\rumors
+       if exist $(DAT)\quest.dat       del $(DAT)\quest.dat
+       if exist $(DAT)\sanctum.lev     del $(DAT)\sanctum.lev
+       if exist $(DAT)\soko?-?.lev     del $(DAT)\soko?-?.lev
+       if exist $(DAT)\tower?.lev      del $(DAT)\tower?.lev
+       if exist $(DAT)\valley.lev      del $(DAT)\valley.lev
+       if exist $(DAT)\water.lev       del $(DAT)\water.lev
+       if exist $(DAT)\wizard?.lev     del $(DAT)\wizard?.lev
+       if exist $(O)sp_lev.tag         del $(O)sp_lev.tag
+       if exist $(SRC)\monstr.c        del $(SRC)\monstr.c
+       if exist $(SRC)\vis_tab.c       del $(SRC)\vis_tab.c
+       if exist $(U)recover.exe        del $(U)recover.exe
+       if exist nhdat.                 del nhdat.
+
+clean:
+       if exist $(O)*.o del $(O)*.o
+       if exist $(O)utility.tag   del $(O)utility.tag
+       if exist $(U)makedefs.exe  del $(U)makedefs.exe
+       if exist $(U)lev_comp.exe  del $(U)lev_comp.exe
+       if exist $(U)dgn_comp.exe  del $(U)dgn_comp.exe
+       if exist $(SRC)\*.lnk      del $(SRC)\*.lnk
+       if exist $(SRC)\*.map      del $(SRC)\*.map
+       if exist $(TILEBMP16)        del $(TILEBMP16)
+
+#===================================================================
+# OTHER DEPENDENCIES
+#===================================================================
+
+#
+# dat dependencies
+#
+
+$(DAT)\data: $(O)utility.tag    $(DATABASE)
+       $(U)makedefs -d
+
+$(DAT)\rumors: $(O)utility.tag    $(DAT)\rumors.tru   $(DAT)\rumors.fal
+       $(U)makedefs -r
+
+$(DAT)\quest.dat: $(O)utility.tag  $(DAT)\quest.txt
+       $(U)makedefs -q
+
+$(DAT)\oracles: $(O)utility.tag    $(DAT)\oracles.txt
+       $(U)makedefs -h
+
+$(DAT)\dungeon: $(O)utility.tag  $(DAT)\dungeon.def
+       $(U)makedefs -e
+       cd $(DAT)
+       $(U)dgn_comp dungeon.pdf
+       cd $(SRC)
+
+#
+# NT dependencies
+#
+
+$(O)nttty.o:   $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nttty.c
+       @$(cc) $(CFLAGS) -I$(WSHR) -o$@  $(NTSYS)\nttty.c
+$(O)winnt.o: $(HACK_H) $(INCL)\win32api.h $(NTSYS)\winnt.c
+       @$(cc) $(CFLAGS) -o$@  $(NTSYS)\winnt.c
+$(O)ntsound.o: $(HACK_H) $(NTSYS)\ntsound.c
+       @$(cc) $(CFLAGS)  -o$@ $(NTSYS)\ntsound.c
+$(O)mapimail.o: $(HACK_H) $(INCL)\nhlan.h $(NTSYS)\mapimail.c
+       @$(cc) $(CFLAGS) -DMAPI_VERBOSE  -o$@ $(NTSYS)\mapimail.c
+
+# 
+# util dependencies
+#
+
+$(O)panic.o:  $(U)panic.c $(CONFIG_H)
+       @$(cc) $(CFLAGS) -o$@ $(U)panic.c
+
+#
+# The rest are stolen from sys/unix/Makefile.src, 
+# with the following changes:
+#   * ../include changed to $(INCL)
+#   * slashes changed to back-slashes 
+#   * -c (which is included in CFLAGS) substituted
+#      with -o$@
+#   * $(CC) changed to $(cc)
+# but otherwise untouched.
+# That means that there is some irrelevant stuff
+# in here, but maintenance should be easier.
+#
+$(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h
+       $(cc) $(CFLAGS) -o$@ ..\sys\atari\tos.c
+$(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\win32api.h
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\pcmain.c
+$(O)pcsys.o: ..\sys\share\pcsys.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\pcsys.c
+$(O)pctty.o: ..\sys\share\pctty.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\pctty.c
+$(O)pcunix.o: ..\sys\share\pcunix.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\pcunix.c
+$(O)random.o: ..\sys\share\random.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\random.c
+$(O)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)\tcap.h
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\ioctl.c
+$(O)unixtty.o: ..\sys\share\unixtty.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\unixtty.c
+$(O)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)\dlb.h
+       $(cc) $(CFLAGS) -o$@ ..\sys\unix\unixmain.c
+$(O)unixunix.o: ..\sys\unix\unixunix.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ..\sys\unix\unixunix.c
+$(O)bemain.o: ..\sys\be\bemain.c $(HACK_H) $(INCL)\dlb.h
+       $(cc) $(CFLAGS) -o$@ ..\sys\be\bemain.c
+$(O)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)\func_tab.h
+       $(cc) $(CFLAGS) -o$@ ..\win\tty\getline.c
+$(O)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)\tcap.h
+       $(cc) $(CFLAGS) -o$@ ..\win\tty\termcap.c
+$(O)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)\tcap.h
+       $(cc) $(CFLAGS) -o$@ ..\win\tty\topl.c
+$(O)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h $(INCL)\tcap.h
+       $(cc) $(CFLAGS) -o$@ ..\win\tty\wintty.c
+$(O)Window.o: ..\win\X11\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \
+               $(CONFIG_H)
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\Window.c
+$(O)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H)
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\dialogs.c
+$(O)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h ..\win\X11\nh72icon \
+               ..\win\X11\nh56icon ..\win\X11\nh32icon
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winX.c
+$(O)winmap.o: ..\win\X11\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\winX.h $(INCL)\tile2x11.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winmap.c
+$(O)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)\winX.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winmenu.c
+$(O)winmesg.o: ..\win\X11\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winmesg.c
+$(O)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)\func_tab.h \
+               $(INCL)\winX.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winmisc.c
+$(O)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)\winX.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winstat.c
+$(O)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\wintext.c
+$(O)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)\winX.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winval.c
+$(O)tile.o: $(SRC)\tile.c $(HACK_H)
+$(O)gnaskstr.o: ..\win\gnome\gnaskstr.c ..\win\gnome\gnaskstr.h \
+               ..\win\gnome\gnmain.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnaskstr.c
+$(O)gnbind.o: ..\win\gnome\gnbind.c ..\win\gnome\gnbind.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gnaskstr.h ..\win\gnome\gnyesno.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnbind.c
+$(O)gnglyph.o: ..\win\gnome\gnglyph.c ..\win\gnome\gnglyph.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnglyph.c
+$(O)gnmain.o: ..\win\gnome\gnmain.c ..\win\gnome\gnmain.h ..\win\gnome\gnsignal.h \
+               ..\win\gnome\gnbind.h ..\win\gnome\gnopts.h $(HACK_H) \
+               $(INCL)\date.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnmain.c
+$(O)gnmap.o: ..\win\gnome\gnmap.c ..\win\gnome\gnmap.h ..\win\gnome\gnglyph.h \
+               ..\win\gnome\gnsignal.h $(HACK_H)
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnmap.c
+$(O)gnmenu.o: ..\win\gnome\gnmenu.c ..\win\gnome\gnmenu.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gnbind.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnmenu.c
+$(O)gnmesg.o: ..\win\gnome\gnmesg.c ..\win\gnome\gnmesg.h ..\win\gnome\gnsignal.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnmesg.c
+$(O)gnopts.o: ..\win\gnome\gnopts.c ..\win\gnome\gnopts.h ..\win\gnome\gnglyph.h \
+               ..\win\gnome\gnmain.h ..\win\gnome\gnmap.h $(HACK_H)
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnopts.c
+$(O)gnplayer.o: ..\win\gnome\gnplayer.c ..\win\gnome\gnplayer.h \
+               ..\win\gnome\gnmain.h $(HACK_H)
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnplayer.c
+$(O)gnsignal.o: ..\win\gnome\gnsignal.c ..\win\gnome\gnsignal.h \
+               ..\win\gnome\gnmain.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnsignal.c
+$(O)gnstatus.o: ..\win\gnome\gnstatus.c ..\win\gnome\gnstatus.h \
+               ..\win\gnome\gnsignal.h ..\win\gnome\gn_xpms.h \
+               ..\win\gnome\gnomeprv.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnstatus.c
+$(O)gntext.o: ..\win\gnome\gntext.c ..\win\gnome\gntext.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gn_rip.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gntext.c
+$(O)gnyesno.o: ..\win\gnome\gnyesno.c ..\win\gnome\gnbind.h ..\win\gnome\gnyesno.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnyesno.c
+$(O)wingem.o: ..\win\gem\wingem.c $(HACK_H) $(INCL)\func_tab.h $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h $(INCL)\wingem.h
+       $(cc) $(CFLAGS) -o$@ ..\win\gem\wingem.c
+$(O)wingem1.o: ..\win\gem\wingem1.c $(INCL)\gem_rsc.h $(INCL)\load_img.h \
+               $(INCL)\wintype.h $(INCL)\wingem.h
+       $(cc) $(CFLAGS) -o$@ ..\win\gem\wingem1.c
+$(O)load_img.o: ..\win\gem\load_img.c $(INCL)\load_img.h
+       $(cc) $(CFLAGS) -o$@ ..\win\gem\load_img.c
+$(O)tile.o: tile.c $(HACK_H)
+$(O)qt_win.o: ..\win\Qt\qt_win.cpp $(HACK_H) $(INCL)\func_tab.h \
+               $(INCL)\dlb.h $(INCL)\patchlevel.h $(INCL)\qt_win.h \
+               $(INCL)\qt_clust.h $(INCL)\qt_kde0.h \
+               $(INCL)\qt_xpms.h qt_win.moc qt_kde0.moc
+       $(CXX) $(CXXFLAGS) -c ..\win\Qt\qt_win.cpp
+$(O)qt_clust.o: ..\win\Qt\qt_clust.cpp $(INCL)\qt_clust.h
+       $(CXX) $(CXXFLAGS) -c ..\win\Qt\qt_clust.cpp
+$(O)monstr.o: $(SRC)\monstr.c $(CONFIG_H)
+$(O)vis_tab.o: $(SRC)\vis_tab.c $(CONFIG_H) $(INCL)\vis_tab.h
+$(O)allmain.o: allmain.c $(HACK_H)
+$(O)alloc.o: alloc.c $(CONFIG_H)
+$(O)apply.o: apply.c $(HACK_H) $(INCL)\edog.h
+$(O)artifact.o: artifact.c $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h
+$(O)attrib.o: attrib.c $(HACK_H) $(INCL)\artifact.h
+$(O)ball.o: ball.c $(HACK_H)
+$(O)bones.o: bones.c $(HACK_H) $(INCL)\lev.h
+$(O)botl.o: botl.c $(HACK_H)
+$(O)cmd.o: cmd.c $(HACK_H) $(INCL)\func_tab.h
+$(O)dbridge.o: dbridge.c $(HACK_H)
+$(O)decl.o: decl.c $(HACK_H)
+$(O)detect.o: detect.c $(HACK_H) $(INCL)\artifact.h
+$(O)dig.o: dig.c $(HACK_H) $(INCL)\edog.h
+$(O)display.o: display.c $(HACK_H)
+$(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)\dlb.h
+$(O)do.o: do.c $(HACK_H) $(INCL)\lev.h
+$(O)do_name.o: do_name.c $(HACK_H)
+$(O)do_wear.o: do_wear.c $(HACK_H)
+$(O)dog.o: dog.c $(HACK_H) $(INCL)\edog.h
+$(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+$(O)dokick.o: dokick.c $(HACK_H) $(INCL)\eshk.h
+$(O)dothrow.o: dothrow.c $(HACK_H) $(INCL)\edog.h
+$(O)drawing.o: drawing.c $(HACK_H) $(INCL)\tcap.h
+$(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h
+$(O)eat.o: eat.c $(HACK_H)
+$(O)end.o: end.c $(HACK_H) $(INCL)\eshk.h $(INCL)\dlb.h
+$(O)engrave.o: engrave.c $(HACK_H) $(INCL)\lev.h
+$(O)exper.o: exper.c $(HACK_H)
+$(O)explode.o: explode.c $(HACK_H)
+$(O)extralev.o: extralev.c $(HACK_H)
+$(O)files.o: files.c $(HACK_H) $(INCL)\dlb.h
+$(O)fountain.o: fountain.c $(HACK_H)
+$(O)hack.o: hack.c $(HACK_H)
+$(O)hacklib.o: hacklib.c $(HACK_H)
+$(O)invent.o: invent.c $(HACK_H) $(INCL)\artifact.h
+$(O)light.o: light.c $(HACK_H) $(INCL)\lev.h
+$(O)lock.o: lock.c $(HACK_H)
+$(O)mail.o: mail.c $(HACK_H) $(INCL)\mail.h
+$(O)makemon.o: makemon.c $(HACK_H) $(INCL)\epri.h $(INCL)\emin.h \
+               $(INCL)\edog.h
+$(O)mapglyph.o: mapglyph.c $(HACK_H)
+$(O)mcastu.o: mcastu.c $(HACK_H)
+$(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+$(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+$(O)minion.o: minion.c $(HACK_H) $(INCL)\emin.h $(INCL)\epri.h
+$(O)mklev.o: mklev.c $(HACK_H)
+$(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)\sp_lev.h
+$(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev.h
+$(O)mkobj.o: mkobj.c $(HACK_H) $(INCL)\artifact.h
+$(O)mkroom.o: mkroom.c $(HACK_H)
+$(O)mon.o: mon.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+$(O)mondata.o: mondata.c $(HACK_H) $(INCL)\eshk.h $(INCL)\epri.h
+$(O)monmove.o: monmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h
+$(O)monst.o: monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \
+               $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\monsym.h \
+               $(INCL)\dungeon.h $(INCL)\eshk.h $(INCL)\vault.h \
+               $(INCL)\epri.h $(INCL)\color.h
+$(O)mplayer.o: mplayer.c $(HACK_H)
+$(O)mthrowu.o: mthrowu.c $(HACK_H)
+$(O)muse.o: muse.c $(HACK_H) $(INCL)\edog.h
+$(O)music.o: music.c $(HACK_H) #interp.c
+$(O)o_init.o: o_init.c $(HACK_H) $(INCL)\lev.h
+$(O)objects.o: objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \
+               $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h
+$(O)objnam.o: objnam.c $(HACK_H)
+$(O)options.o: options.c $(CONFIG_H) $(INCL)\objclass.h $(INCL)\flag.h \
+               $(HACK_H) $(INCL)\tcap.h
+$(O)pager.o: pager.c $(HACK_H) $(INCL)\dlb.h
+$(O)pickup.o: pickup.c $(HACK_H)
+$(O)pline.o: pline.c $(HACK_H) $(INCL)\epri.h $(INCL)\edog.h
+$(O)polyself.o: polyself.c $(HACK_H)
+$(O)potion.o: potion.c $(HACK_H)
+$(O)pray.o: pray.c $(HACK_H) $(INCL)\epri.h
+$(O)priest.o: priest.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\eshk.h \
+               $(INCL)\epri.h $(INCL)\emin.h
+$(O)quest.o: quest.c $(HACK_H) $(INCL)\qtext.h
+$(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)\dlb.h $(INCL)\qtext.h
+$(O)read.o: read.c $(HACK_H)
+$(O)rect.o: rect.c $(HACK_H)
+$(O)region.o: region.c $(HACK_H) $(INCL)\lev.h
+$(O)restore.o: restore.c $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h
+$(O)rip.o: rip.c $(HACK_H)
+$(O)rnd.o: rnd.c $(HACK_H)
+$(O)role.o: role.c $(HACK_H)
+$(O)rumors.o: rumors.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h
+$(O)save.o: save.c $(HACK_H) $(INCL)\lev.h
+$(O)shk.o: shk.c $(HACK_H) $(INCL)\eshk.h
+$(O)shknam.o: shknam.c $(HACK_H) $(INCL)\eshk.h
+$(O)sit.o: sit.c $(HACK_H) $(INCL)\artifact.h
+$(O)sounds.o: sounds.c $(HACK_H) $(INCL)\edog.h
+$(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)\dlb.h $(INCL)\sp_lev.h
+$(O)spell.o: spell.c $(HACK_H)
+$(O)steal.o: steal.c $(HACK_H)
+$(O)steed.o: steed.c $(HACK_H)
+$(O)teleport.o: teleport.c $(HACK_H)
+$(O)timeout.o: timeout.c $(HACK_H) $(INCL)\lev.h
+$(O)topten.o: topten.c $(HACK_H) $(INCL)\dlb.h $(INCL)\patchlevel.h
+$(O)track.o: track.c $(HACK_H)
+$(O)trap.o: trap.c $(HACK_H)
+$(O)u_init.o: u_init.c $(HACK_H)
+$(O)uhitm.o: uhitm.c $(HACK_H)
+$(O)vault.o: vault.c $(HACK_H) $(INCL)\vault.h
+$(O)version.o: version.c $(HACK_H) $(INCL)\date.h $(INCL)\patchlevel.h
+$(O)vision.o: vision.c $(HACK_H) $(INCL)\vis_tab.h
+$(O)weapon.o: weapon.c $(HACK_H)
+$(O)were.o: were.c $(HACK_H)
+$(O)wield.o: wield.c $(HACK_H)
+$(O)windows.o: windows.c $(HACK_H) $(INCL)\wingem.h $(INCL)\winGnome.h
+$(O)wizard.o: wizard.c $(HACK_H) $(INCL)\qtext.h
+$(O)worm.o: worm.c $(HACK_H) $(INCL)\lev.h
+$(O)worn.o: worn.c $(HACK_H)
+$(O)write.o: write.c $(HACK_H)
+$(O)zap.o: zap.c $(HACK_H)
+
+# end of file
+
diff --git a/src/Makefile.gcc b/src/Makefile.gcc
new file mode 100644 (file)
index 0000000..980c2c2
--- /dev/null
@@ -0,0 +1,1352 @@
+#   SCCS Id: @(#)Makefile.gcc       3.4     $Date: 2003/11/16 04:50:57 $
+#   Copyright (c) NetHack PC Development Team 1993-2003
+#
+#   NetHack 3.4.x Makefile for MinGW
+#
+#   Win32 Compilers Tested:
+#                  - MinGW 1.0 (gcc version 2.95.3-6) (Console NetHack only)
+#                  - MinGW 2.0 (gcc version 3.2)
+#
+#   If you don't have this compiler, you can get it at:
+#       http://www.mingw.org/
+#
+#   This is used for building two versions of NetHack:
+#   A tty port utilizing the Win32 Console I/O subsystem, Console
+#       NetHack;
+#   A Win32 native port built on the Windows API, Graphical NetHack or
+#       NetHackW.
+#
+#   In addition to your C compiler,
+#
+#     if you want to change     you will need a
+#     files with suffix         workalike for
+#         .y                     yacc   (such as bison)
+#         .l                     lex    (such as flex)
+#
+#
+#   If you have any questions read the sys/winnt/Install.nt file included
+#   with the distribution.
+#
+#   --
+#   Dion Nicolaas
+#==============================================================================
+# Graphical interface
+# Set to Y for a graphical version
+# Set to anything else (or undefine) for a tty version
+
+#GRAPHICAL = Y
+
+# Debug
+# Set to Y for Debug support (to produce debug information)
+# Set to anything else (or undefine) for a "release" version
+# You can set your debug options below.
+
+DEBUG = Y
+
+cc     = gcc
+rc     = windres
+link   = gcc
+
+cflags = -mms-bitfields
+lflags  =
+ifeq  "$(DEBUG)" "Y"
+cdebug = -g
+linkdebug = -g
+else
+cdebug =
+linkdebug =
+endif
+
+#
+#  Set the gamedir according to your preference.
+#  If not present prior to compilation it gets created.
+
+ifeq  "$(GRAPHICAL)" "Y"
+# Game Name
+GAME    = NetHackW
+else
+# Game Name
+GAME    = NetHack
+endif
+# Game directory
+GAMEDIR = ../binary
+
+#
+#  Source directories.    Makedefs hardcodes these, don't change them.
+#
+
+# NetHack include files
+INCL  = ../include
+# NetHack data files
+DAT   = ../dat
+# NetHack documentation files
+DOC   = ../doc
+# Utility source
+UTIL  = ../util
+# Main source
+SRC   = ../src
+# Shared system files
+SSYS  = ../sys/share
+# NT Win32 specific files
+NTSYS = ../sys/winnt
+# window port files (tty)
+TTY   = ../win/tty
+# window port files (Win32)
+WIN32 = ../win/win32
+# Tile support files
+WSHR  = ../win/share
+
+#
+#  Object directory.
+#
+
+OBJ = o
+
+
+#
+#==========================================
+# Exe File Info.
+#==========================================
+
+# Yacc/Lex ... if you got 'em.
+#
+# If you have yacc and lex programs (or work-alike such as bison
+# and flex), comment out the upper two macros and uncomment
+# the lower two.
+#
+
+DO_YACC = YACC_MSG
+DO_LEX  = LEX_MSG
+#DO_YACC  = YACC_ACT
+#DO_LEX   = LEX_ACT
+
+# - Specify your yacc and lex programs (or work-alikes) here.
+
+#YACC   = bison -y
+YACC   = byacc
+#YACC   = yacc
+
+#LEX    = lex
+LEX     = flex
+
+#
+# - Specify your flex skeleton file (if needed).
+#
+
+FLEXSKEL =
+#FLEXSKEL = -S../tools/flex.ske
+
+YTABC   = y_tab.c
+YTABH   = y_tab.h
+LEXYYC  = lexyy.c
+
+#
+# Optional high-quality BSD random number generation routines
+# (see pcconf.h). Set to nothing if not used.
+#
+
+RANDOM  = $(OBJ)/random.o
+#RANDOM =
+
+#===============================================
+#======= End of Modification Section ===========
+#===============================================
+################################################
+#                                              #
+# Nothing below here should have to be changed.#
+#                                              #
+################################################
+
+ifeq  "$(GRAPHICAL)" "Y"
+WINPORT  = $(O)tile.o $(O)mhaskyn.o $(O)mhdlg.o \
+       $(O)mhfont.o $(O)mhinput.o $(O)mhmain.o $(O)mhmap.o \
+       $(O)mhmenu.o $(O)mhmsgwnd.o $(O)mhrip.o $(O)mhsplash.o \
+       $(O)mhstatus.o $(O)mhtext.o $(O)mswproc.o $(O)winhack.o
+WINPFLAG   = -DTILES -DMSWIN_GRAPHICS -D_WIN32_IE=0x0400
+NHRES   = $(O)winres.o
+WINPINC = -I$(WIN32)
+WINPHDR = $(WIN32)/mhaskyn.h $(WIN32)/mhdlg.h $(WIN32)/mhfont.h \
+       $(WIN32)/mhinput.h $(WIN32)/mhmain.h $(WIN32)/mhmap.h \
+       $(WIN32)/mhmenu.h $(WIN32)/mhmsg.h $(WIN32)/mhmsgwnd.h \
+       $(WIN32)/mhrip.h $(WIN32)/mhstatus.h \
+       $(WIN32)/mhtext.h $(WIN32)/resource.h $(WIN32)/winMS.h
+WINPLIBS =  -lcomctl32 -lwinmm
+else
+WINPORT = $(O)nttty.o
+WINPFLAG= -DWIN32CON
+WINPHDR =
+NHRES   = $(O)console.o
+WINPINC =
+WINPLIBS = -lwinmm
+endif
+
+TILEUTIL16  = $(UTIL)/tile2bmp.exe
+TILEBMP16   = $(SRC)/tiles.bmp
+
+TILEUTIL32  = $(UTIL)/til2bm32.exe
+TILEBMP32   = $(SRC)/tiles32.bmp
+
+SOUND = $(OBJ)/ntsound.o
+
+#SOUND =
+
+# To store all the level files,
+# help files, etc. in a single library file.
+# USE_DLB = Y is left uncommented
+
+USE_DLB = Y
+
+ifeq  "$(USE_DLB)" "Y"
+DLBFLG = -DDLB
+else
+DLBFLG =
+endif
+
+#==========================================
+# Setting up the compiler and linker
+# macros. All builds include the base ones.
+#==========================================
+
+CFLAGSBASE  = -c $(cflags) -I$(INCL) $(WINPINC) $(cdebug)
+LFLAGSBASEC = $(linkdebug)
+LFLAGSBASEG = $(linkdebug) -mwindows
+
+#==========================================
+# Util builds
+#==========================================
+
+CFLAGSU = $(CFLAGSBASE) $(WINPFLAG)
+LFLAGSU = $(LFLAGSBASEC)
+
+#==========================================
+# - Game build
+#==========================================
+
+CFLAGS   = $(CFLAGSBASE) $(WINPFLAG) $(DLBFLG)
+lflags  = $(LFLAGSBASE)
+ifeq "$(GRAPHICAL)" "Y"
+lflags  = $(LFLAGSBASEG)
+else
+lflags  = $(LFLAGSBASEC)
+endif
+
+GAMEFILE = $(GAMEDIR)/$(GAME).exe # whole thing
+
+ifeq  "$(USE_DLB)" "Y"
+DLB = nhdat
+else
+DLB =
+endif
+
+#==========================================
+#================ RULES ==================
+#==========================================
+
+.SUFFIXES: .exe .o .til .uu .c .y .l
+
+#==========================================
+# Rules for files in src
+#==========================================
+
+$(OBJ)/%.o : /%.c
+       $(cc) $(CFLAGS)  -o$@ $<
+
+$(OBJ)/%.o : $(SRC)/%.c
+       $(cc) $(CFLAGS)   -o$@  $<
+
+#==========================================
+# Rules for files in sys/share
+#==========================================
+
+$(OBJ)/%.o : $(SSYS)/%.c
+       $(cc) $(CFLAGS)  -o$@  $<
+
+#==========================================
+# Rules for files in sys/winnt
+#==========================================
+
+$(OBJ)/%.o : $(NTSYS)/%.c
+       $(cc) $(CFLAGS)  -o$@  $<
+
+$(INCL)/%.h : $(NTSYS)/%.h
+       @copy $< $@
+
+#==========================================
+# Rules for files in util
+#==========================================
+
+$(OBJ)/%.o : $(UTIL)/%.c
+       $(cc) $(CFLAGSU) -o$@ $<
+
+#==========================================
+# Rules for files in win/share
+#==========================================
+
+$(OBJ)/%.o : $(WSHR)/%.c
+       $(cc) $(CFLAGS)  -o$@ $<
+
+$(INCL)/%.h : $(WSHR)/%.h
+       @copy $< $@
+
+#{$(WSHR)}.txt{$(DAT)}.txt:
+#      @copy $< $@
+
+#==========================================
+# Rules for files in win/tty
+#==========================================
+
+$(OBJ)/%.o : $(TTY)/%.c
+       $(cc) $(CFLAGS)  -o$@  $<
+
+#==========================================
+# Rules for files in win/win32
+#==========================================
+
+$(OBJ)/%.o : $(WIN32)/%.c
+       $(cc) $(CFLAGS)  -o$@  $<
+
+#==========================================
+#================ MACROS ==================
+#==========================================
+# This section creates shorthand macros for many objects
+# referenced later on in the Makefile.
+#
+
+DEFFILE = $(NTSYS)/$(GAME).def
+
+#
+# Shorten up the location for some files
+#
+
+O  = $(OBJ)/
+
+U  = $(UTIL)/
+
+#
+# Utility Objects.
+#
+
+MAKESRC        = $(U)makedefs.c
+
+SPLEVSRC       = $(U)lev_yacc.c  $(U)lev_$(LEX).c $(U)lev_main.c  $(U)panic.c
+
+DGNCOMPSRC     = $(U)dgn_yacc.c  $(U)dgn_$(LEX).c $(U)dgn_main.c
+
+MAKEOBJS       = $(O)makedefs.o $(O)monst.o $(O)objects.o
+
+SPLEVOBJS      = $(O)lev_yacc.o  $(O)lev_$(LEX).o $(O)lev_main.o \
+       $(O)alloc.o   $(O)decl.o      $(O)drawing.o \
+       $(O)monst.o   $(O)objects.o   $(O)panic.o
+
+DGNCOMPOBJS    = $(O)dgn_yacc.o  $(O)dgn_$(LEX).o $(O)dgn_main.o \
+       $(O)alloc.o   $(O)panic.o
+
+RECOVOBJS      = $(O)recover.o
+
+TILEFILES      = $(WSHR)/monsters.txt $(WSHR)/objects.txt $(WSHR)/other.txt
+
+#
+# These are not invoked during a normal game build in 3.4
+#
+TEXT_IO        = $(O)tiletext.o  $(O)tiletxt.o   $(O)drawing.o \
+       $(O)decl.o    $(O)monst.o     $(O)objects.o
+
+TEXT_IO32      = $(O)tilete32.o $(O)tiletx32.o $(O)drawing.o \
+       $(O)decl.o    $(O)monst.o     $(O)objects.o
+
+GIFREADERS     = $(O)gifread.o   $(O)alloc.o $(O)panic.o
+GIFREADERS32   = $(O)gifrd32.o $(O)alloc.o $(O)panic.o
+
+PPMWRITERS     = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o
+
+#
+#  Object files for the game itself.
+#
+
+VOBJ01 = $(O)allmain.o  $(O)alloc.o    $(O)apply.o    $(O)artifact.o
+VOBJ02 = $(O)attrib.o   $(O)ball.o     $(O)bones.o    $(O)botl.o
+VOBJ03 = $(O)cmd.o      $(O)dbridge.o  $(O)decl.o     $(O)detect.o
+VOBJ04 = $(O)dig.o      $(O)display.o  $(O)do.o       $(O)do_name.o
+VOBJ05 = $(O)do_wear.o  $(O)dog.o      $(O)dogmove.o  $(O)dokick.o
+VOBJ06 = $(O)dothrow.o  $(O)drawing.o  $(O)dungeon.o  $(O)eat.o
+VOBJ07 = $(O)end.o      $(O)engrave.o  $(O)exper.o    $(O)explode.o
+VOBJ08 = $(O)extralev.o $(O)files.o    $(O)fountain.o $(O)hack.o
+VOBJ09 = $(O)hacklib.o  $(O)invent.o   $(O)light.o    $(O)lock.o
+VOBJ10 = $(O)mail.o     $(O)makemon.o  $(O)mapglyph.o $(O)mcastu.o
+VOBJ11 = $(O)mhitm.o    $(O)mhitu.o    $(O)minion.o   $(O)mklev.o
+VOBJ12 = $(O)mkmap.o    $(O)mkmaze.o   $(O)mkobj.o    $(O)mkroom.o
+VOBJ13 = $(O)mon.o      $(O)mondata.o  $(O)monmove.o  $(O)monst.o
+VOBJ14 = $(O)monstr.o   $(O)mplayer.o  $(O)mthrowu.o  $(O)muse.o
+VOBJ15 = $(O)music.o    $(O)o_init.o   $(O)objects.o  $(O)objnam.o
+VOBJ16 = $(O)options.o  $(O)pager.o    $(O)pickup.o   $(O)pline.o
+VOBJ17 = $(O)polyself.o $(O)potion.o   $(O)pray.o     $(O)priest.o
+VOBJ18 = $(O)quest.o    $(O)questpgr.o $(RANDOM)      $(O)read.o
+VOBJ19 = $(O)rect.o     $(O)region.o   $(O)restore.o  $(O)rip.o
+VOBJ20 = $(O)rnd.o      $(O)role.o     $(O)rumors.o   $(O)save.o
+VOBJ21 = $(O)shk.o      $(O)shknam.o   $(O)sit.o      $(O)sounds.o
+VOBJ22 = $(O)sp_lev.o   $(O)spell.o    $(O)steal.o    $(O)steed.o
+VOBJ23 = $(O)teleport.o $(O)timeout.o  $(O)topten.o   $(O)track.o
+VOBJ24 = $(O)trap.o     $(O)u_init.o   $(O)uhitm.o    $(O)vault.o
+VOBJ25 = $(O)vis_tab.o  $(O)vision.o   $(O)weapon.o   $(O)were.o
+VOBJ26 = $(O)wield.o    $(O)windows.o  $(O)wizard.o   $(O)worm.o
+VOBJ27 = $(O)worn.o     $(O)write.o    $(O)zap.o
+
+DLBOBJ = $(O)dlb.o
+
+TTYOBJ = $(O)topl.o     $(O)getline.o  $(O)wintty.o
+
+SOBJ   = $(O)winnt.o    $(O)pcsys.o      $(O)pcunix.o  \
+       $(SOUND) $(O)pcmain.o $(O)mapimail.o $(O)nhlan.o
+
+OBJS   = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \
+       $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \
+       $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \
+       $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \
+       $(VOBJ21) $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) \
+       $(VOBJ26) $(VOBJ27)
+
+WINPOBJ = $(WINPORT)
+
+VVOBJ  = $(O)version.o
+
+ALLOBJ  = $(WINPOBJ) $(SOBJ) $(DLBOBJ)  $(TTYOBJ) $(WOBJ) $(OBJS) $(VVOBJ)
+
+ifeq "$(GRAPHICAL)" "Y"
+OPTIONS_FILE = $(DAT)/guioptions
+else
+OPTIONS_FILE = $(DAT)/ttyoptions
+endif
+
+#==========================================
+# Header file macros
+#==========================================
+
+CONFIG_H = $(INCL)/config.h $(INCL)/config1.h $(INCL)/tradstdc.h \
+              $(INCL)/global.h $(INCL)/coord.h $(INCL)/vmsconf.h \
+              $(INCL)/system.h $(INCL)/unixconf.h $(INCL)/os2conf.h \
+              $(INCL)/micro.h $(INCL)/pcconf.h $(INCL)/tosconf.h \
+              $(INCL)/amiconf.h $(INCL)/macconf.h $(INCL)/beconf.h \
+              $(INCL)/ntconf.h $(INCL)/nhlan.h
+
+HACK_H = $(INCL)/hack.h $(CONFIG_H) $(INCL)/align.h \
+              $(INCL)/dungeon.h $(INCL)/monsym.h $(INCL)/mkroom.h \
+              $(INCL)/objclass.h $(INCL)/youprop.h $(INCL)/prop.h \
+              $(INCL)/permonst.h $(INCL)/monattk.h \
+              $(INCL)/monflag.h $(INCL)/mondata.h $(INCL)/pm.h \
+              $(INCL)/wintype.h $(INCL)/decl.h $(INCL)/quest.h \
+              $(INCL)/spell.h $(INCL)/color.h $(INCL)/obj.h \
+              $(INCL)/you.h $(INCL)/attrib.h $(INCL)/monst.h \
+              $(INCL)/skills.h $(INCL)/onames.h $(INCL)/timeout.h \
+              $(INCL)/trap.h $(INCL)/flag.h $(INCL)/rm.h \
+              $(INCL)/vision.h $(INCL)/display.h $(INCL)/engrave.h \
+              $(INCL)/rect.h $(INCL)/region.h $(INCL)/winprocs.h \
+              $(INCL)/wintty.h $(INCL)/trampoli.h
+
+LEV_H       = $(INCL)/lev.h
+DGN_FILE_H  = $(INCL)/dgn_file.h
+LEV_COMP_H  = $(INCL)/lev_comp.h
+SP_LEV_H    = $(INCL)/sp_lev.h
+TILE_H      = ../win/share/tile.h
+
+#==========================================
+# Miscellaneous
+#==========================================
+
+DATABASE = $(DAT)/data.base
+
+#
+#  The name of the game.
+#
+
+GAMEFILE = $(GAMEDIR)/$(GAME).exe
+
+
+#==========================================
+#=============== TARGETS ==================
+#==========================================
+
+# Since DOS doesn't allow / as path separator, and GCC doesn't allow \ as
+# path separator, we must change all pathnames when performing DOS commands.
+# This is done by blindly applying $(subst /,\, ...) on every command.
+# Where any command contain / for another reason (switch char, or echoing
+# comment lines to lev/dungeon files) a little more care is taken.
+
+#
+#  The default make target (so just typing 'nmake' is useful).
+#
+default : $(GAMEFILE)
+
+#
+#  The main target.
+#
+
+$(GAME) : $(O)obj.tag $(O)utility.tag graphicschk $(GAMEFILE)
+       @echo $(GAME) is up to date.
+
+#
+#  Everything
+#
+
+all :   install
+
+install: graphicschk $(GAME) $(O)install.tag
+       @echo Done.
+
+
+$(O)install.tag:  $(DAT)/data    $(DAT)/rumors    $(DAT)/dungeon \
+              $(DAT)/oracles $(DAT)/quest.dat $(O)sp_lev.tag $(DLB)
+ifeq  "$(USE_DLB)" "Y"
+       $(subst /,\,copy nhdat                $(GAMEDIR))
+       $(subst /,\,copy $(DAT)/license       $(GAMEDIR))
+       $(subst /,\,copy $(DAT)/opthelp       $(GAMEDIR))
+else
+       $(subst /,\,copy $(DAT)/*.            $(GAMEDIR))
+       $(subst /,\,copy $(DAT)/*.dat         $(GAMEDIR))
+       $(subst /,\,copy $(DAT)/*.lev         $(GAMEDIR))
+       $(subst /,\,if exist $(GAMEDIR)/makefile del $(GAMEDIR)/makefile)
+endif
+       $(subst /,\,if exist $(DOC)/guidebook.txt copy $(DOC)/guidebook.txt $(GAMEDIR)/Guidebook.txt)
+       $(subst /,\,if exist $(DOC)/nethack.txt copy $(DOC)/nethack.txt $(GAMEDIR)/NetHack.txt)
+       $(subst /,\,copy $(NTSYS)/defaults.nh   $(GAMEDIR)/defaults.nh)
+       $(subst /,\,echo install done > $@)
+
+#  copy $(NTSYS)/winnt.hlp    $(GAMEDIR)
+
+recover: $(U)recover.exe
+       $(subst /,\,if exist $(U)recover.exe copy $(U)recover.exe  $(GAMEDIR))
+       $(subst /,\,if exist $(DOC)/recover.txt copy $(DOC)/recover.txt $(GAMEDIR)/recover.txt)
+
+$(O)sp_lev.tag: $(O)utility.tag $(DAT)/bigroom.des  $(DAT)/castle.des \
+        $(DAT)/endgame.des $(DAT)/gehennom.des $(DAT)/knox.des   \
+        $(DAT)/medusa.des  $(DAT)/oracle.des   $(DAT)/tower.des  \
+        $(DAT)/yendor.des  $(DAT)/arch.des     $(DAT)/barb.des   \
+        $(DAT)/caveman.des $(DAT)/healer.des   $(DAT)/knight.des \
+        $(DAT)/monk.des    $(DAT)/priest.des   $(DAT)/ranger.des \
+        $(DAT)/rogue.des   $(DAT)/samurai.des  $(DAT)/sokoban.des \
+        $(DAT)/tourist.des $(DAT)/valkyrie.des $(DAT)/wizard.des
+       $(subst /,\,$(U)lev_comp $(DAT)/bigroom.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/castle.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/endgame.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/gehennom.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/knox.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/mines.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/medusa.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/oracle.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/sokoban.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/tower.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/yendor.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/arch.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/barb.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/caveman.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/healer.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/knight.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/monk.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/priest.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/ranger.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/rogue.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/samurai.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/tourist.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/valkyrie.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/wizard.des)
+       $(subst /,\,copy *.lev $(DAT))
+       $(subst /,\,del *.lev)
+       $(subst /,\,echo sp_levs done > $(O)sp_lev.tag)
+
+$(O)utility.tag: $(INCL)/date.h $(INCL)/onames.h $(INCL)/pm.h \
+        $(SRC)/monstr.c $(SRC)/vis_tab.c $(U)lev_comp.exe $(INCL)/vis_tab.h \
+        $(U)dgn_comp.exe $(TILEUTIL16)
+       $(subst /,\,@echo utilities made >$@)
+       @echo utilities made.
+
+tileutil: $(U)gif2txt.exe $(U)gif2tx32.exe $(U)txt2ppm.exe
+       @echo Optional tile development utilities are up to date.
+
+ifeq  "$(GRAPHICAL)" "Y"
+$(NHRES): $(TILEBMP16) $(WIN32)/winhack.rc $(WIN32)/mnsel.bmp \
+        $(WIN32)/mnselcnt.bmp $(WIN32)/mnunsel.bmp \
+        $(WIN32)/petmark.bmp $(WIN32)/NetHack.ico $(WIN32)/rip.bmp \
+        $(WIN32)/splash.bmp
+       @$(rc) -o$@ --include-dir $(WIN32) -i $(WIN32)/winhack.rc
+else
+$(NHRES): $(NTSYS)/console.rc $(NTSYS)/NetHack.ico 
+       @$(rc) -o$@ --include-dir $(NTSYS) -i $(NTSYS)/console.rc
+endif
+
+#==========================================
+#  The main target.
+#==========================================
+$(O)gamedir.tag:
+       $(subst /,\,@if not exist $(GAMEDIR)/*.* echo creating directory $(GAMEDIR))
+       $(subst /,\,@if not exist $(GAMEDIR)/*.* mkdir $(GAMEDIR))
+       $(subst /,\,@echo directory created > $@)
+
+ifeq  "$(GRAPHICAL)" "Y"
+$(GAMEFILE) : $(ALLOBJ) $(NHRES) $(O)gamedir.tag
+else
+$(GAMEFILE) : $(ALLOBJ) $(NHRES) $(O)gamedir.tag \
+        $(GAMEDIR)/nhdefkey.dll $(GAMEDIR)/nh340key.dll $(GAMEDIR)/nhraykey.dll
+endif
+       @echo Linking....
+       @$(link) $(lflags) -o$@ $(ALLOBJ) $(NHRES) $(WINPLIBS)
+       $(subst /,\,@if exist $(O)install.tag del $(O)install.tag)
+
+
+$(O)nhdefkey.o:
+       $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(NTSYS)/nhdefkey.c 
+
+$(GAMEDIR)/nhdefkey.dll : $(O)nhdefkey.o $(O)gamedir.tag
+       @echo Linking $@
+       $(cc) -shared -Wl,--export-all-symbols \
+               -Wl,--add-stdcall-alias -o $@ $<
+
+$(O)nh340key.o:
+       $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(NTSYS)/nh340key.c 
+
+$(GAMEDIR)/nh340key.dll : $(O)nh340key.o $(O)gamedir.tag
+       @echo Linking $@
+       $(cc) -shared -Wl,--export-all-symbols \
+               -Wl,--add-stdcall-alias -o $@ $<
+
+$(O)nhraykey.o:
+               $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(NTSYS)/nhraykey.c 
+
+$(GAMEDIR)/nhraykey.dll : $(O)nhraykey.o $(O)gamedir.tag
+       @echo Linking $@
+       $(cc) -shared -Wl,--export-all-symbols \
+               -Wl,--add-stdcall-alias -o $@ $<
+
+$(GAME)_.ico : $(NTSYS)/$(GAME).ico
+       $(subst /,\,@copy $(NTSYS)/$(GAME).ico $@)
+
+#==========================================
+# Create directory for holding object files
+#==========================================
+
+graphicschk:
+ifeq  "$(GRAPHICAL)" "Y"
+       @echo ----
+       @echo NOTE: This build will include tile support.
+       @echo ----
+endif
+       $(subst /,\,@echo graphicschk > graphicschk)
+
+#
+#  Secondary Targets.
+#
+
+#==========================================
+# Makedefs Stuff
+#==========================================
+
+$(U)makedefs.exe: $(MAKEOBJS)
+       @$(link) $(LFLAGSU) -o$@ $(MAKEOBJS)
+
+$(O)makedefs.o: $(CONFIG_H) $(INCL)/monattk.h $(INCL)/monflag.h \
+        $(INCL)/objclass.h $(INCL)/monsym.h $(INCL)/qtext.h \
+        $(INCL)/patchlevel.h $(U)makedefs.c $(O)obj.tag
+       $(cc) $(CFLAGSU) -o$@ $(U)makedefs.c
+
+#
+#  date.h should be remade every time any of the source or include
+#  files is modified.
+#
+
+$(INCL)/date.h $(OPTIONS_FILE): $(U)makedefs.exe
+       $(subst /,\,$(U)makedefs -v)
+
+#$(OPTIONS_FILE): $(U)makedefs.exe
+#      $(subst /,\,$(U)makedefs -v)
+
+$(INCL)/onames.h : $(U)makedefs.exe
+       $(subst /,\,$(U)makedefs -o)
+
+$(INCL)/pm.h : $(U)makedefs.exe
+       $(subst /,\,$(U)makedefs -p)
+
+#$(INCL)/trap.h : $(U)makedefs.exe
+#  $(U)makedefs -t
+
+$(SRC)/monstr.c: $(U)makedefs.exe
+       $(subst /,\,$(U)makedefs -m)
+
+$(INCL)/vis_tab.h: $(U)makedefs.exe
+       $(subst /,\,$(U)makedefs -z)
+
+$(SRC)/vis_tab.c: $(U)makedefs.exe
+       $(subst /,\,$(U)makedefs -z)
+
+#==========================================
+# uudecode utility and uuencoded targets
+#==========================================
+
+$(U)uudecode.exe: $(O)uudecode.o
+       @$(link) $(LFLAGSU) -o$@ $(O)uudecode.o
+
+$(O)uudecode.o: $(SSYS)/uudecode.c
+
+$(NTSYS)/NetHack.ico : $(U)uudecode.exe $(NTSYS)/nhico.uu
+       $(subst /,\,$(U)uudecode.exe $(NTSYS)/nhico.uu)
+       $(subst /,\,copy NetHack.ico $@)
+       del NetHack.ico
+
+$(WIN32)/NetHack.ico : $(NTSYS)/NetHack.ico
+       $(subst /,\,copy $< $@)
+
+$(WIN32)/mnsel.bmp: $(U)uudecode.exe $(WIN32)/mnsel.uu
+       $(subst /,\,$(U)uudecode.exe $(WIN32)/mnsel.uu)
+       $(subst /,\,copy mnsel.bmp $@)
+       del mnsel.bmp
+
+$(WIN32)/mnselcnt.bmp: $(U)uudecode.exe $(WIN32)/mnselcnt.uu
+       $(subst /,\,$(U)uudecode.exe $(WIN32)/mnselcnt.uu)
+       $(subst /,\,copy mnselcnt.bmp $@)
+       del mnselcnt.bmp
+
+$(WIN32)/mnunsel.bmp: $(U)uudecode.exe $(WIN32)/mnunsel.uu
+       $(subst /,\,$(U)uudecode.exe $(WIN32)/mnunsel.uu)
+       $(subst /,\,copy mnunsel.bmp $@)
+       del mnunsel.bmp
+
+$(WIN32)/petmark.bmp: $(U)uudecode.exe $(WIN32)/petmark.uu
+       $(subst /,\,$(U)uudecode.exe $(WIN32)/petmark.uu)
+       $(subst /,\,copy petmark.bmp $@)
+       del petmark.bmp
+
+$(WIN32)/rip.bmp: $(U)uudecode.exe $(WIN32)/rip.uu
+       $(subst /,\,$(U)uudecode.exe $(WIN32)/rip.uu)
+       $(subst /,\,copy rip.bmp $@)
+       del rip.bmp
+
+$(WIN32)/splash.bmp: $(U)uudecode.exe $(WIN32)/splash.uu
+       $(subst /,\,$(U)uudecode.exe $(WIN32)/splash.uu)
+       $(subst /,\,copy splash.bmp $@)
+       del splash.bmp
+
+
+#==========================================
+# Level Compiler Stuff
+#==========================================
+
+LEVCFLAGS=$(cflags) -c -DWIN32 -D_WIN32 -I../include $(cdebug) -DDLB
+
+$(U)lev_comp.exe: $(SPLEVOBJS)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(SPLEVOBJS)
+
+$(O)lev_yacc.o: $(HACK_H)   $(SP_LEV_H) $(INCL)/lev_comp.h $(U)lev_yacc.c
+       $(cc) $(LEVCFLAGS) -o$@ $(U)lev_yacc.c
+
+$(O)lev_$(LEX).o: $(HACK_H)   $(INCL)/lev_comp.h $(SP_LEV_H) \
+       $(U)lev_$(LEX).c
+       $(cc) $(LEVCFLAGS) -o$@ $(U)lev_$(LEX).c
+
+$(O)lev_main.o:   $(U)lev_main.c $(HACK_H)   $(SP_LEV_H)
+       $(cc) $(LEVCFLAGS) -o$@ $(U)lev_main.c
+
+
+$(U)lev_yacc.c $(INCL)/lev_comp.h : $(U)lev_comp.y
+ifeq  "$(DO_YACC)" "YACC_ACT"
+       $(subst /,\,$(YACC) -d $(U)lev_comp.y)
+       $(subst /,\,copy $(YTABC) $(U)lev_yacc.c)
+       $(subst /,\,copy $(YTABH) $(INCL)/lev_comp.h)
+       $(subst /,\,@del $(YTABC))
+       $(subst /,\,@del $(YTABH))
+
+else
+       @echo $(U)lev_comp.y has changed.
+       @echo To update $(U)lev_yacc.c and $(INCL)/lev_comp.h run $(YACC).
+       @echo ---
+       @echo For now, we will copy the prebuilt lev_yacc.c and
+       @echo lev_comp.h from $(SSYS) into $(UTIL) and use them.
+       $(subst /,\,@copy $(SSYS)/lev_yacc.c $(U)lev_yacc.c >nul)
+       $(subst /,\,@copy $(SSYS)/lev_comp.h $(INCL)/lev_comp.h >nul)
+       $(subst /,\,echo.>>$(U)lev_yacc.c)
+       $(subst /,\,echo.>>$(INCL)/lev_comp.h)
+endif
+
+$(U)lev_$(LEX).c: $(U)lev_comp.l
+ifeq  "$(DO_LEX)" "LEX_ACT"
+       $(subst /,\,$(LEX) $(FLEXSKEL) $(U)lev_comp.l)
+       $(subst /,\,copy $(LEXYYC) $@)
+       $(subst /,\,@del $(LEXYYC))
+else
+       @echo $(U)lev_comp.l has changed. To update $@ run $(LEX).
+       @echo ---
+       @echo For now, we will copy the prebuilt lev_lex.c
+       @echo from $(SSYS) into $(UTIL) and use it.
+       $(subst /,\,@copy $(SSYS)/lev_lex.c $@ >nul)
+       $(subst /,\,echo.>>$@)
+endif
+
+#==========================================
+# Dungeon Compiler Stuff
+#==========================================
+
+$(U)dgn_comp.exe: $(DGNCOMPOBJS)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(DGNCOMPOBJS)
+
+
+$(O)dgn_yacc.o:   $(HACK_H)   $(DGN_FILE_H) $(INCL)/dgn_comp.h $(U)dgn_yacc.c
+       $(cc) $(LEVCFLAGS) -o$@ $(U)dgn_yacc.c
+
+$(O)dgn_$(LEX).o: $(HACK_H)   $(DGN_FILE_H)  $(INCL)/dgn_comp.h \
+        $(U)dgn_$(LEX).c
+       $(cc) $(LEVCFLAGS) -o$@ $(U)dgn_$(LEX).c
+
+$(O)dgn_main.o:   $(HACK_H) $(U)dgn_main.c
+       $(cc) $(LEVCFLAGS) -o$@ $(U)dgn_main.c
+
+$(U)dgn_yacc.c $(INCL)/dgn_comp.h : $(U)dgn_comp.y
+ifeq  "$(DO_YACC)" "YACC_ACT"
+       $(subst /,\,$(YACC) -d $(U)dgn_comp.y)
+       $(subst /,\,copy $(YTABC) $(U)dgn_yacc.c)
+       $(subst /,\,copy $(YTABH) $(INCL)/dgn_comp.h)
+       $(subst /,\,@del $(YTABC))
+       $(subst /,\,@del $(YTABH))
+else
+       @echo $(U)dgn_comp.y has changed. To update dgn_yacc.c and
+       @echo $(INCL)/dgn_comp.h run $(YACC).
+       @echo ---
+       @echo For now, we will copy the prebuilt $(U)dgn_yacc.c and
+       @echo dgn_comp.h from $(SSYS) into $(UTIL) and use them.
+       $(subst /,\,@copy $(SSYS)/dgn_yacc.c $(U)dgn_yacc.c >nul)
+       $(subst /,\,@copy $(SSYS)/dgn_comp.h $(INCL)/dgn_comp.h >nul)
+       $(subst /,\,echo.>>$(U)dgn_yacc.c)
+       $(subst /,\,echo.>>$(INCL)/dgn_comp.h)
+endif
+
+$(U)dgn_$(LEX).c: $(U)dgn_comp.l
+ifeq  "$(DO_LEX)" "LEX_ACT"
+       $(subst /,\,$(LEX) $(FLEXSKEL) $(U)dgn_comp.l)
+       $(subst /,\,copy $(LEXYYC) $@)
+       $(subst /,\,@del $(LEXYYC))
+else
+       @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX).
+       @echo ---
+       @echo For now, we will copy the prebuilt dgn_lex.c
+       @echo from $(SSYS) into $(UTIL) and use it.
+       $(subst /,\,@copy $(SSYS)/dgn_lex.c $@ >nul)
+       $(subst /,\,echo.>>$@)
+endif
+
+#==========================================
+# Create directory for holding object files
+#==========================================
+
+$(O)obj.tag:
+       $(subst /,\,@if not exist $(OBJ)/*.* echo creating directory $(OBJ))
+       $(subst /,\,@if not exist $(OBJ)/*.* mkdir $(OBJ))
+       $(subst /,\,@echo directory created > $@)
+
+
+#==========================================
+#=========== SECONDARY TARGETS ============
+#==========================================
+
+#===========================================
+# Header files NOT distributed in ../include
+#===========================================
+
+$(INCL)/win32api.h: $(NTSYS)/win32api.h
+       $(subst /,\,copy $(NTSYS)/win32api.h $@)
+
+
+#==========================================
+# DLB utility and nhdat file creation
+#==========================================
+
+$(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o
+       @$(link) $(LFLAGSU) -o$@ $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o
+
+
+$(O)dlb.o:   $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)/dlb.h
+       $(cc) $(CFLAGS) -o$@ $(SRC)/dlb.c
+
+$(O)dlb_main.o: $(UTIL)/dlb_main.c $(INCL)/config.h $(INCL)/dlb.h
+       $(cc) $(CFLAGS) -o$@ $(UTIL)/dlb_main.c
+
+$(DAT)/porthelp: $(NTSYS)/porthelp
+       $(subst /,\,@copy $(NTSYS)/porthelp $@ >nul)
+
+nhdat:  $(U)dlb_main.exe $(DAT)/data $(DAT)/oracles $(OPTIONS_FILE) \
+        $(DAT)/quest.dat $(DAT)/rumors $(DAT)/help $(DAT)/hh $(DAT)/cmdhelp \
+        $(DAT)/history $(DAT)/opthelp $(DAT)/wizhelp $(DAT)/dungeon \
+        $(DAT)/porthelp $(DAT)/license $(O)sp_lev.tag
+       $(subst /,\,echo data >$(DAT)/dlb.lst)
+       $(subst /,\,echo oracles >>$(DAT)/dlb.lst)
+       $(subst /,\,if exist $(DAT)/options echo options >>$(DAT)/dlb.lst)
+       $(subst /,\,if exist $(DAT)/ttyoptions echo ttyoptions >>$(DAT)/dlb.lst)
+       $(subst /,\,if exist $(DAT)/guioptions echo guioptions >>$(DAT)/dlb.lst)
+       $(subst /,\,if exist $(DAT)/porthelp echo porthelp >>$(DAT)/dlb.lst)
+       $(subst /,\,echo quest.dat >>$(DAT)/dlb.lst)
+       $(subst /,\,echo rumors >>$(DAT)/dlb.lst)
+       $(subst /,\,echo help >>$(DAT)/dlb.lst)
+       $(subst /,\,echo hh >>$(DAT)/dlb.lst)
+       $(subst /,\,echo cmdhelp >>$(DAT)/dlb.lst)
+       $(subst /,\,echo history >>$(DAT)/dlb.lst)
+       $(subst /,\,echo opthelp >>$(DAT)/dlb.lst)
+       $(subst /,\,echo wizhelp >>$(DAT)/dlb.lst)
+       $(subst /,\,echo dungeon >>$(DAT)/dlb.lst)
+       $(subst /,\,echo license >>$(DAT)/dlb.lst)
+       dir /l /b /-p $(subst /,\,$(DAT)/*.lev >>$(DAT)/dlb.lst)
+       $(subst /,\,$(U)dlb_main CcIf $(DAT) dlb.lst $(SRC)/nhdat)
+
+#==========================================
+#  Recover Utility
+#==========================================
+
+$(U)recover.exe: $(RECOVOBJS)
+       $(link) $(LFLAGSU) -o$@ $(RECOVOBJS)
+
+$(O)recover.o: $(CONFIG_H) $(U)recover.c $(INCL)/win32api.h
+       $(cc) $(CFLAGSU) -o$@ $(U)recover.c
+
+#==========================================
+#  Tile Mapping
+#==========================================
+
+$(SRC)/tile.c: $(U)tilemap.exe
+       @echo A new $@ has been created
+       @$(U)tilemap
+
+$(U)tilemap.exe: $(O)tilemap.o
+       @$(link) $(LFLAGSU) -o$@ $(O)tilemap.o
+
+$(O)tilemap.o: $(WSHR)/tilemap.c $(HACK_H)
+       $(cc) $(CFLAGSU) -o$@ $(WSHR)/tilemap.c
+
+$(O)tiletx32.o: $(WSHR)/tilemap.c $(HACK_H)
+       $(cc) $(CFLAGS) -DTILETEXT -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/tilemap.c
+
+$(O)tiletxt.o: $(WSHR)/tilemap.c $(HACK_H)
+       $(cc) $(CFLAGS) -DTILETEXT -o$@ $(WSHR)/tilemap.c
+
+$(O)gifread.o: $(WSHR)/gifread.c  $(CONFIG_H) $(TILE_H)
+       $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/gifread.c
+
+$(O)gifrd32.o: $(WSHR)/gifread.c  $(CONFIG_H) $(TILE_H)
+       $(cc) $(CFLAGS) -I$(WSHR) -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/gifread.c
+
+$(O)ppmwrite.o: $(WSHR)/ppmwrite.c $(CONFIG_H) $(TILE_H)
+       $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/ppmwrite.c
+
+$(O)tiletext.o: $(WSHR)/tiletext.c  $(CONFIG_H) $(TILE_H)
+       $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/tiletext.c
+
+$(O)tilete32.o: $(WSHR)/tiletext.c  $(CONFIG_H) $(TILE_H)
+       $(cc) $(CFLAGS) -I$(WSHR) -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/tiletext.c
+
+#==========================================
+# Optional Tile Utilities
+#==========================================
+
+$(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(GIFREADERS) $(TEXT_IO)
+
+$(U)gif2tx32.exe: $(GIFREADERS32) $(TEXT_IO32)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(GIFREADERS32) $(TEXT_IO32)
+
+
+$(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(PPMWRITERS) $(TEXT_IO)
+
+
+ifeq  "$(GRAPHICAL)" "Y"
+$(TILEBMP16): $(TILEUTIL16) $(TILEFILES)
+       @echo Creating 16x16 binary tile files (this may take some time)
+       $(subst /,\,@$(U)tile2bmp $(TILEBMP16))
+#$(TILEBMP32): $(TILEUTIL32) $(TILEFILES32)
+#      @echo Creating 32x32 binary tile files (this may take some time)
+#      $(subst /,\,@$(U)til2bm32 $(TILEBMP32))
+else
+$(TILEBMP16):
+$(TILEBMP32):
+endif
+
+$(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(O)tile2bmp.o $(TEXT_IO)
+
+$(U)til2bm32.exe: $(O)til2bm32.o $(TEXT_IO32)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(O)til2bm32.o $(TEXT_IO32)
+
+$(O)tile2bmp.o: $(WSHR)/tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)/win32api.h
+       $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/tile2bmp.c
+
+$(O)til2bm32.o: $(WSHR)/til2bm32.c $(HACK_H) $(TILE_H) $(INCL)/win32api.h
+       $(cc) $(CFLAGS) -I$(WSHR) -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/til2bm32.c
+
+#==========================================
+# Housekeeping
+#==========================================
+
+spotless: clean
+       $(subst /,\,if exist graphicschk       del graphicschk)
+       $(subst /,\,if exist $(INCL)/date.h    del $(INCL)/date.h)
+       $(subst /,\,if exist $(INCL)/onames.h  del $(INCL)/onames.h)
+       $(subst /,\,if exist $(INCL)/pm.h      del $(INCL)/pm.h)
+       $(subst /,\,if exist $(INCL)/vis_tab.h del $(INCL)/vis_tab.h)
+       $(subst /,\,if exist $(SRC)/vis_tab.c  del $(SRC)/vis_tab.c)
+       $(subst /,\,if exist $(SRC)/tile.c     del $(SRC)/tile.c)
+       $(subst /,\,if exist $(U)*.lnk         del $(U)*.lnk)
+       $(subst /,\,if exist $(U)*.map         del $(U)*.map)
+       $(subst /,\,if exist $(DAT)/data       del $(DAT)/data)
+       $(subst /,\,if exist $(DAT)/rumors     del $(DAT)/rumors)
+       $(subst /,\,if exist $(DAT)/???-fil?.lev      del $(DAT)/???-fil?.lev)
+       $(subst /,\,if exist $(DAT)/???-goal.lev      del $(DAT)/???-goal.lev)
+       $(subst /,\,if exist $(DAT)/???-loca.lev      del $(DAT)/???-loca.lev)
+       $(subst /,\,if exist $(DAT)/???-strt.lev      del $(DAT)/???-strt.lev)
+       $(subst /,\,if exist $(DAT)/air.lev      del $(DAT)/air.lev)
+       $(subst /,\,if exist $(DAT)/asmodeus.lev      del $(DAT)/asmodeus.lev)
+       $(subst /,\,if exist $(DAT)/astral.lev   del $(DAT)/astral.lev)
+       $(subst /,\,if exist $(DAT)/baalz.lev    del $(DAT)/baalz.lev)
+       $(subst /,\,if exist $(DAT)/bigrm-*.lev  del $(DAT)/bigrm-*.lev)
+       $(subst /,\,if exist $(DAT)/castle.lev   del $(DAT)/castle.lev)
+       $(subst /,\,if exist $(DAT)/data    del $(DAT)/data)
+       $(subst /,\,if exist $(DAT)/dungeon      del $(DAT)/dungeon)
+       $(subst /,\,if exist $(DAT)/dungeon.pdf  del $(DAT)/dungeon.pdf)
+       $(subst /,\,if exist $(DAT)/earth.lev    del $(DAT)/earth.lev)
+       $(subst /,\,if exist $(DAT)/fakewiz?.lev      del $(DAT)/fakewiz?.lev)
+       $(subst /,\,if exist $(DAT)/fire.lev     del $(DAT)/fire.lev)
+       $(subst /,\,if exist $(DAT)/juiblex.lev  del $(DAT)/juiblex.lev)
+       $(subst /,\,if exist $(DAT)/knox.lev     del $(DAT)/knox.lev)
+       $(subst /,\,if exist $(DAT)/medusa-?.lev      del $(DAT)/medusa-?.lev)
+       $(subst /,\,if exist $(DAT)/mine*.lev    del $(DAT)/mine*.lev)
+       $(subst /,\,if exist $(DAT)/options      del $(DAT)/options)
+       $(subst /,\,if exist $(DAT)/ttyoptions   del $(DAT)/ttyoptions)
+       $(subst /,\,if exist $(DAT)/guioptions   del $(DAT)/guioptions)
+       $(subst /,\,if exist $(DAT)/oracle.lev   del $(DAT)/oracle.lev)
+       $(subst /,\,if exist $(DAT)/oracles      del $(DAT)/oracles)
+       $(subst /,\,if exist $(DAT)/orcus.lev    del $(DAT)/orcus.lev)
+       $(subst /,\,if exist $(DAT)/rumors  del $(DAT)/rumors)
+       $(subst /,\,if exist $(DAT)/quest.dat    del $(DAT)/quest.dat)
+       $(subst /,\,if exist $(DAT)/sanctum.lev  del $(DAT)/sanctum.lev)
+       $(subst /,\,if exist $(DAT)/soko?-?.lev  del $(DAT)/soko?-?.lev)
+       $(subst /,\,if exist $(DAT)/tower?.lev   del $(DAT)/tower?.lev)
+       $(subst /,\,if exist $(DAT)/valley.lev   del $(DAT)/valley.lev)
+       $(subst /,\,if exist $(DAT)/water.lev    del $(DAT)/water.lev)
+       $(subst /,\,if exist $(DAT)/wizard?.lev  del $(DAT)/wizard?.lev)
+       $(subst /,\,if exist $(O)sp_lev.tag     del $(O)sp_lev.tag)
+       $(subst /,\,if exist $(SRC)/monstr.c    del $(SRC)/monstr.c)
+       $(subst /,\,if exist $(SRC)/vis_tab.c   del $(SRC)/vis_tab.c)
+       $(subst /,\,if exist $(U)recover.exe    del $(U)recover.exe)
+       $(subst /,\,if exist $(DAT)/dlb.lst      del $(DAT)/dlb.lst)
+       $(subst /,\,if exist nhdat.         del nhdat.)
+       $(subst /,\,if exist $(O)install.tag    del $(O)install.tag)
+       $(subst /,\,if exist $(O)obj.tag    del $(O)obj.tag)
+       $(subst /,\,if exist $(O)gamedir.tag    del $(O)gamedir.tag)
+ifneq "$(OBJ)" ""
+       $(subst /,\,rmdir $(OBJ)) /s /Q
+endif
+
+clean:
+       $(subst /,\,if exist $(O)*.o del $(O)*.o)
+       $(subst /,\,if exist $(O)utility.tag   del $(O)utility.tag)
+       $(subst /,\,if exist $(U)makedefs.exe  del $(U)makedefs.exe)
+       $(subst /,\,if exist $(U)lev_comp.exe  del $(U)lev_comp.exe)
+       $(subst /,\,if exist $(U)dgn_comp.exe  del $(U)dgn_comp.exe)
+       $(subst /,\,if exist $(SRC)/*.lnk      del $(SRC)/*.lnk)
+       $(subst /,\,if exist $(SRC)/*.map      del $(SRC)/*.map)
+       $(subst /,\,if exist $(TILEBMP16)      del $(TILEBMP16))
+       $(subst /,\,if exist $(TILEBMP32)      del $(TILEBMP32))
+
+#===================================================================
+# OTHER DEPENDENCIES
+#===================================================================
+
+#
+# dat dependencies
+#
+
+$(DAT)/data: $(O)utility.tag    $(DATABASE)
+       $(subst /,\,$(U)makedefs -d)
+
+$(DAT)/rumors: $(O)utility.tag    $(DAT)/rumors.tru   $(DAT)/rumors.fal
+       $(subst /,\,$(U)makedefs -r)
+
+$(DAT)/quest.dat: $(O)utility.tag  $(DAT)/quest.txt
+       $(subst /,\,$(U)makedefs -q)
+
+$(DAT)/oracles: $(O)utility.tag    $(DAT)/oracles.txt
+       $(subst /,\,$(U)makedefs -h)
+
+$(DAT)/dungeon: $(O)utility.tag  $(DAT)/dungeon.def
+       $(subst /,\,$(U)makedefs -e)
+       $(subst /,\,$(U)dgn_comp $(DAT)/dungeon.pdf)
+
+#
+# NT dependencies
+#
+
+$(O)nttty.o:   $(HACK_H) $(TILE_H) $(INCL)/win32api.h $(NTSYS)/nttty.c
+       $(cc) $(CFLAGS) -I$(WSHR) -o$@  $(NTSYS)/nttty.c
+$(O)winnt.o: $(HACK_H) $(INCL)/win32api.h $(NTSYS)/winnt.c
+       $(cc) $(CFLAGS) -o$@  $(NTSYS)/winnt.c
+$(O)ntsound.o: $(HACK_H) $(NTSYS)/ntsound.c
+       $(cc) $(CFLAGS)  -o$@ $(NTSYS)/ntsound.c
+$(O)mapimail.o: $(HACK_H) $(INCL)/nhlan.h $(NTSYS)/mapimail.c
+       $(cc) $(CFLAGS) -DMAPI_VERBOSE  -o$@ $(NTSYS)/mapimail.c
+
+#
+# util dependencies
+#
+
+$(O)panic.o:  $(U)panic.c $(CONFIG_H)
+       $(cc) $(CFLAGS) -o$@ $(U)panic.c
+
+#
+# The rest are stolen from sys/unix/Makefile.src,
+# with the following changes:
+#   * ../include changed to $(INCL)
+#   * -c (which is included in CFLAGS) substituted
+#      with -o$@
+#   * targets prefixed with $(O)
+#   * $(CC) changed to $(cc)
+# but otherwise untouched. 
+# That means that there is some irrelevant stuff
+# in here, but maintenance should be easier.
+#
+$(O)tos.o: ../sys/atari/tos.c $(HACK_H) $(INCL)/tcap.h
+       $(cc) $(CFLAGS) -o$@ ../sys/atari/tos.c
+$(O)pcmain.o: ../sys/share/pcmain.c $(HACK_H) $(INCL)/dlb.h \
+               $(INCL)/win32api.h
+       $(cc) $(CFLAGS) -o$@ ../sys/share/pcmain.c
+$(O)pcsys.o: ../sys/share/pcsys.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/share/pcsys.c
+$(O)pctty.o: ../sys/share/pctty.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/share/pctty.c
+$(O)pcunix.o: ../sys/share/pcunix.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/share/pcunix.c
+$(O)random.o: ../sys/share/random.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/share/random.c
+$(O)ioctl.o: ../sys/share/ioctl.c $(HACK_H) $(INCL)/tcap.h
+       $(cc) $(CFLAGS) -o$@ ../sys/share/ioctl.c
+$(O)unixtty.o: ../sys/share/unixtty.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/share/unixtty.c
+$(O)unixmain.o: ../sys/unix/unixmain.c $(HACK_H) $(INCL)/dlb.h
+       $(cc) $(CFLAGS) -o$@ ../sys/unix/unixmain.c
+$(O)unixunix.o: ../sys/unix/unixunix.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/unix/unixunix.c
+$(O)unixres.o: ../sys/unix/unixres.c $(CONFIG_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/unix/unixres.c
+$(O)bemain.o: ../sys/be/bemain.c $(HACK_H) $(INCL)/dlb.h
+       $(cc) $(CFLAGS) -o$@ ../sys/be/bemain.c
+$(O)getline.o: ../win/tty/getline.c $(HACK_H) $(INCL)/func_tab.h
+       $(cc) $(CFLAGS) -o$@ ../win/tty/getline.c
+$(O)termcap.o: ../win/tty/termcap.c $(HACK_H) $(INCL)/tcap.h
+       $(cc) $(CFLAGS) -o$@ ../win/tty/termcap.c
+$(O)topl.o: ../win/tty/topl.c $(HACK_H) $(INCL)/tcap.h
+       $(cc) $(CFLAGS) -o$@ ../win/tty/topl.c
+$(O)wintty.o: ../win/tty/wintty.c $(HACK_H) $(INCL)/dlb.h \
+               $(INCL)/patchlevel.h $(INCL)/tcap.h
+       $(cc) $(CFLAGS) -o$@ ../win/tty/wintty.c
+$(O)Window.o: ../win/X11/Window.c $(INCL)/xwindowp.h $(INCL)/xwindow.h \
+               $(CONFIG_H)
+       $(cc) $(CFLAGS) -o$@ ../win/X11/Window.c
+$(O)dialogs.o: ../win/X11/dialogs.c $(CONFIG_H)
+       $(cc) $(CFLAGS) -o$@ ../win/X11/dialogs.c
+$(O)winX.o: ../win/X11/winX.c $(HACK_H) $(INCL)/winX.h $(INCL)/dlb.h \
+               $(INCL)/patchlevel.h ../win/X11/nh72icon \
+               ../win/X11/nh56icon ../win/X11/nh32icon
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winX.c
+$(O)winmap.o: ../win/X11/winmap.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/dlb.h \
+               $(INCL)/winX.h $(INCL)/tile2x11.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winmap.c
+$(O)winmenu.o: ../win/X11/winmenu.c $(HACK_H) $(INCL)/winX.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winmenu.c
+$(O)winmesg.o: ../win/X11/winmesg.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/winX.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winmesg.c
+$(O)winmisc.o: ../win/X11/winmisc.c $(HACK_H) $(INCL)/func_tab.h \
+               $(INCL)/winX.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winmisc.c
+$(O)winstat.o: ../win/X11/winstat.c $(HACK_H) $(INCL)/winX.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winstat.c
+$(O)wintext.o: ../win/X11/wintext.c $(HACK_H) $(INCL)/winX.h $(INCL)/xwindow.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/wintext.c
+$(O)winval.o: ../win/X11/winval.c $(HACK_H) $(INCL)/winX.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winval.c
+$(O)tile.o: tile.c $(HACK_H)
+$(O)gnaskstr.o: ../win/gnome/gnaskstr.c ../win/gnome/gnaskstr.h \
+               ../win/gnome/gnmain.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnaskstr.c
+$(O)gnbind.o: ../win/gnome/gnbind.c ../win/gnome/gnbind.h ../win/gnome/gnmain.h \
+               ../win/gnome/gnaskstr.h ../win/gnome/gnyesno.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnbind.c
+$(O)gnglyph.o: ../win/gnome/gnglyph.c ../win/gnome/gnglyph.h $(INCL)/tile2x11.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnglyph.c
+$(O)gnmain.o: ../win/gnome/gnmain.c ../win/gnome/gnmain.h ../win/gnome/gnsignal.h \
+               ../win/gnome/gnbind.h ../win/gnome/gnopts.h $(HACK_H) \
+               $(INCL)/date.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmain.c
+$(O)gnmap.o: ../win/gnome/gnmap.c ../win/gnome/gnmap.h ../win/gnome/gnglyph.h \
+               ../win/gnome/gnsignal.h $(HACK_H)
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmap.c
+$(O)gnmenu.o: ../win/gnome/gnmenu.c ../win/gnome/gnmenu.h ../win/gnome/gnmain.h \
+               ../win/gnome/gnbind.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmenu.c
+$(O)gnmesg.o: ../win/gnome/gnmesg.c ../win/gnome/gnmesg.h ../win/gnome/gnsignal.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmesg.c
+$(O)gnopts.o: ../win/gnome/gnopts.c ../win/gnome/gnopts.h ../win/gnome/gnglyph.h \
+               ../win/gnome/gnmain.h ../win/gnome/gnmap.h $(HACK_H)
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnopts.c
+$(O)gnplayer.o: ../win/gnome/gnplayer.c ../win/gnome/gnplayer.h \
+               ../win/gnome/gnmain.h $(HACK_H)
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnplayer.c
+$(O)gnsignal.o: ../win/gnome/gnsignal.c ../win/gnome/gnsignal.h \
+               ../win/gnome/gnmain.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnsignal.c
+$(O)gnstatus.o: ../win/gnome/gnstatus.c ../win/gnome/gnstatus.h \
+               ../win/gnome/gnsignal.h ../win/gnome/gn_xpms.h \
+               ../win/gnome/gnomeprv.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnstatus.c
+$(O)gntext.o: ../win/gnome/gntext.c ../win/gnome/gntext.h ../win/gnome/gnmain.h \
+               ../win/gnome/gn_rip.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gntext.c
+$(O)gnworn.o: ../win/gnome/gnworn.c ../win/gnome/gnworn.h ../win/gnome/gnglyph.h \
+               ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnworn.c
+$(O)gnyesno.o: ../win/gnome/gnyesno.c ../win/gnome/gnbind.h ../win/gnome/gnyesno.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnyesno.c
+$(O)wingem.o: ../win/gem/wingem.c $(HACK_H) $(INCL)/func_tab.h $(INCL)/dlb.h \
+               $(INCL)/patchlevel.h $(INCL)/wingem.h
+       $(cc) $(CFLAGS) -o$@ ../win/gem/wingem.c
+$(O)wingem1.o: ../win/gem/wingem1.c $(INCL)/gem_rsc.h $(INCL)/load_img.h \
+               $(INCL)/gr_rect.h $(INCL)/wintype.h $(INCL)/wingem.h
+       $(cc) $(CFLAGS) -o$@ ../win/gem/wingem1.c
+$(O)load_img.o: ../win/gem/load_img.c $(INCL)/load_img.h
+       $(cc) $(CFLAGS) -o$@ ../win/gem/load_img.c
+$(O)gr_rect.o: ../win/gem/gr_rect.c $(INCL)/gr_rect.h
+       $(cc) $(CFLAGS) -o$@ ../win/gem/gr_rect.c
+$(O)tile.o: tile.c $(HACK_H)
+$(O)qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) $(INCL)/func_tab.h \
+               $(INCL)/dlb.h $(INCL)/patchlevel.h $(INCL)/tile2x11.h \
+               $(INCL)/qt_win.h $(INCL)/qt_clust.h $(INCL)/qt_kde0.h \
+               $(INCL)/qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc
+       $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_win.cpp
+$(O)qt_clust.o: ../win/Qt/qt_clust.cpp $(INCL)/qt_clust.h
+       $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_clust.cpp
+$(O)qttableview.o: ../win/Qt/qttableview.cpp $(INCL)/qttableview.h
+       $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qttableview.cpp
+$(O)monstr.o: monstr.c $(CONFIG_H)
+$(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)/vis_tab.h
+$(O)allmain.o: allmain.c $(HACK_H)
+$(O)alloc.o: alloc.c $(CONFIG_H)
+$(O)apply.o: apply.c $(HACK_H) $(INCL)/edog.h
+$(O)artifact.o: artifact.c $(HACK_H) $(INCL)/artifact.h $(INCL)/artilist.h
+$(O)attrib.o: attrib.c $(HACK_H)
+$(O)ball.o: ball.c $(HACK_H)
+$(O)bones.o: bones.c $(HACK_H) $(INCL)/lev.h
+$(O)botl.o: botl.c $(HACK_H)
+$(O)cmd.o: cmd.c $(HACK_H) $(INCL)/func_tab.h
+$(O)dbridge.o: dbridge.c $(HACK_H)
+$(O)decl.o: decl.c $(HACK_H)
+$(O)detect.o: detect.c $(HACK_H) $(INCL)/artifact.h
+$(O)dig.o: dig.c $(HACK_H) $(INCL)/edog.h
+$(O)display.o: display.c $(HACK_H)
+$(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)/dlb.h
+$(O)do.o: do.c $(HACK_H) $(INCL)/lev.h
+$(O)do_name.o: do_name.c $(HACK_H)
+$(O)do_wear.o: do_wear.c $(HACK_H)
+$(O)dog.o: dog.c $(HACK_H) $(INCL)/edog.h
+$(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/edog.h
+$(O)dokick.o: dokick.c $(HACK_H) $(INCL)/eshk.h
+$(O)dothrow.o: dothrow.c $(HACK_H) $(INCL)/edog.h
+$(O)drawing.o: drawing.c $(HACK_H) $(INCL)/tcap.h
+$(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)/dgn_file.h $(INCL)/dlb.h
+$(O)eat.o: eat.c $(HACK_H)
+$(O)end.o: end.c $(HACK_H) $(INCL)/eshk.h $(INCL)/dlb.h
+$(O)engrave.o: engrave.c $(HACK_H) $(INCL)/lev.h
+$(O)exper.o: exper.c $(HACK_H)
+$(O)explode.o: explode.c $(HACK_H)
+$(O)extralev.o: extralev.c $(HACK_H)
+$(O)files.o: files.c $(HACK_H) $(INCL)/dlb.h
+$(O)fountain.o: fountain.c $(HACK_H)
+$(O)hack.o: hack.c $(HACK_H)
+$(O)hacklib.o: hacklib.c $(HACK_H)
+$(O)invent.o: invent.c $(HACK_H)
+$(O)light.o: light.c $(HACK_H) $(INCL)/lev.h
+$(O)lock.o: lock.c $(HACK_H)
+$(O)mail.o: mail.c $(HACK_H) $(INCL)/mail.h
+$(O)makemon.o: makemon.c $(HACK_H) $(INCL)/epri.h $(INCL)/emin.h \
+               $(INCL)/edog.h
+$(O)mapglyph.o: mapglyph.c $(HACK_H)
+$(O)mcastu.o: mcastu.c $(HACK_H)
+$(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)/artifact.h $(INCL)/edog.h
+$(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)/artifact.h $(INCL)/edog.h
+$(O)minion.o: minion.c $(HACK_H) $(INCL)/emin.h $(INCL)/epri.h
+$(O)mklev.o: mklev.c $(HACK_H)
+$(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)/sp_lev.h
+$(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)/sp_lev.h $(INCL)/lev.h
+$(O)mkobj.o: mkobj.c $(HACK_H)
+$(O)mkroom.o: mkroom.c $(HACK_H)
+$(O)mon.o: mon.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/edog.h
+$(O)mondata.o: mondata.c $(HACK_H) $(INCL)/eshk.h $(INCL)/epri.h
+$(O)monmove.o: monmove.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/artifact.h \
+               $(INCL)/epri.h
+$(O)monst.o: monst.c $(CONFIG_H) $(INCL)/permonst.h $(INCL)/align.h \
+               $(INCL)/monattk.h $(INCL)/monflag.h $(INCL)/monsym.h \
+               $(INCL)/dungeon.h $(INCL)/eshk.h $(INCL)/vault.h \
+               $(INCL)/epri.h $(INCL)/color.h
+$(O)mplayer.o: mplayer.c $(HACK_H)
+$(O)mthrowu.o: mthrowu.c $(HACK_H)
+$(O)muse.o: muse.c $(HACK_H) $(INCL)/edog.h
+$(O)music.o: music.c $(HACK_H) #interp.c
+$(O)o_init.o: o_init.c $(HACK_H) $(INCL)/lev.h
+$(O)objects.o: objects.c $(CONFIG_H) $(INCL)/obj.h $(INCL)/objclass.h \
+               $(INCL)/prop.h $(INCL)/skills.h $(INCL)/color.h
+$(O)objnam.o: objnam.c $(HACK_H)
+$(O)options.o: options.c $(CONFIG_H) $(INCL)/objclass.h $(INCL)/flag.h \
+               $(HACK_H) $(INCL)/tcap.h
+$(O)pager.o: pager.c $(HACK_H) $(INCL)/dlb.h
+$(O)pickup.o: pickup.c $(HACK_H)
+$(O)pline.o: pline.c $(HACK_H) $(INCL)/epri.h $(INCL)/edog.h
+$(O)polyself.o: polyself.c $(HACK_H)
+$(O)potion.o: potion.c $(HACK_H)
+$(O)pray.o: pray.c $(HACK_H) $(INCL)/epri.h
+$(O)priest.o: priest.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/eshk.h \
+               $(INCL)/epri.h $(INCL)/emin.h
+$(O)quest.o: quest.c $(HACK_H) $(INCL)/qtext.h
+$(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)/dlb.h $(INCL)/qtext.h
+$(O)read.o: read.c $(HACK_H)
+$(O)rect.o: rect.c $(HACK_H)
+$(O)region.o: region.c $(HACK_H) $(INCL)/lev.h
+$(O)restore.o: restore.c $(HACK_H) $(INCL)/lev.h $(INCL)/tcap.h
+$(O)rip.o: rip.c $(HACK_H)
+$(O)rnd.o: rnd.c $(HACK_H)
+$(O)role.o: role.c $(HACK_H)
+$(O)rumors.o: rumors.c $(HACK_H) $(INCL)/lev.h $(INCL)/dlb.h
+$(O)save.o: save.c $(HACK_H) $(INCL)/lev.h
+$(O)shk.o: shk.c $(HACK_H) $(INCL)/eshk.h
+$(O)shknam.o: shknam.c $(HACK_H) $(INCL)/eshk.h
+$(O)sit.o: sit.c $(HACK_H) $(INCL)/artifact.h
+$(O)sounds.o: sounds.c $(HACK_H) $(INCL)/edog.h
+$(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)/dlb.h $(INCL)/sp_lev.h
+$(O)spell.o: spell.c $(HACK_H)
+$(O)steal.o: steal.c $(HACK_H)
+$(O)steed.o: steed.c $(HACK_H)
+$(O)teleport.o: teleport.c $(HACK_H)
+$(O)timeout.o: timeout.c $(HACK_H) $(INCL)/lev.h
+$(O)topten.o: topten.c $(HACK_H) $(INCL)/dlb.h $(INCL)/patchlevel.h
+$(O)track.o: track.c $(HACK_H)
+$(O)trap.o: trap.c $(HACK_H)
+$(O)u_init.o: u_init.c $(HACK_H)
+$(O)uhitm.o: uhitm.c $(HACK_H)
+$(O)vault.o: vault.c $(HACK_H) $(INCL)/vault.h
+$(O)version.o: version.c $(HACK_H) $(INCL)/date.h $(INCL)/patchlevel.h
+$(O)vision.o: vision.c $(HACK_H) $(INCL)/vis_tab.h
+$(O)weapon.o: weapon.c $(HACK_H)
+$(O)were.o: were.c $(HACK_H)
+$(O)wield.o: wield.c $(HACK_H)
+$(O)windows.o: windows.c $(HACK_H) $(INCL)/wingem.h $(INCL)/winGnome.h
+$(O)wizard.o: wizard.c $(HACK_H) $(INCL)/qtext.h $(INCL)/epri.h
+$(O)worm.o: worm.c $(HACK_H) $(INCL)/lev.h
+$(O)worn.o: worn.c $(HACK_H)
+$(O)write.o: write.c $(HACK_H)
+$(O)zap.o: zap.c $(HACK_H)
+
+# end of file
diff --git a/src/allmain.c b/src/allmain.c
new file mode 100644 (file)
index 0000000..d624a2f
--- /dev/null
@@ -0,0 +1,633 @@
+/*     SCCS Id: @(#)allmain.c  3.4     2003/04/02      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* various code that was replicated in *main.c */
+
+#include "hack.h"
+
+#ifndef NO_SIGNAL
+#include <signal.h>
+#endif
+
+#ifdef POSITIONBAR
+STATIC_DCL void NDECL(do_positionbar);
+#endif
+
+#ifdef OVL0
+
+void
+moveloop()
+{
+#if defined(MICRO) || defined(WIN32)
+    char ch;
+    int abort_lev;
+#endif
+    int moveamt = 0, wtcap = 0, change = 0;
+    boolean didmove = FALSE, monscanmove = FALSE;
+
+    flags.moonphase = phase_of_the_moon();
+    if(flags.moonphase == FULL_MOON) {
+       You("are lucky!  Full moon tonight.");
+       change_luck(1);
+    } else if(flags.moonphase == NEW_MOON) {
+       pline("Be careful!  New moon tonight.");
+    }
+    flags.friday13 = friday_13th();
+    if (flags.friday13) {
+       pline("Watch out!  Bad things can happen on Friday the 13th.");
+       change_luck(-1);
+    }
+
+    initrack();
+
+
+    /* Note:  these initializers don't do anything except guarantee that
+           we're linked properly.
+    */
+    decl_init();
+    monst_init();
+    monstr_init();     /* monster strengths */
+    objects_init();
+
+#ifdef WIZARD
+    if (wizard) add_debug_extended_commands();
+#endif
+
+    (void) encumber_msg(); /* in case they auto-picked up something */
+
+    u.uz0.dlevel = u.uz.dlevel;
+    youmonst.movement = NORMAL_SPEED;  /* give the hero some movement points */
+
+    for(;;) {
+       get_nh_event();
+#ifdef POSITIONBAR
+       do_positionbar();
+#endif
+
+       didmove = flags.move;
+       if(didmove) {
+           /* actual time passed */
+           youmonst.movement -= NORMAL_SPEED;
+
+           do { /* hero can't move this turn loop */
+               wtcap = encumber_msg();
+
+               flags.mon_moving = TRUE;
+               do {
+                   monscanmove = movemon();
+                   if (youmonst.movement > NORMAL_SPEED)
+                       break;  /* it's now your turn */
+               } while (monscanmove);
+               flags.mon_moving = FALSE;
+
+               if (!monscanmove && youmonst.movement < NORMAL_SPEED) {
+                   /* both you and the monsters are out of steam this round */
+                   /* set up for a new turn */
+                   struct monst *mtmp;
+                   mcalcdistress();    /* adjust monsters' trap, blind, etc */
+
+                   /* reallocate movement rations to monsters */
+                   for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+                       mtmp->movement += mcalcmove(mtmp);
+
+                   if(!rn2(u.uevent.udemigod ? 25 :
+                           (depth(&u.uz) > depth(&stronghold_level)) ? 50 : 70))
+                       (void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS);
+
+                   /* calculate how much time passed. */
+#ifdef STEED
+                   if (u.usteed && u.umoved) {
+                       /* your speed doesn't augment steed's speed */
+                       moveamt = mcalcmove(u.usteed);
+                   } else
+#endif
+                   {
+                       moveamt = youmonst.data->mmove;
+
+                       if (Very_fast) {        /* speed boots or potion */
+                           /* average movement is 1.67 times normal */
+                           moveamt += NORMAL_SPEED / 2;
+                           if (rn2(3) == 0) moveamt += NORMAL_SPEED / 2;
+                       } else if (Fast) {
+                           /* average movement is 1.33 times normal */
+                           if (rn2(3) != 0) moveamt += NORMAL_SPEED / 2;
+                       }
+                   }
+
+                   switch (wtcap) {
+                       case UNENCUMBERED: break;
+                       case SLT_ENCUMBER: moveamt -= (moveamt / 4); break;
+                       case MOD_ENCUMBER: moveamt -= (moveamt / 2); break;
+                       case HVY_ENCUMBER: moveamt -= ((moveamt * 3) / 4); break;
+                       case EXT_ENCUMBER: moveamt -= ((moveamt * 7) / 8); break;
+                       default: break;
+                   }
+
+                   youmonst.movement += moveamt;
+                   if (youmonst.movement < 0) youmonst.movement = 0;
+                   settrack();
+
+                   monstermoves++;
+                   moves++;
+
+                   /********************************/
+                   /* once-per-turn things go here */
+                   /********************************/
+
+                   if (flags.bypasses) clear_bypasses();
+                   if(Glib) glibr();
+                   nh_timeout();
+                   run_regions();
+
+                   if (u.ublesscnt)  u.ublesscnt--;
+                   if(flags.time && !flags.run)
+                       flags.botl = 1;
+
+                   /* One possible result of prayer is healing.  Whether or
+                    * not you get healed depends on your current hit points.
+                    * If you are allowed to regenerate during the prayer, the
+                    * end-of-prayer calculation messes up on this.
+                    * Another possible result is rehumanization, which requires
+                    * that encumbrance and movement rate be recalculated.
+                    */
+                   if (u.uinvulnerable) {
+                       /* for the moment at least, you're in tiptop shape */
+                       wtcap = UNENCUMBERED;
+                   } else if (Upolyd && youmonst.data->mlet == S_EEL && !is_pool(u.ux,u.uy) && !Is_waterlevel(&u.uz)) {
+                       if (u.mh > 1) {
+                           u.mh--;
+                           flags.botl = 1;
+                       } else if (u.mh < 1)
+                           rehumanize();
+                   } else if (Upolyd && u.mh < u.mhmax) {
+                       if (u.mh < 1)
+                           rehumanize();
+                       else if (Regeneration ||
+                                   (wtcap < MOD_ENCUMBER && !(moves%20))) {
+                           flags.botl = 1;
+                           u.mh++;
+                       }
+                   } else if (u.uhp < u.uhpmax &&
+                        (wtcap < MOD_ENCUMBER || !u.umoved || Regeneration)) {
+                       if (u.ulevel > 9 && !(moves % 3)) {
+                           int heal, Con = (int) ACURR(A_CON);
+
+                           if (Con <= 12) {
+                               heal = 1;
+                           } else {
+                               heal = rnd(Con);
+                               if (heal > u.ulevel-9) heal = u.ulevel-9;
+                           }
+                           flags.botl = 1;
+                           u.uhp += heal;
+                           if(u.uhp > u.uhpmax)
+                               u.uhp = u.uhpmax;
+                       } else if (Regeneration ||
+                            (u.ulevel <= 9 &&
+                             !(moves % ((MAXULEV+12) / (u.ulevel+2) + 1)))) {
+                           flags.botl = 1;
+                           u.uhp++;
+                       }
+                   }
+
+                   /* moving around while encumbered is hard work */
+                   if (wtcap > MOD_ENCUMBER && u.umoved) {
+                       if(!(wtcap < EXT_ENCUMBER ? moves%30 : moves%10)) {
+                           if (Upolyd && u.mh > 1) {
+                               u.mh--;
+                           } else if (!Upolyd && u.uhp > 1) {
+                               u.uhp--;
+                           } else {
+                               You("pass out from exertion!");
+                               exercise(A_CON, FALSE);
+                               fall_asleep(-10, FALSE);
+                           }
+                       }
+                   }
+
+                   if ((u.uen < u.uenmax) &&
+                       ((wtcap < MOD_ENCUMBER &&
+                         (!(moves%((MAXULEV + 8 - u.ulevel) *
+                                   (Role_if(PM_WIZARD) ? 3 : 4) / 6))))
+                        || Energy_regeneration)) {
+                       u.uen += rn1((int)(ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1,1);
+                       if (u.uen > u.uenmax)  u.uen = u.uenmax;
+                       flags.botl = 1;
+                   }
+
+                   if(!u.uinvulnerable) {
+                       if(Teleportation && !rn2(85)) {
+                           xchar old_ux = u.ux, old_uy = u.uy;
+                           tele();
+                           if (u.ux != old_ux || u.uy != old_uy) {
+                               if (!next_to_u()) {
+                                   check_leash(old_ux, old_uy);
+                               }
+#ifdef REDO
+                               /* clear doagain keystrokes */
+                               pushch(0);
+                               savech(0);
+#endif
+                           }
+                       }
+                       /* delayed change may not be valid anymore */
+                       if ((change == 1 && !Polymorph) ||
+                           (change == 2 && u.ulycn == NON_PM))
+                           change = 0;
+                       if(Polymorph && !rn2(100))
+                           change = 1;
+                       else if (u.ulycn >= LOW_PM && !Upolyd &&
+                                !rn2(80 - (20 * night())))
+                           change = 2;
+                       if (change && !Unchanging) {
+                           if (multi >= 0) {
+                               if (occupation)
+                                   stop_occupation();
+                               else
+                                   nomul(0);
+                               if (change == 1) polyself(FALSE);
+                               else you_were();
+                               change = 0;
+                           }
+                       }
+                   }
+
+                   if(Searching && multi >= 0) (void) dosearch0(1);
+                   dosounds();
+                   do_storms();
+                   gethungry();
+                   age_spells();
+                   exerchk();
+                   invault();
+                   if (u.uhave.amulet) amulet();
+                   if (!rn2(40+(int)(ACURR(A_DEX)*3)))
+                       u_wipe_engr(rnd(3));
+                   if (u.uevent.udemigod && !u.uinvulnerable) {
+                       if (u.udg_cnt) u.udg_cnt--;
+                       if (!u.udg_cnt) {
+                           intervene();
+                           u.udg_cnt = rn1(200, 50);
+                       }
+                   }
+                   restore_attrib();
+                   /* underwater and waterlevel vision are done here */
+                   if (Is_waterlevel(&u.uz))
+                       movebubbles();
+                   else if (Underwater)
+                       under_water(0);
+                   /* vision while buried done here */
+                   else if (u.uburied) under_ground(0);
+
+                   /* when immobile, count is in turns */
+                   if(multi < 0) {
+                       if (++multi == 0) {     /* finished yet? */
+                           unmul((char *)0);
+                           /* if unmul caused a level change, take it now */
+                           if (u.utotype) deferred_goto();
+                       }
+                   }
+               }
+           } while (youmonst.movement<NORMAL_SPEED); /* hero can't move loop */
+
+           /******************************************/
+           /* once-per-hero-took-time things go here */
+           /******************************************/
+
+
+       } /* actual time passed */
+
+       /****************************************/
+       /* once-per-player-input things go here */
+       /****************************************/
+
+       find_ac();
+       if(!flags.mv || Blind) {
+           /* redo monsters if hallu or wearing a helm of telepathy */
+           if (Hallucination) {        /* update screen randomly */
+               see_monsters();
+               see_objects();
+               see_traps();
+               if (u.uswallow) swallowed(0);
+           } else if (Unblind_telepat) {
+               see_monsters();
+           } else if (Warning || Warn_of_mon)
+               see_monsters();
+
+           if (vision_full_recalc) vision_recalc(0);   /* vision! */
+       }
+       if(flags.botl || flags.botlx) bot();
+
+       flags.move = 1;
+
+       if(multi >= 0 && occupation) {
+#if defined(MICRO) || defined(WIN32)
+           abort_lev = 0;
+           if (kbhit()) {
+               if ((ch = Getchar()) == ABORT)
+                   abort_lev++;
+# ifdef REDO
+               else
+                   pushch(ch);
+# endif /* REDO */
+           }
+           if (!abort_lev && (*occupation)() == 0)
+#else
+           if ((*occupation)() == 0)
+#endif
+               occupation = 0;
+           if(
+#if defined(MICRO) || defined(WIN32)
+                  abort_lev ||
+#endif
+                  monster_nearby()) {
+               stop_occupation();
+               reset_eat();
+           }
+#if defined(MICRO) || defined(WIN32)
+           if (!(++occtime % 7))
+               display_nhwindow(WIN_MAP, FALSE);
+#endif
+           continue;
+       }
+
+       if ((u.uhave.amulet || Clairvoyant) &&
+           !In_endgame(&u.uz) && !BClairvoyant &&
+           !(moves % 15) && !rn2(2))
+               do_vicinity_map();
+
+       if(u.utrap && u.utraptype == TT_LAVA) {
+           if(!is_lava(u.ux,u.uy))
+               u.utrap = 0;
+           else if (!u.uinvulnerable) {
+               u.utrap -= 1<<8;
+               if(u.utrap < 1<<8) {
+                   killer_format = KILLED_BY;
+                   killer = "molten lava";
+                   You("sink below the surface and die.");
+                   done(DISSOLVED);
+               } else if(didmove && !u.umoved) {
+                   Norep("You sink deeper into the lava.");
+                   u.utrap += rnd(4);
+               }
+           }
+       }
+
+#ifdef WIZARD
+       if (iflags.sanity_check)
+           sanity_check();
+#endif
+
+#ifdef CLIPPING
+       /* just before rhack */
+       cliparound(u.ux, u.uy);
+#endif
+
+       u.umoved = FALSE;
+
+       if (multi > 0) {
+           lookaround();
+           if (!multi) {
+               /* lookaround may clear multi */
+               flags.move = 0;
+               if (flags.time) flags.botl = 1;
+               continue;
+           }
+           if (flags.mv) {
+               if(multi < COLNO && !--multi)
+                   flags.travel = iflags.travel1 = flags.mv = flags.run = 0;
+               domove();
+           } else {
+               --multi;
+               rhack(save_cm);
+           }
+       } else if (multi == 0) {
+#ifdef MAIL
+           ckmailstatus();
+#endif
+           rhack((char *)0);
+       }
+       if (u.utotype)          /* change dungeon level */
+           deferred_goto();    /* after rhack() */
+       /* !flags.move here: multiple movement command stopped */
+       else if (flags.time && (!flags.move || !flags.mv))
+           flags.botl = 1;
+
+       if (vision_full_recalc) vision_recalc(0);       /* vision! */
+       /* when running in non-tport mode, this gets done through domove() */
+       if ((!flags.run || iflags.runmode == RUN_TPORT) &&
+               (multi && (!flags.travel ? !(multi % 7) : !(moves % 7L)))) {
+           if (flags.time && flags.run) flags.botl = 1;
+           display_nhwindow(WIN_MAP, FALSE);
+       }
+    }
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+void
+stop_occupation()
+{
+       if(occupation) {
+               if (!maybe_finished_meal(TRUE))
+                   You("stop %s.", occtxt);
+               occupation = 0;
+               flags.botl = 1; /* in case u.uhs changed */
+/* fainting stops your occupation, there's no reason to sync.
+               sync_hunger();
+*/
+#ifdef REDO
+               nomul(0);
+               pushch(0);
+#endif
+       }
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+void
+display_gamewindows()
+{
+    WIN_MESSAGE = create_nhwindow(NHW_MESSAGE);
+    WIN_STATUS = create_nhwindow(NHW_STATUS);
+    WIN_MAP = create_nhwindow(NHW_MAP);
+    WIN_INVEN = create_nhwindow(NHW_MENU);
+
+#ifdef MAC
+    /*
+     * This _is_ the right place for this - maybe we will
+     * have to split display_gamewindows into create_gamewindows
+     * and show_gamewindows to get rid of this ifdef...
+     */
+       if ( ! strcmp ( windowprocs . name , "mac" ) ) {
+           SanePositions ( ) ;
+       }
+#endif
+
+    /*
+     * The mac port is not DEPENDENT on the order of these
+     * displays, but it looks a lot better this way...
+     */
+    display_nhwindow(WIN_STATUS, FALSE);
+    display_nhwindow(WIN_MESSAGE, FALSE);
+    clear_glyph_buffer();
+    display_nhwindow(WIN_MAP, FALSE);
+}
+
+void
+newgame()
+{
+       int i;
+
+#ifdef MFLOPPY
+       gameDiskPrompt();
+#endif
+
+       flags.ident = 1;
+
+       for (i = 0; i < NUMMONS; i++)
+               mvitals[i].mvflags = mons[i].geno & G_NOCORPSE;
+
+       init_objects();         /* must be before u_init() */
+
+       flags.pantheon = -1;    /* role_init() will reset this */
+       role_init();            /* must be before init_dungeons(), u_init(),
+                                * and init_artifacts() */
+
+       init_dungeons();        /* must be before u_init() to avoid rndmonst()
+                                * creating odd monsters for any tins and eggs
+                                * in hero's initial inventory */
+       init_artifacts();       /* before u_init() in case $WIZKIT specifies
+                                * any artifacts */
+       u_init();
+
+#ifndef NO_SIGNAL
+       (void) signal(SIGINT, (SIG_RET_TYPE) done1);
+#endif
+#ifdef NEWS
+       if(iflags.news) display_file(NEWS, FALSE);
+#endif
+       load_qtlist();  /* load up the quest text info */
+/*     quest_init();*/ /* Now part of role_init() */
+
+       mklev();
+       u_on_upstairs();
+       vision_reset();         /* set up internals for level (after mklev) */
+       check_special_room(FALSE);
+
+       flags.botlx = 1;
+
+       /* Move the monster from under you or else
+        * makedog() will fail when it calls makemon().
+        *                      - ucsfcgl!kneller
+        */
+       if(MON_AT(u.ux, u.uy)) mnexto(m_at(u.ux, u.uy));
+       (void) makedog();
+       docrt();
+
+       if (flags.legacy) {
+               flush_screen(1);
+               com_pager(1);
+       }
+
+#ifdef INSURANCE
+       save_currentstate();
+#endif
+       program_state.something_worth_saving++; /* useful data now exists */
+
+       /* Success! */
+       welcome(TRUE);
+       return;
+}
+
+/* show "welcome [back] to nethack" message at program startup */
+void
+welcome(new_game)
+boolean new_game;      /* false => restoring an old game */
+{
+    char buf[BUFSZ];
+    boolean currentgend = Upolyd ? u.mfemale : flags.female;
+
+    /*
+     * The "welcome back" message always describes your innate form
+     * even when polymorphed or wearing a helm of opposite alignment.
+     * Alignment is shown unconditionally for new games; for restores
+     * it's only shown if it has changed from its original value.
+     * Sex is shown for new games except when it is redundant; for
+     * restores it's only shown if different from its original value.
+     */
+    *buf = '\0';
+    if (new_game || u.ualignbase[A_ORIGINAL] != u.ualignbase[A_CURRENT])
+       Sprintf(eos(buf), " %s", align_str(u.ualignbase[A_ORIGINAL]));
+    if (!urole.name.f &&
+           (new_game ? (urole.allow & ROLE_GENDMASK) == (ROLE_MALE|ROLE_FEMALE) :
+            currentgend != flags.initgend))
+       Sprintf(eos(buf), " %s", genders[currentgend].adj);
+
+    pline(new_game ? "%s %s, welcome to NetHack!  You are a%s %s %s."
+                  : "%s %s, the%s %s %s, welcome back to NetHack!",
+         Hello((struct monst *) 0), plname, buf, urace.adj,
+         (currentgend && urole.name.f) ? urole.name.f : urole.name.m);
+}
+
+#ifdef POSITIONBAR
+STATIC_DCL void
+do_positionbar()
+{
+       static char pbar[COLNO];
+       char *p;
+       
+       p = pbar;
+       /* up stairway */
+       if (upstair.sx &&
+          (glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph) ==
+           S_upstair ||
+           glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph) ==
+           S_upladder)) {
+               *p++ = '<';
+               *p++ = upstair.sx;
+       }
+       if (sstairs.sx &&
+          (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) ==
+           S_upstair ||
+           glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) ==
+           S_upladder)) {
+               *p++ = '<';
+               *p++ = sstairs.sx;
+       }
+
+       /* down stairway */
+       if (dnstair.sx &&
+          (glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph) ==
+           S_dnstair ||
+           glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph) ==
+           S_dnladder)) {
+               *p++ = '>';
+               *p++ = dnstair.sx;
+       }
+       if (sstairs.sx &&
+          (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) ==
+           S_dnstair ||
+           glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) ==
+           S_dnladder)) {
+               *p++ = '>';
+               *p++ = sstairs.sx;
+       }
+
+       /* hero location */
+       if (u.ux) {
+               *p++ = '@';
+               *p++ = u.ux;
+       }
+       /* fence post */
+       *p = 0;
+
+       update_positionbar(pbar);
+}
+#endif
+
+#endif /* OVLB */
+
+/*allmain.c*/
diff --git a/src/alloc.c b/src/alloc.c
new file mode 100644 (file)
index 0000000..e545eea
--- /dev/null
@@ -0,0 +1,144 @@
+/*     SCCS Id: @(#)alloc.c    3.4     1995/10/04      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* to get the malloc() prototype from system.h */
+#define ALLOC_C                /* comment line for pre-compiled headers */
+/* since this file is also used in auxiliary programs, don't include all the
+ * function declarations for all of nethack
+ */
+#define EXTERN_H       /* comment line for pre-compiled headers */
+#include "config.h"
+
+#if defined(MONITOR_HEAP) || defined(WIZARD)
+char *FDECL(fmt_ptr, (const genericptr,char *));
+#endif
+
+#ifdef MONITOR_HEAP
+#undef alloc
+#undef free
+extern void FDECL(free,(genericptr_t));
+static void NDECL(heapmon_init);
+
+static FILE *heaplog = 0;
+static boolean tried_heaplog = FALSE;
+#endif
+
+long *FDECL(alloc,(unsigned int));
+extern void VDECL(panic, (const char *,...)) PRINTF_F(1,2);
+
+
+long *
+alloc(lth)
+register unsigned int lth;
+{
+#ifdef LINT
+/*
+ * a ridiculous definition, suppressing
+ *     "possible pointer alignment problem" for (long *) malloc()
+ * from lint
+ */
+       long dummy = ftell(stderr);
+
+       if(lth) dummy = 0;      /* make sure arg is used */
+       return(&dummy);
+#else
+       register genericptr_t ptr;
+
+       ptr = malloc(lth);
+#ifndef MONITOR_HEAP
+       if (!ptr) panic("Memory allocation failure; cannot get %u bytes", lth);
+#endif
+       return((long *) ptr);
+#endif
+}
+
+
+#if defined(MONITOR_HEAP) || defined(WIZARD)
+
+# if defined(MICRO) || defined(WIN32)
+/* we actually want to know which systems have an ANSI run-time library
+ * to know which support the new %p format for printing pointers.
+ * due to the presence of things like gcc, NHSTDC is not a good test.
+ * so we assume microcomputers have all converted to ANSI and bigger
+ * computers which may have older libraries give reasonable results with
+ * the cast.
+ */
+#  define MONITOR_PTR_FMT
+# endif
+
+# ifdef MONITOR_PTR_FMT
+#  define PTR_FMT "%p"
+#  define PTR_TYP genericptr_t
+# else
+#  define PTR_FMT "%06lx"
+#  define PTR_TYP unsigned long
+# endif
+
+/* format a pointer for display purposes; caller supplies the result buffer */
+char *
+fmt_ptr(ptr, buf)
+const genericptr ptr;
+char *buf;
+{
+       Sprintf(buf, PTR_FMT, (PTR_TYP)ptr);
+       return buf;
+}
+
+#endif
+
+#ifdef MONITOR_HEAP
+
+/* If ${NH_HEAPLOG} is defined and we can create a file by that name,
+   then we'll log the allocation and release information to that file. */
+static void
+heapmon_init()
+{
+       char *logname = getenv("NH_HEAPLOG");
+
+       if (logname && *logname)
+               heaplog = fopen(logname, "w");
+       tried_heaplog = TRUE;
+}
+
+long *
+nhalloc(lth, file, line)
+unsigned int lth;
+const char *file;
+int line;
+{
+       long *ptr = alloc(lth);
+       char ptr_address[20];
+
+       if (!tried_heaplog) heapmon_init();
+       if (heaplog)
+               (void) fprintf(heaplog, "+%5u %s %4d %s\n", lth,
+                               fmt_ptr((genericptr_t)ptr, ptr_address),
+                               line, file);
+       /* potential panic in alloc() was deferred til here */
+       if (!ptr) panic("Cannot get %u bytes, line %d of %s",
+                       lth, line, file);
+
+       return ptr;
+}
+
+void
+nhfree(ptr, file, line)
+genericptr_t ptr;
+const char *file;
+int line;
+{
+       char ptr_address[20];
+
+       if (!tried_heaplog) heapmon_init();
+       if (heaplog)
+               (void) fprintf(heaplog, "-      %s %4d %s\n",
+                               fmt_ptr((genericptr_t)ptr, ptr_address),
+                               line, file);
+
+       free(ptr);
+}
+
+#endif /* MONITOR_HEAP */
+
+/*alloc.c*/
diff --git a/src/apply.c b/src/apply.c
new file mode 100644 (file)
index 0000000..f45e196
--- /dev/null
@@ -0,0 +1,3057 @@
+/*     SCCS Id: @(#)apply.c    3.4     2003/11/18      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "edog.h"
+
+#ifdef OVLB
+
+static const char tools[] = { TOOL_CLASS, WEAPON_CLASS, WAND_CLASS, 0 };
+static const char tools_too[] = { ALL_CLASSES, TOOL_CLASS, POTION_CLASS,
+                                 WEAPON_CLASS, WAND_CLASS, GEM_CLASS, 0 };
+
+#ifdef TOURIST
+STATIC_DCL int FDECL(use_camera, (struct obj *));
+#endif
+STATIC_DCL int FDECL(use_towel, (struct obj *));
+STATIC_DCL boolean FDECL(its_dead, (int,int,int *));
+STATIC_DCL int FDECL(use_stethoscope, (struct obj *));
+STATIC_DCL void FDECL(use_whistle, (struct obj *));
+STATIC_DCL void FDECL(use_magic_whistle, (struct obj *));
+STATIC_DCL void FDECL(use_leash, (struct obj *));
+STATIC_DCL int FDECL(use_mirror, (struct obj *));
+STATIC_DCL void FDECL(use_bell, (struct obj **));
+STATIC_DCL void FDECL(use_candelabrum, (struct obj *));
+STATIC_DCL void FDECL(use_candle, (struct obj **));
+STATIC_DCL void FDECL(use_lamp, (struct obj *));
+STATIC_DCL void FDECL(light_cocktail, (struct obj *));
+STATIC_DCL void FDECL(use_tinning_kit, (struct obj *));
+STATIC_DCL void FDECL(use_figurine, (struct obj **));
+STATIC_DCL void FDECL(use_grease, (struct obj *));
+STATIC_DCL void FDECL(use_trap, (struct obj *));
+STATIC_DCL void FDECL(use_stone, (struct obj *));
+STATIC_PTR int NDECL(set_trap);                /* occupation callback */
+STATIC_DCL int FDECL(use_whip, (struct obj *));
+STATIC_DCL int FDECL(use_pole, (struct obj *));
+STATIC_DCL int FDECL(use_cream_pie, (struct obj *));
+STATIC_DCL int FDECL(use_grapple, (struct obj *));
+STATIC_DCL int FDECL(do_break_wand, (struct obj *));
+STATIC_DCL boolean FDECL(figurine_location_checks,
+                               (struct obj *, coord *, BOOLEAN_P));
+STATIC_DCL boolean NDECL(uhave_graystone);
+STATIC_DCL void FDECL(add_class, (char *, CHAR_P));
+
+#ifdef AMIGA
+void FDECL( amii_speaker, ( struct obj *, char *, int ) );
+#endif
+
+static const char no_elbow_room[] = "don't have enough elbow-room to maneuver.";
+
+#ifdef TOURIST
+STATIC_OVL int
+use_camera(obj)
+       struct obj *obj;
+{
+       register struct monst *mtmp;
+
+       if(Underwater) {
+               pline("Using your camera underwater would void the warranty.");
+               return(0);
+       }
+       if(!getdir((char *)0)) return(0);
+
+       if (obj->spe <= 0) {
+               pline(nothing_happens);
+               return (1);
+       }
+       consume_obj_charge(obj, TRUE);
+
+       if (obj->cursed && !rn2(2)) {
+               (void) zapyourself(obj, TRUE);
+       } else if (u.uswallow) {
+               You("take a picture of %s %s.", s_suffix(mon_nam(u.ustuck)),
+                   mbodypart(u.ustuck, STOMACH));
+       } else if (u.dz) {
+               You("take a picture of the %s.",
+                       (u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy));
+       } else if (!u.dx && !u.dy) {
+               (void) zapyourself(obj, TRUE);
+       } else if ((mtmp = bhit(u.dx, u.dy, COLNO, FLASHED_LIGHT,
+                               (int FDECL((*),(MONST_P,OBJ_P)))0,
+                               (int FDECL((*),(OBJ_P,OBJ_P)))0,
+                               obj)) != 0) {
+               obj->ox = u.ux,  obj->oy = u.uy;
+               (void) flash_hits_mon(mtmp, obj);
+       }
+       return 1;
+}
+#endif
+
+STATIC_OVL int
+use_towel(obj)
+       struct obj *obj;
+{
+       if(!freehand()) {
+               You("have no free %s!", body_part(HAND));
+               return 0;
+       } else if (obj->owornmask) {
+               You("cannot use it while you're wearing it!");
+               return 0;
+       } else if (obj->cursed) {
+               long old;
+               switch (rn2(3)) {
+               case 2:
+                   old = Glib;
+                   Glib += rn1(10, 3);
+                   Your("%s %s!", makeplural(body_part(HAND)),
+                       (old ? "are filthier than ever" : "get slimy"));
+                   return 1;
+               case 1:
+                   if (!ublindf) {
+                       old = u.ucreamed;
+                       u.ucreamed += rn1(10, 3);
+                       pline("Yecch! Your %s %s gunk on it!", body_part(FACE),
+                             (old ? "has more" : "now has"));
+                       make_blinded(Blinded + (long)u.ucreamed - old, TRUE);
+                   } else {
+                       const char *what = (ublindf->otyp == LENSES) ?
+                                           "lenses" : "blindfold";
+                       if (ublindf->cursed) {
+                           You("push your %s %s.", what,
+                               rn2(2) ? "cock-eyed" : "crooked");
+                       } else {
+                           struct obj *saved_ublindf = ublindf;
+                           You("push your %s off.", what);
+                           Blindf_off(ublindf);
+                           dropx(saved_ublindf);
+                       }
+                   }
+                   return 1;
+               case 0:
+                   break;
+               }
+       }
+
+       if (Glib) {
+               Glib = 0;
+               You("wipe off your %s.", makeplural(body_part(HAND)));
+               return 1;
+       } else if(u.ucreamed) {
+               Blinded -= u.ucreamed;
+               u.ucreamed = 0;
+
+               if (!Blinded) {
+                       pline("You've got the glop off.");
+                       Blinded = 1;
+                       make_blinded(0L,TRUE);
+               } else {
+                       Your("%s feels clean now.", body_part(FACE));
+               }
+               return 1;
+       }
+
+       Your("%s and %s are already clean.",
+               body_part(FACE), makeplural(body_part(HAND)));
+
+       return 0;
+}
+
+/* maybe give a stethoscope message based on floor objects */
+STATIC_OVL boolean
+its_dead(rx, ry, resp)
+int rx, ry, *resp;
+{
+       struct obj *otmp;
+       struct trap *ttmp;
+
+       if (!can_reach_floor()) return FALSE;
+
+       /* additional stethoscope messages from jyoung@apanix.apana.org.au */
+       if (Hallucination && sobj_at(CORPSE, rx, ry)) {
+           /* (a corpse doesn't retain the monster's sex,
+              so we're forced to use generic pronoun here) */
+           You_hear("a voice say, \"It's dead, Jim.\"");
+           *resp = 1;
+           return TRUE;
+       } else if (Role_if(PM_HEALER) && ((otmp = sobj_at(CORPSE, rx, ry)) != 0 ||
+                                   (otmp = sobj_at(STATUE, rx, ry)) != 0)) {
+           /* possibly should check uppermost {corpse,statue} in the pile
+              if both types are present, but it's not worth the effort */
+           if (vobj_at(rx, ry)->otyp == STATUE) otmp = vobj_at(rx, ry);
+           if (otmp->otyp == CORPSE) {
+               You("determine that %s unfortunate being is dead.",
+                   (rx == u.ux && ry == u.uy) ? "this" : "that");
+           } else {
+               ttmp = t_at(rx, ry);
+               pline("%s appears to be in %s health for a statue.",
+                     The(mons[otmp->corpsenm].mname),
+                     (ttmp && ttmp->ttyp == STATUE_TRAP) ?
+                       "extraordinary" : "excellent");
+           }
+           return TRUE;
+       }
+       return FALSE;
+}
+
+static const char hollow_str[] = "a hollow sound.  This must be a secret %s!";
+
+/* Strictly speaking it makes no sense for usage of a stethoscope to
+   not take any time; however, unless it did, the stethoscope would be
+   almost useless.  As a compromise, one use per turn is free, another
+   uses up the turn; this makes curse status have a tangible effect. */
+STATIC_OVL int
+use_stethoscope(obj)
+       register struct obj *obj;
+{
+       static long last_used_move = -1;
+       static short last_used_movement = 0;
+       struct monst *mtmp;
+       struct rm *lev;
+       int rx, ry, res;
+       boolean interference = (u.uswallow && is_whirly(u.ustuck->data) &&
+                               !rn2(Role_if(PM_HEALER) ? 10 : 3));
+
+       if (nohands(youmonst.data)) {   /* should also check for no ears and/or deaf */
+               You("have no hands!");  /* not `body_part(HAND)' */
+               return 0;
+       } else if (!freehand()) {
+               You("have no free %s.", body_part(HAND));
+               return 0;
+       }
+       if (!getdir((char *)0)) return 0;
+
+       res = (moves == last_used_move) &&
+             (youmonst.movement == last_used_movement);
+       last_used_move = moves;
+       last_used_movement = youmonst.movement;
+
+#ifdef STEED
+       if (u.usteed && u.dz > 0) {
+               if (interference) {
+                       pline("%s interferes.", Monnam(u.ustuck));
+                       mstatusline(u.ustuck);
+               } else
+                       mstatusline(u.usteed);
+               return res;
+       } else
+#endif
+       if (u.uswallow && (u.dx || u.dy || u.dz)) {
+               mstatusline(u.ustuck);
+               return res;
+       } else if (u.uswallow && interference) {
+               pline("%s interferes.", Monnam(u.ustuck));
+               mstatusline(u.ustuck);
+               return res;
+       } else if (u.dz) {
+               if (Underwater)
+                   You_hear("faint splashing.");
+               else if (u.dz < 0 || !can_reach_floor())
+                   You_cant("reach the %s.",
+                       (u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy));
+               else if (its_dead(u.ux, u.uy, &res))
+                   ;   /* message already given */
+               else if (Is_stronghold(&u.uz))
+                   You_hear("the crackling of hellfire.");
+               else
+                   pline_The("%s seems healthy enough.", surface(u.ux,u.uy));
+               return res;
+       } else if (obj->cursed && !rn2(2)) {
+               You_hear("your heart beat.");
+               return res;
+       }
+       if (Stunned || (Confusion && !rn2(5))) confdir();
+       if (!u.dx && !u.dy) {
+               ustatusline();
+               return res;
+       }
+       rx = u.ux + u.dx; ry = u.uy + u.dy;
+       if (!isok(rx,ry)) {
+               You_hear("a faint typing noise.");
+               return 0;
+       }
+       if ((mtmp = m_at(rx,ry)) != 0) {
+               mstatusline(mtmp);
+               if (mtmp->mundetected) {
+                       mtmp->mundetected = 0;
+                       if (cansee(rx,ry)) newsym(mtmp->mx,mtmp->my);
+               }
+               if (!canspotmon(mtmp))
+                       map_invisible(rx,ry);
+               return res;
+       }
+       if (glyph_is_invisible(levl[rx][ry].glyph)) {
+               unmap_object(rx, ry);
+               newsym(rx, ry);
+               pline_The("invisible monster must have moved.");
+       }
+       lev = &levl[rx][ry];
+       switch(lev->typ) {
+       case SDOOR:
+               You_hear(hollow_str, "door");
+               cvt_sdoor_to_door(lev);         /* ->typ = DOOR */
+               if (Blind) feel_location(rx,ry);
+               else newsym(rx,ry);
+               return res;
+       case SCORR:
+               You_hear(hollow_str, "passage");
+               lev->typ = CORR;
+               unblock_point(rx,ry);
+               if (Blind) feel_location(rx,ry);
+               else newsym(rx,ry);
+               return res;
+       }
+
+       if (!its_dead(rx, ry, &res))
+           You("hear nothing special.");       /* not You_hear()  */
+       return res;
+}
+
+static const char whistle_str[] = "produce a %s whistling sound.";
+
+STATIC_OVL void
+use_whistle(obj)
+struct obj *obj;
+{
+       You(whistle_str, obj->cursed ? "shrill" : "high");
+       wake_nearby();
+}
+
+STATIC_OVL void
+use_magic_whistle(obj)
+struct obj *obj;
+{
+       register struct monst *mtmp, *nextmon;
+
+       if(obj->cursed && !rn2(2)) {
+               You("produce a high-pitched humming noise.");
+               wake_nearby();
+       } else {
+               int pet_cnt = 0;
+               You(whistle_str, Hallucination ? "normal" : "strange");
+               for(mtmp = fmon; mtmp; mtmp = nextmon) {
+                   nextmon = mtmp->nmon; /* trap might kill mon */
+                   if (DEADMONSTER(mtmp)) continue;
+                   if (mtmp->mtame) {
+                       if (mtmp->mtrapped) {
+                           /* no longer in previous trap (affects mintrap) */
+                           mtmp->mtrapped = 0;
+                           fill_pit(mtmp->mx, mtmp->my);
+                       }
+                       mnexto(mtmp);
+                       if (canspotmon(mtmp)) ++pet_cnt;
+                       if (mintrap(mtmp) == 2) change_luck(-1);
+                   }
+               }
+               if (pet_cnt > 0) makeknown(obj->otyp);
+       }
+}
+
+boolean
+um_dist(x,y,n)
+register xchar x, y, n;
+{
+       return((boolean)(abs(u.ux - x) > n  || abs(u.uy - y) > n));
+}
+
+int
+number_leashed()
+{
+       register int i = 0;
+       register struct obj *obj;
+
+       for(obj = invent; obj; obj = obj->nobj)
+               if(obj->otyp == LEASH && obj->leashmon != 0) i++;
+       return(i);
+}
+
+void
+o_unleash(otmp)                /* otmp is about to be destroyed or stolen */
+register struct obj *otmp;
+{
+       register struct monst *mtmp;
+
+       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+               if(mtmp->m_id == (unsigned)otmp->leashmon)
+                       mtmp->mleashed = 0;
+       otmp->leashmon = 0;
+}
+
+void
+m_unleash(mtmp, feedback)      /* mtmp is about to die, or become untame */
+register struct monst *mtmp;
+boolean feedback;
+{
+       register struct obj *otmp;
+
+       if (feedback) {
+           if (canseemon(mtmp))
+               pline("%s pulls free of %s leash!", Monnam(mtmp), mhis(mtmp));
+           else
+               Your("leash falls slack.");
+       }
+       for(otmp = invent; otmp; otmp = otmp->nobj)
+               if(otmp->otyp == LEASH &&
+                               otmp->leashmon == (int)mtmp->m_id)
+                       otmp->leashmon = 0;
+       mtmp->mleashed = 0;
+}
+
+void
+unleash_all()          /* player is about to die (for bones) */
+{
+       register struct obj *otmp;
+       register struct monst *mtmp;
+
+       for(otmp = invent; otmp; otmp = otmp->nobj)
+               if(otmp->otyp == LEASH) otmp->leashmon = 0;
+       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+               mtmp->mleashed = 0;
+}
+
+#define MAXLEASHED     2
+
+/* ARGSUSED */
+STATIC_OVL void
+use_leash(obj)
+struct obj *obj;
+{
+       coord cc;
+       register struct monst *mtmp;
+       int spotmon;
+
+       if(!obj->leashmon && number_leashed() >= MAXLEASHED) {
+               You("cannot leash any more pets.");
+               return;
+       }
+
+       if(!get_adjacent_loc((char *)0, (char *)0, u.ux, u.uy, &cc)) return;
+
+       if((cc.x == u.ux) && (cc.y == u.uy)) {
+#ifdef STEED
+               if (u.usteed && u.dz > 0) {
+                   mtmp = u.usteed;
+                   spotmon = 1;
+                   goto got_target;
+               }
+#endif
+               pline("Leash yourself?  Very funny...");
+               return;
+       }
+
+       if(!(mtmp = m_at(cc.x, cc.y))) {
+               There("is no creature there.");
+               return;
+       }
+
+       spotmon = canspotmon(mtmp);
+#ifdef STEED
+ got_target:
+#endif
+
+       if(!mtmp->mtame) {
+           if(!spotmon)
+               There("is no creature there.");
+           else
+               pline("%s %s leashed!", Monnam(mtmp), (!obj->leashmon) ?
+                               "cannot be" : "is not");
+           return;
+       }
+       if(!obj->leashmon) {
+               if(mtmp->mleashed) {
+                       pline("This %s is already leashed.",
+                             spotmon ? l_monnam(mtmp) : "monster");
+                       return;
+               }
+               You("slip the leash around %s%s.",
+                   spotmon ? "your " : "", l_monnam(mtmp));
+               mtmp->mleashed = 1;
+               obj->leashmon = (int)mtmp->m_id;
+               mtmp->msleeping = 0;
+               return;
+       }
+       if(obj->leashmon != (int)mtmp->m_id) {
+               pline("This leash is not attached to that creature.");
+               return;
+       } else {
+               if(obj->cursed) {
+                       pline_The("leash would not come off!");
+                       obj->bknown = TRUE;
+                       return;
+               }
+               mtmp->mleashed = 0;
+               obj->leashmon = 0;
+               You("remove the leash from %s%s.",
+                   spotmon ? "your " : "", l_monnam(mtmp));
+       }
+       return;
+}
+
+struct obj *
+get_mleash(mtmp)       /* assuming mtmp->mleashed has been checked */
+register struct monst *mtmp;
+{
+       register struct obj *otmp;
+
+       otmp = invent;
+       while(otmp) {
+               if(otmp->otyp == LEASH && otmp->leashmon == (int)mtmp->m_id)
+                       return(otmp);
+               otmp = otmp->nobj;
+       }
+       return((struct obj *)0);
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+boolean
+next_to_u()
+{
+       register struct monst *mtmp;
+       register struct obj *otmp;
+
+       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+               if (DEADMONSTER(mtmp)) continue;
+               if(mtmp->mleashed) {
+                       if (distu(mtmp->mx,mtmp->my) > 2) mnexto(mtmp);
+                       if (distu(mtmp->mx,mtmp->my) > 2) {
+                           for(otmp = invent; otmp; otmp = otmp->nobj)
+                               if(otmp->otyp == LEASH &&
+                                       otmp->leashmon == (int)mtmp->m_id) {
+                                   if(otmp->cursed) return(FALSE);
+                                   You_feel("%s leash go slack.",
+                                       (number_leashed() > 1) ? "a" : "the");
+                                   mtmp->mleashed = 0;
+                                   otmp->leashmon = 0;
+                               }
+                       }
+               }
+       }
+#ifdef STEED
+       /* no pack mules for the Amulet */
+       if (u.usteed && mon_has_amulet(u.usteed)) return FALSE;
+#endif
+       return(TRUE);
+}
+
+#endif /* OVL1 */
+#ifdef OVL0
+
+void
+check_leash(x, y)
+register xchar x, y;
+{
+       register struct obj *otmp;
+       register struct monst *mtmp;
+
+       for (otmp = invent; otmp; otmp = otmp->nobj) {
+           if (otmp->otyp != LEASH || otmp->leashmon == 0) continue;
+           for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+               if (DEADMONSTER(mtmp)) continue;
+               if ((int)mtmp->m_id == otmp->leashmon) break; 
+           }
+           if (!mtmp) {
+               impossible("leash in use isn't attached to anything?");
+               otmp->leashmon = 0;
+               continue;
+           }
+           if (dist2(u.ux,u.uy,mtmp->mx,mtmp->my) >
+                   dist2(x,y,mtmp->mx,mtmp->my)) {
+               if (!um_dist(mtmp->mx, mtmp->my, 3)) {
+                   ;   /* still close enough */
+               } else if (otmp->cursed && !breathless(mtmp->data)) {
+                   if (um_dist(mtmp->mx, mtmp->my, 5) ||
+                           (mtmp->mhp -= rnd(2)) <= 0) {
+                       long save_pacifism = u.uconduct.killer;
+
+                       Your("leash chokes %s to death!", mon_nam(mtmp));
+                       /* hero might not have intended to kill pet, but
+                          that's the result of his actions; gain experience,
+                          lose pacifism, take alignment and luck hit, make
+                          corpse less likely to remain tame after revival */
+                       xkilled(mtmp, 0);       /* no "you kill it" message */
+                       /* life-saving doesn't ordinarily reset this */
+                       if (mtmp->mhp > 0) u.uconduct.killer = save_pacifism;
+                   } else {
+                       pline("%s chokes on the leash!", Monnam(mtmp));
+                       /* tameness eventually drops to 1 here (never 0) */
+                       if (mtmp->mtame && rn2(mtmp->mtame)) mtmp->mtame--;
+                   }
+               } else {
+                   if (um_dist(mtmp->mx, mtmp->my, 5)) {
+                       pline("%s leash snaps loose!", s_suffix(Monnam(mtmp)));
+                       m_unleash(mtmp, FALSE);
+                   } else {
+                       You("pull on the leash.");
+                       if (mtmp->data->msound != MS_SILENT)
+                           switch (rn2(3)) {
+                           case 0:  growl(mtmp);   break;
+                           case 1:  yelp(mtmp);    break;
+                           default: whimper(mtmp); break;
+                           }
+                   }
+               }
+           }
+       }
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+#define WEAK   3       /* from eat.c */
+
+static const char look_str[] = "look %s.";
+
+STATIC_OVL int
+use_mirror(obj)
+struct obj *obj;
+{
+       register struct monst *mtmp;
+       register char mlet;
+       boolean vis;
+
+       if(!getdir((char *)0)) return 0;
+       if(obj->cursed && !rn2(2)) {
+               if (!Blind)
+                       pline_The("mirror fogs up and doesn't reflect!");
+               return 1;
+       }
+       if(!u.dx && !u.dy && !u.dz) {
+               if(!Blind && !Invisible) {
+                   if (u.umonnum == PM_FLOATING_EYE) {
+                       if (!Free_action) {
+                       pline(Hallucination ?
+                             "Yow!  The mirror stares back!" :
+                             "Yikes!  You've frozen yourself!");
+                       nomul(-rnd((MAXULEV+6) - u.ulevel));
+                       } else You("stiffen momentarily under your gaze.");
+                   } else if (youmonst.data->mlet == S_VAMPIRE)
+                       You("don't have a reflection.");
+                   else if (u.umonnum == PM_UMBER_HULK) {
+                       pline("Huh?  That doesn't look like you!");
+                       make_confused(HConfusion + d(3,4),FALSE);
+                   } else if (Hallucination)
+                       You(look_str, hcolor((char *)0));
+                   else if (Sick)
+                       You(look_str, "peaked");
+                   else if (u.uhs >= WEAK)
+                       You(look_str, "undernourished");
+                   else You("look as %s as ever.",
+                               ACURR(A_CHA) > 14 ?
+                               (poly_gender()==1 ? "beautiful" : "handsome") :
+                               "ugly");
+               } else {
+                       You_cant("see your %s %s.",
+                               ACURR(A_CHA) > 14 ?
+                               (poly_gender()==1 ? "beautiful" : "handsome") :
+                               "ugly",
+                               body_part(FACE));
+               }
+               return 1;
+       }
+       if(u.uswallow) {
+               if (!Blind) You("reflect %s %s.", s_suffix(mon_nam(u.ustuck)),
+                   mbodypart(u.ustuck, STOMACH));
+               return 1;
+       }
+       if(Underwater) {
+               You(Hallucination ?
+                   "give the fish a chance to fix their makeup." :
+                   "reflect the murky water.");
+               return 1;
+       }
+       if(u.dz) {
+               if (!Blind)
+                   You("reflect the %s.",
+                       (u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy));
+               return 1;
+       }
+       mtmp = bhit(u.dx, u.dy, COLNO, INVIS_BEAM,
+                   (int FDECL((*),(MONST_P,OBJ_P)))0,
+                   (int FDECL((*),(OBJ_P,OBJ_P)))0,
+                   obj);
+       if (!mtmp || !haseyes(mtmp->data))
+               return 1;
+
+       vis = canseemon(mtmp);
+       mlet = mtmp->data->mlet;
+       if (mtmp->msleeping) {
+               if (vis)
+                   pline ("%s is too tired to look at your mirror.",
+                           Monnam(mtmp));
+       } else if (!mtmp->mcansee) {
+           if (vis)
+               pline("%s can't see anything right now.", Monnam(mtmp));
+       /* some monsters do special things */
+       } else if (mlet == S_VAMPIRE || mlet == S_GHOST) {
+           if (vis)
+               pline ("%s doesn't have a reflection.", Monnam(mtmp));
+       } else if(!mtmp->mcan && !mtmp->minvis &&
+                                       mtmp->data == &mons[PM_MEDUSA]) {
+               if (mon_reflects(mtmp, "The gaze is reflected away by %s %s!"))
+                       return 1;
+               if (vis)
+                       pline("%s is turned to stone!", Monnam(mtmp));
+               stoned = TRUE;
+               killed(mtmp);
+       } else if(!mtmp->mcan && !mtmp->minvis &&
+                                       mtmp->data == &mons[PM_FLOATING_EYE]) {
+               int tmp = d((int)mtmp->m_lev, (int)mtmp->data->mattk[0].damd);
+               if (!rn2(4)) tmp = 120;
+               if (vis)
+                       pline("%s is frozen by its reflection.", Monnam(mtmp));
+               else You_hear("%s stop moving.",something);
+               mtmp->mcanmove = 0;
+               if ( (int) mtmp->mfrozen + tmp > 127)
+                       mtmp->mfrozen = 127;
+               else mtmp->mfrozen += tmp;
+       } else if(!mtmp->mcan && !mtmp->minvis &&
+                                       mtmp->data == &mons[PM_UMBER_HULK]) {
+               if (vis)
+                       pline ("%s confuses itself!", Monnam(mtmp));
+               mtmp->mconf = 1;
+       } else if(!mtmp->mcan && !mtmp->minvis && (mlet == S_NYMPH
+                                    || mtmp->data==&mons[PM_SUCCUBUS])) {
+               if (vis) {
+                   pline ("%s admires herself in your mirror.", Monnam(mtmp));
+                   pline ("She takes it!");
+               } else pline ("It steals your mirror!");
+               setnotworn(obj); /* in case mirror was wielded */
+               freeinv(obj);
+               (void) mpickobj(mtmp,obj);
+               if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
+       } else if (!is_unicorn(mtmp->data) && !humanoid(mtmp->data) &&
+                       (!mtmp->minvis || perceives(mtmp->data)) && rn2(5)) {
+               if (vis)
+                   pline("%s is frightened by its reflection.", Monnam(mtmp));
+               monflee(mtmp, d(2,4), FALSE, FALSE);
+       } else if (!Blind) {
+               if (mtmp->minvis && !See_invisible)
+                   ;
+               else if ((mtmp->minvis && !perceives(mtmp->data))
+                        || !haseyes(mtmp->data))
+                   pline("%s doesn't seem to notice its reflection.",
+                       Monnam(mtmp));
+               else
+                   pline("%s ignores %s reflection.",
+                         Monnam(mtmp), mhis(mtmp));
+       }
+       return 1;
+}
+
+STATIC_OVL void
+use_bell(optr)
+struct obj **optr;
+{
+       register struct obj *obj = *optr;
+       struct monst *mtmp;
+       boolean wakem = FALSE, learno = FALSE,
+               ordinary = (obj->otyp != BELL_OF_OPENING || !obj->spe),
+               invoking = (obj->otyp == BELL_OF_OPENING &&
+                        invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy));
+
+       You("ring %s.", the(xname(obj)));
+
+       if (Underwater || (u.uswallow && ordinary)) {
+#ifdef AMIGA
+           amii_speaker( obj, "AhDhGqEqDhEhAqDqFhGw", AMII_MUFFLED_VOLUME );
+#endif
+           pline("But the sound is muffled.");
+
+       } else if (invoking && ordinary) {
+           /* needs to be recharged... */
+           pline("But it makes no sound.");
+           learno = TRUE;      /* help player figure out why */
+
+       } else if (ordinary) {
+#ifdef AMIGA
+           amii_speaker( obj, "ahdhgqeqdhehaqdqfhgw", AMII_MUFFLED_VOLUME );
+#endif
+           if (obj->cursed && !rn2(4) &&
+                   /* note: once any of them are gone, we stop all of them */
+                   !(mvitals[PM_WOOD_NYMPH].mvflags & G_GONE) &&
+                   !(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) &&
+                   !(mvitals[PM_MOUNTAIN_NYMPH].mvflags & G_GONE) &&
+                   (mtmp = makemon(mkclass(S_NYMPH, 0),
+                                       u.ux, u.uy, NO_MINVENT)) != 0) {
+               You("summon %s!", a_monnam(mtmp));
+               if (!obj_resists(obj, 93, 100)) {
+                   pline("%s shattered!", Tobjnam(obj, "have"));
+                   useup(obj);
+                   *optr = 0;
+               } else switch (rn2(3)) {
+                       default:
+                               break;
+                       case 1:
+                               mon_adjust_speed(mtmp, 2, (struct obj *)0);
+                               break;
+                       case 2: /* no explanation; it just happens... */
+                               nomovemsg = "";
+                               nomul(-rnd(2));
+                               break;
+               }
+           }
+           wakem = TRUE;
+
+       } else {
+           /* charged Bell of Opening */
+           consume_obj_charge(obj, TRUE);
+
+           if (u.uswallow) {
+               if (!obj->cursed)
+                   (void) openit();
+               else
+                   pline(nothing_happens);
+
+           } else if (obj->cursed) {
+               coord mm;
+
+               mm.x = u.ux;
+               mm.y = u.uy;
+               mkundead(&mm, FALSE, NO_MINVENT);
+               wakem = TRUE;
+
+           } else  if (invoking) {
+               pline("%s an unsettling shrill sound...",
+                     Tobjnam(obj, "issue"));
+#ifdef AMIGA
+               amii_speaker( obj, "aefeaefeaefeaefeaefe", AMII_LOUDER_VOLUME );
+#endif
+               obj->age = moves;
+               learno = TRUE;
+               wakem = TRUE;
+
+           } else if (obj->blessed) {
+               int res = 0;
+
+#ifdef AMIGA
+               amii_speaker( obj, "ahahahDhEhCw", AMII_SOFT_VOLUME );
+#endif
+               if (uchain) {
+                   unpunish();
+                   res = 1;
+               }
+               res += openit();
+               switch (res) {
+                 case 0:  pline(nothing_happens); break;
+                 case 1:  pline("%s opens...", Something);
+                          learno = TRUE; break;
+                 default: pline("Things open around you...");
+                          learno = TRUE; break;
+               }
+
+           } else {  /* uncursed */
+#ifdef AMIGA
+               amii_speaker( obj, "AeFeaeFeAefegw", AMII_OKAY_VOLUME );
+#endif
+               if (findit() != 0) learno = TRUE;
+               else pline(nothing_happens);
+           }
+
+       }       /* charged BofO */
+
+       if (learno) {
+           makeknown(BELL_OF_OPENING);
+           obj->known = 1;
+       }
+       if (wakem) wake_nearby();
+}
+
+STATIC_OVL void
+use_candelabrum(obj)
+register struct obj *obj;
+{
+       const char *s = (obj->spe != 1) ? "candles" : "candle";
+
+       if(Underwater) {
+               You("cannot make fire under water.");
+               return;
+       }
+       if(obj->lamplit) {
+               You("snuff the %s.", s);
+               end_burn(obj, TRUE);
+               return;
+       }
+       if(obj->spe <= 0) {
+               pline("This %s has no %s.", xname(obj), s);
+               return;
+       }
+       if(u.uswallow || obj->cursed) {
+               if (!Blind)
+                   pline_The("%s %s for a moment, then %s.",
+                             s, vtense(s, "flicker"), vtense(s, "die"));
+               return;
+       }
+       if(obj->spe < 7) {
+               There("%s only %d %s in %s.",
+                     vtense(s, "are"), obj->spe, s, the(xname(obj)));
+               if (!Blind)
+                   pline("%s lit.  %s dimly.",
+                         obj->spe == 1 ? "It is" : "They are",
+                         Tobjnam(obj, "shine"));
+       } else {
+               pline("%s's %s burn%s", The(xname(obj)), s,
+                       (Blind ? "." : " brightly!"));
+       }
+       if (!invocation_pos(u.ux, u.uy)) {
+               pline_The("%s %s being rapidly consumed!", s, vtense(s, "are"));
+               obj->age /= 2;
+       } else {
+               if(obj->spe == 7) {
+                   if (Blind)
+                     pline("%s a strange warmth!", Tobjnam(obj, "radiate"));
+                   else
+                     pline("%s with a strange light!", Tobjnam(obj, "glow"));
+               }
+               obj->known = 1;
+       }
+       begin_burn(obj, FALSE);
+}
+
+STATIC_OVL void
+use_candle(optr)
+struct obj **optr;
+{
+       register struct obj *obj = *optr;
+       register struct obj *otmp;
+       const char *s = (obj->quan != 1) ? "candles" : "candle";
+       char qbuf[QBUFSZ];
+
+       if(u.uswallow) {
+               You(no_elbow_room);
+               return;
+       }
+       if(Underwater) {
+               pline("Sorry, fire and water don't mix.");
+               return;
+       }
+
+       otmp = carrying(CANDELABRUM_OF_INVOCATION);
+       if(!otmp || otmp->spe == 7) {
+               use_lamp(obj);
+               return;
+       }
+
+       Sprintf(qbuf, "Attach %s", the(xname(obj)));
+       Sprintf(eos(qbuf), " to %s?",
+               safe_qbuf(qbuf, sizeof(" to ?"), the(xname(otmp)),
+                       the(simple_typename(otmp->otyp)), "it"));
+       if(yn(qbuf) == 'n') {
+               if (!obj->lamplit)
+                   You("try to light %s...", the(xname(obj)));
+               use_lamp(obj);
+               return;
+       } else {
+               if ((long)otmp->spe + obj->quan > 7L)
+                   obj = splitobj(obj, 7L - (long)otmp->spe);
+               else *optr = 0;
+               You("attach %ld%s %s to %s.",
+                   obj->quan, !otmp->spe ? "" : " more",
+                   s, the(xname(otmp)));
+               if (!otmp->spe || otmp->age > obj->age)
+                   otmp->age = obj->age;
+               otmp->spe += (int)obj->quan;
+               if (otmp->lamplit && !obj->lamplit)
+                   pline_The("new %s magically %s!", s, vtense(s, "ignite"));
+               else if (!otmp->lamplit && obj->lamplit)
+                   pline("%s out.", (obj->quan > 1L) ? "They go" : "It goes");
+               if (obj->unpaid)
+                   verbalize("You %s %s, you bought %s!",
+                             otmp->lamplit ? "burn" : "use",
+                             (obj->quan > 1L) ? "them" : "it",
+                             (obj->quan > 1L) ? "them" : "it");
+               if (obj->quan < 7L && otmp->spe == 7)
+                   pline("%s now has seven%s candles attached.",
+                         The(xname(otmp)), otmp->lamplit ? " lit" : "");
+               /* candelabrum's light range might increase */
+               if (otmp->lamplit) obj_merge_light_sources(otmp, otmp);
+               /* candles are no longer a separate light source */
+               if (obj->lamplit) end_burn(obj, TRUE);
+               /* candles are now gone */
+               useupall(obj);
+       }
+}
+
+boolean
+snuff_candle(otmp)  /* call in drop, throw, and put in box, etc. */
+register struct obj *otmp;
+{
+       register boolean candle = Is_candle(otmp);
+
+       if ((candle || otmp->otyp == CANDELABRUM_OF_INVOCATION) &&
+               otmp->lamplit) {
+           char buf[BUFSZ];
+           xchar x, y;
+           register boolean many = candle ? otmp->quan > 1L : otmp->spe > 1;
+
+           (void) get_obj_location(otmp, &x, &y, 0);
+           if (otmp->where == OBJ_MINVENT ? cansee(x,y) : !Blind)
+               pline("%s %scandle%s flame%s extinguished.",
+                     Shk_Your(buf, otmp),
+                     (candle ? "" : "candelabrum's "),
+                     (many ? "s'" : "'s"), (many ? "s are" : " is"));
+          end_burn(otmp, TRUE);
+          return(TRUE);
+       }
+       return(FALSE);
+}
+
+/* called when lit lamp is hit by water or put into a container or
+   you've been swallowed by a monster; obj might be in transit while
+   being thrown or dropped so don't assume that its location is valid */
+boolean
+snuff_lit(obj)
+struct obj *obj;
+{
+       xchar x, y;
+
+       if (obj->lamplit) {
+           if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
+                   obj->otyp == BRASS_LANTERN || obj->otyp == POT_OIL) {
+               (void) get_obj_location(obj, &x, &y, 0);
+               if (obj->where == OBJ_MINVENT ? cansee(x,y) : !Blind)
+                   pline("%s %s out!", Yname2(obj), otense(obj, "go"));
+               end_burn(obj, TRUE);
+               return TRUE;
+           }
+           if (snuff_candle(obj)) return TRUE;
+       }
+       return FALSE;
+}
+
+/* Called when potentially lightable object is affected by fire_damage().
+   Return TRUE if object was lit and FALSE otherwise --ALI */
+boolean
+catch_lit(obj)
+struct obj *obj;
+{
+       xchar x, y;
+
+       if (!obj->lamplit && (obj->otyp == MAGIC_LAMP || ignitable(obj))) {
+           if ((obj->otyp == MAGIC_LAMP ||
+                obj->otyp == CANDELABRUM_OF_INVOCATION) &&
+               obj->spe == 0)
+               return FALSE;
+           else if (obj->otyp != MAGIC_LAMP && obj->age == 0)
+               return FALSE;
+           if (!get_obj_location(obj, &x, &y, 0))
+               return FALSE;
+           if (obj->otyp == CANDELABRUM_OF_INVOCATION && obj->cursed)
+               return FALSE;
+           if ((obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
+                obj->otyp == BRASS_LANTERN) && obj->cursed && !rn2(2))
+               return FALSE;
+           if (obj->where == OBJ_MINVENT ? cansee(x,y) : !Blind)
+               pline("%s %s light!", Yname2(obj), otense(obj, "catch"));
+           if (obj->otyp == POT_OIL) makeknown(obj->otyp);
+           if (obj->unpaid && costly_spot(u.ux, u.uy) && (obj->where == OBJ_INVENT)) {
+               /* if it catches while you have it, then it's your tough luck */
+               check_unpaid(obj);
+               verbalize("That's in addition to the cost of %s %s, of course.",
+                               Yname2(obj), obj->quan == 1 ? "itself" : "themselves");
+               bill_dummy_object(obj);
+           }
+           begin_burn(obj, FALSE);
+           return TRUE;
+       }
+       return FALSE;
+}
+
+STATIC_OVL void
+use_lamp(obj)
+struct obj *obj;
+{
+       char buf[BUFSZ];
+
+       if(Underwater) {
+               pline("This is not a diving lamp.");
+               return;
+       }
+       if(obj->lamplit) {
+               if(obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
+                               obj->otyp == BRASS_LANTERN)
+                   pline("%s lamp is now off.", Shk_Your(buf, obj));
+               else
+                   You("snuff out %s.", yname(obj));
+               end_burn(obj, TRUE);
+               return;
+       }
+       /* magic lamps with an spe == 0 (wished for) cannot be lit */
+       if ((!Is_candle(obj) && obj->age == 0)
+                       || (obj->otyp == MAGIC_LAMP && obj->spe == 0)) {
+               if (obj->otyp == BRASS_LANTERN)
+                       Your("lamp has run out of power.");
+               else pline("This %s has no oil.", xname(obj));
+               return;
+       }
+       if (obj->cursed && !rn2(2)) {
+               pline("%s for a moment, then %s.",
+                     Tobjnam(obj, "flicker"), otense(obj, "die"));
+       } else {
+               if(obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
+                               obj->otyp == BRASS_LANTERN) {
+                   check_unpaid(obj);
+                   pline("%s lamp is now on.", Shk_Your(buf, obj));
+               } else {        /* candle(s) */
+                   pline("%s flame%s %s%s",
+                       s_suffix(Yname2(obj)),
+                       plur(obj->quan), otense(obj, "burn"),
+                       Blind ? "." : " brightly!");
+                   if (obj->unpaid && costly_spot(u.ux, u.uy) &&
+                         obj->age == 20L * (long)objects[obj->otyp].oc_cost) {
+                       const char *ithem = obj->quan > 1L ? "them" : "it";
+                       verbalize("You burn %s, you bought %s!", ithem, ithem);
+                       bill_dummy_object(obj);
+                   }
+               }
+               begin_burn(obj, FALSE);
+       }
+}
+
+STATIC_OVL void
+light_cocktail(obj)
+       struct obj *obj;        /* obj is a potion of oil */
+{
+       char buf[BUFSZ];
+
+       if (u.uswallow) {
+           You(no_elbow_room);
+           return;
+       }
+
+       if (obj->lamplit) {
+           You("snuff the lit potion.");
+           end_burn(obj, TRUE);
+           /*
+            * Free & add to re-merge potion.  This will average the
+            * age of the potions.  Not exactly the best solution,
+            * but its easy.
+            */
+           freeinv(obj);
+           (void) addinv(obj);
+           return;
+       } else if (Underwater) {
+           There("is not enough oxygen to sustain a fire.");
+           return;
+       }
+
+       You("light %s potion.%s", shk_your(buf, obj),
+           Blind ? "" : "  It gives off a dim light.");
+       if (obj->unpaid && costly_spot(u.ux, u.uy)) {
+           /* Normally, we shouldn't both partially and fully charge
+            * for an item, but (Yendorian Fuel) Taxes are inevitable...
+            */
+           check_unpaid(obj);
+           verbalize("That's in addition to the cost of the potion, of course.");
+           bill_dummy_object(obj);
+       }
+       makeknown(obj->otyp);
+
+       if (obj->quan > 1L) {
+           obj = splitobj(obj, 1L);
+           begin_burn(obj, FALSE);     /* burn before free to get position */
+           obj_extract_self(obj);      /* free from inv */
+
+           /* shouldn't merge */
+           obj = hold_another_object(obj, "You drop %s!",
+                                     doname(obj), (const char *)0);
+       } else
+           begin_burn(obj, FALSE);
+}
+
+static NEARDATA const char cuddly[] = { TOOL_CLASS, GEM_CLASS, 0 };
+
+int
+dorub()
+{
+       struct obj *obj = getobj(cuddly, "rub");
+
+       if (obj && obj->oclass == GEM_CLASS) {
+           if (is_graystone(obj)) {
+               use_stone(obj);
+               return 1;
+           } else {
+               pline("Sorry, I don't know how to use that.");
+               return 0;
+           }
+       }
+
+       if (!obj || !wield_tool(obj, "rub")) return 0;
+
+       /* now uwep is obj */
+       if (uwep->otyp == MAGIC_LAMP) {
+           if (uwep->spe > 0 && !rn2(3)) {
+               check_unpaid_usage(uwep, TRUE);         /* unusual item use */
+               djinni_from_bottle(uwep);
+               makeknown(MAGIC_LAMP);
+               uwep->otyp = OIL_LAMP;
+               uwep->spe = 0; /* for safety */
+               uwep->age = rn1(500,1000);
+               if (uwep->lamplit) begin_burn(uwep, TRUE);
+               update_inventory();
+           } else if (rn2(2) && !Blind)
+               You("see a puff of smoke.");
+           else pline(nothing_happens);
+       } else if (obj->otyp == BRASS_LANTERN) {
+           /* message from Adventure */
+           pline("Rubbing the electric lamp is not particularly rewarding.");
+           pline("Anyway, nothing exciting happens.");
+       } else pline(nothing_happens);
+       return 1;
+}
+
+int
+dojump()
+{
+       /* Physical jump */
+       return jump(0);
+}
+
+int
+jump(magic)
+int magic; /* 0=Physical, otherwise skill level */
+{
+       coord cc;
+
+       if (!magic && (nolimbs(youmonst.data) || slithy(youmonst.data))) {
+               /* normally (nolimbs || slithy) implies !Jumping,
+                  but that isn't necessarily the case for knights */
+               You_cant("jump; you have no legs!");
+               return 0;
+       } else if (!magic && !Jumping) {
+               You_cant("jump very far.");
+               return 0;
+       } else if (u.uswallow) {
+               if (magic) {
+                       You("bounce around a little.");
+                       return 1;
+               }
+               pline("You've got to be kidding!");
+               return 0;
+       } else if (u.uinwater) {
+               if (magic) {
+                       You("swish around a little.");
+                       return 1;
+               }
+               pline("This calls for swimming, not jumping!");
+               return 0;
+       } else if (u.ustuck) {
+               if (u.ustuck->mtame && !Conflict && !u.ustuck->mconf) {
+                   You("pull free from %s.", mon_nam(u.ustuck));
+                   u.ustuck = 0;
+                   return 1;
+               }
+               if (magic) {
+                       You("writhe a little in the grasp of %s!", mon_nam(u.ustuck));
+                       return 1;
+               }
+               You("cannot escape from %s!", mon_nam(u.ustuck));
+               return 0;
+       } else if (Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
+               if (magic) {
+                       You("flail around a little.");
+                       return 1;
+               }
+               You("don't have enough traction to jump.");
+               return 0;
+       } else if (!magic && near_capacity() > UNENCUMBERED) {
+               You("are carrying too much to jump!");
+               return 0;
+       } else if (!magic && (u.uhunger <= 100 || ACURR(A_STR) < 6)) {
+               You("lack the strength to jump!");
+               return 0;
+       } else if (Wounded_legs) {
+               long wl = (Wounded_legs & BOTH_SIDES);
+               const char *bp = body_part(LEG);
+
+               if (wl == BOTH_SIDES) bp = makeplural(bp);
+#ifdef STEED
+               if (u.usteed)
+                   pline("%s is in no shape for jumping.", Monnam(u.usteed));
+               else
+#endif
+               Your("%s%s %s in no shape for jumping.",
+                    (wl == LEFT_SIDE) ? "left " :
+                       (wl == RIGHT_SIDE) ? "right " : "",
+                    bp, (wl == BOTH_SIDES) ? "are" : "is");
+               return 0;
+       }
+#ifdef STEED
+       else if (u.usteed && u.utrap) {
+               pline("%s is stuck in a trap.", Monnam(u.usteed));
+               return (0);
+       }
+#endif
+
+       pline("Where do you want to jump?");
+       cc.x = u.ux;
+       cc.y = u.uy;
+       if (getpos(&cc, TRUE, "the desired position") < 0)
+               return 0;       /* user pressed ESC */
+       if (!magic && !(HJumping & ~INTRINSIC) && !EJumping &&
+                       distu(cc.x, cc.y) != 5) {
+               /* The Knight jumping restriction still applies when riding a
+                * horse.  After all, what shape is the knight piece in chess?
+                */
+               pline("Illegal move!");
+               return 0;
+       } else if (distu(cc.x, cc.y) > (magic ? 6+magic*3 : 9)) {
+               pline("Too far!");
+               return 0;
+       } else if (!cansee(cc.x, cc.y)) {
+               You("cannot see where to land!");
+               return 0;
+       } else if (!isok(cc.x, cc.y)) {
+               You("cannot jump there!");
+               return 0;
+       } else {
+           coord uc;
+           int range, temp;
+
+           if(u.utrap)
+               switch(u.utraptype) {
+               case TT_BEARTRAP: {
+                   register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
+                   You("rip yourself free of the bear trap!  Ouch!");
+                   losehp(rnd(10), "jumping out of a bear trap", KILLED_BY);
+                   set_wounded_legs(side, rn1(1000,500));
+                   break;
+                 }
+               case TT_PIT:
+                   You("leap from the pit!");
+                   break;
+               case TT_WEB:
+                   You("tear the web apart as you pull yourself free!");
+                   deltrap(t_at(u.ux,u.uy));
+                   break;
+               case TT_LAVA:
+                   You("pull yourself above the lava!");
+                   u.utrap = 0;
+                   return 1;
+               case TT_INFLOOR:
+                   You("strain your %s, but you're still stuck in the floor.",
+                       makeplural(body_part(LEG)));
+                   set_wounded_legs(LEFT_SIDE, rn1(10, 11));
+                   set_wounded_legs(RIGHT_SIDE, rn1(10, 11));
+                   return 1;
+               }
+
+           /*
+            * Check the path from uc to cc, calling hurtle_step at each
+            * location.  The final position actually reached will be
+            * in cc.
+            */
+           uc.x = u.ux;
+           uc.y = u.uy;
+           /* calculate max(abs(dx), abs(dy)) as the range */
+           range = cc.x - uc.x;
+           if (range < 0) range = -range;
+           temp = cc.y - uc.y;
+           if (temp < 0) temp = -temp;
+           if (range < temp)
+               range = temp;
+           (void) walk_path(&uc, &cc, hurtle_step, (genericptr_t)&range);
+
+           /* A little Sokoban guilt... */
+           if (In_sokoban(&u.uz))
+               change_luck(-1);
+
+           teleds(cc.x, cc.y, TRUE);
+           nomul(-1);
+           nomovemsg = "";
+           morehungry(rnd(25));
+           return 1;
+       }
+}
+
+boolean
+tinnable(corpse)
+struct obj *corpse;
+{
+       if (corpse->oeaten) return 0;
+       if (!mons[corpse->corpsenm].cnutrit) return 0;
+       return 1;
+}
+
+STATIC_OVL void
+use_tinning_kit(obj)
+register struct obj *obj;
+{
+       register struct obj *corpse, *can;
+
+       /* This takes only 1 move.  If this is to be changed to take many
+        * moves, we've got to deal with decaying corpses...
+        */
+       if (obj->spe <= 0) {
+               You("seem to be out of tins.");
+               return;
+       }
+       if (!(corpse = floorfood("tin", 2))) return;
+       if (corpse->oeaten) {
+               You("cannot tin %s which is partly eaten.",something);
+               return;
+       }
+       if (touch_petrifies(&mons[corpse->corpsenm])
+               && !Stone_resistance && !uarmg) {
+           char kbuf[BUFSZ];
+
+           if (poly_when_stoned(youmonst.data))
+               You("tin %s without wearing gloves.",
+                       an(mons[corpse->corpsenm].mname));
+           else {
+               pline("Tinning %s without wearing gloves is a fatal mistake...",
+                       an(mons[corpse->corpsenm].mname));
+               Sprintf(kbuf, "trying to tin %s without gloves",
+                       an(mons[corpse->corpsenm].mname));
+           }
+           instapetrify(kbuf);
+       }
+       if (is_rider(&mons[corpse->corpsenm])) {
+               (void) revive_corpse(corpse);
+               verbalize("Yes...  But War does not preserve its enemies...");
+               return;
+       }
+       if (mons[corpse->corpsenm].cnutrit == 0) {
+               pline("That's too insubstantial to tin.");
+               return;
+       }
+       consume_obj_charge(obj, TRUE);
+
+       if ((can = mksobj(TIN, FALSE, FALSE)) != 0) {
+           static const char you_buy_it[] = "You tin it, you bought it!";
+
+           can->corpsenm = corpse->corpsenm;
+           can->cursed = obj->cursed;
+           can->blessed = obj->blessed;
+           can->owt = weight(can);
+           can->known = 1;
+           can->spe = -1;  /* Mark tinned tins. No spinach allowed... */
+           if (carried(corpse)) {
+               if (corpse->unpaid)
+                   verbalize(you_buy_it);
+               useup(corpse);
+           } else {
+               if (costly_spot(corpse->ox, corpse->oy) && !corpse->no_charge)
+                   verbalize(you_buy_it);
+               useupf(corpse, 1L);
+           }
+           can = hold_another_object(can, "You make, but cannot pick up, %s.",
+                                     doname(can), (const char *)0);
+       } else impossible("Tinning failed.");
+}
+
+void
+use_unicorn_horn(obj)
+struct obj *obj;
+{
+#define PROP_COUNT 6           /* number of properties we're dealing with */
+#define ATTR_COUNT (A_MAX*3)   /* number of attribute points we might fix */
+       int idx, val, val_limit,
+           trouble_count, unfixable_trbl, did_prop, did_attr;
+       int trouble_list[PROP_COUNT + ATTR_COUNT];
+
+       if (obj && obj->cursed) {
+           long lcount = (long) rnd(100);
+
+           switch (rn2(6)) {
+           case 0: make_sick(Sick ? Sick/3L + 1L : (long)rn1(ACURR(A_CON),20),
+                       xname(obj), TRUE, SICK_NONVOMITABLE);
+                   break;
+           case 1: make_blinded(Blinded + lcount, TRUE);
+                   break;
+           case 2: if (!Confusion)
+                       You("suddenly feel %s.",
+                           Hallucination ? "trippy" : "confused");
+                   make_confused(HConfusion + lcount, TRUE);
+                   break;
+           case 3: make_stunned(HStun + lcount, TRUE);
+                   break;
+           case 4: (void) adjattrib(rn2(A_MAX), -1, FALSE);
+                   break;
+           case 5: (void) make_hallucinated(HHallucination + lcount, TRUE, 0L);
+                   break;
+           }
+           return;
+       }
+
+/*
+ * Entries in the trouble list use a very simple encoding scheme.
+ */
+#define prop2trbl(X)   ((X) + A_MAX)
+#define attr2trbl(Y)   (Y)
+#define prop_trouble(X) trouble_list[trouble_count++] = prop2trbl(X)
+#define attr_trouble(Y) trouble_list[trouble_count++] = attr2trbl(Y)
+
+       trouble_count = unfixable_trbl = did_prop = did_attr = 0;
+
+       /* collect property troubles */
+       if (Sick) prop_trouble(SICK);
+       if (Blinded > (long)u.ucreamed) prop_trouble(BLINDED);
+       if (HHallucination) prop_trouble(HALLUC);
+       if (Vomiting) prop_trouble(VOMITING);
+       if (HConfusion) prop_trouble(CONFUSION);
+       if (HStun) prop_trouble(STUNNED);
+
+       unfixable_trbl = unfixable_trouble_count(TRUE);
+
+       /* collect attribute troubles */
+       for (idx = 0; idx < A_MAX; idx++) {
+           val_limit = AMAX(idx);
+           /* don't recover strength lost from hunger */
+           if (idx == A_STR && u.uhs >= WEAK) val_limit--;
+           /* don't recover more than 3 points worth of any attribute */
+           if (val_limit > ABASE(idx) + 3) val_limit = ABASE(idx) + 3;
+
+           for (val = ABASE(idx); val < val_limit; val++)
+               attr_trouble(idx);
+           /* keep track of unfixed trouble, for message adjustment below */
+           unfixable_trbl += (AMAX(idx) - val_limit);
+       }
+
+       if (trouble_count == 0) {
+           pline(nothing_happens);
+           return;
+       } else if (trouble_count > 1) {         /* shuffle */
+           int i, j, k;
+
+           for (i = trouble_count - 1; i > 0; i--)
+               if ((j = rn2(i + 1)) != i) {
+                   k = trouble_list[j];
+                   trouble_list[j] = trouble_list[i];
+                   trouble_list[i] = k;
+               }
+       }
+
+       /*
+        *              Chances for number of troubles to be fixed
+        *               0      1      2      3      4      5      6      7
+        *   blessed:  22.7%  22.7%  19.5%  15.4%  10.7%   5.7%   2.6%   0.8%
+        *  uncursed:  35.4%  35.4%  22.9%   6.3%    0      0      0      0
+        */
+       val_limit = rn2( d(2, (obj && obj->blessed) ? 4 : 2) );
+       if (val_limit > trouble_count) val_limit = trouble_count;
+
+       /* fix [some of] the troubles */
+       for (val = 0; val < val_limit; val++) {
+           idx = trouble_list[val];
+
+           switch (idx) {
+           case prop2trbl(SICK):
+               make_sick(0L, (char *) 0, TRUE, SICK_ALL);
+               did_prop++;
+               break;
+           case prop2trbl(BLINDED):
+               make_blinded((long)u.ucreamed, TRUE);
+               did_prop++;
+               break;
+           case prop2trbl(HALLUC):
+               (void) make_hallucinated(0L, TRUE, 0L);
+               did_prop++;
+               break;
+           case prop2trbl(VOMITING):
+               make_vomiting(0L, TRUE);
+               did_prop++;
+               break;
+           case prop2trbl(CONFUSION):
+               make_confused(0L, TRUE);
+               did_prop++;
+               break;
+           case prop2trbl(STUNNED):
+               make_stunned(0L, TRUE);
+               did_prop++;
+               break;
+           default:
+               if (idx >= 0 && idx < A_MAX) {
+                   ABASE(idx) += 1;
+                   did_attr++;
+               } else
+                   panic("use_unicorn_horn: bad trouble? (%d)", idx);
+               break;
+           }
+       }
+
+       if (did_attr)
+           pline("This makes you feel %s!",
+                 (did_prop + did_attr) == (trouble_count + unfixable_trbl) ?
+                 "great" : "better");
+       else if (!did_prop)
+           pline("Nothing seems to happen.");
+
+       flags.botl = (did_attr || did_prop);
+#undef PROP_COUNT
+#undef ATTR_COUNT
+#undef prop2trbl
+#undef attr2trbl
+#undef prop_trouble
+#undef attr_trouble
+}
+
+/*
+ * Timer callback routine: turn figurine into monster
+ */
+void
+fig_transform(arg, timeout)
+genericptr_t arg;
+long timeout;
+{
+       struct obj *figurine = (struct obj *)arg;
+       struct monst *mtmp;
+       coord cc;
+       boolean cansee_spot, silent, okay_spot;
+       boolean redraw = FALSE;
+       char monnambuf[BUFSZ], carriedby[BUFSZ];
+
+       if (!figurine) {
+#ifdef DEBUG
+           pline("null figurine in fig_transform()");
+#endif
+           return;
+       }
+       silent = (timeout != monstermoves); /* happened while away */
+       okay_spot = get_obj_location(figurine, &cc.x, &cc.y, 0);
+       if (figurine->where == OBJ_INVENT ||
+           figurine->where == OBJ_MINVENT)
+               okay_spot = enexto(&cc, cc.x, cc.y,
+                                  &mons[figurine->corpsenm]);
+       if (!okay_spot ||
+           !figurine_location_checks(figurine,&cc, TRUE)) {
+               /* reset the timer to try again later */
+               (void) start_timer((long)rnd(5000), TIMER_OBJECT,
+                               FIG_TRANSFORM, (genericptr_t)figurine);
+               return;
+       }
+
+       cansee_spot = cansee(cc.x, cc.y);
+       mtmp = make_familiar(figurine, cc.x, cc.y, TRUE);
+       if (mtmp) {
+           Sprintf(monnambuf, "%s",an(m_monnam(mtmp)));
+           switch (figurine->where) {
+               case OBJ_INVENT:
+                   if (Blind)
+                       You_feel("%s %s from your pack!", something,
+                           locomotion(mtmp->data,"drop"));
+                   else
+                       You("see %s %s out of your pack!",
+                           monnambuf,
+                           locomotion(mtmp->data,"drop"));
+                   break;
+
+               case OBJ_FLOOR:
+                   if (cansee_spot && !silent) {
+                       You("suddenly see a figurine transform into %s!",
+                               monnambuf);
+                       redraw = TRUE;  /* update figurine's map location */
+                   }
+                   break;
+
+               case OBJ_MINVENT:
+                   if (cansee_spot && !silent) {
+                       struct monst *mon;
+                       mon = figurine->ocarry;
+                       /* figurine carring monster might be invisible */
+                       if (canseemon(figurine->ocarry)) {
+                           Sprintf(carriedby, "%s pack",
+                                    s_suffix(a_monnam(mon)));
+                       }
+                       else if (is_pool(mon->mx, mon->my))
+                           Strcpy(carriedby, "empty water");
+                       else
+                           Strcpy(carriedby, "thin air");
+                       You("see %s %s out of %s!", monnambuf,
+                           locomotion(mtmp->data, "drop"), carriedby);
+                   }
+                   break;
+#if 0
+               case OBJ_MIGRATING:
+                   break;
+#endif
+
+               default:
+                   impossible("figurine came to life where? (%d)",
+                               (int)figurine->where);
+               break;
+           }
+       }
+       /* free figurine now */
+       obj_extract_self(figurine);
+       obfree(figurine, (struct obj *)0);
+       if (redraw) newsym(cc.x, cc.y);
+}
+
+STATIC_OVL boolean
+figurine_location_checks(obj, cc, quietly)
+struct obj *obj;
+coord *cc;
+boolean quietly;
+{
+       xchar x,y;
+
+       if (carried(obj) && u.uswallow) {
+               if (!quietly)
+                       You("don't have enough room in here.");
+               return FALSE;
+       }
+       x = cc->x; y = cc->y;
+       if (!isok(x,y)) {
+               if (!quietly)
+                       You("cannot put the figurine there.");
+               return FALSE;
+       }
+       if (IS_ROCK(levl[x][y].typ) &&
+           !(passes_walls(&mons[obj->corpsenm]) && may_passwall(x,y))) {
+               if (!quietly)
+                   You("cannot place a figurine in %s!",
+                       IS_TREE(levl[x][y].typ) ? "a tree" : "solid rock");
+               return FALSE;
+       }
+       if (sobj_at(BOULDER,x,y) && !passes_walls(&mons[obj->corpsenm])
+                       && !throws_rocks(&mons[obj->corpsenm])) {
+               if (!quietly)
+                       You("cannot fit the figurine on the boulder.");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+STATIC_OVL void
+use_figurine(optr)
+struct obj **optr;
+{
+       register struct obj *obj = *optr;
+       xchar x, y;
+       coord cc;
+
+       if (u.uswallow) {
+               /* can't activate a figurine while swallowed */
+               if (!figurine_location_checks(obj, (coord *)0, FALSE))
+                       return;
+       }
+       if(!getdir((char *)0)) {
+               flags.move = multi = 0;
+               return;
+       }
+       x = u.ux + u.dx; y = u.uy + u.dy;
+       cc.x = x; cc.y = y;
+       /* Passing FALSE arg here will result in messages displayed */
+       if (!figurine_location_checks(obj, &cc, FALSE)) return;
+       You("%s and it transforms.",
+           (u.dx||u.dy) ? "set the figurine beside you" :
+           (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ||
+            is_pool(cc.x, cc.y)) ?
+               "release the figurine" :
+           (u.dz < 0 ?
+               "toss the figurine into the air" :
+               "set the figurine on the ground"));
+       (void) make_familiar(obj, cc.x, cc.y, FALSE);
+       (void) stop_timer(FIG_TRANSFORM, (genericptr_t)obj);
+       useup(obj);
+       *optr = 0;
+}
+
+static NEARDATA const char lubricables[] = { ALL_CLASSES, ALLOW_NONE, 0 };
+static NEARDATA const char need_to_remove_outer_armor[] =
+                       "need to remove your %s to grease your %s.";
+
+STATIC_OVL void
+use_grease(obj)
+struct obj *obj;
+{
+       struct obj *otmp;
+       char buf[BUFSZ];
+
+       if (Glib) {
+           pline("%s from your %s.", Tobjnam(obj, "slip"),
+                 makeplural(body_part(FINGER)));
+           dropx(obj);
+           return;
+       }
+
+       if (obj->spe > 0) {
+               if ((obj->cursed || Fumbling) && !rn2(2)) {
+                       consume_obj_charge(obj, TRUE);
+
+                       pline("%s from your %s.", Tobjnam(obj, "slip"),
+                             makeplural(body_part(FINGER)));
+                       dropx(obj);
+                       return;
+               }
+               otmp = getobj(lubricables, "grease");
+               if (!otmp) return;
+               if ((otmp->owornmask & WORN_ARMOR) && uarmc) {
+                       Strcpy(buf, xname(uarmc));
+                       You(need_to_remove_outer_armor, buf, xname(otmp));
+                       return;
+               }
+#ifdef TOURIST
+               if ((otmp->owornmask & WORN_SHIRT) && (uarmc || uarm)) {
+                       Strcpy(buf, uarmc ? xname(uarmc) : "");
+                       if (uarmc && uarm) Strcat(buf, " and ");
+                       Strcat(buf, uarm ? xname(uarm) : "");
+                       You(need_to_remove_outer_armor, buf, xname(otmp));
+                       return;
+               }
+#endif
+               consume_obj_charge(obj, TRUE);
+
+               if (otmp != &zeroobj) {
+                       You("cover %s with a thick layer of grease.",
+                           yname(otmp));
+                       otmp->greased = 1;
+                       if (obj->cursed && !nohands(youmonst.data)) {
+                           incr_itimeout(&Glib, rnd(15));
+                           pline("Some of the grease gets all over your %s.",
+                               makeplural(body_part(HAND)));
+                       }
+               } else {
+                       Glib += rnd(15);
+                       You("coat your %s with grease.",
+                           makeplural(body_part(FINGER)));
+               }
+       } else {
+           if (obj->known)
+               pline("%s empty.", Tobjnam(obj, "are"));
+           else
+               pline("%s to be empty.", Tobjnam(obj, "seem"));
+       }
+       update_inventory();
+}
+
+static struct trapinfo {
+       struct obj *tobj;
+       xchar tx, ty;
+       int time_needed;
+       boolean force_bungle;
+} trapinfo;
+
+void
+reset_trapset()
+{
+       trapinfo.tobj = 0;
+       trapinfo.force_bungle = 0;
+}
+
+/* touchstones - by Ken Arnold */
+STATIC_OVL void
+use_stone(tstone)
+struct obj *tstone;
+{
+    struct obj *obj;
+    boolean do_scratch;
+    const char *streak_color, *choices;
+    char stonebuf[QBUFSZ];
+    static const char scritch[] = "\"scritch, scritch\"";
+    static const char allowall[3] = { COIN_CLASS, ALL_CLASSES, 0 };
+    static const char justgems[3] = { ALLOW_NONE, GEM_CLASS, 0 };
+#ifndef GOLDOBJ
+    struct obj goldobj;
+#endif
+
+    /* in case it was acquired while blinded */
+    if (!Blind) tstone->dknown = 1;
+    /* when the touchstone is fully known, don't bother listing extra
+       junk as likely candidates for rubbing */
+    choices = (tstone->otyp == TOUCHSTONE && tstone->dknown &&
+               objects[TOUCHSTONE].oc_name_known) ? justgems : allowall;
+    Sprintf(stonebuf, "rub on the stone%s", plur(tstone->quan));
+    if ((obj = getobj(choices, stonebuf)) == 0)
+       return;
+#ifndef GOLDOBJ
+    if (obj->oclass == COIN_CLASS) {
+       u.ugold += obj->quan;   /* keep botl up to date */
+       goldobj = *obj;
+       dealloc_obj(obj);
+       obj = &goldobj;
+    }
+#endif
+
+    if (obj == tstone && obj->quan == 1) {
+       You_cant("rub %s on itself.", the(xname(obj)));
+       return;
+    }
+
+    if (tstone->otyp == TOUCHSTONE && tstone->cursed &&
+           obj->oclass == GEM_CLASS && !is_graystone(obj) &&
+           !obj_resists(obj, 80, 100)) {
+       if (Blind)
+           pline("You feel something shatter.");
+       else if (Hallucination)
+           pline("Oh, wow, look at the pretty shards.");
+       else
+           pline("A sharp crack shatters %s%s.",
+                 (obj->quan > 1) ? "one of " : "", the(xname(obj)));
+#ifndef GOLDOBJ
+     /* assert(obj != &goldobj); */
+#endif
+       useup(obj);
+       return;
+    }
+
+    if (Blind) {
+       pline(scritch);
+       return;
+    } else if (Hallucination) {
+       pline("Oh wow, man: Fractals!");
+       return;
+    }
+
+    do_scratch = FALSE;
+    streak_color = 0;
+
+    switch (obj->oclass) {
+    case GEM_CLASS:    /* these have class-specific handling below */
+    case RING_CLASS:
+       if (tstone->otyp != TOUCHSTONE) {
+           do_scratch = TRUE;
+       } else if (obj->oclass == GEM_CLASS && (tstone->blessed ||
+               (!tstone->cursed &&
+                   (Role_if(PM_ARCHEOLOGIST) || Race_if(PM_GNOME))))) {
+           makeknown(TOUCHSTONE);
+           makeknown(obj->otyp);
+           prinv((char *)0, obj, 0L);
+           return;
+       } else {
+           /* either a ring or the touchstone was not effective */
+           if (objects[obj->otyp].oc_material == GLASS) {
+               do_scratch = TRUE;
+               break;
+           }
+       }
+       streak_color = c_obj_colors[objects[obj->otyp].oc_color];
+       break;          /* gem or ring */
+
+    default:
+       switch (objects[obj->otyp].oc_material) {
+       case CLOTH:
+           pline("%s a little more polished now.", Tobjnam(tstone, "look"));
+           return;
+       case LIQUID:
+           if (!obj->known)            /* note: not "whetstone" */
+               You("must think this is a wetstone, do you?");
+           else
+               pline("%s a little wetter now.", Tobjnam(tstone, "are"));
+           return;
+       case WAX:
+           streak_color = "waxy";
+           break;              /* okay even if not touchstone */
+       case WOOD:
+           streak_color = "wooden";
+           break;              /* okay even if not touchstone */
+       case GOLD:
+           do_scratch = TRUE;  /* scratching and streaks */
+           streak_color = "golden";
+           break;
+       case SILVER:
+           do_scratch = TRUE;  /* scratching and streaks */
+           streak_color = "silvery";
+           break;
+       default:
+           /* Objects passing the is_flimsy() test will not
+              scratch a stone.  They will leave streaks on
+              non-touchstones and touchstones alike. */
+           if (is_flimsy(obj))
+               streak_color = c_obj_colors[objects[obj->otyp].oc_color];
+           else
+               do_scratch = (tstone->otyp != TOUCHSTONE);
+           break;
+       }
+       break;          /* default oclass */
+    }
+
+    Sprintf(stonebuf, "stone%s", plur(tstone->quan));
+    if (do_scratch)
+       pline("You make %s%sscratch marks on the %s.",
+             streak_color ? streak_color : (const char *)"",
+             streak_color ? " " : "", stonebuf);
+    else if (streak_color)
+       pline("You see %s streaks on the %s.", streak_color, stonebuf);
+    else
+       pline(scritch);
+    return;
+}
+
+/* Place a landmine/bear trap.  Helge Hafting */
+STATIC_OVL void
+use_trap(otmp)
+struct obj *otmp;
+{
+       int ttyp, tmp;
+       const char *what = (char *)0;
+       char buf[BUFSZ];
+       const char *occutext = "setting the trap";
+
+       if (nohands(youmonst.data))
+           what = "without hands";
+       else if (Stunned)
+           what = "while stunned";
+       else if (u.uswallow)
+           what = is_animal(u.ustuck->data) ? "while swallowed" :
+                       "while engulfed";
+       else if (Underwater)
+           what = "underwater";
+       else if (Levitation)
+           what = "while levitating";
+       else if (is_pool(u.ux, u.uy))
+           what = "in water";
+       else if (is_lava(u.ux, u.uy))
+           what = "in lava";
+       else if (On_stairs(u.ux, u.uy))
+           what = (u.ux == xdnladder || u.ux == xupladder) ?
+                       "on the ladder" : "on the stairs";
+       else if (IS_FURNITURE(levl[u.ux][u.uy].typ) ||
+               IS_ROCK(levl[u.ux][u.uy].typ) ||
+               closed_door(u.ux, u.uy) || t_at(u.ux, u.uy))
+           what = "here";
+       if (what) {
+           You_cant("set a trap %s!",what);
+           reset_trapset();
+           return;
+       }
+       ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP;
+       if (otmp == trapinfo.tobj &&
+               u.ux == trapinfo.tx && u.uy == trapinfo.ty) {
+           You("resume setting %s %s.",
+               shk_your(buf, otmp),
+               defsyms[trap_to_defsym(what_trap(ttyp))].explanation);
+           set_occupation(set_trap, occutext, 0);
+           return;
+       }
+       trapinfo.tobj = otmp;
+       trapinfo.tx = u.ux,  trapinfo.ty = u.uy;
+       tmp = ACURR(A_DEX);
+       trapinfo.time_needed = (tmp > 17) ? 2 : (tmp > 12) ? 3 :
+                               (tmp > 7) ? 4 : 5;
+       if (Blind) trapinfo.time_needed *= 2;
+       tmp = ACURR(A_STR);
+       if (ttyp == BEAR_TRAP && tmp < 18)
+           trapinfo.time_needed += (tmp > 12) ? 1 : (tmp > 7) ? 2 : 4;
+       /*[fumbling and/or confusion and/or cursed object check(s)
+          should be incorporated here instead of in set_trap]*/
+#ifdef STEED
+       if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
+           boolean chance;
+
+           if (Fumbling || otmp->cursed) chance = (rnl(10) > 3);
+           else  chance = (rnl(10) > 5);
+           You("aren't very skilled at reaching from %s.",
+               mon_nam(u.usteed));
+           Sprintf(buf, "Continue your attempt to set %s?",
+               the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation));
+           if(yn(buf) == 'y') {
+               if (chance) {
+                       switch(ttyp) {
+                           case LANDMINE:      /* set it off */
+                               trapinfo.time_needed = 0;
+                               trapinfo.force_bungle = TRUE;
+                               break;
+                           case BEAR_TRAP:     /* drop it without arming it */
+                               reset_trapset();
+                               You("drop %s!",
+                         the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation));
+                               dropx(otmp);
+                               return;
+                       }
+               }
+           } else {
+               reset_trapset();
+               return;
+           }
+       }
+#endif
+       You("begin setting %s %s.",
+           shk_your(buf, otmp),
+           defsyms[trap_to_defsym(what_trap(ttyp))].explanation);
+       set_occupation(set_trap, occutext, 0);
+       return;
+}
+
+STATIC_PTR
+int
+set_trap()
+{
+       struct obj *otmp = trapinfo.tobj;
+       struct trap *ttmp;
+       int ttyp;
+
+       if (!otmp || !carried(otmp) ||
+               u.ux != trapinfo.tx || u.uy != trapinfo.ty) {
+           /* ?? */
+           reset_trapset();
+           return 0;
+       }
+
+       if (--trapinfo.time_needed > 0) return 1;       /* still busy */
+
+       ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP;
+       ttmp = maketrap(u.ux, u.uy, ttyp);
+       if (ttmp) {
+           ttmp->tseen = 1;
+           ttmp->madeby_u = 1;
+           newsym(u.ux, u.uy); /* if our hero happens to be invisible */
+           if (*in_rooms(u.ux,u.uy,SHOPBASE)) {
+               add_damage(u.ux, u.uy, 0L);             /* schedule removal */
+           }
+           if (!trapinfo.force_bungle)
+               You("finish arming %s.",
+                       the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation));
+           if (((otmp->cursed || Fumbling) && (rnl(10) > 5)) || trapinfo.force_bungle)
+               dotrap(ttmp,
+                       (unsigned)(trapinfo.force_bungle ? FORCEBUNGLE : 0));
+       } else {
+           /* this shouldn't happen */
+           Your("trap setting attempt fails.");
+       }
+       useup(otmp);
+       reset_trapset();
+       return 0;
+}
+
+STATIC_OVL int
+use_whip(obj)
+struct obj *obj;
+{
+    char buf[BUFSZ];
+    struct monst *mtmp;
+    struct obj *otmp;
+    int rx, ry, proficient, res = 0;
+    const char *msg_slipsfree = "The bullwhip slips free.";
+    const char *msg_snap = "Snap!";
+
+    if (obj != uwep) {
+       if (!wield_tool(obj, "lash")) return 0;
+       else res = 1;
+    }
+    if (!getdir((char *)0)) return res;
+
+    if (Stunned || (Confusion && !rn2(5))) confdir();
+    rx = u.ux + u.dx;
+    ry = u.uy + u.dy;
+    mtmp = m_at(rx, ry);
+
+    /* fake some proficiency checks */
+    proficient = 0;
+    if (Role_if(PM_ARCHEOLOGIST)) ++proficient;
+    if (ACURR(A_DEX) < 6) proficient--;
+    else if (ACURR(A_DEX) >= 14) proficient += (ACURR(A_DEX) - 14);
+    if (Fumbling) --proficient;
+    if (proficient > 3) proficient = 3;
+    if (proficient < 0) proficient = 0;
+
+    if (u.uswallow && attack(u.ustuck)) {
+       There("is not enough room to flick your bullwhip.");
+
+    } else if (Underwater) {
+       There("is too much resistance to flick your bullwhip.");
+
+    } else if (u.dz < 0) {
+       You("flick a bug off of the %s.",ceiling(u.ux,u.uy));
+
+    } else if ((!u.dx && !u.dy) || (u.dz > 0)) {
+       int dam;
+
+#ifdef STEED
+       /* Sometimes you hit your steed by mistake */
+       if (u.usteed && !rn2(proficient + 2)) {
+           You("whip %s!", mon_nam(u.usteed));
+           kick_steed();
+           return 1;
+       }
+#endif
+       if (Levitation
+#ifdef STEED
+                       || u.usteed
+#endif
+               ) {
+           /* Have a shot at snaring something on the floor */
+           otmp = level.objects[u.ux][u.uy];
+           if (otmp && otmp->otyp == CORPSE && otmp->corpsenm == PM_HORSE) {
+               pline("Why beat a dead horse?");
+               return 1;
+           }
+           if (otmp && proficient) {
+               You("wrap your bullwhip around %s on the %s.",
+                   an(singular(otmp, xname)), surface(u.ux, u.uy));
+               if (rnl(6) || pickup_object(otmp, 1L, TRUE) < 1)
+                   pline(msg_slipsfree);
+               return 1;
+           }
+       }
+       dam = rnd(2) + dbon() + obj->spe;
+       if (dam <= 0) dam = 1;
+       You("hit your %s with your bullwhip.", body_part(FOOT));
+       Sprintf(buf, "killed %sself with %s bullwhip", uhim(), uhis());
+       losehp(dam, buf, NO_KILLER_PREFIX);
+       flags.botl = 1;
+       return 1;
+
+    } else if ((Fumbling || Glib) && !rn2(5)) {
+       pline_The("bullwhip slips out of your %s.", body_part(HAND));
+       dropx(obj);
+
+    } else if (u.utrap && u.utraptype == TT_PIT) {
+       /*
+        *     Assumptions:
+        *
+        *      if you're in a pit
+        *              - you are attempting to get out of the pit
+        *              - or, if you are applying it towards a small
+        *                monster then it is assumed that you are
+        *                trying to hit it.
+        *      else if the monster is wielding a weapon
+        *              - you are attempting to disarm a monster
+        *      else
+        *              - you are attempting to hit the monster
+        *
+        *      if you're confused (and thus off the mark)
+        *              - you only end up hitting.
+        *
+        */
+       const char *wrapped_what = (char *)0;
+
+       if (mtmp) {
+           if (bigmonst(mtmp->data)) {
+               wrapped_what = strcpy(buf, mon_nam(mtmp));
+           } else if (proficient) {
+               if (attack(mtmp)) return 1;
+               else pline(msg_snap);
+           }
+       }
+       if (!wrapped_what) {
+           if (IS_FURNITURE(levl[rx][ry].typ))
+               wrapped_what = something;
+           else if (sobj_at(BOULDER, rx, ry))
+               wrapped_what = "a boulder";
+       }
+       if (wrapped_what) {
+           coord cc;
+
+           cc.x = rx; cc.y = ry;
+           You("wrap your bullwhip around %s.", wrapped_what);
+           if (proficient && rn2(proficient + 2)) {
+               if (!mtmp || enexto(&cc, rx, ry, youmonst.data)) {
+                   You("yank yourself out of the pit!");
+                   teleds(cc.x, cc.y, TRUE);
+                   u.utrap = 0;
+                   vision_full_recalc = 1;
+               }
+           } else {
+               pline(msg_slipsfree);
+           }
+           if (mtmp) wakeup(mtmp);
+       } else pline(msg_snap);
+
+    } else if (mtmp) {
+       if (!canspotmon(mtmp) &&
+               !glyph_is_invisible(levl[rx][ry].glyph)) {
+          pline("A monster is there that you couldn't see.");
+          map_invisible(rx, ry);
+       }
+       otmp = MON_WEP(mtmp);   /* can be null */
+       if (otmp) {
+           char onambuf[BUFSZ];
+           const char *mon_hand;
+           boolean gotit = proficient && (!Fumbling || !rn2(10));
+
+           Strcpy(onambuf, cxname(otmp));
+           if (gotit) {
+               mon_hand = mbodypart(mtmp, HAND);
+               if (bimanual(otmp)) mon_hand = makeplural(mon_hand);
+           } else
+               mon_hand = 0;   /* lint suppression */
+
+           You("wrap your bullwhip around %s %s.",
+               s_suffix(mon_nam(mtmp)), onambuf);
+           if (gotit && otmp->cursed) {
+               pline("%s welded to %s %s%c",
+                     (otmp->quan == 1L) ? "It is" : "They are",
+                     mhis(mtmp), mon_hand,
+                     !otmp->bknown ? '!' : '.');
+               otmp->bknown = 1;
+               gotit = FALSE;  /* can't pull it free */
+           }
+           if (gotit) {
+               obj_extract_self(otmp);
+               possibly_unwield(mtmp, FALSE);
+               setmnotwielded(mtmp,otmp);
+
+               switch (rn2(proficient + 1)) {
+               case 2:
+                   /* to floor near you */
+                   You("yank %s %s to the %s!", s_suffix(mon_nam(mtmp)),
+                       onambuf, surface(u.ux, u.uy));
+                   place_object(otmp, u.ux, u.uy);
+                   stackobj(otmp);
+                   break;
+               case 3:
+                   /* right to you */
+#if 0
+                   if (!rn2(25)) {
+                       /* proficient with whip, but maybe not
+                          so proficient at catching weapons */
+                       int hitu, hitvalu;
+
+                       hitvalu = 8 + otmp->spe;
+                       hitu = thitu(hitvalu,
+                                    dmgval(otmp, &youmonst),
+                                    otmp, (char *)0);
+                       if (hitu) {
+                           pline_The("%s hits you as you try to snatch it!",
+                               the(onambuf));
+                       }
+                       place_object(otmp, u.ux, u.uy);
+                       stackobj(otmp);
+                       break;
+                   }
+#endif /* 0 */
+                   /* right into your inventory */
+                   You("snatch %s %s!", s_suffix(mon_nam(mtmp)), onambuf);
+                   if (otmp->otyp == CORPSE &&
+                           touch_petrifies(&mons[otmp->corpsenm]) &&
+                           !uarmg && !Stone_resistance &&
+                           !(poly_when_stoned(youmonst.data) &&
+                               polymon(PM_STONE_GOLEM))) {
+                       char kbuf[BUFSZ];
+
+                       Sprintf(kbuf, "%s corpse",
+                               an(mons[otmp->corpsenm].mname));
+                       pline("Snatching %s is a fatal mistake.", kbuf);
+                       instapetrify(kbuf);
+                   }
+                   otmp = hold_another_object(otmp, "You drop %s!",
+                                              doname(otmp), (const char *)0);
+                   break;
+               default:
+                   /* to floor beneath mon */
+                   You("yank %s from %s %s!", the(onambuf),
+                       s_suffix(mon_nam(mtmp)), mon_hand);
+                   obj_no_longer_held(otmp);
+                   place_object(otmp, mtmp->mx, mtmp->my);
+                   stackobj(otmp);
+                   break;
+               }
+           } else {
+               pline(msg_slipsfree);
+           }
+           wakeup(mtmp);
+       } else {
+           if (mtmp->m_ap_type &&
+               !Protection_from_shape_changers && !sensemon(mtmp))
+               stumble_onto_mimic(mtmp);
+           else You("flick your bullwhip towards %s.", mon_nam(mtmp));
+           if (proficient) {
+               if (attack(mtmp)) return 1;
+               else pline(msg_snap);
+           }
+       }
+
+    } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
+           /* it must be air -- water checked above */
+           You("snap your whip through thin air.");
+
+    } else {
+       pline(msg_snap);
+
+    }
+    return 1;
+}
+
+
+static const char
+       not_enough_room[] = "There's not enough room here to use that.",
+       where_to_hit[] = "Where do you want to hit?",
+       cant_see_spot[] = "won't hit anything if you can't see that spot.",
+       cant_reach[] = "can't reach that spot from here.";
+
+/* Distance attacks by pole-weapons */
+STATIC_OVL int
+use_pole (obj)
+       struct obj *obj;
+{
+       int res = 0, typ, max_range = 4, min_range = 4;
+       coord cc;
+       struct monst *mtmp;
+
+
+       /* Are you allowed to use the pole? */
+       if (u.uswallow) {
+           pline(not_enough_room);
+           return (0);
+       }
+       if (obj != uwep) {
+           if (!wield_tool(obj, "swing")) return(0);
+           else res = 1;
+       }
+     /* assert(obj == uwep); */
+
+       /* Prompt for a location */
+       pline(where_to_hit);
+       cc.x = u.ux;
+       cc.y = u.uy;
+       if (getpos(&cc, TRUE, "the spot to hit") < 0)
+           return 0;   /* user pressed ESC */
+
+       /* Calculate range */
+       typ = uwep_skill_type();
+       if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) max_range = 4;
+       else if (P_SKILL(typ) == P_SKILLED) max_range = 5;
+       else max_range = 8;
+       if (distu(cc.x, cc.y) > max_range) {
+           pline("Too far!");
+           return (res);
+       } else if (distu(cc.x, cc.y) < min_range) {
+           pline("Too close!");
+           return (res);
+       } else if (!cansee(cc.x, cc.y) &&
+                  ((mtmp = m_at(cc.x, cc.y)) == (struct monst *)0 ||
+                   !canseemon(mtmp))) {
+           You(cant_see_spot);
+           return (res);
+       } else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */
+           You(cant_reach);
+           return res;
+       }
+
+       /* Attack the monster there */
+       if ((mtmp = m_at(cc.x, cc.y)) != (struct monst *)0) {
+           int oldhp = mtmp->mhp;
+
+           bhitpos = cc;
+           check_caitiff(mtmp);
+           (void) thitmonst(mtmp, uwep);
+           /* check the monster's HP because thitmonst() doesn't return
+            * an indication of whether it hit.  Not perfect (what if it's a
+            * non-silver weapon on a shade?)
+            */
+           if (mtmp->mhp < oldhp)
+               u.uconduct.weaphit++;
+       } else
+           /* Now you know that nothing is there... */
+           pline(nothing_happens);
+       return (1);
+}
+
+STATIC_OVL int
+use_cream_pie(obj)
+struct obj *obj;
+{
+       boolean wasblind = Blind;
+       boolean wascreamed = u.ucreamed;
+       boolean several = FALSE;
+
+       if (obj->quan > 1L) {
+               several = TRUE;
+               obj = splitobj(obj, 1L);
+       }
+       if (Hallucination)
+               You("give yourself a facial.");
+       else
+               pline("You immerse your %s in %s%s.", body_part(FACE),
+                       several ? "one of " : "",
+                       several ? makeplural(the(xname(obj))) : the(xname(obj)));
+       if(can_blnd((struct monst*)0, &youmonst, AT_WEAP, obj)) {
+               int blindinc = rnd(25);
+               u.ucreamed += blindinc;
+               make_blinded(Blinded + (long)blindinc, FALSE);
+               if (!Blind || (Blind && wasblind))
+                       pline("There's %ssticky goop all over your %s.",
+                               wascreamed ? "more " : "",
+                               body_part(FACE));
+               else /* Blind  && !wasblind */
+                       You_cant("see through all the sticky goop on your %s.",
+                               body_part(FACE));
+       }
+       if (obj->unpaid) {
+               verbalize("You used it, you bought it!");
+               bill_dummy_object(obj);
+       }
+       obj_extract_self(obj);
+       delobj(obj);
+       return(0);
+}
+
+STATIC_OVL int
+use_grapple (obj)
+       struct obj *obj;
+{
+       int res = 0, typ, max_range = 4, tohit;
+       coord cc;
+       struct monst *mtmp;
+       struct obj *otmp;
+
+       /* Are you allowed to use the hook? */
+       if (u.uswallow) {
+           pline(not_enough_room);
+           return (0);
+       }
+       if (obj != uwep) {
+           if (!wield_tool(obj, "cast")) return(0);
+           else res = 1;
+       }
+     /* assert(obj == uwep); */
+
+       /* Prompt for a location */
+       pline(where_to_hit);
+       cc.x = u.ux;
+       cc.y = u.uy;
+       if (getpos(&cc, TRUE, "the spot to hit") < 0)
+           return 0;   /* user pressed ESC */
+
+       /* Calculate range */
+       typ = uwep_skill_type();
+       if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) max_range = 4;
+       else if (P_SKILL(typ) == P_SKILLED) max_range = 5;
+       else max_range = 8;
+       if (distu(cc.x, cc.y) > max_range) {
+           pline("Too far!");
+           return (res);
+       } else if (!cansee(cc.x, cc.y)) {
+           You(cant_see_spot);
+           return (res);
+       } else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */
+           You(cant_reach);
+           return res;
+       }
+
+       /* What do you want to hit? */
+       tohit = rn2(5);
+       if (typ != P_NONE && P_SKILL(typ) >= P_SKILLED) {
+           winid tmpwin = create_nhwindow(NHW_MENU);
+           anything any;
+           char buf[BUFSZ];
+           menu_item *selected;
+
+           any.a_void = 0;     /* set all bits to zero */
+           any.a_int = 1;      /* use index+1 (cant use 0) as identifier */
+           start_menu(tmpwin);
+           any.a_int++;
+           Sprintf(buf, "an object on the %s", surface(cc.x, cc.y));
+           add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                        buf, MENU_UNSELECTED);
+           any.a_int++;
+           add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                       "a monster", MENU_UNSELECTED);
+           any.a_int++;
+           Sprintf(buf, "the %s", surface(cc.x, cc.y));
+           add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                        buf, MENU_UNSELECTED);
+           end_menu(tmpwin, "Aim for what?");
+           tohit = rn2(4);
+           if (select_menu(tmpwin, PICK_ONE, &selected) > 0 &&
+                       rn2(P_SKILL(typ) > P_SKILLED ? 20 : 2))
+               tohit = selected[0].item.a_int - 1;
+           free((genericptr_t)selected);
+           destroy_nhwindow(tmpwin);
+       }
+
+       /* What did you hit? */
+       switch (tohit) {
+       case 0: /* Trap */
+           /* FIXME -- untrap needs to deal with non-adjacent traps */
+           break;
+       case 1: /* Object */
+           if ((otmp = level.objects[cc.x][cc.y]) != 0) {
+               You("snag an object from the %s!", surface(cc.x, cc.y));
+               (void) pickup_object(otmp, 1L, FALSE);
+               /* If pickup fails, leave it alone */
+               newsym(cc.x, cc.y);
+               return (1);
+           }
+           break;
+       case 2: /* Monster */
+           if ((mtmp = m_at(cc.x, cc.y)) == (struct monst *)0) break;
+           if (verysmall(mtmp->data) && !rn2(4) &&
+                       enexto(&cc, u.ux, u.uy, (struct permonst *)0)) {
+               You("pull in %s!", mon_nam(mtmp));
+               mtmp->mundetected = 0;
+               rloc_to(mtmp, cc.x, cc.y);
+               return (1);
+           } else if ((!bigmonst(mtmp->data) && !strongmonst(mtmp->data)) ||
+                      rn2(4)) {
+               (void) thitmonst(mtmp, uwep);
+               return (1);
+           }
+           /* FALL THROUGH */
+       case 3: /* Surface */
+           if (IS_AIR(levl[cc.x][cc.y].typ) || is_pool(cc.x, cc.y))
+               pline_The("hook slices through the %s.", surface(cc.x, cc.y));
+           else {
+               You("are yanked toward the %s!", surface(cc.x, cc.y));
+               hurtle(sgn(cc.x-u.ux), sgn(cc.y-u.uy), 1, FALSE);
+               spoteffects(TRUE);
+           }
+           return (1);
+       default:        /* Yourself (oops!) */
+           if (P_SKILL(typ) <= P_BASIC) {
+               You("hook yourself!");
+               losehp(rn1(10,10), "a grappling hook", KILLED_BY);
+               return (1);
+           }
+           break;
+       }
+       pline(nothing_happens);
+       return (1);
+}
+
+
+#define BY_OBJECT      ((struct monst *)0)
+
+/* return 1 if the wand is broken, hence some time elapsed */
+STATIC_OVL int
+do_break_wand(obj)
+    struct obj *obj;
+{
+    static const char nothing_else_happens[] = "But nothing else happens...";
+    register int i, x, y;
+    register struct monst *mon;
+    int dmg, damage;
+    boolean affects_objects;
+    boolean shop_damage = FALSE;
+    int expltype = EXPL_MAGICAL;
+    char confirm[QBUFSZ], the_wand[BUFSZ], buf[BUFSZ];
+
+    Strcpy(the_wand, yname(obj));
+    Sprintf(confirm, "Are you really sure you want to break %s?",
+       safe_qbuf("", sizeof("Are you really sure you want to break ?"),
+                               the_wand, ysimple_name(obj), "the wand"));
+    if (yn(confirm) == 'n' ) return 0;
+
+    if (nohands(youmonst.data)) {
+       You_cant("break %s without hands!", the_wand);
+       return 0;
+    } else if (ACURR(A_STR) < 10) {
+       You("don't have the strength to break %s!", the_wand);
+       return 0;
+    }
+    pline("Raising %s high above your %s, you break it in two!",
+         the_wand, body_part(HEAD));
+
+    /* [ALI] Do this first so that wand is removed from bill. Otherwise,
+     * the freeinv() below also hides it from setpaid() which causes problems.
+     */
+    if (obj->unpaid) {
+       check_unpaid(obj);              /* Extra charge for use */
+       bill_dummy_object(obj);
+    }
+
+    current_wand = obj;                /* destroy_item might reset this */
+    freeinv(obj);              /* hide it from destroy_item instead... */
+    setnotworn(obj);           /* so we need to do this ourselves */
+
+    if (obj->spe <= 0) {
+       pline(nothing_else_happens);
+       goto discard_broken_wand;
+    }
+    obj->ox = u.ux;
+    obj->oy = u.uy;
+    dmg = obj->spe * 4;
+    affects_objects = FALSE;
+
+    switch (obj->otyp) {
+    case WAN_WISHING:
+    case WAN_NOTHING:
+    case WAN_LOCKING:
+    case WAN_PROBING:
+    case WAN_ENLIGHTENMENT:
+    case WAN_OPENING:
+    case WAN_SECRET_DOOR_DETECTION:
+       pline(nothing_else_happens);
+       goto discard_broken_wand;
+    case WAN_DEATH:
+    case WAN_LIGHTNING:
+       dmg *= 4;
+       goto wanexpl;
+    case WAN_FIRE:
+       expltype = EXPL_FIERY;
+    case WAN_COLD:
+       if (expltype == EXPL_MAGICAL) expltype = EXPL_FROSTY;
+       dmg *= 2;
+    case WAN_MAGIC_MISSILE:
+    wanexpl:
+       explode(u.ux, u.uy,
+               (obj->otyp - WAN_MAGIC_MISSILE), dmg, WAND_CLASS, expltype);
+       makeknown(obj->otyp);   /* explode described the effect */
+       goto discard_broken_wand;
+    case WAN_STRIKING:
+       /* we want this before the explosion instead of at the very end */
+       pline("A wall of force smashes down around you!");
+       dmg = d(1 + obj->spe,6);        /* normally 2d12 */
+    case WAN_CANCELLATION:
+    case WAN_POLYMORPH:
+    case WAN_TELEPORTATION:
+    case WAN_UNDEAD_TURNING:
+       affects_objects = TRUE;
+       break;
+    default:
+       break;
+    }
+
+    /* magical explosion and its visual effect occur before specific effects */
+    explode(obj->ox, obj->oy, 0, rnd(dmg), WAND_CLASS, EXPL_MAGICAL);
+
+    /* this makes it hit us last, so that we can see the action first */
+    for (i = 0; i <= 8; i++) {
+       bhitpos.x = x = obj->ox + xdir[i];
+       bhitpos.y = y = obj->oy + ydir[i];
+       if (!isok(x,y)) continue;
+
+       if (obj->otyp == WAN_DIGGING) {
+           if(dig_check(BY_OBJECT, FALSE, x, y)) {
+               if (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)) {
+                   /* normally, pits and holes don't anger guards, but they
+                    * do if it's a wall or door that's being dug */
+                   watch_dig((struct monst *)0, x, y, TRUE);
+                   if (*in_rooms(x,y,SHOPBASE)) shop_damage = TRUE;
+               }                   
+               digactualhole(x, y, BY_OBJECT,
+                             (rn2(obj->spe) < 3 || !Can_dig_down(&u.uz)) ?
+                              PIT : HOLE);
+           }
+           continue;
+       } else if(obj->otyp == WAN_CREATE_MONSTER) {
+           /* u.ux,u.uy creates it near you--x,y might create it in rock */
+           (void) makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS);
+           continue;
+       } else {
+           if (x == u.ux && y == u.uy) {
+               /* teleport objects first to avoid race with tele control and
+                  autopickup.  Other wand/object effects handled after
+                  possible wand damage is assessed */
+               if (obj->otyp == WAN_TELEPORTATION &&
+                   affects_objects && level.objects[x][y]) {
+                   (void) bhitpile(obj, bhito, x, y);
+                   if (flags.botl) bot();              /* potion effects */
+               }
+               damage = zapyourself(obj, FALSE);
+               if (damage) {
+                   Sprintf(buf, "killed %sself by breaking a wand", uhim());
+                   losehp(damage, buf, NO_KILLER_PREFIX);
+               }
+               if (flags.botl) bot();          /* blindness */
+           } else if ((mon = m_at(x, y)) != 0) {
+               (void) bhitm(mon, obj);
+            /* if (flags.botl) bot(); */
+           }
+           if (affects_objects && level.objects[x][y]) {
+               (void) bhitpile(obj, bhito, x, y);
+               if (flags.botl) bot();          /* potion effects */
+           }
+       }
+    }
+
+    /* Note: if player fell thru, this call is a no-op.
+       Damage is handled in digactualhole in that case */
+    if (shop_damage) pay_for_damage("dig into", FALSE);
+
+    if (obj->otyp == WAN_LIGHT)
+       litroom(TRUE, obj);     /* only needs to be done once */
+
+ discard_broken_wand:
+    obj = current_wand;                /* [see dozap() and destroy_item()] */
+    current_wand = 0;
+    if (obj)
+       delobj(obj);
+    nomul(0);
+    return 1;
+}
+
+STATIC_OVL boolean
+uhave_graystone()
+{
+       register struct obj *otmp;
+
+       for(otmp = invent; otmp; otmp = otmp->nobj)
+               if(is_graystone(otmp))
+                       return TRUE;
+       return FALSE;
+}
+
+STATIC_OVL void
+add_class(cl, class)
+char *cl;
+char class;
+{
+       char tmp[2];
+       tmp[0] = class;
+       tmp[1] = '\0';
+       Strcat(cl, tmp);
+}
+
+int
+doapply()
+{
+       struct obj *obj;
+       register int res = 1;
+       char class_list[MAXOCLASSES+2];
+
+       if(check_capacity((char *)0)) return (0);
+
+       if (carrying(POT_OIL) || uhave_graystone())
+               Strcpy(class_list, tools_too);
+       else
+               Strcpy(class_list, tools);
+       if (carrying(CREAM_PIE) || carrying(EUCALYPTUS_LEAF))
+               add_class(class_list, FOOD_CLASS);
+
+       obj = getobj(class_list, "use or apply");
+       if(!obj) return 0;
+
+       if (obj->oartifact && !touch_artifact(obj, &youmonst))
+           return 1;   /* evading your grasp costs a turn; just be
+                          grateful that you don't drop it as well */
+
+       if (obj->oclass == WAND_CLASS)
+           return do_break_wand(obj);
+
+       switch(obj->otyp){
+       case BLINDFOLD:
+       case LENSES:
+               if (obj == ublindf) {
+                   if (!cursed(obj)) Blindf_off(obj);
+               } else if (!ublindf)
+                   Blindf_on(obj);
+               else You("are already %s.",
+                       ublindf->otyp == TOWEL ?     "covered by a towel" :
+                       ublindf->otyp == BLINDFOLD ? "wearing a blindfold" :
+                                                    "wearing lenses");
+               break;
+       case CREAM_PIE:
+               res = use_cream_pie(obj);
+               break;
+       case BULLWHIP:
+               res = use_whip(obj);
+               break;
+       case GRAPPLING_HOOK:
+               res = use_grapple(obj);
+               break;
+       case LARGE_BOX:
+       case CHEST:
+       case ICE_BOX:
+       case SACK:
+       case BAG_OF_HOLDING:
+       case OILSKIN_SACK:
+               res = use_container(obj, 1);
+               break;
+       case BAG_OF_TRICKS:
+               bagotricks(obj);
+               break;
+       case CAN_OF_GREASE:
+               use_grease(obj);
+               break;
+       case LOCK_PICK:
+#ifdef TOURIST
+       case CREDIT_CARD:
+#endif
+       case SKELETON_KEY:
+               (void) pick_lock(obj);
+               break;
+       case PICK_AXE:
+       case DWARVISH_MATTOCK:
+               res = use_pick_axe(obj);
+               break;
+       case TINNING_KIT:
+               use_tinning_kit(obj);
+               break;
+       case LEASH:
+               use_leash(obj);
+               break;
+#ifdef STEED
+       case SADDLE:
+               res = use_saddle(obj);
+               break;
+#endif
+       case MAGIC_WHISTLE:
+               use_magic_whistle(obj);
+               break;
+       case TIN_WHISTLE:
+               use_whistle(obj);
+               break;
+       case EUCALYPTUS_LEAF:
+               /* MRKR: Every Australian knows that a gum leaf makes an */
+               /*       excellent whistle, especially if your pet is a  */
+               /*       tame kangaroo named Skippy.                     */
+               if (obj->blessed) {
+                   use_magic_whistle(obj);
+                   /* sometimes the blessing will be worn off */
+                   if (!rn2(49)) {
+                       if (!Blind) {
+                           char buf[BUFSZ];
+
+                           pline("%s %s %s.", Shk_Your(buf, obj),
+                                 aobjnam(obj, "glow"), hcolor("brown"));
+                           obj->bknown = 1;
+                       }
+                       unbless(obj);
+                   }
+               } else {
+                   use_whistle(obj);
+               }
+               break;
+       case STETHOSCOPE:
+               res = use_stethoscope(obj);
+               break;
+       case MIRROR:
+               res = use_mirror(obj);
+               break;
+       case BELL:
+       case BELL_OF_OPENING:
+               use_bell(&obj);
+               break;
+       case CANDELABRUM_OF_INVOCATION:
+               use_candelabrum(obj);
+               break;
+       case WAX_CANDLE:
+       case TALLOW_CANDLE:
+               use_candle(&obj);
+               break;
+       case OIL_LAMP:
+       case MAGIC_LAMP:
+       case BRASS_LANTERN:
+               use_lamp(obj);
+               break;
+       case POT_OIL:
+               light_cocktail(obj);
+               break;
+#ifdef TOURIST
+       case EXPENSIVE_CAMERA:
+               res = use_camera(obj);
+               break;
+#endif
+       case TOWEL:
+               res = use_towel(obj);
+               break;
+       case CRYSTAL_BALL:
+               use_crystal_ball(obj);
+               break;
+       case MAGIC_MARKER:
+               res = dowrite(obj);
+               break;
+       case TIN_OPENER:
+               if(!carrying(TIN)) {
+                       You("have no tin to open.");
+                       goto xit;
+               }
+               You("cannot open a tin without eating or discarding its contents.");
+               if(flags.verbose)
+                       pline("In order to eat, use the 'e' command.");
+               if(obj != uwep)
+    pline("Opening the tin will be much easier if you wield the tin opener.");
+               goto xit;
+
+       case FIGURINE:
+               use_figurine(&obj);
+               break;
+       case UNICORN_HORN:
+               use_unicorn_horn(obj);
+               break;
+       case WOODEN_FLUTE:
+       case MAGIC_FLUTE:
+       case TOOLED_HORN:
+       case FROST_HORN:
+       case FIRE_HORN:
+       case WOODEN_HARP:
+       case MAGIC_HARP:
+       case BUGLE:
+       case LEATHER_DRUM:
+       case DRUM_OF_EARTHQUAKE:
+               res = do_play_instrument(obj);
+               break;
+       case HORN_OF_PLENTY:    /* not a musical instrument */
+               if (obj->spe > 0) {
+                   struct obj *otmp;
+                   const char *what;
+
+                   consume_obj_charge(obj, TRUE);
+                   if (!rn2(13)) {
+                       otmp = mkobj(POTION_CLASS, FALSE);
+                       if (objects[otmp->otyp].oc_magic) do {
+                           otmp->otyp = rnd_class(POT_BOOZE, POT_WATER);
+                       } while (otmp->otyp == POT_SICKNESS);
+                       what = "A potion";
+                   } else {
+                       otmp = mkobj(FOOD_CLASS, FALSE);
+                       if (otmp->otyp == FOOD_RATION && !rn2(7))
+                           otmp->otyp = LUMP_OF_ROYAL_JELLY;
+                       what = "Some food";
+                   }
+                   pline("%s spills out.", what);
+                   otmp->blessed = obj->blessed;
+                   otmp->cursed = obj->cursed;
+                   otmp->owt = weight(otmp);
+                   otmp = hold_another_object(otmp, u.uswallow ?
+                                      "Oops!  %s out of your reach!" :
+                                       (Is_airlevel(&u.uz) ||
+                                        Is_waterlevel(&u.uz) ||
+                                        levl[u.ux][u.uy].typ < IRONBARS ||
+                                        levl[u.ux][u.uy].typ >= ICE) ?
+                                              "Oops!  %s away from you!" :
+                                              "Oops!  %s to the floor!",
+                                              The(aobjnam(otmp, "slip")),
+                                              (const char *)0);
+                   makeknown(HORN_OF_PLENTY);
+               } else
+                   pline(nothing_happens);
+               break;
+       case LAND_MINE:
+       case BEARTRAP:
+               use_trap(obj);
+               break;
+       case FLINT:
+       case LUCKSTONE:
+       case LOADSTONE:
+       case TOUCHSTONE:
+               use_stone(obj);
+               break;
+       default:
+               /* Pole-weapons can strike at a distance */
+               if (is_pole(obj)) {
+                       res = use_pole(obj);
+                       break;
+               } else if (is_pick(obj) || is_axe(obj)) {
+                       res = use_pick_axe(obj);
+                       break;
+               }
+               pline("Sorry, I don't know how to use that.");
+       xit:
+               nomul(0);
+               return 0;
+       }
+       if (res && obj && obj->oartifact) arti_speak(obj);
+       nomul(0);
+       return res;
+}
+
+/* Keep track of unfixable troubles for purposes of messages saying you feel
+ * great.
+ */
+int
+unfixable_trouble_count(is_horn)
+       boolean is_horn;
+{
+       int unfixable_trbl = 0;
+
+       if (Stoned) unfixable_trbl++;
+       if (Strangled) unfixable_trbl++;
+       if (Wounded_legs
+#ifdef STEED
+                   && !u.usteed
+#endif
+                               ) unfixable_trbl++;
+       if (Slimed) unfixable_trbl++;
+       /* lycanthropy is not desirable, but it doesn't actually make you feel
+          bad */
+
+       /* we'll assume that intrinsic stunning from being a bat/stalker
+          doesn't make you feel bad */
+       if (!is_horn) {
+           if (Confusion) unfixable_trbl++;
+           if (Sick) unfixable_trbl++;
+           if (HHallucination) unfixable_trbl++;
+           if (Vomiting) unfixable_trbl++;
+           if (HStun) unfixable_trbl++;
+       }
+       return unfixable_trbl;
+}
+
+#endif /* OVLB */
+
+/*apply.c*/
diff --git a/src/artifact.c b/src/artifact.c
new file mode 100644 (file)
index 0000000..ef27bd5
--- /dev/null
@@ -0,0 +1,1461 @@
+/*     SCCS Id: @(#)artifact.c 3.4     2003/08/11      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "artifact.h"
+#ifdef OVLB
+#include "artilist.h"
+#else
+STATIC_DCL struct artifact artilist[];
+#endif
+/*
+ * Note:  both artilist[] and artiexist[] have a dummy element #0,
+ *       so loops over them should normally start at #1.  The primary
+ *       exception is the save & restore code, which doesn't care about
+ *       the contents, just the total size.
+ */
+
+extern boolean notonhead;      /* for long worms */
+
+#define get_artifact(o) \
+               (((o)&&(o)->oartifact) ? &artilist[(int) (o)->oartifact] : 0)
+
+STATIC_DCL int FDECL(spec_applies, (const struct artifact *,struct monst *));
+STATIC_DCL int FDECL(arti_invoke, (struct obj*));
+STATIC_DCL boolean FDECL(Mb_hit, (struct monst *magr,struct monst *mdef,
+                                 struct obj *,int *,int,BOOLEAN_P,char *));
+
+/* The amount added to the victim's total hit points to insure that the
+   victim will be killed even after damage bonus/penalty adjustments.
+   Most such penalties are small, and 200 is plenty; the exception is
+   half physical damage.  3.3.1 and previous versions tried to use a very
+   large number to account for this case; now, we just compute the fatal
+   damage by adding it to 2 times the total hit points instead of 1 time.
+   Note: this will still break if they have more than about half the number
+   of hit points that will fit in a 15 bit integer. */
+#define FATAL_DAMAGE_MODIFIER 200
+
+#ifndef OVLB
+STATIC_DCL int spec_dbon_applies;
+STATIC_DCL xchar artidisco[NROFARTIFACTS];
+#else  /* OVLB */
+/* coordinate effects from spec_dbon() with messages in artifact_hit() */
+STATIC_OVL int spec_dbon_applies = 0;
+
+/* flags including which artifacts have already been created */
+static boolean artiexist[1+NROFARTIFACTS+1];
+/* and a discovery list for them (no dummy first entry here) */
+STATIC_OVL xchar artidisco[NROFARTIFACTS];
+
+STATIC_DCL void NDECL(hack_artifacts);
+STATIC_DCL boolean FDECL(attacks, (int,struct obj *));
+
+/* handle some special cases; must be called after u_init() */
+STATIC_OVL void
+hack_artifacts()
+{
+       struct artifact *art;
+       int alignmnt = aligns[flags.initalign].value;
+
+       /* Fix up the alignments of "gift" artifacts */
+       for (art = artilist+1; art->otyp; art++)
+           if (art->role == Role_switch && art->alignment != A_NONE)
+               art->alignment = alignmnt;
+
+       /* Excalibur can be used by any lawful character, not just knights */
+       if (!Role_if(PM_KNIGHT))
+           artilist[ART_EXCALIBUR].role = NON_PM;
+
+       /* Fix up the quest artifact */
+       if (urole.questarti) {
+           artilist[urole.questarti].alignment = alignmnt;
+           artilist[urole.questarti].role = Role_switch;
+       }
+       return;
+}
+
+/* zero out the artifact existence list */
+void
+init_artifacts()
+{
+       (void) memset((genericptr_t) artiexist, 0, sizeof artiexist);
+       (void) memset((genericptr_t) artidisco, 0, sizeof artidisco);
+       hack_artifacts();
+}
+
+void
+save_artifacts(fd)
+int fd;
+{
+       bwrite(fd, (genericptr_t) artiexist, sizeof artiexist);
+       bwrite(fd, (genericptr_t) artidisco, sizeof artidisco);
+}
+
+void
+restore_artifacts(fd)
+int fd;
+{
+       mread(fd, (genericptr_t) artiexist, sizeof artiexist);
+       mread(fd, (genericptr_t) artidisco, sizeof artidisco);
+       hack_artifacts();       /* redo non-saved special cases */
+}
+
+const char *
+artiname(artinum)
+int artinum;
+{
+       if (artinum <= 0 || artinum > NROFARTIFACTS) return("");
+       return(artilist[artinum].name);
+}
+
+/*
+   Make an artifact.  If a specific alignment is specified, then an object of
+   the appropriate alignment is created from scratch, or 0 is returned if
+   none is available.  (If at least one aligned artifact has already been
+   given, then unaligned ones also become eligible for this.)
+   If no alignment is given, then 'otmp' is converted
+   into an artifact of matching type, or returned as-is if that's not possible.
+   For the 2nd case, caller should use ``obj = mk_artifact(obj, A_NONE);''
+   for the 1st, ``obj = mk_artifact((struct obj *)0, some_alignment);''.
+ */
+struct obj *
+mk_artifact(otmp, alignment)
+struct obj *otmp;      /* existing object; ignored if alignment specified */
+aligntyp alignment;    /* target alignment, or A_NONE */
+{
+       const struct artifact *a;
+       int n, m;
+       boolean by_align = (alignment != A_NONE);
+       short o_typ = (by_align || !otmp) ? 0 : otmp->otyp;
+       boolean unique = !by_align && otmp && objects[o_typ].oc_unique;
+       short eligible[NROFARTIFACTS];
+
+       /* gather eligible artifacts */
+       for (n = 0, a = artilist+1, m = 1; a->otyp; a++, m++)
+           if ((!by_align ? a->otyp == o_typ :
+                   (a->alignment == alignment ||
+                       (a->alignment == A_NONE && u.ugifts > 0))) &&
+               (!(a->spfx & SPFX_NOGEN) || unique) && !artiexist[m]) {
+               if (by_align && a->race != NON_PM && race_hostile(&mons[a->race]))
+                   continue;   /* skip enemies' equipment */
+               else if (by_align && Role_if(a->role))
+                   goto make_artif;    /* 'a' points to the desired one */
+               else
+                   eligible[n++] = m;
+           }
+
+       if (n) {                /* found at least one candidate */
+           m = eligible[rn2(n)];       /* [0..n-1] */
+           a = &artilist[m];
+
+           /* make an appropriate object if necessary, then christen it */
+make_artif: if (by_align) otmp = mksobj((int)a->otyp, TRUE, FALSE);
+           otmp = oname(otmp, a->name);
+           otmp->oartifact = m;
+           artiexist[m] = TRUE;
+       } else {
+           /* nothing appropriate could be found; return the original object */
+           if (by_align) otmp = 0;     /* (there was no original object) */
+       }
+       return otmp;
+}
+
+/*
+ * Returns the full name (with articles and correct capitalization) of an
+ * artifact named "name" if one exists, or NULL, it not.
+ * The given name must be rather close to the real name for it to match.
+ * The object type of the artifact is returned in otyp if the return value
+ * is non-NULL.
+ */
+const char*
+artifact_name(name, otyp)
+const char *name;
+short *otyp;
+{
+    register const struct artifact *a;
+    register const char *aname;
+
+    if(!strncmpi(name, "the ", 4)) name += 4;
+
+    for (a = artilist+1; a->otyp; a++) {
+       aname = a->name;
+       if(!strncmpi(aname, "the ", 4)) aname += 4;
+       if(!strcmpi(name, aname)) {
+           *otyp = a->otyp;
+           return a->name;
+       }
+    }
+
+    return (char *)0;
+}
+
+boolean
+exist_artifact(otyp, name)
+register int otyp;
+register const char *name;
+{
+       register const struct artifact *a;
+       register boolean *arex;
+
+       if (otyp && *name)
+           for (a = artilist+1,arex = artiexist+1; a->otyp; a++,arex++)
+               if ((int) a->otyp == otyp && !strcmp(a->name, name))
+                   return *arex;
+       return FALSE;
+}
+
+void
+artifact_exists(otmp, name, mod)
+register struct obj *otmp;
+register const char *name;
+register boolean mod;
+{
+       register const struct artifact *a;
+
+       if (otmp && *name)
+           for (a = artilist+1; a->otyp; a++)
+               if (a->otyp == otmp->otyp && !strcmp(a->name, name)) {
+                   register int m = a - artilist;
+                   otmp->oartifact = (char)(mod ? m : 0);
+                   otmp->age = 0;
+                   if(otmp->otyp == RIN_INCREASE_DAMAGE)
+                       otmp->spe = 0;
+                   artiexist[m] = mod;
+                   break;
+               }
+       return;
+}
+
+int
+nartifact_exist()
+{
+    int a = 0;
+    int n = SIZE(artiexist);
+
+    while(n > 1)
+       if(artiexist[--n]) a++;
+
+    return a;
+}
+#endif /* OVLB */
+#ifdef OVL0
+
+boolean
+spec_ability(otmp, abil)
+struct obj *otmp;
+unsigned long abil;
+{
+       const struct artifact *arti = get_artifact(otmp);
+
+       return((boolean)(arti && (arti->spfx & abil)));
+}
+
+/* used so that callers don't need to known about SPFX_ codes */
+boolean
+confers_luck(obj)
+struct obj *obj;
+{
+    /* might as well check for this too */
+    if (obj->otyp == LUCKSTONE) return TRUE;
+
+    return (obj->oartifact && spec_ability(obj, SPFX_LUCK));
+}
+
+/* used to check whether a monster is getting reflection from an artifact */
+boolean
+arti_reflects(obj)
+struct obj *obj;
+{
+    const struct artifact *arti = get_artifact(obj);
+
+    if (arti) {      
+       /* while being worn */
+       if ((obj->owornmask & ~W_ART) && (arti->spfx & SPFX_REFLECT))
+           return TRUE;
+       /* just being carried */
+       if (arti->cspfx & SPFX_REFLECT) return TRUE;
+    }
+    return FALSE;
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+boolean
+restrict_name(otmp, name)  /* returns 1 if name is restricted for otmp->otyp */
+register struct obj *otmp;
+register const char *name;
+{
+       register const struct artifact *a;
+       register const char *aname;
+
+       if (!*name) return FALSE;
+       if (!strncmpi(name, "the ", 4)) name += 4;
+
+               /* Since almost every artifact is SPFX_RESTR, it doesn't cost
+                  us much to do the string comparison before the spfx check.
+                  Bug fix:  don't name multiple elven daggers "Sting".
+                */
+       for (a = artilist+1; a->otyp; a++) {
+           if (a->otyp != otmp->otyp) continue;
+           aname = a->name;
+           if (!strncmpi(aname, "the ", 4)) aname += 4;
+           if (!strcmp(aname, name))
+               return ((boolean)((a->spfx & (SPFX_NOGEN|SPFX_RESTR)) != 0 ||
+                       otmp->quan > 1L));
+       }
+
+       return FALSE;
+}
+
+STATIC_OVL boolean
+attacks(adtyp, otmp)
+register int adtyp;
+register struct obj *otmp;
+{
+       register const struct artifact *weap;
+
+       if ((weap = get_artifact(otmp)) != 0)
+               return((boolean)(weap->attk.adtyp == adtyp));
+       return FALSE;
+}
+
+boolean
+defends(adtyp, otmp)
+register int adtyp;
+register struct obj *otmp;
+{
+       register const struct artifact *weap;
+
+       if ((weap = get_artifact(otmp)) != 0)
+               return((boolean)(weap->defn.adtyp == adtyp));
+       return FALSE;
+}
+
+/* used for monsters */
+boolean
+protects(adtyp, otmp)
+int adtyp;
+struct obj *otmp;
+{
+       register const struct artifact *weap;
+
+       if ((weap = get_artifact(otmp)) != 0)
+               return (boolean)(weap->cary.adtyp == adtyp);
+       return FALSE;
+}
+
+/*
+ * a potential artifact has just been worn/wielded/picked-up or
+ * unworn/unwielded/dropped.  Pickup/drop only set/reset the W_ART mask.
+ */
+void
+set_artifact_intrinsic(otmp,on,wp_mask)
+register struct obj *otmp;
+boolean on;
+long wp_mask;
+{
+       long *mask = 0;
+       register const struct artifact *oart = get_artifact(otmp);
+       uchar dtyp;
+       long spfx;
+
+       if (!oart) return;
+
+       /* effects from the defn field */
+       dtyp = (wp_mask != W_ART) ? oart->defn.adtyp : oart->cary.adtyp;
+
+       if (dtyp == AD_FIRE)
+           mask = &EFire_resistance;
+       else if (dtyp == AD_COLD)
+           mask = &ECold_resistance;
+       else if (dtyp == AD_ELEC)
+           mask = &EShock_resistance;
+       else if (dtyp == AD_MAGM)
+           mask = &EAntimagic;
+       else if (dtyp == AD_DISN)
+           mask = &EDisint_resistance;
+       else if (dtyp == AD_DRST)
+           mask = &EPoison_resistance;
+
+       if (mask && wp_mask == W_ART && !on) {
+           /* find out if some other artifact also confers this intrinsic */
+           /* if so, leave the mask alone */
+           register struct obj* obj;
+           for(obj = invent; obj; obj = obj->nobj)
+               if(obj != otmp && obj->oartifact) {
+                   register const struct artifact *art = get_artifact(obj);
+                   if(art->cary.adtyp == dtyp) {
+                       mask = (long *) 0;
+                       break;
+                   }
+               }
+       }
+       if (mask) {
+           if (on) *mask |= wp_mask;
+           else *mask &= ~wp_mask;
+       }
+
+       /* intrinsics from the spfx field; there could be more than one */
+       spfx = (wp_mask != W_ART) ? oart->spfx : oart->cspfx;
+       if(spfx && wp_mask == W_ART && !on) {
+           /* don't change any spfx also conferred by other artifacts */
+           register struct obj* obj;
+           for(obj = invent; obj; obj = obj->nobj)
+               if(obj != otmp && obj->oartifact) {
+                   register const struct artifact *art = get_artifact(obj);
+                   spfx &= ~art->cspfx;
+               }
+       }
+
+       if (spfx & SPFX_SEARCH) {
+           if(on) ESearching |= wp_mask;
+           else ESearching &= ~wp_mask;
+       }
+       if (spfx & SPFX_HALRES) {
+           /* make_hallucinated must (re)set the mask itself to get
+            * the display right */
+           /* restoring needed because this is the only artifact intrinsic
+            * that can print a message--need to guard against being printed
+            * when restoring a game
+            */
+           (void) make_hallucinated((long)!on, restoring ? FALSE : TRUE, wp_mask);
+       }
+       if (spfx & SPFX_ESP) {
+           if(on) ETelepat |= wp_mask;
+           else ETelepat &= ~wp_mask;
+           see_monsters();
+       }
+       if (spfx & SPFX_STLTH) {
+           if (on) EStealth |= wp_mask;
+           else EStealth &= ~wp_mask;
+       }
+       if (spfx & SPFX_REGEN) {
+           if (on) ERegeneration |= wp_mask;
+           else ERegeneration &= ~wp_mask;
+       }
+       if (spfx & SPFX_TCTRL) {
+           if (on) ETeleport_control |= wp_mask;
+           else ETeleport_control &= ~wp_mask;
+       }
+       if (spfx & SPFX_WARN) {
+           if (spec_m2(otmp)) {
+               if (on) {
+                       EWarn_of_mon |= wp_mask;
+                       flags.warntype |= spec_m2(otmp);
+               } else {
+                       EWarn_of_mon &= ~wp_mask;
+                       flags.warntype &= ~spec_m2(otmp);
+               }
+               see_monsters();
+           } else {
+               if (on) EWarning |= wp_mask;
+               else EWarning &= ~wp_mask;
+           }
+       }
+       if (spfx & SPFX_EREGEN) {
+           if (on) EEnergy_regeneration |= wp_mask;
+           else EEnergy_regeneration &= ~wp_mask;
+       }
+       if (spfx & SPFX_HSPDAM) {
+           if (on) EHalf_spell_damage |= wp_mask;
+           else EHalf_spell_damage &= ~wp_mask;
+       }
+       if (spfx & SPFX_HPHDAM) {
+           if (on) EHalf_physical_damage |= wp_mask;
+           else EHalf_physical_damage &= ~wp_mask;
+       }
+       if (spfx & SPFX_XRAY) {
+           /* this assumes that no one else is using xray_range */
+           if (on) u.xray_range = 3;
+           else u.xray_range = -1;
+           vision_full_recalc = 1;
+       }
+       if ((spfx & SPFX_REFLECT) && (wp_mask & W_WEP)) {
+           if (on) EReflecting |= wp_mask;
+           else EReflecting &= ~wp_mask;
+       }
+
+       if(wp_mask == W_ART && !on && oart->inv_prop) {
+           /* might have to turn off invoked power too */
+           if (oart->inv_prop <= LAST_PROP &&
+               (u.uprops[oart->inv_prop].extrinsic & W_ARTI))
+               (void) arti_invoke(otmp);
+       }
+}
+
+/*
+ * creature (usually player) tries to touch (pick up or wield) an artifact obj.
+ * Returns 0 if the object refuses to be touched.
+ * This routine does not change any object chains.
+ * Ignores such things as gauntlets, assuming the artifact is not
+ * fooled by such trappings.
+ */
+int
+touch_artifact(obj,mon)
+    struct obj *obj;
+    struct monst *mon;
+{
+    register const struct artifact *oart = get_artifact(obj);
+    boolean badclass, badalign, self_willed, yours;
+
+    if(!oart) return 1;
+
+    yours = (mon == &youmonst);
+    /* all quest artifacts are self-willed; it this ever changes, `badclass'
+       will have to be extended to explicitly include quest artifacts */
+    self_willed = ((oart->spfx & SPFX_INTEL) != 0);
+    if (yours) {
+       badclass = self_willed &&
+                  ((oart->role != NON_PM && !Role_if(oart->role)) ||
+                   (oart->race != NON_PM && !Race_if(oart->race)));
+       badalign = (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE &&
+                  (oart->alignment != u.ualign.type || u.ualign.record < 0);
+    } else if (!is_covetous(mon->data) && !is_mplayer(mon->data)) {
+       badclass = self_willed &&
+                  oart->role != NON_PM && oart != &artilist[ART_EXCALIBUR];
+       badalign = (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE &&
+                  (oart->alignment != sgn(mon->data->maligntyp));
+    } else {    /* an M3_WANTSxxx monster or a fake player */
+       /* special monsters trying to take the Amulet, invocation tools or
+          quest item can touch anything except for `spec_applies' artifacts */
+       badclass = badalign = FALSE;
+    }
+    /* weapons which attack specific categories of monsters are
+       bad for them even if their alignments happen to match */
+    if (!badalign && (oart->spfx & SPFX_DBONUS) != 0) {
+       struct artifact tmp;
+
+       tmp = *oart;
+       tmp.spfx &= SPFX_DBONUS;
+       badalign = !!spec_applies(&tmp, mon);
+    }
+
+    if (((badclass || badalign) && self_willed) ||
+       (badalign && (!yours || !rn2(4))))  {
+       int dmg;
+       char buf[BUFSZ];
+
+       if (!yours) return 0;
+       You("are blasted by %s power!", s_suffix(the(xname(obj))));
+       dmg = d((Antimagic ? 2 : 4), (self_willed ? 10 : 4));
+       Sprintf(buf, "touching %s", oart->name);
+       losehp(dmg, buf, KILLED_BY);
+       exercise(A_WIS, FALSE);
+    }
+
+    /* can pick it up unless you're totally non-synch'd with the artifact */
+    if (badclass && badalign && self_willed) {
+       if (yours) pline("%s your grasp!", Tobjnam(obj, "evade"));
+       return 0;
+    }
+
+    return 1;
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+/* decide whether an artifact's special attacks apply against mtmp */
+STATIC_OVL int
+spec_applies(weap, mtmp)
+register const struct artifact *weap;
+struct monst *mtmp;
+{
+       struct permonst *ptr;
+       boolean yours;
+
+       if(!(weap->spfx & (SPFX_DBONUS | SPFX_ATTK)))
+           return(weap->attk.adtyp == AD_PHYS);
+
+       yours = (mtmp == &youmonst);
+       ptr = mtmp->data;
+
+       if (weap->spfx & SPFX_DMONS) {
+           return (ptr == &mons[(int)weap->mtype]);
+       } else if (weap->spfx & SPFX_DCLAS) {
+           return (weap->mtype == (unsigned long)ptr->mlet);
+       } else if (weap->spfx & SPFX_DFLAG1) {
+           return ((ptr->mflags1 & weap->mtype) != 0L);
+       } else if (weap->spfx & SPFX_DFLAG2) {
+           return ((ptr->mflags2 & weap->mtype) || (yours &&
+                       ((!Upolyd && (urace.selfmask & weap->mtype)) ||
+                        ((weap->mtype & M2_WERE) && u.ulycn >= LOW_PM))));
+       } else if (weap->spfx & SPFX_DALIGN) {
+           return yours ? (u.ualign.type != weap->alignment) :
+                          (ptr->maligntyp == A_NONE ||
+                               sgn(ptr->maligntyp) != weap->alignment);
+       } else if (weap->spfx & SPFX_ATTK) {
+           struct obj *defending_weapon = (yours ? uwep : MON_WEP(mtmp));
+
+           if (defending_weapon && defending_weapon->oartifact &&
+                   defends((int)weap->attk.adtyp, defending_weapon))
+               return FALSE;
+           switch(weap->attk.adtyp) {
+               case AD_FIRE:
+                       return !(yours ? Fire_resistance : resists_fire(mtmp));
+               case AD_COLD:
+                       return !(yours ? Cold_resistance : resists_cold(mtmp));
+               case AD_ELEC:
+                       return !(yours ? Shock_resistance : resists_elec(mtmp));
+               case AD_MAGM:
+               case AD_STUN:
+                       return !(yours ? Antimagic : (rn2(100) < ptr->mr));
+               case AD_DRST:
+                       return !(yours ? Poison_resistance : resists_poison(mtmp));
+               case AD_DRLI:
+                       return !(yours ? Drain_resistance : resists_drli(mtmp));
+               case AD_STON:
+                       return !(yours ? Stone_resistance : resists_ston(mtmp));
+               default:        impossible("Weird weapon special attack.");
+           }
+       }
+       return(0);
+}
+
+/* return the M2 flags of monster that an artifact's special attacks apply against */
+long
+spec_m2(otmp)
+struct obj *otmp;
+{
+       register const struct artifact *artifact = get_artifact(otmp);
+       if (artifact)
+               return artifact->mtype;
+       return 0L;
+}
+
+/* special attack bonus */
+int
+spec_abon(otmp, mon)
+struct obj *otmp;
+struct monst *mon;
+{
+       register const struct artifact *weap = get_artifact(otmp);
+
+       /* no need for an extra check for `NO_ATTK' because this will
+          always return 0 for any artifact which has that attribute */
+
+       if (weap && weap->attk.damn && spec_applies(weap, mon))
+           return rnd((int)weap->attk.damn);
+       return 0;
+}
+
+/* special damage bonus */
+int
+spec_dbon(otmp, mon, tmp)
+struct obj *otmp;
+struct monst *mon;
+int tmp;
+{
+       register const struct artifact *weap = get_artifact(otmp);
+
+       if (!weap || (weap->attk.adtyp == AD_PHYS && /* check for `NO_ATTK' */
+                       weap->attk.damn == 0 && weap->attk.damd == 0))
+           spec_dbon_applies = FALSE;
+       else
+           spec_dbon_applies = spec_applies(weap, mon);
+
+       if (spec_dbon_applies)
+           return weap->attk.damd ? rnd((int)weap->attk.damd) : max(tmp,1);
+       return 0;
+}
+
+/* add identified artifact to discoveries list */
+void
+discover_artifact(m)
+xchar m;
+{
+    int i;
+
+    /* look for this artifact in the discoveries list;
+       if we hit an empty slot then it's not present, so add it */
+    for (i = 0; i < NROFARTIFACTS; i++)
+       if (artidisco[i] == 0 || artidisco[i] == m) {
+           artidisco[i] = m;
+           return;
+       }
+    /* there is one slot per artifact, so we should never reach the
+       end without either finding the artifact or an empty slot... */
+    impossible("couldn't discover artifact (%d)", (int)m);
+}
+
+/* used to decide whether an artifact has been fully identified */
+boolean
+undiscovered_artifact(m)
+xchar m;
+{
+    int i;
+
+    /* look for this artifact in the discoveries list;
+       if we hit an empty slot then it's undiscovered */
+    for (i = 0; i < NROFARTIFACTS; i++)
+       if (artidisco[i] == m)
+           return FALSE;
+       else if (artidisco[i] == 0)
+           break;
+    return TRUE;
+}
+
+/* display a list of discovered artifacts; return their count */
+int
+disp_artifact_discoveries(tmpwin)
+winid tmpwin;          /* supplied by dodiscover() */
+{
+    int i, m, otyp;
+    char buf[BUFSZ];
+
+    for (i = 0; i < NROFARTIFACTS; i++) {
+       if (artidisco[i] == 0) break;   /* empty slot implies end of list */
+       if (i == 0) putstr(tmpwin, iflags.menu_headings, "Artifacts");
+       m = artidisco[i];
+       otyp = artilist[m].otyp;
+       Sprintf(buf, "  %s [%s %s]", artiname(m),
+               align_str(artilist[m].alignment), simple_typename(otyp));
+       putstr(tmpwin, 0, buf);
+    }
+    return i;
+}
+
+#endif /* OVL1 */
+
+#ifdef OVLB
+
+
+       /*
+        * Magicbane's intrinsic magic is incompatible with normal
+        * enchantment magic.  Thus, its effects have a negative
+        * dependence on spe.  Against low mr victims, it typically
+        * does "double athame" damage, 2d4.  Occasionally, it will
+        * cast unbalancing magic which effectively averages out to
+        * 4d4 damage (3d4 against high mr victims), for spe = 0.
+        *
+        * Prior to 3.4.1, the cancel (aka purge) effect always
+        * included the scare effect too; now it's one or the other.
+        * Likewise, the stun effect won't be combined with either
+        * of those two; it will be chosen separately or possibly
+        * used as a fallback when scare or cancel fails.
+        *
+        * [Historical note: a change to artifact_hit() for 3.4.0
+        * unintentionally made all of Magicbane's special effects
+        * be blocked if the defender successfully saved against a
+        * stun attack.  As of 3.4.1, those effects can occur but
+        * will be slightly less likely than they were in 3.3.x.]
+        */
+#define MB_MAX_DIEROLL         8       /* rolls above this aren't magical */
+static const char * const mb_verb[2][4] = {
+       { "probe", "stun", "scare", "cancel" },
+       { "prod", "amaze", "tickle", "purge" },
+};
+#define MB_INDEX_PROBE         0
+#define MB_INDEX_STUN          1
+#define MB_INDEX_SCARE         2
+#define MB_INDEX_CANCEL                3
+
+/* called when someone is being hit by Magicbane */
+STATIC_OVL boolean
+Mb_hit(magr, mdef, mb, dmgptr, dieroll, vis, hittee)
+struct monst *magr, *mdef;     /* attacker and defender */
+struct obj *mb;                        /* Magicbane */
+int *dmgptr;                   /* extra damage target will suffer */
+int dieroll;                   /* d20 that has already scored a hit */
+boolean vis;                   /* whether the action can be seen */
+char *hittee;                  /* target's name: "you" or mon_nam(mdef) */
+{
+    struct permonst *old_uasmon;
+    const char *verb;
+    boolean youattack = (magr == &youmonst),
+           youdefend = (mdef == &youmonst),
+           resisted = FALSE, do_stun, do_confuse, result;
+    int attack_indx, scare_dieroll = MB_MAX_DIEROLL / 2;
+
+    result = FALSE;            /* no message given yet */
+    /* the most severe effects are less likely at higher enchantment */
+    if (mb->spe >= 3)
+       scare_dieroll /= (1 << (mb->spe / 3));
+    /* if target successfully resisted the artifact damage bonus,
+       reduce overall likelihood of the assorted special effects */
+    if (!spec_dbon_applies) dieroll += 1;
+
+    /* might stun even when attempting a more severe effect, but
+       in that case it will only happen if the other effect fails;
+       extra damage will apply regardless; 3.4.1: sometimes might
+       just probe even when it hasn't been enchanted */
+    do_stun = (max(mb->spe,0) < rn2(spec_dbon_applies ? 11 : 7));
+
+    /* the special effects also boost physical damage; increments are
+       generally cumulative, but since the stun effect is based on a
+       different criterium its damage might not be included; the base
+       damage is either 1d4 (athame) or 2d4 (athame+spec_dbon) depending
+       on target's resistance check against AD_STUN (handled by caller)
+       [note that a successful save against AD_STUN doesn't actually
+       prevent the target from ending up stunned] */
+    attack_indx = MB_INDEX_PROBE;
+    *dmgptr += rnd(4);                 /* (2..3)d4 */
+    if (do_stun) {
+       attack_indx = MB_INDEX_STUN;
+       *dmgptr += rnd(4);              /* (3..4)d4 */
+    }
+    if (dieroll <= scare_dieroll) {
+       attack_indx = MB_INDEX_SCARE;
+       *dmgptr += rnd(4);              /* (3..5)d4 */
+    }
+    if (dieroll <= (scare_dieroll / 2)) {
+       attack_indx = MB_INDEX_CANCEL;
+       *dmgptr += rnd(4);              /* (4..6)d4 */
+    }
+
+    /* give the hit message prior to inflicting the effects */
+    verb = mb_verb[!!Hallucination][attack_indx];
+    if (youattack || youdefend || vis) {
+       result = TRUE;
+       pline_The("magic-absorbing blade %s %s!",
+                 vtense((const char *)0, verb), hittee);
+       /* assume probing has some sort of noticeable feedback
+          even if it is being done by one monster to another */
+       if (attack_indx == MB_INDEX_PROBE && !canspotmon(mdef))
+           map_invisible(mdef->mx, mdef->my);
+    }
+
+    /* now perform special effects */
+    switch (attack_indx) {
+    case MB_INDEX_CANCEL:
+       old_uasmon = youmonst.data;
+       /* No mdef->mcan check: even a cancelled monster can be polymorphed
+        * into a golem, and the "cancel" effect acts as if some magical
+        * energy remains in spellcasting defenders to be absorbed later.
+        */
+       if (!cancel_monst(mdef, mb, youattack, FALSE, FALSE)) {
+           resisted = TRUE;
+       } else {
+           do_stun = FALSE;
+           if (youdefend) {
+               if (youmonst.data != old_uasmon)
+                   *dmgptr = 0;    /* rehumanized, so no more damage */
+               if (u.uenmax > 0) {
+                   You("lose magical energy!");
+                   u.uenmax--;
+                   if (u.uen > 0) u.uen--;
+                   flags.botl = 1;
+               }
+           } else {
+               if (mdef->data == &mons[PM_CLAY_GOLEM])
+                   mdef->mhp = 1;      /* cancelled clay golems will die */
+               if (youattack && attacktype(mdef->data, AT_MAGC)) {
+                   You("absorb magical energy!");
+                   u.uenmax++;
+                   u.uen++;
+                   flags.botl = 1;
+               }
+           }
+       }
+       break;
+
+    case MB_INDEX_SCARE:
+       if (youdefend) {
+           if (Antimagic) {
+               resisted = TRUE;
+           } else {
+               nomul(-3);
+               nomovemsg = "";
+               if (magr && magr == u.ustuck && sticks(youmonst.data)) {
+                   u.ustuck = (struct monst *)0;
+                   You("release %s!", mon_nam(magr));
+               }
+           }
+       } else {
+           if (rn2(2) && resist(mdef, WEAPON_CLASS, 0, NOTELL))
+               resisted = TRUE;
+           else
+               monflee(mdef, 3, FALSE, (mdef->mhp > *dmgptr));
+       }
+       if (!resisted) do_stun = FALSE;
+       break;
+
+    case MB_INDEX_STUN:
+       do_stun = TRUE;         /* (this is redundant...) */
+       break;
+
+    case MB_INDEX_PROBE:
+       if (youattack && (mb->spe == 0 || !rn2(3 * abs(mb->spe)))) {
+           pline_The("%s is insightful.", verb);
+           /* pre-damage status */
+           probe_monster(mdef);
+       }
+       break;
+    }
+    /* stun if that was selected and a worse effect didn't occur */
+    if (do_stun) {
+       if (youdefend)
+           make_stunned((HStun + 3), FALSE);
+       else
+           mdef->mstun = 1;
+       /* avoid extra stun message below if we used mb_verb["stun"] above */
+       if (attack_indx == MB_INDEX_STUN) do_stun = FALSE;
+    }
+    /* lastly, all this magic can be confusing... */
+    do_confuse = !rn2(12);
+    if (do_confuse) {
+       if (youdefend)
+           make_confused(HConfusion + 4, FALSE);
+       else
+           mdef->mconf = 1;
+    }
+
+    if (youattack || youdefend || vis) {
+       (void) upstart(hittee); /* capitalize */
+       if (resisted) {
+           pline("%s %s!", hittee, vtense(hittee, "resist"));
+           shieldeff(youdefend ? u.ux : mdef->mx,
+                     youdefend ? u.uy : mdef->my);
+       }
+       if ((do_stun || do_confuse) && flags.verbose) {
+           char buf[BUFSZ];
+
+           buf[0] = '\0';
+           if (do_stun) Strcat(buf, "stunned");
+           if (do_stun && do_confuse) Strcat(buf, " and ");
+           if (do_confuse) Strcat(buf, "confused");
+           pline("%s %s %s%c", hittee, vtense(hittee, "are"),
+                 buf, (do_stun && do_confuse) ? '!' : '.');
+       }
+    }
+
+    return result;
+}
+  
+/* Function used when someone attacks someone else with an artifact
+ * weapon.  Only adds the special (artifact) damage, and returns a 1 if it
+ * did something special (in which case the caller won't print the normal
+ * hit message).  This should be called once upon every artifact attack;
+ * dmgval() no longer takes artifact bonuses into account.  Possible
+ * extension: change the killer so that when an orc kills you with
+ * Stormbringer it's "killed by Stormbringer" instead of "killed by an orc".
+ */
+boolean
+artifact_hit(magr, mdef, otmp, dmgptr, dieroll)
+struct monst *magr, *mdef;
+struct obj *otmp;
+int *dmgptr;
+int dieroll; /* needed for Magicbane and vorpal blades */
+{
+       boolean youattack = (magr == &youmonst);
+       boolean youdefend = (mdef == &youmonst);
+       boolean vis = (!youattack && magr && cansee(magr->mx, magr->my))
+           || (!youdefend && cansee(mdef->mx, mdef->my))
+           || (youattack && u.uswallow && mdef == u.ustuck && !Blind);
+       boolean realizes_damage;
+       const char *wepdesc;
+       static const char you[] = "you";
+       char hittee[BUFSZ];
+
+       Strcpy(hittee, youdefend ? you : mon_nam(mdef));
+
+       /* The following takes care of most of the damage, but not all--
+        * the exception being for level draining, which is specially
+        * handled.  Messages are done in this function, however.
+        */
+       *dmgptr += spec_dbon(otmp, mdef, *dmgptr);
+
+       if (youattack && youdefend) {
+           impossible("attacking yourself with weapon?");
+           return FALSE;
+       }
+
+       realizes_damage = (youdefend || vis || 
+                          /* feel the effect even if not seen */
+                          (youattack && mdef == u.ustuck));
+
+       /* the four basic attacks: fire, cold, shock and missiles */
+       if (attacks(AD_FIRE, otmp)) {
+           if (realizes_damage)
+               pline_The("fiery blade %s %s%c",
+                       !spec_dbon_applies ? "hits" :
+                       (mdef->data == &mons[PM_WATER_ELEMENTAL]) ?
+                       "vaporizes part of" : "burns",
+                       hittee, !spec_dbon_applies ? '.' : '!');
+           if (!rn2(4)) (void) destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
+           if (!rn2(4)) (void) destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
+           if (!rn2(7)) (void) destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
+           if (youdefend && Slimed) burn_away_slime();
+           return realizes_damage;
+       }
+       if (attacks(AD_COLD, otmp)) {
+           if (realizes_damage)
+               pline_The("ice-cold blade %s %s%c",
+                       !spec_dbon_applies ? "hits" : "freezes",
+                       hittee, !spec_dbon_applies ? '.' : '!');
+           if (!rn2(4)) (void) destroy_mitem(mdef, POTION_CLASS, AD_COLD);
+           return realizes_damage;
+       }
+       if (attacks(AD_ELEC, otmp)) {
+           if (realizes_damage)
+               pline_The("massive hammer hits%s %s%c",
+                         !spec_dbon_applies ? "" : "!  Lightning strikes",
+                         hittee, !spec_dbon_applies ? '.' : '!');
+           if (!rn2(5)) (void) destroy_mitem(mdef, RING_CLASS, AD_ELEC);
+           if (!rn2(5)) (void) destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
+           return realizes_damage;
+       }
+       if (attacks(AD_MAGM, otmp)) {
+           if (realizes_damage)
+               pline_The("imaginary widget hits%s %s%c",
+                         !spec_dbon_applies ? "" :
+                               "!  A hail of magic missiles strikes",
+                         hittee, !spec_dbon_applies ? '.' : '!');
+           return realizes_damage;
+       }
+
+       if (attacks(AD_STUN, otmp) && dieroll <= MB_MAX_DIEROLL) {
+           /* Magicbane's special attacks (possibly modifies hittee[]) */
+           return Mb_hit(magr, mdef, otmp, dmgptr, dieroll, vis, hittee);
+       }
+
+       if (!spec_dbon_applies) {
+           /* since damage bonus didn't apply, nothing more to do;  
+              no further attacks have side-effects on inventory */
+           return FALSE;
+       }
+
+       /* We really want "on a natural 20" but Nethack does it in */
+       /* reverse from AD&D. */
+       if (spec_ability(otmp, SPFX_BEHEAD)) {
+           if (otmp->oartifact == ART_TSURUGI_OF_MURAMASA && dieroll == 1) {
+               wepdesc = "The razor-sharp blade";
+               /* not really beheading, but so close, why add another SPFX */
+               if (youattack && u.uswallow && mdef == u.ustuck) {
+                   You("slice %s wide open!", mon_nam(mdef));
+                   *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
+                   return TRUE;
+               }
+               if (!youdefend) {
+                       /* allow normal cutworm() call to add extra damage */
+                       if(notonhead)
+                           return FALSE;
+
+                       if (bigmonst(mdef->data)) {
+                               if (youattack)
+                                       You("slice deeply into %s!",
+                                               mon_nam(mdef));
+                               else if (vis)
+                                       pline("%s cuts deeply into %s!",
+                                             Monnam(magr), hittee);
+                               *dmgptr *= 2;
+                               return TRUE;
+                       }
+                       *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
+                       pline("%s cuts %s in half!", wepdesc, mon_nam(mdef));
+                       otmp->dknown = TRUE;
+                       return TRUE;
+               } else {
+                       if (bigmonst(youmonst.data)) {
+                               pline("%s cuts deeply into you!",
+                                     magr ? Monnam(magr) : wepdesc);
+                               *dmgptr *= 2;
+                               return TRUE;
+                       }
+
+                       /* Players with negative AC's take less damage instead
+                        * of just not getting hit.  We must add a large enough
+                        * value to the damage so that this reduction in
+                        * damage does not prevent death.
+                        */
+                       *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER;
+                       pline("%s cuts you in half!", wepdesc);
+                       otmp->dknown = TRUE;
+                       return TRUE;
+               }
+           } else if (otmp->oartifact == ART_VORPAL_BLADE &&
+                       (dieroll == 1 || mdef->data == &mons[PM_JABBERWOCK])) {
+               static const char * const behead_msg[2] = {
+                    "%s beheads %s!",
+                    "%s decapitates %s!"
+               };
+
+               if (youattack && u.uswallow && mdef == u.ustuck)
+                       return FALSE;
+               wepdesc = artilist[ART_VORPAL_BLADE].name;
+               if (!youdefend) {
+                       if (!has_head(mdef->data) || notonhead || u.uswallow) {
+                               if (youattack)
+                                       pline("Somehow, you miss %s wildly.",
+                                               mon_nam(mdef));
+                               else if (vis)
+                                       pline("Somehow, %s misses wildly.",
+                                               mon_nam(magr));
+                               *dmgptr = 0;
+                               return ((boolean)(youattack || vis));
+                       }
+                       if (noncorporeal(mdef->data) || amorphous(mdef->data)) {
+                               pline("%s slices through %s %s.", wepdesc,
+                                     s_suffix(mon_nam(mdef)),
+                                     mbodypart(mdef,NECK));
+                               return TRUE;
+                       }
+                       *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
+                       pline(behead_msg[rn2(SIZE(behead_msg))],
+                             wepdesc, mon_nam(mdef));
+                       otmp->dknown = TRUE;
+                       return TRUE;
+               } else {
+                       if (!has_head(youmonst.data)) {
+                               pline("Somehow, %s misses you wildly.",
+                                     magr ? mon_nam(magr) : wepdesc);
+                               *dmgptr = 0;
+                               return TRUE;
+                       }
+                       if (noncorporeal(youmonst.data) || amorphous(youmonst.data)) {
+                               pline("%s slices through your %s.",
+                                     wepdesc, body_part(NECK));
+                               return TRUE;
+                       }
+                       *dmgptr = 2 * (Upolyd ? u.mh : u.uhp)
+                                 + FATAL_DAMAGE_MODIFIER;
+                       pline(behead_msg[rn2(SIZE(behead_msg))],
+                             wepdesc, "you");
+                       otmp->dknown = TRUE;
+                       /* Should amulets fall off? */
+                       return TRUE;
+               }
+           }
+       }
+       if (spec_ability(otmp, SPFX_DRLI)) {
+               if (!youdefend) {
+                       if (vis) {
+                           if(otmp->oartifact == ART_STORMBRINGER)
+                               pline_The("%s blade draws the life from %s!",
+                                     hcolor(NH_BLACK),
+                                     mon_nam(mdef));
+                           else
+                               pline("%s draws the life from %s!",
+                                     The(distant_name(otmp, xname)),
+                                     mon_nam(mdef));
+                       }
+                       if (mdef->m_lev == 0) {
+                           *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
+                       } else {
+                           int drain = rnd(8);
+                           *dmgptr += drain;
+                           mdef->mhpmax -= drain;
+                           mdef->m_lev--;
+                           drain /= 2;
+                           if (drain) healup(drain, 0, FALSE, FALSE);
+                       }
+                       return vis;
+               } else { /* youdefend */
+                       int oldhpmax = u.uhpmax;
+
+                       if (Blind)
+                               You_feel("an %s drain your life!",
+                                   otmp->oartifact == ART_STORMBRINGER ?
+                                   "unholy blade" : "object");
+                       else if (otmp->oartifact == ART_STORMBRINGER)
+                               pline_The("%s blade drains your life!",
+                                     hcolor(NH_BLACK));
+                       else
+                               pline("%s drains your life!",
+                                     The(distant_name(otmp, xname)));
+                       losexp("life drainage");
+                       if (magr && magr->mhp < magr->mhpmax) {
+                           magr->mhp += (oldhpmax - u.uhpmax)/2;
+                           if (magr->mhp > magr->mhpmax) magr->mhp = magr->mhpmax;
+                       }
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+static NEARDATA const char recharge_type[] = { ALLOW_COUNT, ALL_CLASSES, 0 };
+static NEARDATA const char invoke_types[] = { ALL_CLASSES, 0 };
+               /* #invoke: an "ugly check" filters out most objects */
+
+int
+doinvoke()
+{
+    register struct obj *obj;
+
+    obj = getobj(invoke_types, "invoke");
+    if (!obj) return 0;
+    if (obj->oartifact && !touch_artifact(obj, &youmonst)) return 1;
+    return arti_invoke(obj);
+}
+
+STATIC_OVL int
+arti_invoke(obj)
+    register struct obj *obj;
+{
+    register const struct artifact *oart = get_artifact(obj);
+
+    if(!oart || !oart->inv_prop) {
+       if(obj->otyp == CRYSTAL_BALL)
+           use_crystal_ball(obj);
+       else
+           pline(nothing_happens);
+       return 1;
+    }
+
+    if(oart->inv_prop > LAST_PROP) {
+       /* It's a special power, not "just" a property */
+       if(obj->age > monstermoves) {
+           /* the artifact is tired :-) */
+           You_feel("that %s %s ignoring you.",
+                    the(xname(obj)), otense(obj, "are"));
+           /* and just got more so; patience is essential... */
+           obj->age += (long) d(3,10);
+           return 1;
+       }
+       obj->age = monstermoves + rnz(100);
+
+       switch(oart->inv_prop) {
+       case TAMING: {
+           struct obj pseudo;
+
+           pseudo = zeroobj;   /* neither cursed nor blessed */
+           pseudo.otyp = SCR_TAMING;
+           (void) seffects(&pseudo);
+           break;
+         }
+       case HEALING: {
+           int healamt = (u.uhpmax + 1 - u.uhp) / 2;
+           long creamed = (long)u.ucreamed;
+
+           if (Upolyd) healamt = (u.mhmax + 1 - u.mh) / 2;
+           if (healamt || Sick || Slimed || Blinded > creamed)
+               You_feel("better.");
+           else
+               goto nothing_special;
+           if (healamt > 0) {
+               if (Upolyd) u.mh += healamt;
+               else u.uhp += healamt;
+           }
+           if(Sick) make_sick(0L,(char *)0,FALSE,SICK_ALL);
+           if(Slimed) Slimed = 0L;
+           if (Blinded > creamed) make_blinded(creamed, FALSE);
+           flags.botl = 1;
+           break;
+         }
+       case ENERGY_BOOST: {
+           int epboost = (u.uenmax + 1 - u.uen) / 2;
+           if (epboost > 120) epboost = 120;           /* arbitrary */
+           else if (epboost < 12) epboost = u.uenmax - u.uen;
+           if(epboost) {
+               You_feel("re-energized.");
+               u.uen += epboost;
+               flags.botl = 1;
+           } else
+               goto nothing_special;
+           break;
+         }
+       case UNTRAP: {
+           if(!untrap(TRUE)) {
+               obj->age = 0; /* don't charge for changing their mind */
+               return 0;
+           }
+           break;
+         }
+       case CHARGE_OBJ: {
+           struct obj *otmp = getobj(recharge_type, "charge");
+           boolean b_effect;
+
+           if (!otmp) {
+               obj->age = 0;
+               return 0;
+           }
+           b_effect = obj->blessed &&
+               (Role_switch == oart->role || !oart->role);
+           recharge(otmp, b_effect ? 1 : obj->cursed ? -1 : 0);
+           update_inventory();
+           break;
+         }
+       case LEV_TELE:
+           level_tele();
+           break;
+       case CREATE_PORTAL: {
+           int i, num_ok_dungeons, last_ok_dungeon = 0;
+           d_level newlev;
+           extern int n_dgns; /* from dungeon.c */
+           winid tmpwin = create_nhwindow(NHW_MENU);
+           anything any;
+
+           any.a_void = 0;     /* set all bits to zero */
+           start_menu(tmpwin);
+           /* use index+1 (cant use 0) as identifier */
+           for (i = num_ok_dungeons = 0; i < n_dgns; i++) {
+               if (!dungeons[i].dunlev_ureached) continue;
+               any.a_int = i+1;
+               add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                        dungeons[i].dname, MENU_UNSELECTED);
+               num_ok_dungeons++;
+               last_ok_dungeon = i;
+           }
+           end_menu(tmpwin, "Open a portal to which dungeon?");
+           if (num_ok_dungeons > 1) {
+               /* more than one entry; display menu for choices */
+               menu_item *selected;
+               int n;
+
+               n = select_menu(tmpwin, PICK_ONE, &selected);
+               if (n <= 0) {
+                   destroy_nhwindow(tmpwin);
+                   goto nothing_special;
+               }
+               i = selected[0].item.a_int - 1;
+               free((genericptr_t)selected);
+           } else
+               i = last_ok_dungeon;    /* also first & only OK dungeon */
+           destroy_nhwindow(tmpwin);
+
+           /*
+            * i is now index into dungeon structure for the new dungeon.
+            * Find the closest level in the given dungeon, open
+            * a use-once portal to that dungeon and go there.
+            * The closest level is either the entry or dunlev_ureached.
+            */
+           newlev.dnum = i;
+           if(dungeons[i].depth_start >= depth(&u.uz))
+               newlev.dlevel = dungeons[i].entry_lev;
+           else
+               newlev.dlevel = dungeons[i].dunlev_ureached;
+           if(u.uhave.amulet || In_endgame(&u.uz) || In_endgame(&newlev) ||
+              newlev.dnum == u.uz.dnum) {
+               You_feel("very disoriented for a moment.");
+           } else {
+               if(!Blind) You("are surrounded by a shimmering sphere!");
+               else You_feel("weightless for a moment.");
+               goto_level(&newlev, FALSE, FALSE, FALSE);
+           }
+           break;
+         }
+       case ENLIGHTENING:
+           enlightenment(0);
+           break;
+       case CREATE_AMMO: {
+           struct obj *otmp = mksobj(ARROW, TRUE, FALSE);
+
+           if (!otmp) goto nothing_special;
+           otmp->blessed = obj->blessed;
+           otmp->cursed = obj->cursed;
+           otmp->bknown = obj->bknown;
+           if (obj->blessed) {
+               if (otmp->spe < 0) otmp->spe = 0;
+               otmp->quan += rnd(10);
+           } else if (obj->cursed) {
+               if (otmp->spe > 0) otmp->spe = 0;
+           } else
+               otmp->quan += rnd(5);
+           otmp->owt = weight(otmp);
+           otmp = hold_another_object(otmp, "Suddenly %s out.",
+                                      aobjnam(otmp, "fall"), (const char *)0);
+           break;
+         }
+       }
+    } else {
+       long eprop = (u.uprops[oart->inv_prop].extrinsic ^= W_ARTI),
+            iprop = u.uprops[oart->inv_prop].intrinsic;
+       boolean on = (eprop & W_ARTI) != 0; /* true if invoked prop just set */
+
+       if(on && obj->age > monstermoves) {
+           /* the artifact is tired :-) */
+           u.uprops[oart->inv_prop].extrinsic ^= W_ARTI;
+           You_feel("that %s %s ignoring you.",
+                    the(xname(obj)), otense(obj, "are"));
+           /* can't just keep repeatedly trying */
+           obj->age += (long) d(3,10);
+           return 1;
+       } else if(!on) {
+           /* when turning off property, determine downtime */
+           /* arbitrary for now until we can tune this -dlc */
+           obj->age = monstermoves + rnz(100);
+       }
+
+       if ((eprop & ~W_ARTI) || iprop) {
+nothing_special:
+           /* you had the property from some other source too */
+           if (carried(obj))
+               You_feel("a surge of power, but nothing seems to happen.");
+           return 1;
+       }
+       switch(oart->inv_prop) {
+       case CONFLICT:
+           if(on) You_feel("like a rabble-rouser.");
+           else You_feel("the tension decrease around you.");
+           break;
+       case LEVITATION:
+           if(on) {
+               float_up();
+               spoteffects(FALSE);
+           } else (void) float_down(I_SPECIAL|TIMEOUT, W_ARTI);
+           break;
+       case INVIS:
+           if (BInvis || Blind) goto nothing_special;
+           newsym(u.ux, u.uy);
+           if (on)
+               Your("body takes on a %s transparency...",
+                    Hallucination ? "normal" : "strange");
+           else
+               Your("body seems to unfade...");
+           break;
+       }
+    }
+
+    return 1;
+}
+
+
+/* WAC return TRUE if artifact is always lit */
+boolean
+artifact_light(obj)
+    struct obj *obj;
+{
+    return (get_artifact(obj) && obj->oartifact == ART_SUNSWORD);
+}
+
+/* KMH -- Talking artifacts are finally implemented */
+void
+arti_speak(obj)
+    struct obj *obj;
+{
+       register const struct artifact *oart = get_artifact(obj);
+       const char *line;
+       char buf[BUFSZ];
+
+
+       /* Is this a speaking artifact? */
+       if (!oart || !(oart->spfx & SPFX_SPEAK))
+               return;
+
+       line = getrumor(bcsign(obj), buf, TRUE);
+       if (!*line)
+               line = "NetHack rumors file closed for renovation.";
+       pline("%s:", Tobjnam(obj, "whisper"));
+       verbalize("%s", line);
+       return;
+}
+
+boolean
+artifact_has_invprop(otmp, inv_prop)
+struct obj *otmp;
+uchar inv_prop;
+{
+       const struct artifact *arti = get_artifact(otmp);
+
+       return((boolean)(arti && (arti->inv_prop == inv_prop)));
+}
+
+/* Return the price sold to the hero of a given artifact or unique item */
+long
+arti_cost(otmp)
+struct obj *otmp;
+{
+       if (!otmp->oartifact)
+           return ((long)objects[otmp->otyp].oc_cost);
+       else if (artilist[(int) otmp->oartifact].cost)
+           return (artilist[(int) otmp->oartifact].cost);
+       else
+           return (100L * (long)objects[otmp->otyp].oc_cost);
+}
+
+#endif /* OVLB */
+
+/*artifact.c*/
diff --git a/src/attrib.c b/src/attrib.c
new file mode 100644 (file)
index 0000000..e4fab6f
--- /dev/null
@@ -0,0 +1,731 @@
+/*     SCCS Id: @(#)attrib.c   3.4     2002/10/07      */
+/*     Copyright 1988, 1989, 1990, 1992, M. Stephenson           */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*  attribute modification routines. */
+
+#include "hack.h"
+
+/* #define DEBUG */    /* uncomment for debugging info */
+
+#ifdef OVLB
+
+       /* part of the output on gain or loss of attribute */
+static
+const char     * const plusattr[] = {
+       "strong", "smart", "wise", "agile", "tough", "charismatic"
+},
+               * const minusattr[] = {
+       "weak", "stupid", "foolish", "clumsy", "fragile", "repulsive"
+};
+
+
+static
+const struct innate {
+       schar   ulevel;
+       long    *ability;
+       const char *gainstr, *losestr;
+}      arc_abil[] = { {         1, &(HStealth), "", "" },
+                    {   1, &(HFast), "", "" },
+                    {  10, &(HSearching), "perceptive", "" },
+                    {   0, 0, 0, 0 } },
+
+       bar_abil[] = { {         1, &(HPoison_resistance), "", "" },
+                    {   7, &(HFast), "quick", "slow" },
+                    {  15, &(HStealth), "stealthy", "" },
+                    {   0, 0, 0, 0 } },
+
+       cav_abil[] = { {         7, &(HFast), "quick", "slow" },
+                    {  15, &(HWarning), "sensitive", "" },
+                    {   0, 0, 0, 0 } },
+
+       hea_abil[] = { {         1, &(HPoison_resistance), "", "" },
+                    {  15, &(HWarning), "sensitive", "" },
+                    {   0, 0, 0, 0 } },
+
+       kni_abil[] = { {         7, &(HFast), "quick", "slow" },
+                    {   0, 0, 0, 0 } },
+
+       mon_abil[] = { {   1, &(HFast), "", "" },
+                    {   1, &(HSleep_resistance), "", "" },
+                    {   1, &(HSee_invisible), "", "" },
+                    {   3, &(HPoison_resistance), "healthy", "" },
+                    {   5, &(HStealth), "stealthy", "" },
+                    {   7, &(HWarning), "sensitive", "" },
+                    {   9, &(HSearching), "perceptive", "unaware" },
+                    {  11, &(HFire_resistance), "cool", "warmer" },
+                    {  13, &(HCold_resistance), "warm", "cooler" },
+                    {  15, &(HShock_resistance), "insulated", "conductive" },
+                    {  17, &(HTeleport_control), "controlled","uncontrolled" },
+                    {   0, 0, 0, 0 } },
+
+       pri_abil[] = { {        15, &(HWarning), "sensitive", "" },
+                    {  20, &(HFire_resistance), "cool", "warmer" },
+                    {   0, 0, 0, 0 } },
+
+       ran_abil[] = { {   1, &(HSearching), "", "" },
+                    {   7, &(HStealth), "stealthy", "" },
+                    {  15, &(HSee_invisible), "", "" },
+                    {   0, 0, 0, 0 } },
+
+       rog_abil[] = { {         1, &(HStealth), "", ""  },
+                    {  10, &(HSearching), "perceptive", "" },
+                    {   0, 0, 0, 0 } },
+
+       sam_abil[] = { {         1, &(HFast), "", "" },
+                    {  15, &(HStealth), "stealthy", "" },
+                    {   0, 0, 0, 0 } },
+
+       tou_abil[] = { {        10, &(HSearching), "perceptive", "" },
+                    {  20, &(HPoison_resistance), "hardy", "" },
+                    {   0, 0, 0, 0 } },
+
+       val_abil[] = { {         1, &(HCold_resistance), "", "" },
+                    {   1, &(HStealth), "", "" },
+                    {   7, &(HFast), "quick", "slow" },
+                    {   0, 0, 0, 0 } },
+
+       wiz_abil[] = { {        15, &(HWarning), "sensitive", "" },
+                    {  17, &(HTeleport_control), "controlled","uncontrolled" },
+                    {   0, 0, 0, 0 } },
+
+       /* Intrinsics conferred by race */
+       elf_abil[] = { {        4, &(HSleep_resistance), "awake", "tired" },
+                    {   0, 0, 0, 0 } },
+
+       orc_abil[] = { {        1, &(HPoison_resistance), "", "" },
+                    {   0, 0, 0, 0 } };
+
+static long next_check = 600L; /* arbitrary first setting */
+STATIC_DCL void NDECL(exerper);
+STATIC_DCL void FDECL(postadjabil, (long *));
+
+/* adjust an attribute; return TRUE if change is made, FALSE otherwise */
+boolean
+adjattrib(ndx, incr, msgflg)
+       int     ndx, incr;
+       int     msgflg;     /* positive => no message, zero => message, and */
+{                          /* negative => conditional (msg if change made) */
+       if (Fixed_abil || !incr) return FALSE;
+
+       if ((ndx == A_INT || ndx == A_WIS)
+                               && uarmh && uarmh->otyp == DUNCE_CAP) {
+               if (msgflg == 0)
+                   Your("cap constricts briefly, then relaxes again.");
+               return FALSE;
+       }
+
+       if (incr > 0) {
+           if ((AMAX(ndx) >= ATTRMAX(ndx)) && (ACURR(ndx) >= AMAX(ndx))) {
+               if (msgflg == 0 && flags.verbose)
+                   pline("You're already as %s as you can get.",
+                         plusattr[ndx]);
+               ABASE(ndx) = AMAX(ndx) = ATTRMAX(ndx); /* just in case */
+               return FALSE;
+           }
+
+           ABASE(ndx) += incr;
+           if(ABASE(ndx) > AMAX(ndx)) {
+               incr = ABASE(ndx) - AMAX(ndx);
+               AMAX(ndx) += incr;
+               if(AMAX(ndx) > ATTRMAX(ndx))
+                   AMAX(ndx) = ATTRMAX(ndx);
+               ABASE(ndx) = AMAX(ndx);
+           }
+       } else {
+           if (ABASE(ndx) <= ATTRMIN(ndx)) {
+               if (msgflg == 0 && flags.verbose)
+                   pline("You're already as %s as you can get.",
+                         minusattr[ndx]);
+               ABASE(ndx) = ATTRMIN(ndx); /* just in case */
+               return FALSE;
+           }
+
+           ABASE(ndx) += incr;
+           if(ABASE(ndx) < ATTRMIN(ndx)) {
+               incr = ABASE(ndx) - ATTRMIN(ndx);
+               ABASE(ndx) = ATTRMIN(ndx);
+               AMAX(ndx) += incr;
+               if(AMAX(ndx) < ATTRMIN(ndx))
+                   AMAX(ndx) = ATTRMIN(ndx);
+           }
+       }
+       if (msgflg <= 0)
+           You_feel("%s%s!",
+                 (incr > 1 || incr < -1) ? "very ": "",
+                 (incr > 0) ? plusattr[ndx] : minusattr[ndx]);
+       flags.botl = 1;
+       if (moves > 1 && (ndx == A_STR || ndx == A_CON))
+               (void)encumber_msg();
+       return TRUE;
+}
+
+void
+gainstr(otmp, incr)
+       register struct obj *otmp;
+       register int incr;
+{
+       int num = 1;
+
+       if(incr) num = incr;
+       else {
+           if(ABASE(A_STR) < 18) num = (rn2(4) ? 1 : rnd(6) );
+           else if (ABASE(A_STR) < STR18(85)) num = rnd(10);
+       }
+       (void) adjattrib(A_STR, (otmp && otmp->cursed) ? -num : num, TRUE);
+}
+
+void
+losestr(num)   /* may kill you; cause may be poison or monster like 'a' */
+       register int num;
+{
+       int ustr = ABASE(A_STR) - num;
+
+       while(ustr < 3) {
+           ++ustr;
+           --num;
+           if (Upolyd) {
+               u.mh -= 6;
+               u.mhmax -= 6;
+           } else {
+               u.uhp -= 6;
+               u.uhpmax -= 6;
+           }
+       }
+       (void) adjattrib(A_STR, -num, TRUE);
+}
+
+void
+change_luck(n)
+       register schar n;
+{
+       u.uluck += n;
+       if (u.uluck < 0 && u.uluck < LUCKMIN)   u.uluck = LUCKMIN;
+       if (u.uluck > 0 && u.uluck > LUCKMAX)   u.uluck = LUCKMAX;
+}
+
+int
+stone_luck(parameter)
+boolean parameter; /* So I can't think up of a good name.  So sue me. --KAA */
+{
+       register struct obj *otmp;
+       register long bonchance = 0;
+
+       for (otmp = invent; otmp; otmp = otmp->nobj)
+           if (confers_luck(otmp)) {
+               if (otmp->cursed) bonchance -= otmp->quan;
+               else if (otmp->blessed) bonchance += otmp->quan;
+               else if (parameter) bonchance += otmp->quan;
+           }
+
+       return sgn((int)bonchance);
+}
+
+/* there has just been an inventory change affecting a luck-granting item */
+void
+set_moreluck()
+{
+       int luckbon = stone_luck(TRUE);
+
+       if (!luckbon && !carrying(LUCKSTONE)) u.moreluck = 0;
+       else if (luckbon >= 0) u.moreluck = LUCKADD;
+       else u.moreluck = -LUCKADD;
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+void
+restore_attrib()
+{
+       int     i;
+
+       for(i = 0; i < A_MAX; i++) {    /* all temporary losses/gains */
+
+          if(ATEMP(i) && ATIME(i)) {
+               if(!(--(ATIME(i)))) { /* countdown for change */
+                   ATEMP(i) += ATEMP(i) > 0 ? -1 : 1;
+
+                   if(ATEMP(i)) /* reset timer */
+                       ATIME(i) = 100 / ACURR(A_CON);
+               }
+           }
+       }
+       (void)encumber_msg();
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+#define AVAL   50              /* tune value for exercise gains */
+
+void
+exercise(i, inc_or_dec)
+int    i;
+boolean        inc_or_dec;
+{
+#ifdef DEBUG
+       pline("Exercise:");
+#endif
+       if (i == A_INT || i == A_CHA) return;   /* can't exercise these */
+
+       /* no physical exercise while polymorphed; the body's temporary */
+       if (Upolyd && i != A_WIS) return;
+
+       if(abs(AEXE(i)) < AVAL) {
+               /*
+                *      Law of diminishing returns (Part I):
+                *
+                *      Gain is harder at higher attribute values.
+                *      79% at "3" --> 0% at "18"
+                *      Loss is even at all levels (50%).
+                *
+                *      Note: *YES* ACURR is the right one to use.
+                */
+               AEXE(i) += (inc_or_dec) ? (rn2(19) > ACURR(i)) : -rn2(2);
+#ifdef DEBUG
+               pline("%s, %s AEXE = %d",
+                       (i == A_STR) ? "Str" : (i == A_WIS) ? "Wis" :
+                       (i == A_DEX) ? "Dex" : "Con",
+                       (inc_or_dec) ? "inc" : "dec", AEXE(i));
+#endif
+       }
+       if (moves > 0 && (i == A_STR || i == A_CON)) (void)encumber_msg();
+}
+
+/* hunger values - from eat.c */
+#define SATIATED       0
+#define NOT_HUNGRY     1
+#define HUNGRY         2
+#define WEAK           3
+#define FAINTING       4
+#define FAINTED                5
+#define STARVED                6
+
+STATIC_OVL void
+exerper()
+{
+       if(!(moves % 10)) {
+               /* Hunger Checks */
+
+               int hs = (u.uhunger > 1000) ? SATIATED :
+                        (u.uhunger > 150) ? NOT_HUNGRY :
+                        (u.uhunger > 50) ? HUNGRY :
+                        (u.uhunger > 0) ? WEAK : FAINTING;
+
+#ifdef DEBUG
+               pline("exerper: Hunger checks");
+#endif
+               switch (hs) {
+                   case SATIATED:      exercise(A_DEX, FALSE);
+                                       if (Role_if(PM_MONK))
+                                           exercise(A_WIS, FALSE);
+                                       break;
+                   case NOT_HUNGRY:    exercise(A_CON, TRUE); break;
+                   case WEAK:          exercise(A_STR, FALSE);
+                                       if (Role_if(PM_MONK))   /* fasting */
+                                           exercise(A_WIS, TRUE);
+                                       break;
+                   case FAINTING:
+                   case FAINTED:       exercise(A_CON, FALSE); break;
+               }
+
+               /* Encumberance Checks */
+#ifdef DEBUG
+               pline("exerper: Encumber checks");
+#endif
+               switch (near_capacity()) {
+                   case MOD_ENCUMBER:  exercise(A_STR, TRUE); break;
+                   case HVY_ENCUMBER:  exercise(A_STR, TRUE);
+                                       exercise(A_DEX, FALSE); break;
+                   case EXT_ENCUMBER:  exercise(A_DEX, FALSE);
+                                       exercise(A_CON, FALSE); break;
+               }
+
+       }
+
+       /* status checks */
+       if(!(moves % 5)) {
+#ifdef DEBUG
+               pline("exerper: Status checks");
+#endif
+               if ((HClairvoyant & (INTRINSIC|TIMEOUT)) &&
+                       !BClairvoyant)                      exercise(A_WIS, TRUE);
+               if (HRegeneration)                      exercise(A_STR, TRUE);
+
+               if(Sick || Vomiting)     exercise(A_CON, FALSE);
+               if(Confusion || Hallucination)          exercise(A_WIS, FALSE);
+               if((Wounded_legs 
+#ifdef STEED
+                   && !u.usteed
+#endif
+                           ) || Fumbling || HStun)     exercise(A_DEX, FALSE);
+       }
+}
+
+void
+exerchk()
+{
+       int     i, mod_val;
+
+       /*      Check out the periodic accumulations */
+       exerper();
+
+#ifdef DEBUG
+       if(moves >= next_check)
+               pline("exerchk: ready to test. multi = %d.", multi);
+#endif
+       /*      Are we ready for a test?        */
+       if(moves >= next_check && !multi) {
+#ifdef DEBUG
+           pline("exerchk: testing.");
+#endif
+           /*
+            *  Law of diminishing returns (Part II):
+            *
+            *  The effects of "exercise" and "abuse" wear
+            *  off over time.  Even if you *don't* get an
+            *  increase/decrease, you lose some of the
+            *  accumulated effects.
+            */
+           for(i = 0; i < A_MAX; AEXE(i++) /= 2) {
+
+               if(ABASE(i) >= 18 || !AEXE(i)) continue;
+               if(i == A_INT || i == A_CHA) continue;/* can't exercise these */
+
+#ifdef DEBUG
+               pline("exerchk: testing %s (%d).",
+                       (i == A_STR) ? "Str" : (i == A_WIS) ? "Wis" :
+                       (i == A_DEX) ? "Dex" : "Con", AEXE(i));
+#endif
+               /*
+                *      Law of diminishing returns (Part III):
+                *
+                *      You don't *always* gain by exercising.
+                *      [MRS 92/10/28 - Treat Wisdom specially for balance.]
+                */
+               if(rn2(AVAL) > ((i != A_WIS) ? abs(AEXE(i)*2/3) : abs(AEXE(i))))
+                   continue;
+               mod_val = sgn(AEXE(i));
+
+#ifdef DEBUG
+               pline("exerchk: changing %d.", i);
+#endif
+               if(adjattrib(i, mod_val, -1)) {
+#ifdef DEBUG
+                   pline("exerchk: changed %d.", i);
+#endif
+                   /* if you actually changed an attrib - zero accumulation */
+                   AEXE(i) = 0;
+                   /* then print an explanation */
+                   switch(i) {
+                   case A_STR: You((mod_val >0) ?
+                                   "must have been exercising." :
+                                   "must have been abusing your body.");
+                               break;
+                   case A_WIS: You((mod_val >0) ?
+                                   "must have been very observant." :
+                                   "haven't been paying attention.");
+                               break;
+                   case A_DEX: You((mod_val >0) ?
+                                   "must have been working on your reflexes." :
+                                   "haven't been working on reflexes lately.");
+                               break;
+                   case A_CON: You((mod_val >0) ?
+                                   "must be leading a healthy life-style." :
+                                   "haven't been watching your health.");
+                               break;
+                   }
+               }
+           }
+           next_check += rn1(200,800);
+#ifdef DEBUG
+           pline("exerchk: next check at %ld.", next_check);
+#endif
+       }
+}
+
+/* next_check will otherwise have its initial 600L after a game restore */
+void
+reset_attribute_clock()
+{
+       if (moves > 600L) next_check = moves + rn1(50,800);
+}
+
+
+void
+init_attr(np)
+       register int    np;
+{
+       register int    i, x, tryct;
+
+
+       for(i = 0; i < A_MAX; i++) {
+           ABASE(i) = AMAX(i) = urole.attrbase[i];
+           ATEMP(i) = ATIME(i) = 0;
+           np -= urole.attrbase[i];
+       }
+
+       tryct = 0;
+       while(np > 0 && tryct < 100) {
+
+           x = rn2(100);
+           for (i = 0; (i < A_MAX) && ((x -= urole.attrdist[i]) > 0); i++) ;
+           if(i >= A_MAX) continue; /* impossible */
+
+           if(ABASE(i) >= ATTRMAX(i)) {
+
+               tryct++;
+               continue;
+           }
+           tryct = 0;
+           ABASE(i)++;
+           AMAX(i)++;
+           np--;
+       }
+
+       tryct = 0;
+       while(np < 0 && tryct < 100) {          /* for redistribution */
+
+           x = rn2(100);
+           for (i = 0; (i < A_MAX) && ((x -= urole.attrdist[i]) > 0); i++) ;
+           if(i >= A_MAX) continue; /* impossible */
+
+           if(ABASE(i) <= ATTRMIN(i)) {
+
+               tryct++;
+               continue;
+           }
+           tryct = 0;
+           ABASE(i)--;
+           AMAX(i)--;
+           np++;
+       }
+}
+
+void
+redist_attr()
+{
+       register int i, tmp;
+
+       for(i = 0; i < A_MAX; i++) {
+           if (i==A_INT || i==A_WIS) continue;
+               /* Polymorphing doesn't change your mind */
+           tmp = AMAX(i);
+           AMAX(i) += (rn2(5)-2);
+           if (AMAX(i) > ATTRMAX(i)) AMAX(i) = ATTRMAX(i);
+           if (AMAX(i) < ATTRMIN(i)) AMAX(i) = ATTRMIN(i);
+           ABASE(i) = ABASE(i) * AMAX(i) / tmp;
+           /* ABASE(i) > ATTRMAX(i) is impossible */
+           if (ABASE(i) < ATTRMIN(i)) ABASE(i) = ATTRMIN(i);
+       }
+       (void)encumber_msg();
+}
+
+STATIC_OVL
+void
+postadjabil(ability)
+long *ability;
+{
+       if (!ability) return;
+       if (ability == &(HWarning) || ability == &(HSee_invisible))
+               see_monsters();
+}
+
+void
+adjabil(oldlevel,newlevel)
+int oldlevel, newlevel;
+{
+       register const struct innate *abil, *rabil;
+       long mask = FROMEXPER;
+
+
+       switch (Role_switch) {
+       case PM_ARCHEOLOGIST:   abil = arc_abil;        break;
+       case PM_BARBARIAN:      abil = bar_abil;        break;
+       case PM_CAVEMAN:        abil = cav_abil;        break;
+       case PM_HEALER:         abil = hea_abil;        break;
+       case PM_KNIGHT:         abil = kni_abil;        break;
+       case PM_MONK:           abil = mon_abil;        break;
+       case PM_PRIEST:         abil = pri_abil;        break;
+       case PM_RANGER:         abil = ran_abil;        break;
+       case PM_ROGUE:          abil = rog_abil;        break;
+       case PM_SAMURAI:        abil = sam_abil;        break;
+#ifdef TOURIST
+       case PM_TOURIST:        abil = tou_abil;        break;
+#endif
+       case PM_VALKYRIE:       abil = val_abil;        break;
+       case PM_WIZARD:         abil = wiz_abil;        break;
+       default:                abil = 0;               break;
+       }
+
+       switch (Race_switch) {
+       case PM_ELF:            rabil = elf_abil;       break;
+       case PM_ORC:            rabil = orc_abil;       break;
+       case PM_HUMAN:
+       case PM_DWARF:
+       case PM_GNOME:
+       default:                rabil = 0;              break;
+       }
+
+       while (abil || rabil) {
+           long prevabil;
+           /* Have we finished with the intrinsics list? */
+           if (!abil || !abil->ability) {
+               /* Try the race intrinsics */
+               if (!rabil || !rabil->ability) break;
+               abil = rabil;
+               rabil = 0;
+               mask = FROMRACE;
+           }
+               prevabil = *(abil->ability);
+               if(oldlevel < abil->ulevel && newlevel >= abil->ulevel) {
+                       /* Abilities gained at level 1 can never be lost
+                        * via level loss, only via means that remove _any_
+                        * sort of ability.  A "gain" of such an ability from
+                        * an outside source is devoid of meaning, so we set
+                        * FROMOUTSIDE to avoid such gains.
+                        */
+                       if (abil->ulevel == 1)
+                               *(abil->ability) |= (mask|FROMOUTSIDE);
+                       else
+                               *(abil->ability) |= mask;
+                       if(!(*(abil->ability) & INTRINSIC & ~mask)) {
+                           if(*(abil->gainstr))
+                               You_feel("%s!", abil->gainstr);
+                       }
+               } else if (oldlevel >= abil->ulevel && newlevel < abil->ulevel) {
+                       *(abil->ability) &= ~mask;
+                       if(!(*(abil->ability) & INTRINSIC)) {
+                           if(*(abil->losestr))
+                               You_feel("%s!", abil->losestr);
+                           else if(*(abil->gainstr))
+                               You_feel("less %s!", abil->gainstr);
+                       }
+               }
+           if (prevabil != *(abil->ability))   /* it changed */
+               postadjabil(abil->ability);
+           abil++;
+       }
+
+       if (oldlevel > 0) {
+           if (newlevel > oldlevel)
+               add_weapon_skill(newlevel - oldlevel);
+           else
+               lose_weapon_skill(oldlevel - newlevel);
+       }
+}
+
+
+int
+newhp()
+{
+       int     hp, conplus;
+
+
+       if (u.ulevel == 0) {
+           /* Initialize hit points */
+           hp = urole.hpadv.infix + urace.hpadv.infix;
+           if (urole.hpadv.inrnd > 0) hp += rnd(urole.hpadv.inrnd);
+           if (urace.hpadv.inrnd > 0) hp += rnd(urace.hpadv.inrnd);
+
+           /* Initialize alignment stuff */
+           u.ualign.type = aligns[flags.initalign].value;
+           u.ualign.record = urole.initrecord;
+
+               return hp;
+       } else {
+           if (u.ulevel < urole.xlev) {
+               hp = urole.hpadv.lofix + urace.hpadv.lofix;
+               if (urole.hpadv.lornd > 0) hp += rnd(urole.hpadv.lornd);
+               if (urace.hpadv.lornd > 0) hp += rnd(urace.hpadv.lornd);
+           } else {
+               hp = urole.hpadv.hifix + urace.hpadv.hifix;
+               if (urole.hpadv.hirnd > 0) hp += rnd(urole.hpadv.hirnd);
+               if (urace.hpadv.hirnd > 0) hp += rnd(urace.hpadv.hirnd);
+           }
+       }
+
+       if (ACURR(A_CON) <= 3) conplus = -2;
+       else if (ACURR(A_CON) <= 6) conplus = -1;
+       else if (ACURR(A_CON) <= 14) conplus = 0;
+       else if (ACURR(A_CON) <= 16) conplus = 1;
+       else if (ACURR(A_CON) == 17) conplus = 2;
+       else if (ACURR(A_CON) == 18) conplus = 3;
+       else conplus = 4;
+       
+       hp += conplus;
+       return((hp <= 0) ? 1 : hp);
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+schar
+acurr(x)
+int x;
+{
+       register int tmp = (u.abon.a[x] + u.atemp.a[x] + u.acurr.a[x]);
+
+       if (x == A_STR) {
+               if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER) return(125);
+#ifdef WIN32_BUG
+               else return(x=((tmp >= 125) ? 125 : (tmp <= 3) ? 3 : tmp));
+#else
+               else return((schar)((tmp >= 125) ? 125 : (tmp <= 3) ? 3 : tmp));
+#endif
+       } else if (x == A_CHA) {
+               if (tmp < 18 && (youmonst.data->mlet == S_NYMPH ||
+                   u.umonnum==PM_SUCCUBUS || u.umonnum == PM_INCUBUS))
+                   return 18;
+       } else if (x == A_INT || x == A_WIS) {
+               /* yes, this may raise int/wis if player is sufficiently
+                * stupid.  there are lower levels of cognition than "dunce".
+                */
+               if (uarmh && uarmh->otyp == DUNCE_CAP) return(6);
+       }
+#ifdef WIN32_BUG
+       return(x=((tmp >= 25) ? 25 : (tmp <= 3) ? 3 : tmp));
+#else
+       return((schar)((tmp >= 25) ? 25 : (tmp <= 3) ? 3 : tmp));
+#endif
+}
+
+/* condense clumsy ACURR(A_STR) value into value that fits into game formulas
+ */
+schar
+acurrstr()
+{
+       register int str = ACURR(A_STR);
+
+       if (str <= 18) return((schar)str);
+       if (str <= 121) return((schar)(19 + str / 50)); /* map to 19-21 */
+       else return((schar)(str - 100));
+}
+
+#endif /* OVL0 */
+#ifdef OVL2
+
+/* avoid possible problems with alignment overflow, and provide a centralized
+ * location for any future alignment limits
+ */
+void
+adjalign(n)
+register int n;
+{
+       register int newalign = u.ualign.record + n;
+
+       if(n < 0) {
+               if(newalign < u.ualign.record)
+                       u.ualign.record = newalign;
+       } else
+               if(newalign > u.ualign.record) {
+                       u.ualign.record = newalign;
+                       if(u.ualign.record > ALIGNLIM)
+                               u.ualign.record = ALIGNLIM;
+               }
+}
+
+#endif /* OVL2 */
+
+/*attrib.c*/
diff --git a/src/ball.c b/src/ball.c
new file mode 100644 (file)
index 0000000..b2a05e0
--- /dev/null
@@ -0,0 +1,790 @@
+/*     SCCS Id: @(#)ball.c     3.4     2003/02/03      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* Ball & Chain =============================================================*/
+
+#include "hack.h"
+
+STATIC_DCL int NDECL(bc_order);
+STATIC_DCL void NDECL(litter);
+
+void
+ballfall()
+{
+       boolean gets_hit;
+
+       gets_hit = (((uball->ox != u.ux) || (uball->oy != u.uy)) &&
+                   ((uwep == uball)? FALSE : (boolean)rn2(5)));
+       if (carried(uball)) {
+               pline("Startled, you drop the iron ball.");
+               if (uwep == uball)
+                       setuwep((struct obj *)0);
+               if (uswapwep == uball)
+                       setuswapwep((struct obj *)0);
+               if (uquiver == uball)
+                       setuqwep((struct obj *)0);;
+               if (uwep != uball)
+                       freeinv(uball);
+       }
+       if(gets_hit){
+               int dmg = rn1(7,25);
+               pline_The("iron ball falls on your %s.",
+                       body_part(HEAD));
+               if (uarmh) {
+                   if(is_metallic(uarmh)) {
+                       pline("Fortunately, you are wearing a hard helmet.");
+                       dmg = 3;
+                   } else if (flags.verbose)
+                       Your("%s does not protect you.", xname(uarmh));
+               }
+               losehp(dmg, "crunched in the head by an iron ball",
+                       NO_KILLER_PREFIX);
+       }
+}
+
+/*
+ *  To make this work, we have to mess with the hero's mind.  The rules for
+ *  ball&chain are:
+ *
+ *     1. If the hero can see them, fine.
+ *     2. If the hero can't see either, it isn't seen.
+ *     3. If either is felt it is seen.
+ *     4. If either is felt and moved, it disappears.
+ *
+ *  If the hero can see, then when a move is done, the ball and chain are
+ *  first picked up, the positions under them are corrected, then they
+ *  are moved after the hero moves.  Not too bad.
+ *
+ *  If the hero is blind, then she can "feel" the ball and/or chain at any
+ *  time.  However, when the hero moves, the felt ball and/or chain become
+ *  unfelt and whatever was felt "under" the ball&chain appears.  Pretty
+ *  nifty, but it requires that the ball&chain "remember" what was under
+ *  them --- i.e. they pick-up glyphs when they are felt and drop them when
+ *  moved (and felt).  When swallowed, the ball&chain are pulled completely
+ *  off of the dungeon, but are still on the object chain.  They are placed
+ *  under the hero when she is expelled.
+ */
+
+/*
+ * from you.h
+ *     int u.bglyph            glyph under the ball
+ *     int u.cglyph            glyph under the chain
+ *     int u.bc_felt           mask for ball/chain being felt
+ *     #define BC_BALL  0x01   bit mask in u.bc_felt for ball
+ *     #define BC_CHAIN 0x02   bit mask in u.bc_felt for chain
+ *     int u.bc_order          ball & chain order
+ *
+ * u.bc_felt is also manipulated in display.c and read.c, the others only
+ * in this file.  None of these variables are valid unless the player is
+ * Blind.
+ */
+
+/* values for u.bc_order */
+#define BCPOS_DIFFER   0       /* ball & chain at different positions */
+#define BCPOS_CHAIN    1       /* chain on top of ball */
+#define BCPOS_BALL     2       /* ball on top of chain */
+
+
+
+/*
+ *  Place the ball & chain under the hero.  Make sure that the ball & chain
+ *  variables are set (actually only needed when blind, but what the heck).
+ *  It is assumed that when this is called, the ball and chain are NOT
+ *  attached to the object list.
+ *
+ *  Should not be called while swallowed.
+ */
+void
+placebc()
+{
+    if (!uchain || !uball) {
+       impossible("Where are your ball and chain?");
+       return;
+    }
+
+    (void) flooreffects(uchain, u.ux, u.uy, "");       /* chain might rust */
+
+    if (carried(uball))                /* the ball is carried */
+       u.bc_order = BCPOS_DIFFER;
+    else {
+       /* ball might rust -- already checked when carried */
+       (void) flooreffects(uball, u.ux, u.uy, "");
+       place_object(uball, u.ux, u.uy);
+       u.bc_order = BCPOS_CHAIN;
+    }
+
+    place_object(uchain, u.ux, u.uy);
+
+    u.bglyph = u.cglyph = levl[u.ux][u.uy].glyph;   /* pick up glyph */
+
+    newsym(u.ux,u.uy);
+}
+
+void
+unplacebc()
+{
+    if (u.uswallow) return;    /* ball&chain not placed while swallowed */
+
+    if (!carried(uball)) {
+       obj_extract_self(uball);
+       if (Blind && (u.bc_felt & BC_BALL))             /* drop glyph */
+           levl[uball->ox][uball->oy].glyph = u.bglyph;
+
+       newsym(uball->ox,uball->oy);
+    }
+    obj_extract_self(uchain);
+    if (Blind && (u.bc_felt & BC_CHAIN))               /* drop glyph */
+       levl[uchain->ox][uchain->oy].glyph = u.cglyph;
+
+    newsym(uchain->ox,uchain->oy);
+    u.bc_felt = 0;                                     /* feel nothing */
+}
+
+
+/*
+ *  Return the stacking of the hero's ball & chain.  This assumes that the
+ *  hero is being punished.
+ */
+STATIC_OVL int
+bc_order()
+{
+    struct obj *obj;
+
+    if (uchain->ox != uball->ox || uchain->oy != uball->oy || carried(uball)
+               || u.uswallow)
+       return BCPOS_DIFFER;
+
+    for (obj = level.objects[uball->ox][uball->oy]; obj; obj = obj->nexthere) {
+       if (obj == uchain) return BCPOS_CHAIN;
+       if (obj == uball) return BCPOS_BALL;
+    }
+    impossible("bc_order:  ball&chain not in same location!");
+    return BCPOS_DIFFER;
+}
+
+/*
+ *  set_bc()
+ *
+ *  The hero is either about to go blind or already blind and just punished.
+ *  Set up the ball and chain variables so that the ball and chain are "felt".
+ */
+void
+set_bc(already_blind)
+int already_blind;
+{
+    int ball_on_floor = !carried(uball);
+
+    u.bc_order = bc_order();                           /* get the order */
+    u.bc_felt = ball_on_floor ? BC_BALL|BC_CHAIN : BC_CHAIN;   /* felt */
+
+    if (already_blind || u.uswallow) {
+       u.cglyph = u.bglyph = levl[u.ux][u.uy].glyph;
+       return;
+    }
+
+    /*
+     *  Since we can still see, remove the ball&chain and get the glyph that
+     *  would be beneath them.  Then put the ball&chain back.  This is pretty
+     *  disgusting, but it will work.
+     */
+    remove_object(uchain);
+    if (ball_on_floor) remove_object(uball);
+
+    newsym(uchain->ox, uchain->oy);
+    u.cglyph = levl[uchain->ox][uchain->oy].glyph;
+
+    if (u.bc_order == BCPOS_DIFFER) {          /* different locations */
+       place_object(uchain, uchain->ox, uchain->oy);
+       newsym(uchain->ox, uchain->oy);
+       if (ball_on_floor) {
+           newsym(uball->ox, uball->oy);               /* see under ball */
+           u.bglyph = levl[uball->ox][uball->oy].glyph;
+           place_object(uball,  uball->ox, uball->oy);
+           newsym(uball->ox, uball->oy);               /* restore ball */
+       }
+    } else {
+       u.bglyph = u.cglyph;
+       if (u.bc_order == BCPOS_CHAIN) {
+           place_object(uball,  uball->ox, uball->oy);
+           place_object(uchain, uchain->ox, uchain->oy);
+       } else {
+           place_object(uchain, uchain->ox, uchain->oy);
+           place_object(uball,  uball->ox, uball->oy);
+       }
+       newsym(uball->ox, uball->oy);
+    }
+}
+
+
+/*
+ *  move_bc()
+ *
+ *  Move the ball and chain.  This is called twice for every move.  The first
+ *  time to pick up the ball and chain before the move, the second time to
+ *  place the ball and chain after the move.  If the ball is carried, this
+ *  function should never have BC_BALL as part of its control.
+ *
+ *  Should not be called while swallowed.
+ */
+void
+move_bc(before, control, ballx, bally, chainx, chainy)
+int   before, control;
+xchar ballx, bally, chainx, chainy;    /* only matter !before */
+{
+    if (Blind) {
+       /*
+        *  The hero is blind.  Time to work hard.  The ball and chain that
+        *  are attached to the hero are very special.  The hero knows that
+        *  they are attached, so when they move, the hero knows that they
+        *  aren't at the last position remembered.  This is complicated
+        *  by the fact that the hero can "feel" the surrounding locations
+        *  at any time, hence, making one or both of them show up again.
+        *  So, we have to keep track of which is felt at any one time and
+        *  act accordingly.
+        */
+       if (!before) {
+           if ((control & BC_CHAIN) && (control & BC_BALL)) {
+               /*
+                *  Both ball and chain moved.  If felt, drop glyph.
+                */
+               if (u.bc_felt & BC_BALL)
+                   levl[uball->ox][uball->oy].glyph = u.bglyph;
+               if (u.bc_felt & BC_CHAIN)
+                   levl[uchain->ox][uchain->oy].glyph = u.cglyph;
+               u.bc_felt = 0;
+
+               /* Pick up glyph at new location. */
+               u.bglyph = levl[ballx][bally].glyph;
+               u.cglyph = levl[chainx][chainy].glyph;
+
+               movobj(uball,ballx,bally);
+               movobj(uchain,chainx,chainy);
+           } else if (control & BC_BALL) {
+               if (u.bc_felt & BC_BALL) {
+                   if (u.bc_order == BCPOS_DIFFER) {   /* ball by itself */
+                       levl[uball->ox][uball->oy].glyph = u.bglyph;
+                   } else if (u.bc_order == BCPOS_BALL) {
+                       if (u.bc_felt & BC_CHAIN) {   /* know chain is there */
+                           map_object(uchain, 0);
+                       } else {
+                           levl[uball->ox][uball->oy].glyph = u.bglyph;
+                       }
+                   }
+                   u.bc_felt &= ~BC_BALL;      /* no longer feel the ball */
+               }
+
+               /* Pick up glyph at new position. */
+               u.bglyph = (ballx != chainx || bally != chainy) ?
+                                       levl[ballx][bally].glyph : u.cglyph;
+
+               movobj(uball,ballx,bally);
+           } else if (control & BC_CHAIN) {
+               if (u.bc_felt & BC_CHAIN) {
+                   if (u.bc_order == BCPOS_DIFFER) {
+                       levl[uchain->ox][uchain->oy].glyph = u.cglyph;
+                   } else if (u.bc_order == BCPOS_CHAIN) {
+                       if (u.bc_felt & BC_BALL) {
+                           map_object(uball, 0);
+                       } else {
+                           levl[uchain->ox][uchain->oy].glyph = u.cglyph;
+                       }
+                   }
+                   u.bc_felt &= ~BC_CHAIN;
+               }
+               /* Pick up glyph at new position. */
+               u.cglyph = (ballx != chainx || bally != chainy) ?
+                                       levl[chainx][chainy].glyph : u.bglyph;
+
+               movobj(uchain,chainx,chainy);
+           }
+
+           u.bc_order = bc_order();    /* reset the order */
+       }
+
+    } else {
+       /*
+        *  The hero is not blind.  To make this work correctly, we need to
+        *  pick up the ball and chain before the hero moves, then put them
+        *  in their new positions after the hero moves.
+        */
+       if (before) {
+           if (!control) {
+               /*
+                * Neither ball nor chain is moving, so remember which was
+                * on top until !before.  Use the variable u.bc_order
+                * since it is only valid when blind.
+                */
+               u.bc_order = bc_order();
+           }
+
+           remove_object(uchain);
+           newsym(uchain->ox, uchain->oy);
+           if (!carried(uball)) {
+               remove_object(uball);
+               newsym(uball->ox,  uball->oy);
+           }
+       } else {
+           int on_floor = !carried(uball);
+
+           if ((control & BC_CHAIN) ||
+                               (!control && u.bc_order == BCPOS_CHAIN)) {
+               /* If the chain moved or nothing moved & chain on top. */
+               if (on_floor) place_object(uball,  ballx, bally);
+               place_object(uchain, chainx, chainy);   /* chain on top */
+           } else {
+               place_object(uchain, chainx, chainy);
+               if (on_floor) place_object(uball,  ballx, bally);
+                                                           /* ball on top */
+           }
+           newsym(chainx, chainy);
+           if (on_floor) newsym(ballx, bally);
+       }
+    }
+}
+
+/* return TRUE if the caller needs to place the ball and chain down again
+ *
+ *  Should not be called while swallowed.  Should be called before movement,
+ *  because we might want to move the ball or chain to the hero's old position.
+ *
+ * It is called if we are moving.  It is also called if we are teleporting
+ * *if* the ball doesn't move and we thus must drag the chain.  It is not
+ * called for ordinary teleportation.
+ *
+ * allow_drag is only used in the ugly special case where teleporting must
+ * drag the chain, while an identical-looking movement must drag both the ball
+ * and chain.
+ */
+boolean
+drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay,
+    allow_drag)
+xchar x, y;
+int *bc_control;
+xchar *ballx, *bally, *chainx, *chainy;
+boolean *cause_delay;
+boolean allow_drag;
+{
+       struct trap *t = (struct trap *)0;
+       boolean already_in_rock;
+
+       *ballx  = uball->ox;
+       *bally  = uball->oy;
+       *chainx = uchain->ox;
+       *chainy = uchain->oy;
+       *bc_control = 0;
+       *cause_delay = FALSE;
+
+       if (dist2(x, y, uchain->ox, uchain->oy) <= 2) { /* nothing moved */
+           move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
+           return TRUE;
+       }
+
+       /* only need to move the chain? */
+       if (carried(uball) || distmin(x, y, uball->ox, uball->oy) <= 2) {
+           xchar oldchainx = uchain->ox, oldchainy = uchain->oy;
+           *bc_control = BC_CHAIN;
+           move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
+           if (carried(uball)) {
+               /* move chain only if necessary */
+               if (distmin(x, y, uchain->ox, uchain->oy) > 1) {
+                   *chainx = u.ux;
+                   *chainy = u.uy;
+               }
+               return TRUE;
+           }
+#define CHAIN_IN_MIDDLE(chx, chy) \
+(distmin(x, y, chx, chy) <= 1 && distmin(chx, chy, uball->ox, uball->oy) <= 1)
+#define IS_CHAIN_ROCK(x,y) \
+(IS_ROCK(levl[x][y].typ) || (IS_DOOR(levl[x][y].typ) && \
+      (levl[x][y].doormask & (D_CLOSED|D_LOCKED))))
+/* Don't ever move the chain into solid rock.  If we have to, then instead
+ * undo the move_bc() and jump to the drag ball code.  Note that this also
+ * means the "cannot carry and drag" message will not appear, since unless we
+ * moved at least two squares there is no possibility of the chain position
+ * being in solid rock.
+ */
+#define SKIP_TO_DRAG { *chainx = oldchainx; *chainy = oldchainy; \
+    move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \
+    goto drag; } 
+           if (IS_CHAIN_ROCK(u.ux, u.uy) || IS_CHAIN_ROCK(*chainx, *chainy)
+                       || IS_CHAIN_ROCK(uball->ox, uball->oy))
+               already_in_rock = TRUE;
+           else
+               already_in_rock = FALSE;
+
+           switch(dist2(x, y, uball->ox, uball->oy)) {
+               /* two spaces diagonal from ball, move chain inbetween */
+               case 8:
+                   *chainx = (uball->ox + x)/2;
+                   *chainy = (uball->oy + y)/2;
+                   if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
+                       SKIP_TO_DRAG;
+                   break;
+
+               /* player is distance 2/1 from ball; move chain to one of the
+                * two spaces between
+                *   @
+                *   __
+                *    0
+                */
+               case 5: {
+                   xchar tempx, tempy, tempx2, tempy2;
+
+                   /* find position closest to current position of chain */
+                   /* no effect if current position is already OK */
+                   if (abs(x - uball->ox) == 1) {
+                       tempx = x;
+                       tempx2 = uball->ox;
+                       tempy = tempy2 = (uball->oy + y)/2;
+                   } else {
+                       tempx = tempx2 = (uball->ox + x)/2;
+                       tempy = y;
+                       tempy2 = uball->oy;
+                   }
+                   if (IS_CHAIN_ROCK(tempx, tempy) &&
+                               !IS_CHAIN_ROCK(tempx2, tempy2) &&
+                               !already_in_rock) {
+                       if (allow_drag) {
+                           /* Avoid pathological case *if* not teleporting:
+                            *   0                          0_
+                            *   _X  move northeast  ----->  X@
+                            *    @
+                            */
+                           if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 &&
+                                 dist2(x, y, tempx, tempy) == 1)
+                               SKIP_TO_DRAG;
+                           /* Avoid pathological case *if* not teleporting:
+                            *    0                          0
+                            *   _X  move east       ----->  X_
+                            *    @                           @
+                            */
+                           if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 &&
+                                 dist2(x, y, tempx, tempy) == 2)
+                               SKIP_TO_DRAG;
+                       }
+                       *chainx = tempx2;
+                       *chainy = tempy2;
+                   } else if (!IS_CHAIN_ROCK(tempx, tempy) &&
+                               IS_CHAIN_ROCK(tempx2, tempy2) &&
+                               !already_in_rock) {
+                       if (allow_drag) {
+                           if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 &&
+                                   dist2(x, y, tempx2, tempy2) == 1)
+                               SKIP_TO_DRAG;
+                           if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 &&
+                                 dist2(x, y, tempx2, tempy2) == 2)
+                               SKIP_TO_DRAG;
+                       }
+                       *chainx = tempx;
+                       *chainy = tempy;
+                   } else if (IS_CHAIN_ROCK(tempx, tempy) &&
+                               IS_CHAIN_ROCK(tempx2, tempy2) &&
+                               !already_in_rock) {
+                       SKIP_TO_DRAG;
+                   } else if (dist2(tempx, tempy, uchain->ox, uchain->oy) <
+                        dist2(tempx2, tempy2, uchain->ox, uchain->oy) ||
+                      ((dist2(tempx, tempy, uchain->ox, uchain->oy) ==
+                        dist2(tempx2, tempy2, uchain->ox, uchain->oy)) && rn2(2))) {
+                       *chainx = tempx;
+                       *chainy = tempy;
+                   } else {
+                       *chainx = tempx2;
+                       *chainy = tempy2;
+                   }
+                   break;
+               }
+
+               /* ball is two spaces horizontal or vertical from player; move*/
+               /* chain inbetween *unless* current chain position is OK */
+               case 4:
+                   if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy))
+                       break;
+                   *chainx = (x + uball->ox)/2;
+                   *chainy = (y + uball->oy)/2;
+                   if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
+                       SKIP_TO_DRAG;
+                   break;
+               
+               /* ball is one space diagonal from player.  Check for the
+                * following special case:
+                *   @
+                *    _    moving southwest becomes  @_
+                *   0                                0
+                * (This will also catch teleporting that happens to resemble
+                * this case, but oh well.)  Otherwise fall through.
+                */
+               case 2:
+                   if (dist2(x, y, uball->ox, uball->oy) == 2 &&
+                           dist2(x, y, uchain->ox, uchain->oy) == 4) {
+                       if (uchain->oy == y)
+                           *chainx = uball->ox;
+                       else
+                           *chainy = uball->oy;
+                       if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
+                           SKIP_TO_DRAG;
+                       break;
+                   }
+                   /* fall through */
+               case 1:
+               case 0:
+                   /* do nothing if possible */
+                   if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy))
+                       break;
+                   /* otherwise try to drag chain to player's old position */
+                   if (CHAIN_IN_MIDDLE(u.ux, u.uy)) {
+                       *chainx = u.ux;
+                       *chainy = u.uy;
+                       break;
+                   }
+                   /* otherwise use player's new position (they must have
+                      teleported, for this to happen) */
+                   *chainx = x;
+                   *chainy = y;
+                   break;
+               
+               default: impossible("bad chain movement");
+                   break;
+           }
+#undef SKIP_TO_DRAG
+#undef IS_CHAIN_ROCK
+#undef CHAIN_IN_MIDDLE
+           return TRUE;
+       }
+
+drag:
+
+       if (near_capacity() > SLT_ENCUMBER && dist2(x, y, u.ux, u.uy) <= 2) {
+           You("cannot %sdrag the heavy iron ball.",
+                           invent ? "carry all that and also " : "");
+           nomul(0);
+           return FALSE;
+       }
+
+       if ((is_pool(uchain->ox, uchain->oy) &&
+                       /* water not mere continuation of previous water */
+                       (levl[uchain->ox][uchain->oy].typ == POOL ||
+                        !is_pool(uball->ox, uball->oy) ||
+                        levl[uball->ox][uball->oy].typ == POOL))
+           || ((t = t_at(uchain->ox, uchain->oy)) &&
+                       (t->ttyp == PIT ||
+                        t->ttyp == SPIKED_PIT ||
+                        t->ttyp == HOLE ||
+                        t->ttyp == TRAPDOOR)) ) {
+
+           if (Levitation) {
+               You_feel("a tug from the iron ball.");
+               if (t) t->tseen = 1;
+           } else {
+               struct monst *victim;
+
+               You("are jerked back by the iron ball!");
+               if ((victim = m_at(uchain->ox, uchain->oy)) != 0) {
+                   int tmp;
+
+                   tmp = -2 + Luck + find_mac(victim);
+                   tmp += omon_adj(victim, uball, TRUE);
+                   if (tmp >= rnd(20))
+                       (void) hmon(victim,uball,1);
+                   else
+                       miss(xname(uball), victim);
+
+               }               /* now check again in case mon died */
+               if (!m_at(uchain->ox, uchain->oy)) {
+                   u.ux = uchain->ox;
+                   u.uy = uchain->oy;
+                   newsym(u.ux0, u.uy0);
+               }
+               nomul(0);
+
+               *bc_control = BC_BALL;
+               move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
+               *ballx = uchain->ox;
+               *bally = uchain->oy;
+               move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy);
+               spoteffects(TRUE);
+               return FALSE;
+           }
+       }
+
+       *bc_control = BC_BALL|BC_CHAIN;
+
+       move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
+       if (dist2(x, y, u.ux, u.uy) > 2) {
+           /* Awful case: we're still in range of the ball, so we thought we
+            * could only move the chain, but it turned out that the target
+            * square for the chain was rock, so we had to drag it instead.
+            * But we can't drag it either, because we teleported and are more
+            * than one square from our old position.  Revert to the teleport
+            * behavior.
+            */
+           *ballx = *chainx = x;
+           *bally = *chainy = y;
+       } else {
+           *ballx  = uchain->ox;
+           *bally  = uchain->oy;
+           *chainx = u.ux;
+           *chainy = u.uy;
+       }
+       *cause_delay = TRUE;
+       return TRUE;
+}
+
+/*
+ *  drop_ball()
+ *
+ *  The punished hero drops or throws her iron ball.  If the hero is
+ *  blind, we must reset the order and glyph.  Check for side effects.
+ *  This routine expects the ball to be already placed.
+ *
+ *  Should not be called while swallowed.
+ */
+void
+drop_ball(x, y)
+xchar x, y;
+{
+    if (Blind) {
+       u.bc_order = bc_order();                        /* get the order */
+                                                       /* pick up glyph */
+       u.bglyph = (u.bc_order) ? u.cglyph : levl[x][y].glyph;
+    }
+
+    if (x != u.ux || y != u.uy) {
+       struct trap *t;
+       const char *pullmsg = "The ball pulls you out of the %s!";
+
+       if (u.utrap && u.utraptype != TT_INFLOOR) {
+           switch(u.utraptype) {
+           case TT_PIT:
+               pline(pullmsg, "pit");
+               break;
+           case TT_WEB:
+               pline(pullmsg, "web");
+               pline_The("web is destroyed!");
+               deltrap(t_at(u.ux,u.uy));
+               break;
+           case TT_LAVA:
+               pline(pullmsg, "lava");
+               break;
+           case TT_BEARTRAP: {
+               register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
+               pline(pullmsg, "bear trap");
+               set_wounded_legs(side, rn1(1000, 500));
+#ifdef STEED
+               if (!u.usteed)
+#endif
+               {
+                   Your("%s %s is severely damaged.",
+                                       (side == LEFT_SIDE) ? "left" : "right",
+                                       body_part(LEG));
+                   losehp(2, "leg damage from being pulled out of a bear trap",
+                                       KILLED_BY);
+               }
+               break;
+             }
+           }
+           u.utrap = 0;
+           fill_pit(u.ux, u.uy);
+       }
+
+       u.ux0 = u.ux;
+       u.uy0 = u.uy;
+       if (!Levitation && !MON_AT(x, y) && !u.utrap &&
+                           (is_pool(x, y) ||
+                            ((t = t_at(x, y)) &&
+                             (t->ttyp == PIT || t->ttyp == SPIKED_PIT ||
+                              t->ttyp == TRAPDOOR || t->ttyp == HOLE)))) {
+           u.ux = x;
+           u.uy = y;
+       } else {
+           u.ux = x - u.dx;
+           u.uy = y - u.dy;
+       }
+       vision_full_recalc = 1; /* hero has moved, recalculate vision later */
+
+       if (Blind) {
+           /* drop glyph under the chain */
+           if (u.bc_felt & BC_CHAIN)
+               levl[uchain->ox][uchain->oy].glyph = u.cglyph;
+           u.bc_felt  = 0;             /* feel nothing */
+           /* pick up new glyph */
+           u.cglyph = (u.bc_order) ? u.bglyph : levl[u.ux][u.uy].glyph;
+       }
+       movobj(uchain,u.ux,u.uy);       /* has a newsym */
+       if (Blind) {
+           u.bc_order = bc_order();
+       }
+       newsym(u.ux0,u.uy0);            /* clean up old position */
+       if (u.ux0 != u.ux || u.uy0 != u.uy) {
+           spoteffects(TRUE);
+           if (In_sokoban(&u.uz))
+               change_luck(-1);        /* Sokoban guilt */
+       }
+    }
+}
+
+
+STATIC_OVL void
+litter()
+{
+       struct obj *otmp = invent, *nextobj;
+       int capacity = weight_cap();
+
+       while (otmp) {
+               nextobj = otmp->nobj;
+               if ((otmp != uball) && (rnd(capacity) <= (int)otmp->owt)) {
+                       if (canletgo(otmp, "")) {
+                               Your("%s you down the stairs.",
+                                    aobjnam(otmp, "follow"));
+                               dropx(otmp);
+                       }
+               }
+               otmp = nextobj;
+       }
+}
+
+void
+drag_down()
+{
+       boolean forward;
+       uchar dragchance = 3;
+
+       /*
+        *      Assume that the ball falls forward if:
+        *
+        *      a) the character is wielding it, or
+        *      b) the character has both hands available to hold it (i.e. is
+        *         not wielding any weapon), or
+        *      c) (perhaps) it falls forward out of his non-weapon hand
+        */
+
+       forward = carried(uball) && (uwep == uball || !uwep || !rn2(3));
+
+       if (carried(uball))
+               You("lose your grip on the iron ball.");
+
+       if (forward) {
+               if(rn2(6)) {
+                       pline_The("iron ball drags you downstairs!");
+                       losehp(rnd(6), "dragged downstairs by an iron ball",
+                               NO_KILLER_PREFIX);
+                       litter();
+               }
+       } else {
+               if(rn2(2)) {
+                       pline_The("iron ball smacks into you!");
+                       losehp(rnd(20), "iron ball collision", KILLED_BY_AN);
+                       exercise(A_STR, FALSE);
+                       dragchance -= 2;
+               }
+               if( (int) dragchance >= rnd(6)) {
+                       pline_The("iron ball drags you downstairs!");
+                       losehp(rnd(3), "dragged downstairs by an iron ball",
+                               NO_KILLER_PREFIX);
+                       exercise(A_STR, FALSE);
+                       litter();
+               }
+       }
+}
+
+/*ball.c*/
diff --git a/src/bones.c b/src/bones.c
new file mode 100644 (file)
index 0000000..585200a
--- /dev/null
@@ -0,0 +1,474 @@
+/*     SCCS Id: @(#)bones.c    3.4     2003/09/06      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985,1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "lev.h"
+
+extern char bones[];   /* from files.c */
+#ifdef MFLOPPY
+extern long bytes_counted;
+#endif
+
+STATIC_DCL boolean FDECL(no_bones_level, (d_level *));
+STATIC_DCL void FDECL(goodfruit, (int));
+STATIC_DCL void FDECL(resetobjs,(struct obj *,BOOLEAN_P));
+STATIC_DCL void FDECL(drop_upon_death, (struct monst *, struct obj *));
+
+STATIC_OVL boolean
+no_bones_level(lev)
+d_level *lev;
+{
+       extern d_level save_dlevel;             /* in do.c */
+       s_level *sptr;
+
+       if (ledger_no(&save_dlevel)) assign_level(lev, &save_dlevel);
+
+       return (boolean)(((sptr = Is_special(lev)) != 0 && !sptr->boneid)
+               || !dungeons[lev->dnum].boneid
+                  /* no bones on the last or multiway branch levels */
+                  /* in any dungeon (level 1 isn't multiway).       */
+               || Is_botlevel(lev) || (Is_branchlev(lev) && lev->dlevel > 1)
+                  /* no bones in the invocation level               */
+               || (In_hell(lev) && lev->dlevel == dunlevs_in_dungeon(lev) - 1)
+               );
+}
+
+/* Call this function for each fruit object saved in the bones level: it marks
+ * that particular type of fruit as existing (the marker is that that type's
+ * ID is positive instead of negative).  This way, when we later save the
+ * chain of fruit types, we know to only save the types that exist.
+ */
+STATIC_OVL void
+goodfruit(id)
+int id;
+{
+       register struct fruit *f;
+
+       for(f=ffruit; f; f=f->nextf) {
+               if(f->fid == -id) {
+                       f->fid = id;
+                       return;
+               }
+       }
+}
+
+STATIC_OVL void
+resetobjs(ochain,restore)
+struct obj *ochain;
+boolean restore;
+{
+       struct obj *otmp;
+
+       for (otmp = ochain; otmp; otmp = otmp->nobj) {
+               if (otmp->cobj)
+                   resetobjs(otmp->cobj,restore);
+
+               if (((otmp->otyp != CORPSE || otmp->corpsenm < SPECIAL_PM)
+                       && otmp->otyp != STATUE)
+                       && (!otmp->oartifact ||
+                          (restore && (exist_artifact(otmp->otyp, ONAME(otmp))
+                                       || is_quest_artifact(otmp))))) {
+                       otmp->oartifact = 0;
+                       otmp->onamelth = 0;
+                       *ONAME(otmp) = '\0';
+               } else if (otmp->oartifact && restore)
+                       artifact_exists(otmp,ONAME(otmp),TRUE);
+               if (!restore) {
+                       /* do not zero out o_ids for ghost levels anymore */
+
+                       if(objects[otmp->otyp].oc_uses_known) otmp->known = 0;
+                       otmp->dknown = otmp->bknown = 0;
+                       otmp->rknown = 0;
+                       otmp->invlet = 0;
+                       otmp->no_charge = 0;
+
+                       if (otmp->otyp == SLIME_MOLD) goodfruit(otmp->spe);
+#ifdef MAIL
+                       else if (otmp->otyp == SCR_MAIL) otmp->spe = 1;
+#endif
+                       else if (otmp->otyp == EGG) otmp->spe = 0;
+                       else if (otmp->otyp == TIN) {
+                           /* make tins of unique monster's meat be empty */
+                           if (otmp->corpsenm >= LOW_PM &&
+                                   (mons[otmp->corpsenm].geno & G_UNIQ))
+                               otmp->corpsenm = NON_PM;
+                       } else if (otmp->otyp == AMULET_OF_YENDOR) {
+                           /* no longer the real Amulet */
+                           otmp->otyp = FAKE_AMULET_OF_YENDOR;
+                           curse(otmp);
+                       } else if (otmp->otyp == CANDELABRUM_OF_INVOCATION) {
+                           if (otmp->lamplit)
+                               end_burn(otmp, TRUE);
+                           otmp->otyp = WAX_CANDLE;
+                           otmp->age = 50L;  /* assume used */
+                           if (otmp->spe > 0)
+                               otmp->quan = (long)otmp->spe;
+                           otmp->spe = 0;
+                           otmp->owt = weight(otmp);
+                           curse(otmp);
+                       } else if (otmp->otyp == BELL_OF_OPENING) {
+                           otmp->otyp = BELL;
+                           curse(otmp);
+                       } else if (otmp->otyp == SPE_BOOK_OF_THE_DEAD) {
+                           otmp->otyp = SPE_BLANK_PAPER;
+                           curse(otmp);
+                       }
+               }
+       }
+}
+
+STATIC_OVL void
+drop_upon_death(mtmp, cont)
+struct monst *mtmp;
+struct obj *cont;
+{
+       struct obj *otmp;
+
+       uswapwep = 0; /* ensure curse() won't cause swapwep to drop twice */
+       while ((otmp = invent) != 0) {
+               obj_extract_self(otmp);
+               obj_no_longer_held(otmp);
+
+               otmp->owornmask = 0;
+               /* lamps don't go out when dropped */
+               if ((cont || artifact_light(otmp)) && obj_is_burning(otmp))
+                   end_burn(otmp, TRUE);       /* smother in statue */
+
+               if(otmp->otyp == SLIME_MOLD) goodfruit(otmp->spe);
+
+               if(rn2(5)) curse(otmp);
+               if (mtmp)
+                       (void) add_to_minv(mtmp, otmp);
+               else if (cont)
+                       (void) add_to_container(cont, otmp);
+               else
+                       place_object(otmp, u.ux, u.uy);
+       }
+#ifndef GOLDOBJ
+       if(u.ugold) {
+               long ugold = u.ugold;
+               if (mtmp) mtmp->mgold = ugold;
+               else if (cont) (void) add_to_container(cont, mkgoldobj(ugold));
+               else (void)mkgold(ugold, u.ux, u.uy);
+               u.ugold = ugold;        /* undo mkgoldobj()'s removal */
+       }
+#endif
+       if (cont) cont->owt = weight(cont);
+}
+
+/* check whether bones are feasible */
+boolean
+can_make_bones()
+{
+       register struct trap *ttmp;
+
+       if (ledger_no(&u.uz) <= 0 || ledger_no(&u.uz) > maxledgerno())
+           return FALSE;
+       if (no_bones_level(&u.uz))
+           return FALSE;               /* no bones for specific levels */
+       if (u.uswallow) {
+           return FALSE;               /* no bones when swallowed */
+       }
+       if (!Is_branchlev(&u.uz)) {
+           /* no bones on non-branches with portals */
+           for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
+               if (ttmp->ttyp == MAGIC_PORTAL) return FALSE;
+       }
+
+       if(depth(&u.uz) <= 0 ||         /* bulletproofing for endgame */
+          (!rn2(1 + (depth(&u.uz)>>2)) /* fewer ghosts on low levels */
+#ifdef WIZARD
+               && !wizard
+#endif
+               )) return FALSE;
+       /* don't let multiple restarts generate multiple copies of objects
+        * in bones files */
+       if (discover) return FALSE;
+       return TRUE;
+}
+
+/* save bones and possessions of a deceased adventurer */
+void
+savebones(corpse)
+struct obj *corpse;
+{
+       int fd, x, y;
+       struct trap *ttmp;
+       struct monst *mtmp;
+       struct permonst *mptr;
+       struct fruit *f;
+       char c, *bonesid;
+       char whynot[BUFSZ];
+
+       /* caller has already checked `can_make_bones()' */
+
+       clear_bypasses();
+       fd = open_bonesfile(&u.uz, &bonesid);
+       if (fd >= 0) {
+               (void) close(fd);
+               compress_bonesfile();
+#ifdef WIZARD
+               if (wizard) {
+                   if (yn("Bones file already exists.  Replace it?") == 'y') {
+                       if (delete_bonesfile(&u.uz)) goto make_bones;
+                       else pline("Cannot unlink old bones.");
+                   }
+               }
+#endif
+               return;
+       }
+
+#ifdef WIZARD
+ make_bones:
+#endif
+       unleash_all();
+       /* in case these characters are not in their home bases */
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+           if (DEADMONSTER(mtmp)) continue;
+           mptr = mtmp->data;
+           if (mtmp->iswiz || mptr == &mons[PM_MEDUSA] ||
+                   mptr->msound == MS_NEMESIS || mptr->msound == MS_LEADER ||
+                   mptr == &mons[PM_VLAD_THE_IMPALER])
+               mongone(mtmp);
+       }
+#ifdef STEED
+       if (u.usteed) dismount_steed(DISMOUNT_BONES);
+#endif
+       dmonsfree();            /* discard dead or gone monsters */
+
+       /* mark all fruits as nonexistent; when we come to them we'll mark
+        * them as existing (using goodfruit())
+        */
+       for(f=ffruit; f; f=f->nextf) f->fid = -f->fid;
+
+       /* check iron balls separately--maybe they're not carrying it */
+       if (uball) uball->owornmask = uchain->owornmask = 0;
+
+       /* dispose of your possessions, usually cursed */
+       if (u.ugrave_arise == (NON_PM - 1)) {
+               struct obj *otmp;
+
+               /* embed your possessions in your statue */
+               otmp = mk_named_object(STATUE, &mons[u.umonnum],
+                                      u.ux, u.uy, plname);
+
+               drop_upon_death((struct monst *)0, otmp);
+               if (!otmp) return;      /* couldn't make statue */
+               mtmp = (struct monst *)0;
+       } else if (u.ugrave_arise < LOW_PM) {
+               /* drop everything */
+               drop_upon_death((struct monst *)0, (struct obj *)0);
+               /* trick makemon() into allowing monster creation
+                * on your location
+                */
+               in_mklev = TRUE;
+               mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, MM_NONAME);
+               in_mklev = FALSE;
+               if (!mtmp) return;
+               mtmp = christen_monst(mtmp, plname);
+               if (corpse)
+                       (void) obj_attach_mid(corpse, mtmp->m_id); 
+       } else {
+               /* give your possessions to the monster you become */
+               in_mklev = TRUE;
+               mtmp = makemon(&mons[u.ugrave_arise], u.ux, u.uy, NO_MM_FLAGS);
+               in_mklev = FALSE;
+               if (!mtmp) {
+                       drop_upon_death((struct monst *)0, (struct obj *)0);
+                       return;
+               }
+               mtmp = christen_monst(mtmp, plname);
+               newsym(u.ux, u.uy);
+               Your("body rises from the dead as %s...",
+                       an(mons[u.ugrave_arise].mname));
+               display_nhwindow(WIN_MESSAGE, FALSE);
+               drop_upon_death(mtmp, (struct obj *)0);
+               m_dowear(mtmp, TRUE);
+       }
+       if (mtmp) {
+               mtmp->m_lev = (u.ulevel ? u.ulevel : 1);
+               mtmp->mhp = mtmp->mhpmax = u.uhpmax;
+               mtmp->female = flags.female;
+               mtmp->msleeping = 1;
+       }
+       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+               resetobjs(mtmp->minvent,FALSE);
+               /* do not zero out m_ids for bones levels any more */
+               mtmp->mlstmv = 0L;
+               if(mtmp->mtame) mtmp->mtame = mtmp->mpeaceful = 0;
+       }
+       for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
+               ttmp->madeby_u = 0;
+               ttmp->tseen = (ttmp->ttyp == HOLE);
+       }
+       resetobjs(fobj,FALSE);
+       resetobjs(level.buriedobjlist, FALSE);
+
+       /* Hero is no longer on the map. */
+       u.ux = u.uy = 0;
+
+       /* Clear all memory from the level. */
+       for(x=0; x<COLNO; x++) for(y=0; y<ROWNO; y++) {
+           levl[x][y].seenv = 0;
+           levl[x][y].waslit = 0;
+           levl[x][y].glyph = cmap_to_glyph(S_stone);
+       }
+
+       fd = create_bonesfile(&u.uz, &bonesid, whynot);
+       if(fd < 0) {
+#ifdef WIZARD
+               if(wizard)
+                       pline("%s", whynot);
+#endif
+               /* bones file creation problems are silent to the player.
+                * Keep it that way, but place a clue into the paniclog.
+                */
+               paniclog("savebones", whynot);
+               return;
+       }
+       c = (char) (strlen(bonesid) + 1);
+
+#ifdef MFLOPPY  /* check whether there is room */
+       if (iflags.checkspace) {
+           savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
+           /* savelev() initializes bytes_counted to 0, so it must come
+            * first here even though it does not in the real save.  the
+            * resulting extra bflush() at the end of savelev() may increase
+            * bytes_counted by a couple over what the real usage will be.
+            *
+            * note it is safe to call store_version() here only because
+            * bufon() is null for ZEROCOMP, which MFLOPPY uses -- otherwise
+            * this code would have to know the size of the version
+            * information itself.
+            */
+           store_version(fd);
+           bwrite(fd, (genericptr_t) &c, sizeof c);
+           bwrite(fd, (genericptr_t) bonesid, (unsigned) c);   /* DD.nnn */
+           savefruitchn(fd, COUNT_SAVE);
+           bflush(fd);
+           if (bytes_counted > freediskspace(bones)) { /* not enough room */
+# ifdef WIZARD
+               if (wizard)
+                       pline("Insufficient space to create bones file.");
+# endif
+               (void) close(fd);
+               cancel_bonesfile();
+               return;
+           }
+           co_false(); /* make sure stuff before savelev() gets written */
+       }
+#endif /* MFLOPPY */
+
+       store_version(fd);
+       bwrite(fd, (genericptr_t) &c, sizeof c);
+       bwrite(fd, (genericptr_t) bonesid, (unsigned) c);       /* DD.nnn */
+       savefruitchn(fd, WRITE_SAVE | FREE_SAVE);
+       update_mlstmv();        /* update monsters for eventual restoration */
+       savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
+       bclose(fd);
+       commit_bonesfile(&u.uz);
+       compress_bonesfile();
+}
+
+int
+getbones()
+{
+       register int fd;
+       register int ok;
+       char c, *bonesid, oldbonesid[10];
+
+       if(discover)            /* save bones files for real games */
+               return(0);
+
+       /* wizard check added by GAN 02/05/87 */
+       if(rn2(3)       /* only once in three times do we find bones */
+#ifdef WIZARD
+               && !wizard
+#endif
+               ) return(0);
+       if(no_bones_level(&u.uz)) return(0);
+       fd = open_bonesfile(&u.uz, &bonesid);
+       if (fd < 0) return(0);
+
+       if ((ok = uptodate(fd, bones)) == 0) {
+#ifdef WIZARD
+           if (!wizard)
+#endif
+               pline("Discarding unuseable bones; no need to panic...");
+       } else {
+#ifdef WIZARD
+               if(wizard)  {
+                       if(yn("Get bones?") == 'n') {
+                               (void) close(fd);
+                               compress_bonesfile();
+                               return(0);
+                       }
+               }
+#endif
+               mread(fd, (genericptr_t) &c, sizeof c); /* length incl. '\0' */
+               mread(fd, (genericptr_t) oldbonesid, (unsigned) c); /* DD.nnn */
+               if (strcmp(bonesid, oldbonesid) != 0) {
+                       char errbuf[BUFSZ];
+
+                       Sprintf(errbuf, "This is bones level '%s', not '%s'!",
+                               oldbonesid, bonesid);
+#ifdef WIZARD
+                       if (wizard) {
+                               pline("%s", errbuf);
+                               ok = FALSE;     /* won't die of trickery */
+                       }
+#endif
+                       trickery(errbuf);
+               } else {
+                       register struct monst *mtmp;
+
+                       getlev(fd, 0, 0, TRUE);
+
+                       /* Note that getlev() now keeps tabs on unique
+                        * monsters such as demon lords, and tracks the
+                        * birth counts of all species just as makemon()
+                        * does.  If a bones monster is extinct or has been
+                        * subject to genocide, their mhpmax will be
+                        * set to the magic DEFUNCT_MONSTER cookie value.
+                        */
+                       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+                           if (mtmp->mhpmax == DEFUNCT_MONSTER) {
+#if defined(DEBUG) && defined(WIZARD)
+                               if (wizard)
+                                   pline("Removing defunct monster %s from bones.",
+                                       mtmp->data->mname);
+#endif
+                               mongone(mtmp);
+                           } else
+                               /* to correctly reset named artifacts on the level */
+                               resetobjs(mtmp->minvent,TRUE);
+                       }
+                       resetobjs(fobj,TRUE);
+                       resetobjs(level.buriedobjlist,TRUE);
+               }
+       }
+       (void) close(fd);
+
+#ifdef WIZARD
+       if(wizard) {
+               if(yn("Unlink bones?") == 'n') {
+                       compress_bonesfile();
+                       return(ok);
+               }
+       }
+#endif
+       if (!delete_bonesfile(&u.uz)) {
+               /* When N games try to simultaneously restore the same
+                * bones file, N-1 of them will fail to delete it
+                * (the first N-1 under AmigaDOS, the last N-1 under UNIX).
+                * So no point in a mysterious message for a normal event
+                * -- just generate a new level for those N-1 games.
+                */
+               /* pline("Cannot unlink bones."); */
+               return(0);
+       }
+       return(ok);
+}
+
+/*bones.c*/
diff --git a/src/botl.c b/src/botl.c
new file mode 100644 (file)
index 0000000..6534ad7
--- /dev/null
@@ -0,0 +1,309 @@
+/*     SCCS Id: @(#)botl.c     3.4     1996/07/15      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+#ifdef OVL0
+extern const char *hu_stat[];  /* defined in eat.c */
+
+const char * const enc_stat[] = {
+       "",
+       "Burdened",
+       "Stressed",
+       "Strained",
+       "Overtaxed",
+       "Overloaded"
+};
+
+STATIC_DCL void NDECL(bot1);
+STATIC_DCL void NDECL(bot2);
+#endif /* OVL0 */
+
+/* MAXCO must hold longest uncompressed status line, and must be larger
+ * than COLNO
+ *
+ * longest practical second status line at the moment is
+ *     Astral Plane $:12345 HP:700(700) Pw:111(111) AC:-127 Xp:30/123456789
+ *     T:123456 Satiated Conf FoodPois Ill Blind Stun Hallu Overloaded
+ * -- or somewhat over 130 characters
+ */
+#if COLNO <= 140
+#define MAXCO 160
+#else
+#define MAXCO (COLNO+20)
+#endif
+
+#ifndef OVLB
+STATIC_DCL int mrank_sz;
+#else /* OVLB */
+STATIC_OVL NEARDATA int mrank_sz = 0; /* loaded by max_rank_sz (from u_init) */
+#endif /* OVLB */
+
+STATIC_DCL const char *NDECL(rank);
+
+#ifdef OVL1
+
+/* convert experience level (1..30) to rank index (0..8) */
+int
+xlev_to_rank(xlev)
+int xlev;
+{
+       return (xlev <= 2) ? 0 : (xlev <= 30) ? ((xlev + 2) / 4) : 8;
+}
+
+#if 0  /* not currently needed */
+/* convert rank index (0..8) to experience level (1..30) */
+int
+rank_to_xlev(rank)
+int rank;
+{
+       return (rank <= 0) ? 1 : (rank <= 8) ? ((rank * 4) - 2) : 30;
+}
+#endif
+
+const char *
+rank_of(lev, monnum, female)
+       int lev;
+       short monnum;
+       boolean female;
+{
+       register struct Role *role;
+       register int i;
+
+
+       /* Find the role */
+       for (role = (struct Role *) roles; role->name.m; role++)
+           if (monnum == role->malenum || monnum == role->femalenum)
+               break;
+       if (!role->name.m)
+           role = &urole;
+
+       /* Find the rank */
+       for (i = xlev_to_rank((int)lev); i >= 0; i--) {
+           if (female && role->rank[i].f) return (role->rank[i].f);
+           if (role->rank[i].m) return (role->rank[i].m);
+       }
+
+       /* Try the role name, instead */
+       if (female && role->name.f) return (role->name.f);
+       else if (role->name.m) return (role->name.m);
+       return ("Player");
+}
+
+
+STATIC_OVL const char *
+rank()
+{
+       return(rank_of(u.ulevel, Role_switch, flags.female));
+}
+
+int
+title_to_mon(str, rank_indx, title_length)
+const char *str;
+int *rank_indx, *title_length;
+{
+       register int i, j;
+
+
+       /* Loop through each of the roles */
+       for (i = 0; roles[i].name.m; i++)
+           for (j = 0; j < 9; j++) {
+               if (roles[i].rank[j].m && !strncmpi(str,
+                               roles[i].rank[j].m, strlen(roles[i].rank[j].m))) {
+                   if (rank_indx) *rank_indx = j;
+                   if (title_length) *title_length = strlen(roles[i].rank[j].m);
+                   return roles[i].malenum;
+               }
+               if (roles[i].rank[j].f && !strncmpi(str,
+                               roles[i].rank[j].f, strlen(roles[i].rank[j].f))) {
+                   if (rank_indx) *rank_indx = j;
+                   if (title_length) *title_length = strlen(roles[i].rank[j].f);
+                   return ((roles[i].femalenum != NON_PM) ?
+                               roles[i].femalenum : roles[i].malenum);
+               }
+           }
+       return NON_PM;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+void
+max_rank_sz()
+{
+       register int i, r, maxr = 0;
+       for (i = 0; i < 9; i++) {
+           if (urole.rank[i].m && (r = strlen(urole.rank[i].m)) > maxr) maxr = r;
+           if (urole.rank[i].f && (r = strlen(urole.rank[i].f)) > maxr) maxr = r;
+       }
+       mrank_sz = maxr;
+       return;
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+#ifdef SCORE_ON_BOTL
+long
+botl_score()
+{
+    int deepest = deepest_lev_reached(FALSE);
+#ifndef GOLDOBJ
+    long ugold = u.ugold + hidden_gold();
+
+    if ((ugold -= u.ugold0) < 0L) ugold = 0L;
+    return ugold + u.urexp + (long)(50 * (deepest - 1))
+#else
+    long umoney = money_cnt(invent) + hidden_gold();
+
+    if ((umoney -= u.umoney0) < 0L) umoney = 0L;
+    return umoney + u.urexp + (long)(50 * (deepest - 1))
+#endif
+                         + (long)(deepest > 30 ? 10000 :
+                                  deepest > 20 ? 1000*(deepest - 20) : 0);
+}
+#endif
+
+STATIC_OVL void
+bot1()
+{
+       char newbot1[MAXCO];
+       register char *nb;
+       register int i,j;
+
+       Strcpy(newbot1, plname);
+       if('a' <= newbot1[0] && newbot1[0] <= 'z') newbot1[0] += 'A'-'a';
+       newbot1[10] = 0;
+       Sprintf(nb = eos(newbot1)," the ");
+
+       if (Upolyd) {
+               char mbot[BUFSZ];
+               int k = 0;
+
+               Strcpy(mbot, mons[u.umonnum].mname);
+               while(mbot[k] != 0) {
+                   if ((k == 0 || (k > 0 && mbot[k-1] == ' ')) &&
+                                       'a' <= mbot[k] && mbot[k] <= 'z')
+                       mbot[k] += 'A' - 'a';
+                   k++;
+               }
+               Sprintf(nb = eos(nb), mbot);
+       } else
+               Sprintf(nb = eos(nb), rank());
+
+       Sprintf(nb = eos(nb),"  ");
+       i = mrank_sz + 15;
+       j = (nb + 2) - newbot1; /* aka strlen(newbot1) but less computation */
+       if((i - j) > 0)
+               Sprintf(nb = eos(nb),"%*s", i-j, " ");  /* pad with spaces */
+       if (ACURR(A_STR) > 18) {
+               if (ACURR(A_STR) > STR18(100))
+                   Sprintf(nb = eos(nb),"St:%2d ",ACURR(A_STR)-100);
+               else if (ACURR(A_STR) < STR18(100))
+                   Sprintf(nb = eos(nb), "St:18/%02d ",ACURR(A_STR)-18);
+               else
+                   Sprintf(nb = eos(nb),"St:18/** ");
+       } else
+               Sprintf(nb = eos(nb), "St:%-1d ",ACURR(A_STR));
+       Sprintf(nb = eos(nb),
+               "Dx:%-1d Co:%-1d In:%-1d Wi:%-1d Ch:%-1d",
+               ACURR(A_DEX), ACURR(A_CON), ACURR(A_INT), ACURR(A_WIS), ACURR(A_CHA));
+       Sprintf(nb = eos(nb), (u.ualign.type == A_CHAOTIC) ? "  Chaotic" :
+                       (u.ualign.type == A_NEUTRAL) ? "  Neutral" : "  Lawful");
+#ifdef SCORE_ON_BOTL
+       if (flags.showscore)
+           Sprintf(nb = eos(nb), " S:%ld", botl_score());
+#endif
+       curs(WIN_STATUS, 1, 0);
+       putstr(WIN_STATUS, 0, newbot1);
+}
+
+/* provide the name of the current level for display by various ports */
+int
+describe_level(buf)
+char *buf;
+{
+       int ret = 1;
+
+       /* TODO:        Add in dungeon name */
+       if (Is_knox(&u.uz))
+               Sprintf(buf, "%s ", dungeons[u.uz.dnum].dname);
+       else if (In_quest(&u.uz))
+               Sprintf(buf, "Home %d ", dunlev(&u.uz));
+       else if (In_endgame(&u.uz))
+               Sprintf(buf,
+                       Is_astralevel(&u.uz) ? "Astral Plane " : "End Game ");
+       else {
+               /* ports with more room may expand this one */
+               Sprintf(buf, "Dlvl:%-2d ", depth(&u.uz));
+               ret = 0;
+       }
+       return ret;
+}
+
+STATIC_OVL void
+bot2()
+{
+       char  newbot2[MAXCO];
+       register char *nb;
+       int hp, hpmax;
+       int cap = near_capacity();
+
+       hp = Upolyd ? u.mh : u.uhp;
+       hpmax = Upolyd ? u.mhmax : u.uhpmax;
+
+       if(hp < 0) hp = 0;
+       (void) describe_level(newbot2);
+       Sprintf(nb = eos(newbot2),
+               "%c:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d", oc_syms[COIN_CLASS],
+#ifndef GOLDOBJ
+               u.ugold,
+#else
+               money_cnt(invent),
+#endif
+               hp, hpmax, u.uen, u.uenmax, u.uac);
+
+       if (Upolyd)
+               Sprintf(nb = eos(nb), " HD:%d", mons[u.umonnum].mlevel);
+#ifdef EXP_ON_BOTL
+       else if(flags.showexp)
+               Sprintf(nb = eos(nb), " Xp:%u/%-1ld", u.ulevel,u.uexp);
+#endif
+       else
+               Sprintf(nb = eos(nb), " Exp:%u", u.ulevel);
+
+       if(flags.time)
+           Sprintf(nb = eos(nb), " T:%ld", moves);
+       if(strcmp(hu_stat[u.uhs], "        ")) {
+               Sprintf(nb = eos(nb), " ");
+               Strcat(newbot2, hu_stat[u.uhs]);
+       }
+       if(Confusion)      Sprintf(nb = eos(nb), " Conf");
+       if(Sick) {
+               if (u.usick_type & SICK_VOMITABLE)
+                          Sprintf(nb = eos(nb), " FoodPois");
+               if (u.usick_type & SICK_NONVOMITABLE)
+                          Sprintf(nb = eos(nb), " Ill");
+       }
+       if(Blind)          Sprintf(nb = eos(nb), " Blind");
+       if(Stunned)        Sprintf(nb = eos(nb), " Stun");
+       if(Hallucination)  Sprintf(nb = eos(nb), " Hallu");
+       if(Slimed)         Sprintf(nb = eos(nb), " Slime");
+       if(cap > UNENCUMBERED)
+               Sprintf(nb = eos(nb), " %s", enc_stat[cap]);
+       curs(WIN_STATUS, 1, 1);
+       putstr(WIN_STATUS, 0, newbot2);
+}
+
+void
+bot()
+{
+       bot1();
+       bot2();
+       flags.botl = flags.botlx = 0;
+}
+
+#endif /* OVL0 */
+
+/*botl.c*/
diff --git a/src/cmd.c b/src/cmd.c
new file mode 100644 (file)
index 0000000..b12c0e5
--- /dev/null
+++ b/src/cmd.c
@@ -0,0 +1,2555 @@
+/*     SCCS Id: @(#)cmd.c      3.4     2003/02/06      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "func_tab.h"
+/* #define DEBUG */    /* uncomment for debugging */
+
+/*
+ * Some systems may have getchar() return EOF for various reasons, and
+ * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
+ */
+#if defined(SYSV) || defined(DGUX) || defined(HPUX)
+#define NR_OF_EOFS     20
+#endif
+
+#define CMD_TRAVEL (char)0x90
+
+#ifdef DEBUG
+/*
+ * only one "wiz_debug_cmd" routine should be available (in whatever
+ * module you are trying to debug) or things are going to get rather
+ * hard to link :-)
+ */
+extern int NDECL(wiz_debug_cmd);
+#endif
+
+#ifdef DUMB    /* stuff commented out in extern.h, but needed here */
+extern int NDECL(doapply); /**/
+extern int NDECL(dorub); /**/
+extern int NDECL(dojump); /**/
+extern int NDECL(doextlist); /**/
+extern int NDECL(dodrop); /**/
+extern int NDECL(doddrop); /**/
+extern int NDECL(dodown); /**/
+extern int NDECL(doup); /**/
+extern int NDECL(donull); /**/
+extern int NDECL(dowipe); /**/
+extern int NDECL(do_mname); /**/
+extern int NDECL(ddocall); /**/
+extern int NDECL(dotakeoff); /**/
+extern int NDECL(doremring); /**/
+extern int NDECL(dowear); /**/
+extern int NDECL(doputon); /**/
+extern int NDECL(doddoremarm); /**/
+extern int NDECL(dokick); /**/
+extern int NDECL(dofire); /**/
+extern int NDECL(dothrow); /**/
+extern int NDECL(doeat); /**/
+extern int NDECL(done2); /**/
+extern int NDECL(doengrave); /**/
+extern int NDECL(dopickup); /**/
+extern int NDECL(ddoinv); /**/
+extern int NDECL(dotypeinv); /**/
+extern int NDECL(dolook); /**/
+extern int NDECL(doprgold); /**/
+extern int NDECL(doprwep); /**/
+extern int NDECL(doprarm); /**/
+extern int NDECL(doprring); /**/
+extern int NDECL(dopramulet); /**/
+extern int NDECL(doprtool); /**/
+extern int NDECL(dosuspend); /**/
+extern int NDECL(doforce); /**/
+extern int NDECL(doopen); /**/
+extern int NDECL(doclose); /**/
+extern int NDECL(dosh); /**/
+extern int NDECL(dodiscovered); /**/
+extern int NDECL(doset); /**/
+extern int NDECL(dotogglepickup); /**/
+extern int NDECL(dowhatis); /**/
+extern int NDECL(doquickwhatis); /**/
+extern int NDECL(dowhatdoes); /**/
+extern int NDECL(dohelp); /**/
+extern int NDECL(dohistory); /**/
+extern int NDECL(doloot); /**/
+extern int NDECL(dodrink); /**/
+extern int NDECL(dodip); /**/
+extern int NDECL(dosacrifice); /**/
+extern int NDECL(dopray); /**/
+extern int NDECL(doturn); /**/
+extern int NDECL(doredraw); /**/
+extern int NDECL(doread); /**/
+extern int NDECL(dosave); /**/
+extern int NDECL(dosearch); /**/
+extern int NDECL(doidtrap); /**/
+extern int NDECL(dopay); /**/
+extern int NDECL(dosit); /**/
+extern int NDECL(dotalk); /**/
+extern int NDECL(docast); /**/
+extern int NDECL(dovspell); /**/
+extern int NDECL(dotele); /**/
+extern int NDECL(dountrap); /**/
+extern int NDECL(doversion); /**/
+extern int NDECL(doextversion); /**/
+extern int NDECL(doswapweapon); /**/
+extern int NDECL(dowield); /**/
+extern int NDECL(dowieldquiver); /**/
+extern int NDECL(dozap); /**/
+extern int NDECL(doorganize); /**/
+#endif /* DUMB */
+
+#ifdef OVL1
+static int NDECL((*timed_occ_fn));
+#endif /* OVL1 */
+
+STATIC_PTR int NDECL(doprev_message);
+STATIC_PTR int NDECL(timed_occupation);
+STATIC_PTR int NDECL(doextcmd);
+STATIC_PTR int NDECL(domonability);
+STATIC_PTR int NDECL(dotravel);
+# ifdef WIZARD
+STATIC_PTR int NDECL(wiz_wish);
+STATIC_PTR int NDECL(wiz_identify);
+STATIC_PTR int NDECL(wiz_map);
+STATIC_PTR int NDECL(wiz_genesis);
+STATIC_PTR int NDECL(wiz_where);
+STATIC_PTR int NDECL(wiz_detect);
+STATIC_PTR int NDECL(wiz_panic);
+STATIC_PTR int NDECL(wiz_polyself);
+STATIC_PTR int NDECL(wiz_level_tele);
+STATIC_PTR int NDECL(wiz_level_change);
+STATIC_PTR int NDECL(wiz_show_seenv);
+STATIC_PTR int NDECL(wiz_show_vision);
+STATIC_PTR int NDECL(wiz_mon_polycontrol);
+STATIC_PTR int NDECL(wiz_show_wmodes);
+#if defined(__BORLANDC__) && !defined(_WIN32)
+extern void FDECL(show_borlandc_stats, (winid));
+#endif
+#ifdef DEBUG_MIGRATING_MONS
+STATIC_PTR int NDECL(wiz_migrate_mons);
+#endif
+STATIC_DCL void FDECL(count_obj, (struct obj *, long *, long *, BOOLEAN_P, BOOLEAN_P));
+STATIC_DCL void FDECL(obj_chain, (winid, const char *, struct obj *, long *, long *));
+STATIC_DCL void FDECL(mon_invent_chain, (winid, const char *, struct monst *, long *, long *));
+STATIC_DCL void FDECL(mon_chain, (winid, const char *, struct monst *, long *, long *));
+STATIC_DCL void FDECL(contained, (winid, const char *, long *, long *));
+STATIC_PTR int NDECL(wiz_show_stats);
+#  ifdef PORT_DEBUG
+STATIC_DCL int NDECL(wiz_port_debug);
+#  endif
+# endif
+STATIC_PTR int NDECL(enter_explore_mode);
+STATIC_PTR int NDECL(doattributes);
+STATIC_PTR int NDECL(doconduct); /**/
+STATIC_PTR boolean NDECL(minimal_enlightenment);
+
+#ifdef OVLB
+STATIC_DCL void FDECL(enlght_line, (const char *,const char *,const char *));
+STATIC_DCL char *FDECL(enlght_combatinc, (const char *,int,int,char *));
+#ifdef UNIX
+static void NDECL(end_of_input);
+#endif
+#endif /* OVLB */
+
+static const char* readchar_queue="";
+
+STATIC_DCL char *NDECL(parse);
+STATIC_DCL boolean FDECL(help_dir, (CHAR_P,const char *));
+
+#ifdef OVL1
+
+STATIC_PTR int
+doprev_message()
+{
+    return nh_doprev_message();
+}
+
+/* Count down by decrementing multi */
+STATIC_PTR int
+timed_occupation()
+{
+       (*timed_occ_fn)();
+       if (multi > 0)
+               multi--;
+       return multi > 0;
+}
+
+/* If you have moved since initially setting some occupations, they
+ * now shouldn't be able to restart.
+ *
+ * The basic rule is that if you are carrying it, you can continue
+ * since it is with you.  If you are acting on something at a distance,
+ * your orientation to it must have changed when you moved.
+ *
+ * The exception to this is taking off items, since they can be taken
+ * off in a number of ways in the intervening time, screwing up ordering.
+ *
+ *     Currently:      Take off all armor.
+ *                     Picking Locks / Forcing Chests.
+ *                     Setting traps.
+ */
+void
+reset_occupations()
+{
+       reset_remarm();
+       reset_pick();
+       reset_trapset();
+}
+
+/* If a time is given, use it to timeout this function, otherwise the
+ * function times out by its own means.
+ */
+void
+set_occupation(fn, txt, xtime)
+int NDECL((*fn));
+const char *txt;
+int xtime;
+{
+       if (xtime) {
+               occupation = timed_occupation;
+               timed_occ_fn = fn;
+       } else
+               occupation = fn;
+       occtxt = txt;
+       occtime = 0;
+       return;
+}
+
+#ifdef REDO
+
+static char NDECL(popch);
+
+/* 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.
+ */
+#define BSIZE 20
+static char pushq[BSIZE], saveq[BSIZE];
+static NEARDATA int phead, ptail, shead, stail;
+
+static char
+popch() {
+       /* If occupied, return '\0', letting tgetch know a character should
+        * be read from the keyboard.  If the character read is not the
+        * ABORT character (as checked in pcmain.c), that character will be
+        * pushed back on the pushq.
+        */
+       if (occupation) return '\0';
+       if (in_doagain) return(char)((shead != stail) ? saveq[stail++] : '\0');
+       else            return(char)((phead != ptail) ? pushq[ptail++] : '\0');
+}
+
+char
+pgetchar() {           /* curtesy of aeb@cwi.nl */
+       register int ch;
+
+       if(!(ch = popch()))
+               ch = nhgetch();
+       return((char)ch);
+}
+
+/* A ch == 0 resets the pushq */
+void
+pushch(ch)
+char ch;
+{
+       if (!ch)
+               phead = ptail = 0;
+       if (phead < BSIZE)
+               pushq[phead++] = ch;
+       return;
+}
+
+/* A ch == 0 resets the saveq. Only save keystrokes when not
+ * replaying a previous command.
+ */
+void
+savech(ch)
+char ch;
+{
+       if (!in_doagain) {
+               if (!ch)
+                       phead = ptail = shead = stail = 0;
+               else if (shead < BSIZE)
+                       saveq[shead++] = ch;
+       }
+       return;
+}
+#endif /* REDO */
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+STATIC_PTR int
+doextcmd()     /* here after # - now read a full-word command */
+{
+       int idx, retval;
+
+       /* keep repeating until we don't run help or quit */
+       do {
+           idx = get_ext_cmd();
+           if (idx < 0) return 0;      /* quit */
+
+           retval = (*extcmdlist[idx].ef_funct)();
+       } while (extcmdlist[idx].ef_funct == doextlist);
+
+       return retval;
+}
+
+int
+doextlist()    /* here after #? - now list all full-word commands */
+{
+       register const struct ext_func_tab *efp;
+       char     buf[BUFSZ];
+       winid datawin;
+
+       datawin = create_nhwindow(NHW_TEXT);
+       putstr(datawin, 0, "");
+       putstr(datawin, 0, "            Extended Commands List");
+       putstr(datawin, 0, "");
+       putstr(datawin, 0, "    Press '#', then type:");
+       putstr(datawin, 0, "");
+
+       for(efp = extcmdlist; efp->ef_txt; efp++) {
+               Sprintf(buf, "    %-15s - %s.", efp->ef_txt, efp->ef_desc);
+               putstr(datawin, 0, buf);
+       }
+       display_nhwindow(datawin, FALSE);
+       destroy_nhwindow(datawin);
+       return 0;
+}
+
+#ifdef TTY_GRAPHICS
+#define MAX_EXT_CMD 40         /* Change if we ever have > 40 ext cmds */
+/*
+ * This is currently used only by the tty port and is
+ * controlled via runtime option 'extmenu'
+ */
+int
+extcmd_via_menu()      /* here after # - now show pick-list of possible commands */
+{
+    const struct ext_func_tab *efp;
+    menu_item *pick_list = (menu_item *)0;
+    winid win;
+    anything any;
+    const struct ext_func_tab *choices[MAX_EXT_CMD];
+    char buf[BUFSZ];
+    char cbuf[QBUFSZ], prompt[QBUFSZ], fmtstr[20];
+    int i, n, nchoices, acount;
+    int ret,  biggest;
+    int accelerator, prevaccelerator;
+    int  matchlevel = 0;
+
+    ret = 0;
+    cbuf[0] = '\0';
+    biggest = 0;
+    while (!ret) {
+           i = n = 0;
+           accelerator = 0;
+           any.a_void = 0;
+           /* populate choices */
+           for(efp = extcmdlist; efp->ef_txt; efp++) {
+               if (!matchlevel || !strncmp(efp->ef_txt, cbuf, matchlevel)) {
+                       choices[i++] = efp;
+                       if ((int)strlen(efp->ef_desc) > biggest) {
+                               biggest = strlen(efp->ef_desc);
+                               Sprintf(fmtstr,"%%-%ds", biggest + 15);
+                       }
+#ifdef DEBUG
+                       if (i >= MAX_EXT_CMD - 2) {
+                           impossible("Exceeded %d extended commands in doextcmd() menu",
+                                       MAX_EXT_CMD - 2);
+                           return 0;
+                       }
+#endif
+               }
+           }
+           choices[i] = (struct ext_func_tab *)0;
+           nchoices = i;
+           /* if we're down to one, we have our selection so get out of here */
+           if (nchoices == 1) {
+               for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++)
+                       if (!strncmpi(extcmdlist[i].ef_txt, cbuf, matchlevel)) {
+                               ret = i;
+                               break;
+                       }
+               break;
+           }
+
+           /* otherwise... */
+           win = create_nhwindow(NHW_MENU);
+           start_menu(win);
+           prevaccelerator = 0;
+           acount = 0;
+           for(i = 0; choices[i]; ++i) {
+               accelerator = choices[i]->ef_txt[matchlevel];
+               if (accelerator != prevaccelerator || nchoices < (ROWNO - 3)) {
+                   if (acount) {
+                       /* flush the extended commands for that letter already in buf */
+                       Sprintf(buf, fmtstr, prompt);
+                       any.a_char = prevaccelerator;
+                       add_menu(win, NO_GLYPH, &any, any.a_char, 0,
+                                       ATR_NONE, buf, FALSE);
+                       acount = 0;
+                   }
+               }
+               prevaccelerator = accelerator;
+               if (!acount || nchoices < (ROWNO - 3)) {
+                   Sprintf(prompt, "%s [%s]", choices[i]->ef_txt,
+                               choices[i]->ef_desc);
+               } else if (acount == 1) {
+                   Sprintf(prompt, "%s or %s", choices[i-1]->ef_txt,
+                               choices[i]->ef_txt);
+               } else {
+                   Strcat(prompt," or ");
+                   Strcat(prompt, choices[i]->ef_txt);
+               }
+               ++acount;
+           }
+           if (acount) {
+               /* flush buf */
+               Sprintf(buf, fmtstr, prompt);
+               any.a_char = prevaccelerator;
+               add_menu(win, NO_GLYPH, &any, any.a_char, 0, ATR_NONE, buf, FALSE);
+           }
+           Sprintf(prompt, "Extended Command: %s", cbuf);
+           end_menu(win, prompt);
+           n = select_menu(win, PICK_ONE, &pick_list);
+           destroy_nhwindow(win);
+           if (n==1) {
+               if (matchlevel > (QBUFSZ - 2)) {
+                       free((genericptr_t)pick_list);
+#ifdef DEBUG
+                       impossible("Too many characters (%d) entered in extcmd_via_menu()",
+                               matchlevel);
+#endif
+                       ret = -1;
+               } else {
+                       cbuf[matchlevel++] = pick_list[0].item.a_char;
+                       cbuf[matchlevel] = '\0';
+                       free((genericptr_t)pick_list);
+               }
+           } else {
+               if (matchlevel) {
+                       ret = 0;
+                       matchlevel = 0;
+               } else
+                       ret = -1;
+           }
+    }
+    return ret;
+}
+#endif
+
+/* #monster command - use special monster ability while polymorphed */
+STATIC_PTR int
+domonability()
+{
+       if (can_breathe(youmonst.data)) return dobreathe();
+       else if (attacktype(youmonst.data, AT_SPIT)) return dospit();
+       else if (youmonst.data->mlet == S_NYMPH) return doremove();
+       else if (attacktype(youmonst.data, AT_GAZE)) return dogaze();
+       else if (is_were(youmonst.data)) return dosummon();
+       else if (webmaker(youmonst.data)) return dospinweb();
+       else if (is_hider(youmonst.data)) return dohide();
+       else if (is_mind_flayer(youmonst.data)) return domindblast();
+       else if (u.umonnum == PM_GREMLIN) {
+           if(IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
+               if (split_mon(&youmonst, (struct monst *)0))
+                   dryup(u.ux, u.uy, TRUE);
+           } else There("is no fountain here.");
+       } else if (is_unicorn(youmonst.data)) {
+           use_unicorn_horn((struct obj *)0);
+           return 1;
+       } else if (youmonst.data->msound == MS_SHRIEK) {
+           You("shriek.");
+           if(u.uburied)
+               pline("Unfortunately sound does not carry well through rock.");
+           else aggravate();
+       } else if (Upolyd)
+               pline("Any special ability you may have is purely reflexive.");
+       else You("don't have a special ability in your normal form!");
+       return 0;
+}
+
+STATIC_PTR int
+enter_explore_mode()
+{
+       if(!discover && !wizard) {
+               pline("Beware!  From explore mode there will be no return to normal game.");
+               if (yn("Do you want to enter explore mode?") == 'y') {
+                       clear_nhwindow(WIN_MESSAGE);
+                       You("are now in non-scoring explore mode.");
+                       discover = TRUE;
+               }
+               else {
+                       clear_nhwindow(WIN_MESSAGE);
+                       pline("Resuming normal game.");
+               }
+       }
+       return 0;
+}
+
+#ifdef WIZARD
+
+/* ^W command - wish for something */
+STATIC_PTR int
+wiz_wish()     /* Unlimited wishes for debug mode by Paul Polderman */
+{
+       if (wizard) {
+           boolean save_verbose = flags.verbose;
+
+           flags.verbose = FALSE;
+           makewish();
+           flags.verbose = save_verbose;
+           (void) encumber_msg();
+       } else
+           pline("Unavailable command '^W'.");
+       return 0;
+}
+
+/* ^I command - identify hero's inventory */
+STATIC_PTR int
+wiz_identify()
+{
+       if (wizard)     identify_pack(0);
+       else            pline("Unavailable command '^I'.");
+       return 0;
+}
+
+/* ^F command - reveal the level map and any traps on it */
+STATIC_PTR int
+wiz_map()
+{
+       if (wizard) {
+           struct trap *t;
+           long save_Hconf = HConfusion,
+                save_Hhallu = HHallucination;
+
+           HConfusion = HHallucination = 0L;
+           for (t = ftrap; t != 0; t = t->ntrap) {
+               t->tseen = 1;
+               map_trap(t, TRUE);
+           }
+           do_mapping();
+           HConfusion = save_Hconf;
+           HHallucination = save_Hhallu;
+       } else
+           pline("Unavailable command '^F'.");
+       return 0;
+}
+
+/* ^G command - generate monster(s); a count prefix will be honored */
+STATIC_PTR int
+wiz_genesis()
+{
+       if (wizard)     (void) create_particular();
+       else            pline("Unavailable command '^G'.");
+       return 0;
+}
+
+/* ^O command - display dungeon layout */
+STATIC_PTR int
+wiz_where()
+{
+       if (wizard) (void) print_dungeon(FALSE, (schar *)0, (xchar *)0);
+       else        pline("Unavailable command '^O'.");
+       return 0;
+}
+
+/* ^E command - detect unseen (secret doors, traps, hidden monsters) */
+STATIC_PTR int
+wiz_detect()
+{
+       if(wizard)  (void) findit();
+       else        pline("Unavailable command '^E'.");
+       return 0;
+}
+
+/* ^V command - level teleport */
+STATIC_PTR int
+wiz_level_tele()
+{
+       if (wizard)     level_tele();
+       else            pline("Unavailable command '^V'.");
+       return 0;
+}
+
+/* #monpolycontrol command - choose new form for shapechangers, polymorphees */
+STATIC_PTR int
+wiz_mon_polycontrol()
+{
+    iflags.mon_polycontrol = !iflags.mon_polycontrol;
+    pline("Monster polymorph control is %s.",
+         iflags.mon_polycontrol ? "on" : "off");
+    return 0;
+}
+
+/* #levelchange command - adjust hero's experience level */
+STATIC_PTR int
+wiz_level_change()
+{
+    char buf[BUFSZ];
+    int newlevel;
+    int ret;
+
+    getlin("To what experience level do you want to be set?", buf);
+    (void)mungspaces(buf);
+    if (buf[0] == '\033' || buf[0] == '\0') ret = 0;
+    else ret = sscanf(buf, "%d", &newlevel);
+
+    if (ret != 1) {
+       pline(Never_mind);
+       return 0;
+    }
+    if (newlevel == u.ulevel) {
+       You("are already that experienced.");
+    } else if (newlevel < u.ulevel) {
+       if (u.ulevel == 1) {
+           You("are already as inexperienced as you can get.");
+           return 0;
+       }
+       if (newlevel < 1) newlevel = 1;
+       while (u.ulevel > newlevel)
+           losexp("#levelchange");
+    } else {
+       if (u.ulevel >= MAXULEV) {
+           You("are already as experienced as you can get.");
+           return 0;
+       }
+       if (newlevel > MAXULEV) newlevel = MAXULEV;
+       while (u.ulevel < newlevel)
+           pluslvl(FALSE);
+    }
+    u.ulevelmax = u.ulevel;
+    return 0;
+}
+
+/* #panic command - test program's panic handling */
+STATIC_PTR int
+wiz_panic()
+{
+       if (yn("Do you want to call panic() and end your game?") == 'y')
+               panic("crash test.");
+        return 0;
+}
+
+/* #polyself command - change hero's form */
+STATIC_PTR int
+wiz_polyself()
+{
+        polyself(TRUE);
+        return 0;
+}
+
+/* #seenv command */
+STATIC_PTR int
+wiz_show_seenv()
+{
+       winid win;
+       int x, y, v, startx, stopx, curx;
+       char row[COLNO+1];
+
+       win = create_nhwindow(NHW_TEXT);
+       /*
+        * Each seenv description takes up 2 characters, so center
+        * the seenv display around the hero.
+        */
+       startx = max(1, u.ux-(COLNO/4));
+       stopx = min(startx+(COLNO/2), COLNO);
+       /* can't have a line exactly 80 chars long */
+       if (stopx - startx == COLNO/2) startx++;
+
+       for (y = 0; y < ROWNO; y++) {
+           for (x = startx, curx = 0; x < stopx; x++, curx += 2) {
+               if (x == u.ux && y == u.uy) {
+                   row[curx] = row[curx+1] = '@';
+               } else {
+                   v = levl[x][y].seenv & 0xff;
+                   if (v == 0)
+                       row[curx] = row[curx+1] = ' ';
+                   else
+                       Sprintf(&row[curx], "%02x", v);
+               }
+           }
+           /* remove trailing spaces */
+           for (x = curx-1; x >= 0; x--)
+               if (row[x] != ' ') break;
+           row[x+1] = '\0';
+
+           putstr(win, 0, row);
+       }
+       display_nhwindow(win, TRUE);
+       destroy_nhwindow(win);
+       return 0;
+}
+
+/* #vision command */
+STATIC_PTR int
+wiz_show_vision()
+{
+       winid win;
+       int x, y, v;
+       char row[COLNO+1];
+
+       win = create_nhwindow(NHW_TEXT);
+       Sprintf(row, "Flags: 0x%x could see, 0x%x in sight, 0x%x temp lit",
+               COULD_SEE, IN_SIGHT, TEMP_LIT);
+       putstr(win, 0, row);
+       putstr(win, 0, "");
+       for (y = 0; y < ROWNO; y++) {
+           for (x = 1; x < COLNO; x++) {
+               if (x == u.ux && y == u.uy)
+                   row[x] = '@';
+               else {
+                   v = viz_array[y][x]; /* data access should be hidden */
+                   if (v == 0)
+                       row[x] = ' ';
+                   else
+                       row[x] = '0' + viz_array[y][x];
+               }
+           }
+           /* remove trailing spaces */
+           for (x = COLNO-1; x >= 1; x--)
+               if (row[x] != ' ') break;
+           row[x+1] = '\0';
+
+           putstr(win, 0, &row[1]);
+       }
+       display_nhwindow(win, TRUE);
+       destroy_nhwindow(win);
+       return 0;
+}
+
+/* #wmode command */
+STATIC_PTR int
+wiz_show_wmodes()
+{
+       winid win;
+       int x,y;
+       char row[COLNO+1];
+       struct rm *lev;
+
+       win = create_nhwindow(NHW_TEXT);
+       for (y = 0; y < ROWNO; y++) {
+           for (x = 0; x < COLNO; x++) {
+               lev = &levl[x][y];
+               if (x == u.ux && y == u.uy)
+                   row[x] = '@';
+               else if (IS_WALL(lev->typ) || lev->typ == SDOOR)
+                   row[x] = '0' + (lev->wall_info & WM_MASK);
+               else if (lev->typ == CORR)
+                   row[x] = '#';
+               else if (IS_ROOM(lev->typ) || IS_DOOR(lev->typ))
+                   row[x] = '.';
+               else
+                   row[x] = 'x';
+           }
+           row[COLNO] = '\0';
+           putstr(win, 0, row);
+       }
+       display_nhwindow(win, TRUE);
+       destroy_nhwindow(win);
+       return 0;
+}
+
+#endif /* WIZARD */
+
+
+/* -enlightenment and conduct- */
+static winid en_win;
+static const char
+       You_[] = "You ",
+       are[]  = "are ",  were[]  = "were ",
+       have[] = "have ", had[]   = "had ",
+       can[]  = "can ",  could[] = "could ";
+static const char
+       have_been[]  = "have been ",
+       have_never[] = "have never ", never[] = "never ";
+
+#define enl_msg(prefix,present,past,suffix) \
+                       enlght_line(prefix, final ? past : present, suffix)
+#define you_are(attr)  enl_msg(You_,are,were,attr)
+#define you_have(attr) enl_msg(You_,have,had,attr)
+#define you_can(attr)  enl_msg(You_,can,could,attr)
+#define you_have_been(goodthing) enl_msg(You_,have_been,were,goodthing)
+#define you_have_never(badthing) enl_msg(You_,have_never,never,badthing)
+#define you_have_X(something)  enl_msg(You_,have,(const char *)"",something)
+
+static void
+enlght_line(start, middle, end)
+const char *start, *middle, *end;
+{
+       char buf[BUFSZ];
+
+       Sprintf(buf, "%s%s%s.", start, middle, end);
+       putstr(en_win, 0, buf);
+}
+
+/* format increased damage or chance to hit */
+static char *
+enlght_combatinc(inctyp, incamt, final, outbuf)
+const char *inctyp;
+int incamt, final;
+char *outbuf;
+{
+       char numbuf[24];
+       const char *modif, *bonus;
+
+       if (final
+#ifdef WIZARD
+               || wizard
+#endif
+         ) {
+           Sprintf(numbuf, "%s%d",
+                   (incamt > 0) ? "+" : "", incamt);
+           modif = (const char *) numbuf;
+       } else {
+           int absamt = abs(incamt);
+
+           if (absamt <= 3) modif = "small";
+           else if (absamt <= 6) modif = "moderate";
+           else if (absamt <= 12) modif = "large";
+           else modif = "huge";
+       }
+       bonus = (incamt > 0) ? "bonus" : "penalty";
+       /* "bonus to hit" vs "damage bonus" */
+       if (!strcmp(inctyp, "damage")) {
+           const char *ctmp = inctyp;
+           inctyp = bonus;
+           bonus = ctmp;
+       }
+       Sprintf(outbuf, "%s %s %s", an(modif), bonus, inctyp);
+       return outbuf;
+}
+
+void
+enlightenment(final)
+int final;     /* 0 => still in progress; 1 => over, survived; 2 => dead */
+{
+       int ltmp;
+       char buf[BUFSZ];
+
+       en_win = create_nhwindow(NHW_MENU);
+       putstr(en_win, 0, final ? "Final Attributes:" : "Current Attributes:");
+       putstr(en_win, 0, "");
+
+#ifdef ELBERETH
+       if (u.uevent.uhand_of_elbereth) {
+           static const char * const hofe_titles[3] = {
+                               "the Hand of Elbereth",
+                               "the Envoy of Balance",
+                               "the Glory of Arioch"
+           };
+           you_are(hofe_titles[u.uevent.uhand_of_elbereth - 1]);
+       }
+#endif
+
+       /* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */
+       if (u.ualign.record >= 20)      you_are("piously aligned");
+       else if (u.ualign.record > 13)  you_are("devoutly aligned");
+       else if (u.ualign.record > 8)   you_are("fervently aligned");
+       else if (u.ualign.record > 3)   you_are("stridently aligned");
+       else if (u.ualign.record == 3)  you_are("aligned");
+       else if (u.ualign.record > 0)   you_are("haltingly aligned");
+       else if (u.ualign.record == 0)  you_are("nominally aligned");
+       else if (u.ualign.record >= -3) you_have("strayed");
+       else if (u.ualign.record >= -8) you_have("sinned");
+       else you_have("transgressed");
+#ifdef WIZARD
+       if (wizard) {
+               Sprintf(buf, " %d", u.ualign.record);
+               enl_msg("Your alignment ", "is", "was", buf);
+       }
+#endif
+
+       /*** Resistances to troubles ***/
+       if (Fire_resistance) you_are("fire resistant");
+       if (Cold_resistance) you_are("cold resistant");
+       if (Sleep_resistance) you_are("sleep resistant");
+       if (Disint_resistance) you_are("disintegration-resistant");
+       if (Shock_resistance) you_are("shock resistant");
+       if (Poison_resistance) you_are("poison resistant");
+       if (Drain_resistance) you_are("level-drain resistant");
+       if (Sick_resistance) you_are("immune to sickness");
+       if (Antimagic) you_are("magic-protected");
+       if (Acid_resistance) you_are("acid resistant");
+       if (Stone_resistance)
+               you_are("petrification resistant");
+       if (Invulnerable) you_are("invulnerable");
+       if (u.uedibility) you_can("recognize detrimental food");
+
+       /*** Troubles ***/
+       if (Halluc_resistance)
+               enl_msg("You resist", "", "ed", " hallucinations");
+       if (final) {
+               if (Hallucination) you_are("hallucinating");
+               if (Stunned) you_are("stunned");
+               if (Confusion) you_are("confused");
+               if (Blinded) you_are("blinded");
+               if (Sick) {
+                       if (u.usick_type & SICK_VOMITABLE)
+                               you_are("sick from food poisoning");
+                       if (u.usick_type & SICK_NONVOMITABLE)
+                               you_are("sick from illness");
+               }
+       }
+       if (Stoned) you_are("turning to stone");
+       if (Slimed) you_are("turning into slime");
+       if (Strangled) you_are((u.uburied) ? "buried" : "being strangled");
+       if (Glib) {
+               Sprintf(buf, "slippery %s", makeplural(body_part(FINGER)));
+               you_have(buf);
+       }
+       if (Fumbling) enl_msg("You fumble", "", "d", "");
+       if (Wounded_legs
+#ifdef STEED
+           && !u.usteed
+#endif
+                         ) {
+               Sprintf(buf, "wounded %s", makeplural(body_part(LEG)));
+               you_have(buf);
+       }
+#if defined(WIZARD) && defined(STEED)
+       if (Wounded_legs && u.usteed && wizard) {
+           Strcpy(buf, x_monnam(u.usteed, ARTICLE_YOUR, (char *)0, 
+                   SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION, FALSE));
+           *buf = highc(*buf);
+           enl_msg(buf, " has", " had", " wounded legs");
+       }
+#endif
+       if (Sleeping) enl_msg("You ", "fall", "fell", " asleep");
+       if (Hunger) enl_msg("You hunger", "", "ed", " rapidly");
+
+       /*** Vision and senses ***/
+       if (See_invisible) enl_msg(You_, "see", "saw", " invisible");
+       if (Blind_telepat) you_are("telepathic");
+       if (Warning) you_are("warned");
+       if (Warn_of_mon && flags.warntype) {
+               Sprintf(buf, "aware of the presence of %s",
+                       (flags.warntype & M2_ORC) ? "orcs" :
+                       (flags.warntype & M2_DEMON) ? "demons" :
+                       something); 
+               you_are(buf);
+       }
+       if (Undead_warning) you_are("warned of undead");
+       if (Searching) you_have("automatic searching");
+       if (Clairvoyant) you_are("clairvoyant");
+       if (Infravision) you_have("infravision");
+       if (Detect_monsters) you_are("sensing the presence of monsters");
+       if (u.umconf) you_are("going to confuse monsters");
+
+       /*** Appearance and behavior ***/
+       if (Adornment) {
+           int adorn = 0;
+
+           if(uleft && uleft->otyp == RIN_ADORNMENT) adorn += uleft->spe;
+           if(uright && uright->otyp == RIN_ADORNMENT) adorn += uright->spe;
+           if (adorn < 0)
+               you_are("poorly adorned");
+           else
+               you_are("adorned");
+       }
+       if (Invisible) you_are("invisible");
+       else if (Invis) you_are("invisible to others");
+       /* ordinarily "visible" is redundant; this is a special case for
+          the situation when invisibility would be an expected attribute */
+       else if ((HInvis || EInvis || pm_invisible(youmonst.data)) && BInvis)
+           you_are("visible");
+       if (Displaced) you_are("displaced");
+       if (Stealth) you_are("stealthy");
+       if (Aggravate_monster) enl_msg("You aggravate", "", "d", " monsters");
+       if (Conflict) enl_msg("You cause", "", "d", " conflict");
+
+       /*** Transportation ***/
+       if (Jumping) you_can("jump");
+       if (Teleportation) you_can("teleport");
+       if (Teleport_control) you_have("teleport control");
+       if (Lev_at_will) you_are("levitating, at will");
+       else if (Levitation) you_are("levitating");     /* without control */
+       else if (Flying) you_can("fly");
+       if (Wwalking) you_can("walk on water");
+       if (Swimming) you_can("swim");        
+       if (Breathless) you_can("survive without air");
+       else if (Amphibious) you_can("breathe water");
+       if (Passes_walls) you_can("walk through walls");
+#ifdef STEED
+       /* If you die while dismounting, u.usteed is still set.  Since several
+        * places in the done() sequence depend on u.usteed, just detect this
+        * special case. */
+       if (u.usteed && (final < 2 || strcmp(killer, "riding accident"))) {
+           Sprintf(buf, "riding %s", y_monnam(u.usteed));
+           you_are(buf);
+       }
+#endif
+       if (u.uswallow) {
+           Sprintf(buf, "swallowed by %s", a_monnam(u.ustuck));
+#ifdef WIZARD
+           if (wizard) Sprintf(eos(buf), " (%u)", u.uswldtim);
+#endif
+           you_are(buf);
+       } else if (u.ustuck) {
+           Sprintf(buf, "%s %s",
+                   (Upolyd && sticks(youmonst.data)) ? "holding" : "held by",
+                   a_monnam(u.ustuck));
+           you_are(buf);
+       }
+
+       /*** Physical attributes ***/
+       if (u.uhitinc)
+           you_have(enlght_combatinc("to hit", u.uhitinc, final, buf));
+       if (u.udaminc)
+           you_have(enlght_combatinc("damage", u.udaminc, final, buf));
+       if (Slow_digestion) you_have("slower digestion");
+       if (Regeneration) enl_msg("You regenerate", "", "d", "");
+       if (u.uspellprot || Protection) {
+           int prot = 0;
+
+           if(uleft && uleft->otyp == RIN_PROTECTION) prot += uleft->spe;
+           if(uright && uright->otyp == RIN_PROTECTION) prot += uright->spe;
+           if (HProtection & INTRINSIC) prot += u.ublessed;
+           prot += u.uspellprot;
+
+           if (prot < 0)
+               you_are("ineffectively protected");
+           else
+               you_are("protected");
+       }
+       if (Protection_from_shape_changers)
+               you_are("protected from shape changers");
+       if (Polymorph) you_are("polymorphing");
+       if (Polymorph_control) you_have("polymorph control");
+       if (u.ulycn >= LOW_PM) {
+               Strcpy(buf, an(mons[u.ulycn].mname));
+               you_are(buf);
+       }
+       if (Upolyd) {
+           if (u.umonnum == u.ulycn) Strcpy(buf, "in beast form");
+           else Sprintf(buf, "polymorphed into %s", an(youmonst.data->mname));
+#ifdef WIZARD
+           if (wizard) Sprintf(eos(buf), " (%d)", u.mtimedone);
+#endif
+           you_are(buf);
+       }
+       if (Unchanging) you_can("not change from your current form");
+       if (Fast) you_are(Very_fast ? "very fast" : "fast");
+       if (Reflecting) you_have("reflection");
+       if (Free_action) you_have("free action");
+       if (Fixed_abil) you_have("fixed abilities");
+       if (Lifesaved)
+               enl_msg("Your life ", "will be", "would have been", " saved");
+       if (u.twoweap) you_are("wielding two weapons at once");
+
+       /*** Miscellany ***/
+       if (Luck) {
+           ltmp = abs((int)Luck);
+           Sprintf(buf, "%s%slucky",
+                   ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "",
+                   Luck < 0 ? "un" : "");
+#ifdef WIZARD
+           if (wizard) Sprintf(eos(buf), " (%d)", Luck);
+#endif
+           you_are(buf);
+       }
+#ifdef WIZARD
+        else if (wizard) enl_msg("Your luck ", "is", "was", " zero");
+#endif
+       if (u.moreluck > 0) you_have("extra luck");
+       else if (u.moreluck < 0) you_have("reduced luck");
+       if (carrying(LUCKSTONE) || stone_luck(TRUE)) {
+           ltmp = stone_luck(FALSE);
+           if (ltmp <= 0)
+               enl_msg("Bad luck ", "does", "did", " not time out for you");
+           if (ltmp >= 0)
+               enl_msg("Good luck ", "does", "did", " not time out for you");
+       }
+
+       if (u.ugangr) {
+           Sprintf(buf, " %sangry with you",
+                   u.ugangr > 6 ? "extremely " : u.ugangr > 3 ? "very " : "");
+#ifdef WIZARD
+           if (wizard) Sprintf(eos(buf), " (%d)", u.ugangr);
+#endif
+           enl_msg(u_gname(), " is", " was", buf);
+       } else
+           /*
+            * We need to suppress this when the game is over, because death
+            * can change the value calculated by can_pray(), potentially
+            * resulting in a false claim that you could have prayed safely.
+            */
+         if (!final) {
+#if 0
+           /* "can [not] safely pray" vs "could [not] have safely prayed" */
+           Sprintf(buf, "%s%ssafely pray%s", can_pray(FALSE) ? "" : "not ",
+                   final ? "have " : "", final ? "ed" : "");
+#else
+           Sprintf(buf, "%ssafely pray", can_pray(FALSE) ? "" : "not ");
+#endif
+#ifdef WIZARD
+           if (wizard) Sprintf(eos(buf), " (%d)", u.ublesscnt);
+#endif
+           you_can(buf);
+       }
+
+    {
+       const char *p;
+
+       buf[0] = '\0';
+       if (final < 2) {    /* still in progress, or quit/escaped/ascended */
+           p = "survived after being killed ";
+           switch (u.umortality) {
+           case 0:  p = !final ? (char *)0 : "survived";  break;
+           case 1:  Strcpy(buf, "once");  break;
+           case 2:  Strcpy(buf, "twice");  break;
+           case 3:  Strcpy(buf, "thrice");  break;
+           default: Sprintf(buf, "%d times", u.umortality);
+                    break;
+           }
+       } else {                /* game ended in character's death */
+           p = "are dead";
+           switch (u.umortality) {
+           case 0:  impossible("dead without dying?");
+           case 1:  break;                     /* just "are dead" */
+           default: Sprintf(buf, " (%d%s time!)", u.umortality,
+                            ordin(u.umortality));
+                    break;
+           }
+       }
+       if (p) enl_msg(You_, "have been killed ", p, buf);
+    }
+
+       display_nhwindow(en_win, TRUE);
+       destroy_nhwindow(en_win);
+       return;
+}
+
+/*
+ * Courtesy function for non-debug, non-explorer mode players
+ * to help refresh them about who/what they are.
+ * Returns FALSE if menu cancelled (dismissed with ESC), TRUE otherwise.
+ */
+STATIC_OVL boolean
+minimal_enlightenment()
+{
+       winid tmpwin;
+       menu_item *selected;
+       anything any;
+       int genidx, n;
+       char buf[BUFSZ], buf2[BUFSZ];
+       static const char untabbed_fmtstr[] = "%-15s: %-12s";
+       static const char untabbed_deity_fmtstr[] = "%-17s%s";
+       static const char tabbed_fmtstr[] = "%s:\t%-12s";
+       static const char tabbed_deity_fmtstr[] = "%s\t%s";
+       static const char *fmtstr;
+       static const char *deity_fmtstr;
+
+       fmtstr = iflags.menu_tab_sep ? tabbed_fmtstr : untabbed_fmtstr;
+       deity_fmtstr = iflags.menu_tab_sep ?
+                       tabbed_deity_fmtstr : untabbed_deity_fmtstr; 
+       any.a_void = 0;
+       buf[0] = buf2[0] = '\0';
+       tmpwin = create_nhwindow(NHW_MENU);
+       start_menu(tmpwin);
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Starting", FALSE);
+
+       /* Starting name, race, role, gender */
+       Sprintf(buf, fmtstr, "name", plname);
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+       Sprintf(buf, fmtstr, "race", urace.noun);
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+       Sprintf(buf, fmtstr, "role",
+               (flags.initgend && urole.name.f) ? urole.name.f : urole.name.m);
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+       Sprintf(buf, fmtstr, "gender", genders[flags.initgend].adj);
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+
+       /* Starting alignment */
+       Sprintf(buf, fmtstr, "alignment", align_str(u.ualignbase[A_ORIGINAL]));
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+
+       /* Current name, race, role, gender */
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE);
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Current", FALSE);
+       Sprintf(buf, fmtstr, "race", Upolyd ? youmonst.data->mname : urace.noun);
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+       if (Upolyd) {
+           Sprintf(buf, fmtstr, "role (base)",
+               (u.mfemale && urole.name.f) ? urole.name.f : urole.name.m);
+           add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+       } else {
+           Sprintf(buf, fmtstr, "role",
+               (flags.female && urole.name.f) ? urole.name.f : urole.name.m);
+           add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+       }
+       /* don't want poly_gender() here; it forces `2' for non-humanoids */
+       genidx = is_neuter(youmonst.data) ? 2 : flags.female;
+       Sprintf(buf, fmtstr, "gender", genders[genidx].adj);
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+       if (Upolyd && (int)u.mfemale != genidx) {
+           Sprintf(buf, fmtstr, "gender (base)", genders[u.mfemale].adj);
+           add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+       }
+
+       /* Current alignment */
+       Sprintf(buf, fmtstr, "alignment", align_str(u.ualign.type));
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+
+       /* Deity list */
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE);
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Deities", FALSE);
+       Sprintf(buf2, deity_fmtstr, align_gname(A_CHAOTIC),
+           (u.ualignbase[A_ORIGINAL] == u.ualign.type
+               && u.ualign.type == A_CHAOTIC) ? " (s,c)" :
+           (u.ualignbase[A_ORIGINAL] == A_CHAOTIC)       ? " (s)" :
+           (u.ualign.type   == A_CHAOTIC)       ? " (c)" : "");
+       Sprintf(buf, fmtstr, "Chaotic", buf2);
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+
+       Sprintf(buf2, deity_fmtstr, align_gname(A_NEUTRAL),
+           (u.ualignbase[A_ORIGINAL] == u.ualign.type
+               && u.ualign.type == A_NEUTRAL) ? " (s,c)" :
+           (u.ualignbase[A_ORIGINAL] == A_NEUTRAL)       ? " (s)" :
+           (u.ualign.type   == A_NEUTRAL)       ? " (c)" : "");
+       Sprintf(buf, fmtstr, "Neutral", buf2);
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+
+       Sprintf(buf2, deity_fmtstr, align_gname(A_LAWFUL),
+           (u.ualignbase[A_ORIGINAL] == u.ualign.type &&
+               u.ualign.type == A_LAWFUL)  ? " (s,c)" :
+           (u.ualignbase[A_ORIGINAL] == A_LAWFUL)        ? " (s)" :
+           (u.ualign.type   == A_LAWFUL)        ? " (c)" : "");
+       Sprintf(buf, fmtstr, "Lawful", buf2);
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+
+       end_menu(tmpwin, "Base Attributes");
+       n = select_menu(tmpwin, PICK_NONE, &selected);
+       destroy_nhwindow(tmpwin);
+       return (n != -1);
+}
+
+STATIC_PTR int
+doattributes()
+{
+       if (!minimal_enlightenment())
+               return 0;
+       if (wizard || discover)
+               enlightenment(0);
+       return 0;
+}
+
+/* KMH, #conduct
+ * (shares enlightenment's tense handling)
+ */
+STATIC_PTR int
+doconduct()
+{
+       show_conduct(0);
+       return 0;
+}
+
+void
+show_conduct(final)
+int final;
+{
+       char buf[BUFSZ];
+       int ngenocided;
+
+       /* Create the conduct window */
+       en_win = create_nhwindow(NHW_MENU);
+       putstr(en_win, 0, "Voluntary challenges:");
+       putstr(en_win, 0, "");
+
+       if (!u.uconduct.food)
+           enl_msg(You_, "have gone", "went", " without food");
+           /* But beverages are okay */
+       else if (!u.uconduct.unvegan)
+           you_have_X("followed a strict vegan diet");
+       else if (!u.uconduct.unvegetarian)
+           you_have_been("vegetarian");
+
+       if (!u.uconduct.gnostic)
+           you_have_been("an atheist");
+
+       if (!u.uconduct.weaphit)
+           you_have_never("hit with a wielded weapon");
+#ifdef WIZARD
+       else if (wizard) {
+           Sprintf(buf, "used a wielded weapon %ld time%s",
+                   u.uconduct.weaphit, plur(u.uconduct.weaphit));
+           you_have_X(buf);
+       }
+#endif
+       if (!u.uconduct.killer)
+           you_have_been("a pacifist");
+
+       if (!u.uconduct.literate)
+           you_have_been("illiterate");
+#ifdef WIZARD
+       else if (wizard) {
+           Sprintf(buf, "read items or engraved %ld time%s",
+                   u.uconduct.literate, plur(u.uconduct.literate));
+           you_have_X(buf);
+       }
+#endif
+
+       ngenocided = num_genocides();
+       if (ngenocided == 0) {
+           you_have_never("genocided any monsters");
+       } else {
+           Sprintf(buf, "genocided %d type%s of monster%s",
+                   ngenocided, plur(ngenocided), plur(ngenocided));
+           you_have_X(buf);
+       }
+
+       if (!u.uconduct.polypiles)
+           you_have_never("polymorphed an object");
+#ifdef WIZARD
+       else if (wizard) {
+           Sprintf(buf, "polymorphed %ld item%s",
+                   u.uconduct.polypiles, plur(u.uconduct.polypiles));
+           you_have_X(buf);
+       }
+#endif
+
+       if (!u.uconduct.polyselfs)
+           you_have_never("changed form");
+#ifdef WIZARD
+       else if (wizard) {
+           Sprintf(buf, "changed form %ld time%s",
+                   u.uconduct.polyselfs, plur(u.uconduct.polyselfs));
+           you_have_X(buf);
+       }
+#endif
+
+       if (!u.uconduct.wishes)
+           you_have_X("used no wishes");
+       else {
+           Sprintf(buf, "used %ld wish%s",
+                   u.uconduct.wishes, (u.uconduct.wishes > 1L) ? "es" : "");
+           you_have_X(buf);
+
+           if (!u.uconduct.wisharti)
+               enl_msg(You_, "have not wished", "did not wish",
+                       " for any artifacts");
+       }
+
+       /* Pop up the window and wait for a key */
+       display_nhwindow(en_win, TRUE);
+       destroy_nhwindow(en_win);
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+#ifndef M
+# ifndef NHSTDC
+#  define M(c)         (0x80 | (c))
+# else
+#  define M(c)         ((c) - 128)
+# endif /* NHSTDC */
+#endif
+#ifndef C
+#define C(c)           (0x1f & (c))
+#endif
+
+static const struct func_tab cmdlist[] = {
+       {C('d'), FALSE, dokick}, /* "D" is for door!...?  Msg is in dokick.c */
+#ifdef WIZARD
+       {C('e'), TRUE, wiz_detect},
+       {C('f'), TRUE, wiz_map},
+       {C('g'), TRUE, wiz_genesis},
+       {C('i'), TRUE, wiz_identify},
+#endif
+       {C('l'), TRUE, doredraw}, /* if number_pad is set */
+#ifdef WIZARD
+       {C('o'), TRUE, wiz_where},
+#endif
+       {C('p'), TRUE, doprev_message},
+       {C('r'), TRUE, doredraw},
+       {C('t'), TRUE, dotele},
+#ifdef WIZARD
+       {C('v'), TRUE, wiz_level_tele},
+       {C('w'), TRUE, wiz_wish},
+#endif
+       {C('x'), TRUE, doattributes},
+#ifdef SUSPEND
+       {C('z'), TRUE, dosuspend},
+#endif
+       {'a', FALSE, doapply},
+       {'A', FALSE, doddoremarm},
+       {M('a'), TRUE, doorganize},
+/*     'b', 'B' : go sw */
+       {'c', FALSE, doclose},
+       {'C', TRUE, do_mname},
+       {M('c'), TRUE, dotalk},
+       {'d', FALSE, dodrop},
+       {'D', FALSE, doddrop},
+       {M('d'), FALSE, dodip},
+       {'e', FALSE, doeat},
+       {'E', FALSE, doengrave},
+       {M('e'), TRUE, enhance_weapon_skill},
+       {'f', FALSE, dofire},
+/*     'F' : fight (one time) */
+       {M('f'), FALSE, doforce},
+/*     'g', 'G' : multiple go */
+/*     'h', 'H' : go west */
+       {'h', TRUE, dohelp}, /* if number_pad is set */
+       {'i', TRUE, ddoinv},
+       {'I', TRUE, dotypeinv},         /* Robert Viduya */
+       {M('i'), TRUE, doinvoke},
+/*     'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */
+       {'j', FALSE, dojump}, /* if number_pad is on */
+       {M('j'), FALSE, dojump},
+       {'k', FALSE, dokick}, /* if number_pad is on */
+       {'l', FALSE, doloot}, /* if number_pad is on */
+       {M('l'), FALSE, doloot},
+/*     'n' prefixes a count if number_pad is on */
+       {M('m'), TRUE, domonability},
+       {'N', TRUE, ddocall}, /* if number_pad is on */
+       {M('n'), TRUE, ddocall},
+       {M('N'), TRUE, ddocall},
+       {'o', FALSE, doopen},
+       {'O', TRUE, doset},
+       {M('o'), FALSE, dosacrifice},
+       {'p', FALSE, dopay},
+       {'P', FALSE, doputon},
+       {M('p'), TRUE, dopray},
+       {'q', FALSE, dodrink},
+       {'Q', FALSE, dowieldquiver},
+       {M('q'), TRUE, done2},
+       {'r', FALSE, doread},
+       {'R', FALSE, doremring},
+       {M('r'), FALSE, dorub},
+       {'s', TRUE, dosearch, "searching"},
+       {'S', TRUE, dosave},
+       {M('s'), FALSE, dosit},
+       {'t', FALSE, dothrow},
+       {'T', FALSE, dotakeoff},
+       {M('t'), TRUE, doturn},
+/*     'u', 'U' : go ne */
+       {'u', FALSE, dountrap}, /* if number_pad is on */
+       {M('u'), FALSE, dountrap},
+       {'v', TRUE, doversion},
+       {'V', TRUE, dohistory},
+       {M('v'), TRUE, doextversion},
+       {'w', FALSE, dowield},
+       {'W', FALSE, dowear},
+       {M('w'), FALSE, dowipe},
+       {'x', FALSE, doswapweapon},
+       {'X', TRUE, enter_explore_mode},
+/*     'y', 'Y' : go nw */
+       {'z', FALSE, dozap},
+       {'Z', TRUE, docast},
+       {'<', FALSE, doup},
+       {'>', FALSE, dodown},
+       {'/', TRUE, dowhatis},
+       {'&', TRUE, dowhatdoes},
+       {'?', TRUE, dohelp},
+       {M('?'), TRUE, doextlist},
+#ifdef SHELL
+       {'!', TRUE, dosh},
+#endif
+       {'.', TRUE, donull, "waiting"},
+       {' ', TRUE, donull, "waiting"},
+       {',', FALSE, dopickup},
+       {':', TRUE, dolook},
+       {';', TRUE, doquickwhatis},
+       {'^', TRUE, doidtrap},
+       {'\\', TRUE, dodiscovered},             /* Robert Viduya */
+       {'@', TRUE, dotogglepickup},
+       {M('2'), FALSE, dotwoweapon},
+       {WEAPON_SYM,  TRUE, doprwep},
+       {ARMOR_SYM,  TRUE, doprarm},
+       {RING_SYM,  TRUE, doprring},
+       {AMULET_SYM, TRUE, dopramulet},
+       {TOOL_SYM, TRUE, doprtool},
+       {'*', TRUE, doprinuse}, /* inventory of all equipment in use */
+       {GOLD_SYM, TRUE, doprgold},
+       {SPBOOK_SYM, TRUE, dovspell},                   /* Mike Stephenson */
+       {'#', TRUE, doextcmd},
+       {'_', TRUE, dotravel},
+       {0,0,0,0}
+};
+
+struct ext_func_tab extcmdlist[] = {
+       {"adjust", "adjust inventory letters", doorganize, TRUE},
+       {"chat", "talk to someone", dotalk, TRUE},      /* converse? */
+       {"conduct", "list which challenges you have adhered to", doconduct, TRUE},
+       {"dip", "dip an object into something", dodip, FALSE},
+       {"enhance", "advance or check weapons skills", enhance_weapon_skill,
+                                                       TRUE},
+       {"force", "force a lock", doforce, FALSE},
+       {"invoke", "invoke an object's powers", doinvoke, TRUE},
+       {"jump", "jump to a location", dojump, FALSE},
+       {"loot", "loot a box on the floor", doloot, FALSE},
+       {"monster", "use a monster's special ability", domonability, TRUE},
+       {"name", "name an item or type of object", ddocall, TRUE},
+       {"offer", "offer a sacrifice to the gods", dosacrifice, FALSE},
+       {"pray", "pray to the gods for help", dopray, TRUE},
+       {"quit", "exit without saving current game", done2, TRUE},
+#ifdef STEED
+       {"ride", "ride (or stop riding) a monster", doride, FALSE},
+#endif
+       {"rub", "rub a lamp or a stone", dorub, FALSE},
+       {"sit", "sit down", dosit, FALSE},
+       {"turn", "turn undead", doturn, TRUE},
+       {"twoweapon", "toggle two-weapon combat", dotwoweapon, FALSE},
+       {"untrap", "untrap something", dountrap, FALSE},
+       {"version", "list compile time options for this version of NetHack",
+               doextversion, TRUE},
+       {"wipe", "wipe off your face", dowipe, FALSE},
+       {"?", "get this list of extended commands", doextlist, TRUE},
+#if defined(WIZARD)
+       /*
+        * There must be a blank entry here for every entry in the table
+        * below.
+        */
+       {(char *)0, (char *)0, donull, TRUE},
+       {(char *)0, (char *)0, donull, TRUE},
+#ifdef DEBUG_MIGRATING_MONS
+       {(char *)0, (char *)0, donull, TRUE},
+#endif
+       {(char *)0, (char *)0, donull, TRUE},
+       {(char *)0, (char *)0, donull, TRUE},
+       {(char *)0, (char *)0, donull, TRUE},
+#ifdef PORT_DEBUG
+       {(char *)0, (char *)0, donull, TRUE},
+#endif
+       {(char *)0, (char *)0, donull, TRUE},
+        {(char *)0, (char *)0, donull, TRUE},
+       {(char *)0, (char *)0, donull, TRUE},
+       {(char *)0, (char *)0, donull, TRUE},
+#ifdef DEBUG
+       {(char *)0, (char *)0, donull, TRUE},
+#endif
+       {(char *)0, (char *)0, donull, TRUE},
+#endif
+       {(char *)0, (char *)0, donull, TRUE}    /* sentinel */
+};
+
+#if defined(WIZARD)
+static const struct ext_func_tab debug_extcmdlist[] = {
+       {"levelchange", "change experience level", wiz_level_change, TRUE},
+       {"lightsources", "show mobile light sources", wiz_light_sources, TRUE},
+#ifdef DEBUG_MIGRATING_MONS
+       {"migratemons", "migrate n random monsters", wiz_migrate_mons, TRUE},
+#endif
+       {"monpolycontrol", "control monster polymorphs", wiz_mon_polycontrol, TRUE},
+       {"panic", "test panic routine (fatal to game)", wiz_panic, TRUE},
+       {"polyself", "polymorph self", wiz_polyself, TRUE},
+#ifdef PORT_DEBUG
+       {"portdebug", "wizard port debug command", wiz_port_debug, TRUE},
+#endif
+       {"seenv", "show seen vectors", wiz_show_seenv, TRUE},
+       {"stats", "show memory statistics", wiz_show_stats, TRUE},
+       {"timeout", "look at timeout queue", wiz_timeout_queue, TRUE},
+       {"vision", "show vision array", wiz_show_vision, TRUE},
+#ifdef DEBUG
+       {"wizdebug", "wizard debug command", wiz_debug_cmd, TRUE},
+#endif
+       {"wmode", "show wall modes", wiz_show_wmodes, TRUE},
+       {(char *)0, (char *)0, donull, TRUE}
+};
+
+/*
+ * Insert debug commands into the extended command list.  This function
+ * assumes that the last entry will be the help entry.
+ *
+ * You must add entries in ext_func_tab every time you add one to the
+ * debug_extcmdlist().
+ */
+void
+add_debug_extended_commands()
+{
+       int i, j, k, n;
+
+       /* count the # of help entries */
+       for (n = 0; extcmdlist[n].ef_txt[0] != '?'; n++)
+           ;
+
+       for (i = 0; debug_extcmdlist[i].ef_txt; i++) {
+           for (j = 0; j < n; j++)
+               if (strcmp(debug_extcmdlist[i].ef_txt, extcmdlist[j].ef_txt) < 0) break;
+
+           /* insert i'th debug entry into extcmdlist[j], pushing down  */
+           for (k = n; k >= j; --k)
+               extcmdlist[k+1] = extcmdlist[k];
+           extcmdlist[j] = debug_extcmdlist[i];
+           n++;        /* now an extra entry */
+       }
+}
+
+
+static const char template[] = "%-18s %4ld  %6ld";
+static const char count_str[] = "                   count  bytes";
+static const char separator[] = "------------------ -----  ------";
+
+STATIC_OVL void
+count_obj(chain, total_count, total_size, top, recurse)
+       struct obj *chain;
+       long *total_count;
+       long *total_size;
+       boolean top;
+       boolean recurse;
+{
+       long count, size;
+       struct obj *obj;
+
+       for (count = size = 0, obj = chain; obj; obj = obj->nobj) {
+           if (top) {
+               count++;
+               size += sizeof(struct obj) + obj->oxlth + obj->onamelth;
+           }
+           if (recurse && obj->cobj)
+               count_obj(obj->cobj, total_count, total_size, TRUE, TRUE);
+       }
+       *total_count += count;
+       *total_size += size;
+}
+
+STATIC_OVL void
+obj_chain(win, src, chain, total_count, total_size)
+       winid win;
+       const char *src;
+       struct obj *chain;
+       long *total_count;
+       long *total_size;
+{
+       char buf[BUFSZ];
+       long count = 0, size = 0;
+
+       count_obj(chain, &count, &size, TRUE, FALSE);
+       *total_count += count;
+       *total_size += size;
+       Sprintf(buf, template, src, count, size);
+       putstr(win, 0, buf);
+}
+
+STATIC_OVL void
+mon_invent_chain(win, src, chain, total_count, total_size)
+       winid win;
+       const char *src;
+       struct monst *chain;
+       long *total_count;
+       long *total_size;
+{
+       char buf[BUFSZ];
+       long count = 0, size = 0;
+       struct monst *mon;
+
+       for (mon = chain; mon; mon = mon->nmon)
+           count_obj(mon->minvent, &count, &size, TRUE, FALSE);
+       *total_count += count;
+       *total_size += size;
+       Sprintf(buf, template, src, count, size);
+       putstr(win, 0, buf);
+}
+
+STATIC_OVL void
+contained(win, src, total_count, total_size)
+       winid win;
+       const char *src;
+       long *total_count;
+       long *total_size;
+{
+       char buf[BUFSZ];
+       long count = 0, size = 0;
+       struct monst *mon;
+
+       count_obj(invent, &count, &size, FALSE, TRUE);
+       count_obj(fobj, &count, &size, FALSE, TRUE);
+       count_obj(level.buriedobjlist, &count, &size, FALSE, TRUE);
+       count_obj(migrating_objs, &count, &size, FALSE, TRUE);
+       /* DEADMONSTER check not required in this loop since they have no inventory */
+       for (mon = fmon; mon; mon = mon->nmon)
+           count_obj(mon->minvent, &count, &size, FALSE, TRUE);
+       for (mon = migrating_mons; mon; mon = mon->nmon)
+           count_obj(mon->minvent, &count, &size, FALSE, TRUE);
+
+       *total_count += count; *total_size += size;
+
+       Sprintf(buf, template, src, count, size);
+       putstr(win, 0, buf);
+}
+
+STATIC_OVL void
+mon_chain(win, src, chain, total_count, total_size)
+       winid win;
+       const char *src;
+       struct monst *chain;
+       long *total_count;
+       long *total_size;
+{
+       char buf[BUFSZ];
+       long count, size;
+       struct monst *mon;
+
+       for (count = size = 0, mon = chain; mon; mon = mon->nmon) {
+           count++;
+           size += sizeof(struct monst) + mon->mxlth + mon->mnamelth;
+       }
+       *total_count += count;
+       *total_size += size;
+       Sprintf(buf, template, src, count, size);
+       putstr(win, 0, buf);
+}
+
+/*
+ * Display memory usage of all monsters and objects on the level.
+ */
+static int
+wiz_show_stats()
+{
+       char buf[BUFSZ];
+       winid win;
+       long total_obj_size = 0, total_obj_count = 0;
+       long total_mon_size = 0, total_mon_count = 0;
+
+       win = create_nhwindow(NHW_TEXT);
+       putstr(win, 0, "Current memory statistics:");
+       putstr(win, 0, "");
+       Sprintf(buf, "Objects, size %d", (int) sizeof(struct obj));
+       putstr(win, 0, buf);
+       putstr(win, 0, "");
+       putstr(win, 0, count_str);
+
+       obj_chain(win, "invent", invent, &total_obj_count, &total_obj_size);
+       obj_chain(win, "fobj", fobj, &total_obj_count, &total_obj_size);
+       obj_chain(win, "buried", level.buriedobjlist,
+                               &total_obj_count, &total_obj_size);
+       obj_chain(win, "migrating obj", migrating_objs,
+                               &total_obj_count, &total_obj_size);
+       mon_invent_chain(win, "minvent", fmon,
+                               &total_obj_count,&total_obj_size);
+       mon_invent_chain(win, "migrating minvent", migrating_mons,
+                               &total_obj_count, &total_obj_size);
+
+       contained(win, "contained",
+                               &total_obj_count, &total_obj_size);
+
+       putstr(win, 0, separator);
+       Sprintf(buf, template, "Total", total_obj_count, total_obj_size);
+       putstr(win, 0, buf);
+
+       putstr(win, 0, "");
+       putstr(win, 0, "");
+       Sprintf(buf, "Monsters, size %d", (int) sizeof(struct monst));
+       putstr(win, 0, buf);
+       putstr(win, 0, "");
+
+       mon_chain(win, "fmon", fmon,
+                               &total_mon_count, &total_mon_size);
+       mon_chain(win, "migrating", migrating_mons,
+                               &total_mon_count, &total_mon_size);
+
+       putstr(win, 0, separator);
+       Sprintf(buf, template, "Total", total_mon_count, total_mon_size);
+       putstr(win, 0, buf);
+
+#if defined(__BORLANDC__) && !defined(_WIN32)
+       show_borlandc_stats(win);
+#endif
+
+       display_nhwindow(win, FALSE);
+       destroy_nhwindow(win);
+       return 0;
+}
+
+void
+sanity_check()
+{
+       obj_sanity_check();
+       timer_sanity_check();
+}
+
+#ifdef DEBUG_MIGRATING_MONS
+static int
+wiz_migrate_mons()
+{
+       int mcount = 0;
+       char inbuf[BUFSZ];
+       struct permonst *ptr;
+       struct monst *mtmp;
+       d_level tolevel;
+       getlin("How many random monsters to migrate? [0]", inbuf);
+       if (*inbuf == '\033') return 0;
+       mcount = atoi(inbuf);
+       if (mcount < 0 || mcount > (COLNO * ROWNO) || Is_botlevel(&u.uz))
+               return 0;
+       while (mcount > 0) {
+               if (Is_stronghold(&u.uz))
+                   assign_level(&tolevel, &valley_level);
+               else
+                   get_level(&tolevel, depth(&u.uz) + 1);
+               ptr = rndmonst();
+               mtmp = makemon(ptr, 0, 0, NO_MM_FLAGS);
+               if (mtmp) migrate_to_level(mtmp, ledger_no(&tolevel),
+                               MIGR_RANDOM, (coord *)0);
+               mcount--;
+       }
+       return 0;
+}
+#endif
+
+#endif /* WIZARD */
+
+#define unctrl(c)      ((c) <= C('z') ? (0x60 | (c)) : (c))
+#define unmeta(c)      (0x7f & (c))
+
+
+void
+rhack(cmd)
+register char *cmd;
+{
+       boolean do_walk, do_rush, prefix_seen, bad_command,
+               firsttime = (cmd == 0);
+
+       iflags.menu_requested = FALSE;
+       if (firsttime) {
+               flags.nopick = 0;
+               cmd = parse();
+       }
+       if (*cmd == '\033') {
+               flags.move = FALSE;
+               return;
+       }
+#ifdef REDO
+       if (*cmd == DOAGAIN && !in_doagain && saveq[0]) {
+               in_doagain = TRUE;
+               stail = 0;
+               rhack((char *)0);       /* read and execute command */
+               in_doagain = FALSE;
+               return;
+       }
+       /* Special case of *cmd == ' ' handled better below */
+       if(!*cmd || *cmd == (char)0377)
+#else
+       if(!*cmd || *cmd == (char)0377 || (!flags.rest_on_space && *cmd == ' '))
+#endif
+       {
+               nhbell();
+               flags.move = FALSE;
+               return;         /* probably we just had an interrupt */
+       }
+       if (iflags.num_pad && iflags.num_pad_mode == 1) {
+               /* This handles very old inconsistent DOS/Windows behaviour
+                * in a new way: earlier, the keyboard handler mapped these,
+                * which caused counts to be strange when entered from the
+                * number pad. Now do not map them until here. 
+                */
+               switch (*cmd) {
+                   case '5':       *cmd = 'g'; break;
+                   case M('5'):    *cmd = 'G'; break;
+                   case M('0'):    *cmd = 'I'; break;
+               }
+        }
+       /* handle most movement commands */
+       do_walk = do_rush = prefix_seen = FALSE;
+       flags.travel = iflags.travel1 = 0;
+       switch (*cmd) {
+        case 'g':  if (movecmd(cmd[1])) {
+                       flags.run = 2;
+                       do_rush = TRUE;
+                   } else
+                       prefix_seen = TRUE;
+                   break;
+        case '5':  if (!iflags.num_pad) break; /* else FALLTHRU */
+        case 'G':  if (movecmd(lowc(cmd[1]))) {
+                       flags.run = 3;
+                       do_rush = TRUE;
+                   } else
+                       prefix_seen = TRUE;
+                   break;
+        case '-':  if (!iflags.num_pad) break; /* else FALLTHRU */
+       /* Effects of movement commands and invisible monsters:
+        * m: always move onto space (even if 'I' remembered)
+        * F: always attack space (even if 'I' not remembered)
+        * normal movement: attack if 'I', move otherwise
+        */
+        case 'F':  if (movecmd(cmd[1])) {
+                       flags.forcefight = 1;
+                       do_walk = TRUE;
+                   } else
+                       prefix_seen = TRUE;
+                   break;
+        case 'm':  if (movecmd(cmd[1]) || u.dz) {
+                       flags.run = 0;
+                       flags.nopick = 1;
+                       if (!u.dz) do_walk = TRUE;
+                       else cmd[0] = cmd[1];   /* "m<" or "m>" */
+                   } else
+                       prefix_seen = TRUE;
+                   break;
+        case 'M':  if (movecmd(lowc(cmd[1]))) {
+                       flags.run = 1;
+                       flags.nopick = 1;
+                       do_rush = TRUE;
+                   } else
+                       prefix_seen = TRUE;
+                   break;
+        case '0':  if (!iflags.num_pad) break;
+                   (void)ddoinv(); /* a convenience borrowed from the PC */
+                   flags.move = FALSE;
+                   multi = 0;
+                   return;
+        case CMD_TRAVEL:
+                   if (iflags.travelcmd) {
+                           flags.travel = 1;
+                           iflags.travel1 = 1;
+                           flags.run = 8;
+                           flags.nopick = 1;
+                           do_rush = TRUE;
+                           break;
+                   }
+                   /*FALLTHRU*/
+        default:   if (movecmd(*cmd)) {        /* ordinary movement */
+                       flags.run = 0;  /* only matters here if it was 8 */
+                       do_walk = TRUE;
+                   } else if (movecmd(iflags.num_pad ?
+                                      unmeta(*cmd) : lowc(*cmd))) {
+                       flags.run = 1;
+                       do_rush = TRUE;
+                   } else if (movecmd(unctrl(*cmd))) {
+                       flags.run = 3;
+                       do_rush = TRUE;
+                   }
+                   break;
+       }
+
+       /* some special prefix handling */
+       /* overload 'm' prefix for ',' to mean "request a menu" */
+       if (prefix_seen && cmd[1] == ',') {
+               iflags.menu_requested = TRUE;
+               ++cmd;
+       }
+
+       if (do_walk) {
+           if (multi) flags.mv = TRUE;
+           domove();
+           flags.forcefight = 0;
+           return;
+       } else if (do_rush) {
+           if (firsttime) {
+               if (!multi) multi = max(COLNO,ROWNO);
+               u.last_str_turn = 0;
+           }
+           flags.mv = TRUE;
+           domove();
+           return;
+       } else if (prefix_seen && cmd[1] == '\033') {   /* <prefix><escape> */
+           /* don't report "unknown command" for change of heart... */
+           bad_command = FALSE;
+       } else if (*cmd == ' ' && !flags.rest_on_space) {
+           bad_command = TRUE;         /* skip cmdlist[] loop */
+
+       /* handle all other commands */
+       } else {
+           register const struct func_tab *tlist;
+           int res, NDECL((*func));
+
+           for (tlist = cmdlist; tlist->f_char; tlist++) {
+               if ((*cmd & 0xff) != (tlist->f_char & 0xff)) continue;
+
+               if (u.uburied && !tlist->can_if_buried) {
+                   You_cant("do that while you are buried!");
+                   res = 0;
+               } else {
+                   /* we discard 'const' because some compilers seem to have
+                      trouble with the pointer passed to set_occupation() */
+                   func = ((struct func_tab *)tlist)->f_funct;
+                   if (tlist->f_text && !occupation && multi)
+                       set_occupation(func, tlist->f_text, multi);
+                   res = (*func)();            /* perform the command */
+               }
+               if (!res) {
+                   flags.move = FALSE;
+                   multi = 0;
+               }
+               return;
+           }
+           /* if we reach here, cmd wasn't found in cmdlist[] */
+           bad_command = TRUE;
+       }
+
+       if (bad_command) {
+           char expcmd[10];
+           register char *cp = expcmd;
+
+           while (*cmd && (int)(cp - expcmd) < (int)(sizeof expcmd - 3)) {
+               if (*cmd >= 040 && *cmd < 0177) {
+                   *cp++ = *cmd++;
+               } else if (*cmd & 0200) {
+                   *cp++ = 'M';
+                   *cp++ = '-';
+                   *cp++ = *cmd++ &= ~0200;
+               } else {
+                   *cp++ = '^';
+                   *cp++ = *cmd++ ^ 0100;
+               }
+           }
+           *cp = '\0';
+           if (!prefix_seen || !iflags.cmdassist ||
+               !help_dir(0, "Invalid direction key!"))
+               Norep("Unknown command '%s'.", expcmd);
+       }
+       /* didn't move */
+       flags.move = FALSE;
+       multi = 0;
+       return;
+}
+
+int
+xytod(x, y)    /* convert an x,y pair into a direction code */
+schar x, y;
+{
+       register int dd;
+
+       for(dd = 0; dd < 8; dd++)
+           if(x == xdir[dd] && y == ydir[dd]) return dd;
+
+       return -1;
+}
+
+void
+dtoxy(cc,dd)   /* convert a direction code into an x,y pair */
+coord *cc;
+register int dd;
+{
+       cc->x = xdir[dd];
+       cc->y = ydir[dd];
+       return;
+}
+
+int
+movecmd(sym)   /* also sets u.dz, but returns false for <> */
+char sym;
+{
+       register const char *dp;
+       register const char *sdp;
+       if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */
+
+       u.dz = 0;
+       if(!(dp = index(sdp, sym))) return 0;
+       u.dx = xdir[dp-sdp];
+       u.dy = ydir[dp-sdp];
+       u.dz = zdir[dp-sdp];
+       if (u.dx && u.dy && u.umonnum == PM_GRID_BUG) {
+               u.dx = u.dy = 0;
+               return 0;
+       }
+       return !u.dz;
+}
+
+/*
+ * uses getdir() but unlike getdir() it specifically
+ * produces coordinates using the direction from getdir()
+ * and verifies that those coordinates are ok.
+ *
+ * If the call to getdir() returns 0, Never_mind is displayed.
+ * If the resulting coordinates are not okay, emsg is displayed.
+ *
+ * Returns non-zero if coordinates in cc are valid.
+ */
+int get_adjacent_loc(prompt,emsg,x,y,cc)
+const char *prompt, *emsg;
+xchar x,y;
+coord *cc;
+{
+       xchar new_x, new_y;
+       if (!getdir(prompt)) {
+               pline(Never_mind);
+               return 0;
+       }
+       new_x = x + u.dx;
+       new_y = y + u.dy;
+       if (cc && isok(new_x,new_y)) {
+               cc->x = new_x;
+               cc->y = new_y;
+       } else {
+               if (emsg) pline(emsg);
+               return 0;
+       }
+       return 1;
+}
+
+int
+getdir(s)
+const char *s;
+{
+       char dirsym;
+
+#ifdef REDO
+       if(in_doagain || *readchar_queue)
+           dirsym = readchar();
+       else
+#endif
+           dirsym = yn_function ((s && *s != '^') ? s : "In what direction?",
+                                       (char *)0, '\0');
+#ifdef REDO
+       savech(dirsym);
+#endif
+       if(dirsym == '.' || dirsym == 's')
+               u.dx = u.dy = u.dz = 0;
+       else if(!movecmd(dirsym) && !u.dz) {
+               boolean did_help = FALSE;
+               if(!index(quitchars, dirsym)) {
+                   if (iflags.cmdassist) {
+                       did_help = help_dir((s && *s == '^') ? dirsym : 0,
+                                           "Invalid direction key!");
+                   }
+                   if (!did_help) pline("What a strange direction!");
+               }
+               return 0;
+       }
+       if(!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir();
+       return 1;
+}
+
+STATIC_OVL boolean
+help_dir(sym, msg)
+char sym;
+const char *msg;
+{
+       char ctrl;
+       winid win;
+       static const char wiz_only_list[] = "EFGIOVW";
+       char buf[BUFSZ], buf2[BUFSZ], *expl;
+
+       win = create_nhwindow(NHW_TEXT);
+       if (!win) return FALSE;
+       if (msg) {
+               Sprintf(buf, "cmdassist: %s", msg);
+               putstr(win, 0, buf);
+               putstr(win, 0, "");
+       }
+       if (letter(sym)) { 
+           sym = highc(sym);
+           ctrl = (sym - 'A') + 1;
+           if ((expl = dowhatdoes_core(ctrl, buf2))
+               && (!index(wiz_only_list, sym)
+#ifdef WIZARD
+                   || wizard
+#endif
+                            )) {
+               Sprintf(buf, "Are you trying to use ^%c%s?", sym,
+                       index(wiz_only_list, sym) ? "" :
+                       " as specified in the Guidebook");
+               putstr(win, 0, buf);
+               putstr(win, 0, "");
+               putstr(win, 0, expl);
+               putstr(win, 0, "");
+               putstr(win, 0, "To use that command, you press");
+               Sprintf(buf,
+                       "the <Ctrl> key, and the <%c> key at the same time.", sym);
+               putstr(win, 0, buf);
+               putstr(win, 0, "");
+           }
+       }
+       if (iflags.num_pad && u.umonnum == PM_GRID_BUG) {
+           putstr(win, 0, "Valid direction keys in your current form (with number_pad on) are:");
+           putstr(win, 0, "             8   ");
+           putstr(win, 0, "             |   ");
+           putstr(win, 0, "          4- . -6");
+           putstr(win, 0, "             |   ");
+           putstr(win, 0, "             2   ");
+       } else if (u.umonnum == PM_GRID_BUG) {
+           putstr(win, 0, "Valid direction keys in your current form are:");
+           putstr(win, 0, "             k   ");
+           putstr(win, 0, "             |   ");
+           putstr(win, 0, "          h- . -l");
+           putstr(win, 0, "             |   ");
+           putstr(win, 0, "             j   ");
+       } else if (iflags.num_pad) {
+           putstr(win, 0, "Valid direction keys (with number_pad on) are:");
+           putstr(win, 0, "          7  8  9");
+           putstr(win, 0, "           \\ | / ");
+           putstr(win, 0, "          4- . -6");
+           putstr(win, 0, "           / | \\ ");
+           putstr(win, 0, "          1  2  3");
+       } else {
+           putstr(win, 0, "Valid direction keys are:");
+           putstr(win, 0, "          y  k  u");
+           putstr(win, 0, "           \\ | / ");
+           putstr(win, 0, "          h- . -l");
+           putstr(win, 0, "           / | \\ ");
+           putstr(win, 0, "          b  j  n");
+       };
+       putstr(win, 0, "");
+       putstr(win, 0, "          <  up");
+       putstr(win, 0, "          >  down");
+       putstr(win, 0, "          .  direct at yourself");
+       putstr(win, 0, "");
+       putstr(win, 0, "(Suppress this message with !cmdassist in config file.)");
+       display_nhwindow(win, FALSE);
+       destroy_nhwindow(win);
+       return TRUE;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+void
+confdir()
+{
+       register int x = (u.umonnum == PM_GRID_BUG) ? 2*rn2(4) : rn2(8);
+       u.dx = xdir[x];
+       u.dy = ydir[x];
+       return;
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+int
+isok(x,y)
+register int x, y;
+{
+       /* x corresponds to curx, so x==1 is the first column. Ach. %% */
+       return x >= 1 && x <= COLNO-1 && y >= 0 && y <= ROWNO-1;
+}
+
+static NEARDATA int last_multi;
+
+/*
+ * convert a MAP window position into a movecmd
+ */
+const char *
+click_to_cmd(x, y, mod)
+    int x, y, mod;
+{
+    int dir;
+    static char cmd[4];
+    cmd[1]=0;
+
+    x -= u.ux;
+    y -= u.uy;
+
+    if (iflags.travelcmd) {
+        if (abs(x) <= 1 && abs(y) <= 1 ) {
+            x = sgn(x), y = sgn(y);
+        } else {
+            u.tx = u.ux+x;
+            u.ty = u.uy+y;
+            cmd[0] = CMD_TRAVEL;
+            return cmd;
+        }
+
+        if(x == 0 && y == 0) {
+            /* here */
+            if(IS_FOUNTAIN(levl[u.ux][u.uy].typ) || IS_SINK(levl[u.ux][u.uy].typ)) {
+                cmd[0]=mod == CLICK_1 ? 'q' : M('d');
+                return cmd;
+            } else if(IS_THRONE(levl[u.ux][u.uy].typ)) {
+                cmd[0]=M('s');
+                return cmd;
+            } else if((u.ux == xupstair && u.uy == yupstair)
+                      || (u.ux == sstairs.sx && u.uy == sstairs.sy && sstairs.up)
+                      || (u.ux == xupladder && u.uy == yupladder)) {
+                return "<";
+            } else if((u.ux == xdnstair && u.uy == ydnstair)
+                      || (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)
+                      || (u.ux == xdnladder && u.uy == ydnladder)) {
+                return ">";
+            } else if(OBJ_AT(u.ux, u.uy)) {
+                cmd[0] = Is_container(level.objects[u.ux][u.uy]) ? M('l') : ',';
+                return cmd;
+            } else {
+                return "."; /* just rest */
+            }
+        }
+
+        /* directional commands */
+
+        dir = xytod(x, y);
+
+       if (!m_at(u.ux+x, u.uy+y) && !test_move(u.ux, u.uy, x, y, TEST_MOVE)) {
+            cmd[1] = (iflags.num_pad ? ndir[dir] : sdir[dir]);
+            cmd[2] = 0;
+            if (IS_DOOR(levl[u.ux+x][u.uy+y].typ)) {
+                /* slight assistance to the player: choose kick/open for them */
+                if (levl[u.ux+x][u.uy+y].doormask & D_LOCKED) {
+                    cmd[0] = C('d');
+                    return cmd;
+                }
+                if (levl[u.ux+x][u.uy+y].doormask & D_CLOSED) {
+                    cmd[0] = 'o';
+                    return cmd;
+                }
+            }
+            if (levl[u.ux+x][u.uy+y].typ <= SCORR) {
+                cmd[0] = 's';
+                cmd[1] = 0;
+                return cmd;
+            }
+        }
+    } else {
+        /* convert without using floating point, allowing sloppy clicking */
+        if(x > 2*abs(y))
+            x = 1, y = 0;
+        else if(y > 2*abs(x))
+            x = 0, y = 1;
+        else if(x < -2*abs(y))
+            x = -1, y = 0;
+        else if(y < -2*abs(x))
+            x = 0, y = -1;
+        else
+            x = sgn(x), y = sgn(y);
+
+        if(x == 0 && y == 0)   /* map click on player to "rest" command */
+            return ".";
+
+        dir = xytod(x, y);
+    }
+
+    /* move, attack, etc. */
+    cmd[1] = 0;
+    if(mod == CLICK_1) {
+       cmd[0] = (iflags.num_pad ? ndir[dir] : sdir[dir]);
+    } else {
+       cmd[0] = (iflags.num_pad ? M(ndir[dir]) :
+               (sdir[dir] - 'a' + 'A')); /* run command */
+    }
+
+    return cmd;
+}
+
+STATIC_OVL char *
+parse()
+{
+#ifdef LINT    /* static char in_line[COLNO]; */
+       char in_line[COLNO];
+#else
+       static char in_line[COLNO];
+#endif
+       register int foo;
+       boolean prezero = FALSE;
+
+       multi = 0;
+       flags.move = 1;
+       flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */
+
+       if (!iflags.num_pad || (foo = readchar()) == 'n')
+           for (;;) {
+               foo = readchar();
+               if (foo >= '0' && foo <= '9') {
+                   multi = 10 * multi + foo - '0';
+                   if (multi < 0 || multi >= LARGEST_INT) multi = LARGEST_INT;
+                   if (multi > 9) {
+                       clear_nhwindow(WIN_MESSAGE);
+                       Sprintf(in_line, "Count: %d", multi);
+                       pline(in_line);
+                       mark_synch();
+                   }
+                   last_multi = multi;
+                   if (!multi && foo == '0') prezero = TRUE;
+               } else break;   /* not a digit */
+           }
+
+       if (foo == '\033') {   /* esc cancels count (TH) */
+           clear_nhwindow(WIN_MESSAGE);
+           multi = last_multi = 0;
+# ifdef REDO
+       } else if (foo == DOAGAIN || in_doagain) {
+           multi = last_multi;
+       } else {
+           last_multi = multi;
+           savech(0);  /* reset input queue */
+           savech((char)foo);
+# endif
+       }
+
+       if (multi) {
+           multi--;
+           save_cm = in_line;
+       } else {
+           save_cm = (char *)0;
+       }
+       in_line[0] = foo;
+       in_line[1] = '\0';
+       if (foo == 'g' || foo == 'G' || foo == 'm' || foo == 'M' ||
+           foo == 'F' || (iflags.num_pad && (foo == '5' || foo == '-'))) {
+           foo = readchar();
+#ifdef REDO
+           savech((char)foo);
+#endif
+           in_line[1] = foo;
+           in_line[2] = 0;
+       }
+       clear_nhwindow(WIN_MESSAGE);
+       if (prezero) in_line[0] = '\033';
+       return(in_line);
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+#ifdef UNIX
+static
+void
+end_of_input()
+{
+#ifndef NOSAVEONHANGUP
+       if (!program_state.done_hup++ && program_state.something_worth_saving)
+           (void) dosave0();
+#endif
+       exit_nhwindows((char *)0);
+       clearlocks();
+       terminate(EXIT_SUCCESS);
+}
+#endif
+
+#endif /* OVLB */
+#ifdef OVL0
+
+char
+readchar()
+{
+       register int sym;
+       int x = u.ux, y = u.uy, mod = 0;
+
+       if ( *readchar_queue )
+           sym = *readchar_queue++;
+       else
+#ifdef REDO
+           sym = in_doagain ? Getchar() : nh_poskey(&x, &y, &mod);
+#else
+           sym = Getchar();
+#endif
+
+#ifdef UNIX
+# ifdef NR_OF_EOFS
+       if (sym == EOF) {
+           register int cnt = NR_OF_EOFS;
+         /*
+          * Some SYSV systems seem to return EOFs for various reasons
+          * (?like when one hits break or for interrupted systemcalls?),
+          * and we must see several before we quit.
+          */
+           do {
+               clearerr(stdin);        /* omit if clearerr is undefined */
+               sym = Getchar();
+           } while (--cnt && sym == EOF);
+       }
+# endif /* NR_OF_EOFS */
+       if (sym == EOF)
+           end_of_input();
+#endif /* UNIX */
+
+       if(sym == 0) {
+           /* click event */
+           readchar_queue = click_to_cmd(x, y, mod);
+           sym = *readchar_queue++;
+       }
+       return((char) sym);
+}
+
+STATIC_PTR int
+dotravel()
+{
+       /* Keyboard travel command */
+       static char cmd[2];
+       coord cc;
+
+       if (!iflags.travelcmd) return 0;
+       cmd[1]=0;
+       cc.x = iflags.travelcc.x;
+       cc.y = iflags.travelcc.y;
+       if (cc.x == -1 && cc.y == -1) {
+           /* No cached destination, start attempt from current position */
+           cc.x = u.ux;
+           cc.y = u.uy;
+       }
+       pline("Where do you want to travel to?");
+       if (getpos(&cc, TRUE, "the desired destination") < 0) {
+               /* user pressed ESC */
+               return 0;
+       }
+       iflags.travelcc.x = u.tx = cc.x;
+       iflags.travelcc.y = u.ty = cc.y;
+       cmd[0] = CMD_TRAVEL;
+       readchar_queue = cmd;
+       return 0;
+}
+
+#ifdef PORT_DEBUG
+# ifdef WIN32CON
+extern void NDECL(win32con_debug_keystrokes);
+extern void NDECL(win32con_handler_info);
+# endif
+
+int
+wiz_port_debug()
+{
+       int n, k;
+       winid win;
+       anything any;
+       int item = 'a';
+       int num_menu_selections;
+       struct menu_selection_struct {
+               char *menutext;
+               void NDECL((*fn));
+       } menu_selections[] = {
+#ifdef WIN32CON
+               {"test win32 keystrokes", win32con_debug_keystrokes},
+               {"show keystroke handler information", win32con_handler_info},
+#endif
+               {(char *)0, (void NDECL((*)))0}         /* array terminator */
+       };
+
+       num_menu_selections = SIZE(menu_selections) - 1;
+       if (num_menu_selections > 0) {
+               menu_item *pick_list;
+               win = create_nhwindow(NHW_MENU);
+               start_menu(win);
+               for (k=0; k < num_menu_selections; ++k) {
+                       any.a_int = k+1;
+                       add_menu(win, NO_GLYPH, &any, item++, 0, ATR_NONE,
+                               menu_selections[k].menutext, MENU_UNSELECTED);
+               }
+               end_menu(win, "Which port debugging feature?");
+               n = select_menu(win, PICK_ONE, &pick_list);
+               destroy_nhwindow(win);
+               if (n > 0) {
+                       n = pick_list[0].item.a_int - 1;
+                       free((genericptr_t) pick_list);
+                       /* execute the function */
+                       (*menu_selections[n].fn)();
+               }
+       } else
+               pline("No port-specific debug capability defined.");
+       return 0;
+}
+# endif /*PORT_DEBUG*/
+
+#endif /* OVL0 */
+#ifdef OVLB
+/*
+ *   Parameter validator for generic yes/no function to prevent
+ *   the core from sending too long a prompt string to the
+ *   window port causing a buffer overflow there.
+ */
+char
+yn_function(query,resp, def)
+const char *query,*resp;
+char def;
+{
+       char qbuf[QBUFSZ];
+       unsigned truncspot, reduction = sizeof(" [N]  ?") + 1;
+
+       if (resp) reduction += strlen(resp) + sizeof(" () ");
+       if (strlen(query) < (QBUFSZ - reduction))
+               return (*windowprocs.win_yn_function)(query, resp, def);
+       paniclog("Query truncated: ", query);
+       reduction += sizeof("...");
+       truncspot = QBUFSZ - reduction;
+       (void) strncpy(qbuf, query, (int)truncspot);
+       qbuf[truncspot] = '\0';
+       Strcat(qbuf,"...");
+       return (*windowprocs.win_yn_function)(qbuf, resp, def);
+}
+#endif
+
+/*cmd.c*/
diff --git a/src/dbridge.c b/src/dbridge.c
new file mode 100644 (file)
index 0000000..df04bc8
--- /dev/null
@@ -0,0 +1,942 @@
+/*     SCCS Id: @(#)dbridge.c  3.4     2003/02/08      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet              */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file contains the drawbridge manipulation (create, open, close,
+ * destroy).
+ *
+ * Added comprehensive monster-handling, and the "entity" structure to
+ * deal with players as well. - 11/89
+ */
+
+#include "hack.h"
+
+#ifdef OVLB
+STATIC_DCL void FDECL(get_wall_for_db, (int *, int *));
+STATIC_DCL struct entity *FDECL(e_at, (int, int));
+STATIC_DCL void FDECL(m_to_e, (struct monst *, int, int, struct entity *));
+STATIC_DCL void FDECL(u_to_e, (struct entity *));
+STATIC_DCL void FDECL(set_entity, (int, int, struct entity *));
+STATIC_DCL const char *FDECL(e_nam, (struct entity *));
+#ifdef D_DEBUG
+static const char *FDECL(Enam, (struct entity *)); /* unused */
+#endif
+STATIC_DCL const char *FDECL(E_phrase, (struct entity *, const char *));
+STATIC_DCL boolean FDECL(e_survives_at, (struct entity *, int, int));
+STATIC_DCL void FDECL(e_died, (struct entity *, int, int));
+STATIC_DCL boolean FDECL(automiss, (struct entity *));
+STATIC_DCL boolean FDECL(e_missed, (struct entity *, BOOLEAN_P));
+STATIC_DCL boolean FDECL(e_jumps, (struct entity *));
+STATIC_DCL void FDECL(do_entity, (struct entity *));
+#endif /* OVLB */
+
+#ifdef OVL0
+
+boolean
+is_pool(x,y)
+int x,y;
+{
+    schar ltyp;
+
+    if (!isok(x,y)) return FALSE;
+    ltyp = levl[x][y].typ;
+    if (ltyp == POOL || ltyp == MOAT || ltyp == WATER) return TRUE;
+    if (ltyp == DRAWBRIDGE_UP &&
+       (levl[x][y].drawbridgemask & DB_UNDER) == DB_MOAT) return TRUE;
+    return FALSE;
+}
+
+boolean
+is_lava(x,y)
+int x,y;
+{
+    schar ltyp;
+
+    if (!isok(x,y)) return FALSE;
+    ltyp = levl[x][y].typ;
+    if (ltyp == LAVAPOOL
+       || (ltyp == DRAWBRIDGE_UP
+           && (levl[x][y].drawbridgemask & DB_UNDER) == DB_LAVA)) return TRUE;
+    return FALSE;
+}
+
+boolean
+is_ice(x,y)
+int x,y;
+{
+    schar ltyp;
+
+    if (!isok(x,y)) return FALSE;
+    ltyp = levl[x][y].typ;
+    if (ltyp == ICE
+       || (ltyp == DRAWBRIDGE_UP
+           && (levl[x][y].drawbridgemask & DB_UNDER) == DB_ICE)) return TRUE;
+    return FALSE;
+}
+
+#endif /* OVL0 */
+
+#ifdef OVL1
+
+/*
+ * We want to know whether a wall (or a door) is the portcullis (passageway)
+ * of an eventual drawbridge.
+ *
+ * Return value:  the direction of the drawbridge.
+ */
+
+int
+is_drawbridge_wall(x,y)
+int x,y;
+{
+       struct rm *lev;
+
+       lev = &levl[x][y];
+       if (lev->typ != DOOR && lev->typ != DBWALL)
+               return (-1);
+
+       if (IS_DRAWBRIDGE(levl[x+1][y].typ) &&
+           (levl[x+1][y].drawbridgemask & DB_DIR) == DB_WEST)
+               return (DB_WEST);
+       if (IS_DRAWBRIDGE(levl[x-1][y].typ) &&
+           (levl[x-1][y].drawbridgemask & DB_DIR) == DB_EAST)
+               return (DB_EAST);
+       if (IS_DRAWBRIDGE(levl[x][y-1].typ) &&
+           (levl[x][y-1].drawbridgemask & DB_DIR) == DB_SOUTH)
+               return (DB_SOUTH);
+       if (IS_DRAWBRIDGE(levl[x][y+1].typ) &&
+           (levl[x][y+1].drawbridgemask & DB_DIR) == DB_NORTH)
+               return (DB_NORTH);
+
+       return (-1);
+}
+
+/*
+ * Use is_db_wall where you want to verify that a
+ * drawbridge "wall" is UP in the location x, y
+ * (instead of UP or DOWN, as with is_drawbridge_wall).
+ */
+boolean
+is_db_wall(x,y)
+int x,y;
+{
+       return((boolean)( levl[x][y].typ == DBWALL ));
+}
+
+
+/*
+ * Return true with x,y pointing to the drawbridge if x,y initially indicate
+ * a drawbridge or drawbridge wall.
+ */
+boolean
+find_drawbridge(x,y)
+int *x,*y;
+{
+       int dir;
+
+       if (IS_DRAWBRIDGE(levl[*x][*y].typ))
+               return TRUE;
+       dir = is_drawbridge_wall(*x,*y);
+       if (dir >= 0) {
+               switch(dir) {
+                       case DB_NORTH: (*y)++; break;
+                       case DB_SOUTH: (*y)--; break;
+                       case DB_EAST:  (*x)--; break;
+                       case DB_WEST:  (*x)++; break;
+               }
+               return TRUE;
+       }
+       return FALSE;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+/*
+ * Find the drawbridge wall associated with a drawbridge.
+ */
+STATIC_OVL void
+get_wall_for_db(x,y)
+int *x,*y;
+{
+       switch (levl[*x][*y].drawbridgemask & DB_DIR) {
+               case DB_NORTH: (*y)--; break;
+               case DB_SOUTH: (*y)++; break;
+               case DB_EAST:  (*x)++; break;
+               case DB_WEST:  (*x)--; break;
+       }
+}
+
+/*
+ * Creation of a drawbridge at pos x,y.
+ *     dir is the direction.
+ *     flag must be put to TRUE if we want the drawbridge to be opened.
+ */
+
+boolean
+create_drawbridge(x,y,dir,flag)
+int x,y,dir;
+boolean flag;
+{
+       int x2,y2;
+       boolean horiz;
+       boolean lava = levl[x][y].typ == LAVAPOOL; /* assume initialized map */
+
+       x2 = x; y2 = y;
+       switch(dir) {
+               case DB_NORTH:
+                       horiz = TRUE;
+                       y2--;
+                       break;
+               case DB_SOUTH:
+                       horiz = TRUE;
+                       y2++;
+                       break;
+               case DB_EAST:
+                       horiz = FALSE;
+                       x2++;
+                       break;
+               default:
+                       impossible("bad direction in create_drawbridge");
+                       /* fall through */
+               case DB_WEST:
+                       horiz = FALSE;
+                       x2--;
+                       break;
+       }
+       if (!IS_WALL(levl[x2][y2].typ))
+               return(FALSE);
+       if (flag) {             /* We want the bridge open */
+               levl[x][y].typ = DRAWBRIDGE_DOWN;
+               levl[x2][y2].typ = DOOR;
+               levl[x2][y2].doormask = D_NODOOR;
+       } else {
+               levl[x][y].typ = DRAWBRIDGE_UP;
+               levl[x2][y2].typ = DBWALL;
+               /* Drawbridges are non-diggable. */
+               levl[x2][y2].wall_info = W_NONDIGGABLE;
+       }
+       levl[x][y].horizontal = !horiz;
+       levl[x2][y2].horizontal = horiz;
+       levl[x][y].drawbridgemask = dir;
+       if(lava) levl[x][y].drawbridgemask |= DB_LAVA;
+       return(TRUE);
+}
+
+struct entity {
+       struct monst *emon;       /* youmonst for the player */
+       struct permonst *edata;   /* must be non-zero for record to be valid */
+       int ex, ey;
+};
+
+#define ENTITIES 2
+
+static NEARDATA struct entity occupants[ENTITIES];
+
+STATIC_OVL
+struct entity *
+e_at(x, y)
+int x, y;
+{
+       int entitycnt;
+
+       for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++)
+               if ((occupants[entitycnt].edata) &&
+                   (occupants[entitycnt].ex == x) &&
+                   (occupants[entitycnt].ey == y))
+                       break;
+#ifdef D_DEBUG
+       pline("entitycnt = %d", entitycnt);
+       wait_synch();
+#endif
+       return((entitycnt == ENTITIES)?
+              (struct entity *)0 : &(occupants[entitycnt]));
+}
+
+STATIC_OVL void
+m_to_e(mtmp, x, y, etmp)
+struct monst *mtmp;
+int x, y;
+struct entity *etmp;
+{
+       etmp->emon = mtmp;
+       if (mtmp) {
+               etmp->ex = x;
+               etmp->ey = y;
+               if (mtmp->wormno && (x != mtmp->mx || y != mtmp->my))
+                       etmp->edata = &mons[PM_LONG_WORM_TAIL];
+               else
+                       etmp->edata = mtmp->data;
+       } else
+               etmp->edata = (struct permonst *)0;
+}
+
+STATIC_OVL void
+u_to_e(etmp)
+struct entity *etmp;
+{
+       etmp->emon = &youmonst;
+       etmp->ex = u.ux;
+       etmp->ey = u.uy;
+       etmp->edata = youmonst.data;
+}
+
+STATIC_OVL void
+set_entity(x, y, etmp)
+int x, y;
+struct entity *etmp;
+{
+       if ((x == u.ux) && (y == u.uy))
+               u_to_e(etmp);
+       else if (MON_AT(x, y))
+               m_to_e(m_at(x, y), x, y, etmp);
+       else
+               etmp->edata = (struct permonst *)0;
+}
+
+#define is_u(etmp) (etmp->emon == &youmonst)
+#define e_canseemon(etmp) (is_u(etmp) ? (boolean)TRUE : canseemon(etmp->emon))
+
+/*
+ * e_strg is a utility routine which is not actually in use anywhere, since
+ * the specialized routines below suffice for all current purposes.
+ */
+
+/* #define e_strg(etmp, func) (is_u(etmp)? (char *)0 : func(etmp->emon)) */
+
+STATIC_OVL const char *
+e_nam(etmp)
+struct entity *etmp;
+{
+       return(is_u(etmp)? "you" : mon_nam(etmp->emon));
+}
+
+#ifdef D_DEBUG
+/*
+ * Enam is another unused utility routine:  E_phrase is preferable.
+ */
+
+static const char *
+Enam(etmp)
+struct entity *etmp;
+{
+       return(is_u(etmp)? "You" : Monnam(etmp->emon));
+}
+#endif /* D_DEBUG */
+
+/*
+ * Generates capitalized entity name, makes 2nd -> 3rd person conversion on
+ * verb, where necessary.
+ */
+
+STATIC_OVL const char *
+E_phrase(etmp, verb)
+struct entity *etmp;
+const char *verb;
+{
+       static char wholebuf[80];
+
+       Strcpy(wholebuf, is_u(etmp) ? "You" : Monnam(etmp->emon));
+       if (!*verb) return(wholebuf);
+       Strcat(wholebuf, " ");
+       if (is_u(etmp))
+           Strcat(wholebuf, verb);
+       else
+           Strcat(wholebuf, vtense((char *)0, verb));
+       return(wholebuf);
+}
+
+/*
+ * Simple-minded "can it be here?" routine
+ */
+
+STATIC_OVL boolean
+e_survives_at(etmp, x, y)
+struct entity *etmp;
+int x, y;
+{
+       if (noncorporeal(etmp->edata))
+               return(TRUE);
+       if (is_pool(x, y))
+               return (boolean)((is_u(etmp) &&
+                               (Wwalking || Amphibious || Swimming ||
+                               Flying || Levitation)) ||
+                       is_swimmer(etmp->edata) || is_flyer(etmp->edata) ||
+                       is_floater(etmp->edata));
+       /* must force call to lava_effects in e_died if is_u */
+       if (is_lava(x, y))
+               return (boolean)((is_u(etmp) && (Levitation || Flying)) ||
+                           likes_lava(etmp->edata) || is_flyer(etmp->edata));
+       if (is_db_wall(x, y))
+               return((boolean)(is_u(etmp) ? Passes_walls :
+                       passes_walls(etmp->edata)));
+       return(TRUE);
+}
+
+STATIC_OVL void
+e_died(etmp, dest, how)
+struct entity *etmp;
+int dest, how;
+{
+       if (is_u(etmp)) {
+               if (how == DROWNING) {
+                       killer = 0;     /* drown() sets its own killer */
+                       (void) drown();
+               } else if (how == BURNING) {
+                       killer = 0;     /* lava_effects() sets its own killer */
+                       (void) lava_effects();
+               } else {
+                       coord xy;
+
+                       /* use more specific killer if specified */
+                       if (!killer) {
+                           killer_format = KILLED_BY_AN;
+                           killer = "falling drawbridge";
+                       }
+                       done(how);
+                       /* So, you didn't die */
+                       if (!e_survives_at(etmp, etmp->ex, etmp->ey)) {
+                           if (enexto(&xy, etmp->ex, etmp->ey, etmp->edata)) {
+                               pline("A %s force teleports you away...",
+                                     Hallucination ? "normal" : "strange");
+                               teleds(xy.x, xy.y, FALSE);
+                           }
+                           /* otherwise on top of the drawbridge is the
+                            * only viable spot in the dungeon, so stay there
+                            */
+                       }
+               }
+               /* we might have crawled out of the moat to survive */
+               etmp->ex = u.ux,  etmp->ey = u.uy;
+       } else {
+               int entitycnt;
+
+               killer = 0;
+               /* fake "digested to death" damage-type suppresses corpse */
+#define mk_message(dest) ((dest & 1) ? "" : (char *)0)
+#define mk_corpse(dest)  ((dest & 2) ? AD_DGST : AD_PHYS)
+               /* if monsters are moving, one of them caused the destruction */
+               if (flags.mon_moving)
+                   monkilled(etmp->emon, mk_message(dest), mk_corpse(dest));
+               else            /* you caused it */
+                   xkilled(etmp->emon, dest);
+               etmp->edata = (struct permonst *)0;
+
+               /* dead long worm handling */
+               for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++) {
+                   if (etmp != &(occupants[entitycnt]) &&
+                       etmp->emon == occupants[entitycnt].emon)
+                       occupants[entitycnt].edata = (struct permonst *)0;
+               }
+#undef mk_message
+#undef mk_corpse
+       }
+}
+
+
+/*
+ * These are never directly affected by a bridge or portcullis.
+ */
+
+STATIC_OVL boolean
+automiss(etmp)
+struct entity *etmp;
+{
+       return (boolean)((is_u(etmp) ? Passes_walls :
+                       passes_walls(etmp->edata)) || noncorporeal(etmp->edata));
+}
+
+/*
+ * Does falling drawbridge or portcullis miss etmp?
+ */
+
+STATIC_OVL boolean
+e_missed(etmp, chunks)
+struct entity *etmp;
+boolean chunks;
+{
+       int misses;
+
+#ifdef D_DEBUG
+       if (chunks)
+               pline("Do chunks miss?");
+#endif
+       if (automiss(etmp))
+               return(TRUE);
+
+       if (is_flyer(etmp->edata) &&
+           (is_u(etmp)? !Sleeping :
+            (etmp->emon->mcanmove && !etmp->emon->msleeping)))
+                                                /* flying requires mobility */
+               misses = 5;     /* out of 8 */
+       else if (is_floater(etmp->edata) ||
+                   (is_u(etmp) && Levitation))  /* doesn't require mobility */
+               misses = 3;
+       else if (chunks && is_pool(etmp->ex, etmp->ey))
+               misses = 2;                                 /* sitting ducks */
+       else
+               misses = 0;
+
+       if (is_db_wall(etmp->ex, etmp->ey))
+               misses -= 3;                                /* less airspace */
+
+#ifdef D_DEBUG
+       pline("Miss chance = %d (out of 8)", misses);
+#endif
+
+       return((boolean)((misses >= rnd(8))? TRUE : FALSE));
+}
+
+/*
+ * Can etmp jump from death?
+ */
+
+STATIC_OVL boolean
+e_jumps(etmp)
+struct entity *etmp;
+{
+       int tmp = 4;            /* out of 10 */
+
+       if (is_u(etmp)? (Sleeping || Fumbling) :
+                       (!etmp->emon->mcanmove || etmp->emon->msleeping ||
+                        !etmp->edata->mmove   || etmp->emon->wormno))
+               return(FALSE);
+
+       if (is_u(etmp)? Confusion : etmp->emon->mconf)
+               tmp -= 2;
+
+       if (is_u(etmp)? Stunned : etmp->emon->mstun)
+               tmp -= 3;
+
+       if (is_db_wall(etmp->ex, etmp->ey))
+               tmp -= 2;                           /* less room to maneuver */
+
+#ifdef D_DEBUG
+       pline("%s to jump (%d chances in 10)", E_phrase(etmp, "try"), tmp);
+#endif
+       return((boolean)((tmp >= rnd(10))? TRUE : FALSE));
+}
+
+STATIC_OVL void
+do_entity(etmp)
+struct entity *etmp;
+{
+       int newx, newy, at_portcullis, oldx, oldy;
+       boolean must_jump = FALSE, relocates = FALSE, e_inview;
+       struct rm *crm;
+
+       if (!etmp->edata)
+               return;
+
+       e_inview = e_canseemon(etmp);
+       oldx = etmp->ex;
+       oldy = etmp->ey;
+       at_portcullis = is_db_wall(oldx, oldy);
+       crm = &levl[oldx][oldy];
+
+       if (automiss(etmp) && e_survives_at(etmp, oldx, oldy)) {
+               if (e_inview && (at_portcullis || IS_DRAWBRIDGE(crm->typ)))
+                       pline_The("%s passes through %s!",
+                             at_portcullis ? "portcullis" : "drawbridge",
+                             e_nam(etmp));
+               if (is_u(etmp)) spoteffects(FALSE);
+               return;
+       }
+       if (e_missed(etmp, FALSE)) {
+               if (at_portcullis)
+                       pline_The("portcullis misses %s!",
+                             e_nam(etmp));
+#ifdef D_DEBUG
+               else
+                       pline_The("drawbridge misses %s!",
+                             e_nam(etmp));
+#endif
+               if (e_survives_at(etmp, oldx, oldy))
+                       return;
+               else {
+#ifdef D_DEBUG
+                       pline("Mon can't survive here");
+#endif
+                       if (at_portcullis)
+                               must_jump = TRUE;
+                       else
+                               relocates = TRUE; /* just ride drawbridge in */
+               }
+       } else {
+               if (crm->typ == DRAWBRIDGE_DOWN) {
+                       pline("%s crushed underneath the drawbridge.",
+                             E_phrase(etmp, "are"));             /* no jump */
+                       e_died(etmp, e_inview? 3 : 2, CRUSHING);/* no corpse */
+                       return;   /* Note: Beyond this point, we know we're  */
+               }                 /* not at an opened drawbridge, since all  */
+               must_jump = TRUE; /* *missable* creatures survive on the     */
+       }                         /* square, and all the unmissed ones die.  */
+       if (must_jump) {
+           if (at_portcullis) {
+               if (e_jumps(etmp)) {
+                   relocates = TRUE;
+#ifdef D_DEBUG
+                   pline("Jump succeeds!");
+#endif
+               } else {
+                   if (e_inview)
+                       pline("%s crushed by the falling portcullis!",
+                             E_phrase(etmp, "are"));
+                   else if (flags.soundok)
+                       You_hear("a crushing sound.");
+                   e_died(etmp, e_inview? 3 : 2, CRUSHING);
+                   /* no corpse */
+                   return;
+               }
+           } else { /* tries to jump off bridge to original square */
+               relocates = !e_jumps(etmp);
+#ifdef D_DEBUG
+               pline("Jump %s!", (relocates)? "fails" : "succeeds");
+#endif
+           }
+       }
+
+/*
+ * Here's where we try to do relocation.  Assumes that etmp is not arriving
+ * at the portcullis square while the drawbridge is falling, since this square
+ * would be inaccessible (i.e. etmp started on drawbridge square) or
+ * unnecessary (i.e. etmp started here) in such a situation.
+ */
+#ifdef D_DEBUG
+       pline("Doing relocation.");
+#endif
+       newx = oldx;
+       newy = oldy;
+       (void)find_drawbridge(&newx, &newy);
+       if ((newx == oldx) && (newy == oldy))
+               get_wall_for_db(&newx, &newy);
+#ifdef D_DEBUG
+       pline("Checking new square for occupancy.");
+#endif
+       if (relocates && (e_at(newx, newy))) {
+
+/*
+ * Standoff problem:  one or both entities must die, and/or both switch
+ * places.  Avoid infinite recursion by checking first whether the other
+ * entity is staying put.  Clean up if we happen to move/die in recursion.
+ */
+               struct entity *other;
+
+               other = e_at(newx, newy);
+#ifdef D_DEBUG
+               pline("New square is occupied by %s", e_nam(other));
+#endif
+               if (e_survives_at(other, newx, newy) && automiss(other)) {
+                       relocates = FALSE;            /* "other" won't budge */
+#ifdef D_DEBUG
+                       pline("%s suicide.", E_phrase(etmp, "commit"));
+#endif
+               } else {
+
+#ifdef D_DEBUG
+                       pline("Handling %s", e_nam(other));
+#endif
+                       while ((e_at(newx, newy) != 0) &&
+                              (e_at(newx, newy) != etmp))
+                               do_entity(other);
+#ifdef D_DEBUG
+                       pline("Checking existence of %s", e_nam(etmp));
+                       wait_synch();
+#endif
+                       if (e_at(oldx, oldy) != etmp) {
+#ifdef D_DEBUG
+                           pline("%s moved or died in recursion somewhere",
+                                 E_phrase(etmp, "have"));
+                           wait_synch();
+#endif
+                           return;
+                       }
+               }
+       }
+       if (relocates && !e_at(newx, newy)) {/* if e_at() entity = worm tail */
+#ifdef D_DEBUG
+               pline("Moving %s", e_nam(etmp));
+#endif
+               if (!is_u(etmp)) {
+                       remove_monster(etmp->ex, etmp->ey);
+                       place_monster(etmp->emon, newx, newy);
+                       update_monster_region(etmp->emon);
+               } else {
+                       u.ux = newx;
+                       u.uy = newy;
+               }
+               etmp->ex = newx;
+               etmp->ey = newy;
+               e_inview = e_canseemon(etmp);
+       }
+#ifdef D_DEBUG
+       pline("Final disposition of %s", e_nam(etmp));
+       wait_synch();
+#endif
+       if (is_db_wall(etmp->ex, etmp->ey)) {
+#ifdef D_DEBUG
+               pline("%s in portcullis chamber", E_phrase(etmp, "are"));
+               wait_synch();
+#endif
+               if (e_inview) {
+                       if (is_u(etmp)) {
+                               You("tumble towards the closed portcullis!");
+                               if (automiss(etmp))
+                                       You("pass through it!");
+                               else
+                                       pline_The("drawbridge closes in...");
+                       } else
+                               pline("%s behind the drawbridge.",
+                                     E_phrase(etmp, "disappear"));
+               }
+               if (!e_survives_at(etmp, etmp->ex, etmp->ey)) {
+                       killer_format = KILLED_BY_AN;
+                       killer = "closing drawbridge";
+                       e_died(etmp, 0, CRUSHING);             /* no message */
+                       return;
+               }
+#ifdef D_DEBUG
+               pline("%s in here", E_phrase(etmp, "survive"));
+#endif
+       } else {
+#ifdef D_DEBUG
+               pline("%s on drawbridge square", E_phrase(etmp, "are"));
+#endif
+               if (is_pool(etmp->ex, etmp->ey) && !e_inview)
+                       if (flags.soundok)
+                               You_hear("a splash.");
+               if (e_survives_at(etmp, etmp->ex, etmp->ey)) {
+                       if (e_inview && !is_flyer(etmp->edata) &&
+                           !is_floater(etmp->edata))
+                               pline("%s from the bridge.",
+                                     E_phrase(etmp, "fall"));
+                       return;
+               }
+#ifdef D_DEBUG
+               pline("%s cannot survive on the drawbridge square",Enam(etmp));
+#endif
+               if (is_pool(etmp->ex, etmp->ey) || is_lava(etmp->ex, etmp->ey))
+                   if (e_inview && !is_u(etmp)) {
+                       /* drown() will supply msgs if nec. */
+                       boolean lava = is_lava(etmp->ex, etmp->ey);
+
+                       if (Hallucination)
+                           pline("%s the %s and disappears.",
+                                 E_phrase(etmp, "drink"),
+                                 lava ? "lava" : "moat");
+                       else
+                           pline("%s into the %s.",
+                                 E_phrase(etmp, "fall"),
+                                 lava ? "lava" : "moat");
+                   }
+               killer_format = NO_KILLER_PREFIX;
+               killer = "fell from a drawbridge";
+               e_died(etmp, e_inview ? 3 : 2,      /* CRUSHING is arbitrary */
+                      (is_pool(etmp->ex, etmp->ey)) ? DROWNING :
+                      (is_lava(etmp->ex, etmp->ey)) ? BURNING :
+                                                      CRUSHING); /*no corpse*/
+               return;
+       }
+}
+
+/*
+ * Close the drawbridge located at x,y
+ */
+
+void
+close_drawbridge(x,y)
+int x,y;
+{
+       register struct rm *lev1, *lev2;
+       struct trap *t;
+       int x2, y2;
+
+       lev1 = &levl[x][y];
+       if (lev1->typ != DRAWBRIDGE_DOWN) return;
+       x2 = x; y2 = y;
+       get_wall_for_db(&x2,&y2);
+       if (cansee(x,y) || cansee(x2,y2))
+               You("see a drawbridge %s up!",
+                   (((u.ux == x || u.uy == y) && !Underwater) ||
+                    distu(x2,y2) < distu(x,y)) ? "coming" : "going");
+       lev1->typ = DRAWBRIDGE_UP;
+       lev2 = &levl[x2][y2];
+       lev2->typ = DBWALL;
+       switch (lev1->drawbridgemask & DB_DIR) {
+               case DB_NORTH:
+               case DB_SOUTH:
+                       lev2->horizontal = TRUE;
+                       break;
+               case DB_WEST:
+               case DB_EAST:
+                       lev2->horizontal = FALSE;
+                       break;
+       }
+       lev2->wall_info = W_NONDIGGABLE;
+       set_entity(x, y, &(occupants[0]));
+       set_entity(x2, y2, &(occupants[1]));
+       do_entity(&(occupants[0]));             /* Do set_entity after first */
+       set_entity(x2, y2, &(occupants[1]));    /* do_entity for worm tail */
+       do_entity(&(occupants[1]));
+       if(OBJ_AT(x,y) && flags.soundok)
+           You_hear("smashing and crushing.");
+       (void) revive_nasty(x,y,(char *)0);
+       (void) revive_nasty(x2,y2,(char *)0);
+       delallobj(x, y);
+       delallobj(x2, y2);
+       if ((t = t_at(x, y)) != 0) deltrap(t);
+       if ((t = t_at(x2, y2)) != 0) deltrap(t);
+       newsym(x, y);
+       newsym(x2, y2);
+       block_point(x2,y2);     /* vision */
+}
+
+/*
+ * Open the drawbridge located at x,y
+ */
+
+void
+open_drawbridge(x,y)
+int x,y;
+{
+       register struct rm *lev1, *lev2;
+       struct trap *t;
+       int x2, y2;
+
+       lev1 = &levl[x][y];
+       if (lev1->typ != DRAWBRIDGE_UP) return;
+       x2 = x; y2 = y;
+       get_wall_for_db(&x2,&y2);
+       if (cansee(x,y) || cansee(x2,y2))
+               You("see a drawbridge %s down!",
+                   (distu(x2,y2) < distu(x,y)) ? "going" : "coming");
+       lev1->typ = DRAWBRIDGE_DOWN;
+       lev2 = &levl[x2][y2];
+       lev2->typ = DOOR;
+       lev2->doormask = D_NODOOR;
+       set_entity(x, y, &(occupants[0]));
+       set_entity(x2, y2, &(occupants[1]));
+       do_entity(&(occupants[0]));             /* do set_entity after first */
+       set_entity(x2, y2, &(occupants[1]));    /* do_entity for worm tails */
+       do_entity(&(occupants[1]));
+       (void) revive_nasty(x,y,(char *)0);
+       delallobj(x, y);
+       if ((t = t_at(x, y)) != 0) deltrap(t);
+       if ((t = t_at(x2, y2)) != 0) deltrap(t);
+       newsym(x, y);
+       newsym(x2, y2);
+       unblock_point(x2,y2);   /* vision */
+       if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE;
+}
+
+/*
+ * Let's destroy the drawbridge located at x,y
+ */
+
+void
+destroy_drawbridge(x,y)
+int x,y;
+{
+       register struct rm *lev1, *lev2;
+       struct trap *t;
+       int x2, y2;
+       boolean e_inview;
+       struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]);
+
+       lev1 = &levl[x][y];
+       if (!IS_DRAWBRIDGE(lev1->typ))
+               return;
+       x2 = x; y2 = y;
+       get_wall_for_db(&x2,&y2);
+       lev2 = &levl[x2][y2];
+       if ((lev1->drawbridgemask & DB_UNDER) == DB_MOAT ||
+           (lev1->drawbridgemask & DB_UNDER) == DB_LAVA) {
+               struct obj *otmp;
+               boolean lava = (lev1->drawbridgemask & DB_UNDER) == DB_LAVA;
+               if (lev1->typ == DRAWBRIDGE_UP) {
+                       if (cansee(x2,y2))
+                           pline_The("portcullis of the drawbridge falls into the %s!",
+                                 lava ? "lava" : "moat");
+                       else if (flags.soundok)
+                               You_hear("a loud *SPLASH*!");
+               } else {
+                       if (cansee(x,y))
+                           pline_The("drawbridge collapses into the %s!",
+                                 lava ? "lava" : "moat");
+                       else if (flags.soundok)
+                               You_hear("a loud *SPLASH*!");
+               }
+               lev1->typ = lava ? LAVAPOOL : MOAT;
+               lev1->drawbridgemask = 0;
+               if ((otmp = sobj_at(BOULDER,x,y)) != 0) {
+                   obj_extract_self(otmp);
+                   (void) flooreffects(otmp,x,y,"fall");
+               }
+       } else {
+               if (cansee(x,y))
+                       pline_The("drawbridge disintegrates!");
+               else
+                       You_hear("a loud *CRASH*!");
+               lev1->typ =
+                       ((lev1->drawbridgemask & DB_ICE) ? ICE : ROOM);
+               lev1->icedpool =
+                       ((lev1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0);
+       }
+       wake_nearto(x, y, 500);
+       lev2->typ = DOOR;
+       lev2->doormask = D_NODOOR;
+       if ((t = t_at(x, y)) != 0) deltrap(t);
+       if ((t = t_at(x2, y2)) != 0) deltrap(t);
+       newsym(x,y);
+       newsym(x2,y2);
+       if (!does_block(x2,y2,lev2)) unblock_point(x2,y2);      /* vision */
+       if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE;
+
+       set_entity(x2, y2, etmp2); /* currently only automissers can be here */
+       if (etmp2->edata) {
+               e_inview = e_canseemon(etmp2);
+               if (!automiss(etmp2)) {
+                       if (e_inview)
+                               pline("%s blown apart by flying debris.",
+                                     E_phrase(etmp2, "are"));
+                       killer_format = KILLED_BY_AN;
+                       killer = "exploding drawbridge";
+                       e_died(etmp2, e_inview? 3 : 2, CRUSHING); /*no corpse*/
+               }            /* nothing which is vulnerable can survive this */
+       }
+       set_entity(x, y, etmp1);
+       if (etmp1->edata) {
+               e_inview = e_canseemon(etmp1);
+               if (e_missed(etmp1, TRUE)) {
+#ifdef D_DEBUG
+                       pline("%s spared!", E_phrase(etmp1, "are"));
+#endif
+               } else {
+                       if (e_inview) {
+                           if (!is_u(etmp1) && Hallucination)
+                               pline("%s into some heavy metal!",
+                                     E_phrase(etmp1, "get"));
+                           else
+                               pline("%s hit by a huge chunk of metal!",
+                                     E_phrase(etmp1, "are"));
+                       } else {
+                           if (flags.soundok && !is_u(etmp1) && !is_pool(x,y))
+                               You_hear("a crushing sound.");
+#ifdef D_DEBUG
+                           else
+                               pline("%s from shrapnel",
+                                     E_phrase(etmp1, "die"));
+#endif
+                       }
+                       killer_format = KILLED_BY_AN;
+                       killer = "collapsing drawbridge";
+                       e_died(etmp1, e_inview? 3 : 2, CRUSHING); /*no corpse*/
+                       if(lev1->typ == MOAT) do_entity(etmp1);
+               }
+       }
+}
+
+#endif /* OVLB */
+
+/*dbridge.c*/
diff --git a/src/decl.c b/src/decl.c
new file mode 100644 (file)
index 0000000..4dd460e
--- /dev/null
@@ -0,0 +1,281 @@
+/*     SCCS Id: @(#)decl.c     3.2     2001/12/10      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+int NDECL((*afternmv));
+int NDECL((*occupation));
+
+/* from xxxmain.c */
+const char *hname = 0;         /* name of the game (argv[0] of main) */
+int hackpid = 0;               /* current process id */
+#if defined(UNIX) || defined(VMS)
+int locknum = 0;               /* max num of simultaneous users */
+#endif
+#ifdef DEF_PAGER
+char *catmore = 0;             /* default pager */
+#endif
+
+NEARDATA int bases[MAXOCLASSES] = DUMMY;
+
+NEARDATA int multi = 0;
+#if 0
+NEARDATA int warnlevel = 0;            /* used by movemon and dochugw */
+#endif
+NEARDATA int nroom = 0;
+NEARDATA int nsubroom = 0;
+NEARDATA int occtime = 0;
+
+int x_maze_max, y_maze_max;    /* initialized in main, used in mkmaze.c */
+int otg_temp;                  /* used by object_to_glyph() [otg] */
+
+#ifdef REDO
+NEARDATA int in_doagain = 0;
+#endif
+
+/*
+ *     The following structure will be initialized at startup time with
+ *     the level numbers of some "important" things in the game.
+ */
+struct dgn_topology dungeon_topology = {DUMMY};
+
+#include "quest.h"
+struct q_score quest_status = DUMMY;
+
+NEARDATA int smeq[MAXNROFROOMS+1] = DUMMY;
+NEARDATA int doorindex = 0;
+
+NEARDATA char *save_cm = 0;
+NEARDATA int killer_format = 0;
+const char *killer = 0;
+const char *delayed_killer = 0;
+#ifdef GOLDOBJ
+NEARDATA long done_money = 0;
+#endif
+char killer_buf[BUFSZ] = DUMMY;
+const char *nomovemsg = 0;
+const char nul[40] = DUMMY;                    /* contains zeros */
+NEARDATA char plname[PL_NSIZ] = DUMMY;         /* player name */
+NEARDATA char pl_character[PL_CSIZ] = DUMMY;
+NEARDATA char pl_race = '\0';
+
+NEARDATA char pl_fruit[PL_FSIZ] = DUMMY;
+NEARDATA int current_fruit = 0;
+NEARDATA struct fruit *ffruit = (struct fruit *)0;
+
+NEARDATA char tune[6] = DUMMY;
+
+const char *occtxt = DUMMY;
+const char quitchars[] = " \r\n\033";
+const char vowels[] = "aeiouAEIOU";
+const char ynchars[] = "yn";
+const char ynqchars[] = "ynq";
+const char ynaqchars[] = "ynaq";
+const char ynNaqchars[] = "yn#aq";
+NEARDATA long yn_number = 0L;
+
+const char disclosure_options[] = "iavgc";
+
+#if defined(MICRO) || defined(WIN32)
+char hackdir[PATHLEN];         /* where rumors, help, record are */
+# ifdef MICRO
+char levels[PATHLEN];          /* where levels are */
+# endif
+#endif /* MICRO || WIN32 */
+
+
+#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 linfo level_info[MAXLINFO];
+
+NEARDATA struct sinfo program_state;
+
+/* 'rogue'-like direction commands (cmd.c) */
+const char sdir[] = "hykulnjb><";
+const char ndir[] = "47896321><";      /* number pad mode */
+const schar xdir[10] = { -1,-1, 0, 1, 1, 1, 0,-1, 0, 0 };
+const schar ydir[10] = {  0,-1,-1,-1, 0, 1, 1, 1, 0, 0 };
+const schar zdir[10] = {  0, 0, 0, 0, 0, 0, 0, 0, 1,-1 };
+
+NEARDATA schar tbx = 0, tby = 0;       /* mthrowu: target */
+
+/* for xname handling of multiple shot missile volleys:
+   number of shots, index of current one, validity check, shoot vs throw */
+NEARDATA struct multishot m_shot = { 0, 0, STRANGE_OBJECT, FALSE };
+
+NEARDATA struct dig_info digging;
+
+NEARDATA dungeon dungeons[MAXDUNGEON]; /* ini'ed by init_dungeon() */
+NEARDATA s_level *sp_levchn;
+NEARDATA stairway upstair = { 0, 0 }, dnstair = { 0, 0 };
+NEARDATA stairway upladder = { 0, 0 }, dnladder = { 0, 0 };
+NEARDATA stairway sstairs = { 0, 0 };
+NEARDATA dest_area updest = { 0, 0, 0, 0, 0, 0, 0, 0 };
+NEARDATA dest_area dndest = { 0, 0, 0, 0, 0, 0, 0, 0 };
+NEARDATA coord inv_pos = { 0, 0 };
+
+NEARDATA boolean in_mklev = FALSE;
+NEARDATA boolean stoned = FALSE;       /* done to monsters hit by 'c' */
+NEARDATA boolean unweapon = FALSE;
+NEARDATA boolean mrg_to_wielded = FALSE;
+                        /* weapon picked is merged with wielded one */
+NEARDATA struct obj *current_wand = 0; /* wand currently zapped/applied */
+
+NEARDATA boolean in_steed_dismounting = FALSE;
+
+NEARDATA coord bhitpos = DUMMY;
+NEARDATA coord doors[DOORMAX] = {DUMMY};
+
+NEARDATA struct mkroom rooms[(MAXNROFROOMS+1)*2] = {DUMMY};
+NEARDATA struct mkroom* subrooms = &rooms[MAXNROFROOMS+1];
+struct mkroom *upstairs_room, *dnstairs_room, *sstairs_room;
+
+dlevel_t level;                /* level map */
+struct trap *ftrap = (struct trap *)0;
+NEARDATA struct monst youmonst = DUMMY;
+NEARDATA struct flag flags = DUMMY;
+NEARDATA struct instance_flags iflags = DUMMY;
+NEARDATA struct you u = DUMMY;
+
+NEARDATA struct obj *invent = (struct obj *)0,
+       *uwep = (struct obj *)0, *uarm = (struct obj *)0,
+       *uswapwep = (struct obj *)0,
+       *uquiver = (struct obj *)0, /* quiver */
+#ifdef TOURIST
+       *uarmu = (struct obj *)0, /* under-wear, so to speak */
+#endif
+       *uskin = (struct obj *)0, /* dragon armor, if a dragon */
+       *uarmc = (struct obj *)0, *uarmh = (struct obj *)0,
+       *uarms = (struct obj *)0, *uarmg = (struct obj *)0,
+       *uarmf = (struct obj *)0, *uamul = (struct obj *)0,
+       *uright = (struct obj *)0,
+       *uleft = (struct obj *)0,
+       *ublindf = (struct obj *)0,
+       *uchain = (struct obj *)0,
+       *uball = (struct obj *)0;
+
+#ifdef TEXTCOLOR
+/*
+ *  This must be the same order as used for buzz() in zap.c.
+ */
+const int zapcolors[NUM_ZAP] = {
+    HI_ZAP,            /* 0 - missile */
+    CLR_ORANGE,                /* 1 - fire */
+    CLR_WHITE,         /* 2 - frost */
+    HI_ZAP,            /* 3 - sleep */
+    CLR_BLACK,         /* 4 - death */
+    CLR_WHITE,         /* 5 - lightning */
+    CLR_YELLOW,                /* 6 - poison gas */
+    CLR_GREEN,         /* 7 - acid */
+};
+#endif /* text color */
+
+const int shield_static[SHIELD_COUNT] = {
+    S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4,   /* 7 per row */
+    S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4,
+    S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4,
+};
+
+NEARDATA struct spell spl_book[MAXSPELL + 1] = {DUMMY};
+
+NEARDATA long moves = 1L, monstermoves = 1L;
+        /* These diverge when player is Fast */
+NEARDATA long wailmsg = 0L;
+
+/* objects that are moving to another dungeon level */
+NEARDATA struct obj *migrating_objs = (struct obj *)0;
+/* objects not yet paid for */
+NEARDATA struct obj *billobjs = (struct obj *)0;
+
+/* used to zero all elements of a struct obj */
+NEARDATA struct obj zeroobj = DUMMY;
+
+/* originally from dog.c */
+NEARDATA char dogname[PL_PSIZ] = DUMMY;
+NEARDATA char catname[PL_PSIZ] = DUMMY;
+NEARDATA char horsename[PL_PSIZ] = DUMMY;
+char preferred_pet;    /* '\0', 'c', 'd', 'n' (none) */
+/* monsters that went down/up together with @ */
+NEARDATA struct monst *mydogs = (struct monst *)0;
+/* monsters that are moving to another dungeon level */
+NEARDATA struct monst *migrating_mons = (struct monst *)0;
+
+NEARDATA struct mvitals mvitals[NUMMONS];
+
+NEARDATA struct c_color_names c_color_names = {
+       "black", "amber", "golden",
+       "light blue", "red", "green",
+       "silver", "blue", "purple",
+       "white"
+};
+
+const char *c_obj_colors[] = {
+       "black",                /* CLR_BLACK */
+       "red",                  /* CLR_RED */
+       "green",                /* CLR_GREEN */
+       "brown",                /* CLR_BROWN */
+       "blue",                 /* CLR_BLUE */
+       "magenta",              /* CLR_MAGENTA */
+       "cyan",                 /* CLR_CYAN */
+       "gray",                 /* CLR_GRAY */
+       "transparent",          /* no_color */
+       "orange",               /* CLR_ORANGE */
+       "bright green",         /* CLR_BRIGHT_GREEN */
+       "yellow",               /* CLR_YELLOW */
+       "bright blue",          /* CLR_BRIGHT_BLUE */
+       "bright magenta",       /* CLR_BRIGHT_MAGENTA */
+       "bright cyan",          /* CLR_BRIGHT_CYAN */
+       "white",                /* CLR_WHITE */
+};
+
+struct c_common_strings c_common_strings = {
+       "Nothing happens.",             "That's enough tries!",
+       "That is a silly thing to %s.", "shudder for a moment.",
+       "something", "Something", "You can move again.", "Never mind.",
+       "vision quickly clears.", {"the", "your"}
+};
+
+/* NOTE: the order of these words exactly corresponds to the
+   order of oc_material values #define'd in objclass.h. */
+const char *materialnm[] = {
+       "mysterious", "liquid", "wax", "organic", "flesh",
+       "paper", "cloth", "leather", "wooden", "bone", "dragonhide",
+       "iron", "metal", "copper", "silver", "gold", "platinum", "mithril",
+       "plastic", "glass", "gemstone", "stone"
+};
+
+/* Vision */
+NEARDATA boolean vision_full_recalc = 0;
+NEARDATA char   **viz_array = 0;/* used in cansee() and couldsee() macros */
+
+/* Global windowing data, defined here for multi-window-system support */
+NEARDATA winid WIN_MESSAGE = WIN_ERR, WIN_STATUS = WIN_ERR;
+NEARDATA winid WIN_MAP = WIN_ERR, WIN_INVEN = WIN_ERR;
+char toplines[TBUFSZ];
+/* Windowing stuff that's really tty oriented, but present for all ports */
+struct tc_gbl_data tc_gbl_data = { 0,0, 0,0 }; /* AS,AE, LI,CO */
+
+char *fqn_prefix[PREFIX_COUNT] = { (char *)0, (char *)0, (char *)0, (char *)0,
+                               (char *)0, (char *)0, (char *)0, (char *)0, (char *)0 };
+
+#ifdef PREFIXES_IN_USE
+char *fqn_prefix_names[PREFIX_COUNT] = { "hackdir", "leveldir", "savedir",
+                                       "bonesdir", "datadir", "scoredir",
+                                       "lockdir", "configdir", "troubledir" };
+#endif
+
+/* dummy routine used to force linkage */
+void
+decl_init()
+{
+    return;
+}
+
+/*decl.c*/
diff --git a/src/detect.c b/src/detect.c
new file mode 100644 (file)
index 0000000..5da025f
--- /dev/null
@@ -0,0 +1,1299 @@
+/*     SCCS Id: @(#)detect.c   3.4     2003/08/13      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Detection routines, including crystal ball, magic mapping, and search
+ * command.
+ */
+
+#include "hack.h"
+#include "artifact.h"
+
+extern boolean known;  /* from read.c */
+
+STATIC_DCL void FDECL(do_dknown_of, (struct obj *));
+STATIC_DCL boolean FDECL(check_map_spot, (int,int,CHAR_P,unsigned));
+STATIC_DCL boolean FDECL(clear_stale_map, (CHAR_P,unsigned));
+STATIC_DCL void FDECL(sense_trap, (struct trap *,XCHAR_P,XCHAR_P,int));
+STATIC_DCL void FDECL(show_map_spot, (int,int));
+STATIC_PTR void FDECL(findone,(int,int,genericptr_t));
+STATIC_PTR void FDECL(openone,(int,int,genericptr_t));
+
+/* Recursively search obj for an object in class oclass and return 1st found */
+struct obj *
+o_in(obj, oclass)
+struct obj* obj;
+char oclass;
+{
+    register struct obj* otmp;
+    struct obj *temp;
+
+    if (obj->oclass == oclass) return obj;
+
+    if (Has_contents(obj)) {
+       for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
+           if (otmp->oclass == oclass) return otmp;
+           else if (Has_contents(otmp) && (temp = o_in(otmp, oclass)))
+               return temp;
+    }
+    return (struct obj *) 0;
+}
+
+/* Recursively search obj for an object made of specified material and return 1st found */
+struct obj *
+o_material(obj, material)
+struct obj* obj;
+unsigned material;
+{
+    register struct obj* otmp;
+    struct obj *temp;
+
+    if (objects[obj->otyp].oc_material == material) return obj;
+
+    if (Has_contents(obj)) {
+       for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
+           if (objects[otmp->otyp].oc_material == material) return otmp;
+           else if (Has_contents(otmp) && (temp = o_material(otmp, material)))
+               return temp;
+    }
+    return (struct obj *) 0;
+}
+
+STATIC_OVL void
+do_dknown_of(obj)
+struct obj *obj;
+{
+    struct obj *otmp;
+
+    obj->dknown = 1;
+    if (Has_contents(obj)) {
+       for(otmp = obj->cobj; otmp; otmp = otmp->nobj)
+           do_dknown_of(otmp);
+    }
+}
+
+/* Check whether the location has an outdated object displayed on it. */
+STATIC_OVL boolean
+check_map_spot(x, y, oclass, material)
+int x, y;
+register char oclass;
+unsigned material;
+{
+       register int glyph;
+       register struct obj *otmp;
+       register struct monst *mtmp;
+
+       glyph = glyph_at(x,y);
+       if (glyph_is_object(glyph)) {
+           /* there's some object shown here */
+           if (oclass == ALL_CLASSES) {
+               return((boolean)( !(level.objects[x][y] ||     /* stale if nothing here */
+                           ((mtmp = m_at(x,y)) != 0 &&
+                               (
+#ifndef GOLDOBJ
+                                mtmp->mgold ||
+#endif
+                                                mtmp->minvent)))));
+           } else {
+               if (material && objects[glyph_to_obj(glyph)].oc_material == material) {
+                       /* the object shown here is of interest because material matches */
+                       for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
+                               if (o_material(otmp, GOLD)) return FALSE;
+                       /* didn't find it; perhaps a monster is carrying it */
+                       if ((mtmp = m_at(x,y)) != 0) {
+                               for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+                                       if (o_material(otmp, GOLD)) return FALSE;
+                       }
+                       /* detection indicates removal of this object from the map */
+                       return TRUE;
+               }
+               if (oclass && objects[glyph_to_obj(glyph)].oc_class == oclass) {
+                       /* the object shown here is of interest because its class matches */
+                       for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
+                               if (o_in(otmp, oclass)) return FALSE;
+                       /* didn't find it; perhaps a monster is carrying it */
+#ifndef GOLDOBJ
+                       if ((mtmp = m_at(x,y)) != 0) {
+                               if (oclass == COIN_CLASS && mtmp->mgold)
+                                       return FALSE;
+                               else for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+                                       if (o_in(otmp, oclass)) return FALSE;
+                       }
+#else
+                       if ((mtmp = m_at(x,y)) != 0) {
+                               for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+                                       if (o_in(otmp, oclass)) return FALSE;
+                       }
+#endif
+                       /* detection indicates removal of this object from the map */
+                       return TRUE;
+               }
+           }
+       }
+       return FALSE;
+}
+
+/*
+   When doing detection, remove stale data from the map display (corpses
+   rotted away, objects carried away by monsters, etc) so that it won't
+   reappear after the detection has completed.  Return true if noticeable
+   change occurs.
+ */
+STATIC_OVL boolean
+clear_stale_map(oclass, material)
+register char oclass;
+unsigned material;
+{
+       register int zx, zy;
+       register boolean change_made = FALSE;
+
+       for (zx = 1; zx < COLNO; zx++)
+           for (zy = 0; zy < ROWNO; zy++)
+               if (check_map_spot(zx, zy, oclass,material)) {
+                   unmap_object(zx, zy);
+                   change_made = TRUE;
+               }
+
+       return change_made;
+}
+
+/* look for gold, on the floor or in monsters' possession */
+int
+gold_detect(sobj)
+register struct obj *sobj;
+{
+    register struct obj *obj;
+    register struct monst *mtmp;
+    int uw = u.uinwater;
+    struct obj *temp;
+    boolean stale;
+
+    known = stale = clear_stale_map(COIN_CLASS,
+                               (unsigned)(sobj->blessed ? GOLD : 0));
+
+    /* look for gold carried by monsters (might be in a container) */
+    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+       if (DEADMONSTER(mtmp)) continue;        /* probably not needed in this case but... */
+#ifndef GOLDOBJ
+       if (mtmp->mgold || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
+#else
+       if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
+#endif
+           known = TRUE;
+           goto outgoldmap;    /* skip further searching */
+       } else for (obj = mtmp->minvent; obj; obj = obj->nobj)
+           if (sobj->blessed && o_material(obj, GOLD)) {
+               known = TRUE;
+               goto outgoldmap;
+           } else if (o_in(obj, COIN_CLASS)) {
+               known = TRUE;
+               goto outgoldmap;        /* skip further searching */
+           }
+    }
+    
+    /* look for gold objects */
+    for (obj = fobj; obj; obj = obj->nobj) {
+       if (sobj->blessed && o_material(obj, GOLD)) {
+           known = TRUE;
+           if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap;
+       } else if (o_in(obj, COIN_CLASS)) {
+           known = TRUE;
+           if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap;
+       }
+    }
+
+    if (!known) {
+       /* no gold found on floor or monster's inventory.
+          adjust message if you have gold in your inventory */
+       if (sobj) {
+               char buf[BUFSZ];
+               if (youmonst.data == &mons[PM_GOLD_GOLEM]) {
+                       Sprintf(buf, "You feel like a million %s!",
+                               currency(2L));
+               } else if (hidden_gold() ||
+#ifndef GOLDOBJ
+                               u.ugold)
+#else
+                               money_cnt(invent))
+#endif
+                       Strcpy(buf,
+                               "You feel worried about your future financial situation.");
+               else
+                       Strcpy(buf, "You feel materially poor.");
+               strange_feeling(sobj, buf);
+        }
+       return(1);
+    }
+    /* only under me - no separate display required */
+    if (stale) docrt();
+    You("notice some gold between your %s.", makeplural(body_part(FOOT)));
+    return(0);
+
+outgoldmap:
+    cls();
+
+    u.uinwater = 0;
+    /* Discover gold locations. */
+    for (obj = fobj; obj; obj = obj->nobj) {
+       if (sobj->blessed && (temp = o_material(obj, GOLD))) {
+           if (temp != obj) {
+               temp->ox = obj->ox;
+               temp->oy = obj->oy;
+           }
+           map_object(temp,1);
+       } else if ((temp = o_in(obj, COIN_CLASS))) {
+           if (temp != obj) {
+               temp->ox = obj->ox;
+               temp->oy = obj->oy;
+           }
+           map_object(temp,1);
+       }
+    }
+    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+       if (DEADMONSTER(mtmp)) continue;        /* probably overkill here */
+#ifndef GOLDOBJ
+       if (mtmp->mgold || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
+#else
+       if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
+#endif
+           struct obj gold;
+
+           gold.otyp = GOLD_PIECE;
+           gold.ox = mtmp->mx;
+           gold.oy = mtmp->my;
+           map_object(&gold,1);
+       } else for (obj = mtmp->minvent; obj; obj = obj->nobj)
+           if (sobj->blessed && (temp = o_material(obj, GOLD))) {
+               temp->ox = mtmp->mx;
+               temp->oy = mtmp->my;
+               map_object(temp,1);
+               break;
+           } else if ((temp = o_in(obj, COIN_CLASS))) {
+               temp->ox = mtmp->mx;
+               temp->oy = mtmp->my;
+               map_object(temp,1);
+               break;
+           }
+    }
+    
+    newsym(u.ux,u.uy);
+    You_feel("very greedy, and sense gold!");
+    exercise(A_WIS, TRUE);
+    display_nhwindow(WIN_MAP, TRUE);
+    docrt();
+    u.uinwater = uw;
+    if (Underwater) under_water(2);
+    if (u.uburied) under_ground(2);
+    return(0);
+}
+
+/* returns 1 if nothing was detected           */
+/* returns 0 if something was detected         */
+int
+food_detect(sobj)
+register struct obj    *sobj;
+{
+    register struct obj *obj;
+    register struct monst *mtmp;
+    register int ct = 0, ctu = 0;
+    boolean confused = (Confusion || (sobj && sobj->cursed)), stale;
+    char oclass = confused ? POTION_CLASS : FOOD_CLASS;
+    const char *what = confused ? something : "food";
+    int uw = u.uinwater;
+
+    stale = clear_stale_map(oclass, 0);
+
+    for (obj = fobj; obj; obj = obj->nobj)
+       if (o_in(obj, oclass)) {
+           if (obj->ox == u.ux && obj->oy == u.uy) ctu++;
+           else ct++;
+       }
+    for (mtmp = fmon; mtmp && !ct; mtmp = mtmp->nmon) {
+       /* no DEADMONSTER(mtmp) check needed since dmons never have inventory */
+       for (obj = mtmp->minvent; obj; obj = obj->nobj)
+           if (o_in(obj, oclass)) {
+               ct++;
+               break;
+           }
+    }
+    
+    if (!ct && !ctu) {
+       known = stale && !confused;
+       if (stale) {
+           docrt();
+           You("sense a lack of %s nearby.", what);
+           if (sobj && sobj->blessed) {
+               if (!u.uedibility) Your("%s starts to tingle.", body_part(NOSE));
+               u.uedibility = 1;
+           }
+       } else if (sobj) {
+           char buf[BUFSZ];
+           Sprintf(buf, "Your %s twitches%s.", body_part(NOSE),
+                       (sobj->blessed && !u.uedibility) ? " then starts to tingle" : "");
+           if (sobj->blessed && !u.uedibility) {
+               boolean savebeginner = flags.beginner;  /* prevent non-delivery of */
+               flags.beginner = FALSE;                 /*      message            */
+               strange_feeling(sobj, buf);
+               flags.beginner = savebeginner;
+               u.uedibility = 1;
+           } else
+               strange_feeling(sobj, buf);
+       }
+       return !stale;
+    } else if (!ct) {
+       known = TRUE;
+       You("%s %s nearby.", sobj ? "smell" : "sense", what);
+       if (sobj && sobj->blessed) {
+               if (!u.uedibility) pline("Your %s starts to tingle.", body_part(NOSE));
+               u.uedibility = 1;
+       }
+    } else {
+       struct obj *temp;
+       known = TRUE;
+       cls();
+       u.uinwater = 0;
+       for (obj = fobj; obj; obj = obj->nobj)
+           if ((temp = o_in(obj, oclass)) != 0) {
+               if (temp != obj) {
+                   temp->ox = obj->ox;
+                   temp->oy = obj->oy;
+               }
+               map_object(temp,1);
+           }
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+           /* no DEADMONSTER(mtmp) check needed since dmons never have inventory */
+           for (obj = mtmp->minvent; obj; obj = obj->nobj)
+               if ((temp = o_in(obj, oclass)) != 0) {
+                   temp->ox = mtmp->mx;
+                   temp->oy = mtmp->my;
+                   map_object(temp,1);
+                   break;      /* skip rest of this monster's inventory */
+               }
+       newsym(u.ux,u.uy);
+       if (sobj) {
+           if (sobj->blessed) {
+               Your("%s %s to tingle and you smell %s.", body_part(NOSE),
+                       u.uedibility ? "continues" : "starts", what);
+               u.uedibility = 1;
+           } else
+               Your("%s tingles and you smell %s.", body_part(NOSE), what);
+       }
+       else You("sense %s.", what);
+       display_nhwindow(WIN_MAP, TRUE);
+       exercise(A_WIS, TRUE);
+       docrt();
+       u.uinwater = uw;
+       if (Underwater) under_water(2);
+       if (u.uburied) under_ground(2);
+    }
+    return(0);
+}
+
+/*
+ * Used for scrolls, potions, spells, and crystal balls.  Returns:
+ *
+ *     1 - nothing was detected
+ *     0 - something was detected
+ */
+int
+object_detect(detector, class)
+struct obj     *detector;      /* object doing the detecting */
+int            class;          /* an object class, 0 for all */
+{
+    register int x, y;
+    char stuff[BUFSZ];
+    int is_cursed = (detector && detector->cursed);
+    int do_dknown = (detector && (detector->oclass == POTION_CLASS ||
+                                   detector->oclass == SPBOOK_CLASS) &&
+                       detector->blessed);
+    int ct = 0, ctu = 0;
+    register struct obj *obj, *otmp = (struct obj *)0;
+    register struct monst *mtmp;
+    int uw = u.uinwater;
+    int sym, boulder = 0;
+
+    if (class < 0 || class >= MAXOCLASSES) {
+       impossible("object_detect:  illegal class %d", class);
+       class = 0;
+    }
+
+    /* Special boulder symbol check - does the class symbol happen
+     * to match iflags.bouldersym which is a user-defined?
+     * If so, that means we aren't sure what they really wanted to
+     * detect. Rather than trump anything, show both possibilities.
+     * We can exclude checking the buried obj chain for boulders below.
+     */
+    sym = class ? def_oc_syms[class] : 0;
+    if (sym && iflags.bouldersym && sym == iflags.bouldersym)
+       boulder = ROCK_CLASS;
+
+    if (Hallucination || (Confusion && class == SCROLL_CLASS))
+       Strcpy(stuff, something);
+    else
+       Strcpy(stuff, class ? oclass_names[class] : "objects");
+    if (boulder && class != ROCK_CLASS) Strcat(stuff, " and/or large stones");
+
+    if (do_dknown) for(obj = invent; obj; obj = obj->nobj) do_dknown_of(obj);
+
+    for (obj = fobj; obj; obj = obj->nobj) {
+       if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) {
+           if (obj->ox == u.ux && obj->oy == u.uy) ctu++;
+           else ct++;
+       }
+       if (do_dknown) do_dknown_of(obj);
+    }
+
+    for (obj = level.buriedobjlist; obj; obj = obj->nobj) {
+       if (!class || o_in(obj, class)) {
+           if (obj->ox == u.ux && obj->oy == u.uy) ctu++;
+           else ct++;
+       }
+       if (do_dknown) do_dknown_of(obj);
+    }
+
+    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+       if (DEADMONSTER(mtmp)) continue;
+       for (obj = mtmp->minvent; obj; obj = obj->nobj) {
+           if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) ct++;
+           if (do_dknown) do_dknown_of(obj);
+       }
+       if ((is_cursed && mtmp->m_ap_type == M_AP_OBJECT &&
+           (!class || class == objects[mtmp->mappearance].oc_class)) ||
+#ifndef GOLDOBJ
+           (mtmp->mgold && (!class || class == COIN_CLASS))) {
+#else
+           (findgold(mtmp->minvent) && (!class || class == COIN_CLASS))) {
+#endif
+           ct++;
+           break;
+       }
+    }
+
+    if (!clear_stale_map(!class ? ALL_CLASSES : class, 0) && !ct) {
+       if (!ctu) {
+           if (detector)
+               strange_feeling(detector, "You feel a lack of something.");
+           return 1;
+       }
+
+       You("sense %s nearby.", stuff);
+       return 0;
+    }
+
+    cls();
+
+    u.uinwater = 0;
+/*
+ *     Map all buried objects first.
+ */
+    for (obj = level.buriedobjlist; obj; obj = obj->nobj)
+       if (!class || (otmp = o_in(obj, class))) {
+           if (class) {
+               if (otmp != obj) {
+                   otmp->ox = obj->ox;
+                   otmp->oy = obj->oy;
+               }
+               map_object(otmp, 1);
+           } else
+               map_object(obj, 1);
+       }
+    /*
+     * If we are mapping all objects, map only the top object of a pile or
+     * the first object in a monster's inventory.  Otherwise, go looking
+     * for a matching object class and display the first one encountered
+     * at each location.
+     *
+     * Objects on the floor override buried objects.
+     */
+    for (x = 1; x < COLNO; x++)
+       for (y = 0; y < ROWNO; y++)
+           for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
+               if ((!class && !boulder) ||
+                   (otmp = o_in(obj, class)) || (otmp = o_in(obj, boulder))) {
+                   if (class || boulder) {
+                       if (otmp != obj) {
+                           otmp->ox = obj->ox;
+                           otmp->oy = obj->oy;
+                       }
+                       map_object(otmp, 1);
+                   } else
+                       map_object(obj, 1);
+                   break;
+               }
+
+    /* Objects in the monster's inventory override floor objects. */
+    for (mtmp = fmon ; mtmp ; mtmp = mtmp->nmon) {
+       if (DEADMONSTER(mtmp)) continue;
+       for (obj = mtmp->minvent; obj; obj = obj->nobj)
+           if ((!class && !boulder) ||
+                (otmp = o_in(obj, class)) || (otmp = o_in(obj, boulder))) {
+               if (!class && !boulder) otmp = obj;
+               otmp->ox = mtmp->mx;            /* at monster location */
+               otmp->oy = mtmp->my;
+               map_object(otmp, 1);
+               break;
+           }
+       /* Allow a mimic to override the detected objects it is carrying. */
+       if (is_cursed && mtmp->m_ap_type == M_AP_OBJECT &&
+               (!class || class == objects[mtmp->mappearance].oc_class)) {
+           struct obj temp;
+
+           temp.otyp = mtmp->mappearance;      /* needed for obj_to_glyph() */
+           temp.ox = mtmp->mx;
+           temp.oy = mtmp->my;
+           temp.corpsenm = PM_TENGU;           /* if mimicing a corpse */
+           map_object(&temp, 1);
+#ifndef GOLDOBJ
+       } else if (mtmp->mgold && (!class || class == COIN_CLASS)) {
+#else
+       } else if (findgold(mtmp->minvent) && (!class || class == COIN_CLASS)) {
+#endif
+           struct obj gold;
+
+           gold.otyp = GOLD_PIECE;
+           gold.ox = mtmp->mx;
+           gold.oy = mtmp->my;
+           map_object(&gold, 1);
+       }
+    }
+
+    newsym(u.ux,u.uy);
+    You("detect the %s of %s.", ct ? "presence" : "absence", stuff);
+    display_nhwindow(WIN_MAP, TRUE);
+    /*
+     * What are we going to do when the hero does an object detect while blind
+     * and the detected object covers a known pool?
+     */
+    docrt();   /* this will correctly reset vision */
+
+    u.uinwater = uw;
+    if (Underwater) under_water(2);
+    if (u.uburied) under_ground(2);
+    return 0;
+}
+
+/*
+ * Used by: crystal balls, potions, fountains
+ *
+ * Returns 1 if nothing was detected.
+ * Returns 0 if something was detected.
+ */
+int
+monster_detect(otmp, mclass)
+register struct obj *otmp;     /* detecting object (if any) */
+int mclass;                    /* monster class, 0 for all */
+{
+    register struct monst *mtmp;
+    int mcnt = 0;
+
+
+    /* Note: This used to just check fmon for a non-zero value
+     * but in versions since 3.3.0 fmon can test TRUE due to the
+     * presence of dmons, so we have to find at least one
+     * with positive hit-points to know for sure.
+     */
+    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+       if (!DEADMONSTER(mtmp)) {
+               mcnt++;
+               break;
+       }
+
+    if (!mcnt) {
+       if (otmp)
+           strange_feeling(otmp, Hallucination ?
+                           "You get the heebie jeebies." :
+                           "You feel threatened.");
+       return 1;
+    } else {
+       boolean woken = FALSE;
+
+       cls();
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+           if (DEADMONSTER(mtmp)) continue;
+           if (!mclass || mtmp->data->mlet == mclass ||
+               (mtmp->data == &mons[PM_LONG_WORM] && mclass == S_WORM_TAIL))
+                   if (mtmp->mx > 0) {
+                       if (mclass && def_monsyms[mclass] == ' ')
+                               show_glyph(mtmp->mx,mtmp->my,
+                                       detected_mon_to_glyph(mtmp));
+                       else
+                               show_glyph(mtmp->mx,mtmp->my,mon_to_glyph(mtmp));
+                       /* don't be stingy - display entire worm */
+                       if (mtmp->data == &mons[PM_LONG_WORM]) detect_wsegs(mtmp,0);
+                   }
+           if (otmp && otmp->cursed &&
+               (mtmp->msleeping || !mtmp->mcanmove)) {
+               mtmp->msleeping = mtmp->mfrozen = 0;
+               mtmp->mcanmove = 1;
+               woken = TRUE;
+           }
+       }
+       display_self();
+       You("sense the presence of monsters.");
+       if (woken)
+           pline("Monsters sense the presence of you.");
+       display_nhwindow(WIN_MAP, TRUE);
+       docrt();
+       if (Underwater) under_water(2);
+       if (u.uburied) under_ground(2);
+    }
+    return 0;
+}
+
+STATIC_OVL void
+sense_trap(trap, x, y, src_cursed)
+struct trap *trap;
+xchar x, y;
+int src_cursed;
+{
+    if (Hallucination || src_cursed) {
+       struct obj obj;                 /* fake object */
+       if (trap) {
+           obj.ox = trap->tx;
+           obj.oy = trap->ty;
+       } else {
+           obj.ox = x;
+           obj.oy = y;
+       }
+       obj.otyp = (src_cursed) ? GOLD_PIECE : random_object();
+       obj.corpsenm = random_monster();        /* if otyp == CORPSE */
+       map_object(&obj,1);
+    } else if (trap) {
+       map_trap(trap,1);
+       trap->tseen = 1;
+    } else {
+       struct trap temp_trap;          /* fake trap */
+       temp_trap.tx = x;
+       temp_trap.ty = y;
+       temp_trap.ttyp = BEAR_TRAP;     /* some kind of trap */
+       map_trap(&temp_trap,1);
+    }
+
+}
+
+/* the detections are pulled out so they can   */
+/* also be used in the crystal ball routine    */
+/* returns 1 if nothing was detected           */
+/* returns 0 if something was detected         */
+int
+trap_detect(sobj)
+register struct obj *sobj;
+/* sobj is null if crystal ball, *scroll if gold detection scroll */
+{
+    register struct trap *ttmp;
+    register struct obj *obj;
+    register int door;
+    int uw = u.uinwater;
+    boolean found = FALSE;
+    coord cc;
+
+    for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
+       if (ttmp->tx != u.ux || ttmp->ty != u.uy)
+           goto outtrapmap;
+       else found = TRUE;
+    }
+    for (obj = fobj; obj; obj = obj->nobj) {
+       if ((obj->otyp==LARGE_BOX || obj->otyp==CHEST) && obj->otrapped) {
+           if (obj->ox != u.ux || obj->oy != u.uy)
+               goto outtrapmap;
+           else found = TRUE;
+       }
+    }
+    for (door = 0; door < doorindex; door++) {
+       cc = doors[door];
+       if (levl[cc.x][cc.y].doormask & D_TRAPPED) {
+           if (cc.x != u.ux || cc.y != u.uy)
+               goto outtrapmap;
+           else found = TRUE;
+       }
+    }
+    if (!found) {
+       char buf[42];
+       Sprintf(buf, "Your %s stop itching.", makeplural(body_part(TOE)));
+       strange_feeling(sobj,buf);
+       return(1);
+    }
+    /* traps exist, but only under me - no separate display required */
+    Your("%s itch.", makeplural(body_part(TOE)));
+    return(0);
+outtrapmap:
+    cls();
+
+    u.uinwater = 0;
+    for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
+       sense_trap(ttmp, 0, 0, sobj && sobj->cursed);
+
+    for (obj = fobj; obj; obj = obj->nobj)
+       if ((obj->otyp==LARGE_BOX || obj->otyp==CHEST) && obj->otrapped)
+       sense_trap((struct trap *)0, obj->ox, obj->oy, sobj && sobj->cursed);
+
+    for (door = 0; door < doorindex; door++) {
+       cc = doors[door];
+       if (levl[cc.x][cc.y].doormask & D_TRAPPED)
+       sense_trap((struct trap *)0, cc.x, cc.y, sobj && sobj->cursed);
+    }
+
+    newsym(u.ux,u.uy);
+    You_feel("%s.", sobj && sobj->cursed ? "very greedy" : "entrapped");
+    display_nhwindow(WIN_MAP, TRUE);
+    docrt();
+    u.uinwater = uw;
+    if (Underwater) under_water(2);
+    if (u.uburied) under_ground(2);
+    return(0);
+}
+
+const char *
+level_distance(where)
+d_level *where;
+{
+    register schar ll = depth(&u.uz) - depth(where);
+    register boolean indun = (u.uz.dnum == where->dnum);
+
+    if (ll < 0) {
+       if (ll < (-8 - rn2(3)))
+           if (!indun) return "far away";
+           else        return "far below";
+       else if (ll < -1)
+           if (!indun) return "away below you";
+           else        return "below you";
+       else
+           if (!indun) return "in the distance";
+           else        return "just below";
+    } else if (ll > 0) {
+       if (ll > (8 + rn2(3)))
+           if (!indun) return "far away";
+           else        return "far above";
+       else if (ll > 1)
+           if (!indun) return "away above you";
+           else        return "above you";
+       else
+           if (!indun) return "in the distance";
+           else        return "just above";
+    } else
+           if (!indun) return "in the distance";
+           else        return "near you";
+}
+
+static const struct {
+    const char *what;
+    d_level *where;
+} level_detects[] = {
+  { "Delphi", &oracle_level },
+  { "Medusa's lair", &medusa_level },
+  { "a castle", &stronghold_level },
+  { "the Wizard of Yendor's tower", &wiz1_level },
+};
+
+void
+use_crystal_ball(obj)
+struct obj *obj;
+{
+    char ch;
+    int oops;
+
+    if (Blind) {
+       pline("Too bad you can't see %s.", the(xname(obj)));
+       return;
+    }
+    oops = (rnd(20) > ACURR(A_INT) || obj->cursed);
+    if (oops && (obj->spe > 0)) {
+       switch (rnd(obj->oartifact ? 4 : 5)) {
+       case 1 : pline("%s too much to comprehend!", Tobjnam(obj, "are"));
+           break;
+       case 2 : pline("%s you!", Tobjnam(obj, "confuse"));
+           make_confused(HConfusion + rnd(100),FALSE);
+           break;
+       case 3 : if (!resists_blnd(&youmonst)) {
+               pline("%s your vision!", Tobjnam(obj, "damage"));
+               make_blinded(Blinded + rnd(100),FALSE);
+               if (!Blind) Your(vision_clears);
+           } else {
+               pline("%s your vision.", Tobjnam(obj, "assault"));
+               You("are unaffected!");
+           }
+           break;
+       case 4 : pline("%s your mind!", Tobjnam(obj, "zap"));
+           (void) make_hallucinated(HHallucination + rnd(100),FALSE,0L);
+           break;
+       case 5 : pline("%s!", Tobjnam(obj, "explode"));
+           useup(obj);
+           obj = 0;    /* it's gone */
+           losehp(rnd(30), "exploding crystal ball", KILLED_BY_AN);
+           break;
+       }
+       if (obj) consume_obj_charge(obj, TRUE);
+       return;
+    }
+
+    if (Hallucination) {
+       if (!obj->spe) {
+           pline("All you see is funky %s haze.", hcolor((char *)0));
+       } else {
+           switch(rnd(6)) {
+           case 1 : You("grok some groovy globs of incandescent lava.");
+               break;
+           case 2 : pline("Whoa!  Psychedelic colors, %s!",
+                          poly_gender() == 1 ? "babe" : "dude");
+               break;
+           case 3 : pline_The("crystal pulses with sinister %s light!",
+                               hcolor((char *)0));
+               break;
+           case 4 : You("see goldfish swimming above fluorescent rocks.");
+               break;
+           case 5 : You("see tiny snowflakes spinning around a miniature farmhouse.");
+               break;
+           default: pline("Oh wow... like a kaleidoscope!");
+               break;
+           }
+           consume_obj_charge(obj, TRUE);
+       }
+       return;
+    }
+
+    /* read a single character */
+    if (flags.verbose) You("may look for an object or monster symbol.");
+    ch = yn_function("What do you look for?", (char *)0, '\0');
+    /* Don't filter out ' ' here; it has a use */
+    if ((ch != def_monsyms[S_GHOST]) && index(quitchars,ch)) { 
+       if (flags.verbose) pline(Never_mind);
+       return;
+    }
+    You("peer into %s...", the(xname(obj)));
+    nomul(-rnd(10));
+    nomovemsg = "";
+    if (obj->spe <= 0)
+       pline_The("vision is unclear.");
+    else {
+       int class;
+       int ret = 0;
+
+       makeknown(CRYSTAL_BALL);
+       consume_obj_charge(obj, TRUE);
+
+       /* special case: accept ']' as synonym for mimic
+        * we have to do this before the def_char_to_objclass check
+        */
+       if (ch == DEF_MIMIC_DEF) ch = DEF_MIMIC;
+
+       if ((class = def_char_to_objclass(ch)) != MAXOCLASSES)
+               ret = object_detect((struct obj *)0, class);
+       else if ((class = def_char_to_monclass(ch)) != MAXMCLASSES)
+               ret = monster_detect((struct obj *)0, class);
+       else if (iflags.bouldersym && (ch == iflags.bouldersym))
+               ret = object_detect((struct obj *)0, ROCK_CLASS);
+       else switch(ch) {
+               case '^':
+                   ret = trap_detect((struct obj *)0);
+                   break;
+               default:
+                   {
+                   int i = rn2(SIZE(level_detects));
+                   You("see %s, %s.",
+                       level_detects[i].what,
+                       level_distance(level_detects[i].where));
+                   }
+                   ret = 0;
+                   break;
+       }
+
+       if (ret) {
+           if (!rn2(100))  /* make them nervous */
+               You("see the Wizard of Yendor gazing out at you.");
+           else pline_The("vision is unclear.");
+       }
+    }
+    return;
+}
+
+STATIC_OVL void
+show_map_spot(x, y)
+register int x, y;
+{
+    register struct rm *lev;
+
+    if (Confusion && rn2(7)) return;
+    lev = &levl[x][y];
+
+    lev->seenv = SVALL;
+
+    /* Secret corridors are found, but not secret doors. */
+    if (lev->typ == SCORR) {
+       lev->typ = CORR;
+       unblock_point(x,y);
+    }
+
+    /* if we don't remember an object or trap there, map it */
+    if (lev->typ == ROOM ?
+           (glyph_is_cmap(lev->glyph) && !glyph_is_trap(lev->glyph) &&
+               glyph_to_cmap(lev->glyph) != ROOM) :
+           (!glyph_is_object(lev->glyph) && !glyph_is_trap(lev->glyph))) {
+       if (level.flags.hero_memory) {
+           magic_map_background(x,y,0);
+           newsym(x,y);                        /* show it, if not blocked */
+       } else {
+           magic_map_background(x,y,1);        /* display it */
+       }
+    }
+}
+
+void
+do_mapping()
+{
+    register int zx, zy;
+    int uw = u.uinwater;
+
+    u.uinwater = 0;
+    for (zx = 1; zx < COLNO; zx++)
+       for (zy = 0; zy < ROWNO; zy++)
+           show_map_spot(zx, zy);
+    exercise(A_WIS, TRUE);
+    u.uinwater = uw;
+    if (!level.flags.hero_memory || Underwater) {
+       flush_screen(1);                        /* flush temp screen */
+       display_nhwindow(WIN_MAP, TRUE);        /* wait */
+       docrt();
+    }
+}
+
+void
+do_vicinity_map()
+{
+    register int zx, zy;
+    int lo_y = (u.uy-5 < 0 ? 0 : u.uy-5),
+       hi_y = (u.uy+6 > ROWNO ? ROWNO : u.uy+6),
+       lo_x = (u.ux-9 < 1 ? 1 : u.ux-9),       /* avoid column 0 */
+       hi_x = (u.ux+10 > COLNO ? COLNO : u.ux+10);
+
+    for (zx = lo_x; zx < hi_x; zx++)
+       for (zy = lo_y; zy < hi_y; zy++)
+           show_map_spot(zx, zy);
+
+    if (!level.flags.hero_memory || Underwater) {
+       flush_screen(1);                        /* flush temp screen */
+       display_nhwindow(WIN_MAP, TRUE);        /* wait */
+       docrt();
+    }
+}
+
+/* convert a secret door into a normal door */
+void
+cvt_sdoor_to_door(lev)
+struct rm *lev;
+{
+       int newmask = lev->doormask & ~WM_MASK;
+
+#ifdef REINCARNATION
+       if (Is_rogue_level(&u.uz))
+           /* rogue didn't have doors, only doorways */
+           newmask = D_NODOOR;
+       else
+#endif
+           /* newly exposed door is closed */
+           if (!(newmask & D_LOCKED)) newmask |= D_CLOSED;
+
+       lev->typ = DOOR;
+       lev->doormask = newmask;
+}
+
+
+STATIC_PTR void
+findone(zx,zy,num)
+int zx,zy;
+genericptr_t num;
+{
+       register struct trap *ttmp;
+       register struct monst *mtmp;
+
+       if(levl[zx][zy].typ == SDOOR) {
+               cvt_sdoor_to_door(&levl[zx][zy]);       /* .typ = DOOR */
+               magic_map_background(zx, zy, 0);
+               newsym(zx, zy);
+               (*(int*)num)++;
+       } else if(levl[zx][zy].typ == SCORR) {
+               levl[zx][zy].typ = CORR;
+               unblock_point(zx,zy);
+               magic_map_background(zx, zy, 0);
+               newsym(zx, zy);
+               (*(int*)num)++;
+       } else if ((ttmp = t_at(zx, zy)) != 0) {
+               if(!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) {
+                       ttmp->tseen = 1;
+                       newsym(zx,zy);
+                       (*(int*)num)++;
+               }
+       } else if ((mtmp = m_at(zx, zy)) != 0) {
+               if(mtmp->m_ap_type) {
+                       seemimic(mtmp);
+                       (*(int*)num)++;
+               }
+               if (mtmp->mundetected &&
+                   (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL)) {
+                       mtmp->mundetected = 0;
+                       newsym(zx, zy);
+                       (*(int*)num)++;
+               }
+               if (!canspotmon(mtmp) &&
+                                   !glyph_is_invisible(levl[zx][zy].glyph))
+                       map_invisible(zx, zy);
+       } else if (glyph_is_invisible(levl[zx][zy].glyph)) {
+               unmap_object(zx, zy);
+               newsym(zx, zy);
+               (*(int*)num)++;
+       }
+}
+
+STATIC_PTR void
+openone(zx,zy,num)
+int zx,zy;
+genericptr_t num;
+{
+       register struct trap *ttmp;
+       register struct obj *otmp;
+
+       if(OBJ_AT(zx, zy)) {
+               for(otmp = level.objects[zx][zy];
+                               otmp; otmp = otmp->nexthere) {
+                   if(Is_box(otmp) && otmp->olocked) {
+                       otmp->olocked = 0;
+                       (*(int*)num)++;
+                   }
+               }
+               /* let it fall to the next cases. could be on trap. */
+       }
+       if(levl[zx][zy].typ == SDOOR || (levl[zx][zy].typ == DOOR &&
+                     (levl[zx][zy].doormask & (D_CLOSED|D_LOCKED)))) {
+               if(levl[zx][zy].typ == SDOOR)
+                   cvt_sdoor_to_door(&levl[zx][zy]);   /* .typ = DOOR */
+               if(levl[zx][zy].doormask & D_TRAPPED) {
+                   if(distu(zx, zy) < 3) b_trapped("door", 0);
+                   else Norep("You %s an explosion!",
+                               cansee(zx, zy) ? "see" :
+                                  (flags.soundok ? "hear" :
+                                               "feel the shock of"));
+                   wake_nearto(zx, zy, 11*11);
+                   levl[zx][zy].doormask = D_NODOOR;
+               } else
+                   levl[zx][zy].doormask = D_ISOPEN;
+               unblock_point(zx, zy);
+               newsym(zx, zy);
+               (*(int*)num)++;
+       } else if(levl[zx][zy].typ == SCORR) {
+               levl[zx][zy].typ = CORR;
+               unblock_point(zx, zy);
+               newsym(zx, zy);
+               (*(int*)num)++;
+       } else if ((ttmp = t_at(zx, zy)) != 0) {
+               if (!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) {
+                   ttmp->tseen = 1;
+                   newsym(zx,zy);
+                   (*(int*)num)++;
+               }
+       } else if (find_drawbridge(&zx, &zy)) {
+               /* make sure it isn't an open drawbridge */
+               open_drawbridge(zx, zy);
+               (*(int*)num)++;
+       }
+}
+
+int
+findit()       /* returns number of things found */
+{
+       int num = 0;
+
+       if(u.uswallow) return(0);
+       do_clear_area(u.ux, u.uy, BOLT_LIM, findone, (genericptr_t) &num);
+       return(num);
+}
+
+int
+openit()       /* returns number of things found and opened */
+{
+       int num = 0;
+
+       if(u.uswallow) {
+               if (is_animal(u.ustuck->data)) {
+                       if (Blind) pline("Its mouth opens!");
+                       else pline("%s opens its mouth!", Monnam(u.ustuck));
+               }
+               expels(u.ustuck, u.ustuck->data, TRUE);
+               return(-1);
+       }
+
+       do_clear_area(u.ux, u.uy, BOLT_LIM, openone, (genericptr_t) &num);
+       return(num);
+}
+
+void
+find_trap(trap)
+struct trap *trap;
+{
+    int tt = what_trap(trap->ttyp);
+    boolean cleared = FALSE;
+
+    trap->tseen = 1;
+    exercise(A_WIS, TRUE);
+    if (Blind)
+       feel_location(trap->tx, trap->ty);
+    else
+       newsym(trap->tx, trap->ty);
+
+    if (levl[trap->tx][trap->ty].glyph != trap_to_glyph(trap)) {
+       /* There's too much clutter to see your find otherwise */
+       cls();
+       map_trap(trap, 1);
+       display_self();
+       cleared = TRUE;
+    }
+
+    You("find %s.", an(defsyms[trap_to_defsym(tt)].explanation));
+
+    if (cleared) {
+       display_nhwindow(WIN_MAP, TRUE);        /* wait */
+       docrt();
+    }
+}
+
+int
+dosearch0(aflag)
+register int aflag;
+{
+#ifdef GCC_BUG
+/* some versions of gcc seriously muck up nested loops. if you get strange
+   crashes while searching in a version compiled with gcc, try putting
+   #define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in the
+   makefile).
+ */
+       volatile xchar x, y;
+#else
+       register xchar x, y;
+#endif
+       register struct trap *trap;
+       register struct monst *mtmp;
+
+       if(u.uswallow) {
+               if (!aflag)
+                       pline("What are you looking for?  The exit?");
+       } else {
+           int fund = (uwep && uwep->oartifact &&
+                   spec_ability(uwep, SPFX_SEARCH)) ?
+                   uwep->spe : 0;
+           if (ublindf && ublindf->otyp == LENSES && !Blind)
+                   fund += 2; /* JDS: lenses help searching */
+           if (fund > 5) fund = 5;
+           for(x = u.ux-1; x < u.ux+2; x++)
+             for(y = u.uy-1; y < u.uy+2; y++) {
+               if(!isok(x,y)) continue;
+               if(x != u.ux || y != u.uy) {
+                   if (Blind && !aflag) feel_location(x,y);
+                   if(levl[x][y].typ == SDOOR) {
+                       if(rnl(7-fund)) continue;
+                       cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */
+                       exercise(A_WIS, TRUE);
+                       nomul(0);
+                       if (Blind && !aflag)
+                           feel_location(x,y); /* make sure it shows up */
+                       else
+                           newsym(x,y);
+                   } else if(levl[x][y].typ == SCORR) {
+                       if(rnl(7-fund)) continue;
+                       levl[x][y].typ = CORR;
+                       unblock_point(x,y);     /* vision */
+                       exercise(A_WIS, TRUE);
+                       nomul(0);
+                       newsym(x,y);
+                   } else {
+               /* Be careful not to find anything in an SCORR or SDOOR */
+                       if((mtmp = m_at(x, y)) && !aflag) {
+                           if(mtmp->m_ap_type) {
+                               seemimic(mtmp);
+               find:           exercise(A_WIS, TRUE);
+                               if (!canspotmon(mtmp)) {
+                                   if (glyph_is_invisible(levl[x][y].glyph)) {
+                                       /* found invisible monster in a square
+                                        * which already has an 'I' in it.
+                                        * Logically, this should still take
+                                        * time and lead to a return(1), but if
+                                        * we did that the player would keep
+                                        * finding the same monster every turn.
+                                        */
+                                       continue;
+                                   } else {
+                                       You_feel("an unseen monster!");
+                                       map_invisible(x, y);
+                                   }
+                               } else if (!sensemon(mtmp))
+                                   You("find %s.", a_monnam(mtmp));
+                               return(1);
+                           }
+                           if(!canspotmon(mtmp)) {
+                               if (mtmp->mundetected &&
+                                  (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL))
+                                       mtmp->mundetected = 0;
+                               newsym(x,y);
+                               goto find;
+                           }
+                       }
+
+                       /* see if an invisible monster has moved--if Blind,
+                        * feel_location() already did it
+                        */
+                       if (!aflag && !mtmp && !Blind &&
+                                   glyph_is_invisible(levl[x][y].glyph)) {
+                           unmap_object(x,y);
+                           newsym(x,y);
+                       }
+
+                       if ((trap = t_at(x,y)) && !trap->tseen && !rnl(8)) {
+                           nomul(0);
+
+                           if (trap->ttyp == STATUE_TRAP) {
+                               if (activate_statue_trap(trap, x, y, FALSE))
+                                   exercise(A_WIS, TRUE);
+                               return(1);
+                           } else {
+                               find_trap(trap);
+                           }
+                       }
+                   }
+               }
+           }
+       }
+       return(1);
+}
+
+int
+dosearch()
+{
+       return(dosearch0(0));
+}
+
+/* Pre-map the sokoban levels */
+void
+sokoban_detect()
+{
+       register int x, y;
+       register struct trap *ttmp;
+       register struct obj *obj;
+
+       /* Map the background and boulders */
+       for (x = 1; x < COLNO; x++)
+           for (y = 0; y < ROWNO; y++) {
+               levl[x][y].seenv = SVALL;
+               levl[x][y].waslit = TRUE;
+               map_background(x, y, 1);
+               for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
+                   if (obj->otyp == BOULDER)
+                       map_object(obj, 1);
+           }
+
+       /* Map the traps */
+       for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
+           ttmp->tseen = 1;
+           map_trap(ttmp, 1);
+       }
+}
+
+
+/*detect.c*/
diff --git a/src/dig.c b/src/dig.c
new file mode 100644 (file)
index 0000000..4c40a59
--- /dev/null
+++ b/src/dig.c
@@ -0,0 +1,1571 @@
+/*     SCCS Id: @(#)dig.c      3.4     2003/03/23      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "edog.h"
+/* #define DEBUG */    /* turn on for diagnostics */
+
+#ifdef OVLB
+
+static NEARDATA boolean did_dig_msg;
+
+STATIC_DCL boolean NDECL(rm_waslit);
+STATIC_DCL void FDECL(mkcavepos, (XCHAR_P,XCHAR_P,int,BOOLEAN_P,BOOLEAN_P));
+STATIC_DCL void FDECL(mkcavearea, (BOOLEAN_P));
+STATIC_DCL int FDECL(dig_typ, (struct obj *,XCHAR_P,XCHAR_P));
+STATIC_DCL int NDECL(dig);
+STATIC_DCL schar FDECL(fillholetyp, (int, int));
+STATIC_DCL void NDECL(dig_up_grave);
+
+/* Indices returned by dig_typ() */
+#define DIGTYP_UNDIGGABLE 0
+#define DIGTYP_ROCK       1
+#define DIGTYP_STATUE     2
+#define DIGTYP_BOULDER    3
+#define DIGTYP_DOOR       4
+#define DIGTYP_TREE       5
+
+
+STATIC_OVL boolean
+rm_waslit()
+{
+    register xchar x, y;
+
+    if(levl[u.ux][u.uy].typ == ROOM && levl[u.ux][u.uy].waslit)
+       return(TRUE);
+    for(x = u.ux-2; x < u.ux+3; x++)
+       for(y = u.uy-1; y < u.uy+2; y++)
+           if(isok(x,y) && levl[x][y].waslit) return(TRUE);
+    return(FALSE);
+}
+
+/* Change level topology.  Messes with vision tables and ignores things like
+ * boulders in the name of a nice effect.  Vision will get fixed up again
+ * immediately after the effect is complete.
+ */
+STATIC_OVL void
+mkcavepos(x, y, dist, waslit, rockit)
+    xchar x,y;
+    int dist;
+    boolean waslit, rockit;
+{
+    register struct rm *lev;
+
+    if(!isok(x,y)) return;
+    lev = &levl[x][y];
+
+    if(rockit) {
+       register struct monst *mtmp;
+
+       if(IS_ROCK(lev->typ)) return;
+       if(t_at(x, y)) return; /* don't cover the portal */
+       if ((mtmp = m_at(x, y)) != 0)   /* make sure crucial monsters survive */
+           if(!passes_walls(mtmp->data)) (void) rloc(mtmp, FALSE);
+    } else if(lev->typ == ROOM) return;
+
+    unblock_point(x,y);        /* make sure vision knows this location is open */
+
+    /* fake out saved state */
+    lev->seenv = 0;
+    lev->doormask = 0;
+    if(dist < 3) lev->lit = (rockit ? FALSE : TRUE);
+    if(waslit) lev->waslit = (rockit ? FALSE : TRUE);
+    lev->horizontal = FALSE;
+    viz_array[y][x] = (dist < 3 ) ?
+       (IN_SIGHT|COULD_SEE) : /* short-circuit vision recalc */
+       COULD_SEE;
+    lev->typ = (rockit ? STONE : ROOM);
+    if(dist >= 3)
+       impossible("mkcavepos called with dist %d", dist);
+    if(Blind)
+       feel_location(x, y);
+    else newsym(x,y);
+}
+
+STATIC_OVL void
+mkcavearea(rockit)
+register boolean rockit;
+{
+    int dist;
+    xchar xmin = u.ux, xmax = u.ux;
+    xchar ymin = u.uy, ymax = u.uy;
+    register xchar i;
+    register boolean waslit = rm_waslit();
+
+    if(rockit) pline("Crash!  The ceiling collapses around you!");
+    else pline("A mysterious force %s cave around you!",
+            (levl[u.ux][u.uy].typ == CORR) ? "creates a" : "extends the");
+    display_nhwindow(WIN_MESSAGE, TRUE);
+
+    for(dist = 1; dist <= 2; dist++) {
+       xmin--; xmax++;
+
+       /* top and bottom */
+       if(dist < 2) { /* the area is wider that it is high */
+           ymin--; ymax++;
+           for(i = xmin+1; i < xmax; i++) {
+               mkcavepos(i, ymin, dist, waslit, rockit);
+               mkcavepos(i, ymax, dist, waslit, rockit);
+           }
+       }
+
+       /* left and right */
+       for(i = ymin; i <= ymax; i++) {
+           mkcavepos(xmin, i, dist, waslit, rockit);
+           mkcavepos(xmax, i, dist, waslit, rockit);
+       }
+
+       flush_screen(1);        /* make sure the new glyphs shows up */
+       delay_output();
+    }
+
+    if(!rockit && levl[u.ux][u.uy].typ == CORR) {
+       levl[u.ux][u.uy].typ = ROOM;
+       if(waslit) levl[u.ux][u.uy].waslit = TRUE;
+       newsym(u.ux, u.uy); /* in case player is invisible */
+    }
+
+    vision_full_recalc = 1;    /* everything changed */
+}
+
+/* When digging into location <x,y>, what are you actually digging into? */
+STATIC_OVL int
+dig_typ(otmp, x, y)
+struct obj *otmp;
+xchar x, y;
+{
+       boolean ispick = is_pick(otmp);
+
+       return (ispick && sobj_at(STATUE, x, y) ? DIGTYP_STATUE :
+               ispick && sobj_at(BOULDER, x, y) ? DIGTYP_BOULDER :
+               closed_door(x, y) ? DIGTYP_DOOR :
+               IS_TREE(levl[x][y].typ) ?
+                       (ispick ? DIGTYP_UNDIGGABLE : DIGTYP_TREE) :
+               ispick && IS_ROCK(levl[x][y].typ) &&
+                       (!level.flags.arboreal || IS_WALL(levl[x][y].typ)) ?
+                       DIGTYP_ROCK : DIGTYP_UNDIGGABLE);
+}
+
+boolean
+is_digging()
+{
+       if (occupation == dig) {
+           return TRUE;
+       }
+       return FALSE;
+}
+
+#define BY_YOU         (&youmonst)
+#define BY_OBJECT      ((struct monst *)0)
+
+boolean
+dig_check(madeby, verbose, x, y)
+       struct monst    *madeby;
+       boolean         verbose;
+       int             x, y;
+{
+       struct trap *ttmp = t_at(x, y);
+       const char *verb = (madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in";
+
+       if (On_stairs(x, y)) {
+           if (x == xdnladder || x == xupladder) {
+               if(verbose) pline_The("ladder resists your effort.");
+           } else if(verbose) pline_The("stairs are too hard to %s.", verb);
+           return(FALSE);
+       } else if (IS_THRONE(levl[x][y].typ) && madeby != BY_OBJECT) {
+           if(verbose) pline_The("throne is too hard to break apart.");
+           return(FALSE);
+       } else if (IS_ALTAR(levl[x][y].typ) && (madeby != BY_OBJECT ||
+                               Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) {
+           if(verbose) pline_The("altar is too hard to break apart.");
+           return(FALSE);
+       } else if (Is_airlevel(&u.uz)) {
+           if(verbose) You("cannot %s thin air.", verb);
+           return(FALSE);
+       } else if (Is_waterlevel(&u.uz)) {
+           if(verbose) pline_The("water splashes and subsides.");
+           return(FALSE);
+       } else if ((IS_ROCK(levl[x][y].typ) && levl[x][y].typ != SDOOR &&
+                     (levl[x][y].wall_info & W_NONDIGGABLE) != 0)
+               || (ttmp &&
+                     (ttmp->ttyp == MAGIC_PORTAL || !Can_dig_down(&u.uz)))) {
+           if(verbose) pline_The("%s here is too hard to %s.",
+                                 surface(x,y), verb);
+           return(FALSE);
+       } else if (sobj_at(BOULDER, x, y)) {
+           if(verbose) There("isn't enough room to %s here.", verb);
+           return(FALSE);
+       } else if (madeby == BY_OBJECT &&
+                   /* the block against existing traps is mainly to
+                      prevent broken wands from turning holes into pits */
+                   (ttmp || is_pool(x,y) || is_lava(x,y))) {
+           /* digging by player handles pools separately */
+           return FALSE;
+       }
+       return(TRUE);
+}
+
+STATIC_OVL int
+dig()
+{
+       register struct rm *lev;
+       register xchar dpx = digging.pos.x, dpy = digging.pos.y;
+       register boolean ispick = uwep && is_pick(uwep);
+       const char *verb =
+           (!uwep || is_pick(uwep)) ? "dig into" : "chop through";
+
+       lev = &levl[dpx][dpy];
+       /* perhaps a nymph stole your pick-axe while you were busy digging */
+       /* or perhaps you teleported away */
+       if (u.uswallow || !uwep || (!ispick && !is_axe(uwep)) ||
+           !on_level(&digging.level, &u.uz) ||
+           ((digging.down ? (dpx != u.ux || dpy != u.uy)
+                          : (distu(dpx,dpy) > 2))))
+               return(0);
+
+       if (digging.down) {
+           if(!dig_check(BY_YOU, TRUE, u.ux, u.uy)) return(0);
+       } else { /* !digging.down */
+           if (IS_TREE(lev->typ) && !may_dig(dpx,dpy) &&
+                       dig_typ(uwep, dpx, dpy) == DIGTYP_TREE) {
+               pline("This tree seems to be petrified.");
+               return(0);
+           }
+           if (IS_ROCK(lev->typ) && !may_dig(dpx,dpy) &&
+                       dig_typ(uwep, dpx, dpy) == DIGTYP_ROCK) {
+               pline("This wall is too hard to %s.", verb);
+               return(0);
+           }
+       }
+       if(Fumbling && !rn2(3)) {
+           switch(rn2(3)) {
+           case 0:
+               if(!welded(uwep)) {
+                   You("fumble and drop your %s.", xname(uwep));
+                   dropx(uwep);
+               } else {
+#ifdef STEED
+                   if (u.usteed)
+                       Your("%s %s and %s %s!",
+                            xname(uwep),
+                            otense(uwep, "bounce"), otense(uwep, "hit"),
+                            mon_nam(u.usteed));
+                   else
+#endif
+                       pline("Ouch!  Your %s %s and %s you!",
+                             xname(uwep),
+                             otense(uwep, "bounce"), otense(uwep, "hit"));
+                   set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
+               }
+               break;
+           case 1:
+               pline("Bang!  You hit with the broad side of %s!",
+                     the(xname(uwep)));
+               break;
+           default: Your("swing misses its mark.");
+               break;
+           }
+           return(0);
+       }
+
+       digging.effort += 10 + rn2(5) + abon() +
+                          uwep->spe - greatest_erosion(uwep) + u.udaminc;
+       if (Race_if(PM_DWARF))
+           digging.effort *= 2;
+       if (digging.down) {
+               register struct trap *ttmp;
+
+               if (digging.effort > 250) {
+                   (void) dighole(FALSE);
+                   (void) memset((genericptr_t)&digging, 0, sizeof digging);
+                   return(0);  /* done with digging */
+               }
+
+               if (digging.effort <= 50 ||
+                   ((ttmp = t_at(dpx,dpy)) != 0 &&
+                       (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT ||
+                        ttmp->ttyp == TRAPDOOR || ttmp->ttyp == HOLE)))
+                   return(1);
+
+               if (IS_ALTAR(lev->typ)) {
+                   altar_wrath(dpx, dpy);
+                   angry_priest();
+               }
+
+               if (dighole(TRUE)) {    /* make pit at <u.ux,u.uy> */
+                   digging.level.dnum = 0;
+                   digging.level.dlevel = -1;
+               }
+               return(0);
+       }
+
+       if (digging.effort > 100) {
+               register const char *digtxt, *dmgtxt = (const char*) 0;
+               register struct obj *obj;
+               register boolean shopedge = *in_rooms(dpx, dpy, SHOPBASE);
+
+               if ((obj = sobj_at(STATUE, dpx, dpy)) != 0) {
+                       if (break_statue(obj))
+                               digtxt = "The statue shatters.";
+                       else
+                               /* it was a statue trap; break_statue()
+                                * printed a message and updated the screen
+                                */
+                               digtxt = (char *)0;
+               } else if ((obj = sobj_at(BOULDER, dpx, dpy)) != 0) {
+                       struct obj *bobj;
+
+                       fracture_rock(obj);
+                       if ((bobj = sobj_at(BOULDER, dpx, dpy)) != 0) {
+                           /* another boulder here, restack it to the top */
+                           obj_extract_self(bobj);
+                           place_object(bobj, dpx, dpy);
+                       }
+                       digtxt = "The boulder falls apart.";
+               } else if (lev->typ == STONE || lev->typ == SCORR ||
+                               IS_TREE(lev->typ)) {
+                       if(Is_earthlevel(&u.uz)) {
+                           if(uwep->blessed && !rn2(3)) {
+                               mkcavearea(FALSE);
+                               goto cleanup;
+                           } else if((uwep->cursed && !rn2(4)) ||
+                                         (!uwep->blessed && !rn2(6))) {
+                               mkcavearea(TRUE);
+                               goto cleanup;
+                           }
+                       }
+                       if (IS_TREE(lev->typ)) {
+                           digtxt = "You cut down the tree.";
+                           lev->typ = ROOM;
+                           if (!rn2(5)) (void) rnd_treefruit_at(dpx, dpy);
+                       } else {
+                           digtxt = "You succeed in cutting away some rock.";
+                           lev->typ = CORR;
+                       }
+               } else if(IS_WALL(lev->typ)) {
+                       if(shopedge) {
+                           add_damage(dpx, dpy, 10L * ACURRSTR);
+                           dmgtxt = "damage";
+                       }
+                       if (level.flags.is_maze_lev) {
+                           lev->typ = ROOM;
+                       } else if (level.flags.is_cavernous_lev &&
+                                  !in_town(dpx, dpy)) {
+                           lev->typ = CORR;
+                       } else {
+                           lev->typ = DOOR;
+                           lev->doormask = D_NODOOR;
+                       }
+                       digtxt = "You make an opening in the wall.";
+               } else if(lev->typ == SDOOR) {
+                       cvt_sdoor_to_door(lev); /* ->typ = DOOR */
+                       digtxt = "You break through a secret door!";
+                       if(!(lev->doormask & D_TRAPPED))
+                               lev->doormask = D_BROKEN;
+               } else if(closed_door(dpx, dpy)) {
+                       digtxt = "You break through the door.";
+                       if(shopedge) {
+                           add_damage(dpx, dpy, 400L);
+                           dmgtxt = "break";
+                       }
+                       if(!(lev->doormask & D_TRAPPED))
+                               lev->doormask = D_BROKEN;
+               } else return(0); /* statue or boulder got taken */
+
+               if(!does_block(dpx,dpy,&levl[dpx][dpy]))
+                   unblock_point(dpx,dpy);     /* vision:  can see through */
+               if(Blind)
+                   feel_location(dpx, dpy);
+               else
+                   newsym(dpx, dpy);
+               if(digtxt && !digging.quiet) pline(digtxt); /* after newsym */
+               if(dmgtxt)
+                   pay_for_damage(dmgtxt, FALSE);
+
+               if(Is_earthlevel(&u.uz) && !rn2(3)) {
+                   register struct monst *mtmp;
+
+                   switch(rn2(2)) {
+                     case 0:
+                       mtmp = makemon(&mons[PM_EARTH_ELEMENTAL],
+                                       dpx, dpy, NO_MM_FLAGS);
+                       break;
+                     default:
+                       mtmp = makemon(&mons[PM_XORN],
+                                       dpx, dpy, NO_MM_FLAGS);
+                       break;
+                   }
+                   if(mtmp) pline_The("debris from your digging comes to life!");
+               }
+               if(IS_DOOR(lev->typ) && (lev->doormask & D_TRAPPED)) {
+                       lev->doormask = D_NODOOR;
+                       b_trapped("door", 0);
+                       newsym(dpx, dpy);
+               }
+cleanup:
+               digging.lastdigtime = moves;
+               digging.quiet = FALSE;
+               digging.level.dnum = 0;
+               digging.level.dlevel = -1;
+               return(0);
+       } else {                /* not enough effort has been spent yet */
+               static const char *const d_target[6] = {
+                       "", "rock", "statue", "boulder", "door", "tree"
+               };
+               int dig_target = dig_typ(uwep, dpx, dpy);
+
+               if (IS_WALL(lev->typ) || dig_target == DIGTYP_DOOR) {
+                   if(*in_rooms(dpx, dpy, SHOPBASE)) {
+                       pline("This %s seems too hard to %s.",
+                             IS_DOOR(lev->typ) ? "door" : "wall", verb);
+                       return(0);
+                   }
+               } else if (!IS_ROCK(lev->typ) && dig_target == DIGTYP_ROCK)
+                   return(0); /* statue or boulder got taken */
+               if(!did_dig_msg) {
+                   You("hit the %s with all your might.",
+                       d_target[dig_target]);
+                   did_dig_msg = TRUE;
+               }
+       }
+       return(1);
+}
+
+/* When will hole be finished? Very rough indication used by shopkeeper. */
+int
+holetime()
+{
+       if(occupation != dig || !*u.ushops) return(-1);
+       return ((250 - digging.effort) / 20);
+}
+
+/* Return typ of liquid to fill a hole with, or ROOM, if no liquid nearby */
+STATIC_OVL
+schar
+fillholetyp(x,y)
+int x, y;
+{
+    register int x1, y1;
+    int lo_x = max(1,x-1), hi_x = min(x+1,COLNO-1),
+       lo_y = max(0,y-1), hi_y = min(y+1,ROWNO-1);
+    int pool_cnt = 0, moat_cnt = 0, lava_cnt = 0;
+
+    for (x1 = lo_x; x1 <= hi_x; x1++)
+       for (y1 = lo_y; y1 <= hi_y; y1++)
+           if (levl[x1][y1].typ == POOL)
+               pool_cnt++;
+           else if (levl[x1][y1].typ == MOAT ||
+                   (levl[x1][y1].typ == DRAWBRIDGE_UP &&
+                       (levl[x1][y1].drawbridgemask & DB_UNDER) == DB_MOAT))
+               moat_cnt++;
+           else if (levl[x1][y1].typ == LAVAPOOL ||
+                   (levl[x1][y1].typ == DRAWBRIDGE_UP &&
+                       (levl[x1][y1].drawbridgemask & DB_UNDER) == DB_LAVA))
+               lava_cnt++;
+    pool_cnt /= 3;             /* not as much liquid as the others */
+
+    if (lava_cnt > moat_cnt + pool_cnt && rn2(lava_cnt + 1))
+       return LAVAPOOL;
+    else if (moat_cnt > 0 && rn2(moat_cnt + 1))
+       return MOAT;
+    else if (pool_cnt > 0 && rn2(pool_cnt + 1))
+       return POOL;
+    else
+       return ROOM;
+}
+
+void
+digactualhole(x, y, madeby, ttyp)
+register int   x, y;
+struct monst   *madeby;
+int ttyp;
+{
+       struct obj *oldobjs, *newobjs;
+       register struct trap *ttmp;
+       char surface_type[BUFSZ];
+       struct rm *lev = &levl[x][y];
+       boolean shopdoor;
+       struct monst *mtmp = m_at(x, y);        /* may be madeby */
+       boolean madeby_u = (madeby == BY_YOU);
+       boolean madeby_obj = (madeby == BY_OBJECT);
+       boolean at_u = (x == u.ux) && (y == u.uy);
+       boolean wont_fall = Levitation || Flying;
+
+       if (u.utrap && u.utraptype == TT_INFLOOR) u.utrap = 0;
+
+       /* these furniture checks were in dighole(), but wand
+          breaking bypasses that routine and calls us directly */
+       if (IS_FOUNTAIN(lev->typ)) {
+           dogushforth(FALSE);
+           SET_FOUNTAIN_WARNED(x,y);           /* force dryup */
+           dryup(x, y, madeby_u);
+           return;
+#ifdef SINKS
+       } else if (IS_SINK(lev->typ)) {
+           breaksink(x, y);
+           return;
+#endif
+       } else if (lev->typ == DRAWBRIDGE_DOWN ||
+                  (is_drawbridge_wall(x, y) >= 0)) {
+           int bx = x, by = y;
+           /* if under the portcullis, the bridge is adjacent */
+           (void) find_drawbridge(&bx, &by);
+           destroy_drawbridge(bx, by);
+           return;
+       }
+
+       if (ttyp != PIT && !Can_dig_down(&u.uz)) {
+           impossible("digactualhole: can't dig %s on this level.",
+                      defsyms[trap_to_defsym(ttyp)].explanation);
+           ttyp = PIT;
+       }
+
+       /* maketrap() might change it, also, in this situation,
+          surface() returns an inappropriate string for a grave */
+       if (IS_GRAVE(lev->typ))
+           Strcpy(surface_type, "grave");
+       else
+           Strcpy(surface_type, surface(x,y));
+       shopdoor = IS_DOOR(lev->typ) && *in_rooms(x, y, SHOPBASE);
+       oldobjs = level.objects[x][y];
+       ttmp = maketrap(x, y, ttyp);
+       if (!ttmp) return;
+       newobjs = level.objects[x][y];
+       ttmp->tseen = (madeby_u || cansee(x,y));
+       ttmp->madeby_u = madeby_u;
+       newsym(ttmp->tx,ttmp->ty);
+
+       if (ttyp == PIT) {
+
+           if(madeby_u) {
+               You("dig a pit in the %s.", surface_type);
+               if (shopdoor) pay_for_damage("ruin", FALSE);
+           } else if (!madeby_obj && canseemon(madeby))
+               pline("%s digs a pit in the %s.", Monnam(madeby), surface_type);
+           else if (cansee(x, y) && flags.verbose)
+               pline("A pit appears in the %s.", surface_type);
+
+           if(at_u) {
+               if (!wont_fall) {
+                   if (!Passes_walls)
+                       u.utrap = rn1(4,2);
+                   u.utraptype = TT_PIT;
+                   vision_full_recalc = 1;     /* vision limits change */
+               } else
+                   u.utrap = 0;
+               if (oldobjs != newobjs) /* something unearthed */
+                       (void) pickup(1);       /* detects pit */
+           } else if(mtmp) {
+               if(is_flyer(mtmp->data) || is_floater(mtmp->data)) {
+                   if(canseemon(mtmp))
+                       pline("%s %s over the pit.", Monnam(mtmp),
+                                                    (is_flyer(mtmp->data)) ?
+                                                    "flies" : "floats");
+               } else if(mtmp != madeby)
+                   (void) mintrap(mtmp);
+           }
+       } else {        /* was TRAPDOOR now a HOLE*/
+
+           if(madeby_u)
+               You("dig a hole through the %s.", surface_type);
+           else if(!madeby_obj && canseemon(madeby))
+               pline("%s digs a hole through the %s.",
+                     Monnam(madeby), surface_type);
+           else if(cansee(x, y) && flags.verbose)
+               pline("A hole appears in the %s.", surface_type);
+
+           if (at_u) {
+               if (!u.ustuck && !wont_fall && !next_to_u()) {
+                   You("are jerked back by your pet!");
+                   wont_fall = TRUE;
+               }
+
+               /* Floor objects get a chance of falling down.  The case where
+                * the hero does NOT fall down is treated here.  The case
+                * where the hero does fall down is treated in goto_level().
+                */
+               if (u.ustuck || wont_fall) {
+                   if (newobjs)
+                       impact_drop((struct obj *)0, x, y, 0);
+                   if (oldobjs != newobjs)
+                       (void) pickup(1);
+                   if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE);
+
+               } else {
+                   d_level newlevel;
+
+                   if (*u.ushops && madeby_u)
+                       shopdig(1); /* shk might snatch pack */
+                   /* handle earlier damage, eg breaking wand of digging */
+                   else if (!madeby_u) pay_for_damage("dig into", TRUE);
+
+                   You("fall through...");
+                   /* Earlier checks must ensure that the destination
+                    * level exists and is in the present dungeon.
+                    */
+                   newlevel.dnum = u.uz.dnum;
+                   newlevel.dlevel = u.uz.dlevel + 1;
+                   goto_level(&newlevel, FALSE, TRUE, FALSE);
+                   /* messages for arriving in special rooms */
+                   spoteffects(FALSE);
+               }
+           } else {
+               if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE);
+               if (newobjs)
+                   impact_drop((struct obj *)0, x, y, 0);
+               if (mtmp) {
+                    /*[don't we need special sokoban handling here?]*/
+                   if (is_flyer(mtmp->data) || is_floater(mtmp->data) ||
+                       mtmp->data == &mons[PM_WUMPUS] ||
+                       (mtmp->wormno && count_wsegs(mtmp) > 5) ||
+                       mtmp->data->msize >= MZ_HUGE) return;
+                   if (mtmp == u.ustuck)       /* probably a vortex */
+                           return;             /* temporary? kludge */
+
+                   if (teleport_pet(mtmp, FALSE)) {
+                       d_level tolevel;
+
+                       if (Is_stronghold(&u.uz)) {
+                           assign_level(&tolevel, &valley_level);
+                       } else if (Is_botlevel(&u.uz)) {
+                           if (canseemon(mtmp))
+                               pline("%s avoids the trap.", Monnam(mtmp));
+                           return;
+                       } else {
+                           get_level(&tolevel, depth(&u.uz) + 1);
+                       }
+                       if (mtmp->isshk) make_angry_shk(mtmp, 0, 0);
+                       migrate_to_level(mtmp, ledger_no(&tolevel),
+                                        MIGR_RANDOM, (coord *)0);
+                   }
+               }
+           }
+       }
+}
+
+/* return TRUE if digging succeeded, FALSE otherwise */
+boolean
+dighole(pit_only)
+boolean pit_only;
+{
+       register struct trap *ttmp = t_at(u.ux, u.uy);
+       struct rm *lev = &levl[u.ux][u.uy];
+       struct obj *boulder_here;
+       schar typ;
+       boolean nohole = !Can_dig_down(&u.uz);
+
+       if ((ttmp && (ttmp->ttyp == MAGIC_PORTAL || nohole)) ||
+          (IS_ROCK(lev->typ) && lev->typ != SDOOR &&
+           (lev->wall_info & W_NONDIGGABLE) != 0)) {
+               pline_The("%s here is too hard to dig in.", surface(u.ux,u.uy));
+
+       } else if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) {
+               pline_The("%s sloshes furiously for a moment, then subsides.",
+                       is_lava(u.ux, u.uy) ? "lava" : "water");
+               wake_nearby();  /* splashing */
+
+       } else if (lev->typ == DRAWBRIDGE_DOWN ||
+                  (is_drawbridge_wall(u.ux, u.uy) >= 0)) {
+               /* drawbridge_down is the platform crossing the moat when the
+                  bridge is extended; drawbridge_wall is the open "doorway" or
+                  closed "door" where the portcullis/mechanism is located */
+               if (pit_only) {
+                   pline_The("drawbridge seems too hard to dig through.");
+                   return FALSE;
+               } else {
+                   int x = u.ux, y = u.uy;
+                   /* if under the portcullis, the bridge is adjacent */
+                   (void) find_drawbridge(&x, &y);
+                   destroy_drawbridge(x, y);
+                   return TRUE;
+               }
+
+       } else if ((boulder_here = sobj_at(BOULDER, u.ux, u.uy)) != 0) {
+               if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) &&
+                   rn2(2)) {
+                       pline_The("boulder settles into the pit.");
+                       ttmp->ttyp = PIT;        /* crush spikes */
+               } else {
+                       /*
+                        * digging makes a hole, but the boulder immediately
+                        * fills it.  Final outcome:  no hole, no boulder.
+                        */
+                       pline("KADOOM! The boulder falls in!");
+                       (void) delfloortrap(ttmp);
+               }
+               delobj(boulder_here);
+               return TRUE;
+
+       } else if (IS_GRAVE(lev->typ)) {        
+           digactualhole(u.ux, u.uy, BY_YOU, PIT);
+           dig_up_grave();
+           return TRUE;
+       } else if (lev->typ == DRAWBRIDGE_UP) {
+               /* must be floor or ice, other cases handled above */
+               /* dig "pit" and let fluid flow in (if possible) */
+               typ = fillholetyp(u.ux,u.uy);
+
+               if (typ == ROOM) {
+                       /*
+                        * We can't dig a hole here since that will destroy
+                        * the drawbridge.  The following is a cop-out. --dlc
+                        */
+                       pline_The("%s here is too hard to dig in.",
+                             surface(u.ux, u.uy));
+                       return FALSE;
+               }
+
+               lev->drawbridgemask &= ~DB_UNDER;
+               lev->drawbridgemask |= (typ == LAVAPOOL) ? DB_LAVA : DB_MOAT;
+
+ liquid_flow:
+               if (ttmp) (void) delfloortrap(ttmp);
+               /* if any objects were frozen here, they're released now */
+               unearth_objs(u.ux, u.uy);
+
+               pline("As you dig, the hole fills with %s!",
+                     typ == LAVAPOOL ? "lava" : "water");
+               if (!Levitation && !Flying) {
+                   if (typ == LAVAPOOL)
+                       (void) lava_effects();
+                   else if (!Wwalking)
+                       (void) drown();
+               }
+               return TRUE;
+
+       /* the following two are here for the wand of digging */
+       } else if (IS_THRONE(lev->typ)) {
+               pline_The("throne is too hard to break apart.");
+
+       } else if (IS_ALTAR(lev->typ)) {
+               pline_The("altar is too hard to break apart.");
+
+       } else {
+               typ = fillholetyp(u.ux,u.uy);
+
+               if (typ != ROOM) {
+                       lev->typ = typ;
+                       goto liquid_flow;
+               }
+
+               /* finally we get to make a hole */
+               if (nohole || pit_only)
+                       digactualhole(u.ux, u.uy, BY_YOU, PIT);
+               else
+                       digactualhole(u.ux, u.uy, BY_YOU, HOLE);
+
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+STATIC_OVL void
+dig_up_grave()
+{
+       struct obj *otmp;
+
+       /* Grave-robbing is frowned upon... */
+       exercise(A_WIS, FALSE);
+       if (Role_if(PM_ARCHEOLOGIST)) {
+           adjalign(-sgn(u.ualign.type)*3);
+           You_feel("like a despicable grave-robber!");
+       } else if (Role_if(PM_SAMURAI)) {
+           adjalign(-sgn(u.ualign.type));
+           You("disturb the honorable dead!");
+       } else if ((u.ualign.type == A_LAWFUL) && (u.ualign.record > -10)) {
+           adjalign(-sgn(u.ualign.type));
+           You("have violated the sanctity of this grave!");
+       }
+
+       switch (rn2(5)) {
+       case 0:
+       case 1:
+           You("unearth a corpse.");
+           if (!!(otmp = mk_tt_object(CORPSE, u.ux, u.uy)))
+               otmp->age -= 100;               /* this is an *OLD* corpse */;
+           break;
+       case 2:
+           if (!Blind) pline(Hallucination ? "Dude!  The living dead!" :
+                       "The grave's owner is very upset!");
+           (void) makemon(mkclass(S_ZOMBIE,0), u.ux, u.uy, NO_MM_FLAGS);
+           break;
+       case 3:
+           if (!Blind) pline(Hallucination ? "I want my mummy!" :
+                       "You've disturbed a tomb!");
+           (void) makemon(mkclass(S_MUMMY,0), u.ux, u.uy, NO_MM_FLAGS);
+           break;
+       default:
+           /* No corpse */
+           pline_The("grave seems unused.  Strange....");
+           break;
+       }
+       levl[u.ux][u.uy].typ = ROOM;
+       del_engr_at(u.ux, u.uy);
+       newsym(u.ux,u.uy);
+       return;
+}
+
+int
+use_pick_axe(obj)
+struct obj *obj;
+{
+       boolean ispick;
+       char dirsyms[12];
+       char qbuf[QBUFSZ];
+       register char *dsp = dirsyms;
+       register int rx, ry;
+       int res = 0;
+       register const char *sdp, *verb;
+
+       if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */
+
+       /* Check tool */
+       if (obj != uwep) {
+           if (!wield_tool(obj, "swing")) return 0;
+           else res = 1;
+       }
+       ispick = is_pick(obj);
+       verb = ispick ? "dig" : "chop";
+
+       if (u.utrap && u.utraptype == TT_WEB) {
+           pline("%s you can't %s while entangled in a web.",
+                 /* res==0 => no prior message;
+                    res==1 => just got "You now wield a pick-axe." message */
+                 !res ? "Unfortunately," : "But", verb);
+           return res;
+       }
+
+       while(*sdp) {
+               (void) movecmd(*sdp);   /* sets u.dx and u.dy and u.dz */
+               rx = u.ux + u.dx;
+               ry = u.uy + u.dy;
+               /* Include down even with axe, so we have at least one direction */
+               if (u.dz > 0 ||
+                   (u.dz == 0 && isok(rx, ry) &&
+                    dig_typ(obj, rx, ry) != DIGTYP_UNDIGGABLE))
+                       *dsp++ = *sdp;
+               sdp++;
+       }
+       *dsp = 0;
+       Sprintf(qbuf, "In what direction do you want to %s? [%s]", verb, dirsyms);
+       if(!getdir(qbuf))
+               return(res);
+
+       return(use_pick_axe2(obj));
+}
+
+/* MRKR: use_pick_axe() is split in two to allow autodig to bypass */
+/*       the "In what direction do you want to dig?" query.        */
+/*       use_pick_axe2() uses the existing u.dx, u.dy and u.dz    */
+
+int
+use_pick_axe2(obj) 
+struct obj *obj;
+{
+       register int rx, ry;
+       register struct rm *lev;
+       int dig_target;
+       boolean ispick = is_pick(obj);
+       const char *verbing = ispick ? "digging" : "chopping";
+
+       if (u.uswallow && attack(u.ustuck)) {
+               ;  /* return(1) */
+       } else if (Underwater) {
+               pline("Turbulence torpedoes your %s attempts.", verbing);
+       } else if(u.dz < 0) {
+               if(Levitation)
+                       You("don't have enough leverage.");
+               else
+                       You_cant("reach the %s.",ceiling(u.ux,u.uy));
+       } else if(!u.dx && !u.dy && !u.dz) {
+               char buf[BUFSZ];
+               int dam;
+
+               dam = rnd(2) + dbon() + obj->spe;
+               if (dam <= 0) dam = 1;
+               You("hit yourself with %s.", yname(uwep));
+               Sprintf(buf, "%s own %s", uhis(),
+                               OBJ_NAME(objects[obj->otyp]));
+               losehp(dam, buf, KILLED_BY);
+               flags.botl=1;
+               return(1);
+       } else if(u.dz == 0) {
+               if(Stunned || (Confusion && !rn2(5))) confdir();
+               rx = u.ux + u.dx;
+               ry = u.uy + u.dy;
+               if(!isok(rx, ry)) {
+                       pline("Clash!");
+                       return(1);
+               }
+               lev = &levl[rx][ry];
+               if(MON_AT(rx, ry) && attack(m_at(rx, ry)))
+                       return(1);
+               dig_target = dig_typ(obj, rx, ry);
+               if (dig_target == DIGTYP_UNDIGGABLE) {
+                       /* ACCESSIBLE or POOL */
+                       struct trap *trap = t_at(rx, ry);
+
+                       if (trap && trap->ttyp == WEB) {
+                           if (!trap->tseen) {
+                               seetrap(trap);
+                               There("is a spider web there!");
+                           }
+                           Your("%s entangled in the web.",
+                               aobjnam(obj, "become"));
+                           /* you ought to be able to let go; tough luck */
+                           /* (maybe `move_into_trap()' would be better) */
+                           nomul(-d(2,2));
+                           nomovemsg = "You pull free.";
+                       } else if (lev->typ == IRONBARS) {
+                           pline("Clang!");
+                           wake_nearby();
+                       } else if (IS_TREE(lev->typ))
+                           You("need an axe to cut down a tree.");
+                       else if (IS_ROCK(lev->typ))
+                           You("need a pick to dig rock.");
+                       else if (!ispick && (sobj_at(STATUE, rx, ry) ||
+                                            sobj_at(BOULDER, rx, ry))) {
+                           boolean vibrate = !rn2(3);
+                           pline("Sparks fly as you whack the %s.%s",
+                               sobj_at(STATUE, rx, ry) ? "statue" : "boulder",
+                               vibrate ? " The axe-handle vibrates violently!" : "");
+                           if (vibrate) losehp(2, "axing a hard object", KILLED_BY);
+                       }
+                       else
+                           You("swing your %s through thin air.",
+                               aobjnam(obj, (char *)0));
+               } else {
+                       static const char * const d_action[6] = {
+                                               "swinging",
+                                               "digging",
+                                               "chipping the statue",
+                                               "hitting the boulder",
+                                               "chopping at the door",
+                                               "cutting the tree"
+                       };
+                       did_dig_msg = FALSE;
+                       digging.quiet = FALSE;
+                       if (digging.pos.x != rx || digging.pos.y != ry ||
+                           !on_level(&digging.level, &u.uz) || digging.down) {
+                           if (flags.autodig &&
+                               dig_target == DIGTYP_ROCK && !digging.down &&
+                               digging.pos.x == u.ux &&
+                               digging.pos.y == u.uy &&
+                               (moves <= digging.lastdigtime+2 &&
+                                moves >= digging.lastdigtime)) {
+                               /* avoid messages if repeated autodigging */
+                               did_dig_msg = TRUE;
+                               digging.quiet = TRUE;
+                           }
+                           digging.down = digging.chew = FALSE;
+                           digging.warned = FALSE;
+                           digging.pos.x = rx;
+                           digging.pos.y = ry;
+                           assign_level(&digging.level, &u.uz);
+                           digging.effort = 0;
+                           if (!digging.quiet)
+                               You("start %s.", d_action[dig_target]);
+                       } else {
+                           You("%s %s.", digging.chew ? "begin" : "continue",
+                                       d_action[dig_target]);
+                           digging.chew = FALSE;
+                       }
+                       set_occupation(dig, verbing, 0);
+               }
+       } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
+               /* it must be air -- water checked above */
+               You("swing your %s through thin air.", aobjnam(obj, (char *)0));
+       } else if (!can_reach_floor()) {
+               You_cant("reach the %s.", surface(u.ux,u.uy));
+       } else if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) {
+               /* Monsters which swim also happen not to be able to dig */
+               You("cannot stay under%s long enough.",
+                               is_pool(u.ux, u.uy) ? "water" : " the lava");
+       } else if (!ispick) {
+               Your("%s merely scratches the %s.",
+                               aobjnam(obj, (char *)0), surface(u.ux,u.uy));
+               u_wipe_engr(3);
+       } else {
+               if (digging.pos.x != u.ux || digging.pos.y != u.uy ||
+                       !on_level(&digging.level, &u.uz) || !digging.down) {
+                   digging.chew = FALSE;
+                   digging.down = TRUE;
+                   digging.warned = FALSE;
+                   digging.pos.x = u.ux;
+                   digging.pos.y = u.uy;
+                   assign_level(&digging.level, &u.uz);
+                   digging.effort = 0;
+                   You("start %s downward.", verbing);
+                   if (*u.ushops) shopdig(0);
+               } else
+                   You("continue %s downward.", verbing);
+               did_dig_msg = FALSE;
+               set_occupation(dig, verbing, 0);
+       }
+       return(1);
+}
+
+/*
+ * Town Watchmen frown on damage to the town walls, trees or fountains.
+ * It's OK to dig holes in the ground, however.
+ * If mtmp is assumed to be a watchman, a watchman is found if mtmp == 0
+ * zap == TRUE if wand/spell of digging, FALSE otherwise (chewing)
+ */
+void
+watch_dig(mtmp, x, y, zap)
+    struct monst *mtmp;
+    xchar x, y;
+    boolean zap;
+{
+       struct rm *lev = &levl[x][y];
+
+       if (in_town(x, y) &&
+           (closed_door(x, y) || lev->typ == SDOOR ||
+            IS_WALL(lev->typ) || IS_FOUNTAIN(lev->typ) || IS_TREE(lev->typ))) {
+           if (!mtmp) {
+               for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+                   if (DEADMONSTER(mtmp)) continue;
+                   if ((mtmp->data == &mons[PM_WATCHMAN] ||
+                        mtmp->data == &mons[PM_WATCH_CAPTAIN]) &&
+                       mtmp->mcansee && m_canseeu(mtmp) &&
+                       couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful)
+                       break;
+               }
+           }
+
+           if (mtmp) {
+               if(zap || digging.warned) {
+                   verbalize("Halt, vandal!  You're under arrest!");
+                   (void) angry_guards(!(flags.soundok));
+               } else {
+                   const char *str;
+
+                   if (IS_DOOR(lev->typ))
+                       str = "door";
+                   else if (IS_TREE(lev->typ))
+                       str = "tree";
+                   else if (IS_ROCK(lev->typ))
+                       str = "wall";
+                   else
+                       str = "fountain";
+                   verbalize("Hey, stop damaging that %s!", str);
+                   digging.warned = TRUE;
+               }
+               if (is_digging())
+                   stop_occupation();
+           }
+       }
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+/* Return TRUE if monster died, FALSE otherwise.  Called from m_move(). */
+boolean
+mdig_tunnel(mtmp)
+register struct monst *mtmp;
+{
+       register struct rm *here;
+       int pile = rnd(12);
+
+       here = &levl[mtmp->mx][mtmp->my];
+       if (here->typ == SDOOR)
+           cvt_sdoor_to_door(here);    /* ->typ = DOOR */
+
+       /* Eats away door if present & closed or locked */
+       if (closed_door(mtmp->mx, mtmp->my)) {
+           if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE))
+               add_damage(mtmp->mx, mtmp->my, 0L);
+           unblock_point(mtmp->mx, mtmp->my);  /* vision */
+           if (here->doormask & D_TRAPPED) {
+               here->doormask = D_NODOOR;
+               if (mb_trapped(mtmp)) { /* mtmp is killed */
+                   newsym(mtmp->mx, mtmp->my);
+                   return TRUE;
+               }
+           } else {
+               if (!rn2(3) && flags.verbose)   /* not too often.. */
+                   You_feel("an unexpected draft.");
+               here->doormask = D_BROKEN;
+           }
+           newsym(mtmp->mx, mtmp->my);
+           return FALSE;
+       } else if (!IS_ROCK(here->typ) && !IS_TREE(here->typ)) /* no dig */
+           return FALSE;
+
+       /* Only rock, trees, and walls fall through to this point. */
+       if ((here->wall_info & W_NONDIGGABLE) != 0) {
+           impossible("mdig_tunnel:  %s at (%d,%d) is undiggable",
+                      (IS_WALL(here->typ) ? "wall" : "stone"),
+                      (int) mtmp->mx, (int) mtmp->my);
+           return FALSE;       /* still alive */
+       }
+
+       if (IS_WALL(here->typ)) {
+           /* KMH -- Okay on arboreal levels (room walls are still stone) */
+           if (flags.soundok && flags.verbose && !rn2(5))
+               You_hear("crashing rock.");
+           if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE))
+               add_damage(mtmp->mx, mtmp->my, 0L);
+           if (level.flags.is_maze_lev) {
+               here->typ = ROOM;
+           } else if (level.flags.is_cavernous_lev &&
+                      !in_town(mtmp->mx, mtmp->my)) {
+               here->typ = CORR;
+           } else {
+               here->typ = DOOR;
+               here->doormask = D_NODOOR;
+           }
+       } else if (IS_TREE(here->typ)) {
+           here->typ = ROOM;
+           if (pile && pile < 5)
+               (void) rnd_treefruit_at(mtmp->mx, mtmp->my);
+       } else {
+           here->typ = CORR;
+           if (pile && pile < 5)
+               (void) mksobj_at((pile == 1) ? BOULDER : ROCK,
+                            mtmp->mx, mtmp->my, TRUE, FALSE);
+       }
+       newsym(mtmp->mx, mtmp->my);
+       if (!sobj_at(BOULDER, mtmp->mx, mtmp->my))
+           unblock_point(mtmp->mx, mtmp->my);  /* vision */
+
+       return FALSE;
+}
+
+#endif /* OVL0 */
+#ifdef OVL3
+
+/* digging via wand zap or spell cast */
+void
+zap_dig()
+{
+       struct rm *room;
+       struct monst *mtmp;
+       struct obj *otmp;
+       int zx, zy, digdepth;
+       boolean shopdoor, shopwall, maze_dig;
+       /*
+        * Original effect (approximately):
+        * from CORR: dig until we pierce a wall
+        * from ROOM: pierce wall and dig until we reach
+        * an ACCESSIBLE place.
+        * Currently: dig for digdepth positions;
+        * also down on request of Lennart Augustsson.
+        */
+
+       if (u.uswallow) {
+           mtmp = u.ustuck;
+
+           if (!is_whirly(mtmp->data)) {
+               if (is_animal(mtmp->data))
+                   You("pierce %s %s wall!",
+                       s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH));
+               mtmp->mhp = 1;          /* almost dead */
+               expels(mtmp, mtmp->data, !is_animal(mtmp->data));
+           }
+           return;
+       } /* swallowed */
+
+       if (u.dz) {
+           if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !Underwater) {
+               if (u.dz < 0 || On_stairs(u.ux, u.uy)) {
+                   if (On_stairs(u.ux, u.uy))
+                       pline_The("beam bounces off the %s and hits the %s.",
+                             (u.ux == xdnladder || u.ux == xupladder) ?
+                             "ladder" : "stairs", ceiling(u.ux, u.uy));
+                   You("loosen a rock from the %s.", ceiling(u.ux, u.uy));
+                   pline("It falls on your %s!", body_part(HEAD));
+                   losehp(rnd((uarmh && is_metallic(uarmh)) ? 2 : 6),
+                          "falling rock", KILLED_BY_AN);
+                   otmp = mksobj_at(ROCK, u.ux, u.uy, FALSE, FALSE);
+                   if (otmp) {
+                       (void)xname(otmp);      /* set dknown, maybe bknown */
+                       stackobj(otmp);
+                   }
+                   newsym(u.ux, u.uy);
+               } else {
+                   watch_dig((struct monst *)0, u.ux, u.uy, TRUE);
+                   (void) dighole(FALSE);
+               }
+           }
+           return;
+       } /* up or down */
+
+       /* normal case: digging across the level */
+       shopdoor = shopwall = FALSE;
+       maze_dig = level.flags.is_maze_lev && !Is_earthlevel(&u.uz);
+       zx = u.ux + u.dx;
+       zy = u.uy + u.dy;
+       digdepth = rn1(18, 8);
+       tmp_at(DISP_BEAM, cmap_to_glyph(S_digbeam));
+       while (--digdepth >= 0) {
+           if (!isok(zx,zy)) break;
+           room = &levl[zx][zy];
+           tmp_at(zx,zy);
+           delay_output();     /* wait a little bit */
+           if (closed_door(zx, zy) || room->typ == SDOOR) {
+               if (*in_rooms(zx,zy,SHOPBASE)) {
+                   add_damage(zx, zy, 400L);
+                   shopdoor = TRUE;
+               }
+               if (room->typ == SDOOR)
+                   room->typ = DOOR;
+               else if (cansee(zx, zy))
+                   pline_The("door is razed!");
+               watch_dig((struct monst *)0, zx, zy, TRUE);
+               room->doormask = D_NODOOR;
+               unblock_point(zx,zy); /* vision */
+               digdepth -= 2;
+               if (maze_dig) break;
+           } else if (maze_dig) {
+               if (IS_WALL(room->typ)) {
+                   if (!(room->wall_info & W_NONDIGGABLE)) {
+                       if (*in_rooms(zx,zy,SHOPBASE)) {
+                           add_damage(zx, zy, 200L);
+                           shopwall = TRUE;
+                       }
+                       room->typ = ROOM;
+                       unblock_point(zx,zy); /* vision */
+                   } else if (!Blind)
+                       pline_The("wall glows then fades.");
+                   break;
+               } else if (IS_TREE(room->typ)) { /* check trees before stone */
+                   if (!(room->wall_info & W_NONDIGGABLE)) {
+                       room->typ = ROOM;
+                       unblock_point(zx,zy); /* vision */
+                   } else if (!Blind)
+                       pline_The("tree shudders but is unharmed.");
+                   break;
+               } else if (room->typ == STONE || room->typ == SCORR) {
+                   if (!(room->wall_info & W_NONDIGGABLE)) {
+                       room->typ = CORR;
+                       unblock_point(zx,zy); /* vision */
+                   } else if (!Blind)
+                       pline_The("rock glows then fades.");
+                   break;
+               }
+           } else if (IS_ROCK(room->typ)) {
+               if (!may_dig(zx,zy)) break;
+               if (IS_WALL(room->typ) || room->typ == SDOOR) {
+                   if (*in_rooms(zx,zy,SHOPBASE)) {
+                       add_damage(zx, zy, 200L);
+                       shopwall = TRUE;
+                   }
+                   watch_dig((struct monst *)0, zx, zy, TRUE);
+                   if (level.flags.is_cavernous_lev && !in_town(zx, zy)) {
+                       room->typ = CORR;
+                   } else {
+                       room->typ = DOOR;
+                       room->doormask = D_NODOOR;
+                   }
+                   digdepth -= 2;
+               } else if (IS_TREE(room->typ)) {
+                   room->typ = ROOM;
+                   digdepth -= 2;
+               } else {        /* IS_ROCK but not IS_WALL or SDOOR */
+                   room->typ = CORR;
+                   digdepth--;
+               }
+               unblock_point(zx,zy); /* vision */
+           }
+           zx += u.dx;
+           zy += u.dy;
+       } /* while */
+       tmp_at(DISP_END,0);     /* closing call */
+       if (shopdoor || shopwall)
+           pay_for_damage(shopdoor ? "destroy" : "dig into", FALSE);
+       return;
+}
+
+/* move objects from fobj/nexthere lists to buriedobjlist, keeping position */
+/* information */
+struct obj *
+bury_an_obj(otmp)
+       struct obj *otmp;
+{
+       struct obj *otmp2;
+       boolean under_ice;
+
+#ifdef DEBUG
+       pline("bury_an_obj: %s", xname(otmp));
+#endif
+       if (otmp == uball)
+               unpunish();
+       /* after unpunish(), or might get deallocated chain */
+       otmp2 = otmp->nexthere;
+       /*
+        * obj_resists(,0,0) prevents Rider corpses from being buried.
+        * It also prevents The Amulet and invocation tools from being
+        * buried.  Since they can't be confined to bags and statues,
+        * it makes sense that they can't be buried either, even though
+        * the real reason there (direct accessibility when carried) is
+        * completely different.
+        */
+       if (otmp == uchain || obj_resists(otmp, 0, 0))
+               return(otmp2);
+
+       if (otmp->otyp == LEASH && otmp->leashmon != 0)
+               o_unleash(otmp);
+
+       if (otmp->lamplit && otmp->otyp != POT_OIL)
+               end_burn(otmp, TRUE);
+
+       obj_extract_self(otmp);
+
+       under_ice = is_ice(otmp->ox, otmp->oy);
+       if (otmp->otyp == ROCK && !under_ice) {
+               /* merges into burying material */
+               obfree(otmp, (struct obj *)0);
+               return(otmp2);
+       }
+       /*
+        * Start a rot on organic material.  Not corpses -- they
+        * are already handled.
+        */
+       if (otmp->otyp == CORPSE) {
+           ;           /* should cancel timer if under_ice */
+       } else if ((under_ice ? otmp->oclass == POTION_CLASS : is_organic(otmp))
+               && !obj_resists(otmp, 5, 95)) {
+           (void) start_timer((under_ice ? 0L : 250L) + (long)rnd(250),
+                              TIMER_OBJECT, ROT_ORGANIC, (genericptr_t)otmp);
+       }
+       add_to_buried(otmp);
+       return(otmp2);
+}
+
+void
+bury_objs(x, y)
+int x, y;
+{
+       struct obj *otmp, *otmp2;
+
+#ifdef DEBUG
+       if(level.objects[x][y] != (struct obj *)0)
+               pline("bury_objs: at %d, %d", x, y);
+#endif
+       for (otmp = level.objects[x][y]; otmp; otmp = otmp2)
+               otmp2 = bury_an_obj(otmp);
+
+       /* don't expect any engravings here, but just in case */
+       del_engr_at(x, y);
+       newsym(x, y);
+}
+
+/* move objects from buriedobjlist to fobj/nexthere lists */
+void
+unearth_objs(x, y)
+int x, y;
+{
+       struct obj *otmp, *otmp2;
+
+#ifdef DEBUG
+       pline("unearth_objs: at %d, %d", x, y);
+#endif
+       for (otmp = level.buriedobjlist; otmp; otmp = otmp2) {
+               otmp2 = otmp->nobj;
+               if (otmp->ox == x && otmp->oy == y) {
+                   obj_extract_self(otmp);
+                   if (otmp->timed)
+                       (void) stop_timer(ROT_ORGANIC, (genericptr_t)otmp);
+                   place_object(otmp, x, y);
+                   stackobj(otmp);
+               }
+       }
+       del_engr_at(x, y);
+       newsym(x, y);
+}
+
+/*
+ * The organic material has rotted away while buried.  As an expansion,
+ * we could add add partial damage.  A damage count is kept in the object
+ * and every time we are called we increment the count and reschedule another
+ * timeout.  Eventually the object rots away.
+ *
+ * This is used by buried objects other than corpses.  When a container rots
+ * away, any contents become newly buried objects.
+ */
+/* ARGSUSED */
+void
+rot_organic(arg, timeout)
+genericptr_t arg;
+long timeout;  /* unused */
+{
+       struct obj *obj = (struct obj *) arg;
+
+       while (Has_contents(obj)) {
+           /* We don't need to place contained object on the floor
+              first, but we do need to update its map coordinates. */
+           obj->cobj->ox = obj->ox,  obj->cobj->oy = obj->oy;
+           /* Everything which can be held in a container can also be
+              buried, so bury_an_obj's use of obj_extract_self insures
+              that Has_contents(obj) will eventually become false. */
+           (void)bury_an_obj(obj->cobj);
+       }
+       obj_extract_self(obj);
+       obfree(obj, (struct obj *) 0);
+}
+
+/*
+ * Called when a corpse has rotted completely away.
+ */
+void
+rot_corpse(arg, timeout)
+genericptr_t arg;
+long timeout;  /* unused */
+{
+       xchar x = 0, y = 0;
+       struct obj *obj = (struct obj *) arg;
+       boolean on_floor = obj->where == OBJ_FLOOR,
+               in_invent = obj->where == OBJ_INVENT;
+
+       if (on_floor) {
+           x = obj->ox;
+           y = obj->oy;
+       } else if (in_invent) {
+           if (flags.verbose) {
+               char *cname = corpse_xname(obj, FALSE);
+               Your("%s%s %s away%c",
+                    obj == uwep ? "wielded " : nul, cname,
+                    otense(obj, "rot"), obj == uwep ? '!' : '.');
+           }
+           if (obj == uwep) {
+               uwepgone();     /* now bare handed */
+               stop_occupation();
+           } else if (obj == uswapwep) {
+               uswapwepgone();
+               stop_occupation();
+           } else if (obj == uquiver) {
+               uqwepgone();
+               stop_occupation();
+           }
+       } else if (obj->where == OBJ_MINVENT && obj->owornmask) {
+           if (obj == MON_WEP(obj->ocarry)) {
+               setmnotwielded(obj->ocarry,obj);
+               MON_NOWEP(obj->ocarry);
+           }
+       }
+       rot_organic(arg, timeout);
+       if (on_floor) newsym(x, y);
+       else if (in_invent) update_inventory();
+}
+
+#if 0
+void
+bury_monst(mtmp)
+struct monst *mtmp;
+{
+#ifdef DEBUG
+       pline("bury_monst: %s", mon_nam(mtmp));
+#endif
+       if(canseemon(mtmp)) {
+           if(is_flyer(mtmp->data) || is_floater(mtmp->data)) {
+               pline_The("%s opens up, but %s is not swallowed!",
+                       surface(mtmp->mx, mtmp->my), mon_nam(mtmp));
+               return;
+           } else
+               pline_The("%s opens up and swallows %s!",
+                       surface(mtmp->mx, mtmp->my), mon_nam(mtmp));
+       }
+
+       mtmp->mburied = TRUE;
+       wakeup(mtmp);                   /* at least give it a chance :-) */
+       newsym(mtmp->mx, mtmp->my);
+}
+
+void
+bury_you()
+{
+#ifdef DEBUG
+       pline("bury_you");
+#endif
+    if (!Levitation && !Flying) {
+       if(u.uswallow)
+           You_feel("a sensation like falling into a trap!");
+       else
+           pline_The("%s opens beneath you and you fall in!",
+                 surface(u.ux, u.uy));
+
+       u.uburied = TRUE;
+       if(!Strangled && !Breathless) Strangled = 6;
+       under_ground(1);
+    }
+}
+
+void
+unearth_you()
+{
+#ifdef DEBUG
+       pline("unearth_you");
+#endif
+       u.uburied = FALSE;
+       under_ground(0);
+       if(!uamul || uamul->otyp != AMULET_OF_STRANGULATION)
+               Strangled = 0;
+       vision_recalc(0);
+}
+
+void
+escape_tomb()
+{
+#ifdef DEBUG
+       pline("escape_tomb");
+#endif
+       if ((Teleportation || can_teleport(youmonst.data)) &&
+           (Teleport_control || rn2(3) < Luck+2)) {
+               You("attempt a teleport spell.");
+               (void) dotele();        /* calls unearth_you() */
+       } else if(u.uburied) { /* still buried after 'port attempt */
+               boolean good;
+
+               if(amorphous(youmonst.data) || Passes_walls ||
+                  noncorporeal(youmonst.data) || unsolid(youmonst.data) ||
+                  (tunnels(youmonst.data) && !needspick(youmonst.data))) {
+
+                   You("%s up through the %s.",
+                       (tunnels(youmonst.data) && !needspick(youmonst.data)) ?
+                        "try to tunnel" : (amorphous(youmonst.data)) ?
+                        "ooze" : "phase", surface(u.ux, u.uy));
+
+                   if(tunnels(youmonst.data) && !needspick(youmonst.data))
+                       good = dighole(TRUE);
+                   else good = TRUE;
+                   if(good) unearth_you();
+               }
+       }
+}
+
+void
+bury_obj(otmp)
+struct obj *otmp;
+{
+
+#ifdef DEBUG
+       pline("bury_obj");
+#endif
+       if(cansee(otmp->ox, otmp->oy))
+          pline_The("objects on the %s tumble into a hole!",
+               surface(otmp->ox, otmp->oy));
+
+       bury_objs(otmp->ox, otmp->oy);
+}
+#endif
+
+#ifdef DEBUG
+int
+wiz_debug_cmd() /* in this case, bury everything at your loc and around */
+{
+       int x, y;
+
+       for (x = u.ux - 1; x <= u.ux + 1; x++)
+           for (y = u.uy - 1; y <= u.uy + 1; y++)
+               if (isok(x,y)) bury_objs(x,y);
+       return 0;
+}
+
+#endif /* DEBUG */
+#endif /* OVL3 */
+
+/*dig.c*/
diff --git a/src/display.c b/src/display.c
new file mode 100644 (file)
index 0000000..2c9e9ae
--- /dev/null
@@ -0,0 +1,2196 @@
+/*     SCCS Id: @(#)display.c  3.4     2003/02/19      */
+/* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */
+/* and Dave Cohrs, 1990.                                         */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *                     THE NEW DISPLAY CODE
+ *
+ * The old display code has been broken up into three parts: vision, display,
+ * and drawing.  Vision decides what locations can and cannot be physically
+ * seen by the hero.  Display decides _what_ is displayed at a given location.
+ * Drawing decides _how_ to draw a monster, fountain, sword, etc.
+ *
+ * The display system uses information from the vision system to decide
+ * what to draw at a given location.  The routines for the vision system
+ * can be found in vision.c and vision.h.  The routines for display can
+ * be found in this file (display.c) and display.h.  The drawing routines
+ * are part of the window port.  See doc/window.doc for the drawing
+ * interface.
+ *
+ * The display system deals with an abstraction called a glyph.  Anything
+ * that could possibly be displayed has a unique glyph identifier.
+ *
+ * What is seen on the screen is a combination of what the hero remembers
+ * and what the hero currently sees.  Objects and dungeon features (walls
+ * doors, etc) are remembered when out of sight.  Monsters and temporary
+ * effects are not remembered.  Each location on the level has an
+ * associated glyph.  This is the hero's _memory_ of what he or she has
+ * seen there before.
+ *
+ * Display rules:
+ *
+ *     If the location is in sight, display in order:
+ *             visible (or sensed) monsters
+ *             visible objects
+ *             known traps
+ *             background
+ *
+ *     If the location is out of sight, display in order:
+ *             sensed monsters (telepathy)
+ *             memory
+ *
+ *
+ *
+ * Here is a list of the major routines in this file to be used externally:
+ *
+ * newsym
+ *
+ * Possibly update the screen location (x,y).  This is the workhorse routine.
+ * It is always correct --- where correct means following the in-sight/out-
+ * of-sight rules.  **Most of the code should use this routine.**  This
+ * routine updates the map and displays monsters.
+ *
+ *
+ * map_background
+ * map_object
+ * map_trap
+ * map_invisible
+ * unmap_object
+ *
+ * If you absolutely must override the in-sight/out-of-sight rules, there
+ * are two possibilities.  First, you can mess with vision to force the
+ * location in sight then use newsym(), or you can  use the map_* routines.
+ * The first has not been tried [no need] and the second is used in the
+ * detect routines --- detect object, magic mapping, etc.  The map_*
+ * routines *change* what the hero remembers.  All changes made by these
+ * routines will be sticky --- they will survive screen redraws.  Do *not*
+ * use these for things that only temporarily change the screen.  These
+ * routines are also used directly by newsym().  unmap_object is used to
+ * clear a remembered object when/if detection reveals it isn't there.
+ *
+ *
+ * show_glyph
+ *
+ * This is direct (no processing in between) buffered access to the screen.
+ * Temporary screen effects are run through this and its companion,
+ * flush_screen().  There is yet a lower level routine, print_glyph(),
+ * but this is unbuffered and graphic dependent (i.e. it must be surrounded
+ * by graphic set-up and tear-down routines).  Do not use print_glyph().
+ *
+ *
+ * see_monsters
+ * see_objects
+ * see_traps
+ *
+ * These are only used when something affects all of the monsters or
+ * objects or traps.  For objects and traps, the only thing is hallucination.
+ * For monsters, there are hallucination and changing from/to blindness, etc.
+ *
+ *
+ * tmp_at
+ *
+ * This is a useful interface for displaying temporary items on the screen.
+ * Its interface is different than previously, so look at it carefully.
+ *
+ *
+ *
+ * Parts of the rm structure that are used:
+ *
+ *     typ     - What is really there.
+ *     glyph   - What the hero remembers.  This will never be a monster.
+ *               Monsters "float" above this.
+ *     lit     - True if the position is lit.  An optimization for
+ *               lit/unlit rooms.
+ *     waslit  - True if the position was *remembered* as lit.
+ *     seenv   - A vector of bits representing the directions from which the
+ *               hero has seen this position.  The vector's primary use is
+ *               determining how walls are seen.  E.g. a wall sometimes looks
+ *               like stone on one side, but is seen as a wall from the other.
+ *               Other uses are for unmapping detected objects and felt
+ *               locations, where we need to know if the hero has ever
+ *               seen the location.
+ *     flags   - Additional information for the typ field.  Different for
+ *               each typ.
+ *     horizontal - Indicates whether the wall or door is horizontal or
+ *                  vertical.
+ */
+#include "hack.h"
+#include "region.h"
+
+STATIC_DCL void FDECL(display_monster,(XCHAR_P,XCHAR_P,struct monst *,int,XCHAR_P));
+STATIC_DCL int FDECL(swallow_to_glyph, (int, int));
+STATIC_DCL void FDECL(display_warning,(struct monst *));
+
+STATIC_DCL int FDECL(check_pos, (int, int, int));
+#ifdef WA_VERBOSE
+STATIC_DCL boolean FDECL(more_than_one, (int, int, int, int, int));
+#endif
+STATIC_DCL int FDECL(set_twall, (int,int, int,int, int,int, int,int));
+STATIC_DCL int FDECL(set_wall, (int, int, int));
+STATIC_DCL int FDECL(set_corn, (int,int, int,int, int,int, int,int));
+STATIC_DCL int FDECL(set_crosswall, (int, int));
+STATIC_DCL void FDECL(set_seenv, (struct rm *, int, int, int, int));
+STATIC_DCL void FDECL(t_warn, (struct rm *));
+STATIC_DCL int FDECL(wall_angle, (struct rm *));
+
+#ifdef INVISIBLE_OBJECTS
+/*
+ * vobj_at()
+ *
+ * Returns a pointer to an object if the hero can see an object at the
+ * given location.  This takes care of invisible objects.  NOTE, this
+ * assumes that the hero is not blind and on top of the object pile.
+ * It does NOT take into account that the location is out of sight, or,
+ * say, one can see blessed, etc.
+ */
+struct obj *
+vobj_at(x,y)
+    xchar x,y;
+{
+    register struct obj *obj = level.objects[x][y];
+
+    while (obj) {
+       if (!obj->oinvis || See_invisible) return obj;
+       obj = obj->nexthere;
+    }
+    return ((struct obj *) 0);
+}
+#endif /* else vobj_at() is defined in display.h */
+
+/*
+ * magic_map_background()
+ *
+ * This function is similar to map_background (see below) except we pay
+ * attention to and correct unexplored, lit ROOM and CORR spots.
+ */
+void
+magic_map_background(x, y, show)
+    xchar x,y;
+    int  show;
+{
+    int glyph = back_to_glyph(x,y);    /* assumes hero can see x,y */
+    struct rm *lev = &levl[x][y];
+
+    /*
+     * Correct for out of sight lit corridors and rooms that the hero
+     * doesn't remember as lit.
+     */
+    if (!cansee(x,y) && !lev->waslit) {
+       /* Floor spaces are dark if unlit.  Corridors are dark if unlit. */
+       if (lev->typ == ROOM && glyph == cmap_to_glyph(S_room))
+           glyph = cmap_to_glyph(S_stone);
+       else if (lev->typ == CORR && glyph == cmap_to_glyph(S_litcorr))
+           glyph = cmap_to_glyph(S_corr);
+    }
+    if (level.flags.hero_memory)
+       lev->glyph = glyph;
+    if (show) show_glyph(x,y, glyph);
+}
+
+/*
+ * The routines map_background(), map_object(), and map_trap() could just
+ * as easily be:
+ *
+ *     map_glyph(x,y,glyph,show)
+ *
+ * Which is called with the xx_to_glyph() in the call.  Then I can get
+ * rid of 3 routines that don't do very much anyway.  And then stop
+ * having to create fake objects and traps.  However, I am reluctant to
+ * make this change.
+ */
+/* FIXME: some of these use xchars for x and y, and some use ints.  Make
+ * this consistent.
+ */
+
+/*
+ * map_background()
+ *
+ * Make the real background part of our map.  This routine assumes that
+ * the hero can physically see the location.  Update the screen if directed.
+ */
+void
+map_background(x, y, show)
+    register xchar x,y;
+    register int  show;
+{
+    register int glyph = back_to_glyph(x,y);
+
+    if (level.flags.hero_memory)
+       levl[x][y].glyph = glyph;
+    if (show) show_glyph(x,y, glyph);
+}
+
+/*
+ * map_trap()
+ *
+ * Map the trap and print it out if directed.  This routine assumes that the
+ * hero can physically see the location.
+ */
+void
+map_trap(trap, show)
+    register struct trap *trap;
+    register int        show;
+{
+    register int x = trap->tx, y = trap->ty;
+    register int glyph = trap_to_glyph(trap);
+
+    if (level.flags.hero_memory)
+       levl[x][y].glyph = glyph;
+    if (show) show_glyph(x, y, glyph);
+}
+
+/*
+ * map_object()
+ *
+ * Map the given object.  This routine assumes that the hero can physically
+ * see the location of the object.  Update the screen if directed.
+ */
+void
+map_object(obj, show)
+    register struct obj *obj;
+    register int       show;
+{
+    register int x = obj->ox, y = obj->oy;
+    register int glyph = obj_to_glyph(obj);
+
+    if (level.flags.hero_memory)
+       levl[x][y].glyph = glyph;
+    if (show) show_glyph(x, y, glyph);
+}
+
+/*
+ * map_invisible()
+ *
+ * Make the hero remember that a square contains an invisible monster.
+ * This is a special case in that the square will continue to be displayed
+ * this way even when the hero is close enough to see it.  To get rid of
+ * this and display the square's actual contents, use unmap_object() followed
+ * by newsym() if necessary.
+ */
+void
+map_invisible(x, y)
+register xchar x, y;
+{
+    if (x != u.ux || y != u.uy) { /* don't display I at hero's location */
+       if (level.flags.hero_memory)
+           levl[x][y].glyph = GLYPH_INVISIBLE;
+       show_glyph(x, y, GLYPH_INVISIBLE);
+    }
+}
+
+/*
+ * unmap_object()
+ *
+ * Remove something from the map when the hero realizes it's not there any
+ * more.  Replace it with background or known trap, but not with any other
+ * If this is used for detection, a full screen update is imminent anyway;
+ * if this is used to get rid of an invisible monster notation, we might have
+ * to call newsym().
+ */
+void
+unmap_object(x, y)
+    register int x, y;
+{
+    register struct trap *trap;
+
+    if (!level.flags.hero_memory) return;
+
+    if ((trap = t_at(x,y)) != 0 && trap->tseen && !covers_traps(x,y))
+       map_trap(trap, 0);
+    else if (levl[x][y].seenv) {
+       struct rm *lev = &levl[x][y];
+
+       map_background(x, y, 0);
+
+       /* turn remembered dark room squares dark */
+       if (!lev->waslit && lev->glyph == cmap_to_glyph(S_room) &&
+                                                           lev->typ == ROOM)
+           lev->glyph = cmap_to_glyph(S_stone);
+    } else
+       levl[x][y].glyph = cmap_to_glyph(S_stone);      /* default val */
+}
+
+
+/*
+ * map_location()
+ *
+ * Make whatever at this location show up.  This is only for non-living
+ * things.  This will not handle feeling invisible objects correctly.
+ *
+ * Internal to display.c, this is a #define for speed.
+ */
+#define _map_location(x,y,show)                                                \
+{                                                                      \
+    register struct obj   *obj;                                                \
+    register struct trap  *trap;                                       \
+                                                                       \
+    if ((obj = vobj_at(x,y)) && !covers_objects(x,y))                  \
+       map_object(obj,show);                                           \
+    else if ((trap = t_at(x,y)) && trap->tseen && !covers_traps(x,y))  \
+       map_trap(trap,show);                                            \
+    else                                                               \
+       map_background(x,y,show);                                       \
+}
+
+void
+map_location(x,y,show)
+    int x, y, show;
+{
+    _map_location(x,y,show);
+}
+
+#define DETECTED       2
+#define PHYSICALLY_SEEN 1
+#define is_worm_tail(mon)      ((mon) && ((x != (mon)->mx)  || (y != (mon)->my)))
+
+/*
+ * display_monster()
+ *
+ * Note that this is *not* a map_XXXX() function!  Monsters sort of float
+ * above everything.
+ *
+ * Yuck.  Display body parts by recognizing that the display position is
+ * not the same as the monster position.  Currently the only body part is
+ * a worm tail.
+ *
+ */
+STATIC_OVL void
+display_monster(x, y, mon, sightflags, worm_tail)
+    register xchar x, y;       /* display position */
+    register struct monst *mon;        /* monster to display */
+    int sightflags;            /* 1 if the monster is physically seen */
+                               /* 2 if detected using Detect_monsters */
+    register xchar worm_tail;  /* mon is actually a worm tail */
+{
+    register boolean mon_mimic = (mon->m_ap_type != M_AP_NOTHING);
+    register int sensed = mon_mimic &&
+       (Protection_from_shape_changers || sensemon(mon));
+    /*
+     * We must do the mimic check first.  If the mimic is mimicing something,
+     * and the location is in sight, we have to change the hero's memory
+     * so that when the position is out of sight, the hero remembers what
+     * the mimic was mimicing.
+     */
+
+    if (mon_mimic && (sightflags == PHYSICALLY_SEEN)) {
+       switch (mon->m_ap_type) {
+           default:
+               impossible("display_monster:  bad m_ap_type value [ = %d ]",
+                                                       (int) mon->m_ap_type);
+           case M_AP_NOTHING:
+               show_glyph(x, y, mon_to_glyph(mon));
+               break;
+
+           case M_AP_FURNITURE: {
+               /*
+                * This is a poor man's version of map_background().  I can't
+                * use map_background() because we are overriding what is in
+                * the 'typ' field.  Maybe have map_background()'s parameters
+                * be (x,y,glyph) instead of just (x,y).
+                *
+                * mappearance is currently set to an S_ index value in
+                * makemon.c.
+                */
+               register int glyph = cmap_to_glyph(mon->mappearance);
+               levl[x][y].glyph = glyph;
+               if (!sensed) show_glyph(x,y, glyph);
+               break;
+           }
+
+           case M_AP_OBJECT: {
+               struct obj obj; /* Make a fake object to send   */
+                               /* to map_object().             */
+               obj.ox = x;
+               obj.oy = y;
+               obj.otyp = mon->mappearance;
+               obj.corpsenm = PM_TENGU;        /* if mimicing a corpse */
+               map_object(&obj,!sensed);
+               break;
+           }
+
+           case M_AP_MONSTER:
+               show_glyph(x,y, monnum_to_glyph(what_mon((int)mon->mappearance)));
+               break;
+       }
+       
+    }
+
+    /* If the mimic is unsucessfully mimicing something, display the monster */
+    if (!mon_mimic || sensed) {
+       int num;
+
+       /* [ALI] Only use detected glyphs when monster wouldn't be
+        * visible by any other means.
+        */
+       if (sightflags == DETECTED) {
+           if (worm_tail)
+               num = detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL));
+           else
+               num = detected_mon_to_glyph(mon);
+       } else if (mon->mtame && !Hallucination) {
+           if (worm_tail)
+               num = petnum_to_glyph(PM_LONG_WORM_TAIL);
+           else
+               num = pet_to_glyph(mon);
+       } else {
+           if (worm_tail)
+               num = monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL));
+           else
+               num = mon_to_glyph(mon);
+       }
+       show_glyph(x,y,num);
+    }
+}
+
+/*
+ * display_warning()
+ *
+ * This is also *not* a map_XXXX() function!  Monster warnings float
+ * above everything just like monsters do, but only if the monster
+ * is not showing.
+ *
+ * Do not call for worm tails.
+ */
+STATIC_OVL void
+display_warning(mon)
+    register struct monst *mon;
+{
+    int x = mon->mx, y = mon->my;
+    int wl = (int) (mon->m_lev / 4);
+    int glyph;
+
+    if (mon_warning(mon)) {
+        if (wl > WARNCOUNT - 1) wl = WARNCOUNT - 1;
+       /* 3.4.1: this really ought to be rn2(WARNCOUNT), but value "0"
+          isn't handled correctly by the what_is routine so avoid it */
+       if (Hallucination) wl = rn1(WARNCOUNT-1,1);
+        glyph = warning_to_glyph(wl);
+    } else if (MATCH_WARN_OF_MON(mon)) {
+       glyph = mon_to_glyph(mon);
+    } else {
+       impossible("display_warning did not match warning type?");
+        return;
+    }
+    show_glyph(x, y, glyph);
+}
+
+/*
+ * feel_location()
+ *
+ * Feel the given location.  This assumes that the hero is blind and that
+ * the given position is either the hero's or one of the eight squares
+ * adjacent to the hero (except for a boulder push).
+ * If an invisible monster has gone away, that will be discovered.  If an
+ * invisible monster has appeared, this will _not_ be discovered since
+ * searching only finds one monster per turn so we must check that separately.
+ */
+void
+feel_location(x, y)
+    xchar x, y;
+{
+    struct rm *lev = &(levl[x][y]);
+    struct obj *boulder;
+    register struct monst *mon;
+
+    /* If the hero's memory of an invisible monster is accurate, we want to keep
+     * him from detecting the same monster over and over again on each turn.
+     * We must return (so we don't erase the monster).  (We must also, in the
+     * search function, be sure to skip over previously detected 'I's.)
+     */
+    if (glyph_is_invisible(levl[x][y].glyph) && m_at(x,y)) return;
+
+    /* The hero can't feel non pool locations while under water. */
+    if (Underwater && !Is_waterlevel(&u.uz) && ! is_pool(x,y))
+       return;
+
+    /* Set the seen vector as if the hero had seen it.  It doesn't matter */
+    /* if the hero is levitating or not.                                 */
+    set_seenv(lev, u.ux, u.uy, x, y);
+
+    if (Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) {
+       /*
+        * Levitation Rules.  It is assumed that the hero can feel the state
+        * of the walls around herself and can tell if she is in a corridor,
+        * room, or doorway.  Boulders are felt because they are large enough.
+        * Anything else is unknown because the hero can't reach the ground.
+        * This makes things difficult.
+        *
+        * Check (and display) in order:
+        *
+        *      + Stone, walls, and closed doors.
+        *      + Boulders.  [see a boulder before a doorway]
+        *      + Doors.
+        *      + Room/water positions
+        *      + Everything else (hallways!)
+        */
+       if (IS_ROCK(lev->typ) || (IS_DOOR(lev->typ) &&
+                               (lev->doormask & (D_LOCKED | D_CLOSED)))) {
+           map_background(x, y, 1);
+       } else if ((boulder = sobj_at(BOULDER,x,y)) != 0) {
+           map_object(boulder, 1);
+       } else if (IS_DOOR(lev->typ)) {
+           map_background(x, y, 1);
+       } else if (IS_ROOM(lev->typ) || IS_POOL(lev->typ)) {
+           /*
+            * An open room or water location.  Normally we wouldn't touch
+            * this, but we have to get rid of remembered boulder symbols.
+            * This will only occur in rare occations when the hero goes
+            * blind and doesn't find a boulder where expected (something
+            * came along and picked it up).  We know that there is not a
+            * boulder at this location.  Show fountains, pools, etc.
+            * underneath if already seen.  Otherwise, show the appropriate
+            * floor symbol.
+            *
+            * Similarly, if the hero digs a hole in a wall or feels a location
+            * that used to contain an unseen monster.  In these cases,
+            * there's no reason to assume anything was underneath, so
+            * just show the appropriate floor symbol.  If something was
+            * embedded in the wall, the glyph will probably already
+            * reflect that.  Don't change the symbol in this case.
+            *
+            * This isn't quite correct.  If the boulder was on top of some
+            * other objects they should be seen once the boulder is removed.
+            * However, we have no way of knowing that what is there now
+            * was there then.  So we let the hero have a lapse of memory.
+            * We could also just display what is currently on the top of the
+            * object stack (if anything).
+            */
+           if (lev->glyph == objnum_to_glyph(BOULDER)) {
+               if (lev->typ != ROOM && lev->seenv) {
+                   map_background(x, y, 1);
+               } else {
+                   lev->glyph = lev->waslit ? cmap_to_glyph(S_room) :
+                                              cmap_to_glyph(S_stone);
+                   show_glyph(x,y,lev->glyph);
+               }
+           } else if ((lev->glyph >= cmap_to_glyph(S_stone) &&
+                       lev->glyph < cmap_to_glyph(S_room)) ||
+                      glyph_is_invisible(levl[x][y].glyph)) {
+               lev->glyph = lev->waslit ? cmap_to_glyph(S_room) :
+                                          cmap_to_glyph(S_stone);
+               show_glyph(x,y,lev->glyph);
+           }
+       } else {
+           /* We feel it (I think hallways are the only things left). */
+           map_background(x, y, 1);
+           /* Corridors are never felt as lit (unless remembered that way) */
+           /* (lit_corridor only).                                         */
+           if (lev->typ == CORR &&
+                   lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit)
+               show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
+       }
+    } else {
+       _map_location(x, y, 1);
+
+       if (Punished) {
+           /*
+            * A ball or chain is only felt if it is first on the object
+            * location list.  Otherwise, we need to clear the felt bit ---
+            * something has been dropped on the ball/chain.  If the bit is
+            * not cleared, then when the ball/chain is moved it will drop
+            * the wrong glyph.
+            */
+           if (uchain->ox == x && uchain->oy == y) {
+               if (level.objects[x][y] == uchain)
+                   u.bc_felt |= BC_CHAIN;
+               else
+                   u.bc_felt &= ~BC_CHAIN;     /* do not feel the chain */
+           }
+           if (!carried(uball) && uball->ox == x && uball->oy == y) {
+               if (level.objects[x][y] == uball)
+                   u.bc_felt |= BC_BALL;
+               else
+                   u.bc_felt &= ~BC_BALL;      /* do not feel the ball */
+           }
+       }
+
+       /* Floor spaces are dark if unlit.  Corridors are dark if unlit. */
+       if (lev->typ == ROOM &&
+                   lev->glyph == cmap_to_glyph(S_room) && !lev->waslit)
+           show_glyph(x,y, lev->glyph = cmap_to_glyph(S_stone));
+       else if (lev->typ == CORR &&
+                   lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit)
+           show_glyph(x,y, lev->glyph = cmap_to_glyph(S_corr));
+    }
+    /* draw monster on top if we can sense it */
+    if ((x != u.ux || y != u.uy) && (mon = m_at(x,y)) && sensemon(mon))
+       display_monster(x, y, mon,
+               (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)) ? PHYSICALLY_SEEN : DETECTED,
+               is_worm_tail(mon));
+}
+
+/*
+ * newsym()
+ *
+ * Possibly put a new glyph at the given location.
+ */
+void
+newsym(x,y)
+    register int x,y;
+{
+    register struct monst *mon;
+    register struct rm *lev = &(levl[x][y]);
+    register int see_it;
+    register xchar worm_tail;
+
+    if (in_mklev) return;
+
+    /* only permit updating the hero when swallowed */
+    if (u.uswallow) {
+       if (x == u.ux && y == u.uy) display_self();
+       return;
+    }
+    if (Underwater && !Is_waterlevel(&u.uz)) {
+       /* don't do anything unless (x,y) is an adjacent underwater position */
+       int dx, dy;
+       if (!is_pool(x,y)) return;
+       dx = x - u.ux;  if (dx < 0) dx = -dx;
+       dy = y - u.uy;  if (dy < 0) dy = -dy;
+       if (dx > 1 || dy > 1) return;
+    }
+
+    /* Can physically see the location. */
+    if (cansee(x,y)) {
+        NhRegion* reg = visible_region_at(x,y);
+       /*
+        * Don't use templit here:  E.g.
+        *
+        *      lev->waslit = !!(lev->lit || templit(x,y));
+        *
+        * Otherwise we have the "light pool" problem, where non-permanently
+        * lit areas just out of sight stay remembered as lit.  They should
+        * re-darken.
+        *
+        * Perhaps ALL areas should revert to their "unlit" look when
+        * out of sight.
+        */
+       lev->waslit = (lev->lit!=0);    /* remember lit condition */
+
+       if (reg != NULL && ACCESSIBLE(lev->typ)) {
+           show_region(reg,x,y);
+           return;
+       }
+       if (x == u.ux && y == u.uy) {
+           if (senseself()) {
+               _map_location(x,y,0);   /* map *under* self */
+               display_self();
+           } else
+               /* we can see what is there */
+               _map_location(x,y,1);
+       }
+       else {
+           mon = m_at(x,y);
+           worm_tail = is_worm_tail(mon);
+           see_it = mon && (worm_tail
+               ? (!mon->minvis || See_invisible)
+               : (mon_visible(mon)) || tp_sensemon(mon) || MATCH_WARN_OF_MON(mon));
+           if (mon && (see_it || (!worm_tail && Detect_monsters))) {
+               if (mon->mtrapped) {
+                   struct trap *trap = t_at(x, y);
+                   int tt = trap ? trap->ttyp : NO_TRAP;
+
+                   /* if monster is in a physical trap, you see the trap too */
+                   if (tt == BEAR_TRAP || tt == PIT ||
+                       tt == SPIKED_PIT ||tt == WEB) {
+                       trap->tseen = TRUE;
+                   }
+               }
+               _map_location(x,y,0);   /* map under the monster */
+               /* also gets rid of any invisibility glyph */
+               display_monster(x, y, mon, see_it ? PHYSICALLY_SEEN : DETECTED, worm_tail);
+           }
+           else if (mon && mon_warning(mon) && !is_worm_tail(mon))
+               display_warning(mon);
+           else if (glyph_is_invisible(levl[x][y].glyph))
+               map_invisible(x, y);
+           else
+               _map_location(x,y,1);   /* map the location */
+       }
+    }
+
+    /* Can't see the location. */
+    else {
+       if (x == u.ux && y == u.uy) {
+           feel_location(u.ux, u.uy);          /* forces an update */
+
+           if (senseself()) display_self();
+       }
+       else if ((mon = m_at(x,y))
+               && ((see_it = (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)
+                               || (see_with_infrared(mon) && mon_visible(mon))))
+                   || Detect_monsters)
+               && !is_worm_tail(mon)) {
+           /* Monsters are printed every time. */
+           /* This also gets rid of any invisibility glyph */
+           display_monster(x, y, mon, see_it ? 0 : DETECTED, 0);
+       }
+       else if ((mon = m_at(x,y)) && mon_warning(mon) &&
+                !is_worm_tail(mon)) {
+               display_warning(mon);
+       }               
+
+       /*
+        * If the location is remembered as being both dark (waslit is false)
+        * and lit (glyph is a lit room or lit corridor) then it was either:
+        *
+        *      (1) A dark location that the hero could see through night
+        *          vision.
+        *
+        *      (2) Darkened while out of the hero's sight.  This can happen
+        *          when cursed scroll of light is read.
+        *
+        * In either case, we have to manually correct the hero's memory to
+        * match waslit.  Deciding when to change waslit is non-trivial.
+        *
+        *  Note:  If flags.lit_corridor is set, then corridors act like room
+        *         squares.  That is, they light up if in night vision range.
+        *         If flags.lit_corridor is not set, then corridors will
+        *         remain dark unless lit by a light spell and may darken
+        *         again, as discussed above.
+        *
+        * These checks and changes must be here and not in back_to_glyph().
+        * They are dependent on the position being out of sight.
+        */
+       else if (!lev->waslit) {
+           if (lev->glyph == cmap_to_glyph(S_litcorr) && lev->typ == CORR)
+               show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
+           else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM)
+               show_glyph(x, y, lev->glyph = cmap_to_glyph(S_stone));
+           else
+               goto show_mem;
+       } else {
+show_mem:
+           show_glyph(x, y, lev->glyph);
+       }
+    }
+}
+
+#undef is_worm_tail
+
+/*
+ * shieldeff()
+ *
+ * Put magic shield pyrotechnics at the given location.  This *could* be
+ * pulled into a platform dependent routine for fancier graphics if desired.
+ */
+void
+shieldeff(x,y)
+    xchar x,y;
+{
+    register int i;
+
+    if (!flags.sparkle) return;
+    if (cansee(x,y)) { /* Don't see anything if can't see the location */
+       for (i = 0; i < SHIELD_COUNT; i++) {
+           show_glyph(x, y, cmap_to_glyph(shield_static[i]));
+           flush_screen(1);    /* make sure the glyph shows up */
+           delay_output();
+       }
+       newsym(x,y);            /* restore the old information */
+    }
+}
+
+
+/*
+ * tmp_at()
+ *
+ * Temporarily place glyphs on the screen.  Do not call delay_output().  It
+ * is up to the caller to decide if it wants to wait [presently, everyone
+ * but explode() wants to delay].
+ *
+ * Call:
+ *     (DISP_BEAM,   glyph)    open, initialize glyph
+ *     (DISP_FLASH,  glyph)    open, initialize glyph
+ *     (DISP_ALWAYS, glyph)    open, initialize glyph
+ *     (DISP_CHANGE, glyph)    change glyph
+ *     (DISP_END,    0)        close & clean up (second argument doesn't
+ *                             matter)
+ *     (DISP_FREEMEM, 0)       only used to prevent memory leak during
+ *                             exit)
+ *     (x, y)                  display the glyph at the location
+ *
+ * DISP_BEAM  - Display the given glyph at each location, but do not erase
+ *             any until the close call.
+ * DISP_FLASH - Display the given glyph at each location, but erase the
+ *             previous location's glyph.
+ * DISP_ALWAYS- Like DISP_FLASH, but vision is not taken into account.
+ */
+
+static struct tmp_glyph {
+    coord saved[COLNO];        /* previously updated positions */
+    int sidx;          /* index of next unused slot in saved[] */
+    int style;         /* either DISP_BEAM or DISP_FLASH or DISP_ALWAYS */
+    int glyph;         /* glyph to use when printing */
+    struct tmp_glyph *prev;
+} tgfirst;
+
+void
+tmp_at(x, y)
+    int x, y;
+{
+    static struct tmp_glyph *tglyph = (struct tmp_glyph *)0;
+    struct tmp_glyph *tmp;
+
+    switch (x) {
+       case DISP_BEAM:
+       case DISP_FLASH:
+       case DISP_ALWAYS:
+           if (!tglyph)
+               tmp = &tgfirst;
+           else        /* nested effect; we need dynamic memory */
+               tmp = (struct tmp_glyph *)alloc(sizeof (struct tmp_glyph));
+           tmp->prev = tglyph;
+           tglyph = tmp;
+           tglyph->sidx = 0;
+           tglyph->style = x;
+           tglyph->glyph = y;
+           flush_screen(0);    /* flush buffered glyphs */
+           return;
+
+       case DISP_FREEMEM:  /* in case game ends with tmp_at() in progress */
+           while (tglyph) {
+               tmp = tglyph->prev;
+               if (tglyph != &tgfirst) free((genericptr_t)tglyph);
+               tglyph = tmp;
+           }
+           return;
+
+       default:
+           break;
+    }
+
+    if (!tglyph) panic("tmp_at: tglyph not initialized");
+
+    switch (x) {
+       case DISP_CHANGE:
+           tglyph->glyph = y;
+           break;
+
+       case DISP_END:
+           if (tglyph->style == DISP_BEAM) {
+               register int i;
+
+               /* Erase (reset) from source to end */
+               for (i = 0; i < tglyph->sidx; i++)
+                   newsym(tglyph->saved[i].x, tglyph->saved[i].y);
+           } else {            /* DISP_FLASH or DISP_ALWAYS */
+               if (tglyph->sidx)       /* been called at least once */
+                   newsym(tglyph->saved[0].x, tglyph->saved[0].y);
+           }
+        /* tglyph->sidx = 0; -- about to be freed, so not necessary */
+           tmp = tglyph->prev;
+           if (tglyph != &tgfirst) free((genericptr_t)tglyph);
+           tglyph = tmp;
+           break;
+
+       default:        /* do it */
+           if (tglyph->style == DISP_BEAM) {
+               if (!cansee(x,y)) break;
+               /* save pos for later erasing */
+               tglyph->saved[tglyph->sidx].x = x;
+               tglyph->saved[tglyph->sidx].y = y;
+               tglyph->sidx += 1;
+           } else {    /* DISP_FLASH/ALWAYS */
+               if (tglyph->sidx) { /* not first call, so reset previous pos */
+                   newsym(tglyph->saved[0].x, tglyph->saved[0].y);
+                   tglyph->sidx = 0;   /* display is presently up to date */
+               }
+               if (!cansee(x,y) && tglyph->style != DISP_ALWAYS) break;
+               tglyph->saved[0].x = x;
+               tglyph->saved[0].y = y;
+               tglyph->sidx = 1;
+           }
+
+           show_glyph(x, y, tglyph->glyph);    /* show it */
+           flush_screen(0);                    /* make sure it shows up */
+           break;
+    } /* end case */
+}
+
+
+/*
+ * swallowed()
+ *
+ * The hero is swallowed.  Show a special graphics sequence for this.  This
+ * bypasses all of the display routines and messes with buffered screen
+ * directly.  This method works because both vision and display check for
+ * being swallowed.
+ */
+void
+swallowed(first)
+    int first;
+{
+    static xchar lastx, lasty; /* last swallowed position */
+    int swallower, left_ok, rght_ok;
+
+    if (first)
+       cls();
+    else {
+       register int x, y;
+
+       /* Clear old location */
+       for (y = lasty-1; y <= lasty+1; y++)
+           for (x = lastx-1; x <= lastx+1; x++)
+               if (isok(x,y)) show_glyph(x,y,cmap_to_glyph(S_stone));
+    }
+
+    swallower = monsndx(u.ustuck->data);
+    /* assume isok(u.ux,u.uy) */
+    left_ok = isok(u.ux-1,u.uy);
+    rght_ok = isok(u.ux+1,u.uy);
+    /*
+     *  Display the hero surrounded by the monster's stomach.
+     */
+    if(isok(u.ux, u.uy-1)) {
+       if (left_ok)
+       show_glyph(u.ux-1, u.uy-1, swallow_to_glyph(swallower, S_sw_tl));
+       show_glyph(u.ux  , u.uy-1, swallow_to_glyph(swallower, S_sw_tc));
+       if (rght_ok)
+       show_glyph(u.ux+1, u.uy-1, swallow_to_glyph(swallower, S_sw_tr));
+    }
+
+    if (left_ok)
+    show_glyph(u.ux-1, u.uy  , swallow_to_glyph(swallower, S_sw_ml));
+    display_self();
+    if (rght_ok)
+    show_glyph(u.ux+1, u.uy  , swallow_to_glyph(swallower, S_sw_mr));
+
+    if(isok(u.ux, u.uy+1)) {
+       if (left_ok)
+       show_glyph(u.ux-1, u.uy+1, swallow_to_glyph(swallower, S_sw_bl));
+       show_glyph(u.ux  , u.uy+1, swallow_to_glyph(swallower, S_sw_bc));
+       if (rght_ok)
+       show_glyph(u.ux+1, u.uy+1, swallow_to_glyph(swallower, S_sw_br));
+    }
+
+    /* Update the swallowed position. */
+    lastx = u.ux;
+    lasty = u.uy;
+}
+
+/*
+ * under_water()
+ *
+ * Similar to swallowed() in operation.  Shows hero when underwater
+ * except when in water level.  Special routines exist for that.
+ */
+void
+under_water(mode)
+    int mode;
+{
+    static xchar lastx, lasty;
+    static boolean dela;
+    register int x, y;
+
+    /* swallowing has a higher precedence than under water */
+    if (Is_waterlevel(&u.uz) || u.uswallow) return;
+
+    /* full update */
+    if (mode == 1 || dela) {
+       cls();
+       dela = FALSE;
+    }
+    /* delayed full update */
+    else if (mode == 2) {
+       dela = TRUE;
+       return;
+    }
+    /* limited update */
+    else {
+       for (y = lasty-1; y <= lasty+1; y++)
+           for (x = lastx-1; x <= lastx+1; x++)
+               if (isok(x,y))
+                   show_glyph(x,y,cmap_to_glyph(S_stone));
+    }
+    for (x = u.ux-1; x <= u.ux+1; x++)
+       for (y = u.uy-1; y <= u.uy+1; y++)
+           if (isok(x,y) && is_pool(x,y)) {
+               if (Blind && !(x == u.ux && y == u.uy))
+                   show_glyph(x,y,cmap_to_glyph(S_stone));
+               else    
+                   newsym(x,y);
+           }
+    lastx = u.ux;
+    lasty = u.uy;
+}
+
+/*
+ *     under_ground()
+ *
+ *     Very restricted display.  You can only see yourself.
+ */
+void
+under_ground(mode)
+    int mode;
+{
+    static boolean dela;
+
+    /* swallowing has a higher precedence than under ground */
+    if (u.uswallow) return;
+
+    /* full update */
+    if (mode == 1 || dela) {
+       cls();
+       dela = FALSE;
+    }
+    /* delayed full update */
+    else if (mode == 2) {
+       dela = TRUE;
+       return;
+    }
+    /* limited update */
+    else
+       newsym(u.ux,u.uy);
+}
+
+
+/* ========================================================================= */
+
+/*
+ * Loop through all of the monsters and update them.  Called when:
+ *     + going blind & telepathic
+ *     + regaining sight & telepathic
+ *      + getting and losing infravision 
+ *     + hallucinating
+ *     + doing a full screen redraw
+ *     + see invisible times out or a ring of see invisible is taken off
+ *     + when a potion of see invisible is quaffed or a ring of see
+ *       invisible is put on
+ *     + gaining telepathy when blind [givit() in eat.c, pleased() in pray.c]
+ *     + losing telepathy while blind [xkilled() in mon.c, attrcurse() in
+ *       sit.c]
+ */
+void
+see_monsters()
+{
+    register struct monst *mon;
+
+    for (mon = fmon; mon; mon = mon->nmon) {
+       if (DEADMONSTER(mon)) continue;
+       newsym(mon->mx,mon->my);
+       if (mon->wormno) see_wsegs(mon);
+    }
+#ifdef STEED
+    /* when mounted, hero's location gets caught by monster loop */
+    if (!u.usteed)
+#endif
+    newsym(u.ux, u.uy);
+}
+
+/*
+ * Block/unblock light depending on what a mimic is mimicing and if it's
+ * invisible or not.  Should be called only when the state of See_invisible
+ * changes.
+ */
+void
+set_mimic_blocking()
+{
+    register struct monst *mon;
+
+    for (mon = fmon; mon; mon = mon->nmon) {
+       if (DEADMONSTER(mon)) continue;
+       if (mon->minvis &&
+          ((mon->m_ap_type == M_AP_FURNITURE &&
+            (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor)) ||
+           (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) {
+           if(See_invisible)
+               block_point(mon->mx, mon->my);
+           else
+               unblock_point(mon->mx, mon->my);
+       }
+    }
+}
+
+/*
+ * Loop through all of the object *locations* and update them.  Called when
+ *     + hallucinating.
+ */
+void
+see_objects()
+{
+    register struct obj *obj;
+    for(obj = fobj; obj; obj = obj->nobj)
+       if (vobj_at(obj->ox,obj->oy) == obj) newsym(obj->ox, obj->oy);
+}
+
+/*
+ * Update hallucinated traps.
+ */
+void
+see_traps()
+{
+    struct trap *trap;
+    int glyph;
+
+    for (trap = ftrap; trap; trap = trap->ntrap) {
+       glyph = glyph_at(trap->tx, trap->ty);
+       if (glyph_is_trap(glyph))
+           newsym(trap->tx, trap->ty);
+    }
+}
+
+/*
+ * Put the cursor on the hero.  Flush all accumulated glyphs before doing it.
+ */
+void
+curs_on_u()
+{
+    flush_screen(1);   /* Flush waiting glyphs & put cursor on hero */
+}
+
+int
+doredraw()
+{
+    docrt();
+    return 0;
+}
+
+void
+docrt()
+{
+    register int x,y;
+    register struct rm *lev;
+
+    if (!u.ux) return; /* display isn't ready yet */
+
+    if (u.uswallow) {
+       swallowed(1);
+       return;
+    }
+    if (Underwater && !Is_waterlevel(&u.uz)) {
+       under_water(1);
+       return;
+    }
+    if (u.uburied) {
+       under_ground(1);
+       return;
+    }
+
+    /* shut down vision */
+    vision_recalc(2);
+
+    /*
+     * This routine assumes that cls() does the following:
+     *      + fills the physical screen with the symbol for rock
+     *      + clears the glyph buffer
+     */
+    cls();
+
+    /* display memory */
+    for (x = 1; x < COLNO; x++) {
+       lev = &levl[x][0];
+       for (y = 0; y < ROWNO; y++, lev++)
+           if (lev->glyph != cmap_to_glyph(S_stone))
+               show_glyph(x,y,lev->glyph);
+    }
+
+    /* see what is to be seen */
+    vision_recalc(0);
+
+    /* overlay with monsters */
+    see_monsters();
+
+    flags.botlx = 1;   /* force a redraw of the bottom line */
+}
+
+
+/* ========================================================================= */
+/* Glyph Buffering (3rd screen) ============================================ */
+
+typedef struct {
+    xchar new;         /* perhaps move this bit into the rm strucure. */
+    int   glyph;
+} gbuf_entry;
+
+static gbuf_entry gbuf[ROWNO][COLNO];
+static char gbuf_start[ROWNO];
+static char gbuf_stop[ROWNO];
+
+/*
+ * Store the glyph in the 3rd screen for later flushing.
+ */
+void
+show_glyph(x,y,glyph)
+    int x, y, glyph;
+{
+    /*
+     * Check for bad positions and glyphs.
+     */
+    if (!isok(x, y)) {
+       const char *text;
+       int  offset;
+
+       /* column 0 is invalid, but it's often used as a flag, so ignore it */
+       if (x == 0) return;
+
+       /*
+        *  This assumes an ordering of the offsets.  See display.h for
+        *  the definition.
+        */
+
+       if (glyph >= GLYPH_WARNING_OFF) {       /* a warning */
+           text = "warning";           offset = glyph - GLYPH_WARNING_OFF;
+       } else if (glyph >= GLYPH_SWALLOW_OFF) {        /* swallow border */
+           text = "swallow border";    offset = glyph - GLYPH_SWALLOW_OFF;
+       } else if (glyph >= GLYPH_ZAP_OFF) {            /* zap beam */
+           text = "zap beam";          offset = glyph - GLYPH_ZAP_OFF;
+       } else if (glyph >= GLYPH_EXPLODE_OFF) {        /* explosion */
+           text = "explosion";         offset = glyph - GLYPH_EXPLODE_OFF;
+       } else if (glyph >= GLYPH_CMAP_OFF) {           /* cmap */
+           text = "cmap_index";        offset = glyph - GLYPH_CMAP_OFF;
+       } else if (glyph >= GLYPH_OBJ_OFF) {            /* object */
+           text = "object";            offset = glyph - GLYPH_OBJ_OFF;
+       } else if (glyph >= GLYPH_RIDDEN_OFF) {         /* ridden mon */
+           text = "ridden mon";        offset = glyph - GLYPH_RIDDEN_OFF;
+       } else if (glyph >= GLYPH_BODY_OFF) {           /* a corpse */
+           text = "corpse";            offset = glyph - GLYPH_BODY_OFF;
+       } else if (glyph >= GLYPH_DETECT_OFF) {         /* detected mon */
+           text = "detected mon";      offset = glyph - GLYPH_DETECT_OFF;
+       } else if (glyph >= GLYPH_INVIS_OFF) {          /* invisible mon */
+           text = "invisible mon";     offset = glyph - GLYPH_INVIS_OFF;
+       } else if (glyph >= GLYPH_PET_OFF) {            /* a pet */
+           text = "pet";               offset = glyph - GLYPH_PET_OFF;
+       } else {                                        /* a monster */
+           text = "monster";           offset = glyph;
+       }
+
+       impossible("show_glyph:  bad pos %d %d with glyph %d [%s %d].",
+                                               x, y, glyph, text, offset);
+       return;
+    }
+
+    if (glyph >= MAX_GLYPH) {
+       impossible("show_glyph:  bad glyph %d [max %d] at (%d,%d).",
+                                       glyph, MAX_GLYPH, x, y);
+       return;
+    }
+
+    if (gbuf[y][x].glyph != glyph) {
+       gbuf[y][x].glyph = glyph;
+       gbuf[y][x].new   = 1;
+       if (gbuf_start[y] > x) gbuf_start[y] = x;
+       if (gbuf_stop[y]  < x) gbuf_stop[y]  = x;
+    }
+}
+
+
+/*
+ * Reset the changed glyph borders so that none of the 3rd screen has
+ * changed.
+ */
+#define reset_glyph_bbox()                     \
+    {                                          \
+       int i;                                  \
+                                               \
+       for (i = 0; i < ROWNO; i++) {           \
+           gbuf_start[i] = COLNO-1;            \
+           gbuf_stop[i]  = 0;                  \
+       }                                       \
+    }
+
+
+static gbuf_entry nul_gbuf = { 0, cmap_to_glyph(S_stone) };
+/*
+ * Turn the 3rd screen into stone.
+ */
+void
+clear_glyph_buffer()
+{
+    register int x, y;
+    register gbuf_entry *gptr;
+
+    for (y = 0; y < ROWNO; y++) {
+       gptr = &gbuf[y][0];
+       for (x = COLNO; x; x--) {
+           *gptr++ = nul_gbuf;
+       }
+    }
+    reset_glyph_bbox();
+}
+
+/*
+ * Assumes that the indicated positions are filled with S_stone glyphs.
+ */
+void
+row_refresh(start,stop,y)
+    int start,stop,y;
+{
+    register int x;
+
+    for (x = start; x <= stop; x++)
+       if (gbuf[y][x].glyph != cmap_to_glyph(S_stone))
+           print_glyph(WIN_MAP,x,y,gbuf[y][x].glyph);
+}
+
+void
+cls()
+{
+    display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */
+    flags.botlx = 1;           /* force update of botl window */
+    clear_nhwindow(WIN_MAP);   /* clear physical screen */
+
+    clear_glyph_buffer();      /* this is sort of an extra effort, but OK */
+}
+
+/*
+ * Synch the third screen with the display.
+ */
+void
+flush_screen(cursor_on_u)
+    int cursor_on_u;
+{
+    /* Prevent infinite loops on errors:
+     *     flush_screen->print_glyph->impossible->pline->flush_screen
+     */
+    static   boolean flushing = 0;
+    static   boolean delay_flushing = 0;
+    register int x,y;
+
+    if (cursor_on_u == -1) delay_flushing = !delay_flushing;
+    if (delay_flushing) return;
+    if (flushing) return;      /* if already flushing then return */
+    flushing = 1;
+
+    for (y = 0; y < ROWNO; y++) {
+       register gbuf_entry *gptr = &gbuf[y][x = gbuf_start[y]];
+       for (; x <= gbuf_stop[y]; gptr++, x++)
+           if (gptr->new) {
+               print_glyph(WIN_MAP,x,y,gptr->glyph);
+               gptr->new = 0;
+           }
+    }
+
+    if (cursor_on_u) curs(WIN_MAP, u.ux,u.uy); /* move cursor to the hero */
+    display_nhwindow(WIN_MAP, FALSE);
+    reset_glyph_bbox();
+    flushing = 0;
+    if(flags.botl || flags.botlx) bot();
+}
+
+/* ========================================================================= */
+
+/*
+ * back_to_glyph()
+ *
+ * Use the information in the rm structure at the given position to create
+ * a glyph of a background.
+ *
+ * I had to add a field in the rm structure (horizontal) so that we knew
+ * if open doors and secret doors were horizontal or vertical.  Previously,
+ * the screen symbol had the horizontal/vertical information set at
+ * level generation time.
+ *
+ * I used the 'ladder' field (really doormask) for deciding if stairwells
+ * were up or down.  I didn't want to check the upstairs and dnstairs
+ * variables.
+ */
+int
+back_to_glyph(x,y)
+    xchar x,y;
+{
+    int idx;
+    struct rm *ptr = &(levl[x][y]);
+
+    switch (ptr->typ) {
+       case SCORR:
+       case STONE:
+           idx = level.flags.arboreal ? S_tree : S_stone;
+           break;
+       case ROOM:              idx = S_room;     break;
+       case CORR:
+           idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr;
+           break;
+       case HWALL:
+       case VWALL:
+       case TLCORNER:
+       case TRCORNER:
+       case BLCORNER:
+       case BRCORNER:
+       case CROSSWALL:
+       case TUWALL:
+       case TDWALL:
+       case TLWALL:
+       case TRWALL:
+       case SDOOR:
+           idx = ptr->seenv ? wall_angle(ptr) : S_stone;
+           break;
+       case DOOR:
+           if (ptr->doormask) {
+               if (ptr->doormask & D_BROKEN)
+                   idx = S_ndoor;
+               else if (ptr->doormask & D_ISOPEN)
+                   idx = (ptr->horizontal) ? S_hodoor : S_vodoor;
+               else                    /* else is closed */
+                   idx = (ptr->horizontal) ? S_hcdoor : S_vcdoor;
+           } else
+               idx = S_ndoor;
+           break;
+       case IRONBARS:  idx = S_bars;     break;
+       case TREE:              idx = S_tree;     break;
+       case POOL:
+       case MOAT:              idx = S_pool;     break;
+       case STAIRS:
+           idx = (ptr->ladder & LA_DOWN) ? S_dnstair : S_upstair;
+           break;
+       case LADDER:
+           idx = (ptr->ladder & LA_DOWN) ? S_dnladder : S_upladder;
+           break;
+       case FOUNTAIN:          idx = S_fountain; break;
+       case SINK:              idx = S_sink;     break;
+       case ALTAR:             idx = S_altar;    break;
+       case GRAVE:             idx = S_grave;    break;
+       case THRONE:            idx = S_throne;   break;
+       case LAVAPOOL:          idx = S_lava;     break;
+       case ICE:               idx = S_ice;      break;
+       case AIR:               idx = S_air;      break;
+       case CLOUD:             idx = S_cloud;    break;
+       case WATER:             idx = S_water;    break;
+       case DBWALL:
+           idx = (ptr->horizontal) ? S_hcdbridge : S_vcdbridge;
+           break;
+       case DRAWBRIDGE_UP:
+           switch(ptr->drawbridgemask & DB_UNDER) {
+           case DB_MOAT:  idx = S_pool; break;
+           case DB_LAVA:  idx = S_lava; break;
+           case DB_ICE:   idx = S_ice;  break;
+           case DB_FLOOR: idx = S_room; break;
+           default:
+               impossible("Strange db-under: %d",
+                          ptr->drawbridgemask & DB_UNDER);
+               idx = S_room; /* something is better than nothing */
+               break;
+           }
+           break;
+       case DRAWBRIDGE_DOWN:
+           idx = (ptr->horizontal) ? S_hodbridge : S_vodbridge;
+           break;
+       default:
+           impossible("back_to_glyph:  unknown level type [ = %d ]",ptr->typ);
+           idx = S_room;
+           break;
+    }
+
+    return cmap_to_glyph(idx);
+}
+
+
+/*
+ * swallow_to_glyph()
+ *
+ * Convert a monster number and a swallow location into the correct glyph.
+ * If you don't want a patchwork monster while hallucinating, decide on
+ * a random monster in swallowed() and don't use what_mon() here.
+ */
+STATIC_OVL int
+swallow_to_glyph(mnum, loc)
+    int mnum;
+    int loc;
+{
+    if (loc < S_sw_tl || S_sw_br < loc) {
+       impossible("swallow_to_glyph: bad swallow location");
+       loc = S_sw_br;
+    }
+    return ((int) (what_mon(mnum)<<3) | (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF;
+}
+
+
+
+/*
+ * zapdir_to_glyph()
+ *
+ * Change the given zap direction and beam type into a glyph.  Each beam
+ * type has four glyphs, one for each of the symbols below.  The order of
+ * the zap symbols [0-3] as defined in rm.h are:
+ *
+ *     |  S_vbeam      ( 0, 1) or ( 0,-1)
+ *     -  S_hbeam      ( 1, 0) or (-1, 0)
+ *     \  S_lslant     ( 1, 1) or (-1,-1)
+ *     /  S_rslant     (-1, 1) or ( 1,-1)
+ */
+int
+zapdir_to_glyph(dx, dy, beam_type)
+    register int dx, dy;
+    int beam_type;
+{
+    if (beam_type >= NUM_ZAP) {
+       impossible("zapdir_to_glyph:  illegal beam type");
+       beam_type = 0;
+    }
+    dx = (dx == dy) ? 2 : (dx && dy) ? 3 : dx ? 1 : 0;
+
+    return ((int) ((beam_type << 2) | dx)) + GLYPH_ZAP_OFF;
+}
+
+
+/*
+ * Utility routine for dowhatis() used to find out the glyph displayed at
+ * the location.  This isn't necessarily the same as the glyph in the levl
+ * structure, so we must check the "third screen".
+ */
+int
+glyph_at(x, y)
+    xchar x,y;
+{
+    if(x < 0 || y < 0 || x >= COLNO || y >= ROWNO)
+       return cmap_to_glyph(S_room);                   /* XXX */
+    return gbuf[y][x].glyph;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* Wall Angle -------------------------------------------------------------- */
+
+/*#define WA_VERBOSE*/ /* give (x,y) locations for all "bad" spots */
+
+#ifdef WA_VERBOSE
+
+static const char *FDECL(type_to_name, (int));
+static void FDECL(error4, (int,int,int,int,int,int));
+
+static int bad_count[MAX_TYPE]; /* count of positions flagged as bad */
+static const char *type_names[MAX_TYPE] = {
+       "STONE",        "VWALL",        "HWALL",        "TLCORNER",
+       "TRCORNER",     "BLCORNER",     "BRCORNER",     "CROSSWALL",
+       "TUWALL",       "TDWALL",       "TLWALL",       "TRWALL",
+       "DBWALL",       "SDOOR",        "SCORR",        "POOL",
+       "MOAT",         "WATER",        "DRAWBRIDGE_UP","LAVAPOOL",
+       "DOOR",         "CORR",         "ROOM",         "STAIRS",
+       "LADDER",       "FOUNTAIN",     "THRONE",       "SINK",
+       "ALTAR",        "ICE",          "DRAWBRIDGE_DOWN","AIR",
+       "CLOUD"
+};
+
+
+static const char *
+type_to_name(type)
+    int type;
+{
+    return (type < 0 || type > MAX_TYPE) ? "unknown" : type_names[type];
+}
+
+static void
+error4(x, y, a, b, c, dd)
+    int x, y, a, b, c, dd;
+{
+    pline("set_wall_state: %s @ (%d,%d) %s%s%s%s",
+       type_to_name(levl[x][y].typ), x, y,
+       a ? "1":"", b ? "2":"", c ? "3":"", dd ? "4":"");
+    bad_count[levl[x][y].typ]++;
+}
+#endif /* WA_VERBOSE */
+
+/*
+ * Return 'which' if position is implies an unfinshed exterior.  Return
+ * zero otherwise.  Unfinished implies outer area is rock or a corridor.
+ *
+ * Things that are ambigious: lava
+ */
+STATIC_OVL int
+check_pos(x, y, which)
+    int x, y, which;
+{
+    int type;
+    if (!isok(x,y)) return which;
+    type = levl[x][y].typ;
+    if (IS_ROCK(type) || type == CORR || type == SCORR) return which;
+    return 0;
+}
+
+/* Return TRUE if more than one is non-zero. */
+/*ARGSUSED*/
+#ifdef WA_VERBOSE
+STATIC_OVL boolean
+more_than_one(x, y, a, b, c)
+    int x, y, a, b, c;
+{
+    if ((a && (b|c)) || (b && (a|c)) || (c && (a|b))) {
+       error4(x,y,a,b,c,0);
+       return TRUE;
+    }
+    return FALSE;
+}
+#else
+#define more_than_one(x, y, a, b, c) (((a) && ((b)|(c))) || ((b) && ((a)|(c))) || ((c) && ((a)|(b))))
+#endif
+
+/* Return the wall mode for a T wall. */
+STATIC_OVL int
+set_twall(x0,y0, x1,y1, x2,y2, x3,y3)
+int x0,y0, x1,y1, x2,y2, x3,y3;
+{
+    int wmode, is_1, is_2, is_3;
+
+    is_1 = check_pos(x1, y1, WM_T_LONG);
+    is_2 = check_pos(x2, y2, WM_T_BL);
+    is_3 = check_pos(x3, y3, WM_T_BR);
+    if (more_than_one(x0, y0, is_1, is_2, is_3)) {
+       wmode = 0;
+    } else {
+       wmode = is_1 + is_2 + is_3;
+    }
+    return wmode;
+}
+
+/* Return wall mode for a horizontal or vertical wall. */
+STATIC_OVL int
+set_wall(x, y, horiz)
+    int x, y, horiz;
+{
+    int wmode, is_1, is_2;
+
+    if (horiz) {
+       is_1 = check_pos(x,y-1, WM_W_TOP);
+       is_2 = check_pos(x,y+1, WM_W_BOTTOM);
+    } else {
+       is_1 = check_pos(x-1,y, WM_W_LEFT);
+       is_2 = check_pos(x+1,y, WM_W_RIGHT);
+    }
+    if (more_than_one(x, y, is_1, is_2, 0)) {
+       wmode = 0;
+    } else {
+       wmode = is_1 + is_2;
+    }
+    return wmode;
+}
+
+
+/* Return a wall mode for a corner wall. (x4,y4) is the "inner" position. */
+STATIC_OVL int
+set_corn(x1,y1, x2,y2, x3,y3, x4,y4)
+       int x1, y1, x2, y2, x3, y3, x4, y4;
+{
+    int wmode, is_1, is_2, is_3, is_4;
+
+    is_1 = check_pos(x1, y1, 1);
+    is_2 = check_pos(x2, y2, 1);
+    is_3 = check_pos(x3, y3, 1);
+    is_4 = check_pos(x4, y4, 1);       /* inner location */
+
+    /*
+     * All 4 should not be true.  So if the inner location is rock,
+     * use it.  If all of the outer 3 are true, use outer.  We currently
+     * can't cover the case where only part of the outer is rock, so
+     * we just say that all the walls are finished (if not overridden
+     * by the inner section).
+     */
+    if (is_4) {
+       wmode = WM_C_INNER;
+    } else if (is_1 && is_2 && is_3)
+       wmode = WM_C_OUTER;
+     else
+       wmode = 0;      /* finished walls on all sides */
+
+    return wmode;
+}
+
+/* Return mode for a crosswall. */
+STATIC_OVL int
+set_crosswall(x, y)
+    int x, y;
+{
+    int wmode, is_1, is_2, is_3, is_4;
+
+    is_1 = check_pos(x-1, y-1, 1);
+    is_2 = check_pos(x+1, y-1, 1);
+    is_3 = check_pos(x+1, y+1, 1);
+    is_4 = check_pos(x-1, y+1, 1);
+
+    wmode = is_1+is_2+is_3+is_4;
+    if (wmode > 1) {
+       if (is_1 && is_3 && (is_2+is_4 == 0)) {
+           wmode = WM_X_TLBR;
+       } else if (is_2 && is_4 && (is_1+is_3 == 0)) {
+           wmode = WM_X_BLTR;
+       } else {
+#ifdef WA_VERBOSE
+           error4(x,y,is_1,is_2,is_3,is_4);
+#endif
+           wmode = 0;
+       }
+    } else if (is_1)
+       wmode = WM_X_TL;
+    else if (is_2)
+       wmode = WM_X_TR;
+    else if (is_3)
+       wmode = WM_X_BR;
+    else if (is_4)
+       wmode = WM_X_BL;
+
+    return wmode;
+}
+
+/* Called from mklev.  Scan the level and set the wall modes. */
+void
+set_wall_state()
+{
+    int x, y;
+    int wmode;
+    struct rm *lev;
+
+#ifdef WA_VERBOSE
+    for (x = 0; x < MAX_TYPE; x++) bad_count[x] = 0;
+#endif
+
+    for (x = 0; x < COLNO; x++)
+       for (lev = &levl[x][0], y = 0; y < ROWNO; y++, lev++) {
+           switch (lev->typ) {
+               case SDOOR:
+                   wmode = set_wall(x, y, (int) lev->horizontal);
+                   break;
+               case VWALL:
+                   wmode = set_wall(x, y, 0);
+                   break;
+               case HWALL:
+                   wmode = set_wall(x, y, 1);
+                   break;
+               case TDWALL:
+                   wmode = set_twall(x,y, x,y-1, x-1,y+1, x+1,y+1);
+                   break;
+               case TUWALL:
+                   wmode = set_twall(x,y, x,y+1, x+1,y-1, x-1,y-1);
+                   break;
+               case TLWALL:
+                   wmode = set_twall(x,y, x+1,y, x-1,y-1, x-1,y+1);
+                   break;
+               case TRWALL:
+                   wmode = set_twall(x,y, x-1,y, x+1,y+1, x+1,y-1);
+                   break;
+               case TLCORNER:
+                   wmode = set_corn(x-1,y-1, x,y-1, x-1,y, x+1,y+1);
+                   break;
+               case TRCORNER:
+                   wmode = set_corn(x,y-1, x+1,y-1, x+1,y, x-1,y+1);
+                   break;
+               case BLCORNER:
+                   wmode = set_corn(x,y+1, x-1,y+1, x-1,y, x+1,y-1);
+                   break;
+               case BRCORNER:
+                   wmode = set_corn(x+1,y, x+1,y+1, x,y+1, x-1,y-1);
+                   break;
+               case CROSSWALL:
+                   wmode = set_crosswall(x, y);
+                   break;
+
+               default:
+                   wmode = -1; /* don't set wall info */
+                   break;
+           }
+
+       if (wmode >= 0)
+           lev->wall_info = (lev->wall_info & ~WM_MASK) | wmode;
+       }
+
+#ifdef WA_VERBOSE
+    /* check if any bad positions found */
+    for (x = y = 0; x < MAX_TYPE; x++)
+       if (bad_count[x]) {
+           if (y == 0) {
+               y = 1;  /* only print once */
+               pline("set_wall_type: wall mode problems with: ");
+           }
+           pline("%s %d;", type_names[x], bad_count[x]);
+       }
+#endif /* WA_VERBOSE */
+}
+
+/* ------------------------------------------------------------------------- */
+/* This matrix is used here and in vision.c. */
+unsigned char seenv_matrix[3][3] = { {SV2,   SV1, SV0},
+                                    {SV3, SVALL, SV7},
+                                    {SV4,   SV5, SV6} };
+
+#define sign(z) ((z) < 0 ? -1 : ((z) > 0 ? 1 : 0))
+
+/* Set the seen vector of lev as if seen from (x0,y0) to (x,y). */
+STATIC_OVL void
+set_seenv(lev, x0, y0, x, y)
+    struct rm *lev;
+    int x0, y0, x, y;  /* from, to */
+{
+    int dx = x-x0, dy = y0-y;
+    lev->seenv |= seenv_matrix[sign(dy)+1][sign(dx)+1];
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* T wall types, one for each row in wall_matrix[][]. */
+#define T_d 0
+#define T_l 1
+#define T_u 2
+#define T_r 3
+
+/*
+ * These are the column names of wall_matrix[][].  They are the "results"
+ * of a tdwall pattern match.  All T walls are rotated so they become
+ * a tdwall.  Then we do a single pattern match, but return the
+ * correct result for the original wall by using different rows for
+ * each of the wall types.
+ */
+#define T_stone  0
+#define T_tlcorn 1
+#define T_trcorn 2
+#define T_hwall  3
+#define T_tdwall 4
+
+static const int wall_matrix[4][5] = {
+    { S_stone, S_tlcorn, S_trcorn, S_hwall, S_tdwall },        /* tdwall */
+    { S_stone, S_trcorn, S_brcorn, S_vwall, S_tlwall },        /* tlwall */
+    { S_stone, S_brcorn, S_blcorn, S_hwall, S_tuwall },        /* tuwall */
+    { S_stone, S_blcorn, S_tlcorn, S_vwall, S_trwall },        /* trwall */
+};
+
+
+/* Cross wall types, one for each "solid" quarter.  Rows of cross_matrix[][]. */
+#define C_bl 0
+#define C_tl 1
+#define C_tr 2
+#define C_br 3
+
+/*
+ * These are the column names for cross_matrix[][].  They express results
+ * in C_br (bottom right) terms.  All crosswalls with a single solid
+ * quarter are rotated so the solid section is at the bottom right.
+ * We pattern match on that, but return the correct result depending
+ * on which row we'ere looking at.
+ */
+#define C_trcorn 0
+#define C_brcorn 1
+#define C_blcorn 2
+#define C_tlwall 3
+#define C_tuwall 4
+#define C_crwall 5
+
+static const int cross_matrix[4][6] = {
+    { S_brcorn, S_blcorn, S_tlcorn, S_tuwall, S_trwall, S_crwall },
+    { S_blcorn, S_tlcorn, S_trcorn, S_trwall, S_tdwall, S_crwall },
+    { S_tlcorn, S_trcorn, S_brcorn, S_tdwall, S_tlwall, S_crwall },
+    { S_trcorn, S_brcorn, S_blcorn, S_tlwall, S_tuwall, S_crwall },
+};
+
+
+/* Print out a T wall warning and all interesting info. */
+STATIC_OVL void
+t_warn(lev)
+    struct rm *lev;
+{
+    static const char warn_str[] = "wall_angle: %s: case %d: seenv = 0x%x";
+    const char *wname;
+
+    if (lev->typ == TUWALL) wname = "tuwall";
+    else if (lev->typ == TLWALL) wname = "tlwall";
+    else if (lev->typ == TRWALL) wname = "trwall";
+    else if (lev->typ == TDWALL) wname = "tdwall";
+    else wname = "unknown";
+    impossible(warn_str, wname, lev->wall_info & WM_MASK,
+       (unsigned int) lev->seenv);
+}
+
+
+/*
+ * Return the correct graphics character index using wall type, wall mode,
+ * and the seen vector.  It is expected that seenv is non zero.
+ *
+ * All T-wall vectors are rotated to be TDWALL.  All single crosswall
+ * blocks are rotated to bottom right.  All double crosswall are rotated
+ * to W_X_BLTR.  All results are converted back.
+ *
+ * The only way to understand this is to take out pen and paper and
+ * draw diagrams.  See rm.h for more details on the wall modes and
+ * seen vector (SV).
+ */
+STATIC_OVL int
+wall_angle(lev)
+    struct rm *lev;
+{
+    register unsigned int seenv = lev->seenv & 0xff;
+    const int *row;
+    int col, idx;
+
+#define only(sv, bits) (((sv) & (bits)) && ! ((sv) & ~(bits)))
+    switch (lev->typ) {
+       case TUWALL:
+               row = wall_matrix[T_u];
+               seenv = (seenv >> 4 | seenv << 4) & 0xff;/* rotate to tdwall */
+               goto do_twall;
+       case TLWALL:
+               row = wall_matrix[T_l];
+               seenv = (seenv >> 2 | seenv << 6) & 0xff;/* rotate to tdwall */
+               goto do_twall;
+       case TRWALL:
+               row = wall_matrix[T_r];
+               seenv = (seenv >> 6 | seenv << 2) & 0xff;/* rotate to tdwall */
+               goto do_twall;
+       case TDWALL:
+               row = wall_matrix[T_d];
+do_twall:
+               switch (lev->wall_info & WM_MASK) {
+                   case 0:
+                       if (seenv == SV4) {
+                           col = T_tlcorn;
+                       } else if (seenv == SV6) {
+                           col = T_trcorn;
+                       } else if (seenv & (SV3|SV5|SV7) ||
+                                           ((seenv & SV4) && (seenv & SV6))) {
+                           col = T_tdwall;
+                       } else if (seenv & (SV0|SV1|SV2)) {
+                           col = (seenv & (SV4|SV6) ? T_tdwall : T_hwall);
+                       } else {
+                           t_warn(lev);
+                           col = T_stone;
+                       }
+                       break;
+                   case WM_T_LONG:
+                       if (seenv & (SV3|SV4) && !(seenv & (SV5|SV6|SV7))) {
+                           col = T_tlcorn;
+                       } else if (seenv&(SV6|SV7) && !(seenv&(SV3|SV4|SV5))) {
+                           col = T_trcorn;
+                       } else if ((seenv & SV5) ||
+                               ((seenv & (SV3|SV4)) && (seenv & (SV6|SV7)))) {
+                           col = T_tdwall;
+                       } else {
+                           /* only SV0|SV1|SV2 */
+                           if (! only(seenv, SV0|SV1|SV2) )
+                               t_warn(lev);
+                           col = T_stone;
+                       }
+                       break;
+                   case WM_T_BL:
+#if 0  /* older method, fixed */
+                       if (only(seenv, SV4|SV5)) {
+                           col = T_tlcorn;
+                       } else if ((seenv & (SV0|SV1|SV2)) &&
+                                       only(seenv, SV0|SV1|SV2|SV6|SV7)) {
+                           col = T_hwall;
+                       } else if (seenv & SV3 ||
+                           ((seenv & (SV0|SV1|SV2)) && (seenv & (SV4|SV5)))) {
+                           col = T_tdwall;
+                       } else {
+                           if (seenv != SV6)
+                               t_warn(lev);
+                           col = T_stone;
+                       }
+#endif /* 0 */
+                       if (only(seenv, SV4|SV5))
+                           col = T_tlcorn;
+                       else if ((seenv & (SV0|SV1|SV2|SV7)) &&
+                                       !(seenv & (SV3|SV4|SV5)))
+                           col = T_hwall;
+                       else if (only(seenv, SV6))
+                           col = T_stone;
+                       else
+                           col = T_tdwall;
+                       break;
+                   case WM_T_BR:
+#if 0  /* older method, fixed */
+                       if (only(seenv, SV5|SV6)) {
+                           col = T_trcorn;
+                       } else if ((seenv & (SV0|SV1|SV2)) &&
+                                           only(seenv, SV0|SV1|SV2|SV3|SV4)) {
+                           col = T_hwall;
+                       } else if (seenv & SV7 ||
+                           ((seenv & (SV0|SV1|SV2)) && (seenv & (SV5|SV6)))) {
+                           col = T_tdwall;
+                       } else {
+                           if (seenv != SV4)
+                               t_warn(lev);
+                           col = T_stone;
+                       }
+#endif /* 0 */
+                       if (only(seenv, SV5|SV6))
+                           col = T_trcorn;
+                       else if ((seenv & (SV0|SV1|SV2|SV3)) &&
+                                       !(seenv & (SV5|SV6|SV7)))
+                           col = T_hwall;
+                       else if (only(seenv, SV4))
+                           col = T_stone;
+                       else
+                           col = T_tdwall;
+
+                       break;
+                   default:
+                       impossible("wall_angle: unknown T wall mode %d",
+                               lev->wall_info & WM_MASK);
+                       col = T_stone;
+                       break;
+               }
+               idx = row[col];
+               break;
+
+       case SDOOR:
+               if (lev->horizontal) goto horiz;
+               /* fall through */
+       case VWALL:
+               switch (lev->wall_info & WM_MASK) {
+                   case 0: idx = seenv ? S_vwall : S_stone; break;
+                   case 1: idx = seenv & (SV1|SV2|SV3|SV4|SV5) ? S_vwall :
+                                                                 S_stone;
+                           break;
+                   case 2: idx = seenv & (SV0|SV1|SV5|SV6|SV7) ? S_vwall :
+                                                                 S_stone;
+                           break;
+                   default:
+                       impossible("wall_angle: unknown vwall mode %d",
+                               lev->wall_info & WM_MASK);
+                       idx = S_stone;
+                       break;
+               }
+               break;
+
+       case HWALL:
+horiz:
+               switch (lev->wall_info & WM_MASK) {
+                   case 0: idx = seenv ? S_hwall : S_stone; break;
+                   case 1: idx = seenv & (SV3|SV4|SV5|SV6|SV7) ? S_hwall :
+                                                                 S_stone;
+                           break;
+                   case 2: idx = seenv & (SV0|SV1|SV2|SV3|SV7) ? S_hwall :
+                                                                 S_stone;
+                           break;
+                   default:
+                       impossible("wall_angle: unknown hwall mode %d",
+                               lev->wall_info & WM_MASK);
+                       idx = S_stone;
+                       break;
+               }
+               break;
+
+#define set_corner(idx, lev, which, outer, inner, name)        \
+    switch ((lev)->wall_info & WM_MASK) {                                  \
+       case 0:          idx = which; break;                                \
+       case WM_C_OUTER: idx = seenv &  (outer) ? which : S_stone; break;   \
+       case WM_C_INNER: idx = seenv & ~(inner) ? which : S_stone; break;   \
+       default:                                                            \
+           impossible("wall_angle: unknown %s mode %d", name,              \
+               (lev)->wall_info & WM_MASK);                                \
+           idx = S_stone;                                                  \
+           break;                                                          \
+    }
+
+       case TLCORNER:
+           set_corner(idx, lev, S_tlcorn, (SV3|SV4|SV5), SV4, "tlcorn");
+           break;
+       case TRCORNER:
+           set_corner(idx, lev, S_trcorn, (SV5|SV6|SV7), SV6, "trcorn");
+           break;
+       case BLCORNER:
+           set_corner(idx, lev, S_blcorn, (SV1|SV2|SV3), SV2, "blcorn");
+           break;
+       case BRCORNER:
+           set_corner(idx, lev, S_brcorn, (SV7|SV0|SV1), SV0, "brcorn");
+           break;
+
+
+       case CROSSWALL:
+               switch (lev->wall_info & WM_MASK) {
+                   case 0:
+                       if (seenv == SV0)
+                           idx = S_brcorn;
+                       else if (seenv == SV2)
+                           idx = S_blcorn;
+                       else if (seenv == SV4)
+                           idx = S_tlcorn;
+                       else if (seenv == SV6)
+                           idx = S_trcorn;
+                       else if (!(seenv & ~(SV0|SV1|SV2)) &&
+                                       (seenv & SV1 || seenv == (SV0|SV2)))
+                           idx = S_tuwall;
+                       else if (!(seenv & ~(SV2|SV3|SV4)) &&
+                                       (seenv & SV3 || seenv == (SV2|SV4)))
+                           idx = S_trwall;
+                       else if (!(seenv & ~(SV4|SV5|SV6)) &&
+                                       (seenv & SV5 || seenv == (SV4|SV6)))
+                           idx = S_tdwall;
+                       else if (!(seenv & ~(SV0|SV6|SV7)) &&
+                                       (seenv & SV7 || seenv == (SV0|SV6)))
+                           idx = S_tlwall;
+                       else
+                           idx = S_crwall;
+                       break;
+
+                   case WM_X_TL:
+                       row = cross_matrix[C_tl];
+                       seenv = (seenv >> 4 | seenv << 4) & 0xff;
+                       goto do_crwall;
+                   case WM_X_TR:
+                       row = cross_matrix[C_tr];
+                       seenv = (seenv >> 6 | seenv << 2) & 0xff;
+                       goto do_crwall;
+                   case WM_X_BL:
+                       row = cross_matrix[C_bl];
+                       seenv = (seenv >> 2 | seenv << 6) & 0xff;
+                       goto do_crwall;
+                   case WM_X_BR:
+                       row = cross_matrix[C_br];
+do_crwall:
+                       if (seenv == SV4)
+                           idx = S_stone;
+                       else {
+                           seenv = seenv & ~SV4;       /* strip SV4 */
+                           if (seenv == SV0) {
+                               col = C_brcorn;
+                           } else if (seenv & (SV2|SV3)) {
+                               if (seenv & (SV5|SV6|SV7))
+                                   col = C_crwall;
+                               else if (seenv & (SV0|SV1))
+                                   col = C_tuwall;
+                               else
+                                   col = C_blcorn;
+                           } else if (seenv & (SV5|SV6)) {
+                               if (seenv & (SV1|SV2|SV3))
+                                   col = C_crwall;
+                               else if (seenv & (SV0|SV7))
+                                   col = C_tlwall;
+                               else
+                                   col = C_trcorn;
+                           } else if (seenv & SV1) {
+                               col = seenv & SV7 ? C_crwall : C_tuwall;
+                           } else if (seenv & SV7) {
+                               col = seenv & SV1 ? C_crwall : C_tlwall;
+                           } else {
+                               impossible(
+                                   "wall_angle: bottom of crwall check");
+                               col = C_crwall;
+                           }
+
+                           idx = row[col];
+                       }
+                       break;
+
+                   case WM_X_TLBR:
+                       if ( only(seenv, SV1|SV2|SV3) )
+                           idx = S_blcorn;
+                       else if ( only(seenv, SV5|SV6|SV7) )
+                           idx = S_trcorn;
+                       else if ( only(seenv, SV0|SV4) )
+                           idx = S_stone;
+                       else
+                           idx = S_crwall;
+                       break;
+
+                   case WM_X_BLTR:
+                       if ( only(seenv, SV0|SV1|SV7) )
+                           idx = S_brcorn;
+                       else if ( only(seenv, SV3|SV4|SV5) )
+                           idx = S_tlcorn;
+                       else if ( only(seenv, SV2|SV6) )
+                           idx = S_stone;
+                       else
+                           idx = S_crwall;
+                       break;
+
+                   default:
+                       impossible("wall_angle: unknown crosswall mode");
+                       idx = S_stone;
+                       break;
+               }
+               break;
+
+       default:
+           impossible("wall_angle: unexpected wall type %d", lev->typ);
+           idx = S_stone;
+    }
+    return idx;
+}
+
+/*display.c*/
diff --git a/src/dlb.c b/src/dlb.c
new file mode 100644 (file)
index 0000000..5d42326
--- /dev/null
+++ b/src/dlb.c
@@ -0,0 +1,544 @@
+/*     SCCS Id: @(#)dlb.c      3.4     1997/07/29      */
+/* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "config.h"
+#include "dlb.h"
+
+#ifdef __DJGPP__
+#include <string.h>
+#endif
+
+#define DATAPREFIX 4
+
+#ifdef DLB
+/*
+ * Data librarian.  Present a STDIO-like interface to NetHack while
+ * multiplexing on one or more "data libraries".  If a file is not found
+ * in a given library, look for it outside the libraries.
+ */
+
+typedef struct dlb_procs {
+    boolean NDECL((*dlb_init_proc));
+    void NDECL((*dlb_cleanup_proc));
+    boolean FDECL((*dlb_fopen_proc), (DLB_P,const char *,const char *));
+    int FDECL((*dlb_fclose_proc), (DLB_P));
+    int FDECL((*dlb_fread_proc), (char *,int,int,DLB_P));
+    int FDECL((*dlb_fseek_proc), (DLB_P,long,int));
+    char *FDECL((*dlb_fgets_proc), (char *,int,DLB_P));
+    int FDECL((*dlb_fgetc_proc), (DLB_P));
+    long FDECL((*dlb_ftell_proc), (DLB_P));
+} dlb_procs_t;
+
+/* without extern.h via hack.h, these haven't been declared for us */
+extern FILE *FDECL(fopen_datafile, (const char *,const char *,int));
+
+#ifdef DLBLIB
+/*
+ * Library Implementation:
+ *
+ * When initialized, we open all library files and read in their tables
+ * of contents.  The library files stay open all the time.  When
+ * a open is requested, the libraries' directories are searched.  If
+ * successful, we return a descriptor that contains the library, file
+ * size, and current file mark.  This descriptor is used for all
+ * successive calls.
+ *
+ * The ability to open more than one library is supported but used
+ * only in the Amiga port (the second library holds the sound files).
+ * For Unix, the idea would be to split the NetHack library
+ * into text and binary parts, where the text version could be shared.
+ */
+
+#define MAX_LIBS 4
+static library dlb_libs[MAX_LIBS];
+
+static boolean FDECL(readlibdir,(library *lp));
+static boolean FDECL(find_file,(const char *name, library **lib, long *startp,
+                                                               long *sizep));
+static boolean NDECL(lib_dlb_init);
+static void NDECL(lib_dlb_cleanup);
+static boolean FDECL(lib_dlb_fopen,(dlb *, const char *, const char *));
+static int FDECL(lib_dlb_fclose,(dlb *));
+static int FDECL(lib_dlb_fread,(char *, int, int, dlb *));
+static int FDECL(lib_dlb_fseek,(dlb *, long, int));
+static char *FDECL(lib_dlb_fgets,(char *, int, dlb *));
+static int FDECL(lib_dlb_fgetc,(dlb *));
+static long FDECL(lib_dlb_ftell,(dlb *));
+
+/* not static because shared with dlb_main.c */
+boolean FDECL(open_library,(const char *lib_name, library *lp));
+void FDECL(close_library,(library *lp));
+
+/* without extern.h via hack.h, these haven't been declared for us */
+extern char *FDECL(eos, (char *));
+
+
+
+/*
+ * Read the directory out of the library.  Return 1 if successful,
+ * 0 if it failed.
+ *
+ * NOTE: An improvement of the file structure should be the file
+ * size as part of the directory entry or perhaps in place of the
+ * offset -- the offset can be calculated by a running tally of
+ * the sizes.
+ *
+ * Library file structure:
+ *
+ * HEADER:
+ * %3ld        library FORMAT revision (currently rev 1)
+ * %1c space
+ * %8ld        # of files in archive (includes 1 for directory)
+ * %1c space
+ * %8ld        size of allocation for string space for directory names
+ * %1c space
+ * %8ld        library offset - sanity check - lseek target for start of first file
+ * %1c space
+ * %8ld        size - sanity check - byte size of complete archive file
+ *
+ * followed by one DIRECTORY entry for each file in the archive, including
+ *  the directory itself:
+ * %1c handling information (compression, etc.)  Always ' ' in rev 1.
+ * %s  file name
+ * %1c space
+ * %8ld        offset in archive file of start of this file
+ * %c  newline
+ *
+ * followed by the contents of the files
+ */
+#define DLB_MIN_VERS  1        /* min library version readable by this code */
+#define DLB_MAX_VERS  1        /* max library version readable by this code */
+
+/*
+ * Read the directory from the library file.   This will allocate and
+ * fill in our globals.  The file pointer is reset back to position
+ * zero.  If any part fails, leave nothing that needs to be deallocated.
+ *
+ * Return TRUE on success, FALSE on failure.
+ */
+static boolean
+readlibdir(lp)
+    library *lp;       /* library pointer to fill in */
+{
+    int i;
+    char *sp;
+    long liboffset, totalsize;
+
+    if (fscanf(lp->fdata, "%ld %ld %ld %ld %ld\n",
+           &lp->rev,&lp->nentries,&lp->strsize,&liboffset,&totalsize) != 5)
+       return FALSE;
+    if (lp->rev > DLB_MAX_VERS || lp->rev < DLB_MIN_VERS) return FALSE;
+
+    lp->dir = (libdir *) alloc(lp->nentries * sizeof(libdir));
+    lp->sspace = (char *) alloc(lp->strsize);
+
+    /* read in each directory entry */
+    for (i = 0, sp = lp->sspace; i < lp->nentries; i++) {
+       lp->dir[i].fname = sp;
+       if (fscanf(lp->fdata, "%c%s %ld\n",
+                       &lp->dir[i].handling, sp, &lp->dir[i].foffset) != 3) {
+           free((genericptr_t) lp->dir);
+           free((genericptr_t) lp->sspace);
+           lp->dir = (libdir *) 0;
+           lp->sspace = (char *) 0;
+           return FALSE;
+       }
+       sp = eos(sp) + 1;
+    }
+
+    /* calculate file sizes using offset information */
+    for (i = 0; i < lp->nentries; i++) {
+       if (i == lp->nentries - 1)
+           lp->dir[i].fsize = totalsize - lp->dir[i].foffset;
+       else
+           lp->dir[i].fsize = lp->dir[i+1].foffset - lp->dir[i].foffset;
+    }
+
+    (void) fseek(lp->fdata, 0L, SEEK_SET);     /* reset back to zero */
+    lp->fmark = 0;
+
+    return TRUE;
+}
+
+/*
+ * Look for the file in our directory structure.  Return 1 if successful,
+ * 0 if not found.  Fill in the size and starting position.
+ */
+static boolean
+find_file(name, lib, startp, sizep)
+    const char *name;
+    library **lib;
+    long *startp, *sizep;
+{
+    int i, j;
+    library *lp;
+
+    for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++) {
+       lp = &dlb_libs[i];
+       for (j = 0; j < lp->nentries; j++) {
+           if (FILENAME_CMP(name, lp->dir[j].fname) == 0) {
+               *lib = lp;
+               *startp = lp->dir[j].foffset;
+               *sizep = lp->dir[j].fsize;
+               return TRUE;
+           }
+       }
+    }
+    *lib = (library *) 0;
+    *startp = *sizep = 0;
+    return FALSE;
+}
+
+/*
+ * Open the library of the given name and fill in the given library
+ * structure.  Return TRUE if successful, FALSE otherwise.
+ */
+boolean
+open_library(lib_name, lp)
+    const char *lib_name;
+    library *lp;
+{
+    boolean status = FALSE;
+
+    lp->fdata = fopen_datafile(lib_name, RDBMODE, DATAPREFIX);
+    if (lp->fdata) {
+       if (readlibdir(lp)) {
+           status = TRUE;
+       } else {
+           (void) fclose(lp->fdata);
+           lp->fdata = (FILE *) 0;
+       }
+    }
+    return status;
+}
+
+void
+close_library(lp)
+    library *lp;
+{
+    (void) fclose(lp->fdata);
+    free((genericptr_t) lp->dir);
+    free((genericptr_t) lp->sspace);
+
+    (void) memset((char *)lp, 0, sizeof(library));
+}
+
+/*
+ * Open the library file once using stdio.  Keep it open, but
+ * keep track of the file position.
+ */
+static boolean
+lib_dlb_init()
+{
+    /* zero out array */
+    (void) memset((char *)&dlb_libs[0], 0, sizeof(dlb_libs));
+
+    /* To open more than one library, add open library calls here. */
+    if (!open_library(DLBFILE, &dlb_libs[0])) return FALSE;
+#ifdef DLBFILE2
+    if (!open_library(DLBFILE2, &dlb_libs[1]))  {
+       close_library(&dlb_libs[0]);
+       return FALSE;
+    }
+#endif
+    return TRUE;
+}
+
+static void
+lib_dlb_cleanup()
+{
+    int i;
+
+    /* close the data file(s) */
+    for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++)
+       close_library(&dlb_libs[i]);
+}
+
+static boolean
+lib_dlb_fopen(dp, name, mode)
+    dlb *dp;
+    const char *name, *mode;
+{
+    long start, size;
+    library *lp;
+
+    /* look up file in directory */
+    if (find_file(name, &lp, &start, &size)) {
+       dp->lib = lp;
+       dp->start = start;
+       dp->size = size;
+       dp->mark = 0;
+       return TRUE;
+       }
+
+    return FALSE;      /* failed */
+}
+
+static int
+lib_dlb_fclose(dp)
+    dlb *dp;
+{
+    /* nothing needs to be done */
+    return 0;
+}
+
+static int
+lib_dlb_fread(buf, size, quan, dp)
+    char *buf;
+    int size, quan;
+    dlb *dp;
+{
+    long pos, nread, nbytes;
+
+    /* make sure we don't read into the next file */
+    if ((dp->size - dp->mark) < (size * quan))
+       quan = (dp->size - dp->mark) / size;
+    if (quan == 0) return 0;
+
+    pos = dp->start + dp->mark;
+    if (dp->lib->fmark != pos) {
+       fseek(dp->lib->fdata, pos, SEEK_SET);   /* check for error??? */
+       dp->lib->fmark = pos;
+    }
+
+    nread = fread(buf, size, quan, dp->lib->fdata);
+    nbytes = nread * size;
+    dp->mark += nbytes;
+    dp->lib->fmark += nbytes;
+
+    return nread;
+}
+
+static int
+lib_dlb_fseek(dp, pos, whence)
+    dlb *dp;
+    long pos;
+    int whence;
+{
+    long curpos;
+
+    switch (whence) {
+       case SEEK_CUR:     curpos = dp->mark + pos;     break;
+       case SEEK_END:     curpos = dp->size - pos;     break;
+       default: /* set */ curpos = pos;                break;
+    }
+    if (curpos < 0) curpos = 0;
+    if (curpos > dp->size) curpos = dp->size;
+
+    dp->mark = curpos;
+    return 0;
+}
+
+static char *
+lib_dlb_fgets(buf, len, dp)
+    char *buf;
+    int len;
+    dlb *dp;
+{
+    int i;
+    char *bp, c = 0;
+
+    if (len <= 0) return buf;  /* sanity check */
+
+    /* return NULL on EOF */
+    if (dp->mark >= dp->size) return (char *) 0;
+
+    len--;     /* save room for null */
+    for (i = 0, bp = buf;
+               i < len && dp->mark < dp->size && c != '\n'; i++, bp++) {
+       if (dlb_fread(bp, 1, 1, dp) <= 0) break;        /* EOF or error */
+       c = *bp;
+    }
+    *bp = '\0';
+
+#if defined(MSDOS) || defined(WIN32)
+    if ((bp = index(buf, '\r')) != 0) {
+       *bp++ = '\n';
+       *bp = '\0';
+    }
+#endif
+
+    return buf;
+}
+
+static int
+lib_dlb_fgetc(dp)
+    dlb *dp;
+{
+    char c;
+
+    if (lib_dlb_fread(&c, 1, 1, dp) != 1) return EOF;
+    return (int) c;
+}
+
+
+static long
+lib_dlb_ftell(dp)
+    dlb *dp;
+{
+    return dp->mark;
+}
+
+const dlb_procs_t lib_dlb_procs = {
+    lib_dlb_init,
+    lib_dlb_cleanup,
+    lib_dlb_fopen,
+    lib_dlb_fclose,
+    lib_dlb_fread,
+    lib_dlb_fseek,
+    lib_dlb_fgets,
+    lib_dlb_fgetc,
+    lib_dlb_ftell
+};
+
+#endif /* DLBLIB */
+
+#ifdef DLBRSRC
+const dlb_procs_t rsrc_dlb_procs = {
+    rsrc_dlb_init,
+    rsrc_dlb_cleanup,
+    rsrc_dlb_fopen,
+    rsrc_dlb_fclose,
+    rsrc_dlb_fread,
+    rsrc_dlb_fseek,
+    rsrc_dlb_fgets,
+    rsrc_dlb_fgetc,
+    rsrc_dlb_ftell
+};
+#endif
+
+/* Global wrapper functions ------------------------------------------------ */
+
+#define do_dlb_init (*dlb_procs->dlb_init_proc)
+#define do_dlb_cleanup (*dlb_procs->dlb_cleanup_proc)
+#define do_dlb_fopen (*dlb_procs->dlb_fopen_proc)
+#define do_dlb_fclose (*dlb_procs->dlb_fclose_proc)
+#define do_dlb_fread (*dlb_procs->dlb_fread_proc)
+#define do_dlb_fseek (*dlb_procs->dlb_fseek_proc)
+#define do_dlb_fgets (*dlb_procs->dlb_fgets_proc)
+#define do_dlb_fgetc (*dlb_procs->dlb_fgetc_proc)
+#define do_dlb_ftell (*dlb_procs->dlb_ftell_proc)
+
+static const dlb_procs_t *dlb_procs;
+static boolean dlb_initialized = FALSE;
+
+boolean
+dlb_init()
+{
+    if (!dlb_initialized) {
+#ifdef DLBLIB
+       dlb_procs = &lib_dlb_procs;
+#endif
+#ifdef DLBRSRC
+       dlb_procs = &rsrc_dlb_procs;
+#endif
+
+       if (dlb_procs) 
+           dlb_initialized = do_dlb_init();
+    }
+
+    return dlb_initialized;
+}
+
+void
+dlb_cleanup()
+{
+    if (dlb_initialized) {
+       do_dlb_cleanup();
+       dlb_initialized = FALSE;
+    }
+}
+
+dlb *
+dlb_fopen(name, mode)
+    const char *name, *mode;
+{
+    FILE *fp;
+    dlb *dp;
+
+    if (!dlb_initialized) return (dlb *) 0;
+
+    dp = (dlb *) alloc(sizeof(dlb));
+    if (do_dlb_fopen(dp, name, mode))
+       dp->fp = (FILE *) 0;
+    else if ((fp = fopen_datafile(name, mode, DATAPREFIX)) != 0)
+       dp->fp = fp;
+    else {
+       /* can't find anything */
+       free((genericptr_t) dp);
+       dp = (dlb *) 0;
+       }
+
+    return dp;
+}
+
+int
+dlb_fclose(dp)
+    dlb *dp;
+{
+       int ret = 0;
+
+    if (dlb_initialized) {
+       if (dp->fp) ret = fclose(dp->fp);
+       else ret = do_dlb_fclose(dp);
+
+       free((genericptr_t) dp);
+    }
+    return ret;
+}
+
+int
+dlb_fread(buf, size, quan, dp)
+    char *buf;
+    int size, quan;
+    dlb *dp;
+{
+    if (!dlb_initialized || size <= 0 || quan <= 0) return 0;
+    if (dp->fp) return (int) fread(buf, size, quan, dp->fp);
+    return do_dlb_fread(buf, size, quan, dp);
+}
+
+int
+dlb_fseek(dp, pos, whence)
+    dlb *dp;
+    long pos;
+    int whence;
+{
+    if (!dlb_initialized) return EOF;
+    if (dp->fp) return fseek(dp->fp, pos, whence);
+    return do_dlb_fseek(dp, pos, whence);
+}
+
+char *
+dlb_fgets(buf, len, dp)
+    char *buf;
+    int len;
+    dlb *dp;
+{
+    if (!dlb_initialized) return (char *) 0;
+    if (dp->fp) return fgets(buf, len, dp->fp);
+    return do_dlb_fgets(buf, len, dp);
+}
+
+int
+dlb_fgetc(dp)
+    dlb *dp;
+{
+    if (!dlb_initialized) return EOF;
+    if (dp->fp) return fgetc(dp->fp);
+    return do_dlb_fgetc(dp);
+}
+
+long
+dlb_ftell(dp)
+    dlb *dp;
+{
+    if (!dlb_initialized) return 0;
+    if (dp->fp) return ftell(dp->fp);
+    return do_dlb_ftell(dp);
+}
+
+#endif /* DLB */
+
+/*dlb.c*/
diff --git a/src/do.c b/src/do.c
new file mode 100644 (file)
index 0000000..858777f
--- /dev/null
+++ b/src/do.c
@@ -0,0 +1,1687 @@
+/*     SCCS Id: @(#)do.c       3.4     2003/12/02      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* Contains code for 'd', 'D' (drop), '>', '<' (up, down) */
+
+#include "hack.h"
+#include "lev.h"
+
+#ifdef SINKS
+# ifdef OVLB
+STATIC_DCL void FDECL(trycall, (struct obj *));
+# endif /* OVLB */
+STATIC_DCL void FDECL(dosinkring, (struct obj *));
+#endif /* SINKS */
+
+STATIC_PTR int FDECL(drop, (struct obj *));
+STATIC_PTR int NDECL(wipeoff);
+
+#ifdef OVL0
+STATIC_DCL int FDECL(menu_drop, (int));
+#endif
+#ifdef OVL2
+STATIC_DCL int NDECL(currentlevel_rewrite);
+STATIC_DCL void NDECL(final_level);
+/* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */
+#endif
+
+#ifdef OVLB
+
+static NEARDATA const char drop_types[] =
+       { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 };
+
+/* 'd' command: drop one inventory item */
+int
+dodrop()
+{
+#ifndef GOLDOBJ
+       int result, i = (invent || u.ugold) ? 0 : (SIZE(drop_types) - 1);
+#else
+       int result, i = (invent) ? 0 : (SIZE(drop_types) - 1);
+#endif
+
+       if (*u.ushops) sellobj_state(SELL_DELIBERATE);
+       result = drop(getobj(&drop_types[i], "drop"));
+       if (*u.ushops) sellobj_state(SELL_NORMAL);
+       reset_occupations();
+
+       return result;
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+/* Called when a boulder is dropped, thrown, or pushed.  If it ends up
+ * in a pool, it either fills the pool up or sinks away.  In either case,
+ * it's gone for good...  If the destination is not a pool, returns FALSE.
+ */
+boolean
+boulder_hits_pool(otmp, rx, ry, pushing)
+struct obj *otmp;
+register int rx, ry;
+boolean pushing;
+{
+       if (!otmp || otmp->otyp != BOULDER)
+           impossible("Not a boulder?");
+       else if (!Is_waterlevel(&u.uz) && (is_pool(rx,ry) || is_lava(rx,ry))) {
+           boolean lava = is_lava(rx,ry), fills_up;
+           const char *what = waterbody_name(rx,ry);
+           schar ltyp = levl[rx][ry].typ;
+           int chance = rn2(10);               /* water: 90%; lava: 10% */
+           fills_up = lava ? chance == 0 : chance != 0;
+
+           if (fills_up) {
+               struct trap *ttmp = t_at(rx, ry);
+
+               if (ltyp == DRAWBRIDGE_UP) {
+                   levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */
+                   levl[rx][ry].drawbridgemask |= DB_FLOOR;
+               } else
+                   levl[rx][ry].typ = ROOM;
+
+               if (ttmp) (void) delfloortrap(ttmp);
+               bury_objs(rx, ry);
+               
+               newsym(rx,ry);
+               if (pushing) {
+                   You("push %s into the %s.", the(xname(otmp)), what);
+                   if (flags.verbose && !Blind)
+                       pline("Now you can cross it!");
+                   /* no splashing in this case */
+               }
+           }
+           if (!fills_up || !pushing) {        /* splashing occurs */
+               if (!u.uinwater) {
+                   if (pushing ? !Blind : cansee(rx,ry)) {
+                       There("is a large splash as %s %s the %s.",
+                             the(xname(otmp)), fills_up? "fills":"falls into",
+                             what);
+                   } else if (flags.soundok)
+                       You_hear("a%s splash.", lava ? " sizzling" : "");
+                   wake_nearto(rx, ry, 40);
+               }
+
+               if (fills_up && u.uinwater && distu(rx,ry) == 0) {
+                   u.uinwater = 0;
+                   docrt();
+                   vision_full_recalc = 1;
+                   You("find yourself on dry land again!");
+               } else if (lava && distu(rx,ry) <= 2) {
+                   You("are hit by molten lava%c",
+                       Fire_resistance ? '.' : '!');
+                       burn_away_slime();
+                   losehp(d((Fire_resistance ? 1 : 3), 6),
+                          "molten lava", KILLED_BY);
+               } else if (!fills_up && flags.verbose &&
+                          (pushing ? !Blind : cansee(rx,ry)))
+                   pline("It sinks without a trace!");
+           }
+
+           /* boulder is now gone */
+           if (pushing) delobj(otmp);
+           else obfree(otmp, (struct obj *)0);
+           return TRUE;
+       }
+       return FALSE;
+}
+
+/* Used for objects which sometimes do special things when dropped; must be
+ * called with the object not in any chain.  Returns TRUE if the object goes
+ * away.
+ */
+boolean
+flooreffects(obj,x,y,verb)
+struct obj *obj;
+int x,y;
+const char *verb;
+{
+       struct trap *t;
+       struct monst *mtmp;
+
+       if (obj->where != OBJ_FREE)
+           panic("flooreffects: obj not free");
+
+       /* make sure things like water_damage() have no pointers to follow */
+       obj->nobj = obj->nexthere = (struct obj *)0;
+
+       if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE))
+               return TRUE;
+       else if (obj->otyp == BOULDER && (t = t_at(x,y)) != 0 &&
+                (t->ttyp==PIT || t->ttyp==SPIKED_PIT
+                       || t->ttyp==TRAPDOOR || t->ttyp==HOLE)) {
+               if (((mtmp = m_at(x, y)) && mtmp->mtrapped) ||
+                       (u.utrap && u.ux == x && u.uy == y)) {
+                   if (*verb)
+                       pline_The("boulder %s into the pit%s.",
+                               vtense((const char *)0, verb),
+                               (mtmp) ? "" : " with you");
+                   if (mtmp) {
+                       if (!passes_walls(mtmp->data) &&
+                               !throws_rocks(mtmp->data)) {
+                           if (hmon(mtmp, obj, TRUE) && !is_whirly(mtmp->data))
+                               return FALSE;   /* still alive */
+                       }
+                       mtmp->mtrapped = 0;
+                   } else {
+                       if (!Passes_walls && !throws_rocks(youmonst.data)) {
+                           losehp(rnd(15), "squished under a boulder",
+                                  NO_KILLER_PREFIX);
+                           return FALSE;       /* player remains trapped */
+                       } else u.utrap = 0;
+                   }
+               }
+               if (*verb) {
+                       if (Blind) {
+                               if ((x == u.ux) && (y == u.uy))
+                                       You_hear("a CRASH! beneath you.");
+                               else
+                                       You_hear("the boulder %s.", verb);
+                       } else if (cansee(x, y)) {
+                               pline_The("boulder %s%s.",
+                                   t->tseen ? "" : "triggers and ",
+                                   t->ttyp == TRAPDOOR ? "plugs a trap door" :
+                                   t->ttyp == HOLE ? "plugs a hole" :
+                                   "fills a pit");
+                       }
+               }
+               deltrap(t);
+               obfree(obj, (struct obj *)0);
+               bury_objs(x, y);
+               newsym(x,y);
+               return TRUE;
+       } else if (is_lava(x, y)) {
+               return fire_damage(obj, FALSE, FALSE, x, y);
+       } else if (is_pool(x, y)) {
+               /* Reasonably bulky objects (arbitrary) splash when dropped.
+                * If you're floating above the water even small things make noise.
+                * Stuff dropped near fountains always misses */
+               if ((Blind || (Levitation || Flying)) && flags.soundok &&
+                   ((x == u.ux) && (y == u.uy))) {
+                   if (!Underwater) {
+                       if (weight(obj) > 9) {
+                               pline("Splash!");
+                       } else if (Levitation || Flying) {
+                               pline("Plop!");
+                       }
+                   }
+                   map_background(x, y, 0);
+                   newsym(x, y);
+               }
+               water_damage(obj, FALSE, FALSE);
+       } else if (u.ux == x && u.uy == y &&
+               (!u.utrap || u.utraptype != TT_PIT) &&
+               (t = t_at(x,y)) != 0 && t->tseen &&
+                       (t->ttyp==PIT || t->ttyp==SPIKED_PIT)) {
+               /* you escaped a pit and are standing on the precipice */
+               if (Blind && flags.soundok)
+                       You_hear("%s %s downwards.",
+                               The(xname(obj)), otense(obj, "tumble"));
+               else
+                       pline("%s %s into %s pit.",
+                               The(xname(obj)), otense(obj, "tumble"),
+                               the_your[t->madeby_u]);
+       }
+       return FALSE;
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+void
+doaltarobj(obj)  /* obj is an object dropped on an altar */
+       register struct obj *obj;
+{
+       if (Blind)
+               return;
+
+       /* KMH, conduct */
+       u.uconduct.gnostic++;
+
+       if ((obj->blessed || obj->cursed) && obj->oclass != COIN_CLASS) {
+               There("is %s flash as %s %s the altar.",
+                       an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)),
+                       doname(obj), otense(obj, "hit"));
+               if (!Hallucination) obj->bknown = 1;
+       } else {
+               pline("%s %s on the altar.", Doname2(obj),
+                       otense(obj, "land"));
+               obj->bknown = 1;
+       }
+}
+
+#ifdef SINKS
+STATIC_OVL
+void
+trycall(obj)
+register struct obj *obj;
+{
+       if(!objects[obj->otyp].oc_name_known &&
+          !objects[obj->otyp].oc_uname)
+          docall(obj);
+}
+
+STATIC_OVL
+void
+dosinkring(obj)  /* obj is a ring being dropped over a kitchen sink */
+register struct obj *obj;
+{
+       register struct obj *otmp,*otmp2;
+       register boolean ideed = TRUE;
+
+       You("drop %s down the drain.", doname(obj));
+       obj->in_use = TRUE;     /* block free identification via interrupt */
+       switch(obj->otyp) {     /* effects that can be noticed without eyes */
+           case RIN_SEARCHING:
+               You("thought your %s got lost in the sink, but there it is!",
+                       xname(obj));
+               goto giveback;
+           case RIN_SLOW_DIGESTION:
+               pline_The("ring is regurgitated!");
+giveback:
+               obj->in_use = FALSE;
+               dropx(obj);
+               trycall(obj);
+               return;
+           case RIN_LEVITATION:
+               pline_The("sink quivers upward for a moment.");
+               break;
+           case RIN_POISON_RESISTANCE:
+               You("smell rotten %s.", makeplural(fruitname(FALSE)));
+               break;
+           case RIN_AGGRAVATE_MONSTER:
+               pline("Several flies buzz angrily around the sink.");
+               break;
+           case RIN_SHOCK_RESISTANCE:
+               pline("Static electricity surrounds the sink.");
+               break;
+           case RIN_CONFLICT:
+               You_hear("loud noises coming from the drain.");
+               break;
+           case RIN_SUSTAIN_ABILITY:   /* KMH */
+               pline_The("water flow seems fixed.");
+               break;
+           case RIN_GAIN_STRENGTH:
+               pline_The("water flow seems %ser now.",
+                       (obj->spe<0) ? "weak" : "strong");
+               break;
+           case RIN_GAIN_CONSTITUTION:
+               pline_The("water flow seems %ser now.",
+                       (obj->spe<0) ? "less" : "great");
+               break;
+           case RIN_INCREASE_ACCURACY: /* KMH */
+               pline_The("water flow %s the drain.",
+                       (obj->spe<0) ? "misses" : "hits");
+               break;
+           case RIN_INCREASE_DAMAGE:
+               pline_The("water's force seems %ser now.",
+                       (obj->spe<0) ? "small" : "great");
+               break;
+           case RIN_HUNGER:
+               ideed = FALSE;
+               for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) {
+                   otmp2 = otmp->nexthere;
+                   if (otmp != uball && otmp != uchain &&
+                           !obj_resists(otmp, 1, 99)) {
+                       if (!Blind) {
+                           pline("Suddenly, %s %s from the sink!",
+                                 doname(otmp), otense(otmp, "vanish"));
+                           ideed = TRUE;
+                       }
+                       delobj(otmp);
+                   }
+               }
+               break;
+           case MEAT_RING:
+               /* Not the same as aggravate monster; besides, it's obvious. */
+               pline("Several flies buzz around the sink.");
+               break;
+           default:
+               ideed = FALSE;
+               break;
+       }
+       if(!Blind && !ideed && obj->otyp != RIN_HUNGER) {
+           ideed = TRUE;
+           switch(obj->otyp) {         /* effects that need eyes */
+               case RIN_ADORNMENT:
+                   pline_The("faucets flash brightly for a moment.");
+                   break;
+               case RIN_REGENERATION:
+                   pline_The("sink looks as good as new.");
+                   break;
+               case RIN_INVISIBILITY:
+                   You("don't see anything happen to the sink.");
+                   break;
+               case RIN_FREE_ACTION:
+                   You("see the ring slide right down the drain!");
+                   break;
+               case RIN_SEE_INVISIBLE:
+                   You("see some air in the sink.");
+                   break;
+               case RIN_STEALTH:
+               pline_The("sink seems to blend into the floor for a moment.");
+                   break;
+               case RIN_FIRE_RESISTANCE:
+               pline_The("hot water faucet flashes brightly for a moment.");
+                   break;
+               case RIN_COLD_RESISTANCE:
+               pline_The("cold water faucet flashes brightly for a moment.");
+                   break;
+               case RIN_PROTECTION_FROM_SHAPE_CHAN:
+                   pline_The("sink looks nothing like a fountain.");
+                   break;
+               case RIN_PROTECTION:
+                   pline_The("sink glows %s for a moment.",
+                           hcolor((obj->spe<0) ? NH_BLACK : NH_SILVER));
+                   break;
+               case RIN_WARNING:
+                   pline_The("sink glows %s for a moment.", hcolor(NH_WHITE));
+                   break;
+               case RIN_TELEPORTATION:
+                   pline_The("sink momentarily vanishes.");
+                   break;
+               case RIN_TELEPORT_CONTROL:
+           pline_The("sink looks like it is being beamed aboard somewhere.");
+                   break;
+               case RIN_POLYMORPH:
+                   pline_The("sink momentarily looks like a fountain.");
+                   break;
+               case RIN_POLYMORPH_CONTROL:
+       pline_The("sink momentarily looks like a regularly erupting geyser.");
+                   break;
+           }
+       }
+       if(ideed)
+           trycall(obj);
+       else
+           You_hear("the ring bouncing down the drainpipe.");
+       if (!rn2(20)) {
+               pline_The("sink backs up, leaving %s.", doname(obj));
+               obj->in_use = FALSE;
+               dropx(obj);
+       } else
+               useup(obj);
+}
+#endif
+
+#endif /* OVLB */
+#ifdef OVL0
+
+/* some common tests when trying to drop or throw items */
+boolean
+canletgo(obj,word)
+register struct obj *obj;
+register const char *word;
+{
+       if(obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)){
+               if (*word)
+                       Norep("You cannot %s %s you are wearing.",word,
+                               something);
+               return(FALSE);
+       }
+       if (obj->otyp == LOADSTONE && obj->cursed) {
+               /* getobj() kludge sets corpsenm to user's specified count
+                  when refusing to split a stack of cursed loadstones */
+               if (*word) {
+                       /* getobj() ignores a count for throwing since that is
+                          implicitly forced to be 1; replicate its kludge... */
+                       if (!strcmp(word, "throw") && obj->quan > 1L)
+                           obj->corpsenm = 1;
+                       pline("For some reason, you cannot %s%s the stone%s!",
+                             word, obj->corpsenm ? " any of" : "",
+                             plur(obj->quan));
+               }
+               obj->corpsenm = 0;              /* reset */
+               obj->bknown = 1;
+               return(FALSE);
+       }
+       if (obj->otyp == LEASH && obj->leashmon != 0) {
+               if (*word)
+                       pline_The("leash is tied around your %s.",
+                                       body_part(HAND));
+               return(FALSE);
+       }
+#ifdef STEED
+       if (obj->owornmask & W_SADDLE) {
+               if (*word)
+                       You("cannot %s %s you are sitting on.", word,
+                               something);
+               return (FALSE);
+       }
+#endif
+       return(TRUE);
+}
+
+STATIC_PTR
+int
+drop(obj)
+register struct obj *obj;
+{
+       if(!obj) return(0);
+       if(!canletgo(obj,"drop"))
+               return(0);
+       if(obj == uwep) {
+               if(welded(uwep)) {
+                       weldmsg(obj);
+                       return(0);
+               }
+               setuwep((struct obj *)0);
+       }
+       if(obj == uquiver) {
+               setuqwep((struct obj *)0);
+       }
+       if (obj == uswapwep) {
+               setuswapwep((struct obj *)0);
+       }
+
+       if (u.uswallow) {
+               /* barrier between you and the floor */
+               if(flags.verbose)
+               {
+                       char buf[BUFSZ];
+
+                       /* doname can call s_suffix, reusing its buffer */
+                       Strcpy(buf, s_suffix(mon_nam(u.ustuck)));
+                       You("drop %s into %s %s.", doname(obj), buf,
+                               mbodypart(u.ustuck, STOMACH));
+               }
+       } else {
+#ifdef SINKS
+           if((obj->oclass == RING_CLASS || obj->otyp == MEAT_RING) &&
+                       IS_SINK(levl[u.ux][u.uy].typ)) {
+               dosinkring(obj);
+               return(1);
+           }
+#endif
+           if (!can_reach_floor()) {
+               if(flags.verbose) You("drop %s.", doname(obj));
+#ifndef GOLDOBJ
+               if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj);
+#else
+               /* Ensure update when we drop gold objects */
+               if (obj->oclass == COIN_CLASS) flags.botl = 1;
+               freeinv(obj);
+#endif
+               hitfloor(obj);
+               return(1);
+           }
+           if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose)
+               You("drop %s.", doname(obj));
+       }
+       dropx(obj);
+       return(1);
+}
+
+/* Called in several places - may produce output */
+/* eg ship_object() and dropy() -> sellobj() both produce output */
+void
+dropx(obj)
+register struct obj *obj;
+{
+#ifndef GOLDOBJ
+       if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj);
+#else
+        /* Ensure update when we drop gold objects */
+        if (obj->oclass == COIN_CLASS) flags.botl = 1;
+        freeinv(obj);
+#endif
+       if (!u.uswallow) {
+           if (ship_object(obj, u.ux, u.uy, FALSE)) return;
+           if (IS_ALTAR(levl[u.ux][u.uy].typ))
+               doaltarobj(obj); /* set bknown */
+       }
+       dropy(obj);
+}
+
+void
+dropy(obj)
+register struct obj *obj;
+{
+       if (obj == uwep) setuwep((struct obj *)0);
+       if (obj == uquiver) setuqwep((struct obj *)0);
+       if (obj == uswapwep) setuswapwep((struct obj *)0);
+
+       if (!u.uswallow && flooreffects(obj,u.ux,u.uy,"drop")) return;
+       /* uswallow check done by GAN 01/29/87 */
+       if(u.uswallow) {
+           boolean could_petrify = FALSE;
+           boolean could_poly = FALSE;
+           boolean could_slime = FALSE;
+           boolean could_grow = FALSE;
+           boolean could_heal = FALSE;
+
+           if (obj != uball) {         /* mon doesn't pick up ball */
+               if (obj->otyp == CORPSE) {
+                   could_petrify = touch_petrifies(&mons[obj->corpsenm]);
+                   could_poly = polyfodder(obj);
+                   could_slime = (obj->corpsenm == PM_GREEN_SLIME);
+                   could_grow = (obj->corpsenm == PM_WRAITH);
+                   could_heal = (obj->corpsenm == PM_NURSE);
+               }
+               (void) mpickobj(u.ustuck,obj);
+               if (is_animal(u.ustuck->data)) {
+                   if (could_poly || could_slime) {
+                       (void) newcham(u.ustuck,
+                                      could_poly ? (struct permonst *)0 :
+                                      &mons[PM_GREEN_SLIME],
+                                      FALSE, could_slime);
+                       delobj(obj);    /* corpse is digested */
+                   } else if (could_petrify) {
+                       minstapetrify(u.ustuck, TRUE);
+                       /* Don't leave a cockatrice corpse in a statue */
+                       if (!u.uswallow) delobj(obj);
+                   } else if (could_grow) {
+                       (void) grow_up(u.ustuck, (struct monst *)0);
+                       delobj(obj);    /* corpse is digested */
+                   } else if (could_heal) {
+                       u.ustuck->mhp = u.ustuck->mhpmax;
+                       delobj(obj);    /* corpse is digested */
+                   }
+               }
+           }
+       } else  {
+           place_object(obj, u.ux, u.uy);
+           if (obj == uball)
+               drop_ball(u.ux,u.uy);
+           else
+               sellobj(obj, u.ux, u.uy);
+           stackobj(obj);
+           if(Blind && Levitation)
+               map_object(obj, 0);
+           newsym(u.ux,u.uy);  /* remap location under self */
+       }
+}
+
+/* things that must change when not held; recurse into containers.
+   Called for both player and monsters */
+void
+obj_no_longer_held(obj)
+struct obj *obj;
+{
+       if (!obj) {
+           return;
+       } else if ((Is_container(obj) || obj->otyp == STATUE) && obj->cobj) {
+           struct obj *contents;
+           for(contents=obj->cobj; contents; contents=contents->nobj)
+               obj_no_longer_held(contents);
+       }
+       switch(obj->otyp) {
+       case CRYSKNIFE:
+           /* KMH -- Fixed crysknives have only 10% chance of reverting */
+           /* only changes when not held by player or monster */
+           if (!obj->oerodeproof || !rn2(10)) {
+               obj->otyp = WORM_TOOTH;
+               obj->oerodeproof = 0;
+           }
+           break;
+       }
+}
+
+/* 'D' command: drop several things */
+int
+doddrop()
+{
+       int result = 0;
+
+       add_valid_menu_class(0); /* clear any classes already there */
+       if (*u.ushops) sellobj_state(SELL_DELIBERATE);
+       if (flags.menu_style != MENU_TRADITIONAL ||
+               (result = ggetobj("drop", drop, 0, FALSE, (unsigned *)0)) < -1)
+           result = menu_drop(result);
+       if (*u.ushops) sellobj_state(SELL_NORMAL);
+       reset_occupations();
+
+       return result;
+}
+
+/* Drop things from the hero's inventory, using a menu. */
+STATIC_OVL int
+menu_drop(retry)
+int retry;
+{
+    int n, i, n_dropped = 0;
+    long cnt;
+    struct obj *otmp, *otmp2;
+#ifndef GOLDOBJ
+    struct obj *u_gold = 0;
+#endif
+    menu_item *pick_list;
+    boolean all_categories = TRUE;
+    boolean drop_everything = FALSE;
+
+#ifndef GOLDOBJ
+    if (u.ugold) {
+       /* Hack: gold is not in the inventory, so make a gold object
+          and put it at the head of the inventory list. */
+       u_gold = mkgoldobj(u.ugold);    /* removes from u.ugold */
+       u_gold->in_use = TRUE;
+       u.ugold = u_gold->quan;         /* put the gold back */
+       assigninvlet(u_gold);           /* might end up as NOINVSYM */
+       u_gold->nobj = invent;
+       invent = u_gold;
+    }
+#endif
+    if (retry) {
+       all_categories = (retry == -2);
+    } else if (flags.menu_style == MENU_FULL) {
+       all_categories = FALSE;
+       n = query_category("Drop what type of items?",
+                       invent,
+                       UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL |
+                       BUC_BLESSED | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN,
+                       &pick_list, PICK_ANY);
+       if (!n) goto drop_done;
+       for (i = 0; i < n; i++) {
+           if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
+               all_categories = TRUE;
+           else if (pick_list[i].item.a_int == 'A')
+               drop_everything = TRUE;
+           else
+               add_valid_menu_class(pick_list[i].item.a_int);
+       }
+       free((genericptr_t) pick_list);
+    } else if (flags.menu_style == MENU_COMBINATION) {
+       unsigned ggoresults = 0;
+       all_categories = FALSE;
+       /* Gather valid classes via traditional NetHack method */
+       i = ggetobj("drop", drop, 0, TRUE, &ggoresults);
+       if (i == -2) all_categories = TRUE;
+       if (ggoresults & ALL_FINISHED) {
+               n_dropped = i;
+               goto drop_done;
+       }
+    }
+
+    if (drop_everything) {
+       for(otmp = invent; otmp; otmp = otmp2) {
+           otmp2 = otmp->nobj;
+           n_dropped += drop(otmp);
+       }
+    } else {
+       /* should coordinate with perm invent, maybe not show worn items */
+       n = query_objlist("What would you like to drop?", invent,
+                       USE_INVLET|INVORDER_SORT, &pick_list,
+                       PICK_ANY, all_categories ? allow_all : allow_category);
+       if (n > 0) {
+           for (i = 0; i < n; i++) {
+               otmp = pick_list[i].item.a_obj;
+               cnt = pick_list[i].count;
+               if (cnt < otmp->quan) {
+                   if (welded(otmp)) {
+                       ;       /* don't split */
+                   } else if (otmp->otyp == LOADSTONE && otmp->cursed) {
+                       /* same kludge as getobj(), for canletgo()'s use */
+                       otmp->corpsenm = (int) cnt;     /* don't split */
+                   } else {
+#ifndef GOLDOBJ
+                       if (otmp->oclass == COIN_CLASS)
+                           (void) splitobj(otmp, otmp->quan - cnt);
+                       else
+#endif
+                           otmp = splitobj(otmp, cnt);
+                   }
+               }
+               n_dropped += drop(otmp);
+           }
+           free((genericptr_t) pick_list);
+       }
+    }
+
+ drop_done:
+#ifndef GOLDOBJ
+    if (u_gold && invent && invent->oclass == COIN_CLASS) {
+       /* didn't drop [all of] it */
+       u_gold = invent;
+       invent = u_gold->nobj;
+       u_gold->in_use = FALSE;
+       dealloc_obj(u_gold);
+       update_inventory();
+    }
+#endif
+    return n_dropped;
+}
+
+#endif /* OVL0 */
+#ifdef OVL2
+
+/* on a ladder, used in goto_level */
+static NEARDATA boolean at_ladder = FALSE;
+
+int
+dodown()
+{
+       struct trap *trap = 0;
+       boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair) ||
+                   (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)),
+               ladder_down = (u.ux == xdnladder && u.uy == ydnladder);
+
+#ifdef STEED
+       if (u.usteed && !u.usteed->mcanmove) {
+               pline("%s won't move!", Monnam(u.usteed));
+               return(0);
+       } else if (u.usteed && u.usteed->meating) {
+               pline("%s is still eating.", Monnam(u.usteed));
+               return(0);
+       } else
+#endif
+       if (Levitation) {
+           if ((HLevitation & I_SPECIAL) || (ELevitation & W_ARTI)) {
+               /* end controlled levitation */
+               if (ELevitation & W_ARTI) {
+                   struct obj *obj;
+
+                   for(obj = invent; obj; obj = obj->nobj) {
+                       if (obj->oartifact &&
+                                       artifact_has_invprop(obj,LEVITATION)) {
+                           if (obj->age < monstermoves)
+                               obj->age = monstermoves + rnz(100);
+                           else
+                               obj->age += rnz(100);
+                       }
+                   }
+               }
+               if (float_down(I_SPECIAL|TIMEOUT, W_ARTI))
+                   return (1);   /* came down, so moved */
+           }
+           floating_above(stairs_down ? "stairs" : ladder_down ?
+                          "ladder" : surface(u.ux, u.uy));
+           return (0);   /* didn't move */
+       }
+       if (!stairs_down && !ladder_down) {
+               if (!(trap = t_at(u.ux,u.uy)) ||
+                       (trap->ttyp != TRAPDOOR && trap->ttyp != HOLE)
+                       || !Can_fall_thru(&u.uz) || !trap->tseen) {
+
+                       if (flags.autodig && !flags.nopick &&
+                               uwep && is_pick(uwep)) {
+                               return use_pick_axe2(uwep);
+                       } else {
+                               You_cant("go down here.");
+                               return(0);
+                       }
+               }
+       }
+       if(u.ustuck) {
+               You("are %s, and cannot go down.",
+                       !u.uswallow ? "being held" : is_animal(u.ustuck->data) ?
+                       "swallowed" : "engulfed");
+               return(1);
+       }
+       if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) {
+               You("are standing at the gate to Gehennom.");
+               pline("Unspeakable cruelty and harm lurk down there.");
+               if (yn("Are you sure you want to enter?") != 'y')
+                       return(0);
+               else pline("So be it.");
+               u.uevent.gehennom_entered = 1;  /* don't ask again */
+       }
+
+       if(!next_to_u()) {
+               You("are held back by your pet!");
+               return(0);
+       }
+
+       if (trap)
+           You("%s %s.", locomotion(youmonst.data, "jump"),
+               trap->ttyp == HOLE ? "down the hole" : "through the trap door");
+
+       if (trap && Is_stronghold(&u.uz)) {
+               goto_hell(FALSE, TRUE);
+       } else {
+               at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
+               next_level(!trap);
+               at_ladder = FALSE;
+       }
+       return(1);
+}
+
+int
+doup()
+{
+       if( (u.ux != xupstair || u.uy != yupstair)
+            && (!xupladder || u.ux != xupladder || u.uy != yupladder)
+            && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy
+                       || !sstairs.up)
+         ) {
+               You_cant("go up here.");
+               return(0);
+       }
+#ifdef STEED
+       if (u.usteed && !u.usteed->mcanmove) {
+               pline("%s won't move!", Monnam(u.usteed));
+               return(0);
+       } else if (u.usteed && u.usteed->meating) {
+               pline("%s is still eating.", Monnam(u.usteed));
+               return(0);
+       } else
+#endif
+       if(u.ustuck) {
+               You("are %s, and cannot go up.",
+                       !u.uswallow ? "being held" : is_animal(u.ustuck->data) ?
+                       "swallowed" : "engulfed");
+               return(1);
+       }
+       if(near_capacity() > SLT_ENCUMBER) {
+               /* No levitation check; inv_weight() already allows for it */
+               Your("load is too heavy to climb the %s.",
+                       levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder");
+               return(1);
+       }
+       if(ledger_no(&u.uz) == 1) {
+               if (yn("Beware, there will be no return! Still climb?") != 'y')
+                       return(0);
+       }
+       if(!next_to_u()) {
+               You("are held back by your pet!");
+               return(0);
+       }
+       at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
+       prev_level(TRUE);
+       at_ladder = FALSE;
+       return(1);
+}
+
+d_level save_dlevel = {0, 0};
+
+/* check that we can write out the current level */
+STATIC_OVL int
+currentlevel_rewrite()
+{
+       register int fd;
+       char whynot[BUFSZ];
+
+       /* since level change might be a bit slow, flush any buffered screen
+        *  output (like "you fall through a trap door") */
+       mark_synch();
+
+       fd = create_levelfile(ledger_no(&u.uz), whynot);
+       if (fd < 0) {
+               /*
+                * This is not quite impossible: e.g., we may have
+                * exceeded our quota. If that is the case then we
+                * cannot leave this level, and cannot save either.
+                * Another possibility is that the directory was not
+                * writable.
+                */
+               pline("%s", whynot);
+               return -1;
+       }
+
+#ifdef MFLOPPY
+       if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) {
+               (void) close(fd);
+               delete_levelfile(ledger_no(&u.uz));
+               pline("NetHack is out of disk space for making levels!");
+               You("can save, quit, or continue playing.");
+               return -1;
+       }
+#endif
+       return fd;
+}
+
+#ifdef INSURANCE
+void
+save_currentstate()
+{
+       int fd;
+
+       if (flags.ins_chkpt) {
+               /* write out just-attained level, with pets and everything */
+               fd = currentlevel_rewrite();
+               if(fd < 0) return;
+               bufon(fd);
+               savelev(fd,ledger_no(&u.uz), WRITE_SAVE);
+               bclose(fd);
+       }
+
+       /* write out non-level state */
+       savestateinlock();
+}
+#endif
+
+/*
+static boolean
+badspot(x, y)
+register xchar x, y;
+{
+       return((levl[x][y].typ != ROOM && levl[x][y].typ != AIR &&
+                        levl[x][y].typ != CORR) || MON_AT(x, y));
+}
+*/
+
+void
+goto_level(newlevel, at_stairs, falling, portal)
+d_level *newlevel;
+boolean at_stairs, falling, portal;
+{
+       int fd, l_idx;
+       xchar new_ledger;
+       boolean cant_go_back,
+               up = (depth(newlevel) < depth(&u.uz)),
+               newdungeon = (u.uz.dnum != newlevel->dnum),
+               was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz),
+               familiar = FALSE;
+       boolean new = FALSE;    /* made a new level? */
+       struct monst *mtmp;
+       char whynot[BUFSZ];
+
+       if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel))
+               newlevel->dlevel = dunlevs_in_dungeon(newlevel);
+       if (newdungeon && In_endgame(newlevel)) { /* 1st Endgame Level !!! */
+               if (u.uhave.amulet)
+                   assign_level(newlevel, &earth_level);
+               else return;
+       }
+       new_ledger = ledger_no(newlevel);
+       if (new_ledger <= 0)
+               done(ESCAPED);  /* in fact < 0 is impossible */
+
+       /* If you have the amulet and are trying to get out of Gehennom, going
+        * up a set of stairs sometimes does some very strange things!
+        * Biased against law and towards chaos, but not nearly as strongly
+        * as it used to be (prior to 3.2.0).
+        * Odds:            old                             new
+        *      "up"    L      N      C         "up"    L      N      C
+        *       +1   75.0   75.0   75.0         +1   75.0   75.0   75.0
+        *        0    0.0   12.5   25.0          0    6.25   8.33  12.5
+        *       -1    8.33   4.17   0.0         -1    6.25   8.33  12.5
+        *       -2    8.33   4.17   0.0         -2    6.25   8.33   0.0
+        *       -3    8.33   4.17   0.0         -3    6.25   0.0    0.0
+        */
+       if (Inhell && up && u.uhave.amulet && !newdungeon && !portal &&
+                               (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)-3)) {
+               if (!rn2(4)) {
+                   int odds = 3 + (int)u.ualign.type,          /* 2..4 */
+                       diff = odds <= 1 ? 0 : rn2(odds);       /* paranoia */
+
+                   if (diff != 0) {
+                       assign_rnd_level(newlevel, &u.uz, diff);
+                       /* if inside the tower, stay inside */
+                       if (was_in_W_tower &&
+                           !On_W_tower_level(newlevel)) diff = 0;
+                   }
+                   if (diff == 0)
+                       assign_level(newlevel, &u.uz);
+
+                   new_ledger = ledger_no(newlevel);
+
+                   pline("A mysterious force momentarily surrounds you...");
+                   if (on_level(newlevel, &u.uz)) {
+                       (void) safe_teleds(FALSE);
+                       (void) next_to_u();
+                       return;
+                   } else
+                       at_stairs = at_ladder = FALSE;
+               }
+       }
+
+       /* Prevent the player from going past the first quest level unless
+        * (s)he has been given the go-ahead by the leader.
+        */
+       if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) {
+               pline("A mysterious force prevents you from descending.");
+               return;
+       }
+
+       if (on_level(newlevel, &u.uz)) return;          /* this can happen */
+
+       fd = currentlevel_rewrite();
+       if (fd < 0) return;
+
+       if (falling) /* assuming this is only trap door or hole */
+           impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel);
+
+       check_special_room(TRUE);               /* probably was a trap door */
+       if (Punished) unplacebc();
+       u.utrap = 0;                            /* needed in level_tele */
+       fill_pit(u.ux, u.uy);
+       u.ustuck = 0;                           /* idem */
+       u.uinwater = 0;
+       u.uundetected = 0;      /* not hidden, even if means are available */
+       keepdogs(FALSE);
+       if (u.uswallow)                         /* idem */
+               u.uswldtim = u.uswallow = 0;
+       /*
+        *  We no longer see anything on the level.  Make sure that this
+        *  follows u.uswallow set to null since uswallow overrides all
+        *  normal vision.
+        */
+       vision_recalc(2);
+
+       /*
+        * Save the level we're leaving.  If we're entering the endgame,
+        * we can get rid of all existing levels because they cannot be
+        * reached any more.  We still need to use savelev()'s cleanup
+        * for the level being left, to recover dynamic memory in use and
+        * to avoid dangling timers and light sources.
+        */
+       cant_go_back = (newdungeon && In_endgame(newlevel));
+       if (!cant_go_back) {
+           update_mlstmv();    /* current monsters are becoming inactive */
+           bufon(fd);          /* use buffered output */
+       }
+       savelev(fd, ledger_no(&u.uz),
+               cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE));
+       bclose(fd);
+       if (cant_go_back) {
+           /* discard unreachable levels; keep #0 */
+           for (l_idx = maxledgerno(); l_idx > 0; --l_idx)
+               delete_levelfile(l_idx);
+       }
+
+#ifdef REINCARNATION
+       if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz))
+               assign_rogue_graphics(Is_rogue_level(newlevel));
+#endif
+#ifdef USE_TILES
+       substitute_tiles(newlevel);
+#endif
+       assign_level(&u.uz0, &u.uz);
+       assign_level(&u.uz, newlevel);
+       assign_level(&u.utolev, newlevel);
+       u.utotype = 0;
+       if (dunlev_reached(&u.uz) < dunlev(&u.uz))
+               dunlev_reached(&u.uz) = dunlev(&u.uz);
+       reset_rndmonst(NON_PM);   /* u.uz change affects monster generation */
+
+       /* set default level change destination areas */
+       /* the special level code may override these */
+       (void) memset((genericptr_t) &updest, 0, sizeof updest);
+       (void) memset((genericptr_t) &dndest, 0, sizeof dndest);
+
+       if (!(level_info[new_ledger].flags & LFILE_EXISTS)) {
+               /* entering this level for first time; make it now */
+               if (level_info[new_ledger].flags & (FORGOTTEN|VISITED)) {
+                   impossible("goto_level: returning to discarded level?");
+                   level_info[new_ledger].flags &= ~(FORGOTTEN|VISITED);
+               }
+               mklev();
+               new = TRUE;     /* made the level */
+       } else {
+               /* returning to previously visited level; reload it */
+               fd = open_levelfile(new_ledger, whynot);
+               if (fd < 0) {
+                       pline("%s", whynot);
+                       pline("Probably someone removed it.");
+                       killer = whynot;
+                       done(TRICKED);
+                       /* we'll reach here if running in wizard mode */
+                       error("Cannot continue this game.");
+               }
+               minit();        /* ZEROCOMP */
+               getlev(fd, hackpid, new_ledger, FALSE);
+               (void) close(fd);
+       }
+       /* do this prior to level-change pline messages */
+       vision_reset();         /* clear old level's line-of-sight */
+       vision_full_recalc = 0; /* don't let that reenable vision yet */
+       flush_screen(-1);       /* ensure all map flushes are postponed */
+
+       if (portal && !In_endgame(&u.uz)) {
+           /* find the portal on the new level */
+           register struct trap *ttrap;
+
+           for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap)
+               if (ttrap->ttyp == MAGIC_PORTAL) break;
+
+           if (!ttrap) panic("goto_level: no corresponding portal!");
+           seetrap(ttrap);
+           u_on_newpos(ttrap->tx, ttrap->ty);
+       } else if (at_stairs && !In_endgame(&u.uz)) {
+           if (up) {
+               if (at_ladder) {
+                   u_on_newpos(xdnladder, ydnladder);
+               } else {
+                   if (newdungeon) {
+                       if (Is_stronghold(&u.uz)) {
+                           register xchar x, y;
+
+                           do {
+                               x = (COLNO - 2 - rnd(5));
+                               y = rn1(ROWNO - 4, 3);
+                           } while(occupied(x, y) ||
+                                   IS_WALL(levl[x][y].typ));
+                           u_on_newpos(x, y);
+                       } else u_on_sstairs();
+                   } else u_on_dnstairs();
+               }
+               /* Remove bug which crashes with levitation/punishment  KAA */
+               if (Punished && !Levitation) {
+                       pline("With great effort you climb the %s.",
+                               at_ladder ? "ladder" : "stairs");
+               } else if (at_ladder)
+                   You("climb up the ladder.");
+           } else {    /* down */
+               if (at_ladder) {
+                   u_on_newpos(xupladder, yupladder);
+               } else {
+                   if (newdungeon) u_on_sstairs();
+                   else u_on_upstairs();
+               }
+               if (u.dz && Flying)
+                   You("fly down along the %s.",
+                       at_ladder ? "ladder" : "stairs");
+               else if (u.dz &&
+                   (near_capacity() > UNENCUMBERED || Punished || Fumbling)) {
+                   You("fall down the %s.", at_ladder ? "ladder" : "stairs");
+                   if (Punished) {
+                       drag_down();
+                       if (carried(uball)) {
+                           if (uwep == uball)
+                               setuwep((struct obj *)0);
+                           if (uswapwep == uball)
+                               setuswapwep((struct obj *)0);
+                           if (uquiver == uball)
+                               setuqwep((struct obj *)0);
+                           freeinv(uball);
+                       }
+                   }
+#ifdef STEED
+                   /* falling off steed has its own losehp() call */
+                   if (u.usteed)
+                       dismount_steed(DISMOUNT_FELL);
+                   else
+#endif
+                       losehp(rnd(3), "falling downstairs", KILLED_BY);
+                   selftouch("Falling, you");
+               } else if (u.dz && at_ladder)
+                   You("climb down the ladder.");
+           }
+       } else {        /* trap door or level_tele or In_endgame */
+           if (was_in_W_tower && On_W_tower_level(&u.uz))
+               /* Stay inside the Wizard's tower when feasible.        */
+               /* Note: up vs down doesn't really matter in this case. */
+               place_lregion(dndest.nlx, dndest.nly,
+                               dndest.nhx, dndest.nhy,
+                               0,0, 0,0, LR_DOWNTELE, (d_level *) 0);
+           else if (up)
+               place_lregion(updest.lx, updest.ly,
+                               updest.hx, updest.hy,
+                               updest.nlx, updest.nly,
+                               updest.nhx, updest.nhy,
+                               LR_UPTELE, (d_level *) 0);
+           else
+               place_lregion(dndest.lx, dndest.ly,
+                               dndest.hx, dndest.hy,
+                               dndest.nlx, dndest.nly,
+                               dndest.nhx, dndest.nhy,
+                               LR_DOWNTELE, (d_level *) 0);
+           if (falling) {
+               if (Punished) ballfall();
+               selftouch("Falling, you");
+           }
+       }
+
+       if (Punished) placebc();
+       obj_delivery();         /* before killing geno'd monsters' eggs */
+       losedogs();
+       kill_genocided_monsters();  /* for those wiped out while in limbo */
+       /*
+        * Expire all timers that have gone off while away.  Must be
+        * after migrating monsters and objects are delivered
+        * (losedogs and obj_delivery).
+        */
+       run_timers();
+
+       initrack();
+
+       if ((mtmp = m_at(u.ux, u.uy)) != 0
+#ifdef STEED
+               && mtmp != u.usteed
+#endif
+               ) {
+           /* There's a monster at your target destination; it might be one
+              which accompanied you--see mon_arrive(dogmove.c)--or perhaps
+              it was already here.  Randomly move you to an adjacent spot
+              or else the monster to any nearby location.  Prior to 3.3.0
+              the latter was done unconditionally. */
+           coord cc;
+
+           if (!rn2(2) &&
+                   enexto(&cc, u.ux, u.uy, youmonst.data) &&
+                   distu(cc.x, cc.y) <= 2)
+               u_on_newpos(cc.x, cc.y);        /*[maybe give message here?]*/
+           else
+               mnexto(mtmp);
+
+           if ((mtmp = m_at(u.ux, u.uy)) != 0) {
+               impossible("mnexto failed (do.c)?");
+               (void) rloc(mtmp, FALSE);
+           }
+       }
+
+       /* initial movement of bubbles just before vision_recalc */
+       if (Is_waterlevel(&u.uz))
+               movebubbles();
+
+       if (level_info[new_ledger].flags & FORGOTTEN) {
+           forget_map(ALL_MAP);        /* forget the map */
+           forget_traps();             /* forget all traps too */
+           familiar = TRUE;
+           level_info[new_ledger].flags &= ~FORGOTTEN;
+       }
+
+       /* Reset the screen. */
+       vision_reset();         /* reset the blockages */
+       docrt();                /* does a full vision recalc */
+       flush_screen(-1);
+
+       /*
+        *  Move all plines beyond the screen reset.
+        */
+
+       /* give room entrance message, if any */
+       check_special_room(FALSE);
+
+       /* Check whether we just entered Gehennom. */
+       if (!In_hell(&u.uz0) && Inhell) {
+           if (Is_valley(&u.uz)) {
+               You("arrive at the Valley of the Dead...");
+               pline_The("odor of burnt flesh and decay pervades the air.");
+#ifdef MICRO
+               display_nhwindow(WIN_MESSAGE, FALSE);
+#endif
+               You_hear("groans and moans everywhere.");
+           } else pline("It is hot here.  You smell smoke...");
+       }
+
+       if (familiar) {
+           static const char * const fam_msgs[4] = {
+               "You have a sense of deja vu.",
+               "You feel like you've been here before.",
+               "This place %s familiar...",
+               0       /* no message */
+           };
+           static const char * const halu_fam_msgs[4] = {
+               "Whoa!  Everything %s different.",
+               "You are surrounded by twisty little passages, all alike.",
+               "Gee, this %s like uncle Conan's place...",
+               0       /* no message */
+           };
+           const char *mesg;
+           char buf[BUFSZ];
+           int which = rn2(4);
+
+           if (Hallucination)
+               mesg = halu_fam_msgs[which];
+           else
+               mesg = fam_msgs[which];
+           if (mesg && index(mesg, '%')) {
+               Sprintf(buf, mesg, !Blind ? "looks" : "seems");
+               mesg = buf;
+           }
+           if (mesg) pline(mesg);
+       }
+
+#ifdef REINCARNATION
+       if (new && Is_rogue_level(&u.uz))
+           You("enter what seems to be an older, more primitive world.");
+#endif
+       /* Final confrontation */
+       if (In_endgame(&u.uz) && newdungeon && u.uhave.amulet)
+               resurrect();
+       if (newdungeon && In_V_tower(&u.uz) && In_hell(&u.uz0))
+               pline_The("heat and smoke are gone.");
+
+       /* the message from your quest leader */
+       if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") &&
+               !(u.uevent.qexpelled || u.uevent.qcompleted || quest_status.leader_is_dead)) {
+
+               if (u.uevent.qcalled) {
+                       com_pager(Role_if(PM_ROGUE) ? 4 : 3);
+               } else {
+                       com_pager(2);
+                       u.uevent.qcalled = TRUE;
+               }
+       }
+
+       /* once Croesus is dead, his alarm doesn't work any more */
+       if (Is_knox(&u.uz) && (new || !mvitals[PM_CROESUS].died)) {
+               You("penetrated a high security area!");
+               pline("An alarm sounds!");
+               for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+                   if (!DEADMONSTER(mtmp) && mtmp->msleeping) mtmp->msleeping = 0;
+       }
+
+       if (on_level(&u.uz, &astral_level))
+           final_level();
+       else
+           onquest();
+       assign_level(&u.uz0, &u.uz); /* reset u.uz0 */
+
+#ifdef INSURANCE
+       save_currentstate();
+#endif
+
+       /* assume this will always return TRUE when changing level */
+       (void) in_out_region(u.ux, u.uy);
+       (void) pickup(1);
+}
+
+STATIC_OVL void
+final_level()
+{
+       struct monst *mtmp;
+       struct obj *otmp;
+       coord mm;
+       int i;
+
+       /* reset monster hostility relative to player */
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+           if (!DEADMONSTER(mtmp)) reset_hostility(mtmp);
+
+       /* create some player-monsters */
+       create_mplayers(rn1(4, 3), TRUE);
+
+       /* create a guardian angel next to player, if worthy */
+       if (Conflict) {
+           pline(
+            "A voice booms: \"Thy desire for conflict shall be fulfilled!\"");
+           for (i = rnd(4); i > 0; --i) {
+               mm.x = u.ux;
+               mm.y = u.uy;
+               if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]))
+                   (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,
+                                    mm.x, mm.y, FALSE);
+           }
+
+       } else if (u.ualign.record > 8) {       /* fervent */
+           pline("A voice whispers: \"Thou hast been worthy of me!\"");
+           mm.x = u.ux;
+           mm.y = u.uy;
+           if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) {
+               if ((mtmp = mk_roamer(&mons[PM_ANGEL], u.ualign.type,
+                                     mm.x, mm.y, TRUE)) != 0) {
+                   if (!Blind)
+                       pline("An angel appears near you.");
+                   else
+                       You_feel("the presence of a friendly angel near you.");
+                   /* guardian angel -- the one case mtame doesn't
+                    * imply an edog structure, so we don't want to
+                    * call tamedog().
+                    */
+                   mtmp->mtame = 10;
+                   /* make him strong enough vs. endgame foes */
+                   mtmp->m_lev = rn1(8,15);
+                   mtmp->mhp = mtmp->mhpmax =
+                                       d((int)mtmp->m_lev,10) + 30 + rnd(30);
+                   if ((otmp = select_hwep(mtmp)) == 0) {
+                       otmp = mksobj(SILVER_SABER, FALSE, FALSE);
+                       if (mpickobj(mtmp, otmp))
+                           panic("merged weapon?");
+                   }
+                   bless(otmp);
+                   if (otmp->spe < 4) otmp->spe += rnd(4);
+                   if ((otmp = which_armor(mtmp, W_ARMS)) == 0 ||
+                           otmp->otyp != SHIELD_OF_REFLECTION) {
+                       (void) mongets(mtmp, AMULET_OF_REFLECTION);
+                       m_dowear(mtmp, TRUE);
+                   }
+               }
+           }
+       }
+}
+
+static char *dfr_pre_msg = 0,  /* pline() before level change */
+           *dfr_post_msg = 0;  /* pline() after level change */
+
+/* change levels at the end of this turn, after monsters finish moving */
+void
+schedule_goto(tolev, at_stairs, falling, portal_flag, pre_msg, post_msg)
+d_level *tolev;
+boolean at_stairs, falling;
+int portal_flag;
+const char *pre_msg, *post_msg;
+{
+       int typmask = 0100;             /* non-zero triggers `deferred_goto' */
+
+       /* destination flags (`goto_level' args) */
+       if (at_stairs)   typmask |= 1;
+       if (falling)     typmask |= 2;
+       if (portal_flag) typmask |= 4;
+       if (portal_flag < 0) typmask |= 0200;   /* flag for portal removal */
+       u.utotype = typmask;
+       /* destination level */
+       assign_level(&u.utolev, tolev);
+
+       if (pre_msg)
+           dfr_pre_msg = strcpy((char *)alloc(strlen(pre_msg) + 1), pre_msg);
+       if (post_msg)
+           dfr_post_msg = strcpy((char *)alloc(strlen(post_msg)+1), post_msg);
+}
+
+/* handle something like portal ejection */
+void
+deferred_goto()
+{
+       if (!on_level(&u.uz, &u.utolev)) {
+           d_level dest;
+           int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */
+
+           assign_level(&dest, &u.utolev);
+           if (dfr_pre_msg) pline(dfr_pre_msg);
+           goto_level(&dest, !!(typmask&1), !!(typmask&2), !!(typmask&4));
+           if (typmask & 0200) {       /* remove portal */
+               struct trap *t = t_at(u.ux, u.uy);
+
+               if (t) {
+                   deltrap(t);
+                   newsym(u.ux, u.uy);
+               }
+           }
+           if (dfr_post_msg) pline(dfr_post_msg);
+       }
+       u.utotype = 0;          /* our caller keys off of this */
+       if (dfr_pre_msg)
+           free((genericptr_t)dfr_pre_msg),  dfr_pre_msg = 0;
+       if (dfr_post_msg)
+           free((genericptr_t)dfr_post_msg),  dfr_post_msg = 0;
+}
+
+#endif /* OVL2 */
+#ifdef OVL3
+
+/*
+ * Return TRUE if we created a monster for the corpse.  If successful, the
+ * corpse is gone.
+ */
+boolean
+revive_corpse(corpse)
+struct obj *corpse;
+{
+    struct monst *mtmp, *mcarry;
+    boolean is_uwep, chewed;
+    xchar where;
+    char *cname, cname_buf[BUFSZ];
+    struct obj *container = (struct obj *)0;
+    int container_where = 0;
+    
+    where = corpse->where;
+    is_uwep = corpse == uwep;
+    cname = eos(strcpy(cname_buf, "bite-covered "));
+    Strcpy(cname, corpse_xname(corpse, TRUE));
+    mcarry = (where == OBJ_MINVENT) ? corpse->ocarry : 0;
+
+    if (where == OBJ_CONTAINED) {
+       struct monst *mtmp2 = (struct monst *)0;
+       container = corpse->ocontainer;
+       mtmp2 = get_container_location(container, &container_where, (int *)0);
+       /* container_where is the outermost container's location even if nested */
+       if (container_where == OBJ_MINVENT && mtmp2) mcarry = mtmp2;
+    }
+    mtmp = revive(corpse);     /* corpse is gone if successful */
+
+    if (mtmp) {
+       chewed = (mtmp->mhp < mtmp->mhpmax);
+       if (chewed) cname = cname_buf;  /* include "bite-covered" prefix */
+       switch (where) {
+           case OBJ_INVENT:
+               if (is_uwep)
+                   pline_The("%s writhes out of your grasp!", cname);
+               else
+                   You_feel("squirming in your backpack!");
+               break;
+
+           case OBJ_FLOOR:
+               if (cansee(mtmp->mx, mtmp->my))
+                   pline("%s rises from the dead!", chewed ?
+                         Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp));
+               break;
+
+           case OBJ_MINVENT:           /* probably a nymph's */
+               if (cansee(mtmp->mx, mtmp->my)) {
+                   if (canseemon(mcarry))
+                       pline("Startled, %s drops %s as it revives!",
+                             mon_nam(mcarry), an(cname));
+                   else
+                       pline("%s suddenly appears!", chewed ?
+                             Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp));
+               }
+               break;
+          case OBJ_CONTAINED:
+               if (container_where == OBJ_MINVENT && cansee(mtmp->mx, mtmp->my) &&
+                   mcarry && canseemon(mcarry) && container) {
+                       char sackname[BUFSZ];
+                       Sprintf(sackname, "%s %s", s_suffix(mon_nam(mcarry)),
+                               xname(container)); 
+                       pline("%s writhes out of %s!", Amonnam(mtmp), sackname);
+               } else if (container_where == OBJ_INVENT && container) {
+                       char sackname[BUFSZ];
+                       Strcpy(sackname, an(xname(container)));
+                       pline("%s %s out of %s in your pack!",
+                               Blind ? Something : Amonnam(mtmp),
+                               locomotion(mtmp->data,"writhes"),
+                               sackname);
+               } else if (container_where == OBJ_FLOOR && container &&
+                           cansee(mtmp->mx, mtmp->my)) {
+                       char sackname[BUFSZ];
+                       Strcpy(sackname, an(xname(container)));
+                       pline("%s escapes from %s!", Amonnam(mtmp), sackname);
+               }
+               break;
+           default:
+               /* we should be able to handle the other cases... */
+               impossible("revive_corpse: lost corpse @ %d", where);
+               break;
+       }
+       return TRUE;
+    }
+    return FALSE;
+}
+
+/* Revive the corpse via a timeout. */
+/*ARGSUSED*/
+void
+revive_mon(arg, timeout)
+genericptr_t arg;
+long timeout;
+{
+    struct obj *body = (struct obj *) arg;
+
+    /* if we succeed, the corpse is gone, otherwise, rot it away */
+    if (!revive_corpse(body)) {
+       if (is_rider(&mons[body->corpsenm]))
+           You_feel("less hassled.");
+       (void) start_timer(250L - (monstermoves-body->age),
+                                       TIMER_OBJECT, ROT_CORPSE, arg);
+    }
+}
+
+int
+donull()
+{
+       return(1);      /* Do nothing, but let other things happen */
+}
+
+#endif /* OVL3 */
+#ifdef OVLB
+
+STATIC_PTR int
+wipeoff()
+{
+       if(u.ucreamed < 4)      u.ucreamed = 0;
+       else                    u.ucreamed -= 4;
+       if (Blinded < 4)        Blinded = 0;
+       else                    Blinded -= 4;
+       if (!Blinded) {
+               pline("You've got the glop off.");
+               u.ucreamed = 0;
+               Blinded = 1;
+               make_blinded(0L,TRUE);
+               return(0);
+       } else if (!u.ucreamed) {
+               Your("%s feels clean now.", body_part(FACE));
+               return(0);
+       }
+       return(1);              /* still busy */
+}
+
+int
+dowipe()
+{
+       if(u.ucreamed)  {
+               static NEARDATA char buf[39];
+
+               Sprintf(buf, "wiping off your %s", body_part(FACE));
+               set_occupation(wipeoff, buf, 0);
+               /* Not totally correct; what if they change back after now
+                * but before they're finished wiping?
+                */
+               return(1);
+       }
+       Your("%s is already clean.", body_part(FACE));
+       return(1);
+}
+
+void
+set_wounded_legs(side, timex)
+register long side;
+register int timex;
+{
+       /* KMH -- STEED
+        * If you are riding, your steed gets the wounded legs instead.
+        * You still call this function, but don't lose hp.
+        * Caller is also responsible for adjusting messages.
+        */
+
+       if(!Wounded_legs) {
+               ATEMP(A_DEX)--;
+               flags.botl = 1;
+       }
+
+       if(!Wounded_legs || (HWounded_legs & TIMEOUT))
+               HWounded_legs = timex;
+       EWounded_legs = side;
+       (void)encumber_msg();
+}
+
+void
+heal_legs()
+{
+       if(Wounded_legs) {
+               if (ATEMP(A_DEX) < 0) {
+                       ATEMP(A_DEX)++;
+                       flags.botl = 1;
+               }
+
+#ifdef STEED
+               if (!u.usteed)
+#endif
+               {
+                       /* KMH, intrinsics patch */
+                       if((EWounded_legs & BOTH_SIDES) == BOTH_SIDES) {
+                       Your("%s feel somewhat better.",
+                               makeplural(body_part(LEG)));
+               } else {
+                       Your("%s feels somewhat better.",
+                               body_part(LEG));
+               }
+               }
+               HWounded_legs = EWounded_legs = 0;
+       }
+       (void)encumber_msg();
+}
+
+#endif /* OVLB */
+
+/*do.c*/
diff --git a/src/do_name.c b/src/do_name.c
new file mode 100644 (file)
index 0000000..47b3f87
--- /dev/null
@@ -0,0 +1,1044 @@
+/*     SCCS Id: @(#)do_name.c  3.4     2003/01/14      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+#ifdef OVLB
+
+STATIC_DCL void FDECL(do_oname, (struct obj *));
+static void FDECL(getpos_help, (BOOLEAN_P,const char *));
+
+extern const char what_is_an_unknown_object[];         /* from pager.c */
+
+/* the response for '?' help request in getpos() */
+static void
+getpos_help(force, goal)
+boolean force;
+const char *goal;
+{
+    char sbuf[BUFSZ];
+    boolean doing_what_is;
+    winid tmpwin = create_nhwindow(NHW_MENU);
+
+    Sprintf(sbuf, "Use [%s] to move the cursor to %s.",
+           iflags.num_pad ? "2468" : "hjkl", goal);
+    putstr(tmpwin, 0, sbuf);
+    putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time.");
+    putstr(tmpwin, 0, "Or enter a background symbol (ex. <).");
+    /* disgusting hack; the alternate selection characters work for any
+       getpos call, but they only matter for dowhatis (and doquickwhatis) */
+    doing_what_is = (goal == what_is_an_unknown_object);
+    Sprintf(sbuf, "Type a .%s when you are at the right place.",
+            doing_what_is ? " or , or ; or :" : "");
+    putstr(tmpwin, 0, sbuf);
+    if (!force)
+       putstr(tmpwin, 0, "Type Space or Escape when you're done.");
+    putstr(tmpwin, 0, "");
+    display_nhwindow(tmpwin, TRUE);
+    destroy_nhwindow(tmpwin);
+}
+
+int
+getpos(cc, force, goal)
+coord *cc;
+boolean force;
+const char *goal;
+{
+    int result = 0;
+    int cx, cy, i, c;
+    int sidx, tx, ty;
+    boolean msg_given = TRUE;  /* clear message window by default */
+    static const char pick_chars[] = ".,;:";
+    const char *cp;
+    const char *sdp;
+    if(iflags.num_pad) sdp = ndir; else sdp = sdir;    /* DICE workaround */
+
+    if (flags.verbose) {
+       pline("(For instructions type a ?)");
+       msg_given = TRUE;
+    }
+    cx = cc->x;
+    cy = cc->y;
+#ifdef CLIPPING
+    cliparound(cx, cy);
+#endif
+    curs(WIN_MAP, cx,cy);
+    flush_screen(0);
+#ifdef MAC
+    lock_mouse_cursor(TRUE);
+#endif
+    for (;;) {
+       c = nh_poskey(&tx, &ty, &sidx);
+       if (c == '\033') {
+           cx = cy = -10;
+           msg_given = TRUE;   /* force clear */
+           result = -1;
+           break;
+       }
+       if(c == 0) {
+           if (!isok(tx, ty)) continue;
+           /* a mouse click event, just assign and return */
+           cx = tx;
+           cy = ty;
+           break;
+       }
+       if ((cp = index(pick_chars, c)) != 0) {
+           /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
+           result = cp - pick_chars;
+           break;
+       }
+       for (i = 0; i < 8; i++) {
+           int dx, dy;
+
+           if (sdp[i] == c) {
+               /* a normal movement letter or digit */
+               dx = xdir[i];
+               dy = ydir[i];
+           } else if (sdir[i] == lowc((char)c)) {
+               /* a shifted movement letter */
+               dx = 8 * xdir[i];
+               dy = 8 * ydir[i];
+           } else
+               continue;
+
+           /* truncate at map edge; diagonal moves complicate this... */
+           if (cx + dx < 1) {
+               dy -= sgn(dy) * (1 - (cx + dx));
+               dx = 1 - cx;            /* so that (cx+dx == 1) */
+           } else if (cx + dx > COLNO-1) {
+               dy += sgn(dy) * ((COLNO-1) - (cx + dx));
+               dx = (COLNO-1) - cx;
+           }
+           if (cy + dy < 0) {
+               dx -= sgn(dx) * (0 - (cy + dy));
+               dy = 0 - cy;            /* so that (cy+dy == 0) */
+           } else if (cy + dy > ROWNO-1) {
+               dx += sgn(dx) * ((ROWNO-1) - (cy + dy));
+               dy = (ROWNO-1) - cy;
+           }
+           cx += dx;
+           cy += dy;
+           goto nxtc;
+       }
+
+       if(c == '?'){
+           getpos_help(force, goal);
+       } else {
+           if (!index(quitchars, c)) {
+               char matching[MAXPCHARS];
+               int pass, lo_x, lo_y, hi_x, hi_y, k = 0;
+               (void)memset((genericptr_t)matching, 0, sizeof matching);
+               for (sidx = 1; sidx < MAXPCHARS; sidx++)
+                   if (c == defsyms[sidx].sym || c == (int)showsyms[sidx])
+                       matching[sidx] = (char) ++k;
+               if (k) {
+                   for (pass = 0; pass <= 1; pass++) {
+                       /* pass 0: just past current pos to lower right;
+                          pass 1: upper left corner to current pos */
+                       lo_y = (pass == 0) ? cy : 0;
+                       hi_y = (pass == 0) ? ROWNO - 1 : cy;
+                       for (ty = lo_y; ty <= hi_y; ty++) {
+                           lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1;
+                           hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1;
+                           for (tx = lo_x; tx <= hi_x; tx++) {
+                               k = levl[tx][ty].glyph;
+                               if (glyph_is_cmap(k) &&
+                                       matching[glyph_to_cmap(k)]) {
+                                   cx = tx,  cy = ty;
+                                   if (msg_given) {
+                                       clear_nhwindow(WIN_MESSAGE);
+                                       msg_given = FALSE;
+                                   }
+                                   goto nxtc;
+                               }
+                           }   /* column */
+                       }       /* row */
+                   }           /* pass */
+                   pline("Can't find dungeon feature '%c'.", c);
+                   msg_given = TRUE;
+                   goto nxtc;
+               } else {
+                   pline("Unknown direction: '%s' (%s).",
+                         visctrl((char)c),
+                         !force ? "aborted" :
+                         iflags.num_pad ? "use 2468 or ." : "use hjkl or .");
+                   msg_given = TRUE;
+               } /* k => matching */
+           } /* !quitchars */
+           if (force) goto nxtc;
+           pline("Done.");
+           msg_given = FALSE;  /* suppress clear */
+           cx = -1;
+           cy = 0;
+           result = 0; /* not -1 */
+           break;
+       }
+    nxtc:      ;
+#ifdef CLIPPING
+       cliparound(cx, cy);
+#endif
+       curs(WIN_MAP,cx,cy);
+       flush_screen(0);
+    }
+#ifdef MAC
+    lock_mouse_cursor(FALSE);
+#endif
+    if (msg_given) clear_nhwindow(WIN_MESSAGE);
+    cc->x = cx;
+    cc->y = cy;
+    return result;
+}
+
+struct monst *
+christen_monst(mtmp, name)
+struct monst *mtmp;
+const char *name;
+{
+       int lth;
+       struct monst *mtmp2;
+       char buf[PL_PSIZ];
+
+       /* dogname & catname are PL_PSIZ arrays; object names have same limit */
+       lth = *name ? (int)(strlen(name) + 1) : 0;
+       if(lth > PL_PSIZ){
+               lth = PL_PSIZ;
+               name = strncpy(buf, name, PL_PSIZ - 1);
+               buf[PL_PSIZ - 1] = '\0';
+       }
+       if (lth == mtmp->mnamelth) {
+               /* don't need to allocate a new monst struct */
+               if (lth) Strcpy(NAME(mtmp), name);
+               return mtmp;
+       }
+       mtmp2 = newmonst(mtmp->mxlth + lth);
+       *mtmp2 = *mtmp;
+       (void) memcpy((genericptr_t)mtmp2->mextra,
+                     (genericptr_t)mtmp->mextra, mtmp->mxlth);
+       mtmp2->mnamelth = lth;
+       if (lth) Strcpy(NAME(mtmp2), name);
+       replmon(mtmp,mtmp2);
+       return(mtmp2);
+}
+
+int
+do_mname()
+{
+       char buf[BUFSZ];
+       coord cc;
+       register int cx,cy;
+       register struct monst *mtmp;
+       char qbuf[QBUFSZ];
+
+       if (Hallucination) {
+               You("would never recognize it anyway.");
+               return 0;
+       }
+       cc.x = u.ux;
+       cc.y = u.uy;
+       if (getpos(&cc, FALSE, "the monster you want to name") < 0 ||
+                       (cx = cc.x) < 0)
+               return 0;
+       cy = cc.y;
+
+       if (cx == u.ux && cy == u.uy) {
+#ifdef STEED
+           if (u.usteed && canspotmon(u.usteed))
+               mtmp = u.usteed;
+           else {
+#endif
+               pline("This %s creature is called %s and cannot be renamed.",
+               ACURR(A_CHA) > 14 ?
+               (flags.female ? "beautiful" : "handsome") :
+               "ugly",
+               plname);
+               return(0);
+#ifdef STEED
+           }
+#endif
+       } else
+           mtmp = m_at(cx, cy);
+
+       if (!mtmp || (!sensemon(mtmp) &&
+                       (!(cansee(cx,cy) || see_with_infrared(mtmp)) || mtmp->mundetected
+                       || mtmp->m_ap_type == M_AP_FURNITURE
+                       || mtmp->m_ap_type == M_AP_OBJECT
+                       || (mtmp->minvis && !See_invisible)))) {
+               pline("I see no monster there.");
+               return(0);
+       }
+       /* special case similar to the one in lookat() */
+       (void) distant_monnam(mtmp, ARTICLE_THE, buf);
+       Sprintf(qbuf, "What do you want to call %s?", buf);
+       getlin(qbuf,buf);
+       if(!*buf || *buf == '\033') return(0);
+       /* strip leading and trailing spaces; unnames monster if all spaces */
+       (void)mungspaces(buf);
+
+       if (mtmp->data->geno & G_UNIQ)
+           pline("%s doesn't like being called names!", Monnam(mtmp));
+       else
+           (void) christen_monst(mtmp, buf);
+       return(0);
+}
+
+/*
+ * This routine changes the address of obj. Be careful not to call it
+ * when there might be pointers around in unknown places. For now: only
+ * when obj is in the inventory.
+ */
+STATIC_OVL
+void
+do_oname(obj)
+register struct obj *obj;
+{
+       char buf[BUFSZ], qbuf[QBUFSZ];
+       const char *aname;
+       short objtyp;
+
+       Sprintf(qbuf, "What do you want to name %s %s?",
+               is_plural(obj) ? "these" : "this", xname(obj));
+       getlin(qbuf, buf);
+       if(!*buf || *buf == '\033')     return;
+       /* strip leading and trailing spaces; unnames item if all spaces */
+       (void)mungspaces(buf);
+
+       /* relax restrictions over proper capitalization for artifacts */
+       if ((aname = artifact_name(buf, &objtyp)) != 0 && objtyp == obj->otyp)
+               Strcpy(buf, aname);
+
+       if (obj->oartifact) {
+               pline_The("artifact seems to resist the attempt.");
+               return;
+       } else if (restrict_name(obj, buf) || exist_artifact(obj->otyp, buf)) {
+               int n = rn2((int)strlen(buf));
+               register char c1, c2;
+
+               c1 = lowc(buf[n]);
+               do c2 = 'a' + rn2('z'-'a'); while (c1 == c2);
+               buf[n] = (buf[n] == c1) ? c2 : highc(c2);  /* keep same case */
+               pline("While engraving your %s slips.", body_part(HAND));
+               display_nhwindow(WIN_MESSAGE, FALSE);
+               You("engrave: \"%s\".",buf);
+       }
+       obj = oname(obj, buf);
+}
+
+/*
+ * Allocate a new and possibly larger storage space for an obj.
+ */
+struct obj *
+realloc_obj(obj, oextra_size, oextra_src, oname_size, name)
+struct obj *obj;
+int oextra_size;               /* storage to allocate for oextra            */
+genericptr_t oextra_src;
+int oname_size;                        /* size of name string + 1 (null terminator) */
+const char *name;
+{
+       struct obj *otmp;
+
+       otmp = newobj(oextra_size + oname_size);
+       *otmp = *obj;   /* the cobj pointer is copied to otmp */
+       if (oextra_size) {
+           if (oextra_src)
+               (void) memcpy((genericptr_t)otmp->oextra, oextra_src,
+                                                       oextra_size);
+       } else {
+           otmp->oattached = OATTACHED_NOTHING;
+       }
+       otmp->oxlth = oextra_size;
+
+       otmp->onamelth = oname_size;
+       otmp->timed = 0;        /* not timed, yet */
+       otmp->lamplit = 0;      /* ditto */
+       /* __GNUC__ note:  if the assignment of otmp->onamelth immediately
+          precedes this `if' statement, a gcc bug will miscompile the
+          test on vax (`insv' instruction used to store bitfield does
+          not set condition codes, but optimizer behaves as if it did).
+          gcc-2.7.2.1 finally fixed this. */
+       if (oname_size) {
+           if (name)
+               Strcpy(ONAME(otmp), name);
+       }
+
+       if (obj->owornmask) {
+               boolean save_twoweap = u.twoweap;
+               /* unwearing the old instance will clear dual-wield mode
+                  if this object is either of the two weapons */
+               setworn((struct obj *)0, obj->owornmask);
+               setworn(otmp, otmp->owornmask);
+               u.twoweap = save_twoweap;
+       }
+
+       /* replace obj with otmp */
+       replace_object(obj, otmp);
+
+       /* fix ocontainer pointers */
+       if (Has_contents(obj)) {
+               struct obj *inside;
+
+               for(inside = obj->cobj; inside; inside = inside->nobj)
+                       inside->ocontainer = otmp;
+       }
+
+       /* move timers and light sources from obj to otmp */
+       if (obj->timed) obj_move_timers(obj, otmp);
+       if (obj->lamplit) obj_move_light_source(obj, otmp);
+
+       /* objects possibly being manipulated by multi-turn occupations
+          which have been interrupted but might be subsequently resumed */
+       if (obj->oclass == FOOD_CLASS)
+           food_substitution(obj, otmp);       /* eat food or open tin */
+       else if (obj->oclass == SPBOOK_CLASS)
+           book_substitution(obj, otmp);       /* read spellbook */
+
+       /* obfree(obj, otmp);   now unnecessary: no pointers on bill */
+       dealloc_obj(obj);       /* let us hope nobody else saved a pointer */
+       return otmp;
+}
+
+struct obj *
+oname(obj, name)
+struct obj *obj;
+const char *name;
+{
+       int lth;
+       char buf[PL_PSIZ];
+
+       lth = *name ? (int)(strlen(name) + 1) : 0;
+       if (lth > PL_PSIZ) {
+               lth = PL_PSIZ;
+               name = strncpy(buf, name, PL_PSIZ - 1);
+               buf[PL_PSIZ - 1] = '\0';
+       }
+       /* If named artifact exists in the game, do not create another.
+        * Also trying to create an artifact shouldn't de-artifact
+        * it (e.g. Excalibur from prayer). In this case the object
+        * will retain its current name. */
+       if (obj->oartifact || (lth && exist_artifact(obj->otyp, name)))
+               return obj;
+
+       if (lth == obj->onamelth) {
+               /* no need to replace entire object */
+               if (lth) Strcpy(ONAME(obj), name);
+       } else {
+               obj = realloc_obj(obj, obj->oxlth,
+                             (genericptr_t)obj->oextra, lth, name);
+       }
+       if (lth) artifact_exists(obj, name, TRUE);
+       if (obj->oartifact) {
+           /* can't dual-wield with artifact as secondary weapon */
+           if (obj == uswapwep) untwoweapon();
+           /* activate warning if you've just named your weapon "Sting" */
+           if (obj == uwep) set_artifact_intrinsic(obj, TRUE, W_WEP);
+       }
+       if (carried(obj)) update_inventory();
+       return obj;
+}
+
+static NEARDATA const char callable[] = {
+       SCROLL_CLASS, POTION_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS,
+       GEM_CLASS, SPBOOK_CLASS, ARMOR_CLASS, TOOL_CLASS, 0 };
+
+int
+ddocall()
+{
+       register struct obj *obj;
+#ifdef REDO
+       char    ch;
+#endif
+       char allowall[2];
+
+       switch(
+#ifdef REDO
+               ch =
+#endif
+               ynq("Name an individual object?")) {
+       case 'q':
+               break;
+       case 'y':
+#ifdef REDO
+               savech(ch);
+#endif
+               allowall[0] = ALL_CLASSES; allowall[1] = '\0';
+               obj = getobj(allowall, "name");
+               if(obj) do_oname(obj);
+               break;
+       default :
+#ifdef REDO
+               savech(ch);
+#endif
+               obj = getobj(callable, "call");
+               if (obj) {
+                       /* behave as if examining it in inventory;
+                          this might set dknown if it was picked up
+                          while blind and the hero can now see */
+                       (void) xname(obj);
+
+                       if (!obj->dknown) {
+                               You("would never recognize another one.");
+                               return 0;
+                       }
+                       docall(obj);
+               }
+               break;
+       }
+       return 0;
+}
+
+void
+docall(obj)
+register struct obj *obj;
+{
+       char buf[BUFSZ], qbuf[QBUFSZ];
+       struct obj otemp;
+       register char **str1;
+
+       if (!obj->dknown) return; /* probably blind */
+       otemp = *obj;
+       otemp.quan = 1L;
+       otemp.onamelth = 0;
+       otemp.oxlth = 0;
+       if (objects[otemp.otyp].oc_class == POTION_CLASS && otemp.fromsink)
+           /* kludge, meaning it's sink water */
+           Sprintf(qbuf,"Call a stream of %s fluid:",
+                   OBJ_DESCR(objects[otemp.otyp]));
+       else
+           Sprintf(qbuf, "Call %s:", an(xname(&otemp)));
+       getlin(qbuf, buf);
+       if(!*buf || *buf == '\033')
+               return;
+
+       /* clear old name */
+       str1 = &(objects[obj->otyp].oc_uname);
+       if(*str1) free((genericptr_t)*str1);
+
+       /* strip leading and trailing spaces; uncalls item if all spaces */
+       (void)mungspaces(buf);
+       if (!*buf) {
+           if (*str1) {        /* had name, so possibly remove from disco[] */
+               /* strip name first, for the update_inventory() call
+                  from undiscover_object() */
+               *str1 = (char *)0;
+               undiscover_object(obj->otyp);
+           }
+       } else {
+           *str1 = strcpy((char *) alloc((unsigned)strlen(buf)+1), buf);
+           discover_object(obj->otyp, FALSE, TRUE); /* possibly add to disco[] */
+       }
+}
+
+#endif /*OVLB*/
+#ifdef OVL0
+
+static const char * const ghostnames[] = {
+       /* these names should have length < PL_NSIZ */
+       /* Capitalize the names for aesthetics -dgk */
+       "Adri", "Andries", "Andreas", "Bert", "David", "Dirk", "Emile",
+       "Frans", "Fred", "Greg", "Hether", "Jay", "John", "Jon", "Karnov",
+       "Kay", "Kenny", "Kevin", "Maud", "Michiel", "Mike", "Peter", "Robert",
+       "Ron", "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue",
+       "Stephan", "Lance Braccus", "Shadowhawk"
+};
+
+/* ghost names formerly set by x_monnam(), now by makemon() instead */
+const char *
+rndghostname()
+{
+    return rn2(7) ? ghostnames[rn2(SIZE(ghostnames))] : (const char *)plname;
+}
+
+/* Monster naming functions:
+ * x_monnam is the generic monster-naming function.
+ *               seen        unseen       detected               named
+ * mon_nam:    the newt        it      the invisible orc       Fido
+ * noit_mon_nam:the newt (as if detected) the invisible orc    Fido
+ * l_monnam:   newt            it      invisible orc           dog called fido
+ * Monnam:     The newt        It      The invisible orc       Fido
+ * noit_Monnam: The newt (as if detected) The invisible orc    Fido
+ * Adjmonnam:  The poor newt   It      The poor invisible orc  The poor Fido
+ * Amonnam:    A newt          It      An invisible orc        Fido
+ * a_monnam:   a newt          it      an invisible orc        Fido
+ * m_monnam:   newt            xan     orc                     Fido
+ * y_monnam:   your newt     your xan  your invisible orc      Fido
+ */
+
+/* Bug: if the monster is a priest or shopkeeper, not every one of these
+ * options works, since those are special cases.
+ */
+char *
+x_monnam(mtmp, article, adjective, suppress, called)
+register struct monst *mtmp;
+int article;
+/* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
+ * ARTICLE_YOUR: "your" on pets, "the" on everything else
+ *
+ * If the monster would be referred to as "it" or if the monster has a name
+ * _and_ there is no adjective, "invisible", "saddled", etc., override this
+ * and always use no article.
+ */
+const char *adjective;
+int suppress;
+/* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
+ * EXACT_NAME: combination of all the above
+ */
+boolean called;
+{
+#ifdef LINT    /* static char buf[BUFSZ]; */
+       char buf[BUFSZ];
+#else
+       static char buf[BUFSZ];
+#endif
+       struct permonst *mdat = mtmp->data;
+       boolean do_hallu, do_invis, do_it, do_saddle;
+       boolean name_at_start, has_adjectives;
+       char *bp;
+
+       if (program_state.gameover)
+           suppress |= SUPPRESS_HALLUCINATION;
+       if (article == ARTICLE_YOUR && !mtmp->mtame)
+           article = ARTICLE_THE;
+
+       do_hallu = Hallucination && !(suppress & SUPPRESS_HALLUCINATION);
+       do_invis = mtmp->minvis && !(suppress & SUPPRESS_INVISIBLE);
+       do_it = !canspotmon(mtmp) && 
+           article != ARTICLE_YOUR &&
+           !program_state.gameover &&
+#ifdef STEED
+           mtmp != u.usteed &&
+#endif
+           !(u.uswallow && mtmp == u.ustuck) &&
+           !(suppress & SUPPRESS_IT);
+       do_saddle = !(suppress & SUPPRESS_SADDLE);
+
+       buf[0] = 0;
+
+       /* unseen monsters, etc.  Use "it" */
+       if (do_it) {
+           Strcpy(buf, "it");
+           return buf;
+       }
+
+       /* priests and minions: don't even use this function */
+       if (mtmp->ispriest || mtmp->isminion) {
+           char priestnambuf[BUFSZ];
+           char *name;
+           long save_prop = EHalluc_resistance;
+           unsigned save_invis = mtmp->minvis;
+
+           /* when true name is wanted, explicitly block Hallucination */
+           if (!do_hallu) EHalluc_resistance = 1L;
+           if (!do_invis) mtmp->minvis = 0;
+           name = priestname(mtmp, priestnambuf);
+           EHalluc_resistance = save_prop;
+           mtmp->minvis = save_invis;
+           if (article == ARTICLE_NONE && !strncmp(name, "the ", 4))
+               name += 4;
+           return strcpy(buf, name);
+       }
+
+       /* Shopkeepers: use shopkeeper name.  For normal shopkeepers, just
+        * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
+        * shopkeeper" or "Asidonhopo the blue dragon".  If hallucinating,
+        * none of this applies.
+        */
+       if (mtmp->isshk && !do_hallu) {
+           if (adjective && article == ARTICLE_THE) {
+               /* pathological case: "the angry Asidonhopo the blue dragon"
+                  sounds silly */
+               Strcpy(buf, "the ");
+               Strcat(strcat(buf, adjective), " ");
+               Strcat(buf, shkname(mtmp));
+               return buf;
+           }
+           Strcat(buf, shkname(mtmp));
+           if (mdat == &mons[PM_SHOPKEEPER] && !do_invis)
+               return buf;
+           Strcat(buf, " the ");
+           if (do_invis)
+               Strcat(buf, "invisible ");
+           Strcat(buf, mdat->mname);
+           return buf;
+       }
+
+       /* Put the adjectives in the buffer */
+       if (adjective)
+           Strcat(strcat(buf, adjective), " ");
+       if (do_invis)
+           Strcat(buf, "invisible ");
+#ifdef STEED
+       if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) &&
+           !Blind && !Hallucination)
+           Strcat(buf, "saddled ");
+#endif
+       if (buf[0] != 0)
+           has_adjectives = TRUE;
+       else
+           has_adjectives = FALSE;
+
+       /* Put the actual monster name or type into the buffer now */
+       /* Be sure to remember whether the buffer starts with a name */
+       if (do_hallu) {
+           Strcat(buf, rndmonnam());
+           name_at_start = FALSE;
+       } else if (mtmp->mnamelth) {
+           char *name = NAME(mtmp);
+
+           if (mdat == &mons[PM_GHOST]) {
+               Sprintf(eos(buf), "%s ghost", s_suffix(name));
+               name_at_start = TRUE;
+           } else if (called) {
+               Sprintf(eos(buf), "%s called %s", mdat->mname, name);
+               name_at_start = (boolean)type_is_pname(mdat);
+           } else if (is_mplayer(mdat) && (bp = strstri(name, " the ")) != 0) {
+               /* <name> the <adjective> <invisible> <saddled> <rank> */
+               char pbuf[BUFSZ];
+
+               Strcpy(pbuf, name);
+               pbuf[bp - name + 5] = '\0'; /* adjectives right after " the " */
+               if (has_adjectives)
+                   Strcat(pbuf, buf);
+               Strcat(pbuf, bp + 5);   /* append the rest of the name */
+               Strcpy(buf, pbuf);
+               article = ARTICLE_NONE;
+               name_at_start = TRUE;
+           } else {
+               Strcat(buf, name);
+               name_at_start = TRUE;
+           }
+       } else if (is_mplayer(mdat) && !In_endgame(&u.uz)) {
+           char pbuf[BUFSZ];
+           Strcpy(pbuf, rank_of((int)mtmp->m_lev,
+                                monsndx(mdat),
+                                (boolean)mtmp->female));
+           Strcat(buf, lcase(pbuf));
+           name_at_start = FALSE;
+       } else {
+           Strcat(buf, mdat->mname);
+           name_at_start = (boolean)type_is_pname(mdat);
+       }
+
+       if (name_at_start && (article == ARTICLE_YOUR || !has_adjectives)) {
+           if (mdat == &mons[PM_WIZARD_OF_YENDOR])
+               article = ARTICLE_THE;
+           else
+               article = ARTICLE_NONE;
+       } else if ((mdat->geno & G_UNIQ) && article == ARTICLE_A) {
+           article = ARTICLE_THE;
+       }
+
+       {
+           char buf2[BUFSZ];
+
+           switch(article) {
+               case ARTICLE_YOUR:
+                   Strcpy(buf2, "your ");
+                   Strcat(buf2, buf);
+                   Strcpy(buf, buf2);
+                   return buf;
+               case ARTICLE_THE:
+                   Strcpy(buf2, "the ");
+                   Strcat(buf2, buf);
+                   Strcpy(buf, buf2);
+                   return buf;
+               case ARTICLE_A:
+                   return(an(buf));
+               case ARTICLE_NONE:
+               default:
+                   return buf;
+           }
+       }
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+char *
+l_monnam(mtmp)
+register struct monst *mtmp;
+{
+       return(x_monnam(mtmp, ARTICLE_NONE, (char *)0, 
+               mtmp->mnamelth ? SUPPRESS_SADDLE : 0, TRUE));
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+char *
+mon_nam(mtmp)
+register struct monst *mtmp;
+{
+       return(x_monnam(mtmp, ARTICLE_THE, (char *)0,
+               mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE));
+}
+
+/* print the name as if mon_nam() was called, but assume that the player
+ * can always see the monster--used for probing and for monsters aggravating
+ * the player with a cursed potion of invisibility
+ */
+char *
+noit_mon_nam(mtmp)
+register struct monst *mtmp;
+{
+       return(x_monnam(mtmp, ARTICLE_THE, (char *)0,
+               mtmp->mnamelth ? (SUPPRESS_SADDLE|SUPPRESS_IT) :
+                   SUPPRESS_IT, FALSE));
+}
+
+char *
+Monnam(mtmp)
+register struct monst *mtmp;
+{
+       register char *bp = mon_nam(mtmp);
+
+       *bp = highc(*bp);
+       return(bp);
+}
+
+char *
+noit_Monnam(mtmp)
+register struct monst *mtmp;
+{
+       register char *bp = noit_mon_nam(mtmp);
+
+       *bp = highc(*bp);
+       return(bp);
+}
+
+/* monster's own name */
+char *
+m_monnam(mtmp)
+struct monst *mtmp;
+{
+       return x_monnam(mtmp, ARTICLE_NONE, (char *)0, EXACT_NAME, FALSE);
+}
+
+/* pet name: "your little dog" */
+char *
+y_monnam(mtmp)
+struct monst *mtmp;
+{
+       int prefix, suppression_flag;
+
+       prefix = mtmp->mtame ? ARTICLE_YOUR : ARTICLE_THE;
+       suppression_flag = (mtmp->mnamelth
+#ifdef STEED
+                           /* "saddled" is redundant when mounted */
+                           || mtmp == u.usteed
+#endif
+                           ) ? SUPPRESS_SADDLE : 0;
+
+       return x_monnam(mtmp, prefix, (char *)0, suppression_flag, FALSE);
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+char *
+Adjmonnam(mtmp, adj)
+register struct monst *mtmp;
+register const char *adj;
+{
+       register char *bp = x_monnam(mtmp, ARTICLE_THE, adj,
+               mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE);
+
+       *bp = highc(*bp);
+       return(bp);
+}
+
+char *
+a_monnam(mtmp)
+register struct monst *mtmp;
+{
+       return x_monnam(mtmp, ARTICLE_A, (char *)0,
+               mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE);
+}
+
+char *
+Amonnam(mtmp)
+register struct monst *mtmp;
+{
+       register char *bp = a_monnam(mtmp);
+
+       *bp = highc(*bp);
+       return(bp);
+}
+
+/* used for monster ID by the '/', ';', and 'C' commands to block remote
+   identification of the endgame altars via their attending priests */
+char *
+distant_monnam(mon, article, outbuf)
+struct monst *mon;
+int article;   /* only ARTICLE_NONE and ARTICLE_THE are handled here */
+char *outbuf;
+{
+    /* high priest(ess)'s identity is concealed on the Astral Plane,
+       unless you're adjacent (overridden for hallucination which does
+       its own obfuscation) */
+    if (mon->data == &mons[PM_HIGH_PRIEST] && !Hallucination &&
+           Is_astralevel(&u.uz) && distu(mon->mx, mon->my) > 2) {
+       Strcpy(outbuf, article == ARTICLE_THE ? "the " : "");
+       Strcat(outbuf, mon->female ? "high priestess" : "high priest");
+    } else {
+       Strcpy(outbuf, x_monnam(mon, article, (char *)0, 0, TRUE));
+    }
+    return outbuf;
+}
+
+static const char * const bogusmons[] = {
+       "jumbo shrimp", "giant pigmy", "gnu", "killer penguin",
+       "giant cockroach", "giant slug", "maggot", "pterodactyl",
+       "tyrannosaurus rex", "basilisk", "beholder", "nightmare",
+       "efreeti", "marid", "rot grub", "bookworm", "master lichen",
+       "shadow", "hologram", "jester", "attorney", "sleazoid",
+       "killer tomato", "amazon", "robot", "battlemech",
+       "rhinovirus", "harpy", "lion-dog", "rat-ant", "Y2K bug",
+                                               /* misc. */
+       "grue", "Christmas-tree monster", "luck sucker", "paskald",
+       "brogmoid", "dornbeast",                /* Quendor (Zork, &c.) */
+       "Ancient Multi-Hued Dragon", "Evil Iggy",
+                                               /* Moria */
+       "emu", "kestrel", "xeroc", "venus flytrap",
+                                               /* Rogue */
+       "creeping coins",                       /* Wizardry */
+       "hydra", "siren",                       /* Greek legend */
+       "killer bunny",                         /* Monty Python */
+       "rodent of unusual size",               /* The Princess Bride */
+       "Smokey the bear",      /* "Only you can prevent forest fires!" */
+       "Luggage",                              /* Discworld */
+       "Ent",                                  /* Lord of the Rings */
+       "tangle tree", "nickelpede", "wiggle",  /* Xanth */
+       "white rabbit", "snark",                /* Lewis Carroll */
+       "pushmi-pullyu",                        /* Dr. Doolittle */
+       "smurf",                                /* The Smurfs */
+       "tribble", "Klingon", "Borg",           /* Star Trek */
+       "Ewok",                                 /* Star Wars */
+       "Totoro",                               /* Tonari no Totoro */
+       "ohmu",                                 /* Nausicaa */
+       "youma",                                /* Sailor Moon */
+       "nyaasu",                               /* Pokemon (Meowth) */
+       "Godzilla", "King Kong",                /* monster movies */
+       "earthquake beast",                     /* old L of SH */
+       "Invid",                                /* Robotech */
+       "Terminator",                           /* The Terminator */
+       "boomer",                               /* Bubblegum Crisis */
+       "Dalek",                                /* Dr. Who ("Exterminate!") */
+       "microscopic space fleet", "Ravenous Bugblatter Beast of Traal",
+                                               /* HGttG */
+       "teenage mutant ninja turtle",          /* TMNT */
+       "samurai rabbit",                       /* Usagi Yojimbo */
+       "aardvark",                             /* Cerebus */
+       "Audrey II",                            /* Little Shop of Horrors */
+       "witch doctor", "one-eyed one-horned flying purple people eater",
+                                               /* 50's rock 'n' roll */
+       "Barney the dinosaur",                  /* saccharine kiddy TV */
+       "Morgoth",                              /* Angband */
+       "Vorlon",                               /* Babylon 5 */
+       "questing beast",               /* King Arthur */
+       "Predator",                             /* Movie */
+       "mother-in-law"                         /* common pest */
+};
+
+
+/* Return a random monster name, for hallucination.
+ * KNOWN BUG: May be a proper name (Godzilla, Barney), may not
+ * (the Terminator, a Dalek).  There's no elegant way to deal
+ * with this without radically modifying the calling functions.
+ */
+const char *
+rndmonnam()
+{
+       int name;
+
+       do {
+           name = rn1(SPECIAL_PM + SIZE(bogusmons) - LOW_PM, LOW_PM);
+       } while (name < SPECIAL_PM &&
+           (type_is_pname(&mons[name]) || (mons[name].geno & G_NOGEN)));
+
+       if (name >= SPECIAL_PM) return bogusmons[name - SPECIAL_PM];
+       return mons[name].mname;
+}
+
+#ifdef REINCARNATION
+const char *
+roguename() /* Name of a Rogue player */
+{
+       char *i, *opts;
+
+       if ((opts = nh_getenv("ROGUEOPTS")) != 0) {
+               for (i = opts; *i; i++)
+                       if (!strncmp("name=",i,5)) {
+                               char *j;
+                               if ((j = index(i+5,',')) != 0)
+                                       *j = (char)0;
+                               return i+5;
+                       }
+       }
+       return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
+               : "Glenn Wichman";
+}
+#endif /* REINCARNATION */
+#endif /* OVLB */
+
+#ifdef OVL2
+
+static NEARDATA const char * const hcolors[] = {
+       "ultraviolet", "infrared", "bluish-orange",
+       "reddish-green", "dark white", "light black", "sky blue-pink",
+       "salty", "sweet", "sour", "bitter",
+       "striped", "spiral", "swirly", "plaid", "checkered", "argyle",
+       "paisley", "blotchy", "guernsey-spotted", "polka-dotted",
+       "square", "round", "triangular",
+       "cabernet", "sangria", "fuchsia", "wisteria",
+       "lemon-lime", "strawberry-banana", "peppermint",
+       "romantic", "incandescent"
+};
+
+const char *
+hcolor(colorpref)
+const char *colorpref;
+{
+       return (Hallucination || !colorpref) ?
+               hcolors[rn2(SIZE(hcolors))] : colorpref;
+}
+
+/* return a random real color unless hallucinating */
+const char *
+rndcolor()
+{
+       int k = rn2(CLR_MAX);
+       return Hallucination ? hcolor((char *)0) : (k == NO_COLOR) ?
+               "colorless" : c_obj_colors[k];
+}
+
+/* Aliases for road-runner nemesis
+ */
+static const char * const coynames[] = {
+       "Carnivorous Vulgaris","Road-Runnerus Digestus",
+       "Eatibus Anythingus"  ,"Famishus-Famishus",
+       "Eatibus Almost Anythingus","Eatius Birdius",
+       "Famishius Fantasticus","Eternalii Famishiis",
+       "Famishus Vulgarus","Famishius Vulgaris Ingeniusi",
+       "Eatius-Slobbius","Hardheadipus Oedipus",
+       "Carnivorous Slobbius","Hard-Headipus Ravenus",
+       "Evereadii Eatibus","Apetitius Giganticus",
+       "Hungrii Flea-Bagius","Overconfidentii Vulgaris",
+       "Caninus Nervous Rex","Grotesques Appetitus",
+       "Nemesis Riduclii","Canis latrans"
+};
+       
+char *
+coyotename(mtmp, buf)
+struct monst *mtmp;
+char *buf;
+{
+    if (mtmp && buf) {
+       Sprintf(buf, "%s - %s",
+           x_monnam(mtmp, ARTICLE_NONE, (char *)0, 0, TRUE),
+           mtmp->mcan ? coynames[SIZE(coynames)-1] : coynames[rn2(SIZE(coynames)-1)]);
+    }
+    return buf;
+}
+#endif /* OVL2 */
+
+/*do_name.c*/
diff --git a/src/do_wear.c b/src/do_wear.c
new file mode 100644 (file)
index 0000000..c197c1b
--- /dev/null
@@ -0,0 +1,2185 @@
+/*     SCCS Id: @(#)do_wear.c  3.4     2003/11/14      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+#ifndef OVLB
+
+STATIC_DCL long takeoff_mask, taking_off;
+
+#else /* OVLB */
+
+STATIC_OVL NEARDATA long takeoff_mask = 0L;
+static NEARDATA long taking_off = 0L;
+
+static NEARDATA int todelay;
+static boolean cancelled_don = FALSE;
+
+static NEARDATA const char see_yourself[] = "see yourself";
+static NEARDATA const char unknown_type[] = "Unknown type of %s (%d)";
+static NEARDATA const char c_armor[]  = "armor",
+                          c_suit[]   = "suit",
+#ifdef TOURIST
+                          c_shirt[]  = "shirt",
+#endif
+                          c_cloak[]  = "cloak",
+                          c_gloves[] = "gloves",
+                          c_boots[]  = "boots",
+                          c_helmet[] = "helmet",
+                          c_shield[] = "shield",
+                          c_weapon[] = "weapon",
+                          c_sword[]  = "sword",
+                          c_axe[]    = "axe",
+                          c_that_[]  = "that";
+
+static NEARDATA const long takeoff_order[] = { WORN_BLINDF, W_WEP,
+       WORN_SHIELD, WORN_GLOVES, LEFT_RING, RIGHT_RING, WORN_CLOAK,
+       WORN_HELMET, WORN_AMUL, WORN_ARMOR,
+#ifdef TOURIST
+       WORN_SHIRT,
+#endif
+       WORN_BOOTS, W_SWAPWEP, W_QUIVER, 0L };
+
+STATIC_DCL void FDECL(on_msg, (struct obj *));
+STATIC_PTR int NDECL(Armor_on);
+STATIC_PTR int NDECL(Boots_on);
+STATIC_DCL int NDECL(Cloak_on);
+STATIC_PTR int NDECL(Helmet_on);
+STATIC_PTR int NDECL(Gloves_on);
+STATIC_PTR int NDECL(Shield_on);
+#ifdef TOURIST
+STATIC_PTR int NDECL(Shirt_on);
+#endif
+STATIC_DCL void NDECL(Amulet_on);
+STATIC_DCL void FDECL(Ring_off_or_gone, (struct obj *, BOOLEAN_P));
+STATIC_PTR int FDECL(select_off, (struct obj *));
+STATIC_DCL struct obj *NDECL(do_takeoff);
+STATIC_PTR int NDECL(take_off);
+STATIC_DCL int FDECL(menu_remarm, (int));
+STATIC_DCL void FDECL(already_wearing, (const char*));
+STATIC_DCL void FDECL(already_wearing2, (const char*, const char*));
+
+void
+off_msg(otmp)
+register struct obj *otmp;
+{
+       if(flags.verbose)
+           You("were wearing %s.", doname(otmp));
+}
+
+/* for items that involve no delay */
+STATIC_OVL void
+on_msg(otmp)
+register struct obj *otmp;
+{
+       if (flags.verbose) {
+           char how[BUFSZ];
+
+           how[0] = '\0';
+           if (otmp->otyp == TOWEL)
+               Sprintf(how, " around your %s", body_part(HEAD));
+           You("are now wearing %s%s.",
+               obj_is_pname(otmp) ? the(xname(otmp)) : an(xname(otmp)),
+               how);
+       }
+}
+
+/*
+ * The Type_on() functions should be called *after* setworn().
+ * The Type_off() functions call setworn() themselves.
+ */
+
+STATIC_PTR
+int
+Boots_on()
+{
+    long oldprop =
+       u.uprops[objects[uarmf->otyp].oc_oprop].extrinsic & ~WORN_BOOTS;
+
+    switch(uarmf->otyp) {
+       case LOW_BOOTS:
+       case IRON_SHOES:
+       case HIGH_BOOTS:
+       case JUMPING_BOOTS:
+       case KICKING_BOOTS:
+               break;
+       case WATER_WALKING_BOOTS:
+               if (u.uinwater) spoteffects(TRUE);
+               break;
+       case SPEED_BOOTS:
+               /* Speed boots are still better than intrinsic speed, */
+               /* though not better than potion speed */
+               if (!oldprop && !(HFast & TIMEOUT)) {
+                       makeknown(uarmf->otyp);
+                       You_feel("yourself speed up%s.",
+                               (oldprop || HFast) ? " a bit more" : "");
+               }
+               break;
+       case ELVEN_BOOTS:
+               if (!oldprop && !HStealth && !BStealth) {
+                       makeknown(uarmf->otyp);
+                       You("walk very quietly.");
+               }
+               break;
+       case FUMBLE_BOOTS:
+               if (!oldprop && !(HFumbling & ~TIMEOUT))
+                       incr_itimeout(&HFumbling, rnd(20));
+               break;
+       case LEVITATION_BOOTS:
+               if (!oldprop && !HLevitation) {
+                       makeknown(uarmf->otyp);
+                       float_up();
+                       spoteffects(FALSE);
+               }
+               break;
+       default: impossible(unknown_type, c_boots, uarmf->otyp);
+    }
+    return 0;
+}
+
+int
+Boots_off()
+{
+    int otyp = uarmf->otyp;
+    long oldprop = u.uprops[objects[otyp].oc_oprop].extrinsic & ~WORN_BOOTS;
+
+    takeoff_mask &= ~W_ARMF;
+       /* For levitation, float_down() returns if Levitation, so we
+        * must do a setworn() _before_ the levitation case.
+        */
+    setworn((struct obj *)0, W_ARMF);
+    switch (otyp) {
+       case SPEED_BOOTS:
+               if (!Very_fast && !cancelled_don) {
+                       makeknown(otyp);
+                       You_feel("yourself slow down%s.",
+                               Fast ? " a bit" : "");
+               }
+               break;
+       case WATER_WALKING_BOOTS:
+               if (is_pool(u.ux,u.uy) && !Levitation && !Flying &&
+                   !is_clinger(youmonst.data) && !cancelled_don) {
+                       makeknown(otyp);
+                       /* make boots known in case you survive the drowning */
+                       spoteffects(TRUE);
+               }
+               break;
+       case ELVEN_BOOTS:
+               if (!oldprop && !HStealth && !BStealth && !cancelled_don) {
+                       makeknown(otyp);
+                       You("sure are noisy.");
+               }
+               break;
+       case FUMBLE_BOOTS:
+               if (!oldprop && !(HFumbling & ~TIMEOUT))
+                       HFumbling = EFumbling = 0;
+               break;
+       case LEVITATION_BOOTS:
+               if (!oldprop && !HLevitation && !cancelled_don) {
+                       (void) float_down(0L, 0L);
+                       makeknown(otyp);
+               }
+               break;
+       case LOW_BOOTS:
+       case IRON_SHOES:
+       case HIGH_BOOTS:
+       case JUMPING_BOOTS:
+       case KICKING_BOOTS:
+               break;
+       default: impossible(unknown_type, c_boots, otyp);
+    }
+    cancelled_don = FALSE;
+    return 0;
+}
+
+STATIC_OVL int
+Cloak_on()
+{
+    long oldprop =
+       u.uprops[objects[uarmc->otyp].oc_oprop].extrinsic & ~WORN_CLOAK;
+
+    switch(uarmc->otyp) {
+       case ELVEN_CLOAK:
+       case CLOAK_OF_PROTECTION:
+       case CLOAK_OF_DISPLACEMENT:
+               makeknown(uarmc->otyp);
+               break;
+       case ORCISH_CLOAK:
+       case DWARVISH_CLOAK:
+       case CLOAK_OF_MAGIC_RESISTANCE:
+       case ROBE:
+       case LEATHER_CLOAK:
+               break;
+       case MUMMY_WRAPPING:
+               /* Note: it's already being worn, so we have to cheat here. */
+               if ((HInvis || EInvis || pm_invisible(youmonst.data)) && !Blind) {
+                   newsym(u.ux,u.uy);
+                   You("can %s!",
+                       See_invisible ? "no longer see through yourself"
+                       : see_yourself);
+               }
+               break;
+       case CLOAK_OF_INVISIBILITY:
+               /* since cloak of invisibility was worn, we know mummy wrapping
+                  wasn't, so no need to check `oldprop' against blocked */
+               if (!oldprop && !HInvis && !Blind) {
+                   makeknown(uarmc->otyp);
+                   newsym(u.ux,u.uy);
+                   pline("Suddenly you can%s yourself.",
+                       See_invisible ? " see through" : "not see");
+               }
+               break;
+       case OILSKIN_CLOAK:
+               pline("%s very tightly.", Tobjnam(uarmc, "fit"));
+               break;
+       /* Alchemy smock gives poison _and_ acid resistance */
+       case ALCHEMY_SMOCK:
+               EAcid_resistance |= WORN_CLOAK;
+               break;
+       default: impossible(unknown_type, c_cloak, uarmc->otyp);
+    }
+    return 0;
+}
+
+int
+Cloak_off()
+{
+    int otyp = uarmc->otyp;
+    long oldprop = u.uprops[objects[otyp].oc_oprop].extrinsic & ~WORN_CLOAK;
+
+    takeoff_mask &= ~W_ARMC;
+       /* For mummy wrapping, taking it off first resets `Invisible'. */
+    setworn((struct obj *)0, W_ARMC);
+    switch (otyp) {
+       case ELVEN_CLOAK:
+       case ORCISH_CLOAK:
+       case DWARVISH_CLOAK:
+       case CLOAK_OF_PROTECTION:
+       case CLOAK_OF_MAGIC_RESISTANCE:
+       case CLOAK_OF_DISPLACEMENT:
+       case OILSKIN_CLOAK:
+       case ROBE:
+       case LEATHER_CLOAK:
+               break;
+       case MUMMY_WRAPPING:
+               if (Invis && !Blind) {
+                   newsym(u.ux,u.uy);
+                   You("can %s.",
+                       See_invisible ? "see through yourself"
+                       : "no longer see yourself");
+               }
+               break;
+       case CLOAK_OF_INVISIBILITY:
+               if (!oldprop && !HInvis && !Blind) {
+                   makeknown(CLOAK_OF_INVISIBILITY);
+                   newsym(u.ux,u.uy);
+                   pline("Suddenly you can %s.",
+                       See_invisible ? "no longer see through yourself"
+                       : see_yourself);
+               }
+               break;
+       /* Alchemy smock gives poison _and_ acid resistance */
+       case ALCHEMY_SMOCK:
+               EAcid_resistance &= ~WORN_CLOAK;
+               break;
+       default: impossible(unknown_type, c_cloak, otyp);
+    }
+    return 0;
+}
+
+STATIC_PTR
+int
+Helmet_on()
+{
+    switch(uarmh->otyp) {
+       case FEDORA:
+       case HELMET:
+       case DENTED_POT:
+       case ELVEN_LEATHER_HELM:
+       case DWARVISH_IRON_HELM:
+       case ORCISH_HELM:
+       case HELM_OF_TELEPATHY:
+               break;
+       case HELM_OF_BRILLIANCE:
+               adj_abon(uarmh, uarmh->spe);
+               break;
+       case CORNUTHAUM:
+               /* people think marked wizards know what they're talking
+                * about, but it takes trained arrogance to pull it off,
+                * and the actual enchantment of the hat is irrelevant.
+                */
+               ABON(A_CHA) += (Role_if(PM_WIZARD) ? 1 : -1);
+               flags.botl = 1;
+               makeknown(uarmh->otyp);
+               break;
+       case HELM_OF_OPPOSITE_ALIGNMENT:
+               if (u.ualign.type == A_NEUTRAL)
+                   u.ualign.type = rn2(2) ? A_CHAOTIC : A_LAWFUL;
+               else u.ualign.type = -(u.ualign.type);
+               u.ublessed = 0; /* lose your god's protection */
+            /* makeknown(uarmh->otyp);   -- moved below, after xname() */
+               /*FALLTHRU*/
+       case DUNCE_CAP:
+               if (!uarmh->cursed) {
+                   if (Blind)
+                       pline("%s for a moment.", Tobjnam(uarmh, "vibrate"));
+                   else
+                       pline("%s %s for a moment.",
+                             Tobjnam(uarmh, "glow"), hcolor(NH_BLACK));
+                   curse(uarmh);
+               }
+               flags.botl = 1;         /* reveal new alignment or INT & WIS */
+               if (Hallucination) {
+                   pline("My brain hurts!"); /* Monty Python's Flying Circus */
+               } else if (uarmh->otyp == DUNCE_CAP) {
+                   You_feel("%s.",     /* track INT change; ignore WIS */
+                 ACURR(A_INT) <= (ABASE(A_INT) + ABON(A_INT) + ATEMP(A_INT)) ?
+                            "like sitting in a corner" : "giddy");
+               } else {
+                   Your("mind oscillates briefly.");
+                   makeknown(HELM_OF_OPPOSITE_ALIGNMENT);
+               }
+               break;
+       default: impossible(unknown_type, c_helmet, uarmh->otyp);
+    }
+    return 0;
+}
+
+int
+Helmet_off()
+{
+    takeoff_mask &= ~W_ARMH;
+
+    switch(uarmh->otyp) {
+       case FEDORA:
+       case HELMET:
+       case DENTED_POT:
+       case ELVEN_LEATHER_HELM:
+       case DWARVISH_IRON_HELM:
+       case ORCISH_HELM:
+           break;
+       case DUNCE_CAP:
+           flags.botl = 1;
+           break;
+       case CORNUTHAUM:
+           if (!cancelled_don) {
+               ABON(A_CHA) += (Role_if(PM_WIZARD) ? -1 : 1);
+               flags.botl = 1;
+           }
+           break;
+       case HELM_OF_TELEPATHY:
+           /* need to update ability before calling see_monsters() */
+           setworn((struct obj *)0, W_ARMH);
+           see_monsters();
+           return 0;
+       case HELM_OF_BRILLIANCE:
+           if (!cancelled_don) adj_abon(uarmh, -uarmh->spe);
+           break;
+       case HELM_OF_OPPOSITE_ALIGNMENT:
+           u.ualign.type = u.ualignbase[A_CURRENT];
+           u.ublessed = 0; /* lose the other god's protection */
+           flags.botl = 1;
+           break;
+       default: impossible(unknown_type, c_helmet, uarmh->otyp);
+    }
+    setworn((struct obj *)0, W_ARMH);
+    cancelled_don = FALSE;
+    return 0;
+}
+
+STATIC_PTR
+int
+Gloves_on()
+{
+    long oldprop =
+       u.uprops[objects[uarmg->otyp].oc_oprop].extrinsic & ~WORN_GLOVES;
+
+    switch(uarmg->otyp) {
+       case LEATHER_GLOVES:
+               break;
+       case GAUNTLETS_OF_FUMBLING:
+               if (!oldprop && !(HFumbling & ~TIMEOUT))
+                       incr_itimeout(&HFumbling, rnd(20));
+               break;
+       case GAUNTLETS_OF_POWER:
+               makeknown(uarmg->otyp);
+               flags.botl = 1; /* taken care of in attrib.c */
+               break;
+       case GAUNTLETS_OF_DEXTERITY:
+               adj_abon(uarmg, uarmg->spe);
+               break;
+       default: impossible(unknown_type, c_gloves, uarmg->otyp);
+    }
+    return 0;
+}
+
+int
+Gloves_off()
+{
+    long oldprop =
+       u.uprops[objects[uarmg->otyp].oc_oprop].extrinsic & ~WORN_GLOVES;
+
+    takeoff_mask &= ~W_ARMG;
+
+    switch(uarmg->otyp) {
+       case LEATHER_GLOVES:
+           break;
+       case GAUNTLETS_OF_FUMBLING:
+           if (!oldprop && !(HFumbling & ~TIMEOUT))
+               HFumbling = EFumbling = 0;
+           break;
+       case GAUNTLETS_OF_POWER:
+           makeknown(uarmg->otyp);
+           flags.botl = 1; /* taken care of in attrib.c */
+           break;
+       case GAUNTLETS_OF_DEXTERITY:
+           if (!cancelled_don) adj_abon(uarmg, -uarmg->spe);
+           break;
+       default: impossible(unknown_type, c_gloves, uarmg->otyp);
+    }
+    setworn((struct obj *)0, W_ARMG);
+    cancelled_don = FALSE;
+    (void) encumber_msg();             /* immediate feedback for GoP */
+
+    /* Prevent wielding cockatrice when not wearing gloves */
+    if (uwep && uwep->otyp == CORPSE &&
+               touch_petrifies(&mons[uwep->corpsenm])) {
+       char kbuf[BUFSZ];
+
+       You("wield the %s in your bare %s.",
+           corpse_xname(uwep, TRUE), makeplural(body_part(HAND)));
+       Strcpy(kbuf, an(corpse_xname(uwep, TRUE)));
+       instapetrify(kbuf);
+       uwepgone();  /* life-saved still doesn't allow touching cockatrice */
+    }
+
+    /* KMH -- ...or your secondary weapon when you're wielding it */
+    if (u.twoweap && uswapwep && uswapwep->otyp == CORPSE &&
+       touch_petrifies(&mons[uswapwep->corpsenm])) {
+       char kbuf[BUFSZ];
+
+       You("wield the %s in your bare %s.",
+           corpse_xname(uswapwep, TRUE), body_part(HAND));
+
+       Strcpy(kbuf, an(corpse_xname(uswapwep, TRUE)));
+       instapetrify(kbuf);
+       uswapwepgone(); /* lifesaved still doesn't allow touching cockatrice */
+    }
+
+    return 0;
+}
+
+STATIC_OVL int
+Shield_on()
+{
+/*
+    switch (uarms->otyp) {
+       case SMALL_SHIELD:
+       case ELVEN_SHIELD:
+       case URUK_HAI_SHIELD:
+       case ORCISH_SHIELD:
+       case DWARVISH_ROUNDSHIELD:
+       case LARGE_SHIELD:
+       case SHIELD_OF_REFLECTION:
+               break;
+       default: impossible(unknown_type, c_shield, uarms->otyp);
+    }
+*/
+    return 0;
+}
+
+int
+Shield_off()
+{
+    takeoff_mask &= ~W_ARMS;
+/*
+    switch (uarms->otyp) {
+       case SMALL_SHIELD:
+       case ELVEN_SHIELD:
+       case URUK_HAI_SHIELD:
+       case ORCISH_SHIELD:
+       case DWARVISH_ROUNDSHIELD:
+       case LARGE_SHIELD:
+       case SHIELD_OF_REFLECTION:
+               break;
+       default: impossible(unknown_type, c_shield, uarms->otyp);
+    }
+*/
+    setworn((struct obj *)0, W_ARMS);
+    return 0;
+}
+
+#ifdef TOURIST
+STATIC_OVL int
+Shirt_on()
+{
+/*
+    switch (uarmu->otyp) {
+       case HAWAIIAN_SHIRT:
+       case T_SHIRT:
+               break;
+       default: impossible(unknown_type, c_shirt, uarmu->otyp);
+    }
+*/
+    return 0;
+}
+
+int
+Shirt_off()
+{
+    takeoff_mask &= ~W_ARMU;
+/*
+    switch (uarmu->otyp) {
+       case HAWAIIAN_SHIRT:
+       case T_SHIRT:
+               break;
+       default: impossible(unknown_type, c_shirt, uarmu->otyp);
+    }
+*/
+    setworn((struct obj *)0, W_ARMU);
+    return 0;
+}
+#endif /*TOURIST*/
+
+/* This must be done in worn.c, because one of the possible intrinsics conferred
+ * is fire resistance, and we have to immediately set HFire_resistance in worn.c
+ * since worn.c will check it before returning.
+ */
+STATIC_PTR
+int
+Armor_on()
+{
+    return 0;
+}
+
+int
+Armor_off()
+{
+    takeoff_mask &= ~W_ARM;
+    setworn((struct obj *)0, W_ARM);
+    cancelled_don = FALSE;
+    return 0;
+}
+
+/* The gone functions differ from the off functions in that if you die from
+ * taking it off and have life saving, you still die.
+ */
+int
+Armor_gone()
+{
+    takeoff_mask &= ~W_ARM;
+    setnotworn(uarm);
+    cancelled_don = FALSE;
+    return 0;
+}
+
+STATIC_OVL void
+Amulet_on()
+{
+    switch(uamul->otyp) {
+       case AMULET_OF_ESP:
+       case AMULET_OF_LIFE_SAVING:
+       case AMULET_VERSUS_POISON:
+       case AMULET_OF_REFLECTION:
+       case AMULET_OF_MAGICAL_BREATHING:
+       case FAKE_AMULET_OF_YENDOR:
+               break;
+       case AMULET_OF_UNCHANGING:
+               if (Slimed) {
+                   Slimed = 0;
+                   flags.botl = 1;
+               }
+               break;
+       case AMULET_OF_CHANGE:
+           {
+               int orig_sex = poly_gender();
+
+               if (Unchanging) break;
+               change_sex();
+               /* Don't use same message as polymorph */
+               if (orig_sex != poly_gender()) {
+                   makeknown(AMULET_OF_CHANGE);
+                   You("are suddenly very %s!", flags.female ? "feminine"
+                       : "masculine");
+                   flags.botl = 1;
+               } else
+                   /* already polymorphed into single-gender monster; only
+                      changed the character's base sex */
+                   You("don't feel like yourself.");
+               pline_The("amulet disintegrates!");
+               if (orig_sex == poly_gender() && uamul->dknown &&
+                       !objects[AMULET_OF_CHANGE].oc_name_known &&
+                       !objects[AMULET_OF_CHANGE].oc_uname)
+                   docall(uamul);
+               useup(uamul);
+               break;
+           }
+       case AMULET_OF_STRANGULATION:
+               makeknown(AMULET_OF_STRANGULATION);
+               pline("It constricts your throat!");
+               Strangled = 6;
+               break;
+       case AMULET_OF_RESTFUL_SLEEP:
+               HSleeping = rnd(100);
+               break;
+       case AMULET_OF_YENDOR:
+               break;
+    }
+}
+
+void
+Amulet_off()
+{
+    takeoff_mask &= ~W_AMUL;
+
+    switch(uamul->otyp) {
+       case AMULET_OF_ESP:
+               /* need to update ability before calling see_monsters() */
+               setworn((struct obj *)0, W_AMUL);
+               see_monsters();
+               return;
+       case AMULET_OF_LIFE_SAVING:
+       case AMULET_VERSUS_POISON:
+       case AMULET_OF_REFLECTION:
+       case AMULET_OF_CHANGE:
+       case AMULET_OF_UNCHANGING:
+       case FAKE_AMULET_OF_YENDOR:
+               break;
+       case AMULET_OF_MAGICAL_BREATHING:
+               if (Underwater) {
+                   /* HMagical_breathing must be set off
+                       before calling drown() */
+                   setworn((struct obj *)0, W_AMUL);
+                   if (!breathless(youmonst.data) && !amphibious(youmonst.data)
+                                               && !Swimming) {
+                       You("suddenly inhale an unhealthy amount of water!");
+                       (void) drown();
+                   }
+                   return;
+               }
+               break;
+       case AMULET_OF_STRANGULATION:
+               if (Strangled) {
+                       You("can breathe more easily!");
+                       Strangled = 0;
+               }
+               break;
+       case AMULET_OF_RESTFUL_SLEEP:
+               setworn((struct obj *)0, W_AMUL);
+               if (!ESleeping)
+                       HSleeping = 0;
+               return;
+       case AMULET_OF_YENDOR:
+               break;
+    }
+    setworn((struct obj *)0, W_AMUL);
+    return;
+}
+
+void
+Ring_on(obj)
+register struct obj *obj;
+{
+    long oldprop = u.uprops[objects[obj->otyp].oc_oprop].extrinsic;
+    int old_attrib, which;
+
+    if (obj == uwep) setuwep((struct obj *) 0);
+    if (obj == uswapwep) setuswapwep((struct obj *) 0);
+    if (obj == uquiver) setuqwep((struct obj *) 0);
+
+    /* only mask out W_RING when we don't have both
+       left and right rings of the same type */
+    if ((oldprop & W_RING) != W_RING) oldprop &= ~W_RING;
+
+    switch(obj->otyp){
+       case RIN_TELEPORTATION:
+       case RIN_REGENERATION:
+       case RIN_SEARCHING:
+       case RIN_STEALTH:
+       case RIN_HUNGER:
+       case RIN_AGGRAVATE_MONSTER:
+       case RIN_POISON_RESISTANCE:
+       case RIN_FIRE_RESISTANCE:
+       case RIN_COLD_RESISTANCE:
+       case RIN_SHOCK_RESISTANCE:
+       case RIN_CONFLICT:
+       case RIN_TELEPORT_CONTROL:
+       case RIN_POLYMORPH:
+       case RIN_POLYMORPH_CONTROL:
+       case RIN_FREE_ACTION:                
+       case RIN_SLOW_DIGESTION:
+       case RIN_SUSTAIN_ABILITY:
+       case MEAT_RING:
+               break;
+       case RIN_WARNING:
+               see_monsters();
+               break;
+       case RIN_SEE_INVISIBLE:
+               /* can now see invisible monsters */
+               set_mimic_blocking(); /* do special mimic handling */
+               see_monsters();
+#ifdef INVISIBLE_OBJECTS
+               see_objects();
+#endif
+
+               if (Invis && !oldprop && !HSee_invisible &&
+                               !perceives(youmonst.data) && !Blind) {
+                   newsym(u.ux,u.uy);
+                   pline("Suddenly you are transparent, but there!");
+                   makeknown(RIN_SEE_INVISIBLE);
+               }
+               break;
+       case RIN_INVISIBILITY:
+               if (!oldprop && !HInvis && !BInvis && !Blind) {
+                   makeknown(RIN_INVISIBILITY);
+                   newsym(u.ux,u.uy);
+                   self_invis_message();
+               }
+               break;
+       case RIN_LEVITATION:
+               if (!oldprop && !HLevitation) {
+                   float_up();
+                   makeknown(RIN_LEVITATION);
+                   spoteffects(FALSE); /* for sinks */
+               }
+               break;
+       case RIN_GAIN_STRENGTH:
+               which = A_STR;
+               goto adjust_attrib;
+       case RIN_GAIN_CONSTITUTION:
+               which = A_CON;
+               goto adjust_attrib;
+       case RIN_ADORNMENT:
+               which = A_CHA;
+ adjust_attrib:
+               old_attrib = ACURR(which);
+               ABON(which) += obj->spe;
+               if (ACURR(which) != old_attrib ||
+                       (objects[obj->otyp].oc_name_known &&
+                           old_attrib != 25 && old_attrib != 3)) {
+                   flags.botl = 1;
+                   makeknown(obj->otyp);
+                   obj->known = 1;
+                   update_inventory();
+               }
+               break;
+       case RIN_INCREASE_ACCURACY:     /* KMH */
+               u.uhitinc += obj->spe;
+               break;
+       case RIN_INCREASE_DAMAGE:
+               u.udaminc += obj->spe;
+               break;
+       case RIN_PROTECTION_FROM_SHAPE_CHAN:
+               rescham();
+               break;
+       case RIN_PROTECTION:
+               if (obj->spe || objects[RIN_PROTECTION].oc_name_known) {
+                   flags.botl = 1;
+                   makeknown(RIN_PROTECTION);
+                   obj->known = 1;
+                   update_inventory();
+               }
+               break;
+    }
+}
+
+STATIC_OVL void
+Ring_off_or_gone(obj,gone)
+register struct obj *obj;
+boolean gone;
+{
+    long mask = (obj->owornmask & W_RING);
+    int old_attrib, which;
+
+    takeoff_mask &= ~mask;
+    if(!(u.uprops[objects[obj->otyp].oc_oprop].extrinsic & mask))
+       impossible("Strange... I didn't know you had that ring.");
+    if(gone) setnotworn(obj);
+    else setworn((struct obj *)0, obj->owornmask);
+
+    switch(obj->otyp) {
+       case RIN_TELEPORTATION:
+       case RIN_REGENERATION:
+       case RIN_SEARCHING:
+       case RIN_STEALTH:
+       case RIN_HUNGER:
+       case RIN_AGGRAVATE_MONSTER:
+       case RIN_POISON_RESISTANCE:
+       case RIN_FIRE_RESISTANCE:
+       case RIN_COLD_RESISTANCE:
+       case RIN_SHOCK_RESISTANCE:
+       case RIN_CONFLICT:
+       case RIN_TELEPORT_CONTROL:
+       case RIN_POLYMORPH:
+       case RIN_POLYMORPH_CONTROL:
+       case RIN_FREE_ACTION:                
+       case RIN_SLOW_DIGESTION:
+       case RIN_SUSTAIN_ABILITY:
+       case MEAT_RING:
+               break;
+       case RIN_WARNING:
+               see_monsters();
+               break;
+       case RIN_SEE_INVISIBLE:
+               /* Make invisible monsters go away */
+               if (!See_invisible) {
+                   set_mimic_blocking(); /* do special mimic handling */
+                   see_monsters();
+#ifdef INVISIBLE_OBJECTS                
+                   see_objects();
+#endif
+               }
+
+               if (Invisible && !Blind) {
+                   newsym(u.ux,u.uy);
+                   pline("Suddenly you cannot see yourself.");
+                   makeknown(RIN_SEE_INVISIBLE);
+               }
+               break;
+       case RIN_INVISIBILITY:
+               if (!Invis && !BInvis && !Blind) {
+                   newsym(u.ux,u.uy);
+                   Your("body seems to unfade%s.",
+                        See_invisible ? " completely" : "..");
+                   makeknown(RIN_INVISIBILITY);
+               }
+               break;
+       case RIN_LEVITATION:
+               (void) float_down(0L, 0L);
+               if (!Levitation) makeknown(RIN_LEVITATION);
+               break;
+       case RIN_GAIN_STRENGTH:
+               which = A_STR;
+               goto adjust_attrib;
+       case RIN_GAIN_CONSTITUTION:
+               which = A_CON;
+               goto adjust_attrib;
+       case RIN_ADORNMENT:
+               which = A_CHA;
+ adjust_attrib:
+               old_attrib = ACURR(which);
+               ABON(which) -= obj->spe;
+               if (ACURR(which) != old_attrib) {
+                   flags.botl = 1;
+                   makeknown(obj->otyp);
+                   obj->known = 1;
+                   update_inventory();
+               }
+               break;
+       case RIN_INCREASE_ACCURACY:     /* KMH */
+               u.uhitinc -= obj->spe;
+               break;
+       case RIN_INCREASE_DAMAGE:
+               u.udaminc -= obj->spe;
+               break;
+       case RIN_PROTECTION:
+               /* might have forgotten it due to amnesia */
+               if (obj->spe) {
+                   flags.botl = 1;
+                   makeknown(RIN_PROTECTION);
+                   obj->known = 1;
+                   update_inventory();
+               }
+       case RIN_PROTECTION_FROM_SHAPE_CHAN:
+               /* If you're no longer protected, let the chameleons
+                * change shape again -dgk
+                */
+               restartcham();
+               break;
+    }
+}
+
+void
+Ring_off(obj)
+struct obj *obj;
+{
+       Ring_off_or_gone(obj,FALSE);
+}
+
+void
+Ring_gone(obj)
+struct obj *obj;
+{
+       Ring_off_or_gone(obj,TRUE);
+}
+
+void
+Blindf_on(otmp)
+register struct obj *otmp;
+{
+       boolean already_blind = Blind, changed = FALSE;
+
+       if (otmp == uwep)
+           setuwep((struct obj *) 0);
+       if (otmp == uswapwep)
+           setuswapwep((struct obj *) 0);
+       if (otmp == uquiver)
+           setuqwep((struct obj *) 0);
+       setworn(otmp, W_TOOL);
+       on_msg(otmp);
+
+       if (Blind && !already_blind) {
+           changed = TRUE;
+           if (flags.verbose) You_cant("see any more.");
+           /* set ball&chain variables before the hero goes blind */
+           if (Punished) set_bc(0);
+       } else if (already_blind && !Blind) {
+           changed = TRUE;
+           /* "You are now wearing the Eyes of the Overworld." */
+           You("can see!");
+       }
+       if (changed) {
+           /* blindness has just been toggled */
+           if (Blind_telepat || Infravision) see_monsters();
+           vision_full_recalc = 1;     /* recalc vision limits */
+           flags.botl = 1;
+       }
+}
+
+void
+Blindf_off(otmp)
+register struct obj *otmp;
+{
+       boolean was_blind = Blind, changed = FALSE;
+
+       takeoff_mask &= ~W_TOOL;
+       setworn((struct obj *)0, otmp->owornmask);
+       off_msg(otmp);
+
+       if (Blind) {
+           if (was_blind) {
+               /* "still cannot see" makes no sense when removing lenses
+                  since they can't have been the cause of your blindness */
+               if (otmp->otyp != LENSES)
+                   You("still cannot see.");
+           } else {
+               changed = TRUE; /* !was_blind */
+               /* "You were wearing the Eyes of the Overworld." */
+               You_cant("see anything now!");
+               /* set ball&chain variables before the hero goes blind */
+               if (Punished) set_bc(0);
+           }
+       } else if (was_blind) {
+           changed = TRUE;     /* !Blind */
+           You("can see again.");
+       }
+       if (changed) {
+           /* blindness has just been toggled */
+           if (Blind_telepat || Infravision) see_monsters();
+           vision_full_recalc = 1;     /* recalc vision limits */
+           flags.botl = 1;
+       }
+}
+
+/* called in main to set intrinsics of worn start-up items */
+void
+set_wear()
+{
+#ifdef TOURIST
+       if (uarmu) (void) Shirt_on();
+#endif
+       if (uarm)  (void) Armor_on();
+       if (uarmc) (void) Cloak_on();
+       if (uarmf) (void) Boots_on();
+       if (uarmg) (void) Gloves_on();
+       if (uarmh) (void) Helmet_on();
+       if (uarms) (void) Shield_on();
+}
+
+/* check whether the target object is currently being put on (or taken off) */
+boolean
+donning(otmp)          /* also checks for doffing */
+register struct obj *otmp;
+{
+ /* long what = (occupation == take_off) ? taking_off : 0L; */
+    long what = taking_off;    /* if nonzero, occupation is implied */
+    boolean result = FALSE;
+
+    if (otmp == uarm)
+       result = (afternmv == Armor_on || afternmv == Armor_off ||
+                 what == WORN_ARMOR);
+#ifdef TOURIST
+    else if (otmp == uarmu)
+       result = (afternmv == Shirt_on || afternmv == Shirt_off ||
+                 what == WORN_SHIRT);
+#endif
+    else if (otmp == uarmc)
+       result = (afternmv == Cloak_on || afternmv == Cloak_off ||
+                 what == WORN_CLOAK);
+    else if (otmp == uarmf)
+       result = (afternmv == Boots_on || afternmv == Boots_off ||
+                 what == WORN_BOOTS);
+    else if (otmp == uarmh)
+       result = (afternmv == Helmet_on || afternmv == Helmet_off ||
+                 what == WORN_HELMET);
+    else if (otmp == uarmg)
+       result = (afternmv == Gloves_on || afternmv == Gloves_off ||
+                 what == WORN_GLOVES);
+    else if (otmp == uarms)
+       result = (afternmv == Shield_on || afternmv == Shield_off ||
+                 what == WORN_SHIELD);
+
+    return result;
+}
+
+void
+cancel_don()
+{
+       /* the piece of armor we were donning/doffing has vanished, so stop
+        * wasting time on it (and don't dereference it when donning would
+        * otherwise finish)
+        */
+       cancelled_don = (afternmv == Boots_on || afternmv == Helmet_on ||
+                        afternmv == Gloves_on || afternmv == Armor_on);
+       afternmv = 0;
+       nomovemsg = (char *)0;
+       multi = 0;
+       todelay = 0;
+       taking_off = 0L;
+}
+
+static NEARDATA const char clothes[] = {ARMOR_CLASS, 0};
+static NEARDATA const char accessories[] = {RING_CLASS, AMULET_CLASS, TOOL_CLASS, FOOD_CLASS, 0};
+
+/* the 'T' command */
+int
+dotakeoff()
+{
+       register struct obj *otmp = (struct obj *)0;
+       int armorpieces = 0;
+
+#define MOREARM(x) if (x) { armorpieces++; otmp = x; }
+       MOREARM(uarmh);
+       MOREARM(uarms);
+       MOREARM(uarmg);
+       MOREARM(uarmf);
+       if (uarmc) {
+               armorpieces++;
+               otmp = uarmc;
+       } else if (uarm) {
+               armorpieces++;
+               otmp = uarm;
+#ifdef TOURIST
+       } else if (uarmu) {
+               armorpieces++;
+               otmp = uarmu;
+#endif
+       }
+       if (!armorpieces) {
+            /* assert( GRAY_DRAGON_SCALES > YELLOW_DRAGON_SCALE_MAIL ); */
+               if (uskin)
+                   pline_The("%s merged with your skin!",
+                             uskin->otyp >= GRAY_DRAGON_SCALES ?
+                               "dragon scales are" : "dragon scale mail is");
+               else
+                   pline("Not wearing any armor.%s", (iflags.cmdassist && 
+                               (uleft || uright || uamul || ublindf)) ?
+                         "  Use 'R' command to remove accessories." : "");
+               return 0;
+       }
+       if (armorpieces > 1)
+               otmp = getobj(clothes, "take off");
+       if (otmp == 0) return(0);
+       if (!(otmp->owornmask & W_ARMOR)) {
+               You("are not wearing that.");
+               return(0);
+       }
+       /* note: the `uskin' case shouldn't be able to happen here; dragons
+          can't wear any armor so will end up with `armorpieces == 0' above */
+       if (otmp == uskin || ((otmp == uarm) && uarmc)
+#ifdef TOURIST
+                         || ((otmp == uarmu) && (uarmc || uarm))
+#endif
+               ) {
+           You_cant("take that off.");
+           return 0;
+       }
+
+       reset_remarm();         /* clear takeoff_mask and taking_off */
+       (void) select_off(otmp);
+       if (!takeoff_mask) return 0;
+       reset_remarm();         /* armoroff() doesn't use takeoff_mask */
+
+       (void) armoroff(otmp);
+       return(1);
+}
+
+/* the 'R' command */
+int
+doremring()
+{
+       register struct obj *otmp = 0;
+       int Accessories = 0;
+
+#define MOREACC(x) if (x) { Accessories++; otmp = x; }
+       MOREACC(uleft);
+       MOREACC(uright);
+       MOREACC(uamul);
+       MOREACC(ublindf);
+
+       if(!Accessories) {
+               pline("Not wearing any accessories.%s", (iflags.cmdassist &&
+                           (uarm || uarmc ||
+#ifdef TOURIST
+                            uarmu ||
+#endif
+                            uarms || uarmh || uarmg || uarmf)) ?
+                     "  Use 'T' command to take off armor." : "");
+               return(0);
+       }
+       if (Accessories != 1) otmp = getobj(accessories, "remove");
+       if(!otmp) return(0);
+       if(!(otmp->owornmask & (W_RING | W_AMUL | W_TOOL))) {
+               You("are not wearing that.");
+               return(0);
+       }
+
+       reset_remarm();         /* clear takeoff_mask and taking_off */
+       (void) select_off(otmp);
+       if (!takeoff_mask) return 0;
+       reset_remarm();         /* not used by Ring_/Amulet_/Blindf_off() */
+
+       if (otmp == uright || otmp == uleft) {
+               /* Sometimes we want to give the off_msg before removing and
+                * sometimes after; for instance, "you were wearing a moonstone
+                * ring (on right hand)" is desired but "you were wearing a
+                * square amulet (being worn)" is not because of the redundant
+                * "being worn".
+                */
+               off_msg(otmp);
+               Ring_off(otmp);
+       } else if (otmp == uamul) {
+               Amulet_off();
+               off_msg(otmp);
+       } else if (otmp == ublindf) {
+               Blindf_off(otmp);       /* does its own off_msg */
+       } else {
+               impossible("removing strange accessory?");
+       }
+       return(1);
+}
+
+/* Check if something worn is cursed _and_ unremovable. */
+int
+cursed(otmp)
+register struct obj *otmp;
+{
+       /* Curses, like chickens, come home to roost. */
+       if((otmp == uwep) ? welded(otmp) : (int)otmp->cursed) {
+               You("can't.  %s cursed.",
+                       (is_boots(otmp) || is_gloves(otmp) || otmp->quan > 1L)
+                       ? "They are" : "It is");
+               otmp->bknown = TRUE;
+               return(1);
+       }
+       return(0);
+}
+
+int
+armoroff(otmp)
+register struct obj *otmp;
+{
+       register int delay = -objects[otmp->otyp].oc_delay;
+
+       if(cursed(otmp)) return(0);
+       if(delay) {
+               nomul(delay);
+               if (is_helmet(otmp)) {
+                       nomovemsg = "You finish taking off your helmet.";
+                       afternmv = Helmet_off;
+                    }
+               else if (is_gloves(otmp)) {
+                       nomovemsg = "You finish taking off your gloves.";
+                       afternmv = Gloves_off;
+                    }
+               else if (is_boots(otmp)) {
+                       nomovemsg = "You finish taking off your boots.";
+                       afternmv = Boots_off;
+                    }
+               else {
+                       nomovemsg = "You finish taking off your suit.";
+                       afternmv = Armor_off;
+               }
+       } else {
+               /* Be warned!  We want off_msg after removing the item to
+                * avoid "You were wearing ____ (being worn)."  However, an
+                * item which grants fire resistance might cause some trouble
+                * if removed in Hell and lifesaving puts it back on; in this
+                * case the message will be printed at the wrong time (after
+                * the messages saying you died and were lifesaved).  Luckily,
+                * no cloak, shield, or fast-removable armor grants fire
+                * resistance, so we can safely do the off_msg afterwards.
+                * Rings do grant fire resistance, but for rings we want the
+                * off_msg before removal anyway so there's no problem.  Take
+                * care in adding armors granting fire resistance; this code
+                * might need modification.
+                * 3.2 (actually 3.1 even): this comment is obsolete since
+                * fire resistance is not needed for Gehennom.
+                */
+               if(is_cloak(otmp))
+                       (void) Cloak_off();
+               else if(is_shield(otmp))
+                       (void) Shield_off();
+               else setworn((struct obj *)0, otmp->owornmask & W_ARMOR);
+               off_msg(otmp);
+       }
+       takeoff_mask = taking_off = 0L;
+       return(1);
+}
+
+STATIC_OVL void
+already_wearing(cc)
+const char *cc;
+{
+       You("are already wearing %s%c", cc, (cc == c_that_) ? '!' : '.');
+}
+
+STATIC_OVL void
+already_wearing2(cc1, cc2)
+const char *cc1, *cc2;
+{
+       You_cant("wear %s because you're wearing %s there already.", cc1, cc2);
+}
+
+/*
+ * canwearobj checks to see whether the player can wear a piece of armor
+ *
+ * inputs: otmp (the piece of armor)
+ *         noisy (if TRUE give error messages, otherwise be quiet about it)
+ * output: mask (otmp's armor type)
+ */
+int
+canwearobj(otmp,mask,noisy)
+struct obj *otmp;
+long *mask;
+boolean noisy;
+{
+    int err = 0;
+    const char *which;
+
+    which = is_cloak(otmp) ? c_cloak :
+#ifdef TOURIST
+           is_shirt(otmp) ? c_shirt :
+#endif
+           is_suit(otmp) ? c_suit : 0;
+    if (which && cantweararm(youmonst.data) &&
+           /* same exception for cloaks as used in m_dowear() */
+           (which != c_cloak || youmonst.data->msize != MZ_SMALL) &&
+           (racial_exception(&youmonst, otmp) < 1)) {
+       if (noisy) pline_The("%s will not fit on your body.", which);
+       return 0;
+    } else if (otmp->owornmask & W_ARMOR) {
+       if (noisy) already_wearing(c_that_);
+       return 0;
+    }
+
+    if (welded(uwep) && bimanual(uwep) &&
+           (is_suit(otmp)
+#ifdef TOURIST
+                       || is_shirt(otmp)
+#endif
+           )) {
+       if (noisy)
+           You("cannot do that while holding your %s.",
+               is_sword(uwep) ? c_sword : c_weapon);
+       return 0;
+    }
+
+    if (is_helmet(otmp)) {
+       if (uarmh) {
+           if (noisy) already_wearing(an(c_helmet));
+           err++;
+       } else if (Upolyd && has_horns(youmonst.data) && !is_flimsy(otmp)) {
+           /* (flimsy exception matches polyself handling) */
+           if (noisy)
+               pline_The("%s won't fit over your horn%s.",
+                         c_helmet, plur(num_horns(youmonst.data)));
+           err++;
+       } else
+           *mask = W_ARMH;
+    } else if (is_shield(otmp)) {
+       if (uarms) {
+           if (noisy) already_wearing(an(c_shield));
+           err++;
+       } else if (uwep && bimanual(uwep)) {
+           if (noisy) 
+               You("cannot wear a shield while wielding a two-handed %s.",
+                   is_sword(uwep) ? c_sword :
+                   (uwep->otyp == BATTLE_AXE) ? c_axe : c_weapon);
+           err++;
+       } else if (u.twoweap) {
+           if (noisy)
+               You("cannot wear a shield while wielding two weapons.");
+           err++;
+       } else
+           *mask = W_ARMS;
+    } else if (is_boots(otmp)) {
+       if (uarmf) {
+           if (noisy) already_wearing(c_boots);
+           err++;
+       } else if (Upolyd && slithy(youmonst.data)) {
+           if (noisy) You("have no feet...");  /* not body_part(FOOT) */
+           err++;
+       } else if (Upolyd && youmonst.data->mlet == S_CENTAUR) {
+           /* break_armor() pushes boots off for centaurs,
+              so don't let dowear() put them back on... */
+           if (noisy) pline("You have too many hooves to wear %s.",
+                            c_boots);  /* makeplural(body_part(FOOT)) yields
+                                          "rear hooves" which sounds odd */
+           err++;
+       } else if (u.utrap && (u.utraptype == TT_BEARTRAP ||
+                               u.utraptype == TT_INFLOOR)) {
+           if (u.utraptype == TT_BEARTRAP) {
+               if (noisy) Your("%s is trapped!", body_part(FOOT));
+           } else {
+               if (noisy) Your("%s are stuck in the %s!",
+                               makeplural(body_part(FOOT)),
+                               surface(u.ux, u.uy));
+           }
+           err++;
+       } else
+           *mask = W_ARMF;
+    } else if (is_gloves(otmp)) {
+       if (uarmg) {
+           if (noisy) already_wearing(c_gloves);
+           err++;
+       } else if (welded(uwep)) {
+           if (noisy) You("cannot wear gloves over your %s.",
+                          is_sword(uwep) ? c_sword : c_weapon);
+           err++;
+       } else
+           *mask = W_ARMG;
+#ifdef TOURIST
+    } else if (is_shirt(otmp)) {
+       if (uarm || uarmc || uarmu) {
+           if (uarmu) {
+               if (noisy) already_wearing(an(c_shirt));
+           } else {
+               if (noisy) You_cant("wear that over your %s.",
+                                  (uarm && !uarmc) ? c_armor : cloak_simple_name(uarmc));
+           }
+           err++;
+       } else
+           *mask = W_ARMU;
+#endif
+    } else if (is_cloak(otmp)) {
+       if (uarmc) {
+           if (noisy) already_wearing(an(cloak_simple_name(uarmc)));
+           err++;
+       } else
+           *mask = W_ARMC;
+    } else if (is_suit(otmp)) {
+       if (uarmc) {
+           if (noisy) You("cannot wear armor over a %s.", cloak_simple_name(uarmc));
+           err++;
+       } else if (uarm) {
+           if (noisy) already_wearing("some armor");
+           err++;
+       } else
+           *mask = W_ARM;
+    } else {
+       /* getobj can't do this after setting its allow_all flag; that
+          happens if you have armor for slots that are covered up or
+          extra armor for slots that are filled */
+       if (noisy) silly_thing("wear", otmp);
+       err++;
+    }
+/* Unnecessary since now only weapons and special items like pick-axes get
+ * welded to your hand, not armor
+    if (welded(otmp)) {
+       if (!err++) {
+           if (noisy) weldmsg(otmp);
+       }
+    }
+ */
+    return !err;
+}
+
+/* the 'W' command */
+int
+dowear()
+{
+       struct obj *otmp;
+       int delay;
+       long mask = 0;
+
+       /* cantweararm checks for suits of armor */
+       /* verysmall or nohands checks for shields, gloves, etc... */
+       if ((verysmall(youmonst.data) || nohands(youmonst.data))) {
+               pline("Don't even bother.");
+               return(0);
+       }
+
+       otmp = getobj(clothes, "wear");
+       if(!otmp) return(0);
+
+       if (!canwearobj(otmp,&mask,TRUE)) return(0);
+
+       if (otmp->oartifact && !touch_artifact(otmp, &youmonst))
+           return 1;   /* costs a turn even though it didn't get worn */
+
+       if (otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT &&
+                       qstart_level.dnum == u.uz.dnum) {       /* in quest */
+               if (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL])
+                       You("narrowly avoid losing all chance at your goal.");
+               else    /* converted */
+                       You("are suddenly overcome with shame and change your mind.");
+               u.ublessed = 0; /* lose your god's protection */
+               makeknown(otmp->otyp);
+               flags.botl = 1;
+               return 1;
+       }
+
+       otmp->known = TRUE;
+       if(otmp == uwep)
+               setuwep((struct obj *)0);
+       if (otmp == uswapwep)
+               setuswapwep((struct obj *) 0);
+       if (otmp == uquiver)
+               setuqwep((struct obj *) 0);
+       setworn(otmp, mask);
+       delay = -objects[otmp->otyp].oc_delay;
+       if(delay){
+               nomul(delay);
+               if(is_boots(otmp)) afternmv = Boots_on;
+               if(is_helmet(otmp)) afternmv = Helmet_on;
+               if(is_gloves(otmp)) afternmv = Gloves_on;
+               if(otmp == uarm) afternmv = Armor_on;
+               nomovemsg = "You finish your dressing maneuver.";
+       } else {
+               if(is_cloak(otmp)) (void) Cloak_on();
+               if (is_shield(otmp)) (void) Shield_on();
+#ifdef TOURIST
+               if (is_shirt(otmp)) (void) Shirt_on();
+#endif
+               on_msg(otmp);
+       }
+       takeoff_mask = taking_off = 0L;
+       return(1);
+}
+
+int
+doputon()
+{
+       register struct obj *otmp;
+       long mask = 0L;
+
+       if(uleft && uright && uamul && ublindf) {
+               Your("%s%s are full, and you're already wearing an amulet and %s.",
+                       humanoid(youmonst.data) ? "ring-" : "",
+                       makeplural(body_part(FINGER)),
+                       ublindf->otyp==LENSES ? "some lenses" : "a blindfold");
+               return(0);
+       }
+       otmp = getobj(accessories, "put on");
+       if(!otmp) return(0);
+       if(otmp->owornmask & (W_RING | W_AMUL | W_TOOL)) {
+               already_wearing(c_that_);
+               return(0);
+       }
+       if(welded(otmp)) {
+               weldmsg(otmp);
+               return(0);
+       }
+       if(otmp == uwep)
+               setuwep((struct obj *)0);
+       if(otmp == uswapwep)
+               setuswapwep((struct obj *) 0);
+       if(otmp == uquiver)
+               setuqwep((struct obj *) 0);
+       if(otmp->oclass == RING_CLASS || otmp->otyp == MEAT_RING) {
+               if(nolimbs(youmonst.data)) {
+                       You("cannot make the ring stick to your body.");
+                       return(0);
+               }
+               if(uleft && uright){
+                       There("are no more %s%s to fill.",
+                               humanoid(youmonst.data) ? "ring-" : "",
+                               makeplural(body_part(FINGER)));
+                       return(0);
+               }
+               if(uleft) mask = RIGHT_RING;
+               else if(uright) mask = LEFT_RING;
+               else do {
+                       char qbuf[QBUFSZ];
+                       char answer;
+
+                       Sprintf(qbuf, "Which %s%s, Right or Left?",
+                               humanoid(youmonst.data) ? "ring-" : "",
+                               body_part(FINGER));
+                       if(!(answer = yn_function(qbuf, "rl", '\0')))
+                               return(0);
+                       switch(answer){
+                       case 'l':
+                       case 'L':
+                               mask = LEFT_RING;
+                               break;
+                       case 'r':
+                       case 'R':
+                               mask = RIGHT_RING;
+                               break;
+                       }
+               } while(!mask);
+               if (uarmg && uarmg->cursed) {
+                       uarmg->bknown = TRUE;
+                   You("cannot remove your gloves to put on the ring.");
+                       return(0);
+               }
+               if (welded(uwep) && bimanual(uwep)) {
+                       /* welded will set bknown */
+           You("cannot free your weapon hands to put on the ring.");
+                       return(0);
+               }
+               if (welded(uwep) && mask==RIGHT_RING) {
+                       /* welded will set bknown */
+           You("cannot free your weapon hand to put on the ring.");
+                       return(0);
+               }
+               if (otmp->oartifact && !touch_artifact(otmp, &youmonst))
+                   return 1; /* costs a turn even though it didn't get worn */
+               setworn(otmp, mask);
+               Ring_on(otmp);
+       } else if (otmp->oclass == AMULET_CLASS) {
+               if(uamul) {
+                       already_wearing("an amulet");
+                       return(0);
+               }
+               if (otmp->oartifact && !touch_artifact(otmp, &youmonst))
+                   return 1;
+               setworn(otmp, W_AMUL);
+               if (otmp->otyp == AMULET_OF_CHANGE) {
+                       Amulet_on();
+                       /* Don't do a prinv() since the amulet is now gone */
+                       return(1);
+               }
+               Amulet_on();
+       } else {        /* it's a blindfold, towel, or lenses */
+               if (ublindf) {
+                       if (ublindf->otyp == TOWEL)
+                               Your("%s is already covered by a towel.",
+                                       body_part(FACE));
+                       else if (ublindf->otyp == BLINDFOLD) {
+                               if (otmp->otyp == LENSES)
+                                       already_wearing2("lenses", "a blindfold");
+                               else
+                                       already_wearing("a blindfold");
+                       } else if (ublindf->otyp == LENSES) {
+                               if (otmp->otyp == BLINDFOLD)
+                                       already_wearing2("a blindfold", "some lenses");
+                               else
+                                       already_wearing("some lenses");
+                       } else
+                               already_wearing(something); /* ??? */
+                       return(0);
+               }
+               if (otmp->otyp != BLINDFOLD && otmp->otyp != TOWEL && otmp->otyp != LENSES) {
+                       You_cant("wear that!");
+                       return(0);
+               }
+               if (otmp->oartifact && !touch_artifact(otmp, &youmonst))
+                   return 1;
+               Blindf_on(otmp);
+               return(1);
+       }
+       if (is_worn(otmp))
+           prinv((char *)0, otmp, 0L);
+       return(1);
+}
+
+#endif /* OVLB */
+
+#ifdef OVL0
+
+void
+find_ac()
+{
+       int uac = mons[u.umonnum].ac;
+
+       if(uarm) uac -= ARM_BONUS(uarm);
+       if(uarmc) uac -= ARM_BONUS(uarmc);
+       if(uarmh) uac -= ARM_BONUS(uarmh);
+       if(uarmf) uac -= ARM_BONUS(uarmf);
+       if(uarms) uac -= ARM_BONUS(uarms);
+       if(uarmg) uac -= ARM_BONUS(uarmg);
+#ifdef TOURIST
+       if(uarmu) uac -= ARM_BONUS(uarmu);
+#endif
+       if(uleft && uleft->otyp == RIN_PROTECTION) uac -= uleft->spe;
+       if(uright && uright->otyp == RIN_PROTECTION) uac -= uright->spe;
+       if (HProtection & INTRINSIC) uac -= u.ublessed;
+       uac -= u.uspellprot;
+       if (uac < -128) uac = -128;     /* u.uac is an schar */
+       if(uac != u.uac){
+               u.uac = uac;
+               flags.botl = 1;
+       }
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+void
+glibr()
+{
+       register struct obj *otmp;
+       int xfl = 0;
+       boolean leftfall, rightfall;
+       const char *otherwep = 0;
+
+       leftfall = (uleft && !uleft->cursed &&
+                   (!uwep || !welded(uwep) || !bimanual(uwep)));
+       rightfall = (uright && !uright->cursed && (!welded(uwep)));
+       if (!uarmg && (leftfall || rightfall) && !nolimbs(youmonst.data)) {
+               /* changed so cursed rings don't fall off, GAN 10/30/86 */
+               Your("%s off your %s.",
+                       (leftfall && rightfall) ? "rings slip" : "ring slips",
+                       (leftfall && rightfall) ? makeplural(body_part(FINGER)) :
+                       body_part(FINGER));
+               xfl++;
+               if (leftfall) {
+                       otmp = uleft;
+                       Ring_off(uleft);
+                       dropx(otmp);
+               }
+               if (rightfall) {
+                       otmp = uright;
+                       Ring_off(uright);
+                       dropx(otmp);
+               }
+       }
+
+       otmp = uswapwep;
+       if (u.twoweap && otmp) {
+               otherwep = is_sword(otmp) ? c_sword :
+                   makesingular(oclass_names[(int)otmp->oclass]);
+               Your("%s %sslips from your %s.",
+                       otherwep,
+                       xfl ? "also " : "",
+                       makeplural(body_part(HAND)));
+               setuswapwep((struct obj *)0);
+               xfl++;
+               if (otmp->otyp != LOADSTONE || !otmp->cursed)
+                       dropx(otmp);
+       }
+       otmp = uwep;
+       if (otmp && !welded(otmp)) {
+               const char *thiswep;
+
+               /* nice wording if both weapons are the same type */
+               thiswep = is_sword(otmp) ? c_sword :
+                   makesingular(oclass_names[(int)otmp->oclass]);
+               if (otherwep && strcmp(thiswep, otherwep)) otherwep = 0;
+
+               /* changed so cursed weapons don't fall, GAN 10/30/86 */
+               Your("%s%s %sslips from your %s.",
+                       otherwep ? "other " : "", thiswep,
+                       xfl ? "also " : "",
+                       makeplural(body_part(HAND)));
+               setuwep((struct obj *)0);
+               if (otmp->otyp != LOADSTONE || !otmp->cursed)
+                       dropx(otmp);
+       }
+}
+
+struct obj *
+some_armor(victim)
+struct monst *victim;
+{
+       register struct obj *otmph, *otmp;
+
+       otmph = (victim == &youmonst) ? uarmc : which_armor(victim, W_ARMC);
+       if (!otmph)
+           otmph = (victim == &youmonst) ? uarm : which_armor(victim, W_ARM);
+#ifdef TOURIST
+       if (!otmph)
+           otmph = (victim == &youmonst) ? uarmu : which_armor(victim, W_ARMU);
+#endif
+       
+       otmp = (victim == &youmonst) ? uarmh : which_armor(victim, W_ARMH);
+       if(otmp && (!otmph || !rn2(4))) otmph = otmp;
+       otmp = (victim == &youmonst) ? uarmg : which_armor(victim, W_ARMG);
+       if(otmp && (!otmph || !rn2(4))) otmph = otmp;
+       otmp = (victim == &youmonst) ? uarmf : which_armor(victim, W_ARMF);
+       if(otmp && (!otmph || !rn2(4))) otmph = otmp;
+       otmp = (victim == &youmonst) ? uarms : which_armor(victim, W_ARMS);
+       if(otmp && (!otmph || !rn2(4))) otmph = otmp;
+       return(otmph);
+}
+
+/* erode some arbitrary armor worn by the victim */
+void
+erode_armor(victim, acid_dmg)
+struct monst *victim;
+boolean acid_dmg;
+{
+       struct obj *otmph = some_armor(victim);
+
+       if (otmph && (otmph != uarmf)) {
+           erode_obj(otmph, acid_dmg, FALSE);
+           if (carried(otmph)) update_inventory();
+       }
+}
+
+/* used for praying to check and fix levitation trouble */
+struct obj *
+stuck_ring(ring, otyp)
+struct obj *ring;
+int otyp;
+{
+    if (ring != uleft && ring != uright) {
+       impossible("stuck_ring: neither left nor right?");
+       return (struct obj *)0;
+    }
+
+    if (ring && ring->otyp == otyp) {
+       /* reasons ring can't be removed match those checked by select_off();
+          limbless case has extra checks because ordinarily it's temporary */
+       if (nolimbs(youmonst.data) &&
+               uamul && uamul->otyp == AMULET_OF_UNCHANGING && uamul->cursed)
+           return uamul;
+       if (welded(uwep) && (ring == uright || bimanual(uwep))) return uwep;
+       if (uarmg && uarmg->cursed) return uarmg;
+       if (ring->cursed) return ring;
+    }
+    /* either no ring or not right type or nothing prevents its removal */
+    return (struct obj *)0;
+}
+
+/* also for praying; find worn item that confers "Unchanging" attribute */
+struct obj *
+unchanger()
+{
+    if (uamul && uamul->otyp == AMULET_OF_UNCHANGING) return uamul;
+    return 0;
+}
+
+/* occupation callback for 'A' */
+STATIC_PTR
+int
+select_off(otmp)
+register struct obj *otmp;
+{
+       struct obj *why;
+       char buf[BUFSZ];
+
+       if (!otmp) return 0;
+       *buf = '\0';                    /* lint suppresion */
+
+       /* special ring checks */
+       if (otmp == uright || otmp == uleft) {
+           if (nolimbs(youmonst.data)) {
+               pline_The("ring is stuck.");
+               return 0;
+           }
+           why = 0;    /* the item which prevents ring removal */
+           if (welded(uwep) && (otmp == uright || bimanual(uwep))) {
+               Sprintf(buf, "free a weapon %s", body_part(HAND));
+               why = uwep;
+           } else if (uarmg && uarmg->cursed) {
+               Sprintf(buf, "take off your %s", c_gloves);
+               why = uarmg;
+           }
+           if (why) {
+               You("cannot %s to remove the ring.", buf);
+               why->bknown = TRUE;
+               return 0;
+           }
+       }
+       /* special glove checks */
+       if (otmp == uarmg) {
+           if (welded(uwep)) {
+               You("are unable to take off your %s while wielding that %s.",
+                   c_gloves, is_sword(uwep) ? c_sword : c_weapon);
+               uwep->bknown = TRUE;
+               return 0;
+           } else if (Glib) {
+               You_cant("take off the slippery %s with your slippery %s.",
+                        c_gloves, makeplural(body_part(FINGER)));
+               return 0;
+           }
+       }
+       /* special boot checks */
+       if (otmp == uarmf) {
+           if (u.utrap && u.utraptype == TT_BEARTRAP) {
+               pline_The("bear trap prevents you from pulling your %s out.",
+                         body_part(FOOT));
+               return 0;
+           } else if (u.utrap && u.utraptype == TT_INFLOOR) {
+               You("are stuck in the %s, and cannot pull your %s out.",
+                   surface(u.ux, u.uy), makeplural(body_part(FOOT)));
+               return 0;
+           }
+       }
+       /* special suit and shirt checks */
+       if (otmp == uarm
+#ifdef TOURIST
+                       || otmp == uarmu
+#endif
+               ) {
+           why = 0;    /* the item which prevents disrobing */
+           if (uarmc && uarmc->cursed) {
+               Sprintf(buf, "remove your %s", cloak_simple_name(uarmc));
+               why = uarmc;
+#ifdef TOURIST
+           } else if (otmp == uarmu && uarm && uarm->cursed) {
+               Sprintf(buf, "remove your %s", c_suit);
+               why = uarm;
+#endif
+           } else if (welded(uwep) && bimanual(uwep)) {
+               Sprintf(buf, "release your %s",
+                       is_sword(uwep) ? c_sword :
+                       (uwep->otyp == BATTLE_AXE) ? c_axe : c_weapon);
+               why = uwep;
+           }
+           if (why) {
+               You("cannot %s to take off %s.", buf, the(xname(otmp)));
+               why->bknown = TRUE;
+               return 0;
+           }
+       }
+       /* basic curse check */
+       if (otmp == uquiver || (otmp == uswapwep && !u.twoweap)) {
+           ;   /* some items can be removed even when cursed */
+       } else {
+           /* otherwise, this is fundamental */
+           if (cursed(otmp)) return 0;
+       }
+
+       if(otmp == uarm) takeoff_mask |= WORN_ARMOR;
+       else if(otmp == uarmc) takeoff_mask |= WORN_CLOAK;
+       else if(otmp == uarmf) takeoff_mask |= WORN_BOOTS;
+       else if(otmp == uarmg) takeoff_mask |= WORN_GLOVES;
+       else if(otmp == uarmh) takeoff_mask |= WORN_HELMET;
+       else if(otmp == uarms) takeoff_mask |= WORN_SHIELD;
+#ifdef TOURIST
+       else if(otmp == uarmu) takeoff_mask |= WORN_SHIRT;
+#endif
+       else if(otmp == uleft) takeoff_mask |= LEFT_RING;
+       else if(otmp == uright) takeoff_mask |= RIGHT_RING;
+       else if(otmp == uamul) takeoff_mask |= WORN_AMUL;
+       else if(otmp == ublindf) takeoff_mask |= WORN_BLINDF;
+       else if(otmp == uwep) takeoff_mask |= W_WEP;
+       else if(otmp == uswapwep) takeoff_mask |= W_SWAPWEP;
+       else if(otmp == uquiver) takeoff_mask |= W_QUIVER;
+
+       else impossible("select_off: %s???", doname(otmp));
+
+       return(0);
+}
+
+STATIC_OVL struct obj *
+do_takeoff()
+{
+       register struct obj *otmp = (struct obj *)0;
+
+       if (taking_off == W_WEP) {
+         if(!cursed(uwep)) {
+           setuwep((struct obj *) 0);
+           You("are empty %s.", body_part(HANDED));
+           u.twoweap = FALSE;
+         }
+       } else if (taking_off == W_SWAPWEP) {
+         setuswapwep((struct obj *) 0);
+         You("no longer have a second weapon readied.");
+         u.twoweap = FALSE;
+       } else if (taking_off == W_QUIVER) {
+         setuqwep((struct obj *) 0);
+         You("no longer have ammunition readied.");
+       } else if (taking_off == WORN_ARMOR) {
+         otmp = uarm;
+         if(!cursed(otmp)) (void) Armor_off();
+       } else if (taking_off == WORN_CLOAK) {
+         otmp = uarmc;
+         if(!cursed(otmp)) (void) Cloak_off();
+       } else if (taking_off == WORN_BOOTS) {
+         otmp = uarmf;
+         if(!cursed(otmp)) (void) Boots_off();
+       } else if (taking_off == WORN_GLOVES) {
+         otmp = uarmg;
+         if(!cursed(otmp)) (void) Gloves_off();
+       } else if (taking_off == WORN_HELMET) {
+         otmp = uarmh;
+         if(!cursed(otmp)) (void) Helmet_off();
+       } else if (taking_off == WORN_SHIELD) {
+         otmp = uarms;
+         if(!cursed(otmp)) (void) Shield_off();
+#ifdef TOURIST
+       } else if (taking_off == WORN_SHIRT) {
+         otmp = uarmu;
+         if (!cursed(otmp)) (void) Shirt_off();
+#endif
+       } else if (taking_off == WORN_AMUL) {
+         otmp = uamul;
+         if(!cursed(otmp)) Amulet_off();
+       } else if (taking_off == LEFT_RING) {
+         otmp = uleft;
+         if(!cursed(otmp)) Ring_off(uleft);
+       } else if (taking_off == RIGHT_RING) {
+         otmp = uright;
+         if(!cursed(otmp)) Ring_off(uright);
+       } else if (taking_off == WORN_BLINDF) {
+         if (!cursed(ublindf)) Blindf_off(ublindf);
+       } else impossible("do_takeoff: taking off %lx", taking_off);
+
+       return(otmp);
+}
+
+static const char *disrobing = "";
+
+STATIC_PTR
+int
+take_off()
+{
+       register int i;
+       register struct obj *otmp;
+
+       if (taking_off) {
+           if (todelay > 0) {
+               todelay--;
+               return(1);      /* still busy */
+           } else {
+               if ((otmp = do_takeoff())) off_msg(otmp);
+           }
+           takeoff_mask &= ~taking_off;
+           taking_off = 0L;
+       }
+
+       for(i = 0; takeoff_order[i]; i++)
+           if(takeoff_mask & takeoff_order[i]) {
+               taking_off = takeoff_order[i];
+               break;
+           }
+
+       otmp = (struct obj *) 0;
+       todelay = 0;
+
+       if (taking_off == 0L) {
+         You("finish %s.", disrobing);
+         return 0;
+       } else if (taking_off == W_WEP) {
+         todelay = 1;
+       } else if (taking_off == W_SWAPWEP) {
+         todelay = 1;
+       } else if (taking_off == W_QUIVER) {
+         todelay = 1;
+       } else if (taking_off == WORN_ARMOR) {
+         otmp = uarm;
+         /* If a cloak is being worn, add the time to take it off and put
+          * it back on again.  Kludge alert! since that time is 0 for all
+          * known cloaks, add 1 so that it actually matters...
+          */
+         if (uarmc) todelay += 2 * objects[uarmc->otyp].oc_delay + 1;
+       } else if (taking_off == WORN_CLOAK) {
+         otmp = uarmc;
+       } else if (taking_off == WORN_BOOTS) {
+         otmp = uarmf;
+       } else if (taking_off == WORN_GLOVES) {
+         otmp = uarmg;
+       } else if (taking_off == WORN_HELMET) {
+         otmp = uarmh;
+       } else if (taking_off == WORN_SHIELD) {
+         otmp = uarms;
+#ifdef TOURIST
+       } else if (taking_off == WORN_SHIRT) {
+         otmp = uarmu;
+         /* add the time to take off and put back on armor and/or cloak */
+         if (uarm)  todelay += 2 * objects[uarm->otyp].oc_delay;
+         if (uarmc) todelay += 2 * objects[uarmc->otyp].oc_delay + 1;
+#endif
+       } else if (taking_off == WORN_AMUL) {
+         todelay = 1;
+       } else if (taking_off == LEFT_RING) {
+         todelay = 1;
+       } else if (taking_off == RIGHT_RING) {
+         todelay = 1;
+       } else if (taking_off == WORN_BLINDF) {
+         todelay = 2;
+       } else {
+         impossible("take_off: taking off %lx", taking_off);
+         return 0;     /* force done */
+       }
+
+       if (otmp) todelay += objects[otmp->otyp].oc_delay;
+
+       /* Since setting the occupation now starts the counter next move, that
+        * would always produce a delay 1 too big per item unless we subtract
+        * 1 here to account for it.
+        */
+       if (todelay > 0) todelay--;
+
+       set_occupation(take_off, disrobing, 0);
+       return(1);              /* get busy */
+}
+
+/* clear saved context to avoid inappropriate resumption of interrupted 'A' */
+void
+reset_remarm()
+{
+       taking_off = takeoff_mask = 0L;
+       disrobing = nul;
+}
+
+/* the 'A' command -- remove multiple worn items */
+int
+doddoremarm()
+{
+    int result = 0;
+
+    if (taking_off || takeoff_mask) {
+       You("continue %s.", disrobing);
+       set_occupation(take_off, disrobing, 0);
+       return 0;
+    } else if (!uwep && !uswapwep && !uquiver && !uamul && !ublindf &&
+               !uleft && !uright && !wearing_armor()) {
+       You("are not wearing anything.");
+       return 0;
+    }
+
+    add_valid_menu_class(0); /* reset */
+    if (flags.menu_style != MENU_TRADITIONAL ||
+           (result = ggetobj("take off", select_off, 0, FALSE, (unsigned *)0)) < -1)
+       result = menu_remarm(result);
+
+    if (takeoff_mask) {
+       /* default activity for armor and/or accessories,
+          possibly combined with weapons */
+       disrobing = "disrobing";
+       /* specific activity when handling weapons only */
+       if (!(takeoff_mask & ~(W_WEP|W_SWAPWEP|W_QUIVER)))
+           disrobing = "disarming";
+       (void) take_off();
+    }
+    /* The time to perform the command is already completely accounted for
+     * in take_off(); if we return 1, that would add an extra turn to each
+     * disrobe.
+     */
+    return 0;
+}
+
+STATIC_OVL int
+menu_remarm(retry)
+int retry;
+{
+    int n, i = 0;
+    menu_item *pick_list;
+    boolean all_worn_categories = TRUE;
+
+    if (retry) {
+       all_worn_categories = (retry == -2);
+    } else if (flags.menu_style == MENU_FULL) {
+       all_worn_categories = FALSE;
+       n = query_category("What type of things do you want to take off?",
+                          invent, WORN_TYPES|ALL_TYPES, &pick_list, PICK_ANY);
+       if (!n) return 0;
+       for (i = 0; i < n; i++) {
+           if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
+               all_worn_categories = TRUE;
+           else
+               add_valid_menu_class(pick_list[i].item.a_int);
+       }
+       free((genericptr_t) pick_list);
+    } else if (flags.menu_style == MENU_COMBINATION) {
+       all_worn_categories = FALSE;
+       if (ggetobj("take off", select_off, 0, TRUE, (unsigned *)0) == -2)
+           all_worn_categories = TRUE;
+    }
+
+    n = query_objlist("What do you want to take off?", invent,
+                       SIGNAL_NOMENU|USE_INVLET|INVORDER_SORT,
+                       &pick_list, PICK_ANY,
+                       all_worn_categories ? is_worn : is_worn_by_type);
+    if (n > 0) {
+       for (i = 0; i < n; i++)
+           (void) select_off(pick_list[i].item.a_obj);
+       free((genericptr_t) pick_list);
+    } else if (n < 0 && flags.menu_style != MENU_COMBINATION) {
+       There("is nothing else you can remove or unwield.");
+    }
+    return 0;
+}
+
+/* hit by destroy armor scroll/black dragon breath/monster spell */
+int
+destroy_arm(atmp)
+register struct obj *atmp;
+{
+       register struct obj *otmp;
+#define DESTROY_ARM(o) ((otmp = (o)) != 0 && \
+                       (!atmp || atmp == otmp) && \
+                       (!obj_resists(otmp, 0, 90)))
+
+       if (DESTROY_ARM(uarmc)) {
+               if (donning(otmp)) cancel_don();
+               Your("%s crumbles and turns to dust!",
+                    cloak_simple_name(uarmc));
+               (void) Cloak_off();
+               useup(otmp);
+       } else if (DESTROY_ARM(uarm)) {
+               if (donning(otmp)) cancel_don();
+               Your("armor turns to dust and falls to the %s!",
+                       surface(u.ux,u.uy));
+               (void) Armor_gone();
+               useup(otmp);
+#ifdef TOURIST
+       } else if (DESTROY_ARM(uarmu)) {
+               if (donning(otmp)) cancel_don();
+               Your("shirt crumbles into tiny threads and falls apart!");
+               (void) Shirt_off();
+               useup(otmp);
+#endif
+       } else if (DESTROY_ARM(uarmh)) {
+               if (donning(otmp)) cancel_don();
+               Your("helmet turns to dust and is blown away!");
+               (void) Helmet_off();
+               useup(otmp);
+       } else if (DESTROY_ARM(uarmg)) {
+               if (donning(otmp)) cancel_don();
+               Your("gloves vanish!");
+               (void) Gloves_off();
+               useup(otmp);
+               selftouch("You");
+       } else if (DESTROY_ARM(uarmf)) {
+               if (donning(otmp)) cancel_don();
+               Your("boots disintegrate!");
+               (void) Boots_off();
+               useup(otmp);
+       } else if (DESTROY_ARM(uarms)) {
+               if (donning(otmp)) cancel_don();
+               Your("shield crumbles away!");
+               (void) Shield_off();
+               useup(otmp);
+       } else {
+               return 0;               /* could not destroy anything */
+       }
+
+#undef DESTROY_ARM
+       stop_occupation();
+       return(1);
+}
+
+void
+adj_abon(otmp, delta)
+register struct obj *otmp;
+register schar delta;
+{
+       if (uarmg && uarmg == otmp && otmp->otyp == GAUNTLETS_OF_DEXTERITY) {
+               if (delta) {
+                       makeknown(uarmg->otyp);
+                       ABON(A_DEX) += (delta);
+               }
+               flags.botl = 1;
+       }
+       if (uarmh && uarmh == otmp && otmp->otyp == HELM_OF_BRILLIANCE) {
+               if (delta) {
+                       makeknown(uarmh->otyp);
+                       ABON(A_INT) += (delta);
+                       ABON(A_WIS) += (delta);
+               }
+               flags.botl = 1;
+       }
+}
+
+#endif /* OVLB */
+
+/*do_wear.c*/
diff --git a/src/dog.c b/src/dog.c
new file mode 100644 (file)
index 0000000..1081665
--- /dev/null
+++ b/src/dog.c
@@ -0,0 +1,939 @@
+/*     SCCS Id: @(#)dog.c      3.4     2002/09/08      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "edog.h"
+
+#ifdef OVLB
+
+STATIC_DCL int NDECL(pet_type);
+
+void
+initedog(mtmp)
+register struct monst *mtmp;
+{
+       mtmp->mtame = is_domestic(mtmp->data) ? 10 : 5;
+       mtmp->mpeaceful = 1;
+       mtmp->mavenge = 0;
+       set_malign(mtmp); /* recalc alignment now that it's tamed */
+       mtmp->mleashed = 0;
+       mtmp->meating = 0;
+       EDOG(mtmp)->droptime = 0;
+       EDOG(mtmp)->dropdist = 10000;
+       EDOG(mtmp)->apport = 10;
+       EDOG(mtmp)->whistletime = 0;
+       EDOG(mtmp)->hungrytime = 1000 + monstermoves;
+       EDOG(mtmp)->ogoal.x = -1;       /* force error if used before set */
+       EDOG(mtmp)->ogoal.y = -1;
+       EDOG(mtmp)->abuse = 0;
+       EDOG(mtmp)->revivals = 0;
+       EDOG(mtmp)->mhpmax_penalty = 0;
+       EDOG(mtmp)->killed_by_u = 0;
+}
+
+STATIC_OVL int
+pet_type()
+{
+       if (urole.petnum != NON_PM)
+           return (urole.petnum);
+       else if (preferred_pet == 'c')
+           return (PM_KITTEN);
+       else if (preferred_pet == 'd')
+           return (PM_LITTLE_DOG);
+       else
+           return (rn2(2) ? PM_KITTEN : PM_LITTLE_DOG);
+}
+
+struct monst *
+make_familiar(otmp,x,y,quietly)
+register struct obj *otmp;
+xchar x, y;
+boolean quietly;
+{
+       struct permonst *pm;
+       struct monst *mtmp = 0;
+       int chance, trycnt = 100;
+
+       do {
+           if (otmp) { /* figurine; otherwise spell */
+               int mndx = otmp->corpsenm;
+               pm = &mons[mndx];
+               /* activating a figurine provides one way to exceed the
+                  maximum number of the target critter created--unless
+                  it has a special limit (erinys, Nazgul) */
+               if ((mvitals[mndx].mvflags & G_EXTINCT) &&
+                       mbirth_limit(mndx) != MAXMONNO) {
+                   if (!quietly)
+                       /* have just been given "You <do something with>
+                          the figurine and it transforms." message */
+                       pline("... into a pile of dust.");
+                   break;      /* mtmp is null */
+               }
+           } else if (!rn2(3)) {
+               pm = &mons[pet_type()];
+           } else {
+               pm = rndmonst();
+               if (!pm) {
+                 if (!quietly)
+                   There("seems to be nothing available for a familiar.");
+                 break;
+               }
+           }
+
+           mtmp = makemon(pm, x, y, MM_EDOG|MM_IGNOREWATER);
+           if (otmp && !mtmp) { /* monster was genocided or square occupied */
+               if (!quietly)
+                  pline_The("figurine writhes and then shatters into pieces!");
+               break;
+           }
+       } while (!mtmp && --trycnt > 0);
+
+       if (!mtmp) return (struct monst *)0;
+
+       if (is_pool(mtmp->mx, mtmp->my) && minliquid(mtmp))
+               return (struct monst *)0;
+
+       initedog(mtmp);
+       mtmp->msleeping = 0;
+       if (otmp) { /* figurine; resulting monster might not become a pet */
+           chance = rn2(10);   /* 0==tame, 1==peaceful, 2==hostile */
+           if (chance > 2) chance = otmp->blessed ? 0 : !otmp->cursed ? 1 : 2;
+           /* 0,1,2:  b=80%,10,10; nc=10%,80,10; c=10%,10,80 */
+           if (chance > 0) {
+               mtmp->mtame = 0;        /* not tame after all */
+               if (chance == 2) { /* hostile (cursed figurine) */
+                   if (!quietly)
+                      You("get a bad feeling about this.");
+                   mtmp->mpeaceful = 0;
+                   set_malign(mtmp);
+               }
+           }
+           /* if figurine has been named, give same name to the monster */
+           if (otmp->onamelth)
+               mtmp = christen_monst(mtmp, ONAME(otmp));
+       }
+       set_malign(mtmp); /* more alignment changes */
+       newsym(mtmp->mx, mtmp->my);
+
+       /* must wield weapon immediately since pets will otherwise drop it */
+       if (mtmp->mtame && attacktype(mtmp->data, AT_WEAP)) {
+               mtmp->weapon_check = NEED_HTH_WEAPON;
+               (void) mon_wield_item(mtmp);
+       }
+       return mtmp;
+}
+
+struct monst *
+makedog()
+{
+       register struct monst *mtmp;
+#ifdef STEED
+       register struct obj *otmp;
+#endif
+       const char *petname;
+       int   pettype;
+       static int petname_used = 0;
+
+       if (preferred_pet == 'n') return((struct monst *) 0);
+
+       pettype = pet_type();
+       if (pettype == PM_LITTLE_DOG)
+               petname = dogname;
+       else if (pettype == PM_PONY)
+               petname = horsename;
+       else
+               petname = catname;
+
+       /* default pet names */
+       if (!*petname && pettype == PM_LITTLE_DOG) {
+           /* All of these names were for dogs. */
+           if(Role_if(PM_CAVEMAN)) petname = "Slasher";   /* The Warrior */
+           if(Role_if(PM_SAMURAI)) petname = "Hachi";     /* Shibuya Station */
+           if(Role_if(PM_BARBARIAN)) petname = "Idefix";  /* Obelix */
+           if(Role_if(PM_RANGER)) petname = "Sirius";     /* Orion's dog */
+       }
+
+       mtmp = makemon(&mons[pettype], u.ux, u.uy, MM_EDOG);
+
+       if(!mtmp) return((struct monst *) 0); /* pets were genocided */
+
+#ifdef STEED
+       /* Horses already wear a saddle */
+       if (pettype == PM_PONY && !!(otmp = mksobj(SADDLE, TRUE, FALSE))) {
+           if (mpickobj(mtmp, otmp))
+               panic("merged saddle?");
+           mtmp->misc_worn_check |= W_SADDLE;
+           otmp->dknown = otmp->bknown = otmp->rknown = 1;
+           otmp->owornmask = W_SADDLE;
+           otmp->leashmon = mtmp->m_id;
+           update_mon_intrinsics(mtmp, otmp, TRUE, TRUE);
+       }
+#endif
+
+       if (!petname_used++ && *petname)
+               mtmp = christen_monst(mtmp, petname);
+
+       initedog(mtmp);
+       return(mtmp);
+}
+
+/* record `last move time' for all monsters prior to level save so that
+   mon_arrive() can catch up for lost time when they're restored later */
+void
+update_mlstmv()
+{
+       struct monst *mon;
+
+       /* monst->mlstmv used to be updated every time `monst' actually moved,
+          but that is no longer the case so we just do a blanket assignment */
+       for (mon = fmon; mon; mon = mon->nmon)
+           if (!DEADMONSTER(mon)) mon->mlstmv = monstermoves;
+}
+
+void
+losedogs()
+{
+       register struct monst *mtmp, *mtmp0 = 0, *mtmp2;
+
+       while ((mtmp = mydogs) != 0) {
+               mydogs = mtmp->nmon;
+               mon_arrive(mtmp, TRUE);
+       }
+
+       for(mtmp = migrating_mons; mtmp; mtmp = mtmp2) {
+               mtmp2 = mtmp->nmon;
+               if (mtmp->mux == u.uz.dnum && mtmp->muy == u.uz.dlevel) {
+                   if(mtmp == migrating_mons)
+                       migrating_mons = mtmp->nmon;
+                   else
+                       mtmp0->nmon = mtmp->nmon;
+                   mon_arrive(mtmp, FALSE);
+               } else
+                   mtmp0 = mtmp;
+       }
+}
+
+/* called from resurrect() in addition to losedogs() */
+void
+mon_arrive(mtmp, with_you)
+struct monst *mtmp;
+boolean with_you;
+{
+       struct trap *t;
+       xchar xlocale, ylocale, xyloc, xyflags, wander;
+       int num_segs;
+
+       mtmp->nmon = fmon;
+       fmon = mtmp;
+       if (mtmp->isshk)
+           set_residency(mtmp, FALSE);
+
+       num_segs = mtmp->wormno;
+       /* baby long worms have no tail so don't use is_longworm() */
+       if ((mtmp->data == &mons[PM_LONG_WORM]) &&
+#ifdef DCC30_BUG
+           (mtmp->wormno = get_wormno(), mtmp->wormno != 0))
+#else
+           (mtmp->wormno = get_wormno()) != 0)
+#endif
+       {
+           initworm(mtmp, num_segs);
+           /* tail segs are not yet initialized or displayed */
+       } else mtmp->wormno = 0;
+
+       /* some monsters might need to do something special upon arrival
+          _after_ the current level has been fully set up; see dochug() */
+       mtmp->mstrategy |= STRAT_ARRIVE;
+
+       /* make sure mnexto(rloc_to(set_apparxy())) doesn't use stale data */
+       mtmp->mux = u.ux,  mtmp->muy = u.uy;
+       xyloc   = mtmp->mtrack[0].x;
+       xyflags = mtmp->mtrack[0].y;
+       xlocale = mtmp->mtrack[1].x;
+       ylocale = mtmp->mtrack[1].y;
+       mtmp->mtrack[0].x = mtmp->mtrack[0].y = 0;
+       mtmp->mtrack[1].x = mtmp->mtrack[1].y = 0;
+
+#ifdef STEED
+       if (mtmp == u.usteed)
+           return;     /* don't place steed on the map */
+#endif
+       if (with_you) {
+           /* When a monster accompanies you, sometimes it will arrive
+              at your intended destination and you'll end up next to
+              that spot.  This code doesn't control the final outcome;
+              goto_level(do.c) decides who ends up at your target spot
+              when there is a monster there too. */
+           if (!MON_AT(u.ux, u.uy) &&
+                   !rn2(mtmp->mtame ? 10 : mtmp->mpeaceful ? 5 : 2))
+               rloc_to(mtmp, u.ux, u.uy);
+           else
+               mnexto(mtmp);
+           return;
+       }
+       /*
+        * The monster arrived on this level independently of the player.
+        * Its coordinate fields were overloaded for use as flags that
+        * specify its final destination.
+        */
+
+       if (mtmp->mlstmv < monstermoves - 1L) {
+           /* heal monster for time spent in limbo */
+           long nmv = monstermoves - 1L - mtmp->mlstmv;
+
+           mon_catchup_elapsed_time(mtmp, nmv);
+           mtmp->mlstmv = monstermoves - 1L;
+
+           /* let monster move a bit on new level (see placement code below) */
+           wander = (xchar) min(nmv, 8);
+       } else
+           wander = 0;
+
+       switch (xyloc) {
+        case MIGR_APPROX_XY:   /* {x,y}locale set above */
+               break;
+        case MIGR_EXACT_XY:    wander = 0;
+               break;
+        case MIGR_NEAR_PLAYER: xlocale = u.ux,  ylocale = u.uy;
+               break;
+        case MIGR_STAIRS_UP:   xlocale = xupstair,  ylocale = yupstair;
+               break;
+        case MIGR_STAIRS_DOWN: xlocale = xdnstair,  ylocale = ydnstair;
+               break;
+        case MIGR_LADDER_UP:   xlocale = xupladder,  ylocale = yupladder;
+               break;
+        case MIGR_LADDER_DOWN: xlocale = xdnladder,  ylocale = ydnladder;
+               break;
+        case MIGR_SSTAIRS:     xlocale = sstairs.sx,  ylocale = sstairs.sy;
+               break;
+        case MIGR_PORTAL:
+               if (In_endgame(&u.uz)) {
+                   /* there is no arrival portal for endgame levels */
+                   /* BUG[?]: for simplicity, this code relies on the fact
+                      that we know that the current endgame levels always
+                      build upwards and never have any exclusion subregion
+                      inside their TELEPORT_REGION settings. */
+                   xlocale = rn1(updest.hx - updest.lx + 1, updest.lx);
+                   ylocale = rn1(updest.hy - updest.ly + 1, updest.ly);
+                   break;
+               }
+               /* find the arrival portal */
+               for (t = ftrap; t; t = t->ntrap)
+                   if (t->ttyp == MAGIC_PORTAL) break;
+               if (t) {
+                   xlocale = t->tx,  ylocale = t->ty;
+                   break;
+               } else {
+                   impossible("mon_arrive: no corresponding portal?");
+               } /*FALLTHRU*/
+        default:
+        case MIGR_RANDOM:      xlocale = ylocale = 0;
+                   break;
+           }
+
+       if (xlocale && wander) {
+           /* monster moved a bit; pick a nearby location */
+           /* mnearto() deals w/stone, et al */
+           char *r = in_rooms(xlocale, ylocale, 0);
+           if (r && *r) {
+               coord c;
+               /* somexy() handles irregular rooms */
+               if (somexy(&rooms[*r - ROOMOFFSET], &c))
+                   xlocale = c.x,  ylocale = c.y;
+               else
+                   xlocale = ylocale = 0;
+           } else {            /* not in a room */
+               int i, j;
+               i = max(1, xlocale - wander);
+               j = min(COLNO-1, xlocale + wander);
+               xlocale = rn1(j - i, i);
+               i = max(0, ylocale - wander);
+               j = min(ROWNO-1, ylocale + wander);
+               ylocale = rn1(j - i, i);
+           }
+       }       /* moved a bit */
+
+       mtmp->mx = 0;   /*(already is 0)*/
+       mtmp->my = xyflags;
+       if (xlocale)
+           (void) mnearto(mtmp, xlocale, ylocale, FALSE);
+       else {
+           if (!rloc(mtmp,TRUE)) {
+               /*
+                * Failed to place migrating monster,
+                * probably because the level is full.
+                * Dump the monster's cargo and leave the monster dead.
+                */
+               struct obj *obj, *corpse;
+               while ((obj = mtmp->minvent) != 0) {
+                   obj_extract_self(obj);
+                   obj_no_longer_held(obj);
+                   if (obj->owornmask & W_WEP)
+                       setmnotwielded(mtmp,obj);
+                   obj->owornmask = 0L;
+                   if (xlocale && ylocale)
+                           place_object(obj, xlocale, ylocale);
+                   else {
+                       rloco(obj);
+                       get_obj_location(obj, &xlocale, &ylocale, 0);
+                   }
+               }
+               corpse = mkcorpstat(CORPSE, (struct monst *)0, mtmp->data,
+                               xlocale, ylocale, FALSE);
+#ifndef GOLDOBJ
+               if (mtmp->mgold) {
+                   if (xlocale == 0 && ylocale == 0 && corpse) {
+                       (void) get_obj_location(corpse, &xlocale, &ylocale, 0);
+                       (void) mkgold(mtmp->mgold, xlocale, ylocale);
+                   }
+                   mtmp->mgold = 0L;
+               }
+#endif
+               mongone(mtmp);
+           }
+       }
+}
+
+/* heal monster for time spent elsewhere */
+void
+mon_catchup_elapsed_time(mtmp, nmv)
+struct monst *mtmp;
+long nmv;              /* number of moves */
+{
+       int imv = 0;    /* avoid zillions of casts and lint warnings */
+
+#if defined(DEBUG) || defined(BETA)
+       if (nmv < 0L) {                 /* crash likely... */
+           panic("catchup from future time?");
+           /*NOTREACHED*/
+           return;
+       } else if (nmv == 0L) {         /* safe, but should'nt happen */
+           impossible("catchup from now?");
+       } else
+#endif
+       if (nmv >= LARGEST_INT)         /* paranoia */
+           imv = LARGEST_INT - 1;
+       else
+           imv = (int)nmv;
+
+       /* might stop being afraid, blind or frozen */
+       /* set to 1 and allow final decrement in movemon() */
+       if (mtmp->mblinded) {
+           if (imv >= (int) mtmp->mblinded) mtmp->mblinded = 1;
+           else mtmp->mblinded -= imv;
+       }
+       if (mtmp->mfrozen) {
+           if (imv >= (int) mtmp->mfrozen) mtmp->mfrozen = 1;
+           else mtmp->mfrozen -= imv;
+       }
+       if (mtmp->mfleetim) {
+           if (imv >= (int) mtmp->mfleetim) mtmp->mfleetim = 1;
+           else mtmp->mfleetim -= imv;
+       }
+
+       /* might recover from temporary trouble */
+       if (mtmp->mtrapped && rn2(imv + 1) > 40/2) mtmp->mtrapped = 0;
+       if (mtmp->mconf    && rn2(imv + 1) > 50/2) mtmp->mconf = 0;
+       if (mtmp->mstun    && rn2(imv + 1) > 10/2) mtmp->mstun = 0;
+
+       /* might finish eating or be able to use special ability again */
+       if (imv > mtmp->meating) mtmp->meating = 0;
+       else mtmp->meating -= imv;
+       if (imv > mtmp->mspec_used) mtmp->mspec_used = 0;
+       else mtmp->mspec_used -= imv;
+
+       /* reduce tameness for every 150 moves you are separated */
+       if (mtmp->mtame) {
+           int wilder = (imv + 75) / 150;
+           if (mtmp->mtame > wilder) mtmp->mtame -= wilder;    /* less tame */
+           else if (mtmp->mtame > rn2(wilder)) mtmp->mtame = 0;  /* untame */
+           else mtmp->mtame = mtmp->mpeaceful = 0;             /* hostile! */
+       }
+       /* check to see if it would have died as a pet; if so, go wild instead
+        * of dying the next time we call dog_move()
+        */
+       if (mtmp->mtame && !mtmp->isminion &&
+                       (carnivorous(mtmp->data) || herbivorous(mtmp->data))) {
+           struct edog *edog = EDOG(mtmp);
+
+           if ((monstermoves > edog->hungrytime + 500 && mtmp->mhp < 3) ||
+                   (monstermoves > edog->hungrytime + 750))
+               mtmp->mtame = mtmp->mpeaceful = 0;
+       }
+
+       if (!mtmp->mtame && mtmp->mleashed) {
+           /* leashed monsters should always be with hero, consequently
+              never losing any time to be accounted for later */
+           impossible("catching up for leashed monster?");
+           m_unleash(mtmp, FALSE);
+       }
+
+       /* recover lost hit points */
+       if (!regenerates(mtmp->data)) imv /= 20;
+       if (mtmp->mhp + imv >= mtmp->mhpmax)
+           mtmp->mhp = mtmp->mhpmax;
+       else mtmp->mhp += imv;
+}
+
+#endif /* OVLB */
+#ifdef OVL2
+
+/* called when you move to another level */
+void
+keepdogs(pets_only)
+boolean pets_only;     /* true for ascension or final escape */
+{
+       register struct monst *mtmp, *mtmp2;
+       register struct obj *obj;
+       int num_segs;
+       boolean stay_behind;
+
+       for (mtmp = fmon; mtmp; mtmp = mtmp2) {
+           mtmp2 = mtmp->nmon;
+           if (DEADMONSTER(mtmp)) continue;
+           if (pets_only && !mtmp->mtame) continue;
+           if (((monnear(mtmp, u.ux, u.uy) && levl_follower(mtmp)) ||
+#ifdef STEED
+                       (mtmp == u.usteed) ||
+#endif
+               /* the wiz will level t-port from anywhere to chase
+                  the amulet; if you don't have it, will chase you
+                  only if in range. -3. */
+                       (u.uhave.amulet && mtmp->iswiz))
+               && ((!mtmp->msleeping && mtmp->mcanmove)
+#ifdef STEED
+                   /* eg if level teleport or new trap, steed has no control
+                      to avoid following */
+                   || (mtmp == u.usteed)
+#endif
+                   )
+               /* monster won't follow if it hasn't noticed you yet */
+               && !(mtmp->mstrategy & STRAT_WAITFORU)) {
+               stay_behind = FALSE;
+               if (mtmp->mtame && mtmp->meating) {
+                       if (canseemon(mtmp))
+                           pline("%s is still eating.", Monnam(mtmp));
+                       stay_behind = TRUE;
+               } else if (mon_has_amulet(mtmp)) {
+                       if (canseemon(mtmp))
+                           pline("%s seems very disoriented for a moment.",
+                               Monnam(mtmp));
+                       stay_behind = TRUE;
+               } else if (mtmp->mtame && mtmp->mtrapped) {
+                       if (canseemon(mtmp))
+                           pline("%s is still trapped.", Monnam(mtmp));
+                       stay_behind = TRUE;
+               }
+#ifdef STEED
+               if (mtmp == u.usteed) stay_behind = FALSE;
+#endif
+               if (stay_behind) {
+                       if (mtmp->mleashed) {
+                               pline("%s leash suddenly comes loose.",
+                                       humanoid(mtmp->data)
+                                           ? (mtmp->female ? "Her" : "His")
+                                           : "Its");
+                               m_unleash(mtmp, FALSE);
+                       }
+                       continue;
+               }
+               if (mtmp->isshk)
+                       set_residency(mtmp, TRUE);
+
+               if (mtmp->wormno) {
+                   register int cnt;
+                   /* NOTE: worm is truncated to # segs = max wormno size */
+                   cnt = count_wsegs(mtmp);
+                   num_segs = min(cnt, MAX_NUM_WORMS - 1);
+                   wormgone(mtmp);
+               } else num_segs = 0;
+
+               /* set minvent's obj->no_charge to 0 */
+               for(obj = mtmp->minvent; obj; obj = obj->nobj) {
+                   if (Has_contents(obj))
+                       picked_container(obj);  /* does the right thing */
+                   obj->no_charge = 0;
+               }
+
+               relmon(mtmp);
+               newsym(mtmp->mx,mtmp->my);
+               mtmp->mx = mtmp->my = 0; /* avoid mnexto()/MON_AT() problem */
+               mtmp->wormno = num_segs;
+               mtmp->mlstmv = monstermoves;
+               mtmp->nmon = mydogs;
+               mydogs = mtmp;
+           } else if (mtmp->iswiz) {
+               /* we want to be able to find him when his next resurrection
+                  chance comes up, but have him resume his present location
+                  if player returns to this level before that time */
+               migrate_to_level(mtmp, ledger_no(&u.uz),
+                                MIGR_EXACT_XY, (coord *)0);
+           } else if (mtmp->mleashed) {
+               /* this can happen if your quest leader ejects you from the
+                  "home" level while a leashed pet isn't next to you */
+               pline("%s leash goes slack.", s_suffix(Monnam(mtmp)));
+               m_unleash(mtmp, FALSE);
+           }
+       }
+}
+
+#endif /* OVL2 */
+#ifdef OVLB
+
+void
+migrate_to_level(mtmp, tolev, xyloc, cc)
+       register struct monst *mtmp;
+       xchar tolev;    /* destination level */
+       xchar xyloc;    /* MIGR_xxx destination xy location: */
+       coord *cc;      /* optional destination coordinates */
+{
+       register struct obj *obj;
+       d_level new_lev;
+       xchar xyflags;
+       int num_segs = 0;       /* count of worm segments */
+
+       if (mtmp->isshk)
+           set_residency(mtmp, TRUE);
+
+       if (mtmp->wormno) {
+           register int cnt;
+         /* **** NOTE: worm is truncated to # segs = max wormno size **** */
+           cnt = count_wsegs(mtmp);
+           num_segs = min(cnt, MAX_NUM_WORMS - 1);
+           wormgone(mtmp);
+       }
+
+       /* set minvent's obj->no_charge to 0 */
+       for(obj = mtmp->minvent; obj; obj = obj->nobj) {
+           if (Has_contents(obj))
+               picked_container(obj);  /* does the right thing */
+           obj->no_charge = 0;
+       }
+
+       if (mtmp->mleashed) {
+               mtmp->mtame--;
+               m_unleash(mtmp, TRUE);
+       }
+       relmon(mtmp);
+       mtmp->nmon = migrating_mons;
+       migrating_mons = mtmp;
+       newsym(mtmp->mx,mtmp->my);
+
+       new_lev.dnum = ledger_to_dnum((xchar)tolev);
+       new_lev.dlevel = ledger_to_dlev((xchar)tolev);
+       /* overload mtmp->[mx,my], mtmp->[mux,muy], and mtmp->mtrack[] as */
+       /* destination codes (setup flag bits before altering mx or my) */
+       xyflags = (depth(&new_lev) < depth(&u.uz));     /* 1 => up */
+       if (In_W_tower(mtmp->mx, mtmp->my, &u.uz)) xyflags |= 2;
+       mtmp->wormno = num_segs;
+       mtmp->mlstmv = monstermoves;
+       mtmp->mtrack[1].x = cc ? cc->x : mtmp->mx;
+       mtmp->mtrack[1].y = cc ? cc->y : mtmp->my;
+       mtmp->mtrack[0].x = xyloc;
+       mtmp->mtrack[0].y = xyflags;
+       mtmp->mux = new_lev.dnum;
+       mtmp->muy = new_lev.dlevel;
+       mtmp->mx = mtmp->my = 0;        /* this implies migration */
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+/* return quality of food; the lower the better */
+/* fungi will eat even tainted food */
+int
+dogfood(mon,obj)
+struct monst *mon;
+register struct obj *obj;
+{
+       boolean carni = carnivorous(mon->data);
+       boolean herbi = herbivorous(mon->data);
+       struct permonst *fptr = &mons[obj->corpsenm];
+       boolean starving;
+
+       if (is_quest_artifact(obj) || obj_resists(obj, 0, 95))
+           return (obj->cursed ? TABU : APPORT);
+
+       switch(obj->oclass) {
+       case FOOD_CLASS:
+           if (obj->otyp == CORPSE &&
+               ((touch_petrifies(&mons[obj->corpsenm]) && !resists_ston(mon))
+                || is_rider(fptr)))
+                   return TABU;
+
+           /* Ghouls only eat old corpses... yum! */
+           if (mon->data == &mons[PM_GHOUL])
+               return (obj->otyp == CORPSE &&
+                       peek_at_iced_corpse_age(obj) + 50L <= monstermoves) ?
+                               DOGFOOD : TABU;
+
+           if (!carni && !herbi)
+                   return (obj->cursed ? UNDEF : APPORT);
+
+           /* a starving pet will eat almost anything */
+           starving = (mon->mtame && !mon->isminion &&
+                       EDOG(mon)->mhpmax_penalty);
+
+           switch (obj->otyp) {
+               case TRIPE_RATION:
+               case MEATBALL:
+               case MEAT_RING:
+               case MEAT_STICK:
+               case HUGE_CHUNK_OF_MEAT:
+                   return (carni ? DOGFOOD : MANFOOD);
+               case EGG:
+                   if (touch_petrifies(&mons[obj->corpsenm]) && !resists_ston(mon))
+                       return POISON;
+                   return (carni ? CADAVER : MANFOOD);
+               case CORPSE:
+                  if ((peek_at_iced_corpse_age(obj) + 50L <= monstermoves
+                                           && obj->corpsenm != PM_LIZARD
+                                           && obj->corpsenm != PM_LICHEN
+                                           && mon->data->mlet != S_FUNGUS) ||
+                       (acidic(&mons[obj->corpsenm]) && !resists_acid(mon)) ||
+                       (poisonous(&mons[obj->corpsenm]) &&
+                                               !resists_poison(mon)))
+                       return POISON;
+                   else if (vegan(fptr))
+                       return (herbi ? CADAVER : MANFOOD);
+                   else return (carni ? CADAVER : MANFOOD);
+               case CLOVE_OF_GARLIC:
+                   return (is_undead(mon->data) ? TABU :
+                           ((herbi || starving) ? ACCFOOD : MANFOOD));
+               case TIN:
+                   return (metallivorous(mon->data) ? ACCFOOD : MANFOOD);
+               case APPLE:
+               case CARROT:
+                   return (herbi ? DOGFOOD : starving ? ACCFOOD : MANFOOD);
+               case BANANA:
+                   return ((mon->data->mlet == S_YETI) ? DOGFOOD :
+                           ((herbi || starving) ? ACCFOOD : MANFOOD));
+               default:
+                   if (starving) return ACCFOOD;
+                   return (obj->otyp > SLIME_MOLD ?
+                           (carni ? ACCFOOD : MANFOOD) :
+                           (herbi ? ACCFOOD : MANFOOD));
+           }
+       default:
+           if (obj->otyp == AMULET_OF_STRANGULATION ||
+                       obj->otyp == RIN_SLOW_DIGESTION)
+               return TABU;
+           if (hates_silver(mon->data) &&
+               objects[obj->otyp].oc_material == SILVER)
+               return(TABU);
+           if (mon->data == &mons[PM_GELATINOUS_CUBE] && is_organic(obj))
+               return(ACCFOOD);
+           if (metallivorous(mon->data) && is_metallic(obj) && (is_rustprone(obj) || mon->data != &mons[PM_RUST_MONSTER])) {
+               /* Non-rustproofed ferrous based metals are preferred. */
+               return((is_rustprone(obj) && !obj->oerodeproof) ? DOGFOOD :
+                       ACCFOOD);
+           }
+           if(!obj->cursed && obj->oclass != BALL_CLASS &&
+                                               obj->oclass != CHAIN_CLASS)
+               return(APPORT);
+           /* fall into next case */
+       case ROCK_CLASS:
+           return(UNDEF);
+       }
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+struct monst *
+tamedog(mtmp, obj)
+register struct monst *mtmp;
+register struct obj *obj;
+{
+       register struct monst *mtmp2;
+
+       /* The Wiz, Medusa and the quest nemeses aren't even made peaceful. */
+       if (mtmp->iswiz || mtmp->data == &mons[PM_MEDUSA]
+                               || (mtmp->data->mflags3 & M3_WANTSARTI))
+               return((struct monst *)0);
+
+       /* worst case, at least it'll be peaceful. */
+       mtmp->mpeaceful = 1;
+       set_malign(mtmp);
+       if(flags.moonphase == FULL_MOON && night() && rn2(6) && obj
+                                               && mtmp->data->mlet == S_DOG)
+               return((struct monst *)0);
+
+       /* If we cannot tame it, at least it's no longer afraid. */
+       mtmp->mflee = 0;
+       mtmp->mfleetim = 0;
+
+       /* make grabber let go now, whether it becomes tame or not */
+       if (mtmp == u.ustuck) {
+           if (u.uswallow)
+               expels(mtmp, mtmp->data, TRUE);
+           else if (!(Upolyd && sticks(youmonst.data)))
+               unstuck(mtmp);
+       }
+
+       /* feeding it treats makes it tamer */
+       if (mtmp->mtame && obj) {
+           int tasty;
+
+           if (mtmp->mcanmove && !mtmp->mconf && !mtmp->meating &&
+               ((tasty = dogfood(mtmp, obj)) == DOGFOOD ||
+                (tasty <= ACCFOOD && EDOG(mtmp)->hungrytime <= monstermoves))) {
+               /* pet will "catch" and eat this thrown food */
+               if (canseemon(mtmp)) {
+                   boolean big_corpse = (obj->otyp == CORPSE &&
+                                         obj->corpsenm >= LOW_PM &&
+                               mons[obj->corpsenm].msize > mtmp->data->msize);
+                   pline("%s catches %s%s",
+                         Monnam(mtmp), the(xname(obj)),
+                         !big_corpse ? "." : ", or vice versa!");
+               } else if (cansee(mtmp->mx,mtmp->my))
+                   pline("%s.", Tobjnam(obj, "stop"));
+               /* dog_eat expects a floor object */
+               place_object(obj, mtmp->mx, mtmp->my);
+               (void) dog_eat(mtmp, obj, mtmp->mx, mtmp->my, FALSE);
+               /* eating might have killed it, but that doesn't matter here;
+                  a non-null result suppresses "miss" message for thrown
+                  food and also implies that the object has been deleted */
+               return mtmp;
+           } else
+               return (struct monst *)0;
+       }
+
+       if (mtmp->mtame || !mtmp->mcanmove ||
+           /* monsters with conflicting structures cannot be tamed */
+           mtmp->isshk || mtmp->isgd || mtmp->ispriest || mtmp->isminion ||
+           is_covetous(mtmp->data) || is_human(mtmp->data) ||
+           (is_demon(mtmp->data) && !is_demon(youmonst.data)) ||
+           (obj && dogfood(mtmp, obj) >= MANFOOD)) return (struct monst *)0;
+
+       if (mtmp->m_id == quest_status.leader_m_id)
+           return((struct monst *)0);
+
+       /* make a new monster which has the pet extension */
+       mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth);
+       *mtmp2 = *mtmp;
+       mtmp2->mxlth = sizeof(struct edog);
+       if (mtmp->mnamelth) Strcpy(NAME(mtmp2), NAME(mtmp));
+       initedog(mtmp2);
+       replmon(mtmp, mtmp2);
+       /* `mtmp' is now obsolete */
+
+       if (obj) {              /* thrown food */
+           /* defer eating until the edog extension has been set up */
+           place_object(obj, mtmp2->mx, mtmp2->my);    /* put on floor */
+           /* devour the food (might grow into larger, genocided monster) */
+           if (dog_eat(mtmp2, obj, mtmp2->mx, mtmp2->my, TRUE) == 2)
+               return mtmp2;           /* oops, it died... */
+           /* `obj' is now obsolete */
+       }
+
+       newsym(mtmp2->mx, mtmp2->my);
+       if (attacktype(mtmp2->data, AT_WEAP)) {
+               mtmp2->weapon_check = NEED_HTH_WEAPON;
+               (void) mon_wield_item(mtmp2);
+       }
+       return(mtmp2);
+}
+
+/*
+ * Called during pet revival or pet life-saving.
+ * If you killed the pet, it revives wild.
+ * If you abused the pet a lot while alive, it revives wild.
+ * If you abused the pet at all while alive, it revives untame.
+ * If the pet wasn't abused and was very tame, it might revive tame.
+ */
+void
+wary_dog(mtmp, was_dead)
+struct monst *mtmp;
+boolean was_dead;
+{
+    struct edog *edog;
+    boolean quietly = was_dead;
+
+    mtmp->meating = 0;
+    if (!mtmp->mtame) return;
+    edog = !mtmp->isminion ? EDOG(mtmp) : 0;
+
+    /* if monster was starving when it died, undo that now */
+    if (edog && edog->mhpmax_penalty) {
+       mtmp->mhpmax += edog->mhpmax_penalty;
+       mtmp->mhp += edog->mhpmax_penalty;      /* heal it */
+       edog->mhpmax_penalty = 0;
+    }
+
+    if (edog && (edog->killed_by_u == 1 || edog->abuse > 2)) {
+       mtmp->mpeaceful = mtmp->mtame = 0;
+       if (edog->abuse >= 0 && edog->abuse < 10)
+           if (!rn2(edog->abuse + 1)) mtmp->mpeaceful = 1;
+       if(!quietly && cansee(mtmp->mx, mtmp->my)) {
+           if (haseyes(youmonst.data)) {
+               if (haseyes(mtmp->data))
+                       pline("%s %s to look you in the %s.",
+                               Monnam(mtmp),
+                               mtmp->mpeaceful ? "seems unable" :
+                                           "refuses",
+                               body_part(EYE));
+               else 
+                       pline("%s avoids your gaze.",
+                               Monnam(mtmp));
+           }
+       }
+    } else {
+       /* chance it goes wild anyway - Pet Semetary */
+       if (!rn2(mtmp->mtame)) {
+           mtmp->mpeaceful = mtmp->mtame = 0;
+       }
+    }
+    if (!mtmp->mtame) {
+       newsym(mtmp->mx, mtmp->my);
+       /* a life-saved monster might be leashed;
+          don't leave it that way if it's no longer tame */
+       if (mtmp->mleashed) m_unleash(mtmp, TRUE);
+    }
+
+    /* if its still a pet, start a clean pet-slate now */
+    if (edog && mtmp->mtame) {
+       edog->revivals++;
+       edog->killed_by_u = 0;
+       edog->abuse = 0;
+       edog->ogoal.x = edog->ogoal.y = -1;
+       if (was_dead || edog->hungrytime < monstermoves + 500L)
+           edog->hungrytime = monstermoves + 500L;
+       if (was_dead) {
+           edog->droptime = 0L;
+           edog->dropdist = 10000;
+           edog->whistletime = 0L;
+           edog->apport = 5;
+       } /* else lifesaved, so retain current values */
+    }
+}
+
+void
+abuse_dog(mtmp)
+struct monst *mtmp;
+{
+       if (!mtmp->mtame) return;
+
+       if (Aggravate_monster || Conflict) mtmp->mtame /=2;
+       else mtmp->mtame--;
+
+       if (mtmp->mtame && !mtmp->isminion)
+           EDOG(mtmp)->abuse++;
+
+       if (!mtmp->mtame && mtmp->mleashed)
+           m_unleash(mtmp, TRUE);
+
+       /* don't make a sound if pet is in the middle of leaving the level */
+       /* newsym isn't necessary in this case either */
+       if (mtmp->mx != 0) {
+           if (mtmp->mtame && rn2(mtmp->mtame)) yelp(mtmp);
+           else growl(mtmp);   /* give them a moment's worry */
+       
+           if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my);
+       }
+}
+
+#endif /* OVLB */
+
+/*dog.c*/
diff --git a/src/dogmove.c b/src/dogmove.c
new file mode 100644 (file)
index 0000000..f2e00c1
--- /dev/null
@@ -0,0 +1,867 @@
+/*     SCCS Id: @(#)dogmove.c  3.4     2002/09/10      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+#include "mfndpos.h"
+#include "edog.h"
+
+extern boolean notonhead;
+
+#ifdef OVL0
+
+STATIC_DCL boolean FDECL(dog_hunger,(struct monst *,struct edog *));
+STATIC_DCL int FDECL(dog_invent,(struct monst *,struct edog *,int));
+STATIC_DCL int FDECL(dog_goal,(struct monst *,struct edog *,int,int,int));
+
+STATIC_DCL struct obj *FDECL(DROPPABLES, (struct monst *));
+STATIC_DCL boolean FDECL(can_reach_location,(struct monst *,XCHAR_P,XCHAR_P,
+    XCHAR_P,XCHAR_P));
+STATIC_DCL boolean FDECL(could_reach_item,(struct monst *, XCHAR_P,XCHAR_P));
+
+STATIC_OVL struct obj *
+DROPPABLES(mon)
+register struct monst *mon;
+{
+       register struct obj *obj;
+       struct obj *wep = MON_WEP(mon);
+       boolean item1 = FALSE, item2 = FALSE;
+
+       if (is_animal(mon->data) || mindless(mon->data))
+               item1 = item2 = TRUE;
+       if (!tunnels(mon->data) || !needspick(mon->data))
+               item1 = TRUE;
+       for(obj = mon->minvent; obj; obj = obj->nobj) {
+               if (!item1 && is_pick(obj) && (obj->otyp != DWARVISH_MATTOCK
+                                               || !which_armor(mon, W_ARMS))) {
+                       item1 = TRUE;
+                       continue;
+               }
+               if (!item2 && obj->otyp == UNICORN_HORN && !obj->cursed) {
+                       item2 = TRUE;
+                       continue;
+               }
+               if (!obj->owornmask && obj != wep) return obj;
+       }
+       return (struct obj *)0;
+}
+
+static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS, 0 };
+
+#endif /* OVL0 */
+
+STATIC_OVL boolean FDECL(cursed_object_at, (int, int));
+
+STATIC_VAR xchar gtyp, gx, gy; /* type and position of dog's current goal */
+
+STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t));
+
+#ifdef OVLB
+STATIC_OVL boolean
+cursed_object_at(x, y)
+int x, y;
+{
+       struct obj *otmp;
+
+       for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
+               if (otmp->cursed) return TRUE;
+       return FALSE;
+}
+
+int
+dog_nutrition(mtmp, obj)
+struct monst *mtmp;
+struct obj *obj;
+{
+       int nutrit;
+
+       /*
+        * It is arbitrary that the pet takes the same length of time to eat
+        * as a human, but gets more nutritional value.
+        */
+       if (obj->oclass == FOOD_CLASS) {
+           if(obj->otyp == CORPSE) {
+               mtmp->meating = 3 + (mons[obj->corpsenm].cwt >> 6);
+               nutrit = mons[obj->corpsenm].cnutrit;
+           } else {
+               mtmp->meating = objects[obj->otyp].oc_delay;
+               nutrit = objects[obj->otyp].oc_nutrition;
+           }
+           switch(mtmp->data->msize) {
+               case MZ_TINY: nutrit *= 8; break;
+               case MZ_SMALL: nutrit *= 6; break;
+               default:
+               case MZ_MEDIUM: nutrit *= 5; break;
+               case MZ_LARGE: nutrit *= 4; break;
+               case MZ_HUGE: nutrit *= 3; break;
+               case MZ_GIGANTIC: nutrit *= 2; break;
+           }
+           if(obj->oeaten) {
+               mtmp->meating = eaten_stat(mtmp->meating, obj);
+               nutrit = eaten_stat(nutrit, obj);
+           }
+       } else if (obj->oclass == COIN_CLASS) {
+           mtmp->meating = (int)(obj->quan/2000) + 1;
+           if (mtmp->meating < 0) mtmp->meating = 1;
+           nutrit = (int)(obj->quan/20);
+           if (nutrit < 0) nutrit = 0;
+       } else {
+           /* Unusual pet such as gelatinous cube eating odd stuff.
+            * meating made consistent with wild monsters in mon.c.
+            * nutrit made consistent with polymorphed player nutrit in
+            * eat.c.  (This also applies to pets eating gold.)
+            */
+           mtmp->meating = obj->owt/20 + 1;
+           nutrit = 5*objects[obj->otyp].oc_nutrition;
+       }
+       return nutrit;
+}
+
+/* returns 2 if pet dies, otherwise 1 */
+int
+dog_eat(mtmp, obj, x, y, devour)
+register struct monst *mtmp;
+register struct obj * obj;
+int x, y;
+boolean devour;
+{
+       register struct edog *edog = EDOG(mtmp);
+       boolean poly = FALSE, grow = FALSE, heal = FALSE;
+       int nutrit;
+
+       if(edog->hungrytime < monstermoves)
+           edog->hungrytime = monstermoves;
+       nutrit = dog_nutrition(mtmp, obj);
+       poly = polyfodder(obj);
+       grow = mlevelgain(obj);
+       heal = mhealup(obj);
+       if (devour) {
+           if (mtmp->meating > 1) mtmp->meating /= 2;
+           if (nutrit > 1) nutrit = (nutrit * 3) / 4;
+       }
+       edog->hungrytime += nutrit;
+       mtmp->mconf = 0;
+       if (edog->mhpmax_penalty) {
+           /* no longer starving */
+           mtmp->mhpmax += edog->mhpmax_penalty;
+           edog->mhpmax_penalty = 0;
+       }
+       if (mtmp->mflee && mtmp->mfleetim > 1) mtmp->mfleetim /= 2;
+       if (mtmp->mtame < 20) mtmp->mtame++;
+       if (x != mtmp->mx || y != mtmp->my) {   /* moved & ate on same turn */
+           newsym(x, y);
+           newsym(mtmp->mx, mtmp->my);
+       }
+       if (is_pool(x, y) && !Underwater) {
+           /* Don't print obj */
+           /* TODO: Reveal presence of sea monster (especially sharks) */
+       } else
+       /* hack: observe the action if either new or old location is in view */
+       /* However, invisible monsters should still be "it" even though out of
+          sight locations should not. */
+       if (cansee(x, y) || cansee(mtmp->mx, mtmp->my))
+           pline("%s %s %s.", mon_visible(mtmp) ? noit_Monnam(mtmp) : "It",
+                 devour ? "devours" : "eats",
+                 (obj->oclass == FOOD_CLASS) ?
+                       singular(obj, doname) : doname(obj));
+       /* It's a reward if it's DOGFOOD and the player dropped/threw it. */
+       /* We know the player had it if invlet is set -dlc */
+       if(dogfood(mtmp,obj) == DOGFOOD && obj->invlet)
+#ifdef LINT
+           edog->apport = 0;
+#else
+           edog->apport += (int)(200L/
+               ((long)edog->dropdist + monstermoves - edog->droptime));
+#endif
+       if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) {
+           /* The object's rustproofing is gone now */
+           obj->oerodeproof = 0;
+           mtmp->mstun = 1;
+           if (canseemon(mtmp) && flags.verbose) {
+               pline("%s spits %s out in disgust!",
+                     Monnam(mtmp), distant_name(obj,doname));
+           }
+       } else if (obj == uball) {
+           unpunish();
+           delobj(obj);
+       } else if (obj == uchain)
+           unpunish();
+       else if (obj->quan > 1L && obj->oclass == FOOD_CLASS) {
+           obj->quan--;
+           obj->owt = weight(obj);
+       } else
+           delobj(obj);
+
+       if (poly) {
+           (void) newcham(mtmp, (struct permonst *)0, FALSE,
+                          cansee(mtmp->mx, mtmp->my));
+       }
+       /* limit "instant" growth to prevent potential abuse */
+       if (grow && (int) mtmp->m_lev < (int)mtmp->data->mlevel + 15) {
+           if (!grow_up(mtmp, (struct monst *)0)) return 2;
+       }
+       if (heal) mtmp->mhp = mtmp->mhpmax;
+       return 1;
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+/* hunger effects -- returns TRUE on starvation */
+STATIC_OVL boolean
+dog_hunger(mtmp, edog)
+register struct monst *mtmp;
+register struct edog *edog;
+{
+       if (monstermoves > edog->hungrytime + 500) {
+           if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) {
+               edog->hungrytime = monstermoves + 500;
+               /* but not too high; it might polymorph */
+           } else if (!edog->mhpmax_penalty) {
+               /* starving pets are limited in healing */
+               int newmhpmax = mtmp->mhpmax / 3;
+               mtmp->mconf = 1;
+               edog->mhpmax_penalty = mtmp->mhpmax - newmhpmax;
+               mtmp->mhpmax = newmhpmax;
+               if (mtmp->mhp > mtmp->mhpmax)
+                   mtmp->mhp = mtmp->mhpmax;
+               if (mtmp->mhp < 1) goto dog_died;
+               if (cansee(mtmp->mx, mtmp->my))
+                   pline("%s is confused from hunger.", Monnam(mtmp));
+               else if (couldsee(mtmp->mx, mtmp->my))
+                   beg(mtmp);
+               else
+                   You_feel("worried about %s.", y_monnam(mtmp));
+               stop_occupation();
+           } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) {
+ dog_died:
+               if (mtmp->mleashed
+#ifdef STEED
+                   && mtmp != u.usteed
+#endif
+                   )
+                   Your("leash goes slack.");
+               else if (cansee(mtmp->mx, mtmp->my))
+                   pline("%s starves.", Monnam(mtmp));
+               else
+                   You_feel("%s for a moment.",
+                       Hallucination ? "bummed" : "sad");
+               mondied(mtmp);
+               return(TRUE);
+           }
+       }
+       return(FALSE);
+}
+
+/* do something with object (drop, pick up, eat) at current position
+ * returns 1 if object eaten (since that counts as dog's move), 2 if died
+ */
+STATIC_OVL int
+dog_invent(mtmp, edog, udist)
+register struct monst *mtmp;
+register struct edog *edog;
+int udist;
+{
+       register int omx, omy;
+       struct obj *obj;
+
+       if (mtmp->msleeping || !mtmp->mcanmove) return(0);
+
+       omx = mtmp->mx;
+       omy = mtmp->my;
+
+       /* if we are carrying sth then we drop it (perhaps near @) */
+       /* Note: if apport == 1 then our behaviour is independent of udist */
+       /* Use udist+1 so steed won't cause divide by zero */
+#ifndef GOLDOBJ
+       if(DROPPABLES(mtmp) || mtmp->mgold) {
+#else
+       if(DROPPABLES(mtmp)) {
+#endif
+           if (!rn2(udist+1) || !rn2(edog->apport))
+               if(rn2(10) < edog->apport){
+                   relobj(mtmp, (int)mtmp->minvis, TRUE);
+                   if(edog->apport > 1) edog->apport--;
+                   edog->dropdist = udist;             /* hpscdi!jon */
+                   edog->droptime = monstermoves;
+               }
+       } else {
+           if((obj=level.objects[omx][omy]) && !index(nofetch,obj->oclass)
+#ifdef MAIL
+                       && obj->otyp != SCR_MAIL
+#endif
+                                                                       ){
+               int edible = dogfood(mtmp, obj);
+
+               if ((edible <= CADAVER ||
+                       /* starving pet is more aggressive about eating */
+                       (edog->mhpmax_penalty && edible == ACCFOOD)) &&
+                   could_reach_item(mtmp, obj->ox, obj->oy))
+                   return dog_eat(mtmp, obj, omx, omy, FALSE);
+
+               if(can_carry(mtmp, obj) && !obj->cursed &&
+                       could_reach_item(mtmp, obj->ox, obj->oy)) {
+                   if(rn2(20) < edog->apport+3) {
+                       if (rn2(udist) || !rn2(edog->apport)) {
+                           if (cansee(omx, omy) && flags.verbose)
+                               pline("%s picks up %s.", Monnam(mtmp),
+                                   distant_name(obj, doname));
+                           obj_extract_self(obj);
+                           newsym(omx,omy);
+                           (void) mpickobj(mtmp,obj);
+                           if (attacktype(mtmp->data, AT_WEAP) &&
+                                       mtmp->weapon_check == NEED_WEAPON) {
+                               mtmp->weapon_check = NEED_HTH_WEAPON;
+                               (void) mon_wield_item(mtmp);
+                           }
+                           m_dowear(mtmp, FALSE);
+                       }
+                   }
+               }
+           }
+       }
+       return 0;
+}
+
+/* set dog's goal -- gtyp, gx, gy
+ * returns -1/0/1 (dog's desire to approach player) or -2 (abort move)
+ */
+STATIC_OVL int
+dog_goal(mtmp, edog, after, udist, whappr)
+register struct monst *mtmp;
+struct edog *edog;
+int after, udist, whappr;
+{
+       register int omx, omy;
+       boolean in_masters_sight, dog_has_minvent;
+       register struct obj *obj;
+       xchar otyp;
+       int appr;
+
+#ifdef STEED
+       /* Steeds don't move on their own will */
+       if (mtmp == u.usteed)
+               return (-2);
+#endif
+
+       omx = mtmp->mx;
+       omy = mtmp->my;
+
+       in_masters_sight = couldsee(omx, omy);
+       dog_has_minvent = (DROPPABLES(mtmp) != 0);
+
+       if (!edog || mtmp->mleashed) {  /* he's not going anywhere... */
+           gtyp = APPORT;
+           gx = u.ux;
+           gy = u.uy;
+       } else {
+#define DDIST(x,y) (dist2(x,y,omx,omy))
+#define SQSRCHRADIUS 5
+           int min_x, max_x, min_y, max_y;
+           register int nx, ny;
+
+           gtyp = UNDEF;       /* no goal as yet */
+           gx = gy = 0;        /* suppress 'used before set' message */
+
+           if ((min_x = omx - SQSRCHRADIUS) < 1) min_x = 1;
+           if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1;
+           if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0;
+           if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1;
+
+           /* nearby food is the first choice, then other objects */
+           for (obj = fobj; obj; obj = obj->nobj) {
+               nx = obj->ox;
+               ny = obj->oy;
+               if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) {
+                   otyp = dogfood(mtmp, obj);
+                   /* skip inferior goals */
+                   if (otyp > gtyp || otyp == UNDEF)
+                       continue;
+                   /* avoid cursed items unless starving */
+                   if (cursed_object_at(nx, ny) &&
+                           !(edog->mhpmax_penalty && otyp < MANFOOD))
+                       continue;
+                   /* skip completely unreacheable goals */
+                   if (!could_reach_item(mtmp, nx, ny) ||
+                       !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny))
+                       continue;
+                   if (otyp < MANFOOD) {
+                       if (otyp < gtyp || DDIST(nx,ny) < DDIST(gx,gy)) {
+                           gx = nx;
+                           gy = ny;
+                           gtyp = otyp;
+                       }
+                   } else if(gtyp == UNDEF && in_masters_sight &&
+                             !dog_has_minvent &&
+                             (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) &&
+                             (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) &&
+                             edog->apport > rn2(8) &&
+                             can_carry(mtmp,obj)) {
+                       gx = nx;
+                       gy = ny;
+                       gtyp = APPORT;
+                   }
+               }
+           }
+       }
+
+       /* follow player if appropriate */
+       if (gtyp == UNDEF ||
+           (gtyp != DOGFOOD && gtyp != APPORT && monstermoves < edog->hungrytime)) {
+               gx = u.ux;
+               gy = u.uy;
+               if (after && udist <= 4 && gx == u.ux && gy == u.uy)
+                       return(-2);
+               appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
+               if (udist > 1) {
+                       if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
+                          whappr ||
+                          (dog_has_minvent && rn2(edog->apport)))
+                               appr = 1;
+               }
+               /* if you have dog food it'll follow you more closely */
+               if (appr == 0) {
+                       obj = invent;
+                       while (obj) {
+                               if(dogfood(mtmp, obj) == DOGFOOD) {
+                                       appr = 1;
+                                       break;
+                               }
+                               obj = obj->nobj;
+                       }
+               }
+       } else
+           appr = 1;   /* gtyp != UNDEF */
+       if(mtmp->mconf)
+           appr = 0;
+
+#define FARAWAY (COLNO + 2)            /* position outside screen */
+       if (gx == u.ux && gy == u.uy && !in_masters_sight) {
+           register coord *cp;
+
+           cp = gettrack(omx,omy);
+           if (cp) {
+               gx = cp->x;
+               gy = cp->y;
+               if(edog) edog->ogoal.x = 0;
+           } else {
+               /* assume master hasn't moved far, and reuse previous goal */
+               if(edog && edog->ogoal.x &&
+                  ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) {
+                   gx = edog->ogoal.x;
+                   gy = edog->ogoal.y;
+                   edog->ogoal.x = 0;
+               } else {
+                   int fardist = FARAWAY * FARAWAY;
+                   gx = gy = FARAWAY; /* random */
+                   do_clear_area(omx, omy, 9, wantdoor,
+                                 (genericptr_t)&fardist);
+
+                   /* here gx == FARAWAY e.g. when dog is in a vault */
+                   if (gx == FARAWAY || (gx == omx && gy == omy)) {
+                       gx = u.ux;
+                       gy = u.uy;
+                   } else if(edog) {
+                       edog->ogoal.x = gx;
+                       edog->ogoal.y = gy;
+                   }
+               }
+           }
+       } else if(edog) {
+           edog->ogoal.x = 0;
+       }
+       return appr;
+}
+
+/* return 0 (no move), 1 (move) or 2 (dead) */
+int
+dog_move(mtmp, after)
+register struct monst *mtmp;
+register int after;    /* this is extra fast monster movement */
+{
+       int omx, omy;           /* original mtmp position */
+       int appr, whappr, udist;
+       int i, j, k;
+       register struct edog *edog = EDOG(mtmp);
+       struct obj *obj = (struct obj *) 0;
+       xchar otyp;
+       boolean has_edog, cursemsg[9], do_eat = FALSE;
+       xchar nix, niy;         /* position mtmp is (considering) moving to */
+       register int nx, ny;    /* temporary coordinates */
+       xchar cnt, uncursedcnt, chcnt;
+       int chi = -1, nidist, ndist;
+       coord poss[9];
+       long info[9], allowflags;
+#define GDIST(x,y) (dist2(x,y,gx,gy))
+
+       /*
+        * Tame Angels have isminion set and an ispriest structure instead of
+        * an edog structure.  Fortunately, guardian Angels need not worry
+        * about mundane things like eating and fetching objects, and can
+        * spend all their energy defending the player.  (They are the only
+        * monsters with other structures that can be tame.)
+        */
+       has_edog = !mtmp->isminion;
+
+       omx = mtmp->mx;
+       omy = mtmp->my;
+       if (has_edog && dog_hunger(mtmp, edog)) return(2);      /* starved */
+
+       udist = distu(omx,omy);
+#ifdef STEED
+       /* Let steeds eat and maybe throw rider during Conflict */
+       if (mtmp == u.usteed) {
+           if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
+               dismount_steed(DISMOUNT_THROWN);
+               return (1);
+           }
+           udist = 1;
+       } else
+#endif
+       /* maybe we tamed him while being swallowed --jgm */
+       if (!udist) return(0);
+
+       nix = omx;      /* set before newdogpos */
+       niy = omy;
+       cursemsg[0] = FALSE;    /* lint suppression */
+       info[0] = 0;            /* ditto */
+
+       if (has_edog) {
+           j = dog_invent(mtmp, edog, udist);
+           if (j == 2) return 2;               /* died */
+           else if (j == 1) goto newdogpos;    /* eating something */
+
+           whappr = (monstermoves - edog->whistletime < 5);
+       } else
+           whappr = 0;
+
+       appr = dog_goal(mtmp, has_edog ? edog : (struct edog *)0,
+                                                       after, udist, whappr);
+       if (appr == -2) return(0);
+
+       allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT;
+       if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK | ALLOW_WALL);
+       if (passes_bars(mtmp->data)) allowflags |= ALLOW_BARS;
+       if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK;
+       if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
+           allowflags |= ALLOW_U;
+           if (!has_edog) {
+               coord mm;
+               /* Guardian angel refuses to be conflicted; rather,
+                * it disappears, angrily, and sends in some nasties
+                */
+               if (canspotmon(mtmp)) {
+                   pline("%s rebukes you, saying:", Monnam(mtmp));
+                   verbalize("Since you desire conflict, have some more!");
+               }
+               mongone(mtmp);
+               i = rnd(4);
+               while(i--) {
+                   mm.x = u.ux;
+                   mm.y = u.uy;
+                   if(enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]))
+                       (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,
+                                        mm.x, mm.y, FALSE);
+               }
+               return(2);
+
+           }
+       }
+       if (!Conflict && !mtmp->mconf &&
+           mtmp == u.ustuck && !sticks(youmonst.data)) {
+           unstuck(mtmp);      /* swallowed case handled above */
+           You("get released!");
+       }
+       if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
+               allowflags |= OPENDOOR;
+               if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR;
+       }
+       if (is_giant(mtmp->data)) allowflags |= BUSTDOOR;
+       if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG;
+       cnt = mfndpos(mtmp, poss, info, allowflags);
+
+       /* Normally dogs don't step on cursed items, but if they have no
+        * other choice they will.  This requires checking ahead of time
+        * to see how many uncursed item squares are around.
+        */
+       uncursedcnt = 0;
+       for (i = 0; i < cnt; i++) {
+               nx = poss[i].x; ny = poss[i].y;
+               if (MON_AT(nx,ny) && !(info[i] & ALLOW_M)) continue;
+               if (cursed_object_at(nx, ny)) continue;
+               uncursedcnt++;
+       }
+
+       chcnt = 0;
+       chi = -1;
+       nidist = GDIST(nix,niy);
+
+       for (i = 0; i < cnt; i++) {
+               nx = poss[i].x;
+               ny = poss[i].y;
+               cursemsg[i] = FALSE;
+
+               /* if leashed, we drag him along. */
+               if (mtmp->mleashed && distu(nx, ny) > 4) continue;
+
+               /* if a guardian, try to stay close by choice */
+               if (!has_edog &&
+                   (j = distu(nx, ny)) > 16 && j >= udist) continue;
+
+               if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) {
+                   int mstatus;
+                   register struct monst *mtmp2 = m_at(nx,ny);
+
+                   if ((int)mtmp2->m_lev >= (int)mtmp->m_lev+2 ||
+                       (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) &&
+                        mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee
+                        && (perceives(mtmp->data) || !mtmp2->minvis)) ||
+                       (mtmp2->data==&mons[PM_GELATINOUS_CUBE] && rn2(10)) ||
+                       (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) ||
+                       ((mtmp->mhp*4 < mtmp->mhpmax
+                         || mtmp2->data->msound == MS_GUARDIAN
+                         || mtmp2->data->msound == MS_LEADER) &&
+                        mtmp2->mpeaceful && !Conflict) ||
+                          (touch_petrifies(mtmp2->data) &&
+                               !resists_ston(mtmp)))
+                       continue;
+
+                   if (after) return(0); /* hit only once each move */
+
+                   notonhead = 0;
+                   mstatus = mattackm(mtmp, mtmp2);
+
+                   /* aggressor (pet) died */
+                   if (mstatus & MM_AGR_DIED) return 2;
+
+                   if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) &&
+                           rn2(4) && mtmp2->mlstmv != monstermoves &&
+                           !onscary(mtmp->mx, mtmp->my, mtmp2) &&
+                           /* monnear check needed: long worms hit on tail */
+                           monnear(mtmp2, mtmp->mx, mtmp->my)) {
+                       mstatus = mattackm(mtmp2, mtmp);  /* return attack */
+                       if (mstatus & MM_DEF_DIED) return 2;
+                   }
+
+                   return 0;
+               }
+
+               {   /* Dog avoids harmful traps, but perhaps it has to pass one
+                    * in order to follow player.  (Non-harmful traps do not
+                    * have ALLOW_TRAPS in info[].)  The dog only avoids the
+                    * trap if you've seen it, unlike enemies who avoid traps
+                    * if they've seen some trap of that type sometime in the
+                    * past.  (Neither behavior is really realistic.)
+                    */
+                   struct trap *trap;
+
+                   if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))) {
+                       if (mtmp->mleashed) {
+                           if (flags.soundok) whimper(mtmp);
+                       } else
+                           /* 1/40 chance of stepping on it anyway, in case
+                            * it has to pass one to follow the player...
+                            */
+                           if (trap->tseen && rn2(40)) continue;
+                   }
+               }
+
+               /* dog eschews cursed objects, but likes dog food */
+               /* (minion isn't interested; `cursemsg' stays FALSE) */
+               if (has_edog)
+               for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) {
+                   if (obj->cursed) cursemsg[i] = TRUE;
+                   else if ((otyp = dogfood(mtmp, obj)) < MANFOOD &&
+                            (otyp < ACCFOOD || edog->hungrytime <= monstermoves)) {
+                       /* Note: our dog likes the food so much that he
+                        * might eat it even when it conceals a cursed object */
+                       nix = nx;
+                       niy = ny;
+                       chi = i;
+                       do_eat = TRUE;
+                       cursemsg[i] = FALSE;    /* not reluctant */
+                       goto newdogpos;
+                   }
+               }
+               /* didn't find something to eat; if we saw a cursed item and
+                  aren't being forced to walk on it, usually keep looking */
+               if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0 &&
+                   rn2(13 * uncursedcnt)) continue;
+
+               /* lessen the chance of backtracking to previous position(s) */
+               k = has_edog ? uncursedcnt : cnt;
+               for (j = 0; j < MTSZ && j < k - 1; j++)
+                       if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
+                               if (rn2(MTSZ * (k - j))) goto nxti;
+
+               j = ((ndist = GDIST(nx,ny)) - nidist) * appr;
+               if ((j == 0 && !rn2(++chcnt)) || j < 0 ||
+                       (j > 0 && !whappr &&
+                               ((omx == nix && omy == niy && !rn2(3))
+                                       || !rn2(12))
+                       )) {
+                       nix = nx;
+                       niy = ny;
+                       nidist = ndist;
+                       if(j < 0) chcnt = 0;
+                       chi = i;
+               }
+       nxti:   ;
+       }
+newdogpos:
+       if (nix != omx || niy != omy) {
+               struct obj *mw_tmp;
+
+               if (info[chi] & ALLOW_U) {
+                       if (mtmp->mleashed) { /* play it safe */
+                               pline("%s breaks loose of %s leash!",
+                                     Monnam(mtmp), mhis(mtmp));
+                               m_unleash(mtmp, FALSE);
+                       }
+                       (void) mattacku(mtmp);
+                       return(0);
+               }
+               if (!m_in_out_region(mtmp, nix, niy))
+                   return 1;
+               if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) ||
+                    closed_door(nix, niy)) &&
+                   mtmp->weapon_check != NO_WEAPON_WANTED &&
+                   tunnels(mtmp->data) && needspick(mtmp->data)) {
+                   if (closed_door(nix, niy)) {
+                       if (!(mw_tmp = MON_WEP(mtmp)) ||
+                           !is_pick(mw_tmp) || !is_axe(mw_tmp))
+                           mtmp->weapon_check = NEED_PICK_OR_AXE;
+                   } else if (IS_TREE(levl[nix][niy].typ)) {
+                       if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp))
+                           mtmp->weapon_check = NEED_AXE;
+                   } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) {
+                       mtmp->weapon_check = NEED_PICK_AXE;
+                   }
+                   if (mtmp->weapon_check >= NEED_PICK_AXE &&
+                       mon_wield_item(mtmp))
+                       return 0;
+               }
+               /* insert a worm_move() if worms ever begin to eat things */
+               remove_monster(omx, omy);
+               place_monster(mtmp, nix, niy);
+               if (cursemsg[chi] && (cansee(omx,omy) || cansee(nix,niy)))
+                       pline("%s moves only reluctantly.", Monnam(mtmp));
+               for (j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
+               mtmp->mtrack[0].x = omx;
+               mtmp->mtrack[0].y = omy;
+               /* We have to know if the pet's gonna do a combined eat and
+                * move before moving it, but it can't eat until after being
+                * moved.  Thus the do_eat flag.
+                */
+               if (do_eat) {
+                   if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2) return 2;
+               }
+       } else if (mtmp->mleashed && distu(omx, omy) > 4) {
+               /* an incredible kludge, but the only way to keep pooch near
+                * after it spends time eating or in a trap, etc.
+                */
+               coord cc;
+
+               nx = sgn(omx - u.ux);
+               ny = sgn(omy - u.uy);
+               cc.x = u.ux + nx;
+               cc.y = u.uy + ny;
+               if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
+
+               i  = xytod(nx, ny);
+               for (j = (i + 7)%8; j < (i + 1)%8; j++) {
+                       dtoxy(&cc, j);
+                       if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
+               }
+               for (j = (i + 6)%8; j < (i + 2)%8; j++) {
+                       dtoxy(&cc, j);
+                       if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
+               }
+               cc.x = mtmp->mx;
+               cc.y = mtmp->my;
+dognext:
+               if (!m_in_out_region(mtmp, nix, niy))
+                 return 1;
+               remove_monster(mtmp->mx, mtmp->my);
+               place_monster(mtmp, cc.x, cc.y);
+               newsym(cc.x,cc.y);
+               set_apparxy(mtmp);
+       }
+       return(1);
+}
+
+/* check if a monster could pick up objects from a location */
+STATIC_OVL boolean
+could_reach_item(mon, nx, ny)
+struct monst *mon;
+xchar nx, ny;
+{
+    if ((!is_pool(nx,ny) || is_swimmer(mon->data)) &&
+       (!is_lava(nx,ny) || likes_lava(mon->data)) &&
+       (!sobj_at(BOULDER,nx,ny) || throws_rocks(mon->data)))
+       return TRUE;
+    return FALSE;
+}
+
+/* Hack to prevent a dog from being endlessly stuck near an object that
+ * it can't reach, such as caught in a teleport scroll niche.  It recursively
+ * checks to see if the squares in between are good.  The checking could be a
+ * little smarter; a full check would probably be useful in m_move() too.
+ * Since the maximum food distance is 5, this should never be more than 5 calls
+ * deep.
+ */
+STATIC_OVL boolean
+can_reach_location(mon, mx, my, fx, fy)
+struct monst *mon;
+xchar mx, my, fx, fy;
+{
+    int i, j;
+    int dist;
+
+    if (mx == fx && my == fy) return TRUE;
+    if (!isok(mx, my)) return FALSE; /* should not happen */
+    
+    dist = dist2(mx, my, fx, fy);
+    for(i=mx-1; i<=mx+1; i++) {
+       for(j=my-1; j<=my+1; j++) {
+           if (!isok(i, j))
+               continue;
+           if (dist2(i, j, fx, fy) >= dist)
+               continue;
+           if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data) &&
+                                   (!may_dig(i,j) || !tunnels(mon->data)))
+               continue;
+           if (IS_DOOR(levl[i][j].typ) &&
+                               (levl[i][j].doormask & (D_CLOSED | D_LOCKED)))
+               continue;
+           if (!could_reach_item(mon, i, j))
+               continue;
+           if (can_reach_location(mon, i, j, fx, fy))
+               return TRUE;
+       }
+    }
+    return FALSE;
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+/*ARGSUSED*/   /* do_clear_area client */
+STATIC_PTR void
+wantdoor(x, y, distance)
+int x, y;
+genericptr_t distance;
+{
+    int ndist;
+
+    if (*(int*)distance > (ndist = distu(x, y))) {
+       gx = x;
+       gy = y;
+       *(int*)distance = ndist;
+    }
+}
+
+#endif /* OVLB */
+
+/*dogmove.c*/
diff --git a/src/dokick.c b/src/dokick.c
new file mode 100644 (file)
index 0000000..f390414
--- /dev/null
@@ -0,0 +1,1491 @@
+/*     SCCS Id: @(#)dokick.c   3.4     2003/12/04      */
+/* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "eshk.h"
+
+#define is_bigfoot(x)  ((x) == &mons[PM_SASQUATCH])
+#define martial()      (martial_bonus() || is_bigfoot(youmonst.data) || \
+               (uarmf && uarmf->otyp == KICKING_BOOTS))
+
+static NEARDATA struct rm *maploc;
+static NEARDATA const char *gate_str;
+
+extern boolean notonhead;      /* for long worms */
+
+STATIC_DCL void FDECL(kickdmg, (struct monst *, BOOLEAN_P));
+STATIC_DCL void FDECL(kick_monster, (XCHAR_P, XCHAR_P));
+STATIC_DCL int FDECL(kick_object, (XCHAR_P, XCHAR_P));
+STATIC_DCL char *FDECL(kickstr, (char *));
+STATIC_DCL void FDECL(otransit_msg, (struct obj *, BOOLEAN_P, long));
+STATIC_DCL void FDECL(drop_to, (coord *,SCHAR_P));
+
+static NEARDATA struct obj *kickobj;
+
+static const char kick_passes_thru[] = "kick passes harmlessly through";
+
+STATIC_OVL void
+kickdmg(mon, clumsy)
+register struct monst *mon;
+register boolean clumsy;
+{
+       register int mdx, mdy;
+       register int dmg = ( ACURRSTR + ACURR(A_DEX) + ACURR(A_CON) )/ 15;
+       int kick_skill = P_NONE;
+       int blessed_foot_damage = 0;
+       boolean trapkilled = FALSE;
+
+       if (uarmf && uarmf->otyp == KICKING_BOOTS)
+           dmg += 5;
+
+       /* excessive wt affects dex, so it affects dmg */
+       if (clumsy) dmg /= 2;
+
+       /* kicking a dragon or an elephant will not harm it */
+       if (thick_skinned(mon->data)) dmg = 0;
+
+       /* attacking a shade is useless */
+       if (mon->data == &mons[PM_SHADE])
+           dmg = 0;
+
+       if ((is_undead(mon->data) || is_demon(mon->data)) && uarmf &&
+               uarmf->blessed)
+           blessed_foot_damage = 1;
+
+       if (mon->data == &mons[PM_SHADE] && !blessed_foot_damage) {
+           pline_The("%s.", kick_passes_thru);
+           /* doesn't exercise skill or abuse alignment or frighten pet,
+              and shades have no passive counterattack */
+           return;
+       }
+
+       if(mon->m_ap_type) seemimic(mon);
+
+       check_caitiff(mon);
+
+       /* squeeze some guilt feelings... */
+       if(mon->mtame) {
+           abuse_dog(mon);
+           if (mon->mtame)
+               monflee(mon, (dmg ? rnd(dmg) : 1), FALSE, FALSE);
+           else
+               mon->mflee = 0;
+       }
+
+       if (dmg > 0) {
+               /* convert potential damage to actual damage */
+               dmg = rnd(dmg);
+               if (martial()) {
+                   if (dmg > 1) kick_skill = P_MARTIAL_ARTS;
+                   dmg += rn2(ACURR(A_DEX)/2 + 1);
+               }
+               /* a good kick exercises your dex */
+               exercise(A_DEX, TRUE);
+       }
+       if (blessed_foot_damage) dmg += rnd(4);
+       if (uarmf) dmg += uarmf->spe;
+       dmg += u.udaminc;       /* add ring(s) of increase damage */
+       if (dmg > 0)
+               mon->mhp -= dmg;
+       if (mon->mhp > 0 && martial() && !bigmonst(mon->data) && !rn2(3) &&
+           mon->mcanmove && mon != u.ustuck && !mon->mtrapped) {
+               /* see if the monster has a place to move into */
+               mdx = mon->mx + u.dx;
+               mdy = mon->my + u.dy;
+               if(goodpos(mdx, mdy, mon, 0)) {
+                       pline("%s reels from the blow.", Monnam(mon));
+                       if (m_in_out_region(mon, mdx, mdy)) {
+                           remove_monster(mon->mx, mon->my);
+                           newsym(mon->mx, mon->my);
+                           place_monster(mon, mdx, mdy);
+                           newsym(mon->mx, mon->my);
+                           set_apparxy(mon);
+                           if (mintrap(mon) == 2) trapkilled = TRUE;
+                       }
+               }
+       }
+
+       (void) passive(mon, TRUE, mon->mhp > 0, AT_KICK);
+       if (mon->mhp <= 0 && !trapkilled) killed(mon);
+
+       /* may bring up a dialog, so put this after all messages */
+       if (kick_skill != P_NONE)       /* exercise proficiency */
+           use_skill(kick_skill, 1);
+}
+
+STATIC_OVL void
+kick_monster(x, y)
+register xchar x, y;
+{
+       register boolean clumsy = FALSE;
+       register struct monst *mon = m_at(x, y);
+       register int i, j;
+
+       bhitpos.x = x;
+       bhitpos.y = y;
+       if (attack_checks(mon, (struct obj *)0)) return;
+       setmangry(mon);
+
+       /* Kick attacks by kicking monsters are normal attacks, not special.
+        * This is almost always worthless, since you can either take one turn
+        * and do all your kicks, or else take one turn and attack the monster
+        * normally, getting all your attacks _including_ all your kicks.
+        * If you have >1 kick attack, you get all of them.
+        */
+       if (Upolyd && attacktype(youmonst.data, AT_KICK)) {
+           struct attack *uattk;
+           int sum;
+           schar tmp = find_roll_to_hit(mon);
+
+           for (i = 0; i < NATTK; i++) {
+               /* first of two kicks might have provoked counterattack
+                  that has incapacitated the hero (ie, floating eye) */
+               if (multi < 0) break;
+
+               uattk = &youmonst.data->mattk[i];
+               /* we only care about kicking attacks here */
+               if (uattk->aatyp != AT_KICK) continue;
+
+               if (mon->data == &mons[PM_SHADE] &&
+                       (!uarmf || !uarmf->blessed)) {
+                   /* doesn't matter whether it would have hit or missed,
+                      and shades have no passive counterattack */
+                   Your("%s %s.", kick_passes_thru, mon_nam(mon));
+                   break;      /* skip any additional kicks */
+               } else if (tmp > rnd(20)) {
+                   You("kick %s.", mon_nam(mon));
+                   sum = damageum(mon, uattk);
+                   (void)passive(mon, (boolean)(sum > 0), (sum != 2), AT_KICK);
+                   if (sum == 2)
+                       break;          /* Defender died */
+               } else {
+                   missum(mon, uattk);
+                   (void)passive(mon, 0, 1, AT_KICK);
+               }
+           }
+           return;
+       }
+
+       if(Levitation && !rn2(3) && verysmall(mon->data) &&
+          !is_flyer(mon->data)) {
+               pline("Floating in the air, you miss wildly!");
+               exercise(A_DEX, FALSE);
+               (void) passive(mon, FALSE, 1, AT_KICK);
+               return;
+       }
+
+       i = -inv_weight();
+       j = weight_cap();
+
+       if(i < (j*3)/10) {
+               if(!rn2((i < j/10) ? 2 : (i < j/5) ? 3 : 4)) {
+                       if(martial() && !rn2(2)) goto doit;
+                       Your("clumsy kick does no damage.");
+                       (void) passive(mon, FALSE, 1, AT_KICK);
+                       return;
+               }
+               if(i < j/10) clumsy = TRUE;
+               else if(!rn2((i < j/5) ? 2 : 3)) clumsy = TRUE;
+       }
+
+       if(Fumbling) clumsy = TRUE;
+
+       else if(uarm && objects[uarm->otyp].oc_bulky && ACURR(A_DEX) < rnd(25))
+               clumsy = TRUE;
+doit:
+       You("kick %s.", mon_nam(mon));
+       if(!rn2(clumsy ? 3 : 4) && (clumsy || !bigmonst(mon->data)) &&
+          mon->mcansee && !mon->mtrapped && !thick_skinned(mon->data) &&
+          mon->data->mlet != S_EEL && haseyes(mon->data) && mon->mcanmove &&
+          !mon->mstun && !mon->mconf && !mon->msleeping &&
+          mon->data->mmove >= 12) {
+               if(!nohands(mon->data) && !rn2(martial() ? 5 : 3)) {
+                   pline("%s blocks your %skick.", Monnam(mon),
+                               clumsy ? "clumsy " : "");
+                   (void) passive(mon, FALSE, 1, AT_KICK);
+                   return;
+               } else {
+                   mnexto(mon);
+                   if(mon->mx != x || mon->my != y) {
+                       if(glyph_is_invisible(levl[x][y].glyph)) {
+                           unmap_object(x, y);
+                           newsym(x, y);
+                       }
+                       pline("%s %s, %s evading your %skick.", Monnam(mon),
+                               (can_teleport(mon->data) ? "teleports" :
+                                is_floater(mon->data) ? "floats" :
+                                is_flyer(mon->data) ? "swoops" :
+                                (nolimbs(mon->data) || slithy(mon->data)) ?
+                                       "slides" : "jumps"),
+                               clumsy ? "easily" : "nimbly",
+                               clumsy ? "clumsy " : "");
+                       (void) passive(mon, FALSE, 1, AT_KICK);
+                       return;
+                   }
+               }
+       }
+       kickdmg(mon, clumsy);
+}
+
+/*
+ *  Return TRUE if caught (the gold taken care of), FALSE otherwise.
+ *  The gold object is *not* attached to the fobj chain!
+ */
+boolean
+ghitm(mtmp, gold)
+register struct monst *mtmp;
+register struct obj *gold;
+{
+       boolean msg_given = FALSE;
+
+       if(!likes_gold(mtmp->data) && !mtmp->isshk && !mtmp->ispriest
+                       && !is_mercenary(mtmp->data)) {
+               wakeup(mtmp);
+       } else if (!mtmp->mcanmove) {
+               /* too light to do real damage */
+               if (canseemon(mtmp)) {
+                   pline_The("%s harmlessly %s %s.", xname(gold),
+                             otense(gold, "hit"), mon_nam(mtmp));
+                   msg_given = TRUE;
+               }
+       } else {
+#ifdef GOLDOBJ
+                long value = gold->quan * objects[gold->otyp].oc_cost;
+#endif
+               mtmp->msleeping = 0;
+               mtmp->meating = 0;
+               if(!rn2(4)) setmangry(mtmp); /* not always pleasing */
+
+               /* greedy monsters catch gold */
+               if (cansee(mtmp->mx, mtmp->my))
+                   pline("%s catches the gold.", Monnam(mtmp));
+#ifndef GOLDOBJ
+               mtmp->mgold += gold->quan;
+#endif
+               if (mtmp->isshk) {
+                       long robbed = ESHK(mtmp)->robbed;
+
+                       if (robbed) {
+#ifndef GOLDOBJ
+                               robbed -= gold->quan;
+#else
+                               robbed -= value;
+#endif
+                               if (robbed < 0) robbed = 0;
+                               pline_The("amount %scovers %s recent losses.",
+                                     !robbed ? "" : "partially ",
+                                     mhis(mtmp));
+                               ESHK(mtmp)->robbed = robbed;
+                               if(!robbed)
+                                       make_happy_shk(mtmp, FALSE);
+                       } else {
+                               if(mtmp->mpeaceful) {
+#ifndef GOLDOBJ
+                                   ESHK(mtmp)->credit += gold->quan;
+#else
+                                   ESHK(mtmp)->credit += value;
+#endif
+                                   You("have %ld %s in credit.",
+                                       ESHK(mtmp)->credit,
+                                       currency(ESHK(mtmp)->credit));
+                               } else verbalize("Thanks, scum!");
+                       }
+               } else if (mtmp->ispriest) {
+                       if (mtmp->mpeaceful)
+                           verbalize("Thank you for your contribution.");
+                       else verbalize("Thanks, scum!");
+               } else if (is_mercenary(mtmp->data)) {
+                   long goldreqd = 0L;
+
+                   if (rn2(3)) {
+                       if (mtmp->data == &mons[PM_SOLDIER])
+                          goldreqd = 100L;
+                       else if (mtmp->data == &mons[PM_SERGEANT])
+                          goldreqd = 250L;
+                       else if (mtmp->data == &mons[PM_LIEUTENANT])
+                          goldreqd = 500L;
+                       else if (mtmp->data == &mons[PM_CAPTAIN])
+                          goldreqd = 750L;
+
+                       if (goldreqd) {
+#ifndef GOLDOBJ
+                          if (gold->quan > goldreqd +
+                               (u.ugold + u.ulevel*rn2(5))/ACURR(A_CHA))
+#else
+                          if (value > goldreqd +
+                               (money_cnt(invent) + u.ulevel*rn2(5))/ACURR(A_CHA))
+#endif
+                           mtmp->mpeaceful = TRUE;
+                       }
+                    }
+                    if (mtmp->mpeaceful)
+                           verbalize("That should do.  Now beat it!");
+                    else verbalize("That's not enough, coward!");
+               }
+
+#ifndef GOLDOBJ
+               dealloc_obj(gold);
+#else
+               add_to_minv(mtmp, gold);
+#endif
+               return TRUE;
+       }
+
+       if (!msg_given) miss(xname(gold), mtmp);
+       return FALSE;
+}
+
+/* container is kicked, dropped, thrown or otherwise impacted by player.
+ * Assumes container is on floor.  Checks contents for possible damage. */
+void
+container_impact_dmg(obj)
+struct obj *obj;
+{
+       struct monst *shkp;
+       struct obj *otmp, *otmp2;
+       long loss = 0L;
+       boolean costly, insider;
+       xchar x = obj->ox, y = obj->oy;
+
+       /* only consider normal containers */
+       if (!Is_container(obj) || Is_mbag(obj)) return;
+
+       costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) &&
+                 costly_spot(x, y));
+       insider = (*u.ushops && inside_shop(u.ux, u.uy) &&
+                  *in_rooms(x, y, SHOPBASE) == *u.ushops);
+
+       for (otmp = obj->cobj; otmp; otmp = otmp2) {
+           const char *result = (char *)0;
+
+           otmp2 = otmp->nobj;
+           if (objects[otmp->otyp].oc_material == GLASS &&
+               otmp->oclass != GEM_CLASS && !obj_resists(otmp, 33, 100)) {
+               result = "shatter";
+           } else if (otmp->otyp == EGG && !rn2(3)) {
+               result = "cracking";
+           }
+           if (result) {
+               if (otmp->otyp == MIRROR) change_luck(-2);
+
+               /* eggs laid by you.  penalty is -1 per egg, max 5,
+                * but it's always exactly 1 that breaks */
+               if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM)
+                   change_luck(-1);
+               You_hear("a muffled %s.", result);
+               if (costly)
+                   loss += stolen_value(otmp, x, y,
+                                        (boolean)shkp->mpeaceful, TRUE);
+               if (otmp->quan > 1L)
+                   useup(otmp);
+               else {
+                   obj_extract_self(otmp);
+                   obfree(otmp, (struct obj *) 0);
+               }
+           }
+       }
+       if (costly && loss) {
+           if (!insider) {
+               You("caused %ld %s worth of damage!", loss, currency(loss));
+               make_angry_shk(shkp, x, y);
+           } else {
+               You("owe %s %ld %s for objects destroyed.",
+                   mon_nam(shkp), loss, currency(loss));
+           }
+       }
+}
+
+STATIC_OVL int
+kick_object(x, y)
+xchar x, y;
+{
+       int range;
+       register struct monst *mon, *shkp;
+       struct trap *trap;
+       char bhitroom;
+       boolean costly, isgold, slide = FALSE;
+
+       /* if a pile, the "top" object gets kicked */
+       kickobj = level.objects[x][y];
+
+       /* kickobj should always be set due to conditions of call */
+       if(!kickobj || kickobj->otyp == BOULDER
+                       || kickobj == uball || kickobj == uchain)
+               return(0);
+
+       if ((trap = t_at(x,y)) != 0 &&
+                       (((trap->ttyp == PIT ||
+                          trap->ttyp == SPIKED_PIT) && !Passes_walls) ||
+                        trap->ttyp == WEB)) {
+               if (!trap->tseen) find_trap(trap);
+               You_cant("kick %s that's in a %s!", something,
+                        Hallucination ? "tizzy" :
+                        (trap->ttyp == WEB) ? "web" : "pit");
+               return 1;
+       }
+
+       if(Fumbling && !rn2(3)) {
+               Your("clumsy kick missed.");
+               return(1);
+       }
+
+       if(kickobj->otyp == CORPSE && touch_petrifies(&mons[kickobj->corpsenm])
+                       && !Stone_resistance && !uarmf) {
+           char kbuf[BUFSZ];
+
+           You("kick the %s with your bare %s.",
+               corpse_xname(kickobj, TRUE), makeplural(body_part(FOOT)));
+           if (!(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
+               You("turn to stone...");
+               killer_format = KILLED_BY;
+               /* KMH -- otmp should be kickobj */
+               Sprintf(kbuf, "kicking %s without boots",
+                       an(corpse_xname(kickobj, TRUE)));
+               killer = kbuf;
+               done(STONING);
+           }
+       }
+
+       /* range < 2 means the object will not move.    */
+       /* maybe dexterity should also figure here.     */
+       range = (int)((ACURRSTR)/2 - kickobj->owt/40);
+
+       if(martial()) range += rnd(3);
+
+       if (is_pool(x, y)) {
+           /* you're in the water too; significantly reduce range */
+           range = range / 3 + 1;      /* {1,2}=>1, {3,4,5}=>2, {6,7,8}=>3 */
+       } else {
+           if (is_ice(x, y)) range += rnd(3),  slide = TRUE;
+           if (kickobj->greased) range += rnd(3),  slide = TRUE;
+       }
+
+       /* Mjollnir is magically too heavy to kick */
+       if(kickobj->oartifact == ART_MJOLLNIR) range = 1;
+
+       /* see if the object has a place to move into */
+       if(!ZAP_POS(levl[x+u.dx][y+u.dy].typ) || closed_door(x+u.dx, y+u.dy))
+               range = 1;
+
+       costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) &&
+                                   costly_spot(x, y));
+       isgold = (kickobj->oclass == COIN_CLASS);
+
+       if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) {
+           if ((!martial() && rn2(20) > ACURR(A_DEX)) ||
+                   IS_ROCK(levl[u.ux][u.uy].typ) || closed_door(u.ux, u.uy)) {
+               if (Blind)
+                   pline("It doesn't come loose.");
+               else
+                   pline("%s %sn't come loose.",
+                         The(distant_name(kickobj, xname)),
+                         otense(kickobj, "do"));
+               return (!rn2(3) || martial());
+           }
+           if (Blind)
+               pline("It comes loose.");
+           else
+               pline("%s %s loose.",
+                     The(distant_name(kickobj, xname)),
+                     otense(kickobj, "come"));
+           obj_extract_self(kickobj);
+           newsym(x, y);
+           if (costly && (!costly_spot(u.ux, u.uy) ||
+                   !index(u.urooms, *in_rooms(x, y, SHOPBASE))))
+               addtobill(kickobj, FALSE, FALSE, FALSE);
+           if (!flooreffects(kickobj, u.ux, u.uy, "fall")) {
+               place_object(kickobj, u.ux, u.uy);
+               stackobj(kickobj);
+               newsym(u.ux, u.uy);
+           }
+           return 1;
+       }
+
+       /* a box gets a chance of breaking open here */
+       if(Is_box(kickobj)) {
+               boolean otrp = kickobj->otrapped;
+
+               if(range < 2) pline("THUD!");
+
+               container_impact_dmg(kickobj);
+
+               if (kickobj->olocked) {
+                   if (!rn2(5) || (martial() && !rn2(2))) {
+                       You("break open the lock!");
+                       kickobj->olocked = 0;
+                       kickobj->obroken = 1;
+                       if (otrp) (void) chest_trap(kickobj, LEG, FALSE);
+                       return(1);
+                   }
+               } else {
+                   if (!rn2(3) || (martial() && !rn2(2))) {
+                       pline_The("lid slams open, then falls shut.");
+                       if (otrp) (void) chest_trap(kickobj, LEG, FALSE);
+                       return(1);
+                   }
+               }
+               if(range < 2) return(1);
+               /* else let it fall through to the next cases... */
+       }
+
+       /* fragile objects should not be kicked */
+       if (hero_breaks(kickobj, kickobj->ox, kickobj->oy, FALSE)) return 1;
+
+       /* too heavy to move.  range is calculated as potential distance from
+        * player, so range == 2 means the object may move up to one square
+        * from its current position
+        */
+       if(range < 2 || (isgold && kickobj->quan > 300L)) {
+           if(!Is_box(kickobj)) pline("Thump!");
+           return(!rn2(3) || martial());
+       }
+
+       if (kickobj->quan > 1L && !isgold) kickobj = splitobj(kickobj, 1L);
+
+       if (slide && !Blind)
+           pline("Whee!  %s %s across the %s.", Doname2(kickobj),
+                 otense(kickobj, "slide"), surface(x,y));
+
+       obj_extract_self(kickobj);
+       (void) snuff_candle(kickobj);
+       newsym(x, y);
+       mon = bhit(u.dx, u.dy, range, KICKED_WEAPON,
+                  (int FDECL((*),(MONST_P,OBJ_P)))0,
+                  (int FDECL((*),(OBJ_P,OBJ_P)))0,
+                  kickobj);
+
+       if(mon) {
+           if (mon->isshk &&
+                   kickobj->where == OBJ_MINVENT && kickobj->ocarry == mon)
+               return 1;       /* alert shk caught it */
+           notonhead = (mon->mx != bhitpos.x || mon->my != bhitpos.y);
+           if (isgold ? ghitm(mon, kickobj) :  /* caught? */
+                   thitmonst(mon, kickobj))    /* hit && used up? */
+               return(1);
+       }
+
+       /* the object might have fallen down a hole */
+       if (kickobj->where == OBJ_MIGRATING) {
+           if (costly) {
+               if(isgold)
+                   costly_gold(x, y, kickobj->quan);
+               else (void)stolen_value(kickobj, x, y,
+                                       (boolean)shkp->mpeaceful, FALSE);
+           }
+           return 1;
+       }
+
+       bhitroom = *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE);
+       if (costly && (!costly_spot(bhitpos.x, bhitpos.y) ||
+                       *in_rooms(x, y, SHOPBASE) != bhitroom)) {
+           if(isgold)
+               costly_gold(x, y, kickobj->quan);
+           else (void)stolen_value(kickobj, x, y,
+                                   (boolean)shkp->mpeaceful, FALSE);
+       }
+
+       if(flooreffects(kickobj,bhitpos.x,bhitpos.y,"fall")) return(1);
+       place_object(kickobj, bhitpos.x, bhitpos.y);
+       stackobj(kickobj);
+       newsym(kickobj->ox, kickobj->oy);
+       return(1);
+}
+
+STATIC_OVL char *
+kickstr(buf)
+char *buf;
+{
+       const char *what;
+
+       if (kickobj) what = distant_name(kickobj,doname);
+       else if (IS_DOOR(maploc->typ)) what = "a door";
+       else if (IS_TREE(maploc->typ)) what = "a tree";
+       else if (IS_STWALL(maploc->typ)) what = "a wall";
+       else if (IS_ROCK(maploc->typ)) what = "a rock";
+       else if (IS_THRONE(maploc->typ)) what = "a throne";
+       else if (IS_FOUNTAIN(maploc->typ)) what = "a fountain";
+       else if (IS_GRAVE(maploc->typ)) what = "a headstone";
+#ifdef SINKS
+       else if (IS_SINK(maploc->typ)) what = "a sink";
+#endif
+       else if (IS_ALTAR(maploc->typ)) what = "an altar";
+       else if (IS_DRAWBRIDGE(maploc->typ)) what = "a drawbridge";
+       else if (maploc->typ == STAIRS) what = "the stairs";
+       else if (maploc->typ == LADDER) what = "a ladder";
+       else if (maploc->typ == IRONBARS) what = "an iron bar";
+       else what = "something weird";
+       return strcat(strcpy(buf, "kicking "), what);
+}
+
+int
+dokick()
+{
+       int x, y;
+       int avrg_attrib;
+       register struct monst *mtmp;
+       boolean no_kick = FALSE;
+       char buf[BUFSZ];
+
+       if (nolimbs(youmonst.data) || slithy(youmonst.data)) {
+               You("have no legs to kick with.");
+               no_kick = TRUE;
+       } else if (verysmall(youmonst.data)) {
+               You("are too small to do any kicking.");
+               no_kick = TRUE;
+#ifdef STEED
+       } else if (u.usteed) {
+               if (yn_function("Kick your steed?", ynchars, 'y') == 'y') {
+                   You("kick %s.", mon_nam(u.usteed));
+                   kick_steed();
+                   return 1;
+               } else {
+                   return 0;
+               }
+#endif
+       } else if (Wounded_legs) {
+               /* note: jump() has similar code */
+               long wl = (EWounded_legs & BOTH_SIDES);
+               const char *bp = body_part(LEG);
+
+               if (wl == BOTH_SIDES) bp = makeplural(bp);
+               Your("%s%s %s in no shape for kicking.",
+                    (wl == LEFT_SIDE) ? "left " :
+                       (wl == RIGHT_SIDE) ? "right " : "",
+                    bp, (wl == BOTH_SIDES) ? "are" : "is");
+               no_kick = TRUE;
+       } else if (near_capacity() > SLT_ENCUMBER) {
+               Your("load is too heavy to balance yourself for a kick.");
+               no_kick = TRUE;
+       } else if (youmonst.data->mlet == S_LIZARD) {
+               Your("legs cannot kick effectively.");
+               no_kick = TRUE;
+       } else if (u.uinwater && !rn2(2)) {
+               Your("slow motion kick doesn't hit anything.");
+               no_kick = TRUE;
+       } else if (u.utrap) {
+               switch (u.utraptype) {
+                   case TT_PIT:
+                       pline("There's not enough room to kick down here.");
+                       break;
+                   case TT_WEB:
+                   case TT_BEARTRAP:
+                       You_cant("move your %s!", body_part(LEG));
+                       break;
+                   default:
+                       break;
+               }
+               no_kick = TRUE;
+       }
+
+       if (no_kick) {
+               /* ignore direction typed before player notices kick failed */
+               display_nhwindow(WIN_MESSAGE, TRUE);    /* --More-- */
+               return 0;
+       }
+
+       if(!getdir((char *)0)) return(0);
+       if(!u.dx && !u.dy) return(0);
+
+       x = u.ux + u.dx;
+       y = u.uy + u.dy;
+
+       /* KMH -- Kicking boots always succeed */
+       if (uarmf && uarmf->otyp == KICKING_BOOTS)
+           avrg_attrib = 99;
+       else
+           avrg_attrib = (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3;
+
+       if(u.uswallow) {
+               switch(rn2(3)) {
+               case 0:  You_cant("move your %s!", body_part(LEG));
+                        break;
+               case 1:  if (is_animal(u.ustuck->data)) {
+                               pline("%s burps loudly.", Monnam(u.ustuck));
+                               break;
+                        }
+               default: Your("feeble kick has no effect."); break;
+               }
+               return(1);
+       }
+       if (Levitation) {
+               int xx, yy;
+
+               xx = u.ux - u.dx;
+               yy = u.uy - u.dy;
+               /* doors can be opened while levitating, so they must be
+                * reachable for bracing purposes
+                * Possible extension: allow bracing against stuff on the side?
+                */
+               if (isok(xx,yy) && !IS_ROCK(levl[xx][yy].typ) &&
+                       !IS_DOOR(levl[xx][yy].typ) &&
+                       (!Is_airlevel(&u.uz) || !OBJ_AT(xx,yy))) {
+                   You("have nothing to brace yourself against.");
+                   return(0);
+               }
+       }
+
+       wake_nearby();
+       u_wipe_engr(2);
+
+       maploc = &levl[x][y];
+
+       /* The next five tests should stay in    */
+       /* their present order: monsters, pools, */
+       /* objects, non-doors, doors.            */
+
+       if(MON_AT(x, y)) {
+               struct permonst *mdat;
+
+               mtmp = m_at(x, y);
+               mdat = mtmp->data;
+               if (!mtmp->mpeaceful || !canspotmon(mtmp))
+                   flags.forcefight = TRUE; /* attack even if invisible */
+               kick_monster(x, y);
+               flags.forcefight = FALSE;
+               /* see comment in attack_checks() */
+               if (!DEADMONSTER(mtmp) &&
+                   !canspotmon(mtmp) &&
+                   /* check x and y; a monster that evades your kick by
+                      jumping to an unseen square doesn't leave an I behind */
+                   mtmp->mx == x && mtmp->my == y &&
+                   !glyph_is_invisible(levl[x][y].glyph) &&
+                   !(u.uswallow && mtmp == u.ustuck))
+                       map_invisible(x, y);
+               if((Is_airlevel(&u.uz) || Levitation) && flags.move) {
+                   int range;
+
+                   range = ((int)youmonst.data->cwt + (weight_cap() + inv_weight()));
+                   if (range < 1) range = 1; /* divide by zero avoidance */
+                   range = (3*(int)mdat->cwt) / range;
+
+                   if(range < 1) range = 1;
+                   hurtle(-u.dx, -u.dy, range, TRUE);
+               }
+               return(1);
+       }
+       if (glyph_is_invisible(levl[x][y].glyph)) {
+               unmap_object(x, y);
+               newsym(x, y);
+       }
+       if (is_pool(x, y) ^ !!u.uinwater) {
+               /* objects normally can't be removed from water by kicking */
+               You("splash some water around.");
+               return 1;
+       }
+
+       kickobj = (struct obj *)0;
+       if (OBJ_AT(x, y) &&
+           (!Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
+            || sobj_at(BOULDER,x,y))) {
+               if(kick_object(x, y)) {
+                   if(Is_airlevel(&u.uz))
+                       hurtle(-u.dx, -u.dy, 1, TRUE); /* assume it's light */
+                   return(1);
+               }
+               goto ouch;
+       }
+
+       if(!IS_DOOR(maploc->typ)) {
+               if(maploc->typ == SDOOR) {
+                   if(!Levitation && rn2(30) < avrg_attrib) {
+                       cvt_sdoor_to_door(maploc);      /* ->typ = DOOR */
+                       pline("Crash!  %s a secret door!",
+                             /* don't "kick open" when it's locked
+                                unless it also happens to be trapped */
+                       (maploc->doormask & (D_LOCKED|D_TRAPPED)) == D_LOCKED ?
+                             "Your kick uncovers" : "You kick open");
+                       exercise(A_DEX, TRUE);
+                       if(maploc->doormask & D_TRAPPED) {
+                           maploc->doormask = D_NODOOR;
+                           b_trapped("door", FOOT);
+                       } else if (maploc->doormask != D_NODOOR &&
+                                  !(maploc->doormask & D_LOCKED))
+                           maploc->doormask = D_ISOPEN;
+                       if (Blind)
+                           feel_location(x,y); /* we know it's gone */
+                       else
+                           newsym(x,y);
+                       if (maploc->doormask == D_ISOPEN ||
+                           maploc->doormask == D_NODOOR)
+                           unblock_point(x,y); /* vision */
+                       return(1);
+                   } else goto ouch;
+               }
+               if(maploc->typ == SCORR) {
+                   if(!Levitation && rn2(30) < avrg_attrib) {
+                       pline("Crash!  You kick open a secret passage!");
+                       exercise(A_DEX, TRUE);
+                       maploc->typ = CORR;
+                       if (Blind)
+                           feel_location(x,y); /* we know it's gone */
+                       else
+                           newsym(x,y);
+                       unblock_point(x,y);     /* vision */
+                       return(1);
+                   } else goto ouch;
+               }
+               if(IS_THRONE(maploc->typ)) {
+                   register int i;
+                   if(Levitation) goto dumb;
+                   if((Luck < 0 || maploc->doormask) && !rn2(3)) {
+                       maploc->typ = ROOM;
+                       maploc->doormask = 0; /* don't leave loose ends.. */
+                       (void) mkgold((long)rnd(200), x, y);
+                       if (Blind)
+                           pline("CRASH!  You destroy it.");
+                       else {
+                           pline("CRASH!  You destroy the throne.");
+                           newsym(x, y);
+                       }
+                       exercise(A_DEX, TRUE);
+                       return(1);
+                   } else if(Luck > 0 && !rn2(3) && !maploc->looted) {
+                       (void) mkgold((long) rn1(201, 300), x, y);
+                       i = Luck + 1;
+                       if(i > 6) i = 6;
+                       while(i--)
+                           (void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL,
+                                       LUCKSTONE-1), x, y, FALSE, TRUE);
+                       if (Blind)
+                           You("kick %s loose!", something);
+                       else {
+                           You("kick loose some ornamental coins and gems!");
+                           newsym(x, y);
+                       }
+                       /* prevent endless milking */
+                       maploc->looted = T_LOOTED;
+                       return(1);
+                   } else if (!rn2(4)) {
+                       if(dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)) {
+                           fall_through(FALSE);
+                           return(1);
+                       } else goto ouch;
+                   }
+                   goto ouch;
+               }
+               if(IS_ALTAR(maploc->typ)) {
+                   if(Levitation) goto dumb;
+                   You("kick %s.",(Blind ? something : "the altar"));
+                   if(!rn2(3)) goto ouch;
+                   altar_wrath(x, y);
+                   exercise(A_DEX, TRUE);
+                   return(1);
+               }
+               if(IS_FOUNTAIN(maploc->typ)) {
+                   if(Levitation) goto dumb;
+                   You("kick %s.",(Blind ? something : "the fountain"));
+                   if(!rn2(3)) goto ouch;
+                   /* make metal boots rust */
+                   if(uarmf && rn2(3))
+                       if (!rust_dmg(uarmf, "metal boots", 1, FALSE, &youmonst)) {
+                               Your("boots get wet.");
+                               /* could cause short-lived fumbling here */
+                       }
+                   exercise(A_DEX, TRUE);
+                   return(1);
+               }
+               if(IS_GRAVE(maploc->typ) || maploc->typ == IRONBARS)
+                   goto ouch;
+               if(IS_TREE(maploc->typ)) {
+                   struct obj *treefruit;
+                   /* nothing, fruit or trouble? 75:23.5:1.5% */
+                   if (rn2(3)) {
+                       if ( !rn2(6) && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE) )
+                           You_hear("a low buzzing."); /* a warning */
+                       goto ouch;
+                   }
+                   if (rn2(15) && !(maploc->looted & TREE_LOOTED) &&
+                         (treefruit = rnd_treefruit_at(x, y))) {
+                       long nfruit = 8L-rnl(7), nfall;
+                       short frtype = treefruit->otyp;
+                       treefruit->quan = nfruit;
+                       if (is_plural(treefruit))
+                           pline("Some %s fall from the tree!", xname(treefruit));
+                       else
+                           pline("%s falls from the tree!", An(xname(treefruit)));
+                       nfall = scatter(x,y,2,MAY_HIT,treefruit);
+                       if (nfall != nfruit) {
+                           /* scatter left some in the tree, but treefruit
+                            * may not refer to the correct object */
+                           treefruit = mksobj(frtype, TRUE, FALSE);
+                           treefruit->quan = nfruit-nfall;
+                           pline("%ld %s got caught in the branches.",
+                               nfruit-nfall, xname(treefruit));
+                           dealloc_obj(treefruit);
+                       }
+                       exercise(A_DEX, TRUE);
+                       exercise(A_WIS, TRUE);  /* discovered a new food source! */
+                       newsym(x, y);
+                       maploc->looted |= TREE_LOOTED;
+                       return(1);
+                   } else if (!(maploc->looted & TREE_SWARM)) {
+                       int cnt = rnl(4) + 2;
+                       int made = 0;
+                       coord mm;
+                       mm.x = x; mm.y = y;
+                       while (cnt--) {
+                           if (enexto(&mm, mm.x, mm.y, &mons[PM_KILLER_BEE])
+                               && makemon(&mons[PM_KILLER_BEE],
+                                              mm.x, mm.y, MM_ANGRY))
+                               made++;
+                       }
+                       if ( made )
+                           pline("You've attracted the tree's former occupants!");
+                       else
+                           You("smell stale honey.");
+                       maploc->looted |= TREE_SWARM;
+                       return(1);
+                   }
+                   goto ouch;
+               }
+#ifdef SINKS
+               if(IS_SINK(maploc->typ)) {
+                   int gend = poly_gender();
+                   short washerndx = (gend == 1 || (gend == 2 && rn2(2))) ?
+                                       PM_INCUBUS : PM_SUCCUBUS;
+
+                   if(Levitation) goto dumb;
+                   if(rn2(5)) {
+                       if(flags.soundok)
+                           pline("Klunk!  The pipes vibrate noisily.");
+                       else pline("Klunk!");
+                       exercise(A_DEX, TRUE);
+                       return(1);
+                   } else if(!(maploc->looted & S_LPUDDING) && !rn2(3) &&
+                         !(mvitals[PM_BLACK_PUDDING].mvflags & G_GONE)) {
+                       if (Blind)
+                           You_hear("a gushing sound.");
+                       else
+                           pline("A %s ooze gushes up from the drain!",
+                                        hcolor(NH_BLACK));
+                       (void) makemon(&mons[PM_BLACK_PUDDING],
+                                        x, y, NO_MM_FLAGS);
+                       exercise(A_DEX, TRUE);
+                       newsym(x,y);
+                       maploc->looted |= S_LPUDDING;
+                       return(1);
+                   } else if(!(maploc->looted & S_LDWASHER) && !rn2(3) &&
+                             !(mvitals[washerndx].mvflags & G_GONE)) {
+                       /* can't resist... */
+                       pline("%s returns!", (Blind ? Something :
+                                                       "The dish washer"));
+                       if (makemon(&mons[washerndx], x, y, NO_MM_FLAGS))
+                           newsym(x,y);
+                       maploc->looted |= S_LDWASHER;
+                       exercise(A_DEX, TRUE);
+                       return(1);
+                   } else if(!rn2(3)) {
+                       pline("Flupp!  %s.", (Blind ?
+                                     "You hear a sloshing sound" :
+                                     "Muddy waste pops up from the drain"));
+                       if(!(maploc->looted & S_LRING)) { /* once per sink */
+                           if (!Blind)
+                               You("see a ring shining in its midst.");
+                           (void) mkobj_at(RING_CLASS, x, y, TRUE);
+                           newsym(x, y);
+                           exercise(A_DEX, TRUE);
+                           exercise(A_WIS, TRUE);      /* a discovery! */
+                           maploc->looted |= S_LRING;
+                       }
+                       return(1);
+                   }
+                   goto ouch;
+               }
+#endif
+               if (maploc->typ == STAIRS || maploc->typ == LADDER ||
+                                                   IS_STWALL(maploc->typ)) {
+                   if(!IS_STWALL(maploc->typ) && maploc->ladder == LA_DOWN)
+                       goto dumb;
+ouch:
+                   pline("Ouch!  That hurts!");
+                   exercise(A_DEX, FALSE);
+                   exercise(A_STR, FALSE);
+                   if (Blind) feel_location(x,y); /* we know we hit it */
+                   if (is_drawbridge_wall(x,y) >= 0) {
+                       pline_The("drawbridge is unaffected.");
+                       /* update maploc to refer to the drawbridge */
+                       (void) find_drawbridge(&x,&y);
+                       maploc = &levl[x][y];
+                   }
+                   if(!rn2(3)) set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
+                   losehp(rnd(ACURR(A_CON) > 15 ? 3 : 5), kickstr(buf),
+                       KILLED_BY);
+                   if(Is_airlevel(&u.uz) || Levitation)
+                       hurtle(-u.dx, -u.dy, rn1(2,4), TRUE); /* assume it's heavy */
+                   return(1);
+               }
+               goto dumb;
+       }
+
+       if(maploc->doormask == D_ISOPEN ||
+          maploc->doormask == D_BROKEN ||
+          maploc->doormask == D_NODOOR) {
+dumb:
+               exercise(A_DEX, FALSE);
+               if (martial() || ACURR(A_DEX) >= 16 || rn2(3)) {
+                       You("kick at empty space.");
+                       if (Blind) feel_location(x,y);
+               } else {
+                       pline("Dumb move!  You strain a muscle.");
+                       exercise(A_STR, FALSE);
+                       set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
+               }
+               if ((Is_airlevel(&u.uz) || Levitation) && rn2(2)) {
+                   hurtle(-u.dx, -u.dy, 1, TRUE);
+                   return 1;           /* you moved, so use up a turn */
+               }
+               return(0);
+       }
+
+       /* not enough leverage to kick open doors while levitating */
+       if(Levitation) goto ouch;
+
+       exercise(A_DEX, TRUE);
+       /* door is known to be CLOSED or LOCKED */
+       if(rnl(35) < avrg_attrib + (!martial() ? 0 : ACURR(A_DEX))) {
+               boolean shopdoor = *in_rooms(x, y, SHOPBASE) ? TRUE : FALSE;
+               /* break the door */
+               if(maploc->doormask & D_TRAPPED) {
+                   if (flags.verbose) You("kick the door.");
+                   exercise(A_STR, FALSE);
+                   maploc->doormask = D_NODOOR;
+                   b_trapped("door", FOOT);
+               } else if(ACURR(A_STR) > 18 && !rn2(5) && !shopdoor) {
+                   pline("As you kick the door, it shatters to pieces!");
+                   exercise(A_STR, TRUE);
+                   maploc->doormask = D_NODOOR;
+               } else {
+                   pline("As you kick the door, it crashes open!");
+                   exercise(A_STR, TRUE);
+                   maploc->doormask = D_BROKEN;
+               }
+               if (Blind)
+                   feel_location(x,y);         /* we know we broke it */
+               else
+                   newsym(x,y);
+               unblock_point(x,y);             /* vision */
+               if (shopdoor) {
+                   add_damage(x, y, 400L);
+                   pay_for_damage("break", FALSE);
+               }
+               if (in_town(x, y))
+                 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+                   if (DEADMONSTER(mtmp)) continue;
+                   if((mtmp->data == &mons[PM_WATCHMAN] ||
+                       mtmp->data == &mons[PM_WATCH_CAPTAIN]) &&
+                       couldsee(mtmp->mx, mtmp->my) &&
+                       mtmp->mpeaceful) {
+                       if (canspotmon(mtmp))
+                           pline("%s yells:", Amonnam(mtmp));
+                       else
+                           You_hear("someone yell:");
+                       verbalize("Halt, thief!  You're under arrest!");
+                       (void) angry_guards(FALSE);
+                       break;
+                   }
+                 }
+       } else {
+           if (Blind) feel_location(x,y);      /* we know we hit it */
+           exercise(A_STR, TRUE);
+           pline("WHAMMM!!!");
+           if (in_town(x, y))
+               for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+                   if (DEADMONSTER(mtmp)) continue;
+                   if ((mtmp->data == &mons[PM_WATCHMAN] ||
+                               mtmp->data == &mons[PM_WATCH_CAPTAIN]) &&
+                           mtmp->mpeaceful && couldsee(mtmp->mx, mtmp->my)) {
+                       if (canspotmon(mtmp))
+                           pline("%s yells:", Amonnam(mtmp));
+                       else
+                           You_hear("someone yell:");
+                       if(levl[x][y].looted & D_WARNED) {
+                           verbalize("Halt, vandal!  You're under arrest!");
+                           (void) angry_guards(FALSE);
+                       } else {
+                           verbalize("Hey, stop damaging that door!");
+                           levl[x][y].looted |= D_WARNED;
+                       }
+                       break;
+                   }
+               }
+       }
+       return(1);
+}
+
+STATIC_OVL void
+drop_to(cc, loc)
+coord *cc;
+schar loc;
+{
+       /* cover all the MIGR_xxx choices generated by down_gate() */
+       switch (loc) {
+        case MIGR_RANDOM:      /* trap door or hole */
+                   if (Is_stronghold(&u.uz)) {
+                       cc->x = valley_level.dnum;
+                       cc->y = valley_level.dlevel;
+                       break;
+                   } else if (In_endgame(&u.uz) || Is_botlevel(&u.uz)) {
+                       cc->y = cc->x = 0;
+                       break;
+                   } /* else fall to the next cases */
+        case MIGR_STAIRS_UP:
+        case MIGR_LADDER_UP:
+                   cc->x = u.uz.dnum;
+                   cc->y = u.uz.dlevel + 1;
+                   break;
+        case MIGR_SSTAIRS:
+                   cc->x = sstairs.tolev.dnum;
+                   cc->y = sstairs.tolev.dlevel;
+                   break;
+        default:
+        case MIGR_NOWHERE:
+                   /* y==0 means "nowhere", in which case x doesn't matter */
+                   cc->y = cc->x = 0;
+                   break;
+       }
+}
+
+void
+impact_drop(missile, x, y, dlev)
+struct obj *missile;
+xchar x, y, dlev;
+{
+       schar toloc;
+       register struct obj *obj, *obj2;
+       register struct monst *shkp;
+       long oct, dct, price, debit, robbed;
+       boolean angry, costly, isrock;
+       coord cc;
+
+       if(!OBJ_AT(x, y)) return;
+
+       toloc = down_gate(x, y);
+       drop_to(&cc, toloc);
+       if (!cc.y) return;
+
+       if (dlev) {
+               /* send objects next to player falling through trap door.
+                * checked in obj_delivery().
+                */
+               toloc = MIGR_NEAR_PLAYER;
+               cc.y = dlev;
+       }
+
+       costly = costly_spot(x, y);
+       price = debit = robbed = 0L;
+       angry = FALSE;
+       shkp = (struct monst *) 0;
+       /* if 'costly', we must keep a record of ESHK(shkp) before
+        * it undergoes changes through the calls to stolen_value.
+        * the angry bit must be reset, if needed, in this fn, since
+        * stolen_value is called under the 'silent' flag to avoid
+        * unsavory pline repetitions.
+        */
+       if(costly) {
+           if ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0) {
+               debit   = ESHK(shkp)->debit;
+               robbed  = ESHK(shkp)->robbed;
+               angry   = !shkp->mpeaceful;
+           }
+       }
+
+       isrock = (missile && missile->otyp == ROCK);
+       oct = dct = 0L;
+       for(obj = level.objects[x][y]; obj; obj = obj2) {
+               obj2 = obj->nexthere;
+               if(obj == missile) continue;
+               /* number of objects in the pile */
+               oct += obj->quan;
+               if(obj == uball || obj == uchain) continue;
+               /* boulders can fall too, but rarely & never due to rocks */
+               if((isrock && obj->otyp == BOULDER) ||
+                  rn2(obj->otyp == BOULDER ? 30 : 3)) continue;
+               obj_extract_self(obj);
+
+               if(costly) {
+                   price += stolen_value(obj, x, y,
+                               (costly_spot(u.ux, u.uy) &&
+                                index(u.urooms, *in_rooms(x, y, SHOPBASE))),
+                               TRUE);
+                   /* set obj->no_charge to 0 */
+                   if (Has_contents(obj))
+                       picked_container(obj);  /* does the right thing */
+                   if (obj->oclass != COIN_CLASS)
+                       obj->no_charge = 0;
+               }
+
+               add_to_migration(obj);
+               obj->ox = cc.x;
+               obj->oy = cc.y;
+               obj->owornmask = (long)toloc;
+
+               /* number of fallen objects */
+               dct += obj->quan;
+       }
+
+       if (dct && cansee(x,y)) {       /* at least one object fell */
+           const char *what = (dct == 1L ? "object falls" : "objects fall");
+
+           if (missile)
+               pline("From the impact, %sother %s.",
+                     dct == oct ? "the " : dct == 1L ? "an" : "", what);
+           else if (oct == dct)
+               pline("%s adjacent %s %s.",
+                     dct == 1L ? "The" : "All the", what, gate_str);
+           else
+               pline("%s adjacent %s %s.",
+                     dct == 1L ? "One of the" : "Some of the",
+                     dct == 1L ? "objects falls" : what, gate_str);
+       }
+
+       if(costly && shkp && price) {
+               if(ESHK(shkp)->robbed > robbed) {
+                   You("removed %ld %s worth of goods!", price, currency(price));
+                   if(cansee(shkp->mx, shkp->my)) {
+                       if(ESHK(shkp)->customer[0] == 0)
+                           (void) strncpy(ESHK(shkp)->customer,
+                                          plname, PL_NSIZ);
+                       if(angry)
+                           pline("%s is infuriated!", Monnam(shkp));
+                       else pline("\"%s, you are a thief!\"", plname);
+                   } else  You_hear("a scream, \"Thief!\"");
+                   hot_pursuit(shkp);
+                   (void) angry_guards(FALSE);
+                   return;
+               }
+               if(ESHK(shkp)->debit > debit) {
+                   long amt = (ESHK(shkp)->debit - debit);
+                   You("owe %s %ld %s for goods lost.",
+                       Monnam(shkp),
+                       amt, currency(amt));
+               }
+       }
+
+}
+
+/* NOTE: ship_object assumes otmp was FREED from fobj or invent.
+ * <x,y> is the point of drop.  otmp is _not_ an <x,y> resident:
+ * otmp is either a kicked, dropped, or thrown object.
+ */
+boolean
+ship_object(otmp, x, y, shop_floor_obj)
+xchar  x, y;
+struct obj *otmp;
+boolean shop_floor_obj;
+{
+       schar toloc;
+       xchar ox, oy;
+       coord cc;
+       struct obj *obj;
+       struct trap *t;
+       boolean nodrop, unpaid, container, impact = FALSE;
+       long n = 0L;
+
+       if (!otmp) return(FALSE);
+       if ((toloc = down_gate(x, y)) == MIGR_NOWHERE) return(FALSE);
+       drop_to(&cc, toloc);
+       if (!cc.y) return(FALSE);
+
+       /* objects other than attached iron ball always fall down ladder,
+          but have a chance of staying otherwise */
+       nodrop = (otmp == uball) || (otmp == uchain) ||
+               (toloc != MIGR_LADDER_UP && rn2(3));
+
+       container = Has_contents(otmp);
+       unpaid = (otmp->unpaid || (container && count_unpaid(otmp->cobj)));
+
+       if(OBJ_AT(x, y)) {
+           for(obj = level.objects[x][y]; obj; obj = obj->nexthere)
+               if(obj != otmp) n += obj->quan;
+           if(n) impact = TRUE;
+       }
+       /* boulders never fall through trap doors, but they might knock
+          other things down before plugging the hole */
+       if (otmp->otyp == BOULDER &&
+               ((t = t_at(x, y)) != 0) &&
+               (t->ttyp == TRAPDOOR || t->ttyp == HOLE)) {
+           if (impact) impact_drop(otmp, x, y, 0);
+           return FALSE;               /* let caller finish the drop */
+       }
+
+       if (cansee(x, y))
+           otransit_msg(otmp, nodrop, n);
+
+       if (nodrop) {
+           if (impact) impact_drop(otmp, x, y, 0);
+           return(FALSE);
+       }
+
+       if(unpaid || shop_floor_obj) {
+           if(unpaid) {
+               subfrombill(otmp, shop_keeper(*u.ushops));
+               (void)stolen_value(otmp, u.ux, u.uy, TRUE, FALSE);
+           } else {
+               ox = otmp->ox;
+               oy = otmp->oy;
+               (void)stolen_value(otmp, ox, oy,
+                         (costly_spot(u.ux, u.uy) &&
+                             index(u.urooms, *in_rooms(ox, oy, SHOPBASE))),
+                         FALSE);
+           }
+           /* set otmp->no_charge to 0 */
+           if(container)
+               picked_container(otmp); /* happens to do the right thing */
+           if(otmp->oclass != COIN_CLASS)
+               otmp->no_charge = 0;
+       }
+
+       if (otmp == uwep) setuwep((struct obj *)0);
+       if (otmp == uquiver) setuqwep((struct obj *)0);
+       if (otmp == uswapwep) setuswapwep((struct obj *)0);
+
+       /* some things break rather than ship */
+       if (breaktest(otmp)) {
+           const char *result;
+
+           if (objects[otmp->otyp].oc_material == GLASS
+#ifdef TOURIST
+               || otmp->otyp == EXPENSIVE_CAMERA
+#endif
+               ) {
+               if (otmp->otyp == MIRROR)
+                   change_luck(-2);
+               result = "crash";
+           } else {
+               /* penalty for breaking eggs laid by you */
+               if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM)
+                   change_luck((schar) -min(otmp->quan, 5L));
+               result = "splat";
+           }
+           You_hear("a muffled %s.",result);
+           obj_extract_self(otmp);
+           obfree(otmp, (struct obj *) 0);
+           return TRUE;
+       }
+
+       add_to_migration(otmp);
+       otmp->ox = cc.x;
+       otmp->oy = cc.y;
+       otmp->owornmask = (long)toloc;
+       /* boulder from rolling boulder trap, no longer part of the trap */
+       if (otmp->otyp == BOULDER) otmp->otrapped = 0;
+
+       if(impact) {
+           /* the objs impacted may be in a shop other than
+            * the one in which the hero is located.  another
+            * check for a shk is made in impact_drop.  it is, e.g.,
+            * possible to kick/throw an object belonging to one
+            * shop into another shop through a gap in the wall,
+            * and cause objects belonging to the other shop to
+            * fall down a trap door--thereby getting two shopkeepers
+            * angry at the hero in one shot.
+            */
+           impact_drop(otmp, x, y, 0);
+           newsym(x,y);
+       }
+       return(TRUE);
+}
+
+void
+obj_delivery()
+{
+       register struct obj *otmp, *otmp2;
+       register int nx, ny;
+       long where;
+
+       for (otmp = migrating_objs; otmp; otmp = otmp2) {
+           otmp2 = otmp->nobj;
+           if (otmp->ox != u.uz.dnum || otmp->oy != u.uz.dlevel) continue;
+
+           obj_extract_self(otmp);
+           where = otmp->owornmask;            /* destination code */
+           otmp->owornmask = 0L;
+
+           switch ((int)where) {
+            case MIGR_STAIRS_UP:   nx = xupstair,  ny = yupstair;
+                               break;
+            case MIGR_LADDER_UP:   nx = xupladder,  ny = yupladder;
+                               break;
+            case MIGR_SSTAIRS:     nx = sstairs.sx,  ny = sstairs.sy;
+                               break;
+            case MIGR_NEAR_PLAYER: nx = u.ux,  ny = u.uy;
+                               break;
+            default:
+            case MIGR_RANDOM:      nx = ny = 0;
+                               break;
+           }
+           if (nx > 0) {
+               place_object(otmp, nx, ny);
+               stackobj(otmp);
+               (void)scatter(nx, ny, rnd(2), 0, otmp);
+           } else {            /* random location */
+               /* set dummy coordinates because there's no
+                  current position for rloco() to update */
+               otmp->ox = otmp->oy = 0;
+               rloco(otmp);
+           }
+       }
+}
+
+STATIC_OVL void
+otransit_msg(otmp, nodrop, num)
+register struct obj *otmp;
+register boolean nodrop;
+long num;
+{
+       char obuf[BUFSZ];
+
+       Sprintf(obuf, "%s%s",
+                (otmp->otyp == CORPSE &&
+                       type_is_pname(&mons[otmp->corpsenm])) ? "" : "The ",
+                xname(otmp));
+
+       if(num) { /* means: other objects are impacted */
+           Sprintf(eos(obuf), " %s %s object%s",
+                   otense(otmp, "hit"),
+                   num == 1L ? "another" : "other",
+                   num > 1L ? "s" : "");
+           if(nodrop)
+               Sprintf(eos(obuf), ".");
+           else
+               Sprintf(eos(obuf), " and %s %s.",
+                       otense(otmp, "fall"), gate_str);
+           pline("%s", obuf);
+       } else if(!nodrop)
+           pline("%s %s %s.", obuf, otense(otmp, "fall"), gate_str);
+}
+
+/* migration destination for objects which fall down to next level */
+schar
+down_gate(x, y)
+xchar x, y;
+{
+       struct trap *ttmp;
+
+       gate_str = 0;
+       /* this matches the player restriction in goto_level() */
+       if (on_level(&u.uz, &qstart_level) && !ok_to_quest())
+           return MIGR_NOWHERE;
+
+       if ((xdnstair == x && ydnstair == y) ||
+               (sstairs.sx == x && sstairs.sy == y && !sstairs.up)) {
+           gate_str = "down the stairs";
+           return (xdnstair == x && ydnstair == y) ?
+                   MIGR_STAIRS_UP : MIGR_SSTAIRS;
+       }
+       if (xdnladder == x && ydnladder == y) {
+           gate_str = "down the ladder";
+           return MIGR_LADDER_UP;
+       }
+
+       if (((ttmp = t_at(x, y)) != 0 && ttmp->tseen) &&
+               (ttmp->ttyp == TRAPDOOR || ttmp->ttyp == HOLE)) {
+           gate_str = (ttmp->ttyp == TRAPDOOR) ?
+                   "through the trap door" : "through the hole";
+           return MIGR_RANDOM;
+       }
+       return MIGR_NOWHERE;
+}
+
+/*dokick.c*/
diff --git a/src/dothrow.c b/src/dothrow.c
new file mode 100644 (file)
index 0000000..2c4389a
--- /dev/null
@@ -0,0 +1,1772 @@
+/*     SCCS Id: @(#)dothrow.c  3.4     2003/12/04      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* Contains code for 't' (throw) */
+
+#include "hack.h"
+#include "edog.h"
+
+STATIC_DCL int FDECL(throw_obj, (struct obj *,int));
+STATIC_DCL void NDECL(autoquiver);
+STATIC_DCL int FDECL(gem_accept, (struct monst *, struct obj *));
+STATIC_DCL void FDECL(tmiss, (struct obj *, struct monst *));
+STATIC_DCL int FDECL(throw_gold, (struct obj *));
+STATIC_DCL void FDECL(check_shop_obj, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P));
+STATIC_DCL void FDECL(breakobj, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P,BOOLEAN_P));
+STATIC_DCL void FDECL(breakmsg, (struct obj *,BOOLEAN_P));
+STATIC_DCL boolean FDECL(toss_up,(struct obj *, BOOLEAN_P));
+STATIC_DCL boolean FDECL(throwing_weapon, (struct obj *));
+STATIC_DCL void FDECL(sho_obj_return_to_u, (struct obj *obj));
+STATIC_DCL boolean FDECL(mhurtle_step, (genericptr_t,int,int));
+
+
+static NEARDATA const char toss_objs[] =
+       { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, WEAPON_CLASS, 0 };
+/* different default choices when wielding a sling (gold must be included) */
+static NEARDATA const char bullets[] =
+       { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, GEM_CLASS, 0 };
+
+struct obj *thrownobj = 0;     /* tracks an object until it lands */
+
+extern boolean notonhead;      /* for long worms */
+
+
+/* Throw the selected object, asking for direction */
+STATIC_OVL int
+throw_obj(obj, shotlimit)
+struct obj *obj;
+int shotlimit;
+{
+       struct obj *otmp;
+       int multishot = 1;
+       schar skill;
+       long wep_mask;
+       boolean twoweap;
+
+       /* ask "in what direction?" */
+#ifndef GOLDOBJ
+       if (!getdir((char *)0)) {
+               if (obj->oclass == COIN_CLASS) {
+                   u.ugold += obj->quan;
+                   flags.botl = 1;
+                   dealloc_obj(obj);
+               }
+               return(0);
+       }
+
+       if(obj->oclass == COIN_CLASS) return(throw_gold(obj));
+#else
+       if (!getdir((char *)0)) {
+           /* obj might need to be merged back into the singular gold object */
+           freeinv(obj);
+           addinv(obj);
+           return(0);
+       }
+
+        /*
+         Throwing money is usually for getting rid of it when
+          a leprechaun approaches, or for bribing an oncoming 
+          angry monster.  So throw the whole object.
+
+          If the money is in quiver, throw one coin at a time,
+          possibly using a sling.
+        */
+       if(obj->oclass == COIN_CLASS && obj != uquiver) return(throw_gold(obj));
+#endif
+
+       if(!canletgo(obj,"throw"))
+               return(0);
+       if (obj->oartifact == ART_MJOLLNIR && obj != uwep) {
+           pline("%s must be wielded before it can be thrown.",
+               The(xname(obj)));
+               return(0);
+       }
+       if ((obj->oartifact == ART_MJOLLNIR && ACURR(A_STR) < STR19(25))
+          || (obj->otyp == BOULDER && !throws_rocks(youmonst.data))) {
+               pline("It's too heavy.");
+               return(1);
+       }
+       if(!u.dx && !u.dy && !u.dz) {
+               You("cannot throw an object at yourself.");
+               return(0);
+       }
+       u_wipe_engr(2);
+       if (!uarmg && !Stone_resistance && (obj->otyp == CORPSE &&
+                   touch_petrifies(&mons[obj->corpsenm]))) {
+               You("throw the %s corpse with your bare %s.",
+                   mons[obj->corpsenm].mname, body_part(HAND));
+               Sprintf(killer_buf, "%s corpse", an(mons[obj->corpsenm].mname));
+               instapetrify(killer_buf);
+       }
+       if (welded(obj)) {
+               weldmsg(obj);
+               return 1;
+       }
+
+       /* Multishot calculations
+        */
+       skill = objects[obj->otyp].oc_skill;
+       if ((ammo_and_launcher(obj, uwep) || skill == P_DAGGER ||
+                       skill == -P_DART || skill == -P_SHURIKEN) &&
+               !(Confusion || Stunned)) {
+           /* Bonus if the player is proficient in this weapon... */
+           switch (P_SKILL(weapon_type(obj))) {
+           default:    break; /* No bonus */
+           case P_SKILLED:     multishot++; break;
+           case P_EXPERT:      multishot += 2; break;
+           }
+           /* ...or is using a special weapon for their role... */
+           switch (Role_switch) {
+           case PM_RANGER:
+               multishot++;
+               break;
+           case PM_ROGUE:
+               if (skill == P_DAGGER) multishot++;
+               break;
+           case PM_SAMURAI:
+               if (obj->otyp == YA && uwep && uwep->otyp == YUMI) multishot++;
+               break;
+           default:
+               break;  /* No bonus */
+           }
+           /* ...or using their race's special bow */
+           switch (Race_switch) {
+           case PM_ELF:
+               if (obj->otyp == ELVEN_ARROW && uwep &&
+                               uwep->otyp == ELVEN_BOW) multishot++;
+               break;
+           case PM_ORC:
+               if (obj->otyp == ORCISH_ARROW && uwep &&
+                               uwep->otyp == ORCISH_BOW) multishot++;
+               break;
+           default:
+               break;  /* No bonus */
+           }
+       }
+
+       if ((long)multishot > obj->quan) multishot = (int)obj->quan;
+       multishot = rnd(multishot);
+       if (shotlimit > 0 && multishot > shotlimit) multishot = shotlimit;
+
+       m_shot.s = ammo_and_launcher(obj,uwep) ? TRUE : FALSE;
+       /* give a message if shooting more than one, or if player
+          attempted to specify a count */
+       if (multishot > 1 || shotlimit > 0) {
+           /* "You shoot N arrows." or "You throw N daggers." */
+           You("%s %d %s.",
+               m_shot.s ? "shoot" : "throw",
+               multishot,      /* (might be 1 if player gave shotlimit) */
+               (multishot == 1) ? singular(obj, xname) :  xname(obj));
+       }
+
+       wep_mask = obj->owornmask;
+       m_shot.o = obj->otyp;
+       m_shot.n = multishot;
+       for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
+           twoweap = u.twoweap;
+           /* split this object off from its slot if necessary */
+           if (obj->quan > 1L) {
+               otmp = splitobj(obj, 1L);
+           } else {
+               otmp = obj;
+               if (otmp->owornmask)
+                   remove_worn_item(otmp, FALSE);
+           }
+           freeinv(otmp);
+           throwit(otmp, wep_mask, twoweap);
+       }
+       m_shot.n = m_shot.i = 0;
+       m_shot.o = STRANGE_OBJECT;
+       m_shot.s = FALSE;
+
+       return 1;
+}
+
+
+int
+dothrow()
+{
+       register struct obj *obj;
+       int shotlimit;
+
+       /*
+        * Since some characters shoot multiple missiles at one time,
+        * allow user to specify a count prefix for 'f' or 't' to limit
+        * number of items thrown (to avoid possibly hitting something
+        * behind target after killing it, or perhaps to conserve ammo).
+        *
+        * Prior to 3.3.0, command ``3t'' meant ``t(shoot) t(shoot) t(shoot)''
+        * and took 3 turns.  Now it means ``t(shoot at most 3 missiles)''.
+        */
+       /* kludge to work around parse()'s pre-decrement of `multi' */
+       shotlimit = (multi || save_cm) ? multi + 1 : 0;
+       multi = 0;              /* reset; it's been used up */
+
+       if (notake(youmonst.data)) {
+           You("are physically incapable of throwing anything.");
+           return 0;
+       }
+
+       if(check_capacity((char *)0)) return(0);
+       obj = getobj(uslinging() ? bullets : toss_objs, "throw");
+       /* it is also possible to throw food */
+       /* (or jewels, or iron balls... ) */
+
+       if (!obj) return(0);
+       return throw_obj(obj, shotlimit);
+}
+
+
+/* KMH -- Automatically fill quiver */
+/* Suggested by Jeffrey Bay <jbay@convex.hp.com> */
+static void
+autoquiver()
+{
+       struct obj *otmp, *oammo = 0, *omissile = 0, *omisc = 0, *altammo = 0;
+
+       if (uquiver)
+           return;
+
+       /* Scan through the inventory */
+       for (otmp = invent; otmp; otmp = otmp->nobj) {
+           if (otmp->owornmask || otmp->oartifact || !otmp->dknown) {
+               ;       /* Skip it */
+           } else if (otmp->otyp == ROCK ||
+                       /* seen rocks or known flint or known glass */
+                       (objects[otmp->otyp].oc_name_known &&
+                        otmp->otyp == FLINT) ||
+                       (objects[otmp->otyp].oc_name_known &&
+                        otmp->oclass == GEM_CLASS &&
+                        objects[otmp->otyp].oc_material == GLASS)) {
+               if (uslinging())
+                   oammo = otmp;
+               else if (ammo_and_launcher(otmp, uswapwep))
+                   altammo = otmp;
+               else if (!omisc)
+                   omisc = otmp;
+           } else if (otmp->oclass == GEM_CLASS) {
+               ;       /* skip non-rock gems--they're ammo but
+                          player has to select them explicitly */
+           } else if (is_ammo(otmp)) {
+               if (ammo_and_launcher(otmp, uwep))
+                   /* Ammo matched with launcher (bow and arrow, crossbow and bolt) */
+                   oammo = otmp;
+               else if (ammo_and_launcher(otmp, uswapwep))
+                   altammo = otmp;
+               else
+                   /* Mismatched ammo (no better than an ordinary weapon) */
+                   omisc = otmp;
+           } else if (is_missile(otmp)) {
+               /* Missile (dart, shuriken, etc.) */
+               omissile = otmp;
+           } else if (otmp->oclass == WEAPON_CLASS && throwing_weapon(otmp)) {
+               /* Ordinary weapon */
+               if (objects[otmp->otyp].oc_skill == P_DAGGER
+                       && !omissile) 
+                   omissile = otmp;
+               else
+                   omisc = otmp;
+           }
+       }
+
+       /* Pick the best choice */
+       if (oammo)
+           setuqwep(oammo);
+       else if (omissile)
+           setuqwep(omissile);
+       else if (altammo)
+           setuqwep(altammo);
+       else if (omisc)
+           setuqwep(omisc);
+
+       return;
+}
+
+
+/* Throw from the quiver */
+int
+dofire()
+{
+       int shotlimit;
+
+       if (notake(youmonst.data)) {
+           You("are physically incapable of doing that.");
+           return 0;
+       }
+
+       if(check_capacity((char *)0)) return(0);
+       if (!uquiver) {
+               if (!flags.autoquiver) {
+                       /* Don't automatically fill the quiver */
+                       You("have no ammunition readied!");
+                       return(dothrow());
+               }
+               autoquiver();
+               if (!uquiver) {
+                       You("have nothing appropriate for your quiver!");
+                       return(dothrow());
+               } else {
+                       You("fill your quiver:");
+                       prinv((char *)0, uquiver, 0L);
+               }
+       }
+
+       /*
+        * Since some characters shoot multiple missiles at one time,
+        * allow user to specify a count prefix for 'f' or 't' to limit
+        * number of items thrown (to avoid possibly hitting something
+        * behind target after killing it, or perhaps to conserve ammo).
+        *
+        * The number specified can never increase the number of missiles.
+        * Using ``5f'' when the shooting skill (plus RNG) dictates launch
+        * of 3 projectiles will result in 3 being shot, not 5.
+        */
+       /* kludge to work around parse()'s pre-decrement of `multi' */
+       shotlimit = (multi || save_cm) ? multi + 1 : 0;
+       multi = 0;              /* reset; it's been used up */
+
+       return throw_obj(uquiver, shotlimit);
+}
+
+
+/*
+ * Object hits floor at hero's feet.  Called from drop() and throwit().
+ */
+void
+hitfloor(obj)
+register struct obj *obj;
+{
+       if (IS_SOFT(levl[u.ux][u.uy].typ) || u.uinwater) {
+               dropy(obj);
+               return;
+       }
+       if (IS_ALTAR(levl[u.ux][u.uy].typ))
+               doaltarobj(obj);
+       else
+               pline("%s hit%s the %s.", Doname2(obj),
+                     (obj->quan == 1L) ? "s" : "", surface(u.ux,u.uy));
+
+       if (hero_breaks(obj, u.ux, u.uy, TRUE)) return;
+       if (ship_object(obj, u.ux, u.uy, FALSE)) return;
+       dropy(obj);
+       if (!u.uswallow) container_impact_dmg(obj);
+}
+
+/*
+ * Walk a path from src_cc to dest_cc, calling a proc for each location
+ * except the starting one.  If the proc returns FALSE, stop walking
+ * and return FALSE.  If stopped early, dest_cc will be the location
+ * before the failed callback.
+ */
+boolean
+walk_path(src_cc, dest_cc, check_proc, arg)
+    coord *src_cc;
+    coord *dest_cc;
+    boolean FDECL((*check_proc), (genericptr_t, int, int));
+    genericptr_t arg;
+{
+    int x, y, dx, dy, x_change, y_change, err, i, prev_x, prev_y;
+    boolean keep_going = TRUE;
+
+    /* Use Bresenham's Line Algorithm to walk from src to dest */
+    dx = dest_cc->x - src_cc->x;
+    dy = dest_cc->y - src_cc->y;
+    prev_x = x = src_cc->x;
+    prev_y = y = src_cc->y;
+
+    if (dx < 0) {
+       x_change = -1;
+       dx = -dx;
+    } else
+       x_change = 1;
+    if (dy < 0) {
+       y_change = -1;
+       dy = -dy;
+    } else
+       y_change = 1;
+
+    i = err = 0;
+    if (dx < dy) {
+       while (i++ < dy) {
+           prev_x = x;
+           prev_y = y;
+           y += y_change;
+           err += dx;
+           if (err >= dy) {
+               x += x_change;
+               err -= dy;
+           }
+       /* check for early exit condition */
+       if (!(keep_going = (*check_proc)(arg, x, y)))
+           break;
+       }
+    } else {
+       while (i++ < dx) {
+           prev_x = x;
+           prev_y = y;
+           x += x_change;
+           err += dy;
+           if (err >= dx) {
+               y += y_change;
+               err -= dx;
+           }
+       /* check for early exit condition */
+       if (!(keep_going = (*check_proc)(arg, x, y)))
+           break;
+       }
+    }
+
+    if (keep_going)
+       return TRUE;    /* successful */
+
+    dest_cc->x = prev_x;
+    dest_cc->y = prev_y;
+    return FALSE;
+}
+
+/*
+ * Single step for the hero flying through the air from jumping, flying,
+ * etc.  Called from hurtle() and jump() via walk_path().  We expect the
+ * argument to be a pointer to an integer -- the range -- which is
+ * used in the calculation of points off if we hit something.
+ *
+ * Bumping into monsters won't cause damage but will wake them and make
+ * them angry.  Auto-pickup isn't done, since you don't have control over
+ * your movements at the time.
+ *
+ * Possible additions/changes:
+ *     o really attack monster if we hit one
+ *     o set stunned if we hit a wall or door
+ *     o reset nomul when we stop
+ *     o creepy feeling if pass through monster (if ever implemented...)
+ *     o bounce off walls
+ *     o let jumps go over boulders
+ */
+boolean
+hurtle_step(arg, x, y)
+    genericptr_t arg;
+    int x, y;
+{
+    int ox, oy, *range = (int *)arg;
+    struct obj *obj;
+    struct monst *mon;
+    boolean may_pass = TRUE;
+    struct trap *ttmp;
+    
+    if (!isok(x,y)) {
+       You_feel("the spirits holding you back.");
+       return FALSE;
+    } else if (!in_out_region(x, y)) {
+       return FALSE;
+    } else if (*range == 0) {
+       return FALSE;                   /* previous step wants to stop now */
+    }
+
+    if (!Passes_walls || !(may_pass = may_passwall(x, y))) {
+       if (IS_ROCK(levl[x][y].typ) || closed_door(x,y)) {
+           const char *s;
+
+           pline("Ouch!");
+           if (IS_TREE(levl[x][y].typ))
+               s = "bumping into a tree";
+           else if (IS_ROCK(levl[x][y].typ))
+               s = "bumping into a wall";
+           else
+               s = "bumping into a door";
+           losehp(rnd(2+*range), s, KILLED_BY);
+           return FALSE;
+       }
+       if (levl[x][y].typ == IRONBARS) {
+           You("crash into some iron bars.  Ouch!");
+           losehp(rnd(2+*range), "crashing into iron bars", KILLED_BY);
+           return FALSE;
+       }
+       if ((obj = sobj_at(BOULDER,x,y)) != 0) {
+           You("bump into a %s.  Ouch!", xname(obj));
+           losehp(rnd(2+*range), "bumping into a boulder", KILLED_BY);
+           return FALSE;
+       }
+       if (!may_pass) {
+           /* did we hit a no-dig non-wall position? */
+           You("smack into something!");
+           losehp(rnd(2+*range), "touching the edge of the universe", KILLED_BY);
+           return FALSE;
+       }
+       if ((u.ux - x) && (u.uy - y) &&
+               bad_rock(youmonst.data,u.ux,y) && bad_rock(youmonst.data,x,u.uy)) {
+           boolean too_much = (invent && (inv_weight() + weight_cap() > 600));
+           /* Move at a diagonal. */
+           if (bigmonst(youmonst.data) || too_much) {
+               You("%sget forcefully wedged into a crevice.",
+                       too_much ? "and all your belongings " : "");
+               losehp(rnd(2+*range), "wedging into a narrow crevice", KILLED_BY);
+               return FALSE;
+           }
+       }
+    }
+
+    if ((mon = m_at(x, y)) != 0) {
+       You("bump into %s.", a_monnam(mon));
+       wakeup(mon);
+       return FALSE;
+    }
+    if ((u.ux - x) && (u.uy - y) &&
+       bad_rock(youmonst.data,u.ux,y) && bad_rock(youmonst.data,x,u.uy)) {
+       /* Move at a diagonal. */
+       if (In_sokoban(&u.uz)) {
+           You("come to an abrupt halt!");
+           return FALSE;
+       }
+    }
+
+    ox = u.ux;
+    oy = u.uy;
+    u.ux = x;
+    u.uy = y;
+    newsym(ox, oy);            /* update old position */
+    vision_recalc(1);          /* update for new position */
+    flush_screen(1);
+    /* FIXME:
+     * Each trap should really trigger on the recoil if
+     * it would trigger during normal movement. However,
+     * not all the possible side-effects of this are
+     * tested [as of 3.4.0] so we trigger those that
+     * we have tested, and offer a message for the
+     * ones that we have not yet tested.
+     */
+    if ((ttmp = t_at(x, y)) != 0) {
+       if (ttmp->ttyp == MAGIC_PORTAL) {
+               dotrap(ttmp,0);
+               return FALSE;
+       } else if (ttmp->ttyp == FIRE_TRAP) {
+               dotrap(ttmp,0);
+       } else if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT ||
+                   ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR) &&
+                  In_sokoban(&u.uz)) {
+               /* Air currents overcome the recoil */
+               dotrap(ttmp,0);
+               *range = 0;
+               return TRUE;
+       } else {
+               if (ttmp->tseen)
+                   You("pass right over %s %s.",
+                       (ttmp->ttyp == ARROW_TRAP) ? "an" : "a",
+                       defsyms[trap_to_defsym(ttmp->ttyp)].explanation);
+       }
+    }
+    if (--*range < 0)          /* make sure our range never goes negative */
+       *range = 0;
+    if (*range != 0)
+       delay_output();
+    return TRUE;
+}
+
+STATIC_OVL boolean
+mhurtle_step(arg, x, y)
+    genericptr_t arg;
+    int x, y;
+{
+       struct monst *mon = (struct monst *)arg;
+
+       /* TODO: Treat walls, doors, iron bars, pools, lava, etc. specially
+        * rather than just stopping before.
+        */
+       if (goodpos(x, y, mon, 0) && m_in_out_region(mon, x, y)) {
+           remove_monster(mon->mx, mon->my);
+           newsym(mon->mx, mon->my);
+           place_monster(mon, x, y);
+           newsym(mon->mx, mon->my);
+           set_apparxy(mon);
+           (void) mintrap(mon);
+           return TRUE;
+       }
+       return FALSE;
+}
+
+/*
+ * The player moves through the air for a few squares as a result of
+ * throwing or kicking something.
+ *
+ * dx and dy should be the direction of the hurtle, not of the original
+ * kick or throw and be only.
+ */
+void
+hurtle(dx, dy, range, verbose)
+    int dx, dy, range;
+    boolean verbose;
+{
+    coord uc, cc;
+
+    /* The chain is stretched vertically, so you shouldn't be able to move
+     * very far diagonally.  The premise that you should be able to move one
+     * spot leads to calculations that allow you to only move one spot away
+     * from the ball, if you are levitating over the ball, or one spot
+     * towards the ball, if you are at the end of the chain.  Rather than
+     * bother with all of that, assume that there is no slack in the chain
+     * for diagonal movement, give the player a message and return.
+     */
+    if(Punished && !carried(uball)) {
+       You_feel("a tug from the iron ball.");
+       nomul(0);
+       return;
+    } else if (u.utrap) {
+       You("are anchored by the %s.",
+           u.utraptype == TT_WEB ? "web" : u.utraptype == TT_LAVA ? "lava" :
+               u.utraptype == TT_INFLOOR ? surface(u.ux,u.uy) : "trap");
+       nomul(0);
+       return;
+    }
+
+    /* make sure dx and dy are [-1,0,1] */
+    dx = sgn(dx);
+    dy = sgn(dy);
+
+    if(!range || (!dx && !dy) || u.ustuck) return; /* paranoia */
+
+    nomul(-range);
+    if (verbose)
+       You("%s in the opposite direction.", range > 1 ? "hurtle" : "float");
+    /* if we're in the midst of shooting multiple projectiles, stop */
+    if (m_shot.i < m_shot.n) {
+       /* last message before hurtling was "you shoot N arrows" */
+       You("stop %sing after the first %s.",
+           m_shot.s ? "shoot" : "throw", m_shot.s ? "shot" : "toss");
+       m_shot.n = m_shot.i;    /* make current shot be the last */
+    }
+    if (In_sokoban(&u.uz))
+       change_luck(-1);        /* Sokoban guilt */
+    uc.x = u.ux;
+    uc.y = u.uy;
+    /* this setting of cc is only correct if dx and dy are [-1,0,1] only */
+    cc.x = u.ux + (dx * range);
+    cc.y = u.uy + (dy * range);
+    (void) walk_path(&uc, &cc, hurtle_step, (genericptr_t)&range);
+}
+
+/* Move a monster through the air for a few squares.
+ */
+void
+mhurtle(mon, dx, dy, range)
+       struct monst *mon;
+       int dx, dy, range;
+{
+    coord mc, cc;
+
+       /* At the very least, debilitate the monster */
+       mon->movement = 0;
+       mon->mstun = 1;
+
+       /* Is the monster stuck or too heavy to push?
+        * (very large monsters have too much inertia, even floaters and flyers)
+        */
+       if (mon->data->msize >= MZ_HUGE || mon == u.ustuck || mon->mtrapped)
+           return;
+
+    /* Make sure dx and dy are [-1,0,1] */
+    dx = sgn(dx);
+    dy = sgn(dy);
+    if(!range || (!dx && !dy)) return; /* paranoia */
+
+       /* Send the monster along the path */
+       mc.x = mon->mx;
+       mc.y = mon->my;
+       cc.x = mon->mx + (dx * range);
+       cc.y = mon->my + (dy * range);
+       (void) walk_path(&mc, &cc, mhurtle_step, (genericptr_t)mon);
+       return;
+}
+
+STATIC_OVL void
+check_shop_obj(obj, x, y, broken)
+register struct obj *obj;
+register xchar x, y;
+register boolean broken;
+{
+       struct monst *shkp = shop_keeper(*u.ushops);
+
+       if(!shkp) return;
+
+       if(broken) {
+               if (obj->unpaid) {
+                   (void)stolen_value(obj, u.ux, u.uy,
+                                      (boolean)shkp->mpeaceful, FALSE);
+                   subfrombill(obj, shkp);
+               }
+               obj->no_charge = 1;
+               return;
+       }
+
+       if (!costly_spot(x, y) || *in_rooms(x, y, SHOPBASE) != *u.ushops) {
+               /* thrown out of a shop or into a different shop */
+               if (obj->unpaid) {
+                   (void)stolen_value(obj, u.ux, u.uy,
+                                      (boolean)shkp->mpeaceful, FALSE);
+                   subfrombill(obj, shkp);
+               }
+       } else {
+               if (costly_spot(u.ux, u.uy) && costly_spot(x, y)) {
+                   if(obj->unpaid) subfrombill(obj, shkp);
+                   else if(!(x == shkp->mx && y == shkp->my))
+                           sellobj(obj, x, y);
+               }
+       }
+}
+
+/*
+ * Hero tosses an object upwards with appropriate consequences.
+ *
+ * Returns FALSE if the object is gone.
+ */
+STATIC_OVL boolean
+toss_up(obj, hitsroof)
+struct obj *obj;
+boolean hitsroof;
+{
+    const char *almost;
+    /* note: obj->quan == 1 */
+
+    if (hitsroof) {
+       if (breaktest(obj)) {
+               pline("%s hits the %s.", Doname2(obj), ceiling(u.ux, u.uy));
+               breakmsg(obj, !Blind);
+               breakobj(obj, u.ux, u.uy, TRUE, TRUE);
+               return FALSE;
+       }
+       almost = "";
+    } else {
+       almost = " almost";
+    }
+    pline("%s%s hits the %s, then falls back on top of your %s.",
+         Doname2(obj), almost, ceiling(u.ux,u.uy), body_part(HEAD));
+
+    /* object now hits you */
+
+    if (obj->oclass == POTION_CLASS) {
+       potionhit(&youmonst, obj, TRUE);
+    } else if (breaktest(obj)) {
+       int otyp = obj->otyp, ocorpsenm = obj->corpsenm;
+       int blindinc;
+
+       /* need to check for blindness result prior to destroying obj */
+       blindinc = (otyp == CREAM_PIE || otyp == BLINDING_VENOM) &&
+                  /* AT_WEAP is ok here even if attack type was AT_SPIT */
+                  can_blnd(&youmonst, &youmonst, AT_WEAP, obj) ? rnd(25) : 0;
+
+       breakmsg(obj, !Blind);
+       breakobj(obj, u.ux, u.uy, TRUE, TRUE);
+       obj = 0;        /* it's now gone */
+       switch (otyp) {
+       case EGG:
+               if (touch_petrifies(&mons[ocorpsenm]) &&
+                   !uarmh && !Stone_resistance &&
+                   !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)))
+               goto petrify;
+       case CREAM_PIE:
+       case BLINDING_VENOM:
+               pline("You've got it all over your %s!", body_part(FACE));
+               if (blindinc) {
+                   if (otyp == BLINDING_VENOM && !Blind)
+                       pline("It blinds you!");
+                   u.ucreamed += blindinc;
+                   make_blinded(Blinded + (long)blindinc, FALSE);
+                   if (!Blind) Your(vision_clears);
+               }
+               break;
+       default:
+               break;
+       }
+       return FALSE;
+    } else {           /* neither potion nor other breaking object */
+       boolean less_damage = uarmh && is_metallic(uarmh), artimsg = FALSE;
+       int dmg = dmgval(obj, &youmonst);
+
+       if (obj->oartifact)
+           /* need a fake die roll here; rn1(18,2) avoids 1 and 20 */
+           artimsg = artifact_hit((struct monst *)0, &youmonst,
+                                  obj, &dmg, rn1(18,2));
+
+       if (!dmg) {     /* probably wasn't a weapon; base damage on weight */
+           dmg = (int) obj->owt / 100;
+           if (dmg < 1) dmg = 1;
+           else if (dmg > 6) dmg = 6;
+           if (youmonst.data == &mons[PM_SHADE] &&
+                   objects[obj->otyp].oc_material != SILVER)
+               dmg = 0;
+       }
+       if (dmg > 1 && less_damage) dmg = 1;
+       if (dmg > 0) dmg += u.udaminc;
+       if (dmg < 0) dmg = 0;   /* beware negative rings of increase damage */
+       if (Half_physical_damage) dmg = (dmg + 1) / 2;
+
+       if (uarmh) {
+           if (less_damage && dmg < (Upolyd ? u.mh : u.uhp)) {
+               if (!artimsg)
+                   pline("Fortunately, you are wearing a hard helmet.");
+           } else if (flags.verbose &&
+                   !(obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])))
+               Your("%s does not protect you.", xname(uarmh));
+       } else if (obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])) {
+           if (!Stone_resistance &&
+                   !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
+ petrify:
+               killer_format = KILLED_BY;
+               killer = "elementary physics";  /* "what goes up..." */
+               You("turn to stone.");
+               if (obj) dropy(obj);    /* bypass most of hitfloor() */
+               done(STONING);
+               return obj ? TRUE : FALSE;
+           }
+       }
+       hitfloor(obj);
+       losehp(dmg, "falling object", KILLED_BY_AN);
+    }
+    return TRUE;
+}
+
+/* return true for weapon meant to be thrown; excludes ammo */
+STATIC_OVL boolean
+throwing_weapon(obj)
+struct obj *obj;
+{
+       return (is_missile(obj) || is_spear(obj) ||
+               /* daggers and knife (excludes scalpel) */
+               (is_blade(obj) && !is_sword(obj) &&
+                (objects[obj->otyp].oc_dir & PIERCE)) ||
+               /* special cases [might want to add AXE] */
+               obj->otyp == WAR_HAMMER || obj->otyp == AKLYS);
+}
+
+/* the currently thrown object is returning to you (not for boomerangs) */
+STATIC_OVL void
+sho_obj_return_to_u(obj)
+struct obj *obj;
+{
+    /* might already be our location (bounced off a wall) */
+    if (bhitpos.x != u.ux || bhitpos.y != u.uy) {
+       int x = bhitpos.x - u.dx, y = bhitpos.y - u.dy;
+
+       tmp_at(DISP_FLASH, obj_to_glyph(obj));
+       while(x != u.ux || y != u.uy) {
+           tmp_at(x, y);
+           delay_output();
+           x -= u.dx; y -= u.dy;
+       }
+       tmp_at(DISP_END, 0);
+    }
+}
+
+void
+throwit(obj, wep_mask, twoweap)
+register struct obj *obj;
+long wep_mask; /* used to re-equip returning boomerang */
+boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
+{
+       register struct monst *mon;
+       register int range, urange;
+       boolean impaired = (Confusion || Stunned || Blind ||
+                          Hallucination || Fumbling);
+
+       if ((obj->cursed || obj->greased) && (u.dx || u.dy) && !rn2(7)) {
+           boolean slipok = TRUE;
+           if (ammo_and_launcher(obj, uwep))
+               pline("%s!", Tobjnam(obj, "misfire"));
+           else {
+               /* only slip if it's greased or meant to be thrown */
+               if (obj->greased || throwing_weapon(obj))
+                   /* BUG: this message is grammatically incorrect if obj has
+                      a plural name; greased gloves or boots for instance. */
+                   pline("%s as you throw it!", Tobjnam(obj, "slip"));
+               else slipok = FALSE;
+           }
+           if (slipok) {
+               u.dx = rn2(3)-1;
+               u.dy = rn2(3)-1;
+               if (!u.dx && !u.dy) u.dz = 1;
+               impaired = TRUE;
+           }
+       }
+
+       if ((u.dx || u.dy || (u.dz < 1)) &&
+           calc_capacity((int)obj->owt) > SLT_ENCUMBER &&
+           (Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
+            : (u.uhp < 10 && u.uhp != u.uhpmax)) &&
+           obj->owt > (unsigned)((Upolyd ? u.mh : u.uhp) * 2) &&
+           !Is_airlevel(&u.uz)) {
+           You("have so little stamina, %s drops from your grasp.",
+               the(xname(obj)));
+           exercise(A_CON, FALSE);
+           u.dx = u.dy = 0;
+           u.dz = 1;
+       }
+
+       thrownobj = obj;
+
+       if(u.uswallow) {
+               mon = u.ustuck;
+               bhitpos.x = mon->mx;
+               bhitpos.y = mon->my;
+       } else if(u.dz) {
+           if (u.dz < 0 && Role_if(PM_VALKYRIE) &&
+                   obj->oartifact == ART_MJOLLNIR && !impaired) {
+               pline("%s the %s and returns to your hand!",
+                     Tobjnam(obj, "hit"), ceiling(u.ux,u.uy));
+               obj = addinv(obj);
+               (void) encumber_msg();
+               setuwep(obj);
+               u.twoweap = twoweap;
+           } else if (u.dz < 0 && !Is_airlevel(&u.uz) &&
+                   !Underwater && !Is_waterlevel(&u.uz)) {
+               (void) toss_up(obj, rn2(5));
+           } else {
+               hitfloor(obj);
+           }
+           thrownobj = (struct obj*)0;
+           return;
+
+       } else if(obj->otyp == BOOMERANG && !Underwater) {
+               if(Is_airlevel(&u.uz) || Levitation)
+                   hurtle(-u.dx, -u.dy, 1, TRUE);
+               mon = boomhit(u.dx, u.dy);
+               if(mon == &youmonst) {          /* the thing was caught */
+                       exercise(A_DEX, TRUE);
+                       obj = addinv(obj);
+                       (void) encumber_msg();
+                       if (wep_mask && !(obj->owornmask & wep_mask)) {
+                           setworn(obj, wep_mask);
+                           u.twoweap = twoweap;
+                       }
+                       thrownobj = (struct obj*)0;
+                       return;
+               }
+       } else {
+               urange = (int)(ACURRSTR)/2;
+               /* balls are easy to throw or at least roll */
+               /* also, this insures the maximum range of a ball is greater
+                * than 1, so the effects from throwing attached balls are
+                * actually possible
+                */
+               if (obj->otyp == HEAVY_IRON_BALL)
+                       range = urange - (int)(obj->owt/100);
+               else
+                       range = urange - (int)(obj->owt/40);
+               if (obj == uball) {
+                       if (u.ustuck) range = 1;
+                       else if (range >= 5) range = 5;
+               }
+               if (range < 1) range = 1;
+
+               if (is_ammo(obj)) {
+                   if (ammo_and_launcher(obj, uwep))
+                       range++;
+                   else if (obj->oclass != GEM_CLASS)
+                       range /= 2;
+               }
+
+               if (Is_airlevel(&u.uz) || Levitation) {
+                   /* action, reaction... */
+                   urange -= range;
+                   if(urange < 1) urange = 1;
+                   range -= urange;
+                   if(range < 1) range = 1;
+               }
+
+               if (obj->otyp == BOULDER)
+                   range = 20;         /* you must be giant */
+               else if (obj->oartifact == ART_MJOLLNIR)
+                   range = (range + 1) / 2;    /* it's heavy */
+               else if (obj == uball && u.utrap && u.utraptype == TT_INFLOOR)
+                   range = 1;
+
+               if (Underwater) range = 1;
+
+               mon = bhit(u.dx, u.dy, range, THROWN_WEAPON,
+                          (int FDECL((*),(MONST_P,OBJ_P)))0,
+                          (int FDECL((*),(OBJ_P,OBJ_P)))0,
+                          obj);
+
+               /* have to do this after bhit() so u.ux & u.uy are correct */
+               if(Is_airlevel(&u.uz) || Levitation)
+                   hurtle(-u.dx, -u.dy, urange, TRUE);
+       }
+
+       if (mon) {
+               boolean obj_gone;
+
+               if (mon->isshk &&
+                   obj->where == OBJ_MINVENT && obj->ocarry == mon) {
+                   thrownobj = (struct obj*)0;
+                   return;             /* alert shk caught it */
+               }
+               (void) snuff_candle(obj);
+               notonhead = (bhitpos.x != mon->mx || bhitpos.y != mon->my);
+               obj_gone = thitmonst(mon, obj);
+               /* Monster may have been tamed; this frees old mon */
+               mon = m_at(bhitpos.x, bhitpos.y);
+
+               /* [perhaps this should be moved into thitmonst or hmon] */
+               if (mon && mon->isshk &&
+                       (!inside_shop(u.ux, u.uy) ||
+                        !index(in_rooms(mon->mx, mon->my, SHOPBASE), *u.ushops)))
+                   hot_pursuit(mon);
+
+               if (obj_gone) return;
+       }
+
+       if (u.uswallow) {
+               /* ball is not picked up by monster */
+               if (obj != uball) (void) mpickobj(u.ustuck,obj);
+       } else {
+               /* the code following might become part of dropy() */
+               if (obj->oartifact == ART_MJOLLNIR &&
+                       Role_if(PM_VALKYRIE) && rn2(100)) {
+                   /* we must be wearing Gauntlets of Power to get here */
+                   sho_obj_return_to_u(obj);       /* display its flight */
+
+                   if (!impaired && rn2(100)) {
+                       pline("%s to your hand!", Tobjnam(obj, "return"));
+                       obj = addinv(obj);
+                       (void) encumber_msg();
+                       setuwep(obj);
+                       u.twoweap = twoweap;
+                       if(cansee(bhitpos.x, bhitpos.y))
+                           newsym(bhitpos.x,bhitpos.y);
+                   } else {
+                       int dmg = rn2(2);
+                       if (!dmg) {
+                           pline(Blind ? "%s lands %s your %s." :
+                                       "%s back to you, landing %s your %s.",
+                                 Blind ? Something : Tobjnam(obj, "return"),
+                                 Levitation ? "beneath" : "at",
+                                 makeplural(body_part(FOOT)));
+                       } else {
+                           dmg += rnd(3);
+                           pline(Blind ? "%s your %s!" :
+                                       "%s back toward you, hitting your %s!",
+                                 Tobjnam(obj, Blind ? "hit" : "fly"),
+                                 body_part(ARM));
+                           (void) artifact_hit((struct monst *)0,
+                                               &youmonst, obj, &dmg, 0);
+                           losehp(dmg, xname(obj),
+                               obj_is_pname(obj) ? KILLED_BY : KILLED_BY_AN);
+                       }
+                       if (ship_object(obj, u.ux, u.uy, FALSE)) {
+                           thrownobj = (struct obj*)0;
+                           return;
+                       }
+                       dropy(obj);
+                   }
+                   thrownobj = (struct obj*)0;
+                   return;
+               }
+
+               if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ) &&
+                       breaktest(obj)) {
+                   tmp_at(DISP_FLASH, obj_to_glyph(obj));
+                   tmp_at(bhitpos.x, bhitpos.y);
+                   delay_output();
+                   tmp_at(DISP_END, 0);
+                   breakmsg(obj, cansee(bhitpos.x, bhitpos.y));
+                   breakobj(obj, bhitpos.x, bhitpos.y, TRUE, TRUE);
+                   return;
+               }
+               if(flooreffects(obj,bhitpos.x,bhitpos.y,"fall")) return;
+               obj_no_longer_held(obj);
+               if (mon && mon->isshk && is_pick(obj)) {
+                   if (cansee(bhitpos.x, bhitpos.y))
+                       pline("%s snatches up %s.",
+                             Monnam(mon), the(xname(obj)));
+                   if(*u.ushops)
+                       check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
+                   (void) mpickobj(mon, obj);  /* may merge and free obj */
+                   thrownobj = (struct obj*)0;
+                   return;
+               }
+               (void) snuff_candle(obj);
+               if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) {
+                   thrownobj = (struct obj*)0;
+                   return;
+               }
+               thrownobj = (struct obj*)0;
+               place_object(obj, bhitpos.x, bhitpos.y);
+               if(*u.ushops && obj != uball)
+                   check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
+
+               stackobj(obj);
+               if (obj == uball)
+                   drop_ball(bhitpos.x, bhitpos.y);
+               if (cansee(bhitpos.x, bhitpos.y))
+                   newsym(bhitpos.x,bhitpos.y);
+               if (obj_sheds_light(obj))
+                   vision_full_recalc = 1;
+               if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ))
+                   container_impact_dmg(obj);
+       }
+}
+
+/* an object may hit a monster; various factors adjust the chance of hitting */
+int
+omon_adj(mon, obj, mon_notices)
+struct monst *mon;
+struct obj *obj;
+boolean mon_notices;
+{
+       int tmp = 0;
+
+       /* size of target affects the chance of hitting */
+       tmp += (mon->data->msize - MZ_MEDIUM);          /* -2..+5 */
+       /* sleeping target is more likely to be hit */
+       if (mon->msleeping) {
+           tmp += 2;
+           if (mon_notices) mon->msleeping = 0;
+       }
+       /* ditto for immobilized target */
+       if (!mon->mcanmove || !mon->data->mmove) {
+           tmp += 4;
+           if (mon_notices && mon->data->mmove && !rn2(10)) {
+               mon->mcanmove = 1;
+               mon->mfrozen = 0;
+           }
+       }
+       /* some objects are more likely to hit than others */
+       switch (obj->otyp) {
+       case HEAVY_IRON_BALL:
+           if (obj != uball) tmp += 2;
+           break;
+       case BOULDER:
+           tmp += 6;
+           break;
+       default:
+           if (obj->oclass == WEAPON_CLASS || is_weptool(obj) ||
+                   obj->oclass == GEM_CLASS)
+               tmp += hitval(obj, mon);
+           break;
+       }
+       return tmp;
+}
+
+/* thrown object misses target monster */
+STATIC_OVL void
+tmiss(obj, mon)
+struct obj *obj;
+struct monst *mon;
+{
+    const char *missile = mshot_xname(obj);
+
+    /* If the target can't be seen or doesn't look like a valid target,
+       avoid "the arrow misses it," or worse, "the arrows misses the mimic."
+       An attentive player will still notice that this is different from
+       an arrow just landing short of any target (no message in that case),
+       so will realize that there is a valid target here anyway. */
+    if (!canseemon(mon) || (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER))
+       pline("%s %s.", The(missile), otense(obj, "miss"));
+    else
+       miss(missile, mon);
+    if (!rn2(3)) wakeup(mon);
+    return;
+}
+
+#define quest_arti_hits_leader(obj,mon)        \
+  (obj->oartifact && is_quest_artifact(obj) && (mon->data->msound == MS_LEADER))
+
+/*
+ * Object thrown by player arrives at monster's location.
+ * Return 1 if obj has disappeared or otherwise been taken care of,
+ * 0 if caller must take care of it.
+ */
+int
+thitmonst(mon, obj)
+register struct monst *mon;
+register struct obj   *obj;
+{
+       register int    tmp; /* Base chance to hit */
+       register int    disttmp; /* distance modifier */
+       int otyp = obj->otyp;
+       boolean guaranteed_hit = (u.uswallow && mon == u.ustuck);
+
+       /* Differences from melee weapons:
+        *
+        * Dex still gives a bonus, but strength does not.
+        * Polymorphed players lacking attacks may still throw.
+        * There's a base -1 to hit.
+        * No bonuses for fleeing or stunned targets (they don't dodge
+        *    melee blows as readily, but dodging arrows is hard anyway).
+        * Not affected by traps, etc.
+        * Certain items which don't in themselves do damage ignore tmp.
+        * Distance and monster size affect chance to hit.
+        */
+       tmp = -1 + Luck + find_mac(mon) + u.uhitinc +
+                       maybe_polyd(youmonst.data->mlevel, u.ulevel);
+       if (ACURR(A_DEX) < 4) tmp -= 3;
+       else if (ACURR(A_DEX) < 6) tmp -= 2;
+       else if (ACURR(A_DEX) < 8) tmp -= 1;
+       else if (ACURR(A_DEX) >= 14) tmp += (ACURR(A_DEX) - 14);
+
+       /* Modify to-hit depending on distance; but keep it sane.
+        * Polearms get a distance penalty even when wielded; it's
+        * hard to hit at a distance.
+        */
+       disttmp = 3 - distmin(u.ux, u.uy, mon->mx, mon->my);
+       if(disttmp < -4) disttmp = -4;
+       tmp += disttmp;
+
+       /* gloves are a hinderance to proper use of bows */
+       if (uarmg && uwep && objects[uwep->otyp].oc_skill == P_BOW) {
+           switch (uarmg->otyp) {
+           case GAUNTLETS_OF_POWER:    /* metal */
+               tmp -= 2;
+               break;
+           case GAUNTLETS_OF_FUMBLING:
+               tmp -= 3;
+               break;
+           case LEATHER_GLOVES:
+           case GAUNTLETS_OF_DEXTERITY:
+               break;
+           default:
+               impossible("Unknown type of gloves (%d)", uarmg->otyp);
+               break;
+           }
+       }
+
+       tmp += omon_adj(mon, obj, TRUE);
+       if (is_orc(mon->data) && maybe_polyd(is_elf(youmonst.data),
+                       Race_if(PM_ELF)))
+           tmp++;
+       if (guaranteed_hit) {
+           tmp += 1000; /* Guaranteed hit */
+       }
+
+       if (obj->oclass == GEM_CLASS && is_unicorn(mon->data)) {
+           if (mon->mtame) {
+               pline("%s catches and drops %s.", Monnam(mon), the(xname(obj)));
+               return 0;
+           } else {
+               pline("%s catches %s.", Monnam(mon), the(xname(obj)));
+               return gem_accept(mon, obj);
+           }
+       }
+
+       /* don't make game unwinnable if naive player throws artifact
+          at leader.... */
+       if (quest_arti_hits_leader(obj, mon)) {
+           /* not wakeup(), which angers non-tame monsters */
+           mon->msleeping = 0;
+           mon->mstrategy &= ~STRAT_WAITMASK;
+
+           if (mon->mcanmove) {
+               pline("%s catches %s.", Monnam(mon), the(xname(obj)));
+               if (mon->mpeaceful) {
+                   boolean next2u = monnear(mon, u.ux, u.uy);
+
+                   finish_quest(obj);  /* acknowledge quest completion */
+                   pline("%s %s %s back to you.", Monnam(mon),
+                         (next2u ? "hands" : "tosses"), the(xname(obj)));
+                   if (!next2u) sho_obj_return_to_u(obj);
+                   obj = addinv(obj);  /* back into your inventory */
+                   (void) encumber_msg();
+               } else {
+                   /* angry leader caught it and isn't returning it */
+                   (void) mpickobj(mon, obj);
+               }
+               return 1;               /* caller doesn't need to place it */
+           }
+           return(0);
+       }
+
+       if (obj->oclass == WEAPON_CLASS || is_weptool(obj) ||
+               obj->oclass == GEM_CLASS) {
+           if (is_ammo(obj)) {
+               if (!ammo_and_launcher(obj, uwep)) {
+                   tmp -= 4;
+               } else {
+                   tmp += uwep->spe - greatest_erosion(uwep);
+                   tmp += weapon_hit_bonus(uwep);
+                   if (uwep->oartifact) tmp += spec_abon(uwep, mon);
+                   /*
+                    * Elves and Samurais are highly trained w/bows,
+                    * especially their own special types of bow.
+                    * Polymorphing won't make you a bow expert.
+                    */
+                   if ((Race_if(PM_ELF) || Role_if(PM_SAMURAI)) &&
+                               (!Upolyd || your_race(youmonst.data)) &&
+                               objects[uwep->otyp].oc_skill == P_BOW) {
+                       tmp++;
+                       if (Race_if(PM_ELF) && uwep->otyp == ELVEN_BOW)
+                           tmp++;
+                       else if (Role_if(PM_SAMURAI) && uwep->otyp == YUMI)
+                           tmp++;
+                   }
+               }
+           } else {
+               if (otyp == BOOMERANG)          /* arbitrary */
+                   tmp += 4;
+               else if (throwing_weapon(obj))  /* meant to be thrown */
+                   tmp += 2;
+               else                            /* not meant to be thrown */
+                   tmp -= 2;
+               /* we know we're dealing with a weapon or weptool handled
+                  by WEAPON_SKILLS once ammo objects have been excluded */
+               tmp += weapon_hit_bonus(obj);
+           }
+
+           if (tmp >= rnd(20)) {
+               if (hmon(mon,obj,1)) {  /* mon still alive */
+                   cutworm(mon, bhitpos.x, bhitpos.y, obj);
+               }
+               exercise(A_DEX, TRUE);
+               /* projectiles other than magic stones
+                  sometimes disappear when thrown */
+               if (objects[otyp].oc_skill < P_NONE &&
+                               objects[otyp].oc_skill > -P_BOOMERANG &&
+                               !objects[otyp].oc_magic) {
+                   /* we were breaking 2/3 of everything unconditionally.
+                    * we still don't want anything to survive unconditionally,
+                    * but we need ammo to stay around longer on average.
+                    */
+                   int broken, chance;
+                   chance = 3 + greatest_erosion(obj) - obj->spe;
+                   if (chance > 1)
+                       broken = rn2(chance);
+                   else
+                       broken = !rn2(4);
+                   if (obj->blessed && !rnl(4))
+                       broken = 0;
+
+                   if (broken) {
+                       if (*u.ushops)
+                           check_shop_obj(obj, bhitpos.x,bhitpos.y, TRUE);
+                       obfree(obj, (struct obj *)0);
+                       return 1;
+                   }
+               }
+               passive_obj(mon, obj, (struct attack *)0);
+           } else {
+               tmiss(obj, mon);
+           }
+
+       } else if (otyp == HEAVY_IRON_BALL) {
+           exercise(A_STR, TRUE);
+           if (tmp >= rnd(20)) {
+               int was_swallowed = guaranteed_hit;
+
+               exercise(A_DEX, TRUE);
+               if (!hmon(mon,obj,1)) {         /* mon killed */
+                   if (was_swallowed && !u.uswallow && obj == uball)
+                       return 1;       /* already did placebc() */
+               }
+           } else {
+               tmiss(obj, mon);
+           }
+
+       } else if (otyp == BOULDER) {
+           exercise(A_STR, TRUE);
+           if (tmp >= rnd(20)) {
+               exercise(A_DEX, TRUE);
+               (void) hmon(mon,obj,1);
+           } else {
+               tmiss(obj, mon);
+           }
+
+       } else if ((otyp == EGG || otyp == CREAM_PIE ||
+                   otyp == BLINDING_VENOM || otyp == ACID_VENOM) &&
+               (guaranteed_hit || ACURR(A_DEX) > rnd(25))) {
+           (void) hmon(mon, obj, 1);
+           return 1;   /* hmon used it up */
+
+       } else if (obj->oclass == POTION_CLASS &&
+               (guaranteed_hit || ACURR(A_DEX) > rnd(25))) {
+           potionhit(mon, obj, TRUE);
+           return 1;
+
+       } else if (befriend_with_obj(mon->data, obj) ||
+                  (mon->mtame && dogfood(mon, obj) <= ACCFOOD)) {
+           if (tamedog(mon, obj))
+               return 1;               /* obj is gone */
+           else {
+               /* not tmiss(), which angers non-tame monsters */
+               miss(xname(obj), mon);
+               mon->msleeping = 0;
+               mon->mstrategy &= ~STRAT_WAITMASK;
+           }
+       } else if (guaranteed_hit) {
+           /* this assumes that guaranteed_hit is due to swallowing */
+           wakeup(mon);
+           if (obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])) {
+               if (is_animal(u.ustuck->data)) {
+                       minstapetrify(u.ustuck, TRUE);
+                       /* Don't leave a cockatrice corpse available in a statue */
+                       if (!u.uswallow) {
+                               delobj(obj);
+                               return 1;
+                       }
+               }
+           }
+           pline("%s into %s %s.",
+               Tobjnam(obj, "vanish"), s_suffix(mon_nam(mon)),
+               is_animal(u.ustuck->data) ? "entrails" : "currents");
+       } else {
+           tmiss(obj, mon);
+       }
+
+       return 0;
+}
+
+STATIC_OVL int
+gem_accept(mon, obj)
+register struct monst *mon;
+register struct obj *obj;
+{
+       char buf[BUFSZ];
+       boolean is_buddy = sgn(mon->data->maligntyp) == sgn(u.ualign.type);
+       boolean is_gem = objects[obj->otyp].oc_material == GEMSTONE;
+       int ret = 0;
+       static NEARDATA const char nogood[] = " is not interested in your junk.";
+       static NEARDATA const char acceptgift[] = " accepts your gift.";
+       static NEARDATA const char maybeluck[] = " hesitatingly";
+       static NEARDATA const char noluck[] = " graciously";
+       static NEARDATA const char addluck[] = " gratefully";
+
+       Strcpy(buf,Monnam(mon));
+       mon->mpeaceful = 1;
+       mon->mavenge = 0;
+
+       /* object properly identified */
+       if(obj->dknown && objects[obj->otyp].oc_name_known) {
+               if(is_gem) {
+                       if(is_buddy) {
+                               Strcat(buf,addluck);
+                               change_luck(5);
+                       } else {
+                               Strcat(buf,maybeluck);
+                               change_luck(rn2(7)-3);
+                       }
+               } else {
+                       Strcat(buf,nogood);
+                       goto nopick;
+               }
+       /* making guesses */
+       } else if(obj->onamelth || objects[obj->otyp].oc_uname) {
+               if(is_gem) {
+                       if(is_buddy) {
+                               Strcat(buf,addluck);
+                               change_luck(2);
+                       } else {
+                               Strcat(buf,maybeluck);
+                               change_luck(rn2(3)-1);
+                       }
+               } else {
+                       Strcat(buf,nogood);
+                       goto nopick;
+               }
+       /* value completely unknown to @ */
+       } else {
+               if(is_gem) {
+                       if(is_buddy) {
+                               Strcat(buf,addluck);
+                               change_luck(1);
+                       } else {
+                               Strcat(buf,maybeluck);
+                               change_luck(rn2(3)-1);
+                       }
+               } else {
+                       Strcat(buf,noluck);
+               }
+       }
+       Strcat(buf,acceptgift);
+       if(*u.ushops) check_shop_obj(obj, mon->mx, mon->my, TRUE);
+       (void) mpickobj(mon, obj);      /* may merge and free obj */
+       ret = 1;
+
+nopick:
+       if(!Blind) pline("%s", buf);
+       if (!tele_restrict(mon)) (void) rloc(mon, FALSE);
+       return(ret);
+}
+
+/*
+ * Comments about the restructuring of the old breaks() routine.
+ *
+ * There are now three distinct phases to object breaking:
+ *     breaktest() - which makes the check/decision about whether the
+ *                   object is going to break.
+ *     breakmsg()  - which outputs a message about the breakage,
+ *                   appropriate for that particular object. Should
+ *                   only be called after a positve breaktest().
+ *                   on the object and, if it going to be called,
+ *                   it must be called before calling breakobj().
+ *                   Calling breakmsg() is optional.
+ *     breakobj()  - which actually does the breakage and the side-effects
+ *                   of breaking that particular object. This should
+ *                   only be called after a positive breaktest() on the
+ *                   object.
+ *
+ * Each of the above routines is currently static to this source module.
+ * There are two routines callable from outside this source module which
+ * perform the routines above in the correct sequence.
+ *
+ *   hero_breaks() - called when an object is to be broken as a result
+ *                   of something that the hero has done. (throwing it,
+ *                   kicking it, etc.)
+ *   breaks()      - called when an object is to be broken for some
+ *                   reason other than the hero doing something to it.
+ */
+
+/*
+ * The hero causes breakage of an object (throwing, dropping it, etc.)
+ * Return 0 if the object didn't break, 1 if the object broke.
+ */
+int
+hero_breaks(obj, x, y, from_invent)
+struct obj *obj;
+xchar x, y;            /* object location (ox, oy may not be right) */
+boolean from_invent;   /* thrown or dropped by player; maybe on shop bill */
+{
+       boolean in_view = !Blind;
+       if (!breaktest(obj)) return 0;
+       breakmsg(obj, in_view);
+       breakobj(obj, x, y, TRUE, from_invent);
+       return 1;
+}
+
+/*
+ * The object is going to break for a reason other than the hero doing
+ * something to it.
+ * Return 0 if the object doesn't break, 1 if the object broke.
+ */
+int
+breaks(obj, x, y)
+struct obj *obj;
+xchar x, y;            /* object location (ox, oy may not be right) */
+{
+       boolean in_view = Blind ? FALSE : cansee(x, y);
+
+       if (!breaktest(obj)) return 0;
+       breakmsg(obj, in_view);
+       breakobj(obj, x, y, FALSE, FALSE);
+       return 1;
+}
+
+/*
+ * Unconditionally break an object. Assumes all resistance checks
+ * and break messages have been delivered prior to getting here.
+ */
+STATIC_OVL void
+breakobj(obj, x, y, hero_caused, from_invent)
+struct obj *obj;
+xchar x, y;            /* object location (ox, oy may not be right) */
+boolean hero_caused;   /* is this the hero's fault? */
+boolean from_invent;
+{
+       switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
+               case MIRROR:
+                       if (hero_caused)
+                           change_luck(-2);
+                       break;
+               case POT_WATER:         /* really, all potions */
+                       if (obj->otyp == POT_OIL && obj->lamplit) {
+                           splatter_burning_oil(x,y);
+                       } else if (distu(x,y) <= 2) {
+                           if (!breathless(youmonst.data) || haseyes(youmonst.data)) {
+                               if (obj->otyp != POT_WATER) {
+                                       if (!breathless(youmonst.data))
+                                            /* [what about "familiar odor" when known?] */
+                                           You("smell a peculiar odor...");
+                                       else {
+                                           int numeyes = eyecount(youmonst.data);
+                                           Your("%s water%s.",
+                                                (numeyes == 1) ? body_part(EYE) :
+                                                       makeplural(body_part(EYE)),
+                                                (numeyes == 1) ? "s" : "");
+                                       }
+                               }
+                               potionbreathe(obj);
+                           }
+                       }
+                       /* monster breathing isn't handled... [yet?] */
+                       break;
+               case EGG:
+                       /* breaking your own eggs is bad luck */
+                       if (hero_caused && obj->spe && obj->corpsenm >= LOW_PM)
+                           change_luck((schar) -min(obj->quan, 5L));
+                       break;
+       }
+       if (hero_caused) {
+           if (from_invent) {
+               if (*u.ushops)
+                       check_shop_obj(obj, x, y, TRUE);
+           } else if (!obj->no_charge && costly_spot(x, y)) {
+               /* it is assumed that the obj is a floor-object */
+               char *o_shop = in_rooms(x, y, SHOPBASE);
+               struct monst *shkp = shop_keeper(*o_shop);
+
+               if (shkp) {             /* (implies *o_shop != '\0') */
+                   static NEARDATA long lastmovetime = 0L;
+                   static NEARDATA boolean peaceful_shk = FALSE;
+                   /*  We want to base shk actions on her peacefulness
+                       at start of this turn, so that "simultaneous"
+                       multiple breakage isn't drastically worse than
+                       single breakage.  (ought to be done via ESHK)  */
+                   if (moves != lastmovetime)
+                       peaceful_shk = shkp->mpeaceful;
+                   if (stolen_value(obj, x, y, peaceful_shk, FALSE) > 0L &&
+                       (*o_shop != u.ushops[0] || !inside_shop(u.ux, u.uy)) &&
+                       moves != lastmovetime) make_angry_shk(shkp, x, y);
+                   lastmovetime = moves;
+               }
+           }
+       }
+       delobj(obj);
+}
+
+/*
+ * Check to see if obj is going to break, but don't actually break it.
+ * Return 0 if the object isn't going to break, 1 if it is.
+ */
+boolean
+breaktest(obj)
+struct obj *obj;
+{
+       if (obj_resists(obj, 1, 99)) return 0;
+       if (objects[obj->otyp].oc_material == GLASS && !obj->oartifact &&
+               obj->oclass != GEM_CLASS)
+           return 1;
+       switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
+#ifdef TOURIST
+               case EXPENSIVE_CAMERA:
+#endif
+               case POT_WATER:         /* really, all potions */
+               case EGG:
+               case CREAM_PIE:
+               case MELON:
+               case ACID_VENOM:
+               case BLINDING_VENOM:
+                       return 1;
+               default:
+                       return 0;
+       }
+}
+
+STATIC_OVL void
+breakmsg(obj, in_view)
+struct obj *obj;
+boolean in_view;
+{
+       const char *to_pieces;
+
+       to_pieces = "";
+       switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
+               default: /* glass or crystal wand */
+                   if (obj->oclass != WAND_CLASS)
+                       impossible("breaking odd object?");
+               case CRYSTAL_PLATE_MAIL:
+               case LENSES:
+               case MIRROR:
+               case CRYSTAL_BALL:
+#ifdef TOURIST
+               case EXPENSIVE_CAMERA:
+#endif
+                       to_pieces = " into a thousand pieces";
+                       /*FALLTHRU*/
+               case POT_WATER:         /* really, all potions */
+                       if (!in_view)
+                           You_hear("%s shatter!", something);
+                       else
+                           pline("%s shatter%s%s!", Doname2(obj),
+                               (obj->quan==1) ? "s" : "", to_pieces);
+                       break;
+               case EGG:
+               case MELON:
+                       pline("Splat!");
+                       break;
+               case CREAM_PIE:
+                       if (in_view) pline("What a mess!");
+                       break;
+               case ACID_VENOM:
+               case BLINDING_VENOM:
+                       pline("Splash!");
+                       break;
+       }
+}
+
+STATIC_OVL int
+throw_gold(obj)
+struct obj *obj;
+{
+       int range, odx, ody;
+#ifndef GOLDOBJ
+       long zorks = obj->quan;
+#endif
+       register struct monst *mon;
+
+       if(!u.dx && !u.dy && !u.dz) {
+#ifndef GOLDOBJ
+               u.ugold += obj->quan;
+               flags.botl = 1;
+               dealloc_obj(obj);
+#endif
+               You("cannot throw gold at yourself.");
+               return(0);
+       }
+#ifdef GOLDOBJ
+        freeinv(obj);
+#endif
+       if(u.uswallow) {
+               pline(is_animal(u.ustuck->data) ?
+                       "%s in the %s's entrails." : "%s into %s.",
+#ifndef GOLDOBJ
+                       "The gold disappears", mon_nam(u.ustuck));
+               u.ustuck->mgold += zorks;
+               dealloc_obj(obj);
+#else
+                       "The money disappears", mon_nam(u.ustuck));
+               add_to_minv(u.ustuck, obj);
+#endif
+               return(1);
+       }
+
+       if(u.dz) {
+               if (u.dz < 0 && !Is_airlevel(&u.uz) &&
+                                       !Underwater && !Is_waterlevel(&u.uz)) {
+       pline_The("gold hits the %s, then falls back on top of your %s.",
+                   ceiling(u.ux,u.uy), body_part(HEAD));
+                   /* some self damage? */
+                   if(uarmh) pline("Fortunately, you are wearing a helmet!");
+               }
+               bhitpos.x = u.ux;
+               bhitpos.y = u.uy;
+       } else {
+               /* consistent with range for normal objects */
+               range = (int)((ACURRSTR)/2 - obj->owt/40);
+
+               /* see if the gold has a place to move into */
+               odx = u.ux + u.dx;
+               ody = u.uy + u.dy;
+               if(!ZAP_POS(levl[odx][ody].typ) || closed_door(odx, ody)) {
+                       bhitpos.x = u.ux;
+                       bhitpos.y = u.uy;
+               } else {
+                       mon = bhit(u.dx, u.dy, range, THROWN_WEAPON,
+                                  (int FDECL((*),(MONST_P,OBJ_P)))0,
+                                  (int FDECL((*),(OBJ_P,OBJ_P)))0,
+                                  obj);
+                       if(mon) {
+                           if (ghitm(mon, obj))        /* was it caught? */
+                               return 1;
+                       } else {
+                           if(ship_object(obj, bhitpos.x, bhitpos.y, FALSE))
+                               return 1;
+                       }
+               }
+       }
+
+       if(flooreffects(obj,bhitpos.x,bhitpos.y,"fall")) return(1);
+       if(u.dz > 0)
+               pline_The("gold hits the %s.", surface(bhitpos.x,bhitpos.y));
+       place_object(obj,bhitpos.x,bhitpos.y);
+       if(*u.ushops) sellobj(obj, bhitpos.x, bhitpos.y);
+       stackobj(obj);
+       newsym(bhitpos.x,bhitpos.y);
+       return(1);
+}
+
+/*dothrow.c*/
diff --git a/src/drawing.c b/src/drawing.c
new file mode 100644 (file)
index 0000000..da39614
--- /dev/null
@@ -0,0 +1,901 @@
+/*     SCCS Id: @(#)drawing.c  3.4     1999/12/02      */
+/* Copyright (c) NetHack Development Team 1992.                          */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "tcap.h"
+
+/* Relevent header information in rm.h and objclass.h. */
+
+#ifdef C
+#undef C
+#endif
+
+#ifdef TEXTCOLOR
+#define C(n) n
+#else
+#define C(n)
+#endif
+
+#define g_FILLER(symbol) 0
+
+uchar oc_syms[MAXOCLASSES] = DUMMY; /* the current object  display symbols */
+uchar showsyms[MAXPCHARS]  = DUMMY; /* the current feature display symbols */
+uchar monsyms[MAXMCLASSES] = DUMMY; /* the current monster display symbols */
+uchar warnsyms[WARNCOUNT]  = DUMMY;  /* the current warning display symbols */
+
+/* Default object class symbols.  See objclass.h. */
+const char def_oc_syms[MAXOCLASSES] = {
+/* 0*/ '\0',           /* placeholder for the "random class" */
+       ILLOBJ_SYM,
+       WEAPON_SYM,
+       ARMOR_SYM,
+       RING_SYM,
+/* 5*/ AMULET_SYM,
+       TOOL_SYM,
+       FOOD_SYM,
+       POTION_SYM,
+       SCROLL_SYM,
+/*10*/ SPBOOK_SYM,
+       WAND_SYM,
+       GOLD_SYM,
+       GEM_SYM,
+       ROCK_SYM,
+/*15*/ BALL_SYM,
+       CHAIN_SYM,
+       VENOM_SYM
+};
+
+const char invisexplain[] = "remembered, unseen, creature";
+
+/* Object descriptions.  Used in do_look(). */
+const char * const objexplain[] = {    /* these match def_oc_syms, above */
+/* 0*/ 0,
+       "strange object",
+       "weapon",
+       "suit or piece of armor",
+       "ring",
+/* 5*/ "amulet",
+       "useful item (pick-axe, key, lamp...)",
+       "piece of food",
+       "potion",
+       "scroll",
+/*10*/ "spellbook",
+       "wand",
+       "pile of coins",
+       "gem or rock",
+       "boulder or statue",
+/*15*/ "iron ball",
+       "iron chain",
+       "splash of venom"
+};
+
+/* Object class names.  Used in object_detect(). */
+const char * const oclass_names[] = {
+/* 0*/ 0,
+       "illegal objects",
+       "weapons",
+       "armor",
+       "rings",
+/* 5*/ "amulets",
+       "tools",
+       "food",
+       "potions",
+       "scrolls",
+/*10*/ "spellbooks",
+       "wands",
+       "coins",
+       "rocks",
+       "large stones",
+/*15*/ "iron balls",
+       "chains",
+       "venoms"
+};
+
+/* Default monster class symbols.  See monsym.h. */
+const char def_monsyms[MAXMCLASSES] = {
+       '\0',           /* holder */
+       DEF_ANT,
+       DEF_BLOB,
+       DEF_COCKATRICE,
+       DEF_DOG,
+       DEF_EYE,
+       DEF_FELINE,
+       DEF_GREMLIN,
+       DEF_HUMANOID,
+       DEF_IMP,
+       DEF_JELLY,              /* 10 */
+       DEF_KOBOLD,
+       DEF_LEPRECHAUN,
+       DEF_MIMIC,
+       DEF_NYMPH,
+       DEF_ORC,
+       DEF_PIERCER,
+       DEF_QUADRUPED,
+       DEF_RODENT,
+       DEF_SPIDER,
+       DEF_TRAPPER,            /* 20 */
+       DEF_UNICORN,
+       DEF_VORTEX,
+       DEF_WORM,
+       DEF_XAN,
+       DEF_LIGHT,
+       DEF_ZRUTY,
+       DEF_ANGEL,
+       DEF_BAT,
+       DEF_CENTAUR,
+       DEF_DRAGON,             /* 30 */
+       DEF_ELEMENTAL,
+       DEF_FUNGUS,
+       DEF_GNOME,
+       DEF_GIANT,
+       '\0',
+       DEF_JABBERWOCK,
+       DEF_KOP,
+       DEF_LICH,
+       DEF_MUMMY,
+       DEF_NAGA,               /* 40 */
+       DEF_OGRE,
+       DEF_PUDDING,
+       DEF_QUANTMECH,
+       DEF_RUSTMONST,
+       DEF_SNAKE,
+       DEF_TROLL,
+       DEF_UMBER,
+       DEF_VAMPIRE,
+       DEF_WRAITH,
+       DEF_XORN,               /* 50 */
+       DEF_YETI,
+       DEF_ZOMBIE,
+       DEF_HUMAN,
+       DEF_GHOST,
+       DEF_GOLEM,
+       DEF_DEMON,
+       DEF_EEL,
+       DEF_LIZARD,
+       DEF_WORM_TAIL,
+       DEF_MIMIC_DEF,          /* 60 */
+};
+
+/* The explanations below are also used when the user gives a string
+ * for blessed genocide, so no text should wholly contain any later
+ * text.  They should also always contain obvious names (eg. cat/feline).
+ */
+const char * const monexplain[MAXMCLASSES] = {
+    0,
+    "ant or other insect",     "blob",                 "cockatrice",
+    "dog or other canine",     "eye or sphere",        "cat or other feline",
+    "gremlin",                 "humanoid",             "imp or minor demon",
+    "jelly",                   "kobold",               "leprechaun",
+    "mimic",                   "nymph",                "orc",
+    "piercer",                 "quadruped",            "rodent",
+    "arachnid or centipede",   "trapper or lurker above", "unicorn or horse",
+    "vortex",          "worm", "xan or other mythical/fantastic insect",
+    "light",                   "zruty",
+
+    "angelic being",           "bat or bird",          "centaur",
+    "dragon",                  "elemental",            "fungus or mold",
+    "gnome",                   "giant humanoid",       0,
+    "jabberwock",              "Keystone Kop",         "lich",
+    "mummy",                   "naga",                 "ogre",
+    "pudding or ooze",         "quantum mechanic",     "rust monster or disenchanter",
+    "snake",                   "troll",                "umber hulk",
+    "vampire",                 "wraith",               "xorn",
+    "apelike creature",                "zombie",
+
+    "human or elf",            "ghost",                "golem",
+    "major demon",             "sea monster",          "lizard",
+    "long worm tail",          "mimic"
+};
+
+const struct symdef def_warnsyms[WARNCOUNT] = {
+       {'0', "unknown creature causing you worry", C(CLR_WHITE)},      /* white warning  */
+       {'1', "unknown creature causing you concern", C(CLR_RED)},      /* pink warning   */
+       {'2', "unknown creature causing you anxiety", C(CLR_RED)},      /* red warning    */
+       {'3', "unknown creature causing you disquiet", C(CLR_RED)},     /* ruby warning   */
+       {'4', "unknown creature causing you alarm",
+                                               C(CLR_MAGENTA)},        /* purple warning */
+       {'5', "unknown creature causing you dread",
+                                               C(CLR_BRIGHT_MAGENTA)}  /* black warning  */
+};
+
+/*
+ *  Default screen symbols with explanations and colors.
+ *  Note:  {ibm|dec|mac}_graphics[] arrays also depend on this symbol order.
+ */
+const struct symdef defsyms[MAXPCHARS] = {
+/* 0*/ {' ', "dark part of a room",C(NO_COLOR)},       /* stone */
+       {'|', "wall",           C(CLR_GRAY)},   /* vwall */
+       {'-', "wall",           C(CLR_GRAY)},   /* hwall */
+       {'-', "wall",           C(CLR_GRAY)},   /* tlcorn */
+       {'-', "wall",           C(CLR_GRAY)},   /* trcorn */
+       {'-', "wall",           C(CLR_GRAY)},   /* blcorn */
+       {'-', "wall",           C(CLR_GRAY)},   /* brcorn */
+       {'-', "wall",           C(CLR_GRAY)},   /* crwall */
+       {'-', "wall",           C(CLR_GRAY)},   /* tuwall */
+       {'-', "wall",           C(CLR_GRAY)},   /* tdwall */
+/*10*/ {'|', "wall",           C(CLR_GRAY)},   /* tlwall */
+       {'|', "wall",           C(CLR_GRAY)},   /* trwall */
+       {'.', "doorway",        C(CLR_GRAY)},   /* ndoor */
+       {'-', "open door",      C(CLR_BROWN)},  /* vodoor */
+       {'|', "open door",      C(CLR_BROWN)},  /* hodoor */
+       {'+', "closed door",    C(CLR_BROWN)},  /* vcdoor */
+       {'+', "closed door",    C(CLR_BROWN)},  /* hcdoor */
+       {'#', "iron bars",      C(HI_METAL)},   /* bars */
+       {'#', "tree",           C(CLR_GREEN)},  /* tree */
+       {'.', "floor of a room",C(CLR_GRAY)},   /* room */
+/*20*/ {'#', "corridor",       C(CLR_GRAY)},   /* dark corr */
+       {'#', "lit corridor",   C(CLR_GRAY)},   /* lit corr (see mapglyph.c) */
+       {'<', "staircase up",   C(CLR_GRAY)},   /* upstair */
+       {'>', "staircase down", C(CLR_GRAY)},   /* dnstair */
+       {'<', "ladder up",      C(CLR_BROWN)},  /* upladder */
+       {'>', "ladder down",    C(CLR_BROWN)},  /* dnladder */
+       {'_', "altar",          C(CLR_GRAY)},   /* altar */
+       {'|', "grave",      C(CLR_GRAY)},   /* grave */
+       {'\\', "opulent throne",C(HI_GOLD)},    /* throne */
+#ifdef SINKS
+       {'#', "sink",           C(CLR_GRAY)},   /* sink */
+#else
+       {'#', "",               C(CLR_GRAY)},   /* sink */
+#endif
+/*30*/ {'{', "fountain",       C(CLR_BLUE)},   /* fountain */
+       {'}', "water",          C(CLR_BLUE)},   /* pool */
+       {'.', "ice",            C(CLR_CYAN)},   /* ice */
+       {'}', "molten lava",    C(CLR_RED)},    /* lava */
+       {'.', "lowered drawbridge",C(CLR_BROWN)},       /* vodbridge */
+       {'.', "lowered drawbridge",C(CLR_BROWN)},       /* hodbridge */
+       {'#', "raised drawbridge",C(CLR_BROWN)},/* vcdbridge */
+       {'#', "raised drawbridge",C(CLR_BROWN)},/* hcdbridge */
+       {' ', "air",            C(CLR_CYAN)},   /* open air */
+       {'#', "cloud",          C(CLR_GRAY)},   /* [part of] a cloud */
+/*40*/ {'}', "water",          C(CLR_BLUE)},   /* under water */
+       {'^', "arrow trap",     C(HI_METAL)},   /* trap */
+       {'^', "dart trap",      C(HI_METAL)},   /* trap */
+       {'^', "falling rock trap",C(CLR_GRAY)}, /* trap */
+       {'^', "squeaky board",  C(CLR_BROWN)},  /* trap */
+       {'^', "bear trap",      C(HI_METAL)},   /* trap */
+       {'^', "land mine",      C(CLR_RED)},    /* trap */
+       {'^', "rolling boulder trap",   C(CLR_GRAY)},   /* trap */
+       {'^', "sleeping gas trap",C(HI_ZAP)},   /* trap */
+       {'^', "rust trap",      C(CLR_BLUE)},   /* trap */
+/*50*/ {'^', "fire trap",      C(CLR_ORANGE)}, /* trap */
+       {'^', "pit",            C(CLR_BLACK)},  /* trap */
+       {'^', "spiked pit",     C(CLR_BLACK)},  /* trap */
+       {'^', "hole",   C(CLR_BROWN)},  /* trap */
+       {'^', "trap door",      C(CLR_BROWN)},  /* trap */
+       {'^', "teleportation trap", C(CLR_MAGENTA)},    /* trap */
+       {'^', "level teleporter", C(CLR_MAGENTA)},      /* trap */
+       {'^', "magic portal",   C(CLR_BRIGHT_MAGENTA)}, /* trap */
+       {'"', "web",            C(CLR_GRAY)},   /* web */
+       {'^', "statue trap",    C(CLR_GRAY)},   /* trap */
+/*60*/ {'^', "magic trap",     C(HI_ZAP)},     /* trap */
+       {'^', "anti-magic field", C(HI_ZAP)},   /* trap */
+       {'^', "polymorph trap", C(CLR_BRIGHT_GREEN)},   /* trap */
+       {'|', "wall",           C(CLR_GRAY)},   /* vbeam */
+       {'-', "wall",           C(CLR_GRAY)},   /* hbeam */
+       {'\\',"wall",           C(CLR_GRAY)},   /* lslant */
+       {'/', "wall",           C(CLR_GRAY)},   /* rslant */
+       {'*', "",               C(CLR_WHITE)},  /* dig beam */
+       {'!', "",               C(CLR_WHITE)},  /* camera flash beam */
+       {')', "",               C(HI_WOOD)},    /* boomerang open left */
+/*70*/ {'(', "",               C(HI_WOOD)},    /* boomerang open right */
+       {'0', "",               C(HI_ZAP)},     /* 4 magic shield symbols */
+       {'#', "",               C(HI_ZAP)},
+       {'@', "",               C(HI_ZAP)},
+       {'*', "",               C(HI_ZAP)},
+       {'/', "",               C(CLR_GREEN)},  /* swallow top left     */
+       {'-', "",               C(CLR_GREEN)},  /* swallow top center   */
+       {'\\', "",              C(CLR_GREEN)},  /* swallow top right    */
+       {'|', "",               C(CLR_GREEN)},  /* swallow middle left  */
+       {'|', "",               C(CLR_GREEN)},  /* swallow middle right */
+/*80*/ {'\\', "",              C(CLR_GREEN)},  /* swallow bottom left  */
+       {'-', "",               C(CLR_GREEN)},  /* swallow bottom center*/
+       {'/', "",               C(CLR_GREEN)},  /* swallow bottom right */
+       {'/', "",               C(CLR_ORANGE)}, /* explosion top left     */
+       {'-', "",               C(CLR_ORANGE)}, /* explosion top center   */
+       {'\\', "",              C(CLR_ORANGE)}, /* explosion top right    */
+       {'|', "",               C(CLR_ORANGE)}, /* explosion middle left  */
+       {' ', "",               C(CLR_ORANGE)}, /* explosion middle center*/
+       {'|', "",               C(CLR_ORANGE)}, /* explosion middle right */
+       {'\\', "",              C(CLR_ORANGE)}, /* explosion bottom left  */
+/*90*/ {'-', "",               C(CLR_ORANGE)}, /* explosion bottom center*/
+       {'/', "",               C(CLR_ORANGE)}, /* explosion bottom right */
+/*
+ *  Note: Additions to this array should be reflected in the
+ *       {ibm,dec,mac}_graphics[] arrays below.
+ */
+};
+
+#undef C
+
+#ifdef ASCIIGRAPH
+
+#ifdef PC9800
+void NDECL((*ibmgraphics_mode_callback)) = 0;  /* set in tty_start_screen() */
+#endif /* PC9800 */
+
+static uchar ibm_graphics[MAXPCHARS] = {
+/* 0*/ g_FILLER(S_stone),
+       0xb3,   /* S_vwall:     meta-3, vertical rule */
+       0xc4,   /* S_hwall:     meta-D, horizontal rule */
+       0xda,   /* S_tlcorn:    meta-Z, top left corner */
+       0xbf,   /* S_trcorn:    meta-?, top right corner */
+       0xc0,   /* S_blcorn:    meta-@, bottom left */
+       0xd9,   /* S_brcorn:    meta-Y, bottom right */
+       0xc5,   /* S_crwall:    meta-E, cross */
+       0xc1,   /* S_tuwall:    meta-A, T up */
+       0xc2,   /* S_tdwall:    meta-B, T down */
+/*10*/ 0xb4,   /* S_tlwall:    meta-4, T left */
+       0xc3,   /* S_trwall:    meta-C, T right */
+       0xfa,   /* S_ndoor:     meta-z, centered dot */
+       0xfe,   /* S_vodoor:    meta-~, small centered square */
+       0xfe,   /* S_hodoor:    meta-~, small centered square */
+       g_FILLER(S_vcdoor),
+       g_FILLER(S_hcdoor),
+       240,    /* S_bars:      equivalence symbol */
+       241,    /* S_tree:      plus or minus symbol */
+       0xfa,   /* S_room:      meta-z, centered dot */
+/*20*/ 0xb0,   /* S_corr:      meta-0, light shading */
+       0xb1,   /* S_litcorr:   meta-1, medium shading */
+       g_FILLER(S_upstair),
+       g_FILLER(S_dnstair),
+       g_FILLER(S_upladder),
+       g_FILLER(S_dnladder),
+       g_FILLER(S_altar),
+       g_FILLER(S_grave),
+       g_FILLER(S_throne),
+       g_FILLER(S_sink),
+/*30*/ 0xf4,   /* S_fountain:  meta-t, integral top half */
+       0xf7,   /* S_pool:      meta-w, approx. equals */
+       0xfa,   /* S_ice:       meta-z, centered dot */
+       0xf7,   /* S_lava:      meta-w, approx. equals */
+       0xfa,   /* S_vodbridge: meta-z, centered dot */
+       0xfa,   /* S_hodbridge: meta-z, centered dot */
+       g_FILLER(S_vcdbridge),
+       g_FILLER(S_hcdbridge),
+       g_FILLER(S_air),
+       g_FILLER(S_cloud),
+/*40*/ 0xf7,   /* S_water:     meta-w, approx. equals */
+       g_FILLER(S_arrow_trap),
+       g_FILLER(S_dart_trap),
+       g_FILLER(S_falling_rock_trap),
+       g_FILLER(S_squeaky_board),
+       g_FILLER(S_bear_trap),
+       g_FILLER(S_land_mine),
+       g_FILLER(S_rolling_boulder_trap),
+       g_FILLER(S_sleeping_gas_trap),
+       g_FILLER(S_rust_trap),
+/*50*/ g_FILLER(S_fire_trap),
+       g_FILLER(S_pit),
+       g_FILLER(S_spiked_pit),
+       g_FILLER(S_hole),
+       g_FILLER(S_trap_door),
+       g_FILLER(S_teleportation_trap),
+       g_FILLER(S_level_teleporter),
+       g_FILLER(S_magic_portal),
+       g_FILLER(S_web),
+       g_FILLER(S_statue_trap),
+/*60*/ g_FILLER(S_magic_trap),
+       g_FILLER(S_anti_magic_trap),
+       g_FILLER(S_polymorph_trap),
+       0xb3,   /* S_vbeam:     meta-3, vertical rule */
+       0xc4,   /* S_hbeam:     meta-D, horizontal rule */
+       g_FILLER(S_lslant),
+       g_FILLER(S_rslant),
+       g_FILLER(S_digbeam),
+       g_FILLER(S_flashbeam),
+       g_FILLER(S_boomleft),
+/*70*/ g_FILLER(S_boomright),
+       g_FILLER(S_ss1),
+       g_FILLER(S_ss2),
+       g_FILLER(S_ss3),
+       g_FILLER(S_ss4),
+       g_FILLER(S_sw_tl),
+       g_FILLER(S_sw_tc),
+       g_FILLER(S_sw_tr),
+       0xb3,   /* S_sw_ml:     meta-3, vertical rule */
+       0xb3,   /* S_sw_mr:     meta-3, vertical rule */
+/*80*/ g_FILLER(S_sw_bl),
+       g_FILLER(S_sw_bc),
+       g_FILLER(S_sw_br),
+       g_FILLER(S_explode1),
+       g_FILLER(S_explode2),
+       g_FILLER(S_explode3),
+       0xb3,   /* S_explode4:  meta-3, vertical rule */
+       g_FILLER(S_explode5),
+       0xb3,   /* S_explode6:  meta-3, vertical rule */
+       g_FILLER(S_explode7),
+/*90*/ g_FILLER(S_explode8),
+       g_FILLER(S_explode9)
+};
+#endif  /* ASCIIGRAPH */
+
+#ifdef TERMLIB
+void NDECL((*decgraphics_mode_callback)) = 0;  /* set in tty_start_screen() */
+
+static uchar dec_graphics[MAXPCHARS] = {
+/* 0*/ g_FILLER(S_stone),
+       0xf8,   /* S_vwall:     meta-x, vertical rule */
+       0xf1,   /* S_hwall:     meta-q, horizontal rule */
+       0xec,   /* S_tlcorn:    meta-l, top left corner */
+       0xeb,   /* S_trcorn:    meta-k, top right corner */
+       0xed,   /* S_blcorn:    meta-m, bottom left */
+       0xea,   /* S_brcorn:    meta-j, bottom right */
+       0xee,   /* S_crwall:    meta-n, cross */
+       0xf6,   /* S_tuwall:    meta-v, T up */
+       0xf7,   /* S_tdwall:    meta-w, T down */
+/*10*/ 0xf5,   /* S_tlwall:    meta-u, T left */
+       0xf4,   /* S_trwall:    meta-t, T right */
+       0xfe,   /* S_ndoor:     meta-~, centered dot */
+       0xe1,   /* S_vodoor:    meta-a, solid block */
+       0xe1,   /* S_hodoor:    meta-a, solid block */
+       g_FILLER(S_vcdoor),
+       g_FILLER(S_hcdoor),
+       0xfb,   /* S_bars:      meta-{, small pi */
+       0xe7,   /* S_tree:      meta-g, plus-or-minus */
+       0xfe,   /* S_room:      meta-~, centered dot */
+/*20*/ g_FILLER(S_corr),
+       g_FILLER(S_litcorr),
+       g_FILLER(S_upstair),
+       g_FILLER(S_dnstair),
+       0xf9,   /* S_upladder:  meta-y, greater-than-or-equals */
+       0xfa,   /* S_dnladder:  meta-z, less-than-or-equals */
+       g_FILLER(S_altar),      /* 0xc3, \E)3: meta-C, dagger */
+       g_FILLER(S_grave),
+       g_FILLER(S_throne),
+       g_FILLER(S_sink),
+/*30*/ g_FILLER(S_fountain),   /* 0xdb, \E)3: meta-[, integral top half */
+       0xe0,   /* S_pool:      meta-\, diamond */
+       0xfe,   /* S_ice:       meta-~, centered dot */
+       0xe0,   /* S_lava:      meta-\, diamond */
+       0xfe,   /* S_vodbridge: meta-~, centered dot */
+       0xfe,   /* S_hodbridge: meta-~, centered dot */
+       g_FILLER(S_vcdbridge),
+       g_FILLER(S_hcdbridge),
+       g_FILLER(S_air),
+       g_FILLER(S_cloud),
+/*40*/ 0xe0,   /* S_water:     meta-\, diamond */
+       g_FILLER(S_arrow_trap),
+       g_FILLER(S_dart_trap),
+       g_FILLER(S_falling_rock_trap),
+       g_FILLER(S_squeaky_board),
+       g_FILLER(S_bear_trap),
+       g_FILLER(S_land_mine),
+       g_FILLER(S_rolling_boulder_trap),
+       g_FILLER(S_sleeping_gas_trap),
+       g_FILLER(S_rust_trap),
+/*50*/ g_FILLER(S_fire_trap),
+       g_FILLER(S_pit),
+       g_FILLER(S_spiked_pit),
+       g_FILLER(S_hole),
+       g_FILLER(S_trap_door),
+       g_FILLER(S_teleportation_trap),
+       g_FILLER(S_level_teleporter),
+       g_FILLER(S_magic_portal),
+       g_FILLER(S_web),        /* 0xbd, \E)3: meta-=, int'l currency */
+       g_FILLER(S_statue_trap),
+/*60*/ g_FILLER(S_magic_trap),
+       g_FILLER(S_anti_magic_trap),
+       g_FILLER(S_polymorph_trap),
+       0xf8,   /* S_vbeam:     meta-x, vertical rule */
+       0xf1,   /* S_hbeam:     meta-q, horizontal rule */
+       g_FILLER(S_lslant),
+       g_FILLER(S_rslant),
+       g_FILLER(S_digbeam),
+       g_FILLER(S_flashbeam),
+       g_FILLER(S_boomleft),
+/*70*/ g_FILLER(S_boomright),
+       g_FILLER(S_ss1),
+       g_FILLER(S_ss2),
+       g_FILLER(S_ss3),
+       g_FILLER(S_ss4),
+       g_FILLER(S_sw_tl),
+       0xef,   /* S_sw_tc:     meta-o, high horizontal line */
+       g_FILLER(S_sw_tr),
+       0xf8,   /* S_sw_ml:     meta-x, vertical rule */
+       0xf8,   /* S_sw_mr:     meta-x, vertical rule */
+/*80*/ g_FILLER(S_sw_bl),
+       0xf3,   /* S_sw_bc:     meta-s, low horizontal line */
+       g_FILLER(S_sw_br),
+       g_FILLER(S_explode1),
+       0xef,   /* S_explode2:  meta-o, high horizontal line */
+       g_FILLER(S_explode3),
+       0xf8,   /* S_explode4:  meta-x, vertical rule */
+       g_FILLER(S_explode5),
+       0xf8,   /* S_explode6:  meta-x, vertical rule */
+       g_FILLER(S_explode7),
+/*90*/ 0xf3,   /* S_explode8:  meta-s, low horizontal line */
+       g_FILLER(S_explode9)
+};
+#endif  /* TERMLIB */
+
+#ifdef MAC_GRAPHICS_ENV
+static uchar mac_graphics[MAXPCHARS] = {
+/* 0*/ g_FILLER(S_stone),
+       0xba,   /* S_vwall */
+       0xcd,   /* S_hwall */
+       0xc9,   /* S_tlcorn */
+       0xbb,   /* S_trcorn */
+       0xc8,   /* S_blcorn */
+       0xbc,   /* S_brcorn */
+       0xce,   /* S_crwall */
+       0xca,   /* S_tuwall */
+       0xcb,   /* S_tdwall */
+/*10*/ 0xb9,   /* S_tlwall */
+       0xcc,   /* S_trwall */
+       0xb0,   /* S_ndoor */
+       0xee,   /* S_vodoor */
+       0xee,   /* S_hodoor */
+       0xef,   /* S_vcdoor */
+       0xef,   /* S_hcdoor */
+       0xf0,   /* S_bars:      equivalency symbol */
+       0xf1,   /* S_tree:      plus-or-minus */
+       g_FILLER(S_Room),
+/*20*/ 0xB0,   /* S_corr */
+       g_FILLER(S_litcorr),
+       g_FILLER(S_upstair),
+       g_FILLER(S_dnstair),
+       g_FILLER(S_upladder),
+       g_FILLER(S_dnladder),
+       g_FILLER(S_altar),
+       0xef,   /* S_grave:     same as open door */
+       g_FILLER(S_throne),
+       g_FILLER(S_sink),
+/*30*/ g_FILLER(S_fountain),
+       0xe0,   /* S_pool */
+       g_FILLER(S_ice),
+       g_FILLER(S_lava),
+       g_FILLER(S_vodbridge),
+       g_FILLER(S_hodbridge),
+       g_FILLER(S_vcdbridge),
+       g_FILLER(S_hcdbridge),
+       g_FILLER(S_air),
+       g_FILLER(S_cloud),
+/*40*/ g_FILLER(S_water),
+       g_FILLER(S_arrow_trap),
+       g_FILLER(S_dart_trap),
+       g_FILLER(S_falling_rock_trap),
+       g_FILLER(S_squeaky_board),
+       g_FILLER(S_bear_trap),
+       g_FILLER(S_land_mine),
+       g_FILLER(S_rolling_boulder_trap),
+       g_FILLER(S_sleeping_gas_trap),
+       g_FILLER(S_rust_trap),
+/*50*/ g_FILLER(S_fire_trap),
+       g_FILLER(S_pit),
+       g_FILLER(S_spiked_pit),
+       g_FILLER(S_hole),
+       g_FILLER(S_trap_door),
+       g_FILLER(S_teleportation_trap),
+       g_FILLER(S_level_teleporter),
+       g_FILLER(S_magic_portal),
+       g_FILLER(S_web),
+       g_FILLER(S_statue_trap),
+/*60*/ g_FILLER(S_magic_trap),
+       g_FILLER(S_anti_magic_trap),
+       g_FILLER(S_polymorph_trap),
+       g_FILLER(S_vbeam),
+       g_FILLER(S_hbeam),
+       g_FILLER(S_lslant),
+       g_FILLER(S_rslant),
+       g_FILLER(S_digbeam),
+       g_FILLER(S_flashbeam),
+       g_FILLER(S_boomleft),
+/*70*/ g_FILLER(S_boomright),
+       g_FILLER(S_ss1),
+       g_FILLER(S_ss2),
+       g_FILLER(S_ss3),
+       g_FILLER(S_ss4),
+       g_FILLER(S_sw_tl),
+       g_FILLER(S_sw_tc),
+       g_FILLER(S_sw_tr),
+       g_FILLER(S_sw_ml),
+       g_FILLER(S_sw_mr),
+/*80*/ g_FILLER(S_sw_bl),
+       g_FILLER(S_sw_bc),
+       g_FILLER(S_sw_br),
+       g_FILLER(S_explode1),
+       g_FILLER(S_explode2),
+       g_FILLER(S_explode3),
+       g_FILLER(S_explode4),
+       g_FILLER(S_explode5),
+       g_FILLER(S_explode6),
+       g_FILLER(S_explode7),
+/*90*/ g_FILLER(S_explode8),
+       g_FILLER(S_explode9)
+};
+#endif /* MAC_GRAPHICS_ENV */
+
+#ifdef PC9800
+void NDECL((*ascgraphics_mode_callback)) = 0;  /* set in tty_start_screen() */
+#endif
+
+/*
+ * Convert the given character to an object class.  If the character is not
+ * recognized, then MAXOCLASSES is returned.  Used in detect.c invent.c,
+ * options.c, pickup.c, sp_lev.c, and lev_main.c.
+ */
+int
+def_char_to_objclass(ch)
+    char ch;
+{
+    int i;
+    for (i = 1; i < MAXOCLASSES; i++)
+       if (ch == def_oc_syms[i]) break;
+    return i;
+}
+
+/*
+ * Convert a character into a monster class.  This returns the _first_
+ * match made.  If there are are no matches, return MAXMCLASSES.
+ */
+int
+def_char_to_monclass(ch)
+    char ch;
+{
+    int i;
+    for (i = 1; i < MAXMCLASSES; i++)
+       if (def_monsyms[i] == ch) break;
+    return i;
+}
+
+void
+assign_graphics(graph_chars, glth, maxlen, offset)
+register uchar *graph_chars;
+int glth, maxlen, offset;
+{
+    register int i;
+
+    for (i = 0; i < maxlen; i++)
+       showsyms[i+offset] = (((i < glth) && graph_chars[i]) ?
+                      graph_chars[i] : defsyms[i+offset].sym);
+}
+
+void
+switch_graphics(gr_set_flag)
+int gr_set_flag;
+{
+    switch (gr_set_flag) {
+       default:
+       case ASCII_GRAPHICS:
+           assign_graphics((uchar *)0, 0, MAXPCHARS, 0);
+#ifdef PC9800
+           if (ascgraphics_mode_callback) (*ascgraphics_mode_callback)();
+#endif
+           break;
+#ifdef ASCIIGRAPH
+       case IBM_GRAPHICS:
+/*
+ * Use the nice IBM Extended ASCII line-drawing characters (codepage 437).
+ *
+ * OS/2 defaults to a multilingual character set (codepage 850, corresponding
+ * to the ISO 8859 character set.  We should probably do a VioSetCp() call to
+ * set the codepage to 437.
+ */
+           iflags.IBMgraphics = TRUE;
+           iflags.DECgraphics = FALSE;
+           assign_graphics(ibm_graphics, SIZE(ibm_graphics), MAXPCHARS, 0);
+#ifdef PC9800
+           if (ibmgraphics_mode_callback) (*ibmgraphics_mode_callback)();
+#endif
+           break;
+#endif /* ASCIIGRAPH */
+#ifdef TERMLIB
+       case DEC_GRAPHICS:
+/*
+ * Use the VT100 line drawing character set.
+ */
+           iflags.DECgraphics = TRUE;
+           iflags.IBMgraphics = FALSE;
+           assign_graphics(dec_graphics, SIZE(dec_graphics), MAXPCHARS, 0);
+           if (decgraphics_mode_callback) (*decgraphics_mode_callback)();
+           break;
+#endif /* TERMLIB */
+#ifdef MAC_GRAPHICS_ENV
+       case MAC_GRAPHICS:
+           assign_graphics(mac_graphics, SIZE(mac_graphics), MAXPCHARS, 0);
+           break;
+#endif
+       }
+    return;
+}
+
+
+#ifdef REINCARNATION
+
+/*
+ * saved display symbols for objects & features.
+ */
+static uchar save_oc_syms[MAXOCLASSES] = DUMMY;
+static uchar save_showsyms[MAXPCHARS]  = DUMMY;
+static uchar save_monsyms[MAXPCHARS]   = DUMMY;
+
+static const uchar r_oc_syms[MAXOCLASSES] = {
+/* 0*/ '\0',
+       ILLOBJ_SYM,
+       WEAPON_SYM,
+       ']',                    /* armor */
+       RING_SYM,
+/* 5*/ ',',                    /* amulet */
+       TOOL_SYM,
+       ':',                    /* food */
+       POTION_SYM,
+       SCROLL_SYM,
+/*10*/ SPBOOK_SYM,
+       WAND_SYM,
+       GEM_SYM,                /* gold -- yes it's the same as gems */
+       GEM_SYM,
+       ROCK_SYM,
+/*15*/ BALL_SYM,
+       CHAIN_SYM,
+       VENOM_SYM
+};
+
+# ifdef ASCIIGRAPH
+/* Rogue level graphics.  Under IBM graphics mode, use the symbols that were
+ * used for Rogue on the IBM PC.  Unfortunately, this can't be completely
+ * done because some of these are control characters--armor and rings under
+ * DOS, and a whole bunch of them under Linux.  Use the TTY Rogue characters
+ * for those cases.
+ */
+static const uchar IBM_r_oc_syms[MAXOCLASSES] = {      /* a la EPYX Rogue */
+/* 0*/ '\0',
+       ILLOBJ_SYM,
+#  if defined(MSDOS) || defined(OS2) || ( defined(WIN32) && !defined(MSWIN_GRAPHICS) )
+       0x18,                   /* weapon: up arrow */
+/*     0x0a, */ ARMOR_SYM,     /* armor:  Vert rect with o */
+/*     0x09, */ RING_SYM,      /* ring:   circle with arrow */
+/* 5*/ 0x0c,                   /* amulet: "female" symbol */
+       TOOL_SYM,
+       0x05,                   /* food:   club (as in cards) */
+       0xad,                   /* potion: upside down '!' */
+       0x0e,                   /* scroll: musical note */
+/*10*/ SPBOOK_SYM,
+       0xe7,                   /* wand:   greek tau */
+       0x0f,                   /* gold:   yes it's the same as gems */
+       0x0f,                   /* gems:   fancy '*' */
+#  else
+       ')',                    /* weapon  */
+       ARMOR_SYM,              /* armor */
+       RING_SYM,               /* ring */
+/* 5*/ ',',                    /* amulet  */
+       TOOL_SYM,
+       ':',                    /* food    */
+       0xad,                   /* potion: upside down '!' */
+       SCROLL_SYM,             /* scroll  */
+/*10*/ SPBOOK_SYM,
+       0xe7,                   /* wand:   greek tau */
+       GEM_SYM,                /* gold:   yes it's the same as gems */
+       GEM_SYM,                /* gems    */
+#  endif
+       ROCK_SYM,
+/*15*/ BALL_SYM,
+       CHAIN_SYM,
+       VENOM_SYM
+};
+# endif /* ASCIIGRAPH */
+
+void
+assign_rogue_graphics(is_rlevel)
+boolean is_rlevel;
+{
+    /* Adjust graphics display characters on Rogue levels */
+
+    if (is_rlevel) {
+       register int i;
+
+       (void) memcpy((genericptr_t)save_showsyms,
+                     (genericptr_t)showsyms, sizeof showsyms);
+       (void) memcpy((genericptr_t)save_oc_syms,
+                     (genericptr_t)oc_syms, sizeof oc_syms);
+       (void) memcpy((genericptr_t)save_monsyms,
+                     (genericptr_t)monsyms, sizeof monsyms);
+
+       /* Use a loop: char != uchar on some machines. */
+       for (i = 0; i < MAXMCLASSES; i++)
+           monsyms[i] = def_monsyms[i];
+# if defined(ASCIIGRAPH) && !defined(MSWIN_GRAPHICS)
+       if (iflags.IBMgraphics
+#  if defined(USE_TILES) && defined(MSDOS)
+               && !iflags.grmode
+#  endif
+               )
+           monsyms[S_HUMAN] = 0x01; /* smiley face */
+# endif
+       for (i = 0; i < MAXPCHARS; i++)
+           showsyms[i] = defsyms[i].sym;
+
+/*
+ * Some day if these rogue showsyms get much more extensive than this,
+ * we may want to create r_showsyms, and IBM_r_showsyms arrays to hold
+ * all of this info and to simply initialize it via a for() loop like r_oc_syms.
+ */
+
+# ifdef ASCIIGRAPH
+       if (!iflags.IBMgraphics
+#  if defined(USE_TILES) && defined(MSDOS)
+               || iflags.grmode
+#  endif
+                               ) {
+# endif
+           showsyms[S_vodoor]  = showsyms[S_hodoor]  = showsyms[S_ndoor] = '+';
+           showsyms[S_upstair] = showsyms[S_dnstair] = '%';
+# ifdef ASCIIGRAPH
+       } else {
+           /* a la EPYX Rogue */
+           showsyms[S_vwall]   = 0xba; /* all walls now use    */
+           showsyms[S_hwall]   = 0xcd; /* double line graphics */
+           showsyms[S_tlcorn]  = 0xc9;
+           showsyms[S_trcorn]  = 0xbb;
+           showsyms[S_blcorn]  = 0xc8;
+           showsyms[S_brcorn]  = 0xbc;
+           showsyms[S_crwall]  = 0xce;
+           showsyms[S_tuwall]  = 0xca;
+           showsyms[S_tdwall]  = 0xcb;
+           showsyms[S_tlwall]  = 0xb9;
+           showsyms[S_trwall]  = 0xcc;
+           showsyms[S_ndoor]   = 0xce;
+           showsyms[S_vodoor]  = 0xce;
+           showsyms[S_hodoor]  = 0xce;
+           showsyms[S_room]    = 0xfa; /* centered dot */
+           showsyms[S_corr]    = 0xb1;
+           showsyms[S_litcorr] = 0xb2;
+           showsyms[S_upstair] = 0xf0; /* Greek Xi */
+           showsyms[S_dnstair] = 0xf0;
+#ifndef MSWIN_GRAPHICS
+           showsyms[S_arrow_trap] = 0x04; /* diamond (cards) */
+           showsyms[S_dart_trap] = 0x04;
+           showsyms[S_falling_rock_trap] = 0x04;
+           showsyms[S_squeaky_board] = 0x04;
+           showsyms[S_bear_trap] = 0x04;
+           showsyms[S_land_mine] = 0x04;
+           showsyms[S_rolling_boulder_trap] = 0x04;
+           showsyms[S_sleeping_gas_trap] = 0x04;
+           showsyms[S_rust_trap] = 0x04;
+           showsyms[S_fire_trap] = 0x04;
+           showsyms[S_pit] = 0x04;
+           showsyms[S_spiked_pit] = 0x04;
+           showsyms[S_hole] = 0x04;
+           showsyms[S_trap_door] = 0x04;
+           showsyms[S_teleportation_trap] = 0x04;
+           showsyms[S_level_teleporter] = 0x04;
+           showsyms[S_magic_portal] = 0x04;
+           showsyms[S_web] = 0x04;
+           showsyms[S_statue_trap] = 0x04;
+           showsyms[S_magic_trap] = 0x04;
+           showsyms[S_anti_magic_trap] = 0x04;
+           showsyms[S_polymorph_trap] = 0x04;
+#endif
+       }
+#endif /* ASCIIGRAPH */
+
+       for (i = 0; i < MAXOCLASSES; i++) {
+#ifdef ASCIIGRAPH
+           if (iflags.IBMgraphics
+# if defined(USE_TILES) && defined(MSDOS)
+               && !iflags.grmode
+# endif
+               )
+               oc_syms[i] = IBM_r_oc_syms[i];
+           else
+#endif /* ASCIIGRAPH */
+               oc_syms[i] = r_oc_syms[i];
+       }
+#if defined(MSDOS) && defined(USE_TILES)
+       if (iflags.grmode) tileview(FALSE);
+#endif
+    } else {
+       (void) memcpy((genericptr_t)showsyms,
+                     (genericptr_t)save_showsyms, sizeof showsyms);
+       (void) memcpy((genericptr_t)oc_syms,
+                     (genericptr_t)save_oc_syms, sizeof oc_syms);
+       (void) memcpy((genericptr_t)monsyms,
+                     (genericptr_t)save_monsyms, sizeof monsyms);
+#if defined(MSDOS) && defined(USE_TILES)
+       if (iflags.grmode) tileview(TRUE);
+#endif
+    }
+}
+#endif /* REINCARNATION */
+
+/*drawing.c*/
diff --git a/src/dungeon.c b/src/dungeon.c
new file mode 100644 (file)
index 0000000..b87b8bb
--- /dev/null
@@ -0,0 +1,1744 @@
+/*     SCCS Id: @(#)dungeon.c  3.4     1999/10/30      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "dgn_file.h"
+#include "dlb.h"
+
+#ifdef OVL1
+
+#define DUNGEON_FILE   "dungeon"
+
+#define X_START                "x-strt"
+#define X_LOCATE       "x-loca"
+#define X_GOAL         "x-goal"
+
+struct proto_dungeon {
+       struct  tmpdungeon tmpdungeon[MAXDUNGEON];
+       struct  tmplevel   tmplevel[LEV_LIMIT];
+       s_level *final_lev[LEV_LIMIT];  /* corresponding level pointers */
+       struct  tmpbranch  tmpbranch[BRANCH_LIMIT];
+
+       int     start;  /* starting index of current dungeon sp levels */
+       int     n_levs; /* number of tmplevel entries */
+       int     n_brs;  /* number of tmpbranch entries */
+};
+
+int n_dgns;                            /* number of dungeons (used here,  */
+                                       /*   and mklev.c)                  */
+static branch *branches = (branch *) 0;        /* dungeon branch list             */
+
+struct lchoice {
+       int idx;
+       schar lev[MAXLINFO];
+       schar playerlev[MAXLINFO];
+       xchar dgn[MAXLINFO];
+       char menuletter;
+};
+
+static void FDECL(Fread, (genericptr_t, int, int, dlb *));
+STATIC_DCL xchar FDECL(dname_to_dnum, (const char *));
+STATIC_DCL int FDECL(find_branch, (const char *, struct proto_dungeon *));
+STATIC_DCL xchar FDECL(parent_dnum, (const char *, struct proto_dungeon *));
+STATIC_DCL int FDECL(level_range, (XCHAR_P,int,int,int,struct proto_dungeon *,int *));
+STATIC_DCL xchar FDECL(parent_dlevel, (const char *, struct proto_dungeon *));
+STATIC_DCL int FDECL(correct_branch_type, (struct tmpbranch *));
+STATIC_DCL branch *FDECL(add_branch, (int, int, struct proto_dungeon *));
+STATIC_DCL void FDECL(add_level, (s_level *));
+STATIC_DCL void FDECL(init_level, (int,int,struct proto_dungeon *));
+STATIC_DCL int FDECL(possible_places, (int, boolean *, struct proto_dungeon *));
+STATIC_DCL xchar FDECL(pick_level, (boolean *, int));
+STATIC_DCL boolean FDECL(place_level, (int, struct proto_dungeon *));
+#ifdef WIZARD
+STATIC_DCL const char *FDECL(br_string, (int));
+STATIC_DCL void FDECL(print_branch, (winid, int, int, int, BOOLEAN_P, struct lchoice *));
+#endif
+
+#ifdef DEBUG
+#define DD     dungeons[i]
+STATIC_DCL void NDECL(dumpit);
+
+STATIC_OVL void
+dumpit()
+{
+       int     i;
+       s_level *x;
+       branch *br;
+
+       for(i = 0; i < n_dgns; i++)  {
+           fprintf(stderr, "\n#%d \"%s\" (%s):\n", i,
+                               DD.dname, DD.proto);
+           fprintf(stderr, "    num_dunlevs %d, dunlev_ureached %d\n",
+                               DD.num_dunlevs, DD.dunlev_ureached);
+           fprintf(stderr, "    depth_start %d, ledger_start %d\n",
+                               DD.depth_start, DD.ledger_start);
+           fprintf(stderr, "    flags:%s%s%s\n",
+                   DD.flags.rogue_like ? " rogue_like" : "",
+                   DD.flags.maze_like  ? " maze_like"  : "",
+                   DD.flags.hellish    ? " hellish"    : "");
+           getchar();
+       }
+       fprintf(stderr,"\nSpecial levels:\n");
+       for(x = sp_levchn; x; x = x->next) {
+           fprintf(stderr, "%s (%d): ", x->proto, x->rndlevs);
+           fprintf(stderr, "on %d, %d; ", x->dlevel.dnum, x->dlevel.dlevel);
+           fprintf(stderr, "flags:%s%s%s%s\n",
+                   x->flags.rogue_like ? " rogue_like" : "",
+                   x->flags.maze_like  ? " maze_like"  : "",
+                   x->flags.hellish    ? " hellish"    : "",
+                   x->flags.town       ? " town"       : "");
+           getchar();
+       }
+       fprintf(stderr,"\nBranches:\n");
+       for (br = branches; br; br = br->next) {
+           fprintf(stderr, "%d: %s, end1 %d %d, end2 %d %d, %s\n",
+               br->id,
+               br->type == BR_STAIR ? "stair" :
+                   br->type == BR_NO_END1 ? "no end1" :
+                   br->type == BR_NO_END2 ? "no end2" :
+                   br->type == BR_PORTAL  ? "portal"  :
+                                            "unknown",
+               br->end1.dnum, br->end1.dlevel,
+               br->end2.dnum, br->end2.dlevel,
+               br->end1_up ? "end1 up" : "end1 down");
+       }
+       getchar();
+       fprintf(stderr,"\nDone\n");
+       getchar();
+}
+#endif
+
+/* Save the dungeon structures. */
+void
+save_dungeon(fd, perform_write, free_data)
+    int fd;
+    boolean perform_write, free_data;
+{
+    branch *curr, *next;
+    int    count;
+
+    if (perform_write) {
+       bwrite(fd, (genericptr_t) &n_dgns, sizeof n_dgns);
+       bwrite(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned)n_dgns);
+       bwrite(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
+       bwrite(fd, (genericptr_t) tune, sizeof tune);
+
+       for (count = 0, curr = branches; curr; curr = curr->next)
+           count++;
+       bwrite(fd, (genericptr_t) &count, sizeof(count));
+
+       for (curr = branches; curr; curr = curr->next)
+           bwrite(fd, (genericptr_t) curr, sizeof (branch));
+
+       count = maxledgerno();
+       bwrite(fd, (genericptr_t) &count, sizeof count);
+       bwrite(fd, (genericptr_t) level_info,
+                       (unsigned)count * sizeof (struct linfo));
+       bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
+    }
+
+    if (free_data) {
+       for (curr = branches; curr; curr = next) {
+           next = curr->next;
+           free((genericptr_t) curr);
+       }
+       branches = 0;
+    }
+}
+
+/* Restore the dungeon structures. */
+void
+restore_dungeon(fd)
+    int fd;
+{
+    branch *curr, *last;
+    int    count, i;
+
+    mread(fd, (genericptr_t) &n_dgns, sizeof(n_dgns));
+    mread(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned)n_dgns);
+    mread(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
+    mread(fd, (genericptr_t) tune, sizeof tune);
+
+    last = branches = (branch *) 0;
+
+    mread(fd, (genericptr_t) &count, sizeof(count));
+    for (i = 0; i < count; i++) {
+       curr = (branch *) alloc(sizeof(branch));
+       mread(fd, (genericptr_t) curr, sizeof(branch));
+       curr->next = (branch *) 0;
+       if (last)
+           last->next = curr;
+       else
+           branches = curr;
+       last = curr;
+    }
+
+    mread(fd, (genericptr_t) &count, sizeof(count));
+    if (count >= MAXLINFO)
+       panic("level information count larger (%d) than allocated size", count);
+    mread(fd, (genericptr_t) level_info, (unsigned)count*sizeof(struct linfo));
+    mread(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
+}
+
+static void
+Fread(ptr, size, nitems, stream)
+       genericptr_t    ptr;
+       int     size, nitems;
+       dlb     *stream;
+{
+       int cnt;
+
+       if((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) {
+           panic(
+ "Premature EOF on dungeon description file!\r\nExpected %d bytes - got %d.",
+                 (size * nitems), (size * cnt));
+           terminate(EXIT_FAILURE);
+       }
+}
+
+STATIC_OVL xchar
+dname_to_dnum(s)
+const char     *s;
+{
+       xchar   i;
+
+       for (i = 0; i < n_dgns; i++)
+           if (!strcmp(dungeons[i].dname, s)) return i;
+
+       panic("Couldn't resolve dungeon number for name \"%s\".", s);
+       /*NOT REACHED*/
+       return (xchar)0;
+}
+
+s_level *
+find_level(s)
+       const char *s;
+{
+       s_level *curr;
+       for(curr = sp_levchn; curr; curr = curr->next)
+           if (!strcmpi(s, curr->proto)) break;
+       return curr;
+}
+
+/* Find the branch that links the named dungeon. */
+STATIC_OVL int
+find_branch(s, pd)
+       const char *s;          /* dungeon name */
+       struct proto_dungeon *pd;
+{
+       int i;
+
+       if (pd) {
+           for (i = 0; i < pd->n_brs; i++)
+               if (!strcmp(pd->tmpbranch[i].name, s)) break;
+           if (i == pd->n_brs) panic("find_branch: can't find %s", s);
+       } else {
+           /* support for level tport by name */
+           branch *br;
+           const char *dnam;
+
+           for (br = branches; br; br = br->next) {
+               dnam = dungeons[br->end2.dnum].dname;
+               if (!strcmpi(dnam, s) ||
+                       (!strncmpi(dnam, "The ", 4) && !strcmpi(dnam + 4, s)))
+                   break;
+           }
+           i = br ? ((ledger_no(&br->end1) << 8) | ledger_no(&br->end2)) : -1;
+       }
+       return i;
+}
+
+
+/*
+ * Find the "parent" by searching the prototype branch list for the branch
+ * listing, then figuring out to which dungeon it belongs.
+ */
+STATIC_OVL xchar
+parent_dnum(s, pd)
+const char        *s;  /* dungeon name */
+struct proto_dungeon *pd;
+{
+       int     i;
+       xchar   pdnum;
+
+       i = find_branch(s, pd);
+       /*
+        * Got branch, now find parent dungeon.  Stop if we have reached
+        * "this" dungeon (if we haven't found it by now it is an error).
+        */
+       for (pdnum = 0; strcmp(pd->tmpdungeon[pdnum].name, s); pdnum++)
+           if ((i -= pd->tmpdungeon[pdnum].branches) < 0)
+               return(pdnum);
+
+       panic("parent_dnum: couldn't resolve branch.");
+       /*NOT REACHED*/
+       return (xchar)0;
+}
+
+/*
+ * Return a starting point and number of successive positions a level
+ * or dungeon entrance can occupy.
+ *
+ * Note: This follows the acouple (instead of the rcouple) rules for a
+ *      negative random component (rand < 0).  These rules are found
+ *      in dgn_comp.y.  The acouple [absolute couple] section says that
+ *      a negative random component means from the (adjusted) base to the
+ *      end of the dungeon.
+ */
+STATIC_OVL int
+level_range(dgn, base, rand, chain, pd, adjusted_base)
+       xchar   dgn;
+       int     base, rand, chain;
+       struct proto_dungeon *pd;
+       int *adjusted_base;
+{
+       int lmax = dungeons[dgn].num_dunlevs;
+
+       if (chain >= 0) {                /* relative to a special level */
+           s_level *levtmp = pd->final_lev[chain];
+           if (!levtmp) panic("level_range: empty chain level!");
+
+           base += levtmp->dlevel.dlevel;
+       } else {                        /* absolute in the dungeon */
+           /* from end of dungeon */
+           if (base < 0) base = (lmax + base + 1);
+       }
+
+       if (base < 1 || base > lmax)
+           panic("level_range: base value out of range");
+
+       *adjusted_base = base;
+
+       if (rand == -1) {       /* from base to end of dungeon */
+           return (lmax - base + 1);
+       } else if (rand) {
+           /* make sure we don't run off the end of the dungeon */
+           return (((base + rand - 1) > lmax) ? lmax-base+1 : rand);
+       } /* else only one choice */
+       return 1;
+}
+
+STATIC_OVL xchar
+parent_dlevel(s, pd)
+       const char      *s;
+       struct proto_dungeon *pd;
+{
+       int i, j, num, base, dnum = parent_dnum(s, pd);
+       branch *curr;
+
+
+       i = find_branch(s, pd);
+       num = level_range(dnum, pd->tmpbranch[i].lev.base,
+                                             pd->tmpbranch[i].lev.rand,
+                                             pd->tmpbranch[i].chain,
+                                             pd, &base);
+
+       /* KMH -- Try our best to find a level without an existing branch */
+       i = j = rn2(num);
+       do {
+               if (++i >= num) i = 0;
+               for (curr = branches; curr; curr = curr->next)
+                       if ((curr->end1.dnum == dnum && curr->end1.dlevel == base+i) ||
+                               (curr->end2.dnum == dnum && curr->end2.dlevel == base+i))
+                               break;
+       } while (curr && i != j);
+       return (base + i);
+}
+
+/* Convert from the temporary branch type to the dungeon branch type. */
+STATIC_OVL int
+correct_branch_type(tbr)
+    struct tmpbranch *tbr;
+{
+    switch (tbr->type) {
+       case TBR_STAIR:         return BR_STAIR;
+       case TBR_NO_UP:         return tbr->up ? BR_NO_END1 : BR_NO_END2;
+       case TBR_NO_DOWN:       return tbr->up ? BR_NO_END2 : BR_NO_END1;
+       case TBR_PORTAL:        return BR_PORTAL;
+    }
+    impossible("correct_branch_type: unknown branch type");
+    return BR_STAIR;
+}
+
+/*
+ * Add the given branch to the branch list.  The branch list is ordered
+ * by end1 dungeon and level followed by end2 dungeon and level.  If
+ * extract_first is true, then the branch is already part of the list
+ * but needs to be repositioned.
+ */
+void
+insert_branch(new_branch, extract_first)
+   branch *new_branch;
+   boolean extract_first;
+{
+    branch *curr, *prev;
+    long new_val, curr_val, prev_val;
+
+    if (extract_first) {
+       for (prev = 0, curr = branches; curr; prev = curr, curr = curr->next)
+           if (curr == new_branch) break;
+
+       if (!curr) panic("insert_branch: not found");
+       if (prev)
+           prev->next = curr->next;
+       else
+           branches = curr->next;
+    }
+    new_branch->next = (branch *) 0;
+
+/* Convert the branch into a unique number so we can sort them. */
+#define branch_val(bp) \
+       ((((long)(bp)->end1.dnum * (MAXLEVEL+1) + \
+         (long)(bp)->end1.dlevel) * (MAXDUNGEON+1) * (MAXLEVEL+1)) + \
+        ((long)(bp)->end2.dnum * (MAXLEVEL+1) + (long)(bp)->end2.dlevel))
+
+    /*
+     * Insert the new branch into the correct place in the branch list.
+     */
+    prev = (branch *) 0;
+    prev_val = -1;
+    new_val = branch_val(new_branch);
+    for (curr = branches; curr;
+                   prev_val = curr_val, prev = curr, curr = curr->next) {
+       curr_val = branch_val(curr);
+       if (prev_val < new_val && new_val <= curr_val) break;
+    }
+    if (prev) {
+       new_branch->next = curr;
+       prev->next = new_branch;
+    } else {
+       new_branch->next = branches;
+       branches = new_branch;
+    }
+}
+
+/* Add a dungeon branch to the branch list. */
+STATIC_OVL branch *
+add_branch(dgn, child_entry_level, pd)
+    int dgn;
+    int child_entry_level;
+    struct proto_dungeon *pd;
+{
+    static int branch_id = 0;
+    int branch_num;
+    branch *new_branch;
+
+    branch_num = find_branch(dungeons[dgn].dname,pd);
+    new_branch = (branch *) alloc(sizeof(branch));
+    new_branch->next = (branch *) 0;
+    new_branch->id = branch_id++;
+    new_branch->type = correct_branch_type(&pd->tmpbranch[branch_num]);
+    new_branch->end1.dnum = parent_dnum(dungeons[dgn].dname, pd);
+    new_branch->end1.dlevel = parent_dlevel(dungeons[dgn].dname, pd);
+    new_branch->end2.dnum = dgn;
+    new_branch->end2.dlevel = child_entry_level;
+    new_branch->end1_up = pd->tmpbranch[branch_num].up ? TRUE : FALSE;
+
+    insert_branch(new_branch, FALSE);
+    return new_branch;
+}
+
+/*
+ * Add new level to special level chain.  Insert it in level order with the
+ * other levels in this dungeon.  This assumes that we are never given a
+ * level that has a dungeon number less than the dungeon number of the
+ * last entry.
+ */
+STATIC_OVL void
+add_level(new_lev)
+    s_level *new_lev;
+{
+       s_level *prev, *curr;
+
+       prev = (s_level *) 0;
+       for (curr = sp_levchn; curr; curr = curr->next) {
+           if (curr->dlevel.dnum == new_lev->dlevel.dnum &&
+                   curr->dlevel.dlevel > new_lev->dlevel.dlevel)
+               break;
+           prev = curr;
+       }
+       if (!prev) {
+           new_lev->next = sp_levchn;
+           sp_levchn = new_lev;
+       } else {
+           new_lev->next = curr;
+           prev->next = new_lev;
+       }
+}
+
+STATIC_OVL void
+init_level(dgn, proto_index, pd)
+       int dgn, proto_index;
+       struct proto_dungeon *pd;
+{
+       s_level *new_level;
+       struct tmplevel *tlevel = &pd->tmplevel[proto_index];
+
+       pd->final_lev[proto_index] = (s_level *) 0; /* no "real" level */
+#ifdef WIZARD
+       if (!wizard)
+#endif
+           if (tlevel->chance <= rn2(100)) return;
+
+       pd->final_lev[proto_index] = new_level =
+                                       (s_level *) alloc(sizeof(s_level));
+       /* load new level with data */
+       Strcpy(new_level->proto, tlevel->name);
+       new_level->boneid = tlevel->boneschar;
+       new_level->dlevel.dnum = dgn;
+       new_level->dlevel.dlevel = 0;   /* for now */
+
+       new_level->flags.town = !!(tlevel->flags & TOWN);
+       new_level->flags.hellish = !!(tlevel->flags & HELLISH);
+       new_level->flags.maze_like = !!(tlevel->flags & MAZELIKE);
+       new_level->flags.rogue_like = !!(tlevel->flags & ROGUELIKE);
+       new_level->flags.align = ((tlevel->flags & D_ALIGN_MASK) >> 4);
+       if (!new_level->flags.align) 
+           new_level->flags.align =
+               ((pd->tmpdungeon[dgn].flags & D_ALIGN_MASK) >> 4);
+
+       new_level->rndlevs = tlevel->rndlevs;
+       new_level->next    = (s_level *) 0;
+}
+
+STATIC_OVL int
+possible_places(idx, map, pd)
+    int idx;           /* prototype index */
+    boolean *map;      /* array MAXLEVEL+1 in length */
+    struct proto_dungeon *pd;
+{
+    int i, start, count;
+    s_level *lev = pd->final_lev[idx];
+
+    /* init level possibilities */
+    for (i = 0; i <= MAXLEVEL; i++) map[i] = FALSE;
+
+    /* get base and range and set those entried to true */
+    count = level_range(lev->dlevel.dnum, pd->tmplevel[idx].lev.base,
+                                       pd->tmplevel[idx].lev.rand,
+                                       pd->tmplevel[idx].chain,
+                                       pd, &start);
+    for (i = start; i < start+count; i++)
+       map[i] = TRUE;
+
+    /* mark off already placed levels */
+    for (i = pd->start; i < idx; i++) {
+       if (pd->final_lev[i] && map[pd->final_lev[i]->dlevel.dlevel]) {
+           map[pd->final_lev[i]->dlevel.dlevel] = FALSE;
+           --count;
+       }
+    }
+
+    return count;
+}
+
+/* Pick the nth TRUE entry in the given boolean array. */
+STATIC_OVL xchar
+pick_level(map, nth)
+    boolean *map;      /* an array MAXLEVEL+1 in size */
+    int nth;
+{
+    int i;
+    for (i = 1; i <= MAXLEVEL; i++)
+       if (map[i] && !nth--) return (xchar) i;
+    panic("pick_level:  ran out of valid levels");
+    return 0;
+}
+
+#ifdef DDEBUG
+static void FDECL(indent,(int));
+
+static void
+indent(d)
+int d;
+{
+    while (d-- > 0) fputs("    ", stderr);
+}
+#endif
+
+/*
+ * Place a level.  First, find the possible places on a dungeon map
+ * template.  Next pick one.  Then try to place the next level.  If
+ * sucessful, we're done.  Otherwise, try another (and another) until
+ * all possible places have been tried.  If all possible places have
+ * been exausted, return false.
+ */
+STATIC_OVL boolean
+place_level(proto_index, pd)
+    int proto_index;
+    struct proto_dungeon *pd;
+{
+    boolean map[MAXLEVEL+1];   /* valid levels are 1..MAXLEVEL inclusive */
+    s_level *lev;
+    int npossible;
+#ifdef DDEBUG
+    int i;
+#endif
+
+    if (proto_index == pd->n_levs) return TRUE;        /* at end of proto levels */
+
+    lev = pd->final_lev[proto_index];
+
+    /* No level created for this prototype, goto next. */
+    if (!lev) return place_level(proto_index+1, pd);
+
+    npossible = possible_places(proto_index, map, pd);
+
+    for (; npossible; --npossible) {
+       lev->dlevel.dlevel = pick_level(map, rn2(npossible));
+#ifdef DDEBUG
+       indent(proto_index-pd->start);
+       fprintf(stderr,"%s: trying %d [ ", lev->proto, lev->dlevel.dlevel);
+       for (i = 1; i <= MAXLEVEL; i++)
+           if (map[i]) fprintf(stderr,"%d ", i);
+       fprintf(stderr,"]\n");
+#endif
+       if (place_level(proto_index+1, pd)) return TRUE;
+       map[lev->dlevel.dlevel] = FALSE;        /* this choice didn't work */
+    }
+#ifdef DDEBUG
+    indent(proto_index-pd->start);
+    fprintf(stderr,"%s: failed\n", lev->proto);
+#endif
+    return FALSE;
+}
+
+
+struct level_map {
+       const char *lev_name;
+       d_level *lev_spec;
+} level_map[] = {
+       { "air",        &air_level },
+       { "asmodeus",   &asmodeus_level },
+       { "astral",     &astral_level },
+       { "baalz",      &baalzebub_level },
+       { "bigroom",    &bigroom_level },
+       { "castle",     &stronghold_level },
+       { "earth",      &earth_level },
+       { "fakewiz1",   &portal_level },
+       { "fire",       &fire_level },
+       { "juiblex",    &juiblex_level },
+       { "knox",       &knox_level },
+       { "medusa",     &medusa_level },
+       { "oracle",     &oracle_level },
+       { "orcus",      &orcus_level },
+#ifdef REINCARNATION
+       { "rogue",      &rogue_level },
+#endif
+       { "sanctum",    &sanctum_level },
+       { "valley",     &valley_level },
+       { "water",      &water_level },
+       { "wizard1",    &wiz1_level },
+       { "wizard2",    &wiz2_level },
+       { "wizard3",    &wiz3_level },
+       { X_START,      &qstart_level },
+       { X_LOCATE,     &qlocate_level },
+       { X_GOAL,       &nemesis_level },
+       { "",           (d_level *)0 }
+};
+
+void
+init_dungeons()                /* initialize the "dungeon" structs */
+{
+       dlb     *dgn_file;
+       register int i, cl = 0, cb = 0;
+       register s_level *x;
+       struct proto_dungeon pd;
+       struct level_map *lev_map;
+       struct version_info vers_info;
+
+       pd.n_levs = pd.n_brs = 0;
+
+       dgn_file = dlb_fopen(DUNGEON_FILE, RDBMODE);
+       if (!dgn_file) {
+           char tbuf[BUFSZ];
+           Sprintf(tbuf, "Cannot open dungeon description - \"%s",
+               DUNGEON_FILE);
+#ifdef DLBRSRC /* using a resource from the executable */
+           Strcat(tbuf, "\" resource!");
+#else /* using a file or DLB file */
+# if defined(DLB)
+           Strcat(tbuf, "\" from ");
+#  ifdef PREFIXES_IN_USE
+           Strcat(tbuf, "\n\"");
+           if (fqn_prefix[DATAPREFIX]) Strcat(tbuf, fqn_prefix[DATAPREFIX]);
+#  else
+           Strcat(tbuf, "\"");
+#  endif
+           Strcat(tbuf, DLBFILE);
+# endif
+           Strcat(tbuf, "\" file!");
+#endif
+#ifdef WIN32
+           interject_assistance(1, INTERJECT_PANIC, (genericptr_t)tbuf,
+                                (genericptr_t)fqn_prefix[DATAPREFIX]);
+#endif
+           panic(tbuf);
+       }
+
+       /* validate the data's version against the program's version */
+       Fread((genericptr_t) &vers_info, sizeof vers_info, 1, dgn_file);
+       /* we'd better clear the screen now, since when error messages come from
+        * check_version() they will be printed using pline(), which doesn't
+        * mix with the raw messages that might be already on the screen
+        */
+       if (iflags.window_inited) clear_nhwindow(WIN_MAP);
+       if (!check_version(&vers_info, DUNGEON_FILE, TRUE))
+           panic("Dungeon description not valid.");
+
+       /*
+        * Read in each dungeon and transfer the results to the internal
+        * dungeon arrays.
+        */
+       sp_levchn = (s_level *) 0;
+       Fread((genericptr_t)&n_dgns, sizeof(int), 1, dgn_file);
+       if (n_dgns >= MAXDUNGEON)
+           panic("init_dungeons: too many dungeons");
+
+       for (i = 0; i < n_dgns; i++) {
+           Fread((genericptr_t)&pd.tmpdungeon[i],
+                                   sizeof(struct tmpdungeon), 1, dgn_file);
+#ifdef WIZARD
+           if(!wizard)
+#endif
+             if(pd.tmpdungeon[i].chance && (pd.tmpdungeon[i].chance <= rn2(100))) {
+               int j;
+
+               /* skip over any levels or branches */
+               for(j = 0; j < pd.tmpdungeon[i].levels; j++)
+                   Fread((genericptr_t)&pd.tmplevel[cl], sizeof(struct tmplevel),
+                                                       1, dgn_file);
+
+               for(j = 0; j < pd.tmpdungeon[i].branches; j++)
+                   Fread((genericptr_t)&pd.tmpbranch[cb],
+                                       sizeof(struct tmpbranch), 1, dgn_file);
+               n_dgns--; i--;
+               continue;
+             }
+
+           Strcpy(dungeons[i].dname, pd.tmpdungeon[i].name);
+           Strcpy(dungeons[i].proto, pd.tmpdungeon[i].protoname);
+           dungeons[i].boneid = pd.tmpdungeon[i].boneschar;
+
+           if(pd.tmpdungeon[i].lev.rand)
+               dungeons[i].num_dunlevs = (xchar)rn1(pd.tmpdungeon[i].lev.rand,
+                                                    pd.tmpdungeon[i].lev.base);
+           else dungeons[i].num_dunlevs = (xchar)pd.tmpdungeon[i].lev.base;
+
+           if(!i) {
+               dungeons[i].ledger_start = 0;
+               dungeons[i].depth_start = 1;
+               dungeons[i].dunlev_ureached = 1;
+           } else {
+               dungeons[i].ledger_start = dungeons[i-1].ledger_start +
+                                             dungeons[i-1].num_dunlevs;
+               dungeons[i].dunlev_ureached = 0;
+           }
+
+           dungeons[i].flags.hellish = !!(pd.tmpdungeon[i].flags & HELLISH);
+           dungeons[i].flags.maze_like = !!(pd.tmpdungeon[i].flags & MAZELIKE);
+           dungeons[i].flags.rogue_like = !!(pd.tmpdungeon[i].flags & ROGUELIKE);
+           dungeons[i].flags.align = ((pd.tmpdungeon[i].flags & D_ALIGN_MASK) >> 4);
+           /*
+            * Set the entry level for this dungeon.  The pd.tmpdungeon entry
+            * value means:
+            *          < 0     from bottom (-1 == bottom level)
+            *            0     default (top)
+            *          > 0     actual level (1 = top)
+            *
+            * Note that the entry_lev field in the dungeon structure is
+            * redundant.  It is used only here and in print_dungeon().
+            */
+           if (pd.tmpdungeon[i].entry_lev < 0) {
+               dungeons[i].entry_lev = dungeons[i].num_dunlevs +
+                                               pd.tmpdungeon[i].entry_lev + 1;
+               if (dungeons[i].entry_lev <= 0) dungeons[i].entry_lev = 1;
+           } else if (pd.tmpdungeon[i].entry_lev > 0) {
+               dungeons[i].entry_lev = pd.tmpdungeon[i].entry_lev;
+               if (dungeons[i].entry_lev > dungeons[i].num_dunlevs)
+                   dungeons[i].entry_lev = dungeons[i].num_dunlevs;
+           } else { /* default */
+               dungeons[i].entry_lev = 1;      /* defaults to top level */
+           }
+
+           if (i) {    /* set depth */
+               branch *br;
+               schar from_depth;
+               boolean from_up;
+
+               br = add_branch(i, dungeons[i].entry_lev, &pd);
+
+               /* Get the depth of the connecting end. */
+               if (br->end1.dnum == i) {
+                   from_depth = depth(&br->end2);
+                   from_up = !br->end1_up;
+               } else {
+                   from_depth = depth(&br->end1);
+                   from_up = br->end1_up;
+               }
+
+               /*
+                * Calculate the depth of the top of the dungeon via
+                * its branch.  First, the depth of the entry point:
+                *
+                *      depth of branch from "parent" dungeon
+                *      + -1 or 1 depending on a up or down stair or
+                *        0 if portal
+                *
+                * Followed by the depth of the top of the dungeon:
+                *
+                *      - (entry depth - 1)
+                *
+                * We'll say that portals stay on the same depth.
+                */
+               dungeons[i].depth_start = from_depth
+                                       + (br->type == BR_PORTAL ? 0 :
+                                                       (from_up ? -1 : 1))
+                                       - (dungeons[i].entry_lev - 1);
+           }
+
+           /* this is redundant - it should have been flagged by dgn_comp */
+           if(dungeons[i].num_dunlevs > MAXLEVEL)
+               dungeons[i].num_dunlevs = MAXLEVEL;
+
+           pd.start = pd.n_levs;       /* save starting point */
+           pd.n_levs += pd.tmpdungeon[i].levels;
+           if (pd.n_levs > LEV_LIMIT)
+               panic("init_dungeon: too many special levels");
+           /*
+            * Read in the prototype special levels.  Don't add generated
+            * special levels until they are all placed.
+            */
+           for(; cl < pd.n_levs; cl++) {
+               Fread((genericptr_t)&pd.tmplevel[cl],
+                                       sizeof(struct tmplevel), 1, dgn_file);
+               init_level(i, cl, &pd);
+           }
+           /*
+            * Recursively place the generated levels for this dungeon.  This
+            * routine will attempt all possible combinations before giving
+            * up.
+            */
+           if (!place_level(pd.start, &pd))
+               panic("init_dungeon:  couldn't place levels");
+#ifdef DDEBUG
+           fprintf(stderr, "--- end of dungeon %d ---\n", i);
+           fflush(stderr);
+           getchar();
+#endif
+           for (; pd.start < pd.n_levs; pd.start++)
+               if (pd.final_lev[pd.start]) add_level(pd.final_lev[pd.start]);
+
+
+           pd.n_brs += pd.tmpdungeon[i].branches;
+           if (pd.n_brs > BRANCH_LIMIT)
+               panic("init_dungeon: too many branches");
+           for(; cb < pd.n_brs; cb++)
+               Fread((genericptr_t)&pd.tmpbranch[cb],
+                                       sizeof(struct tmpbranch), 1, dgn_file);
+       }
+       (void) dlb_fclose(dgn_file);
+
+       for (i = 0; i < 5; i++) tune[i] = 'A' + rn2(7);
+       tune[5] = 0;
+
+       /*
+        * Find most of the special levels and dungeons so we can access their
+        * locations quickly.
+        */
+       for (lev_map = level_map; lev_map->lev_name[0]; lev_map++) {
+               x = find_level(lev_map->lev_name);
+               if (x) {
+                       assign_level(lev_map->lev_spec, &x->dlevel);
+                       if (!strncmp(lev_map->lev_name, "x-", 2)) {
+                               /* This is where the name substitution on the
+                                * levels of the quest dungeon occur.
+                                */
+                               Sprintf(x->proto, "%s%s", urole.filecode, &lev_map->lev_name[1]);
+                       } else if (lev_map->lev_spec == &knox_level) {
+                               branch *br;
+                               /*
+                                * Kludge to allow floating Knox entrance.  We
+                                * specify a floating entrance by the fact that
+                                * its entrance (end1) has a bogus dnum, namely
+                                * n_dgns.
+                                */
+                               for (br = branches; br; br = br->next)
+                                   if (on_level(&br->end2, &knox_level)) break;
+
+                               if (br) br->end1.dnum = n_dgns;
+                               /* adjust the branch's position on the list */
+                               insert_branch(br, TRUE);
+                       }
+               }
+       }
+/*
+ *     I hate hardwiring these names. :-(
+ */
+       quest_dnum = dname_to_dnum("The Quest");
+       sokoban_dnum = dname_to_dnum("Sokoban");
+       mines_dnum = dname_to_dnum("The Gnomish Mines");
+       tower_dnum = dname_to_dnum("Vlad's Tower");
+
+       /* one special fixup for dummy surface level */
+       if ((x = find_level("dummy")) != 0) {
+           i = x->dlevel.dnum;
+           /* the code above puts earth one level above dungeon level #1,
+              making the dummy level overlay level 1; but the whole reason
+              for having the dummy level is to make earth have depth -1
+              instead of 0, so adjust the start point to shift endgame up */
+           if (dunlevs_in_dungeon(&x->dlevel) > 1 - dungeons[i].depth_start)
+               dungeons[i].depth_start -= 1;
+           /* TO DO: strip "dummy" out all the way here,
+              so that it's hidden from <ctrl/O> feedback. */
+       }
+
+#ifdef DEBUG
+       dumpit();
+#endif
+}
+
+xchar
+dunlev(lev)    /* return the level number for lev in *this* dungeon */
+d_level        *lev;
+{
+       return(lev->dlevel);
+}
+
+xchar
+dunlevs_in_dungeon(lev)        /* return the lowest level number for *this* dungeon*/
+d_level        *lev;
+{
+       return(dungeons[lev->dnum].num_dunlevs);
+}
+
+xchar
+deepest_lev_reached(noquest) /* return the lowest level explored in the game*/
+boolean noquest;
+{
+       /* this function is used for three purposes: to provide a factor
+        * of difficulty in monster generation; to provide a factor of
+        * difficulty in experience calculations (botl.c and end.c); and
+        * to insert the deepest level reached in the game in the topten
+        * display.  the 'noquest' arg switch is required for the latter.
+        *
+        * from the player's point of view, going into the Quest is _not_
+        * going deeper into the dungeon -- it is going back "home", where
+        * the dungeon starts at level 1.  given the setup in dungeon.def,
+        * the depth of the Quest (thought of as starting at level 1) is
+        * never lower than the level of entry into the Quest, so we exclude
+        * the Quest from the topten "deepest level reached" display
+        * calculation.  _However_ the Quest is a difficult dungeon, so we
+        * include it in the factor of difficulty calculations.
+        */
+       register int i;
+       d_level tmp;
+       register schar ret = 0;
+
+       for(i = 0; i < n_dgns; i++) {
+           if((tmp.dlevel = dungeons[i].dunlev_ureached) == 0) continue;
+           if(!strcmp(dungeons[i].dname, "The Quest") && noquest) continue;
+
+           tmp.dnum = i;
+           if(depth(&tmp) > ret) ret = depth(&tmp);
+       }
+       return((xchar) ret);
+}
+
+/* return a bookkeeping level number for purpose of comparisons and
+ * save/restore */
+xchar
+ledger_no(lev)
+d_level        *lev;
+{
+       return((xchar)(lev->dlevel + dungeons[lev->dnum].ledger_start));
+}
+
+/*
+ * The last level in the bookkeeping list of level is the bottom of the last
+ * dungeon in the dungeons[] array.
+ *
+ * Maxledgerno() -- which is the max number of levels in the bookkeeping
+ * list, should not be confused with dunlevs_in_dungeon(lev) -- which
+ * returns the max number of levels in lev's dungeon, and both should
+ * not be confused with deepest_lev_reached() -- which returns the lowest
+ * depth visited by the player.
+ */
+xchar
+maxledgerno()
+{
+    return (xchar) (dungeons[n_dgns-1].ledger_start +
+                               dungeons[n_dgns-1].num_dunlevs);
+}
+
+/* return the dungeon that this ledgerno exists in */
+xchar
+ledger_to_dnum(ledgerno)
+xchar  ledgerno;
+{
+       register int i;
+
+       /* find i such that (i->base + 1) <= ledgerno <= (i->base + i->count) */
+       for (i = 0; i < n_dgns; i++)
+           if (dungeons[i].ledger_start < ledgerno &&
+               ledgerno <= dungeons[i].ledger_start + dungeons[i].num_dunlevs)
+               return (xchar)i;
+
+       panic("level number out of range [ledger_to_dnum(%d)]", (int)ledgerno);
+       /*NOT REACHED*/
+       return (xchar)0;
+}
+
+/* return the level of the dungeon this ledgerno exists in */
+xchar
+ledger_to_dlev(ledgerno)
+xchar  ledgerno;
+{
+       return((xchar)(ledgerno - dungeons[ledger_to_dnum(ledgerno)].ledger_start));
+}
+
+#endif /* OVL1 */
+#ifdef OVL0
+
+/* returns the depth of a level, in floors below the surface   */
+/* (note levels in different dungeons can have the same depth).        */
+schar
+depth(lev)
+d_level        *lev;
+{
+       return((schar)( dungeons[lev->dnum].depth_start + lev->dlevel - 1));
+}
+
+boolean
+on_level(lev1, lev2)   /* are "lev1" and "lev2" actually the same? */
+d_level        *lev1, *lev2;
+{
+       return((boolean)((lev1->dnum == lev2->dnum) && (lev1->dlevel == lev2->dlevel)));
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+/* is this level referenced in the special level chain? */
+s_level *
+Is_special(lev)
+d_level        *lev;
+{
+       s_level *levtmp;
+
+       for (levtmp = sp_levchn; levtmp; levtmp = levtmp->next)
+           if (on_level(lev, &levtmp->dlevel)) return(levtmp);
+
+       return((s_level *)0);
+}
+
+/*
+ * Is this a multi-dungeon branch level?  If so, return a pointer to the
+ * branch.  Otherwise, return null.
+ */
+branch *
+Is_branchlev(lev)
+       d_level *lev;
+{
+       branch *curr;
+
+       for (curr = branches; curr; curr = curr->next) {
+           if (on_level(lev, &curr->end1) || on_level(lev, &curr->end2))
+               return curr;
+       }
+       return (branch *) 0;
+}
+
+/* goto the next level (or appropriate dungeon) */
+void
+next_level(at_stairs)
+boolean        at_stairs;
+{
+       if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
+               /* Taking a down dungeon branch. */
+               goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
+       } else {
+               /* Going down a stairs or jump in a trap door. */
+               d_level newlevel;
+
+               newlevel.dnum = u.uz.dnum;
+               newlevel.dlevel = u.uz.dlevel + 1;
+               goto_level(&newlevel, at_stairs, !at_stairs, FALSE);
+       }
+}
+
+/* goto the previous level (or appropriate dungeon) */
+void
+prev_level(at_stairs)
+boolean        at_stairs;
+{
+       if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
+               /* Taking an up dungeon branch. */
+               /* KMH -- Upwards branches are okay if not level 1 */
+               /* (Just make sure it doesn't go above depth 1) */
+               if(!u.uz.dnum && u.uz.dlevel == 1 && !u.uhave.amulet) done(ESCAPED);
+               else goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
+       } else {
+               /* Going up a stairs or rising through the ceiling. */
+               d_level newlevel;
+               newlevel.dnum = u.uz.dnum;
+               newlevel.dlevel = u.uz.dlevel - 1;
+               goto_level(&newlevel, at_stairs, FALSE, FALSE);
+       }
+}
+
+void
+u_on_newpos(x, y)
+int x, y;
+{
+       u.ux = x;
+       u.uy = y;
+#ifdef CLIPPING
+       cliparound(u.ux, u.uy);
+#endif
+#ifdef STEED
+       /* ridden steed always shares hero's location */
+       if (u.usteed) u.usteed->mx = u.ux, u.usteed->my = u.uy;
+#endif
+}
+
+void
+u_on_sstairs() {       /* place you on the special staircase */
+
+       if (sstairs.sx) {
+           u_on_newpos(sstairs.sx, sstairs.sy);
+       } else {
+           /* code stolen from goto_level */
+           int trycnt = 0;
+           xchar x, y;
+#ifdef DEBUG
+           pline("u_on_sstairs: picking random spot");
+#endif
+#define badspot(x,y) ((levl[x][y].typ != ROOM && levl[x][y].typ != CORR) || MON_AT(x, y))
+           do {
+               x = rnd(COLNO-1);
+               y = rn2(ROWNO);
+               if (!badspot(x, y)) {
+                   u_on_newpos(x, y);
+                   return;
+               }
+           } while (++trycnt <= 500);
+           panic("u_on_sstairs: could not relocate player!");
+#undef badspot
+       }
+}
+
+void
+u_on_upstairs()        /* place you on upstairs (or special equivalent) */
+{
+       if (xupstair) {
+               u_on_newpos(xupstair, yupstair);
+       } else
+               u_on_sstairs();
+}
+
+void
+u_on_dnstairs()        /* place you on dnstairs (or special equivalent) */
+{
+       if (xdnstair) {
+               u_on_newpos(xdnstair, ydnstair);
+       } else
+               u_on_sstairs();
+}
+
+boolean
+On_stairs(x, y)
+xchar x, y;
+{
+       return((boolean)((x == xupstair && y == yupstair) ||
+              (x == xdnstair && y == ydnstair) ||
+              (x == xdnladder && y == ydnladder) ||
+              (x == xupladder && y == yupladder) ||
+              (x == sstairs.sx && y == sstairs.sy)));
+}
+
+boolean
+Is_botlevel(lev)
+d_level *lev;
+{
+       return((boolean)(lev->dlevel == dungeons[lev->dnum].num_dunlevs));
+}
+
+boolean
+Can_dig_down(lev)
+d_level *lev;
+{
+       return((boolean)(!level.flags.hardfloor
+           && !Is_botlevel(lev) && !Invocation_lev(lev)));
+}
+
+/*
+ * Like Can_dig_down (above), but also allows falling through on the
+ * stronghold level.  Normally, the bottom level of a dungeon resists
+ * both digging and falling.
+ */
+boolean
+Can_fall_thru(lev)
+d_level *lev;
+{
+       return((boolean)(Can_dig_down(lev) || Is_stronghold(lev)));
+}
+
+/*
+ * True if one can rise up a level (e.g. cursed gain level).
+ * This happens on intermediate dungeon levels or on any top dungeon
+ * level that has a stairwell style branch to the next higher dungeon.
+ * Checks for amulets and such must be done elsewhere.
+ */
+boolean
+Can_rise_up(x, y, lev)
+int    x, y;
+d_level *lev;
+{
+    /* can't rise up from inside the top of the Wizard's tower */
+    /* KMH -- or in sokoban */
+    if (In_endgame(lev) || In_sokoban(lev) ||
+                       (Is_wiz1_level(lev) && In_W_tower(x, y, lev)))
+       return FALSE;
+    return (boolean)(lev->dlevel > 1 ||
+               (dungeons[lev->dnum].entry_lev == 1 && ledger_no(lev) != 1 &&
+                sstairs.sx && sstairs.up));
+}
+
+/*
+ * It is expected that the second argument of get_level is a depth value,
+ * either supplied by the user (teleport control) or randomly generated.
+ * But more than one level can be at the same depth.  If the target level
+ * is "above" the present depth location, get_level must trace "up" from
+ * the player's location (through the ancestors dungeons) the dungeon
+ * within which the target level is located.  With only one exception
+ * which does not pass through this routine (see level_tele), teleporting
+ * "down" is confined to the current dungeon.  At present, level teleport
+ * in dungeons that build up is confined within them.
+ */
+void
+get_level(newlevel, levnum)
+d_level *newlevel;
+int levnum;
+{
+       branch *br;
+       xchar dgn = u.uz.dnum;
+
+       if (levnum <= 0) {
+           /* can only currently happen in endgame */
+           levnum = u.uz.dlevel;
+       } else if (levnum > dungeons[dgn].depth_start
+                           + dungeons[dgn].num_dunlevs - 1) {
+           /* beyond end of dungeon, jump to last level */
+           levnum = dungeons[dgn].num_dunlevs;
+       } else {
+           /* The desired level is in this dungeon or a "higher" one. */
+
+           /*
+            * Branch up the tree until we reach a dungeon that contains the
+            * levnum.
+            */
+           if (levnum < dungeons[dgn].depth_start) {
+
+               do {
+                   /*
+                    * Find the parent dungeon of this dungeon.
+                    *
+                    * This assumes that end2 is always the "child" and it is
+                    * unique.
+                    */
+                   for (br = branches; br; br = br->next)
+                       if (br->end2.dnum == dgn) break;
+                   if (!br)
+                       panic("get_level: can't find parent dungeon");
+
+                   dgn = br->end1.dnum;
+               } while (levnum < dungeons[dgn].depth_start);
+           }
+
+           /* We're within the same dungeon; calculate the level. */
+           levnum = levnum - dungeons[dgn].depth_start + 1;
+       }
+
+       newlevel->dnum = dgn;
+       newlevel->dlevel = levnum;
+}
+
+#endif /* OVL1 */
+#ifdef OVL0
+
+boolean
+In_quest(lev)  /* are you in the quest dungeon? */
+d_level *lev;
+{
+       return((boolean)(lev->dnum == quest_dnum));
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+boolean
+In_mines(lev)  /* are you in the mines dungeon? */
+d_level        *lev;
+{
+       return((boolean)(lev->dnum == mines_dnum));
+}
+
+/*
+ * Return the branch for the given dungeon.
+ *
+ * This function assumes:
+ *     + This is not called with "Dungeons of Doom".
+ *     + There is only _one_ branch to a given dungeon.
+ *     + Field end2 is the "child" dungeon.
+ */
+branch *
+dungeon_branch(s)
+    const char *s;
+{
+    branch *br;
+    xchar  dnum;
+
+    dnum = dname_to_dnum(s);
+
+    /* Find the branch that connects to dungeon i's branch. */
+    for (br = branches; br; br = br->next)
+       if (br->end2.dnum == dnum) break;
+
+    if (!br) panic("dgn_entrance: can't find entrance to %s", s);
+
+    return br;
+}
+
+/*
+ * This returns true if the hero is on the same level as the entrance to
+ * the named dungeon.
+ *
+ * Called from do.c and mklev.c.
+ *
+ * Assumes that end1 is always the "parent".
+ */
+boolean
+at_dgn_entrance(s)
+    const char *s;
+{
+    branch *br;
+
+    br = dungeon_branch(s);
+    return((boolean)(on_level(&u.uz, &br->end1) ? TRUE : FALSE));
+}
+
+boolean
+In_V_tower(lev)        /* is `lev' part of Vlad's tower? */
+d_level        *lev;
+{
+       return((boolean)(lev->dnum == tower_dnum));
+}
+
+boolean
+On_W_tower_level(lev)  /* is `lev' a level containing the Wizard's tower? */
+d_level        *lev;
+{
+       return (boolean)(Is_wiz1_level(lev) ||
+                        Is_wiz2_level(lev) ||
+                        Is_wiz3_level(lev));
+}
+
+boolean
+In_W_tower(x, y, lev)  /* is <x,y> of `lev' inside the Wizard's tower? */
+int    x, y;
+d_level        *lev;
+{
+       if (!On_W_tower_level(lev)) return FALSE;
+       /*
+        * Both of the exclusion regions for arriving via level teleport
+        * (from above or below) define the tower's boundary.
+        *      assert( updest.nIJ == dndest.nIJ for I={l|h},J={x|y} );
+        */
+       if (dndest.nlx > 0)
+           return (boolean)within_bounded_area(x, y, dndest.nlx, dndest.nly,
+                                               dndest.nhx, dndest.nhy);
+       else
+           impossible("No boundary for Wizard's Tower?");
+       return FALSE;
+}
+
+#endif /* OVL1 */
+#ifdef OVL0
+
+boolean
+In_hell(lev)   /* are you in one of the Hell levels? */
+d_level        *lev;
+{
+       return((boolean)(dungeons[lev->dnum].flags.hellish));
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+void
+find_hell(lev) /* sets *lev to be the gateway to Gehennom... */
+d_level *lev;
+{
+       lev->dnum = valley_level.dnum;
+       lev->dlevel = 1;
+}
+
+void
+goto_hell(at_stairs, falling)  /* go directly to hell... */
+boolean        at_stairs, falling;
+{
+       d_level lev;
+
+       find_hell(&lev);
+       goto_level(&lev, at_stairs, falling, FALSE);
+}
+
+void
+assign_level(dest, src)                /* equivalent to dest = source */
+d_level        *dest, *src;
+{
+       dest->dnum = src->dnum;
+       dest->dlevel = src->dlevel;
+}
+
+void
+assign_rnd_level(dest, src, range)     /* dest = src + rn1(range) */
+d_level        *dest, *src;
+int range;
+{
+       dest->dnum = src->dnum;
+       dest->dlevel = src->dlevel + ((range > 0) ? rnd(range) : -rnd(-range)) ;
+
+       if(dest->dlevel > dunlevs_in_dungeon(dest))
+               dest->dlevel = dunlevs_in_dungeon(dest);
+       else if(dest->dlevel < 1)
+               dest->dlevel = 1;
+}
+
+#endif /* OVL1 */
+#ifdef OVL0
+
+int
+induced_align(pct)
+int    pct;
+{
+       s_level *lev = Is_special(&u.uz);
+       aligntyp al;
+
+       if (lev && lev->flags.align)
+               if(rn2(100) < pct) return(lev->flags.align);
+
+       if(dungeons[u.uz.dnum].flags.align)
+               if(rn2(100) < pct) return(dungeons[u.uz.dnum].flags.align);
+
+       al = rn2(3) - 1;
+       return(Align2amask(al));
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+boolean
+Invocation_lev(lev)
+d_level *lev;
+{
+       return((boolean)(In_hell(lev) &&
+               lev->dlevel == (dungeons[lev->dnum].num_dunlevs - 1)));
+}
+
+/* use instead of depth() wherever a degree of difficulty is made
+ * dependent on the location in the dungeon (eg. monster creation).
+ */
+xchar
+level_difficulty()
+{
+       if (In_endgame(&u.uz))
+               return((xchar)(depth(&sanctum_level) + u.ulevel/2));
+       else
+               if (u.uhave.amulet)
+                       return(deepest_lev_reached(FALSE));
+               else
+                       return((xchar) depth(&u.uz));
+}
+
+/* Take one word and try to match it to a level.
+ * Recognized levels are as shown by print_dungeon().
+ */
+schar
+lev_by_name(nam)
+const char *nam;
+{
+    schar lev = 0;
+    s_level *slev;
+    d_level dlev;
+    const char *p;
+    int idx, idxtoo;
+    char buf[BUFSZ];
+
+    /* allow strings like "the oracle level" to find "oracle" */
+    if (!strncmpi(nam, "the ", 4)) nam += 4;
+    if ((p = strstri(nam, " level")) != 0 && p == eos((char*)nam) - 6) {
+       nam = strcpy(buf, nam);
+       *(eos(buf) - 6) = '\0';
+    }
+    /* hell is the old name, and wouldn't match; gehennom would match its
+       branch, yielding the castle level instead of the valley of the dead */
+    if (!strcmpi(nam, "gehennom") || !strcmpi(nam, "hell")) {
+       if (In_V_tower(&u.uz)) nam = " to Vlad's tower";  /* branch to... */
+       else nam = "valley";
+    }
+
+    if ((slev = find_level(nam)) != 0) {
+       dlev = slev->dlevel;
+       idx = ledger_no(&dlev);
+       if ((dlev.dnum == u.uz.dnum ||
+               /* within same branch, or else main dungeon <-> gehennom */
+               (u.uz.dnum == valley_level.dnum &&
+                       dlev.dnum == medusa_level.dnum) ||
+               (u.uz.dnum == medusa_level.dnum &&
+                       dlev.dnum == valley_level.dnum)) &&
+           (   /* either wizard mode or else seen and not forgotten */
+#ifdef WIZARD
+            wizard ||
+#endif
+               (level_info[idx].flags & (FORGOTTEN|VISITED)) == VISITED)) {
+           lev = depth(&slev->dlevel);
+       }
+    } else {   /* not a specific level; try branch names */
+       idx = find_branch(nam, (struct proto_dungeon *)0);
+       /* "<branch> to Xyzzy" */
+       if (idx < 0 && (p = strstri(nam, " to ")) != 0)
+           idx = find_branch(p + 4, (struct proto_dungeon *)0);
+
+       if (idx >= 0) {
+           idxtoo = (idx >> 8) & 0x00FF;
+           idx &= 0x00FF;
+           if (  /* either wizard mode, or else _both_ sides of branch seen */
+#ifdef WIZARD
+               wizard ||
+#endif
+               ((level_info[idx].flags & (FORGOTTEN|VISITED)) == VISITED &&
+                (level_info[idxtoo].flags & (FORGOTTEN|VISITED)) == VISITED)) {
+               if (ledger_to_dnum(idxtoo) == u.uz.dnum) idx = idxtoo;
+               dlev.dnum = ledger_to_dnum(idx);
+               dlev.dlevel = ledger_to_dlev(idx);
+               lev = depth(&dlev);
+           }
+       }
+    }
+    return lev;
+}
+
+#ifdef WIZARD
+
+/* Convert a branch type to a string usable by print_dungeon(). */
+STATIC_OVL const char *
+br_string(type)
+    int type;
+{
+    switch (type) {
+       case BR_PORTAL:  return "Portal";
+       case BR_NO_END1: return "Connection";
+       case BR_NO_END2: return "One way stair";
+       case BR_STAIR:   return "Stair";
+    }
+    return " (unknown)";
+}
+
+/* Print all child branches between the lower and upper bounds. */
+STATIC_OVL void
+print_branch(win, dnum, lower_bound, upper_bound, bymenu, lchoices)
+    winid win;
+    int   dnum;
+    int   lower_bound;
+    int   upper_bound;
+    boolean bymenu;
+    struct lchoice *lchoices;
+{
+    branch *br;
+    char buf[BUFSZ];
+    anything any;
+
+    /* This assumes that end1 is the "parent". */
+    for (br = branches; br; br = br->next) {
+       if (br->end1.dnum == dnum && lower_bound < br->end1.dlevel &&
+                                       br->end1.dlevel <= upper_bound) {
+           Sprintf(buf,"   %s to %s: %d",
+                   br_string(br->type),
+                   dungeons[br->end2.dnum].dname,
+                   depth(&br->end1));
+           if (bymenu) {
+               lchoices->lev[lchoices->idx] = br->end1.dlevel;
+               lchoices->dgn[lchoices->idx] = br->end1.dnum;
+               lchoices->playerlev[lchoices->idx] = depth(&br->end1);
+               any.a_void = 0;
+               any.a_int = lchoices->idx + 1;
+               add_menu(win, NO_GLYPH, &any, lchoices->menuletter,
+                               0, ATR_NONE, buf, MENU_UNSELECTED);
+               if (lchoices->menuletter == 'z') lchoices->menuletter = 'A';
+               else lchoices->menuletter++;
+               lchoices->idx++;
+           } else
+               putstr(win, 0, buf);
+       }
+    }
+}
+
+/* Print available dungeon information. */
+schar
+print_dungeon(bymenu, rlev, rdgn)
+boolean bymenu;
+schar *rlev;
+xchar *rdgn;
+{
+    int     i, last_level, nlev;
+    char    buf[BUFSZ];
+    boolean first;
+    s_level *slev;
+    dungeon *dptr;
+    branch  *br;
+    anything any;
+    struct lchoice lchoices;
+
+    winid   win = create_nhwindow(NHW_MENU);
+    if (bymenu) {
+       start_menu(win);
+       lchoices.idx = 0;
+       lchoices.menuletter = 'a';
+    }
+
+    for (i = 0, dptr = dungeons; i < n_dgns; i++, dptr++) {
+       nlev = dptr->num_dunlevs;
+       if (nlev > 1)
+           Sprintf(buf, "%s: levels %d to %d", dptr->dname, dptr->depth_start,
+                                               dptr->depth_start + nlev - 1);
+       else
+           Sprintf(buf, "%s: level %d", dptr->dname, dptr->depth_start);
+
+       /* Most entrances are uninteresting. */
+       if (dptr->entry_lev != 1) {
+           if (dptr->entry_lev == nlev)
+               Strcat(buf, ", entrance from below");
+           else
+               Sprintf(eos(buf), ", entrance on %d",
+                       dptr->depth_start + dptr->entry_lev - 1);
+       }
+       if (bymenu) {
+           any.a_void = 0;
+           add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf, MENU_UNSELECTED);
+       } else
+           putstr(win, 0, buf);
+
+       /*
+        * Circle through the special levels to find levels that are in
+        * this dungeon.
+        */
+       for (slev = sp_levchn, last_level = 0; slev; slev = slev->next) {
+           if (slev->dlevel.dnum != i) continue;
+
+           /* print any branches before this level */
+           print_branch(win, i, last_level, slev->dlevel.dlevel, bymenu, &lchoices);
+
+           Sprintf(buf, "   %s: %d", slev->proto, depth(&slev->dlevel));
+           if (Is_stronghold(&slev->dlevel))
+               Sprintf(eos(buf), " (tune %s)", tune);
+           if (bymenu) {
+               /* If other floating branches are added, this will need to change */
+               if (i != knox_level.dnum) {
+                       lchoices.lev[lchoices.idx] = slev->dlevel.dlevel;
+                       lchoices.dgn[lchoices.idx] = i;
+               } else {
+                       lchoices.lev[lchoices.idx] = depth(&slev->dlevel);
+                       lchoices.dgn[lchoices.idx] = 0;
+               }
+               lchoices.playerlev[lchoices.idx] = depth(&slev->dlevel);
+               any.a_void = 0;
+               any.a_int = lchoices.idx + 1;
+               add_menu(win, NO_GLYPH, &any, lchoices.menuletter,
+                               0, ATR_NONE, buf, MENU_UNSELECTED);
+               if (lchoices.menuletter == 'z') lchoices.menuletter = 'A';
+               else lchoices.menuletter++;
+               lchoices.idx++;
+           } else
+               putstr(win, 0, buf);
+
+           last_level = slev->dlevel.dlevel;
+       }
+       /* print branches after the last special level */
+       print_branch(win, i, last_level, MAXLEVEL, bymenu, &lchoices);
+    }
+
+    /* Print out floating branches (if any). */
+    for (first = TRUE, br = branches; br; br = br->next) {
+       if (br->end1.dnum == n_dgns) {
+           if (first) {
+               if (!bymenu) {
+                   putstr(win, 0, "");
+                   putstr(win, 0, "Floating branches");
+               }
+               first = FALSE;
+           }
+           Sprintf(buf, "   %s to %s",
+                       br_string(br->type), dungeons[br->end2.dnum].dname);
+           if (!bymenu)
+               putstr(win, 0, buf);
+       }
+    }
+    if (bymenu) {
+       int n;
+       menu_item *selected;
+       int idx;
+
+       end_menu(win, "Level teleport to where:");
+       n = select_menu(win, PICK_ONE, &selected);
+       destroy_nhwindow(win);
+       if (n > 0) {
+               idx = selected[0].item.a_int - 1;
+               free((genericptr_t)selected);
+               if (rlev && rdgn) {
+                       *rlev = lchoices.lev[idx];
+                       *rdgn = lchoices.dgn[idx];
+                       return lchoices.playerlev[idx];
+               }
+       }
+       return 0;
+    }
+
+    /* I hate searching for the invocation pos while debugging. -dean */
+    if (Invocation_lev(&u.uz)) {
+       putstr(win, 0, "");
+       Sprintf(buf, "Invocation position @ (%d,%d), hero @ (%d,%d)",
+               inv_pos.x, inv_pos.y, u.ux, u.uy);
+       putstr(win, 0, buf);
+    }
+    /*
+     * The following is based on the assumption that the inter-level portals
+     * created by the level compiler (not the dungeon compiler) only exist
+     * one per level (currently true, of course).
+     */
+    else if (Is_earthlevel(&u.uz) || Is_waterlevel(&u.uz)
+                               || Is_firelevel(&u.uz) || Is_airlevel(&u.uz)) {
+       struct trap *trap;
+       for (trap = ftrap; trap; trap = trap->ntrap)
+           if (trap->ttyp == MAGIC_PORTAL) break;
+
+       putstr(win, 0, "");
+       if (trap)
+           Sprintf(buf, "Portal @ (%d,%d), hero @ (%d,%d)",
+               trap->tx, trap->ty, u.ux, u.uy);
+       else
+           Sprintf(buf, "No portal found.");
+       putstr(win, 0, buf);
+    }
+
+    display_nhwindow(win, TRUE);
+    destroy_nhwindow(win);
+    return 0;
+}
+#endif /* WIZARD */
+
+#endif /* OVL1 */
+
+/*dungeon.c*/
diff --git a/src/eat.c b/src/eat.c
new file mode 100644 (file)
index 0000000..12e8d9b
--- /dev/null
+++ b/src/eat.c
@@ -0,0 +1,2586 @@
+/*     SCCS Id: @(#)eat.c      3.4     2003/02/13      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+/* #define DEBUG */    /* uncomment to enable new eat code debugging */
+
+#ifdef DEBUG
+# ifdef WIZARD
+#define debugpline     if (wizard) pline
+# else
+#define debugpline     pline
+# endif
+#endif
+
+STATIC_PTR int NDECL(eatmdone);
+STATIC_PTR int NDECL(eatfood);
+STATIC_PTR void FDECL(costly_tin, (const char*));
+STATIC_PTR int NDECL(opentin);
+STATIC_PTR int NDECL(unfaint);
+
+#ifdef OVLB
+STATIC_DCL const char *FDECL(food_xname, (struct obj *,BOOLEAN_P));
+STATIC_DCL void FDECL(choke, (struct obj *));
+STATIC_DCL void NDECL(recalc_wt);
+STATIC_DCL struct obj *FDECL(touchfood, (struct obj *));
+STATIC_DCL void NDECL(do_reset_eat);
+STATIC_DCL void FDECL(done_eating, (BOOLEAN_P));
+STATIC_DCL void FDECL(cprefx, (int));
+STATIC_DCL int FDECL(intrinsic_possible, (int,struct permonst *));
+STATIC_DCL void FDECL(givit, (int,struct permonst *));
+STATIC_DCL void FDECL(cpostfx, (int));
+STATIC_DCL void FDECL(start_tin, (struct obj *));
+STATIC_DCL int FDECL(eatcorpse, (struct obj *));
+STATIC_DCL void FDECL(start_eating, (struct obj *));
+STATIC_DCL void FDECL(fprefx, (struct obj *));
+STATIC_DCL void FDECL(accessory_has_effect, (struct obj *));
+STATIC_DCL void FDECL(fpostfx, (struct obj *));
+STATIC_DCL int NDECL(bite);
+STATIC_DCL int FDECL(edibility_prompts, (struct obj *));
+STATIC_DCL int FDECL(rottenfood, (struct obj *));
+STATIC_DCL void NDECL(eatspecial);
+STATIC_DCL void FDECL(eataccessory, (struct obj *));
+STATIC_DCL const char *FDECL(foodword, (struct obj *));
+STATIC_DCL boolean FDECL(maybe_cannibal, (int,BOOLEAN_P));
+
+char msgbuf[BUFSZ];
+
+#endif /* OVLB */
+
+/* hunger texts used on bottom line (each 8 chars long) */
+#define SATIATED       0
+#define NOT_HUNGRY     1
+#define HUNGRY         2
+#define WEAK           3
+#define FAINTING       4
+#define FAINTED                5
+#define STARVED                6
+
+/* also used to see if you're allowed to eat cats and dogs */
+#define CANNIBAL_ALLOWED() (Role_if(PM_CAVEMAN) || Race_if(PM_ORC))
+
+#ifndef OVLB
+
+STATIC_DCL NEARDATA const char comestibles[];
+STATIC_DCL NEARDATA const char allobj[];
+STATIC_DCL boolean force_save_hs;
+
+#else
+
+STATIC_OVL NEARDATA const char comestibles[] = { FOOD_CLASS, 0 };
+
+/* Gold must come first for getobj(). */
+STATIC_OVL NEARDATA const char allobj[] = {
+       COIN_CLASS, WEAPON_CLASS, ARMOR_CLASS, POTION_CLASS, SCROLL_CLASS,
+       WAND_CLASS, RING_CLASS, AMULET_CLASS, FOOD_CLASS, TOOL_CLASS,
+       GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, SPBOOK_CLASS, 0 };
+
+STATIC_OVL boolean force_save_hs = FALSE;
+
+const char *hu_stat[] = {
+       "Satiated",
+       "        ",
+       "Hungry  ",
+       "Weak    ",
+       "Fainting",
+       "Fainted ",
+       "Starved "
+};
+
+#endif /* OVLB */
+#ifdef OVL1
+
+/*
+ * Decide whether a particular object can be eaten by the possibly
+ * polymorphed character.  Not used for monster checks.
+ */
+boolean
+is_edible(obj)
+register struct obj *obj;
+{
+       /* protect invocation tools but not Rider corpses (handled elsewhere)*/
+     /* if (obj->oclass != FOOD_CLASS && obj_resists(obj, 0, 0)) */
+       if (objects[obj->otyp].oc_unique)
+               return FALSE;
+       /* above also prevents the Amulet from being eaten, so we must never
+          allow fake amulets to be eaten either [which is already the case] */
+
+       if (metallivorous(youmonst.data) && is_metallic(obj) &&
+           (youmonst.data != &mons[PM_RUST_MONSTER] || is_rustprone(obj)))
+               return TRUE;
+       if (u.umonnum == PM_GELATINOUS_CUBE && is_organic(obj) &&
+               /* [g.cubes can eat containers and retain all contents
+                   as engulfed items, but poly'd player can't do that] */
+           !Has_contents(obj))
+               return TRUE;
+
+     /* return((boolean)(!!index(comestibles, obj->oclass))); */
+       return (boolean)(obj->oclass == FOOD_CLASS);
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+void
+init_uhunger()
+{
+       u.uhunger = 900;
+       u.uhs = NOT_HUNGRY;
+}
+
+static const struct { const char *txt; int nut; } tintxts[] = {
+       {"deep fried",   60},
+       {"pickled",      40},
+       {"soup made from", 20},
+       {"pureed",      500},
+#define ROTTEN_TIN 4
+       {"rotten",      -50},
+#define HOMEMADE_TIN 5
+       {"homemade",     50},
+       {"stir fried",   80},
+       {"candied",      100},
+       {"boiled",       50},
+       {"dried",        55},
+       {"szechuan",     70},
+#define FRENCH_FRIED_TIN 11
+       {"french fried", 40},
+       {"sauteed",      95},
+       {"broiled",      80},
+       {"smoked",       50},
+       {"", 0}
+};
+#define TTSZ   SIZE(tintxts)
+
+static NEARDATA struct {
+       struct  obj *tin;
+       int     usedtime, reqtime;
+} tin;
+
+static NEARDATA struct {
+       struct  obj *piece;     /* the thing being eaten, or last thing that
+                                * was partially eaten, unless that thing was
+                                * a tin, which uses the tin structure above,
+                                * in which case this should be 0 */
+       /* doeat() initializes these when piece is valid */
+       int     usedtime,       /* turns spent eating */
+               reqtime;        /* turns required to eat */
+       int     nmod;           /* coded nutrition per turn */
+       Bitfield(canchoke,1);   /* was satiated at beginning */
+
+       /* start_eating() initializes these */
+       Bitfield(fullwarn,1);   /* have warned about being full */
+       Bitfield(eating,1);     /* victual currently being eaten */
+       Bitfield(doreset,1);    /* stop eating at end of turn */
+} victual;
+
+static char *eatmbuf = 0;      /* set by cpostfx() */
+
+STATIC_PTR
+int
+eatmdone()             /* called after mimicing is over */
+{
+       /* release `eatmbuf' */
+       if (eatmbuf) {
+           if (nomovemsg == eatmbuf) nomovemsg = 0;
+           free((genericptr_t)eatmbuf),  eatmbuf = 0;
+       }
+       /* update display */
+       if (youmonst.m_ap_type) {
+           youmonst.m_ap_type = M_AP_NOTHING;
+           newsym(u.ux,u.uy);
+       }
+       return 0;
+}
+
+/* ``[the(] singular(food, xname) [)]'' with awareness of unique monsters */
+STATIC_OVL const char *
+food_xname(food, the_pfx)
+struct obj *food;
+boolean the_pfx;
+{
+       const char *result;
+       int mnum = food->corpsenm;
+
+       if (food->otyp == CORPSE && (mons[mnum].geno & G_UNIQ)) {
+           /* grab xname()'s modifiable return buffer for our own use */
+           char *bufp = xname(food);
+           Sprintf(bufp, "%s%s corpse",
+                   (the_pfx && !type_is_pname(&mons[mnum])) ? "the " : "",
+                   s_suffix(mons[mnum].mname));
+           result = bufp;
+       } else {
+           /* the ordinary case */
+           result = singular(food, xname);
+           if (the_pfx) result = the(result);
+       }
+       return result;
+}
+
+/* Created by GAN 01/28/87
+ * Amended by AKP 09/22/87: if not hard, don't choke, just vomit.
+ * Amended by 3.  06/12/89: if not hard, sometimes choke anyway, to keep risk.
+ *               11/10/89: if hard, rarely vomit anyway, for slim chance.
+ */
+STATIC_OVL void
+choke(food)    /* To a full belly all food is bad. (It.) */
+       register struct obj *food;
+{
+       /* only happens if you were satiated */
+       if (u.uhs != SATIATED) {
+               if (!food || food->otyp != AMULET_OF_STRANGULATION)
+                       return;
+       } else if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL) {
+                       adjalign(-1);           /* gluttony is unchivalrous */
+                       You_feel("like a glutton!");
+       }
+
+       exercise(A_CON, FALSE);
+
+       if (Breathless || (!Strangled && !rn2(20))) {
+               /* choking by eating AoS doesn't involve stuffing yourself */
+               if (food && food->otyp == AMULET_OF_STRANGULATION) {
+                       You("choke, but recover your composure.");
+                       return;
+               }
+               You("stuff yourself and then vomit voluminously.");
+               morehungry(1000);       /* you just got *very* sick! */
+               nomovemsg = 0;
+               vomit();
+       } else {
+               killer_format = KILLED_BY_AN;
+               /*
+                * Note all "killer"s below read "Choked on %s" on the
+                * high score list & tombstone.  So plan accordingly.
+                */
+               if(food) {
+                       You("choke over your %s.", foodword(food));
+                       if (food->oclass == COIN_CLASS) {
+                               killer = "a very rich meal";
+                       } else {
+                               killer = food_xname(food, FALSE);
+                               if (food->otyp == CORPSE &&
+                                   (mons[food->corpsenm].geno & G_UNIQ)) {
+                                   if (!type_is_pname(&mons[food->corpsenm]))
+                                       killer = the(killer);
+                                   killer_format = KILLED_BY;
+                               }
+                       }
+               } else {
+                       You("choke over it.");
+                       killer = "quick snack";
+               }
+               You("die...");
+               done(CHOKING);
+       }
+}
+
+/* modify object wt. depending on time spent consuming it */
+STATIC_OVL void
+recalc_wt()
+{
+       struct obj *piece = victual.piece;
+
+#ifdef DEBUG
+       debugpline("Old weight = %d", piece->owt);
+       debugpline("Used time = %d, Req'd time = %d",
+               victual.usedtime, victual.reqtime);
+#endif
+       piece->owt = weight(piece);
+#ifdef DEBUG
+       debugpline("New weight = %d", piece->owt);
+#endif
+}
+
+void
+reset_eat()            /* called when eating interrupted by an event */
+{
+    /* we only set a flag here - the actual reset process is done after
+     * the round is spent eating.
+     */
+       if(victual.eating && !victual.doreset) {
+#ifdef DEBUG
+           debugpline("reset_eat...");
+#endif
+           victual.doreset = TRUE;
+       }
+       return;
+}
+
+STATIC_OVL struct obj *
+touchfood(otmp)
+register struct obj *otmp;
+{
+       if (otmp->quan > 1L) {
+           if(!carried(otmp))
+               (void) splitobj(otmp, otmp->quan - 1L);
+           else
+               otmp = splitobj(otmp, 1L);
+#ifdef DEBUG
+           debugpline("split object,");
+#endif
+       }
+
+       if (!otmp->oeaten) {
+           if(((!carried(otmp) && costly_spot(otmp->ox, otmp->oy) &&
+                !otmp->no_charge)
+                || otmp->unpaid)) {
+               /* create a dummy duplicate to put on bill */
+               verbalize("You bit it, you bought it!");
+               bill_dummy_object(otmp);
+           }
+           otmp->oeaten = (otmp->otyp == CORPSE ?
+                               mons[otmp->corpsenm].cnutrit :
+                               objects[otmp->otyp].oc_nutrition);
+       }
+
+       if (carried(otmp)) {
+           freeinv(otmp);
+           if (inv_cnt() >= 52) {
+               sellobj_state(SELL_DONTSELL);
+               dropy(otmp);
+               sellobj_state(SELL_NORMAL);
+           } else {
+               otmp->oxlth++;          /* hack to prevent merge */
+               otmp = addinv(otmp);
+               otmp->oxlth--;
+           }
+       }
+       return(otmp);
+}
+
+/* When food decays, in the middle of your meal, we don't want to dereference
+ * any dangling pointers, so set it to null (which should still trigger
+ * do_reset_eat() at the beginning of eatfood()) and check for null pointers
+ * in do_reset_eat().
+ */
+void
+food_disappears(obj)
+register struct obj *obj;
+{
+       if (obj == victual.piece) victual.piece = (struct obj *)0;
+       if (obj->timed) obj_stop_timers(obj);
+}
+
+/* renaming an object usually results in it having a different address;
+   so the sequence start eating/opening, get interrupted, name the food,
+   resume eating/opening would restart from scratch */
+void
+food_substitution(old_obj, new_obj)
+struct obj *old_obj, *new_obj;
+{
+       if (old_obj == victual.piece) victual.piece = new_obj;
+       if (old_obj == tin.tin) tin.tin = new_obj;
+}
+
+STATIC_OVL void
+do_reset_eat()
+{
+#ifdef DEBUG
+       debugpline("do_reset_eat...");
+#endif
+       if (victual.piece) {
+               victual.piece = touchfood(victual.piece);
+               recalc_wt();
+       }
+       victual.fullwarn = victual.eating = victual.doreset = FALSE;
+       /* Do not set canchoke to FALSE; if we continue eating the same object
+        * we need to know if canchoke was set when they started eating it the
+        * previous time.  And if we don't continue eating the same object
+        * canchoke always gets recalculated anyway.
+        */
+       stop_occupation();
+       newuhs(FALSE);
+}
+
+STATIC_PTR
+int
+eatfood()              /* called each move during eating process */
+{
+       if(!victual.piece ||
+        (!carried(victual.piece) && !obj_here(victual.piece, u.ux, u.uy))) {
+               /* maybe it was stolen? */
+               do_reset_eat();
+               return(0);
+       }
+       if(!victual.eating) return(0);
+
+       if(++victual.usedtime <= victual.reqtime) {
+           if(bite()) return(0);
+           return(1);  /* still busy */
+       } else {        /* done */
+           done_eating(TRUE);
+           return(0);
+       }
+}
+
+STATIC_OVL void
+done_eating(message)
+boolean message;
+{
+       victual.piece->in_use = TRUE;
+       occupation = 0; /* do this early, so newuhs() knows we're done */
+       newuhs(FALSE);
+       if (nomovemsg) {
+               if (message) pline(nomovemsg);
+               nomovemsg = 0;
+       } else if (message)
+               You("finish eating %s.", food_xname(victual.piece, TRUE));
+
+       if(victual.piece->otyp == CORPSE)
+               cpostfx(victual.piece->corpsenm);
+       else
+               fpostfx(victual.piece);
+
+       if (carried(victual.piece)) useup(victual.piece);
+       else useupf(victual.piece, 1L);
+       victual.piece = (struct obj *) 0;
+       victual.fullwarn = victual.eating = victual.doreset = FALSE;
+}
+
+STATIC_OVL boolean
+maybe_cannibal(pm, allowmsg)
+int pm;
+boolean allowmsg;
+{
+       if (!CANNIBAL_ALLOWED() && your_race(&mons[pm])) {
+               if (allowmsg) {
+                       if (Upolyd)
+                               You("have a bad feeling deep inside.");
+                       You("cannibal!  You will regret this!");
+               }
+               HAggravate_monster |= FROMOUTSIDE;
+               change_luck(-rn1(4,2));         /* -5..-2 */
+               return TRUE;
+       }
+       return FALSE;
+}
+
+STATIC_OVL void
+cprefx(pm)
+register int pm;
+{
+       (void) maybe_cannibal(pm,TRUE);
+       if (touch_petrifies(&mons[pm]) || pm == PM_MEDUSA) {
+           if (!Stone_resistance &&
+               !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
+               Sprintf(killer_buf, "tasting %s meat", mons[pm].mname);
+               killer_format = KILLED_BY;
+               killer = killer_buf;
+               You("turn to stone.");
+               done(STONING);
+               if (victual.piece)
+                   victual.eating = FALSE;
+               return; /* lifesaved */
+           }
+       }
+
+       switch(pm) {
+           case PM_LITTLE_DOG:
+           case PM_DOG:
+           case PM_LARGE_DOG:
+           case PM_KITTEN:
+           case PM_HOUSECAT:
+           case PM_LARGE_CAT:
+               if (!CANNIBAL_ALLOWED()) {
+                   You_feel("that eating the %s was a bad idea.", mons[pm].mname);
+                   HAggravate_monster |= FROMOUTSIDE;
+               }
+               break;
+           case PM_LIZARD:
+               if (Stoned) fix_petrification();
+               break;
+           case PM_DEATH:
+           case PM_PESTILENCE:
+           case PM_FAMINE:
+               { char buf[BUFSZ];
+                   pline("Eating that is instantly fatal.");
+                   Sprintf(buf, "unwisely ate the body of %s",
+                           mons[pm].mname);
+                   killer = buf;
+                   killer_format = NO_KILLER_PREFIX;
+                   done(DIED);
+                   /* It so happens that since we know these monsters */
+                   /* cannot appear in tins, victual.piece will always */
+                   /* be what we want, which is not generally true. */
+                   if (revive_corpse(victual.piece))
+                       victual.piece = (struct obj *)0;
+                   return;
+               }
+           case PM_GREEN_SLIME:
+               if (!Slimed && !Unchanging && !flaming(youmonst.data) &&
+                       youmonst.data != &mons[PM_GREEN_SLIME]) {
+                   You("don't feel very well.");
+                   Slimed = 10L;
+                   flags.botl = 1;
+               }
+               /* Fall through */
+           default:
+               if (acidic(&mons[pm]) && Stoned)
+                   fix_petrification();
+               break;
+       }
+}
+
+void
+fix_petrification()
+{
+       Stoned = 0;
+       delayed_killer = 0;
+       if (Hallucination)
+           pline("What a pity - you just ruined a future piece of %sart!",
+                 ACURR(A_CHA) > 15 ? "fine " : "");
+       else
+           You_feel("limber!");
+}
+
+/*
+ * If you add an intrinsic that can be gotten by eating a monster, add it
+ * to intrinsic_possible() and givit().  (It must already be in prop.h to
+ * be an intrinsic property.)
+ * It would be very easy to make the intrinsics not try to give you one
+ * that you already had by checking to see if you have it in
+ * intrinsic_possible() instead of givit().
+ */
+
+/* intrinsic_possible() returns TRUE iff a monster can give an intrinsic. */
+STATIC_OVL int
+intrinsic_possible(type, ptr)
+int type;
+register struct permonst *ptr;
+{
+       switch (type) {
+           case FIRE_RES:
+#ifdef DEBUG
+               if (ptr->mconveys & MR_FIRE) {
+                       debugpline("can get fire resistance");
+                       return(TRUE);
+               } else  return(FALSE);
+#else
+               return(ptr->mconveys & MR_FIRE);
+#endif
+           case SLEEP_RES:
+#ifdef DEBUG
+               if (ptr->mconveys & MR_SLEEP) {
+                       debugpline("can get sleep resistance");
+                       return(TRUE);
+               } else  return(FALSE);
+#else
+               return(ptr->mconveys & MR_SLEEP);
+#endif
+           case COLD_RES:
+#ifdef DEBUG
+               if (ptr->mconveys & MR_COLD) {
+                       debugpline("can get cold resistance");
+                       return(TRUE);
+               } else  return(FALSE);
+#else
+               return(ptr->mconveys & MR_COLD);
+#endif
+           case DISINT_RES:
+#ifdef DEBUG
+               if (ptr->mconveys & MR_DISINT) {
+                       debugpline("can get disintegration resistance");
+                       return(TRUE);
+               } else  return(FALSE);
+#else
+               return(ptr->mconveys & MR_DISINT);
+#endif
+           case SHOCK_RES:     /* shock (electricity) resistance */
+#ifdef DEBUG
+               if (ptr->mconveys & MR_ELEC) {
+                       debugpline("can get shock resistance");
+                       return(TRUE);
+               } else  return(FALSE);
+#else
+               return(ptr->mconveys & MR_ELEC);
+#endif
+           case POISON_RES:
+#ifdef DEBUG
+               if (ptr->mconveys & MR_POISON) {
+                       debugpline("can get poison resistance");
+                       return(TRUE);
+               } else  return(FALSE);
+#else
+               return(ptr->mconveys & MR_POISON);
+#endif
+           case TELEPORT:
+#ifdef DEBUG
+               if (can_teleport(ptr)) {
+                       debugpline("can get teleport");
+                       return(TRUE);
+               } else  return(FALSE);
+#else
+               return(can_teleport(ptr));
+#endif
+           case TELEPORT_CONTROL:
+#ifdef DEBUG
+               if (control_teleport(ptr)) {
+                       debugpline("can get teleport control");
+                       return(TRUE);
+               } else  return(FALSE);
+#else
+               return(control_teleport(ptr));
+#endif
+           case TELEPAT:
+#ifdef DEBUG
+               if (telepathic(ptr)) {
+                       debugpline("can get telepathy");
+                       return(TRUE);
+               } else  return(FALSE);
+#else
+               return(telepathic(ptr));
+#endif
+           default:
+               return(FALSE);
+       }
+       /*NOTREACHED*/
+}
+
+/* givit() tries to give you an intrinsic based on the monster's level
+ * and what type of intrinsic it is trying to give you.
+ */
+STATIC_OVL void
+givit(type, ptr)
+int type;
+register struct permonst *ptr;
+{
+       register int chance;
+
+#ifdef DEBUG
+       debugpline("Attempting to give intrinsic %d", type);
+#endif
+       /* some intrinsics are easier to get than others */
+       switch (type) {
+               case POISON_RES:
+                       if ((ptr == &mons[PM_KILLER_BEE] ||
+                                       ptr == &mons[PM_SCORPION]) && !rn2(4))
+                               chance = 1;
+                       else
+                               chance = 15;
+                       break;
+               case TELEPORT:
+                       chance = 10;
+                       break;
+               case TELEPORT_CONTROL:
+                       chance = 12;
+                       break;
+               case TELEPAT:
+                       chance = 1;
+                       break;
+               default:
+                       chance = 15;
+                       break;
+       }
+
+       if (ptr->mlevel <= rn2(chance))
+               return;         /* failed die roll */
+
+       switch (type) {
+           case FIRE_RES:
+#ifdef DEBUG
+               debugpline("Trying to give fire resistance");
+#endif
+               if(!(HFire_resistance & FROMOUTSIDE)) {
+                       You(Hallucination ? "be chillin'." :
+                           "feel a momentary chill.");
+                       HFire_resistance |= FROMOUTSIDE;
+               }
+               break;
+           case SLEEP_RES:
+#ifdef DEBUG
+               debugpline("Trying to give sleep resistance");
+#endif
+               if(!(HSleep_resistance & FROMOUTSIDE)) {
+                       You_feel("wide awake.");
+                       HSleep_resistance |= FROMOUTSIDE;
+               }
+               break;
+           case COLD_RES:
+#ifdef DEBUG
+               debugpline("Trying to give cold resistance");
+#endif
+               if(!(HCold_resistance & FROMOUTSIDE)) {
+                       You_feel("full of hot air.");
+                       HCold_resistance |= FROMOUTSIDE;
+               }
+               break;
+           case DISINT_RES:
+#ifdef DEBUG
+               debugpline("Trying to give disintegration resistance");
+#endif
+               if(!(HDisint_resistance & FROMOUTSIDE)) {
+                       You_feel(Hallucination ?
+                           "totally together, man." :
+                           "very firm.");
+                       HDisint_resistance |= FROMOUTSIDE;
+               }
+               break;
+           case SHOCK_RES:     /* shock (electricity) resistance */
+#ifdef DEBUG
+               debugpline("Trying to give shock resistance");
+#endif
+               if(!(HShock_resistance & FROMOUTSIDE)) {
+                       if (Hallucination)
+                               You_feel("grounded in reality.");
+                       else
+                               Your("health currently feels amplified!");
+                       HShock_resistance |= FROMOUTSIDE;
+               }
+               break;
+           case POISON_RES:
+#ifdef DEBUG
+               debugpline("Trying to give poison resistance");
+#endif
+               if(!(HPoison_resistance & FROMOUTSIDE)) {
+                       You_feel(Poison_resistance ?
+                                "especially healthy." : "healthy.");
+                       HPoison_resistance |= FROMOUTSIDE;
+               }
+               break;
+           case TELEPORT:
+#ifdef DEBUG
+               debugpline("Trying to give teleport");
+#endif
+               if(!(HTeleportation & FROMOUTSIDE)) {
+                       You_feel(Hallucination ? "diffuse." :
+                           "very jumpy.");
+                       HTeleportation |= FROMOUTSIDE;
+               }
+               break;
+           case TELEPORT_CONTROL:
+#ifdef DEBUG
+               debugpline("Trying to give teleport control");
+#endif
+               if(!(HTeleport_control & FROMOUTSIDE)) {
+                       You_feel(Hallucination ?
+                           "centered in your personal space." :
+                           "in control of yourself.");
+                       HTeleport_control |= FROMOUTSIDE;
+               }
+               break;
+           case TELEPAT:
+#ifdef DEBUG
+               debugpline("Trying to give telepathy");
+#endif
+               if(!(HTelepat & FROMOUTSIDE)) {
+                       You_feel(Hallucination ?
+                           "in touch with the cosmos." :
+                           "a strange mental acuity.");
+                       HTelepat |= FROMOUTSIDE;
+                       /* If blind, make sure monsters show up. */
+                       if (Blind) see_monsters();
+               }
+               break;
+           default:
+#ifdef DEBUG
+               debugpline("Tried to give an impossible intrinsic");
+#endif
+               break;
+       }
+}
+
+STATIC_OVL void
+cpostfx(pm)            /* called after completely consuming a corpse */
+register int pm;
+{
+       register int tmp = 0;
+       boolean catch_lycanthropy = FALSE;
+
+       /* in case `afternmv' didn't get called for previously mimicking
+          gold, clean up now to avoid `eatmbuf' memory leak */
+       if (eatmbuf) (void)eatmdone();
+
+       switch(pm) {
+           case PM_NEWT:
+               /* MRKR: "eye of newt" may give small magical energy boost */
+               if (rn2(3) || 3 * u.uen <= 2 * u.uenmax) {
+                   int old_uen = u.uen;
+                   u.uen += rnd(3);
+                   if (u.uen > u.uenmax) {
+                       if (!rn2(3)) u.uenmax++;
+                       u.uen = u.uenmax;
+                   }
+                   if (old_uen != u.uen) {
+                           You_feel("a mild buzz.");
+                           flags.botl = 1;
+                   }
+               }
+               break;
+           case PM_WRAITH:
+               pluslvl(FALSE);
+               break;
+           case PM_HUMAN_WERERAT:
+               catch_lycanthropy = TRUE;
+               u.ulycn = PM_WERERAT;
+               break;
+           case PM_HUMAN_WEREJACKAL:
+               catch_lycanthropy = TRUE;
+               u.ulycn = PM_WEREJACKAL;
+               break;
+           case PM_HUMAN_WEREWOLF:
+               catch_lycanthropy = TRUE;
+               u.ulycn = PM_WEREWOLF;
+               break;
+           case PM_NURSE:
+               if (Upolyd) u.mh = u.mhmax;
+               else u.uhp = u.uhpmax;
+               flags.botl = 1;
+               break;
+           case PM_STALKER:
+               if(!Invis) {
+                       set_itimeout(&HInvis, (long)rn1(100, 50));
+                       if (!Blind && !BInvis) self_invis_message();
+               } else {
+                       if (!(HInvis & INTRINSIC)) You_feel("hidden!");
+                       HInvis |= FROMOUTSIDE;
+                       HSee_invisible |= FROMOUTSIDE;
+               }
+               newsym(u.ux, u.uy);
+               /* fall into next case */
+           case PM_YELLOW_LIGHT:
+               /* fall into next case */
+           case PM_GIANT_BAT:
+               make_stunned(HStun + 30,FALSE);
+               /* fall into next case */
+           case PM_BAT:
+               make_stunned(HStun + 30,FALSE);
+               break;
+           case PM_GIANT_MIMIC:
+               tmp += 10;
+               /* fall into next case */
+           case PM_LARGE_MIMIC:
+               tmp += 20;
+               /* fall into next case */
+           case PM_SMALL_MIMIC:
+               tmp += 20;
+               if (youmonst.data->mlet != S_MIMIC && !Unchanging) {
+                   char buf[BUFSZ];
+                   You_cant("resist the temptation to mimic %s.",
+                       Hallucination ? "an orange" : "a pile of gold");
+#ifdef STEED
+                    /* A pile of gold can't ride. */
+                   if (u.usteed) dismount_steed(DISMOUNT_FELL);
+#endif
+                   nomul(-tmp);
+                   Sprintf(buf, Hallucination ?
+                       "You suddenly dread being peeled and mimic %s again!" :
+                       "You now prefer mimicking %s again.",
+                       an(Upolyd ? youmonst.data->mname : urace.noun));
+                   eatmbuf = strcpy((char *) alloc(strlen(buf) + 1), buf);
+                   nomovemsg = eatmbuf;
+                   afternmv = eatmdone;
+                   /* ??? what if this was set before? */
+                   youmonst.m_ap_type = M_AP_OBJECT;
+                   youmonst.mappearance = Hallucination ? ORANGE : GOLD_PIECE;
+                   newsym(u.ux,u.uy);
+                   curs_on_u();
+                   /* make gold symbol show up now */
+                   display_nhwindow(WIN_MAP, TRUE);
+               }
+               break;
+           case PM_QUANTUM_MECHANIC:
+               Your("velocity suddenly seems very uncertain!");
+               if (HFast & INTRINSIC) {
+                       HFast &= ~INTRINSIC;
+                       You("seem slower.");
+               } else {
+                       HFast |= FROMOUTSIDE;
+                       You("seem faster.");
+               }
+               break;
+           case PM_LIZARD:
+               if (HStun > 2)  make_stunned(2L,FALSE);
+               if (HConfusion > 2)  make_confused(2L,FALSE);
+               break;
+           case PM_CHAMELEON:
+           case PM_DOPPELGANGER:
+        /* case PM_SANDESTIN: */
+               if (!Unchanging) {
+                   You_feel("a change coming over you.");
+                   polyself(FALSE);
+               }
+               break;
+           case PM_MIND_FLAYER:
+           case PM_MASTER_MIND_FLAYER:
+               if (ABASE(A_INT) < ATTRMAX(A_INT)) {
+                       if (!rn2(2)) {
+                               pline("Yum! That was real brain food!");
+                               (void) adjattrib(A_INT, 1, FALSE);
+                               break;  /* don't give them telepathy, too */
+                       }
+               }
+               else {
+                       pline("For some reason, that tasted bland.");
+               }
+               /* fall through to default case */
+           default: {
+               register struct permonst *ptr = &mons[pm];
+               int i, count;
+
+               if (dmgtype(ptr, AD_STUN) || dmgtype(ptr, AD_HALU) ||
+                   pm == PM_VIOLET_FUNGUS) {
+                       pline ("Oh wow!  Great stuff!");
+                       make_hallucinated(HHallucination + 200,FALSE,0L);
+               }
+               if(is_giant(ptr)) gainstr((struct obj *)0, 0);
+
+               /* Check the monster for all of the intrinsics.  If this
+                * monster can give more than one, pick one to try to give
+                * from among all it can give.
+                *
+                * If a monster can give 4 intrinsics then you have
+                * a 1/1 * 1/2 * 2/3 * 3/4 = 1/4 chance of getting the first,
+                * a 1/2 * 2/3 * 3/4 = 1/4 chance of getting the second,
+                * a 1/3 * 3/4 = 1/4 chance of getting the third,
+                * and a 1/4 chance of getting the fourth.
+                *
+                * And now a proof by induction:
+                * it works for 1 intrinsic (1 in 1 of getting it)
+                * for 2 you have a 1 in 2 chance of getting the second,
+                *      otherwise you keep the first
+                * for 3 you have a 1 in 3 chance of getting the third,
+                *      otherwise you keep the first or the second
+                * for n+1 you have a 1 in n+1 chance of getting the (n+1)st,
+                *      otherwise you keep the previous one.
+                * Elliott Kleinrock, October 5, 1990
+                */
+
+                count = 0;     /* number of possible intrinsics */
+                tmp = 0;       /* which one we will try to give */
+                for (i = 1; i <= LAST_PROP; i++) {
+                       if (intrinsic_possible(i, ptr)) {
+                               count++;
+                               /* a 1 in count chance of replacing the old
+                                * one with this one, and a count-1 in count
+                                * chance of keeping the old one.  (note
+                                * that 1 in 1 and 0 in 1 are what we want
+                                * for the first one
+                                */
+                               if (!rn2(count)) {
+#ifdef DEBUG
+                                       debugpline("Intrinsic %d replacing %d",
+                                                               i, tmp);
+#endif
+                                       tmp = i;
+                               }
+                       }
+                }
+
+                /* if any found try to give them one */
+                if (count) givit(tmp, ptr);
+           }
+           break;
+       }
+
+       if (catch_lycanthropy && defends(AD_WERE, uwep)) {
+           if (!touch_artifact(uwep, &youmonst)) {
+               dropx(uwep);
+               uwepgone();
+           }
+       }
+
+       return;
+}
+
+void
+violated_vegetarian()
+{
+    u.uconduct.unvegetarian++;
+    if (Role_if(PM_MONK)) {
+       You_feel("guilty.");
+       adjalign(-1);
+    }
+    return;
+}
+
+/* common code to check and possibly charge for 1 context.tin.tin,
+ * will split() context.tin.tin if necessary */
+STATIC_PTR
+void
+costly_tin(verb)
+       const char* verb;               /* if 0, the verb is "open" */
+{
+       if(((!carried(tin.tin) &&
+            costly_spot(tin.tin->ox, tin.tin->oy) &&
+            !tin.tin->no_charge)
+           || tin.tin->unpaid)) {
+           verbalize("You %s it, you bought it!", verb ? verb : "open");
+           if(tin.tin->quan > 1L) tin.tin = splitobj(tin.tin, 1L);
+           bill_dummy_object(tin.tin);
+       }
+}
+
+STATIC_PTR
+int
+opentin()              /* called during each move whilst opening a tin */
+{
+       register int r;
+       const char *what;
+       int which;
+
+       if(!carried(tin.tin) && !obj_here(tin.tin, u.ux, u.uy))
+                                       /* perhaps it was stolen? */
+               return(0);              /* %% probably we should use tinoid */
+       if(tin.usedtime++ >= 50) {
+               You("give up your attempt to open the tin.");
+               return(0);
+       }
+       if(tin.usedtime < tin.reqtime)
+               return(1);              /* still busy */
+       if(tin.tin->otrapped ||
+          (tin.tin->cursed && tin.tin->spe != -1 && !rn2(8))) {
+               b_trapped("tin", 0);
+               costly_tin("destroyed");
+               goto use_me;
+       }
+       You("succeed in opening the tin.");
+       if(tin.tin->spe != 1) {
+           if (tin.tin->corpsenm == NON_PM) {
+               pline("It turns out to be empty.");
+               tin.tin->dknown = tin.tin->known = TRUE;
+               costly_tin((const char*)0);
+               goto use_me;
+           }
+           r = tin.tin->cursed ? ROTTEN_TIN :  /* always rotten if cursed */
+                   (tin.tin->spe == -1) ? HOMEMADE_TIN :  /* player made it */
+                       rn2(TTSZ-1);            /* else take your pick */
+           if (r == ROTTEN_TIN && (tin.tin->corpsenm == PM_LIZARD ||
+                       tin.tin->corpsenm == PM_LICHEN))
+               r = HOMEMADE_TIN;               /* lizards don't rot */
+           else if (tin.tin->spe == -1 && !tin.tin->blessed && !rn2(7))
+               r = ROTTEN_TIN;                 /* some homemade tins go bad */
+           which = 0;  /* 0=>plural, 1=>as-is, 2=>"the" prefix */
+           if (Hallucination) {
+               what = rndmonnam();
+           } else {
+               what = mons[tin.tin->corpsenm].mname;
+               if (mons[tin.tin->corpsenm].geno & G_UNIQ)
+                   which = type_is_pname(&mons[tin.tin->corpsenm]) ? 1 : 2;
+           }
+           if (which == 0) what = makeplural(what);
+           pline("It smells like %s%s.", (which == 2) ? "the " : "", what);
+           if (yn("Eat it?") == 'n') {
+               if (!Hallucination) tin.tin->dknown = tin.tin->known = TRUE;
+               if (flags.verbose) You("discard the open tin.");
+               costly_tin((const char*)0);
+               goto use_me;
+           }
+           /* in case stop_occupation() was called on previous meal */
+           victual.piece = (struct obj *)0;
+           victual.fullwarn = victual.eating = victual.doreset = FALSE;
+
+           You("consume %s %s.", tintxts[r].txt,
+                       mons[tin.tin->corpsenm].mname);
+
+           /* KMH, conduct */
+           u.uconduct.food++;
+           if (!vegan(&mons[tin.tin->corpsenm]))
+               u.uconduct.unvegan++;
+           if (!vegetarian(&mons[tin.tin->corpsenm]))
+               violated_vegetarian();
+
+           tin.tin->dknown = tin.tin->known = TRUE;
+           cprefx(tin.tin->corpsenm); cpostfx(tin.tin->corpsenm);
+
+           /* charge for one at pre-eating cost */
+           costly_tin((const char*)0);
+
+           /* check for vomiting added by GAN 01/16/87 */
+           if(tintxts[r].nut < 0) make_vomiting((long)rn1(15,10), FALSE);
+           else lesshungry(tintxts[r].nut);
+
+           if(r == 0 || r == FRENCH_FRIED_TIN) {
+               /* Assume !Glib, because you can't open tins when Glib. */
+               incr_itimeout(&Glib, rnd(15));
+               pline("Eating deep fried food made your %s very slippery.",
+                     makeplural(body_part(FINGER)));
+           }
+       } else {
+           if (tin.tin->cursed)
+               pline("It contains some decaying%s%s substance.",
+                       Blind ? "" : " ", Blind ? "" : hcolor(NH_GREEN));
+           else
+               pline("It contains spinach.");
+
+           if (yn("Eat it?") == 'n') {
+               if (!Hallucination && !tin.tin->cursed)
+                   tin.tin->dknown = tin.tin->known = TRUE;
+               if (flags.verbose)
+                   You("discard the open tin.");
+               costly_tin((const char*)0);
+               goto use_me;
+           }
+
+           tin.tin->dknown = tin.tin->known = TRUE;
+           costly_tin((const char*)0);
+
+           if (!tin.tin->cursed)
+               pline("This makes you feel like %s!",
+                     Hallucination ? "Swee'pea" : "Popeye");
+           lesshungry(600);
+           gainstr(tin.tin, 0);
+           u.uconduct.food++;
+       }
+use_me:
+       if (carried(tin.tin)) useup(tin.tin);
+       else useupf(tin.tin, 1L);
+       tin.tin = (struct obj *) 0;
+       return(0);
+}
+
+STATIC_OVL void
+start_tin(otmp)                /* called when starting to open a tin */
+       register struct obj *otmp;
+{
+       register int tmp;
+
+       if (metallivorous(youmonst.data)) {
+               You("bite right into the metal tin...");
+               tmp = 1;
+       } else if (nolimbs(youmonst.data)) {
+               You("cannot handle the tin properly to open it.");
+               return;
+       } else if (otmp->blessed) {
+               pline_The("tin opens like magic!");
+               tmp = 1;
+       } else if(uwep) {
+               switch(uwep->otyp) {
+               case TIN_OPENER:
+                       tmp = 1;
+                       break;
+               case DAGGER:
+               case SILVER_DAGGER:
+               case ELVEN_DAGGER:
+               case ORCISH_DAGGER:
+               case ATHAME:
+               case CRYSKNIFE:
+                       tmp = 3;
+                       break;
+               case PICK_AXE:
+               case AXE:
+                       tmp = 6;
+                       break;
+               default:
+                       goto no_opener;
+               }
+               pline("Using your %s you try to open the tin.",
+                       aobjnam(uwep, (char *)0));
+       } else {
+no_opener:
+               pline("It is not so easy to open this tin.");
+               if(Glib) {
+                       pline_The("tin slips from your %s.",
+                             makeplural(body_part(FINGER)));
+                       if(otmp->quan > 1L) {
+                           otmp = splitobj(otmp, 1L);
+                       }
+                       if (carried(otmp)) dropx(otmp);
+                       else stackobj(otmp);
+                       return;
+               }
+               tmp = rn1(1 + 500/((int)(ACURR(A_DEX) + ACURRSTR)), 10);
+       }
+       tin.reqtime = tmp;
+       tin.usedtime = 0;
+       tin.tin = otmp;
+       set_occupation(opentin, "opening the tin", 0);
+       return;
+}
+
+int
+Hear_again()           /* called when waking up after fainting */
+{
+       flags.soundok = 1;
+       return 0;
+}
+
+/* called on the "first bite" of rotten food */
+STATIC_OVL int
+rottenfood(obj)
+struct obj *obj;
+{
+       pline("Blecch!  Rotten %s!", foodword(obj));
+       if(!rn2(4)) {
+               if (Hallucination) You_feel("rather trippy.");
+               else You_feel("rather %s.", body_part(LIGHT_HEADED));
+               make_confused(HConfusion + d(2,4),FALSE);
+       } else if(!rn2(4) && !Blind) {
+               pline("Everything suddenly goes dark.");
+               make_blinded((long)d(2,10),FALSE);
+               if (!Blind) Your(vision_clears);
+       } else if(!rn2(3)) {
+               const char *what, *where;
+               if (!Blind)
+                   what = "goes",  where = "dark";
+               else if (Levitation || Is_airlevel(&u.uz) ||
+                        Is_waterlevel(&u.uz))
+                   what = "you lose control of",  where = "yourself";
+               else
+                   what = "you slap against the", where =
+#ifdef STEED
+                          (u.usteed) ? "saddle" :
+#endif
+                          surface(u.ux,u.uy);
+               pline_The("world spins and %s %s.", what, where);
+               flags.soundok = 0;
+               nomul(-rnd(10));
+               nomovemsg = "You are conscious again.";
+               afternmv = Hear_again;
+               return(1);
+       }
+       return(0);
+}
+
+STATIC_OVL int
+eatcorpse(otmp)                /* called when a corpse is selected as food */
+       register struct obj *otmp;
+{
+       int tp = 0, mnum = otmp->corpsenm;
+       long rotted = 0L;
+       boolean uniq = !!(mons[mnum].geno & G_UNIQ);
+       int retcode = 0;
+       boolean stoneable = (touch_petrifies(&mons[mnum]) && !Stone_resistance &&
+                               !poly_when_stoned(youmonst.data));
+
+       /* KMH, conduct */
+       if (!vegan(&mons[mnum])) u.uconduct.unvegan++;
+       if (!vegetarian(&mons[mnum])) violated_vegetarian();
+
+       if (mnum != PM_LIZARD && mnum != PM_LICHEN) {
+               long age = peek_at_iced_corpse_age(otmp);
+
+               rotted = (monstermoves - age)/(10L + rn2(20));
+               if (otmp->cursed) rotted += 2L;
+               else if (otmp->blessed) rotted -= 2L;
+       }
+
+       if (mnum != PM_ACID_BLOB && !stoneable && rotted > 5L) {
+               boolean cannibal = maybe_cannibal(mnum, FALSE);
+               pline("Ulch - that %s was tainted%s!",
+                     mons[mnum].mlet == S_FUNGUS ? "fungoid vegetation" :
+                     !vegetarian(&mons[mnum]) ? "meat" : "protoplasm",
+                     cannibal ? " cannibal" : "");
+               if (Sick_resistance) {
+                       pline("It doesn't seem at all sickening, though...");
+               } else {
+                       char buf[BUFSZ];
+                       long sick_time;
+
+                       sick_time = (long) rn1(10, 10);
+                       /* make sure new ill doesn't result in improvement */
+                       if (Sick && (sick_time > Sick))
+                           sick_time = (Sick > 1L) ? Sick - 1L : 1L;
+                       if (!uniq)
+                           Sprintf(buf, "rotted %s", corpse_xname(otmp,TRUE));
+                       else
+                           Sprintf(buf, "%s%s rotted corpse",
+                                   !type_is_pname(&mons[mnum]) ? "the " : "",
+                                   s_suffix(mons[mnum].mname));
+                       make_sick(sick_time, buf, TRUE, SICK_VOMITABLE);
+               }
+               if (carried(otmp)) useup(otmp);
+               else useupf(otmp, 1L);
+               return(2);
+       } else if (acidic(&mons[mnum]) && !Acid_resistance) {
+               tp++;
+               You("have a very bad case of stomach acid."); /* not body_part() */
+               losehp(rnd(15), "acidic corpse", KILLED_BY_AN);
+       } else if (poisonous(&mons[mnum]) && rn2(5)) {
+               tp++;
+               pline("Ecch - that must have been poisonous!");
+               if(!Poison_resistance) {
+                       losestr(rnd(4));
+                       losehp(rnd(15), "poisonous corpse", KILLED_BY_AN);
+               } else  You("seem unaffected by the poison.");
+       /* now any corpse left too long will make you mildly ill */
+       } else if ((rotted > 5L || (rotted > 3L && rn2(5)))
+                                       && !Sick_resistance) {
+               tp++;
+               You_feel("%ssick.", (Sick) ? "very " : "");
+               losehp(rnd(8), "cadaver", KILLED_BY_AN);
+       }
+
+       /* delay is weight dependent */
+       victual.reqtime = 3 + (mons[mnum].cwt >> 6);
+
+       if (!tp && mnum != PM_LIZARD && mnum != PM_LICHEN &&
+                       (otmp->orotten || !rn2(7))) {
+           if (rottenfood(otmp)) {
+               otmp->orotten = TRUE;
+               (void)touchfood(otmp);
+               retcode = 1;
+           }
+
+           if (!mons[otmp->corpsenm].cnutrit) {
+               /* no nutrution: rots away, no message if you passed out */
+               if (!retcode) pline_The("corpse rots away completely.");
+               if (carried(otmp)) useup(otmp);
+               else useupf(otmp, 1L);
+               retcode = 2;
+           }
+                   
+           if (!retcode) consume_oeaten(otmp, 2);      /* oeaten >>= 2 */
+       } else {
+           pline("%s%s %s!",
+                 !uniq ? "This " : !type_is_pname(&mons[mnum]) ? "The " : "",
+                 food_xname(otmp, FALSE),
+                 (vegan(&mons[mnum]) ?
+                  (!carnivorous(youmonst.data) && herbivorous(youmonst.data)) :
+                  (carnivorous(youmonst.data) && !herbivorous(youmonst.data)))
+                 ? "is delicious" : "tastes terrible");
+       }
+
+       return(retcode);
+}
+
+STATIC_OVL void
+start_eating(otmp)             /* called as you start to eat */
+       register struct obj *otmp;
+{
+#ifdef DEBUG
+       debugpline("start_eating: %lx (victual = %lx)", otmp, victual.piece);
+       debugpline("reqtime = %d", victual.reqtime);
+       debugpline("(original reqtime = %d)", objects[otmp->otyp].oc_delay);
+       debugpline("nmod = %d", victual.nmod);
+       debugpline("oeaten = %d", otmp->oeaten);
+#endif
+       victual.fullwarn = victual.doreset = FALSE;
+       victual.eating = TRUE;
+
+       if (otmp->otyp == CORPSE) {
+           cprefx(victual.piece->corpsenm);
+           if (!victual.piece || !victual.eating) {
+               /* rider revived, or died and lifesaved */
+               return;
+           }
+       }
+
+       if (bite()) return;
+
+       if (++victual.usedtime >= victual.reqtime) {
+           /* print "finish eating" message if they just resumed -dlc */
+           done_eating(victual.reqtime > 1 ? TRUE : FALSE);
+           return;
+       }
+
+       Sprintf(msgbuf, "eating %s", food_xname(otmp, TRUE));
+       set_occupation(eatfood, msgbuf, 0);
+}
+
+
+/*
+ * called on "first bite" of (non-corpse) food.
+ * used for non-rotten non-tin non-corpse food
+ */
+STATIC_OVL void
+fprefx(otmp)
+struct obj *otmp;
+{
+       switch(otmp->otyp) {
+           case FOOD_RATION:
+               if(u.uhunger <= 200)
+                   pline(Hallucination ? "Oh wow, like, superior, man!" :
+                         "That food really hit the spot!");
+               else if(u.uhunger <= 700) pline("That satiated your %s!",
+                                               body_part(STOMACH));
+               break;
+           case TRIPE_RATION:
+               if (carnivorous(youmonst.data) && !humanoid(youmonst.data))
+                   pline("That tripe ration was surprisingly good!");
+               else if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC)))
+                   pline(Hallucination ? "Tastes great! Less filling!" :
+                         "Mmm, tripe... not bad!");
+               else {
+                   pline("Yak - dog food!");
+                   more_experienced(1,0);
+                   newexplevel();
+                   /* not cannibalism, but we use similar criteria
+                      for deciding whether to be sickened by this meal */
+                   if (rn2(2) && !CANNIBAL_ALLOWED())
+                       make_vomiting((long)rn1(victual.reqtime, 14), FALSE);
+               }
+               break;
+           case MEATBALL:
+           case MEAT_STICK:
+           case HUGE_CHUNK_OF_MEAT:
+           case MEAT_RING:
+               goto give_feedback;
+            /* break; */
+           case CLOVE_OF_GARLIC:
+               if (is_undead(youmonst.data)) {
+                       make_vomiting((long)rn1(victual.reqtime, 5), FALSE);
+                       break;
+               }
+               /* Fall through otherwise */
+           default:
+               if (otmp->otyp==SLIME_MOLD && !otmp->cursed
+                       && otmp->spe == current_fruit)
+                   pline("My, that was a %s %s!",
+                         Hallucination ? "primo" : "yummy",
+                         singular(otmp, xname));
+               else
+#ifdef UNIX
+               if (otmp->otyp == APPLE || otmp->otyp == PEAR) {
+                   if (!Hallucination) pline("Core dumped.");
+                   else {
+/* This is based on an old Usenet joke, a fake a.out manual page */
+                       int x = rnd(100);
+                       if (x <= 75)
+                           pline("Segmentation fault -- core dumped.");
+                       else if (x <= 99)
+                           pline("Bus error -- core dumped.");
+                       else pline("Yo' mama -- core dumped.");
+                   }
+               } else
+#endif
+#ifdef MAC     /* KMH -- Why should Unix have all the fun? */
+               if (otmp->otyp == APPLE) {
+                       pline("Delicious!  Must be a Macintosh!");
+               } else
+#endif
+               if (otmp->otyp == EGG && stale_egg(otmp)) {
+                   pline("Ugh.  Rotten egg."); /* perhaps others like it */
+                   make_vomiting(Vomiting+d(10,4), TRUE);
+               } else
+ give_feedback:
+                   pline("This %s is %s", singular(otmp, xname),
+                     otmp->cursed ? (Hallucination ? "grody!" : "terrible!") :
+                     (otmp->otyp == CRAM_RATION
+                     || otmp->otyp == K_RATION
+                     || otmp->otyp == C_RATION)
+                     ? "bland." :
+                     Hallucination ? "gnarly!" : "delicious!");
+               break;
+       }
+}
+
+STATIC_OVL void
+accessory_has_effect(otmp)
+struct obj *otmp;
+{
+       pline("Magic spreads through your body as you digest the %s.",
+           otmp->oclass == RING_CLASS ? "ring" : "amulet");
+}
+
+STATIC_OVL void
+eataccessory(otmp)
+struct obj *otmp;
+{
+       int typ = otmp->otyp;
+       long oldprop;
+
+       /* Note: rings are not so common that this is unbalancing. */
+       /* (How often do you even _find_ 3 rings of polymorph in a game?) */
+       oldprop = u.uprops[objects[typ].oc_oprop].intrinsic;
+       if (otmp == uleft || otmp == uright) {
+           Ring_gone(otmp);
+           if (u.uhp <= 0) return; /* died from sink fall */
+       }
+       otmp->known = otmp->dknown = 1; /* by taste */
+       if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5)) {
+         switch (otmp->otyp) {
+           default:
+               if (!objects[typ].oc_oprop) break; /* should never happen */
+
+               if (!(u.uprops[objects[typ].oc_oprop].intrinsic & FROMOUTSIDE))
+                   accessory_has_effect(otmp);
+
+               u.uprops[objects[typ].oc_oprop].intrinsic |= FROMOUTSIDE;
+
+               switch (typ) {
+                 case RIN_SEE_INVISIBLE:
+                   set_mimic_blocking();
+                   see_monsters();
+                   if (Invis && !oldprop && !ESee_invisible &&
+                               !perceives(youmonst.data) && !Blind) {
+                       newsym(u.ux,u.uy);
+                       pline("Suddenly you can see yourself.");
+                       makeknown(typ);
+                   }
+                   break;
+                 case RIN_INVISIBILITY:
+                   if (!oldprop && !EInvis && !BInvis &&
+                                       !See_invisible && !Blind) {
+                       newsym(u.ux,u.uy);
+                       Your("body takes on a %s transparency...",
+                               Hallucination ? "normal" : "strange");
+                       makeknown(typ);
+                   }
+                   break;
+                 case RIN_PROTECTION_FROM_SHAPE_CHAN:
+                   rescham();
+                   break;
+                 case RIN_LEVITATION:
+                   /* undo the `.intrinsic |= FROMOUTSIDE' done above */
+                   u.uprops[LEVITATION].intrinsic = oldprop;
+                   if (!Levitation) {
+                       float_up();
+                       incr_itimeout(&HLevitation, d(10,20));
+                       makeknown(typ);
+                   }
+                   break;
+               }
+               break;
+           case RIN_ADORNMENT:
+               accessory_has_effect(otmp);
+               if (adjattrib(A_CHA, otmp->spe, -1))
+                   makeknown(typ);
+               break;
+           case RIN_GAIN_STRENGTH:
+               accessory_has_effect(otmp);
+               if (adjattrib(A_STR, otmp->spe, -1))
+                   makeknown(typ);
+               break;
+           case RIN_GAIN_CONSTITUTION:
+               accessory_has_effect(otmp);
+               if (adjattrib(A_CON, otmp->spe, -1))
+                   makeknown(typ);
+               break;
+           case RIN_INCREASE_ACCURACY:
+               accessory_has_effect(otmp);
+               u.uhitinc += otmp->spe;
+               break;
+           case RIN_INCREASE_DAMAGE:
+               accessory_has_effect(otmp);
+               u.udaminc += otmp->spe;
+               break;
+           case RIN_PROTECTION:
+               accessory_has_effect(otmp);
+               HProtection |= FROMOUTSIDE;
+               u.ublessed += otmp->spe;
+               flags.botl = 1;
+               break;
+           case RIN_FREE_ACTION:
+               /* Give sleep resistance instead */
+               if (!(HSleep_resistance & FROMOUTSIDE))
+                   accessory_has_effect(otmp);
+               if (!Sleep_resistance)
+                   You_feel("wide awake.");
+               HSleep_resistance |= FROMOUTSIDE;
+               break;
+           case AMULET_OF_CHANGE:
+               accessory_has_effect(otmp);
+               makeknown(typ);
+               change_sex();
+               You("are suddenly very %s!",
+                   flags.female ? "feminine" : "masculine");
+               flags.botl = 1;
+               break;
+           case AMULET_OF_UNCHANGING:
+               /* un-change: it's a pun */
+               if (!Unchanging && Upolyd) {
+                   accessory_has_effect(otmp);
+                   makeknown(typ);
+                   rehumanize();
+               }
+               break;
+           case AMULET_OF_STRANGULATION: /* bad idea! */
+               /* no message--this gives no permanent effect */
+               choke(otmp);
+               break;
+           case AMULET_OF_RESTFUL_SLEEP: /* another bad idea! */
+               if (!(HSleeping & FROMOUTSIDE))
+                   accessory_has_effect(otmp);
+               HSleeping = FROMOUTSIDE | rnd(100);
+               break;
+           case RIN_SUSTAIN_ABILITY:
+           case AMULET_OF_LIFE_SAVING:
+           case AMULET_OF_REFLECTION: /* nice try */
+           /* can't eat Amulet of Yendor or fakes,
+            * and no oc_prop even if you could -3.
+            */
+               break;
+         }
+       }
+}
+
+STATIC_OVL void
+eatspecial() /* called after eating non-food */
+{
+       register struct obj *otmp = victual.piece;
+
+       /* lesshungry wants an occupation to handle choke messages correctly */
+       set_occupation(eatfood, "eating non-food", 0);
+       lesshungry(victual.nmod);
+       occupation = 0;
+       victual.piece = (struct obj *)0;
+       victual.eating = 0;
+       if (otmp->oclass == COIN_CLASS) {
+#ifdef GOLDOBJ
+               if (carried(otmp))
+                   useupall(otmp);
+#else
+               if (otmp->where == OBJ_FREE)
+                   dealloc_obj(otmp);
+#endif
+               else
+                   useupf(otmp, otmp->quan);
+               return;
+       }
+       if (otmp->oclass == POTION_CLASS) {
+               otmp->quan++; /* dopotion() does a useup() */
+               (void)dopotion(otmp);
+       }
+       if (otmp->oclass == RING_CLASS || otmp->oclass == AMULET_CLASS)
+               eataccessory(otmp);
+       else if (otmp->otyp == LEASH && otmp->leashmon)
+               o_unleash(otmp);
+
+       /* KMH -- idea by "Tommy the Terrorist" */
+       if ((otmp->otyp == TRIDENT) && !otmp->cursed)
+       {
+               pline(Hallucination ? "Four out of five dentists agree." :
+                               "That was pure chewing satisfaction!");
+               exercise(A_WIS, TRUE);
+       }
+       if ((otmp->otyp == FLINT) && !otmp->cursed)
+       {
+               pline("Yabba-dabba delicious!");
+               exercise(A_CON, TRUE);
+       }
+
+       if (otmp == uwep && otmp->quan == 1L) uwepgone();
+       if (otmp == uquiver && otmp->quan == 1L) uqwepgone();
+       if (otmp == uswapwep && otmp->quan == 1L) uswapwepgone();
+
+       if (otmp == uball) unpunish();
+       if (otmp == uchain) unpunish(); /* but no useup() */
+       else if (carried(otmp)) useup(otmp);
+       else useupf(otmp, 1L);
+}
+
+/* NOTE: the order of these words exactly corresponds to the
+   order of oc_material values #define'd in objclass.h. */
+static const char *foodwords[] = {
+       "meal", "liquid", "wax", "food", "meat",
+       "paper", "cloth", "leather", "wood", "bone", "scale",
+       "metal", "metal", "metal", "silver", "gold", "platinum", "mithril",
+       "plastic", "glass", "rich food", "stone"
+};
+
+STATIC_OVL const char *
+foodword(otmp)
+register struct obj *otmp;
+{
+       if (otmp->oclass == FOOD_CLASS) return "food";
+       if (otmp->oclass == GEM_CLASS &&
+           objects[otmp->otyp].oc_material == GLASS &&
+           otmp->dknown)
+               makeknown(otmp->otyp);
+       return foodwords[objects[otmp->otyp].oc_material];
+}
+
+STATIC_OVL void
+fpostfx(otmp)          /* called after consuming (non-corpse) food */
+register struct obj *otmp;
+{
+       switch(otmp->otyp) {
+           case SPRIG_OF_WOLFSBANE:
+               if (u.ulycn >= LOW_PM || is_were(youmonst.data))
+                   you_unwere(TRUE);
+               break;
+           case CARROT:
+               make_blinded((long)u.ucreamed,TRUE);
+               break;
+           case FORTUNE_COOKIE:
+               outrumor(bcsign(otmp), BY_COOKIE);
+               if (!Blind) u.uconduct.literate++;
+               break;
+           case LUMP_OF_ROYAL_JELLY:
+               /* This stuff seems to be VERY healthy! */
+               gainstr(otmp, 1);
+               if (Upolyd) {
+                   u.mh += otmp->cursed ? -rnd(20) : rnd(20);
+                   if (u.mh > u.mhmax) {
+                       if (!rn2(17)) u.mhmax++;
+                       u.mh = u.mhmax;
+                   } else if (u.mh <= 0) {
+                       rehumanize();
+                   }
+               } else {
+                   u.uhp += otmp->cursed ? -rnd(20) : rnd(20);
+                   if (u.uhp > u.uhpmax) {
+                       if(!rn2(17)) u.uhpmax++;
+                       u.uhp = u.uhpmax;
+                   } else if (u.uhp <= 0) {
+                       killer_format = KILLED_BY_AN;
+                       killer = "rotten lump of royal jelly";
+                       done(POISONING);
+                   }
+               }
+               if(!otmp->cursed) heal_legs();
+               break;
+           case EGG:
+               if (touch_petrifies(&mons[otmp->corpsenm])) {
+                   if (!Stone_resistance &&
+                       !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
+                       if (!Stoned) Stoned = 5;
+                       killer_format = KILLED_BY_AN;
+                       Sprintf(killer_buf, "%s egg", mons[otmp->corpsenm].mname);
+                       delayed_killer = killer_buf;
+                   }
+               }
+               break;
+           case EUCALYPTUS_LEAF:
+               if (Sick && !otmp->cursed)
+                   make_sick(0L, (char *)0, TRUE, SICK_ALL);
+               if (Vomiting && !otmp->cursed)
+                   make_vomiting(0L, TRUE);
+               break;
+       }
+       return;
+}
+
+/*
+ * return 0 if the food was not dangerous.
+ * return 1 if the food was dangerous and you chose to stop.
+ * return 2 if the food was dangerous and you chose to eat it anyway.
+ */
+STATIC_OVL int
+edibility_prompts(otmp)
+struct obj *otmp;
+{
+       /* blessed food detection granted you a one-use
+          ability to detect food that is unfit for consumption
+          or dangerous and avoid it. */
+
+       char buf[BUFSZ], foodsmell[BUFSZ],
+            it_or_they[QBUFSZ], eat_it_anyway[QBUFSZ];
+       boolean cadaver = (otmp->otyp == CORPSE),
+               stoneorslime = FALSE;
+       int material = objects[otmp->otyp].oc_material,
+           mnum = otmp->corpsenm;
+       long rotted = 0L;
+
+       Strcpy(foodsmell, Tobjnam(otmp, "smell"));
+       Strcpy(it_or_they, (otmp->quan == 1L) ? "it" : "they");
+       Sprintf(eat_it_anyway, "Eat %s anyway?",
+               (otmp->quan == 1L) ? "it" : "one");
+
+       if (cadaver || otmp->otyp == EGG || otmp->otyp == TIN) {
+               /* These checks must match those in eatcorpse() */
+               stoneorslime = (touch_petrifies(&mons[mnum]) &&
+                               !Stone_resistance &&
+                               !poly_when_stoned(youmonst.data));
+
+               if (mnum == PM_GREEN_SLIME)
+                   stoneorslime = (!Unchanging && !flaming(youmonst.data) &&
+                       youmonst.data != &mons[PM_GREEN_SLIME]);
+
+               if (cadaver && mnum != PM_LIZARD && mnum != PM_LICHEN) {
+                       long age = peek_at_iced_corpse_age(otmp);
+                       /* worst case rather than random
+                          in this calculation to force prompt */
+                       rotted = (monstermoves - age)/(10L + 0 /* was rn2(20) */);
+                       if (otmp->cursed) rotted += 2L;
+                       else if (otmp->blessed) rotted -= 2L;
+               }
+       }
+
+       /*
+        * These problems with food should be checked in
+        * order from most detrimental to least detrimental.
+        */
+
+       if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && !Sick_resistance) {
+               /* Tainted meat */
+               Sprintf(buf, "%s like %s could be tainted! %s",
+                       foodsmell, it_or_they, eat_it_anyway);
+               if (yn_function(buf,ynchars,'n')=='n') return 1;
+               else return 2;
+       }
+       if (stoneorslime) {
+               Sprintf(buf, "%s like %s could be something very dangerous! %s",
+                       foodsmell, it_or_they, eat_it_anyway);
+               if (yn_function(buf,ynchars,'n')=='n') return 1;
+               else return 2;
+       }
+       if (otmp->orotten || (cadaver && rotted > 3L)) {
+               /* Rotten */
+               Sprintf(buf, "%s like %s could be rotten! %s",
+                       foodsmell, it_or_they, eat_it_anyway);
+               if (yn_function(buf,ynchars,'n')=='n') return 1;
+               else return 2;
+       }
+       if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) {
+               /* poisonous */
+               Sprintf(buf, "%s like %s might be poisonous! %s",
+                       foodsmell, it_or_they, eat_it_anyway);
+               if (yn_function(buf,ynchars,'n')=='n') return 1;
+               else return 2;
+       }
+       if (cadaver && !vegetarian(&mons[mnum]) &&
+           !u.uconduct.unvegetarian && Role_if(PM_MONK)) {
+               Sprintf(buf, "%s unhealthy. %s",
+                       foodsmell, eat_it_anyway);
+               if (yn_function(buf,ynchars,'n')=='n') return 1;
+               else return 2;
+       }
+       if (cadaver && acidic(&mons[mnum]) && !Acid_resistance) {
+               Sprintf(buf, "%s rather acidic. %s",
+                       foodsmell, eat_it_anyway);
+               if (yn_function(buf,ynchars,'n')=='n') return 1;
+               else return 2;
+       }
+       if (Upolyd && u.umonnum == PM_RUST_MONSTER &&
+           is_metallic(otmp) && otmp->oerodeproof) {
+               Sprintf(buf, "%s disgusting to you right now. %s",
+                       foodsmell, eat_it_anyway);
+               if (yn_function(buf,ynchars,'n')=='n') return 1;
+               else return 2;
+       }
+
+       /*
+        * Breaks conduct, but otherwise safe.
+        */
+        
+       if (!u.uconduct.unvegan &&
+           ((material == LEATHER || material == BONE ||
+             material == DRAGON_HIDE || material == WAX) ||
+            (cadaver && !vegan(&mons[mnum])))) {
+               Sprintf(buf, "%s foul and unfamiliar to you. %s",
+                       foodsmell, eat_it_anyway);
+               if (yn_function(buf,ynchars,'n')=='n') return 1;
+               else return 2;
+       }
+       if (!u.uconduct.unvegetarian &&
+           ((material == LEATHER || material == BONE ||
+             material == DRAGON_HIDE) ||
+            (cadaver && !vegetarian(&mons[mnum])))) {
+               Sprintf(buf, "%s unfamiliar to you. %s",
+                       foodsmell, eat_it_anyway);
+               if (yn_function(buf,ynchars,'n')=='n') return 1;
+               else return 2;
+       }
+
+       if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && Sick_resistance) {
+               /* Tainted meat with Sick_resistance */
+               Sprintf(buf, "%s like %s could be tainted! %s",
+                       foodsmell, it_or_they, eat_it_anyway);
+               if (yn_function(buf,ynchars,'n')=='n') return 1;
+               else return 2;
+       }
+       return 0;
+}
+
+int
+doeat()                /* generic "eat" command funtion (see cmd.c) */
+{
+       register struct obj *otmp;
+       int basenutrit;                 /* nutrition of full item */
+       boolean dont_start = FALSE;
+       
+       if (Strangled) {
+               pline("If you can't breathe air, how can you consume solids?");
+               return 0;
+       }
+       if (!(otmp = floorfood("eat", 0))) return 0;
+       if (check_capacity((char *)0)) return 0;
+
+       if (u.uedibility) {
+               int res = edibility_prompts(otmp);
+               if (res) {
+                   Your("%s stops tingling and your sense of smell returns to normal.",
+                       body_part(NOSE));
+                   u.uedibility = 0;
+                   if (res == 1) return 0;
+               }
+       }
+
+       /* We have to make non-foods take 1 move to eat, unless we want to
+        * do ridiculous amounts of coding to deal with partly eaten plate
+        * mails, players who polymorph back to human in the middle of their
+        * metallic meal, etc....
+        */
+       if (!is_edible(otmp)) {
+           You("cannot eat that!");
+           return 0;
+       } else if ((otmp->owornmask & (W_ARMOR|W_TOOL|W_AMUL
+#ifdef STEED
+                       |W_SADDLE
+#endif
+                       )) != 0) {
+           /* let them eat rings */
+           You_cant("eat %s you're wearing.", something);
+           return 0;
+       }
+       if (is_metallic(otmp) &&
+           u.umonnum == PM_RUST_MONSTER && otmp->oerodeproof) {
+               otmp->rknown = TRUE;
+               if (otmp->quan > 1L) {
+                   if(!carried(otmp))
+                       (void) splitobj(otmp, otmp->quan - 1L);
+                   else
+                       otmp = splitobj(otmp, 1L);
+               }
+               pline("Ulch - That %s was rustproofed!", xname(otmp));
+               /* The regurgitated object's rustproofing is gone now */
+               otmp->oerodeproof = 0;
+               make_stunned(HStun + rn2(10), TRUE);
+               You("spit %s out onto the %s.", the(xname(otmp)),
+                       surface(u.ux, u.uy));
+               if (carried(otmp)) {
+                       freeinv(otmp);
+                       dropy(otmp);
+               }
+               stackobj(otmp);
+               return 1;
+       }
+       /* KMH -- Slow digestion is... indigestible */
+       if (otmp->otyp == RIN_SLOW_DIGESTION) {
+               pline("This ring is indigestible!");
+               (void) rottenfood(otmp);
+               if (otmp->dknown && !objects[otmp->otyp].oc_name_known
+                               && !objects[otmp->otyp].oc_uname)
+                       docall(otmp);
+               return (1);
+       }
+       if (otmp->oclass != FOOD_CLASS) {
+           int material;
+           victual.reqtime = 1;
+           victual.piece = otmp;
+               /* Don't split it, we don't need to if it's 1 move */
+           victual.usedtime = 0;
+           victual.canchoke = (u.uhs == SATIATED);
+               /* Note: gold weighs 1 pt. for each 1000 pieces (see */
+               /* pickup.c) so gold and non-gold is consistent. */
+           if (otmp->oclass == COIN_CLASS)
+               basenutrit = ((otmp->quan > 200000L) ? 2000
+                       : (int)(otmp->quan/100L));
+           else if(otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS)
+               basenutrit = weight(otmp);
+           /* oc_nutrition is usually weight anyway */
+           else basenutrit = objects[otmp->otyp].oc_nutrition;
+           victual.nmod = basenutrit;
+           victual.eating = TRUE; /* needed for lesshungry() */
+
+           material = objects[otmp->otyp].oc_material;
+           if (material == LEATHER ||
+               material == BONE || material == DRAGON_HIDE) {
+               u.uconduct.unvegan++;
+               violated_vegetarian();
+           } else if (material == WAX)
+               u.uconduct.unvegan++;
+           u.uconduct.food++;
+           
+           if (otmp->cursed)
+               (void) rottenfood(otmp);
+
+           if (otmp->oclass == WEAPON_CLASS && otmp->opoisoned) {
+               pline("Ecch - that must have been poisonous!");
+               if(!Poison_resistance) {
+                   losestr(rnd(4));
+                   losehp(rnd(15), xname(otmp), KILLED_BY_AN);
+               } else
+                   You("seem unaffected by the poison.");
+           } else if (!otmp->cursed)
+               pline("This %s is delicious!",
+                     otmp->oclass == COIN_CLASS ? foodword(otmp) :
+                     singular(otmp, xname));
+
+           eatspecial();
+           return 1;
+       }
+
+       if(otmp == victual.piece) {
+       /* If they weren't able to choke, they don't suddenly become able to
+        * choke just because they were interrupted.  On the other hand, if
+        * they were able to choke before, if they lost food it's possible
+        * they shouldn't be able to choke now.
+        */
+           if (u.uhs != SATIATED) victual.canchoke = FALSE;
+           victual.piece = touchfood(otmp);
+           You("resume your meal.");
+           start_eating(victual.piece);
+           return(1);
+       }
+
+       /* nothing in progress - so try to find something. */
+       /* tins are a special case */
+       /* tins must also check conduct separately in case they're discarded */
+       if(otmp->otyp == TIN) {
+           start_tin(otmp);
+           return(1);
+       }
+
+       /* KMH, conduct */
+       u.uconduct.food++;
+
+       victual.piece = otmp = touchfood(otmp);
+       victual.usedtime = 0;
+
+       /* Now we need to calculate delay and nutritional info.
+        * The base nutrition calculated here and in eatcorpse() accounts
+        * for normal vs. rotten food.  The reqtime and nutrit values are
+        * then adjusted in accordance with the amount of food left.
+        */
+       if(otmp->otyp == CORPSE) {
+           int tmp = eatcorpse(otmp);
+           if (tmp == 2) {
+               /* used up */
+               victual.piece = (struct obj *)0;
+               return(1);
+           } else if (tmp)
+               dont_start = TRUE;
+           /* if not used up, eatcorpse sets up reqtime and may modify
+            * oeaten */
+       } else {
+           /* No checks for WAX, LEATHER, BONE, DRAGON_HIDE.  These are
+            * all handled in the != FOOD_CLASS case, above */
+           switch (objects[otmp->otyp].oc_material) {
+           case FLESH:
+               u.uconduct.unvegan++;
+               if (otmp->otyp != EGG) {
+                   violated_vegetarian();
+               }
+               break;
+
+           default:
+               if (otmp->otyp == PANCAKE ||
+                   otmp->otyp == FORTUNE_COOKIE || /* eggs */
+                   otmp->otyp == CREAM_PIE ||
+                   otmp->otyp == CANDY_BAR || /* milk */
+                   otmp->otyp == LUMP_OF_ROYAL_JELLY)
+                   u.uconduct.unvegan++;
+               break;
+           }
+
+           victual.reqtime = objects[otmp->otyp].oc_delay;
+           if (otmp->otyp != FORTUNE_COOKIE &&
+               (otmp->cursed ||
+                (((monstermoves - otmp->age) > (int) otmp->blessed ? 50:30) &&
+               (otmp->orotten || !rn2(7))))) {
+
+               if (rottenfood(otmp)) {
+                   otmp->orotten = TRUE;
+                   dont_start = TRUE;
+               }
+               consume_oeaten(otmp, 1);        /* oeaten >>= 1 */
+           } else fprefx(otmp);
+       }
+
+       /* re-calc the nutrition */
+       if (otmp->otyp == CORPSE) basenutrit = mons[otmp->corpsenm].cnutrit;
+       else basenutrit = objects[otmp->otyp].oc_nutrition;
+
+#ifdef DEBUG
+       debugpline("before rounddiv: victual.reqtime == %d", victual.reqtime);
+       debugpline("oeaten == %d, basenutrit == %d", otmp->oeaten, basenutrit);
+#endif
+       victual.reqtime = (basenutrit == 0 ? 0 :
+               rounddiv(victual.reqtime * (long)otmp->oeaten, basenutrit));
+#ifdef DEBUG
+       debugpline("after rounddiv: victual.reqtime == %d", victual.reqtime);
+#endif
+       /* calculate the modulo value (nutrit. units per round eating)
+        * note: this isn't exact - you actually lose a little nutrition
+        *       due to this method.
+        * TODO: add in a "remainder" value to be given at the end of the
+        *       meal.
+        */
+       if (victual.reqtime == 0 || otmp->oeaten == 0)
+           /* possible if most has been eaten before */
+           victual.nmod = 0;
+       else if ((int)otmp->oeaten >= victual.reqtime)
+           victual.nmod = -((int)otmp->oeaten / victual.reqtime);
+       else
+           victual.nmod = victual.reqtime % otmp->oeaten;
+       victual.canchoke = (u.uhs == SATIATED);
+
+       if (!dont_start) start_eating(otmp);
+       return(1);
+}
+
+/* Take a single bite from a piece of food, checking for choking and
+ * modifying usedtime.  Returns 1 if they choked and survived, 0 otherwise.
+ */
+STATIC_OVL int
+bite()
+{
+       if(victual.canchoke && u.uhunger >= 2000) {
+               choke(victual.piece);
+               return 1;
+       }
+       if (victual.doreset) {
+               do_reset_eat();
+               return 0;
+       }
+       force_save_hs = TRUE;
+       if(victual.nmod < 0) {
+               lesshungry(-victual.nmod);
+               consume_oeaten(victual.piece, victual.nmod); /* -= -nmod */
+       } else if(victual.nmod > 0 && (victual.usedtime % victual.nmod)) {
+               lesshungry(1);
+               consume_oeaten(victual.piece, -1);                /* -= 1 */
+       }
+       force_save_hs = FALSE;
+       recalc_wt();
+       return 0;
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+void
+gethungry()    /* as time goes by - called by moveloop() and domove() */
+{
+       if (u.uinvulnerable) return;    /* you don't feel hungrier */
+
+       if ((!u.usleep || !rn2(10))     /* slow metabolic rate while asleep */
+               && (carnivorous(youmonst.data) || herbivorous(youmonst.data))
+               && !Slow_digestion)
+           u.uhunger--;                /* ordinary food consumption */
+
+       if (moves % 2) {        /* odd turns */
+           /* Regeneration uses up food, unless due to an artifact */
+           if (HRegeneration || ((ERegeneration & (~W_ART)) &&
+                               (ERegeneration != W_WEP || !uwep->oartifact)))
+                       u.uhunger--;
+           if (near_capacity() > SLT_ENCUMBER) u.uhunger--;
+       } else {                /* even turns */
+           if (Hunger) u.uhunger--;
+           /* Conflict uses up food too */
+           if (HConflict || (EConflict & (~W_ARTI))) u.uhunger--;
+           /* +0 charged rings don't do anything, so don't affect hunger */
+           /* Slow digestion still uses ring hunger */
+           switch ((int)(moves % 20)) {        /* note: use even cases only */
+            case  4: if (uleft &&
+                         (uleft->spe || !objects[uleft->otyp].oc_charged))
+                           u.uhunger--;
+                   break;
+            case  8: if (uamul) u.uhunger--;
+                   break;
+            case 12: if (uright &&
+                         (uright->spe || !objects[uright->otyp].oc_charged))
+                           u.uhunger--;
+                   break;
+            case 16: if (u.uhave.amulet) u.uhunger--;
+                   break;
+            default: break;
+           }
+       }
+       newuhs(TRUE);
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+void
+morehungry(num)        /* called after vomiting and after performing feats of magic */
+register int num;
+{
+       u.uhunger -= num;
+       newuhs(TRUE);
+}
+
+
+void
+lesshungry(num)        /* called after eating (and after drinking fruit juice) */
+register int num;
+{
+       /* See comments in newuhs() for discussion on force_save_hs */
+       boolean iseating = (occupation == eatfood) || force_save_hs;
+#ifdef DEBUG
+       debugpline("lesshungry(%d)", num);
+#endif
+       u.uhunger += num;
+       if(u.uhunger >= 2000) {
+           if (!iseating || victual.canchoke) {
+               if (iseating) {
+                   choke(victual.piece);
+                   reset_eat();
+               } else
+                   choke(occupation == opentin ? tin.tin : (struct obj *)0);
+               /* no reset_eat() */
+           }
+       } else {
+           /* Have lesshungry() report when you're nearly full so all eating
+            * warns when you're about to choke.
+            */
+           if (u.uhunger >= 1500) {
+               if (!victual.eating || (victual.eating && !victual.fullwarn)) {
+                   pline("You're having a hard time getting all of it down.");
+                   nomovemsg = "You're finally finished.";
+                   if (!victual.eating)
+                       multi = -2;
+                   else {
+                       victual.fullwarn = TRUE;
+                       if (victual.canchoke && victual.reqtime > 1) {
+                           /* a one-gulp food will not survive a stop */
+                           if (yn_function("Stop eating?",ynchars,'y')=='y') {
+                               reset_eat();
+                               nomovemsg = (char *)0;
+                           }
+                       }
+                   }
+               }
+           }
+       }
+       newuhs(FALSE);
+}
+
+STATIC_PTR
+int
+unfaint()
+{
+       (void) Hear_again();
+       if(u.uhs > FAINTING)
+               u.uhs = FAINTING;
+       stop_occupation();
+       flags.botl = 1;
+       return 0;
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+boolean
+is_fainted()
+{
+       return((boolean)(u.uhs == FAINTED));
+}
+
+void
+reset_faint()  /* call when a faint must be prematurely terminated */
+{
+       if(is_fainted()) nomul(0);
+}
+
+#if 0
+void
+sync_hunger()
+{
+
+       if(is_fainted()) {
+
+               flags.soundok = 0;
+               nomul(-10+(u.uhunger/10));
+               nomovemsg = "You regain consciousness.";
+               afternmv = unfaint;
+       }
+}
+#endif
+
+void
+newuhs(incr)           /* compute and comment on your (new?) hunger status */
+boolean incr;
+{
+       unsigned newhs;
+       static unsigned save_hs;
+       static boolean saved_hs = FALSE;
+       int h = u.uhunger;
+
+       newhs = (h > 1000) ? SATIATED :
+               (h > 150) ? NOT_HUNGRY :
+               (h > 50) ? HUNGRY :
+               (h > 0) ? WEAK : FAINTING;
+
+       /* While you're eating, you may pass from WEAK to HUNGRY to NOT_HUNGRY.
+        * This should not produce the message "you only feel hungry now";
+        * that message should only appear if HUNGRY is an endpoint.  Therefore
+        * we check to see if we're in the middle of eating.  If so, we save
+        * the first hunger status, and at the end of eating we decide what
+        * message to print based on the _entire_ meal, not on each little bit.
+        */
+       /* It is normally possible to check if you are in the middle of a meal
+        * by checking occupation == eatfood, but there is one special case:
+        * start_eating() can call bite() for your first bite before it
+        * sets the occupation.
+        * Anyone who wants to get that case to work _without_ an ugly static
+        * force_save_hs variable, feel free.
+        */
+       /* Note: If you become a certain hunger status in the middle of the
+        * meal, and still have that same status at the end of the meal,
+        * this will incorrectly print the associated message at the end of
+        * the meal instead of the middle.  Such a case is currently
+        * impossible, but could become possible if a message for SATIATED
+        * were added or if HUNGRY and WEAK were separated by a big enough
+        * gap to fit two bites.
+        */
+       if (occupation == eatfood || force_save_hs) {
+               if (!saved_hs) {
+                       save_hs = u.uhs;
+                       saved_hs = TRUE;
+               }
+               u.uhs = newhs;
+               return;
+       } else {
+               if (saved_hs) {
+                       u.uhs = save_hs;
+                       saved_hs = FALSE;
+               }
+       }
+
+       if(newhs == FAINTING) {
+               if(is_fainted()) newhs = FAINTED;
+               if(u.uhs <= WEAK || rn2(20-u.uhunger/10) >= 19) {
+                       if(!is_fainted() && multi >= 0 /* %% */) {
+                               /* stop what you're doing, then faint */
+                               stop_occupation();
+                               You("faint from lack of food.");
+                               flags.soundok = 0;
+                               nomul(-10+(u.uhunger/10));
+                               nomovemsg = "You regain consciousness.";
+                               afternmv = unfaint;
+                               newhs = FAINTED;
+                       }
+               } else
+               if(u.uhunger < -(int)(200 + 20*ACURR(A_CON))) {
+                       u.uhs = STARVED;
+                       flags.botl = 1;
+                       bot();
+                       You("die from starvation.");
+                       killer_format = KILLED_BY;
+                       killer = "starvation";
+                       done(STARVING);
+                       /* if we return, we lifesaved, and that calls newuhs */
+                       return;
+               }
+       }
+
+       if(newhs != u.uhs) {
+               if(newhs >= WEAK && u.uhs < WEAK)
+                       losestr(1);     /* this may kill you -- see below */
+               else if(newhs < WEAK && u.uhs >= WEAK)
+                       losestr(-1);
+               switch(newhs){
+               case HUNGRY:
+                       if (Hallucination) {
+                           You((!incr) ?
+                               "now have a lesser case of the munchies." :
+                               "are getting the munchies.");
+                       } else
+                           You((!incr) ? "only feel hungry now." :
+                                 (u.uhunger < 145) ? "feel hungry." :
+                                  "are beginning to feel hungry.");
+                       if (incr && occupation &&
+                           (occupation != eatfood && occupation != opentin))
+                           stop_occupation();
+                       break;
+               case WEAK:
+                       if (Hallucination)
+                           pline((!incr) ?
+                                 "You still have the munchies." :
+      "The munchies are interfering with your motor capabilities.");
+                       else if (incr &&
+                               (Role_if(PM_WIZARD) || Race_if(PM_ELF) ||
+                                Role_if(PM_VALKYRIE)))
+                           pline("%s needs food, badly!",
+                                 (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ?
+                                 urole.name.m : "Elf");
+                       else
+                           You((!incr) ? "feel weak now." :
+                                 (u.uhunger < 45) ? "feel weak." :
+                                  "are beginning to feel weak.");
+                       if (incr && occupation &&
+                           (occupation != eatfood && occupation != opentin))
+                           stop_occupation();
+                       break;
+               }
+               u.uhs = newhs;
+               flags.botl = 1;
+               bot();
+               if ((Upolyd ? u.mh : u.uhp) < 1) {
+                       You("die from hunger and exhaustion.");
+                       killer_format = KILLED_BY;
+                       killer = "exhaustion";
+                       done(STARVING);
+                       return;
+               }
+       }
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+/* Returns an object representing food.  Object may be either on floor or
+ * in inventory.
+ */
+struct obj *
+floorfood(verb,corpsecheck)    /* get food from floor or pack */
+       const char *verb;
+       int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */
+{
+       register struct obj *otmp;
+       char qbuf[QBUFSZ];
+       char c;
+       boolean feeding = (!strcmp(verb, "eat"));
+
+       /* if we can't touch floor objects then use invent food only */
+       if (!can_reach_floor() ||
+#ifdef STEED
+               (feeding && u.usteed) || /* can't eat off floor while riding */
+#endif
+               ((is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) &&
+                   (Wwalking || is_clinger(youmonst.data) ||
+                       (Flying && !Breathless))))
+           goto skipfloor;
+
+       if (feeding && metallivorous(youmonst.data)) {
+           struct obj *gold;
+           struct trap *ttmp = t_at(u.ux, u.uy);
+
+           if (ttmp && ttmp->tseen && ttmp->ttyp == BEAR_TRAP) {
+               /* If not already stuck in the trap, perhaps there should
+                  be a chance to becoming trapped?  Probably not, because
+                  then the trap would just get eaten on the _next_ turn... */
+               Sprintf(qbuf, "There is a bear trap here (%s); eat it?",
+                       (u.utrap && u.utraptype == TT_BEARTRAP) ?
+                               "holding you" : "armed");
+               if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
+                   u.utrap = u.utraptype = 0;
+                   deltrap(ttmp);
+                   return mksobj(BEARTRAP, TRUE, FALSE);
+               } else if (c == 'q') {
+                   return (struct obj *)0;
+               }
+           }
+
+           if (youmonst.data != &mons[PM_RUST_MONSTER] &&
+               (gold = g_at(u.ux, u.uy)) != 0) {
+               if (gold->quan == 1L)
+                   Sprintf(qbuf, "There is 1 gold piece here; eat it?");
+               else
+                   Sprintf(qbuf, "There are %ld gold pieces here; eat them?",
+                           gold->quan);
+               if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
+                   return gold;
+               } else if (c == 'q') {
+                   return (struct obj *)0;
+               }
+           }
+       }
+
+       /* Is there some food (probably a heavy corpse) here on the ground? */
+       for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) {
+               if(corpsecheck ?
+               (otmp->otyp==CORPSE && (corpsecheck == 1 || tinnable(otmp))) :
+                   feeding ? (otmp->oclass != COIN_CLASS && is_edible(otmp)) :
+                                               otmp->oclass==FOOD_CLASS) {
+                       Sprintf(qbuf, "There %s %s here; %s %s?",
+                               otense(otmp, "are"),
+                               doname(otmp), verb,
+                               (otmp->quan == 1L) ? "it" : "one");
+                       if((c = yn_function(qbuf,ynqchars,'n')) == 'y')
+                               return(otmp);
+                       else if(c == 'q')
+                               return((struct obj *) 0);
+               }
+       }
+
+ skipfloor:
+       /* We cannot use ALL_CLASSES since that causes getobj() to skip its
+        * "ugly checks" and we need to check for inedible items.
+        */
+       otmp = getobj(feeding ? (const char *)allobj :
+                               (const char *)comestibles, verb);
+       if (corpsecheck && otmp)
+           if (otmp->otyp != CORPSE || (corpsecheck == 2 && !tinnable(otmp))) {
+               You_cant("%s that!", verb);
+               return (struct obj *)0;
+           }
+       return otmp;
+}
+
+/* Side effects of vomiting */
+/* added nomul (MRS) - it makes sense, you're too busy being sick! */
+void
+vomit()                /* A good idea from David Neves */
+{
+       make_sick(0L, (char *) 0, TRUE, SICK_VOMITABLE);
+       nomul(-2);
+}
+
+int
+eaten_stat(base, obj)
+register int base;
+register struct obj *obj;
+{
+       long uneaten_amt, full_amount;
+
+       uneaten_amt = (long)obj->oeaten;
+       full_amount = (obj->otyp == CORPSE) ? (long)mons[obj->corpsenm].cnutrit
+                                       : (long)objects[obj->otyp].oc_nutrition;
+       if (uneaten_amt > full_amount) {
+           impossible(
+         "partly eaten food (%ld) more nutritious than untouched food (%ld)",
+                      uneaten_amt, full_amount);
+           uneaten_amt = full_amount;
+       }
+
+       base = (int)(full_amount ? (long)base * uneaten_amt / full_amount : 0L);
+       return (base < 1) ? 1 : base;
+}
+
+/* reduce obj's oeaten field, making sure it never hits or passes 0 */
+void
+consume_oeaten(obj, amt)
+struct obj *obj;
+int amt;
+{
+    /*
+     * This is a hack to try to squelch several long standing mystery
+     * food bugs.  A better solution would be to rewrite the entire
+     * victual handling mechanism from scratch using a less complex
+     * model.  Alternatively, this routine could call done_eating()
+     * or food_disappears() but its callers would need revisions to
+     * cope with victual.piece unexpectedly going away.
+     *
+     * Multi-turn eating operates by setting the food's oeaten field
+     * to its full nutritional value and then running a counter which
+     * independently keeps track of whether there is any food left.
+     * The oeaten field can reach exactly zero on the last turn, and
+     * the object isn't removed from inventory until the next turn
+     * when the "you finish eating" message gets delivered, so the
+     * food would be restored to the status of untouched during that
+     * interval.  This resulted in unexpected encumbrance messages
+     * at the end of a meal (if near enough to a threshold) and would
+     * yield full food if there was an interruption on the critical
+     * turn.  Also, there have been reports over the years of food
+     * becoming massively heavy or producing unlimited satiation;
+     * this would occur if reducing oeaten via subtraction attempted
+     * to drop it below 0 since its unsigned type would produce a
+     * huge positive value instead.  So far, no one has figured out
+     * _why_ that inappropriate subtraction might sometimes happen.
+     */
+
+    if (amt > 0) {
+       /* bit shift to divide the remaining amount of food */
+       obj->oeaten >>= amt;
+    } else {
+       /* simple decrement; value is negative so we actually add it */
+       if ((int) obj->oeaten > -amt)
+           obj->oeaten += amt;
+       else
+           obj->oeaten = 0;
+    }
+
+    if (obj->oeaten == 0) {
+       if (obj == victual.piece)       /* always true unless wishing... */
+           victual.reqtime = victual.usedtime; /* no bites left */
+       obj->oeaten = 1;        /* smallest possible positive value */
+    }
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+/* called when eatfood occupation has been interrupted,
+   or in the case of theft, is about to be interrupted */
+boolean
+maybe_finished_meal(stopping)
+boolean stopping;
+{
+       /* in case consume_oeaten() has decided that the food is all gone */
+       if (occupation == eatfood && victual.usedtime >= victual.reqtime) {
+           if (stopping) occupation = 0;       /* for do_reset_eat */
+           (void) eatfood(); /* calls done_eating() to use up victual.piece */
+           return TRUE;
+       }
+       return FALSE;
+}
+
+#endif /* OVL1 */
+
+/*eat.c*/
diff --git a/src/end.c b/src/end.c
new file mode 100644 (file)
index 0000000..58d47e0
--- /dev/null
+++ b/src/end.c
@@ -0,0 +1,1106 @@
+/*     SCCS Id: @(#)end.c      3.4     2003/03/10      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#define NEED_VARARGS   /* comment line for pre-compiled headers */
+
+#include "hack.h"
+#include "eshk.h"
+#ifndef NO_SIGNAL
+#include <signal.h>
+#endif
+#include "dlb.h"
+
+       /* 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; };
+
+static struct valuable_data
+       gems[LAST_GEM+1 - FIRST_GEM + 1], /* 1 extra for glass */
+       amulets[LAST_AMULET+1 - FIRST_AMULET];
+
+static struct val_list { struct valuable_data *list; int size; } valuables[] = {
+       { gems,    sizeof gems / sizeof *gems },
+       { amulets, sizeof amulets / sizeof *amulets },
+       { 0, 0 }
+};
+
+#ifndef NO_SIGNAL
+STATIC_PTR void FDECL(done_intr, (int));
+# if defined(UNIX) || defined(VMS) || defined (__EMX__)
+static void FDECL(done_hangup, (int));
+# endif
+#endif
+STATIC_DCL void FDECL(disclose,(int,BOOLEAN_P));
+STATIC_DCL void FDECL(get_valuables, (struct obj *));
+STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *,int));
+STATIC_DCL void FDECL(artifact_score, (struct obj *,BOOLEAN_P,winid));
+STATIC_DCL void FDECL(savelife, (int));
+STATIC_DCL void FDECL(list_vanquished, (CHAR_P,BOOLEAN_P));
+STATIC_DCL void FDECL(list_genocided, (CHAR_P,BOOLEAN_P));
+STATIC_DCL boolean FDECL(should_query_disclose_option, (int,char *));
+
+#if defined(__BEOS__) || defined(MICRO) || defined(WIN32) || defined(OS2)
+extern void FDECL(nethack_exit,(int));
+#else
+#define nethack_exit exit
+#endif
+
+#define done_stopprint program_state.stopprint
+
+#ifdef AMIGA
+# define NH_abort()    Abort(0)
+#else
+# ifdef SYSV
+# define NH_abort()    (void) abort()
+# else
+#  ifdef WIN32
+# define NH_abort()    win32_abort()
+#  else
+# define NH_abort()    abort()
+#  endif
+# endif
+#endif
+
+/*
+ * The order of these needs to match the macros in hack.h.
+ */
+static NEARDATA const char *deaths[] = {               /* the array of death */
+       "died", "choked", "poisoned", "starvation", "drowning",
+       "burning", "dissolving under the heat and pressure",
+       "crushed", "turned to stone", "turned into slime",
+       "genocided", "panic", "trickery",
+       "quit", "escaped", "ascended"
+};
+
+static NEARDATA const char *ends[] = {         /* "when you..." */
+       "died", "choked", "were poisoned", "starved", "drowned",
+       "burned", "dissolved in the lava",
+       "were crushed", "turned to stone", "turned into slime",
+       "were genocided", "panicked", "were tricked",
+       "quit", "escaped", "ascended"
+};
+
+extern const char * const killed_by_prefix[];  /* from topten.c */
+
+/*ARGSUSED*/
+void
+done1(sig_unused)   /* called as signal() handler, so sent at least one arg */
+int sig_unused;
+{
+#ifndef NO_SIGNAL
+       (void) signal(SIGINT,SIG_IGN);
+#endif
+       if(flags.ignintr) {
+#ifndef NO_SIGNAL
+               (void) signal(SIGINT, (SIG_RET_TYPE) done1);
+#endif
+               clear_nhwindow(WIN_MESSAGE);
+               curs_on_u();
+               wait_synch();
+               if(multi > 0) nomul(0);
+       } else {
+               (void)done2();
+       }
+}
+
+
+/* "#quit" command or keyboard interrupt */
+int
+done2()
+{
+       if(yn("Really quit?") == 'n') {
+#ifndef NO_SIGNAL
+               (void) signal(SIGINT, (SIG_RET_TYPE) done1);
+#endif
+               clear_nhwindow(WIN_MESSAGE);
+               curs_on_u();
+               wait_synch();
+               if(multi > 0) nomul(0);
+               if(multi == 0) {
+                   u.uinvulnerable = FALSE;    /* avoid ctrl-C bug -dlc */
+                   u.usleep = 0;
+               }
+               return 0;
+       }
+#if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE))
+       if(wizard) {
+           int c;
+# ifdef VMS
+           const char *tmp = "Enter debugger?";
+# else
+#  ifdef LATTICE
+           const char *tmp = "Create SnapShot?";
+#  else
+           const char *tmp = "Dump core?";
+#  endif
+# endif
+           if ((c = ynq(tmp)) == 'y') {
+               (void) signal(SIGINT, (SIG_RET_TYPE) done1);
+               exit_nhwindows((char *)0);
+               NH_abort();
+           } else if (c == 'q') done_stopprint++;
+       }
+#endif
+#ifndef LINT
+       done(QUIT);
+#endif
+       return 0;
+}
+
+#ifndef NO_SIGNAL
+/*ARGSUSED*/
+STATIC_PTR void
+done_intr(sig_unused) /* called as signal() handler, so sent at least one arg */
+int sig_unused;
+{
+       done_stopprint++;
+       (void) signal(SIGINT, SIG_IGN);
+# if defined(UNIX) || defined(VMS)
+       (void) signal(SIGQUIT, SIG_IGN);
+# endif
+       return;
+}
+
+# if defined(UNIX) || defined(VMS) || defined(__EMX__)
+static void
+done_hangup(sig)       /* signal() handler */
+int sig;
+{
+       program_state.done_hup++;
+       (void)signal(SIGHUP, SIG_IGN);
+       done_intr(sig);
+       return;
+}
+# endif
+#endif /* NO_SIGNAL */
+
+void
+done_in_by(mtmp)
+register struct monst *mtmp;
+{
+       char buf[BUFSZ];
+       boolean distorted = (boolean)(Hallucination && canspotmon(mtmp));
+
+       You("die...");
+       mark_synch();   /* flush buffered screen output */
+       buf[0] = '\0';
+       killer_format = KILLED_BY_AN;
+       /* "killed by the high priest of Crom" is okay, "killed by the high
+          priest" alone isn't */
+       if ((mtmp->data->geno & G_UNIQ) != 0 && !(mtmp->data == &mons[PM_HIGH_PRIEST] && !mtmp->ispriest)) {
+           if (!type_is_pname(mtmp->data))
+               Strcat(buf, "the ");
+           killer_format = KILLED_BY;
+       }
+       /* _the_ <invisible> <distorted> ghost of Dudley */
+       if (mtmp->data == &mons[PM_GHOST] && mtmp->mnamelth) {
+               Strcat(buf, "the ");
+               killer_format = KILLED_BY;
+       }
+       if (mtmp->minvis)
+               Strcat(buf, "invisible ");
+       if (distorted)
+               Strcat(buf, "hallucinogen-distorted ");
+
+       if(mtmp->data == &mons[PM_GHOST]) {
+               Strcat(buf, "ghost");
+               if (mtmp->mnamelth) Sprintf(eos(buf), " of %s", NAME(mtmp));
+       } else if(mtmp->isshk) {
+               Sprintf(eos(buf), "%s %s, the shopkeeper",
+                       (mtmp->female ? "Ms." : "Mr."), shkname(mtmp));
+               killer_format = KILLED_BY;
+       } else if (mtmp->ispriest || mtmp->isminion) {
+               /* m_monnam() suppresses "the" prefix plus "invisible", and
+                  it overrides the effect of Hallucination on priestname() */
+               killer = m_monnam(mtmp);
+               Strcat(buf, killer);
+       } else {
+               Strcat(buf, mtmp->data->mname);
+               if (mtmp->mnamelth)
+                   Sprintf(eos(buf), " called %s", NAME(mtmp));
+       }
+
+       if (multi) Strcat(buf, ", while helpless");
+       killer = buf;
+       if (mtmp->data->mlet == S_WRAITH)
+               u.ugrave_arise = PM_WRAITH;
+       else if (mtmp->data->mlet == S_MUMMY && urace.mummynum != NON_PM)
+               u.ugrave_arise = urace.mummynum;
+       else if (mtmp->data->mlet == S_VAMPIRE && Race_if(PM_HUMAN))
+               u.ugrave_arise = PM_VAMPIRE;
+       else if (mtmp->data == &mons[PM_GHOUL])
+               u.ugrave_arise = PM_GHOUL;
+       if (u.ugrave_arise >= LOW_PM &&
+                               (mvitals[u.ugrave_arise].mvflags & G_GENOD))
+               u.ugrave_arise = NON_PM;
+       if (touch_petrifies(mtmp->data))
+               done(STONING);
+       else
+               done(DIED);
+       return;
+}
+
+#if defined(WIN32)
+#define NOTIFY_NETHACK_BUGS
+#endif
+
+/*VARARGS1*/
+void
+panic VA_DECL(const char *, str)
+       VA_START(str);
+       VA_INIT(str, char *);
+
+       if (program_state.panicking++)
+           NH_abort(); /* avoid loops - this should never happen*/
+
+       if (iflags.window_inited) {
+           raw_print("\r\nOops...");
+           wait_synch();       /* make sure all pending output gets flushed */
+           exit_nhwindows((char *)0);
+           iflags.window_inited = 0; /* they're gone; force raw_print()ing */
+       }
+
+       raw_print(program_state.gameover ?
+                 "Postgame wrapup disrupted." :
+                 !program_state.something_worth_saving ?
+                 "Program initialization has failed." :
+                 "Suddenly, the dungeon collapses.");
+#if defined(WIZARD) && !defined(MICRO)
+# if defined(NOTIFY_NETHACK_BUGS)
+       if (!wizard)
+           raw_printf("Report the following error to \"%s\".",
+                       "nethack-bugs@nethack.org");
+       else if (program_state.something_worth_saving)
+           raw_print("\nError save file being written.\n");
+# else
+       if (!wizard)
+           raw_printf("Report error to \"%s\"%s.",
+#  ifdef WIZARD_NAME   /*(KR1ED)*/
+                       WIZARD_NAME,
+#  else
+                       WIZARD,
+#  endif
+                       !program_state.something_worth_saving ? "" :
+                       " and it may be possible to rebuild.");
+# endif
+       if (program_state.something_worth_saving) {
+           set_error_savefile();
+           (void) dosave0();
+       }
+#endif
+       {
+           char buf[BUFSZ];
+           Vsprintf(buf,str,VA_ARGS);
+           raw_print(buf);
+           paniclog("panic", buf);
+       }
+#ifdef WIN32
+       interject(INTERJECT_PANIC);
+#endif
+#if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE) || defined(WIN32))
+       if (wizard)
+           NH_abort(); /* generate core dump */
+#endif
+       VA_END();
+       done(PANICKED);
+}
+
+STATIC_OVL boolean
+should_query_disclose_option(category, defquery)
+int category;
+char *defquery;
+{
+    int idx;
+    char *dop = index(disclosure_options, category);
+
+    if (dop && defquery) {
+       idx = dop - disclosure_options;
+       if (idx < 0 || idx > (NUM_DISCLOSURE_OPTIONS - 1)) {
+           impossible(
+                  "should_query_disclose_option: bad disclosure index %d %c",
+                      idx, category);
+           *defquery = DISCLOSE_PROMPT_DEFAULT_YES;
+           return TRUE;
+       }
+       if (flags.end_disclose[idx] == DISCLOSE_YES_WITHOUT_PROMPT) {
+           *defquery = 'y';
+           return FALSE;
+       } else if (flags.end_disclose[idx] == DISCLOSE_NO_WITHOUT_PROMPT) {
+           *defquery = 'n';
+           return FALSE;
+       } else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_YES) {
+           *defquery = 'y';
+           return TRUE;
+       } else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_NO) {
+           *defquery = 'n';
+           return TRUE;
+       }
+    }
+    if (defquery)
+       impossible("should_query_disclose_option: bad category %c", category);
+    else
+       impossible("should_query_disclose_option: null defquery");
+    return TRUE;
+}
+
+STATIC_OVL void
+disclose(how,taken)
+int how;
+boolean taken;
+{
+       char    c = 0, defquery;
+       char    qbuf[QBUFSZ];
+       boolean ask;
+
+       if (invent) {
+           if(taken)
+               Sprintf(qbuf,"Do you want to see what you had when you %s?",
+                       (how == QUIT) ? "quit" : "died");
+           else
+               Strcpy(qbuf,"Do you want your possessions identified?");
+
+           ask = should_query_disclose_option('i', &defquery);
+           if (!done_stopprint) {
+               c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery;
+               if (c == 'y') {
+                       struct obj *obj;
+
+                       for (obj = invent; obj; obj = obj->nobj) {
+                           makeknown(obj->otyp);
+                           obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
+                       }
+                       (void) display_inventory((char *)0, TRUE);
+                       container_contents(invent, TRUE, TRUE);
+               }
+               if (c == 'q')  done_stopprint++;
+           }
+       }
+
+       ask = should_query_disclose_option('a', &defquery);
+       if (!done_stopprint) {
+           c = ask ? yn_function("Do you want to see your attributes?",
+                                 ynqchars, defquery) : defquery;
+           if (c == 'y')
+               enlightenment(how >= PANICKED ? 1 : 2); /* final */
+           if (c == 'q') done_stopprint++;
+       }
+
+       ask = should_query_disclose_option('v', &defquery);
+       if (!done_stopprint)
+           list_vanquished(defquery, ask);
+
+       ask = should_query_disclose_option('g', &defquery);
+       if (!done_stopprint)
+           list_genocided(defquery, ask);
+
+       ask = should_query_disclose_option('c', &defquery);
+       if (!done_stopprint) {
+           c = ask ? yn_function("Do you want to see your conduct?",
+                                 ynqchars, defquery) : defquery;
+           if (c == 'y')
+               show_conduct(how >= PANICKED ? 1 : 2);
+           if (c == 'q') done_stopprint++;
+       }
+}
+
+/* try to get the player back in a viable state after being killed */
+STATIC_OVL void
+savelife(how)
+int how;
+{
+       u.uswldtim = 0;
+       u.uhp = u.uhpmax;
+       if (u.uhunger < 500) {
+           u.uhunger = 500;
+           newuhs(FALSE);
+       }
+       /* cure impending doom of sickness hero won't have time to fix */
+       if ((Sick & TIMEOUT) == 1) {
+           u.usick_type = 0;
+           Sick = 0;
+       }
+       if (how == CHOKING) init_uhunger();
+       nomovemsg = "You survived that attempt on your life.";
+       flags.move = 0;
+       if(multi > 0) multi = 0; else multi = -1;
+       if(u.utrap && u.utraptype == TT_LAVA) u.utrap = 0;
+       flags.botl = 1;
+       u.ugrave_arise = NON_PM;
+       HUnchanging = 0L;
+       curs_on_u();
+}
+
+/*
+ * Get valuables from the given list.  Revised code: the list always remains
+ * intact.
+ */
+STATIC_OVL void
+get_valuables(list)
+struct obj *list;      /* inventory or container contents */
+{
+    register struct obj *obj;
+    register int i;
+
+    /* find amulets and gems, ignoring all artifacts */
+    for (obj = list; obj; obj = obj->nobj)
+       if (Has_contents(obj)) {
+           get_valuables(obj->cobj);
+       } else if (obj->oartifact) {
+           continue;
+       } else if (obj->oclass == AMULET_CLASS) {
+           i = obj->otyp - FIRST_AMULET;
+           if (!amulets[i].count) {
+               amulets[i].count = obj->quan;
+               amulets[i].typ = obj->otyp;
+           } else amulets[i].count += obj->quan; /* always adds one */
+       } else if (obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE) {
+           i = min(obj->otyp, LAST_GEM + 1) - FIRST_GEM;
+           if (!gems[i].count) {
+               gems[i].count = obj->quan;
+               gems[i].typ = obj->otyp;
+           } else gems[i].count += obj->quan;
+       }
+    return;
+}
+
+/*
+ *  Sort collected valuables, most frequent to least.  We could just
+ *  as easily use qsort, but we don't care about efficiency here.
+ */
+STATIC_OVL void
+sort_valuables(list, size)
+struct valuable_data list[];
+int size;              /* max value is less than 20 */
+{
+    register int i, j;
+    struct valuable_data ltmp;
+
+    /* move greater quantities to the front of the list */
+    for (i = 1; i < size; i++) {
+       if (list[i].count == 0) continue;       /* empty slot */
+       ltmp = list[i]; /* structure copy */
+       for (j = i; j > 0; --j)
+           if (list[j-1].count >= ltmp.count) break;
+           else {
+               list[j] = list[j-1];
+           }
+       list[j] = ltmp;
+    }
+    return;
+}
+
+/* called twice; first to calculate total, then to list relevant items */
+STATIC_OVL void
+artifact_score(list, counting, endwin)
+struct obj *list;
+boolean counting;      /* true => add up points; false => display them */
+winid endwin;
+{
+    char pbuf[BUFSZ];
+    struct obj *otmp;
+    long value, points;
+    short dummy;       /* object type returned by artifact_name() */
+
+    for (otmp = list; otmp; otmp = otmp->nobj) {
+       if (otmp->oartifact ||
+                       otmp->otyp == BELL_OF_OPENING ||
+                       otmp->otyp == SPE_BOOK_OF_THE_DEAD ||
+                       otmp->otyp == CANDELABRUM_OF_INVOCATION) {
+           value = arti_cost(otmp);    /* zorkmid value */
+           points = value * 5 / 2;     /* score value */
+           if (counting) {
+               u.urexp += points;
+           } else {
+               makeknown(otmp->otyp);
+               otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
+               /* assumes artifacts don't have quan > 1 */
+               Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)",
+                       the_unique_obj(otmp) ? "The " : "",
+                       otmp->oartifact ? artifact_name(xname(otmp), &dummy) :
+                               OBJ_NAME(objects[otmp->otyp]),
+                       value, currency(value), points);
+               putstr(endwin, 0, pbuf);
+           }
+       }
+       if (Has_contents(otmp))
+           artifact_score(otmp->cobj, counting, endwin);
+    }
+}
+
+/* Be careful not to call panic from here! */
+void
+done(how)
+int how;
+{
+       boolean taken;
+       char kilbuf[BUFSZ], pbuf[BUFSZ];
+       winid endwin = WIN_ERR;
+       boolean bones_ok, have_windows = iflags.window_inited;
+       struct obj *corpse = (struct obj *)0;
+       long umoney;
+
+       if (how == TRICKED) {
+           if (killer) {
+               paniclog("trickery", killer);
+               killer = 0;
+           }
+#ifdef WIZARD
+           if (wizard) {
+               You("are a very tricky wizard, it seems.");
+               return;
+           }
+#endif
+       }
+
+       /* kilbuf: used to copy killer in case it comes from something like
+        *      xname(), which would otherwise get overwritten when we call
+        *      xname() when listing possessions
+        * pbuf: holds Sprintf'd output for raw_print and putstr
+        */
+       if (how == ASCENDED || (!killer && how == GENOCIDED))
+               killer_format = NO_KILLER_PREFIX;
+       /* Avoid killed by "a" burning or "a" starvation */
+       if (!killer && (how == STARVING || how == BURNING))
+               killer_format = KILLED_BY;
+       Strcpy(kilbuf, (!killer || how >= PANICKED ? deaths[how] : killer));
+       killer = kilbuf;
+
+       if (how < PANICKED) u.umortality++;
+       if (Lifesaved && (how <= GENOCIDED)) {
+               pline("But wait...");
+               makeknown(AMULET_OF_LIFE_SAVING);
+               Your("medallion %s!",
+                     !Blind ? "begins to glow" : "feels warm");
+               if (how == CHOKING) You("vomit ...");
+               You_feel("much better!");
+               pline_The("medallion crumbles to dust!");
+               if (uamul) useup(uamul);
+
+               (void) adjattrib(A_CON, -1, TRUE);
+               if(u.uhpmax <= 0) u.uhpmax = 10;        /* arbitrary */
+               savelife(how);
+               if (how == GENOCIDED)
+                       pline("Unfortunately you are still genocided...");
+               else {
+                       killer = 0;
+                       killer_format = 0;
+                       return;
+               }
+       }
+       if ((
+#ifdef WIZARD
+                       wizard ||
+#endif
+                       discover) && (how <= GENOCIDED)) {
+               if(yn("Die?") == 'y') goto die;
+               pline("OK, so you don't %s.",
+                       (how == CHOKING) ? "choke" : "die");
+               if(u.uhpmax <= 0) u.uhpmax = u.ulevel * 8;      /* arbitrary */
+               savelife(how);
+               killer = 0;
+               killer_format = 0;
+               return;
+       }
+
+    /*
+     * The game is now over...
+     */
+
+die:
+       program_state.gameover = 1;
+       /* in case of a subsequent panic(), there's no point trying to save */
+       program_state.something_worth_saving = 0;
+       /* render vision subsystem inoperative */
+       iflags.vision_inited = 0;
+       /* might have been killed while using a disposable item, so make sure
+          it's gone prior to inventory disclosure and creation of bones data */
+       inven_inuse(TRUE);
+
+       /* Sometimes you die on the first move.  Life's not fair.
+        * On those rare occasions you get hosed immediately, go out
+        * smiling... :-)  -3.
+        */
+       if (moves <= 1 && how < PANICKED)       /* You die... --More-- */
+           pline("Do not pass go.  Do not collect 200 %s.", currency(200L));
+
+       if (have_windows) wait_synch(); /* flush screen output */
+#ifndef NO_SIGNAL
+       (void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
+# if defined(UNIX) || defined(VMS) || defined (__EMX__)
+       (void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
+       (void) signal(SIGHUP, (SIG_RET_TYPE) done_hangup);
+# endif
+#endif /* NO_SIGNAL */
+
+       bones_ok = (how < GENOCIDED) && can_make_bones();
+
+       if (how == TURNED_SLIME)
+           u.ugrave_arise = PM_GREEN_SLIME;
+
+       if (bones_ok && u.ugrave_arise < LOW_PM) {
+           /* corpse gets burnt up too */
+           if (how == BURNING)
+               u.ugrave_arise = (NON_PM - 2);  /* leave no corpse */
+           else if (how == STONING)
+               u.ugrave_arise = (NON_PM - 1);  /* statue instead of corpse */
+           else if (u.ugrave_arise == NON_PM &&
+                    !(mvitals[u.umonnum].mvflags & G_NOCORPSE)) {
+               int mnum = u.umonnum;
+
+               if (!Upolyd) {
+                   /* Base corpse on race when not poly'd since original
+                    * u.umonnum is based on role, and all role monsters
+                    * are human.
+                    */
+                   mnum = (flags.female && urace.femalenum != NON_PM) ?
+                       urace.femalenum : urace.malenum;
+               }
+               corpse = mk_named_object(CORPSE, &mons[mnum],
+                                      u.ux, u.uy, plname);
+               Sprintf(pbuf, "%s, %s%s", plname,
+                       killer_format == NO_KILLER_PREFIX ? "" :
+                       killed_by_prefix[how],
+                       killer_format == KILLED_BY_AN ? an(killer) : killer);
+               make_grave(u.ux, u.uy, pbuf);
+           }
+       }
+
+       if (how == QUIT) {
+               killer_format = NO_KILLER_PREFIX;
+               if (u.uhp < 1) {
+                       how = DIED;
+                       u.umortality++; /* skipped above when how==QUIT */
+                       /* note that killer is pointing at kilbuf */
+                       Strcpy(kilbuf, "quit while already on Charon's boat");
+               }
+       }
+       if (how == ESCAPED || how == PANICKED)
+               killer_format = NO_KILLER_PREFIX;
+
+       if (how != PANICKED) {
+           /* these affect score and/or bones, but avoid them during panic */
+           taken = paybill((how == ESCAPED) ? -1 : (how != QUIT));
+           paygd();
+           clearpriests();
+       } else  taken = FALSE;  /* lint; assert( !bones_ok ); */
+
+       clearlocks();
+
+       if (have_windows) display_nhwindow(WIN_MESSAGE, FALSE);
+
+       if (strcmp(flags.end_disclose, "none") && how != PANICKED)
+               disclose(how, taken);
+       /* finish_paybill should be called after disclosure but before bones */
+       if (bones_ok && taken) finish_paybill();
+
+       /* calculate score, before creating bones [container gold] */
+       {
+           long tmp;
+           int deepest = deepest_lev_reached(FALSE);
+
+#ifndef GOLDOBJ
+           umoney = u.ugold;
+           tmp = u.ugold0;
+#else
+           umoney = money_cnt(invent);
+           tmp = u.umoney0;
+#endif
+           umoney += hidden_gold();    /* accumulate gold from containers */
+           tmp = umoney - tmp;         /* net gain */
+
+           if (tmp < 0L)
+               tmp = 0L;
+           if (how < PANICKED)
+               tmp -= tmp / 10L;
+           u.urexp += tmp;
+           u.urexp += 50L * (long)(deepest - 1);
+           if (deepest > 20)
+               u.urexp += 1000L * (long)((deepest > 30) ? 10 : deepest - 20);
+           if (how == ASCENDED) u.urexp *= 2L;
+       }
+
+       if (bones_ok) {
+#ifdef WIZARD
+           if (!wizard || yn("Save bones?") == 'y')
+#endif
+               savebones(corpse);
+           /* corpse may be invalid pointer now so
+               ensure that it isn't used again */
+           corpse = (struct obj *)0;
+       }
+
+       /* update gold for the rip output, which can't use hidden_gold()
+          (containers will be gone by then if bones just got saved...) */
+#ifndef GOLDOBJ
+       u.ugold = umoney;
+#else
+       done_money = umoney;
+#endif
+
+       /* clean up unneeded windows */
+       if (have_windows) {
+           wait_synch();
+           display_nhwindow(WIN_MESSAGE, TRUE);
+           destroy_nhwindow(WIN_MAP);
+           destroy_nhwindow(WIN_STATUS);
+           destroy_nhwindow(WIN_MESSAGE);
+           WIN_MESSAGE = WIN_STATUS = WIN_MAP = WIN_ERR;
+
+           if(!done_stopprint || flags.tombstone)
+               endwin = create_nhwindow(NHW_TEXT);
+
+           if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR)
+               outrip(endwin, how);
+       } else
+           done_stopprint = 1; /* just avoid any more output */
+
+/* changing kilbuf really changes killer. we do it this way because
+   killer is declared a (const char *)
+*/
+       if (u.uhave.amulet) Strcat(kilbuf, " (with the Amulet)");
+       else if (how == ESCAPED) {
+           if (Is_astralevel(&u.uz))   /* offered Amulet to wrong deity */
+               Strcat(kilbuf, " (in celestial disgrace)");
+           else if (carrying(FAKE_AMULET_OF_YENDOR))
+               Strcat(kilbuf, " (with a fake Amulet)");
+               /* don't bother counting to see whether it should be plural */
+       }
+
+       if (!done_stopprint) {
+           Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname,
+                  how != ASCENDED ?
+                     (const char *) ((flags.female && urole.name.f) ?
+                        urole.name.f : urole.name.m) :
+                     (const char *) (flags.female ? "Demigoddess" : "Demigod"));
+           putstr(endwin, 0, pbuf);
+           putstr(endwin, 0, "");
+       }
+
+       if (how == ESCAPED || how == ASCENDED) {
+           register struct monst *mtmp;
+           register struct obj *otmp;
+           register struct val_list *val;
+           register int i;
+
+           for (val = valuables; val->list; val++)
+               for (i = 0; i < val->size; i++) {
+                   val->list[i].count = 0L;
+               }
+           get_valuables(invent);
+
+           /* add points for collected valuables */
+           for (val = valuables; val->list; val++)
+               for (i = 0; i < val->size; i++)
+                   if (val->list[i].count != 0L)
+                       u.urexp += val->list[i].count
+                                 * (long)objects[val->list[i].typ].oc_cost;
+
+           /* count the points for artifacts */
+           artifact_score(invent, TRUE, endwin);
+
+           keepdogs(TRUE);
+           viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
+           mtmp = mydogs;
+           if (!done_stopprint) Strcpy(pbuf, "You");
+           if (mtmp) {
+               while (mtmp) {
+                   if (!done_stopprint)
+                       Sprintf(eos(pbuf), " and %s", mon_nam(mtmp));
+                   if (mtmp->mtame)
+                       u.urexp += mtmp->mhp;
+                   mtmp = mtmp->nmon;
+               }
+               if (!done_stopprint) putstr(endwin, 0, pbuf);
+               pbuf[0] = '\0';
+           } else {
+               if (!done_stopprint) Strcat(pbuf, " ");
+           }
+           if (!done_stopprint) {
+               Sprintf(eos(pbuf), "%s with %ld point%s,",
+                       how==ASCENDED ? "went to your reward" :
+                                       "escaped from the dungeon",
+                       u.urexp, plur(u.urexp));
+               putstr(endwin, 0, pbuf);
+           }
+
+           if (!done_stopprint)
+               artifact_score(invent, FALSE, endwin);  /* list artifacts */
+
+           /* list valuables here */
+           for (val = valuables; val->list; val++) {
+               sort_valuables(val->list, val->size);
+               for (i = 0; i < val->size && !done_stopprint; i++) {
+                   int typ = val->list[i].typ;
+                   long count = val->list[i].count;
+
+                   if (count == 0L) continue;
+                   if (objects[typ].oc_class != GEM_CLASS || typ <= LAST_GEM) {
+                       otmp = mksobj(typ, FALSE, FALSE);
+                       makeknown(otmp->otyp);
+                       otmp->known = 1;        /* for fake amulets */
+                       otmp->dknown = 1;       /* seen it (blindness fix) */
+                       otmp->onamelth = 0;
+                       otmp->quan = count;
+                       Sprintf(pbuf, "%8ld %s (worth %ld %s),",
+                               count, xname(otmp),
+                               count * (long)objects[typ].oc_cost, currency(2L));
+                       obfree(otmp, (struct obj *)0);
+                   } else {
+                       Sprintf(pbuf,
+                               "%8ld worthless piece%s of colored glass,",
+                               count, plur(count));
+                   }
+                   putstr(endwin, 0, pbuf);
+               }
+           }
+
+       } else if (!done_stopprint) {
+           /* did not escape or ascend */
+           if (u.uz.dnum == 0 && u.uz.dlevel <= 0) {
+               /* level teleported out of the dungeon; `how' is DIED,
+                  due to falling or to "arriving at heaven prematurely" */
+               Sprintf(pbuf, "You %s beyond the confines of the dungeon",
+                       (u.uz.dlevel < 0) ? "passed away" : ends[how]);
+           } else {
+               /* more conventional demise */
+               const char *where = dungeons[u.uz.dnum].dname;
+
+               if (Is_astralevel(&u.uz)) where = "The Astral Plane";
+               Sprintf(pbuf, "You %s in %s", ends[how], where);
+               if (!In_endgame(&u.uz) && !Is_knox(&u.uz))
+                   Sprintf(eos(pbuf), " on dungeon level %d",
+                           In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
+           }
+
+           Sprintf(eos(pbuf), " with %ld point%s,",
+                   u.urexp, plur(u.urexp));
+           putstr(endwin, 0, pbuf);
+       }
+
+       if (!done_stopprint) {
+           Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.",
+                   umoney, plur(umoney), moves, plur(moves));
+           putstr(endwin, 0, pbuf);
+       }
+       if (!done_stopprint) {
+           Sprintf(pbuf,
+            "You were level %d with a maximum of %d hit point%s when you %s.",
+                   u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
+           putstr(endwin, 0, pbuf);
+           putstr(endwin, 0, "");
+       }
+       if (!done_stopprint)
+           display_nhwindow(endwin, TRUE);
+       if (endwin != WIN_ERR)
+           destroy_nhwindow(endwin);
+
+       /* "So when I die, the first thing I will see in Heaven is a
+        * score list?" */
+       if (flags.toptenwin) {
+           topten(how);
+           if (have_windows)
+               exit_nhwindows((char *)0);
+       } else {
+           if (have_windows)
+               exit_nhwindows((char *)0);
+           topten(how);
+       }
+
+       if(done_stopprint) { raw_print(""); raw_print(""); }
+       terminate(EXIT_SUCCESS);
+}
+
+
+void
+container_contents(list, identified, all_containers)
+struct obj *list;
+boolean identified, all_containers;
+{
+       register struct obj *box, *obj;
+       char buf[BUFSZ];
+
+       for (box = list; box; box = box->nobj) {
+           if (Is_container(box) || box->otyp == STATUE) {
+               if (box->otyp == BAG_OF_TRICKS) {
+                   continue;   /* wrong type of container */
+               } else if (box->cobj) {
+                   winid tmpwin = create_nhwindow(NHW_MENU);
+                   Sprintf(buf, "Contents of %s:", the(xname(box)));
+                   putstr(tmpwin, 0, buf);
+                   putstr(tmpwin, 0, "");
+                   for (obj = box->cobj; obj; obj = obj->nobj) {
+                       if (identified) {
+                           makeknown(obj->otyp);
+                           obj->known = obj->bknown =
+                           obj->dknown = obj->rknown = 1;
+                       }
+                       putstr(tmpwin, 0, doname(obj));
+                   }
+                   display_nhwindow(tmpwin, TRUE);
+                   destroy_nhwindow(tmpwin);
+                   if (all_containers)
+                       container_contents(box->cobj, identified, TRUE);
+               } else {
+                   pline("%s empty.", Tobjnam(box, "are"));
+                   display_nhwindow(WIN_MESSAGE, FALSE);
+               }
+           }
+           if (!all_containers)
+               break;
+       }
+}
+
+
+/* should be called with either EXIT_SUCCESS or EXIT_FAILURE */
+void
+terminate(status)
+int status;
+{
+#ifdef MAC
+       getreturn("to exit");
+#endif
+       /* don't bother to try to release memory if we're in panic mode, to
+          avoid trouble in case that happens to be due to memory problems */
+       if (!program_state.panicking) {
+           freedynamicdata();
+           dlb_cleanup();
+       }
+
+       nethack_exit(status);
+}
+
+STATIC_OVL void
+list_vanquished(defquery, ask)
+char defquery;
+boolean ask;
+{
+    register int i, lev;
+    int ntypes = 0, max_lev = 0, nkilled;
+    long total_killed = 0L;
+    char c;
+    winid klwin;
+    char buf[BUFSZ];
+
+    /* get totals first */
+    for (i = LOW_PM; i < NUMMONS; i++) {
+       if (mvitals[i].died) ntypes++;
+       total_killed += (long)mvitals[i].died;
+       if (mons[i].mlevel > max_lev) max_lev = mons[i].mlevel;
+    }
+
+    /* vanquished creatures list;
+     * includes all dead monsters, not just those killed by the player
+     */
+    if (ntypes != 0) {
+       c = ask ? yn_function("Do you want an account of creatures vanquished?",
+                             ynqchars, defquery) : defquery;
+       if (c == 'q') done_stopprint++;
+       if (c == 'y') {
+           klwin = create_nhwindow(NHW_MENU);
+           putstr(klwin, 0, "Vanquished creatures:");
+           putstr(klwin, 0, "");
+
+           /* countdown by monster "toughness" */
+           for (lev = max_lev; lev >= 0; lev--)
+             for (i = LOW_PM; i < NUMMONS; i++)
+               if (mons[i].mlevel == lev && (nkilled = mvitals[i].died) > 0) {
+                   if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST) {
+                       Sprintf(buf, "%s%s",
+                               !type_is_pname(&mons[i]) ? "The " : "",
+                               mons[i].mname);
+                       if (nkilled > 1) {
+                           switch (nkilled) {
+                               case 2:  Sprintf(eos(buf)," (twice)");  break;
+                               case 3:  Sprintf(eos(buf)," (thrice)");  break;
+                               default: Sprintf(eos(buf)," (%d time%s)",
+                                                nkilled, plur(nkilled));
+                                        break;
+                           }
+                       }
+                   } else {
+                       /* trolls or undead might have come back,
+                          but we don't keep track of that */
+                       if (nkilled == 1)
+                           Strcpy(buf, an(mons[i].mname));
+                       else
+                           Sprintf(buf, "%d %s",
+                                   nkilled, makeplural(mons[i].mname));
+                   }
+                   putstr(klwin, 0, buf);
+               }
+           /*
+            * if (Hallucination)
+            *     putstr(klwin, 0, "and a partridge in a pear tree");
+            */
+           if (ntypes > 1) {
+               putstr(klwin, 0, "");
+               Sprintf(buf, "%ld creatures vanquished.", total_killed);
+               putstr(klwin, 0, buf);
+           }
+           display_nhwindow(klwin, TRUE);
+           destroy_nhwindow(klwin);
+       }
+    }
+}
+
+/* number of monster species which have been genocided */
+int
+num_genocides()
+{
+    int i, n = 0;
+
+    for (i = LOW_PM; i < NUMMONS; ++i)
+       if (mvitals[i].mvflags & G_GENOD) ++n;
+
+    return n;
+}
+
+STATIC_OVL void
+list_genocided(defquery, ask)
+char defquery;
+boolean ask;
+{
+    register int i;
+    int ngenocided;
+    char c;
+    winid klwin;
+    char buf[BUFSZ];
+
+    ngenocided = num_genocides();
+
+    /* genocided species list */
+    if (ngenocided != 0) {
+       c = ask ? yn_function("Do you want a list of species genocided?",
+                             ynqchars, defquery) : defquery;
+       if (c == 'q') done_stopprint++;
+       if (c == 'y') {
+           klwin = create_nhwindow(NHW_MENU);
+           putstr(klwin, 0, "Genocided species:");
+           putstr(klwin, 0, "");
+
+           for (i = LOW_PM; i < NUMMONS; i++)
+               if (mvitals[i].mvflags & G_GENOD) {
+                   if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST)
+                       Sprintf(buf, "%s%s",
+                               !type_is_pname(&mons[i]) ? "" : "the ",
+                               mons[i].mname);
+                   else
+                       Strcpy(buf, makeplural(mons[i].mname));
+                   putstr(klwin, 0, buf);
+               }
+
+           putstr(klwin, 0, "");
+           Sprintf(buf, "%d species genocided.", ngenocided);
+           putstr(klwin, 0, buf);
+
+           display_nhwindow(klwin, TRUE);
+           destroy_nhwindow(klwin);
+       }
+    }
+}
+
+/*end.c*/
diff --git a/src/engrave.c b/src/engrave.c
new file mode 100644 (file)
index 0000000..fe09b4f
--- /dev/null
@@ -0,0 +1,1259 @@
+/*     SCCS Id: @(#)engrave.c  3.4     2001/11/04      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "lev.h"
+#include <ctype.h>
+
+STATIC_VAR NEARDATA struct engr *head_engr;
+
+#ifdef OVLB
+/* random engravings */
+static const char *random_mesg[] = {
+       "Elbereth",
+       /* trap engravings */
+       "Vlad was here", "ad aerarium",
+       /* take-offs and other famous engravings */
+       "Owlbreath", "Galadriel",
+       "Kilroy was here",
+       "A.S. ->", "<- A.S.", /* Journey to the Center of the Earth */
+       "You won't get it up the steps", /* Adventure */
+       "Lasciate ogni speranza o voi ch'entrate.", /* Inferno */
+       "Well Come", /* Prisoner */
+       "We apologize for the inconvenience.", /* So Long... */
+       "See you next Wednesday", /* Thriller */
+       "notary sojak", /* Smokey Stover */
+       "For a good time call 8?7-5309",
+       "Please don't feed the animals.", /* Various zoos around the world */
+       "Madam, in Eden, I'm Adam.", /* A palindrome */
+       "Two thumbs up!", /* Siskel & Ebert */
+       "Hello, World!", /* The First C Program */
+#ifdef MAIL
+       "You've got mail!", /* AOL */
+#endif
+       "As if!", /* Clueless */
+};
+
+char *
+random_engraving(outbuf)
+char *outbuf;
+{
+       const char *rumor;
+
+       /* a random engraving may come from the "rumors" file,
+          or from the list above */
+       if (!rn2(4) || !(rumor = getrumor(0, outbuf, TRUE)) || !*rumor)
+           Strcpy(outbuf, random_mesg[rn2(SIZE(random_mesg))]);
+
+       wipeout_text(outbuf, (int)(strlen(outbuf) / 4), 0);
+       return outbuf;
+}
+
+/* Partial rubouts for engraving characters. -3. */
+static const struct {
+       char            wipefrom;
+       const char *    wipeto;
+} rubouts[] = {
+       {'A', "^"},     {'B', "Pb["},   {'C', "("},     {'D', "|)["},
+       {'E', "|FL[_"}, {'F', "|-"},    {'G', "C("},    {'H', "|-"},
+       {'I', "|"},     {'K', "|<"},    {'L', "|_"},    {'M', "|"},
+       {'N', "|\\"},   {'O', "C("},    {'P', "F"},     {'Q', "C("},
+       {'R', "PF"},    {'T', "|"},     {'U', "J"},     {'V', "/\\"},
+       {'W', "V/\\"},  {'Z', "/"},
+       {'b', "|"},     {'d', "c|"},    {'e', "c"},     {'g', "c"},
+       {'h', "n"},     {'j', "i"},     {'k', "|"},     {'l', "|"},
+       {'m', "nr"},    {'n', "r"},     {'o', "c"},     {'q', "c"},
+       {'w', "v"},     {'y', "v"},
+       {':', "."},     {';', ","},
+       {'0', "C("},    {'1', "|"},     {'6', "o"},     {'7', "/"},
+       {'8', "3o"}
+};
+
+void
+wipeout_text(engr, cnt, seed)
+char *engr;
+int cnt;
+unsigned seed;         /* for semi-controlled randomization */
+{
+       char *s;
+       int i, j, nxt, use_rubout, lth = (int)strlen(engr);
+
+       if (lth && cnt > 0) {
+           while (cnt--) {
+               /* pick next character */
+               if (!seed) {
+                   /* random */
+                   nxt = rn2(lth);
+                   use_rubout = rn2(4);
+               } else {
+                   /* predictable; caller can reproduce the same sequence by
+                      supplying the same arguments later, or a pseudo-random
+                      sequence by varying any of them */
+                   nxt = seed % lth;
+                   seed *= 31,  seed %= (BUFSZ-1);
+                   use_rubout = seed & 3;
+               }
+               s = &engr[nxt];
+               if (*s == ' ') continue;
+
+               /* rub out unreadable & small punctuation marks */
+               if (index("?.,'`-|_", *s)) {
+                   *s = ' ';
+                   continue;
+               }
+
+               if (!use_rubout)
+                   i = SIZE(rubouts);
+               else
+                   for (i = 0; i < SIZE(rubouts); i++)
+                       if (*s == rubouts[i].wipefrom) {
+                           /*
+                            * Pick one of the substitutes at random.
+                            */
+                           if (!seed)
+                               j = rn2(strlen(rubouts[i].wipeto));
+                           else {
+                               seed *= 31,  seed %= (BUFSZ-1);
+                               j = seed % (strlen(rubouts[i].wipeto));
+                           }
+                           *s = rubouts[i].wipeto[j];
+                           break;
+                       }
+
+               /* didn't pick rubout; use '?' for unreadable character */
+               if (i == SIZE(rubouts)) *s = '?';
+           }
+       }
+
+       /* trim trailing spaces */
+       while (lth && engr[lth-1] == ' ') engr[--lth] = 0;
+}
+
+boolean
+can_reach_floor()
+{
+       return (boolean)(!u.uswallow &&
+#ifdef STEED
+                       /* Restricted/unskilled riders can't reach the floor */
+                       !(u.usteed && P_SKILL(P_RIDING) < P_BASIC) &&
+#endif
+                        (!Levitation ||
+                         Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)));
+}
+#endif /* OVLB */
+#ifdef OVL0
+
+const char *
+surface(x, y)
+register int x, y;
+{
+       register struct rm *lev = &levl[x][y];
+
+       if ((x == u.ux) && (y == u.uy) && u.uswallow &&
+               is_animal(u.ustuck->data))
+           return "maw";
+       else if (IS_AIR(lev->typ) && Is_airlevel(&u.uz))
+           return "air";
+       else if (is_pool(x,y))
+           return (Underwater && !Is_waterlevel(&u.uz)) ? "bottom" : "water";
+       else if (is_ice(x,y))
+           return "ice";
+       else if (is_lava(x,y))
+           return "lava";
+       else if (lev->typ == DRAWBRIDGE_DOWN)
+           return "bridge";
+       else if(IS_ALTAR(levl[x][y].typ))
+           return "altar";
+       else if(IS_GRAVE(levl[x][y].typ))
+           return "headstone";
+       else if(IS_FOUNTAIN(levl[x][y].typ))
+           return "fountain";
+       else if ((IS_ROOM(lev->typ) && !Is_earthlevel(&u.uz)) ||
+                IS_WALL(lev->typ) || IS_DOOR(lev->typ) || lev->typ == SDOOR)
+           return "floor";
+       else
+           return "ground";
+}
+
+const char *
+ceiling(x, y)
+register int x, y;
+{
+       register struct rm *lev = &levl[x][y];
+       const char *what;
+
+       /* other room types will no longer exist when we're interested --
+        * see check_special_room()
+        */
+       if (*in_rooms(x,y,VAULT))
+           what = "vault's ceiling";
+       else if (*in_rooms(x,y,TEMPLE))
+           what = "temple's ceiling";
+       else if (*in_rooms(x,y,SHOPBASE))
+           what = "shop's ceiling";
+       else if (IS_AIR(lev->typ))
+           what = "sky";
+       else if (Underwater)
+           what = "water's surface";
+       else if ((IS_ROOM(lev->typ) && !Is_earthlevel(&u.uz)) ||
+                IS_WALL(lev->typ) || IS_DOOR(lev->typ) || lev->typ == SDOOR)
+           what = "ceiling";
+       else
+           what = "rock above";
+
+       return what;
+}
+
+struct engr *
+engr_at(x, y)
+xchar x, y;
+{
+       register struct engr *ep = head_engr;
+
+       while(ep) {
+               if(x == ep->engr_x && y == ep->engr_y)
+                       return(ep);
+               ep = ep->nxt_engr;
+       }
+       return((struct engr *) 0);
+}
+
+#ifdef ELBERETH
+/* Decide whether a particular string is engraved at a specified
+ * location; a case-insensitive substring match used.
+ * Ignore headstones, in case the player names herself "Elbereth".
+ */
+int
+sengr_at(s, x, y)
+       const char *s;
+       xchar x, y;
+{
+       register struct engr *ep = engr_at(x,y);
+
+       return (ep && ep->engr_type != HEADSTONE &&
+               ep->engr_time <= moves && strstri(ep->engr_txt, s) != 0);
+}
+#endif /* ELBERETH */
+
+#endif /* OVL0 */
+#ifdef OVL2
+
+void
+u_wipe_engr(cnt)
+register int cnt;
+{
+       if (can_reach_floor())
+               wipe_engr_at(u.ux, u.uy, cnt);
+}
+
+#endif /* OVL2 */
+#ifdef OVL1
+
+void
+wipe_engr_at(x,y,cnt)
+register xchar x,y,cnt;
+{
+       register struct engr *ep = engr_at(x,y);
+
+       /* Headstones are indelible */
+       if(ep && ep->engr_type != HEADSTONE){
+           if(ep->engr_type != BURN || is_ice(x,y)) {
+               if(ep->engr_type != DUST && ep->engr_type != ENGR_BLOOD) {
+                       cnt = rn2(1 + 50/(cnt+1)) ? 0 : 1;
+               }
+               wipeout_text(ep->engr_txt, (int)cnt, 0);
+               while(ep->engr_txt[0] == ' ')
+                       ep->engr_txt++;
+               if(!ep->engr_txt[0]) del_engr(ep);
+           }
+       }
+}
+
+#endif /* OVL1 */
+#ifdef OVL2
+
+void
+read_engr_at(x,y)
+register int x,y;
+{
+       register struct engr *ep = engr_at(x,y);
+       register int    sensed = 0;
+       char buf[BUFSZ];
+       
+       /* Sensing an engraving does not require sight,
+        * nor does it necessarily imply comprehension (literacy).
+        */
+       if(ep && ep->engr_txt[0]) {
+           switch(ep->engr_type) {
+           case DUST:
+               if(!Blind) {
+                       sensed = 1;
+                       pline("%s is written here in the %s.", Something,
+                               is_ice(x,y) ? "frost" : "dust");
+               }
+               break;
+           case ENGRAVE:
+           case HEADSTONE:
+               if (!Blind || can_reach_floor()) {
+                       sensed = 1;
+                       pline("%s is engraved here on the %s.",
+                               Something,
+                               surface(x,y));
+               }
+               break;
+           case BURN:
+               if (!Blind || can_reach_floor()) {
+                       sensed = 1;
+                       pline("Some text has been %s into the %s here.",
+                               is_ice(x,y) ? "melted" : "burned",
+                               surface(x,y));
+               }
+               break;
+           case MARK:
+               if(!Blind) {
+                       sensed = 1;
+                       pline("There's some graffiti on the %s here.",
+                               surface(x,y));
+               }
+               break;
+           case ENGR_BLOOD:
+               /* "It's a message!  Scrawled in blood!"
+                * "What's it say?"
+                * "It says... `See you next Wednesday.'" -- Thriller
+                */
+               if(!Blind) {
+                       sensed = 1;
+                       You("see a message scrawled in blood here.");
+               }
+               break;
+           default:
+               impossible("%s is written in a very strange way.",
+                               Something);
+               sensed = 1;
+           }
+           if (sensed) {
+               char *et;
+               unsigned maxelen = BUFSZ - sizeof("You feel the words: \"\". ");
+               if (strlen(ep->engr_txt) > maxelen) {
+                       (void) strncpy(buf,  ep->engr_txt, (int)maxelen);
+                       buf[maxelen] = '\0';
+                       et = buf;
+               } else
+                       et = ep->engr_txt;
+               You("%s: \"%s\".",
+                     (Blind) ? "feel the words" : "read",  et);
+               if(flags.run > 1) nomul(0);
+           }
+       }
+}
+
+#endif /* OVL2 */
+#ifdef OVLB
+
+void
+make_engr_at(x,y,s,e_time,e_type)
+register int x,y;
+register const char *s;
+register long e_time;
+register xchar e_type;
+{
+       register struct engr *ep;
+
+       if ((ep = engr_at(x,y)) != 0)
+           del_engr(ep);
+       ep = newengr(strlen(s) + 1);
+       ep->nxt_engr = head_engr;
+       head_engr = ep;
+       ep->engr_x = x;
+       ep->engr_y = y;
+       ep->engr_txt = (char *)(ep + 1);
+       Strcpy(ep->engr_txt, s);
+       /* engraving Elbereth shows wisdom */
+       if (!in_mklev && !strcmp(s, "Elbereth")) exercise(A_WIS, TRUE);
+       ep->engr_time = e_time;
+       ep->engr_type = e_type > 0 ? e_type : rnd(N_ENGRAVE-1);
+       ep->engr_lth = strlen(s) + 1;
+}
+
+/* delete any engraving at location <x,y> */
+void
+del_engr_at(x, y)
+int x, y;
+{
+       register struct engr *ep = engr_at(x, y);
+
+       if (ep) del_engr(ep);
+}
+
+/*
+ *     freehand - returns true if player has a free hand
+ */
+int
+freehand()
+{
+       return(!uwep || !welded(uwep) ||
+          (!bimanual(uwep) && (!uarms || !uarms->cursed)));
+/*     if ((uwep && bimanual(uwep)) ||
+           (uwep && uarms))
+               return(0);
+       else
+               return(1);*/
+}
+
+static NEARDATA const char styluses[] =
+       { ALL_CLASSES, ALLOW_NONE, TOOL_CLASS, WEAPON_CLASS, WAND_CLASS,
+         GEM_CLASS, RING_CLASS, 0 };
+
+/* Mohs' Hardness Scale:
+ *  1 - Talc            6 - Orthoclase
+ *  2 - Gypsum          7 - Quartz
+ *  3 - Calcite                 8 - Topaz
+ *  4 - Fluorite        9 - Corundum
+ *  5 - Apatite                10 - Diamond
+ *
+ * Since granite is a igneous rock hardness ~ 7, anything >= 8 should
+ * probably be able to scratch the rock.
+ * Devaluation of less hard gems is not easily possible because obj struct
+ * does not contain individual oc_cost currently. 7/91
+ *
+ * steel     - 5-8.5   (usu. weapon)
+ * diamond    - 10                     * jade       -  5-6      (nephrite)
+ * ruby       -  9     (corundum)      * turquoise  -  5-6
+ * sapphire   -  9     (corundum)      * opal       -  5-6
+ * topaz      -  8                     * glass      - ~5.5
+ * emerald    -  7.5-8 (beryl)         * dilithium  -  4-5??
+ * aquamarine -  7.5-8 (beryl)         * iron       -  4-5
+ * garnet     -  7.25  (var. 6.5-8)    * fluorite   -  4
+ * agate      -  7     (quartz)        * brass      -  3-4
+ * amethyst   -  7     (quartz)        * gold       -  2.5-3
+ * jasper     -  7     (quartz)        * silver     -  2.5-3
+ * onyx       -  7     (quartz)        * copper     -  2.5-3
+ * moonstone  -  6     (orthoclase)    * amber      -  2-2.5
+ */
+
+/* return 1 if action took 1 (or more) moves, 0 if error or aborted */
+int
+doengrave()
+{
+       boolean dengr = FALSE;  /* TRUE if we wipe out the current engraving */
+       boolean doblind = FALSE;/* TRUE if engraving blinds the player */
+       boolean doknown = FALSE;/* TRUE if we identify the stylus */
+       boolean eow = FALSE;    /* TRUE if we are overwriting oep */
+       boolean jello = FALSE;  /* TRUE if we are engraving in slime */
+       boolean ptext = TRUE;   /* TRUE if we must prompt for engrave text */
+       boolean teleengr =FALSE;/* TRUE if we move the old engraving */
+       boolean zapwand = FALSE;/* TRUE if we remove a wand charge */
+       xchar type = DUST;      /* Type of engraving made */
+       char buf[BUFSZ];        /* Buffer for final/poly engraving text */
+       char ebuf[BUFSZ];       /* Buffer for initial engraving text */
+       char qbuf[QBUFSZ];      /* Buffer for query text */
+       char post_engr_text[BUFSZ]; /* Text displayed after engraving prompt */
+       const char *everb;      /* Present tense of engraving type */
+       const char *eloc;       /* Where the engraving is (ie dust/floor/...) */
+       char *sp;               /* Place holder for space count of engr text */
+       int len;                /* # of nonspace chars of new engraving text */
+       int maxelen;            /* Max allowable length of engraving text */
+       struct engr *oep = engr_at(u.ux,u.uy);
+                               /* The current engraving */
+       struct obj *otmp;       /* Object selected with which to engrave */
+       char *writer;
+
+       multi = 0;              /* moves consumed */
+       nomovemsg = (char *)0;  /* occupation end message */
+
+       buf[0] = (char)0;
+       ebuf[0] = (char)0;
+       post_engr_text[0] = (char)0;
+       maxelen = BUFSZ - 1;
+       if (is_demon(youmonst.data) || youmonst.data->mlet == S_VAMPIRE)
+           type = ENGR_BLOOD;
+
+       /* Can the adventurer engrave at all? */
+
+       if(u.uswallow) {
+               if (is_animal(u.ustuck->data)) {
+                       pline("What would you write?  \"Jonah was here\"?");
+                       return(0);
+               } else if (is_whirly(u.ustuck->data)) {
+                       You_cant("reach the %s.", surface(u.ux,u.uy));
+                       return(0);
+               } else
+                       jello = TRUE;
+       } else if (is_lava(u.ux, u.uy)) {
+               You_cant("write on the lava!");
+               return(0);
+       } else if (is_pool(u.ux,u.uy) || IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
+               You_cant("write on the water!");
+               return(0);
+       }
+       if(Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)/* in bubble */) {
+               You_cant("write in thin air!");
+               return(0);
+       }
+       if (cantwield(youmonst.data)) {
+               You_cant("even hold anything!");
+               return(0);
+       }
+       if (check_capacity((char *)0)) return (0);
+
+       /* One may write with finger, or weapon, or wand, or..., or...
+        * Edited by GAN 10/20/86 so as not to change weapon wielded.
+        */
+
+       otmp = getobj(styluses, "write with");
+       if(!otmp) return(0);            /* otmp == zeroobj if fingers */
+
+       if (otmp == &zeroobj) writer = makeplural(body_part(FINGER));
+       else writer = xname(otmp);
+
+       /* There's no reason you should be able to write with a wand
+        * while both your hands are tied up.
+        */
+       if (!freehand() && otmp != uwep && !otmp->owornmask) {
+               You("have no free %s to write with!", body_part(HAND));
+               return(0);
+       }
+
+       if (jello) {
+               You("tickle %s with your %s.", mon_nam(u.ustuck), writer);
+               Your("message dissolves...");
+               return(0);
+       }
+       if (otmp->oclass != WAND_CLASS && !can_reach_floor()) {
+               You_cant("reach the %s!", surface(u.ux,u.uy));
+               return(0);
+       }
+       if (IS_ALTAR(levl[u.ux][u.uy].typ)) {
+               You("make a motion towards the altar with your %s.", writer);
+               altar_wrath(u.ux, u.uy);
+               return(0);
+       }
+       if (IS_GRAVE(levl[u.ux][u.uy].typ)) {
+           if (otmp == &zeroobj) { /* using only finger */
+               You("would only make a small smudge on the %s.",
+                       surface(u.ux, u.uy));
+               return(0);
+           } else if (!levl[u.ux][u.uy].disturbed) {
+               You("disturb the undead!");
+               levl[u.ux][u.uy].disturbed = 1;
+               (void) makemon(&mons[PM_GHOUL], u.ux, u.uy, NO_MM_FLAGS);
+               exercise(A_WIS, FALSE);
+               return(1);
+           }
+       }
+
+       /* SPFX for items */
+
+       switch (otmp->oclass) {
+           default:
+           case AMULET_CLASS:
+           case CHAIN_CLASS:
+           case POTION_CLASS:
+           case COIN_CLASS:
+               break;
+
+           case RING_CLASS:
+               /* "diamond" rings and others should work */
+           case GEM_CLASS:
+               /* diamonds & other hard gems should work */
+               if (objects[otmp->otyp].oc_tough) {
+                       type = ENGRAVE;
+                       break;
+               }
+               break;
+
+           case ARMOR_CLASS:
+               if (is_boots(otmp)) {
+                       type = DUST;
+                       break;
+               }
+               /* fall through */
+           /* Objects too large to engrave with */
+           case BALL_CLASS:
+           case ROCK_CLASS:
+               You_cant("engrave with such a large object!");
+               ptext = FALSE;
+               break;
+
+           /* Objects too silly to engrave with */
+           case FOOD_CLASS:
+           case SCROLL_CLASS:
+           case SPBOOK_CLASS:
+               Your("%s would get %s.", xname(otmp),
+                       is_ice(u.ux,u.uy) ? "all frosty" : "too dirty");
+               ptext = FALSE;
+               break;
+
+           case RANDOM_CLASS:  /* This should mean fingers */
+               break;
+
+           /* The charge is removed from the wand before prompting for
+            * the engraving text, because all kinds of setup decisions
+            * and pre-engraving messages are based upon knowing what type
+            * of engraving the wand is going to do.  Also, the player
+            * will have potentially seen "You wrest .." message, and
+            * therefore will know they are using a charge.
+            */
+           case WAND_CLASS:
+               if (zappable(otmp)) {
+                   check_unpaid(otmp);
+                   zapwand = TRUE;
+                   if (Levitation) ptext = FALSE;
+
+                   switch (otmp->otyp) {
+                   /* DUST wands */
+                   default:
+                       break;
+
+                       /* NODIR wands */
+                   case WAN_LIGHT:
+                   case WAN_SECRET_DOOR_DETECTION:
+                   case WAN_CREATE_MONSTER:
+                   case WAN_WISHING:
+                   case WAN_ENLIGHTENMENT:
+                       zapnodir(otmp);
+                       break;
+
+                       /* IMMEDIATE wands */
+                       /* If wand is "IMMEDIATE", remember to affect the
+                        * previous engraving even if turning to dust.
+                        */
+                   case WAN_STRIKING:
+                       Strcpy(post_engr_text,
+                       "The wand unsuccessfully fights your attempt to write!"
+                       );
+                       break;
+                   case WAN_SLOW_MONSTER:
+                       if (!Blind) {
+                          Sprintf(post_engr_text,
+                                  "The bugs on the %s slow down!",
+                                  surface(u.ux, u.uy));
+                       }
+                       break;
+                   case WAN_SPEED_MONSTER:
+                       if (!Blind) {
+                          Sprintf(post_engr_text,
+                                  "The bugs on the %s speed up!",
+                                  surface(u.ux, u.uy));
+                       }
+                       break;
+                   case WAN_POLYMORPH:
+                       if(oep)  {
+                           if (!Blind) {
+                               type = (xchar)0;        /* random */
+                               (void) random_engraving(buf);
+                           }
+                           dengr = TRUE;
+                       }
+                       break;
+                   case WAN_NOTHING:
+                   case WAN_UNDEAD_TURNING:
+                   case WAN_OPENING:
+                   case WAN_LOCKING:
+                   case WAN_PROBING:
+                       break;
+
+                       /* RAY wands */
+                   case WAN_MAGIC_MISSILE:
+                       ptext = TRUE;
+                       if (!Blind) {
+                          Sprintf(post_engr_text,
+                                  "The %s is riddled by bullet holes!",
+                                  surface(u.ux, u.uy));
+                       }
+                       break;
+
+                   /* can't tell sleep from death - Eric Backus */
+                   case WAN_SLEEP:
+                   case WAN_DEATH:
+                       if (!Blind) {
+                          Sprintf(post_engr_text,
+                                  "The bugs on the %s stop moving!",
+                                  surface(u.ux, u.uy));
+                       }
+                       break;
+
+                   case WAN_COLD:
+                       if (!Blind)
+                           Strcpy(post_engr_text,
+                               "A few ice cubes drop from the wand.");
+                       if(!oep || (oep->engr_type != BURN))
+                           break;
+                   case WAN_CANCELLATION:
+                   case WAN_MAKE_INVISIBLE:
+                       if (oep && oep->engr_type != HEADSTONE) {
+                           if (!Blind)
+                               pline_The("engraving on the %s vanishes!",
+                                       surface(u.ux,u.uy));
+                           dengr = TRUE;
+                       }
+                       break;
+                   case WAN_TELEPORTATION:
+                       if (oep && oep->engr_type != HEADSTONE) {
+                           if (!Blind)
+                               pline_The("engraving on the %s vanishes!",
+                                       surface(u.ux,u.uy));
+                           teleengr = TRUE;
+                       }
+                       break;
+
+                   /* type = ENGRAVE wands */
+                   case WAN_DIGGING:
+                       ptext = TRUE;
+                       type  = ENGRAVE;
+                       if(!objects[otmp->otyp].oc_name_known) {
+                           if (flags.verbose)
+                               pline("This %s is a wand of digging!",
+                               xname(otmp));
+                           doknown = TRUE;
+                       }
+                       if (!Blind)
+                           Strcpy(post_engr_text,
+                               IS_GRAVE(levl[u.ux][u.uy].typ) ?
+                               "Chips fly out from the headstone." :
+                               is_ice(u.ux,u.uy) ?
+                               "Ice chips fly up from the ice surface!" :
+                               "Gravel flies up from the floor.");
+                       else
+                           Strcpy(post_engr_text, "You hear drilling!");
+                       break;
+
+                   /* type = BURN wands */
+                   case WAN_FIRE:
+                       ptext = TRUE;
+                       type  = BURN;
+                       if(!objects[otmp->otyp].oc_name_known) {
+                       if (flags.verbose)
+                           pline("This %s is a wand of fire!", xname(otmp));
+                           doknown = TRUE;
+                       }
+                       Strcpy(post_engr_text,
+                               Blind ? "You feel the wand heat up." :
+                                       "Flames fly from the wand.");
+                       break;
+                   case WAN_LIGHTNING:
+                       ptext = TRUE;
+                       type  = BURN;
+                       if(!objects[otmp->otyp].oc_name_known) {
+                           if (flags.verbose)
+                               pline("This %s is a wand of lightning!",
+                                       xname(otmp));
+                           doknown = TRUE;
+                       }
+                       if (!Blind) {
+                           Strcpy(post_engr_text,
+                                   "Lightning arcs from the wand.");
+                           doblind = TRUE;
+                       } else
+                           Strcpy(post_engr_text, "You hear crackling!");
+                       break;
+
+                   /* type = MARK wands */
+                   /* type = ENGR_BLOOD wands */
+                   }
+               } else /* end if zappable */
+                   if (!can_reach_floor()) {
+                       You_cant("reach the %s!", surface(u.ux,u.uy));
+                       return(0);
+                   }
+               break;
+
+           case WEAPON_CLASS:
+               if (is_blade(otmp)) {
+                   if ((int)otmp->spe > -3)
+                       type = ENGRAVE;
+                   else
+                       Your("%s too dull for engraving.", aobjnam(otmp,"are"));
+               }
+               break;
+
+           case TOOL_CLASS:
+               if(otmp == ublindf) {
+                   pline(
+               "That is a bit difficult to engrave with, don't you think?");
+                   return(0);
+               }
+               switch (otmp->otyp)  {
+                   case MAGIC_MARKER:
+                       if (otmp->spe <= 0)
+                           Your("marker has dried out.");
+                       else
+                           type = MARK;
+                       break;
+                   case TOWEL:
+                       /* Can't really engrave with a towel */
+                       ptext = FALSE;
+                       if (oep)
+                           if ((oep->engr_type == DUST ) ||
+                               (oep->engr_type == ENGR_BLOOD) ||
+                               (oep->engr_type == MARK )) {
+                               if (!Blind)
+                                   You("wipe out the message here.");
+                               else
+                                   Your("%s %s %s.", xname(otmp),
+                                        otense(otmp, "get"),
+                                        is_ice(u.ux,u.uy) ?
+                                        "frosty" : "dusty");
+                               dengr = TRUE;
+                           } else
+                               Your("%s can't wipe out this engraving.",
+                                    xname(otmp));
+                       else
+                           Your("%s %s %s.", xname(otmp), otense(otmp, "get"),
+                                 is_ice(u.ux,u.uy) ? "frosty" : "dusty");
+                       break;
+                   default:
+                       break;
+               }
+               break;
+
+           case VENOM_CLASS:
+#ifdef WIZARD
+               if (wizard) {
+                   pline("Writing a poison pen letter??");
+                   break;
+               }
+#endif
+           case ILLOBJ_CLASS:
+               impossible("You're engraving with an illegal object!");
+               break;
+       }
+
+       if (IS_GRAVE(levl[u.ux][u.uy].typ)) {
+           if (type == ENGRAVE || type == 0)
+               type = HEADSTONE;
+           else {
+               /* ensures the "cannot wipe out" case */
+               type = DUST;
+               dengr = FALSE;
+               teleengr = FALSE;
+               buf[0] = (char)0;
+           }
+       }
+
+       /* End of implement setup */
+
+       /* Identify stylus */
+       if (doknown) {
+           makeknown(otmp->otyp);
+           more_experienced(0,10);
+       }
+
+       if (teleengr) {
+           rloc_engr(oep);
+           oep = (struct engr *)0;
+       }
+
+       if (dengr) {
+           del_engr(oep);
+           oep = (struct engr *)0;
+       }
+
+       /* Something has changed the engraving here */
+       if (*buf) {
+           make_engr_at(u.ux, u.uy, buf, moves, type);
+           pline_The("engraving now reads: \"%s\".", buf);
+           ptext = FALSE;
+       }
+
+       if (zapwand && (otmp->spe < 0)) {
+           pline("%s %sturns to dust.",
+                 The(xname(otmp)), Blind ? "" : "glows violently, then ");
+           if (!IS_GRAVE(levl[u.ux][u.uy].typ))
+               You("are not going to get anywhere trying to write in the %s with your dust.",
+                   is_ice(u.ux,u.uy) ? "frost" : "dust");
+           useup(otmp);
+           ptext = FALSE;
+       }
+
+       if (!ptext) {           /* Early exit for some implements. */
+           if (otmp->oclass == WAND_CLASS && !can_reach_floor())
+               You_cant("reach the %s!", surface(u.ux,u.uy));
+           return(1);
+       }
+
+       /* Special effects should have deleted the current engraving (if
+        * possible) by now.
+        */
+
+       if (oep) {
+           register char c = 'n';
+
+           /* Give player the choice to add to engraving. */
+
+           if (type == HEADSTONE) {
+               /* no choice, only append */
+               c = 'y';
+           } else if ( (type == oep->engr_type) && (!Blind ||
+                (oep->engr_type == BURN) || (oep->engr_type == ENGRAVE)) ) {
+               c = yn_function("Do you want to add to the current engraving?",
+                               ynqchars, 'y');
+               if (c == 'q') {
+                   pline(Never_mind);
+                   return(0);
+               }
+           }
+
+           if (c == 'n' || Blind) {
+
+               if( (oep->engr_type == DUST) || (oep->engr_type == ENGR_BLOOD) ||
+                   (oep->engr_type == MARK) ) {
+                   if (!Blind) {
+                       You("wipe out the message that was %s here.",
+                           ((oep->engr_type == DUST)  ? "written in the dust" :
+                           ((oep->engr_type == ENGR_BLOOD) ? "scrawled in blood"   :
+                                                        "written")));
+                       del_engr(oep);
+                       oep = (struct engr *)0;
+                   } else
+                  /* Don't delete engr until after we *know* we're engraving */
+                       eow = TRUE;
+               } else
+                   if ( (type == DUST) || (type == MARK) || (type == ENGR_BLOOD) ) {
+                       You(
+                        "cannot wipe out the message that is %s the %s here.",
+                        oep->engr_type == BURN ?
+                          (is_ice(u.ux,u.uy) ? "melted into" : "burned into") :
+                          "engraved in", surface(u.ux,u.uy));
+                       return(1);
+                   } else
+                       if ( (type != oep->engr_type) || (c == 'n') ) {
+                           if (!Blind || can_reach_floor())
+                               You("will overwrite the current message.");
+                           eow = TRUE;
+                       }
+           }
+       }
+
+       eloc = surface(u.ux,u.uy);
+       switch(type){
+           default:
+               everb = (oep && !eow ? "add to the weird writing on" :
+                                      "write strangely on");
+               break;
+           case DUST:
+               everb = (oep && !eow ? "add to the writing in" :
+                                      "write in");
+               eloc = is_ice(u.ux,u.uy) ? "frost" : "dust";
+               break;
+           case HEADSTONE:
+               everb = (oep && !eow ? "add to the epitaph on" :
+                                      "engrave on");
+               break;
+           case ENGRAVE:
+               everb = (oep && !eow ? "add to the engraving in" :
+                                      "engrave in");
+               break;
+           case BURN:
+               everb = (oep && !eow ?
+                       ( is_ice(u.ux,u.uy) ? "add to the text melted into" :
+                                             "add to the text burned into") :
+                       ( is_ice(u.ux,u.uy) ? "melt into" : "burn into"));
+               break;
+           case MARK:
+               everb = (oep && !eow ? "add to the graffiti on" :
+                                      "scribble on");
+               break;
+           case ENGR_BLOOD:
+               everb = (oep && !eow ? "add to the scrawl on" :
+                                      "scrawl on");
+               break;
+       }
+
+       /* Tell adventurer what is going on */
+       if (otmp != &zeroobj)
+           You("%s the %s with %s.", everb, eloc, doname(otmp));
+       else
+           You("%s the %s with your %s.", everb, eloc,
+               makeplural(body_part(FINGER)));
+
+       /* Prompt for engraving! */
+       Sprintf(qbuf,"What do you want to %s the %s here?", everb, eloc);
+       getlin(qbuf, ebuf);
+
+       /* Count the actual # of chars engraved not including spaces */
+       len = strlen(ebuf);
+       for (sp = ebuf; *sp; sp++) if (isspace(*sp)) len -= 1;
+
+       if (len == 0 || index(ebuf, '\033')) {
+           if (zapwand) {
+               if (!Blind)
+                   pline("%s, then %s.",
+                         Tobjnam(otmp, "glow"), otense(otmp, "fade"));
+               return(1);
+           } else {
+               pline(Never_mind);
+               return(0);
+           }
+       }
+
+       /* A single `x' is the traditional signature of an illiterate person */
+       if (len != 1 || (!index(ebuf, 'x') && !index(ebuf, 'X')))
+           u.uconduct.literate++;
+
+       /* Mix up engraving if surface or state of mind is unsound.
+          Note: this won't add or remove any spaces. */
+       for (sp = ebuf; *sp; sp++) {
+           if (isspace(*sp)) continue;
+           if (((type == DUST || type == ENGR_BLOOD) && !rn2(25)) ||
+                   (Blind && !rn2(11)) || (Confusion && !rn2(7)) ||
+                   (Stunned && !rn2(4)) || (Hallucination && !rn2(2)))
+               *sp = ' ' + rnd(96 - 2);        /* ASCII '!' thru '~'
+                                                  (excludes ' ' and DEL) */
+       }
+
+       /* Previous engraving is overwritten */
+       if (eow) {
+           del_engr(oep);
+           oep = (struct engr *)0;
+       }
+
+       /* Figure out how long it took to engrave, and if player has
+        * engraved too much.
+        */
+       switch(type){
+           default:
+               multi = -(len/10);
+               if (multi) nomovemsg = "You finish your weird engraving.";
+               break;
+           case DUST:
+               multi = -(len/10);
+               if (multi) nomovemsg = "You finish writing in the dust.";
+               break;
+           case HEADSTONE:
+           case ENGRAVE:
+               multi = -(len/10);
+               if ((otmp->oclass == WEAPON_CLASS) &&
+                   ((otmp->otyp != ATHAME) || otmp->cursed)) {
+                   multi = -len;
+                   maxelen = ((otmp->spe + 3) * 2) + 1;
+                       /* -2 = 3, -1 = 5, 0 = 7, +1 = 9, +2 = 11
+                        * Note: this does not allow a +0 anything (except
+                        *       an athame) to engrave "Elbereth" all at once.
+                        *       However, you could now engrave "Elb", then
+                        *       "ere", then "th".
+                        */
+                   Your("%s dull.", aobjnam(otmp, "get"));
+                   if (otmp->unpaid) {
+                       struct monst *shkp = shop_keeper(*u.ushops);
+                       if (shkp) {
+                           You("damage it, you pay for it!");
+                           bill_dummy_object(otmp);
+                       }
+                   }
+                   if (len > maxelen) {
+                       multi = -maxelen;
+                       otmp->spe = -3;
+                   } else if (len > 1)
+                       otmp->spe -= len >> 1;
+                   else otmp->spe -= 1; /* Prevent infinite engraving */
+               } else
+                   if ( (otmp->oclass == RING_CLASS) ||
+                        (otmp->oclass == GEM_CLASS) )
+                       multi = -len;
+               if (multi) nomovemsg = "You finish engraving.";
+               break;
+           case BURN:
+               multi = -(len/10);
+               if (multi)
+                   nomovemsg = is_ice(u.ux,u.uy) ?
+                       "You finish melting your message into the ice.":
+                       "You finish burning your message into the floor.";
+               break;
+           case MARK:
+               multi = -(len/10);
+               if ((otmp->oclass == TOOL_CLASS) &&
+                   (otmp->otyp == MAGIC_MARKER)) {
+                   maxelen = (otmp->spe) * 2; /* one charge / 2 letters */
+                   if (len > maxelen) {
+                       Your("marker dries out.");
+                       otmp->spe = 0;
+                       multi = -(maxelen/10);
+                   } else
+                       if (len > 1) otmp->spe -= len >> 1;
+                       else otmp->spe -= 1; /* Prevent infinite grafitti */
+               }
+               if (multi) nomovemsg = "You finish defacing the dungeon.";
+               break;
+           case ENGR_BLOOD:
+               multi = -(len/10);
+               if (multi) nomovemsg = "You finish scrawling.";
+               break;
+       }
+
+       /* Chop engraving down to size if necessary */
+       if (len > maxelen) {
+           for (sp = ebuf; (maxelen && *sp); sp++)
+               if (!isspace(*sp)) maxelen--;
+           if (!maxelen && *sp) {
+               *sp = (char)0;
+               if (multi) nomovemsg = "You cannot write any more.";
+               You("only are able to write \"%s\"", ebuf);
+           }
+       }
+
+       /* Add to existing engraving */
+       if (oep) Strcpy(buf, oep->engr_txt);
+
+       (void) strncat(buf, ebuf, (BUFSZ - (int)strlen(buf) - 1));
+
+       make_engr_at(u.ux, u.uy, buf, (moves - multi), type);
+
+       if (post_engr_text[0]) pline(post_engr_text);
+
+       if (doblind && !resists_blnd(&youmonst)) {
+           You("are blinded by the flash!");
+           make_blinded((long)rnd(50),FALSE);
+           if (!Blind) Your(vision_clears);
+       }
+
+       return(1);
+}
+
+void
+save_engravings(fd, mode)
+int fd, mode;
+{
+       register struct engr *ep = head_engr;
+       register struct engr *ep2;
+       unsigned no_more_engr = 0;
+
+       while (ep) {
+           ep2 = ep->nxt_engr;
+           if (ep->engr_lth && ep->engr_txt[0] && perform_bwrite(mode)) {
+               bwrite(fd, (genericptr_t)&(ep->engr_lth), sizeof(ep->engr_lth));
+               bwrite(fd, (genericptr_t)ep, sizeof(struct engr) + ep->engr_lth);
+           }
+           if (release_data(mode))
+               dealloc_engr(ep);
+           ep = ep2;
+       }
+       if (perform_bwrite(mode))
+           bwrite(fd, (genericptr_t)&no_more_engr, sizeof no_more_engr);
+       if (release_data(mode))
+           head_engr = 0;
+}
+
+void
+rest_engravings(fd)
+int fd;
+{
+       register struct engr *ep;
+       unsigned lth;
+
+       head_engr = 0;
+       while(1) {
+               mread(fd, (genericptr_t) &lth, sizeof(unsigned));
+               if(lth == 0) return;
+               ep = newengr(lth);
+               mread(fd, (genericptr_t) ep, sizeof(struct engr) + lth);
+               ep->nxt_engr = head_engr;
+               head_engr = ep;
+               ep->engr_txt = (char *) (ep + 1);       /* Andreas Bormann */
+               /* mark as finished for bones levels -- no problem for
+                * normal levels as the player must have finished engraving
+                * to be able to move again */
+               ep->engr_time = moves;
+       }
+}
+
+void
+del_engr(ep)
+register struct engr *ep;
+{
+       if (ep == head_engr) {
+               head_engr = ep->nxt_engr;
+       } else {
+               register struct engr *ept;
+
+               for (ept = head_engr; ept; ept = ept->nxt_engr)
+                   if (ept->nxt_engr == ep) {
+                       ept->nxt_engr = ep->nxt_engr;
+                       break;
+                   }
+               if (!ept) {
+                   impossible("Error in del_engr?");
+                   return;
+               }
+       }
+       dealloc_engr(ep);
+}
+
+/* randomly relocate an engraving */
+void
+rloc_engr(ep)
+struct engr *ep;
+{
+       int tx, ty, tryct = 200;
+
+       do  {
+           if (--tryct < 0) return;
+           tx = rn1(COLNO-3,2);
+           ty = rn2(ROWNO);
+       } while (engr_at(tx, ty) ||
+               !goodpos(tx, ty, (struct monst *)0, 0));
+
+       ep->engr_x = tx;
+       ep->engr_y = ty;
+}
+
+
+/* Epitaphs for random headstones */
+static const char *epitaphs[] = {
+       "Rest in peace",
+       "R.I.P.",
+       "Rest In Pieces",
+       "Note -- there are NO valuable items in this grave",
+       "1994-1995. The Longest-Lived Hacker Ever",
+       "The Grave of the Unknown Hacker",
+       "We weren't sure who this was, but we buried him here anyway",
+       "Sparky -- he was a very good dog",
+       "Beware of Electric Third Rail",
+       "Made in Taiwan",
+       "Og friend. Og good dude. Og died. Og now food",
+       "Beetlejuice Beetlejuice Beetlejuice",
+       "Look out below!",
+       "Please don't dig me up. I'm perfectly happy down here. -- Resident",
+       "Postman, please note forwarding address: Gehennom, Asmodeus's Fortress, fifth lemure on the left",
+       "Mary had a little lamb/Its fleece was white as snow/When Mary was in trouble/The lamb was first to go",
+       "Be careful, or this could happen to you!",
+       "Soon you'll join this fellow in hell! -- the Wizard of Yendor",
+       "Caution! This grave contains toxic waste",
+       "Sum quod eris",
+       "Here lies an Atheist, all dressed up and no place to go",
+       "Here lies Ezekiel, age 102.  The good die young.",
+       "Here lies my wife: Here let her lie! Now she's at rest and so am I.",
+       "Here lies Johnny Yeast. Pardon me for not rising.",
+       "He always lied while on the earth and now he's lying in it",
+       "I made an ash of myself",
+       "Soon ripe. Soon rotten. Soon gone. But not forgotten.",
+       "Here lies the body of Jonathan Blake. Stepped on the gas instead of the brake.",
+       "Go away!"
+};
+
+/* Create a headstone at the given location.
+ * The caller is responsible for newsym(x, y).
+ */
+void
+make_grave(x, y, str)
+int x, y;
+const char *str;
+{
+       /* Can we put a grave here? */
+       if ((levl[x][y].typ != ROOM && levl[x][y].typ != GRAVE) || t_at(x,y)) return;
+
+       /* Make the grave */
+       levl[x][y].typ = GRAVE;
+
+       /* Engrave the headstone */
+       if (!str) str = epitaphs[rn2(SIZE(epitaphs))];
+       del_engr_at(x, y);
+       make_engr_at(x, y, str, 0L, HEADSTONE);
+       return;
+}
+
+
+#endif /* OVLB */
+
+/*engrave.c*/
diff --git a/src/exper.c b/src/exper.c
new file mode 100644 (file)
index 0000000..649f1c6
--- /dev/null
@@ -0,0 +1,248 @@
+/*     SCCS Id: @(#)exper.c    3.4     2002/11/20      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+STATIC_DCL long FDECL(newuexp, (int));
+STATIC_DCL int FDECL(enermod, (int));
+
+STATIC_OVL long
+newuexp(lev)
+int lev;
+{
+       if (lev < 10) return (10L * (1L << lev));
+       if (lev < 20) return (10000L * (1L << (lev - 10)));
+       return (10000000L * ((long)(lev - 19)));
+}
+
+STATIC_OVL int
+enermod(en)
+int en;
+{
+       switch (Role_switch) {
+       case PM_PRIEST:
+       case PM_WIZARD:
+           return(2 * en);
+       case PM_HEALER:
+       case PM_KNIGHT:
+           return((3 * en) / 2);
+       case PM_BARBARIAN:
+       case PM_VALKYRIE:
+           return((3 * en) / 4);
+       default:
+           return (en);
+       }
+}
+
+int
+experience(mtmp, nk)   /* return # of exp points for mtmp after nk killed */
+       register struct monst *mtmp;
+       register int    nk;
+#if defined(macintosh) && (defined(__SC__) || defined(__MRC__))
+# pragma unused(nk)
+#endif
+{
+       register struct permonst *ptr = mtmp->data;
+       int     i, tmp, tmp2;
+
+       tmp = 1 + mtmp->m_lev * mtmp->m_lev;
+
+/*     For higher ac values, give extra experience */
+       if ((i = find_mac(mtmp)) < 3) tmp += (7 - i) * ((i < 0) ? 2 : 1);
+
+/*     For very fast monsters, give extra experience */
+       if (ptr->mmove > NORMAL_SPEED)
+           tmp += (ptr->mmove > (3*NORMAL_SPEED/2)) ? 5 : 3;
+
+/*     For each "special" attack type give extra experience */
+       for(i = 0; i < NATTK; i++) {
+
+           tmp2 = ptr->mattk[i].aatyp;
+           if(tmp2 > AT_BUTT) {
+
+               if(tmp2 == AT_WEAP) tmp += 5;
+               else if(tmp2 == AT_MAGC) tmp += 10;
+               else tmp += 3;
+           }
+       }
+
+/*     For each "special" damage type give extra experience */
+       for(i = 0; i < NATTK; i++) {
+           tmp2 = ptr->mattk[i].adtyp;
+           if(tmp2 > AD_PHYS && tmp2 < AD_BLND) tmp += 2*mtmp->m_lev;
+           else if((tmp2 == AD_DRLI) || (tmp2 == AD_STON) ||
+                       (tmp2 == AD_SLIM)) tmp += 50;
+           else if(tmp != AD_PHYS) tmp += mtmp->m_lev;
+               /* extra heavy damage bonus */
+           if((int)(ptr->mattk[i].damd * ptr->mattk[i].damn) > 23)
+               tmp += mtmp->m_lev;
+           if (tmp2 == AD_WRAP && ptr->mlet == S_EEL && !Amphibious)
+               tmp += 1000;
+       }
+
+/*     For certain "extra nasty" monsters, give even more */
+       if (extra_nasty(ptr)) tmp += (7 * mtmp->m_lev);
+
+/*     For higher level monsters, an additional bonus is given */
+       if(mtmp->m_lev > 8) tmp += 50;
+
+#ifdef MAIL
+       /* Mail daemons put up no fight. */
+       if(mtmp->data == &mons[PM_MAIL_DAEMON]) tmp = 1;
+#endif
+
+       return(tmp);
+}
+
+void
+more_experienced(exp, rexp)
+       register int exp, rexp;
+{
+       u.uexp += exp;
+       u.urexp += 4*exp + rexp;
+       if(exp
+#ifdef SCORE_ON_BOTL
+          || flags.showscore
+#endif
+          ) flags.botl = 1;
+       if (u.urexp >= (Role_if(PM_WIZARD) ? 1000 : 2000))
+               flags.beginner = 0;
+}
+
+void
+losexp(drainer)                /* e.g., hit by drain life attack */
+const char *drainer;   /* cause of death, if drain should be fatal */
+{
+       register int num;
+
+#ifdef WIZARD
+       /* override life-drain resistance when handling an explicit
+          wizard mode request to reduce level; never fatal though */
+       if (drainer && !strcmp(drainer, "#levelchange"))
+           drainer = 0;
+       else
+#endif
+           if (resists_drli(&youmonst)) return;
+
+       if (u.ulevel > 1) {
+               pline("%s level %d.", Goodbye(), u.ulevel--);
+               /* remove intrinsic abilities */
+               adjabil(u.ulevel + 1, u.ulevel);
+               reset_rndmonst(NON_PM); /* new monster selection */
+       } else {
+               if (drainer) {
+                       killer_format = KILLED_BY;
+                       killer = drainer;
+                       done(DIED);
+               }
+               /* no drainer or lifesaved */
+               u.uexp = 0;
+       }
+       num = newhp();
+       u.uhpmax -= num;
+       if (u.uhpmax < 1) u.uhpmax = 1;
+       u.uhp -= num;
+       if (u.uhp < 1) u.uhp = 1;
+       else if (u.uhp > u.uhpmax) u.uhp = u.uhpmax;
+
+       if (u.ulevel < urole.xlev)
+           num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd,
+                       urole.enadv.lofix + urace.enadv.lofix);
+       else
+           num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd,
+                       urole.enadv.hifix + urace.enadv.hifix);
+       num = enermod(num);             /* M. Stephenson */
+       u.uenmax -= num;
+       if (u.uenmax < 0) u.uenmax = 0;
+       u.uen -= num;
+       if (u.uen < 0) u.uen = 0;
+       else if (u.uen > u.uenmax) u.uen = u.uenmax;
+
+       if (u.uexp > 0)
+               u.uexp = newuexp(u.ulevel) - 1;
+       flags.botl = 1;
+}
+
+/*
+ * Make experience gaining similar to AD&D(tm), whereby you can at most go
+ * up by one level at a time, extra expr possibly helping you along.
+ * After all, how much real experience does one get shooting a wand of death
+ * at a dragon created with a wand of polymorph??
+ */
+void
+newexplevel()
+{
+       if (u.ulevel < MAXULEV && u.uexp >= newuexp(u.ulevel))
+           pluslvl(TRUE);
+}
+
+void
+pluslvl(incr)
+boolean incr;  /* true iff via incremental experience growth */
+{              /*      (false for potion of gain level)      */
+       register int num;
+
+       if (!incr) You_feel("more experienced.");
+       num = newhp();
+       u.uhpmax += num;
+       u.uhp += num;
+       if (Upolyd) {
+           num = rnd(8);
+           u.mhmax += num;
+           u.mh += num;
+       }
+       if (u.ulevel < urole.xlev)
+           num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd,
+                       urole.enadv.lofix + urace.enadv.lofix);
+       else
+           num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd,
+                       urole.enadv.hifix + urace.enadv.hifix);
+       num = enermod(num);     /* M. Stephenson */
+       u.uenmax += num;
+       u.uen += num;
+       if (u.ulevel < MAXULEV) {
+           if (incr) {
+               long tmp = newuexp(u.ulevel + 1);
+               if (u.uexp >= tmp) u.uexp = tmp - 1;
+           } else {
+               u.uexp = newuexp(u.ulevel);
+           }
+           ++u.ulevel;
+           if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel;
+           pline("Welcome to experience level %d.", u.ulevel);
+           adjabil(u.ulevel - 1, u.ulevel);    /* give new intrinsics */
+           reset_rndmonst(NON_PM);             /* new monster selection */
+       }
+       flags.botl = 1;
+}
+
+/* compute a random amount of experience points suitable for the hero's
+   experience level:  base number of points needed to reach the current
+   level plus a random portion of what it takes to get to the next level */
+long
+rndexp(gaining)
+boolean gaining;       /* gaining XP via potion vs setting XP for polyself */
+{
+       long minexp, maxexp, diff, factor, result;
+
+       minexp = (u.ulevel == 1) ? 0L : newuexp(u.ulevel - 1);
+       maxexp = newuexp(u.ulevel);
+       diff = maxexp - minexp,  factor = 1L;
+       /* make sure that `diff' is an argument which rn2() can handle */
+       while (diff >= (long)LARGEST_INT)
+           diff /= 2L,  factor *= 2L;
+       result = minexp + factor * (long)rn2((int)diff);
+       /* 3.4.1:  if already at level 30, add to current experience
+          points rather than to threshold needed to reach the current
+          level; otherwise blessed potions of gain level can result
+          in lowering the experience points instead of raising them */
+       if (u.ulevel == MAXULEV && gaining) {
+           result += (u.uexp - minexp);
+           /* avoid wrapping (over 400 blessed potions needed for that...) */
+           if (result < u.uexp) result = u.uexp;
+       }
+       return result;
+}
+
+/*exper.c*/
diff --git a/src/explode.c b/src/explode.c
new file mode 100644 (file)
index 0000000..8671a2c
--- /dev/null
@@ -0,0 +1,580 @@
+/*     SCCS Id: @(#)explode.c  3.4     2002/11/10      */
+/*     Copyright (C) 1990 by Ken Arromdee */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+#ifdef OVL0
+
+/* Note: Arrays are column first, while the screen is row first */
+static int expl[3][3] = {
+       { S_explode1, S_explode4, S_explode7 },
+       { S_explode2, S_explode5, S_explode8 },
+       { S_explode3, S_explode6, S_explode9 }
+};
+
+/* Note: I had to choose one of three possible kinds of "type" when writing
+ * this function: a wand type (like in zap.c), an adtyp, or an object type.
+ * Wand types get complex because they must be converted to adtyps for
+ * determining such things as fire resistance.  Adtyps get complex in that
+ * they don't supply enough information--was it a player or a monster that
+ * did it, and with a wand, spell, or breath weapon?  Object types share both
+ * these disadvantages....
+ */
+void
+explode(x, y, type, dam, olet, expltype)
+int x, y;
+int type; /* the same as in zap.c */
+int dam;
+char olet;
+int expltype;
+{
+       int i, j, k, damu = dam;
+       boolean starting = 1;
+       boolean visible, any_shield;
+       int uhurt = 0; /* 0=unhurt, 1=items damaged, 2=you and items damaged */
+       const char *str;
+       int idamres, idamnonres;
+       struct monst *mtmp;
+       uchar adtyp;
+       int explmask[3][3];
+               /* 0=normal explosion, 1=do shieldeff, 2=do nothing */
+       boolean shopdamage = FALSE;
+       boolean generic = FALSE;
+
+       if (olet == WAND_CLASS)         /* retributive strike */
+               switch (Role_switch) {
+                       case PM_PRIEST:
+                       case PM_MONK:
+                       case PM_WIZARD: damu /= 5;
+                                 break;
+                       case PM_HEALER:
+                       case PM_KNIGHT: damu /= 2;
+                                 break;
+                       default:  break;
+               }
+
+       if (olet == MON_EXPLODE) {
+           str = killer;
+           killer = 0;         /* set again later as needed */
+           adtyp = AD_PHYS;
+       } else
+       switch (abs(type) % 10) {
+               case 0: str = "magical blast";
+                       adtyp = AD_MAGM;
+                       break;
+               case 1: str =   olet == BURNING_OIL ?   "burning oil" :
+                               olet == SCROLL_CLASS ?  "tower of flame" :
+                                                       "fireball";
+                       adtyp = AD_FIRE;
+                       break;
+               case 2: str = "ball of cold";
+                       adtyp = AD_COLD;
+                       break;
+               case 4: str =  (olet == WAND_CLASS) ? "death field" :
+                                                       "disintegration field";
+                       adtyp = AD_DISN;
+                       break;
+               case 5: str = "ball of lightning";
+                       adtyp = AD_ELEC;
+                       break;
+               case 6: str = "poison gas cloud";
+                       adtyp = AD_DRST;
+                       break;
+               case 7: str = "splash of acid";
+                       adtyp = AD_ACID;
+                       break;
+               default: impossible("explosion base type %d?", type); return;
+       }
+
+       any_shield = visible = FALSE;
+       for (i=0; i<3; i++) for (j=0; j<3; j++) {
+               if (!isok(i+x-1, j+y-1)) {
+                       explmask[i][j] = 2;
+                       continue;
+               } else
+                       explmask[i][j] = 0;
+
+               if (i+x-1 == u.ux && j+y-1 == u.uy) {
+                   switch(adtyp) {
+                       case AD_PHYS:                        
+                               explmask[i][j] = 0;
+                               break;
+                       case AD_MAGM:
+                               explmask[i][j] = !!Antimagic;
+                               break;
+                       case AD_FIRE:
+                               explmask[i][j] = !!Fire_resistance;
+                               break;
+                       case AD_COLD:
+                               explmask[i][j] = !!Cold_resistance;
+                               break;
+                       case AD_DISN:
+                               explmask[i][j] = (olet == WAND_CLASS) ?
+                                               !!(nonliving(youmonst.data) || is_demon(youmonst.data)) :
+                                               !!Disint_resistance;
+                               break;
+                       case AD_ELEC:
+                               explmask[i][j] = !!Shock_resistance;
+                               break;
+                       case AD_DRST:
+                               explmask[i][j] = !!Poison_resistance;
+                               break;
+                       case AD_ACID:
+                               explmask[i][j] = !!Acid_resistance;
+                               break;
+                       default:
+                               impossible("explosion type %d?", adtyp);
+                               break;
+                   }
+               }
+               /* can be both you and mtmp if you're swallowed */
+               mtmp = m_at(i+x-1, j+y-1);
+#ifdef STEED
+               if (!mtmp && i+x-1 == u.ux && j+y-1 == u.uy)
+                       mtmp = u.usteed;
+#endif
+               if (mtmp) {
+                   if (mtmp->mhp < 1) explmask[i][j] = 2;
+                   else switch(adtyp) {
+                       case AD_PHYS:                        
+                               break;
+                       case AD_MAGM:
+                               explmask[i][j] |= resists_magm(mtmp);
+                               break;
+                       case AD_FIRE:
+                               explmask[i][j] |= resists_fire(mtmp);
+                               break;
+                       case AD_COLD:
+                               explmask[i][j] |= resists_cold(mtmp);
+                               break;
+                       case AD_DISN:
+                               explmask[i][j] |= (olet == WAND_CLASS) ?
+                                       (nonliving(mtmp->data) || is_demon(mtmp->data)) :
+                                       resists_disint(mtmp);
+                               break;
+                       case AD_ELEC:
+                               explmask[i][j] |= resists_elec(mtmp);
+                               break;
+                       case AD_DRST:
+                               explmask[i][j] |= resists_poison(mtmp);
+                               break;
+                       case AD_ACID:
+                               explmask[i][j] |= resists_acid(mtmp);
+                               break;
+                       default:
+                               impossible("explosion type %d?", adtyp);
+                               break;
+                   }
+               }
+               if (mtmp && cansee(i+x-1,j+y-1) && !canspotmon(mtmp))
+                   map_invisible(i+x-1, j+y-1);
+               else if (!mtmp && glyph_is_invisible(levl[i+x-1][j+y-1].glyph)) {
+                   unmap_object(i+x-1, j+y-1);
+                   newsym(i+x-1, j+y-1);
+               }
+               if (cansee(i+x-1, j+y-1)) visible = TRUE;
+               if (explmask[i][j] == 1) any_shield = TRUE;
+       }
+
+       if (visible) {
+               /* Start the explosion */
+               for (i=0; i<3; i++) for (j=0; j<3; j++) {
+                       if (explmask[i][j] == 2) continue;
+                       tmp_at(starting ? DISP_BEAM : DISP_CHANGE,
+                               explosion_to_glyph(expltype,expl[i][j]));
+                       tmp_at(i+x-1, j+y-1);
+                       starting = 0;
+               }
+               curs_on_u();    /* will flush screen and output */
+
+               if (any_shield && flags.sparkle) { /* simulate shield effect */
+                   for (k = 0; k < SHIELD_COUNT; k++) {
+                       for (i=0; i<3; i++) for (j=0; j<3; j++) {
+                           if (explmask[i][j] == 1)
+                               /*
+                                * Bypass tmp_at() and send the shield glyphs
+                                * directly to the buffered screen.  tmp_at()
+                                * will clean up the location for us later.
+                                */
+                               show_glyph(i+x-1, j+y-1,
+                                       cmap_to_glyph(shield_static[k]));
+                       }
+                       curs_on_u();    /* will flush screen and output */
+                       delay_output();
+                   }
+
+                   /* Cover last shield glyph with blast symbol. */
+                   for (i=0; i<3; i++) for (j=0; j<3; j++) {
+                       if (explmask[i][j] == 1)
+                           show_glyph(i+x-1,j+y-1,
+                                       explosion_to_glyph(expltype, expl[i][j]));
+                   }
+
+               } else {                /* delay a little bit. */
+                   delay_output();
+                   delay_output();
+               }
+
+               tmp_at(DISP_END, 0); /* clear the explosion */
+       } else {
+           if (olet == MON_EXPLODE) {
+               str = "explosion";
+               generic = TRUE;
+           }
+           if (flags.soundok) You_hear("a blast.");
+       }
+
+    if (dam)
+       for (i=0; i<3; i++) for (j=0; j<3; j++) {
+               if (explmask[i][j] == 2) continue;
+               if (i+x-1 == u.ux && j+y-1 == u.uy)
+                       uhurt = (explmask[i][j] == 1) ? 1 : 2;
+               idamres = idamnonres = 0;
+               if (type >= 0)
+                   (void)zap_over_floor((xchar)(i+x-1), (xchar)(j+y-1),
+                               type, &shopdamage);
+
+               mtmp = m_at(i+x-1, j+y-1);
+#ifdef STEED
+               if (!mtmp && i+x-1 == u.ux && j+y-1 == u.uy)
+                       mtmp = u.usteed;
+#endif
+               if (!mtmp) continue;
+               if (u.uswallow && mtmp == u.ustuck) {
+                       if (is_animal(u.ustuck->data))
+                               pline("%s gets %s!",
+                                     Monnam(u.ustuck),
+                                     (adtyp == AD_FIRE) ? "heartburn" :
+                                     (adtyp == AD_COLD) ? "chilly" :
+                                     (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ?
+                                      "irradiated by pure energy" : "perforated") :
+                                     (adtyp == AD_ELEC) ? "shocked" :
+                                     (adtyp == AD_DRST) ? "poisoned" :
+                                     (adtyp == AD_ACID) ? "an upset stomach" :
+                                      "fried");
+                       else
+                               pline("%s gets slightly %s!",
+                                     Monnam(u.ustuck),
+                                     (adtyp == AD_FIRE) ? "toasted" :
+                                     (adtyp == AD_COLD) ? "chilly" :
+                                     (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ?
+                                      "overwhelmed by pure energy" : "perforated") :
+                                     (adtyp == AD_ELEC) ? "shocked" :
+                                     (adtyp == AD_DRST) ? "intoxicated" :
+                                     (adtyp == AD_ACID) ? "burned" :
+                                      "fried");
+               } else if (cansee(i+x-1, j+y-1)) {
+                   if(mtmp->m_ap_type) seemimic(mtmp);
+                   pline("%s is caught in the %s!", Monnam(mtmp), str);
+               }
+
+               idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp);
+               idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp);
+               idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int) adtyp);
+               idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp);
+               idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp);
+
+               if (explmask[i][j] == 1) {
+                       golemeffects(mtmp, (int) adtyp, dam + idamres);
+                       mtmp->mhp -= idamnonres;
+               } else {
+               /* call resist with 0 and do damage manually so 1) we can
+                * get out the message before doing the damage, and 2) we can
+                * call mondied, not killed, if it's not your blast
+                */
+                       int mdam = dam;
+
+                       if (resist(mtmp, olet, 0, FALSE)) {
+                           if (cansee(i+x-1,j+y-1))
+                               pline("%s resists the %s!", Monnam(mtmp), str);
+                           mdam = dam/2;
+                       }
+                       if (mtmp == u.ustuck)
+                               mdam *= 2;
+                       if (resists_cold(mtmp) && adtyp == AD_FIRE)
+                               mdam *= 2;
+                       else if (resists_fire(mtmp) && adtyp == AD_COLD)
+                               mdam *= 2;
+                       mtmp->mhp -= mdam;
+                       mtmp->mhp -= (idamres + idamnonres);
+               }
+               if (mtmp->mhp <= 0) {
+                       /* KMH -- Don't blame the player for pets killing gas spores */
+                       if (!flags.mon_moving) killed(mtmp);
+                       else monkilled(mtmp, "", (int)adtyp);
+               } else if (!flags.mon_moving) setmangry(mtmp);
+       }
+
+       /* Do your injury last */
+       if (uhurt) {
+               if ((type >= 0 || adtyp == AD_PHYS) &&  /* gas spores */
+                               flags.verbose && olet != SCROLL_CLASS)
+                       You("are caught in the %s!", str);
+               /* do property damage first, in case we end up leaving bones */
+               if (adtyp == AD_FIRE) burn_away_slime();
+               if (Invulnerable) {
+                   damu = 0;
+                   You("are unharmed!");
+               } else if (Half_physical_damage && adtyp == AD_PHYS)
+                   damu = (damu+1) / 2;
+               if (adtyp == AD_FIRE) (void) burnarmor(&youmonst);
+               destroy_item(SCROLL_CLASS, (int) adtyp);
+               destroy_item(SPBOOK_CLASS, (int) adtyp);
+               destroy_item(POTION_CLASS, (int) adtyp);
+               destroy_item(RING_CLASS, (int) adtyp);
+               destroy_item(WAND_CLASS, (int) adtyp);
+
+               ugolemeffects((int) adtyp, damu);
+               if (uhurt == 2) {
+                   if (Upolyd)
+                       u.mh  -= damu;
+                   else
+                       u.uhp -= damu;
+                   flags.botl = 1;
+               }
+
+               if (u.uhp <= 0 || (Upolyd && u.mh <= 0)) {
+                   if (Upolyd) {
+                       rehumanize();
+                   } else {
+                       if (olet == MON_EXPLODE) {
+                           /* killer handled by caller */
+                           if (str != killer_buf && !generic)
+                               Strcpy(killer_buf, str);
+                           killer_format = KILLED_BY_AN;
+                       } else if (type >= 0 && olet != SCROLL_CLASS) {
+                           killer_format = NO_KILLER_PREFIX;
+                           Sprintf(killer_buf, "caught %sself in %s own %s",
+                                   uhim(), uhis(), str);
+                       } else if (!strncmpi(str,"tower of flame", 8) ||
+                                  !strncmpi(str,"fireball", 8)) {
+                           killer_format = KILLED_BY_AN;
+                           Strcpy(killer_buf, str);
+                       } else {
+                           killer_format = KILLED_BY;
+                           Strcpy(killer_buf, str);
+                       }
+                       killer = killer_buf;
+                       /* Known BUG: BURNING suppresses corpse in bones data,
+                          but done does not handle killer reason correctly */
+                       done((adtyp == AD_FIRE) ? BURNING : DIED);
+                   }
+               }
+               exercise(A_STR, FALSE);
+       }
+
+       if (shopdamage) {
+               pay_for_damage(adtyp == AD_FIRE ? "burn away" :
+                              adtyp == AD_COLD ? "shatter" :
+                              adtyp == AD_DISN ? "disintegrate" : "destroy",
+                              FALSE);
+       }
+
+       /* explosions are noisy */
+       i = dam * dam;
+       if (i < 50) i = 50;     /* in case random damage is very small */
+       wake_nearto(x, y, i);
+}
+#endif /* OVL0 */
+#ifdef OVL1
+
+struct scatter_chain {
+       struct scatter_chain *next;     /* pointer to next scatter item */
+       struct obj *obj;                /* pointer to the object        */
+       xchar ox;                       /* location of                  */
+       xchar oy;                       /*      item                    */
+       schar dx;                       /* direction of                 */
+       schar dy;                       /*      travel                  */
+       int range;                      /* range of object              */
+       boolean stopped;                /* flag for in-motion/stopped   */
+};
+
+/*
+ * scflags:
+ *     VIS_EFFECTS     Add visual effects to display
+ *     MAY_HITMON      Objects may hit monsters
+ *     MAY_HITYOU      Objects may hit hero
+ *     MAY_HIT         Objects may hit you or monsters
+ *     MAY_DESTROY     Objects may be destroyed at random
+ *     MAY_FRACTURE    Stone objects can be fractured (statues, boulders)
+ */
+
+/* returns number of scattered objects */
+long
+scatter(sx,sy,blastforce,scflags, obj)
+int sx,sy;                             /* location of objects to scatter */
+int blastforce;                                /* force behind the scattering  */
+unsigned int scflags;
+struct obj *obj;                       /* only scatter this obj        */
+{
+       register struct obj *otmp;
+       register int tmp;
+       int farthest = 0;
+       uchar typ;
+       long qtmp;
+       boolean used_up;
+       boolean individual_object = obj ? TRUE : FALSE;
+       struct monst *mtmp;
+       struct scatter_chain *stmp, *stmp2 = 0;
+       struct scatter_chain *schain = (struct scatter_chain *)0;
+       long total = 0L;
+
+       while ((otmp = individual_object ? obj : level.objects[sx][sy]) != 0) {
+           if (otmp->quan > 1L) {
+               qtmp = otmp->quan - 1;
+               if (qtmp > LARGEST_INT) qtmp = LARGEST_INT;
+               qtmp = (long)rnd((int)qtmp);
+               otmp = splitobj(otmp, qtmp);
+           } else {
+               obj = (struct obj *)0; /* all used */
+           }
+           obj_extract_self(otmp);
+           used_up = FALSE;
+
+           /* 9 in 10 chance of fracturing boulders or statues */
+           if ((scflags & MAY_FRACTURE)
+                       && ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE))
+                       && rn2(10)) {
+               if (otmp->otyp == BOULDER) {
+                   pline("%s apart.", Tobjnam(otmp, "break"));
+                   fracture_rock(otmp);
+                   place_object(otmp, sx, sy);
+                   if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
+                       /* another boulder here, restack it to the top */
+                       obj_extract_self(otmp);
+                       place_object(otmp, sx, sy);
+                   }
+               } else {
+                   struct trap *trap;
+
+                   if ((trap = t_at(sx,sy)) && trap->ttyp == STATUE_TRAP)
+                           deltrap(trap);
+                   pline("%s.", Tobjnam(otmp, "crumble"));
+                   (void) break_statue(otmp);
+                   place_object(otmp, sx, sy); /* put fragments on floor */
+               }
+               used_up = TRUE;
+
+           /* 1 in 10 chance of destruction of obj; glass, egg destruction */
+           } else if ((scflags & MAY_DESTROY) && (!rn2(10)
+                       || (objects[otmp->otyp].oc_material == GLASS
+                       || otmp->otyp == EGG))) {
+               if (breaks(otmp, (xchar)sx, (xchar)sy)) used_up = TRUE;
+           }
+
+           if (!used_up) {
+               stmp = (struct scatter_chain *)
+                                       alloc(sizeof(struct scatter_chain));
+               stmp->next = (struct scatter_chain *)0;
+               stmp->obj = otmp;
+               stmp->ox = sx;
+               stmp->oy = sy;
+               tmp = rn2(8);           /* get the direction */
+               stmp->dx = xdir[tmp];
+               stmp->dy = ydir[tmp];
+               tmp = blastforce - (otmp->owt/40);
+               if (tmp < 1) tmp = 1;
+               stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */
+               if (farthest < stmp->range) farthest = stmp->range;
+               stmp->stopped = FALSE;
+               if (!schain)
+                   schain = stmp;
+               else
+                   stmp2->next = stmp;
+               stmp2 = stmp;
+           }
+       }
+
+       while (farthest-- > 0) {
+               for (stmp = schain; stmp; stmp = stmp->next) {
+                  if ((stmp->range-- > 0) && (!stmp->stopped)) {
+                       bhitpos.x = stmp->ox + stmp->dx;
+                       bhitpos.y = stmp->oy + stmp->dy;
+                       typ = levl[bhitpos.x][bhitpos.y].typ;
+                       if(!isok(bhitpos.x, bhitpos.y)) {
+                               bhitpos.x -= stmp->dx;
+                               bhitpos.y -= stmp->dy;
+                               stmp->stopped = TRUE;
+                       } else if(!ZAP_POS(typ) ||
+                                       closed_door(bhitpos.x, bhitpos.y)) {
+                               bhitpos.x -= stmp->dx;
+                               bhitpos.y -= stmp->dy;
+                               stmp->stopped = TRUE;
+                       } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
+                               if (scflags & MAY_HITMON) {
+                                   stmp->range--;
+                                   if (ohitmon(mtmp, stmp->obj, 1, FALSE)) {
+                                       stmp->obj = (struct obj *)0;
+                                       stmp->stopped = TRUE;
+                                   }
+                               }
+                       } else if (bhitpos.x==u.ux && bhitpos.y==u.uy) {
+                               if (scflags & MAY_HITYOU) {
+                                   int hitvalu, hitu;
+
+                                   if (multi) nomul(0);
+                                   hitvalu = 8 + stmp->obj->spe;
+                                   if (bigmonst(youmonst.data)) hitvalu++;
+                                   hitu = thitu(hitvalu,
+                                                dmgval(stmp->obj, &youmonst),
+                                                stmp->obj, (char *)0);
+                                   if (hitu) {
+                                       stmp->range -= 3;
+                                       stop_occupation();
+                                   }
+                               }
+                       } else {
+                               if (scflags & VIS_EFFECTS) {
+                                   /* tmp_at(bhitpos.x, bhitpos.y); */
+                                   /* delay_output(); */
+                               }
+                       }
+                       stmp->ox = bhitpos.x;
+                       stmp->oy = bhitpos.y;
+                  }
+               }
+       }
+       for (stmp = schain; stmp; stmp = stmp2) {
+               int x,y;
+
+               stmp2 = stmp->next;
+               x = stmp->ox; y = stmp->oy;
+               if (stmp->obj) {
+                       if ( x!=sx || y!=sy )
+                           total += stmp->obj->quan;
+                       place_object(stmp->obj, x, y);
+                       stackobj(stmp->obj);
+               }
+               free((genericptr_t)stmp);
+               newsym(x,y);
+       }
+
+       return total;
+}
+
+
+/*
+ * Splatter burning oil from x,y to the surrounding area.
+ *
+ * This routine should really take a how and direction parameters.
+ * The how is how it was caused, e.g. kicked verses thrown.  The
+ * direction is which way to spread the flaming oil.  Different
+ * "how"s would give different dispersal patterns.  For example,
+ * kicking a burning flask will splatter differently from a thrown
+ * flask hitting the ground.
+ *
+ * For now, just perform a "regular" explosion.
+ */
+void
+splatter_burning_oil(x, y)
+    int x, y;
+{
+/* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */
+#define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */
+    explode(x, y, ZT_SPELL_O_FIRE, d(4,4), BURNING_OIL, EXPL_FIERY);
+}
+
+#endif /* OVL1 */
+
+/*explode.c*/
diff --git a/src/extralev.c b/src/extralev.c
new file mode 100644 (file)
index 0000000..8312402
--- /dev/null
@@ -0,0 +1,346 @@
+/*     SCCS Id: @(#)extralev.c 3.4     2001/09/06      */
+/*     Copyright 1988, 1989 by Ken Arromdee                            */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Support code for "rogue"-style level.
+ */
+
+#include "hack.h"
+
+#ifdef REINCARNATION
+
+struct rogueroom {
+       xchar rlx, rly;
+       xchar dx, dy;
+       boolean real;
+       uchar doortable;
+       int nroom; /* Only meaningful for "real" rooms */
+};
+#define UP 1
+#define DOWN 2
+#define LEFT 4
+#define RIGHT 8
+
+static NEARDATA struct rogueroom r[3][3];
+STATIC_DCL void FDECL(roguejoin,(int,int,int,int,int));
+STATIC_DCL void FDECL(roguecorr,(int,int,int));
+STATIC_DCL void FDECL(miniwalk,(int,int));
+
+STATIC_OVL
+void
+roguejoin(x1,y1,x2,y2, horiz)
+int x1,y1,x2,y2;
+int horiz;
+{
+       register int x,y,middle;
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+       if (horiz) {
+               middle = x1 + rn2(x2-x1+1);
+               for(x=MIN(x1,middle); x<=MAX(x1,middle); x++)
+                       corr(x, y1);
+               for(y=MIN(y1,y2); y<=MAX(y1,y2); y++)
+                       corr(middle,y);
+               for(x=MIN(middle,x2); x<=MAX(middle,x2); x++)
+                       corr(x, y2);
+       } else {
+               middle = y1 + rn2(y2-y1+1);
+               for(y=MIN(y1,middle); y<=MAX(y1,middle); y++)
+                       corr(x1, y);
+               for(x=MIN(x1,x2); x<=MAX(x1,x2); x++)
+                       corr(x, middle);
+               for(y=MIN(middle,y2); y<=MAX(middle,y2); y++)
+                       corr(x2,y);
+       }
+}
+
+STATIC_OVL
+void
+roguecorr(x, y, dir)
+int x,y,dir;
+{
+       register int fromx, fromy, tox, toy;
+
+       if (dir==DOWN) {
+               r[x][y].doortable &= ~DOWN;
+               if (!r[x][y].real) {
+                       fromx = r[x][y].rlx; fromy = r[x][y].rly;
+                       fromx += 1 + 26*x; fromy += 7*y;
+               } else {
+                       fromx = r[x][y].rlx + rn2(r[x][y].dx);
+                       fromy = r[x][y].rly + r[x][y].dy;
+                       fromx += 1 + 26*x; fromy += 7*y;
+                       if (!IS_WALL(levl[fromx][fromy].typ))
+                               impossible("down: no wall at %d,%d?",fromx,
+                                                                       fromy);
+                       dodoor(fromx, fromy, &rooms[r[x][y].nroom]);
+                       levl[fromx][fromy].doormask = D_NODOOR;
+                       fromy++;
+               }
+               if(y >= 2) {
+                       impossible("down door from %d,%d going nowhere?",x,y);
+                       return;
+               }
+               y++;
+               r[x][y].doortable &= ~UP;
+               if (!r[x][y].real) {
+                       tox = r[x][y].rlx; toy = r[x][y].rly;
+                       tox += 1 + 26*x; toy += 7*y;
+               } else {
+                       tox = r[x][y].rlx + rn2(r[x][y].dx);
+                       toy = r[x][y].rly - 1;
+                       tox += 1 + 26*x; toy += 7*y;
+                       if (!IS_WALL(levl[tox][toy].typ))
+                               impossible("up: no wall at %d,%d?",tox,toy);
+                       dodoor(tox, toy, &rooms[r[x][y].nroom]);
+                       levl[tox][toy].doormask = D_NODOOR;
+                       toy--;
+               }
+               roguejoin(fromx, fromy, tox, toy, FALSE);
+               return;
+       } else if (dir == RIGHT) {
+               r[x][y].doortable &= ~RIGHT;
+               if (!r[x][y].real) {
+                       fromx = r[x][y].rlx; fromy = r[x][y].rly;
+                       fromx += 1 + 26*x; fromy += 7*y;
+               } else {
+                       fromx = r[x][y].rlx + r[x][y].dx;
+                       fromy = r[x][y].rly + rn2(r[x][y].dy);
+                       fromx += 1 + 26*x; fromy += 7*y;
+                       if (!IS_WALL(levl[fromx][fromy].typ))
+                               impossible("down: no wall at %d,%d?",fromx,
+                                                                       fromy);
+                       dodoor(fromx, fromy, &rooms[r[x][y].nroom]);
+                       levl[fromx][fromy].doormask = D_NODOOR;
+                       fromx++;
+               }
+               if(x >= 2) {
+                       impossible("right door from %d,%d going nowhere?",x,y);
+                       return;
+               }
+               x++;
+               r[x][y].doortable &= ~LEFT;
+               if (!r[x][y].real) {
+                       tox = r[x][y].rlx; toy = r[x][y].rly;
+                       tox += 1 + 26*x; toy += 7*y;
+               } else {
+                       tox = r[x][y].rlx - 1;
+                       toy = r[x][y].rly + rn2(r[x][y].dy);
+                       tox += 1 + 26*x; toy += 7*y;
+                       if (!IS_WALL(levl[tox][toy].typ))
+                               impossible("left: no wall at %d,%d?",tox,toy);
+                       dodoor(tox, toy, &rooms[r[x][y].nroom]);
+                       levl[tox][toy].doormask = D_NODOOR;
+                       tox--;
+               }
+               roguejoin(fromx, fromy, tox, toy, TRUE);
+               return;
+       } else impossible("corridor in direction %d?",dir);
+}
+
+/* Modified walkfrom() from mkmaze.c */
+STATIC_OVL
+void
+miniwalk(x, y)
+int x,y;
+{
+       register int q, dir;
+       int dirs[4];
+
+       while(1) {
+               q = 0;
+#define doorhere (r[x][y].doortable)
+               if (x>0 && (!(doorhere & LEFT)) &&
+                                       (!r[x-1][y].doortable || !rn2(10)))
+                       dirs[q++] = 0;
+               if (x<2 && (!(doorhere & RIGHT)) &&
+                                       (!r[x+1][y].doortable || !rn2(10)))
+                       dirs[q++] = 1;
+               if (y>0 && (!(doorhere & UP)) &&
+                                       (!r[x][y-1].doortable || !rn2(10)))
+                       dirs[q++] = 2;
+               if (y<2 && (!(doorhere & DOWN)) &&
+                                       (!r[x][y+1].doortable || !rn2(10)))
+                       dirs[q++] = 3;
+       /* Rogue levels aren't just 3 by 3 mazes; they have some extra
+        * connections, thus that 1/10 chance
+        */
+               if (!q) return;
+               dir = dirs[rn2(q)];
+               switch(dir) { /* Move in direction */
+                       case 0: doorhere |= LEFT;
+                               x--;
+                               doorhere |= RIGHT;
+                               break;
+                       case 1: doorhere |= RIGHT;
+                               x++;
+                               doorhere |= LEFT;
+                               break;
+                       case 2: doorhere |= UP;
+                               y--;
+                               doorhere |= DOWN;
+                               break;
+                       case 3: doorhere |= DOWN;
+                               y++;
+                               doorhere |= UP;
+                               break;
+               }
+               miniwalk(x,y);
+       }
+}
+
+void
+makeroguerooms() {
+       register int x,y;
+       /* Rogue levels are structured 3 by 3, with each section containing
+        * a room or an intersection.  The minimum width is 2 each way.
+        * One difference between these and "real" Rogue levels: real Rogue
+        * uses 24 rows and NetHack only 23.  So we cheat a bit by making the
+        * second row of rooms not as deep.
+        *
+        * Each normal space has 6/7 rows and 25 columns in which a room may
+        * actually be placed.  Walls go from rows 0-5/6 and columns 0-24.
+        * Not counting walls, the room may go in
+        * rows 1-5 and columns 1-23 (numbering starting at 0).  A room
+        * coordinate of this type may be converted to a level coordinate
+        * by adding 1+28*x to the column, and 7*y to the row.  (The 1
+        * is because column 0 isn't used [we only use 1-78]).
+        * Room height may be 2-4 (2-5 on last row), length 2-23 (not
+        * counting walls)
+        */
+#define here r[x][y]
+
+       nroom = 0;
+       for(y=0; y<3; y++) for(x=0; x<3; x++) {
+               /* Note: we want to insure at least 1 room.  So, if the
+                * first 8 are all dummies, force the last to be a room.
+                */
+               if (!rn2(5) && (nroom || (x<2 && y<2))) {
+                       /* Arbitrary: dummy rooms may only go where real
+                        * ones do.
+                        */
+                       here.real = FALSE;
+                       here.rlx = rn1(22, 2);
+                       here.rly = rn1((y==2)?4:3, 2);
+               } else {
+                       here.real = TRUE;
+                       here.dx = rn1(22, 2); /* 2-23 long, plus walls */
+                       here.dy = rn1((y==2)?4:3, 2); /* 2-5 high, plus walls */
+
+                       /* boundaries of room floor */
+                       here.rlx = rnd(23 - here.dx + 1);
+                       here.rly = rnd(((y==2) ? 5 : 4)- here.dy + 1);
+                       nroom++;
+               }
+               here.doortable = 0;
+       }
+       miniwalk(rn2(3), rn2(3));
+       nroom = 0;
+       for(y=0; y<3; y++) for(x=0; x<3; x++) {
+               if (here.real) { /* Make a room */
+                       int lowx, lowy, hix, hiy;
+
+                       r[x][y].nroom = nroom;
+                       smeq[nroom] = nroom;
+
+                       lowx = 1 + 26*x + here.rlx;
+                       lowy = 7*y + here.rly;
+                       hix = 1 + 26*x + here.rlx + here.dx - 1;
+                       hiy = 7*y + here.rly + here.dy - 1;
+                       /* Strictly speaking, it should be lit only if above
+                        * level 10, but since Rogue rooms are only
+                        * encountered below level 10, use !rn2(7).
+                        */
+                       add_room(lowx, lowy, hix, hiy,
+                                (boolean) !rn2(7), OROOM, FALSE);
+               }
+       }
+
+       /* Now, add connecting corridors. */
+       for(y=0; y<3; y++) for(x=0; x<3; x++) {
+               if (here.doortable & DOWN)
+                       roguecorr(x, y, DOWN);
+               if (here.doortable & RIGHT)
+                       roguecorr(x, y, RIGHT);
+               if (here.doortable & LEFT)
+                       impossible ("left end of %d, %d never connected?",x,y);
+               if (here.doortable & UP)
+                       impossible ("up end of %d, %d never connected?",x,y);
+       }
+}
+
+void
+corr(x,y)
+int x, y;
+{
+       if (rn2(50)) {
+               levl[x][y].typ = CORR;
+       } else {
+               levl[x][y].typ = SCORR;
+       }
+}
+
+void
+makerogueghost()
+{
+       register struct monst *ghost;
+       struct obj *ghostobj;
+       struct mkroom *croom;
+       int x,y;
+
+       if (!nroom) return; /* Should never happen */
+       croom = &rooms[rn2(nroom)];
+       x = somex(croom); y = somey(croom);
+       if (!(ghost = makemon(&mons[PM_GHOST], x, y, NO_MM_FLAGS)))
+               return;
+       ghost->msleeping = 1;
+       ghost = christen_monst(ghost, roguename());
+
+       if (rn2(4)) {
+               ghostobj = mksobj_at(FOOD_RATION, x, y, FALSE, FALSE);
+               ghostobj->quan = (long) rnd(7);
+               ghostobj->owt = weight(ghostobj);
+       }
+       if (rn2(2)) {
+               ghostobj = mksobj_at(MACE, x, y, FALSE, FALSE);
+               ghostobj->spe = rnd(3);
+               if (rn2(4)) curse(ghostobj);
+       } else {
+               ghostobj = mksobj_at(TWO_HANDED_SWORD, x, y, FALSE, FALSE);
+               ghostobj->spe = rnd(5) - 2;
+               if (rn2(4)) curse(ghostobj);
+       }
+       ghostobj = mksobj_at(BOW, x, y, FALSE, FALSE);
+       ghostobj->spe = 1;
+       if (rn2(4)) curse(ghostobj);
+
+       ghostobj = mksobj_at(ARROW, x, y, FALSE, FALSE);
+       ghostobj->spe = 0;
+       ghostobj->quan = (long) rn1(10,25);
+       ghostobj->owt = weight(ghostobj);
+       if (rn2(4)) curse(ghostobj);
+
+       if (rn2(2)) {
+               ghostobj = mksobj_at(RING_MAIL, x, y, FALSE, FALSE);
+               ghostobj->spe = rn2(3);
+               if (!rn2(3)) ghostobj->oerodeproof = TRUE;
+               if (rn2(4)) curse(ghostobj);
+       } else {
+               ghostobj = mksobj_at(PLATE_MAIL, x, y, FALSE, FALSE);
+               ghostobj->spe = rnd(5) - 2;
+               if (!rn2(3)) ghostobj->oerodeproof = TRUE;
+               if (rn2(4)) curse(ghostobj);
+       }
+       if (rn2(2)) {
+               ghostobj = mksobj_at(FAKE_AMULET_OF_YENDOR, x, y, TRUE, FALSE);
+               ghostobj->known = TRUE;
+       }
+}
+#endif /* REINCARNATION */
+
+/*extralev.c*/
diff --git a/src/files.c b/src/files.c
new file mode 100644 (file)
index 0000000..023546b
--- /dev/null
@@ -0,0 +1,2424 @@
+/*     SCCS Id: @(#)files.c    3.4     2003/11/14      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "dlb.h"
+
+#ifdef TTY_GRAPHICS
+#include "wintty.h" /* more() */
+#endif
+
+#include <ctype.h>
+
+#if !defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C)
+#include <fcntl.h>
+#endif
+
+#include <errno.h>
+#ifdef _MSC_VER        /* MSC 6.0 defines errno quite differently */
+# if (_MSC_VER >= 600)
+#  define SKIP_ERRNO
+# endif
+#else
+# ifdef NHSTDC
+#  define SKIP_ERRNO
+# endif
+#endif
+#ifndef SKIP_ERRNO
+# ifdef _DCC
+const
+# endif
+extern int errno;
+#endif
+
+#if defined(UNIX) && defined(QT_GRAPHICS)
+#include <dirent.h>
+#endif
+
+#if defined(UNIX) || defined(VMS)
+#include <signal.h>
+#endif
+
+#if defined(MSDOS) || defined(OS2) || defined(TOS) || defined(WIN32)
+# ifndef GNUDOS
+#include <sys\stat.h>
+# else
+#include <sys/stat.h>
+# endif
+#endif
+#ifndef O_BINARY       /* used for micros, no-op for others */
+# define O_BINARY 0
+#endif
+
+#ifdef PREFIXES_IN_USE
+#define FQN_NUMBUF 4
+static char fqn_filename_buffer[FQN_NUMBUF][FQN_MAX_FILENAME];
+#endif
+
+#if !defined(MFLOPPY) && !defined(VMS) && !defined(WIN32)
+char bones[] = "bonesnn.xxx";
+char lock[PL_NSIZ+14] = "1lock"; /* long enough for uid+name+.99 */
+#else
+# if defined(MFLOPPY)
+char bones[FILENAME];          /* pathname of bones files */
+char lock[FILENAME];           /* pathname of level files */
+# endif
+# if defined(VMS)
+char bones[] = "bonesnn.xxx;1";
+char lock[PL_NSIZ+17] = "1lock"; /* long enough for _uid+name+.99;1 */
+# endif
+# if defined(WIN32)
+char bones[] = "bonesnn.xxx";
+char lock[PL_NSIZ+25];         /* long enough for username+-+name+.99 */
+# endif
+#endif
+
+#if defined(UNIX) || defined(__BEOS__)
+#define SAVESIZE       (PL_NSIZ + 13)  /* save/99999player.e */
+#else
+# ifdef VMS
+#define SAVESIZE       (PL_NSIZ + 22)  /* [.save]<uid>player.e;1 */
+# else
+#  if defined(WIN32)
+#define SAVESIZE       (PL_NSIZ + 40)  /* username-player.NetHack-saved-game */
+#  else
+#define SAVESIZE       FILENAME        /* from macconf.h or pcconf.h */
+#  endif
+# endif
+#endif
+
+char SAVEF[SAVESIZE];  /* holds relative path of save file from playground */
+#ifdef MICRO
+char SAVEP[SAVESIZE];  /* holds path of directory for save file */
+#endif
+
+#ifdef HOLD_LOCKFILE_OPEN
+struct level_ftrack {
+int init;
+int fd;                                        /* file descriptor for level file     */
+int oflag;                             /* open flags                         */
+boolean nethack_thinks_it_is_open;     /* Does NetHack think it's open?       */
+} lftrack;
+# if defined(WIN32)
+#include <share.h>
+# endif
+#endif /*HOLD_LOCKFILE_OPEN*/
+
+#ifdef WIZARD
+#define WIZKIT_MAX 128
+static char wizkit[WIZKIT_MAX];
+STATIC_DCL FILE *NDECL(fopen_wizkit_file);
+#endif
+
+#ifdef AMIGA
+extern char PATH[];    /* see sys/amiga/amidos.c */
+extern char bbs_id[];
+static int lockptr;
+# ifdef __SASC_60
+#include <proto/dos.h>
+# endif
+
+#include <libraries/dos.h>
+extern void FDECL(amii_set_text_font, ( char *, int ));
+#endif
+
+#if defined(WIN32) || defined(MSDOS)
+static int lockptr;
+# ifdef MSDOS
+#define Delay(a) msleep(a)
+# endif
+#define Close close
+#ifndef WIN_CE
+#define DeleteFile unlink
+#endif
+#endif
+
+#ifdef MAC
+# define unlink macunlink
+#endif
+
+#ifdef USER_SOUNDS
+extern char *sounddir;
+#endif
+
+extern int n_dgns;             /* from dungeon.c */
+
+STATIC_DCL char *FDECL(set_bonesfile_name, (char *,d_level*));
+STATIC_DCL char *NDECL(set_bonestemp_name);
+#ifdef COMPRESS
+STATIC_DCL void FDECL(redirect, (const char *,const char *,FILE *,BOOLEAN_P));
+STATIC_DCL void FDECL(docompress_file, (const char *,BOOLEAN_P));
+#endif
+STATIC_DCL char *FDECL(make_lockname, (const char *,char *));
+STATIC_DCL FILE *FDECL(fopen_config_file, (const char *));
+STATIC_DCL int FDECL(get_uchars, (FILE *,char *,char *,uchar *,BOOLEAN_P,int,const char *));
+int FDECL(parse_config_line, (FILE *,char *,char *,char *));
+#ifdef NOCWD_ASSUMPTIONS
+STATIC_DCL void FDECL(adjust_prefix, (char *, int));
+#endif
+#ifdef SELF_RECOVER
+STATIC_DCL boolean FDECL(copy_bytes, (int, int));
+#endif
+#ifdef HOLD_LOCKFILE_OPEN
+STATIC_DCL int FDECL(open_levelfile_exclusively, (const char *, int, int));
+#endif
+
+/*
+ * fname_encode()
+ *
+ *   Args:
+ *     legal           zero-terminated list of acceptable file name characters
+ *     quotechar       lead-in character used to quote illegal characters as hex digits
+ *     s               string to encode
+ *     callerbuf       buffer to house result
+ *     bufsz           size of callerbuf
+ *
+ *   Notes:
+ *     The hex digits 0-9 and A-F are always part of the legal set due to
+ *     their use in the encoding scheme, even if not explicitly included in 'legal'.
+ *
+ *   Sample:
+ *     The following call:
+ *         (void)fname_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+ *                             '%', "This is a % test!", buf, 512);
+ *     results in this encoding:
+ *         "This%20is%20a%20%25%20test%21"
+ */
+char *
+fname_encode(legal, quotechar, s, callerbuf, bufsz)
+const char *legal;
+char quotechar;
+char *s, *callerbuf;
+int bufsz;
+{
+       char *sp, *op;
+       int cnt = 0;
+       static char hexdigits[] = "0123456789ABCDEF";
+
+       sp = s;
+       op = callerbuf;
+       *op = '\0';
+       
+       while (*sp) {
+               /* Do we have room for one more character or encoding? */
+               if ((bufsz - cnt) <= 4) return callerbuf;
+
+               if (*sp == quotechar) {
+                       (void)sprintf(op, "%c%02X", quotechar, *sp);
+                        op += 3;
+                        cnt += 3;
+               } else if ((index(legal, *sp) != 0) || (index(hexdigits, *sp) != 0)) {
+                       *op++ = *sp;
+                       *op = '\0';
+                       cnt++;
+               } else {
+                       (void)sprintf(op,"%c%02X", quotechar, *sp);
+                       op += 3;
+                       cnt += 3;
+               }
+               sp++;
+       }
+       return callerbuf;
+}
+
+/*
+ * fname_decode()
+ *
+ *   Args:
+ *     quotechar       lead-in character used to quote illegal characters as hex digits
+ *     s               string to decode
+ *     callerbuf       buffer to house result
+ *     bufsz           size of callerbuf
+ */
+char *
+fname_decode(quotechar, s, callerbuf, bufsz)
+char quotechar;
+char *s, *callerbuf;
+int bufsz;
+{
+       char *sp, *op;
+       int k,calc,cnt = 0;
+       static char hexdigits[] = "0123456789ABCDEF";
+
+       sp = s;
+       op = callerbuf;
+       *op = '\0';
+       calc = 0;
+
+       while (*sp) {
+               /* Do we have room for one more character? */
+               if ((bufsz - cnt) <= 2) return callerbuf;
+               if (*sp == quotechar) {
+                       sp++;
+                       for (k=0; k < 16; ++k) if (*sp == hexdigits[k]) break;
+                       if (k >= 16) return callerbuf;  /* impossible, so bail */
+                       calc = k << 4; 
+                       sp++;
+                       for (k=0; k < 16; ++k) if (*sp == hexdigits[k]) break;
+                       if (k >= 16) return callerbuf;  /* impossible, so bail */
+                       calc += k; 
+                       sp++;
+                       *op++ = calc;
+                       *op = '\0';
+               } else {
+                       *op++ = *sp++;
+                       *op = '\0';
+               }
+               cnt++;
+       }
+       return callerbuf;
+}
+
+#ifndef PREFIXES_IN_USE
+/*ARGSUSED*/
+#endif
+const char *
+fqname(basename, whichprefix, buffnum)
+const char *basename;
+int whichprefix, buffnum;
+{
+#ifndef PREFIXES_IN_USE
+       return basename;
+#else
+       if (!basename || whichprefix < 0 || whichprefix >= PREFIX_COUNT)
+               return basename;
+       if (!fqn_prefix[whichprefix])
+               return basename;
+       if (buffnum < 0 || buffnum >= FQN_NUMBUF) {
+               impossible("Invalid fqn_filename_buffer specified: %d",
+                                                               buffnum);
+               buffnum = 0;
+       }
+       if (strlen(fqn_prefix[whichprefix]) + strlen(basename) >=
+                                                   FQN_MAX_FILENAME) {
+               impossible("fqname too long: %s + %s", fqn_prefix[whichprefix],
+                                               basename);
+               return basename;        /* XXX */
+       }
+       Strcpy(fqn_filename_buffer[buffnum], fqn_prefix[whichprefix]);
+       return strcat(fqn_filename_buffer[buffnum], basename);
+#endif
+}
+
+/* reasonbuf must be at least BUFSZ, supplied by caller */
+/*ARGSUSED*/
+int
+validate_prefix_locations(reasonbuf)
+char *reasonbuf;
+{
+#if defined(NOCWD_ASSUMPTIONS)
+       FILE *fp;
+       const char *filename;
+       int prefcnt, failcount = 0;
+       char panicbuf1[BUFSZ], panicbuf2[BUFSZ], *details;
+
+       if (reasonbuf) reasonbuf[0] = '\0';
+       for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++) {
+               /* don't test writing to configdir or datadir; they're readonly */
+               if (prefcnt == CONFIGPREFIX || prefcnt == DATAPREFIX) continue;
+               filename = fqname("validate", prefcnt, 3);
+               if ((fp = fopen(filename, "w"))) {
+                       fclose(fp);
+                       (void) unlink(filename);
+               } else {
+                       if (reasonbuf) {
+                               if (failcount) Strcat(reasonbuf,", ");
+                               Strcat(reasonbuf, fqn_prefix_names[prefcnt]);
+                       }
+                       /* the paniclog entry gets the value of errno as well */
+                       Sprintf(panicbuf1,"Invalid %s", fqn_prefix_names[prefcnt]);
+#if defined (NHSTDC) && !defined(NOTSTDC)
+                       if (!(details = strerror(errno)))
+#endif
+                       details = "";
+                       Sprintf(panicbuf2,"\"%s\", (%d) %s",
+                               fqn_prefix[prefcnt], errno, details);
+                       paniclog(panicbuf1, panicbuf2);
+                       failcount++;
+               }       
+       }
+       if (failcount)
+               return 0;
+       else
+#endif
+       return 1;
+}
+
+/* fopen a file, with OS-dependent bells and whistles */
+/* NOTE: a simpler version of this routine also exists in util/dlb_main.c */
+FILE *
+fopen_datafile(filename, mode, prefix)
+const char *filename, *mode;
+int prefix;
+{
+       FILE *fp;
+
+       filename = fqname(filename, prefix, prefix == TROUBLEPREFIX ? 3 : 0);
+#ifdef VMS     /* essential to have punctuation, to avoid logical names */
+    {
+       char tmp[BUFSIZ];
+
+       if (!index(filename, '.') && !index(filename, ';'))
+               filename = strcat(strcpy(tmp, filename), ";0");
+       fp = fopen(filename, mode, "mbc=16");
+    }
+#else
+       fp = fopen(filename, mode);
+#endif
+       return fp;
+}
+
+/* ----------  BEGIN LEVEL FILE HANDLING ----------- */
+
+#ifdef MFLOPPY
+/* Set names for bones[] and lock[] */
+void
+set_lock_and_bones()
+{
+       if (!ramdisk) {
+               Strcpy(levels, permbones);
+               Strcpy(bones, permbones);
+       }
+       append_slash(permbones);
+       append_slash(levels);
+#ifdef AMIGA
+       strncat(levels, bbs_id, PATHLEN);
+#endif
+       append_slash(bones);
+       Strcat(bones, "bonesnn.*");
+       Strcpy(lock, levels);
+#ifndef AMIGA
+       Strcat(lock, alllevels);
+#endif
+       return;
+}
+#endif /* MFLOPPY */
+
+
+/* Construct a file name for a level-type file, which is of the form
+ * something.level (with any old level stripped off).
+ * This assumes there is space on the end of 'file' to append
+ * a two digit number.  This is true for 'level'
+ * but be careful if you use it for other things -dgk
+ */
+void
+set_levelfile_name(file, lev)
+char *file;
+int lev;
+{
+       char *tf;
+
+       tf = rindex(file, '.');
+       if (!tf) tf = eos(file);
+       Sprintf(tf, ".%d", lev);
+#ifdef VMS
+       Strcat(tf, ";1");
+#endif
+       return;
+}
+
+int
+create_levelfile(lev, errbuf)
+int lev;
+char errbuf[];
+{
+       int fd;
+       const char *fq_lock;
+
+       if (errbuf) *errbuf = '\0';
+       set_levelfile_name(lock, lev);
+       fq_lock = fqname(lock, LEVELPREFIX, 0);
+
+#if defined(MICRO) || defined(WIN32)
+       /* Use O_TRUNC to force the file to be shortened if it already
+        * exists and is currently longer.
+        */
+# ifdef HOLD_LOCKFILE_OPEN
+       if (lev == 0)
+               fd = open_levelfile_exclusively(fq_lock, lev,
+                               O_WRONLY |O_CREAT | O_TRUNC | O_BINARY);
+       else
+# endif
+       fd = open(fq_lock, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK);
+#else
+# ifdef MAC
+       fd = maccreat(fq_lock, LEVL_TYPE);
+# else
+       fd = creat(fq_lock, FCMASK);
+# endif
+#endif /* MICRO || WIN32 */
+
+       if (fd >= 0)
+           level_info[lev].flags |= LFILE_EXISTS;
+       else if (errbuf)        /* failure explanation */
+           Sprintf(errbuf,
+                   "Cannot create file \"%s\" for level %d (errno %d).",
+                   lock, lev, errno);
+
+       return fd;
+}
+
+
+int
+open_levelfile(lev, errbuf)
+int lev;
+char errbuf[];
+{
+       int fd;
+       const char *fq_lock;
+
+       if (errbuf) *errbuf = '\0';
+       set_levelfile_name(lock, lev);
+       fq_lock = fqname(lock, LEVELPREFIX, 0);
+#ifdef MFLOPPY
+       /* If not currently accessible, swap it in. */
+       if (level_info[lev].where != ACTIVE)
+               swapin_file(lev);
+#endif
+#ifdef MAC
+       fd = macopen(fq_lock, O_RDONLY | O_BINARY, LEVL_TYPE);
+#else
+# ifdef HOLD_LOCKFILE_OPEN
+       if (lev == 0)
+               fd = open_levelfile_exclusively(fq_lock, lev, O_RDONLY | O_BINARY );
+       else
+# endif
+       fd = open(fq_lock, O_RDONLY | O_BINARY, 0);
+#endif
+
+       /* for failure, return an explanation that our caller can use;
+          settle for `lock' instead of `fq_lock' because the latter
+          might end up being too big for nethack's BUFSZ */
+       if (fd < 0 && errbuf)
+           Sprintf(errbuf,
+                   "Cannot open file \"%s\" for level %d (errno %d).",
+                   lock, lev, errno);
+
+       return fd;
+}
+
+
+void
+delete_levelfile(lev)
+int lev;
+{
+       /*
+        * Level 0 might be created by port specific code that doesn't
+        * call create_levfile(), so always assume that it exists.
+        */
+       if (lev == 0 || (level_info[lev].flags & LFILE_EXISTS)) {
+               set_levelfile_name(lock, lev);
+#ifdef HOLD_LOCKFILE_OPEN
+               if (lev == 0) really_close();
+#endif
+               (void) unlink(fqname(lock, LEVELPREFIX, 0));
+               level_info[lev].flags &= ~LFILE_EXISTS;
+       }
+}
+
+
+void
+clearlocks()
+{
+#if !defined(PC_LOCKING) && defined(MFLOPPY) && !defined(AMIGA)
+       eraseall(levels, alllevels);
+       if (ramdisk)
+               eraseall(permbones, alllevels);
+#else
+       register int x;
+
+# if defined(UNIX) || defined(VMS)
+       (void) signal(SIGHUP, SIG_IGN);
+# endif
+       /* can't access maxledgerno() before dungeons are created -dlc */
+       for (x = (n_dgns ? maxledgerno() : 0); x >= 0; x--)
+               delete_levelfile(x);    /* not all levels need be present */
+#endif
+}
+
+#ifdef HOLD_LOCKFILE_OPEN
+STATIC_OVL int
+open_levelfile_exclusively(name, lev, oflag)
+const char *name;
+int lev, oflag;
+{
+       int reslt, fd;
+       if (!lftrack.init) {
+               lftrack.init = 1;
+               lftrack.fd = -1;
+       }
+       if (lftrack.fd >= 0) {
+               /* check for compatible access */
+               if (lftrack.oflag == oflag) {
+                       fd = lftrack.fd;
+                       reslt = lseek(fd, 0L, SEEK_SET);
+                       if (reslt == -1L)
+                           panic("open_levelfile_exclusively: lseek failed %d", errno);
+                       lftrack.nethack_thinks_it_is_open = TRUE;
+               } else {
+                       really_close();
+                       fd = sopen(name, oflag,SH_DENYRW, FCMASK);
+                       lftrack.fd = fd;
+                       lftrack.oflag = oflag;
+                       lftrack.nethack_thinks_it_is_open = TRUE;
+               }
+       } else {
+                       fd = sopen(name, oflag,SH_DENYRW, FCMASK);
+                       lftrack.fd = fd;
+                       lftrack.oflag = oflag;
+                       if (fd >= 0)
+                           lftrack.nethack_thinks_it_is_open = TRUE;
+       }
+       return fd;
+}
+
+void
+really_close()
+{
+       int fd = lftrack.fd;
+       lftrack.nethack_thinks_it_is_open = FALSE;
+       lftrack.fd = -1;
+       lftrack.oflag = 0;
+       (void)_close(fd);
+       return;
+}
+
+int
+close(fd)
+int fd;
+{
+       if (lftrack.fd == fd) {
+               really_close(); /* close it, but reopen it to hold it */
+               fd = open_levelfile(0, (char *)0);
+               lftrack.nethack_thinks_it_is_open = FALSE;
+               return 0;
+       }
+       return _close(fd);
+}
+#endif
+       
+/* ----------  END LEVEL FILE HANDLING ----------- */
+
+
+/* ----------  BEGIN BONES FILE HANDLING ----------- */
+
+/* set up "file" to be file name for retrieving bones, and return a
+ * bonesid to be read/written in the bones file.
+ */
+STATIC_OVL char *
+set_bonesfile_name(file, lev)
+char *file;
+d_level *lev;
+{
+       s_level *sptr;
+       char *dptr;
+
+       Sprintf(file, "bon%c%s", dungeons[lev->dnum].boneid,
+                       In_quest(lev) ? urole.filecode : "0");
+       dptr = eos(file);
+       if ((sptr = Is_special(lev)) != 0)
+           Sprintf(dptr, ".%c", sptr->boneid);
+       else
+           Sprintf(dptr, ".%d", lev->dlevel);
+#ifdef VMS
+       Strcat(dptr, ";1");
+#endif
+       return(dptr-2);
+}
+
+/* set up temporary file name for writing bones, to avoid another game's
+ * trying to read from an uncompleted bones file.  we want an uncontentious
+ * name, so use one in the namespace reserved for this game's level files.
+ * (we are not reading or writing level files while writing bones files, so
+ * the same array may be used instead of copying.)
+ */
+STATIC_OVL char *
+set_bonestemp_name()
+{
+       char *tf;
+
+       tf = rindex(lock, '.');
+       if (!tf) tf = eos(lock);
+       Sprintf(tf, ".bn");
+#ifdef VMS
+       Strcat(tf, ";1");
+#endif
+       return lock;
+}
+
+int
+create_bonesfile(lev, bonesid, errbuf)
+d_level *lev;
+char **bonesid;
+char errbuf[];
+{
+       const char *file;
+       int fd;
+
+       if (errbuf) *errbuf = '\0';
+       *bonesid = set_bonesfile_name(bones, lev);
+       file = set_bonestemp_name();
+       file = fqname(file, BONESPREFIX, 0);
+
+#if defined(MICRO) || defined(WIN32)
+       /* Use O_TRUNC to force the file to be shortened if it already
+        * exists and is currently longer.
+        */
+       fd = open(file, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK);
+#else
+# ifdef MAC
+       fd = maccreat(file, BONE_TYPE);
+# else
+       fd = creat(file, FCMASK);
+# endif
+#endif
+       if (fd < 0 && errbuf) /* failure explanation */
+           Sprintf(errbuf,
+                   "Cannot create bones \"%s\", id %s (errno %d).",
+                   lock, *bonesid, errno);
+
+# if defined(VMS) && !defined(SECURE)
+       /*
+          Re-protect bones file with world:read+write+execute+delete access.
+          umask() doesn't seem very reliable; also, vaxcrtl won't let us set
+          delete access without write access, which is what's really wanted.
+          Can't simply create it with the desired protection because creat
+          ANDs the mask with the user's default protection, which usually
+          denies some or all access to world.
+        */
+       (void) chmod(file, FCMASK | 007);  /* allow other users full access */
+# endif /* VMS && !SECURE */
+
+       return fd;
+}
+
+#ifdef MFLOPPY
+/* remove partial bonesfile in process of creation */
+void
+cancel_bonesfile()
+{
+       const char *tempname;
+
+       tempname = set_bonestemp_name();
+       tempname = fqname(tempname, BONESPREFIX, 0);
+       (void) unlink(tempname);
+}
+#endif /* MFLOPPY */
+
+/* move completed bones file to proper name */
+void
+commit_bonesfile(lev)
+d_level *lev;
+{
+       const char *fq_bones, *tempname;
+       int ret;
+
+       (void) set_bonesfile_name(bones, lev);
+       fq_bones = fqname(bones, BONESPREFIX, 0);
+       tempname = set_bonestemp_name();
+       tempname = fqname(tempname, BONESPREFIX, 1);
+
+#if (defined(SYSV) && !defined(SVR4)) || defined(GENIX)
+       /* old SYSVs don't have rename.  Some SVR3's may, but since they
+        * also have link/unlink, it doesn't matter. :-)
+        */
+       (void) unlink(fq_bones);
+       ret = link(tempname, fq_bones);
+       ret += unlink(tempname);
+#else
+       ret = rename(tempname, fq_bones);
+#endif
+#ifdef WIZARD
+       if (wizard && ret != 0)
+               pline("couldn't rename %s to %s.", tempname, fq_bones);
+#endif
+}
+
+
+int
+open_bonesfile(lev, bonesid)
+d_level *lev;
+char **bonesid;
+{
+       const char *fq_bones;
+       int fd;
+
+       *bonesid = set_bonesfile_name(bones, lev);
+       fq_bones = fqname(bones, BONESPREFIX, 0);
+       uncompress(fq_bones);   /* no effect if nonexistent */
+#ifdef MAC
+       fd = macopen(fq_bones, O_RDONLY | O_BINARY, BONE_TYPE);
+#else
+       fd = open(fq_bones, O_RDONLY | O_BINARY, 0);
+#endif
+       return fd;
+}
+
+
+int
+delete_bonesfile(lev)
+d_level *lev;
+{
+       (void) set_bonesfile_name(bones, lev);
+       return !(unlink(fqname(bones, BONESPREFIX, 0)) < 0);
+}
+
+
+/* assume we're compressing the recently read or created bonesfile, so the
+ * file name is already set properly */
+void
+compress_bonesfile()
+{
+       compress(fqname(bones, BONESPREFIX, 0));
+}
+
+/* ----------  END BONES FILE HANDLING ----------- */
+
+
+/* ----------  BEGIN SAVE FILE HANDLING ----------- */
+
+/* set savefile name in OS-dependent manner from pre-existing plname,
+ * avoiding troublesome characters */
+void
+set_savefile_name()
+{
+#if defined(WIN32)
+       char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ];
+#endif
+#ifdef VMS
+       Sprintf(SAVEF, "[.save]%d%s", getuid(), plname);
+       regularize(SAVEF+7);
+       Strcat(SAVEF, ";1");
+#else
+# if defined(MICRO)
+       Strcpy(SAVEF, SAVEP);
+#  ifdef AMIGA
+       strncat(SAVEF, bbs_id, PATHLEN);
+#  endif
+       {
+               int i = strlen(SAVEP);
+#  ifdef AMIGA
+               /* plname has to share space with SAVEP and ".sav" */
+               (void)strncat(SAVEF, plname, FILENAME - i - 4);
+#  else
+               (void)strncat(SAVEF, plname, 8);
+#  endif
+               regularize(SAVEF+i);
+       }
+       Strcat(SAVEF, ".sav");
+# else
+#  if defined(WIN32)
+       /* Obtain the name of the logged on user and incorporate
+        * it into the name. */
+       Sprintf(fnamebuf, "%s-%s", get_username(0), plname);
+       (void)fname_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.",
+                               '%', fnamebuf, encodedfnamebuf, BUFSZ);
+       Sprintf(SAVEF, "%s.NetHack-saved-game", encodedfnamebuf);
+#  else
+       Sprintf(SAVEF, "save/%d%s", (int)getuid(), plname);
+       regularize(SAVEF+5);    /* avoid . or / in name */
+#  endif /* WIN32 */
+# endif        /* MICRO */
+#endif /* VMS   */
+}
+
+#ifdef INSURANCE
+void
+save_savefile_name(fd)
+int fd;
+{
+       (void) write(fd, (genericptr_t) SAVEF, sizeof(SAVEF));
+}
+#endif
+
+
+#if defined(WIZARD) && !defined(MICRO)
+/* change pre-existing savefile name to indicate an error savefile */
+void
+set_error_savefile()
+{
+# ifdef VMS
+      {
+       char *semi_colon = rindex(SAVEF, ';');
+       if (semi_colon) *semi_colon = '\0';
+      }
+       Strcat(SAVEF, ".e;1");
+# else
+#  ifdef MAC
+       Strcat(SAVEF, "-e");
+#  else
+       Strcat(SAVEF, ".e");
+#  endif
+# endif
+}
+#endif
+
+
+/* create save file, overwriting one if it already exists */
+int
+create_savefile()
+{
+       const char *fq_save;
+       int fd;
+
+       fq_save = fqname(SAVEF, SAVEPREFIX, 0);
+#if defined(MICRO) || defined(WIN32)
+       fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
+#else
+# ifdef MAC
+       fd = maccreat(fq_save, SAVE_TYPE);
+# else
+       fd = creat(fq_save, FCMASK);
+# endif
+# if defined(VMS) && !defined(SECURE)
+       /*
+          Make sure the save file is owned by the current process.  That's
+          the default for non-privileged users, but for priv'd users the
+          file will be owned by the directory's owner instead of the user.
+        */
+#  ifdef getuid        /*(see vmsunix.c)*/
+#   undef getuid
+#  endif
+       (void) chown(fq_save, getuid(), getgid());
+# endif /* VMS && !SECURE */
+#endif /* MICRO */
+
+       return fd;
+}
+
+
+/* open savefile for reading */
+int
+open_savefile()
+{
+       const char *fq_save;
+       int fd;
+
+       fq_save = fqname(SAVEF, SAVEPREFIX, 0);
+#ifdef MAC
+       fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE);
+#else
+       fd = open(fq_save, O_RDONLY | O_BINARY, 0);
+#endif
+       return fd;
+}
+
+
+/* delete savefile */
+int
+delete_savefile()
+{
+       (void) unlink(fqname(SAVEF, SAVEPREFIX, 0));
+       return 0;       /* for restore_saved_game() (ex-xxxmain.c) test */
+}
+
+
+/* try to open up a save file and prepare to restore it */
+int
+restore_saved_game()
+{
+       const char *fq_save;
+       int fd;
+
+       set_savefile_name();
+#ifdef MFLOPPY
+       if (!saveDiskPrompt(1))
+           return -1;
+#endif /* MFLOPPY */
+       fq_save = fqname(SAVEF, SAVEPREFIX, 0);
+
+       uncompress(fq_save);
+       if ((fd = open_savefile()) < 0) return fd;
+
+       if (!uptodate(fd, fq_save)) {
+           (void) close(fd),  fd = -1;
+           (void) delete_savefile();
+       }
+       return fd;
+}
+
+#if defined(UNIX) && defined(QT_GRAPHICS)
+/*ARGSUSED*/
+static char*
+plname_from_file(filename)
+const char* filename;
+{
+#ifdef STORE_PLNAME_IN_FILE
+    int fd;
+    char* result = 0;
+
+    Strcpy(SAVEF,filename);
+#ifdef COMPRESS_EXTENSION
+    SAVEF[strlen(SAVEF)-strlen(COMPRESS_EXTENSION)] = '\0';
+#endif
+    uncompress(SAVEF);
+    if ((fd = open_savefile()) >= 0) {
+       if (uptodate(fd, filename)) {
+           char tplname[PL_NSIZ];
+           mread(fd, (genericptr_t) tplname, PL_NSIZ);
+           result = strdup(tplname);
+       }
+       (void) close(fd);
+    }
+    compress(SAVEF);
+
+    return result;
+#else
+# if defined(UNIX) && defined(QT_GRAPHICS)
+    /* Name not stored in save file, so we have to extract it from
+       the filename, which loses information
+       (eg. "/", "_", and "." characters are lost. */
+    int k;
+    int uid;
+    char name[64]; /* more than PL_NSIZ */
+#ifdef COMPRESS_EXTENSION
+#define EXTSTR COMPRESS_EXTENSION
+#else
+#define EXTSTR ""
+#endif
+    if ( sscanf( filename, "%*[^/]/%d%63[^.]" EXTSTR, &uid, name ) == 2 ) {
+#undef EXTSTR
+    /* "_" most likely means " ", which certainly looks nicer */
+       for (k=0; name[k]; k++)
+           if ( name[k]=='_' )
+               name[k]=' ';
+       return strdup(name);
+    } else
+# endif
+    {
+       return 0;
+    }
+#endif
+}
+#endif /* defined(UNIX) && defined(QT_GRAPHICS) */
+
+char**
+get_saved_games()
+{
+#if defined(UNIX) && defined(QT_GRAPHICS)
+    int myuid=getuid();
+    struct dirent **namelist;
+    int n = scandir("save", &namelist, 0, alphasort);;
+    if ( n > 0 ) {
+       int i,j=0;
+       char** result = (char**)alloc((n+1)*sizeof(char*)); /* at most */
+       for (i=0; i<n; i++) {
+           int uid;
+           char name[64]; /* more than PL_NSIZ */
+           if ( sscanf( namelist[i]->d_name, "%d%63s", &uid, name ) == 2 ) {
+               if ( uid == myuid ) {
+                   char filename[BUFSZ];
+                   char* r;
+                   Sprintf(filename,"save/%d%s",uid,name);
+                   r = plname_from_file(filename);
+                   if ( r )
+                       result[j++] = r;
+               }
+           }
+       }
+       result[j++] = 0;
+       return result;
+    } else
+#endif
+    {
+       return 0;
+    }
+}
+
+void
+free_saved_games(saved)
+char** saved;
+{
+    if ( saved ) {
+       int i=0;
+       while (saved[i]) free((genericptr_t)saved[i++]);
+       free((genericptr_t)saved);
+    }
+}
+
+
+/* ----------  END SAVE FILE HANDLING ----------- */
+
+
+/* ----------  BEGIN FILE COMPRESSION HANDLING ----------- */
+
+#ifdef COMPRESS
+
+STATIC_OVL void
+redirect(filename, mode, stream, uncomp)
+const char *filename, *mode;
+FILE *stream;
+boolean uncomp;
+{
+       if (freopen(filename, mode, stream) == (FILE *)0) {
+               (void) fprintf(stderr, "freopen of %s for %scompress failed\n",
+                       filename, uncomp ? "un" : "");
+               terminate(EXIT_FAILURE);
+       }
+}
+
+/*
+ * using system() is simpler, but opens up security holes and causes
+ * problems on at least Interactive UNIX 3.0.1 (SVR3.2), where any
+ * setuid is renounced by /bin/sh, so the files cannot be accessed.
+ *
+ * cf. child() in unixunix.c.
+ */
+STATIC_OVL void
+docompress_file(filename, uncomp)
+const char *filename;
+boolean uncomp;
+{
+       char cfn[80];
+       FILE *cf;
+       const char *args[10];
+# ifdef COMPRESS_OPTIONS
+       char opts[80];
+# endif
+       int i = 0;
+       int f;
+# ifdef TTY_GRAPHICS
+       boolean istty = !strncmpi(windowprocs.name, "tty", 3);
+# endif
+
+       Strcpy(cfn, filename);
+# ifdef COMPRESS_EXTENSION
+       Strcat(cfn, COMPRESS_EXTENSION);
+# endif
+       /* when compressing, we know the file exists */
+       if (uncomp) {
+           if ((cf = fopen(cfn, RDBMODE)) == (FILE *)0)
+                   return;
+           (void) fclose(cf);
+       }
+
+       args[0] = COMPRESS;
+       if (uncomp) args[++i] = "-d";   /* uncompress */
+# ifdef COMPRESS_OPTIONS
+       {
+           /* we can't guarantee there's only one additional option, sigh */
+           char *opt;
+           boolean inword = FALSE;
+
+           Strcpy(opts, COMPRESS_OPTIONS);
+           opt = opts;
+           while (*opt) {
+               if ((*opt == ' ') || (*opt == '\t')) {
+                   if (inword) {
+                       *opt = '\0';
+                       inword = FALSE;
+                   }
+               } else if (!inword) {
+                   args[++i] = opt;
+                   inword = TRUE;
+               }
+               opt++;
+           }
+       }
+# endif
+       args[++i] = (char *)0;
+
+# ifdef TTY_GRAPHICS
+       /* If we don't do this and we are right after a y/n question *and*
+        * there is an error message from the compression, the 'y' or 'n' can
+        * end up being displayed after the error message.
+        */
+       if (istty)
+           mark_synch();
+# endif
+       f = fork();
+       if (f == 0) {   /* child */
+# ifdef TTY_GRAPHICS
+               /* any error messages from the compression must come out after
+                * the first line, because the more() to let the user read
+                * them will have to clear the first line.  This should be
+                * invisible if there are no error messages.
+                */
+               if (istty)
+                   raw_print("");
+# endif
+               /* run compressor without privileges, in case other programs
+                * have surprises along the line of gzip once taking filenames
+                * in GZIP.
+                */
+               /* assume all compressors will compress stdin to stdout
+                * without explicit filenames.  this is true of at least
+                * compress and gzip, those mentioned in config.h.
+                */
+               if (uncomp) {
+                       redirect(cfn, RDBMODE, stdin, uncomp);
+                       redirect(filename, WRBMODE, stdout, uncomp);
+               } else {
+                       redirect(filename, RDBMODE, stdin, uncomp);
+                       redirect(cfn, WRBMODE, stdout, uncomp);
+               }
+               (void) setgid(getgid());
+               (void) setuid(getuid());
+               (void) execv(args[0], (char *const *) args);
+               perror((char *)0);
+               (void) fprintf(stderr, "Exec to %scompress %s failed.\n",
+                       uncomp ? "un" : "", filename);
+               terminate(EXIT_FAILURE);
+       } else if (f == -1) {
+               perror((char *)0);
+               pline("Fork to %scompress %s failed.",
+                       uncomp ? "un" : "", filename);
+               return;
+       }
+       (void) signal(SIGINT, SIG_IGN);
+       (void) signal(SIGQUIT, SIG_IGN);
+       (void) wait((int *)&i);
+       (void) signal(SIGINT, (SIG_RET_TYPE) done1);
+# ifdef WIZARD
+       if (wizard) (void) signal(SIGQUIT, SIG_DFL);
+# endif
+       if (i == 0) {
+           /* (un)compress succeeded: remove file left behind */
+           if (uncomp)
+               (void) unlink(cfn);
+           else
+               (void) unlink(filename);
+       } else {
+           /* (un)compress failed; remove the new, bad file */
+           if (uncomp) {
+               raw_printf("Unable to uncompress %s", filename);
+               (void) unlink(filename);
+           } else {
+               /* no message needed for compress case; life will go on */
+               (void) unlink(cfn);
+           }
+#ifdef TTY_GRAPHICS
+           /* Give them a chance to read any error messages from the
+            * compression--these would go to stdout or stderr and would get
+            * overwritten only in tty mode.  It's still ugly, since the
+            * messages are being written on top of the screen, but at least
+            * the user can read them.
+            */
+           if (istty)
+           {
+               clear_nhwindow(WIN_MESSAGE);
+               more();
+               /* No way to know if this is feasible */
+               /* doredraw(); */
+           }
+#endif
+       }
+}
+#endif /* COMPRESS */
+
+/* compress file */
+void
+compress(filename)
+const char *filename;
+{
+#ifndef COMPRESS
+#if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__)
+# pragma unused(filename)
+#endif
+#else
+       docompress_file(filename, FALSE);
+#endif
+}
+
+
+/* uncompress file if it exists */
+void
+uncompress(filename)
+const char *filename;
+{
+#ifndef COMPRESS
+#if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__)
+# pragma unused(filename)
+#endif
+#else
+       docompress_file(filename, TRUE);
+#endif
+}
+
+/* ----------  END FILE COMPRESSION HANDLING ----------- */
+
+
+/* ----------  BEGIN FILE LOCKING HANDLING ----------- */
+
+static int nesting = 0;
+
+#ifdef NO_FILE_LINKS   /* implies UNIX */
+static int lockfd;     /* for lock_file() to pass to unlock_file() */
+#endif
+
+#define HUP    if (!program_state.done_hup)
+
+STATIC_OVL char *
+make_lockname(filename, lockname)
+const char *filename;
+char *lockname;
+{
+#if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__)
+# pragma unused(filename,lockname)
+       return (char*)0;
+#else
+# if defined(UNIX) || defined(VMS) || defined(AMIGA) || defined(WIN32) || defined(MSDOS)
+#  ifdef NO_FILE_LINKS
+       Strcpy(lockname, LOCKDIR);
+       Strcat(lockname, "/");
+       Strcat(lockname, filename);
+#  else
+       Strcpy(lockname, filename);
+#  endif
+#  ifdef VMS
+      {
+       char *semi_colon = rindex(lockname, ';');
+       if (semi_colon) *semi_colon = '\0';
+      }
+       Strcat(lockname, ".lock;1");
+#  else
+       Strcat(lockname, "_lock");
+#  endif
+       return lockname;
+# else
+       lockname[0] = '\0';
+       return (char*)0;
+# endif  /* UNIX || VMS || AMIGA || WIN32 || MSDOS */
+#endif
+}
+
+
+/* lock a file */
+boolean
+lock_file(filename, whichprefix, retryct)
+const char *filename;
+int whichprefix;
+int retryct;
+{
+#if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__)
+# pragma unused(filename, retryct)
+#endif
+       char locknambuf[BUFSZ];
+       const char *lockname;
+
+       nesting++;
+       if (nesting > 1) {
+           impossible("TRIED TO NEST LOCKS");
+           return TRUE;
+       }
+
+       lockname = make_lockname(filename, locknambuf);
+       filename = fqname(filename, whichprefix, 0);
+#ifndef NO_FILE_LINKS  /* LOCKDIR should be subsumed by LOCKPREFIX */
+       lockname = fqname(lockname, LOCKPREFIX, 2);
+#endif
+
+#if defined(UNIX) || defined(VMS)
+# ifdef NO_FILE_LINKS
+       while ((lockfd = open(lockname, O_RDWR|O_CREAT|O_EXCL, 0666)) == -1) {
+# else
+       while (link(filename, lockname) == -1) {
+# endif
+           register int errnosv = errno;
+
+           switch (errnosv) {  /* George Barbanis */
+           case EEXIST:
+               if (retryct--) {
+                   HUP raw_printf(
+                           "Waiting for access to %s.  (%d retries left).",
+                           filename, retryct);
+# if defined(SYSV) || defined(ULTRIX) || defined(VMS)
+                   (void)
+# endif
+                       sleep(1);
+               } else {
+                   HUP (void) raw_print("I give up.  Sorry.");
+                   HUP raw_printf("Perhaps there is an old %s around?",
+                                       lockname);
+                   nesting--;
+                   return FALSE;
+               }
+
+               break;
+           case ENOENT:
+               HUP raw_printf("Can't find file %s to lock!", filename);
+               nesting--;
+               return FALSE;
+           case EACCES:
+               HUP raw_printf("No write permission to lock %s!", filename);
+               nesting--;
+               return FALSE;
+# ifdef VMS                    /* c__translate(vmsfiles.c) */
+           case EPERM:
+               /* could be misleading, but usually right */
+               HUP raw_printf("Can't lock %s due to directory protection.",
+                              filename);
+               nesting--;
+               return FALSE;
+# endif
+           default:
+               HUP perror(lockname);
+               HUP raw_printf(
+                            "Cannot lock %s for unknown reason (%d).",
+                              filename, errnosv);
+               nesting--;
+               return FALSE;
+           }
+
+       }
+#endif  /* UNIX || VMS */
+
+#if defined(AMIGA) || defined(WIN32) || defined(MSDOS)
+# ifdef AMIGA
+#define OPENFAILURE(fd) (!fd)
+    lockptr = 0;
+# else
+#define OPENFAILURE(fd) (fd < 0)
+    lockptr = -1;
+# endif
+    while (--retryct && OPENFAILURE(lockptr)) {
+# if defined(WIN32) && !defined(WIN_CE)
+       lockptr = sopen(lockname, O_RDWR|O_CREAT, SH_DENYRW, S_IWRITE);
+# else
+       (void)DeleteFile(lockname); /* in case dead process was here first */
+#  ifdef AMIGA
+       lockptr = Open(lockname,MODE_NEWFILE);
+#  else
+       lockptr = open(lockname, O_RDWR|O_CREAT|O_EXCL, S_IWRITE);
+#  endif
+# endif
+       if (OPENFAILURE(lockptr)) {
+           raw_printf("Waiting for access to %s.  (%d retries left).",
+                       filename, retryct);
+           Delay(50);
+       }
+    }
+    if (!retryct) {
+       raw_printf("I give up.  Sorry.");
+       nesting--;
+       return FALSE;
+    }
+#endif /* AMIGA || WIN32 || MSDOS */
+       return TRUE;
+}
+
+
+#ifdef VMS     /* for unlock_file, use the unlink() routine in vmsunix.c */
+# ifdef unlink
+#  undef unlink
+# endif
+# define unlink(foo) vms_unlink(foo)
+#endif
+
+/* unlock file, which must be currently locked by lock_file */
+void
+unlock_file(filename)
+const char *filename;
+#if defined(macintosh) && (defined(__SC__) || defined(__MRC__))
+# pragma unused(filename)
+#endif
+{
+       char locknambuf[BUFSZ];
+       const char *lockname;
+
+       if (nesting == 1) {
+               lockname = make_lockname(filename, locknambuf);
+#ifndef NO_FILE_LINKS  /* LOCKDIR should be subsumed by LOCKPREFIX */
+               lockname = fqname(lockname, LOCKPREFIX, 2);
+#endif
+
+#if defined(UNIX) || defined(VMS)
+               if (unlink(lockname) < 0)
+                       HUP raw_printf("Can't unlink %s.", lockname);
+# ifdef NO_FILE_LINKS
+               (void) close(lockfd);
+# endif
+
+#endif  /* UNIX || VMS */
+
+#if defined(AMIGA) || defined(WIN32) || defined(MSDOS)
+               if (lockptr) Close(lockptr);
+               DeleteFile(lockname);
+               lockptr = 0;
+#endif /* AMIGA || WIN32 || MSDOS */
+       }
+
+       nesting--;
+}
+
+/* ----------  END FILE LOCKING HANDLING ----------- */
+
+
+/* ----------  BEGIN CONFIG FILE HANDLING ----------- */
+
+const char *configfile =
+#ifdef UNIX
+                       ".nethackrc";
+#else
+# if defined(MAC) || defined(__BEOS__)
+                       "NetHack Defaults";
+# else
+#  if defined(MSDOS) || defined(WIN32)
+                       "defaults.nh";
+#  else
+                       "NetHack.cnf";
+#  endif
+# endif
+#endif
+
+
+#ifdef MSDOS
+/* conflict with speed-dial under windows
+ * for XXX.cnf file so support of NetHack.cnf
+ * is for backward compatibility only.
+ * Preferred name (and first tried) is now defaults.nh but
+ * the game will try the old name if there
+ * is no defaults.nh.
+ */
+const char *backward_compat_configfile = "nethack.cnf"; 
+#endif
+
+#ifndef MFLOPPY
+#define fopenp fopen
+#endif
+
+STATIC_OVL FILE *
+fopen_config_file(filename)
+const char *filename;
+{
+       FILE *fp;
+#if defined(UNIX) || defined(VMS)
+       char    tmp_config[BUFSZ];
+       char *envp;
+#endif
+
+       /* "filename" is an environment variable, so it should hang around */
+       /* if set, it is expected to be a full path name (if relevant) */
+       if (filename) {
+#ifdef UNIX
+               if (access(filename, 4) == -1) {
+                       /* 4 is R_OK on newer systems */
+                       /* nasty sneaky attempt to read file through
+                        * NetHack's setuid permissions -- this is the only
+                        * place a file name may be wholly under the player's
+                        * control
+                        */
+                       raw_printf("Access to %s denied (%d).",
+                                       filename, errno);
+                       wait_synch();
+                       /* fall through to standard names */
+               } else
+#endif
+               if ((fp = fopenp(filename, "r")) != (FILE *)0) {
+                   configfile = filename;
+                   return(fp);
+#if defined(UNIX) || defined(VMS)
+               } else {
+                   /* access() above probably caught most problems for UNIX */
+                   raw_printf("Couldn't open requested config file %s (%d).",
+                                       filename, errno);
+                   wait_synch();
+                   /* fall through to standard names */
+#endif
+               }
+       }
+
+#if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32)
+       if ((fp = fopenp(fqname(configfile, CONFIGPREFIX, 0), "r"))
+                                                               != (FILE *)0)
+               return(fp);
+# ifdef MSDOS
+       else if ((fp = fopenp(fqname(backward_compat_configfile,
+                                       CONFIGPREFIX, 0), "r")) != (FILE *)0)
+               return(fp);
+# endif
+#else
+       /* constructed full path names don't need fqname() */
+# ifdef VMS
+       if ((fp = fopenp(fqname("nethackini", CONFIGPREFIX, 0), "r"))
+                                                               != (FILE *)0) {
+               configfile = "nethackini";
+               return(fp);
+       }
+       if ((fp = fopenp("sys$login:nethack.ini", "r")) != (FILE *)0) {
+               configfile = "nethack.ini";
+               return(fp);
+       }
+
+       envp = nh_getenv("HOME");
+       if (!envp)
+               Strcpy(tmp_config, "NetHack.cnf");
+       else
+               Sprintf(tmp_config, "%s%s", envp, "NetHack.cnf");
+       if ((fp = fopenp(tmp_config, "r")) != (FILE *)0)
+               return(fp);
+# else /* should be only UNIX left */
+       envp = nh_getenv("HOME");
+       if (!envp)
+               Strcpy(tmp_config, configfile);
+       else
+               Sprintf(tmp_config, "%s/%s", envp, configfile);
+       if ((fp = fopenp(tmp_config, "r")) != (FILE *)0)
+               return(fp);
+# if defined(__APPLE__)
+       /* try an alternative */
+       if (envp) {
+               Sprintf(tmp_config, "%s/%s", envp, "Library/Preferences/NetHack Defaults");
+               if ((fp = fopenp(tmp_config, "r")) != (FILE *)0)
+                       return(fp);
+               Sprintf(tmp_config, "%s/%s", envp, "Library/Preferences/NetHack Defaults.txt");
+               if ((fp = fopenp(tmp_config, "r")) != (FILE *)0)
+                       return(fp);
+       }
+# endif
+       if (errno != ENOENT) {
+           char *details;
+
+           /* e.g., problems when setuid NetHack can't search home
+            * directory restricted to user */
+
+#if defined (NHSTDC) && !defined(NOTSTDC)
+           if ((details = strerror(errno)) == 0)
+#endif
+               details = "";
+           raw_printf("Couldn't open default config file %s %s(%d).",
+                      tmp_config, details, errno);
+           wait_synch();
+       }
+# endif
+#endif
+       return (FILE *)0;
+
+}
+
+
+/*
+ * Retrieve a list of integers from a file into a uchar array.
+ *
+ * NOTE: zeros are inserted unless modlist is TRUE, in which case the list
+ *  location is unchanged.  Callers must handle zeros if modlist is FALSE.
+ */
+STATIC_OVL int
+get_uchars(fp, buf, bufp, list, modlist, size, name)
+    FILE *fp;          /* input file pointer */
+    char *buf;         /* read buffer, must be of size BUFSZ */
+    char *bufp;                /* current pointer */
+    uchar *list;       /* return list */
+    boolean modlist;   /* TRUE: list is being modified in place */
+    int  size;         /* return list size */
+    const char *name;          /* name of option for error message */
+{
+    unsigned int num = 0;
+    int count = 0;
+    boolean havenum = FALSE;
+
+    while (1) {
+       switch(*bufp) {
+           case ' ':  case '\0':
+           case '\t': case '\n':
+               if (havenum) {
+                   /* if modifying in place, don't insert zeros */
+                   if (num || !modlist) list[count] = num;
+                   count++;
+                   num = 0;
+                   havenum = FALSE;
+               }
+               if (count == size || !*bufp) return count;
+               bufp++;
+               break;
+
+           case '0': case '1': case '2': case '3':
+           case '4': case '5': case '6': case '7':
+           case '8': case '9':
+               havenum = TRUE;
+               num = num*10 + (*bufp-'0');
+               bufp++;
+               break;
+
+           case '\\':
+               if (fp == (FILE *)0)
+                   goto gi_error;
+               do  {
+                   if (!fgets(buf, BUFSZ, fp)) goto gi_error;
+               } while (buf[0] == '#');
+               bufp = buf;
+               break;
+
+           default:
+gi_error:
+               raw_printf("Syntax error in %s", name);
+               wait_synch();
+               return count;
+       }
+    }
+    /*NOTREACHED*/
+}
+
+#ifdef NOCWD_ASSUMPTIONS
+STATIC_OVL void
+adjust_prefix(bufp, prefixid)
+char *bufp;
+int prefixid;
+{
+       char *ptr;
+
+       if (!bufp) return;
+       /* Backward compatibility, ignore trailing ;n */ 
+       if ((ptr = index(bufp, ';')) != 0) *ptr = '\0';
+       if (strlen(bufp) > 0) {
+               fqn_prefix[prefixid] = (char *)alloc(strlen(bufp)+2);
+               Strcpy(fqn_prefix[prefixid], bufp);
+               append_slash(fqn_prefix[prefixid]);
+       }
+}
+#endif
+
+#define match_varname(INP,NAM,LEN) match_optname(INP, NAM, LEN, TRUE)
+
+/*ARGSUSED*/
+int
+parse_config_line(fp, buf, tmp_ramdisk, tmp_levels)
+FILE           *fp;
+char           *buf;
+char           *tmp_ramdisk;
+char           *tmp_levels;
+{
+#if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__)
+# pragma unused(tmp_ramdisk,tmp_levels)
+#endif
+       char            *bufp, *altp;
+       uchar   translate[MAXPCHARS];
+       int   len;
+
+       if (*buf == '#')
+               return 1;
+
+       /* remove trailing whitespace */
+       bufp = eos(buf);
+       while (--bufp > buf && isspace(*bufp))
+               continue;
+
+       if (bufp <= buf)
+               return 1;               /* skip all-blank lines */
+       else
+               *(bufp + 1) = '\0';     /* terminate line */
+
+       /* find the '=' or ':' */
+       bufp = index(buf, '=');
+       altp = index(buf, ':');
+       if (!bufp || (altp && altp < bufp)) bufp = altp;
+       if (!bufp) return 0;
+
+       /* skip  whitespace between '=' and value */
+       do { ++bufp; } while (isspace(*bufp));
+
+       /* Go through possible variables */
+       /* some of these (at least LEVELS and SAVE) should now set the
+        * appropriate fqn_prefix[] rather than specialized variables
+        */
+       if (match_varname(buf, "OPTIONS", 4)) {
+               parseoptions(bufp, TRUE, TRUE);
+               if (plname[0])          /* If a name was given */
+                       plnamesuffix(); /* set the character class */
+#ifdef AUTOPICKUP_EXCEPTIONS
+       } else if (match_varname(buf, "AUTOPICKUP_EXCEPTION", 5)) {
+               add_autopickup_exception(bufp);
+#endif
+#ifdef NOCWD_ASSUMPTIONS
+       } else if (match_varname(buf, "HACKDIR", 4)) {
+               adjust_prefix(bufp, HACKPREFIX);
+       } else if (match_varname(buf, "LEVELDIR", 4) ||
+                  match_varname(buf, "LEVELS", 4)) {
+               adjust_prefix(bufp, LEVELPREFIX);
+       } else if (match_varname(buf, "SAVEDIR", 4)) {
+               adjust_prefix(bufp, SAVEPREFIX);
+       } else if (match_varname(buf, "BONESDIR", 5)) {
+               adjust_prefix(bufp, BONESPREFIX);
+       } else if (match_varname(buf, "DATADIR", 4)) {
+               adjust_prefix(bufp, DATAPREFIX);
+       } else if (match_varname(buf, "SCOREDIR", 4)) {
+               adjust_prefix(bufp, SCOREPREFIX);
+       } else if (match_varname(buf, "LOCKDIR", 4)) {
+               adjust_prefix(bufp, LOCKPREFIX);
+       } else if (match_varname(buf, "CONFIGDIR", 4)) {
+               adjust_prefix(bufp, CONFIGPREFIX);
+       } else if (match_varname(buf, "TROUBLEDIR", 4)) {
+               adjust_prefix(bufp, TROUBLEPREFIX);
+#else /*NOCWD_ASSUMPTIONS*/
+# ifdef MICRO
+       } else if (match_varname(buf, "HACKDIR", 4)) {
+               (void) strncpy(hackdir, bufp, PATHLEN-1);
+#  ifdef MFLOPPY
+       } else if (match_varname(buf, "RAMDISK", 3)) {
+                               /* The following ifdef is NOT in the wrong
+                                * place.  For now, we accept and silently
+                                * ignore RAMDISK */
+#   ifndef AMIGA
+               (void) strncpy(tmp_ramdisk, bufp, PATHLEN-1);
+#   endif
+#  endif
+       } else if (match_varname(buf, "LEVELS", 4)) {
+               (void) strncpy(tmp_levels, bufp, PATHLEN-1);
+
+       } else if (match_varname(buf, "SAVE", 4)) {
+#  ifdef MFLOPPY
+               extern  int saveprompt;
+#  endif
+               char *ptr;
+               if ((ptr = index(bufp, ';')) != 0) {
+                       *ptr = '\0';
+#  ifdef MFLOPPY
+                       if (*(ptr+1) == 'n' || *(ptr+1) == 'N') {
+                               saveprompt = FALSE;
+                       }
+#  endif
+               }
+# ifdef        MFLOPPY
+               else
+                   saveprompt = flags.asksavedisk;
+# endif
+
+               (void) strncpy(SAVEP, bufp, SAVESIZE-1);
+               append_slash(SAVEP);
+# endif /* MICRO */
+#endif /*NOCWD_ASSUMPTIONS*/
+
+       } else if (match_varname(buf, "NAME", 4)) {
+           (void) strncpy(plname, bufp, PL_NSIZ-1);
+           plnamesuffix();
+       } else if (match_varname(buf, "ROLE", 4) ||
+                  match_varname(buf, "CHARACTER", 4)) {
+           if ((len = str2role(bufp)) >= 0)
+               flags.initrole = len;
+       } else if (match_varname(buf, "DOGNAME", 3)) {
+           (void) strncpy(dogname, bufp, PL_PSIZ-1);
+       } else if (match_varname(buf, "CATNAME", 3)) {
+           (void) strncpy(catname, bufp, PL_PSIZ-1);
+
+       } else if (match_varname(buf, "BOULDER", 3)) {
+           (void) get_uchars(fp, buf, bufp, &iflags.bouldersym, TRUE,
+                             1, "BOULDER");
+       } else if (match_varname(buf, "GRAPHICS", 4)) {
+           len = get_uchars(fp, buf, bufp, translate, FALSE,
+                            MAXPCHARS, "GRAPHICS");
+           assign_graphics(translate, len, MAXPCHARS, 0);
+       } else if (match_varname(buf, "DUNGEON", 4)) {
+           len = get_uchars(fp, buf, bufp, translate, FALSE,
+                            MAXDCHARS, "DUNGEON");
+           assign_graphics(translate, len, MAXDCHARS, 0);
+       } else if (match_varname(buf, "TRAPS", 4)) {
+           len = get_uchars(fp, buf, bufp, translate, FALSE,
+                            MAXTCHARS, "TRAPS");
+           assign_graphics(translate, len, MAXTCHARS, MAXDCHARS);
+       } else if (match_varname(buf, "EFFECTS", 4)) {
+           len = get_uchars(fp, buf, bufp, translate, FALSE,
+                            MAXECHARS, "EFFECTS");
+           assign_graphics(translate, len, MAXECHARS, MAXDCHARS+MAXTCHARS);
+
+       } else if (match_varname(buf, "OBJECTS", 3)) {
+           /* oc_syms[0] is the RANDOM object, unused */
+           (void) get_uchars(fp, buf, bufp, &(oc_syms[1]), TRUE,
+                                       MAXOCLASSES-1, "OBJECTS");
+       } else if (match_varname(buf, "MONSTERS", 3)) {
+           /* monsyms[0] is unused */
+           (void) get_uchars(fp, buf, bufp, &(monsyms[1]), TRUE,
+                                       MAXMCLASSES-1, "MONSTERS");
+       } else if (match_varname(buf, "WARNINGS", 5)) {
+           (void) get_uchars(fp, buf, bufp, translate, FALSE,
+                                       WARNCOUNT, "WARNINGS");
+           assign_warnings(translate);
+#ifdef WIZARD
+       } else if (match_varname(buf, "WIZKIT", 6)) {
+           (void) strncpy(wizkit, bufp, WIZKIT_MAX-1);
+#endif
+#ifdef AMIGA
+       } else if (match_varname(buf, "FONT", 4)) {
+               char *t;
+
+               if( t = strchr( buf+5, ':' ) )
+               {
+                   *t = 0;
+                   amii_set_text_font( buf+5, atoi( t + 1 ) );
+                   *t = ':';
+               }
+       } else if (match_varname(buf, "PATH", 4)) {
+               (void) strncpy(PATH, bufp, PATHLEN-1);
+       } else if (match_varname(buf, "DEPTH", 5)) {
+               extern int amii_numcolors;
+               int val = atoi( bufp );
+               amii_numcolors = 1L << min( DEPTH, val );
+       } else if (match_varname(buf, "DRIPENS", 7)) {
+               int i, val;
+               char *t;
+               for (i = 0, t = strtok(bufp, ",/"); t != (char *)0;
+                               i < 20 && (t = strtok((char*)0, ",/")), ++i) {
+                       sscanf(t, "%d", &val );
+                       flags.amii_dripens[i] = val;
+               }
+       } else if (match_varname(buf, "SCREENMODE", 10 )) {
+               extern long amii_scrnmode;
+               if (!stricmp(bufp,"req"))
+                   amii_scrnmode = 0xffffffff; /* Requester */
+               else if( sscanf(bufp, "%x", &amii_scrnmode) != 1 )
+                   amii_scrnmode = 0;
+       } else if (match_varname(buf, "MSGPENS", 7)) {
+               extern int amii_msgAPen, amii_msgBPen;
+               char *t = strtok(bufp, ",/");
+               if( t )
+               {
+                   sscanf(t, "%d", &amii_msgAPen);
+                   if( t = strtok((char*)0, ",/") )
+                               sscanf(t, "%d", &amii_msgBPen);
+               }
+       } else if (match_varname(buf, "TEXTPENS", 8)) {
+               extern int amii_textAPen, amii_textBPen;
+               char *t = strtok(bufp, ",/");
+               if( t )
+               {
+                   sscanf(t, "%d", &amii_textAPen);
+                   if( t = strtok((char*)0, ",/") )
+                               sscanf(t, "%d", &amii_textBPen);
+               }
+       } else if (match_varname(buf, "MENUPENS", 8)) {
+               extern int amii_menuAPen, amii_menuBPen;
+               char *t = strtok(bufp, ",/");
+               if( t )
+               {
+                   sscanf(t, "%d", &amii_menuAPen);
+                   if( t = strtok((char*)0, ",/") )
+                               sscanf(t, "%d", &amii_menuBPen);
+               }
+       } else if (match_varname(buf, "STATUSPENS", 10)) {
+               extern int amii_statAPen, amii_statBPen;
+               char *t = strtok(bufp, ",/");
+               if( t )
+               {
+                   sscanf(t, "%d", &amii_statAPen);
+                   if( t = strtok((char*)0, ",/") )
+                               sscanf(t, "%d", &amii_statBPen);
+               }
+       } else if (match_varname(buf, "OTHERPENS", 9)) {
+               extern int amii_otherAPen, amii_otherBPen;
+               char *t = strtok(bufp, ",/");
+               if( t )
+               {
+                   sscanf(t, "%d", &amii_otherAPen);
+                   if( t = strtok((char*)0, ",/") )
+                               sscanf(t, "%d", &amii_otherBPen);
+               }
+       } else if (match_varname(buf, "PENS", 4)) {
+               extern unsigned short amii_init_map[ AMII_MAXCOLORS ];
+               int i;
+               char *t;
+
+               for (i = 0, t = strtok(bufp, ",/");
+                       i < AMII_MAXCOLORS && t != (char *)0;
+                       t = strtok((char *)0, ",/"), ++i)
+               {
+                       sscanf(t, "%hx", &amii_init_map[i]);
+               }
+               amii_setpens( amii_numcolors = i );
+       } else if (match_varname(buf, "FGPENS", 6)) {
+               extern int foreg[ AMII_MAXCOLORS ];
+               int i;
+               char *t;
+
+               for (i = 0, t = strtok(bufp, ",/");
+                       i < AMII_MAXCOLORS && t != (char *)0;
+                       t = strtok((char *)0, ",/"), ++i)
+               {
+                       sscanf(t, "%d", &foreg[i]);
+               }
+       } else if (match_varname(buf, "BGPENS", 6)) {
+               extern int backg[ AMII_MAXCOLORS ];
+               int i;
+               char *t;
+
+               for (i = 0, t = strtok(bufp, ",/");
+                       i < AMII_MAXCOLORS && t != (char *)0;
+                       t = strtok((char *)0, ",/"), ++i)
+               {
+                       sscanf(t, "%d", &backg[i]);
+               }
+#endif
+#ifdef USER_SOUNDS
+       } else if (match_varname(buf, "SOUNDDIR", 8)) {
+               sounddir = (char *)strdup(bufp);
+       } else if (match_varname(buf, "SOUND", 5)) {
+               add_sound_mapping(bufp);
+#endif
+#ifdef QT_GRAPHICS
+       /* These should move to wc_ options */
+       } else if (match_varname(buf, "QT_TILEWIDTH", 12)) {
+               extern char *qt_tilewidth;
+               if (qt_tilewidth == NULL)       
+                       qt_tilewidth=(char *)strdup(bufp);
+       } else if (match_varname(buf, "QT_TILEHEIGHT", 13)) {
+               extern char *qt_tileheight;
+               if (qt_tileheight == NULL)      
+                       qt_tileheight=(char *)strdup(bufp);
+       } else if (match_varname(buf, "QT_FONTSIZE", 11)) {
+               extern char *qt_fontsize;
+               if (qt_fontsize == NULL)
+                       qt_fontsize=(char *)strdup(bufp);
+       } else if (match_varname(buf, "QT_COMPACT", 10)) {
+               extern int qt_compact_mode;
+               qt_compact_mode = atoi(bufp);
+#endif
+       } else
+               return 0;
+       return 1;
+}
+
+#ifdef USER_SOUNDS
+boolean
+can_read_file(filename)
+const char *filename;
+{
+       return (access(filename, 4) == 0);
+}
+#endif /* USER_SOUNDS */
+
+void
+read_config_file(filename)
+const char *filename;
+{
+#define tmp_levels     (char *)0
+#define tmp_ramdisk    (char *)0
+
+#if defined(MICRO) || defined(WIN32)
+#undef tmp_levels
+       char    tmp_levels[PATHLEN];
+# ifdef MFLOPPY
+#  ifndef AMIGA
+#undef tmp_ramdisk
+       char    tmp_ramdisk[PATHLEN];
+#  endif
+# endif
+#endif
+       char    buf[4*BUFSZ];
+       FILE    *fp;
+
+       if (!(fp = fopen_config_file(filename))) return;
+
+#if defined(MICRO) || defined(WIN32)
+# ifdef MFLOPPY
+#  ifndef AMIGA
+       tmp_ramdisk[0] = 0;
+#  endif
+# endif
+       tmp_levels[0] = 0;
+#endif
+       /* begin detection of duplicate configfile options */
+       set_duplicate_opt_detection(1);
+
+       while (fgets(buf, 4*BUFSZ, fp)) {
+               if (!parse_config_line(fp, buf, tmp_ramdisk, tmp_levels)) {
+                       raw_printf("Bad option line:  \"%.50s\"", buf);
+                       wait_synch();
+               }
+       }
+       (void) fclose(fp);
+       
+       /* turn off detection of duplicate configfile options */
+       set_duplicate_opt_detection(0);
+
+#if defined(MICRO) && !defined(NOCWD_ASSUMPTIONS)
+       /* should be superseded by fqn_prefix[] */
+# ifdef MFLOPPY
+       Strcpy(permbones, tmp_levels);
+#  ifndef AMIGA
+       if (tmp_ramdisk[0]) {
+               Strcpy(levels, tmp_ramdisk);
+               if (strcmp(permbones, levels))          /* if not identical */
+                       ramdisk = TRUE;
+       } else
+#  endif /* AMIGA */
+               Strcpy(levels, tmp_levels);
+
+       Strcpy(bones, levels);
+# endif /* MFLOPPY */
+#endif /* MICRO */
+       return;
+}
+
+#ifdef WIZARD
+STATIC_OVL FILE *
+fopen_wizkit_file()
+{
+       FILE *fp;
+#if defined(VMS) || defined(UNIX)
+       char    tmp_wizkit[BUFSZ];
+#endif
+       char *envp;
+
+       envp = nh_getenv("WIZKIT");
+       if (envp && *envp) (void) strncpy(wizkit, envp, WIZKIT_MAX - 1);
+       if (!wizkit[0]) return (FILE *)0;
+
+#ifdef UNIX
+       if (access(wizkit, 4) == -1) {
+               /* 4 is R_OK on newer systems */
+               /* nasty sneaky attempt to read file through
+                * NetHack's setuid permissions -- this is a
+                * place a file name may be wholly under the player's
+                * control
+                */
+               raw_printf("Access to %s denied (%d).",
+                               wizkit, errno);
+               wait_synch();
+               /* fall through to standard names */
+       } else
+#endif
+       if ((fp = fopenp(wizkit, "r")) != (FILE *)0) {
+           return(fp);
+#if defined(UNIX) || defined(VMS)
+       } else {
+           /* access() above probably caught most problems for UNIX */
+           raw_printf("Couldn't open requested config file %s (%d).",
+                               wizkit, errno);
+           wait_synch();
+#endif
+       }
+
+#if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32)
+       if ((fp = fopenp(fqname(wizkit, CONFIGPREFIX, 0), "r"))
+                                                               != (FILE *)0)
+               return(fp);
+#else
+# ifdef VMS
+       envp = nh_getenv("HOME");
+       if (envp)
+               Sprintf(tmp_wizkit, "%s%s", envp, wizkit);
+       else
+               Sprintf(tmp_wizkit, "%s%s", "sys$login:", wizkit);
+       if ((fp = fopenp(tmp_wizkit, "r")) != (FILE *)0)
+               return(fp);
+# else /* should be only UNIX left */
+       envp = nh_getenv("HOME");
+       if (envp)
+               Sprintf(tmp_wizkit, "%s/%s", envp, wizkit);
+       else    Strcpy(tmp_wizkit, wizkit);
+       if ((fp = fopenp(tmp_wizkit, "r")) != (FILE *)0)
+               return(fp);
+       else if (errno != ENOENT) {
+               /* e.g., problems when setuid NetHack can't search home
+                * directory restricted to user */
+               raw_printf("Couldn't open default wizkit file %s (%d).",
+                                       tmp_wizkit, errno);
+               wait_synch();
+       }
+# endif
+#endif
+       return (FILE *)0;
+}
+
+void
+read_wizkit()
+{
+       FILE *fp;
+       char *ep, buf[BUFSZ];
+       struct obj *otmp;
+       boolean bad_items = FALSE, skip = FALSE;
+
+       if (!wizard || !(fp = fopen_wizkit_file())) return;
+
+       while (fgets(buf, (int)(sizeof buf), fp)) {
+           ep = index(buf, '\n');
+           if (skip) { /* in case previous line was too long */
+               if (ep) skip = FALSE; /* found newline; next line is normal */
+           } else {
+               if (!ep) skip = TRUE; /* newline missing; discard next fgets */
+               else *ep = '\0';                /* remove newline */
+
+               if (buf[0]) {
+                       otmp = readobjnam(buf, (struct obj *)0, FALSE);
+                       if (otmp) {
+                           if (otmp != &zeroobj)
+                               otmp = addinv(otmp);
+                       } else {
+                           /* .60 limits output line width to 79 chars */
+                           raw_printf("Bad wizkit item: \"%.60s\"", buf);
+                           bad_items = TRUE;
+                       }
+               }
+           }
+       }
+       if (bad_items)
+           wait_synch();
+       (void) fclose(fp);
+       return;
+}
+
+#endif /*WIZARD*/
+
+/* ----------  END CONFIG FILE HANDLING ----------- */
+
+/* ----------  BEGIN SCOREBOARD CREATION ----------- */
+
+/* verify that we can write to the scoreboard file; if not, try to create one */
+void
+check_recordfile(dir)
+const char *dir;
+{
+#if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__)
+# pragma unused(dir)
+#endif
+       const char *fq_record;
+       int fd;
+
+#if defined(UNIX) || defined(VMS)
+       fq_record = fqname(RECORD, SCOREPREFIX, 0);
+       fd = open(fq_record, O_RDWR, 0);
+       if (fd >= 0) {
+# ifdef VMS    /* must be stream-lf to use UPDATE_RECORD_IN_PLACE */
+               if (!file_is_stmlf(fd)) {
+                   raw_printf(
+                 "Warning: scoreboard file %s is not in stream_lf format",
+                               fq_record);
+                   wait_synch();
+               }
+# endif
+           (void) close(fd);   /* RECORD is accessible */
+       } else if ((fd = open(fq_record, O_CREAT|O_RDWR, FCMASK)) >= 0) {
+           (void) close(fd);   /* RECORD newly created */
+# if defined(VMS) && !defined(SECURE)
+           /* Re-protect RECORD with world:read+write+execute+delete access. */
+           (void) chmod(fq_record, FCMASK | 007);
+# endif /* VMS && !SECURE */
+       } else {
+           raw_printf("Warning: cannot write scoreboard file %s", fq_record);
+           wait_synch();
+       }
+#endif  /* !UNIX && !VMS */
+#if defined(MICRO) || defined(WIN32)
+       char tmp[PATHLEN];
+
+# ifdef OS2_CODEVIEW   /* explicit path on opening for OS/2 */
+       /* how does this work when there isn't an explicit path or fopenp
+        * for later access to the file via fopen_datafile? ? */
+       (void) strncpy(tmp, dir, PATHLEN - 1);
+       tmp[PATHLEN-1] = '\0';
+       if ((strlen(tmp) + 1 + strlen(RECORD)) < (PATHLEN - 1)) {
+               append_slash(tmp);
+               Strcat(tmp, RECORD);
+       }
+       fq_record = tmp;
+# else
+       Strcpy(tmp, RECORD);
+       fq_record = fqname(RECORD, SCOREPREFIX, 0);
+# endif
+
+       if ((fd = open(fq_record, O_RDWR)) < 0) {
+           /* try to create empty record */
+# if defined(AZTEC_C) || defined(_DCC) || (defined(__GNUC__) && defined(__AMIGA__))
+           /* Aztec doesn't use the third argument */
+           /* DICE doesn't like it */
+           if ((fd = open(fq_record, O_CREAT|O_RDWR)) < 0) {
+# else
+           if ((fd = open(fq_record, O_CREAT|O_RDWR, S_IREAD|S_IWRITE)) < 0) {
+# endif
+       raw_printf("Warning: cannot write record %s", tmp);
+               wait_synch();
+           } else
+               (void) close(fd);
+       } else          /* open succeeded */
+           (void) close(fd);
+#else /* MICRO || WIN32*/
+
+# ifdef MAC
+       /* Create the "record" file, if necessary */
+       fq_record = fqname(RECORD, SCOREPREFIX, 0);
+       fd = macopen (fq_record, O_RDWR | O_CREAT, TEXT_TYPE);
+       if (fd != -1) macclose (fd);
+# endif /* MAC */
+
+#endif /* MICRO || WIN32*/
+}
+
+/* ----------  END SCOREBOARD CREATION ----------- */
+
+/* ----------  BEGIN PANIC/IMPOSSIBLE LOG ----------- */
+
+/*ARGSUSED*/
+void
+paniclog(type, reason)
+const char *type;      /* panic, impossible, trickery */
+const char *reason;    /* explanation */
+{
+#ifdef PANICLOG
+       FILE *lfile;
+       char buf[BUFSZ];
+
+       if (!program_state.in_paniclog) {
+               program_state.in_paniclog = 1;
+               lfile = fopen_datafile(PANICLOG, "a", TROUBLEPREFIX);
+               if (lfile) {
+                   (void) fprintf(lfile, "%s %08ld: %s %s\n",
+                                  version_string(buf), yyyymmdd((time_t)0L),
+                                  type, reason);
+                   (void) fclose(lfile);
+               }
+               program_state.in_paniclog = 0;
+       }
+#endif /* PANICLOG */
+       return;
+}
+
+/* ----------  END PANIC/IMPOSSIBLE LOG ----------- */
+
+#ifdef SELF_RECOVER
+
+/* ----------  BEGIN INTERNAL RECOVER ----------- */
+boolean
+recover_savefile()
+{
+       int gfd, lfd, sfd;
+       int lev, savelev, hpid;
+       xchar levc;
+       struct version_info version_data;
+       int processed[256];
+       char savename[SAVESIZE], errbuf[BUFSZ];
+
+       for (lev = 0; lev < 256; lev++)
+               processed[lev] = 0;
+
+       /* level 0 file contains:
+        *      pid of creating process (ignored here)
+        *      level number for current level of save file
+        *      name of save file nethack would have created
+        *      and game state
+        */
+       gfd = open_levelfile(0, errbuf);
+       if (gfd < 0) {
+           raw_printf("%s\n", errbuf);
+           return FALSE;
+       }
+       if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) {
+           raw_printf(
+"\nCheckpoint data incompletely written or subsequently clobbered. Recovery impossible.");
+           (void)close(gfd);
+           return FALSE;
+       }
+       if (read(gfd, (genericptr_t) &savelev, sizeof(savelev))
+                                                       != sizeof(savelev)) {
+           raw_printf("\nCheckpointing was not in effect for %s -- recovery impossible.\n",
+                       lock);
+           (void)close(gfd);
+           return FALSE;
+       }
+       if ((read(gfd, (genericptr_t) savename, sizeof savename)
+               != sizeof savename) ||
+           (read(gfd, (genericptr_t) &version_data, sizeof version_data)
+               != sizeof version_data)) {
+           raw_printf("\nError reading %s -- can't recover.\n", lock);
+           (void)close(gfd);
+           return FALSE;
+       }
+
+       /* save file should contain:
+        *      version info
+        *      current level (including pets)
+        *      (non-level-based) game state
+        *      other levels
+        */
+       set_savefile_name();
+       sfd = create_savefile();
+       if (sfd < 0) {
+           raw_printf("\nCannot recover savefile %s.\n", SAVEF);
+           (void)close(gfd);
+           return FALSE;
+       }
+
+       lfd = open_levelfile(savelev, errbuf);
+       if (lfd < 0) {
+           raw_printf("\n%s\n", errbuf);
+           (void)close(gfd);
+           (void)close(sfd);
+           delete_savefile();
+           return FALSE;
+       }
+
+       if (write(sfd, (genericptr_t) &version_data, sizeof version_data)
+               != sizeof version_data) {
+           raw_printf("\nError writing %s; recovery failed.", SAVEF);
+           (void)close(gfd);
+           (void)close(sfd);
+           delete_savefile();
+           return FALSE;
+       }
+
+       if (!copy_bytes(lfd, sfd)) {
+               (void) close(lfd);
+               (void) close(sfd);
+               delete_savefile();
+               return FALSE;
+       }
+       (void)close(lfd);
+       processed[savelev] = 1;
+
+       if (!copy_bytes(gfd, sfd)) {
+               (void) close(lfd);
+               (void) close(sfd);
+               delete_savefile();
+               return FALSE;
+       }
+       (void)close(gfd);
+       processed[0] = 1;
+
+       for (lev = 1; lev < 256; lev++) {
+               /* level numbers are kept in xchars in save.c, so the
+                * maximum level number (for the endlevel) must be < 256
+                */
+               if (lev != savelev) {
+                       lfd = open_levelfile(lev, (char *)0);
+                       if (lfd >= 0) {
+                               /* any or all of these may not exist */
+                               levc = (xchar) lev;
+                               write(sfd, (genericptr_t) &levc, sizeof(levc));
+                               if (!copy_bytes(lfd, sfd)) {
+                                       (void) close(lfd);
+                                       (void) close(sfd);
+                                       delete_savefile();
+                                       return FALSE;
+                               }
+                               (void)close(lfd);
+                               processed[lev] = 1;
+                       }
+               }
+       }
+       (void)close(sfd);
+
+#ifdef HOLD_LOCKFILE_OPEN
+       really_close();
+#endif
+       /*
+        * We have a successful savefile!
+        * Only now do we erase the level files.
+        */
+       for (lev = 0; lev < 256; lev++) {
+               if (processed[lev]) {
+                       const char *fq_lock;
+                       set_levelfile_name(lock, lev);
+                       fq_lock = fqname(lock, LEVELPREFIX, 3);
+                       (void) unlink(fq_lock);
+               }
+       }
+       return TRUE;
+}
+
+boolean
+copy_bytes(ifd, ofd)
+int ifd, ofd;
+{
+       char buf[BUFSIZ];
+       int nfrom, nto;
+
+       do {
+               nfrom = read(ifd, buf, BUFSIZ);
+               nto = write(ofd, buf, nfrom);
+               if (nto != nfrom) return FALSE;
+       } while (nfrom == BUFSIZ);
+       return TRUE;
+}
+
+/* ----------  END INTERNAL RECOVER ----------- */
+#endif /*SELF_RECOVER*/
+
+/*files.c*/
diff --git a/src/fountain.c b/src/fountain.c
new file mode 100644 (file)
index 0000000..a1b4249
--- /dev/null
@@ -0,0 +1,602 @@
+/*     SCCS Id: @(#)fountain.c 3.4     2003/03/23      */
+/*     Copyright Scott R. Turner, srt@ucla, 10/27/86 */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* Code for drinking from fountains. */
+
+#include "hack.h"
+
+STATIC_DCL void NDECL(dowatersnakes);
+STATIC_DCL void NDECL(dowaterdemon);
+STATIC_DCL void NDECL(dowaternymph);
+STATIC_PTR void FDECL(gush, (int,int,genericptr_t));
+STATIC_DCL void NDECL(dofindgem);
+
+void
+floating_above(what)
+const char *what;
+{
+    You("are floating high above the %s.", what);
+}
+
+STATIC_OVL void
+dowatersnakes() /* Fountain of snakes! */
+{
+    register int num = rn1(5,2);
+    struct monst *mtmp;
+
+    if (!(mvitals[PM_WATER_MOCCASIN].mvflags & G_GONE)) {
+       if (!Blind)
+           pline("An endless stream of %s pours forth!",
+                 Hallucination ? makeplural(rndmonnam()) : "snakes");
+       else
+           You_hear("%s hissing!", something);
+       while(num-- > 0)
+           if((mtmp = makemon(&mons[PM_WATER_MOCCASIN],
+                       u.ux, u.uy, NO_MM_FLAGS)) && t_at(mtmp->mx, mtmp->my))
+               (void) mintrap(mtmp);
+    } else
+       pline_The("fountain bubbles furiously for a moment, then calms.");
+}
+
+STATIC_OVL
+void
+dowaterdemon() /* Water demon */
+{
+    register struct monst *mtmp;
+
+    if(!(mvitals[PM_WATER_DEMON].mvflags & G_GONE)) {
+       if((mtmp = makemon(&mons[PM_WATER_DEMON],u.ux,u.uy, NO_MM_FLAGS))) {
+           if (!Blind)
+               You("unleash %s!", a_monnam(mtmp));
+           else
+               You_feel("the presence of evil.");
+
+       /* Give those on low levels a (slightly) better chance of survival */
+           if (rnd(100) > (80 + level_difficulty())) {
+               pline("Grateful for %s release, %s grants you a wish!",
+                     mhis(mtmp), mhe(mtmp));
+               makewish();
+               mongone(mtmp);
+           } else if (t_at(mtmp->mx, mtmp->my))
+               (void) mintrap(mtmp);
+       }
+    } else
+       pline_The("fountain bubbles furiously for a moment, then calms.");
+}
+
+STATIC_OVL void
+dowaternymph() /* Water Nymph */
+{
+       register struct monst *mtmp;
+
+       if(!(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) &&
+          (mtmp = makemon(&mons[PM_WATER_NYMPH],u.ux,u.uy, NO_MM_FLAGS))) {
+               if (!Blind)
+                  You("attract %s!", a_monnam(mtmp));
+               else
+                  You_hear("a seductive voice.");
+               mtmp->msleeping = 0;
+               if (t_at(mtmp->mx, mtmp->my))
+                   (void) mintrap(mtmp);
+       } else
+               if (!Blind)
+                  pline("A large bubble rises to the surface and pops.");
+               else
+                  You_hear("a loud pop.");
+}
+
+void
+dogushforth(drinking) /* Gushing forth along LOS from (u.ux, u.uy) */
+int drinking;
+{
+       int madepool = 0;
+
+       do_clear_area(u.ux, u.uy, 7, gush, (genericptr_t)&madepool);
+       if (!madepool) {
+           if (drinking)
+               Your("thirst is quenched.");
+           else
+               pline("Water sprays all over you.");
+       }
+}
+
+STATIC_PTR void
+gush(x, y, poolcnt)
+int x, y;
+genericptr_t poolcnt;
+{
+       register struct monst *mtmp;
+       register struct trap *ttmp;
+
+       if (((x+y)%2) || (x == u.ux && y == u.uy) ||
+           (rn2(1 + distmin(u.ux, u.uy, x, y)))  ||
+           (levl[x][y].typ != ROOM) ||
+           (sobj_at(BOULDER, x, y)) || nexttodoor(x, y))
+               return;
+
+       if ((ttmp = t_at(x, y)) != 0 && !delfloortrap(ttmp))
+               return;
+
+       if (!((*(int *)poolcnt)++))
+           pline("Water gushes forth from the overflowing fountain!");
+
+       /* Put a pool at x, y */
+       levl[x][y].typ = POOL;
+       /* No kelp! */
+       del_engr_at(x, y);
+       water_damage(level.objects[x][y], FALSE, TRUE);
+
+       if ((mtmp = m_at(x, y)) != 0)
+               (void) minliquid(mtmp);
+       else
+               newsym(x,y);
+}
+
+STATIC_OVL void
+dofindgem() /* Find a gem in the sparkling waters. */
+{
+       if (!Blind) You("spot a gem in the sparkling waters!");
+       else You_feel("a gem here!");
+       (void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE-1),
+                        u.ux, u.uy, FALSE, FALSE);
+       SET_FOUNTAIN_LOOTED(u.ux,u.uy);
+       newsym(u.ux, u.uy);
+       exercise(A_WIS, TRUE);                  /* a discovery! */
+}
+
+void
+dryup(x, y, isyou)
+xchar x, y;
+boolean isyou;
+{
+       if (IS_FOUNTAIN(levl[x][y].typ) &&
+           (!rn2(3) || FOUNTAIN_IS_WARNED(x,y))) {
+               if(isyou && in_town(x, y) && !FOUNTAIN_IS_WARNED(x,y)) {
+                       struct monst *mtmp;
+                       SET_FOUNTAIN_WARNED(x,y);
+                       /* Warn about future fountain use. */
+                       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+                           if (DEADMONSTER(mtmp)) continue;
+                           if ((mtmp->data == &mons[PM_WATCHMAN] ||
+                               mtmp->data == &mons[PM_WATCH_CAPTAIN]) &&
+                              couldsee(mtmp->mx, mtmp->my) &&
+                              mtmp->mpeaceful) {
+                               pline("%s yells:", Amonnam(mtmp));
+                               verbalize("Hey, stop using that fountain!");
+                               break;
+                           }
+                       }
+                       /* You can see or hear this effect */
+                       if(!mtmp) pline_The("flow reduces to a trickle.");
+                       return;
+               }
+#ifdef WIZARD
+               if (isyou && wizard) {
+                       if (yn("Dry up fountain?") == 'n')
+                               return;
+               }
+#endif
+               /* replace the fountain with ordinary floor */
+               levl[x][y].typ = ROOM;
+               levl[x][y].looted = 0;
+               levl[x][y].blessedftn = 0;
+               if (cansee(x,y)) pline_The("fountain dries up!");
+               /* The location is seen if the hero/monster is invisible */
+               /* or felt if the hero is blind.                         */
+               newsym(x, y);
+               level.flags.nfountains--;
+               if(isyou && in_town(x, y))
+                   (void) angry_guards(FALSE);
+       }
+}
+
+void
+drinkfountain()
+{
+       /* What happens when you drink from a fountain? */
+       register boolean mgkftn = (levl[u.ux][u.uy].blessedftn == 1);
+       register int fate = rnd(30);
+
+       if (Levitation) {
+               floating_above("fountain");
+               return;
+       }
+
+       if (mgkftn && u.uluck >= 0 && fate >= 10) {
+               int i, ii, littleluck = (u.uluck < 4);
+
+               pline("Wow!  This makes you feel great!");
+               /* blessed restore ability */
+               for (ii = 0; ii < A_MAX; ii++)
+                   if (ABASE(ii) < AMAX(ii)) {
+                       ABASE(ii) = AMAX(ii);
+                       flags.botl = 1;
+                   }
+               /* gain ability, blessed if "natural" luck is high */
+               i = rn2(A_MAX);         /* start at a random attribute */
+               for (ii = 0; ii < A_MAX; ii++) {
+                   if (adjattrib(i, 1, littleluck ? -1 : 0) && littleluck)
+                       break;
+                   if (++i >= A_MAX) i = 0;
+               }
+               display_nhwindow(WIN_MESSAGE, FALSE);
+               pline("A wisp of vapor escapes the fountain...");
+               exercise(A_WIS, TRUE);
+               levl[u.ux][u.uy].blessedftn = 0;
+               return;
+       }
+
+       if (fate < 10) {
+               pline_The("cool draught refreshes you.");
+               u.uhunger += rnd(10); /* don't choke on water */
+               newuhs(FALSE);
+               if(mgkftn) return;
+       } else {
+           switch (fate) {
+
+               case 19: /* Self-knowledge */
+
+                       You_feel("self-knowledgeable...");
+                       display_nhwindow(WIN_MESSAGE, FALSE);
+                       enlightenment(0);
+                       exercise(A_WIS, TRUE);
+                       pline_The("feeling subsides.");
+                       break;
+
+               case 20: /* Foul water */
+
+                       pline_The("water is foul!  You gag and vomit.");
+                       morehungry(rn1(20, 11));
+                       vomit();
+                       break;
+
+               case 21: /* Poisonous */
+
+                       pline_The("water is contaminated!");
+                       if (Poison_resistance) {
+                          pline(
+                             "Perhaps it is runoff from the nearby %s farm.",
+                                fruitname(FALSE));
+                          losehp(rnd(4),"unrefrigerated sip of juice",
+                               KILLED_BY_AN);
+                          break;
+                       }
+                       losestr(rn1(4,3));
+                       losehp(rnd(10),"contaminated water", KILLED_BY);
+                       exercise(A_CON, FALSE);
+                       break;
+
+               case 22: /* Fountain of snakes! */
+
+                       dowatersnakes();
+                       break;
+
+               case 23: /* Water demon */
+                       dowaterdemon();
+                       break;
+
+               case 24: /* Curse an item */ {
+                       register struct obj *obj;
+
+                       pline("This water's no good!");
+                       morehungry(rn1(20, 11));
+                       exercise(A_CON, FALSE);
+                       for(obj = invent; obj ; obj = obj->nobj)
+                               if (!rn2(5))    curse(obj);
+                       break;
+                       }
+
+               case 25: /* See invisible */
+
+                       if (Blind) {
+                           if (Invisible) {
+                               You("feel transparent.");
+                           } else {
+                               You("feel very self-conscious.");
+                               pline("Then it passes.");
+                           }
+                       } else {
+                          You("see an image of someone stalking you.");
+                          pline("But it disappears.");
+                       }
+                       HSee_invisible |= FROMOUTSIDE;
+                       newsym(u.ux,u.uy);
+                       exercise(A_WIS, TRUE);
+                       break;
+
+               case 26: /* See Monsters */
+
+                       (void) monster_detect((struct obj *)0, 0);
+                       exercise(A_WIS, TRUE);
+                       break;
+
+               case 27: /* Find a gem in the sparkling waters. */
+
+                       if (!FOUNTAIN_IS_LOOTED(u.ux,u.uy)) {
+                               dofindgem();
+                               break;
+                       }
+
+               case 28: /* Water Nymph */
+
+                       dowaternymph();
+                       break;
+
+               case 29: /* Scare */ {
+                       register struct monst *mtmp;
+
+                       pline("This water gives you bad breath!");
+                       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+                           if(!DEADMONSTER(mtmp))
+                               monflee(mtmp, 0, FALSE, FALSE);
+                       }
+                       break;
+
+               case 30: /* Gushing forth in this room */
+
+                       dogushforth(TRUE);
+                       break;
+
+               default:
+
+                       pline("This tepid water is tasteless.");
+                       break;
+           }
+       }
+       dryup(u.ux, u.uy, TRUE);
+}
+
+void
+dipfountain(obj)
+register struct obj *obj;
+{
+       if (Levitation) {
+               floating_above("fountain");
+               return;
+       }
+
+       /* Don't grant Excalibur when there's more than one object.  */
+       /* (quantity could be > 1 if merged daggers got polymorphed) */
+       if (obj->otyp == LONG_SWORD && obj->quan == 1L
+           && u.ulevel >= 5 && !rn2(6)
+           && !obj->oartifact
+           && !exist_artifact(LONG_SWORD, artiname(ART_EXCALIBUR))) {
+
+               if (u.ualign.type != A_LAWFUL) {
+                       /* Ha!  Trying to cheat her. */
+                       pline("A freezing mist rises from the water and envelopes the sword.");
+                       pline_The("fountain disappears!");
+                       curse(obj);
+                       if (obj->spe > -6 && !rn2(3)) obj->spe--;
+                       obj->oerodeproof = FALSE;
+                       exercise(A_WIS, FALSE);
+               } else {
+                       /* The lady of the lake acts! - Eric Backus */
+                       /* Be *REAL* nice */
+         pline("From the murky depths, a hand reaches up to bless the sword.");
+                       pline("As the hand retreats, the fountain disappears!");
+                       obj = oname(obj, artiname(ART_EXCALIBUR));
+                       discover_artifact(ART_EXCALIBUR);
+                       bless(obj);
+                       obj->oeroded = obj->oeroded2 = 0;
+                       obj->oerodeproof = TRUE;
+                       exercise(A_WIS, TRUE);
+               }
+               update_inventory();
+               levl[u.ux][u.uy].typ = ROOM;
+               levl[u.ux][u.uy].looted = 0;
+               newsym(u.ux, u.uy);
+               level.flags.nfountains--;
+               if(in_town(u.ux, u.uy))
+                   (void) angry_guards(FALSE);
+               return;
+       } else if (get_wet(obj) && !rn2(2))
+               return;
+
+       /* Acid and water don't mix */
+       if (obj->otyp == POT_ACID) {
+           useup(obj);
+           return;
+       }
+
+       switch (rnd(30)) {
+               case 16: /* Curse the item */
+                       curse(obj);
+                       break;
+               case 17:
+               case 18:
+               case 19:
+               case 20: /* Uncurse the item */
+                       if(obj->cursed) {
+                           if (!Blind)
+                               pline_The("water glows for a moment.");
+                           uncurse(obj);
+                       } else {
+                           pline("A feeling of loss comes over you.");
+                       }
+                       break;
+               case 21: /* Water Demon */
+                       dowaterdemon();
+                       break;
+               case 22: /* Water Nymph */
+                       dowaternymph();
+                       break;
+               case 23: /* an Endless Stream of Snakes */
+                       dowatersnakes();
+                       break;
+               case 24: /* Find a gem */
+                       if (!FOUNTAIN_IS_LOOTED(u.ux,u.uy)) {
+                               dofindgem();
+                               break;
+                       }
+               case 25: /* Water gushes forth */
+                       dogushforth(FALSE);
+                       break;
+               case 26: /* Strange feeling */
+                       pline("A strange tingling runs up your %s.",
+                                                       body_part(ARM));
+                       break;
+               case 27: /* Strange feeling */
+                       You_feel("a sudden chill.");
+                       break;
+               case 28: /* Strange feeling */
+                       pline("An urge to take a bath overwhelms you.");
+#ifndef GOLDOBJ
+                       if (u.ugold > 10) {
+                           u.ugold -= somegold() / 10;
+                           You("lost some of your gold in the fountain!");
+                           CLEAR_FOUNTAIN_LOOTED(u.ux,u.uy);
+                           exercise(A_WIS, FALSE);
+                       }
+#else
+                       {
+                           long money = money_cnt(invent);
+                           struct obj *otmp;
+                            if (money > 10) {
+                               /* Amount to loose.  Might get rounded up as fountains don't pay change... */
+                               money = somegold(money) / 10; 
+                               for (otmp = invent; otmp && money > 0; otmp = otmp->nobj) if (otmp->oclass == COIN_CLASS) {
+                                   int denomination = objects[otmp->otyp].oc_cost;
+                                   long coin_loss = (money + denomination - 1) / denomination;
+                                    coin_loss = min(coin_loss, otmp->quan);
+                                   otmp->quan -= coin_loss;
+                                   money -= coin_loss * denomination;                            
+                                   if (!otmp->quan) delobj(otmp);
+                               }
+                               You("lost some of your money in the fountain!");
+                               CLEAR_FOUNTAIN_LOOTED(u.ux,u.uy);
+                               exercise(A_WIS, FALSE);
+                            }
+                       }
+#endif
+                       break;
+               case 29: /* You see coins */
+
+               /* We make fountains have more coins the closer you are to the
+                * surface.  After all, there will have been more people going
+                * by.  Just like a shopping mall!  Chris Woodbury  */
+
+                   if (FOUNTAIN_IS_LOOTED(u.ux,u.uy)) break;
+                   SET_FOUNTAIN_LOOTED(u.ux,u.uy);
+                   (void) mkgold((long)
+                       (rnd((dunlevs_in_dungeon(&u.uz)-dunlev(&u.uz)+1)*2)+5),
+                       u.ux, u.uy);
+                   if (!Blind)
+               pline("Far below you, you see coins glistening in the water.");
+                   exercise(A_WIS, TRUE);
+                   newsym(u.ux,u.uy);
+                   break;
+       }
+       update_inventory();
+       dryup(u.ux, u.uy, TRUE);
+}
+
+#ifdef SINKS
+void
+breaksink(x,y)
+int x, y;
+{
+    if(cansee(x,y) || (x == u.ux && y == u.uy))
+       pline_The("pipes break!  Water spurts out!");
+    level.flags.nsinks--;
+    levl[x][y].doormask = 0;
+    levl[x][y].typ = FOUNTAIN;
+    level.flags.nfountains++;
+    newsym(x,y);
+}
+
+void
+drinksink()
+{
+       struct obj *otmp;
+       struct monst *mtmp;
+
+       if (Levitation) {
+               floating_above("sink");
+               return;
+       }
+       switch(rn2(20)) {
+               case 0: You("take a sip of very cold water.");
+                       break;
+               case 1: You("take a sip of very warm water.");
+                       break;
+               case 2: You("take a sip of scalding hot water.");
+                       if (Fire_resistance)
+                               pline("It seems quite tasty.");
+                       else losehp(rnd(6), "sipping boiling water", KILLED_BY);
+                       break;
+               case 3: if (mvitals[PM_SEWER_RAT].mvflags & G_GONE)
+                               pline_The("sink seems quite dirty.");
+                       else {
+                               mtmp = makemon(&mons[PM_SEWER_RAT],
+                                               u.ux, u.uy, NO_MM_FLAGS);
+                               if (mtmp) pline("Eek!  There's %s in the sink!",
+                                       (Blind || !canspotmon(mtmp)) ?
+                                       "something squirmy" :
+                                       a_monnam(mtmp));
+                       }
+                       break;
+               case 4: do {
+                               otmp = mkobj(POTION_CLASS,FALSE);
+                               if (otmp->otyp == POT_WATER) {
+                                       obfree(otmp, (struct obj *)0);
+                                       otmp = (struct obj *) 0;
+                               }
+                       } while(!otmp);
+                       otmp->cursed = otmp->blessed = 0;
+                       pline("Some %s liquid flows from the faucet.",
+                             Blind ? "odd" :
+                             hcolor(OBJ_DESCR(objects[otmp->otyp])));
+                       otmp->dknown = !(Blind || Hallucination);
+                       otmp->quan++; /* Avoid panic upon useup() */
+                       otmp->fromsink = 1; /* kludge for docall() */
+                       (void) dopotion(otmp);
+                       obfree(otmp, (struct obj *)0);
+                       break;
+               case 5: if (!(levl[u.ux][u.uy].looted & S_LRING)) {
+                           You("find a ring in the sink!");
+                           (void) mkobj_at(RING_CLASS, u.ux, u.uy, TRUE);
+                           levl[u.ux][u.uy].looted |= S_LRING;
+                           exercise(A_WIS, TRUE);
+                           newsym(u.ux,u.uy);
+                       } else pline("Some dirty water backs up in the drain.");
+                       break;
+               case 6: breaksink(u.ux,u.uy);
+                       break;
+               case 7: pline_The("water moves as though of its own will!");
+                       if ((mvitals[PM_WATER_ELEMENTAL].mvflags & G_GONE)
+                           || !makemon(&mons[PM_WATER_ELEMENTAL],
+                                       u.ux, u.uy, NO_MM_FLAGS))
+                               pline("But it quiets down.");
+                       break;
+               case 8: pline("Yuk, this water tastes awful.");
+                       more_experienced(1,0);
+                       newexplevel();
+                       break;
+               case 9: pline("Gaggg... this tastes like sewage!  You vomit.");
+                       morehungry(rn1(30-ACURR(A_CON), 11));
+                       vomit();
+                       break;
+               case 10: pline("This water contains toxic wastes!");
+                       if (!Unchanging) {
+                               You("undergo a freakish metamorphosis!");
+                               polyself(FALSE);
+                       }
+                       break;
+               /* more odd messages --JJB */
+               case 11: You_hear("clanking from the pipes...");
+                       break;
+               case 12: You_hear("snatches of song from among the sewers...");
+                       break;
+               case 19: if (Hallucination) {
+                  pline("From the murky drain, a hand reaches up... --oops--");
+                               break;
+                       }
+               default: You("take a sip of %s water.",
+                       rn2(3) ? (rn2(2) ? "cold" : "warm") : "hot");
+       }
+}
+#endif /* SINKS */
+
+/*fountain.c*/
diff --git a/src/hack.c b/src/hack.c
new file mode 100644 (file)
index 0000000..0e89c3b
--- /dev/null
@@ -0,0 +1,2303 @@
+/*     SCCS Id: @(#)hack.c     3.4     2003/04/30      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+#ifdef OVL1
+STATIC_DCL void NDECL(maybe_wail);
+#endif /*OVL1*/
+STATIC_DCL int NDECL(moverock);
+STATIC_DCL int FDECL(still_chewing,(XCHAR_P,XCHAR_P));
+#ifdef SINKS
+STATIC_DCL void NDECL(dosinkfall);
+#endif
+STATIC_DCL boolean FDECL(findtravelpath, (BOOLEAN_P));
+STATIC_DCL boolean FDECL(monstinroom, (struct permonst *,int));
+
+STATIC_DCL void FDECL(move_update, (BOOLEAN_P));
+
+#define IS_SHOP(x)     (rooms[x].rtype >= SHOPBASE)
+
+#ifdef OVL2
+
+boolean
+revive_nasty(x, y, msg)
+int x,y;
+const char *msg;
+{
+    register struct obj *otmp, *otmp2;
+    struct monst *mtmp;
+    coord cc;
+    boolean revived = FALSE;
+
+    for(otmp = level.objects[x][y]; otmp; otmp = otmp2) {
+       otmp2 = otmp->nexthere;
+       if (otmp->otyp == CORPSE &&
+           (is_rider(&mons[otmp->corpsenm]) ||
+            otmp->corpsenm == PM_WIZARD_OF_YENDOR)) {
+           /* move any living monster already at that location */
+           if((mtmp = m_at(x,y)) && enexto(&cc, x, y, mtmp->data))
+               rloc_to(mtmp, cc.x, cc.y);
+           if(msg) Norep("%s", msg);
+           revived = revive_corpse(otmp);
+       }
+    }
+
+    /* this location might not be safe, if not, move revived monster */
+    if (revived) {
+       mtmp = m_at(x,y);
+       if (mtmp && !goodpos(x, y, mtmp, 0) &&
+           enexto(&cc, x, y, mtmp->data)) {
+           rloc_to(mtmp, cc.x, cc.y);
+       }
+       /* else impossible? */
+    }
+
+    return (revived);
+}
+
+STATIC_OVL int
+moverock()
+{
+    register xchar rx, ry, sx, sy;
+    register struct obj *otmp;
+    register struct trap *ttmp;
+    register struct monst *mtmp;
+
+    sx = u.ux + u.dx,  sy = u.uy + u.dy;       /* boulder starting position */
+    while ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
+       /* make sure that this boulder is visible as the top object */
+       if (otmp != level.objects[sx][sy]) movobj(otmp, sx, sy);
+
+       rx = u.ux + 2 * u.dx;   /* boulder destination position */
+       ry = u.uy + 2 * u.dy;
+       nomul(0);
+       if (Levitation || Is_airlevel(&u.uz)) {
+           if (Blind) feel_location(sx, sy);
+           You("don't have enough leverage to push %s.", the(xname(otmp)));
+           /* Give them a chance to climb over it? */
+           return -1;
+       }
+       if (verysmall(youmonst.data)
+#ifdef STEED
+                && !u.usteed
+#endif
+                                   ) {
+           if (Blind) feel_location(sx, sy);
+           pline("You're too small to push that %s.", xname(otmp));
+           goto cannot_push;
+       }
+       if (isok(rx,ry) && !IS_ROCK(levl[rx][ry].typ) &&
+           levl[rx][ry].typ != IRONBARS &&
+           (!IS_DOOR(levl[rx][ry].typ) || !(u.dx && u.dy) || (
+#ifdef REINCARNATION
+               !Is_rogue_level(&u.uz) &&
+#endif
+               (levl[rx][ry].doormask & ~D_BROKEN) == D_NODOOR)) &&
+           !sobj_at(BOULDER, rx, ry)) {
+           ttmp = t_at(rx, ry);
+           mtmp = m_at(rx, ry);
+
+               /* KMH -- Sokoban doesn't let you push boulders diagonally */
+           if (In_sokoban(&u.uz) && u.dx && u.dy) {
+               if (Blind) feel_location(sx,sy);
+               pline("%s won't roll diagonally on this %s.",
+                               The(xname(otmp)), surface(sx, sy));
+               goto cannot_push;
+           }
+
+           if (revive_nasty(rx, ry, "You sense movement on the other side."))
+               return (-1);
+
+           if (mtmp && !noncorporeal(mtmp->data) &&
+                   (!mtmp->mtrapped ||
+                        !(ttmp && ((ttmp->ttyp == PIT) ||
+                                   (ttmp->ttyp == SPIKED_PIT))))) {
+               if (Blind) feel_location(sx, sy);
+               if (canspotmon(mtmp))
+                   pline("There's %s on the other side.", a_monnam(mtmp));
+               else {
+                   You_hear("a monster behind %s.", the(xname(otmp)));
+                   map_invisible(rx, ry);
+               }
+               if (flags.verbose)
+                   pline("Perhaps that's why %s cannot move it.",
+#ifdef STEED
+                               u.usteed ? y_monnam(u.usteed) :
+#endif
+                               "you");
+               goto cannot_push;
+           }
+
+           if (ttmp)
+               switch(ttmp->ttyp) {
+               case LANDMINE:
+                   if (rn2(10)) {
+                       obj_extract_self(otmp);
+                       place_object(otmp, rx, ry);
+                       unblock_point(sx, sy);
+                       newsym(sx, sy);
+                       pline("KAABLAMM!!!  %s %s land mine.",
+                             Tobjnam(otmp, "trigger"),
+                             ttmp->madeby_u ? "your" : "a");
+                       blow_up_landmine(ttmp);
+                       /* if the boulder remains, it should fill the pit */
+                       fill_pit(u.ux, u.uy);
+                       if (cansee(rx,ry)) newsym(rx,ry);
+                       continue;
+                   }
+                   break;
+               case SPIKED_PIT:
+               case PIT:
+                   obj_extract_self(otmp);
+                   /* vision kludge to get messages right;
+                      the pit will temporarily be seen even
+                      if this is one among multiple boulders */
+                   if (!Blind) viz_array[ry][rx] |= IN_SIGHT;
+                   if (!flooreffects(otmp, rx, ry, "fall")) {
+                       place_object(otmp, rx, ry);
+                   }
+                   if (mtmp && !Blind) newsym(rx, ry);
+                   continue;
+               case HOLE:
+               case TRAPDOOR:
+                   if (Blind)
+                       pline("Kerplunk!  You no longer feel %s.",
+                               the(xname(otmp)));
+                   else
+                       pline("%s%s and %s a %s in the %s!",
+                         Tobjnam(otmp,
+                          (ttmp->ttyp == TRAPDOOR) ? "trigger" : "fall"),
+                         (ttmp->ttyp == TRAPDOOR) ? nul : " into",
+                         otense(otmp, "plug"),
+                         (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole",
+                         surface(rx, ry));
+                   deltrap(ttmp);
+                   delobj(otmp);
+                   bury_objs(rx, ry);
+                   if (cansee(rx,ry)) newsym(rx,ry);
+                   continue;
+               case LEVEL_TELEP:
+               case TELEP_TRAP:
+#ifdef STEED
+                   if (u.usteed)
+                       pline("%s pushes %s and suddenly it disappears!",
+                             upstart(y_monnam(u.usteed)), the(xname(otmp)));
+                   else
+#endif
+                   You("push %s and suddenly it disappears!",
+                       the(xname(otmp)));
+                   if (ttmp->ttyp == TELEP_TRAP)
+                       rloco(otmp);
+                   else {
+                       int newlev = random_teleport_level();
+                       d_level dest;
+
+                       if (newlev == depth(&u.uz) || In_endgame(&u.uz))
+                           continue;
+                       obj_extract_self(otmp);
+                       add_to_migration(otmp);
+                       get_level(&dest, newlev);
+                       otmp->ox = dest.dnum;
+                       otmp->oy = dest.dlevel;
+                       otmp->owornmask = (long)MIGR_RANDOM;
+                   }
+                   seetrap(ttmp);
+                   continue;
+               }
+           if (closed_door(rx, ry))
+               goto nopushmsg;
+           if (boulder_hits_pool(otmp, rx, ry, TRUE))
+               continue;
+           /*
+            * Re-link at top of fobj chain so that pile order is preserved
+            * when level is restored.
+            */
+           if (otmp != fobj) {
+               remove_object(otmp);
+               place_object(otmp, otmp->ox, otmp->oy);
+           }
+
+           {
+#ifdef LINT /* static long lastmovetime; */
+               long lastmovetime;
+               lastmovetime = 0;
+#else
+               /* note: reset to zero after save/restore cycle */
+               static NEARDATA long lastmovetime;
+#endif
+#ifdef STEED
+               if (!u.usteed) {
+#endif
+                 if (moves > lastmovetime+2 || moves < lastmovetime)
+                   pline("With %s effort you move %s.",
+                         throws_rocks(youmonst.data) ? "little" : "great",
+                         the(xname(otmp)));
+                 exercise(A_STR, TRUE);
+#ifdef STEED
+               } else 
+                   pline("%s moves %s.",
+                         upstart(y_monnam(u.usteed)), the(xname(otmp)));
+#endif
+               lastmovetime = moves;
+           }
+
+           /* Move the boulder *after* the message. */
+           if (glyph_is_invisible(levl[rx][ry].glyph))
+               unmap_object(rx, ry);
+           movobj(otmp, rx, ry);       /* does newsym(rx,ry) */
+           if (Blind) {
+               feel_location(rx,ry);
+               feel_location(sx, sy);
+           } else {
+               newsym(sx, sy);
+           }
+       } else {
+       nopushmsg:
+#ifdef STEED
+         if (u.usteed)
+           pline("%s tries to move %s, but cannot.",
+                 upstart(y_monnam(u.usteed)), the(xname(otmp)));
+         else
+#endif
+           You("try to move %s, but in vain.", the(xname(otmp)));
+           if (Blind) feel_location(sx, sy);
+       cannot_push:
+           if (throws_rocks(youmonst.data)) {
+#ifdef STEED
+               if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
+                   You("aren't skilled enough to %s %s from %s.",
+                       (flags.pickup && !In_sokoban(&u.uz))
+                           ? "pick up" : "push aside",
+                       the(xname(otmp)), y_monnam(u.usteed));
+               } else
+#endif
+               {
+                   pline("However, you can easily %s.",
+                       (flags.pickup && !In_sokoban(&u.uz))
+                           ? "pick it up" : "push it aside");
+                   if (In_sokoban(&u.uz))
+                       change_luck(-1);        /* Sokoban guilt */
+                   break;
+               }
+               break;
+           }
+
+           if (
+#ifdef STEED
+               !u.usteed &&
+#endif     
+               (((!invent || inv_weight() <= -850) &&
+                (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][sy].typ)
+                                    && IS_ROCK(levl[sx][u.uy].typ))))
+               || verysmall(youmonst.data))) {
+               pline("However, you can squeeze yourself into a small opening.");
+               if (In_sokoban(&u.uz))
+                   change_luck(-1);    /* Sokoban guilt */
+               break;
+           } else
+               return (-1);
+       }
+    }
+    return (0);
+}
+
+/*
+ *  still_chewing()
+ *
+ *  Chew on a wall, door, or boulder.  Returns TRUE if still eating, FALSE
+ *  when done.
+ */
+STATIC_OVL int
+still_chewing(x,y)
+    xchar x, y;
+{
+    struct rm *lev = &levl[x][y];
+    struct obj *boulder = sobj_at(BOULDER,x,y);
+    const char *digtxt = (char *)0, *dmgtxt = (char *)0;
+
+    if (digging.down)          /* not continuing previous dig (w/ pick-axe) */
+       (void) memset((genericptr_t)&digging, 0, sizeof digging);
+
+    if (!boulder && IS_ROCK(lev->typ) && !may_dig(x,y)) {
+       You("hurt your teeth on the %s.",
+           IS_TREE(lev->typ) ? "tree" : "hard stone");
+       nomul(0);
+       return 1;
+    } else if (digging.pos.x != x || digging.pos.y != y ||
+               !on_level(&digging.level, &u.uz)) {
+       digging.down = FALSE;
+       digging.chew = TRUE;
+       digging.warned = FALSE;
+       digging.pos.x = x;
+       digging.pos.y = y;
+       assign_level(&digging.level, &u.uz);
+       /* solid rock takes more work & time to dig through */
+       digging.effort =
+           (IS_ROCK(lev->typ) && !IS_TREE(lev->typ) ? 30 : 60) + u.udaminc;
+       You("start chewing %s %s.",
+           (boulder || IS_TREE(lev->typ)) ? "on a" : "a hole in the",
+           boulder ? "boulder" :
+           IS_TREE(lev->typ) ? "tree" : IS_ROCK(lev->typ) ? "rock" : "door");
+       watch_dig((struct monst *)0, x, y, FALSE);
+       return 1;
+    } else if ((digging.effort += (30 + u.udaminc)) <= 100)  {
+       if (flags.verbose)
+           You("%s chewing on the %s.",
+               digging.chew ? "continue" : "begin",
+               boulder ? "boulder" :
+               IS_TREE(lev->typ) ? "tree" :
+               IS_ROCK(lev->typ) ? "rock" : "door");
+       digging.chew = TRUE;
+       watch_dig((struct monst *)0, x, y, FALSE);
+       return 1;
+    }
+
+    /* Okay, you've chewed through something */
+    u.uconduct.food++;
+    u.uhunger += rnd(20);
+
+    if (boulder) {
+       delobj(boulder);                /* boulder goes bye-bye */
+       You("eat the boulder.");        /* yum */
+
+       /*
+        *  The location could still block because of
+        *      1. More than one boulder
+        *      2. Boulder stuck in a wall/stone/door.
+        *
+        *  [perhaps use does_block() below (from vision.c)]
+        */
+       if (IS_ROCK(lev->typ) || closed_door(x,y) || sobj_at(BOULDER,x,y)) {
+           block_point(x,y);   /* delobj will unblock the point */
+           /* reset dig state */
+           (void) memset((genericptr_t)&digging, 0, sizeof digging);
+           return 1;
+       }
+
+    } else if (IS_WALL(lev->typ)) {
+       if (*in_rooms(x, y, SHOPBASE)) {
+           add_damage(x, y, 10L * ACURRSTR);
+           dmgtxt = "damage";
+       }
+       digtxt = "chew a hole in the wall.";
+       if (level.flags.is_maze_lev) {
+           lev->typ = ROOM;
+       } else if (level.flags.is_cavernous_lev && !in_town(x, y)) {
+           lev->typ = CORR;
+       } else {
+           lev->typ = DOOR;
+           lev->doormask = D_NODOOR;
+       }
+    } else if (IS_TREE(lev->typ)) {
+       digtxt = "chew through the tree.";
+       lev->typ = ROOM;
+    } else if (lev->typ == SDOOR) {
+       if (lev->doormask & D_TRAPPED) {
+           lev->doormask = D_NODOOR;
+           b_trapped("secret door", 0);
+       } else {
+           digtxt = "chew through the secret door.";
+           lev->doormask = D_BROKEN;
+       }
+       lev->typ = DOOR;
+
+    } else if (IS_DOOR(lev->typ)) {
+       if (*in_rooms(x, y, SHOPBASE)) {
+           add_damage(x, y, 400L);
+           dmgtxt = "break";
+       }
+       if (lev->doormask & D_TRAPPED) {
+           lev->doormask = D_NODOOR;
+           b_trapped("door", 0);
+       } else {
+           digtxt = "chew through the door.";
+           lev->doormask = D_BROKEN;
+       }
+
+    } else { /* STONE or SCORR */
+       digtxt = "chew a passage through the rock.";
+       lev->typ = CORR;
+    }
+
+    unblock_point(x, y);       /* vision */
+    newsym(x, y);
+    if (digtxt) You(digtxt);   /* after newsym */
+    if (dmgtxt) pay_for_damage(dmgtxt, FALSE);
+    (void) memset((genericptr_t)&digging, 0, sizeof digging);
+    return 0;
+}
+
+#endif /* OVL2 */
+#ifdef OVLB
+
+void
+movobj(obj, ox, oy)
+register struct obj *obj;
+register xchar ox, oy;
+{
+       /* optimize by leaving on the fobj chain? */
+       remove_object(obj);
+       newsym(obj->ox, obj->oy);
+       place_object(obj, ox, oy);
+       newsym(ox, oy);
+}
+
+#ifdef SINKS
+static NEARDATA const char fell_on_sink[] = "fell onto a sink";
+
+STATIC_OVL void
+dosinkfall()
+{
+       register struct obj *obj;
+
+       if (is_floater(youmonst.data) || (HLevitation & FROMOUTSIDE)) {
+           You("wobble unsteadily for a moment.");
+       } else {
+           long save_ELev = ELevitation, save_HLev = HLevitation;
+
+           /* fake removal of levitation in advance so that final
+              disclosure will be right in case this turns out to
+              be fatal; fortunately the fact that rings and boots
+              are really still worn has no effect on bones data */
+           ELevitation = HLevitation = 0L;
+           You("crash to the floor!");
+           losehp(rn1(8, 25 - (int)ACURR(A_CON)),
+                  fell_on_sink, NO_KILLER_PREFIX);
+           exercise(A_DEX, FALSE);
+           selftouch("Falling, you");
+           for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere)
+               if (obj->oclass == WEAPON_CLASS || is_weptool(obj)) {
+                   You("fell on %s.", doname(obj));
+                   losehp(rnd(3), fell_on_sink, NO_KILLER_PREFIX);
+                   exercise(A_CON, FALSE);
+               }
+           ELevitation = save_ELev;
+           HLevitation = save_HLev;
+       }
+
+       ELevitation &= ~W_ARTI;
+       HLevitation &= ~(I_SPECIAL|TIMEOUT);
+       HLevitation++;
+       if(uleft && uleft->otyp == RIN_LEVITATION) {
+           obj = uleft;
+           Ring_off(obj);
+           off_msg(obj);
+       }
+       if(uright && uright->otyp == RIN_LEVITATION) {
+           obj = uright;
+           Ring_off(obj);
+           off_msg(obj);
+       }
+       if(uarmf && uarmf->otyp == LEVITATION_BOOTS) {
+           obj = uarmf;
+           (void)Boots_off();
+           off_msg(obj);
+       }
+       HLevitation--;
+}
+#endif
+
+boolean
+may_dig(x,y)
+register xchar x,y;
+/* intended to be called only on ROCKs */
+{
+    return (boolean)(!(IS_STWALL(levl[x][y].typ) &&
+                       (levl[x][y].wall_info & W_NONDIGGABLE)));
+}
+
+boolean
+may_passwall(x,y)
+register xchar x,y;
+{
+   return (boolean)(!(IS_STWALL(levl[x][y].typ) &&
+                       (levl[x][y].wall_info & W_NONPASSWALL)));
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+boolean
+bad_rock(mdat,x,y)
+struct permonst *mdat;
+register xchar x,y;
+{
+       return((boolean) ((In_sokoban(&u.uz) && sobj_at(BOULDER,x,y)) ||
+              (IS_ROCK(levl[x][y].typ)
+                   && (!tunnels(mdat) || needspick(mdat) || !may_dig(x,y))
+                   && !(passes_walls(mdat) && may_passwall(x,y)))));
+}
+
+boolean
+invocation_pos(x, y)
+xchar x, y;
+{
+       return((boolean)(Invocation_lev(&u.uz) && x == inv_pos.x && y == inv_pos.y));
+}
+
+#endif /* OVL1 */
+#ifdef OVL3
+
+/* return TRUE if (dx,dy) is an OK place to move
+ * mode is one of DO_MOVE, TEST_MOVE or TEST_TRAV
+ */
+boolean 
+test_move(ux, uy, dx, dy, mode)
+int ux, uy, dx, dy;
+int mode;
+{
+    int x = ux+dx;
+    int y = uy+dy;
+    register struct rm *tmpr = &levl[x][y];
+    register struct rm *ust;
+
+    /*
+     *  Check for physical obstacles.  First, the place we are going.
+     */
+    if (IS_ROCK(tmpr->typ) || tmpr->typ == IRONBARS) {
+       if (Blind && mode == DO_MOVE) feel_location(x,y);
+       if (Passes_walls && may_passwall(x,y)) {
+           ;   /* do nothing */
+       } else if (tmpr->typ == IRONBARS) {
+           if (!(Passes_walls || passes_bars(youmonst.data)))
+               return FALSE;
+       } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
+           /* Eat the rock. */
+           if (mode == DO_MOVE && still_chewing(x,y)) return FALSE;
+       } else if (flags.autodig && !flags.run && !flags.nopick &&
+                  uwep && is_pick(uwep)) {
+       /* MRKR: Automatic digging when wielding the appropriate tool */
+           if (mode == DO_MOVE)
+               (void) use_pick_axe2(uwep);
+           return FALSE;
+       } else {
+           if (mode == DO_MOVE) {
+               if (Is_stronghold(&u.uz) && is_db_wall(x,y))
+                   pline_The("drawbridge is up!");
+               if (Passes_walls && !may_passwall(x,y) && In_sokoban(&u.uz))
+                   pline_The("Sokoban walls resist your ability.");
+           }
+           return FALSE;
+       }
+    } else if (IS_DOOR(tmpr->typ)) {
+       if (closed_door(x,y)) {
+           if (Blind && mode == DO_MOVE) feel_location(x,y);
+           if (Passes_walls)
+               ;       /* do nothing */
+           else if (can_ooze(&youmonst)) {
+               if (mode == DO_MOVE) You("ooze under the door.");
+           } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
+               /* Eat the door. */
+               if (mode == DO_MOVE && still_chewing(x,y)) return FALSE;
+           } else {
+               if (mode == DO_MOVE) {
+                   if (amorphous(youmonst.data))
+                       You("try to ooze under the door, but can't squeeze your possessions through.");
+                   else if (x == ux || y == uy) {
+                       if (Blind || Stunned || ACURR(A_DEX) < 10 || Fumbling) {
+#ifdef STEED
+                           if (u.usteed) {
+                               You_cant("lead %s through that closed door.",
+                                        y_monnam(u.usteed));
+                           } else
+#endif
+                           {
+                               pline("Ouch!  You bump into a door.");
+                               exercise(A_DEX, FALSE);
+                           }
+                       } else pline("That door is closed.");
+                   }
+               } else if (mode == TEST_TRAV) goto testdiag;
+               return FALSE;
+           }
+       } else {
+       testdiag:
+           if (dx && dy && !Passes_walls
+               && ((tmpr->doormask & ~D_BROKEN)
+#ifdef REINCARNATION
+                   || Is_rogue_level(&u.uz)
+#endif
+                   || block_door(x,y))) {
+               /* Diagonal moves into a door are not allowed. */
+               if (Blind && mode == DO_MOVE)
+                   feel_location(x,y);
+               return FALSE;
+           }
+       }
+    }
+    if (dx && dy
+           && bad_rock(youmonst.data,ux,y) && bad_rock(youmonst.data,x,uy)) {
+       /* Move at a diagonal. */
+       if (In_sokoban(&u.uz)) {
+           if (mode == DO_MOVE)
+               You("cannot pass that way.");
+           return FALSE;
+       }
+       if (bigmonst(youmonst.data)) {
+           if (mode == DO_MOVE)
+               Your("body is too large to fit through.");
+           return FALSE;
+       }
+       if (invent && (inv_weight() + weight_cap() > 600)) {
+           if (mode == DO_MOVE)
+               You("are carrying too much to get through.");
+           return FALSE;
+       }
+    }
+    /* Pick travel path that does not require crossing a trap.
+     * Avoid water and lava using the usual running rules.
+     * (but not u.ux/u.uy because findtravelpath walks toward u.ux/u.uy) */
+    if (flags.run == 8 && mode != DO_MOVE && (x != u.ux || y != u.uy)) {
+       struct trap* t = t_at(x, y);
+
+       if ((t && t->tseen) ||
+           (!Levitation && !Flying &&
+            !is_clinger(youmonst.data) &&
+            (is_pool(x, y) || is_lava(x, y)) && levl[x][y].seenv))
+           return FALSE;
+    }
+
+    ust = &levl[ux][uy];
+
+    /* Now see if other things block our way . . */
+    if (dx && dy && !Passes_walls
+                    && (IS_DOOR(ust->typ) && ((ust->doormask & ~D_BROKEN)
+#ifdef REINCARNATION
+                            || Is_rogue_level(&u.uz)
+#endif
+                            || block_entry(x, y))
+                        )) {
+       /* Can't move at a diagonal out of a doorway with door. */
+       return FALSE;
+    }
+
+    if (sobj_at(BOULDER,x,y) && (In_sokoban(&u.uz) || !Passes_walls)) {
+       if (!(Blind || Hallucination) && (flags.run >= 2) && mode != TEST_TRAV)
+           return FALSE;
+       if (mode == DO_MOVE) {
+           /* tunneling monsters will chew before pushing */
+           if (tunnels(youmonst.data) && !needspick(youmonst.data) &&
+               !In_sokoban(&u.uz)) {
+               if (still_chewing(x,y)) return FALSE;
+           } else
+               if (moverock() < 0) return FALSE;
+       } else if (mode == TEST_TRAV) {
+           struct obj* obj;
+
+           /* don't pick two boulders in a row, unless there's a way thru */
+           if (sobj_at(BOULDER,ux,uy) && !In_sokoban(&u.uz)) {
+               if (!Passes_walls &&
+                   !(tunnels(youmonst.data) && !needspick(youmonst.data)) &&
+                   !carrying(PICK_AXE) && !carrying(DWARVISH_MATTOCK) &&
+                   !((obj = carrying(WAN_DIGGING)) &&
+                     !objects[obj->otyp].oc_name_known))
+                   return FALSE;
+           }
+       }
+       /* assume you'll be able to push it when you get there... */
+    }
+
+    /* OK, it is a legal place to move. */
+    return TRUE;
+}
+
+/*
+ * Find a path from the destination (u.tx,u.ty) back to (u.ux,u.uy).
+ * A shortest path is returned.  If guess is TRUE, consider various
+ * inaccessible locations as valid intermediate path points.
+ * Returns TRUE if a path was found.
+ */
+static boolean
+findtravelpath(guess)
+boolean guess;
+{
+    /* if travel to adjacent, reachable location, use normal movement rules */
+    if (!guess && iflags.travel1 && distmin(u.ux, u.uy, u.tx, u.ty) == 1) {
+       flags.run = 0;
+       if (test_move(u.ux, u.uy, u.tx-u.ux, u.ty-u.uy, TEST_MOVE)) {
+           u.dx = u.tx-u.ux;
+           u.dy = u.ty-u.uy;
+           nomul(0);
+           iflags.travelcc.x = iflags.travelcc.y = -1;
+           return TRUE;
+       }
+       flags.run = 8;
+    }
+    if (u.tx != u.ux || u.ty != u.uy) {
+       xchar travel[COLNO][ROWNO];
+       xchar travelstepx[2][COLNO*ROWNO];
+       xchar travelstepy[2][COLNO*ROWNO];
+       xchar tx, ty, ux, uy;
+       int n = 1;                      /* max offset in travelsteps */
+       int set = 0;                    /* two sets current and previous */
+       int radius = 1;                 /* search radius */
+       int i;
+
+       /* If guessing, first find an "obvious" goal location.  The obvious
+        * goal is the position the player knows of, or might figure out
+        * (couldsee) that is closest to the target on a straight path.
+        */
+       if (guess) {
+           tx = u.ux; ty = u.uy; ux = u.tx; uy = u.ty;
+       } else {
+           tx = u.tx; ty = u.ty; ux = u.ux; uy = u.uy;
+       }
+
+    noguess:
+       (void) memset((genericptr_t)travel, 0, sizeof(travel));
+       travelstepx[0][0] = tx;
+       travelstepy[0][0] = ty;
+
+       while (n != 0) {
+           int nn = 0;
+
+           for (i = 0; i < n; i++) {
+               int dir;
+               int x = travelstepx[set][i];
+               int y = travelstepy[set][i];
+               static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 };
+               /* no diagonal movement for grid bugs */
+               int dirmax = u.umonnum == PM_GRID_BUG ? 4 : 8;
+
+               for (dir = 0; dir < dirmax; ++dir) {
+                   int nx = x+xdir[ordered[dir]];
+                   int ny = y+ydir[ordered[dir]];
+
+                   if (!isok(nx, ny)) continue;
+                   if ((!Passes_walls && !can_ooze(&youmonst) &&
+                       closed_door(x, y)) || sobj_at(BOULDER, x, y)) {
+                       /* closed doors and boulders usually
+                        * cause a delay, so prefer another path */
+                       if (travel[x][y] > radius-3) {
+                           travelstepx[1-set][nn] = x;
+                           travelstepy[1-set][nn] = y;
+                           /* don't change travel matrix! */
+                           nn++;
+                           continue;
+                       }
+                   }
+                   if (test_move(x, y, nx-x, ny-y, TEST_TRAV) &&
+                       (levl[nx][ny].seenv || (!Blind && couldsee(nx, ny)))) {
+                       if (nx == ux && ny == uy) {
+                           if (!guess) {
+                               u.dx = x-ux;
+                               u.dy = y-uy;
+                               if (x == u.tx && y == u.ty) {
+                                   nomul(0);
+                                   /* reset run so domove run checks work */
+                                   flags.run = 8;
+                                   iflags.travelcc.x = iflags.travelcc.y = -1;
+                               }
+                               return TRUE;
+                           }
+                       } else if (!travel[nx][ny]) {
+                           travelstepx[1-set][nn] = nx;
+                           travelstepy[1-set][nn] = ny;
+                           travel[nx][ny] = radius;
+                           nn++;
+                       }
+                   }
+               }
+           }
+           
+           n = nn;
+           set = 1-set;
+           radius++;
+       }
+
+       /* if guessing, find best location in travel matrix and go there */
+       if (guess) {
+           int px = tx, py = ty;       /* pick location */
+           int dist, nxtdist, d2, nd2;
+
+           dist = distmin(ux, uy, tx, ty);
+           d2 = dist2(ux, uy, tx, ty);
+           for (tx = 1; tx < COLNO; ++tx)
+               for (ty = 0; ty < ROWNO; ++ty)
+                   if (travel[tx][ty]) {
+                       nxtdist = distmin(ux, uy, tx, ty);
+                       if (nxtdist == dist && couldsee(tx, ty)) {
+                           nd2 = dist2(ux, uy, tx, ty);
+                           if (nd2 < d2) {
+                               /* prefer non-zigzag path */
+                               px = tx; py = ty;
+                               d2 = nd2;
+                           }
+                       } else if (nxtdist < dist && couldsee(tx, ty)) {
+                           px = tx; py = ty;
+                           dist = nxtdist;
+                           d2 = dist2(ux, uy, tx, ty);
+                       }
+                   }
+
+           if (px == u.ux && py == u.uy) {
+               /* no guesses, just go in the general direction */
+               u.dx = sgn(u.tx - u.ux);
+               u.dy = sgn(u.ty - u.uy);
+               if (test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE))
+                   return TRUE;
+               goto found;
+           }
+           tx = px;
+           ty = py;
+           ux = u.ux;
+           uy = u.uy;
+           set = 0;
+           n = radius = 1;
+           guess = FALSE;
+           goto noguess;
+       }
+       return FALSE;
+    }
+
+found:
+    u.dx = 0;
+    u.dy = 0;
+    nomul(0);
+    return FALSE;
+}
+
+void
+domove()
+{
+       register struct monst *mtmp;
+       register struct rm *tmpr;
+       register xchar x,y;
+       struct trap *trap;
+       int wtcap;
+       boolean on_ice;
+       xchar chainx, chainy, ballx, bally;     /* ball&chain new positions */
+       int bc_control;                         /* control for ball&chain */
+       boolean cause_delay = FALSE;    /* dragging ball will skip a move */
+       const char *predicament;
+
+       u_wipe_engr(rnd(5));
+
+       if (flags.travel) {
+           if (!findtravelpath(FALSE))
+               (void) findtravelpath(TRUE);
+           iflags.travel1 = 0;
+       }
+
+       if(((wtcap = near_capacity()) >= OVERLOADED
+           || (wtcap > SLT_ENCUMBER &&
+               (Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
+                       : (u.uhp < 10 && u.uhp != u.uhpmax))))
+          && !Is_airlevel(&u.uz)) {
+           if(wtcap < OVERLOADED) {
+               You("don't have enough stamina to move.");
+               exercise(A_CON, FALSE);
+           } else
+               You("collapse under your load.");
+           nomul(0);
+           return;
+       }
+       if(u.uswallow) {
+               u.dx = u.dy = 0;
+               u.ux = x = u.ustuck->mx;
+               u.uy = y = u.ustuck->my;
+               mtmp = u.ustuck;
+       } else {
+               if (Is_airlevel(&u.uz) && rn2(4) &&
+                       !Levitation && !Flying) {
+                   switch(rn2(3)) {
+                   case 0:
+                       You("tumble in place.");
+                       exercise(A_DEX, FALSE);
+                       break;
+                   case 1:
+                       You_cant("control your movements very well."); break;
+                   case 2:
+                       pline("It's hard to walk in thin air.");
+                       exercise(A_DEX, TRUE);
+                       break;
+                   }
+                   return;
+               }
+
+               /* check slippery ice */
+               on_ice = !Levitation && is_ice(u.ux, u.uy);
+               if (on_ice) {
+                   static int skates = 0;
+                   if (!skates) skates = find_skates();
+                   if ((uarmf && uarmf->otyp == skates)
+                           || resists_cold(&youmonst) || Flying
+                           || is_floater(youmonst.data) || is_clinger(youmonst.data)
+                           || is_whirly(youmonst.data))
+                       on_ice = FALSE;
+                   else if (!rn2(Cold_resistance ? 3 : 2)) {
+                       HFumbling |= FROMOUTSIDE;
+                       HFumbling &= ~TIMEOUT;
+                       HFumbling += 1;  /* slip on next move */
+                   }
+               }
+               if (!on_ice && (HFumbling & FROMOUTSIDE))
+                   HFumbling &= ~FROMOUTSIDE;
+
+               x = u.ux + u.dx;
+               y = u.uy + u.dy;
+               if(Stunned || (Confusion && !rn2(5))) {
+                       register int tries = 0;
+
+                       do {
+                               if(tries++ > 50) {
+                                       nomul(0);
+                                       return;
+                               }
+                               confdir();
+                               x = u.ux + u.dx;
+                               y = u.uy + u.dy;
+                       } while(!isok(x, y) || bad_rock(youmonst.data, x, y));
+               }
+               /* turbulence might alter your actual destination */
+               if (u.uinwater) {
+                       water_friction();
+                       if (!u.dx && !u.dy) {
+                               nomul(0);
+                               return;
+                       }
+                       x = u.ux + u.dx;
+                       y = u.uy + u.dy;
+               }
+               if(!isok(x, y)) {
+                       nomul(0);
+                       return;
+               }
+               if (((trap = t_at(x, y)) && trap->tseen) ||
+                   (Blind && !Levitation && !Flying &&
+                    !is_clinger(youmonst.data) &&
+                    (is_pool(x, y) || is_lava(x, y)) && levl[x][y].seenv)) {
+                       if(flags.run >= 2) {
+                               nomul(0);
+                               flags.move = 0;
+                               return;
+                       } else
+                               nomul(0);
+               }
+
+               if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) {
+                   if (distu(u.ustuck->mx, u.ustuck->my) > 2) {
+                       /* perhaps it fled (or was teleported or ... ) */
+                       u.ustuck = 0;
+                   } else if (sticks(youmonst.data)) {
+                       /* When polymorphed into a sticking monster,
+                        * u.ustuck means it's stuck to you, not you to it.
+                        */
+                       You("release %s.", mon_nam(u.ustuck));
+                       u.ustuck = 0;
+                   } else {
+                       /* If holder is asleep or paralyzed:
+                        *      37.5% chance of getting away,
+                        *      12.5% chance of waking/releasing it;
+                        * otherwise:
+                        *       7.5% chance of getting away.
+                        * [strength ought to be a factor]
+                        * If holder is tame and there is no conflict,
+                        * guaranteed escape.
+                        */
+                       switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) {
+                       case 0: case 1: case 2:
+                       pull_free:
+                           You("pull free from %s.", mon_nam(u.ustuck));
+                           u.ustuck = 0;
+                           break;
+                       case 3:
+                           if (!u.ustuck->mcanmove) {
+                               /* it's free to move on next turn */
+                               u.ustuck->mfrozen = 1;
+                               u.ustuck->msleeping = 0;
+                           }
+                           /*FALLTHRU*/
+                       default:
+                           if (u.ustuck->mtame &&
+                               !Conflict && !u.ustuck->mconf)
+                               goto pull_free;
+                           You("cannot escape from %s!", mon_nam(u.ustuck));
+                           nomul(0);
+                           return;
+                       }
+                   }
+               }
+
+               mtmp = m_at(x,y);
+               if (mtmp) {
+                       /* Don't attack if you're running, and can see it */
+                       /* We should never get here if forcefight */
+                       if (flags.run &&
+                           ((!Blind && mon_visible(mtmp) &&
+                             ((mtmp->m_ap_type != M_AP_FURNITURE &&
+                               mtmp->m_ap_type != M_AP_OBJECT) ||
+                              Protection_from_shape_changers)) ||
+                            sensemon(mtmp))) {
+                               nomul(0);
+                               flags.move = 0;
+                               return;
+                       }
+               }
+       }
+
+       u.ux0 = u.ux;
+       u.uy0 = u.uy;
+       bhitpos.x = x;
+       bhitpos.y = y;
+       tmpr = &levl[x][y];
+
+       /* attack monster */
+       if(mtmp) {
+           nomul(0);
+           /* only attack if we know it's there */
+           /* or if we used the 'F' command to fight blindly */
+           /* or if it hides_under, in which case we call attack() to print
+            * the Wait! message.
+            * This is different from ceiling hiders, who aren't handled in
+            * attack().
+            */
+
+           /* If they used a 'm' command, trying to move onto a monster
+            * prints the below message and wastes a turn.  The exception is
+            * if the monster is unseen and the player doesn't remember an
+            * invisible monster--then, we fall through to attack() and
+            * attack_check(), which still wastes a turn, but prints a
+            * different message and makes the player remember the monster.                  */
+           if(flags.nopick &&
+                 (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))){
+               if(mtmp->m_ap_type && !Protection_from_shape_changers
+                                                   && !sensemon(mtmp))
+                   stumble_onto_mimic(mtmp);
+               else if (mtmp->mpeaceful && !Hallucination)
+                   pline("Pardon me, %s.", m_monnam(mtmp));
+               else
+                   You("move right into %s.", mon_nam(mtmp));
+               return;
+           }
+           if(flags.forcefight || !mtmp->mundetected || sensemon(mtmp) ||
+                   ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL) &&
+                       !is_safepet(mtmp))){
+               gethungry();
+               if(wtcap >= HVY_ENCUMBER && moves%3) {
+                   if (Upolyd && u.mh > 1) {
+                       u.mh--;
+                   } else if (!Upolyd && u.uhp > 1) {
+                       u.uhp--;
+                   } else {
+                       You("pass out from exertion!");
+                       exercise(A_CON, FALSE);
+                       fall_asleep(-10, FALSE);
+                   }
+               }
+               if(multi < 0) return;   /* we just fainted */
+
+               /* try to attack; note that it might evade */
+               /* also, we don't attack tame when _safepet_ */
+               if(attack(mtmp)) return;
+           }
+       }
+
+       /* specifying 'F' with no monster wastes a turn */
+       if (flags.forcefight ||
+           /* remembered an 'I' && didn't use a move command */
+           (glyph_is_invisible(levl[x][y].glyph) && !flags.nopick)) {
+               boolean expl = (Upolyd && attacktype(youmonst.data, AT_EXPL));
+               char buf[BUFSZ];
+               Sprintf(buf,"a vacant spot on the %s", surface(x,y));
+               You("%s %s.",
+                   expl ? "explode at" : "attack",
+                   !Underwater ? "thin air" :
+                   is_pool(x,y) ? "empty water" : buf);
+               unmap_object(x, y); /* known empty -- remove 'I' if present */
+               newsym(x, y);
+               nomul(0);
+               if (expl) {
+                   u.mh = -1;          /* dead in the current form */
+                   rehumanize();
+               }
+               return;
+       }
+       if (glyph_is_invisible(levl[x][y].glyph)) {
+           unmap_object(x, y);
+           newsym(x, y);
+       }
+       /* not attacking an animal, so we try to move */
+#ifdef STEED
+       if (u.usteed && !u.usteed->mcanmove && (u.dx || u.dy)) {
+               pline("%s won't move!", upstart(y_monnam(u.usteed)));
+               nomul(0);
+               return;
+       } else
+#endif
+       if(!youmonst.data->mmove) {
+               You("are rooted %s.",
+                   Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ?
+                   "in place" : "to the ground");
+               nomul(0);
+               return;
+       }
+       if(u.utrap) {
+               if(u.utraptype == TT_PIT) {
+                   if (!rn2(2) && sobj_at(BOULDER, u.ux, u.uy)) {
+                       Your("%s gets stuck in a crevice.", body_part(LEG));
+                       display_nhwindow(WIN_MESSAGE, FALSE);
+                       clear_nhwindow(WIN_MESSAGE);
+                       You("free your %s.", body_part(LEG));
+                   } else if (!(--u.utrap)) {
+                       You("%s to the edge of the pit.",
+                               (In_sokoban(&u.uz) && Levitation) ?
+                               "struggle against the air currents and float" :
+#ifdef STEED
+                               u.usteed ? "ride" :
+#endif
+                               "crawl");
+                       fill_pit(u.ux, u.uy);
+                       vision_full_recalc = 1; /* vision limits change */
+                   } else if (flags.verbose) {
+#ifdef STEED
+                       if (u.usteed)
+                           Norep("%s is still in a pit.",
+                                 upstart(y_monnam(u.usteed)));
+                       else
+#endif
+                       Norep( (Hallucination && !rn2(5)) ?
+                               "You've fallen, and you can't get up." :
+                               "You are still in a pit." );
+                   }
+               } else if (u.utraptype == TT_LAVA) {
+                   if(flags.verbose) {
+                       predicament = "stuck in the lava";
+#ifdef STEED
+                       if (u.usteed)
+                           Norep("%s is %s.", upstart(y_monnam(u.usteed)),
+                                 predicament);
+                       else
+#endif
+                       Norep("You are %s.", predicament);
+                   }
+                   if(!is_lava(x,y)) {
+                       u.utrap--;
+                       if((u.utrap & 0xff) == 0) {
+#ifdef STEED
+                           if (u.usteed)
+                               You("lead %s to the edge of the lava.",
+                                   y_monnam(u.usteed));
+                           else
+#endif
+                            You("pull yourself to the edge of the lava.");
+                           u.utrap = 0;
+                       }
+                   }
+                   u.umoved = TRUE;
+               } else if (u.utraptype == TT_WEB) {
+                   if(uwep && uwep->oartifact == ART_STING) {
+                       u.utrap = 0;
+                       pline("Sting cuts through the web!");
+                       return;
+                   }
+                   if(--u.utrap) {
+                       if(flags.verbose) {
+                           predicament = "stuck to the web";
+#ifdef STEED
+                           if (u.usteed)
+                               Norep("%s is %s.", upstart(y_monnam(u.usteed)),
+                                     predicament);
+                           else
+#endif
+                           Norep("You are %s.", predicament);
+                       }
+                   } else {
+#ifdef STEED
+                       if (u.usteed)
+                           pline("%s breaks out of the web.",
+                                 upstart(y_monnam(u.usteed)));
+                       else
+#endif
+                       You("disentangle yourself.");
+                   }
+               } else if (u.utraptype == TT_INFLOOR) {
+                   if(--u.utrap) {
+                       if(flags.verbose) {
+                           predicament = "stuck in the";
+#ifdef STEED
+                           if (u.usteed)
+                               Norep("%s is %s %s.",
+                                     upstart(y_monnam(u.usteed)),
+                                     predicament, surface(u.ux, u.uy));
+                           else
+#endif
+                           Norep("You are %s %s.", predicament,
+                                 surface(u.ux, u.uy));
+                       }
+                   } else {
+#ifdef STEED
+                       if (u.usteed)
+                           pline("%s finally wiggles free.",
+                                 upstart(y_monnam(u.usteed)));
+                       else
+#endif
+                       You("finally wiggle free.");
+                   }
+               } else {
+                   if(flags.verbose) {
+                       predicament = "caught in a bear trap";
+#ifdef STEED
+                       if (u.usteed)
+                           Norep("%s is %s.", upstart(y_monnam(u.usteed)),
+                                 predicament);
+                       else
+#endif
+                       Norep("You are %s.", predicament);
+                   }
+                   if((u.dx && u.dy) || !rn2(5)) u.utrap--;
+               }
+               return;
+       }
+
+       if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) {
+           flags.move = 0;
+           nomul(0);
+           return;
+       }
+
+       /* Move ball and chain.  */
+       if (Punished)
+           if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy,
+                       &cause_delay, TRUE))
+               return;
+
+       /* Check regions entering/leaving */
+       if (!in_out_region(x,y))
+           return;
+
+       /* now move the hero */
+       mtmp = m_at(x, y);
+       u.ux += u.dx;
+       u.uy += u.dy;
+#ifdef STEED
+       /* Move your steed, too */
+       if (u.usteed) {
+               u.usteed->mx = u.ux;
+               u.usteed->my = u.uy;
+               exercise_steed();
+       }
+#endif
+
+       /*
+        * If safepet at destination then move the pet to the hero's
+        * previous location using the same conditions as in attack().
+        * there are special extenuating circumstances:
+        * (1) if the pet dies then your god angers,
+        * (2) if the pet gets trapped then your god may disapprove,
+        * (3) if the pet was already trapped and you attempt to free it
+        * not only do you encounter the trap but you may frighten your
+        * pet causing it to go wild!  moral: don't abuse this privilege.
+        *
+        * Ceiling-hiding pets are skipped by this section of code, to
+        * be caught by the normal falling-monster code.
+        */
+       if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) {
+           /* if trapped, there's a chance the pet goes wild */
+           if (mtmp->mtrapped) {
+               if (!rn2(mtmp->mtame)) {
+                   mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0;
+                   if (mtmp->mleashed) m_unleash(mtmp, TRUE);
+                   growl(mtmp);
+               } else {
+                   yelp(mtmp);
+               }
+           }
+           mtmp->mundetected = 0;
+           if (mtmp->m_ap_type) seemimic(mtmp);
+           else if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my);
+
+           if (mtmp->mtrapped &&
+                   (trap = t_at(mtmp->mx, mtmp->my)) != 0 &&
+                   (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) &&
+                   sobj_at(BOULDER, trap->tx, trap->ty)) {
+               /* can't swap places with pet pinned in a pit by a boulder */
+               u.ux = u.ux0,  u.uy = u.uy0;    /* didn't move after all */
+           } else if (u.ux0 != x && u.uy0 != y &&
+                      bad_rock(mtmp->data, x, u.uy0) &&
+                      bad_rock(mtmp->data, u.ux0, y) &&
+                      (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) {
+               /* can't swap places when pet won't fit thru the opening */
+               u.ux = u.ux0,  u.uy = u.uy0;    /* didn't move after all */
+               You("stop.  %s won't fit through.", upstart(y_monnam(mtmp)));
+           } else {
+               char pnambuf[BUFSZ];
+
+               /* save its current description in case of polymorph */
+               Strcpy(pnambuf, y_monnam(mtmp));
+               mtmp->mtrapped = 0;
+               remove_monster(x, y);
+               place_monster(mtmp, u.ux0, u.uy0);
+
+               /* check for displacing it into pools and traps */
+               switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) {
+               case 0:
+                   You("%s %s.", mtmp->mtame ? "displaced" : "frightened",
+                       pnambuf);
+                   break;
+               case 1:         /* trapped */
+               case 3:         /* changed levels */
+                   /* there's already been a trap message, reinforce it */
+                   abuse_dog(mtmp);
+                   adjalign(-3);
+                   break;
+               case 2:
+                   /* it may have drowned or died.  that's no way to
+                    * treat a pet!  your god gets angry.
+                    */
+                   if (rn2(4)) {
+                       You_feel("guilty about losing your pet like this.");
+                       u.ugangr++;
+                       adjalign(-15);
+                   }
+
+                   /* you killed your pet by direct action.
+                    * minliquid and mintrap don't know to do this
+                    */
+                   u.uconduct.killer++;
+                   break;
+               default:
+                   pline("that's strange, unknown mintrap result!");
+                   break;
+               }
+           }
+       }
+
+       reset_occupations();
+       if (flags.run) {
+           if ( flags.run < 8 )
+               if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) ||
+                       IS_FURNITURE(tmpr->typ))
+                   nomul(0);
+       }
+
+       if (hides_under(youmonst.data))
+           u.uundetected = OBJ_AT(u.ux, u.uy);
+       else if (youmonst.data->mlet == S_EEL)
+           u.uundetected = is_pool(u.ux, u.uy) && !Is_waterlevel(&u.uz);
+       else if (u.dx || u.dy)
+           u.uundetected = 0;
+
+       /*
+        * Mimics (or whatever) become noticeable if they move and are
+        * imitating something that doesn't move.  We could extend this
+        * to non-moving monsters...
+        */
+       if ((u.dx || u.dy) && (youmonst.m_ap_type == M_AP_OBJECT
+                               || youmonst.m_ap_type == M_AP_FURNITURE))
+           youmonst.m_ap_type = M_AP_NOTHING;
+
+       check_leash(u.ux0,u.uy0);
+
+       if(u.ux0 != u.ux || u.uy0 != u.uy) {
+           u.umoved = TRUE;
+           /* Clean old position -- vision_recalc() will print our new one. */
+           newsym(u.ux0,u.uy0);
+           /* Since the hero has moved, adjust what can be seen/unseen. */
+           vision_recalc(1);   /* Do the work now in the recover time. */
+           invocation_message();
+       }
+
+       if (Punished)                           /* put back ball and chain */
+           move_bc(0,bc_control,ballx,bally,chainx,chainy);
+
+       spoteffects(TRUE);
+
+       /* delay next move because of ball dragging */
+       /* must come after we finished picking up, in spoteffects() */
+       if (cause_delay) {
+           nomul(-2);
+           nomovemsg = "";
+       }
+
+       if (flags.run && iflags.runmode != RUN_TPORT) {
+           /* display every step or every 7th step depending upon mode */
+           if (iflags.runmode != RUN_LEAP || !(moves % 7L)) {
+               if (flags.time) flags.botl = 1;
+               curs_on_u();
+               delay_output();
+               if (iflags.runmode == RUN_CRAWL) {
+                   delay_output();
+                   delay_output();
+                   delay_output();
+                   delay_output();
+               }
+           }
+       }
+}
+
+void
+invocation_message()
+{
+       /* a special clue-msg when on the Invocation position */
+       if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) {
+           char buf[BUFSZ];
+           struct obj *otmp = carrying(CANDELABRUM_OF_INVOCATION);
+
+           nomul(0);           /* stop running or travelling */
+#ifdef STEED
+           if (u.usteed) Sprintf(buf, "beneath %s", y_monnam(u.usteed));
+           else
+#endif
+           if (Levitation || Flying) Strcpy(buf, "beneath you");
+           else Sprintf(buf, "under your %s", makeplural(body_part(FOOT)));
+
+           You_feel("a strange vibration %s.", buf);
+           if (otmp && otmp->spe == 7 && otmp->lamplit)
+               pline("%s %s!", The(xname(otmp)),
+                   Blind ? "throbs palpably" : "glows with a strange light");
+       }
+}
+
+#endif /* OVL3 */
+#ifdef OVL2
+
+void
+spoteffects(pick)
+boolean pick;
+{
+       register struct monst *mtmp;
+
+       if(u.uinwater) {
+               int was_underwater;
+
+               if (!is_pool(u.ux,u.uy)) {
+                       if (Is_waterlevel(&u.uz))
+                               You("pop into an air bubble.");
+                       else if (is_lava(u.ux, u.uy))
+                               You("leave the water...");      /* oops! */
+                       else
+                               You("are on solid %s again.",
+                                   is_ice(u.ux, u.uy) ? "ice" : "land");
+               }
+               else if (Is_waterlevel(&u.uz))
+                       goto stillinwater;
+               else if (Levitation)
+                       You("pop out of the water like a cork!");
+               else if (Flying)
+                       You("fly out of the water.");
+               else if (Wwalking)
+                       You("slowly rise above the surface.");
+               else
+                       goto stillinwater;
+               was_underwater = Underwater && !Is_waterlevel(&u.uz);
+               u.uinwater = 0;         /* leave the water */
+               if (was_underwater) {   /* restore vision */
+                       docrt();
+                       vision_full_recalc = 1;
+               }
+       }
+stillinwater:;
+       if (!Levitation && !u.ustuck && !Flying) {
+           /* limit recursive calls through teleds() */
+           if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) {
+#ifdef STEED
+               if (u.usteed && !is_flyer(u.usteed->data) &&
+                       !is_floater(u.usteed->data) &&
+                       !is_clinger(u.usteed->data)) {
+                   dismount_steed(Underwater ?
+                           DISMOUNT_FELL : DISMOUNT_GENERIC);
+                   /* dismount_steed() -> float_down() -> pickup() */
+                   if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz))
+                       pick = FALSE;
+               } else
+#endif
+               if (is_lava(u.ux, u.uy)) {
+                   if (lava_effects()) return;
+               } else if (!Wwalking && drown())
+                   return;
+           }
+       }
+       check_special_room(FALSE);
+#ifdef SINKS
+       if(IS_SINK(levl[u.ux][u.uy].typ) && Levitation)
+               dosinkfall();
+#endif
+       if (!in_steed_dismounting) { /* if dismounting, we'll check again later */
+               struct trap *trap = t_at(u.ux, u.uy);
+               boolean pit;
+               pit = (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT));
+               if (trap && pit)
+                       dotrap(trap, 0);        /* fall into pit */
+               if (pick) (void) pickup(1);
+               if (trap && !pit)
+                       dotrap(trap, 0);        /* fall into arrow trap, etc. */
+       }
+       if((mtmp = m_at(u.ux, u.uy)) && !u.uswallow) {
+               mtmp->mundetected = mtmp->msleeping = 0;
+               switch(mtmp->data->mlet) {
+                   case S_PIERCER:
+                       pline("%s suddenly drops from the %s!",
+                             Amonnam(mtmp), ceiling(u.ux,u.uy));
+                       if(mtmp->mtame) /* jumps to greet you, not attack */
+                           ;
+                       else if(uarmh && is_metallic(uarmh))
+                           pline("Its blow glances off your helmet.");
+                       else if (u.uac + 3 <= rnd(20))
+                           You("are almost hit by %s!",
+                               x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
+                       else {
+                           int dmg;
+                           You("are hit by %s!",
+                               x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
+                           dmg = d(4,6);
+                           if(Half_physical_damage) dmg = (dmg+1) / 2;
+                           mdamageu(mtmp, dmg);
+                       }
+                       break;
+                   default:    /* monster surprises you. */
+                       if(mtmp->mtame)
+                           pline("%s jumps near you from the %s.",
+                                       Amonnam(mtmp), ceiling(u.ux,u.uy));
+                       else if(mtmp->mpeaceful) {
+                               You("surprise %s!",
+                                   Blind && !sensemon(mtmp) ?
+                                   something : a_monnam(mtmp));
+                               mtmp->mpeaceful = 0;
+                       } else
+                           pline("%s attacks you by surprise!",
+                                       Amonnam(mtmp));
+                       break;
+               }
+               mnexto(mtmp); /* have to move the monster */
+       }
+}
+
+STATIC_OVL boolean
+monstinroom(mdat,roomno)
+struct permonst *mdat;
+int roomno;
+{
+       register struct monst *mtmp;
+
+       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+               if(!DEADMONSTER(mtmp) && mtmp->data == mdat &&
+                  index(in_rooms(mtmp->mx, mtmp->my, 0), roomno + ROOMOFFSET))
+                       return(TRUE);
+       return(FALSE);
+}
+
+char *
+in_rooms(x, y, typewanted)
+register xchar x, y;
+register int typewanted;
+{
+       static char buf[5];
+       char rno, *ptr = &buf[4];
+       int typefound, min_x, min_y, max_x, max_y_offset, step;
+       register struct rm *lev;
+
+#define goodtype(rno) (!typewanted || \
+            ((typefound = rooms[rno - ROOMOFFSET].rtype) == typewanted) || \
+            ((typewanted == SHOPBASE) && (typefound > SHOPBASE))) \
+
+       switch (rno = levl[x][y].roomno) {
+               case NO_ROOM:
+                       return(ptr);
+               case SHARED:
+                       step = 2;
+                       break;
+               case SHARED_PLUS:
+                       step = 1;
+                       break;
+               default:                        /* i.e. a regular room # */
+                       if (goodtype(rno))
+                               *(--ptr) = rno;
+                       return(ptr);
+       }
+
+       min_x = x - 1;
+       max_x = x + 1;
+       if (x < 1)
+               min_x += step;
+       else
+       if (x >= COLNO)
+               max_x -= step;
+
+       min_y = y - 1;
+       max_y_offset = 2;
+       if (min_y < 0) {
+               min_y += step;
+               max_y_offset -= step;
+       } else
+       if ((min_y + max_y_offset) >= ROWNO)
+               max_y_offset -= step;
+
+       for (x = min_x; x <= max_x; x += step) {
+               lev = &levl[x][min_y];
+               y = 0;
+               if (((rno = lev[y].roomno) >= ROOMOFFSET) &&
+                   !index(ptr, rno) && goodtype(rno))
+                       *(--ptr) = rno;
+               y += step;
+               if (y > max_y_offset)
+                       continue;
+               if (((rno = lev[y].roomno) >= ROOMOFFSET) &&
+                   !index(ptr, rno) && goodtype(rno))
+                       *(--ptr) = rno;
+               y += step;
+               if (y > max_y_offset)
+                       continue;
+               if (((rno = lev[y].roomno) >= ROOMOFFSET) &&
+                   !index(ptr, rno) && goodtype(rno))
+                       *(--ptr) = rno;
+       }
+       return(ptr);
+}
+
+/* is (x,y) in a town? */
+boolean
+in_town(x, y)
+register int x, y;
+{
+       s_level *slev = Is_special(&u.uz);
+       register struct mkroom *sroom;
+       boolean has_subrooms = FALSE;
+
+       if (!slev || !slev->flags.town) return FALSE;
+
+       /*
+        * See if (x,y) is in a room with subrooms, if so, assume it's the
+        * town.  If there are no subrooms, the whole level is in town.
+        */
+       for (sroom = &rooms[0]; sroom->hx > 0; sroom++) {
+           if (sroom->nsubrooms > 0) {
+               has_subrooms = TRUE;
+               if (inside_room(sroom, x, y)) return TRUE;
+           }
+       }
+
+       return !has_subrooms;
+}
+
+STATIC_OVL void
+move_update(newlev)
+register boolean newlev;
+{
+       char *ptr1, *ptr2, *ptr3, *ptr4;
+
+       Strcpy(u.urooms0, u.urooms);
+       Strcpy(u.ushops0, u.ushops);
+       if (newlev) {
+               u.urooms[0] = '\0';
+               u.uentered[0] = '\0';
+               u.ushops[0] = '\0';
+               u.ushops_entered[0] = '\0';
+               Strcpy(u.ushops_left, u.ushops0);
+               return;
+       }
+       Strcpy(u.urooms, in_rooms(u.ux, u.uy, 0));
+
+       for (ptr1 = &u.urooms[0],
+            ptr2 = &u.uentered[0],
+            ptr3 = &u.ushops[0],
+            ptr4 = &u.ushops_entered[0];
+            *ptr1; ptr1++) {
+               if (!index(u.urooms0, *ptr1))
+                       *(ptr2++) = *ptr1;
+               if (IS_SHOP(*ptr1 - ROOMOFFSET)) {
+                       *(ptr3++) = *ptr1;
+                       if (!index(u.ushops0, *ptr1))
+                               *(ptr4++) = *ptr1;
+               }
+       }
+       *ptr2 = '\0';
+       *ptr3 = '\0';
+       *ptr4 = '\0';
+
+       /* filter u.ushops0 -> u.ushops_left */
+       for (ptr1 = &u.ushops0[0], ptr2 = &u.ushops_left[0]; *ptr1; ptr1++)
+               if (!index(u.ushops, *ptr1))
+                       *(ptr2++) = *ptr1;
+       *ptr2 = '\0';
+}
+
+void
+check_special_room(newlev)
+register boolean newlev;
+{
+       register struct monst *mtmp;
+       char *ptr;
+
+       move_update(newlev);
+
+       if (*u.ushops0)
+           u_left_shop(u.ushops_left, newlev);
+
+       if (!*u.uentered && !*u.ushops_entered)         /* implied by newlev */
+           return;             /* no entrance messages necessary */
+
+       /* Did we just enter a shop? */
+       if (*u.ushops_entered)
+           u_entered_shop(u.ushops_entered);
+
+       for (ptr = &u.uentered[0]; *ptr; ptr++) {
+           register int roomno = *ptr - ROOMOFFSET, rt = rooms[roomno].rtype;
+
+           /* Did we just enter some other special room? */
+           /* vault.c insists that a vault remain a VAULT,
+            * and temples should remain TEMPLEs,
+            * but everything else gives a message only the first time */
+           switch (rt) {
+               case ZOO:
+                   pline("Welcome to David's treasure zoo!");
+                   break;
+               case SWAMP:
+                   pline("It %s rather %s down here.",
+                         Blind ? "feels" : "looks",
+                         Blind ? "humid" : "muddy");
+                   break;
+               case COURT:
+                   You("enter an opulent throne room!");
+                   break;
+               case LEPREHALL:
+                   You("enter a leprechaun hall!");
+                   break;
+               case MORGUE:
+                   if(midnight()) {
+                       const char *run = locomotion(youmonst.data, "Run");
+                       pline("%s away!  %s away!", run, run);
+                   } else
+                       You("have an uncanny feeling...");
+                   break;
+               case BEEHIVE:
+                   You("enter a giant beehive!");
+                   break;
+               case COCKNEST:
+                   You("enter a disgusting nest!");
+                   break;
+               case ANTHOLE:
+                   You("enter an anthole!");
+                   break;
+               case BARRACKS:
+                   if(monstinroom(&mons[PM_SOLDIER], roomno) ||
+                       monstinroom(&mons[PM_SERGEANT], roomno) ||
+                       monstinroom(&mons[PM_LIEUTENANT], roomno) ||
+                       monstinroom(&mons[PM_CAPTAIN], roomno))
+                       You("enter a military barracks!");
+                   else
+                       You("enter an abandoned barracks.");
+                   break;
+               case DELPHI:
+                   if(monstinroom(&mons[PM_ORACLE], roomno))
+                       verbalize("%s, %s, welcome to Delphi!",
+                                       Hello((struct monst *) 0), plname);
+                   break;
+               case TEMPLE:
+                   intemple(roomno + ROOMOFFSET);
+                   /* fall through */
+               default:
+                   rt = 0;
+           }
+
+           if (rt != 0) {
+               rooms[roomno].rtype = OROOM;
+               if (!search_special(rt)) {
+                       /* No more room of that type */
+                       switch(rt) {
+                           case COURT:
+                               level.flags.has_court = 0;
+                               break;
+                           case SWAMP:
+                               level.flags.has_swamp = 0;
+                               break;
+                           case MORGUE:
+                               level.flags.has_morgue = 0;
+                               break;
+                           case ZOO:
+                               level.flags.has_zoo = 0;
+                               break;
+                           case BARRACKS:
+                               level.flags.has_barracks = 0;
+                               break;
+                           case TEMPLE:
+                               level.flags.has_temple = 0;
+                               break;
+                           case BEEHIVE:
+                               level.flags.has_beehive = 0;
+                               break;
+                       }
+               }
+               if (rt == COURT || rt == SWAMP || rt == MORGUE || rt == ZOO)
+                   for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+                       if (!DEADMONSTER(mtmp) && !Stealth && !rn2(3)) mtmp->msleeping = 0;
+           }
+       }
+
+       return;
+}
+
+#endif /* OVL2 */
+#ifdef OVLB
+
+int
+dopickup()
+{
+       int count;
+       struct trap *traphere = t_at(u.ux, u.uy);
+       /* awful kludge to work around parse()'s pre-decrement */
+       count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0;
+       multi = 0;      /* always reset */
+       /* uswallow case added by GAN 01/29/87 */
+       if(u.uswallow) {
+           if (!u.ustuck->minvent) {
+               if (is_animal(u.ustuck->data)) {
+                   You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck)));
+                   pline("But it's kind of slimy, so you drop it.");
+               } else
+                   You("don't %s anything in here to pick up.",
+                         Blind ? "feel" : "see");
+               return(1);
+           } else {
+               int tmpcount = -count;
+               return loot_mon(u.ustuck, &tmpcount, (boolean *)0);
+           }
+       }
+       if(is_pool(u.ux, u.uy)) {
+           if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
+                       || (Flying && !Breathless)) {
+               You("cannot dive into the water to pick things up.");
+               return(0);
+           } else if (!Underwater) {
+               You_cant("even see the bottom, let alone pick up %s.",
+                               something);
+               return(0);
+           }
+       }
+       if (is_lava(u.ux, u.uy)) {
+           if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
+                       || (Flying && !Breathless)) {
+               You_cant("reach the bottom to pick things up.");
+               return(0);
+           } else if (!likes_lava(youmonst.data)) {
+               You("would burn to a crisp trying to pick things up.");
+               return(0);
+           }
+       }
+       if(!OBJ_AT(u.ux, u.uy)) {
+               There("is nothing here to pick up.");
+               return(0);
+       }
+       if (!can_reach_floor()) {
+#ifdef STEED
+               if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
+                   You("aren't skilled enough to reach from %s.",
+                       y_monnam(u.usteed));
+               else
+#endif
+               You("cannot reach the %s.", surface(u.ux,u.uy));
+               return(0);
+       }
+
+       if (traphere && traphere->tseen) {
+               /* Allow pickup from holes and trap doors that you escaped from
+                * because that stuff is teetering on the edge just like you, but
+                * not pits, because there is an elevation discrepancy with stuff
+                * in pits.
+                */
+               if ((traphere->ttyp == PIT || traphere->ttyp == SPIKED_PIT) &&
+                    (!u.utrap || (u.utrap && u.utraptype != TT_PIT))) {
+                       You("cannot reach the bottom of the pit.");
+                       return(0);
+               }
+       }
+
+       return (pickup(-count));
+}
+
+#endif /* OVLB */
+#ifdef OVL2
+
+/* stop running if we see something interesting */
+/* turn around a corner if that is the only way we can proceed */
+/* do not turn left or right twice */
+void
+lookaround()
+{
+    register int x, y, i, x0 = 0, y0 = 0, m0 = 1, i0 = 9;
+    register int corrct = 0, noturn = 0;
+    register struct monst *mtmp;
+    register struct trap *trap;
+
+    /* Grid bugs stop if trying to move diagonal, even if blind.  Maybe */
+    /* they polymorphed while in the middle of a long move. */
+    if (u.umonnum == PM_GRID_BUG && u.dx && u.dy) {
+       nomul(0);
+       return;
+    }
+
+    if(Blind || flags.run == 0) return;
+    for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++) {
+       if(!isok(x,y)) continue;
+
+       if(u.umonnum == PM_GRID_BUG && x != u.ux && y != u.uy) continue;
+
+       if(x == u.ux && y == u.uy) continue;
+
+       if((mtmp = m_at(x,y)) &&
+                   mtmp->m_ap_type != M_AP_FURNITURE &&
+                   mtmp->m_ap_type != M_AP_OBJECT &&
+                   (!mtmp->minvis || See_invisible) && !mtmp->mundetected) {
+           if((flags.run != 1 && !mtmp->mtame)
+                                       || (x == u.ux+u.dx && y == u.uy+u.dy))
+               goto stop;
+       }
+
+       if (levl[x][y].typ == STONE) continue;
+       if (x == u.ux-u.dx && y == u.uy-u.dy) continue;
+
+       if (IS_ROCK(levl[x][y].typ) || (levl[x][y].typ == ROOM) ||
+           IS_AIR(levl[x][y].typ))
+           continue;
+       else if (closed_door(x,y) ||
+                (mtmp && mtmp->m_ap_type == M_AP_FURNITURE &&
+                 (mtmp->mappearance == S_hcdoor ||
+                  mtmp->mappearance == S_vcdoor))) {
+           if(x != u.ux && y != u.uy) continue;
+           if(flags.run != 1) goto stop;
+           goto bcorr;
+       } else if (levl[x][y].typ == CORR) {
+bcorr:
+           if(levl[u.ux][u.uy].typ != ROOM) {
+               if(flags.run == 1 || flags.run == 3 || flags.run == 8) {
+                   i = dist2(x,y,u.ux+u.dx,u.uy+u.dy);
+                   if(i > 2) continue;
+                   if(corrct == 1 && dist2(x,y,x0,y0) != 1)
+                       noturn = 1;
+                   if(i < i0) {
+                       i0 = i;
+                       x0 = x;
+                       y0 = y;
+                       m0 = mtmp ? 1 : 0;
+                   }
+               }
+               corrct++;
+           }
+           continue;
+       } else if ((trap = t_at(x,y)) && trap->tseen) {
+           if(flags.run == 1) goto bcorr;      /* if you must */
+           if(x == u.ux+u.dx && y == u.uy+u.dy) goto stop;
+           continue;
+       } else if (is_pool(x,y) || is_lava(x,y)) {
+           /* water and lava only stop you if directly in front, and stop
+            * you even if you are running
+            */
+           if(!Levitation && !Flying && !is_clinger(youmonst.data) &&
+                               x == u.ux+u.dx && y == u.uy+u.dy)
+                       /* No Wwalking check; otherwise they'd be able
+                        * to test boots by trying to SHIFT-direction
+                        * into a pool and seeing if the game allowed it
+                        */
+                       goto stop;
+           continue;
+       } else {                /* e.g. objects or trap or stairs */
+           if(flags.run == 1) goto bcorr;
+           if(flags.run == 8) continue;
+           if(mtmp) continue;          /* d */
+           if(((x == u.ux - u.dx) && (y != u.uy + u.dy)) ||
+              ((y == u.uy - u.dy) && (x != u.ux + u.dx)))
+              continue;
+       }
+stop:
+       nomul(0);
+       return;
+    } /* end for loops */
+
+    if(corrct > 1 && flags.run == 2) goto stop;
+    if((flags.run == 1 || flags.run == 3 || flags.run == 8) &&
+       !noturn && !m0 && i0 && (corrct == 1 || (corrct == 2 && i0 == 1)))
+    {
+       /* make sure that we do not turn too far */
+       if(i0 == 2) {
+           if(u.dx == y0-u.uy && u.dy == u.ux-x0)
+               i = 2;          /* straight turn right */
+           else
+               i = -2;         /* straight turn left */
+       } else if(u.dx && u.dy) {
+           if((u.dx == u.dy && y0 == u.uy) || (u.dx != u.dy && y0 != u.uy))
+               i = -1;         /* half turn left */
+           else
+               i = 1;          /* half turn right */
+       } else {
+           if((x0-u.ux == y0-u.uy && !u.dy) || (x0-u.ux != y0-u.uy && u.dy))
+               i = 1;          /* half turn right */
+           else
+               i = -1;         /* half turn left */
+       }
+
+       i += u.last_str_turn;
+       if(i <= 2 && i >= -2) {
+           u.last_str_turn = i;
+           u.dx = x0-u.ux;
+           u.dy = y0-u.uy;
+       }
+    }
+}
+
+/* something like lookaround, but we are not running */
+/* react only to monsters that might hit us */
+int
+monster_nearby()
+{
+       register int x,y;
+       register struct monst *mtmp;
+
+       /* Also see the similar check in dochugw() in monmove.c */
+       for(x = u.ux-1; x <= u.ux+1; x++)
+           for(y = u.uy-1; y <= u.uy+1; y++) {
+               if(!isok(x,y)) continue;
+               if(x == u.ux && y == u.uy) continue;
+               if((mtmp = m_at(x,y)) &&
+                  mtmp->m_ap_type != M_AP_FURNITURE &&
+                  mtmp->m_ap_type != M_AP_OBJECT &&
+                  (!mtmp->mpeaceful || Hallucination) &&
+                  (!is_hider(mtmp->data) || !mtmp->mundetected) &&
+                  !noattacks(mtmp->data) &&
+                  mtmp->mcanmove && !mtmp->msleeping &&  /* aplvax!jcn */
+                  !onscary(u.ux, u.uy, mtmp) &&
+                  canspotmon(mtmp))
+                       return(1);
+       }
+       return(0);
+}
+
+void
+nomul(nval)
+       register int nval;
+{
+       if(multi < nval) return;        /* This is a bug fix by ab@unido */
+       u.uinvulnerable = FALSE;        /* Kludge to avoid ctrl-C bug -dlc */
+       u.usleep = 0;
+       multi = nval;
+       flags.travel = iflags.travel1 = flags.mv = flags.run = 0;
+}
+
+/* called when a non-movement, multi-turn action has completed */
+void
+unmul(msg_override)
+const char *msg_override;
+{
+       multi = 0;      /* caller will usually have done this already */
+       if (msg_override) nomovemsg = msg_override;
+       else if (!nomovemsg) nomovemsg = You_can_move_again;
+       if (*nomovemsg) pline(nomovemsg);
+       nomovemsg = 0;
+       u.usleep = 0;
+       if (afternmv) (*afternmv)();
+       afternmv = 0;
+}
+
+#endif /* OVL2 */
+#ifdef OVL1
+
+STATIC_OVL void
+maybe_wail()
+{
+    static short powers[] = { TELEPORT, SEE_INVIS, POISON_RES, COLD_RES,
+                             SHOCK_RES, FIRE_RES, SLEEP_RES, DISINT_RES,
+                             TELEPORT_CONTROL, STEALTH, FAST, INVIS };
+
+    if (moves <= wailmsg + 50) return;
+
+    wailmsg = moves;
+    if (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE)) {
+       const char *who;
+       int i, powercnt;
+
+       who = (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ?
+               urole.name.m : "Elf";
+       if (u.uhp == 1) {
+           pline("%s is about to die.", who);
+       } else {
+           for (i = 0, powercnt = 0; i < SIZE(powers); ++i)
+               if (u.uprops[powers[i]].intrinsic & INTRINSIC) ++powercnt;
+
+           pline(powercnt >= 4 ? "%s, all your powers will be lost..."
+                               : "%s, your life force is running out.", who);
+       }
+    } else {
+       You_hear(u.uhp == 1 ? "the wailing of the Banshee..."
+                           : "the howling of the CwnAnnwn...");
+    }
+}
+
+void
+losehp(n, knam, k_format)
+register int n;
+register const char *knam;
+boolean k_format;
+{
+       if (Upolyd) {
+               u.mh -= n;
+               if (u.mhmax < u.mh) u.mhmax = u.mh;
+               flags.botl = 1;
+               if (u.mh < 1)
+                   rehumanize();
+               else if (n > 0 && u.mh*10 < u.mhmax && Unchanging)
+                   maybe_wail();
+               return;
+       }
+
+       u.uhp -= n;
+       if(u.uhp > u.uhpmax)
+               u.uhpmax = u.uhp;       /* perhaps n was negative */
+       flags.botl = 1;
+       if(u.uhp < 1) {
+               killer_format = k_format;
+               killer = knam;          /* the thing that killed you */
+               You("die...");
+               done(DIED);
+       } else if (n > 0 && u.uhp*10 < u.uhpmax) {
+               maybe_wail();
+       }
+}
+
+int
+weight_cap()
+{
+       register long carrcap;
+
+       carrcap = 25*(ACURRSTR + ACURR(A_CON)) + 50;
+       if (Upolyd) {
+               /* consistent with can_carry() in mon.c */
+               if (youmonst.data->mlet == S_NYMPH)
+                       carrcap = MAX_CARR_CAP;
+               else if (!youmonst.data->cwt)
+                       carrcap = (carrcap * (long)youmonst.data->msize) / MZ_HUMAN;
+               else if (!strongmonst(youmonst.data)
+                       || (strongmonst(youmonst.data) && (youmonst.data->cwt > WT_HUMAN)))
+                       carrcap = (carrcap * (long)youmonst.data->cwt / WT_HUMAN);
+       }
+
+       if (Levitation || Is_airlevel(&u.uz)    /* pugh@cornell */
+#ifdef STEED
+                       || (u.usteed && strongmonst(u.usteed->data))
+#endif
+       )
+               carrcap = MAX_CARR_CAP;
+       else {
+               if(carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP;
+               if (!Flying) {
+                       if(EWounded_legs & LEFT_SIDE) carrcap -= 100;
+                       if(EWounded_legs & RIGHT_SIDE) carrcap -= 100;
+               }
+               if (carrcap < 0) carrcap = 0;
+       }
+       return((int) carrcap);
+}
+
+static int wc; /* current weight_cap(); valid after call to inv_weight() */
+
+/* returns how far beyond the normal capacity the player is currently. */
+/* inv_weight() is negative if the player is below normal capacity. */
+int
+inv_weight()
+{
+       register struct obj *otmp = invent;
+       register int wt = 0;
+
+#ifndef GOLDOBJ
+       /* when putting stuff into containers, gold is inserted at the head
+          of invent for easier manipulation by askchain & co, but it's also
+          retained in u.ugold in order to keep the status line accurate; we
+          mustn't add its weight in twice under that circumstance */
+       wt = (otmp && otmp->oclass == COIN_CLASS) ? 0 :
+               (int)((u.ugold + 50L) / 100L);
+#endif
+       while (otmp) {
+#ifndef GOLDOBJ
+               if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data))
+#else
+               if (otmp->oclass == COIN_CLASS)
+                       wt += (int)(((long)otmp->quan + 50L) / 100L);
+               else if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data))
+#endif
+                       wt += otmp->owt;
+               otmp = otmp->nobj;
+       }
+       wc = weight_cap();
+       return (wt - wc);
+}
+
+/*
+ * Returns 0 if below normal capacity, or the number of "capacity units"
+ * over the normal capacity the player is loaded.  Max is 5.
+ */
+int
+calc_capacity(xtra_wt)
+int xtra_wt;
+{
+    int cap, wt = inv_weight() + xtra_wt;
+
+    if (wt <= 0) return UNENCUMBERED;
+    if (wc <= 1) return OVERLOADED;
+    cap = (wt*2 / wc) + 1;
+    return min(cap, OVERLOADED);
+}
+
+int
+near_capacity()
+{
+    return calc_capacity(0);
+}
+
+int
+max_capacity()
+{
+    int wt = inv_weight();
+
+    return (wt - (2 * wc));
+}
+
+boolean
+check_capacity(str)
+const char *str;
+{
+    if(near_capacity() >= EXT_ENCUMBER) {
+       if(str)
+           pline(str);
+       else
+           You_cant("do that while carrying so much stuff.");
+       return 1;
+    }
+    return 0;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+int
+inv_cnt()
+{
+       register struct obj *otmp = invent;
+       register int ct = 0;
+
+       while(otmp){
+               ct++;
+               otmp = otmp->nobj;
+       }
+       return(ct);
+}
+
+#ifdef GOLDOBJ
+/* Counts the money in an object chain. */
+/* Intended use is for your or some monsters inventory, */
+/* now that u.gold/m.gold is gone.*/
+/* Counting money in a container might be possible too. */
+long
+money_cnt(otmp)
+struct obj *otmp;
+{
+        while(otmp) {
+               /* Must change when silver & copper is implemented: */
+               if (otmp->oclass == COIN_CLASS) return otmp->quan;
+               otmp = otmp->nobj;
+       }
+       return 0;
+}
+#endif
+#endif /* OVLB */
+
+/*hack.c*/
diff --git a/src/hacklib.c b/src/hacklib.c
new file mode 100644 (file)
index 0000000..0d08270
--- /dev/null
@@ -0,0 +1,615 @@
+/*     SCCS Id: @(#)hacklib.c  3.4     2002/12/13      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* Copyright (c) Robert Patrick Rankin, 1991             */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* We could include only config.h, except for the overlay definitions... */
+#include "hack.h"
+/*=
+    Assorted 'small' utility routines. They're virtually independent of
+NetHack, except that rounddiv may call panic().
+
+      return type     routine name    argument type(s)
+       boolean         digit           (char)
+       boolean         letter          (char)
+       char            highc           (char)
+       char            lowc            (char)
+       char *          lcase           (char *)
+       char *          upstart         (char *)
+       char *          mungspaces      (char *)
+       char *          eos             (char *)
+       char *          strkitten       (char *,char)
+       char *          s_suffix        (const char *)
+       char *          xcrypt          (const char *, char *)
+       boolean         onlyspace       (const char *)
+       char *          tabexpand       (char *)
+       char *          visctrl         (char)
+       const char *    ordin           (int)
+       char *          sitoa           (int)
+       int             sgn             (int)
+       int             rounddiv        (long, int)
+       int             distmin         (int, int, int, int)
+       int             dist2           (int, int, int, int)
+       boolean         online2         (int, int)
+       boolean         pmatch          (const char *, const char *)
+       int             strncmpi        (const char *, const char *, int)
+       char *          strstri         (const char *, const char *)
+       boolean         fuzzymatch      (const char *,const char *,const char *,boolean)
+       void            setrandom       (void)
+       int             getyear         (void)
+       char *          yymmdd          (time_t)
+       long            yyyymmdd        (time_t)
+       int             phase_of_the_moon       (void)
+       boolean         friday_13th     (void)
+       int             night           (void)
+       int             midnight        (void)
+=*/
+#ifdef LINT
+# define Static                /* pacify lint */
+#else
+# define Static static
+#endif
+
+#ifdef OVLB
+boolean
+digit(c)               /* is 'c' a digit? */
+    char c;
+{
+    return((boolean)('0' <= c && c <= '9'));
+}
+
+boolean
+letter(c)              /* is 'c' a letter?  note: '@' classed as letter */
+    char c;
+{
+    return((boolean)(('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z')));
+}
+#endif /* OVLB */
+
+#ifdef OVL1
+char
+highc(c)                       /* force 'c' into uppercase */
+    char c;
+{
+    return((char)(('a' <= c && c <= 'z') ? (c & ~040) : c));
+}
+
+char
+lowc(c)                        /* force 'c' into lowercase */
+    char c;
+{
+    return((char)(('A' <= c && c <= 'Z') ? (c | 040) : c));
+}
+#endif /* OVL1 */
+
+#ifdef OVLB
+char *
+lcase(s)               /* convert a string into all lowercase */
+    char *s;
+{
+    register char *p;
+
+    for (p = s; *p; p++)
+       if ('A' <= *p && *p <= 'Z') *p |= 040;
+    return s;
+}
+
+char *
+upstart(s)             /* convert first character of a string to uppercase */
+    char *s;
+{
+    if (s) *s = highc(*s);
+    return s;
+}
+
+/* remove excess whitespace from a string buffer (in place) */
+char *
+mungspaces(bp)
+char *bp;
+{
+    register char c, *p, *p2;
+    boolean was_space = TRUE;
+
+    for (p = p2 = bp; (c = *p) != '\0'; p++) {
+       if (c == '\t') c = ' ';
+       if (c != ' ' || !was_space) *p2++ = c;
+       was_space = (c == ' ');
+    }
+    if (was_space && p2 > bp) p2--;
+    *p2 = '\0';
+    return bp;
+}
+
+#endif /* OVLB */
+
+#ifdef OVL0
+char *
+eos(s)                 /* return the end of a string (pointing at '\0') */
+    register char *s;
+{
+    while (*s) s++;    /* s += strlen(s); */
+    return s;
+}
+
+/* strcat(s, {c,'\0'}); */
+char *
+strkitten(s, c)                /* append a character to a string (in place) */
+    char *s;
+    char c;
+{
+    char *p = eos(s);
+
+    *p++ = c;
+    *p = '\0';
+    return s;
+}
+
+char *
+s_suffix(s)            /* return a name converted to possessive */
+    const char *s;
+{
+    Static char buf[BUFSZ];
+
+    Strcpy(buf, s);
+    if(!strcmpi(buf, "it"))
+       Strcat(buf, "s");
+    else if(*(eos(buf)-1) == 's')
+       Strcat(buf, "'");
+    else
+       Strcat(buf, "'s");
+    return buf;
+}
+
+char *
+xcrypt(str, buf)       /* trivial text encryption routine (see makedefs) */
+const char *str;
+char *buf;
+{
+    register const char *p;
+    register char *q;
+    register int bitmask;
+
+    for (bitmask = 1, p = str, q = buf; *p; q++) {
+       *q = *p++;
+       if (*q & (32|64)) *q ^= bitmask;
+       if ((bitmask <<= 1) >= 32) bitmask = 1;
+    }
+    *q = '\0';
+    return buf;
+}
+#endif /* OVL0 */
+
+#ifdef OVL2
+boolean
+onlyspace(s)           /* is a string entirely whitespace? */
+    const char *s;
+{
+    for (; *s; s++)
+       if (*s != ' ' && *s != '\t') return FALSE;
+    return TRUE;
+}
+#endif /* OVL2 */
+
+#ifdef OVLB
+char *
+tabexpand(sbuf)                /* expand tabs into proper number of spaces */
+    char *sbuf;
+{
+    char buf[BUFSZ];
+    register char *bp, *s = sbuf;
+    register int idx;
+
+    if (!*s) return sbuf;
+
+    /* warning: no bounds checking performed */
+    for (bp = buf, idx = 0; *s; s++)
+       if (*s == '\t') {
+           do *bp++ = ' '; while (++idx % 8);
+       } else {
+           *bp++ = *s;
+           idx++;
+       }
+    *bp = 0;
+    return strcpy(sbuf, buf);
+}
+
+char *
+visctrl(c)             /* make a displayable string from a character */
+    char c;
+{
+    Static char ccc[3];
+
+    c &= 0177;
+
+    ccc[2] = '\0';
+    if (c < 040) {
+       ccc[0] = '^';
+       ccc[1] = c | 0100;      /* letter */
+    } else if (c == 0177) {
+       ccc[0] = '^';
+       ccc[1] = c & ~0100;     /* '?' */
+    } else {
+       ccc[0] = c;             /* printable character */
+       ccc[1] = '\0';
+    }
+    return ccc;
+}
+#endif /* OVLB */
+
+#ifdef OVL2
+const char *
+ordin(n)               /* return the ordinal suffix of a number */
+    int n;                     /* note: should be non-negative */
+{
+    register int dd = n % 10;
+
+    return (dd == 0 || dd > 3 || (n % 100) / 10 == 1) ? "th" :
+           (dd == 1) ? "st" : (dd == 2) ? "nd" : "rd";
+}
+#endif /* OVL2 */
+
+#ifdef OVL1
+char *
+sitoa(n)               /* make a signed digit string from a number */
+    int n;
+{
+    Static char buf[13];
+
+    Sprintf(buf, (n < 0) ? "%d" : "+%d", n);
+    return buf;
+}
+
+int
+sgn(n)                 /* return the sign of a number: -1, 0, or 1 */
+    int n;
+{
+    return (n < 0) ? -1 : (n != 0);
+}
+#endif /* OVL1 */
+
+#ifdef OVLB
+int
+rounddiv(x, y)         /* calculate x/y, rounding as appropriate */
+    long x;
+    int  y;
+{
+    int r, m;
+    int divsgn = 1;
+
+    if (y == 0)
+       panic("division by zero in rounddiv");
+    else if (y < 0) {
+       divsgn = -divsgn;  y = -y;
+    }
+    if (x < 0) {
+       divsgn = -divsgn;  x = -x;
+    }
+    r = x / y;
+    m = x % y;
+    if (2*m >= y) r++;
+
+    return divsgn * r;
+}
+#endif /* OVLB */
+
+#ifdef OVL0
+int
+distmin(x0, y0, x1, y1) /* distance between two points, in moves */
+    int x0, y0, x1, y1;
+{
+    register int dx = x0 - x1, dy = y0 - y1;
+    if (dx < 0) dx = -dx;
+    if (dy < 0) dy = -dy;
+  /*  The minimum number of moves to get from (x0,y0) to (x1,y1) is the
+   :  larger of the [absolute value of the] two deltas.
+   */
+    return (dx < dy) ? dy : dx;
+}
+
+int
+dist2(x0, y0, x1, y1)  /* square of euclidean distance between pair of pts */
+    int x0, y0, x1, y1;
+{
+    register int dx = x0 - x1, dy = y0 - y1;
+    return dx * dx + dy * dy;
+}
+
+boolean
+online2(x0, y0, x1, y1) /* are two points lined up (on a straight line)? */
+    int x0, y0, x1, y1;
+{
+    int dx = x0 - x1, dy = y0 - y1;
+    /*  If either delta is zero then they're on an orthogonal line,
+     *  else if the deltas are equal (signs ignored) they're on a diagonal.
+     */
+    return((boolean)(!dy || !dx || (dy == dx) || (dy + dx == 0)));     /* (dy == -dx) */
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+boolean
+pmatch(patrn, strng)   /* match a string against a pattern */
+    const char *patrn, *strng;
+{
+    char s, p;
+  /*
+   :  Simple pattern matcher:  '*' matches 0 or more characters, '?' matches
+   :  any single character.  Returns TRUE if 'strng' matches 'patrn'.
+   */
+pmatch_top:
+    s = *strng++;  p = *patrn++;       /* get next chars and pre-advance */
+    if (!p)                    /* end of pattern */
+       return((boolean)(s == '\0'));           /* matches iff end of string too */
+    else if (p == '*')         /* wildcard reached */
+       return((boolean)((!*patrn || pmatch(patrn, strng-1)) ? TRUE :
+               s ? pmatch(patrn-1, strng) : FALSE));
+    else if (p != s && (p != '?' || !s))  /* check single character */
+       return FALSE;           /* doesn't match */
+    else                               /* return pmatch(patrn, strng); */
+       goto pmatch_top;        /* optimize tail recursion */
+}
+#endif /* OVLB */
+
+#ifdef OVL2
+#ifndef STRNCMPI
+int
+strncmpi(s1, s2, n)    /* case insensitive counted string comparison */
+    register const char *s1, *s2;
+    register int n; /*(should probably be size_t, which is usually unsigned)*/
+{                                      /*{ aka strncasecmp }*/
+    register char t1, t2;
+
+    while (n--) {
+       if (!*s2) return (*s1 != 0);    /* s1 >= s2 */
+       else if (!*s1) return -1;       /* s1  < s2 */
+       t1 = lowc(*s1++);
+       t2 = lowc(*s2++);
+       if (t1 != t2) return (t1 > t2) ? 1 : -1;
+    }
+    return 0;                          /* s1 == s2 */
+}
+#endif /* STRNCMPI */
+#endif /* OVL2 */
+
+#ifdef OVLB
+#ifndef STRSTRI
+
+char *
+strstri(str, sub)      /* case insensitive substring search */
+    const char *str;
+    const char *sub;
+{
+    register const char *s1, *s2;
+    register int i, k;
+# define TABSIZ 0x20   /* 0x40 would be case-sensitive */
+    char tstr[TABSIZ], tsub[TABSIZ];   /* nibble count tables */
+# if 0
+    assert( (TABSIZ & ~(TABSIZ-1)) == TABSIZ ); /* must be exact power of 2 */
+    assert( &lowc != 0 );                      /* can't be unsafe macro */
+# endif
+
+    /* special case: empty substring */
+    if (!*sub) return (char *) str;
+
+    /* do some useful work while determining relative lengths */
+    for (i = 0; i < TABSIZ; i++)  tstr[i] = tsub[i] = 0;       /* init */
+    for (k = 0, s1 = str; *s1; k++)  tstr[*s1++ & (TABSIZ-1)]++;
+    for (      s2 = sub; *s2; --k)  tsub[*s2++ & (TABSIZ-1)]++;
+
+    /* evaluate the info we've collected */
+    if (k < 0) return (char *) 0;  /* sub longer than str, so can't match */
+    for (i = 0; i < TABSIZ; i++)       /* does sub have more 'x's than str? */
+       if (tsub[i] > tstr[i])  return (char *) 0;  /* match not possible */
+
+    /* now actually compare the substring repeatedly to parts of the string */
+    for (i = 0; i <= k; i++) {
+       s1 = &str[i];
+       s2 = sub;
+       while (lowc(*s1++) == lowc(*s2++))
+           if (!*s2)  return (char *) &str[i];         /* full match */
+    }
+    return (char *) 0; /* not found */
+}
+#endif /* STRSTRI */
+
+/* compare two strings for equality, ignoring the presence of specified
+   characters (typically whitespace) and possibly ignoring case */
+boolean
+fuzzymatch(s1, s2, ignore_chars, caseblind)
+    const char *s1, *s2;
+    const char *ignore_chars;
+    boolean caseblind;
+{
+    register char c1, c2;
+
+    do {
+       while ((c1 = *s1++) != '\0' && index(ignore_chars, c1) != 0) continue;
+       while ((c2 = *s2++) != '\0' && index(ignore_chars, c2) != 0) continue;
+       if (!c1 || !c2) break;  /* stop when end of either string is reached */
+
+       if (caseblind) {
+           c1 = lowc(c1);
+           c2 = lowc(c2);
+       }
+    } while (c1 == c2);
+
+    /* match occurs only when the end of both strings has been reached */
+    return (boolean)(!c1 && !c2);
+}
+
+#endif /* OVLB */
+#ifdef OVL2
+
+/*
+ * Time routines
+ *
+ * The time is used for:
+ *     - seed for rand()
+ *     - year on tombstone and yyyymmdd in record file
+ *     - phase of the moon (various monsters react to NEW_MOON or FULL_MOON)
+ *     - night and midnight (the undead are dangerous at midnight)
+ *     - determination of what files are "very old"
+ */
+
+#if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) && !defined(_DCC) && !defined(__GNUC__)
+extern struct tm *FDECL(localtime,(time_t *));
+#endif
+static struct tm *NDECL(getlt);
+
+void
+setrandom()
+{
+       /* the types are different enough here that sweeping the different
+        * routine names into one via #defines is even more confusing
+        */
+#ifdef RANDOM  /* srandom() from sys/share/random.c */
+       srandom((unsigned int) time((time_t *)0));
+#else
+# if defined(__APPLE__) || defined(BSD) || defined(LINUX) || defined(ULTRIX) || defined(CYGWIN32) /* system srandom() */
+#  if defined(BSD) && !defined(POSIX_TYPES)
+#   if defined(SUNOS4)
+       (void)
+#   endif
+               srandom((int) time((long *)0));
+#  else
+               srandom((int) time((time_t *)0));
+#  endif
+# else
+#  ifdef UNIX  /* system srand48() */
+       srand48((long) time((time_t *)0));
+#  else                /* poor quality system routine */
+       srand((int) time((time_t *)0));
+#  endif
+# endif
+#endif
+}
+
+static struct tm *
+getlt()
+{
+       time_t date;
+
+#if defined(BSD) && !defined(POSIX_TYPES)
+       (void) time((long *)(&date));
+#else
+       (void) time(&date);
+#endif
+#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES))
+       return(localtime((long *)(&date)));
+#else
+       return(localtime(&date));
+#endif
+}
+
+int
+getyear()
+{
+       return(1900 + getlt()->tm_year);
+}
+
+#if 0
+/* This routine is no longer used since in 2000 it will yield "100mmdd". */
+char *
+yymmdd(date)
+time_t date;
+{
+       Static char datestr[10];
+       struct tm *lt;
+
+       if (date == 0)
+               lt = getlt();
+       else
+#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD)
+               lt = localtime((long *)(&date));
+#else
+               lt = localtime(&date);
+#endif
+
+       Sprintf(datestr, "%02d%02d%02d",
+               lt->tm_year, lt->tm_mon + 1, lt->tm_mday);
+       return(datestr);
+}
+#endif
+
+long
+yyyymmdd(date)
+time_t date;
+{
+       long datenum;
+       struct tm *lt;
+
+       if (date == 0)
+               lt = getlt();
+       else
+#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES))
+               lt = localtime((long *)(&date));
+#else
+               lt = localtime(&date);
+#endif
+
+       /* just in case somebody's localtime supplies (year % 100)
+          rather than the expected (year - 1900) */
+       if (lt->tm_year < 70)
+           datenum = (long)lt->tm_year + 2000L;
+       else
+           datenum = (long)lt->tm_year + 1900L;
+       /* yyyy --> yyyymm */
+       datenum = datenum * 100L + (long)(lt->tm_mon + 1);
+       /* yyyymm --> yyyymmdd */
+       datenum = datenum * 100L + (long)lt->tm_mday;
+       return datenum;
+}
+
+/*
+ * moon period = 29.53058 days ~= 30, year = 365.2422 days
+ * days moon phase advances on first day of year compared to preceding year
+ *     = 365.2422 - 12*29.53058 ~= 11
+ * years in Metonic cycle (time until same phases fall on the same days of
+ *     the month) = 18.6 ~= 19
+ * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30
+ *     (29 as initial condition)
+ * current phase in days = first day phase + days elapsed in year
+ * 6 moons ~= 177 days
+ * 177 ~= 8 reported phases * 22
+ * + 11/22 for rounding
+ */
+int
+phase_of_the_moon()            /* 0-7, with 0: new, 4: full */
+{
+       register struct tm *lt = getlt();
+       register int epact, diy, goldn;
+
+       diy = lt->tm_yday;
+       goldn = (lt->tm_year % 19) + 1;
+       epact = (11 * goldn + 18) % 30;
+       if ((epact == 25 && goldn > 11) || epact == 24)
+               epact++;
+
+       return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
+}
+
+boolean
+friday_13th()
+{
+       register struct tm *lt = getlt();
+
+       return((boolean)(lt->tm_wday == 5 /* friday */ && lt->tm_mday == 13));
+}
+
+int
+night()
+{
+       register int hour = getlt()->tm_hour;
+
+       return(hour < 6 || hour > 21);
+}
+
+int
+midnight()
+{
+       return(getlt()->tm_hour == 0);
+}
+#endif /* OVL2 */
+
+/*hacklib.c*/
diff --git a/src/invent.c b/src/invent.c
new file mode 100644 (file)
index 0000000..b9a3683
--- /dev/null
@@ -0,0 +1,2934 @@
+/*     SCCS Id: @(#)invent.c   3.4     2003/12/02      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+#define NOINVSYM       '#'
+#define CONTAINED_SYM  '>'     /* designator for inside a container */
+
+#ifdef OVL1
+STATIC_DCL void NDECL(reorder_invent);
+STATIC_DCL boolean FDECL(mergable,(struct obj *,struct obj *));
+STATIC_DCL void FDECL(invdisp_nothing, (const char *,const char *));
+STATIC_DCL boolean FDECL(worn_wield_only, (struct obj *));
+STATIC_DCL boolean FDECL(only_here, (struct obj *));
+#endif /* OVL1 */
+STATIC_DCL void FDECL(compactify,(char *));
+STATIC_DCL boolean FDECL(taking_off, (const char *));
+STATIC_DCL boolean FDECL(putting_on, (const char *));
+STATIC_PTR int FDECL(ckunpaid,(struct obj *));
+STATIC_PTR int FDECL(ckvalidcat,(struct obj *));
+static char FDECL(display_pickinv, (const char *,BOOLEAN_P, long *));
+#ifdef OVLB
+STATIC_DCL boolean FDECL(this_type_only, (struct obj *));
+STATIC_DCL void NDECL(dounpaid);
+STATIC_DCL struct obj *FDECL(find_unpaid,(struct obj *,struct obj **));
+STATIC_DCL void FDECL(menu_identify, (int));
+STATIC_DCL boolean FDECL(tool_in_use, (struct obj *));
+#endif /* OVLB */
+STATIC_DCL char FDECL(obj_to_let,(struct obj *));
+
+#ifdef OVLB
+
+static int lastinvnr = 51;     /* 0 ... 51 (never saved&restored) */
+
+#ifdef WIZARD
+/* wizards can wish for venom, which will become an invisible inventory
+ * item without this.  putting it in inv_order would mean venom would
+ * suddenly become a choice for all the inventory-class commands, which
+ * would probably cause mass confusion.  the test for inventory venom
+ * is only WIZARD and not wizard because the wizard can leave venom lying
+ * around on a bones level for normal players to find.
+ */
+static char venom_inv[] = { VENOM_CLASS, 0 };  /* (constant) */
+#endif
+
+void
+assigninvlet(otmp)
+register struct obj *otmp;
+{
+       boolean inuse[52];
+       register int i;
+       register struct obj *obj;
+
+#ifdef GOLDOBJ
+        /* There is only one of these in inventory... */        
+        if (otmp->oclass == COIN_CLASS) {
+           otmp->invlet = GOLD_SYM;
+           return;
+       }
+#endif
+
+       for(i = 0; i < 52; i++) inuse[i] = FALSE;
+       for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
+               i = obj->invlet;
+               if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
+               if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
+               if(i == otmp->invlet) otmp->invlet = 0;
+       }
+       if((i = otmp->invlet) &&
+           (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
+               return;
+       for(i = lastinvnr+1; i != lastinvnr; i++) {
+               if(i == 52) { i = -1; continue; }
+               if(!inuse[i]) break;
+       }
+       otmp->invlet = (inuse[i] ? NOINVSYM :
+                       (i < 26) ? ('a'+i) : ('A'+i-26));
+       lastinvnr = i;
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+/* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
+#define inv_rank(o) ((o)->invlet ^ 040)
+
+/* sort the inventory; used by addinv() and doorganize() */
+STATIC_OVL void
+reorder_invent()
+{
+       struct obj *otmp, *prev, *next;
+       boolean need_more_sorting;
+
+       do {
+           /*
+            * We expect at most one item to be out of order, so this
+            * isn't nearly as inefficient as it may first appear.
+            */
+           need_more_sorting = FALSE;
+           for (otmp = invent, prev = 0; otmp; ) {
+               next = otmp->nobj;
+               if (next && inv_rank(next) < inv_rank(otmp)) {
+                   need_more_sorting = TRUE;
+                   if (prev) prev->nobj = next;
+                   else      invent = next;
+                   otmp->nobj = next->nobj;
+                   next->nobj = otmp;
+                   prev = next;
+               } else {
+                   prev = otmp;
+                   otmp = next;
+               }
+           }
+       } while (need_more_sorting);
+}
+
+#undef inv_rank
+
+/* scan a list of objects to see whether another object will merge with
+   one of them; used in pickup.c when all 52 inventory slots are in use,
+   to figure out whether another object could still be picked up */
+struct obj *
+merge_choice(objlist, obj)
+struct obj *objlist, *obj;
+{
+       struct monst *shkp;
+       int save_nocharge;
+
+       if (obj->otyp == SCR_SCARE_MONSTER)     /* punt on these */
+           return (struct obj *)0;
+       /* if this is an item on the shop floor, the attributes it will
+          have when carried are different from what they are now; prevent
+          that from eliciting an incorrect result from mergable() */
+       save_nocharge = obj->no_charge;
+       if (objlist == invent && obj->where == OBJ_FLOOR &&
+               (shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) {
+           if (obj->no_charge) obj->no_charge = 0;
+           /* A billable object won't have its `unpaid' bit set, so would
+              erroneously seem to be a candidate to merge with a similar
+              ordinary object.  That's no good, because once it's really
+              picked up, it won't merge after all.  It might merge with
+              another unpaid object, but we can't check that here (depends
+              too much upon shk's bill) and if it doesn't merge it would
+              end up in the '#' overflow inventory slot, so reject it now. */
+           else if (inhishop(shkp)) return (struct obj *)0;
+       }
+       while (objlist) {
+           if (mergable(objlist, obj)) break;
+           objlist = objlist->nobj;
+       }
+       obj->no_charge = save_nocharge;
+       return objlist;
+}
+
+/* merge obj with otmp and delete obj if types agree */
+int
+merged(potmp, pobj)
+struct obj **potmp, **pobj;
+{
+       register struct obj *otmp = *potmp, *obj = *pobj;
+
+       if(mergable(otmp, obj)) {
+               /* Approximate age: we do it this way because if we were to
+                * do it "accurately" (merge only when ages are identical)
+                * we'd wind up never merging any corpses.
+                * otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
+                *
+                * Don't do the age manipulation if lit.  We would need
+                * to stop the burn on both items, then merge the age,
+                * then restart the burn.
+                */
+               if (!obj->lamplit)
+                   otmp->age = ((otmp->age*otmp->quan) + (obj->age*obj->quan))
+                           / (otmp->quan + obj->quan);
+
+               otmp->quan += obj->quan;
+#ifdef GOLDOBJ
+                /* temporary special case for gold objects!!!! */
+#endif
+               if (otmp->oclass == COIN_CLASS) otmp->owt = weight(otmp);
+               else otmp->owt += obj->owt;
+               if(!otmp->onamelth && obj->onamelth)
+                       otmp = *potmp = oname(otmp, ONAME(obj));
+               obj_extract_self(obj);
+
+               /* really should merge the timeouts */
+               if (obj->lamplit) obj_merge_light_sources(obj, otmp);
+               if (obj->timed) obj_stop_timers(obj);   /* follows lights */
+
+               /* fixup for `#adjust' merging wielded darts, daggers, &c */
+               if (obj->owornmask && carried(otmp)) {
+                   long wmask = otmp->owornmask | obj->owornmask;
+
+                   /* Both the items might be worn in competing slots;
+                      merger preference (regardless of which is which):
+                        primary weapon + alternate weapon -> primary weapon;
+                        primary weapon + quiver -> primary weapon;
+                        alternate weapon + quiver -> alternate weapon.
+                      (Prior to 3.3.0, it was not possible for the two
+                      stacks to be worn in different slots and `obj'
+                      didn't need to be unworn when merging.) */
+                   if (wmask & W_WEP) wmask = W_WEP;
+                   else if (wmask & W_SWAPWEP) wmask = W_SWAPWEP;
+                   else if (wmask & W_QUIVER) wmask = W_QUIVER;
+                   else {
+                       impossible("merging strangely worn items (%lx)", wmask);
+                       wmask = otmp->owornmask;
+                   }
+                   if ((otmp->owornmask & ~wmask) != 0L) setnotworn(otmp);
+                   setworn(otmp, wmask);
+                   setnotworn(obj);
+               }
+#if 0
+               /* (this should not be necessary, since items
+                   already in a monster's inventory don't ever get
+                   merged into other objects [only vice versa]) */
+               else if (obj->owornmask && mcarried(otmp)) {
+                   if (obj == MON_WEP(otmp->ocarry)) {
+                       MON_WEP(otmp->ocarry) = otmp;
+                       otmp->owornmask = W_WEP;
+                   }
+               }
+#endif /*0*/
+
+               obfree(obj,otmp);       /* free(obj), bill->otmp */
+               return(1);
+       }
+       return 0;
+}
+
+/*
+Adjust hero intrinsics as if this object was being added to the hero's
+inventory.  Called _before_ the object has been added to the hero's
+inventory.
+
+This is called when adding objects to the hero's inventory normally (via
+addinv) or when an object in the hero's inventory has been polymorphed
+in-place.
+
+It may be valid to merge this code with with addinv_core2().
+*/
+void
+addinv_core1(obj)
+struct obj *obj;
+{
+       if (obj->oclass == COIN_CLASS) {
+#ifndef GOLDOBJ
+               u.ugold += obj->quan;
+#else
+               flags.botl = 1;
+#endif
+       } else if (obj->otyp == AMULET_OF_YENDOR) {
+               if (u.uhave.amulet) impossible("already have amulet?");
+               u.uhave.amulet = 1;
+       } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
+               if (u.uhave.menorah) impossible("already have candelabrum?");
+               u.uhave.menorah = 1;
+       } else if (obj->otyp == BELL_OF_OPENING) {
+               if (u.uhave.bell) impossible("already have silver bell?");
+               u.uhave.bell = 1;
+       } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
+               if (u.uhave.book) impossible("already have the book?");
+               u.uhave.book = 1;
+       } else if (obj->oartifact) {
+               if (is_quest_artifact(obj)) {
+                   if (u.uhave.questart)
+                       impossible("already have quest artifact?");
+                   u.uhave.questart = 1;
+                   artitouch();
+               }
+               set_artifact_intrinsic(obj, 1, W_ART);
+       }
+}
+
+/*
+Adjust hero intrinsics as if this object was being added to the hero's
+inventory.  Called _after_ the object has been added to the hero's
+inventory.
+
+This is called when adding objects to the hero's inventory normally (via
+addinv) or when an object in the hero's inventory has been polymorphed
+in-place.
+*/
+void
+addinv_core2(obj)
+struct obj *obj;
+{
+       if (confers_luck(obj)) {
+               /* new luckstone must be in inventory by this point
+                * for correct calculation */
+               set_moreluck();
+       }
+}
+
+/*
+Add obj to the hero's inventory.  Make sure the object is "free".
+Adjust hero attributes as necessary.
+*/
+struct obj *
+addinv(obj)
+struct obj *obj;
+{
+       struct obj *otmp, *prev;
+
+       if (obj->where != OBJ_FREE)
+           panic("addinv: obj not free");
+       obj->no_charge = 0;     /* not meaningful for invent */
+
+       addinv_core1(obj);
+#ifndef GOLDOBJ
+       /* if handed gold, we're done */
+       if (obj->oclass == COIN_CLASS)
+           return obj;
+#endif
+
+       /* merge if possible; find end of chain in the process */
+       for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
+           if (merged(&otmp, &obj)) {
+               obj = otmp;
+               goto added;
+           }
+       /* didn't merge, so insert into chain */
+       if (flags.invlet_constant || !prev) {
+           if (flags.invlet_constant) assigninvlet(obj);
+           obj->nobj = invent;         /* insert at beginning */
+           invent = obj;
+           if (flags.invlet_constant) reorder_invent();
+       } else {
+           prev->nobj = obj;           /* insert at end */
+           obj->nobj = 0;
+       }
+       obj->where = OBJ_INVENT;
+
+added:
+       addinv_core2(obj);
+       carry_obj_effects(obj);         /* carrying affects the obj */
+       update_inventory();
+       return(obj);
+}
+
+/*
+ * Some objects are affected by being carried.
+ * Make those adjustments here. Called _after_ the object
+ * has been added to the hero's or monster's inventory,
+ * and after hero's intrinsics have been updated.
+ */
+void
+carry_obj_effects(obj)
+struct obj *obj;
+{
+       /* Cursed figurines can spontaneously transform
+          when carried. */
+       if (obj->otyp == FIGURINE) {
+               if (obj->cursed
+                   && obj->corpsenm != NON_PM
+                   && !dead_species(obj->corpsenm,TRUE)) {
+                       attach_fig_transform_timeout(obj);
+                   }
+       }
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+/* Add an item to the inventory unless we're fumbling or it refuses to be
+ * held (via touch_artifact), and give a message.
+ * If there aren't any free inventory slots, we'll drop it instead.
+ * If both success and failure messages are NULL, then we're just doing the
+ * fumbling/slot-limit checking for a silent grab.  In any case,
+ * touch_artifact will print its own messages if they are warranted.
+ */
+struct obj *
+hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
+struct obj *obj;
+const char *drop_fmt, *drop_arg, *hold_msg;
+{
+       char buf[BUFSZ];
+
+       if (!Blind) obj->dknown = 1;    /* maximize mergibility */
+       if (obj->oartifact) {
+           /* place_object may change these */
+           boolean crysknife = (obj->otyp == CRYSKNIFE);
+           int oerode = obj->oerodeproof;
+           boolean wasUpolyd = Upolyd;
+
+           /* in case touching this object turns out to be fatal */
+           place_object(obj, u.ux, u.uy);
+
+           if (!touch_artifact(obj, &youmonst)) {
+               obj_extract_self(obj);  /* remove it from the floor */
+               dropy(obj);             /* now put it back again :-) */
+               return obj;
+           } else if (wasUpolyd && !Upolyd) {
+               /* loose your grip if you revert your form */
+               if (drop_fmt) pline(drop_fmt, drop_arg);
+               obj_extract_self(obj);
+               dropy(obj);
+               return obj;
+           }
+           obj_extract_self(obj);
+           if (crysknife) {
+               obj->otyp = CRYSKNIFE;
+               obj->oerodeproof = oerode;
+           }
+       }
+       if (Fumbling) {
+           if (drop_fmt) pline(drop_fmt, drop_arg);
+           dropy(obj);
+       } else {
+           long oquan = obj->quan;
+           int prev_encumbr = near_capacity(); /* before addinv() */
+
+           /* encumbrance only matters if it would now become worse
+              than max( current_value, stressed ) */
+           if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER;
+           /* addinv() may redraw the entire inventory, overwriting
+              drop_arg when it comes from something like doname() */
+           if (drop_arg) drop_arg = strcpy(buf, drop_arg);
+
+           obj = addinv(obj);
+           if (inv_cnt() > 52
+                   || ((obj->otyp != LOADSTONE || !obj->cursed)
+                       && near_capacity() > prev_encumbr)) {
+               if (drop_fmt) pline(drop_fmt, drop_arg);
+               /* undo any merge which took place */
+               if (obj->quan > oquan) obj = splitobj(obj, oquan);
+               dropx(obj);
+           } else {
+               if (flags.autoquiver && !uquiver && !obj->owornmask &&
+                       (is_missile(obj) ||
+                           ammo_and_launcher(obj, uwep) ||
+                           ammo_and_launcher(obj, uswapwep)))
+                   setuqwep(obj);
+               if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan);
+           }
+       }
+       return obj;
+}
+
+/* useup() all of an item regardless of its quantity */
+void
+useupall(obj)
+struct obj *obj;
+{
+       setnotworn(obj);
+       freeinv(obj);
+       obfree(obj, (struct obj *)0);   /* deletes contents also */
+}
+
+void
+useup(obj)
+register struct obj *obj;
+{
+       /*  Note:  This works correctly for containers because they */
+       /*         (containers) don't merge.                        */
+       if (obj->quan > 1L) {
+               obj->in_use = FALSE;    /* no longer in use */
+               obj->quan--;
+               obj->owt = weight(obj);
+               update_inventory();
+       } else {
+               useupall(obj);
+       }
+}
+
+/* use one charge from an item and possibly incur shop debt for it */
+void
+consume_obj_charge(obj, maybe_unpaid)
+struct obj *obj;
+boolean maybe_unpaid;  /* false if caller handles shop billing */
+{
+       if (maybe_unpaid) check_unpaid(obj);
+       obj->spe -= 1;
+       if (obj->known) update_inventory();
+}
+
+#endif /* OVLB */
+#ifdef OVL3
+
+/*
+Adjust hero's attributes as if this object was being removed from the
+hero's inventory.  This should only be called from freeinv() and
+where we are polymorphing an object already in the hero's inventory.
+
+Should think of a better name...
+*/
+void
+freeinv_core(obj)
+struct obj *obj;
+{
+       if (obj->oclass == COIN_CLASS) {
+#ifndef GOLDOBJ
+               u.ugold -= obj->quan;
+               obj->in_use = FALSE;
+#endif
+               flags.botl = 1;
+               return;
+       } else if (obj->otyp == AMULET_OF_YENDOR) {
+               if (!u.uhave.amulet) impossible("don't have amulet?");
+               u.uhave.amulet = 0;
+       } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
+               if (!u.uhave.menorah) impossible("don't have candelabrum?");
+               u.uhave.menorah = 0;
+       } else if (obj->otyp == BELL_OF_OPENING) {
+               if (!u.uhave.bell) impossible("don't have silver bell?");
+               u.uhave.bell = 0;
+       } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
+               if (!u.uhave.book) impossible("don't have the book?");
+               u.uhave.book = 0;
+       } else if (obj->oartifact) {
+               if (is_quest_artifact(obj)) {
+                   if (!u.uhave.questart)
+                       impossible("don't have quest artifact?");
+                   u.uhave.questart = 0;
+               }
+               set_artifact_intrinsic(obj, 0, W_ART);
+       }
+
+       if (obj->otyp == LOADSTONE) {
+               curse(obj);
+       } else if (confers_luck(obj)) {
+               set_moreluck();
+               flags.botl = 1;
+       } else if (obj->otyp == FIGURINE && obj->timed) {
+               (void) stop_timer(FIG_TRANSFORM, (genericptr_t) obj);
+       }
+}
+
+/* remove an object from the hero's inventory */
+void
+freeinv(obj)
+register struct obj *obj;
+{
+       extract_nobj(obj, &invent);
+       freeinv_core(obj);
+       update_inventory();
+}
+
+void
+delallobj(x, y)
+int x, y;
+{
+       struct obj *otmp, *otmp2;
+
+       for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
+               if (otmp == uball)
+                       unpunish();
+               /* after unpunish(), or might get deallocated chain */
+               otmp2 = otmp->nexthere;
+               if (otmp == uchain)
+                       continue;
+               delobj(otmp);
+       }
+}
+
+#endif /* OVL3 */
+#ifdef OVL2
+
+/* destroy object in fobj chain (if unpaid, it remains on the bill) */
+void
+delobj(obj)
+register struct obj *obj;
+{
+       boolean update_map;
+
+       if (obj->otyp == AMULET_OF_YENDOR ||
+                       obj->otyp == CANDELABRUM_OF_INVOCATION ||
+                       obj->otyp == BELL_OF_OPENING ||
+                       obj->otyp == SPE_BOOK_OF_THE_DEAD) {
+               /* player might be doing something stupid, but we
+                * can't guarantee that.  assume special artifacts
+                * are indestructible via drawbridges, and exploding
+                * chests, and golem creation, and ...
+                */
+               return;
+       }
+       update_map = (obj->where == OBJ_FLOOR);
+       obj_extract_self(obj);
+       if (update_map) newsym(obj->ox, obj->oy);
+       obfree(obj, (struct obj *) 0);  /* frees contents also */
+}
+
+#endif /* OVL2 */
+#ifdef OVL0
+
+struct obj *
+sobj_at(n,x,y)
+register int n, x, y;
+{
+       register struct obj *otmp;
+
+       for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
+               if(otmp->otyp == n)
+                   return(otmp);
+       return((struct obj *)0);
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+struct obj *
+carrying(type)
+register int type;
+{
+       register struct obj *otmp;
+
+       for(otmp = invent; otmp; otmp = otmp->nobj)
+               if(otmp->otyp == type)
+                       return(otmp);
+       return((struct obj *) 0);
+}
+
+const char *
+currency(amount)
+long amount;
+{
+       if (amount == 1L) return "zorkmid";
+       else return "zorkmids";
+}
+
+boolean
+have_lizard()
+{
+       register struct obj *otmp;
+
+       for(otmp = invent; otmp; otmp = otmp->nobj)
+               if(otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
+                       return(TRUE);
+       return(FALSE);
+}
+
+struct obj *
+o_on(id, objchn)
+unsigned int id;
+register struct obj *objchn;
+{
+       struct obj *temp;
+
+       while(objchn) {
+               if(objchn->o_id == id) return(objchn);
+               if (Has_contents(objchn) && (temp = o_on(id,objchn->cobj)))
+                       return temp;
+               objchn = objchn->nobj;
+       }
+       return((struct obj *) 0);
+}
+
+boolean
+obj_here(obj, x, y)
+register struct obj *obj;
+int x, y;
+{
+       register struct obj *otmp;
+
+       for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
+               if(obj == otmp) return(TRUE);
+       return(FALSE);
+}
+
+#endif /* OVLB */
+#ifdef OVL2
+
+struct obj *
+g_at(x,y)
+register int x, y;
+{
+       register struct obj *obj = level.objects[x][y];
+       while(obj) {
+           if (obj->oclass == COIN_CLASS) return obj;
+           obj = obj->nexthere;
+       }
+       return((struct obj *)0);
+}
+
+#endif /* OVL2 */
+#ifdef OVLB
+#ifndef GOLDOBJ
+/* Make a gold object from the hero's gold. */
+struct obj *
+mkgoldobj(q)
+register long q;
+{
+       register struct obj *otmp;
+
+       otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
+       u.ugold -= q;
+       otmp->quan = q;
+       otmp->owt = weight(otmp);
+       flags.botl = 1;
+       return(otmp);
+}
+#endif
+#endif /* OVLB */
+#ifdef OVL1
+
+STATIC_OVL void
+compactify(buf)
+register char *buf;
+/* compact a string of inventory letters by dashing runs of letters */
+{
+       register int i1 = 1, i2 = 1;
+       register char ilet, ilet1, ilet2;
+
+       ilet2 = buf[0];
+       ilet1 = buf[1];
+       buf[++i2] = buf[++i1];
+       ilet = buf[i1];
+       while(ilet) {
+               if(ilet == ilet1+1) {
+                       if(ilet1 == ilet2+1)
+                               buf[i2 - 1] = ilet1 = '-';
+                       else if(ilet2 == '-') {
+                               buf[i2 - 1] = ++ilet1;
+                               buf[i2] = buf[++i1];
+                               ilet = buf[i1];
+                               continue;
+                       }
+               }
+               ilet2 = ilet1;
+               ilet1 = ilet;
+               buf[++i2] = buf[++i1];
+               ilet = buf[i1];
+       }
+}
+
+/* match the prompt for either 'T' or 'R' command */
+STATIC_OVL boolean
+taking_off(action)
+const char *action;
+{
+    return !strcmp(action, "take off") || !strcmp(action, "remove");
+}
+
+/* match the prompt for either 'W' or 'P' command */
+STATIC_OVL boolean
+putting_on(action)
+const char *action;
+{
+    return !strcmp(action, "wear") || !strcmp(action, "put on");
+}
+
+/*
+ * getobj returns:
+ *     struct obj *xxx:        object to do something with.
+ *     (struct obj *) 0        error return: no object.
+ *     &zeroobj                explicitly no object (as in w-).
+#ifdef GOLDOBJ
+!!!! test if gold can be used in unusual ways (eaten etc.)
+!!!! may be able to remove "usegold"
+#endif
+ */
+struct obj *
+getobj(let,word)
+register const char *let,*word;
+{
+       register struct obj *otmp;
+       register char ilet;
+       char buf[BUFSZ], qbuf[QBUFSZ];
+       char lets[BUFSZ], altlets[BUFSZ], *ap;
+       register int foo = 0;
+       register char *bp = buf;
+       xchar allowcnt = 0;     /* 0, 1 or 2 */
+#ifndef GOLDOBJ
+       boolean allowgold = FALSE;      /* can't use gold because they don't have any */
+#endif
+       boolean usegold = FALSE;        /* can't use gold because its illegal */
+       boolean allowall = FALSE;
+       boolean allownone = FALSE;
+       boolean useboulder = FALSE;
+       xchar foox = 0;
+       long cnt;
+       boolean prezero = FALSE;
+       long dummymask;
+
+       if(*let == ALLOW_COUNT) let++, allowcnt = 1;
+#ifndef GOLDOBJ
+       if(*let == COIN_CLASS) let++,
+               usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE);
+#else
+       if(*let == COIN_CLASS) let++, usegold = TRUE;
+#endif
+
+       /* Equivalent of an "ugly check" for gold */
+       if (usegold && !strcmp(word, "eat") &&
+           (!metallivorous(youmonst.data)
+            || youmonst.data == &mons[PM_RUST_MONSTER]))
+#ifndef GOLDOBJ
+               usegold = allowgold = FALSE;
+#else
+               usegold = FALSE;
+#endif
+
+       if(*let == ALL_CLASSES) let++, allowall = TRUE;
+       if(*let == ALLOW_NONE) let++, allownone = TRUE;
+       /* "ugly check" for reading fortune cookies, part 1 */
+       /* The normal 'ugly check' keeps the object on the inventory list.
+        * We don't want to do that for shirts/cookies, so the check for
+        * them is handled a bit differently (and also requires that we set
+        * allowall in the caller)
+        */
+       if(allowall && !strcmp(word, "read")) allowall = FALSE;
+
+       /* another ugly check: show boulders (not statues) */
+       if(*let == WEAPON_CLASS &&
+          !strcmp(word, "throw") && throws_rocks(youmonst.data))
+           useboulder = TRUE;
+
+       if(allownone) *bp++ = '-';
+#ifndef GOLDOBJ
+       if(allowgold) *bp++ = def_oc_syms[COIN_CLASS];
+#endif
+       if(bp > buf && bp[-1] == '-') *bp++ = ' ';
+       ap = altlets;
+
+       ilet = 'a';
+       for (otmp = invent; otmp; otmp = otmp->nobj) {
+           if (!flags.invlet_constant)
+#ifdef GOLDOBJ
+               if (otmp->invlet != GOLD_SYM) /* don't reassign this */
+#endif
+               otmp->invlet = ilet;    /* reassign() */
+           if (!*let || index(let, otmp->oclass)
+#ifdef GOLDOBJ
+               || (usegold && otmp->invlet == GOLD_SYM)
+#endif
+               || (useboulder && otmp->otyp == BOULDER)
+               ) {
+               register int otyp = otmp->otyp;
+               bp[foo++] = otmp->invlet;
+
+               /* ugly check: remove inappropriate things */
+               if ((taking_off(word) &&
+                   (!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))
+                    || (otmp==uarm && uarmc)
+#ifdef TOURIST
+                    || (otmp==uarmu && (uarm || uarmc))
+#endif
+                   ))
+               || (putting_on(word) &&
+                    (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
+                                                       /* already worn */
+#if 0  /* 3.4.1 -- include currently wielded weapon among the choices */
+               || (!strcmp(word, "wield") &&
+                   (otmp->owornmask & W_WEP))
+#endif
+               || (!strcmp(word, "ready") &&
+                   (otmp == uwep || (otmp == uswapwep && u.twoweap)))
+                   ) {
+                       foo--;
+                       foox++;
+               }
+
+               /* Second ugly check; unlike the first it won't trigger an
+                * "else" in "you don't have anything else to ___".
+                */
+               else if ((putting_on(word) &&
+                   ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) ||
+                   (otmp->oclass == TOOL_CLASS &&
+                    otyp != BLINDFOLD && otyp != TOWEL && otyp != LENSES)))
+               || (!strcmp(word, "wield") &&
+                   (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
+               || (!strcmp(word, "eat") && !is_edible(otmp))
+               || (!strcmp(word, "sacrifice") &&
+                   (otyp != CORPSE &&
+                    otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR))
+               || (!strcmp(word, "write with") &&
+                   (otmp->oclass == TOOL_CLASS &&
+                    otyp != MAGIC_MARKER && otyp != TOWEL))
+               || (!strcmp(word, "tin") &&
+                   (otyp != CORPSE || !tinnable(otmp)))
+               || (!strcmp(word, "rub") &&
+                   ((otmp->oclass == TOOL_CLASS &&
+                     otyp != OIL_LAMP && otyp != MAGIC_LAMP &&
+                     otyp != BRASS_LANTERN) ||
+                    (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
+               || (!strncmp(word, "rub on the stone", 16) &&
+                   *let == GEM_CLASS &&        /* using known touchstone */
+                   otmp->dknown && objects[otyp].oc_name_known)
+               || ((!strcmp(word, "use or apply") ||
+                       !strcmp(word, "untrap with")) &&
+                    /* Picks, axes, pole-weapons, bullwhips */
+                   ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) &&
+                     !is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) ||
+                    (otmp->oclass == POTION_CLASS &&
+                    /* only applicable potion is oil, and it will only
+                       be offered as a choice when already discovered */
+                    (otyp != POT_OIL || !otmp->dknown ||
+                     !objects[POT_OIL].oc_name_known)) ||
+                    (otmp->oclass == FOOD_CLASS &&
+                     otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) ||
+                    (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
+               || (!strcmp(word, "invoke") &&
+                   (!otmp->oartifact && !objects[otyp].oc_unique &&
+                    (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) &&
+                    otyp != CRYSTAL_BALL &&    /* #invoke synonym for apply */
+                  /* note: presenting the possibility of invoking non-artifact
+                     mirrors and/or lamps is a simply a cruel deception... */
+                    otyp != MIRROR && otyp != MAGIC_LAMP &&
+                    (otyp != OIL_LAMP ||       /* don't list known oil lamp */
+                     (otmp->dknown && objects[OIL_LAMP].oc_name_known))))
+               || (!strcmp(word, "untrap with") &&
+                   (otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE))
+               || (!strcmp(word, "charge") && !is_chargeable(otmp))
+                   )
+                       foo--;
+               /* ugly check for unworn armor that can't be worn */
+               else if (putting_on(word) && *let == ARMOR_CLASS &&
+                        !canwearobj(otmp, &dummymask, FALSE)) {
+                       foo--;
+                       allowall = TRUE;
+                       *ap++ = otmp->invlet;
+               }
+           } else {
+
+               /* "ugly check" for reading fortune cookies, part 2 */
+               if ((!strcmp(word, "read") &&
+                   (otmp->otyp == FORTUNE_COOKIE
+#ifdef TOURIST
+                       || otmp->otyp == T_SHIRT
+#endif
+                   )))
+                       allowall = TRUE;
+           }
+
+           if(ilet == 'z') ilet = 'A'; else ilet++;
+       }
+       bp[foo] = 0;
+       if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
+       Strcpy(lets, bp);       /* necessary since we destroy buf */
+       if(foo > 5)                     /* compactify string */
+               compactify(bp);
+       *ap = '\0';
+
+#ifndef GOLDOBJ
+       if(!foo && !allowall && !allowgold && !allownone) {
+#else
+       if(!foo && !allowall && !allownone) {
+#endif
+               You("don't have anything %sto %s.",
+                       foox ? "else " : "", word);
+               return((struct obj *)0);
+       }
+       for(;;) {
+               cnt = 0;
+               if (allowcnt == 2) allowcnt = 1;  /* abort previous count */
+               if(!buf[0]) {
+                       Sprintf(qbuf, "What do you want to %s? [*]", word);
+               } else {
+                       Sprintf(qbuf, "What do you want to %s? [%s or ?*]",
+                               word, buf);
+               }
+#ifdef REDO
+               if (in_doagain)
+                   ilet = readchar();
+               else
+#endif
+                   ilet = yn_function(qbuf, (char *)0, '\0');
+               if(ilet == '0') prezero = TRUE;
+               while(digit(ilet) && allowcnt) {
+#ifdef REDO
+                       if (ilet != '?' && ilet != '*') savech(ilet);
+#endif
+                       cnt = 10*cnt + (ilet - '0');
+                       allowcnt = 2;   /* signal presence of cnt */
+                       ilet = readchar();
+               }
+               if(digit(ilet)) {
+                       pline("No count allowed with this command.");
+                       continue;
+               }
+               if(index(quitchars,ilet)) {
+                   if(flags.verbose)
+                       pline(Never_mind);
+                   return((struct obj *)0);
+               }
+               if(ilet == '-') {
+                       return(allownone ? &zeroobj : (struct obj *) 0);
+               }
+               if(ilet == def_oc_syms[COIN_CLASS]) {
+                       if (!usegold) {
+                           if (!strncmp(word, "rub on ", 7)) {
+                               /* the dangers of building sentences... */
+                               You("cannot rub gold%s.", word + 3);
+                           } else {
+                               You("cannot %s gold.", word);
+                           }
+                           return(struct obj *)0;
+#ifndef GOLDOBJ
+                       } else if (!allowgold) {
+                               You("are not carrying any gold.");
+                               return(struct obj *)0;
+#endif
+                       } 
+                       if(cnt == 0 && prezero) return((struct obj *)0);
+                       /* Historic note: early Nethack had a bug which was
+                        * first reported for Larn, where trying to drop 2^32-n
+                        * gold pieces was allowed, and did interesting things
+                        * to your money supply.  The LRS is the tax bureau
+                        * from Larn.
+                        */
+                       if(cnt < 0) {
+       pline_The("LRS would be very interested to know you have that much.");
+                               return(struct obj *)0;
+                       }
+
+#ifndef GOLDOBJ
+                       if(!(allowcnt == 2 && cnt < u.ugold))
+                               cnt = u.ugold;
+                       return(mkgoldobj(cnt));
+#endif
+               }
+               if(ilet == '?' || ilet == '*') {
+                   char *allowed_choices = (ilet == '?') ? lets : (char *)0;
+                   long ctmp = 0;
+
+                   if (ilet == '?' && !*lets && *altlets)
+                       allowed_choices = altlets;
+                   ilet = display_pickinv(allowed_choices, TRUE,
+                                          allowcnt ? &ctmp : (long *)0);
+                   if(!ilet) continue;
+                   if (allowcnt && ctmp >= 0) {
+                       cnt = ctmp;
+                       if (!cnt) prezero = TRUE;
+                       allowcnt = 2;
+                   }
+                   if(ilet == '\033') {
+                       if(flags.verbose)
+                           pline(Never_mind);
+                       return((struct obj *)0);
+                   }
+                   /* they typed a letter (not a space) at the prompt */
+               }
+               if(allowcnt == 2 && !strcmp(word,"throw")) {
+                   /* permit counts for throwing gold, but don't accept
+                    * counts for other things since the throw code will
+                    * split off a single item anyway */
+#ifdef GOLDOBJ
+                   if (ilet != def_oc_syms[COIN_CLASS])
+#endif
+                       allowcnt = 1;
+                   if(cnt == 0 && prezero) return((struct obj *)0);
+                   if(cnt > 1) {
+                       You("can only throw one item at a time.");
+                       continue;
+                   }
+               }
+#ifdef GOLDOBJ
+               flags.botl = 1; /* May have changed the amount of money */
+#endif
+#ifdef REDO
+               savech(ilet);
+#endif
+               for (otmp = invent; otmp; otmp = otmp->nobj)
+                       if (otmp->invlet == ilet) break;
+               if(!otmp) {
+                       You("don't have that object.");
+#ifdef REDO
+                       if (in_doagain) return((struct obj *) 0);
+#endif
+                       continue;
+               } else if (cnt < 0 || otmp->quan < cnt) {
+                       You("don't have that many!  You have only %ld.",
+                           otmp->quan);
+#ifdef REDO
+                       if (in_doagain) return((struct obj *) 0);
+#endif
+                       continue;
+               }
+               break;
+       }
+       if(!allowall && let && !index(let,otmp->oclass)
+#ifdef GOLDOBJ
+          && !(usegold && otmp->oclass == COIN_CLASS)
+#endif
+          ) {
+               silly_thing(word, otmp);
+               return((struct obj *)0);
+       }
+       if(allowcnt == 2) {     /* cnt given */
+           if(cnt == 0) return (struct obj *)0;
+           if(cnt != otmp->quan) {
+               /* don't split a stack of cursed loadstones */
+               if (otmp->otyp == LOADSTONE && otmp->cursed)
+                   /* kludge for canletgo()'s can't-drop-this message */
+                   otmp->corpsenm = (int) cnt;
+               else
+                   otmp = splitobj(otmp, cnt);
+           }
+       }
+       return(otmp);
+}
+
+void
+silly_thing(word, otmp)
+const char *word;
+struct obj *otmp;
+{
+       const char *s1, *s2, *s3, *what;
+       int ocls = otmp->oclass, otyp = otmp->otyp;
+
+       s1 = s2 = s3 = 0;
+       /* check for attempted use of accessory commands ('P','R') on armor
+          and for corresponding armor commands ('W','T') on accessories */
+       if (ocls == ARMOR_CLASS) {
+           if (!strcmp(word, "put on"))
+               s1 = "W", s2 = "wear", s3 = "";
+           else if (!strcmp(word, "remove"))
+               s1 = "T", s2 = "take", s3 = " off";
+       } else if ((ocls == RING_CLASS || otyp == MEAT_RING) ||
+               ocls == AMULET_CLASS ||
+               (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) {
+           if (!strcmp(word, "wear"))
+               s1 = "P", s2 = "put", s3 = " on";
+           else if (!strcmp(word, "take off"))
+               s1 = "R", s2 = "remove", s3 = "";
+       }
+       if (s1) {
+           what = "that";
+           /* quantity for armor and accessory objects is always 1,
+              but some things should be referred to as plural */
+           if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp))
+               what = "those";
+           pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3);
+       } else {
+           pline(silly_thing_to, word);
+       }
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+STATIC_PTR int
+ckvalidcat(otmp)
+register struct obj *otmp;
+{
+       /* use allow_category() from pickup.c */
+       return((int)allow_category(otmp));
+}
+
+STATIC_PTR int
+ckunpaid(otmp)
+register struct obj *otmp;
+{
+       return((int)(otmp->unpaid));
+}
+
+boolean
+wearing_armor()
+{
+       return((boolean)(uarm || uarmc || uarmf || uarmg || uarmh || uarms
+#ifdef TOURIST
+               || uarmu
+#endif
+               ));
+}
+
+boolean
+is_worn(otmp)
+register struct obj *otmp;
+{
+    return((boolean)(!!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL |
+#ifdef STEED
+                       W_SADDLE |
+#endif
+                       W_WEP | W_SWAPWEP | W_QUIVER))));
+}
+
+static NEARDATA const char removeables[] =
+       { ARMOR_CLASS, WEAPON_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, 0 };
+
+/* interactive version of getobj - used for Drop, Identify and */
+/* Takeoff (A). Return the number of times fn was called successfully */
+/* If combo is TRUE, we just use this to get a category list */
+int
+ggetobj(word, fn, mx, combo, resultflags)
+const char *word;
+int FDECL((*fn),(OBJ_P)), mx;
+boolean combo;         /* combination menu flag */
+unsigned *resultflags;
+{
+       int FDECL((*ckfn),(OBJ_P)) = (int FDECL((*),(OBJ_P))) 0;
+       boolean FDECL((*filter),(OBJ_P)) = (boolean FDECL((*),(OBJ_P))) 0;
+       boolean takeoff, ident, allflag, m_seen;
+       int itemcount;
+#ifndef GOLDOBJ
+       int oletct, iletct, allowgold, unpaid, oc_of_sym;
+#else
+       int oletct, iletct, unpaid, oc_of_sym;
+#endif
+       char sym, *ip, olets[MAXOCLASSES+5], ilets[MAXOCLASSES+5];
+       char extra_removeables[3+1];    /* uwep,uswapwep,uquiver */
+       char buf[BUFSZ], qbuf[QBUFSZ];
+
+       if (resultflags) *resultflags = 0;
+#ifndef GOLDOBJ
+       allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0;
+#endif
+       takeoff = ident = allflag = m_seen = FALSE;
+#ifndef GOLDOBJ
+       if(!invent && !allowgold){
+#else
+       if(!invent){
+#endif
+               You("have nothing to %s.", word);
+               return(0);
+       }
+       add_valid_menu_class(0);        /* reset */
+       if (taking_off(word)) {
+           takeoff = TRUE;
+           filter = is_worn;
+       } else if (!strcmp(word, "identify")) {
+           ident = TRUE;
+           filter = not_fully_identified;
+       }
+
+       iletct = collect_obj_classes(ilets, invent,
+                                       FALSE,
+#ifndef GOLDOBJ
+                                       (allowgold != 0),
+#endif
+                                       filter, &itemcount);
+       unpaid = count_unpaid(invent);
+
+       if (ident && !iletct) {
+           return -1;          /* no further identifications */
+       } else if (!takeoff && (unpaid || invent)) {
+           ilets[iletct++] = ' ';
+           if (unpaid) ilets[iletct++] = 'u';
+           if (count_buc(invent, BUC_BLESSED))  ilets[iletct++] = 'B';
+           if (count_buc(invent, BUC_UNCURSED)) ilets[iletct++] = 'U';
+           if (count_buc(invent, BUC_CURSED))   ilets[iletct++] = 'C';
+           if (count_buc(invent, BUC_UNKNOWN))  ilets[iletct++] = 'X';
+           if (invent) ilets[iletct++] = 'a';
+       } else if (takeoff && invent) {
+           ilets[iletct++] = ' ';
+       }
+       ilets[iletct++] = 'i';
+       if (!combo)
+           ilets[iletct++] = 'm';      /* allow menu presentation on request */
+       ilets[iletct] = '\0';
+
+       for (;;) {
+           Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
+                   word, ilets);
+           getlin(qbuf, buf);
+           if (buf[0] == '\033') return(0);
+           if (index(buf, 'i')) {
+               if (display_inventory((char *)0, TRUE) == '\033') return 0;
+           } else
+               break;
+       }
+
+       extra_removeables[0] = '\0';
+       if (takeoff) {
+           /* arbitrary types of items can be placed in the weapon slots
+              [any duplicate entries in extra_removeables[] won't matter] */
+           if (uwep) (void)strkitten(extra_removeables, uwep->oclass);
+           if (uswapwep) (void)strkitten(extra_removeables, uswapwep->oclass);
+           if (uquiver) (void)strkitten(extra_removeables, uquiver->oclass);
+       }
+
+       ip = buf;
+       olets[oletct = 0] = '\0';
+       while ((sym = *ip++) != '\0') {
+           if (sym == ' ') continue;
+           oc_of_sym = def_char_to_objclass(sym);
+           if (takeoff && oc_of_sym != MAXOCLASSES) {
+               if (index(extra_removeables, oc_of_sym)) {
+                   ;   /* skip rest of takeoff checks */
+               } else if (!index(removeables, oc_of_sym)) {
+                   pline("Not applicable.");
+                   return 0;
+               } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
+                   You("are not wearing any armor.");
+                   return 0;
+               } else if (oc_of_sym == WEAPON_CLASS &&
+                       !uwep && !uswapwep && !uquiver) {
+                   You("are not wielding anything.");
+                   return 0;
+               } else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
+                   You("are not wearing rings.");
+                   return 0;
+               } else if (oc_of_sym == AMULET_CLASS && !uamul) {
+                   You("are not wearing an amulet.");
+                   return 0;
+               } else if (oc_of_sym == TOOL_CLASS && !ublindf) {
+                   You("are not wearing a blindfold.");
+                   return 0;
+               }
+           }
+
+           if (oc_of_sym == COIN_CLASS && !combo) {
+#ifndef GOLDOBJ
+               if (allowgold == 1)
+                   (*fn)(mkgoldobj(u.ugold));
+               else if (!u.ugold)
+                   You("have no gold.");
+               allowgold = 2;
+#else
+               flags.botl = 1;
+#endif
+           } else if (sym == 'a') {
+               allflag = TRUE;
+           } else if (sym == 'A') {
+               /* same as the default */ ;
+           } else if (sym == 'u') {
+               add_valid_menu_class('u');
+               ckfn = ckunpaid;
+           } else if (sym == 'B') {
+               add_valid_menu_class('B');
+               ckfn = ckvalidcat;
+           } else if (sym == 'U') {
+               add_valid_menu_class('U');
+               ckfn = ckvalidcat;
+           } else if (sym == 'C') {
+               add_valid_menu_class('C');
+               ckfn = ckvalidcat;
+           } else if (sym == 'X') {
+               add_valid_menu_class('X');
+               ckfn = ckvalidcat;
+           } else if (sym == 'm') {
+               m_seen = TRUE;
+           } else if (oc_of_sym == MAXOCLASSES) {
+               You("don't have any %c's.", sym);
+           } else if (oc_of_sym != VENOM_CLASS) {      /* suppress venom */
+               if (!index(olets, oc_of_sym)) {
+                   add_valid_menu_class(oc_of_sym);
+                   olets[oletct++] = oc_of_sym;
+                   olets[oletct] = 0;
+               }
+           }
+       }
+
+       if (m_seen)
+           return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3;
+       else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag)
+           return 0;
+#ifndef GOLDOBJ
+       else if (allowgold == 2 && !oletct)
+           return 1;   /* you dropped gold (or at least tried to) */
+       else {
+#else
+       else /*!!!! if (allowgold == 2 && !oletct)
+           !!!! return 1;       you dropped gold (or at least tried to) 
+            !!!! test gold dropping
+       else*/ {
+#endif
+           int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word); 
+           /*
+            * askchain() has already finished the job in this case
+            * so set a special flag to convey that back to the caller
+            * so that it won't continue processing.
+            * Fix for bug C331-1 reported by Irina Rempt-Drijfhout. 
+            */
+           if (combo && allflag && resultflags)
+               *resultflags |= ALL_FINISHED; 
+           return cnt;
+       }
+}
+
+/*
+ * Walk through the chain starting at objchn and ask for all objects
+ * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
+ * whether the action in question (i.e., fn) has to be performed.
+ * If allflag then no questions are asked. Max gives the max nr of
+ * objects to be treated. Return the number of objects treated.
+ */
+int
+askchain(objchn, olets, allflag, fn, ckfn, mx, word)
+struct obj **objchn;
+register int allflag, mx;
+register const char *olets, *word;     /* olets is an Obj Class char array */
+register int FDECL((*fn),(OBJ_P)), FDECL((*ckfn),(OBJ_P));
+{
+       struct obj *otmp, *otmp2, *otmpo;
+       register char sym, ilet;
+       register int cnt = 0, dud = 0, tmp;
+       boolean takeoff, nodot, ident, ininv;
+       char qbuf[QBUFSZ];
+
+       takeoff = taking_off(word);
+       ident = !strcmp(word, "identify");
+       nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") ||
+                ident || takeoff);
+       ininv = (*objchn == invent);
+       /* Changed so the askchain is interrogated in the order specified.
+        * For example, if a person specifies =/ then first all rings will be
+        * asked about followed by all wands -dgk
+        */
+nextclass:
+       ilet = 'a'-1;
+       if (*objchn && (*objchn)->oclass == COIN_CLASS)
+               ilet--;         /* extra iteration */
+       for (otmp = *objchn; otmp; otmp = otmp2) {
+               if(ilet == 'z') ilet = 'A'; else ilet++;
+               otmp2 = otmp->nobj;
+               if (olets && *olets && otmp->oclass != *olets) continue;
+               if (takeoff && !is_worn(otmp)) continue;
+               if (ident && !not_fully_identified(otmp)) continue;
+               if (ckfn && !(*ckfn)(otmp)) continue;
+               if (!allflag) {
+                       Strcpy(qbuf, !ininv ? doname(otmp) :
+                               xprname(otmp, (char *)0, ilet, !nodot, 0L, 0L));
+                       Strcat(qbuf, "?");
+                       sym = (takeoff || ident || otmp->quan < 2L) ?
+                               nyaq(qbuf) : nyNaq(qbuf);
+               }
+               else    sym = 'y';
+
+               otmpo = otmp;
+               if (sym == '#') {
+                /* Number was entered; split the object unless it corresponds
+                   to 'none' or 'all'.  2 special cases: cursed loadstones and
+                   welded weapons (eg, multiple daggers) will remain as merged
+                   unit; done to avoid splitting an object that won't be
+                   droppable (even if we're picking up rather than dropping).
+                 */
+                   if (!yn_number)
+                       sym = 'n';
+                   else {
+                       sym = 'y';
+                       if (yn_number < otmp->quan && !welded(otmp) &&
+                           (!otmp->cursed || otmp->otyp != LOADSTONE)) {
+                           otmp = splitobj(otmp, yn_number);
+                       }
+                   }
+               }
+               switch(sym){
+               case 'a':
+                       allflag = 1;
+               case 'y':
+                       tmp = (*fn)(otmp);
+                       if(tmp < 0) {
+                           if (otmp != otmpo) {
+                               /* split occurred, merge again */
+                               (void) merged(&otmpo, &otmp);
+                           }
+                           goto ret;
+                       }
+                       cnt += tmp;
+                       if(--mx == 0) goto ret;
+               case 'n':
+                       if(nodot) dud++;
+               default:
+                       break;
+               case 'q':
+                       /* special case for seffects() */
+                       if (ident) cnt = -1;
+                       goto ret;
+               }
+       }
+       if (olets && *olets && *++olets)
+               goto nextclass;
+       if(!takeoff && (dud || cnt)) pline("That was all.");
+       else if(!dud && !cnt) pline("No applicable objects.");
+ret:
+       return(cnt);
+}
+
+
+/*
+ *     Object identification routines:
+ */
+
+/* make an object actually be identified; no display updating */
+void
+fully_identify_obj(otmp)
+struct obj *otmp;
+{
+    makeknown(otmp->otyp);
+    if (otmp->oartifact) discover_artifact((xchar)otmp->oartifact);
+    otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
+    if (otmp->otyp == EGG && otmp->corpsenm != NON_PM)
+       learn_egg_type(otmp->corpsenm);
+}
+
+/* ggetobj callback routine; identify an object and give immediate feedback */
+int
+identify(otmp)
+struct obj *otmp;
+{
+    fully_identify_obj(otmp);
+    prinv((char *)0, otmp, 0L);
+    return 1;
+}
+
+/* menu of unidentified objects; select and identify up to id_limit of them */
+STATIC_OVL void
+menu_identify(id_limit)
+int id_limit;
+{
+    menu_item *pick_list;
+    int n, i, first = 1;
+    char buf[BUFSZ];
+    /* assumptions:  id_limit > 0 and at least one unID'd item is present */
+
+    while (id_limit) {
+       Sprintf(buf, "What would you like to identify %s?",
+               first ? "first" : "next");
+       n = query_objlist(buf, invent, SIGNAL_NOMENU|USE_INVLET|INVORDER_SORT,
+               &pick_list, PICK_ANY, not_fully_identified);
+
+       if (n > 0) {
+           if (n > id_limit) n = id_limit;
+           for (i = 0; i < n; i++, id_limit--)
+               (void) identify(pick_list[i].item.a_obj);
+           free((genericptr_t) pick_list);
+           mark_synch(); /* Before we loop to pop open another menu */
+       } else {
+           if (n < 0) pline("That was all.");
+           id_limit = 0; /* Stop now */
+       }
+       first = 0;
+    }
+}
+
+/* dialog with user to identify a given number of items; 0 means all */
+void
+identify_pack(id_limit)
+int id_limit;
+{
+    struct obj *obj, *the_obj;
+    int n, unid_cnt;
+
+    unid_cnt = 0;
+    the_obj = 0;               /* if unid_cnt ends up 1, this will be it */
+    for (obj = invent; obj; obj = obj->nobj)
+       if (not_fully_identified(obj)) ++unid_cnt, the_obj = obj;
+
+    if (!unid_cnt) {
+       You("have already identified all of your possessions.");
+    } else if (!id_limit) {
+       /* identify everything */
+       if (unid_cnt == 1) {
+           (void) identify(the_obj);
+       } else {
+
+           /* TODO:  use fully_identify_obj and cornline/menu/whatever here */
+           for (obj = invent; obj; obj = obj->nobj)
+               if (not_fully_identified(obj)) (void) identify(obj);
+
+       }
+    } else {
+       /* identify up to `id_limit' items */
+       n = 0;
+       if (flags.menu_style == MENU_TRADITIONAL)
+           do {
+               n = ggetobj("identify", identify, id_limit, FALSE, (unsigned *)0);
+               if (n < 0) break; /* quit or no eligible items */
+           } while ((id_limit -= n) > 0);
+       if (n == 0 || n < -1)
+           menu_identify(id_limit);
+    }
+    update_inventory();
+}
+
+#endif /* OVLB */
+#ifdef OVL2
+
+STATIC_OVL char
+obj_to_let(obj)        /* should of course only be called for things in invent */
+register struct obj *obj;
+{
+#ifndef GOLDOBJ
+       if (obj->oclass == COIN_CLASS)
+               return GOLD_SYM;
+#endif
+       if (!flags.invlet_constant) {
+               obj->invlet = NOINVSYM;
+               reassign();
+       }
+       return obj->invlet;
+}
+
+/*
+ * Print the indicated quantity of the given object.  If quan == 0L then use
+ * the current quantity.
+ */
+void
+prinv(prefix, obj, quan)
+const char *prefix;
+register struct obj *obj;
+long quan;
+{
+       if (!prefix) prefix = "";
+       pline("%s%s%s",
+             prefix, *prefix ? " " : "",
+             xprname(obj, (char *)0, obj_to_let(obj), TRUE, 0L, quan));
+}
+
+#endif /* OVL2 */
+#ifdef OVL1
+
+char *
+xprname(obj, txt, let, dot, cost, quan)
+struct obj *obj;
+const char *txt;       /* text to print instead of obj */
+char let;              /* inventory letter */
+boolean dot;           /* append period; (dot && cost => Iu) */
+long cost;             /* cost (for inventory of unpaid or expended items) */
+long quan;             /* if non-0, print this quantity, not obj->quan */
+{
+#ifdef LINT    /* handle static char li[BUFSZ]; */
+    char li[BUFSZ];
+#else
+    static char li[BUFSZ];
+#endif
+    boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
+    long savequan = 0;
+
+    if (quan && obj) {
+       savequan = obj->quan;
+       obj->quan = quan;
+    }
+
+    /*
+     * If let is:
+     * *  Then obj == null and we are printing a total amount.
+     * >  Then the object is contained and doesn't have an inventory letter.
+     */
+    if (cost != 0 || let == '*') {
+       /* if dot is true, we're doing Iu, otherwise Ix */
+       Sprintf(li, "%c - %-45s %6ld %s",
+               (dot && use_invlet ? obj->invlet : let),
+               (txt ? txt : doname(obj)), cost, currency(cost));
+#ifndef GOLDOBJ
+    } else if (obj && obj->oclass == COIN_CLASS) {
+       Sprintf(li, "%ld gold piece%s%s", obj->quan, plur(obj->quan),
+               (dot ? "." : ""));
+#endif
+    } else {
+       /* ordinary inventory display or pickup message */
+       Sprintf(li, "%c - %s%s",
+               (use_invlet ? obj->invlet : let),
+               (txt ? txt : doname(obj)), (dot ? "." : ""));
+    }
+    if (savequan) obj->quan = savequan;
+
+    return li;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+/* the 'i' command */
+int
+ddoinv()
+{
+       (void) display_inventory((char *)0, FALSE);
+       return 0;
+}
+
+/*
+ * find_unpaid()
+ *
+ * Scan the given list of objects.  If last_found is NULL, return the first
+ * unpaid object found.  If last_found is not NULL, then skip over unpaid
+ * objects until last_found is reached, then set last_found to NULL so the
+ * next unpaid object is returned.  This routine recursively follows
+ * containers.
+ */
+STATIC_OVL struct obj *
+find_unpaid(list, last_found)
+    struct obj *list, **last_found;
+{
+    struct obj *obj;
+
+    while (list) {
+       if (list->unpaid) {
+           if (*last_found) {
+               /* still looking for previous unpaid object */
+               if (list == *last_found)
+                   *last_found = (struct obj *) 0;
+           } else
+               return (*last_found = list);
+       }
+       if (Has_contents(list)) {
+           if ((obj = find_unpaid(list->cobj, last_found)) != 0)
+               return obj;
+       }
+       list = list->nobj;
+    }
+    return (struct obj *) 0;
+}
+
+/*
+ * Internal function used by display_inventory and getobj that can display
+ * inventory and return a count as well as a letter. If out_cnt is not null,
+ * any count returned from the menu selection is placed here.
+ */
+static char
+display_pickinv(lets, want_reply, out_cnt)
+register const char *lets;
+boolean want_reply;
+long* out_cnt;
+{
+       struct obj *otmp;
+       char ilet, ret;
+       char *invlet = flags.inv_order;
+       int n, classcount;
+       winid win;                              /* windows being used */
+       static winid local_win = WIN_ERR;       /* window for partial menus */
+       anything any;
+       menu_item *selected;
+
+       /* overriden by global flag */
+       if (flags.perm_invent) {
+           win = (lets && *lets) ? local_win : WIN_INVEN;
+           /* create the first time used */
+           if (win == WIN_ERR)
+               win = local_win = create_nhwindow(NHW_MENU);
+       } else
+           win = WIN_INVEN;
+
+       /*
+       Exit early if no inventory -- but keep going if we are doing
+       a permanent inventory update.  We need to keep going so the
+       permanent inventory window updates itself to remove the last
+       item(s) dropped.  One down side:  the addition of the exception
+       for permanent inventory window updates _can_ pop the window
+       up when it's not displayed -- even if it's empty -- because we
+       don't know at this level if its up or not.  This may not be
+       an issue if empty checks are done before hand and the call
+       to here is short circuited away.
+       */
+       if (!invent && !(flags.perm_invent && !lets && !want_reply)) {
+#ifndef GOLDOBJ
+           pline("Not carrying anything%s.", u.ugold ? " except gold" : "");
+#else
+           pline("Not carrying anything.");
+#endif
+           return 0;
+       }
+
+       /* oxymoron? temporarily assign permanent inventory letters */
+       if (!flags.invlet_constant) reassign();
+
+       if (lets && strlen(lets) == 1) {
+           /* when only one item of interest, use pline instead of menus;
+              we actually use a fake message-line menu in order to allow
+              the user to perform selection at the --More-- prompt for tty */
+           ret = '\0';
+           for (otmp = invent; otmp; otmp = otmp->nobj) {
+               if (otmp->invlet == lets[0]) {
+                   ret = message_menu(lets[0],
+                         want_reply ? PICK_ONE : PICK_NONE,
+                         xprname(otmp, (char *)0, lets[0], TRUE, 0L, 0L));
+                   if (out_cnt) *out_cnt = -1L;        /* select all */
+                   break;
+               }
+           }
+           return ret;
+       }
+
+       start_menu(win);
+nextclass:
+       classcount = 0;
+       any.a_void = 0;         /* set all bits to zero */
+       for(otmp = invent; otmp; otmp = otmp->nobj) {
+               ilet = otmp->invlet;
+               if(!lets || !*lets || index(lets, ilet)) {
+                       if (!flags.sortpack || otmp->oclass == *invlet) {
+                           if (flags.sortpack && !classcount) {
+                               any.a_void = 0;         /* zero */
+                               add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
+                                   let_to_name(*invlet, FALSE), MENU_UNSELECTED);
+                               classcount++;
+                           }
+                           any.a_char = ilet;
+                           add_menu(win, obj_to_glyph(otmp),
+                                       &any, ilet, 0, ATR_NONE, doname(otmp),
+                                       MENU_UNSELECTED);
+                       }
+               }
+       }
+       if (flags.sortpack) {
+               if (*++invlet) goto nextclass;
+#ifdef WIZARD
+               if (--invlet != venom_inv) {
+                       invlet = venom_inv;
+                       goto nextclass;
+               }
+#endif
+       }
+       end_menu(win, (char *) 0);
+
+       n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
+       if (n > 0) {
+           ret = selected[0].item.a_char;
+           if (out_cnt) *out_cnt = selected[0].count;
+           free((genericptr_t)selected);
+       } else
+           ret = !n ? '\0' : '\033';   /* cancelled */
+
+       return ret;
+}
+
+/*
+ * If lets == NULL or "", list all objects in the inventory.  Otherwise,
+ * list all objects with object classes that match the order in lets.
+ *
+ * Returns the letter identifier of a selected item, or 0 if nothing
+ * was selected.
+ */
+char
+display_inventory(lets, want_reply)
+register const char *lets;
+boolean want_reply;
+{
+       return display_pickinv(lets, want_reply, (long *)0);
+}
+
+/*
+ * Returns the number of unpaid items within the given list.  This includes
+ * contained objects.
+ */
+int
+count_unpaid(list)
+    struct obj *list;
+{
+    int count = 0;
+
+    while (list) {
+       if (list->unpaid) count++;
+       if (Has_contents(list))
+           count += count_unpaid(list->cobj);
+       list = list->nobj;
+    }
+    return count;
+}
+
+/*
+ * Returns the number of items with b/u/c/unknown within the given list.  
+ * This does NOT include contained objects.
+ */
+int
+count_buc(list, type)
+    struct obj *list;
+    int type;
+{
+    int count = 0;
+
+    while (list) {
+       if (Role_if(PM_PRIEST)) list->bknown = TRUE;
+       switch(type) {
+           case BUC_BLESSED:
+               if (list->oclass != COIN_CLASS && list->bknown && list->blessed)
+                   count++;
+               break;
+           case BUC_CURSED:
+               if (list->oclass != COIN_CLASS && list->bknown && list->cursed)
+                   count++;
+               break;
+           case BUC_UNCURSED:
+               if (list->oclass != COIN_CLASS &&
+                       list->bknown && !list->blessed && !list->cursed)
+                   count++;
+               break;
+           case BUC_UNKNOWN:
+               if (list->oclass != COIN_CLASS && !list->bknown)
+                   count++;
+               break;
+           default:
+               impossible("need count of curse status %d?", type);
+               return 0;
+       }
+       list = list->nobj;
+    }
+    return count;
+}
+
+STATIC_OVL void
+dounpaid()
+{
+    winid win;
+    struct obj *otmp, *marker;
+    register char ilet;
+    char *invlet = flags.inv_order;
+    int classcount, count, num_so_far;
+    int save_unpaid = 0;       /* lint init */
+    long cost, totcost;
+
+    count = count_unpaid(invent);
+
+    if (count == 1) {
+       marker = (struct obj *) 0;
+       otmp = find_unpaid(invent, &marker);
+
+       /* see if the unpaid item is in the top level inventory */
+       for (marker = invent; marker; marker = marker->nobj)
+           if (marker == otmp) break;
+
+       pline("%s", xprname(otmp, distant_name(otmp, doname),
+                           marker ? otmp->invlet : CONTAINED_SYM,
+                           TRUE, unpaid_cost(otmp), 0L));
+       return;
+    }
+
+    win = create_nhwindow(NHW_MENU);
+    cost = totcost = 0;
+    num_so_far = 0;    /* count of # printed so far */
+    if (!flags.invlet_constant) reassign();
+
+    do {
+       classcount = 0;
+       for (otmp = invent; otmp; otmp = otmp->nobj) {
+           ilet = otmp->invlet;
+           if (otmp->unpaid) {
+               if (!flags.sortpack || otmp->oclass == *invlet) {
+                   if (flags.sortpack && !classcount) {
+                       putstr(win, 0, let_to_name(*invlet, TRUE));
+                       classcount++;
+                   }
+
+                   totcost += cost = unpaid_cost(otmp);
+                   /* suppress "(unpaid)" suffix */
+                   save_unpaid = otmp->unpaid;
+                   otmp->unpaid = 0;
+                   putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
+                                          ilet, TRUE, cost, 0L));
+                   otmp->unpaid = save_unpaid;
+                   num_so_far++;
+               }
+           }
+       }
+    } while (flags.sortpack && (*++invlet));
+
+    if (count > num_so_far) {
+       /* something unpaid is contained */
+       if (flags.sortpack)
+           putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE));
+       /*
+        * Search through the container objects in the inventory for
+        * unpaid items.  The top level inventory items have already
+        * been listed.
+        */
+       for (otmp = invent; otmp; otmp = otmp->nobj) {
+           if (Has_contents(otmp)) {
+               marker = (struct obj *) 0;      /* haven't found any */
+               while (find_unpaid(otmp->cobj, &marker)) {
+                   totcost += cost = unpaid_cost(marker);
+                   save_unpaid = marker->unpaid;
+                   marker->unpaid = 0;    /* suppress "(unpaid)" suffix */
+                   putstr(win, 0,
+                          xprname(marker, distant_name(marker, doname),
+                                  CONTAINED_SYM, TRUE, cost, 0L));
+                   marker->unpaid = save_unpaid;
+               }
+           }
+       }
+    }
+
+    putstr(win, 0, "");
+    putstr(win, 0, xprname((struct obj *)0, "Total:", '*', FALSE, totcost, 0L));
+    display_nhwindow(win, FALSE);
+    destroy_nhwindow(win);
+}
+
+
+/* query objlist callback: return TRUE if obj type matches "this_type" */
+static int this_type;
+
+STATIC_OVL boolean
+this_type_only(obj)
+    struct obj *obj;
+{
+    return (obj->oclass == this_type);
+}
+
+/* the 'I' command */
+int
+dotypeinv()
+{
+       char c = '\0';
+       int n, i = 0;
+       char *extra_types, types[BUFSZ];
+       int class_count, oclass, unpaid_count, itemcount;
+       boolean billx = *u.ushops && doinvbill(0);
+       menu_item *pick_list;
+       boolean traditional = TRUE;
+       const char *prompt = "What type of object do you want an inventory of?";
+
+#ifndef GOLDOBJ
+       if (!invent && !u.ugold && !billx) {
+#else
+       if (!invent && !billx) {
+#endif
+           You("aren't carrying anything.");
+           return 0;
+       }
+       unpaid_count = count_unpaid(invent);
+       if (flags.menu_style != MENU_TRADITIONAL) {
+           if (flags.menu_style == MENU_FULL ||
+                               flags.menu_style == MENU_PARTIAL) {
+               traditional = FALSE;
+               i = UNPAID_TYPES;
+               if (billx) i |= BILLED_TYPES;
+               n = query_category(prompt, invent, i, &pick_list, PICK_ONE);
+               if (!n) return 0;
+               this_type = c = pick_list[0].item.a_int;
+               free((genericptr_t) pick_list);
+           }
+       }
+       if (traditional) {
+           /* collect a list of classes of objects carried, for use as a prompt */
+           types[0] = 0;
+           class_count = collect_obj_classes(types, invent,
+                                             FALSE,
+#ifndef GOLDOBJ
+                                             (u.ugold != 0),
+#endif
+                                             (boolean FDECL((*),(OBJ_P))) 0, &itemcount);
+           if (unpaid_count) {
+               Strcat(types, "u");
+               class_count++;
+           }
+           if (billx) {
+               Strcat(types, "x");
+               class_count++;
+           }
+           /* add everything not already included; user won't see these */
+           extra_types = eos(types);
+           *extra_types++ = '\033';
+           if (!unpaid_count) *extra_types++ = 'u';
+           if (!billx) *extra_types++ = 'x';
+           *extra_types = '\0';        /* for index() */
+           for (i = 0; i < MAXOCLASSES; i++)
+               if (!index(types, def_oc_syms[i])) {
+                   *extra_types++ = def_oc_syms[i];
+                   *extra_types = '\0';
+               }
+
+           if(class_count > 1) {
+               c = yn_function(prompt, types, '\0');
+#ifdef REDO
+               savech(c);
+#endif
+               if(c == '\0') {
+                       clear_nhwindow(WIN_MESSAGE);
+                       return 0;
+               }
+           } else {
+               /* only one thing to itemize */
+               if (unpaid_count)
+                   c = 'u';
+               else if (billx)
+                   c = 'x';
+               else
+                   c = types[0];
+           }
+       }
+       if (c == 'x') {
+           if (billx)
+               (void) doinvbill(1);
+           else
+               pline("No used-up objects on your shopping bill.");
+           return 0;
+       }
+       if (c == 'u') {
+           if (unpaid_count)
+               dounpaid();
+           else
+               You("are not carrying any unpaid objects.");
+           return 0;
+       }
+       if (traditional) {
+           oclass = def_char_to_objclass(c); /* change to object class */
+           if (oclass == COIN_CLASS) {
+               return doprgold();
+           } else if (index(types, c) > index(types, '\033')) {
+               You("have no such objects.");
+               return 0;
+           }
+           this_type = oclass;
+       }
+       if (query_objlist((char *) 0, invent,
+                   (flags.invlet_constant ? USE_INVLET : 0)|INVORDER_SORT,
+                   &pick_list, PICK_NONE, this_type_only) > 0)
+           free((genericptr_t)pick_list);
+       return 0;
+}
+
+/* return a string describing the dungeon feature at <x,y> if there
+   is one worth mentioning at that location; otherwise null */
+const char *
+dfeature_at(x, y, buf)
+int x, y;
+char *buf;
+{
+       struct rm *lev = &levl[x][y];
+       int ltyp = lev->typ, cmap = -1;
+       const char *dfeature = 0;
+       static char altbuf[BUFSZ];
+
+       if (IS_DOOR(ltyp)) {
+           switch (lev->doormask) {
+           case D_NODOOR:      cmap = S_ndoor; break;  /* "doorway" */
+           case D_ISOPEN:      cmap = S_vodoor; break; /* "open door" */
+           case D_BROKEN:      dfeature = "broken door"; break;
+           default:    cmap = S_vcdoor; break; /* "closed door" */
+           }
+           /* override door description for open drawbridge */
+           if (is_drawbridge_wall(x, y) >= 0)
+               dfeature = "open drawbridge portcullis",  cmap = -1;
+       } else if (IS_FOUNTAIN(ltyp))
+           cmap = S_fountain;                          /* "fountain" */
+       else if (IS_THRONE(ltyp))
+           cmap = S_throne;                            /* "opulent throne" */
+       else if (is_lava(x,y))
+           cmap = S_lava;                              /* "molten lava" */
+       else if (is_ice(x,y))
+           cmap = S_ice;                               /* "ice" */
+       else if (is_pool(x,y))
+           dfeature = "pool of water";
+#ifdef SINKS
+       else if (IS_SINK(ltyp))
+           cmap = S_sink;                              /* "sink" */
+#endif
+       else if (IS_ALTAR(ltyp)) {
+           Sprintf(altbuf, "altar to %s (%s)", a_gname(),
+                   align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
+           dfeature = altbuf;
+       } else if ((x == xupstair && y == yupstair) ||
+                (x == sstairs.sx && y == sstairs.sy && sstairs.up))
+           cmap = S_upstair;                           /* "staircase up" */
+       else if ((x == xdnstair && y == ydnstair) ||
+                (x == sstairs.sx && y == sstairs.sy && !sstairs.up))
+           cmap = S_dnstair;                           /* "staircase down" */
+       else if (x == xupladder && y == yupladder)
+           cmap = S_upladder;                          /* "ladder up" */
+       else if (x == xdnladder && y == ydnladder)
+           cmap = S_dnladder;                          /* "ladder down" */
+       else if (ltyp == DRAWBRIDGE_DOWN)
+           cmap = S_vodbridge;                 /* "lowered drawbridge" */
+       else if (ltyp == DBWALL)
+           cmap = S_vcdbridge;                 /* "raised drawbridge" */
+       else if (IS_GRAVE(ltyp))
+           cmap = S_grave;                             /* "grave" */
+       else if (ltyp == TREE)
+           cmap = S_tree;                              /* "tree" */
+       else if (ltyp == IRONBARS)
+           dfeature = "set of iron bars";
+
+       if (cmap >= 0) dfeature = defsyms[cmap].explanation;
+       if (dfeature) Strcpy(buf, dfeature);
+       return dfeature;
+}
+
+/* look at what is here; if there are many objects (5 or more),
+   don't show them unless obj_cnt is 0 */
+int
+look_here(obj_cnt, picked_some)
+int obj_cnt;   /* obj_cnt > 0 implies that autopickup is in progess */
+boolean picked_some;
+{
+       struct obj *otmp;
+       struct trap *trap;
+       const char *verb = Blind ? "feel" : "see";
+       const char *dfeature = (char *)0;
+       char fbuf[BUFSZ], fbuf2[BUFSZ];
+       winid tmpwin;
+       boolean skip_objects = (obj_cnt >= 5), felt_cockatrice = FALSE;
+
+       if (u.uswallow && u.ustuck) {
+           struct monst *mtmp = u.ustuck;
+           Sprintf(fbuf, "Contents of %s %s",
+               s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH));
+           /* Skip "Contents of " by using fbuf index 12 */
+           You("%s to %s what is lying in %s.",
+               Blind ? "try" : "look around", verb, &fbuf[12]);
+           otmp = mtmp->minvent;
+           if (otmp) {
+               for ( ; otmp; otmp = otmp->nobj) {
+                       /* If swallower is an animal, it should have become stone but... */
+                       if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE);
+               }
+               if (Blind) Strcpy(fbuf, "You feel");
+               Strcat(fbuf,":");
+               (void) display_minventory(mtmp, MINV_ALL, fbuf);
+           } else {
+               You("%s no objects here.", verb);
+           }
+           return(!!Blind);
+       }
+       if (!skip_objects && (trap = t_at(u.ux,u.uy)) && trap->tseen)
+               There("is %s here.",
+                       an(defsyms[trap_to_defsym(trap->ttyp)].explanation));
+
+       otmp = level.objects[u.ux][u.uy];
+       dfeature = dfeature_at(u.ux, u.uy, fbuf2);
+       if (dfeature && !strcmp(dfeature, "pool of water") && Underwater)
+               dfeature = 0;
+
+       if (Blind) {
+               boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
+               if (dfeature && !strncmp(dfeature, "altar ", 6)) {
+                   /* don't say "altar" twice, dfeature has more info */
+                   You("try to feel what is here.");
+               } else {
+                   You("try to feel what is %s%s.",
+                       drift ? "floating here" : "lying here on the ",
+                       drift ? ""              : surface(u.ux, u.uy));
+               }
+               if (dfeature && !drift && !strcmp(dfeature, surface(u.ux,u.uy)))
+                       dfeature = 0;           /* ice already identifed */
+               if (!can_reach_floor()) {
+                       pline("But you can't reach it!");
+                       return(0);
+               }
+       }
+
+       if (dfeature)
+               Sprintf(fbuf, "There is %s here.", an(dfeature));
+
+       if (!otmp || is_lava(u.ux,u.uy) || (is_pool(u.ux,u.uy) && !Underwater)) {
+               if (dfeature) pline(fbuf);
+               read_engr_at(u.ux, u.uy); /* Eric Backus */
+               if (!skip_objects && (Blind || !dfeature))
+                   You("%s no objects here.", verb);
+               return(!!Blind);
+       }
+       /* we know there is something here */
+
+       if (skip_objects) {
+           if (dfeature) pline(fbuf);
+           read_engr_at(u.ux, u.uy); /* Eric Backus */
+           There("are %s%s objects here.",
+                 (obj_cnt <= 10) ? "several" : "many",
+                 picked_some ? " more" : "");
+       } else if (!otmp->nexthere) {
+           /* only one object */
+           if (dfeature) pline(fbuf);
+           read_engr_at(u.ux, u.uy); /* Eric Backus */
+#ifdef INVISIBLE_OBJECTS
+           if (otmp->oinvis && !See_invisible) verb = "feel";
+#endif
+           You("%s here %s.", verb, doname(otmp));
+           if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE);
+       } else {
+           display_nhwindow(WIN_MESSAGE, FALSE);
+           tmpwin = create_nhwindow(NHW_MENU);
+           if(dfeature) {
+               putstr(tmpwin, 0, fbuf);
+               putstr(tmpwin, 0, "");
+           }
+           putstr(tmpwin, 0, Blind ? "Things that you feel here:" :
+                                     "Things that are here:");
+           for ( ; otmp; otmp = otmp->nexthere) {
+               if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
+                       char buf[BUFSZ];
+                       felt_cockatrice = TRUE;
+                       Strcpy(buf, doname(otmp));
+                       Strcat(buf, "...");
+                       putstr(tmpwin, 0, buf);
+                       break;
+               }
+               putstr(tmpwin, 0, doname(otmp));
+           }
+           display_nhwindow(tmpwin, TRUE);
+           destroy_nhwindow(tmpwin);
+           if (felt_cockatrice) feel_cockatrice(otmp, FALSE);
+           read_engr_at(u.ux, u.uy); /* Eric Backus */
+       }
+       return(!!Blind);
+}
+
+/* explicilty look at what is here, including all objects */
+int
+dolook()
+{
+       return look_here(0, FALSE);
+}
+
+boolean
+will_feel_cockatrice(otmp, force_touch)
+struct obj *otmp;
+boolean force_touch;
+{
+       if ((Blind || force_touch) && !uarmg && !Stone_resistance &&
+               (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])))
+                       return TRUE;
+       return FALSE;
+}
+
+void
+feel_cockatrice(otmp, force_touch)
+struct obj *otmp;
+boolean force_touch;
+{
+       char kbuf[BUFSZ];
+
+       if (will_feel_cockatrice(otmp, force_touch)) {
+           if(poly_when_stoned(youmonst.data))
+                       You("touched the %s corpse with your bare %s.",
+                               mons[otmp->corpsenm].mname, makeplural(body_part(HAND)));
+           else
+                       pline("Touching the %s corpse is a fatal mistake...",
+                               mons[otmp->corpsenm].mname);
+               Sprintf(kbuf, "%s corpse", an(mons[otmp->corpsenm].mname));
+               instapetrify(kbuf);
+       }
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+void
+stackobj(obj)
+struct obj *obj;
+{
+       struct obj *otmp;
+
+       for(otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
+               if(otmp != obj && merged(&obj,&otmp))
+                       break;
+       return;
+}
+
+STATIC_OVL boolean
+mergable(otmp, obj)    /* returns TRUE if obj  & otmp can be merged */
+       register struct obj *otmp, *obj;
+{
+       if (obj->otyp != otmp->otyp) return FALSE;
+#ifdef GOLDOBJ
+       /* coins of the same kind will always merge */
+       if (obj->oclass == COIN_CLASS) return TRUE;
+#endif
+       if (obj->unpaid != otmp->unpaid ||
+           obj->spe != otmp->spe || obj->dknown != otmp->dknown ||
+           (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) ||
+           obj->cursed != otmp->cursed || obj->blessed != otmp->blessed ||
+           obj->no_charge != otmp->no_charge ||
+           obj->obroken != otmp->obroken ||
+           obj->otrapped != otmp->otrapped ||
+           obj->lamplit != otmp->lamplit ||
+#ifdef INVISIBLE_OBJECTS
+               obj->oinvis != otmp->oinvis ||
+#endif
+           obj->greased != otmp->greased ||
+           obj->oeroded != otmp->oeroded ||
+           obj->oeroded2 != otmp->oeroded2 ||
+           obj->bypass != otmp->bypass)
+           return(FALSE);
+
+       if ((obj->oclass==WEAPON_CLASS || obj->oclass==ARMOR_CLASS) &&
+           (obj->oerodeproof!=otmp->oerodeproof || obj->rknown!=otmp->rknown))
+           return FALSE;
+
+       if (obj->oclass == FOOD_CLASS && (obj->oeaten != otmp->oeaten ||
+                                         obj->orotten != otmp->orotten))
+           return(FALSE);
+
+       if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
+               if (obj->corpsenm != otmp->corpsenm)
+                               return FALSE;
+       }
+
+       /* hatching eggs don't merge; ditto for revivable corpses */
+       if ((obj->otyp == EGG && (obj->timed || otmp->timed)) ||
+           (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM &&
+               is_reviver(&mons[otmp->corpsenm])))
+           return FALSE;
+
+       /* allow candle merging only if their ages are close */
+       /* see begin_burn() for a reference for the magic "25" */
+       if (Is_candle(obj) && obj->age/25 != otmp->age/25)
+           return(FALSE);
+
+       /* burning potions of oil never merge */
+       if (obj->otyp == POT_OIL && obj->lamplit)
+           return FALSE;
+
+       /* don't merge surcharged item with base-cost item */
+       if (obj->unpaid && !same_price(obj, otmp))
+           return FALSE;
+
+       /* if they have names, make sure they're the same */
+       if ( (obj->onamelth != otmp->onamelth &&
+               ((obj->onamelth && otmp->onamelth) || obj->otyp == CORPSE)
+            ) ||
+           (obj->onamelth && otmp->onamelth &&
+                   strncmp(ONAME(obj), ONAME(otmp), (int)obj->onamelth)))
+               return FALSE;
+
+       /* for the moment, any additional information is incompatible */
+       if (obj->oxlth || otmp->oxlth) return FALSE;
+
+       if(obj->oartifact != otmp->oartifact) return FALSE;
+
+       if(obj->known == otmp->known ||
+               !objects[otmp->otyp].oc_uses_known) {
+               return((boolean)(objects[obj->otyp].oc_merge));
+       } else return(FALSE);
+}
+
+int
+doprgold()
+{
+       /* the messages used to refer to "carrying gold", but that didn't
+          take containers into account */
+#ifndef GOLDOBJ
+       if(!u.ugold)
+           Your("wallet is empty.");
+       else
+           Your("wallet contains %ld gold piece%s.", u.ugold, plur(u.ugold));
+#else
+        long umoney = money_cnt(invent);
+       if(!umoney)
+           Your("wallet is empty.");
+       else
+           Your("wallet contains %ld %s.", umoney, currency(umoney));
+#endif
+       shopper_financial_report();
+       return 0;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+int
+doprwep()
+{
+    if (!uwep) {
+       You("are empty %s.", body_part(HANDED));
+    } else {
+       prinv((char *)0, uwep, 0L);
+       if (u.twoweap) prinv((char *)0, uswapwep, 0L);
+    }
+    return 0;
+}
+
+int
+doprarm()
+{
+       if(!wearing_armor())
+               You("are not wearing any armor.");
+       else {
+#ifdef TOURIST
+               char lets[8];
+#else
+               char lets[7];
+#endif
+               register int ct = 0;
+
+#ifdef TOURIST
+               if(uarmu) lets[ct++] = obj_to_let(uarmu);
+#endif
+               if(uarm) lets[ct++] = obj_to_let(uarm);
+               if(uarmc) lets[ct++] = obj_to_let(uarmc);
+               if(uarmh) lets[ct++] = obj_to_let(uarmh);
+               if(uarms) lets[ct++] = obj_to_let(uarms);
+               if(uarmg) lets[ct++] = obj_to_let(uarmg);
+               if(uarmf) lets[ct++] = obj_to_let(uarmf);
+               lets[ct] = 0;
+               (void) display_inventory(lets, FALSE);
+       }
+       return 0;
+}
+
+int
+doprring()
+{
+       if(!uleft && !uright)
+               You("are not wearing any rings.");
+       else {
+               char lets[3];
+               register int ct = 0;
+
+               if(uleft) lets[ct++] = obj_to_let(uleft);
+               if(uright) lets[ct++] = obj_to_let(uright);
+               lets[ct] = 0;
+               (void) display_inventory(lets, FALSE);
+       }
+       return 0;
+}
+
+int
+dopramulet()
+{
+       if (!uamul)
+               You("are not wearing an amulet.");
+       else
+               prinv((char *)0, uamul, 0L);
+       return 0;
+}
+
+STATIC_OVL boolean
+tool_in_use(obj)
+struct obj *obj;
+{
+       if ((obj->owornmask & (W_TOOL
+#ifdef STEED
+                       | W_SADDLE
+#endif
+                       )) != 0L) return TRUE;
+       if (obj->oclass != TOOL_CLASS) return FALSE;
+       return (boolean)(obj == uwep || obj->lamplit ||
+                               (obj->otyp == LEASH && obj->leashmon));
+}
+
+int
+doprtool()
+{
+       struct obj *otmp;
+       int ct = 0;
+       char lets[52+1];
+
+       for (otmp = invent; otmp; otmp = otmp->nobj)
+           if (tool_in_use(otmp))
+               lets[ct++] = obj_to_let(otmp);
+       lets[ct] = '\0';
+       if (!ct) You("are not using any tools.");
+       else (void) display_inventory(lets, FALSE);
+       return 0;
+}
+
+/* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
+   show inventory of all currently wielded, worn, or used objects */
+int
+doprinuse()
+{
+       struct obj *otmp;
+       int ct = 0;
+       char lets[52+1];
+
+       for (otmp = invent; otmp; otmp = otmp->nobj)
+           if (is_worn(otmp) || tool_in_use(otmp))
+               lets[ct++] = obj_to_let(otmp);
+       lets[ct] = '\0';
+       if (!ct) You("are not wearing or wielding anything.");
+       else (void) display_inventory(lets, FALSE);
+       return 0;
+}
+
+/*
+ * uses up an object that's on the floor, charging for it as necessary
+ */
+void
+useupf(obj, numused)
+register struct obj *obj;
+long numused;
+{
+       register struct obj *otmp;
+       boolean at_u = (obj->ox == u.ux && obj->oy == u.uy);
+
+       /* burn_floor_paper() keeps an object pointer that it tries to
+        * useupf() multiple times, so obj must survive if plural */
+       if (obj->quan > numused)
+               otmp = splitobj(obj, numused);
+       else
+               otmp = obj;
+       if(costly_spot(otmp->ox, otmp->oy)) {
+           if(index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
+               addtobill(otmp, FALSE, FALSE, FALSE);
+           else (void)stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
+       }
+       delobj(otmp);
+       if (at_u && u.uundetected && hides_under(youmonst.data))
+           u.uundetected = OBJ_AT(u.ux, u.uy);
+}
+
+#endif /* OVLB */
+
+
+#ifdef OVL1
+
+/*
+ * Conversion from a class to a string for printing.
+ * This must match the object class order.
+ */
+STATIC_VAR NEARDATA const char *names[] = { 0,
+       "Illegal objects", "Weapons", "Armor", "Rings", "Amulets",
+       "Tools", "Comestibles", "Potions", "Scrolls", "Spellbooks",
+       "Wands", "Coins", "Gems", "Boulders/Statues", "Iron balls",
+       "Chains", "Venoms"
+};
+
+static NEARDATA const char oth_symbols[] = {
+       CONTAINED_SYM,
+       '\0'
+};
+
+static NEARDATA const char *oth_names[] = {
+       "Bagged/Boxed items"
+};
+
+static NEARDATA char *invbuf = (char *)0;
+static NEARDATA unsigned invbufsiz = 0;
+
+char *
+let_to_name(let,unpaid)
+char let;
+boolean unpaid;
+{
+       const char *class_name;
+       const char *pos;
+       int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0;
+       unsigned len;
+
+       if (oclass)
+           class_name = names[oclass];
+       else if ((pos = index(oth_symbols, let)) != 0)
+           class_name = oth_names[pos - oth_symbols];
+       else
+           class_name = names[0];
+
+       len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "");
+       if (len > invbufsiz) {
+           if (invbuf) free((genericptr_t)invbuf);
+           invbufsiz = len + 10; /* add slop to reduce incremental realloc */
+           invbuf = (char *) alloc(invbufsiz);
+       }
+       if (unpaid)
+           Strcat(strcpy(invbuf, "Unpaid "), class_name);
+       else
+           Strcpy(invbuf, class_name);
+       return invbuf;
+}
+
+void
+free_invbuf()
+{
+       if (invbuf) free((genericptr_t)invbuf),  invbuf = (char *)0;
+       invbufsiz = 0;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+void
+reassign()
+{
+       register int i;
+       register struct obj *obj;
+
+       for(obj = invent, i = 0; obj; obj = obj->nobj, i++)
+               obj->invlet = (i < 26) ? ('a'+i) : ('A'+i-26);
+       lastinvnr = i;
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+int
+doorganize()   /* inventory organizer by Del Lamb */
+{
+       struct obj *obj, *otmp;
+       register int ix, cur;
+       register char let;
+       char alphabet[52+1], buf[52+1];
+       char qbuf[QBUFSZ];
+       char allowall[2];
+       const char *adj_type;
+
+       if (!flags.invlet_constant) reassign();
+       /* get a pointer to the object the user wants to organize */
+       allowall[0] = ALL_CLASSES; allowall[1] = '\0';
+       if (!(obj = getobj(allowall,"adjust"))) return(0);
+
+       /* initialize the list with all upper and lower case letters */
+       for (let = 'a', ix = 0;  let <= 'z';) alphabet[ix++] = let++;
+       for (let = 'A', ix = 26; let <= 'Z';) alphabet[ix++] = let++;
+       alphabet[52] = 0;
+
+       /* blank out all the letters currently in use in the inventory */
+       /* except those that will be merged with the selected object   */
+       for (otmp = invent; otmp; otmp = otmp->nobj)
+               if (otmp != obj && !mergable(otmp,obj)) {
+                       if (otmp->invlet <= 'Z')
+                               alphabet[(otmp->invlet) - 'A' + 26] = ' ';
+                       else    alphabet[(otmp->invlet) - 'a']      = ' ';
+               }
+
+       /* compact the list by removing all the blanks */
+       for (ix = cur = 0; ix <= 52; ix++)
+               if (alphabet[ix] != ' ') buf[cur++] = alphabet[ix];
+
+       /* and by dashing runs of letters */
+       if(cur > 5) compactify(buf);
+
+       /* get new letter to use as inventory letter */
+       for (;;) {
+               Sprintf(qbuf, "Adjust letter to what [%s]?",buf);
+               let = yn_function(qbuf, (char *)0, '\0');
+               if(index(quitchars,let)) {
+                       pline(Never_mind);
+                       return(0);
+               }
+               if (let == '@' || !letter(let))
+                       pline("Select an inventory slot letter.");
+               else
+                       break;
+       }
+
+       /* change the inventory and print the resulting item */
+       adj_type = "Moving:";
+
+       /*
+        * don't use freeinv/addinv to avoid double-touching artifacts,
+        * dousing lamps, losing luck, cursing loadstone, etc.
+        */
+       extract_nobj(obj, &invent);
+
+       for (otmp = invent; otmp;)
+               if (merged(&otmp,&obj)) {
+                       adj_type = "Merging:";
+                       obj = otmp;
+                       otmp = otmp->nobj;
+                       extract_nobj(obj, &invent);
+               } else {
+                       if (otmp->invlet == let) {
+                               adj_type = "Swapping:";
+                               otmp->invlet = obj->invlet;
+                       }
+                       otmp = otmp->nobj;
+               }
+
+       /* inline addinv (assuming flags.invlet_constant and !merged) */
+       obj->invlet = let;
+       obj->nobj = invent; /* insert at beginning */
+       obj->where = OBJ_INVENT;
+       invent = obj;
+       reorder_invent();
+
+       prinv(adj_type, obj, 0L);
+       update_inventory();
+       return(0);
+}
+
+/* common to display_minventory and display_cinventory */
+STATIC_OVL void
+invdisp_nothing(hdr, txt)
+const char *hdr, *txt;
+{
+       winid win;
+       anything any;
+       menu_item *selected;
+
+       any.a_void = 0;
+       win = create_nhwindow(NHW_MENU);
+       start_menu(win);
+       add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr, MENU_UNSELECTED);
+       add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
+       add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED);
+       end_menu(win, (char *)0);
+       if (select_menu(win, PICK_NONE, &selected) > 0)
+           free((genericptr_t)selected);
+       destroy_nhwindow(win);
+       return;
+}
+
+/* query_objlist callback: return things that could possibly be worn/wielded */
+STATIC_OVL boolean
+worn_wield_only(obj)
+struct obj *obj;
+{
+    return (obj->oclass == WEAPON_CLASS
+               || obj->oclass == ARMOR_CLASS
+               || obj->oclass == AMULET_CLASS
+               || obj->oclass == RING_CLASS
+               || obj->oclass == TOOL_CLASS);
+}
+
+/*
+ * Display a monster's inventory.
+ * Returns a pointer to the object from the monster's inventory selected
+ * or NULL if nothing was selected.
+ *
+ * By default, only worn and wielded items are displayed.  The caller
+ * can pick one.  Modifier flags are:
+ *
+ *     MINV_NOLET      - nothing selectable
+ *     MINV_ALL        - display all inventory
+ */
+struct obj *
+display_minventory(mon, dflags, title)
+register struct monst *mon;
+int dflags;
+char *title;
+{
+       struct obj *ret;
+#ifndef GOLDOBJ
+       struct obj m_gold;
+#endif
+       char tmp[QBUFSZ];
+       int n;
+       menu_item *selected = 0;
+#ifndef GOLDOBJ
+       int do_all = (dflags & MINV_ALL) != 0,
+           do_gold = (do_all && mon->mgold);
+#else
+       int do_all = (dflags & MINV_ALL) != 0;
+#endif
+
+       Sprintf(tmp,"%s %s:", s_suffix(noit_Monnam(mon)),
+               do_all ? "possessions" : "armament");
+
+#ifndef GOLDOBJ
+       if (do_all ? (mon->minvent || mon->mgold)
+#else
+       if (do_all ? (mon->minvent != 0)
+#endif
+                  : (mon->misc_worn_check || MON_WEP(mon))) {
+           /* Fool the 'weapon in hand' routine into
+            * displaying 'weapon in claw', etc. properly.
+            */
+           youmonst.data = mon->data;
+
+#ifndef GOLDOBJ
+           if (do_gold) {
+               /*
+                * Make temporary gold object and insert at the head of
+                * the mon's inventory.  We can get away with using a
+                * stack variable object because monsters don't carry
+                * gold in their inventory, so it won't merge.
+                */
+               m_gold = zeroobj;
+               m_gold.otyp = GOLD_PIECE;  m_gold.oclass = COIN_CLASS;
+               m_gold.quan = mon->mgold;  m_gold.dknown = 1;
+               m_gold.where = OBJ_FREE;
+               /* we had better not merge and free this object... */
+               if (add_to_minv(mon, &m_gold))
+                   panic("display_minventory: static object freed.");
+           }
+
+#endif
+           n = query_objlist(title ? title : tmp, mon->minvent, INVORDER_SORT, &selected,
+                       (dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE,
+                       do_all ? allow_all : worn_wield_only);
+
+#ifndef GOLDOBJ
+           if (do_gold) obj_extract_self(&m_gold);
+#endif
+
+           set_uasmon();
+       } else {
+           invdisp_nothing(title ? title : tmp, "(none)");
+           n = 0;
+       }
+
+       if (n > 0) {
+           ret = selected[0].item.a_obj;
+           free((genericptr_t)selected);
+#ifndef GOLDOBJ
+           /*
+            * Unfortunately, we can't return a pointer to our temporary
+            * gold object.  We'll have to work out a scheme where this
+            * can happen.  Maybe even put gold in the inventory list...
+            */
+           if (ret == &m_gold) ret = (struct obj *) 0;
+#endif
+       } else
+           ret = (struct obj *) 0;
+       return ret;
+}
+
+/*
+ * Display the contents of a container in inventory style.
+ * Currently, this is only used for statues, via wand of probing.
+ */
+struct obj *
+display_cinventory(obj)
+register struct obj *obj;
+{
+       struct obj *ret;
+       char tmp[QBUFSZ];
+       int n;
+       menu_item *selected = 0;
+
+       Sprintf(tmp,"Contents of %s:", doname(obj));
+
+       if (obj->cobj) {
+           n = query_objlist(tmp, obj->cobj, INVORDER_SORT, &selected,
+                           PICK_NONE, allow_all);
+       } else {
+           invdisp_nothing(tmp, "(empty)");
+           n = 0;
+       }
+       if (n > 0) {
+           ret = selected[0].item.a_obj;
+           free((genericptr_t)selected);
+       } else
+           ret = (struct obj *) 0;
+       return ret;
+}
+
+/* query objlist callback: return TRUE if obj is at given location */
+static coord only;
+
+STATIC_OVL boolean
+only_here(obj)
+    struct obj *obj;
+{
+    return (obj->ox == only.x && obj->oy == only.y);
+}
+
+/*
+ * Display a list of buried items in inventory style.  Return a non-zero
+ * value if there were items at that spot.
+ *
+ * Currently, this is only used with a wand of probing zapped downwards.
+ */
+int
+display_binventory(x, y, as_if_seen)
+int x, y;
+boolean as_if_seen;
+{
+       struct obj *obj;
+       menu_item *selected = 0;
+       int n;
+
+       /* count # of objects here */
+       for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj)
+           if (obj->ox == x && obj->oy == y) {
+               if (as_if_seen) obj->dknown = 1;
+               n++;
+           }
+
+       if (n) {
+           only.x = x;
+           only.y = y;
+           if (query_objlist("Things that are buried here:",
+                             level.buriedobjlist, INVORDER_SORT,
+                             &selected, PICK_NONE, only_here) > 0)
+               free((genericptr_t)selected);
+           only.x = only.y = 0;
+       }
+       return n;
+}
+
+#endif /* OVL1 */
+
+/*invent.c*/
diff --git a/src/light.c b/src/light.c
new file mode 100644 (file)
index 0000000..d0029e7
--- /dev/null
@@ -0,0 +1,626 @@
+/*     SCCS Id: @(#)light.c    3.4     1997/04/10      */
+/* Copyright (c) Dean Luick, 1994                                      */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+#include "hack.h"
+#include "lev.h"       /* for checking save modes */
+
+/*
+ * Mobile light sources.
+ *
+ * This implementation minimizes memory at the expense of extra
+ * recalculations.
+ *
+ * Light sources are "things" that have a physical position and range.
+ * They have a type, which gives us information about them.  Currently
+ * they are only attached to objects and monsters.  Note well:  the
+ * polymorphed-player handling assumes that both youmonst.m_id and
+ * youmonst.mx will always remain 0.
+ *
+ * Light sources, like timers, either follow game play (RANGE_GLOBAL) or
+ * stay on a level (RANGE_LEVEL).  Light sources are unique by their
+ * (type, id) pair.  For light sources attached to objects, this id
+ * is a pointer to the object.
+ *
+ * The major working function is do_light_sources(). It is called
+ * when the vision system is recreating its "could see" array.  Here
+ * we add a flag (TEMP_LIT) to the array for all locations that are lit
+ * via a light source.  The bad part of this is that we have to
+ * re-calculate the LOS of each light source every time the vision
+ * system runs.  Even if the light sources and any topology (vision blocking
+ * positions) have not changed.  The good part is that no extra memory
+ * is used, plus we don't have to figure out how far the sources have moved,
+ * or if the topology has changed.
+ *
+ * The structure of the save/restore mechanism is amazingly similar to
+ * the timer save/restore.  This is because they both have the same
+ * principals of having pointers into objects that must be recalculated
+ * across saves and restores.
+ */
+
+#ifdef OVL3
+
+/* flags */
+#define LSF_SHOW       0x1             /* display the light source */
+#define LSF_NEEDS_FIXUP        0x2             /* need oid fixup */
+
+static light_source *light_base = 0;
+
+STATIC_DCL void FDECL(write_ls, (int, light_source *));
+STATIC_DCL int FDECL(maybe_write_ls, (int, int, BOOLEAN_P));
+
+/* imported from vision.c, for small circles */
+extern char circle_data[];
+extern char circle_start[];
+
+
+/* Create a new light source.  */
+void
+new_light_source(x, y, range, type, id)
+    xchar x, y;
+    int range, type;
+    genericptr_t id;
+{
+    light_source *ls;
+
+    if (range > MAX_RADIUS || range < 1) {
+       impossible("new_light_source:  illegal range %d", range);
+       return;
+    }
+
+    ls = (light_source *) alloc(sizeof(light_source));
+
+    ls->next = light_base;
+    ls->x = x;
+    ls->y = y;
+    ls->range = range;
+    ls->type = type;
+    ls->id = id;
+    ls->flags = 0;
+    light_base = ls;
+
+    vision_full_recalc = 1;    /* make the source show up */
+}
+
+/*
+ * Delete a light source. This assumes only one light source is attached
+ * to an object at a time.
+ */
+void
+del_light_source(type, id)
+    int type;
+    genericptr_t id;
+{
+    light_source *curr, *prev;
+    genericptr_t tmp_id;
+
+    /* need to be prepared for dealing a with light source which
+       has only been partially restored during a level change
+       (in particular: chameleon vs prot. from shape changers) */
+    switch (type) {
+    case LS_OBJECT:    tmp_id = (genericptr_t)(((struct obj *)id)->o_id);
+                       break;
+    case LS_MONSTER:   tmp_id = (genericptr_t)(((struct monst *)id)->m_id);
+                       break;
+    default:           tmp_id = 0;
+                       break;
+    }
+
+    for (prev = 0, curr = light_base; curr; prev = curr, curr = curr->next) {
+       if (curr->type != type) continue;
+       if (curr->id == ((curr->flags & LSF_NEEDS_FIXUP) ? tmp_id : id)) {
+           if (prev)
+               prev->next = curr->next;
+           else
+               light_base = curr->next;
+
+           free((genericptr_t)curr);
+           vision_full_recalc = 1;
+           return;
+       }
+    }
+    impossible("del_light_source: not found type=%d, id=0x%lx", type, (long)id);
+}
+
+/* Mark locations that are temporarily lit via mobile light sources. */
+void
+do_light_sources(cs_rows)
+    char **cs_rows;
+{
+    int x, y, min_x, max_x, max_y, offset;
+    char *limits;
+    short at_hero_range = 0;
+    light_source *ls;
+    char *row;
+
+    for (ls = light_base; ls; ls = ls->next) {
+       ls->flags &= ~LSF_SHOW;
+
+       /*
+        * Check for moved light sources.  It may be possible to
+        * save some effort if an object has not moved, but not in
+        * the current setup -- we need to recalculate for every
+        * vision recalc.
+        */
+       if (ls->type == LS_OBJECT) {
+           if (get_obj_location((struct obj *) ls->id, &ls->x, &ls->y, 0))
+               ls->flags |= LSF_SHOW;
+       } else if (ls->type == LS_MONSTER) {
+           if (get_mon_location((struct monst *) ls->id, &ls->x, &ls->y, 0))
+               ls->flags |= LSF_SHOW;
+       }
+
+       /* minor optimization: don't bother with duplicate light sources */
+       /* at hero */
+       if (ls->x == u.ux && ls->y == u.uy) {
+           if (at_hero_range >= ls->range)
+               ls->flags &= ~LSF_SHOW;
+           else
+               at_hero_range = ls->range;
+       }
+
+       if (ls->flags & LSF_SHOW) {
+           /*
+            * Walk the points in the circle and see if they are
+            * visible from the center.  If so, mark'em.
+            *
+            * Kevin's tests indicated that doing this brute-force
+            * method is faster for radius <= 3 (or so).
+            */
+           limits = circle_ptr(ls->range);
+           if ((max_y = (ls->y + ls->range)) >= ROWNO) max_y = ROWNO-1;
+           if ((y = (ls->y - ls->range)) < 0) y = 0;
+           for (; y <= max_y; y++) {
+               row = cs_rows[y];
+               offset = limits[abs(y - ls->y)];
+               if ((min_x = (ls->x - offset)) < 0) min_x = 0;
+               if ((max_x = (ls->x + offset)) >= COLNO) max_x = COLNO-1;
+
+               if (ls->x == u.ux && ls->y == u.uy) {
+                   /*
+                    * If the light source is located at the hero, then
+                    * we can use the COULD_SEE bits already calcualted
+                    * by the vision system.  More importantly than
+                    * this optimization, is that it allows the vision
+                    * system to correct problems with clear_path().
+                    * The function clear_path() is a simple LOS
+                    * path checker that doesn't go out of its way
+                    * make things look "correct".  The vision system
+                    * does this.
+                    */
+                   for (x = min_x; x <= max_x; x++)
+                       if (row[x] & COULD_SEE)
+                           row[x] |= TEMP_LIT;
+               } else {
+                   for (x = min_x; x <= max_x; x++)
+                       if ((ls->x == x && ls->y == y)
+                               || clear_path((int)ls->x, (int) ls->y, x, y))
+                           row[x] |= TEMP_LIT;
+               }
+           }
+       }
+    }
+}
+
+/* (mon->mx == 0) implies migrating */
+#define mon_is_local(mon)      ((mon)->mx > 0)
+
+struct monst *
+find_mid(nid, fmflags)
+unsigned nid;
+unsigned fmflags;
+{
+       struct monst *mtmp;
+
+       if (!nid)
+           return &youmonst;
+       if (fmflags & FM_FMON)
+               for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+                   if (!DEADMONSTER(mtmp) && mtmp->m_id == nid) return mtmp;
+       if (fmflags & FM_MIGRATE)
+               for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
+                   if (mtmp->m_id == nid) return mtmp;
+       if (fmflags & FM_MYDOGS)
+               for (mtmp = mydogs; mtmp; mtmp = mtmp->nmon)
+                   if (mtmp->m_id == nid) return mtmp;
+       return (struct monst *) 0;
+}
+
+/* Save all light sources of the given range. */
+void
+save_light_sources(fd, mode, range)
+    int fd, mode, range;
+{
+    int count, actual, is_global;
+    light_source **prev, *curr;
+
+    if (perform_bwrite(mode)) {
+       count = maybe_write_ls(fd, range, FALSE);
+       bwrite(fd, (genericptr_t) &count, sizeof count);
+       actual = maybe_write_ls(fd, range, TRUE);
+       if (actual != count)
+           panic("counted %d light sources, wrote %d! [range=%d]",
+                 count, actual, range);
+    }
+
+    if (release_data(mode)) {
+       for (prev = &light_base; (curr = *prev) != 0; ) {
+           if (!curr->id) {
+               impossible("save_light_sources: no id! [range=%d]", range);
+               is_global = 0;
+           } else
+           switch (curr->type) {
+           case LS_OBJECT:
+               is_global = !obj_is_local((struct obj *)curr->id);
+               break;
+           case LS_MONSTER:
+               is_global = !mon_is_local((struct monst *)curr->id);
+               break;
+           default:
+               is_global = 0;
+               impossible("save_light_sources: bad type (%d) [range=%d]",
+                          curr->type, range);
+               break;
+           }
+           /* if global and not doing local, or vice versa, remove it */
+           if (is_global ^ (range == RANGE_LEVEL)) {
+               *prev = curr->next;
+               free((genericptr_t)curr);
+           } else {
+               prev = &(*prev)->next;
+           }
+       }
+    }
+}
+
+/*
+ * Pull in the structures from disk, but don't recalculate the object
+ * pointers.
+ */
+void
+restore_light_sources(fd)
+    int fd;
+{
+    int count;
+    light_source *ls;
+
+    /* restore elements */
+    mread(fd, (genericptr_t) &count, sizeof count);
+
+    while (count-- > 0) {
+       ls = (light_source *) alloc(sizeof(light_source));
+       mread(fd, (genericptr_t) ls, sizeof(light_source));
+       ls->next = light_base;
+       light_base = ls;
+    }
+}
+
+/* Relink all lights that are so marked. */
+void
+relink_light_sources(ghostly)
+    boolean ghostly;
+{
+    char which;
+    unsigned nid;
+    light_source *ls;
+
+    for (ls = light_base; ls; ls = ls->next) {
+       if (ls->flags & LSF_NEEDS_FIXUP) {
+           if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) {
+               if (ghostly) {
+                   if (!lookup_id_mapping((unsigned)ls->id, &nid))
+                       impossible("relink_light_sources: no id mapping");
+               } else
+                   nid = (unsigned) ls->id;
+               if (ls->type == LS_OBJECT) {
+                   which = 'o';
+                   ls->id = (genericptr_t) find_oid(nid);
+               } else {
+                   which = 'm';
+                   ls->id = (genericptr_t) find_mid(nid, FM_EVERYWHERE);
+               }
+               if (!ls->id)
+                   impossible("relink_light_sources: cant find %c_id %d",
+                              which, nid);
+           } else
+               impossible("relink_light_sources: bad type (%d)", ls->type);
+
+           ls->flags &= ~LSF_NEEDS_FIXUP;
+       }
+    }
+}
+
+/*
+ * Part of the light source save routine.  Count up the number of light
+ * sources that would be written.  If write_it is true, actually write
+ * the light source out.
+ */
+STATIC_OVL int
+maybe_write_ls(fd, range, write_it)
+    int fd, range;
+    boolean write_it;
+{
+    int count = 0, is_global;
+    light_source *ls;
+
+    for (ls = light_base; ls; ls = ls->next) {
+       if (!ls->id) {
+           impossible("maybe_write_ls: no id! [range=%d]", range);
+           continue;
+       }
+       switch (ls->type) {
+       case LS_OBJECT:
+           is_global = !obj_is_local((struct obj *)ls->id);
+           break;
+       case LS_MONSTER:
+           is_global = !mon_is_local((struct monst *)ls->id);
+           break;
+       default:
+           is_global = 0;
+           impossible("maybe_write_ls: bad type (%d) [range=%d]",
+                      ls->type, range);
+           break;
+       }
+       /* if global and not doing local, or vice versa, count it */
+       if (is_global ^ (range == RANGE_LEVEL)) {
+           count++;
+           if (write_it) write_ls(fd, ls);
+       }
+    }
+
+    return count;
+}
+
+/* Write a light source structure to disk. */
+STATIC_OVL void
+write_ls(fd, ls)
+    int fd;
+    light_source *ls;
+{
+    genericptr_t arg_save;
+    struct obj *otmp;
+    struct monst *mtmp;
+
+    if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) {
+       if (ls->flags & LSF_NEEDS_FIXUP)
+           bwrite(fd, (genericptr_t)ls, sizeof(light_source));
+       else {
+           /* replace object pointer with id for write, then put back */
+           arg_save = ls->id;
+           if (ls->type == LS_OBJECT) {
+               otmp = (struct obj *)ls->id;
+               ls->id = (genericptr_t)otmp->o_id;
+#ifdef DEBUG
+               if (find_oid((unsigned)ls->id) != otmp)
+                   panic("write_ls: can't find obj #%u!", (unsigned)ls->id);
+#endif
+           } else { /* ls->type == LS_MONSTER */
+               mtmp = (struct monst *)ls->id;
+               ls->id = (genericptr_t)mtmp->m_id;
+#ifdef DEBUG
+               if (find_mid((unsigned)ls->id, FM_EVERYWHERE) != mtmp)
+                   panic("write_ls: can't find mon #%u!", (unsigned)ls->id);
+#endif
+           }
+           ls->flags |= LSF_NEEDS_FIXUP;
+           bwrite(fd, (genericptr_t)ls, sizeof(light_source));
+           ls->id = arg_save;
+           ls->flags &= ~LSF_NEEDS_FIXUP;
+       }
+    } else {
+       impossible("write_ls: bad type (%d)", ls->type);
+    }
+}
+
+/* Change light source's ID from src to dest. */
+void
+obj_move_light_source(src, dest)
+    struct obj *src, *dest;
+{
+    light_source *ls;
+
+    for (ls = light_base; ls; ls = ls->next)
+       if (ls->type == LS_OBJECT && ls->id == (genericptr_t) src)
+           ls->id = (genericptr_t) dest;
+    src->lamplit = 0;
+    dest->lamplit = 1;
+}
+
+/* return true if there exist any light sources */
+boolean
+any_light_source()
+{
+    return light_base != (light_source *) 0;
+}
+
+/*
+ * Snuff an object light source if at (x,y).  This currently works
+ * only for burning light sources.
+ */
+void
+snuff_light_source(x, y)
+    int x, y;
+{
+    light_source *ls;
+    struct obj *obj;
+
+    for (ls = light_base; ls; ls = ls->next)
+       /*
+       Is this position check valid??? Can I assume that the positions
+       will always be correct because the objects would have been
+       updated with the last vision update?  [Is that recent enough???]
+       */
+       if (ls->type == LS_OBJECT && ls->x == x && ls->y == y) {
+           obj = (struct obj *) ls->id;
+           if (obj_is_burning(obj)) {
+               /* The only way to snuff Sunsword is to unwield it.  Darkness
+                * scrolls won't affect it.  (If we got here because it was
+                * dropped or thrown inside a monster, this won't matter anyway
+                * because it will go out when dropped.)
+                */
+               if (artifact_light(obj)) continue;
+               end_burn(obj, obj->otyp != MAGIC_LAMP);
+               /*
+                * The current ls element has just been removed (and
+                * ls->next is now invalid).  Return assuming that there
+                * is only one light source attached to each object.
+                */
+               return;
+           }
+       }
+}
+
+/* Return TRUE if object sheds any light at all. */
+boolean
+obj_sheds_light(obj)
+    struct obj *obj;
+{
+    /* so far, only burning objects shed light */
+    return obj_is_burning(obj);
+}
+
+/* Return TRUE if sheds light AND will be snuffed by end_burn(). */
+boolean
+obj_is_burning(obj)
+    struct obj *obj;
+{
+    return (obj->lamplit &&
+               (obj->otyp == MAGIC_LAMP || ignitable(obj) || artifact_light(obj)));
+}
+
+/* copy the light source(s) attachted to src, and attach it/them to dest */
+void
+obj_split_light_source(src, dest)
+    struct obj *src, *dest;
+{
+    light_source *ls, *new_ls;
+
+    for (ls = light_base; ls; ls = ls->next)
+       if (ls->type == LS_OBJECT && ls->id == (genericptr_t) src) {
+           /*
+            * Insert the new source at beginning of list.  This will
+            * never interfere us walking down the list - we are already
+            * past the insertion point.
+            */
+           new_ls = (light_source *) alloc(sizeof(light_source));
+           *new_ls = *ls;
+           if (Is_candle(src)) {
+               /* split candles may emit less light than original group */
+               ls->range = candle_light_range(src);
+               new_ls->range = candle_light_range(dest);
+               vision_full_recalc = 1; /* in case range changed */
+           }
+           new_ls->id = (genericptr_t) dest;
+           new_ls->next = light_base;
+           light_base = new_ls;
+           dest->lamplit = 1;          /* now an active light source */
+       }
+}
+
+/* light source `src' has been folded into light source `dest';
+   used for merging lit candles and adding candle(s) to lit candelabrum */
+void
+obj_merge_light_sources(src, dest)
+struct obj *src, *dest;
+{
+    light_source *ls;
+
+    /* src == dest implies adding to candelabrum */
+    if (src != dest) end_burn(src, TRUE);              /* extinguish candles */
+
+    for (ls = light_base; ls; ls = ls->next)
+       if (ls->type == LS_OBJECT && ls->id == (genericptr_t) dest) {
+           ls->range = candle_light_range(dest);
+           vision_full_recalc = 1;     /* in case range changed */
+           break;
+       }
+}
+
+/* Candlelight is proportional to the number of candles;
+   minimum range is 2 rather than 1 for playability. */
+int
+candle_light_range(obj)
+struct obj *obj;
+{
+    int radius;
+
+    if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
+       /*
+        *      The special candelabrum emits more light than the
+        *      corresponding number of candles would.
+        *       1..3 candles, range 2 (minimum range);
+        *       4..6 candles, range 3 (normal lamp range);
+        *          7 candles, range 4 (bright).
+        */
+       radius = (obj->spe < 4) ? 2 : (obj->spe < 7) ? 3 : 4;
+    } else if (Is_candle(obj)) {
+       /*
+        *      Range is incremented by powers of 7 so that it will take
+        *      wizard mode quantities of candles to get more light than
+        *      from a lamp, without imposing an arbitrary limit.
+        *       1..6   candles, range 2;
+        *       7..48  candles, range 3;
+        *      49..342 candles, range 4; &c.
+        */
+       long n = obj->quan;
+
+       radius = 1;     /* always incremented at least once */
+       do {
+           radius++;
+           n /= 7L;
+       } while (n > 0L);
+    } else {
+       /* we're only called for lit candelabrum or candles */
+     /* impossible("candlelight for %d?", obj->otyp); */
+       radius = 3;             /* lamp's value */
+    }
+    return radius;
+}
+
+#ifdef WIZARD
+extern char *FDECL(fmt_ptr, (const genericptr, char *));  /* from alloc.c */
+
+int
+wiz_light_sources()
+{
+    winid win;
+    char buf[BUFSZ], arg_address[20];
+    light_source *ls;
+
+    win = create_nhwindow(NHW_MENU);   /* corner text window */
+    if (win == WIN_ERR) return 0;
+
+    Sprintf(buf, "Mobile light sources: hero @ (%2d,%2d)", u.ux, u.uy);
+    putstr(win, 0, buf);
+    putstr(win, 0, "");
+
+    if (light_base) {
+       putstr(win, 0, "location range flags  type    id");
+       putstr(win, 0, "-------- ----- ------ ----  -------");
+       for (ls = light_base; ls; ls = ls->next) {
+           Sprintf(buf, "  %2d,%2d   %2d   0x%04x  %s  %s",
+               ls->x, ls->y, ls->range, ls->flags,
+               (ls->type == LS_OBJECT ? "obj" :
+                ls->type == LS_MONSTER ?
+                   (mon_is_local((struct monst *)ls->id) ? "mon" :
+                    ((struct monst *)ls->id == &youmonst) ? "you" :
+                    "<m>") :           /* migrating monster */
+                "???"),
+               fmt_ptr(ls->id, arg_address));
+           putstr(win, 0, buf);
+       }
+    } else
+       putstr(win, 0, "<none>");
+
+
+    display_nhwindow(win, FALSE);
+    destroy_nhwindow(win);
+
+    return 0;
+}
+
+#endif /* WIZARD */
+
+#endif /* OVL3 */
+
+/*light.c*/
diff --git a/src/lock.c b/src/lock.c
new file mode 100644 (file)
index 0000000..4d5d333
--- /dev/null
@@ -0,0 +1,921 @@
+/*     SCCS Id: @(#)lock.c     3.4     2000/02/06      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+STATIC_PTR int NDECL(picklock);
+STATIC_PTR int NDECL(forcelock);
+
+/* at most one of `door' and `box' should be non-null at any given time */
+STATIC_VAR NEARDATA struct xlock_s {
+       struct rm  *door;
+       struct obj *box;
+       int picktyp, chance, usedtime;
+} xlock;
+
+#ifdef OVLB
+
+STATIC_DCL const char *NDECL(lock_action);
+STATIC_DCL boolean FDECL(obstructed,(int,int));
+STATIC_DCL void FDECL(chest_shatter_msg, (struct obj *));
+
+boolean
+picking_lock(x, y)
+       int *x, *y;
+{
+       if (occupation == picklock) {
+           *x = u.ux + u.dx;
+           *y = u.uy + u.dy;
+           return TRUE;
+       } else {
+           *x = *y = 0;
+           return FALSE;
+       }
+}
+
+boolean
+picking_at(x, y)
+int x, y;
+{
+       return (boolean)(occupation == picklock && xlock.door == &levl[x][y]);
+}
+
+/* produce an occupation string appropriate for the current activity */
+STATIC_OVL const char *
+lock_action()
+{
+       /* "unlocking"+2 == "locking" */
+       static const char *actions[] = {
+               /* [0] */       "unlocking the door",
+               /* [1] */       "unlocking the chest",
+               /* [2] */       "unlocking the box",
+               /* [3] */       "picking the lock"
+       };
+
+       /* if the target is currently unlocked, we're trying to lock it now */
+       if (xlock.door && !(xlock.door->doormask & D_LOCKED))
+               return actions[0]+2;    /* "locking the door" */
+       else if (xlock.box && !xlock.box->olocked)
+               return xlock.box->otyp == CHEST ? actions[1]+2 : actions[2]+2;
+       /* otherwise we're trying to unlock it */
+       else if (xlock.picktyp == LOCK_PICK)
+               return actions[3];      /* "picking the lock" */
+#ifdef TOURIST
+       else if (xlock.picktyp == CREDIT_CARD)
+               return actions[3];      /* same as lock_pick */
+#endif
+       else if (xlock.door)
+               return actions[0];      /* "unlocking the door" */
+       else
+               return xlock.box->otyp == CHEST ? actions[1] : actions[2];
+}
+
+STATIC_PTR
+int
+picklock()     /* try to open/close a lock */
+{
+
+       if (xlock.box) {
+           if((xlock.box->ox != u.ux) || (xlock.box->oy != u.uy)) {
+               return((xlock.usedtime = 0));           /* you or it moved */
+           }
+       } else {                /* door */
+           if(xlock.door != &(levl[u.ux+u.dx][u.uy+u.dy])) {
+               return((xlock.usedtime = 0));           /* you moved */
+           }
+           switch (xlock.door->doormask) {
+               case D_NODOOR:
+                   pline("This doorway has no door.");
+                   return((xlock.usedtime = 0));
+               case D_ISOPEN:
+                   You("cannot lock an open door.");
+                   return((xlock.usedtime = 0));
+               case D_BROKEN:
+                   pline("This door is broken.");
+                   return((xlock.usedtime = 0));
+           }
+       }
+
+       if (xlock.usedtime++ >= 50 || nohands(youmonst.data)) {
+           You("give up your attempt at %s.", lock_action());
+           exercise(A_DEX, TRUE);      /* even if you don't succeed */
+           return((xlock.usedtime = 0));
+       }
+
+       if(rn2(100) >= xlock.chance) return(1);         /* still busy */
+
+       You("succeed in %s.", lock_action());
+       if (xlock.door) {
+           if(xlock.door->doormask & D_TRAPPED) {
+                   b_trapped("door", FINGER);
+                   xlock.door->doormask = D_NODOOR;
+                   unblock_point(u.ux+u.dx, u.uy+u.dy);
+                   if (*in_rooms(u.ux+u.dx, u.uy+u.dy, SHOPBASE))
+                       add_damage(u.ux+u.dx, u.uy+u.dy, 0L);
+                   newsym(u.ux+u.dx, u.uy+u.dy);
+           } else if (xlock.door->doormask & D_LOCKED)
+               xlock.door->doormask = D_CLOSED;
+           else xlock.door->doormask = D_LOCKED;
+       } else {
+           xlock.box->olocked = !xlock.box->olocked;
+           if(xlock.box->otrapped)     
+               (void) chest_trap(xlock.box, FINGER, FALSE);
+       }
+       exercise(A_DEX, TRUE);
+       return((xlock.usedtime = 0));
+}
+
+STATIC_PTR
+int
+forcelock()    /* try to force a locked chest */
+{
+
+       register struct obj *otmp;
+
+       if((xlock.box->ox != u.ux) || (xlock.box->oy != u.uy))
+               return((xlock.usedtime = 0));           /* you or it moved */
+
+       if (xlock.usedtime++ >= 50 || !uwep || nohands(youmonst.data)) {
+           You("give up your attempt to force the lock.");
+           if(xlock.usedtime >= 50)            /* you made the effort */
+             exercise((xlock.picktyp) ? A_DEX : A_STR, TRUE);
+           return((xlock.usedtime = 0));
+       }
+
+       if(xlock.picktyp) {     /* blade */
+
+           if(rn2(1000-(int)uwep->spe) > (992-greatest_erosion(uwep)*10) &&
+              !uwep->cursed && !obj_resists(uwep, 0, 99)) {
+               /* for a +0 weapon, probability that it survives an unsuccessful
+                * attempt to force the lock is (.992)^50 = .67
+                */
+               pline("%sour %s broke!",
+                     (uwep->quan > 1L) ? "One of y" : "Y", xname(uwep));
+               useup(uwep);
+               You("give up your attempt to force the lock.");
+               exercise(A_DEX, TRUE);
+               return((xlock.usedtime = 0));
+           }
+       } else                  /* blunt */
+           wake_nearby();      /* due to hammering on the container */
+
+       if(rn2(100) >= xlock.chance) return(1);         /* still busy */
+
+       You("succeed in forcing the lock.");
+       xlock.box->olocked = 0;
+       xlock.box->obroken = 1;
+       if(!xlock.picktyp && !rn2(3)) {
+           struct monst *shkp;
+           boolean costly;
+           long loss = 0L;
+
+           costly = (*u.ushops && costly_spot(u.ux, u.uy));
+           shkp = costly ? shop_keeper(*u.ushops) : 0;
+
+           pline("In fact, you've totally destroyed %s.",
+                 the(xname(xlock.box)));
+
+           /* Put the contents on ground at the hero's feet. */
+           while ((otmp = xlock.box->cobj) != 0) {
+               obj_extract_self(otmp);
+               if(!rn2(3) || otmp->oclass == POTION_CLASS) {
+                   chest_shatter_msg(otmp);
+                   if (costly)
+                       loss += stolen_value(otmp, u.ux, u.uy,
+                                            (boolean)shkp->mpeaceful, TRUE);
+                   if (otmp->quan == 1L) {
+                       obfree(otmp, (struct obj *) 0);
+                       continue;
+                   }
+                   useup(otmp);
+               }
+               if (xlock.box->otyp == ICE_BOX && otmp->otyp == CORPSE) {
+                   otmp->age = monstermoves - otmp->age; /* actual age */
+                   start_corpse_timeout(otmp);
+               }
+               place_object(otmp, u.ux, u.uy);
+               stackobj(otmp);
+           }
+
+           if (costly)
+               loss += stolen_value(xlock.box, u.ux, u.uy,
+                                            (boolean)shkp->mpeaceful, TRUE);
+           if(loss) You("owe %ld %s for objects destroyed.", loss, currency(loss));
+           delobj(xlock.box);
+       }
+       exercise((xlock.picktyp) ? A_DEX : A_STR, TRUE);
+       return((xlock.usedtime = 0));
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+void
+reset_pick()
+{
+       xlock.usedtime = xlock.chance = xlock.picktyp = 0;
+       xlock.door = 0;
+       xlock.box = 0;
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+int
+pick_lock(pick) /* pick a lock with a given object */
+       register struct obj     *pick;
+{
+       int picktyp, c, ch;
+       coord cc;
+       struct rm       *door;
+       struct obj      *otmp;
+       char qbuf[QBUFSZ];
+
+       picktyp = pick->otyp;
+
+       /* check whether we're resuming an interrupted previous attempt */
+       if (xlock.usedtime && picktyp == xlock.picktyp) {
+           static char no_longer[] = "Unfortunately, you can no longer %s %s.";
+
+           if (nohands(youmonst.data)) {
+               const char *what = (picktyp == LOCK_PICK) ? "pick" : "key";
+#ifdef TOURIST
+               if (picktyp == CREDIT_CARD) what = "card";
+#endif
+               pline(no_longer, "hold the", what);
+               reset_pick();
+               return 0;
+           } else if (xlock.box && !can_reach_floor()) {
+               pline(no_longer, "reach the", "lock");
+               reset_pick();
+               return 0;
+           } else {
+               const char *action = lock_action();
+               You("resume your attempt at %s.", action);
+               set_occupation(picklock, action, 0);
+               return(1);
+           }
+       }
+
+       if(nohands(youmonst.data)) {
+               You_cant("hold %s -- you have no hands!", doname(pick));
+               return(0);
+       }
+
+       if((picktyp != LOCK_PICK &&
+#ifdef TOURIST
+           picktyp != CREDIT_CARD &&
+#endif
+           picktyp != SKELETON_KEY)) {
+               impossible("picking lock with object %d?", picktyp);
+               return(0);
+       }
+       ch = 0;         /* lint suppression */
+
+       if(!get_adjacent_loc((char *)0, "Invalid location!", u.ux, u.uy, &cc)) return 0;
+       if (cc.x == u.ux && cc.y == u.uy) {     /* pick lock on a container */
+           const char *verb;
+           boolean it;
+           int count;
+
+           if (u.dz < 0) {
+               There("isn't any sort of lock up %s.",
+                     Levitation ? "here" : "there");
+               return 0;
+           } else if (is_lava(u.ux, u.uy)) {
+               pline("Doing that would probably melt your %s.",
+                     xname(pick));
+               return 0;
+           } else if (is_pool(u.ux, u.uy) && !Underwater) {
+               pline_The("water has no lock.");
+               return 0;
+           }
+
+           count = 0;
+           c = 'n';                    /* in case there are no boxes here */
+           for(otmp = level.objects[cc.x][cc.y]; otmp; otmp = otmp->nexthere)
+               if (Is_box(otmp)) {
+                   ++count;
+                   if (!can_reach_floor()) {
+                       You_cant("reach %s from up here.", the(xname(otmp)));
+                       return 0;
+                   }
+                   it = 0;
+                   if (otmp->obroken) verb = "fix";
+                   else if (!otmp->olocked) verb = "lock", it = 1;
+                   else if (picktyp != LOCK_PICK) verb = "unlock", it = 1;
+                   else verb = "pick";
+                   Sprintf(qbuf, "There is %s here, %s %s?",
+                           safe_qbuf("", sizeof("There is  here, unlock its lock?"),
+                               doname(otmp), an(simple_typename(otmp->otyp)), "a box"),
+                           verb, it ? "it" : "its lock");
+
+                   c = ynq(qbuf);
+                   if(c == 'q') return(0);
+                   if(c == 'n') continue;
+
+                   if (otmp->obroken) {
+                       You_cant("fix its broken lock with %s.", doname(pick));
+                       return 0;
+                   }
+#ifdef TOURIST
+                   else if (picktyp == CREDIT_CARD && !otmp->olocked) {
+                       /* credit cards are only good for unlocking */
+                       You_cant("do that with %s.", doname(pick));
+                       return 0;
+                   }
+#endif
+                   switch(picktyp) {
+#ifdef TOURIST
+                       case CREDIT_CARD:
+                           ch = ACURR(A_DEX) + 20*Role_if(PM_ROGUE);
+                           break;
+#endif
+                       case LOCK_PICK:
+                           ch = 4*ACURR(A_DEX) + 25*Role_if(PM_ROGUE);
+                           break;
+                       case SKELETON_KEY:
+                           ch = 75 + ACURR(A_DEX);
+                           break;
+                       default:        ch = 0;
+                   }
+                   if(otmp->cursed) ch /= 2;
+
+                   xlock.picktyp = picktyp;
+                   xlock.box = otmp;
+                   xlock.door = 0;
+                   break;
+               }
+           if (c != 'y') {
+               if (!count)
+                   There("doesn't seem to be any sort of lock here.");
+               return(0);              /* decided against all boxes */
+           }
+       } else {                        /* pick the lock in a door */
+           struct monst *mtmp;
+
+           if (u.utrap && u.utraptype == TT_PIT) {
+               You_cant("reach over the edge of the pit.");
+               return(0);
+           }
+
+           door = &levl[cc.x][cc.y];
+           if ((mtmp = m_at(cc.x, cc.y)) && canseemon(mtmp)
+                       && mtmp->m_ap_type != M_AP_FURNITURE
+                       && mtmp->m_ap_type != M_AP_OBJECT) {
+#ifdef TOURIST
+               if (picktyp == CREDIT_CARD &&
+                   (mtmp->isshk || mtmp->data == &mons[PM_ORACLE]))
+                   verbalize("No checks, no credit, no problem.");
+               else
+#endif
+                   pline("I don't think %s would appreciate that.", mon_nam(mtmp));
+               return(0);
+           }
+           if(!IS_DOOR(door->typ)) {
+               if (is_drawbridge_wall(cc.x,cc.y) >= 0)
+                   You("%s no lock on the drawbridge.",
+                               Blind ? "feel" : "see");
+               else
+                   You("%s no door there.",
+                               Blind ? "feel" : "see");
+               return(0);
+           }
+           switch (door->doormask) {
+               case D_NODOOR:
+                   pline("This doorway has no door.");
+                   return(0);
+               case D_ISOPEN:
+                   You("cannot lock an open door.");
+                   return(0);
+               case D_BROKEN:
+                   pline("This door is broken.");
+                   return(0);
+               default:
+#ifdef TOURIST
+                   /* credit cards are only good for unlocking */
+                   if(picktyp == CREDIT_CARD && !(door->doormask & D_LOCKED)) {
+                       You_cant("lock a door with a credit card.");
+                       return(0);
+                   }
+#endif
+
+                   Sprintf(qbuf,"%sock it?",
+                       (door->doormask & D_LOCKED) ? "Unl" : "L" );
+
+                   c = yn(qbuf);
+                   if(c == 'n') return(0);
+
+                   switch(picktyp) {
+#ifdef TOURIST
+                       case CREDIT_CARD:
+                           ch = 2*ACURR(A_DEX) + 20*Role_if(PM_ROGUE);
+                           break;
+#endif
+                       case LOCK_PICK:
+                           ch = 3*ACURR(A_DEX) + 30*Role_if(PM_ROGUE);
+                           break;
+                       case SKELETON_KEY:
+                           ch = 70 + ACURR(A_DEX);
+                           break;
+                       default:    ch = 0;
+                   }
+                   xlock.door = door;
+                   xlock.box = 0;
+           }
+       }
+       flags.move = 0;
+       xlock.chance = ch;
+       xlock.picktyp = picktyp;
+       xlock.usedtime = 0;
+       set_occupation(picklock, lock_action(), 0);
+       return(1);
+}
+
+int
+doforce()              /* try to force a chest with your weapon */
+{
+       register struct obj *otmp;
+       register int c, picktyp;
+       char qbuf[QBUFSZ];
+
+       if(!uwep ||     /* proper type test */
+          (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep) &&
+           uwep->oclass != ROCK_CLASS) ||
+          (objects[uwep->otyp].oc_skill < P_DAGGER) ||
+          (objects[uwep->otyp].oc_skill > P_LANCE) ||
+          uwep->otyp == FLAIL || uwep->otyp == AKLYS
+#ifdef KOPS
+          || uwep->otyp == RUBBER_HOSE
+#endif
+         ) {
+           You_cant("force anything without a %sweapon.",
+                 (uwep) ? "proper " : "");
+           return(0);
+       }
+
+       picktyp = is_blade(uwep);
+       if(xlock.usedtime && xlock.box && picktyp == xlock.picktyp) {
+           You("resume your attempt to force the lock.");
+           set_occupation(forcelock, "forcing the lock", 0);
+           return(1);
+       }
+
+       /* A lock is made only for the honest man, the thief will break it. */
+       xlock.box = (struct obj *)0;
+       for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere)
+           if(Is_box(otmp)) {
+               if (otmp->obroken || !otmp->olocked) {
+                   There("is %s here, but its lock is already %s.",
+                         doname(otmp), otmp->obroken ? "broken" : "unlocked");
+                   continue;
+               }
+               Sprintf(qbuf,"There is %s here, force its lock?",
+                       safe_qbuf("", sizeof("There is  here, force its lock?"),
+                               doname(otmp), an(simple_typename(otmp->otyp)),
+                               "a box"));
+
+               c = ynq(qbuf);
+               if(c == 'q') return(0);
+               if(c == 'n') continue;
+
+               if(picktyp)
+                   You("force your %s into a crack and pry.", xname(uwep));
+               else
+                   You("start bashing it with your %s.", xname(uwep));
+               xlock.box = otmp;
+               xlock.chance = objects[uwep->otyp].oc_wldam * 2;
+               xlock.picktyp = picktyp;
+               xlock.usedtime = 0;
+               break;
+           }
+
+       if(xlock.box)   set_occupation(forcelock, "forcing the lock", 0);
+       else            You("decide not to force the issue.");
+       return(1);
+}
+
+int
+doopen()               /* try to open a door */
+{
+       coord cc;
+       register struct rm *door;
+       struct monst *mtmp;
+
+       if (nohands(youmonst.data)) {
+           You_cant("open anything -- you have no hands!");
+           return 0;
+       }
+
+       if (u.utrap && u.utraptype == TT_PIT) {
+           You_cant("reach over the edge of the pit.");
+           return 0;
+       }
+
+       if(!get_adjacent_loc((char *)0, (char *)0, u.ux, u.uy, &cc)) return(0);
+
+       if((cc.x == u.ux) && (cc.y == u.uy)) return(0);
+
+       if ((mtmp = m_at(cc.x,cc.y))                    &&
+               mtmp->m_ap_type == M_AP_FURNITURE       &&
+               (mtmp->mappearance == S_hcdoor ||
+                       mtmp->mappearance == S_vcdoor)  &&
+               !Protection_from_shape_changers)         {
+
+           stumble_onto_mimic(mtmp);
+           return(1);
+       }
+
+       door = &levl[cc.x][cc.y];
+
+       if(!IS_DOOR(door->typ)) {
+               if (is_db_wall(cc.x,cc.y)) {
+                   There("is no obvious way to open the drawbridge.");
+                   return(0);
+               }
+               You("%s no door there.",
+                               Blind ? "feel" : "see");
+               return(0);
+       }
+
+       if (!(door->doormask & D_CLOSED)) {
+           const char *mesg;
+
+           switch (door->doormask) {
+           case D_BROKEN: mesg = " is broken"; break;
+           case D_NODOOR: mesg = "way has no door"; break;
+           case D_ISOPEN: mesg = " is already open"; break;
+           default:       mesg = " is locked"; break;
+           }
+           pline("This door%s.", mesg);
+           if (Blind) feel_location(cc.x,cc.y);
+           return(0);
+       }
+
+       if(verysmall(youmonst.data)) {
+           pline("You're too small to pull the door open.");
+           return(0);
+       }
+
+       /* door is known to be CLOSED */
+       if (rnl(20) < (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3) {
+           pline_The("door opens.");
+           if(door->doormask & D_TRAPPED) {
+               b_trapped("door", FINGER);
+               door->doormask = D_NODOOR;
+               if (*in_rooms(cc.x, cc.y, SHOPBASE)) add_damage(cc.x, cc.y, 0L);
+           } else
+               door->doormask = D_ISOPEN;
+           if (Blind)
+               feel_location(cc.x,cc.y);       /* the hero knows she opened it  */
+           else
+               newsym(cc.x,cc.y);
+           unblock_point(cc.x,cc.y);           /* vision: new see through there */
+       } else {
+           exercise(A_STR, TRUE);
+           pline_The("door resists!");
+       }
+
+       return(1);
+}
+
+STATIC_OVL
+boolean
+obstructed(x,y)
+register int x, y;
+{
+       register struct monst *mtmp = m_at(x, y);
+
+       if(mtmp && mtmp->m_ap_type != M_AP_FURNITURE) {
+               if (mtmp->m_ap_type == M_AP_OBJECT) goto objhere;
+               pline("%s stands in the way!", !canspotmon(mtmp) ?
+                       "Some creature" : Monnam(mtmp));
+               if (!canspotmon(mtmp))
+                   map_invisible(mtmp->mx, mtmp->my);
+               return(TRUE);
+       }
+       if (OBJ_AT(x, y)) {
+objhere:       pline("%s's in the way.", Something);
+               return(TRUE);
+       }
+       return(FALSE);
+}
+
+int
+doclose()              /* try to close a door */
+{
+       register int x, y;
+       register struct rm *door;
+       struct monst *mtmp;
+
+       if (nohands(youmonst.data)) {
+           You_cant("close anything -- you have no hands!");
+           return 0;
+       }
+
+       if (u.utrap && u.utraptype == TT_PIT) {
+           You_cant("reach over the edge of the pit.");
+           return 0;
+       }
+
+       if(!getdir((char *)0)) return(0);
+
+       x = u.ux + u.dx;
+       y = u.uy + u.dy;
+       if((x == u.ux) && (y == u.uy)) {
+               You("are in the way!");
+               return(1);
+       }
+
+       if ((mtmp = m_at(x,y))                          &&
+               mtmp->m_ap_type == M_AP_FURNITURE       &&
+               (mtmp->mappearance == S_hcdoor ||
+                       mtmp->mappearance == S_vcdoor)  &&
+               !Protection_from_shape_changers)         {
+
+           stumble_onto_mimic(mtmp);
+           return(1);
+       }
+
+       door = &levl[x][y];
+
+       if(!IS_DOOR(door->typ)) {
+               if (door->typ == DRAWBRIDGE_DOWN)
+                   There("is no obvious way to close the drawbridge.");
+               else
+                   You("%s no door there.",
+                               Blind ? "feel" : "see");
+               return(0);
+       }
+
+       if(door->doormask == D_NODOOR) {
+           pline("This doorway has no door.");
+           return(0);
+       }
+
+       if(obstructed(x, y)) return(0);
+
+       if(door->doormask == D_BROKEN) {
+           pline("This door is broken.");
+           return(0);
+       }
+
+       if(door->doormask & (D_CLOSED | D_LOCKED)) {
+           pline("This door is already closed.");
+           return(0);
+       }
+
+       if(door->doormask == D_ISOPEN) {
+           if(verysmall(youmonst.data)
+#ifdef STEED
+               && !u.usteed
+#endif
+               ) {
+                pline("You're too small to push the door closed.");
+                return(0);
+           }
+           if (
+#ifdef STEED
+                u.usteed ||
+#endif
+               rn2(25) < (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3) {
+               pline_The("door closes.");
+               door->doormask = D_CLOSED;
+               if (Blind)
+                   feel_location(x,y); /* the hero knows she closed it */
+               else
+                   newsym(x,y);
+               block_point(x,y);       /* vision:  no longer see there */
+           }
+           else {
+               exercise(A_STR, TRUE);
+               pline_The("door resists!");
+           }
+       }
+
+       return(1);
+}
+
+boolean                        /* box obj was hit with spell effect otmp */
+boxlock(obj, otmp)     /* returns true if something happened */
+register struct obj *obj, *otmp;       /* obj *is* a box */
+{
+       register boolean res = 0;
+
+       switch(otmp->otyp) {
+       case WAN_LOCKING:
+       case SPE_WIZARD_LOCK:
+           if (!obj->olocked) {        /* lock it; fix if broken */
+               pline("Klunk!");
+               obj->olocked = 1;
+               obj->obroken = 0;
+               res = 1;
+           } /* else already closed and locked */
+           break;
+       case WAN_OPENING:
+       case SPE_KNOCK:
+           if (obj->olocked) {         /* unlock; couldn't be broken */
+               pline("Klick!");
+               obj->olocked = 0;
+               res = 1;
+           } else                      /* silently fix if broken */
+               obj->obroken = 0;
+           break;
+       case WAN_POLYMORPH:
+       case SPE_POLYMORPH:
+           /* maybe start unlocking chest, get interrupted, then zap it;
+              we must avoid any attempt to resume unlocking it */
+           if (xlock.box == obj)
+               reset_pick();
+           break;
+       }
+       return res;
+}
+
+boolean                        /* Door/secret door was hit with spell effect otmp */
+doorlock(otmp,x,y)     /* returns true if something happened */
+struct obj *otmp;
+int x, y;
+{
+       register struct rm *door = &levl[x][y];
+       boolean res = TRUE;
+       int loudness = 0;
+       const char *msg = (const char *)0;
+       const char *dustcloud = "A cloud of dust";
+       const char *quickly_dissipates = "quickly dissipates";
+       
+       if (door->typ == SDOOR) {
+           switch (otmp->otyp) {
+           case WAN_OPENING:
+           case SPE_KNOCK:
+           case WAN_STRIKING:
+           case SPE_FORCE_BOLT:
+               door->typ = DOOR;
+               door->doormask = D_CLOSED | (door->doormask & D_TRAPPED);
+               newsym(x,y);
+               if (cansee(x,y)) pline("A door appears in the wall!");
+               if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK)
+                   return TRUE;
+               break;          /* striking: continue door handling below */
+           case WAN_LOCKING:
+           case SPE_WIZARD_LOCK:
+           default:
+               return FALSE;
+           }
+       }
+
+       switch(otmp->otyp) {
+       case WAN_LOCKING:
+       case SPE_WIZARD_LOCK:
+#ifdef REINCARNATION
+           if (Is_rogue_level(&u.uz)) {
+               boolean vis = cansee(x,y);
+               /* Can't have real locking in Rogue, so just hide doorway */
+               if (vis) pline("%s springs up in the older, more primitive doorway.",
+                       dustcloud);
+               else
+                       You_hear("a swoosh.");
+               if (obstructed(x,y)) {
+                       if (vis) pline_The("cloud %s.",quickly_dissipates);
+                       return FALSE;
+               }
+               block_point(x, y);
+               door->typ = SDOOR;
+               if (vis) pline_The("doorway vanishes!");
+               newsym(x,y);
+               return TRUE;
+           }
+#endif
+           if (obstructed(x,y)) return FALSE;
+           /* Don't allow doors to close over traps.  This is for pits */
+           /* & trap doors, but is it ever OK for anything else? */
+           if (t_at(x,y)) {
+               /* maketrap() clears doormask, so it should be NODOOR */
+               pline(
+               "%s springs up in the doorway, but %s.",
+               dustcloud, quickly_dissipates);
+               return FALSE;
+           }
+
+           switch (door->doormask & ~D_TRAPPED) {
+           case D_CLOSED:
+               msg = "The door locks!";
+               break;
+           case D_ISOPEN:
+               msg = "The door swings shut, and locks!";
+               break;
+           case D_BROKEN:
+               msg = "The broken door reassembles and locks!";
+               break;
+           case D_NODOOR:
+               msg =
+               "A cloud of dust springs up and assembles itself into a door!";
+               break;
+           default:
+               res = FALSE;
+               break;
+           }
+           block_point(x, y);
+           door->doormask = D_LOCKED | (door->doormask & D_TRAPPED);
+           newsym(x,y);
+           break;
+       case WAN_OPENING:
+       case SPE_KNOCK:
+           if (door->doormask & D_LOCKED) {
+               msg = "The door unlocks!";
+               door->doormask = D_CLOSED | (door->doormask & D_TRAPPED);
+           } else res = FALSE;
+           break;
+       case WAN_STRIKING:
+       case SPE_FORCE_BOLT:
+           if (door->doormask & (D_LOCKED | D_CLOSED)) {
+               if (door->doormask & D_TRAPPED) {
+                   if (MON_AT(x, y))
+                       (void) mb_trapped(m_at(x,y));
+                   else if (flags.verbose) {
+                       if (cansee(x,y))
+                           pline("KABOOM!!  You see a door explode.");
+                       else if (flags.soundok)
+                           You_hear("a distant explosion.");
+                   }
+                   door->doormask = D_NODOOR;
+                   unblock_point(x,y);
+                   newsym(x,y);
+                   loudness = 40;
+                   break;
+               }
+               door->doormask = D_BROKEN;
+               if (flags.verbose) {
+                   if (cansee(x,y))
+                       pline_The("door crashes open!");
+                   else if (flags.soundok)
+                       You_hear("a crashing sound.");
+               }
+               unblock_point(x,y);
+               newsym(x,y);
+               /* force vision recalc before printing more messages */
+               if (vision_full_recalc) vision_recalc(0);
+               loudness = 20;
+           } else res = FALSE;
+           break;
+       default: impossible("magic (%d) attempted on door.", otmp->otyp);
+           break;
+       }
+       if (msg && cansee(x,y)) pline(msg);
+       if (loudness > 0) {
+           /* door was destroyed */
+           wake_nearto(x, y, loudness);
+           if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L);
+       }
+
+       if (res && picking_at(x, y)) {
+           /* maybe unseen monster zaps door you're unlocking */
+           stop_occupation();
+           reset_pick();
+       }
+       return res;
+}
+
+STATIC_OVL void
+chest_shatter_msg(otmp)
+struct obj *otmp;
+{
+       const char *disposition;
+       const char *thing;
+       long save_Blinded;
+
+       if (otmp->oclass == POTION_CLASS) {
+               You("%s %s shatter!", Blind ? "hear" : "see", an(bottlename()));
+               if (!breathless(youmonst.data) || haseyes(youmonst.data))
+                       potionbreathe(otmp);
+               return;
+       }
+       /* We have functions for distant and singular names, but not one */
+       /* which does _both_... */
+       save_Blinded = Blinded;
+       Blinded = 1;
+       thing = singular(otmp, xname);
+       Blinded = save_Blinded;
+       switch (objects[otmp->otyp].oc_material) {
+       case PAPER:     disposition = "is torn to shreds";
+               break;
+       case WAX:       disposition = "is crushed";
+               break;
+       case VEGGY:     disposition = "is pulped";
+               break;
+       case FLESH:     disposition = "is mashed";
+               break;
+       case GLASS:     disposition = "shatters";
+               break;
+       case WOOD:      disposition = "splinters to fragments";
+               break;
+       default:        disposition = "is destroyed";
+               break;
+       }
+       pline("%s %s!", An(thing), disposition);
+}
+
+#endif /* OVLB */
+
+/*lock.c*/
diff --git a/src/mail.c b/src/mail.c
new file mode 100644 (file)
index 0000000..99d7637
--- /dev/null
@@ -0,0 +1,625 @@
+/*     SCCS Id: @(#)mail.c     3.4     2002/01/13      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+#ifdef MAIL
+#include "mail.h"
+
+/*
+ * Notify user when new mail has arrived.  Idea by Merlyn Leroy.
+ *
+ * The mail daemon can move with less than usual restraint.  It can:
+ *     - move diagonally from a door
+ *     - use secret and closed doors
+ *     - run through a monster ("Gangway!", etc.)
+ *     - run over pools & traps
+ *
+ * Possible extensions:
+ *     - Open the file MAIL and do fstat instead of stat for efficiency.
+ *       (But sh uses stat, so this cannot be too bad.)
+ *     - Examine the mail and produce a scroll of mail named "From somebody".
+ *     - Invoke MAILREADER in such a way that only this single letter is read.
+ *     - Do something to the text when the scroll is enchanted or cancelled.
+ *     - Make the daemon always appear at a stairwell, and have it find a
+ *       path to the hero.
+ *
+ * Note by Olaf Seibert: On the Amiga, we usually don't get mail.  So we go
+ *                      through most of the effects at 'random' moments.
+ * Note by Paul Winner:  The MSDOS port also 'fakes' the mail daemon at
+ *                      random intervals.
+ */
+
+STATIC_DCL boolean FDECL(md_start,(coord *));
+STATIC_DCL boolean FDECL(md_stop,(coord *, coord *));
+STATIC_DCL boolean FDECL(md_rush,(struct monst *,int,int));
+STATIC_DCL void FDECL(newmail, (struct mail_info *));
+
+extern char *viz_rmin, *viz_rmax;      /* line-of-sight limits (vision.c) */
+
+#ifdef OVL0
+
+# if !defined(UNIX) && !defined(VMS) && !defined(LAN_MAIL)
+int mustgetmail = -1;
+# endif
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+# ifdef UNIX
+#include <sys/stat.h>
+#include <pwd.h>
+/* DON'T trust all Unices to declare getpwuid() in <pwd.h> */
+#  if !defined(_BULL_SOURCE) && !defined(__sgi) && !defined(_M_UNIX)
+#   if !defined(SUNOS4) && !(defined(ULTRIX) && defined(__GNUC__))
+/* DO trust all SVR4 to typedef uid_t in <sys/types.h> (probably to a long) */
+#    if defined(POSIX_TYPES) || defined(SVR4) || defined(HPUX)
+extern struct passwd *FDECL(getpwuid,(uid_t));
+#    else
+extern struct passwd *FDECL(getpwuid,(int));
+#    endif
+#   endif
+#  endif
+static struct stat omstat,nmstat;
+static char *mailbox = (char *)0;
+static long laststattime;
+
+# if !defined(MAILPATH) && defined(AMS)        /* Just a placeholder for AMS */
+#  define MAILPATH "/dev/null"
+# endif
+# if !defined(MAILPATH) && (defined(LINUX) || defined(__osf__))
+#  define MAILPATH "/var/spool/mail/"
+# endif
+# if !defined(MAILPATH) && defined(__FreeBSD__)
+#  define MAILPATH "/var/mail/"
+# endif
+# if !defined(MAILPATH) && (defined(BSD) || defined(ULTRIX))
+#  define MAILPATH "/usr/spool/mail/"
+# endif
+# if !defined(MAILPATH) && (defined(SYSV) || defined(HPUX))
+#  define MAILPATH "/usr/mail/"
+# endif
+
+void
+getmailstatus()
+{
+       if(!mailbox && !(mailbox = nh_getenv("MAIL"))) {
+#  ifdef MAILPATH
+#   ifdef AMS
+               struct passwd ppasswd;
+
+               (void) memcpy(&ppasswd, getpwuid(getuid()), sizeof(struct passwd));
+               if (ppasswd.pw_dir) {
+                    mailbox = (char *) alloc((unsigned) strlen(ppasswd.pw_dir)+sizeof(AMS_MAILBOX));
+                    Strcpy(mailbox, ppasswd.pw_dir);
+                    Strcat(mailbox, AMS_MAILBOX);
+               } else
+                 return;
+#   else
+               const char *pw_name = getpwuid(getuid())->pw_name;
+               mailbox = (char *) alloc(sizeof(MAILPATH)+strlen(pw_name));
+               Strcpy(mailbox, MAILPATH);
+               Strcat(mailbox, pw_name);
+#  endif /* AMS */
+#  else
+               return;
+#  endif
+       }
+       if(stat(mailbox, &omstat)){
+#  ifdef PERMANENT_MAILBOX
+               pline("Cannot get status of MAIL=\"%s\".", mailbox);
+               mailbox = 0;
+#  else
+               omstat.st_mtime = 0;
+#  endif
+       }
+}
+# endif /* UNIX */
+
+#endif /* OVLB */
+#ifdef OVL0
+
+/*
+ * Pick coordinates for a starting position for the mail daemon.  Called
+ * from newmail() and newphone().
+ */
+STATIC_OVL boolean
+md_start(startp)
+    coord *startp;
+{
+    coord testcc;      /* scratch coordinates */
+    int row;           /* current row we are checking */
+    int lax;           /* if TRUE, pick a position in sight. */
+    int dd;            /* distance to current point */
+    int max_distance;  /* max distance found so far */
+
+    /*
+     * If blind and not telepathic, then it doesn't matter what we pick ---
+     * the hero is not going to see it anyway.  So pick a nearby position.
+     */
+    if (Blind && !Blind_telepat) {
+       if (!enexto(startp, u.ux, u.uy, (struct permonst *) 0))
+           return FALSE;       /* no good posiitons */
+       return TRUE;
+    }
+
+    /*
+     * Arrive at an up or down stairwell if it is in line of sight from the
+     * hero.
+     */
+    if (couldsee(upstair.sx, upstair.sy)) {
+       startp->x = upstair.sx;
+       startp->y = upstair.sy;
+       return TRUE;
+    }
+    if (couldsee(dnstair.sx, dnstair.sy)) {
+       startp->x = dnstair.sx;
+       startp->y = dnstair.sy;
+       return TRUE;
+    }
+
+    /*
+     * Try to pick a location out of sight next to the farthest position away
+     * from the hero.  If this fails, try again, just picking the farthest
+     * position that could be seen.  What we really ought to be doing is
+     * finding a path from a stairwell...
+     *
+     * The arrays viz_rmin[] and viz_rmax[] are set even when blind.  These
+     * are the LOS limits for each row.
+     */
+    lax = 0;   /* be picky */
+    max_distance = -1;
+retry:
+    for (row = 0; row < ROWNO; row++) {
+       if (viz_rmin[row] < viz_rmax[row]) {
+           /* There are valid positions on this row. */
+           dd = distu(viz_rmin[row],row);
+           if (dd > max_distance) {
+               if (lax) {
+                   max_distance = dd;
+                   startp->y = row;
+                   startp->x = viz_rmin[row];
+               
+               } else if (enexto(&testcc, (xchar)viz_rmin[row], row,
+                                               (struct permonst *) 0) &&
+                          !cansee(testcc.x, testcc.y) &&
+                          couldsee(testcc.x, testcc.y)) {
+                   max_distance = dd;
+                   *startp = testcc;
+               }
+           }
+           dd = distu(viz_rmax[row],row);
+           if (dd > max_distance) {
+               if (lax) {
+                   max_distance = dd;
+                   startp->y = row;
+                   startp->x = viz_rmax[row];
+               
+               } else if (enexto(&testcc, (xchar)viz_rmax[row], row,
+                                               (struct permonst *) 0) &&
+                          !cansee(testcc.x,testcc.y) &&
+                          couldsee(testcc.x, testcc.y)) {
+
+                   max_distance = dd;
+                   *startp = testcc;
+               }
+           }
+       }
+    }
+
+    if (max_distance < 0) {
+       if (!lax) {
+           lax = 1;            /* just find a position */
+           goto retry;
+       }
+       return FALSE;
+    }
+
+    return TRUE;
+}
+
+/*
+ * Try to choose a stopping point as near as possible to the starting
+ * position while still adjacent to the hero.  If all else fails, try
+ * enexto().  Use enexto() as a last resort because enexto() chooses
+ * its point randomly, which is not what we want.
+ */
+STATIC_OVL boolean
+md_stop(stopp, startp)
+    coord *stopp;      /* stopping position (we fill it in) */
+    coord *startp;     /* starting positon (read only) */
+{
+    int x, y, distance, min_distance = -1;
+
+    for (x = u.ux-1; x <= u.ux+1; x++)
+       for (y = u.uy-1; y <= u.uy+1; y++) {
+           if (!isok(x, y) || (x == u.ux && y == u.uy)) continue;
+
+           if (ACCESSIBLE(levl[x][y].typ) && !MON_AT(x,y)) {
+               distance = dist2(x,y,startp->x,startp->y);
+               if (min_distance < 0 || distance < min_distance ||
+                       (distance == min_distance && rn2(2))) {
+                   stopp->x = x;
+                   stopp->y = y;
+                   min_distance = distance;
+               }
+           }
+       }
+
+    /* If we didn't find a good spot, try enexto(). */
+    if (min_distance < 0 &&
+               !enexto(stopp, u.ux, u.uy, &mons[PM_MAIL_DAEMON]))
+       return FALSE;
+
+    return TRUE;
+}
+
+/* Let the mail daemon have a larger vocabulary. */
+static NEARDATA const char *mail_text[] = {
+    "Gangway!",
+    "Look out!",
+    "Pardon me!"
+};
+#define md_exclamations()      (mail_text[rn2(3)])
+
+/*
+ * Make the mail daemon run through the dungeon.  The daemon will run over
+ * any monsters that are in its path, but will replace them later.  Return
+ * FALSE if the md gets stuck in a position where there is a monster.  Return
+ * TRUE otherwise.
+ */
+STATIC_OVL boolean
+md_rush(md,tx,ty)
+    struct monst *md;
+    register int tx, ty;               /* destination of mail daemon */
+{
+    struct monst *mon;                 /* displaced monster */
+    register int dx, dy;               /* direction counters */
+    int fx = md->mx, fy = md->my;      /* current location */
+    int nfx = fx, nfy = fy,            /* new location */
+       d1, d2;                         /* shortest distances */
+
+    /*
+     * It is possible that the monster at (fx,fy) is not the md when:
+     * the md rushed the hero and failed, and is now starting back.
+     */
+    if (m_at(fx, fy) == md) {
+       remove_monster(fx, fy);         /* pick up from orig position */
+       newsym(fx, fy);
+    }
+
+    /*
+     * At the beginning and exit of this loop, md is not placed in the
+     * dungeon.
+     */
+    while (1) {
+       /* Find a good location next to (fx,fy) closest to (tx,ty). */
+       d1 = dist2(fx,fy,tx,ty);
+       for (dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++)
+           if ((dx || dy) && isok(fx+dx,fy+dy) &&
+                                      !IS_STWALL(levl[fx+dx][fy+dy].typ)) {
+               d2 = dist2(fx+dx,fy+dy,tx,ty);
+               if (d2 < d1) {
+                   d1 = d2;
+                   nfx = fx+dx;
+                   nfy = fy+dy;
+               }
+           }
+
+       /* Break if the md couldn't find a new position. */
+       if (nfx == fx && nfy == fy) break;
+
+       fx = nfx;                       /* this is our new position */
+       fy = nfy;
+
+       /* Break if the md reaches its destination. */
+       if (fx == tx && fy == ty) break;
+
+       if ((mon = m_at(fx,fy)) != 0)   /* save monster at this position */
+           verbalize(md_exclamations());
+       else if (fx == u.ux && fy == u.uy)
+           verbalize("Excuse me.");
+
+       place_monster(md,fx,fy);        /* put md down */
+       newsym(fx,fy);                  /* see it */
+       flush_screen(0);                /* make sure md shows up */
+       delay_output();                 /* wait a little bit */
+
+       /* Remove md from the dungeon.  Restore original mon, if necessary. */
+       if (mon) {
+           if ((mon->mx != fx) || (mon->my != fy))
+               place_worm_seg(mon, fx, fy);
+           else
+               place_monster(mon, fx, fy);
+       } else
+           remove_monster(fx, fy);
+       newsym(fx,fy);
+    }
+
+    /*
+     * Check for a monster at our stopping position (this is possible, but
+     * very unlikely).  If one exists, then have the md leave in disgust.
+     */
+    if ((mon = m_at(fx, fy)) != 0) {
+       place_monster(md, fx, fy);      /* display md with text below */
+       newsym(fx, fy);
+       verbalize("This place's too crowded.  I'm outta here.");
+
+       if ((mon->mx != fx) || (mon->my != fy)) /* put mon back */
+           place_worm_seg(mon, fx, fy);
+       else
+           place_monster(mon, fx, fy);
+
+       newsym(fx, fy);
+       return FALSE;
+    }
+
+    place_monster(md, fx, fy); /* place at final spot */
+    newsym(fx, fy);
+    flush_screen(0);
+    delay_output();                    /* wait a little bit */
+
+    return TRUE;
+}
+
+/* Deliver a scroll of mail. */
+/*ARGSUSED*/
+STATIC_OVL void
+newmail(info)
+struct mail_info *info;
+{
+    struct monst *md;
+    coord start, stop;
+    boolean message_seen = FALSE;
+
+    /* Try to find good starting and stopping places. */
+    if (!md_start(&start) || !md_stop(&stop,&start)) goto give_up;
+
+    /* Make the daemon.  Have it rush towards the hero. */
+    if (!(md = makemon(&mons[PM_MAIL_DAEMON], start.x, start.y, NO_MM_FLAGS)))
+        goto give_up;
+    if (!md_rush(md, stop.x, stop.y)) goto go_back;
+
+    message_seen = TRUE;
+    verbalize("%s, %s!  %s.", Hello(md), plname, info->display_txt);
+
+    if (info->message_typ) {
+       struct obj *obj = mksobj(SCR_MAIL, FALSE, FALSE);
+       if (distu(md->mx,md->my) > 2)
+           verbalize("Catch!");
+       display_nhwindow(WIN_MESSAGE, FALSE);
+       if (info->object_nam) {
+           obj = oname(obj, info->object_nam);
+           if (info->response_cmd) {   /*(hide extension of the obj name)*/
+               int namelth = info->response_cmd - info->object_nam - 1;
+               if ( namelth <= 0 || namelth >= (int) obj->onamelth )
+                   impossible("mail delivery screwed up");
+               else
+                   *(ONAME(obj) + namelth) = '\0';
+               /* Note: renaming object will discard the hidden command. */
+           }
+       }
+       obj = hold_another_object(obj, "Oops!",
+                                 (const char *)0, (const char *)0);
+    }
+
+    /* zip back to starting location */
+go_back:
+    (void) md_rush(md, start.x, start.y);
+    mongone(md);
+    /* deliver some classes of messages even if no daemon ever shows up */
+give_up:
+    if (!message_seen && info->message_typ == MSG_OTHER)
+       pline("Hark!  \"%s.\"", info->display_txt);
+}
+
+# if !defined(UNIX) && !defined(VMS) && !defined(LAN_MAIL)
+
+void
+ckmailstatus()
+{
+       if (u.uswallow || !flags.biff) return;
+       if (mustgetmail < 0) {
+#if defined(AMIGA) || defined(MSDOS) || defined(TOS)
+           mustgetmail=(moves<2000)?(100+rn2(2000)):(2000+rn2(3000));
+#endif
+           return;
+       }
+       if (--mustgetmail <= 0) {
+               static struct mail_info
+                       deliver = {MSG_MAIL,"I have some mail for you",0,0};
+               newmail(&deliver);
+               mustgetmail = -1;
+       }
+}
+
+/*ARGSUSED*/
+void
+readmail(otmp)
+struct obj *otmp;
+{
+    static char *junk[] = {
+    "Please disregard previous letter.",
+    "Welcome to NetHack.",
+#ifdef AMIGA
+    "Only Amiga makes it possible.",
+    "CATS have all the answers.",
+#endif
+    "Report bugs to <devteam@nethack.org>.",
+    "Invitation: Visit the NetHack web site at http://www.nethack.org!"
+    };
+
+    if (Blind) {
+       pline("Unfortunately you cannot see what it says.");
+    } else
+       pline("It reads:  \"%s\"", junk[rn2(SIZE(junk))]);
+
+}
+
+# endif /* !UNIX && !VMS && !LAN_MAIL */
+
+# ifdef UNIX
+
+void
+ckmailstatus()
+{
+       if(!mailbox || u.uswallow || !flags.biff
+#  ifdef MAILCKFREQ
+                   || moves < laststattime + MAILCKFREQ
+#  endif
+                                                       )
+               return;
+
+       laststattime = moves;
+       if(stat(mailbox, &nmstat)){
+#  ifdef PERMANENT_MAILBOX
+               pline("Cannot get status of MAIL=\"%s\" anymore.", mailbox);
+               mailbox = 0;
+#  else
+               nmstat.st_mtime = 0;
+#  endif
+       } else if(nmstat.st_mtime > omstat.st_mtime) {
+               if (nmstat.st_size) {
+                   static struct mail_info deliver = {
+#  ifndef NO_MAILREADER
+                       MSG_MAIL, "I have some mail for you",
+#  else
+                       /* suppress creation and delivery of scroll of mail */
+                       MSG_OTHER, "You have some mail in the outside world",
+#  endif
+                       0, 0
+                   };
+                   newmail(&deliver);
+               }
+               getmailstatus();        /* might be too late ... */
+       }
+}
+
+/*ARGSUSED*/
+void
+readmail(otmp)
+struct obj *otmp;
+{
+#  ifdef DEF_MAILREADER                        /* This implies that UNIX is defined */
+       register const char *mr = 0;
+
+       display_nhwindow(WIN_MESSAGE, FALSE);
+       if(!(mr = nh_getenv("MAILREADER")))
+               mr = DEF_MAILREADER;
+
+       if(child(1)){
+               (void) execl(mr, mr, (char *)0);
+               terminate(EXIT_FAILURE);
+       }
+#  else
+#   ifndef AMS                         /* AMS mailboxes are directories */
+       display_file(mailbox, TRUE);
+#   endif /* AMS */
+#  endif /* DEF_MAILREADER */
+
+       /* get new stat; not entirely correct: there is a small time
+          window where we do not see new mail */
+       getmailstatus();
+}
+
+# endif /* UNIX */
+
+# ifdef VMS
+
+extern NDECL(struct mail_info *parse_next_broadcast);
+
+volatile int broadcasts = 0;
+
+void
+ckmailstatus()
+{
+    struct mail_info *brdcst;
+
+    if (u.uswallow || !flags.biff) return;
+
+    while (broadcasts > 0) {   /* process all trapped broadcasts [until] */
+       broadcasts--;
+       if ((brdcst = parse_next_broadcast()) != 0) {
+           newmail(brdcst);
+           break;              /* only handle one real message at a time */
+       }
+    }
+}
+
+void
+readmail(otmp)
+struct obj *otmp;
+{
+#  ifdef SHELL /* can't access mail reader without spawning subprocess */
+    const char *txt, *cmd;
+    char *p, buf[BUFSZ], qbuf[BUFSZ];
+    int len;
+
+    /* there should be a command hidden beyond the object name */
+    txt = otmp->onamelth ? ONAME(otmp) : "";
+    len = strlen(txt);
+    cmd = (len + 1 < otmp->onamelth) ? txt + len + 1 : (char *) 0;
+    if (!cmd || !*cmd) cmd = "SPAWN";
+
+    Sprintf(qbuf, "System command (%s)", cmd);
+    getlin(qbuf, buf);
+    if (*buf != '\033') {
+       for (p = eos(buf); p > buf; *p = '\0')
+           if (*--p != ' ') break;     /* strip trailing spaces */
+       if (*buf) cmd = buf;            /* use user entered command */
+       if (!strcmpi(cmd, "SPAWN") || !strcmp(cmd, "!"))
+           cmd = (char *) 0;           /* interactive escape */
+
+       vms_doshell(cmd, TRUE);
+       (void) sleep(1);
+    }
+#  endif /* SHELL */
+}
+
+# endif /* VMS */
+
+# ifdef LAN_MAIL
+
+void
+ckmailstatus()
+{
+       static int laststattime = 0;
+       
+       if(u.uswallow || !flags.biff
+#  ifdef MAILCKFREQ
+                   || moves < laststattime + MAILCKFREQ
+#  endif
+                                                       )
+               return;
+
+       laststattime = moves;
+       if (lan_mail_check()) {
+                   static struct mail_info deliver = {
+#  ifndef NO_MAILREADER
+                       MSG_MAIL, "I have some mail for you",
+#  else
+                       /* suppress creation and delivery of scroll of mail */
+                       MSG_OTHER, "You have some mail in the outside world",
+#  endif
+                       0, 0
+                   };
+                   newmail(&deliver);
+       }
+}
+
+/*ARGSUSED*/
+void
+readmail(otmp)
+struct obj *otmp;
+{
+       lan_mail_read(otmp);
+}
+
+# endif /* LAN_MAIL */
+
+#endif /* OVL0 */
+
+#endif /* MAIL */
+
+/*mail.c*/
diff --git a/src/makemon.c b/src/makemon.c
new file mode 100644 (file)
index 0000000..89098dd
--- /dev/null
@@ -0,0 +1,1800 @@
+/*     SCCS Id: @(#)makemon.c  3.4     2003/09/06      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "epri.h"
+#include "emin.h"
+#include "edog.h"
+#ifdef REINCARNATION
+#include <ctype.h>
+#endif
+
+STATIC_VAR NEARDATA struct monst zeromonst;
+
+/* this assumes that a human quest leader or nemesis is an archetype
+   of the corresponding role; that isn't so for some roles (tourist
+   for instance) but is for the priests and monks we use it for... */
+#define quest_mon_represents_role(mptr,role_pm) \
+               (mptr->mlet == S_HUMAN && Role_if(role_pm) && \
+                 (mptr->msound == MS_LEADER || mptr->msound == MS_NEMESIS))
+
+#ifdef OVL0
+STATIC_DCL boolean FDECL(uncommon, (int));
+STATIC_DCL int FDECL(align_shift, (struct permonst *));
+#endif /* OVL0 */
+STATIC_DCL boolean FDECL(wrong_elem_type, (struct permonst *));
+STATIC_DCL void FDECL(m_initgrp,(struct monst *,int,int,int));
+STATIC_DCL void FDECL(m_initthrow,(struct monst *,int,int));
+STATIC_DCL void FDECL(m_initweap,(struct monst *));
+#ifdef OVL1
+STATIC_DCL void FDECL(m_initinv,(struct monst *));
+#endif /* OVL1 */
+
+extern const int monstr[];
+
+#define m_initsgrp(mtmp, x, y) m_initgrp(mtmp, x, y, 3)
+#define m_initlgrp(mtmp, x, y) m_initgrp(mtmp, x, y, 10)
+#define toostrong(monindx, lev) (monstr[monindx] > lev)
+#define tooweak(monindx, lev)  (monstr[monindx] < lev)
+
+#ifdef OVLB
+boolean
+is_home_elemental(ptr)
+register struct permonst *ptr;
+{
+       if (ptr->mlet == S_ELEMENTAL)
+           switch (monsndx(ptr)) {
+               case PM_AIR_ELEMENTAL: return Is_airlevel(&u.uz);
+               case PM_FIRE_ELEMENTAL: return Is_firelevel(&u.uz);
+               case PM_EARTH_ELEMENTAL: return Is_earthlevel(&u.uz);
+               case PM_WATER_ELEMENTAL: return Is_waterlevel(&u.uz);
+           }
+       return FALSE;
+}
+
+/*
+ * Return true if the given monster cannot exist on this elemental level.
+ */
+STATIC_OVL boolean
+wrong_elem_type(ptr)
+    register struct permonst *ptr;
+{
+    if (ptr->mlet == S_ELEMENTAL) {
+       return((boolean)(!is_home_elemental(ptr)));
+    } else if (Is_earthlevel(&u.uz)) {
+       /* no restrictions? */
+    } else if (Is_waterlevel(&u.uz)) {
+       /* just monsters that can swim */
+       if(!is_swimmer(ptr)) return TRUE;
+    } else if (Is_firelevel(&u.uz)) {
+       if (!pm_resistance(ptr,MR_FIRE)) return TRUE;
+    } else if (Is_airlevel(&u.uz)) {
+       if(!(is_flyer(ptr) && ptr->mlet != S_TRAPPER) && !is_floater(ptr)
+          && !amorphous(ptr) && !noncorporeal(ptr) && !is_whirly(ptr))
+           return TRUE;
+    }
+    return FALSE;
+}
+
+STATIC_OVL void
+m_initgrp(mtmp, x, y, n)       /* make a group just like mtmp */
+register struct monst *mtmp;
+register int x, y, n;
+{
+       coord mm;
+       register int cnt = rnd(n);
+       struct monst *mon;
+#if defined(__GNUC__) && (defined(HPUX) || defined(DGUX))
+       /* There is an unresolved problem with several people finding that
+        * the game hangs eating CPU; if interrupted and restored, the level
+        * will be filled with monsters.  Of those reports giving system type,
+        * there were two DG/UX and two HP-UX, all using gcc as the compiler.
+        * hcroft@hpopb1.cern.ch, using gcc 2.6.3 on HP-UX, says that the
+        * problem went away for him and another reporter-to-newsgroup
+        * after adding this debugging code.  This has almost got to be a
+        * compiler bug, but until somebody tracks it down and gets it fixed,
+        * might as well go with the "but it went away when I tried to find
+        * it" code.
+        */
+       int cnttmp,cntdiv;
+
+       cnttmp = cnt;
+# ifdef DEBUG
+       pline("init group call x=%d,y=%d,n=%d,cnt=%d.", x, y, n, cnt);
+# endif
+       cntdiv = ((u.ulevel < 3) ? 4 : (u.ulevel < 5) ? 2 : 1);
+#endif
+       /* Tuning: cut down on swarming at low character levels [mrs] */
+       cnt /= (u.ulevel < 3) ? 4 : (u.ulevel < 5) ? 2 : 1;
+#if defined(__GNUC__) && (defined(HPUX) || defined(DGUX))
+       if (cnt != (cnttmp/cntdiv)) {
+               pline("cnt=%d using %d, cnttmp=%d, cntdiv=%d", cnt,
+                       (u.ulevel < 3) ? 4 : (u.ulevel < 5) ? 2 : 1,
+                       cnttmp, cntdiv);
+       }
+#endif
+       if(!cnt) cnt++;
+#if defined(__GNUC__) && (defined(HPUX) || defined(DGUX))
+       if (cnt < 0) cnt = 1;
+       if (cnt > 10) cnt = 10;
+#endif
+
+       mm.x = x;
+       mm.y = y;
+       while(cnt--) {
+               if (peace_minded(mtmp->data)) continue;
+               /* Don't create groups of peaceful monsters since they'll get
+                * in our way.  If the monster has a percentage chance so some
+                * are peaceful and some are not, the result will just be a
+                * smaller group.
+                */
+               if (enexto(&mm, mm.x, mm.y, mtmp->data)) {
+                   mon = makemon(mtmp->data, mm.x, mm.y, NO_MM_FLAGS);
+                   mon->mpeaceful = FALSE;
+                   mon->mavenge = 0;
+                   set_malign(mon);
+                   /* Undo the second peace_minded() check in makemon(); if the
+                    * monster turned out to be peaceful the first time we
+                    * didn't create it at all; we don't want a second check.
+                    */
+               }
+       }
+}
+
+STATIC_OVL
+void
+m_initthrow(mtmp,otyp,oquan)
+struct monst *mtmp;
+int otyp,oquan;
+{
+       register struct obj *otmp;
+
+       otmp = mksobj(otyp, TRUE, FALSE);
+       otmp->quan = (long) rn1(oquan, 3);
+       otmp->owt = weight(otmp);
+       if (otyp == ORCISH_ARROW) otmp->opoisoned = TRUE;
+       (void) mpickobj(mtmp, otmp);
+}
+
+#endif /* OVLB */
+#ifdef OVL2
+
+STATIC_OVL void
+m_initweap(mtmp)
+register struct monst *mtmp;
+{
+       register struct permonst *ptr = mtmp->data;
+       register int mm = monsndx(ptr);
+       struct obj *otmp;
+
+#ifdef REINCARNATION
+       if (Is_rogue_level(&u.uz)) return;
+#endif
+/*
+ *     first a few special cases:
+ *
+ *             giants get a boulder to throw sometimes.
+ *             ettins get clubs
+ *             kobolds get darts to throw
+ *             centaurs get some sort of bow & arrows or bolts
+ *             soldiers get all sorts of things.
+ *             kops get clubs & cream pies.
+ */
+       switch (ptr->mlet) {
+           case S_GIANT:
+               if (rn2(2)) (void)mongets(mtmp, (mm != PM_ETTIN) ?
+                                   BOULDER : CLUB);
+               break;
+           case S_HUMAN:
+               if(is_mercenary(ptr)) {
+                   int w1 = 0, w2 = 0;
+                   switch (mm) {
+
+                       case PM_WATCHMAN:
+                       case PM_SOLDIER:
+                         if (!rn2(3)) {
+                             w1 = rn1(BEC_DE_CORBIN - PARTISAN + 1, PARTISAN);
+                             w2 = rn2(2) ? DAGGER : KNIFE;
+                         } else w1 = rn2(2) ? SPEAR : SHORT_SWORD;
+                         break;
+                       case PM_SERGEANT:
+                         w1 = rn2(2) ? FLAIL : MACE;
+                         break;
+                       case PM_LIEUTENANT:
+                         w1 = rn2(2) ? BROADSWORD : LONG_SWORD;
+                         break;
+                       case PM_CAPTAIN:
+                       case PM_WATCH_CAPTAIN:
+                         w1 = rn2(2) ? LONG_SWORD : SILVER_SABER;
+                         break;
+                       default:
+                         if (!rn2(4)) w1 = DAGGER;
+                         if (!rn2(7)) w2 = SPEAR;
+                         break;
+                   }
+                   if (w1) (void)mongets(mtmp, w1);
+                   if (!w2 && w1 != DAGGER && !rn2(4)) w2 = KNIFE;
+                   if (w2) (void)mongets(mtmp, w2);
+               } else if (is_elf(ptr)) {
+                   if (rn2(2))
+                       (void) mongets(mtmp,
+                                  rn2(2) ? ELVEN_MITHRIL_COAT : ELVEN_CLOAK);
+                   if (rn2(2)) (void)mongets(mtmp, ELVEN_LEATHER_HELM);
+                   else if (!rn2(4)) (void)mongets(mtmp, ELVEN_BOOTS);
+                   if (rn2(2)) (void)mongets(mtmp, ELVEN_DAGGER);
+                   switch (rn2(3)) {
+                       case 0:
+                           if (!rn2(4)) (void)mongets(mtmp, ELVEN_SHIELD);
+                           if (rn2(3)) (void)mongets(mtmp, ELVEN_SHORT_SWORD);
+                           (void)mongets(mtmp, ELVEN_BOW);
+                           m_initthrow(mtmp, ELVEN_ARROW, 12);
+                           break;
+                       case 1:
+                           (void)mongets(mtmp, ELVEN_BROADSWORD);
+                           if (rn2(2)) (void)mongets(mtmp, ELVEN_SHIELD);
+                           break;
+                       case 2:
+                           if (rn2(2)) {
+                               (void)mongets(mtmp, ELVEN_SPEAR);
+                               (void)mongets(mtmp, ELVEN_SHIELD);
+                           }
+                           break;
+                   }
+                   if (mm == PM_ELVENKING) {
+                       if (rn2(3) || (in_mklev && Is_earthlevel(&u.uz)))
+                           (void)mongets(mtmp, PICK_AXE);
+                       if (!rn2(50)) (void)mongets(mtmp, CRYSTAL_BALL);
+                   }
+               } else if (ptr->msound == MS_PRIEST ||
+                       quest_mon_represents_role(ptr,PM_PRIEST)) {
+                   otmp = mksobj(MACE, FALSE, FALSE);
+                   if(otmp) {
+                       otmp->spe = rnd(3);
+                       if(!rn2(2)) curse(otmp);
+                       (void) mpickobj(mtmp, otmp);
+                   }
+               }
+               break;
+
+           case S_ANGEL:
+               {
+                   int spe2;
+
+                   /* create minion stuff; can't use mongets */
+                   otmp = mksobj(LONG_SWORD, FALSE, FALSE);
+
+                   /* maybe make it special */
+                   if (!rn2(20) || is_lord(ptr))
+                       otmp = oname(otmp, artiname(
+                               rn2(2) ? ART_DEMONBANE : ART_SUNSWORD));
+                   bless(otmp);
+                   otmp->oerodeproof = TRUE;
+                   spe2 = rn2(4);
+                   otmp->spe = max(otmp->spe, spe2);
+                   (void) mpickobj(mtmp, otmp);
+
+                   otmp = mksobj(!rn2(4) || is_lord(ptr) ?
+                                 SHIELD_OF_REFLECTION : LARGE_SHIELD,
+                                 FALSE, FALSE);
+                   otmp->cursed = FALSE;
+                   otmp->oerodeproof = TRUE;
+                   otmp->spe = 0;
+                   (void) mpickobj(mtmp, otmp);
+               }
+               break;
+
+           case S_HUMANOID:
+               if (mm == PM_HOBBIT) {
+                   switch (rn2(3)) {
+                       case 0:
+                           (void)mongets(mtmp, DAGGER);
+                           break;
+                       case 1:
+                           (void)mongets(mtmp, ELVEN_DAGGER);
+                           break;
+                       case 2:
+                           (void)mongets(mtmp, SLING);
+                           break;
+                     }
+                   if (!rn2(10)) (void)mongets(mtmp, ELVEN_MITHRIL_COAT);
+                   if (!rn2(10)) (void)mongets(mtmp, DWARVISH_CLOAK);
+               } else if (is_dwarf(ptr)) {
+                   if (rn2(7)) (void)mongets(mtmp, DWARVISH_CLOAK);
+                   if (rn2(7)) (void)mongets(mtmp, IRON_SHOES);
+                   if (!rn2(4)) {
+                       (void)mongets(mtmp, DWARVISH_SHORT_SWORD);
+                       /* note: you can't use a mattock with a shield */
+                       if (rn2(2)) (void)mongets(mtmp, DWARVISH_MATTOCK);
+                       else {
+                               (void)mongets(mtmp, AXE);
+                               (void)mongets(mtmp, DWARVISH_ROUNDSHIELD);
+                       }
+                       (void)mongets(mtmp, DWARVISH_IRON_HELM);
+                       if (!rn2(3))
+                           (void)mongets(mtmp, DWARVISH_MITHRIL_COAT);
+                   } else {
+                       (void)mongets(mtmp, !rn2(3) ? PICK_AXE : DAGGER);
+                   }
+               }
+               break;
+# ifdef KOPS
+           case S_KOP:         /* create Keystone Kops with cream pies to
+                                * throw. As suggested by KAA.     [MRS]
+                                */
+               if (!rn2(4)) m_initthrow(mtmp, CREAM_PIE, 2);
+               if (!rn2(3)) (void)mongets(mtmp,(rn2(2)) ? CLUB : RUBBER_HOSE);
+               break;
+# endif
+           case S_ORC:
+               if(rn2(2)) (void)mongets(mtmp, ORCISH_HELM);
+               switch (mm != PM_ORC_CAPTAIN ? mm :
+                       rn2(2) ? PM_MORDOR_ORC : PM_URUK_HAI) {
+                   case PM_MORDOR_ORC:
+                       if(!rn2(3)) (void)mongets(mtmp, SCIMITAR);
+                       if(!rn2(3)) (void)mongets(mtmp, ORCISH_SHIELD);
+                       if(!rn2(3)) (void)mongets(mtmp, KNIFE);
+                       if(!rn2(3)) (void)mongets(mtmp, ORCISH_CHAIN_MAIL);
+                       break;
+                   case PM_URUK_HAI:
+                       if(!rn2(3)) (void)mongets(mtmp, ORCISH_CLOAK);
+                       if(!rn2(3)) (void)mongets(mtmp, ORCISH_SHORT_SWORD);
+                       if(!rn2(3)) (void)mongets(mtmp, IRON_SHOES);
+                       if(!rn2(3)) {
+                           (void)mongets(mtmp, ORCISH_BOW);
+                           m_initthrow(mtmp, ORCISH_ARROW, 12);
+                       }
+                       if(!rn2(3)) (void)mongets(mtmp, URUK_HAI_SHIELD);
+                       break;
+                   default:
+                       if (mm != PM_ORC_SHAMAN && rn2(2))
+                         (void)mongets(mtmp, (mm == PM_GOBLIN || rn2(2) == 0)
+                                                  ? ORCISH_DAGGER : SCIMITAR);
+               }
+               break;
+           case S_OGRE:
+               if (!rn2(mm == PM_OGRE_KING ? 3 : mm == PM_OGRE_LORD ? 6 : 12))
+                   (void) mongets(mtmp, BATTLE_AXE);
+               else
+                   (void) mongets(mtmp, CLUB);
+               break;
+           case S_TROLL:
+               if (!rn2(2)) switch (rn2(4)) {
+                   case 0: (void)mongets(mtmp, RANSEUR); break;
+                   case 1: (void)mongets(mtmp, PARTISAN); break;
+                   case 2: (void)mongets(mtmp, GLAIVE); break;
+                   case 3: (void)mongets(mtmp, SPETUM); break;
+               }
+               break;
+           case S_KOBOLD:
+               if (!rn2(4)) m_initthrow(mtmp, DART, 12);
+               break;
+
+           case S_CENTAUR:
+               if (rn2(2)) {
+                   if(ptr == &mons[PM_FOREST_CENTAUR]) {
+                       (void)mongets(mtmp, BOW);
+                       m_initthrow(mtmp, ARROW, 12);
+                   } else {
+                       (void)mongets(mtmp, CROSSBOW);
+                       m_initthrow(mtmp, CROSSBOW_BOLT, 12);
+                   }
+               }
+               break;
+           case S_WRAITH:
+               (void)mongets(mtmp, KNIFE);
+               (void)mongets(mtmp, LONG_SWORD);
+               break;
+           case S_ZOMBIE:
+               if (!rn2(4)) (void)mongets(mtmp, LEATHER_ARMOR);
+               if (!rn2(4))
+                       (void)mongets(mtmp, (rn2(3) ? KNIFE : SHORT_SWORD));
+               break;
+           case S_LIZARD:
+               if (mm == PM_SALAMANDER)
+                       (void)mongets(mtmp, (rn2(7) ? SPEAR : rn2(3) ?
+                                            TRIDENT : STILETTO));
+               break;
+           case S_DEMON:
+               switch (mm) {
+                   case PM_BALROG:
+                       (void)mongets(mtmp, BULLWHIP);
+                       (void)mongets(mtmp, BROADSWORD);
+                       break;
+                   case PM_ORCUS:
+                       (void)mongets(mtmp, WAN_DEATH); /* the Wand of Orcus */
+                       break;
+                   case PM_HORNED_DEVIL:
+                       (void)mongets(mtmp, rn2(4) ? TRIDENT : BULLWHIP);
+                       break;
+                   case PM_DISPATER:
+                       (void)mongets(mtmp, WAN_STRIKING);
+                       break;
+                   case PM_YEENOGHU:
+                       (void)mongets(mtmp, FLAIL);
+                       break;
+               }
+               /* prevent djinnis and mail daemons from leaving objects when
+                * they vanish
+                */
+               if (!is_demon(ptr)) break;
+               /* fall thru */
+/*
+ *     Now the general case, Some chance of getting some type
+ *     of weapon for "normal" monsters.  Certain special types
+ *     of monsters will get a bonus chance or different selections.
+ */
+           default:
+             {
+               int bias;
+
+               bias = is_lord(ptr) + is_prince(ptr) * 2 + extra_nasty(ptr);
+               switch(rnd(14 - (2 * bias))) {
+                   case 1:
+                       if(strongmonst(ptr)) (void) mongets(mtmp, BATTLE_AXE);
+                       else m_initthrow(mtmp, DART, 12);
+                       break;
+                   case 2:
+                       if(strongmonst(ptr))
+                           (void) mongets(mtmp, TWO_HANDED_SWORD);
+                       else {
+                           (void) mongets(mtmp, CROSSBOW);
+                           m_initthrow(mtmp, CROSSBOW_BOLT, 12);
+                       }
+                       break;
+                   case 3:
+                       (void) mongets(mtmp, BOW);
+                       m_initthrow(mtmp, ARROW, 12);
+                       break;
+                   case 4:
+                       if(strongmonst(ptr)) (void) mongets(mtmp, LONG_SWORD);
+                       else m_initthrow(mtmp, DAGGER, 3);
+                       break;
+                   case 5:
+                       if(strongmonst(ptr))
+                           (void) mongets(mtmp, LUCERN_HAMMER);
+                       else (void) mongets(mtmp, AKLYS);
+                       break;
+                   default:
+                       break;
+               }
+             }
+             break;
+       }
+       if ((int) mtmp->m_lev > rn2(75))
+               (void) mongets(mtmp, rnd_offensive_item(mtmp));
+}
+
+#endif /* OVL2 */
+#ifdef OVL1
+
+#ifdef GOLDOBJ
+/*
+ *   Makes up money for monster's inventory.
+ *   This will change with silver & copper coins
+ */
+void 
+mkmonmoney(mtmp, amount)
+struct monst *mtmp;
+long amount;
+{
+    struct obj *gold = mksobj(GOLD_PIECE, FALSE, FALSE);
+    gold->quan = amount;
+    add_to_minv(mtmp, gold);
+}
+#endif
+
+STATIC_OVL void
+m_initinv(mtmp)
+register struct        monst   *mtmp;
+{
+       register int cnt;
+       register struct obj *otmp;
+       register struct permonst *ptr = mtmp->data;
+#ifdef REINCARNATION
+       if (Is_rogue_level(&u.uz)) return;
+#endif
+/*
+ *     Soldiers get armour & rations - armour approximates their ac.
+ *     Nymphs may get mirror or potion of object detection.
+ */
+       switch(ptr->mlet) {
+
+           case S_HUMAN:
+               if(is_mercenary(ptr)) {
+                   register int mac;
+
+                   switch(monsndx(ptr)) {
+                       case PM_GUARD: mac = -1; break;
+                       case PM_SOLDIER: mac = 3; break;
+                       case PM_SERGEANT: mac = 0; break;
+                       case PM_LIEUTENANT: mac = -2; break;
+                       case PM_CAPTAIN: mac = -3; break;
+                       case PM_WATCHMAN: mac = 3; break;
+                       case PM_WATCH_CAPTAIN: mac = -2; break;
+                       default: impossible("odd mercenary %d?", monsndx(ptr));
+                               mac = 0;
+                               break;
+                   }
+
+                   if (mac < -1 && rn2(5))
+                       mac += 7 + mongets(mtmp, (rn2(5)) ?
+                                          PLATE_MAIL : CRYSTAL_PLATE_MAIL);
+                   else if (mac < 3 && rn2(5))
+                       mac += 6 + mongets(mtmp, (rn2(3)) ?
+                                          SPLINT_MAIL : BANDED_MAIL);
+                   else if (rn2(5))
+                       mac += 3 + mongets(mtmp, (rn2(3)) ?
+                                          RING_MAIL : STUDDED_LEATHER_ARMOR);
+                   else
+                       mac += 2 + mongets(mtmp, LEATHER_ARMOR);
+
+                   if (mac < 10 && rn2(3))
+                       mac += 1 + mongets(mtmp, HELMET);
+                   else if (mac < 10 && rn2(2))
+                       mac += 1 + mongets(mtmp, DENTED_POT);
+                   if (mac < 10 && rn2(3))
+                       mac += 1 + mongets(mtmp, SMALL_SHIELD);
+                   else if (mac < 10 && rn2(2))
+                       mac += 2 + mongets(mtmp, LARGE_SHIELD);
+                   if (mac < 10 && rn2(3))
+                       mac += 1 + mongets(mtmp, LOW_BOOTS);
+                   else if (mac < 10 && rn2(2))
+                       mac += 2 + mongets(mtmp, HIGH_BOOTS);
+                   if (mac < 10 && rn2(3))
+                       mac += 1 + mongets(mtmp, LEATHER_GLOVES);
+                   else if (mac < 10 && rn2(2))
+                       mac += 1 + mongets(mtmp, LEATHER_CLOAK);
+
+                   if(ptr != &mons[PM_GUARD] &&
+                       ptr != &mons[PM_WATCHMAN] &&
+                       ptr != &mons[PM_WATCH_CAPTAIN]) {
+                       if (!rn2(3)) (void) mongets(mtmp, K_RATION);
+                       if (!rn2(2)) (void) mongets(mtmp, C_RATION);
+                       if (ptr != &mons[PM_SOLDIER] && !rn2(3))
+                               (void) mongets(mtmp, BUGLE);
+                   } else
+                          if (ptr == &mons[PM_WATCHMAN] && rn2(3))
+                               (void) mongets(mtmp, TIN_WHISTLE);
+               } else if (ptr == &mons[PM_SHOPKEEPER]) {
+                   (void) mongets(mtmp,SKELETON_KEY);
+                   switch (rn2(4)) {
+                   /* MAJOR fall through ... */
+                   case 0: (void) mongets(mtmp, WAN_MAGIC_MISSILE);
+                   case 1: (void) mongets(mtmp, POT_EXTRA_HEALING);
+                   case 2: (void) mongets(mtmp, POT_HEALING);
+                   case 3: (void) mongets(mtmp, WAN_STRIKING);
+                   }
+               } else if (ptr->msound == MS_PRIEST ||
+                       quest_mon_represents_role(ptr,PM_PRIEST)) {
+                   (void) mongets(mtmp, rn2(7) ? ROBE :
+                                            rn2(3) ? CLOAK_OF_PROTECTION :
+                                                CLOAK_OF_MAGIC_RESISTANCE);
+                   (void) mongets(mtmp, SMALL_SHIELD);
+#ifndef GOLDOBJ
+                   mtmp->mgold = (long)rn1(10,20);
+#else
+                   mkmonmoney(mtmp,(long)rn1(10,20));
+#endif
+               } else if (quest_mon_represents_role(ptr,PM_MONK)) {
+                   (void) mongets(mtmp, rn2(11) ? ROBE :
+                                            CLOAK_OF_MAGIC_RESISTANCE);
+               }
+               break;
+           case S_NYMPH:
+               if(!rn2(2)) (void) mongets(mtmp, MIRROR);
+               if(!rn2(2)) (void) mongets(mtmp, POT_OBJECT_DETECTION);
+               break;
+           case S_GIANT:
+               if (ptr == &mons[PM_MINOTAUR]) {
+                   if (!rn2(3) || (in_mklev && Is_earthlevel(&u.uz)))
+                       (void) mongets(mtmp, WAN_DIGGING);
+               } else if (is_giant(ptr)) {
+                   for (cnt = rn2((int)(mtmp->m_lev / 2)); cnt; cnt--) {
+                       otmp = mksobj(rnd_class(DILITHIUM_CRYSTAL,LUCKSTONE-1),
+                                     FALSE, FALSE);
+                       otmp->quan = (long) rn1(2, 3);
+                       otmp->owt = weight(otmp);
+                       (void) mpickobj(mtmp, otmp);
+                   }
+               }
+               break;
+           case S_WRAITH:
+               if (ptr == &mons[PM_NAZGUL]) {
+                       otmp = mksobj(RIN_INVISIBILITY, FALSE, FALSE);
+                       curse(otmp);
+                       (void) mpickobj(mtmp, otmp);
+               }
+               break;
+           case S_LICH:
+               if (ptr == &mons[PM_MASTER_LICH] && !rn2(13))
+                       (void)mongets(mtmp, (rn2(7) ? ATHAME : WAN_NOTHING));
+               else if (ptr == &mons[PM_ARCH_LICH] && !rn2(3)) {
+                       otmp = mksobj(rn2(3) ? ATHAME : QUARTERSTAFF,
+                                     TRUE, rn2(13) ? FALSE : TRUE);
+                       if (otmp->spe < 2) otmp->spe = rnd(3);
+                       if (!rn2(4)) otmp->oerodeproof = 1;
+                       (void) mpickobj(mtmp, otmp);
+               }
+               break;
+           case S_MUMMY:
+               if (rn2(7)) (void)mongets(mtmp, MUMMY_WRAPPING);
+               break;
+           case S_QUANTMECH:
+               if (!rn2(20)) {
+                       otmp = mksobj(LARGE_BOX, FALSE, FALSE);
+                       otmp->spe = 1; /* flag for special box */
+                       otmp->owt = weight(otmp);
+                       (void) mpickobj(mtmp, otmp);
+               }
+               break;
+           case S_LEPRECHAUN:
+#ifndef GOLDOBJ
+               mtmp->mgold = (long) d(level_difficulty(), 30);
+#else
+               mkmonmoney(mtmp, (long) d(level_difficulty(), 30));
+#endif
+               break;
+           case S_DEMON:
+               /* moved here from m_initweap() because these don't
+                  have AT_WEAP so m_initweap() is not called for them */
+               if (ptr == &mons[PM_ICE_DEVIL] && !rn2(4)) {
+                       (void)mongets(mtmp, SPEAR);
+               } else if (ptr == &mons[PM_ASMODEUS]) {
+                       (void)mongets(mtmp, WAN_COLD);
+                       (void)mongets(mtmp, WAN_FIRE);
+               }
+               break;
+           default:
+               break;
+       }
+
+       /* ordinary soldiers rarely have access to magic (or gold :-) */
+       if (ptr == &mons[PM_SOLDIER] && rn2(13)) return;
+
+       if ((int) mtmp->m_lev > rn2(50))
+               (void) mongets(mtmp, rnd_defensive_item(mtmp));
+       if ((int) mtmp->m_lev > rn2(100))
+               (void) mongets(mtmp, rnd_misc_item(mtmp));
+#ifndef GOLDOBJ
+       if (likes_gold(ptr) && !mtmp->mgold && !rn2(5))
+               mtmp->mgold =
+                     (long) d(level_difficulty(), mtmp->minvent ? 5 : 10);
+#else
+       if (likes_gold(ptr) && !findgold(mtmp->minvent) && !rn2(5))
+               mkmonmoney(mtmp, (long) d(level_difficulty(), mtmp->minvent ? 5 : 10));
+#endif
+}
+
+/* Note: for long worms, always call cutworm (cutworm calls clone_mon) */
+struct monst *
+clone_mon(mon, x, y)
+struct monst *mon;
+xchar x, y;    /* clone's preferred location or 0 (near mon) */
+{
+       coord mm;
+       struct monst *m2;
+
+       /* may be too weak or have been extinguished for population control */
+       if (mon->mhp <= 1 || (mvitals[monsndx(mon->data)].mvflags & G_EXTINCT))
+           return (struct monst *)0;
+
+       if (x == 0) {
+           mm.x = mon->mx;
+           mm.y = mon->my;
+           if (!enexto(&mm, mm.x, mm.y, mon->data) || MON_AT(mm.x, mm.y))
+               return (struct monst *)0;
+       } else if (!isok(x, y)) {
+           return (struct monst *)0;   /* paranoia */
+       } else {
+           mm.x = x;
+           mm.y = y;
+           if (MON_AT(mm.x, mm.y)) {
+               if (!enexto(&mm, mm.x, mm.y, mon->data) || MON_AT(mm.x, mm.y))
+                   return (struct monst *)0;
+           }
+       }
+       m2 = newmonst(0);
+       *m2 = *mon;                     /* copy condition of old monster */
+       m2->nmon = fmon;
+       fmon = m2;
+       m2->m_id = flags.ident++;
+       if (!m2->m_id) m2->m_id = flags.ident++;        /* ident overflowed */
+       m2->mx = mm.x;
+       m2->my = mm.y;
+
+       m2->minvent = (struct obj *) 0; /* objects don't clone */
+       m2->mleashed = FALSE;
+#ifndef GOLDOBJ
+       m2->mgold = 0L;
+#endif
+       /* Max HP the same, but current HP halved for both.  The caller
+        * might want to override this by halving the max HP also.
+        * When current HP is odd, the original keeps the extra point.
+        */
+       m2->mhpmax = mon->mhpmax;
+       m2->mhp = mon->mhp / 2;
+       mon->mhp -= m2->mhp;
+
+       /* since shopkeepers and guards will only be cloned if they've been
+        * polymorphed away from their original forms, the clone doesn't have
+        * room for the extra information.  we also don't want two shopkeepers
+        * around for the same shop.
+        */
+       if (mon->isshk) m2->isshk = FALSE;
+       if (mon->isgd) m2->isgd = FALSE;
+       if (mon->ispriest) m2->ispriest = FALSE;
+       m2->mxlth = 0;
+       place_monster(m2, m2->mx, m2->my);
+       if (emits_light(m2->data))
+           new_light_source(m2->mx, m2->my, emits_light(m2->data),
+                            LS_MONSTER, (genericptr_t)m2);
+       if (m2->mnamelth) {
+           m2->mnamelth = 0; /* or it won't get allocated */
+           m2 = christen_monst(m2, NAME(mon));
+       } else if (mon->isshk) {
+           m2 = christen_monst(m2, shkname(mon));
+       }
+
+       /* not all clones caused by player are tame or peaceful */
+       if (!flags.mon_moving) {
+           if (mon->mtame)
+               m2->mtame = rn2(max(2 + u.uluck, 2)) ? mon->mtame : 0;
+           else if (mon->mpeaceful)
+               m2->mpeaceful = rn2(max(2 + u.uluck, 2)) ? 1 : 0;
+       }
+
+       newsym(m2->mx,m2->my);  /* display the new monster */
+       if (m2->mtame) {
+           struct monst *m3;
+
+           if (mon->isminion) {
+               m3 = newmonst(sizeof(struct epri) + mon->mnamelth);
+               *m3 = *m2;
+               m3->mxlth = sizeof(struct epri);
+               if (m2->mnamelth) Strcpy(NAME(m3), NAME(m2));
+               *(EPRI(m3)) = *(EPRI(mon));
+               replmon(m2, m3);
+               m2 = m3;
+           } else {
+               /* because m2 is a copy of mon it is tame but not init'ed.
+                * however, tamedog will not re-tame a tame dog, so m2
+                * must be made non-tame to get initialized properly.
+                */
+               m2->mtame = 0;
+               if ((m3 = tamedog(m2, (struct obj *)0)) != 0) {
+                   m2 = m3;
+                   *(EDOG(m2)) = *(EDOG(mon));
+               }
+           }
+       }
+       set_malign(m2);
+
+       return m2;
+}
+
+/*
+ * Propagate a species
+ *
+ * Once a certain number of monsters are created, don't create any more
+ * at random (i.e. make them extinct).  The previous (3.2) behavior was
+ * to do this when a certain number had _died_, which didn't make
+ * much sense.
+ *
+ * Returns FALSE propagation unsuccessful
+ *         TRUE  propagation successful
+ */
+boolean
+propagate(mndx, tally, ghostly)
+int mndx;
+boolean tally;
+boolean ghostly;
+{
+       boolean result;
+       uchar lim = mbirth_limit(mndx);
+       boolean gone = (mvitals[mndx].mvflags & G_GONE); /* genocided or extinct */
+
+       result = (((int) mvitals[mndx].born < lim) && !gone) ? TRUE : FALSE;
+
+       /* if it's unique, don't ever make it again */
+       if (mons[mndx].geno & G_UNIQ) mvitals[mndx].mvflags |= G_EXTINCT;
+
+       if (mvitals[mndx].born < 255 && tally && (!ghostly || (ghostly && result)))
+                mvitals[mndx].born++;
+       if ((int) mvitals[mndx].born >= lim && !(mons[mndx].geno & G_NOGEN) &&
+               !(mvitals[mndx].mvflags & G_EXTINCT)) {
+#if defined(DEBUG) && defined(WIZARD)
+               if (wizard) pline("Automatically extinguished %s.",
+                                       makeplural(mons[mndx].mname));
+#endif
+               mvitals[mndx].mvflags |= G_EXTINCT;
+               reset_rndmonst(mndx);
+       }
+       return result;
+}
+
+/*
+ * called with [x,y] = coordinates;
+ *     [0,0] means anyplace
+ *     [u.ux,u.uy] means: near player (if !in_mklev)
+ *
+ *     In case we make a monster group, only return the one at [x,y].
+ */
+struct monst *
+makemon(ptr, x, y, mmflags)
+register struct permonst *ptr;
+register int   x, y;
+register int   mmflags;
+{
+       register struct monst *mtmp;
+       int mndx, mcham, ct, mitem, xlth;
+       boolean anymon = (!ptr);
+       boolean byyou = (x == u.ux && y == u.uy);
+       boolean allow_minvent = ((mmflags & NO_MINVENT) == 0);
+       boolean countbirth = ((mmflags & MM_NOCOUNTBIRTH) == 0);
+       unsigned gpflags = (mmflags & MM_IGNOREWATER) ? MM_IGNOREWATER : 0;
+
+       /* if caller wants random location, do it here */
+       if(x == 0 && y == 0) {
+               int tryct = 0;  /* careful with bigrooms */
+               struct monst fakemon;
+
+               fakemon.data = ptr;     /* set up for goodpos */
+               do {
+                       x = rn1(COLNO-3,2);
+                       y = rn2(ROWNO);
+               } while(!goodpos(x, y, ptr ? &fakemon : (struct monst *)0, gpflags) ||
+                       (!in_mklev && tryct++ < 50 && cansee(x, y)));
+       } else if (byyou && !in_mklev) {
+               coord bypos;
+
+               if(enexto_core(&bypos, u.ux, u.uy, ptr, gpflags)) {
+                       x = bypos.x;
+                       y = bypos.y;
+               } else
+                       return((struct monst *)0);
+       }
+
+       /* Does monster already exist at the position? */
+       if(MON_AT(x, y)) {
+               if ((mmflags & MM_ADJACENTOK) != 0) {
+                       coord bypos;
+                       if(enexto_core(&bypos, x, y, ptr, gpflags)) {
+                               x = bypos.x;
+                               y = bypos.y;
+                       } else
+                               return((struct monst *) 0);
+               } else 
+                       return((struct monst *) 0);
+       }
+
+       if(ptr){
+               mndx = monsndx(ptr);
+               /* if you are to make a specific monster and it has
+                  already been genocided, return */
+               if (mvitals[mndx].mvflags & G_GENOD) return((struct monst *) 0);
+#if defined(WIZARD) && defined(DEBUG)
+               if (wizard && (mvitals[mndx].mvflags & G_EXTINCT))
+                   pline("Explicitly creating extinct monster %s.",
+                       mons[mndx].mname);
+#endif
+       } else {
+               /* make a random (common) monster that can survive here.
+                * (the special levels ask for random monsters at specific
+                * positions, causing mass drowning on the medusa level,
+                * for instance.)
+                */
+               int tryct = 0;  /* maybe there are no good choices */
+               struct monst fakemon;
+               do {
+                       if(!(ptr = rndmonst())) {
+#ifdef DEBUG
+                           pline("Warning: no monster.");
+#endif
+                           return((struct monst *) 0); /* no more monsters! */
+                       }
+                       fakemon.data = ptr;     /* set up for goodpos */
+               } while(!goodpos(x, y, &fakemon, gpflags) && tryct++ < 50);
+               mndx = monsndx(ptr);
+       }
+       (void) propagate(mndx, countbirth, FALSE);
+       xlth = ptr->pxlth;
+       if (mmflags & MM_EDOG) xlth += sizeof(struct edog);
+       else if (mmflags & MM_EMIN) xlth += sizeof(struct emin);
+       mtmp = newmonst(xlth);
+       *mtmp = zeromonst;              /* clear all entries in structure */
+       (void)memset((genericptr_t)mtmp->mextra, 0, xlth);
+       mtmp->nmon = fmon;
+       fmon = mtmp;
+       mtmp->m_id = flags.ident++;
+       if (!mtmp->m_id) mtmp->m_id = flags.ident++;    /* ident overflowed */
+       set_mon_data(mtmp, ptr, 0);
+       if (mtmp->data->msound == MS_LEADER)
+           quest_status.leader_m_id = mtmp->m_id;
+       mtmp->mxlth = xlth;
+       mtmp->mnum = mndx;
+
+       mtmp->m_lev = adj_lev(ptr);
+       if (is_golem(ptr)) {
+           mtmp->mhpmax = mtmp->mhp = golemhp(mndx);
+       } else if (is_rider(ptr)) {
+           /* We want low HP, but a high mlevel so they can attack well */
+           mtmp->mhpmax = mtmp->mhp = d(10,8);
+       } else if (ptr->mlevel > 49) {
+           /* "special" fixed hp monster
+            * the hit points are encoded in the mlevel in a somewhat strange
+            * way to fit in the 50..127 positive range of a signed character
+            * above the 1..49 that indicate "normal" monster levels */
+           mtmp->mhpmax = mtmp->mhp = 2*(ptr->mlevel - 6);
+           mtmp->m_lev = mtmp->mhp / 4;        /* approximation */
+       } else if (ptr->mlet == S_DRAGON && mndx >= PM_GRAY_DRAGON) {
+           /* adult dragons */
+           mtmp->mhpmax = mtmp->mhp = (int) (In_endgame(&u.uz) ?
+               (8 * mtmp->m_lev) : (4 * mtmp->m_lev + d((int)mtmp->m_lev, 4)));
+       } else if (!mtmp->m_lev) {
+           mtmp->mhpmax = mtmp->mhp = rnd(4);
+       } else {
+           mtmp->mhpmax = mtmp->mhp = d((int)mtmp->m_lev, 8);
+           if (is_home_elemental(ptr))
+               mtmp->mhpmax = (mtmp->mhp *= 3);
+       }
+
+       if (is_female(ptr)) mtmp->female = TRUE;
+       else if (is_male(ptr)) mtmp->female = FALSE;
+       else mtmp->female = rn2(2);     /* ignored for neuters */
+
+       if (In_sokoban(&u.uz) && !mindless(ptr))  /* know about traps here */
+           mtmp->mtrapseen = (1L << (PIT - 1)) | (1L << (HOLE - 1));
+       if (ptr->msound == MS_LEADER)           /* leader knows about portal */
+           mtmp->mtrapseen |= (1L << (MAGIC_PORTAL-1));
+
+       place_monster(mtmp, x, y);
+       mtmp->mcansee = mtmp->mcanmove = TRUE;
+       mtmp->mpeaceful = (mmflags & MM_ANGRY) ? FALSE : peace_minded(ptr);
+
+       switch(ptr->mlet) {
+               case S_MIMIC:
+                       set_mimic_sym(mtmp);
+                       break;
+               case S_SPIDER:
+               case S_SNAKE:
+                       if(in_mklev)
+                           if(x && y)
+                               (void) mkobj_at(0, x, y, TRUE);
+                       if(hides_under(ptr) && OBJ_AT(x, y))
+                           mtmp->mundetected = TRUE;
+                       break;
+               case S_LIGHT:
+               case S_ELEMENTAL:
+                       if (mndx == PM_STALKER || mndx == PM_BLACK_LIGHT) {
+                           mtmp->perminvis = TRUE;
+                           mtmp->minvis = TRUE;
+                       }
+                       break;
+               case S_EEL:
+                       if (is_pool(x, y))
+                           mtmp->mundetected = TRUE;
+                       break;
+               case S_LEPRECHAUN:
+                       mtmp->msleeping = 1;
+                       break;
+               case S_JABBERWOCK:
+               case S_NYMPH:
+                       if (rn2(5) && !u.uhave.amulet) mtmp->msleeping = 1;
+                       break;
+               case S_ORC:
+                       if (Race_if(PM_ELF)) mtmp->mpeaceful = FALSE;
+                       break;
+               case S_UNICORN:
+                       if (is_unicorn(ptr) &&
+                                       sgn(u.ualign.type) == sgn(ptr->maligntyp))
+                               mtmp->mpeaceful = TRUE;
+                       break;
+               case S_BAT:
+                       if (Inhell && is_bat(ptr))
+                           mon_adjust_speed(mtmp, 2, (struct obj *)0);
+                       break;
+       }
+       if ((ct = emits_light(mtmp->data)) > 0)
+               new_light_source(mtmp->mx, mtmp->my, ct,
+                                LS_MONSTER, (genericptr_t)mtmp);
+       mitem = 0;      /* extra inventory item for this monster */
+
+       if ((mcham = pm_to_cham(mndx)) != CHAM_ORDINARY) {
+               /* If you're protected with a ring, don't create
+                * any shape-changing chameleons -dgk
+                */
+               if (Protection_from_shape_changers)
+                       mtmp->cham = CHAM_ORDINARY;
+               else {
+                       mtmp->cham = mcham;
+                       (void) newcham(mtmp, rndmonst(), FALSE, FALSE);
+               }
+       } else if (mndx == PM_WIZARD_OF_YENDOR) {
+               mtmp->iswiz = TRUE;
+               flags.no_of_wizards++;
+               if (flags.no_of_wizards == 1 && Is_earthlevel(&u.uz))
+                       mitem = SPE_DIG;
+       } else if (mndx == PM_DJINNI) {
+               flags.djinni_count++;
+       } else if (mndx == PM_GHOST) {
+               flags.ghost_count++;
+               if (!(mmflags & MM_NONAME))
+                       mtmp = christen_monst(mtmp, rndghostname());
+       } else if (mndx == PM_VLAD_THE_IMPALER) {
+               mitem = CANDELABRUM_OF_INVOCATION;
+       } else if (mndx == PM_CROESUS) {
+               mitem = TWO_HANDED_SWORD;
+       } else if (ptr->msound == MS_NEMESIS) {
+               mitem = BELL_OF_OPENING;
+       } else if (mndx == PM_PESTILENCE) {
+               mitem = POT_SICKNESS;
+       }
+       if (mitem && allow_minvent) (void) mongets(mtmp, mitem);
+
+       if(in_mklev) {
+               if(((is_ndemon(ptr)) ||
+                   (mndx == PM_WUMPUS) ||
+                   (mndx == PM_LONG_WORM) ||
+                   (mndx == PM_GIANT_EEL)) && !u.uhave.amulet && rn2(5))
+                       mtmp->msleeping = TRUE;
+       } else {
+               if(byyou) {
+                       newsym(mtmp->mx,mtmp->my);
+                       set_apparxy(mtmp);
+               }
+       }
+       if(is_dprince(ptr) && ptr->msound == MS_BRIBE) {
+           mtmp->mpeaceful = mtmp->minvis = mtmp->perminvis = 1;
+           mtmp->mavenge = 0;
+           if (uwep && uwep->oartifact == ART_EXCALIBUR)
+               mtmp->mpeaceful = mtmp->mtame = FALSE;
+       }
+#ifndef DCC30_BUG
+       if (mndx == PM_LONG_WORM && (mtmp->wormno = get_wormno()) != 0)
+#else
+       /* DICE 3.0 doesn't like assigning and comparing mtmp->wormno in the
+        * same expression.
+        */
+       if (mndx == PM_LONG_WORM &&
+               (mtmp->wormno = get_wormno(), mtmp->wormno != 0))
+#endif
+       {
+           /* we can now create worms with tails - 11/91 */
+           initworm(mtmp, rn2(5));
+           if (count_wsegs(mtmp)) place_worm_tail_randomly(mtmp, x, y);
+       }
+       set_malign(mtmp);               /* having finished peaceful changes */
+       if(anymon) {
+           if ((ptr->geno & G_SGROUP) && rn2(2)) {
+               m_initsgrp(mtmp, mtmp->mx, mtmp->my);
+           } else if (ptr->geno & G_LGROUP) {
+               if(rn2(3))  m_initlgrp(mtmp, mtmp->mx, mtmp->my);
+               else        m_initsgrp(mtmp, mtmp->mx, mtmp->my);
+           }
+       }
+
+       if (allow_minvent) {
+           if(is_armed(ptr))
+               m_initweap(mtmp);       /* equip with weapons / armor */
+           m_initinv(mtmp);  /* add on a few special items incl. more armor */
+           m_dowear(mtmp, TRUE);
+       } else {
+           /* no initial inventory is allowed */
+           if (mtmp->minvent) discard_minvent(mtmp);
+           mtmp->minvent = (struct obj *)0;    /* caller expects this */
+       }
+       if ((ptr->mflags3 & M3_WAITMASK) && !(mmflags & MM_NOWAIT)) {
+               if (ptr->mflags3 & M3_WAITFORU)
+                       mtmp->mstrategy |= STRAT_WAITFORU;
+               if (ptr->mflags3 & M3_CLOSE)
+                       mtmp->mstrategy |= STRAT_CLOSE;
+       }
+
+       if (!in_mklev)
+           newsym(mtmp->mx,mtmp->my);  /* make sure the mon shows up */
+
+       return(mtmp);
+}
+
+int
+mbirth_limit(mndx)
+int mndx;
+{
+       /* assert(MAXMONNO < 255); */
+       return (mndx == PM_NAZGUL ? 9 : mndx == PM_ERINYS ? 3 : MAXMONNO); 
+}
+
+/* used for wand/scroll/spell of create monster */
+/* returns TRUE iff you know monsters have been created */
+boolean
+create_critters(cnt, mptr)
+int cnt;
+struct permonst *mptr;         /* usually null; used for confused reading */
+{
+       coord c;
+       int x, y;
+       struct monst *mon;
+       boolean known = FALSE;
+#ifdef WIZARD
+       boolean ask = wizard;
+#endif
+
+       while (cnt--) {
+#ifdef WIZARD
+           if (ask) {
+               if (create_particular()) {
+                   known = TRUE;
+                   continue;
+               }
+               else ask = FALSE;       /* ESC will shut off prompting */
+           }
+#endif
+           x = u.ux,  y = u.uy;
+           /* if in water, try to encourage an aquatic monster
+              by finding and then specifying another wet location */
+           if (!mptr && u.uinwater && enexto(&c, x, y, &mons[PM_GIANT_EEL]))
+               x = c.x,  y = c.y;
+
+           mon = makemon(mptr, x, y, NO_MM_FLAGS);
+           if (mon && canspotmon(mon)) known = TRUE;
+       }
+       return known;
+}
+
+#endif /* OVL1 */
+#ifdef OVL0
+
+STATIC_OVL boolean
+uncommon(mndx)
+int mndx;
+{
+       if (mons[mndx].geno & (G_NOGEN | G_UNIQ)) return TRUE;
+       if (mvitals[mndx].mvflags & G_GONE) return TRUE;
+       if (Inhell)
+               return(mons[mndx].maligntyp > A_NEUTRAL);
+       else
+               return((mons[mndx].geno & G_HELL) != 0);
+}
+
+/*
+ *     shift the probability of a monster's generation by
+ *     comparing the dungeon alignment and monster alignment.
+ *     return an integer in the range of 0-5.
+ */
+STATIC_OVL int
+align_shift(ptr)
+register struct permonst *ptr;
+{
+    static NEARDATA long oldmoves = 0L;        /* != 1, starting value of moves */
+    static NEARDATA s_level *lev;
+    register int alshift;
+
+    if(oldmoves != moves) {
+       lev = Is_special(&u.uz);
+       oldmoves = moves;
+    }
+    switch((lev) ? lev->flags.align : dungeons[u.uz.dnum].flags.align) {
+    default:   /* just in case */
+    case AM_NONE:      alshift = 0;
+                       break;
+    case AM_LAWFUL:    alshift = (ptr->maligntyp+20)/(2*ALIGNWEIGHT);
+                       break;
+    case AM_NEUTRAL:   alshift = (20 - abs(ptr->maligntyp))/ALIGNWEIGHT;
+                       break;
+    case AM_CHAOTIC:   alshift = (-(ptr->maligntyp-20))/(2*ALIGNWEIGHT);
+                       break;
+    }
+    return alshift;
+}
+
+static NEARDATA struct {
+       int choice_count;
+       char mchoices[SPECIAL_PM];      /* value range is 0..127 */
+} rndmonst_state = { -1, {0} };
+
+/* select a random monster type */
+struct permonst *
+rndmonst()
+{
+       register struct permonst *ptr;
+       register int mndx, ct;
+
+       if (u.uz.dnum == quest_dnum && rn2(7) && (ptr = qt_montype()) != 0)
+           return ptr;
+
+       if (rndmonst_state.choice_count < 0) {  /* need to recalculate */
+           int zlevel, minmlev, maxmlev;
+           boolean elemlevel;
+#ifdef REINCARNATION
+           boolean upper;
+#endif
+
+           rndmonst_state.choice_count = 0;
+           /* look for first common monster */
+           for (mndx = LOW_PM; mndx < SPECIAL_PM; mndx++) {
+               if (!uncommon(mndx)) break;
+               rndmonst_state.mchoices[mndx] = 0;
+           }           
+           if (mndx == SPECIAL_PM) {
+               /* evidently they've all been exterminated */
+#ifdef DEBUG
+               pline("rndmonst: no common mons!");
+#endif
+               return (struct permonst *)0;
+           } /* else `mndx' now ready for use below */
+           zlevel = level_difficulty();
+           /* determine the level of the weakest monster to make. */
+           minmlev = zlevel / 6;
+           /* determine the level of the strongest monster to make. */
+           maxmlev = (zlevel + u.ulevel) / 2;
+#ifdef REINCARNATION
+           upper = Is_rogue_level(&u.uz);
+#endif
+           elemlevel = In_endgame(&u.uz) && !Is_astralevel(&u.uz);
+
+/*
+ *     Find out how many monsters exist in the range we have selected.
+ */
+           /* (`mndx' initialized above) */
+           for ( ; mndx < SPECIAL_PM; mndx++) {
+               ptr = &mons[mndx];
+               rndmonst_state.mchoices[mndx] = 0;
+               if (tooweak(mndx, minmlev) || toostrong(mndx, maxmlev))
+                   continue;
+#ifdef REINCARNATION
+               if (upper && !isupper(def_monsyms[(int)(ptr->mlet)])) continue;
+#endif
+               if (elemlevel && wrong_elem_type(ptr)) continue;
+               if (uncommon(mndx)) continue;
+               if (Inhell && (ptr->geno & G_NOHELL)) continue;
+               ct = (int)(ptr->geno & G_FREQ) + align_shift(ptr);
+               if (ct < 0 || ct > 127)
+                   panic("rndmonst: bad count [#%d: %d]", mndx, ct);
+               rndmonst_state.choice_count += ct;
+               rndmonst_state.mchoices[mndx] = (char)ct;
+           }
+/*
+ *         Possible modification:  if choice_count is "too low",
+ *         expand minmlev..maxmlev range and try again.
+ */
+       } /* choice_count+mchoices[] recalc */
+
+       if (rndmonst_state.choice_count <= 0) {
+           /* maybe no common mons left, or all are too weak or too strong */
+#ifdef DEBUG
+           Norep("rndmonst: choice_count=%d", rndmonst_state.choice_count);
+#endif
+           return (struct permonst *)0;
+       }
+
+/*
+ *     Now, select a monster at random.
+ */
+       ct = rnd(rndmonst_state.choice_count);
+       for (mndx = LOW_PM; mndx < SPECIAL_PM; mndx++)
+           if ((ct -= (int)rndmonst_state.mchoices[mndx]) <= 0) break;
+
+       if (mndx == SPECIAL_PM || uncommon(mndx)) {     /* shouldn't happen */
+           impossible("rndmonst: bad `mndx' [#%d]", mndx);
+           return (struct permonst *)0;
+       }
+       return &mons[mndx];
+}
+
+/* called when you change level (experience or dungeon depth) or when
+   monster species can no longer be created (genocide or extinction) */
+void
+reset_rndmonst(mndx)
+int mndx;      /* particular species that can no longer be created */
+{
+       /* cached selection info is out of date */
+       if (mndx == NON_PM) {
+           rndmonst_state.choice_count = -1;   /* full recalc needed */
+       } else if (mndx < SPECIAL_PM) {
+           rndmonst_state.choice_count -= rndmonst_state.mchoices[mndx];
+           rndmonst_state.mchoices[mndx] = 0;
+       } /* note: safe to ignore extinction of unique monsters */
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+/*     The routine below is used to make one of the multiple types
+ *     of a given monster class.  The second parameter specifies a
+ *     special casing bit mask to allow the normal genesis
+ *     masks to be deactivated.  Returns 0 if no monsters
+ *     in that class can be made.
+ */
+
+struct permonst *
+mkclass(class,spc)
+char   class;
+int    spc;
+{
+       register int    first, last, num = 0;
+       int maxmlev, mask = (G_NOGEN | G_UNIQ) & ~spc;
+
+       maxmlev = level_difficulty() >> 1;
+       if(class < 1 || class >= MAXMCLASSES) {
+           impossible("mkclass called with bad class!");
+           return((struct permonst *) 0);
+       }
+/*     Assumption #1:  monsters of a given class are contiguous in the
+ *                     mons[] array.
+ */
+       for (first = LOW_PM; first < SPECIAL_PM; first++)
+           if (mons[first].mlet == class) break;
+       if (first == SPECIAL_PM) return (struct permonst *) 0;
+
+       for (last = first;
+               last < SPECIAL_PM && mons[last].mlet == class; last++)
+           if (!(mvitals[last].mvflags & G_GONE) && !(mons[last].geno & mask)
+                                       && !is_placeholder(&mons[last])) {
+               /* consider it */
+               if(num && toostrong(last, maxmlev) &&
+                  monstr[last] != monstr[last-1] && rn2(2)) break;
+               num += mons[last].geno & G_FREQ;
+           }
+
+       if(!num) return((struct permonst *) 0);
+
+/*     Assumption #2:  monsters of a given class are presented in ascending
+ *                     order of strength.
+ */
+       for(num = rnd(num); num > 0; first++)
+           if (!(mvitals[first].mvflags & G_GONE) && !(mons[first].geno & mask)
+                                       && !is_placeholder(&mons[first])) {
+               /* skew towards lower value monsters at lower exp. levels */
+               num -= mons[first].geno & G_FREQ;
+               if (num && adj_lev(&mons[first]) > (u.ulevel*2)) {
+                   /* but not when multiple monsters are same level */
+                   if (mons[first].mlevel != mons[first+1].mlevel)
+                       num--;
+               }
+           }
+       first--; /* correct an off-by-one error */
+
+       return(&mons[first]);
+}
+
+int
+adj_lev(ptr)   /* adjust strength of monsters based on u.uz and u.ulevel */
+register struct permonst *ptr;
+{
+       int     tmp, tmp2;
+
+       if (ptr == &mons[PM_WIZARD_OF_YENDOR]) {
+               /* does not depend on other strengths, but does get stronger
+                * every time he is killed
+                */
+               tmp = ptr->mlevel + mvitals[PM_WIZARD_OF_YENDOR].died;
+               if (tmp > 49) tmp = 49;
+               return tmp;
+       }
+
+       if((tmp = ptr->mlevel) > 49) return(50); /* "special" demons/devils */
+       tmp2 = (level_difficulty() - tmp);
+       if(tmp2 < 0) tmp--;             /* if mlevel > u.uz decrement tmp */
+       else tmp += (tmp2 / 5);         /* else increment 1 per five diff */
+
+       tmp2 = (u.ulevel - ptr->mlevel);        /* adjust vs. the player */
+       if(tmp2 > 0) tmp += (tmp2 / 4);         /* level as well */
+
+       tmp2 = (3 * ((int) ptr->mlevel))/ 2;    /* crude upper limit */
+       if (tmp2 > 49) tmp2 = 49;               /* hard upper limit */
+       return((tmp > tmp2) ? tmp2 : (tmp > 0 ? tmp : 0)); /* 0 lower limit */
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+struct permonst *
+grow_up(mtmp, victim)  /* `mtmp' might "grow up" into a bigger version */
+struct monst *mtmp, *victim;
+{
+       int oldtype, newtype, max_increase, cur_increase,
+           lev_limit, hp_threshold;
+       struct permonst *ptr = mtmp->data;
+
+       /* monster died after killing enemy but before calling this function */
+       /* currently possible if killing a gas spore */
+       if (mtmp->mhp <= 0)
+           return ((struct permonst *)0);
+
+       /* note:  none of the monsters with special hit point calculations
+          have both little and big forms */
+       oldtype = monsndx(ptr);
+       newtype = little_to_big(oldtype);
+       if (newtype == PM_PRIEST && mtmp->female) newtype = PM_PRIESTESS;
+
+       /* growth limits differ depending on method of advancement */
+       if (victim) {           /* killed a monster */
+           /*
+            * The HP threshold is the maximum number of hit points for the
+            * current level; once exceeded, a level will be gained.
+            * Possible bug: if somehow the hit points are already higher
+            * than that, monster will gain a level without any increase in HP.
+            */
+           hp_threshold = mtmp->m_lev * 8;             /* normal limit */
+           if (!mtmp->m_lev)
+               hp_threshold = 4;
+           else if (is_golem(ptr))     /* strange creatures */
+               hp_threshold = ((mtmp->mhpmax / 10) + 1) * 10 - 1;
+           else if (is_home_elemental(ptr))
+               hp_threshold *= 3;
+           lev_limit = 3 * (int)ptr->mlevel / 2;       /* same as adj_lev() */
+           /* If they can grow up, be sure the level is high enough for that */
+           if (oldtype != newtype && mons[newtype].mlevel > lev_limit)
+               lev_limit = (int)mons[newtype].mlevel;
+           /* number of hit points to gain; unlike for the player, we put
+              the limit at the bottom of the next level rather than the top */
+           max_increase = rnd((int)victim->m_lev + 1);
+           if (mtmp->mhpmax + max_increase > hp_threshold + 1)
+               max_increase = max((hp_threshold + 1) - mtmp->mhpmax, 0);
+           cur_increase = (max_increase > 1) ? rn2(max_increase) : 0;
+       } else {
+           /* a gain level potion or wraith corpse; always go up a level
+              unless already at maximum (49 is hard upper limit except
+              for demon lords, who start at 50 and can't go any higher) */
+           max_increase = cur_increase = rnd(8);
+           hp_threshold = 0;   /* smaller than `mhpmax + max_increase' */
+           lev_limit = 50;             /* recalc below */
+       }
+
+       mtmp->mhpmax += max_increase;
+       mtmp->mhp += cur_increase;
+       if (mtmp->mhpmax <= hp_threshold)
+           return ptr;         /* doesn't gain a level */
+
+       if (is_mplayer(ptr)) lev_limit = 30;    /* same as player */
+       else if (lev_limit < 5) lev_limit = 5;  /* arbitrary */
+       else if (lev_limit > 49) lev_limit = (ptr->mlevel > 49 ? 50 : 49);
+
+       if ((int)++mtmp->m_lev >= mons[newtype].mlevel && newtype != oldtype) {
+           ptr = &mons[newtype];
+           if (mvitals[newtype].mvflags & G_GENOD) {   /* allow G_EXTINCT */
+               if (sensemon(mtmp))
+                   pline("As %s grows up into %s, %s %s!", mon_nam(mtmp),
+                       an(ptr->mname), mhe(mtmp),
+                       nonliving(ptr) ? "expires" : "dies");
+               set_mon_data(mtmp, ptr, -1);    /* keep mvitals[] accurate */
+               mondied(mtmp);
+               return (struct permonst *)0;
+           }
+           set_mon_data(mtmp, ptr, 1);         /* preserve intrinsics */
+           newsym(mtmp->mx, mtmp->my);         /* color may change */
+           lev_limit = (int)mtmp->m_lev;       /* never undo increment */
+       }
+       /* sanity checks */
+       if ((int)mtmp->m_lev > lev_limit) {
+           mtmp->m_lev--;      /* undo increment */
+           /* HP might have been allowed to grow when it shouldn't */
+           if (mtmp->mhpmax == hp_threshold + 1) mtmp->mhpmax--;
+       }
+       if (mtmp->mhpmax > 50*8) mtmp->mhpmax = 50*8;     /* absolute limit */
+       if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
+
+       return ptr;
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+int
+mongets(mtmp, otyp)
+register struct monst *mtmp;
+register int otyp;
+{
+       register struct obj *otmp;
+       int spe;
+
+       if (!otyp) return 0;
+       otmp = mksobj(otyp, TRUE, FALSE);
+       if (otmp) {
+           if (mtmp->data->mlet == S_DEMON) {
+               /* demons never get blessed objects */
+               if (otmp->blessed) curse(otmp);
+           } else if(is_lminion(mtmp)) {
+               /* lawful minions don't get cursed, bad, or rusting objects */
+               otmp->cursed = FALSE;
+               if(otmp->spe < 0) otmp->spe = 0;
+               otmp->oerodeproof = TRUE;
+           } else if(is_mplayer(mtmp->data) && is_sword(otmp)) {
+               otmp->spe = (3 + rn2(4));
+           }
+
+           if(otmp->otyp == CANDELABRUM_OF_INVOCATION) {
+               otmp->spe = 0;
+               otmp->age = 0L;
+               otmp->lamplit = FALSE;
+               otmp->blessed = otmp->cursed = FALSE;
+           } else if (otmp->otyp == BELL_OF_OPENING) {
+               otmp->blessed = otmp->cursed = FALSE;
+           } else if (otmp->otyp == SPE_BOOK_OF_THE_DEAD) {
+               otmp->blessed = FALSE;
+               otmp->cursed = TRUE;
+           }
+
+           /* leaders don't tolerate inferior quality battle gear */
+           if (is_prince(mtmp->data)) {
+               if (otmp->oclass == WEAPON_CLASS && otmp->spe < 1)
+                   otmp->spe = 1;
+               else if (otmp->oclass == ARMOR_CLASS && otmp->spe < 0)
+                   otmp->spe = 0;
+           }
+
+           spe = otmp->spe;
+           (void) mpickobj(mtmp, otmp);        /* might free otmp */
+           return(spe);
+       } else return(0);
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+int
+golemhp(type)
+int type;
+{
+       switch(type) {
+               case PM_STRAW_GOLEM: return 20;
+               case PM_PAPER_GOLEM: return 20;
+               case PM_ROPE_GOLEM: return 30;
+               case PM_LEATHER_GOLEM: return 40;
+               case PM_GOLD_GOLEM: return 40;
+               case PM_WOOD_GOLEM: return 50;
+               case PM_FLESH_GOLEM: return 40;
+               case PM_CLAY_GOLEM: return 50;
+               case PM_STONE_GOLEM: return 60;
+               case PM_GLASS_GOLEM: return 60;
+               case PM_IRON_GOLEM: return 80;
+               default: return 0;
+       }
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+/*
+ *     Alignment vs. yours determines monster's attitude to you.
+ *     ( some "animal" types are co-aligned, but also hungry )
+ */
+boolean
+peace_minded(ptr)
+register struct permonst *ptr;
+{
+       aligntyp mal = ptr->maligntyp, ual = u.ualign.type;
+
+       if (always_peaceful(ptr)) return TRUE;
+       if (always_hostile(ptr)) return FALSE;
+       if (ptr->msound == MS_LEADER || ptr->msound == MS_GUARDIAN)
+               return TRUE;
+       if (ptr->msound == MS_NEMESIS)  return FALSE;
+
+       if (race_peaceful(ptr)) return TRUE;
+       if (race_hostile(ptr)) return FALSE;
+
+       /* the monster is hostile if its alignment is different from the
+        * player's */
+       if (sgn(mal) != sgn(ual)) return FALSE;
+
+       /* Negative monster hostile to player with Amulet. */
+       if (mal < A_NEUTRAL && u.uhave.amulet) return FALSE;
+
+       /* minions are hostile to players that have strayed at all */
+       if (is_minion(ptr)) return((boolean)(u.ualign.record >= 0));
+
+       /* Last case:  a chance of a co-aligned monster being
+        * hostile.  This chance is greater if the player has strayed
+        * (u.ualign.record negative) or the monster is not strongly aligned.
+        */
+       return((boolean)(!!rn2(16 + (u.ualign.record < -15 ? -15 : u.ualign.record)) &&
+               !!rn2(2 + abs(mal))));
+}
+
+/* Set malign to have the proper effect on player alignment if monster is
+ * killed.  Negative numbers mean it's bad to kill this monster; positive
+ * numbers mean it's good.  Since there are more hostile monsters than
+ * peaceful monsters, the penalty for killing a peaceful monster should be
+ * greater than the bonus for killing a hostile monster to maintain balance.
+ * Rules:
+ *   it's bad to kill peaceful monsters, potentially worse to kill always-
+ *     peaceful monsters
+ *   it's never bad to kill a hostile monster, although it may not be good
+ */
+void
+set_malign(mtmp)
+struct monst *mtmp;
+{
+       schar mal = mtmp->data->maligntyp;
+       boolean coaligned;
+
+       if (mtmp->ispriest || mtmp->isminion) {
+               /* some monsters have individual alignments; check them */
+               if (mtmp->ispriest)
+                       mal = EPRI(mtmp)->shralign;
+               else if (mtmp->isminion)
+                       mal = EMIN(mtmp)->min_align;
+               /* unless alignment is none, set mal to -5,0,5 */
+               /* (see align.h for valid aligntyp values)     */
+               if(mal != A_NONE)
+                       mal *= 5;
+       }
+
+       coaligned = (sgn(mal) == sgn(u.ualign.type));
+       if (mtmp->data->msound == MS_LEADER) {
+               mtmp->malign = -20;
+       } else if (mal == A_NONE) {
+               if (mtmp->mpeaceful)
+                       mtmp->malign = 0;
+               else
+                       mtmp->malign = 20;      /* really hostile */
+       } else if (always_peaceful(mtmp->data)) {
+               int absmal = abs(mal);
+               if (mtmp->mpeaceful)
+                       mtmp->malign = -3*max(5,absmal);
+               else
+                       mtmp->malign = 3*max(5,absmal); /* renegade */
+       } else if (always_hostile(mtmp->data)) {
+               int absmal = abs(mal);
+               if (coaligned)
+                       mtmp->malign = 0;
+               else
+                       mtmp->malign = max(5,absmal);
+       } else if (coaligned) {
+               int absmal = abs(mal);
+               if (mtmp->mpeaceful)
+                       mtmp->malign = -3*max(3,absmal);
+               else    /* renegade */
+                       mtmp->malign = max(3,absmal);
+       } else  /* not coaligned and therefore hostile */
+               mtmp->malign = abs(mal);
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+static NEARDATA char syms[] = {
+       MAXOCLASSES, MAXOCLASSES+1, RING_CLASS, WAND_CLASS, WEAPON_CLASS,
+       FOOD_CLASS, COIN_CLASS, SCROLL_CLASS, POTION_CLASS, ARMOR_CLASS,
+       AMULET_CLASS, TOOL_CLASS, ROCK_CLASS, GEM_CLASS, SPBOOK_CLASS,
+       S_MIMIC_DEF, S_MIMIC_DEF, S_MIMIC_DEF,
+};
+
+void
+set_mimic_sym(mtmp)            /* KAA, modified by ERS */
+register struct monst *mtmp;
+{
+       int typ, roomno, rt;
+       unsigned appear, ap_type;
+       int s_sym;
+       struct obj *otmp;
+       int mx, my;
+
+       if (!mtmp) return;
+       mx = mtmp->mx; my = mtmp->my;
+       typ = levl[mx][my].typ;
+                                       /* only valid for INSIDE of room */
+       roomno = levl[mx][my].roomno - ROOMOFFSET;
+       if (roomno >= 0)
+               rt = rooms[roomno].rtype;
+#ifdef SPECIALIZATION
+       else if (IS_ROOM(typ))
+               rt = OROOM,  roomno = 0;
+#endif
+       else    rt = 0; /* roomno < 0 case for GCC_WARN */
+
+       if (OBJ_AT(mx, my)) {
+               ap_type = M_AP_OBJECT;
+               appear = level.objects[mx][my]->otyp;
+       } else if (IS_DOOR(typ) || IS_WALL(typ) ||
+                  typ == SDOOR || typ == SCORR) {
+               ap_type = M_AP_FURNITURE;
+               /*
+                *  If there is a wall to the left that connects to this
+                *  location, then the mimic mimics a horizontal closed door.
+                *  This does not allow doors to be in corners of rooms.
+                */
+               if (mx != 0 &&
+                       (levl[mx-1][my].typ == HWALL    ||
+                        levl[mx-1][my].typ == TLCORNER ||
+                        levl[mx-1][my].typ == TRWALL   ||
+                        levl[mx-1][my].typ == BLCORNER ||
+                        levl[mx-1][my].typ == TDWALL   ||
+                        levl[mx-1][my].typ == CROSSWALL||
+                        levl[mx-1][my].typ == TUWALL    ))
+                   appear = S_hcdoor;
+               else
+                   appear = S_vcdoor;
+
+               if(!mtmp->minvis || See_invisible)
+                   block_point(mx,my); /* vision */
+       } else if (level.flags.is_maze_lev && rn2(2)) {
+               ap_type = M_AP_OBJECT;
+               appear = STATUE;
+       } else if (roomno < 0) {
+               ap_type = M_AP_OBJECT;
+               appear = BOULDER;
+               if(!mtmp->minvis || See_invisible)
+                   block_point(mx,my); /* vision */
+       } else if (rt == ZOO || rt == VAULT) {
+               ap_type = M_AP_OBJECT;
+               appear = GOLD_PIECE;
+       } else if (rt == DELPHI) {
+               if (rn2(2)) {
+                       ap_type = M_AP_OBJECT;
+                       appear = STATUE;
+               } else {
+                       ap_type = M_AP_FURNITURE;
+                       appear = S_fountain;
+               }
+       } else if (rt == TEMPLE) {
+               ap_type = M_AP_FURNITURE;
+               appear = S_altar;
+       /*
+        * We won't bother with beehives, morgues, barracks, throne rooms
+        * since they shouldn't contain too many mimics anyway...
+        */
+       } else if (rt >= SHOPBASE) {
+               s_sym = get_shop_item(rt - SHOPBASE);
+               if (s_sym < 0) {
+                       ap_type = M_AP_OBJECT;
+                       appear = -s_sym;
+               } else {
+                       if (s_sym == RANDOM_CLASS)
+                               s_sym = syms[rn2((int)sizeof(syms)-2) + 2];
+                       goto assign_sym;
+               }
+       } else {
+               s_sym = syms[rn2((int)sizeof(syms))];
+assign_sym:
+               if (s_sym >= MAXOCLASSES) {
+                       ap_type = M_AP_FURNITURE;
+                       appear = s_sym == MAXOCLASSES ? S_upstair : S_dnstair;
+               } else if (s_sym == COIN_CLASS) {
+                       ap_type = M_AP_OBJECT;
+                       appear = GOLD_PIECE;
+               } else {
+                       ap_type = M_AP_OBJECT;
+                       if (s_sym == S_MIMIC_DEF) {
+                               appear = STRANGE_OBJECT;
+                       } else {
+                               otmp = mkobj( (char) s_sym, FALSE );
+                               appear = otmp->otyp;
+                               /* make sure container contents are free'ed */
+                               obfree(otmp, (struct obj *) 0);
+                       }
+               }
+       }
+       mtmp->m_ap_type = ap_type;
+       mtmp->mappearance = appear;
+}
+
+/* release a monster from a bag of tricks */
+void
+bagotricks(bag)
+struct obj *bag;
+{
+    if (!bag || bag->otyp != BAG_OF_TRICKS) {
+       impossible("bad bag o' tricks");
+    } else if (bag->spe < 1) {
+       pline(nothing_happens);
+    } else {
+       boolean gotone = FALSE;
+       int cnt = 1;
+
+       consume_obj_charge(bag, TRUE);
+
+       if (!rn2(23)) cnt += rn1(7, 1);
+       while (cnt-- > 0) {
+           if (makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS))
+               gotone = TRUE;
+       }
+       if (gotone) makeknown(BAG_OF_TRICKS);
+    }
+}
+
+#endif /* OVLB */
+
+/*makemon.c*/
diff --git a/src/mapglyph.c b/src/mapglyph.c
new file mode 100644 (file)
index 0000000..92fbd17
--- /dev/null
@@ -0,0 +1,241 @@
+/*     SCCS Id: @(#)mapglyph.c 3.4     2003/01/08      */
+/* Copyright (c) David Cohrs, 1991                               */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#if defined(TTY_GRAPHICS)
+#include "wintty.h"    /* for prototype of has_color() only */
+#endif
+#include "color.h"
+#define HI_DOMESTIC CLR_WHITE  /* monst.c */
+
+int explcolors[] = {
+       CLR_BLACK,      /* dark    */
+       CLR_GREEN,      /* noxious */
+       CLR_BROWN,      /* muddy   */
+       CLR_BLUE,       /* wet     */
+       CLR_MAGENTA,    /* magical */
+       CLR_ORANGE,     /* fiery   */
+       CLR_WHITE,      /* frosty  */
+};
+
+#if !defined(TTY_GRAPHICS)
+#define has_color(n)  TRUE
+#endif
+
+#ifdef TEXTCOLOR
+#define zap_color(n)  color = iflags.use_color ? zapcolors[n] : NO_COLOR
+#define cmap_color(n) color = iflags.use_color ? defsyms[n].color : NO_COLOR
+#define obj_color(n)  color = iflags.use_color ? objects[n].oc_color : NO_COLOR
+#define mon_color(n)  color = iflags.use_color ? mons[n].mcolor : NO_COLOR
+#define invis_color(n) color = NO_COLOR
+#define pet_color(n)  color = iflags.use_color ? mons[n].mcolor : NO_COLOR
+#define warn_color(n) color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR
+#define explode_color(n) color = iflags.use_color ? explcolors[n] : NO_COLOR
+# if defined(REINCARNATION) && defined(ASCIIGRAPH)
+#  define ROGUE_COLOR
+# endif
+
+#else  /* no text color */
+
+#define zap_color(n)
+#define cmap_color(n)
+#define obj_color(n)
+#define mon_color(n)
+#define invis_color(n)
+#define pet_color(c)
+#define warn_color(n)
+#define explode_color(n)
+#endif
+
+#ifdef ROGUE_COLOR
+# if defined(USE_TILES) && defined(MSDOS)
+#define HAS_ROGUE_IBM_GRAPHICS (iflags.IBMgraphics && !iflags.grmode && \
+       Is_rogue_level(&u.uz))
+# else
+#define HAS_ROGUE_IBM_GRAPHICS (iflags.IBMgraphics && Is_rogue_level(&u.uz))
+# endif
+#endif
+
+/*ARGSUSED*/
+void
+mapglyph(glyph, ochar, ocolor, ospecial, x, y)
+int glyph, *ocolor, x, y;
+int *ochar;
+unsigned *ospecial;
+{
+       register int offset;
+#if defined(TEXTCOLOR) || defined(ROGUE_COLOR)
+       int color = NO_COLOR;
+#endif
+       uchar ch;
+       unsigned special = 0;
+
+    /*
+     *  Map the glyph back to a character and color.
+     *
+     *  Warning:  For speed, this makes an assumption on the order of
+     *           offsets.  The order is set in display.h.
+     */
+    if ((offset = (glyph - GLYPH_WARNING_OFF)) >= 0) { /* a warning flash */
+       ch = warnsyms[offset];
+# ifdef ROGUE_COLOR
+       if (HAS_ROGUE_IBM_GRAPHICS)
+           color = NO_COLOR;
+       else
+# endif
+           warn_color(offset);
+    } else if ((offset = (glyph - GLYPH_SWALLOW_OFF)) >= 0) {  /* swallow */
+       /* see swallow_to_glyph() in display.c */
+       ch = (uchar) showsyms[S_sw_tl + (offset & 0x7)];
+#ifdef ROGUE_COLOR
+       if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color)
+           color = NO_COLOR;
+       else
+#endif
+           mon_color(offset >> 3);
+    } else if ((offset = (glyph - GLYPH_ZAP_OFF)) >= 0) {      /* zap beam */
+       /* see zapdir_to_glyph() in display.c */
+       ch = showsyms[S_vbeam + (offset & 0x3)];
+#ifdef ROGUE_COLOR
+       if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color)
+           color = NO_COLOR;
+       else
+#endif
+           zap_color((offset >> 2));
+    } else if ((offset = (glyph - GLYPH_EXPLODE_OFF)) >= 0) {  /* explosion */
+       ch = showsyms[(offset % MAXEXPCHARS) + S_explode1];
+       explode_color(offset / MAXEXPCHARS);
+    } else if ((offset = (glyph - GLYPH_CMAP_OFF)) >= 0) {     /* cmap */
+       ch = showsyms[offset];
+#ifdef ROGUE_COLOR
+       if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color) {
+           if (offset >= S_vwall && offset <= S_hcdoor)
+               color = CLR_BROWN;
+           else if (offset >= S_arrow_trap && offset <= S_polymorph_trap)
+               color = CLR_MAGENTA;
+           else if (offset == S_corr || offset == S_litcorr)
+               color = CLR_GRAY;
+           else if (offset >= S_room && offset <= S_water)
+               color = CLR_GREEN;
+           else
+               color = NO_COLOR;
+       } else
+#endif
+#ifdef TEXTCOLOR
+           /* provide a visible difference if normal and lit corridor
+            * use the same symbol */
+           if (iflags.use_color &&
+               offset == S_litcorr && ch == showsyms[S_corr])
+               color = CLR_WHITE;
+           else
+#endif
+           cmap_color(offset);
+    } else if ((offset = (glyph - GLYPH_OBJ_OFF)) >= 0) {      /* object */
+       if (offset == BOULDER && iflags.bouldersym) ch = iflags.bouldersym;
+       else ch = oc_syms[(int)objects[offset].oc_class];
+#ifdef ROGUE_COLOR
+       if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color) {
+           switch(objects[offset].oc_class) {
+               case COIN_CLASS: color = CLR_YELLOW; break;
+               case FOOD_CLASS: color = CLR_RED; break;
+               default: color = CLR_BRIGHT_BLUE; break;
+           }
+       } else
+#endif
+           obj_color(offset);
+    } else if ((offset = (glyph - GLYPH_RIDDEN_OFF)) >= 0) {   /* mon ridden */
+       ch = monsyms[(int)mons[offset].mlet];
+#ifdef ROGUE_COLOR
+       if (HAS_ROGUE_IBM_GRAPHICS)
+           /* This currently implies that the hero is here -- monsters */
+           /* don't ride (yet...).  Should we set it to yellow like in */
+           /* the monster case below?  There is no equivalent in rogue. */
+           color = NO_COLOR;   /* no need to check iflags.use_color */
+       else
+#endif
+           mon_color(offset);
+           special |= MG_RIDDEN;
+    } else if ((offset = (glyph - GLYPH_BODY_OFF)) >= 0) {     /* a corpse */
+       ch = oc_syms[(int)objects[CORPSE].oc_class];
+#ifdef ROGUE_COLOR
+       if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color)
+           color = CLR_RED;
+       else
+#endif
+           mon_color(offset);
+           special |= MG_CORPSE;
+    } else if ((offset = (glyph - GLYPH_DETECT_OFF)) >= 0) {   /* mon detect */
+       ch = monsyms[(int)mons[offset].mlet];
+#ifdef ROGUE_COLOR
+       if (HAS_ROGUE_IBM_GRAPHICS)
+           color = NO_COLOR;   /* no need to check iflags.use_color */
+       else
+#endif
+           mon_color(offset);
+       /* Disabled for now; anyone want to get reverse video to work? */
+       /* is_reverse = TRUE; */
+           special |= MG_DETECT;
+    } else if ((offset = (glyph - GLYPH_INVIS_OFF)) >= 0) {    /* invisible */
+       ch = DEF_INVISIBLE;
+#ifdef ROGUE_COLOR
+       if (HAS_ROGUE_IBM_GRAPHICS)
+           color = NO_COLOR;   /* no need to check iflags.use_color */
+       else
+#endif
+           invis_color(offset);
+           special |= MG_INVIS;
+    } else if ((offset = (glyph - GLYPH_PET_OFF)) >= 0) {      /* a pet */
+       ch = monsyms[(int)mons[offset].mlet];
+#ifdef ROGUE_COLOR
+       if (HAS_ROGUE_IBM_GRAPHICS)
+           color = NO_COLOR;   /* no need to check iflags.use_color */
+       else
+#endif
+           pet_color(offset);
+           special |= MG_PET;
+    } else {                                                   /* a monster */
+       ch = monsyms[(int)mons[glyph].mlet];
+#ifdef ROGUE_COLOR
+       if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color) {
+           if (x == u.ux && y == u.uy)
+               /* actually player should be yellow-on-gray if in a corridor */
+               color = CLR_YELLOW;
+           else
+               color = NO_COLOR;
+       } else
+#endif
+       {
+           mon_color(glyph);
+           /* special case the hero for `showrace' option */
+#ifdef TEXTCOLOR
+           if (iflags.use_color && x == u.ux && y == u.uy &&
+                   iflags.showrace && !Upolyd)
+               color = HI_DOMESTIC;
+#endif
+       }
+    }
+
+#ifdef TEXTCOLOR
+    /* Turn off color if no color defined, or rogue level w/o PC graphics. */
+# ifdef REINCARNATION
+#  ifdef ASCIIGRAPH
+    if (!has_color(color) || (Is_rogue_level(&u.uz) && !HAS_ROGUE_IBM_GRAPHICS))
+#  else
+    if (!has_color(color) || Is_rogue_level(&u.uz))
+#  endif
+# else
+    if (!has_color(color))
+# endif
+       color = NO_COLOR;
+#endif
+
+    *ochar = (int)ch;
+    *ospecial = special;
+#ifdef TEXTCOLOR
+    *ocolor = color;
+#endif
+    return;
+}
+
+/*mapglyph.c*/
diff --git a/src/mcastu.c b/src/mcastu.c
new file mode 100644 (file)
index 0000000..93d3b8d
--- /dev/null
@@ -0,0 +1,788 @@
+/*     SCCS Id: @(#)mcastu.c   3.4     2003/01/08      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+/* monster mage spells */
+#define MGC_PSI_BOLT    0
+#define MGC_CURE_SELF   1
+#define MGC_HASTE_SELF  2
+#define MGC_STUN_YOU    3
+#define MGC_DISAPPEAR   4
+#define MGC_WEAKEN_YOU  5
+#define MGC_DESTRY_ARMR         6
+#define MGC_CURSE_ITEMS         7
+#define MGC_AGGRAVATION         8
+#define MGC_SUMMON_MONS         9
+#define MGC_CLONE_WIZ  10
+#define MGC_DEATH_TOUCH        11
+
+/* monster cleric spells */
+#define CLC_OPEN_WOUNDS         0
+#define CLC_CURE_SELF   1
+#define CLC_CONFUSE_YOU         2
+#define CLC_PARALYZE    3
+#define CLC_BLIND_YOU   4
+#define CLC_INSECTS     5
+#define CLC_CURSE_ITEMS         6
+#define CLC_LIGHTNING   7
+#define CLC_FIRE_PILLAR         8
+#define CLC_GEYSER      9
+
+STATIC_DCL void FDECL(cursetxt,(struct monst *,BOOLEAN_P));
+STATIC_DCL int FDECL(choose_magic_spell, (int));
+STATIC_DCL int FDECL(choose_clerical_spell, (int));
+STATIC_DCL void FDECL(cast_wizard_spell,(struct monst *, int,int));
+STATIC_DCL void FDECL(cast_cleric_spell,(struct monst *, int,int));
+STATIC_DCL boolean FDECL(is_undirected_spell,(unsigned int,int));
+STATIC_DCL boolean FDECL(spell_would_be_useless,(struct monst *,unsigned int,int));
+
+#ifdef OVL0
+
+extern const char * const flash_types[];       /* from zap.c */
+
+/* feedback when frustrated monster couldn't cast a spell */
+STATIC_OVL
+void
+cursetxt(mtmp, undirected)
+struct monst *mtmp;
+boolean undirected;
+{
+       if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)) {
+           const char *point_msg;  /* spellcasting monsters are impolite */
+
+           if (undirected)
+               point_msg = "all around, then curses";
+           else if ((Invis && !perceives(mtmp->data) &&
+                       (mtmp->mux != u.ux || mtmp->muy != u.uy)) ||
+                   (youmonst.m_ap_type == M_AP_OBJECT &&
+                       youmonst.mappearance == STRANGE_OBJECT) ||
+                   u.uundetected)
+               point_msg = "and curses in your general direction";
+           else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
+               point_msg = "and curses at your displaced image";
+           else
+               point_msg = "at you, then curses";
+
+           pline("%s points %s.", Monnam(mtmp), point_msg);
+       } else if ((!(moves % 4) || !rn2(4))) {
+           if (flags.soundok) Norep("You hear a mumbled curse.");
+       }
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+/* convert a level based random selection into a specific mage spell;
+   inappropriate choices will be screened out by spell_would_be_useless() */
+STATIC_OVL int
+choose_magic_spell(spellval)
+int spellval;
+{
+    switch (spellval) {
+    case 22:
+    case 21:
+    case 20:
+       return MGC_DEATH_TOUCH;
+    case 19:
+    case 18:
+       return MGC_CLONE_WIZ;
+    case 17:
+    case 16:
+    case 15:
+       return MGC_SUMMON_MONS;
+    case 14:
+    case 13:
+       return MGC_AGGRAVATION;
+    case 12:
+    case 11:
+    case 10:
+       return MGC_CURSE_ITEMS;
+    case 9:
+    case 8:
+       return MGC_DESTRY_ARMR;
+    case 7:
+    case 6:
+       return MGC_WEAKEN_YOU;
+    case 5:
+    case 4:
+       return MGC_DISAPPEAR;
+    case 3:
+       return MGC_STUN_YOU;
+    case 2:
+       return MGC_HASTE_SELF;
+    case 1:
+       return MGC_CURE_SELF;
+    case 0:
+    default:
+       return MGC_PSI_BOLT;
+    }
+}
+
+/* convert a level based random selection into a specific cleric spell */
+STATIC_OVL int
+choose_clerical_spell(spellnum)
+int spellnum;
+{
+    switch (spellnum) {
+    case 13:
+       return CLC_GEYSER;
+    case 12:
+       return CLC_FIRE_PILLAR;
+    case 11:
+       return CLC_LIGHTNING;
+    case 10:
+    case 9:
+       return CLC_CURSE_ITEMS;
+    case 8:
+       return CLC_INSECTS;
+    case 7:
+    case 6:
+       return CLC_BLIND_YOU;
+    case 5:
+    case 4:
+       return CLC_PARALYZE;
+    case 3:
+    case 2:
+       return CLC_CONFUSE_YOU;
+    case 1:
+       return CLC_CURE_SELF;
+    case 0:
+    default:
+       return CLC_OPEN_WOUNDS;
+    }
+}
+
+/* return values:
+ * 1: successful spell
+ * 0: unsuccessful spell
+ */
+int
+castmu(mtmp, mattk, thinks_it_foundyou, foundyou)
+       register struct monst *mtmp;
+       register struct attack *mattk;
+       boolean thinks_it_foundyou;
+       boolean foundyou;
+{
+       int     dmg, ml = mtmp->m_lev;
+       int ret;
+       int spellnum = 0;
+
+       /* Three cases:
+        * -- monster is attacking you.  Search for a useful spell.
+        * -- monster thinks it's attacking you.  Search for a useful spell,
+        *    without checking for undirected.  If the spell found is directed,
+        *    it fails with cursetxt() and loss of mspec_used.
+        * -- monster isn't trying to attack.  Select a spell once.  Don't keep
+        *    searching; if that spell is not useful (or if it's directed),
+        *    return and do something else. 
+        * Since most spells are directed, this means that a monster that isn't
+        * attacking casts spells only a small portion of the time that an
+        * attacking monster does.
+        */
+       if ((mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) && ml) {
+           int cnt = 40;
+
+           do {
+               spellnum = rn2(ml);
+               if (mattk->adtyp == AD_SPEL)
+                   spellnum = choose_magic_spell(spellnum);
+               else
+                   spellnum = choose_clerical_spell(spellnum);
+               /* not trying to attack?  don't allow directed spells */
+               if (!thinks_it_foundyou) {
+                   if (!is_undirected_spell(mattk->adtyp, spellnum) ||
+                       spell_would_be_useless(mtmp, mattk->adtyp, spellnum)) {
+                       if (foundyou)
+                           impossible("spellcasting monster found you and doesn't know it?");
+                       return 0;
+                   }
+                   break;
+               }
+           } while(--cnt > 0 &&
+                   spell_would_be_useless(mtmp, mattk->adtyp, spellnum));
+           if (cnt == 0) return 0;
+       }
+
+       /* monster unable to cast spells? */
+       if(mtmp->mcan || mtmp->mspec_used || !ml) {
+           cursetxt(mtmp, is_undirected_spell(mattk->adtyp, spellnum));
+           return(0);
+       }
+
+       if (mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) {
+           mtmp->mspec_used = 10 - mtmp->m_lev;
+           if (mtmp->mspec_used < 2) mtmp->mspec_used = 2;
+       }
+
+       /* monster can cast spells, but is casting a directed spell at the
+          wrong place?  If so, give a message, and return.  Do this *after*
+          penalizing mspec_used. */
+       if (!foundyou && thinks_it_foundyou &&
+               !is_undirected_spell(mattk->adtyp, spellnum)) {
+           pline("%s casts a spell at %s!",
+               canseemon(mtmp) ? Monnam(mtmp) : "Something",
+               levl[mtmp->mux][mtmp->muy].typ == WATER
+                   ? "empty water" : "thin air");
+           return(0);
+       }
+
+       nomul(0);
+       if(rn2(ml*10) < (mtmp->mconf ? 100 : 20)) {     /* fumbled attack */
+           if (canseemon(mtmp) && flags.soundok)
+               pline_The("air crackles around %s.", mon_nam(mtmp));
+           return(0);
+       }
+       if (canspotmon(mtmp) || !is_undirected_spell(mattk->adtyp, spellnum)) {
+           pline("%s casts a spell%s!",
+                 canspotmon(mtmp) ? Monnam(mtmp) : "Something",
+                 is_undirected_spell(mattk->adtyp, spellnum) ? "" :
+                 (Invisible && !perceives(mtmp->data) && 
+                  (mtmp->mux != u.ux || mtmp->muy != u.uy)) ?
+                 " at a spot near you" :
+                 (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) ?
+                 " at your displaced image" :
+                 " at you");
+       }
+
+/*
+ *     As these are spells, the damage is related to the level
+ *     of the monster casting the spell.
+ */
+       if (!foundyou) {
+           dmg = 0;
+           if (mattk->adtyp != AD_SPEL && mattk->adtyp != AD_CLRC) {
+               impossible(
+             "%s casting non-hand-to-hand version of hand-to-hand spell %d?",
+                          Monnam(mtmp), mattk->adtyp);
+               return(0);
+           }
+       } else if (mattk->damd)
+           dmg = d((int)((ml/2) + mattk->damn), (int)mattk->damd);
+       else dmg = d((int)((ml/2) + 1), 6);
+       if (Half_spell_damage) dmg = (dmg+1) / 2;
+
+       ret = 1;
+
+       switch (mattk->adtyp) {
+
+           case AD_FIRE:
+               pline("You're enveloped in flames.");
+               if(Fire_resistance) {
+                       shieldeff(u.ux, u.uy);
+                       pline("But you resist the effects.");
+                       dmg = 0;
+               }
+               burn_away_slime();
+               break;
+           case AD_COLD:
+               pline("You're covered in frost.");
+               if(Cold_resistance) {
+                       shieldeff(u.ux, u.uy);
+                       pline("But you resist the effects.");
+                       dmg = 0;
+               }
+               break;
+           case AD_MAGM:
+               You("are hit by a shower of missiles!");
+               if(Antimagic) {
+                       shieldeff(u.ux, u.uy);
+                       pline_The("missiles bounce off!");
+                       dmg = 0;
+               } else dmg = d((int)mtmp->m_lev/2 + 1,6);
+               break;
+           case AD_SPEL:       /* wizard spell */
+           case AD_CLRC:       /* clerical spell */
+           {
+               if (mattk->adtyp == AD_SPEL)
+                   cast_wizard_spell(mtmp, dmg, spellnum);
+               else
+                   cast_cleric_spell(mtmp, dmg, spellnum);
+               dmg = 0; /* done by the spell casting functions */
+               break;
+           }
+       }
+       if(dmg) mdamageu(mtmp, dmg);
+       return(ret);
+}
+
+/* monster wizard and cleric spellcasting functions */
+/*
+   If dmg is zero, then the monster is not casting at you.
+   If the monster is intentionally not casting at you, we have previously
+   called spell_would_be_useless() and spellnum should always be a valid
+   undirected spell.
+   If you modify either of these, be sure to change is_undirected_spell()
+   and spell_would_be_useless().
+ */
+STATIC_OVL
+void
+cast_wizard_spell(mtmp, dmg, spellnum)
+struct monst *mtmp;
+int dmg;
+int spellnum;
+{
+    if (dmg == 0 && !is_undirected_spell(AD_SPEL, spellnum)) {
+       impossible("cast directed wizard spell (%d) with dmg=0?", spellnum);
+       return;
+    }
+
+    switch (spellnum) {
+    case MGC_DEATH_TOUCH:
+       pline("Oh no, %s's using the touch of death!", mhe(mtmp));
+       if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
+           You("seem no deader than before.");
+       } else if (!Antimagic && rn2(mtmp->m_lev) > 12) {
+           if (Hallucination) {
+               You("have an out of body experience.");
+           } else {
+               killer_format = KILLED_BY_AN;
+               killer = "touch of death";
+               done(DIED);
+           }
+       } else {
+           if (Antimagic) shieldeff(u.ux, u.uy);
+           pline("Lucky for you, it didn't work!");
+       }
+       dmg = 0;
+       break;
+    case MGC_CLONE_WIZ:
+       if (mtmp->iswiz && flags.no_of_wizards == 1) {
+           pline("Double Trouble...");
+           clonewiz();
+           dmg = 0;
+       } else
+           impossible("bad wizard cloning?");
+       break;
+    case MGC_SUMMON_MONS:
+    {
+       int count;
+
+       count = nasty(mtmp);    /* summon something nasty */
+       if (mtmp->iswiz)
+           verbalize("Destroy the thief, my pet%s!", plur(count));
+       else {
+           const char *mappear =
+               (count == 1) ? "A monster appears" : "Monsters appear";
+
+           /* messages not quite right if plural monsters created but
+              only a single monster is seen */
+           if (Invisible && !perceives(mtmp->data) &&
+                                   (mtmp->mux != u.ux || mtmp->muy != u.uy))
+               pline("%s around a spot near you!", mappear);
+           else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
+               pline("%s around your displaced image!", mappear);
+           else
+               pline("%s from nowhere!", mappear);
+       }
+       dmg = 0;
+       break;
+    }
+    case MGC_AGGRAVATION:
+       You_feel("that monsters are aware of your presence.");
+       aggravate();
+       dmg = 0;
+       break;
+    case MGC_CURSE_ITEMS:
+       You_feel("as if you need some help.");
+       rndcurse();
+       dmg = 0;
+       break;
+    case MGC_DESTRY_ARMR:
+       if (Antimagic) {
+           shieldeff(u.ux, u.uy);
+           pline("A field of force surrounds you!");
+       } else if (!destroy_arm(some_armor(&youmonst))) {
+           Your("skin itches.");
+       }
+       dmg = 0;
+       break;
+    case MGC_WEAKEN_YOU:               /* drain strength */
+       if (Antimagic) {
+           shieldeff(u.ux, u.uy);
+           You_feel("momentarily weakened.");
+       } else {
+           You("suddenly feel weaker!");
+           dmg = mtmp->m_lev - 6;
+           if (Half_spell_damage) dmg = (dmg + 1) / 2;
+           losestr(rnd(dmg));
+           if (u.uhp < 1)
+               done_in_by(mtmp);
+       }
+       dmg = 0;
+       break;
+    case MGC_DISAPPEAR:                /* makes self invisible */
+       if (!mtmp->minvis && !mtmp->invis_blkd) {
+           if (canseemon(mtmp))
+               pline("%s suddenly %s!", Monnam(mtmp),
+                     !See_invisible ? "disappears" : "becomes transparent");
+           mon_set_minvis(mtmp);
+           dmg = 0;
+       } else
+           impossible("no reason for monster to cast disappear spell?");
+       break;
+    case MGC_STUN_YOU:
+       if (Antimagic || Free_action) {
+           shieldeff(u.ux, u.uy);
+           if (!Stunned)
+               You_feel("momentarily disoriented.");
+           make_stunned(1L, FALSE);
+       } else {
+           You(Stunned ? "struggle to keep your balance." : "reel...");
+           dmg = d(ACURR(A_DEX) < 12 ? 6 : 4, 4);
+           if (Half_spell_damage) dmg = (dmg + 1) / 2;
+           make_stunned(HStun + dmg, FALSE);
+       }
+       dmg = 0;
+       break;
+    case MGC_HASTE_SELF:
+       mon_adjust_speed(mtmp, 1, (struct obj *)0);
+       dmg = 0;
+       break;
+    case MGC_CURE_SELF:
+       if (mtmp->mhp < mtmp->mhpmax) {
+           if (canseemon(mtmp))
+               pline("%s looks better.", Monnam(mtmp));
+           /* note: player healing does 6d4; this used to do 1d8 */
+           if ((mtmp->mhp += d(3,6)) > mtmp->mhpmax)
+               mtmp->mhp = mtmp->mhpmax;
+           dmg = 0;
+       }
+       break;
+    case MGC_PSI_BOLT:
+       /* prior to 3.4.0 Antimagic was setting the damage to 1--this
+          made the spell virtually harmless to players with magic res. */
+       if (Antimagic) {
+           shieldeff(u.ux, u.uy);
+           dmg = (dmg + 1) / 2;
+       }
+       if (dmg <= 5)
+           You("get a slight %sache.", body_part(HEAD));
+       else if (dmg <= 10)
+           Your("brain is on fire!");
+       else if (dmg <= 20)
+           Your("%s suddenly aches painfully!", body_part(HEAD));
+       else
+           Your("%s suddenly aches very painfully!", body_part(HEAD));
+       break;
+    default:
+       impossible("mcastu: invalid magic spell (%d)", spellnum);
+       dmg = 0;
+       break;
+    }
+
+    if (dmg) mdamageu(mtmp, dmg);
+}
+
+STATIC_OVL
+void
+cast_cleric_spell(mtmp, dmg, spellnum)
+struct monst *mtmp;
+int dmg;
+int spellnum;
+{
+    if (dmg == 0 && !is_undirected_spell(AD_CLRC, spellnum)) {
+       impossible("cast directed cleric spell (%d) with dmg=0?", spellnum);
+       return;
+    }
+
+    switch (spellnum) {
+    case CLC_GEYSER:
+       /* this is physical damage, not magical damage */
+       pline("A sudden geyser slams into you from nowhere!");
+       dmg = d(8, 6);
+       if (Half_physical_damage) dmg = (dmg + 1) / 2;
+       break;
+    case CLC_FIRE_PILLAR:
+       pline("A pillar of fire strikes all around you!");
+       if (Fire_resistance) {
+           shieldeff(u.ux, u.uy);
+           dmg = 0;
+       } else
+           dmg = d(8, 6);
+       if (Half_spell_damage) dmg = (dmg + 1) / 2;
+       burn_away_slime();
+       (void) burnarmor(&youmonst);
+       destroy_item(SCROLL_CLASS, AD_FIRE);
+       destroy_item(POTION_CLASS, AD_FIRE);
+       destroy_item(SPBOOK_CLASS, AD_FIRE);
+       (void) burn_floor_paper(u.ux, u.uy, TRUE, FALSE);
+       break;
+    case CLC_LIGHTNING:
+    {
+       boolean reflects;
+
+       pline("A bolt of lightning strikes down at you from above!");
+       reflects = ureflects("It bounces off your %s%s.", "");
+       if (reflects || Shock_resistance) {
+           shieldeff(u.ux, u.uy);
+           dmg = 0;
+           if (reflects)
+               break;
+       } else
+           dmg = d(8, 6);
+       if (Half_spell_damage) dmg = (dmg + 1) / 2;
+       destroy_item(WAND_CLASS, AD_ELEC);
+       destroy_item(RING_CLASS, AD_ELEC);
+       break;
+    }
+    case CLC_CURSE_ITEMS:
+       You_feel("as if you need some help.");
+       rndcurse();
+       dmg = 0;
+       break;
+    case CLC_INSECTS:
+      {
+       /* Try for insects, and if there are none
+          left, go for (sticks to) snakes.  -3. */
+       struct permonst *pm = mkclass(S_ANT,0);
+       struct monst *mtmp2 = (struct monst *)0;
+       char let = (pm ? S_ANT : S_SNAKE);
+       boolean success;
+       int i;
+       coord bypos;
+       int quan;
+
+       quan = (mtmp->m_lev < 2) ? 1 : rnd((int)mtmp->m_lev / 2);
+       if (quan < 3) quan = 3;
+       success = pm ? TRUE : FALSE;
+       for (i = 0; i <= quan; i++) {
+           if (!enexto(&bypos, mtmp->mux, mtmp->muy, mtmp->data))
+               break;
+           if ((pm = mkclass(let,0)) != 0 &&
+                   (mtmp2 = makemon(pm, bypos.x, bypos.y, NO_MM_FLAGS)) != 0) {
+               success = TRUE;
+               mtmp2->msleeping = mtmp2->mpeaceful = mtmp2->mtame = 0;
+               set_malign(mtmp2);
+           }
+       }
+       /* Not quite right:
+         * -- message doesn't always make sense for unseen caster (particularly
+        *    the first message)
+         * -- message assumes plural monsters summoned (non-plural should be
+         *    very rare, unlike in nasty())
+         * -- message assumes plural monsters seen
+         */
+       if (!success)
+           pline("%s casts at a clump of sticks, but nothing happens.",
+               Monnam(mtmp));
+       else if (let == S_SNAKE)
+           pline("%s transforms a clump of sticks into snakes!",
+               Monnam(mtmp));
+       else if (Invisible && !perceives(mtmp->data) &&
+                               (mtmp->mux != u.ux || mtmp->muy != u.uy))
+           pline("%s summons insects around a spot near you!",
+               Monnam(mtmp));
+       else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
+           pline("%s summons insects around your displaced image!",
+               Monnam(mtmp));
+       else
+           pline("%s summons insects!", Monnam(mtmp));
+       dmg = 0;
+       break;
+      }
+    case CLC_BLIND_YOU:
+       /* note: resists_blnd() doesn't apply here */
+       if (!Blinded) {
+           int num_eyes = eyecount(youmonst.data);
+           pline("Scales cover your %s!",
+                 (num_eyes == 1) ?
+                 body_part(EYE) : makeplural(body_part(EYE)));
+           make_blinded(Half_spell_damage ? 100L : 200L, FALSE);
+           if (!Blind) Your(vision_clears);
+           dmg = 0;
+       } else
+           impossible("no reason for monster to cast blindness spell?");
+       break;
+    case CLC_PARALYZE:
+       if (Antimagic || Free_action) {
+           shieldeff(u.ux, u.uy);
+           if (multi >= 0)
+               You("stiffen briefly.");
+           nomul(-1);
+       } else {
+           if (multi >= 0)
+               You("are frozen in place!");
+           dmg = 4 + (int)mtmp->m_lev;
+           if (Half_spell_damage) dmg = (dmg + 1) / 2;
+           nomul(-dmg);
+       }
+       dmg = 0;
+       break;
+    case CLC_CONFUSE_YOU:
+       if (Antimagic) {
+           shieldeff(u.ux, u.uy);
+           You_feel("momentarily dizzy.");
+       } else {
+           boolean oldprop = !!Confusion;
+
+           dmg = (int)mtmp->m_lev;
+           if (Half_spell_damage) dmg = (dmg + 1) / 2;
+           make_confused(HConfusion + dmg, TRUE);
+           if (Hallucination)
+               You_feel("%s!", oldprop ? "trippier" : "trippy");
+           else
+               You_feel("%sconfused!", oldprop ? "more " : "");
+       }
+       dmg = 0;
+       break;
+    case CLC_CURE_SELF:
+       if (mtmp->mhp < mtmp->mhpmax) {
+           if (canseemon(mtmp))
+               pline("%s looks better.", Monnam(mtmp));
+           /* note: player healing does 6d4; this used to do 1d8 */
+           if ((mtmp->mhp += d(3,6)) > mtmp->mhpmax)
+               mtmp->mhp = mtmp->mhpmax;
+           dmg = 0;
+       }
+       break;
+    case CLC_OPEN_WOUNDS:
+       if (Antimagic) {
+           shieldeff(u.ux, u.uy);
+           dmg = (dmg + 1) / 2;
+       }
+       if (dmg <= 5)
+           Your("skin itches badly for a moment.");
+       else if (dmg <= 10)
+           pline("Wounds appear on your body!");
+       else if (dmg <= 20)
+           pline("Severe wounds appear on your body!");
+       else
+           Your("body is covered with painful wounds!");
+       break;
+    default:
+       impossible("mcastu: invalid clerical spell (%d)", spellnum);
+       dmg = 0;
+       break;
+    }
+
+    if (dmg) mdamageu(mtmp, dmg);
+}
+
+STATIC_DCL
+boolean
+is_undirected_spell(adtyp, spellnum)
+unsigned int adtyp;
+int spellnum;
+{
+    if (adtyp == AD_SPEL) {
+       switch (spellnum) {
+       case MGC_CLONE_WIZ:
+       case MGC_SUMMON_MONS:
+       case MGC_AGGRAVATION:
+       case MGC_DISAPPEAR:
+       case MGC_HASTE_SELF:
+       case MGC_CURE_SELF:
+           return TRUE;
+       default:
+           break;
+       }
+    } else if (adtyp == AD_CLRC) {
+       switch (spellnum) {
+       case CLC_INSECTS:
+       case CLC_CURE_SELF:
+           return TRUE;
+       default:
+           break;
+       }
+    }
+    return FALSE;
+}
+
+/* Some spells are useless under some circumstances. */
+STATIC_DCL
+boolean
+spell_would_be_useless(mtmp, adtyp, spellnum)
+struct monst *mtmp;
+unsigned int adtyp;
+int spellnum;
+{
+    /* Some spells don't require the player to really be there and can be cast
+     * by the monster when you're invisible, yet still shouldn't be cast when
+     * the monster doesn't even think you're there.
+     * This check isn't quite right because it always uses your real position.
+     * We really want something like "if the monster could see mux, muy".
+     */
+    boolean mcouldseeu = couldsee(mtmp->mx, mtmp->my);
+
+    if (adtyp == AD_SPEL) {
+       /* aggravate monsters, etc. won't be cast by peaceful monsters */
+       if (mtmp->mpeaceful && (spellnum == MGC_AGGRAVATION ||
+               spellnum == MGC_SUMMON_MONS || spellnum == MGC_CLONE_WIZ))
+           return TRUE;
+       /* haste self when already fast */
+       if (mtmp->permspeed == MFAST && spellnum == MGC_HASTE_SELF)
+           return TRUE;
+       /* invisibility when already invisible */
+       if ((mtmp->minvis || mtmp->invis_blkd) && spellnum == MGC_DISAPPEAR)
+           return TRUE;
+       /* peaceful monster won't cast invisibility if you can't see invisible,
+          same as when monsters drink potions of invisibility.  This doesn't
+          really make a lot of sense, but lets the player avoid hitting
+          peaceful monsters by mistake */
+       if (mtmp->mpeaceful && !See_invisible && spellnum == MGC_DISAPPEAR)
+           return TRUE;
+       /* healing when already healed */
+       if (mtmp->mhp == mtmp->mhpmax && spellnum == MGC_CURE_SELF)
+           return TRUE;
+       /* don't summon monsters if it doesn't think you're around */
+       if (!mcouldseeu && (spellnum == MGC_SUMMON_MONS ||
+               (!mtmp->iswiz && spellnum == MGC_CLONE_WIZ)))
+           return TRUE;
+       if ((!mtmp->iswiz || flags.no_of_wizards > 1)
+                                               && spellnum == MGC_CLONE_WIZ)
+           return TRUE;
+    } else if (adtyp == AD_CLRC) {
+       /* summon insects/sticks to snakes won't be cast by peaceful monsters */
+       if (mtmp->mpeaceful && spellnum == CLC_INSECTS)
+           return TRUE;
+       /* healing when already healed */
+       if (mtmp->mhp == mtmp->mhpmax && spellnum == CLC_CURE_SELF)
+           return TRUE;
+       /* don't summon insects if it doesn't think you're around */
+       if (!mcouldseeu && spellnum == CLC_INSECTS)
+           return TRUE;
+       /* blindness spell on blinded player */
+       if (Blinded && spellnum == CLC_BLIND_YOU)
+           return TRUE;
+    }
+    return FALSE;
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+/* convert 1..10 to 0..9; add 10 for second group (spell casting) */
+#define ad_to_typ(k) (10 + (int)k - 1)
+
+int
+buzzmu(mtmp, mattk)            /* monster uses spell (ranged) */
+       register struct monst *mtmp;
+       register struct attack  *mattk;
+{
+       /* don't print constant stream of curse messages for 'normal'
+          spellcasting monsters at range */
+       if (mattk->adtyp > AD_SPC2)
+           return(0);
+
+       if (mtmp->mcan) {
+           cursetxt(mtmp, FALSE);
+           return(0);
+       }
+       if(lined_up(mtmp) && rn2(3)) {
+           nomul(0);
+           if(mattk->adtyp && (mattk->adtyp < 11)) { /* no cf unsigned >0 */
+               if(canseemon(mtmp))
+                   pline("%s zaps you with a %s!", Monnam(mtmp),
+                         flash_types[ad_to_typ(mattk->adtyp)]);
+               buzz(-ad_to_typ(mattk->adtyp), (int)mattk->damn,
+                    mtmp->mx, mtmp->my, sgn(tbx), sgn(tby));
+           } else impossible("Monster spell %d cast", mattk->adtyp-1);
+       }
+       return(1);
+}
+
+#endif /* OVL0 */
+
+/*mcastu.c*/
diff --git a/src/mhitm.c b/src/mhitm.c
new file mode 100644 (file)
index 0000000..912f1d2
--- /dev/null
@@ -0,0 +1,1460 @@
+/*     SCCS Id: @(#)mhitm.c    3.4     2003/01/02      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "artifact.h"
+#include "edog.h"
+
+extern boolean notonhead;
+
+#ifdef OVLB
+
+static NEARDATA boolean vis, far_noise;
+static NEARDATA long noisetime;
+static NEARDATA struct obj *otmp;
+
+static const char brief_feeling[] =
+       "have a %s feeling for a moment, then it passes.";
+
+STATIC_DCL char *FDECL(mon_nam_too, (char *,struct monst *,struct monst *));
+STATIC_DCL void FDECL(mrustm, (struct monst *, struct monst *, struct obj *));
+STATIC_DCL int FDECL(hitmm, (struct monst *,struct monst *,struct attack *));
+STATIC_DCL int FDECL(gazemm, (struct monst *,struct monst *,struct attack *));
+STATIC_DCL int FDECL(gulpmm, (struct monst *,struct monst *,struct attack *));
+STATIC_DCL int FDECL(explmm, (struct monst *,struct monst *,struct attack *));
+STATIC_DCL int FDECL(mdamagem, (struct monst *,struct monst *,struct attack *));
+STATIC_DCL void FDECL(mswingsm, (struct monst *, struct monst *, struct obj *));
+STATIC_DCL void FDECL(noises,(struct monst *,struct attack *));
+STATIC_DCL void FDECL(missmm,(struct monst *,struct monst *,struct attack *));
+STATIC_DCL int FDECL(passivemm, (struct monst *, struct monst *, BOOLEAN_P, int));
+
+/* 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.
+ */
+static int dieroll;
+
+/* returns mon_nam(mon) relative to other_mon; normal name unless they're
+   the same, in which case the reference is to {him|her|it} self */
+STATIC_OVL char *
+mon_nam_too(outbuf, mon, other_mon)
+char *outbuf;
+struct monst *mon, *other_mon;
+{
+       Strcpy(outbuf, mon_nam(mon));
+       if (mon == other_mon)
+           switch (pronoun_gender(mon)) {
+           case 0:     Strcpy(outbuf, "himself");  break;
+           case 1:     Strcpy(outbuf, "herself");  break;
+           default:    Strcpy(outbuf, "itself"); break;
+           }
+       return outbuf;
+}
+
+STATIC_OVL void
+noises(magr, mattk)
+       register struct monst *magr;
+       register struct attack *mattk;
+{
+       boolean farq = (distu(magr->mx, magr->my) > 15);
+
+       if(flags.soundok && (farq != far_noise || moves-noisetime > 10)) {
+               far_noise = farq;
+               noisetime = moves;
+               You_hear("%s%s.",
+                       (mattk->aatyp == AT_EXPL) ? "an explosion" : "some noises",
+                       farq ? " in the distance" : "");
+       }
+}
+
+STATIC_OVL
+void
+missmm(magr, mdef, mattk)
+       register struct monst *magr, *mdef;
+       struct attack *mattk;
+{
+       const char *fmt;
+       char buf[BUFSZ], mdef_name[BUFSZ];
+
+       if (vis) {
+               if (!canspotmon(magr))
+                   map_invisible(magr->mx, magr->my);
+               if (!canspotmon(mdef))
+                   map_invisible(mdef->mx, mdef->my);
+               if (mdef->m_ap_type) seemimic(mdef);
+               if (magr->m_ap_type) seemimic(magr);
+               fmt = (could_seduce(magr,mdef,mattk) && !magr->mcan) ?
+                       "%s pretends to be friendly to" : "%s misses";
+               Sprintf(buf, fmt, Monnam(magr));
+               pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr));
+       } else  noises(magr, mattk);
+}
+
+/*
+ *  fightm()  -- fight some other monster
+ *
+ *  Returns:
+ *     0 - Monster did nothing.
+ *     1 - If the monster made an attack.  The monster might have died.
+ *
+ *  There is an exception to the above.  If mtmp has the hero swallowed,
+ *  then we report that the monster did nothing so it will continue to
+ *  digest the hero.
+ */
+int
+fightm(mtmp)           /* have monsters fight each other */
+       register struct monst *mtmp;
+{
+       register struct monst *mon, *nmon;
+       int result, has_u_swallowed;
+#ifdef LINT
+       nmon = 0;
+#endif
+       /* perhaps the monster will resist Conflict */
+       if(resist(mtmp, RING_CLASS, 0, 0))
+           return(0);
+
+       if(u.ustuck == mtmp) {
+           /* perhaps we're holding it... */
+           if(itsstuck(mtmp))
+               return(0);
+       }
+       has_u_swallowed = (u.uswallow && (mtmp == u.ustuck));
+
+       for(mon = fmon; mon; mon = nmon) {
+           nmon = mon->nmon;
+           if(nmon == mtmp) nmon = mtmp->nmon;
+           /* Be careful to ignore monsters that are already dead, since we
+            * might be calling this before we've cleaned them up.  This can
+            * happen if the monster attacked a cockatrice bare-handedly, for
+            * instance.
+            */
+           if(mon != mtmp && !DEADMONSTER(mon)) {
+               if(monnear(mtmp,mon->mx,mon->my)) {
+                   if(!u.uswallow && (mtmp == u.ustuck)) {
+                       if(!rn2(4)) {
+                           pline("%s releases you!", Monnam(mtmp));
+                           u.ustuck = 0;
+                       } else
+                           break;
+                   }
+
+                   /* mtmp can be killed */
+                   bhitpos.x = mon->mx;
+                   bhitpos.y = mon->my;
+                   notonhead = 0;
+                   result = mattackm(mtmp,mon);
+
+                   if (result & MM_AGR_DIED) return 1; /* mtmp died */
+                   /*
+                    *  If mtmp has the hero swallowed, lie and say there
+                    *  was no attack (this allows mtmp to digest the hero).
+                    */
+                   if (has_u_swallowed) return 0;
+
+                   /* Allow attacked monsters a chance to hit back. Primarily
+                    * to allow monsters that resist conflict to respond.
+                    */
+                   if ((result & MM_HIT) && !(result & MM_DEF_DIED) &&
+                       rn2(4) && mon->movement >= NORMAL_SPEED) {
+                       mon->movement -= NORMAL_SPEED;
+                       notonhead = 0;
+                       (void) mattackm(mon, mtmp);     /* return attack */
+                   }
+
+                   return ((result & MM_HIT) ? 1 : 0);
+               }
+           }
+       }
+       return 0;
+}
+
+/*
+ * mattackm() -- a monster attacks another monster.
+ *
+ * This function returns a result bitfield:
+ *
+ *         --------- aggressor died
+ *        /  ------- defender died
+ *       /  /  ----- defender was hit
+ *      /  /  /
+ *     x  x  x
+ *
+ *     0x4     MM_AGR_DIED
+ *     0x2     MM_DEF_DIED
+ *     0x1     MM_HIT
+ *     0x0     MM_MISS
+ *
+ * Each successive attack has a lower probability of hitting.  Some rely on the
+ * success of previous attacks.  ** this doen't seem to be implemented -dl **
+ *
+ * In the case of exploding monsters, the monster dies as well.
+ */
+int
+mattackm(magr, mdef)
+    register struct monst *magr,*mdef;
+{
+    int                    i,          /* loop counter */
+                   tmp,        /* amour class difference */
+                   strike,     /* hit this attack */
+                   attk,       /* attack attempted this time */
+                   struck = 0, /* hit at least once */
+                   res[NATTK]; /* results of all attacks */
+    struct attack   *mattk, alt_attk;
+    struct permonst *pa, *pd;
+
+    if (!magr || !mdef) return(MM_MISS);               /* mike@genat */
+    if (!magr->mcanmove || magr->msleeping) return(MM_MISS);
+    pa = magr->data;  pd = mdef->data;
+
+    /* Grid bugs cannot attack at an angle. */
+    if (pa == &mons[PM_GRID_BUG] && magr->mx != mdef->mx
+                                               && magr->my != mdef->my)
+       return(MM_MISS);
+
+    /* Calculate the armour class differential. */
+    tmp = find_mac(mdef) + magr->m_lev;
+    if (mdef->mconf || !mdef->mcanmove || mdef->msleeping) {
+       tmp += 4;
+       mdef->msleeping = 0;
+    }
+
+    /* undetect monsters become un-hidden if they are attacked */
+    if (mdef->mundetected) {
+       mdef->mundetected = 0;
+       newsym(mdef->mx, mdef->my);
+       if(canseemon(mdef) && !sensemon(mdef)) {
+           if (u.usleep) You("dream of %s.",
+                               (mdef->data->geno & G_UNIQ) ?
+                               a_monnam(mdef) : makeplural(m_monnam(mdef)));
+           else pline("Suddenly, you notice %s.", a_monnam(mdef));
+       }
+    }
+
+    /* Elves hate orcs. */
+    if (is_elf(pa) && is_orc(pd)) tmp++;
+
+
+    /* Set up the visibility of action */
+    vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my) && (canspotmon(magr) || canspotmon(mdef)));
+
+    /* Set flag indicating monster has moved this turn.  Necessary since a
+     * monster might get an attack out of sequence (i.e. before its move) in
+     * some cases, in which case this still counts as its move for the round
+     * and it shouldn't move again.
+     */
+    magr->mlstmv = monstermoves;
+
+    /* Now perform all attacks for the monster. */
+    for (i = 0; i < NATTK; i++) {
+       res[i] = MM_MISS;
+       mattk = getmattk(pa, i, res, &alt_attk);
+       otmp = (struct obj *)0;
+       attk = 1;
+       switch (mattk->aatyp) {
+           case AT_WEAP:               /* "hand to hand" attacks */
+               if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) {
+                   magr->weapon_check = NEED_HTH_WEAPON;
+                   if (mon_wield_item(magr) != 0) return 0;
+               }
+               possibly_unwield(magr, FALSE);
+               otmp = MON_WEP(magr);
+
+               if (otmp) {
+                   if (vis) mswingsm(magr, mdef, otmp);
+                   tmp += hitval(otmp, mdef);
+               }
+               /* fall through */
+           case AT_CLAW:
+           case AT_KICK:
+           case AT_BITE:
+           case AT_STNG:
+           case AT_TUCH:
+           case AT_BUTT:
+           case AT_TENT:
+               /* Nymph that teleported away on first attack? */
+               if (distmin(magr->mx,magr->my,mdef->mx,mdef->my) > 1)
+                   return MM_MISS;
+               /* Monsters won't attack cockatrices physically if they
+                * have a weapon instead.  This instinct doesn't work for
+                * players, or under conflict or confusion. 
+                */
+               if (!magr->mconf && !Conflict && otmp &&
+                   mattk->aatyp != AT_WEAP && touch_petrifies(mdef->data)) {
+                   strike = 0;
+                   break;
+               }
+               dieroll = rnd(20 + i);
+               strike = (tmp > dieroll);
+               /* KMH -- don't accumulate to-hit bonuses */
+               if (otmp)
+                   tmp -= hitval(otmp, mdef);
+               if (strike) {
+                   res[i] = hitmm(magr, mdef, mattk);
+                   if((mdef->data == &mons[PM_BLACK_PUDDING] || mdef->data == &mons[PM_BROWN_PUDDING])
+                      && otmp && objects[otmp->otyp].oc_material == IRON
+                      && mdef->mhp > 1 && !mdef->mcan)
+                   {
+                       if (clone_mon(mdef, 0, 0)) {
+                           if (vis) {
+                               char buf[BUFSZ];
+
+                               Strcpy(buf, Monnam(mdef));
+                               pline("%s divides as %s hits it!", buf, mon_nam(magr));
+                           }
+                       }
+                   }
+               } else
+                   missmm(magr, mdef, mattk);
+               break;
+
+           case AT_HUGS:       /* automatic if prev two attacks succeed */
+               strike = (i >= 2 && res[i-1] == MM_HIT && res[i-2] == MM_HIT);
+               if (strike)
+                   res[i] = hitmm(magr, mdef, mattk);
+
+               break;
+
+           case AT_GAZE:
+               strike = 0;     /* will not wake up a sleeper */
+               res[i] = gazemm(magr, mdef, mattk);
+               break;
+
+           case AT_EXPL:
+               res[i] = explmm(magr, mdef, mattk);
+               if (res[i] == MM_MISS) { /* cancelled--no attack */
+                   strike = 0;
+                   attk = 0;
+               } else
+                   strike = 1; /* automatic hit */
+               break;
+
+           case AT_ENGL:
+#ifdef STEED
+               if (u.usteed && (mdef == u.usteed)) {
+                   strike = 0;
+                   break;
+               } 
+#endif
+               /* Engulfing attacks are directed at the hero if
+                * possible. -dlc
+                */
+               if (u.uswallow && magr == u.ustuck)
+                   strike = 0;
+               else {
+                   if ((strike = (tmp > rnd(20+i))))
+                       res[i] = gulpmm(magr, mdef, mattk);
+                   else
+                       missmm(magr, mdef, mattk);
+               }
+               break;
+
+           default:            /* no attack */
+               strike = 0;
+               attk = 0;
+               break;
+       }
+
+       if (attk && !(res[i] & MM_AGR_DIED))
+           res[i] = passivemm(magr, mdef, strike, res[i] & MM_DEF_DIED);
+
+       if (res[i] & MM_DEF_DIED) return res[i];
+
+       /*
+        *  Wake up the defender.  NOTE:  this must follow the check
+        *  to see if the defender died.  We don't want to modify
+        *  unallocated monsters!
+        */
+       if (strike) mdef->msleeping = 0;
+
+       if (res[i] & MM_AGR_DIED)  return res[i];
+       /* return if aggressor can no longer attack */
+       if (!magr->mcanmove || magr->msleeping) return res[i];
+       if (res[i] & MM_HIT) struck = 1;        /* at least one hit */
+    }
+
+    return(struck ? MM_HIT : MM_MISS);
+}
+
+/* Returns the result of mdamagem(). */
+STATIC_OVL int
+hitmm(magr, mdef, mattk)
+       register struct monst *magr,*mdef;
+       struct  attack *mattk;
+{
+       if(vis){
+               int compat;
+               char buf[BUFSZ], mdef_name[BUFSZ];
+
+               if (!canspotmon(magr))
+                   map_invisible(magr->mx, magr->my);
+               if (!canspotmon(mdef))
+                   map_invisible(mdef->mx, mdef->my);
+               if(mdef->m_ap_type) seemimic(mdef);
+               if(magr->m_ap_type) seemimic(magr);
+               if((compat = could_seduce(magr,mdef,mattk)) && !magr->mcan) {
+                       Sprintf(buf, "%s %s", Monnam(magr),
+                               mdef->mcansee ? "smiles at" : "talks to");
+                       pline("%s %s %s.", buf, mon_nam(mdef),
+                               compat == 2 ?
+                                       "engagingly" : "seductively");
+               } else {
+                   char magr_name[BUFSZ];
+
+                   Strcpy(magr_name, Monnam(magr));
+                   switch (mattk->aatyp) {
+                       case AT_BITE:
+                               Sprintf(buf,"%s bites", magr_name);
+                               break;
+                       case AT_STNG:
+                               Sprintf(buf,"%s stings", magr_name);
+                               break;
+                       case AT_BUTT:
+                               Sprintf(buf,"%s butts", magr_name);
+                               break;
+                       case AT_TUCH:
+                               Sprintf(buf,"%s touches", magr_name);
+                               break;
+                       case AT_TENT:
+                               Sprintf(buf, "%s tentacles suck",
+                                       s_suffix(magr_name));
+                               break;
+                       case AT_HUGS:
+                               if (magr != u.ustuck) {
+                                   Sprintf(buf,"%s squeezes", magr_name);
+                                   break;
+                               }
+                       default:
+                               Sprintf(buf,"%s hits", magr_name);
+                   }
+                   pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr));
+               }
+       } else  noises(magr, mattk);
+       return(mdamagem(magr, mdef, mattk));
+}
+
+/* Returns the same values as mdamagem(). */
+STATIC_OVL int
+gazemm(magr, mdef, mattk)
+       register struct monst *magr, *mdef;
+       struct attack *mattk;
+{
+       char buf[BUFSZ];
+
+       if(vis) {
+               Sprintf(buf,"%s gazes at", Monnam(magr));
+               pline("%s %s...", buf, mon_nam(mdef));
+       }
+
+       if (magr->mcan || !magr->mcansee ||
+           (magr->minvis && !perceives(mdef->data)) ||
+           !mdef->mcansee || mdef->msleeping) {
+           if(vis) pline("but nothing happens.");
+           return(MM_MISS);
+       }
+       /* call mon_reflects 2x, first test, then, if visible, print message */
+       if (magr->data == &mons[PM_MEDUSA] && mon_reflects(mdef, (char *)0)) {
+           if (canseemon(mdef))
+               (void) mon_reflects(mdef,
+                                   "The gaze is reflected away by %s %s.");
+           if (mdef->mcansee) {
+               if (mon_reflects(magr, (char *)0)) {
+                   if (canseemon(magr))
+                       (void) mon_reflects(magr,
+                                       "The gaze is reflected away by %s %s.");
+                   return (MM_MISS);
+               }
+               if (mdef->minvis && !perceives(magr->data)) {
+                   if (canseemon(magr)) {
+                       pline("%s doesn't seem to notice that %s gaze was reflected.",
+                             Monnam(magr), mhis(magr));
+                   }
+                   return (MM_MISS);
+               }
+               if (canseemon(magr))
+                   pline("%s is turned to stone!", Monnam(magr));
+               monstone(magr);
+               if (magr->mhp > 0) return (MM_MISS);
+               return (MM_AGR_DIED);
+           }
+       }
+
+       return(mdamagem(magr, mdef, mattk));
+}
+
+/* Returns the same values as mattackm(). */
+STATIC_OVL int
+gulpmm(magr, mdef, mattk)
+       register struct monst *magr, *mdef;
+       register struct attack *mattk;
+{
+       xchar   ax, ay, dx, dy;
+       int     status;
+       char buf[BUFSZ];
+       struct obj *obj;
+
+       if (mdef->data->msize >= MZ_HUGE) return MM_MISS;
+
+       if (vis) {
+               Sprintf(buf,"%s swallows", Monnam(magr));
+               pline("%s %s.", buf, mon_nam(mdef));
+       }
+       for (obj = mdef->minvent; obj; obj = obj->nobj)
+           (void) snuff_lit(obj);
+
+       /*
+        *  All of this maniuplation is needed to keep the display correct.
+        *  There is a flush at the next pline().
+        */
+       ax = magr->mx;
+       ay = magr->my;
+       dx = mdef->mx;
+       dy = mdef->my;
+       /*
+        *  Leave the defender in the monster chain at it's current position,
+        *  but don't leave it on the screen.  Move the agressor to the def-
+        *  ender's position.
+        */
+       remove_monster(ax, ay);
+       place_monster(magr, dx, dy);
+       newsym(ax,ay);                  /* erase old position */
+       newsym(dx,dy);                  /* update new position */
+
+       status = mdamagem(magr, mdef, mattk);
+
+       if ((status & MM_AGR_DIED) && (status & MM_DEF_DIED)) {
+           ;                                   /* both died -- do nothing  */
+       }
+       else if (status & MM_DEF_DIED) {        /* defender died */
+           /*
+            *  Note:  remove_monster() was called in relmon(), wiping out
+            *  magr from level.monsters[mdef->mx][mdef->my].  We need to
+            *  put it back and display it.     -kd
+            */
+           place_monster(magr, dx, dy);
+           newsym(dx, dy);
+       }
+       else if (status & MM_AGR_DIED) {        /* agressor died */
+           place_monster(mdef, dx, dy);
+           newsym(dx, dy);
+       }
+       else {                                  /* both alive, put them back */
+           if (cansee(dx, dy))
+               pline("%s is regurgitated!", Monnam(mdef));
+
+           place_monster(magr, ax, ay);
+           place_monster(mdef, dx, dy);
+           newsym(ax, ay);
+           newsym(dx, dy);
+       }
+
+       return status;
+}
+
+STATIC_OVL int
+explmm(magr, mdef, mattk)
+       register struct monst *magr, *mdef;
+       register struct attack *mattk;
+{
+       int result;
+
+       if (magr->mcan)
+           return MM_MISS;
+
+       if(cansee(magr->mx, magr->my))
+               pline("%s explodes!", Monnam(magr));
+       else    noises(magr, mattk);
+
+       result = mdamagem(magr, mdef, mattk);
+
+       /* Kill off agressor if it didn't die. */
+       if (!(result & MM_AGR_DIED)) {
+           mondead(magr);
+           if (magr->mhp > 0) return result;   /* life saved */
+           result |= MM_AGR_DIED;
+       }
+       if (magr->mtame)        /* give this one even if it was visible */
+           You(brief_feeling, "melancholy");
+
+       return result;
+}
+
+/*
+ *  See comment at top of mattackm(), for return values.
+ */
+STATIC_OVL int
+mdamagem(magr, mdef, mattk)
+       register struct monst   *magr, *mdef;
+       register struct attack  *mattk;
+{
+       struct obj *obj;
+       char buf[BUFSZ];
+       struct permonst *pa = magr->data, *pd = mdef->data;
+       int armpro, num, tmp = d((int)mattk->damn, (int)mattk->damd);
+       boolean cancelled;
+
+       if (touch_petrifies(pd) && !resists_ston(magr)) {
+           long protector = attk_protection((int)mattk->aatyp),
+                wornitems = magr->misc_worn_check;
+
+           /* wielded weapon gives same protection as gloves here */
+           if (otmp != 0) wornitems |= W_ARMG;
+
+           if (protector == 0L ||
+                 (protector != ~0L && (wornitems & protector) != protector)) {
+               if (poly_when_stoned(pa)) {
+                   mon_to_stone(magr);
+                   return MM_HIT; /* no damage during the polymorph */
+               }
+               if (vis) pline("%s turns to stone!", Monnam(magr));
+               monstone(magr);
+               if (magr->mhp > 0) return 0;
+               else if (magr->mtame && !vis)
+                   You(brief_feeling, "peculiarly sad");
+               return MM_AGR_DIED;
+           }
+       }
+
+       /* cancellation factor is the same as when attacking the hero */
+       armpro = magic_negation(mdef);
+       cancelled = magr->mcan || !((rn2(3) >= armpro) || !rn2(50));
+
+       switch(mattk->adtyp) {
+           case AD_DGST:
+               /* eating a Rider or its corpse is fatal */
+               if (is_rider(mdef->data)) {
+                   if (vis)
+                       pline("%s %s!", Monnam(magr),
+                             mdef->data == &mons[PM_FAMINE] ?
+                               "belches feebly, shrivels up and dies" :
+                             mdef->data == &mons[PM_PESTILENCE] ?
+                               "coughs spasmodically and collapses" :
+                               "vomits violently and drops dead");
+                   mondied(magr);
+                   if (magr->mhp > 0) return 0;        /* lifesaved */
+                   else if (magr->mtame && !vis)
+                       You(brief_feeling, "queasy");
+                   return MM_AGR_DIED;
+               }
+               if(flags.verbose && flags.soundok) verbalize("Burrrrp!");
+               tmp = mdef->mhp;
+               /* Use up amulet of life saving */
+               if (!!(obj = mlifesaver(mdef))) m_useup(mdef, obj);
+
+               /* Is a corpse for nutrition possible?  It may kill magr */
+               if (!corpse_chance(mdef, magr, TRUE) || magr->mhp < 1)
+                   break;
+
+               /* Pets get nutrition from swallowing monster whole.
+                * No nutrition from G_NOCORPSE monster, eg, undead.
+                * DGST monsters don't die from undead corpses
+                */
+               num = monsndx(mdef->data);
+               if (magr->mtame && !magr->isminion &&
+                   !(mvitals[num].mvflags & G_NOCORPSE)) {
+                   struct obj *virtualcorpse = mksobj(CORPSE, FALSE, FALSE);
+                   int nutrit;
+
+                   virtualcorpse->corpsenm = num;
+                   virtualcorpse->owt = weight(virtualcorpse);
+                   nutrit = dog_nutrition(magr, virtualcorpse);
+                   dealloc_obj(virtualcorpse);
+
+                   /* only 50% nutrition, 25% of normal eating time */
+                   if (magr->meating > 1) magr->meating = (magr->meating+3)/4;
+                   if (nutrit > 1) nutrit /= 2;
+                   EDOG(magr)->hungrytime += nutrit;
+               }
+               break;
+           case AD_STUN:
+               if (magr->mcan) break;
+               if (canseemon(mdef))
+                   pline("%s %s for a moment.", Monnam(mdef),
+                         makeplural(stagger(mdef->data, "stagger")));
+               mdef->mstun = 1;
+               goto physical;
+           case AD_LEGS:
+               if (magr->mcan) {
+                   tmp = 0;
+                   break;
+               }
+               goto physical;
+           case AD_WERE:
+           case AD_HEAL:
+           case AD_PHYS:
+ physical:
+               if (mattk->aatyp == AT_KICK && thick_skinned(pd)) {
+                   tmp = 0;
+               } else if(mattk->aatyp == AT_WEAP) {
+                   if(otmp) {
+                       if (otmp->otyp == CORPSE &&
+                               touch_petrifies(&mons[otmp->corpsenm]))
+                           goto do_stone;
+                       tmp += dmgval(otmp, mdef);
+                       if (otmp->oartifact) {
+                           (void)artifact_hit(magr,mdef, otmp, &tmp, dieroll);
+                           if (mdef->mhp <= 0)
+                               return (MM_DEF_DIED |
+                                       (grow_up(magr,mdef) ? 0 : MM_AGR_DIED));
+                       }
+                       if (tmp)
+                               mrustm(magr, mdef, otmp);
+                   }
+               } else if (magr->data == &mons[PM_PURPLE_WORM] &&
+                           mdef->data == &mons[PM_SHRIEKER]) {
+                   /* hack to enhance mm_aggression(); we don't want purple
+                      worm's bite attack to kill a shrieker because then it
+                      won't swallow the corpse; but if the target survives,
+                      the subsequent engulf attack should accomplish that */
+                   if (tmp >= mdef->mhp) tmp = mdef->mhp - 1;
+               }
+               break;
+           case AD_FIRE:
+               if (cancelled) {
+                   tmp = 0;
+                   break;
+               }
+               if (vis)
+                   pline("%s is %s!", Monnam(mdef),
+                         on_fire(mdef->data, mattk));
+               if (pd == &mons[PM_STRAW_GOLEM] ||
+                   pd == &mons[PM_PAPER_GOLEM]) {
+                       if (vis) pline("%s burns completely!", Monnam(mdef));
+                       mondied(mdef);
+                       if (mdef->mhp > 0) return 0;
+                       else if (mdef->mtame && !vis)
+                           pline("May %s roast in peace.", mon_nam(mdef));
+                       return (MM_DEF_DIED | (grow_up(magr,mdef) ?
+                                                       0 : MM_AGR_DIED));
+               }
+               tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
+               tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
+               if (resists_fire(mdef)) {
+                   if (vis)
+                       pline_The("fire doesn't seem to burn %s!",
+                                                               mon_nam(mdef));
+                   shieldeff(mdef->mx, mdef->my);
+                   golemeffects(mdef, AD_FIRE, tmp);
+                   tmp = 0;
+               }
+               /* only potions damage resistant players in destroy_item */
+               tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
+               break;
+           case AD_COLD:
+               if (cancelled) {
+                   tmp = 0;
+                   break;
+               }
+               if (vis) pline("%s is covered in frost!", Monnam(mdef));
+               if (resists_cold(mdef)) {
+                   if (vis)
+                       pline_The("frost doesn't seem to chill %s!",
+                                                               mon_nam(mdef));
+                   shieldeff(mdef->mx, mdef->my);
+                   golemeffects(mdef, AD_COLD, tmp);
+                   tmp = 0;
+               }
+               tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
+               break;
+           case AD_ELEC:
+               if (cancelled) {
+                   tmp = 0;
+                   break;
+               }
+               if (vis) pline("%s gets zapped!", Monnam(mdef));
+               tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
+               if (resists_elec(mdef)) {
+                   if (vis) pline_The("zap doesn't shock %s!", mon_nam(mdef));
+                   shieldeff(mdef->mx, mdef->my);
+                   golemeffects(mdef, AD_ELEC, tmp);
+                   tmp = 0;
+               }
+               /* only rings damage resistant players in destroy_item */
+               tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
+               break;
+           case AD_ACID:
+               if (magr->mcan) {
+                   tmp = 0;
+                   break;
+               }
+               if (resists_acid(mdef)) {
+                   if (vis)
+                       pline("%s is covered in acid, but it seems harmless.",
+                             Monnam(mdef));
+                   tmp = 0;
+               } else if (vis) {
+                   pline("%s is covered in acid!", Monnam(mdef));
+                   pline("It burns %s!", mon_nam(mdef));
+               }
+               if (!rn2(30)) erode_armor(mdef, TRUE);
+               if (!rn2(6)) erode_obj(MON_WEP(mdef), TRUE, TRUE);
+               break;
+           case AD_RUST:
+               if (magr->mcan) break;
+               if (pd == &mons[PM_IRON_GOLEM]) {
+                       if (vis) pline("%s falls to pieces!", Monnam(mdef));
+                       mondied(mdef);
+                       if (mdef->mhp > 0) return 0;
+                       else if (mdef->mtame && !vis)
+                           pline("May %s rust in peace.", mon_nam(mdef));
+                       return (MM_DEF_DIED | (grow_up(magr,mdef) ?
+                                                       0 : MM_AGR_DIED));
+               }
+               hurtmarmor(mdef, AD_RUST);
+               mdef->mstrategy &= ~STRAT_WAITFORU;
+               tmp = 0;
+               break;
+           case AD_CORR:
+               if (magr->mcan) break;
+               hurtmarmor(mdef, AD_CORR);
+               mdef->mstrategy &= ~STRAT_WAITFORU;
+               tmp = 0;
+               break;
+           case AD_DCAY:
+               if (magr->mcan) break;
+               if (pd == &mons[PM_WOOD_GOLEM] ||
+                   pd == &mons[PM_LEATHER_GOLEM]) {
+                       if (vis) pline("%s falls to pieces!", Monnam(mdef));
+                       mondied(mdef);
+                       if (mdef->mhp > 0) return 0;
+                       else if (mdef->mtame && !vis)
+                           pline("May %s rot in peace.", mon_nam(mdef));
+                       return (MM_DEF_DIED | (grow_up(magr,mdef) ?
+                                                       0 : MM_AGR_DIED));
+               }
+               hurtmarmor(mdef, AD_DCAY);
+               mdef->mstrategy &= ~STRAT_WAITFORU;
+               tmp = 0;
+               break;
+           case AD_STON:
+               if (magr->mcan) break;
+ do_stone:
+               /* may die from the acid if it eats a stone-curing corpse */
+               if (munstone(mdef, FALSE)) goto post_stone;
+               if (poly_when_stoned(pd)) {
+                       mon_to_stone(mdef);
+                       tmp = 0;
+                       break;
+               }
+               if (!resists_ston(mdef)) {
+                       if (vis) pline("%s turns to stone!", Monnam(mdef));
+                       monstone(mdef);
+ post_stone:           if (mdef->mhp > 0) return 0;
+                       else if (mdef->mtame && !vis)
+                           You(brief_feeling, "peculiarly sad");
+                       return (MM_DEF_DIED | (grow_up(magr,mdef) ?
+                                                       0 : MM_AGR_DIED));
+               }
+               tmp = (mattk->adtyp == AD_STON ? 0 : 1);
+               break;
+           case AD_TLPT:
+               if (!cancelled && tmp < mdef->mhp && !tele_restrict(mdef)) {
+                   char mdef_Monnam[BUFSZ];
+                   /* save the name before monster teleports, otherwise
+                      we'll get "it" in the suddenly disappears message */
+                   if (vis) Strcpy(mdef_Monnam, Monnam(mdef));
+                   mdef->mstrategy &= ~STRAT_WAITFORU;
+                   (void) rloc(mdef, FALSE);
+                   if (vis && !canspotmon(mdef)
+#ifdef STEED
+                       && mdef != u.usteed
+#endif
+                       )
+                       pline("%s suddenly disappears!", mdef_Monnam);
+               }
+               break;
+           case AD_SLEE:
+               if (!cancelled && !mdef->msleeping &&
+                       sleep_monst(mdef, rnd(10), -1)) {
+                   if (vis) {
+                       Strcpy(buf, Monnam(mdef));
+                       pline("%s is put to sleep by %s.", buf, mon_nam(magr));
+                   }
+                   mdef->mstrategy &= ~STRAT_WAITFORU;
+                   slept_monst(mdef);
+               }
+               break;
+           case AD_PLYS:
+               if(!cancelled && mdef->mcanmove) {
+                   if (vis) {
+                       Strcpy(buf, Monnam(mdef));
+                       pline("%s is frozen by %s.", buf, mon_nam(magr));
+                   }
+                   mdef->mcanmove = 0;
+                   mdef->mfrozen = rnd(10);
+                   mdef->mstrategy &= ~STRAT_WAITFORU;
+               }
+               break;
+           case AD_SLOW:
+               if (!cancelled && mdef->mspeed != MSLOW) {
+                   unsigned int oldspeed = mdef->mspeed;
+
+                   mon_adjust_speed(mdef, -1, (struct obj *)0);
+                   mdef->mstrategy &= ~STRAT_WAITFORU;
+                   if (mdef->mspeed != oldspeed && vis)
+                       pline("%s slows down.", Monnam(mdef));
+               }
+               break;
+           case AD_CONF:
+               /* Since confusing another monster doesn't have a real time
+                * limit, setting spec_used would not really be right (though
+                * we still should check for it).
+                */
+               if (!magr->mcan && !mdef->mconf && !magr->mspec_used) {
+                   if (vis) pline("%s looks confused.", Monnam(mdef));
+                   mdef->mconf = 1;
+                   mdef->mstrategy &= ~STRAT_WAITFORU;
+               }
+               break;
+           case AD_BLND:
+               if (can_blnd(magr, mdef, mattk->aatyp, (struct obj*)0)) {
+                   register unsigned rnd_tmp;
+
+                   if (vis && mdef->mcansee)
+                       pline("%s is blinded.", Monnam(mdef));
+                   rnd_tmp = d((int)mattk->damn, (int)mattk->damd);
+                   if ((rnd_tmp += mdef->mblinded) > 127) rnd_tmp = 127;
+                   mdef->mblinded = rnd_tmp;
+                   mdef->mcansee = 0;
+                   mdef->mstrategy &= ~STRAT_WAITFORU;
+               }
+               tmp = 0;
+               break;
+           case AD_HALU:
+               if (!magr->mcan && haseyes(pd) && mdef->mcansee) {
+                   if (vis) pline("%s looks %sconfused.",
+                                   Monnam(mdef), mdef->mconf ? "more " : "");
+                   mdef->mconf = 1;
+                   mdef->mstrategy &= ~STRAT_WAITFORU;
+               }
+               tmp = 0;
+               break;
+           case AD_CURS:
+               if (!night() && (pa == &mons[PM_GREMLIN])) break;
+               if (!magr->mcan && !rn2(10)) {
+                   mdef->mcan = 1;     /* cancelled regardless of lifesave */
+                   mdef->mstrategy &= ~STRAT_WAITFORU;
+                   if (is_were(pd) && pd->mlet != S_HUMAN)
+                       were_change(mdef);
+                   if (pd == &mons[PM_CLAY_GOLEM]) {
+                           if (vis) {
+                               pline("Some writing vanishes from %s head!",
+                                   s_suffix(mon_nam(mdef)));
+                               pline("%s is destroyed!", Monnam(mdef));
+                           }
+                           mondied(mdef);
+                           if (mdef->mhp > 0) return 0;
+                           else if (mdef->mtame && !vis)
+                               You(brief_feeling, "strangely sad");
+                           return (MM_DEF_DIED | (grow_up(magr,mdef) ?
+                                                       0 : MM_AGR_DIED));
+                   }
+                   if (flags.soundok) {
+                           if (!vis) You_hear("laughter.");
+                           else pline("%s chuckles.", Monnam(magr));
+                   }
+               }
+               break;
+           case AD_SGLD:
+               tmp = 0;
+#ifndef GOLDOBJ
+               if (magr->mcan || !mdef->mgold) break;
+               /* technically incorrect; no check for stealing gold from
+                * between mdef's feet...
+                */
+               magr->mgold += mdef->mgold;
+               mdef->mgold = 0;
+#else
+                if (magr->mcan) break;
+               /* technically incorrect; no check for stealing gold from
+                * between mdef's feet...
+                */
+                {
+                   struct obj *gold = findgold(mdef->minvent);
+                   if (!gold) break;
+                    obj_extract_self(gold);
+                   add_to_minv(magr, gold);
+                }
+#endif
+               mdef->mstrategy &= ~STRAT_WAITFORU;
+               if (vis) {
+                   Strcpy(buf, Monnam(magr));
+                   pline("%s steals some gold from %s.", buf, mon_nam(mdef));
+               }
+               if (!tele_restrict(magr)) {
+                   (void) rloc(magr, FALSE);
+                   if (vis && !canspotmon(magr))
+                       pline("%s suddenly disappears!", buf);
+               }
+               break;
+           case AD_DRLI:
+               if (!cancelled && !rn2(3) && !resists_drli(mdef)) {
+                       tmp = d(2,6);
+                       if (vis)
+                           pline("%s suddenly seems weaker!", Monnam(mdef));
+                       mdef->mhpmax -= tmp;
+                       if (mdef->m_lev == 0)
+                               tmp = mdef->mhp;
+                       else mdef->m_lev--;
+                       /* Automatic kill if drained past level 0 */
+               }
+               break;
+#ifdef SEDUCE
+           case AD_SSEX:
+#endif
+           case AD_SITM:       /* for now these are the same */
+           case AD_SEDU:
+               if (magr->mcan) break;
+               /* find an object to steal, non-cursed if magr is tame */
+               for (obj = mdef->minvent; obj; obj = obj->nobj)
+                   if (!magr->mtame || !obj->cursed)
+                       break;
+
+               if (obj) {
+                       char onambuf[BUFSZ], mdefnambuf[BUFSZ];
+
+                       /* make a special x_monnam() call that never omits
+                          the saddle, and save it for later messages */
+                       Strcpy(mdefnambuf, x_monnam(mdef, ARTICLE_THE, (char *)0, 0, FALSE));
+
+                       otmp = obj;
+#ifdef STEED
+                       if (u.usteed == mdef &&
+                                       otmp == which_armor(mdef, W_SADDLE))
+                               /* "You can no longer ride <steed>." */
+                               dismount_steed(DISMOUNT_POLY);
+#endif
+                       obj_extract_self(otmp);
+                       if (otmp->owornmask) {
+                               mdef->misc_worn_check &= ~otmp->owornmask;
+                               if (otmp->owornmask & W_WEP)
+                                   setmnotwielded(mdef,otmp);
+                               otmp->owornmask = 0L;
+                               update_mon_intrinsics(mdef, otmp, FALSE, FALSE);
+                       }
+                       /* add_to_minv() might free otmp [if it merges] */
+                       if (vis)
+                               Strcpy(onambuf, doname(otmp));
+                       (void) add_to_minv(magr, otmp);
+                       if (vis) {
+                               Strcpy(buf, Monnam(magr));
+                               pline("%s steals %s from %s!", buf,
+                                   onambuf, mdefnambuf);
+                       }
+                       possibly_unwield(mdef, FALSE);
+                       mdef->mstrategy &= ~STRAT_WAITFORU;
+                       mselftouch(mdef, (const char *)0, FALSE);
+                       if (mdef->mhp <= 0)
+                               return (MM_DEF_DIED | (grow_up(magr,mdef) ?
+                                                       0 : MM_AGR_DIED));
+                       if (magr->data->mlet == S_NYMPH &&
+                           !tele_restrict(magr)) {
+                           (void) rloc(magr, FALSE);
+                           if (vis && !canspotmon(magr))
+                               pline("%s suddenly disappears!", buf);
+                       }
+               }
+               tmp = 0;
+               break;
+           case AD_DRST:
+           case AD_DRDX:
+           case AD_DRCO:
+               if (!cancelled && !rn2(8)) {
+                   if (vis)
+                       pline("%s %s was poisoned!", s_suffix(Monnam(magr)),
+                             mpoisons_subj(magr, mattk));
+                   if (resists_poison(mdef)) {
+                       if (vis)
+                           pline_The("poison doesn't seem to affect %s.",
+                               mon_nam(mdef));
+                   } else {
+                       if (rn2(10)) tmp += rn1(10,6);
+                       else {
+                           if (vis) pline_The("poison was deadly...");
+                           tmp = mdef->mhp;
+                       }
+                   }
+               }
+               break;
+           case AD_DRIN:
+               if (notonhead || !has_head(pd)) {
+                   if (vis) pline("%s doesn't seem harmed.", Monnam(mdef));
+                   /* Not clear what to do for green slimes */
+                   tmp = 0;
+                   break;
+               }
+               if ((mdef->misc_worn_check & W_ARMH) && rn2(8)) {
+                   if (vis) {
+                       Strcpy(buf, s_suffix(Monnam(mdef)));
+                       pline("%s helmet blocks %s attack to %s head.",
+                               buf, s_suffix(mon_nam(magr)),
+                               mhis(mdef));
+                   }
+                   break;
+               }
+               if (vis) pline("%s brain is eaten!", s_suffix(Monnam(mdef)));
+               if (mindless(pd)) {
+                   if (vis) pline("%s doesn't notice.", Monnam(mdef));
+                   break;
+               }
+               tmp += rnd(10); /* fakery, since monsters lack INT scores */
+               if (magr->mtame && !magr->isminion) {
+                   EDOG(magr)->hungrytime += rnd(60);
+                   magr->mconf = 0;
+               }
+               if (tmp >= mdef->mhp && vis)
+                   pline("%s last thought fades away...",
+                                 s_suffix(Monnam(mdef)));
+               break;
+           case AD_SLIM:
+               if (cancelled) break;   /* physical damage only */
+               if (!rn2(4) && !flaming(mdef->data) &&
+                               mdef->data != &mons[PM_GREEN_SLIME]) {
+                   (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, vis);
+                   mdef->mstrategy &= ~STRAT_WAITFORU;
+                   tmp = 0;
+               }
+               break;
+           case AD_STCK:
+               if (cancelled) tmp = 0;
+               break;
+           case AD_WRAP: /* monsters cannot grab one another, it's too hard */
+               if (magr->mcan) tmp = 0;
+               break;
+           case AD_ENCH:
+               /* there's no msomearmor() function, so just do damage */
+            /* if (cancelled) break; */
+               break;
+           default:    tmp = 0;
+                       break;
+       }
+       if(!tmp) return(MM_MISS);
+
+       if((mdef->mhp -= tmp) < 1) {
+           if (m_at(mdef->mx, mdef->my) == magr) {  /* see gulpmm() */
+               remove_monster(mdef->mx, mdef->my);
+               mdef->mhp = 1;  /* otherwise place_monster will complain */
+               place_monster(mdef, mdef->mx, mdef->my);
+               mdef->mhp = 0;
+           }
+           monkilled(mdef, "", (int)mattk->adtyp);
+           if (mdef->mhp > 0) return 0; /* mdef lifesaved */
+
+           if (mattk->adtyp == AD_DGST) {
+               /* various checks similar to dog_eat and meatobj.
+                * after monkilled() to provide better message ordering */
+               if (mdef->cham != CHAM_ORDINARY) {
+                   (void) newcham(magr, (struct permonst *)0, FALSE, TRUE);
+               } else if (mdef->data == &mons[PM_GREEN_SLIME]) {
+                   (void) newcham(magr, &mons[PM_GREEN_SLIME], FALSE, TRUE);
+               } else if (mdef->data == &mons[PM_WRAITH]) {
+                   (void) grow_up(magr, (struct monst *)0);
+                   /* don't grow up twice */
+                   return (MM_DEF_DIED | (magr->mhp > 0 ? 0 : MM_AGR_DIED));
+               } else if (mdef->data == &mons[PM_NURSE]) {
+                   magr->mhp = magr->mhpmax;
+               }
+           }
+
+           return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED));
+       }
+       return(MM_HIT);
+}
+
+#endif /* OVLB */
+
+
+#ifdef OVL0
+
+int
+noattacks(ptr)                 /* returns 1 if monster doesn't attack */
+       struct  permonst *ptr;
+{
+       int i;
+
+       for(i = 0; i < NATTK; i++)
+               if(ptr->mattk[i].aatyp) return(0);
+
+       return(1);
+}
+
+/* `mon' is hit by a sleep attack; return 1 if it's affected, 0 otherwise */
+int
+sleep_monst(mon, amt, how)
+struct monst *mon;
+int amt, how;
+{
+       if (resists_sleep(mon) ||
+               (how >= 0 && resist(mon, (char)how, 0, NOTELL))) {
+           shieldeff(mon->mx, mon->my);
+       } else if (mon->mcanmove) {
+           amt += (int) mon->mfrozen;
+           if (amt > 0) {      /* sleep for N turns */
+               mon->mcanmove = 0;
+               mon->mfrozen = min(amt, 127);
+           } else {            /* sleep until awakened */
+               mon->msleeping = 1;
+           }
+           return 1;
+       }
+       return 0;
+}
+
+/* sleeping grabber releases, engulfer doesn't; don't use for paralysis! */
+void
+slept_monst(mon)
+struct monst *mon;
+{
+       if ((mon->msleeping || !mon->mcanmove) && mon == u.ustuck &&
+               !sticks(youmonst.data) && !u.uswallow) {
+           pline("%s grip relaxes.", s_suffix(Monnam(mon)));
+           unstuck(mon);
+       }
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+STATIC_OVL void
+mrustm(magr, mdef, obj)
+register struct monst *magr, *mdef;
+register struct obj *obj;
+{
+       boolean is_acid;
+
+       if (!magr || !mdef || !obj) return; /* just in case */
+
+       if (dmgtype(mdef->data, AD_CORR))
+           is_acid = TRUE;
+       else if (dmgtype(mdef->data, AD_RUST))
+           is_acid = FALSE;
+       else
+           return;
+
+       if (!mdef->mcan &&
+           (is_acid ? is_corrodeable(obj) : is_rustprone(obj)) &&
+           (is_acid ? obj->oeroded2 : obj->oeroded) < MAX_ERODE) {
+               if (obj->greased || obj->oerodeproof || (obj->blessed && rn2(3))) {
+                   if (cansee(mdef->mx, mdef->my) && flags.verbose)
+                       pline("%s weapon is not affected.",
+                                        s_suffix(Monnam(magr)));
+                   if (obj->greased && !rn2(2)) obj->greased = 0;
+               } else {
+                   if (cansee(mdef->mx, mdef->my)) {
+                       pline("%s %s%s!", s_suffix(Monnam(magr)),
+                           aobjnam(obj, (is_acid ? "corrode" : "rust")),
+                           (is_acid ? obj->oeroded2 : obj->oeroded)
+                               ? " further" : "");
+                   }
+                   if (is_acid) obj->oeroded2++;
+                   else obj->oeroded++;
+               }
+       }
+}
+
+STATIC_OVL void
+mswingsm(magr, mdef, otemp)
+register struct monst *magr, *mdef;
+register struct obj *otemp;
+{
+       char buf[BUFSZ];
+       if (!flags.verbose || Blind || !mon_visible(magr)) return;
+       Strcpy(buf, mon_nam(mdef));
+       pline("%s %s %s %s at %s.", Monnam(magr),
+             (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings",
+             mhis(magr), singular(otemp, xname), buf);
+}
+
+/*
+ * Passive responses by defenders.  Does not replicate responses already
+ * handled above.  Returns same values as mattackm.
+ */
+STATIC_OVL int
+passivemm(magr,mdef,mhit,mdead)
+register struct monst *magr, *mdef;
+boolean mhit;
+int mdead;
+{
+       register struct permonst *mddat = mdef->data;
+       register struct permonst *madat = magr->data;
+       char buf[BUFSZ];
+       int i, tmp;
+
+       for(i = 0; ; i++) {
+           if(i >= NATTK) return (mdead | mhit); /* no passive attacks */
+           if(mddat->mattk[i].aatyp == AT_NONE) break;
+       }
+       if (mddat->mattk[i].damn)
+           tmp = d((int)mddat->mattk[i].damn,
+                                   (int)mddat->mattk[i].damd);
+       else if(mddat->mattk[i].damd)
+           tmp = d((int)mddat->mlevel+1, (int)mddat->mattk[i].damd);
+       else
+           tmp = 0;
+
+       /* These affect the enemy even if defender killed */
+       switch(mddat->mattk[i].adtyp) {
+           case AD_ACID:
+               if (mhit && !rn2(2)) {
+                   Strcpy(buf, Monnam(magr));
+                   if(canseemon(magr))
+                       pline("%s is splashed by %s acid!",
+                             buf, s_suffix(mon_nam(mdef)));
+                   if (resists_acid(magr)) {
+                       if(canseemon(magr))
+                           pline("%s is not affected.", Monnam(magr));
+                       tmp = 0;
+                   }
+               } else tmp = 0;
+               goto assess_dmg;
+           case AD_ENCH:       /* KMH -- remove enchantment (disenchanter) */
+               if (mhit && !mdef->mcan && otmp) {
+                   (void) drain_item(otmp);
+                   /* No message */
+               }
+               break;
+           default:
+               break;
+       }
+       if (mdead || mdef->mcan) return (mdead|mhit);
+
+       /* These affect the enemy only if defender is still alive */
+       if (rn2(3)) switch(mddat->mattk[i].adtyp) {
+           case AD_PLYS: /* Floating eye */
+               if (tmp > 127) tmp = 127;
+               if (mddat == &mons[PM_FLOATING_EYE]) {
+                   if (!rn2(4)) tmp = 127;
+                   if (magr->mcansee && haseyes(madat) && mdef->mcansee &&
+                       (perceives(madat) || !mdef->minvis)) {
+                       Sprintf(buf, "%s gaze is reflected by %%s %%s.",
+                               s_suffix(mon_nam(mdef)));
+                       if (mon_reflects(magr,
+                                        canseemon(magr) ? buf : (char *)0))
+                               return(mdead|mhit);
+                       Strcpy(buf, Monnam(magr));
+                       if(canseemon(magr))
+                           pline("%s is frozen by %s gaze!",
+                                 buf, s_suffix(mon_nam(mdef)));
+                       magr->mcanmove = 0;
+                       magr->mfrozen = tmp;
+                       return (mdead|mhit);
+                   }
+               } else { /* gelatinous cube */
+                   Strcpy(buf, Monnam(magr));
+                   if(canseemon(magr))
+                       pline("%s is frozen by %s.", buf, mon_nam(mdef));
+                   magr->mcanmove = 0;
+                   magr->mfrozen = tmp;
+                   return (mdead|mhit);
+               }
+               return 1;
+           case AD_COLD:
+               if (resists_cold(magr)) {
+                   if (canseemon(magr)) {
+                       pline("%s is mildly chilly.", Monnam(magr));
+                       golemeffects(magr, AD_COLD, tmp);
+                   }
+                   tmp = 0;
+                   break;
+               }
+               if(canseemon(magr))
+                   pline("%s is suddenly very cold!", Monnam(magr));
+               mdef->mhp += tmp / 2;
+               if (mdef->mhpmax < mdef->mhp) mdef->mhpmax = mdef->mhp;
+               if (mdef->mhpmax > ((int) (mdef->m_lev+1) * 8))
+                   (void)split_mon(mdef, magr);
+               break;
+           case AD_STUN:
+               if (!magr->mstun) {
+                   magr->mstun = 1;
+                   if (canseemon(magr))
+                       pline("%s %s...", Monnam(magr),
+                             makeplural(stagger(magr->data, "stagger")));
+               }
+               tmp = 0;
+               break;
+           case AD_FIRE:
+               if (resists_fire(magr)) {
+                   if (canseemon(magr)) {
+                       pline("%s is mildly warmed.", Monnam(magr));
+                       golemeffects(magr, AD_FIRE, tmp);
+                   }
+                   tmp = 0;
+                   break;
+               }
+               if(canseemon(magr))
+                   pline("%s is suddenly very hot!", Monnam(magr));
+               break;
+           case AD_ELEC:
+               if (resists_elec(magr)) {
+                   if (canseemon(magr)) {
+                       pline("%s is mildly tingled.", Monnam(magr));
+                       golemeffects(magr, AD_ELEC, tmp);
+                   }
+                   tmp = 0;
+                   break;
+               }
+               if(canseemon(magr))
+                   pline("%s is jolted with electricity!", Monnam(magr));
+               break;
+           default: tmp = 0;
+               break;
+       }
+       else tmp = 0;
+
+    assess_dmg:
+       if((magr->mhp -= tmp) <= 0) {
+               monkilled(magr, "", (int)mddat->mattk[i].adtyp);
+               return (mdead | mhit | MM_AGR_DIED);
+       }
+       return (mdead | mhit);
+}
+
+/* "aggressive defense"; what type of armor prevents specified attack
+   from touching its target? */
+long
+attk_protection(aatyp)
+int aatyp;
+{
+    long w_mask = 0L;
+
+    switch (aatyp) {
+    case AT_NONE:
+    case AT_SPIT:
+    case AT_EXPL:
+    case AT_BOOM:
+    case AT_GAZE:
+    case AT_BREA:
+    case AT_MAGC:
+       w_mask = ~0L;           /* special case; no defense needed */
+       break;
+    case AT_CLAW:
+    case AT_TUCH:
+    case AT_WEAP:
+       w_mask = W_ARMG;        /* caller needs to check for weapon */
+       break;
+    case AT_KICK:
+       w_mask = W_ARMF;
+       break;
+    case AT_BUTT:
+       w_mask = W_ARMH;
+       break;
+    case AT_HUGS:
+       w_mask = (W_ARMC|W_ARMG); /* attacker needs both to be protected */
+       break;
+    case AT_BITE:
+    case AT_STNG:
+    case AT_ENGL:
+    case AT_TENT:
+    default:
+       w_mask = 0L;            /* no defense available */
+       break;
+    }
+    return w_mask;
+}
+
+#endif /* OVLB */
+
+/*mhitm.c*/
+
diff --git a/src/mhitu.c b/src/mhitu.c
new file mode 100644 (file)
index 0000000..c0711fc
--- /dev/null
@@ -0,0 +1,2633 @@
+/*     SCCS Id: @(#)mhitu.c    3.4     2003/11/26      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "artifact.h"
+
+STATIC_VAR NEARDATA struct obj *otmp;
+
+STATIC_DCL void FDECL(urustm, (struct monst *, struct obj *));
+# ifdef OVL1
+STATIC_DCL boolean FDECL(u_slip_free, (struct monst *,struct attack *));
+STATIC_DCL int FDECL(passiveum, (struct permonst *,struct monst *,struct attack *));
+# endif /* OVL1 */
+
+#ifdef OVLB
+# ifdef SEDUCE
+STATIC_DCL void FDECL(mayberem, (struct obj *, const char *));
+# endif
+#endif /* OVLB */
+
+STATIC_DCL boolean FDECL(diseasemu, (struct permonst *));
+STATIC_DCL int FDECL(hitmu, (struct monst *,struct attack *));
+STATIC_DCL int FDECL(gulpmu, (struct monst *,struct attack *));
+STATIC_DCL int FDECL(explmu, (struct monst *,struct attack *,BOOLEAN_P));
+STATIC_DCL void FDECL(missmu,(struct monst *,BOOLEAN_P,struct attack *));
+STATIC_DCL void FDECL(mswings,(struct monst *,struct obj *));
+STATIC_DCL void FDECL(wildmiss, (struct monst *,struct attack *));
+
+STATIC_DCL void FDECL(hurtarmor,(int));
+STATIC_DCL void FDECL(hitmsg,(struct monst *,struct attack *));
+
+/* See comment in mhitm.c.  If we use this a lot it probably should be */
+/* changed to a parameter to mhitu. */
+static int dieroll;
+
+#ifdef OVL1
+
+
+STATIC_OVL void
+hitmsg(mtmp, mattk)
+register struct monst *mtmp;
+register struct attack *mattk;
+{
+       int compat;
+
+       /* Note: if opposite gender, "seductively" */
+       /* If same gender, "engagingly" for nymph, normal msg for others */
+       if((compat = could_seduce(mtmp, &youmonst, mattk))
+                       && !mtmp->mcan && !mtmp->mspec_used) {
+               pline("%s %s you %s.", Monnam(mtmp),
+                       Blind ? "talks to" : "smiles at",
+                       compat == 2 ? "engagingly" : "seductively");
+       } else
+           switch (mattk->aatyp) {
+               case AT_BITE:
+                       pline("%s bites!", Monnam(mtmp));
+                       break;
+               case AT_KICK:
+                       pline("%s kicks%c", Monnam(mtmp),
+                                   thick_skinned(youmonst.data) ? '.' : '!');
+                       break;
+               case AT_STNG:
+                       pline("%s stings!", Monnam(mtmp));
+                       break;
+               case AT_BUTT:
+                       pline("%s butts!", Monnam(mtmp));
+                       break;
+               case AT_TUCH:
+                       pline("%s touches you!", Monnam(mtmp));
+                       break;
+               case AT_TENT:
+                       pline("%s tentacles suck you!",
+                                       s_suffix(Monnam(mtmp)));
+                       break;
+               case AT_EXPL:
+               case AT_BOOM:
+                       pline("%s explodes!", Monnam(mtmp));
+                       break;
+               default:
+                       pline("%s hits!", Monnam(mtmp));
+           }
+}
+
+STATIC_OVL void
+missmu(mtmp, nearmiss, mattk)          /* monster missed you */
+register struct monst *mtmp;
+register boolean nearmiss;
+register struct attack *mattk;
+{
+       if (!canspotmon(mtmp))
+           map_invisible(mtmp->mx, mtmp->my);
+
+       if(could_seduce(mtmp, &youmonst, mattk) && !mtmp->mcan)
+           pline("%s pretends to be friendly.", Monnam(mtmp));
+       else {
+           if (!flags.verbose || !nearmiss)
+               pline("%s misses.", Monnam(mtmp));
+           else
+               pline("%s just misses!", Monnam(mtmp));
+       }
+       stop_occupation();
+}
+
+STATIC_OVL void
+mswings(mtmp, otemp)           /* monster swings obj */
+register struct monst *mtmp;
+register struct obj *otemp;
+{
+       if (!flags.verbose || Blind || !mon_visible(mtmp))
+               return;
+       pline("%s %s %s %s.", Monnam(mtmp),
+             (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings",
+             mhis(mtmp), singular(otemp, xname));
+}
+
+/* return how a poison attack was delivered */
+const char *
+mpoisons_subj(mtmp, mattk)
+struct monst *mtmp;
+struct attack *mattk;
+{
+       if (mattk->aatyp == AT_WEAP) {
+           struct obj *mwep = (mtmp == &youmonst) ? uwep : MON_WEP(mtmp);
+           /* "Foo's attack was poisoned." is pretty lame, but at least
+              it's better than "sting" when not a stinging attack... */
+           return (!mwep || !mwep->opoisoned) ? "attack" : "weapon";
+       } else {
+           return (mattk->aatyp == AT_TUCH) ? "contact" :
+                  (mattk->aatyp == AT_GAZE) ? "gaze" :
+                  (mattk->aatyp == AT_BITE) ? "bite" : "sting";
+       }
+}
+
+/* called when your intrinsic speed is taken away */
+void
+u_slow_down()
+{
+       HFast = 0L;
+       if (!Fast)
+           You("slow down.");
+       else    /* speed boots */
+           Your("quickness feels less natural.");
+       exercise(A_DEX, FALSE);
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+STATIC_OVL void
+wildmiss(mtmp, mattk)          /* monster attacked your displaced image */
+       register struct monst *mtmp;
+       register struct attack *mattk;
+{
+       int compat;
+
+       /* no map_invisible() -- no way to tell where _this_ is coming from */
+
+       if (!flags.verbose) return;
+       if (!cansee(mtmp->mx, mtmp->my)) return;
+               /* maybe it's attacking an image around the corner? */
+
+       compat = (mattk->adtyp == AD_SEDU || mattk->adtyp == AD_SSEX) &&
+                could_seduce(mtmp, &youmonst, (struct attack *)0);
+
+       if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
+           const char *swings =
+               mattk->aatyp == AT_BITE ? "snaps" :
+               mattk->aatyp == AT_KICK ? "kicks" :
+               (mattk->aatyp == AT_STNG ||
+                mattk->aatyp == AT_BUTT ||
+                nolimbs(mtmp->data)) ? "lunges" : "swings";
+
+           if (compat)
+               pline("%s tries to touch you and misses!", Monnam(mtmp));
+           else
+               switch(rn2(3)) {
+               case 0: pline("%s %s wildly and misses!", Monnam(mtmp),
+                             swings);
+                   break;
+               case 1: pline("%s attacks a spot beside you.", Monnam(mtmp));
+                   break;
+               case 2: pline("%s strikes at %s!", Monnam(mtmp),
+                               levl[mtmp->mux][mtmp->muy].typ == WATER
+                                   ? "empty water" : "thin air");
+                   break;
+               default:pline("%s %s wildly!", Monnam(mtmp), swings);
+                   break;
+               }
+
+       } else if (Displaced) {
+           if (compat)
+               pline("%s smiles %s at your %sdisplaced image...",
+                       Monnam(mtmp),
+                       compat == 2 ? "engagingly" : "seductively",
+                       Invis ? "invisible " : "");
+           else
+               pline("%s strikes at your %sdisplaced image and misses you!",
+                       /* Note: if you're both invisible and displaced,
+                        * only monsters which see invisible will attack your
+                        * displaced image, since the displaced image is also
+                        * invisible.
+                        */
+                       Monnam(mtmp),
+                       Invis ? "invisible " : "");
+
+       } else if (Underwater) {
+           /* monsters may miss especially on water level where
+              bubbles shake the player here and there */
+           if (compat)
+               pline("%s reaches towards your distorted image.",Monnam(mtmp));
+           else
+               pline("%s is fooled by water reflections and misses!",Monnam(mtmp));
+
+       } else impossible("%s attacks you without knowing your location?",
+               Monnam(mtmp));
+}
+
+void
+expels(mtmp, mdat, message)
+register struct monst *mtmp;
+register struct permonst *mdat; /* if mtmp is polymorphed, mdat != mtmp->data */
+boolean message;
+{
+       if (message) {
+               if (is_animal(mdat))
+                       You("get regurgitated!");
+               else {
+                       char blast[40];
+                       register int i;
+
+                       blast[0] = '\0';
+                       for(i = 0; i < NATTK; i++)
+                               if(mdat->mattk[i].aatyp == AT_ENGL)
+                                       break;
+                       if (mdat->mattk[i].aatyp != AT_ENGL)
+                             impossible("Swallower has no engulfing attack?");
+                       else {
+                               if (is_whirly(mdat)) {
+                                       switch (mdat->mattk[i].adtyp) {
+                                               case AD_ELEC:
+                                                       Strcpy(blast,
+                                                     " in a shower of sparks");
+                                                       break;
+                                               case AD_COLD:
+                                                       Strcpy(blast,
+                                                       " in a blast of frost");
+                                                       break;
+                                       }
+                               } else
+                                       Strcpy(blast, " with a squelch");
+                               You("get expelled from %s%s!",
+                                   mon_nam(mtmp), blast);
+                       }
+               }
+       }
+       unstuck(mtmp);  /* ball&chain returned in unstuck() */
+       mnexto(mtmp);
+       newsym(u.ux,u.uy);
+       spoteffects(TRUE);
+       /* to cover for a case where mtmp is not in a next square */
+       if(um_dist(mtmp->mx,mtmp->my,1))
+               pline("Brrooaa...  You land hard at some distance.");
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+/* select a monster's next attack, possibly substituting for its usual one */
+struct attack *
+getmattk(mptr, indx, prev_result, alt_attk_buf)
+struct permonst *mptr;
+int indx, prev_result[];
+struct attack *alt_attk_buf;
+{
+    struct attack *attk = &mptr->mattk[indx];
+
+    /* prevent a monster with two consecutive disease or hunger attacks
+       from hitting with both of them on the same turn; if the first has
+       already hit, switch to a stun attack for the second */
+    if (indx > 0 && prev_result[indx - 1] > 0 &&
+           (attk->adtyp == AD_DISE ||
+               attk->adtyp == AD_PEST ||
+               attk->adtyp == AD_FAMN) &&
+           attk->adtyp == mptr->mattk[indx - 1].adtyp) {
+       *alt_attk_buf = *attk;
+       attk = alt_attk_buf;
+       attk->adtyp = AD_STUN;
+    }
+    return attk;
+}
+
+/*
+ * mattacku: monster attacks you
+ *     returns 1 if monster dies (e.g. "yellow light"), 0 otherwise
+ *     Note: if you're displaced or invisible the monster might attack the
+ *             wrong position...
+ *     Assumption: it's attacking you or an empty square; if there's another
+ *             monster which it attacks by mistake, the caller had better
+ *             take care of it...
+ */
+int
+mattacku(mtmp)
+       register struct monst *mtmp;
+{
+       struct  attack  *mattk, alt_attk;
+       int     i, j, tmp, sum[NATTK];
+       struct  permonst *mdat = mtmp->data;
+       boolean ranged = (distu(mtmp->mx, mtmp->my) > 3);
+               /* Is it near you?  Affects your actions */
+       boolean range2 = !monnear(mtmp, mtmp->mux, mtmp->muy);
+               /* Does it think it's near you?  Affects its actions */
+       boolean foundyou = (mtmp->mux==u.ux && mtmp->muy==u.uy);
+               /* Is it attacking you or your image? */
+       boolean youseeit = canseemon(mtmp);
+               /* Might be attacking your image around the corner, or
+                * invisible, or you might be blind....
+                */
+       
+       if(!ranged) nomul(0);
+       if(mtmp->mhp <= 0 || (Underwater && !is_swimmer(mtmp->data)))
+           return(0);
+
+       /* If swallowed, can only be affected by u.ustuck */
+       if(u.uswallow) {
+           if(mtmp != u.ustuck)
+               return(0);
+           u.ustuck->mux = u.ux;
+           u.ustuck->muy = u.uy;
+           range2 = 0;
+           foundyou = 1;
+           if(u.uinvulnerable) return (0); /* stomachs can't hurt you! */
+       }
+
+#ifdef STEED
+       else if (u.usteed) {
+               if (mtmp == u.usteed)
+                       /* Your steed won't attack you */
+                       return (0);
+               /* Orcs like to steal and eat horses and the like */
+               if (!rn2(is_orc(mtmp->data) ? 2 : 4) &&
+                               distu(mtmp->mx, mtmp->my) <= 2) {
+                       /* Attack your steed instead */
+                       i = mattackm(mtmp, u.usteed);
+                       if ((i & MM_AGR_DIED))
+                               return (1);
+                       if (i & MM_DEF_DIED || u.umoved)
+                               return (0);
+                       /* Let your steed retaliate */
+                       return (!!(mattackm(u.usteed, mtmp) & MM_DEF_DIED));
+               }
+       }
+#endif
+
+       if (u.uundetected && !range2 && foundyou && !u.uswallow) {
+               u.uundetected = 0;
+               if (is_hider(youmonst.data)) {
+                   coord cc; /* maybe we need a unexto() function? */
+                   struct obj *obj;
+
+                   You("fall from the %s!", ceiling(u.ux,u.uy));
+                   if (enexto(&cc, u.ux, u.uy, youmonst.data)) {
+                       remove_monster(mtmp->mx, mtmp->my);
+                       newsym(mtmp->mx,mtmp->my);
+                       place_monster(mtmp, u.ux, u.uy);
+                       if(mtmp->wormno) worm_move(mtmp);
+                       teleds(cc.x, cc.y, TRUE);
+                       set_apparxy(mtmp);
+                       newsym(u.ux,u.uy);
+                   } else {
+                       pline("%s is killed by a falling %s (you)!",
+                                       Monnam(mtmp), youmonst.data->mname);
+                       killed(mtmp);
+                       newsym(u.ux,u.uy);
+                       if (mtmp->mhp > 0) return 0;
+                       else return 1;
+                   }
+                   if (youmonst.data->mlet != S_PIERCER)
+                       return(0);      /* trappers don't attack */
+
+                   obj = which_armor(mtmp, WORN_HELMET);
+                   if (obj && is_metallic(obj)) {
+                       Your("blow glances off %s helmet.",
+                                      s_suffix(mon_nam(mtmp)));
+                   } else {
+                       if (3 + find_mac(mtmp) <= rnd(20)) {
+                           pline("%s is hit by a falling piercer (you)!",
+                                                               Monnam(mtmp));
+                           if ((mtmp->mhp -= d(3,6)) < 1)
+                               killed(mtmp);
+                       } else
+                         pline("%s is almost hit by a falling piercer (you)!",
+                                                               Monnam(mtmp));
+                   }
+               } else {
+                   if (!youseeit)
+                       pline("It tries to move where you are hiding.");
+                   else {
+                       /* Ugly kludge for eggs.  The message is phrased so as
+                        * to be directed at the monster, not the player,
+                        * which makes "laid by you" wrong.  For the
+                        * parallelism to work, we can't rephrase it, so we
+                        * zap the "laid by you" momentarily instead.
+                        */
+                       struct obj *obj = level.objects[u.ux][u.uy];
+
+                       if (obj ||
+                             (youmonst.data->mlet == S_EEL && is_pool(u.ux, u.uy))) {
+                           int save_spe = 0; /* suppress warning */
+                           if (obj) {
+                               save_spe = obj->spe;
+                               if (obj->otyp == EGG) obj->spe = 0;
+                           }
+                           if (youmonst.data->mlet == S_EEL)
+               pline("Wait, %s!  There's a hidden %s named %s there!",
+                               m_monnam(mtmp), youmonst.data->mname, plname);
+                           else
+            pline("Wait, %s!  There's a %s named %s hiding under %s!",
+                               m_monnam(mtmp), youmonst.data->mname, plname,
+                               doname(level.objects[u.ux][u.uy]));
+                           if (obj) obj->spe = save_spe;
+                       } else
+                           impossible("hiding under nothing?");
+                   }
+                   newsym(u.ux,u.uy);
+               }
+               return(0);
+       }
+       if (youmonst.data->mlet == S_MIMIC && youmonst.m_ap_type &&
+                   !range2 && foundyou && !u.uswallow) {
+               if (!youseeit) pline("It gets stuck on you.");
+               else pline("Wait, %s!  That's a %s named %s!",
+                          m_monnam(mtmp), youmonst.data->mname, plname);
+               u.ustuck = mtmp;
+               youmonst.m_ap_type = M_AP_NOTHING;
+               youmonst.mappearance = 0;
+               newsym(u.ux,u.uy);
+               return(0);
+       }
+
+       /* player might be mimicking an object */
+       if (youmonst.m_ap_type == M_AP_OBJECT && !range2 && foundyou && !u.uswallow) {
+           if (!youseeit)
+                pline("%s %s!", Something,
+                       (likes_gold(mtmp->data) && youmonst.mappearance == GOLD_PIECE) ?
+                       "tries to pick you up" : "disturbs you");
+           else pline("Wait, %s!  That %s is really %s named %s!",
+                       m_monnam(mtmp),
+                       mimic_obj_name(&youmonst),
+                       an(mons[u.umonnum].mname),
+                       plname);
+           if (multi < 0) {    /* this should always be the case */
+               char buf[BUFSZ];
+               Sprintf(buf, "You appear to be %s again.",
+                       Upolyd ? (const char *) an(youmonst.data->mname) :
+                           (const char *) "yourself");
+               unmul(buf);     /* immediately stop mimicking */
+           }
+           return 0;
+       }
+
+/*     Work out the armor class differential   */
+       tmp = AC_VALUE(u.uac) + 10;             /* tmp ~= 0 - 20 */
+       tmp += mtmp->m_lev;
+       if(multi < 0) tmp += 4;
+       if((Invis && !perceives(mdat)) || !mtmp->mcansee)
+               tmp -= 2;
+       if(mtmp->mtrapped) tmp -= 2;
+       if(tmp <= 0) tmp = 1;
+
+       /* make eels visible the moment they hit/miss us */
+       if(mdat->mlet == S_EEL && mtmp->minvis && cansee(mtmp->mx,mtmp->my)) {
+               mtmp->minvis = 0;
+               newsym(mtmp->mx,mtmp->my);
+       }
+
+/*     Special demon handling code */
+       if(!mtmp->cham && is_demon(mdat) && !range2
+          && mtmp->data != &mons[PM_BALROG]
+          && mtmp->data != &mons[PM_SUCCUBUS]
+          && mtmp->data != &mons[PM_INCUBUS])
+           if(!mtmp->mcan && !rn2(13)) msummon(mtmp);
+
+/*     Special lycanthrope handling code */
+       if(!mtmp->cham && is_were(mdat) && !range2) {
+
+           if(is_human(mdat)) {
+               if(!rn2(5 - (night() * 2)) && !mtmp->mcan) new_were(mtmp);
+           } else if(!rn2(30) && !mtmp->mcan) new_were(mtmp);
+           mdat = mtmp->data;
+
+           if(!rn2(10) && !mtmp->mcan) {
+               int numseen, numhelp;
+               char buf[BUFSZ], genericwere[BUFSZ];
+
+               Strcpy(genericwere, "creature");
+               numhelp = were_summon(mdat, FALSE, &numseen, genericwere);
+               if (youseeit) {
+                       pline("%s summons help!", Monnam(mtmp));
+                       if (numhelp > 0) {
+                           if (numseen == 0)
+                               You_feel("hemmed in.");
+                       } else pline("But none comes.");
+               } else {
+                       const char *from_nowhere;
+
+                       if (flags.soundok) {
+                               pline("%s %s!", Something,
+                                       makeplural(growl_sound(mtmp)));
+                               from_nowhere = "";
+                       } else from_nowhere = " from nowhere";
+                       if (numhelp > 0) {
+                           if (numseen < 1) You_feel("hemmed in.");
+                           else {
+                               if (numseen == 1)
+                                       Sprintf(buf, "%s appears",
+                                                       an(genericwere));
+                               else
+                                       Sprintf(buf, "%s appear",
+                                                       makeplural(genericwere));
+                               pline("%s%s!", upstart(buf), from_nowhere);
+                           }
+                       } /* else no help came; but you didn't know it tried */
+               }
+           }
+       }
+
+       if(u.uinvulnerable) {
+           /* monsters won't attack you */
+           if(mtmp == u.ustuck)
+               pline("%s loosens its grip slightly.", Monnam(mtmp));
+           else if(!range2) {
+               if (youseeit || sensemon(mtmp))
+                   pline("%s starts to attack you, but pulls back.",
+                         Monnam(mtmp));
+               else
+                   You_feel("%s move nearby.", something);
+           }
+           return (0);
+       }
+
+       /* Unlike defensive stuff, don't let them use item _and_ attack. */
+       if(find_offensive(mtmp)) {
+               int foo = use_offensive(mtmp);
+
+               if (foo != 0) return(foo==1);
+       }
+
+       for(i = 0; i < NATTK; i++) {
+
+           sum[i] = 0;
+           mattk = getmattk(mdat, i, sum, &alt_attk);
+           if (u.uswallow && (mattk->aatyp != AT_ENGL))
+               continue;
+           switch(mattk->aatyp) {
+               case AT_CLAW:   /* "hand to hand" attacks */
+               case AT_KICK:
+               case AT_BITE:
+               case AT_STNG:
+               case AT_TUCH:
+               case AT_BUTT:
+               case AT_TENT:
+                       if(!range2 && (!MON_WEP(mtmp) || mtmp->mconf || Conflict ||
+                                       !touch_petrifies(youmonst.data))) {
+                           if (foundyou) {
+                               if(tmp > (j = rnd(20+i))) {
+                                   if (mattk->aatyp != AT_KICK ||
+                                           !thick_skinned(youmonst.data))
+                                       sum[i] = hitmu(mtmp, mattk);
+                               } else
+                                   missmu(mtmp, (tmp == j), mattk);
+                           } else
+                               wildmiss(mtmp, mattk);
+                       }
+                       break;
+
+               case AT_HUGS:   /* automatic if prev two attacks succeed */
+                       /* Note: if displaced, prev attacks never succeeded */
+                       if((!range2 && i>=2 && sum[i-1] && sum[i-2])
+                                                       || mtmp == u.ustuck)
+                               sum[i]= hitmu(mtmp, mattk);
+                       break;
+
+               case AT_GAZE:   /* can affect you either ranged or not */
+                       /* Medusa gaze already operated through m_respond in
+                        * dochug(); don't gaze more than once per round.
+                        */
+                       if (mdat != &mons[PM_MEDUSA])
+                               sum[i] = gazemu(mtmp, mattk);
+                       break;
+
+               case AT_EXPL:   /* automatic hit if next to, and aimed at you */
+                       if(!range2) sum[i] = explmu(mtmp, mattk, foundyou);
+                       break;
+
+               case AT_ENGL:
+                       if (!range2) {
+                           if(foundyou) {
+                               if(u.uswallow || tmp > (j = rnd(20+i))) {
+                                   /* Force swallowing monster to be
+                                    * displayed even when player is
+                                    * moving away */
+                                   flush_screen(1);
+                                   sum[i] = gulpmu(mtmp, mattk);
+                               } else {
+                                   missmu(mtmp, (tmp == j), mattk);
+                               }
+                           } else if (is_animal(mtmp->data)) {
+                               pline("%s gulps some air!", Monnam(mtmp));
+                           } else {
+                               if (youseeit)
+                                   pline("%s lunges forward and recoils!",
+                                         Monnam(mtmp));
+                               else
+                                   You_hear("a %s nearby.",
+                                            is_whirly(mtmp->data) ?
+                                               "rushing noise" : "splat");
+                          }
+                       }
+                       break;
+               case AT_BREA:
+                       if(range2) sum[i] = breamu(mtmp, mattk);
+                       /* Note: breamu takes care of displacement */
+                       break;
+               case AT_SPIT:
+                       if(range2) sum[i] = spitmu(mtmp, mattk);
+                       /* Note: spitmu takes care of displacement */
+                       break;
+               case AT_WEAP:
+                       if(range2) {
+#ifdef REINCARNATION
+                               if (!Is_rogue_level(&u.uz))
+#endif
+                                       thrwmu(mtmp);
+                       } else {
+                           int hittmp = 0;
+
+                           /* Rare but not impossible.  Normally the monster
+                            * wields when 2 spaces away, but it can be
+                            * teleported or whatever....
+                            */
+                           if (mtmp->weapon_check == NEED_WEAPON ||
+                                                       !MON_WEP(mtmp)) {
+                               mtmp->weapon_check = NEED_HTH_WEAPON;
+                               /* mon_wield_item resets weapon_check as
+                                * appropriate */
+                               if (mon_wield_item(mtmp) != 0) break;
+                           }
+                           if (foundyou) {
+                               otmp = MON_WEP(mtmp);
+                               if(otmp) {
+                                   hittmp = hitval(otmp, &youmonst);
+                                   tmp += hittmp;
+                                   mswings(mtmp, otmp);
+                               }
+                               if(tmp > (j = dieroll = rnd(20+i)))
+                                   sum[i] = hitmu(mtmp, mattk);
+                               else
+                                   missmu(mtmp, (tmp == j), mattk);
+                               /* KMH -- Don't accumulate to-hit bonuses */
+                               if (otmp)
+                                       tmp -= hittmp;
+                           } else
+                               wildmiss(mtmp, mattk);
+                       }
+                       break;
+               case AT_MAGC:
+                       if (range2)
+                           sum[i] = buzzmu(mtmp, mattk);
+                       else {
+                           if (foundyou)
+                               sum[i] = castmu(mtmp, mattk, TRUE, TRUE);
+                           else
+                               sum[i] = castmu(mtmp, mattk, TRUE, FALSE);
+                       }
+                       break;
+
+               default:                /* no attack */
+                       break;
+           }
+           if(flags.botl) bot();
+       /* give player a chance of waking up before dying -kaa */
+           if(sum[i] == 1) {       /* successful attack */
+               if (u.usleep && u.usleep < monstermoves && !rn2(10)) {
+                   multi = -1;
+                   nomovemsg = "The combat suddenly awakens you.";
+               }
+           }
+           if(sum[i] == 2) return 1;           /* attacker dead */
+           if(sum[i] == 3) break;  /* attacker teleported, no more attacks */
+           /* sum[i] == 0: unsuccessful attack */
+       }
+       return(0);
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+/*
+ * helper function for some compilers that have trouble with hitmu
+ */
+
+STATIC_OVL void
+hurtarmor(attk)
+int attk;
+{
+       int     hurt;
+
+       switch(attk) {
+           /* 0 is burning, which we should never be called with */
+           case AD_RUST: hurt = 1; break;
+           case AD_CORR: hurt = 3; break;
+           default: hurt = 2; break;
+       }
+
+       /* What the following code does: it keeps looping until it
+        * finds a target for the rust monster.
+        * Head, feet, etc... not covered by metal, or covered by
+        * rusty metal, are not targets.  However, your body always
+        * is, no matter what covers it.
+        */
+       while (1) {
+           switch(rn2(5)) {
+           case 0:
+               if (!uarmh || !rust_dmg(uarmh, xname(uarmh), hurt, FALSE, &youmonst))
+                       continue;
+               break;
+           case 1:
+               if (uarmc) {
+                   (void)rust_dmg(uarmc, xname(uarmc), hurt, TRUE, &youmonst);
+                   break;
+               }
+               /* Note the difference between break and continue;
+                * break means it was hit and didn't rust; continue
+                * means it wasn't a target and though it didn't rust
+                * something else did.
+                */
+               if (uarm)
+                   (void)rust_dmg(uarm, xname(uarm), hurt, TRUE, &youmonst);
+#ifdef TOURIST
+               else if (uarmu)
+                   (void)rust_dmg(uarmu, xname(uarmu), hurt, TRUE, &youmonst);
+#endif
+               break;
+           case 2:
+               if (!uarms || !rust_dmg(uarms, xname(uarms), hurt, FALSE, &youmonst))
+                   continue;
+               break;
+           case 3:
+               if (!uarmg || !rust_dmg(uarmg, xname(uarmg), hurt, FALSE, &youmonst))
+                   continue;
+               break;
+           case 4:
+               if (!uarmf || !rust_dmg(uarmf, xname(uarmf), hurt, FALSE, &youmonst))
+                   continue;
+               break;
+           }
+           break; /* Out of while loop */
+       }
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+STATIC_OVL boolean
+diseasemu(mdat)
+struct permonst *mdat;
+{
+       if (Sick_resistance) {
+               You_feel("a slight illness.");
+               return FALSE;
+       } else {
+               make_sick(Sick ? Sick/3L + 1L : (long)rn1(ACURR(A_CON), 20),
+                       mdat->mname, TRUE, SICK_NONVOMITABLE);
+               return TRUE;
+       }
+}
+
+/* check whether slippery clothing protects from hug or wrap attack */
+STATIC_OVL boolean
+u_slip_free(mtmp, mattk)
+struct monst *mtmp;
+struct attack *mattk;
+{
+       struct obj *obj = (uarmc ? uarmc : uarm);
+
+#ifdef TOURIST
+       if (!obj) obj = uarmu;
+#endif
+       if (mattk->adtyp == AD_DRIN) obj = uarmh;
+
+       /* if your cloak/armor is greased, monster slips off; this
+          protection might fail (33% chance) when the armor is cursed */
+       if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK) &&
+               (!obj->cursed || rn2(3))) {
+           pline("%s %s your %s %s!",
+                 Monnam(mtmp),
+                 (mattk->adtyp == AD_WRAP) ?
+                       "slips off of" : "grabs you, but cannot hold onto",
+                 obj->greased ? "greased" : "slippery",
+                 /* avoid "slippery slippery cloak"
+                    for undiscovered oilskin cloak */
+                 (obj->greased || objects[obj->otyp].oc_name_known) ?
+                       xname(obj) : cloak_simple_name(obj));
+
+           if (obj->greased && !rn2(2)) {
+               pline_The("grease wears off.");
+               obj->greased = 0;
+               update_inventory();
+           }
+           return TRUE;
+       }
+       return FALSE;
+}
+
+/* armor that sufficiently covers the body might be able to block magic */
+int
+magic_negation(mon)
+struct monst *mon;
+{
+       struct obj *armor;
+       int armpro = 0;
+
+       armor = (mon == &youmonst) ? uarm : which_armor(mon, W_ARM);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+       armor = (mon == &youmonst) ? uarmc : which_armor(mon, W_ARMC);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+       armor = (mon == &youmonst) ? uarmh : which_armor(mon, W_ARMH);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+
+       /* armor types for shirt, gloves, shoes, and shield don't currently
+          provide any magic cancellation but we might as well be complete */
+#ifdef TOURIST
+       armor = (mon == &youmonst) ? uarmu : which_armor(mon, W_ARMU);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+#endif
+       armor = (mon == &youmonst) ? uarmg : which_armor(mon, W_ARMG);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+       armor = (mon == &youmonst) ? uarmf : which_armor(mon, W_ARMF);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+       armor = (mon == &youmonst) ? uarms : which_armor(mon, W_ARMS);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+
+#ifdef STEED
+       /* this one is really a stretch... */
+       armor = (mon == &youmonst) ? 0 : which_armor(mon, W_SADDLE);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+#endif
+
+       return armpro;
+}
+
+/*
+ * hitmu: monster hits you
+ *       returns 2 if monster dies (e.g. "yellow light"), 1 otherwise
+ *       3 if the monster lives but teleported/paralyzed, so it can't keep
+ *            attacking you
+ */
+STATIC_OVL int
+hitmu(mtmp, mattk)
+       register struct monst *mtmp;
+       register struct attack  *mattk;
+{
+       register struct permonst *mdat = mtmp->data;
+       register int uncancelled, ptmp;
+       int dmg, armpro, permdmg;
+       char     buf[BUFSZ];
+       struct permonst *olduasmon = youmonst.data;
+       int res;
+
+       if (!canspotmon(mtmp))
+           map_invisible(mtmp->mx, mtmp->my);
+
+/*     If the monster is undetected & hits you, you should know where
+ *     the attack came from.
+ */
+       if(mtmp->mundetected && (hides_under(mdat) || mdat->mlet == S_EEL)) {
+           mtmp->mundetected = 0;
+           if (!(Blind ? Blind_telepat : Unblind_telepat)) {
+               struct obj *obj;
+               const char *what;
+
+               if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0) {
+                   if (Blind && !obj->dknown)
+                       what = something;
+                   else if (is_pool(mtmp->mx, mtmp->my) && !Underwater)
+                       what = "the water";
+                   else
+                       what = doname(obj);
+
+                   pline("%s was hidden under %s!", Amonnam(mtmp), what);
+               }
+               newsym(mtmp->mx, mtmp->my);
+           }
+       }
+
+/*     First determine the base damage done */
+       dmg = d((int)mattk->damn, (int)mattk->damd);
+       if(is_undead(mdat) && midnight())
+               dmg += d((int)mattk->damn, (int)mattk->damd); /* extra damage */
+
+/*     Next a cancellation factor      */
+/*     Use uncancelled when the cancellation factor takes into account certain
+ *     armor's special magic protection.  Otherwise just use !mtmp->mcan.
+ */
+       armpro = magic_negation(&youmonst);
+       uncancelled = !mtmp->mcan && ((rn2(3) >= armpro) || !rn2(50));
+
+       permdmg = 0;
+/*     Now, adjust damages via resistances or specific attacks */
+       switch(mattk->adtyp) {
+           case AD_PHYS:
+               if (mattk->aatyp == AT_HUGS && !sticks(youmonst.data)) {
+                   if(!u.ustuck && rn2(2)) {
+                       if (u_slip_free(mtmp, mattk)) {
+                           dmg = 0;
+                       } else {
+                           u.ustuck = mtmp;
+                           pline("%s grabs you!", Monnam(mtmp));
+                       }
+                   } else if(u.ustuck == mtmp) {
+                       exercise(A_STR, FALSE);
+                       You("are being %s.",
+                             (mtmp->data == &mons[PM_ROPE_GOLEM])
+                             ? "choked" : "crushed");
+                   }
+               } else {                          /* hand to hand weapon */
+                   if(mattk->aatyp == AT_WEAP && otmp) {
+                       if (otmp->otyp == CORPSE
+                               && touch_petrifies(&mons[otmp->corpsenm])) {
+                           dmg = 1;
+                           pline("%s hits you with the %s corpse.",
+                               Monnam(mtmp), mons[otmp->corpsenm].mname);
+                           if (!Stoned)
+                               goto do_stone;
+                       }
+                       dmg += dmgval(otmp, &youmonst);
+                       if (dmg <= 0) dmg = 1;
+                       if (!(otmp->oartifact &&
+                               artifact_hit(mtmp, &youmonst, otmp, &dmg,dieroll)))
+                            hitmsg(mtmp, mattk);
+                       if (!dmg) break;
+                       if (u.mh > 1 && u.mh > ((u.uac>0) ? dmg : dmg+u.uac) &&
+                                  objects[otmp->otyp].oc_material == IRON &&
+                                       (u.umonnum==PM_BLACK_PUDDING
+                                       || u.umonnum==PM_BROWN_PUDDING)) {
+                           /* This redundancy necessary because you have to
+                            * take the damage _before_ being cloned.
+                            */
+                           if (u.uac < 0) dmg += u.uac;
+                           if (dmg < 1) dmg = 1;
+                           if (dmg > 1) exercise(A_STR, FALSE);
+                           u.mh -= dmg;
+                           flags.botl = 1;
+                           dmg = 0;
+                           if(cloneu())
+                           You("divide as %s hits you!",mon_nam(mtmp));
+                       }
+                       urustm(mtmp, otmp);
+                   } else if (mattk->aatyp != AT_TUCH || dmg != 0 ||
+                               mtmp != u.ustuck)
+                       hitmsg(mtmp, mattk);
+               }
+               break;
+           case AD_DISE:
+               hitmsg(mtmp, mattk);
+               if (!diseasemu(mdat)) dmg = 0;
+               break;
+           case AD_FIRE:
+               hitmsg(mtmp, mattk);
+               if (uncancelled) {
+                   pline("You're %s!", on_fire(youmonst.data, mattk));
+                   if (youmonst.data == &mons[PM_STRAW_GOLEM] ||
+                       youmonst.data == &mons[PM_PAPER_GOLEM]) {
+                           You("roast!");
+                           /* KMH -- this is okay with unchanging */
+                           rehumanize();
+                           break;
+                   } else if (Fire_resistance) {
+                       pline_The("fire doesn't feel hot!");
+                       dmg = 0;
+                   }
+                   if((int) mtmp->m_lev > rn2(20))
+                       destroy_item(SCROLL_CLASS, AD_FIRE);
+                   if((int) mtmp->m_lev > rn2(20))
+                       destroy_item(POTION_CLASS, AD_FIRE);
+                   if((int) mtmp->m_lev > rn2(25))
+                       destroy_item(SPBOOK_CLASS, AD_FIRE);
+                   burn_away_slime();
+               } else dmg = 0;
+               break;
+           case AD_COLD:
+               hitmsg(mtmp, mattk);
+               if (uncancelled) {
+                   pline("You're covered in frost!");
+                   if (Cold_resistance) {
+                       pline_The("frost doesn't seem cold!");
+                       dmg = 0;
+                   }
+                   if((int) mtmp->m_lev > rn2(20))
+                       destroy_item(POTION_CLASS, AD_COLD);
+               } else dmg = 0;
+               break;
+           case AD_ELEC:
+               hitmsg(mtmp, mattk);
+               if (uncancelled) {
+                   You("get zapped!");
+                   if (Shock_resistance) {
+                       pline_The("zap doesn't shock you!");
+                       dmg = 0;
+                   }
+                   if((int) mtmp->m_lev > rn2(20))
+                       destroy_item(WAND_CLASS, AD_ELEC);
+                   if((int) mtmp->m_lev > rn2(20))
+                       destroy_item(RING_CLASS, AD_ELEC);
+               } else dmg = 0;
+               break;
+           case AD_SLEE:
+               hitmsg(mtmp, mattk);
+               if (uncancelled && multi >= 0 && !rn2(5)) {
+                   if (Sleep_resistance) break;
+                   fall_asleep(-rnd(10), TRUE);
+                   if (Blind) You("are put to sleep!");
+                   else You("are put to sleep by %s!", mon_nam(mtmp));
+               }
+               break;
+           case AD_BLND:
+               if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj*)0)) {
+                   if (!Blind) pline("%s blinds you!", Monnam(mtmp));
+                   make_blinded(Blinded+(long)dmg,FALSE);
+                   if (!Blind) Your(vision_clears);
+               }
+               dmg = 0;
+               break;
+           case AD_DRST:
+               ptmp = A_STR;
+               goto dopois;
+           case AD_DRDX:
+               ptmp = A_DEX;
+               goto dopois;
+           case AD_DRCO:
+               ptmp = A_CON;
+dopois:
+               hitmsg(mtmp, mattk);
+               if (uncancelled && !rn2(8)) {
+                   Sprintf(buf, "%s %s",
+                           s_suffix(Monnam(mtmp)), mpoisons_subj(mtmp, mattk));
+                   poisoned(buf, ptmp, mdat->mname, 30);
+               }
+               break;
+           case AD_DRIN:
+               hitmsg(mtmp, mattk);
+               if (defends(AD_DRIN, uwep) || !has_head(youmonst.data)) {
+                   You("don't seem harmed.");
+                   /* Not clear what to do for green slimes */
+                   break;
+               }
+               if (u_slip_free(mtmp,mattk)) break;
+
+               if (uarmh && rn2(8)) {
+                   /* not body_part(HEAD) */
+                   Your("helmet blocks the attack to your head.");
+                   break;
+               }
+               if (Half_physical_damage) dmg = (dmg+1) / 2;
+               mdamageu(mtmp, dmg);
+
+               if (!uarmh || uarmh->otyp != DUNCE_CAP) {
+                   Your("brain is eaten!");
+                   /* No such thing as mindless players... */
+                   if (ABASE(A_INT) <= ATTRMIN(A_INT)) {
+                       int lifesaved = 0;
+                       struct obj *wore_amulet = uamul;
+
+                       while(1) {
+                           /* avoid looping on "die(y/n)?" */
+                           if (lifesaved && (discover || wizard)) {
+                               if (wore_amulet && !uamul) {
+                                   /* used up AMULET_OF_LIFE_SAVING; still
+                                      subject to dying from brainlessness */
+                                   wore_amulet = 0;
+                               } else {
+                                   /* explicitly chose not to die;
+                                      arbitrarily boost intelligence */
+                                   ABASE(A_INT) = ATTRMIN(A_INT) + 2;
+                                   You_feel("like a scarecrow.");
+                                   break;
+                               }
+                           }
+
+                           if (lifesaved)
+                               pline("Unfortunately your brain is still gone.");
+                           else
+                               Your("last thought fades away.");
+                           killer = "brainlessness";
+                           killer_format = KILLED_BY;
+                           done(DIED);
+                           lifesaved++;
+                       }
+                   }
+               }
+               /* adjattrib gives dunce cap message when appropriate */
+               (void) adjattrib(A_INT, -rnd(2), FALSE);
+               forget_levels(25);      /* lose memory of 25% of levels */
+               forget_objects(25);     /* lose memory of 25% of objects */
+               exercise(A_WIS, FALSE);
+               break;
+           case AD_PLYS:
+               hitmsg(mtmp, mattk);
+               if (uncancelled && multi >= 0 && !rn2(3)) {
+                   if (Free_action) {
+                       You("momentarily stiffen.");            
+                   } else {
+                       if (Blind) You("are frozen!");
+                       else You("are frozen by %s!", mon_nam(mtmp));
+                       nomovemsg = 0;  /* default: "you can move again" */
+                       nomul(-rnd(10));
+                       exercise(A_DEX, FALSE);
+                   }
+               }
+               break;
+           case AD_DRLI:
+               hitmsg(mtmp, mattk);
+               if (uncancelled && !rn2(3) && !Drain_resistance) {
+                   losexp("life drainage");
+               }
+               break;
+           case AD_LEGS:
+               { register long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
+                 const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left";
+
+               /* This case is too obvious to ignore, but Nethack is not in
+                * general very good at considering height--most short monsters
+                * still _can_ attack you when you're flying or mounted.
+                * [FIXME: why can't a flying attacker overcome this?]
+                */
+                 if (
+#ifdef STEED
+                       u.usteed ||
+#endif
+                                   Levitation || Flying) {
+                   pline("%s tries to reach your %s %s!", Monnam(mtmp),
+                         sidestr, body_part(LEG));
+                   dmg = 0;
+                 } else if (mtmp->mcan) {
+                   pline("%s nuzzles against your %s %s!", Monnam(mtmp),
+                         sidestr, body_part(LEG));
+                   dmg = 0;
+                 } else {
+                   if (uarmf) {
+                       if (rn2(2) && (uarmf->otyp == LOW_BOOTS ||
+                                            uarmf->otyp == IRON_SHOES))
+                           pline("%s pricks the exposed part of your %s %s!",
+                               Monnam(mtmp), sidestr, body_part(LEG));
+                       else if (!rn2(5))
+                           pline("%s pricks through your %s boot!",
+                               Monnam(mtmp), sidestr);
+                       else {
+                           pline("%s scratches your %s boot!", Monnam(mtmp),
+                               sidestr);
+                           dmg = 0;
+                           break;
+                       }
+                   } else pline("%s pricks your %s %s!", Monnam(mtmp),
+                         sidestr, body_part(LEG));
+                   set_wounded_legs(side, rnd(60-ACURR(A_DEX)));
+                   exercise(A_STR, FALSE);
+                   exercise(A_DEX, FALSE);
+                 }
+                 break;
+               }
+           case AD_STON:       /* cockatrice */
+               hitmsg(mtmp, mattk);
+               if(!rn2(3)) {
+                   if (mtmp->mcan) {
+                       if (flags.soundok)
+                           You_hear("a cough from %s!", mon_nam(mtmp));
+                   } else {
+                       if (flags.soundok)
+                           You_hear("%s hissing!", s_suffix(mon_nam(mtmp)));
+                       if(!rn2(10) ||
+                           (flags.moonphase == NEW_MOON && !have_lizard())) {
+ do_stone:
+                           if (!Stoned && !Stone_resistance
+                                   && !(poly_when_stoned(youmonst.data) &&
+                                       polymon(PM_STONE_GOLEM))) {
+                               Stoned = 5;
+                               delayed_killer = mtmp->data->mname;
+                               if (mtmp->data->geno & G_UNIQ) {
+                                   if (!type_is_pname(mtmp->data)) {
+                                       static char kbuf[BUFSZ];
+
+                                       /* "the" buffer may be reallocated */
+                                       Strcpy(kbuf, the(delayed_killer));
+                                       delayed_killer = kbuf;
+                                   }
+                                   killer_format = KILLED_BY;
+                               } else killer_format = KILLED_BY_AN;
+                               return(1);
+                               /* You("turn to stone..."); */
+                               /* done_in_by(mtmp); */
+                           }
+                       }
+                   }
+               }
+               break;
+           case AD_STCK:
+               hitmsg(mtmp, mattk);
+               if (uncancelled && !u.ustuck && !sticks(youmonst.data))
+                       u.ustuck = mtmp;
+               break;
+           case AD_WRAP:
+               if ((!mtmp->mcan || u.ustuck == mtmp) && !sticks(youmonst.data)) {
+                   if (!u.ustuck && !rn2(10)) {
+                       if (u_slip_free(mtmp, mattk)) {
+                           dmg = 0;
+                       } else {
+                           pline("%s swings itself around you!",
+                                 Monnam(mtmp));
+                           u.ustuck = mtmp;
+                       }
+                   } else if(u.ustuck == mtmp) {
+                       if (is_pool(mtmp->mx,mtmp->my) && !Swimming
+                           && !Amphibious) {
+                           boolean moat =
+                               (levl[mtmp->mx][mtmp->my].typ != POOL) &&
+                               (levl[mtmp->mx][mtmp->my].typ != WATER) &&
+                               !Is_medusa_level(&u.uz) &&
+                               !Is_waterlevel(&u.uz);
+
+                           pline("%s drowns you...", Monnam(mtmp));
+                           killer_format = KILLED_BY_AN;
+                           Sprintf(buf, "%s by %s",
+                                   moat ? "moat" : "pool of water",
+                                   an(mtmp->data->mname));
+                           killer = buf;
+                           done(DROWNING);
+                       } else if(mattk->aatyp == AT_HUGS)
+                           You("are being crushed.");
+                   } else {
+                       dmg = 0;
+                       if(flags.verbose)
+                           pline("%s brushes against your %s.", Monnam(mtmp),
+                                  body_part(LEG));
+                   }
+               } else dmg = 0;
+               break;
+           case AD_WERE:
+               hitmsg(mtmp, mattk);
+               if (uncancelled && !rn2(4) && u.ulycn == NON_PM &&
+                       !Protection_from_shape_changers &&
+                       !defends(AD_WERE,uwep)) {
+                   You_feel("feverish.");
+                   exercise(A_CON, FALSE);
+                   u.ulycn = monsndx(mdat);
+               }
+               break;
+           case AD_SGLD:
+               hitmsg(mtmp, mattk);
+               if (youmonst.data->mlet == mdat->mlet) break;
+               if(!mtmp->mcan) stealgold(mtmp);
+               break;
+
+           case AD_SITM:       /* for now these are the same */
+           case AD_SEDU:
+               if (is_animal(mtmp->data)) {
+                       hitmsg(mtmp, mattk);
+                       if (mtmp->mcan) break;
+                       /* Continue below */
+               } else if (dmgtype(youmonst.data, AD_SEDU)
+#ifdef SEDUCE
+                       || dmgtype(youmonst.data, AD_SSEX)
+#endif
+                                               ) {
+                       pline("%s %s.", Monnam(mtmp), mtmp->minvent ?
+                   "brags about the goods some dungeon explorer provided" :
+                   "makes some remarks about how difficult theft is lately");
+                       if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
+                       return 3;
+               } else if (mtmp->mcan) {
+                   if (!Blind) {
+                       pline("%s tries to %s you, but you seem %s.",
+                           Adjmonnam(mtmp, "plain"),
+                           flags.female ? "charm" : "seduce",
+                           flags.female ? "unaffected" : "uninterested");
+                   }
+                   if(rn2(3)) {
+                       if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
+                       return 3;
+                   }
+                   break;
+               }
+               buf[0] = '\0';
+               switch (steal(mtmp, buf)) {
+                 case -1:
+                       return 2;
+                 case 0:
+                       break;
+                 default:
+                       if (!is_animal(mtmp->data) && !tele_restrict(mtmp))
+                           (void) rloc(mtmp, FALSE);
+                       if (is_animal(mtmp->data) && *buf) {
+                           if (canseemon(mtmp))
+                               pline("%s tries to %s away with %s.",
+                                     Monnam(mtmp),
+                                     locomotion(mtmp->data, "run"),
+                                     buf);
+                       }
+                       monflee(mtmp, 0, FALSE, FALSE);
+                       return 3;
+               }
+               break;
+#ifdef SEDUCE
+           case AD_SSEX:
+               if(could_seduce(mtmp, &youmonst, mattk) == 1
+                       && !mtmp->mcan)
+                   if (doseduce(mtmp))
+                       return 3;
+               break;
+#endif
+           case AD_SAMU:
+               hitmsg(mtmp, mattk);
+               /* when the Wiz hits, 1/20 steals the amulet */
+               if (u.uhave.amulet ||
+                    u.uhave.bell || u.uhave.book || u.uhave.menorah
+                    || u.uhave.questart) /* carrying the Quest Artifact */
+                   if (!rn2(20)) stealamulet(mtmp);
+               break;
+
+           case AD_TLPT:
+               hitmsg(mtmp, mattk);
+               if (uncancelled) {
+                   if(flags.verbose)
+                       Your("position suddenly seems very uncertain!");
+                   tele();
+               }
+               break;
+           case AD_RUST:
+               hitmsg(mtmp, mattk);
+               if (mtmp->mcan) break;
+               if (u.umonnum == PM_IRON_GOLEM) {
+                       You("rust!");
+                       /* KMH -- this is okay with unchanging */
+                       rehumanize();
+                       break;
+               }
+               hurtarmor(AD_RUST);
+               break;
+           case AD_CORR:
+               hitmsg(mtmp, mattk);
+               if (mtmp->mcan) break;
+               hurtarmor(AD_CORR);
+               break;
+           case AD_DCAY:
+               hitmsg(mtmp, mattk);
+               if (mtmp->mcan) break;
+               if (u.umonnum == PM_WOOD_GOLEM ||
+                   u.umonnum == PM_LEATHER_GOLEM) {
+                       You("rot!");
+                       /* KMH -- this is okay with unchanging */
+                       rehumanize();
+                       break;
+               }
+               hurtarmor(AD_DCAY);
+               break;
+           case AD_HEAL:
+               /* a cancelled nurse is just an ordinary monster */
+               if (mtmp->mcan) {
+                   hitmsg(mtmp, mattk);
+                   break;
+               }
+               if(!uwep
+#ifdef TOURIST
+                  && !uarmu
+#endif
+                  && !uarm && !uarmh && !uarms && !uarmg && !uarmc && !uarmf) {
+                   boolean goaway = FALSE;
+                   pline("%s hits!  (I hope you don't mind.)", Monnam(mtmp));
+                   if (Upolyd) {
+                       u.mh += rnd(7);
+                       if (!rn2(7)) {
+                           /* no upper limit necessary; effect is temporary */
+                           u.mhmax++;
+                           if (!rn2(13)) goaway = TRUE;
+                       }
+                       if (u.mh > u.mhmax) u.mh = u.mhmax;
+                   } else {
+                       u.uhp += rnd(7);
+                       if (!rn2(7)) {
+                           /* hard upper limit via nurse care: 25 * ulevel */
+                           if (u.uhpmax < 5 * u.ulevel + d(2 * u.ulevel, 10))
+                               u.uhpmax++;
+                           if (!rn2(13)) goaway = TRUE;
+                       }
+                       if (u.uhp > u.uhpmax) u.uhp = u.uhpmax;
+                   }
+                   if (!rn2(3)) exercise(A_STR, TRUE);
+                   if (!rn2(3)) exercise(A_CON, TRUE);
+                   if (Sick) make_sick(0L, (char *) 0, FALSE, SICK_ALL);
+                   flags.botl = 1;
+                   if (goaway) {
+                       mongone(mtmp);
+                       return 2;
+                   } else if (!rn2(33)) {
+                       if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
+                       monflee(mtmp, d(3, 6), TRUE, FALSE);
+                       return 3;
+                   }
+                   dmg = 0;
+               } else {
+                   if (Role_if(PM_HEALER)) {
+                       if (flags.soundok && !(moves % 5))
+                     verbalize("Doc, I can't help you unless you cooperate.");
+                       dmg = 0;
+                   } else hitmsg(mtmp, mattk);
+               }
+               break;
+           case AD_CURS:
+               hitmsg(mtmp, mattk);
+               if(!night() && mdat == &mons[PM_GREMLIN]) break;
+               if(!mtmp->mcan && !rn2(10)) {
+                   if (flags.soundok) {
+                       if (Blind) You_hear("laughter.");
+                       else       pline("%s chuckles.", Monnam(mtmp));
+                   }
+                   if (u.umonnum == PM_CLAY_GOLEM) {
+                       pline("Some writing vanishes from your head!");
+                       /* KMH -- this is okay with unchanging */
+                       rehumanize();
+                       break;
+                   }
+                   attrcurse();
+               }
+               break;
+           case AD_STUN:
+               hitmsg(mtmp, mattk);
+               if(!mtmp->mcan && !rn2(4)) {
+                   make_stunned(HStun + dmg, TRUE);
+                   dmg /= 2;
+               }
+               break;
+           case AD_ACID:
+               hitmsg(mtmp, mattk);
+               if (!mtmp->mcan && !rn2(3))
+                   if (Acid_resistance) {
+                       pline("You're covered in acid, but it seems harmless.");
+                       dmg = 0;
+                   } else {
+                       pline("You're covered in acid!  It burns!");
+                       exercise(A_STR, FALSE);
+                   }
+               else            dmg = 0;
+               break;
+           case AD_SLOW:
+               hitmsg(mtmp, mattk);
+               if (uncancelled && HFast &&
+                                       !defends(AD_SLOW, uwep) && !rn2(4))
+                   u_slow_down();
+               break;
+           case AD_DREN:
+               hitmsg(mtmp, mattk);
+               if (uncancelled && !rn2(4))
+                   drain_en(dmg);
+               dmg = 0;
+               break;
+           case AD_CONF:
+               hitmsg(mtmp, mattk);
+               if(!mtmp->mcan && !rn2(4) && !mtmp->mspec_used) {
+                   mtmp->mspec_used = mtmp->mspec_used + (dmg + rn2(6));
+                   if(Confusion)
+                        You("are getting even more confused.");
+                   else You("are getting confused.");
+                   make_confused(HConfusion + dmg, FALSE);
+               }
+               dmg = 0;
+               break;
+           case AD_DETH:
+               pline("%s reaches out with its deadly touch.", Monnam(mtmp));
+               if (is_undead(youmonst.data)) {
+                   /* Still does normal damage */
+                   pline("Was that the touch of death?");
+                   break;
+               }
+               switch (rn2(20)) {
+               case 19: case 18: case 17:
+                   if (!Antimagic) {
+                       killer_format = KILLED_BY_AN;
+                       killer = "touch of death";
+                       done(DIED);
+                       dmg = 0;
+                       break;
+                   } /* else FALLTHRU */
+               default: /* case 16: ... case 5: */
+                   You_feel("your life force draining away...");
+                   permdmg = 1;        /* actual damage done below */
+                   break;
+               case 4: case 3: case 2: case 1: case 0:
+                   if (Antimagic) shieldeff(u.ux, u.uy);
+                   pline("Lucky for you, it didn't work!");
+                   dmg = 0;
+                   break;
+               }
+               break;
+           case AD_PEST:
+               pline("%s reaches out, and you feel fever and chills.",
+                       Monnam(mtmp));
+               (void) diseasemu(mdat); /* plus the normal damage */
+               break;
+           case AD_FAMN:
+               pline("%s reaches out, and your body shrivels.",
+                       Monnam(mtmp));
+               exercise(A_CON, FALSE);
+               if (!is_fainted()) morehungry(rn1(40,40));
+               /* plus the normal damage */
+               break;
+           case AD_SLIM:    
+               hitmsg(mtmp, mattk);
+               if (!uncancelled) break;
+               if (flaming(youmonst.data)) {
+                   pline_The("slime burns away!");
+                   dmg = 0;
+               } else if (Unchanging ||
+                               youmonst.data == &mons[PM_GREEN_SLIME]) {
+                   You("are unaffected.");
+                   dmg = 0;
+               } else if (!Slimed) {
+                   You("don't feel very well.");
+                   Slimed = 10L;
+                   flags.botl = 1;
+                   killer_format = KILLED_BY_AN;
+                   delayed_killer = mtmp->data->mname;
+               } else
+                   pline("Yuck!");
+               break;
+           case AD_ENCH:       /* KMH -- remove enchantment (disenchanter) */
+               hitmsg(mtmp, mattk);
+               /* uncancelled is sufficient enough; please
+                  don't make this attack less frequent */
+               if (uncancelled) {
+                   struct obj *obj = some_armor(&youmonst);
+
+                   if (drain_item(obj)) {
+                       Your("%s less effective.", aobjnam(obj, "seem"));
+                   }
+               }
+               break;
+           default:    dmg = 0;
+                       break;
+       }
+       if(u.uhp < 1) done_in_by(mtmp);
+
+/*     Negative armor class reduces damage done instead of fully protecting
+ *     against hits.
+ */
+       if (dmg && u.uac < 0) {
+               dmg -= rnd(-u.uac);
+               if (dmg < 1) dmg = 1;
+       }
+
+       if(dmg) {
+           if (Half_physical_damage
+                                       /* Mitre of Holiness */
+               || (Role_if(PM_PRIEST) && uarmh && is_quest_artifact(uarmh) &&
+                   (is_undead(mtmp->data) || is_demon(mtmp->data))))
+               dmg = (dmg+1) / 2;
+
+           if (permdmg) {      /* Death's life force drain */
+               int lowerlimit, *hpmax_p;
+               /*
+                * Apply some of the damage to permanent hit points:
+                *      polymorphed         100% against poly'd hpmax
+                *      hpmax > 25*lvl      100% against normal hpmax
+                *      hpmax > 10*lvl  50..100%
+                *      hpmax >  5*lvl  25..75%
+                *      otherwise        0..50%
+                * Never reduces hpmax below 1 hit point per level.
+                */
+               permdmg = rn2(dmg / 2 + 1);
+               if (Upolyd || u.uhpmax > 25 * u.ulevel) permdmg = dmg;
+               else if (u.uhpmax > 10 * u.ulevel) permdmg += dmg / 2;
+               else if (u.uhpmax > 5 * u.ulevel) permdmg += dmg / 4;
+
+               if (Upolyd) {
+                   hpmax_p = &u.mhmax;
+                   /* [can't use youmonst.m_lev] */
+                   lowerlimit = min((int)youmonst.data->mlevel, u.ulevel);
+               } else {
+                   hpmax_p = &u.uhpmax;
+                   lowerlimit = u.ulevel;
+               }
+               if (*hpmax_p - permdmg > lowerlimit)
+                   *hpmax_p -= permdmg;
+               else if (*hpmax_p > lowerlimit)
+                   *hpmax_p = lowerlimit;
+               else    /* unlikely... */
+                   ;   /* already at or below minimum threshold; do nothing */
+               flags.botl = 1;
+           }
+
+           mdamageu(mtmp, dmg);
+       }
+
+       if (dmg)
+           res = passiveum(olduasmon, mtmp, mattk);
+       else
+           res = 1;
+       stop_occupation();
+       return res;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+STATIC_OVL int
+gulpmu(mtmp, mattk)    /* monster swallows you, or damage if u.uswallow */
+       register struct monst *mtmp;
+       register struct attack  *mattk;
+{
+       struct trap *t = t_at(u.ux, u.uy);
+       int     tmp = d((int)mattk->damn, (int)mattk->damd);
+       int     tim_tmp;
+       register struct obj *otmp2;
+       int     i;
+
+       if (!u.uswallow) {      /* swallows you */
+               if (youmonst.data->msize >= MZ_HUGE) return(0);
+               if ((t && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT))) &&
+                   sobj_at(BOULDER, u.ux, u.uy))
+                       return(0);
+
+               if (Punished) unplacebc();      /* ball&chain go away */
+               remove_monster(mtmp->mx, mtmp->my);
+               mtmp->mtrapped = 0;             /* no longer on old trap */
+               place_monster(mtmp, u.ux, u.uy);
+               u.ustuck = mtmp;
+               newsym(mtmp->mx,mtmp->my);
+#ifdef STEED
+               if (is_animal(mtmp->data) && u.usteed) {
+                       char buf[BUFSZ];
+                       /* Too many quirks presently if hero and steed
+                        * are swallowed. Pretend purple worms don't
+                        * like horses for now :-)
+                        */
+                       Strcpy(buf, mon_nam(u.usteed));
+                       pline ("%s lunges forward and plucks you off %s!",
+                               Monnam(mtmp), buf);
+                       dismount_steed(DISMOUNT_ENGULFED);
+               } else
+#endif
+               pline("%s engulfs you!", Monnam(mtmp));
+               stop_occupation();
+               reset_occupations();    /* behave as if you had moved */
+
+               if (u.utrap) {
+                       You("are released from the %s!",
+                               u.utraptype==TT_WEB ? "web" : "trap");
+                       u.utrap = 0;
+               }
+
+               i = number_leashed();
+               if (i > 0) {
+                   const char *s = (i > 1) ? "leashes" : "leash";
+                   pline_The("%s %s loose.", s, vtense(s, "snap"));
+                   unleash_all();
+               }
+
+               if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
+                       minstapetrify(mtmp, TRUE);
+                       if (mtmp->mhp > 0) return 0;
+                       else return 2;
+               }
+
+               display_nhwindow(WIN_MESSAGE, FALSE);
+               vision_recalc(2);       /* hero can't see anything */
+               u.uswallow = 1;
+               /* u.uswldtim always set > 1 */
+               tim_tmp = 25 - (int)mtmp->m_lev;
+               if (tim_tmp > 0) tim_tmp = rnd(tim_tmp) / 2;
+               else if (tim_tmp < 0) tim_tmp = -(rnd(-tim_tmp) / 2);
+               tim_tmp += -u.uac + 10;
+               u.uswldtim = (unsigned)((tim_tmp < 2) ? 2 : tim_tmp);
+               swallowed(1);
+               for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj)
+                   (void) snuff_lit(otmp2);
+       }
+
+       if (mtmp != u.ustuck) return(0);
+       if (u.uswldtim > 0) u.uswldtim -= 1;
+
+       switch(mattk->adtyp) {
+
+               case AD_DGST:
+                   if (Slow_digestion) {
+                       /* Messages are handled below */
+                       u.uswldtim = 0;
+                       tmp = 0;
+                   } else if (u.uswldtim == 0) {
+                       pline("%s totally digests you!", Monnam(mtmp));
+                       tmp = u.uhp;
+                       if (Half_physical_damage) tmp *= 2; /* sorry */
+                   } else {
+                       pline("%s%s digests you!", Monnam(mtmp),
+                             (u.uswldtim == 2) ? " thoroughly" :
+                             (u.uswldtim == 1) ? " utterly" : "");
+                       exercise(A_STR, FALSE);
+                   }
+                   break;
+               case AD_PHYS:
+                   if (mtmp->data == &mons[PM_FOG_CLOUD]) {
+                       You("are laden with moisture and %s",
+                           flaming(youmonst.data) ? "are smoldering out!" :
+                           Breathless ? "find it mildly uncomfortable." :
+                           amphibious(youmonst.data) ? "feel comforted." :
+                           "can barely breathe!");
+                       /* NB: Amphibious includes Breathless */
+                       if (Amphibious && !flaming(youmonst.data)) tmp = 0;
+                   } else {
+                       You("are pummeled with debris!");
+                       exercise(A_STR, FALSE);
+                   }
+                   break;
+               case AD_ACID:
+                   if (Acid_resistance) {
+                       You("are covered with a seemingly harmless goo.");
+                       tmp = 0;
+                   } else {
+                     if (Hallucination) pline("Ouch!  You've been slimed!");
+                     else You("are covered in slime!  It burns!");
+                     exercise(A_STR, FALSE);
+                   }
+                   break;
+               case AD_BLND:
+                   if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj*)0)) {
+                       if(!Blind) {
+                           You_cant("see in here!");
+                           make_blinded((long)tmp,FALSE);
+                           if (!Blind) Your(vision_clears);
+                       } else
+                           /* keep him blind until disgorged */
+                           make_blinded(Blinded+1,FALSE);
+                   }
+                   tmp = 0;
+                   break;
+               case AD_ELEC:
+                   if(!mtmp->mcan && rn2(2)) {
+                       pline_The("air around you crackles with electricity.");
+                       if (Shock_resistance) {
+                               shieldeff(u.ux, u.uy);
+                               You("seem unhurt.");
+                               ugolemeffects(AD_ELEC,tmp);
+                               tmp = 0;
+                       }
+                   } else tmp = 0;
+                   break;
+               case AD_COLD:
+                   if(!mtmp->mcan && rn2(2)) {
+                       if (Cold_resistance) {
+                               shieldeff(u.ux, u.uy);
+                               You_feel("mildly chilly.");
+                               ugolemeffects(AD_COLD,tmp);
+                               tmp = 0;
+                       } else You("are freezing to death!");
+                   } else tmp = 0;
+                   break;
+               case AD_FIRE:
+                   if(!mtmp->mcan && rn2(2)) {
+                       if (Fire_resistance) {
+                               shieldeff(u.ux, u.uy);
+                               You_feel("mildly hot.");
+                               ugolemeffects(AD_FIRE,tmp);
+                               tmp = 0;
+                       } else You("are burning to a crisp!");
+                       burn_away_slime();
+                   } else tmp = 0;
+                   break;
+               case AD_DISE:
+                   if (!diseasemu(mtmp->data)) tmp = 0;
+                   break;
+               default:
+                   tmp = 0;
+                   break;
+       }
+
+       if (Half_physical_damage) tmp = (tmp+1) / 2;
+
+       mdamageu(mtmp, tmp);
+       if (tmp) stop_occupation();
+
+       if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
+           pline("%s very hurriedly %s you!", Monnam(mtmp),
+                 is_animal(mtmp->data)? "regurgitates" : "expels");
+           expels(mtmp, mtmp->data, FALSE);
+       } else if (!u.uswldtim || youmonst.data->msize >= MZ_HUGE) {
+           You("get %s!", is_animal(mtmp->data)? "regurgitated" : "expelled");
+           if (flags.verbose && (is_animal(mtmp->data) ||
+                   (dmgtype(mtmp->data, AD_DGST) && Slow_digestion)))
+               pline("Obviously %s doesn't like your taste.", mon_nam(mtmp));
+           expels(mtmp, mtmp->data, FALSE);
+       }
+       return(1);
+}
+
+STATIC_OVL int
+explmu(mtmp, mattk, ufound)    /* monster explodes in your face */
+register struct monst *mtmp;
+register struct attack  *mattk;
+boolean ufound;
+{
+    if (mtmp->mcan) return(0);
+
+    if (!ufound)
+       pline("%s explodes at a spot in %s!",
+           canseemon(mtmp) ? Monnam(mtmp) : "It",
+           levl[mtmp->mux][mtmp->muy].typ == WATER
+               ? "empty water" : "thin air");
+    else {
+       register int tmp = d((int)mattk->damn, (int)mattk->damd);
+       register boolean not_affected = defends((int)mattk->adtyp, uwep);
+
+       hitmsg(mtmp, mattk);
+
+       switch (mattk->adtyp) {
+           case AD_COLD:
+               not_affected |= Cold_resistance;
+               goto common;
+           case AD_FIRE:
+               not_affected |= Fire_resistance;
+               goto common;
+           case AD_ELEC:
+               not_affected |= Shock_resistance;
+common:
+
+               if (!not_affected) {
+                   if (ACURR(A_DEX) > rnd(20)) {
+                       You("duck some of the blast.");
+                       tmp = (tmp+1) / 2;
+                   } else {
+                       if (flags.verbose) You("get blasted!");
+                   }
+                   if (mattk->adtyp == AD_FIRE) burn_away_slime();
+                   if (Half_physical_damage) tmp = (tmp+1) / 2;
+                   mdamageu(mtmp, tmp);
+               }
+               break;
+
+           case AD_BLND:
+               not_affected = resists_blnd(&youmonst);
+               if (!not_affected) {
+                   /* sometimes you're affected even if it's invisible */
+                   if (mon_visible(mtmp) || (rnd(tmp /= 2) > u.ulevel)) {
+                       You("are blinded by a blast of light!");
+                       make_blinded((long)tmp, FALSE);
+                       if (!Blind) Your(vision_clears);
+                   } else if (flags.verbose)
+                       You("get the impression it was not terribly bright.");
+               }
+               break;
+
+           case AD_HALU:
+               not_affected |= Blind ||
+                       (u.umonnum == PM_BLACK_LIGHT ||
+                        u.umonnum == PM_VIOLET_FUNGUS ||
+                        dmgtype(youmonst.data, AD_STUN));
+               if (!not_affected) {
+                   boolean chg;
+                   if (!Hallucination)
+                       You("are caught in a blast of kaleidoscopic light!");
+                   chg = make_hallucinated(HHallucination + (long)tmp,FALSE,0L);
+                   You("%s.", chg ? "are freaked out" : "seem unaffected");
+               }
+               break;
+
+           default:
+               break;
+       }
+       if (not_affected) {
+           You("seem unaffected by it.");
+           ugolemeffects((int)mattk->adtyp, tmp);
+       }
+    }
+    mondead(mtmp);
+    wake_nearto(mtmp->mx, mtmp->my, 7*7);
+    if (mtmp->mhp > 0) return(0);
+    return(2); /* it dies */
+}
+
+int
+gazemu(mtmp, mattk)    /* monster gazes at you */
+       register struct monst *mtmp;
+       register struct attack  *mattk;
+{
+       switch(mattk->adtyp) {
+           case AD_STON:
+               if (mtmp->mcan || !mtmp->mcansee) {
+                   if (!canseemon(mtmp)) break;        /* silently */
+                   pline("%s %s.", Monnam(mtmp),
+                         (mtmp->data == &mons[PM_MEDUSA] && mtmp->mcan) ?
+                               "doesn't look all that ugly" :
+                               "gazes ineffectually");
+                   break;
+               }
+               if (Reflecting && couldsee(mtmp->mx, mtmp->my) &&
+                       mtmp->data == &mons[PM_MEDUSA]) {
+                   /* hero has line of sight to Medusa and she's not blind */
+                   boolean useeit = canseemon(mtmp);
+
+                   if (useeit)
+                       (void) ureflects("%s gaze is reflected by your %s.",
+                                        s_suffix(Monnam(mtmp)));
+                   if (mon_reflects(mtmp, !useeit ? (char *)0 :
+                                    "The gaze is reflected away by %s %s!"))
+                       break;
+                   if (!m_canseeu(mtmp)) { /* probably you're invisible */
+                       if (useeit)
+                           pline(
+                     "%s doesn't seem to notice that %s gaze was reflected.",
+                                 Monnam(mtmp), mhis(mtmp));
+                       break;
+                   }
+                   if (useeit)
+                       pline("%s is turned to stone!", Monnam(mtmp));
+                   stoned = TRUE;
+                   killed(mtmp);
+
+                   if (mtmp->mhp > 0) break;
+                   return 2;
+               }
+               if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) &&
+                   !Stone_resistance) {
+                   You("meet %s gaze.", s_suffix(mon_nam(mtmp)));
+                   stop_occupation();
+                   if(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
+                       break;
+                   You("turn to stone...");
+                   killer_format = KILLED_BY;
+                   killer = mtmp->data->mname;
+                   done(STONING);
+               }
+               break;
+           case AD_CONF:
+               if(!mtmp->mcan && canseemon(mtmp) &&
+                  couldsee(mtmp->mx, mtmp->my) &&
+                  mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
+                   int conf = d(3,4);
+
+                   mtmp->mspec_used = mtmp->mspec_used + (conf + rn2(6));
+                   if(!Confusion)
+                       pline("%s gaze confuses you!",
+                                         s_suffix(Monnam(mtmp)));
+                   else
+                       You("are getting more and more confused.");
+                   make_confused(HConfusion + conf, FALSE);
+                   stop_occupation();
+               }
+               break;
+           case AD_STUN:
+               if(!mtmp->mcan && canseemon(mtmp) &&
+                  couldsee(mtmp->mx, mtmp->my) &&
+                  mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
+                   int stun = d(2,6);
+
+                   mtmp->mspec_used = mtmp->mspec_used + (stun + rn2(6));
+                   pline("%s stares piercingly at you!", Monnam(mtmp));
+                   make_stunned(HStun + stun, TRUE);
+                   stop_occupation();
+               }
+               break;
+           case AD_BLND:
+               if (!mtmp->mcan && canseemon(mtmp) && !resists_blnd(&youmonst)
+                       && distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) {
+                   int blnd = d((int)mattk->damn, (int)mattk->damd);
+
+                   You("are blinded by %s radiance!",
+                                     s_suffix(mon_nam(mtmp)));
+                   make_blinded((long)blnd,FALSE);
+                   stop_occupation();
+                   /* not blind at this point implies you're wearing
+                      the Eyes of the Overworld; make them block this
+                      particular stun attack too */
+                   if (!Blind) Your(vision_clears);
+                   else make_stunned((long)d(1,3),TRUE);
+               }
+               break;
+           case AD_FIRE:
+               if (!mtmp->mcan && canseemon(mtmp) &&
+                       couldsee(mtmp->mx, mtmp->my) &&
+                       mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
+                   int dmg = d(2,6);
+
+                   pline("%s attacks you with a fiery gaze!", Monnam(mtmp));
+                   stop_occupation();
+                   if (Fire_resistance) {
+                       pline_The("fire doesn't feel hot!");
+                       dmg = 0;
+                   }
+                   burn_away_slime();
+                   if ((int) mtmp->m_lev > rn2(20))
+                       destroy_item(SCROLL_CLASS, AD_FIRE);
+                   if ((int) mtmp->m_lev > rn2(20))
+                       destroy_item(POTION_CLASS, AD_FIRE);
+                   if ((int) mtmp->m_lev > rn2(25))
+                       destroy_item(SPBOOK_CLASS, AD_FIRE);
+                   if (dmg) mdamageu(mtmp, dmg);
+               }
+               break;
+#ifdef PM_BEHOLDER /* work in progress */
+           case AD_SLEE:
+               if(!mtmp->mcan && canseemon(mtmp) &&
+                  couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee &&
+                  multi >= 0 && !rn2(5) && !Sleep_resistance) {
+
+                   fall_asleep(-rnd(10), TRUE);
+                   pline("%s gaze makes you very sleepy...",
+                         s_suffix(Monnam(mtmp)));
+               }
+               break;
+           case AD_SLOW:
+               if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee &&
+                  (HFast & (INTRINSIC|TIMEOUT)) &&
+                  !defends(AD_SLOW, uwep) && !rn2(4))
+
+                   u_slow_down();
+                   stop_occupation();
+               break;
+#endif
+           default: impossible("Gaze attack %d?", mattk->adtyp);
+               break;
+       }
+       return(0);
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+void
+mdamageu(mtmp, n)      /* mtmp hits you for n points damage */
+register struct monst *mtmp;
+register int n;
+{
+       flags.botl = 1;
+       if (Upolyd) {
+               u.mh -= n;
+               if (u.mh < 1) rehumanize();
+       } else {
+               u.uhp -= n;
+               if(u.uhp < 1) done_in_by(mtmp);
+       }
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+STATIC_OVL void
+urustm(mon, obj)
+register struct monst *mon;
+register struct obj *obj;
+{
+       boolean vis;
+       boolean is_acid;
+
+       if (!mon || !obj) return; /* just in case */
+       if (dmgtype(youmonst.data, AD_CORR))
+           is_acid = TRUE;
+       else if (dmgtype(youmonst.data, AD_RUST))
+           is_acid = FALSE;
+       else
+           return;
+
+       vis = cansee(mon->mx, mon->my);
+
+       if ((is_acid ? is_corrodeable(obj) : is_rustprone(obj)) &&
+           (is_acid ? obj->oeroded2 : obj->oeroded) < MAX_ERODE) {
+               if (obj->greased || obj->oerodeproof || (obj->blessed && rn2(3))) {
+                   if (vis)
+                       pline("Somehow, %s weapon is not affected.",
+                                               s_suffix(mon_nam(mon)));
+                   if (obj->greased && !rn2(2)) obj->greased = 0;
+               } else {
+                   if (vis)
+                       pline("%s %s%s!",
+                               s_suffix(Monnam(mon)),
+                               aobjnam(obj, (is_acid ? "corrode" : "rust")),
+                               (is_acid ? obj->oeroded2 : obj->oeroded)
+                                   ? " further" : "");
+                   if (is_acid) obj->oeroded2++;
+                   else obj->oeroded++;
+               }
+       }
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+int
+could_seduce(magr,mdef,mattk)
+struct monst *magr, *mdef;
+struct attack *mattk;
+/* returns 0 if seduction impossible,
+ *        1 if fine,
+ *        2 if wrong gender for nymph */
+{
+       register struct permonst *pagr;
+       boolean agrinvis, defperc;
+       xchar genagr, gendef;
+
+       if (is_animal(magr->data)) return (0);
+       if(magr == &youmonst) {
+               pagr = youmonst.data;
+               agrinvis = (Invis != 0);
+               genagr = poly_gender();
+       } else {
+               pagr = magr->data;
+               agrinvis = magr->minvis;
+               genagr = gender(magr);
+       }
+       if(mdef == &youmonst) {
+               defperc = (See_invisible != 0);
+               gendef = poly_gender();
+       } else {
+               defperc = perceives(mdef->data);
+               gendef = gender(mdef);
+       }
+
+       if(agrinvis && !defperc
+#ifdef SEDUCE
+               && mattk && mattk->adtyp != AD_SSEX
+#endif
+               )
+               return 0;
+
+       if(pagr->mlet != S_NYMPH
+               && ((pagr != &mons[PM_INCUBUS] && pagr != &mons[PM_SUCCUBUS])
+#ifdef SEDUCE
+                   || (mattk && mattk->adtyp != AD_SSEX)
+#endif
+                  ))
+               return 0;
+       
+       if(genagr == 1 - gendef)
+               return 1;
+       else
+               return (pagr->mlet == S_NYMPH) ? 2 : 0;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+#ifdef SEDUCE
+/* Returns 1 if monster teleported */
+int
+doseduce(mon)
+register struct monst *mon;
+{
+       register struct obj *ring, *nring;
+       boolean fem = (mon->data == &mons[PM_SUCCUBUS]); /* otherwise incubus */
+       char qbuf[QBUFSZ];
+
+       if (mon->mcan || mon->mspec_used) {
+               pline("%s acts as though %s has got a %sheadache.",
+                     Monnam(mon), mhe(mon),
+                     mon->mcan ? "severe " : "");
+               return 0;
+       }
+
+       if (unconscious()) {
+               pline("%s seems dismayed at your lack of response.",
+                     Monnam(mon));
+               return 0;
+       }
+
+       if (Blind) pline("It caresses you...");
+       else You_feel("very attracted to %s.", mon_nam(mon));
+
+       for(ring = invent; ring; ring = nring) {
+           nring = ring->nobj;
+           if (ring->otyp != RIN_ADORNMENT) continue;
+           if (fem) {
+               if (rn2(20) < ACURR(A_CHA)) {
+                   Sprintf(qbuf, "\"That %s looks pretty.  May I have it?\"",
+                       safe_qbuf("",sizeof("\"That  looks pretty.  May I have it?\""),
+                       xname(ring), simple_typename(ring->otyp), "ring"));
+                   makeknown(RIN_ADORNMENT);
+                   if (yn(qbuf) == 'n') continue;
+               } else pline("%s decides she'd like your %s, and takes it.",
+                       Blind ? "She" : Monnam(mon), xname(ring));
+               makeknown(RIN_ADORNMENT);
+               if (ring==uleft || ring==uright) Ring_gone(ring);
+               if (ring==uwep) setuwep((struct obj *)0);
+               if (ring==uswapwep) setuswapwep((struct obj *)0);
+               if (ring==uquiver) setuqwep((struct obj *)0);
+               freeinv(ring);
+               (void) mpickobj(mon,ring);
+           } else {
+               char buf[BUFSZ];
+
+               if (uleft && uright && uleft->otyp == RIN_ADORNMENT
+                               && uright->otyp==RIN_ADORNMENT)
+                       break;
+               if (ring==uleft || ring==uright) continue;
+               if (rn2(20) < ACURR(A_CHA)) {
+                   Sprintf(qbuf,"\"That %s looks pretty.  Would you wear it for me?\"",
+                       safe_qbuf("",
+                           sizeof("\"That  looks pretty.  Would you wear it for me?\""),
+                           xname(ring), simple_typename(ring->otyp), "ring"));
+                   makeknown(RIN_ADORNMENT);
+                   if (yn(qbuf) == 'n') continue;
+               } else {
+                   pline("%s decides you'd look prettier wearing your %s,",
+                       Blind ? "He" : Monnam(mon), xname(ring));
+                   pline("and puts it on your finger.");
+               }
+               makeknown(RIN_ADORNMENT);
+               if (!uright) {
+                   pline("%s puts %s on your right %s.",
+                       Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND));
+                   setworn(ring, RIGHT_RING);
+               } else if (!uleft) {
+                   pline("%s puts %s on your left %s.",
+                       Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND));
+                   setworn(ring, LEFT_RING);
+               } else if (uright && uright->otyp != RIN_ADORNMENT) {
+                   Strcpy(buf, xname(uright));
+                   pline("%s replaces your %s with your %s.",
+                       Blind ? "He" : Monnam(mon), buf, xname(ring));
+                   Ring_gone(uright);
+                   setworn(ring, RIGHT_RING);
+               } else if (uleft && uleft->otyp != RIN_ADORNMENT) {
+                   Strcpy(buf, xname(uleft));
+                   pline("%s replaces your %s with your %s.",
+                       Blind ? "He" : Monnam(mon), buf, xname(ring));
+                   Ring_gone(uleft);
+                   setworn(ring, LEFT_RING);
+               } else impossible("ring replacement");
+               Ring_on(ring);
+               prinv((char *)0, ring, 0L);
+           }
+       }
+
+       if (!uarmc && !uarmf && !uarmg && !uarms && !uarmh
+#ifdef TOURIST
+                                                               && !uarmu
+#endif
+                                                                       )
+               pline("%s murmurs sweet nothings into your ear.",
+                       Blind ? (fem ? "She" : "He") : Monnam(mon));
+       else
+               pline("%s murmurs in your ear, while helping you undress.",
+                       Blind ? (fem ? "She" : "He") : Monnam(mon));
+       mayberem(uarmc, cloak_simple_name(uarmc));
+       if(!uarmc)
+               mayberem(uarm, "suit");
+       mayberem(uarmf, "boots");
+       if(!uwep || !welded(uwep))
+               mayberem(uarmg, "gloves");
+       mayberem(uarms, "shield");
+       mayberem(uarmh, "helmet");
+#ifdef TOURIST
+       if(!uarmc && !uarm)
+               mayberem(uarmu, "shirt");
+#endif
+
+       if (uarm || uarmc) {
+               verbalize("You're such a %s; I wish...",
+                               flags.female ? "sweet lady" : "nice guy");
+               if (!tele_restrict(mon)) (void) rloc(mon, FALSE);
+               return 1;
+       }
+       if (u.ualign.type == A_CHAOTIC)
+               adjalign(1);
+
+       /* by this point you have discovered mon's identity, blind or not... */
+       pline("Time stands still while you and %s lie in each other's arms...",
+               noit_mon_nam(mon));
+       if (rn2(35) > ACURR(A_CHA) + ACURR(A_INT)) {
+               /* Don't bother with mspec_used here... it didn't get tired! */
+               pline("%s seems to have enjoyed it more than you...",
+                       noit_Monnam(mon));
+               switch (rn2(5)) {
+                       case 0: You_feel("drained of energy.");
+                               u.uen = 0;
+                               u.uenmax -= rnd(Half_physical_damage ? 5 : 10);
+                               exercise(A_CON, FALSE);
+                               if (u.uenmax < 0) u.uenmax = 0;
+                               break;
+                       case 1: You("are down in the dumps.");
+                               (void) adjattrib(A_CON, -1, TRUE);
+                               exercise(A_CON, FALSE);
+                               flags.botl = 1;
+                               break;
+                       case 2: Your("senses are dulled.");
+                               (void) adjattrib(A_WIS, -1, TRUE);
+                               exercise(A_WIS, FALSE);
+                               flags.botl = 1;
+                               break;
+                       case 3:
+                               if (!resists_drli(&youmonst)) {
+                                   You_feel("out of shape.");
+                                   losexp("overexertion");
+                               } else {
+                                   You("have a curious feeling...");
+                               }
+                               break;
+                       case 4: {
+                               int tmp;
+                               You_feel("exhausted.");
+                               exercise(A_STR, FALSE);
+                               tmp = rn1(10, 6);
+                               if(Half_physical_damage) tmp = (tmp+1) / 2;
+                               losehp(tmp, "exhaustion", KILLED_BY);
+                               break;
+                       }
+               }
+       } else {
+               mon->mspec_used = rnd(100); /* monster is worn out */
+               You("seem to have enjoyed it more than %s...",
+                   noit_mon_nam(mon));
+               switch (rn2(5)) {
+               case 0: You_feel("raised to your full potential.");
+                       exercise(A_CON, TRUE);
+                       u.uen = (u.uenmax += rnd(5));
+                       break;
+               case 1: You_feel("good enough to do it again.");
+                       (void) adjattrib(A_CON, 1, TRUE);
+                       exercise(A_CON, TRUE);
+                       flags.botl = 1;
+                       break;
+               case 2: You("will always remember %s...", noit_mon_nam(mon));
+                       (void) adjattrib(A_WIS, 1, TRUE);
+                       exercise(A_WIS, TRUE);
+                       flags.botl = 1;
+                       break;
+               case 3: pline("That was a very educational experience.");
+                       pluslvl(FALSE);
+                       exercise(A_WIS, TRUE);
+                       break;
+               case 4: You_feel("restored to health!");
+                       u.uhp = u.uhpmax;
+                       if (Upolyd) u.mh = u.mhmax;
+                       exercise(A_STR, TRUE);
+                       flags.botl = 1;
+                       break;
+               }
+       }
+
+       if (mon->mtame) /* don't charge */ ;
+       else if (rn2(20) < ACURR(A_CHA)) {
+               pline("%s demands that you pay %s, but you refuse...",
+                       noit_Monnam(mon),
+                       Blind ? (fem ? "her" : "him") : mhim(mon));
+       } else if (u.umonnum == PM_LEPRECHAUN)
+               pline("%s tries to take your money, but fails...",
+                               noit_Monnam(mon));
+       else {
+#ifndef GOLDOBJ
+               long cost;
+
+               if (u.ugold > (long)LARGEST_INT - 10L)
+                       cost = (long) rnd(LARGEST_INT) + 500L;
+               else
+                       cost = (long) rnd((int)u.ugold + 10) + 500L;
+               if (mon->mpeaceful) {
+                       cost /= 5L;
+                       if (!cost) cost = 1L;
+               }
+               if (cost > u.ugold) cost = u.ugold;
+               if (!cost) verbalize("It's on the house!");
+               else {
+                   pline("%s takes %ld %s for services rendered!",
+                           noit_Monnam(mon), cost, currency(cost));
+                   u.ugold -= cost;
+                   mon->mgold += cost;
+                   flags.botl = 1;
+               }
+#else
+               long cost;
+                long umoney = money_cnt(invent);
+
+               if (umoney > (long)LARGEST_INT - 10L)
+                       cost = (long) rnd(LARGEST_INT) + 500L;
+               else
+                       cost = (long) rnd((int)umoney + 10) + 500L;
+               if (mon->mpeaceful) {
+                       cost /= 5L;
+                       if (!cost) cost = 1L;
+               }
+               if (cost > umoney) cost = umoney;
+               if (!cost) verbalize("It's on the house!");
+               else { 
+                   pline("%s takes %ld %s for services rendered!",
+                           noit_Monnam(mon), cost, currency(cost));
+                    money2mon(mon, cost);
+                   flags.botl = 1;
+               }
+#endif
+       }
+       if (!rn2(25)) mon->mcan = 1; /* monster is worn out */
+       if (!tele_restrict(mon)) (void) rloc(mon, FALSE);
+       return 1;
+}
+
+STATIC_OVL void
+mayberem(obj, str)
+register struct obj *obj;
+const char *str;
+{
+       char qbuf[QBUFSZ];
+
+       if (!obj || !obj->owornmask) return;
+
+       if (rn2(20) < ACURR(A_CHA)) {
+               Sprintf(qbuf,"\"Shall I remove your %s, %s?\"",
+                       str,
+                       (!rn2(2) ? "lover" : !rn2(2) ? "dear" : "sweetheart"));
+               if (yn(qbuf) == 'n') return;
+       } else {
+               char hairbuf[BUFSZ];
+
+               Sprintf(hairbuf, "let me run my fingers through your %s",
+                       body_part(HAIR));
+               verbalize("Take off your %s; %s.", str,
+                       (obj == uarm)  ? "let's get a little closer" :
+                       (obj == uarmc || obj == uarms) ? "it's in the way" :
+                       (obj == uarmf) ? "let me rub your feet" :
+                       (obj == uarmg) ? "they're too clumsy" :
+#ifdef TOURIST
+                       (obj == uarmu) ? "let me massage you" :
+#endif
+                       /* obj == uarmh */
+                       hairbuf);
+       }
+       remove_worn_item(obj, TRUE);
+}
+#endif  /* SEDUCE */
+
+#endif /* OVLB */
+
+#ifdef OVL1
+
+STATIC_OVL int
+passiveum(olduasmon,mtmp,mattk)
+struct permonst *olduasmon;
+register struct monst *mtmp;
+register struct attack *mattk;
+{
+       int i, tmp;
+
+       for (i = 0; ; i++) {
+           if (i >= NATTK) return 1;
+           if (olduasmon->mattk[i].aatyp == AT_NONE ||
+                       olduasmon->mattk[i].aatyp == AT_BOOM) break;
+       }
+       if (olduasmon->mattk[i].damn)
+           tmp = d((int)olduasmon->mattk[i].damn,
+                                   (int)olduasmon->mattk[i].damd);
+       else if(olduasmon->mattk[i].damd)
+           tmp = d((int)olduasmon->mlevel+1, (int)olduasmon->mattk[i].damd);
+       else
+           tmp = 0;
+
+       /* These affect the enemy even if you were "killed" (rehumanized) */
+       switch(olduasmon->mattk[i].adtyp) {
+           case AD_ACID:
+               if (!rn2(2)) {
+                   pline("%s is splashed by your acid!", Monnam(mtmp));
+                   if (resists_acid(mtmp)) {
+                       pline("%s is not affected.", Monnam(mtmp));
+                       tmp = 0;
+                   }
+               } else tmp = 0;
+               if (!rn2(30)) erode_armor(mtmp, TRUE);
+               if (!rn2(6)) erode_obj(MON_WEP(mtmp), TRUE, TRUE);
+               goto assess_dmg;
+           case AD_STON: /* cockatrice */
+           {
+               long protector = attk_protection((int)mattk->aatyp),
+                    wornitems = mtmp->misc_worn_check;
+
+               /* wielded weapon gives same protection as gloves here */
+               if (MON_WEP(mtmp) != 0) wornitems |= W_ARMG;
+
+               if (!resists_ston(mtmp) && (protector == 0L ||
+                       (protector != ~0L &&
+                           (wornitems & protector) != protector))) {
+                   if (poly_when_stoned(mtmp->data)) {
+                       mon_to_stone(mtmp);
+                       return (1);
+                   }
+                   pline("%s turns to stone!", Monnam(mtmp));
+                   stoned = 1;
+                   xkilled(mtmp, 0);
+                   if (mtmp->mhp > 0) return 1;
+                   return 2;
+               }
+               return 1;
+           }
+           case AD_ENCH:       /* KMH -- remove enchantment (disenchanter) */
+               if (otmp) {
+                   (void) drain_item(otmp);
+                   /* No message */
+               }
+               return (1);
+           default:
+               break;
+       }
+       if (!Upolyd) return 1;
+
+       /* These affect the enemy only if you are still a monster */
+       if (rn2(3)) switch(youmonst.data->mattk[i].adtyp) {
+           case AD_PHYS:
+               if (youmonst.data->mattk[i].aatyp == AT_BOOM) {
+                   You("explode!");
+                   /* KMH, balance patch -- this is okay with unchanging */
+                   rehumanize();
+                   goto assess_dmg;
+               }
+               break;
+           case AD_PLYS: /* Floating eye */
+               if (tmp > 127) tmp = 127;
+               if (u.umonnum == PM_FLOATING_EYE) {
+                   if (!rn2(4)) tmp = 127;
+                   if (mtmp->mcansee && haseyes(mtmp->data) && rn2(3) &&
+                               (perceives(mtmp->data) || !Invis)) {
+                       if (Blind)
+                           pline("As a blind %s, you cannot defend yourself.",
+                                                       youmonst.data->mname);
+                       else {
+                           if (mon_reflects(mtmp,
+                                           "Your gaze is reflected by %s %s."))
+                               return 1;
+                           pline("%s is frozen by your gaze!", Monnam(mtmp));
+                           mtmp->mcanmove = 0;
+                           mtmp->mfrozen = tmp;
+                           return 3;
+                       }
+                   }
+               } else { /* gelatinous cube */
+                   pline("%s is frozen by you.", Monnam(mtmp));
+                   mtmp->mcanmove = 0;
+                   mtmp->mfrozen = tmp;
+                   return 3;
+               }
+               return 1;
+           case AD_COLD: /* Brown mold or blue jelly */
+               if (resists_cold(mtmp)) {
+                   shieldeff(mtmp->mx, mtmp->my);
+                   pline("%s is mildly chilly.", Monnam(mtmp));
+                   golemeffects(mtmp, AD_COLD, tmp);
+                   tmp = 0;
+                   break;
+               }
+               pline("%s is suddenly very cold!", Monnam(mtmp));
+               u.mh += tmp / 2;
+               if (u.mhmax < u.mh) u.mhmax = u.mh;
+               if (u.mhmax > ((youmonst.data->mlevel+1) * 8))
+                   (void)split_mon(&youmonst, mtmp);
+               break;
+           case AD_STUN: /* Yellow mold */
+               if (!mtmp->mstun) {
+                   mtmp->mstun = 1;
+                   pline("%s %s.", Monnam(mtmp),
+                         makeplural(stagger(mtmp->data, "stagger")));
+               }
+               tmp = 0;
+               break;
+           case AD_FIRE: /* Red mold */
+               if (resists_fire(mtmp)) {
+                   shieldeff(mtmp->mx, mtmp->my);
+                   pline("%s is mildly warm.", Monnam(mtmp));
+                   golemeffects(mtmp, AD_FIRE, tmp);
+                   tmp = 0;
+                   break;
+               }
+               pline("%s is suddenly very hot!", Monnam(mtmp));
+               break;
+           case AD_ELEC:
+               if (resists_elec(mtmp)) {
+                   shieldeff(mtmp->mx, mtmp->my);
+                   pline("%s is slightly tingled.", Monnam(mtmp));
+                   golemeffects(mtmp, AD_ELEC, tmp);
+                   tmp = 0;
+                   break;
+               }
+               pline("%s is jolted with your electricity!", Monnam(mtmp));
+               break;
+           default: tmp = 0;
+               break;
+       }
+       else tmp = 0;
+
+    assess_dmg:
+       if((mtmp->mhp -= tmp) <= 0) {
+               pline("%s dies!", Monnam(mtmp));
+               xkilled(mtmp,0);
+               if (mtmp->mhp > 0) return 1;
+               return 2;
+       }
+       return 1;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+#include "edog.h"
+struct monst *
+cloneu()
+{
+       register struct monst *mon;
+       int mndx = monsndx(youmonst.data);
+
+       if (u.mh <= 1) return(struct monst *)0;
+       if (mvitals[mndx].mvflags & G_EXTINCT) return(struct monst *)0;
+       mon = makemon(youmonst.data, u.ux, u.uy, NO_MINVENT|MM_EDOG);
+       mon = christen_monst(mon, plname);
+       initedog(mon);
+       mon->m_lev = youmonst.data->mlevel;
+       mon->mhpmax = u.mhmax;
+       mon->mhp = u.mh / 2;
+       u.mh -= mon->mhp;
+       flags.botl = 1;
+       return(mon);
+}
+
+#endif /* OVLB */
+
+/*mhitu.c*/
diff --git a/src/minion.c b/src/minion.c
new file mode 100644 (file)
index 0000000..af47256
--- /dev/null
@@ -0,0 +1,322 @@
+/*     SCCS Id: @(#)minion.c   3.4     2003/01/09      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "emin.h"
+#include "epri.h"
+
+void
+msummon(mon)           /* mon summons a monster */
+struct monst *mon;
+{
+       register struct permonst *ptr;
+       register int dtype = NON_PM, cnt = 0;
+       aligntyp atyp;
+       struct monst *mtmp;
+
+       if (mon) {
+           ptr = mon->data;
+           atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp);
+           if (mon->ispriest || mon->data == &mons[PM_ALIGNED_PRIEST]
+               || mon->data == &mons[PM_ANGEL])
+               atyp = EPRI(mon)->shralign;
+       } else {
+           ptr = &mons[PM_WIZARD_OF_YENDOR];
+           atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp);
+       }
+           
+       if (is_dprince(ptr) || (ptr == &mons[PM_WIZARD_OF_YENDOR])) {
+           dtype = (!rn2(20)) ? dprince(atyp) :
+                                (!rn2(4)) ? dlord(atyp) : ndemon(atyp);
+           cnt = (!rn2(4) && is_ndemon(&mons[dtype])) ? 2 : 1;
+       } else if (is_dlord(ptr)) {
+           dtype = (!rn2(50)) ? dprince(atyp) :
+                                (!rn2(20)) ? dlord(atyp) : ndemon(atyp);
+           cnt = (!rn2(4) && is_ndemon(&mons[dtype])) ? 2 : 1;
+       } else if (is_ndemon(ptr)) {
+           dtype = (!rn2(20)) ? dlord(atyp) :
+                                (!rn2(6)) ? ndemon(atyp) : monsndx(ptr);
+           cnt = 1;
+       } else if (is_lminion(mon)) {
+           dtype = (is_lord(ptr) && !rn2(20)) ? llord() :
+                    (is_lord(ptr) || !rn2(6)) ? lminion() : monsndx(ptr);
+           cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1;
+       } else if (ptr == &mons[PM_ANGEL]) {
+           /* non-lawful angels can also summon */
+           if (!rn2(6)) {
+               switch (atyp) { /* see summon_minion */
+               case A_NEUTRAL:
+                   dtype = PM_AIR_ELEMENTAL + rn2(4);
+                   break;
+               case A_CHAOTIC:
+               case A_NONE:
+                   dtype = ndemon(atyp);
+                   break;
+               }
+           } else {
+               dtype = PM_ANGEL;
+           }
+           cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1;
+       }
+
+       if (dtype == NON_PM) return;
+
+       /* sanity checks */
+       if (cnt > 1 && (mons[dtype].geno & G_UNIQ)) cnt = 1;
+       /*
+        * If this daemon is unique and being re-summoned (the only way we
+        * could get this far with an extinct dtype), try another.
+        */
+       if (mvitals[dtype].mvflags & G_GONE) {
+           dtype = ndemon(atyp);
+           if (dtype == NON_PM) return;
+       }
+
+       while (cnt > 0) {
+           mtmp = makemon(&mons[dtype], u.ux, u.uy, NO_MM_FLAGS);
+           if (mtmp && (dtype == PM_ANGEL)) {
+               /* alignment should match the summoner */
+               EPRI(mtmp)->shralign = atyp;
+           }
+           cnt--;
+       }
+}
+
+void
+summon_minion(alignment, talk)
+aligntyp alignment;
+boolean talk;
+{
+    register struct monst *mon;
+    int mnum;
+
+    switch ((int)alignment) {
+       case A_LAWFUL:
+           mnum = lminion();
+           break;
+       case A_NEUTRAL:
+           mnum = PM_AIR_ELEMENTAL + rn2(4);
+           break;
+       case A_CHAOTIC:
+       case A_NONE:
+           mnum = ndemon(alignment);
+           break;
+       default:
+           impossible("unaligned player?");
+           mnum = ndemon(A_NONE);
+           break;
+    }
+    if (mnum == NON_PM) {
+       mon = 0;
+    } else if (mons[mnum].pxlth == 0) {
+       struct permonst *pm = &mons[mnum];
+       mon = makemon(pm, u.ux, u.uy, MM_EMIN);
+       if (mon) {
+           mon->isminion = TRUE;
+           EMIN(mon)->min_align = alignment;
+       }
+    } else if (mnum == PM_ANGEL) {
+       mon = makemon(&mons[mnum], u.ux, u.uy, NO_MM_FLAGS);
+       if (mon) {
+           mon->isminion = TRUE;
+           EPRI(mon)->shralign = alignment;    /* always A_LAWFUL here */
+       }
+    } else
+       mon = makemon(&mons[mnum], u.ux, u.uy, NO_MM_FLAGS);
+    if (mon) {
+       if (talk) {
+           pline_The("voice of %s booms:", align_gname(alignment));
+           verbalize("Thou shalt pay for thy indiscretion!");
+           if (!Blind)
+               pline("%s appears before you.", Amonnam(mon));
+       }
+       mon->mpeaceful = FALSE;
+       /* don't call set_malign(); player was naughty */
+    }
+}
+
+#define Athome (Inhell && !mtmp->cham)
+
+int
+demon_talk(mtmp)               /* returns 1 if it won't attack. */
+register struct monst *mtmp;
+{
+       long cash, demand, offer;
+
+       if (uwep && uwep->oartifact == ART_EXCALIBUR) {
+           pline("%s looks very angry.", Amonnam(mtmp));
+           mtmp->mpeaceful = mtmp->mtame = 0;
+           set_malign(mtmp);
+           newsym(mtmp->mx, mtmp->my);
+           return 0;
+       }
+
+       /* Slight advantage given. */
+       if (is_dprince(mtmp->data) && mtmp->minvis) {
+           mtmp->minvis = mtmp->perminvis = 0;
+           if (!Blind) pline("%s appears before you.", Amonnam(mtmp));
+           newsym(mtmp->mx,mtmp->my);
+       }
+       if (youmonst.data->mlet == S_DEMON) {   /* Won't blackmail their own. */
+           pline("%s says, \"Good hunting, %s.\"",
+                 Amonnam(mtmp), flags.female ? "Sister" : "Brother");
+           if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
+           return(1);
+       }
+#ifndef GOLDOBJ
+       cash = u.ugold;
+#else
+       cash = money_cnt(invent);
+#endif
+       demand = (cash * (rnd(80) + 20 * Athome)) /
+           (100 * (1 + (sgn(u.ualign.type) == sgn(mtmp->data->maligntyp))));
+
+       if (!demand) {          /* you have no gold */
+           mtmp->mpeaceful = 0;
+           set_malign(mtmp);
+           return 0;
+       } else {
+           /* make sure that the demand is unmeetable if the monster
+              has the Amulet, preventing monster from being satisified
+              and removed from the game (along with said Amulet...) */
+           if (mon_has_amulet(mtmp))
+               demand = cash + (long)rn1(1000,40);
+
+           pline("%s demands %ld %s for safe passage.",
+                 Amonnam(mtmp), demand, currency(demand));
+
+           if ((offer = bribe(mtmp)) >= demand) {
+               pline("%s vanishes, laughing about cowardly mortals.",
+                     Amonnam(mtmp));
+           } else if (offer > 0L && (long)rnd(40) > (demand - offer)) {
+               pline("%s scowls at you menacingly, then vanishes.",
+                     Amonnam(mtmp));
+           } else {
+               pline("%s gets angry...", Amonnam(mtmp));
+               mtmp->mpeaceful = 0;
+               set_malign(mtmp);
+               return 0;
+           }
+       }
+       mongone(mtmp);
+       return(1);
+}
+
+long
+bribe(mtmp)
+struct monst *mtmp;
+{
+       char buf[BUFSZ];
+       long offer;
+#ifdef GOLDOBJ
+       long umoney = money_cnt(invent);
+#endif
+
+       getlin("How much will you offer?", buf);
+       if (sscanf(buf, "%ld", &offer) != 1) offer = 0L;
+
+       /*Michael Paddon -- fix for negative offer to monster*/
+       /*JAR880815 - */
+       if (offer < 0L) {
+               You("try to shortchange %s, but fumble.",
+                       mon_nam(mtmp));
+               return 0L;
+       } else if (offer == 0L) {
+               You("refuse.");
+               return 0L;
+#ifndef GOLDOBJ
+       } else if (offer >= u.ugold) {
+               You("give %s all your gold.", mon_nam(mtmp));
+               offer = u.ugold;
+       } else {
+               You("give %s %ld %s.", mon_nam(mtmp), offer, currency(offer));
+       }
+       u.ugold -= offer;
+       mtmp->mgold += offer;
+#else
+       } else if (offer >= umoney) {
+               You("give %s all your gold.", mon_nam(mtmp));
+               offer = umoney;
+       } else {
+               You("give %s %ld %s.", mon_nam(mtmp), offer, currency(offer));
+       }
+       (void) money2mon(mtmp, offer);
+#endif
+       flags.botl = 1;
+       return(offer);
+}
+
+int
+dprince(atyp)
+aligntyp atyp;
+{
+       int tryct, pm;
+
+       for (tryct = 0; tryct < 20; tryct++) {
+           pm = rn1(PM_DEMOGORGON + 1 - PM_ORCUS, PM_ORCUS);
+           if (!(mvitals[pm].mvflags & G_GONE) &&
+                   (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp)))
+               return(pm);
+       }
+       return(dlord(atyp));    /* approximate */
+}
+
+int
+dlord(atyp)
+aligntyp atyp;
+{
+       int tryct, pm;
+
+       for (tryct = 0; tryct < 20; tryct++) {
+           pm = rn1(PM_YEENOGHU + 1 - PM_JUIBLEX, PM_JUIBLEX);
+           if (!(mvitals[pm].mvflags & G_GONE) &&
+                   (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp)))
+               return(pm);
+       }
+       return(ndemon(atyp));   /* approximate */
+}
+
+/* create lawful (good) lord */
+int
+llord()
+{
+       if (!(mvitals[PM_ARCHON].mvflags & G_GONE))
+               return(PM_ARCHON);
+
+       return(lminion());      /* approximate */
+}
+
+int
+lminion()
+{
+       int     tryct;
+       struct  permonst *ptr;
+
+       for (tryct = 0; tryct < 20; tryct++) {
+           ptr = mkclass(S_ANGEL,0);
+           if (ptr && !is_lord(ptr))
+               return(monsndx(ptr));
+       }
+
+       return NON_PM;
+}
+
+int
+ndemon(atyp)
+aligntyp atyp;
+{
+       int     tryct;
+       struct  permonst *ptr;
+
+       for (tryct = 0; tryct < 20; tryct++) {
+           ptr = mkclass(S_DEMON, 0);
+           if (ptr && is_ndemon(ptr) &&
+                   (atyp == A_NONE || sgn(ptr->maligntyp) == sgn(atyp)))
+               return(monsndx(ptr));
+       }
+
+       return NON_PM;
+}
+
+/*minion.c*/
diff --git a/src/mklev.c b/src/mklev.c
new file mode 100644 (file)
index 0000000..c1fb7cc
--- /dev/null
@@ -0,0 +1,1592 @@
+/*     SCCS Id: @(#)mklev.c    3.4     2001/11/29      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+/* #define DEBUG */    /* uncomment to enable code debugging */
+
+#ifdef DEBUG
+# ifdef WIZARD
+#define debugpline     if (wizard) pline
+# else
+#define debugpline     pline
+# endif
+#endif
+
+/* for UNIX, Rand #def'd to (long)lrand48() or (long)random() */
+/* croom->lx etc are schar (width <= int), so % arith ensures that */
+/* conversion of result to int is reasonable */
+
+
+STATIC_DCL void FDECL(mkfount,(int,struct mkroom *));
+#ifdef SINKS
+STATIC_DCL void FDECL(mksink,(struct mkroom *));
+#endif
+STATIC_DCL void FDECL(mkaltar,(struct mkroom *));
+STATIC_DCL void FDECL(mkgrave,(struct mkroom *));
+STATIC_DCL void NDECL(makevtele);
+STATIC_DCL void NDECL(clear_level_structures);
+STATIC_DCL void NDECL(makelevel);
+STATIC_DCL void NDECL(mineralize);
+STATIC_DCL boolean FDECL(bydoor,(XCHAR_P,XCHAR_P));
+STATIC_DCL struct mkroom *FDECL(find_branch_room, (coord *));
+STATIC_DCL struct mkroom *FDECL(pos_to_room, (XCHAR_P, XCHAR_P));
+STATIC_DCL boolean FDECL(place_niche,(struct mkroom *,int*,int*,int*));
+STATIC_DCL void FDECL(makeniche,(int));
+STATIC_DCL void NDECL(make_niches);
+
+STATIC_PTR int FDECL( CFDECLSPEC do_comp,(const genericptr,const genericptr));
+
+STATIC_DCL void FDECL(dosdoor,(XCHAR_P,XCHAR_P,struct mkroom *,int));
+STATIC_DCL void FDECL(join,(int,int,BOOLEAN_P));
+STATIC_DCL void FDECL(do_room_or_subroom, (struct mkroom *,int,int,int,int,
+                                      BOOLEAN_P,SCHAR_P,BOOLEAN_P,BOOLEAN_P));
+STATIC_DCL void NDECL(makerooms);
+STATIC_DCL void FDECL(finddpos,(coord *,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
+STATIC_DCL void FDECL(mkinvpos, (XCHAR_P,XCHAR_P,int));
+STATIC_DCL void FDECL(mk_knox_portal, (XCHAR_P,XCHAR_P));
+
+#define create_vault() create_room(-1, -1, 2, 2, -1, -1, VAULT, TRUE)
+#define init_vault()   vault_x = -1
+#define do_vault()     (vault_x != -1)
+static xchar           vault_x, vault_y;
+boolean goldseen;
+static boolean made_branch;    /* used only during level creation */
+
+/* Args must be (const genericptr) so that qsort will always be happy. */
+
+STATIC_PTR int CFDECLSPEC
+do_comp(vx,vy)
+const genericptr vx;
+const genericptr vy;
+{
+#ifdef LINT
+/* lint complains about possible pointer alignment problems, but we know
+   that vx and vy are always properly aligned. Hence, the following
+   bogus definition:
+*/
+       return (vx == vy) ? 0 : -1;
+#else
+       register const struct mkroom *x, *y;
+
+       x = (const struct mkroom *)vx;
+       y = (const struct mkroom *)vy;
+       if(x->lx < y->lx) return(-1);
+       return(x->lx > y->lx);
+#endif /* LINT */
+}
+
+STATIC_OVL void
+finddpos(cc, xl,yl,xh,yh)
+coord *cc;
+xchar xl,yl,xh,yh;
+{
+       register xchar x, y;
+
+       x = (xl == xh) ? xl : (xl + rn2(xh-xl+1));
+       y = (yl == yh) ? yl : (yl + rn2(yh-yl+1));
+       if(okdoor(x, y))
+               goto gotit;
+
+       for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
+               if(okdoor(x, y))
+                       goto gotit;
+
+       for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
+               if(IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR)
+                       goto gotit;
+       /* cannot find something reasonable -- strange */
+       x = xl;
+       y = yh;
+gotit:
+       cc->x = x;
+       cc->y = y;
+       return;
+}
+
+void
+sort_rooms()
+{
+#if defined(SYSV) || defined(DGUX)
+       qsort((genericptr_t) rooms, (unsigned)nroom, sizeof(struct mkroom), do_comp);
+#else
+       qsort((genericptr_t) rooms, nroom, sizeof(struct mkroom), do_comp);
+#endif
+}
+
+STATIC_OVL void
+do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, is_room)
+    register struct mkroom *croom;
+    int lowx, lowy;
+    register int hix, hiy;
+    boolean lit;
+    schar rtype;
+    boolean special;
+    boolean is_room;
+{
+       register int x, y;
+       struct rm *lev;
+
+       /* locations might bump level edges in wall-less rooms */
+       /* add/subtract 1 to allow for edge locations */
+       if(!lowx) lowx++;
+       if(!lowy) lowy++;
+       if(hix >= COLNO-1) hix = COLNO-2;
+       if(hiy >= ROWNO-1) hiy = ROWNO-2;
+
+       if(lit) {
+               for(x = lowx-1; x <= hix+1; x++) {
+                       lev = &levl[x][max(lowy-1,0)];
+                       for(y = lowy-1; y <= hiy+1; y++)
+                               lev++->lit = 1;
+               }
+               croom->rlit = 1;
+       } else
+               croom->rlit = 0;
+
+       croom->lx = lowx;
+       croom->hx = hix;
+       croom->ly = lowy;
+       croom->hy = hiy;
+       croom->rtype = rtype;
+       croom->doorct = 0;
+       /* if we're not making a vault, doorindex will still be 0
+        * if we are, we'll have problems adding niches to the previous room
+        * unless fdoor is at least doorindex
+        */
+       croom->fdoor = doorindex;
+       croom->irregular = FALSE;
+
+       croom->nsubrooms = 0;
+       croom->sbrooms[0] = (struct mkroom *) 0;
+       if (!special) {
+           for(x = lowx-1; x <= hix+1; x++)
+               for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
+                   levl[x][y].typ = HWALL;
+                   levl[x][y].horizontal = 1;  /* For open/secret doors. */
+               }
+           for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
+               for(y = lowy; y <= hiy; y++) {
+                   levl[x][y].typ = VWALL;
+                   levl[x][y].horizontal = 0;  /* For open/secret doors. */
+               }
+           for(x = lowx; x <= hix; x++) {
+               lev = &levl[x][lowy];
+               for(y = lowy; y <= hiy; y++)
+                   lev++->typ = ROOM;
+           }
+           if (is_room) {
+               levl[lowx-1][lowy-1].typ = TLCORNER;
+               levl[hix+1][lowy-1].typ = TRCORNER;
+               levl[lowx-1][hiy+1].typ = BLCORNER;
+               levl[hix+1][hiy+1].typ = BRCORNER;
+           } else {    /* a subroom */
+               wallification(lowx-1, lowy-1, hix+1, hiy+1);
+           }
+       }
+}
+
+
+void
+add_room(lowx, lowy, hix, hiy, lit, rtype, special)
+register int lowx, lowy, hix, hiy;
+boolean lit;
+schar rtype;
+boolean special;
+{
+       register struct mkroom *croom;
+
+       croom = &rooms[nroom];
+       do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
+                                           rtype, special, (boolean) TRUE);
+       croom++;
+       croom->hx = -1;
+       nroom++;
+}
+
+void
+add_subroom(proom, lowx, lowy, hix, hiy, lit, rtype, special)
+struct mkroom *proom;
+register int lowx, lowy, hix, hiy;
+boolean lit;
+schar rtype;
+boolean special;
+{
+       register struct mkroom *croom;
+
+       croom = &subrooms[nsubroom];
+       do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
+                                           rtype, special, (boolean) FALSE);
+       proom->sbrooms[proom->nsubrooms++] = croom;
+       croom++;
+       croom->hx = -1;
+       nsubroom++;
+}
+
+STATIC_OVL void
+makerooms()
+{
+       boolean tried_vault = FALSE;
+
+       /* make rooms until satisfied */
+       /* rnd_rect() will returns 0 if no more rects are available... */
+       while(nroom < MAXNROFROOMS && rnd_rect()) {
+               if(nroom >= (MAXNROFROOMS/6) && rn2(2) && !tried_vault) {
+                       tried_vault = TRUE;
+                       if (create_vault()) {
+                               vault_x = rooms[nroom].lx;
+                               vault_y = rooms[nroom].ly;
+                               rooms[nroom].hx = -1;
+                       }
+               } else
+                   if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1))
+                       return;
+       }
+       return;
+}
+
+STATIC_OVL void
+join(a,b,nxcor)
+register int a, b;
+boolean nxcor;
+{
+       coord cc,tt, org, dest;
+       register xchar tx, ty, xx, yy;
+       register struct mkroom *croom, *troom;
+       register int dx, dy;
+
+       croom = &rooms[a];
+       troom = &rooms[b];
+
+       /* find positions cc and tt for doors in croom and troom
+          and direction for a corridor between them */
+
+       if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return;
+       if(troom->lx > croom->hx) {
+               dx = 1;
+               dy = 0;
+               xx = croom->hx+1;
+               tx = troom->lx-1;
+               finddpos(&cc, xx, croom->ly, xx, croom->hy);
+               finddpos(&tt, tx, troom->ly, tx, troom->hy);
+       } else if(troom->hy < croom->ly) {
+               dy = -1;
+               dx = 0;
+               yy = croom->ly-1;
+               finddpos(&cc, croom->lx, yy, croom->hx, yy);
+               ty = troom->hy+1;
+               finddpos(&tt, troom->lx, ty, troom->hx, ty);
+       } else if(troom->hx < croom->lx) {
+               dx = -1;
+               dy = 0;
+               xx = croom->lx-1;
+               tx = troom->hx+1;
+               finddpos(&cc, xx, croom->ly, xx, croom->hy);
+               finddpos(&tt, tx, troom->ly, tx, troom->hy);
+       } else {
+               dy = 1;
+               dx = 0;
+               yy = croom->hy+1;
+               ty = troom->ly-1;
+               finddpos(&cc, croom->lx, yy, croom->hx, yy);
+               finddpos(&tt, troom->lx, ty, troom->hx, ty);
+       }
+       xx = cc.x;
+       yy = cc.y;
+       tx = tt.x - dx;
+       ty = tt.y - dy;
+       if(nxcor && levl[xx+dx][yy+dy].typ)
+               return;
+       if (okdoor(xx,yy) || !nxcor)
+           dodoor(xx,yy,croom);
+
+       org.x  = xx+dx; org.y  = yy+dy;
+       dest.x = tx; dest.y = ty;
+
+       if (!dig_corridor(&org, &dest, nxcor,
+                       level.flags.arboreal ? ROOM : CORR, STONE))
+           return;
+
+       /* we succeeded in digging the corridor */
+       if (okdoor(tt.x, tt.y) || !nxcor)
+           dodoor(tt.x, tt.y, troom);
+
+       if(smeq[a] < smeq[b])
+               smeq[b] = smeq[a];
+       else
+               smeq[a] = smeq[b];
+}
+
+void
+makecorridors()
+{
+       int a, b, i;
+       boolean any = TRUE;
+
+       for(a = 0; a < nroom-1; a++) {
+               join(a, a+1, FALSE);
+               if(!rn2(50)) break; /* allow some randomness */
+       }
+       for(a = 0; a < nroom-2; a++)
+           if(smeq[a] != smeq[a+2])
+               join(a, a+2, FALSE);
+       for(a = 0; any && a < nroom; a++) {
+           any = FALSE;
+           for(b = 0; b < nroom; b++)
+               if(smeq[a] != smeq[b]) {
+                   join(a, b, FALSE);
+                   any = TRUE;
+               }
+       }
+       if(nroom > 2)
+           for(i = rn2(nroom) + 4; i; i--) {
+               a = rn2(nroom);
+               b = rn2(nroom-2);
+               if(b >= a) b += 2;
+               join(a, b, TRUE);
+           }
+}
+
+void
+add_door(x,y,aroom)
+register int x, y;
+register struct mkroom *aroom;
+{
+       register struct mkroom *broom;
+       register int tmp;
+
+       aroom->doorct++;
+       broom = aroom+1;
+       if(broom->hx < 0)
+               tmp = doorindex;
+       else
+               for(tmp = doorindex; tmp > broom->fdoor; tmp--)
+                       doors[tmp] = doors[tmp-1];
+       doorindex++;
+       doors[tmp].x = x;
+       doors[tmp].y = y;
+       for( ; broom->hx >= 0; broom++) broom->fdoor++;
+}
+
+STATIC_OVL void
+dosdoor(x,y,aroom,type)
+register xchar x, y;
+register struct mkroom *aroom;
+register int type;
+{
+       boolean shdoor = ((*in_rooms(x, y, SHOPBASE))? TRUE : FALSE);
+
+       if(!IS_WALL(levl[x][y].typ)) /* avoid SDOORs on already made doors */
+               type = DOOR;
+       levl[x][y].typ = type;
+       if(type == DOOR) {
+           if(!rn2(3)) {      /* is it a locked door, closed, or a doorway? */
+               if(!rn2(5))
+                   levl[x][y].doormask = D_ISOPEN;
+               else if(!rn2(6))
+                   levl[x][y].doormask = D_LOCKED;
+               else
+                   levl[x][y].doormask = D_CLOSED;
+
+               if (levl[x][y].doormask != D_ISOPEN && !shdoor &&
+                   level_difficulty() >= 5 && !rn2(25))
+                   levl[x][y].doormask |= D_TRAPPED;
+           } else
+#ifdef STUPID
+               if (shdoor)
+                       levl[x][y].doormask = D_ISOPEN;
+               else
+                       levl[x][y].doormask = D_NODOOR;
+#else
+               levl[x][y].doormask = (shdoor ? D_ISOPEN : D_NODOOR);
+#endif
+           if(levl[x][y].doormask & D_TRAPPED) {
+               struct monst *mtmp;
+
+               if (level_difficulty() >= 9 && !rn2(5) &&
+                  !((mvitals[PM_SMALL_MIMIC].mvflags & G_GONE) &&
+                    (mvitals[PM_LARGE_MIMIC].mvflags & G_GONE) &&
+                    (mvitals[PM_GIANT_MIMIC].mvflags & G_GONE))) {
+                   /* make a mimic instead */
+                   levl[x][y].doormask = D_NODOOR;
+                   mtmp = makemon(mkclass(S_MIMIC,0), x, y, NO_MM_FLAGS);
+                   if (mtmp)
+                       set_mimic_sym(mtmp);
+               }
+           }
+           /* newsym(x,y); */
+       } else { /* SDOOR */
+               if(shdoor || !rn2(5))   levl[x][y].doormask = D_LOCKED;
+               else                    levl[x][y].doormask = D_CLOSED;
+
+               if(!shdoor && level_difficulty() >= 4 && !rn2(20))
+                   levl[x][y].doormask |= D_TRAPPED;
+       }
+
+       add_door(x,y,aroom);
+}
+
+STATIC_OVL boolean
+place_niche(aroom,dy,xx,yy)
+register struct mkroom *aroom;
+int *dy, *xx, *yy;
+{
+       coord dd;
+
+       if(rn2(2)) {
+           *dy = 1;
+           finddpos(&dd, aroom->lx, aroom->hy+1, aroom->hx, aroom->hy+1);
+       } else {
+           *dy = -1;
+           finddpos(&dd, aroom->lx, aroom->ly-1, aroom->hx, aroom->ly-1);
+       }
+       *xx = dd.x;
+       *yy = dd.y;
+       return((boolean)((isok(*xx,*yy+*dy) && levl[*xx][*yy+*dy].typ == STONE)
+           && (isok(*xx,*yy-*dy) && !IS_POOL(levl[*xx][*yy-*dy].typ)
+                                 && !IS_FURNITURE(levl[*xx][*yy-*dy].typ))));
+}
+
+/* there should be one of these per trap, in the same order as trap.h */
+static NEARDATA const char *trap_engravings[TRAPNUM] = {
+                       (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
+                       (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
+                       (char *)0, (char *)0, (char *)0, (char *)0,
+                       /* 14..16: trap door, teleport, level-teleport */
+                       "Vlad was here", "ad aerarium", "ad aerarium",
+                       (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
+                       (char *)0,
+};
+
+STATIC_OVL void
+makeniche(trap_type)
+int trap_type;
+{
+       register struct mkroom *aroom;
+       register struct rm *rm;
+       register int vct = 8;
+       int dy, xx, yy;
+       register struct trap *ttmp;
+
+       if(doorindex < DOORMAX)
+         while(vct--) {
+           aroom = &rooms[rn2(nroom)];
+           if(aroom->rtype != OROOM) continue; /* not an ordinary room */
+           if(aroom->doorct == 1 && rn2(5)) continue;
+           if(!place_niche(aroom,&dy,&xx,&yy)) continue;
+
+           rm = &levl[xx][yy+dy];
+           if(trap_type || !rn2(4)) {
+
+               rm->typ = SCORR;
+               if(trap_type) {
+                   if((trap_type == HOLE || trap_type == TRAPDOOR)
+                       && !Can_fall_thru(&u.uz))
+                       trap_type = ROCKTRAP;
+                   ttmp = maketrap(xx, yy+dy, trap_type);
+                   if (ttmp) {
+                       if (trap_type != ROCKTRAP) ttmp->once = 1;
+                       if (trap_engravings[trap_type]) {
+                           make_engr_at(xx, yy-dy,
+                                    trap_engravings[trap_type], 0L, DUST);
+                           wipe_engr_at(xx, yy-dy, 5); /* age it a little */
+                       }
+                   }
+               }
+               dosdoor(xx, yy, aroom, SDOOR);
+           } else {
+               rm->typ = CORR;
+               if(rn2(7))
+                   dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
+               else {
+                   if (!level.flags.noteleport)
+                       (void) mksobj_at(SCR_TELEPORTATION,
+                                        xx, yy+dy, TRUE, FALSE);
+                   if (!rn2(3)) (void) mkobj_at(0, xx, yy+dy, TRUE);
+               }
+           }
+           return;
+       }
+}
+
+STATIC_OVL void
+make_niches()
+{
+       register int ct = rnd((nroom>>1) + 1), dep = depth(&u.uz);
+
+       boolean ltptr = (!level.flags.noteleport && dep > 15),
+               vamp = (dep > 5 && dep < 25);
+
+       while(ct--) {
+               if (ltptr && !rn2(6)) {
+                       ltptr = FALSE;
+                       makeniche(LEVEL_TELEP);
+               } else if (vamp && !rn2(6)) {
+                       vamp = FALSE;
+                       makeniche(TRAPDOOR);
+               } else  makeniche(NO_TRAP);
+       }
+}
+
+STATIC_OVL void
+makevtele()
+{
+       makeniche(TELEP_TRAP);
+}
+
+/* clear out various globals that keep information on the current level.
+ * some of this is only necessary for some types of levels (maze, normal,
+ * special) but it's easier to put it all in one place than make sure
+ * each type initializes what it needs to separately.
+ */
+STATIC_OVL void
+clear_level_structures()
+{
+       static struct rm zerorm = { cmap_to_glyph(S_stone),
+                                               0, 0, 0, 0, 0, 0, 0, 0 };
+       register int x,y;
+       register struct rm *lev;
+
+       for(x=0; x<COLNO; x++) {
+           lev = &levl[x][0];
+           for(y=0; y<ROWNO; y++) {
+               *lev++ = zerorm;
+#ifdef MICROPORT_BUG
+               level.objects[x][y] = (struct obj *)0;
+               level.monsters[x][y] = (struct monst *)0;
+#endif
+           }
+       }
+#ifndef MICROPORT_BUG
+       (void) memset((genericptr_t)level.objects, 0, sizeof(level.objects));
+       (void) memset((genericptr_t)level.monsters, 0, sizeof(level.monsters));
+#endif
+       level.objlist = (struct obj *)0;
+       level.buriedobjlist = (struct obj *)0;
+       level.monlist = (struct monst *)0;
+       level.damagelist = (struct damage *)0;
+
+       level.flags.nfountains = 0;
+       level.flags.nsinks = 0;
+       level.flags.has_shop = 0;
+       level.flags.has_vault = 0;
+       level.flags.has_zoo = 0;
+       level.flags.has_court = 0;
+       level.flags.has_morgue = level.flags.graveyard = 0;
+       level.flags.has_beehive = 0;
+       level.flags.has_barracks = 0;
+       level.flags.has_temple = 0;
+       level.flags.has_swamp = 0;
+       level.flags.noteleport = 0;
+       level.flags.hardfloor = 0;
+       level.flags.nommap = 0;
+       level.flags.hero_memory = 1;
+       level.flags.shortsighted = 0;
+       level.flags.arboreal = 0;
+       level.flags.is_maze_lev = 0;
+       level.flags.is_cavernous_lev = 0;
+
+       nroom = 0;
+       rooms[0].hx = -1;
+       nsubroom = 0;
+       subrooms[0].hx = -1;
+       doorindex = 0;
+       init_rect();
+       init_vault();
+       xdnstair = ydnstair = xupstair = yupstair = 0;
+       sstairs.sx = sstairs.sy = 0;
+       xdnladder = ydnladder = xupladder = yupladder = 0;
+       made_branch = FALSE;
+       clear_regions();
+}
+
+STATIC_OVL void
+makelevel()
+{
+       register struct mkroom *croom, *troom;
+       register int tryct;
+       register int x, y;
+       struct monst *tmonst;   /* always put a web with a spider */
+       branch *branchp;
+       int room_threshold;
+
+       if(wiz1_level.dlevel == 0) init_dungeons();
+       oinit();        /* assign level dependent obj probabilities */
+       clear_level_structures();
+
+       {
+           register s_level *slev = Is_special(&u.uz);
+
+           /* check for special levels */
+#ifdef REINCARNATION
+           if (slev && !Is_rogue_level(&u.uz))
+#else
+           if (slev)
+#endif
+           {
+                   makemaz(slev->proto);
+                   return;
+           } else if (dungeons[u.uz.dnum].proto[0]) {
+                   makemaz("");
+                   return;
+           } else if (In_mines(&u.uz)) {
+                   makemaz("minefill");
+                   return;
+           } else if (In_quest(&u.uz)) {
+                   char        fillname[9];
+                   s_level     *loc_lev;
+
+                   Sprintf(fillname, "%s-loca", urole.filecode);
+                   loc_lev = find_level(fillname);
+
+                   Sprintf(fillname, "%s-fil", urole.filecode);
+                   Strcat(fillname,
+                          (u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b");
+                   makemaz(fillname);
+                   return;
+           } else if(In_hell(&u.uz) ||
+                 (rn2(5) && u.uz.dnum == medusa_level.dnum
+                         && depth(&u.uz) > depth(&medusa_level))) {
+                   makemaz("");
+                   return;
+           }
+       }
+
+       /* otherwise, fall through - it's a "regular" level. */
+
+#ifdef REINCARNATION
+       if (Is_rogue_level(&u.uz)) {
+               makeroguerooms();
+               makerogueghost();
+       } else
+#endif
+               makerooms();
+       sort_rooms();
+
+       /* construct stairs (up and down in different rooms if possible) */
+       croom = &rooms[rn2(nroom)];
+       if (!Is_botlevel(&u.uz))
+            mkstairs(somex(croom), somey(croom), 0, croom);    /* down */
+       if (nroom > 1) {
+           troom = croom;
+           croom = &rooms[rn2(nroom-1)];
+           if (croom == troom) croom++;
+       }
+
+       if (u.uz.dlevel != 1) {
+           xchar sx, sy;
+           do {
+               sx = somex(croom);
+               sy = somey(croom);
+           } while(occupied(sx, sy));
+           mkstairs(sx, sy, 1, croom); /* up */
+       }
+
+       branchp = Is_branchlev(&u.uz);  /* possible dungeon branch */
+       room_threshold = branchp ? 4 : 3; /* minimum number of rooms needed
+                                            to allow a random special room */
+#ifdef REINCARNATION
+       if (Is_rogue_level(&u.uz)) goto skip0;
+#endif
+       makecorridors();
+       make_niches();
+
+       /* make a secret treasure vault, not connected to the rest */
+       if(do_vault()) {
+               xchar w,h;
+#ifdef DEBUG
+               debugpline("trying to make a vault...");
+#endif
+               w = 1;
+               h = 1;
+               if (check_room(&vault_x, &w, &vault_y, &h, TRUE)) {
+                   fill_vault:
+                       add_room(vault_x, vault_y, vault_x+w,
+                                vault_y+h, TRUE, VAULT, FALSE);
+                       level.flags.has_vault = 1;
+                       ++room_threshold;
+                       fill_room(&rooms[nroom - 1], FALSE);
+                       mk_knox_portal(vault_x+w, vault_y+h);
+                       if(!level.flags.noteleport && !rn2(3)) makevtele();
+               } else if(rnd_rect() && create_vault()) {
+                       vault_x = rooms[nroom].lx;
+                       vault_y = rooms[nroom].ly;
+                       if (check_room(&vault_x, &w, &vault_y, &h, TRUE))
+                               goto fill_vault;
+                       else
+                               rooms[nroom].hx = -1;
+               }
+       }
+
+    {
+       register int u_depth = depth(&u.uz);
+
+#ifdef WIZARD
+       if(wizard && nh_getenv("SHOPTYPE")) mkroom(SHOPBASE); else
+#endif
+       if (u_depth > 1 &&
+           u_depth < depth(&medusa_level) &&
+           nroom >= room_threshold &&
+           rn2(u_depth) < 3) mkroom(SHOPBASE);
+       else if (u_depth > 4 && !rn2(6)) mkroom(COURT);
+       else if (u_depth > 5 && !rn2(8) &&
+          !(mvitals[PM_LEPRECHAUN].mvflags & G_GONE)) mkroom(LEPREHALL);
+       else if (u_depth > 6 && !rn2(7)) mkroom(ZOO);
+       else if (u_depth > 8 && !rn2(5)) mkroom(TEMPLE);
+       else if (u_depth > 9 && !rn2(5) &&
+          !(mvitals[PM_KILLER_BEE].mvflags & G_GONE)) mkroom(BEEHIVE);
+       else if (u_depth > 11 && !rn2(6)) mkroom(MORGUE);
+       else if (u_depth > 12 && !rn2(8)) mkroom(ANTHOLE);
+       else if (u_depth > 14 && !rn2(4) &&
+          !(mvitals[PM_SOLDIER].mvflags & G_GONE)) mkroom(BARRACKS);
+       else if (u_depth > 15 && !rn2(6)) mkroom(SWAMP);
+       else if (u_depth > 16 && !rn2(8) &&
+          !(mvitals[PM_COCKATRICE].mvflags & G_GONE)) mkroom(COCKNEST);
+    }
+
+#ifdef REINCARNATION
+skip0:
+#endif
+       /* Place multi-dungeon branch. */
+       place_branch(branchp, 0, 0);
+
+       /* for each room: put things inside */
+       for(croom = rooms; croom->hx > 0; croom++) {
+               if(croom->rtype != OROOM) continue;
+
+               /* put a sleeping monster inside */
+               /* Note: monster may be on the stairs. This cannot be
+                  avoided: maybe the player fell through a trap door
+                  while a monster was on the stairs. Conclusion:
+                  we have to check for monsters on the stairs anyway. */
+
+               if(u.uhave.amulet || !rn2(3)) {
+                   x = somex(croom); y = somey(croom);
+                   tmonst = makemon((struct permonst *) 0, x,y,NO_MM_FLAGS);
+                   if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER] &&
+                           !occupied(x, y))
+                       (void) maketrap(x, y, WEB);
+               }
+               /* put traps and mimics inside */
+               goldseen = FALSE;
+               x = 8 - (level_difficulty()/6);
+               if (x <= 1) x = 2;
+               while (!rn2(x))
+                   mktrap(0,0,croom,(coord*)0);
+               if (!goldseen && !rn2(3))
+                   (void) mkgold(0L, somex(croom), somey(croom));
+#ifdef REINCARNATION
+               if(Is_rogue_level(&u.uz)) goto skip_nonrogue;
+#endif
+               if(!rn2(10)) mkfount(0,croom);
+#ifdef SINKS
+               if(!rn2(60)) mksink(croom);
+#endif
+               if(!rn2(60)) mkaltar(croom);
+               x = 80 - (depth(&u.uz) * 2);
+               if (x < 2) x = 2;
+               if(!rn2(x)) mkgrave(croom);
+
+               /* put statues inside */
+               if(!rn2(20))
+                   (void) mkcorpstat(STATUE, (struct monst *)0,
+                                     (struct permonst *)0,
+                                     somex(croom), somey(croom), TRUE);
+               /* put box/chest inside;
+                *  40% chance for at least 1 box, regardless of number
+                *  of rooms; about 5 - 7.5% for 2 boxes, least likely
+                *  when few rooms; chance for 3 or more is neglible.
+                */
+               if(!rn2(nroom * 5 / 2))
+                   (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
+                                    somex(croom), somey(croom), TRUE, FALSE);
+
+               /* maybe make some graffiti */
+               if(!rn2(27 + 3 * abs(depth(&u.uz)))) {
+                   char buf[BUFSZ];
+                   const char *mesg = random_engraving(buf);
+                   if (mesg) {
+                       do {
+                           x = somex(croom);  y = somey(croom);
+                       } while(levl[x][y].typ != ROOM && !rn2(40));
+                       if (!(IS_POOL(levl[x][y].typ) ||
+                             IS_FURNITURE(levl[x][y].typ)))
+                           make_engr_at(x, y, mesg, 0L, MARK);
+                   }
+               }
+
+#ifdef REINCARNATION
+       skip_nonrogue:
+#endif
+               if(!rn2(3)) {
+                   (void) mkobj_at(0, somex(croom), somey(croom), TRUE);
+                   tryct = 0;
+                   while(!rn2(5)) {
+                       if(++tryct > 100) {
+                           impossible("tryct overflow4");
+                           break;
+                       }
+                       (void) mkobj_at(0, somex(croom), somey(croom), TRUE);
+                   }
+               }
+       }
+}
+
+/*
+ *     Place deposits of minerals (gold and misc gems) in the stone
+ *     surrounding the rooms on the map.
+ *     Also place kelp in water.
+ */
+STATIC_OVL void
+mineralize()
+{
+       s_level *sp;
+       struct obj *otmp;
+       int goldprob, gemprob, x, y, cnt;
+
+
+       /* Place kelp, except on the plane of water */
+       if (In_endgame(&u.uz)) return;
+       for (x = 2; x < (COLNO - 2); x++)
+           for (y = 1; y < (ROWNO - 1); y++)
+               if ((levl[x][y].typ == POOL && !rn2(10)) ||
+                       (levl[x][y].typ == MOAT && !rn2(30)))
+                   (void) mksobj_at(KELP_FROND, x, y, TRUE, FALSE);
+
+       /* determine if it is even allowed;
+          almost all special levels are excluded */
+       if (In_hell(&u.uz) || In_V_tower(&u.uz) ||
+#ifdef REINCARNATION
+               Is_rogue_level(&u.uz) ||
+#endif
+               level.flags.arboreal ||
+               ((sp = Is_special(&u.uz)) != 0 && !Is_oracle_level(&u.uz)
+                                       && (!In_mines(&u.uz) || sp->flags.town)
+           )) return;
+
+       /* basic level-related probabilities */
+       goldprob = 20 + depth(&u.uz) / 3;
+       gemprob = goldprob / 4;
+
+       /* mines have ***MORE*** goodies - otherwise why mine? */
+       if (In_mines(&u.uz)) {
+           goldprob *= 2;
+           gemprob *= 3;
+       } else if (In_quest(&u.uz)) {
+           goldprob /= 4;
+           gemprob /= 6;
+       }
+
+       /*
+        * Seed rock areas with gold and/or gems.
+        * We use fairly low level object handling to avoid unnecessary
+        * overhead from placing things in the floor chain prior to burial.
+        */
+       for (x = 2; x < (COLNO - 2); x++)
+         for (y = 1; y < (ROWNO - 1); y++)
+           if (levl[x][y+1].typ != STONE) {     /* <x,y> spot not eligible */
+               y += 2;         /* next two spots aren't eligible either */
+           } else if (levl[x][y].typ != STONE) { /* this spot not eligible */
+               y += 1;         /* next spot isn't eligible either */
+           } else if (!(levl[x][y].wall_info & W_NONDIGGABLE) &&
+                 levl[x][y-1].typ   == STONE &&
+                 levl[x+1][y-1].typ == STONE && levl[x-1][y-1].typ == STONE &&
+                 levl[x+1][y].typ   == STONE && levl[x-1][y].typ   == STONE &&
+                 levl[x+1][y+1].typ == STONE && levl[x-1][y+1].typ == STONE) {
+               if (rn2(1000) < goldprob) {
+                   if ((otmp = mksobj(GOLD_PIECE, FALSE, FALSE)) != 0) {
+                       otmp->ox = x,  otmp->oy = y;
+                       otmp->quan = 1L + rnd(goldprob * 3);
+                       otmp->owt = weight(otmp);
+                       if (!rn2(3)) add_to_buried(otmp);
+                       else place_object(otmp, x, y);
+                   }
+               }
+               if (rn2(1000) < gemprob) {
+                   for (cnt = rnd(2 + dunlev(&u.uz) / 3); cnt > 0; cnt--)
+                       if ((otmp = mkobj(GEM_CLASS, FALSE)) != 0) {
+                           if (otmp->otyp == ROCK) {
+                               dealloc_obj(otmp);      /* discard it */
+                           } else {
+                               otmp->ox = x,  otmp->oy = y;
+                               if (!rn2(3)) add_to_buried(otmp);
+                               else place_object(otmp, x, y);
+                           }
+                   }
+               }
+           }
+}
+
+void
+mklev()
+{
+       struct mkroom *croom;
+
+       if(getbones()) return;
+       in_mklev = TRUE;
+       makelevel();
+       bound_digging();
+       mineralize();
+       in_mklev = FALSE;
+       /* has_morgue gets cleared once morgue is entered; graveyard stays
+          set (graveyard might already be set even when has_morgue is clear
+          [see fixup_special()], so don't update it unconditionally) */
+       if (level.flags.has_morgue)
+           level.flags.graveyard = 1;
+       if (!level.flags.is_maze_lev) {
+           for (croom = &rooms[0]; croom != &rooms[nroom]; croom++)
+#ifdef SPECIALIZATION
+               topologize(croom, FALSE);
+#else
+               topologize(croom);
+#endif
+       }
+       set_wall_state();
+}
+
+void
+#ifdef SPECIALIZATION
+topologize(croom, do_ordinary)
+register struct mkroom *croom;
+boolean do_ordinary;
+#else
+topologize(croom)
+register struct mkroom *croom;
+#endif
+{
+       register int x, y, roomno = (croom - rooms) + ROOMOFFSET;
+       register int lowx = croom->lx, lowy = croom->ly;
+       register int hix = croom->hx, hiy = croom->hy;
+#ifdef SPECIALIZATION
+       register schar rtype = croom->rtype;
+#endif
+       register int subindex, nsubrooms = croom->nsubrooms;
+
+       /* skip the room if already done; i.e. a shop handled out of order */
+       /* also skip if this is non-rectangular (it _must_ be done already) */
+       if ((int) levl[lowx][lowy].roomno == roomno || croom->irregular)
+           return;
+#ifdef SPECIALIZATION
+# ifdef REINCARNATION
+       if (Is_rogue_level(&u.uz))
+           do_ordinary = TRUE;         /* vision routine helper */
+# endif
+       if ((rtype != OROOM) || do_ordinary)
+#endif
+       {
+           /* do innards first */
+           for(x = lowx; x <= hix; x++)
+               for(y = lowy; y <= hiy; y++)
+#ifdef SPECIALIZATION
+                   if (rtype == OROOM)
+                       levl[x][y].roomno = NO_ROOM;
+                   else
+#endif
+                       levl[x][y].roomno = roomno;
+           /* top and bottom edges */
+           for(x = lowx-1; x <= hix+1; x++)
+               for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
+                   levl[x][y].edge = 1;
+                   if (levl[x][y].roomno)
+                       levl[x][y].roomno = SHARED;
+                   else
+                       levl[x][y].roomno = roomno;
+               }
+           /* sides */
+           for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
+               for(y = lowy; y <= hiy; y++) {
+                   levl[x][y].edge = 1;
+                   if (levl[x][y].roomno)
+                       levl[x][y].roomno = SHARED;
+                   else
+                       levl[x][y].roomno = roomno;
+               }
+       }
+       /* subrooms */
+       for (subindex = 0; subindex < nsubrooms; subindex++)
+#ifdef SPECIALIZATION
+               topologize(croom->sbrooms[subindex], (rtype != OROOM));
+#else
+               topologize(croom->sbrooms[subindex]);
+#endif
+}
+
+/* Find an unused room for a branch location. */
+STATIC_OVL struct mkroom *
+find_branch_room(mp)
+    coord *mp;
+{
+    struct mkroom *croom = 0;
+
+    if (nroom == 0) {
+       mazexy(mp);             /* already verifies location */
+    } else {
+       /* not perfect - there may be only one stairway */
+       if(nroom > 2) {
+           int tryct = 0;
+
+           do
+               croom = &rooms[rn2(nroom)];
+           while((croom == dnstairs_room || croom == upstairs_room ||
+                 croom->rtype != OROOM) && (++tryct < 100));
+       } else
+           croom = &rooms[rn2(nroom)];
+
+       do {
+           if (!somexy(croom, mp))
+               impossible("Can't place branch!");
+       } while(occupied(mp->x, mp->y) ||
+           (levl[mp->x][mp->y].typ != CORR && levl[mp->x][mp->y].typ != ROOM));
+    }
+    return croom;
+}
+
+/* Find the room for (x,y).  Return null if not in a room. */
+STATIC_OVL struct mkroom *
+pos_to_room(x, y)
+    xchar x, y;
+{
+    int i;
+    struct mkroom *curr;
+
+    for (curr = rooms, i = 0; i < nroom; curr++, i++)
+       if (inside_room(curr, x, y)) return curr;;
+    return (struct mkroom *) 0;
+}
+
+
+/* If given a branch, randomly place a special stair or portal. */
+void
+place_branch(br, x, y)
+branch *br;    /* branch to place */
+xchar x, y;    /* location */
+{
+       coord         m;
+       d_level       *dest;
+       boolean       make_stairs;
+       struct mkroom *br_room;
+
+       /*
+        * Return immediately if there is no branch to make or we have
+        * already made one.  This routine can be called twice when
+        * a special level is loaded that specifies an SSTAIR location
+        * as a favored spot for a branch.
+        */
+       if (!br || made_branch) return;
+
+       if (!x) {       /* find random coordinates for branch */
+           br_room = find_branch_room(&m);
+           x = m.x;
+           y = m.y;
+       } else {
+           br_room = pos_to_room(x, y);
+       }
+
+       if (on_level(&br->end1, &u.uz)) {
+           /* we're on end1 */
+           make_stairs = br->type != BR_NO_END1;
+           dest = &br->end2;
+       } else {
+           /* we're on end2 */
+           make_stairs = br->type != BR_NO_END2;
+           dest = &br->end1;
+       }
+
+       if (br->type == BR_PORTAL) {
+           mkportal(x, y, dest->dnum, dest->dlevel);
+       } else if (make_stairs) {
+           sstairs.sx = x;
+           sstairs.sy = y;
+           sstairs.up = (char) on_level(&br->end1, &u.uz) ?
+                                           br->end1_up : !br->end1_up;
+           assign_level(&sstairs.tolev, dest);
+           sstairs_room = br_room;
+
+           levl[x][y].ladder = sstairs.up ? LA_UP : LA_DOWN;
+           levl[x][y].typ = STAIRS;
+       }
+       /*
+        * Set made_branch to TRUE even if we didn't make a stairwell (i.e.
+        * make_stairs is false) since there is currently only one branch
+        * per level, if we failed once, we're going to fail again on the
+        * next call.
+        */
+       made_branch = TRUE;
+}
+
+STATIC_OVL boolean
+bydoor(x, y)
+register xchar x, y;
+{
+       register int typ;
+
+       if (isok(x+1, y)) {
+               typ = levl[x+1][y].typ;
+               if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
+       }
+       if (isok(x-1, y)) {
+               typ = levl[x-1][y].typ;
+               if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
+       }
+       if (isok(x, y+1)) {
+               typ = levl[x][y+1].typ;
+               if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
+       }
+       if (isok(x, y-1)) {
+               typ = levl[x][y-1].typ;
+               if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
+       }
+       return FALSE;
+}
+
+/* see whether it is allowable to create a door at [x,y] */
+int
+okdoor(x,y)
+register xchar x, y;
+{
+       register boolean near_door = bydoor(x, y);
+
+       return((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL) &&
+                       doorindex < DOORMAX && !near_door);
+}
+
+void
+dodoor(x,y,aroom)
+register int x, y;
+register struct mkroom *aroom;
+{
+       if(doorindex >= DOORMAX) {
+               impossible("DOORMAX exceeded?");
+               return;
+       }
+
+       dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR);
+}
+
+boolean
+occupied(x, y)
+register xchar x, y;
+{
+       return((boolean)(t_at(x, y)
+               || IS_FURNITURE(levl[x][y].typ)
+               || is_lava(x,y)
+               || is_pool(x,y)
+               || invocation_pos(x,y)
+               ));
+}
+
+/* make a trap somewhere (in croom if mazeflag = 0 && !tm) */
+/* if tm != null, make trap at that location */
+void
+mktrap(num, mazeflag, croom, tm)
+register int num, mazeflag;
+register struct mkroom *croom;
+coord *tm;
+{
+       register int kind;
+       coord m;
+
+       /* no traps in pools */
+       if (tm && is_pool(tm->x,tm->y)) return;
+
+       if (num > 0 && num < TRAPNUM) {
+           kind = num;
+#ifdef REINCARNATION
+       } else if (Is_rogue_level(&u.uz)) {
+           switch (rn2(7)) {
+               default: kind = BEAR_TRAP; break; /* 0 */
+               case 1: kind = ARROW_TRAP; break;
+               case 2: kind = DART_TRAP; break;
+               case 3: kind = TRAPDOOR; break;
+               case 4: kind = PIT; break;
+               case 5: kind = SLP_GAS_TRAP; break;
+               case 6: kind = RUST_TRAP; break;
+           }
+#endif
+       } else if (Inhell && !rn2(5)) {
+           /* bias the frequency of fire traps in Gehennom */
+           kind = FIRE_TRAP;
+       } else {
+           unsigned lvl = level_difficulty();
+
+           do {
+               kind = rnd(TRAPNUM-1);
+               /* reject "too hard" traps */
+               switch (kind) {
+                   case MAGIC_PORTAL:
+                       kind = NO_TRAP; break;
+                   case ROLLING_BOULDER_TRAP:
+                   case SLP_GAS_TRAP:
+                       if (lvl < 2) kind = NO_TRAP; break;
+                   case LEVEL_TELEP:
+                       if (lvl < 5 || level.flags.noteleport)
+                           kind = NO_TRAP; break;
+                   case SPIKED_PIT:
+                       if (lvl < 5) kind = NO_TRAP; break;
+                   case LANDMINE:
+                       if (lvl < 6) kind = NO_TRAP; break;
+                   case WEB:
+                       if (lvl < 7) kind = NO_TRAP; break;
+                   case STATUE_TRAP:
+                   case POLY_TRAP:
+                       if (lvl < 8) kind = NO_TRAP; break;
+                   case FIRE_TRAP:
+                       if (!Inhell) kind = NO_TRAP; break;
+                   case TELEP_TRAP:
+                       if (level.flags.noteleport) kind = NO_TRAP; break;
+                   case HOLE:
+                       /* make these much less often than other traps */
+                       if (rn2(7)) kind = NO_TRAP; break;
+               }
+           } while (kind == NO_TRAP);
+       }
+
+       if ((kind == TRAPDOOR || kind == HOLE) && !Can_fall_thru(&u.uz))
+               kind = ROCKTRAP;
+
+       if (tm)
+           m = *tm;
+       else {
+           register int tryct = 0;
+           boolean avoid_boulder = (kind == PIT || kind == SPIKED_PIT ||
+                                    kind == TRAPDOOR || kind == HOLE);
+
+           do {
+               if (++tryct > 200)
+                   return;
+               if (mazeflag)
+                   mazexy(&m);
+               else if (!somexy(croom,&m))
+                   return;
+           } while (occupied(m.x, m.y) ||
+                       (avoid_boulder && sobj_at(BOULDER, m.x, m.y)));
+       }
+
+       (void) maketrap(m.x, m.y, kind);
+       if (kind == WEB) (void) makemon(&mons[PM_GIANT_SPIDER],
+                                               m.x, m.y, NO_MM_FLAGS);
+}
+
+void
+mkstairs(x, y, up, croom)
+xchar x, y;
+char  up;
+struct mkroom *croom;
+{
+       if (!x) {
+           impossible("mkstairs:  bogus stair attempt at <%d,%d>", x, y);
+           return;
+       }
+
+       /*
+        * We can't make a regular stair off an end of the dungeon.  This
+        * attempt can happen when a special level is placed at an end and
+        * has an up or down stair specified in its description file.
+        */
+       if ((dunlev(&u.uz) == 1 && up) ||
+                       (dunlev(&u.uz) == dunlevs_in_dungeon(&u.uz) && !up))
+           return;
+
+       if(up) {
+               xupstair = x;
+               yupstair = y;
+               upstairs_room = croom;
+       } else {
+               xdnstair = x;
+               ydnstair = y;
+               dnstairs_room = croom;
+       }
+
+       levl[x][y].typ = STAIRS;
+       levl[x][y].ladder = up ? LA_UP : LA_DOWN;
+}
+
+STATIC_OVL
+void
+mkfount(mazeflag,croom)
+register int mazeflag;
+register struct mkroom *croom;
+{
+       coord m;
+       register int tryct = 0;
+
+       do {
+           if(++tryct > 200) return;
+           if(mazeflag)
+               mazexy(&m);
+           else
+               if (!somexy(croom, &m))
+                   return;
+       } while(occupied(m.x, m.y) || bydoor(m.x, m.y));
+
+       /* Put a fountain at m.x, m.y */
+       levl[m.x][m.y].typ = FOUNTAIN;
+       /* Is it a "blessed" fountain? (affects drinking from fountain) */
+       if(!rn2(7)) levl[m.x][m.y].blessedftn = 1;
+
+       level.flags.nfountains++;
+}
+
+#ifdef SINKS
+STATIC_OVL void
+mksink(croom)
+register struct mkroom *croom;
+{
+       coord m;
+       register int tryct = 0;
+
+       do {
+           if(++tryct > 200) return;
+           if (!somexy(croom, &m))
+               return;
+       } while(occupied(m.x, m.y) || bydoor(m.x, m.y));
+
+       /* Put a sink at m.x, m.y */
+       levl[m.x][m.y].typ = SINK;
+
+       level.flags.nsinks++;
+}
+#endif /* SINKS */
+
+
+STATIC_OVL void
+mkaltar(croom)
+register struct mkroom *croom;
+{
+       coord m;
+       register int tryct = 0;
+       aligntyp al;
+
+       if (croom->rtype != OROOM) return;
+
+       do {
+           if(++tryct > 200) return;
+           if (!somexy(croom, &m))
+               return;
+       } while (occupied(m.x, m.y) || bydoor(m.x, m.y));
+
+       /* Put an altar at m.x, m.y */
+       levl[m.x][m.y].typ = ALTAR;
+
+       /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
+       al = rn2((int)A_LAWFUL+2) - 1;
+       levl[m.x][m.y].altarmask = Align2amask( al );
+}
+
+static void
+mkgrave(croom)
+struct mkroom *croom;
+{
+       coord m;
+       register int tryct = 0;
+       register struct obj *otmp;
+       boolean dobell = !rn2(10);
+
+
+       if(croom->rtype != OROOM) return;
+
+       do {
+           if(++tryct > 200) return;
+           if (!somexy(croom, &m))
+               return;
+       } while (occupied(m.x, m.y) || bydoor(m.x, m.y));
+
+       /* Put a grave at m.x, m.y */
+       make_grave(m.x, m.y, dobell ? "Saved by the bell!" : (char *) 0);
+
+       /* Possibly fill it with objects */
+       if (!rn2(3)) (void) mkgold(0L, m.x, m.y);
+       for (tryct = rn2(5); tryct; tryct--) {
+           otmp = mkobj(RANDOM_CLASS, TRUE);
+           if (!otmp) return;
+           curse(otmp);
+           otmp->ox = m.x;
+           otmp->oy = m.y;
+           add_to_buried(otmp);
+       }
+
+       /* Leave a bell, in case we accidentally buried someone alive */
+       if (dobell) (void) mksobj_at(BELL, m.x, m.y, TRUE, FALSE);
+       return;
+}
+
+
+/* maze levels have slightly different constraints from normal levels */
+#define x_maze_min 2
+#define y_maze_min 2
+/*
+ * Major level transmutation: add a set of stairs (to the Sanctum) after
+ * an earthquake that leaves behind a a new topology, centered at inv_pos.
+ * Assumes there are no rooms within the invocation area and that inv_pos
+ * is not too close to the edge of the map.  Also assume the hero can see,
+ * which is guaranteed for normal play due to the fact that sight is needed
+ * to read the Book of the Dead.
+ */
+void
+mkinvokearea()
+{
+    int dist;
+    xchar xmin = inv_pos.x, xmax = inv_pos.x;
+    xchar ymin = inv_pos.y, ymax = inv_pos.y;
+    register xchar i;
+
+    pline_The("floor shakes violently under you!");
+    pline_The("walls around you begin to bend and crumble!");
+    display_nhwindow(WIN_MESSAGE, TRUE);
+
+    mkinvpos(xmin, ymin, 0);           /* middle, before placing stairs */
+
+    for(dist = 1; dist < 7; dist++) {
+       xmin--; xmax++;
+
+       /* top and bottom */
+       if(dist != 3) { /* the area is wider that it is high */
+           ymin--; ymax++;
+           for(i = xmin+1; i < xmax; i++) {
+               mkinvpos(i, ymin, dist);
+               mkinvpos(i, ymax, dist);
+           }
+       }
+
+       /* left and right */
+       for(i = ymin; i <= ymax; i++) {
+           mkinvpos(xmin, i, dist);
+           mkinvpos(xmax, i, dist);
+       }
+
+       flush_screen(1);        /* make sure the new glyphs shows up */
+       delay_output();
+    }
+
+    You("are standing at the top of a stairwell leading down!");
+    mkstairs(u.ux, u.uy, 0, (struct mkroom *)0); /* down */
+    newsym(u.ux, u.uy);
+    vision_full_recalc = 1;    /* everything changed */
+}
+
+/* Change level topology.  Boulders in the vicinity are eliminated.
+ * Temporarily overrides vision in the name of a nice effect.
+ */
+STATIC_OVL void
+mkinvpos(x,y,dist)
+xchar x,y;
+int dist;
+{
+    struct trap *ttmp;
+    struct obj *otmp;
+    boolean make_rocks;
+    register struct rm *lev = &levl[x][y];
+
+    /* clip at existing map borders if necessary */
+    if (!within_bounded_area(x, y, x_maze_min + 1, y_maze_min + 1,
+                                  x_maze_max - 1, y_maze_max - 1)) {
+       /* only outermost 2 columns and/or rows may be truncated due to edge */
+       if (dist < (7 - 2))
+           panic("mkinvpos: <%d,%d> (%d) off map edge!", x, y, dist);
+       return;
+    }
+
+    /* clear traps */
+    if ((ttmp = t_at(x,y)) != 0) deltrap(ttmp);
+
+    /* clear boulders; leave some rocks for non-{moat|trap} locations */
+    make_rocks = (dist != 1 && dist != 4 && dist != 5) ? TRUE : FALSE;
+    while ((otmp = sobj_at(BOULDER, x, y)) != 0) {
+       if (make_rocks) {
+           fracture_rock(otmp);
+           make_rocks = FALSE;         /* don't bother with more rocks */
+       } else {
+           obj_extract_self(otmp);
+           obfree(otmp, (struct obj *)0);
+       }
+    }
+    unblock_point(x,y);        /* make sure vision knows this location is open */
+
+    /* fake out saved state */
+    lev->seenv = 0;
+    lev->doormask = 0;
+    if(dist < 6) lev->lit = TRUE;
+    lev->waslit = TRUE;
+    lev->horizontal = FALSE;
+    viz_array[y][x] = (dist < 6 ) ?
+       (IN_SIGHT|COULD_SEE) : /* short-circuit vision recalc */
+       COULD_SEE;
+
+    switch(dist) {
+    case 1: /* fire traps */
+       if (is_pool(x,y)) break;
+       lev->typ = ROOM;
+       ttmp = maketrap(x, y, FIRE_TRAP);
+       if (ttmp) ttmp->tseen = TRUE;
+       break;
+    case 0: /* lit room locations */
+    case 2:
+    case 3:
+    case 6: /* unlit room locations */
+       lev->typ = ROOM;
+       break;
+    case 4: /* pools (aka a wide moat) */
+    case 5:
+       lev->typ = MOAT;
+       /* No kelp! */
+       break;
+    default:
+       impossible("mkinvpos called with dist %d", dist);
+       break;
+    }
+
+    /* display new value of position; could have a monster/object on it */
+    newsym(x,y);
+}
+
+/*
+ * The portal to Ludios is special.  The entrance can only occur within a
+ * vault in the main dungeon at a depth greater than 10.  The Ludios branch
+ * structure reflects this by having a bogus "source" dungeon:  the value
+ * of n_dgns (thus, Is_branchlev() will never find it).
+ *
+ * Ludios will remain isolated until the branch is corrected by this function.
+ */
+STATIC_OVL void
+mk_knox_portal(x, y)
+xchar x, y;
+{
+       extern int n_dgns;              /* from dungeon.c */
+       d_level *source;
+       branch *br;
+       schar u_depth;
+
+       br = dungeon_branch("Fort Ludios");
+       if (on_level(&knox_level, &br->end1)) {
+           source = &br->end2;
+       } else {
+           /* disallow Knox branch on a level with one branch already */
+           if(Is_branchlev(&u.uz))
+               return;
+           source = &br->end1;
+       }
+
+       /* Already set or 2/3 chance of deferring until a later level. */
+       if (source->dnum < n_dgns || (rn2(3)
+#ifdef WIZARD
+                                     && !wizard
+#endif
+                                     )) return;
+
+       if (! (u.uz.dnum == oracle_level.dnum       /* in main dungeon */
+               && !at_dgn_entrance("The Quest")    /* but not Quest's entry */
+               && (u_depth = depth(&u.uz)) > 10    /* beneath 10 */
+               && u_depth < depth(&medusa_level))) /* and above Medusa */
+           return;
+
+       /* Adjust source to be current level and re-insert branch. */
+       *source = u.uz;
+       insert_branch(br, TRUE);
+
+#ifdef DEBUG
+       pline("Made knox portal.");
+#endif
+       place_branch(br, x, y);
+}
+
+/*mklev.c*/
diff --git a/src/mkmap.c b/src/mkmap.c
new file mode 100644 (file)
index 0000000..ed24ac9
--- /dev/null
@@ -0,0 +1,479 @@
+/*     SCCS Id: @(#)mkmap.c    3.4     1996/05/23      */
+/* Copyright (c) J. C. Collet, M. Stephenson and D. Cohrs, 1992   */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "sp_lev.h"
+
+#define HEIGHT (ROWNO - 1)
+#define WIDTH  (COLNO - 2)
+
+STATIC_DCL void FDECL(init_map,(SCHAR_P));
+STATIC_DCL void FDECL(init_fill,(SCHAR_P,SCHAR_P));
+STATIC_DCL schar FDECL(get_map,(int,int,SCHAR_P));
+STATIC_DCL void FDECL(pass_one,(SCHAR_P,SCHAR_P));
+STATIC_DCL void FDECL(pass_two,(SCHAR_P,SCHAR_P));
+STATIC_DCL void FDECL(pass_three,(SCHAR_P,SCHAR_P));
+STATIC_DCL void NDECL(wallify_map);
+STATIC_DCL void FDECL(join_map,(SCHAR_P,SCHAR_P));
+STATIC_DCL void FDECL(finish_map,(SCHAR_P,SCHAR_P,XCHAR_P,XCHAR_P));
+STATIC_DCL void FDECL(remove_room,(unsigned));
+void FDECL(mkmap, (lev_init *));
+
+char *new_locations;
+int min_rx, max_rx, min_ry, max_ry; /* rectangle bounds for regions */
+static int n_loc_filled;
+
+STATIC_OVL void
+init_map(bg_typ)
+       schar   bg_typ;
+{
+       register int i,j;
+
+       for(i=1; i<COLNO; i++)
+           for(j=0; j<ROWNO; j++)
+               levl[i][j].typ = bg_typ;
+}
+
+STATIC_OVL void
+init_fill(bg_typ, fg_typ)
+       schar   bg_typ, fg_typ;
+{
+       register int i,j;
+       long limit, count;
+
+       limit = (WIDTH * HEIGHT * 2) / 5;
+       count = 0;
+       while(count < limit) {
+           i = rn1(WIDTH-1, 2);
+           j = rnd(HEIGHT-1);
+           if (levl[i][j].typ == bg_typ) {
+               levl[i][j].typ = fg_typ;
+               count++;
+           }
+       }
+}
+
+STATIC_OVL schar
+get_map(col,row, bg_typ)
+       int col,row;
+       schar   bg_typ;
+{
+       if (col <= 0 || row < 0 || col > WIDTH || row >= HEIGHT)
+               return bg_typ;
+       return levl[col][row].typ;
+}
+
+static int dirs[16] = {
+    -1, -1 /**/, -1, 0 /**/, -1, 1 /**/,
+     0, -1 /**/,              0, 1 /**/,
+     1, -1 /**/,  1, 0 /**/,  1, 1};
+
+STATIC_OVL void
+pass_one(bg_typ, fg_typ)
+       schar   bg_typ, fg_typ;
+{
+       register int i,j;
+       short count, dr;
+
+       for(i=2; i<=WIDTH; i++)
+           for(j=1; j<HEIGHT; j++) {
+               for(count=0, dr=0; dr < 8; dr++)
+                   if(get_map(i+dirs[dr*2], j+dirs[(dr*2)+1], bg_typ)
+                                                               == fg_typ)
+                       count++;
+
+               switch(count) {
+                 case 0 : /* death */
+                 case 1 :
+                 case 2:
+                         levl[i][j].typ = bg_typ;
+                         break;
+                 case 5:
+                 case 6:
+                 case 7:
+                 case 8:
+                         levl[i][j].typ = fg_typ;
+                         break;
+                 default:
+                         break;
+                 }
+           }
+}
+
+#define new_loc(i,j)   *(new_locations+ ((j)*(WIDTH+1)) + (i))
+
+STATIC_OVL void
+pass_two(bg_typ, fg_typ)
+       schar   bg_typ, fg_typ;
+{
+       register int i,j;
+       short count, dr;
+
+       for(i=2; i<=WIDTH; i++)
+           for(j=1; j<HEIGHT; j++) {
+               for(count=0, dr=0; dr < 8; dr++)
+                   if(get_map(i+dirs[dr*2], j+dirs[(dr*2)+1], bg_typ)
+                                                               == fg_typ)
+                       count++;
+                   if (count == 5)
+                       new_loc(i,j) = bg_typ;
+                   else
+                       new_loc(i,j) = get_map(i,j, bg_typ);
+           }
+
+       for(i=2; i<=WIDTH; i++)
+           for(j=1; j<HEIGHT; j++)
+               levl[i][j].typ = new_loc(i,j);
+}
+
+STATIC_OVL void
+pass_three(bg_typ, fg_typ)
+       schar   bg_typ, fg_typ;
+{
+       register int i,j;
+       short count, dr;
+
+       for(i=2; i<=WIDTH; i++)
+           for(j=1; j<HEIGHT; j++) {
+               for(count=0, dr=0; dr < 8; dr++)
+                   if(get_map(i+dirs[dr*2], j+dirs[(dr*2)+1], bg_typ)
+                                                               == fg_typ)
+                       count++;
+               if (count < 3)
+                   new_loc(i,j) = bg_typ;
+               else
+                   new_loc(i,j) = get_map(i,j, bg_typ);
+           }
+
+       for(i=2; i<=WIDTH; i++)
+           for(j=1; j<HEIGHT; j++)
+               levl[i][j].typ = new_loc(i,j);
+}
+
+/*
+ * use a flooding algorithm to find all locations that should
+ * have the same rm number as the current location.
+ * if anyroom is TRUE, use IS_ROOM to check room membership instead of
+ * exactly matching levl[sx][sy].typ and walls are included as well.
+ */
+void
+flood_fill_rm(sx, sy, rmno, lit, anyroom)
+    int sx;
+    register int sy;
+    register int rmno;
+    boolean lit;
+    boolean anyroom;
+{
+    register int i;
+    int nx;
+    schar fg_typ = levl[sx][sy].typ;
+
+    /* back up to find leftmost uninitialized location */
+    while (sx > 0 &&
+         (anyroom ? IS_ROOM(levl[sx][sy].typ) : levl[sx][sy].typ == fg_typ) &&
+         (int) levl[sx][sy].roomno != rmno)
+       sx--;
+    sx++; /* compensate for extra decrement */
+
+    /* assume sx,sy is valid */
+    if(sx < min_rx) min_rx = sx;
+    if(sy < min_ry) min_ry = sy;
+
+    for(i=sx; i<=WIDTH && levl[i][sy].typ == fg_typ; i++) {
+       levl[i][sy].roomno = rmno;
+       levl[i][sy].lit = lit;
+       if(anyroom) {
+           /* add walls to room as well */
+           register int ii,jj;
+           for(ii= (i == sx ? i-1 : i); ii <= i+1; ii++)
+               for(jj = sy-1; jj <= sy+1; jj++)
+                   if(isok(ii,jj) &&
+                      (IS_WALL(levl[ii][jj].typ) ||
+                       IS_DOOR(levl[ii][jj].typ))) {
+                       levl[ii][jj].edge = 1;
+                       if(lit) levl[ii][jj].lit = lit;
+                       if ((int) levl[ii][jj].roomno != rmno)
+                           levl[ii][jj].roomno = SHARED;
+                   }
+       }
+       n_loc_filled++;
+    }
+    nx = i;
+
+    if(isok(sx,sy-1)) {
+       for(i=sx; i<nx; i++)
+           if(levl[i][sy-1].typ == fg_typ) {
+               if ((int) levl[i][sy-1].roomno != rmno)
+                   flood_fill_rm(i,sy-1,rmno,lit,anyroom);
+           } else {
+               if((i>sx || isok(i-1,sy-1)) &&
+                     levl[i-1][sy-1].typ == fg_typ) {
+                   if ((int) levl[i-1][sy-1].roomno != rmno)
+                       flood_fill_rm(i-1,sy-1,rmno,lit,anyroom);
+               }
+               if((i<nx-1 || isok(i+1,sy-1)) &&
+                     levl[i+1][sy-1].typ == fg_typ) {
+                   if ((int) levl[i+1][sy-1].roomno != rmno)
+                       flood_fill_rm(i+1,sy-1,rmno,lit,anyroom);
+               }
+           }
+    }
+    if(isok(sx,sy+1)) {
+       for(i=sx; i<nx; i++)
+           if(levl[i][sy+1].typ == fg_typ) {
+               if ((int) levl[i][sy+1].roomno != rmno)
+                   flood_fill_rm(i,sy+1,rmno,lit,anyroom);
+           } else {
+               if((i>sx || isok(i-1,sy+1)) &&
+                     levl[i-1][sy+1].typ == fg_typ) {
+                   if ((int) levl[i-1][sy+1].roomno != rmno)
+                       flood_fill_rm(i-1,sy+1,rmno,lit,anyroom);
+               }
+               if((i<nx-1 || isok(i+1,sy+1)) &&
+                     levl[i+1][sy+1].typ == fg_typ) {
+                   if ((int) levl[i+1][sy+1].roomno != rmno)
+                       flood_fill_rm(i+1,sy+1,rmno,lit,anyroom);
+               }
+           }
+    }
+
+    if(nx > max_rx) max_rx = nx - 1; /* nx is just past valid region */
+    if(sy > max_ry) max_ry = sy;
+}
+
+/*
+ *     If we have drawn a map without walls, this allows us to
+ *     auto-magically wallify it.  Taken from lev_main.c.
+ */
+STATIC_OVL void
+wallify_map()
+{
+
+    int x, y, xx, yy;
+
+    for(x = 1; x < COLNO; x++)
+       for(y = 0; y < ROWNO; y++)
+           if(levl[x][y].typ == STONE) {
+               for(yy = y - 1; yy <= y+1; yy++)
+                   for(xx = x - 1; xx <= x+1; xx++)
+                       if(isok(xx,yy) && levl[xx][yy].typ == ROOM) {
+                           if(yy != y) levl[x][y].typ = HWALL;
+                           else        levl[x][y].typ = VWALL;
+                       }
+           }
+}
+
+STATIC_OVL void
+join_map(bg_typ, fg_typ)
+       schar   bg_typ, fg_typ;
+{
+    register struct mkroom *croom, *croom2;
+
+    register int i, j;
+    int sx, sy;
+    coord sm, em;
+
+    /* first, use flood filling to find all of the regions that need joining */
+    for(i=2; i<=WIDTH; i++)
+       for(j=1; j<HEIGHT; j++) {
+           if(levl[i][j].typ == fg_typ && levl[i][j].roomno == NO_ROOM) {
+               min_rx = max_rx = i;
+               min_ry = max_ry = j;
+               n_loc_filled = 0;
+               flood_fill_rm(i,j,nroom+ROOMOFFSET,FALSE,FALSE);
+               if(n_loc_filled > 3) {
+                   add_room(min_rx, min_ry, max_rx, max_ry,
+                            FALSE, OROOM, TRUE);
+                   rooms[nroom-1].irregular = TRUE;
+                   if(nroom >= (MAXNROFROOMS*2))
+                       goto joinm;
+               } else {
+                   /*
+                    * it's a tiny hole; erase it from the map to avoid
+                    * having the player end up here with no way out.
+                    */
+                   for(sx = min_rx; sx<=max_rx; sx++)
+                       for(sy = min_ry; sy<=max_ry; sy++)
+                           if ((int) levl[sx][sy].roomno ==
+                                   nroom + ROOMOFFSET) {
+                               levl[sx][sy].typ = bg_typ;
+                               levl[sx][sy].roomno = NO_ROOM;
+                           }
+               }
+           }
+       }
+
+joinm:
+    /*
+     * Ok, now we can actually join the regions with fg_typ's.
+     * The rooms are already sorted due to the previous loop,
+     * so don't call sort_rooms(), which can screw up the roomno's
+     * validity in the levl structure.
+     */
+    for(croom = &rooms[0], croom2 = croom + 1; croom2 < &rooms[nroom]; ) {
+       /* pick random starting and end locations for "corridor" */
+       if(!somexy(croom, &sm) || !somexy(croom2, &em)) {
+           /* ack! -- the level is going to be busted */
+           /* arbitrarily pick centers of both rooms and hope for the best */
+           impossible("No start/end room loc in join_map.");
+           sm.x = croom->lx + ((croom->hx - croom->lx) / 2);
+           sm.y = croom->ly + ((croom->hy - croom->ly) / 2);
+           em.x = croom2->lx + ((croom2->hx - croom2->lx) / 2);
+           em.y = croom2->ly + ((croom2->hy - croom2->ly) / 2);
+       }
+
+       (void) dig_corridor(&sm, &em, FALSE, fg_typ, bg_typ);
+
+       /* choose next region to join */
+       /* only increment croom if croom and croom2 are non-overlapping */
+       if(croom2->lx > croom->hx ||
+          ((croom2->ly > croom->hy || croom2->hy < croom->ly) && rn2(3))) {
+           croom = croom2;
+       }
+       croom2++; /* always increment the next room */
+    }
+}
+
+STATIC_OVL void
+finish_map(fg_typ, bg_typ, lit, walled)
+       schar   fg_typ, bg_typ;
+       boolean lit, walled;
+{
+       int     i, j;
+
+       if(walled) wallify_map();
+
+       if(lit) {
+           for(i=1; i<COLNO; i++)
+               for(j=0; j<ROWNO; j++)
+                   if((!IS_ROCK(fg_typ) && levl[i][j].typ == fg_typ) ||
+                      (!IS_ROCK(bg_typ) && levl[i][j].typ == bg_typ) ||
+                      (bg_typ == TREE && levl[i][j].typ == bg_typ) ||
+                       (walled && IS_WALL(levl[i][j].typ)))
+                       levl[i][j].lit = TRUE;
+           for(i = 0; i < nroom; i++)
+               rooms[i].rlit = 1;
+       }
+       /* light lava even if everything's otherwise unlit */
+       for(i=1; i<COLNO; i++)
+           for(j=0; j<ROWNO; j++)
+               if (levl[i][j].typ == LAVAPOOL)
+                   levl[i][j].lit = TRUE;
+}
+
+/*
+ * When level processed by join_map is overlaid by a MAP, some rooms may no
+ * longer be valid.  All rooms in the region lx <= x < hx, ly <= y < hy are
+ * removed.  Rooms partially in the region are truncated.  This function
+ * must be called before the REGIONs or ROOMs of the map are processed, or
+ * those rooms will be removed as well.  Assumes roomno fields in the
+ * region are already cleared, and roomno and irregular fields outside the
+ * region are all set.
+ */
+void
+remove_rooms(lx, ly, hx, hy)
+    int lx, ly, hx, hy;
+{
+    int i;
+    struct mkroom *croom;
+
+    for (i = nroom - 1; i >= 0; --i) {
+       croom = &rooms[i];
+       if (croom->hx < lx || croom->lx >= hx ||
+           croom->hy < ly || croom->ly >= hy) continue; /* no overlap */
+
+       if (croom->lx < lx || croom->hx >= hx ||
+           croom->ly < ly || croom->hy >= hy) { /* partial overlap */
+           /* TODO: ensure remaining parts of room are still joined */
+
+           if (!croom->irregular) impossible("regular room in joined map");
+       } else {
+           /* total overlap, remove the room */
+           remove_room((unsigned)i);
+       }
+    }
+}
+
+/*
+ * Remove roomno from the rooms array, decrementing nroom.  Also updates
+ * all level roomno values of affected higher numbered rooms.  Assumes
+ * level structure contents corresponding to roomno have already been reset.
+ * Currently handles only the removal of rooms that have no subrooms.
+ */
+STATIC_OVL void
+remove_room(roomno)
+    unsigned roomno;
+{
+    struct mkroom *croom = &rooms[roomno];
+    struct mkroom *maxroom = &rooms[--nroom];
+    int i, j;
+    unsigned oroomno;
+
+    if (croom != maxroom) {
+       /* since the order in the array only matters for making corridors,
+        * copy the last room over the one being removed on the assumption
+        * that corridors have already been dug. */
+       (void) memcpy((genericptr_t)croom, (genericptr_t)maxroom,
+                     sizeof(struct mkroom));
+
+       /* since maxroom moved, update affected level roomno values */
+       oroomno = nroom + ROOMOFFSET;
+       roomno += ROOMOFFSET;
+       for (i = croom->lx; i <= croom->hx; ++i)
+           for (j = croom->ly; j <= croom->hy; ++j) {
+               if (levl[i][j].roomno == oroomno)
+                   levl[i][j].roomno = roomno;
+           }
+    }
+
+    maxroom->hx = -1;                  /* just like add_room */
+}
+
+#define N_P1_ITER      1       /* tune map generation via this value */
+#define N_P2_ITER      1       /* tune map generation via this value */
+#define N_P3_ITER      2       /* tune map smoothing via this value */
+
+void
+mkmap(init_lev)
+       lev_init        *init_lev;
+{
+       schar   bg_typ = init_lev->bg,
+               fg_typ = init_lev->fg;
+       boolean smooth = init_lev->smoothed,
+               join = init_lev->joined;
+       xchar   lit = init_lev->lit,
+               walled = init_lev->walled;
+       int i;
+
+       if(lit < 0)
+           lit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? 1 : 0;
+
+       new_locations = (char *)alloc((WIDTH+1) * HEIGHT);
+
+       init_map(bg_typ);
+       init_fill(bg_typ, fg_typ);
+
+       for(i = 0; i < N_P1_ITER; i++)
+           pass_one(bg_typ, fg_typ);
+
+       for(i = 0; i < N_P2_ITER; i++)
+       pass_two(bg_typ, fg_typ);
+
+       if(smooth)
+           for(i = 0; i < N_P3_ITER; i++)
+               pass_three(bg_typ, fg_typ);
+
+       if(join)
+           join_map(bg_typ, fg_typ);
+
+       finish_map(fg_typ, bg_typ, (boolean)lit, (boolean)walled);
+       /* a walled, joined level is cavernous, not mazelike -dlc */
+       if (walled && join) {
+           level.flags.is_maze_lev = FALSE;
+           level.flags.is_cavernous_lev = TRUE;
+       }
+       free(new_locations);
+}
+
+/*mkmap.c*/
diff --git a/src/mkmaze.c b/src/mkmaze.c
new file mode 100644 (file)
index 0000000..12aaee6
--- /dev/null
@@ -0,0 +1,1415 @@
+/*     SCCS Id: @(#)mkmaze.c   3.4     2002/04/04      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "sp_lev.h"
+#include "lev.h"       /* save & restore info */
+
+/* from sp_lev.c, for fixup_special() */
+extern char *lev_message;
+extern lev_region *lregions;
+extern int num_lregions;
+
+STATIC_DCL boolean FDECL(iswall,(int,int));
+STATIC_DCL boolean FDECL(iswall_or_stone,(int,int));
+STATIC_DCL boolean FDECL(is_solid,(int,int));
+STATIC_DCL int FDECL(extend_spine, (int [3][3], int, int, int));
+STATIC_DCL boolean FDECL(okay,(int,int,int));
+STATIC_DCL void FDECL(maze0xy,(coord *));
+STATIC_DCL boolean FDECL(put_lregion_here,(XCHAR_P,XCHAR_P,XCHAR_P,
+       XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,BOOLEAN_P,d_level *));
+STATIC_DCL void NDECL(fixup_special);
+STATIC_DCL void FDECL(move, (int *,int *,int));
+STATIC_DCL void NDECL(setup_waterlevel);
+STATIC_DCL void NDECL(unsetup_waterlevel);
+
+
+STATIC_OVL boolean
+iswall(x,y)
+int x,y;
+{
+    register int type;
+
+    if (!isok(x,y)) return FALSE;
+    type = levl[x][y].typ;
+    return (IS_WALL(type) || IS_DOOR(type) ||
+           type == SDOOR || type == IRONBARS);
+}
+
+STATIC_OVL boolean
+iswall_or_stone(x,y)
+    int x,y;
+{
+    register int type;
+
+    /* out of bounds = stone */
+    if (!isok(x,y)) return TRUE;
+
+    type = levl[x][y].typ;
+    return (type == STONE || IS_WALL(type) || IS_DOOR(type) ||
+           type == SDOOR || type == IRONBARS);
+}
+
+/* return TRUE if out of bounds, wall or rock */
+STATIC_OVL boolean
+is_solid(x,y)
+    int x, y;
+{
+    return (!isok(x,y) || IS_STWALL(levl[x][y].typ));
+}
+
+
+/*
+ * Return 1 (not TRUE - we're doing bit vectors here) if we want to extend
+ * a wall spine in the (dx,dy) direction.  Return 0 otherwise.
+ *
+ * To extend a wall spine in that direction, first there must be a wall there.
+ * Then, extend a spine unless the current position is surrounded by walls
+ * in the direction given by (dx,dy).  E.g. if 'x' is our location, 'W'
+ * a wall, '.' a room, 'a' anything (we don't care), and our direction is
+ * (0,1) - South or down - then:
+ *
+ *             a a a
+ *             W x W           This would not extend a spine from x down
+ *             W W W           (a corridor of walls is formed).
+ *
+ *             a a a
+ *             W x W           This would extend a spine from x down.
+ *             . W W
+ */
+STATIC_OVL int
+extend_spine(locale, wall_there, dx, dy)
+    int locale[3][3];
+    int wall_there, dx, dy;
+{
+    int spine, nx, ny;
+
+    nx = 1 + dx;
+    ny = 1 + dy;
+
+    if (wall_there) {  /* wall in that direction */
+       if (dx) {
+           if (locale[ 1][0] && locale[ 1][2] && /* EW are wall/stone */
+               locale[nx][0] && locale[nx][2]) { /* diag are wall/stone */
+               spine = 0;
+           } else {
+               spine = 1;
+           }
+       } else {        /* dy */
+           if (locale[0][ 1] && locale[2][ 1] && /* NS are wall/stone */
+               locale[0][ny] && locale[2][ny]) { /* diag are wall/stone */
+               spine = 0;
+           } else {
+               spine = 1;
+           }
+       }
+    } else {
+       spine = 0;
+    }
+
+    return spine;
+}
+
+
+/*
+ * Wall cleanup.  This function has two purposes: (1) remove walls that
+ * are totally surrounded by stone - they are redundant.  (2) correct
+ * the types so that they extend and connect to each other.
+ */
+void
+wallification(x1, y1, x2, y2)
+int x1, y1, x2, y2;
+{
+       uchar type;
+       register int x,y;
+       struct rm *lev;
+       int bits;
+       int locale[3][3];       /* rock or wall status surrounding positions */
+       /*
+        * Value 0 represents a free-standing wall.  It could be anything,
+        * so even though this table says VWALL, we actually leave whatever
+        * typ was there alone.
+        */
+       static xchar spine_array[16] = {
+           VWALL,      HWALL,          HWALL,          HWALL,
+           VWALL,      TRCORNER,       TLCORNER,       TDWALL,
+           VWALL,      BRCORNER,       BLCORNER,       TUWALL,
+           VWALL,      TLWALL,         TRWALL,         CROSSWALL
+       };
+
+       /* sanity check on incoming variables */
+       if (x1<0 || x2>=COLNO || x1>x2 || y1<0 || y2>=ROWNO || y1>y2)
+           panic("wallification: bad bounds (%d,%d) to (%d,%d)",x1,y1,x2,y2);
+
+       /* Step 1: change walls surrounded by rock to rock. */
+       for(x = x1; x <= x2; x++)
+           for(y = y1; y <= y2; y++) {
+               lev = &levl[x][y];
+               type = lev->typ;
+               if (IS_WALL(type) && type != DBWALL) {
+                   if (is_solid(x-1,y-1) &&
+                       is_solid(x-1,y  ) &&
+                       is_solid(x-1,y+1) &&
+                       is_solid(x,  y-1) &&
+                       is_solid(x,  y+1) &&
+                       is_solid(x+1,y-1) &&
+                       is_solid(x+1,y  ) &&
+                       is_solid(x+1,y+1))
+                   lev->typ = STONE;
+               }
+           }
+
+       /*
+        * Step 2: set the correct wall type.  We can't combine steps
+        * 1 and 2 into a single sweep because we depend on knowing if
+        * the surrounding positions are stone.
+        */
+       for(x = x1; x <= x2; x++)
+           for(y = y1; y <= y2; y++) {
+               lev = &levl[x][y];
+               type = lev->typ;
+               if ( !(IS_WALL(type) && type != DBWALL)) continue;
+
+               /* set the locations TRUE if rock or wall or out of bounds */
+               locale[0][0] = iswall_or_stone(x-1,y-1);
+               locale[1][0] = iswall_or_stone(  x,y-1);
+               locale[2][0] = iswall_or_stone(x+1,y-1);
+
+               locale[0][1] = iswall_or_stone(x-1,  y);
+               locale[2][1] = iswall_or_stone(x+1,  y);
+
+               locale[0][2] = iswall_or_stone(x-1,y+1);
+               locale[1][2] = iswall_or_stone(  x,y+1);
+               locale[2][2] = iswall_or_stone(x+1,y+1);
+
+               /* determine if wall should extend to each direction NSEW */
+               bits =    (extend_spine(locale, iswall(x,y-1),  0, -1) << 3)
+                       | (extend_spine(locale, iswall(x,y+1),  0,  1) << 2)
+                       | (extend_spine(locale, iswall(x+1,y),  1,  0) << 1)
+                       |  extend_spine(locale, iswall(x-1,y), -1,  0);
+
+               /* don't change typ if wall is free-standing */
+               if (bits) lev->typ = spine_array[bits];
+           }
+}
+
+STATIC_OVL boolean
+okay(x,y,dir)
+int x,y;
+register int dir;
+{
+       move(&x,&y,dir);
+       move(&x,&y,dir);
+       if(x<3 || y<3 || x>x_maze_max || y>y_maze_max || levl[x][y].typ != 0)
+               return(FALSE);
+       return(TRUE);
+}
+
+STATIC_OVL void
+maze0xy(cc)    /* find random starting point for maze generation */
+       coord   *cc;
+{
+       cc->x = 3 + 2*rn2((x_maze_max>>1) - 1);
+       cc->y = 3 + 2*rn2((y_maze_max>>1) - 1);
+       return;
+}
+
+/*
+ * Bad if:
+ *     pos is occupied OR
+ *     pos is inside restricted region (lx,ly,hx,hy) OR
+ *     NOT (pos is corridor and a maze level OR pos is a room OR pos is air)
+ */
+boolean
+bad_location(x, y, lx, ly, hx, hy)
+    xchar x, y;
+    xchar lx, ly, hx, hy;
+{
+    return((boolean)(occupied(x, y) ||
+          within_bounded_area(x,y, lx,ly, hx,hy) ||
+          !((levl[x][y].typ == CORR && level.flags.is_maze_lev) ||
+              levl[x][y].typ == ROOM || levl[x][y].typ == AIR)));
+}
+
+/* pick a location in area (lx, ly, hx, hy) but not in (nlx, nly, nhx, nhy) */
+/* and place something (based on rtype) in that region */
+void
+place_lregion(lx, ly, hx, hy, nlx, nly, nhx, nhy, rtype, lev)
+    xchar      lx, ly, hx, hy;
+    xchar      nlx, nly, nhx, nhy;
+    xchar      rtype;
+    d_level    *lev;
+{
+    int trycnt;
+    boolean oneshot;
+    xchar x, y;
+
+    if(!lx) { /* default to whole level */
+       /*
+        * if there are rooms and this a branch, let place_branch choose
+        * the branch location (to avoid putting branches in corridors).
+        */
+       if(rtype == LR_BRANCH && nroom) {
+           place_branch(Is_branchlev(&u.uz), 0, 0);
+           return;
+       }
+
+       lx = 1; hx = COLNO-1;
+       ly = 1; hy = ROWNO-1;
+    }
+
+    /* first a probabilistic approach */
+
+    oneshot = (lx == hx && ly == hy);
+    for (trycnt = 0; trycnt < 200; trycnt++) {
+       x = rn1((hx - lx) + 1, lx);
+       y = rn1((hy - ly) + 1, ly);
+       if (put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev))
+           return;
+    }
+
+    /* then a deterministic one */
+
+    oneshot = TRUE;
+    for (x = lx; x <= hx; x++)
+       for (y = ly; y <= hy; y++)
+           if (put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev))
+               return;
+
+    impossible("Couldn't place lregion type %d!", rtype);
+}
+
+STATIC_OVL boolean
+put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev)
+xchar x, y;
+xchar nlx, nly, nhx, nhy;
+xchar rtype;
+boolean oneshot;
+d_level *lev;
+{
+    if (bad_location(x, y, nlx, nly, nhx, nhy)) {
+       if (!oneshot) {
+           return FALSE;               /* caller should try again */
+       } else {
+           /* Must make do with the only location possible;
+              avoid failure due to a misplaced trap.
+              It might still fail if there's a dungeon feature here. */
+           struct trap *t = t_at(x,y);
+
+           if (t && t->ttyp != MAGIC_PORTAL) deltrap(t);
+           if (bad_location(x, y, nlx, nly, nhx, nhy)) return FALSE;
+       }
+    }
+    switch (rtype) {
+    case LR_TELE:
+    case LR_UPTELE:
+    case LR_DOWNTELE:
+       /* "something" means the player in this case */
+       if(MON_AT(x, y)) {
+           /* move the monster if no choice, or just try again */
+           if(oneshot) (void) rloc(m_at(x,y), FALSE);
+           else return(FALSE);
+       }
+       u_on_newpos(x, y);
+       break;
+    case LR_PORTAL:
+       mkportal(x, y, lev->dnum, lev->dlevel);
+       break;
+    case LR_DOWNSTAIR:
+    case LR_UPSTAIR:
+       mkstairs(x, y, (char)rtype, (struct mkroom *)0);
+       break;
+    case LR_BRANCH:
+       place_branch(Is_branchlev(&u.uz), x, y);
+       break;
+    }
+    return(TRUE);
+}
+
+static boolean was_waterlevel; /* ugh... this shouldn't be needed */
+
+/* this is special stuff that the level compiler cannot (yet) handle */
+STATIC_OVL void
+fixup_special()
+{
+    register lev_region *r = lregions;
+    struct d_level lev;
+    register int x, y;
+    struct mkroom *croom;
+    boolean added_branch = FALSE;
+
+    if (was_waterlevel) {
+       was_waterlevel = FALSE;
+       u.uinwater = 0;
+       unsetup_waterlevel();
+    } else if (Is_waterlevel(&u.uz)) {
+       level.flags.hero_memory = 0;
+       was_waterlevel = TRUE;
+       /* water level is an odd beast - it has to be set up
+          before calling place_lregions etc. */
+       setup_waterlevel();
+    }
+    for(x = 0; x < num_lregions; x++, r++) {
+       switch(r->rtype) {
+       case LR_BRANCH:
+           added_branch = TRUE;
+           goto place_it;
+
+       case LR_PORTAL:
+           if(*r->rname.str >= '0' && *r->rname.str <= '9') {
+               /* "chutes and ladders" */
+               lev = u.uz;
+               lev.dlevel = atoi(r->rname.str);
+           } else {
+               s_level *sp = find_level(r->rname.str);
+               lev = sp->dlevel;
+           }
+           /* fall into... */
+
+       case LR_UPSTAIR:
+       case LR_DOWNSTAIR:
+       place_it:
+           place_lregion(r->inarea.x1, r->inarea.y1,
+                         r->inarea.x2, r->inarea.y2,
+                         r->delarea.x1, r->delarea.y1,
+                         r->delarea.x2, r->delarea.y2,
+                         r->rtype, &lev);
+           break;
+
+       case LR_TELE:
+       case LR_UPTELE:
+       case LR_DOWNTELE:
+           /* save the region outlines for goto_level() */
+           if(r->rtype == LR_TELE || r->rtype == LR_UPTELE) {
+                   updest.lx = r->inarea.x1; updest.ly = r->inarea.y1;
+                   updest.hx = r->inarea.x2; updest.hy = r->inarea.y2;
+                   updest.nlx = r->delarea.x1; updest.nly = r->delarea.y1;
+                   updest.nhx = r->delarea.x2; updest.nhy = r->delarea.y2;
+           }
+           if(r->rtype == LR_TELE || r->rtype == LR_DOWNTELE) {
+                   dndest.lx = r->inarea.x1; dndest.ly = r->inarea.y1;
+                   dndest.hx = r->inarea.x2; dndest.hy = r->inarea.y2;
+                   dndest.nlx = r->delarea.x1; dndest.nly = r->delarea.y1;
+                   dndest.nhx = r->delarea.x2; dndest.nhy = r->delarea.y2;
+           }
+           /* place_lregion gets called from goto_level() */
+           break;
+       }
+
+       if (r->rname.str) free((genericptr_t) r->rname.str),  r->rname.str = 0;
+    }
+
+    /* place dungeon branch if not placed above */
+    if (!added_branch && Is_branchlev(&u.uz)) {
+       place_lregion(0,0,0,0,0,0,0,0,LR_BRANCH,(d_level *)0);
+    }
+
+       /* KMH -- Sokoban levels */
+       if(In_sokoban(&u.uz))
+               sokoban_detect();
+
+    /* Still need to add some stuff to level file */
+    if (Is_medusa_level(&u.uz)) {
+       struct obj *otmp;
+       int tryct;
+
+       croom = &rooms[0]; /* only one room on the medusa level */
+       for (tryct = rnd(4); tryct; tryct--) {
+           x = somex(croom); y = somey(croom);
+           if (goodpos(x, y, (struct monst *)0, 0)) {
+               otmp = mk_tt_object(STATUE, x, y);
+               while (otmp && (poly_when_stoned(&mons[otmp->corpsenm]) ||
+                               pm_resistance(&mons[otmp->corpsenm],MR_STONE))) {
+                   otmp->corpsenm = rndmonnum();
+                   otmp->owt = weight(otmp);
+               }
+           }
+       }
+
+       if (rn2(2))
+           otmp = mk_tt_object(STATUE, somex(croom), somey(croom));
+       else /* Medusa statues don't contain books */
+           otmp = mkcorpstat(STATUE, (struct monst *)0, (struct permonst *)0,
+                             somex(croom), somey(croom), FALSE);
+       if (otmp) {
+           while (pm_resistance(&mons[otmp->corpsenm],MR_STONE)
+                  || poly_when_stoned(&mons[otmp->corpsenm])) {
+               otmp->corpsenm = rndmonnum();
+               otmp->owt = weight(otmp);
+           }
+       }
+    } else if(Is_wiz1_level(&u.uz)) {
+       croom = search_special(MORGUE);
+
+       create_secret_door(croom, W_SOUTH|W_EAST|W_WEST);
+    } else if(Is_knox(&u.uz)) {
+       /* using an unfilled morgue for rm id */
+       croom = search_special(MORGUE);
+       /* avoid inappropriate morgue-related messages */
+       level.flags.graveyard = level.flags.has_morgue = 0;
+       croom->rtype = OROOM;   /* perhaps it should be set to VAULT? */
+       /* stock the main vault */
+       for(x = croom->lx; x <= croom->hx; x++)
+           for(y = croom->ly; y <= croom->hy; y++) {
+               (void) mkgold((long) rn1(300, 600), x, y);
+               if (!rn2(3) && !is_pool(x,y))
+                   (void)maketrap(x, y, rn2(3) ? LANDMINE : SPIKED_PIT);
+           }
+    } else if (Role_if(PM_PRIEST) && In_quest(&u.uz)) {
+       /* less chance for undead corpses (lured from lower morgues) */
+       level.flags.graveyard = 1;
+    } else if (Is_stronghold(&u.uz)) {
+       level.flags.graveyard = 1;
+    } else if(Is_sanctum(&u.uz)) {
+       croom = search_special(TEMPLE);
+
+       create_secret_door(croom, W_ANY);
+    } else if(on_level(&u.uz, &orcus_level)) {
+          register struct monst *mtmp, *mtmp2;
+
+          /* it's a ghost town, get rid of shopkeepers */
+           for(mtmp = fmon; mtmp; mtmp = mtmp2) {
+                   mtmp2 = mtmp->nmon;
+                   if(mtmp->isshk) mongone(mtmp);
+           }
+    }
+
+    if(lev_message) {
+       char *str, *nl;
+       for(str = lev_message; (nl = index(str, '\n')) != 0; str = nl+1) {
+           *nl = '\0';
+           pline("%s", str);
+       }
+       if(*str)
+           pline("%s", str);
+       free((genericptr_t)lev_message);
+       lev_message = 0;
+    }
+
+    if (lregions)
+       free((genericptr_t) lregions),  lregions = 0;
+    num_lregions = 0;
+}
+
+void
+makemaz(s)
+register const char *s;
+{
+       int x,y;
+       char protofile[20];
+       s_level *sp = Is_special(&u.uz);
+       coord mm;
+
+       if(*s) {
+           if(sp && sp->rndlevs) Sprintf(protofile, "%s-%d", s,
+                                               rnd((int) sp->rndlevs));
+           else                 Strcpy(protofile, s);
+       } else if(*(dungeons[u.uz.dnum].proto)) {
+           if(dunlevs_in_dungeon(&u.uz) > 1) {
+               if(sp && sp->rndlevs)
+                    Sprintf(protofile, "%s%d-%d", dungeons[u.uz.dnum].proto,
+                                               dunlev(&u.uz),
+                                               rnd((int) sp->rndlevs));
+               else Sprintf(protofile, "%s%d", dungeons[u.uz.dnum].proto,
+                                               dunlev(&u.uz));
+           } else if(sp && sp->rndlevs) {
+                    Sprintf(protofile, "%s-%d", dungeons[u.uz.dnum].proto,
+                                               rnd((int) sp->rndlevs));
+           } else Strcpy(protofile, dungeons[u.uz.dnum].proto);
+
+       } else Strcpy(protofile, "");
+
+#ifdef WIZARD
+       /* SPLEVTYPE format is "level-choice,level-choice"... */
+       if (wizard && *protofile && sp && sp->rndlevs) {
+           char *ep = getenv("SPLEVTYPE");     /* not nh_getenv */
+           if (ep) {
+               /* rindex always succeeds due to code in prior block */
+               int len = (rindex(protofile, '-') - protofile) + 1;
+
+               while (ep && *ep) {
+                   if (!strncmp(ep, protofile, len)) {
+                       int pick = atoi(ep + len);
+                       /* use choice only if valid */
+                       if (pick > 0 && pick <= (int) sp->rndlevs)
+                           Sprintf(protofile + len, "%d", pick);
+                       break;
+                   } else {
+                       ep = index(ep, ',');
+                       if (ep) ++ep;
+                   }
+               }
+           }
+       }
+#endif
+
+       if(*protofile) {
+           Strcat(protofile, LEV_EXT);
+           if(load_special(protofile)) {
+               fixup_special();
+               /* some levels can end up with monsters
+                  on dead mon list, including light source monsters */
+               dmonsfree();
+               return; /* no mazification right now */
+           }
+           impossible("Couldn't load \"%s\" - making a maze.", protofile);
+       }
+
+       level.flags.is_maze_lev = TRUE;
+
+#ifndef WALLIFIED_MAZE
+       for(x = 2; x < x_maze_max; x++)
+               for(y = 2; y < y_maze_max; y++)
+                       levl[x][y].typ = STONE;
+#else
+       for(x = 2; x <= x_maze_max; x++)
+               for(y = 2; y <= y_maze_max; y++)
+                       levl[x][y].typ = ((x % 2) && (y % 2)) ? STONE : HWALL;
+#endif
+
+       maze0xy(&mm);
+       walkfrom((int) mm.x, (int) mm.y);
+       /* put a boulder at the maze center */
+       (void) mksobj_at(BOULDER, (int) mm.x, (int) mm.y, TRUE, FALSE);
+
+#ifdef WALLIFIED_MAZE
+       wallification(2, 2, x_maze_max, y_maze_max);
+#endif
+       mazexy(&mm);
+       mkstairs(mm.x, mm.y, 1, (struct mkroom *)0);            /* up */
+       if (!Invocation_lev(&u.uz)) {
+           mazexy(&mm);
+           mkstairs(mm.x, mm.y, 0, (struct mkroom *)0);        /* down */
+       } else {        /* choose "vibrating square" location */
+#define x_maze_min 2
+#define y_maze_min 2
+           /*
+            * Pick a position where the stairs down to Moloch's Sanctum
+            * level will ultimately be created.  At that time, an area
+            * will be altered:  walls removed, moat and traps generated,
+            * boulders destroyed.  The position picked here must ensure
+            * that that invocation area won't extend off the map.
+            *
+            * We actually allow up to 2 squares around the usual edge of
+            * the area to get truncated; see mkinvokearea(mklev.c).
+            */
+#define INVPOS_X_MARGIN (6 - 2)
+#define INVPOS_Y_MARGIN (5 - 2)
+#define INVPOS_DISTANCE 11
+           int x_range = x_maze_max - x_maze_min - 2*INVPOS_X_MARGIN - 1,
+               y_range = y_maze_max - y_maze_min - 2*INVPOS_Y_MARGIN - 1;
+
+#ifdef DEBUG
+           if (x_range <= INVPOS_X_MARGIN || y_range <= INVPOS_Y_MARGIN ||
+                  (x_range * y_range) <= (INVPOS_DISTANCE * INVPOS_DISTANCE))
+               panic("inv_pos: maze is too small! (%d x %d)",
+                     x_maze_max, y_maze_max);
+#endif
+           inv_pos.x = inv_pos.y = 0; /*{occupied() => invocation_pos()}*/
+           do {
+               x = rn1(x_range, x_maze_min + INVPOS_X_MARGIN + 1);
+               y = rn1(y_range, y_maze_min + INVPOS_Y_MARGIN + 1);
+               /* we don't want it to be too near the stairs, nor
+                  to be on a spot that's already in use (wall|trap) */
+           } while (x == xupstair || y == yupstair ||  /*(direct line)*/
+                    abs(x - xupstair) == abs(y - yupstair) ||
+                    distmin(x, y, xupstair, yupstair) <= INVPOS_DISTANCE ||
+                    !SPACE_POS(levl[x][y].typ) || occupied(x, y));
+           inv_pos.x = x;
+           inv_pos.y = y;
+#undef INVPOS_X_MARGIN
+#undef INVPOS_Y_MARGIN
+#undef INVPOS_DISTANCE
+#undef x_maze_min
+#undef y_maze_min
+       }
+
+       /* place branch stair or portal */
+       place_branch(Is_branchlev(&u.uz), 0, 0);
+
+       for(x = rn1(8,11); x; x--) {
+               mazexy(&mm);
+               (void) mkobj_at(rn2(2) ? GEM_CLASS : 0, mm.x, mm.y, TRUE);
+       }
+       for(x = rn1(10,2); x; x--) {
+               mazexy(&mm);
+               (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE);
+       }
+       for (x = rn2(3); x; x--) {
+               mazexy(&mm);
+               (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS);
+       }
+       for(x = rn1(5,7); x; x--) {
+               mazexy(&mm);
+               (void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS);
+       }
+       for(x = rn1(6,7); x; x--) {
+               mazexy(&mm);
+               (void) mkgold(0L,mm.x,mm.y);
+       }
+       for(x = rn1(6,7); x; x--)
+               mktrap(0,1,(struct mkroom *) 0, (coord*) 0);
+}
+
+#ifdef MICRO
+/* Make the mazewalk iterative by faking a stack.  This is needed to
+ * ensure the mazewalk is successful in the limited stack space of
+ * the program.  This iterative version uses the minimum amount of stack
+ * that is totally safe.
+ */
+void
+walkfrom(x,y)
+int x,y;
+{
+#define CELLS (ROWNO * COLNO) / 4              /* a maze cell is 4 squares */
+       char mazex[CELLS + 1], mazey[CELLS + 1];        /* char's are OK */
+       int q, a, dir, pos;
+       int dirs[4];
+
+       pos = 1;
+       mazex[pos] = (char) x;
+       mazey[pos] = (char) y;
+       while (pos) {
+               x = (int) mazex[pos];
+               y = (int) mazey[pos];
+               if(!IS_DOOR(levl[x][y].typ)) {
+                   /* might still be on edge of MAP, so don't overwrite */
+#ifndef WALLIFIED_MAZE
+                   levl[x][y].typ = CORR;
+#else
+                   levl[x][y].typ = ROOM;
+#endif
+                   levl[x][y].flags = 0;
+               }
+               q = 0;
+               for (a = 0; a < 4; a++)
+                       if(okay(x, y, a)) dirs[q++]= a;
+               if (!q)
+                       pos--;
+               else {
+                       dir = dirs[rn2(q)];
+                       move(&x, &y, dir);
+#ifndef WALLIFIED_MAZE
+                       levl[x][y].typ = CORR;
+#else
+                       levl[x][y].typ = ROOM;
+#endif
+                       move(&x, &y, dir);
+                       pos++;
+                       if (pos > CELLS)
+                               panic("Overflow in walkfrom");
+                       mazex[pos] = (char) x;
+                       mazey[pos] = (char) y;
+               }
+       }
+}
+#else
+
+void
+walkfrom(x,y)
+int x,y;
+{
+       register int q,a,dir;
+       int dirs[4];
+
+       if(!IS_DOOR(levl[x][y].typ)) {
+           /* might still be on edge of MAP, so don't overwrite */
+#ifndef WALLIFIED_MAZE
+           levl[x][y].typ = CORR;
+#else
+           levl[x][y].typ = ROOM;
+#endif
+           levl[x][y].flags = 0;
+       }
+
+       while(1) {
+               q = 0;
+               for(a = 0; a < 4; a++)
+                       if(okay(x,y,a)) dirs[q++]= a;
+               if(!q) return;
+               dir = dirs[rn2(q)];
+               move(&x,&y,dir);
+#ifndef WALLIFIED_MAZE
+               levl[x][y].typ = CORR;
+#else
+               levl[x][y].typ = ROOM;
+#endif
+               move(&x,&y,dir);
+               walkfrom(x,y);
+       }
+}
+#endif /* MICRO */
+
+STATIC_OVL void
+move(x,y,dir)
+register int *x, *y;
+register int dir;
+{
+       switch(dir){
+               case 0: --(*y); break;
+               case 1: (*x)++; break;
+               case 2: (*y)++; break;
+               case 3: --(*x); break;
+               default: panic("move: bad direction");
+       }
+}
+
+void
+mazexy(cc)     /* find random point in generated corridors,
+                  so we don't create items in moats, bunkers, or walls */
+       coord   *cc;
+{
+       int cpt=0;
+
+       do {
+           cc->x = 3 + 2*rn2((x_maze_max>>1) - 1);
+           cc->y = 3 + 2*rn2((y_maze_max>>1) - 1);
+           cpt++;
+       } while (cpt < 100 && levl[cc->x][cc->y].typ !=
+#ifdef WALLIFIED_MAZE
+                ROOM
+#else
+                CORR
+#endif
+               );
+       if (cpt >= 100) {
+               register int x, y;
+               /* last try */
+               for (x = 0; x < (x_maze_max>>1) - 1; x++)
+                   for (y = 0; y < (y_maze_max>>1) - 1; y++) {
+                       cc->x = 3 + 2 * x;
+                       cc->y = 3 + 2 * y;
+                       if (levl[cc->x][cc->y].typ ==
+#ifdef WALLIFIED_MAZE
+                           ROOM
+#else
+                           CORR
+#endif
+                          ) return;
+                   }
+               panic("mazexy: can't find a place!");
+       }
+       return;
+}
+
+void
+bound_digging()
+/* put a non-diggable boundary around the initial portion of a level map.
+ * assumes that no level will initially put things beyond the isok() range.
+ *
+ * we can't bound unconditionally on the last line with something in it,
+ * because that something might be a niche which was already reachable,
+ * so the boundary would be breached
+ *
+ * we can't bound unconditionally on one beyond the last line, because
+ * that provides a window of abuse for WALLIFIED_MAZE special levels
+ */
+{
+       register int x,y;
+       register unsigned typ;
+       register struct rm *lev;
+       boolean found, nonwall;
+       int xmin,xmax,ymin,ymax;
+
+       if(Is_earthlevel(&u.uz)) return; /* everything diggable here */
+
+       found = nonwall = FALSE;
+       for(xmin=0; !found; xmin++) {
+               lev = &levl[xmin][0];
+               for(y=0; y<=ROWNO-1; y++, lev++) {
+                       typ = lev->typ;
+                       if(typ != STONE) {
+                               found = TRUE;
+                               if(!IS_WALL(typ)) nonwall = TRUE;
+                       }
+               }
+       }
+       xmin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
+       if (xmin < 0) xmin = 0;
+
+       found = nonwall = FALSE;
+       for(xmax=COLNO-1; !found; xmax--) {
+               lev = &levl[xmax][0];
+               for(y=0; y<=ROWNO-1; y++, lev++) {
+                       typ = lev->typ;
+                       if(typ != STONE) {
+                               found = TRUE;
+                               if(!IS_WALL(typ)) nonwall = TRUE;
+                       }
+               }
+       }
+       xmax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
+       if (xmax >= COLNO) xmax = COLNO-1;
+
+       found = nonwall = FALSE;
+       for(ymin=0; !found; ymin++) {
+               lev = &levl[xmin][ymin];
+               for(x=xmin; x<=xmax; x++, lev += ROWNO) {
+                       typ = lev->typ;
+                       if(typ != STONE) {
+                               found = TRUE;
+                               if(!IS_WALL(typ)) nonwall = TRUE;
+                       }
+               }
+       }
+       ymin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
+
+       found = nonwall = FALSE;
+       for(ymax=ROWNO-1; !found; ymax--) {
+               lev = &levl[xmin][ymax];
+               for(x=xmin; x<=xmax; x++, lev += ROWNO) {
+                       typ = lev->typ;
+                       if(typ != STONE) {
+                               found = TRUE;
+                               if(!IS_WALL(typ)) nonwall = TRUE;
+                       }
+               }
+       }
+       ymax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
+
+       for (x = 0; x < COLNO; x++)
+         for (y = 0; y < ROWNO; y++)
+           if (y <= ymin || y >= ymax || x <= xmin || x >= xmax) {
+#ifdef DCC30_BUG
+               lev = &levl[x][y];
+               lev->wall_info |= W_NONDIGGABLE;
+#else
+               levl[x][y].wall_info |= W_NONDIGGABLE;
+#endif
+           }
+}
+
+void
+mkportal(x, y, todnum, todlevel)
+register xchar x, y, todnum, todlevel;
+{
+       /* a portal "trap" must be matched by a */
+       /* portal in the destination dungeon/dlevel */
+       register struct trap *ttmp = maketrap(x, y, MAGIC_PORTAL);
+
+       if (!ttmp) {
+               impossible("portal on top of portal??");
+               return;
+       }
+#ifdef DEBUG
+       pline("mkportal: at (%d,%d), to %s, level %d",
+               x, y, dungeons[todnum].dname, todlevel);
+#endif
+       ttmp->dst.dnum = todnum;
+       ttmp->dst.dlevel = todlevel;
+       return;
+}
+
+/*
+ * Special waterlevel stuff in endgame (TH).
+ *
+ * Some of these functions would probably logically belong to some
+ * other source files, but they are all so nicely encapsulated here.
+ */
+
+/* to ease the work of debuggers at this stage */
+#define register
+
+#define CONS_OBJ   0
+#define CONS_MON   1
+#define CONS_HERO  2
+#define CONS_TRAP  3
+
+static struct bubble *bbubbles, *ebubbles;
+
+static struct trap *wportal;
+static int xmin, ymin, xmax, ymax;     /* level boundaries */
+/* bubble movement boundaries */
+#define bxmin (xmin + 1)
+#define bymin (ymin + 1)
+#define bxmax (xmax - 1)
+#define bymax (ymax - 1)
+
+STATIC_DCL void NDECL(set_wportal);
+STATIC_DCL void FDECL(mk_bubble, (int,int,int));
+STATIC_DCL void FDECL(mv_bubble, (struct bubble *,int,int,BOOLEAN_P));
+
+void
+movebubbles()
+{
+       static boolean up;
+       register struct bubble *b;
+       register int x, y, i, j;
+       struct trap *btrap;
+       static const struct rm water_pos =
+               { cmap_to_glyph(S_water), WATER, 0, 0, 0, 0, 0, 0, 0 };
+
+       /* set up the portal the first time bubbles are moved */
+       if (!wportal) set_wportal();
+
+       vision_recalc(2);
+       /* keep attached ball&chain separate from bubble objects */
+       if (Punished) unplacebc();
+
+       /*
+        * Pick up everything inside of a bubble then fill all bubble
+        * locations.
+        */
+
+       for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) {
+           if (b->cons) panic("movebubbles: cons != null");
+           for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++)
+               for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++)
+                   if (b->bm[j + 2] & (1 << i)) {
+                       if (!isok(x,y)) {
+                           impossible("movebubbles: bad pos (%d,%d)", x,y);
+                           continue;
+                       }
+
+                       /* pick up objects, monsters, hero, and traps */
+                       if (OBJ_AT(x,y)) {
+                           struct obj *olist = (struct obj *) 0, *otmp;
+                           struct container *cons = (struct container *)
+                               alloc(sizeof(struct container));
+
+                           while ((otmp = level.objects[x][y]) != 0) {
+                               remove_object(otmp);
+                               otmp->ox = otmp->oy = 0;
+                               otmp->nexthere = olist;
+                               olist = otmp;
+                           }
+
+                           cons->x = x;
+                           cons->y = y;
+                           cons->what = CONS_OBJ;
+                           cons->list = (genericptr_t) olist;
+                           cons->next = b->cons;
+                           b->cons = cons;
+                       }
+                       if (MON_AT(x,y)) {
+                           struct monst *mon = m_at(x,y);
+                           struct container *cons = (struct container *)
+                               alloc(sizeof(struct container));
+
+                           cons->x = x;
+                           cons->y = y;
+                           cons->what = CONS_MON;
+                           cons->list = (genericptr_t) mon;
+
+                           cons->next = b->cons;
+                           b->cons = cons;
+
+                           if(mon->wormno)
+                               remove_worm(mon);
+                           else
+                               remove_monster(x, y);
+
+                           newsym(x,y);        /* clean up old position */
+                           mon->mx = mon->my = 0;
+                       }
+                       if (!u.uswallow && x == u.ux && y == u.uy) {
+                           struct container *cons = (struct container *)
+                               alloc(sizeof(struct container));
+
+                           cons->x = x;
+                           cons->y = y;
+                           cons->what = CONS_HERO;
+                           cons->list = (genericptr_t) 0;
+
+                           cons->next = b->cons;
+                           b->cons = cons;
+                       }
+                       if ((btrap = t_at(x,y)) != 0) {
+                           struct container *cons = (struct container *)
+                               alloc(sizeof(struct container));
+
+                           cons->x = x;
+                           cons->y = y;
+                           cons->what = CONS_TRAP;
+                           cons->list = (genericptr_t) btrap;
+
+                           cons->next = b->cons;
+                           b->cons = cons;
+                       }
+
+                       levl[x][y] = water_pos;
+                       block_point(x,y);
+                   }
+       }
+
+       /*
+        * Every second time traverse down.  This is because otherwise
+        * all the junk that changes owners when bubbles overlap
+        * would eventually end up in the last bubble in the chain.
+        */
+
+       up = !up;
+       for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) {
+               register int rx = rn2(3), ry = rn2(3);
+
+               mv_bubble(b,b->dx + 1 - (!b->dx ? rx : (rx ? 1 : 0)),
+                           b->dy + 1 - (!b->dy ? ry : (ry ? 1 : 0)),
+                           FALSE);
+       }
+
+       /* put attached ball&chain back */
+       if (Punished) placebc();
+       vision_full_recalc = 1;
+}
+
+/* when moving in water, possibly (1 in 3) alter the intended destination */
+void
+water_friction()
+{
+       register int x, y, dx, dy;
+       register boolean eff = FALSE;
+
+       if (Swimming && rn2(4))
+               return;         /* natural swimmers have advantage */
+
+       if (u.dx && !rn2(!u.dy ? 3 : 6)) {      /* 1/3 chance or half that */
+               /* cancel delta x and choose an arbitrary delta y value */
+               x = u.ux;
+               do {
+                   dy = rn2(3) - 1;            /* -1, 0, 1 */
+                   y = u.uy + dy;
+               } while (dy && (!isok(x,y) || !is_pool(x,y)));
+               u.dx = 0;
+               u.dy = dy;
+               eff = TRUE;
+       } else if (u.dy && !rn2(!u.dx ? 3 : 5)) {       /* 1/3 or 1/5*(5/6) */
+               /* cancel delta y and choose an arbitrary delta x value */
+               y = u.uy;
+               do {
+                   dx = rn2(3) - 1;            /* -1 .. 1 */
+                   x = u.ux + dx;
+               } while (dx && (!isok(x,y) || !is_pool(x,y)));
+               u.dy = 0;
+               u.dx = dx;
+               eff = TRUE;
+       }
+       if (eff) pline("Water turbulence affects your movements.");
+}
+
+void
+save_waterlevel(fd, mode)
+int fd, mode;
+{
+       register struct bubble *b;
+
+       if (!Is_waterlevel(&u.uz)) return;
+
+       if (perform_bwrite(mode)) {
+           int n = 0;
+           for (b = bbubbles; b; b = b->next) ++n;
+           bwrite(fd, (genericptr_t)&n, sizeof (int));
+           bwrite(fd, (genericptr_t)&xmin, sizeof (int));
+           bwrite(fd, (genericptr_t)&ymin, sizeof (int));
+           bwrite(fd, (genericptr_t)&xmax, sizeof (int));
+           bwrite(fd, (genericptr_t)&ymax, sizeof (int));
+           for (b = bbubbles; b; b = b->next)
+               bwrite(fd, (genericptr_t)b, sizeof (struct bubble));
+       }
+       if (release_data(mode))
+           unsetup_waterlevel();
+}
+
+void
+restore_waterlevel(fd)
+register int fd;
+{
+       register struct bubble *b = (struct bubble *)0, *btmp;
+       register int i;
+       int n;
+
+       if (!Is_waterlevel(&u.uz)) return;
+
+       set_wportal();
+       mread(fd,(genericptr_t)&n,sizeof(int));
+       mread(fd,(genericptr_t)&xmin,sizeof(int));
+       mread(fd,(genericptr_t)&ymin,sizeof(int));
+       mread(fd,(genericptr_t)&xmax,sizeof(int));
+       mread(fd,(genericptr_t)&ymax,sizeof(int));
+       for (i = 0; i < n; i++) {
+               btmp = b;
+               b = (struct bubble *)alloc(sizeof(struct bubble));
+               mread(fd,(genericptr_t)b,sizeof(struct bubble));
+               if (bbubbles) {
+                       btmp->next = b;
+                       b->prev = btmp;
+               } else {
+                       bbubbles = b;
+                       b->prev = (struct bubble *)0;
+               }
+               mv_bubble(b,0,0,TRUE);
+       }
+       ebubbles = b;
+       b->next = (struct bubble *)0;
+       was_waterlevel = TRUE;
+}
+
+const char *waterbody_name(x, y)
+xchar x,y;
+{
+       register struct rm *lev;
+       schar ltyp;
+
+       if (!isok(x,y))
+               return "drink";         /* should never happen */
+       lev = &levl[x][y];
+       ltyp = lev->typ;
+
+       if (is_lava(x,y))
+               return "lava";
+       else if (ltyp == ICE ||
+                (ltyp == DRAWBRIDGE_UP &&
+                 (levl[x][y].drawbridgemask & DB_UNDER) == DB_ICE))
+               return "ice";
+       else if (((ltyp != POOL) && (ltyp != WATER) &&
+         !Is_medusa_level(&u.uz) && !Is_waterlevel(&u.uz) && !Is_juiblex_level(&u.uz)) ||
+          (ltyp == DRAWBRIDGE_UP && (levl[x][y].drawbridgemask & DB_UNDER) == DB_MOAT))
+               return "moat";
+       else if ((ltyp != POOL) && (ltyp != WATER) && Is_juiblex_level(&u.uz))
+               return "swamp";
+       else if (ltyp == POOL)
+               return "pool of water";
+       else return "water";
+}
+
+STATIC_OVL void
+set_wportal()
+{
+       /* there better be only one magic portal on water level... */
+       for (wportal = ftrap; wportal; wportal = wportal->ntrap)
+               if (wportal->ttyp == MAGIC_PORTAL) return;
+       impossible("set_wportal(): no portal!");
+}
+
+STATIC_OVL void
+setup_waterlevel()
+{
+       register int x, y;
+       register int xskip, yskip;
+       register int water_glyph = cmap_to_glyph(S_water);
+
+       /* ouch, hardcoded... */
+
+       xmin = 3;
+       ymin = 1;
+       xmax = 78;
+       ymax = 20;
+
+       /* set hero's memory to water */
+
+       for (x = xmin; x <= xmax; x++)
+               for (y = ymin; y <= ymax; y++)
+                       levl[x][y].glyph = water_glyph;
+
+       /* make bubbles */
+
+       xskip = 10 + rn2(10);
+       yskip = 4 + rn2(4);
+       for (x = bxmin; x <= bxmax; x += xskip)
+               for (y = bymin; y <= bymax; y += yskip)
+                       mk_bubble(x,y,rn2(7));
+}
+
+STATIC_OVL void
+unsetup_waterlevel()
+{
+       register struct bubble *b, *bb;
+
+       /* free bubbles */
+
+       for (b = bbubbles; b; b = bb) {
+               bb = b->next;
+               free((genericptr_t)b);
+       }
+       bbubbles = ebubbles = (struct bubble *)0;
+}
+
+STATIC_OVL void
+mk_bubble(x,y,n)
+register int x, y, n;
+{
+       /*
+        * These bit masks make visually pleasing bubbles on a normal aspect
+        * 25x80 terminal, which naturally results in them being mathematically
+        * anything but symmetric.  For this reason they cannot be computed
+        * in situ, either.  The first two elements tell the dimensions of
+        * the bubble's bounding box.
+        */
+       static uchar
+               bm2[] = {2,1,0x3},
+               bm3[] = {3,2,0x7,0x7},
+               bm4[] = {4,3,0x6,0xf,0x6},
+               bm5[] = {5,3,0xe,0x1f,0xe},
+               bm6[] = {6,4,0x1e,0x3f,0x3f,0x1e},
+               bm7[] = {7,4,0x3e,0x7f,0x7f,0x3e},
+               bm8[] = {8,4,0x7e,0xff,0xff,0x7e},
+               *bmask[] = {bm2,bm3,bm4,bm5,bm6,bm7,bm8};
+
+       register struct bubble *b;
+
+       if (x >= bxmax || y >= bymax) return;
+       if (n >= SIZE(bmask)) {
+               impossible("n too large (mk_bubble)");
+               n = SIZE(bmask) - 1;
+       }
+       b = (struct bubble *)alloc(sizeof(struct bubble));
+       if ((x + (int) bmask[n][0] - 1) > bxmax) x = bxmax - bmask[n][0] + 1;
+       if ((y + (int) bmask[n][1] - 1) > bymax) y = bymax - bmask[n][1] + 1;
+       b->x = x;
+       b->y = y;
+       b->dx = 1 - rn2(3);
+       b->dy = 1 - rn2(3);
+       b->bm = bmask[n];
+       b->cons = 0;
+       if (!bbubbles) bbubbles = b;
+       if (ebubbles) {
+               ebubbles->next = b;
+               b->prev = ebubbles;
+       }
+       else
+               b->prev = (struct bubble *)0;
+       b->next =  (struct bubble *)0;
+       ebubbles = b;
+       mv_bubble(b,0,0,TRUE);
+}
+
+/*
+ * The player, the portal and all other objects and monsters
+ * float along with their associated bubbles.  Bubbles may overlap
+ * freely, and the contents may get associated with other bubbles in
+ * the process.  Bubbles are "sticky", meaning that if the player is
+ * in the immediate neighborhood of one, he/she may get sucked inside.
+ * This property also makes leaving a bubble slightly difficult.
+ */
+STATIC_OVL void
+mv_bubble(b,dx,dy,ini)
+register struct bubble *b;
+register int dx, dy;
+register boolean ini;
+{
+       register int x, y, i, j, colli = 0;
+       struct container *cons, *ctemp;
+
+       /* move bubble */
+       if (dx < -1 || dx > 1 || dy < -1 || dy > 1) {
+           /* pline("mv_bubble: dx = %d, dy = %d", dx, dy); */
+           dx = sgn(dx);
+           dy = sgn(dy);
+       }
+
+       /*
+        * collision with level borders?
+        *      1 = horizontal border, 2 = vertical, 3 = corner
+        */
+       if (b->x <= bxmin) colli |= 2;
+       if (b->y <= bymin) colli |= 1;
+       if ((int) (b->x + b->bm[0] - 1) >= bxmax) colli |= 2;
+       if ((int) (b->y + b->bm[1] - 1) >= bymax) colli |= 1;
+
+       if (b->x < bxmin) {
+           pline("bubble xmin: x = %d, xmin = %d", b->x, bxmin);
+           b->x = bxmin;
+       }
+       if (b->y < bymin) {
+           pline("bubble ymin: y = %d, ymin = %d", b->y, bymin);
+           b->y = bymin;
+       }
+       if ((int) (b->x + b->bm[0] - 1) > bxmax) {
+           pline("bubble xmax: x = %d, xmax = %d",
+                       b->x + b->bm[0] - 1, bxmax);
+           b->x = bxmax - b->bm[0] + 1;
+       }
+       if ((int) (b->y + b->bm[1] - 1) > bymax) {
+           pline("bubble ymax: y = %d, ymax = %d",
+                       b->y + b->bm[1] - 1, bymax);
+           b->y = bymax - b->bm[1] + 1;
+       }
+
+       /* bounce if we're trying to move off the border */
+       if (b->x == bxmin && dx < 0) dx = -dx;
+       if (b->x + b->bm[0] - 1 == bxmax && dx > 0) dx = -dx;
+       if (b->y == bymin && dy < 0) dy = -dy;
+       if (b->y + b->bm[1] - 1 == bymax && dy > 0) dy = -dy;
+
+       b->x += dx;
+       b->y += dy;
+
+       /* void positions inside bubble */
+
+       for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++)
+           for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++)
+               if (b->bm[j + 2] & (1 << i)) {
+                   levl[x][y].typ = AIR;
+                   levl[x][y].lit = 1;
+                   unblock_point(x,y);
+               }
+
+       /* replace contents of bubble */
+       for (cons = b->cons; cons; cons = ctemp) {
+           ctemp = cons->next;
+           cons->x += dx;
+           cons->y += dy;
+
+           switch(cons->what) {
+               case CONS_OBJ: {
+                   struct obj *olist, *otmp;
+
+                   for (olist=(struct obj *)cons->list; olist; olist=otmp) {
+                       otmp = olist->nexthere;
+                       place_object(olist, cons->x, cons->y);
+                   }
+                   break;
+               }
+
+               case CONS_MON: {
+                   struct monst *mon = (struct monst *) cons->list;
+                   (void) mnearto(mon, cons->x, cons->y, TRUE);
+                   break;
+               }
+
+               case CONS_HERO: {
+                   int ux0 = u.ux, uy0 = u.uy;
+
+                   /* change u.ux0 and u.uy0? */
+                   u.ux = cons->x;
+                   u.uy = cons->y;
+                   newsym(ux0, uy0);   /* clean up old position */
+
+                   if (MON_AT(cons->x, cons->y)) {
+                               mnexto(m_at(cons->x,cons->y));
+                       }
+                   break;
+               }
+
+               case CONS_TRAP: {
+                   struct trap *btrap = (struct trap *) cons->list;
+                   btrap->tx = cons->x;
+                   btrap->ty = cons->y;
+                   break;
+               }
+
+               default:
+                   impossible("mv_bubble: unknown bubble contents");
+                   break;
+           }
+           free((genericptr_t)cons);
+       }
+       b->cons = 0;
+
+       /* boing? */
+
+       switch (colli) {
+           case 1: b->dy = -b->dy;     break;
+           case 3: b->dy = -b->dy;     /* fall through */
+           case 2: b->dx = -b->dx;     break;
+           default:
+               /* sometimes alter direction for fun anyway
+                  (higher probability for stationary bubbles) */
+               if (!ini && ((b->dx || b->dy) ? !rn2(20) : !rn2(5))) {
+                       b->dx = 1 - rn2(3);
+                       b->dy = 1 - rn2(3);
+               }
+       }
+}
+
+/*mkmaze.c*/
diff --git a/src/mkobj.c b/src/mkobj.c
new file mode 100644 (file)
index 0000000..3db4c0b
--- /dev/null
@@ -0,0 +1,1639 @@
+/*     SCCS Id: @(#)mkobj.c    3.4     2002/10/07      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "prop.h"
+
+STATIC_DCL void FDECL(mkbox_cnts,(struct obj *));
+STATIC_DCL void FDECL(obj_timer_checks,(struct obj *, XCHAR_P, XCHAR_P, int));
+#ifdef OVL1
+STATIC_DCL void FDECL(container_weight, (struct obj *));
+STATIC_DCL struct obj *FDECL(save_mtraits, (struct obj *, struct monst *));
+#ifdef WIZARD
+STATIC_DCL const char *FDECL(where_name, (int));
+STATIC_DCL void FDECL(check_contained, (struct obj *,const char *));
+#endif
+#endif /* OVL1 */
+
+extern struct obj *thrownobj;          /* defined in dothrow.c */
+
+/*#define DEBUG_EFFECTS*/      /* show some messages for debugging */
+
+struct icp {
+    int  iprob;                /* probability of an item type */
+    char iclass;       /* item class */
+};
+
+#ifdef OVL1
+
+const struct icp mkobjprobs[] = {
+{10, WEAPON_CLASS},
+{10, ARMOR_CLASS},
+{20, FOOD_CLASS},
+{ 8, TOOL_CLASS},
+{ 8, GEM_CLASS},
+{16, POTION_CLASS},
+{16, SCROLL_CLASS},
+{ 4, SPBOOK_CLASS},
+{ 4, WAND_CLASS},
+{ 3, RING_CLASS},
+{ 1, AMULET_CLASS}
+};
+
+const struct icp boxiprobs[] = {
+{18, GEM_CLASS},
+{15, FOOD_CLASS},
+{18, POTION_CLASS},
+{18, SCROLL_CLASS},
+{12, SPBOOK_CLASS},
+{ 7, COIN_CLASS},
+{ 6, WAND_CLASS},
+{ 5, RING_CLASS},
+{ 1, AMULET_CLASS}
+};
+
+#ifdef REINCARNATION
+const struct icp rogueprobs[] = {
+{12, WEAPON_CLASS},
+{12, ARMOR_CLASS},
+{22, FOOD_CLASS},
+{22, POTION_CLASS},
+{22, SCROLL_CLASS},
+{ 5, WAND_CLASS},
+{ 5, RING_CLASS}
+};
+#endif
+
+const struct icp hellprobs[] = {
+{20, WEAPON_CLASS},
+{20, ARMOR_CLASS},
+{16, FOOD_CLASS},
+{12, TOOL_CLASS},
+{10, GEM_CLASS},
+{ 1, POTION_CLASS},
+{ 1, SCROLL_CLASS},
+{ 8, WAND_CLASS},
+{ 8, RING_CLASS},
+{ 4, AMULET_CLASS}
+};
+
+struct obj *
+mkobj_at(let, x, y, artif)
+char let;
+int x, y;
+boolean artif;
+{
+       struct obj *otmp;
+
+       otmp = mkobj(let, artif);
+       place_object(otmp, x, y);
+       return(otmp);
+}
+
+struct obj *
+mksobj_at(otyp, x, y, init, artif)
+int otyp, x, y;
+boolean init, artif;
+{
+       struct obj *otmp;
+
+       otmp = mksobj(otyp, init, artif);
+       place_object(otmp, x, y);
+       return(otmp);
+}
+
+struct obj *
+mkobj(oclass, artif)
+char oclass;
+boolean artif;
+{
+       int tprob, i, prob = rnd(1000);
+
+       if(oclass == RANDOM_CLASS) {
+               const struct icp *iprobs =
+#ifdef REINCARNATION
+                                   (Is_rogue_level(&u.uz)) ?
+                                   (const struct icp *)rogueprobs :
+#endif
+                                   Inhell ? (const struct icp *)hellprobs :
+                                   (const struct icp *)mkobjprobs;
+
+               for(tprob = rnd(100);
+                   (tprob -= iprobs->iprob) > 0;
+                   iprobs++);
+               oclass = iprobs->iclass;
+       }
+
+       i = bases[(int)oclass];
+       while((prob -= objects[i].oc_prob) > 0) i++;
+
+       if(objects[i].oc_class != oclass || !OBJ_NAME(objects[i]))
+               panic("probtype error, oclass=%d i=%d", (int) oclass, i);
+
+       return(mksobj(i, TRUE, artif));
+}
+
+STATIC_OVL void
+mkbox_cnts(box)
+struct obj *box;
+{
+       register int n;
+       register struct obj *otmp;
+
+       box->cobj = (struct obj *) 0;
+
+       switch (box->otyp) {
+       case ICE_BOX:           n = 20; break;
+       case CHEST:             n = 5; break;
+       case LARGE_BOX:         n = 3; break;
+       case SACK:
+       case OILSKIN_SACK:
+                               /* initial inventory: sack starts out empty */
+                               if (moves <= 1 && !in_mklev) { n = 0; break; }
+                               /*else FALLTHRU*/
+       case BAG_OF_HOLDING:    n = 1; break;
+       default:                n = 0; break;
+       }
+
+       for (n = rn2(n+1); n > 0; n--) {
+           if (box->otyp == ICE_BOX) {
+               if (!(otmp = mksobj(CORPSE, TRUE, TRUE))) continue;
+               /* Note: setting age to 0 is correct.  Age has a different
+                * from usual meaning for objects stored in ice boxes. -KAA
+                */
+               otmp->age = 0L;
+               if (otmp->timed) {
+                   (void) stop_timer(ROT_CORPSE, (genericptr_t)otmp);
+                   (void) stop_timer(REVIVE_MON, (genericptr_t)otmp);
+               }
+           } else {
+               register int tprob;
+               const struct icp *iprobs = boxiprobs;
+
+               for (tprob = rnd(100); (tprob -= iprobs->iprob) > 0; iprobs++)
+                   ;
+               if (!(otmp = mkobj(iprobs->iclass, TRUE))) continue;
+
+               /* handle a couple of special cases */
+               if (otmp->oclass == COIN_CLASS) {
+                   /* 2.5 x level's usual amount; weight adjusted below */
+                   otmp->quan = (long)(rnd(level_difficulty()+2) * rnd(75));
+                   otmp->owt = weight(otmp);
+               } else while (otmp->otyp == ROCK) {
+                   otmp->otyp = rnd_class(DILITHIUM_CRYSTAL, LOADSTONE);
+                   if (otmp->quan > 2L) otmp->quan = 1L;
+                   otmp->owt = weight(otmp);
+               }
+               if (box->otyp == BAG_OF_HOLDING) {
+                   if (Is_mbag(otmp)) {
+                       otmp->otyp = SACK;
+                       otmp->spe = 0;
+                       otmp->owt = weight(otmp);
+                   } else while (otmp->otyp == WAN_CANCELLATION)
+                           otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING);
+               }
+           }
+           (void) add_to_container(box, otmp);
+       }
+}
+
+int
+rndmonnum()    /* select a random, common monster type */
+{
+       register struct permonst *ptr;
+       register int    i;
+
+       /* Plan A: get a level-appropriate common monster */
+       ptr = rndmonst();
+       if (ptr) return(monsndx(ptr));
+
+       /* Plan B: get any common monster */
+       do {
+           i = rn1(SPECIAL_PM - LOW_PM, LOW_PM);
+           ptr = &mons[i];
+       } while((ptr->geno & G_NOGEN) || (!Inhell && (ptr->geno & G_HELL)));
+
+       return(i);
+}
+
+/*
+ * Split obj so that it gets size gets reduced by num. The quantity num is
+ * put in the object structure delivered by this call.  The returned object
+ * has its wornmask cleared and is positioned just following the original
+ * in the nobj chain (and nexthere chain when on the floor).
+ */
+struct obj *
+splitobj(obj, num)
+struct obj *obj;
+long num;
+{
+       struct obj *otmp;
+
+       if (obj->cobj || num <= 0L || obj->quan <= num)
+           panic("splitobj");  /* can't split containers */
+       otmp = newobj(obj->oxlth + obj->onamelth);
+       *otmp = *obj;           /* copies whole structure */
+       otmp->o_id = flags.ident++;
+       if (!otmp->o_id) otmp->o_id = flags.ident++;    /* ident overflowed */
+       otmp->timed = 0;        /* not timed, yet */
+       otmp->lamplit = 0;      /* ditto */
+       otmp->owornmask = 0L;   /* new object isn't worn */
+       obj->quan -= num;
+       obj->owt = weight(obj);
+       otmp->quan = num;
+       otmp->owt = weight(otmp);       /* -= obj->owt ? */
+       obj->nobj = otmp;
+       /* Only set nexthere when on the floor, nexthere is also used */
+       /* as a back pointer to the container object when contained. */
+       if (obj->where == OBJ_FLOOR)
+           obj->nexthere = otmp;
+       if (obj->oxlth)
+           (void)memcpy((genericptr_t)otmp->oextra, (genericptr_t)obj->oextra,
+                       obj->oxlth);
+       if (obj->onamelth)
+           (void)strncpy(ONAME(otmp), ONAME(obj), (int)obj->onamelth);
+       if (obj->unpaid) splitbill(obj,otmp);
+       if (obj->timed) obj_split_timers(obj, otmp);
+       if (obj_sheds_light(obj)) obj_split_light_source(obj, otmp);
+       return otmp;
+}
+
+/*
+ * Insert otmp right after obj in whatever chain(s) it is on.  Then extract
+ * obj from the chain(s).  This function does a literal swap.  It is up to
+ * the caller to provide a valid context for the swap.  When done, obj will
+ * still exist, but not on any chain.
+ *
+ * Note:  Don't use use obj_extract_self() -- we are doing an in-place swap,
+ * not actually moving something.
+ */
+void
+replace_object(obj, otmp)
+struct obj *obj;
+struct obj *otmp;
+{
+    otmp->where = obj->where;
+    switch (obj->where) {
+    case OBJ_FREE:
+       /* do nothing */
+       break;
+    case OBJ_INVENT:
+       otmp->nobj = obj->nobj;
+       obj->nobj = otmp;
+       extract_nobj(obj, &invent);
+       break;
+    case OBJ_CONTAINED:
+       otmp->nobj = obj->nobj;
+       otmp->ocontainer = obj->ocontainer;
+       obj->nobj = otmp;
+       extract_nobj(obj, &obj->ocontainer->cobj);
+       break;
+    case OBJ_MINVENT:
+       otmp->nobj = obj->nobj;
+       otmp->ocarry =  obj->ocarry;
+       obj->nobj = otmp;
+       extract_nobj(obj, &obj->ocarry->minvent);
+       break;
+    case OBJ_FLOOR:
+       otmp->nobj = obj->nobj;
+       otmp->nexthere = obj->nexthere;
+       otmp->ox = obj->ox;
+       otmp->oy = obj->oy;
+       obj->nobj = otmp;
+       obj->nexthere = otmp;
+       extract_nobj(obj, &fobj);
+       extract_nexthere(obj, &level.objects[obj->ox][obj->oy]);
+       break;
+    default:
+       panic("replace_object: obj position");
+       break;
+    }
+}
+
+/*
+ * Create a dummy duplicate to put on shop bill.  The duplicate exists
+ * only in the billobjs chain.  This function is used when a shop object
+ * is being altered, and a copy of the original is needed for billing
+ * purposes.  For example, when eating, where an interruption will yield
+ * an object which is different from what it started out as; the "I x"
+ * command needs to display the original object.
+ *
+ * The caller is responsible for checking otmp->unpaid and
+ * costly_spot(u.ux, u.uy).  This function will make otmp no charge.
+ *
+ * Note that check_unpaid_usage() should be used instead for partial
+ * usage of an object.
+ */
+void
+bill_dummy_object(otmp)
+register struct obj *otmp;
+{
+       register struct obj *dummy;
+
+       if (otmp->unpaid)
+           subfrombill(otmp, shop_keeper(*u.ushops));
+       dummy = newobj(otmp->oxlth + otmp->onamelth);
+       *dummy = *otmp;
+       dummy->where = OBJ_FREE;
+       dummy->o_id = flags.ident++;
+       if (!dummy->o_id) dummy->o_id = flags.ident++;  /* ident overflowed */
+       dummy->timed = 0;
+       if (otmp->oxlth)
+           (void)memcpy((genericptr_t)dummy->oextra,
+                       (genericptr_t)otmp->oextra, otmp->oxlth);
+       if (otmp->onamelth)
+           (void)strncpy(ONAME(dummy), ONAME(otmp), (int)otmp->onamelth);
+       if (Is_candle(dummy)) dummy->lamplit = 0;
+       addtobill(dummy, FALSE, TRUE, TRUE);
+       otmp->no_charge = 1;
+       otmp->unpaid = 0;
+       return;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+static const char dknowns[] = {
+               WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS,
+               GEM_CLASS, SPBOOK_CLASS, WEAPON_CLASS, TOOL_CLASS, 0
+};
+
+struct obj *
+mksobj(otyp, init, artif)
+int otyp;
+boolean init;
+boolean artif;
+{
+       int mndx, tryct;
+       struct obj *otmp;
+       char let = objects[otyp].oc_class;
+
+       otmp = newobj(0);
+       *otmp = zeroobj;
+       otmp->age = monstermoves;
+       otmp->o_id = flags.ident++;
+       if (!otmp->o_id) otmp->o_id = flags.ident++;    /* ident overflowed */
+       otmp->quan = 1L;
+       otmp->oclass = let;
+       otmp->otyp = otyp;
+       otmp->where = OBJ_FREE;
+       otmp->dknown = index(dknowns, let) ? 0 : 1;
+       if ((otmp->otyp >= ELVEN_SHIELD && otmp->otyp <= ORCISH_SHIELD) ||
+                       otmp->otyp == SHIELD_OF_REFLECTION)
+               otmp->dknown = 0;
+       if (!objects[otmp->otyp].oc_uses_known)
+               otmp->known = 1;
+#ifdef INVISIBLE_OBJECTS
+       otmp->oinvis = !rn2(1250);
+#endif
+       if (init) switch (let) {
+       case WEAPON_CLASS:
+               otmp->quan = is_multigen(otmp) ? (long) rn1(6,6) : 1L;
+               if(!rn2(11)) {
+                       otmp->spe = rne(3);
+                       otmp->blessed = rn2(2);
+               } else if(!rn2(10)) {
+                       curse(otmp);
+                       otmp->spe = -rne(3);
+               } else  blessorcurse(otmp, 10);
+               if (is_poisonable(otmp) && !rn2(100))
+                       otmp->opoisoned = 1;
+
+               if (artif && !rn2(20))
+                   otmp = mk_artifact(otmp, (aligntyp)A_NONE);
+               break;
+       case FOOD_CLASS:
+           otmp->oeaten = 0;
+           switch(otmp->otyp) {
+           case CORPSE:
+               /* possibly overridden by mkcorpstat() */
+               tryct = 50;
+               do otmp->corpsenm = undead_to_corpse(rndmonnum());
+               while ((mvitals[otmp->corpsenm].mvflags & G_NOCORPSE) && (--tryct > 0));
+               if (tryct == 0) {
+               /* perhaps rndmonnum() only wants to make G_NOCORPSE monsters on
+                  this level; let's create an adventurer's corpse instead, then */
+                       otmp->corpsenm = PM_HUMAN;
+               }
+               /* timer set below */
+               break;
+           case EGG:
+               otmp->corpsenm = NON_PM;        /* generic egg */
+               if (!rn2(3)) for (tryct = 200; tryct > 0; --tryct) {
+                   mndx = can_be_hatched(rndmonnum());
+                   if (mndx != NON_PM && !dead_species(mndx, TRUE)) {
+                       otmp->corpsenm = mndx;          /* typed egg */
+                       attach_egg_hatch_timeout(otmp);
+                       break;
+                   }
+               }
+               break;
+           case TIN:
+               otmp->corpsenm = NON_PM;        /* empty (so far) */
+               if (!rn2(6))
+                   otmp->spe = 1;              /* spinach */
+               else for (tryct = 200; tryct > 0; --tryct) {
+                   mndx = undead_to_corpse(rndmonnum());
+                   if (mons[mndx].cnutrit &&
+                           !(mvitals[mndx].mvflags & G_NOCORPSE)) {
+                       otmp->corpsenm = mndx;
+                       break;
+                   }
+               }
+               blessorcurse(otmp, 10);
+               break;
+           case SLIME_MOLD:
+               otmp->spe = current_fruit;
+               break;
+           case KELP_FROND:
+               otmp->quan = (long) rnd(2);
+               break;
+           }
+           if (otmp->otyp == CORPSE || otmp->otyp == MEAT_RING ||
+               otmp->otyp == KELP_FROND) break;
+           /* fall into next case */
+
+       case GEM_CLASS:
+               if (otmp->otyp == LOADSTONE) curse(otmp);
+               else if (otmp->otyp == ROCK) otmp->quan = (long) rn1(6,6);
+               else if (otmp->otyp != LUCKSTONE && !rn2(6)) otmp->quan = 2L;
+               else otmp->quan = 1L;
+               break;
+       case TOOL_CLASS:
+           switch(otmp->otyp) {
+               case TALLOW_CANDLE:
+               case WAX_CANDLE:        otmp->spe = 1;
+                                       otmp->age = 20L * /* 400 or 200 */
+                                             (long)objects[otmp->otyp].oc_cost;
+                                       otmp->lamplit = 0;
+                                       otmp->quan = 1L +
+                                             (long)(rn2(2) ? rn2(7) : 0);
+                                       blessorcurse(otmp, 5);
+                                       break;
+               case BRASS_LANTERN:
+               case OIL_LAMP:          otmp->spe = 1;
+                                       otmp->age = (long) rn1(500,1000);
+                                       otmp->lamplit = 0;
+                                       blessorcurse(otmp, 5);
+                                       break;
+               case MAGIC_LAMP:        otmp->spe = 1;
+                                       otmp->lamplit = 0;
+                                       blessorcurse(otmp, 2);
+                                       break;
+               case CHEST:
+               case LARGE_BOX:         otmp->olocked = !!(rn2(5));
+                                       otmp->otrapped = !(rn2(10));
+               case ICE_BOX:
+               case SACK:
+               case OILSKIN_SACK:
+               case BAG_OF_HOLDING:    mkbox_cnts(otmp);
+                                       break;
+#ifdef TOURIST
+               case EXPENSIVE_CAMERA:
+#endif
+               case TINNING_KIT:
+               case MAGIC_MARKER:      otmp->spe = rn1(70,30);
+                                       break;
+               case CAN_OF_GREASE:     otmp->spe = rnd(25);
+                                       blessorcurse(otmp, 10);
+                                       break;
+               case CRYSTAL_BALL:      otmp->spe = rnd(5);
+                                       blessorcurse(otmp, 2);
+                                       break;
+               case HORN_OF_PLENTY:
+               case BAG_OF_TRICKS:     otmp->spe = rnd(20);
+                                       break;
+               case FIGURINE:  {       int tryct2 = 0;
+                                       do
+                                           otmp->corpsenm = rndmonnum();
+                                       while(is_human(&mons[otmp->corpsenm])
+                                               && tryct2++ < 30);
+                                       blessorcurse(otmp, 4);
+                                       break;
+                               }
+               case BELL_OF_OPENING:   otmp->spe = 3;
+                                       break;
+               case MAGIC_FLUTE:
+               case MAGIC_HARP:
+               case FROST_HORN:
+               case FIRE_HORN:
+               case DRUM_OF_EARTHQUAKE:
+                                       otmp->spe = rn1(5,4);
+                                       break;
+           }
+           break;
+       case AMULET_CLASS:
+               if (otmp->otyp == AMULET_OF_YENDOR) flags.made_amulet = TRUE;
+               if(rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION ||
+                  otmp->otyp == AMULET_OF_CHANGE ||
+                  otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) {
+                       curse(otmp);
+               } else  blessorcurse(otmp, 10);
+       case VENOM_CLASS:
+       case CHAIN_CLASS:
+       case BALL_CLASS:
+               break;
+       case POTION_CLASS:
+               if (otmp->otyp == POT_OIL)
+                   otmp->age = MAX_OIL_IN_FLASK;       /* amount of oil */
+               /* fall through */
+       case SCROLL_CLASS:
+#ifdef MAIL
+               if (otmp->otyp != SCR_MAIL)
+#endif
+                       blessorcurse(otmp, 4);
+               break;
+       case SPBOOK_CLASS:
+               blessorcurse(otmp, 17);
+               break;
+       case ARMOR_CLASS:
+               if(rn2(10) && (otmp->otyp == FUMBLE_BOOTS ||
+                  otmp->otyp == LEVITATION_BOOTS ||
+                  otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT ||
+                  otmp->otyp == GAUNTLETS_OF_FUMBLING ||
+                  !rn2(11))) {
+                       curse(otmp);
+                       otmp->spe = -rne(3);
+               } else if(!rn2(10)) {
+                       otmp->blessed = rn2(2);
+                       otmp->spe = rne(3);
+               } else  blessorcurse(otmp, 10);
+               if (artif && !rn2(40))                
+                   otmp = mk_artifact(otmp, (aligntyp)A_NONE);
+               /* simulate lacquered armor for samurai */
+               if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL &&
+                   (moves <= 1 || In_quest(&u.uz))) {
+#ifdef UNIXPC
+                       /* optimizer bitfield bug */
+                       otmp->oerodeproof = 1;
+                       otmp->rknown = 1;
+#else
+                       otmp->oerodeproof = otmp->rknown = 1;
+#endif
+               }
+               break;
+       case WAND_CLASS:
+               if(otmp->otyp == WAN_WISHING) otmp->spe = rnd(3); else
+               otmp->spe = rn1(5,
+                       (objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4);
+               blessorcurse(otmp, 17);
+               otmp->recharged = 0; /* used to control recharging */
+               break;
+       case RING_CLASS:
+               if(objects[otmp->otyp].oc_charged) {
+                   blessorcurse(otmp, 3);
+                   if(rn2(10)) {
+                       if(rn2(10) && bcsign(otmp))
+                           otmp->spe = bcsign(otmp) * rne(3);
+                       else otmp->spe = rn2(2) ? rne(3) : -rne(3);
+                   }
+                   /* make useless +0 rings much less common */
+                   if (otmp->spe == 0) otmp->spe = rn2(4) - rn2(3);
+                   /* negative rings are usually cursed */
+                   if (otmp->spe < 0 && rn2(5)) curse(otmp);
+               } else if(rn2(10) && (otmp->otyp == RIN_TELEPORTATION ||
+                         otmp->otyp == RIN_POLYMORPH ||
+                         otmp->otyp == RIN_AGGRAVATE_MONSTER ||
+                         otmp->otyp == RIN_HUNGER || !rn2(9))) {
+                       curse(otmp);
+               }
+               break;
+       case ROCK_CLASS:
+               switch (otmp->otyp) {
+                   case STATUE:
+                       /* possibly overridden by mkcorpstat() */
+                       otmp->corpsenm = rndmonnum();
+                       if (!verysmall(&mons[otmp->corpsenm]) &&
+                               rn2(level_difficulty()/2 + 10) > 10)
+                           (void) add_to_container(otmp,
+                                                   mkobj(SPBOOK_CLASS,FALSE));
+               }
+               break;
+       case COIN_CLASS:
+               break;  /* do nothing */
+       default:
+               impossible("impossible mkobj %d, sym '%c'.", otmp->otyp,
+                                               objects[otmp->otyp].oc_class);
+               return (struct obj *)0;
+       }
+
+       /* Some things must get done (timers) even if init = 0 */
+       switch (otmp->otyp) {
+           case CORPSE:
+               start_corpse_timeout(otmp);
+               break;
+       }
+
+       /* unique objects may have an associated artifact entry */
+       if (objects[otyp].oc_unique && !otmp->oartifact)
+           otmp = mk_artifact(otmp, (aligntyp)A_NONE);
+       otmp->owt = weight(otmp);
+       return(otmp);
+}
+
+/*
+ * Start a corpse decay or revive timer.
+ * This takes the age of the corpse into consideration as of 3.4.0.
+ */
+void
+start_corpse_timeout(body)
+       struct obj *body;
+{
+       long when;              /* rot away when this old */
+       long corpse_age;        /* age of corpse          */
+       int rot_adjust;
+       short action;
+
+#define TAINT_AGE (50L)                /* age when corpses go bad */
+#define TROLL_REVIVE_CHANCE 37 /* 1/37 chance for 50 turns ~ 75% chance */
+#define ROT_AGE (250L)         /* age when corpses rot away */
+
+       /* lizards and lichen don't rot or revive */
+       if (body->corpsenm == PM_LIZARD || body->corpsenm == PM_LICHEN) return;
+
+       action = ROT_CORPSE;            /* default action: rot away */
+       rot_adjust = in_mklev ? 25 : 10;        /* give some variation */
+       corpse_age = monstermoves - body->age;
+       if (corpse_age > ROT_AGE)
+               when = rot_adjust;
+       else
+               when = ROT_AGE - corpse_age;
+       when += (long)(rnz(rot_adjust) - rot_adjust);
+
+       if (is_rider(&mons[body->corpsenm])) {
+               /*
+                * Riders always revive.  They have a 1/3 chance per turn
+                * of reviving after 12 turns.  Always revive by 500.
+                */
+               action = REVIVE_MON;
+               for (when = 12L; when < 500L; when++)
+                   if (!rn2(3)) break;
+
+       } else if (mons[body->corpsenm].mlet == S_TROLL && !body->norevive) {
+               long age;
+               for (age = 2; age <= TAINT_AGE; age++)
+                   if (!rn2(TROLL_REVIVE_CHANCE)) {    /* troll revives */
+                       action = REVIVE_MON;
+                       when = age;
+                       break;
+                   }
+       }
+       
+       if (body->norevive) body->norevive = 0;
+       (void) start_timer(when, TIMER_OBJECT, action, (genericptr_t)body);
+}
+
+void
+bless(otmp)
+register struct obj *otmp;
+{
+#ifdef GOLDOBJ
+       if (otmp->oclass == COIN_CLASS) return;
+#endif
+       otmp->cursed = 0;
+       otmp->blessed = 1;
+       if (carried(otmp) && confers_luck(otmp))
+           set_moreluck();
+       else if (otmp->otyp == BAG_OF_HOLDING)
+           otmp->owt = weight(otmp);
+       else if (otmp->otyp == FIGURINE && otmp->timed)
+               (void) stop_timer(FIG_TRANSFORM, (genericptr_t) otmp);
+       return;
+}
+
+void
+unbless(otmp)
+register struct obj *otmp;
+{
+       otmp->blessed = 0;
+       if (carried(otmp) && confers_luck(otmp))
+           set_moreluck();
+       else if (otmp->otyp == BAG_OF_HOLDING)
+           otmp->owt = weight(otmp);
+}
+
+void
+curse(otmp)
+register struct obj *otmp;
+{
+#ifdef GOLDOBJ
+       if (otmp->oclass == COIN_CLASS) return;
+#endif
+       otmp->blessed = 0;
+       otmp->cursed = 1;
+       /* welded two-handed weapon interferes with some armor removal */
+       if (otmp == uwep && bimanual(uwep)) reset_remarm();
+       /* rules at top of wield.c state that twoweapon cannot be done
+          with cursed alternate weapon */
+       if (otmp == uswapwep && u.twoweap)
+           drop_uswapwep();
+       /* some cursed items need immediate updating */
+       if (carried(otmp) && confers_luck(otmp))
+           set_moreluck();
+       else if (otmp->otyp == BAG_OF_HOLDING)
+           otmp->owt = weight(otmp);
+       else if (otmp->otyp == FIGURINE) {
+               if (otmp->corpsenm != NON_PM
+                   && !dead_species(otmp->corpsenm,TRUE)
+                   && (carried(otmp) || mcarried(otmp)))
+                       attach_fig_transform_timeout(otmp);
+       }
+       return;
+}
+
+void
+uncurse(otmp)
+register struct obj *otmp;
+{
+       otmp->cursed = 0;
+       if (carried(otmp) && confers_luck(otmp))
+           set_moreluck();
+       else if (otmp->otyp == BAG_OF_HOLDING)
+           otmp->owt = weight(otmp);
+       else if (otmp->otyp == FIGURINE && otmp->timed)
+           (void) stop_timer(FIG_TRANSFORM, (genericptr_t) otmp);
+       return;
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+void
+blessorcurse(otmp, chance)
+register struct obj *otmp;
+register int chance;
+{
+       if(otmp->blessed || otmp->cursed) return;
+
+       if(!rn2(chance)) {
+           if(!rn2(2)) {
+               curse(otmp);
+           } else {
+               bless(otmp);
+           }
+       }
+       return;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+int
+bcsign(otmp)
+register struct obj *otmp;
+{
+       return(!!otmp->blessed - !!otmp->cursed);
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+/*
+ *  Calculate the weight of the given object.  This will recursively follow
+ *  and calculate the weight of any containers.
+ *
+ *  Note:  It is possible to end up with an incorrect weight if some part
+ *        of the code messes with a contained object and doesn't update the
+ *        container's weight.
+ */
+int
+weight(obj)
+register struct obj *obj;
+{
+       int wt = objects[obj->otyp].oc_weight;
+
+       if (obj->otyp == LARGE_BOX && obj->spe == 1) /* Schroedinger's Cat */
+               wt += mons[PM_HOUSECAT].cwt;
+       if (Is_container(obj) || obj->otyp == STATUE) {
+               struct obj *contents;
+               register int cwt = 0;
+
+               if (obj->otyp == STATUE && obj->corpsenm >= LOW_PM)
+                   wt = (int)obj->quan *
+                        ((int)mons[obj->corpsenm].cwt * 3 / 2);
+
+               for(contents=obj->cobj; contents; contents=contents->nobj)
+                       cwt += weight(contents);
+               /*
+                *  The weight of bags of holding is calculated as the weight
+                *  of the bag plus the weight of the bag's contents modified
+                *  as follows:
+                *
+                *      Bag status      Weight of contents
+                *      ----------      ------------------
+                *      cursed                  2x
+                *      blessed                 x/4 + 1
+                *      otherwise               x/2 + 1
+                *
+                *  The macro DELTA_CWT in pickup.c also implements these
+                *  weight equations.
+                *
+                *  Note:  The above checks are performed in the given order.
+                *         this means that if an object is both blessed and
+                *         cursed (not supposed to happen), it will be treated
+                *         as cursed.
+                */
+               if (obj->otyp == BAG_OF_HOLDING)
+                   cwt = obj->cursed ? (cwt * 2) :
+                                       (1 + (cwt / (obj->blessed ? 4 : 2)));
+
+               return wt + cwt;
+       }
+       if (obj->otyp == CORPSE && obj->corpsenm >= LOW_PM) {
+               long long_wt = obj->quan * (long) mons[obj->corpsenm].cwt;
+
+               wt = (long_wt > LARGEST_INT) ? LARGEST_INT : (int)long_wt;
+               if (obj->oeaten) wt = eaten_stat(wt, obj);
+               return wt;
+       } else if (obj->oclass == FOOD_CLASS && obj->oeaten) {
+               return eaten_stat((int)obj->quan * wt, obj);
+       } else if (obj->oclass == COIN_CLASS)
+               return (int)((obj->quan + 50L) / 100L);
+       else if (obj->otyp == HEAVY_IRON_BALL && obj->owt != 0)
+               return((int)(obj->owt));        /* kludge for "very" heavy iron ball */
+       return(wt ? wt*(int)obj->quan : ((int)obj->quan + 1)>>1);
+}
+
+static int treefruits[] = {APPLE,ORANGE,PEAR,BANANA,EUCALYPTUS_LEAF};
+
+struct obj *
+rnd_treefruit_at(x,y)
+int x, y;
+{
+       return mksobj_at(treefruits[rn2(SIZE(treefruits))], x, y, TRUE, FALSE);
+}
+#endif /* OVL0 */
+#ifdef OVLB
+
+struct obj *
+mkgold(amount, x, y)
+long amount;
+int x, y;
+{
+    register struct obj *gold = g_at(x,y);
+
+    if (amount <= 0L)
+       amount = (long)(1 + rnd(level_difficulty()+2) * rnd(30));
+    if (gold) {
+       gold->quan += amount;
+    } else {
+       gold = mksobj_at(GOLD_PIECE, x, y, TRUE, FALSE);
+       gold->quan = amount;
+    }
+    gold->owt = weight(gold);
+    return (gold);
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+/* return TRUE if the corpse has special timing */
+#define special_corpse(num)  (((num) == PM_LIZARD)             \
+                               || ((num) == PM_LICHEN)         \
+                               || (is_rider(&mons[num]))       \
+                               || (mons[num].mlet == S_TROLL))
+
+/*
+ * OEXTRA note: Passing mtmp causes mtraits to be saved
+ * even if ptr passed as well, but ptr is always used for
+ * the corpse type (corpsenm). That allows the corpse type
+ * to be different from the original monster,
+ *     i.e.  vampire -> human corpse
+ * yet still allow restoration of the original monster upon
+ * resurrection.
+ */
+struct obj *
+mkcorpstat(objtype, mtmp, ptr, x, y, init)
+int objtype;   /* CORPSE or STATUE */
+struct monst *mtmp;
+struct permonst *ptr;
+int x, y;
+boolean init;
+{
+       register struct obj *otmp;
+
+       if (objtype != CORPSE && objtype != STATUE)
+           impossible("making corpstat type %d", objtype);
+       if (x == 0 && y == 0) {         /* special case - random placement */
+               otmp = mksobj(objtype, init, FALSE);
+               if (otmp) rloco(otmp);
+       } else
+               otmp = mksobj_at(objtype, x, y, init, FALSE);
+       if (otmp) {
+           if (mtmp) {
+               struct obj *otmp2;
+
+               if (!ptr) ptr = mtmp->data;
+               /* save_mtraits frees original data pointed to by otmp */
+               otmp2 = save_mtraits(otmp, mtmp);
+               if (otmp2) otmp = otmp2;
+           }
+           /* use the corpse or statue produced by mksobj() as-is
+              unless `ptr' is non-null */
+           if (ptr) {
+               int old_corpsenm = otmp->corpsenm;
+
+               otmp->corpsenm = monsndx(ptr);
+               otmp->owt = weight(otmp);
+               if (otmp->otyp == CORPSE &&
+                       (special_corpse(old_corpsenm) ||
+                               special_corpse(otmp->corpsenm))) {
+                   obj_stop_timers(otmp);
+                   start_corpse_timeout(otmp);
+               }
+           }
+       }
+       return(otmp);
+}
+
+/*
+ * Attach a monster id to an object, to provide
+ * a lasting association between the two.
+ */
+struct obj *
+obj_attach_mid(obj, mid)
+struct obj *obj;
+unsigned mid;
+{
+    struct obj *otmp;
+    int lth, namelth;
+
+    if (!mid || !obj) return (struct obj *)0;
+    lth = sizeof(mid);
+    namelth = obj->onamelth ? strlen(ONAME(obj)) + 1 : 0;
+    if (namelth) 
+       otmp = realloc_obj(obj, lth, (genericptr_t) &mid, namelth, ONAME(obj));
+    else {
+       otmp = obj;
+       otmp->oxlth = sizeof(mid);
+       (void) memcpy((genericptr_t)otmp->oextra, (genericptr_t)&mid,
+                                                               sizeof(mid));
+    }
+    if (otmp && otmp->oxlth) otmp->oattached = OATTACHED_M_ID; /* mark it */
+    return otmp;
+}
+
+static struct obj *
+save_mtraits(obj, mtmp)
+struct obj *obj;
+struct monst *mtmp;
+{
+       struct obj *otmp;
+       int lth, namelth;
+
+       lth = sizeof(struct monst) + mtmp->mxlth + mtmp->mnamelth;
+       namelth = obj->onamelth ? strlen(ONAME(obj)) + 1 : 0;
+       otmp = realloc_obj(obj, lth, (genericptr_t) mtmp, namelth, ONAME(obj));
+       if (otmp && otmp->oxlth) {
+               struct monst *mtmp2 = (struct monst *)otmp->oextra;
+               if (mtmp->data) mtmp2->mnum = monsndx(mtmp->data);
+               /* invalidate pointers */
+               /* m_id is needed to know if this is a revived quest leader */
+               /* but m_id must be cleared when loading bones */
+               mtmp2->nmon     = (struct monst *)0;
+               mtmp2->data     = (struct permonst *)0;
+               mtmp2->minvent  = (struct obj *)0;
+               otmp->oattached = OATTACHED_MONST;      /* mark it */
+       }
+       return otmp;
+}
+
+/* returns a pointer to a new monst structure based on
+ * the one contained within the obj.
+ */
+struct monst *
+get_mtraits(obj, copyof)
+struct obj *obj;
+boolean copyof;
+{
+       struct monst *mtmp = (struct monst *)0;
+       struct monst *mnew = (struct monst *)0;
+
+       if (obj->oxlth && obj->oattached == OATTACHED_MONST)
+               mtmp = (struct monst *)obj->oextra;
+       if (mtmp) {
+           if (copyof) {
+               int lth = mtmp->mxlth + mtmp->mnamelth;
+               mnew = newmonst(lth);
+               lth += sizeof(struct monst);
+               (void) memcpy((genericptr_t)mnew,
+                               (genericptr_t)mtmp, lth);
+           } else {
+             /* Never insert this returned pointer into mon chains! */
+               mnew = mtmp;
+           }
+       }
+       return mnew;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+/* make an object named after someone listed in the scoreboard file */
+struct obj *
+mk_tt_object(objtype, x, y)
+int objtype; /* CORPSE or STATUE */
+register int x, y;
+{
+       register struct obj *otmp, *otmp2;
+       boolean initialize_it;
+
+       /* player statues never contain books */
+       initialize_it = (objtype != STATUE);
+       if ((otmp = mksobj_at(objtype, x, y, initialize_it, FALSE)) != 0) {
+           /* tt_oname will return null if the scoreboard is empty */
+           if ((otmp2 = tt_oname(otmp)) != 0) otmp = otmp2;
+       }
+       return(otmp);
+}
+
+/* make a new corpse or statue, uninitialized if a statue (i.e. no books) */
+struct obj *
+mk_named_object(objtype, ptr, x, y, nm)
+int objtype;   /* CORPSE or STATUE */
+struct permonst *ptr;
+int x, y;
+const char *nm;
+{
+       struct obj *otmp;
+
+       otmp = mkcorpstat(objtype, (struct monst *)0, ptr,
+                               x, y, (boolean)(objtype != STATUE));
+       if (nm)
+               otmp = oname(otmp, nm);
+       return(otmp);
+}
+
+boolean
+is_flammable(otmp)
+register struct obj *otmp;
+{
+       int otyp = otmp->otyp;
+       int omat = objects[otyp].oc_material;
+
+       if (objects[otyp].oc_oprop == FIRE_RES || otyp == WAN_FIRE)
+               return FALSE;
+
+       return((boolean)((omat <= WOOD && omat != LIQUID) || omat == PLASTIC));
+}
+
+boolean
+is_rottable(otmp)
+register struct obj *otmp;
+{
+       int otyp = otmp->otyp;
+
+       return((boolean)(objects[otyp].oc_material <= WOOD &&
+                       objects[otyp].oc_material != LIQUID));
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+/*
+ * These routines maintain the single-linked lists headed in level.objects[][]
+ * and threaded through the nexthere fields in the object-instance structure.
+ */
+
+/* put the object at the given location */
+void
+place_object(otmp, x, y)
+register struct obj *otmp;
+int x, y;
+{
+    register struct obj *otmp2 = level.objects[x][y];
+
+    if (otmp->where != OBJ_FREE)
+       panic("place_object: obj not free");
+
+    obj_no_longer_held(otmp);
+    if (otmp->otyp == BOULDER) block_point(x,y);       /* vision */
+
+    /* obj goes under boulders */
+    if (otmp2 && (otmp2->otyp == BOULDER)) {
+       otmp->nexthere = otmp2->nexthere;
+       otmp2->nexthere = otmp;
+    } else {
+       otmp->nexthere = otmp2;
+       level.objects[x][y] = otmp;
+    }
+
+    /* set the new object's location */
+    otmp->ox = x;
+    otmp->oy = y;
+
+    otmp->where = OBJ_FLOOR;
+
+    /* add to floor chain */
+    otmp->nobj = fobj;
+    fobj = otmp;
+    if (otmp->timed) obj_timer_checks(otmp, x, y, 0);
+}
+
+#define ON_ICE(a) ((a)->recharged)
+#define ROT_ICE_ADJUSTMENT 2   /* rotting on ice takes 2 times as long */
+
+/* If ice was affecting any objects correct that now
+ * Also used for starting ice effects too. [zap.c]
+ */
+void
+obj_ice_effects(x, y, do_buried)
+int x, y;
+boolean do_buried;
+{
+       struct obj *otmp;
+
+       for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) {
+               if (otmp->timed) obj_timer_checks(otmp, x, y, 0);
+       }
+       if (do_buried) {
+           for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj) {
+               if (otmp->ox == x && otmp->oy == y) {
+                       if (otmp->timed) obj_timer_checks(otmp, x, y, 0);
+               }
+           }
+       }
+}
+
+/*
+ * Returns an obj->age for a corpse object on ice, that would be the
+ * actual obj->age if the corpse had just been lifted from the ice.
+ * This is useful when just using obj->age in a check or calculation because
+ * rot timers pertaining to the object don't have to be stopped and
+ * restarted etc.
+ */
+long
+peek_at_iced_corpse_age(otmp)
+struct obj *otmp;
+{
+    long age, retval = otmp->age;
+    
+    if (otmp->otyp == CORPSE && ON_ICE(otmp)) {
+       /* Adjust the age; must be same as obj_timer_checks() for off ice*/
+       age = monstermoves - otmp->age;
+       retval = otmp->age + (age / ROT_ICE_ADJUSTMENT);
+#ifdef DEBUG_EFFECTS
+       pline_The("%s age has ice modifications:otmp->age = %ld, returning %ld.",
+               s_suffix(doname(otmp)),otmp->age, retval);
+       pline("Effective age of corpse: %ld.",
+               monstermoves - retval);
+#endif
+    }
+    return retval;
+}
+
+STATIC_OVL void
+obj_timer_checks(otmp, x, y, force)
+struct obj *otmp;
+xchar x, y;
+int force;     /* 0 = no force so do checks, <0 = force off, >0 force on */
+{
+    long tleft = 0L;
+    short action = ROT_CORPSE;
+    boolean restart_timer = FALSE;
+    boolean on_floor = (otmp->where == OBJ_FLOOR);
+    boolean buried = (otmp->where == OBJ_BURIED);
+
+    /* Check for corpses just placed on or in ice */
+    if (otmp->otyp == CORPSE && (on_floor || buried) && is_ice(x,y)) {
+       tleft = stop_timer(action, (genericptr_t)otmp);
+       if (tleft == 0L) {
+               action = REVIVE_MON;
+               tleft = stop_timer(action, (genericptr_t)otmp);
+       } 
+       if (tleft != 0L) {
+           long age;
+           
+           tleft = tleft - monstermoves;
+           /* mark the corpse as being on ice */
+           ON_ICE(otmp) = 1;
+#ifdef DEBUG_EFFECTS
+           pline("%s is now on ice at %d,%d.", The(xname(otmp)),x,y);
+#endif
+           /* Adjust the time remaining */
+           tleft *= ROT_ICE_ADJUSTMENT;
+           restart_timer = TRUE;
+           /* Adjust the age; must be same as in obj_ice_age() */
+           age = monstermoves - otmp->age;
+           otmp->age = monstermoves - (age * ROT_ICE_ADJUSTMENT);
+       }
+    }
+    /* Check for corpses coming off ice */
+    else if ((force < 0) ||
+            (otmp->otyp == CORPSE && ON_ICE(otmp) &&
+            ((on_floor && !is_ice(x,y)) || !on_floor))) {
+       tleft = stop_timer(action, (genericptr_t)otmp);
+       if (tleft == 0L) {
+               action = REVIVE_MON;
+               tleft = stop_timer(action, (genericptr_t)otmp);
+       }
+       if (tleft != 0L) {
+               long age;
+
+               tleft = tleft - monstermoves;
+               ON_ICE(otmp) = 0;
+#ifdef DEBUG_EFFECTS
+               pline("%s is no longer on ice at %d,%d.", The(xname(otmp)),x,y);
+#endif
+               /* Adjust the remaining time */
+               tleft /= ROT_ICE_ADJUSTMENT;
+               restart_timer = TRUE;
+               /* Adjust the age */
+               age = monstermoves - otmp->age;
+               otmp->age = otmp->age + (age / ROT_ICE_ADJUSTMENT);
+       }
+    }
+    /* now re-start the timer with the appropriate modifications */ 
+    if (restart_timer)
+       (void) start_timer(tleft, TIMER_OBJECT, action, (genericptr_t)otmp);
+}
+
+#undef ON_ICE
+#undef ROT_ICE_ADJUSTMENT
+
+void
+remove_object(otmp)
+register struct obj *otmp;
+{
+    xchar x = otmp->ox;
+    xchar y = otmp->oy;
+
+    if (otmp->where != OBJ_FLOOR)
+       panic("remove_object: obj not on floor");
+    if (otmp->otyp == BOULDER) unblock_point(x,y); /* vision */
+    extract_nexthere(otmp, &level.objects[x][y]);
+    extract_nobj(otmp, &fobj);
+    if (otmp->timed) obj_timer_checks(otmp,x,y,0);
+}
+
+/* throw away all of a monster's inventory */
+void
+discard_minvent(mtmp)
+struct monst *mtmp;
+{
+    struct obj *otmp;
+
+    while ((otmp = mtmp->minvent) != 0) {
+       obj_extract_self(otmp);
+       obfree(otmp, (struct obj *)0);  /* dealloc_obj() isn't sufficient */
+    }
+}
+
+/*
+ * Free obj from whatever list it is on in preperation of deleting it or
+ * moving it elsewhere.  This will perform all high-level consequences
+ * involved with removing the item.  E.g. if the object is in the hero's
+ * inventory and confers heat resistance, the hero will lose it.
+ *
+ * Object positions:
+ *     OBJ_FREE        not on any list
+ *     OBJ_FLOOR       fobj, level.locations[][] chains (use remove_object)
+ *     OBJ_CONTAINED   cobj chain of container object
+ *     OBJ_INVENT      hero's invent chain (use freeinv)
+ *     OBJ_MINVENT     monster's invent chain
+ *     OBJ_MIGRATING   migrating chain
+ *     OBJ_BURIED      level.buriedobjs chain
+ *     OBJ_ONBILL      on billobjs chain
+ */
+void
+obj_extract_self(obj)
+    struct obj *obj;
+{
+    switch (obj->where) {
+       case OBJ_FREE:
+           break;
+       case OBJ_FLOOR:
+           remove_object(obj);
+           break;
+       case OBJ_CONTAINED:
+           extract_nobj(obj, &obj->ocontainer->cobj);
+           container_weight(obj->ocontainer);
+           break;
+       case OBJ_INVENT:
+           freeinv(obj);
+           break;
+       case OBJ_MINVENT:
+           extract_nobj(obj, &obj->ocarry->minvent);
+           break;
+       case OBJ_MIGRATING:
+           extract_nobj(obj, &migrating_objs);
+           break;
+       case OBJ_BURIED:
+           extract_nobj(obj, &level.buriedobjlist);
+           break;
+       case OBJ_ONBILL:
+           extract_nobj(obj, &billobjs);
+           break;
+       default:
+           panic("obj_extract_self");
+           break;
+    }
+}
+
+
+/* Extract the given object from the chain, following nobj chain. */
+void
+extract_nobj(obj, head_ptr)
+    struct obj *obj, **head_ptr;
+{
+    struct obj *curr, *prev;
+
+    curr = *head_ptr;
+    for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nobj) {
+       if (curr == obj) {
+           if (prev)
+               prev->nobj = curr->nobj;
+           else
+               *head_ptr = curr->nobj;
+           break;
+       }
+    }
+    if (!curr) panic("extract_nobj: object lost");
+    obj->where = OBJ_FREE;
+}
+
+
+/*
+ * Extract the given object from the chain, following nexthere chain.
+ *
+ * This does not set obj->where, this function is expected to be called
+ * in tandem with extract_nobj, which does set it.
+ */
+void
+extract_nexthere(obj, head_ptr)
+    struct obj *obj, **head_ptr;
+{
+    struct obj *curr, *prev;
+
+    curr = *head_ptr;
+    for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nexthere) {
+       if (curr == obj) {
+           if (prev)
+               prev->nexthere = curr->nexthere;
+           else
+               *head_ptr = curr->nexthere;
+           break;
+       }
+    }
+    if (!curr) panic("extract_nexthere: object lost");
+}
+
+
+/*
+ * Add obj to mon's inventory.  If obj is able to merge with something already
+ * in the inventory, then the passed obj is deleted and 1 is returned.
+ * Otherwise 0 is returned.
+ */
+int
+add_to_minv(mon, obj)
+    struct monst *mon;
+    struct obj *obj;
+{
+    struct obj *otmp;
+
+    if (obj->where != OBJ_FREE)
+       panic("add_to_minv: obj not free");
+
+    /* merge if possible */
+    for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
+       if (merged(&otmp, &obj))
+           return 1;   /* obj merged and then free'd */
+    /* else insert; don't bother forcing it to end of chain */
+    obj->where = OBJ_MINVENT;
+    obj->ocarry = mon;
+    obj->nobj = mon->minvent;
+    mon->minvent = obj;
+    return 0;  /* obj on mon's inventory chain */
+}
+
+/*
+ * Add obj to container, make sure obj is "free".  Returns (merged) obj.
+ * The input obj may be deleted in the process.
+ */
+struct obj *
+add_to_container(container, obj)
+    struct obj *container, *obj;
+{
+    struct obj *otmp;
+
+    if (obj->where != OBJ_FREE)
+       panic("add_to_container: obj not free");
+    if (container->where != OBJ_INVENT && container->where != OBJ_MINVENT)
+       obj_no_longer_held(obj);
+
+    /* merge if possible */
+    for (otmp = container->cobj; otmp; otmp = otmp->nobj)
+       if (merged(&otmp, &obj)) return (otmp);
+
+    obj->where = OBJ_CONTAINED;
+    obj->ocontainer = container;
+    obj->nobj = container->cobj;
+    container->cobj = obj;
+    return (obj);
+}
+
+void
+add_to_migration(obj)
+    struct obj *obj;
+{
+    if (obj->where != OBJ_FREE)
+       panic("add_to_migration: obj not free");
+
+    obj->where = OBJ_MIGRATING;
+    obj->nobj = migrating_objs;
+    migrating_objs = obj;
+}
+
+void
+add_to_buried(obj)
+    struct obj *obj;
+{
+    if (obj->where != OBJ_FREE)
+       panic("add_to_buried: obj not free");
+
+    obj->where = OBJ_BURIED;
+    obj->nobj = level.buriedobjlist;
+    level.buriedobjlist = obj;
+}
+
+/* Recalculate the weight of this container and all of _its_ containers. */
+STATIC_OVL void
+container_weight(container)
+    struct obj *container;
+{
+    container->owt = weight(container);
+    if (container->where == OBJ_CONTAINED)
+       container_weight(container->ocontainer);
+/*
+    else if (container->where == OBJ_INVENT)
+       recalculate load delay here ???
+*/
+}
+
+/*
+ * Deallocate the object.  _All_ objects should be run through here for
+ * them to be deallocated.
+ */
+void
+dealloc_obj(obj)
+    struct obj *obj;
+{
+    if (obj->where != OBJ_FREE)
+       panic("dealloc_obj: obj not free");
+
+    /* free up any timers attached to the object */
+    if (obj->timed)
+       obj_stop_timers(obj);
+
+    /*
+     * Free up any light sources attached to the object.
+     *
+     * We may want to just call del_light_source() without any
+     * checks (requires a code change there).  Otherwise this
+     * list must track all objects that can have a light source
+     * attached to it (and also requires lamplit to be set).
+     */
+    if (obj_sheds_light(obj))
+       del_light_source(LS_OBJECT, (genericptr_t) obj);
+
+    if (obj == thrownobj) thrownobj = (struct obj*)0;
+
+    free((genericptr_t) obj);
+}
+
+#ifdef WIZARD
+/* Check all object lists for consistency. */
+void
+obj_sanity_check()
+{
+    int x, y;
+    struct obj *obj;
+    struct monst *mon;
+    const char *mesg;
+    char obj_address[20], mon_address[20];  /* room for formatted pointers */
+
+    mesg = "fobj sanity";
+    for (obj = fobj; obj; obj = obj->nobj) {
+       if (obj->where != OBJ_FLOOR) {
+           pline("%s obj %s %s@(%d,%d): %s\n", mesg,
+               fmt_ptr((genericptr_t)obj, obj_address),
+               where_name(obj->where),
+               obj->ox, obj->oy, doname(obj));
+       }
+       check_contained(obj, mesg);
+    }
+
+    mesg = "location sanity";
+    for (x = 0; x < COLNO; x++)
+       for (y = 0; y < ROWNO; y++)
+           for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
+               if (obj->where != OBJ_FLOOR) {
+                   pline("%s obj %s %s@(%d,%d): %s\n", mesg,
+                       fmt_ptr((genericptr_t)obj, obj_address),
+                       where_name(obj->where),
+                       obj->ox, obj->oy, doname(obj));
+               }
+
+    mesg = "invent sanity";
+    for (obj = invent; obj; obj = obj->nobj) {
+       if (obj->where != OBJ_INVENT) {
+           pline("%s obj %s %s: %s\n", mesg,
+               fmt_ptr((genericptr_t)obj, obj_address),
+               where_name(obj->where), doname(obj));
+       }
+       check_contained(obj, mesg);
+    }
+
+    mesg = "migrating sanity";
+    for (obj = migrating_objs; obj; obj = obj->nobj) {
+       if (obj->where != OBJ_MIGRATING) {
+           pline("%s obj %s %s: %s\n", mesg,
+               fmt_ptr((genericptr_t)obj, obj_address),
+               where_name(obj->where), doname(obj));
+       }
+       check_contained(obj, mesg);
+    }
+
+    mesg = "buried sanity";
+    for (obj = level.buriedobjlist; obj; obj = obj->nobj) {
+       if (obj->where != OBJ_BURIED) {
+           pline("%s obj %s %s: %s\n", mesg,
+               fmt_ptr((genericptr_t)obj, obj_address),
+               where_name(obj->where), doname(obj));
+       }
+       check_contained(obj, mesg);
+    }
+
+    mesg = "bill sanity";
+    for (obj = billobjs; obj; obj = obj->nobj) {
+       if (obj->where != OBJ_ONBILL) {
+           pline("%s obj %s %s: %s\n", mesg,
+               fmt_ptr((genericptr_t)obj, obj_address),
+               where_name(obj->where), doname(obj));
+       }
+       /* shouldn't be a full container on the bill */
+       if (obj->cobj) {
+           pline("%s obj %s contains %s! %s\n", mesg,
+               fmt_ptr((genericptr_t)obj, obj_address),
+               something, doname(obj));
+       }
+    }
+
+    mesg = "minvent sanity";
+    for (mon = fmon; mon; mon = mon->nmon)
+       for (obj = mon->minvent; obj; obj = obj->nobj) {
+           if (obj->where != OBJ_MINVENT) {
+               pline("%s obj %s %s: %s\n", mesg,
+                       fmt_ptr((genericptr_t)obj, obj_address),
+                       where_name(obj->where), doname(obj));
+           }
+           if (obj->ocarry != mon) {
+               pline("%s obj %s (%s) not held by mon %s (%s)\n", mesg,
+                       fmt_ptr((genericptr_t)obj, obj_address),
+                       doname(obj),
+                       fmt_ptr((genericptr_t)mon, mon_address),
+                       mon_nam(mon));
+           }
+           check_contained(obj, mesg);
+       }
+}
+
+/* This must stay consistent with the defines in obj.h. */
+static const char *obj_state_names[NOBJ_STATES] = {
+       "free",         "floor",        "contained",    "invent",
+       "minvent",      "migrating",    "buried",       "onbill"
+};
+
+STATIC_OVL const char *
+where_name(where)
+    int where;
+{
+    return (where<0 || where>=NOBJ_STATES) ? "unknown" : obj_state_names[where];
+}
+
+/* obj sanity check: check objs contained by container */
+STATIC_OVL void
+check_contained(container, mesg)
+    struct obj *container;
+    const char *mesg;
+{
+    struct obj *obj;
+    char obj1_address[20], obj2_address[20];
+
+    for (obj = container->cobj; obj; obj = obj->nobj) {
+       if (obj->where != OBJ_CONTAINED)
+           pline("contained %s obj %s: %s\n", mesg,
+               fmt_ptr((genericptr_t)obj, obj1_address),
+               where_name(obj->where));
+       else if (obj->ocontainer != container)
+           pline("%s obj %s not in container %s\n", mesg,
+               fmt_ptr((genericptr_t)obj, obj1_address),
+               fmt_ptr((genericptr_t)container, obj2_address));
+    }
+}
+#endif /* WIZARD */
+
+#endif /* OVL1 */
+
+/*mkobj.c*/
diff --git a/src/mkroom.c b/src/mkroom.c
new file mode 100644 (file)
index 0000000..b6e708c
--- /dev/null
@@ -0,0 +1,781 @@
+/*     SCCS Id: @(#)mkroom.c   3.4     2001/09/06      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Entry points:
+ *     mkroom() -- make and stock a room of a given type
+ *     nexttodoor() -- return TRUE if adjacent to a door
+ *     has_dnstairs() -- return TRUE if given room has a down staircase
+ *     has_upstairs() -- return TRUE if given room has an up staircase
+ *     courtmon() -- generate a court monster
+ *     save_rooms() -- save rooms into file fd
+ *     rest_rooms() -- restore rooms from file fd
+ */
+
+#include "hack.h"
+
+#ifdef OVLB
+STATIC_DCL boolean FDECL(isbig, (struct mkroom *));
+STATIC_DCL struct mkroom * FDECL(pick_room,(BOOLEAN_P));
+STATIC_DCL void NDECL(mkshop), FDECL(mkzoo,(int)), NDECL(mkswamp);
+STATIC_DCL void NDECL(mktemple);
+STATIC_DCL coord * FDECL(shrine_pos, (int));
+STATIC_DCL struct permonst * NDECL(morguemon);
+STATIC_DCL struct permonst * NDECL(antholemon);
+STATIC_DCL struct permonst * NDECL(squadmon);
+STATIC_DCL void FDECL(save_room, (int,struct mkroom *));
+STATIC_DCL void FDECL(rest_room, (int,struct mkroom *));
+#endif /* OVLB */
+
+#define sq(x) ((x)*(x))
+
+extern const struct shclass shtypes[]; /* defined in shknam.c */
+
+#ifdef OVLB
+
+STATIC_OVL boolean
+isbig(sroom)
+register struct mkroom *sroom;
+{
+       register int area = (sroom->hx - sroom->lx + 1)
+                          * (sroom->hy - sroom->ly + 1);
+       return((boolean)( area > 20 ));
+}
+
+void
+mkroom(roomtype)
+/* make and stock a room of a given type */
+int    roomtype;
+{
+    if (roomtype >= SHOPBASE)
+       mkshop();       /* someday, we should be able to specify shop type */
+    else switch(roomtype) {
+       case COURT:     mkzoo(COURT); break;
+       case ZOO:       mkzoo(ZOO); break;
+       case BEEHIVE:   mkzoo(BEEHIVE); break;
+       case MORGUE:    mkzoo(MORGUE); break;
+       case BARRACKS:  mkzoo(BARRACKS); break;
+       case SWAMP:     mkswamp(); break;
+       case TEMPLE:    mktemple(); break;
+       case LEPREHALL: mkzoo(LEPREHALL); break;
+       case COCKNEST:  mkzoo(COCKNEST); break;
+       case ANTHOLE:   mkzoo(ANTHOLE); break;
+       default:        impossible("Tried to make a room of type %d.", roomtype);
+    }
+}
+
+STATIC_OVL void
+mkshop()
+{
+       register struct mkroom *sroom;
+       int i = -1;
+#ifdef WIZARD
+       char *ep = (char *)0;   /* (init == lint suppression) */
+
+       /* first determine shoptype */
+       if(wizard){
+#ifndef MAC
+               ep = nh_getenv("SHOPTYPE");
+               if(ep){
+                       if(*ep == 'z' || *ep == 'Z'){
+                               mkzoo(ZOO);
+                               return;
+                       }
+                       if(*ep == 'm' || *ep == 'M'){
+                               mkzoo(MORGUE);
+                               return;
+                       }
+                       if(*ep == 'b' || *ep == 'B'){
+                               mkzoo(BEEHIVE);
+                               return;
+                       }
+                       if(*ep == 't' || *ep == 'T' || *ep == '\\'){
+                               mkzoo(COURT);
+                               return;
+                       }
+                       if(*ep == 's' || *ep == 'S'){
+                               mkzoo(BARRACKS);
+                               return;
+                       }
+                       if(*ep == 'a' || *ep == 'A'){
+                               mkzoo(ANTHOLE);
+                               return;
+                       }
+                       if(*ep == 'c' || *ep == 'C'){
+                               mkzoo(COCKNEST);
+                               return;
+                       }
+                       if(*ep == 'l' || *ep == 'L'){
+                               mkzoo(LEPREHALL);
+                               return;
+                       }
+                       if(*ep == '_'){
+                               mktemple();
+                               return;
+                       }
+                       if(*ep == '}'){
+                               mkswamp();
+                               return;
+                       }
+                       for(i=0; shtypes[i].name; i++)
+                               if(*ep == def_oc_syms[(int)shtypes[i].symb])
+                                   goto gottype;
+                       if(*ep == 'g' || *ep == 'G')
+                               i = 0;
+                       else
+                               i = -1;
+               }
+#endif
+       }
+#ifndef MAC
+gottype:
+#endif
+#endif
+       for(sroom = &rooms[0]; ; sroom++){
+               if(sroom->hx < 0) return;
+               if(sroom - rooms >= nroom) {
+                       pline("rooms not closed by -1?");
+                       return;
+               }
+               if(sroom->rtype != OROOM) continue;
+               if(has_dnstairs(sroom) || has_upstairs(sroom))
+                       continue;
+               if(
+#ifdef WIZARD
+                  (wizard && ep && sroom->doorct != 0) ||
+#endif
+                       sroom->doorct == 1) break;
+       }
+       if (!sroom->rlit) {
+               int x, y;
+
+               for(x = sroom->lx - 1; x <= sroom->hx + 1; x++)
+               for(y = sroom->ly - 1; y <= sroom->hy + 1; y++)
+                       levl[x][y].lit = 1;
+               sroom->rlit = 1;
+       }
+
+       if(i < 0) {                     /* shoptype not yet determined */
+           register int j;
+
+           /* pick a shop type at random */
+           for (j = rnd(100), i = 0; (j -= shtypes[i].prob) > 0; i++)
+               continue;
+
+           /* big rooms cannot be wand or book shops,
+            * - so make them general stores
+            */
+           if(isbig(sroom) && (shtypes[i].symb == WAND_CLASS
+                               || shtypes[i].symb == SPBOOK_CLASS)) i = 0;
+       }
+       sroom->rtype = SHOPBASE + i;
+
+       /* set room bits before stocking the shop */
+#ifdef SPECIALIZATION
+       topologize(sroom, FALSE); /* doesn't matter - this is a special room */
+#else
+       topologize(sroom);
+#endif
+
+       /* stock the room with a shopkeeper and artifacts */
+       stock_room(i, sroom);
+}
+
+STATIC_OVL struct mkroom *
+pick_room(strict)
+register boolean strict;
+/* pick an unused room, preferably with only one door */
+{
+       register struct mkroom *sroom;
+       register int i = nroom;
+
+       for(sroom = &rooms[rn2(nroom)]; i--; sroom++) {
+               if(sroom == &rooms[nroom])
+                       sroom = &rooms[0];
+               if(sroom->hx < 0)
+                       return (struct mkroom *)0;
+               if(sroom->rtype != OROOM)       continue;
+               if(!strict) {
+                   if(has_upstairs(sroom) || (has_dnstairs(sroom) && rn2(3)))
+                       continue;
+               } else if(has_upstairs(sroom) || has_dnstairs(sroom))
+                       continue;
+               if(sroom->doorct == 1 || !rn2(5)
+#ifdef WIZARD
+                                               || wizard
+#endif
+                                                       )
+                       return sroom;
+       }
+       return (struct mkroom *)0;
+}
+
+STATIC_OVL void
+mkzoo(type)
+int type;
+{
+       register struct mkroom *sroom;
+
+       if ((sroom = pick_room(FALSE)) != 0) {
+               sroom->rtype = type;
+               fill_zoo(sroom);
+       }
+}
+
+void
+fill_zoo(sroom)
+struct mkroom *sroom;
+{
+       struct monst *mon;
+       register int sx,sy,i;
+       int sh, tx, ty, goldlim, type = sroom->rtype;
+       int rmno = (sroom - rooms) + ROOMOFFSET;
+       coord mm;
+
+#ifdef GCC_WARN
+       tx = ty = goldlim = 0;
+#endif
+
+       sh = sroom->fdoor;
+       switch(type) {
+           case COURT:
+               if(level.flags.is_maze_lev) {
+                   for(tx = sroom->lx; tx <= sroom->hx; tx++)
+                       for(ty = sroom->ly; ty <= sroom->hy; ty++)
+                           if(IS_THRONE(levl[tx][ty].typ))
+                               goto throne_placed;
+               }
+               i = 100;
+               do {    /* don't place throne on top of stairs */
+                       (void) somexy(sroom, &mm);
+                       tx = mm.x; ty = mm.y;
+               } while (occupied((xchar)tx, (xchar)ty) && --i > 0);
+           throne_placed:
+               /* TODO: try to ensure the enthroned monster is an M2_PRINCE */
+               break;
+           case BEEHIVE:
+               tx = sroom->lx + (sroom->hx - sroom->lx + 1)/2;
+               ty = sroom->ly + (sroom->hy - sroom->ly + 1)/2;
+               if(sroom->irregular) {
+                   /* center might not be valid, so put queen elsewhere */
+                   if ((int) levl[tx][ty].roomno != rmno ||
+                           levl[tx][ty].edge) {
+                       (void) somexy(sroom, &mm);
+                       tx = mm.x; ty = mm.y;
+                   }
+               }
+               break;
+           case ZOO:
+           case LEPREHALL:
+               goldlim = 500 * level_difficulty();
+               break;
+       }
+       for(sx = sroom->lx; sx <= sroom->hx; sx++)
+           for(sy = sroom->ly; sy <= sroom->hy; sy++) {
+               if(sroom->irregular) {
+                   if ((int) levl[sx][sy].roomno != rmno ||
+                         levl[sx][sy].edge ||
+                         (sroom->doorct &&
+                          distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1))
+                       continue;
+               } else if(!SPACE_POS(levl[sx][sy].typ) ||
+                         (sroom->doorct &&
+                          ((sx == sroom->lx && doors[sh].x == sx-1) ||
+                           (sx == sroom->hx && doors[sh].x == sx+1) ||
+                           (sy == sroom->ly && doors[sh].y == sy-1) ||
+                           (sy == sroom->hy && doors[sh].y == sy+1))))
+                   continue;
+               /* don't place monster on explicitly placed throne */
+               if(type == COURT && IS_THRONE(levl[sx][sy].typ))
+                   continue;
+               mon = makemon(
+                   (type == COURT) ? courtmon() :
+                   (type == BARRACKS) ? squadmon() :
+                   (type == MORGUE) ? morguemon() :
+                   (type == BEEHIVE) ?
+                       (sx == tx && sy == ty ? &mons[PM_QUEEN_BEE] :
+                        &mons[PM_KILLER_BEE]) :
+                   (type == LEPREHALL) ? &mons[PM_LEPRECHAUN] :
+                   (type == COCKNEST) ? &mons[PM_COCKATRICE] :
+                   (type == ANTHOLE) ? antholemon() :
+                   (struct permonst *) 0,
+                  sx, sy, NO_MM_FLAGS);
+               if(mon) {
+                       mon->msleeping = 1;
+                       if (type==COURT && mon->mpeaceful) {
+                               mon->mpeaceful = 0;
+                               set_malign(mon);
+                       }
+               }
+               switch(type) {
+                   case ZOO:
+                   case LEPREHALL:
+                       if(sroom->doorct)
+                       {
+                           int distval = dist2(sx,sy,doors[sh].x,doors[sh].y);
+                           i = sq(distval);
+                       }
+                       else
+                           i = goldlim;
+                       if(i >= goldlim) i = 5*level_difficulty();
+                       goldlim -= i;
+                       (void) mkgold((long) rn1(i, 10), sx, sy);
+                       break;
+                   case MORGUE:
+                       if(!rn2(5))
+                           (void) mk_tt_object(CORPSE, sx, sy);
+                       if(!rn2(10))    /* lots of treasure buried with dead */
+                           (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
+                                            sx, sy, TRUE, FALSE);
+                       if (!rn2(5))
+                           make_grave(sx, sy, (char *)0);
+                       break;
+                   case BEEHIVE:
+                       if(!rn2(3))
+                           (void) mksobj_at(LUMP_OF_ROYAL_JELLY,
+                                            sx, sy, TRUE, FALSE);
+                       break;
+                   case BARRACKS:
+                       if(!rn2(20))    /* the payroll and some loot */
+                           (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
+                                            sx, sy, TRUE, FALSE);
+                       break;
+                   case COCKNEST:
+                       if(!rn2(3)) {
+                           struct obj *sobj = mk_tt_object(STATUE, sx, sy);
+
+                           if (sobj) {
+                               for (i = rn2(5); i; i--)
+                                   (void) add_to_container(sobj,
+                                               mkobj(RANDOM_CLASS, FALSE));
+                               sobj->owt = weight(sobj);
+                           }
+                       }
+                       break;
+                   case ANTHOLE:
+                       if(!rn2(3))
+                           (void) mkobj_at(FOOD_CLASS, sx, sy, FALSE);
+                       break;
+               }
+           }
+       switch (type) {
+             case COURT:
+               {
+                 struct obj *chest;
+                 levl[tx][ty].typ = THRONE;
+                 (void) somexy(sroom, &mm);
+                 (void) mkgold((long) rn1(50 * level_difficulty(),10), mm.x, mm.y);
+                 /* the royal coffers */
+                 chest = mksobj_at(CHEST, mm.x, mm.y, TRUE, FALSE);
+                 chest->spe = 2; /* so it can be found later */
+                 level.flags.has_court = 1;
+                 break;
+               }
+             case BARRACKS:
+                 level.flags.has_barracks = 1;
+                 break;
+             case ZOO:
+                 level.flags.has_zoo = 1;
+                 break;
+             case MORGUE:
+                 level.flags.has_morgue = 1;
+                 break;
+             case SWAMP:
+                 level.flags.has_swamp = 1;
+                 break;
+             case BEEHIVE:
+                 level.flags.has_beehive = 1;
+                 break;
+       }
+}
+
+/* make a swarm of undead around mm */
+void
+mkundead(mm, revive_corpses, mm_flags)
+coord *mm;
+boolean revive_corpses;
+int mm_flags;
+{
+       int cnt = (level_difficulty() + 1)/10 + rnd(5);
+       struct permonst *mdat;
+       struct obj *otmp;
+       coord cc;
+
+       while (cnt--) {
+           mdat = morguemon();
+           if (enexto(&cc, mm->x, mm->y, mdat) &&
+                   (!revive_corpses ||
+                    !(otmp = sobj_at(CORPSE, cc.x, cc.y)) ||
+                    !revive(otmp)))
+               (void) makemon(mdat, cc.x, cc.y, mm_flags);
+       }
+       level.flags.graveyard = TRUE;   /* reduced chance for undead corpse */
+}
+
+STATIC_OVL struct permonst *
+morguemon()
+{
+       register int i = rn2(100), hd = rn2(level_difficulty());
+
+       if(hd > 10 && i < 10)
+               return((Inhell || In_endgame(&u.uz)) ? mkclass(S_DEMON,0) :
+                                                      &mons[ndemon(A_NONE)]);
+       if(hd > 8 && i > 85)
+               return(mkclass(S_VAMPIRE,0));
+
+       return((i < 20) ? &mons[PM_GHOST]
+                       : (i < 40) ? &mons[PM_WRAITH] : mkclass(S_ZOMBIE,0));
+}
+
+STATIC_OVL struct permonst *
+antholemon()
+{
+       int mtyp;
+
+       /* Same monsters within a level, different ones between levels */
+       switch ((level_difficulty() + ((long)u.ubirthday)) % 3) {
+       default:        mtyp = PM_GIANT_ANT; break;
+       case 0:         mtyp = PM_SOLDIER_ANT; break;
+       case 1:         mtyp = PM_FIRE_ANT; break;
+       }
+       return ((mvitals[mtyp].mvflags & G_GONE) ?
+                       (struct permonst *)0 : &mons[mtyp]);
+}
+
+STATIC_OVL void
+mkswamp()      /* Michiel Huisjes & Fred de Wilde */
+{
+       register struct mkroom *sroom;
+       register int sx,sy,i,eelct = 0;
+
+       for(i=0; i<5; i++) {            /* turn up to 5 rooms swampy */
+               sroom = &rooms[rn2(nroom)];
+               if(sroom->hx < 0 || sroom->rtype != OROOM ||
+                  has_upstairs(sroom) || has_dnstairs(sroom))
+                       continue;
+
+               /* satisfied; make a swamp */
+               sroom->rtype = SWAMP;
+               for(sx = sroom->lx; sx <= sroom->hx; sx++)
+               for(sy = sroom->ly; sy <= sroom->hy; sy++)
+               if(!OBJ_AT(sx, sy) &&
+                  !MON_AT(sx, sy) && !t_at(sx,sy) && !nexttodoor(sx,sy)) {
+                   if((sx+sy)%2) {
+                       levl[sx][sy].typ = POOL;
+                       if(!eelct || !rn2(4)) {
+                           /* mkclass() won't do, as we might get kraken */
+                           (void) makemon(rn2(5) ? &mons[PM_GIANT_EEL]
+                                                 : rn2(2) ? &mons[PM_PIRANHA]
+                                                 : &mons[PM_ELECTRIC_EEL],
+                                               sx, sy, NO_MM_FLAGS);
+                           eelct++;
+                       }
+                   } else
+                       if(!rn2(4))     /* swamps tend to be moldy */
+                           (void) makemon(mkclass(S_FUNGUS,0),
+                                               sx, sy, NO_MM_FLAGS);
+               }
+               level.flags.has_swamp = 1;
+       }
+}
+
+STATIC_OVL coord *
+shrine_pos(roomno)
+int roomno;
+{
+       static coord buf;
+       struct mkroom *troom = &rooms[roomno - ROOMOFFSET];
+
+       buf.x = troom->lx + ((troom->hx - troom->lx) / 2);
+       buf.y = troom->ly + ((troom->hy - troom->ly) / 2);
+       return(&buf);
+}
+
+STATIC_OVL void
+mktemple()
+{
+       register struct mkroom *sroom;
+       coord *shrine_spot;
+       register struct rm *lev;
+
+       if(!(sroom = pick_room(TRUE))) return;
+
+       /* set up Priest and shrine */
+       sroom->rtype = TEMPLE;
+       /*
+        * In temples, shrines are blessed altars
+        * located in the center of the room
+        */
+       shrine_spot = shrine_pos((sroom - rooms) + ROOMOFFSET);
+       lev = &levl[shrine_spot->x][shrine_spot->y];
+       lev->typ = ALTAR;
+       lev->altarmask = induced_align(80);
+       priestini(&u.uz, sroom, shrine_spot->x, shrine_spot->y, FALSE);
+       lev->altarmask |= AM_SHRINE;
+       level.flags.has_temple = 1;
+}
+
+boolean
+nexttodoor(sx,sy)
+register int sx, sy;
+{
+       register int dx, dy;
+       register struct rm *lev;
+       for(dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++) {
+               if(!isok(sx+dx, sy+dy)) continue;
+               if(IS_DOOR((lev = &levl[sx+dx][sy+dy])->typ) ||
+                   lev->typ == SDOOR)
+                       return(TRUE);
+       }
+       return(FALSE);
+}
+
+boolean
+has_dnstairs(sroom)
+register struct mkroom *sroom;
+{
+       if (sroom == dnstairs_room)
+               return TRUE;
+       if (sstairs.sx && !sstairs.up)
+               return((boolean)(sroom == sstairs_room));
+       return FALSE;
+}
+
+boolean
+has_upstairs(sroom)
+register struct mkroom *sroom;
+{
+       if (sroom == upstairs_room)
+               return TRUE;
+       if (sstairs.sx && sstairs.up)
+               return((boolean)(sroom == sstairs_room));
+       return FALSE;
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+int
+somex(croom)
+register struct mkroom *croom;
+{
+       return rn2(croom->hx-croom->lx+1) + croom->lx;
+}
+
+int
+somey(croom)
+register struct mkroom *croom;
+{
+       return rn2(croom->hy-croom->ly+1) + croom->ly;
+}
+
+boolean
+inside_room(croom, x, y)
+struct mkroom *croom;
+xchar x, y;
+{
+       return((boolean)(x >= croom->lx-1 && x <= croom->hx+1 &&
+               y >= croom->ly-1 && y <= croom->hy+1));
+}
+
+boolean
+somexy(croom, c)
+struct mkroom *croom;
+coord *c;
+{
+       int try_cnt = 0;
+       int i;
+
+       if (croom->irregular) {
+           i = (croom - rooms) + ROOMOFFSET;
+
+           while(try_cnt++ < 100) {
+               c->x = somex(croom);
+               c->y = somey(croom);
+               if (!levl[c->x][c->y].edge &&
+                       (int) levl[c->x][c->y].roomno == i)
+                   return TRUE;
+           }
+           /* try harder; exhaustively search until one is found */
+           for(c->x = croom->lx; c->x <= croom->hx; c->x++)
+               for(c->y = croom->ly; c->y <= croom->hy; c->y++)
+                   if (!levl[c->x][c->y].edge &&
+                           (int) levl[c->x][c->y].roomno == i)
+                       return TRUE;
+           return FALSE;
+       }
+
+       if (!croom->nsubrooms) {
+               c->x = somex(croom);
+               c->y = somey(croom);
+               return TRUE;
+       }
+
+       /* Check that coords doesn't fall into a subroom or into a wall */
+
+       while(try_cnt++ < 100) {
+               c->x = somex(croom);
+               c->y = somey(croom);
+               if (IS_WALL(levl[c->x][c->y].typ))
+                   continue;
+               for(i=0 ; i<croom->nsubrooms;i++)
+                   if(inside_room(croom->sbrooms[i], c->x, c->y))
+                       goto you_lose;
+               break;
+you_lose:      ;
+       }
+       if (try_cnt >= 100)
+           return FALSE;
+       return TRUE;
+}
+
+/*
+ * Search for a special room given its type (zoo, court, etc...)
+ *     Special values :
+ *             - ANY_SHOP
+ *             - ANY_TYPE
+ */
+
+struct mkroom *
+search_special(type)
+schar type;
+{
+       register struct mkroom *croom;
+
+       for(croom = &rooms[0]; croom->hx >= 0; croom++)
+           if((type == ANY_TYPE && croom->rtype != OROOM) ||
+              (type == ANY_SHOP && croom->rtype >= SHOPBASE) ||
+              croom->rtype == type)
+               return croom;
+       for(croom = &subrooms[0]; croom->hx >= 0; croom++)
+           if((type == ANY_TYPE && croom->rtype != OROOM) ||
+              (type == ANY_SHOP && croom->rtype >= SHOPBASE) ||
+              croom->rtype == type)
+               return croom;
+       return (struct mkroom *) 0;
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+struct permonst *
+courtmon()
+{
+       int     i = rn2(60) + rn2(3*level_difficulty());
+       if (i > 100)            return(mkclass(S_DRAGON,0));
+       else if (i > 95)        return(mkclass(S_GIANT,0));
+       else if (i > 85)        return(mkclass(S_TROLL,0));
+       else if (i > 75)        return(mkclass(S_CENTAUR,0));
+       else if (i > 60)        return(mkclass(S_ORC,0));
+       else if (i > 45)        return(&mons[PM_BUGBEAR]);
+       else if (i > 30)        return(&mons[PM_HOBGOBLIN]);
+       else if (i > 15)        return(mkclass(S_GNOME,0));
+       else                    return(mkclass(S_KOBOLD,0));
+}
+
+#define NSTYPES (PM_CAPTAIN - PM_SOLDIER + 1)
+
+static struct {
+    unsigned   pm;
+    unsigned   prob;
+} squadprob[NSTYPES] = {
+    {PM_SOLDIER, 80}, {PM_SERGEANT, 15}, {PM_LIEUTENANT, 4}, {PM_CAPTAIN, 1}
+};
+
+STATIC_OVL struct permonst *
+squadmon()             /* return soldier types. */
+{
+       int sel_prob, i, cpro, mndx;
+
+       sel_prob = rnd(80+level_difficulty());
+
+       cpro = 0;
+       for (i = 0; i < NSTYPES; i++) {
+           cpro += squadprob[i].prob;
+           if (cpro > sel_prob) {
+               mndx = squadprob[i].pm;
+               goto gotone;
+           }
+       }
+       mndx = squadprob[rn2(NSTYPES)].pm;
+gotone:
+       if (!(mvitals[mndx].mvflags & G_GONE)) return(&mons[mndx]);
+       else                        return((struct permonst *) 0);
+}
+
+/*
+ * save_room : A recursive function that saves a room and its subrooms
+ * (if any).
+ */
+
+STATIC_OVL void
+save_room(fd, r)
+int    fd;
+struct mkroom *r;
+{
+       short i;
+       /*
+        * Well, I really should write only useful information instead
+        * of writing the whole structure. That is I should not write
+        * the subrooms pointers, but who cares ?
+        */
+       bwrite(fd, (genericptr_t) r, sizeof(struct mkroom));
+       for(i=0; i<r->nsubrooms; i++)
+           save_room(fd, r->sbrooms[i]);
+}
+
+/*
+ * save_rooms : Save all the rooms on disk!
+ */
+
+void
+save_rooms(fd)
+int fd;
+{
+       short i;
+
+       /* First, write the number of rooms */
+       bwrite(fd, (genericptr_t) &nroom, sizeof(nroom));
+       for(i=0; i<nroom; i++)
+           save_room(fd, &rooms[i]);
+}
+
+STATIC_OVL void
+rest_room(fd, r)
+int fd;
+struct mkroom *r;
+{
+       short i;
+
+       mread(fd, (genericptr_t) r, sizeof(struct mkroom));
+       for(i=0; i<r->nsubrooms; i++) {
+               r->sbrooms[i] = &subrooms[nsubroom];
+               rest_room(fd, &subrooms[nsubroom]);
+               subrooms[nsubroom++].resident = (struct monst *)0;
+       }
+}
+
+/*
+ * rest_rooms : That's for restoring rooms. Read the rooms structure from
+ * the disk.
+ */
+
+void
+rest_rooms(fd)
+int    fd;
+{
+       short i;
+
+       mread(fd, (genericptr_t) &nroom, sizeof(nroom));
+       nsubroom = 0;
+       for(i = 0; i<nroom; i++) {
+           rest_room(fd, &rooms[i]);
+           rooms[i].resident = (struct monst *)0;
+       }
+       rooms[nroom].hx = -1;           /* restore ending flags */
+       subrooms[nsubroom].hx = -1;
+}
+#endif /* OVLB */
+
+/*mkroom.c*/
diff --git a/src/mon.c b/src/mon.c
new file mode 100644 (file)
index 0000000..c769953
--- /dev/null
+++ b/src/mon.c
@@ -0,0 +1,2817 @@
+/*     SCCS Id: @(#)mon.c      3.4     2003/12/04      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* If you're using precompiled headers, you don't want this either */
+#ifdef MICROPORT_BUG
+#define MKROOM_H
+#endif
+
+#include "hack.h"
+#include "mfndpos.h"
+#include "edog.h"
+#include <ctype.h>
+
+STATIC_DCL boolean FDECL(restrap,(struct monst *));
+STATIC_DCL long FDECL(mm_aggression, (struct monst *,struct monst *));
+#ifdef OVL2
+STATIC_DCL int NDECL(pick_animal);
+STATIC_DCL int FDECL(select_newcham_form, (struct monst *));
+STATIC_DCL void FDECL(kill_eggs, (struct obj *));
+#endif
+
+#ifdef REINCARNATION
+#define LEVEL_SPECIFIC_NOCORPSE(mdat) \
+        (Is_rogue_level(&u.uz) || \
+          (level.flags.graveyard && is_undead(mdat) && rn2(3)))
+#else
+#define LEVEL_SPECIFIC_NOCORPSE(mdat) \
+          (level.flags.graveyard && is_undead(mdat) && rn2(3))
+#endif
+
+
+#if 0
+/* part of the original warning code which was replaced in 3.3.1 */
+#ifdef OVL1
+#define warnDelay 10
+long lastwarntime;
+int lastwarnlev;
+
+const char *warnings[] = {
+       "white", "pink", "red", "ruby", "purple", "black"
+};
+
+STATIC_DCL void NDECL(warn_effects);
+#endif /* OVL1 */
+#endif /* 0 */
+
+#ifndef OVLB
+STATIC_VAR short cham_to_pm[];
+#else
+STATIC_DCL struct obj *FDECL(make_corpse,(struct monst *));
+STATIC_DCL void FDECL(m_detach, (struct monst *, struct permonst *));
+STATIC_DCL void FDECL(lifesaved_monster, (struct monst *));
+
+/* convert the monster index of an undead to its living counterpart */
+int
+undead_to_corpse(mndx)
+int mndx;
+{
+       switch (mndx) {
+       case PM_KOBOLD_ZOMBIE:
+       case PM_KOBOLD_MUMMY:   mndx = PM_KOBOLD;  break;
+       case PM_DWARF_ZOMBIE:
+       case PM_DWARF_MUMMY:    mndx = PM_DWARF;  break;
+       case PM_GNOME_ZOMBIE:
+       case PM_GNOME_MUMMY:    mndx = PM_GNOME;  break;
+       case PM_ORC_ZOMBIE:
+       case PM_ORC_MUMMY:      mndx = PM_ORC;  break;
+       case PM_ELF_ZOMBIE:
+       case PM_ELF_MUMMY:      mndx = PM_ELF;  break;
+       case PM_VAMPIRE:
+       case PM_VAMPIRE_LORD:
+#if 0  /* DEFERRED */
+       case PM_VAMPIRE_MAGE:
+#endif
+       case PM_HUMAN_ZOMBIE:
+       case PM_HUMAN_MUMMY:    mndx = PM_HUMAN;  break;
+       case PM_GIANT_ZOMBIE:
+       case PM_GIANT_MUMMY:    mndx = PM_GIANT;  break;
+       case PM_ETTIN_ZOMBIE:
+       case PM_ETTIN_MUMMY:    mndx = PM_ETTIN;  break;
+       default:  break;
+       }
+       return mndx;
+}
+
+/* Convert the monster index of some monsters (such as quest guardians)
+ * to their generic species type.
+ *
+ * Return associated character class monster, rather than species
+ * if mode is 1.
+ */
+int
+genus(mndx, mode)
+int mndx, mode;
+{
+       switch (mndx) {
+/* Quest guardians */
+       case PM_STUDENT:     mndx = mode ? PM_ARCHEOLOGIST  : PM_HUMAN; break;
+       case PM_CHIEFTAIN:   mndx = mode ? PM_BARBARIAN : PM_HUMAN; break;
+       case PM_NEANDERTHAL: mndx = mode ? PM_CAVEMAN   : PM_HUMAN; break;
+       case PM_ATTENDANT:   mndx = mode ? PM_HEALER    : PM_HUMAN; break;
+       case PM_PAGE:        mndx = mode ? PM_KNIGHT    : PM_HUMAN; break;
+       case PM_ABBOT:       mndx = mode ? PM_MONK      : PM_HUMAN; break;
+       case PM_ACOLYTE:     mndx = mode ? PM_PRIEST    : PM_HUMAN; break;
+       case PM_HUNTER:      mndx = mode ? PM_RANGER    : PM_HUMAN; break;
+       case PM_THUG:        mndx = mode ? PM_ROGUE     : PM_HUMAN; break;
+       case PM_ROSHI:       mndx = mode ? PM_SAMURAI   : PM_HUMAN; break;
+#ifdef TOURIST
+       case PM_GUIDE:       mndx = mode ? PM_TOURIST   : PM_HUMAN; break;
+#endif
+       case PM_APPRENTICE:  mndx = mode ? PM_WIZARD    : PM_HUMAN; break;
+       case PM_WARRIOR:     mndx = mode ? PM_VALKYRIE  : PM_HUMAN; break;
+       default:
+               if (mndx >= LOW_PM && mndx < NUMMONS) {
+                       struct permonst *ptr = &mons[mndx];
+                       if (is_human(ptr))      mndx = PM_HUMAN;
+                       else if (is_elf(ptr))   mndx = PM_ELF;
+                       else if (is_dwarf(ptr)) mndx = PM_DWARF;
+                       else if (is_gnome(ptr)) mndx = PM_GNOME;
+                       else if (is_orc(ptr))   mndx = PM_ORC;
+               }
+               break;
+       }
+       return mndx;
+}
+
+/* convert monster index to chameleon index */
+int
+pm_to_cham(mndx)
+int mndx;
+{
+       int mcham;
+
+       switch (mndx) {
+       case PM_CHAMELEON:      mcham = CHAM_CHAMELEON; break;
+       case PM_DOPPELGANGER:   mcham = CHAM_DOPPELGANGER; break;
+       case PM_SANDESTIN:      mcham = CHAM_SANDESTIN; break;
+       default: mcham = CHAM_ORDINARY; break;
+       }
+       return mcham;
+}
+
+/* convert chameleon index to monster index */
+STATIC_VAR short cham_to_pm[] = {
+               NON_PM,         /* placeholder for CHAM_ORDINARY */
+               PM_CHAMELEON,
+               PM_DOPPELGANGER,
+               PM_SANDESTIN,
+};
+
+/* for deciding whether corpse or statue will carry along full monster data */
+#define KEEPTRAITS(mon)        ((mon)->isshk || (mon)->mtame ||                \
+                        ((mon)->data->geno & G_UNIQ) ||                \
+                        is_reviver((mon)->data) ||                     \
+                        /* normally leader the will be unique, */      \
+                        /* but he might have been polymorphed  */      \
+                        (mon)->m_id == quest_status.leader_m_id ||     \
+                        /* special cancellation handling for these */  \
+                        (dmgtype((mon)->data, AD_SEDU) ||              \
+                         dmgtype((mon)->data, AD_SSEX)))
+
+/* Creates a monster corpse, a "special" corpse, or nothing if it doesn't
+ * leave corpses.  Monsters which leave "special" corpses should have
+ * G_NOCORPSE set in order to prevent wishing for one, finding tins of one,
+ * etc....
+ */
+STATIC_OVL struct obj *
+make_corpse(mtmp)
+register struct monst *mtmp;
+{
+       register struct permonst *mdat = mtmp->data;
+       int num;
+       struct obj *obj = (struct obj *)0;
+       int x = mtmp->mx, y = mtmp->my;
+       int mndx = monsndx(mdat);
+
+       switch(mndx) {
+           case PM_GRAY_DRAGON:
+           case PM_SILVER_DRAGON:
+#if 0  /* DEFERRED */
+           case PM_SHIMMERING_DRAGON:
+#endif
+           case PM_RED_DRAGON:
+           case PM_ORANGE_DRAGON:
+           case PM_WHITE_DRAGON:
+           case PM_BLACK_DRAGON:
+           case PM_BLUE_DRAGON:
+           case PM_GREEN_DRAGON:
+           case PM_YELLOW_DRAGON:
+               /* Make dragon scales.  This assumes that the order of the */
+               /* dragons is the same as the order of the scales.         */
+               if (!rn2(mtmp->mrevived ? 20 : 3)) {
+                   num = GRAY_DRAGON_SCALES + monsndx(mdat) - PM_GRAY_DRAGON;
+                   obj = mksobj_at(num, x, y, FALSE, FALSE);
+                   obj->spe = 0;
+                   obj->cursed = obj->blessed = FALSE;
+               }
+               goto default_1;
+
+           case PM_WHITE_UNICORN:
+           case PM_GRAY_UNICORN:
+           case PM_BLACK_UNICORN:
+               if (mtmp->mrevived && rn2(20)) {
+                       if (canseemon(mtmp))
+                          pline("%s recently regrown horn crumbles to dust.",
+                               s_suffix(Monnam(mtmp)));
+               } else
+                       (void) mksobj_at(UNICORN_HORN, x, y, TRUE, FALSE);
+               goto default_1;
+           case PM_LONG_WORM:
+               (void) mksobj_at(WORM_TOOTH, x, y, TRUE, FALSE);
+               goto default_1;
+           case PM_VAMPIRE:
+           case PM_VAMPIRE_LORD:
+               /* include mtmp in the mkcorpstat() call */
+               num = undead_to_corpse(mndx);
+               obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, TRUE);
+               obj->age -= 100;                /* this is an *OLD* corpse */
+               break;
+           case PM_KOBOLD_MUMMY:
+           case PM_DWARF_MUMMY:
+           case PM_GNOME_MUMMY:
+           case PM_ORC_MUMMY:
+           case PM_ELF_MUMMY:
+           case PM_HUMAN_MUMMY:
+           case PM_GIANT_MUMMY:
+           case PM_ETTIN_MUMMY:
+           case PM_KOBOLD_ZOMBIE:
+           case PM_DWARF_ZOMBIE:
+           case PM_GNOME_ZOMBIE:
+           case PM_ORC_ZOMBIE:
+           case PM_ELF_ZOMBIE:
+           case PM_HUMAN_ZOMBIE:
+           case PM_GIANT_ZOMBIE:
+           case PM_ETTIN_ZOMBIE:
+               num = undead_to_corpse(mndx);
+               obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, TRUE);
+               obj->age -= 100;                /* this is an *OLD* corpse */
+               break;
+           case PM_IRON_GOLEM:
+               num = d(2,6);
+               while (num--)
+                       obj = mksobj_at(IRON_CHAIN, x, y, TRUE, FALSE);
+               mtmp->mnamelth = 0;
+               break;
+           case PM_GLASS_GOLEM:
+               num = d(2,4);   /* very low chance of creating all glass gems */
+               while (num--)
+                       obj = mksobj_at((LAST_GEM + rnd(9)), x, y, TRUE, FALSE);
+               mtmp->mnamelth = 0;
+               break;
+           case PM_CLAY_GOLEM:
+               obj = mksobj_at(ROCK, x, y, FALSE, FALSE);
+               obj->quan = (long)(rn2(20) + 50);
+               obj->owt = weight(obj);
+               mtmp->mnamelth = 0;
+               break;
+           case PM_STONE_GOLEM:
+               obj = mkcorpstat(STATUE, (struct monst *)0,
+                       mdat, x, y, FALSE);
+               break;
+           case PM_WOOD_GOLEM:
+               num = d(2,4);
+               while(num--) {
+                       obj = mksobj_at(QUARTERSTAFF, x, y, TRUE, FALSE);
+               }
+               mtmp->mnamelth = 0;
+               break;
+           case PM_LEATHER_GOLEM:
+               num = d(2,4);
+               while(num--)
+                       obj = mksobj_at(LEATHER_ARMOR, x, y, TRUE, FALSE);
+               mtmp->mnamelth = 0;
+               break;
+           case PM_GOLD_GOLEM:
+               /* Good luck gives more coins */
+               obj = mkgold((long)(200 - rnl(101)), x, y);
+               mtmp->mnamelth = 0;
+               break;
+           case PM_PAPER_GOLEM:
+               num = rnd(4);
+               while (num--)
+                       obj = mksobj_at(SCR_BLANK_PAPER, x, y, TRUE, FALSE);
+               mtmp->mnamelth = 0;
+               break;
+           default_1:
+           default:
+               if (mvitals[mndx].mvflags & G_NOCORPSE)
+                   return (struct obj *)0;
+               else    /* preserve the unique traits of some creatures */
+                   obj = mkcorpstat(CORPSE, KEEPTRAITS(mtmp) ? mtmp : 0,
+                                    mdat, x, y, TRUE);
+               break;
+       }
+       /* All special cases should precede the G_NOCORPSE check */
+
+       /* if polymorph or undead turning has killed this monster,
+          prevent the same attack beam from hitting its corpse */
+       if (flags.bypasses) bypass_obj(obj);
+
+       if (mtmp->mnamelth)
+           obj = oname(obj, NAME(mtmp));
+
+       /* Avoid "It was hidden under a green mold corpse!" 
+        *  during Blind combat. An unseen monster referred to as "it"
+        *  could be killed and leave a corpse.  If a hider then hid
+        *  underneath it, you could be told the corpse type of a
+        *  monster that you never knew was there without this.
+        *  The code in hitmu() substitutes the word "something"
+        *  if the corpses obj->dknown is 0.
+        */
+       if (Blind && !sensemon(mtmp)) obj->dknown = 0;
+
+#ifdef INVISIBLE_OBJECTS
+       /* Invisible monster ==> invisible corpse */
+       obj->oinvis = mtmp->minvis;
+#endif
+
+       stackobj(obj);
+       newsym(x, y);
+       return obj;
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+#if 0
+/* part of the original warning code which was replaced in 3.3.1 */
+STATIC_OVL void
+warn_effects()
+{
+    if (warnlevel == 100) {
+       if(!Blind && uwep &&
+           (warnlevel > lastwarnlev || moves > lastwarntime + warnDelay)) {
+           Your("%s %s!", aobjnam(uwep, "glow"),
+               hcolor(NH_LIGHT_BLUE));
+           lastwarnlev = warnlevel;
+           lastwarntime = moves;
+       }
+       warnlevel = 0;
+       return;
+    }
+
+    if (warnlevel >= SIZE(warnings))
+       warnlevel = SIZE(warnings)-1;
+    if (!Blind &&
+           (warnlevel > lastwarnlev || moves > lastwarntime + warnDelay)) {
+       const char *which, *what, *how;
+       long rings = (EWarning & (LEFT_RING|RIGHT_RING));
+
+       if (rings) {
+           what = Hallucination ? "mood ring" : "ring";
+           how = "glows";      /* singular verb */
+           if (rings == LEFT_RING) {
+               which = "left ";
+           } else if (rings == RIGHT_RING) {
+               which = "right ";
+           } else {            /* both */
+               which = "";
+               what = (const char *) makeplural(what);
+               how = "glow";   /* plural verb */
+           }
+           Your("%s%s %s %s!", which, what, how, hcolor(warnings[warnlevel]));
+       } else {
+           if (Hallucination)
+               Your("spider-sense is tingling...");
+           else
+               You_feel("apprehensive as you sense a %s flash.",
+                   warnings[warnlevel]);
+       }
+
+       lastwarntime = moves;
+       lastwarnlev = warnlevel;
+    }
+}
+#endif /* 0 */
+
+/* check mtmp and water/lava for compatibility, 0 (survived), 1 (died) */
+int
+minliquid(mtmp)
+register struct monst *mtmp;
+{
+    boolean inpool, inlava, infountain;
+
+    inpool = is_pool(mtmp->mx,mtmp->my) &&
+            !is_flyer(mtmp->data) && !is_floater(mtmp->data);
+    inlava = is_lava(mtmp->mx,mtmp->my) &&
+            !is_flyer(mtmp->data) && !is_floater(mtmp->data);
+    infountain = IS_FOUNTAIN(levl[mtmp->mx][mtmp->my].typ);
+
+#ifdef STEED
+       /* Flying and levitation keeps our steed out of the liquid */
+       /* (but not water-walking or swimming) */
+       if (mtmp == u.usteed && (Flying || Levitation))
+               return (0);
+#endif
+
+    /* Gremlin multiplying won't go on forever since the hit points
+     * keep going down, and when it gets to 1 hit point the clone
+     * function will fail.
+     */
+    if (mtmp->data == &mons[PM_GREMLIN] && (inpool || infountain) && rn2(3)) {
+       if (split_mon(mtmp, (struct monst *)0))
+           dryup(mtmp->mx, mtmp->my, FALSE);
+       if (inpool) water_damage(mtmp->minvent, FALSE, FALSE);
+       return (0);
+    } else if (mtmp->data == &mons[PM_IRON_GOLEM] && inpool && !rn2(5)) {
+       int dam = d(2,6);
+       if (cansee(mtmp->mx,mtmp->my))
+           pline("%s rusts.", Monnam(mtmp));
+       mtmp->mhp -= dam;
+       if (mtmp->mhpmax > dam) mtmp->mhpmax -= dam;
+       if (mtmp->mhp < 1) {
+           mondead(mtmp);
+           if (mtmp->mhp < 1) return (1);
+       }
+       water_damage(mtmp->minvent, FALSE, FALSE);
+       return (0);
+    }
+
+    if (inlava) {
+       /*
+        * Lava effects much as water effects. Lava likers are able to
+        * protect their stuff. Fire resistant monsters can only protect
+        * themselves  --ALI
+        */
+       if (!is_clinger(mtmp->data) && !likes_lava(mtmp->data)) {
+           if (!resists_fire(mtmp)) {
+               if (cansee(mtmp->mx,mtmp->my))
+                   pline("%s %s.", Monnam(mtmp),
+                         mtmp->data == &mons[PM_WATER_ELEMENTAL] ?
+                         "boils away" : "burns to a crisp");
+               mondead(mtmp);
+           }
+           else {
+               if (--mtmp->mhp < 1) {
+                   if (cansee(mtmp->mx,mtmp->my))
+                       pline("%s surrenders to the fire.", Monnam(mtmp));
+                   mondead(mtmp);
+               }
+               else if (cansee(mtmp->mx,mtmp->my))
+                   pline("%s burns slightly.", Monnam(mtmp));
+           }
+           if (mtmp->mhp > 0) {
+               (void) fire_damage(mtmp->minvent, FALSE, FALSE,
+                                               mtmp->mx, mtmp->my);
+               (void) rloc(mtmp, FALSE);
+               return 0;
+           }
+           return (1);
+       }
+    } else if (inpool) {
+       /* Most monsters drown in pools.  flooreffects() will take care of
+        * water damage to dead monsters' inventory, but survivors need to
+        * be handled here.  Swimmers are able to protect their stuff...
+        */
+       if (!is_clinger(mtmp->data)
+           && !is_swimmer(mtmp->data) && !amphibious(mtmp->data)) {
+           if (cansee(mtmp->mx,mtmp->my)) {
+                   pline("%s drowns.", Monnam(mtmp));
+           }
+           if (u.ustuck && u.uswallow && u.ustuck == mtmp) {
+           /* This can happen after a purple worm plucks you off a
+               flying steed while you are over water. */
+               pline("%s sinks as water rushes in and flushes you out.",
+                       Monnam(mtmp));
+           }
+           mondead(mtmp);
+           if (mtmp->mhp > 0) {
+               (void) rloc(mtmp, FALSE);
+               water_damage(mtmp->minvent, FALSE, FALSE);
+               return 0;
+           }
+           return (1);
+       }
+    } else {
+       /* but eels have a difficult time outside */
+       if (mtmp->data->mlet == S_EEL && !Is_waterlevel(&u.uz)) {
+           if(mtmp->mhp > 1) mtmp->mhp--;
+           monflee(mtmp, 2, FALSE, FALSE);
+       }
+    }
+    return (0);
+}
+
+
+int
+mcalcmove(mon)
+struct monst *mon;
+{
+    int mmove = mon->data->mmove;
+
+    /* Note: MSLOW's `+ 1' prevents slowed speed 1 getting reduced to 0;
+     *      MFAST's `+ 2' prevents hasted speed 1 from becoming a no-op;
+     *      both adjustments have negligible effect on higher speeds.
+     */
+    if (mon->mspeed == MSLOW)
+       mmove = (2 * mmove + 1) / 3;
+    else if (mon->mspeed == MFAST)
+       mmove = (4 * mmove + 2) / 3;
+
+#ifdef STEED
+    if (mon == u.usteed) {
+       if (u.ugallop && flags.mv) {
+           /* average movement is 1.50 times normal */
+           mmove = ((rn2(2) ? 4 : 5) * mmove) / 3;
+       }
+    }
+#endif
+
+    return mmove;
+}
+
+/* actions that happen once per ``turn'', regardless of each
+   individual monster's metabolism; some of these might need to
+   be reclassified to occur more in proportion with movement rate */
+void
+mcalcdistress()
+{
+    struct monst *mtmp;
+
+    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+       if (DEADMONSTER(mtmp)) continue;
+
+       /* must check non-moving monsters once/turn in case
+        * they managed to end up in liquid */
+       if (mtmp->data->mmove == 0) {
+           if (vision_full_recalc) vision_recalc(0);
+           if (minliquid(mtmp)) continue;
+       }
+
+       /* regenerate hit points */
+       mon_regen(mtmp, FALSE);
+
+       /* possibly polymorph shapechangers and lycanthropes */
+       if (mtmp->cham && !rn2(6))
+           (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE);
+       were_change(mtmp);
+
+       /* gradually time out temporary problems */
+       if (mtmp->mblinded && !--mtmp->mblinded)
+           mtmp->mcansee = 1;
+       if (mtmp->mfrozen && !--mtmp->mfrozen)
+           mtmp->mcanmove = 1;
+       if (mtmp->mfleetim && !--mtmp->mfleetim)
+           mtmp->mflee = 0;
+
+       /* FIXME: mtmp->mlstmv ought to be updated here */
+    }
+}
+
+int
+movemon()
+{
+    register struct monst *mtmp, *nmtmp;
+    register boolean somebody_can_move = FALSE;
+#if 0
+    /* part of the original warning code which was replaced in 3.3.1 */
+    warnlevel = 0;
+#endif
+
+    /*
+    Some of you may remember the former assertion here that
+    because of deaths and other actions, a simple one-pass
+    algorithm wasn't possible for movemon.  Deaths are no longer
+    removed to the separate list fdmon; they are simply left in
+    the chain with hit points <= 0, to be cleaned up at the end
+    of the pass.
+
+    The only other actions which cause monsters to be removed from
+    the chain are level migrations and losedogs().  I believe losedogs()
+    is a cleanup routine not associated with monster movements, and
+    monsters can only affect level migrations on themselves, not others
+    (hence the fetching of nmon before moving the monster).  Currently,
+    monsters can jump into traps, read cursed scrolls of teleportation,
+    and drink cursed potions of raise level to change levels.  These are
+    all reflexive at this point.  Should one monster be able to level
+    teleport another, this scheme would have problems.
+    */
+
+    for(mtmp = fmon; mtmp; mtmp = nmtmp) {
+       nmtmp = mtmp->nmon;
+
+       /* Find a monster that we have not treated yet.  */
+       if(DEADMONSTER(mtmp))
+           continue;
+       if(mtmp->movement < NORMAL_SPEED)
+           continue;
+
+       mtmp->movement -= NORMAL_SPEED;
+       if (mtmp->movement >= NORMAL_SPEED)
+           somebody_can_move = TRUE;
+
+       if (vision_full_recalc) vision_recalc(0);       /* vision! */
+
+       if (minliquid(mtmp)) continue;
+
+       if (is_hider(mtmp->data)) {
+           /* unwatched mimics and piercers may hide again  [MRS] */
+           if(restrap(mtmp))   continue;
+           if(mtmp->m_ap_type == M_AP_FURNITURE ||
+                               mtmp->m_ap_type == M_AP_OBJECT)
+                   continue;
+           if(mtmp->mundetected) continue;
+       }
+
+       /* continue if the monster died fighting */
+       if (Conflict && !mtmp->iswiz && mtmp->mcansee) {
+           /* Note:
+            *  Conflict does not take effect in the first round.
+            *  Therefore, A monster when stepping into the area will
+            *  get to swing at you.
+            *
+            *  The call to fightm() must be _last_.  The monster might
+            *  have died if it returns 1.
+            */
+           if (couldsee(mtmp->mx,mtmp->my) &&
+               (distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) &&
+                                                       fightm(mtmp))
+               continue;       /* mon might have died */
+       }
+       if(dochugw(mtmp))               /* otherwise just move the monster */
+           continue;
+    }
+#if 0
+    /* part of the original warning code which was replaced in 3.3.1 */
+    if(warnlevel > 0)
+       warn_effects();
+#endif
+
+    if (any_light_source())
+       vision_full_recalc = 1; /* in case a mon moved with a light source */
+    dmonsfree();       /* remove all dead monsters */
+
+    /* a monster may have levteleported player -dlc */
+    if (u.utotype) {
+       deferred_goto();
+       /* changed levels, so these monsters are dormant */
+       somebody_can_move = FALSE;
+    }
+
+    return somebody_can_move;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+#define mstoning(obj)  (ofood(obj) && \
+                                       (touch_petrifies(&mons[(obj)->corpsenm]) || \
+                                       (obj)->corpsenm == PM_MEDUSA))
+
+/*
+ * Maybe eat a metallic object (not just gold).
+ * Return value: 0 => nothing happened, 1 => monster ate something,
+ * 2 => monster died (it must have grown into a genocided form, but
+ * that can't happen at present because nothing which eats objects
+ * has young and old forms).
+ */
+int
+meatmetal(mtmp)
+       register struct monst *mtmp;
+{
+       register struct obj *otmp;
+       struct permonst *ptr;
+       int poly, grow, heal, mstone;
+
+       /* If a pet, eating is handled separately, in dog.c */
+       if (mtmp->mtame) return 0;
+
+       /* Eats topmost metal object if it is there */
+       for (otmp = level.objects[mtmp->mx][mtmp->my];
+                                               otmp; otmp = otmp->nexthere) {
+           if (mtmp->data == &mons[PM_RUST_MONSTER] && !is_rustprone(otmp))
+               continue;
+           if (is_metallic(otmp) && !obj_resists(otmp, 5, 95) &&
+               touch_artifact(otmp,mtmp)) {
+               if (mtmp->data == &mons[PM_RUST_MONSTER] && otmp->oerodeproof) {
+                   if (canseemon(mtmp) && flags.verbose) {
+                       pline("%s eats %s!",
+                               Monnam(mtmp),
+                               distant_name(otmp,doname));
+                   }
+                   /* The object's rustproofing is gone now */
+                   otmp->oerodeproof = 0;
+                   mtmp->mstun = 1;
+                   if (canseemon(mtmp) && flags.verbose) {
+                       pline("%s spits %s out in disgust!",
+                             Monnam(mtmp), distant_name(otmp,doname));
+                   }
+               /* KMH -- Don't eat indigestible/choking objects */
+               } else if (otmp->otyp != AMULET_OF_STRANGULATION &&
+                               otmp->otyp != RIN_SLOW_DIGESTION) {
+                   if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
+                       pline("%s eats %s!", Monnam(mtmp),
+                               distant_name(otmp,doname));
+                   else if (flags.soundok && flags.verbose)
+                       You_hear("a crunching sound.");
+                   mtmp->meating = otmp->owt/2 + 1;
+                   /* Heal up to the object's weight in hp */
+                   if (mtmp->mhp < mtmp->mhpmax) {
+                       mtmp->mhp += objects[otmp->otyp].oc_weight;
+                       if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
+                   }
+                   if(otmp == uball) {
+                       unpunish();
+                       delobj(otmp);
+                   } else if (otmp == uchain) {
+                       unpunish();     /* frees uchain */
+                   } else {
+                       poly = polyfodder(otmp);
+                       grow = mlevelgain(otmp);
+                       heal = mhealup(otmp);
+                       mstone = mstoning(otmp);
+                       delobj(otmp);
+                       ptr = mtmp->data;
+                       if (poly) {
+                           if (newcham(mtmp, (struct permonst *)0,
+                                       FALSE, FALSE))
+                               ptr = mtmp->data;
+                       } else if (grow) {
+                           ptr = grow_up(mtmp, (struct monst *)0);
+                       } else if (mstone) {
+                           if (poly_when_stoned(ptr)) {
+                               mon_to_stone(mtmp);
+                               ptr = mtmp->data;
+                           } else if (!resists_ston(mtmp)) {
+                               if (canseemon(mtmp))
+                                   pline("%s turns to stone!", Monnam(mtmp));
+                               monstone(mtmp);
+                               ptr = (struct permonst *)0;
+                           }
+                       } else if (heal) {
+                           mtmp->mhp = mtmp->mhpmax;
+                       }
+                       if (!ptr) return 2;              /* it died */
+                   }
+                   /* Left behind a pile? */
+                   if (rnd(25) < 3)
+                       (void)mksobj_at(ROCK, mtmp->mx, mtmp->my, TRUE, FALSE);
+                   newsym(mtmp->mx, mtmp->my);
+                   return 1;
+               }
+           }
+       }
+       return 0;
+}
+
+int
+meatobj(mtmp)          /* for gelatinous cubes */
+       register struct monst *mtmp;
+{
+       register struct obj *otmp, *otmp2;
+       struct permonst *ptr;
+       int poly, grow, heal, count = 0, ecount = 0;
+       char buf[BUFSZ];
+
+       buf[0] = '\0';
+       /* If a pet, eating is handled separately, in dog.c */
+       if (mtmp->mtame) return 0;
+
+       /* Eats organic objects, including cloth and wood, if there */
+       /* Engulfs others, except huge rocks and metal attached to player */
+       for (otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) {
+           otmp2 = otmp->nexthere;
+           if (is_organic(otmp) && !obj_resists(otmp, 5, 95) &&
+                   touch_artifact(otmp,mtmp)) {
+               if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) &&
+                       !resists_ston(mtmp))
+                   continue;
+               if (otmp->otyp == AMULET_OF_STRANGULATION ||
+                               otmp->otyp == RIN_SLOW_DIGESTION)
+                   continue;
+               ++count;
+               if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
+                   pline("%s eats %s!", Monnam(mtmp),
+                           distant_name(otmp, doname));
+               else if (flags.soundok && flags.verbose)
+                   You_hear("a slurping sound.");
+               /* Heal up to the object's weight in hp */
+               if (mtmp->mhp < mtmp->mhpmax) {
+                   mtmp->mhp += objects[otmp->otyp].oc_weight;
+                   if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
+               }
+               if (Has_contents(otmp)) {
+                   register struct obj *otmp3;
+                   /* contents of eaten containers become engulfed; this
+                      is arbitrary, but otherwise g.cubes are too powerful */
+                   while ((otmp3 = otmp->cobj) != 0) {
+                       obj_extract_self(otmp3);
+                       if (otmp->otyp == ICE_BOX && otmp3->otyp == CORPSE) {
+                           otmp3->age = monstermoves - otmp3->age;
+                           start_corpse_timeout(otmp3);
+                       }
+                       (void) mpickobj(mtmp, otmp3);
+                   }
+               }
+               poly = polyfodder(otmp);
+               grow = mlevelgain(otmp);
+               heal = mhealup(otmp);
+               delobj(otmp);           /* munch */
+               ptr = mtmp->data;
+               if (poly) {
+                   if (newcham(mtmp, (struct permonst *)0, FALSE, FALSE))
+                       ptr = mtmp->data;
+               } else if (grow) {
+                   ptr = grow_up(mtmp, (struct monst *)0);
+               } else if (heal) {
+                   mtmp->mhp = mtmp->mhpmax;
+               }
+               /* in case it polymorphed or died */
+               if (ptr != &mons[PM_GELATINOUS_CUBE])
+                   return !ptr ? 2 : 1;
+           } else if (otmp->oclass != ROCK_CLASS &&
+                                   otmp != uball && otmp != uchain) {
+               ++ecount;
+               if (ecount == 1) {
+                       Sprintf(buf, "%s engulfs %s.", Monnam(mtmp),
+                           distant_name(otmp,doname));
+               } else if (ecount == 2)
+                       Sprintf(buf, "%s engulfs several objects.", Monnam(mtmp));
+               obj_extract_self(otmp);
+               (void) mpickobj(mtmp, otmp);    /* slurp */
+           }
+           /* Engulf & devour is instant, so don't set meating */
+           if (mtmp->minvis) newsym(mtmp->mx, mtmp->my);
+       }
+       if (ecount > 0) {
+           if (cansee(mtmp->mx, mtmp->my) && flags.verbose && buf[0])
+               pline("%s", buf);
+           else if (flags.soundok && flags.verbose)
+               You_hear("%s slurping sound%s.",
+                       ecount == 1 ? "a" : "several",
+                       ecount == 1 ? "" : "s");
+       }
+       return ((count > 0) || (ecount > 0)) ? 1 : 0;
+}
+
+void
+mpickgold(mtmp)
+       register struct monst *mtmp;
+{
+    register struct obj *gold;
+    int mat_idx;
+
+    if ((gold = g_at(mtmp->mx, mtmp->my)) != 0) {
+       mat_idx = objects[gold->otyp].oc_material;
+#ifndef GOLDOBJ
+       mtmp->mgold += gold->quan;
+       delobj(gold);
+#else
+        obj_extract_self(gold);
+        add_to_minv(mtmp, gold);
+#endif
+       if (cansee(mtmp->mx, mtmp->my) ) {
+           if (flags.verbose && !mtmp->isgd)
+               pline("%s picks up some %s.", Monnam(mtmp),
+                       mat_idx == GOLD ? "gold" : "money");
+           newsym(mtmp->mx, mtmp->my);
+       }
+    }
+}
+#endif /* OVLB */
+#ifdef OVL2
+
+boolean
+mpickstuff(mtmp, str)
+       register struct monst *mtmp;
+       register const char *str;
+{
+       register struct obj *otmp, *otmp2;
+
+/*     prevent shopkeepers from leaving the door of their shop */
+       if(mtmp->isshk && inhishop(mtmp)) return FALSE;
+
+       for(otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) {
+           otmp2 = otmp->nexthere;
+/*     Nymphs take everything.  Most monsters don't pick up corpses. */
+           if (!str ? searches_for_item(mtmp,otmp) :
+                 !!(index(str, otmp->oclass))) {
+               if (otmp->otyp == CORPSE && mtmp->data->mlet != S_NYMPH &&
+                       /* let a handful of corpse types thru to can_carry() */
+                       !touch_petrifies(&mons[otmp->corpsenm]) &&
+                       otmp->corpsenm != PM_LIZARD &&
+                       !acidic(&mons[otmp->corpsenm])) continue;
+               if (!touch_artifact(otmp,mtmp)) continue;
+               if (!can_carry(mtmp,otmp)) continue;
+               if (is_pool(mtmp->mx,mtmp->my)) continue;
+#ifdef INVISIBLE_OBJECTS
+               if (otmp->oinvis && !perceives(mtmp->data)) continue;
+#endif
+               if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
+                       pline("%s picks up %s.", Monnam(mtmp),
+                             (distu(mtmp->mx, mtmp->my) <= 5) ?
+                               doname(otmp) : distant_name(otmp, doname));
+               obj_extract_self(otmp);
+               /* unblock point after extract, before pickup */
+               if (otmp->otyp == BOULDER)
+                   unblock_point(otmp->ox,otmp->oy);   /* vision */
+               (void) mpickobj(mtmp, otmp);    /* may merge and free otmp */
+               m_dowear(mtmp, FALSE);
+               newsym(mtmp->mx, mtmp->my);
+               return TRUE;                    /* pick only one object */
+           }
+       }
+       return FALSE;
+}
+
+#endif /* OVL2 */
+#ifdef OVL0
+
+int
+curr_mon_load(mtmp)
+register struct monst *mtmp;
+{
+       register int curload = 0;
+       register struct obj *obj;
+
+       for(obj = mtmp->minvent; obj; obj = obj->nobj) {
+               if(obj->otyp != BOULDER || !throws_rocks(mtmp->data))
+                       curload += obj->owt;
+       }
+
+       return curload;
+}
+
+int
+max_mon_load(mtmp)
+register struct monst *mtmp;
+{
+       register long maxload;
+
+       /* Base monster carrying capacity is equal to human maximum
+        * carrying capacity, or half human maximum if not strong.
+        * (for a polymorphed player, the value used would be the
+        * non-polymorphed carrying capacity instead of max/half max).
+        * This is then modified by the ratio between the monster weights
+        * and human weights.  Corpseless monsters are given a capacity
+        * proportional to their size instead of weight.
+        */
+       if (!mtmp->data->cwt)
+               maxload = (MAX_CARR_CAP * (long)mtmp->data->msize) / MZ_HUMAN;
+       else if (!strongmonst(mtmp->data)
+               || (strongmonst(mtmp->data) && (mtmp->data->cwt > WT_HUMAN)))
+               maxload = (MAX_CARR_CAP * (long)mtmp->data->cwt) / WT_HUMAN;
+       else    maxload = MAX_CARR_CAP; /*strong monsters w/cwt <= WT_HUMAN*/
+
+       if (!strongmonst(mtmp->data)) maxload /= 2;
+
+       if (maxload < 1) maxload = 1;
+
+       return (int) maxload;
+}
+
+/* for restricting monsters' object-pickup */
+boolean
+can_carry(mtmp,otmp)
+struct monst *mtmp;
+struct obj *otmp;
+{
+       int otyp = otmp->otyp, newload = otmp->owt;
+       struct permonst *mdat = mtmp->data;
+
+       if (notake(mdat)) return FALSE;         /* can't carry anything */
+
+       if (otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) &&
+               !(mtmp->misc_worn_check & W_ARMG) && !resists_ston(mtmp))
+           return FALSE;
+       if (otyp == CORPSE && is_rider(&mons[otmp->corpsenm]))
+           return FALSE;
+       if (objects[otyp].oc_material == SILVER && hates_silver(mdat) &&
+               (otyp != BELL_OF_OPENING || !is_covetous(mdat)))
+           return FALSE;
+
+#ifdef STEED
+       /* Steeds don't pick up stuff (to avoid shop abuse) */
+       if (mtmp == u.usteed) return (FALSE);
+#endif
+       if (mtmp->isshk) return(TRUE); /* no limit */
+       if (mtmp->mpeaceful && !mtmp->mtame) return(FALSE);
+       /* otherwise players might find themselves obligated to violate
+        * their alignment if the monster takes something they need
+        */
+
+       /* special--boulder throwers carry unlimited amounts of boulders */
+       if (throws_rocks(mdat) && otyp == BOULDER)
+               return(TRUE);
+
+       /* nymphs deal in stolen merchandise, but not boulders or statues */
+       if (mdat->mlet == S_NYMPH)
+               return (boolean)(otmp->oclass != ROCK_CLASS);
+
+       if (curr_mon_load(mtmp) + newload > max_mon_load(mtmp)) return FALSE;
+
+       return(TRUE);
+}
+
+/* return number of acceptable neighbour positions */
+int
+mfndpos(mon, poss, info, flag)
+       register struct monst *mon;
+       coord *poss;    /* coord poss[9] */
+       long *info;     /* long info[9] */
+       long flag;
+{
+       struct permonst *mdat = mon->data;
+       register xchar x,y,nx,ny;
+       register int cnt = 0;
+       register uchar ntyp;
+       uchar nowtyp;
+       boolean wantpool,poolok,lavaok,nodiag;
+       boolean rockok = FALSE, treeok = FALSE, thrudoor;
+       int maxx, maxy;
+
+       x = mon->mx;
+       y = mon->my;
+       nowtyp = levl[x][y].typ;
+
+       nodiag = (mdat == &mons[PM_GRID_BUG]);
+       wantpool = mdat->mlet == S_EEL;
+       poolok = is_flyer(mdat) || is_clinger(mdat) ||
+                (is_swimmer(mdat) && !wantpool);
+       lavaok = is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat);
+       thrudoor = ((flag & (ALLOW_WALL|BUSTDOOR)) != 0L);
+       if (flag & ALLOW_DIG) {
+           struct obj *mw_tmp;
+
+           /* need to be specific about what can currently be dug */
+           if (!needspick(mdat)) {
+               rockok = treeok = TRUE;
+           } else if ((mw_tmp = MON_WEP(mon)) && mw_tmp->cursed &&
+                      mon->weapon_check == NO_WEAPON_WANTED) {
+               rockok = is_pick(mw_tmp);
+               treeok = is_axe(mw_tmp);
+           } else {
+               rockok = (m_carrying(mon, PICK_AXE) ||
+                         (m_carrying(mon, DWARVISH_MATTOCK) &&
+                          !which_armor(mon, W_ARMS)));
+               treeok = (m_carrying(mon, AXE) ||
+                         (m_carrying(mon, BATTLE_AXE) &&
+                          !which_armor(mon, W_ARMS)));
+           }
+           thrudoor |= rockok || treeok;
+       }
+
+nexttry:       /* eels prefer the water, but if there is no water nearby,
+                  they will crawl over land */
+       if(mon->mconf) {
+               flag |= ALLOW_ALL;
+               flag &= ~NOTONL;
+       }
+       if(!mon->mcansee)
+               flag |= ALLOW_SSM;
+       maxx = min(x+1,COLNO-1);
+       maxy = min(y+1,ROWNO-1);
+       for(nx = max(1,x-1); nx <= maxx; nx++)
+         for(ny = max(0,y-1); ny <= maxy; ny++) {
+           if(nx == x && ny == y) continue;
+           if(IS_ROCK(ntyp = levl[nx][ny].typ) &&
+              !((flag & ALLOW_WALL) && may_passwall(nx,ny)) &&
+              !((IS_TREE(ntyp) ? treeok : rockok) && may_dig(nx,ny))) continue;
+           /* KMH -- Added iron bars */
+           if (ntyp == IRONBARS && !(flag & ALLOW_BARS)) continue;
+           if(IS_DOOR(ntyp) && !amorphous(mdat) &&
+              ((levl[nx][ny].doormask & D_CLOSED && !(flag & OPENDOOR)) ||
+               (levl[nx][ny].doormask & D_LOCKED && !(flag & UNLOCKDOOR))) &&
+              !thrudoor) continue;
+           if(nx != x && ny != y && (nodiag ||
+#ifdef REINCARNATION
+              ((IS_DOOR(nowtyp) &&
+                ((levl[x][y].doormask & ~D_BROKEN) || Is_rogue_level(&u.uz))) ||
+               (IS_DOOR(ntyp) &&
+                ((levl[nx][ny].doormask & ~D_BROKEN) || Is_rogue_level(&u.uz))))
+#else
+              ((IS_DOOR(nowtyp) && (levl[x][y].doormask & ~D_BROKEN)) ||
+               (IS_DOOR(ntyp) && (levl[nx][ny].doormask & ~D_BROKEN)))
+#endif
+              ))
+               continue;
+           if((is_pool(nx,ny) == wantpool || poolok) &&
+              (lavaok || !is_lava(nx,ny))) {
+               int dispx, dispy;
+               boolean monseeu = (mon->mcansee && (!Invis || perceives(mdat)));
+               boolean checkobj = OBJ_AT(nx,ny);
+
+               /* Displacement also displaces the Elbereth/scare monster,
+                * as long as you are visible.
+                */
+               if(Displaced && monseeu && (mon->mux==nx) && (mon->muy==ny)) {
+                   dispx = u.ux;
+                   dispy = u.uy;
+               } else {
+                   dispx = nx;
+                   dispy = ny;
+               }
+
+               info[cnt] = 0;
+               if ((checkobj || Displaced) && onscary(dispx, dispy, mon)) {
+                   if(!(flag & ALLOW_SSM)) continue;
+                   info[cnt] |= ALLOW_SSM;
+               }
+               if((nx == u.ux && ny == u.uy) ||
+                  (nx == mon->mux && ny == mon->muy)) {
+                       if (nx == u.ux && ny == u.uy) {
+                               /* If it's right next to you, it found you,
+                                * displaced or no.  We must set mux and muy
+                                * right now, so when we return we can tell
+                                * that the ALLOW_U means to attack _you_ and
+                                * not the image.
+                                */
+                               mon->mux = u.ux;
+                               mon->muy = u.uy;
+                       }
+                       if(!(flag & ALLOW_U)) continue;
+                       info[cnt] |= ALLOW_U;
+               } else {
+                       if(MON_AT(nx, ny)) {
+                               struct monst *mtmp2 = m_at(nx, ny);
+                               long mmflag = flag | mm_aggression(mon, mtmp2);
+
+                               if (!(mmflag & ALLOW_M)) continue;
+                               info[cnt] |= ALLOW_M;
+                               if (mtmp2->mtame) {
+                                       if (!(mmflag & ALLOW_TM)) continue;
+                                       info[cnt] |= ALLOW_TM;
+                               }
+                       }
+                       /* Note: ALLOW_SANCT only prevents movement, not */
+                       /* attack, into a temple. */
+                       if(level.flags.has_temple &&
+                          *in_rooms(nx, ny, TEMPLE) &&
+                          !*in_rooms(x, y, TEMPLE) &&
+                          in_your_sanctuary((struct monst *)0, nx, ny)) {
+                               if(!(flag & ALLOW_SANCT)) continue;
+                               info[cnt] |= ALLOW_SANCT;
+                       }
+               }
+               if(checkobj && sobj_at(CLOVE_OF_GARLIC, nx, ny)) {
+                       if(flag & NOGARLIC) continue;
+                       info[cnt] |= NOGARLIC;
+               }
+               if(checkobj && sobj_at(BOULDER, nx, ny)) {
+                       if(!(flag & ALLOW_ROCK)) continue;
+                       info[cnt] |= ALLOW_ROCK;
+               }
+               if (monseeu && onlineu(nx,ny)) {
+                       if(flag & NOTONL) continue;
+                       info[cnt] |= NOTONL;
+               }
+               if (nx != x && ny != y && bad_rock(mdat, x, ny)
+                           && bad_rock(mdat, nx, y)
+                           && (bigmonst(mdat) || (curr_mon_load(mon) > 600)))
+                       continue;
+               /* The monster avoids a particular type of trap if it's familiar
+                * with the trap type.  Pets get ALLOW_TRAPS and checking is
+                * done in dogmove.c.  In either case, "harmless" traps are
+                * neither avoided nor marked in info[].
+                */
+               { register struct trap *ttmp = t_at(nx, ny);
+                   if(ttmp) {
+                       if(ttmp->ttyp >= TRAPNUM || ttmp->ttyp == 0)  {
+impossible("A monster looked at a very strange trap of type %d.", ttmp->ttyp);
+                           continue;
+                       }
+                       if ((ttmp->ttyp != RUST_TRAP
+                                       || mdat == &mons[PM_IRON_GOLEM])
+                               && ttmp->ttyp != STATUE_TRAP
+                               && ((ttmp->ttyp != PIT
+                                   && ttmp->ttyp != SPIKED_PIT
+                                   && ttmp->ttyp != TRAPDOOR
+                                   && ttmp->ttyp != HOLE)
+                                     || (!is_flyer(mdat)
+                                   && !is_floater(mdat)
+                                   && !is_clinger(mdat))
+                                     || In_sokoban(&u.uz))
+                               && (ttmp->ttyp != SLP_GAS_TRAP ||
+                                   !resists_sleep(mon))
+                               && (ttmp->ttyp != BEAR_TRAP ||
+                                   (mdat->msize > MZ_SMALL &&
+                                    !amorphous(mdat) && !is_flyer(mdat)))
+                               && (ttmp->ttyp != FIRE_TRAP ||
+                                   !resists_fire(mon))
+                               && (ttmp->ttyp != SQKY_BOARD || !is_flyer(mdat))
+                               && (ttmp->ttyp != WEB || (!amorphous(mdat) &&
+                                   !webmaker(mdat)))
+                       ) {
+                           if (!(flag & ALLOW_TRAPS)) {
+                               if (mon->mtrapseen & (1L << (ttmp->ttyp - 1)))
+                                   continue;
+                           }
+                           info[cnt] |= ALLOW_TRAPS;
+                       }
+                   }
+               }
+               poss[cnt].x = nx;
+               poss[cnt].y = ny;
+               cnt++;
+           }
+       }
+       if(!cnt && wantpool && !is_pool(x,y)) {
+               wantpool = FALSE;
+               goto nexttry;
+       }
+       return(cnt);
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+/* Monster against monster special attacks; for the specified monster
+   combinations, this allows one monster to attack another adjacent one
+   in the absence of Conflict.  There is no provision for targetting
+   other monsters; just hand to hand fighting when they happen to be
+   next to each other. */
+STATIC_OVL long
+mm_aggression(magr, mdef)
+struct monst *magr,    /* monster that is currently deciding where to move */
+            *mdef;     /* another monster which is next to it */
+{
+       /* supposedly purple worms are attracted to shrieking because they
+          like to eat shriekers, so attack the latter when feasible */
+       if (magr->data == &mons[PM_PURPLE_WORM] &&
+               mdef->data == &mons[PM_SHRIEKER])
+           return ALLOW_M|ALLOW_TM;
+       /* Various other combinations such as dog vs cat, cat vs rat, and
+          elf vs orc have been suggested.  For the time being we don't
+          support those. */
+       return 0L;
+}
+
+boolean
+monnear(mon, x, y)
+register struct monst *mon;
+register int x,y;
+/* Is the square close enough for the monster to move or attack into? */
+{
+       register int distance = dist2(mon->mx, mon->my, x, y);
+       if (distance==2 && mon->data==&mons[PM_GRID_BUG]) return 0;
+       return((boolean)(distance < 3));
+}
+
+/* really free dead monsters */
+void
+dmonsfree()
+{
+    struct monst **mtmp;
+    int count = 0;
+
+    for (mtmp = &fmon; *mtmp;) {
+       if ((*mtmp)->mhp <= 0) {
+           struct monst *freetmp = *mtmp;
+           *mtmp = (*mtmp)->nmon;
+           dealloc_monst(freetmp);
+           count++;
+       } else
+           mtmp = &(*mtmp)->nmon;
+    }
+
+    if (count != iflags.purge_monsters)
+       impossible("dmonsfree: %d removed doesn't match %d pending",
+                  count, iflags.purge_monsters);
+    iflags.purge_monsters = 0;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+/* called when monster is moved to larger structure */
+void
+replmon(mtmp, mtmp2)
+register struct monst *mtmp, *mtmp2;
+{
+    struct obj *otmp;
+
+    /* transfer the monster's inventory */
+    for (otmp = mtmp2->minvent; otmp; otmp = otmp->nobj) {
+#ifdef DEBUG
+       if (otmp->where != OBJ_MINVENT || otmp->ocarry != mtmp)
+           panic("replmon: minvent inconsistency");
+#endif
+       otmp->ocarry = mtmp2;
+    }
+    mtmp->minvent = 0;
+
+    /* remove the old monster from the map and from `fmon' list */
+    relmon(mtmp);
+
+    /* finish adding its replacement */
+#ifdef STEED
+    if (mtmp == u.usteed) ; else       /* don't place steed onto the map */
+#endif
+    place_monster(mtmp2, mtmp2->mx, mtmp2->my);
+    if (mtmp2->wormno)     /* update level.monsters[wseg->wx][wseg->wy] */
+       place_wsegs(mtmp2); /* locations to mtmp2 not mtmp. */
+    if (emits_light(mtmp2->data)) {
+       /* since this is so rare, we don't have any `mon_move_light_source' */
+       new_light_source(mtmp2->mx, mtmp2->my,
+                        emits_light(mtmp2->data),
+                        LS_MONSTER, (genericptr_t)mtmp2);
+       /* here we rely on the fact that `mtmp' hasn't actually been deleted */
+       del_light_source(LS_MONSTER, (genericptr_t)mtmp);
+    }
+    mtmp2->nmon = fmon;
+    fmon = mtmp2;
+    if (u.ustuck == mtmp) u.ustuck = mtmp2;
+#ifdef STEED
+    if (u.usteed == mtmp) u.usteed = mtmp2;
+#endif
+    if (mtmp2->isshk) replshk(mtmp,mtmp2);
+
+    /* discard the old monster */
+    dealloc_monst(mtmp);
+}
+
+/* release mon from display and monster list */
+void
+relmon(mon)
+register struct monst *mon;
+{
+       register struct monst *mtmp;
+
+       if (fmon == (struct monst *)0)  panic ("relmon: no fmon available.");
+
+       remove_monster(mon->mx, mon->my);
+
+       if(mon == fmon) fmon = fmon->nmon;
+       else {
+               for(mtmp = fmon; mtmp && mtmp->nmon != mon; mtmp = mtmp->nmon) ;
+               if(mtmp)    mtmp->nmon = mon->nmon;
+               else        panic("relmon: mon not in list.");
+       }
+}
+
+/* remove effects of mtmp from other data structures */
+STATIC_OVL void
+m_detach(mtmp, mptr)
+struct monst *mtmp;
+struct permonst *mptr; /* reflects mtmp->data _prior_ to mtmp's death */
+{
+       if (mtmp->mleashed) m_unleash(mtmp, FALSE);
+           /* to prevent an infinite relobj-flooreffects-hmon-killed loop */
+       mtmp->mtrapped = 0;
+       mtmp->mhp = 0; /* simplify some tests: force mhp to 0 */
+       relobj(mtmp, 0, FALSE);
+       remove_monster(mtmp->mx, mtmp->my);
+       if (emits_light(mptr))
+           del_light_source(LS_MONSTER, (genericptr_t)mtmp);
+       newsym(mtmp->mx,mtmp->my);
+       unstuck(mtmp);
+       fill_pit(mtmp->mx, mtmp->my);
+
+       if(mtmp->isshk) shkgone(mtmp);
+       if(mtmp->wormno) wormgone(mtmp);
+       iflags.purge_monsters++;
+}
+
+/* find the worn amulet of life saving which will save a monster */
+struct obj *
+mlifesaver(mon)
+struct monst *mon;
+{
+       if (!nonliving(mon->data)) {
+           struct obj *otmp = which_armor(mon, W_AMUL);
+
+           if (otmp && otmp->otyp == AMULET_OF_LIFE_SAVING)
+               return otmp;
+       }
+       return (struct obj *)0;
+}
+
+STATIC_OVL void
+lifesaved_monster(mtmp)
+struct monst *mtmp;
+{
+       struct obj *lifesave = mlifesaver(mtmp);
+
+       if (lifesave) {
+               /* not canseemon; amulets are on the head, so you don't want */
+               /* to show this for a long worm with only a tail visible. */
+               /* Nor do you check invisibility, because glowing and disinte- */
+               /* grating amulets are always visible. */
+               if (cansee(mtmp->mx, mtmp->my)) {
+                       pline("But wait...");
+                       pline("%s medallion begins to glow!",
+                               s_suffix(Monnam(mtmp)));
+                       makeknown(AMULET_OF_LIFE_SAVING);
+                       if (attacktype(mtmp->data, AT_EXPL)
+                           || attacktype(mtmp->data, AT_BOOM))
+                               pline("%s reconstitutes!", Monnam(mtmp));
+                       else
+                               pline("%s looks much better!", Monnam(mtmp));
+                       pline_The("medallion crumbles to dust!");
+               }
+               m_useup(mtmp, lifesave);
+               mtmp->mcanmove = 1;
+               mtmp->mfrozen = 0;
+               if (mtmp->mtame && !mtmp->isminion) {
+                       wary_dog(mtmp, FALSE);
+               }
+               if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10;
+               mtmp->mhp = mtmp->mhpmax;
+               if (mvitals[monsndx(mtmp->data)].mvflags & G_GENOD) {
+                       if (cansee(mtmp->mx, mtmp->my))
+                           pline("Unfortunately %s is still genocided...",
+                               mon_nam(mtmp));
+               } else
+                       return;
+       }
+       mtmp->mhp = 0;
+}
+
+void
+mondead(mtmp)
+register struct monst *mtmp;
+{
+       struct permonst *mptr;
+       int tmp;
+
+       if(mtmp->isgd) {
+               /* if we're going to abort the death, it *must* be before
+                * the m_detach or there will be relmon problems later */
+               if(!grddead(mtmp)) return;
+       }
+       lifesaved_monster(mtmp);
+       if (mtmp->mhp > 0) return;
+
+#ifdef STEED
+       /* Player is thrown from his steed when it dies */
+       if (mtmp == u.usteed)
+               dismount_steed(DISMOUNT_GENERIC);
+#endif
+
+       mptr = mtmp->data;              /* save this for m_detach() */
+       /* restore chameleon, lycanthropes to true form at death */
+       if (mtmp->cham)
+           set_mon_data(mtmp, &mons[cham_to_pm[mtmp->cham]], -1);
+       else if (mtmp->data == &mons[PM_WEREJACKAL])
+           set_mon_data(mtmp, &mons[PM_HUMAN_WEREJACKAL], -1);
+       else if (mtmp->data == &mons[PM_WEREWOLF])
+           set_mon_data(mtmp, &mons[PM_HUMAN_WEREWOLF], -1);
+       else if (mtmp->data == &mons[PM_WERERAT])
+           set_mon_data(mtmp, &mons[PM_HUMAN_WERERAT], -1);
+
+       /* if MAXMONNO monsters of a given type have died, and it
+        * can be done, extinguish that monster.
+        *
+        * mvitals[].died does double duty as total number of dead monsters
+        * and as experience factor for the player killing more monsters.
+        * this means that a dragon dying by other means reduces the
+        * experience the player gets for killing a dragon directly; this
+        * is probably not too bad, since the player likely finagled the
+        * first dead dragon via ring of conflict or pets, and extinguishing
+        * based on only player kills probably opens more avenues of abuse
+        * for rings of conflict and such.
+        */
+       tmp = monsndx(mtmp->data);
+       if (mvitals[tmp].died < 255) mvitals[tmp].died++;
+
+       /* if it's a (possibly polymorphed) quest leader, mark him as dead */
+       if (mtmp->m_id == quest_status.leader_m_id)
+           quest_status.leader_is_dead = TRUE;
+#ifdef MAIL
+       /* if the mail daemon dies, no more mail delivery.  -3. */
+       if (tmp == PM_MAIL_DAEMON) mvitals[tmp].mvflags |= G_GENOD;
+#endif
+
+#ifdef KOPS
+       if (mtmp->data->mlet == S_KOP) {
+           /* Dead Kops may come back. */
+           switch(rnd(5)) {
+               case 1:      /* returns near the stairs */
+                       (void) makemon(mtmp->data,xdnstair,ydnstair,NO_MM_FLAGS);
+                       break;
+               case 2:      /* randomly */
+                       (void) makemon(mtmp->data,0,0,NO_MM_FLAGS);
+                       break;
+               default:
+                       break;
+           }
+       }
+#endif
+       if(mtmp->iswiz) wizdead();
+       if(mtmp->data->msound == MS_NEMESIS) nemdead();
+       if(glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph))
+           unmap_object(mtmp->mx, mtmp->my);
+       m_detach(mtmp, mptr);
+}
+
+/* TRUE if corpse might be dropped, magr may die if mon was swallowed */
+boolean
+corpse_chance(mon, magr, was_swallowed)
+struct monst *mon;
+struct monst *magr;                    /* killer, if swallowed */
+boolean was_swallowed;                 /* digestion */
+{
+       struct permonst *mdat = mon->data;
+       int i, tmp;
+
+       if (mdat == &mons[PM_VLAD_THE_IMPALER] || mdat->mlet == S_LICH) {
+           if (cansee(mon->mx, mon->my) && !was_swallowed)
+               pline("%s body crumbles into dust.", s_suffix(Monnam(mon)));
+           return FALSE;
+       }
+
+       /* Gas spores always explode upon death */
+       for(i = 0; i < NATTK; i++) {
+           if (mdat->mattk[i].aatyp == AT_BOOM) {
+               if (mdat->mattk[i].damn)
+                   tmp = d((int)mdat->mattk[i].damn,
+                               (int)mdat->mattk[i].damd);
+               else if(mdat->mattk[i].damd)
+                   tmp = d((int)mdat->mlevel+1, (int)mdat->mattk[i].damd);
+               else tmp = 0;
+               if (was_swallowed && magr) {
+                   if (magr == &youmonst) {
+                       There("is an explosion in your %s!",
+                             body_part(STOMACH));
+                       Sprintf(killer_buf, "%s explosion",
+                               s_suffix(mdat->mname));
+                       if (Half_physical_damage) tmp = (tmp+1) / 2;
+                       losehp(tmp, killer_buf, KILLED_BY_AN);
+                   } else {
+                       if (flags.soundok) You_hear("an explosion.");
+                       magr->mhp -= tmp;
+                       if (magr->mhp < 1) mondied(magr);
+                       if (magr->mhp < 1) { /* maybe lifesaved */
+                           if (canspotmon(magr))
+                               pline("%s rips open!", Monnam(magr));
+                       } else if (canseemon(magr))
+                           pline("%s seems to have indigestion.",
+                                 Monnam(magr));
+                   }
+
+                   return FALSE;
+               }
+
+               Sprintf(killer_buf, "%s explosion", s_suffix(mdat->mname));
+               killer = killer_buf;
+               killer_format = KILLED_BY_AN;
+               explode(mon->mx, mon->my, -1, tmp, MON_EXPLODE, EXPL_NOXIOUS); 
+               return (FALSE);
+           }
+       }
+
+       /* must duplicate this below check in xkilled() since it results in
+        * creating no objects as well as no corpse
+        */
+       if (LEVEL_SPECIFIC_NOCORPSE(mdat))
+               return FALSE;
+
+       if (bigmonst(mdat) || mdat == &mons[PM_LIZARD]
+                  || is_golem(mdat)
+                  || is_mplayer(mdat)
+                  || is_rider(mdat))
+               return TRUE;
+       return (boolean) (!rn2((int)
+               (2 + ((int)(mdat->geno & G_FREQ)<2) + verysmall(mdat))));
+}
+
+/* drop (perhaps) a cadaver and remove monster */
+void
+mondied(mdef)
+register struct monst *mdef;
+{
+       mondead(mdef);
+       if (mdef->mhp > 0) return;      /* lifesaved */
+
+       if (corpse_chance(mdef, (struct monst *)0, FALSE) &&
+           (accessible(mdef->mx, mdef->my) || is_pool(mdef->mx, mdef->my)))
+               (void) make_corpse(mdef);
+}
+
+/* monster disappears, not dies */
+void
+mongone(mdef)
+register struct monst *mdef;
+{
+       mdef->mhp = 0;  /* can skip some inventory bookkeeping */
+#ifdef STEED
+       /* Player is thrown from his steed when it disappears */
+       if (mdef == u.usteed)
+               dismount_steed(DISMOUNT_GENERIC);
+#endif
+
+       /* drop special items like the Amulet so that a dismissed Kop or nurse
+          can't remove them from the game */
+       mdrop_special_objs(mdef);
+       /* release rest of monster's inventory--it is removed from game */
+       discard_minvent(mdef);
+#ifndef GOLDOBJ
+       mdef->mgold = 0L;
+#endif
+       m_detach(mdef, mdef->data);
+}
+
+/* drop a statue or rock and remove monster */
+void
+monstone(mdef)
+register struct monst *mdef;
+{
+       struct obj *otmp, *obj, *oldminvent;
+       xchar x = mdef->mx, y = mdef->my;
+       boolean wasinside = FALSE;
+
+       /* we have to make the statue before calling mondead, to be able to
+        * put inventory in it, and we have to check for lifesaving before
+        * making the statue....
+        */
+       lifesaved_monster(mdef);
+       if (mdef->mhp > 0) return;
+
+       mdef->mtrapped = 0;     /* (see m_detach) */
+
+       if ((int)mdef->data->msize > MZ_TINY ||
+                   !rn2(2 + ((int) (mdef->data->geno & G_FREQ) > 2))) {
+               oldminvent = 0;
+               /* some objects may end up outside the statue */
+               while ((obj = mdef->minvent) != 0) {
+                   obj_extract_self(obj);
+                   if (obj->owornmask)
+                       update_mon_intrinsics(mdef, obj, FALSE, TRUE);
+                   obj_no_longer_held(obj);
+                   if (obj->owornmask & W_WEP)
+                       setmnotwielded(mdef,obj);
+                   obj->owornmask = 0L;
+                   if (obj->otyp == BOULDER ||
+#if 0                          /* monsters don't carry statues */
+     (obj->otyp == STATUE && mons[obj->corpsenm].msize >= mdef->data->msize) ||
+#endif
+                               obj_resists(obj, 0, 0)) {
+                       if (flooreffects(obj, x, y, "fall")) continue;
+                       place_object(obj, x, y);
+                   } else {
+                       if (obj->lamplit) end_burn(obj, TRUE);
+                       obj->nobj = oldminvent;
+                       oldminvent = obj;
+                   }
+               }
+               /* defer statue creation until after inventory removal
+                  so that saved monster traits won't retain any stale
+                  item-conferred attributes */
+               otmp = mkcorpstat(STATUE, KEEPTRAITS(mdef) ? mdef : 0,
+                                 mdef->data, x, y, FALSE);
+               if (mdef->mnamelth) otmp = oname(otmp, NAME(mdef));
+               while ((obj = oldminvent) != 0) {
+                   oldminvent = obj->nobj;
+                   (void) add_to_container(otmp, obj);
+               }
+#ifndef GOLDOBJ
+               if (mdef->mgold) {
+                       struct obj *au;
+                       au = mksobj(GOLD_PIECE, FALSE, FALSE);
+                       au->quan = mdef->mgold;
+                       au->owt = weight(au);
+                       (void) add_to_container(otmp, au);
+                       mdef->mgold = 0;
+               }
+#endif
+               /* Archeologists should not break unique statues */
+               if (mdef->data->geno & G_UNIQ)
+                       otmp->spe = 1;
+               otmp->owt = weight(otmp);
+       } else
+               otmp = mksobj_at(ROCK, x, y, TRUE, FALSE);
+
+       stackobj(otmp);
+       /* mondead() already does this, but we must do it before the newsym */
+       if(glyph_is_invisible(levl[x][y].glyph))
+           unmap_object(x, y);
+       if (cansee(x, y)) newsym(x,y);
+       /* We don't currently trap the hero in the statue in this case but we could */
+       if (u.uswallow && u.ustuck == mdef) wasinside = TRUE;
+       mondead(mdef);
+       if (wasinside) {
+               if (is_animal(mdef->data))
+                       You("%s through an opening in the new %s.",
+                               locomotion(youmonst.data, "jump"),
+                               xname(otmp));
+       }
+}
+
+/* another monster has killed the monster mdef */
+void
+monkilled(mdef, fltxt, how)
+register struct monst *mdef;
+const char *fltxt;
+int how;
+{
+       boolean be_sad = FALSE;         /* true if unseen pet is killed */
+
+       if ((mdef->wormno ? worm_known(mdef) : cansee(mdef->mx, mdef->my))
+               && fltxt)
+           pline("%s is %s%s%s!", Monnam(mdef),
+                       nonliving(mdef->data) ? "destroyed" : "killed",
+                   *fltxt ? " by the " : "",
+                   fltxt
+                );
+       else
+           be_sad = (mdef->mtame != 0);
+
+       /* no corpses if digested or disintegrated */
+       if(how == AD_DGST || how == -AD_RBRE)
+           mondead(mdef);
+       else
+           mondied(mdef);
+
+       if (be_sad && mdef->mhp <= 0)
+           You("have a sad feeling for a moment, then it passes.");
+}
+
+void
+unstuck(mtmp)
+register struct monst *mtmp;
+{
+       if(u.ustuck == mtmp) {
+               if(u.uswallow){
+                       u.ux = mtmp->mx;
+                       u.uy = mtmp->my;
+                       u.uswallow = 0;
+                       u.uswldtim = 0;
+                       if (Punished) placebc();
+                       vision_full_recalc = 1;
+                       docrt();
+               }
+               u.ustuck = 0;
+       }
+}
+
+void
+killed(mtmp)
+register struct monst *mtmp;
+{
+       xkilled(mtmp, 1);
+}
+
+/* the player has killed the monster mtmp */
+void
+xkilled(mtmp, dest)
+       register struct monst *mtmp;
+/*
+ * Dest=1, normal; dest=0, don't print message; dest=2, don't drop corpse
+ * either; dest=3, message but no corpse
+ */
+       int     dest;
+{
+       register int tmp, x = mtmp->mx, y = mtmp->my;
+       register struct permonst *mdat;
+       int mndx;
+       register struct obj *otmp;
+       register struct trap *t;
+       boolean redisp = FALSE;
+       boolean wasinside = u.uswallow && (u.ustuck == mtmp);
+
+
+       /* KMH, conduct */
+       u.uconduct.killer++;
+
+       if (dest & 1) {
+           const char *verb = nonliving(mtmp->data) ? "destroy" : "kill";
+
+           if (!wasinside && !canspotmon(mtmp))
+               You("%s it!", verb);
+           else {
+               You("%s %s!", verb,
+                   !mtmp->mtame ? mon_nam(mtmp) :
+                       x_monnam(mtmp,
+                                mtmp->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
+                                "poor",
+                                mtmp->mnamelth ? SUPPRESS_SADDLE : 0,
+                                FALSE));
+           }
+       }
+
+       if (mtmp->mtrapped && (t = t_at(x, y)) != 0 &&
+               (t->ttyp == PIT || t->ttyp == SPIKED_PIT) &&
+               sobj_at(BOULDER, x, y))
+           dest |= 2;     /*
+                           * Prevent corpses/treasure being created "on top"
+                           * of the boulder that is about to fall in. This is
+                           * out of order, but cannot be helped unless this
+                           * whole routine is rearranged.
+                           */
+
+       /* your pet knows who just killed it...watch out */
+       if (mtmp->mtame && !mtmp->isminion) EDOG(mtmp)->killed_by_u = 1;
+
+       /* dispose of monster and make cadaver */
+       if(stoned) monstone(mtmp);
+       else mondead(mtmp);
+
+       if (mtmp->mhp > 0) { /* monster lifesaved */
+               /* Cannot put the non-visible lifesaving message in
+                * lifesaved_monster() since the message appears only when you
+                * kill it (as opposed to visible lifesaving which always
+                * appears).
+                */
+               stoned = FALSE;
+               if (!cansee(x,y)) pline("Maybe not...");
+               return;
+       }
+
+       mdat = mtmp->data; /* note: mondead can change mtmp->data */
+       mndx = monsndx(mdat);
+
+       if (stoned) {
+               stoned = FALSE;
+               goto cleanup;
+       }
+
+       if((dest & 2) || LEVEL_SPECIFIC_NOCORPSE(mdat))
+               goto cleanup;
+
+#ifdef MAIL
+       if(mdat == &mons[PM_MAIL_DAEMON]) {
+               stackobj(mksobj_at(SCR_MAIL, x, y, FALSE, FALSE));
+               redisp = TRUE;
+       }
+#endif
+       if((!accessible(x, y) && !is_pool(x, y)) ||
+          (x == u.ux && y == u.uy)) {
+           /* might be mimic in wall or corpse in lava or on player's spot */
+           redisp = TRUE;
+           if(wasinside) spoteffects(TRUE);
+       } else if(x != u.ux || y != u.uy) {
+               /* might be here after swallowed */
+               if (!rn2(6) && !(mvitals[mndx].mvflags & G_NOCORPSE)
+#ifdef KOPS
+                                       && mdat->mlet != S_KOP
+#endif
+                                                       ) {
+                       int typ;
+
+                       otmp = mkobj_at(RANDOM_CLASS, x, y, TRUE);
+                       /* Don't create large objects from small monsters */
+                       typ = otmp->otyp;
+                       if (mdat->msize < MZ_HUMAN && typ != FOOD_RATION
+                           && typ != LEASH
+                           && typ != FIGURINE
+                           && (otmp->owt > 3 ||
+                               objects[typ].oc_big /*oc_bimanual/oc_bulky*/ ||
+                               is_spear(otmp) || is_pole(otmp) ||
+                               typ == MORNING_STAR)) {
+                           delobj(otmp);
+                       } else redisp = TRUE;
+               }
+               /* Whether or not it always makes a corpse is, in theory,
+                * different from whether or not the corpse is "special";
+                * if we want both, we have to specify it explicitly.
+                */
+               if (corpse_chance(mtmp, (struct monst *)0, FALSE))
+                       (void) make_corpse(mtmp);
+       }
+       if(redisp) newsym(x,y);
+cleanup:
+       /* punish bad behaviour */
+       if(is_human(mdat) && (!always_hostile(mdat) && mtmp->malign <= 0) &&
+          (mndx < PM_ARCHEOLOGIST || mndx > PM_WIZARD) &&
+          u.ualign.type != A_CHAOTIC) {
+               HTelepat &= ~INTRINSIC;
+               change_luck(-2);
+               You("murderer!");
+               if (Blind && !Blind_telepat)
+                   see_monsters(); /* Can't sense monsters any more. */
+       }
+       if((mtmp->mpeaceful && !rn2(2)) || mtmp->mtame) change_luck(-1);
+       if (is_unicorn(mdat) &&
+                               sgn(u.ualign.type) == sgn(mdat->maligntyp)) {
+               change_luck(-5);
+               You_feel("guilty...");
+       }
+
+       /* give experience points */
+       tmp = experience(mtmp, (int)mvitals[mndx].died + 1);
+       more_experienced(tmp, 0);
+       newexplevel();          /* will decide if you go up */
+
+       /* adjust alignment points */
+       if (mtmp->m_id == quest_status.leader_m_id) {           /* REAL BAD! */
+           adjalign(-(u.ualign.record+(int)ALIGNLIM/2));
+           pline("That was %sa bad idea...",
+                       u.uevent.qcompleted ? "probably " : "");
+       } else if (mdat->msound == MS_NEMESIS)  /* Real good! */
+           adjalign((int)(ALIGNLIM/4));
+       else if (mdat->msound == MS_GUARDIAN) { /* Bad */
+           adjalign(-(int)(ALIGNLIM/8));
+           if (!Hallucination) pline("That was probably a bad idea...");
+           else pline("Whoopsie-daisy!");
+       }else if (mtmp->ispriest) {
+               adjalign((p_coaligned(mtmp)) ? -2 : 2);
+               /* cancel divine protection for killing your priest */
+               if (p_coaligned(mtmp)) u.ublessed = 0;
+               if (mdat->maligntyp == A_NONE)
+                       adjalign((int)(ALIGNLIM / 4));          /* BIG bonus */
+       } else if (mtmp->mtame) {
+               adjalign(-15);  /* bad!! */
+               /* your god is mighty displeased... */
+               if (!Hallucination) You_hear("the rumble of distant thunder...");
+               else You_hear("the studio audience applaud!");
+       } else if (mtmp->mpeaceful)
+               adjalign(-5);
+
+       /* malign was already adjusted for u.ualign.type and randomization */
+       adjalign(mtmp->malign);
+}
+
+/* changes the monster into a stone monster of the same type */
+/* this should only be called when poly_when_stoned() is true */
+void
+mon_to_stone(mtmp)
+    register struct monst *mtmp;
+{
+    if(mtmp->data->mlet == S_GOLEM) {
+       /* it's a golem, and not a stone golem */
+       if(canseemon(mtmp))
+           pline("%s solidifies...", Monnam(mtmp));
+       if (newcham(mtmp, &mons[PM_STONE_GOLEM], FALSE, FALSE)) {
+           if(canseemon(mtmp))
+               pline("Now it's %s.", an(mtmp->data->mname));
+       } else {
+           if(canseemon(mtmp))
+               pline("... and returns to normal.");
+       }
+    } else
+       impossible("Can't polystone %s!", a_monnam(mtmp));
+}
+
+void
+mnexto(mtmp)   /* Make monster mtmp next to you (if possible) */
+       struct monst *mtmp;
+{
+       coord mm;
+
+#ifdef STEED
+       if (mtmp == u.usteed) {
+               /* Keep your steed in sync with you instead */
+               mtmp->mx = u.ux;
+               mtmp->my = u.uy;
+               return;
+       }
+#endif
+
+       if(!enexto(&mm, u.ux, u.uy, mtmp->data)) return;
+       rloc_to(mtmp, mm.x, mm.y);
+       return;
+}
+
+/* mnearto()
+ * Put monster near (or at) location if possible.
+ * Returns:
+ *     1 - if a monster was moved from x, y to put mtmp at x, y.
+ *     0 - in most cases.
+ */
+boolean
+mnearto(mtmp,x,y,move_other)
+register struct monst *mtmp;
+xchar x, y;
+boolean move_other;    /* make sure mtmp gets to x, y! so move m_at(x, y) */
+{
+       struct monst *othermon = (struct monst *)0;
+       xchar newx, newy;
+       coord mm;
+
+       if ((mtmp->mx == x) && (mtmp->my == y)) return(FALSE);
+
+       if (move_other && (othermon = m_at(x, y))) {
+               if (othermon->wormno)
+                       remove_worm(othermon);
+               else
+                       remove_monster(x, y);
+       }
+
+       newx = x;
+       newy = y;
+
+       if (!goodpos(newx, newy, mtmp, 0)) {
+               /* actually we have real problems if enexto ever fails.
+                * migrating_mons that need to be placed will cause
+                * no end of trouble.
+                */
+               if (!enexto(&mm, newx, newy, mtmp->data)) return(FALSE);
+               newx = mm.x; newy = mm.y;
+       }
+
+       rloc_to(mtmp, newx, newy);
+
+       if (move_other && othermon) {
+           othermon->mx = othermon->my = 0;
+           (void) mnearto(othermon, x, y, FALSE);
+           if ((othermon->mx != x) || (othermon->my != y))
+               return(TRUE);
+       }
+
+       return(FALSE);
+}
+
+
+static const char *poiseff[] = {
+
+       " feel weaker", "r brain is on fire",
+       "r judgement is impaired", "r muscles won't obey you",
+       " feel very sick", " break out in hives"
+};
+
+void
+poisontell(typ)
+
+       int     typ;
+{
+       pline("You%s.", poiseff[typ]);
+}
+
+void
+poisoned(string, typ, pname, fatal)
+const char *string, *pname;
+int  typ, fatal;
+{
+       int i, plural, kprefix = KILLED_BY_AN;
+       boolean thrown_weapon = (fatal < 0);
+
+       if (thrown_weapon) fatal = -fatal;
+       if(strcmp(string, "blast") && !thrown_weapon) {
+           /* 'blast' has already given a 'poison gas' message */
+           /* so have "poison arrow", "poison dart", etc... */
+           plural = (string[strlen(string) - 1] == 's')? 1 : 0;
+           /* avoid "The" Orcus's sting was poisoned... */
+           pline("%s%s %s poisoned!", isupper(*string) ? "" : "The ",
+                       string, plural ? "were" : "was");
+       }
+
+       if(Poison_resistance) {
+               if(!strcmp(string, "blast")) shieldeff(u.ux, u.uy);
+               pline_The("poison doesn't seem to affect you.");
+               return;
+       }
+       /* suppress killer prefix if it already has one */
+       if ((i = name_to_mon(pname)) >= LOW_PM && mons[i].geno & G_UNIQ) {
+           kprefix = KILLED_BY;
+           if (!type_is_pname(&mons[i])) pname = the(pname);
+       } else if (!strncmpi(pname, "the ", 4) ||
+           !strncmpi(pname, "an ", 3) ||
+           !strncmpi(pname, "a ", 2)) {
+           /*[ does this need a plural check too? ]*/
+           kprefix = KILLED_BY;
+       }
+       i = rn2(fatal + 20*thrown_weapon);
+       if(i == 0 && typ != A_CHA) {
+               u.uhp = -1;
+               pline_The("poison was deadly...");
+       } else if(i <= 5) {
+               /* Check that a stat change was made */
+               if (adjattrib(typ, thrown_weapon ? -1 : -rn1(3,3), 1))
+                   pline("You%s!", poiseff[typ]);
+       } else {
+               i = thrown_weapon ? rnd(6) : rn1(10,6);
+               if(Half_physical_damage) i = (i+1) / 2;
+               losehp(i, pname, kprefix);
+       }
+       if(u.uhp < 1) {
+               killer_format = kprefix;
+               killer = pname;
+               /* "Poisoned by a poisoned ___" is redundant */
+               done(strstri(pname, "poison") ? DIED : POISONING);
+       }
+       (void) encumber_msg();
+}
+
+/* monster responds to player action; not the same as a passive attack */
+/* assumes reason for response has been tested, and response _must_ be made */
+void
+m_respond(mtmp)
+register struct monst *mtmp;
+{
+    if(mtmp->data->msound == MS_SHRIEK) {
+       if(flags.soundok) {
+           pline("%s shrieks.", Monnam(mtmp));
+           stop_occupation();
+       }
+       if (!rn2(10)) {
+           if (!rn2(13))
+               (void) makemon(&mons[PM_PURPLE_WORM], 0, 0, NO_MM_FLAGS);
+           else
+               (void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS);
+
+       }
+       aggravate();
+    }
+    if(mtmp->data == &mons[PM_MEDUSA]) {
+       register int i;
+       for(i = 0; i < NATTK; i++)
+            if(mtmp->data->mattk[i].aatyp == AT_GAZE) {
+                (void) gazemu(mtmp, &mtmp->data->mattk[i]);
+                break;
+            }
+    }
+}
+
+#endif /* OVLB */
+#ifdef OVL2
+
+void
+setmangry(mtmp)
+register struct monst *mtmp;
+{
+       mtmp->mstrategy &= ~STRAT_WAITMASK;
+       if(!mtmp->mpeaceful) return;
+       if(mtmp->mtame) return;
+       mtmp->mpeaceful = 0;
+       if(mtmp->ispriest) {
+               if(p_coaligned(mtmp)) adjalign(-5); /* very bad */
+               else adjalign(2);
+       } else
+               adjalign(-1);           /* attacking peaceful monsters is bad */
+       if (couldsee(mtmp->mx, mtmp->my)) {
+               if (humanoid(mtmp->data) || mtmp->isshk || mtmp->isgd)
+                   pline("%s gets angry!", Monnam(mtmp));
+               else if (flags.verbose && flags.soundok) growl(mtmp);
+       }
+
+       /* attacking your own quest leader will anger his or her guardians */
+       if (!flags.mon_moving &&        /* should always be the case here */
+               mtmp->data == &mons[quest_info(MS_LEADER)]) {
+           struct monst *mon;
+           struct permonst *q_guardian = &mons[quest_info(MS_GUARDIAN)];
+           int got_mad = 0;
+
+           /* guardians will sense this attack even if they can't see it */
+           for (mon = fmon; mon; mon = mon->nmon)
+               if (!DEADMONSTER(mon) && mon->data == q_guardian && mon->mpeaceful) {
+                   mon->mpeaceful = 0;
+                   if (canseemon(mon)) ++got_mad;
+               }
+           if (got_mad && !Hallucination)
+               pline_The("%s appear%s to be angry too...",
+                     got_mad == 1 ? q_guardian->mname :
+                                   makeplural(q_guardian->mname),
+                     got_mad == 1 ? "s" : "");
+       }
+}
+
+void
+wakeup(mtmp)
+register struct monst *mtmp;
+{
+       mtmp->msleeping = 0;
+       mtmp->meating = 0;      /* assume there's no salvagable food left */
+       setmangry(mtmp);
+       if(mtmp->m_ap_type) seemimic(mtmp);
+       else if (flags.forcefight && !flags.mon_moving && mtmp->mundetected) {
+           mtmp->mundetected = 0;
+           newsym(mtmp->mx, mtmp->my);
+       }
+}
+
+/* Wake up nearby monsters. */
+void
+wake_nearby()
+{
+       register struct monst *mtmp;
+
+       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+           if (!DEADMONSTER(mtmp) && distu(mtmp->mx,mtmp->my) < u.ulevel*20) {
+               mtmp->msleeping = 0;
+               if (mtmp->mtame && !mtmp->isminion)
+                   EDOG(mtmp)->whistletime = moves;
+           }
+       }
+}
+
+/* Wake up monsters near some particular location. */
+void
+wake_nearto(x, y, distance)
+register int x, y, distance;
+{
+       register struct monst *mtmp;
+
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+           if (!DEADMONSTER(mtmp) && mtmp->msleeping && (distance == 0 ||
+                                dist2(mtmp->mx, mtmp->my, x, y) < distance))
+               mtmp->msleeping = 0;
+       }
+}
+
+/* NOTE: we must check for mimicry before calling this routine */
+void
+seemimic(mtmp)
+register struct monst *mtmp;
+{
+       unsigned old_app = mtmp->mappearance;
+       uchar old_ap_type = mtmp->m_ap_type;
+
+       mtmp->m_ap_type = M_AP_NOTHING;
+       mtmp->mappearance = 0;
+
+       /*
+        *  Discovered mimics don't block light.
+        */
+       if (((old_ap_type == M_AP_FURNITURE &&
+             (old_app == S_hcdoor || old_app == S_vcdoor)) ||
+            (old_ap_type == M_AP_OBJECT && old_app == BOULDER)) &&
+           !does_block(mtmp->mx, mtmp->my, &levl[mtmp->mx][mtmp->my]))
+           unblock_point(mtmp->mx, mtmp->my);
+
+       newsym(mtmp->mx,mtmp->my);
+}
+
+/* force all chameleons to become normal */
+void
+rescham()
+{
+       register struct monst *mtmp;
+       int mcham;
+
+       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+               if (DEADMONSTER(mtmp)) continue;
+               mcham = (int) mtmp->cham;
+               if (mcham) {
+                       mtmp->cham = CHAM_ORDINARY;
+                       (void) newcham(mtmp, &mons[cham_to_pm[mcham]],
+                                      FALSE, FALSE);
+               }
+               if(is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN)
+                       new_were(mtmp);
+               if(mtmp->m_ap_type && cansee(mtmp->mx, mtmp->my)) {
+                       seemimic(mtmp);
+                       /* we pretend that the mimic doesn't */
+                       /* know that it has been unmasked.   */
+                       mtmp->msleeping = 1;
+               }
+       }
+}
+
+/* Let the chameleons change again -dgk */
+void
+restartcham()
+{
+       register struct monst *mtmp;
+
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+               if (DEADMONSTER(mtmp)) continue;
+               mtmp->cham = pm_to_cham(monsndx(mtmp->data));
+               if (mtmp->data->mlet == S_MIMIC && mtmp->msleeping &&
+                               cansee(mtmp->mx, mtmp->my)) {
+                       set_mimic_sym(mtmp);
+                       newsym(mtmp->mx,mtmp->my);
+               }
+       }
+}
+
+/* called when restoring a monster from a saved level; protection
+   against shape-changing might be different now than it was at the
+   time the level was saved. */
+void
+restore_cham(mon)
+struct monst *mon;
+{
+       int mcham;
+
+       if (Protection_from_shape_changers) {
+           mcham = (int) mon->cham;
+           if (mcham) {
+               mon->cham = CHAM_ORDINARY;
+               (void) newcham(mon, &mons[cham_to_pm[mcham]], FALSE, FALSE);
+           } else if (is_were(mon->data) && !is_human(mon->data)) {
+               new_were(mon);
+           }
+       } else if (mon->cham == CHAM_ORDINARY) {
+           mon->cham = pm_to_cham(monsndx(mon->data));
+       }
+}
+
+/* unwatched hiders may hide again; if so, a 1 is returned.  */
+STATIC_OVL boolean
+restrap(mtmp)
+register struct monst *mtmp;
+{
+       if(mtmp->cham || mtmp->mcan || mtmp->m_ap_type ||
+          cansee(mtmp->mx, mtmp->my) || rn2(3) || (mtmp == u.ustuck) ||
+          (sensemon(mtmp) && distu(mtmp->mx, mtmp->my) <= 2))
+               return(FALSE);
+
+       if(mtmp->data->mlet == S_MIMIC) {
+               set_mimic_sym(mtmp);
+               return(TRUE);
+       } else
+           if(levl[mtmp->mx][mtmp->my].typ == ROOM)  {
+               mtmp->mundetected = 1;
+               return(TRUE);
+           }
+
+       return(FALSE);
+}
+
+short *animal_list = 0;                /* list of PM values for animal monsters */
+int animal_list_count;
+
+void
+mon_animal_list(construct)
+boolean construct;
+{
+       if (construct) {
+           short animal_temp[SPECIAL_PM];
+           int i, n;
+
+        /* if (animal_list) impossible("animal_list already exists"); */
+
+           for (n = 0, i = LOW_PM; i < SPECIAL_PM; i++)
+               if (is_animal(&mons[i])) animal_temp[n++] = i;
+        /* if (n == 0) animal_temp[n++] = NON_PM; */
+
+           animal_list = (short *)alloc(n * sizeof *animal_list);
+           (void) memcpy((genericptr_t)animal_list,
+                         (genericptr_t)animal_temp,
+                         n * sizeof *animal_list);
+           animal_list_count = n;
+       } else {        /* release */
+           if (animal_list) free((genericptr_t)animal_list), animal_list = 0;
+           animal_list_count = 0;
+       }
+}
+
+STATIC_OVL int
+pick_animal()
+{
+       if (!animal_list) mon_animal_list(TRUE);
+
+       return animal_list[rn2(animal_list_count)];
+}
+
+STATIC_OVL int
+select_newcham_form(mon)
+struct monst *mon;
+{
+       int mndx = NON_PM;
+
+       switch (mon->cham) {
+           case CHAM_SANDESTIN:
+               if (rn2(7)) mndx = pick_nasty();
+               break;
+           case CHAM_DOPPELGANGER:
+               if (!rn2(7)) mndx = pick_nasty();
+               else if (rn2(3)) mndx = rn1(PM_WIZARD - PM_ARCHEOLOGIST + 1,
+                                           PM_ARCHEOLOGIST);
+               break;
+           case CHAM_CHAMELEON:
+               if (!rn2(3)) mndx = pick_animal();
+               break;
+           case CHAM_ORDINARY:
+             {
+               struct obj *m_armr = which_armor(mon, W_ARM);
+
+               if (m_armr && Is_dragon_scales(m_armr))
+                   mndx = Dragon_scales_to_pm(m_armr) - mons;
+               else if (m_armr && Is_dragon_mail(m_armr))
+                   mndx = Dragon_mail_to_pm(m_armr) - mons;
+             }
+               break;
+       }
+#ifdef WIZARD
+       /* For debugging only: allow control of polymorphed monster; not saved */
+       if (wizard && iflags.mon_polycontrol) {
+               char pprompt[BUFSZ], buf[BUFSZ];
+               int tries = 0;
+               do {
+                       Sprintf(pprompt,
+                               "Change %s into what kind of monster? [type the name]",
+                               mon_nam(mon));
+                       getlin(pprompt,buf);
+                       mndx = name_to_mon(buf);
+                       if (mndx < LOW_PM)
+                               You("cannot polymorph %s into that.", mon_nam(mon));
+                       else break;
+               } while(++tries < 5);
+               if (tries==5) pline(thats_enough_tries);
+       }
+#endif /*WIZARD*/
+       if (mndx == NON_PM) mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM);
+       return mndx;
+}
+
+/* make a chameleon look like a new monster; returns 1 if it actually changed */
+int
+newcham(mtmp, mdat, polyspot, msg)
+struct monst *mtmp;
+struct permonst *mdat;
+boolean polyspot;      /* change is the result of wand or spell of polymorph */
+boolean msg;           /* "The oldmon turns into a newmon!" */
+{
+       int mhp, hpn, hpd;
+       int mndx, tryct;
+       struct permonst *olddata = mtmp->data;
+       char oldname[BUFSZ];
+
+       if (msg) {
+           /* like Monnam() but never mention saddle */
+           Strcpy(oldname, x_monnam(mtmp, ARTICLE_THE, (char *)0,
+                                    SUPPRESS_SADDLE, FALSE));
+           oldname[0] = highc(oldname[0]);
+       }
+
+       /* mdat = 0 -> caller wants a random monster shape */
+       tryct = 0;
+       if (mdat == 0) {
+           while (++tryct <= 100) {
+               mndx = select_newcham_form(mtmp);
+               mdat = &mons[mndx];
+               if ((mvitals[mndx].mvflags & G_GENOD) != 0 ||
+                       is_placeholder(mdat)) continue;
+               /* polyok rules out all M2_PNAME and M2_WERE's;
+                  select_newcham_form might deliberately pick a player
+                  character type, so we can't arbitrarily rule out all
+                  human forms any more */
+               if (is_mplayer(mdat) || (!is_human(mdat) && polyok(mdat)))
+                   break;
+           }
+           if (tryct > 100) return 0;  /* Should never happen */
+       } else if (mvitals[monsndx(mdat)].mvflags & G_GENOD)
+           return(0);  /* passed in mdat is genocided */
+
+       if(is_male(mdat)) {
+               if(mtmp->female) mtmp->female = FALSE;
+       } else if (is_female(mdat)) {
+               if(!mtmp->female) mtmp->female = TRUE;
+       } else if (!is_neuter(mdat)) {
+               if(!rn2(10)) mtmp->female = !mtmp->female;
+       }
+
+       if (In_endgame(&u.uz) && is_mplayer(olddata)) {
+               /* mplayers start out as "Foo the Bar", but some of the
+                * titles are inappropriate when polymorphed, particularly
+                * into the opposite sex.  players don't use ranks when
+                * polymorphed, so dropping the rank for mplayers seems
+                * reasonable.
+                */
+               char *p = index(NAME(mtmp), ' ');
+               if (p) {
+                       *p = '\0';
+                       mtmp->mnamelth = p - NAME(mtmp) + 1;
+               }
+       }
+
+       if(mdat == mtmp->data) return(0);       /* still the same monster */
+
+       if(mtmp->wormno) {                      /* throw tail away */
+               wormgone(mtmp);
+               place_monster(mtmp, mtmp->mx, mtmp->my);
+       }
+
+       hpn = mtmp->mhp;
+       hpd = (mtmp->m_lev < 50) ? ((int)mtmp->m_lev)*8 : mdat->mlevel;
+       if(!hpd) hpd = 4;
+
+       mtmp->m_lev = adj_lev(mdat);            /* new monster level */
+
+       mhp = (mtmp->m_lev < 50) ? ((int)mtmp->m_lev)*8 : mdat->mlevel;
+       if(!mhp) mhp = 4;
+
+       /* new hp: same fraction of max as before */
+#ifndef LINT
+       mtmp->mhp = (int)(((long)hpn*(long)mhp)/(long)hpd);
+#endif
+       if(mtmp->mhp < 0) mtmp->mhp = hpn;      /* overflow */
+/* Unlikely but not impossible; a 1HD creature with 1HP that changes into a
+   0HD creature will require this statement */
+       if (!mtmp->mhp) mtmp->mhp = 1;
+
+/* and the same for maximum hit points */
+       hpn = mtmp->mhpmax;
+#ifndef LINT
+       mtmp->mhpmax = (int)(((long)hpn*(long)mhp)/(long)hpd);
+#endif
+       if(mtmp->mhpmax < 0) mtmp->mhpmax = hpn;        /* overflow */
+       if (!mtmp->mhpmax) mtmp->mhpmax = 1;
+
+       /* take on the new form... */
+       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);
+       mtmp->minvis = mtmp->invis_blkd ? 0 : mtmp->perminvis;
+       if (!(hides_under(mdat) && OBJ_AT(mtmp->mx, mtmp->my)) &&
+                       !(mdat->mlet == S_EEL && is_pool(mtmp->mx, mtmp->my)))
+               mtmp->mundetected = 0;
+       if (u.ustuck == mtmp) {
+               if(u.uswallow) {
+                       if(!attacktype(mdat,AT_ENGL)) {
+                               /* Does mdat care? */
+                               if (!noncorporeal(mdat) && !amorphous(mdat) &&
+                                   !is_whirly(mdat) &&
+                                   (mdat != &mons[PM_YELLOW_LIGHT])) {
+                                       You("break out of %s%s!", mon_nam(mtmp),
+                                           (is_animal(mdat)?
+                                           "'s stomach" : ""));
+                                       mtmp->mhp = 1;  /* almost dead */
+                               }
+                               expels(mtmp, olddata, FALSE);
+                       } else {
+                               /* update swallow glyphs for new monster */
+                               swallowed(0);
+                       }
+               } else if (!sticks(mdat) && !sticks(youmonst.data))
+                       unstuck(mtmp);
+       }
+
+#ifndef DCC30_BUG
+       if (mdat == &mons[PM_LONG_WORM] && (mtmp->wormno = get_wormno()) != 0) {
+#else
+       /* DICE 3.0 doesn't like assigning and comparing mtmp->wormno in the
+        * same expression.
+        */
+       if (mdat == &mons[PM_LONG_WORM] &&
+               (mtmp->wormno = get_wormno(), mtmp->wormno != 0)) {
+#endif
+           /* we can now create worms with tails - 11/91 */
+           initworm(mtmp, rn2(5));
+           if (count_wsegs(mtmp))
+               place_worm_tail_randomly(mtmp, mtmp->mx, mtmp->my);
+       }
+
+       newsym(mtmp->mx,mtmp->my);
+
+       if (msg) {
+           uchar save_mnamelth = mtmp->mnamelth;
+           mtmp->mnamelth = 0;
+           pline("%s turns into %s!", oldname,
+                 mdat == &mons[PM_GREEN_SLIME] ? "slime" :
+                 x_monnam(mtmp, ARTICLE_A, (char*)0, SUPPRESS_SADDLE, FALSE));
+           mtmp->mnamelth = save_mnamelth;
+       }
+
+       possibly_unwield(mtmp, polyspot);       /* might lose use of weapon */
+       mon_break_armor(mtmp, polyspot);
+       if (!(mtmp->misc_worn_check & W_ARMG))
+           mselftouch(mtmp, "No longer petrify-resistant, ",
+                       !flags.mon_moving);
+       m_dowear(mtmp, FALSE);
+
+       /* This ought to re-test can_carry() on each item in the inventory
+        * rather than just checking ex-giants & boulders, but that'd be
+        * pretty expensive to perform.  If implemented, then perhaps
+        * minvent should be sorted in order to drop heaviest items first.
+        */
+       /* former giants can't continue carrying boulders */
+       if (mtmp->minvent && !throws_rocks(mdat)) {
+           register struct obj *otmp, *otmp2;
+
+           for (otmp = mtmp->minvent; otmp; otmp = otmp2) {
+               otmp2 = otmp->nobj;
+               if (otmp->otyp == BOULDER) {
+                   /* this keeps otmp from being polymorphed in the
+                      same zap that the monster that held it is polymorphed */
+                   if (polyspot) bypass_obj(otmp);
+                   obj_extract_self(otmp);
+                   /* probably ought to give some "drop" message here */
+                   if (flooreffects(otmp, mtmp->mx, mtmp->my, "")) continue;
+                   place_object(otmp, mtmp->mx, mtmp->my);
+               }
+           }
+       }
+
+       return(1);
+}
+
+/* sometimes an egg will be special */
+#define BREEDER_EGG (!rn2(77))
+
+/*
+ * Determine if the given monster number can be hatched from an egg.
+ * Return the monster number to use as the egg's corpsenm.  Return
+ * NON_PM if the given monster can't be hatched.
+ */
+int
+can_be_hatched(mnum)
+int mnum;
+{
+    /* ranger quest nemesis has the oviparous bit set, making it
+       be possible to wish for eggs of that unique monster; turn
+       such into ordinary eggs rather than forbidding them outright */
+    if (mnum == PM_SCORPIUS) mnum = PM_SCORPION;
+
+    mnum = little_to_big(mnum);
+    /*
+     * Queen bees lay killer bee eggs (usually), but killer bees don't
+     * grow into queen bees.  Ditto for [winged-]gargoyles.
+     */
+    if (mnum == PM_KILLER_BEE || mnum == PM_GARGOYLE ||
+           (lays_eggs(&mons[mnum]) && (BREEDER_EGG ||
+               (mnum != PM_QUEEN_BEE && mnum != PM_WINGED_GARGOYLE))))
+       return mnum;
+    return NON_PM;
+}
+
+/* type of egg laid by #sit; usually matches parent */
+int
+egg_type_from_parent(mnum, force_ordinary)
+int mnum;      /* parent monster; caller must handle lays_eggs() check */
+boolean force_ordinary;
+{
+    if (force_ordinary || !BREEDER_EGG) {
+       if (mnum == PM_QUEEN_BEE) mnum = PM_KILLER_BEE;
+       else if (mnum == PM_WINGED_GARGOYLE) mnum = PM_GARGOYLE;
+    }
+    return mnum;
+}
+
+/* decide whether an egg of the indicated monster type is viable; */
+/* also used to determine whether an egg or tin can be created... */
+boolean
+dead_species(m_idx, egg)
+int m_idx;
+boolean egg;
+{
+       /*
+        * For monsters with both baby and adult forms, genociding either
+        * form kills all eggs of that monster.  Monsters with more than
+        * two forms (small->large->giant mimics) are more or less ignored;
+        * fortunately, none of them have eggs.  Species extinction due to
+        * overpopulation does not kill eggs.
+        */
+       return (boolean)
+               (m_idx >= LOW_PM &&
+                ((mvitals[m_idx].mvflags & G_GENOD) != 0 ||
+                 (egg &&
+                  (mvitals[big_to_little(m_idx)].mvflags & G_GENOD) != 0)));
+}
+
+/* kill off any eggs of genocided monsters */
+STATIC_OVL void
+kill_eggs(obj_list)
+struct obj *obj_list;
+{
+       struct obj *otmp;
+
+       for (otmp = obj_list; otmp; otmp = otmp->nobj)
+           if (otmp->otyp == EGG) {
+               if (dead_species(otmp->corpsenm, TRUE)) {
+                   /*
+                    * It seems we could also just catch this when
+                    * it attempted to hatch, so we wouldn't have to
+                    * search all of the objlists.. or stop all
+                    * hatch timers based on a corpsenm.
+                    */
+                   kill_egg(otmp);
+               }
+#if 0  /* not used */
+           } else if (otmp->otyp == TIN) {
+               if (dead_species(otmp->corpsenm, FALSE))
+                   otmp->corpsenm = NON_PM;    /* empty tin */
+           } else if (otmp->otyp == CORPSE) {
+               if (dead_species(otmp->corpsenm, FALSE))
+                   ;           /* not yet implemented... */
+#endif
+           } else if (Has_contents(otmp)) {
+               kill_eggs(otmp->cobj);
+           }
+}
+
+/* kill all members of genocided species */
+void
+kill_genocided_monsters()
+{
+       struct monst *mtmp, *mtmp2;
+       boolean kill_cham[CHAM_MAX_INDX+1];
+       int mndx;
+
+       kill_cham[CHAM_ORDINARY] = FALSE;       /* (this is mndx==0) */
+       for (mndx = 1; mndx <= CHAM_MAX_INDX; mndx++)
+         kill_cham[mndx] = (mvitals[cham_to_pm[mndx]].mvflags & G_GENOD) != 0;
+       /*
+        * Called during genocide, and again upon level change.  The latter
+        * catches up with any migrating monsters as they finally arrive at
+        * their intended destinations, so possessions get deposited there.
+        *
+        * Chameleon handling:
+        *      1) if chameleons have been genocided, destroy them
+        *         regardless of current form;
+        *      2) otherwise, force every chameleon which is imitating
+        *         any genocided species to take on a new form.
+        */
+       for (mtmp = fmon; mtmp; mtmp = mtmp2) {
+           mtmp2 = mtmp->nmon;
+           if (DEADMONSTER(mtmp)) continue;
+           mndx = monsndx(mtmp->data);
+           if ((mvitals[mndx].mvflags & G_GENOD) || kill_cham[mtmp->cham]) {
+               if (mtmp->cham && !kill_cham[mtmp->cham])
+                   (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE);
+               else
+                   mondead(mtmp);
+           }
+           if (mtmp->minvent) kill_eggs(mtmp->minvent);
+       }
+
+       kill_eggs(invent);
+       kill_eggs(fobj);
+       kill_eggs(level.buriedobjlist);
+}
+
+#endif /* OVL2 */
+#ifdef OVLB
+
+void
+golemeffects(mon, damtype, dam)
+register struct monst *mon;
+int damtype, dam;
+{
+    int heal = 0, slow = 0;
+
+    if (mon->data == &mons[PM_FLESH_GOLEM]) {
+       if (damtype == AD_ELEC) heal = dam / 6;
+       else if (damtype == AD_FIRE || damtype == AD_COLD) slow = 1;
+    } else if (mon->data == &mons[PM_IRON_GOLEM]) {
+       if (damtype == AD_ELEC) slow = 1;
+       else if (damtype == AD_FIRE) heal = dam;
+    } else {
+       return;
+    }
+    if (slow) {
+       if (mon->mspeed != MSLOW)
+           mon_adjust_speed(mon, -1, (struct obj *)0);
+    }
+    if (heal) {
+       if (mon->mhp < mon->mhpmax) {
+           mon->mhp += dam;
+           if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax;
+           if (cansee(mon->mx, mon->my))
+               pline("%s seems healthier.", Monnam(mon));
+       }
+    }
+}
+
+boolean
+angry_guards(silent)
+register boolean silent;
+{
+       register struct monst *mtmp;
+       register int ct = 0, nct = 0, sct = 0, slct = 0;
+
+       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+               if (DEADMONSTER(mtmp)) continue;
+               if((mtmp->data == &mons[PM_WATCHMAN] ||
+                              mtmp->data == &mons[PM_WATCH_CAPTAIN])
+                                       && mtmp->mpeaceful) {
+                       ct++;
+                       if(cansee(mtmp->mx, mtmp->my) && mtmp->mcanmove) {
+                               if (distu(mtmp->mx, mtmp->my) == 2) nct++;
+                               else sct++;
+                       }
+                       if (mtmp->msleeping || mtmp->mfrozen) {
+                               slct++;
+                               mtmp->msleeping = mtmp->mfrozen = 0;
+                       }
+                       mtmp->mpeaceful = 0;
+               }
+       }
+       if(ct) {
+           if(!silent) { /* do we want pline msgs? */
+               if(slct) pline_The("guard%s wake%s up!",
+                                slct > 1 ? "s" : "", slct == 1 ? "s" : "");
+               if(nct || sct) {
+                       if(nct) pline_The("guard%s get%s angry!",
+                               nct == 1 ? "" : "s", nct == 1 ? "s" : "");
+                       else if(!Blind)
+                               You("see %sangry guard%s approaching!",
+                                 sct == 1 ? "an " : "", sct > 1 ? "s" : "");
+               } else if(flags.soundok)
+                       You_hear("the shrill sound of a guard's whistle.");
+           }
+           return(TRUE);
+       }
+       return(FALSE);
+}
+
+void
+pacify_guards()
+{
+       register struct monst *mtmp;
+
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+           if (DEADMONSTER(mtmp)) continue;
+           if (mtmp->data == &mons[PM_WATCHMAN] ||
+               mtmp->data == &mons[PM_WATCH_CAPTAIN])
+           mtmp->mpeaceful = 1;
+       }
+}
+
+void
+mimic_hit_msg(mtmp, otyp)
+struct monst *mtmp;
+short otyp;
+{
+       short ap = mtmp->mappearance;
+
+       switch(mtmp->m_ap_type) {
+           case M_AP_NOTHING:                  
+           case M_AP_FURNITURE:
+           case M_AP_MONSTER:
+               break;
+           case M_AP_OBJECT:
+               if (otyp == SPE_HEALING || otyp == SPE_EXTRA_HEALING) {
+                   pline("%s seems a more vivid %s than before.",
+                               The(simple_typename(ap)),
+                               c_obj_colors[objects[ap].oc_color]);
+               }
+               break;
+       }
+}
+#endif /* OVLB */
+
+/*mon.c*/
diff --git a/src/mondata.c b/src/mondata.c
new file mode 100644 (file)
index 0000000..c66be4f
--- /dev/null
@@ -0,0 +1,757 @@
+/*     SCCS Id: @(#)mondata.c  3.4     2003/06/02      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "eshk.h"
+#include "epri.h"
+
+/*     These routines provide basic data for any type of monster. */
+
+#ifdef OVLB
+
+void
+set_mon_data(mon, ptr, flag)
+struct monst *mon;
+struct permonst *ptr;
+int flag;
+{
+    mon->data = ptr;
+    if (flag == -1) return;            /* "don't care" */
+
+    if (flag == 1)
+       mon->mintrinsics |= (ptr->mresists & 0x00FF);
+    else
+       mon->mintrinsics = (ptr->mresists & 0x00FF);
+    return;
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+struct attack *
+attacktype_fordmg(ptr, atyp, dtyp)
+struct permonst *ptr;
+int atyp, dtyp;
+{
+    struct attack *a;
+
+    for (a = &ptr->mattk[0]; a < &ptr->mattk[NATTK]; a++)
+       if (a->aatyp == atyp && (dtyp == AD_ANY || a->adtyp == dtyp))
+           return a;
+
+    return (struct attack *)0;
+}
+
+boolean
+attacktype(ptr, atyp)
+struct permonst *ptr;
+int atyp;
+{
+    return attacktype_fordmg(ptr, atyp, AD_ANY) ? TRUE : FALSE;
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+boolean
+poly_when_stoned(ptr)
+    struct permonst *ptr;
+{
+    return((boolean)(is_golem(ptr) && ptr != &mons[PM_STONE_GOLEM] &&
+           !(mvitals[PM_STONE_GOLEM].mvflags & G_GENOD)));
+           /* allow G_EXTINCT */
+}
+
+boolean
+resists_drli(mon)      /* returns TRUE if monster is drain-life resistant */
+struct monst *mon;
+{
+       struct permonst *ptr = mon->data;
+       struct obj *wep = ((mon == &youmonst) ? uwep : MON_WEP(mon));
+
+       return (boolean)(is_undead(ptr) || is_demon(ptr) || is_were(ptr) ||
+                        ptr == &mons[PM_DEATH] ||
+                        (wep && wep->oartifact && defends(AD_DRLI, wep)));
+}
+
+boolean
+resists_magm(mon)      /* TRUE if monster is magic-missile resistant */
+struct monst *mon;
+{
+       struct permonst *ptr = mon->data;
+       struct obj *o;
+
+       /* as of 3.2.0:  gray dragons, Angels, Oracle, Yeenoghu */
+       if (dmgtype(ptr, AD_MAGM) || ptr == &mons[PM_BABY_GRAY_DRAGON] ||
+               dmgtype(ptr, AD_RBRE))  /* Chromatic Dragon */
+           return TRUE;
+       /* check for magic resistance granted by wielded weapon */
+       o = (mon == &youmonst) ? uwep : MON_WEP(mon);
+       if (o && o->oartifact && defends(AD_MAGM, o))
+           return TRUE;
+       /* check for magic resistance granted by worn or carried items */
+       o = (mon == &youmonst) ? invent : mon->minvent;
+       for ( ; o; o = o->nobj)
+           if ((o->owornmask && objects[o->otyp].oc_oprop == ANTIMAGIC) ||
+                   (o->oartifact && protects(AD_MAGM, o)))
+               return TRUE;
+       return FALSE;
+}
+
+/* TRUE iff monster is resistant to light-induced blindness */
+boolean
+resists_blnd(mon)
+struct monst *mon;
+{
+       struct permonst *ptr = mon->data;
+       boolean is_you = (mon == &youmonst);
+       struct obj *o;
+
+       if (is_you ? (Blind || u.usleep) :
+               (mon->mblinded || !mon->mcansee || !haseyes(ptr) ||
+                   /* BUG: temporary sleep sets mfrozen, but since
+                           paralysis does too, we can't check it */
+                   mon->msleeping))
+           return TRUE;
+       /* yellow light, Archon; !dust vortex, !cobra, !raven */
+       if (dmgtype_fromattack(ptr, AD_BLND, AT_EXPL) ||
+               dmgtype_fromattack(ptr, AD_BLND, AT_GAZE))
+           return TRUE;
+       o = is_you ? uwep : MON_WEP(mon);
+       if (o && o->oartifact && defends(AD_BLND, o))
+           return TRUE;
+       o = is_you ? invent : mon->minvent;
+       for ( ; o; o = o->nobj)
+           if ((o->owornmask && objects[o->otyp].oc_oprop == BLINDED) ||
+                   (o->oartifact && protects(AD_BLND, o)))
+               return TRUE;
+       return FALSE;
+}
+
+/* TRUE iff monster can be blinded by the given attack */
+/* Note: may return TRUE when mdef is blind (e.g. new cream-pie attack) */
+boolean
+can_blnd(magr, mdef, aatyp, obj)
+struct monst *magr;            /* NULL == no specific aggressor */
+struct monst *mdef;
+uchar aatyp;
+struct obj *obj;               /* aatyp == AT_WEAP, AT_SPIT */
+{
+       boolean is_you = (mdef == &youmonst);
+       boolean check_visor = FALSE;
+       struct obj *o;
+       const char *s;
+
+       /* no eyes protect against all attacks for now */
+       if (!haseyes(mdef->data))
+           return FALSE;
+
+       switch(aatyp) {
+       case AT_EXPL: case AT_BOOM: case AT_GAZE: case AT_MAGC:
+       case AT_BREA: /* assumed to be lightning */
+           /* light-based attacks may be cancelled or resisted */
+           if (magr && magr->mcan)
+               return FALSE;
+           return !resists_blnd(mdef);
+
+       case AT_WEAP: case AT_SPIT: case AT_NONE:
+           /* an object is used (thrown/spit/other) */
+           if (obj && (obj->otyp == CREAM_PIE)) {
+               if (is_you && Blindfolded)
+                   return FALSE;
+           } else if (obj && (obj->otyp == BLINDING_VENOM)) {
+               /* all ublindf, including LENSES, protect, cream-pies too */
+               if (is_you && (ublindf || u.ucreamed))
+                   return FALSE;
+               check_visor = TRUE;
+           } else if (obj && (obj->otyp == POT_BLINDNESS)) {
+               return TRUE;    /* no defense */
+           } else
+               return FALSE;   /* other objects cannot cause blindness yet */
+           if ((magr == &youmonst) && u.uswallow)
+               return FALSE;   /* can't affect eyes while inside monster */
+           break;
+
+       case AT_ENGL:
+           if (is_you && (Blindfolded || u.usleep || u.ucreamed))
+               return FALSE;
+           if (!is_you && mdef->msleeping)
+               return FALSE;
+           break;
+
+       case AT_CLAW:
+           /* e.g. raven: all ublindf, including LENSES, protect */
+           if (is_you && ublindf)
+               return FALSE;
+           if ((magr == &youmonst) && u.uswallow)
+               return FALSE;   /* can't affect eyes while inside monster */
+           check_visor = TRUE;
+           break;
+
+       case AT_TUCH: case AT_STNG:
+           /* some physical, blind-inducing attacks can be cancelled */
+           if (magr && magr->mcan)
+               return FALSE;
+           break;
+
+       default:
+           break;
+       }
+
+       /* check if wearing a visor (only checked if visor might help) */
+       if (check_visor) {
+           o = (mdef == &youmonst) ? invent : mdef->minvent;
+           for ( ; o; o = o->nobj)
+               if ((o->owornmask & W_ARMH) &&
+                   (s = OBJ_DESCR(objects[o->otyp])) != (char *)0 &&
+                   !strcmp(s, "visored helmet"))
+                   return FALSE;
+       }
+
+       return TRUE;
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+boolean
+ranged_attk(ptr)       /* returns TRUE if monster can attack at range */
+struct permonst *ptr;
+{
+       register int i, atyp;
+       long atk_mask = (1L << AT_BREA) | (1L << AT_SPIT) | (1L << AT_GAZE);
+
+       /* was: (attacktype(ptr, AT_BREA) || attacktype(ptr, AT_WEAP) ||
+               attacktype(ptr, AT_SPIT) || attacktype(ptr, AT_GAZE) ||
+               attacktype(ptr, AT_MAGC));
+          but that's too slow -dlc
+        */
+       for (i = 0; i < NATTK; i++) {
+           atyp = ptr->mattk[i].aatyp;
+           if (atyp >= AT_WEAP) return TRUE;
+        /* assert(atyp < 32); */
+           if ((atk_mask & (1L << atyp)) != 0L) return TRUE;
+       }
+
+       return FALSE;
+}
+
+boolean
+hates_silver(ptr)
+register struct permonst *ptr;
+/* returns TRUE if monster is especially affected by silver weapons */
+{
+       return((boolean)(is_were(ptr) || ptr->mlet==S_VAMPIRE || is_demon(ptr) ||
+               ptr == &mons[PM_SHADE] ||
+               (ptr->mlet==S_IMP && ptr != &mons[PM_TENGU])));
+}
+
+/* true iff the type of monster pass through iron bars */
+boolean
+passes_bars(mptr)
+struct permonst *mptr;
+{
+    return (boolean) (passes_walls(mptr) || amorphous(mptr) ||
+                     is_whirly(mptr) || verysmall(mptr) ||
+                     (slithy(mptr) && !bigmonst(mptr)));
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+boolean
+can_track(ptr)         /* returns TRUE if monster can track well */
+       register struct permonst *ptr;
+{
+       if (uwep && uwep->oartifact == ART_EXCALIBUR)
+               return TRUE;
+       else
+               return((boolean)haseyes(ptr));
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+boolean
+sliparm(ptr)   /* creature will slide out of armor */
+       register struct permonst *ptr;
+{
+       return((boolean)(is_whirly(ptr) || ptr->msize <= MZ_SMALL ||
+                        noncorporeal(ptr)));
+}
+
+boolean
+breakarm(ptr)  /* creature will break out of armor */
+       register struct permonst *ptr;
+{
+       return ((bigmonst(ptr) || (ptr->msize > MZ_SMALL && !humanoid(ptr)) ||
+               /* special cases of humanoids that cannot wear body armor */
+               ptr == &mons[PM_MARILITH] || ptr == &mons[PM_WINGED_GARGOYLE])
+             && !sliparm(ptr));
+}
+#endif /* OVLB */
+#ifdef OVL1
+
+boolean
+sticks(ptr)    /* creature sticks other creatures it hits */
+       register struct permonst *ptr;
+{
+       return((boolean)(dmgtype(ptr,AD_STCK) || dmgtype(ptr,AD_WRAP) ||
+               attacktype(ptr,AT_HUGS)));
+}
+
+/* number of horns this type of monster has on its head */
+int
+num_horns(ptr)
+struct permonst *ptr;
+{
+    switch (monsndx(ptr)) {
+    case PM_HORNED_DEVIL:      /* ? "more than one" */
+    case PM_MINOTAUR:
+    case PM_ASMODEUS:
+    case PM_BALROG:
+       return 2;
+    case PM_WHITE_UNICORN:
+    case PM_GRAY_UNICORN:
+    case PM_BLACK_UNICORN:
+    case PM_KI_RIN:
+       return 1;
+    default:
+       break;
+    }
+    return 0;
+}
+
+struct attack *
+dmgtype_fromattack(ptr, dtyp, atyp)
+struct permonst *ptr;
+int dtyp, atyp;
+{
+    struct attack *a;
+
+    for (a = &ptr->mattk[0]; a < &ptr->mattk[NATTK]; a++)
+       if (a->adtyp == dtyp && (atyp == AT_ANY || a->aatyp == atyp))
+           return a;
+
+    return (struct attack *)0;
+}
+
+boolean
+dmgtype(ptr, dtyp)
+struct permonst *ptr;
+int dtyp;
+{
+    return dmgtype_fromattack(ptr, dtyp, AT_ANY) ? TRUE : FALSE;
+}
+
+/* returns the maximum damage a defender can do to the attacker via
+ * a passive defense */
+int
+max_passive_dmg(mdef, magr)
+    register struct monst *mdef, *magr;
+{
+    int        i, dmg = 0;
+    uchar adtyp;
+
+    for(i = 0; i < NATTK; i++)
+       if(mdef->data->mattk[i].aatyp == AT_NONE ||
+               mdef->data->mattk[i].aatyp == AT_BOOM) {
+           adtyp = mdef->data->mattk[i].adtyp;
+           if ((adtyp == AD_ACID && !resists_acid(magr)) ||
+                   (adtyp == AD_COLD && !resists_cold(magr)) ||
+                   (adtyp == AD_FIRE && !resists_fire(magr)) ||
+                   (adtyp == AD_ELEC && !resists_elec(magr)) ||
+                   adtyp == AD_PHYS) {
+               dmg = mdef->data->mattk[i].damn;
+               if(!dmg) dmg = mdef->data->mlevel+1;
+               dmg *= mdef->data->mattk[i].damd;
+           } else dmg = 0;
+
+           return dmg;
+       }
+    return 0;
+}
+
+#endif /* OVL1 */
+#ifdef OVL0
+
+int
+monsndx(ptr)           /* return an index into the mons array */
+       struct  permonst        *ptr;
+{
+       register int    i;
+
+       i = (int)(ptr - &mons[0]);
+       if (i < LOW_PM || i >= NUMMONS) {
+               /* ought to switch this to use `fmt_ptr' */
+           panic("monsndx - could not index monster (%lx)",
+                 (unsigned long)ptr);
+           return NON_PM;              /* will not get here */
+       }
+
+       return(i);
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+
+int
+name_to_mon(in_str)
+const char *in_str;
+{
+       /* Be careful.  We must check the entire string in case it was
+        * something such as "ettin zombie corpse".  The calling routine
+        * doesn't know about the "corpse" until the monster name has
+        * already been taken off the front, so we have to be able to
+        * read the name with extraneous stuff such as "corpse" stuck on
+        * the end.
+        * This causes a problem for names which prefix other names such
+        * as "ettin" on "ettin zombie".  In this case we want the _longest_
+        * name which exists.
+        * This also permits plurals created by adding suffixes such as 's'
+        * or 'es'.  Other plurals must still be handled explicitly.
+        */
+       register int i;
+       register int mntmp = NON_PM;
+       register char *s, *str, *term;
+       char buf[BUFSZ];
+       int len, slen;
+
+       str = strcpy(buf, in_str);
+
+       if (!strncmp(str, "a ", 2)) str += 2;
+       else if (!strncmp(str, "an ", 3)) str += 3;
+
+       slen = strlen(str);
+       term = str + slen;
+
+       if ((s = strstri(str, "vortices")) != 0)
+           Strcpy(s+4, "ex");
+       /* be careful with "ies"; "priest", "zombies" */
+       else if (slen > 3 && !strcmpi(term-3, "ies") &&
+                   (slen < 7 || strcmpi(term-7, "zombies")))
+           Strcpy(term-3, "y");
+       /* luckily no monster names end in fe or ve with ves plurals */
+       else if (slen > 3 && !strcmpi(term-3, "ves"))
+           Strcpy(term-3, "f");
+
+       slen = strlen(str); /* length possibly needs recomputing */
+
+    {
+       static const struct alt_spl { const char* name; short pm_val; }
+           names[] = {
+           /* Alternate spellings */
+               { "grey dragon",        PM_GRAY_DRAGON },
+               { "baby grey dragon",   PM_BABY_GRAY_DRAGON },
+               { "grey unicorn",       PM_GRAY_UNICORN },
+               { "grey ooze",          PM_GRAY_OOZE },
+               { "gray-elf",           PM_GREY_ELF },
+           /* Hyphenated names */
+               { "ki rin",             PM_KI_RIN },
+               { "uruk hai",           PM_URUK_HAI },
+               { "orc captain",        PM_ORC_CAPTAIN },
+               { "woodland elf",       PM_WOODLAND_ELF },
+               { "green elf",          PM_GREEN_ELF },
+               { "grey elf",           PM_GREY_ELF },
+               { "gray elf",           PM_GREY_ELF },
+               { "elf lord",           PM_ELF_LORD },
+#if 0  /* OBSOLETE */
+               { "high elf",           PM_HIGH_ELF },
+#endif
+               { "olog hai",           PM_OLOG_HAI },
+               { "arch lich",          PM_ARCH_LICH },
+           /* Some irregular plurals */
+               { "incubi",             PM_INCUBUS },
+               { "succubi",            PM_SUCCUBUS },
+               { "violet fungi",       PM_VIOLET_FUNGUS },
+               { "homunculi",          PM_HOMUNCULUS },
+               { "baluchitheria",      PM_BALUCHITHERIUM },
+               { "lurkers above",      PM_LURKER_ABOVE },
+               { "cavemen",            PM_CAVEMAN },
+               { "cavewomen",          PM_CAVEWOMAN },
+               { "djinn",              PM_DJINNI },
+               { "mumakil",            PM_MUMAK },
+               { "erinyes",            PM_ERINYS },
+           /* falsely caught by -ves check above */
+               { "master of thief",    PM_MASTER_OF_THIEVES },
+           /* end of list */
+               { 0, 0 }
+       };
+       register const struct alt_spl *namep;
+
+       for (namep = names; namep->name; namep++)
+           if (!strncmpi(str, namep->name, (int)strlen(namep->name)))
+               return namep->pm_val;
+    }
+
+       for (len = 0, i = LOW_PM; i < NUMMONS; i++) {
+           register int m_i_len = strlen(mons[i].mname);
+           if (m_i_len > len && !strncmpi(mons[i].mname, str, m_i_len)) {
+               if (m_i_len == slen) return i;  /* exact match */
+               else if (slen > m_i_len &&
+                       (str[m_i_len] == ' ' ||
+                        !strcmpi(&str[m_i_len], "s") ||
+                        !strncmpi(&str[m_i_len], "s ", 2) ||
+                        !strcmpi(&str[m_i_len], "'") ||
+                        !strncmpi(&str[m_i_len], "' ", 2) ||
+                        !strcmpi(&str[m_i_len], "'s") ||
+                        !strncmpi(&str[m_i_len], "'s ", 3) ||
+                        !strcmpi(&str[m_i_len], "es") ||
+                        !strncmpi(&str[m_i_len], "es ", 3))) {
+                   mntmp = i;
+                   len = m_i_len;
+               }
+           }
+       }
+       if (mntmp == NON_PM) mntmp = title_to_mon(str, (int *)0, (int *)0);
+       return mntmp;
+}
+
+#endif /* OVL1 */
+#ifdef OVL2
+
+/* returns 3 values (0=male, 1=female, 2=none) */
+int
+gender(mtmp)
+register struct monst *mtmp;
+{
+       if (is_neuter(mtmp->data)) return 2;
+       return mtmp->female;
+}
+
+/* Like gender(), but lower animals and such are still "it". */
+/* This is the one we want to use when printing messages. */
+int
+pronoun_gender(mtmp)
+register struct monst *mtmp;
+{
+       if (is_neuter(mtmp->data) || !canspotmon(mtmp)) return 2;
+       return (humanoid(mtmp->data) || (mtmp->data->geno & G_UNIQ) ||
+               type_is_pname(mtmp->data)) ? (int)mtmp->female : 2;
+}
+
+#endif /* OVL2 */
+#ifdef OVLB
+
+/* used for nearby monsters when you go to another level */
+boolean
+levl_follower(mtmp)
+struct monst *mtmp;
+{
+       /* monsters with the Amulet--even pets--won't follow across levels */
+       if (mon_has_amulet(mtmp)) return FALSE;
+
+       /* some monsters will follow even while intending to flee from you */
+       if (mtmp->mtame || mtmp->iswiz || is_fshk(mtmp)) return TRUE;
+
+       /* stalking types follow, but won't when fleeing unless you hold
+          the Amulet */
+       return (boolean)((mtmp->data->mflags2 & M2_STALK) &&
+                               (!mtmp->mflee || u.uhave.amulet));
+}
+
+static const short grownups[][2] = {
+       {PM_CHICKATRICE, PM_COCKATRICE},
+       {PM_LITTLE_DOG, PM_DOG}, {PM_DOG, PM_LARGE_DOG},
+       {PM_HELL_HOUND_PUP, PM_HELL_HOUND},
+       {PM_WINTER_WOLF_CUB, PM_WINTER_WOLF},
+       {PM_KITTEN, PM_HOUSECAT}, {PM_HOUSECAT, PM_LARGE_CAT},
+       {PM_PONY, PM_HORSE}, {PM_HORSE, PM_WARHORSE},
+       {PM_KOBOLD, PM_LARGE_KOBOLD}, {PM_LARGE_KOBOLD, PM_KOBOLD_LORD},
+       {PM_GNOME, PM_GNOME_LORD}, {PM_GNOME_LORD, PM_GNOME_KING},
+       {PM_DWARF, PM_DWARF_LORD}, {PM_DWARF_LORD, PM_DWARF_KING},
+       {PM_MIND_FLAYER, PM_MASTER_MIND_FLAYER},
+       {PM_ORC, PM_ORC_CAPTAIN}, {PM_HILL_ORC, PM_ORC_CAPTAIN},
+       {PM_MORDOR_ORC, PM_ORC_CAPTAIN}, {PM_URUK_HAI, PM_ORC_CAPTAIN},
+       {PM_SEWER_RAT, PM_GIANT_RAT},
+       {PM_CAVE_SPIDER, PM_GIANT_SPIDER},
+       {PM_OGRE, PM_OGRE_LORD}, {PM_OGRE_LORD, PM_OGRE_KING},
+       {PM_ELF, PM_ELF_LORD}, {PM_WOODLAND_ELF, PM_ELF_LORD},
+       {PM_GREEN_ELF, PM_ELF_LORD}, {PM_GREY_ELF, PM_ELF_LORD},
+       {PM_ELF_LORD, PM_ELVENKING},
+       {PM_LICH, PM_DEMILICH}, {PM_DEMILICH, PM_MASTER_LICH},
+       {PM_MASTER_LICH, PM_ARCH_LICH},
+       {PM_VAMPIRE, PM_VAMPIRE_LORD}, {PM_BAT, PM_GIANT_BAT},
+       {PM_BABY_GRAY_DRAGON, PM_GRAY_DRAGON},
+       {PM_BABY_SILVER_DRAGON, PM_SILVER_DRAGON},
+#if 0  /* DEFERRED */
+       {PM_BABY_SHIMMERING_DRAGON, PM_SHIMMERING_DRAGON},
+#endif
+       {PM_BABY_RED_DRAGON, PM_RED_DRAGON},
+       {PM_BABY_WHITE_DRAGON, PM_WHITE_DRAGON},
+       {PM_BABY_ORANGE_DRAGON, PM_ORANGE_DRAGON},
+       {PM_BABY_BLACK_DRAGON, PM_BLACK_DRAGON},
+       {PM_BABY_BLUE_DRAGON, PM_BLUE_DRAGON},
+       {PM_BABY_GREEN_DRAGON, PM_GREEN_DRAGON},
+       {PM_BABY_YELLOW_DRAGON, PM_YELLOW_DRAGON},
+       {PM_RED_NAGA_HATCHLING, PM_RED_NAGA},
+       {PM_BLACK_NAGA_HATCHLING, PM_BLACK_NAGA},
+       {PM_GOLDEN_NAGA_HATCHLING, PM_GOLDEN_NAGA},
+       {PM_GUARDIAN_NAGA_HATCHLING, PM_GUARDIAN_NAGA},
+       {PM_SMALL_MIMIC, PM_LARGE_MIMIC}, {PM_LARGE_MIMIC, PM_GIANT_MIMIC},
+       {PM_BABY_LONG_WORM, PM_LONG_WORM},
+       {PM_BABY_PURPLE_WORM, PM_PURPLE_WORM},
+       {PM_BABY_CROCODILE, PM_CROCODILE},
+       {PM_SOLDIER, PM_SERGEANT},
+       {PM_SERGEANT, PM_LIEUTENANT},
+       {PM_LIEUTENANT, PM_CAPTAIN},
+       {PM_WATCHMAN, PM_WATCH_CAPTAIN},
+       {PM_ALIGNED_PRIEST, PM_HIGH_PRIEST},
+       {PM_STUDENT, PM_ARCHEOLOGIST},
+       {PM_ATTENDANT, PM_HEALER},
+       {PM_PAGE, PM_KNIGHT},
+       {PM_ACOLYTE, PM_PRIEST},
+       {PM_APPRENTICE, PM_WIZARD},
+       {PM_MANES,PM_LEMURE},
+#ifdef KOPS
+       {PM_KEYSTONE_KOP, PM_KOP_SERGEANT},
+       {PM_KOP_SERGEANT, PM_KOP_LIEUTENANT},
+       {PM_KOP_LIEUTENANT, PM_KOP_KAPTAIN},
+#endif
+       {NON_PM,NON_PM}
+};
+
+int
+little_to_big(montype)
+int montype;
+{
+#ifndef AIXPS2_BUG
+       register int i;
+
+       for (i = 0; grownups[i][0] >= LOW_PM; i++)
+               if(montype == grownups[i][0]) return grownups[i][1];
+       return montype;
+#else
+/* AIX PS/2 C-compiler 1.1.1 optimizer does not like the above for loop,
+ * and causes segmentation faults at runtime.  (The problem does not
+ * occur if -O is not used.)
+ * lehtonen@cs.Helsinki.FI (Tapio Lehtonen) 28031990
+ */
+       int i;
+       int monvalue;
+
+       monvalue = montype;
+       for (i = 0; grownups[i][0] >= LOW_PM; i++)
+               if(montype == grownups[i][0]) monvalue = grownups[i][1];
+
+       return monvalue;
+#endif
+}
+
+int
+big_to_little(montype)
+int montype;
+{
+       register int i;
+
+       for (i = 0; grownups[i][0] >= LOW_PM; i++)
+               if(montype == grownups[i][1]) return grownups[i][0];
+       return montype;
+}
+
+/*
+ * Return the permonst ptr for the race of the monster.
+ * Returns correct pointer for non-polymorphed and polymorphed
+ * player.  It does not return a pointer to player role character.
+ */
+const struct permonst *
+raceptr(mtmp)
+struct monst *mtmp;
+{
+    if (mtmp == &youmonst && !Upolyd) return(&mons[urace.malenum]);
+    else return(mtmp->data);
+}
+
+static const char *levitate[4] = { "float", "Float", "wobble", "Wobble" };
+static const char *flys[4]     = { "fly", "Fly", "flutter", "Flutter" };
+static const char *flyl[4]     = { "fly", "Fly", "stagger", "Stagger" };
+static const char *slither[4]  = { "slither", "Slither", "falter", "Falter" };
+static const char *ooze[4]     = { "ooze", "Ooze", "tremble", "Tremble" };
+static const char *immobile[4] = { "wiggle", "Wiggle", "pulsate", "Pulsate" };
+static const char *crawl[4]    = { "crawl", "Crawl", "falter", "Falter" };
+
+const char *
+locomotion(ptr, def)
+const struct permonst *ptr;
+const char *def;
+{
+       int capitalize = (*def == highc(*def));
+
+       return (
+               is_floater(ptr) ? levitate[capitalize] :
+               (is_flyer(ptr) && ptr->msize <= MZ_SMALL) ? flys[capitalize] :
+               (is_flyer(ptr) && ptr->msize > MZ_SMALL)  ? flyl[capitalize] :
+               slithy(ptr)     ? slither[capitalize] :
+               amorphous(ptr)  ? ooze[capitalize] :
+               !ptr->mmove     ? immobile[capitalize] :
+               nolimbs(ptr)    ? crawl[capitalize] :
+               def
+              );
+
+}
+
+const char *
+stagger(ptr, def)
+const struct permonst *ptr;
+const char *def;
+{
+       int capitalize = 2 + (*def == highc(*def));
+
+       return (
+               is_floater(ptr) ? levitate[capitalize] :
+               (is_flyer(ptr) && ptr->msize <= MZ_SMALL) ? flys[capitalize] :
+               (is_flyer(ptr) && ptr->msize > MZ_SMALL)  ? flyl[capitalize] :
+               slithy(ptr)     ? slither[capitalize] :
+               amorphous(ptr)  ? ooze[capitalize] :
+               !ptr->mmove     ? immobile[capitalize] :
+               nolimbs(ptr)    ? crawl[capitalize] :
+               def
+              );
+
+}
+
+/* return a phrase describing the effect of fire attack on a type of monster */
+const char *
+on_fire(mptr, mattk)
+struct permonst *mptr;
+struct attack *mattk;
+{
+    const char *what;
+
+    switch (monsndx(mptr)) {
+    case PM_FLAMING_SPHERE:
+    case PM_FIRE_VORTEX:
+    case PM_FIRE_ELEMENTAL:
+    case PM_SALAMANDER:
+       what = "already on fire";
+       break;
+    case PM_WATER_ELEMENTAL:
+    case PM_FOG_CLOUD:
+    case PM_STEAM_VORTEX:
+       what = "boiling";
+       break;
+    case PM_ICE_VORTEX:
+    case PM_GLASS_GOLEM:
+       what = "melting";
+       break;
+    case PM_STONE_GOLEM:
+    case PM_CLAY_GOLEM:
+    case PM_GOLD_GOLEM:
+    case PM_AIR_ELEMENTAL:
+    case PM_EARTH_ELEMENTAL:
+    case PM_DUST_VORTEX:
+    case PM_ENERGY_VORTEX:
+       what = "heating up";
+       break;
+    default:
+       what = (mattk->aatyp == AT_HUGS) ? "being roasted" : "on fire";
+       break;
+    }
+    return what;
+}
+
+#endif /* OVLB */
+
+/*mondata.c*/
diff --git a/src/monmove.c b/src/monmove.c
new file mode 100644 (file)
index 0000000..309fd32
--- /dev/null
@@ -0,0 +1,1369 @@
+/*     SCCS Id: @(#)monmove.c  3.4     2002/04/06      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "mfndpos.h"
+#include "artifact.h"
+#include "epri.h"
+
+extern boolean notonhead;
+
+#ifdef OVL0
+
+STATIC_DCL int FDECL(disturb,(struct monst *));
+STATIC_DCL void FDECL(distfleeck,(struct monst *,int *,int *,int *));
+STATIC_DCL int FDECL(m_arrival, (struct monst *));
+STATIC_DCL void FDECL(watch_on_duty,(struct monst *));
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+boolean /* TRUE : mtmp died */
+mb_trapped(mtmp)
+register struct monst *mtmp;
+{
+       if (flags.verbose) {
+           if (cansee(mtmp->mx, mtmp->my))
+               pline("KABOOM!!  You see a door explode.");
+           else if (flags.soundok)
+               You_hear("a distant explosion.");
+       }
+       wake_nearto(mtmp->mx, mtmp->my, 7*7);
+       mtmp->mstun = 1;
+       mtmp->mhp -= rnd(15);
+       if(mtmp->mhp <= 0) {
+               mondied(mtmp);
+               if (mtmp->mhp > 0) /* lifesaved */
+                       return(FALSE);
+               else
+                       return(TRUE);
+       }
+       return(FALSE);
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+STATIC_OVL void
+watch_on_duty(mtmp)
+register struct monst *mtmp;
+{
+       int     x, y;
+
+       if(mtmp->mpeaceful && in_town(u.ux+u.dx, u.uy+u.dy) &&
+          mtmp->mcansee && m_canseeu(mtmp) && !rn2(3)) {
+
+           if(picking_lock(&x, &y) && IS_DOOR(levl[x][y].typ) &&
+              (levl[x][y].doormask & D_LOCKED)) {
+
+               if(couldsee(mtmp->mx, mtmp->my)) {
+
+                 pline("%s yells:", Amonnam(mtmp));
+                 if(levl[x][y].looted & D_WARNED) {
+                       verbalize("Halt, thief!  You're under arrest!");
+                       (void) angry_guards(!(flags.soundok));
+                 } else {
+                       verbalize("Hey, stop picking that lock!");
+                       levl[x][y].looted |=  D_WARNED;
+                 }
+                 stop_occupation();
+               }
+           } else if (is_digging()) {
+               /* chewing, wand/spell of digging are checked elsewhere */
+               watch_dig(mtmp, digging.pos.x, digging.pos.y, FALSE);
+           }
+       }
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+int
+dochugw(mtmp)
+       register struct monst *mtmp;
+{
+       register int x = mtmp->mx, y = mtmp->my;
+       boolean already_saw_mon = !occupation ? 0 : canspotmon(mtmp);
+       int rd = dochug(mtmp);
+#if 0
+       /* part of the original warning code which was replaced in 3.3.1 */
+       int dd;
+
+       if(Warning && !rd && !mtmp->mpeaceful &&
+                       (dd = distu(mtmp->mx,mtmp->my)) < distu(x,y) &&
+                       dd < 100 && !canseemon(mtmp)) {
+           /* Note: this assumes we only want to warn against the monster to
+            * which the weapon does extra damage, as there is no "monster
+            * which the weapon warns against" field.
+            */
+           if (spec_ability(uwep, SPFX_WARN) && spec_dbon(uwep, mtmp, 1))
+               warnlevel = 100;
+           else if ((int) (mtmp->m_lev / 4) > warnlevel)
+               warnlevel = (mtmp->m_lev / 4);
+       }
+#endif /* 0 */
+
+       /* a similar check is in monster_nearby() in hack.c */
+       /* check whether hero notices monster and stops current activity */
+       if (occupation && !rd && !Confusion &&
+           (!mtmp->mpeaceful || Hallucination) &&
+           /* it's close enough to be a threat */
+           distu(mtmp->mx,mtmp->my) <= (BOLT_LIM+1)*(BOLT_LIM+1) &&
+           /* and either couldn't see it before, or it was too far away */
+           (!already_saw_mon || !couldsee(x,y) ||
+               distu(x,y) > (BOLT_LIM+1)*(BOLT_LIM+1)) &&
+           /* can see it now, or sense it and would normally see it */
+           (canseemon(mtmp) ||
+               (sensemon(mtmp) && couldsee(mtmp->mx,mtmp->my))) &&
+           mtmp->mcanmove &&
+           !noattacks(mtmp->data) && !onscary(u.ux, u.uy, mtmp))
+               stop_occupation();
+
+       return(rd);
+}
+
+#endif /* OVL1 */
+#ifdef OVL2
+
+boolean
+onscary(x, y, mtmp)
+int x, y;
+struct monst *mtmp;
+{
+       if (mtmp->isshk || mtmp->isgd || mtmp->iswiz || !mtmp->mcansee ||
+           mtmp->mpeaceful || mtmp->data->mlet == S_HUMAN ||
+           is_lminion(mtmp) || mtmp->data == &mons[PM_ANGEL] ||
+           is_rider(mtmp->data) || mtmp->data == &mons[PM_MINOTAUR])
+               return(FALSE);
+
+       return (boolean)(sobj_at(SCR_SCARE_MONSTER, x, y)
+#ifdef ELBERETH
+                        || sengr_at("Elbereth", x, y)
+#endif
+                        || (mtmp->data->mlet == S_VAMPIRE
+                            && IS_ALTAR(levl[x][y].typ)));
+}
+
+#endif /* OVL2 */
+#ifdef OVL0
+
+/* regenerate lost hit points */
+void
+mon_regen(mon, digest_meal)
+struct monst *mon;
+boolean digest_meal;
+{
+       if (mon->mhp < mon->mhpmax &&
+           (moves % 20 == 0 || regenerates(mon->data))) mon->mhp++;
+       if (mon->mspec_used) mon->mspec_used--;
+       if (digest_meal) {
+           if (mon->meating) mon->meating--;
+       }
+}
+
+/*
+ * Possibly awaken the given monster.  Return a 1 if the monster has been
+ * jolted awake.
+ */
+STATIC_OVL int
+disturb(mtmp)
+       register struct monst *mtmp;
+{
+       /*
+        * + Ettins are hard to surprise.
+        * + Nymphs, jabberwocks, and leprechauns do not easily wake up.
+        *
+        * Wake up if:
+        *      in direct LOS                                           AND
+        *      within 10 squares                                       AND
+        *      not stealthy or (mon is an ettin and 9/10)              AND
+        *      (mon is not a nymph, jabberwock, or leprechaun) or 1/50 AND
+        *      Aggravate or mon is (dog or human) or
+        *          (1/7 and mon is not mimicing furniture or object)
+        */
+       if(couldsee(mtmp->mx,mtmp->my) &&
+               distu(mtmp->mx,mtmp->my) <= 100 &&
+               (!Stealth || (mtmp->data == &mons[PM_ETTIN] && rn2(10))) &&
+               (!(mtmp->data->mlet == S_NYMPH
+                       || mtmp->data == &mons[PM_JABBERWOCK]
+#if 0  /* DEFERRED */
+                       || mtmp->data == &mons[PM_VORPAL_JABBERWOCK]
+#endif
+                       || mtmp->data->mlet == S_LEPRECHAUN) || !rn2(50)) &&
+               (Aggravate_monster
+                       || (mtmp->data->mlet == S_DOG ||
+                               mtmp->data->mlet == S_HUMAN)
+                       || (!rn2(7) && mtmp->m_ap_type != M_AP_FURNITURE &&
+                               mtmp->m_ap_type != M_AP_OBJECT) )) {
+               mtmp->msleeping = 0;
+               return(1);
+       }
+       return(0);
+}
+
+/* monster begins fleeing for the specified time, 0 means untimed flee
+ * if first, only adds fleetime if monster isn't already fleeing
+ * if fleemsg, prints a message about new flight, otherwise, caller should */
+void
+monflee(mtmp, fleetime, first, fleemsg)
+struct monst *mtmp;
+int fleetime;
+boolean first;
+boolean fleemsg;
+{
+       if (u.ustuck == mtmp) {
+           if (u.uswallow)
+               expels(mtmp, mtmp->data, TRUE);
+           else if (!sticks(youmonst.data)) {
+               unstuck(mtmp);  /* monster lets go when fleeing */
+               You("get released!");
+           }
+       }
+
+       if (!first || !mtmp->mflee) {
+           /* don't lose untimed scare */
+           if (!fleetime)
+               mtmp->mfleetim = 0;
+           else if (!mtmp->mflee || mtmp->mfleetim) {
+               fleetime += mtmp->mfleetim;
+               /* ensure monster flees long enough to visibly stop fighting */
+               if (fleetime == 1) fleetime++;
+               mtmp->mfleetim = min(fleetime, 127);
+           }
+           if (!mtmp->mflee && fleemsg && canseemon(mtmp) && !mtmp->mfrozen)
+               pline("%s turns to flee!", (Monnam(mtmp)));
+           mtmp->mflee = 1;
+       }
+}
+
+STATIC_OVL void
+distfleeck(mtmp,inrange,nearby,scared)
+register struct monst *mtmp;
+int *inrange, *nearby, *scared;
+{
+       int seescaryx, seescaryy;
+
+       *inrange = (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <=
+                                                       (BOLT_LIM * BOLT_LIM));
+       *nearby = *inrange && monnear(mtmp, mtmp->mux, mtmp->muy);
+
+       /* Note: if your image is displaced, the monster sees the Elbereth
+        * at your displaced position, thus never attacking your displaced
+        * position, but possibly attacking you by accident.  If you are
+        * invisible, it sees the Elbereth at your real position, thus never
+        * running into you by accident but possibly attacking the spot
+        * where it guesses you are.
+        */
+       if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
+               seescaryx = mtmp->mux;
+               seescaryy = mtmp->muy;
+       } else {
+               seescaryx = u.ux;
+               seescaryy = u.uy;
+       }
+       *scared = (*nearby && (onscary(seescaryx, seescaryy, mtmp) ||
+                              (!mtmp->mpeaceful &&
+                                   in_your_sanctuary(mtmp, 0, 0))));
+
+       if(*scared) {
+               if (rn2(7))
+                   monflee(mtmp, rnd(10), TRUE, TRUE);
+               else
+                   monflee(mtmp, rnd(100), TRUE, TRUE);
+       }
+
+}
+
+/* perform a special one-time action for a monster; returns -1 if nothing
+   special happened, 0 if monster uses up its turn, 1 if monster is killed */
+STATIC_OVL int
+m_arrival(mon)
+struct monst *mon;
+{
+       mon->mstrategy &= ~STRAT_ARRIVE;        /* always reset */
+
+       return -1;
+}
+
+/* returns 1 if monster died moving, 0 otherwise */
+/* The whole dochugw/m_move/distfleeck/mfndpos section is serious spaghetti
+ * code. --KAA
+ */
+int
+dochug(mtmp)
+register struct monst *mtmp;
+{
+       register struct permonst *mdat;
+       register int tmp=0;
+       int inrange, nearby, scared;
+#ifdef GOLDOBJ
+        struct obj *ygold = 0, *lepgold = 0;
+#endif
+
+/*     Pre-movement adjustments        */
+
+       mdat = mtmp->data;
+
+       if (mtmp->mstrategy & STRAT_ARRIVE) {
+           int res = m_arrival(mtmp);
+           if (res >= 0) return res;
+       }
+
+       /* check for waitmask status change */
+       if ((mtmp->mstrategy & STRAT_WAITFORU) &&
+               (m_canseeu(mtmp) || mtmp->mhp < mtmp->mhpmax))
+           mtmp->mstrategy &= ~STRAT_WAITFORU;
+
+       /* update quest status flags */
+       quest_stat_check(mtmp);
+
+       if (!mtmp->mcanmove || (mtmp->mstrategy & STRAT_WAITMASK)) {
+           if (Hallucination) newsym(mtmp->mx,mtmp->my);
+           if (mtmp->mcanmove && (mtmp->mstrategy & STRAT_CLOSE) &&
+              !mtmp->msleeping && monnear(mtmp, u.ux, u.uy))
+               quest_talk(mtmp);       /* give the leaders a chance to speak */
+           return(0);  /* other frozen monsters can't do anything */
+       }
+
+       /* there is a chance we will wake it */
+       if (mtmp->msleeping && !disturb(mtmp)) {
+               if (Hallucination) newsym(mtmp->mx,mtmp->my);
+               return(0);
+       }
+
+       /* not frozen or sleeping: wipe out texts written in the dust */
+       wipe_engr_at(mtmp->mx, mtmp->my, 1);
+
+       /* confused monsters get unconfused with small probability */
+       if (mtmp->mconf && !rn2(50)) mtmp->mconf = 0;
+
+       /* stunned monsters get un-stunned with larger probability */
+       if (mtmp->mstun && !rn2(10)) mtmp->mstun = 0;
+
+       /* some monsters teleport */
+       if (mtmp->mflee && !rn2(40) && can_teleport(mdat) && !mtmp->iswiz &&
+           !level.flags.noteleport) {
+               (void) rloc(mtmp, FALSE);
+               return(0);
+       }
+       if (mdat->msound == MS_SHRIEK && !um_dist(mtmp->mx, mtmp->my, 1))
+           m_respond(mtmp);
+       if (mdat == &mons[PM_MEDUSA] && couldsee(mtmp->mx, mtmp->my))
+           m_respond(mtmp);
+       if (mtmp->mhp <= 0) return(1); /* m_respond gaze can kill medusa */
+
+       /* fleeing monsters might regain courage */
+       if (mtmp->mflee && !mtmp->mfleetim
+          && mtmp->mhp == mtmp->mhpmax && !rn2(25)) mtmp->mflee = 0;
+
+       set_apparxy(mtmp);
+       /* Must be done after you move and before the monster does.  The
+        * set_apparxy() call in m_move() doesn't suffice since the variables
+        * inrange, etc. all depend on stuff set by set_apparxy().
+        */
+
+       /* Monsters that want to acquire things */
+       /* may teleport, so do it before inrange is set */
+       if(is_covetous(mdat)) (void) tactics(mtmp);
+
+       /* check distance and scariness of attacks */
+       distfleeck(mtmp,&inrange,&nearby,&scared);
+
+       if(find_defensive(mtmp)) {
+               if (use_defensive(mtmp) != 0)
+                       return 1;
+       } else if(find_misc(mtmp)) {
+               if (use_misc(mtmp) != 0)
+                       return 1;
+       }
+
+       /* Demonic Blackmail! */
+       if(nearby && mdat->msound == MS_BRIBE &&
+          mtmp->mpeaceful && !mtmp->mtame && !u.uswallow) {
+               if (mtmp->mux != u.ux || mtmp->muy != u.uy) {
+                       pline("%s whispers at thin air.",
+                           cansee(mtmp->mux, mtmp->muy) ? Monnam(mtmp) : "It");
+
+                       if (is_demon(youmonst.data)) {
+                         /* "Good hunting, brother" */
+                           if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
+                       } else {
+                           mtmp->minvis = mtmp->perminvis = 0;
+                           /* Why?  For the same reason in real demon talk */
+                           pline("%s gets angry!", Amonnam(mtmp));
+                           mtmp->mpeaceful = 0;
+                           /* since no way is an image going to pay it off */
+                       }
+               } else if(demon_talk(mtmp)) return(1);  /* you paid it off */
+       }
+
+       /* the watch will look around and see if you are up to no good :-) */
+       if (mdat == &mons[PM_WATCHMAN] || mdat == &mons[PM_WATCH_CAPTAIN])
+               watch_on_duty(mtmp);
+
+       else if (is_mind_flayer(mdat) && !rn2(20)) {
+               struct monst *m2, *nmon = (struct monst *)0;
+
+               if (canseemon(mtmp))
+                       pline("%s concentrates.", Monnam(mtmp));
+               if (distu(mtmp->mx, mtmp->my) > BOLT_LIM * BOLT_LIM) {
+                       You("sense a faint wave of psychic energy.");
+                       goto toofar;
+               }
+               pline("A wave of psychic energy pours over you!");
+               if (mtmp->mpeaceful &&
+                   (!Conflict || resist(mtmp, RING_CLASS, 0, 0)))
+                       pline("It feels quite soothing.");
+               else {
+                       register boolean m_sen = sensemon(mtmp);
+
+                       if (m_sen || (Blind_telepat && rn2(2)) || !rn2(10)) {
+                               int dmg;
+                               pline("It locks on to your %s!",
+                                       m_sen ? "telepathy" :
+                                       Blind_telepat ? "latent telepathy" : "mind");
+                               dmg = rnd(15);
+                               if (Half_spell_damage) dmg = (dmg+1) / 2;
+                               losehp(dmg, "psychic blast", KILLED_BY_AN);
+                       }
+               }
+               for(m2=fmon; m2; m2 = nmon) {
+                       nmon = m2->nmon;
+                       if (DEADMONSTER(m2)) continue;
+                       if (m2->mpeaceful == mtmp->mpeaceful) continue;
+                       if (mindless(m2->data)) continue;
+                       if (m2 == mtmp) continue;
+                       if ((telepathic(m2->data) &&
+                           (rn2(2) || m2->mblinded)) || !rn2(10)) {
+                               if (cansee(m2->mx, m2->my))
+                                   pline("It locks on to %s.", mon_nam(m2));
+                               m2->mhp -= rnd(15);
+                               if (m2->mhp <= 0)
+                                   monkilled(m2, "", AD_DRIN);
+                               else
+                                   m2->msleeping = 0;
+                       }
+               }
+       }
+toofar:
+
+       /* If monster is nearby you, and has to wield a weapon, do so.   This
+        * costs the monster a move, of course.
+        */
+       if((!mtmp->mpeaceful || Conflict) && inrange &&
+          dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8
+          && attacktype(mdat, AT_WEAP)) {
+           struct obj *mw_tmp;
+
+           /* The scared check is necessary.  Otherwise a monster that is
+            * one square near the player but fleeing into a wall would keep    
+            * switching between pick-axe and weapon.  If monster is stuck
+            * in a trap, prefer ranged weapon (wielding is done in thrwmu).
+            * This may cost the monster an attack, but keeps the monster
+            * from switching back and forth if carrying both.
+            */
+           mw_tmp = MON_WEP(mtmp);
+           if (!(scared && mw_tmp && is_pick(mw_tmp)) &&
+               mtmp->weapon_check == NEED_WEAPON &&
+               !(mtmp->mtrapped && !nearby && select_rwep(mtmp))) {
+               mtmp->weapon_check = NEED_HTH_WEAPON;
+               if (mon_wield_item(mtmp) != 0) return(0);
+           }
+       }
+
+/*     Now the actual movement phase   */
+
+#ifndef GOLDOBJ
+       if(!nearby || mtmp->mflee || scared ||
+          mtmp->mconf || mtmp->mstun || (mtmp->minvis && !rn2(3)) ||
+          (mdat->mlet == S_LEPRECHAUN && !u.ugold && (mtmp->mgold || rn2(2))) ||
+#else
+        if (mdat->mlet == S_LEPRECHAUN) {
+           ygold = findgold(invent);
+           lepgold = findgold(mtmp->minvent);
+       }
+
+       if(!nearby || mtmp->mflee || scared ||
+          mtmp->mconf || mtmp->mstun || (mtmp->minvis && !rn2(3)) ||
+          (mdat->mlet == S_LEPRECHAUN && !ygold && (lepgold || rn2(2))) ||
+#endif
+          (is_wanderer(mdat) && !rn2(4)) || (Conflict && !mtmp->iswiz) ||
+          (!mtmp->mcansee && !rn2(4)) || mtmp->mpeaceful) {
+               /* Possibly cast an undirected spell if not attacking you */
+               /* note that most of the time castmu() will pick a directed
+                  spell and do nothing, so the monster moves normally */
+               /* arbitrary distance restriction to keep monster far away
+                  from you from having cast dozens of sticks-to-snakes
+                  or similar spells by the time you reach it */
+               if (dist2(mtmp->mx, mtmp->my, u.ux, u.uy) <= 49 && !mtmp->mspec_used) {
+                   struct attack *a;
+
+                   for (a = &mdat->mattk[0]; a < &mdat->mattk[NATTK]; a++) {
+                       if (a->aatyp == AT_MAGC && (a->adtyp == AD_SPEL || a->adtyp == AD_CLRC)) {
+                           if (castmu(mtmp, a, FALSE, FALSE)) {
+                               tmp = 3;
+                               break;
+                           }
+                       }
+                   }
+               }
+
+               tmp = m_move(mtmp, 0);
+               distfleeck(mtmp,&inrange,&nearby,&scared);      /* recalc */
+
+               switch (tmp) {
+                   case 0:     /* no movement, but it can still attack you */
+                   case 3:     /* absolutely no movement */
+                               /* for pets, case 0 and 3 are equivalent */
+                       /* vault guard might have vanished */
+                       if (mtmp->isgd && (mtmp->mhp < 1 ||
+                                           (mtmp->mx == 0 && mtmp->my == 0)))
+                           return 1;   /* behave as if it died */
+                       /* During hallucination, monster appearance should
+                        * still change - even if it doesn't move.
+                        */
+                       if(Hallucination) newsym(mtmp->mx,mtmp->my);
+                       break;
+                   case 1:     /* monster moved */
+                       /* Maybe it stepped on a trap and fell asleep... */
+                       if (mtmp->msleeping || !mtmp->mcanmove) return(0);
+                       if(!nearby &&
+                         (ranged_attk(mdat) || find_offensive(mtmp)))
+                           break;
+                       else if(u.uswallow && mtmp == u.ustuck) {
+                           /* a monster that's digesting you can move at the
+                            * same time -dlc
+                            */
+                           return(mattacku(mtmp));
+                       } else
+                               return(0);
+                       /*NOTREACHED*/
+                       break;
+                   case 2:     /* monster died */
+                       return(1);
+               }
+       }
+
+/*     Now, attack the player if possible - one attack set per monst   */
+
+       if (!mtmp->mpeaceful ||
+           (Conflict && !resist(mtmp, RING_CLASS, 0, 0))) {
+           if(inrange && !noattacks(mdat) && u.uhp > 0 && !scared && tmp != 3)
+               if(mattacku(mtmp)) return(1); /* monster died (e.g. exploded) */
+
+           if(mtmp->wormno) wormhitu(mtmp);
+       }
+       /* special speeches for quest monsters */
+       if (!mtmp->msleeping && mtmp->mcanmove && nearby)
+           quest_talk(mtmp);
+       /* extra emotional attack for vile monsters */
+       if (inrange && mtmp->data->msound == MS_CUSS && !mtmp->mpeaceful &&
+               couldsee(mtmp->mx, mtmp->my) && !mtmp->minvis && !rn2(5))
+           cuss(mtmp);
+
+       return(tmp == 2);
+}
+
+static NEARDATA const char practical[] = { WEAPON_CLASS, ARMOR_CLASS, GEM_CLASS, FOOD_CLASS, 0 };
+static NEARDATA const char magical[] = {
+       AMULET_CLASS, POTION_CLASS, SCROLL_CLASS, WAND_CLASS, RING_CLASS,
+       SPBOOK_CLASS, 0 };
+static NEARDATA const char indigestion[] = { BALL_CLASS, ROCK_CLASS, 0 };
+static NEARDATA const char boulder_class[] = { ROCK_CLASS, 0 };
+static NEARDATA const char gem_class[] = { GEM_CLASS, 0 };
+
+boolean
+itsstuck(mtmp)
+register struct monst *mtmp;
+{
+       if (sticks(youmonst.data) && mtmp==u.ustuck && !u.uswallow) {
+               pline("%s cannot escape from you!", Monnam(mtmp));
+               return(TRUE);
+       }
+       return(FALSE);
+}
+
+/* Return values:
+ * 0: did not move, but can still attack and do other stuff.
+ * 1: moved, possibly can attack.
+ * 2: monster died.
+ * 3: did not move, and can't do anything else either.
+ */
+int
+m_move(mtmp, after)
+register struct monst *mtmp;
+register int after;
+{
+       register int appr;
+       xchar gx,gy,nix,niy,chcnt;
+       int chi;        /* could be schar except for stupid Sun-2 compiler */
+       boolean likegold=0, likegems=0, likeobjs=0, likemagic=0, conceals=0;
+       boolean likerock=0, can_tunnel=0;
+       boolean can_open=0, can_unlock=0, doorbuster=0;
+       boolean uses_items=0, setlikes=0;
+       boolean avoid=FALSE;
+       struct permonst *ptr;
+       struct monst *mtoo;
+       schar mmoved = 0;       /* not strictly nec.: chi >= 0 will do */
+       long info[9];
+       long flag;
+       int  omx = mtmp->mx, omy = mtmp->my;
+       struct obj *mw_tmp;
+
+       if(mtmp->mtrapped) {
+           int i = mintrap(mtmp);
+           if(i >= 2) { newsym(mtmp->mx,mtmp->my); return(2); }/* it died */
+           if(i == 1) return(0);       /* still in trap, so didn't move */
+       }
+       ptr = mtmp->data; /* mintrap() can change mtmp->data -dlc */
+
+       if (mtmp->meating) {
+           mtmp->meating--;
+           return 3;                   /* still eating */
+       }
+       if (hides_under(ptr) && OBJ_AT(mtmp->mx, mtmp->my) && rn2(10))
+           return 0;           /* do not leave hiding place */
+
+       set_apparxy(mtmp);
+       /* where does mtmp think you are? */
+       /* Not necessary if m_move called from this file, but necessary in
+        * other calls of m_move (ex. leprechauns dodging)
+        */
+#ifdef REINCARNATION
+       if (!Is_rogue_level(&u.uz))
+#endif
+           can_tunnel = tunnels(ptr);
+       can_open = !(nohands(ptr) || verysmall(ptr));
+       can_unlock = ((can_open && m_carrying(mtmp, SKELETON_KEY)) ||
+                     mtmp->iswiz || is_rider(ptr));
+       doorbuster = is_giant(ptr);
+       if(mtmp->wormno) goto not_special;
+       /* my dog gets special treatment */
+       if(mtmp->mtame) {
+           mmoved = dog_move(mtmp, after);
+           goto postmov;
+       }
+
+       /* likewise for shopkeeper */
+       if(mtmp->isshk) {
+           mmoved = shk_move(mtmp);
+           if(mmoved == -2) return(2);
+           if(mmoved >= 0) goto postmov;
+           mmoved = 0;         /* follow player outside shop */
+       }
+
+       /* and for the guard */
+       if(mtmp->isgd) {
+           mmoved = gd_move(mtmp);
+           if(mmoved == -2) return(2);
+           if(mmoved >= 0) goto postmov;
+           mmoved = 0;
+       }
+
+       /* and the acquisitive monsters get special treatment */
+       if(is_covetous(ptr)) {
+           xchar tx = STRAT_GOALX(mtmp->mstrategy),
+                 ty = STRAT_GOALY(mtmp->mstrategy);
+           struct monst *intruder = m_at(tx, ty);
+           /*
+            * if there's a monster on the object or in possesion of it,
+            * attack it.
+            */
+           if((dist2(mtmp->mx, mtmp->my, tx, ty) < 2) &&
+              intruder && (intruder != mtmp)) {
+
+               notonhead = (intruder->mx != tx || intruder->my != ty);
+               if(mattackm(mtmp, intruder) == 2) return(2);
+               mmoved = 1;
+           } else mmoved = 0;
+           goto postmov;
+       }
+
+       /* and for the priest */
+       if(mtmp->ispriest) {
+           mmoved = pri_move(mtmp);
+           if(mmoved == -2) return(2);
+           if(mmoved >= 0) goto postmov;
+           mmoved = 0;
+       }
+
+#ifdef MAIL
+       if(ptr == &mons[PM_MAIL_DAEMON]) {
+           if(flags.soundok && canseemon(mtmp))
+               verbalize("I'm late!");
+           mongone(mtmp);
+           return(2);
+       }
+#endif
+
+       /* teleport if that lies in our nature */
+       if(ptr == &mons[PM_TENGU] && !rn2(5) && !mtmp->mcan &&
+          !tele_restrict(mtmp)) {
+           if(mtmp->mhp < 7 || mtmp->mpeaceful || rn2(2))
+               (void) rloc(mtmp, FALSE);
+           else
+               mnexto(mtmp);
+           mmoved = 1;
+           goto postmov;
+       }
+not_special:
+       if(u.uswallow && !mtmp->mflee && u.ustuck != mtmp) return(1);
+       omx = mtmp->mx;
+       omy = mtmp->my;
+       gx = mtmp->mux;
+       gy = mtmp->muy;
+       appr = mtmp->mflee ? -1 : 1;
+       if (mtmp->mconf || (u.uswallow && mtmp == u.ustuck))
+               appr = 0;
+       else {
+#ifdef GOLDOBJ
+               struct obj *lepgold, *ygold;
+#endif
+               boolean should_see = (couldsee(omx, omy) &&
+                                     (levl[gx][gy].lit ||
+                                      !levl[omx][omy].lit) &&
+                                     (dist2(omx, omy, gx, gy) <= 36));
+
+               if (!mtmp->mcansee ||
+                   (should_see && Invis && !perceives(ptr) && rn2(11)) ||
+                   (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance == STRANGE_OBJECT) || u.uundetected ||
+                   (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance == GOLD_PIECE && !likes_gold(ptr)) ||
+                   (mtmp->mpeaceful && !mtmp->isshk) ||  /* allow shks to follow */
+                   ((monsndx(ptr) == PM_STALKER || ptr->mlet == S_BAT ||
+                     ptr->mlet == S_LIGHT) && !rn2(3)))
+                       appr = 0;
+
+               if(monsndx(ptr) == PM_LEPRECHAUN && (appr == 1) &&
+#ifndef GOLDOBJ
+                  (mtmp->mgold > u.ugold))
+#else
+                  ( (lepgold = findgold(mtmp->minvent)) && 
+                   (lepgold->quan > ((ygold = findgold(invent)) ? ygold->quan : 0L)) ))
+#endif
+                       appr = -1;
+
+               if (!should_see && can_track(ptr)) {
+                       register coord *cp;
+
+                       cp = gettrack(omx,omy);
+                       if (cp) {
+                               gx = cp->x;
+                               gy = cp->y;
+                       }
+               }
+       }
+
+       if ((!mtmp->mpeaceful || !rn2(10))
+#ifdef REINCARNATION
+                                   && (!Is_rogue_level(&u.uz))
+#endif
+                                                           ) {
+           boolean in_line = lined_up(mtmp) &&
+               (distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <=
+                   (throws_rocks(youmonst.data) ? 20 : ACURRSTR/2+1)
+               );
+
+           if (appr != 1 || !in_line) {
+               /* Monsters in combat won't pick stuff up, avoiding the
+                * situation where you toss arrows at it and it has nothing
+                * better to do than pick the arrows up.
+                */
+               register int pctload = (curr_mon_load(mtmp) * 100) /
+                       max_mon_load(mtmp);
+
+               /* look for gold or jewels nearby */
+               likegold = (likes_gold(ptr) && pctload < 95);
+               likegems = (likes_gems(ptr) && pctload < 85);
+               uses_items = (!mindless(ptr) && !is_animal(ptr)
+                       && pctload < 75);
+               likeobjs = (likes_objs(ptr) && pctload < 75);
+               likemagic = (likes_magic(ptr) && pctload < 85);
+               likerock = (throws_rocks(ptr) && pctload < 50 && !In_sokoban(&u.uz));
+               conceals = hides_under(ptr);
+               setlikes = TRUE;
+           }
+       }
+
+#define SQSRCHRADIUS   5
+
+      { register int minr = SQSRCHRADIUS;      /* not too far away */
+       register struct obj *otmp;
+       register int xx, yy;
+       int oomx, oomy, lmx, lmy;
+
+       /* cut down the search radius if it thinks character is closer. */
+       if(distmin(mtmp->mux, mtmp->muy, omx, omy) < SQSRCHRADIUS &&
+           !mtmp->mpeaceful) minr--;
+       /* guards shouldn't get too distracted */
+       if(!mtmp->mpeaceful && is_mercenary(ptr)) minr = 1;
+
+       if((likegold || likegems || likeobjs || likemagic || likerock || conceals)
+             && (!*in_rooms(omx, omy, SHOPBASE) || (!rn2(25) && !mtmp->isshk))) {
+       look_for_obj:
+           oomx = min(COLNO-1, omx+minr);
+           oomy = min(ROWNO-1, omy+minr);
+           lmx = max(1, omx-minr);
+           lmy = max(0, omy-minr);
+           for(otmp = fobj; otmp; otmp = otmp->nobj) {
+               /* monsters may pick rocks up, but won't go out of their way
+                  to grab them; this might hamper sling wielders, but it cuts
+                  down on move overhead by filtering out most common item */
+               if (otmp->otyp == ROCK) continue;
+               xx = otmp->ox;
+               yy = otmp->oy;
+               /* Nymphs take everything.  Most other creatures should not
+                * pick up corpses except as a special case like in
+                * searches_for_item().  We need to do this check in
+                * mpickstuff() as well.
+                */
+               if(xx >= lmx && xx <= oomx && yy >= lmy && yy <= oomy) {
+                   /* don't get stuck circling around an object that's underneath
+                      an immobile or hidden monster; paralysis victims excluded */
+                   if ((mtoo = m_at(xx,yy)) != 0 &&
+                       (mtoo->msleeping || mtoo->mundetected ||
+                        (mtoo->mappearance && !mtoo->iswiz) ||
+                        !mtoo->data->mmove)) continue;
+
+                   if(((likegold && otmp->oclass == COIN_CLASS) ||
+                      (likeobjs && index(practical, otmp->oclass) &&
+                       (otmp->otyp != CORPSE || (ptr->mlet == S_NYMPH
+                          && !is_rider(&mons[otmp->corpsenm])))) ||
+                      (likemagic && index(magical, otmp->oclass)) ||
+                      (uses_items && searches_for_item(mtmp, otmp)) ||
+                      (likerock && otmp->otyp == BOULDER) ||
+                      (likegems && otmp->oclass == GEM_CLASS &&
+                       objects[otmp->otyp].oc_material != MINERAL) ||
+                      (conceals && !cansee(otmp->ox,otmp->oy)) ||
+                      (ptr == &mons[PM_GELATINOUS_CUBE] &&
+                       !index(indigestion, otmp->oclass) &&
+                       !(otmp->otyp == CORPSE &&
+                         touch_petrifies(&mons[otmp->corpsenm])))
+                     ) && touch_artifact(otmp,mtmp)) {
+                       if(can_carry(mtmp,otmp) &&
+                          (throws_rocks(ptr) ||
+                               !sobj_at(BOULDER,xx,yy)) &&
+                          (!is_unicorn(ptr) ||
+                           objects[otmp->otyp].oc_material == GEMSTONE) &&
+                          /* Don't get stuck circling an Elbereth */
+                          !(onscary(xx, yy, mtmp))) {
+                           minr = distmin(omx,omy,xx,yy);
+                           oomx = min(COLNO-1, omx+minr);
+                           oomy = min(ROWNO-1, omy+minr);
+                           lmx = max(1, omx-minr);
+                           lmy = max(0, omy-minr);
+                           gx = otmp->ox;
+                           gy = otmp->oy;
+                           if (gx == omx && gy == omy) {
+                               mmoved = 3; /* actually unnecessary */
+                               goto postmov;
+                           }
+                       }
+                   }
+               }
+           }
+       } else if(likegold) {
+           /* don't try to pick up anything else, but use the same loop */
+           uses_items = 0;
+           likegems = likeobjs = likemagic = likerock = conceals = 0;
+           goto look_for_obj;
+       }
+
+       if(minr < SQSRCHRADIUS && appr == -1) {
+           if(distmin(omx,omy,mtmp->mux,mtmp->muy) <= 3) {
+               gx = mtmp->mux;
+               gy = mtmp->muy;
+           } else
+               appr = 1;
+       }
+      }
+
+       /* don't tunnel if hostile and close enough to prefer a weapon */
+       if (can_tunnel && needspick(ptr) &&
+           ((!mtmp->mpeaceful || Conflict) &&
+            dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8))
+           can_tunnel = FALSE;
+
+       nix = omx;
+       niy = omy;
+       flag = 0L;
+       if (mtmp->mpeaceful && (!Conflict || resist(mtmp, RING_CLASS, 0, 0)))
+           flag |= (ALLOW_SANCT | ALLOW_SSM);
+       else flag |= ALLOW_U;
+       if (is_minion(ptr) || is_rider(ptr)) flag |= ALLOW_SANCT;
+       /* unicorn may not be able to avoid hero on a noteleport level */
+       if (is_unicorn(ptr) && !level.flags.noteleport) flag |= NOTONL;
+       if (passes_walls(ptr)) flag |= (ALLOW_WALL | ALLOW_ROCK);
+       if (passes_bars(ptr)) flag |= ALLOW_BARS;
+       if (can_tunnel) flag |= ALLOW_DIG;
+       if (is_human(ptr) || ptr == &mons[PM_MINOTAUR]) flag |= ALLOW_SSM;
+       if (is_undead(ptr) && ptr->mlet != S_GHOST) flag |= NOGARLIC;
+       if (throws_rocks(ptr)) flag |= ALLOW_ROCK;
+       if (can_open) flag |= OPENDOOR;
+       if (can_unlock) flag |= UNLOCKDOOR;
+       if (doorbuster) flag |= BUSTDOOR;
+       {
+           register int i, j, nx, ny, nearer;
+           int jcnt, cnt;
+           int ndist, nidist;
+           register coord *mtrk;
+           coord poss[9];
+
+           cnt = mfndpos(mtmp, poss, info, flag);
+           chcnt = 0;
+           jcnt = min(MTSZ, cnt-1);
+           chi = -1;
+           nidist = dist2(nix,niy,gx,gy);
+           /* allow monsters be shortsighted on some levels for balance */
+           if(!mtmp->mpeaceful && level.flags.shortsighted &&
+              nidist > (couldsee(nix,niy) ? 144 : 36) && appr == 1) appr = 0;
+           if (is_unicorn(ptr) && level.flags.noteleport) {
+               /* on noteleport levels, perhaps we cannot avoid hero */
+               for(i = 0; i < cnt; i++)
+                   if(!(info[i] & NOTONL)) avoid=TRUE;
+           }
+
+           for(i=0; i < cnt; i++) {
+               if (avoid && (info[i] & NOTONL)) continue;
+               nx = poss[i].x;
+               ny = poss[i].y;
+
+               if (appr != 0) {
+                   mtrk = &mtmp->mtrack[0];
+                   for(j=0; j < jcnt; mtrk++, j++)
+                       if(nx == mtrk->x && ny == mtrk->y)
+                           if(rn2(4*(cnt-j)))
+                               goto nxti;
+               }
+
+               nearer = ((ndist = dist2(nx,ny,gx,gy)) < nidist);
+
+               if((appr == 1 && nearer) || (appr == -1 && !nearer) ||
+                  (!appr && !rn2(++chcnt)) || !mmoved) {
+                   nix = nx;
+                   niy = ny;
+                   nidist = ndist;
+                   chi = i;
+                   mmoved = 1;
+               }
+           nxti:       ;
+           }
+       }
+
+       if(mmoved) {
+           register int j;
+
+           if (mmoved==1 && (u.ux != nix || u.uy != niy) && itsstuck(mtmp))
+               return(3);
+
+           if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) ||
+                closed_door(nix, niy)) &&
+               mmoved==1 && can_tunnel && needspick(ptr)) {
+               if (closed_door(nix, niy)) {
+                   if (!(mw_tmp = MON_WEP(mtmp)) ||
+                       !is_pick(mw_tmp) || !is_axe(mw_tmp))
+                       mtmp->weapon_check = NEED_PICK_OR_AXE;
+               } else if (IS_TREE(levl[nix][niy].typ)) {
+                   if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp))
+                       mtmp->weapon_check = NEED_AXE;
+               } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) {
+                   mtmp->weapon_check = NEED_PICK_AXE;
+               }
+               if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp))
+                   return(3);
+           }
+           /* If ALLOW_U is set, either it's trying to attack you, or it
+            * thinks it is.  In either case, attack this spot in preference to
+            * all others.
+            */
+       /* Actually, this whole section of code doesn't work as you'd expect.
+        * Most attacks are handled in dochug().  It calls distfleeck(), which
+        * among other things sets nearby if the monster is near you--and if
+        * nearby is set, we never call m_move unless it is a special case
+        * (confused, stun, etc.)  The effect is that this ALLOW_U (and
+        * mfndpos) has no effect for normal attacks, though it lets a confused
+        * monster attack you by accident.
+        */
+           if(info[chi] & ALLOW_U) {
+               nix = mtmp->mux;
+               niy = mtmp->muy;
+           }
+           if (nix == u.ux && niy == u.uy) {
+               mtmp->mux = u.ux;
+               mtmp->muy = u.uy;
+               return(0);
+           }
+           /* The monster may attack another based on 1 of 2 conditions:
+            * 1 - It may be confused.
+            * 2 - It may mistake the monster for your (displaced) image.
+            * Pets get taken care of above and shouldn't reach this code.
+            * Conflict gets handled even farther away (movemon()).
+            */
+           if((info[chi] & ALLOW_M) ||
+                  (nix == mtmp->mux && niy == mtmp->muy)) {
+               struct monst *mtmp2;
+               int mstatus;
+               mtmp2 = m_at(nix,niy);
+
+               notonhead = mtmp2 && (nix != mtmp2->mx || niy != mtmp2->my);
+               /* note: mstatus returns 0 if mtmp2 is nonexistent */
+               mstatus = mattackm(mtmp, mtmp2);
+
+               if (mstatus & MM_AGR_DIED)              /* aggressor died */
+                   return 2;
+
+               if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED)  &&
+                   rn2(4) && mtmp2->movement >= NORMAL_SPEED) {
+                   mtmp2->movement -= NORMAL_SPEED;
+                   notonhead = 0;
+                   mstatus = mattackm(mtmp2, mtmp);    /* return attack */
+                   if (mstatus & MM_DEF_DIED)
+                       return 2;
+               }
+               return 3;
+           }
+
+           if (!m_in_out_region(mtmp,nix,niy))
+               return 3;
+           remove_monster(omx, omy);
+           place_monster(mtmp, nix, niy);
+           for(j = MTSZ-1; j > 0; j--)
+               mtmp->mtrack[j] = mtmp->mtrack[j-1];
+           mtmp->mtrack[0].x = omx;
+           mtmp->mtrack[0].y = omy;
+           /* Place a segment at the old position. */
+           if (mtmp->wormno) worm_move(mtmp);
+       } else {
+           if(is_unicorn(ptr) && rn2(2) && !tele_restrict(mtmp)) {
+               (void) rloc(mtmp, FALSE);
+               return(1);
+           }
+           if(mtmp->wormno) worm_nomove(mtmp);
+       }
+postmov:
+       if(mmoved == 1 || mmoved == 3) {
+           boolean canseeit = cansee(mtmp->mx, mtmp->my);
+
+           if(mmoved == 1) {
+               newsym(omx,omy);                /* update the old position */
+               if (mintrap(mtmp) >= 2) {
+                   if(mtmp->mx) newsym(mtmp->mx,mtmp->my);
+                   return(2);  /* it died */
+               }
+               ptr = mtmp->data;
+
+               /* open a door, or crash through it, if you can */
+               if(IS_DOOR(levl[mtmp->mx][mtmp->my].typ)
+                       && !passes_walls(ptr) /* doesn't need to open doors */
+                       && !can_tunnel /* taken care of below */
+                     ) {
+                   struct rm *here = &levl[mtmp->mx][mtmp->my];
+                   boolean btrapped = (here->doormask & D_TRAPPED);
+
+                   if(here->doormask & (D_LOCKED|D_CLOSED) && amorphous(ptr)) {
+                       if (flags.verbose && canseemon(mtmp))
+                           pline("%s %s under the door.", Monnam(mtmp),
+                                 (ptr == &mons[PM_FOG_CLOUD] ||
+                                  ptr == &mons[PM_YELLOW_LIGHT])
+                                 ? "flows" : "oozes");
+                   } else if(here->doormask & D_LOCKED && can_unlock) {
+                       if(btrapped) {
+                           here->doormask = D_NODOOR;
+                           newsym(mtmp->mx, mtmp->my);
+                           unblock_point(mtmp->mx,mtmp->my); /* vision */
+                           if(mb_trapped(mtmp)) return(2);
+                       } else {
+                           if (flags.verbose) {
+                               if (canseeit)
+                                  You("see a door unlock and open.");
+                               else if (flags.soundok)
+                                  You_hear("a door unlock and open.");
+                           }
+                           here->doormask = D_ISOPEN;
+                           /* newsym(mtmp->mx, mtmp->my); */
+                           unblock_point(mtmp->mx,mtmp->my); /* vision */
+                       }
+                   } else if (here->doormask == D_CLOSED && can_open) {
+                       if(btrapped) {
+                           here->doormask = D_NODOOR;
+                           newsym(mtmp->mx, mtmp->my);
+                           unblock_point(mtmp->mx,mtmp->my); /* vision */
+                           if(mb_trapped(mtmp)) return(2);
+                       } else {
+                           if (flags.verbose) {
+                               if (canseeit)
+                                    You("see a door open.");
+                               else if (flags.soundok)
+                                    You_hear("a door open.");
+                           }
+                           here->doormask = D_ISOPEN;
+                           /* newsym(mtmp->mx, mtmp->my); */  /* done below */
+                           unblock_point(mtmp->mx,mtmp->my); /* vision */
+                       }
+                   } else if (here->doormask & (D_LOCKED|D_CLOSED)) {
+                       /* mfndpos guarantees this must be a doorbuster */
+                       if(btrapped) {
+                           here->doormask = D_NODOOR;
+                           newsym(mtmp->mx, mtmp->my);
+                           unblock_point(mtmp->mx,mtmp->my); /* vision */
+                           if(mb_trapped(mtmp)) return(2);
+                       } else {
+                           if (flags.verbose) {
+                               if (canseeit)
+                                   You("see a door crash open.");
+                               else if (flags.soundok)
+                                   You_hear("a door crash open.");
+                           }
+                           if (here->doormask & D_LOCKED && !rn2(2))
+                                   here->doormask = D_NODOOR;
+                           else here->doormask = D_BROKEN;
+                           /* newsym(mtmp->mx, mtmp->my); */ /* done below */
+                           unblock_point(mtmp->mx,mtmp->my); /* vision */
+                       }
+                       /* if it's a shop door, schedule repair */
+                       if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE))
+                           add_damage(mtmp->mx, mtmp->my, 0L);
+                   }
+               } else if (levl[mtmp->mx][mtmp->my].typ == IRONBARS) {
+                       if (flags.verbose && canseemon(mtmp))
+                           Norep("%s %s %s the iron bars.", Monnam(mtmp),
+                                 /* pluralization fakes verb conjugation */
+                                 makeplural(locomotion(ptr, "pass")),
+                                 passes_walls(ptr) ? "through" : "between");
+               }
+
+               /* possibly dig */
+               if (can_tunnel && mdig_tunnel(mtmp))
+                       return(2);  /* mon died (position already updated) */
+
+               /* set also in domove(), hack.c */
+               if (u.uswallow && mtmp == u.ustuck &&
+                                       (mtmp->mx != omx || mtmp->my != omy)) {
+                   /* If the monster moved, then update */
+                   u.ux0 = u.ux;
+                   u.uy0 = u.uy;
+                   u.ux = mtmp->mx;
+                   u.uy = mtmp->my;
+                   swallowed(0);
+               } else
+               newsym(mtmp->mx,mtmp->my);
+           }
+           if(OBJ_AT(mtmp->mx, mtmp->my) && mtmp->mcanmove) {
+               /* recompute the likes tests, in case we polymorphed
+                * or if the "likegold" case got taken above */
+               if (setlikes) {
+                   register int pctload = (curr_mon_load(mtmp) * 100) /
+                       max_mon_load(mtmp);
+
+                   /* look for gold or jewels nearby */
+                   likegold = (likes_gold(ptr) && pctload < 95);
+                   likegems = (likes_gems(ptr) && pctload < 85);
+                   uses_items = (!mindless(ptr) && !is_animal(ptr)
+                                 && pctload < 75);
+                   likeobjs = (likes_objs(ptr) && pctload < 75);
+                   likemagic = (likes_magic(ptr) && pctload < 85);
+                   likerock = (throws_rocks(ptr) && pctload < 50 &&
+                               !In_sokoban(&u.uz));
+                   conceals = hides_under(ptr);
+               }
+
+               /* Maybe a rock mole just ate some metal object */
+               if (metallivorous(ptr)) {
+                   if (meatmetal(mtmp) == 2) return 2; /* it died */
+               }
+
+               if(g_at(mtmp->mx,mtmp->my) && likegold) mpickgold(mtmp);
+
+               /* Maybe a cube ate just about anything */
+               if (ptr == &mons[PM_GELATINOUS_CUBE]) {
+                   if (meatobj(mtmp) == 2) return 2;   /* it died */
+               }
+
+               if(!*in_rooms(mtmp->mx, mtmp->my, SHOPBASE) || !rn2(25)) {
+                   boolean picked = FALSE;
+
+                   if(likeobjs) picked |= mpickstuff(mtmp, practical);
+                   if(likemagic) picked |= mpickstuff(mtmp, magical);
+                   if(likerock) picked |= mpickstuff(mtmp, boulder_class);
+                   if(likegems) picked |= mpickstuff(mtmp, gem_class);
+                   if(uses_items) picked |= mpickstuff(mtmp, (char *)0);
+                   if(picked) mmoved = 3;
+               }
+
+               if(mtmp->minvis) {
+                   newsym(mtmp->mx, mtmp->my);
+                   if (mtmp->wormno) see_wsegs(mtmp);
+               }
+           }
+
+           if(hides_under(ptr) || ptr->mlet == S_EEL) {
+               /* Always set--or reset--mundetected if it's already hidden
+                  (just in case the object it was hiding under went away);
+                  usually set mundetected unless monster can't move.  */
+               if (mtmp->mundetected ||
+                       (mtmp->mcanmove && !mtmp->msleeping && rn2(5)))
+                   mtmp->mundetected = (ptr->mlet != S_EEL) ?
+                       OBJ_AT(mtmp->mx, mtmp->my) :
+                       (is_pool(mtmp->mx, mtmp->my) && !Is_waterlevel(&u.uz));
+               newsym(mtmp->mx, mtmp->my);
+           }
+           if (mtmp->isshk) {
+               after_shk_move(mtmp);
+           }
+       }
+       return(mmoved);
+}
+
+#endif /* OVL0 */
+#ifdef OVL2
+
+boolean
+closed_door(x, y)
+register int x, y;
+{
+       return((boolean)(IS_DOOR(levl[x][y].typ) &&
+                       (levl[x][y].doormask & (D_LOCKED | D_CLOSED))));
+}
+
+boolean
+accessible(x, y)
+register int x, y;
+{
+       return((boolean)(ACCESSIBLE(levl[x][y].typ) && !closed_door(x, y)));
+}
+
+#endif /* OVL2 */
+#ifdef OVL0
+
+/* decide where the monster thinks you are standing */
+void
+set_apparxy(mtmp)
+register struct monst *mtmp;
+{
+       boolean notseen, gotu;
+       register int disp, mx = mtmp->mux, my = mtmp->muy;
+#ifdef GOLDOBJ
+       long umoney = money_cnt(invent);
+#endif
+
+       /*
+        * do cheapest and/or most likely tests first
+        */
+
+       /* pet knows your smell; grabber still has hold of you */
+       if (mtmp->mtame || mtmp == u.ustuck) goto found_you;
+
+       /* monsters which know where you are don't suddenly forget,
+          if you haven't moved away */
+       if (mx == u.ux && my == u.uy) goto found_you;
+
+       notseen = (!mtmp->mcansee || (Invis && !perceives(mtmp->data)));
+       /* add cases as required.  eg. Displacement ... */
+       if (notseen || Underwater) {
+           /* Xorns can smell valuable metal like gold, treat as seen */
+           if ((mtmp->data == &mons[PM_XORN]) &&
+#ifndef GOLDOBJ
+                       u.ugold
+#else
+                       umoney
+#endif
+                       && !Underwater)
+               disp = 0;
+           else
+               disp = 1;
+       } else if (Displaced) {
+           disp = couldsee(mx, my) ? 2 : 1;
+       } else disp = 0;
+       if (!disp) goto found_you;
+
+       /* without something like the following, invis. and displ.
+          are too powerful */
+       gotu = notseen ? !rn2(3) : Displaced ? !rn2(4) : FALSE;
+
+#if 0          /* this never worked as intended & isn't needed anyway */
+       /* If invis but not displaced, staying around gets you 'discovered' */
+       gotu |= (!Displaced && u.dx == 0 && u.dy == 0);
+#endif
+
+       if (!gotu) {
+           register int try_cnt = 0;
+           do {
+               if (++try_cnt > 200) goto found_you;            /* punt */
+               mx = u.ux - disp + rn2(2*disp+1);
+               my = u.uy - disp + rn2(2*disp+1);
+           } while (!isok(mx,my)
+                 || (disp != 2 && mx == mtmp->mx && my == mtmp->my)
+                 || ((mx != u.ux || my != u.uy) &&
+                     !passes_walls(mtmp->data) &&
+                     (!ACCESSIBLE(levl[mx][my].typ) ||
+                      (closed_door(mx, my) && !can_ooze(mtmp))))
+                 || !couldsee(mx, my));
+       } else {
+found_you:
+           mx = u.ux;
+           my = u.uy;
+       }
+
+       mtmp->mux = mx;
+       mtmp->muy = my;
+}
+
+boolean
+can_ooze(mtmp)
+struct monst *mtmp;
+{
+       struct obj *chain, *obj;
+
+       if (!amorphous(mtmp->data)) return FALSE;
+       if (mtmp == &youmonst) {
+#ifndef GOLDOBJ
+               if (u.ugold > 100L) return FALSE;
+#endif
+               chain = invent;
+       } else {
+#ifndef GOLDOBJ
+               if (mtmp->mgold > 100L) return FALSE;
+#endif
+               chain = mtmp->minvent;
+       }
+       for (obj = chain; obj; obj = obj->nobj) {
+               int typ = obj->otyp;
+
+#ifdef GOLDOBJ
+                if (typ == COIN_CLASS && obj->quan > 100L) return FALSE;
+#endif
+               if (obj->oclass != GEM_CLASS &&
+                   !(typ >= ARROW && typ <= BOOMERANG) &&
+                   !(typ >= DAGGER && typ <= CRYSKNIFE) &&
+                   typ != SLING &&
+                   !is_cloak(obj) && typ != FEDORA &&
+                   !is_gloves(obj) && typ != LEATHER_JACKET &&
+#ifdef TOURIST
+                   typ != CREDIT_CARD && !is_shirt(obj) &&
+#endif
+                   !(typ == CORPSE && verysmall(&mons[obj->corpsenm])) &&
+                   typ != FORTUNE_COOKIE && typ != CANDY_BAR &&
+                   typ != PANCAKE && typ != LEMBAS_WAFER &&
+                   typ != LUMP_OF_ROYAL_JELLY &&
+                   obj->oclass != AMULET_CLASS &&
+                   obj->oclass != RING_CLASS &&
+#ifdef WIZARD
+                   obj->oclass != VENOM_CLASS &&
+#endif
+                   typ != SACK && typ != BAG_OF_HOLDING &&
+                   typ != BAG_OF_TRICKS && !Is_candle(obj) &&
+                   typ != OILSKIN_SACK && typ != LEASH &&
+                   typ != STETHOSCOPE && typ != BLINDFOLD && typ != TOWEL &&
+                   typ != TIN_WHISTLE && typ != MAGIC_WHISTLE &&
+                   typ != MAGIC_MARKER && typ != TIN_OPENER &&
+                   typ != SKELETON_KEY && typ != LOCK_PICK
+               ) return FALSE;
+               if (Is_container(obj) && obj->cobj) return FALSE;
+                   
+       }
+       return TRUE;
+}
+
+#endif /* OVL0 */
+
+/*monmove.c*/
diff --git a/src/monst.c b/src/monst.c
new file mode 100644 (file)
index 0000000..dc7c267
--- /dev/null
@@ -0,0 +1,3477 @@
+/*     SCCS Id: @(#)monst.c    3.4     2000/07/14      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "config.h"
+#include "permonst.h"
+#include "monsym.h"
+#include "dungeon.h"   /* prerequisite for eshk,vault,epri */
+#include "eshk.h"
+#include "vault.h"
+#include "epri.h"
+
+#define NO_ATTK {0,0,0,0}
+
+#define WT_ELF    800
+#define WT_DRAGON 4500
+
+#ifdef C
+#undef C
+#endif
+#ifdef TEXTCOLOR
+#include "color.h"
+#define C(color)       color
+#define HI_DOMESTIC    CLR_WHITE       /* use for player + friendlies */
+#define HI_LORD                CLR_MAGENTA
+#else
+#define C(color)
+#endif
+
+void NDECL(monst_init);
+/*
+ *     Entry Format:           (from permonst.h)
+ *
+ *     name, symbol (S_* defines),
+ *     difficulty level, move rate, armor class, magic resistance,
+ *     alignment, creation/geno flags (G_* defines),
+ *     6 * attack structs ( type , damage-type, # dice, # sides ),
+ *     weight (WT_* defines), nutritional value, extension length,
+ *     sounds made (MS_* defines), physical size (MZ_* defines),
+ *     resistances, resistances conferred (both MR_* defines),
+ *     3 * flag bitmaps (M1_*, M2_*, and M3_* defines respectively)
+ *     symbol color (C(x) macro)
+ */
+#define MON(nam,sym,lvl,gen,atk,siz,mr1,mr2,flg1,flg2,flg3,col) \
+          {nam,sym,lvl,gen,atk,siz,mr1,mr2,flg1,flg2,flg3,C(col)}
+/* LVL() and SIZ() collect several fields to cut down on # of args for MON() */
+#define LVL(lvl,mov,ac,mr,aln) lvl,mov,ac,mr,aln
+#define SIZ(wt,nut,pxl,snd,siz) wt,nut,pxl,snd,siz
+/* ATTK() and A() are to avoid braces and commas within args to MON() */
+#define ATTK(at,ad,n,d) {at,ad,n,d}
+#define A(a1,a2,a3,a4,a5,a6) {a1,a2,a3,a4,a5,a6}
+
+
+/*
+ *     Rule #1:        monsters of a given class are contiguous in the
+ *                     mons[] array.
+ *
+ *     Rule #2:        monsters of a given class are presented in ascending
+ *                     order of strength.
+ *
+ *     Rule #3:        monster frequency is included in the geno mask;
+ *                     the frequency can be from 0 to 7.  0's will also
+ *                     be skipped during generation.
+ *
+ *     Rule #4:        monster subclasses (e.g. giants) should be kept
+ *                     together, unless it violates Rule 2.  NOGEN monsters
+ *                     won't violate Rule 2.
+ *
+ * Guidelines for color assignment:
+ *
+ *     * Use the same color for all `growth stages' of a monster (ex.
+ *       little dog/big dog, baby naga/full-grown naga.
+ *
+ *     * Use colors given in names wherever possible. If the class has `real'
+ *       members with strong color associations, use those.
+ *
+ *     * Favor `cool' colors for cold-resistent monsters, `warm' ones for
+ *       fire-resistent ones.
+ *
+ *     * Try to reserve purple (magenta) for powerful `ruler' monsters (queen
+ *       bee, kobold lord, &c.).
+ *
+ *     * Subject to all these constraints, try to use color to make as many
+ *       distinctions as the / command (that is, within a monster letter
+ *       distinct names should map to distinct colors).
+ *
+ * The aim in assigning colors is to be consistent enough so a player can
+ * become `intuitive' about them, deducing some or all of these rules
+ * unconsciously. Use your common sense.
+ */
+
+#ifndef SPLITMON_2
+NEARDATA struct permonst mons[] = {
+/*
+ * ants
+ */
+    MON("giant ant", S_ANT,
+       LVL(2, 18, 3, 0, 0), (G_GENO|G_SGROUP|3),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(10, 10, 0, MS_SILENT, MZ_TINY), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_CARNIVORE,
+       M2_HOSTILE, 0, CLR_BROWN),
+    MON("killer bee", S_ANT,
+       LVL(1, 18, -1, 0, 0), (G_GENO|G_LGROUP|2),
+       A(ATTK(AT_STNG, AD_DRST, 1, 3),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1, 5, 0, MS_BUZZ, MZ_TINY), MR_POISON, MR_POISON,
+       M1_ANIMAL|M1_FLY|M1_NOHANDS|M1_POIS,
+       M2_HOSTILE|M2_FEMALE, 0, CLR_YELLOW),
+    MON("soldier ant", S_ANT,
+       LVL(3, 18, 3, 0, 0), (G_GENO|G_SGROUP|2),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_STNG, AD_DRST, 3, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(20, 5, 0, MS_SILENT, MZ_TINY), MR_POISON, MR_POISON,
+       M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_POIS|M1_CARNIVORE,
+       M2_HOSTILE, 0, CLR_BLUE),
+    MON("fire ant", S_ANT,
+       LVL(3, 18, 3, 10, 0), (G_GENO|G_SGROUP|1),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_BITE, AD_FIRE, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(30, 10, 0, MS_SILENT, MZ_TINY), MR_FIRE, MR_FIRE,
+       M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_CARNIVORE,
+       M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED),
+    MON("giant beetle", S_ANT,
+       LVL(5, 6, 4, 0, 0), (G_GENO|3),
+       A(ATTK(AT_BITE, AD_PHYS, 3, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(10, 10, 0, MS_SILENT, MZ_LARGE), MR_POISON, MR_POISON,
+       M1_ANIMAL|M1_NOHANDS|M1_POIS|M1_CARNIVORE,
+       M2_HOSTILE, 0, CLR_BLACK),
+    MON("queen bee", S_ANT,
+       LVL(9, 24, -4, 0, 0), (G_GENO|G_NOGEN),
+       A(ATTK(AT_STNG, AD_DRST, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1, 5, 0, MS_BUZZ, MZ_TINY), MR_POISON, MR_POISON,
+       M1_ANIMAL|M1_FLY|M1_NOHANDS|M1_OVIPAROUS|M1_POIS,
+       M2_HOSTILE|M2_FEMALE|M2_PRINCE, 0, HI_LORD),
+/*
+ * blobs
+ */
+    MON("acid blob", S_BLOB,
+       LVL(1, 3, 8, 0, 0), (G_GENO|2),
+       A(ATTK(AT_NONE, AD_ACID, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(30, 10, 0, MS_SILENT, MZ_TINY),
+       MR_SLEEP|MR_POISON|MR_ACID|MR_STONE, MR_STONE,
+       M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|
+         M1_MINDLESS|M1_ACID,
+       M2_WANDER|M2_NEUTER, 0, CLR_GREEN),
+    MON("quivering blob", S_BLOB,
+       LVL(5, 1, 8, 0, 0), (G_GENO|2),
+       A(ATTK(AT_TUCH, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(200, 100, 0, MS_SILENT, MZ_SMALL),
+       MR_SLEEP|MR_POISON, MR_POISON,
+       M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS,
+       M2_WANDER|M2_HOSTILE|M2_NEUTER, 0, CLR_WHITE),
+    MON("gelatinous cube", S_BLOB,
+       LVL(6, 6, 8, 0, 0), (G_GENO|2),
+       A(ATTK(AT_TUCH, AD_PLYS, 2, 4), ATTK(AT_NONE, AD_PLYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(600, 150, 0, MS_SILENT, MZ_LARGE),
+       MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON|MR_ACID|MR_STONE,
+       MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP,
+       M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_OMNIVORE|M1_ACID,
+       M2_WANDER|M2_HOSTILE|M2_NEUTER, 0, CLR_CYAN),
+/*
+ * cockatrice
+ */
+    MON("chickatrice", S_COCKATRICE,
+       LVL(4, 4, 8, 30, 0), (G_GENO|G_SGROUP|1),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 2), ATTK(AT_TUCH, AD_STON, 0, 0),
+         ATTK(AT_NONE, AD_STON, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(10, 10, 0, MS_HISS, MZ_TINY),
+       MR_POISON|MR_STONE, MR_POISON|MR_STONE,
+       M1_ANIMAL|M1_NOHANDS|M1_OMNIVORE, M2_HOSTILE,
+       M3_INFRAVISIBLE, CLR_BROWN),
+    MON("cockatrice", S_COCKATRICE,
+       LVL(5, 6, 6, 30, 0), (G_GENO|5),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 3), ATTK(AT_TUCH, AD_STON, 0, 0),
+         ATTK(AT_NONE, AD_STON, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(30, 30, 0, MS_HISS, MZ_SMALL),
+       MR_POISON|MR_STONE, MR_POISON|MR_STONE,
+       M1_ANIMAL|M1_NOHANDS|M1_OMNIVORE|M1_OVIPAROUS, M2_HOSTILE,
+       M3_INFRAVISIBLE, CLR_YELLOW),
+    MON("pyrolisk", S_COCKATRICE, 
+       LVL(6, 6, 6, 30, 0), (G_GENO|1),
+       A(ATTK(AT_GAZE, AD_FIRE, 2, 6), NO_ATTK,
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), 
+       SIZ(30, 30, 0, MS_HISS, MZ_SMALL),
+       MR_POISON|MR_FIRE, MR_POISON|MR_FIRE,
+       M1_ANIMAL|M1_NOHANDS|M1_OMNIVORE|M1_OVIPAROUS, M2_HOSTILE,
+       M3_INFRAVISIBLE, CLR_RED),
+/*
+ * dogs & other canines
+ */
+    MON("jackal", S_DOG,
+       LVL(0, 12, 7, 0, 0), (G_GENO|G_SGROUP|3),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 2),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(300, 250, 0, MS_BARK, MZ_SMALL), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_BROWN),
+    MON("fox", S_DOG,
+       LVL(0, 15, 7, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK,
+         NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(300, 250, 0, MS_BARK, MZ_SMALL), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_RED),
+    MON("coyote", S_DOG,
+       LVL(1, 12, 7, 0, 0), (G_GENO|G_SGROUP|1),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK,
+         NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(300, 250, 0, MS_BARK, MZ_SMALL), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_BROWN),
+    MON("werejackal", S_DOG,
+       LVL(2, 12, 7, 10, -7), (G_NOGEN|G_NOCORPSE),
+       A(ATTK(AT_BITE, AD_WERE, 1, 4), NO_ATTK, NO_ATTK,
+         NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(300, 250, 0, MS_BARK, MZ_SMALL), MR_POISON, 0,
+       M1_NOHANDS|M1_POIS|M1_REGEN|M1_CARNIVORE,
+       M2_NOPOLY|M2_WERE|M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN),
+    MON("little dog", S_DOG,
+       LVL(2, 18, 6, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(150, 150, 0, MS_BARK, MZ_SMALL), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_DOMESTIC, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("dog", S_DOG,
+       LVL(4, 16, 5, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 1 ,6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(400, 200, 0, MS_BARK, MZ_MEDIUM), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_DOMESTIC, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("large dog", S_DOG,
+       LVL(6, 15, 4, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(800, 250, 0, MS_BARK, MZ_MEDIUM), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,
+       M2_STRONG|M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("dingo", S_DOG,
+       LVL(4, 16, 5, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 1 ,6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(400, 200, 0, MS_BARK, MZ_MEDIUM), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_YELLOW),
+    MON("wolf", S_DOG,
+       LVL(5, 12, 4, 0, 0), (G_GENO|G_SGROUP|2),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(500, 250, 0, MS_BARK, MZ_MEDIUM), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_BROWN),
+    MON("werewolf", S_DOG,
+       LVL(5, 12, 4, 20, -7), (G_NOGEN|G_NOCORPSE),
+       A(ATTK(AT_BITE, AD_WERE, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(500, 250, 0, MS_BARK, MZ_MEDIUM), MR_POISON, 0,
+       M1_NOHANDS|M1_POIS|M1_REGEN|M1_CARNIVORE,
+       M2_NOPOLY|M2_WERE|M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN),
+    MON("warg", S_DOG,
+       LVL(7, 12, 4, 0, -5), (G_GENO|G_SGROUP|2),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(850, 350, 0, MS_BARK, MZ_MEDIUM), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_BROWN),
+    MON("winter wolf cub", S_DOG,
+       LVL(5, 12, 4, 0, -5), (G_NOHELL|G_GENO|G_SGROUP|2),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 8), ATTK(AT_BREA, AD_COLD, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(250, 200, 0, MS_BARK, MZ_SMALL), MR_COLD, MR_COLD,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_CYAN),
+    MON("winter wolf", S_DOG,
+       LVL(7, 12, 4, 20, 0), (G_NOHELL|G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_BREA, AD_COLD, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(700, 300, 0, MS_BARK, MZ_LARGE), MR_COLD, MR_COLD,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG, 0, CLR_CYAN),
+    MON("hell hound pup", S_DOG,
+       LVL(7, 12, 4, 20, -5), (G_HELL|G_GENO|G_SGROUP|1),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_BREA, AD_FIRE, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(200, 200, 0, MS_BARK, MZ_SMALL), MR_FIRE, MR_FIRE,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_RED),
+    MON("hell hound", S_DOG,
+       LVL(12, 14, 2, 20, 0), (G_HELL|G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 3, 6), ATTK(AT_BREA, AD_FIRE, 3, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(600, 300, 0, MS_BARK, MZ_MEDIUM), MR_FIRE, MR_FIRE,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE|M2_STRONG,
+       M3_INFRAVISIBLE, CLR_RED),
+#ifdef CHARON
+    MON("Cerberus", S_DOG,
+       LVL(12, 10, 2, 20, -7), (G_HELL|G_UNIQ|1),
+       A(ATTK(AT_BITE, AD_PHYS, 3, 6), ATTK(AT_BITE, AD_PHYS, 3, 6),
+         ATTK(AT_BITE, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1000, 350, 0, MS_BARK, MZ_LARGE), MR_FIRE, MR_FIRE,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,
+       M2_NOPOLY|M2_HOSTILE|M2_STRONG|M2_PNAME|M2_MALE, M3_INFRAVISIBLE,
+       CLR_RED),
+#endif
+/*
+ * eyes
+ */
+    MON("gas spore", S_EYE,
+       LVL(1, 3, 10, 0, 0), (G_NOCORPSE|G_GENO|1),
+       A(ATTK(AT_BOOM, AD_PHYS, 4, 6), NO_ATTK, NO_ATTK,
+         NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(10, 10, 0, MS_SILENT, MZ_SMALL), 0, 0,
+       M1_FLY|M1_BREATHLESS|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_GRAY),
+    MON("floating eye", S_EYE,
+       LVL(2, 1, 9, 10, 0), (G_GENO|5),
+       A(ATTK(AT_NONE, AD_PLYS, 0,70),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(10, 10, 0, MS_SILENT, MZ_SMALL), 0, 0,
+       M1_FLY|M1_AMPHIBIOUS|M1_NOLIMBS|M1_NOHEAD|M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_BLUE),
+    MON("freezing sphere", S_EYE,
+       LVL(6, 13, 4, 0, 0), (G_NOCORPSE|G_NOHELL|G_GENO|2),
+       A(ATTK(AT_EXPL, AD_COLD, 4, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(10, 10, 0, MS_SILENT, MZ_SMALL), MR_COLD, MR_COLD,
+       M1_FLY|M1_BREATHLESS|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_WHITE),
+    MON("flaming sphere", S_EYE, 
+       LVL(6, 13, 4, 0, 0), (G_NOCORPSE|G_GENO|2),
+       A(ATTK(AT_EXPL, AD_FIRE, 4, 6), NO_ATTK, NO_ATTK,
+           NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(10, 10, 0, MS_SILENT, MZ_SMALL), MR_FIRE, MR_FIRE,
+       M1_FLY|M1_BREATHLESS|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS,
+       M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_RED),
+    MON("shocking sphere", S_EYE, 
+       LVL(6, 13, 4, 0, 0), (G_NOCORPSE|G_GENO|2),
+       A(ATTK(AT_EXPL, AD_ELEC, 4, 6), NO_ATTK, NO_ATTK,
+         NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(10, 10, 0, MS_SILENT, MZ_SMALL), MR_ELEC, MR_ELEC,
+       M1_FLY|M1_BREATHLESS|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS,
+       M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, HI_ZAP),
+#if 0          /* not yet implemented */
+    MON("beholder", S_EYE,
+       LVL(6, 3, 4, 0, -10), (G_GENO|2),
+       A(ATTK(AT_GAZE, AD_SLOW, 0, 0), ATTK(AT_GAZE, AD_SLEE, 2,25),
+         ATTK(AT_GAZE, AD_DISN, 0, 0), ATTK(AT_GAZE, AD_STON, 0, 0),
+         ATTK(AT_GAZE, AD_CNCL, 2, 4), ATTK(AT_BITE, AD_PHYS, 2, 4)),
+       SIZ(10, 10, 0, MS_SILENT, MZ_SMALL), MR_COLD, 0,
+       M1_FLY|M1_BREATHLESS|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS,
+       M2_NOPOLY|M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_BROWN),
+#endif
+/*
+ * felines
+ */
+    MON("kitten", S_FELINE,
+       LVL(2, 18, 6, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(150, 150, 0, MS_MEW, MZ_SMALL), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,
+       M2_WANDER|M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("housecat", S_FELINE,
+       LVL(4, 16, 5, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(200, 200, 0, MS_MEW, MZ_SMALL), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_DOMESTIC, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("jaguar", S_FELINE,
+       LVL(4, 15, 6, 0, 0), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         ATTK(AT_BITE, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(600, 300, 0, MS_GROWL, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_BROWN),
+    MON("lynx", S_FELINE, 
+       LVL(5, 15, 6, 0, 0), (G_GENO|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         ATTK(AT_BITE, AD_PHYS, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(600, 300, 0, MS_GROWL, MZ_SMALL), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_CYAN),
+    MON("panther", S_FELINE, 
+       LVL(5, 15, 6, 0, 0), (G_GENO|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6),
+         ATTK(AT_BITE, AD_PHYS, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(600, 300, 0, MS_GROWL, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_BLACK),
+    MON("large cat", S_FELINE,
+       LVL(6, 15, 4, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(250, 250, 0, MS_MEW, MZ_SMALL), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,
+       M2_STRONG|M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("tiger", S_FELINE,
+       LVL(6, 12, 6, 0, 0), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4),
+         ATTK(AT_BITE, AD_PHYS, 1,10), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(600, 300, 0, MS_GROWL, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_YELLOW),
+/*
+ * gremlins and gargoyles
+ */
+    MON("gremlin", S_GREMLIN,
+       LVL(5, 12, 2, 25, -9), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6),
+         ATTK(AT_BITE, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_CURS, 0, 0),
+         NO_ATTK, NO_ATTK),
+       SIZ(100, 20, 0, MS_LAUGH, MZ_SMALL), MR_POISON, MR_POISON,
+       M1_SWIM|M1_HUMANOID|M1_POIS, M2_STALK, M3_INFRAVISIBLE, CLR_GREEN),
+    MON("gargoyle", S_GREMLIN,
+       LVL(6, 10, -4, 0, -9), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_PHYS, 2, 6),
+         ATTK(AT_BITE, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1000, 200, 0, MS_GRUNT, MZ_HUMAN), MR_STONE, MR_STONE,
+       M1_HUMANOID|M1_THICK_HIDE|M1_BREATHLESS,
+       M2_HOSTILE|M2_STRONG, 0, CLR_BROWN),
+    MON("winged gargoyle", S_GREMLIN,
+       LVL(9, 15, -2, 0, -12), (G_GENO|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 3, 6),
+         ATTK(AT_BITE, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1200, 300, 0, MS_GRUNT, MZ_HUMAN), MR_STONE, MR_STONE,
+       M1_FLY|M1_HUMANOID|M1_THICK_HIDE|M1_BREATHLESS|M1_OVIPAROUS,
+       M2_LORD|M2_HOSTILE|M2_STRONG|M2_MAGIC, 0, HI_LORD),
+/*
+ * humanoids
+ */
+    MON("hobbit", S_HUMANOID,
+       LVL(1, 9, 10, 0, 6), (G_GENO|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(500, 200, 0, MS_HUMANOID, MZ_SMALL), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE, M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION,
+       CLR_GREEN),
+    MON("dwarf", S_HUMANOID,
+       LVL(2, 6, 10, 10, 4), (G_GENO|3),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(900, 300, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_TUNNEL|M1_NEEDPICK|M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_DWARF|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("bugbear", S_HUMANOID,
+       LVL(3, 9, 5, 0, -6), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1250, 250, 0, MS_GROWL, MZ_LARGE), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE, M2_STRONG|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN),
+    MON("dwarf lord", S_HUMANOID,
+       LVL(4, 6, 10, 10, 5), (G_GENO|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(900, 300, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_TUNNEL|M1_NEEDPICK|M1_HUMANOID|M1_OMNIVORE,
+       M2_DWARF|M2_STRONG|M2_LORD|M2_MALE|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLUE),
+    MON("dwarf king", S_HUMANOID,
+       LVL(6, 6, 10, 20, 6), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(900, 300, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_TUNNEL|M1_NEEDPICK|M1_HUMANOID|M1_OMNIVORE,
+       M2_DWARF|M2_STRONG|M2_PRINCE|M2_MALE|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+    MON("mind flayer", S_HUMANOID,
+       LVL(9, 12, 5, 90, -8), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 4), ATTK(AT_TENT, AD_DRIN, 2, 1),
+         ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1),
+         NO_ATTK, NO_ATTK),
+       SIZ(1450, 400, 0, MS_HISS, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_FLY|M1_SEE_INVIS|M1_OMNIVORE,
+       M2_HOSTILE|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_MAGENTA),
+    MON("master mind flayer", S_HUMANOID,
+       LVL(13, 12, 0, 90, -8), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_TENT, AD_DRIN, 2, 1),
+         ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1),
+         ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1)),
+       SIZ(1450, 400, 0, MS_HISS, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_FLY|M1_SEE_INVIS|M1_OMNIVORE,
+       M2_HOSTILE|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_MAGENTA),
+/*
+ * imps & other minor demons/devils
+ */
+    MON("manes", S_IMP,
+       LVL(1, 3, 7, 0, -7), (G_GENO|G_LGROUP|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3),
+         ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(100, 100, 0, MS_SILENT, MZ_SMALL), MR_SLEEP|MR_POISON, 0,
+       M1_POIS, M2_HOSTILE|M2_STALK, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("homunculus", S_IMP,
+       LVL(2, 12, 6, 10, -7), (G_GENO|2),
+       A(ATTK(AT_BITE, AD_SLEE, 1, 3),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(60, 100, 0, MS_SILENT, MZ_TINY),
+       MR_SLEEP|MR_POISON, MR_SLEEP|MR_POISON,
+       M1_FLY|M1_POIS, M2_STALK, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GREEN),
+    MON("imp", S_IMP,
+       LVL(3, 12, 2, 20, -7), (G_GENO|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(20, 10, 0, MS_CUSS, MZ_TINY), 0, 0,
+       M1_REGEN, M2_WANDER|M2_STALK, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("lemure", S_IMP,
+       LVL(3, 3, 7, 0, -7), (G_HELL|G_GENO|G_LGROUP|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 3),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(150, 100, 0, MS_SILENT, MZ_MEDIUM),
+       MR_SLEEP|MR_POISON, MR_SLEEP, M1_POIS|M1_REGEN,
+       M2_HOSTILE|M2_WANDER|M2_STALK|M2_NEUTER,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN),
+    MON("quasit", S_IMP,
+       LVL(3, 15, 2, 20, -7), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_DRDX, 1, 2), ATTK(AT_CLAW, AD_DRDX, 1, 2),
+         ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(200, 200, 0, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON,
+       M1_REGEN, M2_STALK, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLUE),
+    MON("tengu", S_IMP,
+       LVL(6, 13, 5, 30, 7), (G_GENO|3),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 7),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(300, 200, 0, MS_SQAWK, MZ_SMALL), MR_POISON, MR_POISON,
+       M1_TPORT|M1_TPORT_CNTRL, M2_STALK, M3_INFRAVISIBLE|M3_INFRAVISION,
+       CLR_CYAN),
+/*
+ * jellies
+ */
+    MON("blue jelly", S_JELLY,
+       LVL(4, 0, 8, 10, 0), (G_GENO|2),
+       A(ATTK(AT_NONE, AD_COLD, 0, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(50, 20, 0, MS_SILENT, MZ_MEDIUM),
+       MR_COLD|MR_POISON, MR_COLD|MR_POISON,
+       M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS
+         |M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_BLUE),
+    MON("spotted jelly", S_JELLY,
+       LVL(5, 0, 8, 10, 0), (G_GENO|1),
+       A(ATTK(AT_NONE, AD_ACID, 0, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(50, 20, 0, MS_SILENT, MZ_MEDIUM), MR_ACID|MR_STONE, 0,
+       M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|
+         M1_MINDLESS|M1_ACID|M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_GREEN),
+    MON("ochre jelly", S_JELLY,
+       LVL(6, 3, 8, 20, 0), (G_GENO|2),
+       A(ATTK(AT_ENGL, AD_ACID, 3, 6), ATTK(AT_NONE, AD_ACID, 3, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(50, 20, 0, MS_SILENT, MZ_MEDIUM), MR_ACID|MR_STONE, 0,
+       M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|
+         M1_MINDLESS|M1_ACID|M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_BROWN),
+/*
+ * kobolds
+ */
+    MON("kobold", S_KOBOLD,
+       LVL(0, 6, 10, 0, -2), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(400, 100, 0, MS_ORC, MZ_SMALL), MR_POISON, 0,
+       M1_HUMANOID|M1_POIS|M1_OMNIVORE, M2_HOSTILE|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN),
+    MON("large kobold", S_KOBOLD,
+       LVL(1, 6, 10, 0, -3), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(450, 150, 0, MS_ORC, MZ_SMALL), MR_POISON, 0,
+       M1_HUMANOID|M1_POIS|M1_OMNIVORE, M2_HOSTILE|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("kobold lord", S_KOBOLD,
+       LVL(2, 6, 10, 0, -4), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(500, 200, 0, MS_ORC, MZ_SMALL), MR_POISON, 0,
+       M1_HUMANOID|M1_POIS|M1_OMNIVORE,
+       M2_HOSTILE|M2_LORD|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION,
+       HI_LORD),
+    MON("kobold shaman", S_KOBOLD,
+       LVL(2, 6, 6, 10, -4), (G_GENO|1),
+       A(ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(450, 150, 0, MS_ORC, MZ_SMALL), MR_POISON, 0,
+       M1_HUMANOID|M1_POIS|M1_OMNIVORE, M2_HOSTILE|M2_MAGIC,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_ZAP),
+/*
+ * leprechauns
+ */
+    MON("leprechaun", S_LEPRECHAUN,
+       LVL(5, 15, 8, 20, 0), (G_GENO|4),
+       A(ATTK(AT_CLAW, AD_SGLD, 1, 2),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(60, 30, 0, MS_LAUGH, MZ_TINY), 0, 0,
+       M1_HUMANOID|M1_TPORT, M2_HOSTILE|M2_GREEDY, M3_INFRAVISIBLE, CLR_GREEN),
+/*
+ * mimics
+ */
+    MON("small mimic", S_MIMIC,
+       LVL(7, 3, 7, 0, 0), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 3, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(300, 200, 0, MS_SILENT, MZ_MEDIUM), MR_ACID, 0,
+       M1_BREATHLESS|M1_AMORPHOUS|M1_HIDE|M1_ANIMAL|M1_NOEYES|
+         M1_NOHEAD|M1_NOLIMBS|M1_THICK_HIDE|M1_CARNIVORE,
+       M2_HOSTILE, 0, CLR_BROWN),
+    MON("large mimic", S_MIMIC,
+       LVL(8, 3, 7, 10, 0), (G_GENO|1),
+       A(ATTK(AT_CLAW, AD_STCK, 3, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(600, 400, 0, MS_SILENT, MZ_LARGE), MR_ACID, 0,
+       M1_CLING|M1_BREATHLESS|M1_AMORPHOUS|M1_HIDE|M1_ANIMAL|M1_NOEYES|
+         M1_NOHEAD|M1_NOLIMBS|M1_THICK_HIDE|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG, 0, CLR_RED),
+    MON("giant mimic", S_MIMIC,
+       LVL(9, 3, 7, 20, 0), (G_GENO|1),
+       A(ATTK(AT_CLAW, AD_STCK, 3, 6), ATTK(AT_CLAW, AD_STCK, 3, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(800, 500, 0, MS_SILENT, MZ_LARGE), MR_ACID, 0,
+       M1_CLING|M1_BREATHLESS|M1_AMORPHOUS|M1_HIDE|M1_ANIMAL|M1_NOEYES|
+         M1_NOHEAD|M1_NOLIMBS|M1_THICK_HIDE|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG, 0, HI_LORD),
+/*
+ * nymphs
+ */
+    MON("wood nymph", S_NYMPH,
+       LVL(3, 12, 9, 20, 0), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_CLAW, AD_SEDU, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(600, 300, 0, MS_SEDUCE, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_TPORT, M2_HOSTILE|M2_FEMALE|M2_COLLECT, M3_INFRAVISIBLE,
+       CLR_GREEN),
+    MON("water nymph", S_NYMPH,
+       LVL(3, 12, 9, 20, 0), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_CLAW, AD_SEDU, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(600, 300, 0, MS_SEDUCE, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_TPORT|M1_SWIM,
+       M2_HOSTILE|M2_FEMALE|M2_COLLECT, M3_INFRAVISIBLE, CLR_BLUE),
+    MON("mountain nymph", S_NYMPH,
+       LVL(3, 12, 9, 20, 0), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_CLAW, AD_SEDU, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(600, 300, 0, MS_SEDUCE, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_TPORT, M2_HOSTILE|M2_FEMALE|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_BROWN),
+/*
+ * orcs
+ */
+    MON("goblin", S_ORC,
+       LVL(0, 6, 10, 0, -3), (G_GENO|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(400, 100, 0, MS_ORC, MZ_SMALL), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE, M2_ORC|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY),
+    MON("hobgoblin", S_ORC,
+       LVL(1, 9, 10, 0, -4), (G_GENO|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1000, 200, 0, MS_ORC, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE, M2_ORC|M2_STRONG|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN),
+       /* plain "orc" for zombie corpses only; not created at random
+        */
+    MON("orc", S_ORC,
+       LVL(1, 9, 10, 0, -3), (G_GENO|G_NOGEN|G_LGROUP),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(850, 150, 0, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_ORC|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("hill orc", S_ORC,
+       LVL(2, 9, 10, 0, -4), (G_GENO|G_LGROUP|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1000, 200, 0, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE,
+       M2_ORC|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_YELLOW),
+    MON("Mordor orc", S_ORC,
+       LVL(3, 5, 10, 0, -5), (G_GENO|G_LGROUP|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1200, 200, 0, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE,
+       M2_ORC|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLUE),
+    MON("Uruk-hai", S_ORC,
+       LVL(3, 7, 10, 0, -4), (G_GENO|G_LGROUP|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1300, 300, 0, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE,
+       M2_ORC|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLACK),
+    MON("orc shaman", S_ORC,
+       LVL(3, 9, 5, 10, -5), (G_GENO|1),
+       A(ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1000, 300, 0, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE,
+       M2_ORC|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_MAGIC,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_ZAP),
+    MON("orc-captain", S_ORC,
+       LVL(5, 5, 10, 0, -5), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1350, 350, 0, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE,
+       M2_ORC|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+/*
+ * piercers
+ */
+    MON("rock piercer", S_PIERCER,
+       LVL(3, 1, 3, 0, 0), (G_GENO|4),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(200, 200, 0, MS_SILENT, MZ_SMALL), 0, 0,
+       M1_CLING|M1_HIDE|M1_ANIMAL|M1_NOEYES|M1_NOLIMBS|M1_CARNIVORE|M1_NOTAKE,
+       M2_HOSTILE, 0, CLR_GRAY),
+    MON("iron piercer", S_PIERCER,
+       LVL(5, 1, 0, 0, 0), (G_GENO|2),
+       A(ATTK(AT_BITE, AD_PHYS, 3, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(400, 300, 0, MS_SILENT, MZ_MEDIUM), 0, 0,
+       M1_CLING|M1_HIDE|M1_ANIMAL|M1_NOEYES|M1_NOLIMBS|M1_CARNIVORE|M1_NOTAKE,
+       M2_HOSTILE, 0, CLR_CYAN),
+    MON("glass piercer", S_PIERCER,
+       LVL(7, 1, 0, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 4, 6), NO_ATTK, NO_ATTK,
+         NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(400, 300, 0, MS_SILENT, MZ_MEDIUM), MR_ACID, 0,
+       M1_CLING|M1_HIDE|M1_ANIMAL|M1_NOEYES|M1_NOLIMBS|M1_CARNIVORE|M1_NOTAKE,
+       M2_HOSTILE, 0, CLR_WHITE),
+/*
+ * quadrupeds
+ */
+    MON("rothe", S_QUADRUPED,
+       LVL(2, 9, 7, 0, 0), (G_GENO|G_SGROUP|4),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 1, 3),
+         ATTK(AT_BITE, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(400, 100, 0, MS_SILENT, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_OMNIVORE, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_BROWN),
+    MON("mumak", S_QUADRUPED,
+       LVL(5, 9, 0, 0, -2), (G_GENO|1),
+       A(ATTK(AT_BUTT, AD_PHYS, 4,12), ATTK(AT_BITE, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2500, 500, 0, MS_ROAR, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_THICK_HIDE|M1_NOHANDS|M1_HERBIVORE,
+       M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_GRAY),
+    MON("leocrotta", S_QUADRUPED,
+       LVL(6, 18, 4, 10, 0), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_BITE, AD_PHYS, 2, 6),
+         ATTK(AT_CLAW, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1200, 500, 0, MS_IMITATE, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_OMNIVORE, M2_HOSTILE|M2_STRONG,
+       M3_INFRAVISIBLE, CLR_RED),
+    MON("wumpus", S_QUADRUPED,
+       LVL(8, 3, 2, 10, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 3, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2500, 500, 0, MS_BURBLE, MZ_LARGE), 0, 0,
+       M1_CLING|M1_ANIMAL|M1_NOHANDS|M1_OMNIVORE,
+       M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_CYAN),
+    MON("titanothere", S_QUADRUPED,
+       LVL(12, 12, 6, 0, 0), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2650, 650, 0, MS_SILENT, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_THICK_HIDE|M1_NOHANDS|M1_HERBIVORE,
+       M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_GRAY),
+    MON("baluchitherium", S_QUADRUPED,
+       LVL(14, 12, 5, 0, 0), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 5, 4), ATTK(AT_CLAW, AD_PHYS, 5, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(3800, 800, 0, MS_SILENT, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_THICK_HIDE|M1_NOHANDS|M1_HERBIVORE,
+       M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_GRAY),
+    MON("mastodon", S_QUADRUPED,
+       LVL(20, 12, 5, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BUTT, AD_PHYS, 4, 8), ATTK(AT_BUTT, AD_PHYS, 4, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(3800, 800, 0, MS_SILENT, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_THICK_HIDE|M1_NOHANDS|M1_HERBIVORE,
+       M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_BLACK),
+/*
+ * rodents
+ */
+    MON("sewer rat", S_RODENT,
+       LVL(0, 12, 7, 0, 0), (G_GENO|G_SGROUP|1),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 3),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(20, 12, 0, MS_SQEEK, MZ_TINY), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_BROWN),
+    MON("giant rat", S_RODENT,
+       LVL(1, 10, 7, 0, 0), (G_GENO|G_SGROUP|2),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 3),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(30, 30, 0, MS_SQEEK, MZ_TINY), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_BROWN),
+    MON("rabid rat", S_RODENT,
+       LVL(2, 12, 6, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_DRCO, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(30, 5, 0, MS_SQEEK, MZ_TINY), MR_POISON, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_POIS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_BROWN),
+    MON("wererat", S_RODENT,
+       LVL(2, 12, 6, 10, -7), (G_NOGEN|G_NOCORPSE),
+       A(ATTK(AT_BITE, AD_WERE, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(40, 30, 0, MS_SQEEK, MZ_TINY), MR_POISON, 0,
+       M1_NOHANDS|M1_POIS|M1_REGEN|M1_CARNIVORE,
+       M2_NOPOLY|M2_WERE|M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN),
+    MON("rock mole", S_RODENT,
+       LVL(3, 3, 0, 20, 0), (G_GENO|2),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(30, 30, 0, MS_SILENT, MZ_SMALL), 0, 0,
+       M1_TUNNEL|M1_ANIMAL|M1_NOHANDS|M1_METALLIVORE,
+       M2_HOSTILE|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE, CLR_GRAY),
+    MON("woodchuck", S_RODENT,
+       LVL(3, 3, 0, 20, 0), (G_NOGEN|G_GENO),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(30, 30, 0, MS_SILENT, MZ_SMALL), 0, 0,
+       M1_TUNNEL/*LOGGING*/|M1_ANIMAL|M1_NOHANDS|M1_SWIM|M1_HERBIVORE,
+               /* In reality, they tunnel instead of cutting lumber.  Oh, well. */
+       M2_WANDER|M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN),
+/*
+ * spiders & scorpions (keep webmaker() in sync if new critters are added)
+ */
+    MON("cave spider", S_SPIDER,
+       LVL(1, 12, 3, 0, 0), (G_GENO|G_SGROUP|2),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 2),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(50, 50, 0, MS_SILENT, MZ_TINY), MR_POISON, MR_POISON,
+       M1_CONCEAL|M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_CARNIVORE,
+       M2_HOSTILE, 0, CLR_GRAY),
+    MON("centipede", S_SPIDER, 
+       LVL(2, 4, 3, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_DRST, 1, 3), NO_ATTK, NO_ATTK,
+         NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(50, 50, 0, MS_SILENT, MZ_TINY), MR_POISON, MR_POISON,
+       M1_CONCEAL|M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_CARNIVORE,
+       M2_HOSTILE, 0, CLR_YELLOW),
+    MON("giant spider", S_SPIDER,
+       LVL(5, 15, 4, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_DRST, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(100, 100, 0, MS_SILENT, MZ_LARGE), MR_POISON, MR_POISON,
+       M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_POIS|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG, 0, CLR_MAGENTA),
+    MON("scorpion", S_SPIDER,
+       LVL(5, 15, 3, 0, 0), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 2), ATTK(AT_CLAW, AD_PHYS, 1, 2),
+         ATTK(AT_STNG, AD_DRST, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(50, 100, 0, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON,
+       M1_CONCEAL|M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_POIS|M1_CARNIVORE,
+       M2_HOSTILE, 0, CLR_RED),
+/*
+ * trappers, lurkers, &c
+ */
+    MON("lurker above", S_TRAPPER,
+       LVL(10, 3, 3, 0, 0), (G_GENO|2),
+       A(ATTK(AT_ENGL, AD_DGST, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(800, 350, 0, MS_SILENT, MZ_HUGE), 0, 0,
+       M1_HIDE|M1_FLY|M1_ANIMAL|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_CARNIVORE,
+       M2_HOSTILE|M2_STALK|M2_STRONG, 0, CLR_GRAY),
+    MON("trapper", S_TRAPPER,
+       LVL(12, 3, 3, 0, 0), (G_GENO|2),
+       A(ATTK(AT_ENGL, AD_DGST, 1,10),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(800, 350, 0, MS_SILENT, MZ_HUGE), 0, 0,
+       M1_HIDE|M1_ANIMAL|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_CARNIVORE,
+       M2_HOSTILE|M2_STALK|M2_STRONG, 0, CLR_GREEN),
+/*
+ * unicorns and horses
+ */
+    MON("white unicorn", S_UNICORN,
+       LVL(4, 24, 2, 70, 7), (G_GENO|2),
+       A(ATTK(AT_BUTT, AD_PHYS, 1,12), ATTK(AT_KICK, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1300, 300, 0, MS_NEIGH, MZ_LARGE), MR_POISON, MR_POISON,
+       M1_NOHANDS|M1_HERBIVORE, M2_WANDER|M2_STRONG|M2_JEWELS,
+       M3_INFRAVISIBLE, CLR_WHITE),
+    MON("gray unicorn", S_UNICORN,
+       LVL(4, 24, 2, 70, 0), (G_GENO|1),
+       A(ATTK(AT_BUTT, AD_PHYS, 1,12), ATTK(AT_KICK, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1300, 300, 0, MS_NEIGH, MZ_LARGE), MR_POISON, MR_POISON,
+       M1_NOHANDS|M1_HERBIVORE, M2_WANDER|M2_STRONG|M2_JEWELS,
+       M3_INFRAVISIBLE, CLR_GRAY),
+    MON("black unicorn", S_UNICORN,
+       LVL(4, 24, 2, 70, -7), (G_GENO|1),
+       A(ATTK(AT_BUTT, AD_PHYS, 1,12), ATTK(AT_KICK, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1300, 300, 0, MS_NEIGH, MZ_LARGE), MR_POISON, MR_POISON,
+       M1_NOHANDS|M1_HERBIVORE, M2_WANDER|M2_STRONG|M2_JEWELS,
+       M3_INFRAVISIBLE, CLR_BLACK),
+    MON("pony", S_UNICORN,
+       LVL(3, 16, 6, 0, 0), (G_GENO|2),
+       A(ATTK(AT_KICK, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_PHYS, 1, 2),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1300, 250, 0, MS_NEIGH, MZ_MEDIUM), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_HERBIVORE, M2_WANDER|M2_STRONG|M2_DOMESTIC,
+       M3_INFRAVISIBLE, CLR_BROWN),
+    MON("horse", S_UNICORN,
+       LVL(5, 20, 5, 0, 0), (G_GENO|2),
+       A(ATTK(AT_KICK, AD_PHYS, 1, 8), ATTK(AT_BITE, AD_PHYS, 1, 3),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 300, 0, MS_NEIGH, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_HERBIVORE, M2_WANDER|M2_STRONG|M2_DOMESTIC,
+       M3_INFRAVISIBLE, CLR_BROWN),
+    MON("warhorse", S_UNICORN,
+       LVL(7, 24, 4, 0, 0), (G_GENO|2),
+       A(ATTK(AT_KICK, AD_PHYS, 1, 10), ATTK(AT_BITE, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1800, 350, 0, MS_NEIGH, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_HERBIVORE, M2_WANDER|M2_STRONG|M2_DOMESTIC,
+       M3_INFRAVISIBLE, CLR_BROWN),
+/*
+ * vortices
+ */
+    MON("fog cloud", S_VORTEX,
+       LVL(3, 1, 0, 0, 0), (G_GENO|G_NOCORPSE|2),
+       A(ATTK(AT_ENGL, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(0, 0, 0, MS_SILENT, MZ_HUGE), MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_FLY|M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|
+         M1_AMORPHOUS|M1_UNSOLID,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_GRAY),
+    MON("dust vortex", S_VORTEX,
+       LVL(4, 20, 2, 30, 0), (G_GENO|G_NOCORPSE|2),
+       A(ATTK(AT_ENGL, AD_BLND, 2, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(0, 0, 0, MS_SILENT, MZ_HUGE), MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_FLY|M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_BROWN),
+    MON("ice vortex", S_VORTEX,
+       LVL(5, 20, 2, 30, 0), (G_NOHELL|G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_ENGL, AD_COLD, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(0, 0, 0, MS_SILENT, MZ_HUGE),
+       MR_COLD|MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_FLY|M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS,
+       M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_CYAN),
+    MON("energy vortex", S_VORTEX,
+       LVL(6, 20, 2, 30, 0), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_ENGL, AD_ELEC, 1, 6), ATTK(AT_ENGL, AD_DREN, 0, 0),
+         ATTK(AT_NONE, AD_ELEC, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(0, 0, 0, MS_SILENT, MZ_HUGE),
+       MR_ELEC|MR_SLEEP|MR_DISINT|MR_POISON|MR_STONE, 0,
+       M1_FLY|M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|
+         M1_UNSOLID,
+       M2_HOSTILE|M2_NEUTER, 0, HI_ZAP),
+    MON("steam vortex", S_VORTEX,
+       LVL(7, 22, 2, 30, 0), (G_HELL|G_GENO|G_NOCORPSE|2),
+       A(ATTK(AT_ENGL, AD_FIRE, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(0, 0, 0, MS_SILENT, MZ_HUGE),
+       MR_FIRE|MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_FLY|M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|
+         M1_UNSOLID,
+       M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_BLUE),
+    MON("fire vortex", S_VORTEX,
+       LVL(8, 22, 2, 30, 0), (G_HELL|G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_ENGL, AD_FIRE, 1,10), ATTK(AT_NONE, AD_FIRE, 0, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(0, 0, 0, MS_SILENT, MZ_HUGE),
+       MR_FIRE|MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_FLY|M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|
+         M1_UNSOLID,
+       M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_YELLOW),
+/*
+ * worms
+ */
+    MON("baby long worm", S_WORM,
+       LVL(8, 3, 5, 0, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(600, 250, 0, MS_SILENT, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_SLITHY|M1_NOLIMBS|M1_CARNIVORE|M1_NOTAKE,
+       M2_HOSTILE, 0, CLR_BROWN),
+    MON("baby purple worm", S_WORM,
+       LVL(8, 3, 5, 0, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(600, 250, 0, MS_SILENT, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_SLITHY|M1_NOLIMBS|M1_CARNIVORE, M2_HOSTILE,
+       0, CLR_MAGENTA),
+    MON("long worm", S_WORM,
+       LVL(8, 3, 5, 10, 0), (G_GENO|2),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_SILENT, MZ_GIGANTIC), 0, 0,
+       M1_ANIMAL|M1_SLITHY|M1_NOLIMBS|M1_OVIPAROUS|M1_CARNIVORE|M1_NOTAKE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY, 0, CLR_BROWN),
+    MON("purple worm", S_WORM,
+       LVL(15, 9, 6, 20, 0), (G_GENO|2),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 8), ATTK(AT_ENGL, AD_DGST, 1,10),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2700, 700, 0, MS_SILENT, MZ_GIGANTIC), 0, 0,
+       M1_ANIMAL|M1_SLITHY|M1_NOLIMBS|M1_OVIPAROUS|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY, 0, CLR_MAGENTA),
+/*
+ * xan, &c
+ */
+    MON("grid bug", S_XAN,
+       LVL(0, 12, 9, 0, 0), (G_GENO|G_SGROUP|G_NOCORPSE|3),
+       A(ATTK(AT_BITE, AD_ELEC, 1, 1),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(15, 10, 0, MS_BUZZ, MZ_TINY), MR_ELEC|MR_POISON, 0,
+       M1_ANIMAL, M2_HOSTILE, M3_INFRAVISIBLE, CLR_MAGENTA),
+    MON("xan", S_XAN,
+       LVL(7, 18, -4, 0, 0), (G_GENO|3),
+       A(ATTK(AT_STNG, AD_LEGS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(300, 300, 0, MS_BUZZ, MZ_TINY), MR_POISON, MR_POISON,
+       M1_FLY|M1_ANIMAL|M1_NOHANDS|M1_POIS, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_RED),
+/*
+ * lights
+ */
+    MON("yellow light", S_LIGHT,
+       LVL(3, 15, 0, 0, 0), (G_NOCORPSE|G_GENO|4),
+       A(ATTK(AT_EXPL, AD_BLND, 10,20),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(0, 0, 0, MS_SILENT, MZ_SMALL),
+       MR_FIRE|MR_COLD|MR_ELEC|MR_DISINT|MR_SLEEP|MR_POISON|MR_ACID|
+         MR_STONE, 0,
+       M1_FLY|M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|
+         M1_MINDLESS|M1_UNSOLID|M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_YELLOW),
+    MON("black light", S_LIGHT,
+       LVL(5, 15, 0, 0, 0), (G_NOCORPSE|G_GENO|2),
+       A(ATTK(AT_EXPL, AD_HALU, 10,12),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(0, 0, 0, MS_SILENT, MZ_SMALL),
+       MR_FIRE|MR_COLD|MR_ELEC|MR_DISINT|MR_SLEEP|MR_POISON|MR_ACID|
+         MR_STONE, 0,
+       M1_FLY|M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|
+         M1_MINDLESS|M1_UNSOLID|M1_SEE_INVIS|M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_BLACK),
+/*
+ * zruty
+ */
+    MON("zruty", S_ZRUTY,
+       LVL(9, 8, 3, 0, 0), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_CLAW, AD_PHYS, 3, 4),
+         ATTK(AT_BITE, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1200, 600, 0, MS_SILENT, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_BROWN),
+/*
+ * Angels and other lawful minions
+ */
+    MON("couatl", S_ANGEL,
+       LVL(8, 10, 5, 30, 7), (G_NOHELL|G_SGROUP|G_NOCORPSE|1),
+       A(ATTK(AT_BITE, AD_DRST, 2, 4), ATTK(AT_BITE, AD_PHYS, 1, 3),
+         ATTK(AT_HUGS, AD_WRAP, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(900, 400, 0, MS_HISS, MZ_LARGE), MR_POISON, 0,
+       M1_FLY|M1_POIS,
+       M2_MINION|M2_STALK|M2_STRONG|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION,
+       CLR_GREEN),
+    MON("Aleax", S_ANGEL,
+       LVL(10, 8, 0, 30, 7), (G_NOHELL|G_NOCORPSE|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         ATTK(AT_KICK, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_IMITATE, MZ_HUMAN),
+       MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON, 0,
+       M1_HUMANOID|M1_SEE_INVIS,
+       M2_MINION|M2_STALK|M2_NASTY|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION,
+       CLR_YELLOW),
+    MON("Angel", S_ANGEL,
+       LVL(14, 10, -4, 55, 12), (G_NOHELL|G_NOCORPSE|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), 
+         ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_MAGC, AD_MAGM, 2, 6),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, sizeof(struct epri), MS_CUSS, MZ_HUMAN),
+       MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON, 0,
+       M1_FLY|M1_HUMANOID|M1_SEE_INVIS,
+       M2_NOPOLY|M2_MINION|M2_STALK|M2_STRONG|M2_NASTY|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_WHITE),
+    MON("ki-rin", S_ANGEL,
+       LVL(16, 18, -5, 90, 15), (G_NOHELL|G_NOCORPSE|1),
+       A(ATTK(AT_KICK, AD_PHYS, 2, 4), ATTK(AT_KICK, AD_PHYS, 2, 4),
+         ATTK(AT_BUTT, AD_PHYS, 3, 6), ATTK(AT_MAGC, AD_SPEL, 2, 6),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_NEIGH, MZ_LARGE), 0, 0,
+       M1_FLY|M1_SEE_INVIS,
+       M2_NOPOLY|M2_MINION|M2_STALK|M2_STRONG|M2_NASTY|M2_LORD,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_GOLD),
+    MON("Archon", S_ANGEL,
+       LVL(19, 16, -6, 80, 15), (G_NOHELL|G_NOCORPSE|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         ATTK(AT_GAZE, AD_BLND, 2, 6), ATTK(AT_CLAW, AD_PHYS, 1, 8),
+         ATTK(AT_MAGC, AD_SPEL, 4, 6), NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_CUSS, MZ_LARGE),
+       MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON, 0,
+       M1_FLY|M1_HUMANOID|M1_SEE_INVIS|M1_REGEN,
+       M2_NOPOLY|M2_MINION|M2_STALK|M2_STRONG|M2_NASTY|M2_LORD|
+         M2_COLLECT|M2_MAGIC,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+/*
+ * Bats
+ */
+    MON("bat", S_BAT,
+       LVL(0, 22, 8, 0, 0), (G_GENO|G_SGROUP|1),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(20, 20, 0, MS_SQEEK, MZ_TINY), 0, 0,
+       M1_FLY|M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_WANDER, M3_INFRAVISIBLE,
+       CLR_BROWN),
+    MON("giant bat", S_BAT,
+       LVL(2, 22, 7, 0, 0), (G_GENO|2),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(30, 30, 0, MS_SQEEK, MZ_SMALL), 0, 0,
+       M1_FLY|M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,
+       M2_WANDER|M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED),
+    MON("raven", S_BAT,
+       LVL(4, 20, 6, 0, 0), (G_GENO|2),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_BLND, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(40, 20, 0, MS_SQAWK, MZ_SMALL), 0, 0,
+       M1_FLY|M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,
+       M2_WANDER|M2_HOSTILE, M3_INFRAVISIBLE, CLR_BLACK),
+    MON("vampire bat", S_BAT,
+       LVL(5, 20, 6, 0, 0), (G_GENO|2),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_DRST, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(30, 20, 0, MS_SQEEK, MZ_SMALL), MR_SLEEP|MR_POISON, 0,
+       M1_FLY|M1_ANIMAL|M1_NOHANDS|M1_POIS|M1_REGEN|M1_OMNIVORE,
+       M2_HOSTILE, M3_INFRAVISIBLE, CLR_BLACK),
+/*
+ * Centaurs
+ */
+    MON("plains centaur", S_CENTAUR,
+       LVL(4, 18, 4, 0, 0), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_KICK, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2500, 500, 0, MS_HUMANOID, MZ_LARGE), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE, M2_STRONG|M2_GREEDY|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_BROWN),
+    MON("forest centaur", S_CENTAUR,
+       LVL(5, 18, 3, 10, -1), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_KICK, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2550, 600, 0, MS_HUMANOID, MZ_LARGE), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE, M2_STRONG|M2_GREEDY|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_GREEN),
+    MON("mountain centaur", S_CENTAUR,
+       LVL(6, 20, 2, 10, -3), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1,10), ATTK(AT_KICK, AD_PHYS, 1, 6),
+         ATTK(AT_KICK, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2550, 500, 0, MS_HUMANOID, MZ_LARGE), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE, M2_STRONG|M2_GREEDY|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_CYAN),
+/*
+ * Dragons
+ */
+       /* The order of the dragons is VERY IMPORTANT.  Quite a few
+        * pieces of code depend on gray being first and yellow being last.
+        * The code also depends on the *order* being the same as that for
+        * dragon scale mail and dragon scales in objects.c.  Baby dragons
+        * cannot confer intrinsics, to avoid polyself/egg abuse.
+        *
+        * As reptiles, dragons are cold-blooded and thus aren't seen
+        * with infravision.  Red dragons are the exception.
+        */
+    MON("baby gray dragon", S_DRAGON,
+       LVL(12, 9, 2, 10, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), 0, 0,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_GRAY),
+    MON("baby silver dragon", S_DRAGON,
+       LVL(12, 9, 2, 10, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), 0, 0,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, DRAGON_SILVER),
+#if 0  /* DEFERRED */
+    MON("baby shimmering dragon", S_DRAGON,
+       LVL(12, 9, 2, 10, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), 0, 0,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_CYAN),
+#endif
+    MON("baby red dragon", S_DRAGON,
+       LVL(12, 9, 2, 10, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_FIRE, 0,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, M3_INFRAVISIBLE, CLR_RED),
+    MON("baby white dragon", S_DRAGON,
+       LVL(12, 9, 2, 10, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_COLD, 0,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_WHITE),
+    MON("baby orange dragon", S_DRAGON,
+       LVL(12, 9, 2, 10, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_SLEEP, 0,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_ORANGE),
+    MON("baby black dragon", S_DRAGON,
+       LVL(12, 9, 2, 10, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_DISINT, 0,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_BLACK),
+    MON("baby blue dragon", S_DRAGON,
+       LVL(12, 9, 2, 10, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_ELEC, 0,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_BLUE),
+    MON("baby green dragon", S_DRAGON,
+       LVL(12, 9, 2, 10, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_POISON, 0,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE|M1_POIS,
+       M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_GREEN),
+    MON("baby yellow dragon", S_DRAGON,
+       LVL(12, 9, 2, 10, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_ACID|MR_STONE, 0,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE|M1_ACID,
+       M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_YELLOW),
+    MON("gray dragon", S_DRAGON,
+       LVL(15, 9, -1, 20, 4), (G_GENO|1),
+       A(ATTK(AT_BREA, AD_MAGM, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8),
+         ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), 0, 0,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS|
+         M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, CLR_GRAY),
+    MON("silver dragon", S_DRAGON,
+       LVL(15, 9, -1, 20, 4), (G_GENO|1),
+       A(ATTK(AT_BREA, AD_COLD, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8),
+         ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_COLD, 0,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS|
+         M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC,
+       0, DRAGON_SILVER),
+#if 0  /* DEFERRED */
+    MON("shimmering dragon", S_DRAGON,
+       LVL(15, 9, -1, 20, 4), (G_GENO|1),
+       A(ATTK(AT_BREA, AD_MAGM, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8),
+         ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), 0, 0,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS|
+         M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC,
+       0, CLR_CYAN),
+#endif
+    MON("red dragon", S_DRAGON,
+       LVL(15, 9, -1, 20, -4), (G_GENO|1),
+       A(ATTK(AT_BREA, AD_FIRE, 6, 6), ATTK(AT_BITE, AD_PHYS, 3, 8),
+         ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_FIRE, MR_FIRE,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS|
+         M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC,
+       M3_INFRAVISIBLE, CLR_RED),
+    MON("white dragon", S_DRAGON,
+       LVL(15, 9, -1, 20, -5), (G_GENO|1),
+       A(ATTK(AT_BREA, AD_COLD, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8),
+         ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_COLD, MR_COLD,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS|
+         M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, CLR_WHITE),
+    MON("orange dragon", S_DRAGON,
+       LVL(15, 9, -1, 20, 5), (G_GENO|1),
+       A(ATTK(AT_BREA, AD_SLEE, 4,25), ATTK(AT_BITE, AD_PHYS, 3, 8),
+         ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_SLEEP, MR_SLEEP,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS|
+         M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC,
+       0, CLR_ORANGE),
+    MON("black dragon", S_DRAGON,
+       LVL(15, 9, -1, 20, -6), (G_GENO|1),
+       A(ATTK(AT_BREA, AD_DISN, 4,10), ATTK(AT_BITE, AD_PHYS, 3, 8),
+         ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_DISINT, MR_DISINT,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS|
+         M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, CLR_BLACK),
+    MON("blue dragon", S_DRAGON,
+       LVL(15, 9, -1, 20, -7), (G_GENO|1),
+       A(ATTK(AT_BREA, AD_ELEC, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8),
+         ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_ELEC, MR_ELEC,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS|
+         M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, CLR_BLUE),
+    MON("green dragon", S_DRAGON,
+       LVL(15, 9, -1, 20, 6), (G_GENO|1),
+       A(ATTK(AT_BREA, AD_DRST, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8),
+         ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_POISON, MR_POISON,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS|
+         M1_CARNIVORE|M1_POIS,
+       M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, CLR_GREEN),
+    MON("yellow dragon", S_DRAGON,
+       LVL(15, 9, -1, 20, 7), (G_GENO|1),
+       A(ATTK(AT_BREA, AD_ACID, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8),
+         ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC),
+       MR_ACID|MR_STONE, MR_STONE,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS|
+         M1_CARNIVORE|M1_ACID,
+       M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC,
+       0, CLR_YELLOW),
+/*
+ * Elementals
+ */
+    MON("stalker", S_ELEMENTAL,
+       LVL(8, 12, 3, 0, 0), (G_GENO|3),
+       A(ATTK(AT_CLAW, AD_PHYS, 4, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(900, 400, 0, MS_SILENT, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_FLY|M1_SEE_INVIS,
+       M2_WANDER|M2_STALK|M2_HOSTILE|M2_STRONG, M3_INFRAVISION, CLR_WHITE),
+    MON("air elemental", S_ELEMENTAL,
+       LVL(8, 36, 2, 30, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_ENGL, AD_PHYS, 1, 10),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(0, 0, 0, MS_SILENT, MZ_HUGE), MR_POISON|MR_STONE, 0,
+       M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_UNSOLID|M1_FLY,
+       M2_STRONG|M2_NEUTER, 0, CLR_CYAN),
+    MON("fire elemental", S_ELEMENTAL,
+       LVL(8, 12, 2, 30, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_FIRE, 3, 6), ATTK(AT_NONE, AD_FIRE, 0, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(0, 0, 0, MS_SILENT, MZ_HUGE), MR_FIRE|MR_POISON|MR_STONE, 0,
+       M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_UNSOLID|M1_FLY|M1_NOTAKE,
+       M2_STRONG|M2_NEUTER, M3_INFRAVISIBLE, CLR_YELLOW),
+    MON("earth elemental", S_ELEMENTAL,
+       LVL(8, 6, 2, 30, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 4, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2500, 0, 0, MS_SILENT, MZ_HUGE),
+       MR_FIRE|MR_COLD|MR_POISON|MR_STONE, 0,
+       M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_BREATHLESS|
+         M1_WALLWALK|M1_THICK_HIDE,
+       M2_STRONG|M2_NEUTER, 0, CLR_BROWN),
+    MON("water elemental", S_ELEMENTAL,
+       LVL(8, 6, 2, 30, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 5, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2500, 0, 0, MS_SILENT, MZ_HUGE), MR_POISON|MR_STONE, 0,
+       M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_AMPHIBIOUS|M1_SWIM,
+       M2_STRONG|M2_NEUTER, 0, CLR_BLUE),
+/*
+ * Fungi
+ */
+    MON("lichen", S_FUNGUS,
+       LVL(0, 1, 9, 0, 0), (G_GENO|4),
+       A(ATTK(AT_TUCH, AD_STCK, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(20, 200, 0, MS_SILENT, MZ_SMALL), 0, 0,
+       M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_BRIGHT_GREEN),
+    MON("brown mold", S_FUNGUS,
+       LVL(1, 0, 9, 0, 0), (G_GENO|1),
+       A(ATTK(AT_NONE, AD_COLD, 0, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(50, 30, 0, MS_SILENT, MZ_SMALL),
+       MR_COLD|MR_POISON, MR_COLD|MR_POISON,
+       M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_BROWN),
+    MON("yellow mold", S_FUNGUS,
+       LVL(1, 0, 9, 0, 0), (G_GENO|2),
+       A(ATTK(AT_NONE, AD_STUN, 0, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(50, 30, 0, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON,
+       M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_POIS|M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_YELLOW),
+    MON("green mold", S_FUNGUS,
+       LVL(1, 0, 9, 0, 0), (G_GENO|1),
+       A(ATTK(AT_NONE, AD_ACID, 0, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(50, 30, 0, MS_SILENT, MZ_SMALL), MR_ACID|MR_STONE, MR_STONE,
+       M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_ACID|M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_GREEN),
+    MON("red mold", S_FUNGUS,
+       LVL(1, 0, 9, 0, 0), (G_GENO|1),
+       A(ATTK(AT_NONE, AD_FIRE, 0, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(50, 30, 0, MS_SILENT, MZ_SMALL),
+       MR_FIRE|MR_POISON, MR_FIRE|MR_POISON,
+       M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_RED),
+    MON("shrieker", S_FUNGUS,
+       LVL(3, 1, 7, 0, 0), (G_GENO|1),
+       A(NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(100, 100, 0, MS_SHRIEK, MZ_SMALL), MR_POISON, MR_POISON,
+       M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_MAGENTA),
+    MON("violet fungus", S_FUNGUS,
+       LVL(3, 1, 7, 0, 0), (G_GENO|2),
+       A(ATTK(AT_TUCH, AD_PHYS, 1, 4), ATTK(AT_TUCH, AD_STCK, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(100, 100, 0, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON,
+       M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_NOTAKE,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_MAGENTA),
+/*
+ * Gnomes
+ */
+    MON("gnome", S_GNOME,
+       LVL(1, 6, 10, 4, 0), (G_GENO|G_SGROUP|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(650, 100, 0, MS_ORC, MZ_SMALL), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_GNOME|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN),
+    MON("gnome lord", S_GNOME,
+       LVL(3, 8, 10, 4, 0), (G_GENO|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(700, 120, 0, MS_ORC, MZ_SMALL), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE, M2_GNOME|M2_LORD|M2_MALE|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLUE),
+    MON("gnomish wizard", S_GNOME,
+       LVL(3, 10, 4, 10, 0), (G_GENO|1),
+       A(ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(700, 120, 0, MS_ORC, MZ_SMALL), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE, M2_GNOME|M2_MAGIC,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_ZAP),
+    MON("gnome king", S_GNOME,
+       LVL(5, 10, 10, 20, 0), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(750, 150, 0, MS_ORC, MZ_SMALL), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE, M2_GNOME|M2_PRINCE|M2_MALE|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+#ifdef SPLITMON_1
+};
+#endif
+#endif /* !SPLITMON_2 */
+
+/* horrible kludge alert:
+ * This is a compiler-specific kludge to allow the compilation of monst.o in
+ * two pieces, by defining first SPLITMON_1 and then SPLITMON_2. The
+ * resulting assembler files (monst1.s and monst2.s) are then run through
+ * sed to change local symbols, concatenated together, and assembled to
+ * produce monst.o. THIS ONLY WORKS WITH THE ATARI GCC, and should only
+ * be done if you don't have enough memory to compile monst.o the "normal"
+ * way.  --ERS
+ */
+
+#ifndef SPLITMON_1
+#ifdef SPLITMON_2
+struct permonst _mons2[] = {
+#endif
+/*
+ * giant Humanoids
+ */
+    MON("giant", S_GIANT,
+       LVL(6, 6, 0, 0, 2), (G_GENO|G_NOGEN|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2,10),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2250, 750, 0, MS_BOAST, MZ_HUGE), 0, 0,
+       M1_HUMANOID|M1_CARNIVORE,
+       M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_JEWELS,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("stone giant", S_GIANT,
+       LVL(6, 6, 0, 0, 2), (G_GENO|G_SGROUP|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2,10),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2250, 750, 0, MS_BOAST, MZ_HUGE), 0, 0,
+       M1_HUMANOID|M1_CARNIVORE,
+       M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_JEWELS,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY),
+    MON("hill giant", S_GIANT,
+       LVL(8, 10, 6, 0, -2), (G_GENO|G_SGROUP|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2200, 700, 0, MS_BOAST, MZ_HUGE), 0, 0,
+       M1_HUMANOID|M1_CARNIVORE,
+       M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_JEWELS,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_CYAN),
+    MON("fire giant", S_GIANT,
+       LVL(9, 12, 4, 5, 2), (G_GENO|G_SGROUP|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2,10),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2250, 750, 0, MS_BOAST, MZ_HUGE), MR_FIRE, MR_FIRE,
+       M1_HUMANOID|M1_CARNIVORE,
+       M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_JEWELS,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_YELLOW),
+    MON("frost giant", S_GIANT,
+       LVL(10, 12, 3, 10, -3), (G_NOHELL|G_GENO|G_SGROUP|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2,12),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2250, 750, 0, MS_BOAST, MZ_HUGE), MR_COLD, MR_COLD,
+       M1_HUMANOID|M1_CARNIVORE,
+       M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_JEWELS,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_WHITE),
+    MON("storm giant", S_GIANT,
+       LVL(16, 12, 3, 10, -3), (G_GENO|G_SGROUP|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 12),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2250, 750, 0, MS_BOAST, MZ_HUGE), MR_ELEC, MR_ELEC,
+       M1_HUMANOID|M1_CARNIVORE,
+       M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_JEWELS,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLUE),
+    MON("ettin", S_GIANT,
+       LVL(10, 12, 3, 0, 0), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_WEAP, AD_PHYS, 3, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1700, 500, 0, MS_GRUNT, MZ_HUGE), 0, 0,
+       M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN),
+    MON("titan", S_GIANT,
+       LVL(16, 18, -3, 70, 9), (1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2300, 900, 0, MS_SPELL, MZ_HUGE), 0, 0,
+       M1_FLY|M1_HUMANOID|M1_OMNIVORE,
+       M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_MAGIC,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_MAGENTA),
+    MON("minotaur", S_GIANT,
+       LVL(15, 15, 6, 0, 0), (G_GENO|G_NOGEN),
+       A(ATTK(AT_CLAW, AD_PHYS, 3,10), ATTK(AT_CLAW, AD_PHYS, 3,10),
+         ATTK(AT_BUTT, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 700, 0, MS_SILENT, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION,
+       CLR_BROWN),
+/* 'I' is a visual marker for all invisible monsters and must be unused */
+/*
+ * Jabberwock
+ */
+    MON("jabberwock", S_JABBERWOCK,
+       LVL(15, 12, -2, 50, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 2,10), ATTK(AT_BITE, AD_PHYS, 2,10),
+         ATTK(AT_CLAW, AD_PHYS, 2,10), ATTK(AT_CLAW, AD_PHYS, 2,10),
+         NO_ATTK, NO_ATTK),
+       SIZ(1300, 600, 0, MS_BURBLE, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_FLY|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY|M2_COLLECT, M3_INFRAVISIBLE, CLR_ORANGE),
+#if 0  /* DEFERRED */
+    MON("vorpal jabberwock", S_JABBERWOCK,       
+       LVL(20, 12, -2, 50, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 3, 10), ATTK(AT_BITE, AD_PHYS, 3, 10),
+         ATTK(AT_CLAW, AD_PHYS, 3, 10), ATTK(AT_CLAW, AD_PHYS, 3, 10),
+         NO_ATTK, NO_ATTK),
+       SIZ(1300, 600, 0, MS_BURBLE, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_FLY|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY|M2_COLLECT, M3_INFRAVISIBLE, HI_LORD),
+#endif
+#ifdef KOPS
+/*
+ * Kops
+ */
+    MON("Keystone Kop", S_KOP,
+       LVL(1, 6, 10, 10, 9), (G_GENO|G_LGROUP|G_NOGEN),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 200, 0, MS_ARREST, MZ_HUMAN), 0, 0, M1_HUMANOID,
+       M2_HUMAN|M2_WANDER|M2_HOSTILE|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE,
+       CLR_BLUE),
+    MON("Kop Sergeant", S_KOP,
+       LVL(2, 8, 10, 10, 10), (G_GENO|G_SGROUP|G_NOGEN),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 200, 0, MS_ARREST, MZ_HUMAN), 0, 0, M1_HUMANOID,
+       M2_HUMAN|M2_WANDER|M2_HOSTILE|M2_STRONG|M2_MALE|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_BLUE),
+    MON("Kop Lieutenant", S_KOP,
+       LVL(3, 10, 10, 20, 11), (G_GENO|G_NOGEN),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 200, 0, MS_ARREST, MZ_HUMAN), 0, 0, M1_HUMANOID,
+       M2_HUMAN|M2_WANDER|M2_HOSTILE|M2_STRONG|M2_MALE|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_CYAN),
+    MON("Kop Kaptain", S_KOP,
+       LVL(4, 12, 10, 20, 12), (G_GENO|G_NOGEN),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 200, 0, MS_ARREST, MZ_HUMAN), 0, 0, M1_HUMANOID,
+       M2_HUMAN|M2_WANDER|M2_HOSTILE|M2_STRONG|M2_MALE|M2_COLLECT,
+       M3_INFRAVISIBLE, HI_LORD),
+#endif
+/*
+ * Liches
+ */
+    MON("lich", S_LICH,
+       LVL(11, 6, 0, 30, -9), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_TUCH, AD_COLD, 1,10), ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1200, 100, 0, MS_MUMBLE, MZ_HUMAN),
+       MR_COLD|MR_SLEEP|MR_POISON, MR_COLD,
+       M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN,
+       M2_UNDEAD|M2_HOSTILE|M2_MAGIC, M3_INFRAVISION, CLR_BROWN),
+    MON("demilich", S_LICH,
+       LVL(14, 9, -2, 60, -12), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_TUCH, AD_COLD, 3, 4), ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1200, 100, 0, MS_MUMBLE, MZ_HUMAN),
+       MR_COLD|MR_SLEEP|MR_POISON, MR_COLD,
+       M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN,
+       M2_UNDEAD|M2_HOSTILE|M2_MAGIC, M3_INFRAVISION, CLR_RED),
+    MON("master lich", S_LICH,
+       LVL(17, 9, -4, 90, -15), (G_HELL|G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_TUCH, AD_COLD, 3, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1200, 100, 0, MS_MUMBLE, MZ_HUMAN),
+       MR_FIRE|MR_COLD|MR_SLEEP|MR_POISON, MR_FIRE|MR_COLD,
+       M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN,
+       M2_UNDEAD|M2_HOSTILE|M2_MAGIC, M3_WANTSBOOK|M3_INFRAVISION, HI_LORD),
+    MON("arch-lich", S_LICH,
+       LVL(25, 9, -6, 90, -15), (G_HELL|G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_TUCH, AD_COLD, 5, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1200, 100, 0, MS_MUMBLE, MZ_HUMAN),
+       MR_FIRE|MR_COLD|MR_SLEEP|MR_ELEC|MR_POISON, MR_FIRE|MR_COLD,
+       M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN,
+       M2_UNDEAD|M2_HOSTILE|M2_MAGIC, M3_WANTSBOOK|M3_INFRAVISION, HI_LORD),
+/*
+ * Mummies
+ */
+    MON("kobold mummy", S_MUMMY,
+       LVL(3, 8, 6, 20, -2), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(400, 50, 0, MS_SILENT, MZ_SMALL), MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS,
+       M2_UNDEAD|M2_HOSTILE, M3_INFRAVISION, CLR_BROWN),
+    MON("gnome mummy", S_MUMMY,
+       LVL(4, 10, 6, 20, -3), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(650, 50, 0, MS_SILENT, MZ_SMALL), MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS,
+       M2_UNDEAD|M2_HOSTILE|M2_GNOME, M3_INFRAVISION, CLR_RED),
+    MON("orc mummy", S_MUMMY,
+       LVL(5, 10, 5, 20, -4), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(850, 75, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS,
+       M2_UNDEAD|M2_HOSTILE|M2_ORC|M2_GREEDY|M2_JEWELS, M3_INFRAVISION,
+       CLR_GRAY),
+    MON("dwarf mummy", S_MUMMY,
+       LVL(5, 10, 5, 20, -4), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(900, 150, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS,
+       M2_UNDEAD|M2_HOSTILE|M2_DWARF|M2_GREEDY|M2_JEWELS, M3_INFRAVISION,
+       CLR_RED),
+    MON("elf mummy", S_MUMMY,
+       LVL(6, 12, 4, 30, -5), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_ELF, 175, 0, MS_SILENT, MZ_HUMAN),
+       MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS,
+       M2_UNDEAD|M2_HOSTILE|M2_ELF, M3_INFRAVISION, CLR_GREEN),
+    MON("human mummy", S_MUMMY,
+       LVL(6, 12, 4, 30, -5), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 200, 0, MS_SILENT, MZ_HUMAN),
+       MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS,
+       M2_UNDEAD|M2_HOSTILE, M3_INFRAVISION, CLR_GRAY),
+    MON("ettin mummy", S_MUMMY,
+       LVL(7, 12, 4, 30, -6), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1700, 250, 0, MS_SILENT, MZ_HUGE),
+       MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS,
+       M2_UNDEAD|M2_HOSTILE|M2_STRONG, M3_INFRAVISION, CLR_BLUE),
+    MON("giant mummy", S_MUMMY,
+       LVL(8, 14, 3, 30, -7), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_CLAW, AD_PHYS, 3, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2050, 375, 0, MS_SILENT, MZ_HUGE),
+       MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS,
+       M2_UNDEAD|M2_HOSTILE|M2_GIANT|M2_STRONG|M2_JEWELS, M3_INFRAVISION,
+       CLR_CYAN),
+/*
+ * Nagas
+ */
+    MON("red naga hatchling", S_NAGA,
+       LVL(3, 10, 6, 0, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(500, 100, 0, MS_MUMBLE, MZ_LARGE),
+       MR_FIRE|MR_POISON, MR_FIRE|MR_POISON,
+       M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_NOTAKE|M1_OMNIVORE, M2_STRONG,
+       M3_INFRAVISIBLE, CLR_RED),
+    MON("black naga hatchling", S_NAGA,
+       LVL(3, 10, 6, 0, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(500, 100, 0, MS_MUMBLE, MZ_LARGE),
+       MR_POISON|MR_ACID|MR_STONE, MR_POISON|MR_STONE,
+       M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_ACID|M1_NOTAKE|M1_CARNIVORE,
+       M2_STRONG, 0, CLR_BLACK),
+    MON("golden naga hatchling", S_NAGA,
+       LVL(3, 10, 6, 0, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(500, 100, 0, MS_MUMBLE, MZ_LARGE), MR_POISON, MR_POISON,
+       M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_NOTAKE|M1_OMNIVORE,
+       M2_STRONG, 0, HI_GOLD),
+    MON("guardian naga hatchling", S_NAGA,
+       LVL(3, 10, 6, 0, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(500, 100, 0, MS_MUMBLE, MZ_LARGE), MR_POISON, MR_POISON,
+       M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_NOTAKE|M1_OMNIVORE,
+       M2_STRONG, 0, CLR_GREEN),
+    MON("red naga", S_NAGA,
+       LVL(6, 12, 4, 0, -4), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_BREA, AD_FIRE, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2600, 400, 0, MS_MUMBLE, MZ_HUGE),
+       MR_FIRE|MR_POISON, MR_FIRE|MR_POISON,
+       M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_OVIPAROUS|M1_NOTAKE|M1_OMNIVORE,
+       M2_STRONG, M3_INFRAVISIBLE, CLR_RED),
+    MON("black naga", S_NAGA,
+       LVL(8, 14, 2, 10, 4), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_SPIT, AD_ACID, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2600, 400, 0, MS_MUMBLE, MZ_HUGE),
+       MR_POISON|MR_ACID|MR_STONE, MR_POISON|MR_STONE,
+       M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_OVIPAROUS|M1_ACID|M1_NOTAKE|
+         M1_CARNIVORE,
+       M2_STRONG, 0, CLR_BLACK),
+    MON("golden naga", S_NAGA,
+       LVL(10, 14, 2, 70, 5), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_MAGC, AD_SPEL, 4, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2600, 400, 0, MS_MUMBLE, MZ_HUGE), MR_POISON, MR_POISON,
+       M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_OVIPAROUS|M1_NOTAKE|M1_OMNIVORE,
+       M2_STRONG, 0, HI_GOLD),
+    MON("guardian naga", S_NAGA,
+       LVL(12, 16, 0, 50, 7), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PLYS, 1, 6), ATTK(AT_SPIT, AD_DRST, 1, 6),
+         ATTK(AT_HUGS, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2600, 400, 0, MS_MUMBLE, MZ_HUGE), MR_POISON, MR_POISON,
+       M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_OVIPAROUS|M1_POIS|M1_NOTAKE|
+         M1_OMNIVORE,
+       M2_STRONG, 0, CLR_GREEN),
+/*
+ * Ogres
+ */
+    MON("ogre", S_OGRE,
+       LVL(5, 10, 5, 0, -3), (G_SGROUP|G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 5),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1600, 500, 0, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID|M1_CARNIVORE,
+       M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN),
+    MON("ogre lord", S_OGRE,
+       LVL(7, 12, 3, 30, -5), (G_GENO|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1700, 700, 0, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID|M1_CARNIVORE,
+       M2_STRONG|M2_LORD|M2_MALE|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("ogre king", S_OGRE,
+       LVL(9, 14, 4, 60, -7), (G_GENO|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 3, 5),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1700, 750, 0, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID|M1_CARNIVORE,
+       M2_STRONG|M2_PRINCE|M2_MALE|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+/*
+ * Puddings
+ */
+    MON("gray ooze", S_PUDDING,
+       LVL(3, 1, 8, 0, 0), (G_GENO|2),
+       A(ATTK(AT_BITE, AD_RUST, 2, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(500, 250, 0, MS_SILENT, MZ_MEDIUM),
+       MR_FIRE|MR_COLD|MR_POISON|MR_ACID|MR_STONE, MR_FIRE|MR_COLD|MR_POISON,
+       M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|
+         M1_MINDLESS|M1_OMNIVORE|M1_ACID,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_GRAY),
+    MON("brown pudding", S_PUDDING,
+       LVL(5, 3, 8, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_DCAY, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(500, 250, 0, MS_SILENT, MZ_MEDIUM),
+       MR_COLD|MR_ELEC|MR_POISON|MR_ACID|MR_STONE, MR_COLD|MR_ELEC|MR_POISON,
+       M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|
+         M1_MINDLESS|M1_OMNIVORE|M1_ACID,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_BROWN),
+    MON("black pudding", S_PUDDING,
+       LVL(10, 6, 6, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_CORR, 3, 8), ATTK(AT_NONE, AD_CORR, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(900, 250, 0, MS_SILENT, MZ_LARGE),
+       MR_COLD|MR_ELEC|MR_POISON|MR_ACID|MR_STONE, MR_COLD|MR_ELEC|MR_POISON,
+       M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|
+         M1_MINDLESS|M1_OMNIVORE|M1_ACID,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_BLACK),
+    MON("green slime", S_PUDDING, 
+       LVL(6, 6, 6, 0, 0), (G_HELL|G_GENO|1),
+       A(ATTK(AT_TUCH, AD_SLIM, 1, 4), ATTK(AT_NONE, AD_SLIM, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(400, 150, 0, MS_SILENT, MZ_LARGE),
+       MR_COLD|MR_ELEC|MR_POISON|MR_ACID|MR_STONE, 0,
+       M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|
+         M1_MINDLESS|M1_OMNIVORE|M1_ACID|M1_POIS,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_GREEN),
+/*
+ * Quantum mechanics
+ */
+    MON("quantum mechanic", S_QUANTMECH,
+       LVL(7, 12, 3, 10, 0), (G_GENO|3),
+       A(ATTK(AT_CLAW, AD_TLPT, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 20, 0, MS_HUMANOID, MZ_HUMAN), MR_POISON, 0,
+       M1_HUMANOID|M1_OMNIVORE|M1_POIS|M1_TPORT, M2_HOSTILE, M3_INFRAVISIBLE,
+       CLR_CYAN),
+/*
+ * Rust monster or disenchanter
+ */
+    MON("rust monster", S_RUSTMONST,
+       LVL(5, 18, 2, 0, 0), (G_GENO|2),
+       A(ATTK(AT_TUCH, AD_RUST, 0, 0), ATTK(AT_TUCH, AD_RUST, 0, 0),
+         ATTK(AT_NONE, AD_RUST, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1000, 250, 0, MS_SILENT, MZ_MEDIUM), 0, 0,
+       M1_SWIM|M1_ANIMAL|M1_NOHANDS|M1_METALLIVORE, M2_HOSTILE,
+       M3_INFRAVISIBLE, CLR_BROWN),
+    MON("disenchanter", S_RUSTMONST,
+       LVL(12, 12, -10, 0, -3), (G_HELL|G_GENO|2),
+       A(ATTK(AT_CLAW, AD_ENCH, 4, 4), ATTK(AT_NONE, AD_ENCH, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(750, 200, 0, MS_GROWL, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_CARNIVORE, M2_HOSTILE,
+       M3_INFRAVISIBLE, CLR_BLUE),
+/*
+ * Snakes
+ */
+    MON("garter snake", S_SNAKE,
+       LVL(1, 8, 8, 0, 0), (G_LGROUP|G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 2),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(50, 60, 0, MS_HISS, MZ_TINY), 0, 0,
+       M1_SWIM|M1_CONCEAL|M1_NOLIMBS|M1_ANIMAL|M1_SLITHY|M1_OVIPAROUS|
+         M1_CARNIVORE|M1_NOTAKE,
+       0, 0, CLR_GREEN),
+    MON("snake", S_SNAKE,
+       LVL(4, 15, 3, 0, 0), (G_GENO|2),
+       A(ATTK(AT_BITE, AD_DRST, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(100, 80, 0, MS_HISS, MZ_SMALL), MR_POISON, MR_POISON,
+       M1_SWIM|M1_CONCEAL|M1_NOLIMBS|M1_ANIMAL|M1_SLITHY|M1_POIS|
+         M1_OVIPAROUS|M1_CARNIVORE|M1_NOTAKE,
+       M2_HOSTILE, 0, CLR_BROWN),
+    MON("water moccasin", S_SNAKE,
+       LVL(4, 15, 3, 0, 0), (G_GENO|G_NOGEN|G_LGROUP),
+       A(ATTK(AT_BITE, AD_DRST, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(150, 80, 0, MS_HISS, MZ_SMALL), MR_POISON, MR_POISON,
+       M1_SWIM|M1_CONCEAL|M1_NOLIMBS|M1_ANIMAL|M1_SLITHY|M1_POIS|
+         M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE,
+       M2_HOSTILE, 0, CLR_RED),
+    MON("pit viper", S_SNAKE,
+       LVL(6, 15, 2, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_DRST, 1, 4), ATTK(AT_BITE, AD_DRST, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(100, 60, 0, MS_HISS, MZ_MEDIUM),
+       MR_POISON, MR_POISON,
+       M1_SWIM|M1_CONCEAL|M1_NOLIMBS|M1_ANIMAL|M1_SLITHY|M1_POIS|
+         M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE,
+       M2_HOSTILE, M3_INFRAVISION, CLR_BLUE),
+    MON("python", S_SNAKE,
+       LVL(6, 3, 5, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 4), ATTK(AT_TUCH, AD_PHYS, 0, 0),
+         ATTK(AT_HUGS, AD_WRAP, 1, 4), ATTK(AT_HUGS, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(250, 100, 0, MS_HISS, MZ_LARGE), 0, 0,
+       M1_SWIM|M1_NOLIMBS|M1_ANIMAL|M1_SLITHY|
+         M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE,
+       M2_HOSTILE|M2_STRONG, M3_INFRAVISION, CLR_MAGENTA),
+    MON("cobra", S_SNAKE,
+       LVL(6, 18, 2, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_DRST, 2, 4), ATTK(AT_SPIT, AD_BLND, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(250, 100, 0, MS_HISS, MZ_MEDIUM),
+       MR_POISON, MR_POISON,
+       M1_SWIM|M1_CONCEAL|M1_NOLIMBS|M1_ANIMAL|M1_SLITHY|M1_POIS|
+         M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE,
+       M2_HOSTILE, 0, CLR_BLUE),
+/*
+ * Trolls
+ */
+    MON("troll", S_TROLL,
+       LVL(7, 12, 4, 0, -3), (G_GENO|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 4, 2), ATTK(AT_CLAW, AD_PHYS, 4, 2),
+         ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(800, 350, 0, MS_GRUNT, MZ_LARGE), 0, 0,
+       M1_HUMANOID|M1_REGEN|M1_CARNIVORE,
+       M2_STRONG|M2_STALK|M2_HOSTILE, M3_INFRAVISIBLE|M3_INFRAVISION,
+       CLR_BROWN),
+    MON("ice troll", S_TROLL,
+       LVL(9, 10, 2, 20, -3), (G_NOHELL|G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_COLD, 2, 6),
+         ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1000, 300, 0, MS_GRUNT, MZ_LARGE), MR_COLD, MR_COLD,
+       M1_HUMANOID|M1_REGEN|M1_CARNIVORE,
+       M2_STRONG|M2_STALK|M2_HOSTILE, M3_INFRAVISIBLE|M3_INFRAVISION,
+       CLR_WHITE),
+    MON("rock troll", S_TROLL,
+       LVL(9, 12, 0, 0, -3), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 2, 8),
+         ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1200, 300, 0, MS_GRUNT, MZ_LARGE), 0, 0,
+       M1_HUMANOID|M1_REGEN|M1_CARNIVORE,
+       M2_STRONG|M2_STALK|M2_HOSTILE|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_CYAN),
+    MON("water troll", S_TROLL,
+       LVL(11, 14, 4, 40, -3), (G_NOGEN|G_GENO),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_PHYS, 2, 8),
+         ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1200, 350, 0, MS_GRUNT, MZ_LARGE), 0, 0,
+       M1_HUMANOID|M1_REGEN|M1_CARNIVORE|M1_SWIM,
+       M2_STRONG|M2_STALK|M2_HOSTILE, M3_INFRAVISIBLE|M3_INFRAVISION,
+       CLR_BLUE),
+    MON("Olog-hai", S_TROLL,
+       LVL(13, 12, -4, 0, -7), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 2, 8),
+         ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 400, 0, MS_GRUNT, MZ_LARGE), 0, 0,
+       M1_HUMANOID|M1_REGEN|M1_CARNIVORE,
+       M2_STRONG|M2_STALK|M2_HOSTILE|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+/*
+ * Umber hulk
+ */
+    MON("umber hulk", S_UMBER,
+       LVL(9, 6, 2, 25, 0), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_CLAW, AD_PHYS, 3, 4),
+         ATTK(AT_BITE, AD_PHYS, 2, 5), ATTK(AT_GAZE, AD_CONF, 0, 0),
+         NO_ATTK, NO_ATTK),
+       SIZ(1200, 500, 0, MS_SILENT, MZ_LARGE), 0, 0,
+       M1_TUNNEL|M1_CARNIVORE, M2_STRONG, M3_INFRAVISIBLE, CLR_BROWN),
+/*
+ * Vampires
+ */
+    MON("vampire", S_VAMPIRE,
+       LVL(10, 12, 1, 25, -8), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_DRLI, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0,
+       M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN,
+       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY, M3_INFRAVISIBLE,
+       CLR_RED),
+    MON("vampire lord", S_VAMPIRE,
+       LVL(12, 14, 0, 50, -9), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_BITE, AD_DRLI, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0,
+       M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN,
+       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_LORD|M2_MALE,
+       M3_INFRAVISIBLE, CLR_BLUE),
+#if 0  /* DEFERRED */
+    MON("vampire mage", S_VAMPIRE,
+       LVL(20, 14, -4, 50, -9), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_DRLI, 2, 8), ATTK(AT_BITE, AD_DRLI, 1, 8),
+         ATTK(AT_MAGC, AD_SPEL, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0,
+       M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN,
+       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_LORD|M2_MALE|
+       M2_MAGIC, M3_INFRAVISIBLE, HI_ZAP),
+#endif
+    MON("Vlad the Impaler", S_VAMPIRE,
+       LVL(14, 18, -3, 80, -10), (G_NOGEN|G_NOCORPSE|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 10), ATTK(AT_BITE, AD_DRLI, 1, 10),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0,
+       M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN,
+       M2_NOPOLY|M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_PNAME|M2_STRONG|
+         M2_NASTY|M2_PRINCE|M2_MALE,
+       M3_WAITFORU|M3_WANTSCAND|M3_INFRAVISIBLE, HI_LORD),
+/*
+ * Wraiths
+ */
+    MON("barrow wight", S_WRAITH,
+       LVL(3, 12, 5, 5, -3), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_WEAP, AD_DRLI, 0, 0), ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1200, 0, 0, MS_SPELL, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_HUMANOID,
+       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_COLLECT, 0, CLR_GRAY),
+    MON("wraith", S_WRAITH,
+       LVL(6, 12, 4, 15, -6), (G_GENO|2),
+       A(ATTK(AT_TUCH, AD_DRLI, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(0, 0, 0, MS_SILENT, MZ_HUMAN),
+       MR_COLD|MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_BREATHLESS|M1_FLY|M1_HUMANOID|M1_UNSOLID,
+       M2_UNDEAD|M2_STALK|M2_HOSTILE, 0, CLR_BLACK),
+    MON("Nazgul", S_WRAITH,
+       LVL(13, 12, 0, 25, -17), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_WEAP, AD_DRLI, 1, 4), ATTK(AT_BREA, AD_SLEE, 2,25),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 0, 0, MS_SPELL, MZ_HUMAN),
+       MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_HUMANOID,
+       M2_NOPOLY|M2_UNDEAD|M2_STALK|M2_STRONG|M2_HOSTILE|M2_MALE|M2_COLLECT,
+       0, HI_LORD),
+/*
+ * Xorn
+ */
+    MON("xorn", S_XORN,
+       LVL(8, 9,-2, 20, 0), (G_GENO|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3),
+         ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 4, 6),
+         NO_ATTK, NO_ATTK),
+       SIZ(1200, 700, 0, MS_ROAR, MZ_MEDIUM),
+       MR_FIRE|MR_COLD|MR_STONE, MR_STONE,
+       M1_BREATHLESS|M1_WALLWALK|M1_THICK_HIDE|M1_METALLIVORE,
+       M2_HOSTILE|M2_STRONG, 0, CLR_BROWN),
+/*
+ * Apelike beasts
+ */
+    MON("monkey", S_YETI,
+       LVL(2, 12, 6, 0, 0), (G_GENO|1),
+       A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_BITE, AD_PHYS, 1, 3),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(100, 50, 0, MS_GROWL, MZ_SMALL), 0, 0,
+       M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE, 0, M3_INFRAVISIBLE, CLR_GRAY),
+    MON("ape", S_YETI,
+       LVL(4, 12, 6, 0, 0), (G_GENO|G_SGROUP|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3),
+         ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1100, 500, 0, MS_GROWL, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE, M2_STRONG, M3_INFRAVISIBLE,
+       CLR_BROWN),
+    MON("owlbear", S_YETI,
+       LVL(5, 12, 5, 0, 0), (G_GENO|3),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6),
+         ATTK(AT_HUGS, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1700, 700, 0, MS_ROAR, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE,
+       M2_HOSTILE|M2_STRONG|M2_NASTY, M3_INFRAVISIBLE, CLR_BROWN),
+    MON("yeti", S_YETI,
+       LVL(5, 15, 6, 0, 0), (G_GENO|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6),
+         ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1600, 700, 0, MS_GROWL, MZ_LARGE), MR_COLD, MR_COLD,
+       M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE, M2_HOSTILE|M2_STRONG,
+       M3_INFRAVISIBLE, CLR_WHITE),
+    MON("carnivorous ape", S_YETI,
+       LVL(6, 12, 6, 0, 0), (G_GENO|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         ATTK(AT_HUGS, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1250, 550, 0, MS_GROWL, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE, M2_HOSTILE|M2_STRONG,
+       M3_INFRAVISIBLE, CLR_BLACK),
+    MON("sasquatch", S_YETI,
+       LVL(7, 15, 6, 0, 2), (G_GENO|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6),
+         ATTK(AT_KICK, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1550, 750, 0, MS_GROWL, MZ_LARGE), 0, 0,
+       M1_ANIMAL|M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE, M2_STRONG,
+       M3_INFRAVISIBLE, CLR_GRAY),
+/*
+ * Zombies
+ */
+    MON("kobold zombie", S_ZOMBIE,
+       LVL(0, 6, 10, 0, -2), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(400, 50, 0, MS_SILENT, MZ_SMALL), MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS,
+       M2_UNDEAD|M2_STALK|M2_HOSTILE, M3_INFRAVISION, CLR_BROWN),
+    MON("gnome zombie", S_ZOMBIE,
+       LVL(1, 6, 10, 0, -2), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 5),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(650, 50, 0, MS_SILENT, MZ_SMALL), MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS,
+       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_GNOME, M3_INFRAVISION, CLR_BROWN),
+    MON("orc zombie", S_ZOMBIE,
+       LVL(2, 6, 9, 0, -3), (G_GENO|G_SGROUP|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(850, 75, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS,
+       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_ORC, M3_INFRAVISION, CLR_GRAY),
+    MON("dwarf zombie", S_ZOMBIE,
+       LVL(2, 6, 9, 0, -3), (G_GENO|G_SGROUP|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(900, 150, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS,
+       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_DWARF, M3_INFRAVISION, CLR_RED),
+    MON("elf zombie", S_ZOMBIE,
+       LVL(3, 6, 9, 0, -3), (G_GENO|G_SGROUP|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 7),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_ELF, 175, 0, MS_SILENT, MZ_HUMAN),
+       MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID,
+       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_ELF, M3_INFRAVISION, CLR_GREEN),
+    MON("human zombie", S_ZOMBIE,
+       LVL(4, 6, 8, 0, -3), (G_GENO|G_SGROUP|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 200, 0, MS_SILENT, MZ_HUMAN),
+       MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID,
+       M2_UNDEAD|M2_STALK|M2_HOSTILE, M3_INFRAVISION, HI_DOMESTIC),
+    MON("ettin zombie", S_ZOMBIE,
+       LVL(6, 8, 6, 0, -4), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1,10), ATTK(AT_CLAW, AD_PHYS, 1,10),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1700, 250, 0, MS_SILENT, MZ_HUGE),
+       MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID,
+       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG, M3_INFRAVISION, CLR_BLUE),
+    MON("giant zombie", S_ZOMBIE,
+       LVL(8, 8, 6, 0, -4), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_PHYS, 2, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2050, 375, 0, MS_SILENT, MZ_HUGE),
+       MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID,
+       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_GIANT|M2_STRONG, M3_INFRAVISION,
+       CLR_CYAN),
+    MON("ghoul", S_ZOMBIE,
+       LVL(3, 6, 10, 0, -2), (G_GENO|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PLYS, 1, 2), ATTK(AT_CLAW, AD_PHYS, 1, 3),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(400, 50, 0, MS_SILENT, MZ_SMALL),
+       MR_COLD|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS,
+       M2_UNDEAD|M2_WANDER|M2_HOSTILE, M3_INFRAVISION, CLR_BLACK),
+    MON("skeleton", S_ZOMBIE,
+       LVL(12, 8, 4, 0, 0), (G_NOCORPSE|G_NOGEN),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_TUCH, AD_SLOW, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(300, 5, 0, MS_BONES, MZ_HUMAN),
+       MR_COLD|MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE,
+       M2_UNDEAD|M2_WANDER|M2_HOSTILE|M2_STRONG|M2_COLLECT|M2_NASTY,
+       M3_INFRAVISION, CLR_WHITE),
+/*
+ * golems
+ */
+    MON("straw golem", S_GOLEM,
+       LVL(3, 12, 10, 0, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 2), ATTK(AT_CLAW, AD_PHYS, 1, 2),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(400, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_YELLOW),
+    MON("paper golem", S_GOLEM,
+       LVL(3, 12, 10, 0, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 3),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(400, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID,
+       M2_HOSTILE|M2_NEUTER, 0, HI_PAPER),
+    MON("rope golem", S_GOLEM,
+       LVL(4, 9, 8, 0, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         ATTK(AT_HUGS, AD_PHYS, 6, 1), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(450, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID,
+       M2_HOSTILE|M2_NEUTER, 0, CLR_BROWN),
+    MON("gold golem", S_GOLEM,
+       LVL(5, 9, 6, 0, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 3), ATTK(AT_CLAW, AD_PHYS, 2, 3),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(450, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON|MR_ACID, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE,
+       M2_HOSTILE|M2_NEUTER, 0, HI_GOLD),
+    MON("leather golem", S_GOLEM,
+       LVL(6, 6, 6, 0, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(800, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID,
+       M2_HOSTILE|M2_NEUTER, 0, HI_LEATHER),
+    MON("wood golem", S_GOLEM,
+       LVL(7, 3, 4, 0, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 3, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(900, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE,
+       M2_HOSTILE|M2_NEUTER, 0, HI_WOOD),
+    MON("flesh golem", S_GOLEM,
+       LVL(9, 8, 9, 30, 0), (1),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_PHYS, 2, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1400, 600, 0, MS_SILENT, MZ_LARGE),
+       MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON,
+       MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID,
+       M2_HOSTILE|M2_STRONG, 0, CLR_RED),
+    MON("clay golem", S_GOLEM,
+       LVL(11, 7, 7, 40, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 3,10),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1550, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE,
+       M2_HOSTILE|M2_STRONG, 0, CLR_BROWN),
+    MON("stone golem", S_GOLEM,
+       LVL(14, 6, 5, 50, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 3, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1900, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE,
+       M2_HOSTILE|M2_STRONG, 0, CLR_GRAY),
+    MON("glass golem", S_GOLEM,
+       LVL(16, 6, 1, 50, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_PHYS, 2, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1800, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON|MR_ACID, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE,
+       M2_HOSTILE|M2_STRONG, 0, CLR_CYAN),
+    MON("iron golem", S_GOLEM,
+       LVL(18, 6, 3, 60, 0), (G_NOCORPSE|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 4,10), ATTK(AT_BREA, AD_DRST, 4, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2000, 0, 0, MS_SILENT, MZ_LARGE),
+       MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON, 0,
+       M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE|M1_POIS,
+       M2_HOSTILE|M2_STRONG|M2_COLLECT, 0, HI_METAL),
+/*
+ * humans, including elves and were-critters
+ */
+    MON("human", S_HUMAN,
+       LVL(0, 12, 10, 0, 0), G_NOGEN,          /* for corpses */
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT,
+       M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("wererat", S_HUMAN,
+       LVL(2, 12, 10, 10, -7), (1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_WERE, MZ_HUMAN), MR_POISON, 0,
+       M1_HUMANOID|M1_POIS|M1_REGEN|M1_OMNIVORE,
+       M2_NOPOLY|M2_WERE|M2_HOSTILE|M2_HUMAN|M2_COLLECT, M3_INFRAVISIBLE,
+       CLR_BROWN),
+    MON("werejackal", S_HUMAN,
+       LVL(2, 12, 10, 10, -7), (1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_WERE, MZ_HUMAN), MR_POISON, 0,
+       M1_HUMANOID|M1_POIS|M1_REGEN|M1_OMNIVORE,
+       M2_NOPOLY|M2_WERE|M2_HOSTILE|M2_HUMAN|M2_COLLECT, M3_INFRAVISIBLE,
+       CLR_RED),
+    MON("werewolf", S_HUMAN,
+       LVL(5, 12, 10, 20, -7), (1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_WERE, MZ_HUMAN), MR_POISON, 0,
+       M1_HUMANOID|M1_POIS|M1_REGEN|M1_OMNIVORE,
+       M2_NOPOLY|M2_WERE|M2_HOSTILE|M2_HUMAN|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_ORANGE),
+    MON("elf", S_HUMAN,
+       LVL(10, 12, 10, 2, -3), G_NOGEN,                /* for corpses */
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_ELF, 350, 0, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP,
+       M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS,
+       M2_NOPOLY|M2_ELF|M2_STRONG|M2_COLLECT, M3_INFRAVISION|M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("Woodland-elf", S_HUMAN,
+       LVL(4, 12, 10, 10, -5), (G_GENO|G_SGROUP|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_ELF, 350, 0, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP,
+       M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS,
+       M2_ELF|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GREEN),
+    MON("Green-elf", S_HUMAN,
+       LVL(5, 12, 10, 10, -6), (G_GENO|G_SGROUP|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_ELF, 350, 0, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP,
+       M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS,
+       M2_ELF|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BRIGHT_GREEN),
+    MON("Grey-elf", S_HUMAN,
+       LVL(6, 12, 10, 10, -7), (G_GENO|G_SGROUP|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_ELF, 350, 0, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP,
+       M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS,
+       M2_ELF|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY),
+    MON("elf-lord", S_HUMAN,
+       LVL(8, 12, 10, 20, -9), (G_GENO|G_SGROUP|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_ELF, 350, 0, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP,
+       M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS,
+       M2_ELF|M2_STRONG|M2_LORD|M2_MALE|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BRIGHT_BLUE),
+    MON("Elvenking", S_HUMAN,
+       LVL(9, 12, 10, 25, -10), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_ELF, 350, 0, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP,
+       M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS,
+       M2_ELF|M2_STRONG|M2_PRINCE|M2_MALE|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+    MON("doppelganger", S_HUMAN,
+       LVL(9, 12, 5, 20, 0), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 12),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_IMITATE, MZ_HUMAN), MR_SLEEP, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_HOSTILE|M2_STRONG|M2_COLLECT,
+       M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("nurse", S_HUMAN,
+       LVL(11, 6, 0, 0, 0), (G_GENO|3),
+       A(ATTK(AT_CLAW, AD_HEAL, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_NURSE, MZ_HUMAN), MR_POISON, MR_POISON,
+       M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_HOSTILE,
+       M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("shopkeeper", S_HUMAN,
+       LVL(12, 18, 0, 50, 0), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 4, 4), ATTK(AT_WEAP, AD_PHYS, 4, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, sizeof(struct eshk), MS_SELL, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT|M2_MAGIC,
+       M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("guard", S_HUMAN,
+       LVL(12, 12, 10, 40, 10), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 4,10),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, sizeof(struct egd), MS_GUARD, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_MERC|M2_PEACEFUL|M2_STRONG|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_BLUE),
+    MON("prisoner", S_HUMAN,
+       LVL(12, 12, 10, 0, 0), G_NOGEN,          /* for special levels */
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_DJINNI, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_CLOSE, HI_DOMESTIC),
+    MON("Oracle", S_HUMAN,
+       LVL(12, 0, 0, 50, 0), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_NONE, AD_MAGM, 0, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_ORACLE, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_FEMALE, M3_INFRAVISIBLE, HI_ZAP),
+    MON("aligned priest", S_HUMAN,
+       LVL(12, 12, 10, 50, 0), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 4,10), ATTK(AT_KICK, AD_PHYS, 1, 4),
+         ATTK(AT_MAGC, AD_CLRC, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, sizeof(struct epri), MS_PRIEST, MZ_HUMAN),
+       MR_ELEC, 0, M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_LORD|M2_PEACEFUL|M2_COLLECT, M3_INFRAVISIBLE,
+       CLR_WHITE),
+    MON("high priest", S_HUMAN,
+       LVL(25, 15, 7, 70, 0), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 4,10), ATTK(AT_KICK, AD_PHYS, 2, 8),
+         ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, sizeof(struct epri), MS_PRIEST, MZ_HUMAN),
+       MR_FIRE|MR_ELEC|MR_SLEEP|MR_POISON, 0,
+       M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_MINION|M2_PRINCE|M2_NASTY|M2_COLLECT|M2_MAGIC,
+       M3_INFRAVISIBLE, CLR_WHITE),
+    MON("soldier", S_HUMAN,
+       LVL(6, 10, 10, 0, -2), (G_SGROUP|G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SOLDIER, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_MERC|M2_STALK|M2_HOSTILE|M2_STRONG|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_GRAY),
+    MON("sergeant", S_HUMAN,
+       LVL(8, 10, 10, 5, -3), (G_SGROUP|G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SOLDIER, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_MERC|M2_STALK|M2_HOSTILE|M2_STRONG|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_RED),
+    MON("lieutenant", S_HUMAN,
+       LVL(10, 10, 10, 15, -4), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 3, 4), ATTK(AT_WEAP, AD_PHYS, 3, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SOLDIER, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_MERC|M2_STALK|M2_HOSTILE|M2_STRONG|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_GREEN),
+    MON("captain", S_HUMAN,
+       LVL(12, 10, 10, 15, -5), (G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 4, 4), ATTK(AT_WEAP, AD_PHYS, 4, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SOLDIER, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_MERC|M2_STALK|M2_HOSTILE|M2_STRONG|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_BLUE),
+       /* Keep these separate - some of the mkroom code assumes that
+        * all the soldiers are contiguous.
+        */
+    MON("watchman", S_HUMAN,
+       LVL(6, 10, 10, 0, -2), (G_SGROUP|G_NOGEN|G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SOLDIER, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_MERC|M2_STALK|M2_PEACEFUL|M2_STRONG|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_GRAY),
+    MON("watch captain", S_HUMAN,
+       LVL(10, 10, 10, 15, -4), (G_NOGEN|G_GENO|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 3, 4), ATTK(AT_WEAP, AD_PHYS, 3, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SOLDIER, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_MERC|M2_STALK|M2_PEACEFUL|M2_STRONG|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_GREEN),
+       /* Unique humans not tied to quests.
+        */
+    MON("Medusa", S_HUMAN,
+       LVL(20, 12, 2, 50, -15), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 1, 8),
+         ATTK(AT_GAZE, AD_STON, 0, 0), ATTK(AT_BITE, AD_DRST, 1, 6),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HISS, MZ_LARGE),
+       MR_POISON|MR_STONE, MR_POISON|MR_STONE,
+       M1_FLY|M1_SWIM|M1_AMPHIBIOUS|M1_HUMANOID|M1_POIS|M1_OMNIVORE,
+       M2_NOPOLY|M2_HOSTILE|M2_STRONG|M2_PNAME|M2_FEMALE,
+       M3_WAITFORU|M3_INFRAVISIBLE, CLR_BRIGHT_GREEN),
+    MON("Wizard of Yendor", S_HUMAN,
+       LVL(30, 12, -8, 100, A_NONE), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_CLAW, AD_SAMU, 2,12), ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_CUSS, MZ_HUMAN),
+       MR_FIRE|MR_POISON, MR_FIRE|MR_POISON,
+       M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_REGEN|M1_SEE_INVIS|M1_TPORT|
+         M1_TPORT_CNTRL|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_HOSTILE|M2_STRONG|M2_NASTY|
+         M2_PRINCE|M2_MALE|M2_MAGIC,
+       M3_COVETOUS|M3_WAITFORU|M3_INFRAVISIBLE, HI_LORD),
+    MON("Croesus", S_HUMAN,
+       LVL(20, 15, 0, 40, 15), (G_UNIQ|G_NOGEN),
+       A(ATTK(AT_WEAP, AD_PHYS, 4,10),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARD, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_PNAME|
+         M2_PRINCE|M2_MALE|M2_GREEDY|M2_JEWELS|M2_COLLECT|M2_MAGIC,
+       M3_INFRAVISIBLE, HI_LORD),
+#ifdef CHARON
+    MON("Charon", S_HUMAN,
+       LVL(76, 18, -5, 120, 0), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_TUCH, AD_PLYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_FERRY, MZ_HUMAN),
+       MR_FIRE|MR_COLD|MR_POISON|MR_STONE, 0,
+       M1_BREATHLESS|M1_SEE_INVIS|M1_HUMANOID,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_PNAME|M2_MALE|M2_GREEDY|M2_COLLECT,
+       M3_INFRAVISIBLE, CLR_WHITE),
+#endif
+/*
+ * ghosts
+ */
+    MON("ghost", S_GHOST,
+       LVL(10, 3, -5, 50, -5), (G_NOCORPSE|G_NOGEN),
+       A(ATTK(AT_TUCH, AD_PHYS, 1, 1),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 0, 0, MS_SILENT, MZ_HUMAN),
+       MR_COLD|MR_DISINT|MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_FLY|M1_BREATHLESS|M1_WALLWALK|M1_HUMANOID|M1_UNSOLID,
+       M2_NOPOLY|M2_UNDEAD|M2_STALK|M2_HOSTILE, M3_INFRAVISION, CLR_GRAY),
+    MON("shade", S_GHOST,
+       LVL(12, 10, 10, 0, 0), (G_NOCORPSE|G_NOGEN),
+       A(ATTK(AT_TUCH, AD_PLYS, 2, 6), ATTK(AT_TUCH, AD_SLOW, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 0, 0, MS_WAIL, MZ_HUMAN),
+       MR_COLD|MR_DISINT|MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_FLY|M1_BREATHLESS|M1_WALLWALK|M1_HUMANOID|M1_UNSOLID|M1_SEE_INVIS,
+       M2_NOPOLY|M2_UNDEAD|M2_WANDER|M2_STALK|M2_HOSTILE|M2_NASTY,
+       M3_INFRAVISION, CLR_BLACK),
+/*
+ * (major) demons
+ */
+    MON("water demon", S_DEMON,
+       LVL(8, 12,-4, 30, -7), (G_NOCORPSE|G_NOGEN),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3),
+         ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_DJINNI, MZ_HUMAN), MR_FIRE|MR_POISON, 0,
+       M1_HUMANOID|M1_POIS|M1_SWIM,
+       M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLUE),
+       /* standard demons & devils
+        */
+    MON("horned devil", S_DEMON,
+       LVL(6, 9, -5, 50, 11), (G_HELL|G_NOCORPSE|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         ATTK(AT_BITE, AD_PHYS, 2, 3), ATTK(AT_STNG, AD_PHYS, 1, 3),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_HUMAN), MR_FIRE|MR_POISON, 0,
+       M1_POIS|M1_THICK_HIDE,
+       M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION,
+       CLR_BROWN),
+#ifdef SEDUCE
+# define SEDUCTION_ATTACKS \
+       A(ATTK(AT_BITE, AD_SSEX, 0, 0), ATTK(AT_CLAW, AD_PHYS, 1, 3), \
+         ATTK(AT_CLAW, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK)
+#else
+# define SEDUCTION_ATTACKS \
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), \
+         ATTK(AT_BITE, AD_DRLI, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK)
+#endif
+    MON("succubus", S_DEMON,
+       LVL(6, 12, 0, 70, -9), (G_NOCORPSE|1),
+       SEDUCTION_ATTACKS,
+       SIZ(WT_HUMAN, 400, 0, MS_SEDUCE, MZ_HUMAN), MR_FIRE|MR_POISON, 0,
+       M1_HUMANOID|M1_FLY|M1_POIS,
+       M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY|M2_FEMALE,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY),
+    MON("incubus", S_DEMON,
+       LVL(6, 12, 0, 70, -9), (G_NOCORPSE|1),
+       SEDUCTION_ATTACKS,
+       SIZ(WT_HUMAN, 400, 0, MS_SEDUCE, MZ_HUMAN), MR_FIRE|MR_POISON, 0,
+       M1_HUMANOID|M1_FLY|M1_POIS,
+       M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY|M2_MALE,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY),
+#undef SEDUCTION_ATTACKS
+    /* Used by AD&D for a type of demon, originally one of the Furies */
+    /* and spelled this way */
+    MON("erinys", S_DEMON,
+       LVL(7, 12, 2, 30, 10), (G_HELL|G_NOCORPSE|G_SGROUP|2),
+       A(ATTK(AT_WEAP, AD_DRST, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_HUMAN), MR_FIRE|MR_POISON, 0,
+       M1_HUMANOID|M1_POIS,
+       M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_FEMALE|
+         M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("barbed devil", S_DEMON,
+       LVL(8, 12, 0, 35, 8), (G_HELL|G_NOCORPSE|G_SGROUP|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4),
+         ATTK(AT_STNG, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_HUMAN), MR_FIRE|MR_POISON, 0,
+       M1_POIS|M1_THICK_HIDE, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("marilith", S_DEMON,
+       LVL(7, 12, -6, 80, -12), (G_HELL|G_NOCORPSE|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4),
+         ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4)),
+       SIZ(WT_HUMAN, 400, 0, MS_CUSS, MZ_LARGE), MR_FIRE|MR_POISON, 0,
+       M1_HUMANOID|M1_SLITHY|M1_SEE_INVIS|M1_POIS,
+       M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY|M2_FEMALE|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("vrock", S_DEMON,
+       LVL(8, 12, 0, 50, -9), (G_HELL|G_NOCORPSE|G_SGROUP|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_CLAW, AD_PHYS, 1, 8),
+         ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_LARGE), MR_FIRE|MR_POISON, 0,
+       M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("hezrou", S_DEMON,
+       LVL(9, 6, -2, 55, -10), (G_HELL|G_NOCORPSE|G_SGROUP|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3),
+         ATTK(AT_BITE, AD_PHYS, 4, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_LARGE), MR_FIRE|MR_POISON, 0,
+       M1_HUMANOID|M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("bone devil", S_DEMON,
+       LVL(9, 15, -1, 40, -9), (G_HELL|G_NOCORPSE|G_SGROUP|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 3, 4), ATTK(AT_STNG, AD_DRST, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_LARGE), MR_FIRE|MR_POISON, 0,
+       M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY),
+    MON("ice devil", S_DEMON,
+       LVL(11, 6, -4, 55, -12), (G_HELL|G_NOCORPSE|2),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_STNG, AD_COLD, 3, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_LARGE),
+       MR_FIRE|MR_COLD|MR_POISON, 0, M1_SEE_INVIS|M1_POIS,
+       M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION,
+       CLR_WHITE),
+    MON("nalfeshnee", S_DEMON,
+       LVL(11, 9, -1, 65, -11), (G_HELL|G_NOCORPSE|1),
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4),
+         ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SPELL, MZ_LARGE), MR_FIRE|MR_POISON, 0,
+       M1_HUMANOID|M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("pit fiend", S_DEMON,
+       LVL(13, 6, -3, 65, -13), (G_HELL|G_NOCORPSE|2),
+       A(ATTK(AT_WEAP, AD_PHYS, 4, 2), ATTK(AT_WEAP, AD_PHYS, 4, 2),
+         ATTK(AT_HUGS, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GROWL, MZ_LARGE), MR_FIRE|MR_POISON, 0,
+       M1_SEE_INVIS|M1_POIS,
+       M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+    MON("balrog", S_DEMON,
+       LVL(16, 5, -2, 75, -14), (G_HELL|G_NOCORPSE|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 8, 4), ATTK(AT_WEAP, AD_PHYS, 4, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_LARGE), MR_FIRE|MR_POISON, 0,
+       M1_FLY|M1_SEE_INVIS|M1_POIS,
+       M2_DEMON|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED),
+       /* Named demon lords & princes plus Arch-Devils.
+        * (their order matters; see minion.c)
+        */
+    MON("Juiblex", S_DEMON,
+       LVL(50, 3, -7, 65, -15), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ),
+       A(ATTK(AT_ENGL, AD_DISE, 4,10), ATTK(AT_SPIT, AD_ACID, 3, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 0, 0, MS_GURGLE, MZ_LARGE),
+       MR_FIRE|MR_POISON|MR_ACID|MR_STONE, 0,
+       M1_AMPHIBIOUS|M1_AMORPHOUS|M1_NOHEAD|M1_FLY|M1_SEE_INVIS|M1_ACID|
+         M1_POIS,
+       M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY|M2_LORD|
+         M2_MALE,
+       M3_WAITFORU|M3_WANTSAMUL|M3_INFRAVISION, CLR_BRIGHT_GREEN),
+    MON("Yeenoghu", S_DEMON,
+       LVL(56, 18, -5, 80, -15), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 3, 6), ATTK(AT_WEAP, AD_CONF, 2, 8),
+         ATTK(AT_CLAW, AD_PLYS, 1, 6), ATTK(AT_MAGC, AD_MAGM, 2, 6),
+         NO_ATTK, NO_ATTK),
+       SIZ(900, 500, 0, MS_ORC, MZ_LARGE), MR_FIRE|MR_POISON, 0,
+       M1_FLY|M1_SEE_INVIS|M1_POIS,
+       M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY|M2_LORD|
+         M2_MALE|M2_COLLECT,
+       M3_WANTSAMUL|M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+    MON("Orcus", S_DEMON,
+       LVL(66, 9, -6, 85, -20), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 3, 4),
+         ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_MAGC, AD_SPEL, 8, 6),
+         ATTK(AT_STNG, AD_DRST, 2, 4), NO_ATTK),
+       SIZ(1500, 500, 0, MS_ORC, MZ_HUGE), MR_FIRE|MR_POISON, 0,
+       M1_FLY|M1_SEE_INVIS|M1_POIS,
+       M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY|M2_PRINCE|
+         M2_MALE|M2_COLLECT,
+       M3_WAITFORU|M3_WANTSBOOK|M3_WANTSAMUL|M3_INFRAVISIBLE|M3_INFRAVISION,
+       HI_LORD),
+    MON("Geryon", S_DEMON,
+       LVL(72, 3, -3, 75, 15), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ),
+       A(ATTK(AT_CLAW, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 3, 6),
+         ATTK(AT_STNG, AD_DRST, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_BRIBE, MZ_HUGE), MR_FIRE|MR_POISON, 0,
+       M1_FLY|M1_SEE_INVIS|M1_POIS|M1_SLITHY,
+       M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY|
+         M2_PRINCE|M2_MALE,
+       M3_WANTSAMUL|M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+    MON("Dispater", S_DEMON,
+       LVL(78, 15, -2, 80, 15), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 4, 6), ATTK(AT_MAGC, AD_SPEL, 6, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_BRIBE, MZ_HUMAN), MR_FIRE|MR_POISON, 0,
+       M1_FLY|M1_SEE_INVIS|M1_POIS|M1_HUMANOID,
+       M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY|
+         M2_PRINCE|M2_MALE|M2_COLLECT,
+       M3_WANTSAMUL|M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+    MON("Baalzebub", S_DEMON,
+       LVL(89, 9, -5, 85, 20), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ),
+       A(ATTK(AT_BITE, AD_DRST, 2, 6), ATTK(AT_GAZE, AD_STUN, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_BRIBE, MZ_LARGE), MR_FIRE|MR_POISON, 0,
+       M1_FLY|M1_SEE_INVIS|M1_POIS,
+       M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY|
+         M2_PRINCE|M2_MALE,
+       M3_WANTSAMUL|M3_WAITFORU|M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+    MON("Asmodeus", S_DEMON,
+       LVL(105, 12, -7, 90, 20), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ),
+       A(ATTK(AT_CLAW, AD_PHYS, 4, 4), ATTK(AT_MAGC, AD_COLD, 6, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_BRIBE, MZ_HUGE), MR_FIRE|MR_COLD|MR_POISON, 0,
+       M1_FLY|M1_SEE_INVIS|M1_HUMANOID|M1_POIS,
+       M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_STRONG|
+         M2_NASTY|M2_PRINCE|M2_MALE,
+       M3_WANTSAMUL|M3_WAITFORU|M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+    MON("Demogorgon", S_DEMON,
+       LVL(106, 15, -8, 95, -20), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ),
+       A(ATTK(AT_MAGC, AD_SPEL, 8, 6), ATTK(AT_STNG, AD_DRLI, 1, 4),
+         ATTK(AT_CLAW, AD_DISE, 1, 6), ATTK(AT_CLAW, AD_DISE, 1, 6),
+         NO_ATTK, NO_ATTK),
+       SIZ(1500, 500, 0, MS_GROWL, MZ_HUGE), MR_FIRE|MR_POISON, 0,
+       M1_FLY|M1_SEE_INVIS|M1_NOHANDS|M1_POIS,
+       M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY|
+         M2_PRINCE|M2_MALE,
+       M3_WANTSAMUL|M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+       /* Riders -- the Four Horsemen of the Apocalypse ("War" == player)
+        */
+    MON("Death", S_DEMON,
+       LVL(30, 12, -5, 100, 0), (G_UNIQ|G_NOGEN),
+       A(ATTK(AT_TUCH, AD_DETH, 8, 8), ATTK(AT_TUCH, AD_DETH, 8, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 1, 0, MS_RIDER, MZ_HUMAN),
+       MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_FLY|M1_HUMANOID|M1_REGEN|M1_SEE_INVIS|M1_TPORT_CNTRL,
+       M2_NOPOLY|M2_STALK|M2_HOSTILE|M2_PNAME|M2_STRONG|M2_NASTY,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+    MON("Pestilence", S_DEMON,
+       LVL(30, 12, -5, 100, 0), (G_UNIQ|G_NOGEN),
+       A(ATTK(AT_TUCH, AD_PEST, 8, 8), ATTK(AT_TUCH, AD_PEST, 8, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 1, 0, MS_RIDER, MZ_HUMAN),
+       MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_FLY|M1_HUMANOID|M1_REGEN|M1_SEE_INVIS|M1_TPORT_CNTRL,
+       M2_NOPOLY|M2_STALK|M2_HOSTILE|M2_PNAME|M2_STRONG|M2_NASTY,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+    MON("Famine", S_DEMON,
+       LVL(30, 12, -5, 100, 0), (G_UNIQ|G_NOGEN),
+       A(ATTK(AT_TUCH, AD_FAMN, 8, 8), ATTK(AT_TUCH, AD_FAMN, 8, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 1, 0, MS_RIDER, MZ_HUMAN),
+       MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_FLY|M1_HUMANOID|M1_REGEN|M1_SEE_INVIS|M1_TPORT_CNTRL,
+       M2_NOPOLY|M2_STALK|M2_HOSTILE|M2_PNAME|M2_STRONG|M2_NASTY,
+       M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD),
+       /* other demons
+        */
+#ifdef MAIL
+    MON("mail daemon", S_DEMON,
+       LVL(56, 24, 10, 127, 0), (G_NOGEN|G_NOCORPSE),
+       A(NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(600, 300, 0, MS_SILENT, MZ_HUMAN),
+       MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON|MR_STONE, 0,
+       M1_FLY|M1_SWIM|M1_BREATHLESS|M1_SEE_INVIS|M1_HUMANOID|M1_POIS,
+       M2_NOPOLY|M2_STALK|M2_PEACEFUL, M3_INFRAVISIBLE|M3_INFRAVISION,
+       CLR_BRIGHT_BLUE),
+#endif
+    MON("djinni", S_DEMON,
+       LVL(7, 12, 4, 30, 0), (G_NOGEN|G_NOCORPSE),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 400, 0, MS_DJINNI, MZ_HUMAN), MR_POISON|MR_STONE, 0,
+       M1_HUMANOID|M1_FLY|M1_POIS,
+       M2_NOPOLY|M2_STALK|M2_COLLECT, M3_INFRAVISIBLE, CLR_YELLOW),
+    MON("sandestin", S_DEMON,
+       LVL(13, 12, 4, 60, -5), (G_HELL|G_NOCORPSE|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1500, 400, 0, MS_CUSS, MZ_HUMAN), MR_STONE, 0,
+       M1_HUMANOID, M2_NOPOLY|M2_STALK|M2_STRONG|M2_COLLECT,
+       M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY),
+/*
+ * sea monsters
+ */
+    MON("jellyfish", S_EEL,
+       LVL(3, 3, 6, 0, 0), (G_GENO|G_NOGEN),
+       A(ATTK(AT_STNG, AD_DRST, 3, 3), NO_ATTK,
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(80, 20, 0, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON,
+       M1_SWIM|M1_AMPHIBIOUS|M1_SLITHY|M1_NOLIMBS|M1_NOTAKE|M1_POIS,
+       M2_HOSTILE, 0, CLR_BLUE),
+    MON("piranha", S_EEL,
+       LVL(5, 12, 4, 0, 0), (G_GENO|G_NOGEN|G_SGROUP),
+       A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK,
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(60, 30, 0, MS_SILENT, MZ_SMALL), 0, 0,
+       M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_SLITHY|M1_NOLIMBS|
+         M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE,
+       M2_HOSTILE, 0, CLR_RED),
+    MON("shark", S_EEL,
+       LVL(7, 12, 2, 0, 0), (G_GENO|G_NOGEN),
+       A(ATTK(AT_BITE, AD_PHYS, 5, 6), NO_ATTK,
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(500, 350, 0, MS_SILENT, MZ_LARGE), 0, 0,
+       M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_SLITHY|M1_NOLIMBS|
+         M1_CARNIVORE|M1_OVIPAROUS|M1_THICK_HIDE|M1_NOTAKE,
+       M2_HOSTILE, 0, CLR_GRAY),
+    MON("giant eel", S_EEL,
+       LVL(5, 9, -1, 0, 0), (G_GENO|G_NOGEN),
+       A(ATTK(AT_BITE, AD_PHYS, 3, 6), ATTK(AT_TUCH, AD_WRAP, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(200, 250, 0, MS_SILENT, MZ_HUGE), 0, 0,
+       M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_SLITHY|M1_NOLIMBS|
+         M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE,
+       M2_HOSTILE, M3_INFRAVISIBLE, CLR_CYAN),
+    MON("electric eel", S_EEL,
+       LVL(7, 10, -3, 0, 0), (G_GENO|G_NOGEN),
+       A(ATTK(AT_BITE, AD_ELEC, 4, 6), ATTK(AT_TUCH, AD_WRAP, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(200, 250, 0, MS_SILENT, MZ_HUGE), MR_ELEC, MR_ELEC,
+       M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_SLITHY|M1_NOLIMBS|
+         M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE,
+       M2_HOSTILE, M3_INFRAVISIBLE, CLR_BRIGHT_BLUE),
+    MON("kraken", S_EEL,
+       LVL(20, 3, 6, 0, -3), (G_GENO|G_NOGEN),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4),
+         ATTK(AT_HUGS, AD_WRAP, 2, 6), ATTK(AT_BITE, AD_PHYS, 5, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(1800, 1000, 0, MS_SILENT, MZ_HUGE), 0, 0,
+       M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,
+       M2_NOPOLY|M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_RED),
+/*
+ * lizards, &c
+ */
+    MON("newt", S_LIZARD,
+       LVL(0, 6, 8, 0, 0), (G_GENO|5),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 2),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(10, 20, 0, MS_SILENT, MZ_TINY), 0, 0,
+       M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,
+       M2_HOSTILE, 0, CLR_YELLOW),
+    MON("gecko", S_LIZARD,
+       LVL(1, 6, 8, 0, 0), (G_GENO|5),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 3),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(10, 20, 0, MS_SQEEK, MZ_TINY), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_GREEN),
+    MON("iguana", S_LIZARD,
+       LVL(2, 6, 7, 0, 0), (G_GENO|5),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(30, 30, 0, MS_SILENT, MZ_TINY), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_BROWN),
+    MON("baby crocodile", S_LIZARD,
+       LVL(3, 6, 7, 0, 0), G_GENO,
+       A(ATTK(AT_BITE, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(200, 200, 0, MS_SILENT, MZ_MEDIUM), 0, 0,
+       M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,
+       M2_HOSTILE, 0, CLR_BROWN),
+    MON("lizard", S_LIZARD,
+       LVL(5, 6, 6, 10, 0), (G_GENO|5),
+       A(ATTK(AT_BITE, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(10, 40, 0, MS_SILENT, MZ_TINY), MR_STONE, MR_STONE,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_GREEN),
+    MON("chameleon", S_LIZARD,
+       LVL(6, 5, 6, 10, 0), (G_GENO|2),
+       A(ATTK(AT_BITE, AD_PHYS, 4, 2),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(100, 100, 0, MS_SILENT, MZ_TINY), 0, 0,
+       M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_NOPOLY|M2_HOSTILE, 0, CLR_BROWN),
+    MON("crocodile", S_LIZARD,
+       LVL(6, 9, 5, 0, 0), (G_GENO|1),
+       A(ATTK(AT_BITE, AD_PHYS, 4, 2), ATTK(AT_CLAW, AD_PHYS, 1,12),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_LARGE), 0, 0,
+       M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_THICK_HIDE|M1_NOHANDS|
+         M1_OVIPAROUS|M1_CARNIVORE,
+       M2_STRONG|M2_HOSTILE, 0, CLR_BROWN),
+    MON("salamander", S_LIZARD,
+       LVL(8, 12, -1, 0, -9), (G_HELL|1),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_TUCH, AD_FIRE, 1, 6),
+         ATTK(AT_HUGS, AD_PHYS, 2, 6), ATTK(AT_HUGS, AD_FIRE, 3, 6),
+         NO_ATTK, NO_ATTK),
+       SIZ(1500, 400, 0, MS_MUMBLE, MZ_HUMAN), MR_SLEEP|MR_FIRE, MR_FIRE,
+       M1_HUMANOID|M1_SLITHY|M1_THICK_HIDE|M1_POIS,
+       M2_STALK|M2_HOSTILE|M2_COLLECT|M2_MAGIC, M3_INFRAVISIBLE, CLR_ORANGE),
+
+/*
+ * dummy monster needed for visual interface
+ */
+       /* (marking it unique prevents figurines)
+        */
+    MON("long worm tail", S_WORM_TAIL,
+       LVL(0, 0, 0, 0, 0), (G_NOGEN|G_NOCORPSE|G_UNIQ),
+       A(NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(0, 0, 0, 0, 0), 0, 0, 0L, M2_NOPOLY, 0, CLR_BROWN),
+
+       /* Note:
+        * Worm tail must be between the normal monsters and the special
+        * quest & pseudo-character ones because an optimization in the
+        * random monster selection code assumes everything beyond here
+        * has the G_NOGEN and M2_NOPOLY attributes.
+        */
+
+/*
+ * character classes
+ */
+    MON("archeologist", S_HUMAN,
+       LVL(10, 12, 10, 1, 3), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_TUNNEL|M1_NEEDPICK|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("barbarian", S_HUMAN,
+       LVL(10, 12, 10, 1, 0), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), MR_POISON, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("caveman", S_HUMAN,
+       LVL(10, 12, 10, 0, 1), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("cavewoman", S_HUMAN,
+       LVL(10, 12, 10, 0, 1), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_FEMALE|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("healer", S_HUMAN,
+       LVL(10, 12, 10, 1, 0), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), MR_POISON, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("knight", S_HUMAN,
+       LVL(10, 12, 10, 1, 3), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("monk", S_HUMAN, 
+       LVL(10, 12, 10, 2, 0), G_NOGEN,
+       A(ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_KICK, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_HERBIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT|M2_MALE,
+       M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("priest", S_HUMAN,
+       LVL(10, 12, 10, 2, 0), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("priestess", S_HUMAN,
+       LVL(10, 12, 10, 2, 0), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_FEMALE|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("ranger", S_HUMAN,
+       LVL(10, 12, 10, 2, -3), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("rogue", S_HUMAN,
+       LVL(10, 12, 10, 1, -3), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT,
+       M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("samurai", S_HUMAN,
+       LVL(10, 12, 10, 1, 3), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC),
+#ifdef TOURIST
+    MON("tourist", S_HUMAN,
+       LVL(10, 12, 10, 1, 0), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC),
+#endif
+    MON("valkyrie", S_HUMAN,
+       LVL(10, 12, 10, 1, -1), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), MR_COLD, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_FEMALE|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("wizard", S_HUMAN,
+       LVL(10, 12, 10, 3, 0), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT|M2_MAGIC, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+/*
+ * quest leaders
+ */
+    MON("Lord Carnarvon", S_HUMAN,
+       LVL(20, 12, 0, 30, 20), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0,
+       M1_TUNNEL|M1_NEEDPICK|M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE|
+         M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISIBLE, HI_LORD),
+    MON("Pelias", S_HUMAN,
+       LVL(20, 12, 0, 30, 0), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), MR_POISON, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE|
+         M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISIBLE, HI_LORD),
+    MON("Shaman Karnov", S_HUMAN,
+       LVL(20, 12, 0, 30, 20), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE|
+         M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISIBLE, HI_LORD),
+#if 0  /* OBSOLETE */
+       /* Two for elves - one of each sex.
+        */
+    MON("Earendil", S_HUMAN,
+       LVL(20, 12, 0, 50, -20), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_ELF, 350, 0, MS_LEADER, MZ_HUMAN), MR_SLEEP, MR_SLEEP,
+       M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE,
+       M2_NOPOLY|M2_ELF|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|
+         M2_MALE|M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISION|M3_INFRAVISIBLE, HI_LORD),
+    MON("Elwing", S_HUMAN,
+       LVL(20, 12, 0, 50, -20), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_ELF, 350, 0, MS_LEADER, MZ_HUMAN), MR_SLEEP, MR_SLEEP,
+       M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE,
+       M2_NOPOLY|M2_ELF|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|
+         M2_FEMALE|M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISION|M3_INFRAVISIBLE, HI_LORD),
+#endif
+    MON("Hippocrates", S_HUMAN,
+       LVL(20, 12, 0, 40, 0), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), MR_POISON, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE|
+         M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISIBLE, HI_LORD),
+    MON("King Arthur", S_HUMAN,
+       LVL(20, 12, 0, 40, 20), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE|
+         M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISIBLE, HI_LORD),
+    MON("Grand Master", S_HUMAN,
+       LVL(25, 12, 0, 70, 0), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_CLAW, AD_PHYS, 4, 10), ATTK(AT_KICK, AD_PHYS, 2, 8),
+         ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN),
+       MR_FIRE|MR_ELEC|MR_SLEEP|MR_POISON, 0,
+       M1_HUMANOID|M1_SEE_INVIS|M1_HERBIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_NASTY|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISIBLE, CLR_BLACK),
+    MON("Arch Priest", S_HUMAN,
+       LVL(25, 12, 7, 70, 0), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 4,10), ATTK(AT_KICK, AD_PHYS, 2, 8),
+         ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN),
+       MR_FIRE|MR_ELEC|MR_SLEEP|MR_POISON, 0,
+       M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISIBLE, CLR_WHITE),
+    MON("Orion", S_HUMAN,
+       LVL(20, 12, 0, 30, 0), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS|M1_SWIM|M1_AMPHIBIOUS,
+       M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE|
+         M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISION|M3_INFRAVISIBLE, HI_LORD),
+       /* Note: Master of Thieves is also the Tourist's nemesis.
+        */
+    MON("Master of Thieves", S_HUMAN,
+       LVL(20, 12, 0, 30, -20), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6),
+         ATTK(AT_CLAW, AD_SAMU, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), MR_STONE, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_MALE|M2_GREEDY|
+         M2_JEWELS|M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISIBLE, HI_LORD),
+    MON("Lord Sato", S_HUMAN,
+       LVL(20, 12, 0, 30, 20), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE|
+         M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISIBLE, HI_LORD),
+#ifdef TOURIST
+    MON("Twoflower", S_HUMAN,
+       LVL(20, 12, 10, 20, 0), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE|
+         M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISIBLE, HI_DOMESTIC),
+#endif
+    MON("Norn", S_HUMAN,
+       LVL(20, 12, 0, 80, 0), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), MR_COLD, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_FEMALE|
+         M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISIBLE, HI_LORD),
+    MON("Neferet the Green", S_HUMAN,
+       LVL(20, 12, 0, 60, 0), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 2, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_FEMALE|M2_PNAME|M2_PEACEFUL|
+         M2_STRONG|M2_COLLECT|M2_MAGIC,
+       M3_CLOSE|M3_INFRAVISIBLE, CLR_GREEN),
+/*
+ * quest nemeses
+ */
+    MON("Minion of Huhetotl", S_DEMON,
+       LVL(16, 12, -2, 75, -14), (G_NOCORPSE|G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 8, 4), ATTK(AT_WEAP, AD_PHYS, 4, 6),
+         ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 2, 6),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_LARGE),
+       MR_FIRE|MR_POISON|MR_STONE, 0, M1_FLY|M1_SEE_INVIS|M1_POIS,
+       M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_COLLECT,
+       M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, CLR_RED),
+    MON("Thoth Amon", S_HUMAN,
+       LVL(16, 12, 0, 10, -14), (G_NOGEN|G_UNIQ|G_NOCORPSE),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 1, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON|MR_STONE, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_STRONG|M2_MALE|M2_STALK|M2_HOSTILE|
+         M2_NASTY|M2_COLLECT|M2_MAGIC,
+       M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, HI_LORD),
+       /* Multi-headed, possessing the breath attacks of all the other dragons
+        * (selected at random when attacking).
+        */
+    MON("Chromatic Dragon", S_DRAGON,
+       LVL(16, 12, 0, 30, -14), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_BREA, AD_RBRE, 6, 8), ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         ATTK(AT_CLAW, AD_SAMU, 2, 8), ATTK(AT_BITE, AD_PHYS, 4, 8),
+         ATTK(AT_BITE, AD_PHYS, 4, 8), ATTK(AT_STNG, AD_PHYS, 1, 6)),
+       SIZ(WT_DRAGON, 1700, 0, MS_NEMESIS, MZ_GIGANTIC),
+       MR_FIRE|MR_COLD|MR_SLEEP|MR_DISINT|MR_ELEC|MR_POISON|MR_ACID|MR_STONE,
+       MR_FIRE|MR_COLD|MR_SLEEP|MR_DISINT|MR_ELEC|MR_POISON|MR_STONE,
+       M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE|M1_SEE_INVIS|M1_POIS,
+       M2_NOPOLY|M2_HOSTILE|M2_FEMALE|M2_STALK|M2_STRONG|M2_NASTY|
+         M2_GREEDY|M2_JEWELS|M2_MAGIC,
+       M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, HI_LORD),
+#if 0  /* OBSOLETE */
+    MON("Goblin King", S_ORC,
+       LVL(15, 12, 10, 0, -15), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6),
+         ATTK(AT_CLAW, AD_SAMU, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(750, 350, 0, MS_NEMESIS, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_ORC|M2_HOSTILE|M2_STRONG|M2_STALK|M2_NASTY|M2_MALE|
+         M2_GREEDY|M2_JEWELS|M2_COLLECT|M2_MAGIC,
+       M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, HI_LORD),
+#endif
+    MON("Cyclops", S_GIANT,
+       LVL(18, 12, 0, 0, -15), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 4, 8), ATTK(AT_WEAP, AD_PHYS, 4, 8),
+         ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(1900, 700, 0, MS_NEMESIS, MZ_HUGE), MR_STONE, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_STALK|M2_HOSTILE|
+         M2_NASTY|M2_MALE|M2_JEWELS|M2_COLLECT,
+       M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, CLR_GRAY),
+    MON("Ixoth", S_DRAGON,
+       LVL(15, 12, -1, 20, -14), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_BREA, AD_FIRE, 8, 6), ATTK(AT_BITE, AD_PHYS, 4, 8),
+         ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_PHYS, 2, 4),
+         ATTK(AT_CLAW, AD_SAMU, 2, 4), NO_ATTK ),
+       SIZ(WT_DRAGON, 1600, 0, MS_NEMESIS, MZ_GIGANTIC),
+       MR_FIRE|MR_STONE, MR_FIRE,
+       M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE|M1_SEE_INVIS,
+       M2_NOPOLY|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_STALK|
+         M2_GREEDY|M2_JEWELS|M2_MAGIC,
+       M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, CLR_RED),
+    MON("Master Kaen", S_HUMAN,
+       LVL(25, 12, -10, 10, -20), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_CLAW, AD_PHYS, 16, 2), ATTK(AT_CLAW, AD_PHYS, 16, 2),
+         ATTK(AT_MAGC, AD_CLRC, 0, 0), ATTK(AT_CLAW, AD_SAMU, 1, 4),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN),
+       MR_POISON|MR_STONE, MR_POISON,
+       M1_HUMANOID|M1_HERBIVORE|M1_SEE_INVIS,
+       M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_NASTY|
+         M2_STALK|M2_COLLECT|M2_MAGIC,
+       M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, HI_LORD),
+    MON("Nalzok", S_DEMON,
+       LVL(16, 12, -2, 85, -127), (G_NOGEN|G_UNIQ|G_NOCORPSE),
+       A(ATTK(AT_WEAP, AD_PHYS, 8, 4), ATTK(AT_WEAP, AD_PHYS, 4, 6),
+         ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 2, 6),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_LARGE),
+       MR_FIRE|MR_POISON|MR_STONE, 0, M1_FLY|M1_SEE_INVIS|M1_POIS,
+       M2_NOPOLY|M2_DEMON|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_STALK|
+         M2_NASTY|M2_COLLECT,
+       M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, CLR_RED),
+    MON("Scorpius", S_SPIDER,
+       LVL(15, 12, 10, 0, -15), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_SAMU, 2, 6),
+         ATTK(AT_STNG, AD_DISE, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(750, 350, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON|MR_STONE, MR_POISON,
+       M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_POIS|M1_CARNIVORE,
+       M2_NOPOLY|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_STALK|M2_NASTY|
+         M2_COLLECT|M2_MAGIC,
+       M3_WANTSARTI|M3_WAITFORU, HI_LORD),
+    MON("Master Assassin", S_HUMAN,
+       LVL(15, 12, 0, 30, 18), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_DRST, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 8),
+         ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_HOSTILE|M2_STALK|M2_NASTY|
+         M2_COLLECT|M2_MAGIC,
+       M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, HI_LORD),
+       /* A renegade daimyo who led a 13 year civil war against the shogun
+        * of his time.
+        */
+    MON("Ashikaga Takauji", S_HUMAN,
+       LVL(15, 12, 0, 40, -13), (G_NOGEN|G_UNIQ|G_NOCORPSE),
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6),
+         ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_STALK|
+         M2_NASTY|M2_MALE|M2_COLLECT|M2_MAGIC,
+       M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, HI_LORD),
+#ifdef TOURIST
+       /*
+        * Note: the Master of Thieves was defined above.
+        */
+#endif
+    MON("Lord Surtur", S_GIANT,
+       LVL(15, 12, 2, 50, 12), (G_NOGEN|G_UNIQ),
+       A(ATTK(AT_WEAP, AD_PHYS, 2,10), ATTK(AT_WEAP, AD_PHYS, 2,10),
+         ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(2250, 850, 0, MS_NEMESIS, MZ_HUGE), MR_FIRE|MR_STONE, MR_FIRE,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_GIANT|M2_MALE|M2_PNAME|M2_HOSTILE|M2_STALK|
+         M2_STRONG|M2_NASTY|M2_ROCKTHROW|M2_JEWELS|M2_COLLECT,
+       M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, HI_LORD),
+    MON("Dark One", S_HUMAN,
+       LVL(15, 12, 0, 80, -10), (G_NOGEN|G_UNIQ|G_NOCORPSE),
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         ATTK(AT_CLAW, AD_SAMU, 1, 4), ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_HOSTILE|M2_STALK|M2_NASTY|
+         M2_COLLECT|M2_MAGIC,
+       M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, CLR_BLACK),
+/*
+ * quest "guardians"
+ */
+    MON("student", S_HUMAN,
+       LVL(5, 12, 10, 10, 3), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0,
+       M1_TUNNEL|M1_NEEDPICK|M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("chieftain", S_HUMAN,
+       LVL(5, 12, 10, 10, 0), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), MR_POISON, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("neanderthal", S_HUMAN,
+       LVL(5, 12, 10, 10, 1), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+#if 0  /* OBSOLETE */
+    MON("High-elf", S_HUMAN,
+       LVL(5, 12, 10, 10, -7), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_MAGC, AD_CLRC, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_ELF, 350, 0, MS_GUARDIAN, MZ_HUMAN), MR_SLEEP, MR_SLEEP,
+       M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE,
+       M2_NOPOLY|M2_ELF|M2_PEACEFUL|M2_COLLECT,
+       M3_INFRAVISION|M3_INFRAVISIBLE, HI_DOMESTIC),
+#endif
+    MON("attendant", S_HUMAN,
+       LVL(5, 12, 10, 10, 3), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), MR_POISON, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("page", S_HUMAN,
+       LVL(5, 12, 10, 10, 3), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("abbot", S_HUMAN, 
+       LVL(5, 12, 10, 20, 0), G_NOGEN,
+       A(ATTK(AT_CLAW, AD_PHYS, 8, 2), ATTK(AT_KICK, AD_STUN, 3, 2),
+         ATTK(AT_MAGC, AD_CLRC, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_HERBIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("acolyte", S_HUMAN,
+       LVL(5, 12, 10, 20, 0), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_CLRC, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("hunter", S_HUMAN,
+       LVL(5, 12, 10, 10, -7), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 4),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT,
+       M3_INFRAVISION|M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("thug", S_HUMAN,
+       LVL(5, 12, 10, 10, -3), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_GREEDY|M2_COLLECT,
+       M3_INFRAVISIBLE, HI_DOMESTIC),
+    MON("ninja", S_HUMAN,
+       LVL(5, 12, 10, 10, 3), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_HOSTILE|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("roshi", S_HUMAN,
+       LVL(5, 12, 10, 10, 3), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+#ifdef TOURIST
+    MON("guide", S_HUMAN,
+       LVL(5, 12, 10, 20, 0), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL | M2_STRONG|M2_COLLECT|M2_MAGIC,
+       M3_INFRAVISIBLE, HI_DOMESTIC),
+#endif
+    MON("warrior", S_HUMAN,
+       LVL(5, 12, 10, 10, -1), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT|M2_FEMALE, M3_INFRAVISIBLE,
+       HI_DOMESTIC),
+    MON("apprentice", S_HUMAN,
+       LVL(5, 12, 10, 30, 0), G_NOGEN,
+       A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0),
+         NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0,
+       M1_HUMANOID|M1_OMNIVORE,
+       M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT|M2_MAGIC,
+       M3_INFRAVISIBLE, HI_DOMESTIC),
+/*
+ * array terminator
+ */
+    MON("", 0,
+       LVL(0, 0, 0, 0, 0), (0),
+       A(NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
+       SIZ(0, 0, 0, 0, 0), 0, 0, 0L, 0L, 0, 0)
+};
+#endif /* !SPLITMON_1 */
+
+#ifndef SPLITMON_1
+/* dummy routine used to force linkage */
+void
+monst_init()
+{
+    return;
+}
+#endif
+
+/*monst.c*/
diff --git a/src/mplayer.c b/src/mplayer.c
new file mode 100644 (file)
index 0000000..8a0d08c
--- /dev/null
@@ -0,0 +1,340 @@
+/*     SCCS Id: @(#)mplayer.c  3.4     1997/02/04      */
+/*     Copyright (c) Izchak Miller, 1992.                        */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+STATIC_DCL const char *NDECL(dev_name);
+STATIC_DCL void FDECL(get_mplname, (struct monst *, char *));
+STATIC_DCL void FDECL(mk_mplayer_armor, (struct monst *, SHORT_P));
+
+/* These are the names of those who
+ * contributed to the development of NetHack 3.2/3.3/3.4.
+ *
+ * Keep in alphabetical order within teams.
+ * Same first name is entered once within each team.
+ */
+static const char *developers[] = {
+       /* devteam */
+       "Dave", "Dean", "Eric", "Izchak", "Janet", "Jessie",
+       "Ken", "Kevin", "Michael", "Mike", "Pat", "Paul", "Steve", "Timo",
+       "Warwick",
+       /* PC team */
+       "Bill", "Eric", "Keizo", "Ken", "Kevin", "Michael", "Mike", "Paul",
+       "Stephen", "Steve", "Timo", "Yitzhak",
+       /* Amiga team */
+       "Andy", "Gregg", "Janne", "Keni", "Mike", "Olaf", "Richard",
+       /* Mac team */
+       "Andy", "Chris", "Dean", "Jon", "Jonathan", "Kevin", "Wang",
+       /* Atari team */
+       "Eric", "Marvin", "Warwick",
+       /* NT team */
+       "Alex", "Dion", "Michael",
+       /* OS/2 team */
+       "Helge", "Ron", "Timo",
+       /* VMS team */
+       "Joshua", "Pat",
+       ""};
+
+
+/* return a randomly chosen developer name */
+STATIC_OVL const char *
+dev_name()
+{
+       register int i, m = 0, n = SIZE(developers);
+       register struct monst *mtmp;
+       register boolean match;
+
+       do {
+           match = FALSE;
+           i = rn2(n);
+           for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+               if(!is_mplayer(mtmp->data)) continue;
+               if(!strncmp(developers[i], NAME(mtmp),
+                                      strlen(developers[i]))) {
+                   match = TRUE;
+                   break;
+               }
+           }
+           m++;
+       } while (match && m < 100); /* m for insurance */
+
+       if (match) return (const char *)0;
+       return(developers[i]);
+}
+
+STATIC_OVL void
+get_mplname(mtmp, nam)
+register struct monst *mtmp;
+char *nam;
+{
+       boolean fmlkind = is_female(mtmp->data);
+       const char *devnam;
+
+       devnam = dev_name();
+       if (!devnam)
+           Strcpy(nam, fmlkind ? "Eve" : "Adam");
+       else if (fmlkind && !!strcmp(devnam, "Janet"))
+           Strcpy(nam, rn2(2) ? "Maud" : "Eve");
+       else Strcpy(nam, devnam);
+
+       if (fmlkind || !strcmp(nam, "Janet"))
+           mtmp->female = 1;
+       else
+           mtmp->female = 0;
+       Strcat(nam, " the ");
+       Strcat(nam, rank_of((int)mtmp->m_lev,
+                           monsndx(mtmp->data),
+                           (boolean)mtmp->female));
+}
+
+STATIC_OVL void
+mk_mplayer_armor(mon, typ)
+struct monst *mon;
+short typ;
+{
+       struct obj *obj;
+
+       if (typ == STRANGE_OBJECT) return;
+       obj = mksobj(typ, FALSE, FALSE);
+       if (!rn2(3)) obj->oerodeproof = 1;
+       if (!rn2(3)) curse(obj);
+       if (!rn2(3)) bless(obj);
+       /* Most players who get to the endgame who have cursed equipment
+        * have it because the wizard or other monsters cursed it, so its
+        * chances of having plusses is the same as usual....
+        */
+       obj->spe = rn2(10) ? (rn2(3) ? rn2(5) : rn1(4,4)) : -rnd(3);
+       (void) mpickobj(mon, obj);
+}
+
+struct monst *
+mk_mplayer(ptr, x, y, special)
+register struct permonst *ptr;
+xchar x, y;
+register boolean special;
+{
+       register struct monst *mtmp;
+       char nam[PL_NSIZ];
+
+       if(!is_mplayer(ptr))
+               return((struct monst *)0);
+
+       if(MON_AT(x, y))
+               (void) rloc(m_at(x, y), FALSE); /* insurance */
+
+       if(!In_endgame(&u.uz)) special = FALSE;
+
+       if ((mtmp = makemon(ptr, x, y, NO_MM_FLAGS)) != 0) {
+           short weapon = rn2(2) ? LONG_SWORD : rnd_class(SPEAR, BULLWHIP);
+           short armor = rnd_class(GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL);
+           short cloak = !rn2(8) ? STRANGE_OBJECT :
+                       rnd_class(OILSKIN_CLOAK, CLOAK_OF_DISPLACEMENT);
+           short helm = !rn2(8) ? STRANGE_OBJECT :
+                       rnd_class(ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY);
+           short shield = !rn2(8) ? STRANGE_OBJECT :
+                       rnd_class(ELVEN_SHIELD, SHIELD_OF_REFLECTION);
+           int quan;
+           struct obj *otmp;
+
+           mtmp->m_lev = (special ? rn1(16,15) : rnd(16));
+           mtmp->mhp = mtmp->mhpmax = d((int)mtmp->m_lev,10) +
+                                       (special ? (30 + rnd(30)) : 30);
+           if(special) {
+               get_mplname(mtmp, nam);
+               mtmp = christen_monst(mtmp, nam);
+               /* that's why they are "stuck" in the endgame :-) */
+               (void)mongets(mtmp, FAKE_AMULET_OF_YENDOR);
+           }
+           mtmp->mpeaceful = 0;
+           set_malign(mtmp); /* peaceful may have changed again */
+
+           switch(monsndx(ptr)) {
+               case PM_ARCHEOLOGIST:
+                   if (rn2(2)) weapon = BULLWHIP;
+                   break;
+               case PM_BARBARIAN:
+                   if (rn2(2)) {
+                       weapon = rn2(2) ? TWO_HANDED_SWORD : BATTLE_AXE;
+                       shield = STRANGE_OBJECT;
+                   }
+                   if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL);
+                   if (helm == HELM_OF_BRILLIANCE) helm = STRANGE_OBJECT;
+                   break;
+               case PM_CAVEMAN:
+               case PM_CAVEWOMAN:
+                   if (rn2(4)) weapon = MACE;
+                   else if (rn2(2)) weapon = CLUB;
+                   if (helm == HELM_OF_BRILLIANCE) helm = STRANGE_OBJECT;
+                   break;
+               case PM_HEALER:
+                   if (rn2(4)) weapon = QUARTERSTAFF;
+                   else if (rn2(2)) weapon = rn2(2) ? UNICORN_HORN : SCALPEL;
+                   if (rn2(4)) helm = rn2(2) ? HELM_OF_BRILLIANCE : HELM_OF_TELEPATHY;
+                   if (rn2(2)) shield = STRANGE_OBJECT;
+                   break;
+               case PM_KNIGHT:
+                   if (rn2(4)) weapon = LONG_SWORD;
+                   if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL);
+                   break;
+               case PM_MONK:
+                   weapon = STRANGE_OBJECT;
+                   armor = STRANGE_OBJECT;
+                   cloak = ROBE;
+                   if (rn2(2)) shield = STRANGE_OBJECT;
+                   break;
+               case PM_PRIEST:
+               case PM_PRIESTESS:
+                   if (rn2(2)) weapon = MACE;
+                   if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL);
+                   if (rn2(4)) cloak = ROBE;
+                   if (rn2(4)) helm = rn2(2) ? HELM_OF_BRILLIANCE : HELM_OF_TELEPATHY;
+                   if (rn2(2)) shield = STRANGE_OBJECT;
+                   break;
+               case PM_RANGER:
+                   if (rn2(2)) weapon = ELVEN_DAGGER;
+                   break;
+               case PM_ROGUE:
+                   if (rn2(2)) weapon = SHORT_SWORD;
+                   break;
+               case PM_SAMURAI:
+                   if (rn2(2)) weapon = KATANA;
+                   break;
+#ifdef TOURIST
+               case PM_TOURIST:
+                   /* Defaults are just fine */
+                   break;
+#endif
+               case PM_VALKYRIE:
+                   if (rn2(2)) weapon = WAR_HAMMER;
+                   if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL);
+                   break;
+               case PM_WIZARD:
+                   if (rn2(4)) weapon = rn2(2) ? QUARTERSTAFF : ATHAME;
+                   if (rn2(2)) {
+                       armor = rn2(2) ? BLACK_DRAGON_SCALE_MAIL :
+                                       SILVER_DRAGON_SCALE_MAIL;
+                       cloak = CLOAK_OF_MAGIC_RESISTANCE;
+                   }
+                   if (rn2(4)) helm = HELM_OF_BRILLIANCE;
+                   shield = STRANGE_OBJECT;
+                   break;
+               default: impossible("bad mplayer monster");
+                   weapon = 0;
+                   break;
+           }
+
+           if (weapon != STRANGE_OBJECT) {
+               otmp = mksobj(weapon, TRUE, FALSE);
+               otmp->spe = (special ? rn1(5,4) : rn2(4));
+               if (!rn2(3)) otmp->oerodeproof = 1;
+               else if (!rn2(2)) otmp->greased = 1;
+               if (special && rn2(2))
+                   otmp = mk_artifact(otmp, A_NONE);
+               /* mplayers knew better than to overenchant Magicbane */
+               if (otmp->oartifact == ART_MAGICBANE)
+                   otmp->spe = rnd(4);
+               (void) mpickobj(mtmp, otmp);
+           }
+
+           if(special) {
+               if (!rn2(10))
+                   (void) mongets(mtmp, rn2(3) ? LUCKSTONE : LOADSTONE);
+               mk_mplayer_armor(mtmp, armor);
+               mk_mplayer_armor(mtmp, cloak);
+               mk_mplayer_armor(mtmp, helm);
+               mk_mplayer_armor(mtmp, shield);
+               if (rn2(8))
+                   mk_mplayer_armor(mtmp, rnd_class(LEATHER_GLOVES,
+                                              GAUNTLETS_OF_DEXTERITY));
+               if (rn2(8))
+                   mk_mplayer_armor(mtmp, rnd_class(LOW_BOOTS, LEVITATION_BOOTS));
+               m_dowear(mtmp, TRUE);
+
+               quan = rn2(3) ? rn2(3) : rn2(16);
+               while(quan--)
+                   (void)mongets(mtmp, rnd_class(DILITHIUM_CRYSTAL, JADE));
+               /* To get the gold "right" would mean a player can double his */
+               /* gold supply by killing one mplayer.  Not good. */
+#ifndef GOLDOBJ
+               mtmp->mgold = rn2(1000);
+#else
+               mkmonmoney(mtmp, rn2(1000));
+#endif
+               quan = rn2(10);
+               while(quan--)
+                   (void) mpickobj(mtmp, mkobj(RANDOM_CLASS, FALSE));
+           }
+           quan = rnd(3);
+           while(quan--)
+               (void)mongets(mtmp, rnd_offensive_item(mtmp));
+           quan = rnd(3);
+           while(quan--)
+               (void)mongets(mtmp, rnd_defensive_item(mtmp));
+           quan = rnd(3);
+           while(quan--)
+               (void)mongets(mtmp, rnd_misc_item(mtmp));
+       }
+
+       return(mtmp);
+}
+
+/* create the indicated number (num) of monster-players,
+ * randomly chosen, and in randomly chosen (free) locations
+ * on the level.  If "special", the size of num should not
+ * be bigger than the number of _non-repeated_ names in the
+ * developers array, otherwise a bunch of Adams and Eves will
+ * fill up the overflow.
+ */
+void
+create_mplayers(num, special)
+register int num;
+boolean special;
+{
+       int pm, x, y;
+       struct monst fakemon;
+
+       while(num) {
+               int tryct = 0;
+
+               /* roll for character class */
+               pm = PM_ARCHEOLOGIST + rn2(PM_WIZARD - PM_ARCHEOLOGIST + 1);
+               fakemon.data = &mons[pm];
+
+               /* roll for an available location */
+               do {
+                   x = rn1(COLNO-4, 2);
+                   y = rnd(ROWNO-2);
+               } while(!goodpos(x, y, &fakemon, 0) && tryct++ <= 50);
+
+               /* if pos not found in 50 tries, don't bother to continue */
+               if(tryct > 50) return;
+
+               (void) mk_mplayer(&mons[pm], (xchar)x, (xchar)y, special);
+               num--;
+       }
+}
+
+void
+mplayer_talk(mtmp)
+register struct monst *mtmp;
+{
+       static const char *same_class_msg[3] = {
+               "I can't win, and neither will you!",
+               "You don't deserve to win!",
+               "Mine should be the honor, not yours!",
+       },                *other_class_msg[3] = {
+               "The low-life wants to talk, eh?",
+               "Fight, scum!",
+               "Here is what I have to say!",
+       };
+
+       if(mtmp->mpeaceful) return; /* will drop to humanoid talk */
+
+       pline("Talk? -- %s",
+               (mtmp->data == &mons[urole.malenum] ||
+               mtmp->data == &mons[urole.femalenum]) ?
+               same_class_msg[rn2(3)] : other_class_msg[rn2(3)]);
+}
+
+/*mplayer.c*/
diff --git a/src/mthrowu.c b/src/mthrowu.c
new file mode 100644 (file)
index 0000000..3038ced
--- /dev/null
@@ -0,0 +1,824 @@
+/*     SCCS Id: @(#)mthrowu.c  3.4     2003/05/09      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+STATIC_DCL int FDECL(drop_throw,(struct obj *,BOOLEAN_P,int,int));
+
+#define URETREATING(x,y) (distmin(u.ux,u.uy,x,y) > distmin(u.ux0,u.uy0,x,y))
+
+#define POLE_LIM 5     /* How far monsters can use pole-weapons */
+
+#ifndef OVLB
+
+STATIC_DCL const char *breathwep[];
+
+#else /* OVLB */
+
+/*
+ * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.
+ */
+STATIC_OVL NEARDATA const char *breathwep[] = {
+                               "fragments",
+                               "fire",
+                               "frost",
+                               "sleep gas",
+                               "a disintegration blast",
+                               "lightning",
+                               "poison gas",
+                               "acid",
+                               "strange breath #8",
+                               "strange breath #9"
+};
+
+/* hero is hit by something other than a monster */
+int
+thitu(tlev, dam, obj, name)
+int tlev, dam;
+struct obj *obj;
+const char *name;      /* if null, then format `obj' */
+{
+       const char *onm, *knm;
+       boolean is_acid;
+       int kprefix = KILLED_BY_AN;
+       char onmbuf[BUFSZ], knmbuf[BUFSZ];
+
+       if (!name) {
+           if (!obj) panic("thitu: name & obj both null?");
+           name = strcpy(onmbuf,
+                        (obj->quan > 1L) ? doname(obj) : mshot_xname(obj));
+           knm = strcpy(knmbuf, killer_xname(obj));
+           kprefix = KILLED_BY;  /* killer_name supplies "an" if warranted */
+       } else {
+           knm = name;
+           /* [perhaps ought to check for plural here to] */
+           if (!strncmpi(name, "the ", 4) ||
+                   !strncmpi(name, "an ", 3) ||
+                   !strncmpi(name, "a ", 2)) kprefix = KILLED_BY;
+       }
+       onm = (obj && obj_is_pname(obj)) ? the(name) :
+                           (obj && obj->quan > 1L) ? name : an(name);
+       is_acid = (obj && obj->otyp == ACID_VENOM);
+
+       if(u.uac + tlev <= rnd(20)) {
+               if(Blind || !flags.verbose) pline("It misses.");
+               else You("are almost hit by %s.", onm);
+               return(0);
+       } else {
+               if(Blind || !flags.verbose) You("are hit!");
+               else You("are hit by %s%s", onm, exclam(dam));
+
+               if (obj && objects[obj->otyp].oc_material == SILVER
+                               && hates_silver(youmonst.data)) {
+                       dam += rnd(20);
+                       pline_The("silver sears your flesh!");
+                       exercise(A_CON, FALSE);
+               }
+               if (is_acid && Acid_resistance)
+                       pline("It doesn't seem to hurt you.");
+               else {
+                       if (is_acid) pline("It burns!");
+                       if (Half_physical_damage) dam = (dam+1) / 2;
+                       losehp(dam, knm, kprefix);
+                       exercise(A_STR, FALSE);
+               }
+               return(1);
+       }
+}
+
+/* Be sure this corresponds with what happens to player-thrown objects in
+ * dothrow.c (for consistency). --KAA
+ * Returns 0 if object still exists (not destroyed).
+ */
+
+STATIC_OVL int
+drop_throw(obj, ohit, x, y)
+register struct obj *obj;
+boolean ohit;
+int x,y;
+{
+       int retvalu = 1;
+       int create;
+       struct monst *mtmp;
+       struct trap *t;
+
+       if (obj->otyp == CREAM_PIE || obj->oclass == VENOM_CLASS ||
+                   (ohit && obj->otyp == EGG))
+               create = 0;
+       else if (ohit && (is_multigen(obj) || obj->otyp == ROCK))
+               create = !rn2(3);
+       else create = 1;
+
+       if (create && !((mtmp = m_at(x, y)) && (mtmp->mtrapped) &&
+                       (t = t_at(x, y)) && ((t->ttyp == PIT) ||
+                       (t->ttyp == SPIKED_PIT)))) {
+               int objgone = 0;
+
+               if (down_gate(x, y) != -1)
+                       objgone = ship_object(obj, x, y, FALSE);
+               if (!objgone) {
+                       if (!flooreffects(obj,x,y,"fall")) { /* don't double-dip on damage */
+                           place_object(obj, x, y);
+                           if (!mtmp && x == u.ux && y == u.uy)
+                               mtmp = &youmonst;
+                           if (mtmp && ohit)
+                               passive_obj(mtmp, obj, (struct attack *)0);
+                           stackobj(obj);
+                           retvalu = 0;
+                       }
+               }
+       } else obfree(obj, (struct obj*) 0);
+       return retvalu;
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+/* an object launched by someone/thing other than player attacks a monster;
+   return 1 if the object has stopped moving (hit or its range used up) */
+int
+ohitmon(mtmp, otmp, range, verbose)
+struct monst *mtmp;    /* accidental target */
+struct obj *otmp;      /* missile; might be destroyed by drop_throw */
+int range;             /* how much farther will object travel if it misses */
+                       /* Use -1 to signify to keep going even after hit, */
+                       /* unless its gone (used for rolling_boulder_traps) */
+boolean verbose;  /* give message(s) even when you can't see what happened */
+{
+       int damage, tmp;
+       boolean vis, ismimic;
+       int objgone = 1;
+
+       ismimic = mtmp->m_ap_type && mtmp->m_ap_type != M_AP_MONSTER;
+       vis = cansee(bhitpos.x, bhitpos.y);
+
+       tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE);
+       if (tmp < rnd(20)) {
+           if (!ismimic) {
+               if (vis) miss(distant_name(otmp, mshot_xname), mtmp);
+               else if (verbose) pline("It is missed.");
+           }
+           if (!range) { /* Last position; object drops */
+               (void) drop_throw(otmp, 0, mtmp->mx, mtmp->my);
+               return 1;
+           }
+       } else if (otmp->oclass == POTION_CLASS) {
+           if (ismimic) seemimic(mtmp);
+           mtmp->msleeping = 0;
+           if (vis) otmp->dknown = 1;
+           potionhit(mtmp, otmp, FALSE);
+           return 1;
+       } else {
+           damage = dmgval(otmp, mtmp);
+           if (otmp->otyp == ACID_VENOM && resists_acid(mtmp))
+               damage = 0;
+           if (ismimic) seemimic(mtmp);
+           mtmp->msleeping = 0;
+           if (vis) hit(distant_name(otmp,mshot_xname), mtmp, exclam(damage));
+           else if (verbose) pline("%s is hit%s", Monnam(mtmp), exclam(damage));
+
+           if (otmp->opoisoned && is_poisonable(otmp)) {
+               if (resists_poison(mtmp)) {
+                   if (vis) pline_The("poison doesn't seem to affect %s.",
+                                  mon_nam(mtmp));
+               } else {
+                   if (rn2(30)) {
+                       damage += rnd(6);
+                   } else {
+                       if (vis) pline_The("poison was deadly...");
+                       damage = mtmp->mhp;
+                   }
+               }
+           }
+           if (objects[otmp->otyp].oc_material == SILVER &&
+                   hates_silver(mtmp->data)) {
+               if (vis) pline_The("silver sears %s flesh!",
+                               s_suffix(mon_nam(mtmp)));
+               else if (verbose) pline("Its flesh is seared!");
+           }
+           if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx,mtmp->my)) {
+               if (resists_acid(mtmp)) {
+                   if (vis || verbose)
+                       pline("%s is unaffected.", Monnam(mtmp));
+                   damage = 0;
+               } else {
+                   if (vis) pline_The("acid burns %s!", mon_nam(mtmp));
+                   else if (verbose) pline("It is burned!");
+               }
+           }
+           mtmp->mhp -= damage;
+           if (mtmp->mhp < 1) {
+               if (vis || verbose)
+                   pline("%s is %s!", Monnam(mtmp),
+                       (nonliving(mtmp->data) || !canspotmon(mtmp))
+                       ? "destroyed" : "killed");
+               /* don't blame hero for unknown rolling boulder trap */
+               if (!flags.mon_moving &&
+                   (otmp->otyp != BOULDER || range >= 0 || !otmp->otrapped))
+                   xkilled(mtmp,0);
+               else mondied(mtmp);
+           }
+
+           if (can_blnd((struct monst*)0, mtmp,
+                   (uchar)(otmp->otyp == BLINDING_VENOM ? AT_SPIT : AT_WEAP),
+                   otmp)) {
+               if (vis && mtmp->mcansee)
+                   pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
+               mtmp->mcansee = 0;
+               tmp = (int)mtmp->mblinded + rnd(25) + 20;
+               if (tmp > 127) tmp = 127;
+               mtmp->mblinded = tmp;
+           }
+
+           objgone = drop_throw(otmp, 1, bhitpos.x, bhitpos.y);
+           if (!objgone && range == -1) {  /* special case */
+                   obj_extract_self(otmp); /* free it for motion again */
+                   return 0;
+           }
+           return 1;
+       }
+       return 0;
+}
+
+void
+m_throw(mon, x, y, dx, dy, range, obj)
+       register struct monst *mon;
+       register int x,y,dx,dy,range;           /* direction and range */
+       register struct obj *obj;
+{
+       register struct monst *mtmp;
+       struct obj *singleobj;
+       char sym = obj->oclass;
+       int hitu, blindinc = 0;
+
+       bhitpos.x = x;
+       bhitpos.y = y;
+
+       if (obj->quan == 1L) {
+           /*
+            * Remove object from minvent.  This cannot be done later on;
+            * what if the player dies before then, leaving the monster
+            * with 0 daggers?  (This caused the infamous 2^32-1 orcish
+            * dagger bug).
+            *
+            * VENOM is not in minvent - it should already be OBJ_FREE.
+            * The extract below does nothing.
+            */
+
+           /* not possibly_unwield, which checks the object's */
+           /* location, not its existence */
+           if (MON_WEP(mon) == obj) {
+                   setmnotwielded(mon,obj);
+                   MON_NOWEP(mon);
+           }
+           obj_extract_self(obj);
+           singleobj = obj;
+           obj = (struct obj *) 0;
+       } else {
+           singleobj = splitobj(obj, 1L);
+           obj_extract_self(singleobj);
+       }
+
+       singleobj->owornmask = 0; /* threw one of multiple weapons in hand? */
+
+       if (singleobj->cursed && (dx || dy) && !rn2(7)) {
+           if(canseemon(mon) && flags.verbose) {
+               if(is_ammo(singleobj))
+                   pline("%s misfires!", Monnam(mon));
+               else
+                   pline("%s as %s throws it!",
+                         Tobjnam(singleobj, "slip"), mon_nam(mon));
+           }
+           dx = rn2(3)-1;
+           dy = rn2(3)-1;
+           /* check validity of new direction */
+           if (!dx && !dy) {
+               (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
+               return;
+           }
+       }
+
+       /* pre-check for doors, walls and boundaries.
+          Also need to pre-check for bars regardless of direction;
+          the random chance for small objects hitting bars is
+          skipped when reaching them at point blank range */
+       if (!isok(bhitpos.x+dx,bhitpos.y+dy)
+           || IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ)
+           || closed_door(bhitpos.x+dx, bhitpos.y+dy)
+           || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS &&
+               hits_bars(&singleobj, bhitpos.x, bhitpos.y, 0, 0))) {
+           (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
+           return;
+       }
+
+       /* Note: drop_throw may destroy singleobj.  Since obj must be destroyed
+        * early to avoid the dagger bug, anyone who modifies this code should
+        * be careful not to use either one after it's been freed.
+        */
+       if (sym) tmp_at(DISP_FLASH, obj_to_glyph(singleobj));
+       while(range-- > 0) { /* Actually the loop is always exited by break */
+               bhitpos.x += dx;
+               bhitpos.y += dy;
+               if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
+                   if (ohitmon(mtmp, singleobj, range, TRUE))
+                       break;
+               } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
+                   if (multi) nomul(0);
+
+                   if (singleobj->oclass == GEM_CLASS &&
+                           singleobj->otyp <= LAST_GEM+9 /* 9 glass colors */
+                           && is_unicorn(youmonst.data)) {
+                       if (singleobj->otyp > LAST_GEM) {
+                           You("catch the %s.", xname(singleobj));
+                           You("are not interested in %s junk.",
+                               s_suffix(mon_nam(mon)));
+                           makeknown(singleobj->otyp);
+                           dropy(singleobj);
+                       } else {
+                           You("accept %s gift in the spirit in which it was intended.",
+                               s_suffix(mon_nam(mon)));
+                           (void)hold_another_object(singleobj,
+                               "You catch, but drop, %s.", xname(singleobj),
+                               "You catch:");
+                       }
+                       break;
+                   }
+                   if (singleobj->oclass == POTION_CLASS) {
+                       if (!Blind) singleobj->dknown = 1;
+                       potionhit(&youmonst, singleobj, FALSE);
+                       break;
+                   }
+                   switch(singleobj->otyp) {
+                       int dam, hitv;
+                       case EGG:
+                           if (!touch_petrifies(&mons[singleobj->corpsenm])) {
+                               impossible("monster throwing egg type %d",
+                                       singleobj->corpsenm);
+                               hitu = 0;
+                               break;
+                           }
+                           /* fall through */
+                       case CREAM_PIE:
+                       case BLINDING_VENOM:
+                           hitu = thitu(8, 0, singleobj, (char *)0);
+                           break;
+                       default:
+                           dam = dmgval(singleobj, &youmonst);
+                           hitv = 3 - distmin(u.ux,u.uy, mon->mx,mon->my);
+                           if (hitv < -4) hitv = -4;
+                           if (is_elf(mon->data) &&
+                               objects[singleobj->otyp].oc_skill == P_BOW) {
+                               hitv++;
+                               if (MON_WEP(mon) &&
+                                   MON_WEP(mon)->otyp == ELVEN_BOW)
+                                   hitv++;
+                               if(singleobj->otyp == ELVEN_ARROW) dam++;
+                           }
+                           if (bigmonst(youmonst.data)) hitv++;
+                           hitv += 8 + singleobj->spe;
+                           if (dam < 1) dam = 1;
+                           hitu = thitu(hitv, dam, singleobj, (char *)0);
+                   }
+                   if (hitu && singleobj->opoisoned &&
+                       is_poisonable(singleobj)) {
+                       char onmbuf[BUFSZ], knmbuf[BUFSZ];
+
+                       Strcpy(onmbuf, xname(singleobj));
+                       Strcpy(knmbuf, killer_xname(singleobj));
+                       poisoned(onmbuf, A_STR, knmbuf, -10);
+                   }
+                   if(hitu &&
+                      can_blnd((struct monst*)0, &youmonst,
+                               (uchar)(singleobj->otyp == BLINDING_VENOM ?
+                                       AT_SPIT : AT_WEAP), singleobj)) {
+                       blindinc = rnd(25);
+                       if(singleobj->otyp == CREAM_PIE) {
+                           if(!Blind) pline("Yecch!  You've been creamed.");
+                           else pline("There's %s sticky all over your %s.",
+                                      something,
+                                      body_part(FACE));
+                       } else if(singleobj->otyp == BLINDING_VENOM) {
+                           int num_eyes = eyecount(youmonst.data);
+                           /* venom in the eyes */
+                           if(!Blind) pline_The("venom blinds you.");
+                           else Your("%s sting%s.",
+                                     (num_eyes == 1) ? body_part(EYE) :
+                                               makeplural(body_part(EYE)),
+                                     (num_eyes == 1) ? "s" : "");
+                       }
+                   }
+                   if (hitu && singleobj->otyp == EGG) {
+                       if (!Stone_resistance
+                           && !(poly_when_stoned(youmonst.data) &&
+                                polymon(PM_STONE_GOLEM))) {
+                           Stoned = 5;
+                           killer = (char *) 0;
+                       }
+                   }
+                   stop_occupation();
+                   if (hitu || !range) {
+                       (void) drop_throw(singleobj, hitu, u.ux, u.uy);
+                       break;
+                   }
+               } else if (!range       /* reached end of path */
+                       /* missile hits edge of screen */
+                       || !isok(bhitpos.x+dx,bhitpos.y+dy)
+                       /* missile hits the wall */
+                       || IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ)
+                       /* missile hit closed door */
+                       || closed_door(bhitpos.x+dx, bhitpos.y+dy)
+                       /* missile might hit iron bars */
+                       || (levl[bhitpos.x+dx][bhitpos.y+dy].typ == IRONBARS &&
+                       hits_bars(&singleobj, bhitpos.x, bhitpos.y, !rn2(5), 0))
+#ifdef SINKS
+                       /* Thrown objects "sink" */
+                       || IS_SINK(levl[bhitpos.x][bhitpos.y].typ)
+#endif
+                                                               ) {
+                   if (singleobj) /* hits_bars might have destroyed it */
+                       (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
+                   break;
+               }
+               tmp_at(bhitpos.x, bhitpos.y);
+               delay_output();
+       }
+       tmp_at(bhitpos.x, bhitpos.y);
+       delay_output();
+       tmp_at(DISP_END, 0);
+
+       if (blindinc) {
+               u.ucreamed += blindinc;
+               make_blinded(Blinded + (long)blindinc, FALSE);
+               if (!Blind) Your(vision_clears);
+       }
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+/* Remove an item from the monster's inventory and destroy it. */
+void
+m_useup(mon, obj)
+struct monst *mon;
+struct obj *obj;
+{
+       if (obj->quan > 1L) {
+               obj->quan--;
+               obj->owt = weight(obj);
+       } else {
+               obj_extract_self(obj);
+               possibly_unwield(mon, FALSE);
+               if (obj->owornmask) {
+                   mon->misc_worn_check &= ~obj->owornmask;
+                   update_mon_intrinsics(mon, obj, FALSE, FALSE);
+               }
+               obfree(obj, (struct obj*) 0);
+       }
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+/* monster attempts ranged weapon attack against player */
+void
+thrwmu(mtmp)
+struct monst *mtmp;
+{
+       struct obj *otmp, *mwep;
+       xchar x, y;
+       schar skill;
+       int multishot;
+       const char *onm;
+
+       /* Rearranged beginning so monsters can use polearms not in a line */
+       if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
+           mtmp->weapon_check = NEED_RANGED_WEAPON;
+           /* mon_wield_item resets weapon_check as appropriate */
+           if(mon_wield_item(mtmp) != 0) return;
+       }
+
+       /* Pick a weapon */
+       otmp = select_rwep(mtmp);
+       if (!otmp) return;
+
+       if (is_pole(otmp)) {
+           int dam, hitv;
+
+           if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) > POLE_LIM ||
+                   !couldsee(mtmp->mx, mtmp->my))
+               return; /* Out of range, or intervening wall */
+
+           if (canseemon(mtmp)) {
+               onm = xname(otmp);
+               pline("%s thrusts %s.", Monnam(mtmp),
+                     obj_is_pname(otmp) ? the(onm) : an(onm));
+           }
+
+           dam = dmgval(otmp, &youmonst);
+           hitv = 3 - distmin(u.ux,u.uy, mtmp->mx,mtmp->my);
+           if (hitv < -4) hitv = -4;
+           if (bigmonst(youmonst.data)) hitv++;
+           hitv += 8 + otmp->spe;
+           if (dam < 1) dam = 1;
+
+           (void) thitu(hitv, dam, otmp, (char *)0);
+           stop_occupation();
+           return;
+       }
+
+       x = mtmp->mx;
+       y = mtmp->my;
+       /* If you are coming toward the monster, the monster
+        * should try to soften you up with missiles.  If you are
+        * going away, you are probably hurt or running.  Give
+        * chase, but if you are getting too far away, throw.
+        */
+       if (!lined_up(mtmp) ||
+               (URETREATING(x,y) &&
+                       rn2(BOLT_LIM - distmin(x,y,mtmp->mux,mtmp->muy))))
+           return;
+
+       skill = objects[otmp->otyp].oc_skill;
+       mwep = MON_WEP(mtmp);           /* wielded weapon */
+
+       /* Multishot calculations */
+       multishot = 1;
+       if ((ammo_and_launcher(otmp, mwep) || skill == P_DAGGER ||
+               skill == -P_DART || skill == -P_SHURIKEN) && !mtmp->mconf) {
+           /* Assumes lords are skilled, princes are expert */
+           if (is_prince(mtmp->data)) multishot += 2;
+           else if (is_lord(mtmp->data)) multishot++;
+
+           switch (monsndx(mtmp->data)) {
+           case PM_RANGER:
+                   multishot++;
+                   break;
+           case PM_ROGUE:
+                   if (skill == P_DAGGER) multishot++;
+                   break;
+           case PM_NINJA:
+           case PM_SAMURAI:
+                   if (otmp->otyp == YA && mwep &&
+                       mwep->otyp == YUMI) multishot++;
+                   break;
+           default:
+               break;
+           }
+           /* racial bonus */
+           if ((is_elf(mtmp->data) &&
+                   otmp->otyp == ELVEN_ARROW &&
+                   mwep && mwep->otyp == ELVEN_BOW) ||
+               (is_orc(mtmp->data) &&
+                   otmp->otyp == ORCISH_ARROW &&
+                   mwep && mwep->otyp == ORCISH_BOW))
+               multishot++;
+
+           if ((long)multishot > otmp->quan) multishot = (int)otmp->quan;
+           if (multishot < 1) multishot = 1;
+           else multishot = rnd(multishot);
+       }
+
+       if (canseemon(mtmp)) {
+           char onmbuf[BUFSZ];
+
+           if (multishot > 1) {
+               /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
+                  xname()'s result will already be pluralized */
+               Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
+               onm = onmbuf;
+           } else {
+               /* "an arrow" */
+               onm = singular(otmp, xname);
+               onm = obj_is_pname(otmp) ? the(onm) : an(onm);
+           }
+           m_shot.s = ammo_and_launcher(otmp,mwep) ? TRUE : FALSE;
+           pline("%s %s %s!", Monnam(mtmp),
+                 m_shot.s ? "shoots" : "throws", onm);
+           m_shot.o = otmp->otyp;
+       } else {
+           m_shot.o = STRANGE_OBJECT;  /* don't give multishot feedback */
+       }
+
+       m_shot.n = multishot;
+       for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++)
+           m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
+                   distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
+       m_shot.n = m_shot.i = 0;
+       m_shot.o = STRANGE_OBJECT;
+       m_shot.s = FALSE;
+
+       nomul(0);
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+int
+spitmu(mtmp, mattk)            /* monster spits substance at you */
+register struct monst *mtmp;
+register struct attack *mattk;
+{
+       register struct obj *otmp;
+
+       if(mtmp->mcan) {
+
+           if(flags.soundok)
+               pline("A dry rattle comes from %s throat.",
+                                     s_suffix(mon_nam(mtmp)));
+           return 0;
+       }
+       if(lined_up(mtmp)) {
+               switch (mattk->adtyp) {
+                   case AD_BLND:
+                   case AD_DRST:
+                       otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
+                       break;
+                   default:
+                       impossible("bad attack type in spitmu");
+                               /* fall through */
+                   case AD_ACID:
+                       otmp = mksobj(ACID_VENOM, TRUE, FALSE);
+                       break;
+               }
+               if(!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy))) {
+                   if (canseemon(mtmp))
+                       pline("%s spits venom!", Monnam(mtmp));
+                   m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
+                       distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy), otmp);
+                   nomul(0);
+                   return 0;
+               }
+       }
+       return 0;
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+int
+breamu(mtmp, mattk)                    /* monster breathes at you (ranged) */
+       register struct monst *mtmp;
+       register struct attack  *mattk;
+{
+       /* if new breath types are added, change AD_ACID to max type */
+       int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ;
+
+       if(lined_up(mtmp)) {
+
+           if(mtmp->mcan) {
+               if(flags.soundok) {
+                   if(canseemon(mtmp))
+                       pline("%s coughs.", Monnam(mtmp));
+                   else
+                       You_hear("a cough.");
+               }
+               return(0);
+           }
+           if(!mtmp->mspec_used && rn2(3)) {
+
+               if((typ >= AD_MAGM) && (typ <= AD_ACID)) {
+
+                   if(canseemon(mtmp))
+                       pline("%s breathes %s!", Monnam(mtmp),
+                             breathwep[typ-1]);
+                   buzz((int) (-20 - (typ-1)), (int)mattk->damn,
+                        mtmp->mx, mtmp->my, sgn(tbx), sgn(tby));
+                   nomul(0);
+                   /* breath runs out sometimes. Also, give monster some
+                    * cunning; don't breath if the player fell asleep.
+                    */
+                   if(!rn2(3))
+                       mtmp->mspec_used = 10+rn2(20);
+                   if(typ == AD_SLEE && !Sleep_resistance)
+                       mtmp->mspec_used += rnd(20);
+               } else impossible("Breath weapon %d used", typ-1);
+           }
+       }
+       return(1);
+}
+
+boolean
+linedup(ax, ay, bx, by)
+register xchar ax, ay, bx, by;
+{
+       tbx = ax - bx;  /* These two values are set for use */
+       tby = ay - by;  /* after successful return.         */
+
+       /* sometimes displacement makes a monster think that you're at its
+          own location; prevent it from throwing and zapping in that case */
+       if (!tbx && !tby) return FALSE;
+
+       if((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */
+          && distmin(tbx, tby, 0, 0) < BOLT_LIM) {
+           if(ax == u.ux && ay == u.uy) return((boolean)(couldsee(bx,by)));
+           else if(clear_path(ax,ay,bx,by)) return TRUE;
+       }
+       return FALSE;
+}
+
+boolean
+lined_up(mtmp)         /* is mtmp in position to use ranged attack? */
+       register struct monst *mtmp;
+{
+       return(linedup(mtmp->mux,mtmp->muy,mtmp->mx,mtmp->my));
+}
+
+#endif /* OVL1 */
+#ifdef OVL0
+
+/* Check if a monster is carrying a particular item.
+ */
+struct obj *
+m_carrying(mtmp, type)
+struct monst *mtmp;
+int type;
+{
+       register struct obj *otmp;
+
+       for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+               if(otmp->otyp == type)
+                       return(otmp);
+       return((struct obj *) 0);
+}
+
+/* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
+boolean
+hits_bars(obj_p, x, y, always_hit, whodidit)
+struct obj **obj_p;    /* *obj_p will be set to NULL if object breaks */
+int x, y;
+int always_hit;        /* caller can force a hit for items which would fit through */
+int whodidit;  /* 1==hero, 0=other, -1==just check whether it'll pass thru */
+{
+    struct obj *otmp = *obj_p;
+    int obj_type = otmp->otyp;
+    boolean hits = always_hit;
+
+    if (!hits)
+       switch (otmp->oclass) {
+       case WEAPON_CLASS:
+           {
+               int oskill = objects[obj_type].oc_skill;
+
+               hits = (oskill != -P_BOW  && oskill != -P_CROSSBOW &&
+                       oskill != -P_DART && oskill != -P_SHURIKEN &&
+                       oskill != P_SPEAR && oskill != P_JAVELIN &&
+                       oskill != P_KNIFE);     /* but not dagger */
+               break;
+           }
+       case ARMOR_CLASS:
+               hits = (objects[obj_type].oc_armcat != ARM_GLOVES);
+               break;
+       case TOOL_CLASS:
+               hits = (obj_type != SKELETON_KEY &&
+                       obj_type != LOCK_PICK &&
+#ifdef TOURIST
+                       obj_type != CREDIT_CARD &&
+#endif
+                       obj_type != TALLOW_CANDLE &&
+                       obj_type != WAX_CANDLE &&
+                       obj_type != LENSES &&
+                       obj_type != TIN_WHISTLE &&
+                       obj_type != MAGIC_WHISTLE);
+               break;
+       case ROCK_CLASS:        /* includes boulder */
+               if (obj_type != STATUE ||
+                       mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE;
+               break;
+       case FOOD_CLASS:
+               if (obj_type == CORPSE &&
+                       mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE;
+               else
+                   hits = (obj_type == MEAT_STICK ||
+                           obj_type == HUGE_CHUNK_OF_MEAT);
+               break;
+       case SPBOOK_CLASS:
+       case WAND_CLASS:
+       case BALL_CLASS:
+       case CHAIN_CLASS:
+               hits = TRUE;
+               break;
+       default:
+               break;
+       }
+
+    if (hits && whodidit != -1) {
+       if (whodidit ? hero_breaks(otmp, x, y, FALSE) : breaks(otmp, x, y))
+           *obj_p = otmp = 0;          /* object is now gone */
+           /* breakage makes its own noises */
+       else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL)
+           pline("Whang!");
+       else if (otmp->oclass == COIN_CLASS ||
+               objects[obj_type].oc_material == GOLD ||
+               objects[obj_type].oc_material == SILVER)
+           pline("Clink!");
+       else
+           pline("Clonk!");
+    }
+
+    return hits;
+}
+
+#endif /* OVL0 */
+
+/*mthrowu.c*/
diff --git a/src/muse.c b/src/muse.c
new file mode 100644 (file)
index 0000000..86044e5
--- /dev/null
@@ -0,0 +1,2182 @@
+/*     SCCS Id: @(#)muse.c     3.4     2002/12/23      */
+/*     Copyright (C) 1990 by Ken Arromdee                         */
+/* NetHack may be freely redistributed.  See license for details.  */
+
+/*
+ * Monster item usage routines.
+ */
+
+#include "hack.h"
+#include "edog.h"
+
+extern const int monstr[];
+
+boolean m_using = FALSE;
+
+/* Let monsters use magic items.  Arbitrary assumptions: Monsters only use
+ * scrolls when they can see, monsters know when wands have 0 charges, monsters
+ * cannot recognize if items are cursed are not, monsters which are confused
+ * don't know not to read scrolls, etc....
+ */
+
+STATIC_DCL struct permonst *FDECL(muse_newcham_mon, (struct monst *));
+STATIC_DCL int FDECL(precheck, (struct monst *,struct obj *));
+STATIC_DCL void FDECL(mzapmsg, (struct monst *,struct obj *,BOOLEAN_P));
+STATIC_DCL void FDECL(mreadmsg, (struct monst *,struct obj *));
+STATIC_DCL void FDECL(mquaffmsg, (struct monst *,struct obj *));
+STATIC_PTR int FDECL(mbhitm, (struct monst *,struct obj *));
+STATIC_DCL void FDECL(mbhit,
+       (struct monst *,int,int FDECL((*),(MONST_P,OBJ_P)),
+       int FDECL((*),(OBJ_P,OBJ_P)),struct obj *));
+STATIC_DCL void FDECL(you_aggravate, (struct monst *));
+STATIC_DCL void FDECL(mon_consume_unstone, (struct monst *,struct obj *,
+       BOOLEAN_P,BOOLEAN_P));
+
+static 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).
+        */
+} m;
+static int trapx, trapy;
+static 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.
+        */
+
+/* Any preliminary checks which may result in the monster being unable to use
+ * the item.  Returns 0 if nothing happened, 2 if the monster can't do anything
+ * (i.e. it teleported) and 1 if it's dead.
+ */
+STATIC_OVL int
+precheck(mon, obj)
+struct monst *mon;
+struct obj *obj;
+{
+       boolean vis;
+
+       if (!obj) return 0;
+       vis = cansee(mon->mx, mon->my);
+
+       if (obj->oclass == POTION_CLASS) {
+           coord cc;
+           static const char *empty = "The potion turns out to be empty.";
+           const char *potion_descr;
+           struct monst *mtmp;
+#define POTION_OCCUPANT_CHANCE(n) (13 + 2*(n)) /* also in potion.c */
+
+           potion_descr = OBJ_DESCR(objects[obj->otyp]);
+           if (potion_descr && !strcmp(potion_descr, "milky")) {
+               if ( flags.ghost_count < MAXMONNO &&
+                   !rn2(POTION_OCCUPANT_CHANCE(flags.ghost_count))) {
+                   if (!enexto(&cc, mon->mx, mon->my, &mons[PM_GHOST])) return 0;
+                   mquaffmsg(mon, obj);
+                   m_useup(mon, obj);
+                   mtmp = makemon(&mons[PM_GHOST], cc.x, cc.y, NO_MM_FLAGS);
+                   if (!mtmp) {
+                       if (vis) pline(empty);
+                   } else {
+                       if (vis) {
+                           pline("As %s opens the bottle, an enormous %s emerges!",
+                              mon_nam(mon),
+                              Hallucination ? rndmonnam() : (const char *)"ghost");
+                           pline("%s is frightened to death, and unable to move.",
+                                   Monnam(mon));
+                       }
+                       mon->mcanmove = 0;
+                       mon->mfrozen = 3;
+                   }
+                   return 2;
+               }
+           }
+           if (potion_descr && !strcmp(potion_descr, "smoky") &&
+                   flags.djinni_count < MAXMONNO &&
+                   !rn2(POTION_OCCUPANT_CHANCE(flags.djinni_count))) {
+               if (!enexto(&cc, mon->mx, mon->my, &mons[PM_DJINNI])) return 0;
+               mquaffmsg(mon, obj);
+               m_useup(mon, obj);
+               mtmp = makemon(&mons[PM_DJINNI], cc.x, cc.y, NO_MM_FLAGS);
+               if (!mtmp) {
+                   if (vis) pline(empty);
+               } else {
+                   if (vis)
+                       pline("In a cloud of smoke, %s emerges!",
+                                                       a_monnam(mtmp));
+                   pline("%s speaks.", vis ? Monnam(mtmp) : Something);
+               /* I suspect few players will be upset that monsters */
+               /* can't wish for wands of death here.... */
+                   if (rn2(2)) {
+                       verbalize("You freed me!");
+                       mtmp->mpeaceful = 1;
+                       set_malign(mtmp);
+                   } else {
+                       verbalize("It is about time.");
+                       if (vis) pline("%s vanishes.", Monnam(mtmp));
+                       mongone(mtmp);
+                   }
+               }
+               return 2;
+           }
+       }
+       if (obj->oclass == WAND_CLASS && obj->cursed && !rn2(100)) {
+           int dam = d(obj->spe+2, 6);
+
+           if (flags.soundok) {
+               if (vis) pline("%s zaps %s, which suddenly explodes!",
+                       Monnam(mon), an(xname(obj)));
+               else You_hear("a zap and an explosion in the distance.");
+           }
+           m_useup(mon, obj);
+           if (mon->mhp <= dam) {
+               monkilled(mon, "", AD_RBRE);
+               return 1;
+           }
+           else mon->mhp -= dam;
+           m.has_defense = m.has_offense = m.has_misc = 0;
+           /* Only one needed to be set to 0 but the others are harmless */
+       }
+       return 0;
+}
+
+STATIC_OVL void
+mzapmsg(mtmp, otmp, self)
+struct monst *mtmp;
+struct obj *otmp;
+boolean self;
+{
+       if (!canseemon(mtmp)) {
+               if (flags.soundok)
+                       You_hear("a %s zap.",
+                                       (distu(mtmp->mx,mtmp->my) <= (BOLT_LIM+1)*(BOLT_LIM+1)) ?
+                                       "nearby" : "distant");
+       } else if (self)
+               pline("%s zaps %sself with %s!",
+                     Monnam(mtmp), mhim(mtmp), doname(otmp));
+       else {
+               pline("%s zaps %s!", Monnam(mtmp), an(xname(otmp)));
+               stop_occupation();
+       }
+}
+
+STATIC_OVL void
+mreadmsg(mtmp, otmp)
+struct monst *mtmp;
+struct obj *otmp;
+{
+       boolean vismon = canseemon(mtmp);
+       char onambuf[BUFSZ];
+       short saverole;
+       unsigned savebknown;
+
+       if (!vismon && !flags.soundok)
+           return;             /* no feedback */
+
+       otmp->dknown = 1;  /* seeing or hearing it read reveals its label */
+       /* shouldn't be able to hear curse/bless status of unseen scrolls;
+          for priest characters, bknown will always be set during naming */
+       savebknown = otmp->bknown;
+       saverole = Role_switch;
+       if (!vismon) {
+           otmp->bknown = 0;
+           if (Role_if(PM_PRIEST)) Role_switch = 0;
+       }
+       Strcpy(onambuf, singular(otmp, doname));
+       Role_switch = saverole;
+       otmp->bknown = savebknown;
+
+       if (vismon)
+           pline("%s reads %s!", Monnam(mtmp), onambuf);
+       else
+           You_hear("%s reading %s.",
+               x_monnam(mtmp, ARTICLE_A, (char *)0,
+                   (SUPPRESS_IT|SUPPRESS_INVISIBLE|SUPPRESS_SADDLE), FALSE),
+               onambuf);
+
+       if (mtmp->mconf)
+           pline("Being confused, %s mispronounces the magic words...",
+                 vismon ? mon_nam(mtmp) : mhe(mtmp));
+}
+
+STATIC_OVL void
+mquaffmsg(mtmp, otmp)
+struct monst *mtmp;
+struct obj *otmp;
+{
+       if (canseemon(mtmp)) {
+               otmp->dknown = 1;
+               pline("%s drinks %s!", Monnam(mtmp), singular(otmp, doname));
+       } else
+               if (flags.soundok)
+                       You_hear("a chugging sound.");
+}
+
+/* Defines for various types of stuff.  The order in which monsters prefer
+ * to use them is determined by the order of the code logic, not the
+ * numerical order in which they are defined.
+ */
+#define MUSE_SCR_TELEPORTATION 1
+#define MUSE_WAN_TELEPORTATION_SELF 2
+#define MUSE_POT_HEALING 3
+#define MUSE_POT_EXTRA_HEALING 4
+#define MUSE_WAN_DIGGING 5
+#define MUSE_TRAPDOOR 6
+#define MUSE_TELEPORT_TRAP 7
+#define MUSE_UPSTAIRS 8
+#define MUSE_DOWNSTAIRS 9
+#define MUSE_WAN_CREATE_MONSTER 10
+#define MUSE_SCR_CREATE_MONSTER 11
+#define MUSE_UP_LADDER 12
+#define MUSE_DN_LADDER 13
+#define MUSE_SSTAIRS 14
+#define MUSE_WAN_TELEPORTATION 15
+#define MUSE_BUGLE 16
+#define MUSE_UNICORN_HORN 17
+#define MUSE_POT_FULL_HEALING 18
+#define MUSE_LIZARD_CORPSE 19
+/*
+#define MUSE_INNATE_TPT 9999
+ * We cannot use this.  Since monsters get unlimited teleportation, if they
+ * were allowed to teleport at will you could never catch them.  Instead,
+ * assume they only teleport at random times, despite the inconsistency that if
+ * you polymorph into one you teleport at will.
+ */
+
+/* Select a defensive item/action for a monster.  Returns TRUE iff one is
+ * found.
+ */
+boolean
+find_defensive(mtmp)
+struct monst *mtmp;
+{
+       register struct obj *obj = 0;
+       struct trap *t;
+       int x=mtmp->mx, y=mtmp->my;
+       boolean stuck = (mtmp == u.ustuck);
+       boolean immobile = (mtmp->data->mmove == 0);
+       int fraction;
+
+       if (is_animal(mtmp->data) || mindless(mtmp->data))
+               return FALSE;
+       if(dist2(x, y, mtmp->mux, mtmp->muy) > 25)
+               return FALSE;
+       if (u.uswallow && stuck) return FALSE;
+
+       m.defensive = (struct obj *)0;
+       m.has_defense = 0;
+
+       /* since unicorn horns don't get used up, the monster would look
+        * silly trying to use the same cursed horn round after round
+        */
+       if (mtmp->mconf || mtmp->mstun || !mtmp->mcansee) {
+           if (!is_unicorn(mtmp->data) && !nohands(mtmp->data)) {
+               for(obj = mtmp->minvent; obj; obj = obj->nobj)
+                   if (obj->otyp == UNICORN_HORN && !obj->cursed)
+                       break;
+           }
+           if (obj || is_unicorn(mtmp->data)) {
+               m.defensive = obj;
+               m.has_defense = MUSE_UNICORN_HORN;
+               return TRUE;
+           }
+       }
+
+       if (mtmp->mconf) {
+           for(obj = mtmp->minvent; obj; obj = obj->nobj) {
+               if (obj->otyp == CORPSE && obj->corpsenm == PM_LIZARD) {
+                   m.defensive = obj;
+                   m.has_defense = MUSE_LIZARD_CORPSE;
+                   return TRUE;
+               }
+           }
+       }
+
+       /* It so happens there are two unrelated cases when we might want to
+        * check specifically for healing alone.  The first is when the monster
+        * is blind (healing cures blindness).  The second is when the monster
+        * is peaceful; then we don't want to flee the player, and by
+        * coincidence healing is all there is that doesn't involve fleeing.
+        * These would be hard to combine because of the control flow.
+        * Pestilence won't use healing even when blind.
+        */
+       if (!mtmp->mcansee && !nohands(mtmp->data) &&
+               mtmp->data != &mons[PM_PESTILENCE]) {
+           if ((obj = m_carrying(mtmp, POT_FULL_HEALING)) != 0) {
+               m.defensive = obj;
+               m.has_defense = MUSE_POT_FULL_HEALING;
+               return TRUE;
+           }
+           if ((obj = m_carrying(mtmp, POT_EXTRA_HEALING)) != 0) {
+               m.defensive = obj;
+               m.has_defense = MUSE_POT_EXTRA_HEALING;
+               return TRUE;
+           }
+           if ((obj = m_carrying(mtmp, POT_HEALING)) != 0) {
+               m.defensive = obj;
+               m.has_defense = MUSE_POT_HEALING;
+               return TRUE;
+           }
+       }
+
+       fraction = u.ulevel < 10 ? 5 : u.ulevel < 14 ? 4 : 3;
+       if(mtmp->mhp >= mtmp->mhpmax ||
+                       (mtmp->mhp >= 10 && mtmp->mhp*fraction >= mtmp->mhpmax))
+               return FALSE;
+
+       if (mtmp->mpeaceful) {
+           if (!nohands(mtmp->data)) {
+               if ((obj = m_carrying(mtmp, POT_FULL_HEALING)) != 0) {
+                   m.defensive = obj;
+                   m.has_defense = MUSE_POT_FULL_HEALING;
+                   return TRUE;
+               }
+               if ((obj = m_carrying(mtmp, POT_EXTRA_HEALING)) != 0) {
+                   m.defensive = obj;
+                   m.has_defense = MUSE_POT_EXTRA_HEALING;
+                   return TRUE;
+               }
+               if ((obj = m_carrying(mtmp, POT_HEALING)) != 0) {
+                   m.defensive = obj;
+                   m.has_defense = MUSE_POT_HEALING;
+                   return TRUE;
+               }
+           }
+           return FALSE;
+       }
+
+       if (levl[x][y].typ == STAIRS && !stuck && !immobile) {
+               if (x == xdnstair && y == ydnstair && !is_floater(mtmp->data))
+                       m.has_defense = MUSE_DOWNSTAIRS;
+               if (x == xupstair && y == yupstair && ledger_no(&u.uz) != 1)
+       /* Unfair to let the monsters leave the dungeon with the Amulet */
+       /* (or go to the endlevel since you also need it, to get there) */
+                       m.has_defense = MUSE_UPSTAIRS;
+       } else if (levl[x][y].typ == LADDER && !stuck && !immobile) {
+               if (x == xupladder && y == yupladder)
+                       m.has_defense = MUSE_UP_LADDER;
+               if (x == xdnladder && y == ydnladder && !is_floater(mtmp->data))
+                       m.has_defense = MUSE_DN_LADDER;
+       } else if (sstairs.sx && sstairs.sx == x && sstairs.sy == y) {
+               m.has_defense = MUSE_SSTAIRS;
+       } else if (!stuck && !immobile) {
+       /* Note: trap doors take precedence over teleport traps. */
+               int xx, yy;
+
+               for(xx = x-1; xx <= x+1; xx++) for(yy = y-1; yy <= y+1; yy++)
+               if (isok(xx,yy))
+               if (xx != u.ux && yy != u.uy)
+               if (mtmp->data != &mons[PM_GRID_BUG] || xx == x || yy == y)
+               if ((xx==x && yy==y) || !level.monsters[xx][yy])
+               if ((t = t_at(xx,yy)) != 0)
+               if ((verysmall(mtmp->data) || throws_rocks(mtmp->data) ||
+                    passes_walls(mtmp->data)) || !sobj_at(BOULDER, xx, yy))
+               if (!onscary(xx,yy,mtmp)) {
+                       if ((t->ttyp == TRAPDOOR || t->ttyp == HOLE)
+                               && !is_floater(mtmp->data)
+                               && !mtmp->isshk && !mtmp->isgd
+                               && !mtmp->ispriest
+                               && Can_fall_thru(&u.uz)
+                                               ) {
+                               trapx = xx;
+                               trapy = yy;
+                               m.has_defense = MUSE_TRAPDOOR;
+                       } else if (t->ttyp == TELEP_TRAP && m.has_defense != MUSE_TRAPDOOR) {
+                               trapx = xx;
+                               trapy = yy;
+                               m.has_defense = MUSE_TELEPORT_TRAP;
+                       }
+               }
+       }
+
+       if (nohands(mtmp->data))        /* can't use objects */
+               goto botm;
+
+       if (is_mercenary(mtmp->data) && (obj = m_carrying(mtmp, BUGLE))) {
+               int xx, yy;
+               struct monst *mon;
+
+               /* Distance is arbitrary.  What we really want to do is
+                * have the soldier play the bugle when it sees or
+                * remembers soldiers nearby...
+                */
+               for(xx = x-3; xx <= x+3; xx++) for(yy = y-3; yy <= y+3; yy++)
+               if (isok(xx,yy))
+               if ((mon = m_at(xx,yy)) && is_mercenary(mon->data) &&
+                               mon->data != &mons[PM_GUARD] &&
+                               (mon->msleeping || (!mon->mcanmove))) {
+                       m.defensive = obj;
+                       m.has_defense = MUSE_BUGLE;
+               }
+       }
+
+       /* use immediate physical escape prior to attempting magic */
+       if (m.has_defense)    /* stairs, trap door or tele-trap, bugle alert */
+               goto botm;
+
+       /* kludge to cut down on trap destruction (particularly portals) */
+       t = t_at(x,y);
+       if (t && (t->ttyp == PIT || t->ttyp == SPIKED_PIT ||
+                 t->ttyp == WEB || t->ttyp == BEAR_TRAP))
+               t = 0;          /* ok for monster to dig here */
+
+#define nomore(x) if(m.has_defense==x) continue;
+       for (obj = mtmp->minvent; obj; obj = obj->nobj) {
+               /* don't always use the same selection pattern */
+               if (m.has_defense && !rn2(3)) break;
+
+               /* nomore(MUSE_WAN_DIGGING); */
+               if (m.has_defense == MUSE_WAN_DIGGING) break;
+               if (obj->otyp == WAN_DIGGING && obj->spe > 0 && !stuck && !t
+                   && !mtmp->isshk && !mtmp->isgd && !mtmp->ispriest
+                   && !is_floater(mtmp->data)
+                   /* monsters digging in Sokoban can ruin things */
+                   && !In_sokoban(&u.uz)
+                   /* digging wouldn't be effective; assume they know that */
+                   && !(levl[x][y].wall_info & W_NONDIGGABLE)
+                   && !(Is_botlevel(&u.uz) || In_endgame(&u.uz))
+                   && !(is_ice(x,y) || is_pool(x,y) || is_lava(x,y))
+                   && !(mtmp->data == &mons[PM_VLAD_THE_IMPALER]
+                        && In_V_tower(&u.uz))) {
+                       m.defensive = obj;
+                       m.has_defense = MUSE_WAN_DIGGING;
+               }
+               nomore(MUSE_WAN_TELEPORTATION_SELF);
+               nomore(MUSE_WAN_TELEPORTATION);
+               if(obj->otyp == WAN_TELEPORTATION && obj->spe > 0) {
+                   /* use the TELEP_TRAP bit to determine if they know
+                    * about noteleport on this level or not.  Avoids
+                    * ineffective re-use of teleportation.  This does
+                    * mean if the monster leaves the level, they'll know
+                    * about teleport traps.
+                    */
+                   if (!level.flags.noteleport ||
+                       !(mtmp->mtrapseen & (1 << (TELEP_TRAP-1)))) {
+                       m.defensive = obj;
+                       m.has_defense = (mon_has_amulet(mtmp))
+                               ? MUSE_WAN_TELEPORTATION
+                               : MUSE_WAN_TELEPORTATION_SELF;
+                   }
+               }
+               nomore(MUSE_SCR_TELEPORTATION);
+               if(obj->otyp == SCR_TELEPORTATION && mtmp->mcansee
+                  && haseyes(mtmp->data)
+                  && (!obj->cursed ||
+                      (!(mtmp->isshk && inhishop(mtmp))
+                           && !mtmp->isgd && !mtmp->ispriest))) {
+                   /* see WAN_TELEPORTATION case above */
+                   if (!level.flags.noteleport ||
+                       !(mtmp->mtrapseen & (1 << (TELEP_TRAP-1)))) {
+                       m.defensive = obj;
+                       m.has_defense = MUSE_SCR_TELEPORTATION;
+                   }
+               }
+
+           if (mtmp->data != &mons[PM_PESTILENCE]) {
+               nomore(MUSE_POT_FULL_HEALING);
+               if(obj->otyp == POT_FULL_HEALING) {
+                       m.defensive = obj;
+                       m.has_defense = MUSE_POT_FULL_HEALING;
+               }
+               nomore(MUSE_POT_EXTRA_HEALING);
+               if(obj->otyp == POT_EXTRA_HEALING) {
+                       m.defensive = obj;
+                       m.has_defense = MUSE_POT_EXTRA_HEALING;
+               }
+               nomore(MUSE_WAN_CREATE_MONSTER);
+               if(obj->otyp == WAN_CREATE_MONSTER && obj->spe > 0) {
+                       m.defensive = obj;
+                       m.has_defense = MUSE_WAN_CREATE_MONSTER;
+               }
+               nomore(MUSE_POT_HEALING);
+               if(obj->otyp == POT_HEALING) {
+                       m.defensive = obj;
+                       m.has_defense = MUSE_POT_HEALING;
+               }
+           } else {    /* Pestilence */
+               nomore(MUSE_POT_FULL_HEALING);
+               if (obj->otyp == POT_SICKNESS) {
+                       m.defensive = obj;
+                       m.has_defense = MUSE_POT_FULL_HEALING;
+               }
+               nomore(MUSE_WAN_CREATE_MONSTER);
+               if (obj->otyp == WAN_CREATE_MONSTER && obj->spe > 0) {
+                       m.defensive = obj;
+                       m.has_defense = MUSE_WAN_CREATE_MONSTER;
+               }
+           }
+               nomore(MUSE_SCR_CREATE_MONSTER);
+               if(obj->otyp == SCR_CREATE_MONSTER) {
+                       m.defensive = obj;
+                       m.has_defense = MUSE_SCR_CREATE_MONSTER;
+               }
+       }
+botm:  return((boolean)(!!m.has_defense));
+#undef nomore
+}
+
+/* Perform a defensive action for a monster.  Must be called immediately
+ * after find_defensive().  Return values are 0: did something, 1: died,
+ * 2: did something and can't attack again (i.e. teleported).
+ */
+int
+use_defensive(mtmp)
+struct monst *mtmp;
+{
+       int i, fleetim, how = 0;
+       struct obj *otmp = m.defensive;
+       boolean vis, vismon, oseen;
+       const char *mcsa = "%s can see again.";
+
+       if ((i = precheck(mtmp, otmp)) != 0) return i;
+       vis = cansee(mtmp->mx, mtmp->my);
+       vismon = canseemon(mtmp);
+       oseen = otmp && vismon;
+
+       /* when using defensive choice to run away, we want monster to avoid
+          rushing right straight back; don't override if already scared */
+       fleetim = !mtmp->mflee ? (33 - (30 * mtmp->mhp / mtmp->mhpmax)) : 0;
+#define m_flee(m)      if (fleetim && !m->iswiz) \
+                       { monflee(m, fleetim, FALSE, FALSE); }
+
+       switch(m.has_defense) {
+       case MUSE_UNICORN_HORN:
+               if (vismon) {
+                   if (otmp)
+                       pline("%s uses a unicorn horn!", Monnam(mtmp));
+                   else
+                       pline_The("tip of %s's horn glows!", mon_nam(mtmp));
+               }
+               if (!mtmp->mcansee) {
+                   mtmp->mcansee = 1;
+                   mtmp->mblinded = 0;
+                   if (vismon) pline(mcsa, Monnam(mtmp));
+               } else if (mtmp->mconf || mtmp->mstun) {
+                   mtmp->mconf = mtmp->mstun = 0;
+                   if (vismon)
+                       pline("%s seems steadier now.", Monnam(mtmp));
+               } else impossible("No need for unicorn horn?");
+               return 2;
+       case MUSE_BUGLE:
+               if (vismon)
+                       pline("%s plays %s!", Monnam(mtmp), doname(otmp));
+               else if (flags.soundok)
+                       You_hear("a bugle playing reveille!");
+               awaken_soldiers();
+               return 2;
+       case MUSE_WAN_TELEPORTATION_SELF:
+               if ((mtmp->isshk && inhishop(mtmp))
+                      || mtmp->isgd || mtmp->ispriest) return 2;
+               m_flee(mtmp);
+               mzapmsg(mtmp, otmp, TRUE);
+               otmp->spe--;
+               how = WAN_TELEPORTATION;
+mon_tele:
+               if (tele_restrict(mtmp)) {      /* mysterious force... */
+                   if (vismon && how)          /* mentions 'teleport' */
+                       makeknown(how);
+                   /* monster learns that teleportation isn't useful here */
+                   if (level.flags.noteleport)
+                       mtmp->mtrapseen |= (1 << (TELEP_TRAP-1));
+                   return 2;
+               }
+               if ((
+#if 0
+                       mon_has_amulet(mtmp) ||
+#endif
+                       On_W_tower_level(&u.uz)) && !rn2(3)) {
+                   if (vismon)
+                       pline("%s seems disoriented for a moment.",
+                               Monnam(mtmp));
+                   return 2;
+               }
+               if (oseen && how) makeknown(how);
+               (void) rloc(mtmp, FALSE);
+               return 2;
+       case MUSE_WAN_TELEPORTATION:
+               zap_oseen = oseen;
+               mzapmsg(mtmp, otmp, FALSE);
+               otmp->spe--;
+               m_using = TRUE;
+               mbhit(mtmp,rn1(8,6),mbhitm,bhito,otmp);
+               /* monster learns that teleportation isn't useful here */
+               if (level.flags.noteleport)
+                   mtmp->mtrapseen |= (1 << (TELEP_TRAP-1));
+               m_using = FALSE;
+               return 2;
+       case MUSE_SCR_TELEPORTATION:
+           {
+               int obj_is_cursed = otmp->cursed;
+
+               if (mtmp->isshk || mtmp->isgd || mtmp->ispriest) return 2;
+               m_flee(mtmp);
+               mreadmsg(mtmp, otmp);
+               m_useup(mtmp, otmp);    /* otmp might be free'ed */
+               how = SCR_TELEPORTATION;
+               if (obj_is_cursed || mtmp->mconf) {
+                       int nlev;
+                       d_level flev;
+
+                       if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
+                           if (vismon)
+                               pline("%s seems very disoriented for a moment.",
+                                       Monnam(mtmp));
+                           return 2;
+                       }
+                       nlev = random_teleport_level();
+                       if (nlev == depth(&u.uz)) {
+                           if (vismon)
+                               pline("%s shudders for a moment.",
+                                                               Monnam(mtmp));
+                           return 2;
+                       }
+                       get_level(&flev, nlev);
+                       migrate_to_level(mtmp, ledger_no(&flev), MIGR_RANDOM,
+                               (coord *)0);
+                       if (oseen) makeknown(SCR_TELEPORTATION);
+               } else goto mon_tele;
+               return 2;
+           }
+       case MUSE_WAN_DIGGING:
+           {   struct trap *ttmp;
+
+               m_flee(mtmp);
+               mzapmsg(mtmp, otmp, FALSE);
+               otmp->spe--;
+               if (oseen) makeknown(WAN_DIGGING);
+               if (IS_FURNITURE(levl[mtmp->mx][mtmp->my].typ) ||
+                   IS_DRAWBRIDGE(levl[mtmp->mx][mtmp->my].typ) ||
+                   (is_drawbridge_wall(mtmp->mx, mtmp->my) >= 0) ||
+                   (sstairs.sx && sstairs.sx == mtmp->mx &&
+                                  sstairs.sy == mtmp->my)) {
+                       pline_The("digging ray is ineffective.");
+                       return 2;
+               }
+               if (!Can_dig_down(&u.uz)) {
+                   if(canseemon(mtmp))
+                       pline_The("%s here is too hard to dig in.",
+                                       surface(mtmp->mx, mtmp->my));
+                   return 2;
+               }
+               ttmp = maketrap(mtmp->mx, mtmp->my, HOLE);
+               if (!ttmp) return 2;
+               seetrap(ttmp);
+               if (vis) {
+                   pline("%s has made a hole in the %s.", Monnam(mtmp),
+                               surface(mtmp->mx, mtmp->my));
+                   pline("%s %s through...", Monnam(mtmp),
+                         is_flyer(mtmp->data) ? "dives" : "falls");
+               } else if (flags.soundok)
+                       You_hear("%s crash through the %s.", something,
+                               surface(mtmp->mx, mtmp->my));
+               /* we made sure that there is a level for mtmp to go to */
+               migrate_to_level(mtmp, ledger_no(&u.uz) + 1,
+                                MIGR_RANDOM, (coord *)0);
+               return 2;
+           }
+       case MUSE_WAN_CREATE_MONSTER:
+           {   coord cc;
+                   /* pm: 0 => random, eel => aquatic, croc => amphibious */
+               struct permonst *pm = !is_pool(mtmp->mx, mtmp->my) ? 0 :
+                            &mons[u.uinwater ? PM_GIANT_EEL : PM_CROCODILE];
+               struct monst *mon;
+
+               if (!enexto(&cc, mtmp->mx, mtmp->my, pm)) return 0;
+               mzapmsg(mtmp, otmp, FALSE);
+               otmp->spe--;
+               mon = makemon((struct permonst *)0, cc.x, cc.y, NO_MM_FLAGS);
+               if (mon && canspotmon(mon) && oseen)
+                   makeknown(WAN_CREATE_MONSTER);
+               return 2;
+           }
+       case MUSE_SCR_CREATE_MONSTER:
+           {   coord cc;
+               struct permonst *pm = 0, *fish = 0;
+               int cnt = 1;
+               struct monst *mon;
+               boolean known = FALSE;
+
+               if (!rn2(73)) cnt += rnd(4);
+               if (mtmp->mconf || otmp->cursed) cnt += 12;
+               if (mtmp->mconf) pm = fish = &mons[PM_ACID_BLOB];
+               else if (is_pool(mtmp->mx, mtmp->my))
+                   fish = &mons[u.uinwater ? PM_GIANT_EEL : PM_CROCODILE];
+               mreadmsg(mtmp, otmp);
+               while(cnt--) {
+                   /* `fish' potentially gives bias towards water locations;
+                      `pm' is what to actually create (0 => random) */
+                   if (!enexto(&cc, mtmp->mx, mtmp->my, fish)) break;
+                   mon = makemon(pm, cc.x, cc.y, NO_MM_FLAGS);
+                   if (mon && canspotmon(mon)) known = TRUE;
+               }
+               /* The only case where we don't use oseen.  For wands, you
+                * have to be able to see the monster zap the wand to know
+                * what type it is.  For teleport scrolls, you have to see
+                * the monster to know it teleported.
+                */
+               if (known)
+                   makeknown(SCR_CREATE_MONSTER);
+               else if (!objects[SCR_CREATE_MONSTER].oc_name_known
+                       && !objects[SCR_CREATE_MONSTER].oc_uname)
+                   docall(otmp);
+               m_useup(mtmp, otmp);
+               return 2;
+           }
+       case MUSE_TRAPDOOR:
+               /* trap doors on "bottom" levels of dungeons are rock-drop
+                * trap doors, not holes in the floor.  We check here for
+                * safety.
+                */
+               if (Is_botlevel(&u.uz)) return 0;
+               m_flee(mtmp);
+               if (vis) {
+                       struct trap *t;
+                       t = t_at(trapx,trapy);
+                       pline("%s %s into a %s!", Monnam(mtmp),
+                       makeplural(locomotion(mtmp->data, "jump")),
+                       t->ttyp == TRAPDOOR ? "trap door" : "hole");
+                       if (levl[trapx][trapy].typ == SCORR) {
+                           levl[trapx][trapy].typ = CORR;
+                           unblock_point(trapx, trapy);
+                       }
+                       seetrap(t_at(trapx,trapy));
+               }
+
+               /*  don't use rloc_to() because worm tails must "move" */
+               remove_monster(mtmp->mx, mtmp->my);
+               newsym(mtmp->mx, mtmp->my);     /* update old location */
+               place_monster(mtmp, trapx, trapy);
+               if (mtmp->wormno) worm_move(mtmp);
+               newsym(trapx, trapy);
+
+               migrate_to_level(mtmp, ledger_no(&u.uz) + 1,
+                                MIGR_RANDOM, (coord *)0);
+               return 2;
+       case MUSE_UPSTAIRS:
+               /* Monsters without amulets escape the dungeon and are
+                * gone for good when they leave up the up stairs.
+                * Monsters with amulets would reach the endlevel,
+                * which we cannot allow since that would leave the
+                * player stranded.
+                */
+               if (ledger_no(&u.uz) == 1) {
+                       if (mon_has_special(mtmp))
+                               return 0;
+                       if (vismon)
+                           pline("%s escapes the dungeon!", Monnam(mtmp));
+                       mongone(mtmp);
+                       return 2;
+               }
+               m_flee(mtmp);
+               if (Inhell && mon_has_amulet(mtmp) && !rn2(4) &&
+                       (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz) - 3)) {
+                   if (vismon) pline(
+     "As %s climbs the stairs, a mysterious force momentarily surrounds %s...",
+                                    mon_nam(mtmp), mhim(mtmp));
+                   /* simpler than for the player; this will usually be
+                      the Wizard and he'll immediately go right to the
+                      upstairs, so there's not much point in having any
+                      chance for a random position on the current level */
+                   migrate_to_level(mtmp, ledger_no(&u.uz) + 1,
+                                    MIGR_RANDOM, (coord *)0);
+               } else {
+                   if (vismon) pline("%s escapes upstairs!", Monnam(mtmp));
+                   migrate_to_level(mtmp, ledger_no(&u.uz) - 1,
+                                    MIGR_STAIRS_DOWN, (coord *)0);
+               }
+               return 2;
+       case MUSE_DOWNSTAIRS:
+               m_flee(mtmp);
+               if (vismon) pline("%s escapes downstairs!", Monnam(mtmp));
+               migrate_to_level(mtmp, ledger_no(&u.uz) + 1,
+                                MIGR_STAIRS_UP, (coord *)0);
+               return 2;
+       case MUSE_UP_LADDER:
+               m_flee(mtmp);
+               if (vismon) pline("%s escapes up the ladder!", Monnam(mtmp));
+               migrate_to_level(mtmp, ledger_no(&u.uz) - 1,
+                                MIGR_LADDER_DOWN, (coord *)0);
+               return 2;
+       case MUSE_DN_LADDER:
+               m_flee(mtmp);
+               if (vismon) pline("%s escapes down the ladder!", Monnam(mtmp));
+               migrate_to_level(mtmp, ledger_no(&u.uz) + 1,
+                                MIGR_LADDER_UP, (coord *)0);
+               return 2;
+       case MUSE_SSTAIRS:
+               m_flee(mtmp);
+               /* the stairs leading up from the 1st level are */
+               /* regular stairs, not sstairs.                 */
+               if (sstairs.up) {
+                       if (vismon)
+                           pline("%s escapes upstairs!", Monnam(mtmp));
+                       if(Inhell) {
+                           migrate_to_level(mtmp, ledger_no(&sstairs.tolev),
+                                            MIGR_RANDOM, (coord *)0);
+                           return 2;
+                       }
+               } else  if (vismon)
+                   pline("%s escapes downstairs!", Monnam(mtmp));
+               migrate_to_level(mtmp, ledger_no(&sstairs.tolev),
+                                MIGR_SSTAIRS, (coord *)0);
+               return 2;
+       case MUSE_TELEPORT_TRAP:
+               m_flee(mtmp);
+               if (vis) {
+                       pline("%s %s onto a teleport trap!", Monnam(mtmp),
+                               makeplural(locomotion(mtmp->data, "jump")));
+                       if (levl[trapx][trapy].typ == SCORR) {
+                           levl[trapx][trapy].typ = CORR;
+                           unblock_point(trapx, trapy);
+                       }
+                       seetrap(t_at(trapx,trapy));
+               }
+               /*  don't use rloc_to() because worm tails must "move" */
+               remove_monster(mtmp->mx, mtmp->my);
+               newsym(mtmp->mx, mtmp->my);     /* update old location */
+               place_monster(mtmp, trapx, trapy);
+               if (mtmp->wormno) worm_move(mtmp);
+               newsym(trapx, trapy);
+
+               goto mon_tele;
+       case MUSE_POT_HEALING:
+               mquaffmsg(mtmp, otmp);
+               i = d(6 + 2 * bcsign(otmp), 4);
+               mtmp->mhp += i;
+               if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = ++mtmp->mhpmax;
+               if (!otmp->cursed && !mtmp->mcansee) {
+                       mtmp->mcansee = 1;
+                       mtmp->mblinded = 0;
+                       if (vismon) pline(mcsa, Monnam(mtmp));
+               }
+               if (vismon) pline("%s looks better.", Monnam(mtmp));
+               if (oseen) makeknown(POT_HEALING);
+               m_useup(mtmp, otmp);
+               return 2;
+       case MUSE_POT_EXTRA_HEALING:
+               mquaffmsg(mtmp, otmp);
+               i = d(6 + 2 * bcsign(otmp), 8);
+               mtmp->mhp += i;
+               if (mtmp->mhp > mtmp->mhpmax)
+                       mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 5 : 2));
+               if (!mtmp->mcansee) {
+                       mtmp->mcansee = 1;
+                       mtmp->mblinded = 0;
+                       if (vismon) pline(mcsa, Monnam(mtmp));
+               }
+               if (vismon) pline("%s looks much better.", Monnam(mtmp));
+               if (oseen) makeknown(POT_EXTRA_HEALING);
+               m_useup(mtmp, otmp);
+               return 2;
+       case MUSE_POT_FULL_HEALING:
+               mquaffmsg(mtmp, otmp);
+               if (otmp->otyp == POT_SICKNESS) unbless(otmp); /* Pestilence */
+               mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 8 : 4));
+               if (!mtmp->mcansee && otmp->otyp != POT_SICKNESS) {
+                       mtmp->mcansee = 1;
+                       mtmp->mblinded = 0;
+                       if (vismon) pline(mcsa, Monnam(mtmp));
+               }
+               if (vismon) pline("%s looks completely healed.", Monnam(mtmp));
+               if (oseen) makeknown(otmp->otyp);
+               m_useup(mtmp, otmp);
+               return 2;
+       case MUSE_LIZARD_CORPSE:
+               /* not actually called for its unstoning effect */
+               mon_consume_unstone(mtmp, otmp, FALSE, FALSE);
+               return 2;
+       case 0: return 0; /* i.e. an exploded wand */
+       default: impossible("%s wanted to perform action %d?", Monnam(mtmp),
+                       m.has_defense);
+               break;
+       }
+       return 0;
+#undef m_flee
+}
+
+int
+rnd_defensive_item(mtmp)
+struct monst *mtmp;
+{
+       struct permonst *pm = mtmp->data;
+       int difficulty = monstr[(monsndx(pm))];
+       int trycnt = 0;
+
+       if(is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data)
+                       || pm->mlet == S_GHOST
+# ifdef KOPS
+                       || pm->mlet == S_KOP
+# endif
+               ) return 0;
+    try_again:
+       switch (rn2(8 + (difficulty > 3) + (difficulty > 6) +
+                               (difficulty > 8))) {
+               case 6: case 9:
+                       if (level.flags.noteleport && ++trycnt < 2)
+                           goto try_again;
+                       if (!rn2(3)) return WAN_TELEPORTATION;
+                       /* else FALLTHRU */
+               case 0: case 1:
+                       return SCR_TELEPORTATION;
+               case 8: case 10:
+                       if (!rn2(3)) return WAN_CREATE_MONSTER;
+                       /* else FALLTHRU */
+               case 2: return SCR_CREATE_MONSTER;
+               case 3: return POT_HEALING;
+               case 4: return POT_EXTRA_HEALING;
+               case 5: return (mtmp->data != &mons[PM_PESTILENCE]) ?
+                               POT_FULL_HEALING : POT_SICKNESS;
+               case 7: if (is_floater(pm) || mtmp->isshk || mtmp->isgd
+                                               || mtmp->ispriest
+                                                                       )
+                               return 0;
+                       else
+                               return WAN_DIGGING;
+       }
+       /*NOTREACHED*/
+       return 0;
+}
+
+#define MUSE_WAN_DEATH 1
+#define MUSE_WAN_SLEEP 2
+#define MUSE_WAN_FIRE 3
+#define MUSE_WAN_COLD 4
+#define MUSE_WAN_LIGHTNING 5
+#define MUSE_WAN_MAGIC_MISSILE 6
+#define MUSE_WAN_STRIKING 7
+#define MUSE_SCR_FIRE 8
+#define MUSE_POT_PARALYSIS 9
+#define MUSE_POT_BLINDNESS 10
+#define MUSE_POT_CONFUSION 11
+#define MUSE_FROST_HORN 12
+#define MUSE_FIRE_HORN 13
+#define MUSE_POT_ACID 14
+/*#define MUSE_WAN_TELEPORTATION 15*/
+#define MUSE_POT_SLEEPING 16
+#define MUSE_SCR_EARTH 17
+
+/* Select an offensive item/action for a monster.  Returns TRUE iff one is
+ * found.
+ */
+boolean
+find_offensive(mtmp)
+struct monst *mtmp;
+{
+       register struct obj *obj;
+       boolean ranged_stuff = lined_up(mtmp);
+       boolean reflection_skip = (Reflecting && rn2(2));
+       struct obj *helmet = which_armor(mtmp, W_ARMH);
+
+       m.offensive = (struct obj *)0;
+       m.has_offense = 0;
+       if (mtmp->mpeaceful || is_animal(mtmp->data) ||
+                               mindless(mtmp->data) || nohands(mtmp->data))
+               return FALSE;
+       if (u.uswallow) return FALSE;
+       if (in_your_sanctuary(mtmp, 0, 0)) return FALSE;
+       if (dmgtype(mtmp->data, AD_HEAL) && !uwep
+#ifdef TOURIST
+           && !uarmu
+#endif
+           && !uarm && !uarmh && !uarms && !uarmg && !uarmc && !uarmf)
+               return FALSE;
+
+       if (!ranged_stuff) return FALSE;
+#define nomore(x) if(m.has_offense==x) continue;
+       for(obj=mtmp->minvent; obj; obj=obj->nobj) {
+               /* nomore(MUSE_WAN_DEATH); */
+               if (!reflection_skip) {
+                   if(obj->otyp == WAN_DEATH && obj->spe > 0) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_WAN_DEATH;
+                   }
+                   nomore(MUSE_WAN_SLEEP);
+                   if(obj->otyp == WAN_SLEEP && obj->spe > 0 && multi >= 0) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_WAN_SLEEP;
+                   }
+                   nomore(MUSE_WAN_FIRE);
+                   if(obj->otyp == WAN_FIRE && obj->spe > 0) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_WAN_FIRE;
+                   }
+                   nomore(MUSE_FIRE_HORN);
+                   if(obj->otyp == FIRE_HORN && obj->spe > 0) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_FIRE_HORN;
+                   }
+                   nomore(MUSE_WAN_COLD);
+                   if(obj->otyp == WAN_COLD && obj->spe > 0) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_WAN_COLD;
+                   }
+                   nomore(MUSE_FROST_HORN);
+                   if(obj->otyp == FROST_HORN && obj->spe > 0) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_FROST_HORN;
+                   }
+                   nomore(MUSE_WAN_LIGHTNING);
+                   if(obj->otyp == WAN_LIGHTNING && obj->spe > 0) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_WAN_LIGHTNING;
+                   }
+                   nomore(MUSE_WAN_MAGIC_MISSILE);
+                   if(obj->otyp == WAN_MAGIC_MISSILE && obj->spe > 0) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_WAN_MAGIC_MISSILE;
+                   }
+               }
+               nomore(MUSE_WAN_STRIKING);
+               if(obj->otyp == WAN_STRIKING && obj->spe > 0) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_WAN_STRIKING;
+               }
+               nomore(MUSE_POT_PARALYSIS);
+               if(obj->otyp == POT_PARALYSIS && multi >= 0) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_POT_PARALYSIS;
+               }
+               nomore(MUSE_POT_BLINDNESS);
+               if(obj->otyp == POT_BLINDNESS && !attacktype(mtmp->data, AT_GAZE)) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_POT_BLINDNESS;
+               }
+               nomore(MUSE_POT_CONFUSION);
+               if(obj->otyp == POT_CONFUSION) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_POT_CONFUSION;
+               }
+               nomore(MUSE_POT_SLEEPING);
+               if(obj->otyp == POT_SLEEPING) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_POT_SLEEPING;
+               }
+               nomore(MUSE_POT_ACID);
+               if(obj->otyp == POT_ACID) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_POT_ACID;
+               }
+               /* we can safely put this scroll here since the locations that
+                * are in a 1 square radius are a subset of the locations that
+                * are in wand range
+                */
+               nomore(MUSE_SCR_EARTH);
+               if (obj->otyp == SCR_EARTH
+                      && ((helmet && is_metallic(helmet)) ||
+                               mtmp->mconf || amorphous(mtmp->data) ||
+                               passes_walls(mtmp->data) ||
+                               noncorporeal(mtmp->data) ||
+                               unsolid(mtmp->data) || !rn2(10))
+                      && dist2(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy) <= 2
+                      && mtmp->mcansee && haseyes(mtmp->data)
+#ifdef REINCARNATION
+                      && !Is_rogue_level(&u.uz)
+#endif
+                      && (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) {
+                   m.offensive = obj;
+                   m.has_offense = MUSE_SCR_EARTH;
+               }
+#if 0
+               nomore(MUSE_SCR_FIRE);
+               if (obj->otyp == SCR_FIRE && resists_fire(mtmp)
+                  && dist2(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy) <= 2
+                  && mtmp->mcansee && haseyes(mtmp->data)) {
+                       m.offensive = obj;
+                       m.has_offense = MUSE_SCR_FIRE;
+               }
+#endif
+       }
+       return((boolean)(!!m.has_offense));
+#undef nomore
+}
+
+STATIC_PTR
+int
+mbhitm(mtmp, otmp)
+register struct monst *mtmp;
+register struct obj *otmp;
+{
+       int tmp;
+
+       boolean reveal_invis = FALSE;
+       if (mtmp != &youmonst) {
+               mtmp->msleeping = 0;
+               if (mtmp->m_ap_type) seemimic(mtmp);
+       }
+       switch(otmp->otyp) {
+       case WAN_STRIKING:
+               reveal_invis = TRUE;
+               if (mtmp == &youmonst) {
+                       if (zap_oseen) makeknown(WAN_STRIKING);
+                       if (Antimagic) {
+                           shieldeff(u.ux, u.uy);
+                           pline("Boing!");
+                       } else if (rnd(20) < 10 + u.uac) {
+                           pline_The("wand hits you!");
+                           tmp = d(2,12);
+                           if(Half_spell_damage) tmp = (tmp+1) / 2;
+                           losehp(tmp, "wand", KILLED_BY_AN);
+                       } else pline_The("wand misses you.");
+                       stop_occupation();
+                       nomul(0);
+               } else if (resists_magm(mtmp)) {
+                       shieldeff(mtmp->mx, mtmp->my);
+                       pline("Boing!");
+               } else if (rnd(20) < 10+find_mac(mtmp)) {
+                       tmp = d(2,12);
+                       hit("wand", mtmp, exclam(tmp));
+                       (void) resist(mtmp, otmp->oclass, tmp, TELL);
+                       if (cansee(mtmp->mx, mtmp->my) && zap_oseen)
+                               makeknown(WAN_STRIKING);
+               } else {
+                       miss("wand", mtmp);
+                       if (cansee(mtmp->mx, mtmp->my) && zap_oseen)
+                               makeknown(WAN_STRIKING);
+               }
+               break;
+       case WAN_TELEPORTATION:
+               if (mtmp == &youmonst) {
+                       if (zap_oseen) makeknown(WAN_TELEPORTATION);
+                       tele();
+               } else {
+                       /* for consistency with zap.c, don't identify */
+                       if (mtmp->ispriest &&
+                               *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) {
+                           if (cansee(mtmp->mx, mtmp->my))
+                               pline("%s resists the magic!", Monnam(mtmp));
+                           mtmp->msleeping = 0;
+                           if(mtmp->m_ap_type) seemimic(mtmp);
+                       } else if (!tele_restrict(mtmp))
+                           (void) rloc(mtmp, FALSE);
+               }
+               break;
+       case WAN_CANCELLATION:
+       case SPE_CANCELLATION:
+               (void) cancel_monst(mtmp, otmp, FALSE, TRUE, FALSE);
+               break;
+       }
+       if (reveal_invis) {
+           if (mtmp->mhp > 0 && cansee(bhitpos.x,bhitpos.y)
+                                                       && !canspotmon(mtmp))
+               map_invisible(bhitpos.x, bhitpos.y);
+       }
+       return 0;
+}
+
+/* A modified bhit() for monsters.  Based on bhit() in zap.c.  Unlike
+ * buzz(), bhit() doesn't take into account the possibility of a monster
+ * zapping you, so we need a special function for it.  (Unless someone wants
+ * to merge the two functions...)
+ */
+STATIC_OVL void
+mbhit(mon,range,fhitm,fhito,obj)
+struct monst *mon;                     /* monster shooting the wand */
+register int range;                    /* direction and range */
+int FDECL((*fhitm),(MONST_P,OBJ_P));
+int FDECL((*fhito),(OBJ_P,OBJ_P));     /* fns called when mon/obj hit */
+struct obj *obj;                       /* 2nd arg to fhitm/fhito */
+{
+       register struct monst *mtmp;
+       register struct obj *otmp;
+       register uchar typ;
+       int ddx, ddy;
+
+       bhitpos.x = mon->mx;
+       bhitpos.y = mon->my;
+       ddx = sgn(mon->mux - mon->mx);
+       ddy = sgn(mon->muy - mon->my);
+
+       while(range-- > 0) {
+               int x,y;
+
+               bhitpos.x += ddx;
+               bhitpos.y += ddy;
+               x = bhitpos.x; y = bhitpos.y;
+
+               if (!isok(x,y)) {
+                   bhitpos.x -= ddx;
+                   bhitpos.y -= ddy;
+                   break;
+               }
+               if (find_drawbridge(&x,&y))
+                   switch (obj->otyp) {
+                       case WAN_STRIKING:
+                           destroy_drawbridge(x,y);
+                   }
+               if(bhitpos.x==u.ux && bhitpos.y==u.uy) {
+                       (*fhitm)(&youmonst, obj);
+                       range -= 3;
+               } else if(MON_AT(bhitpos.x, bhitpos.y)){
+                       mtmp = m_at(bhitpos.x,bhitpos.y);
+                       if (cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp))
+                           map_invisible(bhitpos.x, bhitpos.y);
+                       (*fhitm)(mtmp, obj);
+                       range -= 3;
+               }
+               /* modified by GAN to hit all objects */
+               if(fhito){
+                   int hitanything = 0;
+                   register struct obj *next_obj;
+
+                   for(otmp = level.objects[bhitpos.x][bhitpos.y];
+                                                       otmp; otmp = next_obj) {
+                       /* Fix for polymorph bug, Tim Wright */
+                       next_obj = otmp->nexthere;
+                       hitanything += (*fhito)(otmp, obj);
+                   }
+                   if(hitanything)     range--;
+               }
+               typ = levl[bhitpos.x][bhitpos.y].typ;
+               if(IS_DOOR(typ) || typ == SDOOR) {
+                   switch (obj->otyp) {
+                       /* note: monsters don't use opening or locking magic
+                          at present, but keep these as placeholders */
+                       case WAN_OPENING:
+                       case WAN_LOCKING:
+                       case WAN_STRIKING:
+                           if (doorlock(obj, bhitpos.x, bhitpos.y)) {
+                               makeknown(obj->otyp);
+                               /* if a shop door gets broken, add it to
+                                  the shk's fix list (no cost to player) */
+                               if (levl[bhitpos.x][bhitpos.y].doormask ==
+                                       D_BROKEN &&
+                                   *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE))
+                                   add_damage(bhitpos.x, bhitpos.y, 0L);
+                           }
+                           break;
+                   }
+               }
+               if(!ZAP_POS(typ) || (IS_DOOR(typ) &&
+                  (levl[bhitpos.x][bhitpos.y].doormask & (D_LOCKED | D_CLOSED)))
+                 ) {
+                       bhitpos.x -= ddx;
+                       bhitpos.y -= ddy;
+                       break;
+               }
+       }
+}
+
+/* Perform an offensive action for a monster.  Must be called immediately
+ * after find_offensive().  Return values are same as use_defensive().
+ */
+int
+use_offensive(mtmp)
+struct monst *mtmp;
+{
+       int i;
+       struct obj *otmp = m.offensive;
+       boolean oseen;
+
+       /* offensive potions are not drunk, they're thrown */
+       if (otmp->oclass != POTION_CLASS && (i = precheck(mtmp, otmp)) != 0)
+               return i;
+       oseen = otmp && canseemon(mtmp);
+
+       switch(m.has_offense) {
+       case MUSE_WAN_DEATH:
+       case MUSE_WAN_SLEEP:
+       case MUSE_WAN_FIRE:
+       case MUSE_WAN_COLD:
+       case MUSE_WAN_LIGHTNING:
+       case MUSE_WAN_MAGIC_MISSILE:
+               mzapmsg(mtmp, otmp, FALSE);
+               otmp->spe--;
+               if (oseen) makeknown(otmp->otyp);
+               m_using = TRUE;
+               buzz((int)(-30 - (otmp->otyp - WAN_MAGIC_MISSILE)),
+                       (otmp->otyp == WAN_MAGIC_MISSILE) ? 2 : 6,
+                       mtmp->mx, mtmp->my,
+                       sgn(mtmp->mux-mtmp->mx), sgn(mtmp->muy-mtmp->my));
+               m_using = FALSE;
+               return (mtmp->mhp <= 0) ? 1 : 2;
+       case MUSE_FIRE_HORN:
+       case MUSE_FROST_HORN:
+               if (oseen) {
+                       makeknown(otmp->otyp);
+                       pline("%s plays a %s!", Monnam(mtmp), xname(otmp));
+               } else
+                       You_hear("a horn being played.");
+               otmp->spe--;
+               m_using = TRUE;
+               buzz(-30 - ((otmp->otyp==FROST_HORN) ? AD_COLD-1 : AD_FIRE-1),
+                       rn1(6,6), mtmp->mx, mtmp->my,
+                       sgn(mtmp->mux-mtmp->mx), sgn(mtmp->muy-mtmp->my));
+               m_using = FALSE;
+               return (mtmp->mhp <= 0) ? 1 : 2;
+       case MUSE_WAN_TELEPORTATION:
+       case MUSE_WAN_STRIKING:
+               zap_oseen = oseen;
+               mzapmsg(mtmp, otmp, FALSE);
+               otmp->spe--;
+               m_using = TRUE;
+               mbhit(mtmp,rn1(8,6),mbhitm,bhito,otmp);
+               m_using = FALSE;
+               return 2;
+       case MUSE_SCR_EARTH:
+           {
+               /* TODO: handle steeds */
+               register int x, y;
+               /* don't use monster fields after killing it */
+               boolean confused = (mtmp->mconf ? TRUE : FALSE);
+               int mmx = mtmp->mx, mmy = mtmp->my;
+
+               mreadmsg(mtmp, otmp);
+               /* Identify the scroll */
+               if (canspotmon(mtmp)) {
+                   pline_The("%s rumbles %s %s!", ceiling(mtmp->mx, mtmp->my),
+                               otmp->blessed ? "around" : "above",
+                               mon_nam(mtmp));
+                   if (oseen) makeknown(otmp->otyp);
+               } else if (cansee(mtmp->mx, mtmp->my)) {
+                   pline_The("%s rumbles in the middle of nowhere!",
+                       ceiling(mtmp->mx, mtmp->my));
+                   if (mtmp->minvis)
+                       map_invisible(mtmp->mx, mtmp->my);
+                   if (oseen) makeknown(otmp->otyp);
+               }
+
+               /* Loop through the surrounding squares */
+               for (x = mmx-1; x <= mmx+1; x++) {
+                   for (y = mmy-1; y <= mmy+1; y++) {
+                       /* Is this a suitable spot? */
+                       if (isok(x, y) && !closed_door(x, y) &&
+                                       !IS_ROCK(levl[x][y].typ) &&
+                                       !IS_AIR(levl[x][y].typ) &&
+                                       (((x == mmx) && (y == mmy)) ?
+                                           !otmp->blessed : !otmp->cursed) &&
+                                       (x != u.ux || y != u.uy)) {
+                           register struct obj *otmp2;
+                           register struct monst *mtmp2;
+
+                           /* Make the object(s) */
+                           otmp2 = mksobj(confused ? ROCK : BOULDER,
+                                       FALSE, FALSE);
+                           if (!otmp2) continue;  /* Shouldn't happen */
+                           otmp2->quan = confused ? rn1(5,2) : 1;
+                           otmp2->owt = weight(otmp2);
+
+                           /* Find the monster here (might be same as mtmp) */
+                           mtmp2 = m_at(x, y);
+                           if (mtmp2 && !amorphous(mtmp2->data) &&
+                                       !passes_walls(mtmp2->data) &&
+                                       !noncorporeal(mtmp2->data) &&
+                                       !unsolid(mtmp2->data)) {
+                               struct obj *helmet = which_armor(mtmp2, W_ARMH);
+                               int mdmg;
+
+                               if (cansee(mtmp2->mx, mtmp2->my)) {
+                                   pline("%s is hit by %s!", Monnam(mtmp2),
+                                               doname(otmp2));
+                                   if (mtmp2->minvis && !canspotmon(mtmp2))
+                                       map_invisible(mtmp2->mx, mtmp2->my);
+                               }
+                               mdmg = dmgval(otmp2, mtmp2) * otmp2->quan;
+                               if (helmet) {
+                                   if(is_metallic(helmet)) {
+                                       if (canspotmon(mtmp2))
+                                           pline("Fortunately, %s is wearing a hard helmet.", mon_nam(mtmp2));
+                                       else if (flags.soundok)
+                                           You_hear("a clanging sound.");
+                                       if (mdmg > 2) mdmg = 2;
+                                   } else {
+                                       if (canspotmon(mtmp2))
+                                           pline("%s's %s does not protect %s.",
+                                               Monnam(mtmp2), xname(helmet),
+                                               mhim(mtmp2));
+                                   }
+                               }
+                               mtmp2->mhp -= mdmg;
+                               if (mtmp2->mhp <= 0) {
+                                   pline("%s is killed.", Monnam(mtmp2));
+                                   mondied(mtmp2);
+                               }
+                           }
+                           /* Drop the rock/boulder to the floor */
+                           if (!flooreffects(otmp2, x, y, "fall")) {
+                               place_object(otmp2, x, y);
+                               stackobj(otmp2);
+                               newsym(x, y);  /* map the rock */
+                           }
+                       }
+                   }
+               }
+               m_useup(mtmp, otmp);
+               /* Attack the player */
+               if (distmin(mmx, mmy, u.ux, u.uy) == 1 && !otmp->cursed) {
+                   int dmg;
+                   struct obj *otmp2;
+
+                   /* Okay, _you_ write this without repeating the code */
+                   otmp2 = mksobj(confused ? ROCK : BOULDER,
+                               FALSE, FALSE);
+                   if (!otmp2) goto xxx_noobj;  /* Shouldn't happen */
+                   otmp2->quan = confused ? rn1(5,2) : 1;
+                   otmp2->owt = weight(otmp2);
+                   if (!amorphous(youmonst.data) &&
+                           !Passes_walls &&
+                           !noncorporeal(youmonst.data) &&
+                           !unsolid(youmonst.data)) {
+                       You("are hit by %s!", doname(otmp2));
+                       dmg = dmgval(otmp2, &youmonst) * otmp2->quan;
+                       if (uarmh) {
+                           if(is_metallic(uarmh)) {
+                               pline("Fortunately, you are wearing a hard helmet.");
+                               if (dmg > 2) dmg = 2;
+                           } else if (flags.verbose) {
+                               Your("%s does not protect you.",
+                                               xname(uarmh));
+                           }
+                       }
+                   } else
+                       dmg = 0;
+                   if (!flooreffects(otmp2, u.ux, u.uy, "fall")) {
+                       place_object(otmp2, u.ux, u.uy);
+                       stackobj(otmp2);
+                       newsym(u.ux, u.uy);
+                   }
+                   if (dmg) losehp(dmg, "scroll of earth", KILLED_BY_AN);
+               }
+           xxx_noobj:
+
+               return (mtmp->mhp <= 0) ? 1 : 2;
+           }
+#if 0
+       case MUSE_SCR_FIRE:
+             {
+               boolean vis = cansee(mtmp->mx, mtmp->my);
+
+               mreadmsg(mtmp, otmp);
+               if (mtmp->mconf) {
+                       if (vis)
+                           pline("Oh, what a pretty fire!");
+               } else {
+                       struct monst *mtmp2;
+                       int num;
+
+                       if (vis)
+                           pline_The("scroll erupts in a tower of flame!");
+                       shieldeff(mtmp->mx, mtmp->my);
+                       pline("%s is uninjured.", Monnam(mtmp));
+                       (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE);
+                       (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE);
+                       (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE);
+                       num = (2*(rn1(3, 3) + 2 * bcsign(otmp)) + 1)/3;
+                       if (Fire_resistance)
+                           You("are not harmed.");
+                       burn_away_slime();
+                       if (Half_spell_damage) num = (num+1) / 2;
+                       else losehp(num, "scroll of fire", KILLED_BY_AN);
+                       for(mtmp2 = fmon; mtmp2; mtmp2 = mtmp2->nmon) {
+                          if(DEADMONSTER(mtmp2)) continue;
+                          if(mtmp == mtmp2) continue;
+                          if(dist2(mtmp2->mx,mtmp2->my,mtmp->mx,mtmp->my) < 3){
+                               if (resists_fire(mtmp2)) continue;
+                               mtmp2->mhp -= num;
+                               if (resists_cold(mtmp2))
+                                   mtmp2->mhp -= 3*num;
+                               if(mtmp2->mhp < 1) {
+                                   mondied(mtmp2);
+                                   break;
+                               }
+                           }
+                       }
+               }
+               return 2;
+             }
+#endif /* 0 */
+       case MUSE_POT_PARALYSIS:
+       case MUSE_POT_BLINDNESS:
+       case MUSE_POT_CONFUSION:
+       case MUSE_POT_SLEEPING:
+       case MUSE_POT_ACID:
+               /* Note: this setting of dknown doesn't suffice.  A monster
+                * which is out of sight might throw and it hits something _in_
+                * sight, a problem not existing with wands because wand rays
+                * are not objects.  Also set dknown in mthrowu.c.
+                */
+               if (cansee(mtmp->mx, mtmp->my)) {
+                       otmp->dknown = 1;
+                       pline("%s hurls %s!", Monnam(mtmp),
+                                               singular(otmp, doname));
+               }
+               m_throw(mtmp, mtmp->mx, mtmp->my, sgn(mtmp->mux-mtmp->mx),
+                       sgn(mtmp->muy-mtmp->my),
+                       distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy), otmp);
+               return 2;
+       case 0: return 0; /* i.e. an exploded wand */
+       default: impossible("%s wanted to perform action %d?", Monnam(mtmp),
+                       m.has_offense);
+               break;
+       }
+       return 0;
+}
+
+int
+rnd_offensive_item(mtmp)
+struct monst *mtmp;
+{
+       struct permonst *pm = mtmp->data;
+       int difficulty = monstr[(monsndx(pm))];
+
+       if(is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data)
+                       || pm->mlet == S_GHOST
+# ifdef KOPS
+                       || pm->mlet == S_KOP
+# endif
+               ) return 0;
+       if (difficulty > 7 && !rn2(35)) return WAN_DEATH;
+       switch (rn2(9 - (difficulty < 4) + 4 * (difficulty > 6))) {
+               case 0: {
+                   struct obj *helmet = which_armor(mtmp, W_ARMH);
+
+                   if ((helmet && is_metallic(helmet)) || amorphous(pm) || passes_walls(pm) || noncorporeal(pm) || unsolid(pm))
+                       return SCR_EARTH;
+               } /* fall through */
+               case 1: return WAN_STRIKING;
+               case 2: return POT_ACID;
+               case 3: return POT_CONFUSION;
+               case 4: return POT_BLINDNESS;
+               case 5: return POT_SLEEPING;
+               case 6: return POT_PARALYSIS;
+               case 7: case 8:
+                       return WAN_MAGIC_MISSILE;
+               case 9: return WAN_SLEEP;
+               case 10: return WAN_FIRE;
+               case 11: return WAN_COLD;
+               case 12: return WAN_LIGHTNING;
+       }
+       /*NOTREACHED*/
+       return 0;
+}
+
+#define MUSE_POT_GAIN_LEVEL 1
+#define MUSE_WAN_MAKE_INVISIBLE 2
+#define MUSE_POT_INVISIBILITY 3
+#define MUSE_POLY_TRAP 4
+#define MUSE_WAN_POLYMORPH 5
+#define MUSE_POT_SPEED 6
+#define MUSE_WAN_SPEED_MONSTER 7
+#define MUSE_BULLWHIP 8
+#define MUSE_POT_POLYMORPH 9
+
+boolean
+find_misc(mtmp)
+struct monst *mtmp;
+{
+       register struct obj *obj;
+       struct permonst *mdat = mtmp->data;
+       int x = mtmp->mx, y = mtmp->my;
+       struct trap *t;
+       int xx, yy;
+       boolean immobile = (mdat->mmove == 0);
+       boolean stuck = (mtmp == u.ustuck);
+
+       m.misc = (struct obj *)0;
+       m.has_misc = 0;
+       if (is_animal(mdat) || mindless(mdat))
+               return 0;
+       if (u.uswallow && stuck) return FALSE;
+
+       /* We arbitrarily limit to times when a player is nearby for the
+        * same reason as Junior Pac-Man doesn't have energizers eaten until
+        * you can see them...
+        */
+       if(dist2(x, y, mtmp->mux, mtmp->muy) > 36)
+               return FALSE;
+
+       if (!stuck && !immobile && !mtmp->cham && monstr[monsndx(mdat)] < 6) {
+         boolean ignore_boulders = (verysmall(mdat) ||
+                                    throws_rocks(mdat) ||
+                                    passes_walls(mdat));
+         for(xx = x-1; xx <= x+1; xx++)
+           for(yy = y-1; yy <= y+1; yy++)
+               if (isok(xx,yy) && (xx != u.ux || yy != u.uy))
+                   if (mdat != &mons[PM_GRID_BUG] || xx == x || yy == y)
+                       if (/* (xx==x && yy==y) || */ !level.monsters[xx][yy])
+                           if ((t = t_at(xx, yy)) != 0 &&
+                             (ignore_boulders || !sobj_at(BOULDER, xx, yy))
+                             && !onscary(xx, yy, mtmp)) {
+                               if (t->ttyp == POLY_TRAP) {
+                                   trapx = xx;
+                                   trapy = yy;
+                                   m.has_misc = MUSE_POLY_TRAP;
+                                   return TRUE;
+                               }
+                           }
+       }
+       if (nohands(mdat))
+               return 0;
+
+#define nomore(x) if(m.has_misc==x) continue;
+       for(obj=mtmp->minvent; obj; obj=obj->nobj) {
+               /* Monsters shouldn't recognize cursed items; this kludge is */
+               /* necessary to prevent serious problems though... */
+               if(obj->otyp == POT_GAIN_LEVEL && (!obj->cursed ||
+                           (!mtmp->isgd && !mtmp->isshk && !mtmp->ispriest))) {
+                       m.misc = obj;
+                       m.has_misc = MUSE_POT_GAIN_LEVEL;
+               }
+               nomore(MUSE_BULLWHIP);
+               if(obj->otyp == BULLWHIP && (MON_WEP(mtmp) == obj) &&
+                  distu(mtmp->mx,mtmp->my)==1 && uwep && !mtmp->mpeaceful) {
+                       m.misc = obj;
+                       m.has_misc = MUSE_BULLWHIP;
+               }
+               /* Note: peaceful/tame monsters won't make themselves
+                * invisible unless you can see them.  Not really right, but...
+                */
+               nomore(MUSE_WAN_MAKE_INVISIBLE);
+               if(obj->otyp == WAN_MAKE_INVISIBLE && obj->spe > 0 &&
+                   !mtmp->minvis && !mtmp->invis_blkd &&
+                   (!mtmp->mpeaceful || See_invisible) &&
+                   (!attacktype(mtmp->data, AT_GAZE) || mtmp->mcan)) {
+                       m.misc = obj;
+                       m.has_misc = MUSE_WAN_MAKE_INVISIBLE;
+               }
+               nomore(MUSE_POT_INVISIBILITY);
+               if(obj->otyp == POT_INVISIBILITY &&
+                   !mtmp->minvis && !mtmp->invis_blkd &&
+                   (!mtmp->mpeaceful || See_invisible) &&
+                   (!attacktype(mtmp->data, AT_GAZE) || mtmp->mcan)) {
+                       m.misc = obj;
+                       m.has_misc = MUSE_POT_INVISIBILITY;
+               }
+               nomore(MUSE_WAN_SPEED_MONSTER);
+               if(obj->otyp == WAN_SPEED_MONSTER && obj->spe > 0
+                               && mtmp->mspeed != MFAST && !mtmp->isgd) {
+                       m.misc = obj;
+                       m.has_misc = MUSE_WAN_SPEED_MONSTER;
+               }
+               nomore(MUSE_POT_SPEED);
+               if(obj->otyp == POT_SPEED && mtmp->mspeed != MFAST
+                                                       && !mtmp->isgd) {
+                       m.misc = obj;
+                       m.has_misc = MUSE_POT_SPEED;
+               }
+               nomore(MUSE_WAN_POLYMORPH);
+               if(obj->otyp == WAN_POLYMORPH && obj->spe > 0 && !mtmp->cham
+                               && monstr[monsndx(mdat)] < 6) {
+                       m.misc = obj;
+                       m.has_misc = MUSE_WAN_POLYMORPH;
+               }
+               nomore(MUSE_POT_POLYMORPH);
+               if(obj->otyp == POT_POLYMORPH && !mtmp->cham
+                               && monstr[monsndx(mdat)] < 6) {
+                       m.misc = obj;
+                       m.has_misc = MUSE_POT_POLYMORPH;
+               }
+       }
+       return((boolean)(!!m.has_misc));
+#undef nomore
+}
+
+/* type of monster to polymorph into; defaults to one suitable for the
+   current level rather than the totally arbitrary choice of newcham() */
+static struct permonst *
+muse_newcham_mon(mon)
+struct monst *mon;
+{
+       struct obj *m_armr;
+
+       if ((m_armr = which_armor(mon, W_ARM)) != 0) {
+           if (Is_dragon_scales(m_armr))
+               return Dragon_scales_to_pm(m_armr);
+           else if (Is_dragon_mail(m_armr))
+               return Dragon_mail_to_pm(m_armr);
+       }
+       return rndmonst();
+}
+
+int
+use_misc(mtmp)
+struct monst *mtmp;
+{
+       int i;
+       struct obj *otmp = m.misc;
+       boolean vis, vismon, oseen;
+       char nambuf[BUFSZ];
+
+       if ((i = precheck(mtmp, otmp)) != 0) return i;
+       vis = cansee(mtmp->mx, mtmp->my);
+       vismon = canseemon(mtmp);
+       oseen = otmp && vismon;
+
+       switch(m.has_misc) {
+       case MUSE_POT_GAIN_LEVEL:
+               mquaffmsg(mtmp, otmp);
+               if (otmp->cursed) {
+                   if (Can_rise_up(mtmp->mx, mtmp->my, &u.uz)) {
+                       register int tolev = depth(&u.uz)-1;
+                       d_level tolevel;
+
+                       get_level(&tolevel, tolev);
+                       /* insurance against future changes... */
+                       if(on_level(&tolevel, &u.uz)) goto skipmsg;
+                       if (vismon) {
+                           pline("%s rises up, through the %s!",
+                                 Monnam(mtmp), ceiling(mtmp->mx, mtmp->my));
+                           if(!objects[POT_GAIN_LEVEL].oc_name_known
+                             && !objects[POT_GAIN_LEVEL].oc_uname)
+                               docall(otmp);
+                       }
+                       m_useup(mtmp, otmp);
+                       migrate_to_level(mtmp, ledger_no(&tolevel),
+                                        MIGR_RANDOM, (coord *)0);
+                       return 2;
+                   } else {
+skipmsg:
+                       if (vismon) {
+                           pline("%s looks uneasy.", Monnam(mtmp));
+                           if(!objects[POT_GAIN_LEVEL].oc_name_known
+                             && !objects[POT_GAIN_LEVEL].oc_uname)
+                               docall(otmp);
+                       }
+                       m_useup(mtmp, otmp);
+                       return 2;
+                   }
+               }
+               if (vismon) pline("%s seems more experienced.", Monnam(mtmp));
+               if (oseen) makeknown(POT_GAIN_LEVEL);
+               m_useup(mtmp, otmp);
+               if (!grow_up(mtmp,(struct monst *)0)) return 1;
+                       /* grew into genocided monster */
+               return 2;
+       case MUSE_WAN_MAKE_INVISIBLE:
+       case MUSE_POT_INVISIBILITY:
+               if (otmp->otyp == WAN_MAKE_INVISIBLE) {
+                   mzapmsg(mtmp, otmp, TRUE);
+                   otmp->spe--;
+               } else
+                   mquaffmsg(mtmp, otmp);
+               /* format monster's name before altering its visibility */
+               Strcpy(nambuf, See_invisible ? Monnam(mtmp) : mon_nam(mtmp));
+               mon_set_minvis(mtmp);
+               if (vismon && mtmp->minvis) {   /* was seen, now invisible */
+                   if (See_invisible)
+                       pline("%s body takes on a %s transparency.",
+                             s_suffix(nambuf),
+                             Hallucination ? "normal" : "strange");
+                   else
+                       pline("Suddenly you cannot see %s.", nambuf);
+                   if (oseen) makeknown(otmp->otyp);
+               }
+               if (otmp->otyp == POT_INVISIBILITY) {
+                   if (otmp->cursed) you_aggravate(mtmp);
+                   m_useup(mtmp, otmp);
+               }
+               return 2;
+       case MUSE_WAN_SPEED_MONSTER:
+               mzapmsg(mtmp, otmp, TRUE);
+               otmp->spe--;
+               mon_adjust_speed(mtmp, 1, otmp);
+               return 2;
+       case MUSE_POT_SPEED:
+               mquaffmsg(mtmp, otmp);
+               /* note difference in potion effect due to substantially
+                  different methods of maintaining speed ratings:
+                  player's character becomes "very fast" temporarily;
+                  monster becomes "one stage faster" permanently */
+               mon_adjust_speed(mtmp, 1, otmp);
+               m_useup(mtmp, otmp);
+               return 2;
+       case MUSE_WAN_POLYMORPH:
+               mzapmsg(mtmp, otmp, TRUE);
+               otmp->spe--;
+               (void) newcham(mtmp, muse_newcham_mon(mtmp), TRUE, FALSE);
+               if (oseen) makeknown(WAN_POLYMORPH);
+               return 2;
+       case MUSE_POT_POLYMORPH:
+               mquaffmsg(mtmp, otmp);
+               if (vismon) pline("%s suddenly mutates!", Monnam(mtmp));
+               (void) newcham(mtmp, muse_newcham_mon(mtmp), FALSE, FALSE);
+               if (oseen) makeknown(POT_POLYMORPH);
+               m_useup(mtmp, otmp);
+               return 2;
+       case MUSE_POLY_TRAP:
+               if (vismon)
+                   pline("%s deliberately %s onto a polymorph trap!",
+                       Monnam(mtmp),
+                       makeplural(locomotion(mtmp->data, "jump")));
+               if (vis) seetrap(t_at(trapx,trapy));
+
+               /*  don't use rloc() due to worms */
+               remove_monster(mtmp->mx, mtmp->my);
+               newsym(mtmp->mx, mtmp->my);
+               place_monster(mtmp, trapx, trapy);
+               if (mtmp->wormno) worm_move(mtmp);
+               newsym(trapx, trapy);
+
+               (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE);
+               return 2;
+       case MUSE_BULLWHIP:
+               /* attempt to disarm hero */
+               if (uwep && !rn2(5)) {
+                   const char *The_whip = vismon ? "The bullwhip" : "A whip";
+                   int where_to = rn2(4);
+                   struct obj *obj = uwep;
+                   const char *hand;
+                   char the_weapon[BUFSZ];
+
+                   Strcpy(the_weapon, the(xname(obj)));
+                   hand = body_part(HAND);
+                   if (bimanual(obj)) hand = makeplural(hand);
+
+                   if (vismon)
+                       pline("%s flicks a bullwhip towards your %s!",
+                             Monnam(mtmp), hand);
+                   if (obj->otyp == HEAVY_IRON_BALL) {
+                       pline("%s fails to wrap around %s.",
+                             The_whip, the_weapon);
+                       return 1;
+                   }
+                   pline("%s wraps around %s you're wielding!",
+                         The_whip, the_weapon);
+                   if (welded(obj)) {
+                       pline("%s welded to your %s%c",
+                             !is_plural(obj) ? "It is" : "They are",
+                             hand, !obj->bknown ? '!' : '.');
+                       /* obj->bknown = 1; */ /* welded() takes care of this */
+                       where_to = 0;
+                   }
+                   if (!where_to) {
+                       pline_The("whip slips free.");  /* not `The_whip' */
+                       return 1;
+                   } else if (where_to == 3 && hates_silver(mtmp->data) &&
+                           objects[obj->otyp].oc_material == SILVER) {
+                       /* this monster won't want to catch a silver
+                          weapon; drop it at hero's feet instead */
+                       where_to = 2;
+                   }
+                   freeinv(obj);
+                   uwepgone();
+                   switch (where_to) {
+                       case 1:         /* onto floor beneath mon */
+                           pline("%s yanks %s from your %s!", Monnam(mtmp),
+                                 the_weapon, hand);
+                           place_object(obj, mtmp->mx, mtmp->my);
+                           break;
+                       case 2:         /* onto floor beneath you */
+                           pline("%s yanks %s to the %s!", Monnam(mtmp),
+                                 the_weapon, surface(u.ux, u.uy));
+                           dropy(obj);
+                           break;
+                       case 3:         /* into mon's inventory */
+                           pline("%s snatches %s!", Monnam(mtmp),
+                                 the_weapon);
+                           (void) mpickobj(mtmp,obj);
+                           break;
+                   }
+                   return 1;
+               }
+               return 0;
+       case 0: return 0; /* i.e. an exploded wand */
+       default: impossible("%s wanted to perform action %d?", Monnam(mtmp),
+                       m.has_misc);
+               break;
+       }
+       return 0;
+}
+
+STATIC_OVL void
+you_aggravate(mtmp)
+struct monst *mtmp;
+{
+       pline("For some reason, %s presence is known to you.",
+               s_suffix(noit_mon_nam(mtmp)));
+       cls();
+#ifdef CLIPPING
+       cliparound(mtmp->mx, mtmp->my);
+#endif
+       show_glyph(mtmp->mx, mtmp->my, mon_to_glyph(mtmp));
+       display_self();
+       You_feel("aggravated at %s.", noit_mon_nam(mtmp));
+       display_nhwindow(WIN_MAP, TRUE);
+       docrt();
+       if (unconscious()) {
+               multi = -1;
+               nomovemsg =
+                     "Aggravated, you are jolted into full consciousness.";
+       }
+       newsym(mtmp->mx,mtmp->my);
+       if (!canspotmon(mtmp))
+           map_invisible(mtmp->mx, mtmp->my);
+}
+
+int
+rnd_misc_item(mtmp)
+struct monst *mtmp;
+{
+       struct permonst *pm = mtmp->data;
+       int difficulty = monstr[(monsndx(pm))];
+
+       if(is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data)
+                       || pm->mlet == S_GHOST
+# ifdef KOPS
+                       || pm->mlet == S_KOP
+# endif
+               ) return 0;
+       /* Unlike other rnd_item functions, we only allow _weak_ monsters
+        * to have this item; after all, the item will be used to strengthen
+        * the monster and strong monsters won't use it at all...
+        */
+       if (difficulty < 6 && !rn2(30))
+           return rn2(6) ? POT_POLYMORPH : WAN_POLYMORPH;
+
+       if (!rn2(40) && !nonliving(pm)) return AMULET_OF_LIFE_SAVING;
+
+       switch (rn2(3)) {
+               case 0:
+                       if (mtmp->isgd) return 0;
+                       return rn2(6) ? POT_SPEED : WAN_SPEED_MONSTER;
+               case 1:
+                       if (mtmp->mpeaceful && !See_invisible) return 0;
+                       return rn2(6) ? POT_INVISIBILITY : WAN_MAKE_INVISIBLE;
+               case 2:
+                       return POT_GAIN_LEVEL;
+       }
+       /*NOTREACHED*/
+       return 0;
+}
+
+boolean
+searches_for_item(mon, obj)
+struct monst *mon;
+struct obj *obj;
+{
+       int typ = obj->otyp;
+
+       if (is_animal(mon->data) ||
+               mindless(mon->data) ||
+               mon->data == &mons[PM_GHOST])   /* don't loot bones piles */
+           return FALSE;
+
+       if (typ == WAN_MAKE_INVISIBLE || typ == POT_INVISIBILITY)
+           return (boolean)(!mon->minvis && !mon->invis_blkd && !attacktype(mon->data, AT_GAZE));
+       if (typ == WAN_SPEED_MONSTER || typ == POT_SPEED)
+           return (boolean)(mon->mspeed != MFAST);
+
+       switch (obj->oclass) {
+       case WAND_CLASS:
+           if (obj->spe <= 0)
+               return FALSE;
+           if (typ == WAN_DIGGING)
+               return (boolean)(!is_floater(mon->data));
+           if (typ == WAN_POLYMORPH)
+               return (boolean)(monstr[monsndx(mon->data)] < 6);
+           if (objects[typ].oc_dir == RAY ||
+                   typ == WAN_STRIKING ||
+                   typ == WAN_TELEPORTATION ||
+                   typ == WAN_CREATE_MONSTER)
+               return TRUE;
+           break;
+       case POTION_CLASS:
+           if (typ == POT_HEALING ||
+                   typ == POT_EXTRA_HEALING ||
+                   typ == POT_FULL_HEALING ||
+                   typ == POT_POLYMORPH ||
+                   typ == POT_GAIN_LEVEL ||
+                   typ == POT_PARALYSIS ||
+                   typ == POT_SLEEPING ||
+                   typ == POT_ACID ||
+                   typ == POT_CONFUSION)
+               return TRUE;
+           if (typ == POT_BLINDNESS && !attacktype(mon->data, AT_GAZE))
+               return TRUE;
+           break;
+       case SCROLL_CLASS:
+           if (typ == SCR_TELEPORTATION || typ == SCR_CREATE_MONSTER
+                   || typ == SCR_EARTH)
+               return TRUE;
+           break;
+       case AMULET_CLASS:
+           if (typ == AMULET_OF_LIFE_SAVING)
+               return (boolean)(!nonliving(mon->data));
+           if (typ == AMULET_OF_REFLECTION)
+               return TRUE;
+           break;
+       case TOOL_CLASS:
+           if (typ == PICK_AXE)
+               return (boolean)needspick(mon->data);
+           if (typ == UNICORN_HORN)
+               return (boolean)(!obj->cursed && !is_unicorn(mon->data));
+           if (typ == FROST_HORN || typ == FIRE_HORN)
+               return (obj->spe > 0);
+           break;
+       case FOOD_CLASS:
+           if (typ == CORPSE)
+               return (boolean)(((mon->misc_worn_check & W_ARMG) &&
+                                   touch_petrifies(&mons[obj->corpsenm])) ||
+                               (!resists_ston(mon) &&
+                                   (obj->corpsenm == PM_LIZARD ||
+                                       (acidic(&mons[obj->corpsenm]) &&
+                                        obj->corpsenm != PM_GREEN_SLIME))));
+           if (typ == EGG)
+               return (boolean)(touch_petrifies(&mons[obj->corpsenm]));
+           break;
+       default:
+           break;
+       }
+
+       return FALSE;
+}
+
+boolean
+mon_reflects(mon,str)
+struct monst *mon;
+const char *str;
+{
+       struct obj *orefl = which_armor(mon, W_ARMS);
+
+       if (orefl && orefl->otyp == SHIELD_OF_REFLECTION) {
+           if (str) {
+               pline(str, s_suffix(mon_nam(mon)), "shield");
+               makeknown(SHIELD_OF_REFLECTION);
+           }
+           return TRUE;
+       } else if (arti_reflects(MON_WEP(mon))) {
+           /* due to wielded artifact weapon */
+           if (str)
+               pline(str, s_suffix(mon_nam(mon)), "weapon");
+           return TRUE;
+       } else if ((orefl = which_armor(mon, W_AMUL)) &&
+                               orefl->otyp == AMULET_OF_REFLECTION) {
+           if (str) {
+               pline(str, s_suffix(mon_nam(mon)), "amulet");
+               makeknown(AMULET_OF_REFLECTION);
+           }
+           return TRUE;
+       } else if ((orefl = which_armor(mon, W_ARM)) &&
+               (orefl->otyp == SILVER_DRAGON_SCALES || orefl->otyp == SILVER_DRAGON_SCALE_MAIL)) {
+           if (str)
+               pline(str, s_suffix(mon_nam(mon)), "armor");
+           return TRUE;
+       } else if (mon->data == &mons[PM_SILVER_DRAGON] ||
+               mon->data == &mons[PM_CHROMATIC_DRAGON]) {
+           /* Silver dragons only reflect when mature; babies do not */
+           if (str)
+               pline(str, s_suffix(mon_nam(mon)), "scales");
+           return TRUE;
+       }
+       return FALSE;
+}
+
+boolean
+ureflects (fmt, str)
+const char *fmt, *str;
+{
+       /* Check from outermost to innermost objects */
+       if (EReflecting & W_ARMS) {
+           if (fmt && str) {
+               pline(fmt, str, "shield");
+               makeknown(SHIELD_OF_REFLECTION);
+           }
+           return TRUE;
+       } else if (EReflecting & W_WEP) {
+           /* Due to wielded artifact weapon */
+           if (fmt && str)
+               pline(fmt, str, "weapon");
+           return TRUE;
+       } else if (EReflecting & W_AMUL) {
+           if (fmt && str) {
+               pline(fmt, str, "medallion");
+               makeknown(AMULET_OF_REFLECTION);
+           }
+           return TRUE;
+       } else if (EReflecting & W_ARM) {
+           if (fmt && str)
+               pline(fmt, str, "armor");
+           return TRUE;
+       } else if (youmonst.data == &mons[PM_SILVER_DRAGON]) {
+           if (fmt && str)
+               pline(fmt, str, "scales");
+           return TRUE;
+       }
+       return FALSE;
+}
+
+
+/* TRUE if the monster ate something */
+boolean
+munstone(mon, by_you)
+struct monst *mon;
+boolean by_you;
+{
+       struct obj *obj;
+
+       if (resists_ston(mon)) return FALSE;
+       if (mon->meating || !mon->mcanmove || mon->msleeping) return FALSE;
+
+       for(obj = mon->minvent; obj; obj = obj->nobj) {
+           /* Monsters can also use potions of acid */
+           if ((obj->otyp == POT_ACID) || (obj->otyp == CORPSE &&
+                       (obj->corpsenm == PM_LIZARD || (acidic(&mons[obj->corpsenm]) && obj->corpsenm != PM_GREEN_SLIME)))) {
+               mon_consume_unstone(mon, obj, by_you, TRUE);
+               return TRUE;
+           }
+       }
+       return FALSE;
+}
+
+STATIC_OVL void
+mon_consume_unstone(mon, obj, by_you, stoning)
+struct monst *mon;
+struct obj *obj;
+boolean by_you;
+boolean stoning;
+{
+    int nutrit = (obj->otyp == CORPSE) ? dog_nutrition(mon, obj) : 0;
+    /* also sets meating */
+
+    /* give a "<mon> is slowing down" message and also remove
+       intrinsic speed (comparable to similar effect on the hero) */
+    mon_adjust_speed(mon, -3, (struct obj *)0);
+
+    if (canseemon(mon)) {
+       long save_quan = obj->quan;
+
+       obj->quan = 1L;
+       pline("%s %ss %s.", Monnam(mon),
+                   (obj->otyp == POT_ACID) ? "quaff" : "eat",
+                   distant_name(obj,doname));
+       obj->quan = save_quan;
+    } else if (flags.soundok)
+       You_hear("%s.", (obj->otyp == POT_ACID) ? "drinking" : "chewing");
+    m_useup(mon, obj);
+    if (((obj->otyp == POT_ACID) || acidic(&mons[obj->corpsenm])) &&
+                   !resists_acid(mon)) {
+       mon->mhp -= rnd(15);
+       pline("%s has a very bad case of stomach acid.",
+           Monnam(mon));
+    }
+    if (mon->mhp <= 0) {
+       pline("%s dies!", Monnam(mon));
+       if (by_you) xkilled(mon, 0);
+       else mondead(mon);
+       return;
+    }
+    if (stoning && canseemon(mon)) {
+       if (Hallucination)
+    pline("What a pity - %s just ruined a future piece of art!",
+           mon_nam(mon));
+       else
+           pline("%s seems limber!", Monnam(mon));
+    }
+    if (obj->otyp == CORPSE && obj->corpsenm == PM_LIZARD && mon->mconf) {
+       mon->mconf = 0;
+       if (canseemon(mon))
+           pline("%s seems steadier now.", Monnam(mon));
+    }
+    if (mon->mtame && !mon->isminion && nutrit > 0) {
+       struct edog *edog = EDOG(mon);
+
+       if (edog->hungrytime < monstermoves) edog->hungrytime = monstermoves;
+       edog->hungrytime += nutrit;
+       mon->mconf = 0;
+    }
+    mon->mlstmv = monstermoves; /* it takes a turn */
+}
+
+/*muse.c*/
diff --git a/src/music.c b/src/music.c
new file mode 100644 (file)
index 0000000..e7391d8
--- /dev/null
@@ -0,0 +1,755 @@
+/*     SCCS Id: @(#)music.c    3.4     2003/05/25      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file contains the different functions designed to manipulate the
+ * musical instruments and their various effects.
+ *
+ * Actually the list of instruments / effects is :
+ *
+ * (wooden) flute      may calm snakes if player has enough dexterity
+ * magic flute         may put monsters to sleep:  area of effect depends
+ *                     on player level.
+ * (tooled) horn       Will awaken monsters:  area of effect depends on player
+ *                     level.  May also scare monsters.
+ * fire horn           Acts like a wand of fire.
+ * frost horn          Acts like a wand of cold.
+ * bugle               Will awaken soldiers (if any):  area of effect depends
+ *                     on player level.
+ * (wooden) harp       May calm nymph if player has enough dexterity.
+ * magic harp          Charm monsters:  area of effect depends on player
+ *                     level.
+ * (leather) drum      Will awaken monsters like the horn.
+ * drum of earthquake  Will initiate an earthquake whose intensity depends
+ *                     on player level.  That is, it creates random pits
+ *                     called here chasms.
+ */
+
+#include "hack.h"
+
+STATIC_DCL void FDECL(awaken_monsters,(int));
+STATIC_DCL void FDECL(put_monsters_to_sleep,(int));
+STATIC_DCL void FDECL(charm_snakes,(int));
+STATIC_DCL void FDECL(calm_nymphs,(int));
+STATIC_DCL void FDECL(charm_monsters,(int));
+STATIC_DCL void FDECL(do_earthquake,(int));
+STATIC_DCL int FDECL(do_improvisation,(struct obj *));
+
+#ifdef UNIX386MUSIC
+STATIC_DCL int NDECL(atconsole);
+STATIC_DCL void FDECL(speaker,(struct obj *,char *));
+#endif
+#ifdef VPIX_MUSIC
+extern int sco_flag_console;   /* will need changing if not _M_UNIX */
+STATIC_DCL void NDECL(playinit);
+STATIC_DCL void FDECL(playstring, (char *,size_t));
+STATIC_DCL void FDECL(speaker,(struct obj *,char *));
+#endif
+#ifdef PCMUSIC
+void FDECL( pc_speaker, ( struct obj *, char * ) );
+#endif
+#ifdef AMIGA
+void FDECL( amii_speaker, ( struct obj *, char *, int ) );
+#endif
+
+/*
+ * Wake every monster in range...
+ */
+
+STATIC_OVL void
+awaken_monsters(distance)
+int distance;
+{
+       register struct monst *mtmp = fmon;
+       register int distm;
+
+       while(mtmp) {
+           if (!DEADMONSTER(mtmp)) {
+               distm = distu(mtmp->mx, mtmp->my);
+               if (distm < distance) {
+                   mtmp->msleeping = 0;
+                   mtmp->mcanmove = 1;
+                   mtmp->mfrozen = 0;
+                   /* May scare some monsters */
+                   if (distm < distance/3 &&
+                           !resist(mtmp, TOOL_CLASS, 0, NOTELL))
+                       monflee(mtmp, 0, FALSE, TRUE);
+               }
+           }
+           mtmp = mtmp->nmon;
+       }
+}
+
+/*
+ * Make monsters fall asleep.  Note that they may resist the spell.
+ */
+
+STATIC_OVL void
+put_monsters_to_sleep(distance)
+int distance;
+{
+       register struct monst *mtmp = fmon;
+
+       while(mtmp) {
+               if (!DEADMONSTER(mtmp) && distu(mtmp->mx, mtmp->my) < distance &&
+                       sleep_monst(mtmp, d(10,10), TOOL_CLASS)) {
+                   mtmp->msleeping = 1; /* 10d10 turns + wake_nearby to rouse */
+                   slept_monst(mtmp);
+               }
+               mtmp = mtmp->nmon;
+       }
+}
+
+/*
+ * Charm snakes in range.  Note that the snakes are NOT tamed.
+ */
+
+STATIC_OVL void
+charm_snakes(distance)
+int distance;
+{
+       register struct monst *mtmp = fmon;
+       int could_see_mon, was_peaceful;
+
+       while (mtmp) {
+           if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_SNAKE && mtmp->mcanmove &&
+                   distu(mtmp->mx, mtmp->my) < distance) {
+               was_peaceful = mtmp->mpeaceful;
+               mtmp->mpeaceful = 1;
+               mtmp->mavenge = 0;
+               could_see_mon = canseemon(mtmp);
+               mtmp->mundetected = 0;
+               newsym(mtmp->mx, mtmp->my);
+               if (canseemon(mtmp)) {
+                   if (!could_see_mon)
+                       You("notice %s, swaying with the music.",
+                           a_monnam(mtmp));
+                   else
+                       pline("%s freezes, then sways with the music%s.",
+                             Monnam(mtmp),
+                             was_peaceful ? "" : ", and now seems quieter");
+               }
+           }
+           mtmp = mtmp->nmon;
+       }
+}
+
+/*
+ * Calm nymphs in range.
+ */
+
+STATIC_OVL void
+calm_nymphs(distance)
+int distance;
+{
+       register struct monst *mtmp = fmon;
+
+       while (mtmp) {
+           if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_NYMPH && mtmp->mcanmove &&
+                   distu(mtmp->mx, mtmp->my) < distance) {
+               mtmp->msleeping = 0;
+               mtmp->mpeaceful = 1;
+               mtmp->mavenge = 0;
+               if (canseemon(mtmp))
+                   pline(
+                    "%s listens cheerfully to the music, then seems quieter.",
+                         Monnam(mtmp));
+           }
+           mtmp = mtmp->nmon;
+       }
+}
+
+/* Awake only soldiers of the level. */
+
+void
+awaken_soldiers()
+{
+       register struct monst *mtmp = fmon;
+
+       while(mtmp) {
+           if (!DEADMONSTER(mtmp) &&
+                       is_mercenary(mtmp->data) && mtmp->data != &mons[PM_GUARD]) {
+               mtmp->mpeaceful = mtmp->msleeping = mtmp->mfrozen = 0;
+               mtmp->mcanmove = 1;
+               if (canseemon(mtmp))
+                   pline("%s is now ready for battle!", Monnam(mtmp));
+               else
+                   Norep("You hear the rattle of battle gear being readied.");
+           }
+           mtmp = mtmp->nmon;
+       }
+}
+
+/* Charm monsters in range.  Note that they may resist the spell.
+ * If swallowed, range is reduced to 0.
+ */
+
+STATIC_OVL void
+charm_monsters(distance)
+int distance;
+{
+       struct monst *mtmp, *mtmp2;
+
+       if (u.uswallow) {
+           if (!resist(u.ustuck, TOOL_CLASS, 0, NOTELL))
+               (void) tamedog(u.ustuck, (struct obj *) 0);
+       } else {
+           for (mtmp = fmon; mtmp; mtmp = mtmp2) {
+               mtmp2 = mtmp->nmon;
+               if (DEADMONSTER(mtmp)) continue;
+
+               if (distu(mtmp->mx, mtmp->my) <= distance) {
+                   if (!resist(mtmp, TOOL_CLASS, 0, NOTELL))
+                       (void) tamedog(mtmp, (struct obj *) 0);
+               }
+           }
+       }
+
+}
+
+/* Generate earthquake :-) of desired force.
+ * That is:  create random chasms (pits).
+ */
+
+STATIC_OVL void
+do_earthquake(force)
+int force;
+{
+       register int x,y;
+       struct monst *mtmp;
+       struct obj *otmp;
+       struct trap *chasm;
+       int start_x, start_y, end_x, end_y;
+
+       start_x = u.ux - (force * 2);
+       start_y = u.uy - (force * 2);
+       end_x = u.ux + (force * 2);
+       end_y = u.uy + (force * 2);
+       if (start_x < 1) start_x = 1;
+       if (start_y < 1) start_y = 1;
+       if (end_x >= COLNO) end_x = COLNO - 1;
+       if (end_y >= ROWNO) end_y = ROWNO - 1;
+       for (x=start_x; x<=end_x; x++) for (y=start_y; y<=end_y; y++) {
+           if ((mtmp = m_at(x,y)) != 0) {
+               wakeup(mtmp);   /* peaceful monster will become hostile */
+               if (mtmp->mundetected && is_hider(mtmp->data)) {
+                   mtmp->mundetected = 0;
+                   if (cansee(x,y))
+                       pline("%s is shaken loose from the ceiling!",
+                                                           Amonnam(mtmp));
+                   else
+                       You_hear("a thumping sound.");
+                   if (x==u.ux && y==u.uy)
+                       You("easily dodge the falling %s.",
+                                                           mon_nam(mtmp));
+                   newsym(x,y);
+               }
+           }
+           if (!rn2(14 - force)) switch (levl[x][y].typ) {
+                 case FOUNTAIN : /* Make the fountain disappear */
+                       if (cansee(x,y))
+                               pline_The("fountain falls into a chasm.");
+                       goto do_pit;
+#ifdef SINKS
+                 case SINK :
+                       if (cansee(x,y))
+                               pline_The("kitchen sink falls into a chasm.");
+                       goto do_pit;
+#endif
+                 case ALTAR :
+                       if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) break;
+
+                       if (cansee(x,y))
+                               pline_The("altar falls into a chasm.");
+                       goto do_pit;
+                 case GRAVE :
+                       if (cansee(x,y))
+                               pline_The("headstone topples into a chasm.");
+                       goto do_pit;
+                 case THRONE :
+                       if (cansee(x,y))
+                               pline_The("throne falls into a chasm.");
+                       /* Falls into next case */
+                 case ROOM :
+                 case CORR : /* Try to make a pit */
+do_pit:                    chasm = maketrap(x,y,PIT);
+                   if (!chasm) break;  /* no pit if portal at that location */
+                   chasm->tseen = 1;
+
+                   levl[x][y].doormask = 0;
+
+                   mtmp = m_at(x,y);
+
+                   if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
+                       if (cansee(x, y))
+                          pline("KADOOM! The boulder falls into a chasm%s!",
+                             ((x == u.ux) && (y == u.uy)) ? " below you" : "");
+                       if (mtmp)
+                               mtmp->mtrapped = 0;
+                       obj_extract_self(otmp);
+                       (void) flooreffects(otmp, x, y, "");
+                       break;
+                   }
+
+                   /* We have to check whether monsters or player
+                      falls in a chasm... */
+
+                   if (mtmp) {
+                       if(!is_flyer(mtmp->data) && !is_clinger(mtmp->data)) {
+                           mtmp->mtrapped = 1;
+                           if(cansee(x,y))
+                               pline("%s falls into a chasm!", Monnam(mtmp));
+                           else if (flags.soundok && humanoid(mtmp->data))
+                               You_hear("a scream!");
+                           mselftouch(mtmp, "Falling, ", TRUE);
+                           if (mtmp->mhp > 0)
+                               if ((mtmp->mhp -= rnd(6)) <= 0) {
+                                   if(!cansee(x,y))
+                                       pline("It is destroyed!");
+                                   else {
+                                       You("destroy %s!", mtmp->mtame ?
+                                           x_monnam(mtmp, ARTICLE_THE, "poor",
+                               mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE):
+                                           mon_nam(mtmp));
+                                   }
+                                   xkilled(mtmp,0);
+                               }
+                       }
+                   } else if (x == u.ux && y == u.uy) {
+                           if (Levitation || Flying ||
+                                               is_clinger(youmonst.data)) {
+                                   pline("A chasm opens up under you!");
+                                   You("don't fall in!");
+                           } else {
+                                   You("fall into a chasm!");
+                                   u.utrap = rn1(6,2);
+                                   u.utraptype = TT_PIT;
+                                   losehp(rnd(6),"fell into a chasm",
+                                       NO_KILLER_PREFIX);
+                                   selftouch("Falling, you");
+                           }
+                   } else newsym(x,y);
+                   break;
+                 case DOOR : /* Make the door collapse */
+                   if (levl[x][y].doormask == D_NODOOR) goto do_pit;
+                   if (cansee(x,y))
+                       pline_The("door collapses.");
+                   if (*in_rooms(x, y, SHOPBASE))
+                       add_damage(x, y, 0L);
+                   levl[x][y].doormask = D_NODOOR;
+                   unblock_point(x,y);
+                   newsym(x,y);
+                   break;
+           }
+       }
+}
+
+/*
+ * The player is trying to extract something from his/her instrument.
+ */
+
+STATIC_OVL int
+do_improvisation(instr)
+struct obj *instr;
+{
+       int damage, do_spec = !Confusion;
+#if defined(MAC) || defined(AMIGA) || defined(VPIX_MUSIC) || defined (PCMUSIC)
+       struct obj itmp;
+
+       itmp = *instr;
+       /* if won't yield special effect, make sound of mundane counterpart */
+       if (!do_spec || instr->spe <= 0)
+           while (objects[itmp.otyp].oc_magic) itmp.otyp -= 1;
+# ifdef MAC
+       mac_speaker(&itmp, "C");
+# endif
+# ifdef AMIGA
+       amii_speaker(&itmp, "Cw", AMII_OKAY_VOLUME);
+# endif
+# ifdef VPIX_MUSIC
+       if (sco_flag_console)
+           speaker(&itmp, "C");
+# endif
+#ifdef PCMUSIC
+         pc_speaker ( &itmp, "C");
+#endif
+#endif /* MAC || AMIGA || VPIX_MUSIC || PCMUSIC */
+
+       if (!do_spec)
+           pline("What you produce is quite far from music...");
+       else
+           You("start playing %s.", the(xname(instr)));
+
+       switch (instr->otyp) {
+       case MAGIC_FLUTE:               /* Make monster fall asleep */
+           if (do_spec && instr->spe > 0) {
+               consume_obj_charge(instr, TRUE);
+
+               You("produce soft music.");
+               put_monsters_to_sleep(u.ulevel * 5);
+               exercise(A_DEX, TRUE);
+               break;
+           } /* else FALLTHRU */
+       case WOODEN_FLUTE:              /* May charm snakes */
+           do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25);
+           pline("%s.", Tobjnam(instr, do_spec ? "trill" : "toot"));
+           if (do_spec) charm_snakes(u.ulevel * 3);
+           exercise(A_DEX, TRUE);
+           break;
+       case FROST_HORN:                /* Idem wand of cold */
+       case FIRE_HORN:                 /* Idem wand of fire */
+           if (do_spec && instr->spe > 0) {
+               consume_obj_charge(instr, TRUE);
+
+               if (!getdir((char *)0)) {
+                   pline("%s.", Tobjnam(instr, "vibrate"));
+                   break;
+               } else if (!u.dx && !u.dy && !u.dz) {
+                   if ((damage = zapyourself(instr, TRUE)) != 0) {
+                       char buf[BUFSZ];
+                       Sprintf(buf, "using a magical horn on %sself", uhim());
+                       losehp(damage, buf, KILLED_BY);
+                   }
+               } else {
+                   buzz((instr->otyp == FROST_HORN) ? AD_COLD-1 : AD_FIRE-1,
+                        rn1(6,6), u.ux, u.uy, u.dx, u.dy);
+               }
+               makeknown(instr->otyp);
+               break;
+           } /* else FALLTHRU */
+       case TOOLED_HORN:               /* Awaken or scare monsters */
+           You("produce a frightful, grave sound.");
+           awaken_monsters(u.ulevel * 30);
+           exercise(A_WIS, FALSE);
+           break;
+       case BUGLE:                     /* Awaken & attract soldiers */
+           You("extract a loud noise from %s.", the(xname(instr)));
+           awaken_soldiers();
+           exercise(A_WIS, FALSE);
+           break;
+       case MAGIC_HARP:                /* Charm monsters */
+           if (do_spec && instr->spe > 0) {
+               consume_obj_charge(instr, TRUE);
+
+               pline("%s very attractive music.", Tobjnam(instr, "produce"));
+               charm_monsters((u.ulevel - 1) / 3 + 1);
+               exercise(A_DEX, TRUE);
+               break;
+           } /* else FALLTHRU */
+       case WOODEN_HARP:               /* May calm Nymph */
+           do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25);
+           pline("%s %s.", The(xname(instr)),
+                 do_spec ? "produces a lilting melody" : "twangs");
+           if (do_spec) calm_nymphs(u.ulevel * 3);
+           exercise(A_DEX, TRUE);
+           break;
+       case DRUM_OF_EARTHQUAKE:        /* create several pits */
+           if (do_spec && instr->spe > 0) {
+               consume_obj_charge(instr, TRUE);
+
+               You("produce a heavy, thunderous rolling!");
+               pline_The("entire dungeon is shaking around you!");
+               do_earthquake((u.ulevel - 1) / 3 + 1);
+               /* shake up monsters in a much larger radius... */
+               awaken_monsters(ROWNO * COLNO);
+               makeknown(DRUM_OF_EARTHQUAKE);
+               break;
+           } /* else FALLTHRU */
+       case LEATHER_DRUM:              /* Awaken monsters */
+           You("beat a deafening row!");
+           awaken_monsters(u.ulevel * 40);
+           exercise(A_WIS, FALSE);
+           break;
+       default:
+           impossible("What a weird instrument (%d)!", instr->otyp);
+           break;
+       }
+       return 2;               /* That takes time */
+}
+
+/*
+ * So you want music...
+ */
+
+int
+do_play_instrument(instr)
+struct obj *instr;
+{
+    char buf[BUFSZ], c = 'y';
+    char *s;
+    int x,y;
+    boolean ok;
+
+    if (Underwater) {
+       You_cant("play music underwater!");
+       return(0);
+    }
+    if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) {
+       c = yn("Improvise?");
+    }
+    if (c == 'n') {
+       if (u.uevent.uheard_tune == 2 && yn("Play the passtune?") == 'y') {
+           Strcpy(buf, tune);
+       } else {
+           getlin("What tune are you playing? [5 notes, A-G]", buf);
+           (void)mungspaces(buf);
+           /* convert to uppercase and change any "H" to the expected "B" */
+           for (s = buf; *s; s++) {
+#ifndef AMIGA
+               *s = highc(*s);
+#else
+               /* The AMIGA supports two octaves of notes */
+               if (*s == 'h') *s = 'b';
+#endif
+               if (*s == 'H') *s = 'B';
+           }
+       }
+       You("extract a strange sound from %s!", the(xname(instr)));
+#ifdef UNIX386MUSIC
+       /* if user is at the console, play through the console speaker */
+       if (atconsole())
+           speaker(instr, buf);
+#endif
+#ifdef VPIX_MUSIC
+       if (sco_flag_console)
+           speaker(instr, buf);
+#endif
+#ifdef MAC
+       mac_speaker ( instr , buf ) ;
+#endif
+#ifdef PCMUSIC
+       pc_speaker ( instr, buf );
+#endif
+#ifdef AMIGA
+       {
+               char nbuf[ 20 ];
+               int i;
+               for( i = 0; buf[i] && i < 5; ++i )
+               {
+                       nbuf[ i*2 ] = buf[ i ];
+                       nbuf[ (i*2)+1 ] = 'h';
+               }
+               nbuf[ i*2 ] = 0;
+               amii_speaker ( instr , nbuf, AMII_OKAY_VOLUME ) ;
+       }
+#endif
+       /* Check if there was the Stronghold drawbridge near
+        * and if the tune conforms to what we're waiting for.
+        */
+       if(Is_stronghold(&u.uz)) {
+           exercise(A_WIS, TRUE);              /* just for trying */
+           if(!strcmp(buf,tune)) {
+               /* Search for the drawbridge */
+               for(y=u.uy-1; y<=u.uy+1; y++)
+                   for(x=u.ux-1;x<=u.ux+1;x++)
+                       if(isok(x,y))
+                       if(find_drawbridge(&x,&y)) {
+                           u.uevent.uheard_tune = 2; /* tune now fully known */
+                           if(levl[x][y].typ == DRAWBRIDGE_DOWN)
+                               close_drawbridge(x,y);
+                           else
+                               open_drawbridge(x,y);
+                           return 0;
+                       }
+           } else if(flags.soundok) {
+               if (u.uevent.uheard_tune < 1) u.uevent.uheard_tune = 1;
+               /* Okay, it wasn't the right tune, but perhaps
+                * we can give the player some hints like in the
+                * Mastermind game */
+               ok = FALSE;
+               for(y = u.uy-1; y <= u.uy+1 && !ok; y++)
+                   for(x = u.ux-1; x <= u.ux+1 && !ok; x++)
+                       if(isok(x,y))
+                       if(IS_DRAWBRIDGE(levl[x][y].typ) ||
+                          is_drawbridge_wall(x,y) >= 0)
+                               ok = TRUE;
+               if(ok) { /* There is a drawbridge near */
+                   int tumblers, gears;
+                   boolean matched[5];
+
+                   tumblers = gears = 0;
+                   for(x=0; x < 5; x++)
+                       matched[x] = FALSE;
+
+                   for(x=0; x < (int)strlen(buf); x++)
+                       if(x < 5) {
+                           if(buf[x] == tune[x]) {
+                               gears++;
+                               matched[x] = TRUE;
+                           } else
+                               for(y=0; y < 5; y++)
+                                   if(!matched[y] &&
+                                      buf[x] == tune[y] &&
+                                      buf[y] != tune[y]) {
+                                       tumblers++;
+                                       matched[y] = TRUE;
+                                       break;
+                                   }
+                       }
+                   if(tumblers)
+                       if(gears)
+                           You_hear("%d tumbler%s click and %d gear%s turn.",
+                               tumblers, plur(tumblers), gears, plur(gears));
+                       else
+                           You_hear("%d tumbler%s click.",
+                               tumblers, plur(tumblers));
+                   else if(gears) {
+                       You_hear("%d gear%s turn.", gears, plur(gears));
+                       /* could only get `gears == 5' by playing five
+                          correct notes followed by excess; otherwise,
+                          tune would have matched above */
+                       if (gears == 5) u.uevent.uheard_tune = 2;
+                   }
+               }
+           }
+         }
+       return 1;
+    } else
+           return do_improvisation(instr);
+}
+
+#ifdef UNIX386MUSIC
+/*
+ * Play audible music on the machine's speaker if appropriate.
+ */
+
+STATIC_OVL int
+atconsole()
+{
+    /*
+     * Kluge alert: This code assumes that your [34]86 has no X terminals
+     * attached and that the console tty type is AT386 (this is always true
+     * under AT&T UNIX for these boxen). The theory here is that your remote
+     * ttys will have terminal type `ansi' or something else other than
+     * `AT386' or `xterm'. We'd like to do better than this, but testing
+     * to see if we're running on the console physical terminal is quite
+     * difficult given the presence of virtual consoles and other modern
+     * UNIX impedimenta...
+     */
+    char       *termtype = nh_getenv("TERM");
+
+     return(!strcmp(termtype, "AT386") || !strcmp(termtype, "xterm"));
+}
+
+STATIC_OVL void
+speaker(instr, buf)
+struct obj *instr;
+char   *buf;
+{
+    /*
+     * For this to work, you need to have installed the PD speaker-control
+     * driver for PC-compatible UNIX boxes that I (esr@snark.thyrsus.com)
+     * posted to comp.sources.unix in Feb 1990.  A copy should be included
+     * with your nethack distribution.
+     */
+    int        fd;
+
+    if ((fd = open("/dev/speaker", 1)) != -1)
+    {
+       /* send a prefix to modify instrumental `timbre' */
+       switch (instr->otyp)
+       {
+       case WOODEN_FLUTE:
+       case MAGIC_FLUTE:
+           (void) write(fd, ">ol", 1); /* up one octave & lock */
+           break;
+       case TOOLED_HORN:
+       case FROST_HORN:
+       case FIRE_HORN:
+           (void) write(fd, "<<ol", 2); /* drop two octaves & lock */
+           break;
+       case BUGLE:
+           (void) write(fd, "ol", 2); /* octave lock */
+           break;
+       case WOODEN_HARP:
+       case MAGIC_HARP:
+           (void) write(fd, "l8mlol", 4); /* fast, legato, octave lock */
+           break;
+       }
+       (void) write(fd, buf, strlen(buf));
+       (void) close(fd);
+    }
+}
+#endif /* UNIX386MUSIC */
+
+#ifdef VPIX_MUSIC
+
+# if 0
+#include <sys/types.h>
+#include <sys/console.h>
+#include <sys/vtkd.h>
+# else
+#define KIOC ('K' << 8)
+#define KDMKTONE (KIOC | 8)
+# endif
+
+#define noDEBUG
+
+STATIC_OVL void tone(hz, ticks)
+/* emit tone of frequency hz for given number of ticks */
+unsigned int hz, ticks;
+{
+    ioctl(0,KDMKTONE,hz|((ticks*10)<<16));
+# ifdef DEBUG
+    printf("TONE: %6d %6d\n",hz,ticks * 10);
+# endif
+    nap(ticks * 10);
+}
+
+STATIC_OVL void rest(ticks)
+/* rest for given number of ticks */
+int    ticks;
+{
+    nap(ticks * 10);
+# ifdef DEBUG
+    printf("REST:        %6d\n",ticks * 10);
+# endif
+}
+
+
+#include "interp.c"    /* from snd86unx.shr */
+
+
+STATIC_OVL void
+speaker(instr, buf)
+struct obj *instr;
+char   *buf;
+{
+    /* emit a prefix to modify instrumental `timbre' */
+    playinit();
+    switch (instr->otyp)
+    {
+       case WOODEN_FLUTE:
+       case MAGIC_FLUTE:
+           playstring(">ol", 1); /* up one octave & lock */
+           break;
+       case TOOLED_HORN:
+       case FROST_HORN:
+       case FIRE_HORN:
+           playstring("<<ol", 2); /* drop two octaves & lock */
+           break;
+       case BUGLE:
+           playstring("ol", 2); /* octave lock */
+           break;
+       case WOODEN_HARP:
+       case MAGIC_HARP:
+           playstring("l8mlol", 4); /* fast, legato, octave lock */
+           break;
+    }
+    playstring( buf, strlen(buf));
+}
+
+# ifdef DEBUG
+main(argc,argv)
+char *argv[];
+{
+    if (argc == 2) {
+       playinit();
+       playstring(argv[1], strlen(argv[1]));
+    }
+}
+# endif
+#endif /* VPIX_MUSIC */
+
+/*music.c*/
diff --git a/src/o_init.c b/src/o_init.c
new file mode 100644 (file)
index 0000000..7816fb2
--- /dev/null
@@ -0,0 +1,427 @@
+/*     SCCS Id: @(#)o_init.c   3.4     1999/12/09      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "lev.h"       /* save & restore info */
+
+STATIC_DCL void FDECL(setgemprobs, (d_level*));
+STATIC_DCL void FDECL(shuffle,(int,int,BOOLEAN_P));
+STATIC_DCL void NDECL(shuffle_all);
+STATIC_DCL boolean FDECL(interesting_to_discover,(int));
+
+
+static NEARDATA short disco[NUM_OBJECTS] = DUMMY;
+
+#ifdef USE_TILES
+STATIC_DCL void NDECL(shuffle_tiles);
+extern short glyph2tile[];     /* from tile.c */
+
+/* Shuffle tile assignments to match descriptions, so a red potion isn't
+ * displayed with a blue tile and so on.
+ *
+ * Tile assignments are not saved, and shouldn't be so that a game can
+ * be resumed on an otherwise identical non-tile-using binary, so we have
+ * to reshuffle the assignments from oc_descr_idx information when a game
+ * is restored.  So might as well do that the first time instead of writing
+ * another routine.
+ */
+STATIC_OVL void
+shuffle_tiles()
+{
+       int i;
+       short tmp_tilemap[NUM_OBJECTS];
+
+       for (i = 0; i < NUM_OBJECTS; i++)
+               tmp_tilemap[i] =
+                       glyph2tile[objects[i].oc_descr_idx + GLYPH_OBJ_OFF];
+
+       for (i = 0; i < NUM_OBJECTS; i++)
+               glyph2tile[i + GLYPH_OBJ_OFF] = tmp_tilemap[i];
+}
+#endif /* USE_TILES */
+
+STATIC_OVL void
+setgemprobs(dlev)
+d_level *dlev;
+{
+       int j, first, lev;
+
+       if (dlev)
+           lev = (ledger_no(dlev) > maxledgerno())
+                               ? maxledgerno() : ledger_no(dlev);
+       else
+           lev = 0;
+       first = bases[GEM_CLASS];
+
+       for(j = 0; j < 9-lev/3; j++)
+               objects[first+j].oc_prob = 0;
+       first += j;
+       if (first > LAST_GEM || objects[first].oc_class != GEM_CLASS ||
+           OBJ_NAME(objects[first]) == (char *)0) {
+               raw_printf("Not enough gems? - first=%d j=%d LAST_GEM=%d",
+                       first, j, LAST_GEM);
+               wait_synch();
+           }
+       for (j = first; j <= LAST_GEM; j++)
+               objects[j].oc_prob = (171+j-first)/(LAST_GEM+1-first);
+}
+
+/* shuffle descriptions on objects o_low to o_high */
+STATIC_OVL void
+shuffle(o_low, o_high, domaterial)
+       int o_low, o_high;
+       boolean domaterial;
+{
+       int i, j, num_to_shuffle;
+       short sw;
+       int color;
+
+       for (num_to_shuffle = 0, j=o_low; j <= o_high; j++)
+               if (!objects[j].oc_name_known) num_to_shuffle++;
+       if (num_to_shuffle < 2) return;
+
+       for (j=o_low; j <= o_high; j++) {
+               if (objects[j].oc_name_known) continue;
+               do
+                       i = j + rn2(o_high-j+1);
+               while (objects[i].oc_name_known);
+               sw = objects[j].oc_descr_idx;
+               objects[j].oc_descr_idx = objects[i].oc_descr_idx;
+               objects[i].oc_descr_idx = sw;
+               sw = objects[j].oc_tough;
+               objects[j].oc_tough = objects[i].oc_tough;
+               objects[i].oc_tough = sw;
+               color = objects[j].oc_color;
+               objects[j].oc_color = objects[i].oc_color;
+               objects[i].oc_color = color;
+
+               /* shuffle material */
+               if (domaterial) {
+                       sw = objects[j].oc_material;
+                       objects[j].oc_material = objects[i].oc_material;
+                       objects[i].oc_material = sw;
+               }
+       }
+}
+
+void
+init_objects()
+{
+register int i, first, last, sum;
+register char oclass;
+#ifdef TEXTCOLOR
+# define COPY_OBJ_DESCR(o_dst,o_src) \
+                       o_dst.oc_descr_idx = o_src.oc_descr_idx,\
+                       o_dst.oc_color = o_src.oc_color
+#else
+# define COPY_OBJ_DESCR(o_dst,o_src) o_dst.oc_descr_idx = o_src.oc_descr_idx
+#endif
+
+       /* bug fix to prevent "initialization error" abort on Intel Xenix.
+        * reported by mikew@semike
+        */
+       for (i = 0; i < MAXOCLASSES; i++)
+               bases[i] = 0;
+       /* initialize object descriptions */
+       for (i = 0; i < NUM_OBJECTS; i++)
+               objects[i].oc_name_idx = objects[i].oc_descr_idx = i;
+       /* init base; if probs given check that they add up to 1000,
+          otherwise compute probs */
+       first = 0;
+       while( first < NUM_OBJECTS ) {
+               oclass = objects[first].oc_class;
+               last = first+1;
+               while (last < NUM_OBJECTS && objects[last].oc_class == oclass) last++;
+               bases[(int)oclass] = first;
+
+               if (oclass == GEM_CLASS) {
+                       setgemprobs((d_level *)0);
+
+                       if (rn2(2)) { /* change turquoise from green to blue? */
+                           COPY_OBJ_DESCR(objects[TURQUOISE],objects[SAPPHIRE]);
+                       }
+                       if (rn2(2)) { /* change aquamarine from green to blue? */
+                           COPY_OBJ_DESCR(objects[AQUAMARINE],objects[SAPPHIRE]);
+                       }
+                       switch (rn2(4)) { /* change fluorite from violet? */
+                           case 0:  break;
+                           case 1:     /* blue */
+                               COPY_OBJ_DESCR(objects[FLUORITE],objects[SAPPHIRE]);
+                               break;
+                           case 2:     /* white */
+                               COPY_OBJ_DESCR(objects[FLUORITE],objects[DIAMOND]);
+                               break;
+                           case 3:     /* green */
+                               COPY_OBJ_DESCR(objects[FLUORITE],objects[EMERALD]);
+                               break;
+                       }
+               }
+       check:
+               sum = 0;
+               for(i = first; i < last; i++) sum += objects[i].oc_prob;
+               if(sum == 0) {
+                       for(i = first; i < last; i++)
+                           objects[i].oc_prob = (1000+i-first)/(last-first);
+                       goto check;
+               }
+               if(sum != 1000)
+                       error("init-prob error for class %d (%d%%)", oclass, sum);
+               first = last;
+       }
+       /* shuffle descriptions */
+       shuffle_all();
+#ifdef USE_TILES
+       shuffle_tiles();
+#endif
+}
+
+STATIC_OVL void
+shuffle_all()
+{
+       int first, last, oclass;
+
+       for (oclass = 1; oclass < MAXOCLASSES; oclass++) {
+               first = bases[oclass];
+               last = first+1;
+               while (last < NUM_OBJECTS && objects[last].oc_class == oclass)
+                       last++;
+
+               if (OBJ_DESCR(objects[first]) != (char *)0 &&
+                               oclass != TOOL_CLASS &&
+                               oclass != WEAPON_CLASS &&
+                               oclass != ARMOR_CLASS &&
+                               oclass != GEM_CLASS) {
+                       int j = last-1;
+
+                       if (oclass == POTION_CLASS)
+                           j -= 1;  /* only water has a fixed description */
+                       else if (oclass == AMULET_CLASS ||
+                                oclass == SCROLL_CLASS ||
+                                oclass == SPBOOK_CLASS) {
+                           while (!objects[j].oc_magic || objects[j].oc_unique)
+                               j--;
+                       }
+
+                       /* non-magical amulets, scrolls, and spellbooks
+                        * (ex. imitation Amulets, blank, scrolls of mail)
+                        * and one-of-a-kind magical artifacts at the end of
+                        * their class in objects[] have fixed descriptions.
+                        */
+                       shuffle(first, j, TRUE);
+               }
+       }
+
+       /* shuffle the helmets */
+       shuffle(HELMET, HELM_OF_TELEPATHY, FALSE);
+
+       /* shuffle the gloves */
+       shuffle(LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY, FALSE);
+
+       /* shuffle the cloaks */
+       shuffle(CLOAK_OF_PROTECTION, CLOAK_OF_DISPLACEMENT, FALSE);
+
+       /* shuffle the boots [if they change, update find_skates() below] */
+       shuffle(SPEED_BOOTS, LEVITATION_BOOTS, FALSE);
+}
+
+/* find the object index for snow boots; used [once] by slippery ice code */
+int
+find_skates()
+{
+    register int i;
+    register const char *s;
+
+    for (i = SPEED_BOOTS; i <= LEVITATION_BOOTS; i++)
+       if ((s = OBJ_DESCR(objects[i])) != 0 && !strcmp(s, "snow boots"))
+           return i;
+
+    impossible("snow boots not found?");
+    return -1; /* not 0, or caller would try again each move */
+}
+
+void
+oinit()                        /* level dependent initialization */
+{
+       setgemprobs(&u.uz);
+}
+
+void
+savenames(fd, mode)
+int fd, mode;
+{
+       register int i;
+       unsigned int len;
+
+       if (perform_bwrite(mode)) {
+           bwrite(fd, (genericptr_t)bases, sizeof bases);
+           bwrite(fd, (genericptr_t)disco, sizeof disco);
+           bwrite(fd, (genericptr_t)objects,
+                  sizeof(struct objclass) * NUM_OBJECTS);
+       }
+       /* as long as we use only one version of Hack we
+          need not save oc_name and oc_descr, but we must save
+          oc_uname for all objects */
+       for (i = 0; i < NUM_OBJECTS; i++)
+           if (objects[i].oc_uname) {
+               if (perform_bwrite(mode)) {
+                   len = strlen(objects[i].oc_uname)+1;
+                   bwrite(fd, (genericptr_t)&len, sizeof len);
+                   bwrite(fd, (genericptr_t)objects[i].oc_uname, len);
+               }
+               if (release_data(mode)) {
+                   free((genericptr_t)objects[i].oc_uname);
+                   objects[i].oc_uname = 0;
+               }
+           }
+}
+
+void
+restnames(fd)
+register int fd;
+{
+       register int i;
+       unsigned int len;
+
+       mread(fd, (genericptr_t) bases, sizeof bases);
+       mread(fd, (genericptr_t) disco, sizeof disco);
+       mread(fd, (genericptr_t) objects, sizeof(struct objclass) * NUM_OBJECTS);
+       for (i = 0; i < NUM_OBJECTS; i++)
+           if (objects[i].oc_uname) {
+               mread(fd, (genericptr_t) &len, sizeof len);
+               objects[i].oc_uname = (char *) alloc(len);
+               mread(fd, (genericptr_t)objects[i].oc_uname, len);
+           }
+#ifdef USE_TILES
+       shuffle_tiles();
+#endif
+}
+
+void
+discover_object(oindx, mark_as_known, credit_hero)
+register int oindx;
+boolean mark_as_known;
+boolean credit_hero;
+{
+    if (!objects[oindx].oc_name_known) {
+       register int dindx, acls = objects[oindx].oc_class;
+
+       /* Loop thru disco[] 'til we find the target (which may have been
+          uname'd) or the next open slot; one or the other will be found
+          before we reach the next class...
+        */
+       for (dindx = bases[acls]; disco[dindx] != 0; dindx++)
+           if (disco[dindx] == oindx) break;
+       disco[dindx] = oindx;
+
+       if (mark_as_known) {
+           objects[oindx].oc_name_known = 1;
+           if (credit_hero) exercise(A_WIS, TRUE);
+       }
+       if (moves > 1L) update_inventory();
+    }
+}
+
+/* if a class name has been cleared, we may need to purge it from disco[] */
+void
+undiscover_object(oindx)
+register int oindx;
+{
+    if (!objects[oindx].oc_name_known) {
+       register int dindx, acls = objects[oindx].oc_class;
+       register boolean found = FALSE;
+
+       /* find the object; shift those behind it forward one slot */
+       for (dindx = bases[acls];
+             dindx < NUM_OBJECTS && disco[dindx] != 0
+               && objects[dindx].oc_class == acls; dindx++)
+           if (found)
+               disco[dindx-1] = disco[dindx];
+           else if (disco[dindx] == oindx)
+               found = TRUE;
+
+       /* clear last slot */
+       if (found) disco[dindx-1] = 0;
+       else impossible("named object not in disco");
+       update_inventory();
+    }
+}
+
+STATIC_OVL boolean
+interesting_to_discover(i)
+register int i;
+{
+       /* Pre-discovered objects are now printed with a '*' */
+    return((boolean)(objects[i].oc_uname != (char *)0 ||
+           (objects[i].oc_name_known && OBJ_DESCR(objects[i]) != (char *)0)));
+}
+
+/* items that should stand out once they're known */
+static short uniq_objs[] = {
+       AMULET_OF_YENDOR,
+       SPE_BOOK_OF_THE_DEAD,
+       CANDELABRUM_OF_INVOCATION,
+       BELL_OF_OPENING,
+};
+
+int
+dodiscovered()                         /* free after Robert Viduya */
+{
+    register int i, dis;
+    int        ct = 0;
+    char *s, oclass, prev_class, classes[MAXOCLASSES];
+    winid tmpwin;
+       char buf[BUFSZ];
+
+    tmpwin = create_nhwindow(NHW_MENU);
+    putstr(tmpwin, 0, "Discoveries");
+    putstr(tmpwin, 0, "");
+
+    /* gather "unique objects" into a pseudo-class; note that they'll
+       also be displayed individually within their regular class */
+    for (i = dis = 0; i < SIZE(uniq_objs); i++)
+       if (objects[uniq_objs[i]].oc_name_known) {
+           if (!dis++)
+               putstr(tmpwin, iflags.menu_headings, "Unique Items");
+               Sprintf(buf, "  %s", OBJ_NAME(objects[uniq_objs[i]]));
+           putstr(tmpwin, 0, buf);
+           ++ct;
+       }
+    /* display any known artifacts as another pseudo-class */
+    ct += disp_artifact_discoveries(tmpwin);
+
+    /* several classes are omitted from packorder; one is of interest here */
+    Strcpy(classes, flags.inv_order);
+    if (!index(classes, VENOM_CLASS)) {
+       s = eos(classes);
+       *s++ = VENOM_CLASS;
+       *s = '\0';
+    }
+
+    for (s = classes; *s; s++) {
+       oclass = *s;
+       prev_class = oclass + 1;        /* forced different from oclass */
+       for (i = bases[(int)oclass];
+            i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) {
+           if ((dis = disco[i]) && interesting_to_discover(dis)) {
+               ct++;
+               if (oclass != prev_class) {
+                   putstr(tmpwin, iflags.menu_headings, let_to_name(oclass, FALSE));
+                   prev_class = oclass;
+               }
+               Sprintf(buf, "%s %s",(objects[dis].oc_pre_discovered ? "*" : " "),
+                               obj_typename(dis));
+               putstr(tmpwin, 0, buf);
+           }
+       }
+    }
+    if (ct == 0) {
+       You("haven't discovered anything yet...");
+    } else
+       display_nhwindow(tmpwin, TRUE);
+    destroy_nhwindow(tmpwin);
+
+    return 0;
+}
+
+/*o_init.c*/
diff --git a/src/objects.c b/src/objects.c
new file mode 100644 (file)
index 0000000..1b18a3d
--- /dev/null
@@ -0,0 +1,991 @@
+/*     SCCS Id: @(#)objects.c  3.4     2002/07/31      */
+/* Copyright (c) Mike Threepoint, 1989.                                  */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef OBJECTS_PASS_2_
+/* first pass */
+struct monst { struct monst *dummy; }; /* lint: struct obj's union */
+#include "config.h"
+#include "obj.h"
+#include "objclass.h"
+#include "prop.h"
+#include "skills.h"
+
+#else  /* !OBJECTS_PASS_2_ */
+/* second pass */
+#include "color.h"
+#  define COLOR_FIELD(X) X,
+#endif /* !OBJECTS_PASS_2_ */
+
+
+/* objects have symbols: ) [ = " ( % ! ? + / $ * ` 0 _ . */
+
+/*
+ *     Note:  OBJ() and BITS() macros are used to avoid exceeding argument
+ *     limits imposed by some compilers.  The ctnr field of BITS currently
+ *     does not map into struct objclass, and is ignored in the expansion.
+ *     The 0 in the expansion corresponds to oc_pre_discovered, which is
+ *     set at run-time during role-specific character initialization.
+ */
+
+#ifndef OBJECTS_PASS_2_
+/* first pass -- object descriptive text */
+# define OBJ(name,desc) name,desc
+# define OBJECT(obj,bits,prp,sym,prob,dly,wt,cost,sdam,ldam,oc1,oc2,nut,color) \
+       {obj}
+
+NEARDATA struct objdescr obj_descr[] = {
+#else
+/* second pass -- object definitions */
+
+# define BITS(nmkn,mrg,uskn,ctnr,mgc,chrg,uniq,nwsh,big,tuf,dir,sub,mtrl) \
+       nmkn,mrg,uskn,0,mgc,chrg,uniq,nwsh,big,tuf,dir,mtrl,sub /* SCO ODT 1.1 cpp fodder */
+# define OBJECT(obj,bits,prp,sym,prob,dly,wt,cost,sdam,ldam,oc1,oc2,nut,color) \
+       {0, 0, (char *)0, bits, prp, sym, dly, COLOR_FIELD(color) \
+        prob, wt, cost, sdam, ldam, oc1, oc2, nut}
+# ifndef lint
+#  define HARDGEM(n) (n >= 8)
+# else
+#  define HARDGEM(n) (0)
+# endif
+
+NEARDATA struct objclass objects[] = {
+#endif
+/* dummy object[0] -- description [2nd arg] *must* be NULL */
+       OBJECT(OBJ("strange object",(char *)0), BITS(1,0,0,0,0,0,0,0,0,0,0,P_NONE,0),
+                       0, ILLOBJ_CLASS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+
+/* weapons ... */
+#define WEAPON(name,app,kn,mg,bi,prob,wt,cost,sdam,ldam,hitbon,typ,sub,metal,color) \
+       OBJECT( \
+               OBJ(name,app), BITS(kn,mg,1,0,0,1,0,0,bi,0,typ,sub,metal), 0, \
+               WEAPON_CLASS, prob, 0, \
+               wt, cost, sdam, ldam, hitbon, 0, wt, color )
+#define PROJECTILE(name,app,kn,prob,wt,cost,sdam,ldam,hitbon,metal,sub,color) \
+       OBJECT( \
+               OBJ(name,app), \
+               BITS(kn,1,1,0,0,1,0,0,0,0,PIERCE,sub,metal), 0, \
+               WEAPON_CLASS, prob, 0, \
+               wt, cost, sdam, ldam, hitbon, 0, wt, color )
+#define BOW(name,app,kn,prob,wt,cost,hitbon,metal,sub,color) \
+       OBJECT( \
+               OBJ(name,app), BITS(kn,0,1,0,0,1,0,0,0,0,0,sub,metal), 0, \
+               WEAPON_CLASS, prob, 0, \
+               wt, cost, 2, 2, hitbon, 0, wt, color )
+
+/* Note: for weapons that don't do an even die of damage (ex. 2-7 or 3-18)
+ * the extra damage is added on in weapon.c, not here! */
+
+#define P PIERCE
+#define S SLASH
+#define B WHACK
+
+/* missiles */
+PROJECTILE("arrow", (char *)0,
+               1, 55, 1, 2, 6, 6, 0, IRON, -P_BOW, HI_METAL),
+PROJECTILE("elven arrow", "runed arrow",
+               0, 20, 1, 2, 7, 6, 0, WOOD, -P_BOW, HI_WOOD),
+PROJECTILE("orcish arrow", "crude arrow",
+               0, 20, 1, 2, 5, 6, 0, IRON, -P_BOW, CLR_BLACK),
+PROJECTILE("silver arrow", (char *)0,
+               1, 12, 1, 5, 6, 6, 0, SILVER, -P_BOW, HI_SILVER),
+PROJECTILE("ya", "bamboo arrow",
+               0, 15, 1, 4, 7, 7, 1, METAL, -P_BOW, HI_METAL),
+PROJECTILE("crossbow bolt", (char *)0,
+               1, 55, 1, 2, 4, 6, 0, IRON, -P_CROSSBOW, HI_METAL),
+
+WEAPON("dart", (char *)0,
+       1, 1, 0, 60,  1,  2,  3,  2, 0, P,   -P_DART, IRON, HI_METAL),
+WEAPON("shuriken", "throwing star",
+       0, 1, 0, 35,  1,  5,  8,  6, 2, P,   -P_SHURIKEN, IRON, HI_METAL),
+WEAPON("boomerang", (char *)0,
+       1, 1, 0, 15,  5, 20,  9,  9, 0, 0,   -P_BOOMERANG, WOOD, HI_WOOD),
+
+/* spears */
+WEAPON("spear", (char *)0,
+       1, 1, 0, 50, 30,  3,  6,  8, 0, P,   P_SPEAR, IRON, HI_METAL),
+WEAPON("elven spear", "runed spear",
+       0, 1, 0, 10, 30,  3,  7,  8, 0, P,   P_SPEAR, WOOD, HI_WOOD),
+WEAPON("orcish spear", "crude spear",
+       0, 1, 0, 13, 30,  3,  5,  8, 0, P,   P_SPEAR, IRON, CLR_BLACK),
+WEAPON("dwarvish spear", "stout spear",
+       0, 1, 0, 12, 35,  3,  8,  8, 0, P,   P_SPEAR, IRON, HI_METAL),
+WEAPON("silver spear", (char *)0,
+       1, 1, 0,  2, 36, 40,  6,  8, 0, P,   P_SPEAR, SILVER, HI_SILVER),
+WEAPON("javelin", "throwing spear",
+       0, 1, 0, 10, 20,  3,  6,  6, 0, P,   P_JAVELIN, IRON, HI_METAL),
+
+WEAPON("trident", (char *)0,
+       1, 0, 0,  8, 25,  5,  6,  4, 0, P,   P_TRIDENT, IRON, HI_METAL),
+                                               /* +1 small, +2d4 large */
+
+/* blades */
+WEAPON("dagger", (char *)0,
+       1, 1, 0, 30, 10,  4,  4,  3, 2, P,   P_DAGGER, IRON, HI_METAL),
+WEAPON("elven dagger", "runed dagger",
+       0, 1, 0, 10, 10,  4,  5,  3, 2, P,   P_DAGGER, WOOD, HI_WOOD),
+WEAPON("orcish dagger", "crude dagger",
+       0, 1, 0, 12, 10,  4,  3,  3, 2, P,   P_DAGGER, IRON, CLR_BLACK),
+WEAPON("silver dagger", (char *)0,
+       1, 1, 0,  3, 12, 40,  4,  3, 2, P,   P_DAGGER, SILVER, HI_SILVER),
+WEAPON("athame", (char *)0,
+       1, 1, 0,  0, 10,  4,  4,  3, 2, S,   P_DAGGER, IRON, HI_METAL),
+WEAPON("scalpel", (char *)0,
+       1, 1, 0,  0,  5,  6,  3,  3, 2, S,   P_KNIFE, METAL, HI_METAL),
+WEAPON("knife", (char *)0,
+       1, 1, 0, 20,  5,  4,  3,  2, 0, P|S, P_KNIFE, IRON, HI_METAL),
+WEAPON("stiletto", (char *)0,
+       1, 1, 0,  5,  5,  4,  3,  2, 0, P|S, P_KNIFE, IRON, HI_METAL),
+WEAPON("worm tooth", (char *)0,
+       1, 0, 0,  0, 20,  2,  2,  2, 0, 0,   P_KNIFE, 0, CLR_WHITE),
+WEAPON("crysknife", (char *)0,
+       1, 0, 0,  0, 20,100, 10, 10, 3, P,   P_KNIFE, MINERAL, CLR_WHITE),
+
+WEAPON("axe", (char *)0,
+       1, 0, 0, 40, 60,  8,  6,  4, 0, S,   P_AXE, IRON, HI_METAL),
+WEAPON("battle-axe", "double-headed axe",
+       0, 0, 1, 10,120, 40,  8,  6, 0, S,   P_AXE, IRON, HI_METAL),
+                                               /* "double-bitted" ? */
+
+/* swords */
+WEAPON("short sword", (char *)0,
+       1, 0, 0,  8, 30, 10,  6,  8, 0, P,   P_SHORT_SWORD, IRON, HI_METAL),
+WEAPON("elven short sword", "runed short sword",
+       0, 0, 0,  2, 30, 10,  8,  8, 0, P,   P_SHORT_SWORD, WOOD, HI_WOOD),
+WEAPON("orcish short sword", "crude short sword",
+       0, 0, 0,  3, 30, 10,  5,  8, 0, P,   P_SHORT_SWORD, IRON, CLR_BLACK),
+WEAPON("dwarvish short sword", "broad short sword",
+       0, 0, 0,  2, 30, 10,  7,  8, 0, P,   P_SHORT_SWORD, IRON, HI_METAL),
+WEAPON("scimitar", "curved sword",
+       0, 0, 0, 15, 40, 15,  8,  8, 0, S,   P_SCIMITAR, IRON, HI_METAL),
+WEAPON("silver saber", (char *)0,
+       1, 0, 0,  6, 40, 75,  8,  8, 0, S,   P_SABER, SILVER, HI_SILVER),
+WEAPON("broadsword", (char *)0,
+       1, 0, 0,  8, 70, 10,  4,  6, 0, S,   P_BROAD_SWORD, IRON, HI_METAL),
+                                               /* +d4 small, +1 large */
+WEAPON("elven broadsword", "runed broadsword",
+       0, 0, 0,  4, 70, 10,  6,  6, 0, S,   P_BROAD_SWORD, WOOD, HI_WOOD),
+                                               /* +d4 small, +1 large */
+WEAPON("long sword", (char *)0,
+       1, 0, 0, 50, 40, 15,  8, 12, 0, S,   P_LONG_SWORD, IRON, HI_METAL),
+WEAPON("two-handed sword", (char *)0,
+       1, 0, 1, 22,150, 50, 12,  6, 0, S,   P_TWO_HANDED_SWORD, IRON, HI_METAL),
+                                               /* +2d6 large */
+WEAPON("katana", "samurai sword",
+       0, 0, 0,  4, 40, 80, 10, 12, 1, S,   P_LONG_SWORD, IRON, HI_METAL),
+/* special swords set up for artifacts */
+WEAPON("tsurugi", "long samurai sword",
+       0, 0, 1,  0, 60,500, 16,  8, 2, S,   P_TWO_HANDED_SWORD, METAL, HI_METAL),
+                                               /* +2d6 large */
+WEAPON("runesword", "runed broadsword",
+       0, 0, 0,  0, 40,300,  4,  6, 0, S,   P_BROAD_SWORD, IRON, CLR_BLACK),
+                                               /* +d4 small, +1 large */
+                                               /* +5d2 +d8 from level drain */
+
+/* polearms */
+/* spear-type */
+WEAPON("partisan", "vulgar polearm",
+       0, 0, 1,  5, 80, 10,  6,  6, 0, P,   P_POLEARMS, IRON, HI_METAL),
+                                               /* +1 large */
+WEAPON("ranseur", "hilted polearm",
+       0, 0, 1,  5, 50,  6,  4,  4, 0, P,   P_POLEARMS, IRON, HI_METAL),
+                                               /* +d4 both */
+WEAPON("spetum", "forked polearm",
+       0, 0, 1,  5, 50,  5,  6,  6, 0, P,   P_POLEARMS, IRON, HI_METAL),
+                                               /* +1 small, +d6 large */
+WEAPON("glaive", "single-edged polearm",
+       0, 0, 1,  8, 75,  6,  6, 10, 0, S,   P_POLEARMS, IRON, HI_METAL),
+WEAPON("lance", (char *)0,
+       1, 0, 0,  4,180, 10,  6,  8, 0, P,   P_LANCE, IRON, HI_METAL),
+/* axe-type */
+WEAPON("halberd", "angled poleaxe",
+       0, 0, 1,  8,150, 10, 10,  6, 0, P|S, P_POLEARMS, IRON, HI_METAL),
+                                               /* +1d6 large */
+WEAPON("bardiche", "long poleaxe",
+       0, 0, 1,  4,120,  7,  4,  4, 0, S,   P_POLEARMS, IRON, HI_METAL),
+                                               /* +1d4 small, +2d4 large */
+WEAPON("voulge", "pole cleaver",
+       0, 0, 1,  4,125,  5,  4,  4, 0, S,   P_POLEARMS, IRON, HI_METAL),
+                                               /* +d4 both */
+WEAPON("dwarvish mattock", "broad pick",
+       0, 0, 1, 13,120, 50, 12,  8,-1, B,   P_PICK_AXE, IRON, HI_METAL),
+
+/* curved/hooked */
+WEAPON("fauchard", "pole sickle",
+       0, 0, 1,  6, 60,  5,  6,  8, 0, P|S, P_POLEARMS, IRON, HI_METAL),
+WEAPON("guisarme", "pruning hook",
+       0, 0, 1,  6, 80,  5,  4,  8, 0, S,   P_POLEARMS, IRON, HI_METAL),
+                                               /* +1d4 small */
+WEAPON("bill-guisarme", "hooked polearm",
+       0, 0, 1,  4,120,  7,  4, 10, 0, P|S, P_POLEARMS, IRON, HI_METAL),
+                                               /* +1d4 small */
+/* other */
+WEAPON("lucern hammer", "pronged polearm",
+       0, 0, 1,  5,150,  7,  4,  6, 0, B|P, P_POLEARMS, IRON, HI_METAL),
+                                               /* +1d4 small */
+WEAPON("bec de corbin", "beaked polearm",
+       0, 0, 1,  4,100,  8,  8,  6, 0, B|P, P_POLEARMS, IRON, HI_METAL),
+
+/* bludgeons */
+WEAPON("mace", (char *)0,
+       1, 0, 0, 40, 30,  5,  6,  6, 0, B,   P_MACE, IRON, HI_METAL),
+                                               /* +1 small */
+WEAPON("morning star", (char *)0,
+       1, 0, 0, 12,120, 10,  4,  6, 0, B,   P_MORNING_STAR, IRON, HI_METAL),
+                                               /* +d4 small, +1 large */
+WEAPON("war hammer", (char *)0,
+       1, 0, 0, 15, 50,  5,  4,  4, 0, B,   P_HAMMER, IRON, HI_METAL),
+                                               /* +1 small */
+WEAPON("club", (char *)0,
+       1, 0, 0, 12, 30,  3,  6,  3, 0, B,   P_CLUB, WOOD, HI_WOOD),
+#ifdef KOPS
+WEAPON("rubber hose", (char *)0,
+       1, 0, 0,  0, 20,  3,  4,  3, 0, B,   P_WHIP, PLASTIC, CLR_BROWN),
+#endif
+WEAPON("quarterstaff", "staff",
+       0, 0, 1, 11, 40,  5,  6,  6, 0, B,   P_QUARTERSTAFF, WOOD, HI_WOOD),
+/* two-piece */
+WEAPON("aklys", "thonged club",
+       0, 0, 0,  8, 15,  4,  6,  3, 0, B,   P_CLUB, IRON, HI_METAL),
+WEAPON("flail", (char *)0,
+       1, 0, 0, 40, 15,  4,  6,  4, 0, B,   P_FLAIL, IRON, HI_METAL),
+                                               /* +1 small, +1d4 large */
+/* misc */
+WEAPON("bullwhip", (char *)0,
+       1, 0, 0,  2, 20,  4,  2,  1, 0, 0,   P_WHIP, LEATHER, CLR_BROWN),
+
+/* bows */
+BOW("bow", (char *)0,          1, 24, 30, 60, 0, WOOD, P_BOW, HI_WOOD),
+BOW("elven bow", "runed bow",  0, 12, 30, 60, 0, WOOD, P_BOW, HI_WOOD),
+BOW("orcish bow", "crude bow", 0, 12, 30, 60, 0, WOOD, P_BOW, CLR_BLACK),
+BOW("yumi", "long bow",                0,  0, 30, 60, 0, WOOD, P_BOW, HI_WOOD),
+BOW("sling", (char *)0,                1, 40,  3, 20, 0, LEATHER, P_SLING, HI_LEATHER),
+BOW("crossbow", (char *)0,     1, 45, 50, 40, 0, WOOD, P_CROSSBOW, HI_WOOD),
+
+#undef P
+#undef S
+#undef B
+
+#undef WEAPON
+#undef PROJECTILE
+#undef BOW
+
+/* armor ... */
+/* IRON denotes ferrous metals, including steel.
+ * Only IRON weapons and armor can rust.
+ * Only COPPER (including brass) corrodes.
+ * Some creatures are vulnerable to SILVER.
+ */
+#define ARMOR(name,desc,kn,mgc,blk,power,prob,delay,wt,cost,ac,can,sub,metal,c) \
+       OBJECT( \
+               OBJ(name,desc), BITS(kn,0,1,0,mgc,1,0,0,blk,0,0,sub,metal), power, \
+               ARMOR_CLASS, prob, delay, wt, cost, \
+               0, 0, 10 - ac, can, wt, c )
+#define HELM(name,desc,kn,mgc,power,prob,delay,wt,cost,ac,can,metal,c) \
+       ARMOR(name,desc,kn,mgc,0,power,prob,delay,wt,cost,ac,can,ARM_HELM,metal,c)
+#define CLOAK(name,desc,kn,mgc,power,prob,delay,wt,cost,ac,can,metal,c) \
+       ARMOR(name,desc,kn,mgc,0,power,prob,delay,wt,cost,ac,can,ARM_CLOAK,metal,c)
+#define SHIELD(name,desc,kn,mgc,blk,power,prob,delay,wt,cost,ac,can,metal,c) \
+       ARMOR(name,desc,kn,mgc,blk,power,prob,delay,wt,cost,ac,can,ARM_SHIELD,metal,c)
+#define GLOVES(name,desc,kn,mgc,power,prob,delay,wt,cost,ac,can,metal,c) \
+       ARMOR(name,desc,kn,mgc,0,power,prob,delay,wt,cost,ac,can,ARM_GLOVES,metal,c)
+#define BOOTS(name,desc,kn,mgc,power,prob,delay,wt,cost,ac,can,metal,c) \
+       ARMOR(name,desc,kn,mgc,0,power,prob,delay,wt,cost,ac,can,ARM_BOOTS,metal,c)
+
+/* helmets */
+HELM("elven leather helm", "leather hat",
+               0, 0,  0,       6, 1,  3,   8, 9, 0, LEATHER, HI_LEATHER),
+HELM("orcish helm", "iron skull cap",
+               0, 0,  0,       6, 1, 30,  10, 9, 0, IRON, CLR_BLACK),
+HELM("dwarvish iron helm", "hard hat",
+               0, 0,  0,       6, 1, 40,  20, 8, 0, IRON, HI_METAL),
+HELM("fedora", (char *)0,
+               1, 0,  0,       0, 0,  3,   1,10, 0, CLOTH, CLR_BROWN),
+HELM("cornuthaum", "conical hat",
+               0, 1,  CLAIRVOYANT,
+                               3, 1,  4,  80,10, 2, CLOTH, CLR_BLUE),
+HELM("dunce cap", "conical hat",
+               0, 1,  0,       3, 1,  4,   1,10, 0, CLOTH, CLR_BLUE),
+HELM("dented pot", (char *)0,
+               1, 0,  0,       2, 0, 10,   8, 9, 0, IRON, CLR_BLACK),
+/* With shuffled appearances... */
+HELM("helmet", "plumed helmet",
+               0, 0,  0,      10, 1, 30,  10, 9, 0, IRON, HI_METAL),
+HELM("helm of brilliance", "etched helmet",
+               0, 1,  0,       6, 1, 50,  50, 9, 0, IRON, CLR_GREEN),
+HELM("helm of opposite alignment", "crested helmet",
+               0, 1,  0,       6, 1, 50,  50, 9, 0, IRON, HI_METAL),
+HELM("helm of telepathy", "visored helmet",
+               0, 1,  TELEPAT, 2, 1, 50,  50, 9, 0, IRON, HI_METAL),
+
+/* suits of armor */
+/*
+ * There is code in polyself.c that assumes (1) and (2).
+ * There is code in obj.h, objnam.c, mon.c, read.c that assumes (2).
+ *
+ *     (1) The dragon scale mails and the dragon scales are together.
+ *     (2) That the order of the dragon scale mail and dragon scales is the
+ *         the same defined in monst.c.
+ */
+#define DRGN_ARMR(name,mgc,power,cost,ac,color) \
+       ARMOR(name,(char *)0,1,mgc,1,power,0,5,40,cost,ac,0,ARM_SUIT,DRAGON_HIDE,color)
+/* 3.4.1: dragon scale mail reclassified as "magic" since magic is
+   needed to create them */
+DRGN_ARMR("gray dragon scale mail",   1, ANTIMAGIC,  1200, 1, CLR_GRAY),
+DRGN_ARMR("silver dragon scale mail", 1, REFLECTING, 1200, 1, DRAGON_SILVER),
+#if 0  /* DEFERRED */
+DRGN_ARMR("shimmering dragon scale mail", 1, DISPLACED, 1200, 1, CLR_CYAN),
+#endif
+DRGN_ARMR("red dragon scale mail",    1, FIRE_RES,    900, 1, CLR_RED),
+DRGN_ARMR("white dragon scale mail",  1, COLD_RES,    900, 1, CLR_WHITE),
+DRGN_ARMR("orange dragon scale mail", 1, SLEEP_RES,   900, 1, CLR_ORANGE),
+DRGN_ARMR("black dragon scale mail",  1, DISINT_RES, 1200, 1, CLR_BLACK),
+DRGN_ARMR("blue dragon scale mail",   1, SHOCK_RES,   900, 1, CLR_BLUE),
+DRGN_ARMR("green dragon scale mail",  1, POISON_RES,  900, 1, CLR_GREEN),
+DRGN_ARMR("yellow dragon scale mail", 1, ACID_RES,    900, 1, CLR_YELLOW),
+
+/* For now, only dragons leave these. */
+/* 3.4.1: dragon scales left classified as "non-magic"; they confer
+   magical properties but are produced "naturally" */
+DRGN_ARMR("gray dragon scales",   0, ANTIMAGIC,  700, 7, CLR_GRAY),
+DRGN_ARMR("silver dragon scales", 0, REFLECTING, 700, 7, DRAGON_SILVER),
+#if 0  /* DEFERRED */
+DRGN_ARMR("shimmering dragon scales", 0, DISPLACED,  700, 7, CLR_CYAN),
+#endif
+DRGN_ARMR("red dragon scales",    0, FIRE_RES,   500, 7, CLR_RED),
+DRGN_ARMR("white dragon scales",  0, COLD_RES,   500, 7, CLR_WHITE),
+DRGN_ARMR("orange dragon scales", 0, SLEEP_RES,  500, 7, CLR_ORANGE),
+DRGN_ARMR("black dragon scales",  0, DISINT_RES, 700, 7, CLR_BLACK),
+DRGN_ARMR("blue dragon scales",   0, SHOCK_RES,  500, 7, CLR_BLUE),
+DRGN_ARMR("green dragon scales",  0, POISON_RES, 500, 7, CLR_GREEN),
+DRGN_ARMR("yellow dragon scales", 0, ACID_RES,   500, 7, CLR_YELLOW),
+#undef DRGN_ARMR
+
+ARMOR("plate mail", (char *)0,
+       1, 0, 1, 0,     44, 5, 450, 600,  3, 2, ARM_SUIT, IRON, HI_METAL),
+ARMOR("crystal plate mail", (char *)0,
+       1, 0, 1, 0,     10, 5, 450, 820,  3, 2, ARM_SUIT, GLASS, CLR_WHITE),
+#ifdef TOURIST
+ARMOR("bronze plate mail", (char *)0,
+       1, 0, 1, 0,     25, 5, 450, 400,  4, 0, ARM_SUIT, COPPER, HI_COPPER),
+#else
+ARMOR("bronze plate mail", (char *)0,
+       1, 0, 1, 0,     35, 5, 450, 400,  4, 0, ARM_SUIT, COPPER, HI_COPPER),
+#endif
+ARMOR("splint mail", (char *)0,
+       1, 0, 1, 0,     62, 5, 400,  80,  4, 1, ARM_SUIT, IRON, HI_METAL),
+ARMOR("banded mail", (char *)0,
+       1, 0, 1, 0,     72, 5, 350,  90,  4, 0, ARM_SUIT, IRON, HI_METAL),
+ARMOR("dwarvish mithril-coat", (char *)0,
+       1, 0, 0, 0,     10, 1, 150, 240,  4, 3, ARM_SUIT, MITHRIL, HI_METAL),
+ARMOR("elven mithril-coat", (char *)0,
+       1, 0, 0, 0,     15, 1, 150, 240,  5, 3, ARM_SUIT, MITHRIL, HI_METAL),
+ARMOR("chain mail", (char *)0,
+       1, 0, 0, 0,     72, 5, 300,  75,  5, 1, ARM_SUIT, IRON, HI_METAL),
+ARMOR("orcish chain mail", "crude chain mail",
+       0, 0, 0, 0,     20, 5, 300,  75,  6, 1, ARM_SUIT, IRON, CLR_BLACK),
+ARMOR("scale mail", (char *)0,
+       1, 0, 0, 0,     72, 5, 250,  45,  6, 0, ARM_SUIT, IRON, HI_METAL),
+ARMOR("studded leather armor", (char *)0,
+       1, 0, 0, 0,     72, 3, 200,  15,  7, 1, ARM_SUIT, LEATHER, HI_LEATHER),
+ARMOR("ring mail", (char *)0,
+       1, 0, 0, 0,     72, 5, 250, 100,  7, 0, ARM_SUIT, IRON, HI_METAL),
+ARMOR("orcish ring mail", "crude ring mail",
+       0, 0, 0, 0,     20, 5, 250,  80,  8, 1, ARM_SUIT, IRON, CLR_BLACK),
+ARMOR("leather armor", (char *)0,
+       1, 0, 0, 0,     82, 3, 150,   5,  8, 0, ARM_SUIT, LEATHER, HI_LEATHER),
+ARMOR("leather jacket", (char *)0,
+       1, 0, 0, 0,     12, 0,  30,  10,  9, 0, ARM_SUIT, LEATHER, CLR_BLACK),
+
+#ifdef TOURIST
+/* shirts */
+ARMOR("Hawaiian shirt", (char *)0,
+       1, 0, 0, 0,      8, 0,   5,   3, 10, 0, ARM_SHIRT, CLOTH, CLR_MAGENTA),
+ARMOR("T-shirt", (char *)0,
+       1, 0, 0, 0,      2, 0,   5,   2, 10, 0, ARM_SHIRT, CLOTH, CLR_WHITE),
+#endif
+
+/* cloaks */
+/*  'cope' is not a spelling mistake... leave it be */
+CLOAK("mummy wrapping", (char *)0,
+               1, 0,   0,          0, 0,  3,  2, 10, 1, CLOTH, CLR_GRAY),
+CLOAK("elven cloak", "faded pall",
+               0, 1,   STEALTH,    8, 0, 10, 60,  9, 3, CLOTH, CLR_BLACK),
+CLOAK("orcish cloak", "coarse mantelet",
+               0, 0,   0,          8, 0, 10, 40, 10, 2, CLOTH, CLR_BLACK),
+CLOAK("dwarvish cloak", "hooded cloak",
+               0, 0,   0,          8, 0, 10, 50, 10, 2, CLOTH, HI_CLOTH),
+CLOAK("oilskin cloak", "slippery cloak",
+               0, 0,   0,          8, 0, 10, 50,  9, 3, CLOTH, HI_CLOTH),
+CLOAK("robe", (char *)0,
+               1, 1,   0,          3, 0, 15, 50,  8, 3, CLOTH, CLR_RED),
+CLOAK("alchemy smock", "apron",
+               0, 1,   POISON_RES, 9, 0, 10, 50,  9, 1, CLOTH, CLR_WHITE),
+CLOAK("leather cloak", (char *)0,
+               1, 0,   0,          8, 0, 15, 40,  9, 1, LEATHER, CLR_BROWN),
+/* With shuffled appearances... */
+CLOAK("cloak of protection", "tattered cape",
+               0, 1,   PROTECTION, 9, 0, 10, 50,  7, 3, CLOTH, HI_CLOTH),
+CLOAK("cloak of invisibility", "opera cloak",
+               0, 1,   INVIS,     10, 0, 10, 60,  9, 2, CLOTH, CLR_BRIGHT_MAGENTA),
+CLOAK("cloak of magic resistance", "ornamental cope",
+               0, 1,   ANTIMAGIC,  2, 0, 10, 60,  9, 3, CLOTH, CLR_WHITE),
+CLOAK("cloak of displacement", "piece of cloth",
+               0, 1,   DISPLACED, 10, 0, 10, 50,  9, 2, CLOTH, HI_CLOTH),
+
+/* shields */
+SHIELD("small shield", (char *)0,
+               1, 0, 0, 0,          6, 0, 30,  3,  9, 0, WOOD, HI_WOOD),
+SHIELD("elven shield", "blue and green shield",
+               0, 0, 0, 0,          2, 0, 40,  7,  8, 0, WOOD, CLR_GREEN),
+SHIELD("Uruk-hai shield", "white-handed shield",
+               0, 0, 0, 0,          2, 0, 50,  7,  9, 0, IRON, HI_METAL),
+SHIELD("orcish shield", "red-eyed shield",
+               0, 0, 0, 0,          2, 0, 50,  7,  9, 0, IRON, CLR_RED),
+SHIELD("large shield", (char *)0,
+               1, 0, 1, 0,          7, 0,100, 10,  8, 0, IRON, HI_METAL),
+SHIELD("dwarvish roundshield", "large round shield",
+               0, 0, 0, 0,          4, 0,100, 10,  8, 0, IRON, HI_METAL),
+SHIELD("shield of reflection", "polished silver shield",
+               0, 1, 0, REFLECTING, 3, 0, 50, 50,  8, 0, SILVER, HI_SILVER),
+
+/* gloves */
+/* these have their color but not material shuffled, so the IRON must stay
+ * CLR_BROWN (== HI_LEATHER)
+ */
+GLOVES("leather gloves", "old gloves",
+               0, 0,  0,         16, 1, 10,  8,  9, 0, LEATHER, HI_LEATHER),
+GLOVES("gauntlets of fumbling", "padded gloves",
+               0, 1,  FUMBLING,   8, 1, 10, 50,  9, 0, LEATHER, HI_LEATHER),
+GLOVES("gauntlets of power", "riding gloves",
+               0, 1,  0,          8, 1, 30, 50,  9, 0, IRON, CLR_BROWN),
+GLOVES("gauntlets of dexterity", "fencing gloves",
+               0, 1,  0,          8, 1, 10, 50,  9, 0, LEATHER, HI_LEATHER),
+
+/* boots */
+BOOTS("low boots", "walking shoes",
+               0, 0,  0,         25, 2, 10,  8,  9, 0, LEATHER, HI_LEATHER),
+BOOTS("iron shoes", "hard shoes",
+               0, 0,  0,          7, 2, 50, 16,  8, 0, IRON, HI_METAL),
+BOOTS("high boots", "jackboots",
+               0, 0,  0,         15, 2, 20, 12,  8, 0, LEATHER, HI_LEATHER),
+/* With shuffled appearances... */
+BOOTS("speed boots", "combat boots",
+               0, 1,  FAST,      12, 2, 20, 50,  9, 0, LEATHER, HI_LEATHER),
+BOOTS("water walking boots", "jungle boots",
+               0, 1,  WWALKING,  12, 2, 20, 50,  9, 0, LEATHER, HI_LEATHER),
+BOOTS("jumping boots", "hiking boots",
+               0, 1,  JUMPING,   12, 2, 20, 50,  9, 0, LEATHER, HI_LEATHER),
+BOOTS("elven boots", "mud boots",
+               0, 1,  STEALTH,   12, 2, 15,  8,  9, 0, LEATHER, HI_LEATHER),
+BOOTS("kicking boots", "buckled boots",
+               0, 1,  0,         12, 2, 15,  8,  9, 0, IRON, CLR_BROWN),
+BOOTS("fumble boots", "riding boots",
+               0, 1,  FUMBLING,  12, 2, 20, 30,  9, 0, LEATHER, HI_LEATHER),
+BOOTS("levitation boots", "snow boots",
+               0, 1,  LEVITATION,12, 2, 15, 30,  9, 0, LEATHER, HI_LEATHER),
+#undef HELM
+#undef CLOAK
+#undef SHIELD
+#undef GLOVES
+#undef BOOTS
+#undef ARMOR
+
+/* rings ... */
+#define RING(name,power,stone,cost,mgc,spec,mohs,metal,color) OBJECT( \
+               OBJ(name,stone), \
+               BITS(0,0,spec,0,mgc,spec,0,0,0,HARDGEM(mohs),0,P_NONE,metal), \
+               power, RING_CLASS, 0, 0, 3, cost, 0, 0, 0, 0, 15, color )
+RING("adornment", ADORNED, "wooden",        100, 1, 1, 2, WOOD, HI_WOOD),
+RING("gain strength", 0, "granite",         150, 1, 1, 7, MINERAL, HI_MINERAL),
+RING("gain constitution", 0, "opal",        150, 1, 1, 7, MINERAL,  HI_MINERAL),
+RING("increase accuracy", 0, "clay",        150, 1, 1, 4, MINERAL, CLR_RED),
+RING("increase damage", 0, "coral",         150, 1, 1, 4, MINERAL, CLR_ORANGE),
+RING("protection", PROTECTION, "black onyx",100, 1, 1, 7, MINERAL, CLR_BLACK),
+RING("regeneration", REGENERATION, "moonstone",
+                                           200, 1, 0, 6, MINERAL, HI_MINERAL),
+RING("searching", SEARCHING, "tiger eye",   200, 1, 0, 6, GEMSTONE, CLR_BROWN),
+RING("stealth", STEALTH, "jade",            100, 1, 0, 6, GEMSTONE, CLR_GREEN),
+RING("sustain ability", FIXED_ABIL, "bronze",
+                                           100, 1, 0, 4, COPPER, HI_COPPER),
+RING("levitation", LEVITATION, "agate",     200, 1, 0, 7, GEMSTONE, CLR_RED),
+RING("hunger", HUNGER, "topaz",             100, 1, 0, 8, GEMSTONE, CLR_CYAN),
+RING("aggravate monster", AGGRAVATE_MONSTER, "sapphire",
+                                           150, 1, 0, 9, GEMSTONE, CLR_BLUE),
+RING("conflict", CONFLICT, "ruby",          300, 1, 0, 9, GEMSTONE, CLR_RED),
+RING("warning", WARNING, "diamond",         100, 1, 0,10, GEMSTONE, CLR_WHITE),
+RING("poison resistance", POISON_RES, "pearl",
+                                           150, 1, 0, 4, IRON, CLR_WHITE),
+RING("fire resistance", FIRE_RES, "iron",   200, 1, 0, 5, IRON, HI_METAL),
+RING("cold resistance", COLD_RES, "brass",  150, 1, 0, 4, COPPER, HI_COPPER),
+RING("shock resistance", SHOCK_RES, "copper",
+                                           150, 1, 0, 3, COPPER, HI_COPPER),
+RING("free action",     FREE_ACTION, "twisted",
+                                           200, 1, 0, 6, IRON, HI_METAL),
+RING("slow digestion",  SLOW_DIGESTION, "steel",
+                                           200, 1, 0, 8, IRON, HI_METAL),
+RING("teleportation", TELEPORT, "silver",   200, 1, 0, 3, SILVER, HI_SILVER),
+RING("teleport control", TELEPORT_CONTROL, "gold",
+                                           300, 1, 0, 3, GOLD, HI_GOLD),
+RING("polymorph", POLYMORPH, "ivory",       300, 1, 0, 4, BONE, CLR_WHITE),
+RING("polymorph control", POLYMORPH_CONTROL, "emerald",
+                                           300, 1, 0, 8, GEMSTONE, CLR_BRIGHT_GREEN),
+RING("invisibility", INVIS, "wire",         150, 1, 0, 5, IRON, HI_METAL),
+RING("see invisible", SEE_INVIS, "engagement",
+                                           150, 1, 0, 5, IRON, HI_METAL),
+RING("protection from shape changers", PROT_FROM_SHAPE_CHANGERS, "shiny",
+                                           100, 1, 0, 5, IRON, CLR_BRIGHT_CYAN),
+#undef RING
+
+/* amulets ... - THE Amulet comes last because it is special */
+#define AMULET(name,desc,power,prob) OBJECT( \
+               OBJ(name,desc), BITS(0,0,0,0,1,0,0,0,0,0,0,P_NONE,IRON), power, \
+               AMULET_CLASS, prob, 0, 20, 150, 0, 0, 0, 0, 20, HI_METAL )
+
+AMULET("amulet of ESP",           "circular",   TELEPAT,    175),
+AMULET("amulet of life saving",   "spherical",  LIFESAVED,   75),
+AMULET("amulet of strangulation", "oval",       STRANGLED,  135),
+AMULET("amulet of restful sleep", "triangular", SLEEPING,   135),
+AMULET("amulet versus poison",    "pyramidal",  POISON_RES, 165),
+AMULET("amulet of change",        "square",     0,          130),
+                                               /* POLYMORPH */
+AMULET("amulet of unchanging",    "concave",    UNCHANGING,     45),
+AMULET("amulet of reflection",    "hexagonal",  REFLECTING,  75),
+AMULET("amulet of magical breathing", "octagonal",      MAGICAL_BREATHING, 65),
+OBJECT(OBJ("cheap plastic imitation of the Amulet of Yendor",
+       "Amulet of Yendor"), BITS(0,0,1,0,0,0,0,0,0,0,0,0,PLASTIC), 0,
+       AMULET_CLASS, 0, 0, 20,    0, 0, 0, 0, 0,  1, HI_METAL),
+OBJECT(OBJ("Amulet of Yendor", /* note: description == name */
+       "Amulet of Yendor"), BITS(0,0,1,0,1,0,1,1,0,0,0,0,MITHRIL), 0,
+       AMULET_CLASS, 0, 0, 20, 30000, 0, 0, 0, 0, 20, HI_METAL),
+#undef AMULET
+
+/* tools ... */
+/* tools with weapon characteristics come last */
+#define TOOL(name,desc,kn,mrg,mgc,chg,prob,wt,cost,mat,color) \
+       OBJECT( OBJ(name,desc), \
+               BITS(kn,mrg,chg,0,mgc,chg,0,0,0,0,0,P_NONE,mat), \
+               0, TOOL_CLASS, prob, 0, \
+               wt, cost, 0, 0, 0, 0, wt, color )
+#define CONTAINER(name,desc,kn,mgc,chg,prob,wt,cost,mat,color) \
+       OBJECT( OBJ(name,desc), \
+               BITS(kn,0,chg,1,mgc,chg,0,0,0,0,0,P_NONE,mat), \
+               0, TOOL_CLASS, prob, 0, \
+               wt, cost, 0, 0, 0, 0, wt, color )
+#define WEPTOOL(name,desc,kn,mgc,bi,prob,wt,cost,sdam,ldam,hitbon,sub,mat,clr) \
+       OBJECT( OBJ(name,desc), \
+               BITS(kn,0,1,0,mgc,1,0,0,bi,0,hitbon,sub,mat), \
+               0, TOOL_CLASS, prob, 0, \
+               wt, cost, sdam, ldam, hitbon, 0, wt, clr )
+/* containers */
+CONTAINER("large box", (char *)0,       1, 0, 0,  40,350,   8, WOOD, HI_WOOD),
+CONTAINER("chest", (char *)0,           1, 0, 0,  35,600,  16, WOOD, HI_WOOD),
+CONTAINER("ice box", (char *)0,         1, 0, 0,   5,900,  42, PLASTIC, CLR_WHITE),
+CONTAINER("sack", "bag",                0, 0, 0,  35, 15,   2, CLOTH, HI_CLOTH),
+CONTAINER("oilskin sack", "bag",        0, 0, 0,   5, 15, 100, CLOTH, HI_CLOTH),
+CONTAINER("bag of holding", "bag",      0, 1, 0,  20, 15, 100, CLOTH, HI_CLOTH),
+CONTAINER("bag of tricks", "bag",       0, 1, 1,  20, 15, 100, CLOTH, HI_CLOTH),
+#undef CONTAINER
+
+/* lock opening tools */
+TOOL("skeleton key", "key",     0, 0, 0, 0,  80,  3,  10, IRON, HI_METAL),
+#ifdef TOURIST
+TOOL("lock pick", (char *)0,    1, 0, 0, 0,  60,  4,  20, IRON, HI_METAL),
+TOOL("credit card", (char *)0,  1, 0, 0, 0,  15,  1,  10, PLASTIC, CLR_WHITE),
+#else
+TOOL("lock pick", (char *)0,    1, 0, 0, 0,  75,  4,  20, IRON, HI_METAL),
+#endif
+/* light sources */
+TOOL("tallow candle", "candle", 0, 1, 0, 0,  20,  2,  10, WAX, CLR_WHITE),
+TOOL("wax candle", "candle",    0, 1, 0, 0,   5,  2,  20, WAX, CLR_WHITE),
+TOOL("brass lantern", (char *)0,1, 0, 0, 0,  30, 30,  12, COPPER, CLR_YELLOW),
+TOOL("oil lamp", "lamp",        0, 0, 0, 0,  45, 20,  10, COPPER, CLR_YELLOW),
+TOOL("magic lamp", "lamp",      0, 0, 1, 0,  15, 20,  50, COPPER, CLR_YELLOW),
+/* other tools */
+#ifdef TOURIST
+TOOL("expensive camera", (char *)0,
+                               1, 0, 0, 1,  15, 12, 200, PLASTIC, CLR_BLACK),
+TOOL("mirror", "looking glass", 0, 0, 0, 0,  45, 13,  10, GLASS, HI_SILVER),
+#else
+TOOL("mirror", "looking glass", 0, 0, 0, 0,  60, 13,  10, GLASS, HI_SILVER),
+#endif
+TOOL("crystal ball", "glass orb",
+                               0, 0, 1, 1,  15,150,  60, GLASS, HI_GLASS),
+TOOL("lenses", (char *)0,      1, 0, 0, 0,   5,  3,  80, GLASS, HI_GLASS),
+TOOL("blindfold", (char *)0,    1, 0, 0, 0,  50,  2,  20, CLOTH, CLR_BLACK),
+TOOL("towel", (char *)0,        1, 0, 0, 0,  50,  2,  50, CLOTH, CLR_MAGENTA),
+#ifdef STEED
+TOOL("saddle", (char *)0,       1, 0, 0, 0,   5,200, 150, LEATHER, HI_LEATHER),
+TOOL("leash", (char *)0,        1, 0, 0, 0,  65, 12,  20, LEATHER, HI_LEATHER),
+#else
+TOOL("leash", (char *)0,        1, 0, 0, 0,  70, 12,  20, LEATHER, HI_LEATHER),
+#endif
+TOOL("stethoscope", (char *)0,  1, 0, 0, 0,  25,  4,  75, IRON, HI_METAL),
+TOOL("tinning kit", (char *)0,  1, 0, 0, 1,  15,100,  30, IRON, HI_METAL),
+TOOL("tin opener", (char *)0,   1, 0, 0, 0,  35,  4,  30, IRON, HI_METAL),
+TOOL("can of grease", (char *)0,1, 0, 0, 1,  15, 15,  20, IRON, HI_METAL),
+TOOL("figurine", (char *)0,     1, 0, 1, 0,  25, 50,  80, MINERAL, HI_MINERAL),
+TOOL("magic marker", (char *)0, 1, 0, 1, 1,  15,  2,  50, PLASTIC, CLR_RED),
+/* traps */
+TOOL("land mine",(char *)0,     1, 0, 0, 0,   0,300, 180, IRON, CLR_RED),
+TOOL("beartrap", (char *)0,     1, 0, 0, 0,   0,200,  60, IRON, HI_METAL),
+/* instruments */
+TOOL("tin whistle", "whistle",  0, 0, 0, 0, 100,  3,  10, METAL, HI_METAL),
+TOOL("magic whistle", "whistle",0, 0, 1, 0,  30,  3,  10, METAL, HI_METAL),
+/* "If tin whistles are made out of tin, what do they make foghorns out of?" */
+TOOL("wooden flute", "flute",   0, 0, 0, 0,   4,  5,  12, WOOD, HI_WOOD),
+TOOL("magic flute", "flute",    0, 0, 1, 1,   2,  5,  36, WOOD, HI_WOOD),
+TOOL("tooled horn", "horn",     0, 0, 0, 0,   5, 18,  15, BONE, CLR_WHITE),
+TOOL("frost horn", "horn",      0, 0, 1, 1,   2, 18,  50, BONE, CLR_WHITE),
+TOOL("fire horn", "horn",       0, 0, 1, 1,   2, 18,  50, BONE, CLR_WHITE),
+TOOL("horn of plenty", "horn",  0, 0, 1, 1,   2, 18,  50, BONE, CLR_WHITE),
+TOOL("wooden harp", "harp",     0, 0, 0, 0,   4, 30,  50, WOOD, HI_WOOD),
+TOOL("magic harp", "harp",      0, 0, 1, 1,   2, 30,  50, WOOD, HI_WOOD),
+TOOL("bell", (char *)0,         1, 0, 0, 0,   2, 30,  50, COPPER, HI_COPPER),
+TOOL("bugle", (char *)0,        1, 0, 0, 0,   4, 10,  15, COPPER, HI_COPPER),
+TOOL("leather drum", "drum",    0, 0, 0, 0,   4, 25,  25, LEATHER, HI_LEATHER),
+TOOL("drum of earthquake", "drum",
+                               0, 0, 1, 1,   2, 25,  25, LEATHER, HI_LEATHER),
+/* tools useful as weapons */
+WEPTOOL("pick-axe", (char *)0,
+       1, 0, 0, 20, 100,  50,  6,  3, WHACK,  P_PICK_AXE, IRON, HI_METAL),
+WEPTOOL("grappling hook", "iron hook",
+       0, 0, 0,  5,  30,  50,  2,  6, WHACK,  P_FLAIL, IRON, HI_METAL),
+/* 3.4.1: unicorn horn left classified as "magic" */
+WEPTOOL("unicorn horn", (char *)0,
+       1, 1, 1,  0,  20, 100, 12, 12, PIERCE, P_UNICORN_HORN, BONE, CLR_WHITE),
+
+/* two special unique artifact "tools" */
+OBJECT(OBJ("Candelabrum of Invocation", "candelabrum"),
+               BITS(0,0,1,0,1,0,1,1,0,0,0,P_NONE,GOLD), 0,
+               TOOL_CLASS, 0, 0,10, 5000, 0, 0, 0, 0, 200, HI_GOLD),
+OBJECT(OBJ("Bell of Opening", "silver bell"),
+               BITS(0,0,1,0,1,1,1,1,0,0,0,P_NONE,SILVER), 0,
+               TOOL_CLASS, 0, 0,10, 5000, 0, 0, 0, 0, 50, HI_SILVER),
+#undef TOOL
+#undef WEPTOOL
+
+/* Comestibles ... */
+#define FOOD(name,prob,delay,wt,unk,tin,nutrition,color) OBJECT( \
+               OBJ(name,(char *)0), BITS(1,1,unk,0,0,0,0,0,0,0,0,P_NONE,tin), 0, \
+               FOOD_CLASS, prob, delay, \
+               wt, nutrition/20 + 5, 0, 0, 0, 0, nutrition, color )
+/* all types of food (except tins & corpses) must have a delay of at least 1. */
+/* delay on corpses is computed and is weight dependant */
+/* dog eats foods 0-4 but prefers tripe rations above all others */
+/* fortune cookies can be read */
+/* carrots improve your vision */
+/* +0 tins contain monster meat */
+/* +1 tins (of spinach) make you stronger (like Popeye) */
+/* food CORPSE is a cadaver of some type */
+/* meatballs/sticks/rings are only created from objects via stone to flesh */
+
+/* meat */
+FOOD("tripe ration",       140, 2, 10, 0, FLESH, 200, CLR_BROWN),
+FOOD("corpse",               0, 1,  0, 0, FLESH,   0, CLR_BROWN),
+FOOD("egg",                 85, 1,  1, 1, FLESH,  80, CLR_WHITE),
+FOOD("meatball",             0, 1,  1, 0, FLESH,   5, CLR_BROWN),
+FOOD("meat stick",           0, 1,  1, 0, FLESH,   5, CLR_BROWN),
+FOOD("huge chunk of meat",   0,20,400, 0, FLESH,2000, CLR_BROWN),
+/* special case because it's not mergable */
+OBJECT(OBJ("meat ring", (char *)0),
+    BITS(1,0,0,0,0,0,0,0,0,0,0,0,FLESH),
+    0, FOOD_CLASS, 0, 1, 5, 1, 0, 0, 0, 0, 5, CLR_BROWN),
+
+/* fruits & veggies */
+FOOD("kelp frond",           0, 1,  1, 0, VEGGY,  30, CLR_GREEN),
+FOOD("eucalyptus leaf",      3, 1,  1, 0, VEGGY,  30, CLR_GREEN),
+FOOD("apple",               15, 1,  2, 0, VEGGY,  50, CLR_RED),
+FOOD("orange",              10, 1,  2, 0, VEGGY,  80, CLR_ORANGE),
+FOOD("pear",                10, 1,  2, 0, VEGGY,  50, CLR_BRIGHT_GREEN),
+FOOD("melon",               10, 1,  5, 0, VEGGY, 100, CLR_BRIGHT_GREEN),
+FOOD("banana",              10, 1,  2, 0, VEGGY,  80, CLR_YELLOW),
+FOOD("carrot",              15, 1,  2, 0, VEGGY,  50, CLR_ORANGE),
+FOOD("sprig of wolfsbane",   7, 1,  1, 0, VEGGY,  40, CLR_GREEN),
+FOOD("clove of garlic",      7, 1,  1, 0, VEGGY,  40, CLR_WHITE),
+FOOD("slime mold",          75, 1,  5, 0, VEGGY, 250, HI_ORGANIC),
+
+/* people food */
+FOOD("lump of royal jelly",  0, 1,  2, 0, VEGGY, 200, CLR_YELLOW),
+FOOD("cream pie",           25, 1, 10, 0, VEGGY, 100, CLR_WHITE),
+FOOD("candy bar",           13, 1,  2, 0, VEGGY, 100, CLR_BROWN),
+FOOD("fortune cookie",      55, 1,  1, 0, VEGGY,  40, CLR_YELLOW),
+FOOD("pancake",             25, 2,  2, 0, VEGGY, 200, CLR_YELLOW),
+FOOD("lembas wafer",        20, 2,  5, 0, VEGGY, 800, CLR_WHITE),
+FOOD("cram ration",         20, 3, 15, 0, VEGGY, 600, HI_ORGANIC),
+FOOD("food ration",        380, 5, 20, 0, VEGGY, 800, HI_ORGANIC),
+FOOD("K-ration",             0, 1, 10, 0, VEGGY, 400, HI_ORGANIC),
+FOOD("C-ration",             0, 1, 10, 0, VEGGY, 300, HI_ORGANIC),
+FOOD("tin",                 75, 0, 10, 1, METAL,   0, HI_METAL),
+#undef FOOD
+
+/* potions ... */
+#define POTION(name,desc,mgc,power,prob,cost,color) OBJECT( \
+               OBJ(name,desc), BITS(0,1,0,0,mgc,0,0,0,0,0,0,P_NONE,GLASS), power, \
+               POTION_CLASS, prob, 0, 20, cost, 0, 0, 0, 0, 10, color )
+POTION("gain ability", "ruby",          1, 0,          42, 300, CLR_RED),
+POTION("restore ability", "pink",       1, 0,          40, 100, CLR_BRIGHT_MAGENTA),
+POTION("confusion", "orange",           1, CONFUSION,  42, 100, CLR_ORANGE),
+POTION("blindness", "yellow",           1, BLINDED,    40, 150, CLR_YELLOW),
+POTION("paralysis", "emerald",          1, 0,          42, 300, CLR_BRIGHT_GREEN),
+POTION("speed", "dark green",           1, FAST,       42, 200, CLR_GREEN),
+POTION("levitation", "cyan",            1, LEVITATION, 42, 200, CLR_CYAN),
+POTION("hallucination", "sky blue",     1, HALLUC,     40, 100, CLR_CYAN),
+POTION("invisibility", "brilliant blue",1, INVIS,      40, 150, CLR_BRIGHT_BLUE),
+POTION("see invisible", "magenta",      1, SEE_INVIS,  42,  50, CLR_MAGENTA),
+POTION("healing", "purple-red",         1, 0,          57, 100, CLR_MAGENTA),
+POTION("extra healing", "puce",         1, 0,          47, 100, CLR_RED),
+POTION("gain level", "milky",           1, 0,          20, 300, CLR_WHITE),
+POTION("enlightenment", "swirly",       1, 0,          20, 200, CLR_BROWN),
+POTION("monster detection", "bubbly",   1, 0,          40, 150, CLR_WHITE),
+POTION("object detection", "smoky",     1, 0,          42, 150, CLR_GRAY),
+POTION("gain energy", "cloudy",         1, 0,          42, 150, CLR_WHITE),
+POTION("sleeping",  "effervescent",     1, 0,          42, 100, CLR_GRAY),
+POTION("full healing",  "black",        1, 0,          10, 200, CLR_BLACK),
+POTION("polymorph", "golden",           1, 0,          10, 200, CLR_YELLOW),
+POTION("booze", "brown",                0, 0,          42,  50, CLR_BROWN),
+POTION("sickness", "fizzy",             0, 0,          42,  50, CLR_CYAN),
+POTION("fruit juice", "dark",           0, 0,          42,  50, CLR_BLACK),
+POTION("acid", "white",                 0, 0,          10, 250, CLR_WHITE),
+POTION("oil", "murky",                  0, 0,          30, 250, CLR_BROWN),
+POTION("water", "clear",                0, 0,          92, 100, CLR_CYAN),
+#undef POTION
+
+/* scrolls ... */
+#define SCROLL(name,text,mgc,prob,cost) OBJECT( \
+               OBJ(name,text), BITS(0,1,0,0,mgc,0,0,0,0,0,0,P_NONE,PAPER), 0, \
+               SCROLL_CLASS, prob, 0, 5, cost, 0, 0, 0, 0, 6, HI_PAPER )
+       SCROLL("enchant armor",         "ZELGO MER",            1,  63,  80),
+       SCROLL("destroy armor",         "JUYED AWK YACC",       1,  45, 100),
+       SCROLL("confuse monster",       "NR 9",                 1,  53, 100),
+       SCROLL("scare monster",         "XIXAXA XOXAXA XUXAXA", 1,  35, 100),
+       SCROLL("remove curse",          "PRATYAVAYAH",          1,  65,  80),
+       SCROLL("enchant weapon",        "DAIYEN FOOELS",        1,  80,  60),
+       SCROLL("create monster",        "LEP GEX VEN ZEA",      1,  45, 200),
+       SCROLL("taming",                "PRIRUTSENIE",          1,  15, 200),
+       SCROLL("genocide",              "ELBIB YLOH",           1,  15, 300),
+       SCROLL("light",                 "VERR YED HORRE",       1,  90,  50),
+       SCROLL("teleportation",         "VENZAR BORGAVVE",      1,  55, 100),
+       SCROLL("gold detection",        "THARR",                1,  33, 100),
+       SCROLL("food detection",        "YUM YUM",              1,  25, 100),
+       SCROLL("identify",              "KERNOD WEL",           1, 180,  20),
+       SCROLL("magic mapping",         "ELAM EBOW",            1,  45, 100),
+       SCROLL("amnesia",               "DUAM XNAHT",           1,  35, 200),
+       SCROLL("fire",                  "ANDOVA BEGARIN",       1,  30, 100),
+       SCROLL("earth",                 "KIRJE",                1,  18, 200),
+       SCROLL("punishment",            "VE FORBRYDERNE",       1,  15, 300),
+       SCROLL("charging",              "HACKEM MUCHE",         1,  15, 300),
+       SCROLL("stinking cloud",        "VELOX NEB",            1,  15, 300),
+       SCROLL((char *)0,               "FOOBIE BLETCH",        1,   0, 100),
+       SCROLL((char *)0,               "TEMOV",                1,   0, 100),
+       SCROLL((char *)0,               "GARVEN DEH",           1,   0, 100),
+       SCROLL((char *)0,               "READ ME",              1,   0, 100),
+       /* these must come last because they have special descriptions */
+#ifdef MAIL
+       SCROLL("mail",                  "stamped",          0,   0,   0),
+#endif
+       SCROLL("blank paper",           "unlabeled",        0,  28,  60),
+#undef SCROLL
+
+/* spellbooks ... */
+#define SPELL(name,desc,sub,prob,delay,level,mgc,dir,color) OBJECT( \
+               OBJ(name,desc), BITS(0,0,0,0,mgc,0,0,0,0,0,dir,sub,PAPER), 0, \
+               SPBOOK_CLASS, prob, delay, \
+               50, level*100, 0, 0, 0, level, 20, color )
+SPELL("dig",             "parchment",   P_MATTER_SPELL, 20,  6, 5, 1, RAY,       HI_PAPER),
+SPELL("magic missile",   "vellum",      P_ATTACK_SPELL, 45,  2, 2, 1, RAY,       HI_PAPER),
+SPELL("fireball",        "ragged",      P_ATTACK_SPELL, 20,  4, 4, 1, RAY,       HI_PAPER),
+SPELL("cone of cold",    "dog eared",   P_ATTACK_SPELL, 10,  7, 4, 1, RAY,       HI_PAPER),
+SPELL("sleep",           "mottled",     P_ENCHANTMENT_SPELL, 50,  1, 1, 1, RAY,       HI_PAPER),
+SPELL("finger of death", "stained",     P_ATTACK_SPELL,  5, 10, 7, 1, RAY,       HI_PAPER),
+SPELL("light",           "cloth",       P_DIVINATION_SPELL, 45,  1, 1, 1, NODIR,     HI_CLOTH),
+SPELL("detect monsters", "leather",     P_DIVINATION_SPELL, 43,  1, 1, 1, NODIR,     HI_LEATHER),
+SPELL("healing",         "white",       P_HEALING_SPELL, 40,  2, 1, 1, IMMEDIATE, CLR_WHITE),
+SPELL("knock",           "pink",        P_MATTER_SPELL, 35,  1, 1, 1, IMMEDIATE, CLR_BRIGHT_MAGENTA),
+SPELL("force bolt",      "red",         P_ATTACK_SPELL, 35,  2, 1, 1, IMMEDIATE, CLR_RED),
+SPELL("confuse monster", "orange",      P_ENCHANTMENT_SPELL, 30,  2, 2, 1, IMMEDIATE, CLR_ORANGE),
+SPELL("cure blindness",  "yellow",      P_HEALING_SPELL, 25,  2, 2, 1, IMMEDIATE, CLR_YELLOW),
+SPELL("drain life",      "velvet",      P_ATTACK_SPELL, 10,  2, 2, 1, IMMEDIATE, CLR_MAGENTA),
+SPELL("slow monster",    "light green", P_ENCHANTMENT_SPELL, 30,  2, 2, 1, IMMEDIATE, CLR_BRIGHT_GREEN),
+SPELL("wizard lock",     "dark green",  P_MATTER_SPELL, 30,  3, 2, 1, IMMEDIATE, CLR_GREEN),
+SPELL("create monster",  "turquoise",   P_CLERIC_SPELL, 35,  3, 2, 1, NODIR,     CLR_BRIGHT_CYAN),
+SPELL("detect food",     "cyan",        P_DIVINATION_SPELL, 30,  3, 2, 1, NODIR,     CLR_CYAN),
+SPELL("cause fear",      "light blue",  P_ENCHANTMENT_SPELL, 25,  3, 3, 1, NODIR,     CLR_BRIGHT_BLUE),
+SPELL("clairvoyance",    "dark blue",   P_DIVINATION_SPELL, 15,  3, 3, 1, NODIR,     CLR_BLUE),
+SPELL("cure sickness",   "indigo",      P_HEALING_SPELL, 32,  3, 3, 1, NODIR,     CLR_BLUE),
+SPELL("charm monster",   "magenta",     P_ENCHANTMENT_SPELL, 20,  3, 3, 1, IMMEDIATE, CLR_MAGENTA),
+SPELL("haste self",      "purple",      P_ESCAPE_SPELL, 33,  4, 3, 1, NODIR,     CLR_MAGENTA),
+SPELL("detect unseen",   "violet",      P_DIVINATION_SPELL, 20,  4, 3, 1, NODIR,     CLR_MAGENTA),
+SPELL("levitation",      "tan",         P_ESCAPE_SPELL, 20,  4, 4, 1, NODIR,     CLR_BROWN),
+SPELL("extra healing",   "plaid",       P_HEALING_SPELL, 27,  5, 3, 1, IMMEDIATE, CLR_GREEN),
+SPELL("restore ability", "light brown", P_HEALING_SPELL, 25,  5, 4, 1, NODIR,     CLR_BROWN),
+SPELL("invisibility",    "dark brown",  P_ESCAPE_SPELL, 25,  5, 4, 1, NODIR,     CLR_BROWN),
+SPELL("detect treasure", "gray",        P_DIVINATION_SPELL, 20,  5, 4, 1, NODIR,     CLR_GRAY),
+SPELL("remove curse",    "wrinkled",    P_CLERIC_SPELL, 25,  5, 3, 1, NODIR,     HI_PAPER),
+SPELL("magic mapping",   "dusty",       P_DIVINATION_SPELL, 18,  7, 5, 1, NODIR,     HI_PAPER),
+SPELL("identify",        "bronze",      P_DIVINATION_SPELL, 20,  6, 3, 1, NODIR,     HI_COPPER),
+SPELL("turn undead",     "copper",      P_CLERIC_SPELL, 16,  8, 6, 1, IMMEDIATE, HI_COPPER),
+SPELL("polymorph",       "silver",      P_MATTER_SPELL, 10,  8, 6, 1, IMMEDIATE, HI_SILVER),
+SPELL("teleport away",   "gold",        P_ESCAPE_SPELL, 15,  6, 6, 1, IMMEDIATE, HI_GOLD),
+SPELL("create familiar", "glittering",  P_CLERIC_SPELL, 10,  7, 6, 1, NODIR,     CLR_WHITE),
+SPELL("cancellation",    "shining",     P_MATTER_SPELL, 15,  8, 7, 1, IMMEDIATE, CLR_WHITE),
+SPELL("protection",         "dull",        P_CLERIC_SPELL, 18,  3, 1, 1, NODIR,     HI_PAPER),
+SPELL("jumping",            "thin",        P_ESCAPE_SPELL, 20,  3, 1, 1, IMMEDIATE, HI_PAPER),
+SPELL("stone to flesh",         "thick",       P_HEALING_SPELL, 15,  1, 3, 1, IMMEDIATE, HI_PAPER),
+#if 0  /* DEFERRED */
+SPELL("flame sphere",    "canvas",      P_MATTER_SPELL, 20,  2, 1, 1, NODIR, CLR_BROWN),
+SPELL("freeze sphere",   "hardcover",   P_MATTER_SPELL, 20,  2, 1, 1, NODIR, CLR_BROWN),
+#endif
+/* blank spellbook must come last because it retains its description */
+SPELL("blank paper",     "plain",       P_NONE, 18,  0, 0, 0, 0,         HI_PAPER),
+/* a special, one of a kind, spellbook */
+OBJECT(OBJ("Book of the Dead", "papyrus"), BITS(0,0,1,0,1,0,1,1,0,0,0,P_NONE,PAPER), 0,
+       SPBOOK_CLASS, 0, 0,20, 10000, 0, 0, 0, 7, 20, HI_PAPER),
+#undef SPELL
+
+/* wands ... */
+#define WAND(name,typ,prob,cost,mgc,dir,metal,color) OBJECT( \
+               OBJ(name,typ), BITS(0,0,1,0,mgc,1,0,0,0,0,dir,P_NONE,metal), 0, \
+               WAND_CLASS, prob, 0, 7, cost, 0, 0, 0, 0, 30, color )
+WAND("light",          "glass",    95, 100, 1, NODIR,     GLASS,    HI_GLASS),
+WAND("secret door detection", "balsa",
+                                  50, 150, 1, NODIR,     WOOD,     HI_WOOD),
+WAND("enlightenment",  "crystal",  15, 150, 1, NODIR,     GLASS,    HI_GLASS),
+WAND("create monster", "maple",    45, 200, 1, NODIR,     WOOD,     HI_WOOD),
+WAND("wishing",        "pine",      5, 500, 1, NODIR,     WOOD,     HI_WOOD),
+WAND("nothing",        "oak",      25, 100, 0, IMMEDIATE, WOOD,     HI_WOOD),
+WAND("striking",       "ebony",    75, 150, 1, IMMEDIATE, WOOD,     HI_WOOD),
+WAND("make invisible", "marble",   45, 150, 1, IMMEDIATE, MINERAL,  HI_MINERAL),
+WAND("slow monster",   "tin",      50, 150, 1, IMMEDIATE, METAL,    HI_METAL),
+WAND("speed monster",  "brass",    50, 150, 1, IMMEDIATE, COPPER,   HI_COPPER),
+WAND("undead turning", "copper",   50, 150, 1, IMMEDIATE, COPPER,   HI_COPPER),
+WAND("polymorph",      "silver",   45, 200, 1, IMMEDIATE, SILVER,   HI_SILVER),
+WAND("cancellation",   "platinum", 45, 200, 1, IMMEDIATE, PLATINUM, CLR_WHITE),
+WAND("teleportation",  "iridium",  45, 200, 1, IMMEDIATE, METAL,    CLR_BRIGHT_CYAN),
+WAND("opening",        "zinc",     25, 150, 1, IMMEDIATE, METAL,    HI_METAL),
+WAND("locking",        "aluminum", 25, 150, 1, IMMEDIATE, METAL,    HI_METAL),
+WAND("probing",        "uranium",  30, 150, 1, IMMEDIATE, METAL,    HI_METAL),
+WAND("digging",        "iron",     55, 150, 1, RAY,       IRON,     HI_METAL),
+WAND("magic missile",  "steel",    50, 150, 1, RAY,       IRON,     HI_METAL),
+WAND("fire",           "hexagonal",40, 175, 1, RAY,       IRON,     HI_METAL),
+WAND("cold",           "short",    40, 175, 1, RAY,       IRON,     HI_METAL),
+WAND("sleep",          "runed",    50, 175, 1, RAY,       IRON,     HI_METAL),
+WAND("death",          "long",      5, 500, 1, RAY,       IRON,     HI_METAL),
+WAND("lightning",      "curved",   40, 175, 1, RAY,       IRON,     HI_METAL),
+WAND((char *)0,        "forked",    0, 150, 1, 0,         WOOD,     HI_WOOD),
+WAND((char *)0,        "spiked",    0, 150, 1, 0,         IRON,     HI_METAL),
+WAND((char *)0,        "jeweled",   0, 150, 1, 0,         IRON,     HI_MINERAL),
+#undef WAND
+
+/* coins ... - so far, gold is all there is */
+#define COIN(name,prob,metal,worth) OBJECT( \
+               OBJ(name,(char *)0), BITS(0,1,0,0,0,0,0,0,0,0,0,P_NONE,metal), 0, \
+               COIN_CLASS, prob, 0, 1, worth, 0, 0, 0, 0, 0, HI_GOLD )
+       COIN("gold piece",      1000, GOLD,1),
+#undef COIN
+
+/* gems ... - includes stones and rocks but not boulders */
+#define GEM(name,desc,prob,wt,gval,nutr,mohs,glass,color) OBJECT( \
+           OBJ(name,desc), \
+           BITS(0,1,0,0,0,0,0,0,0,HARDGEM(mohs),0,-P_SLING,glass), 0, \
+           GEM_CLASS, prob, 0, 1, gval, 3, 3, 0, 0, nutr, color )
+#define ROCK(name,desc,kn,prob,wt,gval,sdam,ldam,mgc,nutr,mohs,glass,color) OBJECT( \
+           OBJ(name,desc), \
+           BITS(kn,1,0,0,mgc,0,0,0,0,HARDGEM(mohs),0,-P_SLING,glass), 0, \
+           GEM_CLASS, prob, 0, wt, gval, sdam, ldam, 0, 0, nutr, color )
+GEM("dilithium crystal", "white",      2,  1, 4500, 15,  5, GEMSTONE, CLR_WHITE),
+GEM("diamond", "white",                3,  1, 4000, 15, 10, GEMSTONE, CLR_WHITE),
+GEM("ruby", "red",                     4,  1, 3500, 15,  9, GEMSTONE, CLR_RED),
+GEM("jacinth", "orange",               3,  1, 3250, 15,  9, GEMSTONE, CLR_ORANGE),
+GEM("sapphire", "blue",                4,  1, 3000, 15,  9, GEMSTONE, CLR_BLUE),
+GEM("black opal", "black",             3,  1, 2500, 15,  8, GEMSTONE, CLR_BLACK),
+GEM("emerald", "green",                5,  1, 2500, 15,  8, GEMSTONE, CLR_GREEN),
+GEM("turquoise", "green",              6,  1, 2000, 15,  6, GEMSTONE, CLR_GREEN),
+GEM("citrine", "yellow",               4,  1, 1500, 15,  6, GEMSTONE, CLR_YELLOW),
+GEM("aquamarine", "green",             6,  1, 1500, 15,  8, GEMSTONE, CLR_GREEN),
+GEM("amber", "yellowish brown",        8,  1, 1000, 15,  2, GEMSTONE, CLR_BROWN),
+GEM("topaz", "yellowish brown",       10,  1,  900, 15,  8, GEMSTONE, CLR_BROWN),
+GEM("jet", "black",                    6,  1,  850, 15,  7, GEMSTONE, CLR_BLACK),
+GEM("opal", "white",                  12,  1,  800, 15,  6, GEMSTONE, CLR_WHITE),
+GEM("chrysoberyl", "yellow",           8,  1,  700, 15,  5, GEMSTONE, CLR_YELLOW),
+GEM("garnet", "red",                  12,  1,  700, 15,  7, GEMSTONE, CLR_RED),
+GEM("amethyst", "violet",             14,  1,  600, 15,  7, GEMSTONE, CLR_MAGENTA),
+GEM("jasper", "red",                  15,  1,  500, 15,  7, GEMSTONE, CLR_RED),
+GEM("fluorite", "violet",             15,  1,  400, 15,  4, GEMSTONE, CLR_MAGENTA),
+GEM("obsidian", "black",               9,  1,  200, 15,  6, GEMSTONE, CLR_BLACK),
+GEM("agate", "orange",                12,  1,  200, 15,  6, GEMSTONE, CLR_ORANGE),
+GEM("jade", "green",                  10,  1,  300, 15,  6, GEMSTONE, CLR_GREEN),
+GEM("worthless piece of white glass", "white",   77, 1, 0, 6, 5, GLASS, CLR_WHITE),
+GEM("worthless piece of blue glass", "blue",     77, 1, 0, 6, 5, GLASS, CLR_BLUE),
+GEM("worthless piece of red glass", "red",       77, 1, 0, 6, 5, GLASS, CLR_RED),
+GEM("worthless piece of yellowish brown glass", "yellowish brown",
+                                                77, 1, 0, 6, 5, GLASS, CLR_BROWN),
+GEM("worthless piece of orange glass", "orange", 76, 1, 0, 6, 5, GLASS, CLR_ORANGE),
+GEM("worthless piece of yellow glass", "yellow", 77, 1, 0, 6, 5, GLASS, CLR_YELLOW),
+GEM("worthless piece of black glass",  "black",  76, 1, 0, 6, 5, GLASS, CLR_BLACK),
+GEM("worthless piece of green glass", "green",   77, 1, 0, 6, 5, GLASS, CLR_GREEN),
+GEM("worthless piece of violet glass", "violet", 77, 1, 0, 6, 5, GLASS, CLR_MAGENTA),
+
+/* Placement note: there is a wishable subrange for
+ * "gray stones" in the o_ranges[] array in objnam.c
+ * that is currently everything between luckstones and flint (inclusive).
+ */
+ROCK("luckstone", "gray",      0, 10,  10, 60, 3, 3, 1, 10, 7, MINERAL, CLR_GRAY),
+ROCK("loadstone", "gray",      0, 10, 500,  1, 3, 3, 1, 10, 6, MINERAL, CLR_GRAY),
+ROCK("touchstone", "gray",     0,  8,  10, 45, 3, 3, 1, 10, 6, MINERAL, CLR_GRAY),
+ROCK("flint", "gray",          0, 10,  10,  1, 6, 6, 0, 10, 7, MINERAL, CLR_GRAY),
+ROCK("rock", (char *)0,                1,100,  10,  0, 3, 3, 0, 10, 7, MINERAL, CLR_GRAY),
+#undef GEM
+#undef ROCK
+
+/* miscellaneous ... */
+/* Note: boulders and rocks are not normally created at random; the
+ * probabilities only come into effect when you try to polymorph them.
+ * Boulders weigh more than MAX_CARR_CAP; statues use corpsenm to take
+ * on a specific type and may act as containers (both affect weight).
+ */
+OBJECT(OBJ("boulder",(char *)0), BITS(1,0,0,0,0,0,0,0,1,0,0,P_NONE,MINERAL), 0,
+               ROCK_CLASS,   100, 0, 6000,  0, 20, 20, 0, 0, 2000, HI_MINERAL),
+OBJECT(OBJ("statue", (char *)0), BITS(1,0,0,1,0,0,0,0,0,0,0,P_NONE,MINERAL), 0,
+               ROCK_CLASS,   900, 0, 2500,  0, 20, 20, 0, 0, 2500, CLR_WHITE),
+
+OBJECT(OBJ("heavy iron ball", (char *)0), BITS(1,0,0,0,0,0,0,0,0,0,WHACK,P_NONE,IRON), 0,
+               BALL_CLASS,  1000, 0,  480, 10, 25, 25, 0, 0,  200, HI_METAL),
+                                               /* +d4 when "very heavy" */
+OBJECT(OBJ("iron chain", (char *)0), BITS(1,0,0,0,0,0,0,0,0,0,WHACK,P_NONE,IRON), 0,
+               CHAIN_CLASS, 1000, 0,  120,  0,  4,  4, 0, 0,  200, HI_METAL),
+                                               /* +1 both l & s */
+
+OBJECT(OBJ("blinding venom", "splash of venom"),
+               BITS(0,1,0,0,0,0,0,1,0,0,0,P_NONE,LIQUID), 0,
+               VENOM_CLASS,  500, 0,    1,  0,  0,  0, 0, 0,    0, HI_ORGANIC),
+OBJECT(OBJ("acid venom", "splash of venom"),
+               BITS(0,1,0,0,0,0,0,1,0,0,0,P_NONE,LIQUID), 0,
+               VENOM_CLASS,  500, 0,    1,  0,  6,  6, 0, 0,    0, HI_ORGANIC),
+               /* +d6 small or large */
+
+/* fencepost, the deadly Array Terminator -- name [1st arg] *must* be NULL */
+       OBJECT(OBJ((char *)0,(char *)0), BITS(0,0,0,0,0,0,0,0,0,0,0,P_NONE,0), 0,
+               ILLOBJ_CLASS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+}; /* objects[] */
+
+#ifndef OBJECTS_PASS_2_
+
+/* perform recursive compilation for second structure */
+#  undef OBJ
+#  undef OBJECT
+#  define OBJECTS_PASS_2_
+#include "objects.c"
+
+void NDECL(objects_init);
+
+/* dummy routine used to force linkage */
+void
+objects_init()
+{
+    return;
+}
+
+#endif /* !OBJECTS_PASS_2_ */
+
+/*objects.c*/
diff --git a/src/objnam.c b/src/objnam.c
new file mode 100644 (file)
index 0000000..2130432
--- /dev/null
@@ -0,0 +1,2787 @@
+/*     SCCS Id: @(#)objnam.c   3.4     2003/12/04      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+/* "an uncursed greased partly eaten guardian naga hatchling [corpse]" */
+#define PREFIX 80      /* (56) */
+#define SCHAR_LIM 127
+#define NUMOBUF 12
+
+STATIC_DCL char *FDECL(strprepend,(char *,const char *));
+#ifdef OVLB
+static boolean FDECL(wishymatch, (const char *,const char *,BOOLEAN_P));
+#endif
+static char *NDECL(nextobuf);
+static void FDECL(add_erosion_words, (struct obj *, char *));
+
+struct Jitem {
+       int item;
+       const char *name;
+};
+
+/* true for gems/rocks that should have " stone" appended to their names */
+#define GemStone(typ)  (typ == FLINT ||                                \
+                        (objects[typ].oc_material == GEMSTONE &&       \
+                         (typ != DILITHIUM_CRYSTAL && typ != RUBY &&   \
+                          typ != DIAMOND && typ != SAPPHIRE &&         \
+                          typ != BLACK_OPAL &&         \
+                          typ != EMERALD && typ != OPAL)))
+
+#ifndef OVLB
+
+STATIC_DCL struct Jitem Japanese_items[];
+
+#else /* OVLB */
+
+STATIC_OVL struct Jitem Japanese_items[] = {
+       { SHORT_SWORD, "wakizashi" },
+       { BROADSWORD, "ninja-to" },
+       { FLAIL, "nunchaku" },
+       { GLAIVE, "naginata" },
+       { LOCK_PICK, "osaku" },
+       { WOODEN_HARP, "koto" },
+       { KNIFE, "shito" },
+       { PLATE_MAIL, "tanko" },
+       { HELMET, "kabuto" },
+       { LEATHER_GLOVES, "yugake" },
+       { FOOD_RATION, "gunyoki" },
+       { POT_BOOZE, "sake" },
+       {0, "" }
+};
+
+#endif /* OVLB */
+
+STATIC_DCL const char *FDECL(Japanese_item_name,(int i));
+
+#ifdef OVL1
+
+STATIC_OVL char *
+strprepend(s,pref)
+register char *s;
+register const char *pref;
+{
+       register int i = (int)strlen(pref);
+
+       if(i > PREFIX) {
+               impossible("PREFIX too short (for %d).", i);
+               return(s);
+       }
+       s -= i;
+       (void) strncpy(s, pref, i);     /* do not copy trailing 0 */
+       return(s);
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+/* manage a pool of BUFSZ buffers, so callers don't have to */
+static char *
+nextobuf()
+{
+       static char NEARDATA bufs[NUMOBUF][BUFSZ];
+       static int bufidx = 0;
+
+       bufidx = (bufidx + 1) % NUMOBUF;
+       return bufs[bufidx];
+}
+
+char *
+obj_typename(otyp)
+register int otyp;
+{
+       char *buf = nextobuf();
+       register struct objclass *ocl = &objects[otyp];
+       register const char *actualn = OBJ_NAME(*ocl);
+       register const char *dn = OBJ_DESCR(*ocl);
+       register const char *un = ocl->oc_uname;
+       register int nn = ocl->oc_name_known;
+
+       if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp))
+               actualn = Japanese_item_name(otyp);
+       switch(ocl->oc_class) {
+       case COIN_CLASS:
+               Strcpy(buf, "coin");
+               break;
+       case POTION_CLASS:
+               Strcpy(buf, "potion");
+               break;
+       case SCROLL_CLASS:
+               Strcpy(buf, "scroll");
+               break;
+       case WAND_CLASS:
+               Strcpy(buf, "wand");
+               break;
+       case SPBOOK_CLASS:
+               Strcpy(buf, "spellbook");
+               break;
+       case RING_CLASS:
+               Strcpy(buf, "ring");
+               break;
+       case AMULET_CLASS:
+               if(nn)
+                       Strcpy(buf,actualn);
+               else
+                       Strcpy(buf,"amulet");
+               if(un)
+                       Sprintf(eos(buf)," called %s",un);
+               if(dn)
+                       Sprintf(eos(buf)," (%s)",dn);
+               return(buf);
+       default:
+               if(nn) {
+                       Strcpy(buf, actualn);
+                       if (GemStone(otyp))
+                               Strcat(buf, " stone");
+                       if(un)
+                               Sprintf(eos(buf), " called %s", un);
+                       if(dn)
+                               Sprintf(eos(buf), " (%s)", dn);
+               } else {
+                       Strcpy(buf, dn ? dn : actualn);
+                       if(ocl->oc_class == GEM_CLASS)
+                               Strcat(buf, (ocl->oc_material == MINERAL) ?
+                                               " stone" : " gem");
+                       if(un)
+                               Sprintf(eos(buf), " called %s", un);
+               }
+               return(buf);
+       }
+       /* here for ring/scroll/potion/wand */
+       if(nn) {
+           if (ocl->oc_unique)
+               Strcpy(buf, actualn); /* avoid spellbook of Book of the Dead */
+           else
+               Sprintf(eos(buf), " of %s", actualn);
+       }
+       if(un)
+               Sprintf(eos(buf), " called %s", un);
+       if(dn)
+               Sprintf(eos(buf), " (%s)", dn);
+       return(buf);
+}
+
+/* less verbose result than obj_typename(); either the actual name
+   or the description (but not both); user-assigned name is ignored */
+char *
+simple_typename(otyp)
+int otyp;
+{
+    char *bufp, *pp, *save_uname = objects[otyp].oc_uname;
+
+    objects[otyp].oc_uname = 0;                /* suppress any name given by user */
+    bufp = obj_typename(otyp);
+    objects[otyp].oc_uname = save_uname;
+    if ((pp = strstri(bufp, " (")) != 0)
+       *pp = '\0';             /* strip the appended description */
+    return bufp;
+}
+
+boolean
+obj_is_pname(obj)
+register struct obj *obj;
+{
+    return((boolean)(obj->dknown && obj->known && obj->onamelth &&
+                    /* Since there aren't any objects which are both
+                       artifacts and unique, the last check is redundant. */
+                    obj->oartifact && !objects[obj->otyp].oc_unique));
+}
+
+/* Give the name of an object seen at a distance.  Unlike xname/doname,
+ * we don't want to set dknown if it's not set already.  The kludge used is
+ * to temporarily set Blind so that xname() skips the dknown setting.  This
+ * assumes that we don't want to do this too often; if this function becomes
+ * frequently used, it'd probably be better to pass a parameter to xname()
+ * or doname() instead.
+ */
+char *
+distant_name(obj, func)
+register struct obj *obj;
+char *FDECL((*func), (OBJ_P));
+{
+       char *str;
+
+       long save_Blinded = Blinded;
+       Blinded = 1;
+       str = (*func)(obj);
+       Blinded = save_Blinded;
+       return str;
+}
+
+/* convert player specified fruit name into corresponding fruit juice name
+   ("slice of pizza" -> "pizza juice" rather than "slice of pizza juice") */
+char *
+fruitname(juice)
+boolean juice; /* whether or not to append " juice" to the name */
+{
+    char *buf = nextobuf();
+    const char *fruit_nam = strstri(pl_fruit, " of ");
+
+    if (fruit_nam)
+       fruit_nam += 4;         /* skip past " of " */
+    else
+       fruit_nam = pl_fruit;   /* use it as is */
+
+    Sprintf(buf, "%s%s", makesingular(fruit_nam), juice ? " juice" : "");
+    return buf;
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+char *
+xname(obj)
+register struct obj *obj;
+{
+       register char *buf;
+       register int typ = obj->otyp;
+       register struct objclass *ocl = &objects[typ];
+       register int nn = ocl->oc_name_known;
+       register const char *actualn = OBJ_NAME(*ocl);
+       register const char *dn = OBJ_DESCR(*ocl);
+       register const char *un = ocl->oc_uname;
+
+       buf = nextobuf() + PREFIX;      /* leave room for "17 -3 " */
+       if (Role_if(PM_SAMURAI) && Japanese_item_name(typ))
+               actualn = Japanese_item_name(typ);
+
+       buf[0] = '\0';
+       /*
+        * clean up known when it's tied to oc_name_known, eg after AD_DRIN
+        * This is only required for unique objects since the article
+        * printed for the object is tied to the combination of the two
+        * and printing the wrong article gives away information.
+        */
+       if (!nn && ocl->oc_uses_known && ocl->oc_unique) obj->known = 0;
+       if (!Blind) obj->dknown = TRUE;
+       if (Role_if(PM_PRIEST)) obj->bknown = TRUE;
+       if (obj_is_pname(obj))
+           goto nameit;
+       switch (obj->oclass) {
+           case AMULET_CLASS:
+               if (!obj->dknown)
+                       Strcpy(buf, "amulet");
+               else if (typ == AMULET_OF_YENDOR ||
+                        typ == FAKE_AMULET_OF_YENDOR)
+                       /* each must be identified individually */
+                       Strcpy(buf, obj->known ? actualn : dn);
+               else if (nn)
+                       Strcpy(buf, actualn);
+               else if (un)
+                       Sprintf(buf,"amulet called %s", un);
+               else
+                       Sprintf(buf,"%s amulet", dn);
+               break;
+           case WEAPON_CLASS:
+               if (is_poisonable(obj) && obj->opoisoned)
+                       Strcpy(buf, "poisoned ");
+           case VENOM_CLASS:
+           case TOOL_CLASS:
+               if (typ == LENSES)
+                       Strcpy(buf, "pair of ");
+
+               if (!obj->dknown)
+                       Strcat(buf, dn ? dn : actualn);
+               else if (nn)
+                       Strcat(buf, actualn);
+               else if (un) {
+                       Strcat(buf, dn ? dn : actualn);
+                       Strcat(buf, " called ");
+                       Strcat(buf, un);
+               } else
+                       Strcat(buf, dn ? dn : actualn);
+               /* If we use an() here we'd have to remember never to use */
+               /* it whenever calling doname() or xname(). */
+               if (typ == FIGURINE)
+                   Sprintf(eos(buf), " of a%s %s",
+                       index(vowels,*(mons[obj->corpsenm].mname)) ? "n" : "",
+                       mons[obj->corpsenm].mname);
+               break;
+           case ARMOR_CLASS:
+               /* depends on order of the dragon scales objects */
+               if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) {
+                       Sprintf(buf, "set of %s", actualn);
+                       break;
+               }
+               if(is_boots(obj) || is_gloves(obj)) Strcpy(buf,"pair of ");
+
+               if(obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD
+                               && !obj->dknown) {
+                       Strcpy(buf, "shield");
+                       break;
+               }
+               if(obj->otyp == SHIELD_OF_REFLECTION && !obj->dknown) {
+                       Strcpy(buf, "smooth shield");
+                       break;
+               }
+
+               if(nn)  Strcat(buf, actualn);
+               else if(un) {
+                       if(is_boots(obj))
+                               Strcat(buf,"boots");
+                       else if(is_gloves(obj))
+                               Strcat(buf,"gloves");
+                       else if(is_cloak(obj))
+                               Strcpy(buf,"cloak");
+                       else if(is_helmet(obj))
+                               Strcpy(buf,"helmet");
+                       else if(is_shield(obj))
+                               Strcpy(buf,"shield");
+                       else
+                               Strcpy(buf,"armor");
+                       Strcat(buf, " called ");
+                       Strcat(buf, un);
+               } else  Strcat(buf, dn);
+               break;
+           case FOOD_CLASS:
+               if (typ == SLIME_MOLD) {
+                       register struct fruit *f;
+
+                       for(f=ffruit; f; f = f->nextf) {
+                               if(f->fid == obj->spe) {
+                                       Strcpy(buf, f->fname);
+                                       break;
+                               }
+                       }
+                       if (!f) impossible("Bad fruit #%d?", obj->spe);
+                       break;
+               }
+
+               Strcpy(buf, actualn);
+               if (typ == TIN && obj->known) {
+                   if(obj->spe > 0)
+                       Strcat(buf, " of spinach");
+                   else if (obj->corpsenm == NON_PM)
+                       Strcpy(buf, "empty tin");
+                   else if (vegetarian(&mons[obj->corpsenm]))
+                       Sprintf(eos(buf), " of %s", mons[obj->corpsenm].mname);
+                   else
+                       Sprintf(eos(buf), " of %s meat", mons[obj->corpsenm].mname);
+               }
+               break;
+           case COIN_CLASS:
+           case CHAIN_CLASS:
+               Strcpy(buf, actualn);
+               break;
+           case ROCK_CLASS:
+               if (typ == STATUE)
+                   Sprintf(buf, "%s%s of %s%s",
+                       (Role_if(PM_ARCHEOLOGIST) && (obj->spe & STATUE_HISTORIC)) ? "historic " : "" ,
+                       actualn,
+                       type_is_pname(&mons[obj->corpsenm]) ? "" :
+                         (mons[obj->corpsenm].geno & G_UNIQ) ? "the " :
+                           (index(vowels,*(mons[obj->corpsenm].mname)) ?
+                                                               "an " : "a "),
+                       mons[obj->corpsenm].mname);
+               else Strcpy(buf, actualn);
+               break;
+           case BALL_CLASS:
+               Sprintf(buf, "%sheavy iron ball",
+                       (obj->owt > ocl->oc_weight) ? "very " : "");
+               break;
+           case POTION_CLASS:
+               if (obj->dknown && obj->odiluted)
+                       Strcpy(buf, "diluted ");
+               if(nn || un || !obj->dknown) {
+                       Strcat(buf, "potion");
+                       if(!obj->dknown) break;
+                       if(nn) {
+                           Strcat(buf, " of ");
+                           if (typ == POT_WATER &&
+                               obj->bknown && (obj->blessed || obj->cursed)) {
+                               Strcat(buf, obj->blessed ? "holy " : "unholy ");
+                           }
+                           Strcat(buf, actualn);
+                       } else {
+                               Strcat(buf, " called ");
+                               Strcat(buf, un);
+                       }
+               } else {
+                       Strcat(buf, dn);
+                       Strcat(buf, " potion");
+               }
+               break;
+       case SCROLL_CLASS:
+               Strcpy(buf, "scroll");
+               if(!obj->dknown) break;
+               if(nn) {
+                       Strcat(buf, " of ");
+                       Strcat(buf, actualn);
+               } else if(un) {
+                       Strcat(buf, " called ");
+                       Strcat(buf, un);
+               } else if (ocl->oc_magic) {
+                       Strcat(buf, " labeled ");
+                       Strcat(buf, dn);
+               } else {
+                       Strcpy(buf, dn);
+                       Strcat(buf, " scroll");
+               }
+               break;
+       case WAND_CLASS:
+               if(!obj->dknown)
+                       Strcpy(buf, "wand");
+               else if(nn)
+                       Sprintf(buf, "wand of %s", actualn);
+               else if(un)
+                       Sprintf(buf, "wand called %s", un);
+               else
+                       Sprintf(buf, "%s wand", dn);
+               break;
+       case SPBOOK_CLASS:
+               if (!obj->dknown) {
+                       Strcpy(buf, "spellbook");
+               } else if (nn) {
+                       if (typ != SPE_BOOK_OF_THE_DEAD)
+                           Strcpy(buf, "spellbook of ");
+                       Strcat(buf, actualn);
+               } else if (un) {
+                       Sprintf(buf, "spellbook called %s", un);
+               } else
+                       Sprintf(buf, "%s spellbook", dn);
+               break;
+       case RING_CLASS:
+               if(!obj->dknown)
+                       Strcpy(buf, "ring");
+               else if(nn)
+                       Sprintf(buf, "ring of %s", actualn);
+               else if(un)
+                       Sprintf(buf, "ring called %s", un);
+               else
+                       Sprintf(buf, "%s ring", dn);
+               break;
+       case GEM_CLASS:
+           {
+               const char *rock =
+                           (ocl->oc_material == MINERAL) ? "stone" : "gem";
+               if (!obj->dknown) {
+                   Strcpy(buf, rock);
+               } else if (!nn) {
+                   if (un) Sprintf(buf,"%s called %s", rock, un);
+                   else Sprintf(buf, "%s %s", dn, rock);
+               } else {
+                   Strcpy(buf, actualn);
+                   if (GemStone(typ)) Strcat(buf, " stone");
+               }
+               break;
+           }
+       default:
+               Sprintf(buf,"glorkum %d %d %d", obj->oclass, typ, obj->spe);
+       }
+       if (obj->quan != 1L) Strcpy(buf, makeplural(buf));
+
+       if (obj->onamelth && obj->dknown) {
+               Strcat(buf, " named ");
+nameit:
+               Strcat(buf, ONAME(obj));
+       }
+
+       if (!strncmpi(buf, "the ", 4)) buf += 4;
+       return(buf);
+}
+
+/* xname() output augmented for multishot missile feedback */
+char *
+mshot_xname(obj)
+struct obj *obj;
+{
+    char tmpbuf[BUFSZ];
+    char *onm = xname(obj);
+
+    if (m_shot.n > 1 && m_shot.o == obj->otyp) {
+       /* copy xname's result so that we can reuse its return buffer */
+       Strcpy(tmpbuf, onm);
+       /* "the Nth arrow"; value will eventually be passed to an() or
+          The(), both of which correctly handle this "the " prefix */
+       Sprintf(onm, "the %d%s %s", m_shot.i, ordin(m_shot.i), tmpbuf);
+    }
+
+    return onm;
+}
+
+#endif /* OVL1 */
+#ifdef OVL0
+
+/* used for naming "the unique_item" instead of "a unique_item" */
+boolean
+the_unique_obj(obj)
+register struct obj *obj;
+{
+    if (!obj->dknown)
+       return FALSE;
+    else if (obj->otyp == FAKE_AMULET_OF_YENDOR && !obj->known)
+       return TRUE;            /* lie */
+    else
+       return (boolean)(objects[obj->otyp].oc_unique &&
+                        (obj->known || obj->otyp == AMULET_OF_YENDOR));
+}
+
+static void
+add_erosion_words(obj,prefix)
+struct obj *obj;
+char *prefix;
+{
+       boolean iscrys = (obj->otyp == CRYSKNIFE);
+
+
+       if (!is_damageable(obj) && !iscrys) return;
+
+       /* The only cases where any of these bits do double duty are for
+        * rotted food and diluted potions, which are all not is_damageable().
+        */
+       if (obj->oeroded && !iscrys) {
+               switch (obj->oeroded) {
+                       case 2: Strcat(prefix, "very "); break;
+                       case 3: Strcat(prefix, "thoroughly "); break;
+               }                       
+               Strcat(prefix, is_rustprone(obj) ? "rusty " : "burnt ");
+       }
+       if (obj->oeroded2 && !iscrys) {
+               switch (obj->oeroded2) {
+                       case 2: Strcat(prefix, "very "); break;
+                       case 3: Strcat(prefix, "thoroughly "); break;
+               }                       
+               Strcat(prefix, is_corrodeable(obj) ? "corroded " :
+                       "rotted ");
+       }
+       if (obj->rknown && obj->oerodeproof)
+               Strcat(prefix,
+                      iscrys ? "fixed " :
+                      is_rustprone(obj) ? "rustproof " :
+                      is_corrodeable(obj) ? "corrodeproof " :  /* "stainless"? */
+                      is_flammable(obj) ? "fireproof " : "");
+}
+
+char *
+doname(obj)
+register struct obj *obj;
+{
+       boolean ispoisoned = FALSE;
+       char prefix[PREFIX];
+       char tmpbuf[PREFIX+1];
+       /* when we have to add something at the start of prefix instead of the
+        * end (Strcat is used on the end)
+        */
+       register char *bp = xname(obj);
+
+       /* When using xname, we want "poisoned arrow", and when using
+        * doname, we want "poisoned +0 arrow".  This kludge is about the only
+        * way to do it, at least until someone overhauls xname() and doname(),
+        * combining both into one function taking a parameter.
+        */
+       /* must check opoisoned--someone can have a weirdly-named fruit */
+       if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) {
+               bp += 9;
+               ispoisoned = TRUE;
+       }
+
+       if(obj->quan != 1L)
+               Sprintf(prefix, "%ld ", obj->quan);
+       else if (obj_is_pname(obj) || the_unique_obj(obj)) {
+               if (!strncmpi(bp, "the ", 4))
+                   bp += 4;
+               Strcpy(prefix, "the ");
+       } else
+               Strcpy(prefix, "a ");
+
+#ifdef INVISIBLE_OBJECTS
+       if (obj->oinvis) Strcat(prefix,"invisible ");
+#endif
+
+       if (obj->bknown &&
+           obj->oclass != COIN_CLASS &&
+           (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known
+               || (!obj->cursed && !obj->blessed))) {
+           /* allow 'blessed clear potion' if we don't know it's holy water;
+            * always allow "uncursed potion of water"
+            */
+           if (obj->cursed)
+               Strcat(prefix, "cursed ");
+           else if (obj->blessed)
+               Strcat(prefix, "blessed ");
+           else if ((!obj->known || !objects[obj->otyp].oc_charged ||
+                     (obj->oclass == ARMOR_CLASS ||
+                      obj->oclass == RING_CLASS))
+               /* For most items with charges or +/-, if you know how many
+                * charges are left or what the +/- is, then you must have
+                * totally identified the item, so "uncursed" is unneccesary,
+                * because an identified object not described as "blessed" or
+                * "cursed" must be uncursed.
+                *
+                * If the charges or +/- is not known, "uncursed" must be
+                * printed to avoid ambiguity between an item whose curse
+                * status is unknown, and an item known to be uncursed.
+                */
+#ifdef MAIL
+                       && obj->otyp != SCR_MAIL
+#endif
+                       && obj->otyp != FAKE_AMULET_OF_YENDOR
+                       && obj->otyp != AMULET_OF_YENDOR
+                       && !Role_if(PM_PRIEST))
+               Strcat(prefix, "uncursed ");
+       }
+
+       if (obj->greased) Strcat(prefix, "greased ");
+
+       switch(obj->oclass) {
+       case AMULET_CLASS:
+               if(obj->owornmask & W_AMUL)
+                       Strcat(bp, " (being worn)");
+               break;
+       case WEAPON_CLASS:
+               if(ispoisoned)
+                       Strcat(prefix, "poisoned ");
+plus:
+               add_erosion_words(obj, prefix);
+               if(obj->known) {
+                       Strcat(prefix, sitoa(obj->spe));
+                       Strcat(prefix, " ");
+               }
+               break;
+       case ARMOR_CLASS:
+               if(obj->owornmask & W_ARMOR)
+                       Strcat(bp, (obj == uskin) ? " (embedded in your skin)" :
+                               " (being worn)");
+               goto plus;
+       case TOOL_CLASS:
+               /* weptools already get this done when we go to the +n code */
+               if (!is_weptool(obj))
+                   add_erosion_words(obj, prefix);
+               if(obj->owornmask & (W_TOOL /* blindfold */
+#ifdef STEED
+                               | W_SADDLE
+#endif
+                               )) {
+                       Strcat(bp, " (being worn)");
+                       break;
+               }
+               if (obj->otyp == LEASH && obj->leashmon != 0) {
+                       Strcat(bp, " (in use)");
+                       break;
+               }
+               if (is_weptool(obj))
+                       goto plus;
+               if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
+                       if (!obj->spe)
+                           Strcpy(tmpbuf, "no");
+                       else
+                           Sprintf(tmpbuf, "%d", obj->spe);
+                       Sprintf(eos(bp), " (%s candle%s%s)",
+                               tmpbuf, plur(obj->spe),
+                               !obj->lamplit ? " attached" : ", lit");
+                       break;
+               } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
+                       obj->otyp == BRASS_LANTERN || Is_candle(obj)) {
+                       if (Is_candle(obj) &&
+                           obj->age < 20L * (long)objects[obj->otyp].oc_cost)
+                               Strcat(prefix, "partly used ");
+                       if(obj->lamplit)
+                               Strcat(bp, " (lit)");
+                       break;
+               }
+               if(objects[obj->otyp].oc_charged)
+                   goto charges;
+               break;
+       case WAND_CLASS:
+               add_erosion_words(obj, prefix);
+charges:
+               if(obj->known)
+                   Sprintf(eos(bp), " (%d:%d)", (int)obj->recharged, obj->spe);
+               break;
+       case POTION_CLASS:
+               if (obj->otyp == POT_OIL && obj->lamplit)
+                   Strcat(bp, " (lit)");
+               break;
+       case RING_CLASS:
+               add_erosion_words(obj, prefix);
+ring:
+               if(obj->owornmask & W_RINGR) Strcat(bp, " (on right ");
+               if(obj->owornmask & W_RINGL) Strcat(bp, " (on left ");
+               if(obj->owornmask & W_RING) {
+                   Strcat(bp, body_part(HAND));
+                   Strcat(bp, ")");
+               }
+               if(obj->known && objects[obj->otyp].oc_charged) {
+                       Strcat(prefix, sitoa(obj->spe));
+                       Strcat(prefix, " ");
+               }
+               break;
+       case FOOD_CLASS:
+               if (obj->oeaten)
+                   Strcat(prefix, "partly eaten ");
+               if (obj->otyp == CORPSE) {
+                   if (mons[obj->corpsenm].geno & G_UNIQ) {
+                       Sprintf(prefix, "%s%s ",
+                               (type_is_pname(&mons[obj->corpsenm]) ?
+                                       "" : "the "),
+                               s_suffix(mons[obj->corpsenm].mname));
+                       if (obj->oeaten) Strcat(prefix, "partly eaten ");
+                   } else {
+                       Strcat(prefix, mons[obj->corpsenm].mname);
+                       Strcat(prefix, " ");
+                   }
+               } else if (obj->otyp == EGG) {
+#if 0  /* corpses don't tell if they're stale either */
+                   if (obj->known && stale_egg(obj))
+                       Strcat(prefix, "stale ");
+#endif
+                   if (obj->corpsenm >= LOW_PM &&
+                           (obj->known ||
+                           mvitals[obj->corpsenm].mvflags & MV_KNOWS_EGG)) {
+                       Strcat(prefix, mons[obj->corpsenm].mname);
+                       Strcat(prefix, " ");
+                       if (obj->spe)
+                           Strcat(bp, " (laid by you)");
+                   }
+               }
+               if (obj->otyp == MEAT_RING) goto ring;
+               break;
+       case BALL_CLASS:
+       case CHAIN_CLASS:
+               add_erosion_words(obj, prefix);
+               if(obj->owornmask & W_BALL)
+                       Strcat(bp, " (chained to you)");
+                       break;
+       }
+
+       if((obj->owornmask & W_WEP) && !mrg_to_wielded) {
+               if (obj->quan != 1L) {
+                       Strcat(bp, " (wielded)");
+               } else {
+                       const char *hand_s = body_part(HAND);
+
+                       if (bimanual(obj)) hand_s = makeplural(hand_s);
+                       Sprintf(eos(bp), " (weapon in %s)", hand_s);
+               }
+       }
+       if(obj->owornmask & W_SWAPWEP) {
+               if (u.twoweap)
+                       Sprintf(eos(bp), " (wielded in other %s)",
+                               body_part(HAND));
+               else
+                       Strcat(bp, " (alternate weapon; not wielded)");
+       }
+       if(obj->owornmask & W_QUIVER) Strcat(bp, " (in quiver)");
+       if(obj->unpaid) {
+               xchar ox, oy; 
+               long quotedprice = unpaid_cost(obj);
+               struct monst *shkp = (struct monst *)0;
+
+               if (Has_contents(obj) &&
+                   get_obj_location(obj, &ox, &oy, BURIED_TOO|CONTAINED_TOO) &&
+                   costly_spot(ox, oy) &&
+                   (shkp = shop_keeper(*in_rooms(ox, oy, SHOPBASE))))
+                       quotedprice += contained_cost(obj, shkp, 0L, FALSE, TRUE);
+               Sprintf(eos(bp), " (unpaid, %ld %s)",
+                       quotedprice, currency(quotedprice));
+       }
+       if (!strncmp(prefix, "a ", 2) &&
+                       index(vowels, *(prefix+2) ? *(prefix+2) : *bp)
+                       && (*(prefix+2) || (strncmp(bp, "uranium", 7)
+                               && strncmp(bp, "unicorn", 7)
+                               && strncmp(bp, "eucalyptus", 10)))) {
+               Strcpy(tmpbuf, prefix);
+               Strcpy(prefix, "an ");
+               Strcpy(prefix+3, tmpbuf+2);
+       }
+       bp = strprepend(bp, prefix);
+       return(bp);
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+/* used from invent.c */
+boolean
+not_fully_identified(otmp)
+register struct obj *otmp;
+{
+#ifdef GOLDOBJ
+    /* gold doesn't have any interesting attributes [yet?] */
+    if (otmp->oclass == COIN_CLASS) return FALSE;      /* always fully ID'd */
+#endif
+    /* check fundamental ID hallmarks first */
+    if (!otmp->known || !otmp->dknown ||
+#ifdef MAIL
+           (!otmp->bknown && otmp->otyp != SCR_MAIL) ||
+#else
+           !otmp->bknown ||
+#endif
+           !objects[otmp->otyp].oc_name_known) /* ?redundant? */
+       return TRUE;
+    if (otmp->oartifact && undiscovered_artifact(otmp->oartifact))
+       return TRUE;
+    /* otmp->rknown is the only item of interest if we reach here */
+       /*
+       *  Note:  if a revision ever allows scrolls to become fireproof or
+       *  rings to become shockproof, this checking will need to be revised.
+       *  `rknown' ID only matters if xname() will provide the info about it.
+       */
+    if (otmp->rknown || (otmp->oclass != ARMOR_CLASS &&
+                        otmp->oclass != WEAPON_CLASS &&
+                        !is_weptool(otmp) &&               /* (redunant) */
+                        otmp->oclass != BALL_CLASS))       /* (useless) */
+       return FALSE;
+    else       /* lack of `rknown' only matters for vulnerable objects */
+       return (boolean)(is_rustprone(otmp) ||
+                        is_corrodeable(otmp) ||
+                        is_flammable(otmp));
+}
+
+char *
+corpse_xname(otmp, ignore_oquan)
+struct obj *otmp;
+boolean ignore_oquan;  /* to force singular */
+{
+       char *nambuf = nextobuf();
+
+       Sprintf(nambuf, "%s corpse", mons[otmp->corpsenm].mname);
+
+       if (ignore_oquan || otmp->quan < 2)
+           return nambuf;
+       else
+           return makeplural(nambuf);
+}
+
+/* xname, unless it's a corpse, then corpse_xname(obj, FALSE) */
+char *
+cxname(obj)
+struct obj *obj;
+{
+       if (obj->otyp == CORPSE)
+           return corpse_xname(obj, FALSE);
+       return xname(obj);
+}
+
+/* treat an object as fully ID'd when it might be used as reason for death */
+char *
+killer_xname(obj)
+struct obj *obj;
+{
+    struct obj save_obj;
+    unsigned save_ocknown;
+    char *buf, *save_ocuname;
+
+    /* remember original settings for core of the object;
+       oname and oattached extensions don't matter here--since they
+       aren't modified they don't need to be saved and restored */
+    save_obj = *obj;
+    /* killer name should be more specific than general xname; however, exact
+       info like blessed/cursed and rustproof makes things be too verbose */
+    obj->known = obj->dknown = 1;
+    obj->bknown = obj->rknown = obj->greased = 0;
+    /* if character is a priest[ess], bknown will get toggled back on */
+    obj->blessed = obj->cursed = 0;
+    /* "killed by poisoned <obj>" would be misleading when poison is
+       not the cause of death and "poisoned by poisoned <obj>" would
+       be redundant when it is, so suppress "poisoned" prefix */
+    obj->opoisoned = 0;
+    /* strip user-supplied name; artifacts keep theirs */
+    if (!obj->oartifact) obj->onamelth = 0;
+    /* temporarily identify the type of object */
+    save_ocknown = objects[obj->otyp].oc_name_known;
+    objects[obj->otyp].oc_name_known = 1;
+    save_ocuname = objects[obj->otyp].oc_uname;
+    objects[obj->otyp].oc_uname = 0;   /* avoid "foo called bar" */
+
+    buf = xname(obj);
+    if (obj->quan == 1L) buf = obj_is_pname(obj) ? the(buf) : an(buf);
+
+    objects[obj->otyp].oc_name_known = save_ocknown;
+    objects[obj->otyp].oc_uname = save_ocuname;
+    *obj = save_obj;   /* restore object's core settings */
+
+    return buf;
+}
+
+/*
+ * Used if only one of a collection of objects is named (e.g. in eat.c).
+ */
+const char *
+singular(otmp, func)
+register struct obj *otmp;
+char *FDECL((*func), (OBJ_P));
+{
+       long savequan;
+       char *nam;
+
+       /* Note: using xname for corpses will not give the monster type */
+       if (otmp->otyp == CORPSE && func == xname)
+               return corpse_xname(otmp, TRUE);
+
+       savequan = otmp->quan;
+       otmp->quan = 1L;
+       nam = (*func)(otmp);
+       otmp->quan = savequan;
+       return nam;
+}
+
+char *
+an(str)
+register const char *str;
+{
+       char *buf = nextobuf();
+
+       buf[0] = '\0';
+
+       if (strncmpi(str, "the ", 4) &&
+           strcmp(str, "molten lava") &&
+           strcmp(str, "iron bars") &&
+           strcmp(str, "ice")) {
+               if (index(vowels, *str) &&
+                   strncmp(str, "one-", 4) &&
+                   strncmp(str, "useful", 6) &&
+                   strncmp(str, "unicorn", 7) &&
+                   strncmp(str, "uranium", 7) &&
+                   strncmp(str, "eucalyptus", 10))
+                       Strcpy(buf, "an ");
+               else
+                       Strcpy(buf, "a ");
+       }
+
+       Strcat(buf, str);
+       return buf;
+}
+
+char *
+An(str)
+const char *str;
+{
+       register char *tmp = an(str);
+       *tmp = highc(*tmp);
+       return tmp;
+}
+
+/*
+ * Prepend "the" if necessary; assumes str is a subject derived from xname.
+ * Use type_is_pname() for monster names, not the().  the() is idempotent.
+ */
+char *
+the(str)
+const char *str;
+{
+       char *buf = nextobuf();
+       boolean insert_the = FALSE;
+
+       if (!strncmpi(str, "the ", 4)) {
+           buf[0] = lowc(*str);
+           Strcpy(&buf[1], str+1);
+           return buf;
+       } else if (*str < 'A' || *str > 'Z') {
+           /* not a proper name, needs an article */
+           insert_the = TRUE;
+       } else {
+           /* Probably a proper name, might not need an article */
+           register char *tmp, *named, *called;
+           int l;
+
+           /* some objects have capitalized adjectives in their names */
+           if(((tmp = rindex(str, ' ')) || (tmp = rindex(str, '-'))) &&
+              (tmp[1] < 'A' || tmp[1] > 'Z'))
+               insert_the = TRUE;
+           else if (tmp && index(str, ' ') < tmp) {    /* has spaces */
+               /* it needs an article if the name contains "of" */
+               tmp = strstri(str, " of ");
+               named = strstri(str, " named ");
+               called = strstri(str, " called ");
+               if (called && (!named || called < named)) named = called;
+
+               if (tmp && (!named || tmp < named))     /* found an "of" */
+                   insert_the = TRUE;
+               /* stupid special case: lacks "of" but needs "the" */
+               else if (!named && (l = strlen(str)) >= 31 &&
+                     !strcmp(&str[l - 31], "Platinum Yendorian Express Card"))
+                   insert_the = TRUE;
+           }
+       }
+       if (insert_the)
+           Strcpy(buf, "the ");
+       else
+           buf[0] = '\0';
+       Strcat(buf, str);
+
+       return buf;
+}
+
+char *
+The(str)
+const char *str;
+{
+    register char *tmp = the(str);
+    *tmp = highc(*tmp);
+    return tmp;
+}
+
+/* returns "count cxname(otmp)" or just cxname(otmp) if count == 1 */
+char *
+aobjnam(otmp,verb)
+register struct obj *otmp;
+register const char *verb;
+{
+       register char *bp = cxname(otmp);
+       char prefix[PREFIX];
+
+       if(otmp->quan != 1L) {
+               Sprintf(prefix, "%ld ", otmp->quan);
+               bp = strprepend(bp, prefix);
+       }
+
+       if(verb) {
+           Strcat(bp, " ");
+           Strcat(bp, otense(otmp, verb));
+       }
+       return(bp);
+}
+
+/* like aobjnam, but prepend "The", not count, and use xname */
+char *
+Tobjnam(otmp, verb)
+register struct obj *otmp;
+register const char *verb;
+{
+       char *bp = The(xname(otmp));
+
+       if(verb) {
+           Strcat(bp, " ");
+           Strcat(bp, otense(otmp, verb));
+       }
+       return(bp);
+}
+
+/* return form of the verb (input plural) if xname(otmp) were the subject */
+char *
+otense(otmp, verb)
+register struct obj *otmp;
+register const char *verb;
+{
+       char *buf;
+
+       /*
+        * verb is given in plural (without trailing s).  Return as input
+        * if the result of xname(otmp) would be plural.  Don't bother
+        * recomputing xname(otmp) at this time.
+        */
+       if (!is_plural(otmp))
+           return vtense((char *)0, verb);
+
+       buf = nextobuf();
+       Strcpy(buf, verb);
+       return buf;
+}
+
+/* various singular words that vtense would otherwise categorize as plural */
+static const char * const special_subjs[] = {
+       "erinys",
+       "manes",                /* this one is ambiguous */
+       "Cyclops",
+       "Hippocrates",
+       "Pelias",
+       "aklys",
+       "amnesia",
+       "paralysis",
+       0
+};
+
+/* return form of the verb (input plural) for present tense 3rd person subj */
+char *
+vtense(subj, verb)
+register const char *subj;
+register const char *verb;
+{
+       char *buf = nextobuf();
+       int len, ltmp;
+       const char *sp, *spot;
+       const char * const *spec;
+
+       /*
+        * verb is given in plural (without trailing s).  Return as input
+        * if subj appears to be plural.  Add special cases as necessary.
+        * Many hard cases can already be handled by using otense() instead.
+        * If this gets much bigger, consider decomposing makeplural.
+        * Note: monster names are not expected here (except before corpse).
+        *
+        * special case: allow null sobj to get the singular 3rd person
+        * present tense form so we don't duplicate this code elsewhere.
+        */
+       if (subj) {
+           if (!strncmpi(subj, "a ", 2) || !strncmpi(subj, "an ", 3))
+               goto sing;
+           spot = (const char *)0;
+           for (sp = subj; (sp = index(sp, ' ')) != 0; ++sp) {
+               if (!strncmp(sp, " of ", 4) ||
+                   !strncmp(sp, " from ", 6) ||
+                   !strncmp(sp, " called ", 8) ||
+                   !strncmp(sp, " named ", 7) ||
+                   !strncmp(sp, " labeled ", 9)) {
+                   if (sp != subj) spot = sp - 1;
+                   break;
+               }
+           }
+           len = (int) strlen(subj);
+           if (!spot) spot = subj + len - 1;
+
+           /*
+            * plural: anything that ends in 's', but not '*us' or '*ss'.
+            * Guess at a few other special cases that makeplural creates.
+            */
+           if ((*spot == 's' && spot != subj &&
+                       (*(spot-1) != 'u' && *(spot-1) != 's')) ||
+               ((spot - subj) >= 4 && !strncmp(spot-3, "eeth", 4)) ||
+               ((spot - subj) >= 3 && !strncmp(spot-3, "feet", 4)) ||
+               ((spot - subj) >= 2 && !strncmp(spot-1, "ia", 2)) ||
+               ((spot - subj) >= 2 && !strncmp(spot-1, "ae", 2))) {
+               /* check for special cases to avoid false matches */
+               len = (int)(spot - subj) + 1;
+               for (spec = special_subjs; *spec; spec++) {
+                   ltmp = strlen(*spec);
+                   if (len == ltmp && !strncmpi(*spec, subj, len)) goto sing;
+                   /* also check for <prefix><space><special_subj>
+                      to catch things like "the invisible erinys" */
+                   if (len > ltmp && *(spot - ltmp) == ' ' &&
+                          !strncmpi(*spec, spot - ltmp + 1, ltmp)) goto sing;
+               }
+
+               return strcpy(buf, verb);
+           }
+           /*
+            * 3rd person plural doesn't end in telltale 's';
+            * 2nd person singular behaves as if plural.
+            */
+           if (!strcmpi(subj, "they") || !strcmpi(subj, "you"))
+               return strcpy(buf, verb);
+       }
+
+ sing:
+       len = strlen(verb);
+       spot = verb + len - 1;
+
+       if (!strcmp(verb, "are"))
+           Strcpy(buf, "is");
+       else if (!strcmp(verb, "have"))
+           Strcpy(buf, "has");
+       else if (index("zxs", *spot) ||
+                (len >= 2 && *spot=='h' && index("cs", *(spot-1))) ||
+                (len == 2 && *spot == 'o')) {
+           /* Ends in z, x, s, ch, sh; add an "es" */
+           Strcpy(buf, verb);
+           Strcat(buf, "es");
+       } else if (*spot == 'y' && (!index(vowels, *(spot-1)))) {
+           /* like "y" case in makeplural */
+           Strcpy(buf, verb);
+           Strcpy(buf + len - 1, "ies");
+       } else {
+           Strcpy(buf, verb);
+           Strcat(buf, "s");
+       }
+
+       return buf;
+}
+
+/* capitalized variant of doname() */
+char *
+Doname2(obj)
+register struct obj *obj;
+{
+       register char *s = doname(obj);
+
+       *s = highc(*s);
+       return(s);
+}
+
+/* returns "your xname(obj)" or "Foobar's xname(obj)" or "the xname(obj)" */
+char *
+yname(obj)
+struct obj *obj;
+{
+       char *outbuf = nextobuf();
+       char *s = shk_your(outbuf, obj);        /* assert( s == outbuf ); */
+       int space_left = BUFSZ - strlen(s) - sizeof " ";
+
+       return strncat(strcat(s, " "), cxname(obj), space_left);
+}
+
+/* capitalized variant of yname() */
+char *
+Yname2(obj)
+struct obj *obj;
+{
+       char *s = yname(obj);
+
+       *s = highc(*s);
+       return s;
+}
+
+/* returns "your simple_typename(obj->otyp)"
+ * or "Foobar's simple_typename(obj->otyp)"
+ * or "the simple_typename(obj-otyp)"
+ */
+char *
+ysimple_name(obj)
+struct obj *obj;
+{
+       char *outbuf = nextobuf();
+       char *s = shk_your(outbuf, obj);        /* assert( s == outbuf ); */
+       int space_left = BUFSZ - strlen(s) - sizeof " ";
+
+       return strncat(strcat(s, " "), simple_typename(obj->otyp), space_left);
+}
+
+/* capitalized variant of ysimple_name() */
+char *
+Ysimple_name2(obj)
+struct obj *obj;
+{
+       char *s = ysimple_name(obj);
+
+       *s = highc(*s);
+       return s;
+}
+
+static const char *wrp[] = {
+       "wand", "ring", "potion", "scroll", "gem", "amulet",
+       "spellbook", "spell book",
+       /* for non-specific wishes */
+       "weapon", "armor", "armour", "tool", "food", "comestible",
+};
+static const char wrpsym[] = {
+       WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, GEM_CLASS,
+       AMULET_CLASS, SPBOOK_CLASS, SPBOOK_CLASS,
+       WEAPON_CLASS, ARMOR_CLASS, ARMOR_CLASS, TOOL_CLASS, FOOD_CLASS,
+       FOOD_CLASS
+};
+
+#endif /* OVLB */
+#ifdef OVL0
+
+/* Plural routine; chiefly used for user-defined fruits.  We have to try to
+ * account for everything reasonable the player has; something unreasonable
+ * can still break the code.  However, it's still a lot more accurate than
+ * "just add an s at the end", which Rogue uses...
+ *
+ * Also used for plural monster names ("Wiped out all homunculi.")
+ * and body parts.
+ *
+ * Also misused by muse.c to convert 1st person present verbs to 2nd person.
+ */
+char *
+makeplural(oldstr)
+const char *oldstr;
+{
+       /* Note: cannot use strcmpi here -- it'd give MATZot, CAVEMeN,... */
+       register char *spot;
+       char *str = nextobuf();
+       const char *excess = (char *)0;
+       int len;
+
+       while (*oldstr==' ') oldstr++;
+       if (!oldstr || !*oldstr) {
+               impossible("plural of null?");
+               Strcpy(str, "s");
+               return str;
+       }
+       Strcpy(str, oldstr);
+
+       /*
+        * Skip changing "pair of" to "pairs of".  According to Webster, usual
+        * English usage is use pairs for humans, e.g. 3 pairs of dancers,
+        * and pair for objects and non-humans, e.g. 3 pair of boots.  We don't
+        * refer to pairs of humans in this game so just skip to the bottom.
+        */
+       if (!strncmp(str, "pair of ", 8))
+               goto bottom;
+
+       /* Search for common compounds, ex. lump of royal jelly */
+       for(spot=str; *spot; spot++) {
+               if (!strncmp(spot, " of ", 4)
+                               || !strncmp(spot, " labeled ", 9)
+                               || !strncmp(spot, " called ", 8)
+                               || !strncmp(spot, " named ", 7)
+                               || !strcmp(spot, " above") /* lurkers above */
+                               || !strncmp(spot, " versus ", 8)
+                               || !strncmp(spot, " from ", 6)
+                               || !strncmp(spot, " in ", 4)
+                               || !strncmp(spot, " on ", 4)
+                               || !strncmp(spot, " a la ", 6)
+                               || !strncmp(spot, " with", 5)   /* " with "? */
+                               || !strncmp(spot, " de ", 4)
+                               || !strncmp(spot, " d'", 3)
+                               || !strncmp(spot, " du ", 4)) {
+                       excess = oldstr + (int) (spot - str);
+                       *spot = 0;
+                       break;
+               }
+       }
+       spot--;
+       while (*spot==' ') spot--; /* Strip blanks from end */
+       *(spot+1) = 0;
+       /* Now spot is the last character of the string */
+
+       len = strlen(str);
+
+       /* Single letters */
+       if (len==1 || !letter(*spot)) {
+               Strcpy(spot+1, "'s");
+               goto bottom;
+       }
+
+       /* Same singular and plural; mostly Japanese words except for "manes" */
+       if ((len == 2 && !strcmp(str, "ya")) ||
+           (len >= 2 && !strcmp(spot-1, "ai")) || /* samurai, Uruk-hai */
+           (len >= 3 && !strcmp(spot-2, " ya")) ||
+           (len >= 4 &&
+            (!strcmp(spot-3, "fish") || !strcmp(spot-3, "tuna") ||
+             !strcmp(spot-3, "deer") || !strcmp(spot-3, "yaki"))) ||
+           (len >= 5 && (!strcmp(spot-4, "sheep") ||
+                       !strcmp(spot-4, "ninja") ||
+                       !strcmp(spot-4, "ronin") ||
+                       !strcmp(spot-4, "shito") ||
+                       !strcmp(spot-7, "shuriken") ||
+                       !strcmp(spot-4, "tengu") ||
+                       !strcmp(spot-4, "manes"))) ||
+           (len >= 6 && !strcmp(spot-5, "ki-rin")) ||
+           (len >= 7 && !strcmp(spot-6, "gunyoki")))
+               goto bottom;
+
+       /* man/men ("Wiped out all cavemen.") */
+       if (len >= 3 && !strcmp(spot-2, "man") &&
+                       (len<6 || strcmp(spot-5, "shaman")) &&
+                       (len<5 || strcmp(spot-4, "human"))) {
+               *(spot-1) = 'e';
+               goto bottom;
+       }
+
+       /* tooth/teeth */
+       if (len >= 5 && !strcmp(spot-4, "tooth")) {
+               Strcpy(spot-3, "eeth");
+               goto bottom;
+       }
+
+       /* knife/knives, etc... */
+       if (!strcmp(spot-1, "fe")) {
+               Strcpy(spot-1, "ves");
+               goto bottom;
+       } else if (*spot == 'f') {
+               if (index("lr", *(spot-1)) || index(vowels, *(spot-1))) {
+                       Strcpy(spot, "ves");
+                       goto bottom;
+               } else if (len >= 5 && !strncmp(spot-4, "staf", 4)) {
+                       Strcpy(spot-1, "ves");
+                       goto bottom;
+               }
+       }
+
+       /* foot/feet (body part) */
+       if (len >= 4 && !strcmp(spot-3, "foot")) {
+               Strcpy(spot-2, "eet");
+               goto bottom;
+       }
+
+       /* ium/ia (mycelia, baluchitheria) */
+       if (len >= 3 && !strcmp(spot-2, "ium")) {
+               *(spot--) = (char)0;
+               *spot = 'a';
+               goto bottom;
+       }
+
+       /* algae, larvae, hyphae (another fungus part) */
+       if ((len >= 4 && !strcmp(spot-3, "alga")) ||
+           (len >= 5 &&
+            (!strcmp(spot-4, "hypha") || !strcmp(spot-4, "larva")))) {
+               Strcpy(spot, "ae");
+               goto bottom;
+       }
+
+       /* fungus/fungi, homunculus/homunculi, but buses, lotuses, wumpuses */
+       if (len > 3 && !strcmp(spot-1, "us") &&
+           (len < 5 || (strcmp(spot-4, "lotus") &&
+                        (len < 6 || strcmp(spot-5, "wumpus"))))) {
+               *(spot--) = (char)0;
+               *spot = 'i';
+               goto bottom;
+       }
+
+       /* vortex/vortices */
+       if (len >= 6 && !strcmp(spot-3, "rtex")) {
+               Strcpy(spot-1, "ices");
+               goto bottom;
+       }
+
+       /* djinni/djinn (note: also efreeti/efreet) */
+       if (len >= 6 && !strcmp(spot-5, "djinni")) {
+               *spot = (char)0;
+               goto bottom;
+       }
+
+       /* mumak/mumakil */
+       if (len >= 5 && !strcmp(spot-4, "mumak")) {
+               Strcpy(spot+1, "il");
+               goto bottom;
+       }
+
+       /* sis/ses (nemesis) */
+       if (len >= 3 && !strcmp(spot-2, "sis")) {
+               *(spot-1) = 'e';
+               goto bottom;
+       }
+
+       /* erinys/erinyes */
+       if (len >= 6 && !strcmp(spot-5, "erinys")) {
+               Strcpy(spot, "es");
+               goto bottom;
+       }
+
+       /* mouse/mice,louse/lice (not a monster, but possible in food names) */
+       if (len >= 5 && !strcmp(spot-3, "ouse") && index("MmLl", *(spot-4))) {
+               Strcpy(spot-3, "ice");
+               goto bottom;
+       }
+
+       /* matzoh/matzot, possible food name */
+       if (len >= 6 && (!strcmp(spot-5, "matzoh")
+                                       || !strcmp(spot-5, "matzah"))) {
+               Strcpy(spot-1, "ot");
+               goto bottom;
+       }
+       if (len >= 5 && (!strcmp(spot-4, "matzo")
+                                       || !strcmp(spot-5, "matza"))) {
+               Strcpy(spot, "ot");
+               goto bottom;
+       }
+
+       /* child/children (for wise guys who give their food funny names) */
+       if (len >= 5 && !strcmp(spot-4, "child")) {
+               Strcpy(spot, "dren");
+               goto bottom;
+       }
+
+       /* note: -eau/-eaux (gateau, bordeau...) */
+       /* note: ox/oxen, VAX/VAXen, goose/geese */
+
+       /* Ends in z, x, s, ch, sh; add an "es" */
+       if (index("zxs", *spot)
+                       || (len >= 2 && *spot=='h' && index("cs", *(spot-1)))
+       /* Kludge to get "tomatoes" and "potatoes" right */
+                       || (len >= 4 && !strcmp(spot-2, "ato"))) {
+               Strcpy(spot+1, "es");
+               goto bottom;
+       }
+
+       /* Ends in y preceded by consonant (note: also "qu") change to "ies" */
+       if (*spot == 'y' &&
+           (!index(vowels, *(spot-1)))) {
+               Strcpy(spot, "ies");
+               goto bottom;
+       }
+
+       /* Default: append an 's' */
+       Strcpy(spot+1, "s");
+
+bottom:        if (excess) Strcpy(eos(str), excess);
+       return str;
+}
+
+#endif /* OVL0 */
+
+struct o_range {
+       const char *name, oclass;
+       int  f_o_range, l_o_range;
+};
+
+#ifndef OVLB
+
+STATIC_DCL const struct o_range o_ranges[];
+
+#else /* OVLB */
+
+/* wishable subranges of objects */
+STATIC_OVL NEARDATA const struct o_range o_ranges[] = {
+       { "bag",        TOOL_CLASS,   SACK,           BAG_OF_TRICKS },
+       { "lamp",       TOOL_CLASS,   OIL_LAMP,       MAGIC_LAMP },
+       { "candle",     TOOL_CLASS,   TALLOW_CANDLE,  WAX_CANDLE },
+       { "horn",       TOOL_CLASS,   TOOLED_HORN,    HORN_OF_PLENTY },
+       { "shield",     ARMOR_CLASS,  SMALL_SHIELD,   SHIELD_OF_REFLECTION },
+       { "helm",       ARMOR_CLASS,  ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY },
+       { "gloves",     ARMOR_CLASS,  LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
+       { "gauntlets",  ARMOR_CLASS,  LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
+       { "boots",      ARMOR_CLASS,  LOW_BOOTS,      LEVITATION_BOOTS },
+       { "shoes",      ARMOR_CLASS,  LOW_BOOTS,      IRON_SHOES },
+       { "cloak",      ARMOR_CLASS,  MUMMY_WRAPPING, CLOAK_OF_DISPLACEMENT },
+#ifdef TOURIST
+       { "shirt",      ARMOR_CLASS,  HAWAIIAN_SHIRT, T_SHIRT },
+#endif
+       { "dragon scales",
+                       ARMOR_CLASS,  GRAY_DRAGON_SCALES, YELLOW_DRAGON_SCALES },
+       { "dragon scale mail",
+                       ARMOR_CLASS,  GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL },
+       { "sword",      WEAPON_CLASS, SHORT_SWORD,    KATANA },
+#ifdef WIZARD
+       { "venom",      VENOM_CLASS,  BLINDING_VENOM, ACID_VENOM },
+#endif
+       { "gray stone", GEM_CLASS,    LUCKSTONE,      FLINT },
+       { "grey stone", GEM_CLASS,    LUCKSTONE,      FLINT },
+};
+
+#define BSTRCMP(base,ptr,string) ((ptr) < base || strcmp((ptr),string))
+#define BSTRCMPI(base,ptr,string) ((ptr) < base || strcmpi((ptr),string))
+#define BSTRNCMP(base,ptr,string,num) ((ptr)<base || strncmp((ptr),string,num))
+#define BSTRNCMPI(base,ptr,string,num) ((ptr)<base||strncmpi((ptr),string,num))
+
+/*
+ * Singularize a string the user typed in; this helps reduce the complexity
+ * of readobjnam, and is also used in pager.c to singularize the string
+ * for which help is sought.
+ */
+char *
+makesingular(oldstr)
+const char *oldstr;
+{
+       register char *p, *bp;
+       char *str = nextobuf();
+
+       if (!oldstr || !*oldstr) {
+               impossible("singular of null?");
+               str[0] = 0;
+               return str;
+       }
+       Strcpy(str, oldstr);
+       bp = str;
+
+       while (*bp == ' ') bp++;
+       /* find "cloves of garlic", "worthless pieces of blue glass" */
+       if ((p = strstri(bp, "s of ")) != 0) {
+           /* but don't singularize "gauntlets", "boots", "Eyes of the.." */
+           if (BSTRNCMPI(bp, p-3, "Eye", 3) &&
+               BSTRNCMP(bp, p-4, "boot", 4) &&
+               BSTRNCMP(bp, p-8, "gauntlet", 8))
+               while ((*p = *(p+1)) != 0) p++;
+           return bp;
+       }
+
+       /* remove -s or -es (boxes) or -ies (rubies) */
+       p = eos(bp);
+       if (p >= bp+1 && p[-1] == 's') {
+               if (p >= bp+2 && p[-2] == 'e') {
+                       if (p >= bp+3 && p[-3] == 'i') {
+                               if(!BSTRCMP(bp, p-7, "cookies") ||
+                                  !BSTRCMP(bp, p-4, "pies"))
+                                       goto mins;
+                               Strcpy(p-3, "y");
+                               return bp;
+                       }
+
+                       /* note: cloves / knives from clove / knife */
+                       if(!BSTRCMP(bp, p-6, "knives")) {
+                               Strcpy(p-3, "fe");
+                               return bp;
+                       }
+                       if(!BSTRCMP(bp, p-6, "staves")) {
+                               Strcpy(p-3, "ff");
+                               return bp;
+                       }
+                       if (!BSTRCMPI(bp, p-6, "leaves")) {
+                               Strcpy(p-3, "f");
+                               return bp;
+                       }
+                       if (!BSTRCMP(bp, p-8, "vortices")) {
+                               Strcpy(p-4, "ex");
+                               return bp;
+                       }
+
+                       /* note: nurses, axes but boxes */
+                       if (!BSTRCMP(bp, p-5, "boxes") ||
+                           !BSTRCMP(bp, p-4, "ches")) {
+                               p[-2] = '\0';
+                               return bp;
+                       }
+
+                       if (!BSTRCMP(bp, p-6, "gloves") ||
+                           !BSTRCMP(bp, p-6, "lenses") ||
+                           !BSTRCMP(bp, p-5, "shoes") ||
+                           !BSTRCMP(bp, p-6, "scales"))
+                               return bp;
+
+               } else if (!BSTRCMP(bp, p-5, "boots") ||
+                          !BSTRCMP(bp, p-9, "gauntlets") ||
+                          !BSTRCMP(bp, p-6, "tricks") ||
+                          !BSTRCMP(bp, p-9, "paralysis") ||
+                          !BSTRCMP(bp, p-5, "glass") ||
+                          !BSTRCMP(bp, p-4, "ness") ||
+                          !BSTRCMP(bp, p-14, "shape changers") ||
+                          !BSTRCMP(bp, p-15, "detect monsters") ||
+                          !BSTRCMPI(bp, p-11, "Aesculapius") || /* staff */
+                          !BSTRCMP(bp, p-10, "eucalyptus") ||
+#ifdef WIZARD
+                          !BSTRCMP(bp, p-9, "iron bars") ||
+#endif
+                          !BSTRCMP(bp, p-5, "aklys") ||
+                          !BSTRCMP(bp, p-6, "fungus"))
+                               return bp;
+       mins:
+               p[-1] = '\0';
+
+       } else {
+
+               if(!BSTRCMP(bp, p-5, "teeth")) {
+                       Strcpy(p-5, "tooth");
+                       return bp;
+               }
+
+               if (!BSTRCMP(bp, p-5, "fungi")) {
+                       Strcpy(p-5, "fungus");
+                       return bp;
+               }
+
+               /* here we cannot find the plural suffix */
+       }
+       return bp;
+}
+
+/* compare user string against object name string using fuzzy matching */
+static boolean
+wishymatch(u_str, o_str, retry_inverted)
+const char *u_str;     /* from user, so might be variant spelling */
+const char *o_str;     /* from objects[], so is in canonical form */
+boolean retry_inverted;        /* optional extra "of" handling */
+{
+       /* special case: wizards can wish for traps.  The object is "beartrap"
+        * and the trap is "bear trap", so to let wizards wish for both we
+        * must not fuzzymatch.
+        */
+#ifdef WIZARD
+       if (wizard && !strcmp(o_str, "beartrap"))
+           return !strncmpi(o_str, u_str, 8);
+#endif
+
+       /* ignore spaces & hyphens and upper/lower case when comparing */
+       if (fuzzymatch(u_str, o_str, " -", TRUE)) return TRUE;
+
+       if (retry_inverted) {
+           const char *u_of, *o_of;
+           char *p, buf[BUFSZ];
+
+           /* when just one of the strings is in the form "foo of bar",
+              convert it into "bar foo" and perform another comparison */
+           u_of = strstri(u_str, " of ");
+           o_of = strstri(o_str, " of ");
+           if (u_of && !o_of) {
+               Strcpy(buf, u_of + 4);
+               p = eos(strcat(buf, " "));
+               while (u_str < u_of) *p++ = *u_str++;
+               *p = '\0';
+               return fuzzymatch(buf, o_str, " -", TRUE);
+           } else if (o_of && !u_of) {
+               Strcpy(buf, o_of + 4);
+               p = eos(strcat(buf, " "));
+               while (o_str < o_of) *p++ = *o_str++;
+               *p = '\0';
+               return fuzzymatch(u_str, buf, " -", TRUE);
+           }
+       }
+
+       /* [note: if something like "elven speed boots" ever gets added, these
+          special cases should be changed to call wishymatch() recursively in
+          order to get the "of" inversion handling] */
+       if (!strncmp(o_str, "dwarvish ", 9)) {
+           if (!strncmpi(u_str, "dwarven ", 8))
+               return fuzzymatch(u_str + 8, o_str + 9, " -", TRUE);
+       } else if (!strncmp(o_str, "elven ", 6)) {
+           if (!strncmpi(u_str, "elvish ", 7))
+               return fuzzymatch(u_str + 7, o_str + 6, " -", TRUE);
+           else if (!strncmpi(u_str, "elfin ", 6))
+               return fuzzymatch(u_str + 6, o_str + 6, " -", TRUE);
+       } else if (!strcmp(o_str, "aluminum")) {
+               /* this special case doesn't really fit anywhere else... */
+               /* (note that " wand" will have been stripped off by now) */
+           if (!strcmpi(u_str, "aluminium"))
+               return fuzzymatch(u_str + 9, o_str + 8, " -", TRUE);
+       }
+
+       return FALSE;
+}
+
+/* alternate spellings; if the difference is only the presence or
+   absence of spaces and/or hyphens (such as "pickaxe" vs "pick axe"
+   vs "pick-axe") then there is no need for inclusion in this list;
+   likewise for ``"of" inversions'' ("boots of speed" vs "speed boots") */
+struct alt_spellings {
+       const char *sp;
+       int ob;
+} spellings[] = {
+       { "pickax", PICK_AXE },
+       { "whip", BULLWHIP },
+       { "saber", SILVER_SABER },
+       { "silver sabre", SILVER_SABER },
+       { "smooth shield", SHIELD_OF_REFLECTION },
+       { "grey dragon scale mail", GRAY_DRAGON_SCALE_MAIL },
+       { "grey dragon scales", GRAY_DRAGON_SCALES },
+       { "enchant armour", SCR_ENCHANT_ARMOR },
+       { "destroy armour", SCR_DESTROY_ARMOR },
+       { "scroll of enchant armour", SCR_ENCHANT_ARMOR },
+       { "scroll of destroy armour", SCR_DESTROY_ARMOR },
+       { "leather armour", LEATHER_ARMOR },
+       { "studded leather armour", STUDDED_LEATHER_ARMOR },
+       { "iron ball", HEAVY_IRON_BALL },
+       { "lantern", BRASS_LANTERN },
+       { "mattock", DWARVISH_MATTOCK },
+       { "amulet of poison resistance", AMULET_VERSUS_POISON },
+       { "stone", ROCK },
+#ifdef TOURIST
+       { "camera", EXPENSIVE_CAMERA },
+       { "tee shirt", T_SHIRT },
+#endif
+       { "can", TIN },
+       { "can opener", TIN_OPENER },
+       { "kelp", KELP_FROND },
+       { "eucalyptus", EUCALYPTUS_LEAF },
+       { "grapple", GRAPPLING_HOOK },
+       { (const char *)0, 0 },
+};
+
+/*
+ * Return something wished for.  Specifying a null pointer for
+ * the user request string results in a random object.  Otherwise,
+ * if asking explicitly for "nothing" (or "nil") return no_wish;
+ * if not an object return &zeroobj; if an error (no matching object),
+ * return null.
+ * If from_user is false, we're reading from the wizkit, nothing was typed in.
+ */
+struct obj *
+readobjnam(bp, no_wish, from_user)
+register char *bp;
+struct obj *no_wish;
+boolean from_user;
+{
+       register char *p;
+       register int i;
+       register struct obj *otmp;
+       int cnt, spe, spesgn, typ, very, rechrg;
+       int blessed, uncursed, iscursed, ispoisoned, isgreased;
+       int eroded, eroded2, erodeproof;
+#ifdef INVISIBLE_OBJECTS
+       int isinvisible;
+#endif
+       int halfeaten, mntmp, contents;
+       int islit, unlabeled, ishistoric, isdiluted;
+       struct fruit *f;
+       int ftype = current_fruit;
+       char fruitbuf[BUFSZ];
+       /* Fruits may not mess up the ability to wish for real objects (since
+        * you can leave a fruit in a bones file and it will be added to
+        * another person's game), so they must be checked for last, after
+        * stripping all the possible prefixes and seeing if there's a real
+        * name in there.  So we have to save the full original name.  However,
+        * it's still possible to do things like "uncursed burnt Alaska",
+        * or worse yet, "2 burned 5 course meals", so we need to loop to
+        * strip off the prefixes again, this time stripping only the ones
+        * possible on food.
+        * We could get even more detailed so as to allow food names with
+        * prefixes that _are_ possible on food, so you could wish for
+        * "2 3 alarm chilis".  Currently this isn't allowed; options.c
+        * automatically sticks 'candied' in front of such names.
+        */
+
+       char oclass;
+       char *un, *dn, *actualn;
+       const char *name=0;
+
+       cnt = spe = spesgn = typ = very = rechrg =
+               blessed = uncursed = iscursed =
+#ifdef INVISIBLE_OBJECTS
+               isinvisible =
+#endif
+               ispoisoned = isgreased = eroded = eroded2 = erodeproof =
+               halfeaten = islit = unlabeled = ishistoric = isdiluted = 0;
+       mntmp = NON_PM;
+#define UNDEFINED 0
+#define EMPTY 1
+#define SPINACH 2
+       contents = UNDEFINED;
+       oclass = 0;
+       actualn = dn = un = 0;
+
+       if (!bp) goto any;
+       /* first, remove extra whitespace they may have typed */
+       (void)mungspaces(bp);
+       /* allow wishing for "nothing" to preserve wishless conduct...
+          [now requires "wand of nothing" if that's what was really wanted] */
+       if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil") ||
+           !strcmpi(bp, "none")) return no_wish;
+       /* save the [nearly] unmodified choice string */
+       Strcpy(fruitbuf, bp);
+
+       for(;;) {
+               register int l;
+
+               if (!bp || !*bp) goto any;
+               if (!strncmpi(bp, "an ", l=3) ||
+                   !strncmpi(bp, "a ", l=2)) {
+                       cnt = 1;
+               } else if (!strncmpi(bp, "the ", l=4)) {
+                       ;       /* just increment `bp' by `l' below */
+               } else if (!cnt && digit(*bp) && strcmp(bp, "0")) {
+                       cnt = atoi(bp);
+                       while(digit(*bp)) bp++;
+                       while(*bp == ' ') bp++;
+                       l = 0;
+               } else if (*bp == '+' || *bp == '-') {
+                       spesgn = (*bp++ == '+') ? 1 : -1;
+                       spe = atoi(bp);
+                       while(digit(*bp)) bp++;
+                       while(*bp == ' ') bp++;
+                       l = 0;
+               } else if (!strncmpi(bp, "blessed ", l=8) ||
+                          !strncmpi(bp, "holy ", l=5)) {
+                       blessed = 1;
+               } else if (!strncmpi(bp, "cursed ", l=7) ||
+                          !strncmpi(bp, "unholy ", l=7)) {
+                       iscursed = 1;
+               } else if (!strncmpi(bp, "uncursed ", l=9)) {
+                       uncursed = 1;
+#ifdef INVISIBLE_OBJECTS
+               } else if (!strncmpi(bp, "invisible ", l=10)) {
+                       isinvisible = 1;
+#endif
+               } else if (!strncmpi(bp, "rustproof ", l=10) ||
+                          !strncmpi(bp, "erodeproof ", l=11) ||
+                          !strncmpi(bp, "corrodeproof ", l=13) ||
+                          !strncmpi(bp, "fixed ", l=6) ||
+                          !strncmpi(bp, "fireproof ", l=10) ||
+                          !strncmpi(bp, "rotproof ", l=9)) {
+                       erodeproof = 1;
+               } else if (!strncmpi(bp,"lit ", l=4) ||
+                          !strncmpi(bp,"burning ", l=8)) {
+                       islit = 1;
+               } else if (!strncmpi(bp,"unlit ", l=6) ||
+                          !strncmpi(bp,"extinguished ", l=13)) {
+                       islit = 0;
+               /* "unlabeled" and "blank" are synonymous */
+               } else if (!strncmpi(bp,"unlabeled ", l=10) ||
+                          !strncmpi(bp,"unlabelled ", l=11) ||
+                          !strncmpi(bp,"blank ", l=6)) {
+                       unlabeled = 1;
+               } else if(!strncmpi(bp, "poisoned ",l=9)
+#ifdef WIZARD
+                         || (wizard && !strncmpi(bp, "trapped ",l=8))
+#endif
+                         ) {
+                       ispoisoned=1;
+               } else if(!strncmpi(bp, "greased ",l=8)) {
+                       isgreased=1;
+               } else if (!strncmpi(bp, "very ", l=5)) {
+                       /* very rusted very heavy iron ball */
+                       very = 1;
+               } else if (!strncmpi(bp, "thoroughly ", l=11)) {
+                       very = 2;
+               } else if (!strncmpi(bp, "rusty ", l=6) ||
+                          !strncmpi(bp, "rusted ", l=7) ||
+                          !strncmpi(bp, "burnt ", l=6) ||
+                          !strncmpi(bp, "burned ", l=7)) {
+                       eroded = 1 + very;
+                       very = 0;
+               } else if (!strncmpi(bp, "corroded ", l=9) ||
+                          !strncmpi(bp, "rotted ", l=7)) {
+                       eroded2 = 1 + very;
+                       very = 0;
+               } else if (!strncmpi(bp, "partly eaten ", l=13)) {
+                       halfeaten = 1;
+               } else if (!strncmpi(bp, "historic ", l=9)) {
+                       ishistoric = 1;
+               } else if (!strncmpi(bp, "diluted ", l=8)) {
+                       isdiluted = 1;
+               } else if(!strncmpi(bp, "empty ", l=6)) {
+                       contents = EMPTY;
+               } else break;
+               bp += l;
+       }
+       if(!cnt) cnt = 1;               /* %% what with "gems" etc. ? */
+       if (strlen(bp) > 1) {
+           if ((p = rindex(bp, '(')) != 0) {
+               if (p > bp && p[-1] == ' ') p[-1] = 0;
+               else *p = 0;
+               p++;
+               if (!strcmpi(p, "lit)")) {
+                   islit = 1;
+               } else {
+                   spe = atoi(p);
+                   while (digit(*p)) p++;
+                   if (*p == ':') {
+                       p++;
+                       rechrg = spe;
+                       spe = atoi(p);
+                       while (digit(*p)) p++;
+                   }
+                   if (*p != ')') {
+                       spe = rechrg = 0;
+                   } else {
+                       spesgn = 1;
+                       p++;
+                       if (*p) Strcat(bp, p);
+                   }
+               }
+           }
+       }
+/*
+   otmp->spe is type schar; so we don't want spe to be any bigger or smaller.
+   also, spe should always be positive  -- some cheaters may try to confuse
+   atoi()
+*/
+       if (spe < 0) {
+               spesgn = -1;    /* cheaters get what they deserve */
+               spe = abs(spe);
+       }
+       if (spe > SCHAR_LIM)
+               spe = SCHAR_LIM;
+       if (rechrg < 0 || rechrg > 7) rechrg = 7;       /* recharge_limit */
+
+       /* now we have the actual name, as delivered by xname, say
+               green potions called whisky
+               scrolls labeled "QWERTY"
+               egg
+               fortune cookies
+               very heavy iron ball named hoei
+               wand of wishing
+               elven cloak
+       */
+       if ((p = strstri(bp, " named ")) != 0) {
+               *p = 0;
+               name = p+7;
+       }
+       if ((p = strstri(bp, " called ")) != 0) {
+               *p = 0;
+               un = p+8;
+               /* "helmet called telepathy" is not "helmet" (a specific type)
+                * "shield called reflection" is not "shield" (a general type)
+                */
+               for(i = 0; i < SIZE(o_ranges); i++)
+                   if(!strcmpi(bp, o_ranges[i].name)) {
+                       oclass = o_ranges[i].oclass;
+                       goto srch;
+                   }
+       }
+       if ((p = strstri(bp, " labeled ")) != 0) {
+               *p = 0;
+               dn = p+9;
+       } else if ((p = strstri(bp, " labelled ")) != 0) {
+               *p = 0;
+               dn = p+10;
+       }
+       if ((p = strstri(bp, " of spinach")) != 0) {
+               *p = 0;
+               contents = SPINACH;
+       }
+
+       /*
+       Skip over "pair of ", "pairs of", "set of" and "sets of".
+
+       Accept "3 pair of boots" as well as "3 pairs of boots". It is valid
+       English either way.  See makeplural() for more on pair/pairs.
+
+       We should only double count if the object in question is not
+       refered to as a "pair of".  E.g. We should double if the player
+       types "pair of spears", but not if the player types "pair of
+       lenses".  Luckily (?) all objects that are refered to as pairs
+       -- boots, gloves, and lenses -- are also not mergable, so cnt is
+       ignored anyway.
+       */
+       if(!strncmpi(bp, "pair of ",8)) {
+               bp += 8;
+               cnt *= 2;
+       } else if(cnt > 1 && !strncmpi(bp, "pairs of ",9)) {
+               bp += 9;
+               cnt *= 2;
+       } else if (!strncmpi(bp, "set of ",7)) {
+               bp += 7;
+       } else if (!strncmpi(bp, "sets of ",8)) {
+               bp += 8;
+       }
+
+       /*
+        * Find corpse type using "of" (figurine of an orc, tin of orc meat)
+        * Don't check if it's a wand or spellbook.
+        * (avoid "wand/finger of death" confusion).
+        */
+       if (!strstri(bp, "wand ")
+        && !strstri(bp, "spellbook ")
+        && !strstri(bp, "finger ")) {
+           if ((p = strstri(bp, " of ")) != 0
+               && (mntmp = name_to_mon(p+4)) >= LOW_PM)
+               *p = 0;
+       }
+       /* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */
+       if (strncmpi(bp, "samurai sword", 13)) /* not the "samurai" monster! */
+       if (strncmpi(bp, "wizard lock", 11)) /* not the "wizard" monster! */
+       if (strncmpi(bp, "ninja-to", 8)) /* not the "ninja" rank */
+       if (strncmpi(bp, "master key", 10)) /* not the "master" rank */
+       if (strncmpi(bp, "magenta", 7)) /* not the "mage" rank */
+       if (mntmp < LOW_PM && strlen(bp) > 2 &&
+           (mntmp = name_to_mon(bp)) >= LOW_PM) {
+               int mntmptoo, mntmplen; /* double check for rank title */
+               char *obp = bp;
+               mntmptoo = title_to_mon(bp, (int *)0, &mntmplen);
+               bp += mntmp != mntmptoo ? (int)strlen(mons[mntmp].mname) : mntmplen;
+               if (*bp == ' ') bp++;
+               else if (!strncmpi(bp, "s ", 2)) bp += 2;
+               else if (!strncmpi(bp, "es ", 3)) bp += 3;
+               else if (!*bp && !actualn && !dn && !un && !oclass) {
+                   /* no referent; they don't really mean a monster type */
+                   bp = obp;
+                   mntmp = NON_PM;
+               }
+       }
+
+       /* first change to singular if necessary */
+       if (*bp) {
+               char *sng = makesingular(bp);
+               if (strcmp(bp, sng)) {
+                       if (cnt == 1) cnt = 2;
+                       Strcpy(bp, sng);
+               }
+       }
+
+       /* Alternate spellings (pick-ax, silver sabre, &c) */
+    {
+       struct alt_spellings *as = spellings;
+
+       while (as->sp) {
+               if (fuzzymatch(bp, as->sp, " -", TRUE)) {
+                       typ = as->ob;
+                       goto typfnd;
+               }
+               as++;
+       }
+       /* can't use spellings list for this one due to shuffling */
+       if (!strncmpi(bp, "grey spell", 10))
+               *(bp + 2) = 'a';
+    }
+
+       /* dragon scales - assumes order of dragons */
+       if(!strcmpi(bp, "scales") &&
+                       mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON) {
+               typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON;
+               mntmp = NON_PM; /* no monster */
+               goto typfnd;
+       }
+
+       p = eos(bp);
+       if(!BSTRCMPI(bp, p-10, "holy water")) {
+               typ = POT_WATER;
+               if ((p-bp) >= 12 && *(p-12) == 'u')
+                       iscursed = 1; /* unholy water */
+               else blessed = 1;
+               goto typfnd;
+       }
+       if(unlabeled && !BSTRCMPI(bp, p-6, "scroll")) {
+               typ = SCR_BLANK_PAPER;
+               goto typfnd;
+       }
+       if(unlabeled && !BSTRCMPI(bp, p-9, "spellbook")) {
+               typ = SPE_BLANK_PAPER;
+               goto typfnd;
+       }
+       /*
+        * NOTE: Gold pieces are handled as objects nowadays, and therefore
+        * this section should probably be reconsidered as well as the entire
+        * gold/money concept.  Maybe we want to add other monetary units as
+        * well in the future. (TH)
+        */
+       if(!BSTRCMPI(bp, p-10, "gold piece") || !BSTRCMPI(bp, p-7, "zorkmid") ||
+          !strcmpi(bp, "gold") || !strcmpi(bp, "money") ||
+          !strcmpi(bp, "coin") || *bp == GOLD_SYM) {
+                       if (cnt > 5000
+#ifdef WIZARD
+                                       && !wizard
+#endif
+                                               ) cnt=5000;
+               if (cnt < 1) cnt=1;
+#ifndef GOLDOBJ
+               if (from_user)
+                   pline("%d gold piece%s.", cnt, plur(cnt));
+               u.ugold += cnt;
+               flags.botl=1;
+               return (&zeroobj);
+#else
+                otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
+               otmp->quan = cnt;
+                otmp->owt = weight(otmp);
+               flags.botl=1;
+               return (otmp);
+#endif
+       }
+       if (strlen(bp) == 1 &&
+          (i = def_char_to_objclass(*bp)) < MAXOCLASSES && i > ILLOBJ_CLASS
+#ifdef WIZARD
+           && (wizard || i != VENOM_CLASS)
+#else
+           && i != VENOM_CLASS
+#endif
+           ) {
+               oclass = i;
+               goto any;
+       }
+
+       /* Search for class names: XXXXX potion, scroll of XXXXX.  Avoid */
+       /* false hits on, e.g., rings for "ring mail". */
+       if(strncmpi(bp, "enchant ", 8) &&
+          strncmpi(bp, "destroy ", 8) &&
+          strncmpi(bp, "food detection", 14) &&
+          strncmpi(bp, "ring mail", 9) &&
+          strncmpi(bp, "studded leather arm", 19) &&
+          strncmpi(bp, "leather arm", 11) &&
+          strncmpi(bp, "tooled horn", 11) &&
+          strncmpi(bp, "food ration", 11) &&
+          strncmpi(bp, "meat ring", 9)
+       )
+       for (i = 0; i < (int)(sizeof wrpsym); i++) {
+               register int j = strlen(wrp[i]);
+               if(!strncmpi(bp, wrp[i], j)){
+                       oclass = wrpsym[i];
+                       if(oclass != AMULET_CLASS) {
+                           bp += j;
+                           if(!strncmpi(bp, " of ", 4)) actualn = bp+4;
+                           /* else if(*bp) ?? */
+                       } else
+                           actualn = bp;
+                       goto srch;
+               }
+               if(!BSTRCMPI(bp, p-j, wrp[i])){
+                       oclass = wrpsym[i];
+                       p -= j;
+                       *p = 0;
+                       if(p > bp && p[-1] == ' ') p[-1] = 0;
+                       actualn = dn = bp;
+                       goto srch;
+               }
+       }
+
+       /* "grey stone" check must be before general "stone" */
+       for (i = 0; i < SIZE(o_ranges); i++)
+           if(!strcmpi(bp, o_ranges[i].name)) {
+               typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range);
+               goto typfnd;
+           }
+
+       if (!BSTRCMPI(bp, p-6, " stone")) {
+               p[-6] = 0;
+               oclass = GEM_CLASS;
+               dn = actualn = bp;
+               goto srch;
+       } else if (!strcmpi(bp, "looking glass")) {
+               ;       /* avoid false hit on "* glass" */
+       } else if (!BSTRCMPI(bp, p-6, " glass") || !strcmpi(bp, "glass")) {
+               register char *g = bp;
+               if (strstri(g, "broken")) return (struct obj *)0;
+               if (!strncmpi(g, "worthless ", 10)) g += 10;
+               if (!strncmpi(g, "piece of ", 9)) g += 9;
+               if (!strncmpi(g, "colored ", 8)) g += 8;
+               else if (!strncmpi(g, "coloured ", 9)) g += 9;
+               if (!strcmpi(g, "glass")) {     /* choose random color */
+                       /* 9 different kinds */
+                       typ = LAST_GEM + rnd(9);
+                       if (objects[typ].oc_class == GEM_CLASS) goto typfnd;
+                       else typ = 0;   /* somebody changed objects[]? punt */
+               } else {                /* try to construct canonical form */
+                       char tbuf[BUFSZ];
+                       Strcpy(tbuf, "worthless piece of ");
+                       Strcat(tbuf, g);  /* assume it starts with the color */
+                       Strcpy(bp, tbuf);
+               }
+       }
+
+       actualn = bp;
+       if (!dn) dn = actualn; /* ex. "skull cap" */
+srch:
+       /* check real names of gems first */
+       if(!oclass && actualn) {
+           for(i = bases[GEM_CLASS]; i <= LAST_GEM; i++) {
+               register const char *zn;
+
+               if((zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) {
+                   typ = i;
+                   goto typfnd;
+               }
+           }
+       }
+       i = oclass ? bases[(int)oclass] : 1;
+       while(i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass)){
+               register const char *zn;
+
+               if (actualn && (zn = OBJ_NAME(objects[i])) != 0 &&
+                           wishymatch(actualn, zn, TRUE)) {
+                       typ = i;
+                       goto typfnd;
+               }
+               if (dn && (zn = OBJ_DESCR(objects[i])) != 0 &&
+                           wishymatch(dn, zn, FALSE)) {
+                       /* don't match extra descriptions (w/o real name) */
+                       if (!OBJ_NAME(objects[i])) return (struct obj *)0;
+                       typ = i;
+                       goto typfnd;
+               }
+               if (un && (zn = objects[i].oc_uname) != 0 &&
+                           wishymatch(un, zn, FALSE)) {
+                       typ = i;
+                       goto typfnd;
+               }
+               i++;
+       }
+       if (actualn) {
+               struct Jitem *j = Japanese_items;
+               while(j->item) {
+                       if (actualn && !strcmpi(actualn, j->name)) {
+                               typ = j->item;
+                               goto typfnd;
+                       }
+                       j++;
+               }
+       }
+       if (!strcmpi(bp, "spinach")) {
+               contents = SPINACH;
+               typ = TIN;
+               goto typfnd;
+       }
+       /* Note: not strncmpi.  2 fruits, one capital, one not, are possible. */
+       {
+           char *fp;
+           int l, cntf;
+           int blessedf, iscursedf, uncursedf, halfeatenf;
+
+           blessedf = iscursedf = uncursedf = halfeatenf = 0;
+           cntf = 0;
+
+           fp = fruitbuf;
+           for(;;) {
+               if (!fp || !*fp) break;
+               if (!strncmpi(fp, "an ", l=3) ||
+                   !strncmpi(fp, "a ", l=2)) {
+                       cntf = 1;
+               } else if (!cntf && digit(*fp)) {
+                       cntf = atoi(fp);
+                       while(digit(*fp)) fp++;
+                       while(*fp == ' ') fp++;
+                       l = 0;
+               } else if (!strncmpi(fp, "blessed ", l=8)) {
+                       blessedf = 1;
+               } else if (!strncmpi(fp, "cursed ", l=7)) {
+                       iscursedf = 1;
+               } else if (!strncmpi(fp, "uncursed ", l=9)) {
+                       uncursedf = 1;
+               } else if (!strncmpi(fp, "partly eaten ", l=13)) {
+                       halfeatenf = 1;
+               } else break;
+               fp += l;
+           }
+
+           for(f=ffruit; f; f = f->nextf) {
+               char *f1 = f->fname, *f2 = makeplural(f->fname);
+
+               if(!strncmp(fp, f1, strlen(f1)) ||
+                                       !strncmp(fp, f2, strlen(f2))) {
+                       typ = SLIME_MOLD;
+                       blessed = blessedf;
+                       iscursed = iscursedf;
+                       uncursed = uncursedf;
+                       halfeaten = halfeatenf;
+                       cnt = cntf;
+                       ftype = f->fid;
+                       goto typfnd;
+               }
+           }
+       }
+
+       if(!oclass && actualn) {
+           short objtyp;
+
+           /* Perhaps it's an artifact specified by name, not type */
+           name = artifact_name(actualn, &objtyp);
+           if(name) {
+               typ = objtyp;
+               goto typfnd;
+           }
+       }
+#ifdef WIZARD
+       /* Let wizards wish for traps --KAA */
+       /* must come after objects check so wizards can still wish for
+        * trap objects like beartraps
+        */
+       if (wizard && from_user) {
+               int trap;
+
+               for (trap = NO_TRAP+1; trap < TRAPNUM; trap++) {
+                       const char *tname;
+
+                       tname = defsyms[trap_to_defsym(trap)].explanation;
+                       if (!strncmpi(tname, bp, strlen(tname))) {
+                               /* avoid stupid mistakes */
+                               if((trap == TRAPDOOR || trap == HOLE)
+                                     && !Can_fall_thru(&u.uz)) trap = ROCKTRAP;
+                               (void) maketrap(u.ux, u.uy, trap);
+                               pline("%s.", An(tname));
+                               return(&zeroobj);
+                       }
+               }
+               /* or some other dungeon features -dlc */
+               p = eos(bp);
+               if(!BSTRCMP(bp, p-8, "fountain")) {
+                       levl[u.ux][u.uy].typ = FOUNTAIN;
+                       level.flags.nfountains++;
+                       if(!strncmpi(bp, "magic ", 6))
+                               levl[u.ux][u.uy].blessedftn = 1;
+                       pline("A %sfountain.",
+                             levl[u.ux][u.uy].blessedftn ? "magic " : "");
+                       newsym(u.ux, u.uy);
+                       return(&zeroobj);
+               }
+               if(!BSTRCMP(bp, p-6, "throne")) {
+                       levl[u.ux][u.uy].typ = THRONE;
+                       pline("A throne.");
+                       newsym(u.ux, u.uy);
+                       return(&zeroobj);
+               }
+# ifdef SINKS
+               if(!BSTRCMP(bp, p-4, "sink")) {
+                       levl[u.ux][u.uy].typ = SINK;
+                       level.flags.nsinks++;
+                       pline("A sink.");
+                       newsym(u.ux, u.uy);
+                       return &zeroobj;
+               }
+# endif
+               if(!BSTRCMP(bp, p-4, "pool")) {
+                       levl[u.ux][u.uy].typ = POOL;
+                       del_engr_at(u.ux, u.uy);
+                       pline("A pool.");
+                       /* Must manually make kelp! */
+                       water_damage(level.objects[u.ux][u.uy], FALSE, TRUE);
+                       newsym(u.ux, u.uy);
+                       return &zeroobj;
+               }
+               if (!BSTRCMP(bp, p-4, "lava")) {  /* also matches "molten lava" */
+                       levl[u.ux][u.uy].typ = LAVAPOOL;
+                       del_engr_at(u.ux, u.uy);
+                       pline("A pool of molten lava.");
+                       if (!(Levitation || Flying)) (void) lava_effects();
+                       newsym(u.ux, u.uy);
+                       return &zeroobj;
+               }
+
+               if(!BSTRCMP(bp, p-5, "altar")) {
+                   aligntyp al;
+
+                   levl[u.ux][u.uy].typ = ALTAR;
+                   if(!strncmpi(bp, "chaotic ", 8))
+                       al = A_CHAOTIC;
+                   else if(!strncmpi(bp, "neutral ", 8))
+                       al = A_NEUTRAL;
+                   else if(!strncmpi(bp, "lawful ", 7))
+                       al = A_LAWFUL;
+                   else if(!strncmpi(bp, "unaligned ", 10))
+                       al = A_NONE;
+                   else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
+                       al = (!rn2(6)) ? A_NONE : rn2((int)A_LAWFUL+2) - 1;
+                   levl[u.ux][u.uy].altarmask = Align2amask( al );
+                   pline("%s altar.", An(align_str(al)));
+                   newsym(u.ux, u.uy);
+                   return(&zeroobj);
+               }
+
+               if(!BSTRCMP(bp, p-5, "grave") || !BSTRCMP(bp, p-9, "headstone")) {
+                   make_grave(u.ux, u.uy, (char *) 0);
+                   pline("A grave.");
+                   newsym(u.ux, u.uy);
+                   return(&zeroobj);
+               }
+
+               if(!BSTRCMP(bp, p-4, "tree")) {
+                   levl[u.ux][u.uy].typ = TREE;
+                   pline("A tree.");
+                   newsym(u.ux, u.uy);
+                   block_point(u.ux, u.uy);
+                   return &zeroobj;
+               }
+
+               if(!BSTRCMP(bp, p-4, "bars")) {
+                   levl[u.ux][u.uy].typ = IRONBARS;
+                   pline("Iron bars.");
+                   newsym(u.ux, u.uy);
+                   return &zeroobj;
+               }
+       }
+#endif
+       if(!oclass) return((struct obj *)0);
+any:
+       if(!oclass) oclass = wrpsym[rn2((int)sizeof(wrpsym))];
+typfnd:
+       if (typ) oclass = objects[typ].oc_class;
+
+       /* check for some objects that are not allowed */
+       if (typ && objects[typ].oc_unique) {
+#ifdef WIZARD
+           if (wizard)
+               ;       /* allow unique objects */
+           else
+#endif
+           switch (typ) {
+               case AMULET_OF_YENDOR:
+                   typ = FAKE_AMULET_OF_YENDOR;
+                   break;
+               case CANDELABRUM_OF_INVOCATION:
+                   typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE);
+                   break;
+               case BELL_OF_OPENING:
+                   typ = BELL;
+                   break;
+               case SPE_BOOK_OF_THE_DEAD:
+                   typ = SPE_BLANK_PAPER;
+                   break;
+           }
+       }
+
+       /* catch any other non-wishable objects */
+       if (objects[typ].oc_nowish
+#ifdef WIZARD
+           && !wizard
+#endif
+           )
+           return((struct obj *)0);
+
+       /* convert magic lamps to regular lamps before lighting them or setting
+          the charges */
+       if (typ == MAGIC_LAMP
+#ifdef WIZARD
+                               && !wizard
+#endif
+                                               )
+           typ = OIL_LAMP;
+
+       if(typ) {
+               otmp = mksobj(typ, TRUE, FALSE);
+       } else {
+               otmp = mkobj(oclass, FALSE);
+               if (otmp) typ = otmp->otyp;
+       }
+
+       if (islit &&
+               (typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN ||
+                Is_candle(otmp) || typ == POT_OIL)) {
+           place_object(otmp, u.ux, u.uy);  /* make it viable light source */
+           begin_burn(otmp, FALSE);
+           obj_extract_self(otmp);      /* now release it for caller's use */
+       }
+
+       if(cnt > 0 && objects[typ].oc_merge && oclass != SPBOOK_CLASS &&
+               (cnt < rnd(6) ||
+#ifdef WIZARD
+               wizard ||
+#endif
+                (cnt <= 7 && Is_candle(otmp)) ||
+                (cnt <= 20 &&
+                 ((oclass == WEAPON_CLASS && is_ammo(otmp))
+                               || typ == ROCK || is_missile(otmp)))))
+                       otmp->quan = (long) cnt;
+
+#ifdef WIZARD
+       if (oclass == VENOM_CLASS) otmp->spe = 1;
+#endif
+
+       if (spesgn == 0) spe = otmp->spe;
+#ifdef WIZARD
+       else if (wizard) /* no alteration to spe */ ;
+#endif
+       else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS ||
+                is_weptool(otmp) ||
+                       (oclass==RING_CLASS && objects[typ].oc_charged)) {
+               if(spe > rnd(5) && spe > otmp->spe) spe = 0;
+               if(spe > 2 && Luck < 0) spesgn = -1;
+       } else {
+               if (oclass == WAND_CLASS) {
+                       if (spe > 1 && spesgn == -1) spe = 1;
+               } else {
+                       if (spe > 0 && spesgn == -1) spe = 0;
+               }
+               if (spe > otmp->spe) spe = otmp->spe;
+       }
+
+       if (spesgn == -1) spe = -spe;
+
+       /* set otmp->spe.  This may, or may not, use spe... */
+       switch (typ) {
+               case TIN: if (contents==EMPTY) {
+                               otmp->corpsenm = NON_PM;
+                               otmp->spe = 0;
+                       } else if (contents==SPINACH) {
+                               otmp->corpsenm = NON_PM;
+                               otmp->spe = 1;
+                       }
+                       break;
+               case SLIME_MOLD: otmp->spe = ftype;
+                       /* Fall through */
+               case SKELETON_KEY: case CHEST: case LARGE_BOX:
+               case HEAVY_IRON_BALL: case IRON_CHAIN: case STATUE:
+                       /* otmp->cobj already done in mksobj() */
+                               break;
+#ifdef MAIL
+               case SCR_MAIL: otmp->spe = 1; break;
+#endif
+               case WAN_WISHING:
+#ifdef WIZARD
+                       if (!wizard) {
+#endif
+                               otmp->spe = (rn2(10) ? -1 : 0);
+                               break;
+#ifdef WIZARD
+                       }
+                       /* fall through, if wizard */
+#endif
+               default: otmp->spe = spe;
+       }
+
+       /* set otmp->corpsenm or dragon scale [mail] */
+       if (mntmp >= LOW_PM) {
+               if (mntmp == PM_LONG_WORM_TAIL) mntmp = PM_LONG_WORM;
+
+               switch (typ) {
+               case TIN:
+                       otmp->spe = 0; /* No spinach */
+                       if (dead_species(mntmp, FALSE)) {
+                           otmp->corpsenm = NON_PM;    /* it's empty */
+                       } else if (!(mons[mntmp].geno & G_UNIQ) &&
+                                  !(mvitals[mntmp].mvflags & G_NOCORPSE) &&
+                                  mons[mntmp].cnutrit != 0) {
+                           otmp->corpsenm = mntmp;
+                       }
+                       break;
+               case CORPSE:
+                       if (!(mons[mntmp].geno & G_UNIQ) &&
+                                  !(mvitals[mntmp].mvflags & G_NOCORPSE)) {
+                           /* beware of random troll or lizard corpse,
+                              or of ordinary one being forced to such */
+                           if (otmp->timed) obj_stop_timers(otmp);
+                           if (mons[mntmp].msound == MS_GUARDIAN)
+                               otmp->corpsenm = genus(mntmp,1);
+                           else
+                               otmp->corpsenm = mntmp;
+                           start_corpse_timeout(otmp);
+                       }
+                       break;
+               case FIGURINE:
+                       if (!(mons[mntmp].geno & G_UNIQ)
+                           && !is_human(&mons[mntmp])
+#ifdef MAIL
+                           && mntmp != PM_MAIL_DAEMON
+#endif
+                                                       )
+                               otmp->corpsenm = mntmp;
+                       break;
+               case EGG:
+                       mntmp = can_be_hatched(mntmp);
+                       if (mntmp != NON_PM) {
+                           otmp->corpsenm = mntmp;
+                           if (!dead_species(mntmp, TRUE))
+                               attach_egg_hatch_timeout(otmp);
+                           else
+                               kill_egg(otmp);
+                       }
+                       break;
+               case STATUE: otmp->corpsenm = mntmp;
+                       if (Has_contents(otmp) && verysmall(&mons[mntmp]))
+                           delete_contents(otmp);      /* no spellbook */
+                       otmp->spe = ishistoric ? STATUE_HISTORIC : 0;
+                       break;
+               case SCALE_MAIL:
+                       /* Dragon mail - depends on the order of objects */
+                       /*               & dragons.                      */
+                       if (mntmp >= PM_GRAY_DRAGON &&
+                                               mntmp <= PM_YELLOW_DRAGON)
+                           otmp->otyp = GRAY_DRAGON_SCALE_MAIL +
+                                                   mntmp - PM_GRAY_DRAGON;
+                       break;
+               }
+       }
+
+       /* set blessed/cursed -- setting the fields directly is safe
+        * since weight() is called below and addinv() will take care
+        * of luck */
+       if (iscursed) {
+               curse(otmp);
+       } else if (uncursed) {
+               otmp->blessed = 0;
+               otmp->cursed = (Luck < 0
+#ifdef WIZARD
+                                        && !wizard
+#endif
+                                                       );
+       } else if (blessed) {
+               otmp->blessed = (Luck >= 0
+#ifdef WIZARD
+                                        || wizard
+#endif
+                                                       );
+               otmp->cursed = (Luck < 0
+#ifdef WIZARD
+                                        && !wizard
+#endif
+                                                       );
+       } else if (spesgn < 0) {
+               curse(otmp);
+       }
+
+#ifdef INVISIBLE_OBJECTS
+       if (isinvisible) otmp->oinvis = 1;
+#endif
+
+       /* set eroded */
+       if (is_damageable(otmp) || otmp->otyp == CRYSKNIFE) {
+           if (eroded && (is_flammable(otmp) || is_rustprone(otmp)))
+                   otmp->oeroded = eroded;
+           if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp)))
+                   otmp->oeroded2 = eroded2;
+
+           /* set erodeproof */
+           if (erodeproof && !eroded && !eroded2)
+                   otmp->oerodeproof = (Luck >= 0
+#ifdef WIZARD
+                                            || wizard
+#endif
+                                       );
+       }
+
+       /* set otmp->recharged */
+       if (oclass == WAND_CLASS) {
+           /* prevent wishing abuse */
+           if (otmp->otyp == WAN_WISHING
+#ifdef WIZARD
+                   && !wizard
+#endif
+               ) rechrg = 1;
+           otmp->recharged = (unsigned)rechrg;
+       }
+
+       /* set poisoned */
+       if (ispoisoned) {
+           if (is_poisonable(otmp))
+               otmp->opoisoned = (Luck >= 0);
+           else if (Is_box(otmp) || typ == TIN)
+               otmp->otrapped = 1;
+           else if (oclass == FOOD_CLASS)
+               /* try to taint by making it as old as possible */
+               otmp->age = 1L;
+       }
+
+       if (isgreased) otmp->greased = 1;
+
+       if (isdiluted && otmp->oclass == POTION_CLASS &&
+                       otmp->otyp != POT_WATER)
+               otmp->odiluted = 1;
+
+       if (name) {
+               const char *aname;
+               short objtyp;
+
+               /* an artifact name might need capitalization fixing */
+               aname = artifact_name(name, &objtyp);
+               if (aname && objtyp == otmp->otyp) name = aname;
+
+               otmp = oname(otmp, name);
+               if (otmp->oartifact) {
+                       otmp->quan = 1L;
+                       u.uconduct.wisharti++;  /* KMH, conduct */
+               }
+       }
+
+       /* more wishing abuse: don't allow wishing for certain artifacts */
+       /* and make them pay; charge them for the wish anyway! */
+       if ((is_quest_artifact(otmp) ||
+            (otmp->oartifact && rn2(nartifact_exist()) > 1))
+#ifdef WIZARD
+           && !wizard
+#endif
+           ) {
+           artifact_exists(otmp, ONAME(otmp), FALSE);
+           obfree(otmp, (struct obj *) 0);
+           otmp = &zeroobj;
+           pline("For a moment, you feel %s in your %s, but it disappears!",
+                 something,
+                 makeplural(body_part(HAND)));
+       }
+
+       if (halfeaten && otmp->oclass == FOOD_CLASS) {
+               if (otmp->otyp == CORPSE)
+                       otmp->oeaten = mons[otmp->corpsenm].cnutrit;
+               else otmp->oeaten = objects[otmp->otyp].oc_nutrition;
+               /* (do this adjustment before setting up object's weight) */
+               consume_oeaten(otmp, 1);
+       }
+       otmp->owt = weight(otmp);
+       if (very && otmp->otyp == HEAVY_IRON_BALL) otmp->owt += 160;
+
+       return(otmp);
+}
+
+int
+rnd_class(first,last)
+int first,last;
+{
+       int i, x, sum=0;
+
+       if (first == last)
+           return (first);
+       for(i=first; i<=last; i++)
+               sum += objects[i].oc_prob;
+       if (!sum) /* all zero */
+               return first + rn2(last-first+1);
+       x = rnd(sum);
+       for(i=first; i<=last; i++)
+               if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0)
+                       return i;
+       return 0;
+}
+
+STATIC_OVL const char *
+Japanese_item_name(i)
+int i;
+{
+       struct Jitem *j = Japanese_items;
+
+       while(j->item) {
+               if (i == j->item)
+                       return j->name;
+               j++;
+       }
+       return (const char *)0;
+}
+
+const char *
+cloak_simple_name(cloak)
+struct obj *cloak;
+{
+    if (cloak) {
+       switch (cloak->otyp) {
+       case ROBE:
+           return "robe";
+       case MUMMY_WRAPPING:
+           return "wrapping";
+       case ALCHEMY_SMOCK:
+           return (objects[cloak->otyp].oc_name_known &&
+                       cloak->dknown) ? "smock" : "apron";
+       default:
+           break;
+       }
+    }
+    return "cloak";
+}
+
+const char *
+mimic_obj_name(mtmp)
+struct monst *mtmp;
+{
+       if (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance != STRANGE_OBJECT) {
+               int idx = objects[mtmp->mappearance].oc_descr_idx;
+               if (mtmp->mappearance == GOLD_PIECE) return "gold";
+               return obj_descr[idx].oc_name;
+       }
+       return "whatcha-may-callit";
+}
+#endif /* OVLB */
+
+/*objnam.c*/
diff --git a/src/options.c b/src/options.c
new file mode 100644 (file)
index 0000000..dfb8006
--- /dev/null
@@ -0,0 +1,3862 @@
+/*     SCCS Id: @(#)options.c  3.4     2003/11/14      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifdef OPTION_LISTS_ONLY       /* (AMIGA) external program for opt lists */
+#include "config.h"
+#include "objclass.h"
+#include "flag.h"
+NEARDATA struct flag flags;    /* provide linkage */
+NEARDATA struct instance_flags iflags; /* provide linkage */
+#define static
+#else
+#include "hack.h"
+#include "tcap.h"
+#include <ctype.h>
+#endif
+
+#define WINTYPELEN 16
+
+#ifdef DEFAULT_WC_TILED_MAP
+#define PREFER_TILED TRUE
+#else
+#define PREFER_TILED FALSE
+#endif
+
+/*
+ *  NOTE:  If you add (or delete) an option, please update the short
+ *  options help (option_help()), the long options help (dat/opthelp),
+ *  and the current options setting display function (doset()),
+ *  and also the Guidebooks.
+ *
+ *  The order matters.  If an option is a an initial substring of another
+ *  option (e.g. time and timed_delay) the shorter one must come first.
+ */
+
+static struct Bool_Opt
+{
+       const char *name;
+       boolean *addr, initvalue;
+       int optflags;
+} boolopt[] = {
+#ifdef AMIGA
+       {"altmeta", &flags.altmeta, TRUE, DISP_IN_GAME},
+#else
+       {"altmeta", (boolean *)0, TRUE, DISP_IN_GAME},
+#endif
+       {"ascii_map",     &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME},    /*WC*/
+#ifdef MFLOPPY
+       {"asksavedisk", &flags.asksavedisk, FALSE, SET_IN_GAME},
+#else
+       {"asksavedisk", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+       {"autodig", &flags.autodig, FALSE, SET_IN_GAME},
+       {"autopickup", &flags.pickup, TRUE, SET_IN_GAME},
+       {"autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME},
+#if defined(MICRO) && !defined(AMIGA)
+       {"BIOS", &iflags.BIOS, FALSE, SET_IN_FILE},
+#else
+       {"BIOS", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+#ifdef INSURANCE
+       {"checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME},
+#else
+       {"checkpoint", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+#ifdef MFLOPPY
+       {"checkspace", &iflags.checkspace, TRUE, SET_IN_GAME},
+#else
+       {"checkspace", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+       {"cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME},
+# if defined(MICRO) || defined(WIN32)
+       {"color",         &iflags.wc_color,TRUE, SET_IN_GAME},          /*WC*/
+# else /* systems that support multiple terminals, many monochrome */
+       {"color",         &iflags.wc_color, FALSE, SET_IN_GAME},        /*WC*/
+# endif
+       {"confirm",&flags.confirm, TRUE, SET_IN_GAME},
+#if defined(TERMLIB) && !defined(MAC_GRAPHICS_ENV)
+       {"DECgraphics", &iflags.DECgraphics, FALSE, SET_IN_GAME},
+#else
+       {"DECgraphics", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+       {"eight_bit_tty", &iflags.wc_eight_bit_input, FALSE, SET_IN_GAME},      /*WC*/
+#ifdef TTY_GRAPHICS
+       {"extmenu", &iflags.extmenu, FALSE, SET_IN_GAME},
+#else
+       {"extmenu", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+#ifdef OPT_DISPMAP
+       {"fast_map", &flags.fast_map, TRUE, SET_IN_GAME},
+#else
+       {"fast_map", (boolean *)0, TRUE, SET_IN_FILE},
+#endif
+       {"female", &flags.female, FALSE, DISP_IN_GAME},
+       {"fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME},
+#ifdef AMIFLUSH
+       {"flush", &flags.amiflush, FALSE, SET_IN_GAME},
+#else
+       {"flush", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+       {"fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE},
+       {"help", &flags.help, TRUE, SET_IN_GAME},
+       {"hilite_pet",    &iflags.wc_hilite_pet, FALSE, SET_IN_GAME},   /*WC*/
+#ifdef ASCIIGRAPH
+       {"IBMgraphics", &iflags.IBMgraphics, FALSE, SET_IN_GAME},
+#else
+       {"IBMgraphics", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+#ifndef MAC
+       {"ignintr", &flags.ignintr, FALSE, SET_IN_GAME},
+#else
+       {"ignintr", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+       {"large_font", &iflags.obsolete, FALSE, SET_IN_FILE},   /* OBSOLETE */
+       {"legacy", &flags.legacy, TRUE, DISP_IN_GAME},
+       {"lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME},
+       {"lootabc", &iflags.lootabc, FALSE, SET_IN_GAME},
+#ifdef MAC_GRAPHICS_ENV
+       {"Macgraphics", &iflags.MACgraphics, TRUE, SET_IN_GAME},
+#else
+       {"Macgraphics", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+#ifdef MAIL
+       {"mail", &flags.biff, TRUE, SET_IN_GAME},
+#else
+       {"mail", (boolean *)0, TRUE, SET_IN_FILE},
+#endif
+#ifdef WIZARD
+       /* for menu debugging only*/
+       {"menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_GAME},
+#else
+       {"menu_tab_sep", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+       {"mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME},        /*WC*/
+#ifdef NEWS
+       {"news", &iflags.news, TRUE, DISP_IN_GAME},
+#else
+       {"news", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+       {"null", &flags.null, TRUE, SET_IN_GAME},
+#ifdef MAC
+       {"page_wait", &flags.page_wait, TRUE, SET_IN_GAME},
+#else
+       {"page_wait", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+       {"perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME},
+       {"popup_dialog",  &iflags.wc_popup_dialog, FALSE, SET_IN_GAME}, /*WC*/
+       {"prayconfirm", &flags.prayconfirm, TRUE, SET_IN_GAME},
+       {"preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME},        /*WC*/
+       {"pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME},
+#if defined(MICRO) && !defined(AMIGA)
+       {"rawio", &iflags.rawio, FALSE, DISP_IN_GAME},
+#else
+       {"rawio", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+       {"rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME},
+       {"safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME},
+#ifdef WIZARD
+       {"sanity_check", &iflags.sanity_check, FALSE, SET_IN_GAME},
+#else
+       {"sanity_check", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+#ifdef EXP_ON_BOTL
+       {"showexp", &flags.showexp, FALSE, SET_IN_GAME},
+#else
+       {"showexp", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+       {"showrace", &iflags.showrace, FALSE, SET_IN_GAME},
+#ifdef SCORE_ON_BOTL
+       {"showscore", &flags.showscore, FALSE, SET_IN_GAME},
+#else
+       {"showscore", (boolean *)0, FALSE, SET_IN_FILE},
+#endif
+       {"silent", &flags.silent, TRUE, SET_IN_GAME},
+       {"softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE},
+       {"sortpack", &flags.sortpack, TRUE, SET_IN_GAME},
+       {"sound", &flags.soundok, TRUE, SET_IN_GAME},
+       {"sparkle", &flags.sparkle, TRUE, SET_IN_GAME},
+       {"standout", &flags.standout, FALSE, SET_IN_GAME},
+       {"splash_screen",     &iflags.wc_splash_screen, TRUE, DISP_IN_GAME},    /*WC*/
+       {"tiled_map",     &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME},    /*WC*/
+       {"time", &flags.time, FALSE, SET_IN_GAME},
+#ifdef TIMED_DELAY
+       {"timed_delay", &flags.nap, TRUE, SET_IN_GAME},
+#else
+       {"timed_delay", (boolean *)0, FALSE, SET_IN_GAME},
+#endif
+       {"tombstone",&flags.tombstone, TRUE, SET_IN_GAME},
+       {"toptenwin",&flags.toptenwin, FALSE, SET_IN_GAME},
+       {"travel", &iflags.travelcmd, TRUE, SET_IN_GAME},
+#ifdef WIN32CON
+       {"use_inverse",   &iflags.wc_inverse, TRUE, SET_IN_GAME},               /*WC*/
+#else
+       {"use_inverse",   &iflags.wc_inverse, FALSE, SET_IN_GAME},              /*WC*/
+#endif
+       {"verbose", &flags.verbose, TRUE, SET_IN_GAME},
+       {"wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME},
+       {(char *)0, (boolean *)0, FALSE, 0}
+};
+
+/* compound options, for option_help() and external programs like Amiga
+ * frontend */
+static struct Comp_Opt
+{
+       const char *name, *descr;
+       int size;       /* for frontends and such allocating space --
+                        * usually allowed size of data in game, but
+                        * occasionally maximum reasonable size for
+                        * typing when game maintains information in
+                        * a different format */
+       int optflags;
+} compopt[] = {
+       { "align",    "your starting alignment (lawful, neutral, or chaotic)",
+                                               8, DISP_IN_GAME },
+       { "align_message", "message window alignment", 20, DISP_IN_GAME },      /*WC*/
+       { "align_status", "status window alignment", 20, DISP_IN_GAME },        /*WC*/
+       { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME },
+       { "boulder",  "the symbol to use for displaying boulders",
+                                               1, SET_IN_GAME },
+       { "catname",  "the name of your (first) cat (e.g., catname:Tabby)",
+                                               PL_PSIZ, DISP_IN_GAME },
+       { "disclose", "the kinds of information to disclose at end of game",
+                                               sizeof(flags.end_disclose) * 2,
+                                               SET_IN_GAME },
+       { "dogname",  "the name of your (first) dog (e.g., dogname:Fang)",
+                                               PL_PSIZ, DISP_IN_GAME },
+       { "dungeon",  "the symbols to use in drawing the dungeon map",
+                                               MAXDCHARS+1, SET_IN_FILE },
+       { "effects",  "the symbols to use in drawing special effects",
+                                               MAXECHARS+1, SET_IN_FILE },
+       { "font_map", "the font to use in the map window", 40, DISP_IN_GAME },  /*WC*/
+       { "font_menu", "the font to use in menus", 40, DISP_IN_GAME },          /*WC*/
+       { "font_message", "the font to use in the message window",
+                                               40, DISP_IN_GAME },             /*WC*/
+       { "font_size_map", "the size of the map font", 20, DISP_IN_GAME },      /*WC*/
+       { "font_size_menu", "the size of the menu font", 20, DISP_IN_GAME },    /*WC*/
+       { "font_size_message", "the size of the message font", 20, DISP_IN_GAME },      /*WC*/
+       { "font_size_status", "the size of the status font", 20, DISP_IN_GAME },        /*WC*/
+       { "font_size_text", "the size of the text font", 20, DISP_IN_GAME },    /*WC*/
+       { "font_status", "the font to use in status window", 40, DISP_IN_GAME }, /*WC*/
+       { "font_text", "the font to use in text windows", 40, DISP_IN_GAME },   /*WC*/
+       { "fruit",    "the name of a fruit you enjoy eating",
+                                               PL_FSIZ, SET_IN_GAME },
+       { "gender",   "your starting gender (male or female)",
+                                               8, DISP_IN_GAME },
+       { "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
+                                               PL_PSIZ, DISP_IN_GAME },
+       { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME },     /*WC*/
+       { "menustyle", "user interface for object selection",
+                                               MENUTYPELEN, SET_IN_GAME },
+       { "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE },
+       { "menu_deselect_page", "deselect all items on this page of a menu",
+                                               4, SET_IN_FILE },
+       { "menu_first_page", "jump to the first page in a menu",
+                                               4, SET_IN_FILE },
+       { "menu_headings", "bold, inverse, or underline headings", 9, SET_IN_GAME },
+       { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE },
+       { "menu_invert_page", "invert all items on this page of a menu",
+                                               4, SET_IN_FILE },
+       { "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE },
+       { "menu_next_page", "goto the next menu page", 4, SET_IN_FILE },
+       { "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE },
+       { "menu_search", "search for a menu item", 4, SET_IN_FILE },
+       { "menu_select_all", "select all items in a menu", 4, SET_IN_FILE },
+       { "menu_select_page", "select all items on this page of a menu",
+                                               4, SET_IN_FILE },
+       { "monsters", "the symbols to use for monsters",
+                                               MAXMCLASSES, SET_IN_FILE },
+       { "msghistory", "number of top line messages to save",
+                                               5, DISP_IN_GAME },
+# ifdef TTY_GRAPHICS
+       {"msg_window", "the type of message window required",1, SET_IN_GAME},
+# else
+       {"msg_window", "the type of message window required", 1, SET_IN_FILE},
+# endif
+       { "name",     "your character's name (e.g., name:Merlin-W)",
+                                               PL_NSIZ, DISP_IN_GAME },
+       { "number_pad", "use the number pad", 1, SET_IN_GAME},
+       { "objects",  "the symbols to use for objects",
+                                               MAXOCLASSES, SET_IN_FILE },
+       { "packorder", "the inventory order of the items in your pack",
+                                               MAXOCLASSES, SET_IN_GAME },
+#ifdef CHANGE_COLOR
+       { "palette",  "palette (00c/880/-fff is blue/yellow/reverse white)",
+                                               15 , SET_IN_GAME },
+# if defined(MAC)
+       { "hicolor",  "same as palette, only order is reversed",
+                                               15, SET_IN_FILE },
+# endif
+#endif
+       { "pettype",  "your preferred initial pet type", 4, DISP_IN_GAME },
+       { "pickup_burden",  "maximum burden picked up before prompt",
+                                               20, SET_IN_GAME },
+       { "pickup_types", "types of objects to pick up automatically",
+                                               MAXOCLASSES, SET_IN_GAME },
+       { "player_selection", "choose character via dialog or prompts",
+                                               12, DISP_IN_GAME },
+       { "race",     "your starting race (e.g., Human, Elf)",
+                                               PL_CSIZ, DISP_IN_GAME },
+       { "role",     "your starting role (e.g., Barbarian, Valkyrie)",
+                                               PL_CSIZ, DISP_IN_GAME },
+       { "runmode", "display frequency when `running' or `travelling'",
+                                               sizeof "teleport", SET_IN_GAME },
+       { "scores",   "the parts of the score list you wish to see",
+                                               32, SET_IN_GAME },
+       { "scroll_amount", "amount to scroll map when scroll_margin is reached",
+                                               20, DISP_IN_GAME }, /*WC*/
+       { "scroll_margin", "scroll map when this far from the edge", 20, DISP_IN_GAME }, /*WC*/
+#ifdef MSDOS
+       { "soundcard", "type of sound card to use", 20, SET_IN_FILE },
+#endif
+       { "suppress_alert", "suppress alerts about version-specific features",
+                                               8, SET_IN_GAME },
+       { "tile_width", "width of tiles", 20, DISP_IN_GAME},    /*WC*/
+       { "tile_height", "height of tiles", 20, DISP_IN_GAME},  /*WC*/
+       { "tile_file", "name of tile file", 70, DISP_IN_GAME},  /*WC*/
+       { "traps",    "the symbols to use in drawing traps",
+                                               MAXTCHARS+1, SET_IN_FILE },
+       { "vary_msgcount", "show more old messages at a time", 20, DISP_IN_GAME }, /*WC*/
+#ifdef MSDOS
+       { "video",    "method of video updating", 20, SET_IN_FILE },
+#endif
+#ifdef VIDEOSHADES
+       { "videocolors", "color mappings for internal screen routines",
+                                               40, DISP_IN_GAME },
+       { "videoshades", "gray shades to map to black/gray/white",
+                                               32, DISP_IN_GAME },
+#endif
+#ifdef WIN32CON
+       {"subkeyvalue", "override keystroke value", 7, SET_IN_FILE},
+#endif
+       { "windowcolors",  "the foreground/background colors of windows",       /*WC*/
+                                               80, DISP_IN_GAME },
+       { "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
+       { (char *)0, (char *)0, 0, 0 }
+};
+
+#ifdef OPTION_LISTS_ONLY
+#undef static
+
+#else  /* use rest of file */
+
+static boolean need_redraw; /* for doset() */
+
+#if defined(TOS) && defined(TEXTCOLOR)
+extern boolean colors_changed; /* in tos.c */
+#endif
+
+#ifdef VIDEOSHADES
+extern char *shade[3];           /* in sys/msdos/video.c */
+extern char ttycolors[CLR_MAX];          /* in sys/msdos/video.c */
+#endif
+
+static char def_inv_order[MAXOCLASSES] = {
+       COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
+       SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS,
+       TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
+};
+
+/*
+ * Default menu manipulation command accelerators.  These may _not_ be:
+ *
+ *     + a number - reserved for counts
+ *     + an upper or lower case US ASCII letter - used for accelerators
+ *     + ESC - reserved for escaping the menu
+ *     + NULL, CR or LF - reserved for commiting the selection(s).  NULL
+ *       is kind of odd, but the tty's xwaitforspace() will return it if
+ *       someone hits a <ret>.
+ *     + a default object class symbol - used for object class accelerators
+ *
+ * Standard letters (for now) are:
+ *
+ *             <  back 1 page
+ *             >  forward 1 page
+ *             ^  first page
+ *             |  last page
+ *             :  search
+ *
+ *             page            all
+ *              ,    select     .
+ *              \    deselect   -
+ *              ~    invert     @
+ *
+ * The command name list is duplicated in the compopt array.
+ */
+typedef struct {
+    const char *name;
+    char cmd;
+} menu_cmd_t;
+
+#define NUM_MENU_CMDS 11
+static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = {
+/* 0*/ { "menu_first_page",    MENU_FIRST_PAGE },
+       { "menu_last_page",     MENU_LAST_PAGE },
+       { "menu_next_page",     MENU_NEXT_PAGE },
+       { "menu_previous_page", MENU_PREVIOUS_PAGE },
+       { "menu_select_all",    MENU_SELECT_ALL },
+/* 5*/ { "menu_deselect_all",  MENU_UNSELECT_ALL },
+       { "menu_invert_all",    MENU_INVERT_ALL },
+       { "menu_select_page",   MENU_SELECT_PAGE },
+       { "menu_deselect_page", MENU_UNSELECT_PAGE },
+       { "menu_invert_page",   MENU_INVERT_PAGE },
+/*10*/ { "menu_search",                MENU_SEARCH },
+};
+
+/*
+ * 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(doset_add_menu, (winid,const char *,int));
+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 void FDECL(badoption, (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 void FDECL(oc_to_str, (char *, char *));
+STATIC_DCL void FDECL(graphics_opts, (char *,const char *,int,int));
+STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *));
+STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *));
+STATIC_DCL boolean FDECL(special_handling, (const char *, BOOLEAN_P, BOOLEAN_P));
+STATIC_DCL void FDECL(warning_opts, (char *,const char *));
+STATIC_DCL void FDECL(duplicate_opt_detection, (const char *, int));
+
+STATIC_OVL void FDECL(wc_set_font_name, (int, char *));
+STATIC_OVL int FDECL(wc_set_window_colors, (char *));
+STATIC_OVL boolean FDECL(is_wc_option, (const char *));
+STATIC_OVL boolean FDECL(wc_supported, (const char *));
+STATIC_OVL boolean FDECL(is_wc2_option, (const char *));
+STATIC_OVL boolean FDECL(wc2_supported, (const char *));
+#ifdef AUTOPICKUP_EXCEPTIONS
+STATIC_DCL void FDECL(remove_autopickup_exception, (struct autopickup_exception *));
+STATIC_OVL int FDECL(count_ape_maps, (int *, int *));
+#endif
+
+/* check whether a user-supplied option string is a proper leading
+   substring of a particular option name; option string might have
+   a colon or equals sign and arbitrary value appended to it */
+boolean
+match_optname(user_string, opt_name, min_length, val_allowed)
+const char *user_string, *opt_name;
+int min_length;
+boolean val_allowed;
+{
+       int len = (int)strlen(user_string);
+
+       if (val_allowed) {
+           const char *p = index(user_string, ':'),
+                      *q = index(user_string, '=');
+
+           if (!p || (q && q < p)) p = q;
+           while(p && p > user_string && isspace(*(p-1))) p--;
+           if (p) len = (int)(p - user_string);
+       }
+
+       return (len >= min_length) && !strncmpi(opt_name, user_string, len);
+}
+
+/* most environment variables will eventually be printed in an error
+ * message if they don't work, and most error message paths go through
+ * BUFSZ buffers, which could be overflowed by a maliciously long
+ * environment variable.  if a variable can legitimately be long, or
+ * if it's put in a smaller buffer, the responsible code will have to
+ * bounds-check itself.
+ */
+char *
+nh_getenv(ev)
+const char *ev;
+{
+       char *getev = getenv(ev);
+
+       if (getev && strlen(getev) <= (BUFSZ / 2))
+               return getev;
+       else
+               return (char *)0;
+}
+
+void
+initoptions()
+{
+#ifndef MAC
+       char *opts;
+#endif
+       int i;
+
+       /* initialize the random number generator */
+       setrandom();
+
+       /* for detection of configfile options specified multiple times */
+       iflags.opt_booldup = iflags.opt_compdup = (int *)0;
+       
+       for (i = 0; boolopt[i].name; i++) {
+               if (boolopt[i].addr)
+                       *(boolopt[i].addr) = boolopt[i].initvalue;
+       }
+       flags.end_own = FALSE;
+       flags.end_top = 3;
+       flags.end_around = 2;
+       iflags.runmode = RUN_LEAP;
+       iflags.msg_history = 20;
+#ifdef TTY_GRAPHICS
+       iflags.prevmsg_window = 's';
+#endif
+       iflags.menu_headings = ATR_INVERSE;
+
+       /* Use negative indices to indicate not yet selected */
+       flags.initrole = -1;
+       flags.initrace = -1;
+       flags.initgend = -1;
+       flags.initalign = -1;
+
+       /* Set the default monster and object class symbols.  Don't use */
+       /* memcpy() --- sizeof char != sizeof uchar on some machines.   */
+       for (i = 0; i < MAXOCLASSES; i++)
+               oc_syms[i] = (uchar) def_oc_syms[i];
+       for (i = 0; i < MAXMCLASSES; i++)
+               monsyms[i] = (uchar) def_monsyms[i];
+       for (i = 0; i < WARNCOUNT; i++)
+               warnsyms[i] = def_warnsyms[i].sym;
+       iflags.bouldersym = 0;
+       iflags.travelcc.x = iflags.travelcc.y = -1;
+       flags.warnlevel = 1;
+       flags.warntype = 0L;
+
+     /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
+       (void)memcpy((genericptr_t)flags.inv_order,
+                    (genericptr_t)def_inv_order, sizeof flags.inv_order);
+       flags.pickup_types[0] = '\0';
+       flags.pickup_burden = MOD_ENCUMBER;
+
+       for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
+               flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
+       switch_graphics(ASCII_GRAPHICS);        /* set default characters */
+#if defined(UNIX) && defined(TTY_GRAPHICS)
+       /*
+        * Set defaults for some options depending on what we can
+        * detect about the environment's capabilities.
+        * This has to be done after the global initialization above
+        * and before reading user-specific initialization via
+        * config file/environment variable below.
+        */
+       /* this detects the IBM-compatible console on most 386 boxes */
+       if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) {
+               switch_graphics(IBM_GRAPHICS);
+# ifdef TEXTCOLOR
+               iflags.use_color = TRUE;
+# endif
+       }
+#endif /* UNIX && TTY_GRAPHICS */
+#if defined(UNIX) || defined(VMS)
+# ifdef TTY_GRAPHICS
+       /* detect whether a "vt" terminal can handle alternate charsets */
+       if ((opts = nh_getenv("TERM")) &&
+           !strncmpi(opts, "vt", 2) && AS && AE &&
+           index(AS, '\016') && index(AE, '\017')) {
+               switch_graphics(DEC_GRAPHICS);
+       }
+# endif
+#endif /* UNIX || VMS */
+
+#ifdef MAC_GRAPHICS_ENV
+       switch_graphics(MAC_GRAPHICS);
+#endif /* MAC_GRAPHICS_ENV */
+       flags.menu_style = MENU_FULL;
+
+       /* since this is done before init_objects(), do partial init here */
+       objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
+       nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
+#ifndef MAC
+       opts = getenv("NETHACKOPTIONS");
+       if (!opts) opts = getenv("HACKOPTIONS");
+       if (opts) {
+               if (*opts == '/' || *opts == '\\' || *opts == '@') {
+                       if (*opts == '@') opts++;       /* @filename */
+                       /* looks like a filename */
+                       if (strlen(opts) < BUFSZ/2)
+                           read_config_file(opts);
+               } else {
+                       read_config_file((char *)0);
+                       /* let the total length of options be long;
+                        * parseoptions() will check each individually
+                        */
+                       parseoptions(opts, TRUE, FALSE);
+               }
+       } else
+#endif
+               read_config_file((char *)0);
+
+       (void)fruitadd(pl_fruit);
+       /* Remove "slime mold" from list of object names; this will     */
+       /* prevent it from being wished unless it's actually present    */
+       /* as a named (or default) fruit.  Wishing for "fruit" will     */
+       /* result in the player's preferred fruit [better than "\033"]. */
+       obj_descr[SLIME_MOLD].oc_name = "fruit";
+
+       return;
+}
+
+STATIC_OVL void
+nmcpy(dest, src, maxlen)
+       char    *dest;
+       const char *src;
+       int     maxlen;
+{
+       int     count;
+
+       for(count = 1; count < maxlen; count++) {
+               if(*src == ',' || *src == '\0') break; /*exit on \0 terminator*/
+               *dest++ = *src++;
+       }
+       *dest = 0;
+}
+
+/*
+ * escapes: escape expansion for showsyms. C-style escapes understood include
+ * \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix
+ * for control characters is also understood, and \[mM] followed by any of the
+ * previous forms or by a character has the effect of 'meta'-ing the value (so
+ * that the alternate character set will be enabled).
+ */
+STATIC_OVL void
+escapes(cp, tp)
+const char     *cp;
+char *tp;
+{
+    while (*cp)
+    {
+       int     cval = 0, meta = 0;
+
+       if (*cp == '\\' && index("mM", cp[1])) {
+               meta = 1;
+               cp += 2;
+       }
+       if (*cp == '\\' && index("0123456789xXoO", cp[1]))
+       {
+           const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
+           int dcount = 0;
+
+           cp++;
+           if (*cp == 'x' || *cp == 'X')
+               for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
+                   cval = (cval * 16) + (dp - hex) / 2;
+           else if (*cp == 'o' || *cp == 'O')
+               for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++)
+                   cval = (cval * 8) + (*cp - '0');
+           else
+               for (; (index("0123456789",*cp)) && (dcount++ < 3); cp++)
+                   cval = (cval * 10) + (*cp - '0');
+       }
+       else if (*cp == '\\')           /* C-style character escapes */
+       {
+           switch (*++cp)
+           {
+           case '\\': cval = '\\'; break;
+           case 'n': cval = '\n'; break;
+           case 't': cval = '\t'; break;
+           case 'b': cval = '\b'; break;
+           case 'r': cval = '\r'; break;
+           default: cval = *cp;
+           }
+           cp++;
+       }
+       else if (*cp == '^')            /* expand control-character syntax */
+       {
+           cval = (*++cp & 0x1f);
+           cp++;
+       }
+       else
+           cval = *cp++;
+       if (meta)
+           cval |= 0x80;
+       *tp++ = cval;
+    }
+    *tp = '\0';
+}
+
+STATIC_OVL void
+rejectoption(optname)
+const char *optname;
+{
+#ifdef MICRO
+       pline("\"%s\" settable only from %s.", optname, configfile);
+#else
+       pline("%s can be set only from NETHACKOPTIONS or %s.", optname,
+                       configfile);
+#endif
+}
+
+STATIC_OVL void
+badoption(opts)
+const char *opts;
+{
+       if (!initial) {
+           if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1))
+               option_help();
+           else
+               pline("Bad syntax: %s.  Enter \"?g\" for help.", opts);
+           return;
+       }
+#ifdef MAC
+       else return;
+#endif
+
+       if(from_file)
+           raw_printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts);
+       else
+           raw_printf("Bad syntax in NETHACKOPTIONS: %s.", opts);
+
+       wait_synch();
+}
+
+STATIC_OVL char *
+string_for_opt(opts, val_optional)
+char *opts;
+boolean val_optional;
+{
+       char *colon, *equals;
+
+       colon = index(opts, ':');
+       equals = index(opts, '=');
+       if (!colon || (equals && equals < colon)) colon = equals;
+
+       if (!colon || !*++colon) {
+               if (!val_optional) badoption(opts);
+               return (char *)0;
+       }
+       return colon;
+}
+
+STATIC_OVL char *
+string_for_env_opt(optname, opts, val_optional)
+const char *optname;
+char *opts;
+boolean val_optional;
+{
+       if(!initial) {
+               rejectoption(optname);
+               return (char *)0;
+       }
+       return string_for_opt(opts, val_optional);
+}
+
+STATIC_OVL void
+bad_negation(optname, with_parameter)
+const char *optname;
+boolean with_parameter;
+{
+       pline_The("%s option may not %sbe negated.",
+               optname,
+               with_parameter ? "both have a value and " : "");
+}
+
+/*
+ * Change the inventory order, using the given string as the new order.
+ * Missing characters in the new order are filled in at the end from
+ * the current inv_order, except for gold, which is forced to be first
+ * if not explicitly present.
+ *
+ * This routine returns 1 unless there is a duplicate or bad char in
+ * the string.
+ */
+STATIC_OVL int
+change_inv_order(op)
+char *op;
+{
+    int oc_sym, num;
+    char *sp, buf[BUFSZ];
+
+    num = 0;
+#ifndef GOLDOBJ
+    if (!index(op, GOLD_SYM))
+       buf[num++] = COIN_CLASS;
+#else
+    /*  !!!! probably unnecessary with gold as normal inventory */
+#endif
+
+    for (sp = op; *sp; sp++) {
+       oc_sym = def_char_to_objclass(*sp);
+       /* reject bad or duplicate entries */
+       if (oc_sym == MAXOCLASSES ||
+               oc_sym == RANDOM_CLASS || oc_sym == ILLOBJ_CLASS ||
+               !index(flags.inv_order, oc_sym) || index(sp+1, *sp))
+           return 0;
+       /* retain good ones */
+       buf[num++] = (char) oc_sym;
+    }
+    buf[num] = '\0';
+
+    /* fill in any omitted classes, using previous ordering */
+    for (sp = flags.inv_order; *sp; sp++)
+       if (!index(buf, *sp)) {
+           buf[num++] = *sp;
+           buf[num] = '\0';    /* explicitly terminate for next index() */
+       }
+
+    Strcpy(flags.inv_order, buf);
+    return 1;
+}
+
+STATIC_OVL void
+graphics_opts(opts, optype, maxlen, offset)
+register char *opts;
+const char *optype;
+int maxlen, offset;
+{
+       uchar translate[MAXPCHARS+1];
+       int length, i;
+
+       if (!(opts = string_for_env_opt(optype, opts, FALSE)))
+               return;
+       escapes(opts, opts);
+
+       length = strlen(opts);
+       if (length > maxlen) length = maxlen;
+       /* match the form obtained from PC configuration files */
+       for (i = 0; i < length; i++)
+               translate[i] = (uchar) opts[i];
+       assign_graphics(translate, length, maxlen, offset);
+}
+
+STATIC_OVL void
+warning_opts(opts, optype)
+register char *opts;
+const char *optype;
+{
+       uchar translate[MAXPCHARS+1];
+       int length, i;
+
+       if (!(opts = string_for_env_opt(optype, opts, FALSE)))
+               return;
+       escapes(opts, opts);
+
+       length = strlen(opts);
+       if (length > WARNCOUNT) length = WARNCOUNT;
+       /* match the form obtained from PC configuration files */
+       for (i = 0; i < length; i++)
+            translate[i] = (((i < WARNCOUNT) && opts[i]) ?
+                          (uchar) opts[i] : def_warnsyms[i].sym);
+       assign_warnings(translate);
+}
+
+void
+assign_warnings(graph_chars)
+register uchar *graph_chars;
+{
+       int i;
+       for (i = 0; i < WARNCOUNT; i++)
+           if (graph_chars[i]) warnsyms[i] = graph_chars[i];
+}
+
+STATIC_OVL int
+feature_alert_opts(op, optn)
+char *op;
+const char *optn;
+{
+       char buf[BUFSZ];
+       boolean rejectver = FALSE;
+       unsigned long fnv = get_feature_notice_ver(op);         /* version.c */
+       if (fnv == 0L) return 0;
+       if (fnv > get_current_feature_ver())
+               rejectver = TRUE;
+       else
+               flags.suppress_alert = fnv;
+       if (rejectver) {
+               if (!initial)
+                       You_cant("disable new feature alerts for future versions.");
+               else {
+                       Sprintf(buf,
+                               "\n%s=%s Invalid reference to a future version ignored",
+                               optn, op);
+                       badoption(buf);
+               }
+               return 0;
+       }
+       if (!initial) {
+               Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
+                       FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
+               pline("Feature change alerts disabled for NetHack %s features and prior.",
+                       buf);
+       }
+       return 1;
+}
+
+void
+set_duplicate_opt_detection(on_or_off)
+int on_or_off;
+{
+       int k, *optptr;
+       if (on_or_off != 0) {
+               /*-- ON --*/
+               if (iflags.opt_booldup)
+                       impossible("iflags.opt_booldup already on (memory leak)");
+               iflags.opt_booldup = (int *)alloc(SIZE(boolopt) * sizeof(int));
+               optptr = iflags.opt_booldup;
+               for (k = 0; k < SIZE(boolopt); ++k)
+                       *optptr++ = 0;
+                       
+               if (iflags.opt_compdup)
+                       impossible("iflags.opt_compdup already on (memory leak)");
+               iflags.opt_compdup = (int *)alloc(SIZE(compopt) * sizeof(int));
+               optptr = iflags.opt_compdup;
+               for (k = 0; k < SIZE(compopt); ++k)
+                       *optptr++ = 0;
+       } else {
+               /*-- OFF --*/
+               if (iflags.opt_booldup) free((genericptr_t) iflags.opt_booldup);
+               iflags.opt_booldup = (int *)0;
+               if (iflags.opt_compdup) free((genericptr_t) iflags.opt_compdup);
+               iflags.opt_compdup = (int *)0;
+       } 
+}
+
+STATIC_OVL void
+duplicate_opt_detection(opts, bool_or_comp)
+const char *opts;
+int bool_or_comp;      /* 0 == boolean option, 1 == compound */
+{
+       int i, *optptr;
+#if defined(MAC)
+       /* the Mac has trouble dealing with the output of messages while
+        * processing the config file.  That should get fixed one day.
+        * For now just return.
+        */
+       return;
+#endif
+       if ((bool_or_comp == 0) && iflags.opt_booldup && initial && from_file) {
+           for (i = 0; boolopt[i].name; i++) {
+               if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
+                       optptr = iflags.opt_booldup + i;
+                       if (*optptr == 1) {
+                           raw_printf(
+                               "\nWarning - Boolean option specified multiple times: %s.\n",
+                                       opts);
+                               wait_synch();
+                       }
+                       *optptr += 1;
+                       break; /* don't match multiple options */
+               }
+           }
+       } else if ((bool_or_comp == 1) && iflags.opt_compdup && initial && from_file) {
+           for (i = 0; compopt[i].name; i++) {
+               if (match_optname(opts, compopt[i].name, strlen(compopt[i].name), TRUE)) {
+                       optptr = iflags.opt_compdup + i;
+                       if (*optptr == 1) {
+                           raw_printf(
+                               "\nWarning - compound option specified multiple times: %s.\n",
+                                       compopt[i].name);
+                               wait_synch();
+                       }
+                       *optptr += 1;
+                       break; /* don't match multiple options */
+               }
+           }
+       }
+}
+
+void
+parseoptions(opts, tinitial, tfrom_file)
+register char *opts;
+boolean tinitial, tfrom_file;
+{
+       register char *op;
+       unsigned num;
+       boolean negated;
+       int i;
+       const char *fullname;
+
+       initial = tinitial;
+       from_file = tfrom_file;
+       if ((op = index(opts, ',')) != 0) {
+               *op++ = 0;
+               parseoptions(op, initial, from_file);
+       }
+       if (strlen(opts) > BUFSZ/2) {
+               badoption("option too long");
+               return;
+       }
+
+       /* strip leading and trailing white space */
+       while (isspace(*opts)) opts++;
+       op = eos(opts);
+       while (--op >= opts && isspace(*op)) *op = '\0';
+
+       if (!*opts) return;
+       negated = FALSE;
+       while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
+               if (*opts == '!') opts++; else opts += 2;
+               negated = !negated;
+       }
+
+       /* variant spelling */
+
+       if (match_optname(opts, "colour", 5, FALSE))
+               Strcpy(opts, "color");  /* fortunately this isn't longer */
+
+       if (!match_optname(opts, "subkeyvalue", 11, TRUE)) /* allow multiple */
+       duplicate_opt_detection(opts, 1);       /* 1 means compound opts */
+
+       /* special boolean options */
+
+       if (match_optname(opts, "female", 3, FALSE)) {
+               if(!initial && flags.female == negated)
+                       pline("That is not anatomically possible.");
+               else
+                       flags.initgend = flags.female = !negated;
+               return;
+       }
+
+       if (match_optname(opts, "male", 4, FALSE)) {
+               if(!initial && flags.female != negated)
+                       pline("That is not anatomically possible.");
+               else
+                       flags.initgend = flags.female = negated;
+               return;
+       }
+
+#if defined(MICRO) && !defined(AMIGA)
+       /* included for compatibility with old NetHack.cnf files */
+       if (match_optname(opts, "IBM_", 4, FALSE)) {
+               iflags.BIOS = !negated;
+               return;
+       }
+#endif /* MICRO */
+
+       /* compound options */
+
+       fullname = "pettype";
+       if (match_optname(opts, fullname, 3, TRUE)) {
+               if ((op = string_for_env_opt(fullname, opts, negated)) != 0) {
+                   if (negated) bad_negation(fullname, TRUE);
+                   else switch (*op) {
+                       case 'd':       /* dog */
+                       case 'D':
+                           preferred_pet = 'd';
+                           break;
+                       case 'c':       /* cat */
+                       case 'C':
+                       case 'f':       /* feline */
+                       case 'F':
+                           preferred_pet = 'c';
+                           break;
+                       case 'n':       /* no pet */
+                       case 'N':
+                           preferred_pet = 'n';
+                           break;
+                       default:
+                           pline("Unrecognized pet type '%s'.", op);
+                           break;
+                   }
+               } else if (negated) preferred_pet = 'n';
+               return;
+       }
+
+       fullname = "catname";
+       if (match_optname(opts, fullname, 3, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
+                       nmcpy(catname, op, PL_PSIZ);
+               return;
+       }
+
+       fullname = "dogname";
+       if (match_optname(opts, fullname, 3, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
+                       nmcpy(dogname, op, PL_PSIZ);
+               return;
+       }
+
+       fullname = "horsename";
+       if (match_optname(opts, fullname, 5, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
+                       nmcpy(horsename, op, PL_PSIZ);
+               return;
+       }
+
+       fullname = "number_pad";
+       if (match_optname(opts, fullname, 10, TRUE)) {
+               boolean compat = (strlen(opts) <= 10);
+               number_pad(iflags.num_pad ? 1 : 0);
+               op = string_for_opt(opts, (compat || !initial));
+               if (!op) {
+                   if (compat || negated || initial) {
+                       /* for backwards compatibility, "number_pad" without a
+                          value is a synonym for number_pad:1 */
+                       iflags.num_pad = !negated;
+                       if (iflags.num_pad) iflags.num_pad_mode = 0;
+                   }
+                   return;
+               }
+               if (negated) {
+                   bad_negation("number_pad", TRUE);
+                   return;
+               }
+               if (*op == '1' || *op == '2') {
+                       iflags.num_pad = 1;
+                       if (*op == '2') iflags.num_pad_mode = 1;
+                       else iflags.num_pad_mode = 0;
+               } else if (*op == '0') {
+                       iflags.num_pad = 0;
+                       iflags.num_pad_mode = 0;
+               } else badoption(opts);
+               return;
+       }
+
+       fullname = "runmode";
+       if (match_optname(opts, fullname, 4, TRUE)) {
+               if (negated) {
+                       iflags.runmode = RUN_TPORT;
+               } else if ((op = string_for_opt(opts, FALSE)) != 0) {
+                   if (!strncmpi(op, "teleport", strlen(op)))
+                       iflags.runmode = RUN_TPORT;
+                   else if (!strncmpi(op, "run", strlen(op)))
+                       iflags.runmode = RUN_LEAP;
+                   else if (!strncmpi(op, "walk", strlen(op)))
+                       iflags.runmode = RUN_STEP;
+                   else if (!strncmpi(op, "crawl", strlen(op)))
+                       iflags.runmode = RUN_CRAWL;
+                   else
+                       badoption(opts);
+               }
+               return;
+       }
+
+       fullname = "msghistory";
+       if (match_optname(opts, fullname, 3, TRUE)) {
+               op = string_for_env_opt(fullname, opts, negated);
+               if ((negated && !op) || (!negated && op)) {
+                       iflags.msg_history = negated ? 0 : atoi(op);
+               } else if (negated) bad_negation(fullname, TRUE);
+               return;
+       }
+
+       fullname="msg_window";
+       /* msg_window:single, combo, full or reversed */
+       if (match_optname(opts, fullname, 4, TRUE)) {
+       /* allow option to be silently ignored by non-tty ports */
+#ifdef TTY_GRAPHICS
+               int tmp;
+               if (!(op = string_for_opt(opts, TRUE))) {
+                   tmp = negated ? 's' : 'f';
+               } else {
+                         if (negated) {
+                               bad_negation(fullname, TRUE);
+                               return;
+                                 }
+                   tmp = tolower(*op);
+               }
+               switch (tmp) {
+                       case 's':       /* single message history cycle (default if negated) */
+                               iflags.prevmsg_window = 's';
+                               break;
+                       case 'c':       /* combination: two singles, then full page reversed */
+                               iflags.prevmsg_window = 'c';
+                               break;
+                       case 'f':       /* full page (default if no opts) */
+                               iflags.prevmsg_window = 'f';
+                               break;
+                       case 'r':       /* full page (reversed) */
+                               iflags.prevmsg_window = 'r';
+                               break;
+                       default:
+                               badoption(opts);
+               }
+#endif
+               return;
+       }
+
+       /* WINCAP
+        * setting font options  */
+       fullname = "font";
+       if (!strncmpi(opts, fullname, 4))
+       {
+               int wintype = -1;
+               char *fontopts = opts + 4;
+
+               if (!strncmpi(fontopts, "map", 3) ||
+                   !strncmpi(fontopts, "_map", 4))
+                       wintype = NHW_MAP;
+               else if (!strncmpi(fontopts, "message", 7) ||
+                        !strncmpi(fontopts, "_message", 8))
+                       wintype = NHW_MESSAGE;
+               else if (!strncmpi(fontopts, "text", 4) ||
+                        !strncmpi(fontopts, "_text", 5))
+                       wintype = NHW_TEXT;                     
+               else if (!strncmpi(fontopts, "menu", 4) ||
+                        !strncmpi(fontopts, "_menu", 5))
+                       wintype = NHW_MENU;
+               else if (!strncmpi(fontopts, "status", 6) ||
+                        !strncmpi(fontopts, "_status", 7))
+                       wintype = NHW_STATUS;
+               else if (!strncmpi(fontopts, "_size", 5)) {
+                       if (!strncmpi(fontopts, "_size_map", 8))
+                               wintype = NHW_MAP;
+                       else if (!strncmpi(fontopts, "_size_message", 12))
+                               wintype = NHW_MESSAGE;
+                       else if (!strncmpi(fontopts, "_size_text", 9))
+                               wintype = NHW_TEXT;
+                       else if (!strncmpi(fontopts, "_size_menu", 9))
+                               wintype = NHW_MENU;
+                       else if (!strncmpi(fontopts, "_size_status", 11))
+                               wintype = NHW_STATUS;
+                       else {
+                               badoption(opts);
+                               return;
+                       }
+                       if (wintype > 0 && !negated &&
+                           (op = string_for_opt(opts, FALSE)) != 0) {
+                           switch(wintype)  {
+                               case NHW_MAP:
+                                       iflags.wc_fontsiz_map = atoi(op);
+                                       break;
+                               case NHW_MESSAGE:
+                                       iflags.wc_fontsiz_message = atoi(op);
+                                       break;
+                               case NHW_TEXT:
+                                       iflags.wc_fontsiz_text = atoi(op);
+                                       break;
+                               case NHW_MENU:
+                                       iflags.wc_fontsiz_menu = atoi(op);
+                                       break;
+                               case NHW_STATUS:
+                                       iflags.wc_fontsiz_status = atoi(op);
+                                       break;
+                           }
+                       }
+                       return;
+               } else {
+                       badoption(opts);
+               }
+               if (wintype > 0 &&
+                   (op = string_for_opt(opts, FALSE)) != 0) {
+                       wc_set_font_name(wintype, op);
+#ifdef MAC
+                       set_font_name (wintype, op);
+#endif
+                       return;
+               } else if (negated) bad_negation(fullname, TRUE);
+               return;
+       }
+#ifdef CHANGE_COLOR
+       if (match_optname(opts, "palette", 3, TRUE)
+# ifdef MAC
+           || match_optname(opts, "hicolor", 3, TRUE)
+# endif
+                                                       ) {
+           int color_number, color_incr;
+
+# ifdef MAC
+           if (match_optname(opts, "hicolor", 3, TRUE)) {
+               if (negated) {
+                   bad_negation("hicolor", FALSE);
+                   return;
+               }
+               color_number = CLR_MAX + 4;     /* HARDCODED inverse number */
+               color_incr = -1;
+           } else {
+# endif
+               if (negated) {
+                   bad_negation("palette", FALSE);
+                   return;
+               }
+               color_number = 0;
+               color_incr = 1;
+# ifdef MAC
+           }
+# endif
+           if ((op = string_for_opt(opts, FALSE)) != (char *)0) {
+               char *pt = op;
+               int cnt, tmp, reverse;
+               long rgb;
+
+               while (*pt && color_number >= 0) {
+                   cnt = 3;
+                   rgb = 0L;
+                   if (*pt == '-') {
+                       reverse = 1;
+                       pt++;
+                   } else {
+                       reverse = 0;
+                   }
+                   while (cnt-- > 0) {
+                       if (*pt && *pt != '/') {
+# ifdef AMIGA
+                           rgb <<= 4;
+# else
+                           rgb <<= 8;
+# endif
+                           tmp = *(pt++);
+                           if (isalpha(tmp)) {
+                               tmp = (tmp + 9) & 0xf;  /* Assumes ASCII... */
+                           } else {
+                               tmp &= 0xf;     /* Digits in ASCII too... */
+                           }
+# ifndef AMIGA
+                           /* Add an extra so we fill f -> ff and 0 -> 00 */
+                           rgb += tmp << 4;
+# endif
+                           rgb += tmp;
+                       }
+                   }
+                   if (*pt == '/') {
+                       pt++;
+                   }
+                   change_color(color_number, rgb, reverse);
+                   color_number += color_incr;
+               }
+           }
+           if (!initial) {
+               need_redraw = TRUE;
+           }
+           return;
+       }
+#endif /* CHANGE_COLOR */
+
+       if (match_optname(opts, "fruit", 2, TRUE)) {
+               char empty_str = '\0';
+               op = string_for_opt(opts, negated);
+               if (negated) {
+                   if (op) {
+                       bad_negation("fruit", TRUE);
+                       return;
+                   }
+                   op = &empty_str;
+                   goto goodfruit;
+               }
+               if (!op) return;
+               if (!initial) {
+                   struct fruit *f;
+
+                   num = 0;
+                   for(f=ffruit; f; f=f->nextf) {
+                       if (!strcmp(op, f->fname)) goto goodfruit;
+                       num++;
+                   }
+                   if (num >= 100) {
+                       pline("Doing that so many times isn't very fruitful.");
+                       return;
+                   }
+               }
+goodfruit:
+               nmcpy(pl_fruit, op, PL_FSIZ);
+       /* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */
+               if (!*pl_fruit)
+                   nmcpy(pl_fruit, "slime mold", PL_FSIZ);
+               if (!initial)
+                   (void)fruitadd(pl_fruit);
+               /* If initial, then initoptions is allowed to do it instead
+                * of here (initoptions always has to do it even if there's
+                * no fruit option at all.  Also, we don't want people
+                * setting multiple fruits in their options.)
+                */
+               return;
+       }
+
+       /* graphics:string */
+       fullname = "graphics";
+       if (match_optname(opts, fullname, 2, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else graphics_opts(opts, fullname, MAXPCHARS, 0);
+               return;
+       }
+       fullname = "dungeon";
+       if (match_optname(opts, fullname, 2, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else graphics_opts(opts, fullname, MAXDCHARS, 0);
+               return;
+       }
+       fullname = "traps";
+       if (match_optname(opts, fullname, 2, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else graphics_opts(opts, fullname, MAXTCHARS, MAXDCHARS);
+               return;
+       }
+       fullname = "effects";
+       if (match_optname(opts, fullname, 2, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else
+                graphics_opts(opts, fullname, MAXECHARS, MAXDCHARS+MAXTCHARS);
+               return;
+       }
+
+       /* objects:string */
+       fullname = "objects";
+       if (match_optname(opts, fullname, 7, TRUE)) {
+               int length;
+
+               if (negated) {
+                   bad_negation(fullname, FALSE);
+                   return;
+               }
+               if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
+                       return;
+               escapes(opts, opts);
+
+               /*
+                * Override the default object class symbols.  The first
+                * object in the object class is the "random object".  I
+                * don't want to use 0 as an object class, so the "random
+                * object" is basically a place holder.
+                *
+                * The object class symbols have already been initialized in
+                * initoptions().
+                */
+               length = strlen(opts);
+               if (length >= MAXOCLASSES)
+                   length = MAXOCLASSES-1;     /* don't count RANDOM_OBJECT */
+
+               for (i = 0; i < length; i++)
+                   oc_syms[i+1] = (uchar) opts[i];
+               return;
+       }
+
+       /* monsters:string */
+       fullname = "monsters";
+       if (match_optname(opts, fullname, 8, TRUE)) {
+               int length;
+
+               if (negated) {
+                   bad_negation(fullname, FALSE);
+                   return;
+               }
+               if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
+                       return;
+               escapes(opts, opts);
+
+               /* Override default mon class symbols set in initoptions(). */
+               length = strlen(opts);
+               if (length >= MAXMCLASSES)
+                   length = MAXMCLASSES-1;     /* mon class 0 unused */
+
+               for (i = 0; i < length; i++)
+                   monsyms[i+1] = (uchar) opts[i];
+               return;
+       }
+       fullname = "warnings";
+       if (match_optname(opts, fullname, 5, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else warning_opts(opts, fullname);
+               return;
+       }
+       /* boulder:symbol */
+       fullname = "boulder";
+       if (match_optname(opts, fullname, 7, TRUE)) {
+               int clash = 0;
+               if (negated) {
+                   bad_negation(fullname, FALSE);
+                   return;
+               }
+/*             if (!(opts = string_for_env_opt(fullname, opts, FALSE))) */
+               if (!(opts = string_for_opt(opts, FALSE)))
+                       return;
+               escapes(opts, opts);
+               if (def_char_to_monclass(opts[0]) != MAXMCLASSES)
+                       clash = 1;
+               else if (opts[0] >= '1' && opts[0] <= '5')
+                       clash = 2;
+               if (clash) {
+                       /* symbol chosen matches a used monster or warning
+                          symbol which is not good - reject it*/
+                       pline(
+                 "Badoption - boulder symbol '%c' conflicts with a %s symbol.",
+                               opts[0], (clash == 1) ? "monster" : "warning");
+               } else {
+                       /*
+                        * Override the default boulder symbol.
+                        */
+                       iflags.bouldersym = (uchar) opts[0];
+               }
+               if (!initial) need_redraw = TRUE;
+               return;
+       }
+
+       /* name:string */
+       fullname = "name";
+       if (match_optname(opts, fullname, 4, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
+                       nmcpy(plname, op, PL_NSIZ);
+               return;
+       }
+
+       /* role:string or character:string */
+       fullname = "role";
+       if (match_optname(opts, fullname, 4, TRUE) ||
+           match_optname(opts, (fullname = "character"), 4, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
+                       if ((flags.initrole = str2role(op)) == ROLE_NONE)
+                               badoption(opts);
+                       else  /* Backwards compatibility */
+                               nmcpy(pl_character, op, PL_NSIZ);
+               }
+               return;
+       }
+
+       /* race:string */
+       fullname = "race";
+       if (match_optname(opts, fullname, 4, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
+                       if ((flags.initrace = str2race(op)) == ROLE_NONE)
+                               badoption(opts);
+                       else /* Backwards compatibility */
+                               pl_race = *op;
+               }
+               return;
+       }
+
+       /* gender:string */
+       fullname = "gender";
+       if (match_optname(opts, fullname, 4, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
+                       if ((flags.initgend = str2gend(op)) == ROLE_NONE)
+                               badoption(opts);
+                       else
+                               flags.female = flags.initgend;
+               }
+               return;
+       }
+
+       /* altkeyhandler:string */
+       fullname = "altkeyhandler";
+       if (match_optname(opts, fullname, 4, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else if ((op = string_for_opt(opts, negated))) {
+#ifdef WIN32CON
+                   (void)strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5);
+                   load_keyboard_handler();
+#endif
+               }
+               return;
+       }
+
+       /* WINCAP
+        * align_status:[left|top|right|bottom] */
+       fullname = "align_status";
+       if (match_optname(opts, fullname, sizeof("align_status")-1, TRUE)) {
+               op = string_for_opt(opts, negated);
+               if (op && !negated) {
+                   if (!strncmpi (op, "left", sizeof("left")-1))
+                       iflags.wc_align_status = ALIGN_LEFT;
+                   else if (!strncmpi (op, "top", sizeof("top")-1))
+                       iflags.wc_align_status = ALIGN_TOP;
+                   else if (!strncmpi (op, "right", sizeof("right")-1))
+                       iflags.wc_align_status = ALIGN_RIGHT;
+                   else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
+                       iflags.wc_align_status = ALIGN_BOTTOM;
+                   else
+                       badoption(opts);
+               } else if (negated) bad_negation(fullname, TRUE);
+               return;
+       }
+       /* WINCAP
+        * align_message:[left|top|right|bottom] */
+       fullname = "align_message";
+       if (match_optname(opts, fullname, sizeof("align_message")-1, TRUE)) {
+               op = string_for_opt(opts, negated);
+               if (op && !negated) {
+                   if (!strncmpi (op, "left", sizeof("left")-1))
+                       iflags.wc_align_message = ALIGN_LEFT;
+                   else if (!strncmpi (op, "top", sizeof("top")-1))
+                       iflags.wc_align_message = ALIGN_TOP;
+                   else if (!strncmpi (op, "right", sizeof("right")-1))
+                       iflags.wc_align_message = ALIGN_RIGHT;
+                   else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
+                       iflags.wc_align_message = ALIGN_BOTTOM;
+                   else
+                       badoption(opts);
+               } else if (negated) bad_negation(fullname, TRUE);
+               return;
+       }
+       /* align:string */
+       fullname = "align";
+       if (match_optname(opts, fullname, sizeof("align")-1, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
+                       if ((flags.initalign = str2align(op)) == ROLE_NONE)
+                               badoption(opts);
+               return;
+       }
+
+       /* the order to list the pack */
+       fullname = "packorder";
+       if (match_optname(opts, fullname, 4, TRUE)) {
+               if (negated) {
+                   bad_negation(fullname, FALSE);
+                   return;
+               } else if (!(op = string_for_opt(opts, FALSE))) return;
+
+               if (!change_inv_order(op))
+                       badoption(opts);
+               return;
+       }
+
+       /* maximum burden picked up before prompt (Warren Cheung) */
+       fullname = "pickup_burden";
+       if (match_optname(opts, fullname, 8, TRUE)) {
+               if (negated) {
+                       bad_negation(fullname, FALSE);
+                       return;
+               } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
+                   switch (tolower(*op)) {
+                               /* Unencumbered */
+                               case 'u':
+                                       flags.pickup_burden = UNENCUMBERED;
+                                       break;
+                               /* Burdened (slight encumbrance) */
+                               case 'b':
+                                       flags.pickup_burden = SLT_ENCUMBER;
+                                       break;
+                               /* streSsed (moderate encumbrance) */
+                               case 's':
+                                       flags.pickup_burden = MOD_ENCUMBER;
+                                       break;
+                               /* straiNed (heavy encumbrance) */
+                               case 'n':
+                                       flags.pickup_burden = HVY_ENCUMBER;
+                                       break;
+                               /* OverTaxed (extreme encumbrance) */
+                               case 'o':
+                               case 't':
+                                       flags.pickup_burden = EXT_ENCUMBER;
+                                       break;
+                               /* overLoaded */
+                               case 'l':
+                                       flags.pickup_burden = OVERLOADED;
+                                       break;
+                               default:
+                               badoption(opts);
+                   }
+               }
+               return;
+       }
+
+       /* types of objects to pick up automatically */
+       if (match_optname(opts, "pickup_types", 8, TRUE)) {
+               char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1],
+                    qbuf[QBUFSZ], abuf[BUFSZ];
+               int oc_sym;
+               boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu;
+
+               oc_to_str(flags.pickup_types, tbuf);
+               flags.pickup_types[0] = '\0';   /* all */
+               op = string_for_opt(opts, (compat || !initial));
+               if (!op) {
+                   if (compat || negated || initial) {
+                       /* for backwards compatibility, "pickup" without a
+                          value is a synonym for autopickup of all types
+                          (and during initialization, we can't prompt yet) */
+                       flags.pickup = !negated;
+                       return;
+                   }
+                   oc_to_str(flags.inv_order, ocl);
+                   use_menu = TRUE;
+                   if (flags.menu_style == MENU_TRADITIONAL ||
+                           flags.menu_style == MENU_COMBINATION) {
+                       use_menu = FALSE;
+                       Sprintf(qbuf, "New pickup_types: [%s am] (%s)",
+                               ocl, *tbuf ? tbuf : "all");
+                       getlin(qbuf, abuf);
+                       op = mungspaces(abuf);
+                       if (abuf[0] == '\0' || abuf[0] == '\033')
+                           op = tbuf;          /* restore */
+                       else if (abuf[0] == 'm')
+                           use_menu = TRUE;
+                   }
+                   if (use_menu) {
+                       (void) choose_classes_menu("Auto-Pickup what?", 1,
+                                                  TRUE, ocl, tbuf);
+                       op = tbuf;
+                   }
+               }
+               if (negated) {
+                   bad_negation("pickup_types", TRUE);
+                   return;
+               }
+               while (*op == ' ') op++;
+               if (*op != 'a' && *op != 'A') {
+                   num = 0;
+                   while (*op) {
+                       oc_sym = def_char_to_objclass(*op);
+                       /* make sure all are valid obj symbols occuring once */
+                       if (oc_sym != MAXOCLASSES &&
+                           !index(flags.pickup_types, oc_sym)) {
+                           flags.pickup_types[num] = (char)oc_sym;
+                           flags.pickup_types[++num] = '\0';
+                       } else
+                           badopt = TRUE;
+                       op++;
+                   }
+                   if (badopt) badoption(opts);
+               }
+               return;
+       }
+       /* WINCAP
+        * player_selection: dialog | prompts */
+       fullname = "player_selection";
+       if (match_optname(opts, fullname, sizeof("player_selection")-1, TRUE)) {
+               op = string_for_opt(opts, negated);
+               if (op && !negated) {
+                   if (!strncmpi (op, "dialog", sizeof("dialog")-1))
+                       iflags.wc_player_selection = VIA_DIALOG;
+                   else if (!strncmpi (op, "prompt", sizeof("prompt")-1))
+                       iflags.wc_player_selection = VIA_PROMPTS;
+                   else
+                       badoption(opts);
+               } else if (negated) bad_negation(fullname, TRUE);
+               return;
+       }
+
+       /* things to disclose at end of game */
+       if (match_optname(opts, "disclose", 7, TRUE)) {
+               /*
+                * The order that the end_disclore options are stored:
+                * inventory, attribs, vanquished, genocided, conduct
+                * There is an array in flags:
+                *      end_disclose[NUM_DISCLOSURE_OPT];
+                * with option settings for the each of the following:
+                * iagvc [see disclosure_options in decl.c]:
+                * Legal setting values in that array are:
+                *      DISCLOSE_PROMPT_DEFAULT_YES  ask with default answer yes
+                *      DISCLOSE_PROMPT_DEFAULT_NO   ask with default answer no
+                *      DISCLOSE_YES_WITHOUT_PROMPT  always disclose and don't ask
+                *      DISCLOSE_NO_WITHOUT_PROMPT   never disclose and don't ask
+                *
+                * Those setting values can be used in the option
+                * string as a prefix to get the desired behaviour.
+                *
+                * For backward compatibility, no prefix is required,
+                * and the presence of a i,a,g,v, or c without a prefix
+                * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
+                */
+               boolean badopt = FALSE;
+               int idx, prefix_val;
+
+               op = string_for_opt(opts, TRUE);
+               if (op && negated) {
+                       bad_negation("disclose", TRUE);
+                       return;
+               }
+               /* "disclose" without a value means "all with prompting"
+                  and negated means "none without prompting" */
+               if (!op || !strcmpi(op, "all") || !strcmpi(op, "none")) {
+                       if (op && !strcmpi(op, "none")) negated = TRUE;
+                       for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++)
+                           flags.end_disclose[num] = negated ?
+                                               DISCLOSE_NO_WITHOUT_PROMPT :
+                                               DISCLOSE_PROMPT_DEFAULT_YES;
+                       return;
+               }
+
+               num = 0;
+               prefix_val = -1;
+               while (*op && num < sizeof flags.end_disclose - 1) {
+                       register char c, *dop;
+                       static char valid_settings[] = {
+                               DISCLOSE_PROMPT_DEFAULT_YES,
+                               DISCLOSE_PROMPT_DEFAULT_NO,
+                               DISCLOSE_YES_WITHOUT_PROMPT,
+                               DISCLOSE_NO_WITHOUT_PROMPT,
+                               '\0'
+                       };
+                       c = lowc(*op);
+                       if (c == 'k') c = 'v';  /* killed -> vanquished */
+                       dop = index(disclosure_options, c);
+                       if (dop) {
+                               idx = dop - disclosure_options;
+                               if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) {
+                                   impossible("bad disclosure index %d %c",
+                                                       idx, c);
+                                   continue;
+                               }
+                               if (prefix_val != -1) {
+                                   flags.end_disclose[idx] = prefix_val;
+                                   prefix_val = -1;
+                               } else
+                                   flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT;
+                       } else if (index(valid_settings, c)) {
+                               prefix_val = c;
+                       } else if (c == ' ') {
+                               /* do nothing */
+                       } else
+                               badopt = TRUE;                          
+                       op++;
+               }
+               if (badopt) badoption(opts);
+               return;
+       }
+
+       /* scores:5t[op] 5a[round] o[wn] */
+       if (match_optname(opts, "scores", 4, TRUE)) {
+           if (negated) {
+               bad_negation("scores", FALSE);
+               return;
+           }
+           if (!(op = string_for_opt(opts, FALSE))) return;
+
+           while (*op) {
+               int inum = 1;
+
+               if (digit(*op)) {
+                   inum = atoi(op);
+                   while (digit(*op)) op++;
+               } else if (*op == '!') {
+                   negated = !negated;
+                   op++;
+               }
+               while (*op == ' ') op++;
+
+               switch (*op) {
+                case 't':
+                case 'T':  flags.end_top = inum;
+                           break;
+                case 'a':
+                case 'A':  flags.end_around = inum;
+                           break;
+                case 'o':
+                case 'O':  flags.end_own = !negated;
+                           break;
+                default:   badoption(opts);
+                           return;
+               }
+               while (letter(*++op) || *op == ' ') continue;
+               if (*op == '/') op++;
+           }
+           return;
+       }
+
+       fullname = "suppress_alert";
+       if (match_optname(opts, fullname, 4, TRUE)) {
+               op = string_for_opt(opts, negated);
+               if (negated) bad_negation(fullname, FALSE);
+               else if (op) (void) feature_alert_opts(op,fullname);
+               return;
+       }
+       
+#ifdef VIDEOSHADES
+       /* videocolors:string */
+       fullname = "videocolors";
+       if (match_optname(opts, fullname, 6, TRUE) ||
+           match_optname(opts, "videocolours", 10, TRUE)) {
+               if (negated) {
+                       bad_negation(fullname, FALSE);
+                       return;
+               }
+               else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
+                       return;
+               }
+               if (!assign_videocolors(opts))
+                       badoption(opts);
+               return;
+       }
+       /* videoshades:string */
+       fullname = "videoshades";
+       if (match_optname(opts, fullname, 6, TRUE)) {
+               if (negated) {
+                       bad_negation(fullname, FALSE);
+                       return;
+               }
+               else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
+                       return;
+               }
+               if (!assign_videoshades(opts))
+                       badoption(opts);
+               return;
+       }
+#endif /* VIDEOSHADES */
+#ifdef MSDOS
+# ifdef NO_TERMS
+       /* video:string -- must be after longer tests */
+       fullname = "video";
+       if (match_optname(opts, fullname, 5, TRUE)) {
+               if (negated) {
+                       bad_negation(fullname, FALSE);
+                       return;
+               }
+               else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
+                       return;
+               }
+               if (!assign_video(opts))
+                       badoption(opts);
+               return;
+       }
+# endif /* NO_TERMS */
+       /* soundcard:string -- careful not to match boolean 'sound' */
+       fullname = "soundcard";
+       if (match_optname(opts, fullname, 6, TRUE)) {
+               if (negated) {
+                       bad_negation(fullname, FALSE);
+                       return;
+               }
+               else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
+                       return;
+               }
+               if (!assign_soundcard(opts))
+                       badoption(opts);
+               return;
+       }
+#endif /* MSDOS */
+
+       /* WINCAP
+        * map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|ascii8x12|
+                       ascii16x12|ascii12x16|ascii10x18|fit_to_screen] */
+       fullname = "map_mode";
+       if (match_optname(opts, fullname, sizeof("map_mode")-1, TRUE)) {
+               op = string_for_opt(opts, negated);
+               if (op && !negated) {
+                   if (!strncmpi (op, "tiles", sizeof("tiles")-1))
+                       iflags.wc_map_mode = MAP_MODE_TILES;
+                   else if (!strncmpi (op, "ascii4x6", sizeof("ascii4x6")-1))
+                       iflags.wc_map_mode = MAP_MODE_ASCII4x6;
+                   else if (!strncmpi (op, "ascii6x8", sizeof("ascii6x8")-1))
+                       iflags.wc_map_mode = MAP_MODE_ASCII6x8;
+                   else if (!strncmpi (op, "ascii8x8", sizeof("ascii8x8")-1))
+                       iflags.wc_map_mode = MAP_MODE_ASCII8x8;
+                   else if (!strncmpi (op, "ascii16x8", sizeof("ascii16x8")-1))
+                       iflags.wc_map_mode = MAP_MODE_ASCII16x8;
+                   else if (!strncmpi (op, "ascii7x12", sizeof("ascii7x12")-1))
+                       iflags.wc_map_mode = MAP_MODE_ASCII7x12;
+                   else if (!strncmpi (op, "ascii8x12", sizeof("ascii8x12")-1))
+                       iflags.wc_map_mode = MAP_MODE_ASCII8x12;
+                   else if (!strncmpi (op, "ascii16x12", sizeof("ascii16x12")-1))
+                       iflags.wc_map_mode = MAP_MODE_ASCII16x12;
+                   else if (!strncmpi (op, "ascii12x16", sizeof("ascii12x16")-1))
+                       iflags.wc_map_mode = MAP_MODE_ASCII12x16;
+                   else if (!strncmpi (op, "ascii10x18", sizeof("ascii10x18")-1))
+                       iflags.wc_map_mode = MAP_MODE_ASCII10x18;
+                   else if (!strncmpi (op, "fit_to_screen", sizeof("fit_to_screen")-1))
+                       iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
+                   else
+                       badoption(opts);
+               } else if (negated) bad_negation(fullname, TRUE);
+               return;
+       }
+       /* WINCAP
+        * scroll_amount:nn */
+       fullname = "scroll_amount";
+       if (match_optname(opts, fullname, sizeof("scroll_amount")-1, TRUE)) {
+               op = string_for_opt(opts, negated);
+               if ((negated && !op) || (!negated && op)) {
+                       iflags.wc_scroll_amount = negated ? 1 : atoi(op);
+               } else if (negated) bad_negation(fullname, TRUE);
+               return;
+       }
+       /* WINCAP
+        * scroll_margin:nn */
+       fullname = "scroll_margin";
+       if (match_optname(opts, fullname, sizeof("scroll_margin")-1, TRUE)) {
+               op = string_for_opt(opts, negated);
+               if ((negated && !op) || (!negated && op)) {
+                       iflags.wc_scroll_margin = negated ? 5 : atoi(op);
+               } else if (negated) bad_negation(fullname, TRUE);
+               return;
+       }
+       fullname = "subkeyvalue";
+       if (match_optname(opts, fullname, 5, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else {
+#if defined(WIN32CON)
+                       op = string_for_opt(opts, 0);
+                       map_subkeyvalue(op);
+#endif
+               }
+               return;
+       }
+       /* WINCAP
+        * tile_width:nn */
+       fullname = "tile_width";
+       if (match_optname(opts, fullname, sizeof("tile_width")-1, TRUE)) {
+               op = string_for_opt(opts, negated);
+               if ((negated && !op) || (!negated && op)) {
+                       iflags.wc_tile_width = negated ? 0 : atoi(op);
+               } else if (negated) bad_negation(fullname, TRUE);
+               return;
+       }
+       /* WINCAP
+        * tile_file:name */
+       fullname = "tile_file";
+       if (match_optname(opts, fullname, sizeof("tile_file")-1, TRUE)) {
+               if ((op = string_for_opt(opts, FALSE)) != 0) {
+                       if (iflags.wc_tile_file) free(iflags.wc_tile_file);
+                       iflags.wc_tile_file = (char *)alloc(strlen(op) + 1);
+                       Strcpy(iflags.wc_tile_file, op);
+               }
+               return;
+       }
+       /* WINCAP
+        * tile_height:nn */
+       fullname = "tile_height";
+       if (match_optname(opts, fullname, sizeof("tile_height")-1, TRUE)) {
+               op = string_for_opt(opts, negated);
+               if ((negated && !op) || (!negated && op)) {
+                       iflags.wc_tile_height = negated ? 0 : atoi(op);
+               } else if (negated) bad_negation(fullname, TRUE);
+               return;
+       }
+       /* WINCAP
+        * vary_msgcount:nn */
+       fullname = "vary_msgcount";
+       if (match_optname(opts, fullname, sizeof("vary_msgcount")-1, TRUE)) {
+               op = string_for_opt(opts, negated);
+               if ((negated && !op) || (!negated && op)) {
+                       iflags.wc_vary_msgcount = negated ? 0 : atoi(op);
+               } else if (negated) bad_negation(fullname, TRUE);
+               return;
+       }
+       fullname = "windowtype";
+       if (match_optname(opts, fullname, 3, TRUE)) {
+           if (negated) {
+               bad_negation(fullname, FALSE);
+               return;
+           } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
+               char buf[WINTYPELEN];
+               nmcpy(buf, op, WINTYPELEN);
+               choose_windows(buf);
+           }
+           return;
+       }
+
+       /* WINCAP
+        * setting window colors
+         * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
+         */
+       fullname = "windowcolors";
+       if (match_optname(opts, fullname, 7, TRUE)) {
+               if ((op = string_for_opt(opts, FALSE)) != 0) {
+                       if (!wc_set_window_colors(op))
+                               badoption(opts);
+               } else if (negated) bad_negation(fullname, TRUE);
+               return;
+       }
+
+       /* menustyle:traditional or combo or full or partial */
+       if (match_optname(opts, "menustyle", 4, TRUE)) {
+               int tmp;
+               boolean val_required = (strlen(opts) > 5 && !negated);
+
+               if (!(op = string_for_opt(opts, !val_required))) {
+                   if (val_required) return; /* string_for_opt gave feedback */
+                   tmp = negated ? 'n' : 'f';
+               } else {
+                   tmp = tolower(*op);
+               }
+               switch (tmp) {
+                       case 'n':       /* none */
+                       case 't':       /* traditional */
+                               flags.menu_style = MENU_TRADITIONAL;
+                               break;
+                       case 'c':       /* combo: trad.class sel+menu */
+                               flags.menu_style = MENU_COMBINATION;
+                               break;
+                       case 'p':       /* partial: no class menu */
+                               flags.menu_style = MENU_PARTIAL;
+                               break;
+                       case 'f':       /* full: class menu + menu */
+                               flags.menu_style = MENU_FULL;
+                               break;
+                       default:
+                               badoption(opts);
+               }
+               return;
+       }
+
+       fullname = "menu_headings";
+       if (match_optname(opts, fullname, 12, TRUE)) {
+               if (negated) {
+                       bad_negation(fullname, FALSE);
+                       return;
+               }
+               else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
+                       return;
+               }
+               if (!strcmpi(opts,"bold"))
+                       iflags.menu_headings = ATR_BOLD;
+               else if (!strcmpi(opts,"inverse"))
+                       iflags.menu_headings = ATR_INVERSE;
+               else if (!strcmpi(opts,"underline"))
+                       iflags.menu_headings = ATR_ULINE;
+               else
+                       badoption(opts);
+               return;
+       }
+
+       /* check for menu command mapping */
+       for (i = 0; i < NUM_MENU_CMDS; i++) {
+           fullname = default_menu_cmd_info[i].name;
+           if (match_optname(opts, fullname, (int)strlen(fullname), TRUE)) {
+               if (negated)
+                   bad_negation(fullname, FALSE);
+               else if ((op = string_for_opt(opts, FALSE)) != 0) {
+                   int j;
+                   char c, op_buf[BUFSZ];
+                   boolean isbad = FALSE;
+
+                   escapes(op, op_buf);
+                   c = *op_buf;
+
+                   if (c == 0 || c == '\r' || c == '\n' || c == '\033' ||
+                           c == ' ' || digit(c) || (letter(c) && c != '@'))
+                       isbad = TRUE;
+                   else        /* reject default object class symbols */
+                       for (j = 1; j < MAXOCLASSES; j++)
+                           if (c == def_oc_syms[i]) {
+                               isbad = TRUE;
+                               break;
+                           }
+
+                   if (isbad)
+                       badoption(opts);
+                   else
+                       add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd);
+               }
+               return;
+           }
+       }
+
+       /* OK, if we still haven't recognized the option, check the boolean
+        * options list
+        */
+       for (i = 0; boolopt[i].name; i++) {
+               if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
+                       /* options that don't exist */
+                       if (!boolopt[i].addr) {
+                           if (!initial && !negated)
+                               pline_The("\"%s\" option is not available.",
+                                       boolopt[i].name);
+                           return;
+                       }
+                       /* options that must come from config file */
+                       if (!initial && (boolopt[i].optflags == SET_IN_FILE)) {
+                           rejectoption(boolopt[i].name);
+                           return;
+                       }
+
+                       *(boolopt[i].addr) = !negated;
+
+                       duplicate_opt_detection(boolopt[i].name, 0);
+
+#if defined(TERMLIB) || defined(ASCIIGRAPH) || defined(MAC_GRAPHICS_ENV)
+                       if (FALSE
+# ifdef TERMLIB
+                                || (boolopt[i].addr) == &iflags.DECgraphics
+# endif
+# ifdef ASCIIGRAPH
+                                || (boolopt[i].addr) == &iflags.IBMgraphics
+# endif
+# ifdef MAC_GRAPHICS_ENV
+                                || (boolopt[i].addr) == &iflags.MACgraphics
+# endif
+                               ) {
+# ifdef REINCARNATION
+                           if (!initial && Is_rogue_level(&u.uz))
+                               assign_rogue_graphics(FALSE);
+# endif
+                           need_redraw = TRUE;
+# ifdef TERMLIB
+                           if ((boolopt[i].addr) == &iflags.DECgraphics)
+                               switch_graphics(iflags.DECgraphics ?
+                                               DEC_GRAPHICS : ASCII_GRAPHICS);
+# endif
+# ifdef ASCIIGRAPH
+                           if ((boolopt[i].addr) == &iflags.IBMgraphics)
+                               switch_graphics(iflags.IBMgraphics ?
+                                               IBM_GRAPHICS : ASCII_GRAPHICS);
+# endif
+# ifdef MAC_GRAPHICS_ENV
+                           if ((boolopt[i].addr) == &iflags.MACgraphics)
+                               switch_graphics(iflags.MACgraphics ?
+                                               MAC_GRAPHICS : ASCII_GRAPHICS);
+# endif
+# ifdef REINCARNATION
+                           if (!initial && Is_rogue_level(&u.uz))
+                               assign_rogue_graphics(TRUE);
+# endif
+                       }
+#endif /* TERMLIB || ASCIIGRAPH || MAC_GRAPHICS_ENV */
+
+                       /* only do processing below if setting with doset() */
+                       if (initial) return;
+
+                       if ((boolopt[i].addr) == &flags.time
+#ifdef EXP_ON_BOTL
+                        || (boolopt[i].addr) == &flags.showexp
+#endif
+#ifdef SCORE_ON_BOTL
+                        || (boolopt[i].addr) == &flags.showscore
+#endif
+                           )
+                           flags.botl = TRUE;
+
+                       else if ((boolopt[i].addr) == &flags.invlet_constant) {
+                           if (flags.invlet_constant) reassign();
+                       }
+#ifdef LAN_MAIL
+                       else if ((boolopt[i].addr) == &flags.biff) {
+                           if (flags.biff) lan_mail_init();
+                           else lan_mail_finish();
+                       }
+#endif
+                       else if ((boolopt[i].addr) == &flags.lit_corridor) {
+                           /*
+                            * All corridor squares seen via night vision or
+                            * candles & lamps change.  Update them by calling
+                            * newsym() on them.  Don't do this if we are
+                            * initializing the options --- the vision system
+                            * isn't set up yet.
+                            */
+                           vision_recalc(2);           /* shut down vision */
+                           vision_full_recalc = 1;     /* delayed recalc */
+                       }
+                       else if ((boolopt[i].addr) == &iflags.use_inverse ||
+                                       (boolopt[i].addr) == &iflags.showrace ||
+                                       (boolopt[i].addr) == &iflags.hilite_pet) {
+                           need_redraw = TRUE;
+                       }
+#ifdef TEXTCOLOR
+                       else if ((boolopt[i].addr) == &iflags.use_color) {
+                           need_redraw = TRUE;
+# ifdef TOS
+                           if ((boolopt[i].addr) == &iflags.use_color
+                               && iflags.BIOS) {
+                               if (colors_changed)
+                                   restore_colors();
+                               else
+                                   set_colors();
+                           }
+# endif
+                       }
+#endif
+
+                       return;
+               }
+       }
+
+       /* out of valid options */
+       badoption(opts);
+}
+
+
+static NEARDATA const char *menutype[] = {
+       "traditional", "combination", "partial", "full"
+};
+
+static NEARDATA const char *burdentype[] = {
+       "unencumbered", "burdened", "stressed",
+       "strained", "overtaxed", "overloaded"
+};
+
+static NEARDATA const char *runmodes[] = {
+       "teleport", "run", "walk", "crawl"
+};
+
+/*
+ * Convert the given string of object classes to a string of default object
+ * symbols.
+ */
+STATIC_OVL void
+oc_to_str(src,dest)
+    char *src, *dest;
+{
+    int i;
+
+    while ((i = (int) *src++) != 0) {
+       if (i < 0 || i >= MAXOCLASSES)
+           impossible("oc_to_str:  illegal object class %d", i);
+       else
+           *dest++ = def_oc_syms[i];
+    }
+    *dest = '\0';
+}
+
+/*
+ * Add the given mapping to the menu command map list.  Always keep the
+ * maps valid C strings.
+ */
+void
+add_menu_cmd_alias(from_ch, to_ch)
+    char from_ch, to_ch;
+{
+    if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS)
+       pline("out of menu map space.");
+    else {
+       mapped_menu_cmds[n_menu_mapped] = from_ch;
+       mapped_menu_op[n_menu_mapped] = to_ch;
+       n_menu_mapped++;
+       mapped_menu_cmds[n_menu_mapped] = 0;
+       mapped_menu_op[n_menu_mapped] = 0;
+    }
+}
+
+/*
+ * Map the given character to its corresponding menu command.  If it
+ * doesn't match anything, just return the original.
+ */
+char
+map_menu_cmd(ch)
+    char ch;
+{
+    char *found = index(mapped_menu_cmds, ch);
+    if (found) {
+       int idx = found - mapped_menu_cmds;
+       ch = mapped_menu_op[idx];
+    }
+    return ch;
+}
+
+
+#if defined(MICRO) || defined(MAC) || defined(WIN32)
+# define OPTIONS_HEADING "OPTIONS"
+#else
+# define OPTIONS_HEADING "NETHACKOPTIONS"
+#endif
+
+static char fmtstr_doset_add_menu[] = "%s%-15s [%s]   "; 
+static char fmtstr_doset_add_menu_tab[] = "%s\t[%s]";
+
+STATIC_OVL void
+doset_add_menu(win, option, indexoffset)
+    winid win;                 /* window to add to */
+    const char *option;                /* option name */
+    int indexoffset;           /* value to add to index in compopt[], or zero
+                                  if option cannot be changed */
+{
+    const char *value = "unknown";             /* current value */
+    char buf[BUFSZ], buf2[BUFSZ];
+    anything any;
+    int i;
+
+    any.a_void = 0;
+    if (indexoffset == 0) {
+       any.a_int = 0;
+       value = get_compopt_value(option, buf2);
+    } else {
+       for (i=0; compopt[i].name; i++)
+           if (strcmp(option, compopt[i].name) == 0) break;
+
+       if (compopt[i].name) {
+           any.a_int = i + 1 + indexoffset;
+           value = get_compopt_value(option, buf2);
+       } else {
+           /* We are trying to add an option not found in compopt[].
+              This is almost certainly bad, but we'll let it through anyway
+              (with a zero value, so it can't be selected). */
+           any.a_int = 0;
+       }
+    }
+    /* "    " replaces "a - " -- assumes menus follow that style */
+    if (!iflags.menu_tab_sep)
+       Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : "    ", option, value);
+    else
+       Sprintf(buf, fmtstr_doset_add_menu_tab, option, value);
+    add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
+}
+
+/* Changing options via menu by Per Liboriussen */
+int
+doset()
+{
+       char buf[BUFSZ], buf2[BUFSZ];
+       int i, pass, boolcount, pick_cnt, pick_idx, opt_indx;
+       boolean *bool_p;
+       winid tmpwin;
+       anything any;
+       menu_item *pick_list;
+       int indexoffset, startpass, endpass;
+       boolean setinitial = FALSE, fromfile = FALSE;
+       int biggest_name = 0;
+
+       tmpwin = create_nhwindow(NHW_MENU);
+       start_menu(tmpwin);
+
+       any.a_void = 0;
+ add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
+                "Booleans (selecting will toggle value):", MENU_UNSELECTED);
+       any.a_int = 0;
+       /* first list any other non-modifiable booleans, then modifiable ones */
+       for (pass = 0; pass <= 1; pass++)
+           for (i = 0; boolopt[i].name; i++)
+               if ((bool_p = boolopt[i].addr) != 0 &&
+                       ((boolopt[i].optflags == DISP_IN_GAME && pass == 0) ||
+                        (boolopt[i].optflags == SET_IN_GAME && pass == 1))) {
+                   if (bool_p == &flags.female) continue;  /* obsolete */
+#ifdef WIZARD
+                   if (bool_p == &iflags.sanity_check && !wizard) continue;
+                   if (bool_p == &iflags.menu_tab_sep && !wizard) continue;
+#endif
+                   if (is_wc_option(boolopt[i].name) &&
+                       !wc_supported(boolopt[i].name)) continue;
+                   if (is_wc2_option(boolopt[i].name) &&
+                       !wc2_supported(boolopt[i].name)) continue;
+                   any.a_int = (pass == 0) ? 0 : i + 1;
+                   if (!iflags.menu_tab_sep)
+                       Sprintf(buf, "%s%-13s [%s]",
+                           pass == 0 ? "    " : "",
+                           boolopt[i].name, *bool_p ? "true" : "false");
+                   else
+                       Sprintf(buf, "%s\t[%s]",
+                           boolopt[i].name, *bool_p ? "true" : "false");
+                   add_menu(tmpwin, NO_GLYPH, &any, 0, 0,
+                            ATR_NONE, buf, MENU_UNSELECTED);
+               }
+
+       boolcount = i;
+       indexoffset = boolcount;
+       any.a_void = 0;
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
+ add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
+                "Compounds (selecting will prompt for new value):",
+                MENU_UNSELECTED);
+
+       startpass = DISP_IN_GAME;
+       endpass = SET_IN_GAME;
+
+       /* spin through the options to find the biggest name
+           and adjust the format string accordingly if needed */
+       biggest_name = 0;
+       for (i = 0; compopt[i].name; i++)
+               if (compopt[i].optflags >= startpass && compopt[i].optflags <= endpass &&
+                   strlen(compopt[i].name) > (unsigned) biggest_name)
+                       biggest_name = (int) strlen(compopt[i].name);
+       if (biggest_name > 30) biggest_name = 30;
+       if (!iflags.menu_tab_sep)
+               Sprintf(fmtstr_doset_add_menu, "%%s%%-%ds [%%s]", biggest_name);
+       
+       /* deliberately put `name', `role', `race', `gender' first */
+       doset_add_menu(tmpwin, "name", 0);
+       doset_add_menu(tmpwin, "role", 0);
+       doset_add_menu(tmpwin, "race", 0);
+       doset_add_menu(tmpwin, "gender", 0);
+
+       for (pass = startpass; pass <= endpass; pass++) 
+           for (i = 0; compopt[i].name; i++)
+               if (compopt[i].optflags == pass) {
+                       if (!strcmp(compopt[i].name, "name") ||
+                           !strcmp(compopt[i].name, "role") ||
+                           !strcmp(compopt[i].name, "race") ||
+                           !strcmp(compopt[i].name, "gender"))
+                               continue;
+                       else if (is_wc_option(compopt[i].name) &&
+                                       !wc_supported(compopt[i].name))
+                               continue;
+                       else if (is_wc2_option(compopt[i].name) &&
+                                       !wc2_supported(compopt[i].name))
+                               continue;
+                       else
+                               doset_add_menu(tmpwin, compopt[i].name,
+                                       (pass == DISP_IN_GAME) ? 0 : indexoffset);
+               }
+#ifdef AUTOPICKUP_EXCEPTIONS
+       any.a_int = -1;
+       Sprintf(buf, "autopickup exceptions (%d currently set)",
+               count_ape_maps((int *)0, (int *)0));
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
+
+#endif /* AUTOPICKUP_EXCEPTIONS */
+#ifdef PREFIXES_IN_USE
+       any.a_void = 0;
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
+                "Variable playground locations:", MENU_UNSELECTED);
+       for (i = 0; i < PREFIX_COUNT; i++)
+               doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
+#endif
+       end_menu(tmpwin, "Set what options?");
+       need_redraw = FALSE;
+       if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) {
+           /*
+            * Walk down the selection list and either invert the booleans
+            * or prompt for new values. In most cases, call parseoptions()
+            * to take care of options that require special attention, like
+            * redraws.
+            */
+           for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
+               opt_indx = pick_list[pick_idx].item.a_int - 1;
+#ifdef AUTOPICKUP_EXCEPTIONS
+               if (opt_indx == -2) {
+                   special_handling("autopickup_exception",
+                                       setinitial, fromfile);
+               } else
+#endif
+               if (opt_indx < boolcount) {
+                   /* boolean option */
+                   Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",
+                           boolopt[opt_indx].name);
+                   parseoptions(buf, setinitial, fromfile);
+                   if (wc_supported(boolopt[opt_indx].name) ||
+                       wc2_supported(boolopt[opt_indx].name))
+                       preference_update(boolopt[opt_indx].name);
+               } else {
+                   /* compound option */
+                   opt_indx -= boolcount;
+
+                   if (!special_handling(compopt[opt_indx].name,
+                                                       setinitial, fromfile)) {
+                       Sprintf(buf, "Set %s to what?", compopt[opt_indx].name);
+                       getlin(buf, buf2);
+                       if (buf2[0] == '\033')
+                           continue;
+                       Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2);
+                       /* pass the buck */
+                       parseoptions(buf, setinitial, fromfile);
+                   }
+                   if (wc_supported(compopt[opt_indx].name) ||
+                       wc2_supported(compopt[opt_indx].name))
+                       preference_update(compopt[opt_indx].name);
+               }
+           }
+           free((genericptr_t)pick_list);
+           pick_list = (menu_item *)0;
+       }
+
+       destroy_nhwindow(tmpwin);
+       if (need_redraw)
+           (void) doredraw();
+       return 0;
+}
+
+STATIC_OVL boolean
+special_handling(optname, setinitial, setfromfile)
+const char *optname;
+boolean setinitial,setfromfile;
+{
+    winid tmpwin;
+    anything any;
+    int i;
+    char buf[BUFSZ];
+    boolean retval = FALSE;
+    
+    /* Special handling of menustyle, pickup_burden, pickup_types,
+     * disclose, runmode, msg_window, menu_headings, and number_pad options.
+#ifdef AUTOPICKUP_EXCEPTIONS
+     * Also takes care of interactive autopickup_exception_handling changes.
+#endif
+     */
+    if (!strcmp("menustyle", optname)) {
+       const char *style_name;
+       menu_item *style_pick = (menu_item *)0;
+        tmpwin = create_nhwindow(NHW_MENU);
+       start_menu(tmpwin);
+       for (i = 0; i < SIZE(menutype); i++) {
+               style_name = menutype[i];
+               /* note: separate `style_name' variable used
+                  to avoid an optimizer bug in VAX C V2.3 */
+               any.a_int = i + 1;
+               add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0,
+                        ATR_NONE, style_name, MENU_UNSELECTED);
+        }
+       end_menu(tmpwin, "Select menustyle:");
+       if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) {
+               flags.menu_style = style_pick->item.a_int - 1;
+               free((genericptr_t)style_pick);
+        }
+       destroy_nhwindow(tmpwin);
+        retval = TRUE;
+    } else if (!strcmp("pickup_burden", optname)) {
+       const char *burden_name, *burden_letters = "ubsntl";
+       menu_item *burden_pick = (menu_item *)0;
+        tmpwin = create_nhwindow(NHW_MENU);
+       start_menu(tmpwin);
+       for (i = 0; i < SIZE(burdentype); i++) {
+               burden_name = burdentype[i];
+               any.a_int = i + 1;
+               add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0,
+                        ATR_NONE, burden_name, MENU_UNSELECTED);
+        }
+       end_menu(tmpwin, "Select encumbrance level:");
+       if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) {
+               flags.pickup_burden = burden_pick->item.a_int - 1;
+               free((genericptr_t)burden_pick);
+       }
+       destroy_nhwindow(tmpwin);
+       retval = TRUE;
+    } else if (!strcmp("pickup_types", optname)) {
+       /* parseoptions will prompt for the list of types */
+       parseoptions(strcpy(buf, "pickup_types"), setinitial, setfromfile);
+       retval = TRUE;
+    } else if (!strcmp("disclose", optname)) {
+       int pick_cnt, pick_idx, opt_idx;
+       menu_item *disclosure_category_pick = (menu_item *)0;
+       /*
+        * The order of disclose_names[]
+         * must correspond to disclosure_options in decl.h
+         */
+       static const char *disclosure_names[] = {
+               "inventory", "attributes", "vanquished", "genocides", "conduct"
+       };
+       int disc_cat[NUM_DISCLOSURE_OPTIONS];
+       const char *disclosure_name;
+
+        tmpwin = create_nhwindow(NHW_MENU);
+       start_menu(tmpwin);
+       for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
+               disclosure_name = disclosure_names[i];
+               any.a_int = i + 1;
+               add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0,
+                        ATR_NONE, disclosure_name, MENU_UNSELECTED);
+               disc_cat[i] = 0;
+        }
+       end_menu(tmpwin, "Change which disclosure options categories:");
+       if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_category_pick)) > 0) {
+           for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
+               opt_idx = disclosure_category_pick[pick_idx].item.a_int - 1;
+               disc_cat[opt_idx] = 1;
+           }
+           free((genericptr_t)disclosure_category_pick);
+           disclosure_category_pick = (menu_item *)0;
+       }
+       destroy_nhwindow(tmpwin);
+
+       for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
+           if (disc_cat[i]) {
+               char dbuf[BUFSZ];
+               menu_item *disclosure_option_pick = (menu_item *)0;
+               Sprintf(dbuf, "Disclosure options for %s:", disclosure_names[i]);
+               tmpwin = create_nhwindow(NHW_MENU);
+               start_menu(tmpwin);
+               any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
+               add_menu(tmpwin, NO_GLYPH, &any, 'a', 0,
+                       ATR_NONE,"Never disclose and don't prompt", MENU_UNSELECTED);
+               any.a_void = 0;
+               any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
+               add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
+                       ATR_NONE,"Always disclose and don't prompt", MENU_UNSELECTED);
+               any.a_void = 0;
+               any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
+               add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
+                       ATR_NONE,"Prompt and default answer to \"No\"", MENU_UNSELECTED);
+               any.a_void = 0;
+               any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
+               add_menu(tmpwin, NO_GLYPH, &any, 'd', 0,
+                       ATR_NONE,"Prompt and default answer to \"Yes\"", MENU_UNSELECTED);
+               end_menu(tmpwin, dbuf);
+               if (select_menu(tmpwin, PICK_ONE, &disclosure_option_pick) > 0) {
+                       flags.end_disclose[i] = disclosure_option_pick->item.a_char;
+                       free((genericptr_t)disclosure_option_pick);
+               }
+               destroy_nhwindow(tmpwin);
+           }
+       }
+       retval = TRUE;
+    } else if (!strcmp("runmode", optname)) {
+       const char *mode_name;
+       menu_item *mode_pick = (menu_item *)0;
+       tmpwin = create_nhwindow(NHW_MENU);
+       start_menu(tmpwin);
+       for (i = 0; i < SIZE(runmodes); i++) {
+               mode_name = runmodes[i];
+               any.a_int = i + 1;
+               add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0,
+                        ATR_NONE, mode_name, MENU_UNSELECTED);
+       }
+       end_menu(tmpwin, "Select run/travel display mode:");
+       if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
+               iflags.runmode = mode_pick->item.a_int - 1;
+               free((genericptr_t)mode_pick);
+       }
+       destroy_nhwindow(tmpwin);
+       retval = TRUE;
+    } 
+#ifdef TTY_GRAPHICS
+      else if (!strcmp("msg_window", optname)) {
+       /* by Christian W. Cooper */
+       menu_item *window_pick = (menu_item *)0;
+       tmpwin = create_nhwindow(NHW_MENU);
+       start_menu(tmpwin);
+       any.a_char = 's';
+       add_menu(tmpwin, NO_GLYPH, &any, 's', 0,
+               ATR_NONE, "single", MENU_UNSELECTED);
+       any.a_char = 'c';
+       add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
+               ATR_NONE, "combination", MENU_UNSELECTED);
+       any.a_char = 'f';
+       add_menu(tmpwin, NO_GLYPH, &any, 'f', 0,
+               ATR_NONE, "full", MENU_UNSELECTED);
+       any.a_char = 'r';
+       add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
+               ATR_NONE, "reversed", MENU_UNSELECTED);
+       end_menu(tmpwin, "Select message history display type:");
+       if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
+               iflags.prevmsg_window = window_pick->item.a_char;
+               free((genericptr_t)window_pick);
+       }
+       destroy_nhwindow(tmpwin);
+        retval = TRUE;
+    }
+#endif
+     else if (!strcmp("align_message", optname) ||
+               !strcmp("align_status", optname)) {
+       menu_item *window_pick = (menu_item *)0;
+       char abuf[BUFSZ];
+       boolean msg = (*(optname+6) == 'm');
+
+       tmpwin = create_nhwindow(NHW_MENU);
+       start_menu(tmpwin);
+       any.a_int = ALIGN_TOP;
+       add_menu(tmpwin, NO_GLYPH, &any, 't', 0,
+               ATR_NONE, "top", MENU_UNSELECTED);
+       any.a_int = ALIGN_BOTTOM;
+       add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
+               ATR_NONE, "bottom", MENU_UNSELECTED);
+       any.a_int = ALIGN_LEFT;
+       add_menu(tmpwin, NO_GLYPH, &any, 'l', 0,
+               ATR_NONE, "left", MENU_UNSELECTED);
+       any.a_int = ALIGN_RIGHT;
+       add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
+               ATR_NONE, "right", MENU_UNSELECTED);
+       Sprintf(abuf, "Select %s window placement relative to the map:",
+               msg ? "message" : "status");
+       end_menu(tmpwin, abuf);
+       if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {          
+               if (msg) iflags.wc_align_message = window_pick->item.a_int;
+               else iflags.wc_align_status = window_pick->item.a_int;
+               free((genericptr_t)window_pick);
+       }
+       destroy_nhwindow(tmpwin);
+        retval = TRUE;
+    } else if (!strcmp("number_pad", optname)) {
+       static const char *npchoices[3] =
+               {"0 (off)", "1 (on)", "2 (on, DOS compatible)"};
+       const char *npletters = "abc";
+       menu_item *mode_pick = (menu_item *)0;
+
+       tmpwin = create_nhwindow(NHW_MENU);
+       start_menu(tmpwin);
+       for (i = 0; i < SIZE(npchoices); i++) {
+               any.a_int = i + 1;
+               add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0,
+                        ATR_NONE, npchoices[i], MENU_UNSELECTED);
+        }
+       end_menu(tmpwin, "Select number_pad mode:");
+       if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
+               int mode = mode_pick->item.a_int - 1;
+               switch(mode) {
+                       case 2:
+                               iflags.num_pad = 1;
+                               iflags.num_pad_mode = 1;
+                               break;
+                       case 1:
+                               iflags.num_pad = 1;
+                               iflags.num_pad_mode = 0;
+                               break;
+                       case 0:
+                       default:
+                               iflags.num_pad = 0;
+                               iflags.num_pad_mode = 0;
+               }
+               free((genericptr_t)mode_pick);
+        }
+       destroy_nhwindow(tmpwin);
+        retval = TRUE;
+    } else if (!strcmp("menu_headings", optname)) {
+       static const char *mhchoices[3] = {"bold", "inverse", "underline"};
+       const char *npletters = "biu";
+       menu_item *mode_pick = (menu_item *)0;
+
+       tmpwin = create_nhwindow(NHW_MENU);
+       start_menu(tmpwin);
+       for (i = 0; i < SIZE(mhchoices); i++) {
+               any.a_int = i + 1;
+               add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0,
+                        ATR_NONE, mhchoices[i], MENU_UNSELECTED);
+        }
+       end_menu(tmpwin, "How to highlight menu headings:");
+       if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
+               int mode = mode_pick->item.a_int - 1;
+               switch(mode) {
+                       case 2:
+                               iflags.menu_headings = ATR_ULINE;
+                               break;
+                       case 0:
+                               iflags.menu_headings = ATR_BOLD;
+                               break;
+                       case 1:
+                       default:
+                               iflags.menu_headings = ATR_INVERSE;
+               }
+               free((genericptr_t)mode_pick);
+        }
+       destroy_nhwindow(tmpwin);
+        retval = TRUE;
+#ifdef AUTOPICKUP_EXCEPTIONS
+    } else if (!strcmp("autopickup_exception", optname)) {
+       boolean retval;
+       int pick_cnt, pick_idx, opt_idx, pass;
+       int totalapes = 0, numapes[2] = {0,0};
+       menu_item *pick_list = (menu_item *)0;
+       anything any;
+       char apebuf[BUFSZ];
+       struct autopickup_exception *ape;
+       static const char *action_titles[] = {
+               "a", "add new autopickup exception",
+               "l", "list autopickup exceptions",
+               "r", "remove existing autopickup exception",
+               "e", "exit this menu",
+       };
+ape_again:
+       opt_idx = 0;
+       totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]);
+       tmpwin = create_nhwindow(NHW_MENU);
+       start_menu(tmpwin);
+       any.a_int = 0;
+       for (i = 0; i < SIZE(action_titles) ; i += 2) {
+               any.a_int++;
+               if (!totalapes && (i >= 2 && i < 6)) continue;
+               add_menu(tmpwin, NO_GLYPH, &any, *action_titles[i],
+                     0, ATR_NONE, action_titles[i+1], MENU_UNSELECTED);
+        }
+       end_menu(tmpwin, "Do what?");
+       if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
+               for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
+                       opt_idx = pick_list[pick_idx].item.a_int - 1;
+               }
+               free((genericptr_t)pick_list);
+               pick_list = (menu_item *)0;
+       }
+       destroy_nhwindow(tmpwin);
+       if (pick_cnt < 1) return FALSE;
+
+       if (opt_idx == 0) {     /* add new */
+               getlin("What new autopickup exception pattern?", &apebuf[1]);
+               if (apebuf[1] == '\033') return FALSE;
+               apebuf[0] = '"';
+               Strcat(apebuf,"\"");
+               add_autopickup_exception(apebuf);
+               goto ape_again;
+       } else if (opt_idx == 3) {
+               retval = TRUE;
+       } else {        /* remove */
+               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];
+                   any.a_void = 0;
+                   add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
+                               (pass == 0) ? "Never pickup" : "Always pickup",
+                               MENU_UNSELECTED);
+                   for (i = 0; i < numapes[pass] && ape; i++) {
+                       any.a_void = (opt_idx == 1) ? 0 : ape;
+                       Sprintf(apebuf, "\"%s\"", ape->pattern);
+                       add_menu(tmpwin, NO_GLYPH, &any,
+                               0, 0, ATR_NONE, apebuf, MENU_UNSELECTED);
+                       ape = ape->next;
+                   }
+               }
+               Sprintf(apebuf, "%s autopickup exceptions",
+                       (opt_idx == 1) ? "List of" : "Remove which");
+               end_menu(tmpwin, apebuf);
+               pick_cnt = select_menu(tmpwin,
+                                       (opt_idx == 1) ?  PICK_NONE : PICK_ANY,
+                                       &pick_list);
+               if (pick_cnt > 0) {
+                   for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
+                       remove_autopickup_exception(
+                        (struct autopickup_exception *)pick_list[pick_idx].item.a_void);
+               }
+               free((genericptr_t)pick_list);
+               pick_list = (menu_item *)0;
+               destroy_nhwindow(tmpwin);
+               goto ape_again;
+       }
+       retval = TRUE;
+#endif /* AUTOPICKUP_EXCEPTIONS */
+    }
+    return retval;
+}
+
+#define rolestring(val,array,field) ((val >= 0) ? array[val].field : \
+                                    (val == ROLE_RANDOM) ? randomrole : none)
+
+/* This is ugly. We have all the option names in the compopt[] array,
+   but we need to look at each option individually to get the value. */
+STATIC_OVL const char *
+get_compopt_value(optname, buf)
+const char *optname;
+char *buf;
+{
+       char ocl[MAXOCLASSES+1];
+       static const char none[] = "(none)", randomrole[] = "random",
+                    to_be_done[] = "(to be done)",
+                    defopt[] = "default",
+                    defbrief[] = "def";
+       int i;
+
+       buf[0] = '\0';
+       if (!strcmp(optname,"align_message"))
+               Sprintf(buf, "%s", iflags.wc_align_message == ALIGN_TOP     ? "top" :
+                                  iflags.wc_align_message == ALIGN_LEFT    ? "left" :
+                                  iflags.wc_align_message == ALIGN_BOTTOM  ? "bottom" :
+                                  iflags.wc_align_message == ALIGN_RIGHT   ? "right" :
+                                  defopt);
+       else if (!strcmp(optname,"align_status"))
+               Sprintf(buf, "%s", iflags.wc_align_status == ALIGN_TOP     ? "top" :
+                                  iflags.wc_align_status == ALIGN_LEFT    ? "left" :
+                                  iflags.wc_align_status == ALIGN_BOTTOM  ? "bottom" :
+                                  iflags.wc_align_status == ALIGN_RIGHT   ? "right" :
+                                  defopt);
+       else if (!strcmp(optname,"align"))
+               Sprintf(buf, "%s", rolestring(flags.initalign, aligns, adj));
+#ifdef WIN32CON
+       else if (!strcmp(optname,"altkeyhandler"))
+               Sprintf(buf, "%s", iflags.altkeyhandler[0] ?
+                       iflags.altkeyhandler : "default");
+#endif
+       else if (!strcmp(optname, "boulder"))
+               Sprintf(buf, "%c", iflags.bouldersym ?
+                       iflags.bouldersym : oc_syms[(int)objects[BOULDER].oc_class]);
+       else if (!strcmp(optname, "catname")) 
+               Sprintf(buf, "%s", catname[0] ? catname : none );
+       else if (!strcmp(optname, "disclose")) {
+               for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
+                       char topt[2];
+                       if (i) Strcat(buf," ");
+                       topt[1] = '\0';
+                       topt[0] = flags.end_disclose[i];
+                       Strcat(buf, topt);
+                       topt[0] = disclosure_options[i];
+                       Strcat(buf, topt);
+               }
+       }
+       else if (!strcmp(optname, "dogname")) 
+               Sprintf(buf, "%s", dogname[0] ? dogname : none );
+       else if (!strcmp(optname, "dungeon"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "effects"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "font_map"))
+               Sprintf(buf, "%s", iflags.wc_font_map ? iflags.wc_font_map : defopt);
+       else if (!strcmp(optname, "font_message"))
+               Sprintf(buf, "%s", iflags.wc_font_message ? iflags.wc_font_message : defopt);
+       else if (!strcmp(optname, "font_status"))
+               Sprintf(buf, "%s", iflags.wc_font_status ? iflags.wc_font_status : defopt);
+       else if (!strcmp(optname, "font_menu"))
+               Sprintf(buf, "%s", iflags.wc_font_menu ? iflags.wc_font_menu : defopt);
+       else if (!strcmp(optname, "font_text"))
+               Sprintf(buf, "%s", iflags.wc_font_text ? iflags.wc_font_text : defopt);
+       else if (!strcmp(optname, "font_size_map")) {
+               if (iflags.wc_fontsiz_map) Sprintf(buf, "%d", iflags.wc_fontsiz_map);
+               else Strcpy(buf, defopt);
+       }
+       else if (!strcmp(optname, "font_size_message")) {
+               if (iflags.wc_fontsiz_message) Sprintf(buf, "%d",
+                                                       iflags.wc_fontsiz_message);
+               else Strcpy(buf, defopt);
+       }
+       else if (!strcmp(optname, "font_size_status")) {
+               if (iflags.wc_fontsiz_status) Sprintf(buf, "%d", iflags.wc_fontsiz_status);
+               else Strcpy(buf, defopt);
+       }
+       else if (!strcmp(optname, "font_size_menu")) {
+               if (iflags.wc_fontsiz_menu) Sprintf(buf, "%d", iflags.wc_fontsiz_menu);
+               else Strcpy(buf, defopt);
+       }
+       else if (!strcmp(optname, "font_size_text")) {
+               if (iflags.wc_fontsiz_text) Sprintf(buf, "%d",iflags.wc_fontsiz_text);
+               else Strcpy(buf, defopt);
+       }
+       else if (!strcmp(optname, "fruit")) 
+               Sprintf(buf, "%s", pl_fruit);
+       else if (!strcmp(optname, "gender"))
+               Sprintf(buf, "%s", rolestring(flags.initgend, genders, adj));
+       else if (!strcmp(optname, "horsename")) 
+               Sprintf(buf, "%s", horsename[0] ? horsename : none);
+       else if (!strcmp(optname, "map_mode"))
+               Sprintf(buf, "%s",
+                       iflags.wc_map_mode == MAP_MODE_TILES      ? "tiles" :
+                       iflags.wc_map_mode == MAP_MODE_ASCII4x6   ? "ascii4x6" :
+                       iflags.wc_map_mode == MAP_MODE_ASCII6x8   ? "ascii6x8" :
+                       iflags.wc_map_mode == MAP_MODE_ASCII8x8   ? "ascii8x8" :
+                       iflags.wc_map_mode == MAP_MODE_ASCII16x8  ? "ascii16x8" :
+                       iflags.wc_map_mode == MAP_MODE_ASCII7x12  ? "ascii7x12" :
+                       iflags.wc_map_mode == MAP_MODE_ASCII8x12  ? "ascii8x12" :
+                       iflags.wc_map_mode == MAP_MODE_ASCII16x12 ? "ascii16x12" :
+                       iflags.wc_map_mode == MAP_MODE_ASCII12x16 ? "ascii12x16" :
+                       iflags.wc_map_mode == MAP_MODE_ASCII10x18 ? "ascii10x18" :
+                       iflags.wc_map_mode == MAP_MODE_ASCII_FIT_TO_SCREEN ?
+                       "fit_to_screen" : defopt);
+       else if (!strcmp(optname, "menustyle")) 
+               Sprintf(buf, "%s", menutype[(int)flags.menu_style] );
+       else if (!strcmp(optname, "menu_deselect_all"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "menu_deselect_page"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "menu_first_page"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "menu_invert_all"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "menu_headings")) {
+               Sprintf(buf, "%s", (iflags.menu_headings == ATR_BOLD) ?
+                       "bold" :   (iflags.menu_headings == ATR_INVERSE) ?
+                       "inverse" :   (iflags.menu_headings == ATR_ULINE) ?
+                       "underline" : "unknown");
+       }
+       else if (!strcmp(optname, "menu_invert_page"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "menu_last_page"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "menu_next_page"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "menu_previous_page"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "menu_search"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "menu_select_all"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "menu_select_page"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "monsters"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "msghistory"))
+               Sprintf(buf, "%u", iflags.msg_history);
+#ifdef TTY_GRAPHICS
+       else if (!strcmp(optname, "msg_window"))
+               Sprintf(buf, "%s", (iflags.prevmsg_window=='s') ? "single" :
+                                       (iflags.prevmsg_window=='c') ? "combination" :
+                                       (iflags.prevmsg_window=='f') ? "full" : "reversed");
+#endif
+       else if (!strcmp(optname, "name"))
+               Sprintf(buf, "%s", plname);
+       else if (!strcmp(optname, "number_pad"))
+               Sprintf(buf, "%s",
+                       (!iflags.num_pad) ? "0=off" :
+                       (iflags.num_pad_mode) ? "2=on, DOS compatible" : "1=on");
+       else if (!strcmp(optname, "objects"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "packorder")) {
+               oc_to_str(flags.inv_order, ocl);
+               Sprintf(buf, "%s", ocl);
+            }
+#ifdef CHANGE_COLOR
+       else if (!strcmp(optname, "palette")) 
+               Sprintf(buf, "%s", get_color_string());
+#endif
+       else if (!strcmp(optname, "pettype")) 
+               Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat" :
+                               (preferred_pet == 'd') ? "dog" :
+                               (preferred_pet == 'n') ? "none" : "random");
+       else if (!strcmp(optname, "pickup_burden"))
+               Sprintf(buf, "%s", burdentype[flags.pickup_burden] );
+       else if (!strcmp(optname, "pickup_types")) {
+               oc_to_str(flags.pickup_types, ocl);
+               Sprintf(buf, "%s", ocl[0] ? ocl : "all" );
+            }
+       else if (!strcmp(optname, "race"))
+               Sprintf(buf, "%s", rolestring(flags.initrace, races, noun));
+       else if (!strcmp(optname, "role"))
+               Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m));
+       else if (!strcmp(optname, "runmode"))
+               Sprintf(buf, "%s", runmodes[iflags.runmode]);
+       else if (!strcmp(optname, "scores")) {
+               Sprintf(buf, "%d top/%d around%s", flags.end_top,
+                               flags.end_around, flags.end_own ? "/own" : "");
+       }
+       else if (!strcmp(optname, "scroll_amount")) {
+               if (iflags.wc_scroll_amount) Sprintf(buf, "%d",iflags.wc_scroll_amount);
+               else Strcpy(buf, defopt);
+       }
+       else if (!strcmp(optname, "scroll_margin")) {
+               if (iflags.wc_scroll_margin) Sprintf(buf, "%d",iflags.wc_scroll_margin);
+               else Strcpy(buf, defopt);
+       }
+       else if (!strcmp(optname, "player_selection"))
+               Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog");
+#ifdef MSDOS
+       else if (!strcmp(optname, "soundcard"))
+               Sprintf(buf, "%s", to_be_done);
+#endif
+       else if (!strcmp(optname, "suppress_alert")) {
+           if (flags.suppress_alert == 0L)
+               Strcpy(buf, none);
+           else
+               Sprintf(buf, "%lu.%lu.%lu",
+                       FEATURE_NOTICE_VER_MAJ,
+                       FEATURE_NOTICE_VER_MIN,
+                       FEATURE_NOTICE_VER_PATCH);
+       }
+       else if (!strcmp(optname, "tile_file"))
+               Sprintf(buf, "%s", iflags.wc_tile_file ? iflags.wc_tile_file : defopt);
+       else if (!strcmp(optname, "tile_height")) {
+               if (iflags.wc_tile_height) Sprintf(buf, "%d",iflags.wc_tile_height);
+               else Strcpy(buf, defopt);
+       }
+       else if (!strcmp(optname, "tile_width")) {
+               if (iflags.wc_tile_width) Sprintf(buf, "%d",iflags.wc_tile_width);
+               else Strcpy(buf, defopt);
+       }
+       else if (!strcmp(optname, "traps"))
+               Sprintf(buf, "%s", to_be_done);
+       else if (!strcmp(optname, "vary_msgcount")) {
+               if (iflags.wc_vary_msgcount) Sprintf(buf, "%d",iflags.wc_vary_msgcount);
+               else Strcpy(buf, defopt);
+       }
+#ifdef MSDOS
+       else if (!strcmp(optname, "video"))
+               Sprintf(buf, "%s", to_be_done);
+#endif
+#ifdef VIDEOSHADES
+       else if (!strcmp(optname, "videoshades"))
+               Sprintf(buf, "%s-%s-%s", shade[0],shade[1],shade[2]);
+       else if (!strcmp(optname, "videocolors"))
+               Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
+                       ttycolors[CLR_RED], ttycolors[CLR_GREEN],
+                       ttycolors[CLR_BROWN], ttycolors[CLR_BLUE],
+                       ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN],
+                       ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],
+                       ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],
+                       ttycolors[CLR_BRIGHT_MAGENTA],
+                       ttycolors[CLR_BRIGHT_CYAN]);
+#endif /* VIDEOSHADES */
+       else if (!strcmp(optname, "windowtype"))
+               Sprintf(buf, "%s", windowprocs.name);
+       else if (!strcmp(optname, "windowcolors"))
+               Sprintf(buf, "%s/%s %s/%s %s/%s %s/%s",
+                       iflags.wc_foregrnd_menu    ? iflags.wc_foregrnd_menu : defbrief,
+                       iflags.wc_backgrnd_menu    ? iflags.wc_backgrnd_menu : defbrief,
+                       iflags.wc_foregrnd_message ? iflags.wc_foregrnd_message : defbrief,
+                       iflags.wc_backgrnd_message ? iflags.wc_backgrnd_message : defbrief,
+                       iflags.wc_foregrnd_status  ? iflags.wc_foregrnd_status : defbrief,
+                       iflags.wc_backgrnd_status  ? iflags.wc_backgrnd_status : defbrief,
+                       iflags.wc_foregrnd_text    ? iflags.wc_foregrnd_text : defbrief,
+                       iflags.wc_backgrnd_text    ? iflags.wc_backgrnd_text : defbrief);
+#ifdef PREFIXES_IN_USE
+       else {
+           for (i = 0; i < PREFIX_COUNT; ++i)
+               if (!strcmp(optname, fqn_prefix_names[i]) && fqn_prefix[i])
+                       Sprintf(buf, "%s", fqn_prefix[i]);
+       }
+#endif
+
+       if (buf[0]) return buf;
+       else return "unknown";
+}
+
+int
+dotogglepickup()
+{
+       char buf[BUFSZ], ocl[MAXOCLASSES+1];
+
+       flags.pickup = !flags.pickup;
+       if (flags.pickup) {
+           oc_to_str(flags.pickup_types, ocl);
+           Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all",
+#ifdef AUTOPICKUP_EXCEPTIONS
+                       (iflags.autopickup_exceptions[AP_LEAVE] ||
+                        iflags.autopickup_exceptions[AP_GRAB]) ?
+                        ((count_ape_maps((int *)0, (int *)0) == 1) ?
+                           ", with one exception" : ", with some exceptions") :
+#endif
+                       "");
+       } else {
+           Strcpy(buf, "OFF");
+       }
+       pline("Autopickup: %s.", buf);
+       return 0;
+}
+
+#ifdef AUTOPICKUP_EXCEPTIONS
+int
+add_autopickup_exception(mapping)
+const char *mapping;
+{
+       struct autopickup_exception *ape, **apehead;
+       char text[256], *text2;
+       int textsize = 0;
+       boolean grab = FALSE;
+
+       if (sscanf(mapping, "\"%255[^\"]\"", text) == 1) {
+               text2 = &text[0];
+               if (*text2 == '<') {            /* force autopickup */
+                       grab = TRUE;
+                       ++text2;
+               } else if (*text2 == '>') {     /* default - Do not pickup */
+                       grab = FALSE;
+                       ++text2;
+               }
+               textsize = strlen(text2);
+               apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB] :
+                                  &iflags.autopickup_exceptions[AP_LEAVE];
+               ape = (struct autopickup_exception *)
+                               alloc(sizeof(struct autopickup_exception));
+               ape->pattern = (char *) alloc(textsize+1);
+               Strcpy(ape->pattern, text2);
+               ape->grab = grab;
+               if (!*apehead) ape->next = (struct autopickup_exception *)0;
+               else ape->next = *apehead;
+               *apehead = ape;
+       } else {
+           raw_print("syntax error in AUTOPICKUP_EXCEPTION");
+           return 0;
+       }
+       return 1;
+}
+
+STATIC_OVL void
+remove_autopickup_exception(whichape)
+struct autopickup_exception *whichape;
+{
+    struct autopickup_exception *ape, *prev = 0;
+    int chain = whichape->grab ? AP_GRAB : AP_LEAVE;
+
+    for (ape = iflags.autopickup_exceptions[chain]; ape;) {
+       if (ape == whichape) {
+           struct autopickup_exception *freeape = ape;
+           ape = ape->next;
+           if (prev) prev->next = ape;
+           else iflags.autopickup_exceptions[chain] = ape;
+           free(freeape->pattern);
+           free(freeape);
+       } else {
+           prev = ape;
+           ape = ape->next;
+       }
+    }
+}
+
+STATIC_OVL int
+count_ape_maps(leave, grab)
+int *leave, *grab;
+{
+       struct autopickup_exception *ape;
+       int pass, totalapes, numapes[2] = {0,0};
+
+       for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
+               ape = iflags.autopickup_exceptions[pass];
+               while(ape) {
+                       ape = ape->next;
+                       numapes[pass]++;
+               }
+       }
+       totalapes = numapes[AP_LEAVE] + numapes[AP_GRAB];
+       if (leave) *leave = numapes[AP_LEAVE];
+       if (grab) *grab = numapes[AP_GRAB];
+       return totalapes;
+}
+
+void
+free_autopickup_exceptions()
+{
+       struct autopickup_exception *ape;
+       int pass;
+
+       for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
+               while((ape = iflags.autopickup_exceptions[pass]) != 0) {
+                       free(ape->pattern);
+                       iflags.autopickup_exceptions[pass] = ape->next;
+                       free(ape);
+               }
+       }
+}
+#endif /* AUTOPICKUP_EXCEPTIONS */
+
+/* data for option_help() */
+static const char *opt_intro[] = {
+       "",
+       "                 NetHack Options Help:",
+       "",
+#define CONFIG_SLOT 3  /* fill in next value at run-time */
+       (char *)0,
+#if !defined(MICRO) && !defined(MAC)
+       "or use `NETHACKOPTIONS=\"<options>\"' in your environment",
+#endif
+       "(<options> is a list of options separated by commas)",
+#ifdef VMS
+       "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
+#endif
+       "or press \"O\" while playing and use the menu.",
+       "",
+ "Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
+       (char *)0
+};
+
+static const char *opt_epilog[] = {
+       "",
+ "Some of the options can be set only before the game is started; those",
+       "items will not be selectable in the 'O' command's menu.",
+       (char *)0
+};
+
+void
+option_help()
+{
+    char buf[BUFSZ], buf2[BUFSZ];
+    register int i;
+    winid datawin;
+
+    datawin = create_nhwindow(NHW_TEXT);
+    Sprintf(buf, "Set options as OPTIONS=<options> in %s", configfile);
+    opt_intro[CONFIG_SLOT] = (const char *) buf;
+    for (i = 0; opt_intro[i]; i++)
+       putstr(datawin, 0, opt_intro[i]);
+
+    /* Boolean options */
+    for (i = 0; boolopt[i].name; i++) {
+       if (boolopt[i].addr) {
+#ifdef WIZARD
+           if (boolopt[i].addr == &iflags.sanity_check && !wizard) continue;
+           if (boolopt[i].addr == &iflags.menu_tab_sep && !wizard) continue;
+#endif
+           next_opt(datawin, boolopt[i].name);
+       }
+    }
+    next_opt(datawin, "");
+
+    /* Compound options */
+    putstr(datawin, 0, "Compound options:");
+    for (i = 0; compopt[i].name; i++) {
+       Sprintf(buf2, "`%s'", compopt[i].name);
+       Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr,
+               compopt[i+1].name ? ',' : '.');
+       putstr(datawin, 0, buf);
+    }
+
+    for (i = 0; opt_epilog[i]; i++)
+       putstr(datawin, 0, opt_epilog[i]);
+
+    display_nhwindow(datawin, FALSE);
+    destroy_nhwindow(datawin);
+    return;
+}
+
+/*
+ * prints the next boolean option, on the same line if possible, on a new
+ * line if not. End with next_opt("").
+ */
+void
+next_opt(datawin, str)
+winid datawin;
+const char *str;
+{
+       static char *buf = 0;
+       int i;
+       char *s;
+
+       if (!buf) *(buf = (char *)alloc(BUFSZ)) = '\0';
+
+       if (!*str) {
+               s = eos(buf);
+               if (s > &buf[1] && s[-2] == ',')
+                   Strcpy(s - 2, "."); /* replace last ", " */
+               i = COLNO;      /* (greater than COLNO - 2) */
+       } else {
+               i = strlen(buf) + strlen(str) + 2;
+       }
+
+       if (i > COLNO - 2) { /* rule of thumb */
+               putstr(datawin, 0, buf);
+               buf[0] = 0;
+       }
+       if (*str) {
+               Strcat(buf, str);
+               Strcat(buf, ", ");
+       } else {
+               putstr(datawin, 0, str);
+               free(buf),  buf = 0;
+       }
+       return;
+}
+
+/* Returns the fid of the fruit type; if that type already exists, it
+ * returns the fid of that one; if it does not exist, it adds a new fruit
+ * type to the chain and returns the new one.
+ */
+int
+fruitadd(str)
+char *str;
+{
+       register int i;
+       register struct fruit *f;
+       struct fruit *lastf = 0;
+       int highest_fruit_id = 0;
+       char buf[PL_FSIZ];
+       boolean user_specified = (str == pl_fruit);
+       /* if not user-specified, then it's a fruit name for a fruit on
+        * a bones level...
+        */
+
+       /* Note: every fruit has an id (spe for fruit objects) of at least
+        * 1; 0 is an error.
+        */
+       if (user_specified) {
+               /* disallow naming after other foods (since it'd be impossible
+                * to tell the difference)
+                */
+
+               boolean found = FALSE, numeric = FALSE;
+
+               for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS;
+                                               i++) {
+                       if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) {
+                               found = TRUE;
+                               break;
+                       }
+               }
+               {
+                   char *c;
+
+                   c = pl_fruit;
+
+                   for(c = pl_fruit; *c >= '0' && *c <= '9'; c++)
+                       ;
+                   if (isspace(*c) || *c == 0) numeric = TRUE;
+               }
+               if (found || numeric ||
+                   !strncmp(str, "cursed ", 7) ||
+                   !strncmp(str, "uncursed ", 9) ||
+                   !strncmp(str, "blessed ", 8) ||
+                   !strncmp(str, "partly eaten ", 13) ||
+                   (!strncmp(str, "tin of ", 7) &&
+                       (!strcmp(str+7, "spinach") ||
+                        name_to_mon(str+7) >= LOW_PM)) ||
+                   !strcmp(str, "empty tin") ||
+                   ((!strncmp(eos(str)-7," corpse",7) ||
+                           !strncmp(eos(str)-4, " egg",4)) &&
+                       name_to_mon(str) >= LOW_PM))
+                       {
+                               Strcpy(buf, pl_fruit);
+                               Strcpy(pl_fruit, "candied ");
+                               nmcpy(pl_fruit+8, buf, PL_FSIZ-8);
+               }
+       }
+       for(f=ffruit; f; f = f->nextf) {
+               lastf = f;
+               if(f->fid > highest_fruit_id) highest_fruit_id = f->fid;
+               if(!strncmp(str, f->fname, PL_FSIZ))
+                       goto nonew;
+       }
+       /* if adding another fruit would overflow spe, use a random
+          fruit instead... we've got a lot to choose from. */
+       if (highest_fruit_id >= 127) return rnd(127);
+       highest_fruit_id++;
+       f = newfruit();
+       if (ffruit) lastf->nextf = f;
+       else ffruit = f;
+       Strcpy(f->fname, str);
+       f->fid = highest_fruit_id;
+       f->nextf = 0;
+nonew:
+       if (user_specified) current_fruit = highest_fruit_id;
+       return f->fid;
+}
+
+/*
+ * This is a somewhat generic menu for taking a list of NetHack style
+ * class choices and presenting them via a description
+ * rather than the traditional NetHack characters.
+ * (Benefits users whose first exposure to NetHack is via tiles).
+ *
+ * prompt
+ *          The title at the top of the menu.
+ *
+ * category: 0 = monster class
+ *           1 = object  class
+ *
+ * way
+ *          FALSE = PICK_ONE, TRUE = PICK_ANY
+ *
+ * class_list
+ *          a null terminated string containing the list of choices.
+ *
+ * class_selection
+ *          a null terminated string containing the selected characters.
+ *
+ * Returns number selected.
+ */
+int
+choose_classes_menu(prompt, category, way, class_list, class_select)
+const char *prompt;
+int category;
+boolean way;
+char *class_list;
+char *class_select;
+{
+    menu_item *pick_list = (menu_item *)0;
+    winid win;
+    anything any;
+    char buf[BUFSZ];
+    int i, n;
+    int ret;
+    int next_accelerator, accelerator;
+
+    if (class_list == (char *)0 || class_select == (char *)0) return 0;
+    accelerator = 0;
+    next_accelerator = 'a';
+    any.a_void = 0;
+    win = create_nhwindow(NHW_MENU);
+    start_menu(win);
+    while (*class_list) {
+       const char *text;
+       boolean selected;
+
+       text = (char *)0;
+       selected = FALSE;
+       switch (category) {
+               case 0:
+                       text = monexplain[def_char_to_monclass(*class_list)];
+                       accelerator = *class_list;
+                       Sprintf(buf, "%s", text);
+                       break;
+               case 1:
+                       text = objexplain[def_char_to_objclass(*class_list)];
+                       accelerator = next_accelerator;
+                       Sprintf(buf, "%c  %s", *class_list, text);
+                       break;
+               default:
+                       impossible("choose_classes_menu: invalid category %d",
+                                       category);
+       }
+       if (way && *class_select) {     /* Selections there already */
+               if (index(class_select, *class_list)) {
+                       selected = TRUE;
+               }
+       }
+       any.a_int = *class_list;
+       add_menu(win, NO_GLYPH, &any, accelerator,
+                 category ? *class_list : 0,
+                 ATR_NONE, buf, selected);
+       ++class_list;
+       if (category > 0) {
+               ++next_accelerator;
+               if (next_accelerator == ('z' + 1)) next_accelerator = 'A';
+               if (next_accelerator == ('Z' + 1)) break;
+       }
+    }
+    end_menu(win, prompt);
+    n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list);
+    destroy_nhwindow(win);
+    if (n > 0) {
+       for (i = 0; i < n; ++i)
+           *class_select++ = (char)pick_list[i].item.a_int;
+       free((genericptr_t)pick_list);
+       ret = n;
+    } else if (n == -1) {
+       class_select = eos(class_select);
+       ret = -1;
+    } else
+       ret = 0;
+    *class_select = '\0';
+    return ret;
+}
+
+struct wc_Opt wc_options[] = {
+       {"ascii_map", WC_ASCII_MAP},
+       {"color", WC_COLOR},
+       {"eight_bit_tty", WC_EIGHT_BIT_IN},
+       {"hilite_pet", WC_HILITE_PET},
+       {"popup_dialog", WC_POPUP_DIALOG},
+       {"player_selection", WC_PLAYER_SELECTION},
+       {"preload_tiles", WC_PRELOAD_TILES},
+       {"tiled_map", WC_TILED_MAP},
+       {"tile_file", WC_TILE_FILE},
+       {"tile_width", WC_TILE_WIDTH},
+       {"tile_height", WC_TILE_HEIGHT},
+       {"use_inverse", WC_INVERSE},
+       {"align_message", WC_ALIGN_MESSAGE},
+       {"align_status", WC_ALIGN_STATUS},
+       {"font_map", WC_FONT_MAP},
+       {"font_menu", WC_FONT_MENU},
+       {"font_message",WC_FONT_MESSAGE},
+#if 0
+       {"perm_invent",WC_PERM_INVENT},
+#endif
+       {"font_size_map", WC_FONTSIZ_MAP},
+       {"font_size_menu", WC_FONTSIZ_MENU},
+       {"font_size_message", WC_FONTSIZ_MESSAGE},
+       {"font_size_status", WC_FONTSIZ_STATUS},
+       {"font_size_text", WC_FONTSIZ_TEXT},
+       {"font_status", WC_FONT_STATUS},
+       {"font_text", WC_FONT_TEXT},
+       {"map_mode", WC_MAP_MODE},
+       {"scroll_amount", WC_SCROLL_AMOUNT},
+       {"scroll_margin", WC_SCROLL_MARGIN},
+       {"splash_screen", WC_SPLASH_SCREEN},
+       {"vary_msgcount",WC_VARY_MSGCOUNT},
+       {"windowcolors", WC_WINDOWCOLORS},
+       {"mouse_support", WC_MOUSE_SUPPORT},
+       {(char *)0, 0L}
+};
+
+struct wc_Opt wc2_options[] = {
+       {"fullscreen", WC2_FULLSCREEN},
+       {"softkeyboard", WC2_SOFTKEYBOARD},
+       {"wraptext", WC2_WRAPTEXT},
+       {(char *)0, 0L}
+};
+
+
+/*
+ * If a port wants to change or ensure that the
+ * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is
+ * correct (for controlling its display in the option menu) call
+ * set_option_mod_status()
+ * with the second argument of 0,2, or 3 respectively.
+ */
+void
+set_option_mod_status(optnam, status)
+const char *optnam;
+int status;
+{
+       int k;
+       if (status < SET_IN_FILE || status > SET_IN_GAME) {
+               impossible("set_option_mod_status: status out of range %d.",
+                          status);
+               return;
+       }
+       for (k = 0; boolopt[k].name; k++) {
+               if (!strncmpi(boolopt[k].name, optnam, strlen(optnam))) {
+                       boolopt[k].optflags = status;
+                       return;
+               }
+       }
+       for (k = 0; compopt[k].name; k++) {
+               if (!strncmpi(compopt[k].name, optnam, strlen(optnam))) {
+                       compopt[k].optflags = status;
+                       return;
+               }
+       }
+}
+
+/*
+ * You can set several wc_options in one call to
+ * set_wc_option_mod_status() by setting
+ * the appropriate bits for each option that you
+ * are setting in the optmask argument
+ * prior to calling.
+ *    example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN, SET_IN_GAME);
+ */
+void
+set_wc_option_mod_status(optmask, status)
+unsigned long optmask;
+int status;
+{
+       int k = 0;
+       if (status < SET_IN_FILE || status > SET_IN_GAME) {
+               impossible("set_wc_option_mod_status: status out of range %d.",
+                          status);
+               return;
+       }
+       while (wc_options[k].wc_name) {
+               if (optmask & wc_options[k].wc_bit) {
+                       set_option_mod_status(wc_options[k].wc_name, status);
+               }
+               k++;
+       }
+}
+
+STATIC_OVL boolean
+is_wc_option(optnam)
+const char *optnam;
+{
+       int k = 0;
+       while (wc_options[k].wc_name) {
+               if (strcmp(wc_options[k].wc_name, optnam) == 0)
+                       return TRUE;
+               k++;
+       }
+       return FALSE;
+}
+
+STATIC_OVL boolean
+wc_supported(optnam)
+const char *optnam;
+{
+       int k = 0;
+       while (wc_options[k].wc_name) {
+               if (!strcmp(wc_options[k].wc_name, optnam) &&
+                   (windowprocs.wincap & wc_options[k].wc_bit))
+                       return TRUE;
+               k++;
+       }
+       return FALSE;
+}
+
+
+/*
+ * You can set several wc2_options in one call to
+ * set_wc2_option_mod_status() by setting
+ * the appropriate bits for each option that you
+ * are setting in the optmask argument
+ * prior to calling.
+ *    example: set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT, SET_IN_FILE);
+ */
+
+void
+set_wc2_option_mod_status(optmask, status)
+unsigned long optmask;
+int status;
+{
+       int k = 0;
+       if (status < SET_IN_FILE || status > SET_IN_GAME) {
+               impossible("set_wc2_option_mod_status: status out of range %d.",
+                          status);
+               return;
+       }
+       while (wc2_options[k].wc_name) {
+               if (optmask & wc2_options[k].wc_bit) {
+                       set_option_mod_status(wc2_options[k].wc_name, status);
+               }
+               k++;
+       }
+}
+
+STATIC_OVL boolean
+is_wc2_option(optnam)
+const char *optnam;
+{
+       int k = 0;
+       while (wc2_options[k].wc_name) {
+               if (strcmp(wc2_options[k].wc_name, optnam) == 0)
+                       return TRUE;
+               k++;
+       }
+       return FALSE;
+}
+
+STATIC_OVL boolean
+wc2_supported(optnam)
+const char *optnam;
+{
+       int k = 0;
+       while (wc2_options[k].wc_name) {
+               if (!strcmp(wc2_options[k].wc_name, optnam) &&
+                   (windowprocs.wincap2 & wc2_options[k].wc_bit))
+                       return TRUE;
+               k++;
+       }
+       return FALSE;
+}
+
+
+STATIC_OVL void
+wc_set_font_name(wtype, fontname)
+int wtype;
+char *fontname;
+{
+       char **fn = (char **)0;
+       if (!fontname) return;
+       switch(wtype) {
+           case NHW_MAP:
+                       fn = &iflags.wc_font_map;
+                       break;
+           case NHW_MESSAGE:
+                       fn = &iflags.wc_font_message;
+                       break;
+           case NHW_TEXT:
+                       fn = &iflags.wc_font_text;
+                       break;
+           case NHW_MENU:
+                       fn = &iflags.wc_font_menu;
+                       break;
+           case NHW_STATUS:
+                       fn = &iflags.wc_font_status;
+                       break;
+           default:
+                       return;
+       }
+       if (fn) {
+               if (*fn) free(*fn);
+               *fn = (char *)alloc(strlen(fontname) + 1);
+               Strcpy(*fn, fontname);
+       }
+       return;
+}
+
+STATIC_OVL int
+wc_set_window_colors(op)
+char *op;
+{
+       /* syntax:
+        *  menu white/black message green/yellow status white/blue text white/black
+        */
+
+       int j;
+       char buf[BUFSZ];
+       char *wn, *tfg, *tbg, *newop;
+       static const char *wnames[] = { "menu", "message", "status", "text" };
+       static const char *shortnames[] = { "mnu", "msg", "sts", "txt" };
+       static char **fgp[] = {
+               &iflags.wc_foregrnd_menu,
+               &iflags.wc_foregrnd_message,
+               &iflags.wc_foregrnd_status,
+               &iflags.wc_foregrnd_text
+       };
+       static char **bgp[] = {
+               &iflags.wc_backgrnd_menu,
+               &iflags.wc_backgrnd_message,
+               &iflags.wc_backgrnd_status,
+               &iflags.wc_backgrnd_text
+       };
+
+       Strcpy(buf, op);
+       newop = mungspaces(buf);
+       while (newop && *newop) {
+
+               wn = tfg = tbg = (char *)0;
+
+               /* until first non-space in case there's leading spaces - before colorname*/
+               while(*newop && isspace(*newop)) newop++;
+               if (*newop) wn = newop;
+               else return 0;
+
+               /* until first space - colorname*/
+               while(*newop && !isspace(*newop)) newop++;
+               if (*newop) *newop = '\0';
+               else return 0;
+               newop++;
+
+               /* until first non-space - before foreground*/
+               while(*newop && isspace(*newop)) newop++;
+               if (*newop) tfg = newop;
+               else return 0;
+
+               /* until slash - foreground */
+               while(*newop && *newop != '/') newop++;
+               if (*newop) *newop = '\0';
+               else return 0;
+               newop++;
+
+               /* until first non-space (in case there's leading space after slash) - before background */
+               while(*newop && isspace(*newop)) newop++;
+               if (*newop) tbg = newop;
+               else return 0;
+
+               /* until first space - background */
+               while(*newop && !isspace(*newop)) newop++;
+               if (*newop) *newop++ = '\0';
+
+               for (j = 0; j < 4; ++j) {
+                       if (!strcmpi(wn, wnames[j]) ||
+                           !strcmpi(wn, shortnames[j])) {
+                               if (tfg && !strstri(tfg, " ")) {
+                                       if (*fgp[j]) free(*fgp[j]);
+                                       *fgp[j] = (char *)alloc(strlen(tfg) + 1);
+                                       Strcpy(*fgp[j], tfg);
+                               }
+                               if (tbg && !strstri(tbg, " ")) {
+                                       if (*bgp[j]) free(*bgp[j]);
+                                       *bgp[j] = (char *)alloc(strlen(tbg) + 1);
+                                       Strcpy(*bgp[j], tbg);
+                               }
+                               break;
+                       }
+               }
+       }
+       return 1;
+}
+
+#endif /* OPTION_LISTS_ONLY */
+
+/*options.c*/
diff --git a/src/pager.c b/src/pager.c
new file mode 100644 (file)
index 0000000..96093f4
--- /dev/null
@@ -0,0 +1,964 @@
+/*     SCCS Id: @(#)pager.c    3.4     2003/08/13      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* This file contains the command routines dowhatis() and dohelp() and */
+/* a few other help related facilities */
+
+#include "hack.h"
+#include "dlb.h"
+
+STATIC_DCL boolean FDECL(is_swallow_sym, (int));
+STATIC_DCL int FDECL(append_str, (char *, const char *));
+STATIC_DCL struct permonst * FDECL(lookat, (int, int, char *, char *));
+STATIC_DCL void FDECL(checkfile,
+                     (char *,struct permonst *,BOOLEAN_P,BOOLEAN_P));
+STATIC_DCL int FDECL(do_look, (BOOLEAN_P));
+STATIC_DCL boolean FDECL(help_menu, (int *));
+#ifdef PORT_HELP
+extern void NDECL(port_help);
+#endif
+
+/* Returns "true" for characters that could represent a monster's stomach. */
+STATIC_OVL boolean
+is_swallow_sym(c)
+int c;
+{
+    int i;
+    for (i = S_sw_tl; i <= S_sw_br; i++)
+       if ((int)showsyms[i] == c) return TRUE;
+    return FALSE;
+}
+
+/*
+ * Append new_str to the end of buf if new_str doesn't already exist as
+ * a substring of buf.  Return 1 if the string was appended, 0 otherwise.
+ * It is expected that buf is of size BUFSZ.
+ */
+STATIC_OVL int
+append_str(buf, new_str)
+    char *buf;
+    const char *new_str;
+{
+    int space_left;    /* space remaining in buf */
+
+    if (strstri(buf, new_str)) return 0;
+
+    space_left = BUFSZ - strlen(buf) - 1;
+    (void) strncat(buf, " or ", space_left);
+    (void) strncat(buf, new_str, space_left - 4);
+    return 1;
+}
+
+/*
+ * Return the name of the glyph found at (x,y).
+ * If not hallucinating and the glyph is a monster, also monster data.
+ */
+STATIC_OVL struct permonst *
+lookat(x, y, buf, monbuf)
+    int x, y;
+    char *buf, *monbuf;
+{
+    register struct monst *mtmp = (struct monst *) 0;
+    struct permonst *pm = (struct permonst *) 0;
+    int glyph;
+
+    buf[0] = monbuf[0] = 0;
+    glyph = glyph_at(x,y);
+    if (u.ux == x && u.uy == y && senseself()) {
+       char race[QBUFSZ];
+
+       /* if not polymorphed, show both the role and the race */
+       race[0] = 0;
+       if (!Upolyd) {
+           Sprintf(race, "%s ", urace.adj);
+       }
+
+       Sprintf(buf, "%s%s%s called %s",
+               Invis ? "invisible " : "",
+               race,
+               mons[u.umonnum].mname,
+               plname);
+       /* file lookup can't distinguish between "gnomish wizard" monster
+          and correspondingly named player character, always picking the
+          former; force it to find the general "wizard" entry instead */
+       if (Role_if(PM_WIZARD) && Race_if(PM_GNOME) && !Upolyd)
+           pm = &mons[PM_WIZARD];
+
+#ifdef STEED
+       if (u.usteed) {
+           char steedbuf[BUFSZ];
+
+           Sprintf(steedbuf, ", mounted on %s", y_monnam(u.usteed));
+           /* assert((sizeof buf >= strlen(buf)+strlen(steedbuf)+1); */
+           Strcat(buf, steedbuf);
+       }
+#endif
+       /* When you see yourself normally, no explanation is appended
+          (even if you could also see yourself via other means).
+          Sensing self while blind or swallowed is treated as if it
+          were by normal vision (cf canseeself()). */
+       if ((Invisible || u.uundetected) && !Blind && !u.uswallow) {
+           unsigned how = 0;
+
+           if (Infravision)     how |= 1;
+           if (Unblind_telepat) how |= 2;
+           if (Detect_monsters) how |= 4;
+
+           if (how)
+               Sprintf(eos(buf), " [seen: %s%s%s%s%s]",
+                       (how & 1) ? "infravision" : "",
+                       /* add comma if telep and infrav */
+                       ((how & 3) > 2) ? ", " : "",
+                       (how & 2) ? "telepathy" : "",
+                       /* add comma if detect and (infrav or telep or both) */
+                       ((how & 7) > 4) ? ", " : "",
+                       (how & 4) ? "monster detection" : "");
+       }
+    } else if (u.uswallow) {
+       /* all locations when swallowed other than the hero are the monster */
+       Sprintf(buf, "interior of %s",
+                                   Blind ? "a monster" : a_monnam(u.ustuck));
+       pm = u.ustuck->data;
+    } else if (glyph_is_monster(glyph)) {
+       bhitpos.x = x;
+       bhitpos.y = y;
+       mtmp = m_at(x,y);
+       if (mtmp != (struct monst *) 0) {
+           char *name, monnambuf[BUFSZ];
+           boolean accurate = !Hallucination;
+
+           if (mtmp->data == &mons[PM_COYOTE] && accurate)
+               name = coyotename(mtmp, monnambuf);
+           else
+               name = distant_monnam(mtmp, ARTICLE_NONE, monnambuf);
+
+           pm = mtmp->data;
+           Sprintf(buf, "%s%s%s",
+                   (mtmp->mx != x || mtmp->my != y) ?
+                       ((mtmp->isshk && accurate)
+                               ? "tail of " : "tail of a ") : "",
+                   (mtmp->mtame && accurate) ? "tame " :
+                   (mtmp->mpeaceful && accurate) ? "peaceful " : "",
+                   name);
+           if (u.ustuck == mtmp)
+               Strcat(buf, (Upolyd && sticks(youmonst.data)) ?
+                       ", being held" : ", holding you");
+           if (mtmp->mleashed)
+               Strcat(buf, ", leashed to you");
+
+           if (mtmp->mtrapped && cansee(mtmp->mx, mtmp->my)) {
+               struct trap *t = t_at(mtmp->mx, mtmp->my);
+               int tt = t ? t->ttyp : NO_TRAP;
+
+               /* newsym lets you know of the trap, so mention it here */
+               if (tt == BEAR_TRAP || tt == PIT ||
+                       tt == SPIKED_PIT || tt == WEB)
+                   Sprintf(eos(buf), ", trapped in %s",
+                           an(defsyms[trap_to_defsym(tt)].explanation));
+           }
+
+           {
+               int ways_seen = 0, normal = 0, xraydist;
+               boolean useemon = (boolean) canseemon(mtmp);
+
+               xraydist = (u.xray_range<0) ? -1 : u.xray_range * u.xray_range;
+               /* normal vision */
+               if ((mtmp->wormno ? worm_known(mtmp) : cansee(mtmp->mx, mtmp->my)) &&
+                       mon_visible(mtmp) && !mtmp->minvis) {
+                   ways_seen++;
+                   normal++;
+               }
+               /* see invisible */
+               if (useemon && mtmp->minvis)
+                   ways_seen++;
+               /* infravision */
+               if ((!mtmp->minvis || See_invisible) && see_with_infrared(mtmp))
+                   ways_seen++;
+               /* telepathy */
+               if (tp_sensemon(mtmp))
+                   ways_seen++;
+               /* xray */
+               if (useemon && xraydist > 0 &&
+                       distu(mtmp->mx, mtmp->my) <= xraydist)
+                   ways_seen++;
+               if (Detect_monsters)
+                   ways_seen++;
+               if (MATCH_WARN_OF_MON(mtmp))
+                   ways_seen++;
+
+               if (ways_seen > 1 || !normal) {
+                   if (normal) {
+                       Strcat(monbuf, "normal vision");
+                       /* can't actually be 1 yet here */
+                       if (ways_seen-- > 1) Strcat(monbuf, ", ");
+                   }
+                   if (useemon && mtmp->minvis) {
+                       Strcat(monbuf, "see invisible");
+                       if (ways_seen-- > 1) Strcat(monbuf, ", ");
+                   }
+                   if ((!mtmp->minvis || See_invisible) &&
+                           see_with_infrared(mtmp)) {
+                       Strcat(monbuf, "infravision");
+                       if (ways_seen-- > 1) Strcat(monbuf, ", ");
+                   }
+                   if (tp_sensemon(mtmp)) {
+                       Strcat(monbuf, "telepathy");
+                       if (ways_seen-- > 1) Strcat(monbuf, ", ");
+                   }
+                   if (useemon && xraydist > 0 &&
+                           distu(mtmp->mx, mtmp->my) <= xraydist) {
+                       /* Eyes of the Overworld */
+                       Strcat(monbuf, "astral vision");
+                       if (ways_seen-- > 1) Strcat(monbuf, ", ");
+                   }
+                   if (Detect_monsters) {
+                       Strcat(monbuf, "monster detection");
+                       if (ways_seen-- > 1) Strcat(monbuf, ", ");
+                   }
+                   if (MATCH_WARN_OF_MON(mtmp)) {
+                       char wbuf[BUFSZ];
+                       if (Hallucination)
+                               Strcat(monbuf, "paranoid delusion");
+                       else {
+                               Sprintf(wbuf, "warned of %s",
+                                       makeplural(mtmp->data->mname));
+                               Strcat(monbuf, wbuf);
+                       }
+                       if (ways_seen-- > 1) Strcat(monbuf, ", ");
+                   }
+               }
+           }
+       }
+    }
+    else if (glyph_is_object(glyph)) {
+       struct obj *otmp = vobj_at(x,y);
+
+       if (!otmp || otmp->otyp != glyph_to_obj(glyph)) {
+           if (glyph_to_obj(glyph) != STRANGE_OBJECT) {
+               otmp = mksobj(glyph_to_obj(glyph), FALSE, FALSE);
+               if (otmp->oclass == COIN_CLASS)
+                   otmp->quan = 2L; /* to force pluralization */
+               else if (otmp->otyp == SLIME_MOLD)
+                   otmp->spe = current_fruit;  /* give the fruit a type */
+               Strcpy(buf, distant_name(otmp, xname));
+               dealloc_obj(otmp);
+           }
+       } else
+           Strcpy(buf, distant_name(otmp, xname));
+
+       if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR)
+           Strcat(buf, " embedded in stone");
+       else if (IS_WALL(levl[x][y].typ) || levl[x][y].typ == SDOOR)
+           Strcat(buf, " embedded in a wall");
+       else if (closed_door(x,y))
+           Strcat(buf, " embedded in a door");
+       else if (is_pool(x,y))
+           Strcat(buf, " in water");
+       else if (is_lava(x,y))
+           Strcat(buf, " in molten lava");     /* [can this ever happen?] */
+    } else if (glyph_is_trap(glyph)) {
+       int tnum = what_trap(glyph_to_trap(glyph));
+       Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation);
+    } else if(!glyph_is_cmap(glyph)) {
+       Strcpy(buf,"dark part of a room");
+    } else switch(glyph_to_cmap(glyph)) {
+    case S_altar:
+       if(!In_endgame(&u.uz))
+           Sprintf(buf, "%s altar",
+               align_str(Amask2align(levl[x][y].altarmask & ~AM_SHRINE)));
+       else Sprintf(buf, "aligned altar");
+       break;
+    case S_ndoor:
+       if (is_drawbridge_wall(x, y) >= 0)
+           Strcpy(buf,"open drawbridge portcullis");
+       else if ((levl[x][y].doormask & ~D_TRAPPED) == D_BROKEN)
+           Strcpy(buf,"broken door");
+       else
+           Strcpy(buf,"doorway");
+       break;
+    case S_cloud:
+       Strcpy(buf, Is_airlevel(&u.uz) ? "cloudy area" : "fog/vapor cloud");
+       break;
+    default:
+       Strcpy(buf,defsyms[glyph_to_cmap(glyph)].explanation);
+       break;
+    }
+
+    return ((pm && !Hallucination) ? pm : (struct permonst *) 0);
+}
+
+/*
+ * Look in the "data" file for more info.  Called if the user typed in the
+ * whole name (user_typed_name == TRUE), or we've found a possible match
+ * with a character/glyph and flags.help is TRUE.
+ *
+ * NOTE: when (user_typed_name == FALSE), inp is considered read-only and
+ *      must not be changed directly, e.g. via lcase(). We want to force
+ *      lcase() for data.base lookup so that we can have a clean key.
+ *      Therefore, we create a copy of inp _just_ for data.base lookup.
+ */
+STATIC_OVL void
+checkfile(inp, pm, user_typed_name, without_asking)
+    char *inp;
+    struct permonst *pm;
+    boolean user_typed_name, without_asking;
+{
+    dlb *fp;
+    char buf[BUFSZ], newstr[BUFSZ];
+    char *ep, *dbase_str;
+    long txt_offset;
+    int chk_skip;
+    boolean found_in_file = FALSE, skipping_entry = FALSE;
+
+    fp = dlb_fopen(DATAFILE, "r");
+    if (!fp) {
+       pline("Cannot open data file!");
+       return;
+    }
+
+    /* To prevent the need for entries in data.base like *ngel to account
+     * for Angel and angel, make the lookup string the same for both
+     * user_typed_name and picked name.
+     */
+    if (pm != (struct permonst *) 0 && !user_typed_name)
+       dbase_str = strcpy(newstr, pm->mname);
+    else dbase_str = strcpy(newstr, inp);
+    (void) lcase(dbase_str);
+
+    if (!strncmp(dbase_str, "interior of ", 12))
+       dbase_str += 12;
+    if (!strncmp(dbase_str, "a ", 2))
+       dbase_str += 2;
+    else if (!strncmp(dbase_str, "an ", 3))
+       dbase_str += 3;
+    else if (!strncmp(dbase_str, "the ", 4))
+       dbase_str += 4;
+    if (!strncmp(dbase_str, "tame ", 5))
+       dbase_str += 5;
+    else if (!strncmp(dbase_str, "peaceful ", 9))
+       dbase_str += 9;
+    if (!strncmp(dbase_str, "invisible ", 10))
+       dbase_str += 10;
+    if (!strncmp(dbase_str, "statue of ", 10))
+       dbase_str[6] = '\0';
+    else if (!strncmp(dbase_str, "figurine of ", 12))
+       dbase_str[8] = '\0';
+
+    /* Make sure the name is non-empty. */
+    if (*dbase_str) {
+       /* adjust the input to remove "named " and convert to lower case */
+       char *alt = 0;  /* alternate description */
+
+       if ((ep = strstri(dbase_str, " named ")) != 0)
+           alt = ep + 7;
+       else
+           ep = strstri(dbase_str, " called ");
+       if (!ep) ep = strstri(dbase_str, ", ");
+       if (ep && ep > dbase_str) *ep = '\0';
+
+       /*
+        * If the object is named, then the name is the alternate description;
+        * otherwise, the result of makesingular() applied to the name is. This
+        * isn't strictly optimal, but named objects of interest to the user
+        * will usually be found under their name, rather than under their
+        * object type, so looking for a singular form is pointless.
+        */
+
+       if (!alt)
+           alt = makesingular(dbase_str);
+       else
+           if (user_typed_name)
+               (void) lcase(alt);
+
+       /* skip first record; read second */
+       txt_offset = 0L;
+       if (!dlb_fgets(buf, BUFSZ, fp) || !dlb_fgets(buf, BUFSZ, fp)) {
+           impossible("can't read 'data' file");
+           (void) dlb_fclose(fp);
+           return;
+       } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1 || txt_offset <= 0)
+           goto bad_data_file;
+
+       /* look for the appropriate entry */
+       while (dlb_fgets(buf,BUFSZ,fp)) {
+           if (*buf == '.') break;  /* we passed last entry without success */
+
+           if (digit(*buf)) {
+               /* a number indicates the end of current entry */
+               skipping_entry = FALSE;
+           } else if (!skipping_entry) {
+               if (!(ep = index(buf, '\n'))) goto bad_data_file;
+               *ep = 0;
+               /* if we match a key that begins with "~", skip this entry */
+               chk_skip = (*buf == '~') ? 1 : 0;
+               if (pmatch(&buf[chk_skip], dbase_str) ||
+                       (alt && pmatch(&buf[chk_skip], alt))) {
+                   if (chk_skip) {
+                       skipping_entry = TRUE;
+                       continue;
+                   } else {
+                       found_in_file = TRUE;
+                       break;
+                   }
+               }
+           }
+       }
+    }
+
+    if(found_in_file) {
+       long entry_offset;
+       int  entry_count;
+       int  i;
+
+       /* skip over other possible matches for the info */
+       do {
+           if (!dlb_fgets(buf, BUFSZ, fp)) goto bad_data_file;
+       } while (!digit(*buf));
+       if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2) {
+bad_data_file: impossible("'data' file in wrong format");
+               (void) dlb_fclose(fp);
+               return;
+       }
+
+       if (user_typed_name || without_asking || yn("More info?") == 'y') {
+           winid datawin;
+
+           if (dlb_fseek(fp, txt_offset + entry_offset, SEEK_SET) < 0) {
+               pline("? Seek error on 'data' file!");
+               (void) dlb_fclose(fp);
+               return;
+           }
+           datawin = create_nhwindow(NHW_MENU);
+           for (i = 0; i < entry_count; i++) {
+               if (!dlb_fgets(buf, BUFSZ, fp)) goto bad_data_file;
+               if ((ep = index(buf, '\n')) != 0) *ep = 0;
+               if (index(buf+1, '\t') != 0) (void) tabexpand(buf+1);
+               putstr(datawin, 0, buf+1);
+           }
+           display_nhwindow(datawin, FALSE);
+           destroy_nhwindow(datawin);
+       }
+    } else if (user_typed_name)
+       pline("I don't have any information on those things.");
+
+    (void) dlb_fclose(fp);
+}
+
+/* getpos() return values */
+#define LOOK_TRADITIONAL       0       /* '.' -- ask about "more info?" */
+#define LOOK_QUICK             1       /* ',' -- skip "more info?" */
+#define LOOK_ONCE              2       /* ';' -- skip and stop looping */
+#define LOOK_VERBOSE           3       /* ':' -- show more info w/o asking */
+
+/* also used by getpos hack in do_name.c */
+const char what_is_an_unknown_object[] = "an unknown object";
+
+STATIC_OVL int
+do_look(quick)
+    boolean quick;     /* use cursor && don't search for "more info" */
+{
+    char    out_str[BUFSZ], look_buf[BUFSZ];
+    const char *x_str, *firstmatch = 0;
+    struct permonst *pm = 0;
+    int     i, ans = 0;
+    int     sym;               /* typed symbol or converted glyph */
+    int            found;              /* count of matching syms found */
+    coord   cc;                        /* screen pos of unknown glyph */
+    boolean save_verbose;      /* saved value of flags.verbose */
+    boolean from_screen;       /* question from the screen */
+    boolean need_to_look;      /* need to get explan. from glyph */
+    boolean hit_trap;          /* true if found trap explanation */
+    int skipped_venom;         /* non-zero if we ignored "splash of venom" */
+    static const char *mon_interior = "the interior of a monster";
+
+    if (quick) {
+       from_screen = TRUE;     /* yes, we want to use the cursor */
+    } else {
+       i = ynq("Specify unknown object by cursor?");
+       if (i == 'q') return 0;
+       from_screen = (i == 'y');
+    }
+
+    if (from_screen) {
+       cc.x = u.ux;
+       cc.y = u.uy;
+       sym = 0;                /* gcc -Wall lint */
+    } else {
+       getlin("Specify what? (type the word)", out_str);
+       if (out_str[0] == '\0' || out_str[0] == '\033')
+           return 0;
+
+       if (out_str[1]) {       /* user typed in a complete string */
+           checkfile(out_str, pm, TRUE, TRUE);
+           return 0;
+       }
+       sym = out_str[0];
+    }
+
+    /* Save the verbose flag, we change it later. */
+    save_verbose = flags.verbose;
+    flags.verbose = flags.verbose && !quick;
+    /*
+     * The user typed one letter, or we're identifying from the screen.
+     */
+    do {
+       /* Reset some variables. */
+       need_to_look = FALSE;
+       pm = (struct permonst *)0;
+       skipped_venom = 0;
+       found = 0;
+       out_str[0] = '\0';
+
+       if (from_screen) {
+           int glyph;  /* glyph at selected position */
+
+           if (flags.verbose)
+               pline("Please move the cursor to %s.",
+                      what_is_an_unknown_object);
+           else
+               pline("Pick an object.");
+
+           ans = getpos(&cc, quick, what_is_an_unknown_object);
+           if (ans < 0 || cc.x < 0) {
+               flags.verbose = save_verbose;
+               return 0;       /* done */
+           }
+           flags.verbose = FALSE;      /* only print long question once */
+
+           /* Convert the glyph at the selected position to a symbol. */
+           glyph = glyph_at(cc.x,cc.y);
+           if (glyph_is_cmap(glyph)) {
+               sym = showsyms[glyph_to_cmap(glyph)];
+           } else if (glyph_is_trap(glyph)) {
+               sym = showsyms[trap_to_defsym(glyph_to_trap(glyph))];
+           } else if (glyph_is_object(glyph)) {
+               sym = oc_syms[(int)objects[glyph_to_obj(glyph)].oc_class];
+               if (sym == '`' && iflags.bouldersym && (int)glyph_to_obj(glyph) == BOULDER)
+                       sym = iflags.bouldersym;
+           } else if (glyph_is_monster(glyph)) {
+               /* takes care of pets, detected, ridden, and regular mons */
+               sym = monsyms[(int)mons[glyph_to_mon(glyph)].mlet];
+           } else if (glyph_is_swallow(glyph)) {
+               sym = showsyms[glyph_to_swallow(glyph)+S_sw_tl];
+           } else if (glyph_is_invisible(glyph)) {
+               sym = DEF_INVISIBLE;
+           } else if (glyph_is_warning(glyph)) {
+               sym = glyph_to_warning(glyph);
+               sym = warnsyms[sym];
+           } else {
+               impossible("do_look:  bad glyph %d at (%d,%d)",
+                                               glyph, (int)cc.x, (int)cc.y);
+               sym = ' ';
+           }
+       }
+
+       /*
+        * Check all the possibilities, saving all explanations in a buffer.
+        * When all have been checked then the string is printed.
+        */
+
+       /* Check for monsters */
+       for (i = 0; i < MAXMCLASSES; i++) {
+           if (sym == (from_screen ? monsyms[i] : def_monsyms[i]) &&
+               monexplain[i]) {
+               need_to_look = TRUE;
+               if (!found) {
+                   Sprintf(out_str, "%c       %s", sym, an(monexplain[i]));
+                   firstmatch = monexplain[i];
+                   found++;
+               } else {
+                   found += append_str(out_str, an(monexplain[i]));
+               }
+           }
+       }
+       /* handle '@' as a special case if it refers to you and you're
+          playing a character which isn't normally displayed by that
+          symbol; firstmatch is assumed to already be set for '@' */
+       if ((from_screen ?
+               (sym == monsyms[S_HUMAN] && cc.x == u.ux && cc.y == u.uy) :
+               (sym == def_monsyms[S_HUMAN] && !iflags.showrace)) &&
+           !(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd)
+           found += append_str(out_str, "you");        /* tack on "or you" */
+
+       /*
+        * Special case: if identifying from the screen, and we're swallowed,
+        * and looking at something other than our own symbol, then just say
+        * "the interior of a monster".
+        */
+       if (u.uswallow && from_screen && is_swallow_sym(sym)) {
+           if (!found) {
+               Sprintf(out_str, "%c       %s", sym, mon_interior);
+               firstmatch = mon_interior;
+           } else {
+               found += append_str(out_str, mon_interior);
+           }
+           need_to_look = TRUE;
+       }
+
+       /* Now check for objects */
+       for (i = 1; i < MAXOCLASSES; i++) {
+           if (sym == (from_screen ? oc_syms[i] : def_oc_syms[i])) {
+               need_to_look = TRUE;
+               if (from_screen && i == VENOM_CLASS) {
+                   skipped_venom++;
+                   continue;
+               }
+               if (!found) {
+                   Sprintf(out_str, "%c       %s", sym, an(objexplain[i]));
+                   firstmatch = objexplain[i];
+                   found++;
+               } else {
+                   found += append_str(out_str, an(objexplain[i]));
+               }
+           }
+       }
+
+       if (sym == DEF_INVISIBLE) {
+           if (!found) {
+               Sprintf(out_str, "%c       %s", sym, an(invisexplain));
+               firstmatch = invisexplain;
+               found++;
+           } else {
+               found += append_str(out_str, an(invisexplain));
+           }
+       }
+
+#define is_cmap_trap(i) ((i) >= S_arrow_trap && (i) <= S_polymorph_trap)
+#define is_cmap_drawbridge(i) ((i) >= S_vodbridge && (i) <= S_hcdbridge)
+
+       /* Now check for graphics symbols */
+       for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) {
+           x_str = defsyms[i].explanation;
+           if (sym == (from_screen ? showsyms[i] : defsyms[i].sym) && *x_str) {
+               /* avoid "an air", "a water", or "a floor of a room" */
+               int article = (i == S_room) ? 2 :               /* 2=>"the" */
+                             !(strcmp(x_str, "air") == 0 ||    /* 1=>"an"  */
+                               strcmp(x_str, "water") == 0);   /* 0=>(none)*/
+
+               if (!found) {
+                   if (is_cmap_trap(i)) {
+                       Sprintf(out_str, "%c       a trap", sym);
+                       hit_trap = TRUE;
+                   } else {
+                       Sprintf(out_str, "%c       %s", sym,
+                               article == 2 ? the(x_str) :
+                               article == 1 ? an(x_str) : x_str);
+                   }
+                   firstmatch = x_str;
+                   found++;
+               } else if (!u.uswallow && !(hit_trap && is_cmap_trap(i)) &&
+                          !(found >= 3 && is_cmap_drawbridge(i))) {
+                   found += append_str(out_str,
+                                       article == 2 ? the(x_str) :
+                                       article == 1 ? an(x_str) : x_str);
+                   if (is_cmap_trap(i)) hit_trap = TRUE;
+               }
+
+               if (i == S_altar || is_cmap_trap(i))
+                   need_to_look = TRUE;
+           }
+       }
+
+       /* Now check for warning symbols */
+       for (i = 1; i < WARNCOUNT; i++) {
+           x_str = def_warnsyms[i].explanation;
+           if (sym == (from_screen ? warnsyms[i] : def_warnsyms[i].sym)) {
+               if (!found) {
+                       Sprintf(out_str, "%c       %s",
+                               sym, def_warnsyms[i].explanation);
+                       firstmatch = def_warnsyms[i].explanation;
+                       found++;
+               } else {
+                       found += append_str(out_str, def_warnsyms[i].explanation);
+               }
+               /* Kludge: warning trumps boulders on the display.
+                  Reveal the boulder too or player can get confused */
+               if (from_screen && sobj_at(BOULDER, cc.x, cc.y))
+                       Strcat(out_str, " co-located with a boulder");
+               break;  /* out of for loop*/
+           }
+       }
+    
+       /* if we ignored venom and list turned out to be short, put it back */
+       if (skipped_venom && found < 2) {
+           x_str = objexplain[VENOM_CLASS];
+           if (!found) {
+               Sprintf(out_str, "%c       %s", sym, an(x_str));
+               firstmatch = x_str;
+               found++;
+           } else {
+               found += append_str(out_str, an(x_str));
+           }
+       }
+
+       /* handle optional boulder symbol as a special case */ 
+       if (iflags.bouldersym && sym == iflags.bouldersym) {
+           if (!found) {
+               firstmatch = "boulder";
+               Sprintf(out_str, "%c       %s", sym, an(firstmatch));
+               found++;
+           } else {
+               found += append_str(out_str, "boulder");
+           }
+       }
+       
+       /*
+        * If we are looking at the screen, follow multiple possibilities or
+        * an ambiguous explanation by something more detailed.
+        */
+       if (from_screen) {
+           if (found > 1 || need_to_look) {
+               char monbuf[BUFSZ];
+               char temp_buf[BUFSZ];
+
+               pm = lookat(cc.x, cc.y, look_buf, monbuf);
+               firstmatch = look_buf;
+               if (*firstmatch) {
+                   Sprintf(temp_buf, " (%s)", firstmatch);
+                   (void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1);
+                   found = 1;  /* we have something to look up */
+               }
+               if (monbuf[0]) {
+                   Sprintf(temp_buf, " [seen: %s]", monbuf);
+                   (void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1);
+               }
+           }
+       }
+
+       /* Finally, print out our explanation. */
+       if (found) {
+           pline("%s", out_str);
+           /* check the data file for information about this thing */
+           if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE &&
+                       (ans == LOOK_VERBOSE || (flags.help && !quick))) {
+               char temp_buf[BUFSZ];
+               Strcpy(temp_buf, firstmatch);
+               checkfile(temp_buf, pm, FALSE, (boolean)(ans == LOOK_VERBOSE));
+           }
+       } else {
+           pline("I've never heard of such things.");
+       }
+
+    } while (from_screen && !quick && ans != LOOK_ONCE);
+
+    flags.verbose = save_verbose;
+    return 0;
+}
+
+
+int
+dowhatis()
+{
+       return do_look(FALSE);
+}
+
+int
+doquickwhatis()
+{
+       return do_look(TRUE);
+}
+
+int
+doidtrap()
+{
+       register struct trap *trap;
+       int x, y, tt;
+
+       if (!getdir("^")) return 0;
+       x = u.ux + u.dx;
+       y = u.uy + u.dy;
+       for (trap = ftrap; trap; trap = trap->ntrap)
+           if (trap->tx == x && trap->ty == y) {
+               if (!trap->tseen) break;
+               tt = trap->ttyp;
+               if (u.dz) {
+                   if (u.dz < 0 ? (tt == TRAPDOOR || tt == HOLE) :
+                           tt == ROCKTRAP) break;
+               }
+               tt = what_trap(tt);
+               pline("That is %s%s%s.",
+                     an(defsyms[trap_to_defsym(tt)].explanation),
+                     !trap->madeby_u ? "" : (tt == WEB) ? " woven" :
+                         /* trap doors & spiked pits can't be made by
+                            player, and should be considered at least
+                            as much "set" as "dug" anyway */
+                         (tt == HOLE || tt == PIT) ? " dug" : " set",
+                     !trap->madeby_u ? "" : " by you");
+               return 0;
+           }
+       pline("I can't see a trap there.");
+       return 0;
+}
+
+char *
+dowhatdoes_core(q, cbuf)
+char q;
+char *cbuf;
+{
+       dlb *fp;
+       char bufr[BUFSZ];
+       register char *buf = &bufr[6], *ep, ctrl, meta;
+
+       fp = dlb_fopen(CMDHELPFILE, "r");
+       if (!fp) {
+               pline("Cannot open data file!");
+               return 0;
+       }
+
+       ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0);
+       meta = ((0x80 & q) ? (0x7f & q) : 0);
+       while(dlb_fgets(buf,BUFSZ-6,fp)) {
+           if ((ctrl && *buf=='^' && *(buf+1)==ctrl) ||
+               (meta && *buf=='M' && *(buf+1)=='-' && *(buf+2)==meta) ||
+               *buf==q) {
+               ep = index(buf, '\n');
+               if(ep) *ep = 0;
+               if (ctrl && buf[2] == '\t'){
+                       buf = bufr + 1;
+                       (void) strncpy(buf, "^?      ", 8);
+                       buf[1] = ctrl;
+               } else if (meta && buf[3] == '\t'){
+                       buf = bufr + 2;
+                       (void) strncpy(buf, "M-?     ", 8);
+                       buf[2] = meta;
+               } else if(buf[1] == '\t'){
+                       buf = bufr;
+                       buf[0] = q;
+                       (void) strncpy(buf+1, "       ", 7);
+               }
+               (void) dlb_fclose(fp);
+               Strcpy(cbuf, buf);
+               return cbuf;
+           }
+       }
+       (void) dlb_fclose(fp);
+       return (char *)0;
+}
+
+int
+dowhatdoes()
+{
+       char bufr[BUFSZ];
+       char q, *reslt;
+
+#if defined(UNIX) || defined(VMS)
+       introff();
+#endif
+       q = yn_function("What command?", (char *)0, '\0');
+#if defined(UNIX) || defined(VMS)
+       intron();
+#endif
+       reslt = dowhatdoes_core(q, bufr);
+       if (reslt)
+               pline("%s", reslt);
+       else
+               pline("I've never heard of such commands.");
+       return 0;
+}
+
+/* data for help_menu() */
+static const char *help_menu_items[] = {
+/* 0*/ "Long description of the game and commands.",
+/* 1*/ "List of game commands.",
+/* 2*/ "Concise history of NetHack.",
+/* 3*/ "Info on a character in the game display.",
+/* 4*/ "Info on what a given key does.",
+/* 5*/ "List of game options.",
+/* 6*/ "Longer explanation of game options.",
+/* 7*/ "List of extended commands.",
+/* 8*/ "The NetHack license.",
+#ifdef PORT_HELP
+       "%s-specific help and commands.",
+#define PORT_HELP_ID 100
+#define WIZHLP_SLOT 10
+#else
+#define WIZHLP_SLOT 9
+#endif
+#ifdef WIZARD
+       "List of wizard-mode commands.",
+#endif
+       "",
+       (char *)0
+};
+
+STATIC_OVL boolean
+help_menu(sel)
+       int *sel;
+{
+       winid tmpwin = create_nhwindow(NHW_MENU);
+#ifdef PORT_HELP
+       char helpbuf[QBUFSZ];
+#endif
+       int i, n;
+       menu_item *selected;
+       anything any;
+
+       any.a_void = 0;         /* zero all bits */
+       start_menu(tmpwin);
+#ifdef WIZARD
+       if (!wizard) help_menu_items[WIZHLP_SLOT] = "",
+                    help_menu_items[WIZHLP_SLOT+1] = (char *)0;
+#endif
+       for (i = 0; help_menu_items[i]; i++)
+#ifdef PORT_HELP
+           /* port-specific line has a %s in it for the PORT_ID */
+           if (help_menu_items[i][0] == '%') {
+               Sprintf(helpbuf, help_menu_items[i], PORT_ID);
+               any.a_int = PORT_HELP_ID + 1;
+               add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                        helpbuf, MENU_UNSELECTED);
+           } else
+#endif
+           {
+               any.a_int = (*help_menu_items[i]) ? i+1 : 0;
+               add_menu(tmpwin, NO_GLYPH, &any, 0, 0,
+                       ATR_NONE, help_menu_items[i], MENU_UNSELECTED);
+           }
+       end_menu(tmpwin, "Select one item:");
+       n = select_menu(tmpwin, PICK_ONE, &selected);
+       destroy_nhwindow(tmpwin);
+       if (n > 0) {
+           *sel = selected[0].item.a_int - 1;
+           free((genericptr_t)selected);
+           return TRUE;
+       }
+       return FALSE;
+}
+
+int
+dohelp()
+{
+       int sel = 0;
+
+       if (help_menu(&sel)) {
+               switch (sel) {
+                       case  0:  display_file(HELP, TRUE);  break;
+                       case  1:  display_file(SHELP, TRUE);  break;
+                       case  2:  (void) dohistory();  break;
+                       case  3:  (void) dowhatis();  break;
+                       case  4:  (void) dowhatdoes();  break;
+                       case  5:  option_help();  break;
+                       case  6:  display_file(OPTIONFILE, TRUE);  break;
+                       case  7:  (void) doextlist();  break;
+                       case  8:  display_file(LICENSE, TRUE);  break;
+#ifdef WIZARD
+                       /* handle slot 9 or 10 */
+                       default: display_file(DEBUGHELP, TRUE);  break;
+#endif
+#ifdef PORT_HELP
+                       case PORT_HELP_ID:  port_help();  break;
+#endif
+               }
+       }
+       return 0;
+}
+
+int
+dohistory()
+{
+       display_file(HISTORY, TRUE);
+       return 0;
+}
+
+/*pager.c*/
diff --git a/src/pickup.c b/src/pickup.c
new file mode 100644 (file)
index 0000000..07be607
--- /dev/null
@@ -0,0 +1,2417 @@
+/*     SCCS Id: @(#)pickup.c   3.4     2003/07/27      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *     Contains code for picking objects up, and container use.
+ */
+
+#include "hack.h"
+
+STATIC_DCL void FDECL(simple_look, (struct obj *,BOOLEAN_P));
+#ifndef GOLDOBJ
+STATIC_DCL boolean FDECL(query_classes, (char *,boolean *,boolean *,
+               const char *,struct obj *,BOOLEAN_P,BOOLEAN_P,int *));
+#else
+STATIC_DCL boolean FDECL(query_classes, (char *,boolean *,boolean *,
+               const char *,struct obj *,BOOLEAN_P,int *));
+#endif
+STATIC_DCL void FDECL(check_here, (BOOLEAN_P));
+STATIC_DCL boolean FDECL(n_or_more, (struct obj *));
+STATIC_DCL boolean FDECL(all_but_uchain, (struct obj *));
+#if 0 /* not used */
+STATIC_DCL boolean FDECL(allow_cat_no_uchain, (struct obj *));
+#endif
+STATIC_DCL int FDECL(autopick, (struct obj*, int, menu_item **));
+STATIC_DCL int FDECL(count_categories, (struct obj *,int));
+STATIC_DCL long FDECL(carry_count,
+                     (struct obj *,struct obj *,long,BOOLEAN_P,int *,int *));
+STATIC_DCL int FDECL(lift_object, (struct obj *,struct obj *,long *,BOOLEAN_P));
+STATIC_DCL boolean FDECL(mbag_explodes, (struct obj *,int));
+STATIC_PTR int FDECL(in_container,(struct obj *));
+STATIC_PTR int FDECL(ck_bag,(struct obj *));
+STATIC_PTR int FDECL(out_container,(struct obj *));
+STATIC_DCL long FDECL(mbag_item_gone, (int,struct obj *));
+STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *));
+STATIC_DCL int FDECL(menu_loot, (int, struct obj *, BOOLEAN_P));
+STATIC_DCL int FDECL(in_or_out_menu, (const char *,struct obj *, BOOLEAN_P, BOOLEAN_P));
+STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P));
+STATIC_DCL boolean FDECL(able_to_loot, (int, int));
+STATIC_DCL boolean FDECL(mon_beside, (int, int));
+
+/* define for query_objlist() and autopickup() */
+#define FOLLOW(curr, flags) \
+    (((flags) & BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj)
+
+/*
+ *  How much the weight of the given container will change when the given
+ *  object is removed from it.  This calculation must match the one used
+ *  by weight() in mkobj.c.
+ */
+#define DELTA_CWT(cont,obj)            \
+    ((cont)->cursed ? (obj)->owt * 2 : \
+                     1 + ((obj)->owt / ((cont)->blessed ? 4 : 2)))
+#define GOLD_WT(n)             (((n) + 50L) / 100L)
+/* if you can figure this out, give yourself a hearty pat on the back... */
+#define GOLD_CAPACITY(w,n)     (((w) * -100L) - ((n) + 50L) - 1L)
+
+static const char moderateloadmsg[] = "You have a little trouble lifting";
+static const char nearloadmsg[] = "You have much trouble lifting";
+static const char overloadmsg[] = "You have extreme difficulty lifting";
+
+/* BUG: this lets you look at cockatrice corpses while blind without
+   touching them */
+/* much simpler version of the look-here code; used by query_classes() */
+STATIC_OVL void
+simple_look(otmp, here)
+struct obj *otmp;      /* list of objects */
+boolean here;          /* flag for type of obj list linkage */
+{
+       /* Neither of the first two cases is expected to happen, since
+        * we're only called after multiple classes of objects have been
+        * detected, hence multiple objects must be present.
+        */
+       if (!otmp) {
+           impossible("simple_look(null)");
+       } else if (!(here ? otmp->nexthere : otmp->nobj)) {
+           pline("%s", doname(otmp));
+       } else {
+           winid tmpwin = create_nhwindow(NHW_MENU);
+           putstr(tmpwin, 0, "");
+           do {
+               putstr(tmpwin, 0, doname(otmp));
+               otmp = here ? otmp->nexthere : otmp->nobj;
+           } while (otmp);
+           display_nhwindow(tmpwin, TRUE);
+           destroy_nhwindow(tmpwin);
+       }
+}
+
+#ifndef GOLDOBJ
+int
+collect_obj_classes(ilets, otmp, here, incl_gold, filter, itemcount)
+char ilets[];
+register struct obj *otmp;
+boolean here, incl_gold;
+boolean FDECL((*filter),(OBJ_P));
+int *itemcount;
+#else
+int
+collect_obj_classes(ilets, otmp, here, filter, itemcount)
+char ilets[];
+register struct obj *otmp;
+boolean here;
+boolean FDECL((*filter),(OBJ_P));
+int *itemcount;
+#endif
+{
+       register int iletct = 0;
+       register char c;
+
+       *itemcount = 0;
+#ifndef GOLDOBJ
+       if (incl_gold)
+           ilets[iletct++] = def_oc_syms[COIN_CLASS];
+#endif
+       ilets[iletct] = '\0'; /* terminate ilets so that index() will work */
+       while (otmp) {
+           c = def_oc_syms[(int)otmp->oclass];
+           if (!index(ilets, c) && (!filter || (*filter)(otmp)))
+               ilets[iletct++] = c,  ilets[iletct] = '\0';
+           *itemcount += 1;
+           otmp = here ? otmp->nexthere : otmp->nobj;
+       }
+
+       return iletct;
+}
+
+/*
+ * Suppose some '?' and '!' objects are present, but '/' objects aren't:
+ *     "a" picks all items without further prompting;
+ *     "A" steps through all items, asking one by one;
+ *     "?" steps through '?' items, asking, and ignores '!' ones;
+ *     "/" becomes 'A', since no '/' present;
+ *     "?a" or "a?" picks all '?' without further prompting;
+ *     "/a" or "a/" becomes 'A' since there aren't any '/'
+ *         (bug fix:  3.1.0 thru 3.1.3 treated it as "a");
+ *     "?/a" or "a?/" or "/a?",&c picks all '?' even though no '/'
+ *         (ie, treated as if it had just been "?a").
+ */
+#ifndef GOLDOBJ
+STATIC_OVL boolean
+query_classes(oclasses, one_at_a_time, everything, action, objs,
+             here, incl_gold, menu_on_demand)
+char oclasses[];
+boolean *one_at_a_time, *everything;
+const char *action;
+struct obj *objs;
+boolean here, incl_gold;
+int *menu_on_demand;
+#else
+STATIC_OVL boolean
+query_classes(oclasses, one_at_a_time, everything, action, objs,
+             here, menu_on_demand)
+char oclasses[];
+boolean *one_at_a_time, *everything;
+const char *action;
+struct obj *objs;
+boolean here;
+int *menu_on_demand;
+#endif
+{
+       char ilets[20], inbuf[BUFSZ];
+       int iletct, oclassct;
+       boolean not_everything;
+       char qbuf[QBUFSZ];
+       boolean m_seen;
+       int itemcount;
+
+       oclasses[oclassct = 0] = '\0';
+       *one_at_a_time = *everything = m_seen = FALSE;
+       iletct = collect_obj_classes(ilets, objs, here,
+#ifndef GOLDOBJ
+                                    incl_gold,
+#endif
+                                    (boolean FDECL((*),(OBJ_P))) 0, &itemcount);
+       if (iletct == 0) {
+               return FALSE;
+       } else if (iletct == 1) {
+               oclasses[0] = def_char_to_objclass(ilets[0]);
+               oclasses[1] = '\0';
+               if (itemcount && menu_on_demand) {
+                       ilets[iletct++] = 'm';
+                       *menu_on_demand = 0;
+                       ilets[iletct] = '\0';
+               }
+       } else  {       /* more than one choice available */
+               const char *where = 0;
+               register char sym, oc_of_sym, *p;
+               /* additional choices */
+               ilets[iletct++] = ' ';
+               ilets[iletct++] = 'a';
+               ilets[iletct++] = 'A';
+               ilets[iletct++] = (objs == invent ? 'i' : ':');
+               if (menu_on_demand) {
+                       ilets[iletct++] = 'm';
+                       *menu_on_demand = 0;
+               }
+               ilets[iletct] = '\0';
+ask_again:
+               oclasses[oclassct = 0] = '\0';
+               *one_at_a_time = *everything = FALSE;
+               not_everything = FALSE;
+               Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
+                       action, ilets);
+               getlin(qbuf,inbuf);
+               if (*inbuf == '\033') return FALSE;
+
+               for (p = inbuf; (sym = *p++); ) {
+                   /* new A function (selective all) added by GAN 01/09/87 */
+                   if (sym == ' ') continue;
+                   else if (sym == 'A') *one_at_a_time = TRUE;
+                   else if (sym == 'a') *everything = TRUE;
+                   else if (sym == ':') {
+                       simple_look(objs, here);  /* dumb if objs==invent */
+                       goto ask_again;
+                   } else if (sym == 'i') {
+                       (void) display_inventory((char *)0, TRUE);
+                       goto ask_again;
+                   } else if (sym == 'm') {
+                       m_seen = TRUE;
+                   } else {
+                       oc_of_sym = def_char_to_objclass(sym);
+                       if (index(ilets,sym)) {
+                           add_valid_menu_class(oc_of_sym);
+                           oclasses[oclassct++] = oc_of_sym;
+                           oclasses[oclassct] = '\0';
+                       } else {
+                           if (!where)
+                               where = !strcmp(action,"pick up")  ? "here" :
+                                       !strcmp(action,"take out") ?
+                                                           "inside" : "";
+                           if (*where)
+                               There("are no %c's %s.", sym, where);
+                           else
+                               You("have no %c's.", sym);
+                           not_everything = TRUE;
+                       }
+                   }
+               }
+               if (m_seen && menu_on_demand) {
+                       *menu_on_demand = (*everything || !oclassct) ? -2 : -3;
+                       return FALSE;
+               }
+               if (!oclassct && (!*everything || not_everything)) {
+                   /* didn't pick anything,
+                      or tried to pick something that's not present */
+                   *one_at_a_time = TRUE;      /* force 'A' */
+                   *everything = FALSE;        /* inhibit 'a' */
+               }
+       }
+       return TRUE;
+}
+
+/* look at the objects at our location, unless there are too many of them */
+STATIC_OVL void
+check_here(picked_some)
+boolean picked_some;
+{
+       register struct obj *obj;
+       register int ct = 0;
+
+       /* count the objects here */
+       for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) {
+           if (obj != uchain)
+               ct++;
+       }
+
+       /* If there are objects here, take a look. */
+       if (ct) {
+           if (flags.run) nomul(0);
+           flush_screen(1);
+           (void) look_here(ct, picked_some);
+       } else {
+           read_engr_at(u.ux,u.uy);
+       }
+}
+
+/* Value set by query_objlist() for n_or_more(). */
+static long val_for_n_or_more;
+
+/* query_objlist callback: return TRUE if obj's count is >= reference value */
+STATIC_OVL boolean
+n_or_more(obj)
+struct obj *obj;
+{
+    if (obj == uchain) return FALSE;
+    return (obj->quan >= val_for_n_or_more);
+}
+
+/* List of valid menu classes for query_objlist() and allow_category callback */
+static char valid_menu_classes[MAXOCLASSES + 2];
+
+void
+add_valid_menu_class(c)
+int c;
+{
+       static int vmc_count = 0;
+
+       if (c == 0)  /* reset */
+         vmc_count = 0;
+       else
+         valid_menu_classes[vmc_count++] = (char)c;
+       valid_menu_classes[vmc_count] = '\0';
+}
+
+/* query_objlist callback: return TRUE if not uchain */
+STATIC_OVL boolean
+all_but_uchain(obj)
+struct obj *obj;
+{
+    return (obj != uchain);
+}
+
+/* query_objlist callback: return TRUE */
+/*ARGSUSED*/
+boolean
+allow_all(obj)
+struct obj *obj;
+{
+    return TRUE;
+}
+
+boolean
+allow_category(obj)
+struct obj *obj;
+{
+    if (Role_if(PM_PRIEST)) obj->bknown = TRUE;
+    if (((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) ||
+       (index(valid_menu_classes, obj->oclass) != (char *)0))
+       return TRUE;
+    else if (((index(valid_menu_classes,'U') != (char *)0) &&
+       (obj->oclass != COIN_CLASS && obj->bknown && !obj->blessed && !obj->cursed)))
+       return TRUE;
+    else if (((index(valid_menu_classes,'B') != (char *)0) &&
+       (obj->oclass != COIN_CLASS && obj->bknown && obj->blessed)))
+       return TRUE;
+    else if (((index(valid_menu_classes,'C') != (char *)0) &&
+       (obj->oclass != COIN_CLASS && obj->bknown && obj->cursed)))
+       return TRUE;
+    else if (((index(valid_menu_classes,'X') != (char *)0) &&
+       (obj->oclass != COIN_CLASS && !obj->bknown)))
+       return TRUE;
+    else
+       return FALSE;
+}
+
+#if 0 /* not used */
+/* query_objlist callback: return TRUE if valid category (class), no uchain */
+STATIC_OVL boolean
+allow_cat_no_uchain(obj)
+struct obj *obj;
+{
+    if ((obj != uchain) &&
+       (((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) ||
+       (index(valid_menu_classes, obj->oclass) != (char *)0)))
+       return TRUE;
+    else
+       return FALSE;
+}
+#endif
+
+/* query_objlist callback: return TRUE if valid class and worn */
+boolean
+is_worn_by_type(otmp)
+register struct obj *otmp;
+{
+       return((boolean)(!!(otmp->owornmask &
+                       (W_ARMOR | W_RING | W_AMUL | W_TOOL | W_WEP | W_SWAPWEP | W_QUIVER)))
+               && (index(valid_menu_classes, otmp->oclass) != (char *)0));
+}
+
+/*
+ * Have the hero pick things from the ground
+ * or a monster's inventory if swallowed.
+ *
+ * Arg what:
+ *     >0  autopickup
+ *     =0  interactive
+ *     <0  pickup count of something
+ *
+ * Returns 1 if tried to pick something up, whether
+ * or not it succeeded.
+ */
+int
+pickup(what)
+int what;              /* should be a long */
+{
+       int i, n, res, count, n_tried = 0, n_picked = 0;
+       menu_item *pick_list = (menu_item *) 0;
+       boolean autopickup = what > 0;
+       struct obj *objchain;
+       int traverse_how;
+
+       if (what < 0)           /* pick N of something */
+           count = -what;
+       else                    /* pick anything */
+           count = 0;
+
+       if (!u.uswallow) {
+               struct trap *ttmp = t_at(u.ux, u.uy);
+               /* no auto-pick if no-pick move, nothing there, or in a pool */
+               if (autopickup && (flags.nopick || !OBJ_AT(u.ux, u.uy) ||
+                       (is_pool(u.ux, u.uy) && !Underwater) || is_lava(u.ux, u.uy))) {
+                       read_engr_at(u.ux, u.uy);
+                       return (0);
+               }
+
+               /* no pickup if levitating & not on air or water level */
+               if (!can_reach_floor()) {
+                   if ((multi && !flags.run) || (autopickup && !flags.pickup))
+                       read_engr_at(u.ux, u.uy);
+                   return (0);
+               }
+               if (ttmp && ttmp->tseen) {
+                   /* Allow pickup from holes and trap doors that you escaped
+                    * from because that stuff is teetering on the edge just
+                    * like you, but not pits, because there is an elevation
+                    * discrepancy with stuff in pits.
+                    */
+                   if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) &&
+                       (!u.utrap || (u.utrap && u.utraptype != TT_PIT))) {
+                       read_engr_at(u.ux, u.uy);
+                       return(0);
+                   }
+               }
+               /* multi && !flags.run means they are in the middle of some other
+                * action, or possibly paralyzed, sleeping, etc.... and they just
+                * teleported onto the object.  They shouldn't pick it up.
+                */
+               if ((multi && !flags.run) || (autopickup && !flags.pickup)) {
+                   check_here(FALSE);
+                   return (0);
+               }
+               if (notake(youmonst.data)) {
+                   if (!autopickup)
+                       You("are physically incapable of picking anything up.");
+                   else
+                       check_here(FALSE);
+                   return (0);
+               }
+
+               /* if there's anything here, stop running */
+               if (OBJ_AT(u.ux,u.uy) && flags.run && flags.run != 8 && !flags.nopick) nomul(0);
+       }
+
+       add_valid_menu_class(0);        /* reset */
+       if (!u.uswallow) {
+               objchain = level.objects[u.ux][u.uy];
+               traverse_how = BY_NEXTHERE;
+       } else {
+               objchain = u.ustuck->minvent;
+               traverse_how = 0;       /* nobj */
+       }
+       /*
+        * Start the actual pickup process.  This is split into two main
+        * sections, the newer menu and the older "traditional" methods.
+        * Automatic pickup has been split into its own menu-style routine
+        * to make things less confusing.
+        */
+       if (autopickup) {
+           n = autopick(objchain, traverse_how, &pick_list);
+           goto menu_pickup;
+       }
+
+       if (flags.menu_style != MENU_TRADITIONAL || iflags.menu_requested) {
+
+           /* use menus exclusively */
+           if (count) {        /* looking for N of something */
+               char buf[QBUFSZ];
+               Sprintf(buf, "Pick %d of what?", count);
+               val_for_n_or_more = count;      /* set up callback selector */
+               n = query_objlist(buf, objchain,
+                           traverse_how|AUTOSELECT_SINGLE|INVORDER_SORT,
+                           &pick_list, PICK_ONE, n_or_more);
+               /* correct counts, if any given */
+               for (i = 0; i < n; i++)
+                   pick_list[i].count = count;
+           } else {
+               n = query_objlist("Pick up what?", objchain,
+                       traverse_how|AUTOSELECT_SINGLE|INVORDER_SORT|FEEL_COCKATRICE,
+                       &pick_list, PICK_ANY, all_but_uchain);
+           }
+menu_pickup:
+           n_tried = n;
+           for (n_picked = i = 0 ; i < n; i++) {
+               res = pickup_object(pick_list[i].item.a_obj,pick_list[i].count,
+                                       FALSE);
+               if (res < 0) break;     /* can't continue */
+               n_picked += res;
+           }
+           if (pick_list) free((genericptr_t)pick_list);
+
+       } else {
+           /* old style interface */
+           int ct = 0;
+           long lcount;
+           boolean all_of_a_type, selective;
+           char oclasses[MAXOCLASSES];
+           struct obj *obj, *obj2;
+
+           oclasses[0] = '\0';         /* types to consider (empty for all) */
+           all_of_a_type = TRUE;       /* take all of considered types */
+           selective = FALSE;          /* ask for each item */
+
+           /* check for more than one object */
+           for (obj = objchain;
+                 obj; obj = (traverse_how == BY_NEXTHERE) ? obj->nexthere : obj->nobj)
+               ct++;
+
+           if (ct == 1 && count) {
+               /* if only one thing, then pick it */
+               obj = objchain;
+               lcount = min(obj->quan, (long)count);
+               n_tried++;
+               if (pickup_object(obj, lcount, FALSE) > 0)
+                   n_picked++; /* picked something */
+               goto end_query;
+
+           } else if (ct >= 2) {
+               int via_menu = 0;
+
+               There("are %s objects here.",
+                     (ct <= 10) ? "several" : "many");
+               if (!query_classes(oclasses, &selective, &all_of_a_type,
+                                  "pick up", objchain,
+                                  traverse_how == BY_NEXTHERE,
+#ifndef GOLDOBJ
+                                  FALSE,
+#endif
+                                  &via_menu)) {
+                   if (!via_menu) return (0);
+                   n = query_objlist("Pick up what?",
+                                 objchain,
+                                 traverse_how|(selective ? 0 : INVORDER_SORT),
+                                 &pick_list, PICK_ANY,
+                                 via_menu == -2 ? allow_all : allow_category);
+                   goto menu_pickup;
+               }
+           }
+
+           for (obj = objchain; obj; obj = obj2) {
+               if (traverse_how == BY_NEXTHERE)
+                       obj2 = obj->nexthere;   /* perhaps obj will be picked up */
+               else
+                       obj2 = obj->nobj;
+               lcount = -1L;
+
+               if (!selective && oclasses[0] && !index(oclasses,obj->oclass))
+                   continue;
+
+               if (!all_of_a_type) {
+                   char qbuf[BUFSZ];
+                   Sprintf(qbuf, "Pick up %s?",
+                       safe_qbuf("", sizeof("Pick up ?"), doname(obj),
+                                       an(simple_typename(obj->otyp)), "something"));
+                   switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) {
+                   case 'q': goto end_query;   /* out 2 levels */
+                   case 'n': continue;
+                   case 'a':
+                       all_of_a_type = TRUE;
+                       if (selective) {
+                           selective = FALSE;
+                           oclasses[0] = obj->oclass;
+                           oclasses[1] = '\0';
+                       }
+                       break;
+                   case '#':   /* count was entered */
+                       if (!yn_number) continue; /* 0 count => No */
+                       lcount = (long) yn_number;
+                       if (lcount > obj->quan) lcount = obj->quan;
+                       /* fall thru */
+                   default:    /* 'y' */
+                       break;
+                   }
+               }
+               if (lcount == -1L) lcount = obj->quan;
+
+               n_tried++;
+               if ((res = pickup_object(obj, lcount, FALSE)) < 0) break;
+               n_picked += res;
+           }
+end_query:
+           ;   /* semicolon needed by brain-damaged compilers */
+       }
+
+       if (!u.uswallow) {
+               if (!OBJ_AT(u.ux,u.uy)) u.uundetected = 0;
+
+               /* position may need updating (invisible hero) */
+               if (n_picked) newsym(u.ux,u.uy);
+
+               /* see whether there's anything else here, after auto-pickup is done */
+               if (autopickup) check_here(n_picked > 0);
+       }
+       return (n_tried > 0);
+}
+
+#ifdef AUTOPICKUP_EXCEPTIONS
+boolean
+is_autopickup_exception(obj, grab)
+struct obj *obj;
+boolean grab;   /* forced pickup, rather than forced leave behind? */
+{
+       /*
+        *  Does the text description of this match an exception?
+        */
+       char *objdesc = makesingular(doname(obj));
+       struct autopickup_exception *ape = (grab) ?
+                                       iflags.autopickup_exceptions[AP_GRAB] :
+                                       iflags.autopickup_exceptions[AP_LEAVE];
+       while (ape) {
+               if (pmatch(ape->pattern, objdesc)) return TRUE;
+               ape = ape->next;
+       }
+       return FALSE;
+}
+#endif /* AUTOPICKUP_EXCEPTIONS */
+
+/*
+ * Pick from the given list using flags.pickup_types.  Return the number
+ * of items picked (not counts).  Create an array that returns pointers
+ * and counts of the items to be picked up.  If the number of items
+ * picked is zero, the pickup list is left alone.  The caller of this
+ * function must free the pickup list.
+ */
+STATIC_OVL int
+autopick(olist, follow, pick_list)
+struct obj *olist;     /* the object list */
+int follow;            /* how to follow the object list */
+menu_item **pick_list; /* list of objects and counts to pick up */
+{
+       menu_item *pi;  /* pick item */
+       struct obj *curr;
+       int n;
+       const char *otypes = flags.pickup_types;
+
+       /* first count the number of eligible items */
+       for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow))
+
+
+#ifndef AUTOPICKUP_EXCEPTIONS
+           if (!*otypes || index(otypes, curr->oclass))
+#else
+           if ((!*otypes || index(otypes, curr->oclass) ||
+                is_autopickup_exception(curr, TRUE)) &&
+                !is_autopickup_exception(curr, FALSE))
+#endif
+               n++;
+
+       if (n) {
+           *pick_list = pi = (menu_item *) alloc(sizeof(menu_item) * n);
+           for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow))
+#ifndef AUTOPICKUP_EXCEPTIONS
+               if (!*otypes || index(otypes, curr->oclass)) {
+#else
+           if ((!*otypes || index(otypes, curr->oclass) ||
+                is_autopickup_exception(curr, TRUE)) &&
+                !is_autopickup_exception(curr, FALSE)) {
+#endif
+                   pi[n].item.a_obj = curr;
+                   pi[n].count = curr->quan;
+                   n++;
+               }
+       }
+       return n;
+}
+
+
+/*
+ * Put up a menu using the given object list.  Only those objects on the
+ * list that meet the approval of the allow function are displayed.  Return
+ * a count of the number of items selected, as well as an allocated array of
+ * menu_items, containing pointers to the objects selected and counts.  The
+ * returned counts are guaranteed to be in bounds and non-zero.
+ *
+ * Query flags:
+ *     BY_NEXTHERE       - Follow object list via nexthere instead of nobj.
+ *     AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just
+ *                         use it.
+ *     USE_INVLET        - Use object's invlet.
+ *     INVORDER_SORT     - Use hero's pack order.
+ *     SIGNAL_NOMENU     - Return -1 rather than 0 if nothing passes "allow".
+ */
+int
+query_objlist(qstr, olist, qflags, pick_list, how, allow)
+const char *qstr;              /* query string */
+struct obj *olist;             /* the list to pick from */
+int qflags;                    /* options to control the query */
+menu_item **pick_list;         /* return list of items picked */
+int how;                       /* type of query */
+boolean FDECL((*allow), (OBJ_P));/* allow function */
+{
+       int n;
+       winid win;
+       struct obj *curr, *last;
+       char *pack;
+       anything any;
+       boolean printed_type_name;
+
+       *pick_list = (menu_item *) 0;
+       if (!olist) return 0;
+
+       /* count the number of items allowed */
+       for (n = 0, last = 0, curr = olist; curr; curr = FOLLOW(curr, qflags))
+           if ((*allow)(curr)) {
+               last = curr;
+               n++;
+           }
+
+       if (n == 0)     /* nothing to pick here */
+           return (qflags & SIGNAL_NOMENU) ? -1 : 0;
+
+       if (n == 1 && (qflags & AUTOSELECT_SINGLE)) {
+           *pick_list = (menu_item *) alloc(sizeof(menu_item));
+           (*pick_list)->item.a_obj = last;
+           (*pick_list)->count = last->quan;
+           return 1;
+       }
+
+       win = create_nhwindow(NHW_MENU);
+       start_menu(win);
+       any.a_obj = (struct obj *) 0;
+
+       /*
+        * Run through the list and add the objects to the menu.  If
+        * INVORDER_SORT is set, we'll run through the list once for
+        * each type so we can group them.  The allow function will only
+        * be called once per object in the list.
+        */
+       pack = flags.inv_order;
+       do {
+           printed_type_name = FALSE;
+           for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
+               if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE &&
+                    will_feel_cockatrice(curr, FALSE)) {
+                       destroy_nhwindow(win);  /* stop the menu and revert */
+                       (void) look_here(0, FALSE);
+                       return 0;
+               }
+               if ((!(qflags & INVORDER_SORT) || curr->oclass == *pack)
+                                                       && (*allow)(curr)) {
+
+                   /* if sorting, print type name (once only) */
+                   if (qflags & INVORDER_SORT && !printed_type_name) {
+                       any.a_obj = (struct obj *) 0;
+                       add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
+                                       let_to_name(*pack, FALSE), MENU_UNSELECTED);
+                       printed_type_name = TRUE;
+                   }
+
+                   any.a_obj = curr;
+                   add_menu(win, obj_to_glyph(curr), &any,
+                           qflags & USE_INVLET ? curr->invlet : 0,
+                           def_oc_syms[(int)objects[curr->otyp].oc_class],
+                           ATR_NONE, doname(curr), MENU_UNSELECTED);
+               }
+           }
+           pack++;
+       } while (qflags & INVORDER_SORT && *pack);
+
+       end_menu(win, qstr);
+       n = select_menu(win, how, pick_list);
+       destroy_nhwindow(win);
+
+       if (n > 0) {
+           menu_item *mi;
+           int i;
+
+           /* fix up counts:  -1 means no count used => pick all */
+           for (i = 0, mi = *pick_list; i < n; i++, mi++)
+               if (mi->count == -1L || mi->count > mi->item.a_obj->quan)
+                   mi->count = mi->item.a_obj->quan;
+       } else if (n < 0) {
+           n = 0;      /* caller's don't expect -1 */
+       }
+       return n;
+}
+
+/*
+ * allow menu-based category (class) selection (for Drop,take off etc.)
+ *
+ */
+int
+query_category(qstr, olist, qflags, pick_list, how)
+const char *qstr;              /* query string */
+struct obj *olist;             /* the list to pick from */
+int qflags;                    /* behaviour modification flags */
+menu_item **pick_list;         /* return list of items picked */
+int how;                       /* type of query */
+{
+       int n;
+       winid win;
+       struct obj *curr;
+       char *pack;
+       anything any;
+       boolean collected_type_name;
+       char invlet;
+       int ccount;
+       boolean do_unpaid = FALSE;
+       boolean do_blessed = FALSE, do_cursed = FALSE, do_uncursed = FALSE,
+           do_buc_unknown = FALSE;
+       int num_buc_types = 0;
+
+       *pick_list = (menu_item *) 0;
+       if (!olist) return 0;
+       if ((qflags & UNPAID_TYPES) && count_unpaid(olist)) do_unpaid = TRUE;
+       if ((qflags & BUC_BLESSED) && count_buc(olist, BUC_BLESSED)) {
+           do_blessed = TRUE;
+           num_buc_types++;
+       }
+       if ((qflags & BUC_CURSED) && count_buc(olist, BUC_CURSED)) {
+           do_cursed = TRUE;
+           num_buc_types++;
+       }
+       if ((qflags & BUC_UNCURSED) && count_buc(olist, BUC_UNCURSED)) {
+           do_uncursed = TRUE;
+           num_buc_types++;
+       }
+       if ((qflags & BUC_UNKNOWN) && count_buc(olist, BUC_UNKNOWN)) {
+           do_buc_unknown = TRUE;
+           num_buc_types++;
+       }
+
+       ccount = count_categories(olist, qflags);
+       /* no point in actually showing a menu for a single category */
+       if (ccount == 1 && !do_unpaid && num_buc_types <= 1 && !(qflags & BILLED_TYPES)) {
+           for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
+               if ((qflags & WORN_TYPES) &&
+                   !(curr->owornmask & (W_ARMOR|W_RING|W_AMUL|W_TOOL|W_WEP|W_SWAPWEP|W_QUIVER)))
+                   continue;
+               break;
+           }
+           if (curr) {
+               *pick_list = (menu_item *) alloc(sizeof(menu_item));
+               (*pick_list)->item.a_int = curr->oclass;
+               return 1;
+           } else {
+#ifdef DEBUG
+               impossible("query_category: no single object match");
+#endif
+           }
+           return 0;
+       }
+
+       win = create_nhwindow(NHW_MENU);
+       start_menu(win);
+       pack = flags.inv_order;
+       if ((qflags & ALL_TYPES) && (ccount > 1)) {
+               invlet = 'a';
+               any.a_void = 0;
+               any.a_int = ALL_TYPES_SELECTED;
+               add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
+                      (qflags & WORN_TYPES) ? "All worn types" : "All types",
+                       MENU_UNSELECTED);
+               invlet = 'b';
+       } else
+               invlet = 'a';
+       do {
+           collected_type_name = FALSE;
+           for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
+               if (curr->oclass == *pack) {
+                  if ((qflags & WORN_TYPES) &&
+                               !(curr->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL |
+                       W_WEP | W_SWAPWEP | W_QUIVER)))
+                        continue;
+                  if (!collected_type_name) {
+                       any.a_void = 0;
+                       any.a_int = curr->oclass;
+                       add_menu(win, NO_GLYPH, &any, invlet++,
+                               def_oc_syms[(int)objects[curr->otyp].oc_class],
+                               ATR_NONE, let_to_name(*pack, FALSE),
+                               MENU_UNSELECTED);
+                       collected_type_name = TRUE;
+                  }
+               }
+           }
+           pack++;
+           if (invlet >= 'u') {
+               impossible("query_category: too many categories");
+               return 0;
+           }
+       } while (*pack);
+       /* unpaid items if there are any */
+       if (do_unpaid) {
+               invlet = 'u';
+               any.a_void = 0;
+               any.a_int = 'u';
+               add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
+                       "Unpaid items", MENU_UNSELECTED);
+       }
+       /* billed items: checked by caller, so always include if BILLED_TYPES */
+       if (qflags & BILLED_TYPES) {
+               invlet = 'x';
+               any.a_void = 0;
+               any.a_int = 'x';
+               add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
+                        "Unpaid items already used up", MENU_UNSELECTED);
+       }
+       if (qflags & CHOOSE_ALL) {
+               invlet = 'A';
+               any.a_void = 0;
+               any.a_int = 'A';
+               add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
+                       (qflags & WORN_TYPES) ?
+                       "Auto-select every item being worn" :
+                       "Auto-select every item", MENU_UNSELECTED);
+       }
+       /* items with b/u/c/unknown if there are any */
+       if (do_blessed) {
+               invlet = 'B';
+               any.a_void = 0;
+               any.a_int = 'B';
+               add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
+                       "Items known to be Blessed", MENU_UNSELECTED);
+       }
+       if (do_cursed) {
+               invlet = 'C';
+               any.a_void = 0;
+               any.a_int = 'C';
+               add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
+                       "Items known to be Cursed", MENU_UNSELECTED);
+       }
+       if (do_uncursed) {
+               invlet = 'U';
+               any.a_void = 0;
+               any.a_int = 'U';
+               add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
+                       "Items known to be Uncursed", MENU_UNSELECTED);
+       }
+       if (do_buc_unknown) {
+               invlet = 'X';
+               any.a_void = 0;
+               any.a_int = 'X';
+               add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
+                       "Items of unknown B/C/U status",
+                       MENU_UNSELECTED);
+       }
+       end_menu(win, qstr);
+       n = select_menu(win, how, pick_list);
+       destroy_nhwindow(win);
+       if (n < 0)
+           n = 0;      /* caller's don't expect -1 */
+       return n;
+}
+
+STATIC_OVL int
+count_categories(olist, qflags)
+struct obj *olist;
+int qflags;
+{
+       char *pack;
+       boolean counted_category;
+       int ccount = 0;
+       struct obj *curr;
+
+       pack = flags.inv_order;
+       do {
+           counted_category = FALSE;
+           for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
+               if (curr->oclass == *pack) {
+                  if ((qflags & WORN_TYPES) &&
+                       !(curr->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL |
+                       W_WEP | W_SWAPWEP | W_QUIVER)))
+                        continue;
+                  if (!counted_category) {
+                       ccount++;
+                       counted_category = TRUE;
+                  }
+               }
+           }
+           pack++;
+       } while (*pack);
+       return ccount;
+}
+
+/* could we carry `obj'? if not, could we carry some of it/them? */
+STATIC_OVL long
+carry_count(obj, container, count, telekinesis, wt_before, wt_after)
+struct obj *obj, *container;   /* object to pick up, bag it's coming out of */
+long count;
+boolean telekinesis;
+int *wt_before, *wt_after;
+{
+    boolean adjust_wt = container && carried(container),
+           is_gold = obj->oclass == COIN_CLASS;
+    int wt, iw, ow, oow;
+    long qq, savequan;
+#ifdef GOLDOBJ
+    long umoney = money_cnt(invent);
+#endif
+    unsigned saveowt;
+    const char *verb, *prefx1, *prefx2, *suffx;
+    char obj_nambuf[BUFSZ], where[BUFSZ];
+
+    savequan = obj->quan;
+    saveowt = obj->owt;
+
+    iw = max_capacity();
+
+    if (count != savequan) {
+       obj->quan = count;
+       obj->owt = (unsigned)weight(obj);
+    }
+    wt = iw + (int)obj->owt;
+    if (adjust_wt)
+       wt -= (container->otyp == BAG_OF_HOLDING) ?
+               (int)DELTA_CWT(container, obj) : (int)obj->owt;
+#ifndef GOLDOBJ
+    if (is_gold)       /* merged gold might affect cumulative weight */
+       wt -= (GOLD_WT(u.ugold) + GOLD_WT(count) - GOLD_WT(u.ugold + count));
+#else
+    /* This will go with silver+copper & new gold weight */
+    if (is_gold)       /* merged gold might affect cumulative weight */
+       wt -= (GOLD_WT(umoney) + GOLD_WT(count) - GOLD_WT(umoney + count));
+#endif
+    if (count != savequan) {
+       obj->quan = savequan;
+       obj->owt = saveowt;
+    }
+    *wt_before = iw;
+    *wt_after  = wt;
+
+    if (wt < 0)
+       return count;
+
+    /* see how many we can lift */
+    if (is_gold) {
+#ifndef GOLDOBJ
+       iw -= (int)GOLD_WT(u.ugold);
+       if (!adjust_wt) {
+           qq = GOLD_CAPACITY((long)iw, u.ugold);
+       } else {
+           oow = 0;
+           qq = 50L - (u.ugold % 100L) - 1L;
+#else
+       iw -= (int)GOLD_WT(umoney);
+       if (!adjust_wt) {
+           qq = GOLD_CAPACITY((long)iw, umoney);
+       } else {
+           oow = 0;
+           qq = 50L - (umoney % 100L) - 1L;
+#endif
+           if (qq < 0L) qq += 100L;
+           for ( ; qq <= count; qq += 100L) {
+               obj->quan = qq;
+               obj->owt = (unsigned)GOLD_WT(qq);
+#ifndef GOLDOBJ
+               ow = (int)GOLD_WT(u.ugold + qq);
+#else
+               ow = (int)GOLD_WT(umoney + qq);
+#endif
+               ow -= (container->otyp == BAG_OF_HOLDING) ?
+                       (int)DELTA_CWT(container, obj) : (int)obj->owt;
+               if (iw + ow >= 0) break;
+               oow = ow;
+           }
+           iw -= oow;
+           qq -= 100L;
+       }
+       if (qq < 0L) qq = 0L;
+       else if (qq > count) qq = count;
+#ifndef GOLDOBJ
+       wt = iw + (int)GOLD_WT(u.ugold + qq);
+#else
+       wt = iw + (int)GOLD_WT(umoney + qq);
+#endif
+    } else if (count > 1 || count < obj->quan) {
+       /*
+        * Ugh. Calc num to lift by changing the quan of of the
+        * object and calling weight.
+        *
+        * This works for containers only because containers
+        * don't merge.         -dean
+        */
+       for (qq = 1L; qq <= count; qq++) {
+           obj->quan = qq;
+           obj->owt = (unsigned)(ow = weight(obj));
+           if (adjust_wt)
+               ow -= (container->otyp == BAG_OF_HOLDING) ?
+                       (int)DELTA_CWT(container, obj) : (int)obj->owt;
+           if (iw + ow >= 0)
+               break;
+           wt = iw + ow;
+       }
+       --qq;
+    } else {
+       /* there's only one, and we can't lift it */
+       qq = 0L;
+    }
+    obj->quan = savequan;
+    obj->owt = saveowt;
+
+    if (qq < count) {
+       /* some message will be given */
+       Strcpy(obj_nambuf, doname(obj));
+       if (container) {
+           Sprintf(where, "in %s", the(xname(container)));
+           verb = "carry";
+       } else {
+           Strcpy(where, "lying here");
+           verb = telekinesis ? "acquire" : "lift";
+       }
+    } else {
+       /* lint supppression */
+       *obj_nambuf = *where = '\0';
+       verb = "";
+    }
+    /* we can carry qq of them */
+    if (qq > 0) {
+       if (qq < count)
+           You("can only %s %s of the %s %s.",
+               verb, (qq == 1L) ? "one" : "some", obj_nambuf, where);
+       *wt_after = wt;
+       return qq;
+    }
+
+    if (!container) Strcpy(where, "here");  /* slightly shorter form */
+#ifndef GOLDOBJ
+    if (invent || u.ugold) {
+#else
+    if (invent || umoney) {
+#endif
+       prefx1 = "you cannot ";
+       prefx2 = "";
+       suffx  = " any more";
+    } else {
+       prefx1 = (obj->quan == 1L) ? "it " : "even one ";
+       prefx2 = "is too heavy for you to ";
+       suffx  = "";
+    }
+    There("%s %s %s, but %s%s%s%s.",
+         otense(obj, "are"), obj_nambuf, where,
+         prefx1, prefx2, verb, suffx);
+
+ /* *wt_after = iw; */
+    return 0L;
+}
+
+/* determine whether character is able and player is willing to carry `obj' */
+STATIC_OVL
+int 
+lift_object(obj, container, cnt_p, telekinesis)
+struct obj *obj, *container;   /* object to pick up, bag it's coming out of */
+long *cnt_p;
+boolean telekinesis;
+{
+    int result, old_wt, new_wt, prev_encumbr, next_encumbr;
+
+    if (obj->otyp == BOULDER && In_sokoban(&u.uz)) {
+       You("cannot get your %s around this %s.",
+                       body_part(HAND), xname(obj));
+       return -1;
+    }
+    if (obj->otyp == LOADSTONE ||
+           (obj->otyp == BOULDER && throws_rocks(youmonst.data)))
+       return 1;               /* lift regardless of current situation */
+
+    *cnt_p = carry_count(obj, container, *cnt_p, telekinesis, &old_wt, &new_wt);
+    if (*cnt_p < 1L) {
+       result = -1;    /* nothing lifted */
+#ifndef GOLDOBJ
+    } else if (obj->oclass != COIN_CLASS && inv_cnt() >= 52 &&
+               !merge_choice(invent, obj)) {
+#else
+    } else if (inv_cnt() >= 52 && !merge_choice(invent, obj)) {
+#endif
+       Your("knapsack cannot accommodate any more items.");
+       result = -1;    /* nothing lifted */
+    } else {
+       result = 1;
+       prev_encumbr = near_capacity();
+       if (prev_encumbr < flags.pickup_burden)
+               prev_encumbr = flags.pickup_burden;
+       next_encumbr = calc_capacity(new_wt - old_wt);
+       if (next_encumbr > prev_encumbr) {
+           if (telekinesis) {
+               result = 0;     /* don't lift */
+           } else {
+               char qbuf[BUFSZ];
+               long savequan = obj->quan;
+
+               obj->quan = *cnt_p;
+               Strcpy(qbuf,
+                       (next_encumbr > HVY_ENCUMBER) ? overloadmsg :
+                       (next_encumbr > MOD_ENCUMBER) ? nearloadmsg :
+                       moderateloadmsg);
+               Sprintf(eos(qbuf), " %s. Continue?",
+                       safe_qbuf(qbuf, sizeof(" . Continue?"),
+                               doname(obj), an(simple_typename(obj->otyp)), "something"));
+               obj->quan = savequan;
+               switch (ynq(qbuf)) {
+               case 'q':  result = -1; break;
+               case 'n':  result =  0; break;
+               default:   break;       /* 'y' => result == 1 */
+               }
+               clear_nhwindow(WIN_MESSAGE);
+           }
+       }
+    }
+
+    if (obj->otyp == SCR_SCARE_MONSTER && result <= 0 && !container)
+       obj->spe = 0;
+    return result;
+}
+
+/* To prevent qbuf overflow in prompts use planA only
+ * if it fits, or planB if PlanA doesn't fit,
+ * finally using the fallback as a last resort.
+ * last_restort is expected to be very short.
+ */
+const char *
+safe_qbuf(qbuf, padlength, planA, planB, last_resort)
+const char *qbuf, *planA, *planB, *last_resort;
+unsigned padlength;
+{
+       /* convert size_t (or int for ancient systems) to ordinary unsigned */
+       unsigned len_qbuf = (unsigned)strlen(qbuf),
+                len_planA = (unsigned)strlen(planA),
+                len_planB = (unsigned)strlen(planB),
+                len_lastR = (unsigned)strlen(last_resort);
+       unsigned textleft = QBUFSZ - (len_qbuf + padlength);
+
+       if (len_lastR >= textleft) {
+           impossible("safe_qbuf: last_resort too large at %u characters.",
+                      len_lastR);
+           return "";
+       }
+       return (len_planA < textleft) ? planA :
+                   (len_planB < textleft) ? planB : last_resort;
+}
+
+/*
+ * Pick up <count> of obj from the ground and add it to the hero's inventory.
+ * Returns -1 if caller should break out of its loop, 0 if nothing picked
+ * up, 1 if otherwise.
+ */
+int
+pickup_object(obj, count, telekinesis)
+struct obj *obj;
+long count;
+boolean telekinesis;   /* not picking it up directly by hand */
+{
+       int res, nearload;
+#ifndef GOLDOBJ
+       const char *where = (obj->ox == u.ux && obj->oy == u.uy) ?
+                           "here" : "there";
+#endif
+
+       if (obj->quan < count) {
+           impossible("pickup_object: count %ld > quan %ld?",
+               count, obj->quan);
+           return 0;
+       }
+
+       /* In case of auto-pickup, where we haven't had a chance
+          to look at it yet; affects docall(SCR_SCARE_MONSTER). */
+       if (!Blind)
+#ifdef INVISIBLE_OBJECTS
+               if (!obj->oinvis || See_invisible)
+#endif
+               obj->dknown = 1;
+
+       if (obj == uchain) {    /* do not pick up attached chain */
+           return 0;
+       } else if (obj->oartifact && !touch_artifact(obj,&youmonst)) {
+           return 0;
+#ifndef GOLDOBJ
+       } else if (obj->oclass == COIN_CLASS) {
+           /* Special consideration for gold pieces... */
+           long iw = (long)max_capacity() - GOLD_WT(u.ugold);
+           long gold_capacity = GOLD_CAPACITY(iw, u.ugold);
+
+           if (gold_capacity <= 0L) {
+               pline(
+              "There %s %ld gold piece%s %s, but you cannot carry any more.",
+                     otense(obj, "are"),
+                     obj->quan, plur(obj->quan), where);
+               return 0;
+           } else if (gold_capacity < count) {
+               You("can only %s %s of the %ld gold pieces lying %s.",
+                   telekinesis ? "acquire" : "carry",
+                   gold_capacity == 1L ? "one" : "some", obj->quan, where);
+               pline("%s %ld gold piece%s.",
+                   nearloadmsg, gold_capacity, plur(gold_capacity));
+               u.ugold += gold_capacity;
+               obj->quan -= gold_capacity;
+               costly_gold(obj->ox, obj->oy, gold_capacity);
+           } else {
+               u.ugold += count;
+               if ((nearload = near_capacity()) != 0)
+                   pline("%s %ld gold piece%s.",
+                         nearload < MOD_ENCUMBER ?
+                         moderateloadmsg : nearloadmsg,
+                         count, plur(count));
+               else
+                   prinv((char *) 0, obj, count);
+               costly_gold(obj->ox, obj->oy, count);
+               if (count == obj->quan)
+                   delobj(obj);
+               else
+                   obj->quan -= count;
+           }
+           flags.botl = 1;
+           if (flags.run) nomul(0);
+           return 1;
+#endif
+       } else if (obj->otyp == CORPSE) {
+           if ( (touch_petrifies(&mons[obj->corpsenm])) && !uarmg
+                               && !Stone_resistance && !telekinesis) {
+               if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
+                   display_nhwindow(WIN_MESSAGE, FALSE);
+               else {
+                       char kbuf[BUFSZ];
+
+                       Strcpy(kbuf, an(corpse_xname(obj, TRUE)));
+                       pline("Touching %s is a fatal mistake.", kbuf);
+                       instapetrify(kbuf);
+                   return -1;
+               }
+           } else if (is_rider(&mons[obj->corpsenm])) {
+               pline("At your %s, the corpse suddenly moves...",
+                       telekinesis ? "attempted acquisition" : "touch");
+               (void) revive_corpse(obj);
+               exercise(A_WIS, FALSE);
+               return -1;
+           }
+       } else  if (obj->otyp == SCR_SCARE_MONSTER) {
+           if (obj->blessed) obj->blessed = 0;
+           else if (!obj->spe && !obj->cursed) obj->spe = 1;
+           else {
+               pline_The("scroll%s %s to dust as you %s %s up.",
+                       plur(obj->quan), otense(obj, "turn"),
+                       telekinesis ? "raise" : "pick",
+                       (obj->quan == 1L) ? "it" : "them");
+               if (!(objects[SCR_SCARE_MONSTER].oc_name_known) &&
+                                   !(objects[SCR_SCARE_MONSTER].oc_uname))
+                   docall(obj);
+               useupf(obj, obj->quan);
+               return 1;       /* tried to pick something up and failed, but
+                                  don't want to terminate pickup loop yet   */
+           }
+       }
+
+       if ((res = lift_object(obj, (struct obj *)0, &count, telekinesis)) <= 0)
+           return res;
+
+#ifdef GOLDOBJ
+        /* Whats left of the special case for gold :-) */
+       if (obj->oclass == COIN_CLASS) flags.botl = 1;
+#endif
+       if (obj->quan != count && obj->otyp != LOADSTONE)
+           obj = splitobj(obj, count);
+
+       obj = pick_obj(obj);
+
+       if (uwep && uwep == obj) mrg_to_wielded = TRUE;
+       nearload = near_capacity();
+       prinv(nearload == SLT_ENCUMBER ? moderateloadmsg : (char *) 0,
+             obj, count);
+       mrg_to_wielded = FALSE;
+       return 1;
+}
+
+/*
+ * Do the actual work of picking otmp from the floor or monster's interior
+ * and putting it in the hero's inventory.  Take care of billing.  Return a
+ * pointer to the object where otmp ends up.  This may be different
+ * from otmp because of merging.
+ *
+ * Gold never reaches this routine unless GOLDOBJ is defined.
+ */
+struct obj *
+pick_obj(otmp)
+struct obj *otmp;
+{
+       obj_extract_self(otmp);
+       if (!u.uswallow && otmp != uball && costly_spot(otmp->ox, otmp->oy)) {
+           char saveushops[5], fakeshop[2];
+
+           /* addtobill cares about your location rather than the object's;
+              usually they'll be the same, but not when using telekinesis
+              (if ever implemented) or a grappling hook */
+           Strcpy(saveushops, u.ushops);
+           fakeshop[0] = *in_rooms(otmp->ox, otmp->oy, SHOPBASE);
+           fakeshop[1] = '\0';
+           Strcpy(u.ushops, fakeshop);
+           /* sets obj->unpaid if necessary */
+           addtobill(otmp, TRUE, FALSE, FALSE);
+           Strcpy(u.ushops, saveushops);
+           /* if you're outside the shop, make shk notice */
+           if (!index(u.ushops, *fakeshop))
+               remote_burglary(otmp->ox, otmp->oy);
+       }
+       if (otmp->no_charge)    /* only applies to objects outside invent */
+           otmp->no_charge = 0;
+       newsym(otmp->ox, otmp->oy);
+       return addinv(otmp);    /* might merge it with other objects */
+}
+
+/*
+ * prints a message if encumbrance changed since the last check and
+ * returns the new encumbrance value (from near_capacity()).
+ */
+int
+encumber_msg()
+{
+    static int oldcap = UNENCUMBERED;
+    int newcap = near_capacity();
+
+    if(oldcap < newcap) {
+       switch(newcap) {
+       case 1: Your("movements are slowed slightly because of your load.");
+               break;
+       case 2: You("rebalance your load.  Movement is difficult.");
+               break;
+       case 3: You("%s under your heavy load.  Movement is very hard.",
+                   stagger(youmonst.data, "stagger"));
+               break;
+       default: You("%s move a handspan with this load!",
+                    newcap == 4 ? "can barely" : "can't even");
+               break;
+       }
+       flags.botl = 1;
+    } else if(oldcap > newcap) {
+       switch(newcap) {
+       case 0: Your("movements are now unencumbered.");
+               break;
+       case 1: Your("movements are only slowed slightly by your load.");
+               break;
+       case 2: You("rebalance your load.  Movement is still difficult.");
+               break;
+       case 3: You("%s under your load.  Movement is still very hard.",
+                   stagger(youmonst.data, "stagger"));
+               break;
+       }
+       flags.botl = 1;
+    }
+
+    oldcap = newcap;
+    return (newcap);
+}
+
+/* Is there a container at x,y. Optional: return count of containers at x,y */
+STATIC_OVL int
+container_at(x, y, countem)
+int x,y;
+boolean countem;
+{
+       struct obj *cobj, *nobj;
+       int container_count = 0;
+       
+       for(cobj = level.objects[x][y]; cobj; cobj = nobj) {
+               nobj = cobj->nexthere;
+               if(Is_container(cobj)) {
+                       container_count++;
+                       if (!countem) break;
+               }
+       }
+       return container_count;
+}
+
+STATIC_OVL boolean
+able_to_loot(x, y)
+int x, y;
+{
+       if (!can_reach_floor()) {
+#ifdef STEED
+               if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
+                       rider_cant_reach(); /* not skilled enough to reach */
+               else
+#endif
+                       You("cannot reach the %s.", surface(x, y));
+               return FALSE;
+       } else if (is_pool(x, y) || is_lava(x, y)) {
+               /* at present, can't loot in water even when Underwater */
+               You("cannot loot things that are deep in the %s.",
+                   is_lava(x, y) ? "lava" : "water");
+               return FALSE;
+       } else if (nolimbs(youmonst.data)) {
+               pline("Without limbs, you cannot loot anything.");
+               return FALSE;
+       } else if (!freehand()) {
+               pline("Without a free %s, you cannot loot anything.",
+                       body_part(HAND));
+               return FALSE;
+       }
+       return TRUE;
+}
+
+STATIC_OVL boolean
+mon_beside(x,y)
+int x, y;
+{
+       int i,j,nx,ny;
+       for(i = -1; i <= 1; i++)
+           for(j = -1; j <= 1; j++) {
+               nx = x + i;
+               ny = y + j;
+               if(isok(nx, ny) && MON_AT(nx, ny))
+                       return TRUE;
+           }
+       return FALSE;
+}
+
+int
+doloot()       /* loot a container on the floor or loot saddle from mon. */
+{
+    register struct obj *cobj, *nobj;
+    register int c = -1;
+    int timepassed = 0;
+    coord cc;
+    boolean underfoot = TRUE;
+    const char *dont_find_anything = "don't find anything";
+    struct monst *mtmp;
+    char qbuf[BUFSZ];
+    int prev_inquiry = 0;
+    boolean prev_loot = FALSE;
+
+    if (check_capacity((char *)0)) {
+       /* "Can't do that while carrying so much stuff." */
+       return 0;
+    }
+    if (nohands(youmonst.data)) {
+       You("have no hands!");  /* not `body_part(HAND)' */
+       return 0;
+    }
+    cc.x = u.ux; cc.y = u.uy;
+
+lootcont:
+
+    if (container_at(cc.x, cc.y, FALSE)) {
+       boolean any = FALSE;
+
+       if (!able_to_loot(cc.x, cc.y)) return 0;
+       for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) {
+           nobj = cobj->nexthere;
+
+           if (Is_container(cobj)) {
+               Sprintf(qbuf, "There is %s here, loot it?",
+                       safe_qbuf("", sizeof("There is  here, loot it?"),
+                            doname(cobj), an(simple_typename(cobj->otyp)),
+                            "a container"));
+               c = ynq(qbuf);
+               if (c == 'q') return (timepassed);
+               if (c == 'n') continue;
+               any = TRUE;
+
+               if (cobj->olocked) {
+                   pline("Hmmm, it seems to be locked.");
+                   continue;
+               }
+               if (cobj->otyp == BAG_OF_TRICKS) {
+                   int tmp;
+                   You("carefully open the bag...");
+                   pline("It develops a huge set of teeth and bites you!");
+                   tmp = rnd(10);
+                   if (Half_physical_damage) tmp = (tmp+1) / 2;
+                   losehp(tmp, "carnivorous bag", KILLED_BY_AN);
+                   makeknown(BAG_OF_TRICKS);
+                   timepassed = 1;
+                   continue;
+               }
+
+               You("carefully open %s...", the(xname(cobj)));
+               timepassed |= use_container(cobj, 0);
+               if (multi < 0) return 1;                /* chest trap */
+           }
+       }
+       if (any) c = 'y';
+    } else if (Confusion) {
+#ifndef GOLDOBJ
+       if (u.ugold){
+           long contribution = rnd((int)min(LARGEST_INT,u.ugold));
+           struct obj *goldob = mkgoldobj(contribution);
+#else
+       struct obj *goldob;
+       /* Find a money object to mess with */
+       for (goldob = invent; goldob; goldob = goldob->nobj) {
+           if (goldob->oclass == COIN_CLASS) break;
+       }
+       if (goldob){
+           long contribution = rnd((int)min(LARGEST_INT, goldob->quan));
+           if (contribution < goldob->quan)
+               goldob = splitobj(goldob, contribution);
+           freeinv(goldob);
+#endif
+           if (IS_THRONE(levl[u.ux][u.uy].typ)){
+               struct obj *coffers;
+               int pass;
+               /* find the original coffers chest, or any chest */
+               for (pass = 2; pass > -1; pass -= 2)
+                   for (coffers = fobj; coffers; coffers = coffers->nobj)
+                       if (coffers->otyp == CHEST && coffers->spe == pass)
+                           goto gotit; /* two level break */
+gotit:
+               if (coffers) {
+           verbalize("Thank you for your contribution to reduce the debt.");
+                   (void) add_to_container(coffers, goldob);
+                   coffers->owt = weight(coffers);
+               } else {
+                   struct monst *mon = makemon(courtmon(),
+                                           u.ux, u.uy, NO_MM_FLAGS);
+                   if (mon) {
+#ifndef GOLDOBJ
+                       mon->mgold += goldob->quan;
+                       delobj(goldob);
+                       pline("The exchequer accepts your contribution.");
+                   } else {
+                       dropx(goldob);
+                   }
+               }
+           } else {
+               dropx(goldob);
+#else
+                       add_to_minv(mon, goldob);
+                       pline("The exchequer accepts your contribution.");
+                   } else {
+                       dropy(goldob);
+                   }
+               }
+           } else {
+               dropy(goldob);
+#endif
+               pline("Ok, now there is loot here.");
+           }
+       }
+    } else if (IS_GRAVE(levl[cc.x][cc.y].typ)) {
+       You("need to dig up the grave to effectively loot it...");
+    }
+    /*
+     * 3.3.1 introduced directional looting for some things.
+     */
+    if (c != 'y' && mon_beside(u.ux, u.uy)) {
+       if (!get_adjacent_loc("Loot in what direction?", "Invalid loot location",
+                       u.ux, u.uy, &cc)) return 0;
+       if (cc.x == u.ux && cc.y == u.uy) {
+           underfoot = TRUE;
+           if (container_at(cc.x, cc.y, FALSE))
+               goto lootcont;
+       } else
+           underfoot = FALSE;
+       if (u.dz < 0) {
+           You("%s to loot on the %s.", dont_find_anything,
+               ceiling(cc.x, cc.y));
+           timepassed = 1;
+           return timepassed;
+       }
+       mtmp = m_at(cc.x, cc.y);
+       if (mtmp) timepassed = loot_mon(mtmp, &prev_inquiry, &prev_loot);
+
+       /* Preserve pre-3.3.1 behaviour for containers.
+        * Adjust this if-block to allow container looting
+        * from one square away to change that in the future.
+        */
+       if (!underfoot) {
+           if (container_at(cc.x, cc.y, FALSE)) {
+               if (mtmp) {
+                   You_cant("loot anything %sthere with %s in the way.",
+                           prev_inquiry ? "else " : "", mon_nam(mtmp));
+                   return timepassed;
+               } else {
+                   You("have to be at a container to loot it.");
+               }
+           } else {
+               You("%s %sthere to loot.", dont_find_anything,
+                       (prev_inquiry || prev_loot) ? "else " : "");
+               return timepassed;
+           }
+       }
+    } else if (c != 'y' && c != 'n') {
+       You("%s %s to loot.", dont_find_anything,
+                   underfoot ? "here" : "there");
+    }
+    return (timepassed);
+}
+
+/* loot_mon() returns amount of time passed.
+ */
+int
+loot_mon(mtmp, passed_info, prev_loot)
+struct monst *mtmp;
+int *passed_info;
+boolean *prev_loot;
+{
+    int c = -1;
+    int timepassed = 0;
+#ifdef STEED
+    struct obj *otmp;
+    char qbuf[QBUFSZ];
+
+    /* 3.3.1 introduced the ability to remove saddle from a steed             */
+    /*         *passed_info is set to TRUE if a loot query was given.               */
+    /* *prev_loot is set to TRUE if something was actually acquired in here. */
+    if (mtmp && mtmp != u.usteed && (otmp = which_armor(mtmp, W_SADDLE))) {
+       long unwornmask;
+       if (passed_info) *passed_info = 1;
+       Sprintf(qbuf, "Do you want to remove the saddle from %s?",
+               x_monnam(mtmp, ARTICLE_THE, (char *)0, SUPPRESS_SADDLE, FALSE));
+       if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
+               if (nolimbs(youmonst.data)) {
+                   You_cant("do that without limbs."); /* not body_part(HAND) */
+                   return (0);
+               }
+               if (otmp->cursed) {
+                   You("can't. The saddle seems to be stuck to %s.",
+                       x_monnam(mtmp, ARTICLE_THE, (char *)0,
+                               SUPPRESS_SADDLE, FALSE));
+                           
+                   /* the attempt costs you time */
+                       return (1);
+               }
+               obj_extract_self(otmp);
+               if ((unwornmask = otmp->owornmask) != 0L) {
+                   mtmp->misc_worn_check &= ~unwornmask;
+                   otmp->owornmask = 0L;
+                   update_mon_intrinsics(mtmp, otmp, FALSE, FALSE);
+               }
+               otmp = hold_another_object(otmp, "You drop %s!", doname(otmp),
+                                       (const char *)0);
+               timepassed = rnd(3);
+               if (prev_loot) *prev_loot = TRUE;
+       } else if (c == 'q') {
+               return (0);
+       }
+    }
+#endif /* STEED */
+    /* 3.4.0 introduced the ability to pick things up from within swallower's stomach */
+    if (u.uswallow) {
+       int count = passed_info ? *passed_info : 0;
+       timepassed = pickup(count);
+    }
+    return timepassed;
+}
+
+/*
+ * Decide whether an object being placed into a magic bag will cause
+ * it to explode.  If the object is a bag itself, check recursively.
+ */
+STATIC_OVL boolean
+mbag_explodes(obj, depthin)
+    struct obj *obj;
+    int depthin;
+{
+    /* these won't cause an explosion when they're empty */
+    if ((obj->otyp == WAN_CANCELLATION || obj->otyp == BAG_OF_TRICKS) &&
+           obj->spe <= 0)
+       return FALSE;
+
+    /* odds: 1/1, 2/2, 3/4, 4/8, 5/16, 6/32, 7/64, 8/128, 9/128, 10/128,... */
+    if ((Is_mbag(obj) || obj->otyp == WAN_CANCELLATION) &&
+       (rn2(1 << (depthin > 7 ? 7 : depthin)) <= depthin))
+       return TRUE;
+    else if (Has_contents(obj)) {
+       struct obj *otmp;
+
+       for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
+           if (mbag_explodes(otmp, depthin+1)) return TRUE;
+    }
+    return FALSE;
+}
+
+/* A variable set in use_container(), to be used by the callback routines   */
+/* in_container(), and out_container() from askchain() and use_container(). */
+static NEARDATA struct obj *current_container;
+#define Icebox (current_container->otyp == ICE_BOX)
+
+/* Returns: -1 to stop, 1 item was inserted, 0 item was not inserted. */
+STATIC_PTR int
+in_container(obj)
+register struct obj *obj;
+{
+       boolean floor_container = !carried(current_container);
+       boolean was_unpaid = FALSE;
+       char buf[BUFSZ];
+
+       if (!current_container) {
+               impossible("<in> no current_container?");
+               return 0;
+       } else if (obj == uball || obj == uchain) {
+               You("must be kidding.");
+               return 0;
+       } else if (obj == current_container) {
+               pline("That would be an interesting topological exercise.");
+               return 0;
+       } else if (obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) {
+               Norep("You cannot %s %s you are wearing.",
+                       Icebox ? "refrigerate" : "stash", something);
+               return 0;
+       } else if ((obj->otyp == LOADSTONE) && obj->cursed) {
+               obj->bknown = 1;
+             pline_The("stone%s won't leave your person.", plur(obj->quan));
+               return 0;
+       } else if (obj->otyp == AMULET_OF_YENDOR ||
+                  obj->otyp == CANDELABRUM_OF_INVOCATION ||
+                  obj->otyp == BELL_OF_OPENING ||
+                  obj->otyp == SPE_BOOK_OF_THE_DEAD) {
+       /* Prohibit Amulets in containers; if you allow it, monsters can't
+        * steal them.  It also becomes a pain to check to see if someone
+        * has the Amulet.  Ditto for the Candelabrum, the Bell and the Book.
+        */
+           pline("%s cannot be confined in such trappings.", The(xname(obj)));
+           return 0;
+       } else if (obj->otyp == LEASH && obj->leashmon != 0) {
+               pline("%s attached to your pet.", Tobjnam(obj, "are"));
+               return 0;
+       } else if (obj == uwep) {
+               if (welded(obj)) {
+                       weldmsg(obj);
+                       return 0;
+               }
+               setuwep((struct obj *) 0);
+               if (uwep) return 0;     /* unwielded, died, rewielded */
+       } else if (obj == uswapwep) {
+               setuswapwep((struct obj *) 0);
+               if (uswapwep) return 0;     /* unwielded, died, rewielded */
+       } else if (obj == uquiver) {
+               setuqwep((struct obj *) 0);
+               if (uquiver) return 0;     /* unwielded, died, rewielded */
+       }
+
+       if (obj->otyp == CORPSE) {
+           if ( (touch_petrifies(&mons[obj->corpsenm])) && !uarmg
+                && !Stone_resistance) {
+               if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
+                   display_nhwindow(WIN_MESSAGE, FALSE);
+               else {
+                   char kbuf[BUFSZ];
+
+                   Strcpy(kbuf, an(corpse_xname(obj, TRUE)));
+                   pline("Touching %s is a fatal mistake.", kbuf);
+                   instapetrify(kbuf);
+                   return -1;
+               }
+           }
+       }
+
+       /* boxes, boulders, and big statues can't fit into any container */
+       if (obj->otyp == ICE_BOX || Is_box(obj) || obj->otyp == BOULDER ||
+               (obj->otyp == STATUE && bigmonst(&mons[obj->corpsenm]))) {
+               /*
+                *  xname() uses a static result array.  Save obj's name
+                *  before current_container's name is computed.  Don't
+                *  use the result of strcpy() within You() --- the order
+                *  of evaluation of the parameters is undefined.
+                */
+               Strcpy(buf, the(xname(obj)));
+               You("cannot fit %s into %s.", buf,
+                   the(xname(current_container)));
+               return 0;
+       }
+
+       freeinv(obj);
+
+       if (obj_is_burning(obj))        /* this used to be part of freeinv() */
+               (void) snuff_lit(obj);
+
+       if (floor_container && costly_spot(u.ux, u.uy)) {
+           if (current_container->no_charge && !obj->unpaid) {
+               /* don't sell when putting the item into your own container */
+               obj->no_charge = 1;
+           } else if (obj->oclass != COIN_CLASS) {
+               /* sellobj() will take an unpaid item off the shop bill
+                * note: coins are handled later */
+               was_unpaid = obj->unpaid ? TRUE : FALSE;
+               sellobj_state(SELL_DELIBERATE);
+               sellobj(obj, u.ux, u.uy);
+               sellobj_state(SELL_NORMAL);
+           }
+       }
+       if (Icebox && !age_is_relative(obj)) {
+               obj->age = monstermoves - obj->age; /* actual age */
+               /* stop any corpse timeouts when frozen */
+               if (obj->otyp == CORPSE && obj->timed) {
+                       long rot_alarm = stop_timer(ROT_CORPSE, (genericptr_t)obj);
+                       (void) stop_timer(REVIVE_MON, (genericptr_t)obj);
+                       /* mark a non-reviving corpse as such */
+                       if (rot_alarm) obj->norevive = 1;
+               }
+       } else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) {
+               /* explicitly mention what item is triggering the explosion */
+               pline(
+             "As you put %s inside, you are blasted by a magical explosion!",
+                     doname(obj));
+               /* did not actually insert obj yet */
+               if (was_unpaid) addtobill(obj, FALSE, FALSE, TRUE);
+               obfree(obj, (struct obj *)0);
+               delete_contents(current_container);
+               if (!floor_container)
+                       useup(current_container);
+               else if (obj_here(current_container, u.ux, u.uy))
+                       useupf(current_container, obj->quan);
+               else
+                       panic("in_container:  bag not found.");
+
+               losehp(d(6,6),"magical explosion", KILLED_BY_AN);
+               current_container = 0;  /* baggone = TRUE; */
+       }
+
+       if (current_container) {
+           Strcpy(buf, the(xname(current_container)));
+           You("put %s into %s.", doname(obj), buf);
+
+           /* gold in container always needs to be added to credit */
+           if (floor_container && obj->oclass == COIN_CLASS)
+               sellobj(obj, current_container->ox, current_container->oy);
+           (void) add_to_container(current_container, obj);
+           current_container->owt = weight(current_container);
+       }
+       /* gold needs this, and freeinv() many lines above may cause
+        * the encumbrance to disappear from the status, so just always
+        * update status immediately.
+        */
+       bot();
+
+       return(current_container ? 1 : -1);
+}
+
+STATIC_PTR int
+ck_bag(obj)
+struct obj *obj;
+{
+       return current_container && obj != current_container;
+}
+
+/* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */
+STATIC_PTR int
+out_container(obj)
+register struct obj *obj;
+{
+       register struct obj *otmp;
+       boolean is_gold = (obj->oclass == COIN_CLASS);
+       int res, loadlev;
+       long count;
+
+       if (!current_container) {
+               impossible("<out> no current_container?");
+               return -1;
+       } else if (is_gold) {
+               obj->owt = weight(obj);
+       }
+
+       if(obj->oartifact && !touch_artifact(obj,&youmonst)) return 0;
+
+       if (obj->otyp == CORPSE) {
+           if ( (touch_petrifies(&mons[obj->corpsenm])) && !uarmg
+                && !Stone_resistance) {
+               if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
+                   display_nhwindow(WIN_MESSAGE, FALSE);
+               else {
+                   char kbuf[BUFSZ];
+
+                   Strcpy(kbuf, an(corpse_xname(obj, TRUE)));
+                   pline("Touching %s is a fatal mistake.", kbuf);
+                   instapetrify(kbuf);
+                   return -1;
+               }
+           }
+       }
+
+       count = obj->quan;
+       if ((res = lift_object(obj, current_container, &count, FALSE)) <= 0)
+           return res;
+
+       if (obj->quan != count && obj->otyp != LOADSTONE)
+           obj = splitobj(obj, count);
+
+       /* Remove the object from the list. */
+       obj_extract_self(obj);
+       current_container->owt = weight(current_container);
+
+       if (Icebox && !age_is_relative(obj)) {
+               obj->age = monstermoves - obj->age; /* actual age */
+               if (obj->otyp == CORPSE)
+                       start_corpse_timeout(obj);
+       }
+       /* simulated point of time */
+
+       if(!obj->unpaid && !carried(current_container) &&
+            costly_spot(current_container->ox, current_container->oy)) {
+               obj->ox = current_container->ox;
+               obj->oy = current_container->oy;
+               addtobill(obj, FALSE, FALSE, FALSE);
+       }
+       if (is_pick(obj) && !obj->unpaid && *u.ushops && shop_keeper(*u.ushops))
+               verbalize("You sneaky cad! Get out of here with that pick!");
+
+       otmp = addinv(obj);
+       loadlev = near_capacity();
+       prinv(loadlev ?
+             (loadlev < MOD_ENCUMBER ?
+              "You have a little trouble removing" :
+              "You have much trouble removing") : (char *)0,
+             otmp, count);
+
+       if (is_gold) {
+#ifndef GOLDOBJ
+               dealloc_obj(obj);
+#endif
+               bot();  /* update character's gold piece count immediately */
+       }
+       return 1;
+}
+
+/* an object inside a cursed bag of holding is being destroyed */
+STATIC_OVL long
+mbag_item_gone(held, item)
+int held;
+struct obj *item;
+{
+    struct monst *shkp;
+    long loss = 0L;
+
+    if (item->dknown)
+       pline("%s %s vanished!", Doname2(item), otense(item, "have"));
+    else
+       You("%s %s disappear!", Blind ? "notice" : "see", doname(item));
+
+    if (*u.ushops && (shkp = shop_keeper(*u.ushops)) != 0) {
+       if (held ? (boolean) item->unpaid : costly_spot(u.ux, u.uy))
+           loss = stolen_value(item, u.ux, u.uy,
+                               (boolean)shkp->mpeaceful, TRUE);
+    }
+    obfree(item, (struct obj *) 0);
+    return loss;
+}
+
+STATIC_OVL void
+observe_quantum_cat(box)
+struct obj *box;
+{
+    static NEARDATA const char sc[] = "Schroedinger's Cat";
+    struct obj *deadcat;
+    struct monst *livecat;
+    xchar ox, oy;
+
+    box->spe = 0;              /* box->owt will be updated below */
+    if (get_obj_location(box, &ox, &oy, 0))
+       box->ox = ox, box->oy = oy;     /* in case it's being carried */
+
+    /* this isn't really right, since any form of observation
+       (telepathic or monster/object/food detection) ought to
+       force the determination of alive vs dead state; but basing
+       it just on opening the box is much simpler to cope with */
+    livecat = rn2(2) ? makemon(&mons[PM_HOUSECAT],
+                              box->ox, box->oy, NO_MINVENT) : 0;
+    if (livecat) {
+       livecat->mpeaceful = 1;
+       set_malign(livecat);
+       if (!canspotmon(livecat))
+           You("think %s brushed your %s.", something, body_part(FOOT));
+       else
+           pline("%s inside the box is still alive!", Monnam(livecat));
+       (void) christen_monst(livecat, sc);
+    } else {
+       deadcat = mk_named_object(CORPSE, &mons[PM_HOUSECAT],
+                                 box->ox, box->oy, sc);
+       if (deadcat) {
+           obj_extract_self(deadcat);
+           (void) add_to_container(box, deadcat);
+       }
+       pline_The("%s inside the box is dead!",
+           Hallucination ? rndmonnam() : "housecat");
+    }
+    box->owt = weight(box);
+    return;
+}
+
+#undef Icebox
+
+int
+use_container(obj, held)
+register struct obj *obj;
+register int held;
+{
+       struct obj *curr, *otmp;
+#ifndef GOLDOBJ
+       struct obj *u_gold = (struct obj *)0;
+#endif
+       boolean one_by_one, allflag, quantum_cat = FALSE,
+               loot_out = FALSE, loot_in = FALSE;
+       char select[MAXOCLASSES+1];
+       char qbuf[BUFSZ], emptymsg[BUFSZ], pbuf[QBUFSZ];
+       long loss = 0L;
+       int cnt = 0, used = 0,
+           menu_on_request;
+
+       emptymsg[0] = '\0';
+       if (nohands(youmonst.data)) {
+               You("have no hands!");  /* not `body_part(HAND)' */
+               return 0;
+       } else if (!freehand()) {
+               You("have no free %s.", body_part(HAND));
+               return 0;
+       }
+       if (obj->olocked) {
+           pline("%s to be locked.", Tobjnam(obj, "seem"));
+           if (held) You("must put it down to unlock.");
+           return 0;
+       } else if (obj->otrapped) {
+           if (held) You("open %s...", the(xname(obj)));
+           (void) chest_trap(obj, HAND, FALSE);
+           /* even if the trap fails, you've used up this turn */
+           if (multi >= 0) {   /* in case we didn't become paralyzed */
+               nomul(-1);
+               nomovemsg = "";
+           }
+           return 1;
+       }
+       current_container = obj;        /* for use by in/out_container */
+
+       if (obj->spe == 1) {
+           observe_quantum_cat(obj);
+           used = 1;
+           quantum_cat = TRUE; /* for adjusting "it's empty" message */
+       }
+       /* Count the number of contained objects. Sometimes toss objects if */
+       /* a cursed magic bag.                                              */
+       for (curr = obj->cobj; curr; curr = otmp) {
+           otmp = curr->nobj;
+           if (Is_mbag(obj) && obj->cursed && !rn2(13)) {
+               obj_extract_self(curr);
+               loss += mbag_item_gone(held, curr);
+               used = 1;
+           } else {
+               cnt++;
+           }
+       }
+
+       if (loss)       /* magic bag lost some shop goods */
+           You("owe %ld %s for lost merchandise.", loss, currency(loss));
+       obj->owt = weight(obj); /* in case any items were lost */
+
+       if (!cnt)
+           Sprintf(emptymsg, "%s is %sempty.", Yname2(obj),
+                   quantum_cat ? "now " : "");
+
+       if (cnt || flags.menu_style == MENU_FULL) {
+           Strcpy(qbuf, "Do you want to take something out of ");
+           Sprintf(eos(qbuf), "%s?",
+                   safe_qbuf(qbuf, 1, yname(obj), ysimple_name(obj), "it"));
+           if (flags.menu_style != MENU_TRADITIONAL) {
+               if (flags.menu_style == MENU_FULL) {
+                   int t;
+                   char menuprompt[BUFSZ];
+                   boolean outokay = (cnt != 0);
+#ifndef GOLDOBJ
+                   boolean inokay = (invent != 0) || (u.ugold != 0);
+#else
+                   boolean inokay = (invent != 0);
+#endif
+                   if (!outokay && !inokay) {
+                       pline("%s", emptymsg);
+                       You("don't have anything to put in.");
+                       return used;
+                   }
+                   menuprompt[0] = '\0';
+                   if (!cnt) Sprintf(menuprompt, "%s ", emptymsg);
+                   Strcat(menuprompt, "Do what?");
+                   t = in_or_out_menu(menuprompt, current_container, outokay, inokay);
+                   if (t <= 0) return 0;
+                   loot_out = (t & 0x01) != 0;
+                   loot_in  = (t & 0x02) != 0;
+               } else {        /* MENU_COMBINATION or MENU_PARTIAL */
+                   loot_out = (yn_function(qbuf, "ynq", 'n') == 'y');
+               }
+               if (loot_out) {
+                   add_valid_menu_class(0);    /* reset */
+                   used |= menu_loot(0, current_container, FALSE) > 0;
+               }
+           } else {
+               /* traditional code */
+ask_again2:
+               menu_on_request = 0;
+               add_valid_menu_class(0);        /* reset */
+               Strcpy(pbuf, ":ynq");
+               if (cnt) Strcat(pbuf, "m");
+               switch (yn_function(qbuf, pbuf, 'n')) {
+               case ':':
+                   container_contents(current_container, FALSE, FALSE);
+                   goto ask_again2;
+               case 'y':
+                   if (query_classes(select, &one_by_one, &allflag,
+                                     "take out", current_container->cobj,
+                                     FALSE,
+#ifndef GOLDOBJ
+                                     FALSE,
+#endif
+                                     &menu_on_request)) {
+                       if (askchain((struct obj **)&current_container->cobj,
+                                    (one_by_one ? (char *)0 : select),
+                                    allflag, out_container,
+                                    (int FDECL((*),(OBJ_P)))0,
+                                    0, "nodot"))
+                           used = 1;
+                   } else if (menu_on_request < 0) {
+                       used |= menu_loot(menu_on_request,
+                                         current_container, FALSE) > 0;
+                   }
+                   /*FALLTHRU*/
+               case 'n':
+                   break;
+               case 'm':
+                   menu_on_request = -2; /* triggers ALL_CLASSES */
+                   used |= menu_loot(menu_on_request, current_container, FALSE) > 0;
+                   break;
+               case 'q':
+               default:
+                   return used;
+               }
+           }
+       } else {
+           pline("%s", emptymsg);              /* <whatever> is empty. */
+       }
+
+#ifndef GOLDOBJ
+       if (!invent && u.ugold == 0) {
+#else
+       if (!invent) {
+#endif
+           /* nothing to put in, but some feedback is necessary */
+           You("don't have anything to put in.");
+           return used;
+       }
+       if (flags.menu_style != MENU_FULL) {
+           Sprintf(qbuf, "Do you wish to put %s in?", something);
+           Strcpy(pbuf, ynqchars);
+           if (flags.menu_style == MENU_TRADITIONAL && invent && inv_cnt() > 0)
+               Strcat(pbuf, "m");
+           switch (yn_function(qbuf, pbuf, 'n')) {
+               case 'y':
+                   loot_in = TRUE;
+                   break;
+               case 'n':
+                   break;
+               case 'm':
+                   add_valid_menu_class(0);      /* reset */
+                   menu_on_request = -2; /* triggers ALL_CLASSES */
+                   used |= menu_loot(menu_on_request, current_container, TRUE) > 0;
+                   break;
+               case 'q':
+               default:
+                   return used;
+           }
+       }
+       /*
+        * Gone: being nice about only selecting food if we know we are
+        * putting things in an ice chest.
+        */
+       if (loot_in) {
+#ifndef GOLDOBJ
+           if (u.ugold) {
+               /*
+                * Hack: gold is not in the inventory, so make a gold object
+                * and put it at the head of the inventory list.
+                */
+               u_gold = mkgoldobj(u.ugold);    /* removes from u.ugold */
+               u_gold->in_use = TRUE;
+               u.ugold = u_gold->quan;         /* put the gold back */
+               assigninvlet(u_gold);           /* might end up as NOINVSYM */
+               u_gold->nobj = invent;
+               invent = u_gold;
+           }
+#endif
+           add_valid_menu_class(0);      /* reset */
+           if (flags.menu_style != MENU_TRADITIONAL) {
+               used |= menu_loot(0, current_container, TRUE) > 0;
+           } else {
+               /* traditional code */
+               menu_on_request = 0;
+               if (query_classes(select, &one_by_one, &allflag, "put in",
+                                  invent, FALSE,
+#ifndef GOLDOBJ
+                                  (u.ugold != 0L),
+#endif
+                                  &menu_on_request)) {
+                   (void) askchain((struct obj **)&invent,
+                                   (one_by_one ? (char *)0 : select), allflag,
+                                   in_container, ck_bag, 0, "nodot");
+                   used = 1;
+               } else if (menu_on_request < 0) {
+                   used |= menu_loot(menu_on_request,
+                                     current_container, TRUE) > 0;
+               }
+           }
+       }
+
+#ifndef GOLDOBJ
+       if (u_gold && invent && invent->oclass == COIN_CLASS) {
+           /* didn't stash [all of] it */
+           u_gold = invent;
+           invent = u_gold->nobj;
+           u_gold->in_use = FALSE;
+           dealloc_obj(u_gold);
+       }
+#endif
+       return used;
+}
+
+/* Loot a container (take things out, put things in), using a menu. */
+STATIC_OVL int
+menu_loot(retry, container, put_in)
+int retry;
+struct obj *container;
+boolean put_in;
+{
+    int n, i, n_looted = 0;
+    boolean all_categories = TRUE, loot_everything = FALSE;
+    char buf[BUFSZ];
+    const char *takeout = "Take out", *putin = "Put in";
+    struct obj *otmp, *otmp2;
+    menu_item *pick_list;
+    int mflags, res;
+    long count;
+
+    if (retry) {
+       all_categories = (retry == -2);
+    } else if (flags.menu_style == MENU_FULL) {
+       all_categories = FALSE;
+       Sprintf(buf,"%s what type of objects?", put_in ? putin : takeout);
+       mflags = put_in ? ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN :
+                         ALL_TYPES | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN;
+       n = query_category(buf, put_in ? invent : container->cobj,
+                          mflags, &pick_list, PICK_ANY);
+       if (!n) return 0;
+       for (i = 0; i < n; i++) {
+           if (pick_list[i].item.a_int == 'A')
+               loot_everything = TRUE;
+           else if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
+               all_categories = TRUE;
+           else
+               add_valid_menu_class(pick_list[i].item.a_int);
+       }
+       free((genericptr_t) pick_list);
+    }
+
+    if (loot_everything) {
+       for (otmp = container->cobj; otmp; otmp = otmp2) {
+           otmp2 = otmp->nobj;
+           res = out_container(otmp);
+           if (res < 0) break;
+       }
+    } else {
+       mflags = INVORDER_SORT;
+       if (put_in && flags.invlet_constant) mflags |= USE_INVLET;
+       Sprintf(buf,"%s what?", put_in ? putin : takeout);
+       n = query_objlist(buf, put_in ? invent : container->cobj,
+                         mflags, &pick_list, PICK_ANY,
+                         all_categories ? allow_all : allow_category);
+       if (n) {
+               n_looted = n;
+               for (i = 0; i < n; i++) {
+                   otmp = pick_list[i].item.a_obj;
+                   count = pick_list[i].count;
+                   if (count > 0 && count < otmp->quan) {
+                       otmp = splitobj(otmp, count);
+                       /* special split case also handled by askchain() */
+                   }
+                   res = put_in ? in_container(otmp) : out_container(otmp);
+                   if (res < 0) {
+                       if (otmp != pick_list[i].item.a_obj) {
+                           /* split occurred, merge again */
+                           (void) merged(&pick_list[i].item.a_obj, &otmp);
+                       }
+                       break;
+                   }
+               }
+               free((genericptr_t)pick_list);
+       }
+    }
+    return n_looted;
+}
+
+STATIC_OVL int
+in_or_out_menu(prompt, obj, outokay, inokay)
+const char *prompt;
+struct obj *obj;
+boolean outokay, inokay;
+{
+    winid win;
+    anything any;
+    menu_item *pick_list;
+    char buf[BUFSZ];
+    int n;
+    const char *menuselector = iflags.lootabc ? "abc" : "oib";
+
+    any.a_void = 0;
+    win = create_nhwindow(NHW_MENU);
+    start_menu(win);
+    if (outokay) {
+       any.a_int = 1;
+       Sprintf(buf,"Take %s out of %s", something, the(xname(obj)));
+       add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE,
+                       buf, MENU_UNSELECTED);
+    }
+    menuselector++;
+    if (inokay) {
+       any.a_int = 2;
+       Sprintf(buf,"Put %s into %s", something, the(xname(obj)));
+       add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, buf, MENU_UNSELECTED);
+    }
+    menuselector++;
+    if (outokay && inokay) {
+       any.a_int = 3;
+       add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE,
+                       "Both of the above", MENU_UNSELECTED);
+    }
+    end_menu(win, prompt);
+    n = select_menu(win, PICK_ONE, &pick_list);
+    destroy_nhwindow(win);
+    if (n > 0) {
+       n = pick_list[0].item.a_int;
+       free((genericptr_t) pick_list);
+    }
+    return n;
+}
+
+/*pickup.c*/
diff --git a/src/pline.c b/src/pline.c
new file mode 100644 (file)
index 0000000..8210f8d
--- /dev/null
@@ -0,0 +1,440 @@
+/*     SCCS Id: @(#)pline.c    3.4     1999/11/28      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#define NEED_VARARGS /* Uses ... */    /* comment line for pre-compiled headers */
+#include "hack.h"
+#include "epri.h"
+#ifdef WIZARD
+#include "edog.h"
+#endif
+
+#ifdef OVLB
+
+static boolean no_repeat = FALSE;
+
+static char *FDECL(You_buf, (int));
+
+/*VARARGS1*/
+/* Note that these declarations rely on knowledge of the internals
+ * of the variable argument handling stuff in "tradstdc.h"
+ */
+
+#if defined(USE_STDARG) || defined(USE_VARARGS)
+static void FDECL(vpline, (const char *, va_list));
+
+void
+pline VA_DECL(const char *, line)
+       VA_START(line);
+       VA_INIT(line, char *);
+       vpline(line, VA_ARGS);
+       VA_END();
+}
+
+# ifdef USE_STDARG
+static void
+vpline(const char *line, va_list the_args) {
+# else
+static void
+vpline(line, the_args) const char *line; va_list the_args; {
+# endif
+
+#else  /* USE_STDARG | USE_VARARG */
+
+#define vpline pline
+
+void
+pline VA_DECL(const char *, line)
+#endif /* USE_STDARG | USE_VARARG */
+
+       char pbuf[BUFSZ];
+/* Do NOT use VA_START and VA_END in here... see above */
+
+       if (!line || !*line) return;
+       if (index(line, '%')) {
+           Vsprintf(pbuf,line,VA_ARGS);
+           line = pbuf;
+       }
+       if (!iflags.window_inited) {
+           raw_print(line);
+           return;
+       }
+#ifndef MAC
+       if (no_repeat && !strcmp(line, toplines))
+           return;
+#endif /* MAC */
+       if (vision_full_recalc) vision_recalc(0);
+       if (u.ux) flush_screen(1);              /* %% */
+       putstr(WIN_MESSAGE, 0, line);
+}
+
+/*VARARGS1*/
+void
+Norep VA_DECL(const char *, line)
+       VA_START(line);
+       VA_INIT(line, const char *);
+       no_repeat = TRUE;
+       vpline(line, VA_ARGS);
+       no_repeat = FALSE;
+       VA_END();
+       return;
+}
+
+/* work buffer for You(), &c and verbalize() */
+static char *you_buf = 0;
+static int you_buf_siz = 0;
+
+static char *
+You_buf(siz)
+int siz;
+{
+       if (siz > you_buf_siz) {
+               if (you_buf) free((genericptr_t) you_buf);
+               you_buf_siz = siz + 10;
+               you_buf = (char *) alloc((unsigned) you_buf_siz);
+       }
+       return you_buf;
+}
+
+void
+free_youbuf()
+{
+       if (you_buf) free((genericptr_t) you_buf),  you_buf = (char *)0;
+       you_buf_siz = 0;
+}
+
+/* `prefix' must be a string literal, not a pointer */
+#define YouPrefix(pointer,prefix,text) \
+ Strcpy((pointer = You_buf((int)(strlen(text) + sizeof prefix))), prefix)
+
+#define YouMessage(pointer,prefix,text) \
+ strcat((YouPrefix(pointer, prefix, text), pointer), text)
+
+/*VARARGS1*/
+void
+You VA_DECL(const char *, line)
+       char *tmp;
+       VA_START(line);
+       VA_INIT(line, const char *);
+       vpline(YouMessage(tmp, "You ", line), VA_ARGS);
+       VA_END();
+}
+
+/*VARARGS1*/
+void
+Your VA_DECL(const char *,line)
+       char *tmp;
+       VA_START(line);
+       VA_INIT(line, const char *);
+       vpline(YouMessage(tmp, "Your ", line), VA_ARGS);
+       VA_END();
+}
+
+/*VARARGS1*/
+void
+You_feel VA_DECL(const char *,line)
+       char *tmp;
+       VA_START(line);
+       VA_INIT(line, const char *);
+       vpline(YouMessage(tmp, "You feel ", line), VA_ARGS);
+       VA_END();
+}
+
+
+/*VARARGS1*/
+void
+You_cant VA_DECL(const char *,line)
+       char *tmp;
+       VA_START(line);
+       VA_INIT(line, const char *);
+       vpline(YouMessage(tmp, "You can't ", line), VA_ARGS);
+       VA_END();
+}
+
+/*VARARGS1*/
+void
+pline_The VA_DECL(const char *,line)
+       char *tmp;
+       VA_START(line);
+       VA_INIT(line, const char *);
+       vpline(YouMessage(tmp, "The ", line), VA_ARGS);
+       VA_END();
+}
+
+/*VARARGS1*/
+void
+There VA_DECL(const char *,line)
+       char *tmp;
+       VA_START(line);
+       VA_INIT(line, const char *);
+       vpline(YouMessage(tmp, "There ", line), VA_ARGS);
+       VA_END();
+}
+
+/*VARARGS1*/
+void
+You_hear VA_DECL(const char *,line)
+       char *tmp;
+       VA_START(line);
+       VA_INIT(line, const char *);
+       if (Underwater)
+               YouPrefix(tmp, "You barely hear ", line);
+       else if (u.usleep)
+               YouPrefix(tmp, "You dream that you hear ", line);
+       else
+               YouPrefix(tmp, "You hear ", line);
+       vpline(strcat(tmp, line), VA_ARGS);
+       VA_END();
+}
+
+/*VARARGS1*/
+void
+verbalize VA_DECL(const char *,line)
+       char *tmp;
+       if (!flags.soundok) return;
+       VA_START(line);
+       VA_INIT(line, const char *);
+       tmp = You_buf((int)strlen(line) + sizeof "\"\"");
+       Strcpy(tmp, "\"");
+       Strcat(tmp, line);
+       Strcat(tmp, "\"");
+       vpline(tmp, VA_ARGS);
+       VA_END();
+}
+
+/*VARARGS1*/
+/* Note that these declarations rely on knowledge of the internals
+ * of the variable argument handling stuff in "tradstdc.h"
+ */
+
+#if defined(USE_STDARG) || defined(USE_VARARGS)
+static void FDECL(vraw_printf,(const char *,va_list));
+
+void
+raw_printf VA_DECL(const char *, line)
+       VA_START(line);
+       VA_INIT(line, char *);
+       vraw_printf(line, VA_ARGS);
+       VA_END();
+}
+
+# ifdef USE_STDARG
+static void
+vraw_printf(const char *line, va_list the_args) {
+# else
+static void
+vraw_printf(line, the_args) const char *line; va_list the_args; {
+# endif
+
+#else  /* USE_STDARG | USE_VARARG */
+
+void
+raw_printf VA_DECL(const char *, line)
+#endif
+/* Do NOT use VA_START and VA_END in here... see above */
+
+       if(!index(line, '%'))
+           raw_print(line);
+       else {
+           char pbuf[BUFSZ];
+           Vsprintf(pbuf,line,VA_ARGS);
+           raw_print(pbuf);
+       }
+}
+
+
+/*VARARGS1*/
+void
+impossible VA_DECL(const char *, s)
+       VA_START(s);
+       VA_INIT(s, const char *);
+       if (program_state.in_impossible)
+               panic("impossible called impossible");
+       program_state.in_impossible = 1;
+       {
+           char pbuf[BUFSZ];
+           Vsprintf(pbuf,s,VA_ARGS);
+           paniclog("impossible", pbuf);
+       }
+       vpline(s,VA_ARGS);
+       pline("Program in disorder - perhaps you'd better #quit.");
+       program_state.in_impossible = 0;
+       VA_END();
+}
+
+const char *
+align_str(alignment)
+    aligntyp alignment;
+{
+    switch ((int)alignment) {
+       case A_CHAOTIC: return "chaotic";
+       case A_NEUTRAL: return "neutral";
+       case A_LAWFUL:  return "lawful";
+       case A_NONE:    return "unaligned";
+    }
+    return "unknown";
+}
+
+void
+mstatusline(mtmp)
+register struct monst *mtmp;
+{
+       aligntyp alignment;
+       char info[BUFSZ], monnambuf[BUFSZ];
+
+       if (mtmp->ispriest || mtmp->data == &mons[PM_ALIGNED_PRIEST]
+                               || mtmp->data == &mons[PM_ANGEL])
+               alignment = EPRI(mtmp)->shralign;
+       else
+               alignment = mtmp->data->maligntyp;
+       alignment = (alignment > 0) ? A_LAWFUL :
+               (alignment < 0) ? A_CHAOTIC :
+               A_NEUTRAL;
+
+       info[0] = 0;
+       if (mtmp->mtame) {        Strcat(info, ", tame");
+#ifdef WIZARD
+           if (wizard) {
+               Sprintf(eos(info), " (%d", mtmp->mtame);
+               if (!mtmp->isminion)
+                   Sprintf(eos(info), "; hungry %ld; apport %d",
+                       EDOG(mtmp)->hungrytime, EDOG(mtmp)->apport);
+               Strcat(info, ")");
+           }
+#endif
+       }
+       else if (mtmp->mpeaceful) Strcat(info, ", peaceful");
+       if (mtmp->meating)        Strcat(info, ", eating");
+       if (mtmp->mcan)           Strcat(info, ", cancelled");
+       if (mtmp->mconf)          Strcat(info, ", confused");
+       if (mtmp->mblinded || !mtmp->mcansee)
+                                 Strcat(info, ", blind");
+       if (mtmp->mstun)          Strcat(info, ", stunned");
+       if (mtmp->msleeping)      Strcat(info, ", asleep");
+#if 0  /* unfortunately mfrozen covers temporary sleep and being busy
+          (donning armor, for instance) as well as paralysis */
+       else if (mtmp->mfrozen)   Strcat(info, ", paralyzed");
+#else
+       else if (mtmp->mfrozen || !mtmp->mcanmove)
+                                 Strcat(info, ", can't move");
+#endif
+                                 /* [arbitrary reason why it isn't moving] */
+       else if (mtmp->mstrategy & STRAT_WAITMASK)
+                                 Strcat(info, ", meditating");
+       else if (mtmp->mflee)     Strcat(info, ", scared");
+       if (mtmp->mtrapped)       Strcat(info, ", trapped");
+       if (mtmp->mspeed)         Strcat(info,
+                                       mtmp->mspeed == MFAST ? ", fast" :
+                                       mtmp->mspeed == MSLOW ? ", slow" :
+                                       ", ???? speed");
+       if (mtmp->mundetected)    Strcat(info, ", concealed");
+       if (mtmp->minvis)         Strcat(info, ", invisible");
+       if (mtmp == u.ustuck)     Strcat(info,
+                       (sticks(youmonst.data)) ? ", held by you" :
+                               u.uswallow ? (is_animal(u.ustuck->data) ?
+                               ", swallowed you" :
+                               ", engulfed you") :
+                               ", holding you");
+#ifdef STEED
+       if (mtmp == u.usteed)     Strcat(info, ", carrying you");
+#endif
+
+       /* avoid "Status of the invisible newt ..., invisible" */
+       /* and unlike a normal mon_nam, use "saddled" even if it has a name */
+       Strcpy(monnambuf, x_monnam(mtmp, ARTICLE_THE, (char *)0,
+           (SUPPRESS_IT|SUPPRESS_INVISIBLE), FALSE));
+
+       pline("Status of %s (%s):  Level %d  HP %d(%d)  AC %d%s.",
+               monnambuf,
+               align_str(alignment),
+               mtmp->m_lev,
+               mtmp->mhp,
+               mtmp->mhpmax,
+               find_mac(mtmp),
+               info);
+}
+
+void
+ustatusline()
+{
+       char info[BUFSZ];
+
+       info[0] = '\0';
+       if (Sick) {
+               Strcat(info, ", dying from");
+               if (u.usick_type & SICK_VOMITABLE)
+                       Strcat(info, " food poisoning");
+               if (u.usick_type & SICK_NONVOMITABLE) {
+                       if (u.usick_type & SICK_VOMITABLE)
+                               Strcat(info, " and");
+                       Strcat(info, " illness");
+               }
+       }
+       if (Stoned)             Strcat(info, ", solidifying");
+       if (Slimed)             Strcat(info, ", becoming slimy");
+       if (Strangled)          Strcat(info, ", being strangled");
+       if (Vomiting)           Strcat(info, ", nauseated"); /* !"nauseous" */
+       if (Confusion)          Strcat(info, ", confused");
+       if (Blind) {
+           Strcat(info, ", blind");
+           if (u.ucreamed) {
+               if ((long)u.ucreamed < Blinded || Blindfolded
+                                               || !haseyes(youmonst.data))
+                   Strcat(info, ", cover");
+               Strcat(info, "ed by sticky goop");
+           }   /* note: "goop" == "glop"; variation is intentional */
+       }
+       if (Stunned)            Strcat(info, ", stunned");
+#ifdef STEED
+       if (!u.usteed)
+#endif
+       if (Wounded_legs) {
+           const char *what = body_part(LEG);
+           if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
+               what = makeplural(what);
+                               Sprintf(eos(info), ", injured %s", what);
+       }
+       if (Glib)               Sprintf(eos(info), ", slippery %s",
+                                       makeplural(body_part(HAND)));
+       if (u.utrap)            Strcat(info, ", trapped");
+       if (Fast)               Strcat(info, Very_fast ?
+                                               ", very fast" : ", fast");
+       if (u.uundetected)      Strcat(info, ", concealed");
+       if (Invis)              Strcat(info, ", invisible");
+       if (u.ustuck) {
+           if (sticks(youmonst.data))
+               Strcat(info, ", holding ");
+           else
+               Strcat(info, ", held by ");
+           Strcat(info, mon_nam(u.ustuck));
+       }
+
+       pline("Status of %s (%s%s):  Level %d  HP %d(%d)  AC %d%s.",
+               plname,
+                   (u.ualign.record >= 20) ? "piously " :
+                   (u.ualign.record > 13) ? "devoutly " :
+                   (u.ualign.record > 8) ? "fervently " :
+                   (u.ualign.record > 3) ? "stridently " :
+                   (u.ualign.record == 3) ? "" :
+                   (u.ualign.record >= 1) ? "haltingly " :
+                   (u.ualign.record == 0) ? "nominally " :
+                                           "insufficiently ",
+               align_str(u.ualign.type),
+               Upolyd ? mons[u.umonnum].mlevel : u.ulevel,
+               Upolyd ? u.mh : u.uhp,
+               Upolyd ? u.mhmax : u.uhpmax,
+               u.uac,
+               info);
+}
+
+void
+self_invis_message()
+{
+       pline("%s %s.",
+           Hallucination ? "Far out, man!  You" : "Gee!  All of a sudden, you",
+           See_invisible ? "can see right through yourself" :
+               "can't see yourself");
+}
+
+#endif /* OVLB */
+/*pline.c*/
diff --git a/src/polyself.c b/src/polyself.c
new file mode 100644 (file)
index 0000000..b051acb
--- /dev/null
@@ -0,0 +1,1339 @@
+/*     SCCS Id: @(#)polyself.c 3.4     2003/01/08      */
+/*     Copyright (C) 1987, 1988, 1989 by Ken Arromdee */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Polymorph self routine.
+ *
+ * Note:  the light source handling code assumes that both youmonst.m_id
+ * and youmonst.mx will always remain 0 when it handles the case of the
+ * player polymorphed into a light-emitting monster.
+ */
+
+#include "hack.h"
+
+#ifdef OVLB
+STATIC_DCL void FDECL(polyman, (const char *,const char *));
+STATIC_DCL void NDECL(break_armor);
+STATIC_DCL void FDECL(drop_weapon,(int));
+STATIC_DCL void NDECL(uunstick);
+STATIC_DCL int FDECL(armor_to_dragon,(int));
+STATIC_DCL void NDECL(newman);
+
+/* update the youmonst.data structure pointer */
+void
+set_uasmon()
+{
+       set_mon_data(&youmonst, &mons[u.umonnum], 0);
+}
+
+/* make a (new) human out of the player */
+STATIC_OVL void
+polyman(fmt, arg)
+const char *fmt, *arg;
+{
+       boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow,
+               was_mimicking = (youmonst.m_ap_type == M_AP_OBJECT);
+       boolean could_pass_walls = Passes_walls;
+       boolean was_blind = !!Blind;
+
+       if (Upolyd) {
+               u.acurr = u.macurr;     /* restore old attribs */
+               u.amax = u.mamax;
+               u.umonnum = u.umonster;
+               flags.female = u.mfemale;
+       }
+       set_uasmon();
+
+       u.mh = u.mhmax = 0;
+       u.mtimedone = 0;
+       skinback(FALSE);
+       u.uundetected = 0;
+
+       if (sticky) uunstick();
+       find_ac();
+       if (was_mimicking) {
+           if (multi < 0) unmul("");
+           youmonst.m_ap_type = M_AP_NOTHING;
+       }
+
+       newsym(u.ux,u.uy);
+
+       You(fmt, arg);
+       /* check whether player foolishly genocided self while poly'd */
+       if ((mvitals[urole.malenum].mvflags & G_GENOD) ||
+                       (urole.femalenum != NON_PM &&
+                       (mvitals[urole.femalenum].mvflags & G_GENOD)) ||
+                       (mvitals[urace.malenum].mvflags & G_GENOD) ||
+                       (urace.femalenum != NON_PM &&
+                       (mvitals[urace.femalenum].mvflags & G_GENOD))) {
+           /* intervening activity might have clobbered genocide info */
+           killer = delayed_killer;
+           if (!killer || !strstri(killer, "genocid")) {
+               killer_format = KILLED_BY;
+               killer = "self-genocide";
+           }
+           done(GENOCIDED);
+       }
+
+       if (u.twoweap && !could_twoweap(youmonst.data))
+           untwoweapon();
+
+       if (u.utraptype == TT_PIT) {
+           if (could_pass_walls) {     /* player forms cannot pass walls */
+               u.utrap = rn1(6,2);
+           }
+       }
+       if (was_blind && !Blind) {      /* reverting from eyeless */
+           Blinded = 1L;
+           make_blinded(0L, TRUE);     /* remove blindness */
+       }
+
+       if(!Levitation && !u.ustuck &&
+          (is_pool(u.ux,u.uy) || is_lava(u.ux,u.uy)))
+               spoteffects(TRUE);
+
+       see_monsters();
+}
+
+void
+change_sex()
+{
+       /* setting u.umonster for caveman/cavewoman or priest/priestess
+          swap unintentionally makes `Upolyd' appear to be true */
+       boolean already_polyd = (boolean) Upolyd;
+
+       /* Some monsters are always of one sex and their sex can't be changed */
+       /* succubi/incubi can change, but are handled below */
+       /* !already_polyd check necessary because is_male() and is_female()
+           are true if the player is a priest/priestess */
+       if (!already_polyd || (!is_male(youmonst.data) && !is_female(youmonst.data) && !is_neuter(youmonst.data)))
+           flags.female = !flags.female;
+       if (already_polyd)      /* poly'd: also change saved sex */
+           u.mfemale = !u.mfemale;
+       max_rank_sz();          /* [this appears to be superfluous] */
+       if ((already_polyd ? u.mfemale : flags.female) && urole.name.f)
+           Strcpy(pl_character, urole.name.f);
+       else
+           Strcpy(pl_character, urole.name.m);
+       u.umonster = ((already_polyd ? u.mfemale : flags.female) && urole.femalenum != NON_PM) ?
+                       urole.femalenum : urole.malenum;
+       if (!already_polyd) {
+           u.umonnum = u.umonster;
+       } else if (u.umonnum == PM_SUCCUBUS || u.umonnum == PM_INCUBUS) {
+           flags.female = !flags.female;
+           /* change monster type to match new sex */
+           u.umonnum = (u.umonnum == PM_SUCCUBUS) ? PM_INCUBUS : PM_SUCCUBUS;
+           set_uasmon();
+       }
+}
+
+STATIC_OVL void
+newman()
+{
+       int tmp, oldlvl;
+
+       tmp = u.uhpmax;
+       oldlvl = u.ulevel;
+       u.ulevel = u.ulevel + rn1(5, -2);
+       if (u.ulevel > 127 || u.ulevel < 1) { /* level went below 0? */
+           u.ulevel = oldlvl; /* restore old level in case they lifesave */
+           goto dead;
+       }
+       if (u.ulevel > MAXULEV) u.ulevel = MAXULEV;
+       /* If your level goes down, your peak level goes down by
+          the same amount so that you can't simply use blessed
+          full healing to undo the decrease.  But if your level
+          goes up, your peak level does *not* undergo the same
+          adjustment; you might end up losing out on the chance
+          to regain some levels previously lost to other causes. */
+       if (u.ulevel < oldlvl) u.ulevelmax -= (oldlvl - u.ulevel);
+       if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel;
+
+       if (!rn2(10)) change_sex();
+
+       adjabil(oldlvl, (int)u.ulevel);
+       reset_rndmonst(NON_PM); /* new monster generation criteria */
+
+       /* random experience points for the new experience level */
+       u.uexp = rndexp(FALSE);
+
+       /* u.uhpmax * u.ulevel / oldlvl: proportionate hit points to new level
+        * -10 and +10: don't apply proportionate HP to 10 of a starting
+        *   character's hit points (since a starting character's hit points
+        *   are not on the same scale with hit points obtained through level
+        *   gain)
+        * 9 - rn2(19): random change of -9 to +9 hit points
+        */
+#ifndef LINT
+       u.uhpmax = ((u.uhpmax - 10) * (long)u.ulevel / oldlvl + 10) +
+               (9 - rn2(19));
+#endif
+
+#ifdef LINT
+       u.uhp = u.uhp + tmp;
+#else
+       u.uhp = u.uhp * (long)u.uhpmax/tmp;
+#endif
+
+       tmp = u.uenmax;
+#ifndef LINT
+       u.uenmax = u.uenmax * (long)u.ulevel / oldlvl + 9 - rn2(19);
+#endif
+       if (u.uenmax < 0) u.uenmax = 0;
+#ifndef LINT
+       u.uen = (tmp ? u.uen * (long)u.uenmax / tmp : u.uenmax);
+#endif
+
+       redist_attr();
+       u.uhunger = rn1(500,500);
+       if (Sick) make_sick(0L, (char *) 0, FALSE, SICK_ALL);
+       Stoned = 0;
+       delayed_killer = 0;
+       if (u.uhp <= 0 || u.uhpmax <= 0) {
+               if (Polymorph_control) {
+                   if (u.uhp <= 0) u.uhp = 1;
+                   if (u.uhpmax <= 0) u.uhpmax = 1;
+               } else {
+dead: /* we come directly here if their experience level went to 0 or less */
+                   Your("new form doesn't seem healthy enough to survive.");
+                   killer_format = KILLED_BY_AN;
+                   killer="unsuccessful polymorph";
+                   done(DIED);
+                   newuhs(FALSE);
+                   return; /* lifesaved */
+               }
+       }
+       newuhs(FALSE);
+       polyman("feel like a new %s!",
+               (flags.female && urace.individual.f) ? urace.individual.f :
+               (urace.individual.m) ? urace.individual.m : urace.noun);
+       if (Slimed) {
+               Your("body transforms, but there is still slime on you.");
+               Slimed = 10L;
+       }
+       flags.botl = 1;
+       see_monsters();
+       (void) encumber_msg();
+}
+
+void
+polyself(forcecontrol)
+boolean forcecontrol;     
+{
+       char buf[BUFSZ];
+       int old_light, new_light;
+       int mntmp = NON_PM;
+       int tries=0;
+       boolean draconian = (uarm &&
+                               uarm->otyp >= GRAY_DRAGON_SCALE_MAIL &&
+                               uarm->otyp <= YELLOW_DRAGON_SCALES);
+       boolean iswere = (u.ulycn >= LOW_PM || is_were(youmonst.data));
+       boolean isvamp = (youmonst.data->mlet == S_VAMPIRE || u.umonnum == PM_VAMPIRE_BAT);
+       boolean was_floating = (Levitation || Flying);
+
+        if(!Polymorph_control && !forcecontrol && !draconian && !iswere && !isvamp) {
+           if (rn2(20) > ACURR(A_CON)) {
+               You(shudder_for_moment);
+               losehp(rnd(30), "system shock", KILLED_BY_AN);
+               exercise(A_CON, FALSE);
+               return;
+           }
+       }
+       old_light = Upolyd ? emits_light(youmonst.data) : 0;
+
+       if (Polymorph_control || forcecontrol) {
+               do {
+                       getlin("Become what kind of monster? [type the name]",
+                               buf);
+                       mntmp = name_to_mon(buf);
+                       if (mntmp < LOW_PM)
+                               pline("I've never heard of such monsters.");
+                       /* Note:  humans are illegal as monsters, but an
+                        * illegal monster forces newman(), which is what we
+                        * want if they specified a human.... */
+                       else if (!polyok(&mons[mntmp]) && !your_race(&mons[mntmp]))
+                               You("cannot polymorph into that.");
+                       else break;
+               } while(++tries < 5);
+               if (tries==5) pline(thats_enough_tries);
+               /* allow skin merging, even when polymorph is controlled */
+               if (draconian &&
+                   (mntmp == armor_to_dragon(uarm->otyp) || tries == 5))
+                   goto do_merge;
+       } else if (draconian || iswere || isvamp) {
+               /* special changes that don't require polyok() */
+               if (draconian) {
+                   do_merge:
+                       mntmp = armor_to_dragon(uarm->otyp);
+                       if (!(mvitals[mntmp].mvflags & G_GENOD)) {
+                               /* allow G_EXTINCT */
+                               You("merge with your scaly armor.");
+                               uskin = uarm;
+                               uarm = (struct obj *)0;
+                               /* save/restore hack */
+                               uskin->owornmask |= I_SPECIAL;
+                       }
+               } else if (iswere) {
+                       if (is_were(youmonst.data))
+                               mntmp = PM_HUMAN; /* Illegal; force newman() */
+                       else
+                               mntmp = u.ulycn;
+               } else {
+                       if (youmonst.data->mlet == S_VAMPIRE)
+                               mntmp = PM_VAMPIRE_BAT;
+                       else
+                               mntmp = PM_VAMPIRE;
+               }
+               /* if polymon fails, "you feel" message has been given
+                  so don't follow up with another polymon or newman */
+               if (mntmp == PM_HUMAN) newman();        /* werecritter */
+               else (void) polymon(mntmp);
+               goto made_change;    /* maybe not, but this is right anyway */
+       }
+
+       if (mntmp < LOW_PM) {
+               tries = 0;
+               do {
+                       /* randomly pick an "ordinary" monster */
+                       mntmp = rn1(SPECIAL_PM - LOW_PM, LOW_PM);
+               } while((!polyok(&mons[mntmp]) || is_placeholder(&mons[mntmp]))
+                               && tries++ < 200);
+       }
+
+       /* The below polyok() fails either if everything is genocided, or if
+        * we deliberately chose something illegal to force newman().
+        */
+       if (!polyok(&mons[mntmp]) || !rn2(5) || your_race(&mons[mntmp]))
+               newman();
+       else if(!polymon(mntmp)) return;
+
+       if (!uarmg) selftouch("No longer petrify-resistant, you");
+
+ made_change:
+       new_light = Upolyd ? emits_light(youmonst.data) : 0;
+       if (old_light != new_light) {
+           if (old_light)
+               del_light_source(LS_MONSTER, (genericptr_t)&youmonst);
+           if (new_light == 1) ++new_light;  /* otherwise it's undetectable */
+           if (new_light)
+               new_light_source(u.ux, u.uy, new_light,
+                                LS_MONSTER, (genericptr_t)&youmonst);
+       }
+       if (is_pool(u.ux,u.uy) && was_floating && !(Levitation || Flying) &&
+               !breathless(youmonst.data) && !amphibious(youmonst.data) &&
+               !Swimming) drown();
+}
+
+/* (try to) make a mntmp monster out of the player */
+int
+polymon(mntmp) /* returns 1 if polymorph successful */
+int    mntmp;
+{
+       boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow,
+               was_blind = !!Blind, dochange = FALSE;
+       boolean could_pass_walls = Passes_walls;
+       int mlvl;
+
+       if (mvitals[mntmp].mvflags & G_GENOD) { /* allow G_EXTINCT */
+               You_feel("rather %s-ish.",mons[mntmp].mname);
+               exercise(A_WIS, TRUE);
+               return(0);
+       }
+
+       /* KMH, conduct */
+       u.uconduct.polyselfs++;
+
+       if (!Upolyd) {
+               /* Human to monster; save human stats */
+               u.macurr = u.acurr;
+               u.mamax = u.amax;
+               u.mfemale = flags.female;
+       } else {
+               /* Monster to monster; restore human stats, to be
+                * immediately changed to provide stats for the new monster
+                */
+               u.acurr = u.macurr;
+               u.amax = u.mamax;
+               flags.female = u.mfemale;
+       }
+
+       if (youmonst.m_ap_type) {
+           /* stop mimicking immediately */
+           if (multi < 0) unmul("");
+       } else if (mons[mntmp].mlet != S_MIMIC) {
+           /* as in polyman() */
+           youmonst.m_ap_type = M_AP_NOTHING;
+       }
+       if (is_male(&mons[mntmp])) {
+               if(flags.female) dochange = TRUE;
+       } else if (is_female(&mons[mntmp])) {
+               if(!flags.female) dochange = TRUE;
+       } else if (!is_neuter(&mons[mntmp]) && mntmp != u.ulycn) {
+               if(!rn2(10)) dochange = TRUE;
+       }
+       if (dochange) {
+               flags.female = !flags.female;
+               You("%s %s%s!",
+                   (u.umonnum != mntmp) ? "turn into a" : "feel like a new",
+                   (is_male(&mons[mntmp]) || is_female(&mons[mntmp])) ? "" :
+                       flags.female ? "female " : "male ",
+                   mons[mntmp].mname);
+       } else {
+               if (u.umonnum != mntmp)
+                       You("turn into %s!", an(mons[mntmp].mname));
+               else
+                       You_feel("like a new %s!", mons[mntmp].mname);
+       }
+       if (Stoned && poly_when_stoned(&mons[mntmp])) {
+               /* poly_when_stoned already checked stone golem genocide */
+               You("turn to stone!");
+               mntmp = PM_STONE_GOLEM;
+               Stoned = 0;
+               delayed_killer = 0;
+       }
+
+       u.mtimedone = rn1(500, 500);
+       u.umonnum = mntmp;
+       set_uasmon();
+
+       /* New stats for monster, to last only as long as polymorphed.
+        * Currently only strength gets changed.
+        */
+       if(strongmonst(&mons[mntmp])) ABASE(A_STR) = AMAX(A_STR) = STR18(100);
+
+       if (Stone_resistance && Stoned) { /* parnes@eniac.seas.upenn.edu */
+               Stoned = 0;
+               delayed_killer = 0;
+               You("no longer seem to be petrifying.");
+       }
+       if (Sick_resistance && Sick) {
+               make_sick(0L, (char *) 0, FALSE, SICK_ALL);
+               You("no longer feel sick.");
+       }
+       if (Slimed) {
+           if (flaming(youmonst.data)) {
+               pline_The("slime burns away!");
+               Slimed = 0L;
+               flags.botl = 1;
+           } else if (mntmp == PM_GREEN_SLIME) {
+               /* do it silently */
+               Slimed = 0L;
+               flags.botl = 1;
+           }
+       }
+       if (nohands(youmonst.data)) Glib = 0;
+
+       /*
+       mlvl = adj_lev(&mons[mntmp]);
+        * We can't do the above, since there's no such thing as an
+        * "experience level of you as a monster" for a polymorphed character.
+        */
+       mlvl = (int)mons[mntmp].mlevel;
+       if (youmonst.data->mlet == S_DRAGON && mntmp >= PM_GRAY_DRAGON) {
+               u.mhmax = In_endgame(&u.uz) ? (8*mlvl) : (4*mlvl + d(mlvl,4));
+       } else if (is_golem(youmonst.data)) {
+               u.mhmax = golemhp(mntmp);
+       } else {
+               if (!mlvl) u.mhmax = rnd(4);
+               else u.mhmax = d(mlvl, 8);
+               if (is_home_elemental(&mons[mntmp])) u.mhmax *= 3;
+       }
+       u.mh = u.mhmax;
+
+       if (u.ulevel < mlvl) {
+       /* Low level characters can't become high level monsters for long */
+#ifdef DUMB
+               /* DRS/NS 2.2.6 messes up -- Peter Kendell */
+               int mtd = u.mtimedone, ulv = u.ulevel;
+
+               u.mtimedone = mtd * ulv / mlvl;
+#else
+               u.mtimedone = u.mtimedone * u.ulevel / mlvl;
+#endif
+       }
+
+       if (uskin && mntmp != armor_to_dragon(uskin->otyp))
+               skinback(FALSE);
+       break_armor();
+       drop_weapon(1);
+       if (hides_under(youmonst.data))
+               u.uundetected = OBJ_AT(u.ux, u.uy);
+       else if (youmonst.data->mlet == S_EEL)
+               u.uundetected = is_pool(u.ux, u.uy);
+       else
+               u.uundetected = 0;
+
+       if (u.utraptype == TT_PIT) {
+           if (could_pass_walls && !Passes_walls) {
+               u.utrap = rn1(6,2);
+           } else if (!could_pass_walls && Passes_walls) {
+               u.utrap = 0;
+           }
+       }
+       if (was_blind && !Blind) {      /* previous form was eyeless */
+           Blinded = 1L;
+           make_blinded(0L, TRUE);     /* remove blindness */
+       }
+       newsym(u.ux,u.uy);              /* Change symbol */
+
+       if (!sticky && !u.uswallow && u.ustuck && sticks(youmonst.data)) u.ustuck = 0;
+       else if (sticky && !sticks(youmonst.data)) uunstick();
+#ifdef STEED
+       if (u.usteed) {
+           if (touch_petrifies(u.usteed->data) &&
+                       !Stone_resistance && rnl(3)) {
+               char buf[BUFSZ];
+
+               pline("No longer petrifying-resistant, you touch %s.",
+                               mon_nam(u.usteed));
+               Sprintf(buf, "riding %s", an(u.usteed->data->mname));
+               instapetrify(buf);
+           }
+           if (!can_ride(u.usteed)) dismount_steed(DISMOUNT_POLY);
+       }
+#endif
+
+       if (flags.verbose) {
+           static const char use_thec[] = "Use the command #%s to %s.";
+           static const char monsterc[] = "monster";
+           if (can_breathe(youmonst.data))
+               pline(use_thec,monsterc,"use your breath weapon");
+           if (attacktype(youmonst.data, AT_SPIT))
+               pline(use_thec,monsterc,"spit venom");
+           if (youmonst.data->mlet == S_NYMPH)
+               pline(use_thec,monsterc,"remove an iron ball");
+           if (attacktype(youmonst.data, AT_GAZE))
+               pline(use_thec,monsterc,"gaze at monsters");
+           if (is_hider(youmonst.data))
+               pline(use_thec,monsterc,"hide");
+           if (is_were(youmonst.data))
+               pline(use_thec,monsterc,"summon help");
+           if (webmaker(youmonst.data))
+               pline(use_thec,monsterc,"spin a web");
+           if (u.umonnum == PM_GREMLIN)
+               pline(use_thec,monsterc,"multiply in a fountain");
+           if (is_unicorn(youmonst.data))
+               pline(use_thec,monsterc,"use your horn");
+           if (is_mind_flayer(youmonst.data))
+               pline(use_thec,monsterc,"emit a mental blast");
+           if (youmonst.data->msound == MS_SHRIEK) /* worthless, actually */
+               pline(use_thec,monsterc,"shriek");
+           if (lays_eggs(youmonst.data) && flags.female)
+               pline(use_thec,"sit","lay an egg");
+       }
+       /* you now know what an egg of your type looks like */
+       if (lays_eggs(youmonst.data)) {
+           learn_egg_type(u.umonnum);
+           /* make queen bees recognize killer bee eggs */
+           learn_egg_type(egg_type_from_parent(u.umonnum, TRUE));
+       }
+       find_ac();
+       if((!Levitation && !u.ustuck && !Flying &&
+           (is_pool(u.ux,u.uy) || is_lava(u.ux,u.uy))) ||
+          (Underwater && !Swimming))
+           spoteffects(TRUE);
+       if (Passes_walls && u.utrap && u.utraptype == TT_INFLOOR) {
+           u.utrap = 0;
+           pline_The("rock seems to no longer trap you.");
+       } else if (likes_lava(youmonst.data) && u.utrap && u.utraptype == TT_LAVA) {
+           u.utrap = 0;
+           pline_The("lava now feels soothing.");
+       }
+       if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) {
+           if (Punished) {
+               You("slip out of the iron chain.");
+               unpunish();
+           }
+       }
+       if (u.utrap && (u.utraptype == TT_WEB || u.utraptype == TT_BEARTRAP) &&
+               (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data) ||
+                 (youmonst.data->msize <= MZ_SMALL && u.utraptype == TT_BEARTRAP))) {
+           You("are no longer stuck in the %s.",
+                   u.utraptype == TT_WEB ? "web" : "bear trap");
+           /* probably should burn webs too if PM_FIRE_ELEMENTAL */
+           u.utrap = 0;
+       }
+       if (webmaker(youmonst.data) && u.utrap && u.utraptype == TT_WEB) {
+           You("orient yourself on the web.");
+           u.utrap = 0;
+       }
+       flags.botl = 1;
+       vision_full_recalc = 1;
+       see_monsters();
+       exercise(A_CON, FALSE);
+       exercise(A_WIS, TRUE);
+       (void) encumber_msg();
+       return(1);
+}
+
+STATIC_OVL void
+break_armor()
+{
+    register struct obj *otmp;
+
+    if (breakarm(youmonst.data)) {
+       if ((otmp = uarm) != 0) {
+               if (donning(otmp)) cancel_don();
+               You("break out of your armor!");
+               exercise(A_STR, FALSE);
+               (void) Armor_gone();
+               useup(otmp);
+       }
+       if ((otmp = uarmc) != 0) {
+           if(otmp->oartifact) {
+               Your("%s falls off!", cloak_simple_name(otmp));
+               (void) Cloak_off();
+               dropx(otmp);
+           } else {
+               Your("%s tears apart!", cloak_simple_name(otmp));
+               (void) Cloak_off();
+               useup(otmp);
+           }
+       }
+#ifdef TOURIST
+       if (uarmu) {
+               Your("shirt rips to shreds!");
+               useup(uarmu);
+       }
+#endif
+    } else if (sliparm(youmonst.data)) {
+       if (((otmp = uarm) != 0) && (racial_exception(&youmonst, otmp) < 1)) {
+               if (donning(otmp)) cancel_don();
+               Your("armor falls around you!");
+               (void) Armor_gone();
+               dropx(otmp);
+       }
+       if ((otmp = uarmc) != 0) {
+               if (is_whirly(youmonst.data))
+                       Your("%s falls, unsupported!", cloak_simple_name(otmp));
+               else You("shrink out of your %s!", cloak_simple_name(otmp));
+               (void) Cloak_off();
+               dropx(otmp);
+       }
+#ifdef TOURIST
+       if ((otmp = uarmu) != 0) {
+               if (is_whirly(youmonst.data))
+                       You("seep right through your shirt!");
+               else You("become much too small for your shirt!");
+               setworn((struct obj *)0, otmp->owornmask & W_ARMU);
+               dropx(otmp);
+       }
+#endif
+    }
+    if (has_horns(youmonst.data)) {
+       if ((otmp = uarmh) != 0) {
+           if (is_flimsy(otmp) && !donning(otmp)) {
+               char hornbuf[BUFSZ], yourbuf[BUFSZ];
+
+               /* Future possiblities: This could damage/destroy helmet */
+               Sprintf(hornbuf, "horn%s", plur(num_horns(youmonst.data)));
+               Your("%s %s through %s %s.", hornbuf, vtense(hornbuf, "pierce"),
+                    shk_your(yourbuf, otmp), xname(otmp));
+           } else {
+               if (donning(otmp)) cancel_don();
+               Your("helmet falls to the %s!", surface(u.ux, u.uy));
+               (void) Helmet_off();
+               dropx(otmp);
+           }
+       }
+    }
+    if (nohands(youmonst.data) || verysmall(youmonst.data)) {
+       if ((otmp = uarmg) != 0) {
+           if (donning(otmp)) cancel_don();
+           /* Drop weapon along with gloves */
+           You("drop your gloves%s!", uwep ? " and weapon" : "");
+           drop_weapon(0);
+           (void) Gloves_off();
+           dropx(otmp);
+       }
+       if ((otmp = uarms) != 0) {
+           You("can no longer hold your shield!");
+           (void) Shield_off();
+           dropx(otmp);
+       }
+       if ((otmp = uarmh) != 0) {
+           if (donning(otmp)) cancel_don();
+           Your("helmet falls to the %s!", surface(u.ux, u.uy));
+           (void) Helmet_off();
+           dropx(otmp);
+       }
+    }
+    if (nohands(youmonst.data) || verysmall(youmonst.data) ||
+               slithy(youmonst.data) || youmonst.data->mlet == S_CENTAUR) {
+       if ((otmp = uarmf) != 0) {
+           if (donning(otmp)) cancel_don();
+           if (is_whirly(youmonst.data))
+               Your("boots fall away!");
+           else Your("boots %s off your feet!",
+                       verysmall(youmonst.data) ? "slide" : "are pushed");
+           (void) Boots_off();
+           dropx(otmp);
+       }
+    }
+}
+
+STATIC_OVL void
+drop_weapon(alone)
+int alone;
+{
+    struct obj *otmp;
+    struct obj *otmp2;
+
+    if ((otmp = uwep) != 0) {
+       /* !alone check below is currently superfluous but in the
+        * future it might not be so if there are monsters which cannot
+        * wear gloves but can wield weapons
+        */
+       if (!alone || cantwield(youmonst.data)) {
+           struct obj *wep = uwep;
+
+           if (alone) You("find you must drop your weapon%s!",
+                               u.twoweap ? "s" : "");
+           otmp2 = u.twoweap ? uswapwep : 0;
+           uwepgone();
+           if (!wep->cursed || wep->otyp != LOADSTONE)
+               dropx(otmp);
+           if (otmp2 != 0) {
+               uswapwepgone();
+               if (!otmp2->cursed || otmp2->otyp != LOADSTONE)
+                   dropx(otmp2);
+           }
+           untwoweapon();
+       } else if (!could_twoweap(youmonst.data)) {
+           untwoweapon();
+       }
+    }
+}
+
+void
+rehumanize()
+{
+       /* You can't revert back while unchanging */
+       if (Unchanging && (u.mh < 1)) {
+               killer_format = NO_KILLER_PREFIX;
+               killer = "killed while stuck in creature form";
+               done(DIED);
+       }
+
+       if (emits_light(youmonst.data))
+           del_light_source(LS_MONSTER, (genericptr_t)&youmonst);
+       polyman("return to %s form!", urace.adj);
+
+       if (u.uhp < 1) {
+           char kbuf[256];
+
+           Sprintf(kbuf, "reverting to unhealthy %s form", urace.adj);
+           killer_format = KILLED_BY;
+           killer = kbuf;
+           done(DIED);
+       }
+       if (!uarmg) selftouch("No longer petrify-resistant, you");
+       nomul(0);
+
+       flags.botl = 1;
+       vision_full_recalc = 1;
+       (void) encumber_msg();
+}
+
+int
+dobreathe()
+{
+       struct attack *mattk;
+
+       if (Strangled) {
+           You_cant("breathe.  Sorry.");
+           return(0);
+       }
+       if (u.uen < 15) {
+           You("don't have enough energy to breathe!");
+           return(0);
+       }
+       u.uen -= 15;
+       flags.botl = 1;
+
+       if (!getdir((char *)0)) return(0);
+
+       mattk = attacktype_fordmg(youmonst.data, AT_BREA, AD_ANY);
+       if (!mattk)
+           impossible("bad breath attack?");   /* mouthwash needed... */
+       else
+           buzz((int) (20 + mattk->adtyp-1), (int)mattk->damn,
+               u.ux, u.uy, u.dx, u.dy);
+       return(1);
+}
+
+int
+dospit()
+{
+       struct obj *otmp;
+
+       if (!getdir((char *)0)) return(0);
+       otmp = mksobj(u.umonnum==PM_COBRA ? BLINDING_VENOM : ACID_VENOM,
+                       TRUE, FALSE);
+       otmp->spe = 1; /* to indicate it's yours */
+       throwit(otmp, 0L, FALSE);
+       return(1);
+}
+
+int
+doremove()
+{
+       if (!Punished) {
+               You("are not chained to anything!");
+               return(0);
+       }
+       unpunish();
+       return(1);
+}
+
+int
+dospinweb()
+{
+       register struct trap *ttmp = t_at(u.ux,u.uy);
+
+       if (Levitation || Is_airlevel(&u.uz)
+           || Underwater || Is_waterlevel(&u.uz)) {
+               You("must be on the ground to spin a web.");
+               return(0);
+       }
+       if (u.uswallow) {
+               You("release web fluid inside %s.", mon_nam(u.ustuck));
+               if (is_animal(u.ustuck->data)) {
+                       expels(u.ustuck, u.ustuck->data, TRUE);
+                       return(0);
+               }
+               if (is_whirly(u.ustuck->data)) {
+                       int i;
+
+                       for (i = 0; i < NATTK; i++)
+                               if (u.ustuck->data->mattk[i].aatyp == AT_ENGL)
+                                       break;
+                       if (i == NATTK)
+                              impossible("Swallower has no engulfing attack?");
+                       else {
+                               char sweep[30];
+
+                               sweep[0] = '\0';
+                               switch(u.ustuck->data->mattk[i].adtyp) {
+                                       case AD_FIRE:
+                                               Strcpy(sweep, "ignites and ");
+                                               break;
+                                       case AD_ELEC:
+                                               Strcpy(sweep, "fries and ");
+                                               break;
+                                       case AD_COLD:
+                                               Strcpy(sweep,
+                                                     "freezes, shatters and ");
+                                               break;
+                               }
+                               pline_The("web %sis swept away!", sweep);
+                       }
+                       return(0);
+               }                    /* default: a nasty jelly-like creature */
+               pline_The("web dissolves into %s.", mon_nam(u.ustuck));
+               return(0);
+       }
+       if (u.utrap) {
+               You("cannot spin webs while stuck in a trap.");
+               return(0);
+       }
+       exercise(A_DEX, TRUE);
+       if (ttmp) switch (ttmp->ttyp) {
+               case PIT:
+               case SPIKED_PIT: You("spin a web, covering up the pit.");
+                       deltrap(ttmp);
+                       bury_objs(u.ux, u.uy);
+                       newsym(u.ux, u.uy);
+                       return(1);
+               case SQKY_BOARD: pline_The("squeaky board is muffled.");
+                       deltrap(ttmp);
+                       newsym(u.ux, u.uy);
+                       return(1);
+               case TELEP_TRAP:
+               case LEVEL_TELEP:
+               case MAGIC_PORTAL:
+                       Your("webbing vanishes!");
+                       return(0);
+               case WEB: You("make the web thicker.");
+                       return(1);
+               case HOLE:
+               case TRAPDOOR:
+                       You("web over the %s.",
+                           (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole");
+                       deltrap(ttmp);
+                       newsym(u.ux, u.uy);
+                       return 1;
+               case ROLLING_BOULDER_TRAP:
+                       You("spin a web, jamming the trigger.");
+                       deltrap(ttmp);
+                       newsym(u.ux, u.uy);
+                       return(1);
+               case ARROW_TRAP:
+               case DART_TRAP:
+               case BEAR_TRAP:
+               case ROCKTRAP:
+               case FIRE_TRAP:
+               case LANDMINE:
+               case SLP_GAS_TRAP:
+               case RUST_TRAP:
+               case MAGIC_TRAP:
+               case ANTI_MAGIC:
+               case POLY_TRAP:
+                       You("have triggered a trap!");
+                       dotrap(ttmp, 0);
+                       return(1);
+               default:
+                       impossible("Webbing over trap type %d?", ttmp->ttyp);
+                       return(0);
+               }
+       else if (On_stairs(u.ux, u.uy)) {
+           /* cop out: don't let them hide the stairs */
+           Your("web fails to impede access to the %s.",
+                (levl[u.ux][u.uy].typ == STAIRS) ? "stairs" : "ladder");
+           return(1);
+                
+       }
+       ttmp = maketrap(u.ux, u.uy, WEB);
+       if (ttmp) {
+               ttmp->tseen = 1;
+               ttmp->madeby_u = 1;
+       }
+       newsym(u.ux, u.uy);
+       return(1);
+}
+
+int
+dosummon()
+{
+       int placeholder;
+       if (u.uen < 10) {
+           You("lack the energy to send forth a call for help!");
+           return(0);
+       }
+       u.uen -= 10;
+       flags.botl = 1;
+
+       You("call upon your brethren for help!");
+       exercise(A_WIS, TRUE);
+       if (!were_summon(youmonst.data, TRUE, &placeholder, (char *)0))
+               pline("But none arrive.");
+       return(1);
+}
+
+int
+dogaze()
+{
+       register struct monst *mtmp;
+       int looked = 0;
+       char qbuf[QBUFSZ];
+       int i;
+       uchar adtyp = 0;
+
+       for (i = 0; i < NATTK; i++) {
+           if(youmonst.data->mattk[i].aatyp == AT_GAZE) {
+               adtyp = youmonst.data->mattk[i].adtyp;
+               break;
+           }
+       }
+       if (adtyp != AD_CONF && adtyp != AD_FIRE) {
+           impossible("gaze attack %d?", adtyp);
+           return 0;
+       }
+
+
+       if (Blind) {
+           You_cant("see anything to gaze at.");
+           return 0;
+       }
+       if (u.uen < 15) {
+           You("lack the energy to use your special gaze!");
+           return(0);
+       }
+       u.uen -= 15;
+       flags.botl = 1;
+
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+           if (DEADMONSTER(mtmp)) continue;
+           if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)) {
+               looked++;
+               if (Invis && !perceives(mtmp->data))
+                   pline("%s seems not to notice your gaze.", Monnam(mtmp));
+               else if (mtmp->minvis && !See_invisible)
+                   You_cant("see where to gaze at %s.", Monnam(mtmp));
+               else if (mtmp->m_ap_type == M_AP_FURNITURE
+                       || mtmp->m_ap_type == M_AP_OBJECT) {
+                   looked--;
+                   continue;
+               } else if (flags.safe_dog && !Confusion && !Hallucination
+                 && mtmp->mtame) {
+                   You("avoid gazing at %s.", y_monnam(mtmp));
+               } else {
+                   if (flags.confirm && mtmp->mpeaceful && !Confusion
+                                                       && !Hallucination) {
+                       Sprintf(qbuf, "Really %s %s?",
+                           (adtyp == AD_CONF) ? "confuse" : "attack",
+                           mon_nam(mtmp));
+                       if (yn(qbuf) != 'y') continue;
+                       setmangry(mtmp);
+                   }
+                   if (!mtmp->mcanmove || mtmp->mstun || mtmp->msleeping ||
+                                   !mtmp->mcansee || !haseyes(mtmp->data)) {
+                       looked--;
+                       continue;
+                   }
+                   /* No reflection check for consistency with when a monster
+                    * gazes at *you*--only medusa gaze gets reflected then.
+                    */
+                   if (adtyp == AD_CONF) {
+                       if (!mtmp->mconf)
+                           Your("gaze confuses %s!", mon_nam(mtmp));
+                       else
+                           pline("%s is getting more and more confused.",
+                                                       Monnam(mtmp));
+                       mtmp->mconf = 1;
+                   } else if (adtyp == AD_FIRE) {
+                       int dmg = d(2,6);
+                       You("attack %s with a fiery gaze!", mon_nam(mtmp));
+                       if (resists_fire(mtmp)) {
+                           pline_The("fire doesn't burn %s!", mon_nam(mtmp));
+                           dmg = 0;
+                       }
+                       if((int) u.ulevel > rn2(20))
+                           (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE);
+                       if((int) u.ulevel > rn2(20))
+                           (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE);
+                       if((int) u.ulevel > rn2(25))
+                           (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE);
+                       if (dmg && !DEADMONSTER(mtmp)) mtmp->mhp -= dmg;
+                       if (mtmp->mhp <= 0) killed(mtmp);
+                   }
+                   /* For consistency with passive() in uhitm.c, this only
+                    * affects you if the monster is still alive.
+                    */
+                   if (!DEADMONSTER(mtmp) &&
+                         (mtmp->data==&mons[PM_FLOATING_EYE]) && !mtmp->mcan) {
+                       if (!Free_action) {
+                           You("are frozen by %s gaze!",
+                                            s_suffix(mon_nam(mtmp)));
+                           nomul((u.ulevel > 6 || rn2(4)) ?
+                                   -d((int)mtmp->m_lev+1,
+                                           (int)mtmp->data->mattk[0].damd)
+                                   : -200);
+                           return 1;
+                       } else
+                           You("stiffen momentarily under %s gaze.",
+                                   s_suffix(mon_nam(mtmp)));
+                   }
+                   /* Technically this one shouldn't affect you at all because
+                    * the Medusa gaze is an active monster attack that only
+                    * works on the monster's turn, but for it to *not* have an
+                    * effect would be too weird.
+                    */
+                   if (!DEADMONSTER(mtmp) &&
+                           (mtmp->data == &mons[PM_MEDUSA]) && !mtmp->mcan) {
+                       pline(
+                        "Gazing at the awake %s is not a very good idea.",
+                           l_monnam(mtmp));
+                       /* as if gazing at a sleeping anything is fruitful... */
+                       You("turn to stone...");
+                       killer_format = KILLED_BY;
+                       killer = "deliberately meeting Medusa's gaze";
+                       done(STONING);
+                   }
+               }
+           }
+       }
+       if (!looked) You("gaze at no place in particular.");
+       return 1;
+}
+
+int
+dohide()
+{
+       boolean ismimic = youmonst.data->mlet == S_MIMIC;
+
+       if (u.uundetected || (ismimic && youmonst.m_ap_type != M_AP_NOTHING)) {
+               You("are already hiding.");
+               return(0);
+       }
+       if (ismimic) {
+               /* should bring up a dialog "what would you like to imitate?" */
+               youmonst.m_ap_type = M_AP_OBJECT;
+               youmonst.mappearance = STRANGE_OBJECT;
+       } else
+               u.uundetected = 1;
+       newsym(u.ux,u.uy);
+       return(1);
+}
+
+int
+domindblast()
+{
+       struct monst *mtmp, *nmon;
+
+       if (u.uen < 10) {
+           You("concentrate but lack the energy to maintain doing so.");
+           return(0);
+       }
+       u.uen -= 10;
+       flags.botl = 1;
+
+       You("concentrate.");
+       pline("A wave of psychic energy pours out.");
+       for(mtmp=fmon; mtmp; mtmp = nmon) {
+               int u_sen;
+
+               nmon = mtmp->nmon;
+               if (DEADMONSTER(mtmp))
+                       continue;
+               if (distu(mtmp->mx, mtmp->my) > BOLT_LIM * BOLT_LIM)
+                       continue;
+               if(mtmp->mpeaceful)
+                       continue;
+               u_sen = telepathic(mtmp->data) && !mtmp->mcansee;
+               if (u_sen || (telepathic(mtmp->data) && rn2(2)) || !rn2(10)) {
+                       You("lock in on %s %s.", s_suffix(mon_nam(mtmp)),
+                               u_sen ? "telepathy" :
+                               telepathic(mtmp->data) ? "latent telepathy" :
+                               "mind");
+                       mtmp->mhp -= rnd(15);
+                       if (mtmp->mhp <= 0)
+                               killed(mtmp);
+               }
+       }
+       return 1;
+}
+
+STATIC_OVL void
+uunstick()
+{
+       pline("%s is no longer in your clutches.", Monnam(u.ustuck));
+       u.ustuck = 0;
+}
+
+void
+skinback(silently)
+boolean silently;
+{
+       if (uskin) {
+               if (!silently) Your("skin returns to its original form.");
+               uarm = uskin;
+               uskin = (struct obj *)0;
+               /* undo save/restore hack */
+               uarm->owornmask &= ~I_SPECIAL;
+       }
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+const char *
+mbodypart(mon, part)
+struct monst *mon;
+int part;
+{
+       static NEARDATA const char
+       *humanoid_parts[] = { "arm", "eye", "face", "finger",
+               "fingertip", "foot", "hand", "handed", "head", "leg",
+               "light headed", "neck", "spine", "toe", "hair",
+               "blood", "lung", "nose", "stomach"},
+       *jelly_parts[] = { "pseudopod", "dark spot", "front",
+               "pseudopod extension", "pseudopod extremity",
+               "pseudopod root", "grasp", "grasped", "cerebral area",
+               "lower pseudopod", "viscous", "middle", "surface",
+               "pseudopod extremity", "ripples", "juices",
+               "surface", "sensor", "stomach" },
+       *animal_parts[] = { "forelimb", "eye", "face", "foreclaw", "claw tip",
+               "rear claw", "foreclaw", "clawed", "head", "rear limb",
+               "light headed", "neck", "spine", "rear claw tip",
+               "fur", "blood", "lung", "nose", "stomach" },
+       *bird_parts[] = { "wing", "eye", "face", "wing", "wing tip",
+               "foot", "wing", "winged", "head", "leg",
+               "light headed", "neck", "spine", "toe",
+               "feathers", "blood", "lung", "bill", "stomach" },
+       *horse_parts[] = { "foreleg", "eye", "face", "forehoof", "hoof tip",
+               "rear hoof", "foreclaw", "hooved", "head", "rear leg",
+               "light headed", "neck", "backbone", "rear hoof tip",
+               "mane", "blood", "lung", "nose", "stomach"},
+       *sphere_parts[] = { "appendage", "optic nerve", "body", "tentacle",
+               "tentacle tip", "lower appendage", "tentacle", "tentacled",
+               "body", "lower tentacle", "rotational", "equator", "body",
+               "lower tentacle tip", "cilia", "life force", "retina",
+               "olfactory nerve", "interior" },
+       *fungus_parts[] = { "mycelium", "visual area", "front", "hypha",
+               "hypha", "root", "strand", "stranded", "cap area",
+               "rhizome", "sporulated", "stalk", "root", "rhizome tip",
+               "spores", "juices", "gill", "gill", "interior" },
+       *vortex_parts[] = { "region", "eye", "front", "minor current",
+               "minor current", "lower current", "swirl", "swirled",
+               "central core", "lower current", "addled", "center",
+               "currents", "edge", "currents", "life force",
+               "center", "leading edge", "interior" },
+       *snake_parts[] = { "vestigial limb", "eye", "face", "large scale",
+               "large scale tip", "rear region", "scale gap", "scale gapped",
+               "head", "rear region", "light headed", "neck", "length",
+               "rear scale", "scales", "blood", "lung", "forked tongue", "stomach" },
+       *fish_parts[] = { "fin", "eye", "premaxillary", "pelvic axillary",
+               "pelvic fin", "anal fin", "pectoral fin", "finned", "head", "peduncle",
+               "played out", "gills", "dorsal fin", "caudal fin",
+               "scales", "blood", "gill", "nostril", "stomach" };
+       /* claw attacks are overloaded in mons[]; most humanoids with
+          such attacks should still reference hands rather than claws */
+       static const char not_claws[] = {
+               S_HUMAN, S_MUMMY, S_ZOMBIE, S_ANGEL,
+               S_NYMPH, S_LEPRECHAUN, S_QUANTMECH, S_VAMPIRE,
+               S_ORC, S_GIANT,         /* quest nemeses */
+               '\0'            /* string terminator; assert( S_xxx != 0 ); */
+       };
+       struct permonst *mptr = mon->data;
+
+       if (part == HAND || part == HANDED) {   /* some special cases */
+           if (mptr->mlet == S_DOG || mptr->mlet == S_FELINE ||
+                   mptr->mlet == S_YETI)
+               return part == HAND ? "paw" : "pawed";
+           if (humanoid(mptr) && attacktype(mptr, AT_CLAW) &&
+                   !index(not_claws, mptr->mlet) &&
+                   mptr != &mons[PM_STONE_GOLEM] &&
+                   mptr != &mons[PM_INCUBUS] && mptr != &mons[PM_SUCCUBUS])
+               return part == HAND ? "claw" : "clawed";
+       }
+       if ((mptr == &mons[PM_MUMAK] || mptr == &mons[PM_MASTODON]) &&
+               part == NOSE)
+           return "trunk";
+       if (mptr == &mons[PM_SHARK] && part == HAIR)
+           return "skin";      /* sharks don't have scales */
+       if (mptr == &mons[PM_JELLYFISH] && (part == ARM || part == FINGER ||
+           part == HAND || part == FOOT || part == TOE))
+           return "tentacle";
+       if (mptr == &mons[PM_FLOATING_EYE] && part == EYE)
+           return "cornea";
+       if (humanoid(mptr) &&
+               (part == ARM || part == FINGER || part == FINGERTIP ||
+                   part == HAND || part == HANDED))
+           return humanoid_parts[part];
+       if (mptr == &mons[PM_RAVEN])
+           return bird_parts[part];
+       if (mptr->mlet == S_CENTAUR || mptr->mlet == S_UNICORN ||
+               (mptr == &mons[PM_ROTHE] && part != HAIR))
+           return horse_parts[part];
+       if (mptr->mlet == S_LIGHT) {
+               if (part == HANDED) return "rayed";
+               else if (part == ARM || part == FINGER ||
+                               part == FINGERTIP || part == HAND) return "ray";
+               else return "beam";
+       }
+       if (mptr->mlet == S_EEL && mptr != &mons[PM_JELLYFISH])
+           return fish_parts[part];
+       if (slithy(mptr) || (mptr->mlet == S_DRAGON && part == HAIR))
+           return snake_parts[part];
+       if (mptr->mlet == S_EYE)
+           return sphere_parts[part];
+       if (mptr->mlet == S_JELLY || mptr->mlet == S_PUDDING ||
+               mptr->mlet == S_BLOB || mptr == &mons[PM_JELLYFISH])
+           return jelly_parts[part];
+       if (mptr->mlet == S_VORTEX || mptr->mlet == S_ELEMENTAL)
+           return vortex_parts[part];
+       if (mptr->mlet == S_FUNGUS)
+           return fungus_parts[part];
+       if (humanoid(mptr))
+           return humanoid_parts[part];
+       return animal_parts[part];
+}
+
+const char *
+body_part(part)
+int part;
+{
+       return mbodypart(&youmonst, part);
+}
+
+#endif /* OVL1 */
+#ifdef OVL0
+
+int
+poly_gender()
+{
+/* Returns gender of polymorphed player; 0/1=same meaning as flags.female,
+ * 2=none.
+ */
+       if (is_neuter(youmonst.data) || !humanoid(youmonst.data)) return 2;
+       return flags.female;
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+void
+ugolemeffects(damtype, dam)
+int damtype, dam;
+{
+       int heal = 0;
+       /* We won't bother with "slow"/"haste" since players do not
+        * have a monster-specific slow/haste so there is no way to
+        * restore the old velocity once they are back to human.
+        */
+       if (u.umonnum != PM_FLESH_GOLEM && u.umonnum != PM_IRON_GOLEM)
+               return;
+       switch (damtype) {
+               case AD_ELEC: if (u.umonnum == PM_FLESH_GOLEM)
+                               heal = dam / 6; /* Approx 1 per die */
+                       break;
+               case AD_FIRE: if (u.umonnum == PM_IRON_GOLEM)
+                               heal = dam;
+                       break;
+       }
+       if (heal && (u.mh < u.mhmax)) {
+               u.mh += heal;
+               if (u.mh > u.mhmax) u.mh = u.mhmax;
+               flags.botl = 1;
+               pline("Strangely, you feel better than before.");
+               exercise(A_STR, TRUE);
+       }
+}
+
+STATIC_OVL int
+armor_to_dragon(atyp)
+int atyp;
+{
+       switch(atyp) {
+           case GRAY_DRAGON_SCALE_MAIL:
+           case GRAY_DRAGON_SCALES:
+               return PM_GRAY_DRAGON;
+           case SILVER_DRAGON_SCALE_MAIL:
+           case SILVER_DRAGON_SCALES:
+               return PM_SILVER_DRAGON;
+#if 0  /* DEFERRED */
+           case SHIMMERING_DRAGON_SCALE_MAIL:
+           case SHIMMERING_DRAGON_SCALES:
+               return PM_SHIMMERING_DRAGON;
+#endif
+           case RED_DRAGON_SCALE_MAIL:
+           case RED_DRAGON_SCALES:
+               return PM_RED_DRAGON;
+           case ORANGE_DRAGON_SCALE_MAIL:
+           case ORANGE_DRAGON_SCALES:
+               return PM_ORANGE_DRAGON;
+           case WHITE_DRAGON_SCALE_MAIL:
+           case WHITE_DRAGON_SCALES:
+               return PM_WHITE_DRAGON;
+           case BLACK_DRAGON_SCALE_MAIL:
+           case BLACK_DRAGON_SCALES:
+               return PM_BLACK_DRAGON;
+           case BLUE_DRAGON_SCALE_MAIL:
+           case BLUE_DRAGON_SCALES:
+               return PM_BLUE_DRAGON;
+           case GREEN_DRAGON_SCALE_MAIL:
+           case GREEN_DRAGON_SCALES:
+               return PM_GREEN_DRAGON;
+           case YELLOW_DRAGON_SCALE_MAIL:
+           case YELLOW_DRAGON_SCALES:
+               return PM_YELLOW_DRAGON;
+           default:
+               return -1;
+       }
+}
+
+#endif /* OVLB */
+
+/*polyself.c*/
diff --git a/src/potion.c b/src/potion.c
new file mode 100644 (file)
index 0000000..04abd41
--- /dev/null
@@ -0,0 +1,2012 @@
+/*     SCCS Id: @(#)potion.c   3.4     2002/10/02      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+#ifdef OVLB
+boolean notonhead = FALSE;
+
+static NEARDATA int nothing, unkn;
+static NEARDATA const char beverages[] = { POTION_CLASS, 0 };
+
+STATIC_DCL long FDECL(itimeout, (long));
+STATIC_DCL long FDECL(itimeout_incr, (long,int));
+STATIC_DCL void NDECL(ghost_from_bottle);
+STATIC_DCL short FDECL(mixtype, (struct obj *,struct obj *));
+
+/* force `val' to be within valid range for intrinsic timeout value */
+STATIC_OVL long
+itimeout(val)
+long val;
+{
+    if (val >= TIMEOUT) val = TIMEOUT;
+    else if (val < 1) val = 0;
+
+    return val;
+}
+
+/* increment `old' by `incr' and force result to be valid intrinsic timeout */
+STATIC_OVL long
+itimeout_incr(old, incr)
+long old;
+int incr;
+{
+    return itimeout((old & TIMEOUT) + (long)incr);
+}
+
+/* set the timeout field of intrinsic `which' */
+void
+set_itimeout(which, val)
+long *which, val;
+{
+    *which &= ~TIMEOUT;
+    *which |= itimeout(val);
+}
+
+/* increment the timeout field of intrinsic `which' */
+void
+incr_itimeout(which, incr)
+long *which;
+int incr;
+{
+    set_itimeout(which, itimeout_incr(*which, incr));
+}
+
+void
+make_confused(xtime,talk)
+long xtime;
+boolean talk;
+{
+       long old = HConfusion;
+
+       if (!xtime && old) {
+               if (talk)
+                   You_feel("less %s now.",
+                       Hallucination ? "trippy" : "confused");
+       }
+       if ((xtime && !old) || (!xtime && old)) flags.botl = TRUE;
+
+       set_itimeout(&HConfusion, xtime);
+}
+
+void
+make_stunned(xtime,talk)
+long xtime;
+boolean talk;
+{
+       long old = HStun;
+
+       if (!xtime && old) {
+               if (talk)
+                   You_feel("%s now.",
+                       Hallucination ? "less wobbly" : "a bit steadier");
+       }
+       if (xtime && !old) {
+               if (talk) {
+#ifdef STEED
+                       if (u.usteed)
+                               You("wobble in the saddle.");
+                       else
+#endif
+                       You("%s...", stagger(youmonst.data, "stagger"));
+               }
+       }
+       if ((!xtime && old) || (xtime && !old)) flags.botl = TRUE;
+
+       set_itimeout(&HStun, xtime);
+}
+
+void
+make_sick(xtime, cause, talk, type)
+long xtime;
+const char *cause;     /* sickness cause */
+boolean talk;
+int type;
+{
+       long old = Sick;
+
+       if (xtime > 0L) {
+           if (Sick_resistance) return;
+           if (!old) {
+               /* newly sick */
+               You_feel("deathly sick.");
+           } else {
+               /* already sick */
+               if (talk) You_feel("%s worse.",
+                             xtime <= Sick/2L ? "much" : "even");
+           }
+           set_itimeout(&Sick, xtime);
+           u.usick_type |= type;
+           flags.botl = TRUE;
+       } else if (old && (type & u.usick_type)) {
+           /* was sick, now not */
+           u.usick_type &= ~type;
+           if (u.usick_type) { /* only partly cured */
+               if (talk) You_feel("somewhat better.");
+               set_itimeout(&Sick, Sick * 2); /* approximation */
+           } else {
+               if (talk) pline("What a relief!");
+               Sick = 0L;              /* set_itimeout(&Sick, 0L) */
+           }
+           flags.botl = TRUE;
+       }
+
+       if (Sick) {
+           exercise(A_CON, FALSE);
+           if (cause) {
+               (void) strncpy(u.usick_cause, cause, sizeof(u.usick_cause));
+               u.usick_cause[sizeof(u.usick_cause)-1] = 0;
+               }
+           else
+               u.usick_cause[0] = 0;
+       } else
+           u.usick_cause[0] = 0;
+}
+
+void
+make_vomiting(xtime, talk)
+long xtime;
+boolean talk;
+{
+       long old = Vomiting;
+
+       if(!xtime && old)
+           if(talk) You_feel("much less nauseated now.");
+
+       set_itimeout(&Vomiting, xtime);
+}
+
+static const char vismsg[] = "vision seems to %s for a moment but is %s now.";
+static const char eyemsg[] = "%s momentarily %s.";
+
+void
+make_blinded(xtime, talk)
+long xtime;
+boolean talk;
+{
+       long old = Blinded;
+       boolean u_could_see, can_see_now;
+       int eyecnt;
+       char buf[BUFSZ];
+
+       /* we need to probe ahead in case the Eyes of the Overworld
+          are or will be overriding blindness */
+       u_could_see = !Blind;
+       Blinded = xtime ? 1L : 0L;
+       can_see_now = !Blind;
+       Blinded = old;          /* restore */
+
+       if (u.usleep) talk = FALSE;
+
+       if (can_see_now && !u_could_see) {      /* regaining sight */
+           if (talk) {
+               if (Hallucination)
+                   pline("Far out!  Everything is all cosmic again!");
+               else
+                   You("can see again.");
+           }
+       } else if (old && !xtime) {
+           /* clearing temporary blindness without toggling blindness */
+           if (talk) {
+               if (!haseyes(youmonst.data)) {
+                   strange_feeling((struct obj *)0, (char *)0);
+               } else if (Blindfolded) {
+                   Strcpy(buf, body_part(EYE));
+                   eyecnt = eyecount(youmonst.data);
+                   Your(eyemsg, (eyecnt == 1) ? buf : makeplural(buf),
+                        (eyecnt == 1) ? "itches" : "itch");
+               } else {        /* Eyes of the Overworld */
+                   Your(vismsg, "brighten",
+                        Hallucination ? "sadder" : "normal");
+               }
+           }
+       }
+
+       if (u_could_see && !can_see_now) {      /* losing sight */
+           if (talk) {
+               if (Hallucination)
+                   pline("Oh, bummer!  Everything is dark!  Help!");
+               else
+                   pline("A cloud of darkness falls upon you.");
+           }
+           /* Before the hero goes blind, set the ball&chain variables. */
+           if (Punished) set_bc(0);
+       } else if (!old && xtime) {
+           /* setting temporary blindness without toggling blindness */
+           if (talk) {
+               if (!haseyes(youmonst.data)) {
+                   strange_feeling((struct obj *)0, (char *)0);
+               } else if (Blindfolded) {
+                   Strcpy(buf, body_part(EYE));
+                   eyecnt = eyecount(youmonst.data);
+                   Your(eyemsg, (eyecnt == 1) ? buf : makeplural(buf),
+                        (eyecnt == 1) ? "twitches" : "twitch");
+               } else {        /* Eyes of the Overworld */
+                   Your(vismsg, "dim",
+                        Hallucination ? "happier" : "normal");
+               }
+           }
+       }
+
+       set_itimeout(&Blinded, xtime);
+
+       if (u_could_see ^ can_see_now) {  /* one or the other but not both */
+           flags.botl = 1;
+           vision_full_recalc = 1;     /* blindness just got toggled */
+           if (Blind_telepat || Infravision) see_monsters();
+       }
+}
+
+boolean
+make_hallucinated(xtime, talk, mask)
+long xtime;    /* nonzero if this is an attempt to turn on hallucination */
+boolean talk;
+long mask;     /* nonzero if resistance status should change by mask */
+{
+       long old = HHallucination;
+       boolean changed = 0;
+       const char *message, *verb;
+
+       message = (!xtime) ? "Everything %s SO boring now." :
+                            "Oh wow!  Everything %s so cosmic!";
+       verb = (!Blind) ? "looks" : "feels";
+
+       if (mask) {
+           if (HHallucination) changed = TRUE;
+
+           if (!xtime) EHalluc_resistance |= mask;
+           else EHalluc_resistance &= ~mask;
+       } else {
+           if (!EHalluc_resistance && (!!HHallucination != !!xtime))
+               changed = TRUE;
+           set_itimeout(&HHallucination, xtime);
+
+           /* clearing temporary hallucination without toggling vision */
+           if (!changed && !HHallucination && old && talk) {
+               if (!haseyes(youmonst.data)) {
+                   strange_feeling((struct obj *)0, (char *)0);
+               } else if (Blind) {
+                   char buf[BUFSZ];
+                   int eyecnt = eyecount(youmonst.data);
+
+                   Strcpy(buf, body_part(EYE));
+                   Your(eyemsg, (eyecnt == 1) ? buf : makeplural(buf),
+                        (eyecnt == 1) ? "itches" : "itch");
+               } else {        /* Grayswandir */
+                   Your(vismsg, "flatten", "normal");
+               }
+           }
+       }
+
+       if (changed) {
+           if (u.uswallow) {
+               swallowed(0);   /* redraw swallow display */
+           } else {
+               /* The see_* routines should be called *before* the pline. */
+               see_monsters();
+               see_objects();
+               see_traps();
+           }
+
+           /* for perm_inv and anything similar
+           (eg. Qt windowport's equipped items display) */
+           update_inventory();
+
+           flags.botl = 1;
+           if (talk) pline(message, verb);
+       }
+       return changed;
+}
+
+STATIC_OVL void
+ghost_from_bottle()
+{
+       struct monst *mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, NO_MM_FLAGS);
+
+       if (!mtmp) {
+               pline("This bottle turns out to be empty.");
+               return;
+       }
+       if (Blind) {
+               pline("As you open the bottle, %s emerges.", something);
+               return;
+       }
+       pline("As you open the bottle, an enormous %s emerges!",
+               Hallucination ? rndmonnam() : (const char *)"ghost");
+       if(flags.verbose)
+           You("are frightened to death, and unable to move.");
+       nomul(-3);
+       nomovemsg = "You regain your composure.";
+}
+
+/* "Quaffing is like drinking, except you spill more."  -- Terry Pratchett
+ */
+int
+dodrink()
+{
+       register struct obj *otmp;
+       const char *potion_descr;
+
+       if (Strangled) {
+               pline("If you can't breathe air, how can you drink liquid?");
+               return 0;
+       }
+       /* Is there a fountain to drink from here? */
+       if (IS_FOUNTAIN(levl[u.ux][u.uy].typ) && !Levitation) {
+               if(yn("Drink from the fountain?") == 'y') {
+                       drinkfountain();
+                       return 1;
+               }
+       }
+#ifdef SINKS
+       /* Or a kitchen sink? */
+       if (IS_SINK(levl[u.ux][u.uy].typ)) {
+               if (yn("Drink from the sink?") == 'y') {
+                       drinksink();
+                       return 1;
+               }
+       }
+#endif
+
+       /* Or are you surrounded by water? */
+       if (Underwater) {
+               if (yn("Drink the water around you?") == 'y') {
+                   pline("Do you know what lives in this water!");
+                       return 1;
+               }
+       }
+
+       otmp = getobj(beverages, "drink");
+       if(!otmp) return(0);
+       otmp->in_use = TRUE;            /* you've opened the stopper */
+
+#define POTION_OCCUPANT_CHANCE(n) (13 + 2*(n)) /* also in muse.c */
+
+       potion_descr = OBJ_DESCR(objects[otmp->otyp]);
+       if (potion_descr) {
+           if (!strcmp(potion_descr, "milky") &&
+                   flags.ghost_count < MAXMONNO &&
+                   !rn2(POTION_OCCUPANT_CHANCE(flags.ghost_count))) {
+               ghost_from_bottle();
+               useup(otmp);
+               return(1);
+           } else if (!strcmp(potion_descr, "smoky") &&
+                   flags.djinni_count < MAXMONNO &&
+                   !rn2(POTION_OCCUPANT_CHANCE(flags.djinni_count))) {
+               djinni_from_bottle(otmp);
+               useup(otmp);
+               return(1);
+           }
+       }
+       return dopotion(otmp);
+}
+
+int
+dopotion(otmp)
+register struct obj *otmp;
+{
+       int retval;
+
+       otmp->in_use = TRUE;
+       nothing = unkn = 0;
+       if((retval = peffects(otmp)) >= 0) return(retval);
+
+       if(nothing) {
+           unkn++;
+           You("have a %s feeling for a moment, then it passes.",
+                 Hallucination ? "normal" : "peculiar");
+       }
+       if(otmp->dknown && !objects[otmp->otyp].oc_name_known) {
+               if(!unkn) {
+                       makeknown(otmp->otyp);
+                       more_experienced(0,10);
+               } else if(!objects[otmp->otyp].oc_uname)
+                       docall(otmp);
+       }
+       useup(otmp);
+       return(1);
+}
+
+int
+peffects(otmp)
+       register struct obj     *otmp;
+{
+       register int i, ii, lim;
+
+       switch(otmp->otyp){
+       case POT_RESTORE_ABILITY:
+       case SPE_RESTORE_ABILITY:
+               unkn++;
+               if(otmp->cursed) {
+                   pline("Ulch!  This makes you feel mediocre!");
+                   break;
+               } else {
+                   pline("Wow!  This makes you feel %s!",
+                         (otmp->blessed) ?
+                               (unfixable_trouble_count(FALSE) ? "better" : "great")
+                         : "good");
+                   i = rn2(A_MAX);             /* start at a random point */
+                   for (ii = 0; ii < A_MAX; ii++) {
+                       lim = AMAX(i);
+                       if (i == A_STR && u.uhs >= 3) --lim;    /* WEAK */
+                       if (ABASE(i) < lim) {
+                           ABASE(i) = lim;
+                           flags.botl = 1;
+                           /* only first found if not blessed */
+                           if (!otmp->blessed) break;
+                       }
+                       if(++i >= A_MAX) i = 0;
+                   }
+               }
+               break;
+       case POT_HALLUCINATION:
+               if (Hallucination || Halluc_resistance) nothing++;
+               (void) make_hallucinated(itimeout_incr(HHallucination,
+                                          rn1(200, 600 - 300 * bcsign(otmp))),
+                                 TRUE, 0L);
+               break;
+       case POT_WATER:
+               if(!otmp->blessed && !otmp->cursed) {
+                   pline("This tastes like water.");
+                   u.uhunger += rnd(10);
+                   newuhs(FALSE);
+                   break;
+               }
+               unkn++;
+               if(is_undead(youmonst.data) || is_demon(youmonst.data) ||
+                               u.ualign.type == A_CHAOTIC) {
+                   if(otmp->blessed) {
+                       pline("This burns like acid!");
+                       exercise(A_CON, FALSE);
+                       if (u.ulycn >= LOW_PM) {
+                           Your("affinity to %s disappears!",
+                                makeplural(mons[u.ulycn].mname));
+                           if (youmonst.data == &mons[u.ulycn])
+                               you_unwere(FALSE);
+                           u.ulycn = NON_PM;   /* cure lycanthropy */
+                       }
+                       losehp(d(2,6), "potion of holy water", KILLED_BY_AN);
+                   } else if(otmp->cursed) {
+                       You_feel("quite proud of yourself.");
+                       healup(d(2,6),0,0,0);
+                       if (u.ulycn >= LOW_PM && !Upolyd) you_were();
+                       exercise(A_CON, TRUE);
+                   }
+               } else {
+                   if(otmp->blessed) {
+                       You_feel("full of awe.");
+                       make_sick(0L, (char *) 0, TRUE, SICK_ALL);
+                       exercise(A_WIS, TRUE);
+                       exercise(A_CON, TRUE);
+                       if (u.ulycn >= LOW_PM)
+                           you_unwere(TRUE);   /* "Purified" */
+                       /* make_confused(0L,TRUE); */
+                   } else {
+                       if(u.ualign.type == A_LAWFUL) {
+                           pline("This burns like acid!");
+                           losehp(d(2,6), "potion of unholy water",
+                               KILLED_BY_AN);
+                       } else
+                           You_feel("full of dread.");
+                       if (u.ulycn >= LOW_PM && !Upolyd) you_were();
+                       exercise(A_CON, FALSE);
+                   }
+               }
+               break;
+       case POT_BOOZE:
+               unkn++;
+               pline("Ooph!  This tastes like %s%s!",
+                     otmp->odiluted ? "watered down " : "",
+                     Hallucination ? "dandelion wine" : "liquid fire");
+               if (!otmp->blessed)
+                   make_confused(itimeout_incr(HConfusion, d(3,8)), FALSE);
+               /* the whiskey makes us feel better */
+               if (!otmp->odiluted) healup(1, 0, FALSE, FALSE);
+               u.uhunger += 10 * (2 + bcsign(otmp));
+               newuhs(FALSE);
+               exercise(A_WIS, FALSE);
+               if(otmp->cursed) {
+                       You("pass out.");
+                       multi = -rnd(15);
+                       nomovemsg = "You awake with a headache.";
+               }
+               break;
+       case POT_ENLIGHTENMENT:
+               if(otmp->cursed) {
+                       unkn++;
+                       You("have an uneasy feeling...");
+                       exercise(A_WIS, FALSE);
+               } else {
+                       if (otmp->blessed) {
+                               (void) adjattrib(A_INT, 1, FALSE);
+                               (void) adjattrib(A_WIS, 1, FALSE);
+                       }
+                       You_feel("self-knowledgeable...");
+                       display_nhwindow(WIN_MESSAGE, FALSE);
+                       enlightenment(0);
+                       pline_The("feeling subsides.");
+                       exercise(A_WIS, TRUE);
+               }
+               break;
+       case SPE_INVISIBILITY:
+               /* spell cannot penetrate mummy wrapping */
+               if (BInvis && uarmc->otyp == MUMMY_WRAPPING) {
+                       You_feel("rather itchy under your %s.", xname(uarmc));
+                       break;
+               }
+               /* FALLTHRU */
+       case POT_INVISIBILITY:
+               if (Invis || Blind || BInvis) {
+                   nothing++;
+               } else {
+                   self_invis_message();
+               }
+               if (otmp->blessed) HInvis |= FROMOUTSIDE;
+               else incr_itimeout(&HInvis, rn1(15,31));
+               newsym(u.ux,u.uy);      /* update position */
+               if(otmp->cursed) {
+                   pline("For some reason, you feel your presence is known.");
+                   aggravate();
+               }
+               break;
+       case POT_SEE_INVISIBLE:
+               /* tastes like fruit juice in Rogue */
+       case POT_FRUIT_JUICE:
+           {
+               int msg = Invisible && !Blind;
+
+               unkn++;
+               if (otmp->cursed)
+                   pline("Yecch!  This tastes %s.",
+                         Hallucination ? "overripe" : "rotten");
+               else
+                   pline(Hallucination ?
+                     "This tastes like 10%% real %s%s all-natural beverage." :
+                               "This tastes like %s%s.",
+                         otmp->odiluted ? "reconstituted " : "",
+                         fruitname(TRUE));
+               if (otmp->otyp == POT_FRUIT_JUICE) {
+                   u.uhunger += (otmp->odiluted ? 5 : 10) * (2 + bcsign(otmp));
+                   newuhs(FALSE);
+                   break;
+               }
+               if (!otmp->cursed) {
+                       /* Tell them they can see again immediately, which
+                        * will help them identify the potion...
+                        */
+                       make_blinded(0L,TRUE);
+               }
+               if (otmp->blessed)
+                       HSee_invisible |= FROMOUTSIDE;
+               else
+                       incr_itimeout(&HSee_invisible, rn1(100,750));
+               set_mimic_blocking(); /* do special mimic handling */
+               see_monsters(); /* see invisible monsters */
+               newsym(u.ux,u.uy); /* see yourself! */
+               if (msg && !Blind) { /* Blind possible if polymorphed */
+                   You("can see through yourself, but you are visible!");
+                   unkn--;
+               }
+               break;
+           }
+       case POT_PARALYSIS:
+               if (Free_action)
+                   You("stiffen momentarily.");
+               else {
+                   if (Levitation || Is_airlevel(&u.uz)||Is_waterlevel(&u.uz))
+                       You("are motionlessly suspended.");
+#ifdef STEED
+                   else if (u.usteed)
+                       You("are frozen in place!");
+#endif
+                   else
+                       Your("%s are frozen to the %s!",
+                            makeplural(body_part(FOOT)), surface(u.ux, u.uy));
+                   nomul(-(rn1(10, 25 - 12*bcsign(otmp))));
+                   nomovemsg = You_can_move_again;
+                   exercise(A_DEX, FALSE);
+               }
+               break;
+       case POT_SLEEPING:
+               if(Sleep_resistance || Free_action)
+                   You("yawn.");
+               else {
+                   You("suddenly fall asleep!");
+                   fall_asleep(-rn1(10, 25 - 12*bcsign(otmp)), TRUE);
+               }
+               break;
+       case POT_MONSTER_DETECTION:
+       case SPE_DETECT_MONSTERS:
+               if (otmp->blessed) {
+                   int x, y;
+
+                   if (Detect_monsters) nothing++;
+                   unkn++;
+                   /* after a while, repeated uses become less effective */
+                   if (HDetect_monsters >= 300L)
+                       i = 1;
+                   else
+                       i = rn1(40,21);
+                   incr_itimeout(&HDetect_monsters, i);
+                   for (x = 1; x < COLNO; x++) {
+                       for (y = 0; y < ROWNO; y++) {
+                           if (levl[x][y].glyph == GLYPH_INVISIBLE) {
+                               unmap_object(x, y);
+                               newsym(x,y);
+                           }
+                           if (MON_AT(x,y)) unkn = 0;
+                       }
+                   }
+                   see_monsters();
+                   if (unkn) You_feel("lonely.");
+                   break;
+               }
+               if (monster_detect(otmp, 0))
+                       return(1);              /* nothing detected */
+               exercise(A_WIS, TRUE);
+               break;
+       case POT_OBJECT_DETECTION:
+       case SPE_DETECT_TREASURE:
+               if (object_detect(otmp, 0))
+                       return(1);              /* nothing detected */
+               exercise(A_WIS, TRUE);
+               break;
+       case POT_SICKNESS:
+               pline("Yecch!  This stuff tastes like poison.");
+               if (otmp->blessed) {
+                   pline("(But in fact it was mildly stale %s.)",
+                         fruitname(TRUE));
+                   if (!Role_if(PM_HEALER)) {
+                       /* NB: blessed otmp->fromsink is not possible */
+                       losehp(1, "mildly contaminated potion", KILLED_BY_AN);
+                   }
+               } else {
+                   if(Poison_resistance)
+                       pline(
+                         "(But in fact it was biologically contaminated %s.)",
+                             fruitname(TRUE));
+                   if (Role_if(PM_HEALER))
+                       pline("Fortunately, you have been immunized.");
+                   else {
+                       int typ = rn2(A_MAX);
+
+                       if (!Fixed_abil) {
+                           poisontell(typ);
+                           (void) adjattrib(typ,
+                                       Poison_resistance ? -1 : -rn1(4,3),
+                                       TRUE);
+                       }
+                       if(!Poison_resistance) {
+                           if (otmp->fromsink)
+                               losehp(rnd(10)+5*!!(otmp->cursed),
+                                      "contaminated tap water", KILLED_BY);
+                           else
+                               losehp(rnd(10)+5*!!(otmp->cursed),
+                                      "contaminated potion", KILLED_BY_AN);
+                       }
+                       exercise(A_CON, FALSE);
+                   }
+               }
+               if(Hallucination) {
+                       You("are shocked back to your senses!");
+                       (void) make_hallucinated(0L,FALSE,0L);
+               }
+               break;
+       case POT_CONFUSION:
+               if(!Confusion)
+                   if (Hallucination) {
+                       pline("What a trippy feeling!");
+                       unkn++;
+                   } else
+                       pline("Huh, What?  Where am I?");
+               else    nothing++;
+               make_confused(itimeout_incr(HConfusion,
+                                           rn1(7, 16 - 8 * bcsign(otmp))),
+                             FALSE);
+               break;
+       case POT_GAIN_ABILITY:
+               if(otmp->cursed) {
+                   pline("Ulch!  That potion tasted foul!");
+                   unkn++;
+               } else if (Fixed_abil) {
+                   nothing++;
+               } else {      /* If blessed, increase all; if not, try up to */
+                   int itmp; /* 6 times to find one which can be increased. */
+                   i = -1;             /* increment to 0 */
+                   for (ii = A_MAX; ii > 0; ii--) {
+                       i = (otmp->blessed ? i + 1 : rn2(A_MAX));
+                       /* only give "your X is already as high as it can get"
+                          message on last attempt (except blessed potions) */
+                       itmp = (otmp->blessed || ii == 1) ? 0 : -1;
+                       if (adjattrib(i, 1, itmp) && !otmp->blessed)
+                           break;
+                   }
+               }
+               break;
+       case POT_SPEED:
+               if(Wounded_legs && !otmp->cursed
+#ifdef STEED
+                  && !u.usteed /* heal_legs() would heal steeds legs */
+#endif
+                                               ) {
+                       heal_legs();
+                       unkn++;
+                       break;
+               } /* and fall through */
+       case SPE_HASTE_SELF:
+               if(!Very_fast) /* wwf@doe.carleton.ca */
+                       You("are suddenly moving %sfaster.",
+                               Fast ? "" : "much ");
+               else {
+                       Your("%s get new energy.",
+                               makeplural(body_part(LEG)));
+                       unkn++;
+               }
+               exercise(A_DEX, TRUE);
+               incr_itimeout(&HFast, rn1(10, 100 + 60 * bcsign(otmp)));
+               break;
+       case POT_BLINDNESS:
+               if(Blind) nothing++;
+               make_blinded(itimeout_incr(Blinded,
+                                          rn1(200, 250 - 125 * bcsign(otmp))),
+                            (boolean)!Blind);
+               break;
+       case POT_GAIN_LEVEL:
+               if (otmp->cursed) {
+                       unkn++;
+                       /* they went up a level */
+                       if((ledger_no(&u.uz) == 1 && u.uhave.amulet) ||
+                               Can_rise_up(u.ux, u.uy, &u.uz)) {
+                           const char *riseup ="rise up, through the %s!";
+                           if(ledger_no(&u.uz) == 1) {
+                               You(riseup, ceiling(u.ux,u.uy));
+                               goto_level(&earth_level, FALSE, FALSE, FALSE);
+                           } else {
+                               register int newlev = depth(&u.uz)-1;
+                               d_level newlevel;
+
+                               get_level(&newlevel, newlev);
+                               if(on_level(&newlevel, &u.uz)) {
+                                   pline("It tasted bad.");
+                                   break;
+                               } else You(riseup, ceiling(u.ux,u.uy));
+                               goto_level(&newlevel, FALSE, FALSE, FALSE);
+                           }
+                       }
+                       else You("have an uneasy feeling.");
+                       break;
+               }
+               pluslvl(FALSE);
+               if (otmp->blessed)
+                       /* blessed potions place you at a random spot in the
+                        * middle of the new level instead of the low point
+                        */
+                       u.uexp = rndexp(TRUE);
+               break;
+       case POT_HEALING:
+               You_feel("better.");
+               healup(d(6 + 2 * bcsign(otmp), 4),
+                      !otmp->cursed ? 1 : 0, !!otmp->blessed, !otmp->cursed);
+               exercise(A_CON, TRUE);
+               break;
+       case POT_EXTRA_HEALING:
+               You_feel("much better.");
+               healup(d(6 + 2 * bcsign(otmp), 8),
+                      otmp->blessed ? 5 : !otmp->cursed ? 2 : 0,
+                      !otmp->cursed, TRUE);
+               (void) make_hallucinated(0L,TRUE,0L);
+               exercise(A_CON, TRUE);
+               exercise(A_STR, TRUE);
+               break;
+       case POT_FULL_HEALING:
+               You_feel("completely healed.");
+               healup(400, 4+4*bcsign(otmp), !otmp->cursed, TRUE);
+               /* Restore one lost level if blessed */
+               if (otmp->blessed && u.ulevel < u.ulevelmax) {
+                   /* when multiple levels have been lost, drinking
+                      multiple potions will only get half of them back */
+                   u.ulevelmax -= 1;
+                   pluslvl(FALSE);
+               }
+               (void) make_hallucinated(0L,TRUE,0L);
+               exercise(A_STR, TRUE);
+               exercise(A_CON, TRUE);
+               break;
+       case POT_LEVITATION:
+       case SPE_LEVITATION:
+               if (otmp->cursed) HLevitation &= ~I_SPECIAL;
+               if(!Levitation) {
+                       /* kludge to ensure proper operation of float_up() */
+                       HLevitation = 1;
+                       float_up();
+                       /* reverse kludge */
+                       HLevitation = 0;
+                       if (otmp->cursed && !Is_waterlevel(&u.uz)) {
+       if((u.ux != xupstair || u.uy != yupstair)
+          && (u.ux != sstairs.sx || u.uy != sstairs.sy || !sstairs.up)
+          && (!xupladder || u.ux != xupladder || u.uy != yupladder)
+       ) {
+                                       You("hit your %s on the %s.",
+                                               body_part(HEAD),
+                                               ceiling(u.ux,u.uy));
+                                       losehp(uarmh ? 1 : rnd(10),
+                                               "colliding with the ceiling",
+                                               KILLED_BY);
+                               } else (void) doup();
+                       }
+               } else
+                       nothing++;
+               if (otmp->blessed) {
+                   incr_itimeout(&HLevitation, rn1(50,250));
+                   HLevitation |= I_SPECIAL;
+               } else incr_itimeout(&HLevitation, rn1(140,10));
+               spoteffects(FALSE);     /* for sinks */
+               break;
+       case POT_GAIN_ENERGY:                   /* M. Stephenson */
+               {       register int num;
+                       if(otmp->cursed)
+                           You_feel("lackluster.");
+                       else
+                           pline("Magical energies course through your body.");
+                       num = rnd(5) + 5 * otmp->blessed + 1;
+                       u.uenmax += (otmp->cursed) ? -num : num;
+                       u.uen += (otmp->cursed) ? -num : num;
+                       if(u.uenmax <= 0) u.uenmax = 0;
+                       if(u.uen <= 0) u.uen = 0;
+                       flags.botl = 1;
+                       exercise(A_WIS, TRUE);
+               }
+               break;
+       case POT_OIL:                           /* P. Winner */
+               {
+                       boolean good_for_you = FALSE;
+
+                       if (otmp->lamplit) {
+                           if (likes_fire(youmonst.data)) {
+                               pline("Ahh, a refreshing drink.");
+                               good_for_you = TRUE;
+                           } else {
+                               You("burn your %s.", body_part(FACE));
+                               losehp(d(Fire_resistance ? 1 : 3, 4),
+                                      "burning potion of oil", KILLED_BY_AN);
+                           }
+                       } else if(otmp->cursed)
+                           pline("This tastes like castor oil.");
+                       else
+                           pline("That was smooth!");
+                       exercise(A_WIS, good_for_you);
+               }
+               break;
+       case POT_ACID:
+               if (Acid_resistance)
+                       /* Not necessarily a creature who _likes_ acid */
+                       pline("This tastes %s.", Hallucination ? "tangy" : "sour");
+               else {
+                       pline("This burns%s!", otmp->blessed ? " a little" :
+                                       otmp->cursed ? " a lot" : " like acid");
+                       losehp(d(otmp->cursed ? 2 : 1, otmp->blessed ? 4 : 8),
+                                       "potion of acid", KILLED_BY_AN);
+                       exercise(A_CON, FALSE);
+               }
+               if (Stoned) fix_petrification();
+               unkn++; /* holy/unholy water can burn like acid too */
+               break;
+       case POT_POLYMORPH:
+               You_feel("a little %s.", Hallucination ? "normal" : "strange");
+               if (!Unchanging) polyself(FALSE);
+               break;
+       default:
+               impossible("What a funny potion! (%u)", otmp->otyp);
+               return(0);
+       }
+       return(-1);
+}
+
+void
+healup(nhp, nxtra, curesick, cureblind)
+       int nhp, nxtra;
+       register boolean curesick, cureblind;
+{
+       if (nhp) {
+               if (Upolyd) {
+                       u.mh += nhp;
+                       if (u.mh > u.mhmax) u.mh = (u.mhmax += nxtra);
+               } else {
+                       u.uhp += nhp;
+                       if(u.uhp > u.uhpmax) u.uhp = (u.uhpmax += nxtra);
+               }
+       }
+       if(cureblind)   make_blinded(0L,TRUE);
+       if(curesick)    make_sick(0L, (char *) 0, TRUE, SICK_ALL);
+       flags.botl = 1;
+       return;
+}
+
+void
+strange_feeling(obj,txt)
+register struct obj *obj;
+register const char *txt;
+{
+       if (flags.beginner || !txt)
+               You("have a %s feeling for a moment, then it passes.",
+               Hallucination ? "normal" : "strange");
+       else
+               pline(txt);
+
+       if(!obj)        /* e.g., crystal ball finds no traps */
+               return;
+
+       if(obj->dknown && !objects[obj->otyp].oc_name_known &&
+                                               !objects[obj->otyp].oc_uname)
+               docall(obj);
+       useup(obj);
+}
+
+const char *bottlenames[] = {
+       "bottle", "phial", "flagon", "carafe", "flask", "jar", "vial"
+};
+
+
+const char *
+bottlename()
+{
+       return bottlenames[rn2(SIZE(bottlenames))];
+}
+
+void
+potionhit(mon, obj, your_fault)
+register struct monst *mon;
+register struct obj *obj;
+boolean your_fault;
+{
+       register const char *botlnam = bottlename();
+       boolean isyou = (mon == &youmonst);
+       int distance;
+
+       if(isyou) {
+               distance = 0;
+               pline_The("%s crashes on your %s and breaks into shards.",
+                       botlnam, body_part(HEAD));
+               losehp(rnd(2), "thrown potion", KILLED_BY_AN);
+       } else {
+               distance = distu(mon->mx,mon->my);
+               if (!cansee(mon->mx,mon->my)) pline("Crash!");
+               else {
+                   char *mnam = mon_nam(mon);
+                   char buf[BUFSZ];
+
+                   if(has_head(mon->data)) {
+                       Sprintf(buf, "%s %s",
+                               s_suffix(mnam),
+                               (notonhead ? "body" : "head"));
+                   } else {
+                       Strcpy(buf, mnam);
+                   }
+                   pline_The("%s crashes on %s and breaks into shards.",
+                          botlnam, buf);
+               }
+               if(rn2(5) && mon->mhp > 1)
+                       mon->mhp--;
+       }
+
+       /* oil doesn't instantly evaporate */
+       if (obj->otyp != POT_OIL && cansee(mon->mx,mon->my))
+               pline("%s.", Tobjnam(obj, "evaporate"));
+
+    if (isyou) {
+       switch (obj->otyp) {
+       case POT_OIL:
+               if (obj->lamplit)
+                   splatter_burning_oil(u.ux, u.uy);
+               break;
+       case POT_POLYMORPH:
+               You_feel("a little %s.", Hallucination ? "normal" : "strange");
+               if (!Unchanging && !Antimagic) polyself(FALSE);
+               break;
+       case POT_ACID:
+               if (!Acid_resistance) {
+                   pline("This burns%s!", obj->blessed ? " a little" :
+                                   obj->cursed ? " a lot" : "");
+                   losehp(d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8),
+                                   "potion of acid", KILLED_BY_AN);
+               }
+               break;
+       }
+    } else {
+       boolean angermon = TRUE;
+
+       if (!your_fault) angermon = FALSE;
+       switch (obj->otyp) {
+       case POT_HEALING:
+       case POT_EXTRA_HEALING:
+       case POT_FULL_HEALING:
+               if (mon->data == &mons[PM_PESTILENCE]) goto do_illness;
+               /*FALLTHRU*/
+       case POT_RESTORE_ABILITY:
+       case POT_GAIN_ABILITY:
+ do_healing:
+               angermon = FALSE;
+               if(mon->mhp < mon->mhpmax) {
+                   mon->mhp = mon->mhpmax;
+                   if (canseemon(mon))
+                       pline("%s looks sound and hale again.", Monnam(mon));
+               }
+               break;
+       case POT_SICKNESS:
+               if (mon->data == &mons[PM_PESTILENCE]) goto do_healing;
+               if (dmgtype(mon->data, AD_DISE) ||
+                          dmgtype(mon->data, AD_PEST) || /* won't happen, see prior goto */
+                          resists_poison(mon)) {
+                   if (canseemon(mon))
+                       pline("%s looks unharmed.", Monnam(mon));
+                   break;
+               }
+ do_illness:
+               if((mon->mhpmax > 3) && !resist(mon, POTION_CLASS, 0, NOTELL))
+                       mon->mhpmax /= 2;
+               if((mon->mhp > 2) && !resist(mon, POTION_CLASS, 0, NOTELL))
+                       mon->mhp /= 2;
+               if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax;
+               if (canseemon(mon))
+                   pline("%s looks rather ill.", Monnam(mon));
+               break;
+       case POT_CONFUSION:
+       case POT_BOOZE:
+               if(!resist(mon, POTION_CLASS, 0, NOTELL))  mon->mconf = TRUE;
+               break;
+       case POT_INVISIBILITY:
+               angermon = FALSE;
+               mon_set_minvis(mon);
+               break;
+       case POT_SLEEPING:
+               /* wakeup() doesn't rouse victims of temporary sleep */
+               if (sleep_monst(mon, rnd(12), POTION_CLASS)) {
+                   pline("%s falls asleep.", Monnam(mon));
+                   slept_monst(mon);
+               }
+               break;
+       case POT_PARALYSIS:
+               if (mon->mcanmove) {
+                       mon->mcanmove = 0;
+                       /* really should be rnd(5) for consistency with players
+                        * breathing potions, but...
+                        */
+                       mon->mfrozen = rnd(25);
+               }
+               break;
+       case POT_SPEED:
+               angermon = FALSE;
+               mon_adjust_speed(mon, 1, obj);
+               break;
+       case POT_BLINDNESS:
+               if(haseyes(mon->data)) {
+                   register int btmp = 64 + rn2(32) +
+                       rn2(32) * !resist(mon, POTION_CLASS, 0, NOTELL);
+                   btmp += mon->mblinded;
+                   mon->mblinded = min(btmp,127);
+                   mon->mcansee = 0;
+               }
+               break;
+       case POT_WATER:
+               if (is_undead(mon->data) || is_demon(mon->data) ||
+                       is_were(mon->data)) {
+                   if (obj->blessed) {
+                       pline("%s %s in pain!", Monnam(mon),
+                             is_silent(mon->data) ? "writhes" : "shrieks");
+                       mon->mhp -= d(2,6);
+                       /* should only be by you */
+                       if (mon->mhp < 1) killed(mon);
+                       else if (is_were(mon->data) && !is_human(mon->data))
+                           new_were(mon);      /* revert to human */
+                   } else if (obj->cursed) {
+                       angermon = FALSE;
+                       if (canseemon(mon))
+                           pline("%s looks healthier.", Monnam(mon));
+                       mon->mhp += d(2,6);
+                       if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax;
+                       if (is_were(mon->data) && is_human(mon->data) &&
+                               !Protection_from_shape_changers)
+                           new_were(mon);      /* transform into beast */
+                   }
+               } else if(mon->data == &mons[PM_GREMLIN]) {
+                   angermon = FALSE;
+                   (void)split_mon(mon, (struct monst *)0);
+               } else if(mon->data == &mons[PM_IRON_GOLEM]) {
+                   if (canseemon(mon))
+                       pline("%s rusts.", Monnam(mon));
+                   mon->mhp -= d(1,6);
+                   /* should only be by you */
+                   if (mon->mhp < 1) killed(mon);
+               }
+               break;
+       case POT_OIL:
+               if (obj->lamplit)
+                       splatter_burning_oil(mon->mx, mon->my);
+               break;
+       case POT_ACID:
+               if (!resists_acid(mon) && !resist(mon, POTION_CLASS, 0, NOTELL)) {
+                   pline("%s %s in pain!", Monnam(mon),
+                         is_silent(mon->data) ? "writhes" : "shrieks");
+                   mon->mhp -= d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8);
+                   if (mon->mhp < 1) {
+                       if (your_fault)
+                           killed(mon);
+                       else
+                           monkilled(mon, "", AD_ACID);
+                   }
+               }
+               break;
+       case POT_POLYMORPH:
+               (void) bhitm(mon, obj);
+               break;
+/*
+       case POT_GAIN_LEVEL:
+       case POT_LEVITATION:
+       case POT_FRUIT_JUICE:
+       case POT_MONSTER_DETECTION:
+       case POT_OBJECT_DETECTION:
+               break;
+*/
+       }
+       if (angermon)
+           wakeup(mon);
+       else
+           mon->msleeping = 0;
+    }
+
+       /* Note: potionbreathe() does its own docall() */
+       if ((distance==0 || ((distance < 3) && rn2(5))) &&
+           (!breathless(youmonst.data) || haseyes(youmonst.data)))
+               potionbreathe(obj);
+       else if (obj->dknown && !objects[obj->otyp].oc_name_known &&
+                  !objects[obj->otyp].oc_uname && cansee(mon->mx,mon->my))
+               docall(obj);
+       if(*u.ushops && obj->unpaid) {
+               register struct monst *shkp =
+                       shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE));
+
+               if(!shkp)
+                   obj->unpaid = 0;
+               else {
+                   (void)stolen_value(obj, u.ux, u.uy,
+                                (boolean)shkp->mpeaceful, FALSE);
+                   subfrombill(obj, shkp);
+               }
+       }
+       obfree(obj, (struct obj *)0);
+}
+
+/* vapors are inhaled or get in your eyes */
+void
+potionbreathe(obj)
+register struct obj *obj;
+{
+       register int i, ii, isdone, kn = 0;
+
+       switch(obj->otyp) {
+       case POT_RESTORE_ABILITY:
+       case POT_GAIN_ABILITY:
+               if(obj->cursed) {
+                   if (!breathless(youmonst.data))
+                       pline("Ulch!  That potion smells terrible!");
+                   else if (haseyes(youmonst.data)) {
+                       int numeyes = eyecount(youmonst.data);
+                       Your("%s sting%s!",
+                            (numeyes == 1) ? body_part(EYE) : makeplural(body_part(EYE)),
+                            (numeyes == 1) ? "s" : "");
+                   }
+                   break;
+               } else {
+                   i = rn2(A_MAX);             /* start at a random point */
+                   for(isdone = ii = 0; !isdone && ii < A_MAX; ii++) {
+                       if(ABASE(i) < AMAX(i)) {
+                           ABASE(i)++;
+                           /* only first found if not blessed */
+                           isdone = !(obj->blessed);
+                           flags.botl = 1;
+                       }
+                       if(++i >= A_MAX) i = 0;
+                   }
+               }
+               break;
+       case POT_FULL_HEALING:
+               if (Upolyd && u.mh < u.mhmax) u.mh++, flags.botl = 1;
+               if (u.uhp < u.uhpmax) u.uhp++, flags.botl = 1;
+               /*FALL THROUGH*/
+       case POT_EXTRA_HEALING:
+               if (Upolyd && u.mh < u.mhmax) u.mh++, flags.botl = 1;
+               if (u.uhp < u.uhpmax) u.uhp++, flags.botl = 1;
+               /*FALL THROUGH*/
+       case POT_HEALING:
+               if (Upolyd && u.mh < u.mhmax) u.mh++, flags.botl = 1;
+               if (u.uhp < u.uhpmax) u.uhp++, flags.botl = 1;
+               exercise(A_CON, TRUE);
+               break;
+       case POT_SICKNESS:
+               if (!Role_if(PM_HEALER)) {
+                       if (Upolyd) {
+                           if (u.mh <= 5) u.mh = 1; else u.mh -= 5;
+                       } else {
+                           if (u.uhp <= 5) u.uhp = 1; else u.uhp -= 5;
+                       }
+                       flags.botl = 1;
+                       exercise(A_CON, FALSE);
+               }
+               break;
+       case POT_HALLUCINATION:
+               You("have a momentary vision.");
+               break;
+       case POT_CONFUSION:
+       case POT_BOOZE:
+               if(!Confusion)
+                       You_feel("somewhat dizzy.");
+               make_confused(itimeout_incr(HConfusion, rnd(5)), FALSE);
+               break;
+       case POT_INVISIBILITY:
+               if (!Blind && !Invis) {
+                   kn++;
+                   pline("For an instant you %s!",
+                       See_invisible ? "could see right through yourself"
+                       : "couldn't see yourself");
+               }
+               break;
+       case POT_PARALYSIS:
+               kn++;
+               if (!Free_action) {
+                   pline("%s seems to be holding you.", Something);
+                   nomul(-rnd(5));
+                   nomovemsg = You_can_move_again;
+                   exercise(A_DEX, FALSE);
+               } else You("stiffen momentarily.");
+               break;
+       case POT_SLEEPING:
+               kn++;
+               if (!Free_action && !Sleep_resistance) {
+                   You_feel("rather tired.");
+                   nomul(-rnd(5));
+                   nomovemsg = You_can_move_again;
+                   exercise(A_DEX, FALSE);
+               } else You("yawn.");
+               break;
+       case POT_SPEED:
+               if (!Fast) Your("knees seem more flexible now.");
+               incr_itimeout(&HFast, rnd(5));
+               exercise(A_DEX, TRUE);
+               break;
+       case POT_BLINDNESS:
+               if (!Blind && !u.usleep) {
+                   kn++;
+                   pline("It suddenly gets dark.");
+               }
+               make_blinded(itimeout_incr(Blinded, rnd(5)), FALSE);
+               if (!Blind && !u.usleep) Your(vision_clears);
+               break;
+       case POT_WATER:
+               if(u.umonnum == PM_GREMLIN) {
+                   (void)split_mon(&youmonst, (struct monst *)0);
+               } else if (u.ulycn >= LOW_PM) {
+                   /* vapor from [un]holy water will trigger
+                      transformation but won't cure lycanthropy */
+                   if (obj->blessed && youmonst.data == &mons[u.ulycn])
+                       you_unwere(FALSE);
+                   else if (obj->cursed && !Upolyd)
+                       you_were();
+               }
+               break;
+       case POT_ACID:
+       case POT_POLYMORPH:
+               exercise(A_CON, FALSE);
+               break;
+/*
+       case POT_GAIN_LEVEL:
+       case POT_LEVITATION:
+       case POT_FRUIT_JUICE:
+       case POT_MONSTER_DETECTION:
+       case POT_OBJECT_DETECTION:
+       case POT_OIL:
+               break;
+*/
+       }
+       /* note: no obfree() */
+       if (obj->dknown) {
+           if (kn)
+               makeknown(obj->otyp);
+           else if (!objects[obj->otyp].oc_name_known &&
+                                               !objects[obj->otyp].oc_uname)
+               docall(obj);
+       }
+}
+
+STATIC_OVL short
+mixtype(o1, o2)
+register struct obj *o1, *o2;
+/* returns the potion type when o1 is dipped in o2 */
+{
+       /* cut down on the number of cases below */
+       if (o1->oclass == POTION_CLASS &&
+           (o2->otyp == POT_GAIN_LEVEL ||
+            o2->otyp == POT_GAIN_ENERGY ||
+            o2->otyp == POT_HEALING ||
+            o2->otyp == POT_EXTRA_HEALING ||
+            o2->otyp == POT_FULL_HEALING ||
+            o2->otyp == POT_ENLIGHTENMENT ||
+            o2->otyp == POT_FRUIT_JUICE)) {
+               struct obj *swp;
+
+               swp = o1; o1 = o2; o2 = swp;
+       }
+
+       switch (o1->otyp) {
+               case POT_HEALING:
+                       switch (o2->otyp) {
+                           case POT_SPEED:
+                           case POT_GAIN_LEVEL:
+                           case POT_GAIN_ENERGY:
+                               return POT_EXTRA_HEALING;
+                       }
+               case POT_EXTRA_HEALING:
+                       switch (o2->otyp) {
+                           case POT_GAIN_LEVEL:
+                           case POT_GAIN_ENERGY:
+                               return POT_FULL_HEALING;
+                       }
+               case POT_FULL_HEALING:
+                       switch (o2->otyp) {
+                           case POT_GAIN_LEVEL:
+                           case POT_GAIN_ENERGY:
+                               return POT_GAIN_ABILITY;
+                       }
+               case UNICORN_HORN:
+                       switch (o2->otyp) {
+                           case POT_SICKNESS:
+                               return POT_FRUIT_JUICE;
+                           case POT_HALLUCINATION:
+                           case POT_BLINDNESS:
+                           case POT_CONFUSION:
+                               return POT_WATER;
+                       }
+                       break;
+               case AMETHYST:          /* "a-methyst" == "not intoxicated" */
+                       if (o2->otyp == POT_BOOZE)
+                           return POT_FRUIT_JUICE;
+                       break;
+               case POT_GAIN_LEVEL:
+               case POT_GAIN_ENERGY:
+                       switch (o2->otyp) {
+                           case POT_CONFUSION:
+                               return (rn2(3) ? POT_BOOZE : POT_ENLIGHTENMENT);
+                           case POT_HEALING:
+                               return POT_EXTRA_HEALING;
+                           case POT_EXTRA_HEALING:
+                               return POT_FULL_HEALING;
+                           case POT_FULL_HEALING:
+                               return POT_GAIN_ABILITY;
+                           case POT_FRUIT_JUICE:
+                               return POT_SEE_INVISIBLE;
+                           case POT_BOOZE:
+                               return POT_HALLUCINATION;
+                       }
+                       break;
+               case POT_FRUIT_JUICE:
+                       switch (o2->otyp) {
+                           case POT_SICKNESS:
+                               return POT_SICKNESS;
+                           case POT_SPEED:
+                               return POT_BOOZE;
+                           case POT_GAIN_LEVEL:
+                           case POT_GAIN_ENERGY:
+                               return POT_SEE_INVISIBLE;
+                       }
+                       break;
+               case POT_ENLIGHTENMENT:
+                       switch (o2->otyp) {
+                           case POT_LEVITATION:
+                               if (rn2(3)) return POT_GAIN_LEVEL;
+                               break;
+                           case POT_FRUIT_JUICE:
+                               return POT_BOOZE;
+                           case POT_BOOZE:
+                               return POT_CONFUSION;
+                       }
+                       break;
+       }
+
+       return 0;
+}
+
+
+boolean
+get_wet(obj)
+register struct obj *obj;
+/* returns TRUE if something happened (potion should be used up) */
+{
+       char Your_buf[BUFSZ];
+
+       if (snuff_lit(obj)) return(TRUE);
+
+       if (obj->greased) {
+               grease_protect(obj,(char *)0,&youmonst);
+               return(FALSE);
+       }
+       (void) Shk_Your(Your_buf, obj);
+       /* (Rusting shop goods ought to be charged for.) */
+       switch (obj->oclass) {
+           case POTION_CLASS:
+               if (obj->otyp == POT_WATER) return FALSE;
+               /* KMH -- Water into acid causes an explosion */
+               if (obj->otyp == POT_ACID) {
+                       pline("It boils vigorously!");
+                       You("are caught in the explosion!");
+                       losehp(rnd(10), "elementary chemistry", KILLED_BY);
+                       makeknown(obj->otyp);
+                       update_inventory();
+                       return (TRUE);
+               }
+               pline("%s %s%s.", Your_buf, aobjnam(obj,"dilute"),
+                     obj->odiluted ? " further" : "");
+               if(obj->unpaid && costly_spot(u.ux, u.uy)) {
+                   You("dilute it, you pay for it.");
+                   bill_dummy_object(obj);
+               }
+               if (obj->odiluted) {
+                       obj->odiluted = 0;
+#ifdef UNIXPC
+                       obj->blessed = FALSE;
+                       obj->cursed = FALSE;
+#else
+                       obj->blessed = obj->cursed = FALSE;
+#endif
+                       obj->otyp = POT_WATER;
+               } else obj->odiluted++;
+               update_inventory();
+               return TRUE;
+           case SCROLL_CLASS:
+               if (obj->otyp != SCR_BLANK_PAPER
+#ifdef MAIL
+                   && obj->otyp != SCR_MAIL
+#endif
+                   ) {
+                       if (!Blind) {
+                               boolean oq1 = obj->quan == 1L;
+                               pline_The("scroll%s %s.",
+                                         oq1 ? "" : "s", otense(obj, "fade"));
+                       }
+                       if(obj->unpaid && costly_spot(u.ux, u.uy)) {
+                           You("erase it, you pay for it.");
+                           bill_dummy_object(obj);
+                       }
+                       obj->otyp = SCR_BLANK_PAPER;
+                       obj->spe = 0;
+                       update_inventory();
+                       return TRUE;
+               } else break;
+           case SPBOOK_CLASS:
+               if (obj->otyp != SPE_BLANK_PAPER) {
+
+                       if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
+       pline("%s suddenly heats up; steam rises and it remains dry.",
+                               The(xname(obj)));
+                       } else {
+                           if (!Blind) {
+                                   boolean oq1 = obj->quan == 1L;
+                                   pline_The("spellbook%s %s.",
+                                       oq1 ? "" : "s", otense(obj, "fade"));
+                           }
+                           if(obj->unpaid && costly_spot(u.ux, u.uy)) {
+                               You("erase it, you pay for it.");
+                               bill_dummy_object(obj);
+                           }
+                           obj->otyp = SPE_BLANK_PAPER;
+                           update_inventory();
+                       }
+                       return TRUE;
+               }
+               break;
+           case WEAPON_CLASS:
+           /* Just "fall through" to generic rustprone check for now. */
+           /* fall through */
+           default:
+               if (!obj->oerodeproof && is_rustprone(obj) &&
+                   (obj->oeroded < MAX_ERODE) && !rn2(2)) {
+                       pline("%s %s some%s.",
+                             Your_buf, aobjnam(obj, "rust"),
+                             obj->oeroded ? " more" : "what");
+                       obj->oeroded++;
+                       update_inventory();
+                       return TRUE;
+               } else break;
+       }
+       pline("%s %s wet.", Your_buf, aobjnam(obj,"get"));
+       return FALSE;
+}
+
+int
+dodip()
+{
+       register struct obj *potion, *obj;
+       struct obj *singlepotion;
+       const char *tmp;
+       uchar here;
+       char allowall[2];
+       short mixture;
+       char qbuf[QBUFSZ], Your_buf[BUFSZ];
+
+       allowall[0] = ALL_CLASSES; allowall[1] = '\0';
+       if(!(obj = getobj(allowall, "dip")))
+               return(0);
+
+       here = levl[u.ux][u.uy].typ;
+       /* Is there a fountain to dip into here? */
+       if (IS_FOUNTAIN(here)) {
+               if(yn("Dip it into the fountain?") == 'y') {
+                       dipfountain(obj);
+                       return(1);
+               }
+       } else if (is_pool(u.ux,u.uy)) {
+               tmp = waterbody_name(u.ux,u.uy);
+               Sprintf(qbuf, "Dip it into the %s?", tmp);
+               if (yn(qbuf) == 'y') {
+                   if (Levitation) {
+                       floating_above(tmp);
+#ifdef STEED
+                   } else if (u.usteed && !is_swimmer(u.usteed->data) &&
+                           P_SKILL(P_RIDING) < P_BASIC) {
+                       rider_cant_reach(); /* not skilled enough to reach */
+#endif
+                   } else {
+                       (void) get_wet(obj);
+                       if (obj->otyp == POT_ACID) useup(obj);
+                   }
+                   return 1;
+               }
+       }
+
+       if(!(potion = getobj(beverages, "dip into")))
+               return(0);
+       if (potion == obj && potion->quan == 1L) {
+               pline("That is a potion bottle, not a Klein bottle!");
+               return 0;
+       }
+       potion->in_use = TRUE;          /* assume it will be used up */
+       if(potion->otyp == POT_WATER) {
+               boolean useeit = !Blind;
+               if (useeit) (void) Shk_Your(Your_buf, obj);
+               if (potion->blessed) {
+                       if (obj->cursed) {
+                               if (useeit)
+                                   pline("%s %s %s.",
+                                         Your_buf,
+                                         aobjnam(obj, "softly glow"),
+                                         hcolor(NH_AMBER));
+                               uncurse(obj);
+                               obj->bknown=1;
+       poof:
+                               if(!(objects[potion->otyp].oc_name_known) &&
+                                  !(objects[potion->otyp].oc_uname))
+                                       docall(potion);
+                               useup(potion);
+                               return(1);
+                       } else if(!obj->blessed) {
+                               if (useeit) {
+                                   tmp = hcolor(NH_LIGHT_BLUE);
+                                   pline("%s %s with a%s %s aura.",
+                                         Your_buf,
+                                         aobjnam(obj, "softly glow"),
+                                         index(vowels, *tmp) ? "n" : "", tmp);
+                               }
+                               bless(obj);
+                               obj->bknown=1;
+                               goto poof;
+                       }
+               } else if (potion->cursed) {
+                       if (obj->blessed) {
+                               if (useeit)
+                                   pline("%s %s %s.",
+                                         Your_buf,
+                                         aobjnam(obj, "glow"),
+                                         hcolor((const char *)"brown"));
+                               unbless(obj);
+                               obj->bknown=1;
+                               goto poof;
+                       } else if(!obj->cursed) {
+                               if (useeit) {
+                                   tmp = hcolor(NH_BLACK);
+                                   pline("%s %s with a%s %s aura.",
+                                         Your_buf,
+                                         aobjnam(obj, "glow"),
+                                         index(vowels, *tmp) ? "n" : "", tmp);
+                               }
+                               curse(obj);
+                               obj->bknown=1;
+                               goto poof;
+                       }
+               } else
+                       if (get_wet(obj))
+                           goto poof;
+       } else if (obj->otyp == POT_POLYMORPH ||
+               potion->otyp == POT_POLYMORPH) {
+           /* some objects can't be polymorphed */
+           if (obj->otyp == potion->otyp ||    /* both POT_POLY */
+                   obj->otyp == WAN_POLYMORPH ||
+                   obj->otyp == SPE_POLYMORPH ||
+                   obj == uball || obj == uskin ||
+                   obj_resists(obj->otyp == POT_POLYMORPH ?
+                               potion : obj, 5, 95)) {
+               pline(nothing_happens);
+           } else {
+               boolean was_wep = FALSE, was_swapwep = FALSE, was_quiver = FALSE;
+               short save_otyp = obj->otyp;
+               /* KMH, conduct */
+               u.uconduct.polypiles++;
+
+               if (obj == uwep) was_wep = TRUE;
+               else if (obj == uswapwep) was_swapwep = TRUE;
+               else if (obj == uquiver) was_quiver = TRUE;
+
+               obj = poly_obj(obj, STRANGE_OBJECT);
+
+               if (was_wep) setuwep(obj);
+               else if (was_swapwep) setuswapwep(obj);
+               else if (was_quiver) setuqwep(obj);
+
+               if (obj->otyp != save_otyp) {
+                       makeknown(POT_POLYMORPH);
+                       useup(potion);
+                       prinv((char *)0, obj, 0L);
+                       return 1;
+               } else {
+                       pline("Nothing seems to happen.");
+                       goto poof;
+               }
+           }
+           potion->in_use = FALSE;     /* didn't go poof */
+           return(1);
+       } else if(obj->oclass == POTION_CLASS && obj->otyp != potion->otyp) {
+               /* Mixing potions is dangerous... */
+               pline_The("potions mix...");
+               /* KMH, balance patch -- acid is particularly unstable */
+               if (obj->cursed || obj->otyp == POT_ACID || !rn2(10)) {
+                       pline("BOOM!  They explode!");
+                       exercise(A_STR, FALSE);
+                       if (!breathless(youmonst.data) || haseyes(youmonst.data))
+                               potionbreathe(obj);
+                       useup(obj);
+                       useup(potion);
+                       losehp(rnd(10), "alchemic blast", KILLED_BY_AN);
+                       return(1);
+               }
+
+               obj->blessed = obj->cursed = obj->bknown = 0;
+               if (Blind || Hallucination) obj->dknown = 0;
+
+               if ((mixture = mixtype(obj, potion)) != 0) {
+                       obj->otyp = mixture;
+               } else {
+                   switch (obj->odiluted ? 1 : rnd(8)) {
+                       case 1:
+                               obj->otyp = POT_WATER;
+                               break;
+                       case 2:
+                       case 3:
+                               obj->otyp = POT_SICKNESS;
+                               break;
+                       case 4:
+                               {
+                                 struct obj *otmp;
+                                 otmp = mkobj(POTION_CLASS,FALSE);
+                                 obj->otyp = otmp->otyp;
+                                 obfree(otmp, (struct obj *)0);
+                               }
+                               break;
+                       default:
+                               if (!Blind)
+                         pline_The("mixture glows brightly and evaporates.");
+                               useup(obj);
+                               useup(potion);
+                               return(1);
+                   }
+               }
+
+               obj->odiluted = (obj->otyp != POT_WATER);
+
+               if (obj->otyp == POT_WATER && !Hallucination) {
+                       pline_The("mixture bubbles%s.",
+                               Blind ? "" : ", then clears");
+               } else if (!Blind) {
+                       pline_The("mixture looks %s.",
+                               hcolor(OBJ_DESCR(objects[obj->otyp])));
+               }
+
+               useup(potion);
+               return(1);
+       }
+
+#ifdef INVISIBLE_OBJECTS
+       if (potion->otyp == POT_INVISIBILITY && !obj->oinvis) {
+               obj->oinvis = TRUE;
+               if (!Blind) {
+                   if (!See_invisible) pline("Where did %s go?",
+                               the(xname(obj)));
+                   else You("notice a little haziness around %s.",
+                               the(xname(obj)));
+               }
+               goto poof;
+       } else if (potion->otyp == POT_SEE_INVISIBLE && obj->oinvis) {
+               obj->oinvis = FALSE;
+               if (!Blind) {
+                   if (!See_invisible) pline("So that's where %s went!",
+                               the(xname(obj)));
+                   else pline_The("haziness around %s disappears.",
+                               the(xname(obj)));
+               }
+               goto poof;
+       }
+#endif
+
+       if(is_poisonable(obj)) {
+           if(potion->otyp == POT_SICKNESS && !obj->opoisoned) {
+               char buf[BUFSZ];
+               if (potion->quan > 1L)
+                   Sprintf(buf, "One of %s", the(xname(potion)));
+               else
+                   Strcpy(buf, The(xname(potion)));
+               pline("%s forms a coating on %s.",
+                     buf, the(xname(obj)));
+               obj->opoisoned = TRUE;
+               goto poof;
+           } else if(obj->opoisoned &&
+                     (potion->otyp == POT_HEALING ||
+                      potion->otyp == POT_EXTRA_HEALING ||
+                      potion->otyp == POT_FULL_HEALING)) {
+               pline("A coating wears off %s.", the(xname(obj)));
+               obj->opoisoned = 0;
+               goto poof;
+           }
+       }
+
+       if (potion->otyp == POT_OIL) {
+           boolean wisx = FALSE;
+           if (potion->lamplit) {      /* burning */
+               int omat = objects[obj->otyp].oc_material;
+               /* the code here should be merged with fire_damage */
+               if (catch_lit(obj)) {
+                   /* catch_lit does all the work if true */
+               } else if (obj->oerodeproof || obj_resists(obj, 5, 95) ||
+                          !is_flammable(obj) || obj->oclass == FOOD_CLASS) {
+                   pline("%s %s to burn for a moment.",
+                         Yname2(obj), otense(obj, "seem"));
+               } else {
+                   if ((omat == PLASTIC || omat == PAPER) && !obj->oartifact)
+                       obj->oeroded = MAX_ERODE;
+                   pline_The("burning oil %s %s.",
+                           obj->oeroded == MAX_ERODE ? "destroys" : "damages",
+                           yname(obj));
+                   if (obj->oeroded == MAX_ERODE) {
+                       obj_extract_self(obj);
+                       obfree(obj, (struct obj *)0);
+                       obj = (struct obj *) 0;
+                   } else {
+                       /* we know it's carried */
+                       if (obj->unpaid) {
+                           /* create a dummy duplicate to put on bill */
+                           verbalize("You burnt it, you bought it!");
+                           bill_dummy_object(obj);
+                       }
+                       obj->oeroded++;
+                   }
+               }
+           } else if (potion->cursed) {
+               pline_The("potion spills and covers your %s with oil.",
+                         makeplural(body_part(FINGER)));
+               incr_itimeout(&Glib, d(2,10));
+           } else if (obj->oclass != WEAPON_CLASS && !is_weptool(obj)) {
+               /* the following cases apply only to weapons */
+               goto more_dips;
+           /* Oil removes rust and corrosion, but doesn't unburn.
+            * Arrows, etc are classed as metallic due to arrowhead
+            * material, but dipping in oil shouldn't repair them.
+            */
+           } else if ((!is_rustprone(obj) && !is_corrodeable(obj)) ||
+                       is_ammo(obj) || (!obj->oeroded && !obj->oeroded2)) {
+               /* uses up potion, doesn't set obj->greased */
+               pline("%s %s with an oily sheen.",
+                     Yname2(obj), otense(obj, "gleam"));
+           } else {
+               pline("%s %s less %s.",
+                     Yname2(obj), otense(obj, "are"),
+                     (obj->oeroded && obj->oeroded2) ? "corroded and rusty" :
+                       obj->oeroded ? "rusty" : "corroded");
+               if (obj->oeroded > 0) obj->oeroded--;
+               if (obj->oeroded2 > 0) obj->oeroded2--;
+               wisx = TRUE;
+           }
+           exercise(A_WIS, wisx);
+           makeknown(potion->otyp);
+           useup(potion);
+           return 1;
+       }
+    more_dips:
+
+       /* Allow filling of MAGIC_LAMPs to prevent identification by player */
+       if ((obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP) &&
+          (potion->otyp == POT_OIL)) {
+           /* Turn off engine before fueling, turn off fuel too :-)  */
+           if (obj->lamplit || potion->lamplit) {
+               useup(potion);
+               explode(u.ux, u.uy, 11, d(6,6), 0, EXPL_FIERY);
+               exercise(A_WIS, FALSE);
+               return 1;
+           }
+           /* Adding oil to an empty magic lamp renders it into an oil lamp */
+           if ((obj->otyp == MAGIC_LAMP) && obj->spe == 0) {
+               obj->otyp = OIL_LAMP;
+               obj->age = 0;
+           }
+           if (obj->age > 1000L) {
+               pline("%s %s full.", Yname2(obj), otense(obj, "are"));
+               potion->in_use = FALSE; /* didn't go poof */
+           } else {
+               You("fill %s with oil.", yname(obj));
+               check_unpaid(potion);   /* Yendorian Fuel Tax */
+               obj->age += 2*potion->age;      /* burns more efficiently */
+               if (obj->age > 1500L) obj->age = 1500L;
+               useup(potion);
+               exercise(A_WIS, TRUE);
+           }
+           makeknown(POT_OIL);
+           obj->spe = 1;
+           update_inventory();
+           return 1;
+       }
+
+       potion->in_use = FALSE;         /* didn't go poof */
+       if ((obj->otyp == UNICORN_HORN || obj->otyp == AMETHYST) &&
+           (mixture = mixtype(obj, potion)) != 0) {
+               char oldbuf[BUFSZ], newbuf[BUFSZ];
+               short old_otyp = potion->otyp;
+               boolean old_dknown = FALSE;
+               boolean more_than_one = potion->quan > 1;
+
+               oldbuf[0] = '\0';
+               if (potion->dknown) {
+                   old_dknown = TRUE;
+                   Sprintf(oldbuf, "%s ",
+                           hcolor(OBJ_DESCR(objects[potion->otyp])));
+               }
+               /* with multiple merged potions, split off one and
+                  just clear it */
+               if (potion->quan > 1L) {
+                   singlepotion = splitobj(potion, 1L);
+               } else singlepotion = potion;
+               
+               if(singlepotion->unpaid && costly_spot(u.ux, u.uy)) {
+                   You("use it, you pay for it.");
+                   bill_dummy_object(singlepotion);
+               }
+               singlepotion->otyp = mixture;
+               singlepotion->blessed = 0;
+               if (mixture == POT_WATER)
+                   singlepotion->cursed = singlepotion->odiluted = 0;
+               else
+                   singlepotion->cursed = obj->cursed;  /* odiluted left as-is */
+               singlepotion->bknown = FALSE;
+               if (Blind) {
+                   singlepotion->dknown = FALSE;
+               } else {
+                   singlepotion->dknown = !Hallucination;
+                   if (mixture == POT_WATER && singlepotion->dknown)
+                       Sprintf(newbuf, "clears");
+                   else
+                       Sprintf(newbuf, "turns %s",
+                               hcolor(OBJ_DESCR(objects[mixture])));
+                   pline_The("%spotion%s %s.", oldbuf,
+                             more_than_one ? " that you dipped into" : "",
+                             newbuf);
+                   if(!objects[old_otyp].oc_uname &&
+                       !objects[old_otyp].oc_name_known && old_dknown) {
+                       struct obj fakeobj;
+                       fakeobj = zeroobj;
+                       fakeobj.dknown = 1;
+                       fakeobj.otyp = old_otyp;
+                       fakeobj.oclass = POTION_CLASS;
+                       docall(&fakeobj);
+                   }
+               }
+               obj_extract_self(singlepotion);
+               singlepotion = hold_another_object(singlepotion,
+                                       "You juggle and drop %s!",
+                                       doname(singlepotion), (const char *)0);
+               update_inventory();
+               return(1);
+       }
+
+       pline("Interesting...");
+       return(1);
+}
+
+
+void
+djinni_from_bottle(obj)
+register struct obj *obj;
+{
+       struct monst *mtmp;
+       int chance;
+
+       if(!(mtmp = makemon(&mons[PM_DJINNI], u.ux, u.uy, NO_MM_FLAGS))){
+               pline("It turns out to be empty.");
+               return;
+       }
+
+       if (!Blind) {
+               pline("In a cloud of smoke, %s emerges!", a_monnam(mtmp));
+               pline("%s speaks.", Monnam(mtmp));
+       } else {
+               You("smell acrid fumes.");
+               pline("%s speaks.", Something);
+       }
+
+       chance = rn2(5);
+       if (obj->blessed) chance = (chance == 4) ? rnd(4) : 0;
+       else if (obj->cursed) chance = (chance == 0) ? rn2(4) : 4;
+       /* 0,1,2,3,4:  b=80%,5,5,5,5; nc=20%,20,20,20,20; c=5%,5,5,5,80 */
+
+       switch (chance) {
+       case 0 : verbalize("I am in your debt.  I will grant one wish!");
+               makewish();
+               mongone(mtmp);
+               break;
+       case 1 : verbalize("Thank you for freeing me!");
+               (void) tamedog(mtmp, (struct obj *)0);
+               break;
+       case 2 : verbalize("You freed me!");
+               mtmp->mpeaceful = TRUE;
+               set_malign(mtmp);
+               break;
+       case 3 : verbalize("It is about time!");
+               pline("%s vanishes.", Monnam(mtmp));
+               mongone(mtmp);
+               break;
+       default: verbalize("You disturbed me, fool!");
+               break;
+       }
+}
+
+/* clone a gremlin or mold (2nd arg non-null implies heat as the trigger);
+   hit points are cut in half (odd HP stays with original) */
+struct monst *
+split_mon(mon, mtmp)
+struct monst *mon,     /* monster being split */
+            *mtmp;     /* optional attacker whose heat triggered it */
+{
+       struct monst *mtmp2;
+       char reason[BUFSZ];
+
+       reason[0] = '\0';
+       if (mtmp) Sprintf(reason, " from %s heat",
+                         (mtmp == &youmonst) ? (const char *)"your" :
+                             (const char *)s_suffix(mon_nam(mtmp)));
+
+       if (mon == &youmonst) {
+           mtmp2 = cloneu();
+           if (mtmp2) {
+               mtmp2->mhpmax = u.mhmax / 2;
+               u.mhmax -= mtmp2->mhpmax;
+               flags.botl = 1;
+               You("multiply%s!", reason);
+           }
+       } else {
+           mtmp2 = clone_mon(mon, 0, 0);
+           if (mtmp2) {
+               mtmp2->mhpmax = mon->mhpmax / 2;
+               mon->mhpmax -= mtmp2->mhpmax;
+               if (canspotmon(mon))
+                   pline("%s multiplies%s!", Monnam(mon), reason);
+           }
+       }
+       return mtmp2;
+}
+
+#endif /* OVLB */
+
+/*potion.c*/
diff --git a/src/pray.c b/src/pray.c
new file mode 100644 (file)
index 0000000..0df2855
--- /dev/null
@@ -0,0 +1,1872 @@
+/*     SCCS Id: @(#)pray.c     3.4     2003/03/23      */
+/* Copyright (c) Benson I. Margulies, Mike Stephenson, Steve Linhart, 1989. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "epri.h"
+
+STATIC_PTR int NDECL(prayer_done);
+STATIC_DCL struct obj *NDECL(worst_cursed_item);
+STATIC_DCL int NDECL(in_trouble);
+STATIC_DCL void FDECL(fix_worst_trouble,(int));
+STATIC_DCL void FDECL(angrygods,(ALIGNTYP_P));
+STATIC_DCL void FDECL(at_your_feet, (const char *));
+#ifdef ELBERETH
+STATIC_DCL void NDECL(gcrownu);
+#endif /*ELBERETH*/
+STATIC_DCL void FDECL(pleased,(ALIGNTYP_P));
+STATIC_DCL void FDECL(godvoice,(ALIGNTYP_P,const char*));
+STATIC_DCL void FDECL(god_zaps_you,(ALIGNTYP_P));
+STATIC_DCL void FDECL(fry_by_god,(ALIGNTYP_P));
+STATIC_DCL void FDECL(gods_angry,(ALIGNTYP_P));
+STATIC_DCL void FDECL(gods_upset,(ALIGNTYP_P));
+STATIC_DCL void FDECL(consume_offering,(struct obj *));
+STATIC_DCL boolean FDECL(water_prayer,(BOOLEAN_P));
+STATIC_DCL boolean FDECL(blocked_boulder,(int,int));
+
+/* simplify a few tests */
+#define Cursed_obj(obj,typ) ((obj) && (obj)->otyp == (typ) && (obj)->cursed)
+
+/*
+ * Logic behind deities and altars and such:
+ * + prayers are made to your god if not on an altar, and to the altar's god
+ *   if you are on an altar
+ * + If possible, your god answers all prayers, which is why bad things happen
+ *   if you try to pray on another god's altar
+ * + sacrifices work basically the same way, but the other god may decide to
+ *   accept your allegiance, after which they are your god.  If rejected,
+ *   your god takes over with your punishment.
+ * + if you're in Gehennom, all messages come from Moloch
+ */
+
+/*
+ *     Moloch, who dwells in Gehennom, is the "renegade" cruel god
+ *     responsible for the theft of the Amulet from Marduk, the Creator.
+ *     Moloch is unaligned.
+ */
+static const char      *Moloch = "Moloch";
+
+static const char *godvoices[] = {
+    "booms out",
+    "thunders",
+    "rings out",
+    "booms",
+};
+
+/* values calculated when prayer starts, and used when completed */
+static aligntyp p_aligntyp;
+static int p_trouble;
+static int p_type; /* (-1)-3: (-1)=really naughty, 3=really good */
+
+#define PIOUS 20
+#define DEVOUT 14
+#define FERVENT 9
+#define STRIDENT 4
+
+/*
+ * The actual trouble priority is determined by the order of the
+ * checks performed in in_trouble() rather than by these numeric
+ * values, so keep that code and these values synchronized in
+ * order to have the values be meaningful.
+ */
+
+#define TROUBLE_STONED                 13
+#define TROUBLE_SLIMED                 12
+#define TROUBLE_STRANGLED              11
+#define TROUBLE_LAVA                   10
+#define TROUBLE_SICK                    9
+#define TROUBLE_STARVING                8
+#define TROUBLE_HIT                     7
+#define TROUBLE_LYCANTHROPE             6
+#define TROUBLE_COLLAPSING              5
+#define TROUBLE_STUCK_IN_WALL           4
+#define TROUBLE_CURSED_LEVITATION       3
+#define TROUBLE_UNUSEABLE_HANDS                 2
+#define TROUBLE_CURSED_BLINDFOLD        1
+
+#define TROUBLE_PUNISHED              (-1)
+#define TROUBLE_FUMBLING              (-2)
+#define TROUBLE_CURSED_ITEMS          (-3)
+#define TROUBLE_SADDLE                (-4)
+#define TROUBLE_BLIND                 (-5)
+#define TROUBLE_POISONED              (-6)
+#define TROUBLE_WOUNDED_LEGS          (-7)
+#define TROUBLE_HUNGRY                (-8)
+#define TROUBLE_STUNNED                       (-9)
+#define TROUBLE_CONFUSED             (-10)
+#define TROUBLE_HALLUCINATION        (-11)
+
+/* We could force rehumanize of polyselfed people, but we can't tell
+   unintentional shape changes from the other kind. Oh well.
+   3.4.2: make an exception if polymorphed into a form which lacks
+   hands; that's a case where the ramifications override this doubt.
+ */
+
+/* Return 0 if nothing particular seems wrong, positive numbers for
+   serious trouble, and negative numbers for comparative annoyances. This
+   returns the worst problem. There may be others, and the gods may fix
+   more than one.
+
+This could get as bizarre as noting surrounding opponents, (or hostile dogs),
+but that's really hard.
+ */
+
+#define ugod_is_angry() (u.ualign.record < 0)
+#define on_altar()     IS_ALTAR(levl[u.ux][u.uy].typ)
+#define on_shrine()    ((levl[u.ux][u.uy].altarmask & AM_SHRINE) != 0)
+#define a_align(x,y)   ((aligntyp)Amask2align(levl[x][y].altarmask & AM_MASK))
+
+STATIC_OVL int
+in_trouble()
+{
+       struct obj *otmp;
+       int i, j, count=0;
+
+/* Borrowed from eat.c */
+
+#define SATIATED       0
+#define NOT_HUNGRY     1
+#define HUNGRY         2
+#define WEAK           3
+#define FAINTING       4
+#define FAINTED                5
+#define STARVED                6
+
+       /*
+        * major troubles
+        */
+       if(Stoned) return(TROUBLE_STONED);
+       if(Slimed) return(TROUBLE_SLIMED);
+       if(Strangled) return(TROUBLE_STRANGLED);
+       if(u.utrap && u.utraptype == TT_LAVA) return(TROUBLE_LAVA);
+       if(Sick) return(TROUBLE_SICK);
+       if(u.uhs >= WEAK) return(TROUBLE_STARVING);
+       if (Upolyd ? (u.mh <= 5 || u.mh*7 <= u.mhmax) :
+               (u.uhp <= 5 || u.uhp*7 <= u.uhpmax)) return TROUBLE_HIT;
+       if(u.ulycn >= LOW_PM) return(TROUBLE_LYCANTHROPE);
+       if(near_capacity() >= EXT_ENCUMBER && AMAX(A_STR)-ABASE(A_STR) > 3)
+               return(TROUBLE_COLLAPSING);
+
+       for (i= -1; i<=1; i++) for(j= -1; j<=1; j++) {
+               if (!i && !j) continue;
+               if (!isok(u.ux+i, u.uy+j) || IS_ROCK(levl[u.ux+i][u.uy+j].typ)
+                   || (blocked_boulder(i,j) && !throws_rocks(youmonst.data)))
+                       count++;
+       }
+       if (count == 8 && !Passes_walls)
+               return(TROUBLE_STUCK_IN_WALL);
+
+       if (Cursed_obj(uarmf, LEVITATION_BOOTS) ||
+               stuck_ring(uleft, RIN_LEVITATION) ||
+               stuck_ring(uright, RIN_LEVITATION))
+               return(TROUBLE_CURSED_LEVITATION);
+       if (nohands(youmonst.data) || !freehand()) {
+           /* for bag/box access [cf use_container()]...
+              make sure it's a case that we know how to handle;
+              otherwise "fix all troubles" would get stuck in a loop */
+           if (welded(uwep)) return TROUBLE_UNUSEABLE_HANDS;
+           if (Upolyd && nohands(youmonst.data) && (!Unchanging ||
+                   ((otmp = unchanger()) != 0 && otmp->cursed)))
+               return TROUBLE_UNUSEABLE_HANDS;
+       }
+       if(Blindfolded && ublindf->cursed) return(TROUBLE_CURSED_BLINDFOLD);
+
+       /*
+        * minor troubles
+        */
+       if(Punished) return(TROUBLE_PUNISHED);
+       if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING) ||
+               Cursed_obj(uarmf, FUMBLE_BOOTS))
+           return TROUBLE_FUMBLING;
+       if (worst_cursed_item()) return TROUBLE_CURSED_ITEMS;
+#ifdef STEED
+       if (u.usteed) { /* can't voluntarily dismount from a cursed saddle */
+           otmp = which_armor(u.usteed, W_SADDLE);
+           if (Cursed_obj(otmp, SADDLE)) return TROUBLE_SADDLE;
+       }
+#endif
+
+       if (Blinded > 1 && haseyes(youmonst.data)) return(TROUBLE_BLIND);
+       for(i=0; i<A_MAX; i++)
+           if(ABASE(i) < AMAX(i)) return(TROUBLE_POISONED);
+       if(Wounded_legs
+#ifdef STEED
+                   && !u.usteed
+#endif
+                               ) return (TROUBLE_WOUNDED_LEGS);
+       if(u.uhs >= HUNGRY) return(TROUBLE_HUNGRY);
+       if(HStun) return (TROUBLE_STUNNED);
+       if(HConfusion) return (TROUBLE_CONFUSED);
+       if(Hallucination) return(TROUBLE_HALLUCINATION);
+       return(0);
+}
+
+/* select an item for TROUBLE_CURSED_ITEMS */
+STATIC_OVL struct obj *
+worst_cursed_item()
+{
+    register struct obj *otmp;
+
+    /* if strained or worse, check for loadstone first */
+    if (near_capacity() >= HVY_ENCUMBER) {
+       for (otmp = invent; otmp; otmp = otmp->nobj)
+           if (Cursed_obj(otmp, LOADSTONE)) return otmp;
+    }
+    /* weapon takes precedence if it is interfering
+       with taking off a ring or putting on a shield */
+    if (welded(uwep) && (uright || bimanual(uwep))) {  /* weapon */
+       otmp = uwep;
+    /* gloves come next, due to rings */
+    } else if (uarmg && uarmg->cursed) {               /* gloves */
+       otmp = uarmg;
+    /* then shield due to two handed weapons and spells */
+    } else if (uarms && uarms->cursed) {               /* shield */
+       otmp = uarms;
+    /* then cloak due to body armor */
+    } else if (uarmc && uarmc->cursed) {               /* cloak */
+       otmp = uarmc;
+    } else if (uarm && uarm->cursed) {                 /* suit */
+       otmp = uarm;
+    } else if (uarmh && uarmh->cursed) {               /* helmet */
+       otmp = uarmh;
+    } else if (uarmf && uarmf->cursed) {               /* boots */
+       otmp = uarmf;
+#ifdef TOURIST
+    } else if (uarmu && uarmu->cursed) {               /* shirt */
+       otmp = uarmu;
+#endif
+    } else if (uamul && uamul->cursed) {               /* amulet */
+       otmp = uamul;
+    } else if (uleft && uleft->cursed) {               /* left ring */
+       otmp = uleft;
+    } else if (uright && uright->cursed) {             /* right ring */
+       otmp = uright;
+    } else if (ublindf && ublindf->cursed) {           /* eyewear */
+       otmp = ublindf; /* must be non-blinding lenses */
+    /* if weapon wasn't handled above, do it now */
+    } else if (welded(uwep)) {                         /* weapon */
+       otmp = uwep;
+    /* active secondary weapon even though it isn't welded */
+    } else if (uswapwep && uswapwep->cursed && u.twoweap) {
+       otmp = uswapwep;
+    /* all worn items ought to be handled by now */
+    } else {
+       for (otmp = invent; otmp; otmp = otmp->nobj) {
+           if (!otmp->cursed) continue;
+           if (otmp->otyp == LOADSTONE || confers_luck(otmp))
+               break;
+       }
+    }
+    return otmp;
+}
+
+STATIC_OVL void
+fix_worst_trouble(trouble)
+register int trouble;
+{
+       int i;
+       struct obj *otmp = 0;
+       const char *what = (const char *)0;
+       static NEARDATA const char leftglow[] = "left ring softly glows",
+                                  rightglow[] = "right ring softly glows";
+
+       switch (trouble) {
+           case TROUBLE_STONED:
+                   You_feel("more limber.");
+                   Stoned = 0;
+                   flags.botl = 1;
+                   delayed_killer = 0;
+                   break;
+           case TROUBLE_SLIMED:
+                   pline_The("slime disappears.");
+                   Slimed = 0;
+                   flags.botl = 1;
+                   delayed_killer = 0;
+                   break;
+           case TROUBLE_STRANGLED:
+                   if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) {
+                       Your("amulet vanishes!");
+                       useup(uamul);
+                   }
+                   You("can breathe again.");
+                   Strangled = 0;
+                   flags.botl = 1;
+                   break;
+           case TROUBLE_LAVA:
+                   You("are back on solid ground.");
+                   /* teleport should always succeed, but if not,
+                    * just untrap them.
+                    */
+                   if(!safe_teleds(FALSE))
+                       u.utrap = 0;
+                   break;
+           case TROUBLE_STARVING:
+                   losestr(-1);
+                   /* fall into... */
+           case TROUBLE_HUNGRY:
+                   Your("%s feels content.", body_part(STOMACH));
+                   init_uhunger();
+                   flags.botl = 1;
+                   break;
+           case TROUBLE_SICK:
+                   You_feel("better.");
+                   make_sick(0L, (char *) 0, FALSE, SICK_ALL);
+                   break;
+           case TROUBLE_HIT:
+                   /* "fix all troubles" will keep trying if hero has
+                      5 or less hit points, so make sure they're always
+                      boosted to be more than that */
+                   You_feel("much better.");
+                   if (Upolyd) {
+                       u.mhmax += rnd(5);
+                       if (u.mhmax <= 5) u.mhmax = 5+1;
+                       u.mh = u.mhmax;
+                   }
+                   if (u.uhpmax < u.ulevel * 5 + 11) u.uhpmax += rnd(5);
+                   if (u.uhpmax <= 5) u.uhpmax = 5+1;
+                   u.uhp = u.uhpmax;
+                   flags.botl = 1;
+                   break;
+           case TROUBLE_COLLAPSING:
+                   ABASE(A_STR) = AMAX(A_STR);
+                   flags.botl = 1;
+                   break;
+           case TROUBLE_STUCK_IN_WALL:
+                   Your("surroundings change.");
+                   /* no control, but works on no-teleport levels */
+                   (void) safe_teleds(FALSE);
+                   break;
+           case TROUBLE_CURSED_LEVITATION:
+                   if (Cursed_obj(uarmf, LEVITATION_BOOTS)) {
+                       otmp = uarmf;
+                   } else if ((otmp = stuck_ring(uleft,RIN_LEVITATION)) !=0) {
+                       if (otmp == uleft) what = leftglow;
+                   } else if ((otmp = stuck_ring(uright,RIN_LEVITATION))!=0) {
+                       if (otmp == uright) what = rightglow;
+                   }
+                   goto decurse;
+           case TROUBLE_UNUSEABLE_HANDS:
+                   if (welded(uwep)) {
+                       otmp = uwep;
+                       goto decurse;
+                   }
+                   if (Upolyd && nohands(youmonst.data)) {
+                       if (!Unchanging) {
+                           Your("shape becomes uncertain.");
+                           rehumanize();  /* "You return to {normal} form." */
+                       } else if ((otmp = unchanger()) != 0 && otmp->cursed) {
+                           /* otmp is an amulet of unchanging */
+                           goto decurse;
+                       }
+                   }
+                   if (nohands(youmonst.data) || !freehand())
+                       impossible("fix_worst_trouble: couldn't cure hands.");
+                   break;
+           case TROUBLE_CURSED_BLINDFOLD:
+                   otmp = ublindf;
+                   goto decurse;
+           case TROUBLE_LYCANTHROPE:
+                   you_unwere(TRUE);
+                   break;
+       /*
+        */
+           case TROUBLE_PUNISHED:
+                   Your("chain disappears.");
+                   unpunish();
+                   break;
+           case TROUBLE_FUMBLING:
+                   if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING))
+                       otmp = uarmg;
+                   else if (Cursed_obj(uarmf, FUMBLE_BOOTS))
+                       otmp = uarmf;
+                   goto decurse;
+                   /*NOTREACHED*/
+                   break;
+           case TROUBLE_CURSED_ITEMS:
+                   otmp = worst_cursed_item();
+                   if (otmp == uright) what = rightglow;
+                   else if (otmp == uleft) what = leftglow;
+decurse:
+                   if (!otmp) {
+                       impossible("fix_worst_trouble: nothing to uncurse.");
+                       return;
+                   }
+                   uncurse(otmp);
+                   if (!Blind) {
+                       Your("%s %s.", what ? what :
+                               (const char *)aobjnam(otmp, "softly glow"),
+                            hcolor(NH_AMBER));
+                       otmp->bknown = TRUE;
+                   }
+                   update_inventory();
+                   break;
+           case TROUBLE_POISONED:
+                   if (Hallucination)
+                       pline("There's a tiger in your tank.");
+                   else
+                       You_feel("in good health again.");
+                   for(i=0; i<A_MAX; i++) {
+                       if(ABASE(i) < AMAX(i)) {
+                               ABASE(i) = AMAX(i);
+                               flags.botl = 1;
+                       }
+                   }
+                   (void) encumber_msg();
+                   break;
+           case TROUBLE_BLIND:
+               {
+                   int num_eyes = eyecount(youmonst.data);
+                   const char *eye = body_part(EYE);
+
+                   Your("%s feel%s better.",
+                        (num_eyes == 1) ? eye : makeplural(eye),
+                        (num_eyes == 1) ? "s" : "");
+                   u.ucreamed = 0;
+                   make_blinded(0L,FALSE);
+                   break;
+               }
+           case TROUBLE_WOUNDED_LEGS:
+                   heal_legs();
+                   break;
+           case TROUBLE_STUNNED:
+                   make_stunned(0L,TRUE);
+                   break;
+           case TROUBLE_CONFUSED:
+                   make_confused(0L,TRUE);
+                   break;
+           case TROUBLE_HALLUCINATION:
+                   pline ("Looks like you are back in Kansas.");
+                   (void) make_hallucinated(0L,FALSE,0L);
+                   break;
+#ifdef STEED
+           case TROUBLE_SADDLE:
+                   otmp = which_armor(u.usteed, W_SADDLE);
+                   uncurse(otmp);
+                   if (!Blind) {
+                       pline("%s %s %s.",
+                             s_suffix(upstart(y_monnam(u.usteed))),
+                             aobjnam(otmp, "softly glow"),
+                             hcolor(NH_AMBER));
+                       otmp->bknown = TRUE;
+                   }
+                   break;
+#endif
+       }
+}
+
+/* "I am sometimes shocked by...  the nuns who never take a bath without
+ * wearing a bathrobe all the time.  When asked why, since no man can see them,
+ * they reply 'Oh, but you forget the good God'.  Apparently they conceive of
+ * the Deity as a Peeping Tom, whose omnipotence enables Him to see through
+ * bathroom walls, but who is foiled by bathrobes." --Bertrand Russell, 1943
+ * Divine wrath, dungeon walls, and armor follow the same principle.
+ */
+STATIC_OVL void
+god_zaps_you(resp_god)
+aligntyp resp_god;
+{
+       if (u.uswallow) {
+           pline("Suddenly a bolt of lightning comes down at you from the heavens!");
+           pline("It strikes %s!", mon_nam(u.ustuck));
+           if (!resists_elec(u.ustuck)) {
+               pline("%s fries to a crisp!", Monnam(u.ustuck));
+               /* Yup, you get experience.  It takes guts to successfully
+                * pull off this trick on your god, anyway.
+                */
+               xkilled(u.ustuck, 0);
+           } else
+               pline("%s seems unaffected.", Monnam(u.ustuck));
+       } else {
+           pline("Suddenly, a bolt of lightning strikes you!");
+           if (Reflecting) {
+               shieldeff(u.ux, u.uy);
+               if (Blind)
+                   pline("For some reason you're unaffected.");
+               else
+                   (void) ureflects("%s reflects from your %s.", "It");
+           } else if (Shock_resistance) {
+               shieldeff(u.ux, u.uy);
+               pline("It seems not to affect you.");
+           } else
+               fry_by_god(resp_god);
+       }
+
+       pline("%s is not deterred...", align_gname(resp_god));
+       if (u.uswallow) {
+           pline("A wide-angle disintegration beam aimed at you hits %s!",
+                       mon_nam(u.ustuck));
+           if (!resists_disint(u.ustuck)) {
+               pline("%s fries to a crisp!", Monnam(u.ustuck));
+               xkilled(u.ustuck, 2); /* no corpse */
+           } else
+               pline("%s seems unaffected.", Monnam(u.ustuck));
+       } else {
+           pline("A wide-angle disintegration beam hits you!");
+
+           /* disintegrate shield and body armor before disintegrating
+            * the impudent mortal, like black dragon breath -3.
+            */
+           if (uarms && !(EReflecting & W_ARMS) &&
+                       !(EDisint_resistance & W_ARMS))
+               (void) destroy_arm(uarms);
+           if (uarmc && !(EReflecting & W_ARMC) &&
+                       !(EDisint_resistance & W_ARMC))
+               (void) destroy_arm(uarmc);
+           if (uarm && !(EReflecting & W_ARM) &&
+                       !(EDisint_resistance & W_ARM) && !uarmc)
+               (void) destroy_arm(uarm);
+#ifdef TOURIST
+           if (uarmu && !uarm && !uarmc) (void) destroy_arm(uarmu);
+#endif
+           if (!Disint_resistance)
+               fry_by_god(resp_god);
+           else {
+               You("bask in its %s glow for a minute...", NH_BLACK);
+               godvoice(resp_god, "I believe it not!");
+           }
+           if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) {
+               /* one more try for high altars */
+               verbalize("Thou cannot escape my wrath, mortal!");
+               summon_minion(resp_god, FALSE);
+               summon_minion(resp_god, FALSE);
+               summon_minion(resp_god, FALSE);
+               verbalize("Destroy %s, my servants!", uhim());
+           }
+       }
+}
+
+STATIC_OVL void
+fry_by_god(resp_god)
+aligntyp resp_god;
+{
+       char killerbuf[64];
+
+       You("fry to a crisp.");
+       killer_format = KILLED_BY;
+       Sprintf(killerbuf, "the wrath of %s", align_gname(resp_god));
+       killer = killerbuf;
+       done(DIED);
+}
+
+STATIC_OVL void
+angrygods(resp_god)
+aligntyp resp_god;
+{
+       register int    maxanger;
+
+       if(Inhell) resp_god = A_NONE;
+       u.ublessed = 0;
+
+       /* changed from tmp = u.ugangr + abs (u.uluck) -- rph */
+       /* added test for alignment diff -dlc */
+       if(resp_god != u.ualign.type)
+           maxanger =  u.ualign.record/2 + (Luck > 0 ? -Luck/3 : -Luck);
+       else
+           maxanger =  3*u.ugangr +
+               ((Luck > 0 || u.ualign.record >= STRIDENT) ? -Luck/3 : -Luck);
+       if (maxanger < 1) maxanger = 1; /* possible if bad align & good luck */
+       else if (maxanger > 15) maxanger = 15;  /* be reasonable */
+
+       switch (rn2(maxanger)) {
+           case 0:
+           case 1:     You_feel("that %s is %s.", align_gname(resp_god),
+                           Hallucination ? "bummed" : "displeased");
+                       break;
+           case 2:
+           case 3:
+                       godvoice(resp_god,(char *)0);
+                       pline("\"Thou %s, %s.\"",
+                           (ugod_is_angry() && resp_god == u.ualign.type)
+                               ? "hast strayed from the path" :
+                                               "art arrogant",
+                             youmonst.data->mlet == S_HUMAN ? "mortal" : "creature");
+                       verbalize("Thou must relearn thy lessons!");
+                       (void) adjattrib(A_WIS, -1, FALSE);
+                       losexp((char *)0);
+                       break;
+           case 6:     if (!Punished) {
+                           gods_angry(resp_god);
+                           punish((struct obj *)0);
+                           break;
+                       } /* else fall thru */
+           case 4:
+           case 5:     gods_angry(resp_god);
+                       if (!Blind && !Antimagic)
+                           pline("%s glow surrounds you.",
+                                 An(hcolor(NH_BLACK)));
+                       rndcurse();
+                       break;
+           case 7:
+           case 8:     godvoice(resp_god,(char *)0);
+                       verbalize("Thou durst %s me?",
+                                 (on_altar() &&
+                                  (a_align(u.ux,u.uy) != resp_god)) ?
+                                 "scorn":"call upon");
+                       pline("\"Then die, %s!\"",
+                             youmonst.data->mlet == S_HUMAN ? "mortal" : "creature");
+                       summon_minion(resp_god, FALSE);
+                       break;
+
+           default:    gods_angry(resp_god);
+                       god_zaps_you(resp_god);
+                       break;
+       }
+       u.ublesscnt = rnz(300);
+       return;
+}
+
+/* helper to print "str appears at your feet", or appropriate */
+static void
+at_your_feet(str)
+       const char *str;
+{
+       if (Blind) str = Something;
+       if (u.uswallow) {
+           /* barrier between you and the floor */
+           pline("%s %s into %s %s.", str, vtense(str, "drop"),
+                 s_suffix(mon_nam(u.ustuck)), mbodypart(u.ustuck, STOMACH));
+       } else {
+           pline("%s %s %s your %s!", str,
+                 Blind ? "lands" : vtense(str, "appear"),
+                 Levitation ? "beneath" : "at",
+                 makeplural(body_part(FOOT)));
+       }
+}
+
+#ifdef ELBERETH
+STATIC_OVL void
+gcrownu()
+{
+    struct obj *obj;
+    boolean already_exists, in_hand;
+    short class_gift;
+    int sp_no;
+#define ok_wep(o) ((o) && ((o)->oclass == WEAPON_CLASS || is_weptool(o)))
+
+    HSee_invisible |= FROMOUTSIDE;
+    HFire_resistance |= FROMOUTSIDE;
+    HCold_resistance |= FROMOUTSIDE;
+    HShock_resistance |= FROMOUTSIDE;
+    HSleep_resistance |= FROMOUTSIDE;
+    HPoison_resistance |= FROMOUTSIDE;
+    godvoice(u.ualign.type, (char *)0);
+
+    obj = ok_wep(uwep) ? uwep : 0;
+    already_exists = in_hand = FALSE;  /* lint suppression */
+    switch (u.ualign.type) {
+    case A_LAWFUL:
+       u.uevent.uhand_of_elbereth = 1;
+       verbalize("I crown thee...  The Hand of Elbereth!");
+       break;
+    case A_NEUTRAL:
+       u.uevent.uhand_of_elbereth = 2;
+       in_hand = (uwep && uwep->oartifact == ART_VORPAL_BLADE);
+       already_exists = exist_artifact(LONG_SWORD, artiname(ART_VORPAL_BLADE));
+       verbalize("Thou shalt be my Envoy of Balance!");
+       break;
+    case A_CHAOTIC:
+       u.uevent.uhand_of_elbereth = 3;
+       in_hand = (uwep && uwep->oartifact == ART_STORMBRINGER);
+       already_exists = exist_artifact(RUNESWORD, artiname(ART_STORMBRINGER));
+       verbalize("Thou art chosen to %s for My Glory!",
+                 already_exists && !in_hand ? "take lives" : "steal souls");
+       break;
+    }
+
+    class_gift = STRANGE_OBJECT;
+    /* 3.3.[01] had this in the A_NEUTRAL case below,
+       preventing chaotic wizards from receiving a spellbook */
+    if (Role_if(PM_WIZARD) &&
+           (!uwep || (uwep->oartifact != ART_VORPAL_BLADE &&
+                      uwep->oartifact != ART_STORMBRINGER)) &&
+           !carrying(SPE_FINGER_OF_DEATH)) {
+       class_gift = SPE_FINGER_OF_DEATH;
+ make_splbk:
+       obj = mksobj(class_gift, TRUE, FALSE);
+       bless(obj);
+       obj->bknown = TRUE;
+       at_your_feet("A spellbook");
+       dropy(obj);
+       u.ugifts++;
+       /* when getting a new book for known spell, enhance
+          currently wielded weapon rather than the book */
+       for (sp_no = 0; sp_no < MAXSPELL; sp_no++)
+           if (spl_book[sp_no].sp_id == class_gift) {
+               if (ok_wep(uwep)) obj = uwep;   /* to be blessed,&c */
+               break;
+           }
+    } else if (Role_if(PM_MONK) &&
+           (!uwep || !uwep->oartifact) &&
+           !carrying(SPE_RESTORE_ABILITY)) {
+       /* monks rarely wield a weapon */
+       class_gift = SPE_RESTORE_ABILITY;
+       goto make_splbk;
+    }
+
+    switch (u.ualign.type) {
+    case A_LAWFUL:
+       if (class_gift != STRANGE_OBJECT) {
+           ;           /* already got bonus above */
+       } else if (obj && obj->otyp == LONG_SWORD && !obj->oartifact) {
+           if (!Blind) Your("sword shines brightly for a moment.");
+           obj = oname(obj, artiname(ART_EXCALIBUR));
+           if (obj && obj->oartifact == ART_EXCALIBUR) u.ugifts++;
+       }
+       /* acquire Excalibur's skill regardless of weapon or gift */
+       unrestrict_weapon_skill(P_LONG_SWORD);
+       if (obj && obj->oartifact == ART_EXCALIBUR)
+           discover_artifact(ART_EXCALIBUR);
+       break;
+    case A_NEUTRAL:
+       if (class_gift != STRANGE_OBJECT) {
+           ;           /* already got bonus above */
+       } else if (in_hand) {
+           Your("%s goes snicker-snack!", xname(obj));
+           obj->dknown = TRUE;
+       } else if (!already_exists) {
+           obj = mksobj(LONG_SWORD, FALSE, FALSE);
+           obj = oname(obj, artiname(ART_VORPAL_BLADE));
+           obj->spe = 1;
+           at_your_feet("A sword");
+           dropy(obj);
+           u.ugifts++;
+       }
+       /* acquire Vorpal Blade's skill regardless of weapon or gift */
+       unrestrict_weapon_skill(P_LONG_SWORD);
+       if (obj && obj->oartifact == ART_VORPAL_BLADE)
+           discover_artifact(ART_VORPAL_BLADE);
+       break;
+    case A_CHAOTIC:
+      {
+       char swordbuf[BUFSZ];
+
+       Sprintf(swordbuf, "%s sword", hcolor(NH_BLACK));
+       if (class_gift != STRANGE_OBJECT) {
+           ;           /* already got bonus above */
+       } else if (in_hand) {
+           Your("%s hums ominously!", swordbuf);
+           obj->dknown = TRUE;
+       } else if (!already_exists) {
+           obj = mksobj(RUNESWORD, FALSE, FALSE);
+           obj = oname(obj, artiname(ART_STORMBRINGER));
+           at_your_feet(An(swordbuf));
+           obj->spe = 1;
+           dropy(obj);
+           u.ugifts++;
+       }
+       /* acquire Stormbringer's skill regardless of weapon or gift */
+       unrestrict_weapon_skill(P_BROAD_SWORD);
+       if (obj && obj->oartifact == ART_STORMBRINGER)
+           discover_artifact(ART_STORMBRINGER);
+       break;
+      }
+    default:
+       obj = 0;        /* lint */
+       break;
+    }
+
+    /* enhance weapon regardless of alignment or artifact status */
+    if (ok_wep(obj)) {
+       bless(obj);
+       obj->oeroded = obj->oeroded2 = 0;
+       obj->oerodeproof = TRUE;
+       obj->bknown = obj->rknown = TRUE;
+       if (obj->spe < 1) obj->spe = 1;
+       /* acquire skill in this weapon */
+       unrestrict_weapon_skill(weapon_type(obj));
+    } else if (class_gift == STRANGE_OBJECT) {
+       /* opportunity knocked, but there was nobody home... */
+       You_feel("unworthy.");
+    }
+    update_inventory();
+    return;
+}
+#endif /*ELBERETH*/
+
+STATIC_OVL void
+pleased(g_align)
+       aligntyp g_align;
+{
+       /* don't use p_trouble, worst trouble may get fixed while praying */
+       int trouble = in_trouble();     /* what's your worst difficulty? */
+       int pat_on_head = 0, kick_on_butt;
+
+       You_feel("that %s is %s.", align_gname(g_align),
+           u.ualign.record >= DEVOUT ?
+           Hallucination ? "pleased as punch" : "well-pleased" :
+           u.ualign.record >= STRIDENT ?
+           Hallucination ? "ticklish" : "pleased" :
+           Hallucination ? "full" : "satisfied");
+
+       /* not your deity */
+       if (on_altar() && p_aligntyp != u.ualign.type) {
+               adjalign(-1);
+               return;
+       } else if (u.ualign.record < 2 && trouble <= 0) adjalign(1);
+
+       /* depending on your luck & align level, the god you prayed to will:
+          - fix your worst problem if it's major.
+          - fix all your major problems.
+          - fix your worst problem if it's minor.
+          - fix all of your problems.
+          - do you a gratuitous favor.
+
+          if you make it to the the last category, you roll randomly again
+          to see what they do for you.
+
+          If your luck is at least 0, then you are guaranteed rescued
+          from your worst major problem. */
+
+       if (!trouble && u.ualign.record >= DEVOUT) {
+           /* if hero was in trouble, but got better, no special favor */
+           if (p_trouble == 0) pat_on_head = 1;
+       } else {
+           int action = rn1(Luck + (on_altar() ? 3 + on_shrine() : 2), 1);
+
+           if (!on_altar()) action = min(action, 3);
+           if (u.ualign.record < STRIDENT)
+               action = (u.ualign.record > 0 || !rnl(2)) ? 1 : 0;
+
+           switch(min(action,5)) {
+           case 5: pat_on_head = 1;
+           case 4: do fix_worst_trouble(trouble);
+                   while ((trouble = in_trouble()) != 0);
+                   break;
+
+           case 3: fix_worst_trouble(trouble);
+           case 2: while ((trouble = in_trouble()) > 0)
+                   fix_worst_trouble(trouble);
+                   break;
+
+           case 1: if (trouble > 0) fix_worst_trouble(trouble);
+           case 0: break; /* your god blows you off, too bad */
+           }
+       }
+
+    /* note: can't get pat_on_head unless all troubles have just been
+       fixed or there were no troubles to begin with; hallucination
+       won't be in effect so special handling for it is superfluous */
+    if(pat_on_head)
+       switch(rn2((Luck + 6)>>1)) {
+       case 0: break;
+       case 1:
+           if (uwep && (welded(uwep) || uwep->oclass == WEAPON_CLASS ||
+                        is_weptool(uwep))) {
+               char repair_buf[BUFSZ];
+
+               *repair_buf = '\0';
+               if (uwep->oeroded || uwep->oeroded2)
+                   Sprintf(repair_buf, " and %s now as good as new",
+                           otense(uwep, "are"));
+
+               if (uwep->cursed) {
+                   uncurse(uwep);
+                   uwep->bknown = TRUE;
+                   if (!Blind)
+                       Your("%s %s%s.", aobjnam(uwep, "softly glow"),
+                            hcolor(NH_AMBER), repair_buf);
+                   else You_feel("the power of %s over your %s.",
+                       u_gname(), xname(uwep));
+                   *repair_buf = '\0';
+               } else if (!uwep->blessed) {
+                   bless(uwep);
+                   uwep->bknown = TRUE;
+                   if (!Blind)
+                       Your("%s with %s aura%s.",
+                            aobjnam(uwep, "softly glow"),
+                            an(hcolor(NH_LIGHT_BLUE)), repair_buf);
+                   else You_feel("the blessing of %s over your %s.",
+                       u_gname(), xname(uwep));
+                   *repair_buf = '\0';
+               }
+
+               /* fix any rust/burn/rot damage, but don't protect
+                  against future damage */
+               if (uwep->oeroded || uwep->oeroded2) {
+                   uwep->oeroded = uwep->oeroded2 = 0;
+                   /* only give this message if we didn't just bless
+                      or uncurse (which has already given a message) */
+                   if (*repair_buf)
+                       Your("%s as good as new!",
+                            aobjnam(uwep, Blind ? "feel" : "look"));
+               }
+               update_inventory();
+           }
+           break;
+       case 3:
+           /* takes 2 hints to get the music to enter the stronghold */
+           if (!u.uevent.uopened_dbridge) {
+               if (u.uevent.uheard_tune < 1) {
+                   godvoice(g_align,(char *)0);
+                   verbalize("Hark, %s!",
+                         youmonst.data->mlet == S_HUMAN ? "mortal" : "creature");
+                   verbalize(
+                       "To enter the castle, thou must play the right tune!");
+                   u.uevent.uheard_tune++;
+                   break;
+               } else if (u.uevent.uheard_tune < 2) {
+                   You_hear("a divine music...");
+                   pline("It sounds like:  \"%s\".", tune);
+                   u.uevent.uheard_tune++;
+                   break;
+               }
+           }
+           /* Otherwise, falls into next case */
+       case 2:
+           if (!Blind)
+               You("are surrounded by %s glow.", an(hcolor(NH_GOLDEN)));
+           /* if any levels have been lost (and not yet regained),
+              treat this effect like blessed full healing */
+           if (u.ulevel < u.ulevelmax) {
+               u.ulevelmax -= 1;       /* see potion.c */
+               pluslvl(FALSE);
+           } else {
+               u.uhpmax += 5;
+               if (Upolyd) u.mhmax += 5;
+           }
+           u.uhp = u.uhpmax;
+           if (Upolyd) u.mh = u.mhmax;
+           ABASE(A_STR) = AMAX(A_STR);
+           if (u.uhunger < 900) init_uhunger();
+           if (u.uluck < 0) u.uluck = 0;
+           make_blinded(0L,TRUE);
+           flags.botl = 1;
+           break;
+       case 4: {
+           register struct obj *otmp;
+           int any = 0;
+
+           if (Blind)
+               You_feel("the power of %s.", u_gname());
+           else You("are surrounded by %s aura.",
+                    an(hcolor(NH_LIGHT_BLUE)));
+           for(otmp=invent; otmp; otmp=otmp->nobj) {
+               if (otmp->cursed) {
+                   uncurse(otmp);
+                   if (!Blind) {
+                       Your("%s %s.", aobjnam(otmp, "softly glow"),
+                            hcolor(NH_AMBER));
+                       otmp->bknown = TRUE;
+                       ++any;
+                   }
+               }
+           }
+           if (any) update_inventory();
+           break;
+       }
+       case 5: {
+           const char *msg="\"and thus I grant thee the gift of %s!\"";
+           godvoice(u.ualign.type, "Thou hast pleased me with thy progress,");
+           if (!(HTelepat & INTRINSIC))  {
+               HTelepat |= FROMOUTSIDE;
+               pline(msg, "Telepathy");
+               if (Blind) see_monsters();
+           } else if (!(HFast & INTRINSIC))  {
+               HFast |= FROMOUTSIDE;
+               pline(msg, "Speed");
+           } else if (!(HStealth & INTRINSIC))  {
+               HStealth |= FROMOUTSIDE;
+               pline(msg, "Stealth");
+           } else {
+               if (!(HProtection & INTRINSIC))  {
+                   HProtection |= FROMOUTSIDE;
+                   if (!u.ublessed)  u.ublessed = rn1(3, 2);
+               } else u.ublessed++;
+               pline(msg, "my protection");
+           }
+           verbalize("Use it wisely in my name!");
+           break;
+       }
+       case 7:
+       case 8:
+       case 9:         /* KMH -- can occur during full moons */
+#ifdef ELBERETH
+           if (u.ualign.record >= PIOUS && !u.uevent.uhand_of_elbereth) {
+               gcrownu();
+               break;
+           } /* else FALLTHRU */
+#endif /*ELBERETH*/
+       case 6: {
+           struct obj *otmp;
+           int sp_no, trycnt = u.ulevel + 1;
+
+           at_your_feet("An object");
+           /* not yet known spells given preference over already known ones */
+           /* Also, try to grant a spell for which there is a skill slot */
+           otmp = mkobj(SPBOOK_CLASS, TRUE);
+           while (--trycnt > 0) {
+               if (otmp->otyp != SPE_BLANK_PAPER) {
+                   for (sp_no = 0; sp_no < MAXSPELL; sp_no++)
+                       if (spl_book[sp_no].sp_id == otmp->otyp) break;
+                   if (sp_no == MAXSPELL &&
+                       !P_RESTRICTED(spell_skilltype(otmp->otyp)))
+                       break;  /* usable, but not yet known */
+               } else {
+                   if (!objects[SPE_BLANK_PAPER].oc_name_known ||
+                           carrying(MAGIC_MARKER)) break;
+               }
+               otmp->otyp = rnd_class(bases[SPBOOK_CLASS], SPE_BLANK_PAPER);
+           }
+           bless(otmp);
+           place_object(otmp, u.ux, u.uy);
+           break;
+       }
+       default:        impossible("Confused deity!");
+           break;
+       }
+
+       u.ublesscnt = rnz(350);
+       kick_on_butt = u.uevent.udemigod ? 1 : 0;
+#ifdef ELBERETH
+       if (u.uevent.uhand_of_elbereth) kick_on_butt++;
+#endif
+       if (kick_on_butt) u.ublesscnt += kick_on_butt * rnz(1000);
+
+       return;
+}
+
+/* either blesses or curses water on the altar,
+ * returns true if it found any water here.
+ */
+STATIC_OVL boolean
+water_prayer(bless_water)
+    boolean bless_water;
+{
+    register struct obj* otmp;
+    register long changed = 0;
+    boolean other = FALSE, bc_known = !(Blind || Hallucination);
+
+    for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) {
+       /* turn water into (un)holy water */
+       if (otmp->otyp == POT_WATER &&
+               (bless_water ? !otmp->blessed : !otmp->cursed)) {
+           otmp->blessed = bless_water;
+           otmp->cursed = !bless_water;
+           otmp->bknown = bc_known;
+           changed += otmp->quan;
+       } else if(otmp->oclass == POTION_CLASS)
+           other = TRUE;
+    }
+    if(!Blind && changed) {
+       pline("%s potion%s on the altar glow%s %s for a moment.",
+             ((other && changed > 1L) ? "Some of the" :
+                                       (other ? "One of the" : "The")),
+             ((other || changed > 1L) ? "s" : ""), (changed > 1L ? "" : "s"),
+             (bless_water ? hcolor(NH_LIGHT_BLUE) : hcolor(NH_BLACK)));
+    }
+    return((boolean)(changed > 0L));
+}
+
+STATIC_OVL void
+godvoice(g_align, words)
+    aligntyp g_align;
+    const char *words;
+{
+    const char *quot = "";
+    if(words)
+       quot = "\"";
+    else
+       words = "";
+
+    pline_The("voice of %s %s: %s%s%s", align_gname(g_align),
+         godvoices[rn2(SIZE(godvoices))], quot, words, quot);
+}
+
+STATIC_OVL void
+gods_angry(g_align)
+    aligntyp g_align;
+{
+    godvoice(g_align, "Thou hast angered me.");
+}
+
+/* The g_align god is upset with you. */
+STATIC_OVL void
+gods_upset(g_align)
+       aligntyp g_align;
+{
+       if(g_align == u.ualign.type) u.ugangr++;
+       else if(u.ugangr) u.ugangr--;
+       angrygods(g_align);
+}
+
+static NEARDATA const char sacrifice_types[] = { FOOD_CLASS, AMULET_CLASS, 0 };
+
+STATIC_OVL void
+consume_offering(otmp)
+register struct obj *otmp;
+{
+    if (Hallucination)
+       switch (rn2(3)) {
+           case 0:
+               Your("sacrifice sprouts wings and a propeller and roars away!");
+               break;
+           case 1:
+               Your("sacrifice puffs up, swelling bigger and bigger, and pops!");
+               break;
+           case 2:
+               Your("sacrifice collapses into a cloud of dancing particles and fades away!");
+               break;
+       }
+    else if (Blind && u.ualign.type == A_LAWFUL)
+       Your("sacrifice disappears!");
+    else Your("sacrifice is consumed in a %s!",
+             u.ualign.type == A_LAWFUL ? "flash of light" : "burst of flame");
+    if (carried(otmp)) useup(otmp);
+    else useupf(otmp, 1L);
+    exercise(A_WIS, TRUE);
+}
+
+int
+dosacrifice()
+{
+    register struct obj *otmp;
+    int value = 0;
+    int pm;
+    aligntyp altaralign = a_align(u.ux,u.uy);
+
+    if (!on_altar() || u.uswallow) {
+       You("are not standing on an altar.");
+       return 0;
+    }
+
+    if (In_endgame(&u.uz)) {
+       if (!(otmp = getobj(sacrifice_types, "sacrifice"))) return 0;
+    } else {
+       if (!(otmp = floorfood("sacrifice", 1))) return 0;
+    }
+    /*
+      Was based on nutritional value and aging behavior (< 50 moves).
+      Sacrificing a food ration got you max luck instantly, making the
+      gods as easy to please as an angry dog!
+
+      Now only accepts corpses, based on the game's evaluation of their
+      toughness.  Human and pet sacrifice, as well as sacrificing unicorns
+      of your alignment, is strongly discouraged.
+     */
+
+#define MAXVALUE 24 /* Highest corpse value (besides Wiz) */
+
+    if (otmp->otyp == CORPSE) {
+       register struct permonst *ptr = &mons[otmp->corpsenm];
+       struct monst *mtmp;
+       extern const int monstr[];
+
+       /* KMH, conduct */
+       u.uconduct.gnostic++;
+
+       /* you're handling this corpse, even if it was killed upon the altar */
+       feel_cockatrice(otmp, TRUE);
+
+       if (otmp->corpsenm == PM_ACID_BLOB
+               || (monstermoves <= peek_at_iced_corpse_age(otmp) + 50)) {
+           value = monstr[otmp->corpsenm] + 1;
+           if (otmp->oeaten)
+               value = eaten_stat(value, otmp);
+       }
+
+       if (your_race(ptr)) {
+           if (is_demon(youmonst.data)) {
+               You("find the idea very satisfying.");
+               exercise(A_WIS, TRUE);
+           } else if (u.ualign.type != A_CHAOTIC) {
+                   pline("You'll regret this infamous offense!");
+                   exercise(A_WIS, FALSE);
+           }
+
+           if (altaralign != A_CHAOTIC && altaralign != A_NONE) {
+               /* curse the lawful/neutral altar */
+               pline_The("altar is stained with %s blood.", urace.adj);
+               if(!Is_astralevel(&u.uz))
+                   levl[u.ux][u.uy].altarmask = AM_CHAOTIC;
+               angry_priest();
+           } else {
+               struct monst *dmon;
+               const char *demonless_msg;
+
+               /* Human sacrifice on a chaotic or unaligned altar */
+               /* is equivalent to demon summoning */
+               if (altaralign == A_CHAOTIC && u.ualign.type != A_CHAOTIC) {
+                   pline(
+                    "The blood floods the altar, which vanishes in %s cloud!",
+                         an(hcolor(NH_BLACK)));
+                   levl[u.ux][u.uy].typ = ROOM;
+                   levl[u.ux][u.uy].altarmask = 0;
+                   newsym(u.ux, u.uy);
+                   angry_priest();
+                   demonless_msg = "cloud dissipates";
+               } else {
+                   /* either you're chaotic or altar is Moloch's or both */
+                   pline_The("blood covers the altar!");
+                   change_luck(altaralign == A_NONE ? -2 : 2);
+                   demonless_msg = "blood coagulates";
+               }
+               if ((pm = dlord(altaralign)) != NON_PM &&
+                   (dmon = makemon(&mons[pm], u.ux, u.uy, NO_MM_FLAGS))) {
+                   You("have summoned %s!", a_monnam(dmon));
+                   if (sgn(u.ualign.type) == sgn(dmon->data->maligntyp))
+                       dmon->mpeaceful = TRUE;
+                   You("are terrified, and unable to move.");
+                   nomul(-3);
+               } else pline_The("%s.", demonless_msg);
+           }
+
+           if (u.ualign.type != A_CHAOTIC) {
+               adjalign(-5);
+               u.ugangr += 3;
+               (void) adjattrib(A_WIS, -1, TRUE);
+               if (!Inhell) angrygods(u.ualign.type);
+               change_luck(-5);
+           } else adjalign(5);
+           if (carried(otmp)) useup(otmp);
+           else useupf(otmp, 1L);
+           return(1);
+       } else if (otmp->oxlth && otmp->oattached == OATTACHED_MONST
+                   && ((mtmp = get_mtraits(otmp, FALSE)) != (struct monst *)0)
+                   && mtmp->mtame) {
+           /* mtmp is a temporary pointer to a tame monster's attributes,
+            * not a real monster */
+           pline("So this is how you repay loyalty?");
+           adjalign(-3);
+           value = -1;
+           HAggravate_monster |= FROMOUTSIDE;
+       } else if (is_undead(ptr)) { /* Not demons--no demon corpses */
+           if (u.ualign.type != A_CHAOTIC)
+               value += 1;
+       } else if (is_unicorn(ptr)) {
+           int unicalign = sgn(ptr->maligntyp);
+
+           /* If same as altar, always a very bad action. */
+           if (unicalign == altaralign) {
+               pline("Such an action is an insult to %s!",
+                     (unicalign == A_CHAOTIC)
+                     ? "chaos" : unicalign ? "law" : "balance");
+               (void) adjattrib(A_WIS, -1, TRUE);
+               value = -5;
+           } else if (u.ualign.type == altaralign) {
+               /* If different from altar, and altar is same as yours, */
+               /* it's a very good action */
+               if (u.ualign.record < ALIGNLIM)
+                   You_feel("appropriately %s.", align_str(u.ualign.type));
+               else You_feel("you are thoroughly on the right path.");
+               adjalign(5);
+               value += 3;
+           } else
+               /* If sacrificing unicorn of your alignment to altar not of */
+               /* your alignment, your god gets angry and it's a conversion */
+               if (unicalign == u.ualign.type) {
+                   u.ualign.record = -1;
+                   value = 1;
+               } else value += 3;
+       }
+    } /* corpse */
+
+    if (otmp->otyp == AMULET_OF_YENDOR) {
+       if (!Is_astralevel(&u.uz)) {
+           if (Hallucination)
+                   You_feel("homesick.");
+           else
+                   You_feel("an urge to return to the surface.");
+           return 1;
+       } else {
+           /* The final Test.  Did you win? */
+           if(uamul == otmp) Amulet_off();
+           u.uevent.ascended = 1;
+           if(carried(otmp)) useup(otmp); /* well, it's gone now */
+           else useupf(otmp, 1L);
+           You("offer the Amulet of Yendor to %s...", a_gname());
+           if (u.ualign.type != altaralign) {
+               /* And the opposing team picks you up and
+                  carries you off on their shoulders */
+               adjalign(-99);
+               pline("%s accepts your gift, and gains dominion over %s...",
+                     a_gname(), u_gname());
+               pline("%s is enraged...", u_gname());
+               pline("Fortunately, %s permits you to live...", a_gname());
+               pline("A cloud of %s smoke surrounds you...",
+                     hcolor((const char *)"orange"));
+               done(ESCAPED);
+           } else { /* super big win */
+               adjalign(10);
+pline("An invisible choir sings, and you are bathed in radiance...");
+               godvoice(altaralign, "Congratulations, mortal!");
+               display_nhwindow(WIN_MESSAGE, FALSE);
+verbalize("In return for thy service, I grant thee the gift of Immortality!");
+               You("ascend to the status of Demigod%s...",
+                   flags.female ? "dess" : "");
+               done(ASCENDED);
+           }
+       }
+    } /* real Amulet */
+
+    if (otmp->otyp == FAKE_AMULET_OF_YENDOR) {
+           if (flags.soundok)
+               You_hear("a nearby thunderclap.");
+           if (!otmp->known) {
+               You("realize you have made a %s.",
+                   Hallucination ? "boo-boo" : "mistake");
+               otmp->known = TRUE;
+               change_luck(-1);
+               return 1;
+           } else {
+               /* don't you dare try to fool the gods */
+               change_luck(-3);
+               adjalign(-1);
+               u.ugangr += 3;
+               value = -3;
+           }
+    } /* fake Amulet */
+
+    if (value == 0) {
+       pline(nothing_happens);
+       return (1);
+    }
+
+    if (altaralign != u.ualign.type &&
+       (Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) {
+       /*
+        * REAL BAD NEWS!!! High altars cannot be converted.  Even an attempt
+        * gets the god who owns it truely pissed off.
+        */
+       You_feel("the air around you grow charged...");
+       pline("Suddenly, you realize that %s has noticed you...", a_gname());
+       godvoice(altaralign, "So, mortal!  You dare desecrate my High Temple!");
+       /* Throw everything we have at the player */
+       god_zaps_you(altaralign);
+    } else if (value < 0) { /* I don't think the gods are gonna like this... */
+       gods_upset(altaralign);
+    } else {
+       int saved_anger = u.ugangr;
+       int saved_cnt = u.ublesscnt;
+       int saved_luck = u.uluck;
+
+       /* Sacrificing at an altar of a different alignment */
+       if (u.ualign.type != altaralign) {
+           /* Is this a conversion ? */
+           /* An unaligned altar in Gehennom will always elicit rejection. */
+           if (ugod_is_angry() || (altaralign == A_NONE && Inhell)) {
+               if(u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL] &&
+                  altaralign != A_NONE) {
+                   You("have a strong feeling that %s is angry...", u_gname());
+                   consume_offering(otmp);
+                   pline("%s accepts your allegiance.", a_gname());
+
+                   /* The player wears a helm of opposite alignment? */
+                   if (uarmh && uarmh->otyp == HELM_OF_OPPOSITE_ALIGNMENT)
+                       u.ualignbase[A_CURRENT] = altaralign;
+                   else
+                       u.ualign.type = u.ualignbase[A_CURRENT] = altaralign;
+                   u.ublessed = 0;
+                   flags.botl = 1;
+
+                   You("have a sudden sense of a new direction.");
+                   /* Beware, Conversion is costly */
+                   change_luck(-3);
+                   u.ublesscnt += 300;
+                   adjalign((int)(u.ualignbase[A_ORIGINAL] * (ALIGNLIM / 2)));
+               } else {
+                   u.ugangr += 3;
+                   adjalign(-5);
+                   pline("%s rejects your sacrifice!", a_gname());
+                   godvoice(altaralign, "Suffer, infidel!");
+                   change_luck(-5);
+                   (void) adjattrib(A_WIS, -2, TRUE);
+                   if (!Inhell) angrygods(u.ualign.type);
+               }
+               return(1);
+           } else {
+               consume_offering(otmp);
+               You("sense a conflict between %s and %s.",
+                   u_gname(), a_gname());
+               if (rn2(8 + u.ulevel) > 5) {
+                   struct monst *pri;
+                   You_feel("the power of %s increase.", u_gname());
+                   exercise(A_WIS, TRUE);
+                   change_luck(1);
+                   /* Yes, this is supposed to be &=, not |= */
+                   levl[u.ux][u.uy].altarmask &= AM_SHRINE;
+                   /* the following accommodates stupid compilers */
+                   levl[u.ux][u.uy].altarmask =
+                       levl[u.ux][u.uy].altarmask | (Align2amask(u.ualign.type));
+                   if (!Blind)
+                       pline_The("altar glows %s.",
+                             hcolor(
+                             u.ualign.type == A_LAWFUL ? NH_WHITE :
+                             u.ualign.type ? NH_BLACK : (const char *)"gray"));
+
+                   if (rnl(u.ulevel) > 6 && u.ualign.record > 0 &&
+                      rnd(u.ualign.record) > (3*ALIGNLIM)/4)
+                       summon_minion(altaralign, TRUE);
+                   /* anger priest; test handles bones files */
+                   if((pri = findpriest(temple_occupied(u.urooms))) &&
+                      !p_coaligned(pri))
+                       angry_priest();
+               } else {
+                   pline("Unluckily, you feel the power of %s decrease.",
+                         u_gname());
+                   change_luck(-1);
+                   exercise(A_WIS, FALSE);
+                   if (rnl(u.ulevel) > 6 && u.ualign.record > 0 &&
+                      rnd(u.ualign.record) > (7*ALIGNLIM)/8)
+                       summon_minion(altaralign, TRUE);
+               }
+               return(1);
+           }
+       }
+
+       consume_offering(otmp);
+       /* OK, you get brownie points. */
+       if(u.ugangr) {
+           u.ugangr -=
+               ((value * (u.ualign.type == A_CHAOTIC ? 2 : 3)) / MAXVALUE);
+           if(u.ugangr < 0) u.ugangr = 0;
+           if(u.ugangr != saved_anger) {
+               if (u.ugangr) {
+                   pline("%s seems %s.", u_gname(),
+                         Hallucination ? "groovy" : "slightly mollified");
+
+                   if ((int)u.uluck < 0) change_luck(1);
+               } else {
+                   pline("%s seems %s.", u_gname(), Hallucination ?
+                         "cosmic (not a new fact)" : "mollified");
+
+                   if ((int)u.uluck < 0) u.uluck = 0;
+               }
+           } else { /* not satisfied yet */
+               if (Hallucination)
+                   pline_The("gods seem tall.");
+               else You("have a feeling of inadequacy.");
+           }
+       } else if(ugod_is_angry()) {
+           if(value > MAXVALUE) value = MAXVALUE;
+           if(value > -u.ualign.record) value = -u.ualign.record;
+           adjalign(value);
+           You_feel("partially absolved.");
+       } else if (u.ublesscnt > 0) {
+           u.ublesscnt -=
+               ((value * (u.ualign.type == A_CHAOTIC ? 500 : 300)) / MAXVALUE);
+           if(u.ublesscnt < 0) u.ublesscnt = 0;
+           if(u.ublesscnt != saved_cnt) {
+               if (u.ublesscnt) {
+                   if (Hallucination)
+                       You("realize that the gods are not like you and I.");
+                   else
+                       You("have a hopeful feeling.");
+                   if ((int)u.uluck < 0) change_luck(1);
+               } else {
+                   if (Hallucination)
+                       pline("Overall, there is a smell of fried onions.");
+                   else
+                       You("have a feeling of reconciliation.");
+                   if ((int)u.uluck < 0) u.uluck = 0;
+               }
+           }
+       } else {
+           int nartifacts = nartifact_exist();
+
+           /* you were already in pretty good standing */
+           /* The player can gain an artifact */
+           /* The chance goes down as the number of artifacts goes up */
+           if (u.ulevel > 2 && u.uluck >= 0 &&
+               !rn2(10 + (2 * u.ugifts * nartifacts))) {
+               otmp = mk_artifact((struct obj *)0, a_align(u.ux,u.uy));
+               if (otmp) {
+                   if (otmp->spe < 0) otmp->spe = 0;
+                   if (otmp->cursed) uncurse(otmp);
+                   otmp->oerodeproof = TRUE;
+                   dropy(otmp);
+                   at_your_feet("An object");
+                   godvoice(u.ualign.type, "Use my gift wisely!");
+                   u.ugifts++;
+                   u.ublesscnt = rnz(300 + (50 * nartifacts));
+                   exercise(A_WIS, TRUE);
+                   /* make sure we can use this weapon */
+                   unrestrict_weapon_skill(weapon_type(otmp));
+                   discover_artifact(otmp->oartifact);
+                   return(1);
+               }
+           }
+           change_luck((value * LUCKMAX) / (MAXVALUE * 2));
+           if ((int)u.uluck < 0) u.uluck = 0;
+           if (u.uluck != saved_luck) {
+               if (Blind)
+                   You("think %s brushed your %s.",something, body_part(FOOT));
+               else You(Hallucination ?
+                   "see crabgrass at your %s.  A funny thing in a dungeon." :
+                   "glimpse a four-leaf clover at your %s.",
+                   makeplural(body_part(FOOT)));
+           }
+       }
+    }
+    return(1);
+}
+
+
+/* determine prayer results in advance; also used for enlightenment */
+boolean
+can_pray(praying)
+boolean praying;       /* false means no messages should be given */
+{
+    int alignment;
+
+    p_aligntyp = on_altar() ? a_align(u.ux,u.uy) : u.ualign.type;
+    p_trouble = in_trouble();
+
+    if (is_demon(youmonst.data) && (p_aligntyp != A_CHAOTIC)) {
+       if (praying)
+           pline_The("very idea of praying to a %s god is repugnant to you.",
+                 p_aligntyp ? "lawful" : "neutral");
+       return FALSE;
+    }
+
+    if (praying)
+       You("begin praying to %s.", align_gname(p_aligntyp));
+
+    if (u.ualign.type && u.ualign.type == -p_aligntyp)
+       alignment = -u.ualign.record;           /* Opposite alignment altar */
+    else if (u.ualign.type != p_aligntyp)
+       alignment = u.ualign.record / 2;        /* Different alignment altar */
+    else alignment = u.ualign.record;
+
+    if ((p_trouble > 0) ? (u.ublesscnt > 200) : /* big trouble */
+       (p_trouble < 0) ? (u.ublesscnt > 100) : /* minor difficulties */
+       (u.ublesscnt > 0))                      /* not in trouble */
+       p_type = 0;             /* too soon... */
+    else if ((int)Luck < 0 || u.ugangr || alignment < 0)
+       p_type = 1;             /* too naughty... */
+    else /* alignment >= 0 */ {
+       if(on_altar() && u.ualign.type != p_aligntyp)
+           p_type = 2;
+       else
+           p_type = 3;
+    }
+
+    if (is_undead(youmonst.data) && !Inhell &&
+       (p_aligntyp == A_LAWFUL || (p_aligntyp == A_NEUTRAL && !rn2(10))))
+       p_type = -1;
+    /* Note:  when !praying, the random factor for neutrals makes the
+       return value a non-deterministic approximation for enlightenment.
+       This case should be uncommon enough to live with... */
+
+    return !praying ? (boolean)(p_type == 3 && !Inhell) : TRUE;
+}
+
+int
+dopray()
+{
+    /* Confirm accidental slips of Alt-P */
+    if (flags.prayconfirm)
+       if (yn("Are you sure you want to pray?") == 'n')
+           return 0;
+
+    u.uconduct.gnostic++;
+    /* Praying implies that the hero is conscious and since we have
+       no deafness attribute this implies that all verbalized messages
+       can be heard.  So, in case the player has used the 'O' command
+       to toggle this accessible flag off, force it to be on. */
+    flags.soundok = 1;
+
+    /* set up p_type and p_alignment */
+    if (!can_pray(TRUE)) return 0;
+
+#ifdef WIZARD
+    if (wizard && p_type >= 0) {
+       if (yn("Force the gods to be pleased?") == 'y') {
+           u.ublesscnt = 0;
+           if (u.uluck < 0) u.uluck = 0;
+           if (u.ualign.record <= 0) u.ualign.record = 1;
+           u.ugangr = 0;
+           if(p_type < 2) p_type = 3;
+       }
+    }
+#endif
+    nomul(-3);
+    nomovemsg = "You finish your prayer.";
+    afternmv = prayer_done;
+
+    if(p_type == 3 && !Inhell) {
+       /* if you've been true to your god you can't die while you pray */
+       if (!Blind)
+           You("are surrounded by a shimmering light.");
+       u.uinvulnerable = TRUE;
+    }
+
+    return(1);
+}
+
+STATIC_PTR int
+prayer_done()          /* M. Stephenson (1.0.3b) */
+{
+    aligntyp alignment = p_aligntyp;
+
+    u.uinvulnerable = FALSE;
+    if(p_type == -1) {
+       godvoice(alignment,
+                alignment == A_LAWFUL ?
+                "Vile creature, thou durst call upon me?" :
+                "Walk no more, perversion of nature!");
+       You_feel("like you are falling apart.");
+       /* KMH -- Gods have mastery over unchanging */
+       rehumanize();
+       losehp(rnd(20), "residual undead turning effect", KILLED_BY_AN);
+       exercise(A_CON, FALSE);
+       return(1);
+    }
+    if (Inhell) {
+       pline("Since you are in Gehennom, %s won't help you.",
+             align_gname(alignment));
+       /* haltingly aligned is least likely to anger */
+       if (u.ualign.record <= 0 || rnl(u.ualign.record))
+           angrygods(u.ualign.type);
+       return(0);
+    }
+
+    if (p_type == 0) {
+       if(on_altar() && u.ualign.type != alignment)
+           (void) water_prayer(FALSE);
+       u.ublesscnt += rnz(250);
+       change_luck(-3);
+       gods_upset(u.ualign.type);
+    } else if(p_type == 1) {
+       if(on_altar() && u.ualign.type != alignment)
+           (void) water_prayer(FALSE);
+       angrygods(u.ualign.type);       /* naughty */
+    } else if(p_type == 2) {
+       if(water_prayer(FALSE)) {
+           /* attempted water prayer on a non-coaligned altar */
+           u.ublesscnt += rnz(250);
+           change_luck(-3);
+           gods_upset(u.ualign.type);
+       } else pleased(alignment);
+    } else {
+       /* coaligned */
+       if(on_altar())
+           (void) water_prayer(TRUE);
+       pleased(alignment); /* nice */
+    }
+    return(1);
+}
+
+int
+doturn()
+{      /* Knights & Priest(esse)s only please */
+
+       struct monst *mtmp, *mtmp2;
+       int once, range, xlev;
+
+       if (!Role_if(PM_PRIEST) && !Role_if(PM_KNIGHT)) {
+               /* Try to use turn undead spell. */
+               if (objects[SPE_TURN_UNDEAD].oc_name_known) {
+                   register int sp_no;
+                   for (sp_no = 0; sp_no < MAXSPELL &&
+                        spl_book[sp_no].sp_id != NO_SPELL &&
+                        spl_book[sp_no].sp_id != SPE_TURN_UNDEAD; sp_no++);
+
+                   if (sp_no < MAXSPELL &&
+                       spl_book[sp_no].sp_id == SPE_TURN_UNDEAD)
+                           return spelleffects(sp_no, TRUE);
+               }
+
+               You("don't know how to turn undead!");
+               return(0);
+       }
+       u.uconduct.gnostic++;
+
+       if ((u.ualign.type != A_CHAOTIC &&
+                   (is_demon(youmonst.data) || is_undead(youmonst.data))) ||
+                               u.ugangr > 6 /* "Die, mortal!" */) {
+
+               pline("For some reason, %s seems to ignore you.", u_gname());
+               aggravate();
+               exercise(A_WIS, FALSE);
+               return(0);
+       }
+
+       if (Inhell) {
+           pline("Since you are in Gehennom, %s won't help you.", u_gname());
+           aggravate();
+           return(0);
+       }
+       pline("Calling upon %s, you chant an arcane formula.", u_gname());
+       exercise(A_WIS, TRUE);
+
+       /* note: does not perform unturn_dead() on victims' inventories */
+       range = BOLT_LIM + (u.ulevel / 5);      /* 5 to 11 */
+       range *= range;
+       once = 0;
+       for(mtmp = fmon; mtmp; mtmp = mtmp2) {
+           mtmp2 = mtmp->nmon;
+
+           if (DEADMONSTER(mtmp)) continue;
+           if (!cansee(mtmp->mx,mtmp->my) ||
+               distu(mtmp->mx,mtmp->my) > range) continue;
+
+           if (!mtmp->mpeaceful && (is_undead(mtmp->data) ||
+                  (is_demon(mtmp->data) && (u.ulevel > (MAXULEV/2))))) {
+
+                   mtmp->msleeping = 0;
+                   if (Confusion) {
+                       if (!once++)
+                           pline("Unfortunately, your voice falters.");
+                       mtmp->mflee = 0;
+                       mtmp->mfrozen = 0;
+                       mtmp->mcanmove = 1;
+                   } else if (!resist(mtmp, '\0', 0, TELL)) {
+                       xlev = 6;
+                       switch (mtmp->data->mlet) {
+                           /* this is intentional, lichs are tougher
+                              than zombies. */
+                       case S_LICH:    xlev += 2;  /*FALLTHRU*/
+                       case S_GHOST:   xlev += 2;  /*FALLTHRU*/
+                       case S_VAMPIRE: xlev += 2;  /*FALLTHRU*/
+                       case S_WRAITH:  xlev += 2;  /*FALLTHRU*/
+                       case S_MUMMY:   xlev += 2;  /*FALLTHRU*/
+                       case S_ZOMBIE:
+                           if (u.ulevel >= xlev &&
+                                   !resist(mtmp, '\0', 0, NOTELL)) {
+                               if (u.ualign.type == A_CHAOTIC) {
+                                   mtmp->mpeaceful = 1;
+                                   set_malign(mtmp);
+                               } else { /* damn them */
+                                   killed(mtmp);
+                               }
+                               break;
+                           } /* else flee */
+                           /*FALLTHRU*/
+                       default:
+                           monflee(mtmp, 0, FALSE, TRUE);
+                           break;
+                       }
+                   }
+           }
+       }
+       nomul(-5);
+       return(1);
+}
+
+const char *
+a_gname()
+{
+    return(a_gname_at(u.ux, u.uy));
+}
+
+const char *
+a_gname_at(x,y)     /* returns the name of an altar's deity */
+xchar x, y;
+{
+    if(!IS_ALTAR(levl[x][y].typ)) return((char *)0);
+
+    return align_gname(a_align(x,y));
+}
+
+const char *
+u_gname()  /* returns the name of the player's deity */
+{
+    return align_gname(u.ualign.type);
+}
+
+const char *
+align_gname(alignment)
+aligntyp alignment;
+{
+    const char *gnam;
+
+    switch (alignment) {
+     case A_NONE:      gnam = Moloch; break;
+     case A_LAWFUL:    gnam = urole.lgod; break;
+     case A_NEUTRAL:   gnam = urole.ngod; break;
+     case A_CHAOTIC:   gnam = urole.cgod; break;
+     default:          impossible("unknown alignment.");
+                       gnam = "someone"; break;
+    }
+    if (*gnam == '_') ++gnam;
+    return gnam;
+}
+
+/* hallucination handling for priest/minion names: select a random god
+   iff character is hallucinating */
+const char *
+halu_gname(alignment)
+aligntyp alignment;
+{
+    const char *gnam;
+    int which;
+
+    if (!Hallucination) return align_gname(alignment);
+
+    which = randrole();
+    switch (rn2(3)) {
+     case 0:   gnam = roles[which].lgod; break;
+     case 1:   gnam = roles[which].ngod; break;
+     case 2:   gnam = roles[which].cgod; break;
+     default:  gnam = 0; break;                /* lint suppression */
+    }
+    if (!gnam) gnam = Moloch;
+    if (*gnam == '_') ++gnam;
+    return gnam;
+}
+
+/* deity's title */
+const char *
+align_gtitle(alignment)
+aligntyp alignment;
+{
+    const char *gnam, *result = "god";
+
+    switch (alignment) {
+     case A_LAWFUL:    gnam = urole.lgod; break;
+     case A_NEUTRAL:   gnam = urole.ngod; break;
+     case A_CHAOTIC:   gnam = urole.cgod; break;
+     default:          gnam = 0; break;
+    }
+    if (gnam && *gnam == '_') result = "goddess";
+    return result;
+}
+
+void
+altar_wrath(x, y)
+register int x, y;
+{
+    aligntyp altaralign = a_align(x,y);
+
+    if(!strcmp(align_gname(altaralign), u_gname())) {
+       godvoice(altaralign, "How darest thou desecrate my altar!");
+       (void) adjattrib(A_WIS, -1, FALSE);
+    } else {
+       pline("A voice (could it be %s?) whispers:",
+             align_gname(altaralign));
+       verbalize("Thou shalt pay, infidel!");
+       change_luck(-1);
+    }
+}
+
+/* assumes isok() at one space away, but not necessarily at two */
+STATIC_OVL boolean
+blocked_boulder(dx,dy)
+int dx,dy;
+{
+    register struct obj *otmp;
+    long count = 0L;
+
+    for(otmp = level.objects[u.ux+dx][u.uy+dy]; otmp; otmp = otmp->nexthere) {
+       if(otmp->otyp == BOULDER)
+           count += otmp->quan;
+    }
+
+    switch(count) {
+       case 0: return FALSE; /* no boulders--not blocked */
+       case 1: break; /* possibly blocked depending on if it's pushable */
+       default: return TRUE; /* >1 boulder--blocked after they push the top
+           one; don't force them to push it first to find out */
+    }
+
+    if (!isok(u.ux+2*dx, u.uy+2*dy))
+       return TRUE;
+    if (IS_ROCK(levl[u.ux+2*dx][u.uy+2*dy].typ))
+       return TRUE;
+    if (sobj_at(BOULDER, u.ux+2*dx, u.uy+2*dy))
+       return TRUE;
+
+    return FALSE;
+}
+
+/*pray.c*/
diff --git a/src/priest.c b/src/priest.c
new file mode 100644 (file)
index 0000000..5681930
--- /dev/null
@@ -0,0 +1,721 @@
+/*     SCCS Id: @(#)priest.c   3.4     2002/11/06      */
+/* Copyright (c) Izchak Miller, Steve Linhart, 1989.             */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "mfndpos.h"
+#include "eshk.h"
+#include "epri.h"
+#include "emin.h"
+
+/* this matches the categorizations shown by enlightenment */
+#define ALGN_SINNED    (-4)    /* worse than strayed */
+
+#ifdef OVLB
+
+STATIC_DCL boolean FDECL(histemple_at,(struct monst *,XCHAR_P,XCHAR_P));
+STATIC_DCL boolean FDECL(has_shrine,(struct monst *));
+
+/*
+ * Move for priests and shopkeepers.  Called from shk_move() and pri_move().
+ * Valid returns are  1: moved  0: didn't  -1: let m_move do it  -2: died.
+ */
+int
+move_special(mtmp,in_his_shop,appr,uondoor,avoid,omx,omy,gx,gy)
+register struct monst *mtmp;
+boolean in_his_shop;
+schar appr;
+boolean uondoor,avoid;
+register xchar omx,omy,gx,gy;
+{
+       register xchar nx,ny,nix,niy;
+       register schar i;
+       schar chcnt,cnt;
+       coord poss[9];
+       long info[9];
+       long allowflags;
+       struct obj *ib = (struct obj *)0;
+
+       if(omx == gx && omy == gy)
+               return(0);
+       if(mtmp->mconf) {
+               avoid = FALSE;
+               appr = 0;
+       }
+
+       nix = omx;
+       niy = omy;
+       if (mtmp->isshk) allowflags = ALLOW_SSM;
+       else allowflags = ALLOW_SSM | ALLOW_SANCT;
+       if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK|ALLOW_WALL);
+       if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK;
+       if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG;
+       if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
+               allowflags |= OPENDOOR;
+               if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR;
+       }
+       if (is_giant(mtmp->data)) allowflags |= BUSTDOOR;
+       cnt = mfndpos(mtmp, poss, info, allowflags);
+
+       if(mtmp->isshk && avoid && uondoor) { /* perhaps we cannot avoid him */
+               for(i=0; i<cnt; i++)
+                   if(!(info[i] & NOTONL)) goto pick_move;
+               avoid = FALSE;
+       }
+
+#define GDIST(x,y)     (dist2(x,y,gx,gy))
+pick_move:
+       chcnt = 0;
+       for(i=0; i<cnt; i++) {
+               nx = poss[i].x;
+               ny = poss[i].y;
+               if(levl[nx][ny].typ == ROOM ||
+                       (mtmp->ispriest &&
+                           levl[nx][ny].typ == ALTAR) ||
+                       (mtmp->isshk &&
+                           (!in_his_shop || ESHK(mtmp)->following))) {
+                   if(avoid && (info[i] & NOTONL))
+                       continue;
+                   if((!appr && !rn2(++chcnt)) ||
+                       (appr && GDIST(nx,ny) < GDIST(nix,niy))) {
+                           nix = nx;
+                           niy = ny;
+                   }
+               }
+       }
+       if(mtmp->ispriest && avoid &&
+                       nix == omx && niy == omy && onlineu(omx,omy)) {
+               /* might as well move closer as long it's going to stay
+                * lined up */
+               avoid = FALSE;
+               goto pick_move;
+       }
+
+       if(nix != omx || niy != omy) {
+               remove_monster(omx, omy);
+               place_monster(mtmp, nix, niy);
+               newsym(nix,niy);
+               if (mtmp->isshk && !in_his_shop && inhishop(mtmp))
+                   check_special_room(FALSE);
+               if(ib) {
+                       if (cansee(mtmp->mx,mtmp->my))
+                           pline("%s picks up %s.", Monnam(mtmp),
+                               distant_name(ib,doname));
+                       obj_extract_self(ib);
+                       (void) mpickobj(mtmp, ib);
+               }
+               return(1);
+       }
+       return(0);
+}
+
+#endif /* OVLB */
+
+#ifdef OVL0
+
+char
+temple_occupied(array)
+register char *array;
+{
+       register char *ptr;
+
+       for (ptr = array; *ptr; ptr++)
+               if (rooms[*ptr - ROOMOFFSET].rtype == TEMPLE)
+                       return(*ptr);
+       return('\0');
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+STATIC_OVL boolean
+histemple_at(priest, x, y)
+register struct monst *priest;
+register xchar x, y;
+{
+       return((boolean)((EPRI(priest)->shroom == *in_rooms(x, y, TEMPLE)) &&
+              on_level(&(EPRI(priest)->shrlevel), &u.uz)));
+}
+
+/*
+ * pri_move: return 1: moved  0: didn't  -1: let m_move do it  -2: died
+ */
+int
+pri_move(priest)
+register struct monst *priest;
+{
+       register xchar gx,gy,omx,omy;
+       schar temple;
+       boolean avoid = TRUE;
+
+       omx = priest->mx;
+       omy = priest->my;
+
+       if(!histemple_at(priest, omx, omy)) return(-1);
+
+       temple = EPRI(priest)->shroom;
+
+       gx = EPRI(priest)->shrpos.x;
+       gy = EPRI(priest)->shrpos.y;
+
+       gx += rn1(3,-1);        /* mill around the altar */
+       gy += rn1(3,-1);
+
+       if(!priest->mpeaceful ||
+          (Conflict && !resist(priest, RING_CLASS, 0, 0))) {
+               if(monnear(priest, u.ux, u.uy)) {
+                       if(Displaced)
+                               Your("displaced image doesn't fool %s!",
+                                       mon_nam(priest));
+                       (void) mattacku(priest);
+                       return(0);
+               } else if(index(u.urooms, temple)) {
+                       /* chase player if inside temple & can see him */
+                       if(priest->mcansee && m_canseeu(priest)) {
+                               gx = u.ux;
+                               gy = u.uy;
+                       }
+                       avoid = FALSE;
+               }
+       } else if(Invis) avoid = FALSE;
+
+       return(move_special(priest,FALSE,TRUE,FALSE,avoid,omx,omy,gx,gy));
+}
+
+/* exclusively for mktemple() */
+void
+priestini(lvl, sroom, sx, sy, sanctum)
+d_level        *lvl;
+struct mkroom *sroom;
+int sx, sy;
+boolean sanctum;   /* is it the seat of the high priest? */
+{
+       struct monst *priest;
+       struct obj *otmp;
+       int cnt;
+
+       if(MON_AT(sx+1, sy))
+               (void) rloc(m_at(sx+1, sy), FALSE); /* insurance */
+
+       priest = makemon(&mons[sanctum ? PM_HIGH_PRIEST : PM_ALIGNED_PRIEST],
+                        sx + 1, sy, NO_MM_FLAGS);
+       if (priest) {
+               EPRI(priest)->shroom = (sroom - rooms) + ROOMOFFSET;
+               EPRI(priest)->shralign = Amask2align(levl[sx][sy].altarmask);
+               EPRI(priest)->shrpos.x = sx;
+               EPRI(priest)->shrpos.y = sy;
+               assign_level(&(EPRI(priest)->shrlevel), lvl);
+               priest->mtrapseen = ~0; /* traps are known */
+               priest->mpeaceful = 1;
+               priest->ispriest = 1;
+               priest->msleeping = 0;
+               set_malign(priest); /* mpeaceful may have changed */
+
+               /* now his/her goodies... */
+               if(sanctum && EPRI(priest)->shralign == A_NONE &&
+                    on_level(&sanctum_level, &u.uz)) {
+                       (void) mongets(priest, AMULET_OF_YENDOR);
+               }
+               /* 2 to 4 spellbooks */
+               for (cnt = rn1(3,2); cnt > 0; --cnt) {
+                   (void) mpickobj(priest, mkobj(SPBOOK_CLASS, FALSE));
+               }
+               /* robe [via makemon()] */
+               if (rn2(2) && (otmp = which_armor(priest, W_ARMC)) != 0) {
+                   if (p_coaligned(priest))
+                       uncurse(otmp);
+                   else
+                       curse(otmp);
+               }
+       }
+}
+
+/*
+ * Specially aligned monsters are named specially.
+ *     - aligned priests with ispriest and high priests have shrines
+ *             they retain ispriest and epri when polymorphed
+ *     - aligned priests without ispriest and Angels are roamers
+ *             they retain isminion and access epri as emin when polymorphed
+ *             (coaligned Angels are also created as minions, but they
+ *             use the same naming convention)
+ *     - minions do not have ispriest but have isminion and emin
+ *     - caller needs to inhibit Hallucination if it wants to force
+ *             the true name even when under that influence
+ */
+char *
+priestname(mon, pname)
+register struct monst *mon;
+char *pname;           /* caller-supplied output buffer */
+{
+       const char *what = Hallucination ? rndmonnam() : mon->data->mname;
+
+       Strcpy(pname, "the ");
+       if (mon->minvis) Strcat(pname, "invisible ");
+       if (mon->ispriest || mon->data == &mons[PM_ALIGNED_PRIEST] ||
+                                       mon->data == &mons[PM_ANGEL]) {
+               /* use epri */
+               if (mon->mtame && mon->data == &mons[PM_ANGEL])
+                       Strcat(pname, "guardian ");
+               if (mon->data != &mons[PM_ALIGNED_PRIEST] &&
+                               mon->data != &mons[PM_HIGH_PRIEST]) {
+                       Strcat(pname, what);
+                       Strcat(pname, " ");
+               }
+               if (mon->data != &mons[PM_ANGEL]) {
+                       if (!mon->ispriest && EPRI(mon)->renegade)
+                               Strcat(pname, "renegade ");
+                       if (mon->data == &mons[PM_HIGH_PRIEST])
+                               Strcat(pname, "high ");
+                       if (Hallucination)
+                               Strcat(pname, "poohbah ");
+                       else if (mon->female)
+                               Strcat(pname, "priestess ");
+                       else
+                               Strcat(pname, "priest ");
+               }
+               Strcat(pname, "of ");
+               Strcat(pname, halu_gname((int)EPRI(mon)->shralign));
+               return(pname);
+       }
+       /* use emin instead of epri */
+       Strcat(pname, what);
+       Strcat(pname, " of ");
+       Strcat(pname, halu_gname(EMIN(mon)->min_align));
+       return(pname);
+}
+
+boolean
+p_coaligned(priest)
+struct monst *priest;
+{
+       return((boolean)(u.ualign.type == ((int)EPRI(priest)->shralign)));
+}
+
+STATIC_OVL boolean
+has_shrine(pri)
+struct monst *pri;
+{
+       struct rm *lev;
+
+       if(!pri)
+               return(FALSE);
+       lev = &levl[EPRI(pri)->shrpos.x][EPRI(pri)->shrpos.y];
+       if (!IS_ALTAR(lev->typ) || !(lev->altarmask & AM_SHRINE))
+               return(FALSE);
+       return((boolean)(EPRI(pri)->shralign == Amask2align(lev->altarmask & ~AM_SHRINE)));
+}
+
+struct monst *
+findpriest(roomno)
+char roomno;
+{
+       register struct monst *mtmp;
+
+       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+           if (DEADMONSTER(mtmp)) continue;
+           if(mtmp->ispriest && (EPRI(mtmp)->shroom == roomno) &&
+              histemple_at(mtmp,mtmp->mx,mtmp->my))
+               return(mtmp);
+       }
+       return (struct monst *)0;
+}
+
+/* called from check_special_room() when the player enters the temple room */
+void
+intemple(roomno)
+register int roomno;
+{
+       register struct monst *priest = findpriest((char)roomno);
+       boolean tended = (priest != (struct monst *)0);
+       boolean shrined, sanctum, can_speak;
+       const char *msg1, *msg2;
+       char buf[BUFSZ];
+
+       if(!temple_occupied(u.urooms0)) {
+           if(tended) {
+               shrined = has_shrine(priest);
+               sanctum = (priest->data == &mons[PM_HIGH_PRIEST] &&
+                          (Is_sanctum(&u.uz) || In_endgame(&u.uz)));
+               can_speak = (priest->mcanmove && !priest->msleeping &&
+                            flags.soundok);
+               if (can_speak) {
+                   unsigned save_priest = priest->ispriest;
+                   /* don't reveal the altar's owner upon temple entry in
+                      the endgame; for the Sanctum, the next message names
+                      Moloch so suppress the "of Moloch" for him here too */
+                   if (sanctum && !Hallucination) priest->ispriest = 0;
+                   pline("%s intones:",
+                       canseemon(priest) ? Monnam(priest) : "A nearby voice");
+                   priest->ispriest = save_priest;
+               }
+               msg2 = 0;
+               if(sanctum && Is_sanctum(&u.uz)) {
+                   if(priest->mpeaceful) {
+                       msg1 = "Infidel, you have entered Moloch's Sanctum!";
+                       msg2 = "Be gone!";
+                       priest->mpeaceful = 0;
+                       set_malign(priest);
+                   } else
+                       msg1 = "You desecrate this place by your presence!";
+               } else {
+                   Sprintf(buf, "Pilgrim, you enter a %s place!",
+                           !shrined ? "desecrated" : "sacred");
+                   msg1 = buf;
+               }
+               if (can_speak) {
+                   verbalize(msg1);
+                   if (msg2) verbalize(msg2);
+               }
+               if(!sanctum) {
+                   /* !tended -> !shrined */
+                   if (!shrined || !p_coaligned(priest) ||
+                           u.ualign.record <= ALGN_SINNED)
+                       You("have a%s forbidding feeling...",
+                               (!shrined) ? "" : " strange");
+                   else You("experience a strange sense of peace.");
+               }
+           } else {
+               switch(rn2(3)) {
+                 case 0: You("have an eerie feeling..."); break;
+                 case 1: You_feel("like you are being watched."); break;
+                 default: pline("A shiver runs down your %s.",
+                       body_part(SPINE)); break;
+               }
+               if(!rn2(5)) {
+                   struct monst *mtmp;
+
+                   if(!(mtmp = makemon(&mons[PM_GHOST],u.ux,u.uy,NO_MM_FLAGS)))
+                       return;
+                   if (!Blind || sensemon(mtmp))
+                       pline("An enormous ghost appears next to you!");
+                   else You("sense a presence close by!");
+                   mtmp->mpeaceful = 0;
+                   set_malign(mtmp);
+                   if(flags.verbose)
+                       You("are frightened to death, and unable to move.");
+                   nomul(-3);
+                   nomovemsg = "You regain your composure.";
+              }
+          }
+       }
+}
+
+void
+priest_talk(priest)
+register struct monst *priest;
+{
+       boolean coaligned = p_coaligned(priest);
+       boolean strayed = (u.ualign.record < 0);
+
+       /* KMH, conduct */
+       u.uconduct.gnostic++;
+
+       if(priest->mflee || (!priest->ispriest && coaligned && strayed)) {
+           pline("%s doesn't want anything to do with you!",
+                               Monnam(priest));
+           priest->mpeaceful = 0;
+           return;
+       }
+
+       /* priests don't chat unless peaceful and in their own temple */
+       if(!histemple_at(priest,priest->mx,priest->my) ||
+                !priest->mpeaceful || !priest->mcanmove || priest->msleeping) {
+           static const char *cranky_msg[3] = {
+               "Thou wouldst have words, eh?  I'll give thee a word or two!",
+               "Talk?  Here is what I have to say!",
+               "Pilgrim, I would speak no longer with thee."
+           };
+
+           if(!priest->mcanmove || priest->msleeping) {
+               pline("%s breaks out of %s reverie!",
+                     Monnam(priest), mhis(priest));
+               priest->mfrozen = priest->msleeping = 0;
+               priest->mcanmove = 1;
+           }
+           priest->mpeaceful = 0;
+           verbalize(cranky_msg[rn2(3)]);
+           return;
+       }
+
+       /* you desecrated the temple and now you want to chat? */
+       if(priest->mpeaceful && *in_rooms(priest->mx, priest->my, TEMPLE) &&
+                 !has_shrine(priest)) {
+           verbalize("Begone!  Thou desecratest this holy place with thy presence.");
+           priest->mpeaceful = 0;
+           return;
+       }
+#ifndef GOLDOBJ
+       if(!u.ugold) {
+           if(coaligned && !strayed) {
+               if (priest->mgold > 0L) {
+                   /* Note: two bits is actually 25 cents.  Hmm. */
+                   pline("%s gives you %s for an ale.", Monnam(priest),
+                       (priest->mgold == 1L) ? "one bit" : "two bits");
+                   if (priest->mgold > 1L)
+                       u.ugold = 2L;
+                   else
+                       u.ugold = 1L;
+                   priest->mgold -= u.ugold;
+                   flags.botl = 1;
+#else
+       if(!money_cnt(invent)) {
+           if(coaligned && !strayed) {
+                long pmoney = money_cnt(priest->minvent);
+               if (pmoney > 0L) {
+                   /* Note: two bits is actually 25 cents.  Hmm. */
+                   pline("%s gives you %s for an ale.", Monnam(priest),
+                       (pmoney == 1L) ? "one bit" : "two bits");
+                    money2u(priest, pmoney > 1L ? 2 : 1);
+#endif
+               } else
+                   pline("%s preaches the virtues of poverty.", Monnam(priest));
+               exercise(A_WIS, TRUE);
+           } else
+               pline("%s is not interested.", Monnam(priest));
+           return;
+       } else {
+           long offer;
+
+           pline("%s asks you for a contribution for the temple.",
+                       Monnam(priest));
+           if((offer = bribe(priest)) == 0) {
+               verbalize("Thou shalt regret thine action!");
+               if(coaligned) adjalign(-1);
+           } else if(offer < (u.ulevel * 200)) {
+#ifndef GOLDOBJ
+               if(u.ugold > (offer * 2L)) verbalize("Cheapskate.");
+#else
+               if(money_cnt(invent) > (offer * 2L)) verbalize("Cheapskate.");
+#endif
+               else {
+                   verbalize("I thank thee for thy contribution.");
+                   /*  give player some token  */
+                   exercise(A_WIS, TRUE);
+               }
+           } else if(offer < (u.ulevel * 400)) {
+               verbalize("Thou art indeed a pious individual.");
+#ifndef GOLDOBJ
+               if(u.ugold < (offer * 2L)) {
+#else
+               if(money_cnt(invent) < (offer * 2L)) {
+#endif
+                   if (coaligned && u.ualign.record <= ALGN_SINNED)
+                       adjalign(1);
+                   verbalize("I bestow upon thee a blessing.");
+                   incr_itimeout(&HClairvoyant, rn1(500,500));
+               }
+           } else if(offer < (u.ulevel * 600) &&
+                     u.ublessed < 20 &&
+                     (u.ublessed < 9 || !rn2(u.ublessed))) {
+               verbalize("Thy devotion has been rewarded.");
+               if (!(HProtection & INTRINSIC))  {
+                       HProtection |= FROMOUTSIDE;
+                       if (!u.ublessed)  u.ublessed = rn1(3, 2);
+               } else u.ublessed++;
+           } else {
+               verbalize("Thy selfless generosity is deeply appreciated.");
+#ifndef GOLDOBJ
+               if(u.ugold < (offer * 2L) && coaligned) {
+#else
+               if(money_cnt(invent) < (offer * 2L) && coaligned) {
+#endif
+                   if(strayed && (moves - u.ucleansed) > 5000L) {
+                       u.ualign.record = 0; /* cleanse thee */
+                       u.ucleansed = moves;
+                   } else {
+                       adjalign(2);
+                   }
+               }
+           }
+       }
+}
+
+struct monst *
+mk_roamer(ptr, alignment, x, y, peaceful)
+register struct permonst *ptr;
+aligntyp alignment;
+xchar x, y;
+boolean peaceful;
+{
+       register struct monst *roamer;
+       register boolean coaligned = (u.ualign.type == alignment);
+
+       if (ptr != &mons[PM_ALIGNED_PRIEST] && ptr != &mons[PM_ANGEL])
+               return((struct monst *)0);
+       
+       if (MON_AT(x, y)) (void) rloc(m_at(x, y), FALSE);       /* insurance */
+
+       if (!(roamer = makemon(ptr, x, y, NO_MM_FLAGS)))
+               return((struct monst *)0);
+
+       EPRI(roamer)->shralign = alignment;
+       if (coaligned && !peaceful)
+               EPRI(roamer)->renegade = TRUE;
+       /* roamer->ispriest == FALSE naturally */
+       roamer->isminion = TRUE;        /* borrowing this bit */
+       roamer->mtrapseen = ~0;         /* traps are known */
+       roamer->mpeaceful = peaceful;
+       roamer->msleeping = 0;
+       set_malign(roamer); /* peaceful may have changed */
+
+       /* MORE TO COME */
+       return(roamer);
+}
+
+void
+reset_hostility(roamer)
+register struct monst *roamer;
+{
+       if(!(roamer->isminion && (roamer->data == &mons[PM_ALIGNED_PRIEST] ||
+                                 roamer->data == &mons[PM_ANGEL])))
+               return;
+
+       if(EPRI(roamer)->shralign != u.ualign.type) {
+           roamer->mpeaceful = roamer->mtame = 0;
+           set_malign(roamer);
+       }
+       newsym(roamer->mx, roamer->my);
+}
+
+boolean
+in_your_sanctuary(mon, x, y)
+struct monst *mon;     /* if non-null, <mx,my> overrides <x,y> */
+xchar x, y;
+{
+       register char roomno;
+       register struct monst *priest;
+
+       if (mon) {
+           if (is_minion(mon->data) || is_rider(mon->data)) return FALSE;
+           x = mon->mx, y = mon->my;
+       }
+       if (u.ualign.record <= ALGN_SINNED)     /* sinned or worse */
+           return FALSE;
+       if ((roomno = temple_occupied(u.urooms)) == 0 ||
+               roomno != *in_rooms(x, y, TEMPLE))
+           return FALSE;
+       if ((priest = findpriest(roomno)) == 0)
+           return FALSE;
+       return (boolean)(has_shrine(priest) &&
+                        p_coaligned(priest) &&
+                        priest->mpeaceful);
+}
+
+void
+ghod_hitsu(priest)     /* when attacking "priest" in his temple */
+struct monst *priest;
+{
+       int x, y, ax, ay, roomno = (int)temple_occupied(u.urooms);
+       struct mkroom *troom;
+
+       if (!roomno || !has_shrine(priest))
+               return;
+
+       ax = x = EPRI(priest)->shrpos.x;
+       ay = y = EPRI(priest)->shrpos.y;
+       troom = &rooms[roomno - ROOMOFFSET];
+
+       if((u.ux == x && u.uy == y) || !linedup(u.ux, u.uy, x, y)) {
+           if(IS_DOOR(levl[u.ux][u.uy].typ)) {
+
+               if(u.ux == troom->lx - 1) {
+                   x = troom->hx;
+                   y = u.uy;
+               } else if(u.ux == troom->hx + 1) {
+                   x = troom->lx;
+                   y = u.uy;
+               } else if(u.uy == troom->ly - 1) {
+                   x = u.ux;
+                   y = troom->hy;
+               } else if(u.uy == troom->hy + 1) {
+                   x = u.ux;
+                   y = troom->ly;
+               }
+           } else {
+               switch(rn2(4)) {
+               case 0:  x = u.ux; y = troom->ly; break;
+               case 1:  x = u.ux; y = troom->hy; break;
+               case 2:  x = troom->lx; y = u.uy; break;
+               default: x = troom->hx; y = u.uy; break;
+               }
+           }
+           if(!linedup(u.ux, u.uy, x, y)) return;
+       }
+
+       switch(rn2(3)) {
+       case 0:
+           pline("%s roars in anger:  \"Thou shalt suffer!\"",
+                       a_gname_at(ax, ay));
+           break;
+       case 1:
+           pline("%s voice booms:  \"How darest thou harm my servant!\"",
+                       s_suffix(a_gname_at(ax, ay)));
+           break;
+       default:
+           pline("%s roars:  \"Thou dost profane my shrine!\"",
+                       a_gname_at(ax, ay));
+           break;
+       }
+
+       buzz(-10-(AD_ELEC-1), 6, x, y, sgn(tbx), sgn(tby)); /* bolt of lightning */
+       exercise(A_WIS, FALSE);
+}
+
+void
+angry_priest()
+{
+       register struct monst *priest;
+       struct rm *lev;
+
+       if ((priest = findpriest(temple_occupied(u.urooms))) != 0) {
+           wakeup(priest);
+           /*
+            * If the altar has been destroyed or converted, let the
+            * priest run loose.
+            * (When it's just a conversion and there happens to be
+            *  a fresh corpse nearby, the priest ought to have an
+            *  opportunity to try converting it back; maybe someday...)
+            */
+           lev = &levl[EPRI(priest)->shrpos.x][EPRI(priest)->shrpos.y];
+           if (!IS_ALTAR(lev->typ) ||
+               ((aligntyp)Amask2align(lev->altarmask & AM_MASK) !=
+                       EPRI(priest)->shralign)) {
+               priest->ispriest = 0;           /* now a roamer */
+               priest->isminion = 1;           /* but still aligned */
+               /* this overloads the `shroom' field, which is now clobbered */
+               EPRI(priest)->renegade = 0;
+           }
+       }
+}
+
+/*
+ * When saving bones, find priests that aren't on their shrine level,
+ * and remove them.   This avoids big problems when restoring bones.
+ */
+void
+clearpriests()
+{
+    register struct monst *mtmp, *mtmp2;
+
+    for(mtmp = fmon; mtmp; mtmp = mtmp2) {
+       mtmp2 = mtmp->nmon;
+       if (!DEADMONSTER(mtmp) && mtmp->ispriest && !on_level(&(EPRI(mtmp)->shrlevel), &u.uz))
+           mongone(mtmp);
+    }
+}
+
+/* munge priest-specific structure when restoring -dlc */
+void
+restpriest(mtmp, ghostly)
+register struct monst *mtmp;
+boolean ghostly;
+{
+    if(u.uz.dlevel) {
+       if (ghostly)
+           assign_level(&(EPRI(mtmp)->shrlevel), &u.uz);
+    }
+}
+
+#endif /* OVLB */
+
+/*priest.c*/
diff --git a/src/quest.c b/src/quest.c
new file mode 100644 (file)
index 0000000..13597ac
--- /dev/null
@@ -0,0 +1,387 @@
+/*     SCCS Id: @(#)quest.c    3.4     2000/05/05      */
+/*     Copyright 1991, M. Stephenson             */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+/*  quest dungeon branch routines. */
+
+#include "quest.h"
+#include "qtext.h"
+
+#define Not_firsttime  (on_level(&u.uz0, &u.uz))
+#define Qstat(x)       (quest_status.x)
+
+STATIC_DCL void NDECL(on_start);
+STATIC_DCL void NDECL(on_locate);
+STATIC_DCL void NDECL(on_goal);
+STATIC_DCL boolean NDECL(not_capable);
+STATIC_DCL int FDECL(is_pure, (BOOLEAN_P));
+STATIC_DCL void FDECL(expulsion, (BOOLEAN_P));
+STATIC_DCL void NDECL(chat_with_leader);
+STATIC_DCL void NDECL(chat_with_nemesis);
+STATIC_DCL void NDECL(chat_with_guardian);
+STATIC_DCL void FDECL(prisoner_speaks, (struct monst *));
+
+
+STATIC_OVL void
+on_start()
+{
+  if(!Qstat(first_start)) {
+    qt_pager(QT_FIRSTTIME);
+    Qstat(first_start) = TRUE;
+  } else if((u.uz0.dnum != u.uz.dnum) || (u.uz0.dlevel < u.uz.dlevel)) {
+    if(Qstat(not_ready) <= 2) qt_pager(QT_NEXTTIME);
+    else       qt_pager(QT_OTHERTIME);
+  }
+}
+
+STATIC_OVL void
+on_locate()
+{
+  if(!Qstat(first_locate)) {
+    qt_pager(QT_FIRSTLOCATE);
+    Qstat(first_locate) = TRUE;
+  } else if(u.uz0.dlevel < u.uz.dlevel && !Qstat(killed_nemesis))
+       qt_pager(QT_NEXTLOCATE);
+}
+
+STATIC_OVL void
+on_goal()
+{
+  if (Qstat(killed_nemesis)) {
+    return;
+  } else if (!Qstat(made_goal)) {
+    qt_pager(QT_FIRSTGOAL);
+    Qstat(made_goal) = 1;
+  } else {
+    qt_pager(QT_NEXTGOAL);
+    if(Qstat(made_goal) < 7) Qstat(made_goal)++;
+  }
+}
+
+void
+onquest()
+{
+       if(u.uevent.qcompleted || Not_firsttime) return;
+       if(!Is_special(&u.uz)) return;
+
+       if(Is_qstart(&u.uz)) on_start();
+       else if(Is_qlocate(&u.uz) && u.uz.dlevel > u.uz0.dlevel) on_locate();
+       else if(Is_nemesis(&u.uz)) on_goal();
+       return;
+}
+
+void
+nemdead()
+{
+       if(!Qstat(killed_nemesis)) {
+           Qstat(killed_nemesis) = TRUE;
+           qt_pager(QT_KILLEDNEM);
+       }
+}
+
+void
+artitouch()
+{
+       if(!Qstat(touched_artifact)) {
+           Qstat(touched_artifact) = TRUE;
+           qt_pager(QT_GOTIT);
+           exercise(A_WIS, TRUE);
+       }
+}
+
+/* external hook for do.c (level change check) */
+boolean
+ok_to_quest()
+{
+       return((boolean)((Qstat(got_quest) || Qstat(got_thanks)))
+                       && (is_pure(FALSE) > 0));
+}
+
+STATIC_OVL boolean
+not_capable()
+{
+       return((boolean)(u.ulevel < MIN_QUEST_LEVEL));
+}
+
+STATIC_OVL int
+is_pure(talk)
+boolean talk;
+{
+    int purity;
+    aligntyp original_alignment = u.ualignbase[A_ORIGINAL];
+
+#ifdef WIZARD
+    if (wizard && talk) {
+       if (u.ualign.type != original_alignment) {
+           You("are currently %s instead of %s.",
+               align_str(u.ualign.type), align_str(original_alignment));
+       } else if (u.ualignbase[A_CURRENT] != original_alignment) {
+           You("have converted.");
+       } else if (u.ualign.record < MIN_QUEST_ALIGN) {
+           You("are currently %d and require %d.",
+               u.ualign.record, MIN_QUEST_ALIGN);
+           if (yn_function("adjust?", (char *)0, 'y') == 'y')
+               u.ualign.record = MIN_QUEST_ALIGN;
+       }
+    }
+#endif
+    purity = (u.ualign.record >= MIN_QUEST_ALIGN &&
+             u.ualign.type == original_alignment &&
+             u.ualignbase[A_CURRENT] == original_alignment) ?  1 :
+            (u.ualignbase[A_CURRENT] != original_alignment) ? -1 : 0;
+    return purity;
+}
+
+/*
+ * Expell the player to the stairs on the parent of the quest dungeon.
+ *
+ * This assumes that the hero is currently _in_ the quest dungeon and that
+ * there is a single branch to and from it.
+ */
+STATIC_OVL void
+expulsion(seal)
+boolean seal;
+{
+    branch *br;
+    d_level *dest;
+    struct trap *t;
+    int portal_flag;
+
+    br = dungeon_branch("The Quest");
+    dest = (br->end1.dnum == u.uz.dnum) ? &br->end2 : &br->end1;
+    portal_flag = u.uevent.qexpelled ? 0 :     /* returned via artifact? */
+                 !seal ? 1 : -1;
+    schedule_goto(dest, FALSE, FALSE, portal_flag, (char *)0, (char *)0);
+    if (seal) {        /* remove the portal to the quest - sealing it off */
+       int reexpelled = u.uevent.qexpelled;
+       u.uevent.qexpelled = 1;
+       /* Delete the near portal now; the far (main dungeon side)
+          portal will be deleted as part of arrival on that level.
+          If monster movement is in progress, any who haven't moved
+          yet will now miss out on a chance to wander through it... */
+       for (t = ftrap; t; t = t->ntrap)
+           if (t->ttyp == MAGIC_PORTAL) break;
+       if (t) deltrap(t);      /* (display might be briefly out of sync) */
+       else if (!reexpelled) impossible("quest portal already gone?");
+    }
+}
+
+/* Either you've returned to quest leader while carrying the quest
+   artifact or you've just thrown it to/at him or her.  If quest
+   completion text hasn't been given yet, give it now.  Otherwise
+   give another message about the character keeping the artifact
+   and using the magic portal to return to the dungeon. */
+void
+finish_quest(obj)
+struct obj *obj;       /* quest artifact; possibly null if carrying Amulet */
+{
+       struct obj *otmp;
+
+       if (u.uhave.amulet) {   /* unlikely but not impossible */
+           qt_pager(QT_HASAMULET);
+           /* leader IDs the real amulet but ignores any fakes */
+           if ((otmp = carrying(AMULET_OF_YENDOR)) != 0)
+               fully_identify_obj(otmp);
+       } else {
+           qt_pager(!Qstat(got_thanks) ? QT_OFFEREDIT : QT_OFFEREDIT2);
+           /* should have obtained bell during quest;
+              if not, suggest returning for it now */
+           if ((otmp = carrying(BELL_OF_OPENING)) == 0)
+               com_pager(5);
+       }
+       Qstat(got_thanks) = TRUE;
+
+       if (obj) {
+           u.uevent.qcompleted = 1;    /* you did it! */
+           /* behave as if leader imparts sufficient info about the
+              quest artifact */
+           fully_identify_obj(obj);
+           update_inventory();
+       }
+}
+
+STATIC_OVL void
+chat_with_leader()
+{
+/*     Rule 0: Cheater checks.                                 */
+       if(u.uhave.questart && !Qstat(met_nemesis))
+           Qstat(cheater) = TRUE;
+
+/*     It is possible for you to get the amulet without completing
+ *     the quest.  If so, try to induce the player to quest.
+ */
+       if(Qstat(got_thanks)) {
+/*     Rule 1: You've gone back with/without the amulet.       */
+           if(u.uhave.amulet)  finish_quest((struct obj *)0);
+
+/*     Rule 2: You've gone back before going for the amulet.   */
+           else                qt_pager(QT_POSTHANKS);
+       }
+
+/*     Rule 3: You've got the artifact and are back to return it. */
+         else if(u.uhave.questart) {
+           struct obj *otmp;
+
+           for (otmp = invent; otmp; otmp = otmp->nobj)
+               if (is_quest_artifact(otmp)) break;
+
+           finish_quest(otmp);
+
+/*     Rule 4: You haven't got the artifact yet.       */
+       } else if(Qstat(got_quest)) {
+           qt_pager(rn1(10, QT_ENCOURAGE));
+
+/*     Rule 5: You aren't yet acceptable - or are you? */
+       } else {
+         if(!Qstat(met_leader)) {
+           qt_pager(QT_FIRSTLEADER);
+           Qstat(met_leader) = TRUE;
+           Qstat(not_ready) = 0;
+         } else qt_pager(QT_NEXTLEADER);
+         /* the quest leader might have passed through the portal into
+            the regular dungeon; none of the remaining make sense there */
+         if (!on_level(&u.uz, &qstart_level)) return;
+
+         if(not_capable()) {
+           qt_pager(QT_BADLEVEL);
+           exercise(A_WIS, TRUE);
+           expulsion(FALSE);
+         } else if(is_pure(TRUE) < 0) {
+           com_pager(QT_BANISHED);
+           expulsion(TRUE);
+         } else if(is_pure(TRUE) == 0) {
+           qt_pager(QT_BADALIGN);
+           if(Qstat(not_ready) == MAX_QUEST_TRIES) {
+             qt_pager(QT_LASTLEADER);
+             expulsion(TRUE);
+           } else {
+             Qstat(not_ready)++;
+             exercise(A_WIS, TRUE);
+             expulsion(FALSE);
+           }
+         } else {      /* You are worthy! */
+           qt_pager(QT_ASSIGNQUEST);
+           exercise(A_WIS, TRUE);
+           Qstat(got_quest) = TRUE;
+         }
+       }
+}
+
+void
+leader_speaks(mtmp)
+       register struct monst *mtmp;
+{
+       /* maybe you attacked leader? */
+       if(!mtmp->mpeaceful) {
+               Qstat(pissed_off) = TRUE;
+               mtmp->mstrategy &= ~STRAT_WAITMASK;     /* end the inaction */
+       }
+       /* the quest leader might have passed through the portal into the
+          regular dungeon; if so, mustn't perform "backwards expulsion" */
+       if (!on_level(&u.uz, &qstart_level)) return;
+
+       if(Qstat(pissed_off)) {
+         qt_pager(QT_LASTLEADER);
+         expulsion(TRUE);
+       } else chat_with_leader();
+}
+
+STATIC_OVL void
+chat_with_nemesis()
+{
+/*     The nemesis will do most of the talking, but... */
+       qt_pager(rn1(10, QT_DISCOURAGE));
+       if(!Qstat(met_nemesis)) Qstat(met_nemesis++);
+}
+
+void
+nemesis_speaks()
+{
+       if(!Qstat(in_battle)) {
+         if(u.uhave.questart) qt_pager(QT_NEMWANTSIT);
+         else if(Qstat(made_goal) == 1 || !Qstat(met_nemesis))
+             qt_pager(QT_FIRSTNEMESIS);
+         else if(Qstat(made_goal) < 4) qt_pager(QT_NEXTNEMESIS);
+         else if(Qstat(made_goal) < 7) qt_pager(QT_OTHERNEMESIS);
+         else if(!rn2(5))      qt_pager(rn1(10, QT_DISCOURAGE));
+         if(Qstat(made_goal) < 7) Qstat(made_goal)++;
+         Qstat(met_nemesis) = TRUE;
+       } else /* he will spit out random maledictions */
+         if(!rn2(5))   qt_pager(rn1(10, QT_DISCOURAGE));
+}
+
+STATIC_OVL void
+chat_with_guardian()
+{
+/*     These guys/gals really don't have much to say... */
+       if (u.uhave.questart && Qstat(killed_nemesis))
+           qt_pager(rn1(5, QT_GUARDTALK2));
+       else
+           qt_pager(rn1(5, QT_GUARDTALK));
+}
+
+STATIC_OVL void
+prisoner_speaks (mtmp)
+       register struct monst *mtmp;
+{
+       if (mtmp->data == &mons[PM_PRISONER] &&
+                       (mtmp->mstrategy & STRAT_WAITMASK)) {
+           /* Awaken the prisoner */
+           if (canseemon(mtmp))
+               pline("%s speaks:", Monnam(mtmp));
+           verbalize("I'm finally free!");
+           mtmp->mstrategy &= ~STRAT_WAITMASK;
+           mtmp->mpeaceful = 1;
+
+           /* Your god is happy... */
+           adjalign(3);
+
+               /* ...But the guards are not */
+           (void) angry_guards(FALSE);
+       }
+       return;
+}
+
+void
+quest_chat(mtmp)
+       register struct monst *mtmp;
+{
+    if (mtmp->m_id == Qstat(leader_m_id)) {
+       chat_with_leader();
+       return;
+    }
+    switch(mtmp->data->msound) {
+           case MS_NEMESIS:    chat_with_nemesis(); break;
+           case MS_GUARDIAN:   chat_with_guardian(); break;
+           default:    impossible("quest_chat: Unknown quest character %s.",
+                                  mon_nam(mtmp));
+       }
+}
+
+void
+quest_talk(mtmp)
+       register struct monst *mtmp;
+{
+    if (mtmp->m_id == Qstat(leader_m_id)) {
+       leader_speaks(mtmp);
+       return;
+    }
+    switch(mtmp->data->msound) {
+           case MS_NEMESIS:    nemesis_speaks(); break;
+           case MS_DJINNI:     prisoner_speaks(mtmp); break;
+           default:            break;
+       }
+}
+
+void
+quest_stat_check(mtmp)
+       struct monst *mtmp;
+{
+    if(mtmp->data->msound == MS_NEMESIS)
+       Qstat(in_battle) = (mtmp->mcanmove && !mtmp->msleeping &&
+                           monnear(mtmp, u.ux, u.uy));
+}
+
+/*quest.c*/
diff --git a/src/questpgr.c b/src/questpgr.c
new file mode 100644 (file)
index 0000000..b4b80af
--- /dev/null
@@ -0,0 +1,442 @@
+/*     SCCS Id: @(#)questpgr.c 3.4     2000/05/05      */
+/*     Copyright 1991, M. Stephenson             */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "dlb.h"
+
+/*  quest-specific pager routines. */
+
+#include "qtext.h"
+
+#define QTEXT_FILE     "quest.dat"
+
+/* #define DEBUG */    /* uncomment for debugging */
+
+static void FDECL(Fread, (genericptr_t,int,int,dlb *));
+STATIC_DCL struct qtmsg * FDECL(construct_qtlist, (long));
+STATIC_DCL const char * NDECL(intermed);
+STATIC_DCL const char * NDECL(neminame);
+STATIC_DCL const char * NDECL(guardname);
+STATIC_DCL const char * NDECL(homebase);
+STATIC_DCL struct qtmsg * FDECL(msg_in, (struct qtmsg *,int));
+STATIC_DCL void FDECL(convert_arg, (CHAR_P));
+STATIC_DCL void NDECL(convert_line);
+STATIC_DCL void FDECL(deliver_by_pline, (struct qtmsg *));
+STATIC_DCL void FDECL(deliver_by_window, (struct qtmsg *,int));
+
+static char    in_line[80], cvt_buf[64], out_line[128];
+static struct  qtlists qt_list;
+static dlb     *msg_file;
+/* used by ldrname() and neminame(), then copied into cvt_buf */
+static char    nambuf[sizeof cvt_buf];
+
+#ifdef DEBUG
+static void NDECL(dump_qtlist);
+
+static void
+dump_qtlist()  /* dump the character msg list to check appearance */
+{
+       struct  qtmsg   *msg;
+       long    size;
+
+       for (msg = qt_list.chrole; msg->msgnum > 0; msg++) {
+               pline("msgnum %d: delivery %c",
+                       msg->msgnum, msg->delivery);
+               more();
+               (void) dlb_fseek(msg_file, msg->offset, SEEK_SET);
+               deliver_by_window(msg, NHW_TEXT);
+       }
+}
+#endif /* DEBUG */
+
+static void
+Fread(ptr, size, nitems, stream)
+genericptr_t   ptr;
+int    size, nitems;
+dlb    *stream;
+{
+       int cnt;
+
+       if ((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) {
+
+           panic("PREMATURE EOF ON QUEST TEXT FILE! Expected %d bytes, got %d",
+                   (size * nitems), (size * cnt));
+       }
+}
+
+STATIC_OVL struct qtmsg *
+construct_qtlist(hdr_offset)
+long   hdr_offset;
+{
+       struct qtmsg *msg_list;
+       int     n_msgs;
+
+       (void) dlb_fseek(msg_file, hdr_offset, SEEK_SET);
+       Fread(&n_msgs, sizeof(int), 1, msg_file);
+       msg_list = (struct qtmsg *)
+               alloc((unsigned)(n_msgs+1)*sizeof(struct qtmsg));
+
+       /*
+        * Load up the list.
+        */
+       Fread((genericptr_t)msg_list, n_msgs*sizeof(struct qtmsg), 1, msg_file);
+
+       msg_list[n_msgs].msgnum = -1;
+       return(msg_list);
+}
+
+void
+load_qtlist()
+{
+
+       int     n_classes, i;
+       char    qt_classes[N_HDR][LEN_HDR];
+       long    qt_offsets[N_HDR];
+
+       msg_file = dlb_fopen(QTEXT_FILE, RDBMODE);
+       if (!msg_file)
+           panic("CANNOT OPEN QUEST TEXT FILE %s.", QTEXT_FILE);
+
+       /*
+        * Read in the number of classes, then the ID's & offsets for
+        * each header.
+        */
+
+       Fread(&n_classes, sizeof(int), 1, msg_file);
+       Fread(&qt_classes[0][0], sizeof(char)*LEN_HDR, n_classes, msg_file);
+       Fread(qt_offsets, sizeof(long), n_classes, msg_file);
+
+       /*
+        * Now construct the message lists for quick reference later
+        * on when we are actually paging the messages out.
+        */
+
+       qt_list.common = qt_list.chrole = (struct qtmsg *)0;
+
+       for (i = 0; i < n_classes; i++) {
+           if (!strncmp(COMMON_ID, qt_classes[i], LEN_HDR))
+               qt_list.common = construct_qtlist(qt_offsets[i]);
+           else if (!strncmp(urole.filecode, qt_classes[i], LEN_HDR))
+               qt_list.chrole = construct_qtlist(qt_offsets[i]);
+#if 0  /* UNUSED but available */
+           else if (!strncmp(urace.filecode, qt_classes[i], LEN_HDR))
+               qt_list.chrace = construct_qtlist(qt_offsets[i]);
+#endif
+       }
+
+       if (!qt_list.common || !qt_list.chrole)
+           impossible("load_qtlist: cannot load quest text.");
+#ifdef DEBUG
+       dump_qtlist();
+#endif
+       return; /* no ***DON'T*** close the msg_file */
+}
+
+/* called at program exit */
+void
+unload_qtlist()
+{
+       if (msg_file)
+           (void) dlb_fclose(msg_file),  msg_file = 0;
+       if (qt_list.common)
+           free((genericptr_t) qt_list.common),  qt_list.common = 0;
+       if (qt_list.chrole)
+           free((genericptr_t) qt_list.chrole),  qt_list.chrole = 0;
+       return;
+}
+
+short
+quest_info(typ)
+int typ;
+{
+       switch (typ) {
+           case 0:             return (urole.questarti);
+           case MS_LEADER:     return (urole.ldrnum);
+           case MS_NEMESIS:    return (urole.neminum);
+           case MS_GUARDIAN:   return (urole.guardnum);
+           default:            impossible("quest_info(%d)", typ);
+       }
+       return 0;
+}
+
+const char *
+ldrname()      /* return your role leader's name */
+{
+       int i = urole.ldrnum;
+
+       Sprintf(nambuf, "%s%s",
+               type_is_pname(&mons[i]) ? "" : "the ",
+               mons[i].mname);
+       return nambuf;
+}
+
+STATIC_OVL const char *
+intermed()     /* return your intermediate target string */
+{
+       return (urole.intermed);
+}
+
+boolean
+is_quest_artifact(otmp)
+struct obj *otmp;
+{
+       return((boolean)(otmp->oartifact == urole.questarti));
+}
+
+STATIC_OVL const char *
+neminame()     /* return your role nemesis' name */
+{
+       int i = urole.neminum;
+
+       Sprintf(nambuf, "%s%s",
+               type_is_pname(&mons[i]) ? "" : "the ",
+               mons[i].mname);
+       return nambuf;
+}
+
+STATIC_OVL const char *
+guardname()    /* return your role leader's guard monster name */
+{
+       int i = urole.guardnum;
+
+       return(mons[i].mname);
+}
+
+STATIC_OVL const char *
+homebase()     /* return your role leader's location */
+{
+       return(urole.homebase);
+}
+
+STATIC_OVL struct qtmsg *
+msg_in(qtm_list, msgnum)
+struct qtmsg *qtm_list;
+int    msgnum;
+{
+       struct qtmsg *qt_msg;
+
+       for (qt_msg = qtm_list; qt_msg->msgnum > 0; qt_msg++)
+           if (qt_msg->msgnum == msgnum) return(qt_msg);
+
+       return((struct qtmsg *)0);
+}
+
+STATIC_OVL void
+convert_arg(c)
+char c;
+{
+       register const char *str;
+
+       switch (c) {
+
+           case 'p':   str = plname;
+                       break;
+           case 'c':   str = (flags.female && urole.name.f) ?
+                               urole.name.f : urole.name.m;
+                       break;
+           case 'r':   str = rank_of(u.ulevel, Role_switch, flags.female);
+                       break;
+           case 'R':   str = rank_of(MIN_QUEST_LEVEL, Role_switch,
+                               flags.female);
+                       break;
+           case 's':   str = (flags.female) ? "sister" : "brother";
+                       break;
+           case 'S':   str = (flags.female) ? "daughter" : "son";
+                       break;
+           case 'l':   str = ldrname();
+                       break;
+           case 'i':   str = intermed();
+                       break;
+           case 'o':   str = the(artiname(urole.questarti));
+                       break;
+           case 'n':   str = neminame();
+                       break;
+           case 'g':   str = guardname();
+                       break;
+           case 'G':   str = align_gtitle(u.ualignbase[A_ORIGINAL]);
+                       break;
+           case 'H':   str = homebase();
+                       break;
+           case 'a':   str = align_str(u.ualignbase[A_ORIGINAL]);
+                       break;
+           case 'A':   str = align_str(u.ualign.type);
+                       break;
+           case 'd':   str = align_gname(u.ualignbase[A_ORIGINAL]);
+                       break;
+           case 'D':   str = align_gname(A_LAWFUL);
+                       break;
+           case 'C':   str = "chaotic";
+                       break;
+           case 'N':   str = "neutral";
+                       break;
+           case 'L':   str = "lawful";
+                       break;
+           case 'x':   str = Blind ? "sense" : "see";
+                       break;
+           case 'Z':   str = dungeons[0].dname;
+                       break;
+           case '%':   str = "%";
+                       break;
+            default:   str = "";
+                       break;
+       }
+       Strcpy(cvt_buf, str);
+}
+
+STATIC_OVL void
+convert_line()
+{
+       char *c, *cc;
+       char xbuf[BUFSZ];
+
+       cc = out_line;
+       for (c = xcrypt(in_line, xbuf); *c; c++) {
+
+           *cc = 0;
+           switch(*c) {
+
+               case '\r':
+               case '\n':
+                       *(++cc) = 0;
+                       return;
+
+               case '%':
+                       if (*(c+1)) {
+                           convert_arg(*(++c));
+                           switch (*(++c)) {
+
+                                       /* insert "a"/"an" prefix */
+                               case 'A': Strcat(cc, An(cvt_buf));
+                                   cc += strlen(cc);
+                                   continue; /* for */
+                               case 'a': Strcat(cc, an(cvt_buf));
+                                   cc += strlen(cc);
+                                   continue; /* for */
+
+                                       /* capitalize */
+                               case 'C': cvt_buf[0] = highc(cvt_buf[0]);
+                                   break;
+
+                                       /* pluralize */
+                               case 'P': cvt_buf[0] = highc(cvt_buf[0]);
+                               case 'p': Strcpy(cvt_buf, makeplural(cvt_buf));
+                                   break;
+
+                                       /* append possessive suffix */
+                               case 'S': cvt_buf[0] = highc(cvt_buf[0]);
+                               case 's': Strcpy(cvt_buf, s_suffix(cvt_buf));
+                                   break;
+
+                                       /* strip any "the" prefix */
+                               case 't': if (!strncmpi(cvt_buf, "the ", 4)) {
+                                       Strcat(cc, &cvt_buf[4]);
+                                       cc += strlen(cc);
+                                       continue; /* for */
+                                   }
+                                   break;
+
+                               default: --c;   /* undo switch increment */
+                                   break;
+                           }
+                           Strcat(cc, cvt_buf);
+                           cc += strlen(cvt_buf);
+                           break;
+                       }       /* else fall through */
+
+               default:
+                       *cc++ = *c;
+                       break;
+           }
+       }
+       if (cc >= out_line + sizeof out_line)
+           panic("convert_line: overflow");
+       *cc = 0;
+       return;
+}
+
+STATIC_OVL void
+deliver_by_pline(qt_msg)
+struct qtmsg *qt_msg;
+{
+       long    size;
+
+       for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) {
+           (void) dlb_fgets(in_line, 80, msg_file);
+           convert_line();
+           pline(out_line);
+       }
+
+}
+
+STATIC_OVL void
+deliver_by_window(qt_msg, how)
+struct qtmsg *qt_msg;
+int how;
+{
+       long    size;
+       winid datawin = create_nhwindow(how);
+
+       for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) {
+           (void) dlb_fgets(in_line, 80, msg_file);
+           convert_line();
+           putstr(datawin, 0, out_line);
+       }
+       display_nhwindow(datawin, TRUE);
+       destroy_nhwindow(datawin);
+}
+
+void
+com_pager(msgnum)
+int    msgnum;
+{
+       struct qtmsg *qt_msg;
+
+       if (!(qt_msg = msg_in(qt_list.common, msgnum))) {
+               impossible("com_pager: message %d not found.", msgnum);
+               return;
+       }
+
+       (void) dlb_fseek(msg_file, qt_msg->offset, SEEK_SET);
+       if (qt_msg->delivery == 'p') deliver_by_pline(qt_msg);
+       else if (msgnum == 1) deliver_by_window(qt_msg, NHW_MENU);
+       else                 deliver_by_window(qt_msg, NHW_TEXT);
+       return;
+}
+
+void
+qt_pager(msgnum)
+int    msgnum;
+{
+       struct qtmsg *qt_msg;
+
+       if (!(qt_msg = msg_in(qt_list.chrole, msgnum))) {
+               impossible("qt_pager: message %d not found.", msgnum);
+               return;
+       }
+
+       (void) dlb_fseek(msg_file, qt_msg->offset, SEEK_SET);
+       if (qt_msg->delivery == 'p' && strcmp(windowprocs.name, "X11"))
+               deliver_by_pline(qt_msg);
+       else    deliver_by_window(qt_msg, NHW_TEXT);
+       return;
+}
+
+struct permonst *
+qt_montype()
+{
+       int qpm;
+
+       if (rn2(5)) {
+           qpm = urole.enemy1num;
+           if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD))
+               return (&mons[qpm]);
+           return (mkclass(urole.enemy1sym, 0));
+       }
+       qpm = urole.enemy2num;
+       if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD))
+           return (&mons[qpm]);
+       return (mkclass(urole.enemy2sym, 0));
+}
+
+/*questpgr.c*/
diff --git a/src/read.c b/src/read.c
new file mode 100644 (file)
index 0000000..ab530f0
--- /dev/null
@@ -0,0 +1,1878 @@
+/*     SCCS Id: @(#)read.c     3.4     2003/10/22      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+/* KMH -- Copied from pray.c; this really belongs in a header file */
+#define DEVOUT 14
+#define STRIDENT 4
+
+#define Your_Own_Role(mndx) \
+       ((mndx) == urole.malenum || \
+        (urole.femalenum != NON_PM && (mndx) == urole.femalenum))
+#define Your_Own_Race(mndx) \
+       ((mndx) == urace.malenum || \
+        (urace.femalenum != NON_PM && (mndx) == urace.femalenum))
+
+#ifdef OVLB
+
+boolean        known;
+
+static NEARDATA const char readable[] =
+                  { ALL_CLASSES, SCROLL_CLASS, SPBOOK_CLASS, 0 };
+static const char all_count[] = { ALLOW_COUNT, ALL_CLASSES, 0 };
+
+static void FDECL(wand_explode, (struct obj *));
+static void NDECL(do_class_genocide);
+static void FDECL(stripspe,(struct obj *));
+static void FDECL(p_glow1,(struct obj *));
+static void FDECL(p_glow2,(struct obj *,const char *));
+static void FDECL(randomize,(int *, int));
+static void FDECL(forget_single_object, (int));
+static void FDECL(forget, (int));
+static void FDECL(maybe_tame, (struct monst *,struct obj *));
+
+STATIC_PTR void FDECL(set_lit, (int,int,genericptr_t));
+
+int
+doread()
+{
+       register struct obj *scroll;
+       register boolean confused;
+
+       known = FALSE;
+       if(check_capacity((char *)0)) return (0);
+       scroll = getobj(readable, "read");
+       if(!scroll) return(0);
+
+       /* outrumor has its own blindness check */
+       if(scroll->otyp == FORTUNE_COOKIE) {
+           if(flags.verbose)
+               You("break up the cookie and throw away the pieces.");
+           outrumor(bcsign(scroll), BY_COOKIE);
+           if (!Blind) u.uconduct.literate++;
+           useup(scroll);
+           return(1);
+#ifdef TOURIST
+       } else if (scroll->otyp == T_SHIRT) {
+           static const char *shirt_msgs[] = { /* Scott Bigham */
+    "I explored the Dungeons of Doom and all I got was this lousy T-shirt!",
+    "Is that Mjollnir in your pocket or are you just happy to see me?",
+    "It's not the size of your sword, it's how #enhance'd you are with it.",
+    "Madame Elvira's House O' Succubi Lifetime Customer",
+    "Madame Elvira's House O' Succubi Employee of the Month",
+    "Ludios Vault Guards Do It In Small, Dark Rooms",
+    "Yendor Military Soldiers Do It In Large Groups",
+    "I survived Yendor Military Boot Camp",
+    "Ludios Accounting School Intra-Mural Lacrosse Team",
+    "Oracle(TM) Fountains 10th Annual Wet T-Shirt Contest",
+    "Hey, black dragon!  Disintegrate THIS!",
+    "I'm With Stupid -->",
+    "Don't blame me, I voted for Izchak!",
+    "Don't Panic",                             /* HHGTTG */
+    "Furinkan High School Athletic Dept.",     /* Ranma 1/2 */
+    "Hel-LOOO, Nurse!",                        /* Animaniacs */
+           };
+           char buf[BUFSZ];
+           int erosion;
+
+           if (Blind) {
+               You_cant("feel any Braille writing.");
+               return 0;
+           }
+           u.uconduct.literate++;
+           if(flags.verbose)
+               pline("It reads:");
+           Strcpy(buf, shirt_msgs[scroll->o_id % SIZE(shirt_msgs)]);
+           erosion = greatest_erosion(scroll);
+           if (erosion)
+               wipeout_text(buf,
+                       (int)(strlen(buf) * erosion / (2*MAX_ERODE)),
+                            scroll->o_id ^ (unsigned)u.ubirthday);
+           pline("\"%s\"", buf);
+           return 1;
+#endif /* TOURIST */
+       } else if (scroll->oclass != SCROLL_CLASS
+               && scroll->oclass != SPBOOK_CLASS) {
+           pline(silly_thing_to, "read");
+           return(0);
+       } else if (Blind) {
+           const char *what = 0;
+           if (scroll->oclass == SPBOOK_CLASS)
+               what = "mystic runes";
+           else if (!scroll->dknown)
+               what = "formula on the scroll";
+           if (what) {
+               pline("Being blind, you cannot read the %s.", what);
+               return(0);
+           }
+       }
+
+       /* Actions required to win the game aren't counted towards conduct */
+       if (scroll->otyp != SPE_BOOK_OF_THE_DEAD &&
+               scroll->otyp != SPE_BLANK_PAPER &&
+               scroll->otyp != SCR_BLANK_PAPER)
+           u.uconduct.literate++;
+
+       confused = (Confusion != 0);
+#ifdef MAIL
+       if (scroll->otyp == SCR_MAIL) confused = FALSE;
+#endif
+       if(scroll->oclass == SPBOOK_CLASS) {
+           return(study_book(scroll));
+       }
+       scroll->in_use = TRUE;  /* scroll, not spellbook, now being read */
+       if(scroll->otyp != SCR_BLANK_PAPER) {
+         if(Blind)
+           pline("As you %s the formula on it, the scroll disappears.",
+                       is_silent(youmonst.data) ? "cogitate" : "pronounce");
+         else
+           pline("As you read the scroll, it disappears.");
+         if(confused) {
+           if (Hallucination)
+               pline("Being so trippy, you screw up...");
+           else
+               pline("Being confused, you mis%s the magic words...",
+                       is_silent(youmonst.data) ? "understand" : "pronounce");
+         }
+       }
+       if(!seffects(scroll))  {
+               if(!objects[scroll->otyp].oc_name_known) {
+                   if(known) {
+                       makeknown(scroll->otyp);
+                       more_experienced(0,10);
+                   } else if(!objects[scroll->otyp].oc_uname)
+                       docall(scroll);
+               }
+               if(scroll->otyp != SCR_BLANK_PAPER)
+                       useup(scroll);
+               else scroll->in_use = FALSE;
+       }
+       return(1);
+}
+
+static void
+stripspe(obj)
+register struct obj *obj;
+{
+       if (obj->blessed) pline(nothing_happens);
+       else {
+               if (obj->spe > 0) {
+                   obj->spe = 0;
+                   if (obj->otyp == OIL_LAMP || obj->otyp == BRASS_LANTERN)
+                       obj->age = 0;
+                   Your("%s %s briefly.",xname(obj), otense(obj, "vibrate"));
+               } else pline(nothing_happens);
+       }
+}
+
+static void
+p_glow1(otmp)
+register struct obj    *otmp;
+{
+       Your("%s %s briefly.", xname(otmp),
+            otense(otmp, Blind ? "vibrate" : "glow"));
+}
+
+static void
+p_glow2(otmp,color)
+register struct obj    *otmp;
+register const char *color;
+{
+       Your("%s %s%s%s for a moment.",
+               xname(otmp),
+               otense(otmp, Blind ? "vibrate" : "glow"),
+               Blind ? "" : " ",
+               Blind ? nul : hcolor(color));
+}
+
+/* Is the object chargeable?  For purposes of inventory display; it is */
+/* possible to be able to charge things for which this returns FALSE. */
+boolean
+is_chargeable(obj)
+struct obj *obj;
+{
+       if (obj->oclass == WAND_CLASS) return TRUE;
+       /* known && !uname is possible after amnesia/mind flayer */
+       if (obj->oclass == RING_CLASS)
+           return (boolean)(objects[obj->otyp].oc_charged &&
+                       (obj->known || objects[obj->otyp].oc_uname));
+       if (is_weptool(obj))    /* specific check before general tools */
+           return FALSE;
+       if (obj->oclass == TOOL_CLASS)
+           return (boolean)(objects[obj->otyp].oc_charged);
+       return FALSE; /* why are weapons/armor considered charged anyway? */
+}
+
+/*
+ * recharge an object; curse_bless is -1 if the recharging implement
+ * was cursed, +1 if blessed, 0 otherwise.
+ */
+void
+recharge(obj, curse_bless)
+struct obj *obj;
+int curse_bless;
+{
+       register int n;
+       boolean is_cursed, is_blessed;
+
+       is_cursed = curse_bless < 0;
+       is_blessed = curse_bless > 0;
+
+       if (obj->oclass == WAND_CLASS) {
+           /* undo any prior cancellation, even when is_cursed */
+           if (obj->spe == -1) obj->spe = 0;
+
+           /*
+            * Recharging might cause wands to explode.
+            *  v = number of previous recharges
+            *        v = percentage chance to explode on this attempt
+            *                v = cumulative odds for exploding
+            *  0 :   0       0
+            *  1 :   0.29    0.29
+            *  2 :   2.33    2.62
+            *  3 :   7.87   10.28
+            *  4 :  18.66   27.02
+            *  5 :  36.44   53.62
+            *  6 :  62.97   82.83
+            *  7 : 100     100
+            */
+           n = (int)obj->recharged;
+           if (n > 0 && (obj->otyp == WAN_WISHING ||
+                   (n * n * n > rn2(7*7*7)))) {        /* recharge_limit */
+               wand_explode(obj);
+               return;
+           }
+           /* didn't explode, so increment the recharge count */
+           obj->recharged = (unsigned)(n + 1);
+
+           /* now handle the actual recharging */
+           if (is_cursed) {
+               stripspe(obj);
+           } else {
+               int lim = (obj->otyp == WAN_WISHING) ? 3 :
+                       (objects[obj->otyp].oc_dir != NODIR) ? 8 : 15;
+
+               n = (lim == 3) ? 3 : rn1(5, lim + 1 - 5);
+               if (!is_blessed) n = rnd(n);
+
+               if (obj->spe < n) obj->spe = n;
+               else obj->spe++;
+               if (obj->otyp == WAN_WISHING && obj->spe > 3) {
+                   wand_explode(obj);
+                   return;
+               }
+               if (obj->spe >= lim) p_glow2(obj, NH_BLUE);
+               else p_glow1(obj);
+           }
+
+       } else if (obj->oclass == RING_CLASS &&
+                                       objects[obj->otyp].oc_charged) {
+           /* charging does not affect ring's curse/bless status */
+           int s = is_blessed ? rnd(3) : is_cursed ? -rnd(2) : 1;
+           boolean is_on = (obj == uleft || obj == uright);
+
+           /* destruction depends on current state, not adjustment */
+           if (obj->spe > rn2(7) || obj->spe <= -5) {
+               Your("%s %s momentarily, then %s!",
+                    xname(obj), otense(obj,"pulsate"), otense(obj,"explode"));
+               if (is_on) Ring_gone(obj);
+               s = rnd(3 * abs(obj->spe));     /* amount of damage */
+               useup(obj);
+               losehp(s, "exploding ring", KILLED_BY_AN);
+           } else {
+               long mask = is_on ? (obj == uleft ? LEFT_RING :
+                                    RIGHT_RING) : 0L;
+               Your("%s spins %sclockwise for a moment.",
+                    xname(obj), s < 0 ? "counter" : "");
+               /* cause attributes and/or properties to be updated */
+               if (is_on) Ring_off(obj);
+               obj->spe += s;  /* update the ring while it's off */
+               if (is_on) setworn(obj, mask), Ring_on(obj);
+               /* oartifact: if a touch-sensitive artifact ring is
+                  ever created the above will need to be revised  */
+           }
+
+       } else if (obj->oclass == TOOL_CLASS) {
+           int rechrg = (int)obj->recharged;
+
+           if (objects[obj->otyp].oc_charged) {
+               /* tools don't have a limit, but the counter used does */
+               if (rechrg < 7) /* recharge_limit */
+                   obj->recharged++;
+           }
+           switch(obj->otyp) {
+           case BELL_OF_OPENING:
+               if (is_cursed) stripspe(obj);
+               else if (is_blessed) obj->spe += rnd(3);
+               else obj->spe += 1;
+               if (obj->spe > 5) obj->spe = 5;
+               break;
+           case MAGIC_MARKER:
+           case TINNING_KIT:
+#ifdef TOURIST
+           case EXPENSIVE_CAMERA:
+#endif
+               if (is_cursed) stripspe(obj);
+               else if (rechrg && obj->otyp == MAGIC_MARKER) { /* previously recharged */
+                   obj->recharged = 1; /* override increment done above */
+                   if (obj->spe < 3)
+                       Your("marker seems permanently dried out.");
+                   else
+                       pline(nothing_happens);
+               } else if (is_blessed) {
+                   n = rn1(16,15);             /* 15..30 */
+                   if (obj->spe + n <= 50)
+                       obj->spe = 50;
+                   else if (obj->spe + n <= 75)
+                       obj->spe = 75;
+                   else {
+                       int chrg = (int)obj->spe;
+                       if ((chrg + n) > 127)
+                               obj->spe = 127;
+                       else
+                               obj->spe += n;
+                   }
+                   p_glow2(obj, NH_BLUE);
+               } else {
+                   n = rn1(11,10);             /* 10..20 */
+                   if (obj->spe + n <= 50)
+                       obj->spe = 50;
+                   else {
+                       int chrg = (int)obj->spe;
+                       if ((chrg + n) > 127)
+                               obj->spe = 127;
+                       else
+                               obj->spe += n;
+                   }
+                   p_glow2(obj, NH_WHITE);
+               }
+               break;
+           case OIL_LAMP:
+           case BRASS_LANTERN:
+               if (is_cursed) {
+                   stripspe(obj);
+                   if (obj->lamplit) {
+                       if (!Blind)
+                           pline("%s out!", Tobjnam(obj, "go"));
+                       end_burn(obj, TRUE);
+                   }
+               } else if (is_blessed) {
+                   obj->spe = 1;
+                   obj->age = 1500;
+                   p_glow2(obj, NH_BLUE);
+               } else {
+                   obj->spe = 1;
+                   obj->age += 750;
+                   if (obj->age > 1500) obj->age = 1500;
+                   p_glow1(obj);
+               }
+               break;
+           case CRYSTAL_BALL:
+               if (is_cursed) stripspe(obj);
+               else if (is_blessed) {
+                   obj->spe = 6;
+                   p_glow2(obj, NH_BLUE);
+               } else {
+                   if (obj->spe < 5) {
+                       obj->spe++;
+                       p_glow1(obj);
+                   } else pline(nothing_happens);
+               }
+               break;
+           case HORN_OF_PLENTY:
+           case BAG_OF_TRICKS:
+           case CAN_OF_GREASE:
+               if (is_cursed) stripspe(obj);
+               else if (is_blessed) {
+                   if (obj->spe <= 10)
+                       obj->spe += rn1(10, 6);
+                   else obj->spe += rn1(5, 6);
+                   if (obj->spe > 50) obj->spe = 50;
+                   p_glow2(obj, NH_BLUE);
+               } else {
+                   obj->spe += rnd(5);
+                   if (obj->spe > 50) obj->spe = 50;
+                   p_glow1(obj);
+               }
+               break;
+           case MAGIC_FLUTE:
+           case MAGIC_HARP:
+           case FROST_HORN:
+           case FIRE_HORN:
+           case DRUM_OF_EARTHQUAKE:
+               if (is_cursed) {
+                   stripspe(obj);
+               } else if (is_blessed) {
+                   obj->spe += d(2,4);
+                   if (obj->spe > 20) obj->spe = 20;
+                   p_glow2(obj, NH_BLUE);
+               } else {
+                   obj->spe += rnd(4);
+                   if (obj->spe > 20) obj->spe = 20;
+                   p_glow1(obj);
+               }
+               break;
+           default:
+               goto not_chargable;
+               /*NOTREACHED*/
+               break;
+           } /* switch */
+
+       } else {
+ not_chargable:
+           You("have a feeling of loss.");
+       }
+}
+
+
+/* Forget known information about this object class. */
+static void
+forget_single_object(obj_id)
+       int obj_id;
+{
+       objects[obj_id].oc_name_known = 0;
+       objects[obj_id].oc_pre_discovered = 0;  /* a discovery when relearned */
+       if (objects[obj_id].oc_uname) {
+           free((genericptr_t)objects[obj_id].oc_uname);
+           objects[obj_id].oc_uname = 0;
+       }
+       undiscover_object(obj_id);      /* after clearing oc_name_known */
+
+       /* clear & free object names from matching inventory items too? */
+}
+
+
+#if 0  /* here if anyone wants it.... */
+/* Forget everything known about a particular object class. */
+static void
+forget_objclass(oclass)
+       int oclass;
+{
+       int i;
+
+       for (i=bases[oclass];
+               i < NUM_OBJECTS && objects[i].oc_class==oclass; i++)
+           forget_single_object(i);
+}
+#endif
+
+
+/* randomize the given list of numbers  0 <= i < count */
+static void
+randomize(indices, count)
+       int *indices;
+       int count;
+{
+       int i, iswap, temp;
+
+       for (i = count - 1; i > 0; i--) {
+           if ((iswap = rn2(i + 1)) == i) continue;
+           temp = indices[i];
+           indices[i] = indices[iswap];
+           indices[iswap] = temp;
+       }
+}
+
+
+/* Forget % of known objects. */
+void
+forget_objects(percent)
+       int percent;
+{
+       int i, count;
+       int indices[NUM_OBJECTS];
+
+       if (percent == 0) return;
+       if (percent <= 0 || percent > 100) {
+           impossible("forget_objects: bad percent %d", percent);
+           return;
+       }
+
+       for (count = 0, i = 1; i < NUM_OBJECTS; i++)
+           if (OBJ_DESCR(objects[i]) &&
+                   (objects[i].oc_name_known || objects[i].oc_uname))
+               indices[count++] = i;
+
+       randomize(indices, count);
+
+       /* forget first % of randomized indices */
+       count = ((count * percent) + 50) / 100;
+       for (i = 0; i < count; i++)
+           forget_single_object(indices[i]);
+}
+
+
+/* Forget some or all of map (depends on parameters). */
+void
+forget_map(howmuch)
+       int howmuch;
+{
+       register int zx, zy;
+
+       if (In_sokoban(&u.uz))
+           return;
+
+       known = TRUE;
+       for(zx = 0; zx < COLNO; zx++) for(zy = 0; zy < ROWNO; zy++)
+           if (howmuch & ALL_MAP || rn2(7)) {
+               /* Zonk all memory of this location. */
+               levl[zx][zy].seenv = 0;
+               levl[zx][zy].waslit = 0;
+               levl[zx][zy].glyph = cmap_to_glyph(S_stone);
+           }
+}
+
+/* Forget all traps on the level. */
+void
+forget_traps()
+{
+       register struct trap *trap;
+
+       /* forget all traps (except the one the hero is in :-) */
+       for (trap = ftrap; trap; trap = trap->ntrap)
+           if ((trap->tx != u.ux || trap->ty != u.uy) && (trap->ttyp != HOLE))
+               trap->tseen = 0;
+}
+
+/*
+ * Forget given % of all levels that the hero has visited and not forgotten,
+ * except this one.
+ */
+void
+forget_levels(percent)
+       int percent;
+{
+       int i, count;
+       xchar  maxl, this_lev;
+       int indices[MAXLINFO];
+
+       if (percent == 0) return;
+
+       if (percent <= 0 || percent > 100) {
+           impossible("forget_levels: bad percent %d", percent);
+           return;
+       }
+
+       this_lev = ledger_no(&u.uz);
+       maxl = maxledgerno();
+
+       /* count & save indices of non-forgotten visited levels */
+       /* Sokoban levels are pre-mapped for the player, and should stay
+        * so, or they become nearly impossible to solve.  But try to
+        * shift the forgetting elsewhere by fiddling with percent
+        * instead of forgetting fewer levels.
+        */
+       for (count = 0, i = 0; i <= maxl; i++)
+           if ((level_info[i].flags & VISITED) &&
+                       !(level_info[i].flags & FORGOTTEN) && i != this_lev) {
+               if (ledger_to_dnum(i) == sokoban_dnum)
+                   percent += 2;
+               else
+                   indices[count++] = i;
+           }
+       
+       if (percent > 100) percent = 100;
+
+       randomize(indices, count);
+
+       /* forget first % of randomized indices */
+       count = ((count * percent) + 50) / 100;
+       for (i = 0; i < count; i++) {
+           level_info[indices[i]].flags |= FORGOTTEN;
+       }
+}
+
+/*
+ * Forget some things (e.g. after reading a scroll of amnesia).  When called,
+ * the following are always forgotten:
+ *
+ *     - felt ball & chain
+ *     - traps
+ *     - part (6 out of 7) of the map
+ *
+ * Other things are subject to flags:
+ *
+ *     howmuch & ALL_MAP       = forget whole map
+ *     howmuch & ALL_SPELLS    = forget all spells
+ */
+static void
+forget(howmuch)
+int howmuch;
+{
+
+       if (Punished) u.bc_felt = 0;    /* forget felt ball&chain */
+
+       forget_map(howmuch);
+       forget_traps();
+
+       /* 1 in 3 chance of forgetting some levels */
+       if (!rn2(3)) forget_levels(rn2(25));
+
+       /* 1 in 3 chance of forgeting some objects */
+       if (!rn2(3)) forget_objects(rn2(25));
+
+       if (howmuch & ALL_SPELLS) losespells();
+       /*
+        * Make sure that what was seen is restored correctly.  To do this,
+        * we need to go blind for an instant --- turn off the display,
+        * then restart it.  All this work is needed to correctly handle
+        * walls which are stone on one side and wall on the other.  Turning
+        * off the seen bits above will make the wall revert to stone,  but
+        * there are cases where we don't want this to happen.  The easiest
+        * thing to do is to run it through the vision system again, which
+        * is always correct.
+        */
+       docrt();                /* this correctly will reset vision */
+}
+
+/* monster is hit by scroll of taming's effect */
+static void
+maybe_tame(mtmp, sobj)
+struct monst *mtmp;
+struct obj *sobj;
+{
+       if (sobj->cursed) {
+           setmangry(mtmp);
+       } else {
+           if (mtmp->isshk)
+               make_happy_shk(mtmp, FALSE);
+           else if (!resist(mtmp, sobj->oclass, 0, NOTELL))
+               (void) tamedog(mtmp, (struct obj *) 0);
+       }
+}
+
+int
+seffects(sobj)
+register struct obj    *sobj;
+{
+       register int cval;
+       register boolean confused = (Confusion != 0);
+       register struct obj *otmp;
+
+       if (objects[sobj->otyp].oc_magic)
+               exercise(A_WIS, TRUE);          /* just for trying */
+       switch(sobj->otyp) {
+#ifdef MAIL
+       case SCR_MAIL:
+               known = TRUE;
+               if (sobj->spe)
+                   pline("This seems to be junk mail addressed to the finder of the Eye of Larn.");
+               /* note to the puzzled: the game Larn actually sends you junk
+                * mail if you win!
+                */
+               else readmail(sobj);
+               break;
+#endif
+       case SCR_ENCHANT_ARMOR:
+           {
+               register schar s;
+               boolean special_armor;
+               boolean same_color;
+
+               otmp = some_armor(&youmonst);
+               if(!otmp) {
+                       strange_feeling(sobj,
+                                       !Blind ? "Your skin glows then fades." :
+                                       "Your skin feels warm for a moment.");
+                       exercise(A_CON, !sobj->cursed);
+                       exercise(A_STR, !sobj->cursed);
+                       return(1);
+               }
+               if(confused) {
+                       otmp->oerodeproof = !(sobj->cursed);
+                       if(Blind) {
+                           otmp->rknown = FALSE;
+                           Your("%s %s warm for a moment.",
+                               xname(otmp), otense(otmp, "feel"));
+                       } else {
+                           otmp->rknown = TRUE;
+                           Your("%s %s covered by a %s %s %s!",
+                               xname(otmp), otense(otmp, "are"),
+                               sobj->cursed ? "mottled" : "shimmering",
+                                hcolor(sobj->cursed ? NH_BLACK : NH_GOLDEN),
+                               sobj->cursed ? "glow" :
+                                 (is_shield(otmp) ? "layer" : "shield"));
+                       }
+                       if (otmp->oerodeproof &&
+                           (otmp->oeroded || otmp->oeroded2)) {
+                           otmp->oeroded = otmp->oeroded2 = 0;
+                           Your("%s %s as good as new!",
+                                xname(otmp),
+                                otense(otmp, Blind ? "feel" : "look"));
+                       }
+                       break;
+               }
+               /* elven armor vibrates warningly when enchanted beyond a limit */
+               special_armor = is_elven_armor(otmp) ||
+                       (Role_if(PM_WIZARD) && otmp->otyp == CORNUTHAUM);
+               if (sobj->cursed)
+                   same_color =
+                       (otmp->otyp == BLACK_DRAGON_SCALE_MAIL ||
+                        otmp->otyp == BLACK_DRAGON_SCALES);
+               else
+                   same_color =
+                       (otmp->otyp == SILVER_DRAGON_SCALE_MAIL ||
+                        otmp->otyp == SILVER_DRAGON_SCALES ||
+                        otmp->otyp == SHIELD_OF_REFLECTION);
+               if (Blind) same_color = FALSE;
+
+               /* KMH -- catch underflow */
+               s = sobj->cursed ? -otmp->spe : otmp->spe;
+               if (s > (special_armor ? 5 : 3) && rn2(s)) {
+               Your("%s violently %s%s%s for a while, then %s.",
+                    xname(otmp),
+                    otense(otmp, Blind ? "vibrate" : "glow"),
+                    (!Blind && !same_color) ? " " : nul,
+                    (Blind || same_color) ? nul :
+                       hcolor(sobj->cursed ? NH_BLACK : NH_SILVER),
+                    otense(otmp, "evaporate"));
+                       if(is_cloak(otmp)) (void) Cloak_off();
+                       if(is_boots(otmp)) (void) Boots_off();
+                       if(is_helmet(otmp)) (void) Helmet_off();
+                       if(is_gloves(otmp)) (void) Gloves_off();
+                       if(is_shield(otmp)) (void) Shield_off();
+                       if(otmp == uarm) (void) Armor_gone();
+                       useup(otmp);
+                       break;
+               }
+               s = sobj->cursed ? -1 :
+                   otmp->spe >= 9 ? (rn2(otmp->spe) == 0) :
+                   sobj->blessed ? rnd(3-otmp->spe/3) : 1;
+               if (s >= 0 && otmp->otyp >= GRAY_DRAGON_SCALES &&
+                                       otmp->otyp <= YELLOW_DRAGON_SCALES) {
+                       /* dragon scales get turned into dragon scale mail */
+                       Your("%s merges and hardens!", xname(otmp));
+                       setworn((struct obj *)0, W_ARM);
+                       /* assumes same order */
+                       otmp->otyp = GRAY_DRAGON_SCALE_MAIL +
+                                               otmp->otyp - GRAY_DRAGON_SCALES;
+                       otmp->cursed = 0;
+                       if (sobj->blessed) {
+                               otmp->spe++;
+                               otmp->blessed = 1;
+                       }
+                       otmp->known = 1;
+                       setworn(otmp, W_ARM);
+                       break;
+               }
+               Your("%s %s%s%s%s for a %s.",
+                       xname(otmp),
+                       s == 0 ? "violently " : nul,
+                       otense(otmp, Blind ? "vibrate" : "glow"),
+                       (!Blind && !same_color) ? " " : nul,
+                       (Blind || same_color) ? nul : hcolor(sobj->cursed ? NH_BLACK : NH_SILVER),
+                         (s*s>1) ? "while" : "moment");
+               otmp->cursed = sobj->cursed;
+               if (!otmp->blessed || sobj->cursed)
+                       otmp->blessed = sobj->blessed;
+               if (s) {
+                       otmp->spe += s;
+                       adj_abon(otmp, s);
+                       known = otmp->known;
+               }
+
+               if ((otmp->spe > (special_armor ? 5 : 3)) &&
+                   (special_armor || !rn2(7)))
+                       Your("%s suddenly %s %s.",
+                               xname(otmp), otense(otmp, "vibrate"),
+                               Blind ? "again" : "unexpectedly");
+               break;
+           }
+       case SCR_DESTROY_ARMOR:
+           {
+               otmp = some_armor(&youmonst);
+               if(confused) {
+                       if(!otmp) {
+                               strange_feeling(sobj,"Your bones itch.");
+                               exercise(A_STR, FALSE);
+                               exercise(A_CON, FALSE);
+                               return(1);
+                       }
+                       otmp->oerodeproof = sobj->cursed;
+                       p_glow2(otmp, NH_PURPLE);
+                       break;
+               }
+               if(!sobj->cursed || !otmp || !otmp->cursed) {
+                   if(!destroy_arm(otmp)) {
+                       strange_feeling(sobj,"Your skin itches.");
+                       exercise(A_STR, FALSE);
+                       exercise(A_CON, FALSE);
+                       return(1);
+                   } else
+                       known = TRUE;
+               } else {        /* armor and scroll both cursed */
+                   Your("%s %s.", xname(otmp), otense(otmp, "vibrate"));
+                   if (otmp->spe >= -6) otmp->spe--;
+                   make_stunned(HStun + rn1(10, 10), TRUE);
+               }
+           }
+           break;
+       case SCR_CONFUSE_MONSTER:
+       case SPE_CONFUSE_MONSTER:
+               if(youmonst.data->mlet != S_HUMAN || sobj->cursed) {
+                       if(!HConfusion) You_feel("confused.");
+                       make_confused(HConfusion + rnd(100),FALSE);
+               } else  if(confused) {
+                   if(!sobj->blessed) {
+                       Your("%s begin to %s%s.",
+                           makeplural(body_part(HAND)),
+                           Blind ? "tingle" : "glow ",
+                           Blind ? nul : hcolor(NH_PURPLE));
+                       make_confused(HConfusion + rnd(100),FALSE);
+                   } else {
+                       pline("A %s%s surrounds your %s.",
+                           Blind ? nul : hcolor(NH_RED),
+                           Blind ? "faint buzz" : " glow",
+                           body_part(HEAD));
+                       make_confused(0L,TRUE);
+                   }
+               } else {
+                   if (!sobj->blessed) {
+                       Your("%s%s %s%s.",
+                       makeplural(body_part(HAND)),
+                       Blind ? "" : " begin to glow",
+                       Blind ? (const char *)"tingle" : hcolor(NH_RED),
+                       u.umconf ? " even more" : "");
+                       u.umconf++;
+                   } else {
+                       if (Blind)
+                           Your("%s tingle %s sharply.",
+                               makeplural(body_part(HAND)),
+                               u.umconf ? "even more" : "very");
+                       else
+                           Your("%s glow a%s brilliant %s.",
+                               makeplural(body_part(HAND)),
+                               u.umconf ? "n even more" : "",
+                               hcolor(NH_RED));
+                       /* after a while, repeated uses become less effective */
+                       if (u.umconf >= 40)
+                           u.umconf++;
+                       else
+                           u.umconf += rn1(8, 2);
+                   }
+               }
+               break;
+       case SCR_SCARE_MONSTER:
+       case SPE_CAUSE_FEAR:
+           {   register int ct = 0;
+               register struct monst *mtmp;
+
+               for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+                   if (DEADMONSTER(mtmp)) continue;
+                   if(cansee(mtmp->mx,mtmp->my)) {
+                       if(confused || sobj->cursed) {
+                           mtmp->mflee = mtmp->mfrozen = mtmp->msleeping = 0;
+                           mtmp->mcanmove = 1;
+                       } else
+                           if (! resist(mtmp, sobj->oclass, 0, NOTELL))
+                               monflee(mtmp, 0, FALSE, FALSE);
+                       if(!mtmp->mtame) ct++;  /* pets don't laugh at you */
+                   }
+               }
+               if(!ct)
+                     You_hear("%s in the distance.",
+                              (confused || sobj->cursed) ? "sad wailing" :
+                                                       "maniacal laughter");
+               else if(sobj->otyp == SCR_SCARE_MONSTER)
+                       You_hear("%s close by.",
+                                 (confused || sobj->cursed) ? "sad wailing" :
+                                                "maniacal laughter");
+               break;
+           }
+       case SCR_BLANK_PAPER:
+           if (Blind)
+               You("don't remember there being any magic words on this scroll.");
+           else
+               pline("This scroll seems to be blank.");
+           known = TRUE;
+           break;
+       case SCR_REMOVE_CURSE:
+       case SPE_REMOVE_CURSE:
+           {   register struct obj *obj;
+               if(confused)
+                   if (Hallucination)
+                       You_feel("the power of the Force against you!");
+                   else
+                       You_feel("like you need some help.");
+               else
+                   if (Hallucination)
+                       You_feel("in touch with the Universal Oneness.");
+                   else
+                       You_feel("like someone is helping you.");
+
+               if (sobj->cursed) {
+                   pline_The("scroll disintegrates.");
+               } else {
+                   for (obj = invent; obj; obj = obj->nobj) {
+                       long wornmask;
+#ifdef GOLDOBJ
+                       /* gold isn't subject to cursing and blessing */
+                       if (obj->oclass == COIN_CLASS) continue;
+#endif
+                       wornmask = (obj->owornmask & ~(W_BALL|W_ART|W_ARTI));
+                       if (wornmask && !sobj->blessed) {
+                           /* handle a couple of special cases; we don't
+                              allow auxiliary weapon slots to be used to
+                              artificially increase number of worn items */
+                           if (obj == uswapwep) {
+                               if (!u.twoweap) wornmask = 0L;
+                           } else if (obj == uquiver) {
+                               if (obj->oclass == WEAPON_CLASS) {
+                                   /* mergeable weapon test covers ammo,
+                                      missiles, spears, daggers & knives */
+                                   if (!objects[obj->otyp].oc_merge) 
+                                       wornmask = 0L;
+                               } else if (obj->oclass == GEM_CLASS) {
+                                   /* possibly ought to check whether
+                                      alternate weapon is a sling... */
+                                   if (!uslinging()) wornmask = 0L;
+                               } else {
+                                   /* weptools don't merge and aren't
+                                      reasonable quivered weapons */
+                                   wornmask = 0L;
+                               }
+                           }
+                       }
+                       if (sobj->blessed || wornmask ||
+                            obj->otyp == LOADSTONE ||
+                            (obj->otyp == LEASH && obj->leashmon)) {
+                           if(confused) blessorcurse(obj, 2);
+                           else uncurse(obj);
+                       }
+                   }
+               }
+               if(Punished && !confused) unpunish();
+               update_inventory();
+               break;
+           }
+       case SCR_CREATE_MONSTER:
+       case SPE_CREATE_MONSTER:
+           if (create_critters(1 + ((confused || sobj->cursed) ? 12 : 0) +
+                               ((sobj->blessed || rn2(73)) ? 0 : rnd(4)),
+                       confused ? &mons[PM_ACID_BLOB] : (struct permonst *)0))
+               known = TRUE;
+           /* no need to flush monsters; we ask for identification only if the
+            * monsters are not visible
+            */
+           break;
+       case SCR_ENCHANT_WEAPON:
+               if(uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))
+                       && confused) {
+               /* oclass check added 10/25/86 GAN */
+                       uwep->oerodeproof = !(sobj->cursed);
+                       if (Blind) {
+                           uwep->rknown = FALSE;
+                           Your("weapon feels warm for a moment.");
+                       } else {
+                           uwep->rknown = TRUE;
+                           Your("%s covered by a %s %s %s!",
+                               aobjnam(uwep, "are"),
+                               sobj->cursed ? "mottled" : "shimmering",
+                               hcolor(sobj->cursed ? NH_PURPLE : NH_GOLDEN),
+                               sobj->cursed ? "glow" : "shield");
+                       }
+                       if (uwep->oerodeproof && (uwep->oeroded || uwep->oeroded2)) {
+                           uwep->oeroded = uwep->oeroded2 = 0;
+                           Your("%s as good as new!",
+                                aobjnam(uwep, Blind ? "feel" : "look"));
+                       }
+               } else return !chwepon(sobj,
+                                      sobj->cursed ? -1 :
+                                      !uwep ? 1 :
+                                      uwep->spe >= 9 ? (rn2(uwep->spe) == 0) :
+                                      sobj->blessed ? rnd(3-uwep->spe/3) : 1);
+               break;
+       case SCR_TAMING:
+       case SPE_CHARM_MONSTER:
+               if (u.uswallow) {
+                   maybe_tame(u.ustuck, sobj);
+               } else {
+                   int i, j, bd = confused ? 5 : 1;
+                   struct monst *mtmp;
+
+                   for (i = -bd; i <= bd; i++) for(j = -bd; j <= bd; j++) {
+                       if (!isok(u.ux + i, u.uy + j)) continue;
+                       if ((mtmp = m_at(u.ux + i, u.uy + j)) != 0)
+                           maybe_tame(mtmp, sobj);
+                   }
+               }
+               break;
+       case SCR_GENOCIDE:
+               You("have found a scroll of genocide!");
+               known = TRUE;
+               if (sobj->blessed) do_class_genocide();
+               else do_genocide(!sobj->cursed | (2 * !!Confusion));
+               break;
+       case SCR_LIGHT:
+               if(!Blind) known = TRUE;
+               litroom(!confused && !sobj->cursed, sobj);
+               break;
+       case SCR_TELEPORTATION:
+               if(confused || sobj->cursed) level_tele();
+               else {
+                       if (sobj->blessed && !Teleport_control) {
+                               known = TRUE;
+                               if (yn("Do you wish to teleport?")=='n')
+                                       break;
+                       }
+                       tele();
+                       if(Teleport_control || !couldsee(u.ux0, u.uy0) ||
+                          (distu(u.ux0, u.uy0) >= 16))
+                               known = TRUE;
+               }
+               break;
+       case SCR_GOLD_DETECTION:
+               if (confused || sobj->cursed) return(trap_detect(sobj));
+               else return(gold_detect(sobj));
+       case SCR_FOOD_DETECTION:
+       case SPE_DETECT_FOOD:
+               if (food_detect(sobj))
+                       return(1);      /* nothing detected */
+               break;
+       case SPE_IDENTIFY:
+               cval = rn2(5);
+               goto id;
+       case SCR_IDENTIFY:
+               /* known = TRUE; */
+               if(confused)
+                       You("identify this as an identify scroll.");
+               else
+                       pline("This is an identify scroll.");
+               if (sobj->blessed || (!sobj->cursed && !rn2(5))) {
+                       cval = rn2(5);
+                       /* Note: if rn2(5)==0, identify all items */
+                       if (cval == 1 && sobj->blessed && Luck > 0) ++cval;
+               } else  cval = 1;
+               if(!objects[sobj->otyp].oc_name_known) more_experienced(0,10);
+               useup(sobj);
+               makeknown(SCR_IDENTIFY);
+       id:
+               if(invent && !confused) {
+                   identify_pack(cval);
+               }
+               return(1);
+       case SCR_CHARGING:
+               if (confused) {
+                   You_feel("charged up!");
+                   if (u.uen < u.uenmax)
+                       u.uen = u.uenmax;
+                   else
+                       u.uen = (u.uenmax += d(5,4));
+                   flags.botl = 1;
+                   break;
+               }
+               known = TRUE;
+               pline("This is a charging scroll.");
+               otmp = getobj(all_count, "charge");
+               if (!otmp) break;
+               recharge(otmp, sobj->cursed ? -1 : (sobj->blessed ? 1 : 0));
+               break;
+       case SCR_MAGIC_MAPPING:
+               if (level.flags.nommap) {
+                   Your("mind is filled with crazy lines!");
+                   if (Hallucination)
+                       pline("Wow!  Modern art.");
+                   else
+                       Your("%s spins in bewilderment.", body_part(HEAD));
+                   make_confused(HConfusion + rnd(30), FALSE);
+                   break;
+               }
+               if (sobj->blessed) {
+                   register int x, y;
+
+                   for (x = 1; x < COLNO; x++)
+                       for (y = 0; y < ROWNO; y++)
+                           if (levl[x][y].typ == SDOOR)
+                               cvt_sdoor_to_door(&levl[x][y]);
+                   /* do_mapping() already reveals secret passages */
+               }
+               known = TRUE;
+       case SPE_MAGIC_MAPPING:
+               if (level.flags.nommap) {
+                   Your("%s spins as %s blocks the spell!", body_part(HEAD), something);
+                   make_confused(HConfusion + rnd(30), FALSE);
+                   break;
+               }
+               pline("A map coalesces in your mind!");
+               cval = (sobj->cursed && !confused);
+               if(cval) HConfusion = 1;        /* to screw up map */
+               do_mapping();
+               if(cval) {
+                   HConfusion = 0;             /* restore */
+                   pline("Unfortunately, you can't grasp the details.");
+               }
+               break;
+       case SCR_AMNESIA:
+               known = TRUE;
+               forget( (!sobj->blessed ? ALL_SPELLS : 0) |
+                       (!confused || sobj->cursed ? ALL_MAP : 0) );
+               if (Hallucination) /* Ommmmmm! */
+                       Your("mind releases itself from mundane concerns.");
+               else if (!strncmpi(plname, "Maud", 4))
+                       pline("As your mind turns inward on itself, you forget everything else.");
+               else if (rn2(2))
+                       pline("Who was that Maud person anyway?");
+               else
+                       pline("Thinking of Maud you forget everything else.");
+               exercise(A_WIS, FALSE);
+               break;
+       case SCR_FIRE:
+               /*
+                * Note: Modifications have been made as of 3.0 to allow for
+                * some damage under all potential cases.
+                */
+               cval = bcsign(sobj);
+               if(!objects[sobj->otyp].oc_name_known) more_experienced(0,10);
+               useup(sobj);
+               makeknown(SCR_FIRE);
+               if(confused) {
+                   if(Fire_resistance) {
+                       shieldeff(u.ux, u.uy);
+                       if(!Blind)
+                           pline("Oh, look, what a pretty fire in your %s.",
+                               makeplural(body_part(HAND)));
+                       else You_feel("a pleasant warmth in your %s.",
+                               makeplural(body_part(HAND)));
+                   } else {
+                       pline_The("scroll catches fire and you burn your %s.",
+                               makeplural(body_part(HAND)));
+                       losehp(1, "scroll of fire", KILLED_BY_AN);
+                   }
+                   return(1);
+               }
+               if (Underwater)
+                       pline_The("water around you vaporizes violently!");
+               else {
+                   pline_The("scroll erupts in a tower of flame!");
+                   burn_away_slime();
+               }
+               explode(u.ux, u.uy, 11, (2*(rn1(3, 3) + 2 * cval) + 1)/3,
+                                                       SCROLL_CLASS, EXPL_FIERY);
+               return(1);
+       case SCR_EARTH:
+           /* TODO: handle steeds */
+           if (
+#ifdef REINCARNATION
+               !Is_rogue_level(&u.uz) && 
+#endif
+                (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) {
+               register int x, y;
+
+               /* Identify the scroll */
+               pline_The("%s rumbles %s you!", ceiling(u.ux,u.uy),
+                               sobj->blessed ? "around" : "above");
+               known = 1;
+               if (In_sokoban(&u.uz))
+                   change_luck(-1);    /* Sokoban guilt */
+
+               /* Loop through the surrounding squares */
+               if (!sobj->cursed) for (x = u.ux-1; x <= u.ux+1; x++) {
+                   for (y = u.uy-1; y <= u.uy+1; y++) {
+
+                       /* Is this a suitable spot? */
+                       if (isok(x, y) && !closed_door(x, y) &&
+                                       !IS_ROCK(levl[x][y].typ) &&
+                                       !IS_AIR(levl[x][y].typ) &&
+                                       (x != u.ux || y != u.uy)) {
+                           register struct obj *otmp2;
+                           register struct monst *mtmp;
+
+                           /* Make the object(s) */
+                           otmp2 = mksobj(confused ? ROCK : BOULDER,
+                                       FALSE, FALSE);
+                           if (!otmp2) continue;  /* Shouldn't happen */
+                           otmp2->quan = confused ? rn1(5,2) : 1;
+                           otmp2->owt = weight(otmp2);
+
+                           /* Find the monster here (won't be player) */
+                           mtmp = m_at(x, y);
+                           if (mtmp && !amorphous(mtmp->data) &&
+                                       !passes_walls(mtmp->data) &&
+                                       !noncorporeal(mtmp->data) &&
+                                       !unsolid(mtmp->data)) {
+                               struct obj *helmet = which_armor(mtmp, W_ARMH);
+                               int mdmg;
+
+                               if (cansee(mtmp->mx, mtmp->my)) {
+                                   pline("%s is hit by %s!", Monnam(mtmp),
+                                               doname(otmp2));
+                                   if (mtmp->minvis && !canspotmon(mtmp))
+                                       map_invisible(mtmp->mx, mtmp->my);
+                               }
+                               mdmg = dmgval(otmp2, mtmp) * otmp2->quan;
+                               if (helmet) {
+                                   if(is_metallic(helmet)) {
+                                       if (canspotmon(mtmp))
+                                           pline("Fortunately, %s is wearing a hard helmet.", mon_nam(mtmp));
+                                       else if (flags.soundok)
+                                           You_hear("a clanging sound.");
+                                       if (mdmg > 2) mdmg = 2;
+                                   } else {
+                                       if (canspotmon(mtmp))
+                                           pline("%s's %s does not protect %s.",
+                                               Monnam(mtmp), xname(helmet),
+                                               mhim(mtmp));
+                                   }
+                               }
+                               mtmp->mhp -= mdmg;
+                               if (mtmp->mhp <= 0)
+                                   xkilled(mtmp, 1);
+                           }
+                           /* Drop the rock/boulder to the floor */
+                           if (!flooreffects(otmp2, x, y, "fall")) {
+                               place_object(otmp2, x, y);
+                               stackobj(otmp2);
+                               newsym(x, y);  /* map the rock */
+                           }
+                       }
+                   }
+               }
+               /* Attack the player */
+               if (!sobj->blessed) {
+                   int dmg;
+                   struct obj *otmp2;
+
+                   /* Okay, _you_ write this without repeating the code */
+                   otmp2 = mksobj(confused ? ROCK : BOULDER,
+                               FALSE, FALSE);
+                   if (!otmp2) break;
+                   otmp2->quan = confused ? rn1(5,2) : 1;
+                   otmp2->owt = weight(otmp2);
+                   if (!amorphous(youmonst.data) &&
+                               !Passes_walls &&
+                               !noncorporeal(youmonst.data) &&
+                               !unsolid(youmonst.data)) {
+                       You("are hit by %s!", doname(otmp2));
+                       dmg = dmgval(otmp2, &youmonst) * otmp2->quan;
+                       if (uarmh && !sobj->cursed) {
+                           if(is_metallic(uarmh)) {
+                               pline("Fortunately, you are wearing a hard helmet.");
+                               if (dmg > 2) dmg = 2;
+                           } else if (flags.verbose) {
+                               Your("%s does not protect you.",
+                                               xname(uarmh));
+                           }
+                       }
+                   } else
+                       dmg = 0;
+                   /* Must be before the losehp(), for bones files */
+                   if (!flooreffects(otmp2, u.ux, u.uy, "fall")) {
+                       place_object(otmp2, u.ux, u.uy);
+                       stackobj(otmp2);
+                       newsym(u.ux, u.uy);
+                   }
+                   if (dmg) losehp(dmg, "scroll of earth", KILLED_BY_AN);
+               }
+           }
+           break;
+       case SCR_PUNISHMENT:
+               known = TRUE;
+               if(confused || sobj->blessed) {
+                       You_feel("guilty.");
+                       break;
+               }
+               punish(sobj);
+               break;
+       case SCR_STINKING_CLOUD: {
+               coord cc;
+
+               You("have found a scroll of stinking cloud!");
+               known = TRUE;
+               pline("Where do you want to center the cloud?");
+               cc.x = u.ux;
+               cc.y = u.uy;
+               if (getpos(&cc, TRUE, "the desired position") < 0) {
+                   pline(Never_mind);
+                   return 0;
+               }
+               if (!cansee(cc.x, cc.y) || distu(cc.x, cc.y) >= 32) {
+                   You("smell rotten eggs.");
+                   return 0;
+               }
+               (void) create_gas_cloud(cc.x, cc.y, 3+bcsign(sobj),
+                                               8+4*bcsign(sobj));
+               break;
+       }
+       default:
+               impossible("What weird effect is this? (%u)", sobj->otyp);
+       }
+       return(0);
+}
+
+static void
+wand_explode(obj)
+register struct obj *obj;
+{
+    obj->in_use = TRUE;        /* in case losehp() is fatal */
+    Your("%s vibrates violently, and explodes!",xname(obj));
+    nhbell();
+    losehp(rnd(2*(u.uhpmax+1)/3), "exploding wand", KILLED_BY_AN);
+    useup(obj);
+    exercise(A_STR, FALSE);
+}
+
+/*
+ * Low-level lit-field update routine.
+ */
+STATIC_PTR void
+set_lit(x,y,val)
+int x, y;
+genericptr_t val;
+{
+       if (val)
+           levl[x][y].lit = 1;
+       else {
+           levl[x][y].lit = 0;
+           snuff_light_source(x, y);
+       }
+}
+
+void
+litroom(on,obj)
+register boolean on;
+struct obj *obj;
+{
+       char is_lit;    /* value is irrelevant; we use its address
+                          as a `not null' flag for set_lit() */
+
+       /* first produce the text (provided you're not blind) */
+       if(!on) {
+               register struct obj *otmp;
+
+               if (!Blind) {
+                   if(u.uswallow) {
+                       pline("It seems even darker in here than before.");
+                       return;
+                   }
+                   if (uwep && artifact_light(uwep) && uwep->lamplit)
+                       pline("Suddenly, the only light left comes from %s!",
+                               the(xname(uwep)));
+                   else
+                       You("are surrounded by darkness!");
+               }
+
+               /* the magic douses lamps, et al, too */
+               for(otmp = invent; otmp; otmp = otmp->nobj)
+                   if (otmp->lamplit)
+                       (void) snuff_lit(otmp);
+               if (Blind) goto do_it;
+       } else {
+               if (Blind) goto do_it;
+               if(u.uswallow){
+                       if (is_animal(u.ustuck->data))
+                               pline("%s %s is lit.",
+                                       s_suffix(Monnam(u.ustuck)),
+                                       mbodypart(u.ustuck, STOMACH));
+                       else
+                               if (is_whirly(u.ustuck->data))
+                                       pline("%s shines briefly.",
+                                             Monnam(u.ustuck));
+                               else
+                                       pline("%s glistens.", Monnam(u.ustuck));
+                       return;
+               }
+               pline("A lit field surrounds you!");
+       }
+
+do_it:
+       /* No-op in water - can only see the adjacent squares and that's it! */
+       if (Underwater || Is_waterlevel(&u.uz)) return;
+       /*
+        *  If we are darkening the room and the hero is punished but not
+        *  blind, then we have to pick up and replace the ball and chain so
+        *  that we don't remember them if they are out of sight.
+        */
+       if (Punished && !on && !Blind)
+           move_bc(1, 0, uball->ox, uball->oy, uchain->ox, uchain->oy);
+
+#ifdef REINCARNATION
+       if (Is_rogue_level(&u.uz)) {
+           /* Can't use do_clear_area because MAX_RADIUS is too small */
+           /* rogue lighting must light the entire room */
+           int rnum = levl[u.ux][u.uy].roomno - ROOMOFFSET;
+           int rx, ry;
+           if(rnum >= 0) {
+               for(rx = rooms[rnum].lx-1; rx <= rooms[rnum].hx+1; rx++)
+                   for(ry = rooms[rnum].ly-1; ry <= rooms[rnum].hy+1; ry++)
+                       set_lit(rx, ry,
+                               (genericptr_t)(on ? &is_lit : (char *)0));
+               rooms[rnum].rlit = on;
+           }
+           /* hallways remain dark on the rogue level */
+       } else
+#endif
+           do_clear_area(u.ux,u.uy,
+               (obj && obj->oclass==SCROLL_CLASS && obj->blessed) ? 9 : 5,
+               set_lit, (genericptr_t)(on ? &is_lit : (char *)0));
+
+       /*
+        *  If we are not blind, then force a redraw on all positions in sight
+        *  by temporarily blinding the hero.  The vision recalculation will
+        *  correctly update all previously seen positions *and* correctly
+        *  set the waslit bit [could be messed up from above].
+        */
+       if (!Blind) {
+           vision_recalc(2);
+
+           /* replace ball&chain */
+           if (Punished && !on)
+               move_bc(0, 0, uball->ox, uball->oy, uchain->ox, uchain->oy);
+       }
+
+       vision_full_recalc = 1; /* delayed vision recalculation */
+}
+
+static void
+do_class_genocide()
+{
+       int i, j, immunecnt, gonecnt, goodcnt, class, feel_dead = 0;
+       char buf[BUFSZ];
+       boolean gameover = FALSE;       /* true iff killed self */
+
+       for(j=0; ; j++) {
+               if (j >= 5) {
+                       pline(thats_enough_tries);
+                       return;
+               }
+               do {
+                   getlin("What class of monsters do you wish to genocide?",
+                       buf);
+                   (void)mungspaces(buf);
+               } while (buf[0]=='\033' || !buf[0]);
+               /* choosing "none" preserves genocideless conduct */
+               if (!strcmpi(buf, "none") ||
+                   !strcmpi(buf, "nothing")) return;
+
+               if (strlen(buf) == 1) {
+                   if (buf[0] == ILLOBJ_SYM)
+                       buf[0] = def_monsyms[S_MIMIC];
+                   class = def_char_to_monclass(buf[0]);
+               } else {
+                   char buf2[BUFSZ];
+
+                   class = 0;
+                   Strcpy(buf2, makesingular(buf));
+                   Strcpy(buf, buf2);
+               }
+               immunecnt = gonecnt = goodcnt = 0;
+               for (i = LOW_PM; i < NUMMONS; i++) {
+                   if (class == 0 &&
+                           strstri(monexplain[(int)mons[i].mlet], buf) != 0)
+                       class = mons[i].mlet;
+                   if (mons[i].mlet == class) {
+                       if (!(mons[i].geno & G_GENO)) immunecnt++;
+                       else if(mvitals[i].mvflags & G_GENOD) gonecnt++;
+                       else goodcnt++;
+                   }
+               }
+               /*
+                * TODO[?]: If user's input doesn't match any class
+                *          description, check individual species names.
+                */
+               if (!goodcnt && class != mons[urole.malenum].mlet &&
+                               class != mons[urace.malenum].mlet) {
+                       if (gonecnt)
+       pline("All such monsters are already nonexistent.");
+                       else if (immunecnt ||
+                               (buf[0] == DEF_INVISIBLE && buf[1] == '\0'))
+       You("aren't permitted to genocide such monsters.");
+                       else
+#ifdef WIZARD  /* to aid in topology testing; remove pesky monsters */
+                         if (wizard && buf[0] == '*') {
+                           register struct monst *mtmp, *mtmp2;
+
+                           gonecnt = 0;
+                           for (mtmp = fmon; mtmp; mtmp = mtmp2) {
+                               mtmp2 = mtmp->nmon;
+                               if (DEADMONSTER(mtmp)) continue;
+                               mongone(mtmp);
+                               gonecnt++;
+                           }
+       pline("Eliminated %d monster%s.", gonecnt, plur(gonecnt));
+                           return;
+                       } else
+#endif
+       pline("That symbol does not represent any monster.");
+                       continue;
+               }
+
+               for (i = LOW_PM; i < NUMMONS; i++) {
+                   if(mons[i].mlet == class) {
+                       char nam[BUFSZ];
+
+                       Strcpy(nam, makeplural(mons[i].mname));
+                       /* Although "genus" is Latin for race, the hero benefits
+                        * from both race and role; thus genocide affects either.
+                        */
+                       if (Your_Own_Role(i) || Your_Own_Race(i) ||
+                               ((mons[i].geno & G_GENO)
+                               && !(mvitals[i].mvflags & G_GENOD))) {
+                       /* This check must be first since player monsters might
+                        * have G_GENOD or !G_GENO.
+                        */
+                           mvitals[i].mvflags |= (G_GENOD|G_NOCORPSE);
+                           reset_rndmonst(i);
+                           kill_genocided_monsters();
+                           update_inventory();         /* eggs & tins */
+                           pline("Wiped out all %s.", nam);
+                           if (Upolyd && i == u.umonnum) {
+                               u.mh = -1;
+                               if (Unchanging) {
+                                   if (!feel_dead++) You("die.");
+                                   /* finish genociding this class of
+                                      monsters before ultimately dying */
+                                   gameover = TRUE;
+                               } else
+                                   rehumanize();
+                           }
+                           /* Self-genocide if it matches either your race
+                              or role.  Assumption:  male and female forms
+                              share same monster class. */
+                           if (i == urole.malenum || i == urace.malenum) {
+                               u.uhp = -1;
+                               if (Upolyd) {
+                                   if (!feel_dead++) You_feel("dead inside.");
+                               } else {
+                                   if (!feel_dead++) You("die.");
+                                   gameover = TRUE;
+                               }
+                           }
+                       } else if (mvitals[i].mvflags & G_GENOD) {
+                           if (!gameover)
+                               pline("All %s are already nonexistent.", nam);
+                       } else if (!gameover) {
+                         /* suppress feedback about quest beings except
+                            for those applicable to our own role */
+                         if ((mons[i].msound != MS_LEADER ||
+                              quest_info(MS_LEADER) == i)
+                          && (mons[i].msound != MS_NEMESIS ||
+                              quest_info(MS_NEMESIS) == i)
+                          && (mons[i].msound != MS_GUARDIAN ||
+                              quest_info(MS_GUARDIAN) == i)
+                       /* non-leader/nemesis/guardian role-specific monster */
+                          && (i != PM_NINJA ||         /* nuisance */
+                              Role_if(PM_SAMURAI))) {
+                               boolean named, uniq;
+
+                               named = type_is_pname(&mons[i]) ? TRUE : FALSE;
+                               uniq = (mons[i].geno & G_UNIQ) ? TRUE : FALSE;
+                               /* one special case */
+                               if (i == PM_HIGH_PRIEST) uniq = FALSE;
+
+                               You("aren't permitted to genocide %s%s.",
+                                   (uniq && !named) ? "the " : "",
+                                   (uniq || named) ? mons[i].mname : nam);
+                           }
+                       }
+                   }
+               }
+               if (gameover || u.uhp == -1) {
+                   killer_format = KILLED_BY_AN;
+                   killer = "scroll of genocide";
+                   if (gameover) done(GENOCIDED);
+               }
+               return;
+       }
+}
+
+#define REALLY 1
+#define PLAYER 2
+#define ONTHRONE 4
+void
+do_genocide(how)
+int how;
+/* 0 = no genocide; create monsters (cursed scroll) */
+/* 1 = normal genocide */
+/* 3 = forced genocide of player */
+/* 5 (4 | 1) = normal genocide from throne */
+{
+       char buf[BUFSZ];
+       register int    i, killplayer = 0;
+       register int mndx;
+       register struct permonst *ptr;
+       const char *which;
+
+       if (how & PLAYER) {
+               mndx = u.umonster;      /* non-polymorphed mon num */
+               ptr = &mons[mndx];
+               Strcpy(buf, ptr->mname);
+               killplayer++;
+       } else {
+           for(i = 0; ; i++) {
+               if(i >= 5) {
+                   pline(thats_enough_tries);
+                   return;
+               }
+               getlin("What monster do you want to genocide? [type the name]",
+                       buf);
+               (void)mungspaces(buf);
+               /* choosing "none" preserves genocideless conduct */
+               if (!strcmpi(buf, "none") || !strcmpi(buf, "nothing")) {
+                   /* ... but no free pass if cursed */
+                   if (!(how & REALLY)) {
+                       ptr = rndmonst();
+                       if (!ptr) return; /* no message, like normal case */
+                       mndx = monsndx(ptr);
+                       break;          /* remaining checks don't apply */
+                   } else return;
+               }
+
+               mndx = name_to_mon(buf);
+               if (mndx == NON_PM || (mvitals[mndx].mvflags & G_GENOD)) {
+                       pline("Such creatures %s exist in this world.",
+                             (mndx == NON_PM) ? "do not" : "no longer");
+                       continue;
+               }
+               ptr = &mons[mndx];
+               /* Although "genus" is Latin for race, the hero benefits
+                * from both race and role; thus genocide affects either.
+                */
+               if (Your_Own_Role(mndx) || Your_Own_Race(mndx)) {
+                       killplayer++;
+                       break;
+               }
+               if (is_human(ptr)) adjalign(-sgn(u.ualign.type));
+               if (is_demon(ptr)) adjalign(sgn(u.ualign.type));
+
+               if(!(ptr->geno & G_GENO)) {
+                       if(flags.soundok) {
+       /* fixme: unconditional "caverns" will be silly in some circumstances */
+                           if(flags.verbose)
+                       pline("A thunderous voice booms through the caverns:");
+                           verbalize("No, mortal!  That will not be done.");
+                       }
+                       continue;
+               }
+               /* KMH -- Unchanging prevents rehumanization */
+               if (Unchanging && ptr == youmonst.data)
+                   killplayer++;
+               break;
+           }
+       }
+
+       which = "all ";
+       if (Hallucination) {
+           if (Upolyd)
+               Strcpy(buf,youmonst.data->mname);
+           else {
+               Strcpy(buf, (flags.female && urole.name.f) ?
+                               urole.name.f : urole.name.m);
+               buf[0] = lowc(buf[0]);
+           }
+       } else {
+           Strcpy(buf, ptr->mname); /* make sure we have standard singular */
+           if ((ptr->geno & G_UNIQ) && ptr != &mons[PM_HIGH_PRIEST])
+               which = !type_is_pname(ptr) ? "the " : "";
+       }
+       if (how & REALLY) {
+           /* setting no-corpse affects wishing and random tin generation */
+           mvitals[mndx].mvflags |= (G_GENOD | G_NOCORPSE);
+           pline("Wiped out %s%s.", which,
+                 (*which != 'a') ? buf : makeplural(buf));
+
+           if (killplayer) {
+               /* might need to wipe out dual role */
+               if (urole.femalenum != NON_PM && mndx == urole.malenum)
+                   mvitals[urole.femalenum].mvflags |= (G_GENOD | G_NOCORPSE);
+               if (urole.femalenum != NON_PM && mndx == urole.femalenum)
+                   mvitals[urole.malenum].mvflags |= (G_GENOD | G_NOCORPSE);
+               if (urace.femalenum != NON_PM && mndx == urace.malenum)
+                   mvitals[urace.femalenum].mvflags |= (G_GENOD | G_NOCORPSE);
+               if (urace.femalenum != NON_PM && mndx == urace.femalenum)
+                   mvitals[urace.malenum].mvflags |= (G_GENOD | G_NOCORPSE);
+
+               u.uhp = -1;
+               if (how & PLAYER) {
+                   killer_format = KILLED_BY;
+                   killer = "genocidal confusion";
+               } else if (how & ONTHRONE) {
+                   /* player selected while on a throne */
+                   killer_format = KILLED_BY_AN;
+                   killer = "imperious order";
+               } else { /* selected player deliberately, not confused */
+                   killer_format = KILLED_BY_AN;
+                   killer = "scroll of genocide";
+               }
+
+       /* Polymorphed characters will die as soon as they're rehumanized. */
+       /* KMH -- Unchanging prevents rehumanization */
+               if (Upolyd && ptr != youmonst.data) {
+                       delayed_killer = killer;
+                       killer = 0;
+                       You_feel("dead inside.");
+               } else
+                       done(GENOCIDED);
+           } else if (ptr == youmonst.data) {
+               rehumanize();
+           }
+           reset_rndmonst(mndx);
+           kill_genocided_monsters();
+           update_inventory(); /* in case identified eggs were affected */
+       } else {
+           int cnt = 0;
+
+           if (!(mons[mndx].geno & G_UNIQ) &&
+                   !(mvitals[mndx].mvflags & (G_GENOD | G_EXTINCT)))
+               for (i = rn1(3, 4); i > 0; i--) {
+                   if (!makemon(ptr, u.ux, u.uy, NO_MINVENT))
+                       break;  /* couldn't make one */
+                   ++cnt;
+                   if (mvitals[mndx].mvflags & G_EXTINCT)
+                       break;  /* just made last one */
+               }
+           if (cnt)
+               pline("Sent in some %s.", makeplural(buf));
+           else
+               pline(nothing_happens);
+       }
+}
+
+void
+punish(sobj)
+register struct obj    *sobj;
+{
+       /* KMH -- Punishment is still okay when you are riding */
+       You("are being punished for your misbehavior!");
+       if(Punished){
+               Your("iron ball gets heavier.");
+               uball->owt += 160 * (1 + sobj->cursed);
+               return;
+       }
+       if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) {
+               pline("A ball and chain appears, then falls away.");
+               dropy(mkobj(BALL_CLASS, TRUE));
+               return;
+       }
+       setworn(mkobj(CHAIN_CLASS, TRUE), W_CHAIN);
+       setworn(mkobj(BALL_CLASS, TRUE), W_BALL);
+       uball->spe = 1;         /* special ball (see save) */
+
+       /*
+        *  Place ball & chain if not swallowed.  If swallowed, the ball &
+        *  chain variables will be set at the next call to placebc().
+        */
+       if (!u.uswallow) {
+           placebc();
+           if (Blind) set_bc(1);       /* set up ball and chain variables */
+           newsym(u.ux,u.uy);          /* see ball&chain if can't see self */
+       }
+}
+
+void
+unpunish()
+{          /* remove the ball and chain */
+       struct obj *savechain = uchain;
+
+       obj_extract_self(uchain);
+       newsym(uchain->ox,uchain->oy);
+       setworn((struct obj *)0, W_CHAIN);
+       dealloc_obj(savechain);
+       uball->spe = 0;
+       setworn((struct obj *)0, W_BALL);
+}
+
+/* some creatures have special data structures that only make sense in their
+ * normal locations -- if the player tries to create one elsewhere, or to revive
+ * one, the disoriented creature becomes a zombie
+ */
+boolean
+cant_create(mtype, revival)
+int *mtype;
+boolean revival;
+{
+
+       /* SHOPKEEPERS can be revived now */
+       if (*mtype==PM_GUARD || (*mtype==PM_SHOPKEEPER && !revival)
+            || *mtype==PM_ALIGNED_PRIEST || *mtype==PM_ANGEL) {
+               *mtype = PM_HUMAN_ZOMBIE;
+               return TRUE;
+       } else if (*mtype==PM_LONG_WORM_TAIL) { /* for create_particular() */
+               *mtype = PM_LONG_WORM;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+#ifdef WIZARD
+/*
+ * Make a new monster with the type controlled by the user.
+ *
+ * Note:  when creating a monster by class letter, specifying the
+ * "strange object" (']') symbol produces a random monster rather
+ * than a mimic; this behavior quirk is useful so don't "fix" it...
+ */
+boolean
+create_particular()
+{
+       char buf[BUFSZ], *bufp, monclass = MAXMCLASSES;
+       int which, tries, i;
+       struct permonst *whichpm;
+       struct monst *mtmp;
+       boolean madeany = FALSE;
+       boolean maketame, makepeaceful, makehostile;
+
+       tries = 0;
+       do {
+           which = urole.malenum;      /* an arbitrary index into mons[] */
+           maketame = makepeaceful = makehostile = FALSE;
+           getlin("Create what kind of monster? [type the name or symbol]",
+                  buf);
+           bufp = mungspaces(buf);
+           if (*bufp == '\033') return FALSE;
+           /* allow the initial disposition to be specified */
+           if (!strncmpi(bufp, "tame ", 5)) {
+               bufp += 5;
+               maketame = TRUE;
+           } else if (!strncmpi(bufp, "peaceful ", 9)) {
+               bufp += 9;
+               makepeaceful = TRUE;
+           } else if (!strncmpi(bufp, "hostile ", 8)) {
+               bufp += 8;
+               makehostile = TRUE;
+           }
+           /* decide whether a valid monster was chosen */
+           if (strlen(bufp) == 1) {
+               monclass = def_char_to_monclass(*bufp);
+               if (monclass != MAXMCLASSES) break;     /* got one */
+           } else {
+               which = name_to_mon(bufp);
+               if (which >= LOW_PM) break;             /* got one */
+           }
+           /* no good; try again... */
+           pline("I've never heard of such monsters.");
+       } while (++tries < 5);
+
+       if (tries == 5) {
+           pline(thats_enough_tries);
+       } else {
+           (void) cant_create(&which, FALSE);
+           whichpm = &mons[which];
+           for (i = 0; i <= multi; i++) {
+               if (monclass != MAXMCLASSES)
+                   whichpm = mkclass(monclass, 0);
+               if (maketame) {
+                   mtmp = makemon(whichpm, u.ux, u.uy, MM_EDOG);
+                   if (mtmp) {
+                       initedog(mtmp);
+                       set_malign(mtmp);
+                   }
+               } else {
+                   mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS);
+                   if ((makepeaceful || makehostile) && mtmp) {
+                       mtmp->mtame = 0;        /* sanity precaution */
+                       mtmp->mpeaceful = makepeaceful ? 1 : 0;
+                       set_malign(mtmp);
+                   }
+               }
+               if (mtmp) madeany = TRUE;
+           }
+       }
+       return madeany;
+}
+#endif /* WIZARD */
+
+#endif /* OVLB */
+
+/*read.c*/
diff --git a/src/rect.c b/src/rect.c
new file mode 100644 (file)
index 0000000..dc6be73
--- /dev/null
@@ -0,0 +1,194 @@
+/*     SCCS Id: @(#)rect.c     3.4     1990/02/22      */
+/* Copyright (c) 1990 by Jean-Christophe Collet         */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+int FDECL(get_rect_ind, (NhRect *));
+
+static boolean FDECL(intersect, (NhRect *,NhRect *,NhRect *));
+
+    /*
+     * In this file, we will handle the various rectangle functions we
+     * need for room generation.
+     */
+
+#define MAXRECT        50
+#define XLIM   4
+#define YLIM   3
+
+static NhRect rect[MAXRECT+1];
+static int rect_cnt;
+
+/*
+ * Initialisation of internal structures. Should be called for every
+ * new level to be build...
+ */
+
+void
+init_rect()
+{
+       rect_cnt = 1;
+       rect[0].lx = rect[0].ly = 0;
+       rect[0].hx = COLNO - 1;
+       rect[0].hy = ROWNO - 1;
+}
+
+/*
+ * Search Index of one precise NhRect.
+ *
+ */
+
+int
+get_rect_ind(r)
+NhRect *r;
+{
+       register NhRect *rectp;
+       register int lx, ly, hx, hy;
+       register int i;
+
+       lx = r->lx; ly = r->ly;
+       hx = r->hx; hy = r->hy;
+       for (i=0,rectp = &rect[0];i<rect_cnt;i++,rectp++)
+           if ( lx == rectp->lx && ly == rectp->ly &&
+                hx == rectp->hx && hy == rectp->hy)
+               return i;
+       return -1;
+}
+
+/*
+ * Search a free rectangle that include the one given in arg
+ */
+
+NhRect *
+get_rect(r)
+NhRect *r;
+{
+       register NhRect *rectp;
+       register int lx, ly, hx, hy;
+       register int i;
+
+       lx = r->lx; ly = r->ly;
+       hx = r->hx; hy = r->hy;
+       for (i=0,rectp = &rect[0];i<rect_cnt;i++,rectp++)
+           if ( lx >= rectp->lx && ly >= rectp->ly &&
+                hx <= rectp->hx && hy <= rectp->hy)
+               return rectp;
+       return 0;
+}
+
+/*
+ * Get some random NhRect from the list.
+ */
+
+NhRect *
+rnd_rect()
+{
+           return rect_cnt > 0 ? &rect[rn2(rect_cnt)] : 0;
+}
+
+/*
+ * Search intersection between two rectangles (r1 & r2).
+ * return TRUE if intersection exist and put it in r3.
+ * otherwise returns FALSE
+ */
+
+static boolean
+intersect(r1, r2, r3)
+NhRect *r1, *r2, *r3;
+{
+       if (r2->lx > r1->hx || r2->ly > r1->hy ||
+           r2->hx < r1->lx || r2->hy < r1->ly)
+           return FALSE;
+
+       r3->lx = (r2->lx > r1->lx ? r2->lx : r1->lx);
+       r3->ly = (r2->ly > r1->ly ? r2->ly : r1->ly);
+       r3->hx = (r2->hx > r1->hx ? r1->hx : r2->hx);
+       r3->hy = (r2->hy > r1->hy ? r1->hy : r2->hy);
+
+       if (r3->lx > r3->hx || r3->ly > r3->hy)
+           return FALSE;
+       return TRUE;
+}
+
+/*
+ * Remove a rectangle from the list of free NhRect.
+ */
+
+void
+remove_rect(r)
+NhRect *r;
+{
+       int ind;
+
+       ind = get_rect_ind(r);
+       if ( ind >=0 )
+           rect[ind] = rect[--rect_cnt];
+}
+
+/*
+ * Add a NhRect to the list.
+ */
+
+void
+add_rect(r)
+NhRect *r;
+{
+       if (rect_cnt >= MAXRECT) {
+#ifdef WIZARD
+               if (wizard) pline("MAXRECT may be too small.");
+#endif
+               return;
+       }
+       /* Check that this NhRect is not included in another one */
+       if (get_rect(r))
+           return;
+       rect[rect_cnt] = *r;
+       rect_cnt++;
+}
+
+/*
+ * Okay, here we have two rectangles (r1 & r2).
+ * r1 was already in the list and r2 is included in r1.
+ * What we want is to allocate r2, that is split r1 into smaller rectangles
+ * then remove it.
+ */
+
+void
+split_rects(r1, r2)
+NhRect *r1, *r2;
+{
+       NhRect r, old_r;
+       int i;
+
+       old_r = *r1;
+       remove_rect(r1);
+
+       /* Walk down since rect_cnt & rect[] will change... */
+       for (i=rect_cnt-1; i>=0; i--)
+           if (intersect(&rect[i], r2, &r))
+               split_rects(&rect[i], &r);
+       
+       if (r2->ly - old_r.ly-1 > (old_r.hy < ROWNO - 1 ? 2*YLIM : YLIM+1)+4) {
+               r = old_r;
+               r.hy = r2->ly - 2;
+               add_rect(&r);
+       }
+       if (r2->lx - old_r.lx-1 > (old_r.hx < COLNO - 1 ? 2*XLIM : XLIM+1)+4) {
+               r = old_r;
+               r.hx = r2->lx - 2;
+               add_rect(&r);
+       }
+       if (old_r.hy - r2->hy-1 > (old_r.ly > 0 ? 2*YLIM : YLIM+1)+4) {
+               r = old_r;
+               r.ly = r2->hy + 2;
+               add_rect(&r);
+       }
+       if (old_r.hx - r2->hx-1 > (old_r.lx > 0 ? 2*XLIM : XLIM+1)+4) {
+               r = old_r;
+               r.lx = r2->hx + 2;
+               add_rect(&r);
+       }
+}
+
+/*rect.c*/
diff --git a/src/region.c b/src/region.c
new file mode 100644 (file)
index 0000000..e4d12af
--- /dev/null
@@ -0,0 +1,985 @@
+/*     SCCS Id: @(#)region.c   3.4     2002/10/15      */
+/* Copyright (c) 1996 by Jean-Christophe Collet         */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "lev.h"
+
+/*
+ * This should really go into the level structure, but
+ * I'll start here for ease. It *WILL* move into the level
+ * structure eventually.
+ */
+
+static NhRegion **regions;
+static int n_regions = 0;
+static int max_regions = 0;
+
+#define NO_CALLBACK (-1)
+
+boolean FDECL(inside_gas_cloud, (genericptr,genericptr));
+boolean FDECL(expire_gas_cloud, (genericptr,genericptr));
+boolean FDECL(inside_rect, (NhRect *,int,int));
+boolean FDECL(inside_region, (NhRegion *,int,int));
+NhRegion *FDECL(create_region, (NhRect *,int));
+void FDECL(add_rect_to_reg, (NhRegion *,NhRect *));
+void FDECL(add_mon_to_reg, (NhRegion *,struct monst *));
+void FDECL(remove_mon_from_reg, (NhRegion *,struct monst *));
+boolean FDECL(mon_in_region, (NhRegion *,struct monst *));
+
+#if 0
+NhRegion *FDECL(clone_region, (NhRegion *));
+#endif
+void FDECL(free_region, (NhRegion *));
+void FDECL(add_region, (NhRegion *));
+void FDECL(remove_region, (NhRegion *));
+
+#if 0
+void FDECL(replace_mon_regions, (struct monst *,struct monst *));
+void FDECL(remove_mon_from_regions, (struct monst *));
+NhRegion *FDECL(create_msg_region, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,
+                                   const char *,const char *));
+boolean FDECL(enter_force_field, (genericptr,genericptr));
+NhRegion *FDECL(create_force_field, (XCHAR_P,XCHAR_P,int,int));
+#endif
+
+static void FDECL(reset_region_mids, (NhRegion *));
+
+static callback_proc callbacks[] = {
+#define INSIDE_GAS_CLOUD 0
+    inside_gas_cloud,
+#define EXPIRE_GAS_CLOUD 1
+    expire_gas_cloud
+};
+
+/* Should be inlined. */
+boolean
+inside_rect(r, x, y)
+NhRect *r;
+int x, y;
+{
+    return (x >= r->lx && x <= r->hx && y >= r->ly && y <= r->hy);
+}
+
+/*
+ * Check if a point is inside a region.
+ */
+boolean
+inside_region(reg, x, y)
+NhRegion *reg;
+int x, y;
+{
+    int i;
+
+    if (reg == NULL || !inside_rect(&(reg->bounding_box), x, y))
+       return FALSE;
+    for (i = 0; i < reg->nrects; i++)
+       if (inside_rect(&(reg->rects[i]), x, y))
+           return TRUE;
+    return FALSE;
+}
+
+/*
+ * Create a region. It does not activate it.
+ */
+NhRegion *
+create_region(rects, nrect)
+NhRect *rects;
+int nrect;
+{
+    int i;
+    NhRegion *reg;
+
+    reg = (NhRegion *) alloc(sizeof (NhRegion));
+    /* Determines bounding box */
+    if (nrect > 0) {
+       reg->bounding_box = rects[0];
+    } else {
+       reg->bounding_box.lx = 99;
+       reg->bounding_box.ly = 99;
+       reg->bounding_box.hx = 0;
+       reg->bounding_box.hy = 0;
+    }
+    reg->nrects = nrect;
+    reg->rects = nrect > 0 ? (NhRect *)alloc((sizeof (NhRect)) * nrect) : NULL;
+    for (i = 0; i < nrect; i++) {
+       if (rects[i].lx < reg->bounding_box.lx)
+           reg->bounding_box.lx = rects[i].lx;
+       if (rects[i].ly < reg->bounding_box.ly)
+           reg->bounding_box.ly = rects[i].ly;
+       if (rects[i].hx > reg->bounding_box.hx)
+           reg->bounding_box.hx = rects[i].hx;
+       if (rects[i].hy > reg->bounding_box.hy)
+           reg->bounding_box.hy = rects[i].hy;
+       reg->rects[i] = rects[i];
+    }
+    reg->ttl = -1;             /* Defaults */
+    reg->attach_2_u = FALSE;
+    reg->attach_2_m = 0;
+    /* reg->attach_2_o = NULL; */
+    reg->enter_msg = NULL;
+    reg->leave_msg = NULL;
+    reg->expire_f = NO_CALLBACK;
+    reg->enter_f = NO_CALLBACK;
+    reg->can_enter_f = NO_CALLBACK;
+    reg->leave_f = NO_CALLBACK;
+    reg->can_leave_f = NO_CALLBACK;
+    reg->inside_f = NO_CALLBACK;
+    clear_hero_inside(reg);
+    clear_heros_fault(reg);
+    reg->n_monst = 0;
+    reg->max_monst = 0;
+    reg->monsters = NULL;
+    reg->arg = NULL;
+    return reg;
+}
+
+/*
+ * Add rectangle to region.
+ */
+void
+add_rect_to_reg(reg, rect)
+NhRegion *reg;
+NhRect *rect;
+{
+    NhRect *tmp_rect;
+
+    tmp_rect = (NhRect *) alloc(sizeof (NhRect) * (reg->nrects + 1));
+    if (reg->nrects > 0) {
+       (void) memcpy((genericptr_t) tmp_rect, (genericptr_t) reg->rects,
+                     (sizeof (NhRect) * reg->nrects));
+       free((genericptr_t) reg->rects);
+    }
+    tmp_rect[reg->nrects] = *rect;
+    reg->nrects++;
+    reg->rects = tmp_rect;
+    /* Update bounding box if needed */
+    if (reg->bounding_box.lx > rect->lx)
+       reg->bounding_box.lx = rect->lx;
+    if (reg->bounding_box.ly > rect->ly)
+       reg->bounding_box.ly = rect->ly;
+    if (reg->bounding_box.hx < rect->hx)
+       reg->bounding_box.hx = rect->hx;
+    if (reg->bounding_box.hy < rect->hy)
+       reg->bounding_box.hy = rect->hy;
+}
+
+/*
+ * Add a monster to the region
+ */
+void
+add_mon_to_reg(reg, mon)
+NhRegion *reg;
+struct monst *mon;
+{
+    int i;
+    unsigned *tmp_m;
+
+    if (reg->max_monst <= reg->n_monst) {
+       tmp_m = (unsigned *)
+                   alloc(sizeof (unsigned) * (reg->max_monst + MONST_INC));
+       if (reg->max_monst > 0) {
+           for (i = 0; i < reg->max_monst; i++)
+               tmp_m[i] = reg->monsters[i];
+           free((genericptr_t) reg->monsters);
+       }
+       reg->monsters = tmp_m;
+       reg->max_monst += MONST_INC;
+    }
+    reg->monsters[reg->n_monst++] = mon->m_id;
+}
+
+/*
+ * Remove a monster from the region list (it left or died...)
+ */
+void
+remove_mon_from_reg(reg, mon)
+NhRegion *reg;
+struct monst *mon;
+{
+    register int i;
+
+    for (i = 0; i < reg->n_monst; i++)
+       if (reg->monsters[i] == mon->m_id) {
+           reg->n_monst--;
+           reg->monsters[i] = reg->monsters[reg->n_monst];
+           return;
+       }
+}
+
+/*
+ * Check if a monster is inside the region.
+ * It's probably quicker to check with the region internal list
+ * than to check for coordinates.
+ */
+boolean
+mon_in_region(reg, mon)
+NhRegion *reg;
+struct monst *mon;
+{
+    int i;
+
+    for (i = 0; i < reg->n_monst; i++)
+       if (reg->monsters[i] == mon->m_id)
+           return TRUE;
+    return FALSE;
+}
+
+#if 0
+/* not yet used */
+
+/*
+ * Clone (make a standalone copy) the region.
+ */
+NhRegion *
+clone_region(reg)
+NhRegion *reg;
+{
+    NhRegion *ret_reg;
+
+    ret_reg = create_region(reg->rects, reg->nrects);
+    ret_reg->ttl = reg->ttl;
+    ret_reg->attach_2_u = reg->attach_2_u;
+    ret_reg->attach_2_m = reg->attach_2_m;
+ /* ret_reg->attach_2_o = reg->attach_2_o; */
+    ret_reg->expire_f = reg->expire_f;
+    ret_reg->enter_f = reg->enter_f;
+    ret_reg->can_enter_f = reg->can_enter_f;
+    ret_reg->leave_f = reg->leave_f;
+    ret_reg->can_leave_f = reg->can_leave_f;
+    ret_reg->player_flags = reg->player_flags; /* set/clear_hero_inside,&c*/
+    ret_reg->n_monst = reg->n_monst;
+    if (reg->n_monst > 0) {
+       ret_reg->monsters = (unsigned *)
+                               alloc((sizeof (unsigned)) * reg->n_monst);
+       (void) memcpy((genericptr_t) ret_reg->monsters, (genericptr_t) reg->monsters,
+                     sizeof (unsigned) * reg->n_monst);
+    } else
+       ret_reg->monsters = NULL;
+    return ret_reg;
+}
+
+#endif /*0*/
+
+/*
+ * Free mem from region.
+ */
+void
+free_region(reg)
+NhRegion *reg;
+{
+    if (reg) {
+       if (reg->rects)
+           free((genericptr_t) reg->rects);
+       if (reg->monsters)
+           free((genericptr_t) reg->monsters);
+       free((genericptr_t) reg);
+    }
+}
+
+/*
+ * Add a region to the list.
+ * This actually activates the region.
+ */
+void
+add_region(reg)
+NhRegion *reg;
+{
+    NhRegion **tmp_reg;
+    int i, j;
+
+    if (max_regions <= n_regions) {
+       tmp_reg = regions;
+       regions = (NhRegion **)alloc(sizeof (NhRegion *) * (max_regions + 10));
+       if (max_regions > 0) {
+           (void) memcpy((genericptr_t) regions, (genericptr_t) tmp_reg,
+                         max_regions * sizeof (NhRegion *));
+           free((genericptr_t) tmp_reg);
+       }
+       max_regions += 10;
+    }
+    regions[n_regions] = reg;
+    n_regions++;
+    /* Check for monsters inside the region */
+    for (i = reg->bounding_box.lx; i <= reg->bounding_box.hx; i++)
+       for (j = reg->bounding_box.ly; j <= reg->bounding_box.hy; j++) {
+           /* Some regions can cross the level boundaries */
+           if (!isok(i,j))
+               continue;
+           if (MON_AT(i, j) && inside_region(reg, i, j))
+               add_mon_to_reg(reg, level.monsters[i][j]);
+           if (reg->visible && cansee(i, j))
+               newsym(i, j);
+       }
+    /* Check for player now... */
+    if (inside_region(reg, u.ux, u.uy)) 
+       set_hero_inside(reg);
+    else
+       clear_hero_inside(reg);
+}
+
+/*
+ * Remove a region from the list & free it.
+ */
+void
+remove_region(reg)
+NhRegion *reg;
+{
+    register int i, x, y;
+
+    for (i = 0; i < n_regions; i++)
+       if (regions[i] == reg)
+           break;
+    if (i == n_regions)
+       return;
+
+    /* Update screen if necessary */
+    if (reg->visible)
+       for (x = reg->bounding_box.lx; x <= reg->bounding_box.hx; x++)
+           for (y = reg->bounding_box.ly; y <= reg->bounding_box.hy; y++)
+               if (isok(x,y) && inside_region(reg, x, y) && cansee(x, y))
+                   newsym(x, y);
+
+    free_region(reg);
+    regions[i] = regions[n_regions - 1];
+    regions[n_regions - 1] = (NhRegion *) 0;
+    n_regions--;
+}
+
+/*
+ * Remove all regions and clear all related data (This must be down
+ * when changing level, for instance).
+ */
+void
+clear_regions()
+{
+    register int i;
+
+    for (i = 0; i < n_regions; i++)
+       free_region(regions[i]);
+    n_regions = 0;
+    if (max_regions > 0)
+       free((genericptr_t) regions);
+    max_regions = 0;
+    regions = NULL;
+}
+
+/*
+ * This function is called every turn.
+ * It makes the regions age, if necessary and calls the appropriate
+ * callbacks when needed.
+ */
+void
+run_regions()
+{
+    register int i, j, k;
+    int f_indx;
+
+    /* End of life ? */
+    /* Do it backward because the array will be modified */
+    for (i = n_regions - 1; i >= 0; i--) {
+       if (regions[i]->ttl == 0) {
+           if ((f_indx = regions[i]->expire_f) == NO_CALLBACK ||
+               (*callbacks[f_indx])(regions[i], (genericptr_t) 0))
+               remove_region(regions[i]);
+       }
+    }
+
+    /* Process remaining regions */
+    for (i = 0; i < n_regions; i++) {
+       /* Make the region age */
+       if (regions[i]->ttl > 0)
+           regions[i]->ttl--;
+       /* Check if player is inside region */
+       f_indx = regions[i]->inside_f;
+       if (f_indx != NO_CALLBACK && hero_inside(regions[i]))
+           (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
+       /* Check if any monster is inside region */
+       if (f_indx != NO_CALLBACK) {
+           for (j = 0; j < regions[i]->n_monst; j++) {
+               struct monst *mtmp = find_mid(regions[i]->monsters[j], FM_FMON);
+
+               if (!mtmp || mtmp->mhp <= 0 ||
+                               (*callbacks[f_indx])(regions[i], mtmp)) {
+                   /* The monster died, remove it from list */
+                   k = (regions[i]->n_monst -= 1);
+                   regions[i]->monsters[j] = regions[i]->monsters[k];
+                   regions[i]->monsters[k] = 0;
+                   --j;    /* current slot has been reused; recheck it next */
+               }
+           }
+       }
+    }
+}
+
+/*
+ * check whether player enters/leaves one or more regions.
+ */
+boolean
+in_out_region(x, y)
+xchar
+    x, y;
+{
+    int i, f_indx;
+
+    /* First check if we can do the move */
+    for (i = 0; i < n_regions; i++) {
+       if (inside_region(regions[i], x, y)
+           && !hero_inside(regions[i]) && !regions[i]->attach_2_u) {
+           if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK)
+               if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
+                   return FALSE;
+       } else
+           if (hero_inside(regions[i])
+               && !inside_region(regions[i], x, y)
+               && !regions[i]->attach_2_u) {
+           if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK)
+               if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
+                   return FALSE;
+       }
+    }
+
+    /* Callbacks for the regions we do leave */
+    for (i = 0; i < n_regions; i++)
+       if (hero_inside(regions[i]) &&
+               !regions[i]->attach_2_u && !inside_region(regions[i], x, y)) {
+           clear_hero_inside(regions[i]);
+           if (regions[i]->leave_msg != NULL)
+               pline(regions[i]->leave_msg);
+           if ((f_indx = regions[i]->leave_f) != NO_CALLBACK)
+               (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
+       }
+
+    /* Callbacks for the regions we do enter */
+    for (i = 0; i < n_regions; i++)
+       if (!hero_inside(regions[i]) &&
+               !regions[i]->attach_2_u && inside_region(regions[i], x, y)) {
+           set_hero_inside(regions[i]);
+           if (regions[i]->enter_msg != NULL)
+               pline(regions[i]->enter_msg);
+           if ((f_indx = regions[i]->enter_f) != NO_CALLBACK)
+               (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
+       }
+    return TRUE;
+}
+
+/*
+ * check wether a monster enters/leaves one or more region.
+*/
+boolean
+m_in_out_region(mon, x, y)
+struct monst *mon;
+xchar x, y;
+{
+    int i, f_indx;
+
+    /* First check if we can do the move */
+    for (i = 0; i < n_regions; i++) {
+       if (inside_region(regions[i], x, y) &&
+               !mon_in_region(regions[i], mon) &&
+               regions[i]->attach_2_m != mon->m_id) {
+           if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK)
+               if (!(*callbacks[f_indx])(regions[i], mon))
+                   return FALSE;
+       } else if (mon_in_region(regions[i], mon) &&
+               !inside_region(regions[i], x, y) &&
+               regions[i]->attach_2_m != mon->m_id) {
+           if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK)
+               if (!(*callbacks[f_indx])(regions[i], mon))
+                   return FALSE;
+       }
+    }
+
+    /* Callbacks for the regions we do leave */
+    for (i = 0; i < n_regions; i++)
+       if (mon_in_region(regions[i], mon) &&
+               regions[i]->attach_2_m != mon->m_id &&
+               !inside_region(regions[i], x, y)) {
+           remove_mon_from_reg(regions[i], mon);
+           if ((f_indx = regions[i]->leave_f) != NO_CALLBACK)
+               (void) (*callbacks[f_indx])(regions[i], mon);
+       }
+
+    /* Callbacks for the regions we do enter */
+    for (i = 0; i < n_regions; i++)
+       if (!hero_inside(regions[i]) &&
+               !regions[i]->attach_2_u && inside_region(regions[i], x, y)) {
+           add_mon_to_reg(regions[i], mon);
+           if ((f_indx = regions[i]->enter_f) != NO_CALLBACK)
+               (void) (*callbacks[f_indx])(regions[i], mon);
+       }
+    return TRUE;
+}
+
+/*
+ * Checks player's regions after a teleport for instance.
+ */
+void
+update_player_regions()
+{
+    register int i;
+
+    for (i = 0; i < n_regions; i++)
+       if (!regions[i]->attach_2_u && inside_region(regions[i], u.ux, u.uy))
+           set_hero_inside(regions[i]);
+       else
+           clear_hero_inside(regions[i]);
+}
+
+/*
+ * Ditto for a specified monster.
+ */
+void
+update_monster_region(mon)
+struct monst *mon;
+{
+    register int i;
+
+    for (i = 0; i < n_regions; i++) {
+       if (inside_region(regions[i], mon->mx, mon->my)) {
+           if (!mon_in_region(regions[i], mon))
+               add_mon_to_reg(regions[i], mon);
+       } else {
+           if (mon_in_region(regions[i], mon))
+               remove_mon_from_reg(regions[i], mon);
+       }
+    }
+}
+
+#if 0
+/* not yet used */
+
+/*
+ * Change monster pointer in regions
+ * This happens, for instance, when a monster grows and
+ * need a new structure (internally that is).
+ */
+void
+replace_mon_regions(monold, monnew)
+struct monst *monold, *monnew;
+{
+    register int i;
+
+    for (i = 0; i < n_regions; i++)
+       if (mon_in_region(regions[i], monold)) {
+           remove_mon_from_reg(regions[i], monold);
+           add_mon_to_reg(regions[i], monnew);
+       }
+}
+
+/*
+ * Remove monster from all regions it was in (ie monster just died)
+ */
+void
+remove_mon_from_regions(mon)
+struct monst *mon;
+{
+    register int i;
+
+    for (i = 0; i < n_regions; i++)
+       if (mon_in_region(regions[i], mon))
+           remove_mon_from_reg(regions[i], mon);
+}
+
+#endif /*0*/
+
+/*
+ * Check if a spot is under a visible region (eg: gas cloud).
+ * Returns NULL if not, otherwise returns region.
+ */
+NhRegion *
+visible_region_at(x, y)
+xchar x, y;
+{
+    register int i;
+
+    for (i = 0; i < n_regions; i++)
+       if (inside_region(regions[i], x, y) && regions[i]->visible &&
+               regions[i]->ttl != 0)
+           return regions[i];
+    return (NhRegion *) 0;
+}
+
+void
+show_region(reg, x, y)
+NhRegion *reg;
+xchar x, y;
+{
+    show_glyph(x, y, reg->glyph);
+}
+
+/**
+ * save_regions :
+ */
+void
+save_regions(fd, mode)
+int fd;
+int mode;
+{
+    int i, j;
+    unsigned n;
+
+    if (!perform_bwrite(mode)) goto skip_lots;
+
+    bwrite(fd, (genericptr_t) &moves, sizeof (moves)); /* timestamp */
+    bwrite(fd, (genericptr_t) &n_regions, sizeof (n_regions));
+    for (i = 0; i < n_regions; i++) {
+       bwrite(fd, (genericptr_t) &regions[i]->bounding_box, sizeof (NhRect));
+       bwrite(fd, (genericptr_t) &regions[i]->nrects, sizeof (short));
+       for (j = 0; j < regions[i]->nrects; j++)
+           bwrite(fd, (genericptr_t) &regions[i]->rects[j], sizeof (NhRect));
+       bwrite(fd, (genericptr_t) &regions[i]->attach_2_u, sizeof (boolean));
+       n = 0;
+       bwrite(fd, (genericptr_t) &regions[i]->attach_2_m, sizeof (unsigned));
+       n = regions[i]->enter_msg != NULL ? strlen(regions[i]->enter_msg) : 0;
+       bwrite(fd, (genericptr_t) &n, sizeof n);
+       if (n > 0)
+           bwrite(fd, (genericptr_t) regions[i]->enter_msg, n);
+       n = regions[i]->leave_msg != NULL ? strlen(regions[i]->leave_msg) : 0;
+       bwrite(fd, (genericptr_t) &n, sizeof n);
+       if (n > 0)
+           bwrite(fd, (genericptr_t) regions[i]->leave_msg, n);
+       bwrite(fd, (genericptr_t) &regions[i]->ttl, sizeof (short));
+       bwrite(fd, (genericptr_t) &regions[i]->expire_f, sizeof (short));
+       bwrite(fd, (genericptr_t) &regions[i]->can_enter_f, sizeof (short));
+       bwrite(fd, (genericptr_t) &regions[i]->enter_f, sizeof (short));
+       bwrite(fd, (genericptr_t) &regions[i]->can_leave_f, sizeof (short));
+       bwrite(fd, (genericptr_t) &regions[i]->leave_f, sizeof (short));
+       bwrite(fd, (genericptr_t) &regions[i]->inside_f, sizeof (short));
+       bwrite(fd, (genericptr_t) &regions[i]->player_flags, sizeof (boolean));
+       bwrite(fd, (genericptr_t) &regions[i]->n_monst, sizeof (short));
+       for (j = 0; j < regions[i]->n_monst; j++)
+           bwrite(fd, (genericptr_t) &regions[i]->monsters[j],
+            sizeof (unsigned));
+       bwrite(fd, (genericptr_t) &regions[i]->visible, sizeof (boolean));
+       bwrite(fd, (genericptr_t) &regions[i]->glyph, sizeof (int));
+       bwrite(fd, (genericptr_t) &regions[i]->arg, sizeof (genericptr_t));
+    }
+
+skip_lots:
+    if (release_data(mode))
+       clear_regions();
+}
+
+void
+rest_regions(fd, ghostly)
+int fd;
+boolean ghostly; /* If a bones file restore */
+{
+    int i, j;
+    unsigned n;
+    long tmstamp;
+    char *msg_buf;
+
+    clear_regions();           /* Just for security */
+    mread(fd, (genericptr_t) &tmstamp, sizeof (tmstamp));
+    if (ghostly) tmstamp = 0;
+    else tmstamp = (moves - tmstamp);
+    mread(fd, (genericptr_t) &n_regions, sizeof (n_regions));
+    max_regions = n_regions;
+    if (n_regions > 0)
+       regions = (NhRegion **) alloc(sizeof (NhRegion *) * n_regions);
+    for (i = 0; i < n_regions; i++) {
+       regions[i] = (NhRegion *) alloc(sizeof (NhRegion));
+       mread(fd, (genericptr_t) &regions[i]->bounding_box, sizeof (NhRect));
+       mread(fd, (genericptr_t) &regions[i]->nrects, sizeof (short));
+
+       if (regions[i]->nrects > 0)
+           regions[i]->rects = (NhRect *)
+                                 alloc(sizeof (NhRect) * regions[i]->nrects);
+       for (j = 0; j < regions[i]->nrects; j++)
+           mread(fd, (genericptr_t) &regions[i]->rects[j], sizeof (NhRect));
+       mread(fd, (genericptr_t) &regions[i]->attach_2_u, sizeof (boolean));
+       mread(fd, (genericptr_t) &regions[i]->attach_2_m, sizeof (unsigned));
+
+       mread(fd, (genericptr_t) &n, sizeof n);
+       if (n > 0) {
+           msg_buf = (char *) alloc(n + 1);
+           mread(fd, (genericptr_t) msg_buf, n);
+           msg_buf[n] = '\0';
+           regions[i]->enter_msg = (const char *) msg_buf;
+       } else
+           regions[i]->enter_msg = NULL;
+
+       mread(fd, (genericptr_t) &n, sizeof n);
+       if (n > 0) {
+           msg_buf = (char *) alloc(n + 1);
+           mread(fd, (genericptr_t) msg_buf, n);
+           msg_buf[n] = '\0';
+           regions[i]->leave_msg = (const char *) msg_buf;
+       } else
+           regions[i]->leave_msg = NULL;
+
+       mread(fd, (genericptr_t) &regions[i]->ttl, sizeof (short));
+       /* check for expired region */
+       if (regions[i]->ttl >= 0)
+           regions[i]->ttl =
+               (regions[i]->ttl > tmstamp) ? regions[i]->ttl - tmstamp : 0;
+       mread(fd, (genericptr_t) &regions[i]->expire_f, sizeof (short));
+       mread(fd, (genericptr_t) &regions[i]->can_enter_f, sizeof (short));
+       mread(fd, (genericptr_t) &regions[i]->enter_f, sizeof (short));
+       mread(fd, (genericptr_t) &regions[i]->can_leave_f, sizeof (short));
+       mread(fd, (genericptr_t) &regions[i]->leave_f, sizeof (short));
+       mread(fd, (genericptr_t) &regions[i]->inside_f, sizeof (short));
+       mread(fd, (genericptr_t) &regions[i]->player_flags, sizeof (boolean));
+       if (ghostly) {  /* settings pertained to old player */
+           clear_hero_inside(regions[i]);
+           clear_heros_fault(regions[i]);
+       }
+       mread(fd, (genericptr_t) &regions[i]->n_monst, sizeof (short));
+       if (regions[i]->n_monst > 0)
+           regions[i]->monsters =
+               (unsigned *) alloc(sizeof (unsigned) * regions[i]->n_monst);
+       else
+           regions[i]->monsters = NULL;
+       regions[i]->max_monst = regions[i]->n_monst;
+       for (j = 0; j < regions[i]->n_monst; j++)
+           mread(fd, (genericptr_t) &regions[i]->monsters[j],
+                 sizeof (unsigned));
+       mread(fd, (genericptr_t) &regions[i]->visible, sizeof (boolean));
+       mread(fd, (genericptr_t) &regions[i]->glyph, sizeof (int));
+       mread(fd, (genericptr_t) &regions[i]->arg, sizeof (genericptr_t));
+    }
+    /* remove expired regions, do not trigger the expire_f callback (yet!);
+       also update monster lists if this data is coming from a bones file */
+    for (i = n_regions - 1; i >= 0; i--)
+       if (regions[i]->ttl == 0)
+           remove_region(regions[i]);
+       else if (ghostly && regions[i]->n_monst > 0)
+           reset_region_mids(regions[i]);
+}
+
+/* update monster IDs for region being loaded from bones; `ghostly' implied */
+static void
+reset_region_mids(reg)
+NhRegion *reg;
+{
+    int i = 0, n = reg->n_monst;
+    unsigned *mid_list = reg->monsters;
+
+    while (i < n)
+       if (!lookup_id_mapping(mid_list[i], &mid_list[i])) {
+           /* shrink list to remove missing monster; order doesn't matter */
+           mid_list[i] = mid_list[--n];
+       } else {
+           /* move on to next monster */
+           ++i;
+       }
+    reg->n_monst = n;
+    return;
+}
+
+#if 0
+/* not yet used */
+
+/*--------------------------------------------------------------*
+ *                                                             *
+ *                     Create Region with just a message       *
+ *                                                             *
+ *--------------------------------------------------------------*/
+
+NhRegion *
+create_msg_region(x, y, w, h, msg_enter, msg_leave)
+xchar x, y;
+xchar w, h;
+const char *msg_enter;
+const char *msg_leave;
+{
+    NhRect tmprect;
+    NhRegion *reg = create_region((NhRect *) 0, 0);
+
+    reg->enter_msg = msg_enter;
+    reg->leave_msg = msg_leave;
+    tmprect.lx = x;
+    tmprect.ly = y;
+    tmprect.hx = x + w;
+    tmprect.hy = y + h;
+    add_rect_to_reg(reg, &tmprect);
+    reg->ttl = -1;
+    return reg;
+}
+
+
+/*--------------------------------------------------------------*
+ *                                                             *
+ *                     Force Field Related Code                *
+ *                     (unused yet)                            *
+ *--------------------------------------------------------------*/
+
+boolean
+enter_force_field(p1, p2)
+genericptr_t p1;
+genericptr_t p2;
+{
+    struct monst *mtmp;
+
+    if (p2 == NULL) {          /* That means the player */
+       if (!Blind)
+               You("bump into %s. Ouch!",
+                   Hallucination ? "an invisible tree" :
+                       "some kind of invisible wall");
+       else
+           pline("Ouch!");
+    } else {
+       mtmp = (struct monst *) p2;
+       if (canseemon(mtmp))
+           pline("%s bumps into %s!", Monnam(mtmp), something);
+    }
+    return FALSE;
+}
+
+NhRegion *
+create_force_field(x, y, radius, ttl)
+xchar x, y;
+int radius, ttl;
+{
+    int i;
+    NhRegion *ff;
+    int nrect;
+    NhRect tmprect;
+
+    ff = create_region((NhRect *) 0, 0);
+    nrect = radius;
+    tmprect.lx = x;
+    tmprect.hx = x;
+    tmprect.ly = y - (radius - 1);
+    tmprect.hy = y + (radius - 1);
+    for (i = 0; i < nrect; i++) {
+       add_rect_to_reg(ff, &tmprect);
+       tmprect.lx--;
+       tmprect.hx++;
+       tmprect.ly++;
+       tmprect.hy--;
+    }
+    ff->ttl = ttl;
+    if (!in_mklev && !flags.mon_moving)
+       set_heros_fault(ff);            /* assume player has created it */
+ /* ff->can_enter_f = enter_force_field; */
+ /* ff->can_leave_f = enter_force_field; */
+    add_region(ff);
+    return ff;
+}
+
+#endif /*0*/
+
+/*--------------------------------------------------------------*
+ *                                                             *
+ *                     Gas cloud related code                  *
+ *                                                             *
+ *--------------------------------------------------------------*/
+
+/*
+ * Here is an example of an expire function that may prolong
+ * region life after some mods...
+ */
+boolean
+expire_gas_cloud(p1, p2)
+genericptr_t p1;
+genericptr_t p2;
+{
+    NhRegion *reg;
+    int damage;
+
+    reg = (NhRegion *) p1;
+    damage = (int) reg->arg;
+
+    /* If it was a thick cloud, it dissipates a little first */
+    if (damage >= 5) {
+       damage /= 2;            /* It dissipates, let's do less damage */
+       reg->arg = (genericptr_t) damage;
+       reg->ttl = 2;           /* Here's the trick : reset ttl */
+       return FALSE;           /* THEN return FALSE, means "still there" */
+    }
+    return TRUE;               /* OK, it's gone, you can free it! */
+}
+
+boolean
+inside_gas_cloud(p1, p2)
+genericptr_t p1;
+genericptr_t p2;
+{
+    NhRegion *reg;
+    struct monst *mtmp;
+    int dam;
+
+    reg = (NhRegion *) p1;
+    dam = (int) reg->arg;
+    if (p2 == NULL) {          /* This means *YOU* Bozo! */
+       if (nonliving(youmonst.data) || Breathless)
+           return FALSE;
+       if (!Blind)
+           make_blinded(1L, FALSE);
+       if (!Poison_resistance) {
+           pline("%s is burning your %s!", Something, makeplural(body_part(LUNG)));
+           You("cough and spit blood!");
+           losehp(rnd(dam) + 5, "gas cloud", KILLED_BY_AN);
+           return FALSE;
+       } else {
+           You("cough!");
+           return FALSE;
+       }
+    } else {                   /* A monster is inside the cloud */
+       mtmp = (struct monst *) p2;
+
+       /* Non living and non breathing monsters are not concerned */
+       if (!nonliving(mtmp->data) && !breathless(mtmp->data)) {
+           if (cansee(mtmp->mx, mtmp->my))
+               pline("%s coughs!", Monnam(mtmp));
+           setmangry(mtmp);
+           if (haseyes(mtmp->data) && mtmp->mcansee) {
+               mtmp->mblinded = 1;
+               mtmp->mcansee = 0;
+           }
+           if (resists_poison(mtmp))
+               return FALSE;
+           mtmp->mhp -= rnd(dam) + 5;
+           if (mtmp->mhp <= 0) {
+               if (heros_fault(reg))
+                   killed(mtmp);
+               else
+                   monkilled(mtmp, "gas cloud", AD_DRST);
+               if (mtmp->mhp <= 0) {   /* not lifesaved */
+                   return TRUE;
+               }
+           }
+       }
+    }
+    return FALSE;              /* Monster is still alive */
+}
+
+NhRegion *
+create_gas_cloud(x, y, radius, damage)
+xchar x, y;
+int radius;
+int damage;
+{
+    NhRegion *cloud;
+    int i, nrect;
+    NhRect tmprect;
+
+    cloud = create_region((NhRect *) 0, 0);
+    nrect = radius;
+    tmprect.lx = x;
+    tmprect.hx = x;
+    tmprect.ly = y - (radius - 1);
+    tmprect.hy = y + (radius - 1);
+    for (i = 0; i < nrect; i++) {
+       add_rect_to_reg(cloud, &tmprect);
+       tmprect.lx--;
+       tmprect.hx++;
+       tmprect.ly++;
+       tmprect.hy--;
+    }
+    cloud->ttl = rn1(3,4);
+    if (!in_mklev && !flags.mon_moving)
+       set_heros_fault(cloud);         /* assume player has created it */
+    cloud->inside_f = INSIDE_GAS_CLOUD;
+    cloud->expire_f = EXPIRE_GAS_CLOUD;
+    cloud->arg = (genericptr_t) damage;
+    cloud->visible = TRUE;
+    cloud->glyph = cmap_to_glyph(S_cloud);
+    add_region(cloud);
+    return cloud;
+}
+
+/*region.c*/
diff --git a/src/restore.c b/src/restore.c
new file mode 100644 (file)
index 0000000..aaabbed
--- /dev/null
@@ -0,0 +1,1093 @@
+/*     SCCS Id: @(#)restore.c  3.4     2003/09/06      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "lev.h"
+#include "tcap.h" /* for TERMLIB and ASCIIGRAPH */
+
+#if defined(MICRO)
+extern int dotcnt;     /* shared with save */
+extern int dotrow;     /* shared with save */
+#endif
+
+#ifdef USE_TILES
+extern void FDECL(substitute_tiles, (d_level *));       /* from tile.c */
+#endif
+
+#ifdef ZEROCOMP
+static int NDECL(mgetc);
+#endif
+STATIC_DCL void NDECL(find_lev_obj);
+STATIC_DCL void FDECL(restlevchn, (int));
+STATIC_DCL void FDECL(restdamage, (int,BOOLEAN_P));
+STATIC_DCL struct obj *FDECL(restobjchn, (int,BOOLEAN_P,BOOLEAN_P));
+STATIC_DCL struct monst *FDECL(restmonchn, (int,BOOLEAN_P));
+STATIC_DCL struct fruit *FDECL(loadfruitchn, (int));
+STATIC_DCL void FDECL(freefruitchn, (struct fruit *));
+STATIC_DCL void FDECL(ghostfruit, (struct obj *));
+STATIC_DCL boolean FDECL(restgamestate, (int, unsigned int *, unsigned int *));
+STATIC_DCL void FDECL(restlevelstate, (unsigned int, unsigned int));
+STATIC_DCL int FDECL(restlevelfile, (int,XCHAR_P));
+STATIC_DCL void FDECL(reset_oattached_mids, (BOOLEAN_P));
+
+/*
+ * Save a mapping of IDs from ghost levels to the current level.  This
+ * map is used by the timer routines when restoring ghost levels.
+ */
+#define N_PER_BUCKET 64
+struct bucket {
+    struct bucket *next;
+    struct {
+       unsigned gid;   /* ghost ID */
+       unsigned nid;   /* new ID */
+    } map[N_PER_BUCKET];
+};
+
+STATIC_DCL void NDECL(clear_id_mapping);
+STATIC_DCL void FDECL(add_id_mapping, (unsigned, unsigned));
+
+static int n_ids_mapped = 0;
+static struct bucket *id_map = 0;
+
+
+#ifdef AMII_GRAPHICS
+void FDECL( amii_setpens, (int) );     /* use colors from save file */
+extern int amii_numcolors;
+#endif
+
+#include "quest.h"
+
+boolean restoring = FALSE;
+static NEARDATA struct fruit *oldfruit;
+static NEARDATA long omoves;
+
+#define Is_IceBox(o) ((o)->otyp == ICE_BOX ? TRUE : FALSE)
+
+/* Recalculate level.objects[x][y], since this info was not saved. */
+STATIC_OVL void
+find_lev_obj()
+{
+       register struct obj *fobjtmp = (struct obj *)0;
+       register struct obj *otmp;
+       int x,y;
+
+       for(x=0; x<COLNO; x++) for(y=0; y<ROWNO; y++)
+               level.objects[x][y] = (struct obj *)0;
+
+       /*
+        * Reverse the entire fobj chain, which is necessary so that we can
+        * place the objects in the proper order.  Make all obj in chain
+        * OBJ_FREE so place_object will work correctly.
+        */
+       while ((otmp = fobj) != 0) {
+               fobj = otmp->nobj;
+               otmp->nobj = fobjtmp;
+               otmp->where = OBJ_FREE;
+               fobjtmp = otmp;
+       }
+       /* fobj should now be empty */
+
+       /* Set level.objects (as well as reversing the chain back again) */
+       while ((otmp = fobjtmp) != 0) {
+               fobjtmp = otmp->nobj;
+               place_object(otmp, otmp->ox, otmp->oy);
+       }
+}
+
+/* Things that were marked "in_use" when the game was saved (ex. via the
+ * infamous "HUP" cheat) get used up here.
+ */
+void
+inven_inuse(quietly)
+boolean quietly;
+{
+       register struct obj *otmp, *otmp2;
+
+       for (otmp = invent; otmp; otmp = otmp2) {
+           otmp2 = otmp->nobj;
+#ifndef GOLDOBJ
+           if (otmp->oclass == COIN_CLASS) {
+               /* in_use gold is created by some menu operations */
+               if (!otmp->in_use) {
+                   impossible("inven_inuse: !in_use gold in inventory");
+               }
+               extract_nobj(otmp, &invent);
+               otmp->in_use = FALSE;
+               dealloc_obj(otmp);
+           } else
+#endif /* GOLDOBJ */
+           if (otmp->in_use) {
+               if (!quietly) pline("Finishing off %s...", xname(otmp));
+               useup(otmp);
+           }
+       }
+}
+
+STATIC_OVL void
+restlevchn(fd)
+register int fd;
+{
+       int cnt;
+       s_level *tmplev, *x;
+
+       sp_levchn = (s_level *) 0;
+       mread(fd, (genericptr_t) &cnt, sizeof(int));
+       for(; cnt > 0; cnt--) {
+
+           tmplev = (s_level *)alloc(sizeof(s_level));
+           mread(fd, (genericptr_t) tmplev, sizeof(s_level));
+           if(!sp_levchn) sp_levchn = tmplev;
+           else {
+
+               for(x = sp_levchn; x->next; x = x->next);
+               x->next = tmplev;
+           }
+           tmplev->next = (s_level *)0;
+       }
+}
+
+STATIC_OVL void
+restdamage(fd, ghostly)
+int fd;
+boolean ghostly;
+{
+       int counter;
+       struct damage *tmp_dam;
+
+       mread(fd, (genericptr_t) &counter, sizeof(counter));
+       if (!counter)
+           return;
+       tmp_dam = (struct damage *)alloc(sizeof(struct damage));
+       while (--counter >= 0) {
+           char damaged_shops[5], *shp = (char *)0;
+
+           mread(fd, (genericptr_t) tmp_dam, sizeof(*tmp_dam));
+           if (ghostly)
+               tmp_dam->when += (monstermoves - omoves);
+           Strcpy(damaged_shops,
+                  in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE));
+           if (u.uz.dlevel) {
+               /* when restoring, there are two passes over the current
+                * level.  the first time, u.uz isn't set, so neither is
+                * shop_keeper().  just wait and process the damage on
+                * the second pass.
+                */
+               for (shp = damaged_shops; *shp; shp++) {
+                   struct monst *shkp = shop_keeper(*shp);
+
+                   if (shkp && inhishop(shkp) &&
+                           repair_damage(shkp, tmp_dam, TRUE))
+                       break;
+               }
+           }
+           if (!shp || !*shp) {
+               tmp_dam->next = level.damagelist;
+               level.damagelist = tmp_dam;
+               tmp_dam = (struct damage *)alloc(sizeof(*tmp_dam));
+           }
+       }
+       free((genericptr_t)tmp_dam);
+}
+
+STATIC_OVL struct obj *
+restobjchn(fd, ghostly, frozen)
+register int fd;
+boolean ghostly, frozen;
+{
+       register struct obj *otmp, *otmp2 = 0;
+       register struct obj *first = (struct obj *)0;
+       int xl;
+
+       while(1) {
+               mread(fd, (genericptr_t) &xl, sizeof(xl));
+               if(xl == -1) break;
+               otmp = newobj(xl);
+               if(!first) first = otmp;
+               else otmp2->nobj = otmp;
+               mread(fd, (genericptr_t) otmp,
+                                       (unsigned) xl + sizeof(struct obj));
+               if (ghostly) {
+                   unsigned nid = flags.ident++;
+                   add_id_mapping(otmp->o_id, nid);
+                   otmp->o_id = nid;
+               }
+               if (ghostly && otmp->otyp == SLIME_MOLD) ghostfruit(otmp);
+               /* Ghost levels get object age shifted from old player's clock
+                * to new player's clock.  Assumption: new player arrived
+                * immediately after old player died.
+                */
+               if (ghostly && !frozen && !age_is_relative(otmp))
+                   otmp->age = monstermoves - omoves + otmp->age;
+
+               /* get contents of a container or statue */
+               if (Has_contents(otmp)) {
+                   struct obj *otmp3;
+                   otmp->cobj = restobjchn(fd, ghostly, Is_IceBox(otmp));
+                   /* restore container back pointers */
+                   for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj)
+                       otmp3->ocontainer = otmp;
+               }
+               if (otmp->bypass) otmp->bypass = 0;
+
+               otmp2 = otmp;
+       }
+       if(first && otmp2->nobj){
+               impossible("Restobjchn: error reading objchn.");
+               otmp2->nobj = 0;
+       }
+
+       return(first);
+}
+
+STATIC_OVL struct monst *
+restmonchn(fd, ghostly)
+register int fd;
+boolean ghostly;
+{
+       register struct monst *mtmp, *mtmp2 = 0;
+       register struct monst *first = (struct monst *)0;
+       int xl;
+       struct permonst *monbegin;
+       boolean moved;
+
+       /* get the original base address */
+       mread(fd, (genericptr_t)&monbegin, sizeof(monbegin));
+       moved = (monbegin != mons);
+
+       while(1) {
+               mread(fd, (genericptr_t) &xl, sizeof(xl));
+               if(xl == -1) break;
+               mtmp = newmonst(xl);
+               if(!first) first = mtmp;
+               else mtmp2->nmon = mtmp;
+               mread(fd, (genericptr_t) mtmp, (unsigned) xl + sizeof(struct monst));
+               if (ghostly) {
+                       unsigned nid = flags.ident++;
+                       add_id_mapping(mtmp->m_id, nid);
+                       mtmp->m_id = nid;
+               }
+               if (moved && mtmp->data) {
+                       int offset = mtmp->data - monbegin;     /*(ptrdiff_t)*/
+                       mtmp->data = mons + offset;  /* new permonst location */
+               }
+               if (ghostly) {
+                       int mndx = monsndx(mtmp->data);
+                       if (propagate(mndx, TRUE, ghostly) == 0) {
+                               /* cookie to trigger purge in getbones() */
+                               mtmp->mhpmax = DEFUNCT_MONSTER; 
+                       }
+               }
+               if(mtmp->minvent) {
+                       struct obj *obj;
+                       mtmp->minvent = restobjchn(fd, ghostly, FALSE);
+                       /* restore monster back pointer */
+                       for (obj = mtmp->minvent; obj; obj = obj->nobj)
+                               obj->ocarry = mtmp;
+               }
+               if (mtmp->mw) {
+                       struct obj *obj;
+
+                       for(obj = mtmp->minvent; obj; obj = obj->nobj)
+                               if (obj->owornmask & W_WEP) break;
+                       if (obj) mtmp->mw = obj;
+                       else {
+                               MON_NOWEP(mtmp);
+                               impossible("bad monster weapon restore");
+                       }
+               }
+
+               if (mtmp->isshk) restshk(mtmp, ghostly);
+               if (mtmp->ispriest) restpriest(mtmp, ghostly);
+
+               mtmp2 = mtmp;
+       }
+       if(first && mtmp2->nmon){
+               impossible("Restmonchn: error reading monchn.");
+               mtmp2->nmon = 0;
+       }
+       return(first);
+}
+
+STATIC_OVL struct fruit *
+loadfruitchn(fd)
+int fd;
+{
+       register struct fruit *flist, *fnext;
+
+       flist = 0;
+       while (fnext = newfruit(),
+              mread(fd, (genericptr_t)fnext, sizeof *fnext),
+              fnext->fid != 0) {
+               fnext->nextf = flist;
+               flist = fnext;
+       }
+       dealloc_fruit(fnext);
+       return flist;
+}
+
+STATIC_OVL void
+freefruitchn(flist)
+register struct fruit *flist;
+{
+       register struct fruit *fnext;
+
+       while (flist) {
+           fnext = flist->nextf;
+           dealloc_fruit(flist);
+           flist = fnext;
+       }
+}
+
+STATIC_OVL void
+ghostfruit(otmp)
+register struct obj *otmp;
+{
+       register struct fruit *oldf;
+
+       for (oldf = oldfruit; oldf; oldf = oldf->nextf)
+               if (oldf->fid == otmp->spe) break;
+
+       if (!oldf) impossible("no old fruit?");
+       else otmp->spe = fruitadd(oldf->fname);
+}
+
+STATIC_OVL
+boolean
+restgamestate(fd, stuckid, steedid)
+register int fd;
+unsigned int *stuckid, *steedid;       /* STEED */
+{
+       /* discover is actually flags.explore */
+       boolean remember_discover = discover;
+       struct obj *otmp;
+       int uid;
+
+       mread(fd, (genericptr_t) &uid, sizeof uid);
+       if (uid != getuid()) {          /* strange ... */
+           /* for wizard mode, issue a reminder; for others, treat it
+              as an attempt to cheat and refuse to restore this file */
+           pline("Saved game was not yours.");
+#ifdef WIZARD
+           if (!wizard)
+#endif
+               return FALSE;
+       }
+
+       mread(fd, (genericptr_t) &flags, sizeof(struct flag));
+       flags.bypasses = 0;     /* never use the saved value of bypasses */
+       if (remember_discover) discover = remember_discover;
+
+       role_init();    /* Reset the initial role, race, gender, and alignment */
+#ifdef AMII_GRAPHICS
+       amii_setpens(amii_numcolors);   /* use colors from save file */
+#endif
+       mread(fd, (genericptr_t) &u, sizeof(struct you));
+       set_uasmon();
+#ifdef CLIPPING
+       cliparound(u.ux, u.uy);
+#endif
+       if(u.uhp <= 0 && (!Upolyd || u.mh <= 0)) {
+           u.ux = u.uy = 0;    /* affects pline() [hence You()] */
+           You("were not healthy enough to survive restoration.");
+           /* wiz1_level.dlevel is used by mklev.c to see if lots of stuff is
+            * uninitialized, so we only have to set it and not the other stuff.
+            */
+           wiz1_level.dlevel = 0;
+           u.uz.dnum = 0;
+           u.uz.dlevel = 1;
+           return(FALSE);
+       }
+
+       /* this stuff comes after potential aborted restore attempts */
+       restore_timers(fd, RANGE_GLOBAL, FALSE, 0L);
+       restore_light_sources(fd);
+       invent = restobjchn(fd, FALSE, FALSE);
+       migrating_objs = restobjchn(fd, FALSE, FALSE);
+       migrating_mons = restmonchn(fd, FALSE);
+       mread(fd, (genericptr_t) mvitals, sizeof(mvitals));
+
+       /* this comes after inventory has been loaded */
+       for(otmp = invent; otmp; otmp = otmp->nobj)
+               if(otmp->owornmask)
+                       setworn(otmp, otmp->owornmask);
+       /* reset weapon so that player will get a reminder about "bashing"
+          during next fight when bare-handed or wielding an unconventional
+          item; for pick-axe, we aren't able to distinguish between having
+          applied or wielded it, so be conservative and assume the former */
+       otmp = uwep;    /* `uwep' usually init'd by setworn() in loop above */
+       uwep = 0;       /* clear it and have setuwep() reinit */
+       setuwep(otmp);  /* (don't need any null check here) */
+       if (!uwep || uwep->otyp == PICK_AXE || uwep->otyp == GRAPPLING_HOOK)
+           unweapon = TRUE;
+
+       restore_dungeon(fd);
+       restlevchn(fd);
+       mread(fd, (genericptr_t) &moves, sizeof moves);
+       mread(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
+       mread(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
+       mread(fd, (genericptr_t) spl_book,
+                               sizeof(struct spell) * (MAXSPELL + 1));
+       restore_artifacts(fd);
+       restore_oracles(fd);
+       if (u.ustuck)
+               mread(fd, (genericptr_t) stuckid, sizeof (*stuckid));
+#ifdef STEED
+       if (u.usteed)
+               mread(fd, (genericptr_t) steedid, sizeof (*steedid));
+#endif
+       mread(fd, (genericptr_t) pl_character, sizeof pl_character);
+
+       mread(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
+       mread(fd, (genericptr_t) &current_fruit, sizeof current_fruit);
+       freefruitchn(ffruit);   /* clean up fruit(s) made by initoptions() */
+       ffruit = loadfruitchn(fd);
+
+       restnames(fd);
+       restore_waterlevel(fd);
+       /* must come after all mons & objs are restored */
+       relink_timers(FALSE);
+       relink_light_sources(FALSE);
+       return(TRUE);
+}
+
+/* update game state pointers to those valid for the current level (so we
+ * don't dereference a wild u.ustuck when saving the game state, for instance)
+ */
+STATIC_OVL void
+restlevelstate(stuckid, steedid)
+unsigned int stuckid, steedid; /* STEED */
+{
+       register struct monst *mtmp;
+
+       if (stuckid) {
+               for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+                       if (mtmp->m_id == stuckid) break;
+               if (!mtmp) panic("Cannot find the monster ustuck.");
+               u.ustuck = mtmp;
+       }
+#ifdef STEED
+       if (steedid) {
+               for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+                       if (mtmp->m_id == steedid) break;
+               if (!mtmp) panic("Cannot find the monster usteed.");
+               u.usteed = mtmp;
+               remove_monster(mtmp->mx, mtmp->my);
+       }
+#endif
+}
+
+/*ARGSUSED*/   /* fd used in MFLOPPY only */
+STATIC_OVL int
+restlevelfile(fd, ltmp)
+register int fd;
+xchar ltmp;
+#if defined(macintosh) && (defined(__SC__) || defined(__MRC__))
+# pragma unused(fd)
+#endif
+{
+       register int nfd;
+       char whynot[BUFSZ];
+
+       nfd = create_levelfile(ltmp, whynot);
+       if (nfd < 0) {
+               /* BUG: should suppress any attempt to write a panic
+                  save file if file creation is now failing... */
+               panic("restlevelfile: %s", whynot);
+       }
+#ifdef MFLOPPY
+       if (!savelev(nfd, ltmp, COUNT_SAVE)) {
+
+               /* The savelev can't proceed because the size required
+                * is greater than the available disk space.
+                */
+               pline("Not enough space on `%s' to restore your game.",
+                       levels);
+
+               /* Remove levels and bones that may have been created.
+                */
+               (void) close(nfd);
+# ifdef AMIGA
+               clearlocks();
+# else
+               eraseall(levels, alllevels);
+               eraseall(levels, allbones);
+
+               /* Perhaps the person would like to play without a
+                * RAMdisk.
+                */
+               if (ramdisk) {
+                       /* PlaywoRAMdisk may not return, but if it does
+                        * it is certain that ramdisk will be 0.
+                        */
+                       playwoRAMdisk();
+                       /* Rewind save file and try again */
+                       (void) lseek(fd, (off_t)0, 0);
+                       (void) uptodate(fd, (char *)0); /* skip version */
+                       return dorecover(fd);   /* 0 or 1 */
+               } else {
+# endif
+                       pline("Be seeing you...");
+                       terminate(EXIT_SUCCESS);
+# ifndef AMIGA
+               }
+# endif
+       }
+#endif
+       bufon(nfd);
+       savelev(nfd, ltmp, WRITE_SAVE | FREE_SAVE);
+       bclose(nfd);
+       return(2);
+}
+
+int
+dorecover(fd)
+register int fd;
+{
+       unsigned int stuckid = 0, steedid = 0;  /* not a register */
+       xchar ltmp;
+       int rtmp;
+       struct obj *otmp;
+
+#ifdef STORE_PLNAME_IN_FILE
+       mread(fd, (genericptr_t) plname, PL_NSIZ);
+#endif
+
+       restoring = TRUE;
+       getlev(fd, 0, (xchar)0, FALSE);
+       if (!restgamestate(fd, &stuckid, &steedid)) {
+               display_nhwindow(WIN_MESSAGE, TRUE);
+               savelev(-1, 0, FREE_SAVE);      /* discard current level */
+               (void) close(fd);
+               (void) delete_savefile();
+               restoring = FALSE;
+               return(0);
+       }
+       restlevelstate(stuckid, steedid);
+#ifdef INSURANCE
+       savestateinlock();
+#endif
+       rtmp = restlevelfile(fd, ledger_no(&u.uz));
+       if (rtmp < 2) return(rtmp);  /* dorecover called recursively */
+
+       /* these pointers won't be valid while we're processing the
+        * other levels, but they'll be reset again by restlevelstate()
+        * afterwards, and in the meantime at least u.usteed may mislead
+        * place_monster() on other levels
+        */
+       u.ustuck = (struct monst *)0;
+#ifdef STEED
+       u.usteed = (struct monst *)0;
+#endif
+
+#ifdef MICRO
+# ifdef AMII_GRAPHICS
+       {
+       extern struct window_procs amii_procs;
+       if(windowprocs.win_init_nhwindows== amii_procs.win_init_nhwindows){
+           extern winid WIN_BASE;
+           clear_nhwindow(WIN_BASE);   /* hack until there's a hook for this */
+       }
+       }
+# else
+       clear_nhwindow(WIN_MAP);
+# endif
+       clear_nhwindow(WIN_MESSAGE);
+       You("return to level %d in %s%s.",
+               depth(&u.uz), dungeons[u.uz.dnum].dname,
+               flags.debug ? " while in debug mode" :
+               flags.explore ? " while in explore mode" : "");
+       curs(WIN_MAP, 1, 1);
+       dotcnt = 0;
+       dotrow = 2;
+       if (strncmpi("X11", windowprocs.name, 3))
+         putstr(WIN_MAP, 0, "Restoring:");
+#endif
+       while(1) {
+#ifdef ZEROCOMP
+               if(mread(fd, (genericptr_t) &ltmp, sizeof ltmp) < 0)
+#else
+               if(read(fd, (genericptr_t) &ltmp, sizeof ltmp) != sizeof ltmp)
+#endif
+                       break;
+               getlev(fd, 0, ltmp, FALSE);
+#ifdef MICRO
+               curs(WIN_MAP, 1+dotcnt++, dotrow);
+               if (dotcnt >= (COLNO - 1)) {
+                       dotrow++;
+                       dotcnt = 0;
+               }
+               if (strncmpi("X11", windowprocs.name, 3)){
+                 putstr(WIN_MAP, 0, ".");
+               }
+               mark_synch();
+#endif
+               rtmp = restlevelfile(fd, ltmp);
+               if (rtmp < 2) return(rtmp);  /* dorecover called recursively */
+       }
+
+#ifdef BSD
+       (void) lseek(fd, 0L, 0);
+#else
+       (void) lseek(fd, (off_t)0, 0);
+#endif
+       (void) uptodate(fd, (char *)0);         /* skip version info */
+#ifdef STORE_PLNAME_IN_FILE
+       mread(fd, (genericptr_t) plname, PL_NSIZ);
+#endif
+       getlev(fd, 0, (xchar)0, FALSE);
+       (void) close(fd);
+
+       if (!wizard && !discover)
+               (void) delete_savefile();
+#ifdef REINCARNATION
+       if (Is_rogue_level(&u.uz)) assign_rogue_graphics(TRUE);
+#endif
+#ifdef USE_TILES
+       substitute_tiles(&u.uz);
+#endif
+       restlevelstate(stuckid, steedid);
+#ifdef MFLOPPY
+       gameDiskPrompt();
+#endif
+       max_rank_sz(); /* to recompute mrank_sz (botl.c) */
+       /* take care of iron ball & chain */
+       for(otmp = fobj; otmp; otmp = otmp->nobj)
+               if(otmp->owornmask)
+                       setworn(otmp, otmp->owornmask);
+
+       /* in_use processing must be after:
+        *    + The inventory has been read so that freeinv() works.
+        *    + The current level has been restored so billing information
+        *      is available.
+        */
+       inven_inuse(FALSE);
+
+       load_qtlist();  /* re-load the quest text info */
+       reset_attribute_clock();
+       /* Set up the vision internals, after levl[] data is loaded */
+       /* but before docrt().                                      */
+       vision_reset();
+       vision_full_recalc = 1; /* recompute vision (not saved) */
+
+       run_timers();   /* expire all timers that have gone off while away */
+       docrt();
+       restoring = FALSE;
+       clear_nhwindow(WIN_MESSAGE);
+       program_state.something_worth_saving++; /* useful data now exists */
+
+       /* Success! */
+       welcome(FALSE);
+       return(1);
+}
+
+void
+trickery(reason)
+char *reason;
+{
+       pline("Strange, this map is not as I remember it.");
+       pline("Somebody is trying some trickery here...");
+       pline("This game is void.");
+       killer = reason;
+       done(TRICKED);
+}
+
+void
+getlev(fd, pid, lev, ghostly)
+int fd, pid;
+xchar lev;
+boolean ghostly;
+{
+       register struct trap *trap;
+       register struct monst *mtmp;
+       branch *br;
+       int hpid;
+       xchar dlvl;
+       int x, y;
+#ifdef TOS
+       short tlev;
+#endif
+
+       if (ghostly)
+           clear_id_mapping();
+
+#if defined(MSDOS) || defined(OS2)
+       setmode(fd, O_BINARY);
+#endif
+       /* Load the old fruit info.  We have to do it first, so the
+        * information is available when restoring the objects.
+        */
+       if (ghostly) oldfruit = loadfruitchn(fd);
+
+       /* First some sanity checks */
+       mread(fd, (genericptr_t) &hpid, sizeof(hpid));
+/* CHECK:  This may prevent restoration */
+#ifdef TOS
+       mread(fd, (genericptr_t) &tlev, sizeof(tlev));
+       dlvl=tlev&0x00ff;
+#else
+       mread(fd, (genericptr_t) &dlvl, sizeof(dlvl));
+#endif
+       if ((pid && pid != hpid) || (lev && dlvl != lev)) {
+           char trickbuf[BUFSZ];
+
+           if (pid && pid != hpid)
+               Sprintf(trickbuf, "PID (%d) doesn't match saved PID (%d)!",
+                       hpid, pid);
+           else
+               Sprintf(trickbuf, "This is level %d, not %d!", dlvl, lev);
+#ifdef WIZARD
+           if (wizard) pline(trickbuf);
+#endif
+           trickery(trickbuf);
+       }
+
+#ifdef RLECOMP
+       {
+               short   i, j;
+               uchar   len;
+               struct rm r;
+               
+#if defined(MAC)
+               /* Suppress warning about used before set */
+               (void) memset((genericptr_t) &r, 0, sizeof(r));
+#endif
+               i = 0; j = 0; len = 0;
+               while(i < ROWNO) {
+                   while(j < COLNO) {
+                       if(len > 0) {
+                           levl[j][i] = r;
+                           len -= 1;
+                           j += 1;
+                       } else {
+                           mread(fd, (genericptr_t)&len, sizeof(uchar));
+                           mread(fd, (genericptr_t)&r, sizeof(struct rm));
+                       }
+                   }
+                   j = 0;
+                   i += 1;
+               }
+       }
+#else
+       mread(fd, (genericptr_t) levl, sizeof(levl));
+#endif /* RLECOMP */
+
+       mread(fd, (genericptr_t)&omoves, sizeof(omoves));
+       mread(fd, (genericptr_t)&upstair, sizeof(stairway));
+       mread(fd, (genericptr_t)&dnstair, sizeof(stairway));
+       mread(fd, (genericptr_t)&upladder, sizeof(stairway));
+       mread(fd, (genericptr_t)&dnladder, sizeof(stairway));
+       mread(fd, (genericptr_t)&sstairs, sizeof(stairway));
+       mread(fd, (genericptr_t)&updest, sizeof(dest_area));
+       mread(fd, (genericptr_t)&dndest, sizeof(dest_area));
+       mread(fd, (genericptr_t)&level.flags, sizeof(level.flags));
+       mread(fd, (genericptr_t)doors, sizeof(doors));
+       rest_rooms(fd);         /* No joke :-) */
+       if (nroom)
+           doorindex = rooms[nroom - 1].fdoor + rooms[nroom - 1].doorct;
+       else
+           doorindex = 0;
+
+       restore_timers(fd, RANGE_LEVEL, ghostly, monstermoves - omoves);
+       restore_light_sources(fd);
+       fmon = restmonchn(fd, ghostly);
+
+       /* regenerate animals while on another level */
+       if (u.uz.dlevel) {
+           register struct monst *mtmp2;
+
+           for (mtmp = fmon; mtmp; mtmp = mtmp2) {
+               mtmp2 = mtmp->nmon;
+               if (ghostly) {
+                       /* reset peaceful/malign relative to new character */
+                       if(!mtmp->isshk)
+                               /* shopkeepers will reset based on name */
+                               mtmp->mpeaceful = peace_minded(mtmp->data);
+                       set_malign(mtmp);
+               } else if (monstermoves > omoves)
+                       mon_catchup_elapsed_time(mtmp, monstermoves - omoves);
+
+               /* update shape-changers in case protection against
+                  them is different now than when the level was saved */
+               restore_cham(mtmp);
+           }
+       }
+
+       rest_worm(fd);  /* restore worm information */
+       ftrap = 0;
+       while (trap = newtrap(),
+              mread(fd, (genericptr_t)trap, sizeof(struct trap)),
+              trap->tx != 0) { /* need "!= 0" to work around DICE 3.0 bug */
+               trap->ntrap = ftrap;
+               ftrap = trap;
+       }
+       dealloc_trap(trap);
+       fobj = restobjchn(fd, ghostly, FALSE);
+       find_lev_obj();
+       /* restobjchn()'s `frozen' argument probably ought to be a callback
+          routine so that we can check for objects being buried under ice */
+       level.buriedobjlist = restobjchn(fd, ghostly, FALSE);
+       billobjs = restobjchn(fd, ghostly, FALSE);
+       rest_engravings(fd);
+
+       /* reset level.monsters for new level */
+       for (x = 0; x < COLNO; x++)
+           for (y = 0; y < ROWNO; y++)
+               level.monsters[x][y] = (struct monst *) 0;
+       for (mtmp = level.monlist; mtmp; mtmp = mtmp->nmon) {
+           if (mtmp->isshk)
+               set_residency(mtmp, FALSE);
+           place_monster(mtmp, mtmp->mx, mtmp->my);
+           if (mtmp->wormno) place_wsegs(mtmp);
+       }
+       restdamage(fd, ghostly);
+
+       rest_regions(fd, ghostly);
+       if (ghostly) {
+           /* Now get rid of all the temp fruits... */
+           freefruitchn(oldfruit),  oldfruit = 0;
+
+           if (lev > ledger_no(&medusa_level) &&
+                       lev < ledger_no(&stronghold_level) && xdnstair == 0) {
+               coord cc;
+
+               mazexy(&cc);
+               xdnstair = cc.x;
+               ydnstair = cc.y;
+               levl[cc.x][cc.y].typ = STAIRS;
+           }
+
+           br = Is_branchlev(&u.uz);
+           if (br && u.uz.dlevel == 1) {
+               d_level ltmp;
+
+               if (on_level(&u.uz, &br->end1))
+                   assign_level(&ltmp, &br->end2);
+               else
+                   assign_level(&ltmp, &br->end1);
+
+               switch(br->type) {
+               case BR_STAIR:
+               case BR_NO_END1:
+               case BR_NO_END2: /* OK to assign to sstairs if it's not used */
+                   assign_level(&sstairs.tolev, &ltmp);
+                   break;              
+               case BR_PORTAL: /* max of 1 portal per level */
+                   {
+                       register struct trap *ttmp;
+                       for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
+                           if (ttmp->ttyp == MAGIC_PORTAL)
+                               break;
+                       if (!ttmp) panic("getlev: need portal but none found");
+                       assign_level(&ttmp->dst, &ltmp);
+                   }
+                   break;
+               }
+           } else if (!br) {
+               /* Remove any dangling portals. */
+               register struct trap *ttmp;
+               for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
+                   if (ttmp->ttyp == MAGIC_PORTAL) {
+                       deltrap(ttmp);
+                       break; /* max of 1 portal/level */
+                   }
+           }
+       }
+
+       /* must come after all mons & objs are restored */
+       relink_timers(ghostly);
+       relink_light_sources(ghostly);
+       reset_oattached_mids(ghostly);
+
+       if (ghostly)
+           clear_id_mapping();
+}
+
+
+/* Clear all structures for object and monster ID mapping. */
+STATIC_OVL void
+clear_id_mapping()
+{
+    struct bucket *curr;
+
+    while ((curr = id_map) != 0) {
+       id_map = curr->next;
+       free((genericptr_t) curr);
+    }
+    n_ids_mapped = 0;
+}
+
+/* Add a mapping to the ID map. */
+STATIC_OVL void
+add_id_mapping(gid, nid)
+    unsigned gid, nid;
+{
+    int idx;
+
+    idx = n_ids_mapped % N_PER_BUCKET;
+    /* idx is zero on first time through, as well as when a new bucket is */
+    /* needed */
+    if (idx == 0) {
+       struct bucket *gnu = (struct bucket *) alloc(sizeof(struct bucket));
+       gnu->next = id_map;
+       id_map = gnu;
+    }
+
+    id_map->map[idx].gid = gid;
+    id_map->map[idx].nid = nid;
+    n_ids_mapped++;
+}
+
+/*
+ * Global routine to look up a mapping.  If found, return TRUE and fill
+ * in the new ID value.  Otherwise, return false and return -1 in the new
+ * ID.
+ */
+boolean
+lookup_id_mapping(gid, nidp)
+    unsigned gid, *nidp;
+{
+    int i;
+    struct bucket *curr;
+
+    if (n_ids_mapped)
+       for (curr = id_map; curr; curr = curr->next) {
+           /* first bucket might not be totally full */
+           if (curr == id_map) {
+               i = n_ids_mapped % N_PER_BUCKET;
+               if (i == 0) i = N_PER_BUCKET;
+           } else
+               i = N_PER_BUCKET;
+
+           while (--i >= 0)
+               if (gid == curr->map[i].gid) {
+                   *nidp = curr->map[i].nid;
+                   return TRUE;
+               }
+       }
+
+    return FALSE;
+}
+
+STATIC_OVL void
+reset_oattached_mids(ghostly)
+boolean ghostly;
+{
+    struct obj *otmp;
+    unsigned oldid, nid;
+    for (otmp = fobj; otmp; otmp = otmp->nobj) {
+       if (ghostly && otmp->oattached == OATTACHED_MONST && otmp->oxlth) {
+           struct monst *mtmp = (struct monst *)otmp->oextra;
+
+           mtmp->m_id = 0;
+           mtmp->mpeaceful = mtmp->mtame = 0;  /* pet's owner died! */
+       }
+       if (ghostly && otmp->oattached == OATTACHED_M_ID) {
+           (void) memcpy((genericptr_t)&oldid, (genericptr_t)otmp->oextra,
+                                                               sizeof(oldid));
+           if (lookup_id_mapping(oldid, &nid))
+               (void) memcpy((genericptr_t)otmp->oextra, (genericptr_t)&nid,
+                                                               sizeof(nid));
+           else
+               otmp->oattached = OATTACHED_NOTHING;
+       }
+    }
+}
+
+
+#ifdef ZEROCOMP
+#define RLESC '\0'     /* Leading character for run of RLESC's */
+
+#ifndef ZEROCOMP_BUFSIZ
+#define ZEROCOMP_BUFSIZ BUFSZ
+#endif
+static NEARDATA unsigned char inbuf[ZEROCOMP_BUFSIZ];
+static NEARDATA unsigned short inbufp = 0;
+static NEARDATA unsigned short inbufsz = 0;
+static NEARDATA short inrunlength = -1;
+static NEARDATA int mreadfd;
+
+static int
+mgetc()
+{
+    if (inbufp >= inbufsz) {
+       inbufsz = read(mreadfd, (genericptr_t)inbuf, sizeof inbuf);
+       if (!inbufsz) {
+           if (inbufp > sizeof inbuf)
+               error("EOF on file #%d.\n", mreadfd);
+           inbufp = 1 + sizeof inbuf;  /* exactly one warning :-) */
+           return -1;
+       }
+       inbufp = 0;
+    }
+    return inbuf[inbufp++];
+}
+
+void
+minit()
+{
+    inbufsz = 0;
+    inbufp = 0;
+    inrunlength = -1;
+}
+
+int
+mread(fd, buf, len)
+int fd;
+genericptr_t buf;
+register unsigned len;
+{
+    /*register int readlen = 0;*/
+    if (fd < 0) error("Restore error; mread attempting to read file %d.", fd);
+    mreadfd = fd;
+    while (len--) {
+       if (inrunlength > 0) {
+           inrunlength--;
+           *(*((char **)&buf))++ = '\0';
+       } else {
+           register short ch = mgetc();
+           if (ch < 0) return -1; /*readlen;*/
+           if ((*(*(char **)&buf)++ = (char)ch) == RLESC) {
+               inrunlength = mgetc();
+           }
+       }
+       /*readlen++;*/
+    }
+    return 0; /*readlen;*/
+}
+
+#else /* ZEROCOMP */
+
+void
+minit()
+{
+    return;
+}
+
+void
+mread(fd, buf, len)
+register int fd;
+register genericptr_t buf;
+register unsigned int len;
+{
+       register int rlen;
+
+#if defined(BSD) || defined(ULTRIX)
+       rlen = read(fd, buf, (int) len);
+       if(rlen != len){
+#else /* e.g. SYSV, __TURBOC__ */
+       rlen = read(fd, buf, (unsigned) len);
+       if((unsigned)rlen != len){
+#endif
+               pline("Read %d instead of %u bytes.", rlen, len);
+               if(restoring) {
+                       (void) close(fd);
+                       (void) delete_savefile();
+                       error("Error restoring old game.");
+               }
+               panic("Error reading level file.");
+       }
+}
+#endif /* ZEROCOMP */
+
+/*restore.c*/
diff --git a/src/rip.c b/src/rip.c
new file mode 100644 (file)
index 0000000..9a82630
--- /dev/null
+++ b/src/rip.c
@@ -0,0 +1,175 @@
+/*     SCCS Id: @(#)rip.c      3.4     2003/01/08      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+STATIC_DCL void FDECL(center, (int, char *));
+
+extern const char * const killed_by_prefix[];  /* from topten.c */
+
+#if defined(TTY_GRAPHICS) || defined(X11_GRAPHICS) || defined(GEM_GRAPHICS) || defined(MSWIN_GRAPHICS)
+# define TEXT_TOMBSTONE
+#endif
+#if defined(mac) || defined(__BEOS__) || defined(WIN32_GRAPHICS)
+# ifndef TEXT_TOMBSTONE
+#  define TEXT_TOMBSTONE
+# endif
+#endif
+
+#ifdef TEXT_TOMBSTONE
+
+#ifndef NH320_DEDICATION
+/* A normal tombstone for end of game display. */
+static const char *rip_txt[] = {
+"                       ----------",
+"                      /          \\",
+"                     /    REST    \\",
+"                    /      IN      \\",
+"                   /     PEACE      \\",
+"                  /                  \\",
+"                  |                  |", /* Name of player */
+"                  |                  |", /* Amount of $ */
+"                  |                  |", /* Type of death */
+"                  |                  |", /* . */
+"                  |                  |", /* . */
+"                  |                  |", /* . */
+"                  |       1001       |", /* Real year of death */
+"                 *|     *  *  *      | *",
+"        _________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______",
+0
+};
+#define STONE_LINE_CENT 28     /* char[] element of center of stone face */
+#else  /* NH320_DEDICATION */
+/* NetHack 3.2.x displayed a dual tombstone as a tribute to Izchak. */
+static const char *rip_txt[] = {
+"              ----------                      ----------",
+"             /          \\                    /          \\",
+"            /    REST    \\                  /    This    \\",
+"           /      IN      \\                /  release of  \\",
+"          /     PEACE      \\              /   NetHack is   \\",
+"         /                  \\            /   dedicated to   \\",
+"         |                  |            |  the memory of   |",
+"         |                  |            |                  |",
+"         |                  |            |  Izchak Miller   |",
+"         |                  |            |   1935 - 1994    |",
+"         |                  |            |                  |",
+"         |                  |            |     Ascended     |",
+"         |       1001       |            |                  |",
+"      *  |     *  *  *      | *        * |      *  *  *     | *",
+" _____)/\\|\\__//(\\/(/\\)/\\//\\/|_)________)/|\\\\_/_/(\\/(/\\)/\\/\\/|_)____",
+0
+};
+#define STONE_LINE_CENT 19     /* char[] element of center of stone face */
+#endif /* NH320_DEDICATION */
+#define STONE_LINE_LEN 16      /* # chars that fit on one line
+                                * (note 1 ' ' border)
+                                */
+#define NAME_LINE 6            /* *char[] line # for player name */
+#define GOLD_LINE 7            /* *char[] line # for amount of gold */
+#define DEATH_LINE 8           /* *char[] line # for death description */
+#define YEAR_LINE 12           /* *char[] line # for year */
+
+static char **rip;
+
+STATIC_OVL void
+center(line, text)
+int line;
+char *text;
+{
+       register char *ip,*op;
+       ip = text;
+       op = &rip[line][STONE_LINE_CENT - ((strlen(text)+1)>>1)];
+       while(*ip) *op++ = *ip++;
+}
+
+
+void
+genl_outrip(tmpwin, how)
+winid tmpwin;
+int how;
+{
+       register char **dp;
+       register char *dpx;
+       char buf[BUFSZ];
+       register int x;
+       int line;
+
+       rip = dp = (char **) alloc(sizeof(rip_txt));
+       for (x = 0; rip_txt[x]; x++) {
+               dp[x] = (char *) alloc((unsigned int)(strlen(rip_txt[x]) + 1));
+               Strcpy(dp[x], rip_txt[x]);
+       }
+       dp[x] = (char *)0;
+
+       /* Put name on stone */
+       Sprintf(buf, "%s", plname);
+       buf[STONE_LINE_LEN] = 0;
+       center(NAME_LINE, buf);
+
+       /* Put $ on stone */
+#ifndef GOLDOBJ
+       Sprintf(buf, "%ld Au", u.ugold);
+#else
+       Sprintf(buf, "%ld Au", done_money);
+#endif
+       buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */
+       center(GOLD_LINE, buf);
+
+       /* Put together death description */
+       switch (killer_format) {
+               default: impossible("bad killer format?");
+               case KILLED_BY_AN:
+                       Strcpy(buf, killed_by_prefix[how]);
+                       Strcat(buf, an(killer));
+                       break;
+               case KILLED_BY:
+                       Strcpy(buf, killed_by_prefix[how]);
+                       Strcat(buf, killer);
+                       break;
+               case NO_KILLER_PREFIX:
+                       Strcpy(buf, killer);
+                       break;
+       }
+
+       /* Put death type on stone */
+       for (line=DEATH_LINE, dpx = buf; line<YEAR_LINE; line++) {
+               register int i,i0;
+               char tmpchar;
+
+               if ( (i0=strlen(dpx)) > STONE_LINE_LEN) {
+                               for(i = STONE_LINE_LEN;
+                                   ((i0 > STONE_LINE_LEN) && i); i--)
+                                       if(dpx[i] == ' ') i0 = i;
+                               if(!i) i0 = STONE_LINE_LEN;
+               }
+               tmpchar = dpx[i0];
+               dpx[i0] = 0;
+               center(line, dpx);
+               if (tmpchar != ' ') {
+                       dpx[i0] = tmpchar;
+                       dpx= &dpx[i0];
+               } else  dpx= &dpx[i0+1];
+       }
+
+       /* Put year on stone */
+       Sprintf(buf, "%4d", getyear());
+       center(YEAR_LINE, buf);
+
+       putstr(tmpwin, 0, "");
+       for(; *dp; dp++)
+               putstr(tmpwin, 0, *dp);
+
+       putstr(tmpwin, 0, "");
+       putstr(tmpwin, 0, "");
+
+       for (x = 0; rip_txt[x]; x++) {
+               free((genericptr_t)rip[x]);
+       }
+       free((genericptr_t)rip);
+       rip = 0;
+}
+
+#endif /* TEXT_TOMBSTONE */
+
+/*rip.c*/
diff --git a/src/rnd.c b/src/rnd.c
new file mode 100644 (file)
index 0000000..313b70b
--- /dev/null
+++ b/src/rnd.c
@@ -0,0 +1,145 @@
+/*     SCCS Id: @(#)rnd.c      3.4     1996/02/07      */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+/* "Rand()"s definition is determined by [OS]conf.h */
+#if defined(LINT) && defined(UNIX)     /* rand() is long... */
+extern int NDECL(rand);
+#define RND(x) (rand() % x)
+#else /* LINT */
+# if defined(UNIX) || defined(RANDOM)
+#define RND(x) (int)(Rand() % (long)(x))
+# else
+/* Good luck: the bottom order bits are cyclic. */
+#define RND(x) (int)((Rand()>>3) % (x))
+# endif
+#endif /* LINT */
+
+#ifdef OVL0
+
+int
+rn2(x)         /* 0 <= rn2(x) < x */
+register int x;
+{
+#ifdef DEBUG
+       if (x <= 0) {
+               impossible("rn2(%d) attempted", x);
+               return(0);
+       }
+       x = RND(x);
+       return(x);
+#else
+       return(RND(x));
+#endif
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+int
+rnl(x)         /* 0 <= rnl(x) < x; sometimes subtracting Luck */
+register int x;        /* good luck approaches 0, bad luck approaches (x-1) */
+{
+       register int i;
+
+#ifdef DEBUG
+       if (x <= 0) {
+               impossible("rnl(%d) attempted", x);
+               return(0);
+       }
+#endif
+       i = RND(x);
+
+       if (Luck && rn2(50 - Luck)) {
+           i -= (x <= 15 && Luck >= -5 ? Luck/3 : Luck);
+           if (i < 0) i = 0;
+           else if (i >= x) i = x-1;
+       }
+
+       return i;
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+int
+rnd(x)         /* 1 <= rnd(x) <= x */
+register int x;
+{
+#ifdef DEBUG
+       if (x <= 0) {
+               impossible("rnd(%d) attempted", x);
+               return(1);
+       }
+       x = RND(x)+1;
+       return(x);
+#else
+       return(RND(x)+1);
+#endif
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+int
+d(n,x)         /* n <= d(n,x) <= (n*x) */
+register int n, x;
+{
+       register int tmp = n;
+
+#ifdef DEBUG
+       if (x < 0 || n < 0 || (x == 0 && n != 0)) {
+               impossible("d(%d,%d) attempted", n, x);
+               return(1);
+       }
+#endif
+       while(n--) tmp += RND(x);
+       return(tmp); /* Alea iacta est. -- J.C. */
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+int
+rne(x)
+register int x;
+{
+       register int tmp, utmp;
+
+       utmp = (u.ulevel < 15) ? 5 : u.ulevel/3;
+       tmp = 1;
+       while (tmp < utmp && !rn2(x))
+               tmp++;
+       return tmp;
+
+       /* was:
+        *      tmp = 1;
+        *      while(!rn2(x)) tmp++;
+        *      return(min(tmp,(u.ulevel < 15) ? 5 : u.ulevel/3));
+        * which is clearer but less efficient and stands a vanishingly
+        * small chance of overflowing tmp
+        */
+}
+
+int
+rnz(i)
+int i;
+{
+#ifdef LINT
+       int x = i;
+       int tmp = 1000;
+#else
+       register long x = i;
+       register long tmp = 1000;
+#endif
+       tmp += rn2(1000);
+       tmp *= rne(4);
+       if (rn2(2)) { x *= tmp; x /= 1000; }
+       else { x *= 1000; x /= tmp; }
+       return((int)x);
+}
+
+#endif /* OVLB */
+
+/*rnd.c*/
diff --git a/src/role.c b/src/role.c
new file mode 100644 (file)
index 0000000..c751d10
--- /dev/null
@@ -0,0 +1,1491 @@
+/*     SCCS Id: @(#)role.c     3.4     2003/01/08      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985-1999. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+
+/*** Table of all roles ***/
+/* According to AD&D, HD for some classes (ex. Wizard) should be smaller
+ * (4-sided for wizards).  But this is not AD&D, and using the AD&D
+ * rule here produces an unplayable character.  Thus I have used a minimum
+ * of an 10-sided hit die for everything.  Another AD&D change: wizards get
+ * a minimum strength of 4 since without one you can't teleport or cast
+ * spells. --KAA
+ *
+ * As the wizard has been updated (wizard patch 5 jun '96) their HD can be
+ * brought closer into line with AD&D. This forces wizards to use magic more
+ * and distance themselves from their attackers. --LSZ
+ *
+ * With the introduction of races, some hit points and energy
+ * has been reallocated for each race.  The values assigned
+ * to the roles has been reduced by the amount allocated to
+ * humans.  --KMH
+ *
+ * God names use a leading underscore to flag goddesses.
+ */
+const struct Role roles[] = {
+{      {"Archeologist", 0}, {
+       {"Digger",      0},
+       {"Field Worker",0},
+       {"Investigator",0},
+       {"Exhumer",     0},
+       {"Excavator",   0},
+       {"Spelunker",   0},
+       {"Speleologist",0},
+       {"Collector",   0},
+       {"Curator",     0} },
+       "Quetzalcoatl", "Camaxtli", "Huhetotl", /* Central American */
+       "Arc", "the College of Archeology", "the Tomb of the Toltec Kings",
+       PM_ARCHEOLOGIST, NON_PM, NON_PM,
+       PM_LORD_CARNARVON, PM_STUDENT, PM_MINION_OF_HUHETOTL,
+       NON_PM, PM_HUMAN_MUMMY, S_SNAKE, S_MUMMY,
+       ART_ORB_OF_DETECTION,
+       MH_HUMAN|MH_DWARF|MH_GNOME | ROLE_MALE|ROLE_FEMALE |
+         ROLE_LAWFUL|ROLE_NEUTRAL,
+       /* Str Int Wis Dex Con Cha */
+       {   7, 10, 10,  7,  7,  7 },
+       {  20, 20, 20, 10, 20, 10 },
+       /* Init   Lower  Higher */
+       { 11, 0,  0, 8,  1, 0 },        /* Hit points */
+       {  1, 0,  0, 1,  0, 1 },14,     /* Energy */
+       10, 5, 0, 2, 10, A_INT, SPE_MAGIC_MAPPING,   -4
+},
+{      {"Barbarian", 0}, {
+       {"Plunderer",   "Plunderess"},
+       {"Pillager",    0},
+       {"Bandit",      0},
+       {"Brigand",     0},
+       {"Raider",      0},
+       {"Reaver",      0},
+       {"Slayer",      0},
+       {"Chieftain",   "Chieftainess"},
+       {"Conqueror",   "Conqueress"} },
+       "Mitra", "Crom", "Set", /* Hyborian */
+       "Bar", "the Camp of the Duali Tribe", "the Duali Oasis",
+       PM_BARBARIAN, NON_PM, NON_PM,
+       PM_PELIAS, PM_CHIEFTAIN, PM_THOTH_AMON,
+       PM_OGRE, PM_TROLL, S_OGRE, S_TROLL,
+       ART_HEART_OF_AHRIMAN,
+       MH_HUMAN|MH_ORC | ROLE_MALE|ROLE_FEMALE |
+         ROLE_NEUTRAL|ROLE_CHAOTIC,
+       /* Str Int Wis Dex Con Cha */
+       {  16,  7,  7, 15, 16,  6 },
+       {  30,  6,  7, 20, 30,  7 },
+       /* Init   Lower  Higher */
+       { 14, 0,  0,10,  2, 0 },        /* Hit points */
+       {  1, 0,  0, 1,  0, 1 },10,     /* Energy */
+       10, 14, 0, 0,  8, A_INT, SPE_HASTE_SELF,      -4
+},
+{      {"Caveman", "Cavewoman"}, {
+       {"Troglodyte",  0},
+       {"Aborigine",   0},
+       {"Wanderer",    0},
+       {"Vagrant",     0},
+       {"Wayfarer",    0},
+       {"Roamer",      0},
+       {"Nomad",       0},
+       {"Rover",       0},
+       {"Pioneer",     0} },
+       "Anu", "_Ishtar", "Anshar", /* Babylonian */
+       "Cav", "the Caves of the Ancestors", "the Dragon's Lair",
+       PM_CAVEMAN, PM_CAVEWOMAN, PM_LITTLE_DOG,
+       PM_SHAMAN_KARNOV, PM_NEANDERTHAL, PM_CHROMATIC_DRAGON,
+       PM_BUGBEAR, PM_HILL_GIANT, S_HUMANOID, S_GIANT,
+       ART_SCEPTRE_OF_MIGHT,
+       MH_HUMAN|MH_DWARF|MH_GNOME | ROLE_MALE|ROLE_FEMALE |
+         ROLE_LAWFUL|ROLE_NEUTRAL,
+       /* Str Int Wis Dex Con Cha */
+       {  10,  7,  7,  7,  8,  6 },
+       {  30,  6,  7, 20, 30,  7 },
+       /* Init   Lower  Higher */
+       { 14, 0,  0, 8,  2, 0 },        /* Hit points */
+       {  1, 0,  0, 1,  0, 1 },10,     /* Energy */
+       0, 12, 0, 1,  8, A_INT, SPE_DIG,             -4
+},
+{      {"Healer", 0}, {
+       {"Rhizotomist",    0},
+       {"Empiric",        0},
+       {"Embalmer",       0},
+       {"Dresser",        0},
+       {"Medicus ossium", "Medica ossium"},
+       {"Herbalist",      0},
+       {"Magister",       "Magistra"},
+       {"Physician",      0},
+       {"Chirurgeon",     0} },
+       "_Athena", "Hermes", "Poseidon", /* Greek */
+       "Hea", "the Temple of Epidaurus", "the Temple of Coeus",
+       PM_HEALER, NON_PM, NON_PM,
+       PM_HIPPOCRATES, PM_ATTENDANT, PM_CYCLOPS,
+       PM_GIANT_RAT, PM_SNAKE, S_RODENT, S_YETI,
+       ART_STAFF_OF_AESCULAPIUS,
+       MH_HUMAN|MH_GNOME | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL,
+       /* Str Int Wis Dex Con Cha */
+       {   7,  7, 13,  7, 11, 16 },
+       {  15, 20, 20, 15, 25, 5 },
+       /* Init   Lower  Higher */
+       { 11, 0,  0, 8,  1, 0 },        /* Hit points */
+       {  1, 4,  0, 1,  0, 2 },20,     /* Energy */
+       10, 3,-3, 2, 10, A_WIS, SPE_CURE_SICKNESS,   -4
+},
+{      {"Knight", 0}, {
+       {"Gallant",     0},
+       {"Esquire",     0},
+       {"Bachelor",    0},
+       {"Sergeant",    0},
+       {"Knight",      0},
+       {"Banneret",    0},
+       {"Chevalier",   "Chevaliere"},
+       {"Seignieur",   "Dame"},
+       {"Paladin",     0} },
+       "Lugh", "_Brigit", "Manannan Mac Lir", /* Celtic */
+       "Kni", "Camelot Castle", "the Isle of Glass",
+       PM_KNIGHT, NON_PM, PM_PONY,
+       PM_KING_ARTHUR, PM_PAGE, PM_IXOTH,
+       PM_QUASIT, PM_OCHRE_JELLY, S_IMP, S_JELLY,
+       ART_MAGIC_MIRROR_OF_MERLIN,
+       MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL,
+       /* Str Int Wis Dex Con Cha */
+       {  13,  7, 14,  8, 10, 17 },
+       {  30, 15, 15, 10, 20, 10 },
+       /* Init   Lower  Higher */
+       { 14, 0,  0, 8,  2, 0 },        /* Hit points */
+       {  1, 4,  0, 1,  0, 2 },10,     /* Energy */
+       10, 8,-2, 0,  9, A_WIS, SPE_TURN_UNDEAD,     -4
+},
+{      {"Monk", 0}, {
+       {"Candidate",         0},
+       {"Novice",            0},
+       {"Initiate",          0},
+       {"Student of Stones", 0},
+       {"Student of Waters", 0},
+       {"Student of Metals", 0},
+       {"Student of Winds",  0},
+       {"Student of Fire",   0},
+       {"Master",            0} },
+       "Shan Lai Ching", "Chih Sung-tzu", "Huan Ti", /* Chinese */
+       "Mon", "the Monastery of Chan-Sune",
+         "the Monastery of the Earth-Lord",
+       PM_MONK, NON_PM, NON_PM,
+       PM_GRAND_MASTER, PM_ABBOT, PM_MASTER_KAEN,
+       PM_EARTH_ELEMENTAL, PM_XORN, S_ELEMENTAL, S_XORN,
+       ART_EYES_OF_THE_OVERWORLD,
+       MH_HUMAN | ROLE_MALE|ROLE_FEMALE |
+         ROLE_LAWFUL|ROLE_NEUTRAL|ROLE_CHAOTIC,
+       /* Str Int Wis Dex Con Cha */
+       {  10,  7,  8,  8,  7,  7 },
+       {  25, 10, 20, 20, 15, 10 },
+       /* Init   Lower  Higher */
+       { 12, 0,  0, 8,  1, 0 },        /* Hit points */
+       {  2, 2,  0, 2,  0, 2 },10,     /* Energy */
+       10, 8,-2, 2, 20, A_WIS, SPE_RESTORE_ABILITY, -4
+},
+{      {"Priest", "Priestess"}, {
+       {"Aspirant",    0},
+       {"Acolyte",     0},
+       {"Adept",       0},
+       {"Priest",      "Priestess"},
+       {"Curate",      0},
+       {"Canon",       "Canoness"},
+       {"Lama",        0},
+       {"Patriarch",   "Matriarch"},
+       {"High Priest", "High Priestess"} },
+       0, 0, 0,        /* chosen randomly from among the other roles */
+       "Pri", "the Great Temple", "the Temple of Nalzok",
+       PM_PRIEST, PM_PRIESTESS, NON_PM,
+       PM_ARCH_PRIEST, PM_ACOLYTE, PM_NALZOK,
+       PM_HUMAN_ZOMBIE, PM_WRAITH, S_ZOMBIE, S_WRAITH,
+       ART_MITRE_OF_HOLINESS,
+       MH_HUMAN|MH_ELF | ROLE_MALE|ROLE_FEMALE |
+         ROLE_LAWFUL|ROLE_NEUTRAL|ROLE_CHAOTIC,
+       /* Str Int Wis Dex Con Cha */
+       {   7,  7, 10,  7,  7,  7 },
+       {  15, 10, 30, 15, 20, 10 },
+       /* Init   Lower  Higher */
+       { 12, 0,  0, 8,  1, 0 },        /* Hit points */
+       {  4, 3,  0, 2,  0, 2 },10,     /* Energy */
+       0, 3,-2, 2, 10, A_WIS, SPE_REMOVE_CURSE,    -4
+},
+  /* Note:  Rogue precedes Ranger so that use of `-R' on the command line
+     retains its traditional meaning. */
+{      {"Rogue", 0}, {
+       {"Footpad",     0},
+       {"Cutpurse",    0},
+       {"Rogue",       0},
+       {"Pilferer",    0},
+       {"Robber",      0},
+       {"Burglar",     0},
+       {"Filcher",     0},
+       {"Magsman",     "Magswoman"},
+       {"Thief",       0} },
+       "Issek", "Mog", "Kos", /* Nehwon */
+       "Rog", "the Thieves' Guild Hall", "the Assassins' Guild Hall",
+       PM_ROGUE, NON_PM, NON_PM,
+       PM_MASTER_OF_THIEVES, PM_THUG, PM_MASTER_ASSASSIN,
+       PM_LEPRECHAUN, PM_GUARDIAN_NAGA, S_NYMPH, S_NAGA,
+       ART_MASTER_KEY_OF_THIEVERY,
+       MH_HUMAN|MH_ORC | ROLE_MALE|ROLE_FEMALE |
+         ROLE_CHAOTIC,
+       /* Str Int Wis Dex Con Cha */
+       {   7,  7,  7, 10,  7,  6 },
+       {  20, 10, 10, 30, 20, 10 },
+       /* Init   Lower  Higher */
+       { 10, 0,  0, 8,  1, 0 },        /* Hit points */
+       {  1, 0,  0, 1,  0, 1 },11,     /* Energy */
+       10, 8, 0, 1,  9, A_INT, SPE_DETECT_TREASURE, -4
+},
+{      {"Ranger", 0}, {
+#if 0  /* OBSOLETE */
+       {"Edhel",       "Elleth"},
+       {"Edhel",       "Elleth"},      /* elf-maid */
+       {"Ohtar",       "Ohtie"},       /* warrior */
+       {"Kano",                        /* commander (Q.) ['a] */
+                       "Kanie"},       /* educated guess, until further research- SAC */
+       {"Arandur",                     /* king's servant, minister (Q.) - guess */
+                       "Aranduriel"},  /* educated guess */
+       {"Hir",         "Hiril"},       /* lord, lady (S.) ['ir] */
+       {"Aredhel",     "Arwen"},       /* noble elf, maiden (S.) */
+       {"Ernil",       "Elentariel"},  /* prince (S.), elf-maiden (Q.) */
+       {"Elentar",     "Elentari"},    /* Star-king, -queen (Q.) */
+       "Solonor Thelandira", "Aerdrie Faenya", "Lolth", /* Elven */
+#endif
+       {"Tenderfoot",    0},
+       {"Lookout",       0},
+       {"Trailblazer",   0},
+       {"Reconnoiterer", "Reconnoiteress"},
+       {"Scout",         0},
+       {"Arbalester",    0},   /* One skilled at crossbows */
+       {"Archer",        0},
+       {"Sharpshooter",  0},
+       {"Marksman",      "Markswoman"} },
+       "Mercury", "_Venus", "Mars", /* Roman/planets */
+       "Ran", "Orion's camp", "the cave of the wumpus",
+       PM_RANGER, NON_PM, PM_LITTLE_DOG /* Orion & canis major */,
+       PM_ORION, PM_HUNTER, PM_SCORPIUS,
+       PM_FOREST_CENTAUR, PM_SCORPION, S_CENTAUR, S_SPIDER,
+       ART_LONGBOW_OF_DIANA,
+       MH_HUMAN|MH_ELF|MH_GNOME|MH_ORC | ROLE_MALE|ROLE_FEMALE |
+         ROLE_NEUTRAL|ROLE_CHAOTIC,
+       /* Str Int Wis Dex Con Cha */
+       {  13, 13, 13,  9, 13,  7 },
+       {  30, 10, 10, 20, 20, 10 },
+       /* Init   Lower  Higher */
+       { 13, 0,  0, 6,  1, 0 },        /* Hit points */
+       {  1, 0,  0, 1,  0, 1 },12,     /* Energy */
+       10, 9, 2, 1, 10, A_INT, SPE_INVISIBILITY,   -4
+},
+{      {"Samurai", 0}, {
+       {"Hatamoto",    0},  /* Banner Knight */
+       {"Ronin",       0},  /* no allegiance */
+       {"Ninja",       "Kunoichi"},  /* secret society */
+       {"Joshu",       0},  /* heads a castle */
+       {"Ryoshu",      0},  /* has a territory */
+       {"Kokushu",     0},  /* heads a province */
+       {"Daimyo",      0},  /* a samurai lord */
+       {"Kuge",        0},  /* Noble of the Court */
+       {"Shogun",      0} },/* supreme commander, warlord */
+       "_Amaterasu Omikami", "Raijin", "Susanowo", /* Japanese */
+       "Sam", "the Castle of the Taro Clan", "the Shogun's Castle",
+       PM_SAMURAI, NON_PM, PM_LITTLE_DOG,
+       PM_LORD_SATO, PM_ROSHI, PM_ASHIKAGA_TAKAUJI,
+       PM_WOLF, PM_STALKER, S_DOG, S_ELEMENTAL,
+       ART_TSURUGI_OF_MURAMASA,
+       MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL,
+       /* Str Int Wis Dex Con Cha */
+       {  10,  8,  7, 10, 17,  6 },
+       {  30, 10,  8, 30, 14,  8 },
+       /* Init   Lower  Higher */
+       { 13, 0,  0, 8,  1, 0 },        /* Hit points */
+       {  1, 0,  0, 1,  0, 1 },11,     /* Energy */
+       10, 10, 0, 0,  8, A_INT, SPE_CLAIRVOYANCE,    -4
+},
+#ifdef TOURIST
+{      {"Tourist", 0}, {
+       {"Rambler",     0},
+       {"Sightseer",   0},
+       {"Excursionist",0},
+       {"Peregrinator","Peregrinatrix"},
+       {"Traveler",    0},
+       {"Journeyer",   0},
+       {"Voyager",     0},
+       {"Explorer",    0},
+       {"Adventurer",  0} },
+       "Blind Io", "_The Lady", "Offler", /* Discworld */
+       "Tou", "Ankh-Morpork", "the Thieves' Guild Hall",
+       PM_TOURIST, NON_PM, NON_PM,
+       PM_TWOFLOWER, PM_GUIDE, PM_MASTER_OF_THIEVES,
+       PM_GIANT_SPIDER, PM_FOREST_CENTAUR, S_SPIDER, S_CENTAUR,
+       ART_YENDORIAN_EXPRESS_CARD,
+       MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL,
+       /* Str Int Wis Dex Con Cha */
+       {   7, 10,  6,  7,  7, 10 },
+       {  15, 10, 10, 15, 30, 20 },
+       /* Init   Lower  Higher */
+       {  8, 0,  0, 8,  0, 0 },        /* Hit points */
+       {  1, 0,  0, 1,  0, 1 },14,     /* Energy */
+       0, 5, 1, 2, 10, A_INT, SPE_CHARM_MONSTER,   -4
+},
+#endif
+{      {"Valkyrie", 0}, {
+       {"Stripling",   0},
+       {"Skirmisher",  0},
+       {"Fighter",     0},
+       {"Man-at-arms", "Woman-at-arms"},
+       {"Warrior",     0},
+       {"Swashbuckler",0},
+       {"Hero",        "Heroine"},
+       {"Champion",    0},
+       {"Lord",        "Lady"} },
+       "Tyr", "Odin", "Loki", /* Norse */
+       "Val", "the Shrine of Destiny", "the cave of Surtur",
+       PM_VALKYRIE, NON_PM, NON_PM /*PM_WINTER_WOLF_CUB*/,
+       PM_NORN, PM_WARRIOR, PM_LORD_SURTUR,
+       PM_FIRE_ANT, PM_FIRE_GIANT, S_ANT, S_GIANT,
+       ART_ORB_OF_FATE,
+       MH_HUMAN|MH_DWARF | ROLE_FEMALE | ROLE_LAWFUL|ROLE_NEUTRAL,
+       /* Str Int Wis Dex Con Cha */
+       {  10,  7,  7,  7, 10,  7 },
+       {  30,  6,  7, 20, 30,  7 },
+       /* Init   Lower  Higher */
+       { 14, 0,  0, 8,  2, 0 },        /* Hit points */
+       {  1, 0,  0, 1,  0, 1 },10,     /* Energy */
+       0, 10,-2, 0,  9, A_WIS, SPE_CONE_OF_COLD,    -4
+},
+{      {"Wizard", 0}, {
+       {"Evoker",      0},
+       {"Conjurer",    0},
+       {"Thaumaturge", 0},
+       {"Magician",    0},
+       {"Enchanter",   "Enchantress"},
+       {"Sorcerer",    "Sorceress"},
+       {"Necromancer", 0},
+       {"Wizard",      0},
+       {"Mage",        0} },
+       "Ptah", "Thoth", "Anhur", /* Egyptian */
+       "Wiz", "the Lonely Tower", "the Tower of Darkness",
+       PM_WIZARD, NON_PM, PM_KITTEN,
+       PM_NEFERET_THE_GREEN, PM_APPRENTICE, PM_DARK_ONE,
+       PM_VAMPIRE_BAT, PM_XORN, S_BAT, S_WRAITH,
+       ART_EYE_OF_THE_AETHIOPICA,
+       MH_HUMAN|MH_ELF|MH_GNOME|MH_ORC | ROLE_MALE|ROLE_FEMALE |
+         ROLE_NEUTRAL|ROLE_CHAOTIC,
+       /* Str Int Wis Dex Con Cha */
+       {   7, 10,  7,  7,  7,  7 },
+       {  10, 30, 10, 20, 20, 10 },
+       /* Init   Lower  Higher */
+       { 10, 0,  0, 8,  1, 0 },        /* Hit points */
+       {  4, 3,  0, 2,  0, 3 },12,     /* Energy */
+       0, 1, 0, 3, 10, A_INT, SPE_MAGIC_MISSILE,   -4
+},
+/* Array terminator */
+{{0, 0}}
+};
+
+
+/* The player's role, created at runtime from initial
+ * choices.  This may be munged in role_init().
+ */
+struct Role urole =
+{      {"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
+};
+
+
+
+/* Table of all races */
+const struct Race races[] = {
+{      "human", "human", "humanity", "Hum",
+       {"man", "woman"},
+       PM_HUMAN, NON_PM, PM_HUMAN_MUMMY, PM_HUMAN_ZOMBIE,
+       MH_HUMAN | ROLE_MALE|ROLE_FEMALE |
+         ROLE_LAWFUL|ROLE_NEUTRAL|ROLE_CHAOTIC,
+       MH_HUMAN, 0, MH_GNOME|MH_ORC,
+       /*    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 */
+},
+{      "elf", "elven", "elvenkind", "Elf",
+       {0, 0},
+       PM_ELF, NON_PM, PM_ELF_MUMMY, PM_ELF_ZOMBIE,
+       MH_ELF | ROLE_MALE|ROLE_FEMALE | ROLE_CHAOTIC,
+       MH_ELF, MH_ELF, MH_ORC,
+       /*  Str    Int Wis Dex Con Cha */
+       {    3,     3,  3,  3,  3,  3 },
+       {   18,    20, 20, 18, 16, 18 },
+       /* Init   Lower  Higher */
+       {  1, 0,  0, 1,  1, 0 },        /* Hit points */
+       {  2, 0,  3, 0,  3, 0 }         /* Energy */
+},
+{      "dwarf", "dwarven", "dwarvenkind", "Dwa",
+       {0, 0},
+       PM_DWARF, NON_PM, PM_DWARF_MUMMY, PM_DWARF_ZOMBIE,
+       MH_DWARF | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL,
+       MH_DWARF, MH_DWARF|MH_GNOME, MH_ORC,
+       /*    Str     Int Wis Dex Con Cha */
+       {      3,      3,  3,  3,  3,  3 },
+       { STR18(100), 16, 16, 20, 20, 16 },
+       /* Init   Lower  Higher */
+       {  4, 0,  0, 3,  2, 0 },        /* Hit points */
+       {  0, 0,  0, 0,  0, 0 }         /* Energy */
+},
+{      "gnome", "gnomish", "gnomehood", "Gno",
+       {0, 0},
+       PM_GNOME, NON_PM, PM_GNOME_MUMMY, PM_GNOME_ZOMBIE,
+       MH_GNOME | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL,
+       MH_GNOME, MH_DWARF|MH_GNOME, MH_HUMAN,
+       /*  Str    Int Wis Dex Con Cha */
+       {    3,     3,  3,  3,  3,  3 },
+       {STR18(50),19, 18, 18, 18, 18 },
+       /* Init   Lower  Higher */
+       {  1, 0,  0, 1,  0, 0 },        /* Hit points */
+       {  2, 0,  2, 0,  2, 0 }         /* Energy */
+},
+{      "orc", "orcish", "orcdom", "Orc",
+       {0, 0},
+       PM_ORC, NON_PM, PM_ORC_MUMMY, PM_ORC_ZOMBIE,
+       MH_ORC | ROLE_MALE|ROLE_FEMALE | ROLE_CHAOTIC,
+       MH_ORC, 0, MH_HUMAN|MH_ELF|MH_DWARF,
+       /*  Str    Int Wis Dex Con Cha */
+       {   3,      3,  3,  3,  3,  3 },
+       {STR18(50),16, 16, 18, 18, 16 },
+       /* Init   Lower  Higher */
+       {  1, 0,  0, 1,  0, 0 },        /* Hit points */
+       {  1, 0,  1, 0,  1, 0 }         /* Energy */
+},
+/* Array terminator */
+{ 0, 0, 0, 0 }};
+
+
+/* The player's race, created at runtime from initial
+ * choices.  This may be munged in role_init().
+ */
+struct Race urace =
+{      "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 */
+};
+
+
+/* Table of all genders */
+const struct Gender genders[] = {
+       {"male",        "he",   "him",  "his",  "Mal",  ROLE_MALE},
+       {"female",      "she",  "her",  "her",  "Fem",  ROLE_FEMALE},
+       {"neuter",      "it",   "it",   "its",  "Ntr",  ROLE_NEUTER}
+};
+
+
+/* Table of all alignments */
+const struct Align aligns[] = {
+       {"law",         "lawful",       "Law",  ROLE_LAWFUL,    A_LAWFUL},
+       {"balance",     "neutral",      "Neu",  ROLE_NEUTRAL,   A_NEUTRAL},
+       {"chaos",       "chaotic",      "Cha",  ROLE_CHAOTIC,   A_CHAOTIC},
+       {"evil",        "unaligned",    "Una",  0,              A_NONE}
+};
+
+STATIC_DCL char * FDECL(promptsep, (char *, int));
+STATIC_DCL int FDECL(role_gendercount, (int));
+STATIC_DCL int FDECL(race_alignmentcount, (int));
+
+/* used by str2XXX() */
+static char NEARDATA randomstr[] = "random";
+
+
+boolean
+validrole(rolenum)
+       int rolenum;
+{
+       return (rolenum >= 0 && rolenum < SIZE(roles)-1);
+}
+
+
+int
+randrole()
+{
+       return (rn2(SIZE(roles)-1));
+}
+
+
+int
+str2role(str)
+       char *str;
+{
+       int i, len;
+
+       /* Is str valid? */
+       if (!str || !str[0])
+           return ROLE_NONE;
+
+       /* Match as much of str as is provided */
+       len = strlen(str);
+       for (i = 0; roles[i].name.m; i++) {
+           /* Does it match the male name? */
+           if (!strncmpi(str, roles[i].name.m, len))
+               return i;
+           /* Or the female name? */
+           if (roles[i].name.f && !strncmpi(str, roles[i].name.f, len))
+               return i;
+           /* Or the filecode? */
+           if (!strcmpi(str, roles[i].filecode))
+               return i;
+       }
+
+       if ((len == 1 && (*str == '*' || *str == '@')) ||
+               !strncmpi(str, randomstr, len))
+           return ROLE_RANDOM;
+
+       /* Couldn't find anything appropriate */
+       return ROLE_NONE;
+}
+
+
+boolean
+validrace(rolenum, racenum)
+       int rolenum, racenum;
+{
+       /* Assumes validrole */
+       return (racenum >= 0 && racenum < SIZE(races)-1 &&
+               (roles[rolenum].allow & races[racenum].allow & ROLE_RACEMASK));
+}
+
+
+int
+randrace(rolenum)
+       int rolenum;
+{
+       int i, n = 0;
+
+       /* Count the number of valid races */
+       for (i = 0; races[i].noun; i++)
+           if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK)
+               n++;
+
+       /* Pick a random race */
+       /* Use a factor of 100 in case of bad random number generators */
+       if (n) n = rn2(n*100)/100;
+       for (i = 0; races[i].noun; i++)
+           if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK) {
+               if (n) n--;
+               else return (i);
+           }
+
+       /* This role has no permitted races? */
+       return (rn2(SIZE(races)-1));
+}
+
+
+int
+str2race(str)
+       char *str;
+{
+       int i, len;
+
+       /* Is str valid? */
+       if (!str || !str[0])
+           return ROLE_NONE;
+
+       /* Match as much of str as is provided */
+       len = strlen(str);
+       for (i = 0; races[i].noun; i++) {
+           /* Does it match the noun? */
+           if (!strncmpi(str, races[i].noun, len))
+               return i;
+           /* Or the filecode? */
+           if (!strcmpi(str, races[i].filecode))
+               return i;
+       }
+
+       if ((len == 1 && (*str == '*' || *str == '@')) ||
+               !strncmpi(str, randomstr, len))
+           return ROLE_RANDOM;
+
+       /* Couldn't find anything appropriate */
+       return ROLE_NONE;
+}
+
+
+boolean
+validgend(rolenum, racenum, gendnum)
+       int rolenum, racenum, gendnum;
+{
+       /* Assumes validrole and validrace */
+       return (gendnum >= 0 && gendnum < ROLE_GENDERS &&
+               (roles[rolenum].allow & races[racenum].allow &
+                genders[gendnum].allow & ROLE_GENDMASK));
+}
+
+
+int
+randgend(rolenum, racenum)
+       int rolenum, racenum;
+{
+       int i, n = 0;
+
+       /* Count the number of valid genders */
+       for (i = 0; i < ROLE_GENDERS; i++)
+           if (roles[rolenum].allow & races[racenum].allow &
+                       genders[i].allow & ROLE_GENDMASK)
+               n++;
+
+       /* Pick a random gender */
+       if (n) n = rn2(n);
+       for (i = 0; i < ROLE_GENDERS; i++)
+           if (roles[rolenum].allow & races[racenum].allow &
+                       genders[i].allow & ROLE_GENDMASK) {
+               if (n) n--;
+               else return (i);
+           }
+
+       /* This role/race has no permitted genders? */
+       return (rn2(ROLE_GENDERS));
+}
+
+
+int
+str2gend(str)
+       char *str;
+{
+       int i, len;
+
+       /* Is str valid? */
+       if (!str || !str[0])
+           return ROLE_NONE;
+
+       /* Match as much of str as is provided */
+       len = strlen(str);
+       for (i = 0; i < ROLE_GENDERS; i++) {
+           /* Does it match the adjective? */
+           if (!strncmpi(str, genders[i].adj, len))
+               return i;
+           /* Or the filecode? */
+           if (!strcmpi(str, genders[i].filecode))
+               return i;
+       }
+       if ((len == 1 && (*str == '*' || *str == '@')) ||
+               !strncmpi(str, randomstr, len))
+           return ROLE_RANDOM;
+
+       /* Couldn't find anything appropriate */
+       return ROLE_NONE;
+}
+
+
+boolean
+validalign(rolenum, racenum, alignnum)
+       int rolenum, racenum, alignnum;
+{
+       /* Assumes validrole and validrace */
+       return (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
+               (roles[rolenum].allow & races[racenum].allow &
+                aligns[alignnum].allow & ROLE_ALIGNMASK));
+}
+
+
+int
+randalign(rolenum, racenum)
+       int rolenum, racenum;
+{
+       int i, n = 0;
+
+       /* Count the number of valid alignments */
+       for (i = 0; i < ROLE_ALIGNS; i++)
+           if (roles[rolenum].allow & races[racenum].allow &
+                       aligns[i].allow & ROLE_ALIGNMASK)
+               n++;
+
+       /* Pick a random alignment */
+       if (n) n = rn2(n);
+       for (i = 0; i < ROLE_ALIGNS; i++)
+           if (roles[rolenum].allow & races[racenum].allow &
+                       aligns[i].allow & ROLE_ALIGNMASK) {
+               if (n) n--;
+               else return (i);
+           }
+
+       /* This role/race has no permitted alignments? */
+       return (rn2(ROLE_ALIGNS));
+}
+
+
+int
+str2align(str)
+       char *str;
+{
+       int i, len;
+
+       /* Is str valid? */
+       if (!str || !str[0])
+           return ROLE_NONE;
+
+       /* Match as much of str as is provided */
+       len = strlen(str);
+       for (i = 0; i < ROLE_ALIGNS; i++) {
+           /* Does it match the adjective? */
+           if (!strncmpi(str, aligns[i].adj, len))
+               return i;
+           /* Or the filecode? */
+           if (!strcmpi(str, aligns[i].filecode))
+               return i;
+       }
+       if ((len == 1 && (*str == '*' || *str == '@')) ||
+               !strncmpi(str, randomstr, len))
+           return ROLE_RANDOM;
+
+       /* Couldn't find anything appropriate */
+       return ROLE_NONE;
+}
+
+/* is rolenum compatible with any racenum/gendnum/alignnum constraints? */
+boolean
+ok_role(rolenum, racenum, gendnum, alignnum)
+int rolenum, racenum, gendnum, alignnum;
+{
+    int i;
+    short allow;
+
+    if (rolenum >= 0 && rolenum < SIZE(roles)-1) {
+       allow = roles[rolenum].allow;
+       if (racenum >= 0 && racenum < SIZE(races)-1 &&
+               !(allow & races[racenum].allow & ROLE_RACEMASK))
+           return FALSE;
+       if (gendnum >= 0 && gendnum < ROLE_GENDERS &&
+               !(allow & genders[gendnum].allow & ROLE_GENDMASK))
+           return FALSE;
+       if (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
+               !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
+           return FALSE;
+       return TRUE;
+    } else {
+       for (i = 0; i < SIZE(roles)-1; i++) {
+           allow = roles[i].allow;
+           if (racenum >= 0 && racenum < SIZE(races)-1 &&
+                   !(allow & races[racenum].allow & ROLE_RACEMASK))
+               continue;
+           if (gendnum >= 0 && gendnum < ROLE_GENDERS &&
+                   !(allow & genders[gendnum].allow & ROLE_GENDMASK))
+               continue;
+           if (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
+                   !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
+               continue;
+           return TRUE;
+       }
+       return FALSE;
+    }
+}
+
+/* pick a random role subject to any racenum/gendnum/alignnum constraints */
+/* If pickhow == PICK_RIGID a role is returned only if there is  */
+/* a single possibility */
+int
+pick_role(racenum, gendnum, alignnum, pickhow)
+int racenum, gendnum, alignnum, pickhow;
+{
+    int i;
+    int roles_ok = 0;
+
+    for (i = 0; i < SIZE(roles)-1; i++) {
+       if (ok_role(i, racenum, gendnum, alignnum))
+           roles_ok++;
+    }
+    if (roles_ok == 0 || (roles_ok > 1 && pickhow == PICK_RIGID))
+       return ROLE_NONE;
+    roles_ok = rn2(roles_ok);
+    for (i = 0; i < SIZE(roles)-1; i++) {
+       if (ok_role(i, racenum, gendnum, alignnum)) {
+           if (roles_ok == 0)
+               return i;
+           else
+               roles_ok--;
+       }
+    }
+    return ROLE_NONE;
+}
+
+/* is racenum compatible with any rolenum/gendnum/alignnum constraints? */
+boolean
+ok_race(rolenum, racenum, gendnum, alignnum)
+int rolenum, racenum, gendnum, alignnum;
+{
+    int i;
+    short allow;
+
+    if (racenum >= 0 && racenum < SIZE(races)-1) {
+       allow = races[racenum].allow;
+       if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
+               !(allow & roles[rolenum].allow & ROLE_RACEMASK))
+           return FALSE;
+       if (gendnum >= 0 && gendnum < ROLE_GENDERS &&
+               !(allow & genders[gendnum].allow & ROLE_GENDMASK))
+           return FALSE;
+       if (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
+               !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
+           return FALSE;
+       return TRUE;
+    } else {
+       for (i = 0; i < SIZE(races)-1; i++) {
+           allow = races[i].allow;
+           if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
+                   !(allow & roles[rolenum].allow & ROLE_RACEMASK))
+               continue;
+           if (gendnum >= 0 && gendnum < ROLE_GENDERS &&
+                   !(allow & genders[gendnum].allow & ROLE_GENDMASK))
+               continue;
+           if (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
+                   !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
+               continue;
+           return TRUE;
+       }
+       return FALSE;
+    }
+}
+
+/* pick a random race subject to any rolenum/gendnum/alignnum constraints */
+/* If pickhow == PICK_RIGID a race is returned only if there is  */
+/* a single possibility */
+int
+pick_race(rolenum, gendnum, alignnum, pickhow)
+int rolenum, gendnum, alignnum, pickhow;
+{
+    int i;
+    int races_ok = 0;
+
+    for (i = 0; i < SIZE(races)-1; i++) {
+       if (ok_race(rolenum, i, gendnum, alignnum))
+           races_ok++;
+    }
+    if (races_ok == 0 || (races_ok > 1 && pickhow == PICK_RIGID))
+       return ROLE_NONE;
+    races_ok = rn2(races_ok);
+    for (i = 0; i < SIZE(races)-1; i++) {
+       if (ok_race(rolenum, i, gendnum, alignnum)) {
+           if (races_ok == 0)
+               return i;
+           else
+               races_ok--;
+       }
+    }
+    return ROLE_NONE;
+}
+
+/* is gendnum compatible with any rolenum/racenum/alignnum constraints? */
+/* gender and alignment are not comparable (and also not constrainable) */
+boolean
+ok_gend(rolenum, racenum, gendnum, alignnum)
+int rolenum, racenum, gendnum, alignnum;
+{
+    int i;
+    short allow;
+
+    if (gendnum >= 0 && gendnum < ROLE_GENDERS) {
+       allow = genders[gendnum].allow;
+       if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
+               !(allow & roles[rolenum].allow & ROLE_GENDMASK))
+           return FALSE;
+       if (racenum >= 0 && racenum < SIZE(races)-1 &&
+               !(allow & races[racenum].allow & ROLE_GENDMASK))
+           return FALSE;
+       return TRUE;
+    } else {
+       for (i = 0; i < ROLE_GENDERS; i++) {
+           allow = genders[i].allow;
+           if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
+                   !(allow & roles[rolenum].allow & ROLE_GENDMASK))
+               continue;
+           if (racenum >= 0 && racenum < SIZE(races)-1 &&
+                   !(allow & races[racenum].allow & ROLE_GENDMASK))
+               continue;
+           return TRUE;
+       }
+       return FALSE;
+    }
+}
+
+/* pick a random gender subject to any rolenum/racenum/alignnum constraints */
+/* gender and alignment are not comparable (and also not constrainable) */
+/* If pickhow == PICK_RIGID a gender is returned only if there is  */
+/* a single possibility */
+int
+pick_gend(rolenum, racenum, alignnum, pickhow)
+int rolenum, racenum, alignnum, pickhow;
+{
+    int i;
+    int gends_ok = 0;
+
+    for (i = 0; i < ROLE_GENDERS; i++) {
+       if (ok_gend(rolenum, racenum, i, alignnum))
+           gends_ok++;
+    }
+    if (gends_ok == 0 || (gends_ok > 1 && pickhow == PICK_RIGID))
+       return ROLE_NONE;
+    gends_ok = rn2(gends_ok);
+    for (i = 0; i < ROLE_GENDERS; i++) {
+       if (ok_gend(rolenum, racenum, i, alignnum)) {
+           if (gends_ok == 0)
+               return i;
+           else
+               gends_ok--;
+       }
+    }
+    return ROLE_NONE;
+}
+
+/* is alignnum compatible with any rolenum/racenum/gendnum constraints? */
+/* alignment and gender are not comparable (and also not constrainable) */
+boolean
+ok_align(rolenum, racenum, gendnum, alignnum)
+int rolenum, racenum, gendnum, alignnum;
+{
+    int i;
+    short allow;
+
+    if (alignnum >= 0 && alignnum < ROLE_ALIGNS) {
+       allow = aligns[alignnum].allow;
+       if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
+               !(allow & roles[rolenum].allow & ROLE_ALIGNMASK))
+           return FALSE;
+       if (racenum >= 0 && racenum < SIZE(races)-1 &&
+               !(allow & races[racenum].allow & ROLE_ALIGNMASK))
+           return FALSE;
+       return TRUE;
+    } else {
+       for (i = 0; i < ROLE_ALIGNS; i++) {
+           allow = races[i].allow;
+           if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
+                   !(allow & roles[rolenum].allow & ROLE_ALIGNMASK))
+               continue;
+           if (racenum >= 0 && racenum < SIZE(races)-1 &&
+                   !(allow & races[racenum].allow & ROLE_ALIGNMASK))
+               continue;
+           return TRUE;
+       }
+       return FALSE;
+    }
+}
+
+/* pick a random alignment subject to any rolenum/racenum/gendnum constraints */
+/* alignment and gender are not comparable (and also not constrainable) */
+/* If pickhow == PICK_RIGID an alignment is returned only if there is  */
+/* a single possibility */
+int
+pick_align(rolenum, racenum, gendnum, pickhow)
+int rolenum, racenum, gendnum, pickhow;
+{
+    int i;
+    int aligns_ok = 0;
+
+    for (i = 0; i < ROLE_ALIGNS; i++) {
+       if (ok_align(rolenum, racenum, gendnum, i))
+           aligns_ok++;
+    }
+    if (aligns_ok == 0 || (aligns_ok > 1 && pickhow == PICK_RIGID))
+       return ROLE_NONE;
+    aligns_ok = rn2(aligns_ok);
+    for (i = 0; i < ROLE_ALIGNS; i++) {
+       if (ok_align(rolenum, racenum, gendnum, i)) {
+           if (aligns_ok == 0)
+               return i;
+           else
+               aligns_ok--;
+       }
+    }
+    return ROLE_NONE;
+}
+
+void
+rigid_role_checks()
+{
+    /* Some roles are limited to a single race, alignment, or gender and
+     * calling this routine prior to XXX_player_selection() will help
+     * prevent an extraneous prompt that actually doesn't allow
+     * you to choose anything further. Note the use of PICK_RIGID which
+     * causes the pick_XX() routine to return a value only if there is one
+     * single possible selection, otherwise it returns ROLE_NONE.
+     *
+     */
+    if (flags.initrole == ROLE_RANDOM) {
+       /* If the role was explicitly specified as ROLE_RANDOM
+        * via -uXXXX-@ then choose the role in here to narrow down
+        * later choices. Pick a random role in this case.
+        */
+       flags.initrole = pick_role(flags.initrace, flags.initgend,
+                                       flags.initalign, PICK_RANDOM);
+       if (flags.initrole < 0)
+           flags.initrole = randrole();
+    }
+    if (flags.initrole != ROLE_NONE) {
+       if (flags.initrace == ROLE_NONE)
+            flags.initrace = pick_race(flags.initrole, flags.initgend,
+                                               flags.initalign, PICK_RIGID);
+       if (flags.initalign == ROLE_NONE)
+            flags.initalign = pick_align(flags.initrole, flags.initrace,
+                                               flags.initgend, PICK_RIGID);
+       if (flags.initgend == ROLE_NONE)
+            flags.initgend = pick_gend(flags.initrole, flags.initrace,
+                                               flags.initalign, PICK_RIGID);
+    }
+}
+
+#define BP_ALIGN       0
+#define BP_GEND                1
+#define BP_RACE                2
+#define BP_ROLE                3
+#define NUM_BP         4
+
+STATIC_VAR char pa[NUM_BP], post_attribs;
+
+STATIC_OVL char *
+promptsep(buf, num_post_attribs)
+char *buf;
+int num_post_attribs;
+{
+       const char *conj = "and ";
+       if (num_post_attribs > 1
+           && post_attribs < num_post_attribs && post_attribs > 1)
+               Strcat(buf, ","); 
+       Strcat(buf, " ");
+       --post_attribs;
+       if (!post_attribs && num_post_attribs > 1) Strcat(buf, conj);
+       return buf;
+}
+
+STATIC_OVL int
+role_gendercount(rolenum)
+int rolenum;
+{
+       int gendcount = 0;
+       if (validrole(rolenum)) {
+               if (roles[rolenum].allow & ROLE_MALE) ++gendcount;
+               if (roles[rolenum].allow & ROLE_FEMALE) ++gendcount;
+               if (roles[rolenum].allow & ROLE_NEUTER) ++gendcount;
+       }
+       return gendcount;
+}
+
+STATIC_OVL int
+race_alignmentcount(racenum)
+int racenum;
+{
+       int aligncount = 0;
+       if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) {
+               if (races[racenum].allow & ROLE_CHAOTIC) ++aligncount;
+               if (races[racenum].allow & ROLE_LAWFUL) ++aligncount;
+               if (races[racenum].allow & ROLE_NEUTRAL) ++aligncount;
+       }
+       return aligncount;
+}
+
+char *
+root_plselection_prompt(suppliedbuf, buflen, rolenum, racenum, gendnum, alignnum)
+char *suppliedbuf;
+int buflen, rolenum, racenum, gendnum, alignnum;
+{
+       int k, gendercount = 0, aligncount = 0;
+       char buf[BUFSZ];
+       static char err_ret[] = " character's";
+       boolean donefirst = FALSE;
+
+       if (!suppliedbuf || buflen < 1) return err_ret;
+
+       /* initialize these static variables each time this is called */
+       post_attribs = 0;
+       for (k=0; k < NUM_BP; ++k)
+               pa[k] = 0;
+       buf[0] = '\0';
+       *suppliedbuf = '\0';
+       
+       /* How many alignments are allowed for the desired race? */
+       if (racenum != ROLE_NONE && racenum != ROLE_RANDOM)
+               aligncount = race_alignmentcount(racenum);
+
+       if (alignnum != ROLE_NONE && alignnum != ROLE_RANDOM) {
+               /* if race specified, and multiple choice of alignments for it */
+               if ((racenum >= 0) && (aligncount > 1)) {
+                       if (donefirst) Strcat(buf, " ");
+                       Strcat(buf, aligns[alignnum].adj);
+                       donefirst = TRUE;
+               } else {
+                       if (donefirst) Strcat(buf, " ");
+                       Strcat(buf, aligns[alignnum].adj);
+                       donefirst = TRUE;
+               }
+       } else {
+               /* if alignment not specified, but race is specified
+                       and only one choice of alignment for that race then
+                       don't include it in the later list */
+               if ((((racenum != ROLE_NONE && racenum != ROLE_RANDOM) &&
+                       ok_race(rolenum, racenum, gendnum, alignnum))
+                     && (aligncount > 1))
+                    || (racenum == ROLE_NONE || racenum == ROLE_RANDOM)) {
+                       pa[BP_ALIGN] = 1;
+                       post_attribs++;
+               }
+       }
+       /* <your lawful> */
+
+       /* How many genders are allowed for the desired role? */
+       if (validrole(rolenum))
+               gendercount = role_gendercount(rolenum);
+
+       if (gendnum != ROLE_NONE  && gendnum != ROLE_RANDOM) {
+               if (validrole(rolenum)) {
+                    /* if role specified, and multiple choice of genders for it,
+                       and name of role itself does not distinguish gender */
+                       if ((rolenum != ROLE_NONE) && (gendercount > 1)
+                                               && !roles[rolenum].name.f) {
+                               if (donefirst) Strcat(buf, " ");
+                               Strcat(buf, genders[gendnum].adj);
+                               donefirst = TRUE;
+                       }
+               } else {
+                       if (donefirst) Strcat(buf, " ");
+                       Strcat(buf, genders[gendnum].adj);
+                       donefirst = TRUE;
+               }
+       } else {
+               /* if gender not specified, but role is specified
+                       and only one choice of gender then
+                       don't include it in the later list */
+               if ((validrole(rolenum) && (gendercount > 1)) || !validrole(rolenum)) {
+                       pa[BP_GEND] = 1;
+                       post_attribs++;
+               }
+       }
+       /* <your lawful female> */
+
+       if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) {
+               if (validrole(rolenum) && ok_race(rolenum, racenum, gendnum, alignnum)) {
+                       if (donefirst) Strcat(buf, " "); 
+                       Strcat(buf, (rolenum == ROLE_NONE) ?
+                               races[racenum].noun :
+                               races[racenum].adj);
+                       donefirst = TRUE;
+               } else if (!validrole(rolenum)) {
+                       if (donefirst) Strcat(buf, " ");
+                       Strcat(buf, races[racenum].noun);
+                       donefirst = TRUE;
+               } else {
+                       pa[BP_RACE] = 1;
+                       post_attribs++;
+               }
+       } else {
+               pa[BP_RACE] = 1;
+               post_attribs++;
+       }
+       /* <your lawful female gnomish> || <your lawful female gnome> */
+
+       if (validrole(rolenum)) {
+               if (donefirst) Strcat(buf, " ");
+               if (gendnum != ROLE_NONE) {
+                   if (gendnum == 1  && roles[rolenum].name.f)
+                       Strcat(buf, roles[rolenum].name.f);
+                   else
+                       Strcat(buf, roles[rolenum].name.m);
+               } else {
+                       if (roles[rolenum].name.f) {
+                               Strcat(buf, roles[rolenum].name.m);
+                               Strcat(buf, "/");
+                               Strcat(buf, roles[rolenum].name.f);
+                       } else 
+                               Strcat(buf, roles[rolenum].name.m);
+               }
+               donefirst = TRUE;
+       } else if (rolenum == ROLE_NONE) {
+               pa[BP_ROLE] = 1;
+               post_attribs++;
+       }
+       
+       if ((racenum == ROLE_NONE || racenum == ROLE_RANDOM) && !validrole(rolenum)) {
+               if (donefirst) Strcat(buf, " ");
+               Strcat(buf, "character");
+               donefirst = TRUE;
+       }
+       /* <your lawful female gnomish cavewoman> || <your lawful female gnome>
+        *    || <your lawful female character>
+        */
+       if (buflen > (int) (strlen(buf) + 1)) {
+               Strcpy(suppliedbuf, buf);
+               return suppliedbuf;
+       } else
+               return err_ret;
+}
+
+char *
+build_plselection_prompt(buf, buflen, rolenum, racenum, gendnum, alignnum)
+char *buf;
+int buflen, rolenum, racenum, gendnum, alignnum;
+{
+       const char *defprompt = "Shall I pick a character for you? [ynq] ";
+       int num_post_attribs = 0;
+       char tmpbuf[BUFSZ];
+       
+       if (buflen < QBUFSZ)
+               return (char *)defprompt;
+
+       Strcpy(tmpbuf, "Shall I pick ");
+       if (racenum != ROLE_NONE || validrole(rolenum))
+               Strcat(tmpbuf, "your ");
+       else {
+               Strcat(tmpbuf, "a ");
+       }
+       /* <your> */
+
+       (void)  root_plselection_prompt(eos(tmpbuf), buflen - strlen(tmpbuf),
+                                       rolenum, racenum, gendnum, alignnum);
+       Sprintf(buf, "%s", s_suffix(tmpbuf));
+
+       /* buf should now be:
+        * < your lawful female gnomish cavewoman's> || <your lawful female gnome's>
+        *    || <your lawful female character's>
+        *
+         * Now append the post attributes to it
+        */
+
+       num_post_attribs = post_attribs;
+       if (post_attribs) {
+               if (pa[BP_RACE]) {
+                       (void) promptsep(eos(buf), num_post_attribs);
+                       Strcat(buf, "race");
+               }
+               if (pa[BP_ROLE]) {
+                       (void) promptsep(eos(buf), num_post_attribs);
+                       Strcat(buf, "role");
+               }
+               if (pa[BP_GEND]) {
+                       (void) promptsep(eos(buf), num_post_attribs);
+                       Strcat(buf, "gender");
+               }
+               if (pa[BP_ALIGN]) {
+                       (void) promptsep(eos(buf), num_post_attribs);
+                       Strcat(buf, "alignment");
+               }
+       }
+       Strcat(buf, " for you? [ynq] ");
+       return buf;
+}
+
+#undef BP_ALIGN
+#undef BP_GEND
+#undef BP_RACE
+#undef BP_ROLE
+#undef NUM_BP
+
+void
+plnamesuffix()
+{
+       char *sptr, *eptr;
+       int i;
+
+       /* Look for tokens delimited by '-' */
+       if ((eptr = index(plname, '-')) != (char *) 0)
+           *eptr++ = '\0';
+       while (eptr) {
+           /* Isolate the next token */
+           sptr = eptr;
+           if ((eptr = index(sptr, '-')) != (char *)0)
+               *eptr++ = '\0';
+
+           /* Try to match it to something */
+           if ((i = str2role(sptr)) != ROLE_NONE)
+               flags.initrole = i;
+           else if ((i = str2race(sptr)) != ROLE_NONE)
+               flags.initrace = i;
+           else if ((i = str2gend(sptr)) != ROLE_NONE)
+               flags.initgend = i;
+           else if ((i = str2align(sptr)) != ROLE_NONE)
+               flags.initalign = i;
+       }
+       if(!plname[0]) {
+           askname();
+           plnamesuffix();
+       }
+
+       /* commas in the plname confuse the record file, convert to spaces */
+       for (sptr = plname; *sptr; sptr++) {
+               if (*sptr == ',') *sptr = ' ';
+       }
+}
+
+
+/*
+ *     Special setup modifications here:
+ *
+ *     Unfortunately, this is going to have to be done
+ *     on each newgame or restore, because you lose the permonst mods
+ *     across a save/restore.  :-)
+ *
+ *     1 - The Rogue Leader is the Tourist Nemesis.
+ *     2 - Priests start with a random alignment - convert the leader and
+ *         guardians here.
+ *     3 - Elves can have one of two different leaders, but can't work it
+ *         out here because it requires hacking the level file data (see
+ *         sp_lev.c).
+ *
+ * This code also replaces quest_init().
+ */
+void
+role_init()
+{
+       int alignmnt;
+
+       /* Strip the role letter out of the player name.
+        * This is included for backwards compatibility.
+        */
+       plnamesuffix();
+
+       /* Check for a valid role.  Try flags.initrole first. */
+       if (!validrole(flags.initrole)) {
+           /* Try the player letter second */
+           if ((flags.initrole = str2role(pl_character)) < 0)
+               /* None specified; pick a random role */
+               flags.initrole = randrole();
+       }
+
+       /* We now have a valid role index.  Copy the role name back. */
+       /* This should become OBSOLETE */
+       Strcpy(pl_character, roles[flags.initrole].name.m);
+       pl_character[PL_CSIZ-1] = '\0';
+
+       /* Check for a valid race */
+       if (!validrace(flags.initrole, flags.initrace))
+           flags.initrace = randrace(flags.initrole);
+
+       /* Check for a valid gender.  If new game, check both initgend
+        * and female.  On restore, assume flags.female is correct. */
+       if (flags.pantheon == -1) {     /* new game */
+           if (!validgend(flags.initrole, flags.initrace, flags.female))
+               flags.female = !flags.female;
+       }
+       if (!validgend(flags.initrole, flags.initrace, flags.initgend))
+           /* Note that there is no way to check for an unspecified gender. */
+           flags.initgend = flags.female;
+
+       /* Check for a valid alignment */
+       if (!validalign(flags.initrole, flags.initrace, flags.initalign))
+           /* Pick a random alignment */
+           flags.initalign = randalign(flags.initrole, flags.initrace);
+       alignmnt = aligns[flags.initalign].value;
+
+       /* Initialize urole and urace */
+       urole = roles[flags.initrole];
+       urace = races[flags.initrace];
+
+       /* Fix up the quest leader */
+       if (urole.ldrnum != NON_PM) {
+           mons[urole.ldrnum].msound = MS_LEADER;
+           mons[urole.ldrnum].mflags2 |= (M2_PEACEFUL);
+           mons[urole.ldrnum].mflags3 |= M3_CLOSE;
+           mons[urole.ldrnum].maligntyp = alignmnt * 3;
+       }
+
+       /* Fix up the quest guardians */
+       if (urole.guardnum != NON_PM) {
+           mons[urole.guardnum].mflags2 |= (M2_PEACEFUL);
+           mons[urole.guardnum].maligntyp = alignmnt * 3;
+       }
+
+       /* Fix up the quest nemesis */
+       if (urole.neminum != NON_PM) {
+           mons[urole.neminum].msound = MS_NEMESIS;
+           mons[urole.neminum].mflags2 &= ~(M2_PEACEFUL);
+           mons[urole.neminum].mflags2 |= (M2_NASTY|M2_STALK|M2_HOSTILE);
+           mons[urole.neminum].mflags3 |= M3_WANTSARTI | M3_WAITFORU;
+       }
+
+       /* Fix up the god names */
+       if (flags.pantheon == -1) {             /* new game */
+           flags.pantheon = flags.initrole;    /* use own gods */
+           while (!roles[flags.pantheon].lgod) /* unless they're missing */
+               flags.pantheon = randrole();
+       }
+       if (!urole.lgod) {
+           urole.lgod = roles[flags.pantheon].lgod;
+           urole.ngod = roles[flags.pantheon].ngod;
+           urole.cgod = roles[flags.pantheon].cgod;
+       }
+
+       /* Fix up infravision */
+       if (mons[urace.malenum].mflags3 & M3_INFRAVISION) {
+           /* although an infravision intrinsic is possible, infravision
+            * is purely a property of the physical race.  This means that we
+            * must put the infravision flag in the player's current race
+            * (either that or have separate permonst entries for
+            * elven/non-elven members of each class).  The side effect is that
+            * all NPCs of that class will have (probably bogus) infravision,
+            * but since infravision has no effect for NPCs anyway we can
+            * ignore this.
+            */
+           mons[urole.malenum].mflags3 |= M3_INFRAVISION;
+           if (urole.femalenum != NON_PM)
+               mons[urole.femalenum].mflags3 |= M3_INFRAVISION;
+       }
+
+       /* Artifacts are fixed in hack_artifacts() */
+
+       /* Success! */
+       return;
+}
+
+const char *
+Hello(mtmp)
+struct monst *mtmp;
+{
+       switch (Role_switch) {
+       case PM_KNIGHT:
+           return ("Salutations"); /* Olde English */
+       case PM_SAMURAI:
+           return (mtmp && mtmp->data == &mons[PM_SHOPKEEPER] ?
+                       "Irasshaimase" : "Konnichi wa"); /* Japanese */
+#ifdef TOURIST
+       case PM_TOURIST:
+           return ("Aloha");       /* Hawaiian */
+#endif
+       case PM_VALKYRIE:
+           return (
+#ifdef MAIL
+                       mtmp && mtmp->data == &mons[PM_MAIL_DAEMON] ? "Hallo" :
+#endif
+                       "Velkommen");   /* Norse */
+       default:
+           return ("Hello");
+       }
+}
+
+const char *
+Goodbye()
+{
+       switch (Role_switch) {
+       case PM_KNIGHT:
+           return ("Fare thee well");  /* Olde English */
+       case PM_SAMURAI:
+           return ("Sayonara");        /* Japanese */
+#ifdef TOURIST
+       case PM_TOURIST:
+           return ("Aloha");           /* Hawaiian */
+#endif
+       case PM_VALKYRIE:
+           return ("Farvel");          /* Norse */
+       default:
+           return ("Goodbye");
+       }
+}
+
+/* role.c */
diff --git a/src/rumors.c b/src/rumors.c
new file mode 100644 (file)
index 0000000..3272d1c
--- /dev/null
@@ -0,0 +1,382 @@
+/*     SCCS Id: @(#)rumors.c   3.4     1996/04/20      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "lev.h"
+#include "dlb.h"
+
+/*     [note: this comment is fairly old, but still accurate for 3.1]
+ * Rumors have been entirely rewritten to speed up the access.  This is
+ * essential when working from floppies.  Using fseek() the way that's done
+ * here means rumors following longer rumors are output more often than those
+ * following shorter rumors.  Also, you may see the same rumor more than once
+ * in a particular game (although the odds are highly against it), but
+ * this also happens with real fortune cookies.  -dgk
+ */
+
+/*     3.1
+ * The rumors file consists of a "do not edit" line, a hexadecimal number
+ * giving the number of bytes of useful/true rumors, followed by those
+ * true rumors (one per line), followed by the useless/false/misleading/cute
+ * rumors (also one per line).  Number of bytes of untrue rumors is derived
+ * via fseek(EOF)+ftell().
+ *
+ * The oracles file consists of a "do not edit" comment, a decimal count N
+ * and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
+ * records, separated by "---" lines.  The first oracle is a special case,
+ * and placed there by 'makedefs'.
+ */
+
+STATIC_DCL void FDECL(init_rumors, (dlb *));
+STATIC_DCL void FDECL(init_oracles, (dlb *));
+
+static long true_rumor_start,  true_rumor_size,  true_rumor_end,
+           false_rumor_start, false_rumor_size, false_rumor_end;
+static int oracle_flg = 0;  /* -1=>don't use, 0=>need init, 1=>init done */
+static unsigned oracle_cnt = 0;
+static long *oracle_loc = 0;
+
+STATIC_OVL void
+init_rumors(fp)
+dlb *fp;
+{
+       char line[BUFSZ];
+
+       (void) dlb_fgets(line, sizeof line, fp); /* skip "don't edit" comment */
+       (void) dlb_fgets(line, sizeof line, fp);
+       if (sscanf(line, "%6lx\n", &true_rumor_size) == 1 &&
+           true_rumor_size > 0L) {
+           (void) dlb_fseek(fp, 0L, SEEK_CUR);
+           true_rumor_start  = dlb_ftell(fp);
+           true_rumor_end    = true_rumor_start + true_rumor_size;
+           (void) dlb_fseek(fp, 0L, SEEK_END);
+           false_rumor_end   = dlb_ftell(fp);
+           false_rumor_start = true_rumor_end; /* ok, so it's redundant... */
+           false_rumor_size  = false_rumor_end - false_rumor_start;
+       } else
+           true_rumor_size = -1L;      /* init failed */
+}
+
+/* exclude_cookie is a hack used because we sometimes want to get rumors in a
+ * context where messages such as "You swallowed the fortune!" that refer to
+ * cookies should not appear.  This has no effect for true rumors since none
+ * of them contain such references anyway.
+ */
+char *
+getrumor(truth, rumor_buf, exclude_cookie)
+int truth; /* 1=true, -1=false, 0=either */
+char *rumor_buf;
+boolean exclude_cookie; 
+{
+       dlb     *rumors;
+       long tidbit, beginning;
+       char    *endp, line[BUFSZ], xbuf[BUFSZ];
+
+       rumor_buf[0] = '\0';
+       if (true_rumor_size < 0L)       /* we couldn't open RUMORFILE */
+               return rumor_buf;
+
+       rumors = dlb_fopen(RUMORFILE, "r");
+
+       if (rumors) {
+           int count = 0;
+           int adjtruth;
+
+           do {
+               rumor_buf[0] = '\0';
+               if (true_rumor_size == 0L) {    /* if this is 1st outrumor() */
+                   init_rumors(rumors);
+                   if (true_rumor_size < 0L) { /* init failed */
+                       Sprintf(rumor_buf, "Error reading \"%.80s\".",
+                               RUMORFILE);
+                       return rumor_buf;
+                   }
+               }
+               /*
+                *      input:      1    0   -1
+                *       rn2 \ +1  2=T  1=T  0=F
+                *       adj./ +0  1=T  0=F -1=F
+                */
+               switch (adjtruth = truth + rn2(2)) {
+                 case  2:      /*(might let a bogus input arg sneak thru)*/
+                 case  1:  beginning = true_rumor_start;
+                           tidbit = Rand() % true_rumor_size;
+                       break;
+                 case  0:      /* once here, 0 => false rather than "either"*/
+                 case -1:  beginning = false_rumor_start;
+                           tidbit = Rand() % false_rumor_size;
+                       break;
+                 default:
+                           impossible("strange truth value for rumor");
+                       return strcpy(rumor_buf, "Oops...");
+               }
+               (void) dlb_fseek(rumors, beginning + tidbit, SEEK_SET);
+               (void) dlb_fgets(line, sizeof line, rumors);
+               if (!dlb_fgets(line, sizeof line, rumors) ||
+                   (adjtruth > 0 && dlb_ftell(rumors) > true_rumor_end)) {
+                       /* reached end of rumors -- go back to beginning */
+                       (void) dlb_fseek(rumors, beginning, SEEK_SET);
+                       (void) dlb_fgets(line, sizeof line, rumors);
+               }
+               if ((endp = index(line, '\n')) != 0) *endp = 0;
+               Strcat(rumor_buf, xcrypt(line, xbuf));
+           } while(count++ < 50 && exclude_cookie && (strstri(rumor_buf, "fortune") || strstri(rumor_buf, "pity")));
+           (void) dlb_fclose(rumors);
+           if (count >= 50)
+               impossible("Can't find non-cookie rumor?");
+           else
+               exercise(A_WIS, (adjtruth > 0));
+       } else {
+               pline("Can't open rumors file!");
+               true_rumor_size = -1;   /* don't try to open it again */
+       }
+       return rumor_buf;
+}
+
+void
+outrumor(truth, mechanism)
+int truth; /* 1=true, -1=false, 0=either */
+int mechanism;
+{
+       static const char fortune_msg[] =
+               "This cookie has a scrap of paper inside.";
+       const char *line;
+       char buf[BUFSZ];
+       boolean reading = (mechanism == BY_COOKIE ||
+                          mechanism == BY_PAPER);
+
+       if (reading) {
+           /* deal with various things that prevent reading */
+           if (is_fainted() && mechanism == BY_COOKIE)
+               return;
+           else if (Blind) {
+               if (mechanism == BY_COOKIE)
+                       pline(fortune_msg);
+               pline("What a pity that you cannot read it!");
+               return;
+           }
+       }
+       line = getrumor(truth, buf, reading ? FALSE : TRUE);
+       if (!*line)
+               line = "NetHack rumors file closed for renovation.";
+       switch (mechanism) {
+           case BY_ORACLE:
+               /* Oracle delivers the rumor */
+               pline("True to her word, the Oracle %ssays: ",
+                 (!rn2(4) ? "offhandedly " : (!rn2(3) ? "casually " :
+                 (rn2(2) ? "nonchalantly " : ""))));
+               verbalize("%s", line);
+               exercise(A_WIS, TRUE);
+               return;
+           case BY_COOKIE:
+               pline(fortune_msg);
+               /* FALLTHRU */
+           case BY_PAPER:
+               pline("It reads:");
+               break;
+       }
+       pline("%s", line);
+}
+
+STATIC_OVL void
+init_oracles(fp)
+dlb *fp;
+{
+       register int i;
+       char line[BUFSZ];
+       int cnt = 0;
+
+       /* this assumes we're only called once */
+       (void) dlb_fgets(line, sizeof line, fp); /* skip "don't edit" comment*/
+       (void) dlb_fgets(line, sizeof line, fp);
+       if (sscanf(line, "%5d\n", &cnt) == 1 && cnt > 0) {
+           oracle_cnt = (unsigned) cnt;
+           oracle_loc = (long *) alloc((unsigned)cnt * sizeof (long));
+           for (i = 0; i < cnt; i++) {
+               (void) dlb_fgets(line, sizeof line, fp);
+               (void) sscanf(line, "%5lx\n", &oracle_loc[i]);
+           }
+       }
+       return;
+}
+
+void
+save_oracles(fd, mode)
+int fd, mode;
+{
+       if (perform_bwrite(mode)) {
+           bwrite(fd, (genericptr_t) &oracle_cnt, sizeof oracle_cnt);
+           if (oracle_cnt)
+               bwrite(fd, (genericptr_t)oracle_loc, oracle_cnt*sizeof (long));
+       }
+       if (release_data(mode)) {
+           if (oracle_cnt) {
+               free((genericptr_t)oracle_loc);
+               oracle_loc = 0,  oracle_cnt = 0,  oracle_flg = 0;
+           }
+       }
+}
+
+void
+restore_oracles(fd)
+int fd;
+{
+       mread(fd, (genericptr_t) &oracle_cnt, sizeof oracle_cnt);
+       if (oracle_cnt) {
+           oracle_loc = (long *) alloc(oracle_cnt * sizeof (long));
+           mread(fd, (genericptr_t) oracle_loc, oracle_cnt * sizeof (long));
+           oracle_flg = 1;     /* no need to call init_oracles() */
+       }
+}
+
+void
+outoracle(special, delphi)
+boolean special;
+boolean delphi;
+{
+       char    line[COLNO];
+       char    *endp;
+       dlb     *oracles;
+       int oracle_idx;
+       char xbuf[BUFSZ];
+
+       if(oracle_flg < 0 ||                    /* couldn't open ORACLEFILE */
+          (oracle_flg > 0 && oracle_cnt == 0)) /* oracles already exhausted */
+               return;
+
+       oracles = dlb_fopen(ORACLEFILE, "r");
+
+       if (oracles) {
+               winid tmpwin;
+               if (oracle_flg == 0) {  /* if this is the first outoracle() */
+                       init_oracles(oracles);
+                       oracle_flg = 1;
+                       if (oracle_cnt == 0) return;
+               }
+               /* oracle_loc[0] is the special oracle;         */
+               /* oracle_loc[1..oracle_cnt-1] are normal ones  */
+               if (oracle_cnt <= 1 && !special) return;  /*(shouldn't happen)*/
+               oracle_idx = special ? 0 : rnd((int) oracle_cnt - 1);
+               (void) dlb_fseek(oracles, oracle_loc[oracle_idx], SEEK_SET);
+               if (!special) oracle_loc[oracle_idx] = oracle_loc[--oracle_cnt];
+
+               tmpwin = create_nhwindow(NHW_TEXT);
+               if (delphi)
+                   putstr(tmpwin, 0, special ?
+                         "The Oracle scornfully takes all your money and says:" :
+                         "The Oracle meditates for a moment and then intones:");
+               else
+                   putstr(tmpwin, 0, "The message reads:");
+               putstr(tmpwin, 0, "");
+
+               while(dlb_fgets(line, COLNO, oracles) && strcmp(line,"---\n")) {
+                       if ((endp = index(line, '\n')) != 0) *endp = 0;
+                       putstr(tmpwin, 0, xcrypt(line, xbuf));
+               }
+               display_nhwindow(tmpwin, TRUE);
+               destroy_nhwindow(tmpwin);
+               (void) dlb_fclose(oracles);
+       } else {
+               pline("Can't open oracles file!");
+               oracle_flg = -1;        /* don't try to open it again */
+       }
+}
+
+int
+doconsult(oracl)
+register struct monst *oracl;
+{
+#ifdef GOLDOBJ
+        long umoney = money_cnt(invent);
+#endif
+       int u_pay, minor_cost = 50, major_cost = 500 + 50 * u.ulevel;
+       int add_xpts;
+       char qbuf[QBUFSZ];
+
+       multi = 0;
+
+       if (!oracl) {
+               There("is no one here to consult.");
+               return 0;
+       } else if (!oracl->mpeaceful) {
+               pline("%s is in no mood for consultations.", Monnam(oracl));
+               return 0;
+#ifndef GOLDOBJ
+       } else if (!u.ugold) {
+#else
+       } else if (!umoney) {
+#endif
+               You("have no money.");
+               return 0;
+       }
+
+       Sprintf(qbuf,
+               "\"Wilt thou settle for a minor consultation?\" (%d %s)",
+               minor_cost, currency((long)minor_cost));
+       switch (ynq(qbuf)) {
+           default:
+           case 'q':
+               return 0;
+           case 'y':
+#ifndef GOLDOBJ
+               if (u.ugold < (long)minor_cost) {
+#else
+               if (umoney < (long)minor_cost) {
+#endif
+                   You("don't even have enough money for that!");
+                   return 0;
+               }
+               u_pay = minor_cost;
+               break;
+           case 'n':
+#ifndef GOLDOBJ
+               if (u.ugold <= (long)minor_cost ||      /* don't even ask */
+#else
+               if (umoney <= (long)minor_cost ||       /* don't even ask */
+#endif
+                   (oracle_cnt == 1 || oracle_flg < 0)) return 0;
+               Sprintf(qbuf,
+                       "\"Then dost thou desire a major one?\" (%d %s)",
+                       major_cost, currency((long)major_cost));
+               if (yn(qbuf) != 'y') return 0;
+#ifndef GOLDOBJ
+               u_pay = (u.ugold < (long)major_cost ? (int)u.ugold
+                                                   : major_cost);
+#else
+               u_pay = (umoney < (long)major_cost ? (int)umoney
+                                                   : major_cost);
+#endif
+               break;
+       }
+#ifndef GOLDOBJ
+       u.ugold -= (long)u_pay;
+       oracl->mgold += (long)u_pay;
+#else
+        money2mon(oracl, (long)u_pay);
+#endif
+       flags.botl = 1;
+       add_xpts = 0;   /* first oracle of each type gives experience points */
+       if (u_pay == minor_cost) {
+               outrumor(1, BY_ORACLE);
+               if (!u.uevent.minor_oracle)
+                   add_xpts = u_pay / (u.uevent.major_oracle ? 25 : 10);
+                   /* 5 pts if very 1st, or 2 pts if major already done */
+               u.uevent.minor_oracle = TRUE;
+       } else {
+               boolean cheapskate = u_pay < major_cost;
+               outoracle(cheapskate, TRUE);
+               if (!cheapskate && !u.uevent.major_oracle)
+                   add_xpts = u_pay / (u.uevent.minor_oracle ? 25 : 10);
+                   /* ~100 pts if very 1st, ~40 pts if minor already done */
+               u.uevent.major_oracle = TRUE;
+               exercise(A_WIS, !cheapskate);
+       }
+       if (add_xpts) {
+               more_experienced(add_xpts, u_pay/50);
+               newexplevel();
+       }
+       return 1;
+}
+
+/*rumors.c*/
diff --git a/src/save.c b/src/save.c
new file mode 100644 (file)
index 0000000..9291eb9
--- /dev/null
@@ -0,0 +1,1120 @@
+/*     SCCS Id: @(#)save.c     3.4     2003/11/14      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "lev.h"
+#include "quest.h"
+
+#ifndef NO_SIGNAL
+#include <signal.h>
+#endif
+#if !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C)
+#include <fcntl.h>
+#endif
+
+#ifdef MFLOPPY
+long bytes_counted;
+static int count_only;
+#endif
+
+#ifdef MICRO
+int dotcnt, dotrow;    /* also used in restore */
+#endif
+
+#ifdef ZEROCOMP
+STATIC_DCL void FDECL(bputc, (int));
+#endif
+STATIC_DCL void FDECL(savelevchn, (int,int));
+STATIC_DCL void FDECL(savedamage, (int,int));
+STATIC_DCL void FDECL(saveobjchn, (int,struct obj *,int));
+STATIC_DCL void FDECL(savemonchn, (int,struct monst *,int));
+STATIC_DCL void FDECL(savetrapchn, (int,struct trap *,int));
+STATIC_DCL void FDECL(savegamestate, (int,int));
+#ifdef MFLOPPY
+STATIC_DCL void FDECL(savelev0, (int,XCHAR_P,int));
+STATIC_DCL boolean NDECL(swapout_oldest);
+STATIC_DCL void FDECL(copyfile, (char *,char *));
+#endif /* MFLOPPY */
+#ifdef GCC_WARN
+static long nulls[10];
+#else
+#define nulls nul
+#endif
+
+#if defined(UNIX) || defined(VMS) || defined(__EMX__) || defined(WIN32)
+#define HUP    if (!program_state.done_hup)
+#else
+#define HUP
+#endif
+
+/* need to preserve these during save to avoid accessing freed memory */
+static unsigned ustuck_id = 0, usteed_id = 0;
+
+int
+dosave()
+{
+       clear_nhwindow(WIN_MESSAGE);
+       if(yn("Really save?") == 'n') {
+               clear_nhwindow(WIN_MESSAGE);
+               if(multi > 0) nomul(0);
+       } else {
+               clear_nhwindow(WIN_MESSAGE);
+               pline("Saving...");
+#if defined(UNIX) || defined(VMS) || defined(__EMX__)
+               program_state.done_hup = 0;
+#endif
+               if(dosave0()) {
+                       program_state.something_worth_saving = 0;
+                       u.uhp = -1;             /* universal game's over indicator */
+                       /* make sure they see the Saving message */
+                       display_nhwindow(WIN_MESSAGE, TRUE);
+                       exit_nhwindows("Be seeing you...");
+                       terminate(EXIT_SUCCESS);
+               } else (void)doredraw();
+       }
+       return 0;
+}
+
+
+#if defined(UNIX) || defined(VMS) || defined (__EMX__) || defined(WIN32)
+/*ARGSUSED*/
+void
+hangup(sig_unused)  /* called as signal() handler, so sent at least one arg */
+int sig_unused;
+{
+# ifdef NOSAVEONHANGUP
+       (void) signal(SIGINT, SIG_IGN);
+       clearlocks();
+#  ifndef VMS
+       terminate(EXIT_FAILURE);
+#  endif
+# else /* SAVEONHANGUP */
+       if (!program_state.done_hup++) {
+           if (program_state.something_worth_saving)
+               (void) dosave0();
+#  ifdef VMS
+           /* don't call exit when already within an exit handler;
+              that would cancel any other pending user-mode handlers */
+           if (!program_state.exiting)
+#  endif
+           {
+               clearlocks();
+               terminate(EXIT_FAILURE);
+           }
+       }
+# endif
+       return;
+}
+#endif
+
+/* returns 1 if save successful */
+int
+dosave0()
+{
+       const char *fq_save;
+       register int fd, ofd;
+       xchar ltmp;
+       d_level uz_save;
+       char whynot[BUFSZ];
+
+       if (!SAVEF[0])
+               return 0;
+       fq_save = fqname(SAVEF, SAVEPREFIX, 1); /* level files take 0 */
+
+#if defined(UNIX) || defined(VMS)
+       (void) signal(SIGHUP, SIG_IGN);
+#endif
+#ifndef NO_SIGNAL
+       (void) signal(SIGINT, SIG_IGN);
+#endif
+
+#if defined(MICRO) && defined(MFLOPPY)
+       if (!saveDiskPrompt(0)) return 0;
+#endif
+
+       HUP if (iflags.window_inited) {
+           uncompress(fq_save);
+           fd = open_savefile();
+           if (fd > 0) {
+               (void) close(fd);
+               clear_nhwindow(WIN_MESSAGE);
+               There("seems to be an old save file.");
+               if (yn("Overwrite the old file?") == 'n') {
+                   compress(fq_save);
+                   return 0;
+               }
+           }
+       }
+
+       HUP mark_synch();       /* flush any buffered screen output */
+
+       fd = create_savefile();
+       if(fd < 0) {
+               HUP pline("Cannot open save file.");
+               (void) delete_savefile();       /* ab@unido */
+               return(0);
+       }
+
+       vision_recalc(2);       /* shut down vision to prevent problems
+                                  in the event of an impossible() call */
+       
+       /* undo date-dependent luck adjustments made at startup time */
+       if(flags.moonphase == FULL_MOON)        /* ut-sally!fletcher */
+               change_luck(-1);                /* and unido!ab */
+       if(flags.friday13)
+               change_luck(1);
+       if(iflags.window_inited)
+           HUP clear_nhwindow(WIN_MESSAGE);
+
+#ifdef MICRO
+       dotcnt = 0;
+       dotrow = 2;
+       curs(WIN_MAP, 1, 1);
+       if (strncmpi("X11", windowprocs.name, 3))
+         putstr(WIN_MAP, 0, "Saving:");
+#endif
+#ifdef MFLOPPY
+       /* make sure there is enough disk space */
+       if (iflags.checkspace) {
+           long fds, needed;
+
+           savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
+           savegamestate(fd, COUNT_SAVE);
+           needed = bytes_counted;
+
+           for (ltmp = 1; ltmp <= maxledgerno(); ltmp++)
+               if (ltmp != ledger_no(&u.uz) && level_info[ltmp].where)
+                   needed += level_info[ltmp].size + (sizeof ltmp);
+           fds = freediskspace(fq_save);
+           if (needed > fds) {
+               HUP {
+                   There("is insufficient space on SAVE disk.");
+                   pline("Require %ld bytes but only have %ld.", needed, fds);
+               }
+               flushout();
+               (void) close(fd);
+               (void) delete_savefile();
+               return 0;
+           }
+
+           co_false();
+       }
+#endif /* MFLOPPY */
+
+       store_version(fd);
+#ifdef STORE_PLNAME_IN_FILE
+       bwrite(fd, (genericptr_t) plname, PL_NSIZ);
+#endif
+       ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
+#ifdef STEED
+       usteed_id = (u.usteed ? u.usteed->m_id : 0);
+#endif
+       savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
+       savegamestate(fd, WRITE_SAVE | FREE_SAVE);
+
+       /* While copying level files around, zero out u.uz to keep
+        * parts of the restore code from completely initializing all
+        * in-core data structures, since all we're doing is copying.
+        * This also avoids at least one nasty core dump.
+        */
+       uz_save = u.uz;
+       u.uz.dnum = u.uz.dlevel = 0;
+       /* these pointers are no longer valid, and at least u.usteed
+        * may mislead place_monster() on other levels
+        */
+       u.ustuck = (struct monst *)0;
+#ifdef STEED
+       u.usteed = (struct monst *)0;
+#endif
+
+       for(ltmp = (xchar)1; ltmp <= maxledgerno(); ltmp++) {
+               if (ltmp == ledger_no(&uz_save)) continue;
+               if (!(level_info[ltmp].flags & LFILE_EXISTS)) continue;
+#ifdef MICRO
+               curs(WIN_MAP, 1 + dotcnt++, dotrow);
+               if (dotcnt >= (COLNO - 1)) {
+                       dotrow++;
+                       dotcnt = 0;
+               }
+               if (strncmpi("X11", windowprocs.name, 3)){
+                 putstr(WIN_MAP, 0, ".");
+               }
+               mark_synch();
+#endif
+               ofd = open_levelfile(ltmp, whynot);
+               if (ofd < 0) {
+                   HUP pline("%s", whynot);
+                   (void) close(fd);
+                   (void) delete_savefile();
+                   HUP killer = whynot;
+                   HUP done(TRICKED);
+                   return(0);
+               }
+               minit();        /* ZEROCOMP */
+               getlev(ofd, hackpid, ltmp, FALSE);
+               (void) close(ofd);
+               bwrite(fd, (genericptr_t) &ltmp, sizeof ltmp); /* level number*/
+               savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE);     /* actual level*/
+               delete_levelfile(ltmp);
+       }
+       bclose(fd);
+
+       u.uz = uz_save;
+
+       /* get rid of current level --jgm */
+       delete_levelfile(ledger_no(&u.uz));
+       delete_levelfile(0);
+       compress(fq_save);
+       return(1);
+}
+
+STATIC_OVL void
+savegamestate(fd, mode)
+register int fd, mode;
+{
+       int uid;
+
+#ifdef MFLOPPY
+       count_only = (mode & COUNT_SAVE);
+#endif
+       uid = getuid();
+       bwrite(fd, (genericptr_t) &uid, sizeof uid);
+       bwrite(fd, (genericptr_t) &flags, sizeof(struct flag));
+       bwrite(fd, (genericptr_t) &u, sizeof(struct you));
+
+       /* must come before migrating_objs and migrating_mons are freed */
+       save_timers(fd, mode, RANGE_GLOBAL);
+       save_light_sources(fd, mode, RANGE_GLOBAL);
+
+       saveobjchn(fd, invent, mode);
+       saveobjchn(fd, migrating_objs, mode);
+       savemonchn(fd, migrating_mons, mode);
+       if (release_data(mode)) {
+           invent = 0;
+           migrating_objs = 0;
+           migrating_mons = 0;
+       }
+       bwrite(fd, (genericptr_t) mvitals, sizeof(mvitals));
+
+       save_dungeon(fd, (boolean)!!perform_bwrite(mode),
+                        (boolean)!!release_data(mode));
+       savelevchn(fd, mode);
+       bwrite(fd, (genericptr_t) &moves, sizeof moves);
+       bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
+       bwrite(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
+       bwrite(fd, (genericptr_t) spl_book,
+                               sizeof(struct spell) * (MAXSPELL + 1));
+       save_artifacts(fd);
+       save_oracles(fd, mode);
+       if(ustuck_id)
+           bwrite(fd, (genericptr_t) &ustuck_id, sizeof ustuck_id);
+#ifdef STEED
+       if(usteed_id)
+           bwrite(fd, (genericptr_t) &usteed_id, sizeof usteed_id);
+#endif
+       bwrite(fd, (genericptr_t) pl_character, sizeof pl_character);
+       bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
+       bwrite(fd, (genericptr_t) &current_fruit, sizeof current_fruit);
+       savefruitchn(fd, mode);
+       savenames(fd, mode);
+       save_waterlevel(fd, mode);
+       bflush(fd);
+}
+
+#ifdef INSURANCE
+void
+savestateinlock()
+{
+       int fd, hpid;
+       static boolean havestate = TRUE;
+       char whynot[BUFSZ];
+
+       /* When checkpointing is on, the full state needs to be written
+        * on each checkpoint.  When checkpointing is off, only the pid
+        * needs to be in the level.0 file, so it does not need to be
+        * constantly rewritten.  When checkpointing is turned off during
+        * a game, however, the file has to be rewritten once to truncate
+        * it and avoid restoring from outdated information.
+        *
+        * Restricting havestate to this routine means that an additional
+        * noop pid rewriting will take place on the first "checkpoint" after
+        * the game is started or restored, if checkpointing is off.
+        */
+       if (flags.ins_chkpt || havestate) {
+               /* save the rest of the current game state in the lock file,
+                * following the original int pid, the current level number,
+                * and the current savefile name, which should not be subject
+                * to any internal compression schemes since they must be
+                * readable by an external utility
+                */
+               fd = open_levelfile(0, whynot);
+               if (fd < 0) {
+                   pline("%s", whynot);
+                   pline("Probably someone removed it.");
+                   killer = whynot;
+                   done(TRICKED);
+                   return;
+               }
+
+               (void) read(fd, (genericptr_t) &hpid, sizeof(hpid));
+               if (hackpid != hpid) {
+                   Sprintf(whynot,
+                           "Level #0 pid (%d) doesn't match ours (%d)!",
+                           hpid, hackpid);
+                   pline("%s", whynot);
+                   killer = whynot;
+                   done(TRICKED);
+               }
+               (void) close(fd);
+
+               fd = create_levelfile(0, whynot);
+               if (fd < 0) {
+                   pline("%s", whynot);
+                   killer = whynot;
+                   done(TRICKED);
+                   return;
+               }
+               (void) write(fd, (genericptr_t) &hackpid, sizeof(hackpid));
+               if (flags.ins_chkpt) {
+                   int currlev = ledger_no(&u.uz);
+
+                   (void) write(fd, (genericptr_t) &currlev, sizeof(currlev));
+                   save_savefile_name(fd);
+                   store_version(fd);
+#ifdef STORE_PLNAME_IN_FILE
+                   bwrite(fd, (genericptr_t) plname, PL_NSIZ);
+#endif
+                   ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
+#ifdef STEED
+                   usteed_id = (u.usteed ? u.usteed->m_id : 0);
+#endif
+                   savegamestate(fd, WRITE_SAVE);
+               }
+               bclose(fd);
+       }
+       havestate = flags.ins_chkpt;
+}
+#endif
+
+#ifdef MFLOPPY
+boolean
+savelev(fd, lev, mode)
+int fd;
+xchar lev;
+int mode;
+{
+       if (mode & COUNT_SAVE) {
+               bytes_counted = 0;
+               savelev0(fd, lev, COUNT_SAVE);
+               /* probably bytes_counted will be filled in again by an
+                * immediately following WRITE_SAVE anyway, but we'll
+                * leave it out of checkspace just in case */
+               if (iflags.checkspace) {
+                       while (bytes_counted > freediskspace(levels))
+                               if (!swapout_oldest())
+                                       return FALSE;
+               }
+       }
+       if (mode & (WRITE_SAVE | FREE_SAVE)) {
+               bytes_counted = 0;
+               savelev0(fd, lev, mode);
+       }
+       if (mode != FREE_SAVE) {
+               level_info[lev].where = ACTIVE;
+               level_info[lev].time = moves;
+               level_info[lev].size = bytes_counted;
+       }
+       return TRUE;
+}
+
+STATIC_OVL void
+savelev0(fd,lev,mode)
+#else
+void
+savelev(fd,lev,mode)
+#endif
+int fd;
+xchar lev;
+int mode;
+{
+#ifdef TOS
+       short tlev;
+#endif
+
+       /* if we're tearing down the current level without saving anything
+          (which happens upon entrance to the endgame or after an aborted
+          restore attempt) then we don't want to do any actual I/O */
+       if (mode == FREE_SAVE) goto skip_lots;
+       if (iflags.purge_monsters) {
+               /* purge any dead monsters (necessary if we're starting
+                * a panic save rather than a normal one, or sometimes
+                * when changing levels without taking time -- e.g.
+                * create statue trap then immediately level teleport) */
+               dmonsfree();
+       }
+
+       if(fd < 0) panic("Save on bad file!");  /* impossible */
+#ifdef MFLOPPY
+       count_only = (mode & COUNT_SAVE);
+#endif
+       if (lev >= 0 && lev <= maxledgerno())
+           level_info[lev].flags |= VISITED;
+       bwrite(fd,(genericptr_t) &hackpid,sizeof(hackpid));
+#ifdef TOS
+       tlev=lev; tlev &= 0x00ff;
+       bwrite(fd,(genericptr_t) &tlev,sizeof(tlev));
+#else
+       bwrite(fd,(genericptr_t) &lev,sizeof(lev));
+#endif
+#ifdef RLECOMP
+       {
+           /* perform run-length encoding of rm structs */
+           struct rm *prm, *rgrm;
+           int x, y;
+           uchar match;
+
+           rgrm = &levl[0][0];         /* start matching at first rm */
+           match = 0;
+
+           for (y = 0; y < ROWNO; y++) {
+               for (x = 0; x < COLNO; x++) {
+                   prm = &levl[x][y];
+                   if (prm->glyph == rgrm->glyph
+                       && prm->typ == rgrm->typ
+                       && prm->seenv == rgrm->seenv
+                       && prm->horizontal == rgrm->horizontal
+                       && prm->flags == rgrm->flags
+                       && prm->lit == rgrm->lit
+                       && prm->waslit == rgrm->waslit
+                       && prm->roomno == rgrm->roomno
+                       && prm->edge == rgrm->edge) {
+                       match++;
+                       if (match > 254) {
+                           match = 254;        /* undo this match */
+                           goto writeout;
+                       }
+                   } else {
+                       /* the run has been broken,
+                        * write out run-length encoding */
+                   writeout:
+                       bwrite(fd, (genericptr_t)&match, sizeof(uchar));
+                       bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
+                       /* start encoding again. we have at least 1 rm
+                        * in the next run, viz. this one. */
+                       match = 1;
+                       rgrm = prm;
+                   }
+               }
+           }
+           if (match > 0) {
+               bwrite(fd, (genericptr_t)&match, sizeof(uchar));
+               bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
+           }
+       }
+#else
+       bwrite(fd,(genericptr_t) levl,sizeof(levl));
+#endif /* RLECOMP */
+
+       bwrite(fd,(genericptr_t) &monstermoves,sizeof(monstermoves));
+       bwrite(fd,(genericptr_t) &upstair,sizeof(stairway));
+       bwrite(fd,(genericptr_t) &dnstair,sizeof(stairway));
+       bwrite(fd,(genericptr_t) &upladder,sizeof(stairway));
+       bwrite(fd,(genericptr_t) &dnladder,sizeof(stairway));
+       bwrite(fd,(genericptr_t) &sstairs,sizeof(stairway));
+       bwrite(fd,(genericptr_t) &updest,sizeof(dest_area));
+       bwrite(fd,(genericptr_t) &dndest,sizeof(dest_area));
+       bwrite(fd,(genericptr_t) &level.flags,sizeof(level.flags));
+       bwrite(fd, (genericptr_t) doors, sizeof(doors));
+       save_rooms(fd); /* no dynamic memory to reclaim */
+
+       /* from here on out, saving also involves allocated memory cleanup */
+ skip_lots:
+       /* must be saved before mons, objs, and buried objs */
+       save_timers(fd, mode, RANGE_LEVEL);
+       save_light_sources(fd, mode, RANGE_LEVEL);
+
+       savemonchn(fd, fmon, mode);
+       save_worm(fd, mode);    /* save worm information */
+       savetrapchn(fd, ftrap, mode);
+       saveobjchn(fd, fobj, mode);
+       saveobjchn(fd, level.buriedobjlist, mode);
+       saveobjchn(fd, billobjs, mode);
+       if (release_data(mode)) {
+           fmon = 0;
+           ftrap = 0;
+           fobj = 0;
+           level.buriedobjlist = 0;
+           billobjs = 0;
+       }
+       save_engravings(fd, mode);
+       savedamage(fd, mode);
+       save_regions(fd, mode);
+       if (mode != FREE_SAVE) bflush(fd);
+}
+
+#ifdef ZEROCOMP
+/* The runs of zero-run compression are flushed after the game state or a
+ * level is written out.  This adds a couple bytes to a save file, where
+ * the runs could be mashed together, but it allows gluing together game
+ * state and level files to form a save file, and it means the flushing
+ * does not need to be specifically called for every other time a level
+ * file is written out.
+ */
+
+#define RLESC '\0'    /* Leading character for run of LRESC's */
+#define flushoutrun(ln) (bputc(RLESC), bputc(ln), ln = -1)
+
+#ifndef ZEROCOMP_BUFSIZ
+# define ZEROCOMP_BUFSIZ BUFSZ
+#endif
+static NEARDATA unsigned char outbuf[ZEROCOMP_BUFSIZ];
+static NEARDATA unsigned short outbufp = 0;
+static NEARDATA short outrunlength = -1;
+static NEARDATA int bwritefd;
+static NEARDATA boolean compressing = FALSE;
+
+/*dbg()
+{
+    HUP printf("outbufp %d outrunlength %d\n", outbufp,outrunlength);
+}*/
+
+STATIC_OVL void
+bputc(c)
+int c;
+{
+#ifdef MFLOPPY
+    bytes_counted++;
+    if (count_only)
+      return;
+#endif
+    if (outbufp >= sizeof outbuf) {
+       (void) write(bwritefd, outbuf, sizeof outbuf);
+       outbufp = 0;
+    }
+    outbuf[outbufp++] = (unsigned char)c;
+}
+
+/*ARGSUSED*/
+void
+bufon(fd)
+int fd;
+{
+    compressing = TRUE;
+    return;
+}
+
+/*ARGSUSED*/
+void
+bufoff(fd)
+int fd;
+{
+    if (outbufp) {
+       outbufp = 0;
+       panic("closing file with buffered data still unwritten");
+    }
+    outrunlength = -1;
+    compressing = FALSE;
+    return;
+}
+
+void
+bflush(fd)  /* flush run and buffer */
+register int fd;
+{
+    bwritefd = fd;
+    if (outrunlength >= 0) {   /* flush run */
+       flushoutrun(outrunlength);
+    }
+#ifdef MFLOPPY
+    if (count_only) outbufp = 0;
+#endif
+
+    if (outbufp) {
+       if (write(fd, outbuf, outbufp) != outbufp) {
+#if defined(UNIX) || defined(VMS) || defined(__EMX__)
+           if (program_state.done_hup)
+               terminate(EXIT_FAILURE);
+           else
+#endif
+               bclose(fd);     /* panic (outbufp != 0) */
+       }
+       outbufp = 0;
+    }
+}
+
+void
+bwrite(fd, loc, num)
+int fd;
+genericptr_t loc;
+register unsigned num;
+{
+    register unsigned char *bp = (unsigned char *)loc;
+
+    if (!compressing) {
+#ifdef MFLOPPY
+       bytes_counted += num;
+       if (count_only) return;
+#endif
+       if ((unsigned) write(fd, loc, num) != num) {
+#if defined(UNIX) || defined(VMS) || defined(__EMX__)
+           if (program_state.done_hup)
+               terminate(EXIT_FAILURE);
+           else
+#endif
+               panic("cannot write %u bytes to file #%d", num, fd);
+       }
+    } else {
+       bwritefd = fd;
+       for (; num; num--, bp++) {
+           if (*bp == RLESC) { /* One more char in run */
+               if (++outrunlength == 0xFF) {
+                   flushoutrun(outrunlength);
+               }
+           } else {            /* end of run */
+               if (outrunlength >= 0) {        /* flush run */
+                   flushoutrun(outrunlength);
+               }
+               bputc(*bp);
+           }
+       }
+    }
+}
+
+void
+bclose(fd)
+int fd;
+{
+    bufoff(fd);
+    (void) close(fd);
+    return;
+}
+
+#else /* ZEROCOMP */
+
+static int bw_fd = -1;
+static FILE *bw_FILE = 0;
+static boolean buffering = FALSE;
+
+void
+bufon(fd)
+    int fd;
+{
+#ifdef UNIX
+    if(bw_fd >= 0)
+       panic("double buffering unexpected");
+    bw_fd = fd;
+    if((bw_FILE = fdopen(fd, "w")) == 0)
+       panic("buffering of file %d failed", fd);
+#endif
+    buffering = TRUE;
+}
+
+void
+bufoff(fd)
+int fd;
+{
+    bflush(fd);
+    buffering = FALSE;
+}
+
+void
+bflush(fd)
+    int fd;
+{
+#ifdef UNIX
+    if(fd == bw_fd) {
+       if(fflush(bw_FILE) == EOF)
+           panic("flush of savefile failed!");
+    }
+#endif
+    return;
+}
+
+void
+bwrite(fd,loc,num)
+register int fd;
+register genericptr_t loc;
+register unsigned num;
+{
+       boolean failed;
+
+#ifdef MFLOPPY
+       bytes_counted += num;
+       if (count_only) return;
+#endif
+
+#ifdef UNIX
+       if (buffering) {
+           if(fd != bw_fd)
+               panic("unbuffered write to fd %d (!= %d)", fd, bw_fd);
+
+           failed = (fwrite(loc, (int)num, 1, bw_FILE) != 1);
+       } else
+#endif /* UNIX */
+       {
+/* lint wants the 3rd arg of write to be an int; lint -p an unsigned */
+#if defined(BSD) || defined(ULTRIX)
+           failed = (write(fd, loc, (int)num) != (int)num);
+#else /* e.g. SYSV, __TURBOC__ */
+           failed = (write(fd, loc, num) != num);
+#endif
+       }
+
+       if (failed) {
+#if defined(UNIX) || defined(VMS) || defined(__EMX__)
+           if (program_state.done_hup)
+               terminate(EXIT_FAILURE);
+           else
+#endif
+               panic("cannot write %u bytes to file #%d", num, fd);
+       }
+}
+
+void
+bclose(fd)
+    int fd;
+{
+    bufoff(fd);
+#ifdef UNIX
+    if (fd == bw_fd) {
+       (void) fclose(bw_FILE);
+       bw_fd = -1;
+       bw_FILE = 0;
+    } else
+#endif
+       (void) close(fd);
+    return;
+}
+#endif /* ZEROCOMP */
+
+STATIC_OVL void
+savelevchn(fd, mode)
+register int fd, mode;
+{
+       s_level *tmplev, *tmplev2;
+       int cnt = 0;
+
+       for (tmplev = sp_levchn; tmplev; tmplev = tmplev->next) cnt++;
+       if (perform_bwrite(mode))
+           bwrite(fd, (genericptr_t) &cnt, sizeof(int));
+
+       for (tmplev = sp_levchn; tmplev; tmplev = tmplev2) {
+           tmplev2 = tmplev->next;
+           if (perform_bwrite(mode))
+               bwrite(fd, (genericptr_t) tmplev, sizeof(s_level));
+           if (release_data(mode))
+               free((genericptr_t) tmplev);
+       }
+       if (release_data(mode))
+           sp_levchn = 0;
+}
+
+STATIC_OVL void
+savedamage(fd, mode)
+register int fd, mode;
+{
+       register struct damage *damageptr, *tmp_dam;
+       unsigned int xl = 0;
+
+       damageptr = level.damagelist;
+       for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next)
+           xl++;
+       if (perform_bwrite(mode))
+           bwrite(fd, (genericptr_t) &xl, sizeof(xl));
+
+       while (xl--) {
+           if (perform_bwrite(mode))
+               bwrite(fd, (genericptr_t) damageptr, sizeof(*damageptr));
+           tmp_dam = damageptr;
+           damageptr = damageptr->next;
+           if (release_data(mode))
+               free((genericptr_t)tmp_dam);
+       }
+       if (release_data(mode))
+           level.damagelist = 0;
+}
+
+STATIC_OVL void
+saveobjchn(fd, otmp, mode)
+register int fd, mode;
+register struct obj *otmp;
+{
+       register struct obj *otmp2;
+       unsigned int xl;
+       int minusone = -1;
+
+       while(otmp) {
+           otmp2 = otmp->nobj;
+           if (perform_bwrite(mode)) {
+               xl = otmp->oxlth + otmp->onamelth;
+               bwrite(fd, (genericptr_t) &xl, sizeof(int));
+               bwrite(fd, (genericptr_t) otmp, xl + sizeof(struct obj));
+           }
+           if (Has_contents(otmp))
+               saveobjchn(fd,otmp->cobj,mode);
+           if (release_data(mode)) {
+               if (otmp->oclass == FOOD_CLASS) food_disappears(otmp);
+               if (otmp->oclass == SPBOOK_CLASS) book_disappears(otmp);
+               otmp->where = OBJ_FREE; /* set to free so dealloc will work */
+               otmp->timed = 0;        /* not timed any more */
+               otmp->lamplit = 0;      /* caller handled lights */
+               dealloc_obj(otmp);
+           }
+           otmp = otmp2;
+       }
+       if (perform_bwrite(mode))
+           bwrite(fd, (genericptr_t) &minusone, sizeof(int));
+}
+
+STATIC_OVL void
+savemonchn(fd, mtmp, mode)
+register int fd, mode;
+register struct monst *mtmp;
+{
+       register struct monst *mtmp2;
+       unsigned int xl;
+       int minusone = -1;
+       struct permonst *monbegin = &mons[0];
+
+       if (perform_bwrite(mode))
+           bwrite(fd, (genericptr_t) &monbegin, sizeof(monbegin));
+
+       while (mtmp) {
+           mtmp2 = mtmp->nmon;
+           if (perform_bwrite(mode)) {
+               xl = mtmp->mxlth + mtmp->mnamelth;
+               bwrite(fd, (genericptr_t) &xl, sizeof(int));
+               bwrite(fd, (genericptr_t) mtmp, xl + sizeof(struct monst));
+           }
+           if (mtmp->minvent)
+               saveobjchn(fd,mtmp->minvent,mode);
+           if (release_data(mode))
+               dealloc_monst(mtmp);
+           mtmp = mtmp2;
+       }
+       if (perform_bwrite(mode))
+           bwrite(fd, (genericptr_t) &minusone, sizeof(int));
+}
+
+STATIC_OVL void
+savetrapchn(fd, trap, mode)
+register int fd, mode;
+register struct trap *trap;
+{
+       register struct trap *trap2;
+
+       while (trap) {
+           trap2 = trap->ntrap;
+           if (perform_bwrite(mode))
+               bwrite(fd, (genericptr_t) trap, sizeof(struct trap));
+           if (release_data(mode))
+               dealloc_trap(trap);
+           trap = trap2;
+       }
+       if (perform_bwrite(mode))
+           bwrite(fd, (genericptr_t)nulls, sizeof(struct trap));
+}
+
+/* save all the fruit names and ID's; this is used only in saving whole games
+ * (not levels) and in saving bones levels.  When saving a bones level,
+ * we only want to save the fruits which exist on the bones level; the bones
+ * level routine marks nonexistent fruits by making the fid negative.
+ */
+void
+savefruitchn(fd, mode)
+register int fd, mode;
+{
+       register struct fruit *f2, *f1;
+
+       f1 = ffruit;
+       while (f1) {
+           f2 = f1->nextf;
+           if (f1->fid >= 0 && perform_bwrite(mode))
+               bwrite(fd, (genericptr_t) f1, sizeof(struct fruit));
+           if (release_data(mode))
+               dealloc_fruit(f1);
+           f1 = f2;
+       }
+       if (perform_bwrite(mode))
+           bwrite(fd, (genericptr_t)nulls, sizeof(struct fruit));
+       if (release_data(mode))
+           ffruit = 0;
+}
+
+/* also called by prscore(); this probably belongs in dungeon.c... */
+void
+free_dungeons()
+{
+#ifdef FREE_ALL_MEMORY
+       savelevchn(0, FREE_SAVE);
+       save_dungeon(0, FALSE, TRUE);
+#endif
+       return;
+}
+
+void
+freedynamicdata()
+{
+       unload_qtlist();
+       free_invbuf();  /* let_to_name (invent.c) */
+       free_youbuf();  /* You_buf,&c (pline.c) */
+       tmp_at(DISP_FREEMEM, 0);        /* temporary display effects */
+#ifdef FREE_ALL_MEMORY
+# define freeobjchn(X) (saveobjchn(0, X, FREE_SAVE),  X = 0)
+# define freemonchn(X) (savemonchn(0, X, FREE_SAVE),  X = 0)
+# define freetrapchn(X)        (savetrapchn(0, X, FREE_SAVE), X = 0)
+# define freefruitchn()         savefruitchn(0, FREE_SAVE)
+# define freenames()    savenames(0, FREE_SAVE)
+# define free_oracles()        save_oracles(0, FREE_SAVE)
+# define free_waterlevel() save_waterlevel(0, FREE_SAVE)
+# define free_worm()    save_worm(0, FREE_SAVE)
+# define free_timers(R)         save_timers(0, FREE_SAVE, R)
+# define free_light_sources(R) save_light_sources(0, FREE_SAVE, R);
+# define free_engravings() save_engravings(0, FREE_SAVE)
+# define freedamage()   savedamage(0, FREE_SAVE)
+# define free_animals()         mon_animal_list(FALSE)
+
+       /* move-specific data */
+       dmonsfree();            /* release dead monsters */
+
+       /* level-specific data */
+       free_timers(RANGE_LEVEL);
+       free_light_sources(RANGE_LEVEL);
+       freemonchn(fmon);
+       free_worm();            /* release worm segment information */
+       freetrapchn(ftrap);
+       freeobjchn(fobj);
+       freeobjchn(level.buriedobjlist);
+       freeobjchn(billobjs);
+       free_engravings();
+       freedamage();
+
+       /* game-state data */
+       free_timers(RANGE_GLOBAL);
+       free_light_sources(RANGE_GLOBAL);
+       freeobjchn(invent);
+       freeobjchn(migrating_objs);
+       freemonchn(migrating_mons);
+       freemonchn(mydogs);             /* ascension or dungeon escape */
+     /* freelevchn();  [folded into free_dungeons()] */
+       free_animals();
+       free_oracles();
+       freefruitchn();
+       freenames();
+       free_waterlevel();
+       free_dungeons();
+
+       /* some pointers in iflags */
+       if (iflags.wc_font_map) free(iflags.wc_font_map);
+       if (iflags.wc_font_message) free(iflags.wc_font_message);
+       if (iflags.wc_font_text) free(iflags.wc_font_text);
+       if (iflags.wc_font_menu) free(iflags.wc_font_menu);
+       if (iflags.wc_font_status) free(iflags.wc_font_status);
+       if (iflags.wc_tile_file) free(iflags.wc_tile_file);
+#ifdef AUTOPICKUP_EXCEPTIONS
+       free_autopickup_exceptions();
+#endif
+
+#endif /* FREE_ALL_MEMORY */
+       return;
+}
+
+#ifdef MFLOPPY
+boolean
+swapin_file(lev)
+int lev;
+{
+       char to[PATHLEN], from[PATHLEN];
+
+       Sprintf(from, "%s%s", permbones, alllevels);
+       Sprintf(to, "%s%s", levels, alllevels);
+       set_levelfile_name(from, lev);
+       set_levelfile_name(to, lev);
+       if (iflags.checkspace) {
+               while (level_info[lev].size > freediskspace(to))
+                       if (!swapout_oldest())
+                               return FALSE;
+       }
+# ifdef WIZARD
+       if (wizard) {
+               pline("Swapping in `%s'.", from);
+               wait_synch();
+       }
+# endif
+       copyfile(from, to);
+       (void) unlink(from);
+       level_info[lev].where = ACTIVE;
+       return TRUE;
+}
+
+STATIC_OVL boolean
+swapout_oldest() {
+       char to[PATHLEN], from[PATHLEN];
+       int i, oldest;
+       long oldtime;
+
+       if (!ramdisk)
+               return FALSE;
+       for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno(); i++)
+               if (level_info[i].where == ACTIVE
+               && (!oldtime || level_info[i].time < oldtime)) {
+                       oldest = i;
+                       oldtime = level_info[i].time;
+               }
+       if (!oldest)
+               return FALSE;
+       Sprintf(from, "%s%s", levels, alllevels);
+       Sprintf(to, "%s%s", permbones, alllevels);
+       set_levelfile_name(from, oldest);
+       set_levelfile_name(to, oldest);
+# ifdef WIZARD
+       if (wizard) {
+               pline("Swapping out `%s'.", from);
+               wait_synch();
+       }
+# endif
+       copyfile(from, to);
+       (void) unlink(from);
+       level_info[oldest].where = SWAPPED;
+       return TRUE;
+}
+
+STATIC_OVL void
+copyfile(from, to)
+char *from, *to;
+{
+# ifdef TOS
+
+       if (_copyfile(from, to))
+               panic("Can't copy %s to %s", from, to);
+# else
+       char buf[BUFSIZ];       /* this is system interaction, therefore
+                                * BUFSIZ instead of NetHack's BUFSZ */
+       int nfrom, nto, fdfrom, fdto;
+
+       if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0)
+               panic("Can't copy from %s !?", from);
+       if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0)
+               panic("Can't copy to %s", to);
+       do {
+               nfrom = read(fdfrom, buf, BUFSIZ);
+               nto = write(fdto, buf, nfrom);
+               if (nto != nfrom)
+                       panic("Copyfile failed!");
+       } while (nfrom == BUFSIZ);
+       (void) close(fdfrom);
+       (void) close(fdto);
+# endif /* TOS */
+}
+
+void
+co_false()         /* see comment in bones.c */
+{
+    count_only = FALSE;
+    return;
+}
+
+#endif /* MFLOPPY */
+
+/*save.c*/
diff --git a/src/shk.c b/src/shk.c
new file mode 100644 (file)
index 0000000..53c868b
--- /dev/null
+++ b/src/shk.c
@@ -0,0 +1,4098 @@
+/*     SCCS Id: @(#)shk.c      3.4     2003/12/04      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "eshk.h"
+
+/*#define DEBUG*/
+
+#define PAY_SOME    2
+#define PAY_BUY     1
+#define PAY_CANT    0  /* too poor */
+#define PAY_SKIP  (-1)
+#define PAY_BROKE (-2)
+
+#ifdef KOPS
+STATIC_DCL void FDECL(makekops, (coord *));
+STATIC_DCL void FDECL(call_kops, (struct monst *,BOOLEAN_P));
+# ifdef OVLB
+STATIC_DCL void FDECL(kops_gone, (BOOLEAN_P));
+# endif /* OVLB */
+#endif /* KOPS */
+
+#define IS_SHOP(x)     (rooms[x].rtype >= SHOPBASE)
+
+extern const struct shclass shtypes[]; /* defined in shknam.c */
+extern struct obj *thrownobj;          /* defined in dothrow.c */
+
+STATIC_VAR NEARDATA long int followmsg;        /* last time of follow message */
+
+STATIC_DCL void FDECL(setpaid, (struct monst *));
+STATIC_DCL long FDECL(addupbill, (struct monst *));
+STATIC_DCL void FDECL(pacify_shk, (struct monst *));
+STATIC_DCL struct bill_x *FDECL(onbill, (struct obj *, struct monst *, BOOLEAN_P));
+STATIC_DCL struct monst *FDECL(next_shkp, (struct monst *, BOOLEAN_P));
+STATIC_DCL long FDECL(shop_debt, (struct eshk *));
+STATIC_DCL char *FDECL(shk_owns, (char *,struct obj *));
+STATIC_DCL char *FDECL(mon_owns, (char *,struct obj *));
+STATIC_DCL void FDECL(clear_unpaid,(struct obj *));
+STATIC_DCL long FDECL(check_credit, (long, struct monst *));
+STATIC_DCL void FDECL(pay, (long, struct monst *));
+STATIC_DCL long FDECL(get_cost, (struct obj *, struct monst *));
+STATIC_DCL long FDECL(set_cost, (struct obj *, struct monst *));
+STATIC_DCL const char *FDECL(shk_embellish, (struct obj *, long));
+STATIC_DCL long FDECL(cost_per_charge, (struct monst *,struct obj *,BOOLEAN_P));
+STATIC_DCL long FDECL(cheapest_item, (struct monst *));
+STATIC_DCL int FDECL(dopayobj, (struct monst *, struct bill_x *,
+                           struct obj **, int, BOOLEAN_P));
+STATIC_DCL long FDECL(stolen_container, (struct obj *, struct monst *, long,
+                                    BOOLEAN_P));
+STATIC_DCL long FDECL(getprice, (struct obj *,BOOLEAN_P));
+STATIC_DCL void FDECL(shk_names_obj,
+                (struct monst *,struct obj *,const char *,long,const char *));
+STATIC_DCL struct obj *FDECL(bp_to_obj, (struct bill_x *));
+STATIC_DCL boolean FDECL(inherits, (struct monst *,int,int));
+STATIC_DCL void FDECL(set_repo_loc, (struct eshk *));
+STATIC_DCL boolean NDECL(angry_shk_exists);
+STATIC_DCL void FDECL(rile_shk, (struct monst *));
+STATIC_DCL void FDECL(rouse_shk, (struct monst *,BOOLEAN_P));
+STATIC_DCL void FDECL(remove_damage, (struct monst *, BOOLEAN_P));
+STATIC_DCL void FDECL(sub_one_frombill, (struct obj *, struct monst *));
+STATIC_DCL void FDECL(add_one_tobill, (struct obj *, BOOLEAN_P));
+STATIC_DCL void FDECL(dropped_container, (struct obj *, struct monst *,
+                                     BOOLEAN_P));
+STATIC_DCL void FDECL(add_to_billobjs, (struct obj *));
+STATIC_DCL void FDECL(bill_box_content, (struct obj *, BOOLEAN_P, BOOLEAN_P,
+                                    struct monst *));
+#ifdef OVL1
+static boolean FDECL(rob_shop, (struct monst *));
+#endif
+
+#ifdef OVLB
+/*
+       invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
+               obj->quan <= bp->bquan
+ */
+
+
+#ifdef GOLDOBJ
+/*
+    Transfer money from inventory to monster when paying
+    shopkeepers, priests, oracle, succubus, & other demons.
+    Simple with only gold coins.
+    This routine will handle money changing when multiple
+    coin types is implemented, only appropriate
+    monsters will pay change.  (Peaceful shopkeepers, priests
+    & the oracle try to maintain goodwill while selling
+    their wares or services.  Angry monsters and all demons
+    will keep anything they get their hands on.
+    Returns the amount actually paid, so we can know
+    if the monster kept the change.
+ */
+long
+money2mon(mon, amount)
+struct monst *mon;
+long amount;
+{
+    struct obj *ygold = findgold(invent);
+
+    if (amount <= 0) {
+       impossible("%s payment in money2mon!", amount ? "negative" : "zero");
+       return 0L;
+    }
+    if (!ygold || ygold->quan < amount) {
+       impossible("Paying without %s money?", ygold ? "enough" : "");
+       return 0L;
+    }
+
+    if (ygold->quan > amount)
+       ygold = splitobj(ygold, amount);
+    else if (ygold->owornmask)
+       remove_worn_item(ygold, FALSE);         /* quiver */
+    freeinv(ygold);
+    add_to_minv(mon, ygold);
+    flags.botl = 1;
+    return amount;
+}
+
+
+/*
+    Transfer money from monster to inventory.
+    Used when the shopkeeper pay for items, and when
+    the priest gives you money for an ale.
+ */
+void
+money2u(mon, amount)
+struct monst *mon;
+long amount;
+{
+    struct obj *mongold = findgold(mon->minvent);
+
+    if (amount <= 0) {
+       impossible("%s payment in money2u!", amount ? "negative" : "zero");
+       return;
+    }
+    if (!mongold || mongold->quan < amount) {
+       impossible("%s paying without %s money?", a_monnam(mon),
+                  mongold ? "enough" : "");
+       return;
+    }
+
+    if (mongold->quan > amount) mongold = splitobj(mongold, amount);
+    obj_extract_self(mongold);
+
+    if (!merge_choice(invent, mongold) && inv_cnt() >= 52) {
+       You("have no room for the money!");
+       dropy(mongold);
+    } else {
+       addinv(mongold);
+       flags.botl = 1;
+    }
+}
+
+#endif /* GOLDOBJ */
+
+STATIC_OVL struct monst *
+next_shkp(shkp, withbill)
+register struct monst *shkp;
+register boolean withbill;
+{
+       for (; shkp; shkp = shkp->nmon) {
+           if (DEADMONSTER(shkp)) continue;
+           if (shkp->isshk && (ESHK(shkp)->billct || !withbill)) break;
+       }
+
+       if (shkp) {
+           if (NOTANGRY(shkp)) {
+               if (ESHK(shkp)->surcharge) pacify_shk(shkp);
+           } else {
+               if (!ESHK(shkp)->surcharge) rile_shk(shkp);
+           }
+       }
+       return(shkp);
+}
+
+char *
+shkname(mtmp)                          /* called in do_name.c */
+register struct monst *mtmp;
+{
+       return(ESHK(mtmp)->shknam);
+}
+
+void
+shkgone(mtmp)                          /* called in mon.c */
+struct monst *mtmp;
+{
+       struct eshk *eshk = ESHK(mtmp);
+       struct mkroom *sroom = &rooms[eshk->shoproom - ROOMOFFSET];
+       struct obj *otmp;
+       char *p;
+       int sx, sy;
+
+       /* [BUG: some of this should be done on the shop level */
+       /*       even when the shk dies on a different level.] */
+       if (on_level(&eshk->shoplevel, &u.uz)) {
+           remove_damage(mtmp, TRUE);
+           sroom->resident = (struct monst *)0;
+           if (!search_special(ANY_SHOP))
+               level.flags.has_shop = 0;
+
+           /* items on shop floor revert to ordinary objects */
+           for (sx = sroom->lx; sx <= sroom->hx; sx++)
+             for (sy = sroom->ly; sy <= sroom->hy; sy++)
+               for (otmp = level.objects[sx][sy]; otmp; otmp = otmp->nexthere)
+                   otmp->no_charge = 0;
+
+           /* Make sure bill is set only when the
+              dead shk is the resident shk. */
+           if ((p = index(u.ushops, eshk->shoproom)) != 0) {
+               setpaid(mtmp);
+               eshk->bill_p = (struct bill_x *)0;
+               /* remove eshk->shoproom from u.ushops */
+               do { *p = *(p + 1); } while (*++p);
+           }
+       }
+}
+
+void
+set_residency(shkp, zero_out)
+register struct monst *shkp;
+register boolean zero_out;
+{
+       if (on_level(&(ESHK(shkp)->shoplevel), &u.uz))
+           rooms[ESHK(shkp)->shoproom - ROOMOFFSET].resident =
+               (zero_out)? (struct monst *)0 : shkp;
+}
+
+void
+replshk(mtmp,mtmp2)
+register struct monst *mtmp, *mtmp2;
+{
+       rooms[ESHK(mtmp2)->shoproom - ROOMOFFSET].resident = mtmp2;
+       if (inhishop(mtmp) && *u.ushops == ESHK(mtmp)->shoproom) {
+               ESHK(mtmp2)->bill_p = &(ESHK(mtmp2)->bill[0]);
+       }
+}
+
+/* do shopkeeper specific structure munging -dlc */
+void
+restshk(shkp, ghostly)
+struct monst *shkp;
+boolean ghostly;
+{
+    if (u.uz.dlevel) {
+       struct eshk *eshkp = ESHK(shkp);
+
+       if (eshkp->bill_p != (struct bill_x *) -1000)
+           eshkp->bill_p = &eshkp->bill[0];
+       /* shoplevel can change as dungeons move around */
+       /* savebones guarantees that non-homed shk's will be gone */
+       if (ghostly) {
+           assign_level(&eshkp->shoplevel, &u.uz);
+           if (ANGRY(shkp) && strncmpi(eshkp->customer, plname, PL_NSIZ))
+               pacify_shk(shkp);
+       }
+    }
+}
+
+#endif /* OVLB */
+#ifdef OVL3
+
+/* Clear the unpaid bit on all of the objects in the list. */
+STATIC_OVL void
+clear_unpaid(list)
+register struct obj *list;
+{
+    while (list) {
+       if (Has_contents(list)) clear_unpaid(list->cobj);
+       list->unpaid = 0;
+       list = list->nobj;
+    }
+}
+#endif /*OVL3*/
+#ifdef OVLB
+
+/* either you paid or left the shop or the shopkeeper died */
+STATIC_OVL void
+setpaid(shkp)
+register struct monst *shkp;
+{
+       register struct obj *obj;
+       register struct monst *mtmp;
+
+       /* FIXME: object handling should be limited to
+          items which are on this particular shk's bill */
+
+       clear_unpaid(invent);
+       clear_unpaid(fobj);
+       clear_unpaid(level.buriedobjlist);
+       if (thrownobj) thrownobj->unpaid = 0;
+       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+               clear_unpaid(mtmp->minvent);
+       for(mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
+               clear_unpaid(mtmp->minvent);
+
+       while ((obj = billobjs) != 0) {
+               obj_extract_self(obj);
+               dealloc_obj(obj);
+       }
+       if(shkp) {
+               ESHK(shkp)->billct = 0;
+               ESHK(shkp)->credit = 0L;
+               ESHK(shkp)->debit = 0L;
+               ESHK(shkp)->loan = 0L;
+       }
+}
+
+STATIC_OVL long
+addupbill(shkp)
+register struct monst *shkp;
+{
+       register int ct = ESHK(shkp)->billct;
+       register struct bill_x *bp = ESHK(shkp)->bill_p;
+       register long total = 0L;
+
+       while(ct--){
+               total += bp->price * bp->bquan;
+               bp++;
+       }
+       return(total);
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+#ifdef KOPS
+STATIC_OVL void
+call_kops(shkp, nearshop)
+register struct monst *shkp;
+register boolean nearshop;
+{
+       /* Keystone Kops srt@ucla */
+       register boolean nokops;
+
+       if(!shkp) return;
+
+       if (flags.soundok)
+           pline("An alarm sounds!");
+
+       nokops = ((mvitals[PM_KEYSTONE_KOP].mvflags & G_GONE) &&
+                 (mvitals[PM_KOP_SERGEANT].mvflags & G_GONE) &&
+                 (mvitals[PM_KOP_LIEUTENANT].mvflags & G_GONE) &&
+                 (mvitals[PM_KOP_KAPTAIN].mvflags & G_GONE));
+
+       if(!angry_guards(!flags.soundok) && nokops) {
+           if(flags.verbose && flags.soundok)
+               pline("But no one seems to respond to it.");
+           return;
+       }
+
+       if(nokops) return;
+
+       {
+           coord mm;
+
+           if (nearshop) {
+               /* Create swarm around you, if you merely "stepped out" */
+               if (flags.verbose)
+                   pline_The("Keystone Kops appear!");
+               mm.x = u.ux;
+               mm.y = u.uy;
+               makekops(&mm);
+               return;
+           }
+           if (flags.verbose)
+                pline_The("Keystone Kops are after you!");
+           /* Create swarm near down staircase (hinders return to level) */
+           mm.x = xdnstair;
+           mm.y = ydnstair;
+           makekops(&mm);
+           /* Create swarm near shopkeeper (hinders return to shop) */
+           mm.x = shkp->mx;
+           mm.y = shkp->my;
+           makekops(&mm);
+       }
+}
+#endif /* KOPS */
+
+/* x,y is strictly inside shop */
+char
+inside_shop(x, y)
+register xchar x, y;
+{
+       register char rno;
+
+       rno = levl[x][y].roomno;
+       if ((rno < ROOMOFFSET) || levl[x][y].edge || !IS_SHOP(rno-ROOMOFFSET))
+           return(NO_ROOM);
+       else
+           return(rno);
+}
+
+void
+u_left_shop(leavestring, newlev)
+char *leavestring;
+boolean newlev;
+{
+       struct monst *shkp;
+       struct eshk *eshkp;
+
+       /*
+        * IF player
+        * ((didn't leave outright) AND
+        *  ((he is now strictly-inside the shop) OR
+        *   (he wasn't strictly-inside last turn anyway)))
+        * THEN (there's nothing to do, so just return)
+        */
+       if(!*leavestring &&
+          (!levl[u.ux][u.uy].edge || levl[u.ux0][u.uy0].edge))
+           return;
+
+       shkp = shop_keeper(*u.ushops0);
+       if (!shkp || !inhishop(shkp))
+           return;     /* shk died, teleported, changed levels... */
+
+       eshkp = ESHK(shkp);
+       if (!eshkp->billct && !eshkp->debit)    /* bill is settled */
+           return;
+
+       if (!*leavestring && shkp->mcanmove && !shkp->msleeping) {
+           /*
+            * Player just stepped onto shop-boundary (known from above logic).
+            * Try to intimidate him into paying his bill
+            */
+           verbalize(NOTANGRY(shkp) ?
+                     "%s!  Please pay before leaving." :
+                     "%s!  Don't you leave without paying!",
+                     plname);
+           return;
+       }
+
+       if (rob_shop(shkp)) {
+#ifdef KOPS
+           call_kops(shkp, (!newlev && levl[u.ux0][u.uy0].edge));
+#else
+           (void) angry_guards(FALSE);
+#endif
+       }
+}
+
+/* robbery from outside the shop via telekinesis or grappling hook */
+void
+remote_burglary(x, y)
+xchar x, y;
+{
+       struct monst *shkp;
+       struct eshk *eshkp;
+
+       shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
+       if (!shkp || !inhishop(shkp))
+           return;     /* shk died, teleported, changed levels... */
+
+       eshkp = ESHK(shkp);
+       if (!eshkp->billct && !eshkp->debit)    /* bill is settled */
+           return;
+
+       if (rob_shop(shkp)) {
+#ifdef KOPS
+           /*[might want to set 2nd arg based on distance from shop doorway]*/
+           call_kops(shkp, FALSE);
+#else
+           (void) angry_guards(FALSE);
+#endif
+       }
+}
+
+/* shop merchandise has been taken; pay for it with any credit available;  
+   return false if the debt is fully covered by credit, true otherwise */
+static boolean
+rob_shop(shkp)
+struct monst *shkp;
+{
+       struct eshk *eshkp;
+       long total;
+
+       eshkp = ESHK(shkp);
+       rouse_shk(shkp, TRUE);
+       total = (addupbill(shkp) + eshkp->debit);
+       if (eshkp->credit >= total) {
+           Your("credit of %ld %s is used to cover your shopping bill.",
+                eshkp->credit, currency(eshkp->credit));
+           total = 0L;         /* credit gets cleared by setpaid() */
+       } else {
+           You("escaped the shop without paying!");
+           total -= eshkp->credit;
+       }
+       setpaid(shkp);
+       if (!total) return FALSE;
+
+       /* by this point, we know an actual robbery has taken place */
+       eshkp->robbed += total;
+       You("stole %ld %s worth of merchandise.",
+           total, currency(total));
+       if (!Role_if(PM_ROGUE)) /* stealing is unlawful */
+           adjalign(-sgn(u.ualign.type));
+
+       hot_pursuit(shkp);
+       return TRUE;
+}
+
+void
+u_entered_shop(enterstring)
+register char *enterstring;
+{
+
+       register int rt;
+       register struct monst *shkp;
+       register struct eshk *eshkp;
+       static const char no_shk[] = "This shop appears to be deserted.";
+       static char empty_shops[5];
+
+       if(!*enterstring)
+               return;
+
+       if(!(shkp = shop_keeper(*enterstring))) {
+           if (!index(empty_shops, *enterstring) &&
+               in_rooms(u.ux, u.uy, SHOPBASE) !=
+                                 in_rooms(u.ux0, u.uy0, SHOPBASE))
+               pline(no_shk);
+           Strcpy(empty_shops, u.ushops);
+           u.ushops[0] = '\0';
+           return;
+       }
+
+       eshkp = ESHK(shkp);
+
+       if (!inhishop(shkp)) {
+           /* dump core when referenced */
+           eshkp->bill_p = (struct bill_x *) -1000;
+           if (!index(empty_shops, *enterstring))
+               pline(no_shk);
+           Strcpy(empty_shops, u.ushops);
+           u.ushops[0] = '\0';
+           return;
+       }
+
+       eshkp->bill_p = &(eshkp->bill[0]);
+
+       if ((!eshkp->visitct || *eshkp->customer) &&
+           strncmpi(eshkp->customer, plname, PL_NSIZ)) {
+           /* You seem to be new here */
+           eshkp->visitct = 0;
+           eshkp->following = 0;
+           (void) strncpy(eshkp->customer,plname,PL_NSIZ);
+           pacify_shk(shkp);
+       }
+
+       if (shkp->msleeping || !shkp->mcanmove || eshkp->following)
+           return;     /* no dialog */
+
+       if (Invis) {
+           pline("%s senses your presence.", shkname(shkp));
+           verbalize("Invisible customers are not welcome!");
+           return;
+       }
+
+       rt = rooms[*enterstring - ROOMOFFSET].rtype;
+
+       if (ANGRY(shkp)) {
+           verbalize("So, %s, you dare return to %s %s?!",
+                     plname,
+                     s_suffix(shkname(shkp)),
+                     shtypes[rt - SHOPBASE].name);
+       } else if (eshkp->robbed) {
+           pline("%s mutters imprecations against shoplifters.", shkname(shkp));
+       } else {
+           verbalize("%s, %s!  Welcome%s to %s %s!",
+                     Hello(shkp), plname,
+                     eshkp->visitct++ ? " again" : "",
+                     s_suffix(shkname(shkp)),
+                     shtypes[rt - SHOPBASE].name);
+       }
+       /* can't do anything about blocking if teleported in */
+       if (!inside_shop(u.ux, u.uy)) {
+           boolean should_block;
+           int cnt;
+           const char *tool;
+           struct obj *pick = carrying(PICK_AXE),
+                      *mattock = carrying(DWARVISH_MATTOCK);
+
+           if (pick || mattock) {
+               cnt = 1;        /* so far */
+               if (pick && mattock) {  /* carrying both types */
+                   tool = "digging tool";
+                   cnt = 2;    /* `more than 1' is all that matters */
+               } else if (pick) {
+                   tool = "pick-axe";
+                   /* hack: `pick' already points somewhere into inventory */
+                   while ((pick = pick->nobj) != 0)
+                       if (pick->otyp == PICK_AXE) ++cnt;
+               } else {        /* assert(mattock != 0) */
+                   tool = "mattock";
+                   while ((mattock = mattock->nobj) != 0)
+                       if (mattock->otyp == DWARVISH_MATTOCK) ++cnt;
+                   /* [ALI] Shopkeeper identifies mattock(s) */
+                   if (!Blind) makeknown(DWARVISH_MATTOCK);
+               }
+               verbalize(NOTANGRY(shkp) ?
+                         "Will you please leave your %s%s outside?" :
+                         "Leave the %s%s outside.",
+                         tool, plur(cnt));
+               should_block = TRUE;
+#ifdef STEED
+           } else if (u.usteed) {
+               verbalize(NOTANGRY(shkp) ?
+                         "Will you please leave %s outside?" :
+                         "Leave %s outside.", y_monnam(u.usteed));
+               should_block = TRUE;
+#endif
+           } else {
+               should_block = (Fast && (sobj_at(PICK_AXE, u.ux, u.uy) ||
+                                     sobj_at(DWARVISH_MATTOCK, u.ux, u.uy)));
+           }
+           if (should_block) (void) dochug(shkp);  /* shk gets extra move */
+       }
+       return;
+}
+
+/*
+   Decide whether two unpaid items are mergable; caller is responsible for
+   making sure they're unpaid and the same type of object; we check the price
+   quoted by the shopkeeper and also that they both belong to the same shk.
+ */
+boolean
+same_price(obj1, obj2)
+struct obj *obj1, *obj2;
+{
+       register struct monst *shkp1, *shkp2;
+       register struct bill_x *bp1 = 0, *bp2 = 0;
+       register boolean are_mergable = FALSE;
+
+       /* look up the first object by finding shk whose bill it's on */
+       for (shkp1 = next_shkp(fmon, TRUE); shkp1;
+               shkp1 = next_shkp(shkp1->nmon, TRUE))
+           if ((bp1 = onbill(obj1, shkp1, TRUE)) != 0) break;
+       /* second object is probably owned by same shk; if not, look harder */
+       if (shkp1 && (bp2 = onbill(obj2, shkp1, TRUE)) != 0) {
+           shkp2 = shkp1;
+       } else {
+           for (shkp2 = next_shkp(fmon, TRUE); shkp2;
+                   shkp2 = next_shkp(shkp2->nmon, TRUE))
+               if ((bp2 = onbill(obj2, shkp2, TRUE)) != 0) break;
+       }
+
+       if (!bp1 || !bp2) impossible("same_price: object wasn't on any bill!");
+       else are_mergable = (shkp1 == shkp2 && bp1->price == bp2->price);
+       return are_mergable;
+}
+
+/*
+ * Figure out how much is owed to a given shopkeeper.
+ * At present, we ignore any amount robbed from the shop, to avoid
+ * turning the `$' command into a way to discover that the current
+ * level is bones data which has a shk on the warpath.
+ */
+STATIC_OVL long
+shop_debt(eshkp)
+struct eshk *eshkp;
+{
+       struct bill_x *bp;
+       int ct;
+       long debt = eshkp->debit;
+
+       for (bp = eshkp->bill_p, ct = eshkp->billct; ct > 0; bp++, ct--)
+           debt += bp->price * bp->bquan;
+       return debt;
+}
+
+/* called in response to the `$' command */
+void
+shopper_financial_report()
+{
+       struct monst *shkp, *this_shkp = shop_keeper(inside_shop(u.ux, u.uy));
+       struct eshk *eshkp;
+       long amt;
+       int pass;
+
+       if (this_shkp &&
+           !(ESHK(this_shkp)->credit || shop_debt(ESHK(this_shkp)))) {
+           You("have no credit or debt in here.");
+           this_shkp = 0;      /* skip first pass */
+       }
+
+       /* pass 0: report for the shop we're currently in, if any;
+          pass 1: report for all other shops on this level. */
+       for (pass = this_shkp ? 0 : 1; pass <= 1; pass++)
+           for (shkp = next_shkp(fmon, FALSE);
+                   shkp; shkp = next_shkp(shkp->nmon, FALSE)) {
+               if ((shkp != this_shkp) ^ pass) continue;
+               eshkp = ESHK(shkp);
+               if ((amt = eshkp->credit) != 0)
+                   You("have %ld %s credit at %s %s.",
+                       amt, currency(amt), s_suffix(shkname(shkp)),
+                       shtypes[eshkp->shoptype - SHOPBASE].name);
+               else if (shkp == this_shkp)
+                   You("have no credit in here.");
+               if ((amt = shop_debt(eshkp)) != 0)
+                   You("owe %s %ld %s.",
+                       shkname(shkp), amt, currency(amt));
+               else if (shkp == this_shkp)
+                   You("don't owe any money here.");
+           }
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+int
+inhishop(mtmp)
+register struct monst *mtmp;
+{
+       return(index(in_rooms(mtmp->mx, mtmp->my, SHOPBASE),
+                    ESHK(mtmp)->shoproom) &&
+               on_level(&(ESHK(mtmp)->shoplevel), &u.uz));
+}
+
+struct monst *
+shop_keeper(rmno)
+register char rmno;
+{
+       struct monst *shkp = rmno >= ROOMOFFSET ?
+                               rooms[rmno - ROOMOFFSET].resident : 0;
+
+       if (shkp) {
+           if (NOTANGRY(shkp)) {
+               if (ESHK(shkp)->surcharge) pacify_shk(shkp);
+           } else {
+               if (!ESHK(shkp)->surcharge) rile_shk(shkp);
+           }
+       }
+       return shkp;
+}
+
+boolean
+tended_shop(sroom)
+register struct mkroom *sroom;
+{
+       register struct monst *mtmp = sroom->resident;
+
+       if (!mtmp)
+               return(FALSE);
+       else
+               return((boolean)(inhishop(mtmp)));
+}
+
+STATIC_OVL struct bill_x *
+onbill(obj, shkp, silent)
+register struct obj *obj;
+register struct monst *shkp;
+register boolean silent;
+{
+       if (shkp) {
+               register struct bill_x *bp = ESHK(shkp)->bill_p;
+               register int ct = ESHK(shkp)->billct;
+
+               while (--ct >= 0)
+                   if (bp->bo_id == obj->o_id) {
+                       if (!obj->unpaid) pline("onbill: paid obj on bill?");
+                       return bp;
+                   } else bp++;
+       }
+       if(obj->unpaid & !silent) pline("onbill: unpaid obj not on bill?");
+       return (struct bill_x *)0;
+}
+
+/* Delete the contents of the given object. */
+void
+delete_contents(obj)
+register struct obj *obj;
+{
+       register struct obj *curr;
+
+       while ((curr = obj->cobj) != 0) {
+           obj_extract_self(curr);
+           obfree(curr, (struct obj *)0);
+       }
+}
+
+/* called with two args on merge */
+void
+obfree(obj, merge)
+register struct obj *obj, *merge;
+{
+       register struct bill_x *bp;
+       register struct bill_x *bpm;
+       register struct monst *shkp;
+
+       if (obj->otyp == LEASH && obj->leashmon) o_unleash(obj);
+       if (obj->oclass == FOOD_CLASS) food_disappears(obj);
+       if (obj->oclass == SPBOOK_CLASS) book_disappears(obj);
+       if (Has_contents(obj)) delete_contents(obj);
+
+       shkp = 0;
+       if (obj->unpaid) {
+           /* look for a shopkeeper who owns this object */
+           for (shkp = next_shkp(fmon, TRUE); shkp;
+                   shkp = next_shkp(shkp->nmon, TRUE))
+               if (onbill(obj, shkp, TRUE)) break;
+       }
+       /* sanity check, more or less */
+       if (!shkp) shkp = shop_keeper(*u.ushops);
+               /*
+                * Note:  `shkp = shop_keeper(*u.ushops)' used to be
+                *        unconditional.  But obfree() is used all over
+                *        the place, so making its behavior be dependent
+                *        upon player location doesn't make much sense.
+                */
+
+       if ((bp = onbill(obj, shkp, FALSE)) != 0) {
+               if(!merge){
+                       bp->useup = 1;
+                       obj->unpaid = 0;        /* only for doinvbill */
+                       add_to_billobjs(obj);
+                       return;
+               }
+               bpm = onbill(merge, shkp, FALSE);
+               if(!bpm){
+                       /* this used to be a rename */
+                       impossible("obfree: not on bill??");
+                       return;
+               } else {
+                       /* this was a merger */
+                       bpm->bquan += bp->bquan;
+                       ESHK(shkp)->billct--;
+#ifdef DUMB
+                       {
+                       /* DRS/NS 2.2.6 messes up -- Peter Kendell */
+                               int indx = ESHK(shkp)->billct;
+                               *bp = ESHK(shkp)->bill_p[indx];
+                       }
+#else
+                       *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct];
+#endif
+               }
+       }
+       dealloc_obj(obj);
+}
+#endif /* OVLB */
+#ifdef OVL3
+
+STATIC_OVL long
+check_credit(tmp, shkp)
+long tmp;
+register struct monst *shkp;
+{
+       long credit = ESHK(shkp)->credit;
+
+       if(credit == 0L) return(tmp);
+       if(credit >= tmp) {
+               pline_The("price is deducted from your credit.");
+               ESHK(shkp)->credit -=tmp;
+               tmp = 0L;
+       } else {
+               pline_The("price is partially covered by your credit.");
+               ESHK(shkp)->credit = 0L;
+               tmp -= credit;
+       }
+       return(tmp);
+}
+
+STATIC_OVL void
+pay(tmp,shkp)
+long tmp;
+register struct monst *shkp;
+{
+       long robbed = ESHK(shkp)->robbed;
+       long balance = ((tmp <= 0L) ? tmp : check_credit(tmp, shkp));
+
+#ifndef GOLDOBJ
+       u.ugold -= balance;
+       shkp->mgold += balance;
+#else
+       if (balance > 0) money2mon(shkp, balance);
+       else if (balance < 0) money2u(shkp, -balance);
+#endif
+       flags.botl = 1;
+       if(robbed) {
+               robbed -= tmp;
+               if(robbed < 0) robbed = 0L;
+               ESHK(shkp)->robbed = robbed;
+       }
+}
+#endif /*OVL3*/
+#ifdef OVLB
+
+/* return shkp to home position */
+void
+home_shk(shkp, killkops)
+register struct monst *shkp;
+register boolean killkops;
+{
+       register xchar x = ESHK(shkp)->shk.x, y = ESHK(shkp)->shk.y;
+
+       (void) mnearto(shkp, x, y, TRUE);
+       level.flags.has_shop = 1;
+       if (killkops) {
+#ifdef KOPS
+               kops_gone(TRUE);
+#else
+               You_feel("vaguely apprehensive.");
+#endif
+               pacify_guards();
+       }
+       after_shk_move(shkp);
+}
+
+STATIC_OVL boolean
+angry_shk_exists()
+{
+       register struct monst *shkp;
+
+       for (shkp = next_shkp(fmon, FALSE);
+               shkp; shkp = next_shkp(shkp->nmon, FALSE))
+           if (ANGRY(shkp)) return(TRUE);
+       return(FALSE);
+}
+
+/* remove previously applied surcharge from all billed items */
+STATIC_OVL void
+pacify_shk(shkp)
+register struct monst *shkp;
+{
+       NOTANGRY(shkp) = TRUE;  /* make peaceful */
+       if (ESHK(shkp)->surcharge) {
+               register struct bill_x *bp = ESHK(shkp)->bill_p;
+               register int ct = ESHK(shkp)->billct;
+
+               ESHK(shkp)->surcharge = FALSE;
+               while (ct-- > 0) {
+                       register long reduction = (bp->price + 3L) / 4L;
+                       bp->price -= reduction;         /* undo 33% increase */
+                       bp++;
+               }
+       }
+}
+
+/* add aggravation surcharge to all billed items */
+STATIC_OVL void
+rile_shk(shkp)
+register struct monst *shkp;
+{
+       NOTANGRY(shkp) = FALSE; /* make angry */
+       if (!ESHK(shkp)->surcharge) {
+               register struct bill_x *bp = ESHK(shkp)->bill_p;
+               register int ct = ESHK(shkp)->billct;
+
+               ESHK(shkp)->surcharge = TRUE;
+               while (ct-- > 0) {
+                       register long surcharge = (bp->price + 2L) / 3L;
+                       bp->price += surcharge;
+                       bp++;
+               }
+       }
+}
+
+/* wakeup and/or unparalyze shopkeeper */
+STATIC_OVL void
+rouse_shk(shkp, verbosely)
+struct monst *shkp;
+boolean verbosely;
+{
+       if (!shkp->mcanmove || shkp->msleeping) {
+           /* greed induced recovery... */
+           if (verbosely && canspotmon(shkp))
+               pline("%s %s.", Monnam(shkp),
+                     shkp->msleeping ? "wakes up" : "can move again");
+           shkp->msleeping = 0;
+           shkp->mfrozen = 0;
+           shkp->mcanmove = 1;
+       }
+}
+
+void
+make_happy_shk(shkp, silentkops)
+register struct monst *shkp;
+register boolean silentkops;
+{
+       boolean wasmad = ANGRY(shkp);
+       struct eshk *eshkp = ESHK(shkp);
+
+       pacify_shk(shkp);
+       eshkp->following = 0;
+       eshkp->robbed = 0L;
+       if (!Role_if(PM_ROGUE))
+               adjalign(sgn(u.ualign.type));
+       if(!inhishop(shkp)) {
+               char shk_nam[BUFSZ];
+               boolean vanished = canseemon(shkp);
+
+               Strcpy(shk_nam, mon_nam(shkp));
+               if (on_level(&eshkp->shoplevel, &u.uz)) {
+                       home_shk(shkp, FALSE);
+                       /* didn't disappear if shk can still be seen */
+                       if (canseemon(shkp)) vanished = FALSE;
+               } else {
+                       /* if sensed, does disappear regardless whether seen */
+                       if (sensemon(shkp)) vanished = TRUE;
+                       /* can't act as porter for the Amulet, even if shk
+                          happens to be going farther down rather than up */
+                       mdrop_special_objs(shkp);
+                       /* arrive near shop's door */
+                       migrate_to_level(shkp, ledger_no(&eshkp->shoplevel),
+                                        MIGR_APPROX_XY, &eshkp->shd);
+               }
+               if (vanished)
+                   pline("Satisfied, %s suddenly disappears!", shk_nam);
+       } else if(wasmad)
+               pline("%s calms down.", Monnam(shkp));
+
+       if(!angry_shk_exists()) {
+#ifdef KOPS
+               kops_gone(silentkops);
+#endif
+               pacify_guards();
+       }
+}
+
+void
+hot_pursuit(shkp)
+register struct monst *shkp;
+{
+       if(!shkp->isshk) return;
+
+       rile_shk(shkp);
+       (void) strncpy(ESHK(shkp)->customer, plname, PL_NSIZ);
+       ESHK(shkp)->following = 1;
+}
+
+/* used when the shkp is teleported or falls (ox == 0) out of his shop,
+ * or when the player is not on a costly_spot and he
+ * damages something inside the shop.  these conditions
+ * must be checked by the calling function.
+ */
+void
+make_angry_shk(shkp, ox, oy)
+register struct monst *shkp;
+register xchar ox,oy;
+{
+       xchar sx, sy;
+       struct eshk *eshkp = ESHK(shkp);
+
+       /* all pending shop transactions are now "past due" */
+       if (eshkp->billct || eshkp->debit || eshkp->loan || eshkp->credit) {
+           eshkp->robbed += (addupbill(shkp) + eshkp->debit + eshkp->loan);
+           eshkp->robbed -= eshkp->credit;
+           if (eshkp->robbed < 0L) eshkp->robbed = 0L;
+           /* billct, debit, loan, and credit will be cleared by setpaid */
+           setpaid(shkp);
+       }
+
+       /* If you just used a wand of teleportation to send the shk away, you
+          might not be able to see her any more.  Monnam would yield "it",
+          which makes this message look pretty silly, so temporarily restore
+          her original location during the call to Monnam. */
+       sx = shkp->mx,  sy = shkp->my;
+       if (isok(ox, oy) && cansee(ox, oy) && !cansee(sx, sy))
+               shkp->mx = ox,  shkp->my = oy;
+       pline("%s %s!", Monnam(shkp),
+             !ANGRY(shkp) ? "gets angry" : "is furious");
+       shkp->mx = sx,  shkp->my = sy;
+       hot_pursuit(shkp);
+}
+
+STATIC_VAR const char no_money[] = "Moreover, you%s have no money.";
+STATIC_VAR const char not_enough_money[] =
+                           "Besides, you don't have enough to interest %s.";
+
+#else
+STATIC_VAR const char no_money[];
+STATIC_VAR const char not_enough_money[];
+#endif /*OVLB*/
+
+#ifdef OVL3
+
+STATIC_OVL long
+cheapest_item(shkp)   /* delivers the cheapest item on the list */
+register struct monst *shkp;
+{
+       register int ct = ESHK(shkp)->billct;
+       register struct bill_x *bp = ESHK(shkp)->bill_p;
+       register long gmin = (bp->price * bp->bquan);
+
+       while(ct--){
+               if(bp->price * bp->bquan < gmin)
+                       gmin = bp->price * bp->bquan;
+               bp++;
+       }
+       return(gmin);
+}
+#endif /*OVL3*/
+#ifdef OVL0
+
+int
+dopay()
+{
+       register struct eshk *eshkp;
+       register struct monst *shkp;
+       struct monst *nxtm, *resident;
+       long ltmp;
+#ifdef GOLDOBJ
+       long umoney;
+#endif
+       int pass, tmp, sk = 0, seensk = 0;
+       boolean paid = FALSE, stashed_gold = (hidden_gold() > 0L);
+
+       multi = 0;
+
+       /* find how many shk's there are, how many are in */
+       /* sight, and are you in a shop room with one.    */
+       nxtm = resident = 0;
+       for (shkp = next_shkp(fmon, FALSE);
+               shkp; shkp = next_shkp(shkp->nmon, FALSE)) {
+           sk++;
+           if (ANGRY(shkp) && distu(shkp->mx, shkp->my) <= 2) nxtm = shkp;
+           if (canspotmon(shkp)) seensk++;
+           if (inhishop(shkp) && (*u.ushops == ESHK(shkp)->shoproom))
+               resident = shkp;
+       }
+
+       if (nxtm) {                     /* Player should always appease an */
+            shkp = nxtm;               /* irate shk standing next to them. */
+            goto proceed;
+       }
+
+       if ((!sk && (!Blind || Blind_telepat)) || (!Blind && !seensk)) {
+      There("appears to be no shopkeeper here to receive your payment.");
+               return(0);
+       }
+
+       if(!seensk) {
+               You_cant("see...");
+               return(0);
+       }
+
+       /* the usual case.  allow paying at a distance when */
+       /* inside a tended shop.  should we change that?    */
+       if(sk == 1 && resident) {
+               shkp = resident;
+               goto proceed;
+       }
+
+       if (seensk == 1) {
+               for (shkp = next_shkp(fmon, FALSE);
+                       shkp; shkp = next_shkp(shkp->nmon, FALSE))
+                   if (canspotmon(shkp)) break;
+               if (shkp != resident && distu(shkp->mx, shkp->my) > 2) {
+                   pline("%s is not near enough to receive your payment.",
+                                            Monnam(shkp));
+                   return(0);
+               }
+       } else {
+               struct monst *mtmp;
+               coord cc;
+               int cx, cy;
+
+               pline("Pay whom?");
+               cc.x = u.ux;
+               cc.y = u.uy;
+               if (getpos(&cc, TRUE, "the creature you want to pay") < 0)
+                   return 0;   /* player pressed ESC */
+               cx = cc.x;
+               cy = cc.y;
+               if(cx < 0) {
+                    pline("Try again...");
+                    return(0);
+               }
+               if(u.ux == cx && u.uy == cy) {
+                    You("are generous to yourself.");
+                    return(0);
+               }
+               mtmp = m_at(cx, cy);
+               if(!mtmp) {
+                    There("is no one there to receive your payment.");
+                    return(0);
+               }
+               if(!mtmp->isshk) {
+                    pline("%s is not interested in your payment.",
+                                   Monnam(mtmp));
+                    return(0);
+               }
+               if (mtmp != resident && distu(mtmp->mx, mtmp->my) > 2) {
+                    pline("%s is too far to receive your payment.",
+                                   Monnam(mtmp));
+                    return(0);
+               }
+               shkp = mtmp;
+       }
+
+       if(!shkp) {
+#ifdef DEBUG
+               pline("dopay: null shkp.");
+#endif
+               return(0);
+       }
+proceed:
+       eshkp = ESHK(shkp);
+       ltmp = eshkp->robbed;
+
+       /* wake sleeping shk when someone who owes money offers payment */
+       if (ltmp || eshkp->billct || eshkp->debit) 
+           rouse_shk(shkp, TRUE);
+
+       if (!shkp->mcanmove || shkp->msleeping) { /* still asleep/paralyzed */
+               pline("%s %s.", Monnam(shkp),
+                     rn2(2) ? "seems to be napping" : "doesn't respond");
+               return 0;
+       }
+
+       if(shkp != resident && NOTANGRY(shkp)) {
+#ifdef GOLDOBJ
+                umoney = money_cnt(invent);
+#endif
+               if(!ltmp)
+                   You("do not owe %s anything.", mon_nam(shkp));
+#ifndef GOLDOBJ
+               else if(!u.ugold) {
+#else
+               else if(!umoney) {
+#endif
+                   You("%shave no money.", stashed_gold ? "seem to " : "");
+                   if(stashed_gold)
+                       pline("But you have some gold stashed away.");
+               } else {
+#ifndef GOLDOBJ
+                   long ugold = u.ugold;
+                   if(ugold > ltmp) {
+#else
+                   if(umoney > ltmp) {
+#endif
+                       You("give %s the %ld gold piece%s %s asked for.",
+                           mon_nam(shkp), ltmp, plur(ltmp), mhe(shkp));
+                       pay(ltmp, shkp);
+                   } else {
+                       You("give %s all your%s gold.", mon_nam(shkp),
+                                       stashed_gold ? " openly kept" : "");
+#ifndef GOLDOBJ
+                       pay(u.ugold, shkp);
+#else
+                       pay(umoney, shkp);
+#endif
+                       if (stashed_gold) pline("But you have hidden gold!");
+                   }
+#ifndef GOLDOBJ
+                   if((ugold < ltmp/2L) || (ugold < ltmp && stashed_gold))
+#else
+                   if((umoney < ltmp/2L) || (umoney < ltmp && stashed_gold))
+#endif
+                       pline("Unfortunately, %s doesn't look satisfied.",
+                             mhe(shkp));
+                   else
+                       make_happy_shk(shkp, FALSE);
+               }
+               return(1);
+       }
+
+       /* ltmp is still eshkp->robbed here */
+       if (!eshkp->billct && !eshkp->debit) {
+#ifdef GOLDOBJ
+                umoney = money_cnt(invent);
+#endif
+               if(!ltmp && NOTANGRY(shkp)) {
+                   You("do not owe %s anything.", mon_nam(shkp));
+#ifndef GOLDOBJ
+                   if (!u.ugold)
+#else
+                   if (!umoney)
+#endif
+                       pline(no_money, stashed_gold ? " seem to" : "");
+               } else if(ltmp) {
+                   pline("%s is after blood, not money!", Monnam(shkp));
+#ifndef GOLDOBJ
+                   if(u.ugold < ltmp/2L ||
+                               (u.ugold < ltmp && stashed_gold)) {
+                       if (!u.ugold)
+#else
+                   if(umoney < ltmp/2L ||
+                               (umoney < ltmp && stashed_gold)) {
+                       if (!umoney)
+#endif
+                           pline(no_money, stashed_gold ? " seem to" : "");
+                       else pline(not_enough_money, mhim(shkp));
+                       return(1);
+                   }
+                   pline("But since %s shop has been robbed recently,",
+                         mhis(shkp));
+                   pline("you %scompensate %s for %s losses.",
+#ifndef GOLDOBJ
+                         (u.ugold < ltmp) ? 
+#else
+                         (umoney < ltmp) ? 
+#endif
+                         "partially " : "",
+                         mon_nam(shkp), mhis(shkp));
+#ifndef GOLDOBJ
+                   pay(u.ugold < ltmp ? u.ugold : ltmp, shkp);
+#else
+                   pay(umoney < ltmp ? umoney : ltmp, shkp);
+#endif
+                   make_happy_shk(shkp, FALSE);
+               } else {
+                   /* shopkeeper is angry, but has not been robbed --
+                    * door broken, attacked, etc. */
+                   pline("%s is after your hide, not your money!",
+                         Monnam(shkp));
+#ifndef GOLDOBJ
+                   if(u.ugold < 1000L) {
+                       if (!u.ugold)
+#else
+                   if(umoney < 1000L) {
+                       if (!umoney)
+#endif
+                           pline(no_money, stashed_gold ? " seem to" : "");
+                       else pline(not_enough_money, mhim(shkp));
+                       return(1);
+                   }
+                   You("try to appease %s by giving %s 1000 gold pieces.",
+                       x_monnam(shkp, ARTICLE_THE, "angry", 0, FALSE),
+                       mhim(shkp));
+                   pay(1000L,shkp);
+                   if (strncmp(eshkp->customer, plname, PL_NSIZ) || rn2(3))
+                       make_happy_shk(shkp, FALSE);
+                   else
+                       pline("But %s is as angry as ever.", mon_nam(shkp));
+               }
+               return(1);
+       }
+       if(shkp != resident) {
+               impossible("dopay: not to shopkeeper?");
+               if(resident) setpaid(resident);
+               return(0);
+       }        
+       /* pay debt, if any, first */
+       if(eshkp->debit) {
+               long dtmp = eshkp->debit;
+               long loan = eshkp->loan;
+               char sbuf[BUFSZ];
+#ifdef GOLDOBJ
+                umoney = money_cnt(invent);
+#endif
+               Sprintf(sbuf, "You owe %s %ld %s ",
+                                          shkname(shkp), dtmp, currency(dtmp));
+               if(loan) {
+                   if(loan == dtmp)
+                       Strcat(sbuf, "you picked up in the store.");
+                   else Strcat(sbuf,
+                          "for gold picked up and the use of merchandise.");
+               } else Strcat(sbuf, "for the use of merchandise.");
+               pline(sbuf);
+#ifndef GOLDOBJ
+               if (u.ugold + eshkp->credit < dtmp) {
+#else
+               if (umoney + eshkp->credit < dtmp) {
+#endif
+                   pline("But you don't%s have enough gold%s.",
+                       stashed_gold ? " seem to" : "",
+                       eshkp->credit ? " or credit" : "");
+                   return(1);
+               } else {
+                   if (eshkp->credit >= dtmp) {
+                       eshkp->credit -= dtmp;
+                       eshkp->debit = 0L;
+                       eshkp->loan = 0L;
+                       Your("debt is covered by your credit.");
+                   } else if (!eshkp->credit) {
+#ifndef GOLDOBJ
+                       u.ugold -= dtmp;
+                       shkp->mgold += dtmp;
+#else
+                        money2mon(shkp, dtmp);
+#endif
+                       eshkp->debit = 0L;
+                       eshkp->loan = 0L;
+                       You("pay that debt.");
+                       flags.botl = 1;
+                   } else {
+                       dtmp -= eshkp->credit;
+                       eshkp->credit = 0L;
+#ifndef GOLDOBJ
+                       u.ugold -= dtmp;
+                       shkp->mgold += dtmp;
+#else
+                        money2mon(shkp, dtmp);
+#endif
+                       eshkp->debit = 0L;
+                       eshkp->loan = 0L;
+                       pline("That debt is partially offset by your credit.");
+                       You("pay the remainder.");
+                       flags.botl = 1;
+                   }
+                   paid = TRUE;
+               }
+       }
+       /* now check items on bill */
+       if (eshkp->billct) {
+           register boolean itemize;
+#ifndef GOLDOBJ
+           if (!u.ugold && !eshkp->credit) {
+#else
+            umoney = money_cnt(invent);
+           if (!umoney && !eshkp->credit) {
+#endif
+               You("%shave no money or credit%s.",
+                                   stashed_gold ? "seem to " : "",
+                                   paid ? " left" : "");
+               return(0);
+           }
+#ifndef GOLDOBJ
+           if ((u.ugold + eshkp->credit) < cheapest_item(shkp)) {
+#else
+           if ((umoney + eshkp->credit) < cheapest_item(shkp)) {
+#endif
+               You("don't have enough money to buy%s the item%s you picked.",
+                   eshkp->billct > 1 ? " any of" : "", plur(eshkp->billct));
+               if(stashed_gold)
+                   pline("Maybe you have some gold stashed away?");
+               return(0);
+           }
+
+           /* this isn't quite right; it itemizes without asking if the
+            * single item on the bill is partly used up and partly unpaid */
+           itemize = (eshkp->billct > 1 ? yn("Itemized billing?") == 'y' : 1);
+
+           for (pass = 0; pass <= 1; pass++) {
+               tmp = 0;
+               while (tmp < eshkp->billct) {
+                   struct obj *otmp;
+                   register struct bill_x *bp = &(eshkp->bill_p[tmp]);
+
+                   /* find the object on one of the lists */
+                   if ((otmp = bp_to_obj(bp)) != 0) {
+                       /* if completely used up, object quantity is stale;
+                          restoring it to its original value here avoids
+                          making the partly-used-up code more complicated */
+                       if (bp->useup) otmp->quan = bp->bquan;
+                   } else {
+                       impossible("Shopkeeper administration out of order.");
+                       setpaid(shkp);  /* be nice to the player */
+                       return 1;
+                   }
+                   if (pass == bp->useup && otmp->quan == bp->bquan) {
+                       /* pay for used-up items on first pass and others
+                        * on second, so player will be stuck in the store
+                        * less often; things which are partly used up
+                        * are processed on both passes */
+                       tmp++;
+                   } else {
+                       switch (dopayobj(shkp, bp, &otmp, pass, itemize)) {
+                         case PAY_CANT:
+                               return 1;       /*break*/
+                         case PAY_BROKE:
+                               paid = TRUE;
+                               goto thanks;    /*break*/
+                         case PAY_SKIP:
+                               tmp++;
+                               continue;       /*break*/
+                         case PAY_SOME:
+                               paid = TRUE;
+                               if (itemize) bot();
+                               continue;       /*break*/
+                         case PAY_BUY:
+                               paid = TRUE;
+                               break;
+                       }
+                       if (itemize) bot();
+                       *bp = eshkp->bill_p[--eshkp->billct];
+                   }
+               }
+           }
+       thanks:
+           if (!itemize)
+               update_inventory(); /* Done in dopayobj() if itemize. */
+       }
+       if(!ANGRY(shkp) && paid)
+           verbalize("Thank you for shopping in %s %s!",
+               s_suffix(shkname(shkp)),
+               shtypes[eshkp->shoptype - SHOPBASE].name);
+       return(1);
+}
+#endif /*OVL0*/
+#ifdef OVL3
+
+/* return 2 if used-up portion paid */
+/*       1 if paid successfully    */
+/*       0 if not enough money     */
+/*      -1 if skip this object     */
+/*      -2 if no money/credit left */
+STATIC_OVL int
+dopayobj(shkp, bp, obj_p, which, itemize)
+register struct monst *shkp;
+register struct bill_x *bp;
+struct obj **obj_p;
+int    which;          /* 0 => used-up item, 1 => other (unpaid or lost) */
+boolean itemize;
+{
+       register struct obj *obj = *obj_p;
+       long ltmp, quan, save_quan;
+#ifdef GOLDOBJ
+       long umoney = money_cnt(invent);
+#endif
+       int buy;
+       boolean stashed_gold = (hidden_gold() > 0L),
+               consumed = (which == 0);
+
+       if(!obj->unpaid && !bp->useup){
+               impossible("Paid object on bill??");
+               return PAY_BUY;
+       }
+#ifndef GOLDOBJ
+       if(itemize && u.ugold + ESHK(shkp)->credit == 0L){
+#else
+       if(itemize && umoney + ESHK(shkp)->credit == 0L){
+#endif
+               You("%shave no money or credit left.",
+                            stashed_gold ? "seem to " : "");
+               return PAY_BROKE;
+       }
+       /* we may need to temporarily adjust the object, if part of the
+          original quantity has been used up but part remains unpaid  */
+       save_quan = obj->quan;
+       if (consumed) {
+           /* either completely used up (simple), or split needed */
+           quan = bp->bquan;
+           if (quan > obj->quan)       /* difference is amount used up */
+               quan -= obj->quan;
+       } else {
+           /* dealing with ordinary unpaid item */
+           quan = obj->quan;
+       }
+       obj->quan = quan;       /* to be used by doname() */
+       obj->unpaid = 0;        /* ditto */
+       ltmp = bp->price * quan;
+       buy = PAY_BUY;          /* flag; if changed then return early */
+
+       if (itemize) {
+           char qbuf[BUFSZ];
+           Sprintf(qbuf,"%s for %ld %s.  Pay?", quan == 1L ?
+                   Doname2(obj) : doname(obj), ltmp, currency(ltmp));
+           if (yn(qbuf) == 'n') {
+               buy = PAY_SKIP;         /* don't want to buy */
+           } else if (quan < bp->bquan && !consumed) { /* partly used goods */
+               obj->quan = bp->bquan - save_quan;      /* used up amount */
+               verbalize("%s for the other %s before buying %s.",
+                         ANGRY(shkp) ? "Pay" : "Please pay", xname(obj),
+                         save_quan > 1L ? "these" : "this one");
+               buy = PAY_SKIP;         /* shk won't sell */
+           }
+       }
+#ifndef GOLDOBJ
+       if (buy == PAY_BUY && u.ugold + ESHK(shkp)->credit < ltmp) {
+#else
+       if (buy == PAY_BUY && umoney + ESHK(shkp)->credit < ltmp) {
+#endif
+           You("don't%s have gold%s enough to pay for %s.",
+               stashed_gold ? " seem to" : "",
+               (ESHK(shkp)->credit > 0L) ? " or credit" : "",
+               doname(obj));
+           buy = itemize ? PAY_SKIP : PAY_CANT;
+       }
+
+       if (buy != PAY_BUY) {
+           /* restore unpaid object to original state */
+           obj->quan = save_quan;
+           obj->unpaid = 1;
+           return buy;
+       }
+
+       pay(ltmp, shkp);
+       shk_names_obj(shkp, obj, consumed ?
+                       "paid for %s at a cost of %ld gold piece%s.%s" :
+                       "bought %s for %ld gold piece%s.%s", ltmp, "");
+       obj->quan = save_quan;          /* restore original count */
+       /* quan => amount just bought, save_quan => remaining unpaid count */
+       if (consumed) {
+           if (quan != bp->bquan) {
+               /* eliminate used-up portion; remainder is still unpaid */
+               bp->bquan = obj->quan;
+               obj->unpaid = 1;
+               bp->useup = 0;
+               buy = PAY_SOME;
+           } else {    /* completely used-up, so get rid of it */
+               obj_extract_self(obj);
+            /* assert( obj == *obj_p ); */
+               dealloc_obj(obj);
+               *obj_p = 0;     /* destroy pointer to freed object */
+           }
+       } else if (itemize)
+           update_inventory(); /* Done just once in dopay() if !itemize. */
+       return buy;
+}
+#endif /*OVL3*/
+#ifdef OVLB
+
+static coord repo_location;    /* repossession context */
+
+/* routine called after dying (or quitting) */
+boolean
+paybill(croaked)
+int croaked;   /* -1: escaped dungeon; 0: quit; 1: died */
+{
+       register struct monst *mtmp, *mtmp2, *resident= (struct monst *)0;
+       register boolean taken = FALSE;
+       register int numsk = 0;
+
+       /* if we escaped from the dungeon, shopkeepers can't reach us;
+          shops don't occur on level 1, but this could happen if hero
+          level teleports out of the dungeon and manages not to die */
+       if (croaked < 0) return FALSE;
+
+       /* this is where inventory will end up if any shk takes it */
+       repo_location.x = repo_location.y = 0;
+
+       /* give shopkeeper first crack */
+       if ((mtmp = shop_keeper(*u.ushops)) && inhishop(mtmp)) {
+           numsk++;
+           resident = mtmp;
+           taken = inherits(resident, numsk, croaked);
+       }
+       for (mtmp = next_shkp(fmon, FALSE);
+               mtmp; mtmp = next_shkp(mtmp2, FALSE)) {
+           mtmp2 = mtmp->nmon;
+           if (mtmp != resident) {
+               /* for bones: we don't want a shopless shk around */
+               if(!on_level(&(ESHK(mtmp)->shoplevel), &u.uz))
+                       mongone(mtmp);
+               else {
+                   numsk++;
+                   taken |= inherits(mtmp, numsk, croaked);
+               }
+           }
+       }
+       if(numsk == 0) return(FALSE);
+       return(taken);
+}
+
+STATIC_OVL boolean
+inherits(shkp, numsk, croaked)
+struct monst *shkp;
+int numsk;
+int croaked;
+{
+       long loss = 0L;
+#ifdef GOLDOBJ
+       long umoney;
+#endif
+       struct eshk *eshkp = ESHK(shkp);
+       boolean take = FALSE, taken = FALSE;
+       int roomno = *u.ushops;
+       char takes[BUFSZ];
+
+       /* the simplifying principle is that first-come */
+       /* already took everything you had.             */
+       if (numsk > 1) {
+           if (cansee(shkp->mx, shkp->my && croaked))
+               pline("%s %slooks at your corpse%s and %s.",
+                     Monnam(shkp),
+                     (!shkp->mcanmove || shkp->msleeping) ? "wakes up, " : "",
+                     !rn2(2) ? (shkp->female ? ", shakes her head," :
+                          ", shakes his head,") : "",
+                     !inhishop(shkp) ? "disappears" : "sighs");
+           rouse_shk(shkp, FALSE);     /* wake shk for bones */    
+           taken = (roomno == eshkp->shoproom);
+           goto skip;
+       }
+
+       /* get one case out of the way: you die in the shop, the */
+       /* shopkeeper is peaceful, nothing stolen, nothing owed. */
+       if(roomno == eshkp->shoproom && inhishop(shkp) &&
+           !eshkp->billct && !eshkp->robbed && !eshkp->debit &&
+            NOTANGRY(shkp) && !eshkp->following) {
+               if (invent)
+                       pline("%s gratefully inherits all your possessions.",
+                               shkname(shkp));
+               set_repo_loc(eshkp);
+               goto clear;
+       }
+
+       if (eshkp->billct || eshkp->debit || eshkp->robbed) {
+               if (roomno == eshkp->shoproom && inhishop(shkp))
+                   loss = addupbill(shkp) + eshkp->debit;
+               if (loss < eshkp->robbed) loss = eshkp->robbed;
+               take = TRUE;
+       }
+
+       if (eshkp->following || ANGRY(shkp) || take) {
+#ifndef GOLDOBJ
+               if (!invent && !u.ugold) goto skip;
+#else
+               if (!invent) goto skip;
+                umoney = money_cnt(invent);
+#endif
+               takes[0] = '\0';
+               if (!shkp->mcanmove || shkp->msleeping)
+                       Strcat(takes, "wakes up and ");
+               if (distu(shkp->mx, shkp->my) > 2)
+                       Strcat(takes, "comes and ");
+               Strcat(takes, "takes");
+
+#ifndef GOLDOBJ
+               if (loss > u.ugold || !loss || roomno == eshkp->shoproom) {
+                       eshkp->robbed -= u.ugold;
+                       if (eshkp->robbed < 0L) eshkp->robbed = 0L;
+                       shkp->mgold += u.ugold;
+                       u.ugold = 0L;
+#else
+               if (loss > umoney || !loss || roomno == eshkp->shoproom) {
+                       eshkp->robbed -= umoney;
+                       if (eshkp->robbed < 0L) eshkp->robbed = 0L;
+                        if (umoney > 0) money2mon(shkp, umoney);
+#endif
+                       flags.botl = 1;
+                       pline("%s %s all your possessions.",
+                             shkname(shkp), takes);
+                       taken = TRUE;
+                       /* where to put player's invent (after disclosure) */
+                       set_repo_loc(eshkp);
+               } else {
+#ifndef GOLDOBJ
+                       shkp->mgold += loss;
+                       u.ugold -= loss;
+#else
+                        money2mon(shkp, loss);
+#endif
+                       flags.botl = 1;
+                       pline("%s %s the %ld %s %sowed %s.",
+                             Monnam(shkp), takes,
+                             loss, currency(loss),
+                             strncmp(eshkp->customer, plname, PL_NSIZ) ?
+                                       "" : "you ",
+                             shkp->female ? "her" : "him");
+                       /* shopkeeper has now been paid in full */
+                       pacify_shk(shkp);
+                       eshkp->following = 0;
+                       eshkp->robbed = 0L;
+               }
+skip:
+               /* in case we create bones */
+               rouse_shk(shkp, FALSE); /* wake up */
+               if (!inhishop(shkp))
+                       home_shk(shkp, FALSE);
+       }
+clear:
+       setpaid(shkp);
+       return(taken);
+}
+
+STATIC_OVL void
+set_repo_loc(eshkp)
+struct eshk *eshkp;
+{
+       register xchar ox, oy;
+
+       /* if you're not in this shk's shop room, or if you're in its doorway
+           or entry spot, then your gear gets dumped all the way inside */
+       if (*u.ushops != eshkp->shoproom ||
+               IS_DOOR(levl[u.ux][u.uy].typ) ||
+               (u.ux == eshkp->shk.x && u.uy == eshkp->shk.y)) {
+           /* shk.x,shk.y is the position immediately in
+            * front of the door -- move in one more space
+            */
+           ox = eshkp->shk.x;
+           oy = eshkp->shk.y;
+           ox += sgn(ox - eshkp->shd.x);
+           oy += sgn(oy - eshkp->shd.y);
+       } else {                /* already inside this shk's shop */
+           ox = u.ux;
+           oy = u.uy;
+       }
+       /* finish_paybill will deposit invent here */
+       repo_location.x = ox;
+       repo_location.y = oy;
+}
+
+/* called at game exit, after inventory disclosure but before making bones */
+void
+finish_paybill()
+{
+       register struct obj *otmp;
+       int ox = repo_location.x,
+           oy = repo_location.y;
+
+#if 0          /* don't bother */
+       if (ox == 0 && oy == 0) impossible("finish_paybill: no location");
+#endif
+       /* normally done by savebones(), but that's too late in this case */
+       unleash_all();
+       /* transfer all of the character's inventory to the shop floor */
+       while ((otmp = invent) != 0) {
+           otmp->owornmask = 0L;       /* perhaps we should call setnotworn? */
+           otmp->lamplit = 0;          /* avoid "goes out" msg from freeinv */
+           if (rn2(5)) curse(otmp);    /* normal bones treatment for invent */
+           obj_extract_self(otmp);
+           place_object(otmp, ox, oy);
+       }
+}
+
+/* find obj on one of the lists */
+STATIC_OVL struct obj *
+bp_to_obj(bp)
+register struct bill_x *bp;
+{
+       register struct obj *obj;
+       register unsigned int id = bp->bo_id;
+
+       if(bp->useup)
+               obj = o_on(id, billobjs);
+       else
+               obj = find_oid(id);
+       return obj;
+}
+
+/*
+ * Look for o_id on all lists but billobj.  Return obj or NULL if not found.
+ * Its OK for restore_timers() to call this function, there should not
+ * be any timeouts on the billobjs chain.
+ */
+struct obj *
+find_oid(id)
+unsigned id;
+{
+       struct obj *obj;
+       struct monst *mon, *mmtmp[3];
+       int i;
+
+       /* first check various obj lists directly */
+       if ((obj = o_on(id, invent)) != 0) return obj;
+       if ((obj = o_on(id, fobj)) != 0) return obj;
+       if ((obj = o_on(id, level.buriedobjlist)) != 0) return obj;
+       if ((obj = o_on(id, migrating_objs)) != 0) return obj;
+
+       /* not found yet; check inventory for members of various monst lists */
+       mmtmp[0] = fmon;
+       mmtmp[1] = migrating_mons;
+       mmtmp[2] = mydogs;              /* for use during level changes */
+       for (i = 0; i < 3; i++)
+           for (mon = mmtmp[i]; mon; mon = mon->nmon)
+               if ((obj = o_on(id, mon->minvent)) != 0) return obj;
+
+       /* not found at all */
+       return (struct obj *)0;
+}
+#endif /*OVLB*/
+#ifdef OVL3
+
+/* calculate the value that the shk will charge for [one of] an object */
+STATIC_OVL long
+get_cost(obj, shkp)
+register struct obj *obj;
+register struct monst *shkp;   /* if angry, impose a surcharge */
+{
+       register long tmp = getprice(obj, FALSE);
+
+       if (!tmp) tmp = 5L;
+       /* shopkeeper may notice if the player isn't very knowledgeable -
+          especially when gem prices are concerned */
+       if (!obj->dknown || !objects[obj->otyp].oc_name_known) {
+               if (obj->oclass == GEM_CLASS &&
+                       objects[obj->otyp].oc_material == GLASS) {
+                   int i;
+                   /* get a value that's 'random' from game to game, but the
+                      same within the same game */
+                   boolean pseudorand =
+                       (((int)u.ubirthday % obj->otyp) >= obj->otyp/2);
+
+                   /* all gems are priced high - real or not */
+                   switch(obj->otyp - LAST_GEM) {
+                       case 1: /* white */
+                           i = pseudorand ? DIAMOND : OPAL;
+                           break;
+                       case 2: /* blue */
+                           i = pseudorand ? SAPPHIRE : AQUAMARINE;
+                           break;
+                       case 3: /* red */
+                           i = pseudorand ? RUBY : JASPER;
+                           break;
+                       case 4: /* yellowish brown */
+                           i = pseudorand ? AMBER : TOPAZ;
+                           break;
+                       case 5: /* orange */
+                           i = pseudorand ? JACINTH : AGATE;
+                           break;
+                       case 6: /* yellow */
+                           i = pseudorand ? CITRINE : CHRYSOBERYL;
+                           break;
+                       case 7: /* black */
+                           i = pseudorand ? BLACK_OPAL : JET;
+                           break;
+                       case 8: /* green */
+                           i = pseudorand ? EMERALD : JADE;
+                           break;
+                       case 9: /* violet */
+                           i = pseudorand ? AMETHYST : FLUORITE;
+                           break;
+                       default: impossible("bad glass gem %d?", obj->otyp);
+                           i = STRANGE_OBJECT;
+                           break;
+                   }
+                   tmp = (long) objects[i].oc_cost;
+               } else if (!(obj->o_id % 4)) /* arbitrarily impose surcharge */
+                   tmp += tmp / 3L;
+       }
+#ifdef TOURIST
+       if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV/2))
+           || (uarmu && !uarm && !uarmc))      /* touristy shirt visible */
+               tmp += tmp / 3L;
+       else
+#endif
+       if (uarmh && uarmh->otyp == DUNCE_CAP)
+               tmp += tmp / 3L;
+
+       if (ACURR(A_CHA) > 18)          tmp /= 2L;
+       else if (ACURR(A_CHA) > 17)     tmp -= tmp / 3L;
+       else if (ACURR(A_CHA) > 15)     tmp -= tmp / 4L;
+       else if (ACURR(A_CHA) < 6)      tmp *= 2L;
+       else if (ACURR(A_CHA) < 8)      tmp += tmp / 2L;
+       else if (ACURR(A_CHA) < 11)     tmp += tmp / 3L;
+       if (tmp <= 0L) tmp = 1L;
+       else if (obj->oartifact) tmp *= 4L;
+       /* anger surcharge should match rile_shk's */
+       if (shkp && ESHK(shkp)->surcharge) tmp += (tmp + 2L) / 3L;
+       return tmp;
+}
+#endif /*OVL3*/
+#ifdef OVLB
+
+/* returns the price of a container's content.  the price
+ * of the "top" container is added in the calling functions.
+ * a different price quoted for selling as vs. buying.
+ */
+long
+contained_cost(obj, shkp, price, usell, unpaid_only)
+register struct obj *obj;
+register struct monst *shkp;
+long price;
+register boolean usell;
+register boolean unpaid_only;
+{
+       register struct obj *otmp;
+
+       /* the price of contained objects */
+       for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
+           if (otmp->oclass == COIN_CLASS) continue;
+           /* the "top" container is evaluated by caller */
+           if (usell) {
+               if (saleable(shkp, otmp) &&
+                       !otmp->unpaid && otmp->oclass != BALL_CLASS &&
+                       !(otmp->oclass == FOOD_CLASS && otmp->oeaten) &&
+                       !(Is_candle(otmp) && otmp->age <
+                               20L * (long)objects[otmp->otyp].oc_cost))
+                   price += set_cost(otmp, shkp);
+           } else if (!otmp->no_charge &&
+                     (!unpaid_only || (unpaid_only && otmp->unpaid))) {
+                   price += get_cost(otmp, shkp) * otmp->quan;
+           }
+
+           if (Has_contents(otmp))
+                   price += contained_cost(otmp, shkp, price, usell, unpaid_only);
+       }
+
+       return(price);
+}
+
+long
+contained_gold(obj)
+register struct obj *obj;
+{
+       register struct obj *otmp;
+       register long value = 0L;
+
+       /* accumulate contained gold */
+       for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
+           if (otmp->oclass == COIN_CLASS)
+               value += otmp->quan;
+           else if (Has_contents(otmp))
+               value += contained_gold(otmp);
+
+       return(value);
+}
+
+STATIC_OVL void
+dropped_container(obj, shkp, sale)
+register struct obj *obj;
+register struct monst *shkp;
+register boolean sale;
+{
+       register struct obj *otmp;
+
+       /* the "top" container is treated in the calling fn */
+       for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
+           if (otmp->oclass == COIN_CLASS) continue;
+
+           if (!otmp->unpaid && !(sale && saleable(shkp, otmp)))
+               otmp->no_charge = 1;
+
+           if (Has_contents(otmp))
+               dropped_container(otmp, shkp, sale);
+       }
+}
+
+void
+picked_container(obj)
+register struct obj *obj;
+{
+       register struct obj *otmp;
+
+       /* the "top" container is treated in the calling fn */
+       for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
+           if (otmp->oclass == COIN_CLASS) continue;
+
+           if (otmp->no_charge)
+               otmp->no_charge = 0;
+
+           if (Has_contents(otmp))
+               picked_container(otmp);
+       }
+}
+#endif /*OVLB*/
+#ifdef OVL3
+
+/* calculate how much the shk will pay when buying [all of] an object */
+STATIC_OVL long
+set_cost(obj, shkp)
+register struct obj *obj;
+register struct monst *shkp;
+{
+       long tmp = getprice(obj, TRUE) * obj->quan;
+
+#ifdef TOURIST
+       if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV/2))
+           || (uarmu && !uarm && !uarmc))      /* touristy shirt visible */
+               tmp /= 3L;
+       else
+#endif
+       if (uarmh && uarmh->otyp == DUNCE_CAP)
+               tmp /= 3L;
+       else
+               tmp /= 2L;
+
+       /* shopkeeper may notice if the player isn't very knowledgeable -
+          especially when gem prices are concerned */
+       if (!obj->dknown || !objects[obj->otyp].oc_name_known) {
+               if (obj->oclass == GEM_CLASS) {
+                       /* different shop keepers give different prices */
+                       if (objects[obj->otyp].oc_material == GEMSTONE ||
+                           objects[obj->otyp].oc_material == GLASS) {
+                               tmp = (obj->otyp % (6 - shkp->m_id % 3));
+                               tmp = (tmp + 3) * obj->quan;
+                       }
+               } else if (tmp > 1L && !rn2(4))
+                       tmp -= tmp / 4L;
+       }
+       return tmp;
+}
+
+#endif /*OVL3*/
+#ifdef OVLB
+
+/* called from doinv(invent.c) for inventory of unpaid objects */
+long
+unpaid_cost(unp_obj)
+register struct obj *unp_obj;  /* known to be unpaid */
+{
+       register struct bill_x *bp = (struct bill_x *)0;
+       register struct monst *shkp;
+
+       for(shkp = next_shkp(fmon, TRUE); shkp;
+                                       shkp = next_shkp(shkp->nmon, TRUE))
+           if ((bp = onbill(unp_obj, shkp, TRUE)) != 0) break;
+
+       /* onbill() gave no message if unexpected problem occurred */
+       if(!bp) impossible("unpaid_cost: object wasn't on any bill!");
+
+       return bp ? unp_obj->quan * bp->price : 0L;
+}
+
+STATIC_OVL void
+add_one_tobill(obj, dummy)
+register struct obj *obj;
+register boolean dummy;
+{
+       register struct monst *shkp;
+       register struct bill_x *bp;
+       register int bct;
+       register char roomno = *u.ushops;
+
+       if (!roomno) return;
+       if (!(shkp = shop_keeper(roomno))) return;
+       if (!inhishop(shkp)) return;
+
+       if (onbill(obj, shkp, FALSE) || /* perhaps thrown away earlier */
+                   (obj->oclass == FOOD_CLASS && obj->oeaten))
+               return;
+
+       if (ESHK(shkp)->billct == BILLSZ) {
+               You("got that for free!");
+               return;
+       }
+
+       /* To recognize objects the shopkeeper is not interested in. -dgk
+        */
+       if (obj->no_charge) {
+               obj->no_charge = 0;
+               return;
+       }
+
+       bct = ESHK(shkp)->billct;
+       bp = &(ESHK(shkp)->bill_p[bct]);
+       bp->bo_id = obj->o_id;
+       bp->bquan = obj->quan;
+       if(dummy) {               /* a dummy object must be inserted into  */
+           bp->useup = 1;        /* the billobjs chain here.  crucial for */
+           add_to_billobjs(obj); /* eating floorfood in shop.  see eat.c  */
+       } else  bp->useup = 0;
+       bp->price = get_cost(obj, shkp);
+       ESHK(shkp)->billct++;
+       obj->unpaid = 1;
+}
+
+STATIC_OVL void
+add_to_billobjs(obj)
+    struct obj *obj;
+{
+    if (obj->where != OBJ_FREE)
+       panic("add_to_billobjs: obj not free");
+    if (obj->timed)
+       obj_stop_timers(obj);
+
+    obj->nobj = billobjs;
+    billobjs = obj;
+    obj->where = OBJ_ONBILL;
+}
+
+/* recursive billing of objects within containers. */
+STATIC_OVL void
+bill_box_content(obj, ininv, dummy, shkp)
+register struct obj *obj;
+register boolean ininv, dummy;
+register struct monst *shkp;
+{
+       register struct obj *otmp;
+
+       for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
+               if (otmp->oclass == COIN_CLASS) continue;
+
+               /* the "top" box is added in addtobill() */
+               if (!otmp->no_charge)
+                   add_one_tobill(otmp, dummy);
+               if (Has_contents(otmp))
+                   bill_box_content(otmp, ininv, dummy, shkp);
+       }
+
+}
+
+/* shopkeeper tells you what you bought or sold, sometimes partly IDing it */
+STATIC_OVL void
+shk_names_obj(shkp, obj, fmt, amt, arg)
+struct monst *shkp;
+struct obj *obj;
+const char *fmt;       /* "%s %ld %s %s", doname(obj), amt, plur(amt), arg */
+long amt;
+const char *arg;
+{
+       char *obj_name, fmtbuf[BUFSZ];
+       boolean was_unknown = !obj->dknown;
+
+       obj->dknown = TRUE;
+       /* Use real name for ordinary weapons/armor, and spell-less
+        * scrolls/books (that is, blank and mail), but only if the
+        * object is within the shk's area of interest/expertise.
+        */
+       if (!objects[obj->otyp].oc_magic && saleable(shkp, obj) &&
+           (obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS ||
+            obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS ||
+            obj->otyp == MIRROR)) {
+           was_unknown |= !objects[obj->otyp].oc_name_known;
+           makeknown(obj->otyp);
+       }
+       obj_name = doname(obj);
+       /* Use an alternate message when extra information is being provided */
+       if (was_unknown) {
+           Sprintf(fmtbuf, "%%s; you %s", fmt);
+           obj_name[0] = highc(obj_name[0]);
+           pline(fmtbuf, obj_name, (obj->quan > 1) ? "them" : "it",
+                 amt, plur(amt), arg);
+       } else {
+           You(fmt, obj_name, amt, plur(amt), arg);
+       }
+}
+
+void
+addtobill(obj, ininv, dummy, silent)
+register struct obj *obj;
+register boolean ininv, dummy, silent;
+{
+       register struct monst *shkp;
+       register char roomno = *u.ushops;
+       long ltmp = 0L, cltmp = 0L, gltmp = 0L;
+       register boolean container = Has_contents(obj);
+
+       if(!*u.ushops) return;
+
+       if(!(shkp = shop_keeper(roomno))) return;
+
+       if(!inhishop(shkp)) return;
+
+       if(/* perhaps we threw it away earlier */
+                onbill(obj, shkp, FALSE) ||
+                (obj->oclass == FOOD_CLASS && obj->oeaten)
+             ) return;
+
+       if(ESHK(shkp)->billct == BILLSZ) {
+               You("got that for free!");
+               return;
+       }
+
+       if(obj->oclass == COIN_CLASS) {
+               costly_gold(obj->ox, obj->oy, obj->quan);
+               return;
+       }
+
+       if(!obj->no_charge)
+           ltmp = get_cost(obj, shkp);
+
+       if (obj->no_charge && !container) {
+               obj->no_charge = 0;
+               return;
+       }
+
+       if(container) {
+           if(obj->cobj == (struct obj *)0) {
+               if(obj->no_charge) {
+                   obj->no_charge = 0;
+                   return;
+               } else {
+                   add_one_tobill(obj, dummy);
+                   goto speak;
+               }
+           } else {
+               cltmp += contained_cost(obj, shkp, cltmp, FALSE, FALSE);
+               gltmp += contained_gold(obj);
+           }
+
+           if(ltmp) add_one_tobill(obj, dummy);
+           if(cltmp) bill_box_content(obj, ininv, dummy, shkp);
+           picked_container(obj); /* reset contained obj->no_charge */
+
+           ltmp += cltmp;
+
+           if(gltmp) {
+               costly_gold(obj->ox, obj->oy, gltmp);
+               if(!ltmp) return;
+           }
+
+           if(obj->no_charge)
+               obj->no_charge = 0;
+
+       } else /* i.e., !container */
+           add_one_tobill(obj, dummy);
+speak:
+       if (shkp->mcanmove && !shkp->msleeping && !silent) {
+           char buf[BUFSZ];
+
+           if(!ltmp) {
+               pline("%s has no interest in %s.", Monnam(shkp),
+                                            the(xname(obj)));
+               return;
+           }
+           Strcpy(buf, "\"For you, ");
+           if (ANGRY(shkp)) Strcat(buf, "scum ");
+           else {
+               static const char *honored[5] = {
+                 "good", "honored", "most gracious", "esteemed",
+                 "most renowned and sacred"
+               };
+               Strcat(buf, honored[rn2(4) + u.uevent.udemigod]);
+               if (!is_human(youmonst.data)) Strcat(buf, " creature");
+               else
+                   Strcat(buf, (flags.female) ? " lady" : " sir");
+           }
+           if(ininv) {
+               long quan = obj->quan;
+               obj->quan = 1L; /* fool xname() into giving singular */
+               pline("%s; only %ld %s %s.\"", buf, ltmp,
+                       (quan > 1L) ? "per" : "for this", xname(obj));
+               obj->quan = quan;
+           } else
+               pline("%s will cost you %ld %s%s.",
+                       The(xname(obj)), ltmp, currency(ltmp),
+                       (obj->quan > 1L) ? " each" : "");
+       } else if(!silent) {
+           if(ltmp) pline_The("list price of %s is %ld %s%s.",
+                                  the(xname(obj)), ltmp, currency(ltmp),
+                                  (obj->quan > 1L) ? " each" : "");
+           else pline("%s does not notice.", Monnam(shkp));
+       }
+}
+
+void
+splitbill(obj, otmp)
+register struct obj *obj, *otmp;
+{
+       /* otmp has been split off from obj */
+       register struct bill_x *bp;
+       register long tmp;
+       register struct monst *shkp = shop_keeper(*u.ushops);
+
+       if(!shkp || !inhishop(shkp)) {
+               impossible("splitbill: no resident shopkeeper??");
+               return;
+       }
+       bp = onbill(obj, shkp, FALSE);
+       if(!bp) {
+               impossible("splitbill: not on bill?");
+               return;
+       }
+       if(bp->bquan < otmp->quan) {
+               impossible("Negative quantity on bill??");
+       }
+       if(bp->bquan == otmp->quan) {
+               impossible("Zero quantity on bill??");
+       }
+       bp->bquan -= otmp->quan;
+
+       if(ESHK(shkp)->billct == BILLSZ) otmp->unpaid = 0;
+       else {
+               tmp = bp->price;
+               bp = &(ESHK(shkp)->bill_p[ESHK(shkp)->billct]);
+               bp->bo_id = otmp->o_id;
+               bp->bquan = otmp->quan;
+               bp->useup = 0;
+               bp->price = tmp;
+               ESHK(shkp)->billct++;
+       }
+}
+
+STATIC_OVL void
+sub_one_frombill(obj, shkp)
+register struct obj *obj;
+register struct monst *shkp;
+{
+       register struct bill_x *bp;
+
+       if((bp = onbill(obj, shkp, FALSE)) != 0) {
+               register struct obj *otmp;
+
+               obj->unpaid = 0;
+               if(bp->bquan > obj->quan){
+                       otmp = newobj(0);
+                       *otmp = *obj;
+                       bp->bo_id = otmp->o_id = flags.ident++;
+                       otmp->where = OBJ_FREE;
+                       otmp->quan = (bp->bquan -= obj->quan);
+                       otmp->owt = 0;  /* superfluous */
+                       otmp->onamelth = 0;
+                       otmp->oxlth = 0;
+                       otmp->oattached = OATTACHED_NOTHING;
+                       bp->useup = 1;
+                       add_to_billobjs(otmp);
+                       return;
+               }
+               ESHK(shkp)->billct--;
+#ifdef DUMB
+               {
+               /* DRS/NS 2.2.6 messes up -- Peter Kendell */
+                       int indx = ESHK(shkp)->billct;
+                       *bp = ESHK(shkp)->bill_p[indx];
+               }
+#else
+               *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct];
+#endif
+               return;
+       } else if (obj->unpaid) {
+               impossible("sub_one_frombill: unpaid object not on bill");
+               obj->unpaid = 0;
+       }
+}
+
+/* recursive check of unpaid objects within nested containers. */
+void
+subfrombill(obj, shkp)
+register struct obj *obj;
+register struct monst *shkp;
+{
+       register struct obj *otmp;
+
+       sub_one_frombill(obj, shkp);
+
+       if (Has_contents(obj))
+           for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
+               if(otmp->oclass == COIN_CLASS) continue;
+
+               if (Has_contents(otmp))
+                   subfrombill(otmp, shkp);
+               else
+                   sub_one_frombill(otmp, shkp);
+           }
+}
+
+#endif /*OVLB*/
+#ifdef OVL3
+
+STATIC_OVL long
+stolen_container(obj, shkp, price, ininv)
+register struct obj *obj;
+register struct monst *shkp;
+long price;
+register boolean ininv;
+{
+       register struct obj *otmp;
+
+       if(ininv && obj->unpaid)
+           price += get_cost(obj, shkp);
+       else {
+           if(!obj->no_charge)
+               price += get_cost(obj, shkp);
+           obj->no_charge = 0;
+       }
+
+       /* the price of contained objects, if any */
+       for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
+
+           if(otmp->oclass == COIN_CLASS) continue;
+
+           if (!Has_contents(otmp)) {
+               if(ininv) {
+                   if(otmp->unpaid)
+                       price += otmp->quan * get_cost(otmp, shkp);
+               } else {
+                   if(!otmp->no_charge) {
+                       if(otmp->oclass != FOOD_CLASS || !otmp->oeaten)
+                           price += otmp->quan * get_cost(otmp, shkp);
+                   }
+                   otmp->no_charge = 0;
+               }
+           } else
+               price += stolen_container(otmp, shkp, price, ininv);
+       }
+
+       return(price);
+}
+#endif /*OVL3*/
+#ifdef OVLB
+
+long
+stolen_value(obj, x, y, peaceful, silent)
+register struct obj *obj;
+register xchar x, y;
+register boolean peaceful, silent;
+{
+       register long value = 0L, gvalue = 0L;
+       register struct monst *shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
+
+       if (!shkp || !inhishop(shkp))
+           return (0L);
+
+       if(obj->oclass == COIN_CLASS) {
+           gvalue += obj->quan;
+       } else if (Has_contents(obj)) {
+           register boolean ininv = !!count_unpaid(obj->cobj);
+
+           value += stolen_container(obj, shkp, value, ininv);
+           if(!ininv) gvalue += contained_gold(obj);
+       } else if (!obj->no_charge && saleable(shkp, obj)) {
+           value += get_cost(obj, shkp);
+       }
+
+       if(gvalue + value == 0L) return(0L);
+
+       value += gvalue;
+
+       if(peaceful) {
+           boolean credit_use = !!ESHK(shkp)->credit;
+           value = check_credit(value, shkp);
+           /* 'peaceful' affects general treatment, but doesn't affect
+            * the fact that other code expects that all charges after the
+            * shopkeeper is angry are included in robbed, not debit */
+           if (ANGRY(shkp))
+               ESHK(shkp)->robbed += value;
+           else 
+               ESHK(shkp)->debit += value;
+
+           if(!silent) {
+               const char *still = "";
+
+               if (credit_use) {
+                   if (ESHK(shkp)->credit) {
+                       You("have %ld %s credit remaining.",
+                                ESHK(shkp)->credit, currency(ESHK(shkp)->credit));
+                       return value;
+                   } else if (!value) {
+                       You("have no credit remaining.");
+                       return 0;
+                   }
+                   still = "still ";
+               }
+               if(obj->oclass == COIN_CLASS)
+                   You("%sowe %s %ld %s!", still,
+                       mon_nam(shkp), value, currency(value));
+               else
+                   You("%sowe %s %ld %s for %s!", still,
+                       mon_nam(shkp), value, currency(value),
+                       obj->quan > 1L ? "them" : "it");
+           }
+       } else {
+           ESHK(shkp)->robbed += value;
+
+           if(!silent) {
+               if(cansee(shkp->mx, shkp->my)) {
+                   Norep("%s booms: \"%s, you are a thief!\"",
+                               Monnam(shkp), plname);
+               } else  Norep("You hear a scream, \"Thief!\"");
+           }
+           hot_pursuit(shkp);
+           (void) angry_guards(FALSE);
+       }
+       return(value);
+}
+
+/* auto-response flag for/from "sell foo?" 'a' => 'y', 'q' => 'n' */
+static char sell_response = 'a';
+static int sell_how = SELL_NORMAL;
+/* can't just use sell_response='y' for auto_credit because the 'a' response
+   shouldn't carry over from ordinary selling to credit selling */
+static boolean auto_credit = FALSE;
+
+void
+sellobj_state(deliberate)
+int deliberate;
+{
+       /* If we're deliberately dropping something, there's no automatic
+          response to the shopkeeper's "want to sell" query; however, if we
+          accidentally drop anything, the shk will buy it/them without asking.
+          This retains the old pre-query risk that slippery fingers while in
+          shops entailed:  you drop it, you've lost it.
+        */
+       sell_response = (deliberate != SELL_NORMAL) ? '\0' : 'a';
+       sell_how = deliberate;
+       auto_credit = FALSE;
+}
+
+void
+sellobj(obj, x, y)
+register struct obj *obj;
+xchar x, y;
+{
+       register struct monst *shkp;
+       register struct eshk *eshkp;
+       long ltmp = 0L, cltmp = 0L, gltmp = 0L, offer;
+       boolean saleitem, cgold = FALSE, container = Has_contents(obj);
+       boolean isgold = (obj->oclass == COIN_CLASS);
+       boolean only_partially_your_contents = FALSE;
+
+       if(!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) ||
+          !inhishop(shkp)) return;
+       if(!costly_spot(x, y))  return;
+       if(!*u.ushops) return;
+
+       if(obj->unpaid && !container && !isgold) {
+           sub_one_frombill(obj, shkp);
+           return;
+       }
+       if(container) {
+               /* find the price of content before subfrombill */
+               cltmp += contained_cost(obj, shkp, cltmp, TRUE, FALSE);
+               /* find the value of contained gold */
+               gltmp += contained_gold(obj);
+               cgold = (gltmp > 0L);
+       }
+
+       saleitem = saleable(shkp, obj);
+       if(!isgold && !obj->unpaid && saleitem)
+           ltmp = set_cost(obj, shkp);
+
+       offer = ltmp + cltmp;
+
+       /* get one case out of the way: nothing to sell, and no gold */
+       if(!isgold &&
+          ((offer + gltmp) == 0L || sell_how == SELL_DONTSELL)) {
+               register boolean unpaid = (obj->unpaid ||
+                                 (container && count_unpaid(obj->cobj)));
+
+               if(container) {
+                       dropped_container(obj, shkp, FALSE);
+                       if(!obj->unpaid && !saleitem)
+                           obj->no_charge = 1;
+                       if(obj->unpaid || count_unpaid(obj->cobj))
+                           subfrombill(obj, shkp);
+               } else obj->no_charge = 1;
+
+               if(!unpaid && (sell_how != SELL_DONTSELL))
+                   pline("%s seems uninterested.", Monnam(shkp));
+               return;
+       }
+
+       /* you dropped something of your own - probably want to sell it */
+       rouse_shk(shkp, TRUE);  /* wake up sleeping or paralyzed shk */
+       eshkp = ESHK(shkp);
+
+       if (ANGRY(shkp)) { /* they become shop-objects, no pay */
+               pline("Thank you, scum!");
+               subfrombill(obj, shkp);
+               return;
+       }
+
+       if(eshkp->robbed) {  /* shkp is not angry? */
+               if(isgold) offer = obj->quan;
+               else if(cgold) offer += cgold;
+               if((eshkp->robbed -= offer < 0L))
+                       eshkp->robbed = 0L;
+               if(offer) verbalize(
+  "Thank you for your contribution to restock this recently plundered shop.");
+               subfrombill(obj, shkp);
+               return;
+       }
+
+       if(isgold || cgold) {
+               if(!cgold) gltmp = obj->quan;
+
+               if(eshkp->debit >= gltmp) {
+                   if(eshkp->loan) { /* you carry shop's gold */
+                        if(eshkp->loan >= gltmp)
+                            eshkp->loan -= gltmp;
+                        else eshkp->loan = 0L;
+                   }
+                   eshkp->debit -= gltmp;
+                   Your("debt is %spaid off.",
+                               eshkp->debit ? "partially " : "");
+               } else {
+                   long delta = gltmp - eshkp->debit;
+
+                   eshkp->credit += delta;
+                   if(eshkp->debit) {
+                       eshkp->debit = 0L;
+                       eshkp->loan = 0L;
+                       Your("debt is paid off.");
+                   }
+                   pline("%ld %s %s added to your credit.",
+                               delta, currency(delta), delta > 1L ? "are" : "is");
+               }
+               if(offer) goto move_on;
+               else {
+                   if(!isgold) {
+                       if (container)
+                           dropped_container(obj, shkp, FALSE);
+                       if (!obj->unpaid && !saleitem) obj->no_charge = 1;
+                       subfrombill(obj, shkp);
+                   }
+                   return;
+               }
+       }
+move_on:
+       if((!saleitem && !(container && cltmp > 0L))
+          || eshkp->billct == BILLSZ
+          || obj->oclass == BALL_CLASS
+          || obj->oclass == CHAIN_CLASS || offer == 0L
+          || (obj->oclass == FOOD_CLASS && obj->oeaten)
+          || (Is_candle(obj) &&
+                  obj->age < 20L * (long)objects[obj->otyp].oc_cost)) {
+               pline("%s seems uninterested%s.", Monnam(shkp),
+                       cgold ? " in the rest" : "");
+               if (container)
+                   dropped_container(obj, shkp, FALSE);
+               obj->no_charge = 1;
+               return;
+       }
+        
+#ifndef GOLDOBJ
+       if(!shkp->mgold) {
+#else
+       if(!money_cnt(shkp->minvent)) {
+#endif
+               char c, qbuf[BUFSZ];
+               long tmpcr = ((offer * 9L) / 10L) + (offer <= 1L);
+
+               if (sell_how == SELL_NORMAL || auto_credit) {
+                   c = sell_response = 'y';
+               } else if (sell_response != 'n') {
+                   pline("%s cannot pay you at present.", Monnam(shkp));
+                   Sprintf(qbuf,
+                           "Will you accept %ld %s in credit for %s?",
+                           tmpcr, currency(tmpcr), doname(obj));
+                   /* won't accept 'a' response here */
+                   /* KLY - 3/2000 yes, we will, it's a damn nuisance
+                       to have to constantly hit 'y' to sell for credit */
+                   c = ynaq(qbuf);
+                   if (c == 'a') {
+                       c = 'y';
+                       auto_credit = TRUE;
+                   }
+               } else          /* previously specified "quit" */
+                   c = 'n';
+
+               if (c == 'y') {
+                   shk_names_obj(shkp, obj, (sell_how != SELL_NORMAL) ?
+                           "traded %s for %ld zorkmid%s in %scredit." :
+                       "relinquish %s and acquire %ld zorkmid%s in %scredit.",
+                           tmpcr,
+                           (eshkp->credit > 0L) ? "additional " : "");
+                   eshkp->credit += tmpcr;
+                   subfrombill(obj, shkp);
+               } else {
+                   if (c == 'q') sell_response = 'n';
+                   if (container)
+                       dropped_container(obj, shkp, FALSE);
+                   if (!obj->unpaid) obj->no_charge = 1;
+                   subfrombill(obj, shkp);
+               }
+       } else {
+               char qbuf[BUFSZ];
+#ifndef GOLDOBJ
+               boolean short_funds = (offer > shkp->mgold);
+               if (short_funds) offer = shkp->mgold;
+#else
+                long shkmoney = money_cnt(shkp->minvent);
+               boolean short_funds = (offer > shkmoney);
+               if (short_funds) offer = shkmoney;
+#endif
+               if (!sell_response) {
+                   only_partially_your_contents =
+                       (contained_cost(obj, shkp, 0L, FALSE, FALSE) !=
+                        contained_cost(obj, shkp, 0L, FALSE, TRUE));
+                   Sprintf(qbuf,
+                        "%s offers%s %ld gold piece%s for%s %s %s.  Sell %s?",
+                           Monnam(shkp), short_funds ? " only" : "",
+                           offer, plur(offer),
+                           (!ltmp && cltmp && only_partially_your_contents) ?
+                            " your items in" : (!ltmp && cltmp) ? " the contents of" : "",
+                           obj->unpaid ? "the" : "your", cxname(obj),
+                           (obj->quan == 1L &&
+                           !(!ltmp && cltmp && only_partially_your_contents)) ?
+                           "it" : "them");
+               } else  qbuf[0] = '\0';         /* just to pacify lint */
+
+               switch (sell_response ? sell_response : ynaq(qbuf)) {
+                case 'q':  sell_response = 'n';
+                case 'n':  if (container)
+                               dropped_container(obj, shkp, FALSE);
+                           if (!obj->unpaid) obj->no_charge = 1;
+                           subfrombill(obj, shkp);
+                           break;
+                case 'a':  sell_response = 'y';
+                case 'y':  if (container)
+                               dropped_container(obj, shkp, TRUE);
+                           if (!obj->unpaid && !saleitem) obj->no_charge = 1;
+                           subfrombill(obj, shkp);
+                           pay(-offer, shkp);
+                           shk_names_obj(shkp, obj, (sell_how != SELL_NORMAL) ?
+                                   (!ltmp && cltmp && only_partially_your_contents) ?
+                                   "sold some items inside %s for %ld gold pieces%s.%s" :
+                                   "sold %s for %ld gold piece%s.%s" :
+              "relinquish %s and receive %ld gold piece%s in compensation.%s",
+                                   offer, "");
+                           break;
+                default:   impossible("invalid sell response");
+               }
+       }
+}
+
+int
+doinvbill(mode)
+int mode;              /* 0: deliver count 1: paged */
+{
+#ifdef __SASC
+       void sasc_bug(struct obj *, unsigned);
+#endif
+       struct monst *shkp;
+       struct eshk *eshkp;
+       struct bill_x *bp, *end_bp;
+       struct obj *obj;
+       long totused;
+       char *buf_p;
+       winid datawin;
+
+       shkp = shop_keeper(*u.ushops);
+       if (!shkp || !inhishop(shkp)) {
+           if (mode != 0) impossible("doinvbill: no shopkeeper?");
+           return 0;
+       }
+       eshkp = ESHK(shkp);
+
+       if (mode == 0) {
+           /* count expended items, so that the `I' command can decide
+              whether to include 'x' in its prompt string */
+           int cnt = !eshkp->debit ? 0 : 1;
+
+           for (bp = eshkp->bill_p, end_bp = &eshkp->bill_p[eshkp->billct];
+                   bp < end_bp; bp++)
+               if (bp->useup ||
+                       ((obj = bp_to_obj(bp)) != 0 && obj->quan < bp->bquan))
+                   cnt++;
+           return cnt;
+       }
+
+       datawin = create_nhwindow(NHW_MENU);
+       putstr(datawin, 0, "Unpaid articles already used up:");
+       putstr(datawin, 0, "");
+
+       totused = 0L;
+       for (bp = eshkp->bill_p, end_bp = &eshkp->bill_p[eshkp->billct];
+               bp < end_bp; bp++) {
+           obj = bp_to_obj(bp);
+           if(!obj) {
+               impossible("Bad shopkeeper administration.");
+               goto quit;
+           }
+           if(bp->useup || bp->bquan > obj->quan) {
+               long oquan, uquan, thisused;
+               unsigned save_unpaid;
+
+               save_unpaid = obj->unpaid;
+               oquan = obj->quan;
+               uquan = (bp->useup ? bp->bquan : bp->bquan - oquan);
+               thisused = bp->price * uquan;
+               totused += thisused;
+               obj->unpaid = 0;                /* ditto */
+               /* Why 'x'?  To match `I x', more or less. */
+               buf_p = xprname(obj, (char *)0, 'x', FALSE, thisused, uquan);
+#ifdef __SASC
+                               /* SAS/C 6.2 can't cope for some reason */
+               sasc_bug(obj,save_unpaid);
+#else
+               obj->unpaid = save_unpaid;
+#endif
+               putstr(datawin, 0, buf_p);
+           }
+       }
+       if (eshkp->debit) {
+           /* additional shop debt which has no itemization available */
+           if (totused) putstr(datawin, 0, "");
+           totused += eshkp->debit;
+           buf_p = xprname((struct obj *)0,
+                           "usage charges and/or other fees",
+                           GOLD_SYM, FALSE, eshkp->debit, 0L);
+           putstr(datawin, 0, buf_p);
+       }
+       buf_p = xprname((struct obj *)0, "Total:", '*', FALSE, totused, 0L);
+       putstr(datawin, 0, "");
+       putstr(datawin, 0, buf_p);
+       display_nhwindow(datawin, FALSE);
+    quit:
+       destroy_nhwindow(datawin);
+       return(0);
+}
+
+#define HUNGRY 2
+
+STATIC_OVL long
+getprice(obj, shk_buying)
+register struct obj *obj;
+boolean shk_buying;
+{
+       register long tmp = (long) objects[obj->otyp].oc_cost;
+
+       if (obj->oartifact) {
+           tmp = arti_cost(obj);
+           if (shk_buying) tmp /= 4;
+       }
+       switch(obj->oclass) {
+       case FOOD_CLASS:
+               /* simpler hunger check, (2-4)*cost */
+               if (u.uhs >= HUNGRY && !shk_buying) tmp *= (long) u.uhs;
+               if (obj->oeaten) tmp = 0L;
+               break;
+       case WAND_CLASS:
+               if (obj->spe == -1) tmp = 0L;
+               break;
+       case POTION_CLASS:
+               if (obj->otyp == POT_WATER && !obj->blessed && !obj->cursed)
+                       tmp = 0L;
+               break;
+       case ARMOR_CLASS:
+       case WEAPON_CLASS:
+               if (obj->spe > 0) tmp += 10L * (long) obj->spe;
+               break;
+       case TOOL_CLASS:
+               if (Is_candle(obj) &&
+                       obj->age < 20L * (long)objects[obj->otyp].oc_cost)
+                   tmp /= 2L;
+               break;
+       }
+       return tmp;
+}
+
+/* shk catches thrown pick-axe */
+struct monst *
+shkcatch(obj, x, y)
+register struct obj *obj;
+register xchar x, y;
+{
+       register struct monst *shkp;
+
+       if (!(shkp = shop_keeper(inside_shop(x, y))) ||
+           !inhishop(shkp)) return(0);
+
+       if (shkp->mcanmove && !shkp->msleeping &&
+           (*u.ushops != ESHK(shkp)->shoproom || !inside_shop(u.ux, u.uy)) &&
+           dist2(shkp->mx, shkp->my, x, y) < 3 &&
+           /* if it is the shk's pos, you hit and anger him */
+           (shkp->mx != x || shkp->my != y)) {
+               if (mnearto(shkp, x, y, TRUE))
+                   verbalize("Out of my way, scum!");
+               if (cansee(x, y)) {
+                   pline("%s nimbly%s catches %s.",
+                         Monnam(shkp),
+                         (x == shkp->mx && y == shkp->my) ? "" : " reaches over and",
+                         the(xname(obj)));
+                   if (!canspotmon(shkp))
+                       map_invisible(x, y);
+                   delay_output();
+                   mark_synch();
+               }
+               subfrombill(obj, shkp);
+               (void) mpickobj(shkp, obj);
+               return shkp;
+       }
+       return (struct monst *)0;
+}
+
+void
+add_damage(x, y, cost)
+register xchar x, y;
+long cost;
+{
+       struct damage *tmp_dam;
+       char *shops;
+
+       if (IS_DOOR(levl[x][y].typ)) {
+           struct monst *mtmp;
+
+           /* Don't schedule for repair unless it's a real shop entrance */
+           for (shops = in_rooms(x, y, SHOPBASE); *shops; shops++)
+               if ((mtmp = shop_keeper(*shops)) != 0 &&
+                       x == ESHK(mtmp)->shd.x && y == ESHK(mtmp)->shd.y)
+                   break;
+           if (!*shops) return;
+       }
+       for (tmp_dam = level.damagelist; tmp_dam; tmp_dam = tmp_dam->next)
+           if (tmp_dam->place.x == x && tmp_dam->place.y == y) {
+               tmp_dam->cost += cost;
+               return;
+           }
+       tmp_dam = (struct damage *)alloc((unsigned)sizeof(struct damage));
+       tmp_dam->when = monstermoves;
+       tmp_dam->place.x = x;
+       tmp_dam->place.y = y;
+       tmp_dam->cost = cost;
+       tmp_dam->typ = levl[x][y].typ;
+       tmp_dam->next = level.damagelist;
+       level.damagelist = tmp_dam;
+       /* If player saw damage, display as a wall forever */
+       if (cansee(x, y))
+           levl[x][y].seenv = SVALL;
+}
+
+#endif /*OVLB*/
+#ifdef OVL0
+
+/*
+ * Do something about damage. Either (!croaked) try to repair it, or
+ * (croaked) just discard damage structs for non-shared locations, since
+ * they'll never get repaired. Assume that shared locations will get
+ * repaired eventually by the other shopkeeper(s). This might be an erroneous
+ * assumption (they might all be dead too), but we have no reasonable way of
+ * telling that.
+ */
+STATIC_OVL
+void
+remove_damage(shkp, croaked)
+register struct monst *shkp;
+register boolean croaked;
+{
+       register struct damage *tmp_dam, *tmp2_dam;
+       register boolean did_repair = FALSE, saw_door = FALSE;
+       register boolean saw_floor = FALSE, stop_picking = FALSE;
+       register boolean saw_untrap = FALSE;
+       uchar saw_walls = 0;
+
+       tmp_dam = level.damagelist;
+       tmp2_dam = 0;
+       while (tmp_dam) {
+           register xchar x = tmp_dam->place.x, y = tmp_dam->place.y;
+           char shops[5];
+           int disposition;
+
+           disposition = 0;
+           Strcpy(shops, in_rooms(x, y, SHOPBASE));
+           if (index(shops, ESHK(shkp)->shoproom)) {
+               if (croaked)
+                   disposition = (shops[1])? 0 : 1;
+               else if (stop_picking)
+                   disposition = repair_damage(shkp, tmp_dam, FALSE);
+               else {
+                   /* Defer the stop_occupation() until after repair msgs */
+                   if (closed_door(x, y))
+                       stop_picking = picking_at(x, y);
+                   disposition = repair_damage(shkp, tmp_dam, FALSE);
+                   if (!disposition)
+                       stop_picking = FALSE;
+               }
+           }
+
+           if (!disposition) {
+               tmp2_dam = tmp_dam;
+               tmp_dam = tmp_dam->next;
+               continue;
+           }
+
+           if (disposition > 1) {
+               did_repair = TRUE;
+               if (cansee(x, y)) {
+                   if (IS_WALL(levl[x][y].typ))
+                       saw_walls++;
+                   else if (IS_DOOR(levl[x][y].typ))
+                       saw_door = TRUE;
+                   else if (disposition == 3)          /* untrapped */
+                       saw_untrap = TRUE;
+                   else
+                       saw_floor = TRUE;
+               }
+           }
+
+           tmp_dam = tmp_dam->next;
+           if (!tmp2_dam) {
+               free((genericptr_t)level.damagelist);
+               level.damagelist = tmp_dam;
+           } else {
+               free((genericptr_t)tmp2_dam->next);
+               tmp2_dam->next = tmp_dam;
+           }
+       }
+       if (!did_repair)
+           return;
+       if (saw_walls) {
+           pline("Suddenly, %s section%s of wall close%s up!",
+                 (saw_walls == 1) ? "a" : (saw_walls <= 3) ?
+                                                 "some" : "several",
+                 (saw_walls == 1) ? "" : "s", (saw_walls == 1) ? "s" : "");
+           if (saw_door)
+               pline_The("shop door reappears!");
+           if (saw_floor)
+               pline_The("floor is repaired!");
+       } else {
+           if (saw_door)
+               pline("Suddenly, the shop door reappears!");
+           else if (saw_floor)
+               pline("Suddenly, the floor damage is gone!");
+           else if (saw_untrap)
+               pline("Suddenly, the trap is removed from the floor!");
+           else if (inside_shop(u.ux, u.uy) == ESHK(shkp)->shoproom)
+               You_feel("more claustrophobic than before.");
+           else if (flags.soundok && !rn2(10))
+               Norep("The dungeon acoustics noticeably change.");
+       }
+       if (stop_picking)
+               stop_occupation();
+}
+
+/*
+ * 0: repair postponed, 1: silent repair (no messages), 2: normal repair
+ * 3: untrap
+ */
+int
+repair_damage(shkp, tmp_dam, catchup)
+register struct monst *shkp;
+register struct damage *tmp_dam;
+boolean catchup;       /* restoring a level */
+{
+       register xchar x, y, i;
+       xchar litter[9];
+       register struct monst *mtmp;
+       register struct obj *otmp;
+       register struct trap *ttmp;
+
+       if ((monstermoves - tmp_dam->when) < REPAIR_DELAY)
+           return(0);
+       if (shkp->msleeping || !shkp->mcanmove || ESHK(shkp)->following)
+           return(0);
+       x = tmp_dam->place.x;
+       y = tmp_dam->place.y;
+       if (!IS_ROOM(tmp_dam->typ)) {
+           if (x == u.ux && y == u.uy)
+               if (!Passes_walls)
+                   return(0);
+           if (x == shkp->mx && y == shkp->my)
+               return(0);
+           if ((mtmp = m_at(x, y)) && (!passes_walls(mtmp->data)))
+               return(0);
+       }
+       if ((ttmp = t_at(x, y)) != 0) {
+           if (x == u.ux && y == u.uy)
+               if (!Passes_walls)
+                   return(0);
+           if (ttmp->ttyp == LANDMINE || ttmp->ttyp == BEAR_TRAP) {
+               /* convert to an object */
+               otmp = mksobj((ttmp->ttyp == LANDMINE) ? LAND_MINE :
+                               BEARTRAP, TRUE, FALSE);
+               otmp->quan= 1;
+               otmp->owt = weight(otmp);
+               (void) mpickobj(shkp, otmp);
+           }
+           deltrap(ttmp);
+           if(IS_DOOR(tmp_dam->typ)) {
+               levl[x][y].doormask = D_CLOSED; /* arbitrary */
+               block_point(x, y);
+           } else if (IS_WALL(tmp_dam->typ)) {
+               levl[x][y].typ = tmp_dam->typ;
+               block_point(x, y);
+           }
+           newsym(x, y);
+           return(3);
+       }
+       if (IS_ROOM(tmp_dam->typ)) {
+           /* No messages, because player already filled trap door */
+           return(1);
+       }
+       if ((tmp_dam->typ == levl[x][y].typ) &&
+           (!IS_DOOR(tmp_dam->typ) || (levl[x][y].doormask > D_BROKEN)))
+           /* No messages if player already replaced shop door */
+           return(1);
+       levl[x][y].typ = tmp_dam->typ;
+       (void) memset((genericptr_t)litter, 0, sizeof(litter));
+       if ((otmp = level.objects[x][y]) != 0) {
+           /* Scatter objects haphazardly into the shop */
+#define NEED_UPDATE 1
+#define OPEN       2
+#define INSHOP     4
+#define horiz(i) ((i%3)-1)
+#define vert(i)  ((i/3)-1)
+           for (i = 0; i < 9; i++) {
+               if ((i == 4) || (!ZAP_POS(levl[x+horiz(i)][y+vert(i)].typ)))
+                   continue;
+               litter[i] = OPEN;
+               if (inside_shop(x+horiz(i),
+                               y+vert(i)) == ESHK(shkp)->shoproom)
+                   litter[i] |= INSHOP;
+           }
+           if (Punished && !u.uswallow &&
+                               ((uchain->ox == x && uchain->oy == y) ||
+                                (uball->ox == x && uball->oy == y))) {
+               /*
+                * Either the ball or chain is in the repair location.
+                *
+                * Take the easy way out and put ball&chain under hero.
+                */
+               verbalize("Get your junk out of my wall!");
+               unplacebc();    /* pick 'em up */
+               placebc();      /* put 'em down */
+           }
+           while ((otmp = level.objects[x][y]) != 0)
+               /* Don't mess w/ boulders -- just merge into wall */
+               if ((otmp->otyp == BOULDER) || (otmp->otyp == ROCK)) {
+                   obj_extract_self(otmp);
+                   obfree(otmp, (struct obj *)0);
+               } else {
+                   while (!(litter[i = rn2(9)] & INSHOP));
+                       remove_object(otmp);
+                       place_object(otmp, x+horiz(i), y+vert(i));
+                       litter[i] |= NEED_UPDATE;
+               }
+       }
+       if (catchup) return 1;  /* repair occurred while off level */
+
+       block_point(x, y);
+       if(IS_DOOR(tmp_dam->typ)) {
+           levl[x][y].doormask = D_CLOSED; /* arbitrary */
+           newsym(x, y);
+       } else {
+           /* don't set doormask  - it is (hopefully) the same as it was */
+           /* if not, perhaps save it with the damage array...  */
+
+           if (IS_WALL(tmp_dam->typ) && cansee(x, y)) {
+           /* Player sees actual repair process, so they KNOW it's a wall */
+               levl[x][y].seenv = SVALL;
+               newsym(x, y);
+           }
+           /* Mark this wall as "repaired".  There currently is no code */
+           /* to do anything about repaired walls, so don't do it.      */
+       }
+       for (i = 0; i < 9; i++)
+           if (litter[i] & NEED_UPDATE)
+               newsym(x+horiz(i), y+vert(i));
+       return(2);
+#undef NEED_UPDATE
+#undef OPEN
+#undef INSHOP
+#undef vert
+#undef horiz
+}
+#endif /*OVL0*/
+#ifdef OVL3
+/*
+ * shk_move: return 1: moved  0: didn't  -1: let m_move do it  -2: died
+ */
+int
+shk_move(shkp)
+register struct monst *shkp;
+{
+       register xchar gx,gy,omx,omy;
+       register int udist;
+       register schar appr;
+       register struct eshk *eshkp = ESHK(shkp);
+       int z;
+       boolean uondoor = FALSE, satdoor, avoid = FALSE, badinv;
+
+       omx = shkp->mx;
+       omy = shkp->my;
+
+       if (inhishop(shkp))
+           remove_damage(shkp, FALSE);
+
+       if((udist = distu(omx,omy)) < 3 &&
+          (shkp->data != &mons[PM_GRID_BUG] || (omx==u.ux || omy==u.uy))) {
+               if(ANGRY(shkp) ||
+                  (Conflict && !resist(shkp, RING_CLASS, 0, 0))) {
+                       if(Displaced)
+                         Your("displaced image doesn't fool %s!",
+                               mon_nam(shkp));
+                       (void) mattacku(shkp);
+                       return(0);
+               }
+               if(eshkp->following) {
+                       if(strncmp(eshkp->customer, plname, PL_NSIZ)) {
+                           verbalize("%s, %s!  I was looking for %s.",
+                                   Hello(shkp), plname, eshkp->customer);
+                                   eshkp->following = 0;
+                           return(0);
+                       }
+                       if(moves > followmsg+4) {
+                           verbalize("%s, %s!  Didn't you forget to pay?",
+                                   Hello(shkp), plname);
+                           followmsg = moves;
+                           if (!rn2(9)) {
+                             pline("%s doesn't like customers who don't pay.",
+                                   Monnam(shkp));
+                               rile_shk(shkp);
+                           }
+                       }
+                       if(udist < 2)
+                           return(0);
+               }
+       }
+
+       appr = 1;
+       gx = eshkp->shk.x;
+       gy = eshkp->shk.y;
+       satdoor = (gx == omx && gy == omy);
+       if(eshkp->following || ((z = holetime()) >= 0 && z*z <= udist)){
+               /* [This distance check used to apply regardless of
+                   whether the shk was following, but that resulted in
+                   m_move() sometimes taking the shk out of the shop if
+                   the player had fenced him in with boulders or traps.
+                   Such voluntary abandonment left unpaid objects in
+                   invent, triggering billing impossibilities on the
+                   next level once the character fell through the hole.] */
+               if (udist > 4 && eshkp->following)
+                   return(-1); /* leave it to m_move */
+               gx = u.ux;
+               gy = u.uy;
+       } else if(ANGRY(shkp)) {
+               /* Move towards the hero if the shopkeeper can see him. */
+               if(shkp->mcansee && m_canseeu(shkp)) {
+                       gx = u.ux;
+                       gy = u.uy;
+               }
+               avoid = FALSE;
+       } else {
+#define        GDIST(x,y)      (dist2(x,y,gx,gy))
+               if (Invis
+#ifdef STEED
+                       || u.usteed
+#endif
+                       ) {
+                   avoid = FALSE;
+               } else {
+                   uondoor = (u.ux == eshkp->shd.x && u.uy == eshkp->shd.y);
+                   if(uondoor) {
+                       badinv = (carrying(PICK_AXE) || carrying(DWARVISH_MATTOCK) ||
+                                 (Fast && (sobj_at(PICK_AXE, u.ux, u.uy) ||
+                                 sobj_at(DWARVISH_MATTOCK, u.ux, u.uy))));
+                       if(satdoor && badinv)
+                           return(0);
+                       avoid = !badinv;
+                   } else {
+                       avoid = (*u.ushops && distu(gx,gy) > 8);
+                       badinv = FALSE;
+                   }
+
+                   if(((!eshkp->robbed && !eshkp->billct && !eshkp->debit)
+                       || avoid) && GDIST(omx,omy) < 3) {
+                       if (!badinv && !onlineu(omx,omy))
+                           return(0);
+                       if(satdoor)
+                           appr = gx = gy = 0;
+                   }
+               }
+       }
+
+       z = move_special(shkp,inhishop(shkp),appr,uondoor,avoid,omx,omy,gx,gy);
+       if (z > 0) after_shk_move(shkp);
+
+       return z;
+}
+
+/* called after shopkeeper moves, in case the move causes re-entry into shop */
+void
+after_shk_move(shkp)
+struct monst *shkp;
+{
+       struct eshk *eshkp = ESHK(shkp);
+
+       if (eshkp->bill_p == (struct bill_x *) -1000 && inhishop(shkp)) {
+           /* reset bill_p, need to re-calc player's occupancy too */
+           eshkp->bill_p = &eshkp->bill[0];
+           check_special_room(FALSE);
+       }
+}
+
+#endif /*OVL3*/
+#ifdef OVLB
+
+/* for use in levl_follower (mondata.c) */
+boolean
+is_fshk(mtmp)
+register struct monst *mtmp;
+{
+       return((boolean)(mtmp->isshk && ESHK(mtmp)->following));
+}
+
+/* You are digging in the shop. */
+void
+shopdig(fall)
+register int fall;
+{
+    register struct monst *shkp = shop_keeper(*u.ushops);
+    int lang;
+    const char *grabs = "grabs";
+
+    if(!shkp) return;
+
+    /* 0 == can't speak, 1 == makes animal noises, 2 == speaks */
+    lang = 0;
+    if (shkp->msleeping || !shkp->mcanmove || is_silent(shkp->data))
+       ;       /* lang stays 0 */
+    else if (shkp->data->msound <= MS_ANIMAL)
+       lang = 1;
+    else if (shkp->data->msound >= MS_HUMANOID)
+       lang = 2;
+
+    if(!inhishop(shkp)) {
+       if (Role_if(PM_KNIGHT)) {
+           You_feel("like a common thief.");
+           adjalign(-sgn(u.ualign.type));
+       }
+       return;
+    }
+
+    if(!fall) {
+       if (lang == 2) {
+           if(u.utraptype == TT_PIT)
+               verbalize(
+                       "Be careful, %s, or you might fall through the floor.",
+                       flags.female ? "madam" : "sir");
+           else
+               verbalize("%s, do not damage the floor here!",
+                       flags.female ? "Madam" : "Sir");
+       }
+       if (Role_if(PM_KNIGHT)) {
+           You_feel("like a common thief.");
+           adjalign(-sgn(u.ualign.type));
+       }
+    } else if(!um_dist(shkp->mx, shkp->my, 5) &&
+               !shkp->msleeping && shkp->mcanmove &&
+               (ESHK(shkp)->billct || ESHK(shkp)->debit)) {
+           register struct obj *obj, *obj2;
+           if (nolimbs(shkp->data)) {
+               grabs = "knocks off";
+#if 0
+              /* This is what should happen, but for balance
+               * reasons, it isn't currently.
+               */
+               if (lang == 2)
+                   pline("%s curses %s inability to grab your backpack!",
+                         shkname(shkp), mhim(shkp));
+               rile_shk(shkp);
+               return;
+#endif
+           }
+           if (distu(shkp->mx, shkp->my) > 2) {
+               mnexto(shkp);
+               /* for some reason the shopkeeper can't come next to you */
+               if (distu(shkp->mx, shkp->my) > 2) {
+                   if (lang == 2)
+                       pline("%s curses you in anger and frustration!",
+                             shkname(shkp));
+                   rile_shk(shkp);
+                   return;
+               } else
+                   pline("%s %s, and %s your backpack!",
+                         shkname(shkp),
+                         makeplural(locomotion(shkp->data,"leap")), grabs);
+           } else
+               pline("%s %s your backpack!", shkname(shkp), grabs);
+
+           for(obj = invent; obj; obj = obj2) {
+               obj2 = obj->nobj;
+               if ((obj->owornmask & ~(W_SWAPWEP|W_QUIVER)) != 0 ||
+                       (obj == uswapwep && u.twoweap) ||
+                       (obj->otyp == LEASH && obj->leashmon)) continue;
+               if (obj == current_wand) continue;
+               setnotworn(obj);
+               freeinv(obj);
+               subfrombill(obj, shkp);
+               (void) add_to_minv(shkp, obj);  /* may free obj */
+           }
+    }
+}
+
+#ifdef KOPS
+STATIC_OVL void
+makekops(mm)
+coord *mm;
+{
+       static const short k_mndx[4] = {
+           PM_KEYSTONE_KOP, PM_KOP_SERGEANT, PM_KOP_LIEUTENANT, PM_KOP_KAPTAIN
+       };
+       int k_cnt[4], cnt, mndx, k;
+
+       k_cnt[0] = cnt = abs(depth(&u.uz)) + rnd(5);
+       k_cnt[1] = (cnt / 3) + 1;       /* at least one sarge */
+       k_cnt[2] = (cnt / 6);           /* maybe a lieutenant */
+       k_cnt[3] = (cnt / 9);           /* and maybe a kaptain */
+
+       for (k = 0; k < 4; k++) {
+           if ((cnt = k_cnt[k]) == 0) break;
+           mndx = k_mndx[k];
+           if (mvitals[mndx].mvflags & G_GONE) continue;
+
+           while (cnt--)
+               if (enexto(mm, mm->x, mm->y, &mons[mndx]))
+                   (void) makemon(&mons[mndx], mm->x, mm->y, NO_MM_FLAGS);
+       }
+}
+#endif /* KOPS */
+
+void
+pay_for_damage(dmgstr, cant_mollify)
+const char *dmgstr;
+boolean cant_mollify;
+{
+       register struct monst *shkp = (struct monst *)0;
+       char shops_affected[5];
+       register boolean uinshp = (*u.ushops != '\0');
+       char qbuf[80];
+       register xchar x, y;
+       boolean dugwall = !strcmp(dmgstr, "dig into") ||        /* wand */
+                         !strcmp(dmgstr, "damage");            /* pick-axe */
+       struct damage *tmp_dam, *appear_here = 0;
+       /* any number >= (80*80)+(24*24) would do, actually */
+       long cost_of_damage = 0L;
+       unsigned int nearest_shk = 7000, nearest_damage = 7000;
+       int picks = 0;
+
+       for (tmp_dam = level.damagelist;
+            (tmp_dam && (tmp_dam->when == monstermoves));
+            tmp_dam = tmp_dam->next) {
+           char *shp;
+
+           if (!tmp_dam->cost)
+               continue;
+           cost_of_damage += tmp_dam->cost;
+           Strcpy(shops_affected,
+                  in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE));
+           for (shp = shops_affected; *shp; shp++) {
+               struct monst *tmp_shk;
+               unsigned int shk_distance;
+
+               if (!(tmp_shk = shop_keeper(*shp)))
+                   continue;
+               if (tmp_shk == shkp) {
+                   unsigned int damage_distance =
+                                  distu(tmp_dam->place.x, tmp_dam->place.y);
+
+                   if (damage_distance < nearest_damage) {
+                       nearest_damage = damage_distance;
+                       appear_here = tmp_dam;
+                   }
+                   continue;
+               }
+               if (!inhishop(tmp_shk))
+                   continue;
+               shk_distance = distu(tmp_shk->mx, tmp_shk->my);
+               if (shk_distance > nearest_shk)
+                   continue;
+               if ((shk_distance == nearest_shk) && picks) {
+                   if (rn2(++picks))
+                       continue;
+               } else
+                   picks = 1;
+               shkp = tmp_shk;
+               nearest_shk = shk_distance;
+               appear_here = tmp_dam;
+               nearest_damage = distu(tmp_dam->place.x, tmp_dam->place.y);
+           }
+       }
+
+       if (!cost_of_damage || !shkp)
+           return;
+
+       x = appear_here->place.x;
+       y = appear_here->place.y;
+
+       /* not the best introduction to the shk... */
+       (void) strncpy(ESHK(shkp)->customer,plname,PL_NSIZ);
+
+       /* if the shk is already on the war path, be sure it's all out */
+       if(ANGRY(shkp) || ESHK(shkp)->following) {
+               hot_pursuit(shkp);
+               return;
+       }
+
+       /* if the shk is not in their shop.. */
+       if(!*in_rooms(shkp->mx,shkp->my,SHOPBASE)) {
+               if(!cansee(shkp->mx, shkp->my))
+                       return;
+               goto getcad;
+       }
+
+       if(uinshp) {
+               if(um_dist(shkp->mx, shkp->my, 1) &&
+                       !um_dist(shkp->mx, shkp->my, 3)) {
+                   pline("%s leaps towards you!", shkname(shkp));
+                   mnexto(shkp);
+               }
+               if(um_dist(shkp->mx, shkp->my, 1)) goto getcad;
+       } else {
+           /*
+            * Make shkp show up at the door.  Effect:  If there is a monster
+            * in the doorway, have the hero hear the shopkeeper yell a bit,
+            * pause, then have the shopkeeper appear at the door, having
+            * yanked the hapless critter out of the way.
+            */
+           if (MON_AT(x, y)) {
+               if(flags.soundok) {
+                   You_hear("an angry voice:");
+                   verbalize("Out of my way, scum!");
+                   wait_synch();
+#if defined(UNIX) || defined(VMS)
+# if defined(SYSV) || defined(ULTRIX) || defined(VMS)
+                   (void)
+# endif
+                       sleep(1);
+#endif
+               }
+           }
+           (void) mnearto(shkp, x, y, TRUE);
+       }
+
+       if((um_dist(x, y, 1) && !uinshp) || cant_mollify ||
+#ifndef GOLDOBJ
+          (u.ugold + ESHK(shkp)->credit) < cost_of_damage
+#else
+          (money_cnt(invent) + ESHK(shkp)->credit) < cost_of_damage
+#endif
+                               || !rn2(50)) {
+               if(um_dist(x, y, 1) && !uinshp) {
+                   pline("%s shouts:", shkname(shkp));
+                   verbalize("Who dared %s my %s?", dmgstr,
+                                        dugwall ? "shop" : "door");
+               } else {
+getcad:
+                   verbalize("How dare you %s my %s?", dmgstr,
+                                        dugwall ? "shop" : "door");
+               }
+               hot_pursuit(shkp);
+               return;
+       }
+
+       if (Invis) Your("invisibility does not fool %s!", shkname(shkp));
+       Sprintf(qbuf,"\"Cad!  You did %ld %s worth of damage!\"  Pay? ",
+                cost_of_damage, currency(cost_of_damage));
+       if(yn(qbuf) != 'n') {
+               cost_of_damage = check_credit(cost_of_damage, shkp);
+#ifndef GOLDOBJ
+               u.ugold -= cost_of_damage;
+               shkp->mgold += cost_of_damage;
+#else
+                money2mon(shkp, cost_of_damage);
+#endif
+               flags.botl = 1;
+               pline("Mollified, %s accepts your restitution.",
+                       shkname(shkp));
+               /* move shk back to his home loc */
+               home_shk(shkp, FALSE);
+               pacify_shk(shkp);
+       } else {
+               verbalize("Oh, yes!  You'll pay!");
+               hot_pursuit(shkp);
+               adjalign(-sgn(u.ualign.type));
+       }
+}
+#endif /*OVLB*/
+#ifdef OVL0
+/* called in dokick.c when we kick an object that might be in a store */
+boolean
+costly_spot(x, y)
+register xchar x, y;
+{
+       register struct monst *shkp;
+
+       if (!level.flags.has_shop) return FALSE;
+       shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
+       if(!shkp || !inhishop(shkp)) return(FALSE);
+
+       return((boolean)(inside_shop(x, y) &&
+               !(x == ESHK(shkp)->shk.x &&
+                       y == ESHK(shkp)->shk.y)));
+}
+#endif /*OVL0*/
+#ifdef OVLB
+
+/* called by dotalk(sounds.c) when #chatting; returns obj if location
+   contains shop goods and shopkeeper is willing & able to speak */
+struct obj *
+shop_object(x, y)
+register xchar x, y;
+{
+    register struct obj *otmp;
+    register struct monst *shkp;
+
+    if(!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) || !inhishop(shkp))
+       return(struct obj *)0;
+
+    for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
+       if (otmp->oclass != COIN_CLASS)
+           break;
+    /* note: otmp might have ->no_charge set, but that's ok */
+    return (otmp && costly_spot(x, y) && NOTANGRY(shkp)
+           && shkp->mcanmove && !shkp->msleeping)
+               ? otmp : (struct obj *)0;
+}
+
+/* give price quotes for all objects linked to this one (ie, on this spot) */
+void
+price_quote(first_obj)
+register struct obj *first_obj;
+{
+    register struct obj *otmp;
+    char buf[BUFSZ], price[40];
+    long cost;
+    int cnt = 0;
+    winid tmpwin;
+    struct monst *shkp = shop_keeper(inside_shop(u.ux, u.uy));
+
+    tmpwin = create_nhwindow(NHW_MENU);
+    putstr(tmpwin, 0, "Fine goods for sale:");
+    putstr(tmpwin, 0, "");
+    for (otmp = first_obj; otmp; otmp = otmp->nexthere) {
+       if (otmp->oclass == COIN_CLASS) continue;
+       cost = (otmp->no_charge || otmp == uball || otmp == uchain) ? 0L :
+               get_cost(otmp, (struct monst *)0);
+       if (Has_contents(otmp))
+           cost += contained_cost(otmp, shkp, 0L, FALSE, FALSE);
+       if (!cost) {
+           Strcpy(price, "no charge");
+       } else {
+           Sprintf(price, "%ld %s%s", cost, currency(cost),
+                   otmp->quan > 1L ? " each" : "");
+       }
+       Sprintf(buf, "%s, %s", doname(otmp), price);
+       putstr(tmpwin, 0, buf),  cnt++;
+    }
+    if (cnt > 1) {
+       display_nhwindow(tmpwin, TRUE);
+    } else if (cnt == 1) {
+       if (first_obj->no_charge || first_obj == uball || first_obj == uchain){
+           pline("%s!", buf);  /* buf still contains the string */
+       } else {
+           /* print cost in slightly different format, so can't reuse buf */
+           cost = get_cost(first_obj, (struct monst *)0);
+           if (Has_contents(first_obj))
+               cost += contained_cost(first_obj, shkp, 0L, FALSE, FALSE);
+           pline("%s, price %ld %s%s%s", doname(first_obj),
+               cost, currency(cost), first_obj->quan > 1L ? " each" : "",
+               shk_embellish(first_obj, cost));
+       }
+    }
+    destroy_nhwindow(tmpwin);
+}
+#endif /*OVLB*/
+#ifdef OVL3
+
+STATIC_OVL const char *
+shk_embellish(itm, cost)
+register struct obj *itm;
+long cost;
+{
+    if (!rn2(3)) {
+       register int o, choice = rn2(5);
+       if (choice == 0) choice = (cost < 100L ? 1 : cost < 500L ? 2 : 3);
+       switch (choice) {
+           case 4:
+               if (cost < 10L) break; else o = itm->oclass;
+               if (o == FOOD_CLASS) return ", gourmets' delight!";
+               if (objects[itm->otyp].oc_name_known
+                   ? objects[itm->otyp].oc_magic
+                   : (o == AMULET_CLASS || o == RING_CLASS   ||
+                      o == WAND_CLASS   || o == POTION_CLASS ||
+                      o == SCROLL_CLASS || o == SPBOOK_CLASS))
+                   return ", painstakingly developed!";
+               return ", superb craftsmanship!";
+           case 3: return ", finest quality.";
+           case 2: return ", an excellent choice.";
+           case 1: return ", a real bargain.";
+          default: break;
+       }
+    } else if (itm->oartifact) {
+       return ", one of a kind!";
+    }
+    return ".";
+}
+#endif /*OVL3*/
+#ifdef OVLB
+
+/* First 4 supplied by Ronen and Tamar, remainder by development team */
+const char *Izchak_speaks[]={
+    "%s says: 'These shopping malls give me a headache.'",
+    "%s says: 'Slow down.  Think clearly.'",
+    "%s says: 'You need to take things one at a time.'",
+    "%s says: 'I don't like poofy coffee... give me Columbian Supremo.'",
+    "%s says that getting the devteam's agreement on anything is difficult.",
+    "%s says that he has noticed those who serve their deity will prosper.",
+    "%s says: 'Don't try to steal from me - I have friends in high places!'",
+    "%s says: 'You may well need something from this shop in the future.'",
+    "%s comments about the Valley of the Dead as being a gateway."
+};
+
+void
+shk_chat(shkp)
+struct monst *shkp;
+{
+       struct eshk *eshk;
+#ifdef GOLDOBJ
+       long shkmoney;
+#endif
+       if (!shkp->isshk) {
+               /* The monster type is shopkeeper, but this monster is
+                  not actually a shk, which could happen if someone
+                  wishes for a shopkeeper statue and then animates it.
+                  (Note: shkname() would be "" in a case like this.) */
+               pline("%s asks whether you've seen any untended shops recently.",
+                     Monnam(shkp));
+               /* [Perhaps we ought to check whether this conversation
+                  is taking place inside an untended shop, but a shopless
+                  shk can probably be expected to be rather disoriented.] */
+               return;
+       }
+
+       eshk = ESHK(shkp);
+       if (ANGRY(shkp))
+               pline("%s mentions how much %s dislikes %s customers.",
+                       shkname(shkp), mhe(shkp),
+                       eshk->robbed ? "non-paying" : "rude");
+       else if (eshk->following) {
+               if (strncmp(eshk->customer, plname, PL_NSIZ)) {
+                   verbalize("%s %s!  I was looking for %s.",
+                           Hello(shkp), plname, eshk->customer);
+                   eshk->following = 0;
+               } else {
+                   verbalize("%s %s!  Didn't you forget to pay?",
+                             Hello(shkp), plname);
+               }
+       } else if (eshk->billct) {
+               register long total = addupbill(shkp) + eshk->debit;
+               pline("%s says that your bill comes to %ld %s.",
+                     shkname(shkp), total, currency(total));
+       } else if (eshk->debit)
+               pline("%s reminds you that you owe %s %ld %s.",
+                     shkname(shkp), mhim(shkp),
+                     eshk->debit, currency(eshk->debit));
+       else if (eshk->credit)
+               pline("%s encourages you to use your %ld %s of credit.",
+                     shkname(shkp), eshk->credit, currency(eshk->credit));
+       else if (eshk->robbed)
+               pline("%s complains about a recent robbery.", shkname(shkp));
+#ifndef GOLDOBJ
+       else if (shkp->mgold < 50)
+#else
+       else if ((shkmoney = money_cnt(shkp->minvent)) < 50)
+#endif
+               pline("%s complains that business is bad.", shkname(shkp));
+#ifndef GOLDOBJ
+       else if (shkp->mgold > 4000)
+#else
+       else if (shkmoney > 4000)
+#endif
+               pline("%s says that business is good.", shkname(shkp));
+       else if (strcmp(shkname(shkp), "Izchak") == 0)
+               pline(Izchak_speaks[rn2(SIZE(Izchak_speaks))],shkname(shkp));
+       else
+               pline("%s talks about the problem of shoplifters.",shkname(shkp));
+}
+
+#ifdef KOPS
+STATIC_OVL void
+kops_gone(silent)
+register boolean silent;
+{
+       register int cnt = 0;
+       register struct monst *mtmp, *mtmp2;
+
+       for (mtmp = fmon; mtmp; mtmp = mtmp2) {
+           mtmp2 = mtmp->nmon;
+           if (mtmp->data->mlet == S_KOP) {
+               if (canspotmon(mtmp)) cnt++;
+               mongone(mtmp);
+           }
+       }
+       if (cnt && !silent)
+           pline_The("Kop%s (disappointed) vanish%s into thin air.",
+                     plur(cnt), cnt == 1 ? "es" : "");
+}
+#endif /* KOPS */
+
+#endif /*OVLB*/
+#ifdef OVL3
+
+STATIC_OVL long
+cost_per_charge(shkp, otmp, altusage)
+struct monst *shkp;
+struct obj *otmp;
+boolean altusage; /* some items have an "alternate" use with different cost */
+{
+       long tmp = 0L;
+
+       if(!shkp || !inhishop(shkp)) return(0L); /* insurance */
+       tmp = get_cost(otmp, shkp);
+
+       /* The idea is to make the exhaustive use of */
+       /* an unpaid item more expensive than buying */
+       /* it outright.                              */
+       if(otmp->otyp == MAGIC_LAMP) {                   /* 1 */
+               /* normal use (ie, as light source) of a magic lamp never
+                  degrades its value, but not charging anything would make
+                  identifcation too easy; charge an amount comparable to
+                  what is charged for an ordinary lamp (don't bother with
+                  angry shk surchage) */
+               if (!altusage) tmp = (long) objects[OIL_LAMP].oc_cost;
+               else tmp += tmp / 3L;   /* djinni is being released */
+       } else if(otmp->otyp == MAGIC_MARKER) {          /* 70 - 100 */
+               /* no way to determine in advance   */
+               /* how many charges will be wasted. */
+               /* so, arbitrarily, one half of the */
+               /* price per use.                   */
+               tmp /= 2L;
+       } else if(otmp->otyp == BAG_OF_TRICKS ||         /* 1 - 20 */
+                 otmp->otyp == HORN_OF_PLENTY) {
+               tmp /= 5L;
+       } else if(otmp->otyp == CRYSTAL_BALL ||          /* 1 - 5 */
+                 otmp->otyp == OIL_LAMP ||              /* 1 - 10 */
+                 otmp->otyp == BRASS_LANTERN ||
+                (otmp->otyp >= MAGIC_FLUTE &&
+                 otmp->otyp <= DRUM_OF_EARTHQUAKE) ||   /* 5 - 9 */
+                 otmp->oclass == WAND_CLASS) {          /* 3 - 11 */
+               if (otmp->spe > 1) tmp /= 4L;
+       } else if (otmp->oclass == SPBOOK_CLASS) {
+               tmp -= tmp / 5L;
+       } else if (otmp->otyp == CAN_OF_GREASE ||
+                  otmp->otyp == TINNING_KIT
+#ifdef TOURIST
+                  || otmp->otyp == EXPENSIVE_CAMERA
+#endif
+                  ) {
+               tmp /= 10L;
+       } else if (otmp->otyp == POT_OIL) {
+               tmp /= 5L;
+       }
+       return(tmp);
+}
+#endif /*OVL3*/
+#ifdef OVLB
+
+/* Charge the player for partial use of an unpaid object.
+ *
+ * Note that bill_dummy_object() should be used instead
+ * when an object is completely used.
+ */
+void
+check_unpaid_usage(otmp, altusage)
+struct obj *otmp;
+boolean altusage;
+{
+       struct monst *shkp;
+       const char *fmt, *arg1, *arg2;
+       long tmp;
+
+       if (!otmp->unpaid || !*u.ushops ||
+               (otmp->spe <= 0 && objects[otmp->otyp].oc_charged))
+           return;
+       if (!(shkp = shop_keeper(*u.ushops)) || !inhishop(shkp))
+           return;
+       if ((tmp = cost_per_charge(shkp, otmp, altusage)) == 0L)
+           return;
+
+       arg1 = arg2 = "";
+       if (otmp->oclass == SPBOOK_CLASS) {
+           fmt = "%sYou owe%s %ld %s.";
+           arg1 = rn2(2) ? "This is no free library, cad!  " : "";
+           arg2 = ESHK(shkp)->debit > 0L ? " an additional" : "";
+       } else if (otmp->otyp == POT_OIL) {
+           fmt = "%s%sThat will cost you %ld %s (Yendorian Fuel Tax).";
+       } else {
+           fmt = "%s%sUsage fee, %ld %s.";
+           if (!rn2(3)) arg1 = "Hey!  ";
+           if (!rn2(3)) arg2 = "Ahem.  ";
+       }
+
+       if (shkp->mcanmove || !shkp->msleeping)
+           verbalize(fmt, arg1, arg2, tmp, currency(tmp));
+       ESHK(shkp)->debit += tmp;
+       exercise(A_WIS, TRUE);          /* you just got info */
+}
+
+/* for using charges of unpaid objects "used in the normal manner" */
+void
+check_unpaid(otmp)
+struct obj *otmp;
+{
+       check_unpaid_usage(otmp, FALSE);                /* normal item use */
+}
+
+void
+costly_gold(x, y, amount)
+register xchar x, y;
+register long amount;
+{
+       register long delta;
+       register struct monst *shkp;
+       register struct eshk *eshkp;
+
+       if(!costly_spot(x, y)) return;
+       /* shkp now guaranteed to exist by costly_spot() */
+       shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
+
+       eshkp = ESHK(shkp);
+       if(eshkp->credit >= amount) {
+           if(eshkp->credit > amount)
+               Your("credit is reduced by %ld %s.",
+                                       amount, currency(amount));
+           else Your("credit is erased.");
+           eshkp->credit -= amount;
+       } else {
+           delta = amount - eshkp->credit;
+           if(eshkp->credit)
+               Your("credit is erased.");
+           if(eshkp->debit)
+               Your("debt increases by %ld %s.",
+                                       delta, currency(delta));
+           else You("owe %s %ld %s.",
+                               shkname(shkp), delta, currency(delta));
+           eshkp->debit += delta;
+           eshkp->loan += delta;
+           eshkp->credit = 0L;
+       }
+}
+
+/* used in domove to block diagonal shop-exit */
+/* x,y should always be a door */
+boolean
+block_door(x,y)
+register xchar x, y;
+{
+       register int roomno = *in_rooms(x, y, SHOPBASE);
+       register struct monst *shkp;
+
+       if(roomno < 0 || !IS_SHOP(roomno)) return(FALSE);
+       if(!IS_DOOR(levl[x][y].typ)) return(FALSE);
+       if(roomno != *u.ushops) return(FALSE);
+
+       if(!(shkp = shop_keeper((char)roomno)) || !inhishop(shkp))
+               return(FALSE);
+
+       if(shkp->mx == ESHK(shkp)->shk.x && shkp->my == ESHK(shkp)->shk.y
+           /* Actually, the shk should be made to block _any_
+            * door, including a door the player digs, if the
+            * shk is within a 'jumping' distance.
+            */
+           && ESHK(shkp)->shd.x == x && ESHK(shkp)->shd.y == y
+           && shkp->mcanmove && !shkp->msleeping
+           && (ESHK(shkp)->debit || ESHK(shkp)->billct ||
+               ESHK(shkp)->robbed)) {
+               pline("%s%s blocks your way!", shkname(shkp),
+                               Invis ? " senses your motion and" : "");
+               return(TRUE);
+       }
+       return(FALSE);
+}
+
+/* used in domove to block diagonal shop-entry */
+/* u.ux, u.uy should always be a door */
+boolean
+block_entry(x,y)
+register xchar x, y;
+{
+       register xchar sx, sy;
+       register int roomno;
+       register struct monst *shkp;
+
+       if(!(IS_DOOR(levl[u.ux][u.uy].typ) &&
+               levl[u.ux][u.uy].doormask == D_BROKEN)) return(FALSE);
+
+       roomno = *in_rooms(x, y, SHOPBASE);
+       if(roomno < 0 || !IS_SHOP(roomno)) return(FALSE);
+       if(!(shkp = shop_keeper((char)roomno)) || !inhishop(shkp))
+               return(FALSE);
+
+       if(ESHK(shkp)->shd.x != u.ux || ESHK(shkp)->shd.y != u.uy)
+               return(FALSE);
+
+       sx = ESHK(shkp)->shk.x;
+       sy = ESHK(shkp)->shk.y;
+
+       if(shkp->mx == sx && shkp->my == sy
+               && shkp->mcanmove && !shkp->msleeping
+               && (x == sx-1 || x == sx+1 || y == sy-1 || y == sy+1)
+               && (Invis || carrying(PICK_AXE) || carrying(DWARVISH_MATTOCK)
+#ifdef STEED
+                       || u.usteed
+#endif
+         )) {
+               pline("%s%s blocks your way!", shkname(shkp),
+                               Invis ? " senses your motion and" : "");
+               return(TRUE);
+       }
+       return(FALSE);
+}
+
+#endif /* OVLB */
+#ifdef OVL2
+
+char *
+shk_your(buf, obj)
+char *buf;
+struct obj *obj;
+{
+       if (!shk_owns(buf, obj) && !mon_owns(buf, obj))
+           Strcpy(buf, carried(obj) ? "your" : "the");
+       return buf;
+}
+
+char *
+Shk_Your(buf, obj)
+char *buf;
+struct obj *obj;
+{
+       (void) shk_your(buf, obj);
+       *buf = highc(*buf);
+       return buf;
+}
+
+STATIC_OVL char *
+shk_owns(buf, obj)
+char *buf;
+struct obj *obj;
+{
+       struct monst *shkp;
+       xchar x, y;
+
+       if (get_obj_location(obj, &x, &y, 0) &&
+           (obj->unpaid ||
+            (obj->where==OBJ_FLOOR && !obj->no_charge && costly_spot(x,y)))) {
+           shkp = shop_keeper(inside_shop(x, y));
+           return strcpy(buf, shkp ? s_suffix(shkname(shkp)) : "the");
+       }
+       return (char *)0;
+}
+
+STATIC_OVL char *
+mon_owns(buf, obj)
+char *buf;
+struct obj *obj;
+{
+       if (obj->where == OBJ_MINVENT)
+           return strcpy(buf, s_suffix(mon_nam(obj->ocarry)));
+       return (char *)0;
+}
+
+#endif /* OVL2 */
+#ifdef OVLB
+
+#ifdef __SASC
+void
+sasc_bug(struct obj *op, unsigned x){
+       op->unpaid=x;
+}
+#endif
+
+#endif /* OVLB */
+
+/*shk.c*/
diff --git a/src/shknam.c b/src/shknam.c
new file mode 100644 (file)
index 0000000..f029303
--- /dev/null
@@ -0,0 +1,530 @@
+/*     SCCS Id: @(#)shknam.c   3.4     2003/01/09      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* shknam.c -- initialize a shop */
+
+#include "hack.h"
+#include "eshk.h"
+
+#ifndef OVLB
+extern const struct shclass shtypes[];
+
+#else
+
+STATIC_DCL void FDECL(mkshobj_at, (const struct shclass *,int,int));
+STATIC_DCL void FDECL(nameshk, (struct monst *,const char * const *));
+STATIC_DCL int  FDECL(shkinit, (const struct shclass *,struct mkroom *));
+
+static const char * const shkliquors[] = {
+    /* Ukraine */
+    "Njezjin", "Tsjernigof", "Ossipewsk", "Gorlowka",
+    /* Belarus */
+    "Gomel",
+    /* N. Russia */
+    "Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja",
+    "Narodnaja", "Kyzyl",
+    /* Silezie */
+    "Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice",
+    "Brzeg", "Krnov", "Hradec Kralove",
+    /* Schweiz */
+    "Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm",
+    "Flims", "Vals", "Schuls", "Zum Loch",
+    0
+};
+
+static const char * const shkbooks[] = {
+    /* Eire */
+    "Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon", "Lahinch",
+    "Kinnegad", "Lugnaquillia", "Enniscorthy", "Gweebarra",
+    "Kittamagh", "Nenagh", "Sneem", "Ballingeary", "Kilgarvan",
+    "Cahersiveen", "Glenbeigh", "Kilmihil", "Kiltamagh",
+    "Droichead Atha", "Inniscrone", "Clonegal", "Lisnaskea",
+    "Culdaff", "Dunfanaghy", "Inishbofin", "Kesh",
+    0
+};
+
+static const char * const shkarmors[] = {
+    /* Turquie */
+    "Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep",
+    "Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak",
+    "Iskenderun", "Kadirli", "Siverek", "Pervari", "Malasgirt",
+    "Bayburt", "Ayancik", "Zonguldak", "Balya", "Tefenni",
+    "Artvin", "Kars", "Makharadze", "Malazgirt", "Midyat",
+    "Birecik", "Kirikkale", "Alaca", "Polatli", "Nallihan",
+    0
+};
+
+static const char * const shkwands[] = {
+    /* Wales */
+    "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach",
+    "Rhaeader", "Llandrindod", "Llanfair-ym-muallt",
+    "Y-Fenni", "Maesteg", "Rhydaman", "Beddgelert",
+    "Curig", "Llanrwst", "Llanerchymedd", "Caergybi",
+    /* Scotland */
+    "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar",
+    "Kerloch", "Beinn a Ghlo", "Drumnadrochit", "Morven",
+    "Uist", "Storr", "Sgurr na Ciche", "Cannich", "Gairloch",
+    "Kyleakin", "Dunvegan",
+    0
+};
+
+static const char * const shkrings[] = {
+    /* Hollandse familienamen */
+    "Feyfer", "Flugi", "Gheel", "Havic", "Haynin", "Hoboken",
+    "Imbyze", "Juyn", "Kinsky", "Massis", "Matray", "Moy",
+    "Olycan", "Sadelin", "Svaving", "Tapper", "Terwen", "Wirix",
+    "Ypey",
+    /* Skandinaviske navne */
+    "Rastegaisa", "Varjag Njarga", "Kautekeino", "Abisko",
+    "Enontekis", "Rovaniemi", "Avasaksa", "Haparanda",
+    "Lulea", "Gellivare", "Oeloe", "Kajaani", "Fauske",
+    0
+};
+
+static const char * const shkfoods[] = {
+    /* Indonesia */
+    "Djasinga", "Tjibarusa", "Tjiwidej", "Pengalengan",
+    "Bandjar", "Parbalingga", "Bojolali", "Sarangan",
+    "Ngebel", "Djombang", "Ardjawinangun", "Berbek",
+    "Papar", "Baliga", "Tjisolok", "Siboga", "Banjoewangi",
+    "Trenggalek", "Karangkobar", "Njalindoeng", "Pasawahan",
+    "Pameunpeuk", "Patjitan", "Kediri", "Pemboeang", "Tringanoe",
+    "Makin", "Tipor", "Semai", "Berhala", "Tegal", "Samoe",
+    0
+};
+
+static const char * const shkweapons[] = {
+    /* Perigord */
+    "Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard",
+    "Melac", "Neuvicq", "Vanzac", "Picq", "Urignac", "Corignac",
+    "Fleac", "Lonzac", "Vergt", "Queyssac", "Liorac", "Echourgnac",
+    "Cazelon", "Eypau", "Carignan", "Monbazillac", "Jonzac",
+    "Pons", "Jumilhac", "Fenouilledes", "Laguiolet", "Saujon",
+    "Eymoutiers", "Eygurande", "Eauze", "Labouheyre",
+    0
+};
+
+static const char * const shktools[] = {
+    /* Spmi */
+    "Ymla", "Eed-morra", "Cubask", "Nieb", "Bnowr Falr", "Telloc Cyaj",
+    "Sperc", "Noskcirdneh", "Yawolloh", "Hyeghu", "Niskal", "Trahnil",
+    "Htargcm", "Enrobwem", "Kachzi Rellim", "Regien", "Donmyar",
+    "Yelpur", "Nosnehpets", "Stewe", "Renrut", "_Zlaw", "Nosalnef",
+    "Rewuorb", "Rellenk", "Yad", "Cire Htims", "Y-crad", "Nenilukah",
+    "Corsh", "Aned",
+#ifdef OVERLAY
+    "Erreip", "Nehpets", "Mron", "Snivek", "Lapu", "Kahztiy",
+#endif
+#ifdef WIN32
+    "Lechaim", "Lexa", "Niod",
+#endif
+#ifdef MAC
+    "Nhoj-lee", "Evad\'kh", "Ettaw-noj", "Tsew-mot", "Ydna-s",
+    "Yao-hang", "Tonbar", "Kivenhoug",
+#endif
+#ifdef AMIGA
+    "Falo", "Nosid-da\'r", "Ekim-p", "Rebrol-nek", "Noslo", "Yl-rednow",
+    "Mured-oog", "Ivrajimsal",
+#endif
+#ifdef TOS
+    "Nivram",
+#endif
+#ifdef VMS
+    "Lez-tneg", "Ytnu-haled", "Niknar",
+#endif
+    0
+};
+
+static const char * const shklight[] = {
+    /* Romania */
+    "Zarnesti", "Slanic", "Nehoiasu", "Ludus", "Sighisoara", "Nisipitu",
+    "Razboieni", "Bicaz", "Dorohoi", "Vaslui", "Fetesti", "Tirgu Neamt",
+    "Babadag", "Zimnicea", "Zlatna", "Jiu", "Eforie", "Mamaia",
+    /* Bulgaria */
+    "Silistra", "Tulovo", "Panagyuritshte", "Smolyan", "Kirklareli",
+    "Pernik", "Lom", "Haskovo", "Dobrinishte", "Varvara", "Oryahovo",
+    "Troyan", "Lovech", "Sliven",
+    0
+};
+
+static const char * const shkgeneral[] = {
+    /* Suriname */
+    "Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi",
+    "Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo",
+    "Akalapi", "Sipaliwini",
+    /* Greenland */
+    "Annootok", "Upernavik", "Angmagssalik",
+    /* N. Canada */
+    "Aklavik", "Inuvik", "Tuktoyaktuk",
+    "Chicoutimi", "Ouiatchouane", "Chibougamau",
+    "Matagami", "Kipawa", "Kinojevis",
+    "Abitibi", "Maganasipi",
+    /* Iceland */
+    "Akureyri", "Kopasker", "Budereyri", "Akranes", "Bordeyri",
+    "Holmavik",
+    0
+};
+
+/*
+ * To add new shop types, all that is necessary is to edit the shtypes[] array.
+ * See mkroom.h for the structure definition.  Typically, you'll have to lower
+ * some or all of the probability fields in old entries to free up some
+ * percentage for the new type.
+ *
+ * The placement type field is not yet used but will be in the near future.
+ *
+ * The iprobs array in each entry defines the probabilities for various kinds
+ * of objects to be present in the given shop type.  You can associate with
+ * each percentage either a generic object type (represented by one of the
+ * *_CLASS macros) or a specific object (represented by an onames.h define).
+ * In the latter case, prepend it with a unary minus so the code can know
+ * (by testing the sign) whether to use mkobj() or mksobj().
+ */
+
+const struct shclass shtypes[] = {
+       {"general store", RANDOM_CLASS, 44,
+           D_SHOP, {{100, RANDOM_CLASS}, {0, 0}, {0, 0}}, shkgeneral},
+       {"used armor dealership", ARMOR_CLASS, 14,
+           D_SHOP, {{90, ARMOR_CLASS}, {10, WEAPON_CLASS}, {0, 0}},
+            shkarmors},
+       {"second-hand bookstore", SCROLL_CLASS, 10, D_SHOP,
+           {{90, SCROLL_CLASS}, {10, SPBOOK_CLASS}, {0, 0}}, shkbooks},
+       {"liquor emporium", POTION_CLASS, 10, D_SHOP,
+           {{100, POTION_CLASS}, {0, 0}, {0, 0}}, shkliquors},
+       {"antique weapons outlet", WEAPON_CLASS, 5, D_SHOP,
+           {{90, WEAPON_CLASS}, {10, ARMOR_CLASS}, {0, 0}}, shkweapons},
+       {"delicatessen", FOOD_CLASS, 5, D_SHOP,
+           {{83, FOOD_CLASS}, {5, -POT_FRUIT_JUICE}, {4, -POT_BOOZE},
+            {5, -POT_WATER}, {3, -ICE_BOX}}, shkfoods},
+       {"jewelers", RING_CLASS, 3, D_SHOP,
+           {{85, RING_CLASS}, {10, GEM_CLASS}, {5, AMULET_CLASS}, {0, 0}},
+           shkrings},
+       {"quality apparel and accessories", WAND_CLASS, 3, D_SHOP,
+           {{90, WAND_CLASS}, {5, -LEATHER_GLOVES}, {5, -ELVEN_CLOAK}, {0, 0}},
+            shkwands},
+       {"hardware store", TOOL_CLASS, 3, D_SHOP,
+           {{100, TOOL_CLASS}, {0, 0}, {0, 0}}, shktools},
+       /* Actually shktools is ignored; the code specifically chooses a
+        * random implementor name (along with candle shops having
+        * random shopkeepers)
+        */
+       {"rare books", SPBOOK_CLASS, 3, D_SHOP,
+           {{90, SPBOOK_CLASS}, {10, SCROLL_CLASS}, {0, 0}}, shkbooks},
+       /* Shops below this point are "unique".  That is they must all have a
+        * probability of zero.  They are only created via the special level
+        * loader.
+        */
+       {"lighting store", TOOL_CLASS, 0, D_SHOP,
+           {{32, -WAX_CANDLE}, {50, -TALLOW_CANDLE},
+            {5, -BRASS_LANTERN}, {10, -OIL_LAMP}, {3, -MAGIC_LAMP}}, shklight},
+       {(char *)0, 0, 0, 0, {{0, 0}, {0, 0}, {0, 0}}, 0}
+};
+
+#if 0
+/* validate shop probabilities; otherwise incorrect local changes could
+   end up provoking infinite loops or wild subscripts fetching garbage */
+void
+init_shop_selection()
+{
+       register int i, j, item_prob, shop_prob;
+
+       for (shop_prob = 0, i = 0; i < SIZE(shtypes); i++) {
+               shop_prob += shtypes[i].prob;
+               for (item_prob = 0, j = 0; j < SIZE(shtypes[0].iprobs); j++)
+                       item_prob += shtypes[i].iprobs[j].iprob;
+               if (item_prob != 100)
+                       panic("item probabilities total to %d for %s shops!",
+                               item_prob, shtypes[i].name);
+       }
+       if (shop_prob != 100)
+               panic("shop probabilities total to %d!", shop_prob);
+}
+#endif /*0*/
+
+STATIC_OVL void
+mkshobj_at(shp, sx, sy)
+/* make an object of the appropriate type for a shop square */
+const struct shclass *shp;
+int sx, sy;
+{
+       struct monst *mtmp;
+       int atype;
+       struct permonst *ptr;
+
+       if (rn2(100) < depth(&u.uz) &&
+               !MON_AT(sx, sy) && (ptr = mkclass(S_MIMIC,0)) &&
+               (mtmp = makemon(ptr,sx,sy,NO_MM_FLAGS)) != 0) {
+           /* note: makemon will set the mimic symbol to a shop item */
+           if (rn2(10) >= depth(&u.uz)) {
+               mtmp->m_ap_type = M_AP_OBJECT;
+               mtmp->mappearance = STRANGE_OBJECT;
+           }
+       } else {
+           atype = get_shop_item(shp - shtypes);
+           if (atype < 0)
+               (void) mksobj_at(-atype, sx, sy, TRUE, TRUE);
+           else
+               (void) mkobj_at(atype, sx, sy, TRUE);
+       }
+}
+
+/* extract a shopkeeper name for the given shop type */
+STATIC_OVL void
+nameshk(shk, nlp)
+struct monst *shk;
+const char * const *nlp;
+{
+       int i, trycnt, names_avail;
+       const char *shname = 0;
+       struct monst *mtmp;
+       int name_wanted;
+       s_level *sptr;
+
+       if (nlp == shklight && In_mines(&u.uz)
+               && (sptr = Is_special(&u.uz)) != 0 && sptr->flags.town) {
+           /* special-case minetown lighting shk */
+           shname = "Izchak";
+           shk->female = FALSE;
+       } else {
+           /* We want variation from game to game, without needing the save
+              and restore support which would be necessary for randomization;
+              try not to make too many assumptions about time_t's internals;
+              use ledger_no rather than depth to keep mine town distinct. */
+           int nseed = (int)((long)u.ubirthday / 257L);
+
+           name_wanted = ledger_no(&u.uz) + (nseed % 13) - (nseed % 5);
+           if (name_wanted < 0) name_wanted += (13 + 5);
+           shk->female = name_wanted & 1;
+
+           for (names_avail = 0; nlp[names_avail]; names_avail++)
+               continue;
+
+           for (trycnt = 0; trycnt < 50; trycnt++) {
+               if (nlp == shktools) {
+                   shname = shktools[rn2(names_avail)];
+                   shk->female = (*shname == '_');
+                   if (shk->female) shname++;
+               } else if (name_wanted < names_avail) {
+                   shname = nlp[name_wanted];
+               } else if ((i = rn2(names_avail)) != 0) {
+                   shname = nlp[i - 1];
+               } else if (nlp != shkgeneral) {
+                   nlp = shkgeneral;   /* try general names */
+                   for (names_avail = 0; nlp[names_avail]; names_avail++)
+                       continue;
+                   continue;           /* next `trycnt' iteration */
+               } else {
+                   shname = shk->female ? "Lucrezia" : "Dirk";
+               }
+
+               /* is name already in use on this level? */
+               for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+                   if (DEADMONSTER(mtmp) || (mtmp == shk) || !mtmp->isshk) continue;
+                   if (strcmp(ESHK(mtmp)->shknam, shname)) continue;
+                   break;
+               }
+               if (!mtmp) break;       /* new name */
+           }
+       }
+       (void) strncpy(ESHK(shk)->shknam, shname, PL_NSIZ);
+       ESHK(shk)->shknam[PL_NSIZ-1] = 0;
+}
+
+STATIC_OVL int
+shkinit(shp, sroom)    /* create a new shopkeeper in the given room */
+const struct shclass   *shp;
+struct mkroom  *sroom;
+{
+       register int sh, sx, sy;
+       struct monst *shk;
+
+       /* place the shopkeeper in the given room */
+       sh = sroom->fdoor;
+       sx = doors[sh].x;
+       sy = doors[sh].y;
+
+       /* check that the shopkeeper placement is sane */
+       if(sroom->irregular) {
+           int rmno = (sroom - rooms) + ROOMOFFSET;
+           if (isok(sx-1,sy) && !levl[sx-1][sy].edge &&
+               (int) levl[sx-1][sy].roomno == rmno) sx--;
+           else if (isok(sx+1,sy) && !levl[sx+1][sy].edge &&
+               (int) levl[sx+1][sy].roomno == rmno) sx++;
+           else if (isok(sx,sy-1) && !levl[sx][sy-1].edge &&
+               (int) levl[sx][sy-1].roomno == rmno) sy--;
+           else if (isok(sx,sy+1) && !levl[sx][sy+1].edge &&
+               (int) levl[sx][sy+1].roomno == rmno) sx++;
+           else goto shk_failed;
+       }
+       else if(sx == sroom->lx-1) sx++;
+       else if(sx == sroom->hx+1) sx--;
+       else if(sy == sroom->ly-1) sy++;
+       else if(sy == sroom->hy+1) sy--; else {
+       shk_failed:
+#ifdef DEBUG
+# ifdef WIZARD
+           /* Said to happen sometimes, but I have never seen it. */
+           /* Supposedly fixed by fdoor change in mklev.c */
+           if(wizard) {
+               register int j = sroom->doorct;
+
+               pline("Where is shopdoor?");
+               pline("Room at (%d,%d),(%d,%d).",
+                     sroom->lx, sroom->ly, sroom->hx, sroom->hy);
+               pline("doormax=%d doorct=%d fdoor=%d",
+                     doorindex, sroom->doorct, sh);
+               while(j--) {
+                   pline("door [%d,%d]", doors[sh].x, doors[sh].y);
+                   sh++;
+               }
+               display_nhwindow(WIN_MESSAGE, FALSE);
+           }
+# endif
+#endif
+           return(-1);
+       }
+
+       if(MON_AT(sx, sy)) (void) rloc(m_at(sx, sy), FALSE); /* insurance */
+
+       /* now initialize the shopkeeper monster structure */
+       if(!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, NO_MM_FLAGS)))
+               return(-1);
+       shk->isshk = shk->mpeaceful = 1;
+       set_malign(shk);
+       shk->msleeping = 0;
+       shk->mtrapseen = ~0;    /* we know all the traps already */
+       ESHK(shk)->shoproom = (sroom - rooms) + ROOMOFFSET;
+       sroom->resident = shk;
+       ESHK(shk)->shoptype = sroom->rtype;
+       assign_level(&(ESHK(shk)->shoplevel), &u.uz);
+       ESHK(shk)->shd = doors[sh];
+       ESHK(shk)->shk.x = sx;
+       ESHK(shk)->shk.y = sy;
+       ESHK(shk)->robbed = 0L;
+       ESHK(shk)->credit = 0L;
+       ESHK(shk)->debit = 0L;
+       ESHK(shk)->loan = 0L;
+       ESHK(shk)->visitct = 0;
+       ESHK(shk)->following = 0;
+       ESHK(shk)->billct = 0;
+#ifndef GOLDOBJ
+       shk->mgold = 1000L + 30L*(long)rnd(100);        /* initial capital */
+#else
+        mkmonmoney(shk, 1000L + 30L*(long)rnd(100));   /* initial capital */
+#endif
+       if (shp->shknms == shkrings)
+           (void) mongets(shk, TOUCHSTONE);
+       nameshk(shk, shp->shknms);
+
+       return(sh);
+}
+
+/* stock a newly-created room with objects */
+void
+stock_room(shp_indx, sroom)
+int shp_indx;
+register struct mkroom *sroom;
+{
+    /*
+     * Someday soon we'll dispatch on the shdist field of shclass to do
+     * different placements in this routine. Currently it only supports
+     * shop-style placement (all squares except a row nearest the first
+     * door get objects).
+     */
+    register int sx, sy, sh;
+    char buf[BUFSZ];
+    int rmno = (sroom - rooms) + ROOMOFFSET;
+    const struct shclass *shp = &shtypes[shp_indx];
+
+    /* first, try to place a shopkeeper in the room */
+    if ((sh = shkinit(shp, sroom)) < 0)
+       return;
+
+    /* make sure no doorways without doors, and no */
+    /* trapped doors, in shops.                           */
+    sx = doors[sroom->fdoor].x;
+    sy = doors[sroom->fdoor].y;
+
+    if(levl[sx][sy].doormask == D_NODOOR) {
+           levl[sx][sy].doormask = D_ISOPEN;
+           newsym(sx,sy);
+    }
+    if(levl[sx][sy].typ == SDOOR) {
+           cvt_sdoor_to_door(&levl[sx][sy]);   /* .typ = DOOR */
+           newsym(sx,sy);
+    }
+    if(levl[sx][sy].doormask & D_TRAPPED)
+           levl[sx][sy].doormask = D_LOCKED;
+
+    if(levl[sx][sy].doormask == D_LOCKED) {
+           register int m = sx, n = sy;
+
+           if(inside_shop(sx+1,sy)) m--;
+           else if(inside_shop(sx-1,sy)) m++;
+           if(inside_shop(sx,sy+1)) n--;
+           else if(inside_shop(sx,sy-1)) n++;
+           Sprintf(buf, "Closed for inventory");
+           make_engr_at(m, n, buf, 0L, DUST);
+    }
+
+    for(sx = sroom->lx; sx <= sroom->hx; sx++)
+       for(sy = sroom->ly; sy <= sroom->hy; sy++) {
+           if(sroom->irregular) {
+               if (levl[sx][sy].edge || (int) levl[sx][sy].roomno != rmno ||
+                  distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)
+                   continue;
+           } else if((sx == sroom->lx && doors[sh].x == sx-1) ||
+                     (sx == sroom->hx && doors[sh].x == sx+1) ||
+                     (sy == sroom->ly && doors[sh].y == sy-1) ||
+                     (sy == sroom->hy && doors[sh].y == sy+1)) continue;
+           mkshobj_at(shp, sx, sy);
+       }
+
+    /*
+     * Special monster placements (if any) should go here: that way,
+     * monsters will sit on top of objects and not the other way around.
+     */
+
+    level.flags.has_shop = TRUE;
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+/* does shkp's shop stock this item type? */
+boolean
+saleable(shkp, obj)
+struct monst *shkp;
+struct obj *obj;
+{
+    int i, shp_indx = ESHK(shkp)->shoptype - SHOPBASE;
+    const struct shclass *shp = &shtypes[shp_indx];
+
+    if (shp->symb == RANDOM_CLASS) return TRUE;
+    else for (i = 0; i < SIZE(shtypes[0].iprobs) && shp->iprobs[i].iprob; i++)
+               if (shp->iprobs[i].itype < 0 ?
+                       shp->iprobs[i].itype == - obj->otyp :
+                       shp->iprobs[i].itype == obj->oclass) return TRUE;
+    /* not found */
+    return FALSE;
+}
+
+/* positive value: class; negative value: specific object type */
+int
+get_shop_item(type)
+int type;
+{
+       const struct shclass *shp = shtypes+type;
+       register int i,j;
+
+       /* select an appropriate object type at random */
+       for(j = rnd(100), i = 0; (j -= shp->iprobs[i].iprob) > 0; i++)
+               continue;
+
+       return shp->iprobs[i].itype;
+}
+
+#endif /* OVL0 */
+
+/*shknam.c*/
diff --git a/src/sit.c b/src/sit.c
new file mode 100644 (file)
index 0000000..2d2df2b
--- /dev/null
+++ b/src/sit.c
@@ -0,0 +1,451 @@
+/*     SCCS Id: @(#)sit.c      3.4     2002/09/21      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "artifact.h"
+
+void
+take_gold()
+{
+#ifndef GOLDOBJ
+       if (u.ugold <= 0)  {
+               You_feel("a strange sensation.");
+       } else {
+               You("notice you have no gold!");
+               u.ugold = 0;
+               flags.botl = 1;
+       }
+#else
+        struct obj *otmp, *nobj;
+       int lost_money = 0;
+       for (otmp = invent; otmp; otmp = nobj) {
+               nobj = otmp->nobj;
+               if (otmp->oclass == COIN_CLASS) {
+                       lost_money = 1;
+                       delobj(otmp);
+               }
+       }
+       if (!lost_money)  {
+               You_feel("a strange sensation.");
+       } else {
+               You("notice you have no money!");
+               flags.botl = 1;
+       }
+#endif
+}
+
+int
+dosit()
+{
+       static const char sit_message[] = "sit on the %s.";
+       register struct trap *trap;
+       register int typ = levl[u.ux][u.uy].typ;
+
+
+#ifdef STEED
+       if (u.usteed) {
+           You("are already sitting on %s.", mon_nam(u.usteed));
+           return (0);
+       }
+#endif
+
+       if(!can_reach_floor())  {
+           if (Levitation)
+               You("tumble in place.");
+           else
+               You("are sitting on air.");
+           return 0;
+       } else if (is_pool(u.ux, u.uy) && !Underwater) {  /* water walking */
+           goto in_water;
+       }
+
+       if(OBJ_AT(u.ux, u.uy)) {
+           register struct obj *obj;
+
+           obj = level.objects[u.ux][u.uy];
+           You("sit on %s.", the(xname(obj)));
+           if (!(Is_box(obj) || objects[obj->otyp].oc_material == CLOTH))
+               pline("It's not very comfortable...");
+
+       } else if ((trap = t_at(u.ux, u.uy)) != 0 ||
+                  (u.utrap && (u.utraptype >= TT_LAVA))) {
+
+           if (u.utrap) {
+               exercise(A_WIS, FALSE); /* you're getting stuck longer */
+               if(u.utraptype == TT_BEARTRAP) {
+                   You_cant("sit down with your %s in the bear trap.", body_part(FOOT));
+                   u.utrap++;
+               } else if(u.utraptype == TT_PIT) {
+                   if(trap->ttyp == SPIKED_PIT) {
+                       You("sit down on a spike.  Ouch!");
+                       losehp(1, "sitting on an iron spike", KILLED_BY);
+                       exercise(A_STR, FALSE);
+                   } else
+                       You("sit down in the pit.");
+                   u.utrap += rn2(5);
+               } else if(u.utraptype == TT_WEB) {
+                   You("sit in the spider web and get entangled further!");
+                   u.utrap += rn1(10, 5);
+               } else if(u.utraptype == TT_LAVA) {
+                   /* Must have fire resistance or they'd be dead already */
+                   You("sit in the lava!");
+                   u.utrap += rnd(4);
+                   losehp(d(2,10), "sitting in lava", KILLED_BY);
+               } else if(u.utraptype == TT_INFLOOR) {
+                   You_cant("maneuver to sit!");
+                   u.utrap++;
+               }
+           } else {
+               You("sit down.");
+               dotrap(trap, 0);
+           }
+       } else if(Underwater || Is_waterlevel(&u.uz)) {
+           if (Is_waterlevel(&u.uz))
+               There("are no cushions floating nearby.");
+           else
+               You("sit down on the muddy bottom.");
+       } else if(is_pool(u.ux, u.uy)) {
+ in_water:
+           You("sit in the water.");
+           if (!rn2(10) && uarm)
+               (void) rust_dmg(uarm, "armor", 1, TRUE, &youmonst);
+           if (!rn2(10) && uarmf && uarmf->otyp != WATER_WALKING_BOOTS)
+               (void) rust_dmg(uarm, "armor", 1, TRUE, &youmonst);
+#ifdef SINKS
+       } else if(IS_SINK(typ)) {
+
+           You(sit_message, defsyms[S_sink].explanation);
+           Your("%s gets wet.", humanoid(youmonst.data) ? "rump" : "underside");
+#endif
+       } else if(IS_ALTAR(typ)) {
+
+           You(sit_message, defsyms[S_altar].explanation);
+           altar_wrath(u.ux, u.uy);
+
+       } else if(IS_GRAVE(typ)) {
+
+           You(sit_message, defsyms[S_grave].explanation);
+
+       } else if(typ == STAIRS) {
+
+           You(sit_message, "stairs");
+
+       } else if(typ == LADDER) {
+
+           You(sit_message, "ladder");
+
+       } else if (is_lava(u.ux, u.uy)) {
+
+           /* must be WWalking */
+           You(sit_message, "lava");
+           burn_away_slime();
+           if (likes_lava(youmonst.data)) {
+               pline_The("lava feels warm.");
+               return 1;
+           }
+           pline_The("lava burns you!");
+           losehp(d((Fire_resistance ? 2 : 10), 10),
+                  "sitting on lava", KILLED_BY);
+
+       } else if (is_ice(u.ux, u.uy)) {
+
+           You(sit_message, defsyms[S_ice].explanation);
+           if (!Cold_resistance) pline_The("ice feels cold.");
+
+       } else if (typ == DRAWBRIDGE_DOWN) {
+
+           You(sit_message, "drawbridge");
+
+       } else if(IS_THRONE(typ)) {
+
+           You(sit_message, defsyms[S_throne].explanation);
+           if (rnd(6) > 4)  {
+               switch (rnd(13))  {
+                   case 1:
+                       (void) adjattrib(rn2(A_MAX), -rn1(4,3), FALSE);
+                       losehp(rnd(10), "cursed throne", KILLED_BY_AN);
+                       break;
+                   case 2:
+                       (void) adjattrib(rn2(A_MAX), 1, FALSE);
+                       break;
+                   case 3:
+                       pline("A%s electric shock shoots through your body!",
+                             (Shock_resistance) ? "n" : " massive");
+                       losehp(Shock_resistance ? rnd(6) : rnd(30),
+                              "electric chair", KILLED_BY_AN);
+                       exercise(A_CON, FALSE);
+                       break;
+                   case 4:
+                       You_feel("much, much better!");
+                       if (Upolyd) {
+                           if (u.mh >= (u.mhmax - 5))  u.mhmax += 4;
+                           u.mh = u.mhmax;
+                       }
+                       if(u.uhp >= (u.uhpmax - 5))  u.uhpmax += 4;
+                       u.uhp = u.uhpmax;
+                       make_blinded(0L,TRUE);
+                       make_sick(0L, (char *) 0, FALSE, SICK_ALL);
+                       heal_legs();
+                       flags.botl = 1;
+                       break;
+                   case 5:
+                       take_gold();
+                       break;
+                   case 6:
+                       if(u.uluck + rn2(5) < 0) {
+                           You_feel("your luck is changing.");
+                           change_luck(1);
+                       } else      makewish();
+                       break;
+                   case 7:
+                       {
+                       register int cnt = rnd(10);
+
+                       pline("A voice echoes:");
+                       verbalize("Thy audience hath been summoned, %s!",
+                                 flags.female ? "Dame" : "Sire");
+                       while(cnt--)
+                           (void) makemon(courtmon(), u.ux, u.uy, NO_MM_FLAGS);
+                       break;
+                       }
+                   case 8:
+                       pline("A voice echoes:");
+                       verbalize("By thy Imperious order, %s...",
+                                 flags.female ? "Dame" : "Sire");
+                       do_genocide(5); /* REALLY|ONTHRONE, see do_genocide() */
+                       break;
+                   case 9:
+                       pline("A voice echoes:");
+       verbalize("A curse upon thee for sitting upon this most holy throne!");
+                       if (Luck > 0)  {
+                           make_blinded(Blinded + rn1(100,250),TRUE);
+                       } else      rndcurse();
+                       break;
+                   case 10:
+                       if (Luck < 0 || (HSee_invisible & INTRINSIC))  {
+                               if (level.flags.nommap) {
+                                       pline(
+                                       "A terrible drone fills your head!");
+                                       make_confused(HConfusion + rnd(30),
+                                                                       FALSE);
+                               } else {
+                                       pline("An image forms in your mind.");
+                                       do_mapping();
+                               }
+                       } else  {
+                               Your("vision becomes clear.");
+                               HSee_invisible |= FROMOUTSIDE;
+                               newsym(u.ux, u.uy);
+                       }
+                       break;
+                   case 11:
+                       if (Luck < 0)  {
+                           You_feel("threatened.");
+                           aggravate();
+                       } else  {
+
+                           You_feel("a wrenching sensation.");
+                           tele();             /* teleport him */
+                       }
+                       break;
+                   case 12:
+                       You("are granted an insight!");
+                       if (invent) {
+                           /* rn2(5) agrees w/seffects() */
+                           identify_pack(rn2(5));
+                       }
+                       break;
+                   case 13:
+                       Your("mind turns into a pretzel!");
+                       make_confused(HConfusion + rn1(7,16),FALSE);
+                       break;
+                   default:    impossible("throne effect");
+                               break;
+               }
+           } else {
+               if (is_prince(youmonst.data))
+                   You_feel("very comfortable here.");
+               else
+                   You_feel("somehow out of place...");
+           }
+
+           if (!rn2(3) && IS_THRONE(levl[u.ux][u.uy].typ)) {
+               /* may have teleported */
+               levl[u.ux][u.uy].typ = ROOM;
+               pline_The("throne vanishes in a puff of logic.");
+               newsym(u.ux,u.uy);
+           }
+
+       } else if (lays_eggs(youmonst.data)) {
+               struct obj *uegg;
+
+               if (!flags.female) {
+                       pline("Males can't lay eggs!");
+                       return 0;
+               }
+
+               if (u.uhunger < (int)objects[EGG].oc_nutrition) {
+                       You("don't have enough energy to lay an egg.");
+                       return 0;
+               }
+
+               uegg = mksobj(EGG, FALSE, FALSE);
+               uegg->spe = 1;
+               uegg->quan = 1;
+               uegg->owt = weight(uegg);
+               uegg->corpsenm = egg_type_from_parent(u.umonnum, FALSE);
+               uegg->known = uegg->dknown = 1;
+               attach_egg_hatch_timeout(uegg);
+               You("lay an egg.");
+               dropy(uegg);
+               stackobj(uegg);
+               morehungry((int)objects[EGG].oc_nutrition);
+       } else if (u.uswallow)
+               There("are no seats in here!");
+       else
+               pline("Having fun sitting on the %s?", surface(u.ux,u.uy));
+       return(1);
+}
+
+void
+rndcurse()                     /* curse a few inventory items at random! */
+{
+       int     nobj = 0;
+       int     cnt, onum;
+       struct  obj     *otmp;
+       static const char mal_aura[] = "feel a malignant aura surround %s.";
+
+       if (uwep && (uwep->oartifact == ART_MAGICBANE) && rn2(20)) {
+           You(mal_aura, "the magic-absorbing blade");
+           return;
+       }
+
+       if(Antimagic) {
+           shieldeff(u.ux, u.uy);
+           You(mal_aura, "you");
+       }
+
+       for (otmp = invent; otmp; otmp = otmp->nobj) {
+#ifdef GOLDOBJ
+           /* gold isn't subject to being cursed or blessed */
+           if (otmp->oclass == COIN_CLASS) continue;
+#endif
+           nobj++;
+       }
+       if (nobj) {
+           for (cnt = rnd(6/((!!Antimagic) + (!!Half_spell_damage) + 1));
+                cnt > 0; cnt--)  {
+               onum = rnd(nobj);
+               for (otmp = invent; otmp; otmp = otmp->nobj) {
+#ifdef GOLDOBJ
+                   /* as above */
+                   if (otmp->oclass == COIN_CLASS) continue;
+#endif
+                   if (--onum == 0) break;     /* found the target */
+               }
+               /* the !otmp case should never happen; picking an already
+                  cursed item happens--avoid "resists" message in that case */
+               if (!otmp || otmp->cursed) continue;    /* next target */
+
+               if(otmp->oartifact && spec_ability(otmp, SPFX_INTEL) &&
+                  rn2(10) < 8) {
+                   pline("%s!", Tobjnam(otmp, "resist"));
+                   continue;
+               }
+
+               if(otmp->blessed)
+                       unbless(otmp);
+               else
+                       curse(otmp);
+           }
+           update_inventory();
+       }
+
+#ifdef STEED
+       /* treat steed's saddle as extended part of hero's inventory */
+       if (u.usteed && !rn2(4) &&
+               (otmp = which_armor(u.usteed, W_SADDLE)) != 0 &&
+               !otmp->cursed) {        /* skip if already cursed */
+           if (otmp->blessed)
+               unbless(otmp);
+           else
+               curse(otmp);
+           if (!Blind) {
+               pline("%s %s %s.",
+                     s_suffix(upstart(y_monnam(u.usteed))),
+                     aobjnam(otmp, "glow"),
+                     hcolor(otmp->cursed ? NH_BLACK : (const char *)"brown"));
+               otmp->bknown = TRUE;
+           }
+       }
+#endif /*STEED*/
+}
+
+void
+attrcurse()                    /* remove a random INTRINSIC ability */
+{
+       switch(rnd(11)) {
+       case 1 : if (HFire_resistance & INTRINSIC) {
+                       HFire_resistance &= ~INTRINSIC;
+                       You_feel("warmer.");
+                       break;
+               }
+       case 2 : if (HTeleportation & INTRINSIC) {
+                       HTeleportation &= ~INTRINSIC;
+                       You_feel("less jumpy.");
+                       break;
+               }
+       case 3 : if (HPoison_resistance & INTRINSIC) {
+                       HPoison_resistance &= ~INTRINSIC;
+                       You_feel("a little sick!");
+                       break;
+               }
+       case 4 : if (HTelepat & INTRINSIC) {
+                       HTelepat &= ~INTRINSIC;
+                       if (Blind && !Blind_telepat)
+                           see_monsters();     /* Can't sense mons anymore! */
+                       Your("senses fail!");
+                       break;
+               }
+       case 5 : if (HCold_resistance & INTRINSIC) {
+                       HCold_resistance &= ~INTRINSIC;
+                       You_feel("cooler.");
+                       break;
+               }
+       case 6 : if (HInvis & INTRINSIC) {
+                       HInvis &= ~INTRINSIC;
+                       You_feel("paranoid.");
+                       break;
+               }
+       case 7 : if (HSee_invisible & INTRINSIC) {
+                       HSee_invisible &= ~INTRINSIC;
+                       You("%s!", Hallucination ? "tawt you taw a puttie tat"
+                                               : "thought you saw something");
+                       break;
+               }
+       case 8 : if (HFast & INTRINSIC) {
+                       HFast &= ~INTRINSIC;
+                       You_feel("slower.");
+                       break;
+               }
+       case 9 : if (HStealth & INTRINSIC) {
+                       HStealth &= ~INTRINSIC;
+                       You_feel("clumsy.");
+                       break;
+               }
+       case 10: if (HProtection & INTRINSIC) {
+                       HProtection &= ~INTRINSIC;
+                       You_feel("vulnerable.");
+                       break;
+               }
+       case 11: if (HAggravate_monster & INTRINSIC) {
+                       HAggravate_monster &= ~INTRINSIC;
+                       You_feel("less attractive.");
+                       break;
+               }
+       default: break;
+       }
+}
+
+/*sit.c*/
diff --git a/src/sounds.c b/src/sounds.c
new file mode 100644 (file)
index 0000000..ebd51aa
--- /dev/null
@@ -0,0 +1,1033 @@
+/*     SCCS Id: @(#)sounds.c   3.4     2002/05/06      */
+/*     Copyright (c) 1989 Janet Walz, Mike Threepoint */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "edog.h"
+#ifdef USER_SOUNDS
+# ifdef USER_SOUNDS_REGEX
+#include <regex.h>
+# endif
+#endif
+
+#ifdef OVLB
+
+static int FDECL(domonnoise,(struct monst *));
+static int NDECL(dochat);
+
+#endif /* OVLB */
+
+#ifdef OVL0
+
+static int FDECL(mon_in_room, (struct monst *,int));
+
+/* this easily could be a macro, but it might overtax dumb compilers */
+static int
+mon_in_room(mon, rmtyp)
+struct monst *mon;
+int rmtyp;
+{
+    int rno = levl[mon->mx][mon->my].roomno;
+
+    return rooms[rno - ROOMOFFSET].rtype == rmtyp;
+}
+
+void
+dosounds()
+{
+    register struct mkroom *sroom;
+    register int hallu, vx, vy;
+#if defined(AMIGA) && defined(AZTEC_C_WORKAROUND)
+    int xx;
+#endif
+    struct monst *mtmp;
+
+    if (!flags.soundok || u.uswallow || Underwater) return;
+
+    hallu = Hallucination ? 1 : 0;
+
+    if (level.flags.nfountains && !rn2(400)) {
+       static const char * const fountain_msg[4] = {
+               "bubbling water.",
+               "water falling on coins.",
+               "the splashing of a naiad.",
+               "a soda fountain!",
+       };
+       You_hear(fountain_msg[rn2(3)+hallu]);
+    }
+#ifdef SINK
+    if (level.flags.nsinks && !rn2(300)) {
+       static const char * const sink_msg[3] = {
+               "a slow drip.",
+               "a gurgling noise.",
+               "dishes being washed!",
+       };
+       You_hear(sink_msg[rn2(2)+hallu]);
+    }
+#endif
+    if (level.flags.has_court && !rn2(200)) {
+       static const char * const throne_msg[4] = {
+               "the tones of courtly conversation.",
+               "a sceptre pounded in judgment.",
+               "Someone shouts \"Off with %s head!\"",
+               "Queen Beruthiel's cats!",
+       };
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+           if (DEADMONSTER(mtmp)) continue;
+           if ((mtmp->msleeping ||
+                       is_lord(mtmp->data) || is_prince(mtmp->data)) &&
+               !is_animal(mtmp->data) &&
+               mon_in_room(mtmp, COURT)) {
+               /* finding one is enough, at least for now */
+               int which = rn2(3)+hallu;
+
+               if (which != 2) You_hear(throne_msg[which]);
+               else            pline(throne_msg[2], uhis());
+               return;
+           }
+       }
+    }
+    if (level.flags.has_swamp && !rn2(200)) {
+       static const char * const swamp_msg[3] = {
+               "hear mosquitoes!",
+               "smell marsh gas!",     /* so it's a smell...*/
+               "hear Donald Duck!",
+       };
+       You(swamp_msg[rn2(2)+hallu]);
+       return;
+    }
+    if (level.flags.has_vault && !rn2(200)) {
+       if (!(sroom = search_special(VAULT))) {
+           /* strange ... */
+           level.flags.has_vault = 0;
+           return;
+       }
+       if(gd_sound())
+           switch (rn2(2)+hallu) {
+               case 1: {
+                   boolean gold_in_vault = FALSE;
+
+                   for (vx = sroom->lx;vx <= sroom->hx; vx++)
+                       for (vy = sroom->ly; vy <= sroom->hy; vy++)
+                           if (g_at(vx, vy))
+                               gold_in_vault = TRUE;
+#if defined(AMIGA) && defined(AZTEC_C_WORKAROUND)
+                   /* Bug in aztec assembler here. Workaround below */
+                   xx = ROOM_INDEX(sroom) + ROOMOFFSET;
+                   xx = (xx != vault_occupied(u.urooms));
+                   if(xx)
+#else
+                   if (vault_occupied(u.urooms) !=
+                        (ROOM_INDEX(sroom) + ROOMOFFSET))
+#endif /* AZTEC_C_WORKAROUND */
+                   {
+                       if (gold_in_vault)
+                           You_hear(!hallu ? "someone counting money." :
+                               "the quarterback calling the play.");
+                       else
+                           You_hear("someone searching.");
+                       break;
+                   }
+                   /* fall into... (yes, even for hallucination) */
+               }
+               case 0:
+                   You_hear("the footsteps of a guard on patrol.");
+                   break;
+               case 2:
+                   You_hear("Ebenezer Scrooge!");
+                   break;
+           }
+       return;
+    }
+    if (level.flags.has_beehive && !rn2(200)) {
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+           if (DEADMONSTER(mtmp)) continue;
+           if ((mtmp->data->mlet == S_ANT && is_flyer(mtmp->data)) &&
+               mon_in_room(mtmp, BEEHIVE)) {
+               switch (rn2(2)+hallu) {
+                   case 0:
+                       You_hear("a low buzzing.");
+                       break;
+                   case 1:
+                       You_hear("an angry drone.");
+                       break;
+                   case 2:
+                       You_hear("bees in your %sbonnet!",
+                           uarmh ? "" : "(nonexistent) ");
+                       break;
+               }
+               return;
+           }
+       }
+    }
+    if (level.flags.has_morgue && !rn2(200)) {
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+           if (DEADMONSTER(mtmp)) continue;
+           if (is_undead(mtmp->data) &&
+               mon_in_room(mtmp, MORGUE)) {
+               switch (rn2(2)+hallu) {
+                   case 0:
+                       You("suddenly realize it is unnaturally quiet.");
+                       break;
+                   case 1:
+                       pline_The("%s on the back of your %s stands up.",
+                               body_part(HAIR), body_part(NECK));
+                       break;
+                   case 2:
+                       pline_The("%s on your %s seems to stand up.",
+                               body_part(HAIR), body_part(HEAD));
+                       break;
+               }
+               return;
+           }
+       }
+    }
+    if (level.flags.has_barracks && !rn2(200)) {
+       static const char * const barracks_msg[4] = {
+               "blades being honed.",
+               "loud snoring.",
+               "dice being thrown.",
+               "General MacArthur!",
+       };
+       int count = 0;
+
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+           if (DEADMONSTER(mtmp)) continue;
+           if (is_mercenary(mtmp->data) &&
+#if 0          /* don't bother excluding these */
+               !strstri(mtmp->data->mname, "watch") &&
+               !strstri(mtmp->data->mname, "guard") &&
+#endif
+               mon_in_room(mtmp, BARRACKS) &&
+               /* sleeping implies not-yet-disturbed (usually) */
+               (mtmp->msleeping || ++count > 5)) {
+               You_hear(barracks_msg[rn2(3)+hallu]);
+               return;
+           }
+       }
+    }
+    if (level.flags.has_zoo && !rn2(200)) {
+       static const char * const zoo_msg[3] = {
+               "a sound reminiscent of an elephant stepping on a peanut.",
+               "a sound reminiscent of a seal barking.",
+               "Doctor Doolittle!",
+       };
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+           if (DEADMONSTER(mtmp)) continue;
+           if ((mtmp->msleeping || is_animal(mtmp->data)) &&
+                   mon_in_room(mtmp, ZOO)) {
+               You_hear(zoo_msg[rn2(2)+hallu]);
+               return;
+           }
+       }
+    }
+    if (level.flags.has_shop && !rn2(200)) {
+       if (!(sroom = search_special(ANY_SHOP))) {
+           /* strange... */
+           level.flags.has_shop = 0;
+           return;
+       }
+       if (tended_shop(sroom) &&
+               !index(u.ushops, ROOM_INDEX(sroom) + ROOMOFFSET)) {
+           static const char * const shop_msg[3] = {
+                   "someone cursing shoplifters.",
+                   "the chime of a cash register.",
+                   "Neiman and Marcus arguing!",
+           };
+           You_hear(shop_msg[rn2(2)+hallu]);
+       }
+       return;
+    }
+    if (Is_oracle_level(&u.uz) && !rn2(400)) {
+       /* make sure the Oracle is still here */
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+           if (!DEADMONSTER(mtmp) && mtmp->data == &mons[PM_ORACLE])
+               break;
+       /* and don't produce silly effects when she's clearly visible */
+       if (mtmp && (hallu || !canseemon(mtmp))) {
+           static const char * const ora_msg[5] = {
+                   "a strange wind.",          /* Jupiter at Dodona */
+                   "convulsive ravings.",      /* Apollo at Delphi */
+                   "snoring snakes.",          /* AEsculapius at Epidaurus */
+                   "someone say \"No more woodchucks!\"",
+                   "a loud ZOT!"               /* both rec.humor.oracle */
+           };
+           You_hear(ora_msg[rn2(3)+hallu*2]);
+       }
+       return;
+    }
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+static const char * const h_sounds[] = {
+    "beep", "boing", "sing", "belche", "creak", "cough", "rattle",
+    "ululate", "pop", "jingle", "sniffle", "tinkle", "eep"
+};
+
+const char *
+growl_sound(mtmp)
+register struct monst *mtmp;
+{
+       const char *ret;
+
+       switch (mtmp->data->msound) {
+       case MS_MEW:
+       case MS_HISS:
+           ret = "hiss";
+           break;
+       case MS_BARK:
+       case MS_GROWL:
+           ret = "growl";
+           break;
+       case MS_ROAR:
+           ret = "roar";
+           break;
+       case MS_BUZZ:
+           ret = "buzz";
+           break;
+       case MS_SQEEK:
+           ret = "squeal";
+           break;
+       case MS_SQAWK:
+           ret = "screech";
+           break;
+       case MS_NEIGH:
+           ret = "neigh";
+           break;
+       case MS_WAIL:
+           ret = "wail";
+           break;
+       case MS_SILENT:
+               ret = "commotion";
+               break;
+       default:
+               ret = "scream";
+       }
+       return ret;
+}
+
+/* the sounds of a seriously abused pet, including player attacking it */
+void
+growl(mtmp)
+register struct monst *mtmp;
+{
+    register const char *growl_verb = 0;
+
+    if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound)
+       return;
+
+    /* presumably nearness and soundok checks have already been made */
+    if (Hallucination)
+       growl_verb = h_sounds[rn2(SIZE(h_sounds))];
+    else
+       growl_verb = growl_sound(mtmp);
+    if (growl_verb) {
+       pline("%s %s!", Monnam(mtmp), vtense((char *)0, growl_verb));
+       if(flags.run) nomul(0);
+       wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 18);
+    }
+}
+
+/* the sounds of mistreated pets */
+void
+yelp(mtmp)
+register struct monst *mtmp;
+{
+    register const char *yelp_verb = 0;
+
+    if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound)
+       return;
+
+    /* presumably nearness and soundok checks have already been made */
+    if (Hallucination)
+       yelp_verb = h_sounds[rn2(SIZE(h_sounds))];
+    else switch (mtmp->data->msound) {
+       case MS_MEW:
+           yelp_verb = "yowl";
+           break;
+       case MS_BARK:
+       case MS_GROWL:
+           yelp_verb = "yelp";
+           break;
+       case MS_ROAR:
+           yelp_verb = "snarl";
+           break;
+       case MS_SQEEK:
+           yelp_verb = "squeal";
+           break;
+       case MS_SQAWK:
+           yelp_verb = "screak";
+           break;
+       case MS_WAIL:
+           yelp_verb = "wail";
+           break;
+    }
+    if (yelp_verb) {
+       pline("%s %s!", Monnam(mtmp), vtense((char *)0, yelp_verb));
+       if(flags.run) nomul(0);
+       wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 12);
+    }
+}
+
+/* the sounds of distressed pets */
+void
+whimper(mtmp)
+register struct monst *mtmp;
+{
+    register const char *whimper_verb = 0;
+
+    if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound)
+       return;
+
+    /* presumably nearness and soundok checks have already been made */
+    if (Hallucination)
+       whimper_verb = h_sounds[rn2(SIZE(h_sounds))];
+    else switch (mtmp->data->msound) {
+       case MS_MEW:
+       case MS_GROWL:
+           whimper_verb = "whimper";
+           break;
+       case MS_BARK:
+           whimper_verb = "whine";
+           break;
+       case MS_SQEEK:
+           whimper_verb = "squeal";
+           break;
+    }
+    if (whimper_verb) {
+       pline("%s %s.", Monnam(mtmp), vtense((char *)0, whimper_verb));
+       if(flags.run) nomul(0);
+       wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 6);
+    }
+}
+
+/* pet makes "I'm hungry" noises */
+void
+beg(mtmp)
+register struct monst *mtmp;
+{
+    if (mtmp->msleeping || !mtmp->mcanmove ||
+           !(carnivorous(mtmp->data) || herbivorous(mtmp->data)))
+       return;
+
+    /* presumably nearness and soundok checks have already been made */
+    if (!is_silent(mtmp->data) && mtmp->data->msound <= MS_ANIMAL)
+       (void) domonnoise(mtmp);
+    else if (mtmp->data->msound >= MS_HUMANOID) {
+       if (!canspotmon(mtmp))
+           map_invisible(mtmp->mx, mtmp->my);
+       verbalize("I'm hungry.");
+    }
+}
+
+static int
+domonnoise(mtmp)
+register struct monst *mtmp;
+{
+    register const char *pline_msg = 0,        /* Monnam(mtmp) will be prepended */
+                       *verbl_msg = 0; /* verbalize() */
+    struct permonst *ptr = mtmp->data;
+    char verbuf[BUFSZ];
+
+    /* presumably nearness and sleep checks have already been made */
+    if (!flags.soundok) return(0);
+    if (is_silent(ptr)) return(0);
+
+    /* Make sure its your role's quest quardian; adjust if not */
+    if (ptr->msound == MS_GUARDIAN && ptr != &mons[urole.guardnum]) {
+       int mndx = monsndx(ptr);
+       ptr = &mons[genus(mndx,1)];
+    }
+
+    /* be sure to do this before talking; the monster might teleport away, in
+     * which case we want to check its pre-teleport position
+     */
+    if (!canspotmon(mtmp))
+       map_invisible(mtmp->mx, mtmp->my);
+
+    switch (ptr->msound) {
+       case MS_ORACLE:
+           return doconsult(mtmp);
+       case MS_PRIEST:
+           priest_talk(mtmp);
+           break;
+       case MS_LEADER:
+       case MS_NEMESIS:
+       case MS_GUARDIAN:
+           quest_chat(mtmp);
+           break;
+       case MS_SELL: /* pitch, pay, total */
+           shk_chat(mtmp);
+           break;
+       case MS_VAMPIRE:
+           {
+           /* vampire messages are varied by tameness, peacefulness, and time of night */
+               boolean isnight = night();
+               boolean kindred =    (Upolyd && (u.umonnum == PM_VAMPIRE ||
+                                      u.umonnum == PM_VAMPIRE_LORD));
+               boolean nightchild = (Upolyd && (u.umonnum == PM_WOLF ||
+                                      u.umonnum == PM_WINTER_WOLF ||
+                                      u.umonnum == PM_WINTER_WOLF_CUB));
+               const char *racenoun = (flags.female && urace.individual.f) ?
+                                       urace.individual.f : (urace.individual.m) ?
+                                       urace.individual.m : urace.noun;
+
+               if (mtmp->mtame) {
+                       if (kindred) {
+                               Sprintf(verbuf, "Good %s to you Master%s",
+                                       isnight ? "evening" : "day",
+                                       isnight ? "!" : ".  Why do we not rest?");
+                               verbl_msg = verbuf;
+                       } else {
+                           Sprintf(verbuf,"%s%s",
+                               nightchild ? "Child of the night, " : "",
+                               midnight() ?
+                                       "I can stand this craving no longer!" :
+                               isnight ?
+                                       "I beg you, help me satisfy this growing craving!" :
+                                       "I find myself growing a little weary.");
+                               verbl_msg = verbuf;
+                       }
+               } else if (mtmp->mpeaceful) {
+                       if (kindred && isnight) {
+                               Sprintf(verbuf, "Good feeding %s!",
+                                       flags.female ? "sister" : "brother");
+                               verbl_msg = verbuf;
+                       } else if (nightchild && isnight) {
+                               Sprintf(verbuf,
+                                   "How nice to hear you, child of the night!");
+                               verbl_msg = verbuf;
+                       } else
+                               verbl_msg = "I only drink... potions.";
+               } else {
+                       int vampindex;
+                       static const char * const vampmsg[] = {
+                              /* These first two (0 and 1) are specially handled below */
+                               "I vant to suck your %s!",
+                               "I vill come after %s without regret!",
+                              /* other famous vampire quotes can follow here if desired */
+                       };
+                       if (kindred)
+                           verbl_msg = "This is my hunting ground that you dare to prowl!";
+                       else if (youmonst.data == &mons[PM_SILVER_DRAGON] ||
+                                youmonst.data == &mons[PM_BABY_SILVER_DRAGON]) {
+                           /* Silver dragons are silver in color, not made of silver */
+                           Sprintf(verbuf, "%s! Your silver sheen does not frighten me!",
+                                       youmonst.data == &mons[PM_SILVER_DRAGON] ?
+                                       "Fool" : "Young Fool");
+                           verbl_msg = verbuf; 
+                       } else {
+                           vampindex = rn2(SIZE(vampmsg));
+                           if (vampindex == 0) {
+                               Sprintf(verbuf, vampmsg[vampindex], body_part(BLOOD));
+                               verbl_msg = verbuf;
+                           } else if (vampindex == 1) {
+                               Sprintf(verbuf, vampmsg[vampindex],
+                                       Upolyd ? an(mons[u.umonnum].mname) : an(racenoun));
+                               verbl_msg = verbuf;
+                           } else
+                               verbl_msg = vampmsg[vampindex];
+                       }
+               }
+           }
+           break;
+       case MS_WERE:
+           if (flags.moonphase == FULL_MOON && (night() ^ !rn2(13))) {
+               pline("%s throws back %s head and lets out a blood curdling %s!",
+                     Monnam(mtmp), mhis(mtmp),
+                     ptr == &mons[PM_HUMAN_WERERAT] ? "shriek" : "howl");
+               wake_nearto(mtmp->mx, mtmp->my, 11*11);
+           } else
+               pline_msg =
+                    "whispers inaudibly.  All you can make out is \"moon\".";
+           break;
+       case MS_BARK:
+           if (flags.moonphase == FULL_MOON && night()) {
+               pline_msg = "howls.";
+           } else if (mtmp->mpeaceful) {
+               if (mtmp->mtame &&
+                       (mtmp->mconf || mtmp->mflee || mtmp->mtrapped ||
+                        moves > EDOG(mtmp)->hungrytime || mtmp->mtame < 5))
+                   pline_msg = "whines.";
+               else if (mtmp->mtame && EDOG(mtmp)->hungrytime > moves + 1000)
+                   pline_msg = "yips.";
+               else {
+                   if (mtmp->data != &mons[PM_DINGO])  /* dingos do not actually bark */
+                           pline_msg = "barks.";
+               }
+           } else {
+               pline_msg = "growls.";
+           }
+           break;
+       case MS_MEW:
+           if (mtmp->mtame) {
+               if (mtmp->mconf || mtmp->mflee || mtmp->mtrapped ||
+                       mtmp->mtame < 5)
+                   pline_msg = "yowls.";
+               else if (moves > EDOG(mtmp)->hungrytime)
+                   pline_msg = "meows.";
+               else if (EDOG(mtmp)->hungrytime > moves + 1000)
+                   pline_msg = "purrs.";
+               else
+                   pline_msg = "mews.";
+               break;
+           } /* else FALLTHRU */
+       case MS_GROWL:
+           pline_msg = mtmp->mpeaceful ? "snarls." : "growls!";
+           break;
+       case MS_ROAR:
+           pline_msg = mtmp->mpeaceful ? "snarls." : "roars!";
+           break;
+       case MS_SQEEK:
+           pline_msg = "squeaks.";
+           break;
+       case MS_SQAWK:
+           if (ptr == &mons[PM_RAVEN] && !mtmp->mpeaceful)
+               verbl_msg = "Nevermore!";
+           else
+               pline_msg = "squawks.";
+           break;
+       case MS_HISS:
+           if (!mtmp->mpeaceful)
+               pline_msg = "hisses!";
+           else return 0;      /* no sound */
+           break;
+       case MS_BUZZ:
+           pline_msg = mtmp->mpeaceful ? "drones." : "buzzes angrily.";
+           break;
+       case MS_GRUNT:
+           pline_msg = "grunts.";
+           break;
+       case MS_NEIGH:
+           if (mtmp->mtame < 5)
+               pline_msg = "neighs.";
+           else if (moves > EDOG(mtmp)->hungrytime)
+               pline_msg = "whinnies.";
+           else
+               pline_msg = "whickers.";
+           break;
+       case MS_WAIL:
+           pline_msg = "wails mournfully.";
+           break;
+       case MS_GURGLE:
+           pline_msg = "gurgles.";
+           break;
+       case MS_BURBLE:
+           pline_msg = "burbles.";
+           break;
+       case MS_SHRIEK:
+           pline_msg = "shrieks.";
+           aggravate();
+           break;
+       case MS_IMITATE:
+           pline_msg = "imitates you.";
+           break;
+       case MS_BONES:
+           pline("%s rattles noisily.", Monnam(mtmp));
+           You("freeze for a moment.");
+           nomul(-2);
+           break;
+       case MS_LAUGH:
+           {
+               static const char * const laugh_msg[4] = {
+                   "giggles.", "chuckles.", "snickers.", "laughs.",
+               };
+               pline_msg = laugh_msg[rn2(4)];
+           }
+           break;
+       case MS_MUMBLE:
+           pline_msg = "mumbles incomprehensibly.";
+           break;
+       case MS_DJINNI:
+           if (mtmp->mtame) {
+               verbl_msg = "Sorry, I'm all out of wishes.";
+           } else if (mtmp->mpeaceful) {
+               if (ptr == &mons[PM_WATER_DEMON])
+                   pline_msg = "gurgles.";
+               else
+                   verbl_msg = "I'm free!";
+           } else verbl_msg = "This will teach you not to disturb me!";
+           break;
+       case MS_BOAST:  /* giants */
+           if (!mtmp->mpeaceful) {
+               switch (rn2(4)) {
+               case 0: pline("%s boasts about %s gem collection.",
+                             Monnam(mtmp), mhis(mtmp));
+                       break;
+               case 1: pline_msg = "complains about a diet of mutton.";
+                       break;
+              default: pline_msg = "shouts \"Fee Fie Foe Foo!\" and guffaws.";
+                       wake_nearto(mtmp->mx, mtmp->my, 7*7);
+                       break;
+               }
+               break;
+           }
+           /* else FALLTHRU */
+       case MS_HUMANOID:
+           if (!mtmp->mpeaceful) {
+               if (In_endgame(&u.uz) && is_mplayer(ptr)) {
+                   mplayer_talk(mtmp);
+                   break;
+               } else return 0;        /* no sound */
+           }
+           /* Generic peaceful humanoid behaviour. */
+           if (mtmp->mflee)
+               pline_msg = "wants nothing to do with you.";
+           else if (mtmp->mhp < mtmp->mhpmax/4)
+               pline_msg = "moans.";
+           else if (mtmp->mconf || mtmp->mstun)
+               verbl_msg = !rn2(3) ? "Huh?" : rn2(2) ? "What?" : "Eh?";
+           else if (!mtmp->mcansee)
+               verbl_msg = "I can't see!";
+           else if (mtmp->mtrapped) {
+               struct trap *t = t_at(mtmp->mx, mtmp->my);
+
+               if (t) t->tseen = 1;
+               verbl_msg = "I'm trapped!";
+           } else if (mtmp->mhp < mtmp->mhpmax/2)
+               pline_msg = "asks for a potion of healing.";
+           else if (mtmp->mtame && !mtmp->isminion &&
+                                               moves > EDOG(mtmp)->hungrytime)
+               verbl_msg = "I'm hungry.";
+           /* Specific monsters' interests */
+           else if (is_elf(ptr))
+               pline_msg = "curses orcs.";
+           else if (is_dwarf(ptr))
+               pline_msg = "talks about mining.";
+           else if (likes_magic(ptr))
+               pline_msg = "talks about spellcraft.";
+           else if (ptr->mlet == S_CENTAUR)
+               pline_msg = "discusses hunting.";
+           else switch (monsndx(ptr)) {
+               case PM_HOBBIT:
+                   pline_msg = (mtmp->mhpmax - mtmp->mhp >= 10) ?
+                               "complains about unpleasant dungeon conditions."
+                               : "asks you about the One Ring.";
+                   break;
+               case PM_ARCHEOLOGIST:
+    pline_msg = "describes a recent article in \"Spelunker Today\" magazine.";
+                   break;
+#ifdef TOURIST
+               case PM_TOURIST:
+                   verbl_msg = "Aloha.";
+                   break;
+#endif
+               default:
+                   pline_msg = "discusses dungeon exploration.";
+                   break;
+           }
+           break;
+       case MS_SEDUCE:
+#ifdef SEDUCE
+           if (ptr->mlet != S_NYMPH &&
+               could_seduce(mtmp, &youmonst, (struct attack *)0) == 1) {
+                       (void) doseduce(mtmp);
+                       break;
+           }
+           switch ((poly_gender() != (int) mtmp->female) ? rn2(3) : 0)
+#else
+           switch ((poly_gender() == 0) ? rn2(3) : 0)
+#endif
+           {
+               case 2:
+                       verbl_msg = "Hello, sailor.";
+                       break;
+               case 1:
+                       pline_msg = "comes on to you.";
+                       break;
+               default:
+                       pline_msg = "cajoles you.";
+           }
+           break;
+#ifdef KOPS
+       case MS_ARREST:
+           if (mtmp->mpeaceful)
+               verbalize("Just the facts, %s.",
+                     flags.female ? "Ma'am" : "Sir");
+           else {
+               static const char * const arrest_msg[3] = {
+                   "Anything you say can be used against you.",
+                   "You're under arrest!",
+                   "Stop in the name of the Law!",
+               };
+               verbl_msg = arrest_msg[rn2(3)];
+           }
+           break;
+#endif
+       case MS_BRIBE:
+           if (mtmp->mpeaceful && !mtmp->mtame) {
+               (void) demon_talk(mtmp);
+               break;
+           }
+           /* fall through */
+       case MS_CUSS:
+           if (!mtmp->mpeaceful)
+               cuss(mtmp);
+           break;
+       case MS_SPELL:
+           /* deliberately vague, since it's not actually casting any spell */
+           pline_msg = "seems to mutter a cantrip.";
+           break;
+       case MS_NURSE:
+           if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)))
+               verbl_msg = "Put that weapon away before you hurt someone!";
+           else if (uarmc || uarm || uarmh || uarms || uarmg || uarmf)
+               verbl_msg = Role_if(PM_HEALER) ?
+                         "Doc, I can't help you unless you cooperate." :
+                         "Please undress so I can examine you.";
+#ifdef TOURIST
+           else if (uarmu)
+               verbl_msg = "Take off your shirt, please.";
+#endif
+           else verbl_msg = "Relax, this won't hurt a bit.";
+           break;
+       case MS_GUARD:
+#ifndef GOLDOBJ
+           if (u.ugold)
+#else
+           if (money_cnt(invent))
+#endif
+               verbl_msg = "Please drop that gold and follow me.";
+           else
+               verbl_msg = "Please follow me.";
+           break;
+       case MS_SOLDIER:
+           {
+               static const char * const soldier_foe_msg[3] = {
+                   "Resistance is useless!",
+                   "You're dog meat!",
+                   "Surrender!",
+               },                * const soldier_pax_msg[3] = {
+                   "What lousy pay we're getting here!",
+                   "The food's not fit for Orcs!",
+                   "My feet hurt, I've been on them all day!",
+               };
+               verbl_msg = mtmp->mpeaceful ? soldier_pax_msg[rn2(3)]
+                                           : soldier_foe_msg[rn2(3)];
+           }
+           break;
+       case MS_RIDER:
+           if (ptr == &mons[PM_DEATH] && !rn2(10))
+               pline_msg = "is busy reading a copy of Sandman #8.";
+           else verbl_msg = "Who do you think you are, War?";
+           break;
+    }
+
+    if (pline_msg) pline("%s %s", Monnam(mtmp), pline_msg);
+    else if (verbl_msg) verbalize(verbl_msg);
+    return(1);
+}
+
+
+int
+dotalk()
+{
+    int result;
+    boolean save_soundok = flags.soundok;
+    flags.soundok = 1; /* always allow sounds while chatting */
+    result = dochat();
+    flags.soundok = save_soundok;
+    return result;
+}
+
+static int
+dochat()
+{
+    register struct monst *mtmp;
+    register int tx,ty;
+    struct obj *otmp;
+
+    if (is_silent(youmonst.data)) {
+       pline("As %s, you cannot speak.", an(youmonst.data->mname));
+       return(0);
+    }
+    if (Strangled) {
+       You_cant("speak.  You're choking!");
+       return(0);
+    }
+    if (u.uswallow) {
+       pline("They won't hear you out there.");
+       return(0);
+    }
+    if (Underwater) {
+       Your("speech is unintelligible underwater.");
+       return(0);
+    }
+
+    if (!Blind && (otmp = shop_object(u.ux, u.uy)) != (struct obj *)0) {
+       /* standing on something in a shop and chatting causes the shopkeeper
+          to describe the price(s).  This can inhibit other chatting inside
+          a shop, but that shouldn't matter much.  shop_object() returns an
+          object iff inside a shop and the shopkeeper is present and willing
+          (not angry) and able (not asleep) to speak and the position contains
+          any objects other than just gold.
+       */
+       price_quote(otmp);
+       return(1);
+    }
+
+    if (!getdir("Talk to whom? (in what direction)")) {
+       /* decided not to chat */
+       return(0);
+    }
+
+#ifdef STEED
+    if (u.usteed && u.dz > 0)
+       return (domonnoise(u.usteed));
+#endif
+    if (u.dz) {
+       pline("They won't hear you %s there.", u.dz < 0 ? "up" : "down");
+       return(0);
+    }
+
+    if (u.dx == 0 && u.dy == 0) {
+/*
+ * Let's not include this.  It raises all sorts of questions: can you wear
+ * 2 helmets, 2 amulets, 3 pairs of gloves or 6 rings as a marilith,
+ * etc...  --KAA
+       if (u.umonnum == PM_ETTIN) {
+           You("discover that your other head makes boring conversation.");
+           return(1);
+       }
+*/
+       pline("Talking to yourself is a bad habit for a dungeoneer.");
+       return(0);
+    }
+
+    tx = u.ux+u.dx; ty = u.uy+u.dy;
+    mtmp = m_at(tx, ty);
+
+    if (!mtmp || mtmp->mundetected ||
+               mtmp->m_ap_type == M_AP_FURNITURE ||
+               mtmp->m_ap_type == M_AP_OBJECT)
+       return(0);
+
+    /* sleeping monsters won't talk, except priests (who wake up) */
+    if ((!mtmp->mcanmove || mtmp->msleeping) && !mtmp->ispriest) {
+       /* If it is unseen, the player can't tell the difference between
+          not noticing him and just not existing, so skip the message. */
+       if (canspotmon(mtmp))
+           pline("%s seems not to notice you.", Monnam(mtmp));
+       return(0);
+    }
+
+    /* if this monster is waiting for something, prod it into action */
+    mtmp->mstrategy &= ~STRAT_WAITMASK;
+
+    if (mtmp->mtame && mtmp->meating) {
+       if (!canspotmon(mtmp))
+           map_invisible(mtmp->mx, mtmp->my);
+       pline("%s is eating noisily.", Monnam(mtmp));
+       return (0);
+    }
+
+    return domonnoise(mtmp);
+}
+
+#ifdef USER_SOUNDS
+
+extern void FDECL(play_usersound, (const char*, int));
+
+typedef struct audio_mapping_rec {
+#ifdef USER_SOUNDS_REGEX
+       struct re_pattern_buffer regex;
+#else
+       char *pattern;
+#endif
+       char *filename;
+       int volume;
+       struct audio_mapping_rec *next;
+} audio_mapping;
+
+static audio_mapping *soundmap = 0;
+
+char* sounddir = ".";
+
+/* adds a sound file mapping, returns 0 on failure, 1 on success */
+int
+add_sound_mapping(mapping)
+const char *mapping;
+{
+       char text[256];
+       char filename[256];
+       char filespec[256];
+       int volume;
+
+       if (sscanf(mapping, "MESG \"%255[^\"]\"%*[\t ]\"%255[^\"]\" %d",
+                  text, filename, &volume) == 3) {
+           const char *err;
+           audio_mapping *new_map;
+
+           if (strlen(sounddir) + strlen(filename) > 254) {
+               raw_print("sound file name too long");
+               return 0;
+           }
+           Sprintf(filespec, "%s/%s", sounddir, filename);
+
+           if (can_read_file(filespec)) {
+               new_map = (audio_mapping *)alloc(sizeof(audio_mapping));
+#ifdef USER_SOUNDS_REGEX
+               new_map->regex.translate = 0;
+               new_map->regex.fastmap = 0;
+               new_map->regex.buffer = 0;
+               new_map->regex.allocated = 0;
+               new_map->regex.regs_allocated = REGS_FIXED;
+#else
+               new_map->pattern = (char *)alloc(strlen(text) + 1);
+               Strcpy(new_map->pattern, text);
+#endif
+               new_map->filename = strdup(filespec);
+               new_map->volume = volume;
+               new_map->next = soundmap;
+
+#ifdef USER_SOUNDS_REGEX
+               err = re_compile_pattern(text, strlen(text), &new_map->regex);
+#else
+               err = 0;
+#endif
+               if (err) {
+                   raw_print(err);
+                   free(new_map->filename);
+                   free(new_map);
+                   return 0;
+               } else {
+                   soundmap = new_map;
+               }
+           } else {
+               Sprintf(text, "cannot read %.243s", filespec);
+               raw_print(text);
+               return 0;
+           }
+       } else {
+           raw_print("syntax error in SOUND");
+           return 0;
+       }
+
+       return 1;
+}
+
+void
+play_sound_for_message(msg)
+const char* msg;
+{
+       audio_mapping* cursor = soundmap;
+
+       while (cursor) {
+#ifdef USER_SOUNDS_REGEX
+           if (re_search(&cursor->regex, msg, strlen(msg), 0, 9999, 0) >= 0) {
+#else
+           if (pmatch(cursor->pattern, msg)) {
+#endif
+               play_usersound(cursor->filename, cursor->volume);
+           }
+           cursor = cursor->next;
+       }
+}
+
+#endif /* USER_SOUNDS */
+
+#endif /* OVLB */
+
+/*sounds.c*/
diff --git a/src/sp_lev.c b/src/sp_lev.c
new file mode 100644 (file)
index 0000000..435609f
--- /dev/null
@@ -0,0 +1,2663 @@
+/*     SCCS Id: @(#)sp_lev.c   3.4     2001/09/06      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * 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"
+/* #define DEBUG */    /* uncomment to enable code debugging */
+
+#ifdef DEBUG
+# ifdef WIZARD
+#define debugpline     if (wizard) pline
+# else
+#define debugpline     pline
+# endif
+#endif
+
+#include "sp_lev.h"
+#include "rect.h"
+
+extern void FDECL(mkmap, (lev_init *));
+
+STATIC_DCL void FDECL(get_room_loc, (schar *, schar *, struct mkroom *));
+STATIC_DCL void FDECL(get_free_room_loc, (schar *, schar *, struct mkroom *));
+STATIC_DCL void FDECL(create_trap, (trap *, struct mkroom *));
+STATIC_DCL int FDECL(noncoalignment, (ALIGNTYP_P));
+STATIC_DCL void FDECL(create_monster, (monster *, struct mkroom *));
+STATIC_DCL void FDECL(create_object, (object *, struct mkroom *));
+STATIC_DCL void FDECL(create_engraving, (engraving *,struct mkroom *));
+STATIC_DCL void FDECL(create_stairs, (stair *, struct mkroom *));
+STATIC_DCL void FDECL(create_altar, (altar *, struct mkroom *));
+STATIC_DCL void FDECL(create_gold, (gold *, struct mkroom *));
+STATIC_DCL void FDECL(create_feature, (int,int,struct mkroom *,int));
+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 boolean FDECL(create_subroom, (struct mkroom *, XCHAR_P, XCHAR_P,
+                                       XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P));
+
+#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))
+
+static NEARDATA walk walklist[50];
+extern int min_rx, max_rx, min_ry, max_ry; /* from mkmap.c */
+
+static char Map[COLNO][ROWNO];
+static char robjects[10], rloc_x[10], rloc_y[10], rmonst[10];
+static aligntyp        ralign[3] = { AM_CHAOTIC, AM_NEUTRAL, AM_LAWFUL };
+static NEARDATA xchar xstart, ystart;
+static NEARDATA char xsize, ysize;
+
+STATIC_DCL void FDECL(set_wall_property, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,int));
+STATIC_DCL int NDECL(rnddoor);
+STATIC_DCL int NDECL(rndtrap);
+STATIC_DCL void FDECL(get_location, (schar *,schar *,int));
+STATIC_DCL void FDECL(sp_lev_shuffle, (char *,char *,int));
+STATIC_DCL void FDECL(light_region, (region *));
+STATIC_DCL void FDECL(load_common_data, (dlb *,int));
+STATIC_DCL void FDECL(load_one_monster, (dlb *,monster *));
+STATIC_DCL void FDECL(load_one_object, (dlb *,object *));
+STATIC_DCL void FDECL(load_one_engraving, (dlb *,engraving *));
+STATIC_DCL boolean FDECL(load_rooms, (dlb *));
+STATIC_DCL void FDECL(maze1xy, (coord *,int));
+STATIC_DCL boolean FDECL(load_maze, (dlb *));
+STATIC_DCL void FDECL(create_door, (room_door *, struct mkroom *));
+STATIC_DCL void FDECL(free_rooms,(room **, int));
+STATIC_DCL void FDECL(build_room, (room *, room*));
+
+char *lev_message = 0;
+lev_region *lregions = 0;
+int num_lregions = 0;
+lev_init init_lev;
+
+/*
+ * 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 = y1; y <= y2; y++)
+           for(x = x1; x <= x2; x++)
+               if(IS_STWALL(levl[x][y].typ))
+                   levl[x][y].wall_info |= prop;
+}
+
+/*
+ * 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;
+}
+
+/*
+ * 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 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;
+}
+
+/*
+ * Coordinates in special level files are handled specially:
+ *
+ *     if x or y is -11, we generate a random coordinate.
+ *     if x or y is between -1 and -10, we read one from the corresponding
+ *     register (x0, x1, ... x9).
+ *     if x or y is nonnegative, we convert it from relative to the local map
+ *     to global coordinates.
+ *     The "humidity" flag is used to insure that engravings aren't
+ *     created underwater, or eels on dry land.
+ */
+#define DRY    0x1
+#define WET    0x2
+
+STATIC_DCL boolean FDECL(is_ok_location, (SCHAR_P, SCHAR_P, int));
+
+STATIC_OVL void
+get_location(x, y, humidity)
+schar *x, *y;
+int humidity;
+{
+       int cpt = 0;
+
+       if (*x >= 0) {                  /* normal locations */
+               *x += xstart;
+               *y += ystart;
+       } else if (*x > -11) {          /* special locations */
+               *y = ystart + rloc_y[ - *y - 1];
+               *x = xstart + rloc_x[ - *x - 1];
+       } else {                        /* random location */
+           do {
+               *x = xstart + rn2((int)xsize);
+               *y = ystart + rn2((int)ysize);
+               if (is_ok_location(*x,*y,humidity)) break;
+           } while (++cpt < 100);
+           if (cpt >= 100) {
+               register int xx, yy;
+               /* last try */
+               for (xx = 0; xx < xsize; xx++)
+                   for (yy = 0; yy < ysize; yy++) {
+                       *x = xstart + xx;
+                       *y = ystart + yy;
+                       if (is_ok_location(*x,*y,humidity)) goto found_it;
+                   }
+               panic("get_location:  can't find a place!");
+           }
+       }
+found_it:;
+
+       if (!isok(*x,*y)) {
+           impossible("get_location:  (%d,%d) out of bounds", *x, *y);
+           *x = x_maze_max; *y = y_maze_max;
+       }
+}
+
+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 */
+
+       if (humidity & DRY) {
+           typ = levl[x][y].typ;
+           if (typ == ROOM || typ == AIR ||
+                   typ == CLOUD || typ == ICE || typ == CORR)
+               return TRUE;
+       }
+       if (humidity & WET) {
+           if (is_pool(x,y) || is_lava(x,y))
+               return TRUE;
+       }
+       return FALSE;
+}
+
+/*
+ * Shuffle the registers for locations, objects or monsters
+ */
+
+STATIC_OVL void
+sp_lev_shuffle(list1, list2, n)
+char list1[], list2[];
+int n;
+{
+       register int i, j;
+       register char k;
+
+       for (i = n - 1; i > 0; i--) {
+               if ((j = rn2(i + 1)) == i) continue;
+               k = list1[j];
+               list1[j] = list1[i];
+               list1[i] = k;
+               if (list2) {
+                       k = list2[j];
+                       list2[j] = list2[i];
+                       list2[i] = k;
+               }
+       }
+}
+
+/*
+ * 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 a relative position inside a room.
+ * negative values for x or y means RANDOM!
+ */
+
+STATIC_OVL void
+get_free_room_loc(x,y, croom)
+schar          *x, *y;
+struct mkroom  *croom;
+{
+       schar try_x, try_y;
+       register int trycnt = 0;
+
+       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;
+}
+
+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) {
+#ifdef DEBUG
+                               if(!vault)
+                                   debugpline("strange area [%d,%d] in check_room.",x,y);
+#endif
+                               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 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 totaly 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 ! */
+#ifdef DEBUG
+                               debugpline("No more rects...");
+#endif
+                               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 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 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, y;
+       int     trycnt = 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;
+               if (dpos == -1) /* The position is RANDOM */
+                   dpos = rn2((dwall == W_WEST || dwall == W_EAST) ?
+                           (broom->hy - broom->ly) : (broom->hx - broom->lx));
+
+               /* Convert wall and pos into an absolute coordinate! */
+
+               switch (dwall) {
+                     case W_NORTH:
+                       y = broom->ly - 1;
+                       x = broom->lx + dpos;
+                       break;
+                     case W_SOUTH:
+                       y = broom->hy + 1;
+                       x = broom->lx + dpos;
+                       break;
+                     case W_WEST:
+                       x = broom->lx - 1;
+                       y = broom->ly + dpos;
+                       break;
+                     case W_EAST:
+                       x = broom->hx + 1;
+                       y = broom->ly + dpos;
+                       break;
+                     default:
+                       x = y = 0;
+                       panic("create_door: No wall for door!");
+                       break;
+               }
+               if (okdoor(x,y))
+                   break;
+       } while (++trycnt <= 100);
+       if (trycnt > 100) {
+               impossible("create_door: Can't find a proper place!");
+               return;
+       }
+       add_door(x,y,broom);
+       levl[x][y].typ = (dd->secret ? SDOOR : DOOR);
+       levl[x][y].doormask = dd->mask;
+}
+
+/*
+ * 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;
+           add_door(sx,sy,croom);
+           return;
+       }
+    }
+
+    impossible("couldn't create secret door on any walls 0x%x", walls);
+}
+
+/*
+ * Create a trap in a room.
+ */
+
+STATIC_OVL void
+create_trap(t,croom)
+trap   *t;
+struct mkroom  *croom;
+{
+    schar      x,y;
+    coord      tm;
+
+    if (rn2(100) < t->chance) {
+       x = t->x;
+       y = t->y;
+       if (croom)
+           get_free_room_loc(&x, &y, croom);
+       else
+           get_location(&x, &y, DRY);
+
+       tm.x = x;
+       tm.y = y;
+
+       mktrap(t->type, 1, (struct mkroom*) 0, &tm);
+    }
+}
+
+/*
+ * 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);
+}
+
+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 (rn2(100) < m->chance) {
+
+       if (m->class >= 0)
+           class = (char) def_char_to_monclass((char)m->class);
+       else if (m->class > -11)
+           class = (char) def_char_to_monclass(rmonst[- m->class - 1]);
+       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 <= -11) ? 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))
+               goto m_done;
+           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;
+
+       x = m->x;
+       y = m->y;
+       if (croom)
+           get_room_loc(&x, &y, croom);
+       else {
+           if (!pm || !is_swimmer(pm))
+               get_location(&x, &y, DRY);
+           else if (pm->mlet == S_EEL)
+               get_location(&x, &y, WET);
+           else
+               get_location(&x, &y, DRY|WET);
+       }
+       /* 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 != -12)
+           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) {
+           /* handle specific attributes for some special monsters */
+           if (m->name.str) mtmp = christen_monst(mtmp, m->name.str);
+
+           /*
+            * This is currently hardwired for mimics only.  It should
+            * eventually be expanded.
+            */
+           if (m->appear_as.str && mtmp->data->mlet == S_MIMIC) {
+               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;
+                       }
+                       break;
+
+                   case M_AP_MONSTER:
+                       /* note: mimics don't appear as monsters! */
+                       /*       (but chameleons can :-)          */
+                   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 (rn2(100) < m->chance) */
+ m_done:
+    Free(m->name.str);
+    Free(m->appear_as.str);
+}
+
+/*
+ * 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? */
+
+    if (rn2(100) < o->chance) {
+       named = o->name.str ? TRUE : FALSE;
+
+       x = o->x; y = o->y;
+       if (croom)
+           get_room_loc(&x, &y, croom);
+       else
+           get_location(&x, &y, DRY);
+
+       if (o->class >= 0)
+           c = o->class;
+       else if (o->class > -11)
+           c = robjects[ -(o->class+1)];
+       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 - 1) otmp->corpsenm = rndmonnum();
+       else if (o->corpsenm != NON_PM) otmp->corpsenm = o->corpsenm;
+
+       /* assume we wouldn't be given an egg corpsenm unless it was
+          hatchable */
+       if (otmp->otyp == EGG && otmp->corpsenm != NON_PM) {
+           if (dead_species(otmp->otyp, TRUE))
+               kill_egg(otmp); /* make sure nothing hatches */
+           else
+               attach_egg_hatch_timeout(otmp); /* attach new hatch timeout */
+       }
+
+       if (named)
+           otmp = oname(otmp, o->name.str);
+
+       switch(o->containment) {
+           static struct obj *container = 0;
+
+           /* contents */
+           case 1:
+               if (!container) {
+                   impossible("create_object: no container");
+                   break;
+               }
+               remove_object(otmp);
+               (void) add_to_container(container, otmp);
+               goto o_done;            /* don't stack, but do other cleanup */
+           /* container */
+           case 2:
+               delete_contents(otmp);
+               container = otmp;
+               break;
+           /* nothing */
+           case 0: break;
+
+           default: impossible("containment type %d?", (int) o->containment);
+       }
+
+       /* 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;
+
+           /* 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; ; wastyp = rndmonnum()) {
+               /* makemon without rndmonst() might create a group */
+               was = makemon(&mons[wastyp], 0, 0, NO_MM_FLAGS);
+               if (!resists_ston(was)) break;
+               mongone(was);
+           }
+           otmp->corpsenm = 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);
+       }
+
+       stackobj(otmp);
+
+    }          /* if (rn2(100) < o->chance) */
+ o_done:
+    Free(o->name.str);
+}
+
+/*
+ * Randomly place a specific engraving, then release its memory.
+ */
+STATIC_OVL void
+create_engraving(e, croom)
+engraving *e;
+struct mkroom *croom;
+{
+       xchar x, y;
+
+       x = e->x,  y = e->y;
+       if (croom)
+           get_room_loc(&x, &y, croom);
+       else
+           get_location(&x, &y, DRY);
+
+       make_engr_at(x, y, e->engr.str, 0L, e->etype);
+       free((genericptr_t) e->engr.str);
+}
+
+/*
+ * Create stairs in a room.
+ *
+ */
+
+STATIC_OVL void
+create_stairs(s,croom)
+stair  *s;
+struct mkroom  *croom;
+{
+       schar           x,y;
+
+       x = s->x; y = s->y;
+       get_free_room_loc(&x, &y, croom);
+       mkstairs(x,y,(char)s->up, croom);
+}
+
+/*
+ * Create an altar in a room.
+ */
+
+STATIC_OVL void
+create_altar(a, croom)
+       altar           *a;
+       struct mkroom   *croom;
+{
+       schar           sproom,x,y;
+       aligntyp        amask;
+       boolean         croom_is_temple = TRUE;
+       int oldtyp; 
+
+       x = a->x; y = a->y;
+
+       if (croom) {
+           get_free_room_loc(&x, &y, croom);
+           if (croom->rtype != TEMPLE)
+               croom_is_temple = FALSE;
+       } else {
+           get_location(&x, &y, DRY);
+           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;
+
+       a->x = x;
+       a->y = y;
+
+       /* 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 == -11) ? 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 (oldtyp == FOUNTAIN)
+           level.flags.nfountains--;
+       else if (oldtyp == SINK)
+           level.flags.nsinks--;
+
+       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;
+       }
+}
+
+/*
+ * Create a gold pile in a room.
+ */
+
+STATIC_OVL void
+create_gold(g,croom)
+gold *g;
+struct mkroom  *croom;
+{
+       schar           x,y;
+
+       x = g->x; y= g->y;
+       if (croom)
+           get_room_loc(&x, &y, croom);
+       else
+           get_location(&x, &y, DRY);
+
+       if (g->amount == -1)
+           g->amount = rnd(200);
+       (void) mkgold((long) g->amount, x, y);
+}
+
+/*
+ * Create a feature (e.g a fountain) in a room.
+ */
+
+STATIC_OVL void
+create_feature(fx, fy, croom, typ)
+int            fx, fy;
+struct mkroom  *croom;
+int            typ;
+{
+       schar           x,y;
+       int             trycnt = 0;
+
+       x = fx;  y = fy;
+       if (croom) {
+           if (x < 0 && y < 0)
+               do {
+                   x = -1;  y = -1;
+                   get_room_loc(&x, &y, croom);
+               } while (++trycnt <= 200 && occupied(x,y));
+           else
+               get_room_loc(&x, &y, croom);
+           if(trycnt > 200)
+               return;
+       } else {
+           get_location(&x, &y, DRY);
+       }
+       /* Don't cover up an existing feature (particularly randomly
+          placed stairs).  However, if the _same_ feature is already
+          here, it came from the map drawing and we still need to
+          update the special counters. */
+       if (IS_FURNITURE(levl[x][y].typ) && levl[x][y].typ != typ)
+           return;
+
+       levl[x][y].typ = typ;
+       if (typ == FOUNTAIN)
+           level.flags.nfountains++;
+       else if (typ == SINK)
+           level.flags.nsinks++;
+}
+
+/*
+ * 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 a corridor between two points.
+ */
+
+boolean
+dig_corridor(org,dest,nxcor,ftyp,btyp)
+coord *org, *dest;
+boolean nxcor;
+schar ftyp, btyp;
+{
+       register int dx=0, dy=0, dix, diy, cct;
+       register struct rm *crm;
+       register 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) {
+#ifdef DEBUG
+               debugpline("dig_corridor: bad coords : (%d,%d) (%d,%d).",
+                          xx,yy,tx,ty);
+#endif
+               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);
+
+           /* 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;
+}
+
+/*
+ * 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!");
+    }
+}
+
+/*
+ * 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) {
+               sort_rooms();
+               fix_stair_rooms();
+               makecorridors();
+               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 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;
+       }
+}
+
+STATIC_OVL void
+free_rooms(ro, n)
+room **ro;
+int n;
+{
+       short j;
+       room *r;
+
+       while(n--) {
+               r = ro[n];
+               Free(r->name);
+               Free(r->parent);
+               if ((j = r->ndoor) != 0) {
+                       while(j--)
+                           Free(r->doors[j]);
+                       Free(r->doors);
+               }
+               if ((j = r->nstair) != 0) {
+                       while(j--)
+                           Free(r->stairs[j]);
+                       Free(r->stairs);
+               }
+               if ((j = r->naltar) != 0) {
+                       while (j--)
+                           Free(r->altars[j]);
+                       Free(r->altars);
+               }
+               if ((j = r->nfountain) != 0) {
+                       while(j--)
+                           Free(r->fountains[j]);
+                       Free(r->fountains);
+               }
+               if ((j = r->nsink) != 0) {
+                       while(j--)
+                           Free(r->sinks[j]);
+                       Free(r->sinks);
+               }
+               if ((j = r->npool) != 0) {
+                       while(j--)
+                           Free(r->pools[j]);
+                       Free(r->pools);
+               }
+               if ((j = r->ntrap) != 0) {
+                       while (j--)
+                           Free(r->traps[j]);
+                       Free(r->traps);
+               }
+               if ((j = r->nmonster) != 0) {
+                       while (j--)
+                               Free(r->monsters[j]);
+                       Free(r->monsters);
+               }
+               if ((j = r->nobject) != 0) {
+                       while (j--)
+                               Free(r->objects[j]);
+                       Free(r->objects);
+               }
+               if ((j = r->ngold) != 0) {
+                       while(j--)
+                           Free(r->golds[j]);
+                       Free(r->golds);
+               }
+               if ((j = r->nengraving) != 0) {
+                       while (j--)
+                               Free(r->engravings[j]);
+                       Free(r->engravings);
+               }
+               Free(r);
+       }
+       Free(ro);
+}
+
+STATIC_OVL void
+build_room(r, pr)
+room *r, *pr;
+{
+       boolean okroom;
+       struct mkroom   *aroom;
+       short i;
+       xchar rtype = (!r->chance || rn2(100) < r->chance) ? r->rtype : OROOM;
+
+       if(pr) {
+               aroom = &subrooms[nsubroom];
+               okroom = create_subroom(pr->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);
+               r->mkr = aroom;
+       }
+
+       if (okroom) {
+               /* Create subrooms if necessary... */
+               for(i=0; i < r->nsubroom; i++)
+                   build_room(r->subrooms[i], r);
+               /* And now we can fill the room! */
+
+               /* Priority to the stairs */
+
+               for(i=0; i <r->nstair; i++)
+                   create_stairs(r->stairs[i], aroom);
+
+               /* Then to the various elements (sinks, etc..) */
+               for(i = 0; i<r->nsink; i++)
+                   create_feature(r->sinks[i]->x, r->sinks[i]->y, aroom, SINK);
+               for(i = 0; i<r->npool; i++)
+                   create_feature(r->pools[i]->x, r->pools[i]->y, aroom, POOL);
+               for(i = 0; i<r->nfountain; i++)
+                   create_feature(r->fountains[i]->x, r->fountains[i]->y,
+                                  aroom, FOUNTAIN);
+               for(i = 0; i<r->naltar; i++)
+                   create_altar(r->altars[i], aroom);
+               for(i = 0; i<r->ndoor; i++)
+                   create_door(r->doors[i], aroom);
+
+               /* The traps */
+               for(i = 0; i<r->ntrap; i++)
+                   create_trap(r->traps[i], aroom);
+
+               /* The monsters */
+               for(i = 0; i<r->nmonster; i++)
+                   create_monster(r->monsters[i], aroom);
+
+               /* The objects */
+               for(i = 0; i<r->nobject; i++)
+                   create_object(r->objects[i], aroom);
+
+               /* The gold piles */
+               for(i = 0; i<r->ngold; i++)
+                   create_gold(r->golds[i], aroom);
+
+               /* The engravings */
+               for (i = 0; i < r->nengraving; i++)
+                   create_engraving(r->engravings[i], aroom);
+
+#ifdef SPECIALIZATION
+               topologize(aroom,FALSE);                /* set roomno */
+#else
+               topologize(aroom);                      /* set roomno */
+#endif
+               /* MRS - 07/04/91 - This is temporary but should result
+                * in proper filling of shops, etc.
+                * DLC - this can fail if corridors are added to this room
+                * at a later point.  Currently no good way to fix this.
+                */
+               if(aroom->rtype != OROOM && r->filled) fill_room(aroom, FALSE);
+       }
+}
+
+/*
+ * 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++;
+       }
+    }
+}
+
+/* initialization common to all special levels */
+STATIC_OVL void
+load_common_data(fd, typ)
+dlb *fd;
+int typ;
+{
+       uchar   n;
+       long    lev_flags;
+       int     i;
+
+      {
+       aligntyp atmp;
+       /* shuffle 3 alignments; can't use sp_lev_shuffle() on aligntyp's */
+       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; }
+      }
+
+       level.flags.is_maze_lev = typ == SP_LEV_MAZE;
+
+       /* Read the level initialization data */
+       Fread((genericptr_t) &init_lev, 1, sizeof(lev_init), fd);
+       if(init_lev.init_present) {
+           if(init_lev.lit < 0)
+               init_lev.lit = rn2(2);
+           mkmap(&init_lev);
+       }
+
+       /* Read the per level flags */
+       Fread((genericptr_t) &lev_flags, 1, sizeof(lev_flags), fd);
+       if (lev_flags & NOTELEPORT)
+           level.flags.noteleport = 1;
+       if (lev_flags & HARDFLOOR)
+           level.flags.hardfloor = 1;
+       if (lev_flags & NOMMAP)
+           level.flags.nommap = 1;
+       if (lev_flags & SHORTSIGHTED)
+           level.flags.shortsighted = 1;
+       if (lev_flags & ARBOREAL)
+           level.flags.arboreal = 1;
+
+       /* Read message */
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+       if (n) {
+           lev_message = (char *) alloc(n + 1);
+           Fread((genericptr_t) lev_message, 1, (int) n, fd);
+           lev_message[n] = 0;
+       }
+}
+
+STATIC_OVL void
+load_one_monster(fd, m)
+dlb *fd;
+monster *m;
+{
+       int size;
+
+       Fread((genericptr_t) m, 1, sizeof *m, fd);
+       if ((size = m->name.len) != 0) {
+           m->name.str = (char *) alloc((unsigned)size + 1);
+           Fread((genericptr_t) m->name.str, 1, size, fd);
+           m->name.str[size] = '\0';
+       } else
+           m->name.str = (char *) 0;
+       if ((size = m->appear_as.len) != 0) {
+           m->appear_as.str = (char *) alloc((unsigned)size + 1);
+           Fread((genericptr_t) m->appear_as.str, 1, size, fd);
+           m->appear_as.str[size] = '\0';
+       } else
+           m->appear_as.str = (char *) 0;
+}
+
+STATIC_OVL void
+load_one_object(fd, o)
+dlb *fd;
+object *o;
+{
+       int size;
+
+       Fread((genericptr_t) o, 1, sizeof *o, fd);
+       if ((size = o->name.len) != 0) {
+           o->name.str = (char *) alloc((unsigned)size + 1);
+           Fread((genericptr_t) o->name.str, 1, size, fd);
+           o->name.str[size] = '\0';
+       } else
+           o->name.str = (char *) 0;
+}
+
+STATIC_OVL void
+load_one_engraving(fd, e)
+dlb *fd;
+engraving *e;
+{
+       int size;
+
+       Fread((genericptr_t) e, 1, sizeof *e, fd);
+       size = e->engr.len;
+       e->engr.str = (char *) alloc((unsigned)size+1);
+       Fread((genericptr_t) e->engr.str, 1, size, fd);
+       e->engr.str[size] = '\0';
+}
+
+STATIC_OVL boolean
+load_rooms(fd)
+dlb *fd;
+{
+       xchar           nrooms, ncorr;
+       char            n;
+       short           size;
+       corridor        tmpcor;
+       room**          tmproom;
+       int             i, j;
+
+       load_common_data(fd, SP_LEV_ROOMS);
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrobjects */
+       if (n) {
+               Fread((genericptr_t)robjects, sizeof(*robjects), n, fd);
+               sp_lev_shuffle(robjects, (char *)0, (int)n);
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrmonst */
+       if (n) {
+               Fread((genericptr_t)rmonst, sizeof(*rmonst), n, fd);
+               sp_lev_shuffle(rmonst, (char *)0, (int)n);
+       }
+
+       Fread((genericptr_t) &nrooms, 1, sizeof(nrooms), fd);
+                                               /* Number of rooms to read */
+       tmproom = NewTab(room,nrooms);
+       for (i=0;i<nrooms;i++) {
+               room *r;
+
+               r = tmproom[i] = New(room);
+
+               /* Let's see if this room has a name */
+               Fread((genericptr_t) &size, 1, sizeof(size), fd);
+               if (size > 0) { /* Yup, it does! */
+                       r->name = (char *) alloc((unsigned)size + 1);
+                       Fread((genericptr_t) r->name, 1, size, fd);
+                       r->name[size] = 0;
+               } else
+                   r->name = (char *) 0;
+
+               /* Let's see if this room has a parent */
+               Fread((genericptr_t) &size, 1, sizeof(size), fd);
+               if (size > 0) { /* Yup, it does! */
+                       r->parent = (char *) alloc((unsigned)size + 1);
+                       Fread((genericptr_t) r->parent, 1, size, fd);
+                       r->parent[size] = 0;
+               } else
+                   r->parent = (char *) 0;
+
+               Fread((genericptr_t) &r->x, 1, sizeof(r->x), fd);
+                                       /* x pos on the grid (1-5) */
+               Fread((genericptr_t) &r->y, 1, sizeof(r->y), fd);
+                                        /* y pos on the grid (1-5) */
+               Fread((genericptr_t) &r->w, 1, sizeof(r->w), fd);
+                                        /* width of the room */
+               Fread((genericptr_t) &r->h, 1, sizeof(r->h), fd);
+                                        /* height of the room */
+               Fread((genericptr_t) &r->xalign, 1, sizeof(r->xalign), fd);
+                                        /* horizontal alignment */
+               Fread((genericptr_t) &r->yalign, 1, sizeof(r->yalign), fd);
+                                        /* vertical alignment */
+               Fread((genericptr_t) &r->rtype, 1, sizeof(r->rtype), fd);
+                                        /* type of room (zoo, shop, etc.) */
+               Fread((genericptr_t) &r->chance, 1, sizeof(r->chance), fd);
+                                        /* chance of room being special. */
+               Fread((genericptr_t) &r->rlit, 1, sizeof(r->rlit), fd);
+                                        /* lit or not ? */
+               Fread((genericptr_t) &r->filled, 1, sizeof(r->filled), fd);
+                                        /* to be filled? */
+               r->nsubroom= 0;
+
+               /* read the doors */
+               Fread((genericptr_t) &r->ndoor, 1, sizeof(r->ndoor), fd);
+               if ((n = r->ndoor) != 0)
+                   r->doors = NewTab(room_door, n);
+               while(n--) {
+                       r->doors[(int)n] = New(room_door);
+                       Fread((genericptr_t) r->doors[(int)n], 1,
+                               sizeof(room_door), fd);
+               }
+
+               /* read the stairs */
+               Fread((genericptr_t) &r->nstair, 1, sizeof(r->nstair), fd);
+               if ((n = r->nstair) != 0)
+                   r->stairs = NewTab(stair, n);
+               while (n--) {
+                       r->stairs[(int)n] = New(stair);
+                       Fread((genericptr_t) r->stairs[(int)n], 1,
+                               sizeof(stair), fd);
+               }
+
+               /* read the altars */
+               Fread((genericptr_t) &r->naltar, 1, sizeof(r->naltar), fd);
+               if ((n = r->naltar) != 0)
+                   r->altars = NewTab(altar, n);
+               while (n--) {
+                       r->altars[(int)n] = New(altar);
+                       Fread((genericptr_t) r->altars[(int)n], 1,
+                               sizeof(altar), fd);
+               }
+
+               /* read the fountains */
+               Fread((genericptr_t) &r->nfountain, 1,
+                       sizeof(r->nfountain), fd);
+               if ((n = r->nfountain) != 0)
+                   r->fountains = NewTab(fountain, n);
+               while (n--) {
+                       r->fountains[(int)n] = New(fountain);
+                       Fread((genericptr_t) r->fountains[(int)n], 1,
+                               sizeof(fountain), fd);
+               }
+
+               /* read the sinks */
+               Fread((genericptr_t) &r->nsink, 1, sizeof(r->nsink), fd);
+               if ((n = r->nsink) != 0)
+                   r->sinks = NewTab(sink, n);
+               while (n--) {
+                       r->sinks[(int)n] = New(sink);
+                       Fread((genericptr_t) r->sinks[(int)n], 1, sizeof(sink), fd);
+               }
+
+               /* read the pools */
+               Fread((genericptr_t) &r->npool, 1, sizeof(r->npool), fd);
+               if ((n = r->npool) != 0)
+                   r->pools = NewTab(pool,n);
+               while (n--) {
+                       r->pools[(int)n] = New(pool);
+                       Fread((genericptr_t) r->pools[(int)n], 1, sizeof(pool), fd);
+               }
+
+               /* read the traps */
+               Fread((genericptr_t) &r->ntrap, 1, sizeof(r->ntrap), fd);
+               if ((n = r->ntrap) != 0)
+                   r->traps = NewTab(trap, n);
+               while(n--) {
+                       r->traps[(int)n] = New(trap);
+                       Fread((genericptr_t) r->traps[(int)n], 1, sizeof(trap), fd);
+               }
+
+               /* read the monsters */
+               Fread((genericptr_t) &r->nmonster, 1, sizeof(r->nmonster), fd);
+               if ((n = r->nmonster) != 0) {
+                   r->monsters = NewTab(monster, n);
+                   while(n--) {
+                       r->monsters[(int)n] = New(monster);
+                       load_one_monster(fd, r->monsters[(int)n]);
+                   }
+               } else
+                   r->monsters = 0;
+
+               /* read the objects, in same order as mazes */
+               Fread((genericptr_t) &r->nobject, 1, sizeof(r->nobject), fd);
+               if ((n = r->nobject) != 0) {
+                   r->objects = NewTab(object, n);
+                   for (j = 0; j < n; ++j) {
+                       r->objects[j] = New(object);
+                       load_one_object(fd, r->objects[j]);
+                   }
+               } else
+                   r->objects = 0;
+
+               /* read the gold piles */
+               Fread((genericptr_t) &r->ngold, 1, sizeof(r->ngold), fd);
+               if ((n = r->ngold) != 0)
+                   r->golds = NewTab(gold, n);
+               while (n--) {
+                       r->golds[(int)n] = New(gold);
+                       Fread((genericptr_t) r->golds[(int)n], 1, sizeof(gold), fd);
+               }
+
+               /* read the engravings */
+               Fread((genericptr_t) &r->nengraving, 1,
+                       sizeof(r->nengraving), fd);
+               if ((n = r->nengraving) != 0) {
+                   r->engravings = NewTab(engraving,n);
+                   while (n--) {
+                       r->engravings[(int)n] = New(engraving);
+                       load_one_engraving(fd, r->engravings[(int)n]);
+                   }
+               } else
+                   r->engravings = 0;
+
+       }
+
+       /* Now that we have loaded all the rooms, search the
+        * subrooms and create the links.
+        */
+
+       for (i = 0; i<nrooms; i++)
+           if (tmproom[i]->parent) {
+                   /* Search the parent room */
+                   for(j=0; j<nrooms; j++)
+                       if (tmproom[j]->name && !strcmp(tmproom[j]->name,
+                                                      tmproom[i]->parent)) {
+                               n = tmproom[j]->nsubroom++;
+                               tmproom[j]->subrooms[(int)n] = tmproom[i];
+                               break;
+                       }
+           }
+
+       /*
+        * Create the rooms now...
+        */
+
+       for (i=0; i < nrooms; i++)
+           if(!tmproom[i]->parent)
+               build_room(tmproom[i], (room *) 0);
+
+       free_rooms(tmproom, nrooms);
+
+       /* read the corridors */
+
+       Fread((genericptr_t) &ncorr, sizeof(ncorr), 1, fd);
+       for (i=0; i<ncorr; i++) {
+               Fread((genericptr_t) &tmpcor, 1, sizeof(tmpcor), fd);
+               create_corridor(&tmpcor);
+       }
+
+       return TRUE;
+}
+
+/*
+ * 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) || Map[x][y] ||
+                !is_ok_location((schar)x, (schar)y, humidity));
+
+       m->x = (xchar)x,  m->y = (xchar)y;
+}
+
+/*
+ * The Big Thing: special maze loader
+ *
+ * Could be cleaner, but it works.
+ */
+
+STATIC_OVL boolean
+load_maze(fd)
+dlb *fd;
+{
+    xchar   x, y, typ;
+    boolean prefilled, room_not_needed;
+
+    char    n, numpart = 0;
+    xchar   nwalk = 0, nwalk_sav;
+    schar   filling;
+    char    halign, valign;
+
+    int     xi, dir, size;
+    coord   mm;
+    int     mapcount, mapcountmax, mapfact;
+
+    lev_region  tmplregion;
+    region  tmpregion;
+    door    tmpdoor;
+    trap    tmptrap;
+    monster tmpmons;
+    object  tmpobj;
+    drawbridge tmpdb;
+    walk    tmpwalk;
+    digpos  tmpdig;
+    lad     tmplad;
+    stair   tmpstair, prevstair;
+    altar   tmpaltar;
+    gold    tmpgold;
+    fountain tmpfountain;
+    engraving tmpengraving;
+    xchar   mustfill[(MAXNROFROOMS+1)*2];
+    struct trap *badtrap;
+    boolean has_bounds;
+
+    (void) memset((genericptr_t)&Map[0][0], 0, sizeof Map);
+    load_common_data(fd, SP_LEV_MAZE);
+
+    /* Initialize map */
+    Fread((genericptr_t) &filling, 1, sizeof(filling), fd);
+    if (!init_lev.init_present) { /* don't init if mkmap() has been called */
+      for(x = 2; x <= x_maze_max; x++)
+       for(y = 0; y <= y_maze_max; y++)
+           if (filling == -1) {
+#ifndef WALLIFIED_MAZE
+                   levl[x][y].typ = STONE;
+#else
+                   levl[x][y].typ =
+                       (y < 2 || ((x % 2) && (y % 2))) ? STONE : HWALL;
+#endif
+           } else {
+                   levl[x][y].typ = filling;
+           }
+    }
+
+    /* Start reading the file */
+    Fread((genericptr_t) &numpart, 1, sizeof(numpart), fd);
+                                               /* Number of parts */
+    if (!numpart || numpart > 9)
+       panic("load_maze error: numpart = %d", (int) numpart);
+
+    while (numpart--) {
+       Fread((genericptr_t) &halign, 1, sizeof(halign), fd);
+                                       /* Horizontal alignment */
+       Fread((genericptr_t) &valign, 1, sizeof(valign), fd);
+                                       /* Vertical alignment */
+       Fread((genericptr_t) &xsize, 1, sizeof(xsize), fd);
+                                       /* size in X */
+       Fread((genericptr_t) &ysize, 1, sizeof(ysize), fd);
+                                       /* size in Y */
+       switch((int) halign) {
+           case LEFT:      xstart = 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++;
+       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 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.
+        */
+       has_bounds = FALSE;
+
+       if(init_lev.init_present && xsize <= 1 && ysize <= 1) {
+           xstart = 1;
+           ystart = 0;
+           xsize = COLNO-1;
+           ysize = ROWNO;
+       } else {
+           /* Load the map */
+           for(y = ystart; y < ystart+ysize; y++)
+               for(x = xstart; x < xstart+xsize; x++) {
+                   levl[x][y].typ = Fgetc(fd);
+                   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;
+                   /*
+                    * Note: Even though levl[x][y].typ is type schar,
+                    *   lev_comp.y saves it as type char. Since schar != char
+                    *   all the time we must make this exception or hack
+                    *   through lev_comp.y to fix.
+                    */
+
+                   /*
+                    *  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(levl[x][y].typ == CROSSWALL)
+                       has_bounds = TRUE;
+                   Map[x][y] = 1;
+               }
+           if (init_lev.init_present && init_lev.joined)
+               remove_rooms(xstart, ystart, xstart+xsize, ystart+ysize);
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of level regions */
+       if(n) {
+           if(num_lregions) {
+               /* realloc the lregion space to add the new ones */
+               /* don't really free it up until the whole level is done */
+               lev_region *newl = (lev_region *) alloc(sizeof(lev_region) *
+                                               (unsigned)(n+num_lregions));
+               (void) memcpy((genericptr_t)(newl+n), (genericptr_t)lregions,
+                                       sizeof(lev_region) * num_lregions);
+               Free(lregions);
+               num_lregions += n;
+               lregions = newl;
+           } else {
+               num_lregions = n;
+               lregions = (lev_region *)
+                               alloc(sizeof(lev_region) * (unsigned)n);
+           }
+       }
+
+       while(n--) {
+           Fread((genericptr_t) &tmplregion, sizeof(tmplregion), 1, fd);
+           if ((size = tmplregion.rname.len) != 0) {
+               tmplregion.rname.str = (char *) alloc((unsigned)size + 1);
+               Fread((genericptr_t) tmplregion.rname.str, size, 1, fd);
+               tmplregion.rname.str[size] = '\0';
+           } else
+               tmplregion.rname.str = (char *) 0;
+           if(!tmplregion.in_islev) {
+               get_location(&tmplregion.inarea.x1, &tmplregion.inarea.y1,
+                                                               DRY|WET);
+               get_location(&tmplregion.inarea.x2, &tmplregion.inarea.y2,
+                                                               DRY|WET);
+           }
+           if(!tmplregion.del_islev) {
+               get_location(&tmplregion.delarea.x1, &tmplregion.delarea.y1,
+                                                               DRY|WET);
+               get_location(&tmplregion.delarea.x2, &tmplregion.delarea.y2,
+                                                               DRY|WET);
+           }
+           lregions[(int)n] = tmplregion;
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Random objects */
+       if(n) {
+               Fread((genericptr_t)robjects, sizeof(*robjects), (int) n, fd);
+               sp_lev_shuffle(robjects, (char *)0, (int)n);
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Random locations */
+       if(n) {
+               Fread((genericptr_t)rloc_x, sizeof(*rloc_x), (int) n, fd);
+               Fread((genericptr_t)rloc_y, sizeof(*rloc_y), (int) n, fd);
+               sp_lev_shuffle(rloc_x, rloc_y, (int)n);
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Random monsters */
+       if(n) {
+               Fread((genericptr_t)rmonst, sizeof(*rmonst), (int) n, fd);
+               sp_lev_shuffle(rmonst, (char *)0, (int)n);
+       }
+
+       (void) memset((genericptr_t)mustfill, 0, sizeof(mustfill));
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of subrooms */
+       while(n--) {
+               register struct mkroom *troom;
+
+               Fread((genericptr_t)&tmpregion, 1, sizeof(tmpregion), fd);
+
+               if(tmpregion.rtype > MAXRTYPE) {
+                   tmpregion.rtype -= MAXRTYPE+1;
+                   prefilled = TRUE;
+               } else
+                   prefilled = FALSE;
+
+               if(tmpregion.rlit < 0)
+                   tmpregion.rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77))
+                       ? TRUE : FALSE;
+
+               get_location(&tmpregion.x1, &tmpregion.y1, DRY|WET);
+               get_location(&tmpregion.x2, &tmpregion.y2, DRY|WET);
+
+               /* 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 = (tmpregion.rtype == OROOM &&
+                                  !tmpregion.rirreg && !prefilled);
+               if (room_not_needed || nroom >= MAXNROFROOMS) {
+                   if (!room_not_needed)
+                       impossible("Too many rooms on new level!");
+                   light_region(&tmpregion);
+                   continue;
+               }
+
+               troom = &rooms[nroom];
+
+               /* mark rooms that must be filled, but do it later */
+               if (tmpregion.rtype != OROOM)
+                   mustfill[nroom] = (prefilled ? 2 : 1);
+
+               if(tmpregion.rirreg) {
+                   min_rx = max_rx = tmpregion.x1;
+                   min_ry = max_ry = tmpregion.y1;
+                   flood_fill_rm(tmpregion.x1, tmpregion.y1,
+                                 nroom+ROOMOFFSET, tmpregion.rlit, TRUE);
+                   add_room(min_rx, min_ry, max_rx, max_ry,
+                            FALSE, tmpregion.rtype, TRUE);
+                   troom->rlit = tmpregion.rlit;
+                   troom->irregular = TRUE;
+               } else {
+                   add_room(tmpregion.x1, tmpregion.y1,
+                            tmpregion.x2, tmpregion.y2,
+                            tmpregion.rlit, tmpregion.rtype, TRUE);
+#ifdef SPECIALIZATION
+                   topologize(troom,FALSE);            /* set roomno */
+#else
+                   topologize(troom);                  /* set roomno */
+#endif
+               }
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of doors */
+       while(n--) {
+               struct mkroom *croom = &rooms[0];
+
+               Fread((genericptr_t)&tmpdoor, 1, sizeof(tmpdoor), fd);
+
+               x = tmpdoor.x;  y = tmpdoor.y;
+               typ = tmpdoor.mask == -1 ? rnddoor() : tmpdoor.mask;
+
+               get_location(&x, &y, DRY);
+               if(levl[x][y].typ != SDOOR)
+                       levl[x][y].typ = DOOR;
+               else {
+                       if(typ < D_CLOSED)
+                           typ = D_CLOSED; /* force it to be closed */
+               }
+               levl[x][y].doormask = typ;
+
+               /* Now the complicated part, list it with each subroom */
+               /* The dog move and mail daemon routines use this */
+               while(croom->hx >= 0 && doorindex < DOORMAX) {
+                   if(croom->hx >= x-1 && croom->lx <= x+1 &&
+                      croom->hy >= y-1 && croom->ly <= y+1) {
+                       /* Found it */
+                       add_door(x, y, croom);
+                   }
+                   croom++;
+               }
+       }
+
+       /* now that we have rooms _and_ associated doors, fill the rooms */
+       for(n = 0; n < SIZE(mustfill); n++)
+           if(mustfill[(int)n])
+               fill_room(&rooms[(int)n], (mustfill[(int)n] == 2));
+
+       /* if special boundary syms (CROSSWALL) in map, remove them now */
+       if(has_bounds) {
+           for(x = xstart; x < xstart+xsize; x++)
+               for(y = ystart; y < ystart+ysize; y++)
+                   if(levl[x][y].typ == CROSSWALL)
+                       levl[x][y].typ = ROOM;
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of drawbridges */
+       while(n--) {
+               Fread((genericptr_t)&tmpdb, 1, sizeof(tmpdb), fd);
+
+               x = tmpdb.x;  y = tmpdb.y;
+               get_location(&x, &y, DRY|WET);
+
+               if (!create_drawbridge(x, y, tmpdb.dir, tmpdb.db_open))
+                   impossible("Cannot create drawbridge.");
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of mazewalks */
+       while(n--) {
+               Fread((genericptr_t)&tmpwalk, 1, sizeof(tmpwalk), fd);
+
+               get_location(&tmpwalk.x, &tmpwalk.y, DRY|WET);
+
+               walklist[nwalk++] = tmpwalk;
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of non_diggables */
+       while(n--) {
+               Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd);
+
+               get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET);
+               get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET);
+
+               set_wall_property(tmpdig.x1, tmpdig.y1,
+                                 tmpdig.x2, tmpdig.y2, W_NONDIGGABLE);
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of non_passables */
+       while(n--) {
+               Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd);
+
+               get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET);
+               get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET);
+
+               set_wall_property(tmpdig.x1, tmpdig.y1,
+                                 tmpdig.x2, tmpdig.y2, W_NONPASSWALL);
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of ladders */
+       while(n--) {
+               Fread((genericptr_t)&tmplad, 1, sizeof(tmplad), fd);
+
+               x = tmplad.x;  y = tmplad.y;
+               get_location(&x, &y, DRY);
+
+               levl[x][y].typ = LADDER;
+               if (tmplad.up == 1) {
+                       xupladder = x;  yupladder = y;
+                       levl[x][y].ladder = LA_UP;
+               } else {
+                       xdnladder = x;  ydnladder = y;
+                       levl[x][y].ladder = LA_DOWN;
+               }
+       }
+
+       prevstair.x = prevstair.y = 0;
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of stairs */
+       while(n--) {
+               Fread((genericptr_t)&tmpstair, 1, sizeof(tmpstair), fd);
+
+               xi = 0;
+               do {
+                   x = tmpstair.x;  y = tmpstair.y;
+                   get_location(&x, &y, DRY);
+               } while(prevstair.x && xi++ < 100 &&
+                       distmin(x,y,prevstair.x,prevstair.y) <= 8);
+               if ((badtrap = t_at(x,y)) != 0) deltrap(badtrap);
+               mkstairs(x, y, (char)tmpstair.up, (struct mkroom *)0);
+               prevstair.x = x;
+               prevstair.y = y;
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of altars */
+       while(n--) {
+               Fread((genericptr_t)&tmpaltar, 1, sizeof(tmpaltar), fd);
+
+               create_altar(&tmpaltar, (struct mkroom *)0);
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of fountains */
+       while (n--) {
+               Fread((genericptr_t)&tmpfountain, 1, sizeof(tmpfountain), fd);
+
+               create_feature(tmpfountain.x, tmpfountain.y,
+                              (struct mkroom *)0, FOUNTAIN);
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of traps */
+       while(n--) {
+               Fread((genericptr_t)&tmptrap, 1, sizeof(tmptrap), fd);
+
+               create_trap(&tmptrap, (struct mkroom *)0);
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of monsters */
+       while(n--) {
+               load_one_monster(fd, &tmpmons);
+
+               create_monster(&tmpmons, (struct mkroom *)0);
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of objects */
+       while(n--) {
+               load_one_object(fd, &tmpobj);
+
+               create_object(&tmpobj, (struct mkroom *)0);
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of gold piles */
+       while (n--) {
+               Fread((genericptr_t)&tmpgold, 1, sizeof(tmpgold), fd);
+
+               create_gold(&tmpgold, (struct mkroom *)0);
+       }
+
+       Fread((genericptr_t) &n, 1, sizeof(n), fd);
+                                               /* Number of engravings */
+       while(n--) {
+               load_one_engraving(fd, &tmpengraving);
+
+               create_engraving(&tmpengraving, (struct mkroom *)0);
+       }
+
+    }          /* numpart loop */
+
+    nwalk_sav = nwalk;
+    while(nwalk--) {
+           x = (xchar) walklist[nwalk].x;
+           y = (xchar) walklist[nwalk].y;
+           dir = walklist[nwalk].dir;
+
+           /* 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: panic("load_maze: bad MAZEWALK direction");
+           }
+
+           if(!IS_DOOR(levl[x][y].typ)) {
+#ifndef WALLIFIED_MAZE
+               levl[x][y].typ = CORR;
+#else
+               levl[x][y].typ = ROOM;
+#endif
+               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 */
+#ifndef WALLIFIED_MAZE
+               levl[x][y].typ = CORR;
+#else
+               levl[x][y].typ = ROOM;
+#endif
+               levl[x][y].flags = 0;
+           }
+
+           if (!(y % 2)) {
+               if (dir == W_SOUTH)
+                   y++;
+               else
+                   y--;
+           }
+
+           walkfrom(x, y);
+    }
+    wallification(1, 0, COLNO-1, ROWNO-1);
+
+    /*
+     * 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.
+     */
+    mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2);
+
+    for(x = 2; x < x_maze_max; x++)
+       for(y = 0; y < y_maze_max; y++)
+           if(Map[x][y]) mapcount--;
+
+    if (nwalk_sav && (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, WET|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);
+           }
+    }
+    return TRUE;
+}
+
+/*
+ * General loader
+ */
+
+boolean
+load_special(name)
+const char *name;
+{
+       dlb *fd;
+       boolean result = FALSE;
+       char c;
+       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))
+           goto give_up;
+
+       Fread((genericptr_t) &c, sizeof c, 1, fd); /* c Header */
+
+       switch (c) {
+               case SP_LEV_ROOMS:
+                   result = load_rooms(fd);
+                   break;
+               case SP_LEV_MAZE:
+                   result = load_maze(fd);
+                   break;
+               default:        /* ??? */
+                   result = FALSE;
+       }
+ give_up:
+       (void)dlb_fclose(fd);
+       return result;
+}
+
+/*sp_lev.c*/
diff --git a/src/spell.c b/src/spell.c
new file mode 100644 (file)
index 0000000..4659cfa
--- /dev/null
@@ -0,0 +1,1264 @@
+/*     SCCS Id: @(#)spell.c    3.4     2003/01/17      */
+/*     Copyright (c) M. Stephenson 1988                          */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+static NEARDATA schar delay;           /* moves left for this spell */
+static NEARDATA struct obj *book;      /* last/current book being xscribed */
+
+/* spellmenu arguments; 0 thru n-1 used as spl_book[] index when swapping */
+#define SPELLMENU_CAST (-2)
+#define SPELLMENU_VIEW (-1)
+
+#define KEEN 20000
+#define MAX_SPELL_STUDY 3
+#define incrnknow(spell)        spl_book[spell].sp_know = KEEN
+
+#define spellev(spell)         spl_book[spell].sp_lev
+#define spellname(spell)       OBJ_NAME(objects[spellid(spell)])
+#define spellet(spell) \
+       ((char)((spell < 26) ? ('a' + spell) : ('A' + spell - 26)))
+
+STATIC_DCL int FDECL(spell_let_to_idx, (CHAR_P));
+STATIC_DCL boolean FDECL(cursed_book, (struct obj *bp));
+STATIC_DCL boolean FDECL(confused_book, (struct obj *));
+STATIC_DCL void FDECL(deadbook, (struct obj *));
+STATIC_PTR int NDECL(learn);
+STATIC_DCL boolean FDECL(getspell, (int *));
+STATIC_DCL boolean FDECL(dospellmenu, (const char *,int,int *));
+STATIC_DCL int FDECL(percent_success, (int));
+STATIC_DCL int NDECL(throwspell);
+STATIC_DCL void NDECL(cast_protection);
+STATIC_DCL void FDECL(spell_backfire, (int));
+STATIC_DCL const char *FDECL(spelltypemnemonic, (int));
+STATIC_DCL int FDECL(isqrt, (int));
+
+/* The roles[] table lists the role-specific values for tuning
+ * percent_success().
+ *
+ * Reasoning:
+ *   spelbase, spelheal:
+ *     Arc are aware of magic through historical research
+ *     Bar abhor magic (Conan finds it "interferes with his animal instincts")
+ *     Cav are ignorant to magic
+ *     Hea are very aware of healing magic through medical research
+ *     Kni are moderately aware of healing from Paladin training
+ *     Mon use magic to attack and defend in lieu of weapons and armor
+ *     Pri are very aware of healing magic through theological research
+ *     Ran avoid magic, preferring to fight unseen and unheard
+ *     Rog are moderately aware of magic through trickery
+ *     Sam have limited magical awareness, prefering meditation to conjuring
+ *     Tou are aware of magic from all the great films they have seen
+ *     Val have limited magical awareness, prefering fighting
+ *     Wiz are trained mages
+ *
+ *     The arms penalty is lessened for trained fighters Bar, Kni, Ran,
+ *     Sam, Val -
+ *     the penalty is its metal interference, not encumbrance.
+ *     The `spelspec' is a single spell which is fundamentally easier
+ *      for that role to cast.
+ *
+ *  spelspec, spelsbon:
+ *     Arc map masters (SPE_MAGIC_MAPPING)
+ *     Bar fugue/berserker (SPE_HASTE_SELF)
+ *     Cav born to dig (SPE_DIG)
+ *     Hea to heal (SPE_CURE_SICKNESS)
+ *     Kni to turn back evil (SPE_TURN_UNDEAD)
+ *     Mon to preserve their abilities (SPE_RESTORE_ABILITY)
+ *     Pri to bless (SPE_REMOVE_CURSE)
+ *     Ran to hide (SPE_INVISIBILITY)
+ *     Rog to find loot (SPE_DETECT_TREASURE)
+ *     Sam to be At One (SPE_CLAIRVOYANCE)
+ *     Tou to smile (SPE_CHARM_MONSTER)
+ *     Val control the cold (SPE_CONE_OF_COLD)
+ *     Wiz all really, but SPE_MAGIC_MISSILE is their party trick
+ *
+ *     See percent_success() below for more comments.
+ *
+ *  uarmbon, uarmsbon, uarmhbon, uarmgbon, uarmfbon:
+ *     Fighters find body armour & shield a little less limiting.
+ *     Headgear, Gauntlets and Footwear are not role-specific (but
+ *     still have an effect, except helm of brilliance, which is designed
+ *     to permit magic-use).
+ */
+
+#define uarmhbon 4 /* Metal helmets interfere with the mind */
+#define uarmgbon 6 /* Casting channels through the hands */
+#define uarmfbon 2 /* All metal interferes to some degree */
+
+/* since the spellbook itself doesn't blow up, don't say just "explodes" */
+static const char explodes[] = "radiates explosive energy";
+
+/* convert a letter into a number in the range 0..51, or -1 if not a letter */
+STATIC_OVL int
+spell_let_to_idx(ilet)
+char ilet;
+{
+    int indx;
+
+    indx = ilet - 'a';
+    if (indx >= 0 && indx < 26) return indx;
+    indx = ilet - 'A';
+    if (indx >= 0 && indx < 26) return indx + 26;
+    return -1;
+}
+
+/* TRUE: book should be destroyed by caller */
+STATIC_OVL boolean
+cursed_book(bp)
+       struct obj *bp;
+{
+       int lev = objects[bp->otyp].oc_level;
+
+       switch(rn2(lev)) {
+       case 0:
+               You_feel("a wrenching sensation.");
+               tele();         /* teleport him */
+               break;
+       case 1:
+               You_feel("threatened.");
+               aggravate();
+               break;
+       case 2:
+               make_blinded(Blinded + rn1(100,250),TRUE);
+               break;
+       case 3:
+               take_gold();
+               break;
+       case 4:
+               pline("These runes were just too much to comprehend.");
+               make_confused(HConfusion + rn1(7,16),FALSE);
+               break;
+       case 5:
+               pline_The("book was coated with contact poison!");
+               if (uarmg) {
+                   if (uarmg->oerodeproof || !is_corrodeable(uarmg)) {
+                       Your("gloves seem unaffected.");
+                   } else if (uarmg->oeroded2 < MAX_ERODE) {
+                       if (uarmg->greased) {
+                           grease_protect(uarmg, "gloves", &youmonst);
+                       } else {
+                           Your("gloves corrode%s!",
+                                uarmg->oeroded2+1 == MAX_ERODE ?
+                                " completely" : uarmg->oeroded2 ?
+                                " further" : "");
+                           uarmg->oeroded2++;
+                       }
+                   } else
+                       Your("gloves %s completely corroded.",
+                            Blind ? "feel" : "look");
+                   break;
+               }
+               /* temp disable in_use; death should not destroy the book */
+               bp->in_use = FALSE;
+               losestr(Poison_resistance ? rn1(2,1) : rn1(4,3));
+               losehp(rnd(Poison_resistance ? 6 : 10),
+                      "contact-poisoned spellbook", KILLED_BY_AN);
+               bp->in_use = TRUE;
+               break;
+       case 6:
+               if(Antimagic) {
+                   shieldeff(u.ux, u.uy);
+                   pline_The("book %s, but you are unharmed!", explodes);
+               } else {
+                   pline("As you read the book, it %s in your %s!",
+                         explodes, body_part(FACE));
+                   losehp(2*rnd(10)+5, "exploding rune", KILLED_BY_AN);
+               }
+               return TRUE;
+       default:
+               rndcurse();
+               break;
+       }
+       return FALSE;
+}
+
+/* study while confused: returns TRUE if the book is destroyed */
+STATIC_OVL boolean
+confused_book(spellbook)
+struct obj *spellbook;
+{
+       boolean gone = FALSE;
+
+       if (!rn2(3) && spellbook->otyp != SPE_BOOK_OF_THE_DEAD) {
+           spellbook->in_use = TRUE;   /* in case called from learn */
+           pline(
+       "Being confused you have difficulties in controlling your actions.");
+           display_nhwindow(WIN_MESSAGE, FALSE);
+           You("accidentally tear the spellbook to pieces.");
+           if (!objects[spellbook->otyp].oc_name_known &&
+               !objects[spellbook->otyp].oc_uname)
+               docall(spellbook);
+           useup(spellbook);
+           gone = TRUE;
+       } else {
+           You("find yourself reading the %s line over and over again.",
+               spellbook == book ? "next" : "first");
+       }
+       return gone;
+}
+
+/* special effects for The Book of the Dead */
+STATIC_OVL void
+deadbook(book2)
+struct obj *book2;
+{
+    struct monst *mtmp, *mtmp2;
+    coord mm;
+
+    You("turn the pages of the Book of the Dead...");
+    makeknown(SPE_BOOK_OF_THE_DEAD);
+    /* KMH -- Need ->known to avoid "_a_ Book of the Dead" */
+    book2->known = 1;
+    if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) {
+       register struct obj *otmp;
+       register boolean arti1_primed = FALSE, arti2_primed = FALSE,
+                        arti_cursed = FALSE;
+
+       if(book2->cursed) {
+           pline_The("runes appear scrambled.  You can't read them!");
+           return;
+       }
+
+       if(!u.uhave.bell || !u.uhave.menorah) {
+           pline("A chill runs down your %s.", body_part(SPINE));
+           if(!u.uhave.bell) You_hear("a faint chime...");
+           if(!u.uhave.menorah) pline("Vlad's doppelganger is amused.");
+           return;
+       }
+
+       for(otmp = invent; otmp; otmp = otmp->nobj) {
+           if(otmp->otyp == CANDELABRUM_OF_INVOCATION &&
+              otmp->spe == 7 && otmp->lamplit) {
+               if(!otmp->cursed) arti1_primed = TRUE;
+               else arti_cursed = TRUE;
+           }
+           if(otmp->otyp == BELL_OF_OPENING &&
+              (moves - otmp->age) < 5L) { /* you rang it recently */
+               if(!otmp->cursed) arti2_primed = TRUE;
+               else arti_cursed = TRUE;
+           }
+       }
+
+       if(arti_cursed) {
+           pline_The("invocation fails!");
+           pline("At least one of your artifacts is cursed...");
+       } else if(arti1_primed && arti2_primed) {
+           unsigned soon = (unsigned) d(2,6);  /* time til next intervene() */
+
+           /* successful invocation */
+           mkinvokearea();
+           u.uevent.invoked = 1;
+           /* in case you haven't killed the Wizard yet, behave as if
+              you just did */
+           u.uevent.udemigod = 1;      /* wizdead() */
+           if (!u.udg_cnt || u.udg_cnt > soon) u.udg_cnt = soon;
+       } else {        /* at least one artifact not prepared properly */
+           You("have a feeling that %s is amiss...", something);
+           goto raise_dead;
+       }
+       return;
+    }
+
+    /* when not an invocation situation */
+    if (book2->cursed) {
+raise_dead:
+
+       You("raised the dead!");
+       /* first maybe place a dangerous adversary */
+       if (!rn2(3) && ((mtmp = makemon(&mons[PM_MASTER_LICH],
+                                       u.ux, u.uy, NO_MINVENT)) != 0 ||
+                       (mtmp = makemon(&mons[PM_NALFESHNEE],
+                                       u.ux, u.uy, NO_MINVENT)) != 0)) {
+           mtmp->mpeaceful = 0;
+           set_malign(mtmp);
+       }
+       /* next handle the affect on things you're carrying */
+       (void) unturn_dead(&youmonst);
+       /* last place some monsters around you */
+       mm.x = u.ux;
+       mm.y = u.uy;
+       mkundead(&mm, TRUE, NO_MINVENT);
+    } else if(book2->blessed) {
+       for(mtmp = fmon; mtmp; mtmp = mtmp2) {
+           mtmp2 = mtmp->nmon;         /* tamedog() changes chain */
+           if (DEADMONSTER(mtmp)) continue;
+
+           if (is_undead(mtmp->data) && cansee(mtmp->mx, mtmp->my)) {
+               mtmp->mpeaceful = TRUE;
+               if(sgn(mtmp->data->maligntyp) == sgn(u.ualign.type)
+                  && distu(mtmp->mx, mtmp->my) < 4)
+                   if (mtmp->mtame) {
+                       if (mtmp->mtame < 20)
+                           mtmp->mtame++;
+                   } else
+                       (void) tamedog(mtmp, (struct obj *)0);
+               else monflee(mtmp, 0, FALSE, TRUE);
+           }
+       }
+    } else {
+       switch(rn2(3)) {
+       case 0:
+           Your("ancestors are annoyed with you!");
+           break;
+       case 1:
+           pline_The("headstones in the cemetery begin to move!");
+           break;
+       default:
+           pline("Oh my!  Your name appears in the book!");
+       }
+    }
+    return;
+}
+
+STATIC_PTR int
+learn()
+{
+       int i;
+       short booktype;
+       char splname[BUFSZ];
+       boolean costly = TRUE;
+
+       /* JDS: lenses give 50% faster reading; 33% smaller read time */
+       if (delay && ublindf && ublindf->otyp == LENSES && rn2(2)) delay++;
+       if (Confusion) {                /* became confused while learning */
+           (void) confused_book(book);
+           book = 0;                   /* no longer studying */
+           nomul(delay);               /* remaining delay is uninterrupted */
+           delay = 0;
+           return(0);
+       }
+       if (delay) {    /* not if (delay++), so at end delay == 0 */
+           delay++;
+           return(1); /* still busy */
+       }
+       exercise(A_WIS, TRUE);          /* you're studying. */
+       booktype = book->otyp;
+       if(booktype == SPE_BOOK_OF_THE_DEAD) {
+           deadbook(book);
+           return(0);
+       }
+
+       Sprintf(splname, objects[booktype].oc_name_known ?
+                       "\"%s\"" : "the \"%s\" spell",
+               OBJ_NAME(objects[booktype]));
+       for (i = 0; i < MAXSPELL; i++)  {
+               if (spellid(i) == booktype)  {
+                       if (book->spestudied > MAX_SPELL_STUDY) {
+                           pline("This spellbook is too faint to be read any more.");
+                           book->otyp = booktype = SPE_BLANK_PAPER;
+                       } else if (spellknow(i) <= 1000) {
+                           Your("knowledge of %s is keener.", splname);
+                           incrnknow(i);
+                           book->spestudied++;
+                           exercise(A_WIS,TRUE);       /* extra study */
+                       } else { /* 1000 < spellknow(i) <= MAX_SPELL_STUDY */
+                           You("know %s quite well already.", splname);
+                           costly = FALSE;
+                       }
+                       /* make book become known even when spell is already
+                          known, in case amnesia made you forget the book */
+                       makeknown((int)booktype);
+                       break;
+               } else if (spellid(i) == NO_SPELL)  {
+                       spl_book[i].sp_id = booktype;
+                       spl_book[i].sp_lev = objects[booktype].oc_level;
+                       incrnknow(i);
+                       book->spestudied++;
+                       You(i > 0 ? "add %s to your repertoire." : "learn %s.",
+                           splname);
+                       makeknown((int)booktype);
+                       break;
+               }
+       }
+       if (i == MAXSPELL) impossible("Too many spells memorized!");
+
+       if (book->cursed) {     /* maybe a demon cursed it */
+           if (cursed_book(book)) {
+               useup(book);
+               book = 0;
+               return 0;
+           }
+       }
+       if (costly) check_unpaid(book);
+       book = 0;
+       return(0);
+}
+
+int
+study_book(spellbook)
+register struct obj *spellbook;
+{
+       register int     booktype = spellbook->otyp;
+       register boolean confused = (Confusion != 0);
+       boolean too_hard = FALSE;
+
+       if (delay && !confused && spellbook == book &&
+                   /* handle the sequence: start reading, get interrupted,
+                      have book become erased somehow, resume reading it */
+                   booktype != SPE_BLANK_PAPER) {
+               You("continue your efforts to memorize the spell.");
+       } else {
+               /* KMH -- Simplified this code */
+               if (booktype == SPE_BLANK_PAPER) {
+                       pline("This spellbook is all blank.");
+                       makeknown(booktype);
+                       return(1);
+               }
+               switch (objects[booktype].oc_level) {
+                case 1:
+                case 2:
+                       delay = -objects[booktype].oc_delay;
+                       break;
+                case 3:
+                case 4:
+                       delay = -(objects[booktype].oc_level - 1) *
+                               objects[booktype].oc_delay;
+                       break;
+                case 5:
+                case 6:
+                       delay = -objects[booktype].oc_level *
+                               objects[booktype].oc_delay;
+                       break;
+                case 7:
+                       delay = -8 * objects[booktype].oc_delay;
+                       break;
+                default:
+                       impossible("Unknown spellbook level %d, book %d;",
+                               objects[booktype].oc_level, booktype);
+                       return 0;
+               }
+
+               /* Books are often wiser than their readers (Rus.) */
+               spellbook->in_use = TRUE;
+               if (!spellbook->blessed &&
+                   spellbook->otyp != SPE_BOOK_OF_THE_DEAD) {
+                   if (spellbook->cursed) {
+                       too_hard = TRUE;
+                   } else {
+                       /* uncursed - chance to fail */
+                       int read_ability = ACURR(A_INT) + 4 + u.ulevel/2
+                           - 2*objects[booktype].oc_level
+                           + ((ublindf && ublindf->otyp == LENSES) ? 2 : 0);
+                       /* only wizards know if a spell is too difficult */
+                       if (Role_if(PM_WIZARD) && read_ability < 20 &&
+                           !confused) {
+                           char qbuf[QBUFSZ];
+                           Sprintf(qbuf,
+                     "This spellbook is %sdifficult to comprehend. Continue?",
+                                   (read_ability < 12 ? "very " : ""));
+                           if (yn(qbuf) != 'y') {
+                               spellbook->in_use = FALSE;
+                               return(1);
+                           }
+                       }
+                       /* its up to random luck now */
+                       if (rnd(20) > read_ability) {
+                           too_hard = TRUE;
+                       }
+                   }
+               }
+
+               if (too_hard) {
+                   boolean gone = cursed_book(spellbook);
+
+                   nomul(delay);                       /* study time */
+                   delay = 0;
+                   if(gone || !rn2(3)) {
+                       if (!gone) pline_The("spellbook crumbles to dust!");
+                       if (!objects[spellbook->otyp].oc_name_known &&
+                               !objects[spellbook->otyp].oc_uname)
+                           docall(spellbook);
+                       useup(spellbook);
+                   } else
+                       spellbook->in_use = FALSE;
+                   return(1);
+               } else if (confused) {
+                   if (!confused_book(spellbook)) {
+                       spellbook->in_use = FALSE;
+                   }
+                   nomul(delay);
+                   delay = 0;
+                   return(1);
+               }
+               spellbook->in_use = FALSE;
+
+               You("begin to %s the runes.",
+                   spellbook->otyp == SPE_BOOK_OF_THE_DEAD ? "recite" :
+                   "memorize");
+       }
+
+       book = spellbook;
+       set_occupation(learn, "studying", 0);
+       return(1);
+}
+
+/* a spellbook has been destroyed or the character has changed levels;
+   the stored address for the current book is no longer valid */
+void
+book_disappears(obj)
+struct obj *obj;
+{
+       if (obj == book) book = (struct obj *)0;
+}
+
+/* renaming an object usually results in it having a different address;
+   so the sequence start reading, get interrupted, name the book, resume
+   reading would read the "new" book from scratch */
+void
+book_substitution(old_obj, new_obj)
+struct obj *old_obj, *new_obj;
+{
+       if (old_obj == book) book = new_obj;
+}
+
+/* called from moveloop() */
+void
+age_spells()
+{
+       int i;
+       /*
+        * The time relative to the hero (a pass through move
+        * loop) causes all spell knowledge to be decremented.
+        * The hero's speed, rest status, conscious status etc.
+        * does not alter the loss of memory.
+        */
+       for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++)
+           if (spellknow(i))
+               decrnknow(i);
+       return;
+}
+
+/*
+ * Return TRUE if a spell was picked, with the spell index in the return
+ * parameter.  Otherwise return FALSE.
+ */
+STATIC_OVL boolean
+getspell(spell_no)
+       int *spell_no;
+{
+       int nspells, idx;
+       char ilet, lets[BUFSZ], qbuf[QBUFSZ];
+
+       if (spellid(0) == NO_SPELL)  {
+           You("don't know any spells right now.");
+           return FALSE;
+       }
+       if (flags.menu_style == MENU_TRADITIONAL) {
+           /* we know there is at least 1 known spell */
+           for (nspells = 1; nspells < MAXSPELL
+                           && spellid(nspells) != NO_SPELL; nspells++)
+               continue;
+
+           if (nspells == 1)  Strcpy(lets, "a");
+           else if (nspells < 27)  Sprintf(lets, "a-%c", 'a' + nspells - 1);
+           else if (nspells == 27)  Sprintf(lets, "a-zA");
+           else Sprintf(lets, "a-zA-%c", 'A' + nspells - 27);
+
+           for(;;)  {
+               Sprintf(qbuf, "Cast which spell? [%s ?]", lets);
+               if ((ilet = yn_function(qbuf, (char *)0, '\0')) == '?')
+                   break;
+
+               if (index(quitchars, ilet))
+                   return FALSE;
+
+               idx = spell_let_to_idx(ilet);
+               if (idx >= 0 && idx < nspells) {
+                   *spell_no = idx;
+                   return TRUE;
+               } else
+                   You("don't know that spell.");
+           }
+       }
+       return dospellmenu("Choose which spell to cast",
+                          SPELLMENU_CAST, spell_no);
+}
+
+/* the 'Z' command -- cast a spell */
+int
+docast()
+{
+       int spell_no;
+
+       if (getspell(&spell_no))
+           return spelleffects(spell_no, FALSE);
+       return 0;
+}
+
+STATIC_OVL const char *
+spelltypemnemonic(skill)
+int skill;
+{
+       switch (skill) {
+           case P_ATTACK_SPELL:
+               return "attack";
+           case P_HEALING_SPELL:
+               return "healing";
+           case P_DIVINATION_SPELL:
+               return "divination";
+           case P_ENCHANTMENT_SPELL:
+               return "enchantment";
+           case P_CLERIC_SPELL:
+               return "clerical";
+           case P_ESCAPE_SPELL:
+               return "escape";
+           case P_MATTER_SPELL:
+               return "matter";
+           default:
+               impossible("Unknown spell skill, %d;", skill);
+               return "";
+       }
+}
+
+int
+spell_skilltype(booktype)
+int booktype;
+{
+       return (objects[booktype].oc_skill);
+}
+
+STATIC_OVL void
+cast_protection()
+{
+       int loglev = 0;
+       int l = u.ulevel;
+       int natac = u.uac - u.uspellprot;
+       int gain;
+
+       /* loglev=log2(u.ulevel)+1 (1..5) */
+       while (l) {
+           loglev++;
+           l /= 2;
+       }
+
+       /* The more u.uspellprot you already have, the less you get,
+        * and the better your natural ac, the less you get.
+        *
+        *      LEVEL AC    SPELLPROT from sucessive SPE_PROTECTION casts
+        *      1     10    0,  1,  2,  3,  4
+        *      1      0    0,  1,  2,  3
+        *      1    -10    0,  1,  2
+        *      2-3   10    0,  2,  4,  5,  6,  7,  8
+        *      2-3    0    0,  2,  4,  5,  6
+        *      2-3  -10    0,  2,  3,  4
+        *      4-7   10    0,  3,  6,  8,  9, 10, 11, 12
+        *      4-7    0    0,  3,  5,  7,  8,  9
+        *      4-7  -10    0,  3,  5,  6
+        *      7-15 -10    0,  3,  5,  6
+        *      8-15  10    0,  4,  7, 10, 12, 13, 14, 15, 16
+        *      8-15   0    0,  4,  7,  9, 10, 11, 12
+        *      8-15 -10    0,  4,  6,  7,  8
+        *     16-30  10    0,  5,  9, 12, 14, 16, 17, 18, 19, 20
+        *     16-30   0    0,  5,  9, 11, 13, 14, 15
+        *     16-30 -10    0,  5,  8,  9, 10
+        */
+       gain = loglev - (int)u.uspellprot / (4 - min(3,(10 - natac)/10));
+
+       if (gain > 0) {
+           if (!Blind) {
+               const char *hgolden = hcolor(NH_GOLDEN);
+
+               if (u.uspellprot)
+                   pline_The("%s haze around you becomes more dense.",
+                             hgolden);
+               else
+                   pline_The("%s around you begins to shimmer with %s haze.",
+                       /*[ what about being inside solid rock while polyd? ]*/
+                       (Underwater || Is_waterlevel(&u.uz)) ? "water" : "air",
+                             an(hgolden));
+           }
+           u.uspellprot += gain;
+           u.uspmtime =
+               P_SKILL(spell_skilltype(SPE_PROTECTION)) == P_EXPERT ? 20 : 10;
+           if (!u.usptime)
+               u.usptime = u.uspmtime;
+           find_ac();
+       } else {
+           Your("skin feels warm for a moment.");
+       }
+}
+
+/* attempting to cast a forgotten spell will cause disorientation */
+STATIC_OVL void
+spell_backfire(spell)
+int spell;
+{
+    long duration = (long)((spellev(spell) + 1) * 3);   /* 6..24 */
+
+    /* prior to 3.4.1, the only effect was confusion; it still predominates */
+    switch (rn2(10)) {
+    case 0:
+    case 1:
+    case 2:
+    case 3: make_confused(duration, FALSE);                    /* 40% */
+           break;
+    case 4:
+    case 5:
+    case 6: make_confused(2L * duration / 3L, FALSE);          /* 30% */
+           make_stunned(duration / 3L, FALSE);
+           break;
+    case 7:
+    case 8: make_stunned(2L * duration / 3L, FALSE);           /* 20% */
+           make_confused(duration / 3L, FALSE);
+           break;
+    case 9: make_stunned(duration, FALSE);                     /* 10% */
+           break;
+    }
+    return;
+}
+
+int
+spelleffects(spell, atme)
+int spell;
+boolean atme;
+{
+       int energy, damage, chance, n, intell;
+       int skill, role_skill;
+       boolean confused = (Confusion != 0);
+       struct obj *pseudo;
+       coord cc;
+
+       /*
+        * Spell casting no longer affects knowledge of the spell. A
+        * decrement of spell knowledge is done every turn.
+        */
+       if (spellknow(spell) <= 0) {
+           Your("knowledge of this spell is twisted.");
+           pline("It invokes nightmarish images in your mind...");
+           spell_backfire(spell);
+           return(0);
+       } else if (spellknow(spell) <= 100) {
+           You("strain to recall the spell.");
+       } else if (spellknow(spell) <= 1000) {
+           Your("knowledge of this spell is growing faint.");
+       }
+       energy = (spellev(spell) * 5);    /* 5 <= energy <= 35 */
+
+       if (u.uhunger <= 10 && spellid(spell) != SPE_DETECT_FOOD) {
+               You("are too hungry to cast that spell.");
+               return(0);
+       } else if (ACURR(A_STR) < 4)  {
+               You("lack the strength to cast spells.");
+               return(0);
+       } else if(check_capacity(
+               "Your concentration falters while carrying so much stuff.")) {
+           return (1);
+       } else if (!freehand()) {
+               Your("arms are not free to cast!");
+               return (0);
+       }
+
+       if (u.uhave.amulet) {
+               You_feel("the amulet draining your energy away.");
+               energy += rnd(2*energy);
+       }
+       if(energy > u.uen)  {
+               You("don't have enough energy to cast that spell.");
+               return(0);
+       } else {
+               if (spellid(spell) != SPE_DETECT_FOOD) {
+                       int hungr = energy * 2;
+
+                       /* If hero is a wizard, their current intelligence
+                        * (bonuses + temporary + current)
+                        * affects hunger reduction in casting a spell.
+                        * 1. int = 17-18 no reduction
+                        * 2. int = 16    1/4 hungr
+                        * 3. int = 15    1/2 hungr
+                        * 4. int = 1-14  normal reduction
+                        * The reason for this is:
+                        * a) Intelligence affects the amount of exertion
+                        * in thinking.
+                        * b) Wizards have spent their life at magic and
+                        * understand quite well how to cast spells.
+                        */
+                       intell = acurr(A_INT);
+                       if (!Role_if(PM_WIZARD)) intell = 10;
+                       switch (intell) {
+                               case 25: case 24: case 23: case 22:
+                               case 21: case 20: case 19: case 18:
+                               case 17: hungr = 0; break;
+                               case 16: hungr /= 4; break;
+                               case 15: hungr /= 2; break;
+                       }
+                       /* don't put player (quite) into fainting from
+                        * casting a spell, particularly since they might
+                        * not even be hungry at the beginning; however,
+                        * this is low enough that they must eat before
+                        * casting anything else except detect food
+                        */
+                       if (hungr > u.uhunger-3)
+                               hungr = u.uhunger-3;
+                       morehungry(hungr);
+               }
+       }
+
+       chance = percent_success(spell);
+       if (confused || (rnd(100) > chance)) {
+               You("fail to cast the spell correctly.");
+               u.uen -= energy / 2;
+               flags.botl = 1;
+               return(1);
+       }
+
+       u.uen -= energy;
+       flags.botl = 1;
+       exercise(A_WIS, TRUE);
+       /* pseudo is a temporary "false" object containing the spell stats */
+       pseudo = mksobj(spellid(spell), FALSE, FALSE);
+       pseudo->blessed = pseudo->cursed = 0;
+       pseudo->quan = 20L;                     /* do not let useup get it */
+       /*
+        * Find the skill the hero has in a spell type category.
+        * See spell_skilltype for categories.
+        */
+       skill = spell_skilltype(pseudo->otyp);
+       role_skill = P_SKILL(skill);
+
+       switch(pseudo->otyp)  {
+       /*
+        * At first spells act as expected.  As the hero increases in skill
+        * with the appropriate spell type, some spells increase in their
+        * effects, e.g. more damage, further distance, and so on, without
+        * additional cost to the spellcaster.
+        */
+       case SPE_CONE_OF_COLD:
+       case SPE_FIREBALL:
+           if (role_skill >= P_SKILLED) {
+               if (throwspell()) {
+                   cc.x=u.dx;cc.y=u.dy;
+                   n=rnd(8)+1;
+                   while(n--) {
+                       if(!u.dx && !u.dy && !u.dz) {
+                           if ((damage = zapyourself(pseudo, TRUE)) != 0) {
+                               char buf[BUFSZ];
+                               Sprintf(buf, "zapped %sself with a spell", uhim());
+                               losehp(damage, buf, NO_KILLER_PREFIX);
+                           }
+                       } else {
+                           explode(u.dx, u.dy,
+                                   pseudo->otyp - SPE_MAGIC_MISSILE + 10,
+                                   u.ulevel/2 + 1 + spell_damage_bonus(), 0,
+                                       (pseudo->otyp == SPE_CONE_OF_COLD) ?
+                                               EXPL_FROSTY : EXPL_FIERY);
+                       }
+                       u.dx = cc.x+rnd(3)-2; u.dy = cc.y+rnd(3)-2;
+                       if (!isok(u.dx,u.dy) || !cansee(u.dx,u.dy) ||
+                           IS_STWALL(levl[u.dx][u.dy].typ) || u.uswallow) {
+                           /* Spell is reflected back to center */
+                           u.dx = cc.x;
+                           u.dy = cc.y;
+                       }
+                   }
+               }
+               break;
+           } /* else fall through... */
+
+       /* these spells are all duplicates of wand effects */
+       case SPE_FORCE_BOLT:
+       case SPE_SLEEP:
+       case SPE_MAGIC_MISSILE:
+       case SPE_KNOCK:
+       case SPE_SLOW_MONSTER:
+       case SPE_WIZARD_LOCK:
+       case SPE_DIG:
+       case SPE_TURN_UNDEAD:
+       case SPE_POLYMORPH:
+       case SPE_TELEPORT_AWAY:
+       case SPE_CANCELLATION:
+       case SPE_FINGER_OF_DEATH:
+       case SPE_LIGHT:
+       case SPE_DETECT_UNSEEN:
+       case SPE_HEALING:
+       case SPE_EXTRA_HEALING:
+       case SPE_DRAIN_LIFE:
+       case SPE_STONE_TO_FLESH:
+               if (!(objects[pseudo->otyp].oc_dir == NODIR)) {
+                       if (atme) u.dx = u.dy = u.dz = 0;
+                       else if (!getdir((char *)0)) {
+                           /* getdir cancelled, re-use previous direction */
+                           pline_The("magical energy is released!");
+                       }
+                       if(!u.dx && !u.dy && !u.dz) {
+                           if ((damage = zapyourself(pseudo, TRUE)) != 0) {
+                               char buf[BUFSZ];
+                               Sprintf(buf, "zapped %sself with a spell", uhim());
+                               losehp(damage, buf, NO_KILLER_PREFIX);
+                           }
+                       } else weffects(pseudo);
+               } else weffects(pseudo);
+               update_inventory();     /* spell may modify inventory */
+               break;
+
+       /* these are all duplicates of scroll effects */
+       case SPE_REMOVE_CURSE:
+       case SPE_CONFUSE_MONSTER:
+       case SPE_DETECT_FOOD:
+       case SPE_CAUSE_FEAR:
+               /* high skill yields effect equivalent to blessed scroll */
+               if (role_skill >= P_SKILLED) pseudo->blessed = 1;
+               /* fall through */
+       case SPE_CHARM_MONSTER:
+       case SPE_MAGIC_MAPPING:
+       case SPE_CREATE_MONSTER:
+       case SPE_IDENTIFY:
+               (void) seffects(pseudo);
+               break;
+
+       /* these are all duplicates of potion effects */
+       case SPE_HASTE_SELF:
+       case SPE_DETECT_TREASURE:
+       case SPE_DETECT_MONSTERS:
+       case SPE_LEVITATION:
+       case SPE_RESTORE_ABILITY:
+               /* high skill yields effect equivalent to blessed potion */
+               if (role_skill >= P_SKILLED) pseudo->blessed = 1;
+               /* fall through */
+       case SPE_INVISIBILITY:
+               (void) peffects(pseudo);
+               break;
+
+       case SPE_CURE_BLINDNESS:
+               healup(0, 0, FALSE, TRUE);
+               break;
+       case SPE_CURE_SICKNESS:
+               if (Sick) You("are no longer ill.");
+               if (Slimed) {
+                   pline_The("slime disappears!");
+                   Slimed = 0;
+                /* flags.botl = 1; -- healup() handles this */
+               }
+               healup(0, 0, TRUE, FALSE);
+               break;
+       case SPE_CREATE_FAMILIAR:
+               (void) make_familiar((struct obj *)0, u.ux, u.uy, FALSE);
+               break;
+       case SPE_CLAIRVOYANCE:
+               if (!BClairvoyant)
+                   do_vicinity_map();
+               /* at present, only one thing blocks clairvoyance */
+               else if (uarmh && uarmh->otyp == CORNUTHAUM)
+                   You("sense a pointy hat on top of your %s.",
+                       body_part(HEAD));
+               break;
+       case SPE_PROTECTION:
+               cast_protection();
+               break;
+       case SPE_JUMPING:
+               if (!jump(max(role_skill,1)))
+                       pline(nothing_happens);
+               break;
+       default:
+               impossible("Unknown spell %d attempted.", spell);
+               obfree(pseudo, (struct obj *)0);
+               return(0);
+       }
+
+       /* gain skill for successful cast */
+       use_skill(skill, spellev(spell));
+
+       obfree(pseudo, (struct obj *)0);        /* now, get rid of it */
+       return(1);
+}
+
+/* Choose location where spell takes effect. */
+STATIC_OVL int
+throwspell()
+{
+       coord cc;
+
+       if (u.uinwater) {
+           pline("You're joking! In this weather?"); return 0;
+       } else if (Is_waterlevel(&u.uz)) {
+           You("had better wait for the sun to come out."); return 0;
+       }
+
+       pline("Where do you want to cast the spell?");
+       cc.x = u.ux;
+       cc.y = u.uy;
+       if (getpos(&cc, TRUE, "the desired position") < 0)
+           return 0;   /* user pressed ESC */
+       /* The number of moves from hero to where the spell drops.*/
+       if (distmin(u.ux, u.uy, cc.x, cc.y) > 10) {
+           pline_The("spell dissipates over the distance!");
+           return 0;
+       } else if (u.uswallow) {
+           pline_The("spell is cut short!");
+           exercise(A_WIS, FALSE); /* What were you THINKING! */
+           u.dx = 0;
+           u.dy = 0;
+           return 1;
+       } else if (!cansee(cc.x, cc.y) || IS_STWALL(levl[cc.x][cc.y].typ)) {
+           Your("mind fails to lock onto that location!");
+           return 0;
+       } else {
+           u.dx=cc.x;
+           u.dy=cc.y;
+           return 1;
+       }
+}
+
+void
+losespells()
+{
+       boolean confused = (Confusion != 0);
+       int  n, nzap, i;
+
+       book = 0;
+       for (n = 0; n < MAXSPELL && spellid(n) != NO_SPELL; n++)
+               continue;
+       if (n) {
+               nzap = rnd(n) + confused ? 1 : 0;
+               if (nzap > n) nzap = n;
+               for (i = n - nzap; i < n; i++) {
+                   spellid(i) = NO_SPELL;
+                   exercise(A_WIS, FALSE);     /* ouch! */
+               }
+       }
+}
+
+/* the '+' command -- view known spells */
+int
+dovspell()
+{
+       char qbuf[QBUFSZ];
+       int splnum, othnum;
+       struct spell spl_tmp;
+
+       if (spellid(0) == NO_SPELL)
+           You("don't know any spells right now.");
+       else {
+           while (dospellmenu("Currently known spells",
+                              SPELLMENU_VIEW, &splnum)) {
+               Sprintf(qbuf, "Reordering spells; swap '%c' with",
+                       spellet(splnum));
+               if (!dospellmenu(qbuf, splnum, &othnum)) break;
+
+               spl_tmp = spl_book[splnum];
+               spl_book[splnum] = spl_book[othnum];
+               spl_book[othnum] = spl_tmp;
+           }
+       }
+       return 0;
+}
+
+STATIC_OVL boolean
+dospellmenu(prompt, splaction, spell_no)
+const char *prompt;
+int splaction; /* SPELLMENU_CAST, SPELLMENU_VIEW, or spl_book[] index */
+int *spell_no;
+{
+       winid tmpwin;
+       int i, n, how;
+       char buf[BUFSZ];
+       menu_item *selected;
+       anything any;
+
+       tmpwin = create_nhwindow(NHW_MENU);
+       start_menu(tmpwin);
+       any.a_void = 0;         /* zero out all bits */
+
+       /*
+        * The correct spacing of the columns depends on the
+        * following that (1) the font is monospaced and (2)
+        * that selection letters are pre-pended to the given
+        * string and are of the form "a - ".
+        *
+        * To do it right would require that we implement columns
+        * in the window-ports (say via a tab character).
+        */
+       if (!iflags.menu_tab_sep)
+               Sprintf(buf, "%-20s     Level  %-12s Fail", "    Name", "Category");
+       else
+               Sprintf(buf, "Name\tLevel\tCategory\tFail");
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
+       for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++) {
+               Sprintf(buf, iflags.menu_tab_sep ?
+                       "%s\t%-d%s\t%s\t%-d%%" : "%-20s  %2d%s   %-12s %3d%%",
+                       spellname(i), spellev(i),
+                       spellknow(i) ? " " : "*",
+                       spelltypemnemonic(spell_skilltype(spellid(i))),
+                       100 - percent_success(i));
+
+               any.a_int = i+1;        /* must be non-zero */
+               add_menu(tmpwin, NO_GLYPH, &any,
+                        spellet(i), 0, ATR_NONE, buf,
+                        (i == splaction) ? MENU_SELECTED : MENU_UNSELECTED);
+             }
+       end_menu(tmpwin, prompt);
+
+       how = PICK_ONE;
+       if (splaction == SPELLMENU_VIEW && spellid(1) == NO_SPELL)
+           how = PICK_NONE;    /* only one spell => nothing to swap with */
+       n = select_menu(tmpwin, how, &selected);
+       destroy_nhwindow(tmpwin);
+       if (n > 0) {
+               *spell_no = selected[0].item.a_int - 1;
+               /* menu selection for `PICK_ONE' does not
+                  de-select any preselected entry */
+               if (n > 1 && *spell_no == splaction)
+                   *spell_no = selected[1].item.a_int - 1;
+               free((genericptr_t)selected);
+               /* default selection of preselected spell means that
+                  user chose not to swap it with anything */
+               if (*spell_no == splaction) return FALSE;
+               return TRUE;
+       } else if (splaction >= 0) {
+           /* explicit de-selection of preselected spell means that
+              user is still swapping but not for the current spell */
+           *spell_no = splaction;
+           return TRUE;
+       }
+       return FALSE;
+}
+
+/* Integer square root function without using floating point. */
+STATIC_OVL int
+isqrt(val)
+int val;
+{
+    int rt = 0;
+    int odd = 1;
+    while(val >= odd) {
+       val = val-odd;
+       odd = odd+2;
+       rt = rt + 1;
+    }
+    return rt;
+}
+
+STATIC_OVL int
+percent_success(spell)
+int spell;
+{
+       /* Intrinsic and learned ability are combined to calculate
+        * the probability of player's success at cast a given spell.
+        */
+       int chance, splcaster, special, statused;
+       int difficulty;
+       int skill;
+
+       /* Calculate intrinsic ability (splcaster) */
+
+       splcaster = urole.spelbase;
+       special = urole.spelheal;
+       statused = ACURR(urole.spelstat);
+
+       if (uarm && is_metallic(uarm))
+           splcaster += (uarmc && uarmc->otyp == ROBE) ?
+               urole.spelarmr/2 : urole.spelarmr;
+       else if (uarmc && uarmc->otyp == ROBE)
+           splcaster -= urole.spelarmr;
+       if (uarms) splcaster += urole.spelshld;
+
+       if (uarmh && is_metallic(uarmh) && uarmh->otyp != HELM_OF_BRILLIANCE)
+               splcaster += uarmhbon;
+       if (uarmg && is_metallic(uarmg)) splcaster += uarmgbon;
+       if (uarmf && is_metallic(uarmf)) splcaster += uarmfbon;
+
+       if (spellid(spell) == urole.spelspec)
+               splcaster += urole.spelsbon;
+
+
+       /* `healing spell' bonus */
+       if (spellid(spell) == SPE_HEALING ||
+           spellid(spell) == SPE_EXTRA_HEALING ||
+           spellid(spell) == SPE_CURE_BLINDNESS ||
+           spellid(spell) == SPE_CURE_SICKNESS ||
+           spellid(spell) == SPE_RESTORE_ABILITY ||
+           spellid(spell) == SPE_REMOVE_CURSE) splcaster += special;
+
+       if (splcaster > 20) splcaster = 20;
+
+       /* Calculate learned ability */
+
+       /* Players basic likelihood of being able to cast any spell
+        * is based of their `magic' statistic. (Int or Wis)
+        */
+       chance = 11 * statused / 2;
+
+       /*
+        * High level spells are harder.  Easier for higher level casters.
+        * The difficulty is based on the hero's level and their skill level
+        * in that spell type.
+        */
+       skill = P_SKILL(spell_skilltype(spellid(spell)));
+       skill = max(skill,P_UNSKILLED) - 1;     /* unskilled => 0 */
+       difficulty= (spellev(spell)-1) * 4 - ((skill * 6) + (u.ulevel/3) + 1);
+
+       if (difficulty > 0) {
+               /* Player is too low level or unskilled. */
+               chance -= isqrt(900 * difficulty + 2000);
+       } else {
+               /* Player is above level.  Learning continues, but the
+                * law of diminishing returns sets in quickly for
+                * low-level spells.  That is, a player quickly gains
+                * no advantage for raising level.
+                */
+               int learning = 15 * -difficulty / spellev(spell);
+               chance += learning > 20 ? 20 : learning;
+       }
+
+       /* Clamp the chance: >18 stat and advanced learning only help
+        * to a limit, while chances below "hopeless" only raise the
+        * specter of overflowing 16-bit ints (and permit wearing a
+        * shield to raise the chances :-).
+        */
+       if (chance < 0) chance = 0;
+       if (chance > 120) chance = 120;
+
+       /* Wearing anything but a light shield makes it very awkward
+        * to cast a spell.  The penalty is not quite so bad for the
+        * player's role-specific spell.
+        */
+       if (uarms && weight(uarms) > (int) objects[SMALL_SHIELD].oc_weight) {
+               if (spellid(spell) == urole.spelspec) {
+                       chance /= 2;
+               } else {
+                       chance /= 4;
+               }
+       }
+
+       /* Finally, chance (based on player intell/wisdom and level) is
+        * combined with ability (based on player intrinsics and
+        * encumbrances).  No matter how intelligent/wise and advanced
+        * a player is, intrinsics and encumbrance can prevent casting;
+        * and no matter how able, learning is always required.
+        */
+       chance = chance * (20-splcaster) / 15 - splcaster;
+
+       /* Clamp to percentile */
+       if (chance > 100) chance = 100;
+       if (chance < 0) chance = 0;
+
+       return chance;
+}
+
+
+/* Learn a spell during creation of the initial inventory */
+void
+initialspell(obj)
+struct obj *obj;
+{
+       int i;
+
+       for (i = 0; i < MAXSPELL; i++) {
+           if (spellid(i) == obj->otyp) {
+                pline("Error: Spell %s already known.",
+                               OBJ_NAME(objects[obj->otyp]));
+                return;
+           }
+           if (spellid(i) == NO_SPELL)  {
+               spl_book[i].sp_id = obj->otyp;
+               spl_book[i].sp_lev = objects[obj->otyp].oc_level;
+               incrnknow(i);
+               return;
+           }
+       }
+       impossible("Too many spells memorized!");
+       return;
+}
+
+/*spell.c*/
diff --git a/src/steal.c b/src/steal.c
new file mode 100644 (file)
index 0000000..1feed77
--- /dev/null
@@ -0,0 +1,635 @@
+/*     SCCS Id: @(#)steal.c    3.4     2003/12/04      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+STATIC_PTR int NDECL(stealarm);
+
+#ifdef OVLB
+STATIC_DCL const char *FDECL(equipname, (struct obj *));
+STATIC_DCL void FDECL(mdrop_obj, (struct monst *,struct obj *,BOOLEAN_P));
+
+STATIC_OVL const char *
+equipname(otmp)
+register struct obj *otmp;
+{
+       return (
+#ifdef TOURIST
+               (otmp == uarmu) ? "shirt" :
+#endif
+               (otmp == uarmf) ? "boots" :
+               (otmp == uarms) ? "shield" :
+               (otmp == uarmg) ? "gloves" :
+               (otmp == uarmc) ? cloak_simple_name(otmp) :
+               (otmp == uarmh) ? "helmet" : "armor");
+}
+
+#ifndef GOLDOBJ
+long           /* actually returns something that fits in an int */
+somegold()
+{
+#ifdef LINT    /* long conv. ok */
+       return(0L);
+#else
+       return (long)( (u.ugold < 100) ? u.ugold :
+               (u.ugold > 10000) ? rnd(10000) : rnd((int) u.ugold) );
+#endif
+}
+
+void
+stealgold(mtmp)
+register struct monst *mtmp;
+{
+       register struct obj *gold = g_at(u.ux, u.uy);
+       register long tmp;
+
+       if (gold && ( !u.ugold || gold->quan > u.ugold || !rn2(5))) {
+           mtmp->mgold += gold->quan;
+           delobj(gold);
+           newsym(u.ux, u.uy);
+           pline("%s quickly snatches some gold from between your %s!",
+                   Monnam(mtmp), makeplural(body_part(FOOT)));
+           if(!u.ugold || !rn2(5)) {
+               if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
+               /* do not set mtmp->mavenge here; gold on the floor is fair game */
+               monflee(mtmp, 0, FALSE, FALSE);
+           }
+       } else if(u.ugold) {
+           u.ugold -= (tmp = somegold());
+           Your("purse feels lighter.");
+           mtmp->mgold += tmp;
+       if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
+           mtmp->mavenge = 1;
+           monflee(mtmp, 0, FALSE, FALSE);
+           flags.botl = 1;
+       }
+}
+
+#else /* !GOLDOBJ */
+
+long           /* actually returns something that fits in an int */
+somegold(umoney)
+long umoney;
+{
+#ifdef LINT    /* long conv. ok */
+       return(0L);
+#else
+       return (long)( (umoney < 100) ? umoney :
+               (umoney > 10000) ? rnd(10000) : rnd((int) umoney) );
+#endif
+}
+
+/*
+Find the first (and hopefully only) gold object in a chain.
+Used when leprechaun (or you as leprechaun) looks for
+someone else's gold.  Returns a pointer so the gold may
+be seized without further searching.
+May search containers too.
+Deals in gold only, as leprechauns don't care for lesser coins.
+*/
+struct obj *
+findgold(chain)
+register struct obj *chain;
+{
+        while (chain && chain->otyp != GOLD_PIECE) chain = chain->nobj;
+        return chain;
+}
+
+/* 
+Steal gold coins only.  Leprechauns don't care for lesser coins.
+*/
+void
+stealgold(mtmp)
+register struct monst *mtmp;
+{
+       register struct obj *fgold = g_at(u.ux, u.uy);
+       register struct obj *ygold;
+       register long tmp;
+
+        /* skip lesser coins on the floor */        
+        while (fgold && fgold->otyp != GOLD_PIECE) fgold = fgold->nexthere; 
+
+        /* Do you have real gold? */
+        ygold = findgold(invent);
+
+       if (fgold && ( !ygold || fgold->quan > ygold->quan || !rn2(5))) {
+            obj_extract_self(fgold);
+           add_to_minv(mtmp, fgold);
+           newsym(u.ux, u.uy);
+           pline("%s quickly snatches some gold from between your %s!",
+                   Monnam(mtmp), makeplural(body_part(FOOT)));
+           if(!ygold || !rn2(5)) {
+               if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
+               monflee(mtmp, 0, FALSE, FALSE);
+           }
+       } else if(ygold) {
+            const int gold_price = objects[GOLD_PIECE].oc_cost;
+           tmp = (somegold(money_cnt(invent)) + gold_price - 1) / gold_price;
+           tmp = min(tmp, ygold->quan);
+            if (tmp < ygold->quan) ygold = splitobj(ygold, tmp);
+            freeinv(ygold);
+            add_to_minv(mtmp, ygold);
+           Your("purse feels lighter.");
+           if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
+           monflee(mtmp, 0, FALSE, FALSE);
+           flags.botl = 1;
+       }
+}
+#endif /* GOLDOBJ */
+
+/* steal armor after you finish taking it off */
+unsigned int stealoid;         /* object to be stolen */
+unsigned int stealmid;         /* monster doing the stealing */
+
+STATIC_PTR int
+stealarm()
+{
+       register struct monst *mtmp;
+       register struct obj *otmp;
+
+       for(otmp = invent; otmp; otmp = otmp->nobj) {
+           if(otmp->o_id == stealoid) {
+               for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+                   if(mtmp->m_id == stealmid) {
+                       if(DEADMONSTER(mtmp)) impossible("stealarm(): dead monster stealing"); 
+                       if(!dmgtype(mtmp->data, AD_SITM)) /* polymorphed */
+                           goto botm;
+                       if(otmp->unpaid)
+                           subfrombill(otmp, shop_keeper(*u.ushops));
+                       freeinv(otmp);
+                       pline("%s steals %s!", Monnam(mtmp), doname(otmp));
+                       (void) mpickobj(mtmp,otmp);     /* may free otmp */
+                       /* Implies seduction, "you gladly hand over ..."
+                          so we don't set mavenge bit here. */
+                       monflee(mtmp, 0, FALSE, FALSE);
+                       if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
+                       break;
+                   }
+               }
+               break;
+           }
+       }
+botm:   stealoid = 0;
+       return 0;
+}
+
+/* An object you're wearing has been taken off by a monster (theft or
+   seduction).  Also used if a worn item gets transformed (stone to flesh). */
+void
+remove_worn_item(obj, unchain_ball)
+struct obj *obj;
+boolean unchain_ball;  /* whether to unpunish or just unwield */
+{
+       if (donning(obj))
+           cancel_don();
+       if (!obj->owornmask)
+           return;
+
+       if (obj->owornmask & W_ARMOR) {
+           if (obj == uskin) {
+               impossible("Removing embedded scales?");
+               skinback(TRUE);         /* uarm = uskin; uskin = 0; */
+           }
+           if (obj == uarm) (void) Armor_off();
+           else if (obj == uarmc) (void) Cloak_off();
+           else if (obj == uarmf) (void) Boots_off();
+           else if (obj == uarmg) (void) Gloves_off();
+           else if (obj == uarmh) (void) Helmet_off();
+           else if (obj == uarms) (void) Shield_off();
+#ifdef TOURIST
+           else if (obj == uarmu) (void) Shirt_off();
+#endif
+           /* catchall -- should never happen */
+           else setworn((struct obj *)0, obj->owornmask & W_ARMOR);
+       } else if (obj->owornmask & W_AMUL) {
+           Amulet_off();
+       } else if (obj->owornmask & W_RING) {
+           Ring_gone(obj);
+       } else if (obj->owornmask & W_TOOL) {
+           Blindf_off(obj);
+       } else if (obj->owornmask & (W_WEP|W_SWAPWEP|W_QUIVER)) {
+           if (obj == uwep)
+               uwepgone();
+           if (obj == uswapwep)
+               uswapwepgone();
+           if (obj == uquiver)
+               uqwepgone();
+       }
+
+       if (obj->owornmask & (W_BALL|W_CHAIN)) {
+           if (unchain_ball) unpunish();
+       } else if (obj->owornmask) {
+           /* catchall */
+           setnotworn(obj);
+       }
+}
+
+/* Returns 1 when something was stolen (or at least, when N should flee now)
+ * Returns -1 if the monster died in the attempt
+ * Avoid stealing the object stealoid
+ */
+int
+steal(mtmp, objnambuf)
+struct monst *mtmp;
+char *objnambuf;
+{
+       struct obj *otmp;
+       int tmp, could_petrify, named = 0, armordelay;
+       boolean monkey_business; /* true iff an animal is doing the thievery */
+
+       if (objnambuf) *objnambuf = '\0';
+       /* the following is true if successful on first of two attacks. */
+       if(!monnear(mtmp, u.ux, u.uy)) return(0);
+
+       /* food being eaten might already be used up but will not have
+          been removed from inventory yet; we don't want to steal that,
+          so this will cause it to be removed now */
+       if (occupation) (void) maybe_finished_meal(FALSE);
+
+       if (!invent || (inv_cnt() == 1 && uskin)) {
+nothing_to_steal:
+           /* Not even a thousand men in armor can strip a naked man. */
+           if(Blind)
+             pline("Somebody tries to rob you, but finds nothing to steal.");
+           else
+             pline("%s tries to rob you, but there is nothing to steal!",
+               Monnam(mtmp));
+           return(1);  /* let her flee */
+       }
+
+       monkey_business = is_animal(mtmp->data);
+       if (monkey_business) {
+           ;   /* skip ring special cases */
+       } else if (Adornment & LEFT_RING) {
+           otmp = uleft;
+           goto gotobj;
+       } else if (Adornment & RIGHT_RING) {
+           otmp = uright;
+           goto gotobj;
+       }
+
+       tmp = 0;
+       for(otmp = invent; otmp; otmp = otmp->nobj)
+           if ((!uarm || otmp != uarmc) && otmp != uskin
+#ifdef INVISIBLE_OBJECTS
+                               && (!otmp->oinvis || perceives(mtmp->data))
+#endif
+                               )
+               tmp += ((otmp->owornmask &
+                       (W_ARMOR | W_RING | W_AMUL | W_TOOL)) ? 5 : 1);
+       if (!tmp) goto nothing_to_steal;
+       tmp = rn2(tmp);
+       for(otmp = invent; otmp; otmp = otmp->nobj)
+           if ((!uarm || otmp != uarmc) && otmp != uskin
+#ifdef INVISIBLE_OBJECTS
+                               && (!otmp->oinvis || perceives(mtmp->data))
+#endif
+                       )
+               if((tmp -= ((otmp->owornmask &
+                       (W_ARMOR | W_RING | W_AMUL | W_TOOL)) ? 5 : 1)) < 0)
+                       break;
+       if(!otmp) {
+               impossible("Steal fails!");
+               return(0);
+       }
+       /* can't steal gloves while wielding - so steal the wielded item. */
+       if (otmp == uarmg && uwep)
+           otmp = uwep;
+       /* can't steal armor while wearing cloak - so steal the cloak. */
+       else if(otmp == uarm && uarmc) otmp = uarmc;
+#ifdef TOURIST
+       else if(otmp == uarmu && uarmc) otmp = uarmc;
+       else if(otmp == uarmu && uarm) otmp = uarm;
+#endif
+gotobj:
+       if(otmp->o_id == stealoid) return(0);
+
+       /* animals can't overcome curse stickiness nor unlock chains */
+       if (monkey_business) {
+           boolean ostuck;
+           /* is the player prevented from voluntarily giving up this item?
+              (ignores loadstones; the !can_carry() check will catch those) */
+           if (otmp == uball)
+               ostuck = TRUE;  /* effectively worn; curse is implicit */
+           else if (otmp == uquiver || (otmp == uswapwep && !u.twoweap))
+               ostuck = FALSE; /* not really worn; curse doesn't matter */
+           else
+               ostuck = (otmp->cursed && otmp->owornmask);
+
+           if (ostuck || !can_carry(mtmp, otmp)) {
+               static const char * const how[] = { "steal","snatch","grab","take" };
+ cant_take:
+               pline("%s tries to %s your %s but gives up.",
+                     Monnam(mtmp), how[rn2(SIZE(how))],
+                     (otmp->owornmask & W_ARMOR) ? equipname(otmp) :
+                      cxname(otmp));
+               /* the fewer items you have, the less likely the thief
+                  is going to stick around to try again (0) instead of
+                  running away (1) */
+               return !rn2(inv_cnt() / 5 + 2);
+           }
+       }
+
+       if (otmp->otyp == LEASH && otmp->leashmon) {
+           if (monkey_business && otmp->cursed) goto cant_take;
+           o_unleash(otmp);
+       }
+
+       /* you're going to notice the theft... */
+       stop_occupation();
+
+       if((otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))){
+               switch(otmp->oclass) {
+               case TOOL_CLASS:
+               case AMULET_CLASS:
+               case RING_CLASS:
+               case FOOD_CLASS: /* meat ring */
+                   remove_worn_item(otmp, TRUE);
+                   break;
+               case ARMOR_CLASS:
+                   armordelay = objects[otmp->otyp].oc_delay;
+                   /* Stop putting on armor which has been stolen. */
+                   if (donning(otmp)) {
+                       remove_worn_item(otmp, TRUE);
+                       break;
+                   } else if (monkey_business) {
+                       /* animals usually don't have enough patience
+                          to take off items which require extra time */
+                       if (armordelay >= 1 && rn2(10)) goto cant_take;
+                       remove_worn_item(otmp, TRUE);
+                       break;
+                   } else {
+                       int curssv = otmp->cursed;
+                       int slowly;
+                       boolean seen = canspotmon(mtmp);
+
+                       otmp->cursed = 0;
+                       /* can't charm you without first waking you */
+                       if (multi < 0 && is_fainted()) unmul((char *)0);
+                       slowly = (armordelay >= 1 || multi < 0);
+                       if(flags.female)
+                           pline("%s charms you.  You gladly %s your %s.",
+                                 !seen ? "She" : Monnam(mtmp),
+                                 curssv ? "let her take" :
+                                 slowly ? "start removing" : "hand over",
+                                 equipname(otmp));
+                       else
+                           pline("%s seduces you and %s off your %s.",
+                                 !seen ? "She" : Adjmonnam(mtmp, "beautiful"),
+                                 curssv ? "helps you to take" :
+                                 slowly ? "you start taking" : "you take",
+                                 equipname(otmp));
+                       named++;
+                       /* the following is to set multi for later on */
+                       nomul(-armordelay);
+                       remove_worn_item(otmp, TRUE);
+                       otmp->cursed = curssv;
+                       if(multi < 0){
+                               /*
+                               multi = 0;
+                               nomovemsg = 0;
+                               afternmv = 0;
+                               */
+                               stealoid = otmp->o_id;
+                               stealmid = mtmp->m_id;
+                               afternmv = stealarm;
+                               return(0);
+                       }
+                   }
+                   break;
+               default:
+                   impossible("Tried to steal a strange worn thing. [%d]",
+                              otmp->oclass);
+               }
+       }
+       else if (otmp->owornmask)
+           remove_worn_item(otmp, TRUE);
+
+       /* do this before removing it from inventory */
+       if (objnambuf) Strcpy(objnambuf, yname(otmp));
+       /* set mavenge bit so knights won't suffer an
+        * alignment penalty during retaliation;
+        */
+       mtmp->mavenge = 1;
+
+       freeinv(otmp);
+       pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp));
+       could_petrify = (otmp->otyp == CORPSE &&
+                        touch_petrifies(&mons[otmp->corpsenm]));
+       (void) mpickobj(mtmp,otmp);     /* may free otmp */
+       if (could_petrify && !(mtmp->misc_worn_check & W_ARMG)) {
+           minstapetrify(mtmp, TRUE);
+           return -1;
+       }
+       return((multi < 0) ? 0 : 1);
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+/* Returns 1 if otmp is free'd, 0 otherwise. */
+int
+mpickobj(mtmp,otmp)
+register struct monst *mtmp;
+register struct obj *otmp;
+{
+    int freed_otmp;
+
+#ifndef GOLDOBJ
+    if (otmp->oclass == COIN_CLASS) {
+       mtmp->mgold += otmp->quan;
+       obfree(otmp, (struct obj *)0);
+       freed_otmp = 1;
+    } else {
+#endif
+    boolean snuff_otmp = FALSE;
+    /* don't want hidden light source inside the monster; assumes that
+       engulfers won't have external inventories; whirly monsters cause
+       the light to be extinguished rather than letting it shine thru */
+    if (otmp->lamplit &&  /* hack to avoid function calls for most objs */
+       obj_sheds_light(otmp) &&
+       attacktype(mtmp->data, AT_ENGL)) {
+       /* this is probably a burning object that you dropped or threw */
+       if (u.uswallow && mtmp == u.ustuck && !Blind)
+           pline("%s out.", Tobjnam(otmp, "go"));
+       snuff_otmp = TRUE;
+    }
+    /* Must do carrying effects on object prior to add_to_minv() */
+    carry_obj_effects(otmp);
+    /* add_to_minv() might free otmp [if merged with something else],
+       so we have to call it after doing the object checks */
+    freed_otmp = add_to_minv(mtmp, otmp);
+    /* and we had to defer this until object is in mtmp's inventory */
+    if (snuff_otmp) snuff_light_source(mtmp->mx, mtmp->my);
+#ifndef GOLDOBJ
+    }
+#endif
+    return freed_otmp;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+void
+stealamulet(mtmp)
+struct monst *mtmp;
+{
+    struct obj *otmp = (struct obj *)0;
+    int real=0, fake=0;
+
+    /* select the artifact to steal */
+    if(u.uhave.amulet) {
+       real = AMULET_OF_YENDOR;
+       fake = FAKE_AMULET_OF_YENDOR;
+    } else if(u.uhave.questart) {
+       for(otmp = invent; otmp; otmp = otmp->nobj)
+           if(is_quest_artifact(otmp)) break;
+       if (!otmp) return;      /* should we panic instead? */
+    } else if(u.uhave.bell) {
+       real = BELL_OF_OPENING;
+       fake = BELL;
+    } else if(u.uhave.book) {
+       real = SPE_BOOK_OF_THE_DEAD;
+    } else if(u.uhave.menorah) {
+       real = CANDELABRUM_OF_INVOCATION;
+    } else return;     /* you have nothing of special interest */
+
+    if (!otmp) {
+       /* If we get here, real and fake have been set up. */
+       for(otmp = invent; otmp; otmp = otmp->nobj)
+           if(otmp->otyp == real || (otmp->otyp == fake && !mtmp->iswiz))
+               break;
+    }
+
+    if (otmp) { /* we have something to snatch */
+       if (otmp->owornmask)
+           remove_worn_item(otmp, TRUE);
+       freeinv(otmp);
+       /* mpickobj wont merge otmp because none of the above things
+          to steal are mergable */
+       (void) mpickobj(mtmp,otmp);     /* may merge and free otmp */
+       pline("%s stole %s!", Monnam(mtmp), doname(otmp));
+       if (can_teleport(mtmp->data) && !tele_restrict(mtmp))
+           (void) rloc(mtmp, FALSE);
+    }
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+/* drop one object taken from a (possibly dead) monster's inventory */
+STATIC_OVL void
+mdrop_obj(mon, obj, verbosely)
+struct monst *mon;
+struct obj *obj;
+boolean verbosely;
+{
+    int omx = mon->mx, omy = mon->my;
+
+    if (obj->owornmask) {
+       /* perform worn item handling if the monster is still alive */
+       if (mon->mhp > 0) {
+           mon->misc_worn_check &= ~obj->owornmask;
+           update_mon_intrinsics(mon, obj, FALSE, TRUE);
+        /* obj_no_longer_held(obj); -- done by place_object */
+           if (obj->owornmask & W_WEP) setmnotwielded(mon, obj);
+#ifdef STEED
+       /* don't charge for an owned saddle on dead steed */
+       } else if (mon->mtame && (obj->owornmask & W_SADDLE) && 
+               !obj->unpaid && costly_spot(omx, omy)) {
+           obj->no_charge = 1;
+#endif
+       }
+       obj->owornmask = 0L;
+    }
+    if (verbosely && cansee(omx, omy))
+       pline("%s drops %s.", Monnam(mon), distant_name(obj, doname));
+    if (!flooreffects(obj, omx, omy, "fall")) {
+       place_object(obj, omx, omy);
+       stackobj(obj);
+    }
+}
+
+/* some monsters bypass the normal rules for moving between levels or
+   even leaving the game entirely; when that happens, prevent them from
+   taking the Amulet or invocation tools with them */
+void
+mdrop_special_objs(mon)
+struct monst *mon;
+{
+    struct obj *obj, *otmp;
+
+    for (obj = mon->minvent; obj; obj = otmp) {
+       otmp = obj->nobj;
+       /* the Amulet, invocation tools, and Rider corpses resist even when
+          artifacts and ordinary objects are given 0% resistance chance */
+       if (obj_resists(obj, 0, 0)) {
+           obj_extract_self(obj);
+           mdrop_obj(mon, obj, FALSE);
+       }
+    }
+}
+
+/* release the objects the creature is carrying */
+void
+relobj(mtmp,show,is_pet)
+register struct monst *mtmp;
+register int show;
+boolean is_pet;                /* If true, pet should keep wielded/worn items */
+{
+       register struct obj *otmp;
+       register int omx = mtmp->mx, omy = mtmp->my;
+       struct obj *keepobj = 0;
+       struct obj *wep = MON_WEP(mtmp);
+       boolean item1 = FALSE, item2 = FALSE;
+
+       if (!is_pet || mindless(mtmp->data) || is_animal(mtmp->data))
+               item1 = item2 = TRUE;
+       if (!tunnels(mtmp->data) || !needspick(mtmp->data))
+               item1 = TRUE;
+
+       while ((otmp = mtmp->minvent) != 0) {
+               obj_extract_self(otmp);
+               /* special case: pick-axe and unicorn horn are non-worn */
+               /* items that we also want pets to keep 1 of */
+               /* (It is a coincidence that these can also be wielded.) */
+               if (otmp->owornmask || otmp == wep ||
+                   ((!item1 && otmp->otyp == PICK_AXE) ||
+                    (!item2 && otmp->otyp == UNICORN_HORN && !otmp->cursed))) {
+                       if (is_pet) { /* dont drop worn/wielded item */
+                               if (otmp->otyp == PICK_AXE)
+                                       item1 = TRUE;
+                               if (otmp->otyp == UNICORN_HORN && !otmp->cursed)
+                                       item2 = TRUE;
+                               otmp->nobj = keepobj;
+                               keepobj = otmp;
+                               continue;
+                       }
+               }
+               mdrop_obj(mtmp, otmp, is_pet && flags.verbose);
+       }
+
+       /* put kept objects back */
+       while ((otmp = keepobj) != (struct obj *)0) {
+           keepobj = otmp->nobj;
+           (void) add_to_minv(mtmp, otmp);
+       }
+#ifndef GOLDOBJ
+       if (mtmp->mgold) {
+               register long g = mtmp->mgold;
+               (void) mkgold(g, omx, omy);
+               if (is_pet && cansee(omx, omy) && flags.verbose)
+                       pline("%s drops %ld gold piece%s.", Monnam(mtmp),
+                               g, plur(g));
+               mtmp->mgold = 0L;
+       }
+#endif
+       
+       if (show & cansee(omx, omy))
+               newsym(omx, omy);
+}
+
+#endif /* OVL0 */
+
+/*steal.c*/
diff --git a/src/steed.c b/src/steed.c
new file mode 100644 (file)
index 0000000..52e97dc
--- /dev/null
@@ -0,0 +1,641 @@
+/*     SCCS Id: @(#)steed.c    3.4     2003/01/10      */
+/* Copyright (c) Kevin Hugo, 1998-1999. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+
+#ifdef STEED
+
+/* Monsters that might be ridden */
+static NEARDATA const char steeds[] = {
+       S_QUADRUPED, S_UNICORN, S_ANGEL, S_CENTAUR, S_DRAGON, S_JABBERWOCK, '\0'
+};
+
+STATIC_DCL boolean FDECL(landing_spot, (coord *, int, int));
+
+/* caller has decided that hero can't reach something while mounted */
+void
+rider_cant_reach()
+{
+     You("aren't skilled enough to reach from %s.", y_monnam(u.usteed));
+}
+
+/*** Putting the saddle on ***/
+
+/* Can this monster wear a saddle? */
+boolean
+can_saddle(mtmp)
+       struct monst *mtmp;
+{
+       struct permonst *ptr = mtmp->data;
+
+       return (index(steeds, ptr->mlet) && (ptr->msize >= MZ_MEDIUM) &&
+                       (!humanoid(ptr) || ptr->mlet == S_CENTAUR) &&
+                       !amorphous(ptr) && !noncorporeal(ptr) &&
+                       !is_whirly(ptr) && !unsolid(ptr));
+}
+
+
+int
+use_saddle(otmp)
+       struct obj *otmp;
+{
+       struct monst *mtmp;
+       struct permonst *ptr;
+       int chance;
+       const char *s;
+
+
+       /* Can you use it? */
+       if (nohands(youmonst.data)) {
+               You("have no hands!");  /* not `body_part(HAND)' */
+               return 0;
+       } else if (!freehand()) {
+               You("have no free %s.", body_part(HAND));
+               return 0;
+       }
+
+       /* Select an animal */
+       if (u.uswallow || Underwater || !getdir((char *)0)) {
+           pline(Never_mind);
+           return 0;
+       }
+       if (!u.dx && !u.dy) {
+           pline("Saddle yourself?  Very funny...");
+           return 0;
+       }
+       if (!isok(u.ux+u.dx, u.uy+u.dy) ||
+                       !(mtmp = m_at(u.ux+u.dx, u.uy+u.dy)) ||
+                       !canspotmon(mtmp)) {
+           pline("I see nobody there.");
+           return 1;
+       }
+
+       /* Is this a valid monster? */
+       if (mtmp->misc_worn_check & W_SADDLE ||
+                       which_armor(mtmp, W_SADDLE)) {
+           pline("%s doesn't need another one.", Monnam(mtmp));
+           return 1;
+       }
+       ptr = mtmp->data;
+       if (touch_petrifies(ptr) && !uarmg && !Stone_resistance) {
+           char kbuf[BUFSZ];
+
+           You("touch %s.", mon_nam(mtmp));
+           if (!(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
+               Sprintf(kbuf, "attempting to saddle %s", an(mtmp->data->mname));
+               instapetrify(kbuf);
+           }
+       }
+       if (ptr == &mons[PM_INCUBUS] || ptr == &mons[PM_SUCCUBUS]) {
+           pline("Shame on you!");
+           exercise(A_WIS, FALSE);
+           return 1;
+       }
+       if (mtmp->isminion || mtmp->isshk || mtmp->ispriest ||
+                       mtmp->isgd || mtmp->iswiz) {
+           pline("I think %s would mind.", mon_nam(mtmp));
+           return 1;
+       }
+       if (!can_saddle(mtmp)) {
+               You_cant("saddle such a creature.");
+               return 1;
+       }
+
+       /* Calculate your chance */
+       chance = ACURR(A_DEX) + ACURR(A_CHA)/2 + 2*mtmp->mtame;
+       chance += u.ulevel * (mtmp->mtame ? 20 : 5);
+       if (!mtmp->mtame) chance -= 10*mtmp->m_lev;
+       if (Role_if(PM_KNIGHT))
+           chance += 20;
+       switch (P_SKILL(P_RIDING)) {
+       case P_ISRESTRICTED:
+       case P_UNSKILLED:
+       default:
+           chance -= 20;       break;
+       case P_BASIC:
+           break;
+       case P_SKILLED:
+           chance += 15;       break;
+       case P_EXPERT:
+           chance += 30;       break;
+       }
+       if (Confusion || Fumbling || Glib)
+           chance -= 20;
+       else if (uarmg &&
+               (s = OBJ_DESCR(objects[uarmg->otyp])) != (char *)0 &&
+               !strncmp(s, "riding ", 7))
+           /* Bonus for wearing "riding" (but not fumbling) gloves */
+           chance += 10;
+       else if (uarmf &&
+               (s = OBJ_DESCR(objects[uarmf->otyp])) != (char *)0 &&
+               !strncmp(s, "riding ", 7))
+           /* ... or for "riding boots" */
+           chance += 10;
+       if (otmp->cursed)
+           chance -= 50;
+
+       /* Make the attempt */
+       if (rn2(100) < chance) {
+           You("put the saddle on %s.", mon_nam(mtmp));
+           if (otmp->owornmask) remove_worn_item(otmp, FALSE);
+           freeinv(otmp);
+           /* mpickobj may free otmp it if merges, but we have already
+              checked for a saddle above, so no merger should happen */
+           (void) mpickobj(mtmp, otmp);
+           mtmp->misc_worn_check |= W_SADDLE;
+           otmp->owornmask = W_SADDLE;
+           otmp->leashmon = mtmp->m_id;
+           update_mon_intrinsics(mtmp, otmp, TRUE, FALSE);
+       } else
+           pline("%s resists!", Monnam(mtmp));
+       return 1;
+}
+
+
+/*** Riding the monster ***/
+
+/* Can we ride this monster?  Caller should also check can_saddle() */
+boolean
+can_ride(mtmp)
+       struct monst *mtmp;
+{
+       return (mtmp->mtame && humanoid(youmonst.data) &&
+                       !verysmall(youmonst.data) && !bigmonst(youmonst.data) &&
+                       (!Underwater || is_swimmer(mtmp->data)));
+}
+
+
+int
+doride()
+{
+       boolean forcemount = FALSE;
+
+       if (u.usteed)
+           dismount_steed(DISMOUNT_BYCHOICE);
+       else if (getdir((char *)0) && isok(u.ux+u.dx, u.uy+u.dy)) {
+#ifdef WIZARD
+       if (wizard && yn("Force the mount to succeed?") == 'y')
+               forcemount = TRUE;
+#endif
+           return (mount_steed(m_at(u.ux+u.dx, u.uy+u.dy), forcemount));
+       } else
+           return 0;
+       return 1;
+}
+
+
+/* Start riding, with the given monster */
+boolean
+mount_steed(mtmp, force)
+       struct monst *mtmp;     /* The animal */
+       boolean force;          /* Quietly force this animal */
+{
+       struct obj *otmp;
+       char buf[BUFSZ];
+       struct permonst *ptr;
+
+       /* Sanity checks */
+       if (u.usteed) {
+           You("are already riding %s.", mon_nam(u.usteed));
+           return (FALSE);
+       }
+
+       /* Is the player in the right form? */
+       if (Hallucination && !force) {
+           pline("Maybe you should find a designated driver.");
+           return (FALSE);
+       }
+       /* While riding Wounded_legs refers to the steed's,
+        * not the hero's legs.
+        * That opens up a potential abuse where the player
+        * can mount a steed, then dismount immediately to
+        * heal leg damage, because leg damage is always
+        * healed upon dismount (Wounded_legs context switch).
+        * By preventing a hero with Wounded_legs from
+        * mounting a steed, the potential for abuse is
+        * minimized, if not eliminated altogether.
+        */
+       if (Wounded_legs) {
+           Your("%s are in no shape for riding.", makeplural(body_part(LEG)));
+#ifdef WIZARD
+           if (force && wizard && yn("Heal your legs?") == 'y')
+               HWounded_legs = EWounded_legs = 0;
+           else
+#endif
+           return (FALSE);
+       }
+
+       if (Upolyd && (!humanoid(youmonst.data) || verysmall(youmonst.data) ||
+                       bigmonst(youmonst.data) || slithy(youmonst.data))) {
+           You("won't fit on a saddle.");
+           return (FALSE);
+       }
+       if(!force && (near_capacity() > SLT_ENCUMBER)) {
+           You_cant("do that while carrying so much stuff.");
+           return (FALSE);
+       }
+
+       /* Can the player reach and see the monster? */
+       if (!mtmp || (!force && ((Blind && !Blind_telepat) ||
+               mtmp->mundetected ||
+               mtmp->m_ap_type == M_AP_FURNITURE ||
+               mtmp->m_ap_type == M_AP_OBJECT))) {
+           pline("I see nobody there.");
+           return (FALSE);
+       }
+       if (u.uswallow || u.ustuck || u.utrap || Punished ||
+           !test_move(u.ux, u.uy, mtmp->mx-u.ux, mtmp->my-u.uy, TEST_MOVE)) {
+           if (Punished || !(u.uswallow || u.ustuck || u.utrap))
+               You("are unable to swing your %s over.", body_part(LEG)); 
+           else
+               You("are stuck here for now.");
+           return (FALSE);
+       }
+
+       /* Is this a valid monster? */
+       otmp = which_armor(mtmp, W_SADDLE);
+       if (!otmp) {
+           pline("%s is not saddled.", Monnam(mtmp));
+           return (FALSE);
+       }
+       ptr = mtmp->data;
+       if (touch_petrifies(ptr) && !Stone_resistance) {
+           char kbuf[BUFSZ];
+
+           You("touch %s.", mon_nam(mtmp));
+           Sprintf(kbuf, "attempting to ride %s", an(mtmp->data->mname));
+           instapetrify(kbuf);
+       }
+       if (!mtmp->mtame || mtmp->isminion) {
+           pline("I think %s would mind.", mon_nam(mtmp));
+           return (FALSE);
+       }
+       if (mtmp->mtrapped) {
+           struct trap *t = t_at(mtmp->mx, mtmp->my);
+
+           You_cant("mount %s while %s's trapped in %s.",
+                    mon_nam(mtmp), mhe(mtmp),
+                    an(defsyms[trap_to_defsym(t->ttyp)].explanation));
+           return (FALSE);
+       }
+
+       if (!force && !Role_if(PM_KNIGHT) && !(--mtmp->mtame)) {
+           /* no longer tame */
+           newsym(mtmp->mx, mtmp->my);
+           pline("%s resists%s!", Monnam(mtmp),
+                 mtmp->mleashed ? " and its leash comes off" : "");
+           if (mtmp->mleashed) m_unleash(mtmp, FALSE);
+           return (FALSE);
+       }
+       if (!force && Underwater && !is_swimmer(ptr)) {
+           You_cant("ride that creature while under water.");
+           return (FALSE);
+       }
+       if (!can_saddle(mtmp) || !can_ride(mtmp)) {
+           You_cant("ride such a creature.");
+           return (0);
+       }
+
+       /* Is the player impaired? */
+       if (!force && !is_floater(ptr) && !is_flyer(ptr) &&
+                       Levitation && !Lev_at_will) {
+           You("cannot reach %s.", mon_nam(mtmp));
+           return (FALSE);
+       }
+       if (!force && uarm && is_metallic(uarm) &&
+                       greatest_erosion(uarm)) {
+           Your("%s armor is too stiff to be able to mount %s.",
+                       uarm->oeroded ? "rusty" : "corroded",
+                       mon_nam(mtmp));
+           return (FALSE);
+       }
+       if (!force && (Confusion || Fumbling || Glib || Wounded_legs ||
+               otmp->cursed || (u.ulevel+mtmp->mtame < rnd(MAXULEV/2+5)))) {
+           if (Levitation) {
+               pline("%s slips away from you.", Monnam(mtmp));
+               return FALSE;
+           }
+           You("slip while trying to get on %s.", mon_nam(mtmp));
+
+           Sprintf(buf, "slipped while mounting %s",
+                   /* "a saddled mumak" or "a saddled pony called Dobbin" */
+                   x_monnam(mtmp, ARTICLE_A, (char *)0,
+                       SUPPRESS_IT|SUPPRESS_INVISIBLE|SUPPRESS_HALLUCINATION,
+                            TRUE));
+           losehp(rn1(5,10), buf, NO_KILLER_PREFIX);
+           return (FALSE);
+       }
+
+       /* Success */
+       if (!force) {
+           if (Levitation && !is_floater(ptr) && !is_flyer(ptr))
+               /* Must have Lev_at_will at this point */
+               pline("%s magically floats up!", Monnam(mtmp));
+           You("mount %s.", mon_nam(mtmp));
+       }
+       /* setuwep handles polearms differently when you're mounted */
+       if (uwep && is_pole(uwep)) unweapon = FALSE;
+       u.usteed = mtmp;
+       remove_monster(mtmp->mx, mtmp->my);
+       teleds(mtmp->mx, mtmp->my, TRUE);
+       return (TRUE);
+}
+
+
+/* You and your steed have moved */
+void
+exercise_steed()
+{
+       if (!u.usteed)
+               return;
+
+       /* It takes many turns of riding to exercise skill */
+       if (u.urideturns++ >= 100) {
+           u.urideturns = 0;
+           use_skill(P_RIDING, 1);
+       }
+       return;
+}
+
+
+/* The player kicks or whips the steed */
+void
+kick_steed()
+{
+       char He[4];
+       if (!u.usteed)
+           return;
+
+       /* [ALI] Various effects of kicking sleeping/paralyzed steeds */
+       if (u.usteed->msleeping || !u.usteed->mcanmove) {
+           /* We assume a message has just been output of the form
+            * "You kick <steed>."
+            */
+           Strcpy(He, mhe(u.usteed));
+           *He = highc(*He);
+           if ((u.usteed->mcanmove || u.usteed->mfrozen) && !rn2(2)) {
+               if (u.usteed->mcanmove)
+                   u.usteed->msleeping = 0;
+               else if (u.usteed->mfrozen > 2)
+                   u.usteed->mfrozen -= 2;
+               else {
+                   u.usteed->mfrozen = 0;
+                   u.usteed->mcanmove = 1;
+               }
+               if (u.usteed->msleeping || !u.usteed->mcanmove)
+                   pline("%s stirs.", He);
+               else
+                   pline("%s rouses %sself!", He, mhim(u.usteed));
+           } else
+               pline("%s does not respond.", He);
+           return;
+       }
+
+       /* Make the steed less tame and check if it resists */
+       if (u.usteed->mtame) u.usteed->mtame--;
+       if (!u.usteed->mtame && u.usteed->mleashed) m_unleash(u.usteed, TRUE);
+       if (!u.usteed->mtame || (u.ulevel+u.usteed->mtame < rnd(MAXULEV/2+5))) {
+           newsym(u.usteed->mx, u.usteed->my);
+           dismount_steed(DISMOUNT_THROWN);
+           return;
+       }
+
+       pline("%s gallops!", Monnam(u.usteed));
+       u.ugallop += rn1(20, 30);
+       return;
+}
+
+/*
+ * Try to find a dismount point adjacent to the steed's location.
+ * If all else fails, try enexto().  Use enexto() as a last resort because
+ * enexto() chooses its point randomly, possibly even outside the
+ * room's walls, which is not what we want.
+ * Adapted from mail daemon code.
+ */
+STATIC_OVL boolean
+landing_spot(spot, reason, forceit)
+coord *spot;   /* landing position (we fill it in) */
+int reason;
+int forceit;
+{
+    int i = 0, x, y, distance, min_distance = -1;
+    boolean found = FALSE;
+    struct trap *t;
+
+    /* avoid known traps (i == 0) and boulders, but allow them as a backup */
+    if (reason != DISMOUNT_BYCHOICE || Stunned || Confusion || Fumbling) i = 1;
+    for (; !found && i < 2; ++i) {
+       for (x = u.ux-1; x <= u.ux+1; x++)
+           for (y = u.uy-1; y <= u.uy+1; y++) {
+               if (!isok(x, y) || (x == u.ux && y == u.uy)) continue;
+
+               if (ACCESSIBLE(levl[x][y].typ) &&
+                           !MON_AT(x,y) && !closed_door(x,y)) {
+                   distance = distu(x,y);
+                   if (min_distance < 0 || distance < min_distance ||
+                           (distance == min_distance && rn2(2))) {
+                       if (i > 0 || (((t = t_at(x, y)) == 0 || !t->tseen) &&
+                                     (!sobj_at(BOULDER, x, y) ||
+                                      throws_rocks(youmonst.data)))) {
+                           spot->x = x;
+                           spot->y = y;
+                           min_distance = distance;
+                           found = TRUE;
+                       }
+                   }
+               }
+           }
+    }
+
+    /* If we didn't find a good spot and forceit is on, try enexto(). */
+    if (forceit && min_distance < 0 &&
+               !enexto(spot, u.ux, u.uy, youmonst.data))
+       return FALSE;
+
+    return found;
+}
+
+/* Stop riding the current steed */
+void
+dismount_steed(reason)
+       int reason;             /* Player was thrown off etc. */
+{
+       struct monst *mtmp;
+       struct obj *otmp;
+       coord cc;
+       const char *verb = "fall";
+       boolean repair_leg_damage = TRUE;
+       unsigned save_utrap = u.utrap;
+       boolean have_spot = landing_spot(&cc,reason,0);
+       
+       mtmp = u.usteed;                /* make a copy of steed pointer */
+       /* Sanity check */
+       if (!mtmp)              /* Just return silently */
+           return;
+
+       /* Check the reason for dismounting */
+       otmp = which_armor(mtmp, W_SADDLE);
+       switch (reason) {
+           case DISMOUNT_THROWN:
+               verb = "are thrown";
+           case DISMOUNT_FELL:
+               You("%s off of %s!", verb, mon_nam(mtmp));
+               if (!have_spot) have_spot = landing_spot(&cc,reason,1);
+               losehp(rn1(10,10), "riding accident", KILLED_BY_AN);
+               set_wounded_legs(BOTH_SIDES, (int)HWounded_legs + rn1(5,5));
+               repair_leg_damage = FALSE;
+               break;
+           case DISMOUNT_POLY:
+               You("can no longer ride %s.", mon_nam(u.usteed));
+               if (!have_spot) have_spot = landing_spot(&cc,reason,1);
+               break;
+           case DISMOUNT_ENGULFED:
+               /* caller displays message */
+               break;
+           case DISMOUNT_BONES:
+               /* hero has just died... */
+               break;
+           case DISMOUNT_GENERIC:
+               /* no messages, just make it so */
+               break;
+           case DISMOUNT_BYCHOICE:
+           default:
+               if (otmp && otmp->cursed) {
+                   You("can't.  The saddle %s cursed.",
+                       otmp->bknown ? "is" : "seems to be");
+                   otmp->bknown = TRUE;
+                   return;
+               }
+               if (!have_spot) {
+                   You("can't. There isn't anywhere for you to stand.");
+                   return;
+               }
+               if (!mtmp->mnamelth) {
+                       pline("You've been through the dungeon on %s with no name.",
+                               an(mtmp->data->mname));
+                       if (Hallucination)
+                               pline("It felt good to get out of the rain.");
+               } else
+                       You("dismount %s.", mon_nam(mtmp));
+       }
+       /* While riding these refer to the steed's legs
+        * so after dismounting they refer to the player's
+        * legs once again.
+        */
+       if (repair_leg_damage) HWounded_legs = EWounded_legs = 0;
+
+       /* Release the steed and saddle */
+       u.usteed = 0;
+       u.ugallop = 0L;
+
+       /* Set player and steed's position.  Try moving the player first
+          unless we're in the midst of creating a bones file. */
+       if (reason == DISMOUNT_BONES) {
+           /* move the steed to an adjacent square */
+           if (enexto(&cc, u.ux, u.uy, mtmp->data))
+               rloc_to(mtmp, cc.x, cc.y);
+           else        /* evidently no room nearby; move steed elsewhere */
+               (void) rloc(mtmp, FALSE);
+           return;
+       }
+       if (!DEADMONSTER(mtmp)) {
+           place_monster(mtmp, u.ux, u.uy);
+           if (!u.uswallow && !u.ustuck && have_spot) {
+               struct permonst *mdat = mtmp->data;
+
+               /* The steed may drop into water/lava */
+               if (!is_flyer(mdat) && !is_floater(mdat) && !is_clinger(mdat)) {
+                   if (is_pool(u.ux, u.uy)) {
+                       if (!Underwater)
+                           pline("%s falls into the %s!", Monnam(mtmp),
+                                                       surface(u.ux, u.uy));
+                       if (!is_swimmer(mdat) && !amphibious(mdat)) {
+                           killed(mtmp);
+                           adjalign(-1);
+                       }
+                   } else if (is_lava(u.ux, u.uy)) {
+                       pline("%s is pulled into the lava!", Monnam(mtmp));
+                       if (!likes_lava(mdat)) {
+                           killed(mtmp);
+                           adjalign(-1);
+                       }
+                   }
+               }
+           /* Steed dismounting consists of two steps: being moved to another
+            * square, and descending to the floor.  We have functions to do
+            * each of these activities, but they're normally called
+            * individually and include an attempt to look at or pick up the
+            * objects on the floor:
+            * teleds() --> spoteffects() --> pickup()
+            * float_down() --> pickup()
+            * We use this kludge to make sure there is only one such attempt.
+            *
+            * Clearly this is not the best way to do it.  A full fix would
+            * involve having these functions not call pickup() at all, instead
+            * calling them first and calling pickup() afterwards.  But it
+            * would take a lot of work to keep this change from having any
+            * unforseen side effects (for instance, you would no longer be
+            * able to walk onto a square with a hole, and autopickup before
+            * falling into the hole).
+            */
+               /* [ALI] No need to move the player if the steed died. */
+               if (!DEADMONSTER(mtmp)) {
+                   /* Keep steed here, move the player to cc;
+                    * teleds() clears u.utrap
+                    */
+                   in_steed_dismounting = TRUE;
+                   teleds(cc.x, cc.y, TRUE);
+                   in_steed_dismounting = FALSE;
+
+                   /* Put your steed in your trap */
+                   if (save_utrap)
+                       (void) mintrap(mtmp);
+               }
+           /* Couldn't... try placing the steed */
+           } else if (enexto(&cc, u.ux, u.uy, mtmp->data)) {
+               /* Keep player here, move the steed to cc */
+               rloc_to(mtmp, cc.x, cc.y);
+               /* Player stays put */
+           /* Otherwise, kill the steed */
+           } else {
+               killed(mtmp);
+               adjalign(-1);
+           }
+       }
+
+       /* Return the player to the floor */
+       if (reason != DISMOUNT_ENGULFED) {
+           in_steed_dismounting = TRUE;
+           (void) float_down(0L, W_SADDLE);
+           in_steed_dismounting = FALSE;
+           flags.botl = 1;
+           (void)encumber_msg();
+           vision_full_recalc = 1;
+       } else
+           flags.botl = 1;
+       /* polearms behave differently when not mounted */
+       if (uwep && is_pole(uwep)) unweapon = TRUE;
+       return;
+}
+
+void
+place_monster(mon, x, y)
+struct monst *mon;
+int x, y;
+{
+    if (mon == u.usteed ||
+           /* special case is for convoluted vault guard handling */
+           (DEADMONSTER(mon) && !(mon->isgd && x == 0 && y == 0))) {
+       impossible("placing %s onto map?",
+                  (mon == u.usteed) ? "steed" : "defunct monster");
+       return;
+    }
+    mon->mx = x, mon->my = y;
+    level.monsters[x][y] = mon;
+}
+
+#endif /* STEED */
+
+/*steed.c*/
diff --git a/src/teleport.c b/src/teleport.c
new file mode 100644 (file)
index 0000000..c913e3c
--- /dev/null
@@ -0,0 +1,1291 @@
+/*     SCCS Id: @(#)teleport.c 3.4     2003/08/11      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+STATIC_DCL boolean FDECL(tele_jump_ok, (int,int,int,int));
+STATIC_DCL boolean FDECL(teleok, (int,int,BOOLEAN_P));
+STATIC_DCL void NDECL(vault_tele);
+STATIC_DCL boolean FDECL(rloc_pos_ok, (int,int,struct monst *));
+STATIC_DCL void FDECL(mvault_tele, (struct monst *));
+
+/*
+ * Is (x,y) a good position of mtmp?  If mtmp is NULL, then is (x,y) good
+ * for an object?
+ *
+ * This function will only look at mtmp->mdat, so makemon, mplayer, etc can
+ * call it to generate new monster positions with fake monster structures.
+ */
+boolean
+goodpos(x, y, mtmp, gpflags)
+int x,y;
+struct monst *mtmp;
+unsigned gpflags;
+{
+       struct permonst *mdat = NULL;
+       boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0);
+
+       if (!isok(x, y)) return FALSE;
+
+       /* in many cases, we're trying to create a new monster, which
+        * can't go on top of the player or any existing monster.
+        * however, occasionally we are relocating engravings or objects,
+        * which could be co-located and thus get restricted a bit too much.
+        * oh well.
+        */
+       if (mtmp != &youmonst && x == u.ux && y == u.uy
+#ifdef STEED
+                       && (!u.usteed || mtmp != u.usteed)
+#endif
+                       )
+               return FALSE;
+
+       if (mtmp) {
+           struct monst *mtmp2 = m_at(x,y);
+
+           /* Be careful with long worms.  A monster may be placed back in
+            * its own location.  Normally, if m_at() returns the same monster
+            * that we're trying to place, the monster is being placed in its
+            * own location.  However, that is not correct for worm segments,
+            * because all the segments of the worm return the same m_at().
+            * Actually we overdo the check a little bit--a worm can't be placed
+            * in its own location, period.  If we just checked for mtmp->mx
+            * != x || mtmp->my != y, we'd miss the case where we're called
+            * to place the worm segment and the worm's head is at x,y.
+            */
+           if (mtmp2 && (mtmp2 != mtmp || mtmp->wormno))
+               return FALSE;
+
+           mdat = mtmp->data;
+           if (is_pool(x,y) && !ignorewater) {
+               if (mtmp == &youmonst)
+                       return !!(HLevitation || Flying || Wwalking ||
+                                       Swimming || Amphibious);
+               else    return (is_flyer(mdat) || is_swimmer(mdat) ||
+                                                       is_clinger(mdat));
+           } else if (mdat->mlet == S_EEL && rn2(13) && !ignorewater) {
+               return FALSE;
+           } else if (is_lava(x,y)) {
+               if (mtmp == &youmonst)
+                   return !!HLevitation;
+               else
+                   return (is_flyer(mdat) || likes_lava(mdat));
+           }
+           if (passes_walls(mdat) && may_passwall(x,y)) return TRUE;
+       }
+       if (!ACCESSIBLE(levl[x][y].typ)) {
+               if (!(is_pool(x,y) && ignorewater)) return FALSE;
+       }
+
+       if (closed_door(x, y) && (!mdat || !amorphous(mdat)))
+               return FALSE;
+       if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat)))
+               return FALSE;
+       return TRUE;
+}
+
+/*
+ * "entity next to"
+ *
+ * Attempt to find a good place for the given monster type in the closest
+ * position to (xx,yy).  Do so in successive square rings around (xx,yy).
+ * If there is more than one valid positon in the ring, choose one randomly.
+ * Return TRUE and the position chosen when successful, FALSE otherwise.
+ */
+boolean
+enexto(cc, xx, yy, mdat)
+coord *cc;
+register xchar xx, yy;
+struct permonst *mdat;
+{
+       return enexto_core(cc, xx, yy, mdat, 0);
+}
+
+boolean
+enexto_core(cc, xx, yy, mdat, entflags)
+coord *cc;
+register xchar xx, yy;
+struct permonst *mdat;
+unsigned entflags;
+{
+#define MAX_GOOD 15
+    coord good[MAX_GOOD], *good_ptr;
+    int x, y, range, i;
+    int xmin, xmax, ymin, ymax;
+    struct monst fakemon;      /* dummy monster */
+
+    if (!mdat) {
+#ifdef DEBUG
+       pline("enexto() called with mdat==0");
+#endif
+       /* default to player's original monster type */
+       mdat = &mons[u.umonster];
+    }
+    fakemon.data = mdat;       /* set up for goodpos */
+    good_ptr = good;
+    range = 1;
+    /*
+     * Walk around the border of the square with center (xx,yy) and
+     * radius range.  Stop when we find at least one valid position.
+     */
+    do {
+       xmin = max(1, xx-range);
+       xmax = min(COLNO-1, xx+range);
+       ymin = max(0, yy-range);
+       ymax = min(ROWNO-1, yy+range);
+
+       for (x = xmin; x <= xmax; x++)
+           if (goodpos(x, ymin, &fakemon, entflags)) {
+               good_ptr->x = x;
+               good_ptr->y = ymin ;
+               /* beware of accessing beyond segment boundaries.. */
+               if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
+           }
+       for (x = xmin; x <= xmax; x++)
+           if (goodpos(x, ymax, &fakemon, entflags)) {
+               good_ptr->x = x;
+               good_ptr->y = ymax ;
+               /* beware of accessing beyond segment boundaries.. */
+               if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
+           }
+       for (y = ymin+1; y < ymax; y++)
+           if (goodpos(xmin, y, &fakemon, entflags)) {
+               good_ptr->x = xmin;
+               good_ptr-> y = y ;
+               /* beware of accessing beyond segment boundaries.. */
+               if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
+           }
+       for (y = ymin+1; y < ymax; y++)
+           if (goodpos(xmax, y, &fakemon, entflags)) {
+               good_ptr->x = xmax;
+               good_ptr->y = y ;
+               /* beware of accessing beyond segment boundaries.. */
+               if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
+           }
+       range++;
+
+       /* return if we've grown too big (nothing is valid) */
+       if (range > ROWNO && range > COLNO) return FALSE;
+    } while (good_ptr == good);
+
+full:
+    i = rn2((int)(good_ptr - good));
+    cc->x = good[i].x;
+    cc->y = good[i].y;
+    return TRUE;
+}
+
+/*
+ * Check for restricted areas present in some special levels.  (This might
+ * need to be augmented to allow deliberate passage in wizard mode, but
+ * only for explicitly chosen destinations.)
+ */
+STATIC_OVL boolean
+tele_jump_ok(x1, y1, x2, y2)
+int x1, y1, x2, y2;
+{
+       if (dndest.nlx > 0) {
+           /* if inside a restricted region, can't teleport outside */
+           if (within_bounded_area(x1, y1, dndest.nlx, dndest.nly,
+                                               dndest.nhx, dndest.nhy) &&
+               !within_bounded_area(x2, y2, dndest.nlx, dndest.nly,
+                                               dndest.nhx, dndest.nhy))
+               return FALSE;
+           /* and if outside, can't teleport inside */
+           if (!within_bounded_area(x1, y1, dndest.nlx, dndest.nly,
+                                               dndest.nhx, dndest.nhy) &&
+               within_bounded_area(x2, y2, dndest.nlx, dndest.nly,
+                                               dndest.nhx, dndest.nhy))
+               return FALSE;
+       }
+       if (updest.nlx > 0) {           /* ditto */
+           if (within_bounded_area(x1, y1, updest.nlx, updest.nly,
+                                               updest.nhx, updest.nhy) &&
+               !within_bounded_area(x2, y2, updest.nlx, updest.nly,
+                                               updest.nhx, updest.nhy))
+               return FALSE;
+           if (!within_bounded_area(x1, y1, updest.nlx, updest.nly,
+                                               updest.nhx, updest.nhy) &&
+               within_bounded_area(x2, y2, updest.nlx, updest.nly,
+                                               updest.nhx, updest.nhy))
+               return FALSE;
+       }
+       return TRUE;
+}
+
+STATIC_OVL boolean
+teleok(x, y, trapok)
+register int x, y;
+boolean trapok;
+{
+       if (!trapok && t_at(x, y)) return FALSE;
+       if (!goodpos(x, y, &youmonst, 0)) return FALSE;
+       if (!tele_jump_ok(u.ux, u.uy, x, y)) return FALSE;
+       if (!in_out_region(x, y)) return FALSE;
+       return TRUE;
+}
+
+void
+teleds(nux, nuy, allow_drag)
+register int nux,nuy;
+boolean allow_drag;
+{
+       boolean ball_active = (Punished && uball->where != OBJ_FREE),
+               ball_still_in_range = FALSE;
+
+       /* If they have to move the ball, then drag if allow_drag is true;
+        * otherwise they are teleporting, so unplacebc().  
+        * If they don't have to move the ball, then always "drag" whether or
+        * not allow_drag is true, because we are calling that function, not
+        * to drag, but to move the chain.  *However* there are some dumb
+        * special cases:
+        *    0                          0
+        *   _X  move east       ----->  X_
+        *    @                           @
+        * These are permissible if teleporting, but not if dragging.  As a
+        * result, drag_ball() needs to know about allow_drag and might end
+        * up dragging the ball anyway.  Also, drag_ball() might find that
+        * dragging the ball is completely impossible (ball in range but there's
+        * rock in the way), in which case it teleports the ball on its own.
+        */
+       if (ball_active) {
+           if (!carried(uball) && distmin(nux, nuy, uball->ox, uball->oy) <= 2)
+               ball_still_in_range = TRUE; /* don't have to move the ball */
+           else {
+               /* have to move the ball */
+               if (!allow_drag || distmin(u.ux, u.uy, nux, nuy) > 1) {
+                   /* we should not have dist > 1 and allow_drag at the same
+                    * time, but just in case, we must then revert to teleport.
+                    */
+                   allow_drag = FALSE;
+                   unplacebc();
+               }
+           }
+       }
+       u.utrap = 0;
+       u.ustuck = 0;
+       u.ux0 = u.ux;
+       u.uy0 = u.uy;
+
+       if (hides_under(youmonst.data))
+               u.uundetected = OBJ_AT(nux, nuy);
+       else if (youmonst.data->mlet == S_EEL)
+               u.uundetected = is_pool(nux, nuy);
+       else {
+               u.uundetected = 0;
+               /* mimics stop being unnoticed */
+               if (youmonst.data->mlet == S_MIMIC)
+                   youmonst.m_ap_type = M_AP_NOTHING;
+       }
+
+       if (u.uswallow) {
+               u.uswldtim = u.uswallow = 0;
+               if (Punished && !ball_active) {
+                   /* ensure ball placement, like unstuck */
+                   ball_active = TRUE;
+                   allow_drag = FALSE;
+               }
+               docrt();
+       }
+       if (ball_active) {
+           if (ball_still_in_range || allow_drag) {
+               int bc_control;
+               xchar ballx, bally, chainx, chainy;
+               boolean cause_delay;
+
+               if (drag_ball(nux, nuy, &bc_control, &ballx, &bally,
+                                   &chainx, &chainy, &cause_delay, allow_drag))
+                   move_bc(0, bc_control, ballx, bally, chainx, chainy);
+           }
+       }
+       /* must set u.ux, u.uy after drag_ball(), which may need to know
+          the old position if allow_drag is true... */
+       u.ux = nux;
+       u.uy = nuy;
+       fill_pit(u.ux0, u.uy0);
+       if (ball_active) {
+           if (!ball_still_in_range && !allow_drag)
+               placebc();
+       }
+       initrack(); /* teleports mess up tracking monsters without this */
+       update_player_regions();
+#ifdef STEED
+       /* Move your steed, too */
+       if (u.usteed) {
+               u.usteed->mx = nux;
+               u.usteed->my = nuy;
+       }
+#endif
+       /*
+        *  Make sure the hero disappears from the old location.  This will
+        *  not happen if she is teleported within sight of her previous
+        *  location.  Force a full vision recalculation because the hero
+        *  is now in a new location.
+        */
+       newsym(u.ux0,u.uy0);
+       see_monsters();
+       vision_full_recalc = 1;
+       nomul(0);
+       vision_recalc(0);       /* vision before effects */
+       spoteffects(TRUE);
+       invocation_message();
+}
+
+boolean
+safe_teleds(allow_drag)
+boolean allow_drag;
+{
+       register int nux, nuy, tcnt = 0;
+
+       do {
+               nux = rnd(COLNO-1);
+               nuy = rn2(ROWNO);
+       } while (!teleok(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 400);
+
+       if (tcnt <= 400) {
+               teleds(nux, nuy, allow_drag);
+               return TRUE;
+       } else
+               return FALSE;
+}
+
+STATIC_OVL void
+vault_tele()
+{
+       register struct mkroom *croom = search_special(VAULT);
+       coord c;
+
+       if (croom && somexy(croom, &c) && teleok(c.x,c.y,FALSE)) {
+               teleds(c.x,c.y,FALSE);
+               return;
+       }
+       tele();
+}
+
+boolean
+teleport_pet(mtmp, force_it)
+register struct monst *mtmp;
+boolean force_it;
+{
+       register struct obj *otmp;
+
+#ifdef STEED
+       if (mtmp == u.usteed)
+               return (FALSE);
+#endif
+
+       if (mtmp->mleashed) {
+           otmp = get_mleash(mtmp);
+           if (!otmp) {
+               impossible("%s is leashed, without a leash.", Monnam(mtmp));
+               goto release_it;
+           }
+           if (otmp->cursed && !force_it) {
+               yelp(mtmp);
+               return FALSE;
+           } else {
+               Your("leash goes slack.");
+ release_it:
+               m_unleash(mtmp, FALSE);
+               return TRUE;
+           }
+       }
+       return TRUE;
+}
+
+void
+tele()
+{
+       coord cc;
+
+       /* Disable teleportation in stronghold && Vlad's Tower */
+       if (level.flags.noteleport) {
+#ifdef WIZARD
+               if (!wizard) {
+#endif
+                   pline("A mysterious force prevents you from teleporting!");
+                   return;
+#ifdef WIZARD
+               }
+#endif
+       }
+
+       /* don't show trap if "Sorry..." */
+       if (!Blinded) make_blinded(0L,FALSE);
+
+       if ((u.uhave.amulet || On_W_tower_level(&u.uz)) && !rn2(3)) {
+           You_feel("disoriented for a moment.");
+           return;
+       }
+       if ((Teleport_control && !Stunned)
+#ifdef WIZARD
+                           || wizard
+#endif
+                                       ) {
+           if (unconscious()) {
+               pline("Being unconscious, you cannot control your teleport.");
+           } else {
+#ifdef STEED
+                   char buf[BUFSZ];
+                   if (u.usteed) Sprintf(buf," and %s", mon_nam(u.usteed));
+#endif
+                   pline("To what position do you%s want to be teleported?",
+#ifdef STEED
+                               u.usteed ? buf :
+#endif
+                          "");
+                   cc.x = u.ux;
+                   cc.y = u.uy;
+                   if (getpos(&cc, TRUE, "the desired position") < 0)
+                       return; /* abort */
+                   /* possible extensions: introduce a small error if
+                      magic power is low; allow transfer to solid rock */
+                   if (teleok(cc.x, cc.y, FALSE)) {
+                       teleds(cc.x, cc.y, FALSE);
+                       return;
+                   }
+                   pline("Sorry...");
+               }
+       }
+
+       (void) safe_teleds(FALSE);
+}
+
+int
+dotele()
+{
+       struct trap *trap;
+
+       trap = t_at(u.ux, u.uy);
+       if (trap && (!trap->tseen || trap->ttyp != TELEP_TRAP))
+               trap = 0;
+
+       if (trap) {
+               if (trap->once) {
+                       pline("This is a vault teleport, usable once only.");
+                       if (yn("Jump in?") == 'n')
+                               trap = 0;
+                       else {
+                               deltrap(trap);
+                               newsym(u.ux, u.uy);
+                       }
+               }
+               if (trap)
+                       You("%s onto the teleportation trap.",
+                           locomotion(youmonst.data, "jump"));
+       }
+       if (!trap) {
+           boolean castit = FALSE;
+           register int sp_no = 0, energy = 0;
+
+           if (!Teleportation || (u.ulevel < (Role_if(PM_WIZARD) ? 8 : 12)
+                                       && !can_teleport(youmonst.data))) {
+               /* Try to use teleport away spell. */
+               if (objects[SPE_TELEPORT_AWAY].oc_name_known && !Confusion)
+                   for (sp_no = 0; sp_no < MAXSPELL; sp_no++)
+                       if (spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY) {
+                               castit = TRUE;
+                               break;
+                       }
+#ifdef WIZARD
+               if (!wizard) {
+#endif
+                   if (!castit) {
+                       if (!Teleportation)
+                           You("don't know that spell.");
+                       else You("are not able to teleport at will.");
+                       return(0);
+                   }
+#ifdef WIZARD
+               }
+#endif
+           }
+
+           if (u.uhunger <= 100 || ACURR(A_STR) < 6) {
+#ifdef WIZARD
+               if (!wizard) {
+#endif
+                       You("lack the strength %s.",
+                           castit ? "for a teleport spell" : "to teleport");
+                       return 1;
+#ifdef WIZARD
+               }
+#endif
+           }
+
+           energy = objects[SPE_TELEPORT_AWAY].oc_level * 7 / 2 - 2;
+           if (u.uen <= energy) {
+#ifdef WIZARD
+               if (wizard)
+                       energy = u.uen;
+               else
+#endif
+               {
+                       You("lack the energy %s.",
+                           castit ? "for a teleport spell" : "to teleport");
+                       return 1;
+               }
+           }
+
+           if (check_capacity(
+                       "Your concentration falters from carrying so much."))
+               return 1;
+
+           if (castit) {
+               exercise(A_WIS, TRUE);
+               if (spelleffects(sp_no, TRUE))
+                       return(1);
+               else
+#ifdef WIZARD
+                   if (!wizard)
+#endif
+                       return(0);
+           } else {
+               u.uen -= energy;
+               flags.botl = 1;
+           }
+       }
+
+       if (next_to_u()) {
+               if (trap && trap->once) vault_tele();
+               else tele();
+               (void) next_to_u();
+       } else {
+               You(shudder_for_moment);
+               return(0);
+       }
+       if (!trap) morehungry(100);
+       return(1);
+}
+
+
+void
+level_tele()
+{
+       register int newlev;
+       d_level newlevel;
+       const char *escape_by_flying = 0;       /* when surviving dest of -N */
+       char buf[BUFSZ];
+       boolean force_dest = FALSE;
+
+       if ((u.uhave.amulet || In_endgame(&u.uz) || In_sokoban(&u.uz))
+#ifdef WIZARD
+                                               && !wizard
+#endif
+                                                       ) {
+           You_feel("very disoriented for a moment.");
+           return;
+       }
+       if ((Teleport_control && !Stunned)
+#ifdef WIZARD
+          || wizard
+#endif
+               ) {
+           char qbuf[BUFSZ];
+           int trycnt = 0;
+
+           Strcpy(qbuf, "To what level do you want to teleport?");
+           do {
+               if (++trycnt == 2) {
+#ifdef WIZARD
+                       if (wizard) Strcat(qbuf, " [type a number or ? for a menu]");
+                       else
+#endif
+                       Strcat(qbuf, " [type a number]");
+               }
+               getlin(qbuf, buf);
+               if (!strcmp(buf,"\033")) {      /* cancelled */
+                   if (Confusion && rnl(5)) {
+                       pline("Oops...");
+                       goto random_levtport;
+                   }
+                   return;
+               } else if (!strcmp(buf,"*")) {
+                   goto random_levtport;
+               } else if (Confusion && rnl(5)) {
+                   pline("Oops...");
+                   goto random_levtport;
+               }
+#ifdef WIZARD
+               if (wizard && !strcmp(buf,"?")) {
+                   schar destlev = 0;
+                   xchar destdnum = 0;
+
+                   if ((newlev = (int)print_dungeon(TRUE, &destlev, &destdnum))) {
+                       newlevel.dnum = destdnum;
+                       newlevel.dlevel = destlev;
+                       if (In_endgame(&newlevel) && !In_endgame(&u.uz)) {
+                               Sprintf(buf,
+                                   "Destination is earth level");
+                               if (!u.uhave.amulet) {
+                                       struct obj *obj;
+                                       obj = mksobj(AMULET_OF_YENDOR,
+                                                       TRUE, FALSE);
+                                       if (obj) {
+                                               obj = addinv(obj);
+                                               Strcat(buf, " with the amulet");
+                                       }
+                               }
+                               assign_level(&newlevel, &earth_level);
+                               pline("%s.", buf);
+                       }
+                       force_dest = TRUE;
+                   } else return;
+               } else
+#endif
+               if ((newlev = lev_by_name(buf)) == 0) newlev = atoi(buf);
+           } while (!newlev && !digit(buf[0]) &&
+                    (buf[0] != '-' || !digit(buf[1])) &&
+                    trycnt < 10);
+
+           /* no dungeon escape via this route */
+           if (newlev == 0) {
+               if (trycnt >= 10)
+                   goto random_levtport;
+               if (ynq("Go to Nowhere.  Are you sure?") != 'y') return;
+               You("%s in agony as your body begins to warp...",
+                   is_silent(youmonst.data) ? "writhe" : "scream");
+               display_nhwindow(WIN_MESSAGE, FALSE);
+               You("cease to exist.");
+               if (invent) Your("possessions land on the %s with a thud.",
+                               surface(u.ux, u.uy));
+               killer_format = NO_KILLER_PREFIX;
+               killer = "committed suicide";
+               done(DIED);
+               pline("An energized cloud of dust begins to coalesce.");
+               Your("body rematerializes%s.", invent ?
+                       ", and you gather up all your possessions" : "");
+               return;
+           }
+
+           /* if in Knox and the requested level > 0, stay put.
+            * we let negative values requests fall into the "heaven" loop.
+            */
+           if (Is_knox(&u.uz) && newlev > 0) {
+               You(shudder_for_moment);
+               return;
+           }
+           /* if in Quest, the player sees "Home 1", etc., on the status
+            * line, instead of the logical depth of the level.  controlled
+            * level teleport request is likely to be relativized to the
+            * status line, and consequently it should be incremented to
+            * the value of the logical depth of the target level.
+            *
+            * we let negative values requests fall into the "heaven" loop.
+            */
+           if (In_quest(&u.uz) && newlev > 0)
+               newlev = newlev + dungeons[u.uz.dnum].depth_start - 1;
+       } else { /* involuntary level tele */
+ random_levtport:
+           newlev = random_teleport_level();
+           if (newlev == depth(&u.uz)) {
+               You(shudder_for_moment);
+               return;
+           }
+       }
+
+       if (!next_to_u()) {
+               You(shudder_for_moment);
+               return;
+       }
+#ifdef WIZARD
+       if (In_endgame(&u.uz)) {        /* must already be wizard */
+           int llimit = dunlevs_in_dungeon(&u.uz);
+
+           if (newlev >= 0 || newlev <= -llimit) {
+               You_cant("get there from here.");
+               return;
+           }
+           newlevel.dnum = u.uz.dnum;
+           newlevel.dlevel = llimit + newlev;
+           schedule_goto(&newlevel, FALSE, FALSE, 0, (char *)0, (char *)0);
+           return;
+       }
+#endif
+
+       killer = 0;             /* still alive, so far... */
+
+       if (newlev < 0 && !force_dest) {
+               if (*u.ushops0) {
+                   /* take unpaid inventory items off of shop bills */
+                   in_mklev = TRUE;    /* suppress map update */
+                   u_left_shop(u.ushops0, TRUE);
+                   /* you're now effectively out of the shop */
+                   *u.ushops0 = *u.ushops = '\0';
+                   in_mklev = FALSE;
+               }
+               if (newlev <= -10) {
+                       You("arrive in heaven.");
+                       verbalize("Thou art early, but we'll admit thee.");
+                       killer_format = NO_KILLER_PREFIX;
+                       killer = "went to heaven prematurely";
+               } else if (newlev == -9) {
+                       You_feel("deliriously happy. ");
+                       pline("(In fact, you're on Cloud 9!) ");
+                       display_nhwindow(WIN_MESSAGE, FALSE);
+               } else
+                       You("are now high above the clouds...");
+
+               if (killer) {
+                   ;           /* arrival in heaven is pending */
+               } else if (Levitation) {
+                   escape_by_flying = "float gently down to earth";
+               } else if (Flying) {
+                   escape_by_flying = "fly down to the ground";
+               } else {
+                   pline("Unfortunately, you don't know how to fly.");
+                   You("plummet a few thousand feet to your death.");
+                   Sprintf(buf,
+                         "teleported out of the dungeon and fell to %s death",
+                           uhis());
+                   killer = buf;
+                   killer_format = NO_KILLER_PREFIX;
+               }
+       }
+
+       if (killer) {   /* the chosen destination was not survivable */
+           d_level lsav;
+
+           /* set specific death location; this also suppresses bones */
+           lsav = u.uz;        /* save current level, see below */
+           u.uz.dnum = 0;      /* main dungeon */
+           u.uz.dlevel = (newlev <= -10) ? -10 : 0;    /* heaven or surface */
+           done(DIED);
+           /* can only get here via life-saving (or declining to die in
+              explore|debug mode); the hero has now left the dungeon... */
+           escape_by_flying = "find yourself back on the surface";
+           u.uz = lsav;        /* restore u.uz so escape code works */
+       }
+
+       /* calls done(ESCAPED) if newlevel==0 */
+       if (escape_by_flying) {
+           You("%s.", escape_by_flying);
+           newlevel.dnum = 0;          /* specify main dungeon */
+           newlevel.dlevel = 0;        /* escape the dungeon */
+           /* [dlevel used to be set to 1, but it doesn't make sense to
+               teleport out of the dungeon and float or fly down to the
+               surface but then actually arrive back inside the dungeon] */
+       } else if (u.uz.dnum == medusa_level.dnum &&
+           newlev >= dungeons[u.uz.dnum].depth_start +
+                                               dunlevs_in_dungeon(&u.uz)) {
+#ifdef WIZARD
+           if (!(wizard && force_dest))
+#endif
+           find_hell(&newlevel);
+       } else {
+           /* if invocation did not yet occur, teleporting into
+            * the last level of Gehennom is forbidden.
+            */
+#ifdef WIZARD
+               if (!wizard)
+#endif
+           if (Inhell && !u.uevent.invoked &&
+                       newlev >= (dungeons[u.uz.dnum].depth_start +
+                                       dunlevs_in_dungeon(&u.uz) - 1)) {
+               newlev = dungeons[u.uz.dnum].depth_start +
+                                       dunlevs_in_dungeon(&u.uz) - 2;
+               pline("Sorry...");
+           }
+           /* no teleporting out of quest dungeon */
+           if (In_quest(&u.uz) && newlev < depth(&qstart_level))
+               newlev = depth(&qstart_level);
+           /* the player thinks of levels purely in logical terms, so
+            * we must translate newlev to a number relative to the
+            * current dungeon.
+            */
+#ifdef WIZARD
+           if (!(wizard && force_dest))
+#endif
+           get_level(&newlevel, newlev);
+       }
+       schedule_goto(&newlevel, FALSE, FALSE, 0, (char *)0, (char *)0);
+       /* in case player just read a scroll and is about to be asked to
+          call it something, we can't defer until the end of the turn */
+       if (u.utotype && !flags.mon_moving) deferred_goto();
+}
+
+void
+domagicportal(ttmp)
+register struct trap *ttmp;
+{
+       struct d_level target_level;
+
+       if (!next_to_u()) {
+               You(shudder_for_moment);
+               return;
+       }
+
+       /* if landed from another portal, do nothing */
+       /* problem: level teleport landing escapes the check */
+       if (!on_level(&u.uz, &u.uz0)) return;
+
+       You("activated a magic portal!");
+
+       /* prevent the poor shnook, whose amulet was stolen while in
+        * the endgame, from accidently triggering the portal to the
+        * next level, and thus losing the game
+        */
+       if (In_endgame(&u.uz) && !u.uhave.amulet) {
+           You_feel("dizzy for a moment, but nothing happens...");
+           return;
+       }
+
+       target_level = ttmp->dst;
+       schedule_goto(&target_level, FALSE, FALSE, 1,
+                     "You feel dizzy for a moment, but the sensation passes.",
+                     (char *)0);
+}
+
+void
+tele_trap(trap)
+struct trap *trap;
+{
+       if (In_endgame(&u.uz) || Antimagic) {
+               if (Antimagic)
+                       shieldeff(u.ux, u.uy);
+               You_feel("a wrenching sensation.");
+       } else if (!next_to_u()) {
+               You(shudder_for_moment);
+       } else if (trap->once) {
+               deltrap(trap);
+               newsym(u.ux,u.uy);      /* get rid of trap symbol */
+               vault_tele();
+       } else
+               tele();
+}
+
+void
+level_tele_trap(trap)
+struct trap *trap;
+{
+       You("%s onto a level teleport trap!",
+                     Levitation ? (const char *)"float" :
+                                 locomotion(youmonst.data, "step"));
+       if (Antimagic) {
+           shieldeff(u.ux, u.uy);
+       }
+       if (Antimagic || In_endgame(&u.uz)) {
+           You_feel("a wrenching sensation.");
+           return;
+       }
+       if (!Blind)
+           You("are momentarily blinded by a flash of light.");
+       else
+           You("are momentarily disoriented.");
+       deltrap(trap);
+       newsym(u.ux,u.uy);      /* get rid of trap symbol */
+       level_tele();
+}
+
+/* check whether monster can arrive at location <x,y> via Tport (or fall) */
+STATIC_OVL boolean
+rloc_pos_ok(x, y, mtmp)
+register int x, y;             /* coordinates of candidate location */
+struct monst *mtmp;
+{
+       register int xx, yy;
+
+       if (!goodpos(x, y, mtmp, 0)) return FALSE;
+       /*
+        * Check for restricted areas present in some special levels.
+        *
+        * `xx' is current column; if 0, then `yy' will contain flag bits
+        * rather than row:  bit #0 set => moving upwards; bit #1 set =>
+        * inside the Wizard's tower.
+        */
+       xx = mtmp->mx;
+       yy = mtmp->my;
+       if (!xx) {
+           /* no current location (migrating monster arrival) */
+           if (dndest.nlx && On_W_tower_level(&u.uz))
+               return ((yy & 2) != 0) ^        /* inside xor not within */
+                      !within_bounded_area(x, y, dndest.nlx, dndest.nly,
+                                                 dndest.nhx, dndest.nhy);
+           if (updest.lx && (yy & 1) != 0)     /* moving up */
+               return (within_bounded_area(x, y, updest.lx, updest.ly,
+                                                 updest.hx, updest.hy) &&
+                      (!updest.nlx ||
+                       !within_bounded_area(x, y, updest.nlx, updest.nly,
+                                                  updest.nhx, updest.nhy)));
+           if (dndest.lx && (yy & 1) == 0)     /* moving down */
+               return (within_bounded_area(x, y, dndest.lx, dndest.ly,
+                                                 dndest.hx, dndest.hy) &&
+                      (!dndest.nlx ||
+                       !within_bounded_area(x, y, dndest.nlx, dndest.nly,
+                                                  dndest.nhx, dndest.nhy)));
+       } else {
+           /* current location is <xx,yy> */
+           if (!tele_jump_ok(xx, yy, x, y)) return FALSE;
+       }
+       /* <x,y> is ok */
+       return TRUE;
+}
+
+/*
+ * rloc_to()
+ *
+ * Pulls a monster from its current position and places a monster at
+ * a new x and y.  If oldx is 0, then the monster was not in the levels.monsters
+ * array.  However, if oldx is 0, oldy may still have a value because mtmp is a
+ * migrating_mon.  Worm tails are always placed randomly around the head of
+ * the worm.
+ */
+void
+rloc_to(mtmp, x, y)
+struct monst *mtmp;
+register int x, y;
+{
+       register int oldx = mtmp->mx, oldy = mtmp->my;
+       boolean resident_shk = mtmp->isshk && inhishop(mtmp);
+
+       if (x == mtmp->mx && y == mtmp->my)     /* that was easy */
+               return;
+
+       if (oldx) {                             /* "pick up" monster */
+           if (mtmp->wormno)
+               remove_worm(mtmp);
+           else {
+               remove_monster(oldx, oldy);
+               newsym(oldx, oldy);             /* update old location */
+           }
+       }
+
+       place_monster(mtmp, x, y);              /* put monster down */
+       update_monster_region(mtmp);
+
+       if (mtmp->wormno)                       /* now put down tail */
+               place_worm_tail_randomly(mtmp, x, y);
+
+       if (u.ustuck == mtmp) {
+               if (u.uswallow) {
+                       u.ux = x;
+                       u.uy = y;
+                       docrt();
+               } else  u.ustuck = 0;
+       }
+
+       newsym(x, y);                           /* update new location */
+       set_apparxy(mtmp);                      /* orient monster */
+
+       /* shopkeepers will only teleport if you zap them with a wand of
+          teleportation or if they've been transformed into a jumpy monster;
+          the latter only happens if you've attacked them with polymorph */
+       if (resident_shk && !inhishop(mtmp)) make_angry_shk(mtmp, oldx, oldy);
+}
+
+/* place a monster at a random location, typically due to teleport */
+/* return TRUE if successful, FALSE if not */
+boolean
+rloc(mtmp, suppress_impossible)
+struct monst *mtmp;    /* mx==0 implies migrating monster arrival */
+boolean suppress_impossible;
+{
+       register int x, y, trycount;
+
+#ifdef STEED
+       if (mtmp == u.usteed) {
+           tele();
+           return TRUE;
+       }
+#endif
+
+       if (mtmp->iswiz && mtmp->mx) {  /* Wizard, not just arriving */
+           if (!In_W_tower(u.ux, u.uy, &u.uz))
+               x = xupstair,  y = yupstair;
+           else if (!xdnladder)        /* bottom level of tower */
+               x = xupladder,  y = yupladder;
+           else
+               x = xdnladder,  y = ydnladder;
+           /* if the wiz teleports away to heal, try the up staircase,
+              to block the player's escaping before he's healed
+              (deliberately use `goodpos' rather than `rloc_pos_ok' here) */
+           if (goodpos(x, y, mtmp, 0))
+               goto found_xy;
+       }
+
+       trycount = 0;
+       do {
+           x = rn1(COLNO-3,2);
+           y = rn2(ROWNO);
+           if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp)
+                                : goodpos(x, y, mtmp, 0))
+               goto found_xy;
+       } while (++trycount < 1000);
+
+       /* last ditch attempt to find a good place */
+       for (x = 2; x < COLNO - 1; x++)
+           for (y = 0; y < ROWNO; y++)
+               if (goodpos(x, y, mtmp, 0))
+                   goto found_xy;
+
+       /* level either full of monsters or somehow faulty */
+       if (!suppress_impossible)
+               impossible("rloc(): couldn't relocate monster");
+       return FALSE;
+
+ found_xy:
+       rloc_to(mtmp, x, y);
+       return TRUE;
+}
+
+STATIC_OVL void
+mvault_tele(mtmp)
+struct monst *mtmp;
+{
+       register struct mkroom *croom = search_special(VAULT);
+       coord c;
+
+       if (croom && somexy(croom, &c) &&
+                               goodpos(c.x, c.y, mtmp, 0)) {
+               rloc_to(mtmp, c.x, c.y);
+               return;
+       }
+       (void) rloc(mtmp, FALSE);
+}
+
+boolean
+tele_restrict(mon)
+struct monst *mon;
+{
+       if (level.flags.noteleport) {
+               if (canseemon(mon))
+                   pline("A mysterious force prevents %s from teleporting!",
+                       mon_nam(mon));
+               return TRUE;
+       }
+       return FALSE;
+}
+
+void
+mtele_trap(mtmp, trap, in_sight)
+struct monst *mtmp;
+struct trap *trap;
+int in_sight;
+{
+       char *monname;
+
+       if (tele_restrict(mtmp)) return;
+       if (teleport_pet(mtmp, FALSE)) {
+           /* save name with pre-movement visibility */
+           monname = Monnam(mtmp);
+
+           /* Note: don't remove the trap if a vault.  Other-
+            * wise the monster will be stuck there, since
+            * the guard isn't going to come for it...
+            */
+           if (trap->once) mvault_tele(mtmp);
+           else (void) rloc(mtmp, FALSE);
+
+           if (in_sight) {
+               if (canseemon(mtmp))
+                   pline("%s seems disoriented.", monname);
+               else
+                   pline("%s suddenly disappears!", monname);
+               seetrap(trap);
+           }
+       }
+}
+
+/* return 0 if still on level, 3 if not */
+int
+mlevel_tele_trap(mtmp, trap, force_it, in_sight)
+struct monst *mtmp;
+struct trap *trap;
+boolean force_it;
+int in_sight;
+{
+       int tt = trap->ttyp;
+       struct permonst *mptr = mtmp->data;
+
+       if (mtmp == u.ustuck)   /* probably a vortex */
+           return 0;           /* temporary? kludge */
+       if (teleport_pet(mtmp, force_it)) {
+           d_level tolevel;
+           int migrate_typ = MIGR_RANDOM;
+
+           if ((tt == HOLE || tt == TRAPDOOR)) {
+               if (Is_stronghold(&u.uz)) {
+                   assign_level(&tolevel, &valley_level);
+               } else if (Is_botlevel(&u.uz)) {
+                   if (in_sight && trap->tseen)
+                       pline("%s avoids the %s.", Monnam(mtmp),
+                       (tt == HOLE) ? "hole" : "trap");
+                   return 0;
+               } else {
+                   get_level(&tolevel, depth(&u.uz) + 1);
+               }
+           } else if (tt == MAGIC_PORTAL) {
+               if (In_endgame(&u.uz) &&
+                   (mon_has_amulet(mtmp) || is_home_elemental(mptr))) {
+                   if (in_sight && mptr->mlet != S_ELEMENTAL) {
+                       pline("%s seems to shimmer for a moment.",
+                                                       Monnam(mtmp));
+                       seetrap(trap);
+                   }
+                   return 0;
+               } else {
+                   assign_level(&tolevel, &trap->dst);
+                   migrate_typ = MIGR_PORTAL;
+               }
+           } else { /* (tt == LEVEL_TELEP) */
+               int nlev;
+
+               if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
+                   if (in_sight)
+                       pline("%s seems very disoriented for a moment.",
+                               Monnam(mtmp));
+                   return 0;
+               }
+               nlev = random_teleport_level();
+               if (nlev == depth(&u.uz)) {
+                   if (in_sight)
+                       pline("%s shudders for a moment.", Monnam(mtmp));
+                   return 0;
+               }
+               get_level(&tolevel, nlev);
+           }
+
+           if (in_sight) {
+               pline("Suddenly, %s disappears out of sight.", mon_nam(mtmp));
+               seetrap(trap);
+           }
+           migrate_to_level(mtmp, ledger_no(&tolevel),
+                            migrate_typ, (coord *)0);
+           return 3;   /* no longer on this level */
+       }
+       return 0;
+}
+
+
+void
+rloco(obj)
+register struct obj *obj;
+{
+       register xchar tx, ty, otx, oty;
+       boolean restricted_fall;
+       int try_limit = 4000;
+
+       if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) {
+           if (revive_corpse(obj)) return;
+       }
+
+       obj_extract_self(obj);
+       otx = obj->ox;
+       oty = obj->oy;
+       restricted_fall = (otx == 0 && dndest.lx);
+       do {
+           tx = rn1(COLNO-3,2);
+           ty = rn2(ROWNO);
+           if (!--try_limit) break;
+       } while (!goodpos(tx, ty, (struct monst *)0, 0) ||
+               /* bug: this lacks provision for handling the Wizard's tower */
+                (restricted_fall &&
+                 (!within_bounded_area(tx, ty, dndest.lx, dndest.ly,
+                                               dndest.hx, dndest.hy) ||
+                  (dndest.nlx &&
+                   within_bounded_area(tx, ty, dndest.nlx, dndest.nly,
+                                               dndest.nhx, dndest.nhy)))));
+
+       if (flooreffects(obj, tx, ty, "fall")) {
+           return;
+       } else if (otx == 0 && oty == 0) {
+           ;   /* fell through a trap door; no update of old loc needed */
+       } else {
+           if (costly_spot(otx, oty)
+             && (!costly_spot(tx, ty) ||
+                 !index(in_rooms(tx, ty, 0), *in_rooms(otx, oty, 0)))) {
+               if (costly_spot(u.ux, u.uy) &&
+                           index(u.urooms, *in_rooms(otx, oty, 0)))
+                   addtobill(obj, FALSE, FALSE, FALSE);
+               else (void)stolen_value(obj, otx, oty, FALSE, FALSE);
+           }
+           newsym(otx, oty);   /* update old location */
+       }
+       place_object(obj, tx, ty);
+       newsym(tx, ty);
+}
+
+/* Returns an absolute depth */
+int
+random_teleport_level()
+{
+       int nlev, max_depth, min_depth,
+           cur_depth = (int)depth(&u.uz);
+
+       if (!rn2(5) || Is_knox(&u.uz))
+           return cur_depth;
+
+       /* What I really want to do is as follows:
+        * -- If in a dungeon that goes down, the new level is to be restricted
+        *    to [top of parent, bottom of current dungeon]
+        * -- If in a dungeon that goes up, the new level is to be restricted
+        *    to [top of current dungeon, bottom of parent]
+        * -- If in a quest dungeon or similar dungeon entered by portals,
+        *    the new level is to be restricted to [top of current dungeon,
+        *    bottom of current dungeon]
+        * The current behavior is not as sophisticated as that ideal, but is
+        * still better what we used to do, which was like this for players
+        * but different for monsters for no obvious reason.  Currently, we
+        * must explicitly check for special dungeons.  We check for Knox
+        * above; endgame is handled in the caller due to its different
+        * message ("disoriented").
+        * --KAA
+        * 3.4.2: explicitly handle quest here too, to fix the problem of
+        * monsters sometimes level teleporting out of it into main dungeon.
+        * Also prevent monsters reaching the Sanctum prior to invocation.
+        */
+       min_depth = In_quest(&u.uz) ? dungeons[u.uz.dnum].depth_start : 1;
+       max_depth = dunlevs_in_dungeon(&u.uz) +
+                       (dungeons[u.uz.dnum].depth_start - 1);
+       /* can't reach the Sanctum if the invocation hasn't been performed */
+       if (Inhell && !u.uevent.invoked) max_depth -= 1;
+
+       /* Get a random value relative to the current dungeon */
+       /* Range is 1 to current+3, current not counting */
+       nlev = rn2(cur_depth + 3 - min_depth) + min_depth;
+       if (nlev >= cur_depth) nlev++;
+
+       if (nlev > max_depth) {
+           nlev = max_depth;
+           /* teleport up if already on bottom */
+           if (Is_botlevel(&u.uz)) nlev -= rnd(3);
+       }
+       if (nlev < min_depth) {
+           nlev = min_depth;
+           if (nlev == cur_depth) {
+               nlev += rnd(3);
+               if (nlev > max_depth)
+                   nlev = max_depth;
+           }
+       }
+       return nlev;
+}
+
+/* you teleport a monster (via wand, spell, or poly'd q.mechanic attack);
+   return false iff the attempt fails */
+boolean
+u_teleport_mon(mtmp, give_feedback)
+struct monst *mtmp;
+boolean give_feedback;
+{
+       coord cc;
+
+       if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) {
+           if (give_feedback)
+               pline("%s resists your magic!", Monnam(mtmp));
+           return FALSE;
+       } else if (level.flags.noteleport && u.uswallow && mtmp == u.ustuck) {
+           if (give_feedback)
+               You("are no longer inside %s!", mon_nam(mtmp));
+           unstuck(mtmp);
+           (void) rloc(mtmp, FALSE);
+       } else if (is_rider(mtmp->data) && rn2(13) &&
+                  enexto(&cc, u.ux, u.uy, mtmp->data))
+           rloc_to(mtmp, cc.x, cc.y);
+       else
+           (void) rloc(mtmp, FALSE);
+       return TRUE;
+}
+
+/*teleport.c*/
diff --git a/src/timeout.c b/src/timeout.c
new file mode 100644 (file)
index 0000000..6a336d6
--- /dev/null
@@ -0,0 +1,1856 @@
+/*     SCCS Id: @(#)timeout.c  3.4     2002/12/17      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "lev.h"       /* for checking save modes */
+
+STATIC_DCL void NDECL(stoned_dialogue);
+STATIC_DCL void NDECL(vomiting_dialogue);
+STATIC_DCL void NDECL(choke_dialogue);
+STATIC_DCL void NDECL(slime_dialogue);
+STATIC_DCL void NDECL(slip_or_trip);
+STATIC_DCL void FDECL(see_lamp_flicker, (struct obj *, const char *));
+STATIC_DCL void FDECL(lantern_message, (struct obj *));
+STATIC_DCL void FDECL(cleanup_burn, (genericptr_t,long));
+
+#ifdef OVLB
+
+/* He is being petrified - dialogue by inmet!tower */
+static NEARDATA const char * const stoned_texts[] = {
+       "You are slowing down.",                /* 5 */
+       "Your limbs are stiffening.",           /* 4 */
+       "Your limbs have turned to stone.",     /* 3 */
+       "You have turned to stone.",            /* 2 */
+       "You are a statue."                     /* 1 */
+};
+
+STATIC_OVL void
+stoned_dialogue()
+{
+       register long i = (Stoned & TIMEOUT);
+
+       if (i > 0L && i <= SIZE(stoned_texts))
+               pline(stoned_texts[SIZE(stoned_texts) - i]);
+       if (i == 5L)
+               HFast = 0L;
+       if (i == 3L)
+               nomul(-3);
+       exercise(A_DEX, FALSE);
+}
+
+/* He is getting sicker and sicker prior to vomiting */
+static NEARDATA const char * const vomiting_texts[] = {
+       "are feeling mildly nauseated.",        /* 14 */
+       "feel slightly confused.",              /* 11 */
+       "can't seem to think straight.",        /* 8 */
+       "feel incredibly sick.",                /* 5 */
+       "suddenly vomit!"                       /* 2 */
+};
+
+STATIC_OVL void
+vomiting_dialogue()
+{
+       register long i = (Vomiting & TIMEOUT) / 3L;
+
+       if ((((Vomiting & TIMEOUT) % 3L) == 2) && (i >= 0)
+           && (i < SIZE(vomiting_texts)))
+               You(vomiting_texts[SIZE(vomiting_texts) - i - 1]);
+
+       switch ((int) i) {
+       case 0:
+               vomit();
+               morehungry(20);
+               break;
+       case 2:
+               make_stunned(HStun + d(2,4), FALSE);
+               /* fall through */
+       case 3:
+               make_confused(HConfusion + d(2,4), FALSE);
+               break;
+       }
+       exercise(A_CON, FALSE);
+}
+
+static NEARDATA const char * const choke_texts[] = {
+       "You find it hard to breathe.",
+       "You're gasping for air.",
+       "You can no longer breathe.",
+       "You're turning %s.",
+       "You suffocate."
+};
+
+static NEARDATA const char * const choke_texts2[] = {
+       "Your %s is becoming constricted.",
+       "Your blood is having trouble reaching your brain.",
+       "The pressure on your %s increases.",
+       "Your consciousness is fading.",
+       "You suffocate."
+};
+
+STATIC_OVL void
+choke_dialogue()
+{
+       register long i = (Strangled & TIMEOUT);
+
+       if(i > 0 && i <= SIZE(choke_texts)) {
+           if (Breathless || !rn2(50))
+               pline(choke_texts2[SIZE(choke_texts2) - i], body_part(NECK));
+           else {
+               const char *str = choke_texts[SIZE(choke_texts)-i];
+
+               if (index(str, '%'))
+                   pline(str, hcolor(NH_BLUE));
+               else
+                   pline(str);
+           }
+       }
+       exercise(A_STR, FALSE);
+}
+
+static NEARDATA const char * const slime_texts[] = {
+       "You are turning a little %s.",           /* 5 */
+       "Your limbs are getting oozy.",              /* 4 */
+       "Your skin begins to peel away.",            /* 3 */
+       "You are turning into %s.",       /* 2 */
+       "You have become %s."             /* 1 */
+};
+
+STATIC_OVL void
+slime_dialogue()
+{
+       register long i = (Slimed & TIMEOUT) / 2L;
+
+       if (((Slimed & TIMEOUT) % 2L) && i >= 0L
+               && i < SIZE(slime_texts)) {
+           const char *str = slime_texts[SIZE(slime_texts) - i - 1L];
+
+           if (index(str, '%')) {
+               if (i == 4L) {  /* "you are turning green" */
+                   if (!Blind) /* [what if you're already green?] */
+                       pline(str, hcolor(NH_GREEN));
+               } else
+                   pline(str, an(Hallucination ? rndmonnam() : "green slime"));
+           } else
+               pline(str);
+       }
+       if (i == 3L) {  /* limbs becoming oozy */
+           HFast = 0L; /* lose intrinsic speed */
+           stop_occupation();
+           if (multi > 0) nomul(0);
+       }
+       exercise(A_DEX, FALSE);
+}
+
+void
+burn_away_slime()
+{
+       if (Slimed) {
+           pline_The("slime that covers you is burned away!");
+           Slimed = 0L;
+           flags.botl = 1;
+       }
+       return;
+}
+
+
+#endif /* OVLB */
+#ifdef OVL0
+
+void
+nh_timeout()
+{
+       register struct prop *upp;
+       int sleeptime;
+       int m_idx;
+       int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0;
+
+       if (flags.friday13) baseluck -= 1;
+
+       if (u.uluck != baseluck &&
+               moves % (u.uhave.amulet || u.ugangr ? 300 : 600) == 0) {
+       /* Cursed luckstones stop bad luck from timing out; blessed luckstones
+        * stop good luck from timing out; normal luckstones stop both;
+        * neither is stopped if you don't have a luckstone.
+        * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th
+        */
+           register int time_luck = stone_luck(FALSE);
+           boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE);
+
+           if(u.uluck > baseluck && (nostone || time_luck < 0))
+               u.uluck--;
+           else if(u.uluck < baseluck && (nostone || time_luck > 0))
+               u.uluck++;
+       }
+       if(u.uinvulnerable) return; /* things past this point could kill you */
+       if(Stoned) stoned_dialogue();
+       if(Slimed) slime_dialogue();
+       if(Vomiting) vomiting_dialogue();
+       if(Strangled) choke_dialogue();
+       if(u.mtimedone && !--u.mtimedone) {
+               if (Unchanging)
+                       u.mtimedone = rnd(100*youmonst.data->mlevel + 1);
+               else
+                       rehumanize();
+       }
+       if(u.ucreamed) u.ucreamed--;
+
+       /* Dissipate spell-based protection. */
+       if (u.usptime) {
+           if (--u.usptime == 0 && u.uspellprot) {
+               u.usptime = u.uspmtime;
+               u.uspellprot--;
+               find_ac();
+               if (!Blind)
+                   Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
+                         u.uspellprot ? "becomes less dense" : "disappears");
+           }
+       }
+
+#ifdef STEED
+       if (u.ugallop) {
+           if (--u.ugallop == 0L && u.usteed)
+               pline("%s stops galloping.", Monnam(u.usteed));
+       }
+#endif
+
+       for(upp = u.uprops; upp < u.uprops+SIZE(u.uprops); upp++)
+           if((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) {
+               switch(upp - u.uprops){
+               case STONED:
+                       if (delayed_killer && !killer) {
+                               killer = delayed_killer;
+                               delayed_killer = 0;
+                       }
+                       if (!killer) {
+                               /* leaving killer_format would make it
+                                  "petrified by petrification" */
+                               killer_format = NO_KILLER_PREFIX;
+                               killer = "killed by petrification";
+                       }
+                       done(STONING);
+                       break;
+               case SLIMED:
+                       if (delayed_killer && !killer) {
+                               killer = delayed_killer;
+                               delayed_killer = 0;
+                       }
+                       if (!killer) {
+                               killer_format = NO_KILLER_PREFIX;
+                               killer = "turned into green slime";
+                       }
+                       done(TURNED_SLIME);
+                       break;
+               case VOMITING:
+                       make_vomiting(0L, TRUE);
+                       break;
+               case SICK:
+                       You("die from your illness.");
+                       killer_format = KILLED_BY_AN;
+                       killer = u.usick_cause;
+                       if ((m_idx = name_to_mon(killer)) >= LOW_PM) {
+                           if (type_is_pname(&mons[m_idx])) {
+                               killer_format = KILLED_BY;
+                           } else if (mons[m_idx].geno & G_UNIQ) {
+                               killer = the(killer);
+                               Strcpy(u.usick_cause, killer);
+                               killer_format = KILLED_BY;
+                           }
+                       }
+                       u.usick_type = 0;
+                       done(POISONING);
+                       break;
+               case FAST:
+                       if (!Very_fast)
+                               You_feel("yourself slowing down%s.",
+                                                       Fast ? " a bit" : "");
+                       break;
+               case CONFUSION:
+                       HConfusion = 1; /* So make_confused works properly */
+                       make_confused(0L, TRUE);
+                       stop_occupation();
+                       break;
+               case STUNNED:
+                       HStun = 1;
+                       make_stunned(0L, TRUE);
+                       stop_occupation();
+                       break;
+               case BLINDED:
+                       Blinded = 1;
+                       make_blinded(0L, TRUE);
+                       stop_occupation();
+                       break;
+               case INVIS:
+                       newsym(u.ux,u.uy);
+                       if (!Invis && !BInvis && !Blind) {
+                           You(!See_invisible ?
+                                   "are no longer invisible." :
+                                   "can no longer see through yourself.");
+                           stop_occupation();
+                       }
+                       break;
+               case SEE_INVIS:
+                       set_mimic_blocking(); /* do special mimic handling */
+                       see_monsters();         /* make invis mons appear */
+                       newsym(u.ux,u.uy);      /* make self appear */
+                       stop_occupation();
+                       break;
+               case WOUNDED_LEGS:
+                       heal_legs();
+                       stop_occupation();
+                       break;
+               case HALLUC:
+                       HHallucination = 1;
+                       (void) make_hallucinated(0L, TRUE, 0L);
+                       stop_occupation();
+                       break;
+               case SLEEPING:
+                       if (unconscious() || Sleep_resistance)
+                               HSleeping += rnd(100);
+                       else if (Sleeping) {
+                               You("fall asleep.");
+                               sleeptime = rnd(20);
+                               fall_asleep(-sleeptime, TRUE);
+                               HSleeping += sleeptime + rnd(100);
+                       }
+                       break;
+               case LEVITATION:
+                       (void) float_down(I_SPECIAL|TIMEOUT, 0L);
+                       break;
+               case STRANGLED:
+                       killer_format = KILLED_BY;
+                       killer = (u.uburied) ? "suffocation" : "strangulation";
+                       done(DIED);
+                       break;
+               case FUMBLING:
+                       /* call this only when a move took place.  */
+                       /* otherwise handle fumbling msgs locally. */
+                       if (u.umoved && !Levitation) {
+                           slip_or_trip();
+                           nomul(-2);
+                           nomovemsg = "";
+                           /* The more you are carrying the more likely you
+                            * are to make noise when you fumble.  Adjustments
+                            * to this number must be thoroughly play tested.
+                            */
+                           if ((inv_weight() > -500)) {
+                               You("make a lot of noise!");
+                               wake_nearby();
+                           }
+                       }
+                       /* from outside means slippery ice; don't reset
+                          counter if that's the only fumble reason */
+                       HFumbling &= ~FROMOUTSIDE;
+                       if (Fumbling)
+                           HFumbling += rnd(20);
+                       break;
+               case DETECT_MONSTERS:
+                       see_monsters();
+                       break;
+               }
+       }
+
+       run_timers();
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+void
+fall_asleep(how_long, wakeup_msg)
+int how_long;
+boolean wakeup_msg;
+{
+       stop_occupation();
+       nomul(how_long);
+       /* generally don't notice sounds while sleeping */
+       if (wakeup_msg && multi == how_long) {
+           /* caller can follow with a direct call to Hear_again() if
+              there's a need to override this when wakeup_msg is true */
+           flags.soundok = 0;
+           afternmv = Hear_again;      /* this won't give any messages */
+       }
+       /* early wakeup from combat won't be possible until next monster turn */
+       u.usleep = monstermoves;
+       nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again;
+}
+
+/* Attach an egg hatch timeout to the given egg. */
+void
+attach_egg_hatch_timeout(egg)
+struct obj *egg;
+{
+       int i;
+
+       /* stop previous timer, if any */
+       (void) stop_timer(HATCH_EGG, (genericptr_t) egg);
+
+       /*
+        * Decide if and when to hatch the egg.  The old hatch_it() code tried
+        * once a turn from age 151 to 200 (inclusive), hatching if it rolled
+        * a number x, 1<=x<=age, where x>150.  This yields a chance of
+        * hatching > 99.9993%.  Mimic that here.
+        */
+       for (i = (MAX_EGG_HATCH_TIME-50)+1; i <= MAX_EGG_HATCH_TIME; i++)
+           if (rnd(i) > 150) {
+               /* egg will hatch */
+               (void) start_timer((long)i, TIMER_OBJECT,
+                                               HATCH_EGG, (genericptr_t)egg);
+               break;
+           }
+}
+
+/* prevent an egg from ever hatching */
+void
+kill_egg(egg)
+struct obj *egg;
+{
+       /* stop previous timer, if any */
+       (void) stop_timer(HATCH_EGG, (genericptr_t) egg);
+}
+
+/* timer callback routine: hatch the given egg */
+void
+hatch_egg(arg, timeout)
+genericptr_t arg;
+long timeout;
+{
+       struct obj *egg;
+       struct monst *mon, *mon2;
+       coord cc;
+       xchar x, y;
+       boolean yours, silent, knows_egg = FALSE;
+       boolean cansee_hatchspot = FALSE;
+       int i, mnum, hatchcount = 0;
+
+       egg = (struct obj *) arg;
+       /* sterilized while waiting */
+       if (egg->corpsenm == NON_PM) return;
+
+       mon = mon2 = (struct monst *)0;
+       mnum = big_to_little(egg->corpsenm);
+       /* The identity of one's father is learned, not innate */
+       yours = (egg->spe || (!flags.female && carried(egg) && !rn2(2)));
+       silent = (timeout != monstermoves);     /* hatched while away */
+
+       /* only can hatch when in INVENT, FLOOR, MINVENT */
+       if (get_obj_location(egg, &x, &y, 0)) {
+           hatchcount = rnd((int)egg->quan);
+           cansee_hatchspot = cansee(x, y) && !silent;
+           if (!(mons[mnum].geno & G_UNIQ) &&
+                  !(mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) {
+               for (i = hatchcount; i > 0; i--) {
+                   if (!enexto(&cc, x, y, &mons[mnum]) ||
+                        !(mon = makemon(&mons[mnum], cc.x, cc.y, NO_MINVENT)))
+                       break;
+                   /* tame if your own egg hatches while you're on the
+                      same dungeon level, or any dragon egg which hatches
+                      while it's in your inventory */
+                   if ((yours && !silent) ||
+                       (carried(egg) && mon->data->mlet == S_DRAGON)) {
+                       if ((mon2 = tamedog(mon, (struct obj *)0)) != 0) {
+                           mon = mon2;
+                           if (carried(egg) && mon->data->mlet != S_DRAGON)
+                               mon->mtame = 20;
+                       }
+                   }
+                   if (mvitals[mnum].mvflags & G_EXTINCT)
+                       break;  /* just made last one */
+                   mon2 = mon; /* in case makemon() fails on 2nd egg */
+               }
+               if (!mon) mon = mon2;
+               hatchcount -= i;
+               egg->quan -= (long)hatchcount;
+           }
+       }
+#if 0
+       /*
+        * We could possibly hatch while migrating, but the code isn't
+        * set up for it...
+        */
+       else if (obj->where == OBJ_MIGRATING) {
+           /*
+           We can do several things.  The first ones that come to
+           mind are:
+
+           + Create the hatched monster then place it on the migrating
+             mons list.  This is tough because all makemon() is made
+             to place the monster as well.    Makemon() also doesn't
+             lend itself well to splitting off a "not yet placed"
+             subroutine.
+
+           + Mark the egg as hatched, then place the monster when we
+             place the migrating objects.
+
+           + Or just kill any egg which gets sent to another level.
+             Falling is the usual reason such transportation occurs.
+           */
+           cansee_hatchspot = FALSE;
+           mon = ???
+           }
+#endif
+
+       if (mon) {
+           char monnambuf[BUFSZ], carriedby[BUFSZ];
+           boolean siblings = (hatchcount > 1), redraw = FALSE;
+
+           if (cansee_hatchspot) {
+               Sprintf(monnambuf, "%s%s",
+                       siblings ? "some " : "",
+                       siblings ?
+                       makeplural(m_monnam(mon)) : an(m_monnam(mon)));
+               /* we don't learn the egg type here because learning
+                  an egg type requires either seeing the egg hatch
+                  or being familiar with the egg already,
+                  as well as being able to see the resulting
+                  monster, checked below
+               */
+           }
+           switch (egg->where) {
+               case OBJ_INVENT:
+                   knows_egg = TRUE; /* true even if you are blind */
+                   if (!cansee_hatchspot)
+                       You_feel("%s %s from your pack!", something,
+                           locomotion(mon->data, "drop"));
+                   else
+                       You("see %s %s out of your pack!",
+                           monnambuf, locomotion(mon->data, "drop"));
+                   if (yours) {
+                       pline("%s cries sound like \"%s%s\"",
+                           siblings ? "Their" : "Its",
+                           flags.female ? "mommy" : "daddy",
+                           egg->spe ? "." : "?");
+                   } else if (mon->data->mlet == S_DRAGON) {
+                       verbalize("Gleep!");            /* Mything eggs :-) */
+                   }
+                   break;
+
+               case OBJ_FLOOR:
+                   if (cansee_hatchspot) {
+                       knows_egg = TRUE;
+                       You("see %s hatch.", monnambuf);
+                       redraw = TRUE;  /* update egg's map location */
+                   }
+                   break;
+
+               case OBJ_MINVENT:
+                   if (cansee_hatchspot) {
+                       /* egg carring monster might be invisible */
+                       if (canseemon(egg->ocarry)) {
+                           Sprintf(carriedby, "%s pack",
+                                    s_suffix(a_monnam(egg->ocarry)));
+                           knows_egg = TRUE;
+                       }
+                       else if (is_pool(mon->mx, mon->my))
+                           Strcpy(carriedby, "empty water");
+                       else
+                           Strcpy(carriedby, "thin air");
+                       You("see %s %s out of %s!", monnambuf,
+                           locomotion(mon->data, "drop"), carriedby);
+                   }
+                   break;
+#if 0
+               case OBJ_MIGRATING:
+                   break;
+#endif
+               default:
+                   impossible("egg hatched where? (%d)", (int)egg->where);
+                   break;
+           }
+
+           if (cansee_hatchspot && knows_egg)
+               learn_egg_type(mnum);
+
+           if (egg->quan > 0) {
+               /* still some eggs left */
+               attach_egg_hatch_timeout(egg);
+               if (egg->timed) {
+                   /* replace ordinary egg timeout with a short one */
+                   (void) stop_timer(HATCH_EGG, (genericptr_t)egg);
+                   (void) start_timer((long)rnd(12), TIMER_OBJECT,
+                                       HATCH_EGG, (genericptr_t)egg);
+               }
+           } else if (carried(egg)) {
+               useup(egg);
+           } else {
+               /* free egg here because we use it above */
+               obj_extract_self(egg);
+               obfree(egg, (struct obj *)0);
+           }
+           if (redraw) newsym(x, y);
+       }
+}
+
+/* Learn to recognize eggs of the given type. */
+void
+learn_egg_type(mnum)
+int mnum;
+{
+       /* baby monsters hatch from grown-up eggs */
+       mnum = little_to_big(mnum);
+       mvitals[mnum].mvflags |= MV_KNOWS_EGG;
+       /* we might have just learned about other eggs being carried */
+       update_inventory();
+}
+
+/* Attach a fig_transform timeout to the given figurine. */
+void
+attach_fig_transform_timeout(figurine)
+struct obj *figurine;
+{
+       int i;
+
+       /* stop previous timer, if any */
+       (void) stop_timer(FIG_TRANSFORM, (genericptr_t) figurine);
+
+       /*
+        * Decide when to transform the figurine.
+        */
+       i = rnd(9000) + 200;
+       /* figurine will transform */
+       (void) start_timer((long)i, TIMER_OBJECT,
+                               FIG_TRANSFORM, (genericptr_t)figurine);
+}
+
+/* give a fumble message */
+STATIC_OVL void
+slip_or_trip()
+{
+       struct obj *otmp = vobj_at(u.ux, u.uy);
+       const char *what, *pronoun;
+       char buf[BUFSZ];
+       boolean on_foot = TRUE;
+#ifdef STEED
+       if (u.usteed) on_foot = FALSE;
+#endif
+
+       if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy)) otmp = 0;
+
+       if (otmp && on_foot) {          /* trip over something in particular */
+           /*
+               If there is only one item, it will have just been named
+               during the move, so refer to by via pronoun; otherwise,
+               if the top item has been or can be seen, refer to it by
+               name; if not, look for rocks to trip over; trip over
+               anonymous "something" if there aren't any rocks.
+            */
+           pronoun = otmp->quan == 1L ? "it" : Hallucination ? "they" : "them";
+           what = !otmp->nexthere ? pronoun :
+                 (otmp->dknown || !Blind) ? doname(otmp) :
+                 ((otmp = sobj_at(ROCK, u.ux, u.uy)) == 0 ? something :
+                 (otmp->quan == 1L ? "a rock" : "some rocks"));
+           if (Hallucination) {
+               what = strcpy(buf, what);
+               buf[0] = highc(buf[0]);
+               pline("Egads!  %s bite%s your %s!",
+                       what, (!otmp || otmp->quan == 1L) ? "s" : "",
+                       body_part(FOOT));
+           } else {
+               You("trip over %s.", what);
+           }
+       } else if (rn2(3) && is_ice(u.ux, u.uy)) {
+           pline("%s %s%s on the ice.",
+#ifdef STEED
+               u.usteed ? upstart(x_monnam(u.usteed,
+                               u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
+                               (char *)0, SUPPRESS_SADDLE, FALSE)) :
+#endif
+               "You", rn2(2) ? "slip" : "slide", on_foot ? "" : "s");
+       } else {
+           if (on_foot) {
+               switch (rn2(4)) {
+                 case 1:
+                       You("trip over your own %s.", Hallucination ?
+                               "elbow" : makeplural(body_part(FOOT)));
+                       break;
+                 case 2:
+                       You("slip %s.", Hallucination ?
+                               "on a banana peel" : "and nearly fall");
+                       break;
+                 case 3:
+                       You("flounder.");
+                       break;
+                 default:
+                       You("stumble.");
+                       break;
+               }
+           }
+#ifdef STEED
+           else {
+               switch (rn2(4)) {
+                 case 1:
+                       Your("%s slip out of the stirrups.", makeplural(body_part(FOOT)));
+                       break;
+                 case 2:
+                       You("let go of the reins.");
+                       break;
+                 case 3:
+                       You("bang into the saddle-horn.");
+                       break;
+                 default:
+                       You("slide to one side of the saddle.");
+                       break;
+               }
+               dismount_steed(DISMOUNT_FELL);
+           }
+#endif
+       }
+}
+
+/* Print a lamp flicker message with tailer. */
+STATIC_OVL void
+see_lamp_flicker(obj, tailer)
+struct obj *obj;
+const char *tailer;
+{
+       switch (obj->where) {
+           case OBJ_INVENT:
+           case OBJ_MINVENT:
+               pline("%s flickers%s.", Yname2(obj), tailer);
+               break;
+           case OBJ_FLOOR:
+               You("see %s flicker%s.", an(xname(obj)), tailer);
+               break;
+       }
+}
+
+/* Print a dimming message for brass lanterns. */
+STATIC_OVL void
+lantern_message(obj)
+struct obj *obj;
+{
+       /* from adventure */
+       switch (obj->where) {
+           case OBJ_INVENT:
+               Your("lantern is getting dim.");
+               if (Hallucination)
+                   pline("Batteries have not been invented yet.");
+               break;
+           case OBJ_FLOOR:
+               You("see a lantern getting dim.");
+               break;
+           case OBJ_MINVENT:
+               pline("%s lantern is getting dim.",
+                   s_suffix(Monnam(obj->ocarry)));
+               break;
+       }
+}
+
+/*
+ * Timeout callback for for objects that are burning. E.g. lamps, candles.
+ * See begin_burn() for meanings of obj->age and obj->spe.
+ */
+void
+burn_object(arg, timeout)
+genericptr_t arg;
+long timeout;
+{
+       struct obj *obj = (struct obj *) arg;
+       boolean canseeit, many, menorah, need_newsym;
+       xchar x, y;
+       char whose[BUFSZ];
+
+       menorah = obj->otyp == CANDELABRUM_OF_INVOCATION;
+       many = menorah ? obj->spe > 1 : obj->quan > 1L;
+
+       /* timeout while away */
+       if (timeout != monstermoves) {
+           long how_long = monstermoves - timeout;
+
+           if (how_long >= obj->age) {
+               obj->age = 0;
+               end_burn(obj, FALSE);
+
+               if (menorah) {
+                   obj->spe = 0;       /* no more candles */
+               } else if (Is_candle(obj) || obj->otyp == POT_OIL) {
+                   /* get rid of candles and burning oil potions */
+                   obj_extract_self(obj);
+                   obfree(obj, (struct obj *)0);
+                   obj = (struct obj *) 0;
+               }
+
+           } else {
+               obj->age -= how_long;
+               begin_burn(obj, TRUE);
+           }
+           return;
+       }
+
+       /* only interested in INVENT, FLOOR, and MINVENT */
+       if (get_obj_location(obj, &x, &y, 0)) {
+           canseeit = !Blind && cansee(x, y);
+           /* set up `whose[]' to be "Your" or "Fred's" or "The goblin's" */
+           (void) Shk_Your(whose, obj);
+       } else {
+           canseeit = FALSE;
+       }
+       need_newsym = FALSE;
+
+       /* obj->age is the age remaining at this point.  */
+       switch (obj->otyp) {
+           case POT_OIL:
+                   /* this should only be called when we run out */
+                   if (canseeit) {
+                       switch (obj->where) {
+                           case OBJ_INVENT:
+                           case OBJ_MINVENT:
+                               pline("%s potion of oil has burnt away.",
+                                   whose);
+                               break;
+                           case OBJ_FLOOR:
+                               You("see a burning potion of oil go out.");
+                               need_newsym = TRUE;
+                               break;
+                       }
+                   }
+                   end_burn(obj, FALSE);       /* turn off light source */
+                   obj_extract_self(obj);
+                   obfree(obj, (struct obj *)0);
+                   obj = (struct obj *) 0;
+                   break;
+
+           case BRASS_LANTERN:
+           case OIL_LAMP:
+               switch((int)obj->age) {
+                   case 150:
+                   case 100:
+                   case 50:
+                       if (canseeit) {
+                           if (obj->otyp == BRASS_LANTERN)
+                               lantern_message(obj);
+                           else
+                               see_lamp_flicker(obj,
+                                   obj->age == 50L ? " considerably" : "");
+                       }
+                       break;
+
+                   case 25:
+                       if (canseeit) {
+                           if (obj->otyp == BRASS_LANTERN)
+                               lantern_message(obj);
+                           else {
+                               switch (obj->where) {
+                                   case OBJ_INVENT:
+                                   case OBJ_MINVENT:
+                                       pline("%s %s seems about to go out.",
+                                           whose, xname(obj));
+                                       break;
+                                   case OBJ_FLOOR:
+                                       You("see %s about to go out.",
+                                           an(xname(obj)));
+                                       break;
+                               }
+                           }
+                       }
+                       break;
+
+                   case 0:
+                       /* even if blind you'll know if holding it */
+                       if (canseeit || obj->where == OBJ_INVENT) {
+                           switch (obj->where) {
+                               case OBJ_INVENT:
+                               case OBJ_MINVENT:
+                                   if (obj->otyp == BRASS_LANTERN)
+                                       pline("%s lantern has run out of power.",
+                                           whose);
+                                   else
+                                       pline("%s %s has gone out.",
+                                           whose, xname(obj));
+                                   break;
+                               case OBJ_FLOOR:
+                                   if (obj->otyp == BRASS_LANTERN)
+                                       You("see a lantern run out of power.");
+                                   else
+                                       You("see %s go out.",
+                                           an(xname(obj)));
+                                   break;
+                           }
+                       }
+                       end_burn(obj, FALSE);
+                       break;
+
+                   default:
+                       /*
+                        * Someone added fuel to the lamp while it was
+                        * lit.  Just fall through and let begin burn
+                        * handle the new age.
+                        */
+                       break;
+               }
+
+               if (obj->age)
+                   begin_burn(obj, TRUE);
+
+               break;
+
+           case CANDELABRUM_OF_INVOCATION:
+           case TALLOW_CANDLE:
+           case WAX_CANDLE:
+               switch (obj->age) {
+                   case 75:
+                       if (canseeit)
+                           switch (obj->where) {
+                               case OBJ_INVENT:
+                               case OBJ_MINVENT:
+                                   pline("%s %scandle%s getting short.",
+                                       whose,
+                                       menorah ? "candelabrum's " : "",
+                                       many ? "s are" : " is");
+                                   break;
+                               case OBJ_FLOOR:
+                                   You("see %scandle%s getting short.",
+                                           menorah ? "a candelabrum's " :
+                                               many ? "some " : "a ",
+                                           many ? "s" : "");
+                                   break;
+                           }
+                       break;
+
+                   case 15:
+                       if (canseeit)
+                           switch (obj->where) {
+                               case OBJ_INVENT:
+                               case OBJ_MINVENT:
+                                   pline(
+                                       "%s %scandle%s flame%s flicker%s low!",
+                                           whose,
+                                           menorah ? "candelabrum's " : "",
+                                           many ? "s'" : "'s",
+                                           many ? "s" : "",
+                                           many ? "" : "s");
+                                   break;
+                               case OBJ_FLOOR:
+                                   You("see %scandle%s flame%s flicker low!",
+                                           menorah ? "a candelabrum's " :
+                                               many ? "some " : "a ",
+                                           many ? "s'" : "'s",
+                                           many ? "s" : "");
+                                   break;
+                           }
+                       break;
+
+                   case 0:
+                       /* we know even if blind and in our inventory */
+                       if (canseeit || obj->where == OBJ_INVENT) {
+                           if (menorah) {
+                               switch (obj->where) {
+                                   case OBJ_INVENT:
+                                   case OBJ_MINVENT:
+                                       pline("%s candelabrum's flame%s.",
+                                           whose,
+                                           many ? "s die" : " dies");
+                                       break;
+                                   case OBJ_FLOOR:
+                                       You("see a candelabrum's flame%s die.",
+                                               many ? "s" : "");
+                                       break;
+                               }
+                           } else {
+                               switch (obj->where) {
+                                   case OBJ_INVENT:
+                                   case OBJ_MINVENT:
+                                       pline("%s %s %s consumed!",
+                                           whose,
+                                           xname(obj),
+                                           many ? "are" : "is");
+                                       break;
+                                   case OBJ_FLOOR:
+                                       /*
+                                       You see some wax candles consumed!
+                                       You see a wax candle consumed!
+                                       */
+                                       You("see %s%s consumed!",
+                                           many ? "some " : "",
+                                           many ? xname(obj):an(xname(obj)));
+                                       need_newsym = TRUE;
+                                       break;
+                               }
+
+                               /* post message */
+                               pline(Hallucination ?
+                                       (many ? "They shriek!" :
+                                               "It shrieks!") :
+                                       Blind ? "" :
+                                           (many ? "Their flames die." :
+                                                   "Its flame dies."));
+                           }
+                       }
+                       end_burn(obj, FALSE);
+
+                       if (menorah) {
+                           obj->spe = 0;
+                       } else {
+                           obj_extract_self(obj);
+                           obfree(obj, (struct obj *)0);
+                           obj = (struct obj *) 0;
+                       }
+                       break;
+
+                   default:
+                       /*
+                        * Someone added fuel (candles) to the menorah while
+                        * it was lit.  Just fall through and let begin burn
+                        * handle the new age.
+                        */
+                       break;
+               }
+
+               if (obj && obj->age)
+                   begin_burn(obj, TRUE);
+
+               break;
+
+           default:
+               impossible("burn_object: unexpeced obj %s", xname(obj));
+               break;
+       }
+       if (need_newsym) newsym(x, y);
+}
+
+/*
+ * Start a burn timeout on the given object. If not "already lit" then
+ * create a light source for the vision system.  There had better not
+ * be a burn already running on the object.
+ *
+ * Magic lamps stay lit as long as there's a genie inside, so don't start
+ * a timer.
+ *
+ * Burn rules:
+ *     potions of oil, lamps & candles:
+ *             age = # of turns of fuel left
+ *             spe = <unused>
+ *
+ *     magic lamps:
+ *             age = <unused>
+ *             spe = 0 not lightable, 1 lightable forever
+ *
+ *     candelabrum:
+ *             age = # of turns of fuel left
+ *             spe = # of candles
+ *
+ * Once the burn begins, the age will be set to the amount of fuel
+ * remaining _once_the_burn_finishes_.  If the burn is terminated
+ * early then fuel is added back.
+ *
+ * This use of age differs from the use of age for corpses and eggs.
+ * For the latter items, age is when the object was created, so we
+ * know when it becomes "bad".
+ *
+ * This is a "silent" routine - it should not print anything out.
+ */
+void
+begin_burn(obj, already_lit)
+       struct obj *obj;
+       boolean already_lit;
+{
+       int radius = 3;
+       long turns = 0;
+       boolean do_timer = TRUE;
+
+       if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj))
+           return;
+
+       switch (obj->otyp) {
+           case MAGIC_LAMP:
+               obj->lamplit = 1;
+               do_timer = FALSE;
+               break;
+
+           case POT_OIL:
+               turns = obj->age;
+               radius = 1;     /* very dim light */
+               break;
+
+           case BRASS_LANTERN:
+           case OIL_LAMP:
+               /* magic times are 150, 100, 50, 25, and 0 */
+               if (obj->age > 150L)
+                   turns = obj->age - 150L;
+               else if (obj->age > 100L)
+                   turns = obj->age - 100L;
+               else if (obj->age > 50L)
+                   turns = obj->age - 50L;
+               else if (obj->age > 25L)
+                   turns = obj->age - 25L;
+               else
+                   turns = obj->age;
+               break;
+
+           case CANDELABRUM_OF_INVOCATION:
+           case TALLOW_CANDLE:
+           case WAX_CANDLE:
+               /* magic times are 75, 15, and 0 */
+               if (obj->age > 75L)
+                   turns = obj->age - 75L;
+               else if (obj->age > 15L)
+                   turns = obj->age - 15L;
+               else
+                   turns = obj->age;
+               radius = candle_light_range(obj);
+               break;
+
+           default:
+                /* [ALI] Support artifact light sources */
+                if (artifact_light(obj)) {
+                   obj->lamplit = 1;
+                   do_timer = FALSE;
+                   radius = 2;
+               } else {
+                   impossible("begin burn: unexpected %s", xname(obj));
+                   turns = obj->age;
+               }
+               break;
+       }
+
+       if (do_timer) {
+           if (start_timer(turns, TIMER_OBJECT,
+                                       BURN_OBJECT, (genericptr_t)obj)) {
+               obj->lamplit = 1;
+               obj->age -= turns;
+               if (carried(obj) && !already_lit)
+                   update_inventory();
+           } else {
+               obj->lamplit = 0;
+           }
+       } else {
+           if (carried(obj) && !already_lit)
+               update_inventory();
+       }
+
+       if (obj->lamplit && !already_lit) {
+           xchar x, y;
+
+           if (get_obj_location(obj, &x, &y, CONTAINED_TOO|BURIED_TOO))
+               new_light_source(x, y, radius, LS_OBJECT, (genericptr_t) obj);
+           else
+               impossible("begin_burn: can't get obj position");
+       }
+}
+
+/*
+ * Stop a burn timeout on the given object if timer attached.  Darken
+ * light source.
+ */
+void
+end_burn(obj, timer_attached)
+       struct obj *obj;
+       boolean timer_attached;
+{
+       if (!obj->lamplit) {
+           impossible("end_burn: obj %s not lit", xname(obj));
+           return;
+       }
+
+       if (obj->otyp == MAGIC_LAMP || artifact_light(obj))
+           timer_attached = FALSE;
+
+       if (!timer_attached) {
+           /* [DS] Cleanup explicitly, since timer cleanup won't happen */
+           del_light_source(LS_OBJECT, (genericptr_t)obj);
+           obj->lamplit = 0;
+           if (obj->where == OBJ_INVENT)
+               update_inventory();
+       } else if (!stop_timer(BURN_OBJECT, (genericptr_t) obj))
+           impossible("end_burn: obj %s not timed!", xname(obj));
+}
+
+#endif /* OVL1 */
+#ifdef OVL0
+
+/*
+ * Cleanup a burning object if timer stopped.
+ */
+static void
+cleanup_burn(arg, expire_time)
+    genericptr_t arg;
+    long expire_time;
+{
+    struct obj *obj = (struct obj *)arg;
+    if (!obj->lamplit) {
+       impossible("cleanup_burn: obj %s not lit", xname(obj));
+       return;
+    }
+
+    del_light_source(LS_OBJECT, arg);
+
+    /* restore unused time */
+    obj->age += expire_time - monstermoves;
+
+    obj->lamplit = 0;
+
+    if (obj->where == OBJ_INVENT)
+       update_inventory();
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+void
+do_storms()
+{
+    int nstrike;
+    register int x, y;
+    int dirx, diry;
+    int count;
+
+    /* no lightning if not the air level or too often, even then */
+    if(!Is_airlevel(&u.uz) || rn2(8))
+       return;
+
+    /* the number of strikes is 8-log2(nstrike) */
+    for(nstrike = rnd(64); nstrike <= 64; nstrike *= 2) {
+       count = 0;
+       do {
+           x = rnd(COLNO-1);
+           y = rn2(ROWNO);
+       } while (++count < 100 && levl[x][y].typ != CLOUD);
+
+       if(count < 100) {
+           dirx = rn2(3) - 1;
+           diry = rn2(3) - 1;
+           if(dirx != 0 || diry != 0)
+               buzz(-15, /* "monster" LIGHTNING spell */
+                    8, x, y, dirx, diry);
+       }
+    }
+
+    if(levl[u.ux][u.uy].typ == CLOUD) {
+       /* inside a cloud during a thunder storm is deafening */
+       pline("Kaboom!!!  Boom!!  Boom!!");
+       if(!u.uinvulnerable) {
+           stop_occupation();
+           nomul(-3);
+       }
+    } else
+       You_hear("a rumbling noise.");
+}
+#endif /* OVL1 */
+
+
+#ifdef OVL0
+/* ------------------------------------------------------------------------- */
+/*
+ * Generic Timeout Functions.
+ *
+ * Interface:
+ *
+ * General:
+ *     boolean start_timer(long timeout,short kind,short func_index,
+ *                                                     genericptr_t arg)
+ *             Start a timer of kind 'kind' that will expire at time
+ *             monstermoves+'timeout'.  Call the function at 'func_index'
+ *             in the timeout table using argument 'arg'.  Return TRUE if
+ *             a timer was started.  This places the timer on a list ordered
+ *             "sooner" to "later".  If an object, increment the object's
+ *             timer count.
+ *
+ *     long stop_timer(short func_index, genericptr_t arg)
+ *             Stop a timer specified by the (func_index, arg) pair.  This
+ *             assumes that such a pair is unique.  Return the time the
+ *             timer would have gone off.  If no timer is found, return 0.
+ *             If an object, decrement the object's timer count.
+ *
+ *     void run_timers(void)
+ *             Call timers that have timed out.
+ *
+ *
+ * Save/Restore:
+ *     void save_timers(int fd, int mode, int range)
+ *             Save all timers of range 'range'.  Range is either global
+ *             or local.  Global timers follow game play, local timers
+ *             are saved with a level.  Object and monster timers are
+ *             saved using their respective id's instead of pointers.
+ *
+ *     void restore_timers(int fd, int range, boolean ghostly, long adjust)
+ *             Restore timers of range 'range'.  If from a ghost pile,
+ *             adjust the timeout by 'adjust'.  The object and monster
+ *             ids are not restored until later.
+ *
+ *     void relink_timers(boolean ghostly)
+ *             Relink all object and monster timers that had been saved
+ *             using their object's or monster's id number.
+ *
+ * Object Specific:
+ *     void obj_move_timers(struct obj *src, struct obj *dest)
+ *             Reassign all timers from src to dest.
+ *
+ *     void obj_split_timers(struct obj *src, struct obj *dest)
+ *             Duplicate all timers assigned to src and attach them to dest.
+ *
+ *     void obj_stop_timers(struct obj *obj)
+ *             Stop all timers attached to obj.
+ */
+
+#ifdef WIZARD
+STATIC_DCL const char *FDECL(kind_name, (SHORT_P));
+STATIC_DCL void FDECL(print_queue, (winid, timer_element *));
+#endif
+STATIC_DCL void FDECL(insert_timer, (timer_element *));
+STATIC_DCL timer_element *FDECL(remove_timer, (timer_element **, SHORT_P,
+                                                               genericptr_t));
+STATIC_DCL void FDECL(write_timer, (int, timer_element *));
+STATIC_DCL boolean FDECL(mon_is_local, (struct monst *));
+STATIC_DCL boolean FDECL(timer_is_local, (timer_element *));
+STATIC_DCL int FDECL(maybe_write_timer, (int, int, BOOLEAN_P));
+
+/* ordered timer list */
+static timer_element *timer_base;              /* "active" */
+static unsigned long timer_id = 1;
+
+/* If defined, then include names when printing out the timer queue */
+#define VERBOSE_TIMER
+
+typedef struct {
+    timeout_proc f, cleanup;
+#ifdef VERBOSE_TIMER
+    const char *name;
+# define TTAB(a, b, c) {a,b,c}
+#else
+# define TTAB(a, b, c) {a,b}
+#endif
+} ttable;
+
+/* table of timeout functions */
+static const ttable timeout_funcs[NUM_TIME_FUNCS] = {
+    TTAB(rot_organic,  (timeout_proc)0,        "rot_organic"),
+    TTAB(rot_corpse,   (timeout_proc)0,        "rot_corpse"),
+    TTAB(revive_mon,   (timeout_proc)0,        "revive_mon"),
+    TTAB(burn_object,  cleanup_burn,           "burn_object"),
+    TTAB(hatch_egg,    (timeout_proc)0,        "hatch_egg"),
+    TTAB(fig_transform,        (timeout_proc)0,        "fig_transform")
+};
+#undef TTAB
+
+
+#if defined(WIZARD)
+
+STATIC_OVL const char *
+kind_name(kind)
+    short kind;
+{
+    switch (kind) {
+       case TIMER_LEVEL: return "level";
+       case TIMER_GLOBAL: return "global";
+       case TIMER_OBJECT: return "object";
+       case TIMER_MONSTER: return "monster";
+    }
+    return "unknown";
+}
+
+STATIC_OVL void
+print_queue(win, base)
+    winid win;
+    timer_element *base;
+{
+    timer_element *curr;
+    char buf[BUFSZ], arg_address[20];
+
+    if (!base) {
+       putstr(win, 0, "<empty>");
+    } else {
+       putstr(win, 0, "timeout  id   kind   call");
+       for (curr = base; curr; curr = curr->next) {
+#ifdef VERBOSE_TIMER
+           Sprintf(buf, " %4ld   %4ld  %-6s %s(%s)",
+               curr->timeout, curr->tid, kind_name(curr->kind),
+               timeout_funcs[curr->func_index].name,
+               fmt_ptr((genericptr_t)curr->arg, arg_address));
+#else
+           Sprintf(buf, " %4ld   %4ld  %-6s #%d(%s)",
+               curr->timeout, curr->tid, kind_name(curr->kind),
+               curr->func_index,
+               fmt_ptr((genericptr_t)curr->arg, arg_address));
+#endif
+           putstr(win, 0, buf);
+       }
+    }
+}
+
+int
+wiz_timeout_queue()
+{
+    winid win;
+    char buf[BUFSZ];
+
+    win = create_nhwindow(NHW_MENU);   /* corner text window */
+    if (win == WIN_ERR) return 0;
+
+    Sprintf(buf, "Current time = %ld.", monstermoves);
+    putstr(win, 0, buf);
+    putstr(win, 0, "");
+    putstr(win, 0, "Active timeout queue:");
+    putstr(win, 0, "");
+    print_queue(win, timer_base);
+
+    display_nhwindow(win, FALSE);
+    destroy_nhwindow(win);
+
+    return 0;
+}
+
+void
+timer_sanity_check()
+{
+    timer_element *curr;
+    char obj_address[20];
+
+    /* this should be much more complete */
+    for (curr = timer_base; curr; curr = curr->next)
+       if (curr->kind == TIMER_OBJECT) {
+           struct obj *obj = (struct obj *) curr->arg;
+           if (obj->timed == 0) {
+               pline("timer sanity: untimed obj %s, timer %ld",
+                     fmt_ptr((genericptr_t)obj, obj_address), curr->tid);
+           }
+       }
+}
+
+#endif /* WIZARD */
+
+
+/*
+ * Pick off timeout elements from the global queue and call their functions.
+ * Do this until their time is less than or equal to the move count.
+ */
+void
+run_timers()
+{
+    timer_element *curr;
+
+    /*
+     * Always use the first element.  Elements may be added or deleted at
+     * any time.  The list is ordered, we are done when the first element
+     * is in the future.
+     */
+    while (timer_base && timer_base->timeout <= monstermoves) {
+       curr = timer_base;
+       timer_base = curr->next;
+
+       if (curr->kind == TIMER_OBJECT) ((struct obj *)(curr->arg))->timed--;
+       (*timeout_funcs[curr->func_index].f)(curr->arg, curr->timeout);
+       free((genericptr_t) curr);
+    }
+}
+
+
+/*
+ * Start a timer.  Return TRUE if successful.
+ */
+boolean
+start_timer(when, kind, func_index, arg)
+long when;
+short kind;
+short func_index;
+genericptr_t arg;
+{
+    timer_element *gnu;
+
+    if (func_index < 0 || func_index >= NUM_TIME_FUNCS)
+       panic("start_timer");
+
+    gnu = (timer_element *) alloc(sizeof(timer_element));
+    gnu->next = 0;
+    gnu->tid = timer_id++;
+    gnu->timeout = monstermoves + when;
+    gnu->kind = kind;
+    gnu->needs_fixup = 0;
+    gnu->func_index = func_index;
+    gnu->arg = arg;
+    insert_timer(gnu);
+
+    if (kind == TIMER_OBJECT)  /* increment object's timed count */
+       ((struct obj *)arg)->timed++;
+
+    /* should check for duplicates and fail if any */
+    return TRUE;
+}
+
+
+/*
+ * Remove the timer from the current list and free it up.  Return the time
+ * it would have gone off, 0 if not found.
+ */
+long
+stop_timer(func_index, arg)
+short func_index;
+genericptr_t arg;
+{
+    timer_element *doomed;
+    long timeout;
+
+    doomed = remove_timer(&timer_base, func_index, arg);
+
+    if (doomed) {
+       timeout = doomed->timeout;
+       if (doomed->kind == TIMER_OBJECT)
+           ((struct obj *)arg)->timed--;
+       if (timeout_funcs[doomed->func_index].cleanup)
+           (*timeout_funcs[doomed->func_index].cleanup)(arg, timeout);
+       free((genericptr_t) doomed);
+       return timeout;
+    }
+    return 0;
+}
+
+
+/*
+ * Move all object timers from src to dest, leaving src untimed.
+ */
+void
+obj_move_timers(src, dest)
+    struct obj *src, *dest;
+{
+    int count;
+    timer_element *curr;
+
+    for (count = 0, curr = timer_base; curr; curr = curr->next)
+       if (curr->kind == TIMER_OBJECT && curr->arg == (genericptr_t)src) {
+           curr->arg = (genericptr_t) dest;
+           dest->timed++;
+           count++;
+       }
+    if (count != src->timed)
+       panic("obj_move_timers");
+    src->timed = 0;
+}
+
+
+/*
+ * Find all object timers and duplicate them for the new object "dest".
+ */
+void
+obj_split_timers(src, dest)
+    struct obj *src, *dest;
+{
+    timer_element *curr, *next_timer=0;
+
+    for (curr = timer_base; curr; curr = next_timer) {
+       next_timer = curr->next;        /* things may be inserted */
+       if (curr->kind == TIMER_OBJECT && curr->arg == (genericptr_t)src) {
+           (void) start_timer(curr->timeout-monstermoves, TIMER_OBJECT,
+                                       curr->func_index, (genericptr_t)dest);
+       }
+    }
+}
+
+
+/*
+ * Stop all timers attached to this object.  We can get away with this because
+ * all object pointers are unique.
+ */
+void
+obj_stop_timers(obj)
+    struct obj *obj;
+{
+    timer_element *curr, *prev, *next_timer=0;
+
+    for (prev = 0, curr = timer_base; curr; curr = next_timer) {
+       next_timer = curr->next;
+       if (curr->kind == TIMER_OBJECT && curr->arg == (genericptr_t)obj) {
+           if (prev)
+               prev->next = curr->next;
+           else
+               timer_base = curr->next;
+           if (timeout_funcs[curr->func_index].cleanup)
+               (*timeout_funcs[curr->func_index].cleanup)(curr->arg,
+                       curr->timeout);
+           free((genericptr_t) curr);
+       } else {
+           prev = curr;
+       }
+    }
+    obj->timed = 0;
+}
+
+
+/* Insert timer into the global queue */
+STATIC_OVL void
+insert_timer(gnu)
+    timer_element *gnu;
+{
+    timer_element *curr, *prev;
+
+    for (prev = 0, curr = timer_base; curr; prev = curr, curr = curr->next)
+       if (curr->timeout >= gnu->timeout) break;
+
+    gnu->next = curr;
+    if (prev)
+       prev->next = gnu;
+    else
+       timer_base = gnu;
+}
+
+
+STATIC_OVL timer_element *
+remove_timer(base, func_index, arg)
+timer_element **base;
+short func_index;
+genericptr_t arg;
+{
+    timer_element *prev, *curr;
+
+    for (prev = 0, curr = *base; curr; prev = curr, curr = curr->next)
+       if (curr->func_index == func_index && curr->arg == arg) break;
+
+    if (curr) {
+       if (prev)
+           prev->next = curr->next;
+       else
+           *base = curr->next;
+    }
+
+    return curr;
+}
+
+
+STATIC_OVL void
+write_timer(fd, timer)
+    int fd;
+    timer_element *timer;
+{
+    genericptr_t arg_save;
+
+    switch (timer->kind) {
+       case TIMER_GLOBAL:
+       case TIMER_LEVEL:
+           /* assume no pointers in arg */
+           bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
+           break;
+
+       case TIMER_OBJECT:
+           if (timer->needs_fixup)
+               bwrite(fd, (genericptr_t)timer, sizeof(timer_element));
+           else {
+               /* replace object pointer with id */
+               arg_save = timer->arg;
+               timer->arg = (genericptr_t)((struct obj *)timer->arg)->o_id;
+               timer->needs_fixup = 1;
+               bwrite(fd, (genericptr_t)timer, sizeof(timer_element));
+               timer->arg = arg_save;
+               timer->needs_fixup = 0;
+           }
+           break;
+
+       case TIMER_MONSTER:
+           if (timer->needs_fixup)
+               bwrite(fd, (genericptr_t)timer, sizeof(timer_element));
+           else {
+               /* replace monster pointer with id */
+               arg_save = timer->arg;
+               timer->arg = (genericptr_t)((struct monst *)timer->arg)->m_id;
+               timer->needs_fixup = 1;
+               bwrite(fd, (genericptr_t)timer, sizeof(timer_element));
+               timer->arg = arg_save;
+               timer->needs_fixup = 0;
+           }
+           break;
+
+       default:
+           panic("write_timer");
+           break;
+    }
+}
+
+
+/*
+ * Return TRUE if the object will stay on the level when the level is
+ * saved.
+ */
+boolean
+obj_is_local(obj)
+    struct obj *obj;
+{
+    switch (obj->where) {
+       case OBJ_INVENT:
+       case OBJ_MIGRATING:     return FALSE;
+       case OBJ_FLOOR:
+       case OBJ_BURIED:        return TRUE;
+       case OBJ_CONTAINED:     return obj_is_local(obj->ocontainer);
+       case OBJ_MINVENT:       return mon_is_local(obj->ocarry);
+    }
+    panic("obj_is_local");
+    return FALSE;
+}
+
+
+/*
+ * Return TRUE if the given monster will stay on the level when the
+ * level is saved.
+ */
+STATIC_OVL boolean
+mon_is_local(mon)
+struct monst *mon;
+{
+    struct monst *curr;
+
+    for (curr = migrating_mons; curr; curr = curr->nmon)
+       if (curr == mon) return FALSE;
+    /* `mydogs' is used during level changes, never saved and restored */
+    for (curr = mydogs; curr; curr = curr->nmon)
+       if (curr == mon) return FALSE;
+    return TRUE;
+}
+
+
+/*
+ * Return TRUE if the timer is attached to something that will stay on the
+ * level when the level is saved.
+ */
+STATIC_OVL boolean
+timer_is_local(timer)
+    timer_element *timer;
+{
+    switch (timer->kind) {
+       case TIMER_LEVEL:       return TRUE;
+       case TIMER_GLOBAL:      return FALSE;
+       case TIMER_OBJECT:      return obj_is_local((struct obj *)timer->arg);
+       case TIMER_MONSTER:     return mon_is_local((struct monst *)timer->arg);
+    }
+    panic("timer_is_local");
+    return FALSE;
+}
+
+
+/*
+ * Part of the save routine.  Count up the number of timers that would
+ * be written.  If write_it is true, actually write the timer.
+ */
+STATIC_OVL int
+maybe_write_timer(fd, range, write_it)
+    int fd, range;
+    boolean write_it;
+{
+    int count = 0;
+    timer_element *curr;
+
+    for (curr = timer_base; curr; curr = curr->next) {
+       if (range == RANGE_GLOBAL) {
+           /* global timers */
+
+           if (!timer_is_local(curr)) {
+               count++;
+               if (write_it) write_timer(fd, curr);
+           }
+
+       } else {
+           /* local timers */
+
+           if (timer_is_local(curr)) {
+               count++;
+               if (write_it) write_timer(fd, curr);
+           }
+
+       }
+    }
+
+    return count;
+}
+
+
+/*
+ * Save part of the timer list.  The parameter 'range' specifies either
+ * global or level timers to save.  The timer ID is saved with the global
+ * timers.
+ *
+ * Global range:
+ *             + timeouts that follow the hero (global)
+ *             + timeouts that follow obj & monst that are migrating
+ *
+ * Level range:
+ *             + timeouts that are level specific (e.g. storms)
+ *             + timeouts that stay with the level (obj & monst)
+ */
+void
+save_timers(fd, mode, range)
+    int fd, mode, range;
+{
+    timer_element *curr, *prev, *next_timer=0;
+    int count;
+
+    if (perform_bwrite(mode)) {
+       if (range == RANGE_GLOBAL)
+           bwrite(fd, (genericptr_t) &timer_id, sizeof(timer_id));
+
+       count = maybe_write_timer(fd, range, FALSE);
+       bwrite(fd, (genericptr_t) &count, sizeof count);
+       (void) maybe_write_timer(fd, range, TRUE);
+    }
+
+    if (release_data(mode)) {
+       for (prev = 0, curr = timer_base; curr; curr = next_timer) {
+           next_timer = curr->next;    /* in case curr is removed */
+
+           if ( !(!!(range == RANGE_LEVEL) ^ !!timer_is_local(curr)) ) {
+               if (prev)
+                   prev->next = curr->next;
+               else
+                   timer_base = curr->next;
+               free((genericptr_t) curr);
+               /* prev stays the same */
+           } else {
+               prev = curr;
+           }
+       }
+    }
+}
+
+
+/*
+ * Pull in the structures from disk, but don't recalculate the object and
+ * monster pointers.
+ */
+void
+restore_timers(fd, range, ghostly, adjust)
+    int fd, range;
+    boolean ghostly;   /* restoring from a ghost level */
+    long adjust;       /* how much to adjust timeout */
+{
+    int count;
+    timer_element *curr;
+
+    if (range == RANGE_GLOBAL)
+       mread(fd, (genericptr_t) &timer_id, sizeof timer_id);
+
+    /* restore elements */
+    mread(fd, (genericptr_t) &count, sizeof count);
+    while (count-- > 0) {
+       curr = (timer_element *) alloc(sizeof(timer_element));
+       mread(fd, (genericptr_t) curr, sizeof(timer_element));
+       if (ghostly)
+           curr->timeout += adjust;
+       insert_timer(curr);
+    }
+}
+
+
+/* reset all timers that are marked for reseting */
+void
+relink_timers(ghostly)
+    boolean ghostly;
+{
+    timer_element *curr;
+    unsigned nid;
+
+    for (curr = timer_base; curr; curr = curr->next) {
+       if (curr->needs_fixup) {
+           if (curr->kind == TIMER_OBJECT) {
+               if (ghostly) {
+                   if (!lookup_id_mapping((unsigned)curr->arg, &nid))
+                       panic("relink_timers 1");
+               } else
+                   nid = (unsigned) curr->arg;
+               curr->arg = (genericptr_t) find_oid(nid);
+               if (!curr->arg) panic("cant find o_id %d", nid);
+               curr->needs_fixup = 0;
+           } else if (curr->kind == TIMER_MONSTER) {
+               panic("relink_timers: no monster timer implemented");
+           } else
+               panic("relink_timers 2");
+       }
+    }
+}
+
+#endif /* OVL0 */
+
+/*timeout.c*/
diff --git a/src/topten.c b/src/topten.c
new file mode 100644 (file)
index 0000000..19a0488
--- /dev/null
@@ -0,0 +1,977 @@
+/*     SCCS Id: @(#)topten.c   3.4     2000/01/21      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "dlb.h"
+#ifdef SHORT_FILENAMES
+#include "patchlev.h"
+#else
+#include "patchlevel.h"
+#endif
+
+#ifdef VMS
+ /* We don't want to rewrite the whole file, because that entails       */
+ /* creating a new version which requires that the old one be deletable. */
+# define UPDATE_RECORD_IN_PLACE
+#endif
+
+/*
+ * Updating in place can leave junk at the end of the file in some
+ * circumstances (if it shrinks and the O.S. doesn't have a straightforward
+ * way to truncate it).  The trailing junk is harmless and the code
+ * which reads the scores will ignore it.
+ */
+#ifdef UPDATE_RECORD_IN_PLACE
+static long final_fpos;
+#endif
+
+#define done_stopprint program_state.stopprint
+
+#define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
+#define dealloc_ttentry(ttent) free((genericptr_t) (ttent))
+#define NAMSZ  10
+#define DTHSZ  100
+#define ROLESZ   3
+#define PERSMAX         3              /* entries per name/uid per char. allowed */
+#define POINTSMIN      1       /* must be > 0 */
+#define ENTRYMAX       100     /* must be >= 10 */
+
+#if !defined(MICRO) && !defined(MAC) && !defined(WIN32)
+#define PERS_IS_UID            /* delete for PERSMAX per name; now per uid */
+#endif
+struct toptenentry {
+       struct toptenentry *tt_next;
+#ifdef UPDATE_RECORD_IN_PLACE
+       long fpos;
+#endif
+       long points;
+       int deathdnum, deathlev;
+       int maxlvl, hp, maxhp, deaths;
+       int ver_major, ver_minor, patchlevel;
+       long deathdate, birthdate;
+       int uid;
+       char plrole[ROLESZ+1];
+       char plrace[ROLESZ+1];
+       char plgend[ROLESZ+1];
+       char plalign[ROLESZ+1];
+       char name[NAMSZ+1];
+       char death[DTHSZ+1];
+} *tt_head;
+
+STATIC_DCL void FDECL(topten_print, (const char *));
+STATIC_DCL void FDECL(topten_print_bold, (const char *));
+STATIC_DCL xchar FDECL(observable_depth, (d_level *));
+STATIC_DCL void NDECL(outheader);
+STATIC_DCL void FDECL(outentry, (int,struct toptenentry *,BOOLEAN_P));
+STATIC_DCL void FDECL(readentry, (FILE *,struct toptenentry *));
+STATIC_DCL void FDECL(writeentry, (FILE *,struct toptenentry *));
+STATIC_DCL void FDECL(free_ttlist, (struct toptenentry *));
+STATIC_DCL int FDECL(classmon, (char *,BOOLEAN_P));
+STATIC_DCL int FDECL(score_wanted,
+               (BOOLEAN_P, int,struct toptenentry *,int,const char **,int));
+#ifdef NO_SCAN_BRACK
+STATIC_DCL void FDECL(nsb_mung_line,(char*));
+STATIC_DCL void FDECL(nsb_unmung_line,(char*));
+#endif
+
+/* must fit with end.c; used in rip.c */
+NEARDATA const char * const killed_by_prefix[] = {
+       "killed by ", "choked on ", "poisoned by ", "died of ", "drowned in ",
+       "burned by ", "dissolved in ", "crushed to death by ", "petrified by ",
+       "turned to slime by ", "killed by ", "", "", "", "", ""
+};
+
+static winid toptenwin = WIN_ERR;
+
+STATIC_OVL void
+topten_print(x)
+const char *x;
+{
+       if (toptenwin == WIN_ERR)
+           raw_print(x);
+       else
+           putstr(toptenwin, ATR_NONE, x);
+}
+
+STATIC_OVL void
+topten_print_bold(x)
+const char *x;
+{
+       if (toptenwin == WIN_ERR)
+           raw_print_bold(x);
+       else
+           putstr(toptenwin, ATR_BOLD, x);
+}
+
+STATIC_OVL xchar
+observable_depth(lev)
+d_level *lev;
+{
+#if 0  /* if we ever randomize the order of the elemental planes, we
+          must use a constant external representation in the record file */
+       if (In_endgame(lev)) {
+           if (Is_astralevel(lev))      return -5;
+           else if (Is_waterlevel(lev)) return -4;
+           else if (Is_firelevel(lev))  return -3;
+           else if (Is_airlevel(lev))   return -2;
+           else if (Is_earthlevel(lev)) return -1;
+           else                         return 0;      /* ? */
+       } else
+#endif
+           return depth(lev);
+}
+
+STATIC_OVL void
+readentry(rfile,tt)
+FILE *rfile;
+struct toptenentry *tt;
+{
+#ifdef NO_SCAN_BRACK /* Version_ Pts DgnLevs_ Hp___ Died__Born id */
+       static const char fmt[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d%*c";
+       static const char fmt32[] = "%c%c %s %s%*c";
+       static const char fmt33[] = "%s %s %s %s %s %s%*c";
+#else
+       static const char fmt[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ";
+       static const char fmt32[] = "%c%c %[^,],%[^\n]%*c";
+       static const char fmt33[] = "%s %s %s %s %[^,],%[^\n]%*c";
+#endif
+
+#ifdef UPDATE_RECORD_IN_PLACE
+       /* note: fscanf() below must read the record's terminating newline */
+       final_fpos = tt->fpos = ftell(rfile);
+#endif
+#define TTFIELDS 13
+       if(fscanf(rfile, fmt,
+                       &tt->ver_major, &tt->ver_minor, &tt->patchlevel,
+                       &tt->points, &tt->deathdnum, &tt->deathlev,
+                       &tt->maxlvl, &tt->hp, &tt->maxhp, &tt->deaths,
+                       &tt->deathdate, &tt->birthdate,
+                       &tt->uid) != TTFIELDS)
+#undef TTFIELDS
+               tt->points = 0;
+       else {
+               /* Check for backwards compatibility */
+               if (tt->ver_major < 3 ||
+                               (tt->ver_major == 3 && tt->ver_minor < 3)) {
+                       int i;
+
+                   if (fscanf(rfile, fmt32,
+                               tt->plrole, tt->plgend,
+                               tt->name, tt->death) != 4)
+                       tt->points = 0;
+                   tt->plrole[1] = '\0';
+                   if ((i = str2role(tt->plrole)) >= 0)
+                       Strcpy(tt->plrole, roles[i].filecode);
+                   Strcpy(tt->plrace, "?");
+                   Strcpy(tt->plgend, (tt->plgend[0] == 'M') ? "Mal" : "Fem");
+                   Strcpy(tt->plalign, "?");
+               } else if (fscanf(rfile, fmt33,
+                               tt->plrole, tt->plrace, tt->plgend,
+                               tt->plalign, tt->name, tt->death) != 6)
+                       tt->points = 0;
+#ifdef NO_SCAN_BRACK
+               if(tt->points > 0) {
+                       nsb_unmung_line(tt->name);
+                       nsb_unmung_line(tt->death);
+               }
+#endif
+       }
+
+       /* check old score entries for Y2K problem and fix whenever found */
+       if (tt->points > 0) {
+               if (tt->birthdate < 19000000L) tt->birthdate += 19000000L;
+               if (tt->deathdate < 19000000L) tt->deathdate += 19000000L;
+       }
+}
+
+STATIC_OVL void
+writeentry(rfile,tt)
+FILE *rfile;
+struct toptenentry *tt;
+{
+#ifdef NO_SCAN_BRACK
+       nsb_mung_line(tt->name);
+       nsb_mung_line(tt->death);
+                          /* Version_ Pts DgnLevs_ Hp___ Died__Born id */
+       (void) fprintf(rfile,"%d %d %d %ld %d %d %d %d %d %d %ld %ld %d ",
+#else
+       (void) fprintf(rfile,"%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ",
+#endif
+               tt->ver_major, tt->ver_minor, tt->patchlevel,
+               tt->points, tt->deathdnum, tt->deathlev,
+               tt->maxlvl, tt->hp, tt->maxhp, tt->deaths,
+               tt->deathdate, tt->birthdate, tt->uid);
+       if (tt->ver_major < 3 ||
+                       (tt->ver_major == 3 && tt->ver_minor < 3))
+#ifdef NO_SCAN_BRACK
+               (void) fprintf(rfile,"%c%c %s %s\n",
+#else
+               (void) fprintf(rfile,"%c%c %s,%s\n",
+#endif
+                       tt->plrole[0], tt->plgend[0],
+                       onlyspace(tt->name) ? "_" : tt->name, tt->death);
+       else
+#ifdef NO_SCAN_BRACK
+               (void) fprintf(rfile,"%s %s %s %s %s %s\n",
+#else
+               (void) fprintf(rfile,"%s %s %s %s %s,%s\n",
+#endif
+                       tt->plrole, tt->plrace, tt->plgend, tt->plalign,
+                       onlyspace(tt->name) ? "_" : tt->name, tt->death);
+
+#ifdef NO_SCAN_BRACK
+       nsb_unmung_line(tt->name);
+       nsb_unmung_line(tt->death);
+#endif
+}
+
+STATIC_OVL void
+free_ttlist(tt)
+struct toptenentry *tt;
+{
+       struct toptenentry *ttnext;
+
+       while (tt->points > 0) {
+               ttnext = tt->tt_next;
+               dealloc_ttentry(tt);
+               tt = ttnext;
+       }
+       dealloc_ttentry(tt);
+}
+
+void
+topten(how)
+int how;
+{
+       int uid = getuid();
+       int rank, rank0 = -1, rank1 = 0;
+       int occ_cnt = PERSMAX;
+       register struct toptenentry *t0, *tprev;
+       struct toptenentry *t1;
+       FILE *rfile;
+       register int flg = 0;
+       boolean t0_used;
+#ifdef LOGFILE
+       FILE *lfile;
+#endif /* LOGFILE */
+
+/* Under DICE 3.0, this crashes the system consistently, apparently due to
+ * corruption of *rfile somewhere.  Until I figure this out, just cut out
+ * topten support entirely - at least then the game exits cleanly.  --AC
+ */
+#ifdef _DCC
+       return;
+#endif
+
+/* If we are in the midst of a panic, cut out topten entirely.
+ * topten uses alloc() several times, which will lead to
+ * problems if the panic was the result of an alloc() failure.
+ */
+       if (program_state.panicking)
+               return;
+
+       if (flags.toptenwin) {
+           toptenwin = create_nhwindow(NHW_TEXT);
+       }
+
+#if defined(UNIX) || defined(VMS) || defined(__EMX__)
+#define HUP    if (!program_state.done_hup)
+#else
+#define HUP
+#endif
+
+#ifdef TOS
+       restore_colors();       /* make sure the screen is black on white */
+#endif
+       /* create a new 'topten' entry */
+       t0_used = FALSE;
+       t0 = newttentry();
+       /* deepest_lev_reached() is in terms of depth(), and reporting the
+        * deepest level reached in the dungeon death occurred in doesn't
+        * seem right, so we have to report the death level in depth() terms
+        * as well (which also seems reasonable since that's all the player
+        * sees on the screen anyway)
+        */
+       t0->ver_major = VERSION_MAJOR;
+       t0->ver_minor = VERSION_MINOR;
+       t0->patchlevel = PATCHLEVEL;
+       t0->points = u.urexp;
+       t0->deathdnum = u.uz.dnum;
+       t0->deathlev = observable_depth(&u.uz);
+       t0->maxlvl = deepest_lev_reached(TRUE);
+       t0->hp = u.uhp;
+       t0->maxhp = u.uhpmax;
+       t0->deaths = u.umortality;
+       t0->uid = uid;
+       (void) strncpy(t0->plrole, urole.filecode, ROLESZ);
+       t0->plrole[ROLESZ] = '\0';
+       (void) strncpy(t0->plrace, urace.filecode, ROLESZ);
+       t0->plrace[ROLESZ] = '\0';
+       (void) strncpy(t0->plgend, genders[flags.female].filecode, ROLESZ);
+       t0->plgend[ROLESZ] = '\0';
+       (void) strncpy(t0->plalign, aligns[1-u.ualign.type].filecode, ROLESZ);
+       t0->plalign[ROLESZ] = '\0';
+       (void) strncpy(t0->name, plname, NAMSZ);
+       t0->name[NAMSZ] = '\0';
+       t0->death[0] = '\0';
+       switch (killer_format) {
+               default: impossible("bad killer format?");
+               case KILLED_BY_AN:
+                       Strcat(t0->death, killed_by_prefix[how]);
+                       (void) strncat(t0->death, an(killer),
+                                               DTHSZ-strlen(t0->death));
+                       break;
+               case KILLED_BY:
+                       Strcat(t0->death, killed_by_prefix[how]);
+                       (void) strncat(t0->death, killer,
+                                               DTHSZ-strlen(t0->death));
+                       break;
+               case NO_KILLER_PREFIX:
+                       (void) strncat(t0->death, killer, DTHSZ);
+                       break;
+       }
+       t0->birthdate = yyyymmdd(u.ubirthday);
+       t0->deathdate = yyyymmdd((time_t)0L);
+       t0->tt_next = 0;
+#ifdef UPDATE_RECORD_IN_PLACE
+       t0->fpos = -1L;
+#endif
+
+#ifdef LOGFILE         /* used for debugging (who dies of what, where) */
+       if (lock_file(LOGFILE, SCOREPREFIX, 10)) {
+           if(!(lfile = fopen_datafile(LOGFILE, "a", SCOREPREFIX))) {
+               HUP raw_print("Cannot open log file!");
+           } else {
+               writeentry(lfile, t0);
+               (void) fclose(lfile);
+           }
+           unlock_file(LOGFILE);
+       }
+#endif /* LOGFILE */
+
+       if (wizard || discover) {
+           if (how != PANICKED) HUP {
+               char pbuf[BUFSZ];
+               topten_print("");
+               Sprintf(pbuf,
+             "Since you were in %s mode, the score list will not be checked.",
+                   wizard ? "wizard" : "discover");
+               topten_print(pbuf);
+           }
+           goto showwin;
+       }
+
+       if (!lock_file(RECORD, SCOREPREFIX, 60))
+               goto destroywin;
+
+#ifdef UPDATE_RECORD_IN_PLACE
+       rfile = fopen_datafile(RECORD, "r+", SCOREPREFIX);
+#else
+       rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
+#endif
+
+       if (!rfile) {
+               HUP raw_print("Cannot open record file!");
+               unlock_file(RECORD);
+               goto destroywin;
+       }
+
+       HUP topten_print("");
+
+       /* assure minimum number of points */
+       if(t0->points < POINTSMIN) t0->points = 0;
+
+       t1 = tt_head = newttentry();
+       tprev = 0;
+       /* rank0: -1 undefined, 0 not_on_list, n n_th on list */
+       for(rank = 1; ; ) {
+           readentry(rfile, t1);
+           if (t1->points < POINTSMIN) t1->points = 0;
+           if(rank0 < 0 && t1->points < t0->points) {
+               rank0 = rank++;
+               if(tprev == 0)
+                       tt_head = t0;
+               else
+                       tprev->tt_next = t0;
+               t0->tt_next = t1;
+#ifdef UPDATE_RECORD_IN_PLACE
+               t0->fpos = t1->fpos;    /* insert here */
+#endif
+               t0_used = TRUE;
+               occ_cnt--;
+               flg++;          /* ask for a rewrite */
+           } else tprev = t1;
+
+           if(t1->points == 0) break;
+           if(
+#ifdef PERS_IS_UID
+               t1->uid == t0->uid &&
+#else
+               strncmp(t1->name, t0->name, NAMSZ) == 0 &&
+#endif
+               !strncmp(t1->plrole, t0->plrole, ROLESZ) &&
+               --occ_cnt <= 0) {
+                   if(rank0 < 0) {
+                       rank0 = 0;
+                       rank1 = rank;
+                       HUP {
+                           char pbuf[BUFSZ];
+                           Sprintf(pbuf,
+                         "You didn't beat your previous score of %ld points.",
+                                   t1->points);
+                           topten_print(pbuf);
+                           topten_print("");
+                       }
+                   }
+                   if(occ_cnt < 0) {
+                       flg++;
+                       continue;
+                   }
+               }
+           if(rank <= ENTRYMAX) {
+               t1->tt_next = newttentry();
+               t1 = t1->tt_next;
+               rank++;
+           }
+           if(rank > ENTRYMAX) {
+               t1->points = 0;
+               break;
+           }
+       }
+       if(flg) {       /* rewrite record file */
+#ifdef UPDATE_RECORD_IN_PLACE
+               (void) fseek(rfile, (t0->fpos >= 0 ?
+                                    t0->fpos : final_fpos), SEEK_SET);
+#else
+               (void) fclose(rfile);
+               if(!(rfile = fopen_datafile(RECORD, "w", SCOREPREFIX))){
+                       HUP raw_print("Cannot write record file");
+                       unlock_file(RECORD);
+                       free_ttlist(tt_head);
+                       goto destroywin;
+               }
+#endif /* UPDATE_RECORD_IN_PLACE */
+               if(!done_stopprint) if(rank0 > 0){
+                   if(rank0 <= 10)
+                       topten_print("You made the top ten list!");
+                   else {
+                       char pbuf[BUFSZ];
+                       Sprintf(pbuf,
+                         "You reached the %d%s place on the top %d list.",
+                               rank0, ordin(rank0), ENTRYMAX);
+                       topten_print(pbuf);
+                   }
+                   topten_print("");
+               }
+       }
+       if(rank0 == 0) rank0 = rank1;
+       if(rank0 <= 0) rank0 = rank;
+       if(!done_stopprint) outheader();
+       t1 = tt_head;
+       for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
+           if(flg
+#ifdef UPDATE_RECORD_IN_PLACE
+                   && rank >= rank0
+#endif
+               ) writeentry(rfile, t1);
+           if (done_stopprint) continue;
+           if (rank > flags.end_top &&
+                   (rank < rank0 - flags.end_around ||
+                    rank > rank0 + flags.end_around) &&
+                   (!flags.end_own ||
+#ifdef PERS_IS_UID
+                                       t1->uid != t0->uid
+#else
+                                       strncmp(t1->name, t0->name, NAMSZ)
+#endif
+               )) continue;
+           if (rank == rank0 - flags.end_around &&
+                   rank0 > flags.end_top + flags.end_around + 1 &&
+                   !flags.end_own)
+               topten_print("");
+           if(rank != rank0)
+               outentry(rank, t1, FALSE);
+           else if(!rank1)
+               outentry(rank, t1, TRUE);
+           else {
+               outentry(rank, t1, TRUE);
+               outentry(0, t0, TRUE);
+           }
+       }
+       if(rank0 >= rank) if(!done_stopprint)
+               outentry(0, t0, TRUE);
+#ifdef UPDATE_RECORD_IN_PLACE
+       if (flg) {
+# ifdef TRUNCATE_FILE
+           /* if a reasonable way to truncate a file exists, use it */
+           truncate_file(rfile);
+# else
+           /* use sentinel record rather than relying on truncation */
+           t1->points = 0L;    /* terminates file when read back in */
+           t1->ver_major = t1->ver_minor = t1->patchlevel = 0;
+           t1->uid = t1->deathdnum = t1->deathlev = 0;
+           t1->maxlvl = t1->hp = t1->maxhp = t1->deaths = 0;
+           t1->plrole[0] = t1->plrace[0] = t1->plgend[0] = t1->plalign[0] = '-';
+           t1->plrole[1] = t1->plrace[1] = t1->plgend[1] = t1->plalign[1] = 0;
+           t1->birthdate = t1->deathdate = yyyymmdd((time_t)0L);
+           Strcpy(t1->name, "@");
+           Strcpy(t1->death, "<eod>\n");
+           writeentry(rfile, t1);
+           (void) fflush(rfile);
+# endif        /* TRUNCATE_FILE */
+       }
+#endif /* UPDATE_RECORD_IN_PLACE */
+       (void) fclose(rfile);
+       unlock_file(RECORD);
+       free_ttlist(tt_head);
+
+  showwin:
+       if (flags.toptenwin && !done_stopprint) display_nhwindow(toptenwin, 1);
+  destroywin:
+       if (!t0_used) dealloc_ttentry(t0);
+       if (flags.toptenwin) {
+           destroy_nhwindow(toptenwin);
+           toptenwin=WIN_ERR;
+       }
+}
+
+STATIC_OVL void
+outheader()
+{
+       char linebuf[BUFSZ];
+       register char *bp;
+
+       Strcpy(linebuf, " No  Points     Name");
+       bp = eos(linebuf);
+       while(bp < linebuf + COLNO - 9) *bp++ = ' ';
+       Strcpy(bp, "Hp [max]");
+       topten_print(linebuf);
+}
+
+/* so>0: standout line; so=0: ordinary line */
+STATIC_OVL void
+outentry(rank, t1, so)
+struct toptenentry *t1;
+int rank;
+boolean so;
+{
+       boolean second_line = TRUE;
+       char linebuf[BUFSZ];
+       char *bp, hpbuf[24], linebuf3[BUFSZ];
+       int hppos, lngr;
+
+
+       linebuf[0] = '\0';
+       if (rank) Sprintf(eos(linebuf), "%3d", rank);
+       else Strcat(linebuf, "   ");
+
+       Sprintf(eos(linebuf), " %10ld  %.10s", t1->points, t1->name);
+       Sprintf(eos(linebuf), "-%s", t1->plrole);
+       if (t1->plrace[0] != '?')
+               Sprintf(eos(linebuf), "-%s", t1->plrace);
+       /* Printing of gender and alignment is intentional.  It has been
+        * part of the NetHack Geek Code, and illustrates a proper way to
+        * specify a character from the command line.
+        */
+       Sprintf(eos(linebuf), "-%s", t1->plgend);
+       if (t1->plalign[0] != '?')
+               Sprintf(eos(linebuf), "-%s ", t1->plalign);
+       else
+               Strcat(linebuf, " ");
+       if (!strncmp("escaped", t1->death, 7)) {
+           Sprintf(eos(linebuf), "escaped the dungeon %s[max level %d]",
+                   !strncmp(" (", t1->death + 7, 2) ? t1->death + 7 + 2 : "",
+                   t1->maxlvl);
+           /* fixup for closing paren in "escaped... with...Amulet)[max..." */
+           if ((bp = index(linebuf, ')')) != 0)
+               *bp = (t1->deathdnum == astral_level.dnum) ? '\0' : ' ';
+           second_line = FALSE;
+       } else if (!strncmp("ascended", t1->death, 8)) {
+           Sprintf(eos(linebuf), "ascended to demigod%s-hood",
+                   (t1->plgend[0] == 'F') ? "dess" : "");
+           second_line = FALSE;
+       } else {
+           if (!strncmp(t1->death, "quit", 4)) {
+               Strcat(linebuf, "quit");
+               second_line = FALSE;
+           } else if (!strncmp(t1->death, "died of st", 10)) {
+               Strcat(linebuf, "starved to death");
+               second_line = FALSE;
+           } else if (!strncmp(t1->death, "choked", 6)) {
+               Sprintf(eos(linebuf), "choked on h%s food",
+                       (t1->plgend[0] == 'F') ? "er" : "is");
+           } else if (!strncmp(t1->death, "poisoned", 8)) {
+               Strcat(linebuf, "was poisoned");
+           } else if (!strncmp(t1->death, "crushed", 7)) {
+               Strcat(linebuf, "was crushed to death");
+           } else if (!strncmp(t1->death, "petrified by ", 13)) {
+               Strcat(linebuf, "turned to stone");
+           } else Strcat(linebuf, "died");
+
+           if (t1->deathdnum == astral_level.dnum) {
+               const char *arg, *fmt = " on the Plane of %s";
+
+               switch (t1->deathlev) {
+               case -5:
+                       fmt = " on the %s Plane";
+                       arg = "Astral"; break;
+               case -4:
+                       arg = "Water";  break;
+               case -3:
+                       arg = "Fire";   break;
+               case -2:
+                       arg = "Air";    break;
+               case -1:
+                       arg = "Earth";  break;
+               default:
+                       arg = "Void";   break;
+               }
+               Sprintf(eos(linebuf), fmt, arg);
+           } else {
+               Sprintf(eos(linebuf), " in %s", dungeons[t1->deathdnum].dname);
+               if (t1->deathdnum != knox_level.dnum)
+                   Sprintf(eos(linebuf), " on level %d", t1->deathlev);
+               if (t1->deathlev != t1->maxlvl)
+                   Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);
+           }
+
+           /* kludge for "quit while already on Charon's boat" */
+           if (!strncmp(t1->death, "quit ", 5))
+               Strcat(linebuf, t1->death + 4);
+       }
+       Strcat(linebuf, ".");
+
+       /* Quit, starved, ascended, and escaped contain no second line */
+       if (second_line)
+           Sprintf(eos(linebuf), "  %c%s.", highc(*(t1->death)), t1->death+1);
+
+       lngr = (int)strlen(linebuf);
+       if (t1->hp <= 0) hpbuf[0] = '-', hpbuf[1] = '\0';
+       else Sprintf(hpbuf, "%d", t1->hp);
+       /* beginning of hp column after padding (not actually padded yet) */
+       hppos = COLNO - (sizeof("  Hp [max]")-1); /* sizeof(str) includes \0 */
+       while (lngr >= hppos) {
+           for(bp = eos(linebuf);
+                   !(*bp == ' ' && (bp-linebuf < hppos));
+                   bp--)
+               ;
+           /* special case: if about to wrap in the middle of maximum
+              dungeon depth reached, wrap in front of it instead */
+           if (bp > linebuf + 5 && !strncmp(bp - 5, " [max", 5)) bp -= 5;
+           Strcpy(linebuf3, bp+1);
+           *bp = 0;
+           if (so) {
+               while (bp < linebuf + (COLNO-1)) *bp++ = ' ';
+               *bp = 0;
+               topten_print_bold(linebuf);
+           } else
+               topten_print(linebuf);
+           Sprintf(linebuf, "%15s %s", "", linebuf3);
+           lngr = strlen(linebuf);
+       }
+       /* beginning of hp column not including padding */
+       hppos = COLNO - 7 - (int)strlen(hpbuf);
+       bp = eos(linebuf);
+
+       if (bp <= linebuf + hppos) {
+           /* pad any necessary blanks to the hit point entry */
+           while (bp < linebuf + hppos) *bp++ = ' ';
+           Strcpy(bp, hpbuf);
+           Sprintf(eos(bp), " %s[%d]",
+                   (t1->maxhp < 10) ? "  " : (t1->maxhp < 100) ? " " : "",
+                   t1->maxhp);
+       }
+
+       if (so) {
+           bp = eos(linebuf);
+           if (so >= COLNO) so = COLNO-1;
+           while (bp < linebuf + so) *bp++ = ' ';
+           *bp = 0;
+           topten_print_bold(linebuf);
+       } else
+           topten_print(linebuf);
+}
+
+STATIC_OVL int
+score_wanted(current_ver, rank, t1, playerct, players, uid)
+boolean current_ver;
+int rank;
+struct toptenentry *t1;
+int playerct;
+const char **players;
+int uid;
+{
+       int i;
+
+       if (current_ver && (t1->ver_major != VERSION_MAJOR ||
+                           t1->ver_minor != VERSION_MINOR ||
+                           t1->patchlevel != PATCHLEVEL))
+               return 0;
+
+#ifdef PERS_IS_UID
+       if (!playerct && t1->uid == uid)
+               return 1;
+#endif
+
+       for (i = 0; i < playerct; i++) {
+           if (players[i][0] == '-' && index("pr", players[i][1]) &&
+                players[i][2] == 0 && i + 1 < playerct) {
+               char *arg = (char *)players[i + 1];
+               if ((players[i][1] == 'p' &&
+                    str2role(arg) == str2role(t1->plrole)) ||
+                   (players[i][1] == 'r' &&
+                    str2race(arg) == str2race(t1->plrace)))
+                   return 1;
+               i++;
+           } else if (strcmp(players[i], "all") == 0 ||
+                   strncmp(t1->name, players[i], NAMSZ) == 0 ||
+                   (players[i][0] == '-' &&
+                    players[i][1] == t1->plrole[0] &&
+                    players[i][2] == 0) ||
+                   (digit(players[i][0]) && rank <= atoi(players[i])))
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * print selected parts of score list.
+ * argc >= 2, with argv[0] untrustworthy (directory names, et al.),
+ * and argv[1] starting with "-s".
+ */
+void
+prscore(argc,argv)
+int argc;
+char **argv;
+{
+       const char **players;
+       int playerct, rank;
+       boolean current_ver = TRUE, init_done = FALSE;
+       register struct toptenentry *t1;
+       FILE *rfile;
+       boolean match_found = FALSE;
+       register int i;
+       char pbuf[BUFSZ];
+       int uid = -1;
+#ifndef PERS_IS_UID
+       const char *player0;
+#endif
+
+       if (argc < 2 || strncmp(argv[1], "-s", 2)) {
+               raw_printf("prscore: bad arguments (%d)", argc);
+               return;
+       }
+
+       rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
+       if (!rfile) {
+               raw_print("Cannot open record file!");
+               return;
+       }
+
+#ifdef AMIGA
+       {
+           extern winid amii_rawprwin;
+           init_nhwindows(&argc, argv);
+           amii_rawprwin = create_nhwindow(NHW_TEXT);
+       }
+#endif
+
+       /* If the score list isn't after a game, we never went through
+        * initialization. */
+       if (wiz1_level.dlevel == 0) {
+               dlb_init();
+               init_dungeons();
+               init_done = TRUE;
+       }
+
+       if (!argv[1][2]){       /* plain "-s" */
+               argc--;
+               argv++;
+       } else  argv[1] += 2;
+
+       if (argc > 1 && !strcmp(argv[1], "-v")) {
+               current_ver = FALSE;
+               argc--;
+               argv++;
+       }
+
+       if (argc <= 1) {
+#ifdef PERS_IS_UID
+               uid = getuid();
+               playerct = 0;
+               players = (const char **)0;
+#else
+               player0 = plname;
+               if (!*player0)
+# ifdef AMIGA
+                       player0 = "all";        /* single user system */
+# else
+                       player0 = "hackplayer";
+# endif
+               playerct = 1;
+               players = &player0;
+#endif
+       } else {
+               playerct = --argc;
+               players = (const char **)++argv;
+       }
+       raw_print("");
+
+       t1 = tt_head = newttentry();
+       for (rank = 1; ; rank++) {
+           readentry(rfile, t1);
+           if (t1->points == 0) break;
+           if (!match_found &&
+                   score_wanted(current_ver, rank, t1, playerct, players, uid))
+               match_found = TRUE;
+           t1->tt_next = newttentry();
+           t1 = t1->tt_next;
+       }
+
+       (void) fclose(rfile);
+       if (init_done) {
+           free_dungeons();
+           dlb_cleanup();
+       }
+
+       if (match_found) {
+           outheader();
+           t1 = tt_head;
+           for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
+               if (score_wanted(current_ver, rank, t1, playerct, players, uid))
+                   (void) outentry(rank, t1, 0);
+           }
+       } else {
+           Sprintf(pbuf, "Cannot find any %sentries for ",
+                               current_ver ? "current " : "");
+           if (playerct < 1) Strcat(pbuf, "you.");
+           else {
+               if (playerct > 1) Strcat(pbuf, "any of ");
+               for (i = 0; i < playerct; i++) {
+                   /* stop printing players if there are too many to fit */
+                   if (strlen(pbuf) + strlen(players[i]) + 2 >= BUFSZ) {
+                       if (strlen(pbuf) < BUFSZ-4) Strcat(pbuf, "...");
+                       else Strcpy(pbuf+strlen(pbuf)-4, "...");
+                       break;
+                   }
+                   Strcat(pbuf, players[i]);
+                   if (i < playerct-1) {
+                       if (players[i][0] == '-' &&
+                           index("pr", players[i][1]) && players[i][2] == 0)
+                           Strcat(pbuf, " ");
+                       else Strcat(pbuf, ":");
+                   }
+               }
+           }
+           raw_print(pbuf);
+           raw_printf("Usage: %s -s [-v] <playertypes> [maxrank] [playernames]",
+
+                        hname);
+           raw_printf("Player types are: [-p role] [-r race]");
+       }
+       free_ttlist(tt_head);
+#ifdef AMIGA
+       {
+           extern winid amii_rawprwin;
+           display_nhwindow(amii_rawprwin, 1);
+           destroy_nhwindow(amii_rawprwin);
+           amii_rawprwin = WIN_ERR;
+       }
+#endif
+}
+
+STATIC_OVL int
+classmon(plch, fem)
+       char *plch;
+       boolean fem;
+{
+       int i;
+
+       /* Look for this role in the role table */
+       for (i = 0; roles[i].name.m; i++)
+           if (!strncmp(plch, roles[i].filecode, ROLESZ)) {
+               if (fem && roles[i].femalenum != NON_PM)
+                   return roles[i].femalenum;
+               else if (roles[i].malenum != NON_PM)
+                   return roles[i].malenum;
+               else
+                   return PM_HUMAN;
+           }
+       /* this might be from a 3.2.x score for former Elf class */
+       if (!strcmp(plch, "E")) return PM_RANGER;
+
+       impossible("What weird role is this? (%s)", plch);
+       return (PM_HUMAN_MUMMY);
+}
+
+/*
+ * Get a random player name and class from the high score list,
+ * and attach them to an object (for statues or morgue corpses).
+ */
+struct obj *
+tt_oname(otmp)
+struct obj *otmp;
+{
+       int rank;
+       register int i;
+       register struct toptenentry *tt;
+       FILE *rfile;
+       struct toptenentry tt_buf;
+
+       if (!otmp) return((struct obj *) 0);
+
+       rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
+       if (!rfile) {
+               impossible("Cannot open record file!");
+               return (struct obj *)0;
+       }
+
+       tt = &tt_buf;
+       rank = rnd(10);
+pickentry:
+       for(i = rank; i; i--) {
+           readentry(rfile, tt);
+           if(tt->points == 0) break;
+       }
+
+       if(tt->points == 0) {
+               if(rank > 1) {
+                       rank = 1;
+                       rewind(rfile);
+                       goto pickentry;
+               }
+               otmp = (struct obj *) 0;
+       } else {
+               /* reset timer in case corpse started out as lizard or troll */
+               if (otmp->otyp == CORPSE) obj_stop_timers(otmp);
+               otmp->corpsenm = classmon(tt->plrole, (tt->plgend[0] == 'F'));
+               otmp->owt = weight(otmp);
+               otmp = oname(otmp, tt->name);
+               if (otmp->otyp == CORPSE) start_corpse_timeout(otmp);
+       }
+
+       (void) fclose(rfile);
+       return otmp;
+}
+
+#ifdef NO_SCAN_BRACK
+/* Lattice scanf isn't up to reading the scorefile.  What */
+/* follows deals with that; I admit it's ugly. (KL) */
+/* Now generally available (KL) */
+STATIC_OVL void
+nsb_mung_line(p)
+       char *p;
+{
+       while ((p = index(p, ' ')) != 0) *p = '|';
+}
+
+STATIC_OVL void
+nsb_unmung_line(p)
+       char *p;
+{
+       while ((p = index(p, '|')) != 0) *p = ' ';
+}
+#endif /* NO_SCAN_BRACK */
+
+/*topten.c*/
diff --git a/src/track.c b/src/track.c
new file mode 100644 (file)
index 0000000..d8d9e71
--- /dev/null
@@ -0,0 +1,68 @@
+/*     SCCS Id: @(#)track.c    3.4     87/08/08        */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+/* track.c - version 1.0.2 */
+
+#include "hack.h"
+
+#define UTSZ   50
+
+STATIC_VAR NEARDATA int utcnt, utpnt;
+STATIC_VAR NEARDATA coord utrack[UTSZ];
+
+#ifdef OVLB
+
+void
+initrack()
+{
+       utcnt = utpnt = 0;
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+/* add to track */
+void
+settrack()
+{
+       if(utcnt < UTSZ) utcnt++;
+       if(utpnt == UTSZ) utpnt = 0;
+       utrack[utpnt].x = u.ux;
+       utrack[utpnt].y = u.uy;
+       utpnt++;
+}
+
+#endif /* OVL1 */
+#ifdef OVL0
+
+coord *
+gettrack(x, y)
+register int x, y;
+{
+    register int cnt, ndist;
+    register coord *tc;
+    cnt = utcnt;
+    for(tc = &utrack[utpnt]; cnt--; ){
+       if(tc == utrack) tc = &utrack[UTSZ-1];
+       else tc--;
+       ndist = distmin(x,y,tc->x,tc->y);
+
+       /* if far away, skip track entries til we're closer */
+       if(ndist > 2) {
+           ndist -= 2; /* be careful due to extra decrement at top of loop */
+           cnt -= ndist;
+           if(cnt <= 0)
+               return (coord *) 0; /* too far away, no matches possible */
+           if(tc < &utrack[ndist])
+               tc += (UTSZ-ndist);
+           else
+               tc -= ndist;
+       } else if(ndist <= 1)
+           return(ndist ? tc : 0);
+    }
+    return (coord *)0;
+}
+
+#endif /* OVL0 */
+
+/*track.c*/
diff --git a/src/trap.c b/src/trap.c
new file mode 100644 (file)
index 0000000..d336276
--- /dev/null
@@ -0,0 +1,4015 @@
+/*     SCCS Id: @(#)trap.c     3.4     2003/10/20      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+extern const char * const destroy_strings[];   /* from zap.c */
+
+STATIC_DCL void FDECL(dofiretrap, (struct obj *));
+STATIC_DCL void NDECL(domagictrap);
+STATIC_DCL boolean FDECL(emergency_disrobe,(boolean *));
+STATIC_DCL int FDECL(untrap_prob, (struct trap *ttmp));
+STATIC_DCL void FDECL(cnv_trap_obj, (int, int, struct trap *));
+STATIC_DCL void FDECL(move_into_trap, (struct trap *));
+STATIC_DCL int FDECL(try_disarm, (struct trap *,BOOLEAN_P));
+STATIC_DCL void FDECL(reward_untrap, (struct trap *, struct monst *));
+STATIC_DCL int FDECL(disarm_holdingtrap, (struct trap *));
+STATIC_DCL int FDECL(disarm_landmine, (struct trap *));
+STATIC_DCL int FDECL(disarm_squeaky_board, (struct trap *));
+STATIC_DCL int FDECL(disarm_shooting_trap, (struct trap *, int));
+STATIC_DCL int FDECL(try_lift, (struct monst *, struct trap *, int, BOOLEAN_P));
+STATIC_DCL int FDECL(help_monster_out, (struct monst *, struct trap *));
+STATIC_DCL boolean FDECL(thitm, (int,struct monst *,struct obj *,int,BOOLEAN_P));
+STATIC_DCL int FDECL(mkroll_launch,
+                       (struct trap *,XCHAR_P,XCHAR_P,SHORT_P,long));
+STATIC_DCL boolean FDECL(isclearpath,(coord *, int, SCHAR_P, SCHAR_P));
+#ifdef STEED
+STATIC_OVL int FDECL(steedintrap, (struct trap *, struct obj *));
+STATIC_OVL boolean FDECL(keep_saddle_with_steedcorpse,
+                       (unsigned, struct obj *, struct obj *));
+#endif
+
+#ifndef OVLB
+STATIC_VAR const char *a_your[2];
+STATIC_VAR const char *A_Your[2];
+STATIC_VAR const char tower_of_flame[];
+STATIC_VAR const char *A_gush_of_water_hits;
+STATIC_VAR const char * const blindgas[6];
+
+#else
+
+STATIC_VAR const char * const a_your[2] = { "a", "your" };
+STATIC_VAR const char * const A_Your[2] = { "A", "Your" };
+STATIC_VAR const char tower_of_flame[] = "tower of flame";
+STATIC_VAR const char * const A_gush_of_water_hits = "A gush of water hits";
+STATIC_VAR const char * const blindgas[6] = 
+       {"humid", "odorless", "pungent", "chilling", "acrid", "biting"};
+
+#endif /* OVLB */
+
+#ifdef OVLB
+
+/* called when you're hit by fire (dofiretrap,buzz,zapyourself,explode) */
+boolean                        /* returns TRUE if hit on torso */
+burnarmor(victim)
+struct monst *victim;
+{
+    struct obj *item;
+    char buf[BUFSZ];
+    int mat_idx;
+    
+    if (!victim) return 0;
+#define burn_dmg(obj,descr) rust_dmg(obj, descr, 0, FALSE, victim)
+    while (1) {
+       switch (rn2(5)) {
+       case 0:
+           item = (victim == &youmonst) ? uarmh : which_armor(victim, W_ARMH);
+           if (item) {
+               mat_idx = objects[item->otyp].oc_material;
+               Sprintf(buf,"%s helmet", materialnm[mat_idx] );
+           }
+           if (!burn_dmg(item, item ? buf : "helmet")) continue;
+           break;
+       case 1:
+           item = (victim == &youmonst) ? uarmc : which_armor(victim, W_ARMC);
+           if (item) {
+               (void) burn_dmg(item, cloak_simple_name(item));
+               return TRUE;
+           }
+           item = (victim == &youmonst) ? uarm : which_armor(victim, W_ARM);
+           if (item) {
+               (void) burn_dmg(item, xname(item));
+               return TRUE;
+           }
+#ifdef TOURIST
+           item = (victim == &youmonst) ? uarmu : which_armor(victim, W_ARMU);
+           if (item)
+               (void) burn_dmg(item, "shirt");
+#endif
+           return TRUE;
+       case 2:
+           item = (victim == &youmonst) ? uarms : which_armor(victim, W_ARMS);
+           if (!burn_dmg(item, "wooden shield")) continue;
+           break;
+       case 3:
+           item = (victim == &youmonst) ? uarmg : which_armor(victim, W_ARMG);
+           if (!burn_dmg(item, "gloves")) continue;
+           break;
+       case 4:
+           item = (victim == &youmonst) ? uarmf : which_armor(victim, W_ARMF);
+           if (!burn_dmg(item, "boots")) continue;
+           break;
+       }
+       break; /* Out of while loop */
+    }
+    return FALSE;
+#undef burn_dmg
+}
+
+/* Generic rust-armor function.  Returns TRUE if a message was printed;
+ * "print", if set, means to print a message (and thus to return TRUE) even
+ * if the item could not be rusted; otherwise a message is printed and TRUE is
+ * returned only for rustable items.
+ */
+boolean
+rust_dmg(otmp, ostr, type, print, victim)
+register struct obj *otmp;
+register const char *ostr;
+int type;
+boolean print;
+struct monst *victim;
+{
+       static NEARDATA const char * const action[] = { "smoulder", "rust", "rot", "corrode" };
+       static NEARDATA const char * const msg[] =  { "burnt", "rusted", "rotten", "corroded" };
+       boolean vulnerable = FALSE;
+       boolean grprot = FALSE;
+       boolean is_primary = TRUE;
+       boolean vismon = (victim != &youmonst) && canseemon(victim);
+       int erosion;
+
+       if (!otmp) return(FALSE);
+       switch(type) {
+               case 0: vulnerable = is_flammable(otmp);
+                       break;
+               case 1: vulnerable = is_rustprone(otmp);
+                       grprot = TRUE;
+                       break;
+               case 2: vulnerable = is_rottable(otmp);
+                       is_primary = FALSE;
+                       break;
+               case 3: vulnerable = is_corrodeable(otmp);
+                       grprot = TRUE;
+                       is_primary = FALSE;
+                       break;
+       }
+       erosion = is_primary ? otmp->oeroded : otmp->oeroded2;
+
+       if (!print && (!vulnerable || otmp->oerodeproof || erosion == MAX_ERODE))
+               return FALSE;
+
+       if (!vulnerable) {
+           if (flags.verbose) {
+               if (victim == &youmonst)
+                   Your("%s %s not affected.", ostr, vtense(ostr, "are"));
+               else if (vismon)
+                   pline("%s's %s %s not affected.", Monnam(victim), ostr,
+                         vtense(ostr, "are"));
+           }
+       } else if (erosion < MAX_ERODE) {
+           if (grprot && otmp->greased) {
+               grease_protect(otmp,ostr,victim);
+           } else if (otmp->oerodeproof || (otmp->blessed && !rnl(4))) {
+               if (flags.verbose) {
+                   if (victim == &youmonst)
+                       pline("Somehow, your %s %s not affected.",
+                             ostr, vtense(ostr, "are"));
+                   else if (vismon)
+                       pline("Somehow, %s's %s %s not affected.",
+                             mon_nam(victim), ostr, vtense(ostr, "are"));
+               }
+           } else {
+               if (victim == &youmonst)
+                   Your("%s %s%s!", ostr,
+                        vtense(ostr, action[type]),
+                        erosion+1 == MAX_ERODE ? " completely" :
+                           erosion ? " further" : "");
+               else if (vismon)
+                   pline("%s's %s %s%s!", Monnam(victim), ostr,
+                       vtense(ostr, action[type]),
+                       erosion+1 == MAX_ERODE ? " completely" :
+                         erosion ? " further" : "");
+               if (is_primary)
+                   otmp->oeroded++;
+               else
+                   otmp->oeroded2++;
+               update_inventory();
+           }
+       } else {
+           if (flags.verbose) {
+               if (victim == &youmonst)
+                   Your("%s %s completely %s.", ostr,
+                        vtense(ostr, Blind ? "feel" : "look"),
+                        msg[type]);
+               else if (vismon)
+                   pline("%s's %s %s completely %s.",
+                         Monnam(victim), ostr,
+                         vtense(ostr, "look"), msg[type]);
+           }
+       }
+       return(TRUE);
+}
+
+void
+grease_protect(otmp,ostr,victim)
+register struct obj *otmp;
+register const char *ostr;
+struct monst *victim;
+{
+       static const char txt[] = "protected by the layer of grease!";
+       boolean vismon = victim && (victim != &youmonst) && canseemon(victim);
+
+       if (ostr) {
+           if (victim == &youmonst)
+               Your("%s %s %s", ostr, vtense(ostr, "are"), txt);
+           else if (vismon)
+               pline("%s's %s %s %s", Monnam(victim),
+                   ostr, vtense(ostr, "are"), txt);
+       } else {
+           if (victim == &youmonst)
+               Your("%s %s",aobjnam(otmp,"are"), txt);
+           else if (vismon)
+               pline("%s's %s %s", Monnam(victim), aobjnam(otmp,"are"), txt);
+       }
+       if (!rn2(2)) {
+           otmp->greased = 0;
+           if (carried(otmp)) {
+               pline_The("grease dissolves.");
+               update_inventory();
+           }
+       }
+}
+
+struct trap *
+maketrap(x,y,typ)
+register int x, y, typ;
+{
+       register struct trap *ttmp;
+       register struct rm *lev;
+       register boolean oldplace;
+
+       if ((ttmp = t_at(x,y)) != 0) {
+           if (ttmp->ttyp == MAGIC_PORTAL) return (struct trap *)0;
+           oldplace = TRUE;
+           if (u.utrap && (x == u.ux) && (y == u.uy) &&
+             ((u.utraptype == TT_BEARTRAP && typ != BEAR_TRAP) ||
+             (u.utraptype == TT_WEB && typ != WEB) ||
+             (u.utraptype == TT_PIT && typ != PIT && typ != SPIKED_PIT)))
+                   u.utrap = 0;
+       } else {
+           oldplace = FALSE;
+           ttmp = newtrap();
+           ttmp->tx = x;
+           ttmp->ty = y;
+           ttmp->launch.x = -1;        /* force error if used before set */
+           ttmp->launch.y = -1;
+       }
+       ttmp->ttyp = typ;
+       switch(typ) {
+           case STATUE_TRAP:       /* create a "living" statue */
+             { struct monst *mtmp;
+               struct obj *otmp, *statue;
+
+               statue = mkcorpstat(STATUE, (struct monst *)0,
+                                       &mons[rndmonnum()], x, y, FALSE);
+               mtmp = makemon(&mons[statue->corpsenm], 0, 0, NO_MM_FLAGS);
+               if (!mtmp) break; /* should never happen */
+               while(mtmp->minvent) {
+                   otmp = mtmp->minvent;
+                   otmp->owornmask = 0;
+                   obj_extract_self(otmp);
+                   (void) add_to_container(statue, otmp);
+               }
+               statue->owt = weight(statue);
+               mongone(mtmp);
+               break;
+             }
+           case ROLLING_BOULDER_TRAP:  /* boulder will roll towards trigger */
+               (void) mkroll_launch(ttmp, x, y, BOULDER, 1L);
+               break;
+           case HOLE:
+           case PIT:
+           case SPIKED_PIT:
+           case TRAPDOOR:
+               lev = &levl[x][y];
+               if (*in_rooms(x, y, SHOPBASE) &&
+                       ((typ == HOLE || typ == TRAPDOOR) ||
+                        IS_DOOR(lev->typ) || IS_WALL(lev->typ)))
+                   add_damage(x, y,            /* schedule repair */
+                              ((IS_DOOR(lev->typ) || IS_WALL(lev->typ))
+                               && !flags.mon_moving) ? 200L : 0L);
+               lev->doormask = 0;      /* subsumes altarmask, icedpool... */
+               if (IS_ROOM(lev->typ)) /* && !IS_AIR(lev->typ) */
+                   lev->typ = ROOM;
+
+               /*
+                * some cases which can happen when digging
+                * down while phazing thru solid areas
+                */
+               else if (lev->typ == STONE || lev->typ == SCORR)
+                   lev->typ = CORR;
+               else if (IS_WALL(lev->typ) || lev->typ == SDOOR)
+                   lev->typ = level.flags.is_maze_lev ? ROOM :
+                              level.flags.is_cavernous_lev ? CORR : DOOR;
+
+               unearth_objs(x, y);
+               break;
+       }
+       if (ttmp->ttyp == HOLE) ttmp->tseen = 1;  /* You can't hide a hole */
+       else ttmp->tseen = 0;
+       ttmp->once = 0;
+       ttmp->madeby_u = 0;
+       ttmp->dst.dnum = -1;
+       ttmp->dst.dlevel = -1;
+       if (!oldplace) {
+           ttmp->ntrap = ftrap;
+           ftrap = ttmp;
+       }
+       return(ttmp);
+}
+
+void
+fall_through(td)
+boolean td;    /* td == TRUE : trap door or hole */
+{
+       d_level dtmp;
+       char msgbuf[BUFSZ];
+       const char *dont_fall = 0;
+       register int newlevel = dunlev(&u.uz);
+
+       /* KMH -- You can't escape the Sokoban level traps */
+       if(Blind && Levitation && !In_sokoban(&u.uz)) return;
+
+       do {
+           newlevel++;
+       } while(!rn2(4) && newlevel < dunlevs_in_dungeon(&u.uz));
+
+       if(td) {
+           struct trap *t=t_at(u.ux,u.uy);
+           seetrap(t);
+           if (!In_sokoban(&u.uz)) {
+               if (t->ttyp == TRAPDOOR)
+                       pline("A trap door opens up under you!");
+               else 
+                       pline("There's a gaping hole under you!");
+           }
+       } else pline_The("%s opens up under you!", surface(u.ux,u.uy));
+
+       if (In_sokoban(&u.uz) && Can_fall_thru(&u.uz))
+           ;   /* KMH -- You can't escape the Sokoban level traps */
+       else if(Levitation || u.ustuck || !Can_fall_thru(&u.uz)
+          || Flying || is_clinger(youmonst.data)
+          || (Inhell && !u.uevent.invoked &&
+                                       newlevel == dunlevs_in_dungeon(&u.uz))
+               ) {
+           dont_fall = "don't fall in.";
+       } else if (youmonst.data->msize >= MZ_HUGE) {
+           dont_fall = "don't fit through.";
+       } else if (!next_to_u()) {
+           dont_fall = "are jerked back by your pet!";
+       }
+       if (dont_fall) {
+           You(dont_fall);
+           /* hero didn't fall through, but any objects here might */
+           impact_drop((struct obj *)0, u.ux, u.uy, 0);
+           if (!td) {
+               display_nhwindow(WIN_MESSAGE, FALSE);
+               pline_The("opening under you closes up.");
+           }
+           return;
+       }
+
+       if(*u.ushops) shopdig(1);
+       if (Is_stronghold(&u.uz)) {
+           find_hell(&dtmp);
+       } else {
+           dtmp.dnum = u.uz.dnum;
+           dtmp.dlevel = newlevel;
+       }
+       if (!td)
+           Sprintf(msgbuf, "The hole in the %s above you closes up.",
+                   ceiling(u.ux,u.uy));
+       schedule_goto(&dtmp, FALSE, TRUE, 0,
+                     (char *)0, !td ? msgbuf : (char *)0);
+}
+
+/*
+ * Animate the given statue.  May have been via shatter attempt, trap,
+ * or stone to flesh spell.  Return a monster if successfully animated.
+ * If the monster is animated, the object is deleted.  If fail_reason
+ * is non-null, then fill in the reason for failure (or success).
+ *
+ * The cause of animation is:
+ *
+ *     ANIMATE_NORMAL  - hero "finds" the monster
+ *     ANIMATE_SHATTER - hero tries to destroy the statue
+ *     ANIMATE_SPELL   - stone to flesh spell hits the statue
+ *
+ * Perhaps x, y is not needed if we can use get_obj_location() to find
+ * the statue's location... ???
+ */
+struct monst *
+animate_statue(statue, x, y, cause, fail_reason)
+struct obj *statue;
+xchar x, y;
+int cause;
+int *fail_reason;
+{
+       struct permonst *mptr;
+       struct monst *mon = 0;
+       struct obj *item;
+       coord cc;
+       boolean historic = (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && (statue->spe & STATUE_HISTORIC));
+       char statuename[BUFSZ];
+
+       Strcpy(statuename,the(xname(statue)));
+
+       if (statue->oxlth && statue->oattached == OATTACHED_MONST) {
+           cc.x = x,  cc.y = y;
+           mon = montraits(statue, &cc);
+           if (mon && mon->mtame && !mon->isminion)
+               wary_dog(mon, TRUE);
+       } else {
+           /* statue of any golem hit with stone-to-flesh becomes flesh golem */
+           if (is_golem(&mons[statue->corpsenm]) && cause == ANIMATE_SPELL)
+               mptr = &mons[PM_FLESH_GOLEM];
+           else
+               mptr = &mons[statue->corpsenm];
+           /*
+            * Guard against someone wishing for a statue of a unique monster
+            * (which is allowed in normal play) and then tossing it onto the
+            * [detected or guessed] location of a statue trap.  Normally the
+            * uppermost statue is the one which would be activated.
+            */
+           if ((mptr->geno & G_UNIQ) && cause != ANIMATE_SPELL) {
+               if (fail_reason) *fail_reason = AS_MON_IS_UNIQUE;
+               return (struct monst *)0;
+           }
+           if (cause == ANIMATE_SPELL &&
+               ((mptr->geno & G_UNIQ) || mptr->msound == MS_GUARDIAN)) {
+               /* Statues of quest guardians or unique monsters
+                * will not stone-to-flesh as the real thing.
+                */
+               mon = makemon(&mons[PM_DOPPELGANGER], x, y,
+                       NO_MINVENT|MM_NOCOUNTBIRTH|MM_ADJACENTOK);
+               if (mon) {
+                       /* makemon() will set mon->cham to
+                        * CHAM_ORDINARY if hero is wearing
+                        * ring of protection from shape changers
+                        * when makemon() is called, so we have to
+                        * check the field before calling newcham().
+                        */
+                       if (mon->cham == CHAM_DOPPELGANGER)
+                               (void) newcham(mon, mptr, FALSE, FALSE);
+               }
+           } else
+               mon = makemon(mptr, x, y, (cause == ANIMATE_SPELL) ?
+                       (NO_MINVENT | MM_ADJACENTOK) : NO_MINVENT);
+       }
+
+       if (!mon) {
+           if (fail_reason) *fail_reason = AS_NO_MON;
+           return (struct monst *)0;
+       }
+
+       /* in case statue is wielded and hero zaps stone-to-flesh at self */
+       if (statue->owornmask) remove_worn_item(statue, TRUE);
+
+       /* allow statues to be of a specific gender */
+       if (statue->spe & STATUE_MALE)
+           mon->female = FALSE;
+       else if (statue->spe & STATUE_FEMALE)
+           mon->female = TRUE;
+       /* if statue has been named, give same name to the monster */
+       if (statue->onamelth)
+           mon = christen_monst(mon, ONAME(statue));
+       /* transfer any statue contents to monster's inventory */
+       while ((item = statue->cobj) != 0) {
+           obj_extract_self(item);
+           (void) add_to_minv(mon, item);
+       }
+       m_dowear(mon, TRUE);
+       delobj(statue);
+
+       /* mimic statue becomes seen mimic; other hiders won't be hidden */
+       if (mon->m_ap_type) seemimic(mon);
+       else mon->mundetected = FALSE;
+       if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) {
+           const char *comes_to_life = nonliving(mon->data) ?
+                                       "moves" : "comes to life"; 
+           if (cause == ANIMATE_SPELL)
+               pline("%s %s!", upstart(statuename),
+                       canspotmon(mon) ? comes_to_life : "disappears");
+           else
+               pline_The("statue %s!",
+                       canspotmon(mon) ? comes_to_life : "disappears");
+           if (historic) {
+                   You_feel("guilty that the historic statue is now gone.");
+                   adjalign(-1);
+           }
+       } else if (cause == ANIMATE_SHATTER)
+           pline("Instead of shattering, the statue suddenly %s!",
+               canspotmon(mon) ? "comes to life" : "disappears");
+       else { /* cause == ANIMATE_NORMAL */
+           You("find %s posing as a statue.",
+               canspotmon(mon) ? a_monnam(mon) : something);
+           stop_occupation();
+       }
+       /* avoid hiding under nothing */
+       if (x == u.ux && y == u.uy &&
+               Upolyd && hides_under(youmonst.data) && !OBJ_AT(x, y))
+           u.uundetected = 0;
+
+       if (fail_reason) *fail_reason = AS_OK;
+       return mon;
+}
+
+/*
+ * You've either stepped onto a statue trap's location or you've triggered a
+ * statue trap by searching next to it or by trying to break it with a wand
+ * or pick-axe.
+ */
+struct monst *
+activate_statue_trap(trap, x, y, shatter)
+struct trap *trap;
+xchar x, y;
+boolean shatter;
+{
+       struct monst *mtmp = (struct monst *)0;
+       struct obj *otmp = sobj_at(STATUE, x, y);
+       int fail_reason;
+
+       /*
+        * Try to animate the first valid statue.  Stop the loop when we
+        * actually create something or the failure cause is not because
+        * the mon was unique.
+        */
+       deltrap(trap);
+       while (otmp) {
+           mtmp = animate_statue(otmp, x, y,
+                   shatter ? ANIMATE_SHATTER : ANIMATE_NORMAL, &fail_reason);
+           if (mtmp || fail_reason != AS_MON_IS_UNIQUE) break;
+
+           while ((otmp = otmp->nexthere) != 0)
+               if (otmp->otyp == STATUE) break;
+       }
+
+       if (Blind) feel_location(x, y);
+       else newsym(x, y);
+       return mtmp;
+}
+
+#ifdef STEED
+STATIC_OVL boolean
+keep_saddle_with_steedcorpse(steed_mid, objchn, saddle)
+unsigned steed_mid;
+struct obj *objchn, *saddle;
+{
+       if (!saddle) return FALSE;
+       while(objchn) {
+               if(objchn->otyp == CORPSE &&
+                  objchn->oattached == OATTACHED_MONST && objchn->oxlth) {
+                       struct monst *mtmp = (struct monst *)objchn->oextra;
+                       if (mtmp->m_id == steed_mid) {
+                               /* move saddle */
+                               xchar x,y;
+                               if (get_obj_location(objchn, &x, &y, 0)) {
+                                       obj_extract_self(saddle);
+                                       place_object(saddle, x, y);
+                                       stackobj(saddle);
+                               }
+                               return TRUE;
+                       }
+               }
+               if (Has_contents(objchn) &&
+                   keep_saddle_with_steedcorpse(steed_mid, objchn->cobj, saddle))
+                       return TRUE;
+               objchn = objchn->nobj;
+       }
+       return FALSE;
+}
+#endif /*STEED*/
+
+void
+dotrap(trap, trflags)
+register struct trap *trap;
+unsigned trflags;
+{
+       register int ttype = trap->ttyp;
+       register struct obj *otmp;
+       boolean already_seen = trap->tseen;
+       boolean webmsgok = (!(trflags & NOWEBMSG));
+       boolean forcebungle = (trflags & FORCEBUNGLE);
+
+       nomul(0);
+
+       /* KMH -- You can't escape the Sokoban level traps */
+       if (In_sokoban(&u.uz) &&
+                       (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE ||
+                       ttype == TRAPDOOR)) {
+           /* The "air currents" message is still appropriate -- even when
+            * the hero isn't flying or levitating -- because it conveys the
+            * reason why the player cannot escape the trap with a dexterity
+            * check, clinging to the ceiling, etc.
+            */
+           pline("Air currents pull you down into %s %s!",
+               a_your[trap->madeby_u],
+               defsyms[trap_to_defsym(ttype)].explanation);
+           /* then proceed to normal trap effect */
+       } else if (already_seen) {
+           if ((Levitation || Flying) &&
+                   (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE ||
+                   ttype == BEAR_TRAP)) {
+               You("%s over %s %s.",
+                   Levitation ? "float" : "fly",
+                   a_your[trap->madeby_u],
+                   defsyms[trap_to_defsym(ttype)].explanation);
+               return;
+           }
+           if(!Fumbling && ttype != MAGIC_PORTAL &&
+               ttype != ANTI_MAGIC && !forcebungle &&
+               (!rn2(5) ||
+           ((ttype == PIT || ttype == SPIKED_PIT) && is_clinger(youmonst.data)))) {
+               You("escape %s %s.",
+                   (ttype == ARROW_TRAP && !trap->madeby_u) ? "an" :
+                       a_your[trap->madeby_u],
+                   defsyms[trap_to_defsym(ttype)].explanation);
+               return;
+           }
+       }
+
+#ifdef STEED
+       if (u.usteed) u.usteed->mtrapseen |= (1 << (ttype-1));
+#endif
+
+       switch(ttype) {
+           case ARROW_TRAP:
+               if (trap->once && trap->tseen && !rn2(15)) {
+                   You_hear("a loud click!");
+                   deltrap(trap);
+                   newsym(u.ux,u.uy);
+                   break;
+               }
+               trap->once = 1;
+               seetrap(trap);
+               pline("An arrow shoots out at you!");
+               otmp = mksobj(ARROW, TRUE, FALSE);
+               otmp->quan = 1L;
+               otmp->owt = weight(otmp);
+               otmp->opoisoned = 0;
+#ifdef STEED
+               if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) /* nothing */;
+               else
+#endif
+               if (thitu(8, dmgval(otmp, &youmonst), otmp, "arrow")) {
+                   obfree(otmp, (struct obj *)0);
+               } else {
+                   place_object(otmp, u.ux, u.uy);
+                   if (!Blind) otmp->dknown = 1;
+                   stackobj(otmp);
+                   newsym(u.ux, u.uy);
+               }
+               break;
+           case DART_TRAP:
+               if (trap->once && trap->tseen && !rn2(15)) {
+                   You_hear("a soft click.");
+                   deltrap(trap);
+                   newsym(u.ux,u.uy);
+                   break;
+               }
+               trap->once = 1;
+               seetrap(trap);
+               pline("A little dart shoots out at you!");
+               otmp = mksobj(DART, TRUE, FALSE);
+               otmp->quan = 1L;
+               otmp->owt = weight(otmp);
+               if (!rn2(6)) otmp->opoisoned = 1;
+#ifdef STEED
+               if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) /* nothing */;
+               else
+#endif
+               if (thitu(7, dmgval(otmp, &youmonst), otmp, "little dart")) {
+                   if (otmp->opoisoned)
+                       poisoned("dart", A_CON, "little dart", -10);
+                   obfree(otmp, (struct obj *)0);
+               } else {
+                   place_object(otmp, u.ux, u.uy);
+                   if (!Blind) otmp->dknown = 1;
+                   stackobj(otmp);
+                   newsym(u.ux, u.uy);
+               }
+               break;
+           case ROCKTRAP:
+               if (trap->once && trap->tseen && !rn2(15)) {
+                   pline("A trap door in %s opens, but nothing falls out!",
+                         the(ceiling(u.ux,u.uy)));
+                   deltrap(trap);
+                   newsym(u.ux,u.uy);
+               } else {
+                   int dmg = d(2,6); /* should be std ROCK dmg? */
+
+                   trap->once = 1;
+                   seetrap(trap);
+                   otmp = mksobj_at(ROCK, u.ux, u.uy, TRUE, FALSE);
+                   otmp->quan = 1L;
+                   otmp->owt = weight(otmp);
+
+                   pline("A trap door in %s opens and %s falls on your %s!",
+                         the(ceiling(u.ux,u.uy)),
+                         an(xname(otmp)),
+                         body_part(HEAD));
+
+                   if (uarmh) {
+                       if(is_metallic(uarmh)) {
+                           pline("Fortunately, you are wearing a hard helmet.");
+                           dmg = 2;
+                       } else if (flags.verbose) {
+                           Your("%s does not protect you.", xname(uarmh));
+                       }
+                   }
+
+                   if (!Blind) otmp->dknown = 1;
+                   stackobj(otmp);
+                   newsym(u.ux,u.uy);  /* map the rock */
+
+                   losehp(dmg, "falling rock", KILLED_BY_AN);
+                   exercise(A_STR, FALSE);
+               }
+               break;
+
+           case SQKY_BOARD:        /* stepped on a squeaky board */
+               if (Levitation || Flying) {
+                   if (!Blind) {
+                       seetrap(trap);
+                       if (Hallucination)
+                               You("notice a crease in the linoleum.");
+                       else
+                               You("notice a loose board below you.");
+                   }
+               } else {
+                   seetrap(trap);
+                   pline("A board beneath you squeaks loudly.");
+                   wake_nearby();
+               }
+               break;
+
+           case BEAR_TRAP:
+               if(Levitation || Flying) break;
+               seetrap(trap);
+               if(amorphous(youmonst.data) || is_whirly(youmonst.data) ||
+                                                   unsolid(youmonst.data)) {
+                   pline("%s bear trap closes harmlessly through you.",
+                           A_Your[trap->madeby_u]);
+                   break;
+               }
+               if(
+#ifdef STEED
+                  !u.usteed &&
+#endif
+                  youmonst.data->msize <= MZ_SMALL) {
+                   pline("%s bear trap closes harmlessly over you.",
+                           A_Your[trap->madeby_u]);
+                   break;
+               }
+               u.utrap = rn1(4, 4);
+               u.utraptype = TT_BEARTRAP;
+#ifdef STEED
+               if (u.usteed) {
+                   pline("%s bear trap closes on %s %s!",
+                       A_Your[trap->madeby_u], s_suffix(mon_nam(u.usteed)),
+                       mbodypart(u.usteed, FOOT));
+               } else
+#endif
+               {
+                   pline("%s bear trap closes on your %s!",
+                           A_Your[trap->madeby_u], body_part(FOOT));
+                   if(u.umonnum == PM_OWLBEAR || u.umonnum == PM_BUGBEAR)
+                       You("howl in anger!");
+               }
+               exercise(A_DEX, FALSE);
+               break;
+
+           case SLP_GAS_TRAP:
+               seetrap(trap);
+               if(Sleep_resistance || breathless(youmonst.data)) {
+                   You("are enveloped in a cloud of gas!");
+                   break;
+               }
+               pline("A cloud of gas puts you to sleep!");
+               fall_asleep(-rnd(25), TRUE);
+#ifdef STEED
+               (void) steedintrap(trap, (struct obj *)0);
+#endif
+               break;
+
+           case RUST_TRAP:
+               seetrap(trap);
+               if (u.umonnum == PM_IRON_GOLEM) {
+                   int dam = u.mhmax;
+
+                   pline("%s you!", A_gush_of_water_hits);
+                   You("are covered with rust!");
+                   if (Half_physical_damage) dam = (dam+1) / 2;
+                   losehp(dam, "rusting away", KILLED_BY);
+                   break;
+               } else if (u.umonnum == PM_GREMLIN && rn2(3)) {
+                   pline("%s you!", A_gush_of_water_hits);
+                   (void)split_mon(&youmonst, (struct monst *)0);
+                   break;
+               }
+
+           /* Unlike monsters, traps cannot aim their rust attacks at
+            * you, so instead of looping through and taking either the
+            * first rustable one or the body, we take whatever we get,
+            * even if it is not rustable.
+            */
+               switch (rn2(5)) {
+                   case 0:
+                       pline("%s you on the %s!", A_gush_of_water_hits,
+                                   body_part(HEAD));
+                       (void) rust_dmg(uarmh, "helmet", 1, TRUE, &youmonst);
+                       break;
+                   case 1:
+                       pline("%s your left %s!", A_gush_of_water_hits,
+                                   body_part(ARM));
+                       if (rust_dmg(uarms, "shield", 1, TRUE, &youmonst))
+                           break;
+                       if (u.twoweap || (uwep && bimanual(uwep)))
+                           erode_obj(u.twoweap ? uswapwep : uwep, FALSE, TRUE);
+glovecheck:            (void) rust_dmg(uarmg, "gauntlets", 1, TRUE, &youmonst);
+                       /* Not "metal gauntlets" since it gets called
+                        * even if it's leather for the message
+                        */
+                       break;
+                   case 2:
+                       pline("%s your right %s!", A_gush_of_water_hits,
+                                   body_part(ARM));
+                       erode_obj(uwep, FALSE, TRUE);
+                       goto glovecheck;
+                   default:
+                       pline("%s you!", A_gush_of_water_hits);
+                       for (otmp=invent; otmp; otmp = otmp->nobj)
+                                   (void) snuff_lit(otmp);
+                       if (uarmc)
+                           (void) rust_dmg(uarmc, cloak_simple_name(uarmc),
+                                               1, TRUE, &youmonst);
+                       else if (uarm)
+                           (void) rust_dmg(uarm, "armor", 1, TRUE, &youmonst);
+#ifdef TOURIST
+                       else if (uarmu)
+                           (void) rust_dmg(uarmu, "shirt", 1, TRUE, &youmonst);
+#endif
+               }
+               update_inventory();
+               break;
+
+           case FIRE_TRAP:
+               seetrap(trap);
+               dofiretrap((struct obj *)0);
+               break;
+
+           case PIT:
+           case SPIKED_PIT:
+               /* KMH -- You can't escape the Sokoban level traps */
+               if (!In_sokoban(&u.uz) && (Levitation || Flying)) break;
+               seetrap(trap);
+               if (!In_sokoban(&u.uz) && is_clinger(youmonst.data)) {
+                   if(trap->tseen) {
+                       You("see %s %spit below you.", a_your[trap->madeby_u],
+                           ttype == SPIKED_PIT ? "spiked " : "");
+                   } else {
+                       pline("%s pit %sopens up under you!",
+                           A_Your[trap->madeby_u],
+                           ttype == SPIKED_PIT ? "full of spikes " : "");
+                       You("don't fall in!");
+                   }
+                   break;
+               }
+               if (!In_sokoban(&u.uz)) {
+                   char verbbuf[BUFSZ];
+#ifdef STEED
+                   if (u.usteed) {
+                       if ((trflags & RECURSIVETRAP) != 0)
+                           Sprintf(verbbuf, "and %s fall",
+                               x_monnam(u.usteed,
+                                   u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
+                                   (char *)0, SUPPRESS_SADDLE, FALSE));
+                       else
+                           Sprintf(verbbuf,"lead %s",
+                               x_monnam(u.usteed,
+                                        u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
+                                        "poor", SUPPRESS_SADDLE, FALSE));
+                   } else
+#endif
+                   Strcpy(verbbuf,"fall");
+                   You("%s into %s pit!", verbbuf, a_your[trap->madeby_u]);
+               }
+               /* wumpus reference */
+               if (Role_if(PM_RANGER) && !trap->madeby_u && !trap->once &&
+                       In_quest(&u.uz) && Is_qlocate(&u.uz)) {
+                   pline("Fortunately it has a bottom after all...");
+                   trap->once = 1;
+               } else if (u.umonnum == PM_PIT_VIPER ||
+                       u.umonnum == PM_PIT_FIEND)
+                   pline("How pitiful.  Isn't that the pits?");
+               if (ttype == SPIKED_PIT) {
+                   const char *predicament = "on a set of sharp iron spikes";
+#ifdef STEED
+                   if (u.usteed) {
+                       pline("%s lands %s!",
+                               upstart(x_monnam(u.usteed,
+                                        u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
+                                        "poor", SUPPRESS_SADDLE, FALSE)),
+                             predicament);
+                   } else
+#endif
+                   You("land %s!", predicament);
+               }
+               if (!Passes_walls)
+                   u.utrap = rn1(6,2);
+               u.utraptype = TT_PIT;
+#ifdef STEED
+               if (!steedintrap(trap, (struct obj *)0)) {
+#endif
+               if (ttype == SPIKED_PIT) {
+                   losehp(rnd(10),"fell into a pit of iron spikes",
+                       NO_KILLER_PREFIX);
+                   if (!rn2(6))
+                       poisoned("spikes", A_STR, "fall onto poison spikes", 8);
+               } else
+                   losehp(rnd(6),"fell into a pit", NO_KILLER_PREFIX);
+               if (Punished && !carried(uball)) {
+                   unplacebc();
+                   ballfall();
+                   placebc();
+               }
+               selftouch("Falling, you");
+               vision_full_recalc = 1; /* vision limits change */
+               exercise(A_STR, FALSE);
+               exercise(A_DEX, FALSE);
+#ifdef STEED
+               }
+#endif
+               break;
+           case HOLE:
+           case TRAPDOOR:
+               if (!Can_fall_thru(&u.uz)) {
+                   seetrap(trap);      /* normally done in fall_through */
+                   impossible("dotrap: %ss cannot exist on this level.",
+                              defsyms[trap_to_defsym(ttype)].explanation);
+                   break;              /* don't activate it after all */
+               }
+               fall_through(TRUE);
+               break;
+
+           case TELEP_TRAP:
+               seetrap(trap);
+               tele_trap(trap);
+               break;
+           case LEVEL_TELEP:
+               seetrap(trap);
+               level_tele_trap(trap);
+               break;
+
+           case WEB: /* Our luckless player has stumbled into a web. */
+               seetrap(trap);
+               if (amorphous(youmonst.data) || is_whirly(youmonst.data) ||
+                                                   unsolid(youmonst.data)) {
+                   if (acidic(youmonst.data) || u.umonnum == PM_GELATINOUS_CUBE ||
+                       u.umonnum == PM_FIRE_ELEMENTAL) {
+                       if (webmsgok)
+                           You("%s %s spider web!",
+                               (u.umonnum == PM_FIRE_ELEMENTAL) ? "burn" : "dissolve",
+                               a_your[trap->madeby_u]);
+                       deltrap(trap);
+                       newsym(u.ux,u.uy);
+                       break;
+                   }
+                   if (webmsgok) You("flow through %s spider web.",
+                           a_your[trap->madeby_u]);
+                   break;
+               }
+               if (webmaker(youmonst.data)) {
+                   if (webmsgok)
+                       pline(trap->madeby_u ? "You take a walk on your web."
+                                        : "There is a spider web here.");
+                   break;
+               }
+               if (webmsgok) {
+                   char verbbuf[BUFSZ];
+                   verbbuf[0] = '\0';
+#ifdef STEED
+                   if (u.usteed)
+                       Sprintf(verbbuf,"lead %s",
+                               x_monnam(u.usteed,
+                                        u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
+                                        "poor", SUPPRESS_SADDLE, FALSE));
+                   else
+#endif
+                       
+                   Sprintf(verbbuf, "%s", Levitation ? (const char *)"float" :
+                               locomotion(youmonst.data, "stumble"));
+                   You("%s into %s spider web!",
+                       verbbuf, a_your[trap->madeby_u]);
+               }
+               u.utraptype = TT_WEB;
+
+               /* Time stuck in the web depends on your/steed strength. */
+               {
+                   register int str = ACURR(A_STR);
+
+#ifdef STEED
+                   /* If mounted, the steed gets trapped.  Use mintrap
+                    * to do all the work.  If mtrapped is set as a result,
+                    * unset it and set utrap instead.  In the case of a
+                    * strongmonst and mintrap said it's trapped, use a
+                    * short but non-zero trap time.  Otherwise, monsters
+                    * have no specific strength, so use player strength.
+                    * This gets skipped for webmsgok, which implies that
+                    * the steed isn't a factor.
+                    */
+                   if (u.usteed && webmsgok) {
+                       /* mtmp location might not be up to date */
+                       u.usteed->mx = u.ux;
+                       u.usteed->my = u.uy;
+
+                       /* mintrap currently does not return 2(died) for webs */
+                       if (mintrap(u.usteed)) {
+                           u.usteed->mtrapped = 0;
+                           if (strongmonst(u.usteed->data)) str = 17;
+                       } else {
+                           break;
+                       }
+
+                       webmsgok = FALSE; /* mintrap printed the messages */
+                   }
+#endif
+                   if (str <= 3) u.utrap = rn1(6,6);
+                   else if (str < 6) u.utrap = rn1(6,4);
+                   else if (str < 9) u.utrap = rn1(4,4);
+                   else if (str < 12) u.utrap = rn1(4,2);
+                   else if (str < 15) u.utrap = rn1(2,2);
+                   else if (str < 18) u.utrap = rnd(2);
+                   else if (str < 69) u.utrap = 1;
+                   else {
+                       u.utrap = 0;
+                       if (webmsgok)
+                           You("tear through %s web!", a_your[trap->madeby_u]);
+                       deltrap(trap);
+                       newsym(u.ux,u.uy);      /* get rid of trap symbol */
+                   }
+               }
+               break;
+
+           case STATUE_TRAP:
+               (void) activate_statue_trap(trap, u.ux, u.uy, FALSE);
+               break;
+
+           case MAGIC_TRAP:        /* A magic trap. */
+               seetrap(trap);
+               if (!rn2(30)) {
+                   deltrap(trap);
+                   newsym(u.ux,u.uy);  /* update position */
+                   You("are caught in a magical explosion!");
+                   losehp(rnd(10), "magical explosion", KILLED_BY_AN);
+                   Your("body absorbs some of the magical energy!");
+                   u.uen = (u.uenmax += 2);
+               } else domagictrap();
+#ifdef STEED
+               (void) steedintrap(trap, (struct obj *)0);
+#endif
+               break;
+
+           case ANTI_MAGIC:
+               seetrap(trap);
+               if(Antimagic) {
+                   shieldeff(u.ux, u.uy);
+                   You_feel("momentarily lethargic.");
+               } else drain_en(rnd(u.ulevel) + 1);
+               break;
+
+           case POLY_TRAP: {
+               char verbbuf[BUFSZ];
+               seetrap(trap);
+#ifdef STEED
+               if (u.usteed)
+                       Sprintf(verbbuf, "lead %s",
+                               x_monnam(u.usteed,
+                                        u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
+                                        (char *)0, SUPPRESS_SADDLE, FALSE));
+               else
+#endif
+                Sprintf(verbbuf,"%s",
+                   Levitation ? (const char *)"float" :
+                   locomotion(youmonst.data, "step"));
+               You("%s onto a polymorph trap!", verbbuf);
+               if(Antimagic || Unchanging) {
+                   shieldeff(u.ux, u.uy);
+                   You_feel("momentarily different.");
+                   /* Trap did nothing; don't remove it --KAA */
+               } else {
+#ifdef STEED
+                   (void) steedintrap(trap, (struct obj *)0);
+#endif
+                   deltrap(trap);      /* delete trap before polymorph */
+                   newsym(u.ux,u.uy);  /* get rid of trap symbol */
+                   You_feel("a change coming over you.");
+                   polyself(FALSE);
+               }
+               break;
+           }
+           case LANDMINE: {
+#ifdef STEED
+               unsigned steed_mid = 0;
+               struct obj *saddle = 0;
+#endif
+               if (Levitation || Flying) {
+                   if (!already_seen && rn2(3)) break;
+                   seetrap(trap);
+                   pline("%s %s in a pile of soil below you.",
+                           already_seen ? "There is" : "You discover",
+                           trap->madeby_u ? "the trigger of your mine" :
+                                            "a trigger");
+                   if (already_seen && rn2(3)) break;
+                   pline("KAABLAMM!!!  %s %s%s off!",
+                         forcebungle ? "Your inept attempt sets" :
+                                       "The air currents set",
+                           already_seen ? a_your[trap->madeby_u] : "",
+                           already_seen ? " land mine" : "it");
+               } else {
+#ifdef STEED
+                   /* prevent landmine from killing steed, throwing you to
+                    * the ground, and you being affected again by the same
+                    * mine because it hasn't been deleted yet
+                    */
+                   static boolean recursive_mine = FALSE;
+
+                   if (recursive_mine) break;
+#endif
+                   seetrap(trap);
+                   pline("KAABLAMM!!!  You triggered %s land mine!",
+                                           a_your[trap->madeby_u]);
+#ifdef STEED
+                   if (u.usteed) steed_mid = u.usteed->m_id;
+                   recursive_mine = TRUE;
+                   (void) steedintrap(trap, (struct obj *)0);
+                   recursive_mine = FALSE;
+                   saddle = sobj_at(SADDLE,u.ux, u.uy);
+#endif
+                   set_wounded_legs(LEFT_SIDE, rn1(35, 41));
+                   set_wounded_legs(RIGHT_SIDE, rn1(35, 41));
+                   exercise(A_DEX, FALSE);
+               }
+               blow_up_landmine(trap);
+#ifdef STEED
+               if (steed_mid && saddle && !u.usteed)
+                       (void)keep_saddle_with_steedcorpse(steed_mid, fobj, saddle);
+#endif
+               newsym(u.ux,u.uy);              /* update trap symbol */
+               losehp(rnd(16), "land mine", KILLED_BY_AN);
+               /* fall recursively into the pit... */
+               if ((trap = t_at(u.ux, u.uy)) != 0) dotrap(trap, RECURSIVETRAP);
+               fill_pit(u.ux, u.uy);
+               break;
+           }
+           case ROLLING_BOULDER_TRAP: {
+               int style = ROLL | (trap->tseen ? LAUNCH_KNOWN : 0);
+
+               seetrap(trap);
+               pline("Click! You trigger a rolling boulder trap!");
+               if(!launch_obj(BOULDER, trap->launch.x, trap->launch.y,
+                     trap->launch2.x, trap->launch2.y, style)) {
+                   deltrap(trap);
+                   newsym(u.ux,u.uy);  /* get rid of trap symbol */
+                   pline("Fortunately for you, no boulder was released.");
+               }
+               break;
+           }
+           case MAGIC_PORTAL:
+               seetrap(trap);
+               domagicportal(trap);
+               break;
+
+           default:
+               seetrap(trap);
+               impossible("You hit a trap of type %u", trap->ttyp);
+       }
+}
+
+#ifdef STEED
+STATIC_OVL int
+steedintrap(trap, otmp)
+struct trap *trap;
+struct obj *otmp;
+{
+       struct monst *mtmp = u.usteed;
+       struct permonst *mptr;
+       int tt;
+       boolean in_sight;
+       boolean trapkilled = FALSE;
+       boolean steedhit = FALSE;
+
+       if (!u.usteed || !trap) return 0;
+       mptr = mtmp->data;
+       tt = trap->ttyp;
+       mtmp->mx = u.ux;
+       mtmp->my = u.uy;
+
+       in_sight = !Blind;
+       switch (tt) {
+               case ARROW_TRAP:
+                       if(!otmp) {
+                               impossible("steed hit by non-existant arrow?");
+                               return 0;
+                       }
+                       if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
+                       steedhit = TRUE;
+                       break;
+               case DART_TRAP:
+                       if(!otmp) {
+                               impossible("steed hit by non-existant dart?");
+                               return 0;
+                       }
+                       if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
+                       steedhit = TRUE;
+                       break;
+               case SLP_GAS_TRAP:
+                   if (!resists_sleep(mtmp) && !breathless(mptr) &&
+                               !mtmp->msleeping && mtmp->mcanmove) {
+                           mtmp->mcanmove = 0;
+                           mtmp->mfrozen = rnd(25);
+                           if (in_sight) {
+                               pline("%s suddenly falls asleep!",
+                                     Monnam(mtmp));
+                           }
+                       }
+                       steedhit = TRUE;
+                       break;
+               case LANDMINE:
+                       if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE))
+                           trapkilled = TRUE;
+                       steedhit = TRUE;
+                       break;
+               case PIT:
+               case SPIKED_PIT:
+                       if (mtmp->mhp <= 0 ||
+                               thitm(0, mtmp, (struct obj *)0,
+                                     rnd((tt == PIT) ? 6 : 10), FALSE))
+                           trapkilled = TRUE;
+                       steedhit = TRUE;
+                       break;
+               case POLY_TRAP: 
+                   if (!resists_magm(mtmp)) {
+                       if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) {
+                       (void) newcham(mtmp, (struct permonst *)0,
+                                      FALSE, FALSE);
+                       if (!can_saddle(mtmp) || !can_ride(mtmp)) {
+                               dismount_steed(DISMOUNT_POLY);
+                       } else {
+                               You("have to adjust yourself in the saddle on %s.",
+                                       x_monnam(mtmp,
+                                        mtmp->mnamelth ? ARTICLE_NONE : ARTICLE_A,
+                                        (char *)0, SUPPRESS_SADDLE, FALSE));
+                       }
+                               
+                   }
+                   steedhit = TRUE;
+                   break;
+               default:
+                       return 0;
+           }
+       }
+       if(trapkilled) {
+               dismount_steed(DISMOUNT_POLY);
+               return 2;
+       }
+       else if(steedhit) return 1;
+       else return 0;
+}
+#endif /*STEED*/
+
+/* some actions common to both player and monsters for triggered landmine */
+void
+blow_up_landmine(trap)
+struct trap *trap;
+{
+       (void)scatter(trap->tx, trap->ty, 4,
+               MAY_DESTROY | MAY_HIT | MAY_FRACTURE | VIS_EFFECTS,
+               (struct obj *)0);
+       del_engr_at(trap->tx, trap->ty);
+       wake_nearto(trap->tx, trap->ty, 400);
+       if (IS_DOOR(levl[trap->tx][trap->ty].typ))
+           levl[trap->tx][trap->ty].doormask = D_BROKEN;
+       /* TODO: destroy drawbridge if present */
+       /* caller may subsequently fill pit, e.g. with a boulder */
+       trap->ttyp = PIT;               /* explosion creates a pit */
+       trap->madeby_u = FALSE;         /* resulting pit isn't yours */
+       seetrap(trap);                  /* and it isn't concealed */
+}
+
+#endif /* OVLB */
+#ifdef OVL3
+
+/*
+ * Move obj from (x1,y1) to (x2,y2)
+ *
+ * Return 0 if no object was launched.
+ *        1 if an object was launched and placed somewhere.
+ *        2 if an object was launched, but used up.
+ */
+int
+launch_obj(otyp, x1, y1, x2, y2, style)
+short otyp;
+register int x1,y1,x2,y2;
+int style;
+{
+       register struct monst *mtmp;
+       register struct obj *otmp, *otmp2;
+       register int dx,dy;
+       struct obj *singleobj;
+       boolean used_up = FALSE;
+       boolean otherside = FALSE;
+       int dist;
+       int tmp;
+       int delaycnt = 0;
+
+       otmp = sobj_at(otyp, x1, y1);
+       /* Try the other side too, for rolling boulder traps */
+       if (!otmp && otyp == BOULDER) {
+               otherside = TRUE;
+               otmp = sobj_at(otyp, x2, y2);
+       }
+       if (!otmp) return 0;
+       if (otherside) {        /* swap 'em */
+               int tx, ty;
+
+               tx = x1; ty = y1;
+               x1 = x2; y1 = y2;
+               x2 = tx; y2 = ty;
+       }
+
+       if (otmp->quan == 1L) {
+           obj_extract_self(otmp);
+           singleobj = otmp;
+           otmp = (struct obj *) 0;
+       } else {
+           singleobj = splitobj(otmp, 1L);
+           obj_extract_self(singleobj);
+       }
+       newsym(x1,y1);
+       /* in case you're using a pick-axe to chop the boulder that's being
+          launched (perhaps a monster triggered it), destroy context so that
+          next dig attempt never thinks you're resuming previous effort */
+       if ((otyp == BOULDER || otyp == STATUE) &&
+           singleobj->ox == digging.pos.x && singleobj->oy == digging.pos.y)
+           (void) memset((genericptr_t)&digging, 0, sizeof digging);
+
+       dist = distmin(x1,y1,x2,y2);
+       bhitpos.x = x1;
+       bhitpos.y = y1;
+       dx = sgn(x2 - x1);
+       dy = sgn(y2 - y1);
+       switch (style) {
+           case ROLL|LAUNCH_UNSEEN:
+                       if (otyp == BOULDER) {
+                           You_hear(Hallucination ?
+                                    "someone bowling." :
+                                    "rumbling in the distance.");
+                       }
+                       style &= ~LAUNCH_UNSEEN;
+                       goto roll;
+           case ROLL|LAUNCH_KNOWN:
+                       /* use otrapped as a flag to ohitmon */
+                       singleobj->otrapped = 1;
+                       style &= ~LAUNCH_KNOWN;
+                       /* fall through */
+           roll:
+           case ROLL:
+                       delaycnt = 2;
+                       /* fall through */
+           default:
+                       if (!delaycnt) delaycnt = 1;
+                       if (!cansee(bhitpos.x,bhitpos.y)) curs_on_u();
+                       tmp_at(DISP_FLASH, obj_to_glyph(singleobj));
+                       tmp_at(bhitpos.x, bhitpos.y);
+       }
+
+       /* Set the object in motion */
+       while(dist-- > 0 && !used_up) {
+               struct trap *t;
+               tmp_at(bhitpos.x, bhitpos.y);
+               tmp = delaycnt;
+
+               /* dstage@u.washington.edu -- Delay only if hero sees it */
+               if (cansee(bhitpos.x, bhitpos.y))
+                       while (tmp-- > 0) delay_output();
+
+               bhitpos.x += dx;
+               bhitpos.y += dy;
+               t = t_at(bhitpos.x, bhitpos.y);
+               
+               if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
+                       if (otyp == BOULDER && throws_rocks(mtmp->data)) {
+                           if (rn2(3)) {
+                               pline("%s snatches the boulder.",
+                                       Monnam(mtmp));
+                               singleobj->otrapped = 0;
+                               (void) mpickobj(mtmp, singleobj);
+                               used_up = TRUE;
+                               break;
+                           }
+                       }
+                       if (ohitmon(mtmp,singleobj,
+                                       (style==ROLL) ? -1 : dist, FALSE)) {
+                               used_up = TRUE;
+                               break;
+                       }
+               } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
+                       if (multi) nomul(0);
+                       if (thitu(9 + singleobj->spe,
+                                 dmgval(singleobj, &youmonst),
+                                 singleobj, (char *)0))
+                           stop_occupation();
+               }
+               if (style == ROLL) {
+                   if (down_gate(bhitpos.x, bhitpos.y) != -1) {
+                       if(ship_object(singleobj, bhitpos.x, bhitpos.y, FALSE)){
+                               used_up = TRUE;
+                               break;
+                       }
+                   }
+                   if (t && otyp == BOULDER) {
+                       switch(t->ttyp) {
+                       case LANDMINE:
+                           if (rn2(10) > 2) {
+                               pline(
+                                 "KAABLAMM!!!%s",
+                                 cansee(bhitpos.x, bhitpos.y) ?
+                                       " The rolling boulder triggers a land mine." : "");
+                               deltrap(t);
+                               del_engr_at(bhitpos.x,bhitpos.y);
+                               place_object(singleobj, bhitpos.x, bhitpos.y);
+                               singleobj->otrapped = 0;
+                               fracture_rock(singleobj);
+                               (void)scatter(bhitpos.x,bhitpos.y, 4,
+                                       MAY_DESTROY|MAY_HIT|MAY_FRACTURE|VIS_EFFECTS,
+                                       (struct obj *)0);
+                               if (cansee(bhitpos.x,bhitpos.y))
+                                       newsym(bhitpos.x,bhitpos.y);
+                               used_up = TRUE;
+                           }
+                           break;              
+                       case LEVEL_TELEP:
+                       case TELEP_TRAP:
+                           if (cansee(bhitpos.x, bhitpos.y))
+                               pline("Suddenly the rolling boulder disappears!");
+                           else
+                               You_hear("a rumbling stop abruptly.");
+                           singleobj->otrapped = 0;
+                           if (t->ttyp == TELEP_TRAP)
+                               rloco(singleobj);
+                           else {
+                               int newlev = random_teleport_level();
+                               d_level dest;
+
+                               if (newlev == depth(&u.uz) || In_endgame(&u.uz))
+                                   continue;
+                               add_to_migration(singleobj);
+                               get_level(&dest, newlev);
+                               singleobj->ox = dest.dnum;
+                               singleobj->oy = dest.dlevel;
+                               singleobj->owornmask = (long)MIGR_RANDOM;
+                           }
+                           seetrap(t);
+                           used_up = TRUE;
+                           break;
+                       case PIT:
+                       case SPIKED_PIT:
+                       case HOLE:
+                       case TRAPDOOR:
+                           /* the boulder won't be used up if there is a
+                              monster in the trap; stop rolling anyway */
+                           x2 = bhitpos.x,  y2 = bhitpos.y;  /* stops here */
+                           if (flooreffects(singleobj, x2, y2, "fall"))
+                               used_up = TRUE;
+                           dist = -1;  /* stop rolling immediately */
+                           break;
+                       }
+                       if (used_up || dist == -1) break;
+                   }
+                   if (flooreffects(singleobj, bhitpos.x, bhitpos.y, "fall")) {
+                       used_up = TRUE;
+                       break;
+                   }
+                   if (otyp == BOULDER &&
+                      (otmp2 = sobj_at(BOULDER, bhitpos.x, bhitpos.y)) != 0) {
+                       const char *bmsg =
+                                    " as one boulder sets another in motion";
+
+                       if (!isok(bhitpos.x + dx, bhitpos.y + dy) || !dist ||
+                           IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ))
+                           bmsg = " as one boulder hits another";
+
+                       You_hear("a loud crash%s!",
+                               cansee(bhitpos.x, bhitpos.y) ? bmsg : "");
+                       obj_extract_self(otmp2);
+                       /* pass off the otrapped flag to the next boulder */
+                       otmp2->otrapped = singleobj->otrapped;
+                       singleobj->otrapped = 0;
+                       place_object(singleobj, bhitpos.x, bhitpos.y);
+                       singleobj = otmp2;
+                       otmp2 = (struct obj *)0;
+                       wake_nearto(bhitpos.x, bhitpos.y, 10*10);
+                   }
+               }
+               if (otyp == BOULDER && closed_door(bhitpos.x,bhitpos.y)) {
+                       if (cansee(bhitpos.x, bhitpos.y))
+                               pline_The("boulder crashes through a door.");
+                       levl[bhitpos.x][bhitpos.y].doormask = D_BROKEN;
+                       if (dist) unblock_point(bhitpos.x, bhitpos.y);
+               }
+
+               /* if about to hit iron bars, do so now */
+               if (dist > 0 && isok(bhitpos.x + dx,bhitpos.y + dy) &&
+                       levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS) {
+                   x2 = bhitpos.x,  y2 = bhitpos.y;    /* object stops here */
+                   if (hits_bars(&singleobj, x2, y2, !rn2(20), 0)) {
+                       if (!singleobj) used_up = TRUE;
+                       break;
+                   }
+               }
+       }
+       tmp_at(DISP_END, 0);
+       if (!used_up) {
+               singleobj->otrapped = 0;
+               place_object(singleobj, x2,y2);
+               newsym(x2,y2);
+               return 1;
+       } else
+               return 2;
+}
+
+#endif /* OVL3 */
+#ifdef OVLB
+
+void
+seetrap(trap)
+       register struct trap *trap;
+{
+       if(!trap->tseen) {
+           trap->tseen = 1;
+           newsym(trap->tx, trap->ty);
+       }
+}
+
+#endif /* OVLB */
+#ifdef OVL3
+
+STATIC_OVL int
+mkroll_launch(ttmp, x, y, otyp, ocount)
+struct trap *ttmp;
+xchar x,y;
+short otyp;
+long ocount;
+{
+       struct obj *otmp;
+       register int tmp;
+       schar dx,dy;
+       int distance;
+       coord cc;
+       coord bcc;
+       int trycount = 0;
+       boolean success = FALSE;
+       int mindist = 4;
+
+       if (ttmp->ttyp == ROLLING_BOULDER_TRAP) mindist = 2;
+       distance = rn1(5,4);    /* 4..8 away */
+       tmp = rn2(8);           /* randomly pick a direction to try first */
+       while (distance >= mindist) {
+               dx = xdir[tmp];
+               dy = ydir[tmp];
+               cc.x = x; cc.y = y;
+               /* Prevent boulder from being placed on water */
+               if (ttmp->ttyp == ROLLING_BOULDER_TRAP
+                               && is_pool(x+distance*dx,y+distance*dy))
+                       success = FALSE;
+               else success = isclearpath(&cc, distance, dx, dy);
+               if (ttmp->ttyp == ROLLING_BOULDER_TRAP) {
+                       boolean success_otherway;
+                       bcc.x = x; bcc.y = y;
+                       success_otherway = isclearpath(&bcc, distance,
+                                               -(dx), -(dy));
+                       if (!success_otherway) success = FALSE;
+               }
+               if (success) break;
+               if (++tmp > 7) tmp = 0;
+               if ((++trycount % 8) == 0) --distance;
+       }
+       if (!success) {
+           /* create the trap without any ammo, launch pt at trap location */
+               cc.x = bcc.x = x;
+               cc.y = bcc.y = y;
+       } else {
+               otmp = mksobj(otyp, TRUE, FALSE);
+               otmp->quan = ocount;
+               otmp->owt = weight(otmp);
+               place_object(otmp, cc.x, cc.y);
+               stackobj(otmp);
+       }
+       ttmp->launch.x = cc.x;
+       ttmp->launch.y = cc.y;
+       if (ttmp->ttyp == ROLLING_BOULDER_TRAP) {
+               ttmp->launch2.x = bcc.x;
+               ttmp->launch2.y = bcc.y;
+       } else
+               ttmp->launch_otyp = otyp;
+       newsym(ttmp->launch.x, ttmp->launch.y);
+       return 1;
+}
+
+STATIC_OVL boolean
+isclearpath(cc,distance,dx,dy)
+coord *cc;
+int distance;
+schar dx,dy;
+{
+       uchar typ;
+       xchar x, y;
+
+       x = cc->x;
+       y = cc->y;
+       while (distance-- > 0) {
+               x += dx;
+               y += dy;
+               typ = levl[x][y].typ;
+               if (!isok(x,y) || !ZAP_POS(typ) || closed_door(x,y))
+                       return FALSE;
+       }
+       cc->x = x;
+       cc->y = y;
+       return TRUE;
+}
+#endif /* OVL3 */
+#ifdef OVL1
+
+int
+mintrap(mtmp)
+register struct monst *mtmp;
+{
+       register struct trap *trap = t_at(mtmp->mx, mtmp->my);
+       boolean trapkilled = FALSE;
+       struct permonst *mptr = mtmp->data;
+       struct obj *otmp;
+
+       if (!trap) {
+           mtmp->mtrapped = 0; /* perhaps teleported? */
+       } else if (mtmp->mtrapped) {    /* is currently in the trap */
+           if (!trap->tseen &&
+               cansee(mtmp->mx, mtmp->my) && canseemon(mtmp) &&
+               (trap->ttyp == SPIKED_PIT || trap->ttyp == BEAR_TRAP ||
+                trap->ttyp == HOLE || trap->ttyp == PIT ||
+                trap->ttyp == WEB)) {
+               /* If you come upon an obviously trapped monster, then
+                * you must be able to see the trap it's in too.
+                */
+               seetrap(trap);
+           }
+               
+           if (!rn2(40)) {
+               if (sobj_at(BOULDER, mtmp->mx, mtmp->my) &&
+                       (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) {
+                   if (!rn2(2)) {
+                       mtmp->mtrapped = 0;
+                       if (canseemon(mtmp))
+                           pline("%s pulls free...", Monnam(mtmp));
+                       fill_pit(mtmp->mx, mtmp->my);
+                   }
+               } else {
+                   mtmp->mtrapped = 0;
+               }
+           } else if (metallivorous(mptr)) {
+               if (trap->ttyp == BEAR_TRAP) {
+                   if (canseemon(mtmp))
+                       pline("%s eats a bear trap!", Monnam(mtmp));
+                   deltrap(trap);
+                   mtmp->meating = 5;
+                   mtmp->mtrapped = 0;
+               } else if (trap->ttyp == SPIKED_PIT) {
+                   if (canseemon(mtmp))
+                       pline("%s munches on some spikes!", Monnam(mtmp));
+                   trap->ttyp = PIT;
+                   mtmp->meating = 5;
+               }
+           }
+       } else {
+           register int tt = trap->ttyp;
+           boolean in_sight, tear_web, see_it,
+                   inescapable = ((tt == HOLE || tt == PIT) &&
+                                  In_sokoban(&u.uz) && !trap->madeby_u);
+           const char *fallverb;
+
+#ifdef STEED
+           /* true when called from dotrap, inescapable is not an option */
+           if (mtmp == u.usteed) inescapable = TRUE;
+#endif
+           if (!inescapable &&
+                   ((mtmp->mtrapseen & (1 << (tt-1))) != 0 ||
+                       (tt == HOLE && !mindless(mtmp->data)))) {
+               /* it has been in such a trap - perhaps it escapes */
+               if(rn2(4)) return(0);
+           } else {
+               mtmp->mtrapseen |= (1 << (tt-1));
+           }
+           /* Monster is aggravated by being trapped by you.
+              Recognizing who made the trap isn't completely
+              unreasonable; everybody has their own style. */
+           if (trap->madeby_u && rnl(5)) setmangry(mtmp);
+
+           in_sight = canseemon(mtmp);
+           see_it = cansee(mtmp->mx, mtmp->my);
+#ifdef STEED
+           /* assume hero can tell what's going on for the steed */
+           if (mtmp == u.usteed) in_sight = TRUE;
+#endif
+           switch (tt) {
+               case ARROW_TRAP:
+                       if (trap->once && trap->tseen && !rn2(15)) {
+                           if (in_sight && see_it)
+                               pline("%s triggers a trap but nothing happens.",
+                                     Monnam(mtmp));
+                           deltrap(trap);
+                           newsym(mtmp->mx, mtmp->my);
+                           break;
+                       }
+                       trap->once = 1;
+                       otmp = mksobj(ARROW, TRUE, FALSE);
+                       otmp->quan = 1L;
+                       otmp->owt = weight(otmp);
+                       otmp->opoisoned = 0;
+                       if (in_sight) seetrap(trap);
+                       if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
+                       break;
+               case DART_TRAP:
+                       if (trap->once && trap->tseen && !rn2(15)) {
+                           if (in_sight && see_it)
+                               pline("%s triggers a trap but nothing happens.",
+                                     Monnam(mtmp));
+                           deltrap(trap);
+                           newsym(mtmp->mx, mtmp->my);
+                           break;
+                       }
+                       trap->once = 1;
+                       otmp = mksobj(DART, TRUE, FALSE);
+                       otmp->quan = 1L;
+                       otmp->owt = weight(otmp);
+                       if (!rn2(6)) otmp->opoisoned = 1;
+                       if (in_sight) seetrap(trap);
+                       if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
+                       break;
+               case ROCKTRAP:
+                       if (trap->once && trap->tseen && !rn2(15)) {
+                           if (in_sight && see_it)
+                               pline("A trap door above %s opens, but nothing falls out!",
+                                     mon_nam(mtmp));
+                           deltrap(trap);
+                           newsym(mtmp->mx, mtmp->my);
+                           break;
+                       }
+                       trap->once = 1;
+                       otmp = mksobj(ROCK, TRUE, FALSE);
+                       otmp->quan = 1L;
+                       otmp->owt = weight(otmp);
+                       if (in_sight) seetrap(trap);
+                       if (thitm(0, mtmp, otmp, d(2, 6), FALSE))
+                           trapkilled = TRUE;
+                       break;
+
+               case SQKY_BOARD:
+                       if(is_flyer(mptr)) break;
+                       /* stepped on a squeaky board */
+                       if (in_sight) {
+                           pline("A board beneath %s squeaks loudly.", mon_nam(mtmp));
+                           seetrap(trap);
+                       } else
+                          You_hear("a distant squeak.");
+                       /* wake up nearby monsters */
+                       wake_nearto(mtmp->mx, mtmp->my, 40);
+                       break;
+
+               case BEAR_TRAP:
+                       if(mptr->msize > MZ_SMALL &&
+                               !amorphous(mptr) && !is_flyer(mptr) &&
+                               !is_whirly(mptr) && !unsolid(mptr)) {
+                           mtmp->mtrapped = 1;
+                           if(in_sight) {
+                               pline("%s is caught in %s bear trap!",
+                                     Monnam(mtmp), a_your[trap->madeby_u]);
+                               seetrap(trap);
+                           } else {
+                               if((mptr == &mons[PM_OWLBEAR]
+                                   || mptr == &mons[PM_BUGBEAR])
+                                  && flags.soundok)
+                                   You_hear("the roaring of an angry bear!");
+                           }
+                       }
+                       break;
+
+               case SLP_GAS_TRAP:
+                   if (!resists_sleep(mtmp) && !breathless(mptr) &&
+                               !mtmp->msleeping && mtmp->mcanmove) {
+                           mtmp->mcanmove = 0;
+                           mtmp->mfrozen = rnd(25);
+                           if (in_sight) {
+                               pline("%s suddenly falls asleep!",
+                                     Monnam(mtmp));
+                               seetrap(trap);
+                           }
+                       }
+                       break;
+
+               case RUST_TRAP:
+                   {
+                       struct obj *target;
+
+                       if (in_sight)
+                           seetrap(trap);
+                       switch (rn2(5)) {
+                       case 0:
+                           if (in_sight)
+                               pline("%s %s on the %s!", A_gush_of_water_hits,
+                                   mon_nam(mtmp), mbodypart(mtmp, HEAD));
+                           target = which_armor(mtmp, W_ARMH);
+                           (void) rust_dmg(target, "helmet", 1, TRUE, mtmp);
+                           break;
+                       case 1:
+                           if (in_sight)
+                               pline("%s %s's left %s!", A_gush_of_water_hits,
+                                   mon_nam(mtmp), mbodypart(mtmp, ARM));
+                           target = which_armor(mtmp, W_ARMS);
+                           if (rust_dmg(target, "shield", 1, TRUE, mtmp))
+                               break;
+                           target = MON_WEP(mtmp);
+                           if (target && bimanual(target))
+                               erode_obj(target, FALSE, TRUE);
+glovecheck:                target = which_armor(mtmp, W_ARMG);
+                           (void) rust_dmg(target, "gauntlets", 1, TRUE, mtmp);
+                           break;
+                       case 2:
+                           if (in_sight)
+                               pline("%s %s's right %s!", A_gush_of_water_hits,
+                                   mon_nam(mtmp), mbodypart(mtmp, ARM));
+                           erode_obj(MON_WEP(mtmp), FALSE, TRUE);
+                           goto glovecheck;
+                       default:
+                           if (in_sight)
+                               pline("%s %s!", A_gush_of_water_hits,
+                                   mon_nam(mtmp));
+                           for (otmp=mtmp->minvent; otmp; otmp = otmp->nobj)
+                               (void) snuff_lit(otmp);
+                           target = which_armor(mtmp, W_ARMC);
+                           if (target)
+                               (void) rust_dmg(target, cloak_simple_name(target),
+                                                1, TRUE, mtmp);
+                           else {
+                               target = which_armor(mtmp, W_ARM);
+                               if (target)
+                                   (void) rust_dmg(target, "armor", 1, TRUE, mtmp);
+#ifdef TOURIST
+                               else {
+                                   target = which_armor(mtmp, W_ARMU);
+                                   (void) rust_dmg(target, "shirt", 1, TRUE, mtmp);
+                               }
+#endif
+                           }
+                       }
+                       if (mptr == &mons[PM_IRON_GOLEM]) {
+                               if (in_sight)
+                                   pline("%s falls to pieces!", Monnam(mtmp));
+                               else if(mtmp->mtame)
+                                   pline("May %s rust in peace.",
+                                                               mon_nam(mtmp));
+                               mondied(mtmp);
+                               if (mtmp->mhp <= 0)
+                                       trapkilled = TRUE;
+                       } else if (mptr == &mons[PM_GREMLIN] && rn2(3)) {
+                               (void)split_mon(mtmp, (struct monst *)0);
+                       }
+                       break;
+                   }
+               case FIRE_TRAP:
+ mfiretrap:
+                       if (in_sight)
+                           pline("A %s erupts from the %s under %s!",
+                                 tower_of_flame,
+                                 surface(mtmp->mx,mtmp->my), mon_nam(mtmp));
+                       else if (see_it)  /* evidently `mtmp' is invisible */
+                           You("see a %s erupt from the %s!",
+                               tower_of_flame, surface(mtmp->mx,mtmp->my));
+
+                       if (resists_fire(mtmp)) {
+                           if (in_sight) {
+                               shieldeff(mtmp->mx,mtmp->my);
+                               pline("%s is uninjured.", Monnam(mtmp));
+                           }
+                       } else {
+                           int num = d(2,4), alt;
+                           boolean immolate = FALSE;
+
+                           /* paper burns very fast, assume straw is tightly
+                            * packed and burns a bit slower */
+                           switch (monsndx(mtmp->data)) {
+                           case PM_PAPER_GOLEM:   immolate = TRUE;
+                                                  alt = mtmp->mhpmax; break;
+                           case PM_STRAW_GOLEM:   alt = mtmp->mhpmax / 2; break;
+                           case PM_WOOD_GOLEM:    alt = mtmp->mhpmax / 4; break;
+                           case PM_LEATHER_GOLEM: alt = mtmp->mhpmax / 8; break;
+                           default: alt = 0; break;
+                           }
+                           if (alt > num) num = alt;
+
+                           if (thitm(0, mtmp, (struct obj *)0, num, immolate))
+                               trapkilled = TRUE;
+                           else
+                               /* we know mhp is at least `num' below mhpmax,
+                                  so no (mhp > mhpmax) check is needed here */
+                               mtmp->mhpmax -= rn2(num + 1);
+                       }
+                       if (burnarmor(mtmp) || rn2(3)) {
+                           (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE);
+                           (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE);
+                           (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE);
+                       }
+                       if (burn_floor_paper(mtmp->mx, mtmp->my, see_it, FALSE) &&
+                               !see_it && distu(mtmp->mx, mtmp->my) <= 3*3)
+                           You("smell smoke.");
+                       if (is_ice(mtmp->mx,mtmp->my))
+                           melt_ice(mtmp->mx,mtmp->my);
+                       if (see_it) seetrap(trap);
+                       break;
+
+               case PIT:
+               case SPIKED_PIT:
+                       fallverb = "falls";
+                       if (is_flyer(mptr) || is_floater(mptr) ||
+                               (mtmp->wormno && count_wsegs(mtmp) > 5) ||
+                               is_clinger(mptr)) {
+                           if (!inescapable) break;    /* avoids trap */
+                           fallverb = "is dragged";    /* sokoban pit */
+                       }
+                       if (!passes_walls(mptr))
+                           mtmp->mtrapped = 1;
+                       if (in_sight) {
+                           pline("%s %s into %s pit!",
+                                 Monnam(mtmp), fallverb,
+                                 a_your[trap->madeby_u]);
+                           if (mptr == &mons[PM_PIT_VIPER] || mptr == &mons[PM_PIT_FIEND])
+                               pline("How pitiful.  Isn't that the pits?");
+                           seetrap(trap);
+                       }
+                       mselftouch(mtmp, "Falling, ", FALSE);
+                       if (mtmp->mhp <= 0 ||
+                               thitm(0, mtmp, (struct obj *)0,
+                                     rnd((tt == PIT) ? 6 : 10), FALSE))
+                           trapkilled = TRUE;
+                       break;
+               case HOLE:
+               case TRAPDOOR:
+                       if (!Can_fall_thru(&u.uz)) {
+                        impossible("mintrap: %ss cannot exist on this level.",
+                                   defsyms[trap_to_defsym(tt)].explanation);
+                           break;      /* don't activate it after all */
+                       }
+                       if (is_flyer(mptr) || is_floater(mptr) ||
+                               mptr == &mons[PM_WUMPUS] ||
+                               (mtmp->wormno && count_wsegs(mtmp) > 5) ||
+                               mptr->msize >= MZ_HUGE) {
+                           if (inescapable) {  /* sokoban hole */
+                               if (in_sight) {
+                                   pline("%s seems to be yanked down!",
+                                         Monnam(mtmp));
+                                   /* suppress message in mlevel_tele_trap() */
+                                   in_sight = FALSE;
+                                   seetrap(trap);
+                               }
+                           } else
+                               break;
+                       }
+                       /* Fall through */
+               case LEVEL_TELEP:
+               case MAGIC_PORTAL:
+                       {
+                           int mlev_res;
+                           mlev_res = mlevel_tele_trap(mtmp, trap,
+                                                       inescapable, in_sight);
+                           if (mlev_res) return(mlev_res);
+                       }
+                       break;
+
+               case TELEP_TRAP:
+                       mtele_trap(mtmp, trap, in_sight);
+                       break;
+
+               case WEB:
+                       /* Monster in a web. */
+                       if (webmaker(mptr)) break;
+                       if (amorphous(mptr) || is_whirly(mptr) || unsolid(mptr)){
+                           if(acidic(mptr) ||
+                              mptr == &mons[PM_GELATINOUS_CUBE] ||
+                              mptr == &mons[PM_FIRE_ELEMENTAL]) {
+                               if (in_sight)
+                                   pline("%s %s %s spider web!",
+                                         Monnam(mtmp),
+                                         (mptr == &mons[PM_FIRE_ELEMENTAL]) ?
+                                           "burns" : "dissolves",
+                                         a_your[trap->madeby_u]);
+                               deltrap(trap);
+                               newsym(mtmp->mx, mtmp->my);
+                               break;
+                           }
+                           if (in_sight) {
+                               pline("%s flows through %s spider web.",
+                                     Monnam(mtmp),
+                                     a_your[trap->madeby_u]);
+                               seetrap(trap);
+                           }
+                           break;
+                       }
+                       tear_web = FALSE;
+                       switch (monsndx(mptr)) {
+                           case PM_OWLBEAR: /* Eric Backus */
+                           case PM_BUGBEAR:
+                               if (!in_sight) {
+                                   You_hear("the roaring of a confused bear!");
+                                   mtmp->mtrapped = 1;
+                                   break;
+                               }
+                               /* fall though */
+                           default:
+                               if (mptr->mlet == S_GIANT ||
+                                   (mptr->mlet == S_DRAGON &&
+                                       extra_nasty(mptr)) || /* excl. babies */
+                                   (mtmp->wormno && count_wsegs(mtmp) > 5)) {
+                                   tear_web = TRUE;
+                               } else if (in_sight) {
+                                   pline("%s is caught in %s spider web.",
+                                         Monnam(mtmp),
+                                         a_your[trap->madeby_u]);
+                                   seetrap(trap);
+                               }
+                               mtmp->mtrapped = tear_web ? 0 : 1;
+                               break;
+                           /* this list is fairly arbitrary; it deliberately
+                              excludes wumpus & giant/ettin zombies/mummies */
+                           case PM_TITANOTHERE:
+                           case PM_BALUCHITHERIUM:
+                           case PM_PURPLE_WORM:
+                           case PM_JABBERWOCK:
+                           case PM_IRON_GOLEM:
+                           case PM_BALROG:
+                           case PM_KRAKEN:
+                           case PM_MASTODON:
+                               tear_web = TRUE;
+                               break;
+                       }
+                       if (tear_web) {
+                           if (in_sight)
+                               pline("%s tears through %s spider web!",
+                                     Monnam(mtmp), a_your[trap->madeby_u]);
+                           deltrap(trap);
+                           newsym(mtmp->mx, mtmp->my);
+                       }
+                       break;
+
+               case STATUE_TRAP:
+                       break;
+
+               case MAGIC_TRAP:
+                       /* A magic trap.  Monsters usually immune. */
+                       if (!rn2(21)) goto mfiretrap;
+                       break;
+               case ANTI_MAGIC:
+                       break;
+
+               case LANDMINE:
+                       if(rn2(3))
+                               break; /* monsters usually don't set it off */
+                       if(is_flyer(mptr)) {
+                               boolean already_seen = trap->tseen;
+                               if (in_sight && !already_seen) {
+       pline("A trigger appears in a pile of soil below %s.", mon_nam(mtmp));
+                                       seetrap(trap);
+                               }
+                               if (rn2(3)) break;
+                               if (in_sight) {
+                                       newsym(mtmp->mx, mtmp->my);
+                                       pline_The("air currents set %s off!",
+                                         already_seen ? "a land mine" : "it");
+                               }
+                       } else if(in_sight) {
+                           newsym(mtmp->mx, mtmp->my);
+                           pline("KAABLAMM!!!  %s triggers %s land mine!",
+                               Monnam(mtmp), a_your[trap->madeby_u]);
+                       }
+                       if (!in_sight)
+                               pline("Kaablamm!  You hear an explosion in the distance!");
+                       blow_up_landmine(trap);
+                       if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE))
+                               trapkilled = TRUE;
+                       else {
+                               /* monsters recursively fall into new pit */
+                               if (mintrap(mtmp) == 2) trapkilled=TRUE;
+                       }
+                       /* a boulder may fill the new pit, crushing monster */
+                       fill_pit(trap->tx, trap->ty);
+                       if (mtmp->mhp <= 0) trapkilled = TRUE;
+                       if (unconscious()) {
+                               multi = -1;
+                               nomovemsg="The explosion awakens you!";
+                       }
+                       break;
+
+               case POLY_TRAP:
+                   if (resists_magm(mtmp)) {
+                       shieldeff(mtmp->mx, mtmp->my);
+                   } else if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) {
+                       (void) newcham(mtmp, (struct permonst *)0,
+                                      FALSE, FALSE);
+                       if (in_sight) seetrap(trap);
+                   }
+                   break;
+
+               case ROLLING_BOULDER_TRAP:
+                   if (!is_flyer(mptr)) {
+                       int style = ROLL | (in_sight ? 0 : LAUNCH_UNSEEN);
+
+                       newsym(mtmp->mx,mtmp->my);
+                       if (in_sight)
+                           pline("Click! %s triggers %s.", Monnam(mtmp),
+                                 trap->tseen ?
+                                 "a rolling boulder trap" :
+                                 something);
+                       if (launch_obj(BOULDER, trap->launch.x, trap->launch.y,
+                               trap->launch2.x, trap->launch2.y, style)) {
+                           if (in_sight) trap->tseen = TRUE;
+                           if (mtmp->mhp <= 0) trapkilled = TRUE;
+                       } else {
+                           deltrap(trap);
+                           newsym(mtmp->mx,mtmp->my);
+                       }
+                   }
+                   break;
+
+               default:
+                       impossible("Some monster encountered a strange trap of type %d.", tt);
+           }
+       }
+       if(trapkilled) return 2;
+       return mtmp->mtrapped;
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+/* Combine cockatrice checks into single functions to avoid repeating code. */
+void
+instapetrify(str)
+const char *str;
+{
+       if (Stone_resistance) return;
+       if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
+           return;
+       You("turn to stone...");
+       killer_format = KILLED_BY;
+       killer = str;
+       done(STONING);
+}
+
+void
+minstapetrify(mon,byplayer)
+struct monst *mon;
+boolean byplayer;
+{
+       if (resists_ston(mon)) return;
+       if (poly_when_stoned(mon->data)) {
+               mon_to_stone(mon);
+               return;
+       }
+
+       /* give a "<mon> is slowing down" message and also remove
+          intrinsic speed (comparable to similar effect on the hero) */
+       mon_adjust_speed(mon, -3, (struct obj *)0);
+
+       if (cansee(mon->mx, mon->my))
+               pline("%s turns to stone.", Monnam(mon));
+       if (byplayer) {
+               stoned = TRUE;
+               xkilled(mon,0);
+       } else monstone(mon);
+}
+
+void
+selftouch(arg)
+const char *arg;
+{
+       char kbuf[BUFSZ];
+
+       if(uwep && uwep->otyp == CORPSE && touch_petrifies(&mons[uwep->corpsenm])
+                       && !Stone_resistance) {
+               pline("%s touch the %s corpse.", arg,
+                       mons[uwep->corpsenm].mname);
+               Sprintf(kbuf, "%s corpse", an(mons[uwep->corpsenm].mname));
+               instapetrify(kbuf);
+       }
+       /* Or your secondary weapon, if wielded */
+       if(u.twoweap && uswapwep && uswapwep->otyp == CORPSE &&
+                       touch_petrifies(&mons[uswapwep->corpsenm]) && !Stone_resistance){
+               pline("%s touch the %s corpse.", arg,
+                       mons[uswapwep->corpsenm].mname);
+               Sprintf(kbuf, "%s corpse", an(mons[uswapwep->corpsenm].mname));
+               instapetrify(kbuf);
+       }
+}
+
+void
+mselftouch(mon,arg,byplayer)
+struct monst *mon;
+const char *arg;
+boolean byplayer;
+{
+       struct obj *mwep = MON_WEP(mon);
+
+       if (mwep && mwep->otyp == CORPSE && touch_petrifies(&mons[mwep->corpsenm])) {
+               if (cansee(mon->mx, mon->my)) {
+                       pline("%s%s touches the %s corpse.",
+                           arg ? arg : "", arg ? mon_nam(mon) : Monnam(mon),
+                           mons[mwep->corpsenm].mname);
+               }
+               minstapetrify(mon, byplayer);
+       }
+}
+
+void
+float_up()
+{
+       if(u.utrap) {
+               if(u.utraptype == TT_PIT) {
+                       u.utrap = 0;
+                       You("float up, out of the pit!");
+                       vision_full_recalc = 1; /* vision limits change */
+                       fill_pit(u.ux, u.uy);
+               } else if (u.utraptype == TT_INFLOOR) {
+                       Your("body pulls upward, but your %s are still stuck.",
+                            makeplural(body_part(LEG)));
+               } else {
+                       You("float up, only your %s is still stuck.",
+                               body_part(LEG));
+               }
+       }
+       else if(Is_waterlevel(&u.uz))
+               pline("It feels as though you've lost some weight.");
+       else if(u.uinwater)
+               spoteffects(TRUE);
+       else if(u.uswallow)
+               You(is_animal(u.ustuck->data) ?
+                       "float away from the %s."  :
+                       "spiral up into %s.",
+                   is_animal(u.ustuck->data) ?
+                       surface(u.ux, u.uy) :
+                       mon_nam(u.ustuck));
+       else if (Hallucination)
+               pline("Up, up, and awaaaay!  You're walking on air!");
+       else if(Is_airlevel(&u.uz))
+               You("gain control over your movements.");
+       else
+               You("start to float in the air!");
+#ifdef STEED
+       if (u.usteed && !is_floater(u.usteed->data) &&
+                                               !is_flyer(u.usteed->data)) {
+           if (Lev_at_will)
+               pline("%s magically floats up!", Monnam(u.usteed));
+           else {
+               You("cannot stay on %s.", mon_nam(u.usteed));
+               dismount_steed(DISMOUNT_GENERIC);
+           }
+       }
+#endif
+       return;
+}
+
+void
+fill_pit(x, y)
+int x, y;
+{
+       struct obj *otmp;
+       struct trap *t;
+
+       if ((t = t_at(x, y)) &&
+           ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)) &&
+           (otmp = sobj_at(BOULDER, x, y))) {
+               obj_extract_self(otmp);
+               (void) flooreffects(otmp, x, y, "settle");
+       }
+}
+
+int
+float_down(hmask, emask)
+long hmask, emask;     /* might cancel timeout */
+{
+       register struct trap *trap = (struct trap *)0;
+       d_level current_dungeon_level;
+       boolean no_msg = FALSE;
+
+       HLevitation &= ~hmask;
+       ELevitation &= ~emask;
+       if(Levitation) return(0); /* maybe another ring/potion/boots */
+       if(u.uswallow) {
+           You("float down, but you are still %s.",
+               is_animal(u.ustuck->data) ? "swallowed" : "engulfed");
+           return(1);
+       }
+
+       if (Punished && !carried(uball) &&
+           (is_pool(uball->ox, uball->oy) ||
+            ((trap = t_at(uball->ox, uball->oy)) &&
+             ((trap->ttyp == PIT) || (trap->ttyp == SPIKED_PIT) ||
+              (trap->ttyp == TRAPDOOR) || (trap->ttyp == HOLE))))) {
+                       u.ux0 = u.ux;
+                       u.uy0 = u.uy;
+                       u.ux = uball->ox;
+                       u.uy = uball->oy;
+                       movobj(uchain, uball->ox, uball->oy);
+                       newsym(u.ux0, u.uy0);
+                       vision_full_recalc = 1; /* in case the hero moved. */
+       }
+       /* check for falling into pool - added by GAN 10/20/86 */
+       if(!Flying) {
+               if (!u.uswallow && u.ustuck) {
+                       if (sticks(youmonst.data))
+                               You("aren't able to maintain your hold on %s.",
+                                       mon_nam(u.ustuck));
+                       else
+                               pline("Startled, %s can no longer hold you!",
+                                       mon_nam(u.ustuck));
+                       u.ustuck = 0;
+               }
+               /* kludge alert:
+                * drown() and lava_effects() print various messages almost
+                * every time they're called which conflict with the "fall
+                * into" message below.  Thus, we want to avoid printing
+                * confusing, duplicate or out-of-order messages.
+                * Use knowledge of the two routines as a hack -- this
+                * should really be handled differently -dlc
+                */
+               if(is_pool(u.ux,u.uy) && !Wwalking && !Swimming && !u.uinwater)
+                       no_msg = drown();
+
+               if(is_lava(u.ux,u.uy)) {
+                       (void) lava_effects();
+                       no_msg = TRUE;
+               }
+       }
+       if (!trap) {
+           trap = t_at(u.ux,u.uy);
+           if(Is_airlevel(&u.uz))
+               You("begin to tumble in place.");
+           else if (Is_waterlevel(&u.uz) && !no_msg)
+               You_feel("heavier.");
+           /* u.uinwater msgs already in spoteffects()/drown() */
+           else if (!u.uinwater && !no_msg) {
+#ifdef STEED
+               if (!(emask & W_SADDLE))
+#endif
+               {
+                   boolean sokoban_trap = (In_sokoban(&u.uz) && trap);
+                   if (Hallucination)
+                       pline("Bummer!  You've %s.",
+                             is_pool(u.ux,u.uy) ?
+                             "splashed down" : sokoban_trap ? "crashed" :
+                             "hit the ground");
+                   else {
+                       if (!sokoban_trap)
+                           You("float gently to the %s.",
+                               surface(u.ux, u.uy));
+                       else {
+                           /* Justification elsewhere for Sokoban traps
+                            * is based on air currents. This is
+                            * consistent with that.
+                            * The unexpected additional force of the
+                            * air currents once leviation
+                            * ceases knocks you off your feet.
+                            */
+                           You("fall over.");
+                           losehp(rnd(2), "dangerous winds", KILLED_BY);
+#ifdef STEED
+                           if (u.usteed) dismount_steed(DISMOUNT_FELL);
+#endif
+                           selftouch("As you fall, you");
+                       }
+                   }
+               }
+           }
+       }
+
+       /* can't rely on u.uz0 for detecting trap door-induced level change;
+          it gets changed to reflect the new level before we can check it */
+       assign_level(&current_dungeon_level, &u.uz);
+
+       if(trap)
+               switch(trap->ttyp) {
+               case STATUE_TRAP:
+                       break;
+               case HOLE:
+               case TRAPDOOR:
+                       if(!Can_fall_thru(&u.uz) || u.ustuck)
+                               break;
+                       /* fall into next case */
+               default:
+                       if (!u.utrap) /* not already in the trap */
+                               dotrap(trap, 0);
+       }
+
+       if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !u.uswallow &&
+               /* falling through trap door calls goto_level,
+                  and goto_level does its own pickup() call */
+               on_level(&u.uz, &current_dungeon_level))
+           (void) pickup(1);
+       return 1;
+}
+
+STATIC_OVL void
+dofiretrap(box)
+struct obj *box;       /* null for floor trap */
+{
+       boolean see_it = !Blind;
+       int num, alt;
+
+/* Bug: for box case, the equivalent of burn_floor_paper() ought
+ * to be done upon its contents.
+ */
+
+       if ((box && !carried(box)) ? is_pool(box->ox, box->oy) : Underwater) {
+           pline("A cascade of steamy bubbles erupts from %s!",
+                   the(box ? xname(box) : surface(u.ux,u.uy)));
+           if (Fire_resistance) You("are uninjured.");
+           else losehp(rnd(3), "boiling water", KILLED_BY);
+           return;
+       }
+       pline("A %s %s from %s!", tower_of_flame,
+             box ? "bursts" : "erupts",
+             the(box ? xname(box) : surface(u.ux,u.uy)));
+       if (Fire_resistance) {
+           shieldeff(u.ux, u.uy);
+           num = rn2(2);
+       } else if (Upolyd) {
+           num = d(2,4);
+           switch (u.umonnum) {
+           case PM_PAPER_GOLEM:   alt = u.mhmax; break;
+           case PM_STRAW_GOLEM:   alt = u.mhmax / 2; break;
+           case PM_WOOD_GOLEM:    alt = u.mhmax / 4; break;
+           case PM_LEATHER_GOLEM: alt = u.mhmax / 8; break;
+           default: alt = 0; break;
+           }
+           if (alt > num) num = alt;
+           if (u.mhmax > mons[u.umonnum].mlevel)
+               u.mhmax -= rn2(min(u.mhmax,num + 1)), flags.botl = 1;
+       } else {
+           num = d(2,4);
+           if (u.uhpmax > u.ulevel)
+               u.uhpmax -= rn2(min(u.uhpmax,num + 1)), flags.botl = 1;
+       }
+       if (!num)
+           You("are uninjured.");
+       else
+           losehp(num, tower_of_flame, KILLED_BY_AN);
+       burn_away_slime();
+
+       if (burnarmor(&youmonst) || rn2(3)) {
+           destroy_item(SCROLL_CLASS, AD_FIRE);
+           destroy_item(SPBOOK_CLASS, AD_FIRE);
+           destroy_item(POTION_CLASS, AD_FIRE);
+       }
+       if (!box && burn_floor_paper(u.ux, u.uy, see_it, TRUE) && !see_it)
+           You("smell paper burning.");
+       if (is_ice(u.ux, u.uy))
+           melt_ice(u.ux, u.uy);
+}
+
+STATIC_OVL void
+domagictrap()
+{
+       register int fate = rnd(20);
+
+       /* What happened to the poor sucker? */
+
+       if (fate < 10) {
+         /* Most of the time, it creates some monsters. */
+         register int cnt = rnd(4);
+
+         if (!resists_blnd(&youmonst)) {
+               You("are momentarily blinded by a flash of light!");
+               make_blinded((long)rn1(5,10),FALSE);
+               if (!Blind) Your(vision_clears);
+         } else if (!Blind) {
+               You("see a flash of light!");
+         }  else
+               You_hear("a deafening roar!");
+         while(cnt--)
+               (void) makemon((struct permonst *) 0, u.ux, u.uy, NO_MM_FLAGS);
+       }
+       else
+         switch (fate) {
+
+            case 10:
+            case 11:
+                     /* sometimes nothing happens */
+                       break;
+            case 12: /* a flash of fire */
+                       dofiretrap((struct obj *)0);
+                       break;
+
+            /* odd feelings */
+            case 13:   pline("A shiver runs up and down your %s!",
+                             body_part(SPINE));
+                       break;
+            case 14:   You_hear(Hallucination ?
+                               "the moon howling at you." :
+                               "distant howling.");
+                       break;
+            case 15:   if (on_level(&u.uz, &qstart_level))
+                           You_feel("%slike the prodigal son.",
+                             (flags.female || (Upolyd && is_neuter(youmonst.data))) ?
+                                    "oddly " : "");
+                       else
+                           You("suddenly yearn for %s.",
+                               Hallucination ? "Cleveland" :
+                           (In_quest(&u.uz) || at_dgn_entrance("The Quest")) ?
+                                               "your nearby homeland" :
+                                               "your distant homeland");
+                       break;
+            case 16:   Your("pack shakes violently!");
+                       break;
+            case 17:   You(Hallucination ?
+                               "smell hamburgers." :
+                               "smell charred flesh.");
+                       break;
+            case 18:   You_feel("tired.");
+                       break;
+
+            /* very occasionally something nice happens. */
+
+            case 19:
+                   /* tame nearby monsters */
+                  {   register int i,j;
+                      register struct monst *mtmp;
+
+                      (void) adjattrib(A_CHA,1,FALSE);
+                      for(i = -1; i <= 1; i++) for(j = -1; j <= 1; j++) {
+                          if(!isok(u.ux+i, u.uy+j)) continue;
+                          mtmp = m_at(u.ux+i, u.uy+j);
+                          if(mtmp)
+                              (void) tamedog(mtmp, (struct obj *)0);
+                      }
+                      break;
+                  }
+
+            case 20:
+                   /* uncurse stuff */
+                  {    struct obj pseudo;
+                       long save_conf = HConfusion;
+
+                       pseudo = zeroobj;   /* neither cursed nor blessed */
+                       pseudo.otyp = SCR_REMOVE_CURSE;
+                       HConfusion = 0L;
+                       (void) seffects(&pseudo);
+                       HConfusion = save_conf;
+                       break;
+                  }
+            default: break;
+         }
+}
+
+/*
+ * Scrolls, spellbooks, potions, and flammable items
+ * may get affected by the fire.
+ *
+ * Return number of objects destroyed. --ALI
+ */
+int
+fire_damage(chain, force, here, x, y)
+struct obj *chain;
+boolean force, here;
+xchar x, y;
+{
+    int chance;
+    struct obj *obj, *otmp, *nobj, *ncobj;
+    int retval = 0;
+    int in_sight = !Blind && couldsee(x, y);   /* Don't care if it's lit */
+    int dindx;
+
+    for (obj = chain; obj; obj = nobj) {
+       nobj = here ? obj->nexthere : obj->nobj;
+
+       /* object might light in a controlled manner */
+       if (catch_lit(obj))
+           continue;
+
+       if (Is_container(obj)) {
+           switch (obj->otyp) {
+           case ICE_BOX:
+               continue;               /* Immune */
+               /*NOTREACHED*/
+               break;
+           case CHEST:
+               chance = 40;
+               break;
+           case LARGE_BOX:
+               chance = 30;
+               break;
+           default:
+               chance = 20;
+               break;
+           }
+           if (!force && (Luck + 5) > rn2(chance))
+               continue;
+           /* Container is burnt up - dump contents out */
+           if (in_sight) pline("%s catches fire and burns.", Yname2(obj));
+           if (Has_contents(obj)) {
+               if (in_sight) pline("Its contents fall out.");
+               for (otmp = obj->cobj; otmp; otmp = ncobj) {
+                   ncobj = otmp->nobj;
+                   obj_extract_self(otmp);
+                   if (!flooreffects(otmp, x, y, ""))
+                       place_object(otmp, x, y);
+               }
+           }
+           delobj(obj);
+           retval++;
+       } else if (!force && (Luck + 5) > rn2(20)) {
+           /*  chance per item of sustaining damage:
+            *  max luck (full moon):    5%
+            *  max luck (elsewhen):    10%
+            *  avg luck (Luck==0):     75%
+            *  awful luck (Luck<-4):  100%
+            */
+           continue;
+       } else if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) {
+           if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
+               continue;
+           if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
+               if (in_sight) pline("Smoke rises from %s.", the(xname(obj)));
+               continue;
+           }
+           dindx = (obj->oclass == SCROLL_CLASS) ? 2 : 3;
+           if (in_sight)
+               pline("%s %s.", Yname2(obj), (obj->quan > 1) ?
+                     destroy_strings[dindx*3 + 1] : destroy_strings[dindx*3]);
+           delobj(obj);
+           retval++;
+       } else if (obj->oclass == POTION_CLASS) {
+           dindx = 1;
+           if (in_sight)
+               pline("%s %s.", Yname2(obj), (obj->quan > 1) ?
+                     destroy_strings[dindx*3 + 1] : destroy_strings[dindx*3]);
+           delobj(obj);
+           retval++;
+       } else if (is_flammable(obj) && obj->oeroded < MAX_ERODE &&
+                  !(obj->oerodeproof || (obj->blessed && !rnl(4)))) {
+           if (in_sight) {
+               pline("%s %s%s.", Yname2(obj), otense(obj, "burn"),
+                     obj->oeroded+1 == MAX_ERODE ? " completely" :
+                     obj->oeroded ? " further" : "");
+           }
+           obj->oeroded++;
+       }
+    }
+
+    if (retval && !in_sight)
+       You("smell smoke.");
+    return retval;
+}
+
+void
+water_damage(obj, force, here)
+register struct obj *obj;
+register boolean force, here;
+{
+       struct obj *otmp;
+
+       /* Scrolls, spellbooks, potions, weapons and
+          pieces of armor may get affected by the water */
+       for (; obj; obj = otmp) {
+               otmp = here ? obj->nexthere : obj->nobj;
+
+               (void) snuff_lit(obj);
+
+               if(obj->otyp == CAN_OF_GREASE && obj->spe > 0) {
+                       continue;
+               } else if(obj->greased) {
+                       if (force || !rn2(2)) obj->greased = 0;
+               } else if(Is_container(obj) && !Is_box(obj) &&
+                       (obj->otyp != OILSKIN_SACK || (obj->cursed && !rn2(3)))) {
+                       water_damage(obj->cobj, force, FALSE);
+               } else if (!force && (Luck + 5) > rn2(20)) {
+                       /*  chance per item of sustaining damage:
+                        *      max luck (full moon):    5%
+                        *      max luck (elsewhen):    10%
+                        *      avg luck (Luck==0):     75%
+                        *      awful luck (Luck<-4):  100%
+                        */
+                       continue;
+               } else if (obj->oclass == SCROLL_CLASS) {
+#ifdef MAIL
+                   if (obj->otyp != SCR_MAIL)
+#endif
+                   {
+                       obj->otyp = SCR_BLANK_PAPER;
+                       obj->spe = 0;
+                   }
+               } else if (obj->oclass == SPBOOK_CLASS) {
+                       if (obj->otyp == SPE_BOOK_OF_THE_DEAD)
+                               pline("Steam rises from %s.", the(xname(obj)));
+                       else obj->otyp = SPE_BLANK_PAPER;
+               } else if (obj->oclass == POTION_CLASS) {
+                       if (obj->otyp == POT_ACID) {
+                               /* damage player/monster? */
+                               pline("A potion explodes!");
+                               delobj(obj);
+                               continue;
+                       } else if (obj->odiluted) {
+                               obj->otyp = POT_WATER;
+                               obj->blessed = obj->cursed = 0;
+                               obj->odiluted = 0;
+                       } else if (obj->otyp != POT_WATER)
+                               obj->odiluted++;
+               } else if (is_rustprone(obj) && obj->oeroded < MAX_ERODE &&
+                         !(obj->oerodeproof || (obj->blessed && !rnl(4)))) {
+                       /* all metal stuff and armor except (body armor
+                          protected by oilskin cloak) */
+                       if(obj->oclass != ARMOR_CLASS || obj != uarm ||
+                          !uarmc || uarmc->otyp != OILSKIN_CLOAK ||
+                          (uarmc->cursed && !rn2(3)))
+                               obj->oeroded++;
+               }
+       }
+}
+
+/*
+ * This function is potentially expensive - rolling
+ * inventory list multiple times.  Luckily it's seldom needed.
+ * Returns TRUE if disrobing made player unencumbered enough to
+ * crawl out of the current predicament.
+ */
+STATIC_OVL boolean
+emergency_disrobe(lostsome)
+boolean *lostsome;
+{
+       int invc = inv_cnt();
+
+       while (near_capacity() > (Punished ? UNENCUMBERED : SLT_ENCUMBER)) {
+           register struct obj *obj, *otmp = (struct obj *)0;
+           register int i;
+
+           /* Pick a random object */
+           if (invc > 0) {
+               i = rn2(invc);
+               for (obj = invent; obj; obj = obj->nobj) {
+                   /*
+                    * Undroppables are: body armor, boots, gloves,
+                    * amulets, and rings because of the time and effort
+                    * in removing them + loadstone and other cursed stuff
+                    * for obvious reasons.
+                    */
+                   if (!((obj->otyp == LOADSTONE && obj->cursed) ||
+                         obj == uamul || obj == uleft || obj == uright ||
+                         obj == ublindf || obj == uarm || obj == uarmc ||
+                         obj == uarmg || obj == uarmf ||
+#ifdef TOURIST
+                         obj == uarmu ||
+#endif
+                         (obj->cursed && (obj == uarmh || obj == uarms)) ||
+                         welded(obj)))
+                       otmp = obj;
+                   /* reached the mark and found some stuff to drop? */
+                   if (--i < 0 && otmp) break;
+
+                   /* else continue */
+               }
+           }
+#ifndef GOLDOBJ
+           if (!otmp) {
+               /* Nothing available left to drop; try gold */
+               if (u.ugold) {
+                   pline("In desperation, you drop your purse.");
+                   /* Hack: gold is not in the inventory, so make a gold object
+                    * and put it at the head of the inventory list.
+                    */
+                   obj = mkgoldobj(u.ugold);    /* removes from u.ugold */
+                   obj->in_use = TRUE;
+                   u.ugold = obj->quan;         /* put the gold back */
+                   assigninvlet(obj);           /* might end up as NOINVSYM */
+                   obj->nobj = invent;
+                   invent = obj;
+                   *lostsome = TRUE;
+                   dropx(obj);
+                   continue;                    /* Try again */
+               }
+               /* We can't even drop gold! */
+               return (FALSE);
+           }
+#else
+           if (!otmp) return (FALSE); /* nothing to drop! */   
+#endif
+           if (otmp->owornmask) remove_worn_item(otmp, FALSE);
+           *lostsome = TRUE;
+           dropx(otmp);
+           invc--;
+       }
+       return(TRUE);
+}
+
+/*
+ *  return(TRUE) == player relocated
+ */
+boolean
+drown()
+{
+       boolean inpool_ok = FALSE, crawl_ok;
+       int i, x, y;
+
+       /* happily wading in the same contiguous pool */
+       if (u.uinwater && is_pool(u.ux-u.dx,u.uy-u.dy) &&
+           (Swimming || Amphibious)) {
+               /* water effects on objects every now and then */
+               if (!rn2(5)) inpool_ok = TRUE;
+               else return(FALSE);
+       }
+
+       if (!u.uinwater) {
+           You("%s into the water%c",
+               Is_waterlevel(&u.uz) ? "plunge" : "fall",
+               Amphibious || Swimming ? '.' : '!');
+           if (!Swimming && !Is_waterlevel(&u.uz))
+                   You("sink like %s.",
+                       Hallucination ? "the Titanic" : "a rock");
+       }
+
+       water_damage(invent, FALSE, FALSE);
+
+       if (u.umonnum == PM_GREMLIN && rn2(3))
+           (void)split_mon(&youmonst, (struct monst *)0);
+       else if (u.umonnum == PM_IRON_GOLEM) {
+           You("rust!");
+           i = d(2,6);
+           if (u.mhmax > i) u.mhmax -= i;
+           losehp(i, "rusting away", KILLED_BY);
+       }
+       if (inpool_ok) return(FALSE);
+
+       if ((i = number_leashed()) > 0) {
+               pline_The("leash%s slip%s loose.",
+                       (i > 1) ? "es" : "",
+                       (i > 1) ? "" : "s");
+               unleash_all();
+       }
+
+       if (Amphibious || Swimming) {
+               if (Amphibious) {
+                       if (flags.verbose)
+                               pline("But you aren't drowning.");
+                       if (!Is_waterlevel(&u.uz)) {
+                               if (Hallucination)
+                                       Your("keel hits the bottom.");
+                               else
+                                       You("touch bottom.");
+                       }
+               }
+               if (Punished) {
+                       unplacebc();
+                       placebc();
+               }
+               vision_recalc(2);       /* unsee old position */
+               u.uinwater = 1;
+               under_water(1);
+               vision_full_recalc = 1;
+               return(FALSE);
+       }
+       if ((Teleportation || can_teleport(youmonst.data)) &&
+                   !u.usleep && (Teleport_control || rn2(3) < Luck+2)) {
+               You("attempt a teleport spell.");       /* utcsri!carroll */
+               if (!level.flags.noteleport) {
+                       (void) dotele();
+                       if(!is_pool(u.ux,u.uy))
+                               return(TRUE);
+               } else pline_The("attempted teleport spell fails.");
+       }
+#ifdef STEED
+       if (u.usteed) {
+               dismount_steed(DISMOUNT_GENERIC);
+               if(!is_pool(u.ux,u.uy))
+                       return(TRUE);
+       }
+#endif
+       crawl_ok = FALSE;
+       x = y = 0;              /* lint suppression */
+       /* if sleeping, wake up now so that we don't crawl out of water
+          while still asleep; we can't do that the same way that waking
+          due to combat is handled; note unmul() clears u.usleep */
+       if (u.usleep) unmul("Suddenly you wake up!");
+       /* can't crawl if unable to move (crawl_ok flag stays false) */
+       if (multi < 0 || (Upolyd && !youmonst.data->mmove)) goto crawl;
+       /* look around for a place to crawl to */
+       for (i = 0; i < 100; i++) {
+               x = rn1(3,u.ux - 1);
+               y = rn1(3,u.uy - 1);
+               if (goodpos(x, y, &youmonst, 0)) {
+                       crawl_ok = TRUE;
+                       goto crawl;
+               }
+       }
+       /* one more scan */
+       for (x = u.ux - 1; x <= u.ux + 1; x++)
+               for (y = u.uy - 1; y <= u.uy + 1; y++)
+                       if (goodpos(x, y, &youmonst, 0)) {
+                               crawl_ok = TRUE;
+                               goto crawl;
+                       }
+ crawl:
+       if (crawl_ok) {
+               boolean lost = FALSE;
+               /* time to do some strip-tease... */
+               boolean succ = Is_waterlevel(&u.uz) ? TRUE :
+                               emergency_disrobe(&lost);
+
+               You("try to crawl out of the water.");
+               if (lost)
+                       You("dump some of your gear to lose weight...");
+               if (succ) {
+                       pline("Pheew!  That was close.");
+                       teleds(x,y,TRUE);
+                       return(TRUE);
+               }
+               /* still too much weight */
+               pline("But in vain.");
+       }
+       u.uinwater = 1;
+       You("drown.");
+       killer_format = KILLED_BY_AN;
+       killer = (levl[u.ux][u.uy].typ == POOL || Is_medusa_level(&u.uz)) ?
+           "pool of water" : "moat";
+       done(DROWNING);
+       /* oops, we're still alive.  better get out of the water. */
+       while (!safe_teleds(TRUE)) {
+               pline("You're still drowning.");
+               done(DROWNING);
+       }
+       if (u.uinwater) {
+           u.uinwater = 0;
+           You("find yourself back %s.", Is_waterlevel(&u.uz) ?
+               "in an air bubble" : "on land");
+       }
+       return(TRUE);
+}
+
+void
+drain_en(n)
+register int n;
+{
+       if (!u.uenmax) return;
+       You_feel("your magical energy drain away!");
+       u.uen -= n;
+       if(u.uen < 0)  {
+               u.uenmax += u.uen;
+               if(u.uenmax < 0) u.uenmax = 0;
+               u.uen = 0;
+       }
+       flags.botl = 1;
+}
+
+int
+dountrap()     /* disarm a trap */
+{
+       if (near_capacity() >= HVY_ENCUMBER) {
+           pline("You're too strained to do that.");
+           return 0;
+       }
+       if ((nohands(youmonst.data) && !webmaker(youmonst.data)) || !youmonst.data->mmove) {
+           pline("And just how do you expect to do that?");
+           return 0;
+       } else if (u.ustuck && sticks(youmonst.data)) {
+           pline("You'll have to let go of %s first.", mon_nam(u.ustuck));
+           return 0;
+       }
+       if (u.ustuck || (welded(uwep) && bimanual(uwep))) {
+           Your("%s seem to be too busy for that.",
+                makeplural(body_part(HAND)));
+           return 0;
+       }
+       return untrap(FALSE);
+}
+#endif /* OVLB */
+#ifdef OVL2
+
+/* Probability of disabling a trap.  Helge Hafting */
+STATIC_OVL int
+untrap_prob(ttmp)
+struct trap *ttmp;
+{
+       int chance = 3;
+
+       /* Only spiders know how to deal with webs reliably */
+       if (ttmp->ttyp == WEB && !webmaker(youmonst.data))
+               chance = 30;
+       if (Confusion || Hallucination) chance++;
+       if (Blind) chance++;
+       if (Stunned) chance += 2;
+       if (Fumbling) chance *= 2;
+       /* Your own traps are better known than others. */
+       if (ttmp && ttmp->madeby_u) chance--;
+       if (Role_if(PM_ROGUE)) {
+           if (rn2(2 * MAXULEV) < u.ulevel) chance--;
+           if (u.uhave.questart && chance > 1) chance--;
+       } else if (Role_if(PM_RANGER) && chance > 1) chance--;
+       return rn2(chance);
+}
+
+/* Replace trap with object(s).  Helge Hafting */
+STATIC_OVL void
+cnv_trap_obj(otyp, cnt, ttmp)
+int otyp;
+int cnt;
+struct trap *ttmp;
+{
+       struct obj *otmp = mksobj(otyp, TRUE, FALSE);
+       otmp->quan=cnt;
+       otmp->owt = weight(otmp);
+       /* Only dart traps are capable of being poisonous */
+       if (otyp != DART)
+           otmp->opoisoned = 0;
+       place_object(otmp, ttmp->tx, ttmp->ty);
+       /* Sell your own traps only... */
+       if (ttmp->madeby_u) sellobj(otmp, ttmp->tx, ttmp->ty);
+       stackobj(otmp);
+       newsym(ttmp->tx, ttmp->ty);
+       deltrap(ttmp);
+}
+
+/* while attempting to disarm an adjacent trap, we've fallen into it */
+STATIC_OVL void
+move_into_trap(ttmp)
+struct trap *ttmp;
+{
+       int bc;
+       xchar x = ttmp->tx, y = ttmp->ty, bx, by, cx, cy;
+       boolean unused;
+
+       /* we know there's no monster in the way, and we're not trapped */
+       if (!Punished || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused,
+               TRUE)) {
+           u.ux0 = u.ux,  u.uy0 = u.uy;
+           u.ux = x,  u.uy = y;
+           u.umoved = TRUE;
+           newsym(u.ux0, u.uy0);
+           vision_recalc(1);
+           check_leash(u.ux0, u.uy0);
+           if (Punished) move_bc(0, bc, bx, by, cx, cy);
+           spoteffects(FALSE); /* dotrap() */
+           exercise(A_WIS, FALSE);
+       }
+}
+
+/* 0: doesn't even try
+ * 1: tries and fails
+ * 2: succeeds
+ */
+STATIC_OVL int
+try_disarm(ttmp, force_failure)
+struct trap *ttmp;
+boolean force_failure;
+{
+       struct monst *mtmp = m_at(ttmp->tx,ttmp->ty);
+       int ttype = ttmp->ttyp;
+       boolean under_u = (!u.dx && !u.dy);
+       boolean holdingtrap = (ttype == BEAR_TRAP || ttype == WEB);
+       
+       /* Test for monster first, monsters are displayed instead of trap. */
+       if (mtmp && (!mtmp->mtrapped || !holdingtrap)) {
+               pline("%s is in the way.", Monnam(mtmp));
+               return 0;
+       }
+       /* We might be forced to move onto the trap's location. */
+       if (sobj_at(BOULDER, ttmp->tx, ttmp->ty)
+                               && !Passes_walls && !under_u) {
+               There("is a boulder in your way.");
+               return 0;
+       }
+       /* duplicate tight-space checks from test_move */
+       if (u.dx && u.dy &&
+           bad_rock(youmonst.data,u.ux,ttmp->ty) &&
+           bad_rock(youmonst.data,ttmp->tx,u.uy)) {
+           if ((invent && (inv_weight() + weight_cap() > 600)) ||
+               bigmonst(youmonst.data)) {
+               /* don't allow untrap if they can't get thru to it */
+               You("are unable to reach the %s!",
+                   defsyms[trap_to_defsym(ttype)].explanation);
+               return 0;
+           }
+       }
+       /* untrappable traps are located on the ground. */
+       if (!can_reach_floor()) {
+#ifdef STEED
+               if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
+                       You("aren't skilled enough to reach from %s.",
+                               mon_nam(u.usteed));
+               else
+#endif
+               You("are unable to reach the %s!",
+                       defsyms[trap_to_defsym(ttype)].explanation);
+               return 0;
+       }
+
+       /* Will our hero succeed? */
+       if (force_failure || untrap_prob(ttmp)) {
+               if (rnl(5)) {
+                   pline("Whoops...");
+                   if (mtmp) {         /* must be a trap that holds monsters */
+                       if (ttype == BEAR_TRAP) {
+                           if (mtmp->mtame) abuse_dog(mtmp);
+                           if ((mtmp->mhp -= rnd(4)) <= 0) killed(mtmp);
+                       } else if (ttype == WEB) {
+                           if (!webmaker(youmonst.data)) {
+                               struct trap *ttmp2 = maketrap(u.ux, u.uy, WEB);
+                               if (ttmp2) {
+                                   pline_The("webbing sticks to you. You're caught too!");
+                                   dotrap(ttmp2, NOWEBMSG);
+#ifdef STEED
+                                   if (u.usteed && u.utrap) {
+                                       /* you, not steed, are trapped */
+                                       dismount_steed(DISMOUNT_FELL);
+                                   }
+#endif
+                               }
+                           } else
+                               pline("%s remains entangled.", Monnam(mtmp));
+                       }
+                   } else if (under_u) {
+                       dotrap(ttmp, 0);
+                   } else {
+                       move_into_trap(ttmp);
+                   }
+               } else {
+                   pline("%s %s is difficult to %s.",
+                         ttmp->madeby_u ? "Your" : under_u ? "This" : "That",
+                         defsyms[trap_to_defsym(ttype)].explanation,
+                         (ttype == WEB) ? "remove" : "disarm");
+               }
+               return 1;
+       }
+       return 2;
+}
+
+STATIC_OVL void
+reward_untrap(ttmp, mtmp)
+struct trap *ttmp;
+struct monst *mtmp;
+{
+       if (!ttmp->madeby_u) {
+           if (rnl(10) < 8 && !mtmp->mpeaceful &&
+                   !mtmp->msleeping && !mtmp->mfrozen &&
+                   !mindless(mtmp->data) &&
+                   mtmp->data->mlet != S_HUMAN) {
+               mtmp->mpeaceful = 1;
+               set_malign(mtmp);       /* reset alignment */
+               pline("%s is grateful.", Monnam(mtmp));
+           }
+           /* Helping someone out of a trap is a nice thing to do,
+            * A lawful may be rewarded, but not too often.  */
+           if (!rn2(3) && !rnl(8) && u.ualign.type == A_LAWFUL) {
+               adjalign(1);
+               You_feel("that you did the right thing.");
+           }
+       }
+}
+
+STATIC_OVL int
+disarm_holdingtrap(ttmp) /* Helge Hafting */
+struct trap *ttmp;
+{
+       struct monst *mtmp;
+       int fails = try_disarm(ttmp, FALSE);
+
+       if (fails < 2) return fails;
+
+       /* ok, disarm it. */
+
+       /* untrap the monster, if any.
+          There's no need for a cockatrice test, only the trap is touched */
+       if ((mtmp = m_at(ttmp->tx,ttmp->ty)) != 0) {
+               mtmp->mtrapped = 0;
+               You("remove %s %s from %s.", the_your[ttmp->madeby_u],
+                       (ttmp->ttyp == BEAR_TRAP) ? "bear trap" : "webbing",
+                       mon_nam(mtmp));
+               reward_untrap(ttmp, mtmp);
+       } else {
+               if (ttmp->ttyp == BEAR_TRAP) {
+                       You("disarm %s bear trap.", the_your[ttmp->madeby_u]);
+                       cnv_trap_obj(BEARTRAP, 1, ttmp);
+               } else /* if (ttmp->ttyp == WEB) */ {
+                       You("succeed in removing %s web.", the_your[ttmp->madeby_u]);
+                       deltrap(ttmp);
+               }
+       }
+       newsym(u.ux + u.dx, u.uy + u.dy);
+       return 1;
+}
+
+STATIC_OVL int
+disarm_landmine(ttmp) /* Helge Hafting */
+struct trap *ttmp;
+{
+       int fails = try_disarm(ttmp, FALSE);
+
+       if (fails < 2) return fails;
+       You("disarm %s land mine.", the_your[ttmp->madeby_u]);
+       cnv_trap_obj(LAND_MINE, 1, ttmp);
+       return 1;
+}
+
+/* getobj will filter down to cans of grease and known potions of oil */
+static NEARDATA const char oil[] = { ALL_CLASSES, TOOL_CLASS, POTION_CLASS, 0 };
+
+/* it may not make much sense to use grease on floor boards, but so what? */
+STATIC_OVL int
+disarm_squeaky_board(ttmp)
+struct trap *ttmp;
+{
+       struct obj *obj;
+       boolean bad_tool;
+       int fails;
+
+       obj = getobj(oil, "untrap with");
+       if (!obj) return 0;
+
+       bad_tool = (obj->cursed ||
+                       ((obj->otyp != POT_OIL || obj->lamplit) &&
+                        (obj->otyp != CAN_OF_GREASE || !obj->spe)));
+
+       fails = try_disarm(ttmp, bad_tool);
+       if (fails < 2) return fails;
+
+       /* successfully used oil or grease to fix squeaky board */
+       if (obj->otyp == CAN_OF_GREASE) {
+           consume_obj_charge(obj, TRUE);
+       } else {
+           useup(obj); /* oil */
+           makeknown(POT_OIL);
+       }
+       You("repair the squeaky board.");       /* no madeby_u */
+       deltrap(ttmp);
+       newsym(u.ux + u.dx, u.uy + u.dy);
+       more_experienced(1, 5);
+       newexplevel();
+       return 1;
+}
+
+/* removes traps that shoot arrows, darts, etc. */
+STATIC_OVL int
+disarm_shooting_trap(ttmp, otyp)
+struct trap *ttmp;
+int otyp;
+{
+       int fails = try_disarm(ttmp, FALSE);
+
+       if (fails < 2) return fails;
+       You("disarm %s trap.", the_your[ttmp->madeby_u]);
+       cnv_trap_obj(otyp, 50-rnl(50), ttmp);
+       return 1;
+}
+
+/* Is the weight too heavy?
+ * Formula as in near_capacity() & check_capacity() */
+STATIC_OVL int
+try_lift(mtmp, ttmp, wt, stuff)
+struct monst *mtmp;
+struct trap *ttmp;
+int wt;
+boolean stuff;
+{
+       int wc = weight_cap();
+
+       if (((wt * 2) / wc) >= HVY_ENCUMBER) {
+           pline("%s is %s for you to lift.", Monnam(mtmp),
+                 stuff ? "carrying too much" : "too heavy");
+           if (!ttmp->madeby_u && !mtmp->mpeaceful && mtmp->mcanmove &&
+                   !mindless(mtmp->data) &&
+                   mtmp->data->mlet != S_HUMAN && rnl(10) < 3) {
+               mtmp->mpeaceful = 1;
+               set_malign(mtmp);               /* reset alignment */
+               pline("%s thinks it was nice of you to try.", Monnam(mtmp));
+           }
+           return 0;
+       }
+       return 1;
+}
+
+/* Help trapped monster (out of a (spiked) pit) */
+STATIC_OVL int
+help_monster_out(mtmp, ttmp)
+struct monst *mtmp;
+struct trap *ttmp;
+{
+       int wt;
+       struct obj *otmp;
+       boolean uprob;
+
+       /*
+        * This works when levitating too -- consistent with the ability
+        * to hit monsters while levitating.
+        *
+        * Should perhaps check that our hero has arms/hands at the
+        * moment.  Helping can also be done by engulfing...
+        *
+        * Test the monster first - monsters are displayed before traps.
+        */
+       if (!mtmp->mtrapped) {
+               pline("%s isn't trapped.", Monnam(mtmp));
+               return 0;
+       }
+       /* Do you have the necessary capacity to lift anything? */
+       if (check_capacity((char *)0)) return 1;
+
+       /* Will our hero succeed? */
+       if ((uprob = untrap_prob(ttmp)) && !mtmp->msleeping && mtmp->mcanmove) {
+               You("try to reach out your %s, but %s backs away skeptically.",
+                       makeplural(body_part(ARM)),
+                       mon_nam(mtmp));
+               return 1;
+       }
+
+
+       /* is it a cockatrice?... */
+       if (touch_petrifies(mtmp->data) && !uarmg && !Stone_resistance) {
+               You("grab the trapped %s using your bare %s.",
+                               mtmp->data->mname, makeplural(body_part(HAND)));
+
+               if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
+                       display_nhwindow(WIN_MESSAGE, FALSE);
+               else {
+                       char kbuf[BUFSZ];
+
+                       Sprintf(kbuf, "trying to help %s out of a pit",
+                                       an(mtmp->data->mname));
+                       instapetrify(kbuf);
+                       return 1;
+               }
+       }
+       /* need to do cockatrice check first if sleeping or paralyzed */
+       if (uprob) {
+           You("try to grab %s, but cannot get a firm grasp.",
+               mon_nam(mtmp));
+           if (mtmp->msleeping) {
+               mtmp->msleeping = 0;
+               pline("%s awakens.", Monnam(mtmp));
+           }
+           return 1;
+       }
+
+       You("reach out your %s and grab %s.",
+           makeplural(body_part(ARM)), mon_nam(mtmp));
+
+       if (mtmp->msleeping) {
+           mtmp->msleeping = 0;
+           pline("%s awakens.", Monnam(mtmp));
+       } else if (mtmp->mfrozen && !rn2(mtmp->mfrozen)) {
+           /* After such manhandling, perhaps the effect wears off */
+           mtmp->mcanmove = 1;
+           mtmp->mfrozen = 0;
+           pline("%s stirs.", Monnam(mtmp));
+       }
+
+       /* is the monster too heavy? */
+       wt = inv_weight() + mtmp->data->cwt;
+       if (!try_lift(mtmp, ttmp, wt, FALSE)) return 1;
+
+       /* is the monster with inventory too heavy? */
+       for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+               wt += otmp->owt;
+       if (!try_lift(mtmp, ttmp, wt, TRUE)) return 1;
+
+       You("pull %s out of the pit.", mon_nam(mtmp));
+       mtmp->mtrapped = 0;
+       fill_pit(mtmp->mx, mtmp->my);
+       reward_untrap(ttmp, mtmp);
+       return 1;
+}
+
+int
+untrap(force)
+boolean force;
+{
+       register struct obj *otmp;
+       register boolean confused = (Confusion > 0 || Hallucination > 0);
+       register int x,y;
+       int ch;
+       struct trap *ttmp;
+       struct monst *mtmp;
+       boolean trap_skipped = FALSE;
+       boolean box_here = FALSE;
+       boolean deal_with_floor_trap = FALSE;
+       char the_trap[BUFSZ], qbuf[QBUFSZ];
+       int containercnt = 0;
+
+       if(!getdir((char *)0)) return(0);
+       x = u.ux + u.dx;
+       y = u.uy + u.dy;
+
+       for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) {
+               if(Is_box(otmp) && !u.dx && !u.dy) {
+                       box_here = TRUE;
+                       containercnt++;
+                       if (containercnt > 1) break;
+               }
+       }
+
+       if ((ttmp = t_at(x,y)) && ttmp->tseen) {
+               deal_with_floor_trap = TRUE;
+               Strcpy(the_trap, the(defsyms[trap_to_defsym(ttmp->ttyp)].explanation));
+               if (box_here) {
+                       if (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) {
+                           You_cant("do much about %s%s.",
+                                       the_trap, u.utrap ?
+                                       " that you're stuck in" :
+                                       " while standing on the edge of it");
+                           trap_skipped = TRUE;
+                           deal_with_floor_trap = FALSE;
+                       } else {
+                           Sprintf(qbuf, "There %s and %s here. %s %s?",
+                               (containercnt == 1) ? "is a container" : "are containers",
+                               an(defsyms[trap_to_defsym(ttmp->ttyp)].explanation),
+                               ttmp->ttyp == WEB ? "Remove" : "Disarm", the_trap);
+                           switch (ynq(qbuf)) {
+                               case 'q': return(0);
+                               case 'n': trap_skipped = TRUE;
+                                         deal_with_floor_trap = FALSE;
+                                         break;
+                           }
+                       }
+               }
+               if (deal_with_floor_trap) {
+                   if (u.utrap) {
+                       You("cannot deal with %s while trapped%s!", the_trap,
+                               (x == u.ux && y == u.uy) ? " in it" : "");
+                       return 1;
+                   }
+                   switch(ttmp->ttyp) {
+                       case BEAR_TRAP:
+                       case WEB:
+                               return disarm_holdingtrap(ttmp);
+                       case LANDMINE:
+                               return disarm_landmine(ttmp);
+                       case SQKY_BOARD:
+                               return disarm_squeaky_board(ttmp);
+                       case DART_TRAP:
+                               return disarm_shooting_trap(ttmp, DART);
+                       case ARROW_TRAP:
+                               return disarm_shooting_trap(ttmp, ARROW);
+                       case PIT:
+                       case SPIKED_PIT:
+                               if (!u.dx && !u.dy) {
+                                   You("are already on the edge of the pit.");
+                                   return 0;
+                               }
+                               if (!(mtmp = m_at(x,y))) {
+                                   pline("Try filling the pit instead.");
+                                   return 0;
+                               }
+                               return help_monster_out(mtmp, ttmp);
+                       default:
+                               You("cannot disable %s trap.", (u.dx || u.dy) ? "that" : "this");
+                               return 0;
+                   }
+               }
+       } /* end if */
+
+       if(!u.dx && !u.dy) {
+           for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
+               if(Is_box(otmp)) {
+                   Sprintf(qbuf, "There is %s here. Check it for traps?",
+                       safe_qbuf("", sizeof("There is  here. Check it for traps?"),
+                               doname(otmp), an(simple_typename(otmp->otyp)), "a box"));
+                   switch (ynq(qbuf)) {
+                       case 'q': return(0);
+                       case 'n': continue;
+                   }
+#ifdef STEED
+                   if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
+                       You("aren't skilled enough to reach from %s.",
+                               mon_nam(u.usteed));
+                       return(0);
+                   }
+#endif
+                   if((otmp->otrapped && (force || (!confused
+                               && rn2(MAXULEV + 1 - u.ulevel) < 10)))
+                      || (!force && confused && !rn2(3))) {
+                       You("find a trap on %s!", the(xname(otmp)));
+                       if (!confused) exercise(A_WIS, TRUE);
+
+                       switch (ynq("Disarm it?")) {
+                           case 'q': return(1);
+                           case 'n': trap_skipped = TRUE;  continue;
+                       }
+
+                       if(otmp->otrapped) {
+                           exercise(A_DEX, TRUE);
+                           ch = ACURR(A_DEX) + u.ulevel;
+                           if (Role_if(PM_ROGUE)) ch *= 2;
+                           if(!force && (confused || Fumbling ||
+                               rnd(75+level_difficulty()/2) > ch)) {
+                               (void) chest_trap(otmp, FINGER, TRUE);
+                           } else {
+                               You("disarm it!");
+                               otmp->otrapped = 0;
+                           }
+                       } else pline("That %s was not trapped.", xname(otmp));
+                       return(1);
+                   } else {
+                       You("find no traps on %s.", the(xname(otmp)));
+                       return(1);
+                   }
+               }
+
+           You(trap_skipped ? "find no other traps here."
+                            : "know of no traps here.");
+           return(0);
+       }
+
+       if ((mtmp = m_at(x,y))                          &&
+               mtmp->m_ap_type == M_AP_FURNITURE       &&
+               (mtmp->mappearance == S_hcdoor ||
+                       mtmp->mappearance == S_vcdoor)  &&
+               !Protection_from_shape_changers)         {
+
+           stumble_onto_mimic(mtmp);
+           return(1);
+       }
+
+       if (!IS_DOOR(levl[x][y].typ)) {
+           if ((ttmp = t_at(x,y)) && ttmp->tseen)
+               You("cannot disable that trap.");
+           else
+               You("know of no traps there.");
+           return(0);
+       }
+
+       switch (levl[x][y].doormask) {
+           case D_NODOOR:
+               You("%s no door there.", Blind ? "feel" : "see");
+               return(0);
+           case D_ISOPEN:
+               pline("This door is safely open.");
+               return(0);
+           case D_BROKEN:
+               pline("This door is broken.");
+               return(0);
+       }
+
+       if ((levl[x][y].doormask & D_TRAPPED
+            && (force ||
+                (!confused && rn2(MAXULEV - u.ulevel + 11) < 10)))
+           || (!force && confused && !rn2(3))) {
+               You("find a trap on the door!");
+               exercise(A_WIS, TRUE);
+               if (ynq("Disarm it?") != 'y') return(1);
+               if (levl[x][y].doormask & D_TRAPPED) {
+                   ch = 15 + (Role_if(PM_ROGUE) ? u.ulevel*3 : u.ulevel);
+                   exercise(A_DEX, TRUE);
+                   if(!force && (confused || Fumbling ||
+                                    rnd(75+level_difficulty()/2) > ch)) {
+                       You("set it off!");
+                       b_trapped("door", FINGER);
+                       levl[x][y].doormask = D_NODOOR;
+                       unblock_point(x, y);
+                       newsym(x, y);
+                       /* (probably ought to charge for this damage...) */
+                       if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L);
+                   } else {
+                       You("disarm it!");
+                       levl[x][y].doormask &= ~D_TRAPPED;
+                   }
+               } else pline("This door was not trapped.");
+               return(1);
+       } else {
+               You("find no traps on the door.");
+               return(1);
+       }
+}
+#endif /* OVL2 */
+#ifdef OVLB
+
+/* only called when the player is doing something to the chest directly */
+boolean
+chest_trap(obj, bodypart, disarm)
+register struct obj *obj;
+register int bodypart;
+boolean disarm;
+{
+       register struct obj *otmp = obj, *otmp2;
+       char    buf[80];
+       const char *msg;
+       coord cc;
+
+       if (get_obj_location(obj, &cc.x, &cc.y, 0))     /* might be carried */
+           obj->ox = cc.x,  obj->oy = cc.y;
+
+       otmp->otrapped = 0;     /* trap is one-shot; clear flag first in case
+                                  chest kills you and ends up in bones file */
+       You(disarm ? "set it off!" : "trigger a trap!");
+       display_nhwindow(WIN_MESSAGE, FALSE);
+       if (Luck > -13 && rn2(13+Luck) > 7) {   /* saved by luck */
+           /* trap went off, but good luck prevents damage */
+           switch (rn2(13)) {
+               case 12:
+               case 11:  msg = "explosive charge is a dud";  break;
+               case 10:
+               case  9:  msg = "electric charge is grounded";  break;
+               case  8:
+               case  7:  msg = "flame fizzles out";  break;
+               case  6:
+               case  5:
+               case  4:  msg = "poisoned needle misses";  break;
+               case  3:
+               case  2:
+               case  1:
+               case  0:  msg = "gas cloud blows away";  break;
+               default:  impossible("chest disarm bug");  msg = (char *)0;
+                         break;
+           }
+           if (msg) pline("But luckily the %s!", msg);
+       } else {
+           switch(rn2(20) ? ((Luck >= 13) ? 0 : rn2(13-Luck)) : rn2(26)) {
+               case 25:
+               case 24:
+               case 23:
+               case 22:
+               case 21: {
+                         struct monst *shkp = 0;
+                         long loss = 0L;
+                         boolean costly, insider;
+                         register xchar ox = obj->ox, oy = obj->oy;
+
+                         /* the obj location need not be that of player */
+                         costly = (costly_spot(ox, oy) &&
+                                  (shkp = shop_keeper(*in_rooms(ox, oy,
+                                   SHOPBASE))) != (struct monst *)0);
+                         insider = (*u.ushops && inside_shop(u.ux, u.uy) &&
+                                   *in_rooms(ox, oy, SHOPBASE) == *u.ushops);
+
+                         pline("%s!", Tobjnam(obj, "explode"));
+                         Sprintf(buf, "exploding %s", xname(obj));
+
+                         if(costly)
+                             loss += stolen_value(obj, ox, oy,
+                                               (boolean)shkp->mpeaceful, TRUE);
+                         delete_contents(obj);
+                         /* we're about to delete all things at this location,
+                          * which could include the ball & chain.
+                          * If we attempt to call unpunish() in the
+                          * for-loop below we can end up with otmp2
+                          * being invalid once the chain is gone.
+                          * Deal with ball & chain right now instead.
+                          */
+                         if (Punished && !carried(uball) &&
+                               ((uchain->ox == u.ux && uchain->oy == u.uy) ||
+                                (uball->ox == u.ux && uball->oy == u.uy)))
+                               unpunish();
+
+                         for(otmp = level.objects[u.ux][u.uy];
+                                                       otmp; otmp = otmp2) {
+                             otmp2 = otmp->nexthere;
+                             if(costly)
+                                 loss += stolen_value(otmp, otmp->ox,
+                                         otmp->oy, (boolean)shkp->mpeaceful,
+                                         TRUE);
+                             delobj(otmp);
+                         }
+                         wake_nearby();
+                         losehp(d(6,6), buf, KILLED_BY_AN);
+                         exercise(A_STR, FALSE);
+                         if(costly && loss) {
+                             if(insider)
+                             You("owe %ld %s for objects destroyed.",
+                                                       loss, currency(loss));
+                             else {
+                                 You("caused %ld %s worth of damage!",
+                                                       loss, currency(loss));
+                                 make_angry_shk(shkp, ox, oy);
+                             }
+                         }
+                         return TRUE;
+                       }
+               case 20:
+               case 19:
+               case 18:
+               case 17:
+                       pline("A cloud of noxious gas billows from %s.",
+                                                       the(xname(obj)));
+                       poisoned("gas cloud", A_STR, "cloud of poison gas",15);
+                       exercise(A_CON, FALSE);
+                       break;
+               case 16:
+               case 15:
+               case 14:
+               case 13:
+                       You_feel("a needle prick your %s.",body_part(bodypart));
+                       poisoned("needle", A_CON, "poisoned needle",10);
+                       exercise(A_CON, FALSE);
+                       break;
+               case 12:
+               case 11:
+               case 10:
+               case 9:
+                       dofiretrap(obj);
+                       break;
+               case 8:
+               case 7:
+               case 6: {
+                       int dmg;
+
+                       You("are jolted by a surge of electricity!");
+                       if(Shock_resistance)  {
+                           shieldeff(u.ux, u.uy);
+                           You("don't seem to be affected.");
+                           dmg = 0;
+                       } else
+                           dmg = d(4, 4);
+                       destroy_item(RING_CLASS, AD_ELEC);
+                       destroy_item(WAND_CLASS, AD_ELEC);
+                       if (dmg) losehp(dmg, "electric shock", KILLED_BY_AN);
+                       break;
+                     }
+               case 5:
+               case 4:
+               case 3:
+                       if (!Free_action) {                        
+                       pline("Suddenly you are frozen in place!");
+                       nomul(-d(5, 6));
+                       exercise(A_DEX, FALSE);
+                       nomovemsg = You_can_move_again;
+                       } else You("momentarily stiffen.");
+                       break;
+               case 2:
+               case 1:
+               case 0:
+                       pline("A cloud of %s gas billows from %s.",
+                               Blind ? blindgas[rn2(SIZE(blindgas))] :
+                               rndcolor(), the(xname(obj)));
+                       if(!Stunned) {
+                           if (Hallucination)
+                               pline("What a groovy feeling!");
+                           else if (Blind)
+                               You("%s and get dizzy...",
+                                   stagger(youmonst.data, "stagger"));
+                           else
+                               You("%s and your vision blurs...",
+                                   stagger(youmonst.data, "stagger"));
+                       }
+                       make_stunned(HStun + rn1(7, 16),FALSE);
+                       (void) make_hallucinated(HHallucination + rn1(5, 16),FALSE,0L);
+                       break;
+               default: impossible("bad chest trap");
+                       break;
+           }
+           bot();                      /* to get immediate botl re-display */
+       }
+
+       return FALSE;
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+struct trap *
+t_at(x,y)
+register int x, y;
+{
+       register struct trap *trap = ftrap;
+       while(trap) {
+               if(trap->tx == x && trap->ty == y) return(trap);
+               trap = trap->ntrap;
+       }
+       return((struct trap *)0);
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+void
+deltrap(trap)
+register struct trap *trap;
+{
+       register struct trap *ttmp;
+
+       if(trap == ftrap)
+               ftrap = ftrap->ntrap;
+       else {
+               for(ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap) ;
+               ttmp->ntrap = trap->ntrap;
+       }
+       dealloc_trap(trap);
+}
+
+boolean
+delfloortrap(ttmp)
+register struct trap *ttmp;
+{
+       /* Destroy a trap that emanates from the floor. */
+       /* some of these are arbitrary -dlc */
+       if (ttmp && ((ttmp->ttyp == SQKY_BOARD) ||
+                    (ttmp->ttyp == BEAR_TRAP) ||
+                    (ttmp->ttyp == LANDMINE) ||
+                    (ttmp->ttyp == FIRE_TRAP) ||
+                    (ttmp->ttyp == PIT) ||
+                    (ttmp->ttyp == SPIKED_PIT) ||
+                    (ttmp->ttyp == HOLE) ||
+                    (ttmp->ttyp == TRAPDOOR) ||
+                    (ttmp->ttyp == TELEP_TRAP) ||
+                    (ttmp->ttyp == LEVEL_TELEP) ||
+                    (ttmp->ttyp == WEB) ||
+                    (ttmp->ttyp == MAGIC_TRAP) ||
+                    (ttmp->ttyp == ANTI_MAGIC))) {
+           register struct monst *mtmp;
+
+           if (ttmp->tx == u.ux && ttmp->ty == u.uy) {
+               u.utrap = 0;
+               u.utraptype = 0;
+           } else if ((mtmp = m_at(ttmp->tx, ttmp->ty)) != 0) {
+               mtmp->mtrapped = 0;
+           }
+           deltrap(ttmp);
+           return TRUE;
+       } else
+           return FALSE;
+}
+
+/* used for doors (also tins).  can be used for anything else that opens. */
+void
+b_trapped(item, bodypart)
+register const char *item;
+register int bodypart;
+{
+       register int lvl = level_difficulty();
+       int dmg = rnd(5 + (lvl < 5 ? lvl : 2+lvl/2));
+
+       pline("KABOOM!!  %s was booby-trapped!", The(item));
+       wake_nearby();
+       losehp(dmg, "explosion", KILLED_BY_AN);
+       exercise(A_STR, FALSE);
+       if (bodypart) exercise(A_CON, FALSE);
+       make_stunned(HStun + dmg, TRUE);
+}
+
+/* Monster is hit by trap. */
+/* Note: doesn't work if both obj and d_override are null */
+STATIC_OVL boolean
+thitm(tlev, mon, obj, d_override, nocorpse)
+int tlev;
+struct monst *mon;
+struct obj *obj;
+int d_override;
+boolean nocorpse;
+{
+       int strike;
+       boolean trapkilled = FALSE;
+
+       if (d_override) strike = 1;
+       else if (obj) strike = (find_mac(mon) + tlev + obj->spe <= rnd(20));
+       else strike = (find_mac(mon) + tlev <= rnd(20));
+
+       /* Actually more accurate than thitu, which doesn't take
+        * obj->spe into account.
+        */
+       if(!strike) {
+               if (obj && cansee(mon->mx, mon->my))
+                   pline("%s is almost hit by %s!", Monnam(mon), doname(obj));
+       } else {
+               int dam = 1;
+
+               if (obj && cansee(mon->mx, mon->my))
+                       pline("%s is hit by %s!", Monnam(mon), doname(obj));
+               if (d_override) dam = d_override;
+               else if (obj) {
+                       dam = dmgval(obj, mon);
+                       if (dam < 1) dam = 1;
+               }
+               if ((mon->mhp -= dam) <= 0) {
+                       int xx = mon->mx;
+                       int yy = mon->my;
+
+                       monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS);
+                       if (mon->mhp <= 0) {
+                               newsym(xx, yy);
+                               trapkilled = TRUE;
+                       }
+               }
+       }
+       if (obj && (!strike || d_override)) {
+               place_object(obj, mon->mx, mon->my);
+               stackobj(obj);
+       } else if (obj) dealloc_obj(obj);
+
+       return trapkilled;
+}
+
+boolean
+unconscious()
+{
+       return((boolean)(multi < 0 && (!nomovemsg ||
+               u.usleep ||
+               !strncmp(nomovemsg,"You regain con", 14) ||
+               !strncmp(nomovemsg,"You are consci", 14))));
+}
+
+static const char lava_killer[] = "molten lava";
+
+boolean
+lava_effects()
+{
+    register struct obj *obj, *obj2;
+    int dmg;
+    boolean usurvive;
+
+    burn_away_slime();
+    if (likes_lava(youmonst.data)) return FALSE;
+
+    if (!Fire_resistance) {
+       if(Wwalking) {
+           dmg = d(6,6);
+           pline_The("lava here burns you!");
+           if(dmg < u.uhp) {
+               losehp(dmg, lava_killer, KILLED_BY);
+               goto burn_stuff;
+           }
+       } else
+           You("fall into the lava!");
+
+       usurvive = Lifesaved || discover;
+#ifdef WIZARD
+       if (wizard) usurvive = TRUE;
+#endif
+       for(obj = invent; obj; obj = obj2) {
+           obj2 = obj->nobj;
+           if(is_organic(obj) && !obj->oerodeproof) {
+               if(obj->owornmask) {
+                   if (usurvive)
+                       Your("%s into flame!", aobjnam(obj, "burst"));
+
+                   if(obj == uarm) (void) Armor_gone();
+                   else if(obj == uarmc) (void) Cloak_off();
+                   else if(obj == uarmh) (void) Helmet_off();
+                   else if(obj == uarms) (void) Shield_off();
+                   else if(obj == uarmg) (void) Gloves_off();
+                   else if(obj == uarmf) (void) Boots_off();
+#ifdef TOURIST
+                   else if(obj == uarmu) setnotworn(obj);
+#endif
+                   else if(obj == uleft) Ring_gone(obj);
+                   else if(obj == uright) Ring_gone(obj);
+                   else if(obj == ublindf) Blindf_off(obj);
+                   else if(obj == uamul) Amulet_off();
+                   else if(obj == uwep) uwepgone();
+                   else if (obj == uquiver) uqwepgone();
+                   else if (obj == uswapwep) uswapwepgone();
+               }
+               useupall(obj);
+           }
+       }
+
+       /* s/he died... */
+       u.uhp = -1;
+       killer_format = KILLED_BY;
+       killer = lava_killer;
+       You("burn to a crisp...");
+       done(BURNING);
+       while (!safe_teleds(TRUE)) {
+               pline("You're still burning.");
+               done(BURNING);
+       }
+       You("find yourself back on solid %s.", surface(u.ux, u.uy));
+       return(TRUE);
+    }
+
+    if (!Wwalking) {
+       u.utrap = rn1(4, 4) + (rn1(4, 12) << 8);
+       u.utraptype = TT_LAVA;
+       You("sink into the lava, but it only burns slightly!");
+       if (u.uhp > 1)
+           losehp(1, lava_killer, KILLED_BY);
+    }
+    /* just want to burn boots, not all armor; destroy_item doesn't work on
+       armor anyway */
+burn_stuff:
+    if(uarmf && !uarmf->oerodeproof && is_organic(uarmf)) {
+       /* save uarmf value because Boots_off() sets uarmf to null */
+       obj = uarmf;
+       Your("%s bursts into flame!", xname(obj));
+       (void) Boots_off();
+       useup(obj);
+    }
+    destroy_item(SCROLL_CLASS, AD_FIRE);
+    destroy_item(SPBOOK_CLASS, AD_FIRE);
+    destroy_item(POTION_CLASS, AD_FIRE);
+    return(FALSE);
+}
+
+#endif /* OVLB */
+
+/*trap.c*/
diff --git a/src/u_init.c b/src/u_init.c
new file mode 100644 (file)
index 0000000..77c92b0
--- /dev/null
@@ -0,0 +1,1062 @@
+/*     SCCS Id: @(#)u_init.c   3.4     2002/10/22      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+struct trobj {
+       short trotyp;
+       schar trspe;
+       char trclass;
+       Bitfield(trquan,6);
+       Bitfield(trbless,2);
+};
+
+STATIC_DCL void FDECL(ini_inv, (struct trobj *));
+STATIC_DCL void FDECL(knows_object,(int));
+STATIC_DCL void FDECL(knows_class,(CHAR_P));
+STATIC_DCL boolean FDECL(restricted_spell_discipline, (int));
+
+#define UNDEF_TYP      0
+#define UNDEF_SPE      '\177'
+#define UNDEF_BLESS    2
+
+/*
+ *     Initial inventory for the various roles.
+ */
+
+static struct trobj Archeologist[] = {
+       /* if adventure has a name...  idea from tan@uvm-gen */
+       { BULLWHIP, 2, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { LEATHER_JACKET, 0, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { FEDORA, 0, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { FOOD_RATION, 0, FOOD_CLASS, 3, 0 },
+       { PICK_AXE, UNDEF_SPE, TOOL_CLASS, 1, UNDEF_BLESS },
+       { TINNING_KIT, UNDEF_SPE, TOOL_CLASS, 1, UNDEF_BLESS },
+       { TOUCHSTONE, 0, GEM_CLASS, 1, 0 },
+       { SACK, 0, TOOL_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Barbarian[] = {
+#define B_MAJOR        0       /* two-handed sword or battle-axe  */
+#define B_MINOR        1       /* matched with axe or short sword */
+       { TWO_HANDED_SWORD, 0, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { AXE, 0, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { RING_MAIL, 0, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { FOOD_RATION, 0, FOOD_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Cave_man[] = {
+#define C_AMMO 2
+       { CLUB, 1, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { SLING, 2, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { FLINT, 0, GEM_CLASS, 15, UNDEF_BLESS },       /* quan is variable */
+       { ROCK, 0, GEM_CLASS, 3, 0 },                   /* yields 18..33 */
+       { LEATHER_ARMOR, 0, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Healer[] = {
+       { SCALPEL, 0, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { LEATHER_GLOVES, 1, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { STETHOSCOPE, 0, TOOL_CLASS, 1, 0 },
+       { POT_HEALING, 0, POTION_CLASS, 4, UNDEF_BLESS },
+       { POT_EXTRA_HEALING, 0, POTION_CLASS, 4, UNDEF_BLESS },
+       { WAN_SLEEP, UNDEF_SPE, WAND_CLASS, 1, UNDEF_BLESS },
+       /* always blessed, so it's guaranteed readable */
+       { SPE_HEALING, 0, SPBOOK_CLASS, 1, 1 },
+       { SPE_EXTRA_HEALING, 0, SPBOOK_CLASS, 1, 1 },
+       { SPE_STONE_TO_FLESH, 0, SPBOOK_CLASS, 1, 1 },
+       { APPLE, 0, FOOD_CLASS, 5, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Knight[] = {
+       { LONG_SWORD, 1, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { LANCE, 1, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { RING_MAIL, 1, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { HELMET, 0, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { SMALL_SHIELD, 0, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { LEATHER_GLOVES, 0, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { APPLE, 0, FOOD_CLASS, 10, 0 },
+       { CARROT, 0, FOOD_CLASS, 10, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Monk[] = {
+#define M_BOOK         2
+       { LEATHER_GLOVES, 2, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { ROBE, 1, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { UNDEF_TYP, UNDEF_SPE, SPBOOK_CLASS, 1, 1 },
+       { UNDEF_TYP, UNDEF_SPE, SCROLL_CLASS, 1, UNDEF_BLESS },
+       { POT_HEALING, 0, POTION_CLASS, 3, UNDEF_BLESS },
+       { FOOD_RATION, 0, FOOD_CLASS, 3, 0 },
+       { APPLE, 0, FOOD_CLASS, 5, UNDEF_BLESS },
+       { ORANGE, 0, FOOD_CLASS, 5, UNDEF_BLESS },
+       /* Yes, we know fortune cookies aren't really from China.  They were
+        * invented by George Jung in Los Angeles, California, USA in 1916.
+        */
+       { FORTUNE_COOKIE, 0, FOOD_CLASS, 3, UNDEF_BLESS },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Priest[] = {
+       { MACE, 1, WEAPON_CLASS, 1, 1 },
+       { ROBE, 0, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { SMALL_SHIELD, 0, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { POT_WATER, 0, POTION_CLASS, 4, 1 },   /* holy water */
+       { CLOVE_OF_GARLIC, 0, FOOD_CLASS, 1, 0 },
+       { SPRIG_OF_WOLFSBANE, 0, FOOD_CLASS, 1, 0 },
+       { UNDEF_TYP, UNDEF_SPE, SPBOOK_CLASS, 2, UNDEF_BLESS },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Ranger[] = {
+#define RAN_BOW                        1
+#define RAN_TWO_ARROWS 2
+#define RAN_ZERO_ARROWS        3
+       { DAGGER, 1, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { BOW, 1, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { ARROW, 2, WEAPON_CLASS, 50, UNDEF_BLESS },
+       { ARROW, 0, WEAPON_CLASS, 30, UNDEF_BLESS },
+       { CLOAK_OF_DISPLACEMENT, 2, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { CRAM_RATION, 0, FOOD_CLASS, 4, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Rogue[] = {
+#define R_DAGGERS      1
+       { SHORT_SWORD, 0, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { DAGGER, 0, WEAPON_CLASS, 10, 0 },     /* quan is variable */
+       { LEATHER_ARMOR, 1, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { POT_SICKNESS, 0, POTION_CLASS, 1, 0 },
+       { LOCK_PICK, 9, TOOL_CLASS, 1, 0 },
+       { SACK, 0, TOOL_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Samurai[] = {
+#define S_ARROWS       3
+       { KATANA, 0, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { SHORT_SWORD, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, /* wakizashi */
+       { YUMI, 0, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { YA, 0, WEAPON_CLASS, 25, UNDEF_BLESS }, /* variable quan */
+       { SPLINT_MAIL, 0, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { 0, 0, 0, 0, 0 }
+};
+#ifdef TOURIST
+static struct trobj Tourist[] = {
+#define T_DARTS                0
+       { DART, 2, WEAPON_CLASS, 25, UNDEF_BLESS },     /* quan is variable */
+       { UNDEF_TYP, UNDEF_SPE, FOOD_CLASS, 10, 0 },
+       { POT_EXTRA_HEALING, 0, POTION_CLASS, 2, UNDEF_BLESS },
+       { SCR_MAGIC_MAPPING, 0, SCROLL_CLASS, 4, UNDEF_BLESS },
+       { HAWAIIAN_SHIRT, 0, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { EXPENSIVE_CAMERA, UNDEF_SPE, TOOL_CLASS, 1, 0 },
+       { CREDIT_CARD, 0, TOOL_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+#endif
+static struct trobj Valkyrie[] = {
+       { LONG_SWORD, 1, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { DAGGER, 0, WEAPON_CLASS, 1, UNDEF_BLESS },
+       { SMALL_SHIELD, 3, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { FOOD_RATION, 0, FOOD_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Wizard[] = {
+#define W_MULTSTART    2
+#define W_MULTEND      6
+       { QUARTERSTAFF, 1, WEAPON_CLASS, 1, 1 },
+       { CLOAK_OF_MAGIC_RESISTANCE, 0, ARMOR_CLASS, 1, UNDEF_BLESS },
+       { UNDEF_TYP, UNDEF_SPE, WAND_CLASS, 1, UNDEF_BLESS },
+       { UNDEF_TYP, UNDEF_SPE, RING_CLASS, 2, UNDEF_BLESS },
+       { UNDEF_TYP, UNDEF_SPE, POTION_CLASS, 3, UNDEF_BLESS },
+       { UNDEF_TYP, UNDEF_SPE, SCROLL_CLASS, 3, UNDEF_BLESS },
+       { SPE_FORCE_BOLT, 0, SPBOOK_CLASS, 1, 1 },
+       { UNDEF_TYP, UNDEF_SPE, SPBOOK_CLASS, 1, UNDEF_BLESS },
+       { 0, 0, 0, 0, 0 }
+};
+
+/*
+ *     Optional extra inventory items.
+ */
+
+static struct trobj Tinopener[] = {
+       { TIN_OPENER, 0, TOOL_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Magicmarker[] = {
+       { MAGIC_MARKER, UNDEF_SPE, TOOL_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Lamp[] = {
+       { OIL_LAMP, 1, TOOL_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Blindfold[] = {
+       { BLINDFOLD, 0, TOOL_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Instrument[] = {
+       { WOODEN_FLUTE, 0, TOOL_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Xtra_food[] = {
+       { UNDEF_TYP, UNDEF_SPE, FOOD_CLASS, 2, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+#ifdef TOURIST
+static struct trobj Leash[] = {
+       { LEASH, 0, TOOL_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+static struct trobj Towel[] = {
+       { TOWEL, 0, TOOL_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+#endif /* TOURIST */
+static struct trobj Wishing[] = {
+       { WAN_WISHING, 3, WAND_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+#ifdef GOLDOBJ
+static struct trobj Money[] = {
+       { GOLD_PIECE, 0 , COIN_CLASS, 1, 0 },
+       { 0, 0, 0, 0, 0 }
+};
+#endif
+
+/* race-based substitutions for initial inventory;
+   the weaker cloak for elven rangers is intentional--they shoot better */
+static struct inv_sub { short race_pm, item_otyp, subs_otyp; } inv_subs[] = {
+    { PM_ELF,  DAGGER,                 ELVEN_DAGGER          },
+    { PM_ELF,  SPEAR,                  ELVEN_SPEAR           },
+    { PM_ELF,  SHORT_SWORD,            ELVEN_SHORT_SWORD     },
+    { PM_ELF,  BOW,                    ELVEN_BOW             },
+    { PM_ELF,  ARROW,                  ELVEN_ARROW           },
+    { PM_ELF,  HELMET,                 ELVEN_LEATHER_HELM    },
+ /* { PM_ELF,  SMALL_SHIELD,           ELVEN_SHIELD          }, */
+    { PM_ELF,  CLOAK_OF_DISPLACEMENT,  ELVEN_CLOAK           },
+    { PM_ELF,  CRAM_RATION,            LEMBAS_WAFER          },
+    { PM_ORC,  DAGGER,                 ORCISH_DAGGER         },
+    { PM_ORC,  SPEAR,                  ORCISH_SPEAR          },
+    { PM_ORC,  SHORT_SWORD,            ORCISH_SHORT_SWORD    },
+    { PM_ORC,  BOW,                    ORCISH_BOW            },
+    { PM_ORC,  ARROW,                  ORCISH_ARROW          },
+    { PM_ORC,  HELMET,                 ORCISH_HELM           },
+    { PM_ORC,  SMALL_SHIELD,           ORCISH_SHIELD         },
+    { PM_ORC,  RING_MAIL,              ORCISH_RING_MAIL      },
+    { PM_ORC,  CHAIN_MAIL,             ORCISH_CHAIN_MAIL     },
+    { PM_DWARF, SPEAR,                 DWARVISH_SPEAR        },
+    { PM_DWARF, SHORT_SWORD,           DWARVISH_SHORT_SWORD  },
+    { PM_DWARF, HELMET,                        DWARVISH_IRON_HELM    },
+ /* { PM_DWARF, SMALL_SHIELD,          DWARVISH_ROUNDSHIELD  }, */
+ /* { PM_DWARF, PICK_AXE,              DWARVISH_MATTOCK      }, */
+    { PM_GNOME, BOW,                   CROSSBOW              },
+    { PM_GNOME, ARROW,                 CROSSBOW_BOLT         },
+    { NON_PM,  STRANGE_OBJECT,         STRANGE_OBJECT        }
+};
+
+static const struct def_skill Skill_A[] = {
+    { P_DAGGER, P_BASIC },             { P_KNIFE,  P_BASIC },
+    { P_PICK_AXE, P_EXPERT },          { P_SHORT_SWORD, P_BASIC },
+    { P_SCIMITAR, P_SKILLED },         { P_SABER, P_EXPERT },
+    { P_CLUB, P_SKILLED },             { P_QUARTERSTAFF, P_SKILLED },
+    { P_SLING, P_SKILLED },            { P_DART, P_BASIC },
+    { P_BOOMERANG, P_EXPERT },         { P_WHIP, P_EXPERT },
+    { P_UNICORN_HORN, P_SKILLED },
+    { P_ATTACK_SPELL, P_BASIC },       { P_HEALING_SPELL, P_BASIC },
+    { P_DIVINATION_SPELL, P_EXPERT},   { P_MATTER_SPELL, P_BASIC},
+#ifdef STEED
+    { P_RIDING, P_BASIC },
+#endif
+    { P_TWO_WEAPON_COMBAT, P_BASIC },
+    { P_BARE_HANDED_COMBAT, P_EXPERT },
+    { P_NONE, 0 }
+};
+
+static const struct def_skill Skill_B[] = {
+    { P_DAGGER, P_BASIC },             { P_AXE, P_EXPERT },
+    { P_PICK_AXE, P_SKILLED }, { P_SHORT_SWORD, P_EXPERT },
+    { P_BROAD_SWORD, P_SKILLED },      { P_LONG_SWORD, P_SKILLED },
+    { P_TWO_HANDED_SWORD, P_EXPERT },  { P_SCIMITAR, P_SKILLED },
+    { P_SABER, P_BASIC },              { P_CLUB, P_SKILLED },
+    { P_MACE, P_SKILLED },             { P_MORNING_STAR, P_SKILLED },
+    { P_FLAIL, P_BASIC },              { P_HAMMER, P_EXPERT },
+    { P_QUARTERSTAFF, P_BASIC },       { P_SPEAR, P_SKILLED },
+    { P_TRIDENT, P_SKILLED },          { P_BOW, P_BASIC },
+    { P_ATTACK_SPELL, P_SKILLED },
+#ifdef STEED
+    { P_RIDING, P_BASIC },
+#endif
+    { P_TWO_WEAPON_COMBAT, P_BASIC },
+    { P_BARE_HANDED_COMBAT, P_MASTER },
+    { P_NONE, 0 }
+};
+
+static const struct def_skill Skill_C[] = {
+    { P_DAGGER, P_BASIC },             { P_KNIFE,  P_SKILLED },
+    { P_AXE, P_SKILLED },              { P_PICK_AXE, P_BASIC },
+    { P_CLUB, P_EXPERT },              { P_MACE, P_EXPERT },
+    { P_MORNING_STAR, P_BASIC },       { P_FLAIL, P_SKILLED },
+    { P_HAMMER, P_SKILLED },           { P_QUARTERSTAFF, P_EXPERT },
+    { P_POLEARMS, P_SKILLED },         { P_SPEAR, P_EXPERT },
+    { P_JAVELIN, P_SKILLED },          { P_TRIDENT, P_SKILLED },
+    { P_BOW, P_SKILLED },              { P_SLING, P_EXPERT },
+    { P_ATTACK_SPELL, P_BASIC },       { P_MATTER_SPELL, P_SKILLED },
+    { P_BOOMERANG, P_EXPERT },         { P_UNICORN_HORN, P_BASIC },
+    { P_BARE_HANDED_COMBAT, P_MASTER },
+    { P_NONE, 0 }
+};
+
+static const struct def_skill Skill_H[] = {
+    { P_DAGGER, P_SKILLED },           { P_KNIFE, P_EXPERT },
+    { P_SHORT_SWORD, P_SKILLED },      { P_SCIMITAR, P_BASIC },
+    { P_SABER, P_BASIC },              { P_CLUB, P_SKILLED },
+    { P_MACE, P_BASIC },               { P_QUARTERSTAFF, P_EXPERT },
+    { P_POLEARMS, P_BASIC },           { P_SPEAR, P_BASIC },
+    { P_JAVELIN, P_BASIC },            { P_TRIDENT, P_BASIC },
+    { P_SLING, P_SKILLED },            { P_DART, P_EXPERT },
+    { P_SHURIKEN, P_SKILLED },         { P_UNICORN_HORN, P_EXPERT },
+    { P_HEALING_SPELL, P_EXPERT },
+    { P_BARE_HANDED_COMBAT, P_BASIC },
+    { P_NONE, 0 }
+};
+
+static const struct def_skill Skill_K[] = {
+    { P_DAGGER, P_BASIC },             { P_KNIFE, P_BASIC },
+    { P_AXE, P_SKILLED },              { P_PICK_AXE, P_BASIC },
+    { P_SHORT_SWORD, P_SKILLED },      { P_BROAD_SWORD, P_SKILLED },
+    { P_LONG_SWORD, P_EXPERT },        { P_TWO_HANDED_SWORD, P_SKILLED },
+    { P_SCIMITAR, P_BASIC },           { P_SABER, P_SKILLED },
+    { P_CLUB, P_BASIC },               { P_MACE, P_SKILLED },
+    { P_MORNING_STAR, P_SKILLED },     { P_FLAIL, P_BASIC },
+    { P_HAMMER, P_BASIC },             { P_POLEARMS, P_SKILLED },
+    { P_SPEAR, P_SKILLED },            { P_JAVELIN, P_SKILLED },
+    { P_TRIDENT, P_BASIC },            { P_LANCE, P_EXPERT },
+    { P_BOW, P_BASIC },                        { P_CROSSBOW, P_SKILLED },
+    { P_ATTACK_SPELL, P_SKILLED },     { P_HEALING_SPELL, P_SKILLED },
+    { P_CLERIC_SPELL, P_SKILLED },
+#ifdef STEED
+    { P_RIDING, P_EXPERT },
+#endif
+    { P_TWO_WEAPON_COMBAT, P_SKILLED },
+    { P_BARE_HANDED_COMBAT, P_EXPERT },
+    { P_NONE, 0 }
+};
+
+static const struct def_skill Skill_Mon[] = {
+    { P_QUARTERSTAFF, P_BASIC },    { P_SPEAR, P_BASIC },
+    { P_JAVELIN, P_BASIC },                { P_CROSSBOW, P_BASIC },
+    { P_SHURIKEN, P_BASIC },
+    { P_ATTACK_SPELL, P_BASIC },    { P_HEALING_SPELL, P_EXPERT },
+    { P_DIVINATION_SPELL, P_BASIC },{ P_ENCHANTMENT_SPELL, P_BASIC },
+    { P_CLERIC_SPELL, P_SKILLED },  { P_ESCAPE_SPELL, P_BASIC },
+    { P_MATTER_SPELL, P_BASIC },
+    { P_MARTIAL_ARTS, P_GRAND_MASTER },
+    { P_NONE, 0 }
+};
+
+static const struct def_skill Skill_P[] = {
+    { P_CLUB, P_EXPERT },              { P_MACE, P_EXPERT },
+    { P_MORNING_STAR, P_EXPERT },      { P_FLAIL, P_EXPERT },
+    { P_HAMMER, P_EXPERT },            { P_QUARTERSTAFF, P_EXPERT },
+    { P_POLEARMS, P_SKILLED },         { P_SPEAR, P_SKILLED },
+    { P_JAVELIN, P_SKILLED },          { P_TRIDENT, P_SKILLED },
+    { P_LANCE, P_BASIC },              { P_BOW, P_BASIC },
+    { P_SLING, P_BASIC },              { P_CROSSBOW, P_BASIC },
+    { P_DART, P_BASIC },               { P_SHURIKEN, P_BASIC },
+    { P_BOOMERANG, P_BASIC },          { P_UNICORN_HORN, P_SKILLED },
+    { P_HEALING_SPELL, P_EXPERT },     { P_DIVINATION_SPELL, P_EXPERT },
+    { P_CLERIC_SPELL, P_EXPERT },
+    { P_BARE_HANDED_COMBAT, P_BASIC },
+    { P_NONE, 0 }
+};
+
+static const struct def_skill Skill_R[] = {
+    { P_DAGGER, P_EXPERT },            { P_KNIFE,  P_EXPERT },
+    { P_SHORT_SWORD, P_EXPERT },       { P_BROAD_SWORD, P_SKILLED },
+    { P_LONG_SWORD, P_SKILLED },       { P_TWO_HANDED_SWORD, P_BASIC },
+    { P_SCIMITAR, P_SKILLED },         { P_SABER, P_SKILLED },
+    { P_CLUB, P_SKILLED },             { P_MACE, P_SKILLED },
+    { P_MORNING_STAR, P_BASIC },       { P_FLAIL, P_BASIC },
+    { P_HAMMER, P_BASIC },             { P_POLEARMS, P_BASIC },
+    { P_SPEAR, P_BASIC },              { P_CROSSBOW, P_EXPERT },
+    { P_DART, P_EXPERT },              { P_SHURIKEN, P_SKILLED },
+    { P_DIVINATION_SPELL, P_SKILLED }, { P_ESCAPE_SPELL, P_SKILLED },
+    { P_MATTER_SPELL, P_SKILLED },
+#ifdef STEED
+    { P_RIDING, P_BASIC },
+#endif
+    { P_TWO_WEAPON_COMBAT, P_EXPERT },
+    { P_BARE_HANDED_COMBAT, P_EXPERT },
+    { P_NONE, 0 }
+};
+
+static const struct def_skill Skill_Ran[] = {
+    { P_DAGGER, P_EXPERT },             { P_KNIFE,  P_SKILLED },
+    { P_AXE, P_SKILLED },       { P_PICK_AXE, P_BASIC },
+    { P_SHORT_SWORD, P_BASIC },         { P_MORNING_STAR, P_BASIC },
+    { P_FLAIL, P_SKILLED },     { P_HAMMER, P_BASIC },
+    { P_QUARTERSTAFF, P_BASIC }, { P_POLEARMS, P_SKILLED },
+    { P_SPEAR, P_SKILLED },     { P_JAVELIN, P_EXPERT },
+    { P_TRIDENT, P_BASIC },     { P_BOW, P_EXPERT },
+    { P_SLING, P_EXPERT },      { P_CROSSBOW, P_EXPERT },
+    { P_DART, P_EXPERT },       { P_SHURIKEN, P_SKILLED },
+    { P_BOOMERANG, P_EXPERT },  { P_WHIP, P_BASIC },
+    { P_HEALING_SPELL, P_BASIC },
+    { P_DIVINATION_SPELL, P_EXPERT },
+    { P_ESCAPE_SPELL, P_BASIC },
+#ifdef STEED
+    { P_RIDING, P_BASIC },
+#endif
+    { P_BARE_HANDED_COMBAT, P_BASIC },
+    { P_NONE, 0 }
+};
+
+static const struct def_skill Skill_S[] = {
+    { P_DAGGER, P_BASIC },             { P_KNIFE,  P_SKILLED },
+    { P_SHORT_SWORD, P_EXPERT },       { P_BROAD_SWORD, P_SKILLED },
+    { P_LONG_SWORD, P_EXPERT },                { P_TWO_HANDED_SWORD, P_EXPERT },
+    { P_SCIMITAR, P_BASIC },           { P_SABER, P_BASIC },
+    { P_FLAIL, P_SKILLED },            { P_QUARTERSTAFF, P_BASIC },
+    { P_POLEARMS, P_SKILLED },         { P_SPEAR, P_BASIC },
+    { P_JAVELIN, P_BASIC },            { P_LANCE, P_SKILLED },
+    { P_BOW, P_EXPERT },               { P_SHURIKEN, P_EXPERT },
+    { P_ATTACK_SPELL, P_SKILLED },     { P_CLERIC_SPELL, P_SKILLED },
+#ifdef STEED
+    { P_RIDING, P_SKILLED },
+#endif
+    { P_TWO_WEAPON_COMBAT, P_EXPERT },
+    { P_MARTIAL_ARTS, P_MASTER },
+    { P_NONE, 0 }
+};
+
+#ifdef TOURIST
+static const struct def_skill Skill_T[] = {
+    { P_DAGGER, P_EXPERT },            { P_KNIFE,  P_SKILLED },
+    { P_AXE, P_BASIC },                        { P_PICK_AXE, P_BASIC },
+    { P_SHORT_SWORD, P_EXPERT },       { P_BROAD_SWORD, P_BASIC },
+    { P_LONG_SWORD, P_BASIC },         { P_TWO_HANDED_SWORD, P_BASIC },
+    { P_SCIMITAR, P_SKILLED },         { P_SABER, P_SKILLED },
+    { P_MACE, P_BASIC },               { P_MORNING_STAR, P_BASIC },
+    { P_FLAIL, P_BASIC },              { P_HAMMER, P_BASIC },
+    { P_QUARTERSTAFF, P_BASIC },       { P_POLEARMS, P_BASIC },
+    { P_SPEAR, P_BASIC },              { P_JAVELIN, P_BASIC },
+    { P_TRIDENT, P_BASIC },            { P_LANCE, P_BASIC },
+    { P_BOW, P_BASIC },                        { P_SLING, P_BASIC },
+    { P_CROSSBOW, P_BASIC },           { P_DART, P_EXPERT },
+    { P_SHURIKEN, P_BASIC },           { P_BOOMERANG, P_BASIC },
+    { P_WHIP, P_BASIC },               { P_UNICORN_HORN, P_SKILLED },
+    { P_DIVINATION_SPELL, P_BASIC },   { P_ENCHANTMENT_SPELL, P_BASIC },
+    { P_ESCAPE_SPELL, P_SKILLED },
+#ifdef STEED
+    { P_RIDING, P_BASIC },
+#endif
+    { P_TWO_WEAPON_COMBAT, P_SKILLED },
+    { P_BARE_HANDED_COMBAT, P_SKILLED },
+    { P_NONE, 0 }
+};
+#endif /* TOURIST */
+
+static const struct def_skill Skill_V[] = {
+    { P_DAGGER, P_EXPERT },            { P_AXE, P_EXPERT },
+    { P_PICK_AXE, P_SKILLED },         { P_SHORT_SWORD, P_SKILLED },
+    { P_BROAD_SWORD, P_SKILLED },      { P_LONG_SWORD, P_EXPERT },
+    { P_TWO_HANDED_SWORD, P_EXPERT },  { P_SCIMITAR, P_BASIC },
+    { P_SABER, P_BASIC },              { P_HAMMER, P_EXPERT },
+    { P_QUARTERSTAFF, P_BASIC },       { P_POLEARMS, P_SKILLED },
+    { P_SPEAR, P_SKILLED },            { P_JAVELIN, P_BASIC },
+    { P_TRIDENT, P_BASIC },            { P_LANCE, P_SKILLED },
+    { P_SLING, P_BASIC },
+    { P_ATTACK_SPELL, P_BASIC },       { P_ESCAPE_SPELL, P_BASIC },
+#ifdef STEED
+    { P_RIDING, P_SKILLED },
+#endif
+    { P_TWO_WEAPON_COMBAT, P_SKILLED },
+    { P_BARE_HANDED_COMBAT, P_EXPERT },
+    { P_NONE, 0 }
+};
+
+static const struct def_skill Skill_W[] = {
+    { P_DAGGER, P_EXPERT },            { P_KNIFE,  P_SKILLED },
+    { P_AXE, P_SKILLED },              { P_SHORT_SWORD, P_BASIC },
+    { P_CLUB, P_SKILLED },             { P_MACE, P_BASIC },
+    { P_QUARTERSTAFF, P_EXPERT },      { P_POLEARMS, P_SKILLED },
+    { P_SPEAR, P_BASIC },              { P_JAVELIN, P_BASIC },
+    { P_TRIDENT, P_BASIC },            { P_SLING, P_SKILLED },
+    { P_DART, P_EXPERT },              { P_SHURIKEN, P_BASIC },
+    { P_ATTACK_SPELL, P_EXPERT },      { P_HEALING_SPELL, P_SKILLED },
+    { P_DIVINATION_SPELL, P_EXPERT },  { P_ENCHANTMENT_SPELL, P_SKILLED },
+    { P_CLERIC_SPELL, P_SKILLED },     { P_ESCAPE_SPELL, P_EXPERT },
+    { P_MATTER_SPELL, P_EXPERT },
+#ifdef STEED
+    { P_RIDING, P_BASIC },
+#endif
+    { P_BARE_HANDED_COMBAT, P_BASIC },
+    { P_NONE, 0 }
+};
+
+
+STATIC_OVL void
+knows_object(obj)
+register int obj;
+{
+       discover_object(obj,TRUE,FALSE);
+       objects[obj].oc_pre_discovered = 1;     /* not a "discovery" */
+}
+
+/* Know ordinary (non-magical) objects of a certain class,
+ * like all gems except the loadstone and luckstone.
+ */
+STATIC_OVL void
+knows_class(sym)
+register char sym;
+{
+       register int ct;
+       for (ct = 1; ct < NUM_OBJECTS; ct++)
+               if (objects[ct].oc_class == sym && !objects[ct].oc_magic)
+                       knows_object(ct);
+}
+
+void
+u_init()
+{
+       register int i;
+
+       flags.female = flags.initgend;
+       flags.beginner = 1;
+
+       /* zero u, including pointer values --
+        * necessary when aborting from a failed restore */
+       (void) memset((genericptr_t)&u, 0, sizeof(u));
+       u.ustuck = (struct monst *)0;
+
+#if 0  /* documentation of more zero values as desirable */
+       u.usick_cause[0] = 0;
+       u.uluck  = u.moreluck = 0;
+# ifdef TOURIST
+       uarmu = 0;
+# endif
+       uarm = uarmc = uarmh = uarms = uarmg = uarmf = 0;
+       uwep = uball = uchain = uleft = uright = 0;
+       uswapwep = uquiver = 0;
+       u.twoweap = 0;
+       u.ublessed = 0;                         /* not worthy yet */
+       u.ugangr   = 0;                         /* gods not angry */
+       u.ugifts   = 0;                         /* no divine gifts bestowed */
+# ifdef ELBERETH
+       u.uevent.uhand_of_elbereth = 0;
+# endif
+       u.uevent.uheard_tune = 0;
+       u.uevent.uopened_dbridge = 0;
+       u.uevent.udemigod = 0;          /* not a demi-god yet... */
+       u.udg_cnt = 0;
+       u.mh = u.mhmax = u.mtimedone = 0;
+       u.uz.dnum = u.uz0.dnum = 0;
+       u.utotype = 0;
+#endif /* 0 */
+
+       u.uz.dlevel = 1;
+       u.uz0.dlevel = 0;
+       u.utolev = u.uz;
+
+       u.umoved = FALSE;
+       u.umortality = 0;
+       u.ugrave_arise = NON_PM;
+
+       u.umonnum = u.umonster = (flags.female &&
+                       urole.femalenum != NON_PM) ? urole.femalenum :
+                       urole.malenum;
+       set_uasmon();
+
+       u.ulevel = 0;   /* set up some of the initial attributes */
+       u.uhp = u.uhpmax = newhp();
+       u.uenmax = urole.enadv.infix + urace.enadv.infix;
+       if (urole.enadv.inrnd > 0)
+           u.uenmax += rnd(urole.enadv.inrnd);
+       if (urace.enadv.inrnd > 0)
+           u.uenmax += rnd(urace.enadv.inrnd);
+       u.uen = u.uenmax;
+       u.uspellprot = 0;
+       adjabil(0,1);
+       u.ulevel = u.ulevelmax = 1;
+
+       init_uhunger();
+       for (i = 0; i <= MAXSPELL; i++) spl_book[i].sp_id = NO_SPELL;
+       u.ublesscnt = 300;                      /* no prayers just yet */
+       u.ualignbase[A_CURRENT] = u.ualignbase[A_ORIGINAL] = u.ualign.type =
+                       aligns[flags.initalign].value;
+       u.ulycn = NON_PM;
+
+#if defined(BSD) && !defined(POSIX_TYPES)
+       (void) time((long *)&u.ubirthday);
+#else
+       (void) time(&u.ubirthday);
+#endif
+
+       /*
+        *  For now, everyone starts out with a night vision range of 1 and
+        *  their xray range disabled.
+        */
+       u.nv_range   =  1;
+       u.xray_range = -1;
+
+
+       /*** Role-specific initializations ***/
+       switch (Role_switch) {
+       /* rn2(100) > 50 necessary for some choices because some
+        * random number generators are bad enough to seriously
+        * skew the results if we use rn2(2)...  --KAA
+        */
+       case PM_ARCHEOLOGIST:
+               ini_inv(Archeologist);
+               if(!rn2(10)) ini_inv(Tinopener);
+               else if(!rn2(4)) ini_inv(Lamp);
+               else if(!rn2(10)) ini_inv(Magicmarker);
+               knows_object(SACK);
+               knows_object(TOUCHSTONE);
+               skill_init(Skill_A);
+               break;
+       case PM_BARBARIAN:
+               if (rn2(100) >= 50) {   /* see above comment */
+                   Barbarian[B_MAJOR].trotyp = BATTLE_AXE;
+                   Barbarian[B_MINOR].trotyp = SHORT_SWORD;
+               }
+               ini_inv(Barbarian);
+               if(!rn2(6)) ini_inv(Lamp);
+               knows_class(WEAPON_CLASS);
+               knows_class(ARMOR_CLASS);
+               skill_init(Skill_B);
+               break;
+       case PM_CAVEMAN:
+               Cave_man[C_AMMO].trquan = rn1(11, 10);  /* 10..20 */
+               ini_inv(Cave_man);
+               skill_init(Skill_C);
+               break;
+       case PM_HEALER:
+#ifndef GOLDOBJ
+               u.ugold = u.ugold0 = rn1(1000, 1001);
+#else
+               u.umoney0 = rn1(1000, 1001);
+#endif
+               ini_inv(Healer);
+               if(!rn2(25)) ini_inv(Lamp);
+               knows_object(POT_FULL_HEALING);
+               skill_init(Skill_H);
+               break;
+       case PM_KNIGHT:
+               ini_inv(Knight);
+               knows_class(WEAPON_CLASS);
+               knows_class(ARMOR_CLASS);
+               /* give knights chess-like mobility
+                * -- idea from wooledge@skybridge.scl.cwru.edu */
+               HJumping |= FROMOUTSIDE;
+               skill_init(Skill_K);
+               break;
+       case PM_MONK:
+               switch (rn2(90) / 30) {
+               case 0: Monk[M_BOOK].trotyp = SPE_HEALING; break;
+               case 1: Monk[M_BOOK].trotyp = SPE_PROTECTION; break;
+               case 2: Monk[M_BOOK].trotyp = SPE_SLEEP; break;
+               }
+               ini_inv(Monk);
+               if(!rn2(5)) ini_inv(Magicmarker);
+               else if(!rn2(10)) ini_inv(Lamp);
+               knows_class(ARMOR_CLASS);
+               skill_init(Skill_Mon);
+               break;
+       case PM_PRIEST:
+               ini_inv(Priest);
+               if(!rn2(10)) ini_inv(Magicmarker);
+               else if(!rn2(10)) ini_inv(Lamp);
+               knows_object(POT_WATER);
+               skill_init(Skill_P);
+               /* KMH, conduct --
+                * Some may claim that this isn't agnostic, since they
+                * are literally "priests" and they have holy water.
+                * But we don't count it as such.  Purists can always
+                * avoid playing priests and/or confirm another player's
+                * role in their YAAP.
+                */
+               break;
+       case PM_RANGER:
+               Ranger[RAN_TWO_ARROWS].trquan = rn1(10, 50);
+               Ranger[RAN_ZERO_ARROWS].trquan = rn1(10, 30);
+               ini_inv(Ranger);
+               skill_init(Skill_Ran);
+               break;
+       case PM_ROGUE:
+               Rogue[R_DAGGERS].trquan = rn1(10, 6);
+#ifndef GOLDOBJ
+               u.ugold = u.ugold0 = 0;
+#else
+               u.umoney0 = 0;
+#endif
+               ini_inv(Rogue);
+               if(!rn2(5)) ini_inv(Blindfold);
+               knows_object(SACK);
+               skill_init(Skill_R);
+               break;
+       case PM_SAMURAI:
+               Samurai[S_ARROWS].trquan = rn1(20, 26);
+               ini_inv(Samurai);
+               if(!rn2(5)) ini_inv(Blindfold);
+               knows_class(WEAPON_CLASS);
+               knows_class(ARMOR_CLASS);
+               skill_init(Skill_S);
+               break;
+#ifdef TOURIST
+       case PM_TOURIST:
+               Tourist[T_DARTS].trquan = rn1(20, 21);
+#ifndef GOLDOBJ
+               u.ugold = u.ugold0 = rnd(1000);
+#else
+               u.umoney0 = rnd(1000);
+#endif
+               ini_inv(Tourist);
+               if(!rn2(25)) ini_inv(Tinopener);
+               else if(!rn2(25)) ini_inv(Leash);
+               else if(!rn2(25)) ini_inv(Towel);
+               else if(!rn2(25)) ini_inv(Magicmarker);
+               skill_init(Skill_T);
+               break;
+#endif
+       case PM_VALKYRIE:
+               ini_inv(Valkyrie);
+               if(!rn2(6)) ini_inv(Lamp);
+               knows_class(WEAPON_CLASS);
+               knows_class(ARMOR_CLASS);
+               skill_init(Skill_V);
+               break;
+       case PM_WIZARD:
+               ini_inv(Wizard);
+               if(!rn2(5)) ini_inv(Magicmarker);
+               if(!rn2(5)) ini_inv(Blindfold);
+               skill_init(Skill_W);
+               break;
+
+       default:        /* impossible */
+               break;
+       }
+
+
+       /*** Race-specific initializations ***/
+       switch (Race_switch) {
+       case PM_HUMAN:
+           /* Nothing special */
+           break;
+
+       case PM_ELF:
+           /*
+            * Elves are people of music and song, or they are warriors.
+            * Non-warriors get an instrument.  We use a kludge to
+            * get only non-magic instruments.
+            */
+           if (Role_if(PM_PRIEST) || Role_if(PM_WIZARD)) {
+               static int trotyp[] = {
+                   WOODEN_FLUTE, TOOLED_HORN, WOODEN_HARP,
+                   BELL, BUGLE, LEATHER_DRUM
+               };
+               Instrument[0].trotyp = trotyp[rn2(SIZE(trotyp))];
+               ini_inv(Instrument);
+           }
+
+           /* Elves can recognize all elvish objects */
+           knows_object(ELVEN_SHORT_SWORD);
+           knows_object(ELVEN_ARROW);
+           knows_object(ELVEN_BOW);
+           knows_object(ELVEN_SPEAR);
+           knows_object(ELVEN_DAGGER);
+           knows_object(ELVEN_BROADSWORD);
+           knows_object(ELVEN_MITHRIL_COAT);
+           knows_object(ELVEN_LEATHER_HELM);
+           knows_object(ELVEN_SHIELD);
+           knows_object(ELVEN_BOOTS);
+           knows_object(ELVEN_CLOAK);
+           break;
+
+       case PM_DWARF:
+           /* Dwarves can recognize all dwarvish objects */
+           knows_object(DWARVISH_SPEAR);
+           knows_object(DWARVISH_SHORT_SWORD);
+           knows_object(DWARVISH_MATTOCK);
+           knows_object(DWARVISH_IRON_HELM);
+           knows_object(DWARVISH_MITHRIL_COAT);
+           knows_object(DWARVISH_CLOAK);
+           knows_object(DWARVISH_ROUNDSHIELD);
+           break;
+
+       case PM_GNOME:
+           break;
+
+       case PM_ORC:
+           /* compensate for generally inferior equipment */
+           if (!Role_if(PM_WIZARD))
+               ini_inv(Xtra_food);
+           /* Orcs can recognize all orcish objects */
+           knows_object(ORCISH_SHORT_SWORD);
+           knows_object(ORCISH_ARROW);
+           knows_object(ORCISH_BOW);
+           knows_object(ORCISH_SPEAR);
+           knows_object(ORCISH_DAGGER);
+           knows_object(ORCISH_CHAIN_MAIL);
+           knows_object(ORCISH_RING_MAIL);
+           knows_object(ORCISH_HELM);
+           knows_object(ORCISH_SHIELD);
+           knows_object(URUK_HAI_SHIELD);
+           knows_object(ORCISH_CLOAK);
+           break;
+
+       default:        /* impossible */
+               break;
+       }
+
+       if (discover)
+               ini_inv(Wishing);
+
+#ifdef WIZARD
+       if (wizard)
+               read_wizkit();
+#endif
+
+#ifndef GOLDOBJ
+       u.ugold0 += hidden_gold();      /* in case sack has gold in it */
+#else
+       if (u.umoney0) ini_inv(Money);
+       u.umoney0 += hidden_gold();     /* in case sack has gold in it */
+#endif
+
+       find_ac();                      /* get initial ac value */
+       init_attr(75);                  /* init attribute values */
+       max_rank_sz();                  /* set max str size for class ranks */
+/*
+ *     Do we really need this?
+ */
+       for(i = 0; i < A_MAX; i++)
+           if(!rn2(20)) {
+               register int xd = rn2(7) - 2;   /* biased variation */
+               (void) adjattrib(i, xd, TRUE);
+               if (ABASE(i) < AMAX(i)) AMAX(i) = ABASE(i);
+           }
+
+       /* make sure you can carry all you have - especially for Tourists */
+       while (inv_weight() > 0) {
+               if (adjattrib(A_STR, 1, TRUE)) continue;
+               if (adjattrib(A_CON, 1, TRUE)) continue;
+               /* only get here when didn't boost strength or constitution */
+               break;
+       }
+
+       return;
+}
+
+/* skills aren't initialized, so we use the role-specific skill lists */
+STATIC_OVL boolean
+restricted_spell_discipline(otyp)
+int otyp;
+{
+    const struct def_skill *skills;
+    int this_skill = spell_skilltype(otyp);
+
+    switch (Role_switch) {
+     case PM_ARCHEOLOGIST:     skills = Skill_A; break;
+     case PM_BARBARIAN:                skills = Skill_B; break;
+     case PM_CAVEMAN:          skills = Skill_C; break;
+     case PM_HEALER:           skills = Skill_H; break;
+     case PM_KNIGHT:           skills = Skill_K; break;
+     case PM_MONK:             skills = Skill_Mon; break;
+     case PM_PRIEST:           skills = Skill_P; break;
+     case PM_RANGER:           skills = Skill_Ran; break;
+     case PM_ROGUE:            skills = Skill_R; break;
+     case PM_SAMURAI:          skills = Skill_S; break;
+#ifdef TOURIST
+     case PM_TOURIST:          skills = Skill_T; break;
+#endif
+     case PM_VALKYRIE:         skills = Skill_V; break;
+     case PM_WIZARD:           skills = Skill_W; break;
+     default:                  skills = 0; break;      /* lint suppression */
+    }
+
+    while (skills->skill != P_NONE) {
+       if (skills->skill == this_skill) return FALSE;
+       ++skills;
+    }
+    return TRUE;
+}
+
+STATIC_OVL void
+ini_inv(trop)
+register struct trobj *trop;
+{
+       struct obj *obj;
+       int otyp, i;
+
+       while (trop->trclass) {
+               if (trop->trotyp != UNDEF_TYP) {
+                       otyp = (int)trop->trotyp;
+                       if (urace.malenum != PM_HUMAN) {
+                           /* substitute specific items for generic ones */
+                           for (i = 0; inv_subs[i].race_pm != NON_PM; ++i)
+                               if (inv_subs[i].race_pm == urace.malenum &&
+                                       otyp == inv_subs[i].item_otyp) {
+                                   otyp = inv_subs[i].subs_otyp;
+                                   break;
+                               }
+                       }
+                       obj = mksobj(otyp, TRUE, FALSE);
+               } else {        /* UNDEF_TYP */
+                       static NEARDATA short nocreate = STRANGE_OBJECT;
+                       static NEARDATA short nocreate2 = STRANGE_OBJECT;
+                       static NEARDATA short nocreate3 = STRANGE_OBJECT;
+                       static NEARDATA short nocreate4 = STRANGE_OBJECT;
+               /*
+                * For random objects, do not create certain overly powerful
+                * items: wand of wishing, ring of levitation, or the
+                * polymorph/polymorph control combination.  Specific objects,
+                * i.e. the discovery wishing, are still OK.
+                * Also, don't get a couple of really useless items.  (Note:
+                * punishment isn't "useless".  Some players who start out with
+                * one will immediately read it and use the iron ball as a
+                * weapon.)
+                */
+                       obj = mkobj(trop->trclass, FALSE);
+                       otyp = obj->otyp;
+                       while (otyp == WAN_WISHING
+                               || otyp == nocreate
+                               || otyp == nocreate2
+                               || otyp == nocreate3
+                               || otyp == nocreate4
+#ifdef ELBERETH
+                               || otyp == RIN_LEVITATION
+#endif
+                               /* 'useless' items */
+                               || otyp == POT_HALLUCINATION
+                               || otyp == POT_ACID
+                               || otyp == SCR_AMNESIA
+                               || otyp == SCR_FIRE
+                               || otyp == SCR_BLANK_PAPER
+                               || otyp == SPE_BLANK_PAPER
+                               || otyp == RIN_AGGRAVATE_MONSTER
+                               || otyp == RIN_HUNGER
+                               || otyp == WAN_NOTHING
+                               /* Monks don't use weapons */
+                               || (otyp == SCR_ENCHANT_WEAPON &&
+                                   Role_if(PM_MONK))
+                               /* wizard patch -- they already have one */
+                               || (otyp == SPE_FORCE_BOLT &&
+                                   Role_if(PM_WIZARD))
+                               /* powerful spells are either useless to
+                                  low level players or unbalancing; also
+                                  spells in restricted skill categories */
+                               || (obj->oclass == SPBOOK_CLASS &&
+                                   (objects[otyp].oc_level > 3 ||
+                                   restricted_spell_discipline(otyp)))
+                                                       ) {
+                               dealloc_obj(obj);
+                               obj = mkobj(trop->trclass, FALSE);
+                               otyp = obj->otyp;
+                       }
+
+                       /* Don't start with +0 or negative rings */
+                       if (objects[otyp].oc_charged && obj->spe <= 0)
+                               obj->spe = rne(3);
+
+                       /* Heavily relies on the fact that 1) we create wands
+                        * before rings, 2) that we create rings before
+                        * spellbooks, and that 3) not more than 1 object of a
+                        * particular symbol is to be prohibited.  (For more
+                        * objects, we need more nocreate variables...)
+                        */
+                       switch (otyp) {
+                           case WAN_POLYMORPH:
+                           case RIN_POLYMORPH:
+                           case POT_POLYMORPH:
+                               nocreate = RIN_POLYMORPH_CONTROL;
+                               break;
+                           case RIN_POLYMORPH_CONTROL:
+                               nocreate = RIN_POLYMORPH;
+                               nocreate2 = SPE_POLYMORPH;
+                               nocreate3 = POT_POLYMORPH;
+                       }
+                       /* Don't have 2 of the same ring or spellbook */
+                       if (obj->oclass == RING_CLASS ||
+                           obj->oclass == SPBOOK_CLASS)
+                               nocreate4 = otyp;
+               }
+
+#ifdef GOLDOBJ
+               if (trop->trclass == COIN_CLASS) {
+                       /* no "blessed" or "identified" money */
+                       obj->quan = u.umoney0;
+               } else {
+#endif
+                       obj->dknown = obj->bknown = obj->rknown = 1;
+                       if (objects[otyp].oc_uses_known) obj->known = 1;
+                       obj->cursed = 0;
+                       if (obj->opoisoned && u.ualign.type != A_CHAOTIC)
+                           obj->opoisoned = 0;
+                       if (obj->oclass == WEAPON_CLASS ||
+                               obj->oclass == TOOL_CLASS) {
+                           obj->quan = (long) trop->trquan;
+                           trop->trquan = 1;
+                       } else if (obj->oclass == GEM_CLASS &&
+                               is_graystone(obj) && obj->otyp != FLINT) {
+                           obj->quan = 1L;
+                       }
+                       if (trop->trspe != UNDEF_SPE)
+                           obj->spe = trop->trspe;
+                       if (trop->trbless != UNDEF_BLESS)
+                           obj->blessed = trop->trbless;
+#ifdef GOLDOBJ
+               }
+#endif
+               /* defined after setting otyp+quan + blessedness */
+               obj->owt = weight(obj);
+               obj = addinv(obj);
+
+               /* Make the type known if necessary */
+               if (OBJ_DESCR(objects[otyp]) && obj->known)
+                       discover_object(otyp, TRUE, FALSE);
+               if (otyp == OIL_LAMP)
+                       discover_object(POT_OIL, TRUE, FALSE);
+
+               if(obj->oclass == ARMOR_CLASS){
+                       if (is_shield(obj) && !uarms) {
+                               setworn(obj, W_ARMS);
+                               if (uswapwep) setuswapwep((struct obj *) 0);
+                       } else if (is_helmet(obj) && !uarmh)
+                               setworn(obj, W_ARMH);
+                       else if (is_gloves(obj) && !uarmg)
+                               setworn(obj, W_ARMG);
+#ifdef TOURIST
+                       else if (is_shirt(obj) && !uarmu)
+                               setworn(obj, W_ARMU);
+#endif
+                       else if (is_cloak(obj) && !uarmc)
+                               setworn(obj, W_ARMC);
+                       else if (is_boots(obj) && !uarmf)
+                               setworn(obj, W_ARMF);
+                       else if (is_suit(obj) && !uarm)
+                               setworn(obj, W_ARM);
+               }
+
+               if (obj->oclass == WEAPON_CLASS || is_weptool(obj) ||
+                       otyp == TIN_OPENER || otyp == FLINT || otyp == ROCK) {
+                   if (is_ammo(obj) || is_missile(obj)) {
+                       if (!uquiver) setuqwep(obj);
+                   } else if (!uwep) setuwep(obj);
+                   else if (!uswapwep) setuswapwep(obj);
+               }
+               if (obj->oclass == SPBOOK_CLASS &&
+                               obj->otyp != SPE_BLANK_PAPER)
+                   initialspell(obj);
+
+#if !defined(PYRAMID_BUG) && !defined(MAC)
+               if(--trop->trquan) continue;    /* make a similar object */
+#else
+               if(trop->trquan) {              /* check if zero first */
+                       --trop->trquan;
+                       if(trop->trquan)
+                               continue;       /* make a similar object */
+               }
+#endif
+               trop++;
+       }
+}
+
+/*u_init.c*/
diff --git a/src/uhitm.c b/src/uhitm.c
new file mode 100644 (file)
index 0000000..3dd028a
--- /dev/null
@@ -0,0 +1,2512 @@
+/*     SCCS Id: @(#)uhitm.c    3.4     2003/02/18      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+STATIC_DCL boolean FDECL(known_hitum, (struct monst *,int *,struct attack *));
+STATIC_DCL void FDECL(steal_it, (struct monst *, struct attack *));
+STATIC_DCL boolean FDECL(hitum, (struct monst *,int,struct attack *));
+STATIC_DCL boolean FDECL(hmon_hitmon, (struct monst *,struct obj *,int));
+#ifdef STEED
+STATIC_DCL int FDECL(joust, (struct monst *,struct obj *));
+#endif
+STATIC_DCL void NDECL(demonpet);
+STATIC_DCL boolean FDECL(m_slips_free, (struct monst *mtmp,struct attack *mattk));
+STATIC_DCL int FDECL(explum, (struct monst *,struct attack *));
+STATIC_DCL void FDECL(start_engulf, (struct monst *));
+STATIC_DCL void NDECL(end_engulf);
+STATIC_DCL int FDECL(gulpum, (struct monst *,struct attack *));
+STATIC_DCL boolean FDECL(hmonas, (struct monst *,int));
+STATIC_DCL void FDECL(nohandglow, (struct monst *));
+STATIC_DCL boolean FDECL(shade_aware, (struct obj *));
+
+extern boolean notonhead;      /* for long worms */
+/* The below might become a parameter instead if we use it a lot */
+static int dieroll;
+/* Used to flag attacks caused by Stormbringer's maliciousness. */
+static boolean override_confirmation = FALSE;
+
+#define PROJECTILE(obj)        ((obj) && is_ammo(obj))
+
+/* modified from hurtarmor() in mhitu.c */
+/* This is not static because it is also used for monsters rusting monsters */
+void
+hurtmarmor(mdef, attk)
+struct monst *mdef;
+int attk;
+{
+       int     hurt;
+       struct obj *target;
+
+       switch(attk) {
+           /* 0 is burning, which we should never be called with */
+           case AD_RUST: hurt = 1; break;
+           case AD_CORR: hurt = 3; break;
+           default: hurt = 2; break;
+       }
+       /* What the following code does: it keeps looping until it
+        * finds a target for the rust monster.
+        * Head, feet, etc... not covered by metal, or covered by
+        * rusty metal, are not targets.  However, your body always
+        * is, no matter what covers it.
+        */
+       while (1) {
+           switch(rn2(5)) {
+           case 0:
+               target = which_armor(mdef, W_ARMH);
+               if (!target || !rust_dmg(target, xname(target), hurt, FALSE, mdef))
+                   continue;
+               break;
+           case 1:
+               target = which_armor(mdef, W_ARMC);
+               if (target) {
+                   (void)rust_dmg(target, xname(target), hurt, TRUE, mdef);
+                   break;
+               }
+               if ((target = which_armor(mdef, W_ARM)) != (struct obj *)0) {
+                   (void)rust_dmg(target, xname(target), hurt, TRUE, mdef);
+#ifdef TOURIST
+               } else if ((target = which_armor(mdef, W_ARMU)) != (struct obj *)0) {
+                   (void)rust_dmg(target, xname(target), hurt, TRUE, mdef);
+#endif
+               }
+               break;
+           case 2:
+               target = which_armor(mdef, W_ARMS);
+               if (!target || !rust_dmg(target, xname(target), hurt, FALSE, mdef))
+                   continue;
+               break;
+           case 3:
+               target = which_armor(mdef, W_ARMG);
+               if (!target || !rust_dmg(target, xname(target), hurt, FALSE, mdef))
+                   continue;
+               break;
+           case 4:
+               target = which_armor(mdef, W_ARMF);
+               if (!target || !rust_dmg(target, xname(target), hurt, FALSE, mdef))
+                   continue;
+               break;
+           }
+           break; /* Out of while loop */
+       }
+}
+
+/* FALSE means it's OK to attack */
+boolean
+attack_checks(mtmp, wep)
+register struct monst *mtmp;
+struct obj *wep;       /* uwep for attack(), null for kick_monster() */
+{
+       char qbuf[QBUFSZ];
+
+       /* if you're close enough to attack, alert any waiting monster */
+       mtmp->mstrategy &= ~STRAT_WAITMASK;
+
+       if (u.uswallow && mtmp == u.ustuck) return FALSE;
+
+       if (flags.forcefight) {
+               /* Do this in the caller, after we checked that the monster
+                * didn't die from the blow.  Reason: putting the 'I' there
+                * causes the hero to forget the square's contents since
+                * both 'I' and remembered contents are stored in .glyph.
+                * If the monster dies immediately from the blow, the 'I' will
+                * not stay there, so the player will have suddenly forgotten
+                * the square's contents for no apparent reason.
+               if (!canspotmon(mtmp) &&
+                   !glyph_is_invisible(levl[u.ux+u.dx][u.uy+u.dy].glyph))
+                       map_invisible(u.ux+u.dx, u.uy+u.dy);
+                */
+               return FALSE;
+       }
+
+       /* Put up an invisible monster marker, but with exceptions for
+        * monsters that hide and monsters you've been warned about.
+        * The former already prints a warning message and
+        * prevents you from hitting the monster just via the hidden monster
+        * code below; if we also did that here, similar behavior would be
+        * happening two turns in a row.  The latter shows a glyph on
+        * the screen, so you know something is there.
+        */
+       if (!canspotmon(mtmp) &&
+                   !glyph_is_warning(glyph_at(u.ux+u.dx,u.uy+u.dy)) &&
+                   !glyph_is_invisible(levl[u.ux+u.dx][u.uy+u.dy].glyph) &&
+                   !(!Blind && mtmp->mundetected && hides_under(mtmp->data))) {
+               pline("Wait!  There's %s there you can't see!",
+                       something);
+               map_invisible(u.ux+u.dx, u.uy+u.dy);
+               /* if it was an invisible mimic, treat it as if we stumbled
+                * onto a visible mimic
+                */
+               if(mtmp->m_ap_type && !Protection_from_shape_changers) {
+                   if(!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data,AD_STCK))
+                       u.ustuck = mtmp;
+               }
+               wakeup(mtmp); /* always necessary; also un-mimics mimics */
+               return TRUE;
+       }
+
+       if (mtmp->m_ap_type && !Protection_from_shape_changers &&
+          !sensemon(mtmp) &&
+          !glyph_is_warning(glyph_at(u.ux+u.dx,u.uy+u.dy))) {
+               /* If a hidden mimic was in a square where a player remembers
+                * some (probably different) unseen monster, the player is in
+                * luck--he attacks it even though it's hidden.
+                */
+               if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) {
+                   seemimic(mtmp);
+                   return(FALSE);
+               }
+               stumble_onto_mimic(mtmp);
+               return TRUE;
+       }
+
+       if (mtmp->mundetected && !canseemon(mtmp) &&
+               !glyph_is_warning(glyph_at(u.ux+u.dx,u.uy+u.dy)) &&
+               (hides_under(mtmp->data) || mtmp->data->mlet == S_EEL)) {
+           mtmp->mundetected = mtmp->msleeping = 0;
+           newsym(mtmp->mx, mtmp->my);
+           if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) {
+               seemimic(mtmp);
+               return(FALSE);
+           }
+           if (!(Blind ? Blind_telepat : Unblind_telepat)) {
+               struct obj *obj;
+
+               if (Blind || (is_pool(mtmp->mx,mtmp->my) && !Underwater))
+                   pline("Wait!  There's a hidden monster there!");
+               else if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0)
+                   pline("Wait!  There's %s hiding under %s!",
+                         an(l_monnam(mtmp)), doname(obj));
+               return TRUE;
+           }
+       }
+
+       /*
+        * make sure to wake up a monster from the above cases if the
+        * hero can sense that the monster is there.
+        */
+       if ((mtmp->mundetected || mtmp->m_ap_type) && sensemon(mtmp)) {
+           mtmp->mundetected = 0;
+           wakeup(mtmp);
+       }
+
+       if (flags.confirm && mtmp->mpeaceful
+           && !Confusion && !Hallucination && !Stunned) {
+               /* Intelligent chaotic weapons (Stormbringer) want blood */
+               if (wep && wep->oartifact == ART_STORMBRINGER) {
+                       override_confirmation = TRUE;
+                       return(FALSE);
+               }
+               if (canspotmon(mtmp)) {
+                       Sprintf(qbuf, "Really attack %s?", mon_nam(mtmp));
+                       if (yn(qbuf) != 'y') {
+                               flags.move = 0;
+                               return(TRUE);
+                       }
+               }
+       }
+
+       return(FALSE);
+}
+
+/*
+ * It is unchivalrous for a knight to attack the defenseless or from behind.
+ */
+void
+check_caitiff(mtmp)
+struct monst *mtmp;
+{
+       if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL &&
+           (!mtmp->mcanmove || mtmp->msleeping ||
+            (mtmp->mflee && !mtmp->mavenge)) &&
+           u.ualign.record > -10) {
+           You("caitiff!");
+           adjalign(-1);
+       }
+}
+
+schar
+find_roll_to_hit(mtmp)
+register struct monst *mtmp;
+{
+       schar tmp;
+       int tmp2;
+
+       tmp = 1 + Luck + abon() + find_mac(mtmp) + u.uhitinc +
+               maybe_polyd(youmonst.data->mlevel, u.ulevel);
+
+       check_caitiff(mtmp);
+
+/*     attacking peaceful creatures is bad for the samurai's giri */
+       if (Role_if(PM_SAMURAI) && mtmp->mpeaceful &&
+           u.ualign.record > -10) {
+           You("dishonorably attack the innocent!");
+           adjalign(-1);
+       }
+
+/*     Adjust vs. (and possibly modify) monster state.         */
+
+       if(mtmp->mstun) tmp += 2;
+       if(mtmp->mflee) tmp += 2;
+
+       if (mtmp->msleeping) {
+               mtmp->msleeping = 0;
+               tmp += 2;
+       }
+       if(!mtmp->mcanmove) {
+               tmp += 4;
+               if(!rn2(10)) {
+                       mtmp->mcanmove = 1;
+                       mtmp->mfrozen = 0;
+               }
+       }
+       if (is_orc(mtmp->data) && maybe_polyd(is_elf(youmonst.data),
+                       Race_if(PM_ELF)))
+           tmp++;
+       if(Role_if(PM_MONK) && !Upolyd) {
+           if (uarm) {
+               Your("armor is rather cumbersome...");
+               tmp -= urole.spelarmr;
+           } else if (!uwep && !uarms) {
+               tmp += (u.ulevel / 3) + 2;
+           }
+       }
+
+/*     with a lot of luggage, your agility diminishes */
+       if ((tmp2 = near_capacity()) != 0) tmp -= (tmp2*2) - 1;
+       if (u.utrap) tmp -= 3;
+/*     Some monsters have a combination of weapon attacks and non-weapon
+ *     attacks.  It is therefore wrong to add hitval to tmp; we must add
+ *     it only for the specific attack (in hmonas()).
+ */
+       if (uwep && !Upolyd) {
+               tmp += hitval(uwep, mtmp);
+               tmp += weapon_hit_bonus(uwep);
+       }
+       return tmp;
+}
+
+/* try to attack; return FALSE if monster evaded */
+/* u.dx and u.dy must be set */
+boolean
+attack(mtmp)
+register struct monst *mtmp;
+{
+       schar tmp;
+       register struct permonst *mdat = mtmp->data;
+
+       /* This section of code provides protection against accidentally
+        * hitting peaceful (like '@') and tame (like 'd') monsters.
+        * Protection is provided as long as player is not: blind, confused,
+        * hallucinating or stunned.
+        * changes by wwp 5/16/85
+        * More changes 12/90, -dkh-. if its tame and safepet, (and protected
+        * 07/92) then we assume that you're not trying to attack. Instead,
+        * you'll usually just swap places if this is a movement command
+        */
+       /* Intelligent chaotic weapons (Stormbringer) want blood */
+       if (is_safepet(mtmp) && !flags.forcefight) {
+           if (!uwep || uwep->oartifact != ART_STORMBRINGER) {
+               /* there are some additional considerations: this won't work
+                * if in a shop or Punished or you miss a random roll or
+                * if you can walk thru walls and your pet cannot (KAA) or
+                * if your pet is a long worm (unless someone does better).
+                * there's also a chance of displacing a "frozen" monster.
+                * sleeping monsters might magically walk in their sleep.
+                */
+               boolean foo = (Punished || !rn2(7) || is_longworm(mtmp->data)),
+                       inshop = FALSE;
+               char *p;
+
+               for (p = in_rooms(mtmp->mx, mtmp->my, SHOPBASE); *p; p++)
+                   if (tended_shop(&rooms[*p - ROOMOFFSET])) {
+                       inshop = TRUE;
+                       break;
+                   }
+
+               if (inshop || foo ||
+                       (IS_ROCK(levl[u.ux][u.uy].typ) &&
+                                       !passes_walls(mtmp->data))) {
+                   char buf[BUFSZ];
+
+                   monflee(mtmp, rnd(6), FALSE, FALSE);
+                   Strcpy(buf, y_monnam(mtmp));
+                   buf[0] = highc(buf[0]);
+                   You("stop.  %s is in the way!", buf);
+                   return(TRUE);
+               } else if ((mtmp->mfrozen || (! mtmp->mcanmove)
+                               || (mtmp->data->mmove == 0)) && rn2(6)) {
+                   pline("%s doesn't seem to move!", Monnam(mtmp));
+                   return(TRUE);
+               } else return(FALSE);
+           }
+       }
+
+       /* possibly set in attack_checks;
+          examined in known_hitum, called via hitum or hmonas below */
+       override_confirmation = FALSE;
+       if (attack_checks(mtmp, uwep)) return(TRUE);
+
+       if (Upolyd) {
+               /* certain "pacifist" monsters don't attack */
+               if(noattacks(youmonst.data)) {
+                       You("have no way to attack monsters physically.");
+                       mtmp->mstrategy &= ~STRAT_WAITMASK;
+                       goto atk_done;
+               }
+       }
+
+       if(check_capacity("You cannot fight while so heavily loaded."))
+           goto atk_done;
+
+       if (u.twoweap && !can_twoweapon())
+               untwoweapon();
+
+       if(unweapon) {
+           unweapon = FALSE;
+           if(flags.verbose) {
+               if(uwep)
+                   You("begin bashing monsters with your %s.",
+                       aobjnam(uwep, (char *)0));
+               else if (!cantwield(youmonst.data))
+                   You("begin %sing monsters with your %s %s.",
+                       Role_if(PM_MONK) ? "strik" : "bash",
+                       uarmg ? "gloved" : "bare",      /* Del Lamb */
+                       makeplural(body_part(HAND)));
+           }
+       }
+       exercise(A_STR, TRUE);          /* you're exercising muscles */
+       /* andrew@orca: prevent unlimited pick-axe attacks */
+       u_wipe_engr(3);
+
+       /* Is the "it died" check actually correct? */
+       if(mdat->mlet == S_LEPRECHAUN && !mtmp->mfrozen && !mtmp->msleeping &&
+          !mtmp->mconf && mtmp->mcansee && !rn2(7) &&
+          (m_move(mtmp, 0) == 2 ||                         /* it died */
+          mtmp->mx != u.ux+u.dx || mtmp->my != u.uy+u.dy)) /* it moved */
+               return(FALSE);
+
+       tmp = find_roll_to_hit(mtmp);
+       if (Upolyd)
+               (void) hmonas(mtmp, tmp);
+       else
+               (void) hitum(mtmp, tmp, youmonst.data->mattk);
+       mtmp->mstrategy &= ~STRAT_WAITMASK;
+
+atk_done:
+       /* see comment in attack_checks() */
+       /* we only need to check for this if we did an attack_checks()
+        * and it returned 0 (it's okay to attack), and the monster didn't
+        * evade.
+        */
+       if (flags.forcefight && mtmp->mhp > 0 && !canspotmon(mtmp) &&
+           !glyph_is_invisible(levl[u.ux+u.dx][u.uy+u.dy].glyph) &&
+           !(u.uswallow && mtmp == u.ustuck))
+               map_invisible(u.ux+u.dx, u.uy+u.dy);
+
+       return(TRUE);
+}
+
+STATIC_OVL boolean
+known_hitum(mon, mhit, uattk)  /* returns TRUE if monster still lives */
+register struct monst *mon;
+register int *mhit;
+struct attack *uattk;
+{
+       register boolean malive = TRUE;
+
+       if (override_confirmation) {
+           /* this may need to be generalized if weapons other than
+              Stormbringer acquire similar anti-social behavior... */
+           if (flags.verbose) Your("bloodthirsty blade attacks!");
+       }
+
+       if(!*mhit) {
+           missum(mon, uattk);
+       } else {
+           int oldhp = mon->mhp,
+               x = u.ux + u.dx, y = u.uy + u.dy;
+
+           /* KMH, conduct */
+           if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)))
+               u.uconduct.weaphit++;
+
+           /* we hit the monster; be careful: it might die or
+              be knocked into a different location */
+           notonhead = (mon->mx != x || mon->my != y);
+           malive = hmon(mon, uwep, 0);
+           /* this assumes that Stormbringer was uwep not uswapwep */ 
+           if (malive && u.twoweap && !override_confirmation &&
+                   m_at(x, y) == mon)
+               malive = hmon(mon, uswapwep, 0);
+           if (malive) {
+               /* monster still alive */
+               if(!rn2(25) && mon->mhp < mon->mhpmax/2
+                           && !(u.uswallow && mon == u.ustuck)) {
+                   /* maybe should regurgitate if swallowed? */
+                   if(!rn2(3)) {
+                       monflee(mon, rnd(100), FALSE, TRUE);
+                   } else monflee(mon, 0, FALSE, TRUE);
+
+                   if(u.ustuck == mon && !u.uswallow && !sticks(youmonst.data))
+                       u.ustuck = 0;
+               }
+               /* Vorpal Blade hit converted to miss */
+               /* could be headless monster or worm tail */
+               if (mon->mhp == oldhp) {
+                   *mhit = 0;
+                   /* a miss does not break conduct */
+                   if (uwep &&
+                       (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)))
+                       --u.uconduct.weaphit;
+               }
+               if (mon->wormno && *mhit)
+                   cutworm(mon, x, y, uwep);
+           }
+       }
+       return(malive);
+}
+
+STATIC_OVL boolean
+hitum(mon, tmp, uattk)         /* returns TRUE if monster still lives */
+struct monst *mon;
+int tmp;
+struct attack *uattk;
+{
+       boolean malive;
+       int mhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
+
+       if(tmp > dieroll) exercise(A_DEX, TRUE);
+       malive = known_hitum(mon, &mhit, uattk);
+       (void) passive(mon, mhit, malive, AT_WEAP);
+       return(malive);
+}
+
+boolean                        /* general "damage monster" routine */
+hmon(mon, obj, thrown)         /* return TRUE if mon still alive */
+struct monst *mon;
+struct obj *obj;
+int thrown;
+{
+       boolean result, anger_guards;
+
+       anger_guards = (mon->mpeaceful &&
+                           (mon->ispriest || mon->isshk ||
+                            mon->data == &mons[PM_WATCHMAN] ||
+                            mon->data == &mons[PM_WATCH_CAPTAIN]));
+       result = hmon_hitmon(mon, obj, thrown);
+       if (mon->ispriest && !rn2(2)) ghod_hitsu(mon);
+       if (anger_guards) (void)angry_guards(!flags.soundok);
+       return result;
+}
+
+/* guts of hmon() */
+STATIC_OVL boolean
+hmon_hitmon(mon, obj, thrown)
+struct monst *mon;
+struct obj *obj;
+int thrown;
+{
+       int tmp;
+       struct permonst *mdat = mon->data;
+       int barehand_silver_rings = 0;
+       /* The basic reason we need all these booleans is that we don't want
+        * a "hit" message when a monster dies, so we have to know how much
+        * damage it did _before_ outputting a hit message, but any messages
+        * associated with the damage don't come out until _after_ outputting
+        * a hit message.
+        */
+       boolean hittxt = FALSE, destroyed = FALSE, already_killed = FALSE;
+       boolean get_dmg_bonus = TRUE;
+       boolean ispoisoned = FALSE, needpoismsg = FALSE, poiskilled = FALSE;
+       boolean silvermsg = FALSE, silverobj = FALSE;
+       boolean valid_weapon_attack = FALSE;
+       boolean unarmed = !uwep && !uarm && !uarms;
+#ifdef STEED
+       int jousting = 0;
+#endif
+       int wtype;
+       struct obj *monwep;
+       char yourbuf[BUFSZ];
+       char unconventional[BUFSZ];     /* substituted for word "attack" in msg */
+       char saved_oname[BUFSZ];
+
+       unconventional[0] = '\0';
+       saved_oname[0] = '\0';
+
+       wakeup(mon);
+       if(!obj) {      /* attack with bare hands */
+           if (mdat == &mons[PM_SHADE])
+               tmp = 0;
+           else if (martial_bonus())
+               tmp = rnd(4);   /* bonus for martial arts */
+           else
+               tmp = rnd(2);
+           valid_weapon_attack = (tmp > 1);
+           /* blessed gloves give bonuses when fighting 'bare-handed' */
+           if (uarmg && uarmg->blessed && (is_undead(mdat) || is_demon(mdat)))
+               tmp += rnd(4);
+           /* So do silver rings.  Note: rings are worn under gloves, so you
+            * don't get both bonuses.
+            */
+           if (!uarmg) {
+               if (uleft && objects[uleft->otyp].oc_material == SILVER)
+                   barehand_silver_rings++;
+               if (uright && objects[uright->otyp].oc_material == SILVER)
+                   barehand_silver_rings++;
+               if (barehand_silver_rings && hates_silver(mdat)) {
+                   tmp += rnd(20);
+                   silvermsg = TRUE;
+               }
+           }
+       } else {
+           Strcpy(saved_oname, cxname(obj));
+           if(obj->oclass == WEAPON_CLASS || is_weptool(obj) ||
+              obj->oclass == GEM_CLASS) {
+
+               /* is it not a melee weapon? */
+               if (/* if you strike with a bow... */
+                   is_launcher(obj) ||
+                   /* or strike with a missile in your hand... */
+                   (!thrown && (is_missile(obj) || is_ammo(obj))) ||
+                   /* or use a pole at short range and not mounted... */
+                   (!thrown &&
+#ifdef STEED
+                    !u.usteed &&
+#endif
+                    is_pole(obj)) ||
+                   /* or throw a missile without the proper bow... */
+                   (is_ammo(obj) && !ammo_and_launcher(obj, uwep))) {
+                   /* then do only 1-2 points of damage */
+                   if (mdat == &mons[PM_SHADE] && obj->otyp != SILVER_ARROW)
+                       tmp = 0;
+                   else
+                       tmp = rnd(2);
+                   if (!thrown && obj == uwep && obj->otyp == BOOMERANG &&
+                           rnl(4) == 4-1) {
+                       boolean more_than_1 = (obj->quan > 1L);
+
+                       pline("As you hit %s, %s%s %s breaks into splinters.",
+                             mon_nam(mon), more_than_1 ? "one of " : "",
+                             shk_your(yourbuf, obj), xname(obj));
+                       if (!more_than_1) uwepgone();   /* set unweapon */
+                       useup(obj);
+                       if (!more_than_1) obj = (struct obj *) 0;
+                       hittxt = TRUE;
+                       if (mdat != &mons[PM_SHADE])
+                           tmp++;
+                   }
+               } else {
+                   tmp = dmgval(obj, mon);
+                   /* a minimal hit doesn't exercise proficiency */
+                   valid_weapon_attack = (tmp > 1);
+                   if (!valid_weapon_attack || mon == u.ustuck || u.twoweap) {
+                       ;       /* no special bonuses */
+                   } else if (mon->mflee && Role_if(PM_ROGUE) && !Upolyd) {
+                       You("strike %s from behind!", mon_nam(mon));
+                       tmp += rnd(u.ulevel);
+                       hittxt = TRUE;
+                   } else if (dieroll == 2 && obj == uwep &&
+                         obj->oclass == WEAPON_CLASS &&
+                         (bimanual(obj) ||
+                           (Role_if(PM_SAMURAI) && obj->otyp == KATANA && !uarms)) &&
+                         ((wtype = uwep_skill_type()) != P_NONE &&
+                           P_SKILL(wtype) >= P_SKILLED) &&
+                         ((monwep = MON_WEP(mon)) != 0 &&
+                          !is_flimsy(monwep) &&
+                          !obj_resists(monwep,
+                                50 + 15 * greatest_erosion(obj), 100))) {
+                       /*
+                        * 2.5% chance of shattering defender's weapon when
+                        * using a two-handed weapon; less if uwep is rusted.
+                        * [dieroll == 2 is most successful non-beheading or
+                        * -bisecting hit, in case of special artifact damage;
+                        * the percentage chance is (1/20)*(50/100).]
+                        */
+                       setmnotwielded(mon,monwep);
+                       MON_NOWEP(mon);
+                       mon->weapon_check = NEED_WEAPON;
+                       pline("%s %s %s from the force of your blow!",
+                             s_suffix(Monnam(mon)), xname(monwep),
+                             otense(monwep, "shatter"));
+                       m_useup(mon, monwep);
+                       /* If someone just shattered MY weapon, I'd flee! */
+                       if (rn2(4)) {
+                           monflee(mon, d(2,3), TRUE, TRUE);
+                       }
+                       hittxt = TRUE;
+                   }
+
+                   if (obj->oartifact &&
+                       artifact_hit(&youmonst, mon, obj, &tmp, dieroll)) {
+                       if(mon->mhp <= 0) /* artifact killed monster */
+                           return FALSE;
+                       if (tmp == 0) return TRUE;
+                       hittxt = TRUE;
+                   }
+                   if (objects[obj->otyp].oc_material == SILVER
+                               && hates_silver(mdat)) {
+                       silvermsg = TRUE; silverobj = TRUE;
+                   }
+#ifdef STEED
+                   if (u.usteed && !thrown && tmp > 0 &&
+                           weapon_type(obj) == P_LANCE && mon != u.ustuck) {
+                       jousting = joust(mon, obj);
+                       /* exercise skill even for minimal damage hits */
+                       if (jousting) valid_weapon_attack = TRUE;
+                   }
+#endif
+                   if (thrown && (is_ammo(obj) || is_missile(obj))) {
+                       if (ammo_and_launcher(obj, uwep)) {
+                           /* Elves and Samurai do extra damage using
+                            * their bows&arrows; they're highly trained.
+                            */
+                           if (Role_if(PM_SAMURAI) &&
+                               obj->otyp == YA && uwep->otyp == YUMI)
+                               tmp++;
+                           else if (Race_if(PM_ELF) &&
+                                    obj->otyp == ELVEN_ARROW &&
+                                    uwep->otyp == ELVEN_BOW)
+                               tmp++;
+                       }
+                       if(obj->opoisoned && is_poisonable(obj))
+                           ispoisoned = TRUE;
+                   }
+               }
+           } else if(obj->oclass == POTION_CLASS) {
+               if (obj->quan > 1L)
+                   obj = splitobj(obj, 1L);
+               else
+                   setuwep((struct obj *)0);
+               freeinv(obj);
+               potionhit(mon, obj, TRUE);
+               if (mon->mhp <= 0) return FALSE;        /* killed */
+               hittxt = TRUE;
+               /* in case potion effect causes transformation */
+               mdat = mon->data;
+               tmp = (mdat == &mons[PM_SHADE]) ? 0 : 1;
+           } else {
+               if (mdat == &mons[PM_SHADE] && !shade_aware(obj)) {
+                   tmp = 0;
+                   Strcpy(unconventional, cxname(obj));
+               } else {
+                   switch(obj->otyp) {
+                   case BOULDER:               /* 1d20 */
+                   case HEAVY_IRON_BALL:       /* 1d25 */
+                   case IRON_CHAIN:            /* 1d4+1 */
+                       tmp = dmgval(obj, mon);
+                       break;
+                   case MIRROR:
+                       if (breaktest(obj)) {
+                           You("break %s mirror.  That's bad luck!",
+                               shk_your(yourbuf, obj));
+                           change_luck(-2);
+                           useup(obj);
+                           obj = (struct obj *) 0;
+                           unarmed = FALSE;    /* avoid obj==0 confusion */
+                           get_dmg_bonus = FALSE;
+                           hittxt = TRUE;
+                       }
+                       tmp = 1;
+                       break;
+#ifdef TOURIST
+                   case EXPENSIVE_CAMERA:
+                       You("succeed in destroying %s camera.  Congratulations!",
+                               shk_your(yourbuf, obj));
+                       useup(obj);
+                       return(TRUE);
+                       /*NOTREACHED*/
+                       break;
+#endif
+                   case CORPSE:                /* fixed by polder@cs.vu.nl */
+                       if (touch_petrifies(&mons[obj->corpsenm])) {
+                           static const char withwhat[] = "corpse";
+                           tmp = 1;
+                           hittxt = TRUE;
+                           You("hit %s with %s %s.", mon_nam(mon),
+                               obj->dknown ? the(mons[obj->corpsenm].mname) :
+                               an(mons[obj->corpsenm].mname),
+                               (obj->quan > 1) ? makeplural(withwhat) : withwhat);
+                           if (!munstone(mon, TRUE))
+                               minstapetrify(mon, TRUE);
+                           if (resists_ston(mon)) break;
+                           /* note: hp may be <= 0 even if munstoned==TRUE */
+                           return (boolean) (mon->mhp > 0);
+#if 0
+                       } else if (touch_petrifies(mdat)) {
+                           /* maybe turn the corpse into a statue? */
+#endif
+                       }
+                       tmp = (obj->corpsenm >= LOW_PM ?
+                                       mons[obj->corpsenm].msize : 0) + 1;
+                       break;
+                   case EGG:
+                     {
+#define useup_eggs(o)  { if (thrown) obfree(o,(struct obj *)0); \
+                         else useupall(o); \
+                         o = (struct obj *)0; }        /* now gone */
+                       long cnt = obj->quan;
+
+                       tmp = 1;                /* nominal physical damage */
+                       get_dmg_bonus = FALSE;
+                       hittxt = TRUE;          /* message always given */
+                       /* egg is always either used up or transformed, so next
+                          hand-to-hand attack should yield a "bashing" mesg */
+                       if (obj == uwep) unweapon = TRUE;
+                       if (obj->spe && obj->corpsenm >= LOW_PM) {
+                           if (obj->quan < 5)
+                               change_luck((schar) -(obj->quan));
+                           else
+                               change_luck(-5);
+                       }
+
+                       if (touch_petrifies(&mons[obj->corpsenm])) {
+                           /*learn_egg_type(obj->corpsenm);*/
+                           pline("Splat! You hit %s with %s %s egg%s!",
+                               mon_nam(mon),
+                               obj->known ? "the" : cnt > 1L ? "some" : "a",
+                               obj->known ? mons[obj->corpsenm].mname : "petrifying",
+                               plur(cnt));
+                           obj->known = 1;     /* (not much point...) */
+                           useup_eggs(obj);
+                           if (!munstone(mon, TRUE))
+                               minstapetrify(mon, TRUE);
+                           if (resists_ston(mon)) break;
+                           return (boolean) (mon->mhp > 0);
+                       } else {        /* ordinary egg(s) */
+                           const char *eggp =
+                                    (obj->corpsenm != NON_PM && obj->known) ?
+                                             the(mons[obj->corpsenm].mname) :
+                                             (cnt > 1L) ? "some" : "an";
+                           You("hit %s with %s egg%s.",
+                               mon_nam(mon), eggp, plur(cnt));
+                           if (touch_petrifies(mdat) && !stale_egg(obj)) {
+                               pline_The("egg%s %s alive any more...",
+                                     plur(cnt),
+                                     (cnt == 1L) ? "isn't" : "aren't");
+                               if (obj->timed) obj_stop_timers(obj);
+                               obj->otyp = ROCK;
+                               obj->oclass = GEM_CLASS;
+                               obj->oartifact = 0;
+                               obj->spe = 0;
+                               obj->known = obj->dknown = obj->bknown = 0;
+                               obj->owt = weight(obj);
+                               if (thrown) place_object(obj, mon->mx, mon->my);
+                           } else {
+                               pline("Splat!");
+                               useup_eggs(obj);
+                               exercise(A_WIS, FALSE);
+                           }
+                       }
+                       break;
+#undef useup_eggs
+                     }
+                   case CLOVE_OF_GARLIC:       /* no effect against demons */
+                       if (is_undead(mdat)) {
+                           monflee(mon, d(2, 4), FALSE, TRUE);
+                       }
+                       tmp = 1;
+                       break;
+                   case CREAM_PIE:
+                   case BLINDING_VENOM:
+                       mon->msleeping = 0;
+                       if (can_blnd(&youmonst, mon, (uchar)
+                                   (obj->otyp == BLINDING_VENOM
+                                    ? AT_SPIT : AT_WEAP), obj)) {
+                           if (Blind) {
+                               pline(obj->otyp == CREAM_PIE ?
+                                     "Splat!" : "Splash!");
+                           } else if (obj->otyp == BLINDING_VENOM) {
+                               pline_The("venom blinds %s%s!", mon_nam(mon),
+                                         mon->mcansee ? "" : " further");
+                           } else {
+                               char *whom = mon_nam(mon);
+                               char *what = The(xname(obj));
+                               if (!thrown && obj->quan > 1)
+                                   what = An(singular(obj, xname));
+                               /* note: s_suffix returns a modifiable buffer */
+                               if (haseyes(mdat)
+                                   && mdat != &mons[PM_FLOATING_EYE])
+                                   whom = strcat(strcat(s_suffix(whom), " "),
+                                                 mbodypart(mon, FACE));
+                               pline("%s %s over %s!",
+                                     what, vtense(what, "splash"), whom);
+                           }
+                           setmangry(mon);
+                           mon->mcansee = 0;
+                           tmp = rn1(25, 21);
+                           if(((int) mon->mblinded + tmp) > 127)
+                               mon->mblinded = 127;
+                           else mon->mblinded += tmp;
+                       } else {
+                           pline(obj->otyp==CREAM_PIE ? "Splat!" : "Splash!");
+                           setmangry(mon);
+                       }
+                       if (thrown) obfree(obj, (struct obj *)0);
+                       else useup(obj);
+                       hittxt = TRUE;
+                       get_dmg_bonus = FALSE;
+                       tmp = 0;
+                       break;
+                   case ACID_VENOM: /* thrown (or spit) */
+                       if (resists_acid(mon)) {
+                               Your("venom hits %s harmlessly.",
+                                       mon_nam(mon));
+                               tmp = 0;
+                       } else {
+                               Your("venom burns %s!", mon_nam(mon));
+                               tmp = dmgval(obj, mon);
+                       }
+                       if (thrown) obfree(obj, (struct obj *)0);
+                       else useup(obj);
+                       hittxt = TRUE;
+                       get_dmg_bonus = FALSE;
+                       break;
+                   default:
+                       /* non-weapons can damage because of their weight */
+                       /* (but not too much) */
+                       tmp = obj->owt/100;
+                       if(tmp < 1) tmp = 1;
+                       else tmp = rnd(tmp);
+                       if(tmp > 6) tmp = 6;
+                       /*
+                        * Things like silver wands can arrive here so
+                        * so we need another silver check.
+                        */
+                       if (objects[obj->otyp].oc_material == SILVER
+                                               && hates_silver(mdat)) {
+                               tmp += rnd(20);
+                               silvermsg = TRUE; silverobj = TRUE;
+                       }
+                   }
+               }
+           }
+       }
+
+       /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG)
+        *      *OR* if attacking bare-handed!! */
+
+       if (get_dmg_bonus && tmp > 0) {
+               tmp += u.udaminc;
+               /* If you throw using a propellor, you don't get a strength
+                * bonus but you do get an increase-damage bonus.
+                */
+               if(!thrown || !obj || !uwep || !ammo_and_launcher(obj, uwep))
+                   tmp += dbon();
+       }
+
+       if (valid_weapon_attack) {
+           struct obj *wep;
+
+           /* to be valid a projectile must have had the correct projector */
+           wep = PROJECTILE(obj) ? uwep : obj;
+           tmp += weapon_dam_bonus(wep);
+           /* [this assumes that `!thrown' implies wielded...] */
+           wtype = thrown ? weapon_type(wep) : uwep_skill_type();
+           use_skill(wtype, 1);
+       }
+
+       if (ispoisoned) {
+           int nopoison = (10 - (obj->owt/10));            
+           if(nopoison < 2) nopoison = 2;
+           if Role_if(PM_SAMURAI) {
+               You("dishonorably use a poisoned weapon!");
+               adjalign(-sgn(u.ualign.type));
+           } else if ((u.ualign.type == A_LAWFUL) && (u.ualign.record > -10)) {
+               You_feel("like an evil coward for using a poisoned weapon.");
+               adjalign(-1);
+           }
+           if (obj && !rn2(nopoison)) {
+               obj->opoisoned = FALSE;
+               Your("%s %s no longer poisoned.", xname(obj),
+                    otense(obj, "are"));
+           }
+           if (resists_poison(mon))
+               needpoismsg = TRUE;
+           else if (rn2(10))
+               tmp += rnd(6);
+           else poiskilled = TRUE;
+       }
+       if (tmp < 1) {
+           /* make sure that negative damage adjustment can't result
+              in inadvertently boosting the victim's hit points */
+           tmp = 0;
+           if (mdat == &mons[PM_SHADE]) {
+               if (!hittxt) {
+                   const char *what = unconventional[0] ? unconventional : "attack";
+                   Your("%s %s harmlessly through %s.",
+                       what, vtense(what, "pass"),
+                       mon_nam(mon));
+                   hittxt = TRUE;
+               }
+           } else {
+               if (get_dmg_bonus) tmp = 1;
+           }
+       }
+
+#ifdef STEED
+       if (jousting) {
+           tmp += d(2, (obj == uwep) ? 10 : 2);        /* [was in dmgval()] */
+           You("joust %s%s",
+                        mon_nam(mon), canseemon(mon) ? exclam(tmp) : ".");
+           if (jousting < 0) {
+               Your("%s shatters on impact!", xname(obj));
+               /* (must be either primary or secondary weapon to get here) */
+               u.twoweap = FALSE;      /* untwoweapon() is too verbose here */
+               if (obj == uwep) uwepgone();            /* set unweapon */
+               /* minor side-effect: broken lance won't split puddings */
+               useup(obj);
+               obj = 0;
+           }
+           /* avoid migrating a dead monster */
+           if (mon->mhp > tmp) {
+               mhurtle(mon, u.dx, u.dy, 1);
+               mdat = mon->data; /* in case of a polymorph trap */
+               if (DEADMONSTER(mon)) already_killed = TRUE;
+           }
+           hittxt = TRUE;
+       } else
+#endif
+
+       /* VERY small chance of stunning opponent if unarmed. */
+       if (unarmed && tmp > 1 && !thrown && !obj && !Upolyd) {
+           if (rnd(100) < P_SKILL(P_BARE_HANDED_COMBAT) &&
+                       !bigmonst(mdat) && !thick_skinned(mdat)) {
+               if (canspotmon(mon))
+                   pline("%s %s from your powerful strike!", Monnam(mon),
+                         makeplural(stagger(mon->data, "stagger")));
+               /* avoid migrating a dead monster */
+               if (mon->mhp > tmp) {
+                   mhurtle(mon, u.dx, u.dy, 1);
+                   mdat = mon->data; /* in case of a polymorph trap */
+                   if (DEADMONSTER(mon)) already_killed = TRUE;
+               }
+               hittxt = TRUE;
+           }
+       }
+
+       if (!already_killed) mon->mhp -= tmp;
+       /* adjustments might have made tmp become less than what
+          a level draining artifact has already done to max HP */
+       if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax;
+       if (mon->mhp < 1)
+               destroyed = TRUE;
+       if (mon->mtame && (!mon->mflee || mon->mfleetim) && tmp > 0) {
+               abuse_dog(mon);
+               monflee(mon, 10 * rnd(tmp), FALSE, FALSE);
+       }
+       if((mdat == &mons[PM_BLACK_PUDDING] || mdat == &mons[PM_BROWN_PUDDING])
+                  && obj && obj == uwep
+                  && objects[obj->otyp].oc_material == IRON
+                  && mon->mhp > 1 && !thrown && !mon->mcan
+                  /* && !destroyed  -- guaranteed by mhp > 1 */ ) {
+               if (clone_mon(mon, 0, 0)) {
+                       pline("%s divides as you hit it!", Monnam(mon));
+                       hittxt = TRUE;
+               }
+       }
+
+       if (!hittxt &&                  /*( thrown => obj exists )*/
+         (!destroyed || (thrown && m_shot.n > 1 && m_shot.o == obj->otyp))) {
+               if (thrown) hit(mshot_xname(obj), mon, exclam(tmp));
+               else if (!flags.verbose) You("hit it.");
+               else You("%s %s%s", Role_if(PM_BARBARIAN) ? "smite" : "hit",
+                        mon_nam(mon), canseemon(mon) ? exclam(tmp) : ".");
+       }
+
+       if (silvermsg) {
+               const char *fmt;
+               char *whom = mon_nam(mon);
+               char silverobjbuf[BUFSZ];
+
+               if (canspotmon(mon)) {
+                   if (barehand_silver_rings == 1)
+                       fmt = "Your silver ring sears %s!";
+                   else if (barehand_silver_rings == 2)
+                       fmt = "Your silver rings sear %s!";
+                   else if (silverobj && saved_oname[0]) {
+                       Sprintf(silverobjbuf, "Your %s%s %s %%s!",
+                               strstri(saved_oname, "silver") ?
+                                       "" : "silver ",
+                               saved_oname, vtense(saved_oname, "sear"));
+                       fmt = silverobjbuf;
+                   } else
+                       fmt = "The silver sears %s!";
+               } else {
+                   *whom = highc(*whom);       /* "it" -> "It" */
+                   fmt = "%s is seared!";
+               }
+               /* note: s_suffix returns a modifiable buffer */
+               if (!noncorporeal(mdat))
+                   whom = strcat(s_suffix(whom), " flesh");
+               pline(fmt, whom);
+       }
+
+       if (needpoismsg)
+               pline_The("poison doesn't seem to affect %s.", mon_nam(mon));
+       if (poiskilled) {
+               pline_The("poison was deadly...");
+               if (!already_killed) xkilled(mon, 0);
+               return FALSE;
+       } else if (destroyed) {
+               if (!already_killed)
+                   killed(mon);        /* takes care of most messages */
+       } else if(u.umconf && !thrown) {
+               nohandglow(mon);
+               if (!mon->mconf && !resist(mon, SPBOOK_CLASS, 0, NOTELL)) {
+                       mon->mconf = 1;
+                       if (!mon->mstun && mon->mcanmove && !mon->msleeping &&
+                               canseemon(mon))
+                           pline("%s appears confused.", Monnam(mon));
+               }
+       }
+
+       return((boolean)(destroyed ? FALSE : TRUE));
+}
+
+STATIC_OVL boolean
+shade_aware(obj)
+struct obj *obj;
+{
+       if (!obj) return FALSE;
+       /*
+        * The things in this list either
+        * 1) affect shades.
+        *  OR
+        * 2) are dealt with properly by other routines
+        *    when it comes to shades.
+        */
+       if (obj->otyp == BOULDER || obj->otyp == HEAVY_IRON_BALL
+           || obj->otyp == IRON_CHAIN          /* dmgval handles those first three */
+           || obj->otyp == MIRROR              /* silver in the reflective surface */
+           || obj->otyp == CLOVE_OF_GARLIC     /* causes shades to flee */
+           || objects[obj->otyp].oc_material == SILVER)
+               return TRUE;
+       return FALSE;
+}
+
+/* check whether slippery clothing protects from hug or wrap attack */
+/* [currently assumes that you are the attacker] */
+STATIC_OVL boolean
+m_slips_free(mdef, mattk)
+struct monst *mdef;
+struct attack *mattk;
+{
+       struct obj *obj;
+
+       if (mattk->adtyp == AD_DRIN) {
+           /* intelligence drain attacks the head */
+           obj = which_armor(mdef, W_ARMH);
+       } else {
+           /* grabbing attacks the body */
+           obj = which_armor(mdef, W_ARMC);            /* cloak */
+           if (!obj) obj = which_armor(mdef, W_ARM);   /* suit */
+#ifdef TOURIST
+           if (!obj) obj = which_armor(mdef, W_ARMU);  /* shirt */
+#endif
+       }
+
+       /* if your cloak/armor is greased, monster slips off; this
+          protection might fail (33% chance) when the armor is cursed */
+       if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK) &&
+               (!obj->cursed || rn2(3))) {
+           You("%s %s %s %s!",
+               mattk->adtyp == AD_WRAP ?
+                       "slip off of" : "grab, but cannot hold onto",
+               s_suffix(mon_nam(mdef)),
+               obj->greased ? "greased" : "slippery",
+               /* avoid "slippery slippery cloak"
+                  for undiscovered oilskin cloak */
+               (obj->greased || objects[obj->otyp].oc_name_known) ?
+                       xname(obj) : cloak_simple_name(obj));
+
+           if (obj->greased && !rn2(2)) {
+               pline_The("grease wears off.");
+               obj->greased = 0;
+           }
+           return TRUE;
+       }
+       return FALSE;
+}
+
+/* used when hitting a monster with a lance while mounted */
+STATIC_OVL int /* 1: joust hit; 0: ordinary hit; -1: joust but break lance */
+joust(mon, obj)
+struct monst *mon;     /* target */
+struct obj *obj;       /* weapon */
+{
+    int skill_rating, joust_dieroll;
+
+    if (Fumbling || Stunned) return 0;
+    /* sanity check; lance must be wielded in order to joust */
+    if (obj != uwep && (obj != uswapwep || !u.twoweap)) return 0;
+
+    /* if using two weapons, use worse of lance and two-weapon skills */
+    skill_rating = P_SKILL(weapon_type(obj));  /* lance skill */
+    if (u.twoweap && P_SKILL(P_TWO_WEAPON_COMBAT) < skill_rating)
+       skill_rating = P_SKILL(P_TWO_WEAPON_COMBAT);
+    if (skill_rating == P_ISRESTRICTED) skill_rating = P_UNSKILLED; /* 0=>1 */
+
+    /* odds to joust are expert:80%, skilled:60%, basic:40%, unskilled:20% */
+    if ((joust_dieroll = rn2(5)) < skill_rating) {
+       if (joust_dieroll == 0 && rnl(50) == (50-1) &&
+               !unsolid(mon->data) && !obj_resists(obj, 0, 100))
+           return -1;  /* hit that breaks lance */
+       return 1;       /* successful joust */
+    }
+    return 0;  /* no joust bonus; revert to ordinary attack */
+}
+
+/*
+ * Send in a demon pet for the hero.  Exercise wisdom.
+ *
+ * This function used to be inline to damageum(), but the Metrowerks compiler
+ * (DR4 and DR4.5) screws up with an internal error 5 "Expression Too Complex."
+ * Pulling it out makes it work.
+ */
+STATIC_OVL void
+demonpet()
+{
+       int i;
+       struct permonst *pm;
+       struct monst *dtmp;
+
+       pline("Some hell-p has arrived!");
+       i = !rn2(6) ? ndemon(u.ualign.type) : NON_PM;
+       pm = i != NON_PM ? &mons[i] : youmonst.data;
+       if ((dtmp = makemon(pm, u.ux, u.uy, NO_MM_FLAGS)) != 0)
+           (void)tamedog(dtmp, (struct obj *)0);
+       exercise(A_WIS, TRUE);
+}
+
+/*
+ * Player uses theft attack against monster.
+ *
+ * If the target is wearing body armor, take all of its possesions;
+ * otherwise, take one object.  [Is this really the behavior we want?]
+ *
+ * This routine implicitly assumes that there is no way to be able to
+ * resist petfication (ie, be polymorphed into a xorn or golem) at the
+ * same time as being able to steal (poly'd into nymph or succubus).
+ * If that ever changes, the check for touching a cockatrice corpse
+ * will need to be smarter about whether to break out of the theft loop.
+ */
+STATIC_OVL void
+steal_it(mdef, mattk)
+struct monst *mdef;
+struct attack *mattk;
+{
+       struct obj *otmp, *stealoid, **minvent_ptr;
+       long unwornmask;
+
+       if (!mdef->minvent) return;             /* nothing to take */
+
+       /* look for worn body armor */
+       stealoid = (struct obj *)0;
+       if (could_seduce(&youmonst, mdef, mattk)) {
+           /* find armor, and move it to end of inventory in the process */
+           minvent_ptr = &mdef->minvent;
+           while ((otmp = *minvent_ptr) != 0)
+               if (otmp->owornmask & W_ARM) {
+                   if (stealoid) panic("steal_it: multiple worn suits");
+                   *minvent_ptr = otmp->nobj;  /* take armor out of minvent */
+                   stealoid = otmp;
+                   stealoid->nobj = (struct obj *)0;
+               } else {
+                   minvent_ptr = &otmp->nobj;
+               }
+           *minvent_ptr = stealoid;    /* put armor back into minvent */
+       }
+
+       if (stealoid) {         /* we will be taking everything */
+           if (gender(mdef) == (int) u.mfemale &&
+                       youmonst.data->mlet == S_NYMPH)
+               You("charm %s.  She gladly hands over her possessions.",
+                   mon_nam(mdef));
+           else
+               You("seduce %s and %s starts to take off %s clothes.",
+                   mon_nam(mdef), mhe(mdef), mhis(mdef));
+       }
+
+       while ((otmp = mdef->minvent) != 0) {
+           if (!Upolyd) break;         /* no longer have ability to steal */
+           /* take the object away from the monster */
+           obj_extract_self(otmp);
+           if ((unwornmask = otmp->owornmask) != 0L) {
+               mdef->misc_worn_check &= ~unwornmask;
+               if (otmp->owornmask & W_WEP) {
+                   setmnotwielded(mdef,otmp);
+                   MON_NOWEP(mdef);
+               }
+               otmp->owornmask = 0L;
+               update_mon_intrinsics(mdef, otmp, FALSE, FALSE);
+
+               if (otmp == stealoid)   /* special message for final item */
+                   pline("%s finishes taking off %s suit.",
+                         Monnam(mdef), mhis(mdef));
+           }
+           /* give the object to the character */
+           otmp = hold_another_object(otmp, "You snatched but dropped %s.",
+                                      doname(otmp), "You steal: ");
+           if (otmp->where != OBJ_INVENT) continue;
+           if (otmp->otyp == CORPSE &&
+                   touch_petrifies(&mons[otmp->corpsenm]) && !uarmg) {
+               char kbuf[BUFSZ];
+
+               Sprintf(kbuf, "stolen %s corpse", mons[otmp->corpsenm].mname);
+               instapetrify(kbuf);
+               break;          /* stop the theft even if hero survives */
+           }
+           /* more take-away handling, after theft message */
+           if (unwornmask & W_WEP) {           /* stole wielded weapon */
+               possibly_unwield(mdef, FALSE);
+           } else if (unwornmask & W_ARMG) {   /* stole worn gloves */
+               mselftouch(mdef, (const char *)0, TRUE);
+               if (mdef->mhp <= 0)     /* it's now a statue */
+                   return;             /* can't continue stealing */
+           }
+
+           if (!stealoid) break;       /* only taking one item */
+       }
+}
+
+int
+damageum(mdef, mattk)
+register struct monst *mdef;
+register struct attack *mattk;
+{
+       register struct permonst *pd = mdef->data;
+       register int    tmp = d((int)mattk->damn, (int)mattk->damd);
+       int armpro;
+       boolean negated;
+
+       armpro = magic_negation(mdef);
+       /* since hero can't be cancelled, only defender's armor applies */
+       negated = !((rn2(3) >= armpro) || !rn2(50));
+
+       if (is_demon(youmonst.data) && !rn2(13) && !uwep
+               && u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS
+               && u.umonnum != PM_BALROG) {
+           demonpet();
+           return(0);
+       }
+       switch(mattk->adtyp) {
+           case AD_STUN:
+               if(!Blind)
+                   pline("%s %s for a moment.", Monnam(mdef),
+                         makeplural(stagger(mdef->data, "stagger")));
+               mdef->mstun = 1;
+               goto physical;
+           case AD_LEGS:
+            /* if (u.ucancelled) { */
+            /*    tmp = 0;         */
+            /*    break;           */
+            /* }                   */
+               goto physical;
+           case AD_WERE:           /* no special effect on monsters */
+           case AD_HEAL:           /* likewise */
+           case AD_PHYS:
+ physical:
+               if(mattk->aatyp == AT_WEAP) {
+                   if(uwep) tmp = 0;
+               } else if(mattk->aatyp == AT_KICK) {
+                   if(thick_skinned(mdef->data)) tmp = 0;
+                   if(mdef->data == &mons[PM_SHADE]) {
+                       if (!(uarmf && uarmf->blessed)) {
+                           impossible("bad shade attack function flow?");
+                           tmp = 0;
+                       } else
+                           tmp = rnd(4); /* bless damage */
+                   }
+               }
+               break;
+           case AD_FIRE:
+               if (negated) {
+                   tmp = 0;
+                   break;
+               }
+               if (!Blind)
+                   pline("%s is %s!", Monnam(mdef),
+                         on_fire(mdef->data, mattk));
+               if (pd == &mons[PM_STRAW_GOLEM] ||
+                   pd == &mons[PM_PAPER_GOLEM]) {
+                   if (!Blind)
+                       pline("%s burns completely!", Monnam(mdef));
+                   xkilled(mdef,2);
+                   tmp = 0;
+                   break;
+                   /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
+               }
+               tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
+               tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
+               if (resists_fire(mdef)) {
+                   if (!Blind)
+                       pline_The("fire doesn't heat %s!", mon_nam(mdef));
+                   golemeffects(mdef, AD_FIRE, tmp);
+                   shieldeff(mdef->mx, mdef->my);
+                   tmp = 0;
+               }
+               /* only potions damage resistant players in destroy_item */
+               tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
+               break;
+           case AD_COLD:
+               if (negated) {
+                   tmp = 0;
+                   break;
+               }
+               if (!Blind) pline("%s is covered in frost!", Monnam(mdef));
+               if (resists_cold(mdef)) {
+                   shieldeff(mdef->mx, mdef->my);
+                   if (!Blind)
+                       pline_The("frost doesn't chill %s!", mon_nam(mdef));
+                   golemeffects(mdef, AD_COLD, tmp);
+                   tmp = 0;
+               }
+               tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
+               break;
+           case AD_ELEC:
+               if (negated) {
+                   tmp = 0;
+                   break;
+               }
+               if (!Blind) pline("%s is zapped!", Monnam(mdef));
+               tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
+               if (resists_elec(mdef)) {
+                   if (!Blind)
+                       pline_The("zap doesn't shock %s!", mon_nam(mdef));
+                   golemeffects(mdef, AD_ELEC, tmp);
+                   shieldeff(mdef->mx, mdef->my);
+                   tmp = 0;
+               }
+               /* only rings damage resistant players in destroy_item */
+               tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
+               break;
+           case AD_ACID:
+               if (resists_acid(mdef)) tmp = 0;
+               break;
+           case AD_STON:
+               if (!munstone(mdef, TRUE))
+                   minstapetrify(mdef, TRUE);
+               tmp = 0;
+               break;
+#ifdef SEDUCE
+           case AD_SSEX:
+#endif
+           case AD_SEDU:
+           case AD_SITM:
+               steal_it(mdef, mattk);
+               tmp = 0;
+               break;
+           case AD_SGLD:
+#ifndef GOLDOBJ
+               if (mdef->mgold) {
+                   u.ugold += mdef->mgold;
+                   mdef->mgold = 0;
+                   Your("purse feels heavier.");
+               }
+#else
+                /* This you as a leprechaun, so steal
+                   real gold only, no lesser coins */
+               {
+                   struct obj *mongold = findgold(mdef->minvent);
+                   if (mongold) {
+                       obj_extract_self(mongold);  
+                       if (merge_choice(invent, mongold) || inv_cnt() < 52) {
+                           addinv(mongold);
+                           Your("purse feels heavier.");
+                       } else {
+                            You("grab %s's gold, but find no room in your knapsack.", mon_nam(mdef));
+                           dropy(mongold);
+                       }
+                   }
+               }
+#endif
+               exercise(A_DEX, TRUE);
+               tmp = 0;
+               break;
+           case AD_TLPT:
+               if (tmp <= 0) tmp = 1;
+               if (!negated && tmp < mdef->mhp) {
+                   char nambuf[BUFSZ];
+                   boolean u_saw_mon = canseemon(mdef) ||
+                                       (u.uswallow && u.ustuck == mdef);
+                   /* record the name before losing sight of monster */
+                   Strcpy(nambuf, Monnam(mdef));
+                   if (u_teleport_mon(mdef, FALSE) &&
+                           u_saw_mon && !canseemon(mdef))
+                       pline("%s suddenly disappears!", nambuf);
+               }
+               break;
+           case AD_BLND:
+               if (can_blnd(&youmonst, mdef, mattk->aatyp, (struct obj*)0)) {
+                   if(!Blind && mdef->mcansee)
+                       pline("%s is blinded.", Monnam(mdef));
+                   mdef->mcansee = 0;
+                   tmp += mdef->mblinded;
+                   if (tmp > 127) tmp = 127;
+                   mdef->mblinded = tmp;
+               }
+               tmp = 0;
+               break;
+           case AD_CURS:
+               if (night() && !rn2(10) && !mdef->mcan) {
+                   if (mdef->data == &mons[PM_CLAY_GOLEM]) {
+                       if (!Blind)
+                           pline("Some writing vanishes from %s head!",
+                               s_suffix(mon_nam(mdef)));
+                       xkilled(mdef, 0);
+                       /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
+                   } else {
+                       mdef->mcan = 1;
+                       You("chuckle.");
+                   }
+               }
+               tmp = 0;
+               break;
+           case AD_DRLI:
+               if (!negated && !rn2(3) && !resists_drli(mdef)) {
+                       int xtmp = d(2,6);
+                       pline("%s suddenly seems weaker!", Monnam(mdef));
+                       mdef->mhpmax -= xtmp;
+                       if ((mdef->mhp -= xtmp) <= 0 || !mdef->m_lev) {
+                               pline("%s dies!", Monnam(mdef));
+                               xkilled(mdef,0);
+                       } else
+                               mdef->m_lev--;
+                       tmp = 0;
+               }
+               break;
+           case AD_RUST:
+               if (pd == &mons[PM_IRON_GOLEM]) {
+                       pline("%s falls to pieces!", Monnam(mdef));
+                       xkilled(mdef,0);
+               }
+               hurtmarmor(mdef, AD_RUST);
+               tmp = 0;
+               break;
+           case AD_CORR:
+               hurtmarmor(mdef, AD_CORR);
+               tmp = 0;
+               break;
+           case AD_DCAY:
+               if (pd == &mons[PM_WOOD_GOLEM] ||
+                   pd == &mons[PM_LEATHER_GOLEM]) {
+                       pline("%s falls to pieces!", Monnam(mdef));
+                       xkilled(mdef,0);
+               }
+               hurtmarmor(mdef, AD_DCAY);
+               tmp = 0;
+               break;
+           case AD_DRST:
+           case AD_DRDX:
+           case AD_DRCO:
+               if (!negated && !rn2(8)) {
+                   Your("%s was poisoned!", mpoisons_subj(&youmonst, mattk));
+                   if (resists_poison(mdef))
+                       pline_The("poison doesn't seem to affect %s.",
+                               mon_nam(mdef));
+                   else {
+                       if (!rn2(10)) {
+                           Your("poison was deadly...");
+                           tmp = mdef->mhp;
+                       } else tmp += rn1(10,6);
+                   }
+               }
+               break;
+           case AD_DRIN:
+               if (notonhead || !has_head(mdef->data)) {
+                   pline("%s doesn't seem harmed.", Monnam(mdef));
+                   tmp = 0;
+                   if (!Unchanging && mdef->data == &mons[PM_GREEN_SLIME]) {
+                       if (!Slimed) {
+                           You("suck in some slime and don't feel very well.");
+                           Slimed = 10L;
+                       }
+                   }
+                   break;
+               }
+               if (m_slips_free(mdef, mattk)) break;
+
+               if ((mdef->misc_worn_check & W_ARMH) && rn2(8)) {
+                   pline("%s helmet blocks your attack to %s head.",
+                         s_suffix(Monnam(mdef)), mhis(mdef));
+                   break;
+               }
+
+               You("eat %s brain!", s_suffix(mon_nam(mdef)));
+               u.uconduct.food++;
+               if (touch_petrifies(mdef->data) && !Stone_resistance && !Stoned) {
+                   Stoned = 5;
+                   killer_format = KILLED_BY_AN;
+                   delayed_killer = mdef->data->mname;
+               }
+               if (!vegan(mdef->data))
+                   u.uconduct.unvegan++;
+               if (!vegetarian(mdef->data))
+                   violated_vegetarian();
+               if (mindless(mdef->data)) {
+                   pline("%s doesn't notice.", Monnam(mdef));
+                   break;
+               }
+               tmp += rnd(10);
+               morehungry(-rnd(30)); /* cannot choke */
+               if (ABASE(A_INT) < AMAX(A_INT)) {
+                       ABASE(A_INT) += rnd(4);
+                       if (ABASE(A_INT) > AMAX(A_INT))
+                               ABASE(A_INT) = AMAX(A_INT);
+                       flags.botl = 1;
+               }
+               exercise(A_WIS, TRUE);
+               break;
+           case AD_STCK:
+               if (!negated && !sticks(mdef->data))
+                   u.ustuck = mdef; /* it's now stuck to you */
+               break;
+           case AD_WRAP:
+               if (!sticks(mdef->data)) {
+                   if (!u.ustuck && !rn2(10)) {
+                       if (m_slips_free(mdef, mattk)) {
+                           tmp = 0;
+                       } else {
+                           You("swing yourself around %s!",
+                                 mon_nam(mdef));
+                           u.ustuck = mdef;
+                       }
+                   } else if(u.ustuck == mdef) {
+                       /* Monsters don't wear amulets of magical breathing */
+                       if (is_pool(u.ux,u.uy) && !is_swimmer(mdef->data) &&
+                           !amphibious(mdef->data)) {
+                           You("drown %s...", mon_nam(mdef));
+                           tmp = mdef->mhp;
+                       } else if(mattk->aatyp == AT_HUGS)
+                           pline("%s is being crushed.", Monnam(mdef));
+                   } else {
+                       tmp = 0;
+                       if (flags.verbose)
+                           You("brush against %s %s.",
+                               s_suffix(mon_nam(mdef)),
+                               mbodypart(mdef, LEG));
+                   }
+               } else tmp = 0;
+               break;
+           case AD_PLYS:
+               if (!negated && mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) {
+                   if (!Blind) pline("%s is frozen by you!", Monnam(mdef));
+                   mdef->mcanmove = 0;
+                   mdef->mfrozen = rnd(10);
+               }
+               break;
+           case AD_SLEE:
+               if (!negated && !mdef->msleeping &&
+                           sleep_monst(mdef, rnd(10), -1)) {
+                   if (!Blind)
+                       pline("%s is put to sleep by you!", Monnam(mdef));
+                   slept_monst(mdef);
+               }
+               break;
+           case AD_SLIM:
+               if (negated) break;     /* physical damage only */
+               if (!rn2(4) && !flaming(mdef->data) &&
+                               mdef->data != &mons[PM_GREEN_SLIME]) {
+                   You("turn %s into slime.", mon_nam(mdef));
+                   (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, FALSE);
+                   tmp = 0;
+               }
+               break;
+           case AD_ENCH:       /* KMH -- remove enchantment (disenchanter) */
+               /* there's no msomearmor() function, so just do damage */
+            /* if (negated) break; */
+               break;
+           case AD_SLOW:
+               if (!negated && mdef->mspeed != MSLOW) {
+                   unsigned int oldspeed = mdef->mspeed;
+
+                   mon_adjust_speed(mdef, -1, (struct obj *)0);
+                   if (mdef->mspeed != oldspeed && canseemon(mdef))
+                       pline("%s slows down.", Monnam(mdef));
+               }
+               break;
+           case AD_CONF:
+               if (!mdef->mconf) {
+                   if (canseemon(mdef))
+                       pline("%s looks confused.", Monnam(mdef));
+                   mdef->mconf = 1;
+               }
+               break;
+           default:    tmp = 0;
+               break;
+       }
+
+       mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */
+       if((mdef->mhp -= tmp) < 1) {
+           if (mdef->mtame && !cansee(mdef->mx,mdef->my)) {
+               You_feel("embarrassed for a moment.");
+               if (tmp) xkilled(mdef, 0); /* !tmp but hp<1: already killed */
+           } else if (!flags.verbose) {
+               You("destroy it!");
+               if (tmp) xkilled(mdef, 0);
+           } else
+               if (tmp) killed(mdef);
+           return(2);
+       }
+       return(1);
+}
+
+STATIC_OVL int
+explum(mdef, mattk)
+register struct monst *mdef;
+register struct attack *mattk;
+{
+       register int tmp = d((int)mattk->damn, (int)mattk->damd);
+
+       You("explode!");
+       switch(mattk->adtyp) {
+           boolean resistance; /* only for cold/fire/elec */
+
+           case AD_BLND:
+               if (!resists_blnd(mdef)) {
+                   pline("%s is blinded by your flash of light!", Monnam(mdef));
+                   mdef->mblinded = min((int)mdef->mblinded + tmp, 127);
+                   mdef->mcansee = 0;
+               }
+               break;
+           case AD_HALU:
+               if (haseyes(mdef->data) && mdef->mcansee) {
+                   pline("%s is affected by your flash of light!",
+                         Monnam(mdef));
+                   mdef->mconf = 1;
+               }
+               break;
+           case AD_COLD:
+               resistance = resists_cold(mdef);
+               goto common;
+           case AD_FIRE:
+               resistance = resists_fire(mdef);
+               goto common;
+           case AD_ELEC:
+               resistance = resists_elec(mdef);
+common:
+               if (!resistance) {
+                   pline("%s gets blasted!", Monnam(mdef));
+                   mdef->mhp -= tmp;
+                   if (mdef->mhp <= 0) {
+                        killed(mdef);
+                        return(2);
+                   }
+               } else {
+                   shieldeff(mdef->mx, mdef->my);
+                   if (is_golem(mdef->data))
+                       golemeffects(mdef, (int)mattk->adtyp, tmp);
+                   else
+                       pline_The("blast doesn't seem to affect %s.",
+                               mon_nam(mdef));
+               }
+               break;
+           default:
+               break;
+       }
+       return(1);
+}
+
+STATIC_OVL void
+start_engulf(mdef)
+struct monst *mdef;
+{
+       if (!Invisible) {
+               map_location(u.ux, u.uy, TRUE);
+               tmp_at(DISP_ALWAYS, mon_to_glyph(&youmonst));
+               tmp_at(mdef->mx, mdef->my);
+       }
+       You("engulf %s!", mon_nam(mdef));
+       delay_output();
+       delay_output();
+}
+
+STATIC_OVL void
+end_engulf()
+{
+       if (!Invisible) {
+               tmp_at(DISP_END, 0);
+               newsym(u.ux, u.uy);
+       }
+}
+
+STATIC_OVL int
+gulpum(mdef,mattk)
+register struct monst *mdef;
+register struct attack *mattk;
+{
+       register int tmp;
+       register int dam = d((int)mattk->damn, (int)mattk->damd);
+       struct obj *otmp;
+       /* Not totally the same as for real monsters.  Specifically, these
+        * don't take multiple moves.  (It's just too hard, for too little
+        * result, to program monsters which attack from inside you, which
+        * would be necessary if done accurately.)  Instead, we arbitrarily
+        * kill the monster immediately for AD_DGST and we regurgitate them
+        * after exactly 1 round of attack otherwise.  -KAA
+        */
+
+       if(mdef->data->msize >= MZ_HUGE) return 0;
+
+       if(u.uhunger < 1500 && !u.uswallow) {
+           for (otmp = mdef->minvent; otmp; otmp = otmp->nobj)
+               (void) snuff_lit(otmp);
+
+           if(!touch_petrifies(mdef->data) || Stone_resistance) {
+#ifdef LINT    /* static char msgbuf[BUFSZ]; */
+               char msgbuf[BUFSZ];
+#else
+               static char msgbuf[BUFSZ];
+#endif
+               start_engulf(mdef);
+               switch(mattk->adtyp) {
+                   case AD_DGST:
+                       /* eating a Rider or its corpse is fatal */
+                       if (is_rider(mdef->data)) {
+                        pline("Unfortunately, digesting any of it is fatal.");
+                           end_engulf();
+                           Sprintf(msgbuf, "unwisely tried to eat %s",
+                                   mdef->data->mname);
+                           killer = msgbuf;
+                           killer_format = NO_KILLER_PREFIX;
+                           done(DIED);
+                           return 0;           /* lifesaved */
+                       }
+
+                       if (Slow_digestion) {
+                           dam = 0;
+                           break;
+                       }
+
+                       /* KMH, conduct */
+                       u.uconduct.food++;
+                       if (!vegan(mdef->data))
+                            u.uconduct.unvegan++;
+                       if (!vegetarian(mdef->data))
+                            violated_vegetarian();
+
+                       /* Use up amulet of life saving */
+                       if (!!(otmp = mlifesaver(mdef))) m_useup(mdef, otmp);
+
+                       newuhs(FALSE);
+                       xkilled(mdef,2);
+                       if (mdef->mhp > 0) { /* monster lifesaved */
+                           You("hurriedly regurgitate the sizzling in your %s.",
+                               body_part(STOMACH));
+                       } else {
+                           tmp = 1 + (mdef->data->cwt >> 8);
+                           if (corpse_chance(mdef, &youmonst, TRUE) &&
+                               !(mvitals[monsndx(mdef->data)].mvflags &
+                                 G_NOCORPSE)) {
+                               /* nutrition only if there can be a corpse */
+                               u.uhunger += (mdef->data->cnutrit+1) / 2;
+                           } else tmp = 0;
+                           Sprintf(msgbuf, "You totally digest %s.",
+                                           mon_nam(mdef));
+                           if (tmp != 0) {
+                               /* setting afternmv = end_engulf is tempting,
+                                * but will cause problems if the player is
+                                * attacked (which uses his real location) or
+                                * if his See_invisible wears off
+                                */
+                               You("digest %s.", mon_nam(mdef));
+                               if (Slow_digestion) tmp *= 2;
+                               nomul(-tmp);
+                               nomovemsg = msgbuf;
+                           } else pline("%s", msgbuf);
+                           if (mdef->data == &mons[PM_GREEN_SLIME]) {
+                               Sprintf(msgbuf, "%s isn't sitting well with you.",
+                                       The(mdef->data->mname));
+                               if (!Unchanging) {
+                                       Slimed = 5L;
+                                       flags.botl = 1;
+                               }
+                           } else
+                           exercise(A_CON, TRUE);
+                       }
+                       end_engulf();
+                       return(2);
+                   case AD_PHYS:
+                       if (youmonst.data == &mons[PM_FOG_CLOUD]) {
+                           pline("%s is laden with your moisture.",
+                                 Monnam(mdef));
+                           if (amphibious(mdef->data) &&
+                               !flaming(mdef->data)) {
+                               dam = 0;
+                               pline("%s seems unharmed.", Monnam(mdef));
+                           }
+                       } else
+                           pline("%s is pummeled with your debris!",
+                                 Monnam(mdef));
+                       break;
+                   case AD_ACID:
+                       pline("%s is covered with your goo!", Monnam(mdef));
+                       if (resists_acid(mdef)) {
+                           pline("It seems harmless to %s.", mon_nam(mdef));
+                           dam = 0;
+                       }
+                       break;
+                   case AD_BLND:
+                       if (can_blnd(&youmonst, mdef, mattk->aatyp, (struct obj *)0)) {
+                           if (mdef->mcansee)
+                               pline("%s can't see in there!", Monnam(mdef));
+                           mdef->mcansee = 0;
+                           dam += mdef->mblinded;
+                           if (dam > 127) dam = 127;
+                           mdef->mblinded = dam;
+                       }
+                       dam = 0;
+                       break;
+                   case AD_ELEC:
+                       if (rn2(2)) {
+                           pline_The("air around %s crackles with electricity.", mon_nam(mdef));
+                           if (resists_elec(mdef)) {
+                               pline("%s seems unhurt.", Monnam(mdef));
+                               dam = 0;
+                           }
+                           golemeffects(mdef,(int)mattk->adtyp,dam);
+                       } else dam = 0;
+                       break;
+                   case AD_COLD:
+                       if (rn2(2)) {
+                           if (resists_cold(mdef)) {
+                               pline("%s seems mildly chilly.", Monnam(mdef));
+                               dam = 0;
+                           } else
+                               pline("%s is freezing to death!",Monnam(mdef));
+                           golemeffects(mdef,(int)mattk->adtyp,dam);
+                       } else dam = 0;
+                       break;
+                   case AD_FIRE:
+                       if (rn2(2)) {
+                           if (resists_fire(mdef)) {
+                               pline("%s seems mildly hot.", Monnam(mdef));
+                               dam = 0;
+                           } else
+                               pline("%s is burning to a crisp!",Monnam(mdef));
+                           golemeffects(mdef,(int)mattk->adtyp,dam);
+                       } else dam = 0;
+                       break;
+               }
+               end_engulf();
+               if ((mdef->mhp -= dam) <= 0) {
+                   killed(mdef);
+                   if (mdef->mhp <= 0) /* not lifesaved */
+                       return(2);
+               }
+               You("%s %s!", is_animal(youmonst.data) ? "regurgitate"
+                       : "expel", mon_nam(mdef));
+               if (Slow_digestion || is_animal(youmonst.data)) {
+                   pline("Obviously, you didn't like %s taste.",
+                         s_suffix(mon_nam(mdef)));
+               }
+           } else {
+               char kbuf[BUFSZ];
+
+               You("bite into %s.", mon_nam(mdef));
+               Sprintf(kbuf, "swallowing %s whole", an(mdef->data->mname));
+               instapetrify(kbuf);
+           }
+       }
+       return(0);
+}
+
+void
+missum(mdef,mattk)
+register struct monst *mdef;
+register struct attack *mattk;
+{
+       if (could_seduce(&youmonst, mdef, mattk))
+               You("pretend to be friendly to %s.", mon_nam(mdef));
+       else if(canspotmon(mdef) && flags.verbose)
+               You("miss %s.", mon_nam(mdef));
+       else
+               You("miss it.");
+       if (!mdef->msleeping && mdef->mcanmove)
+               wakeup(mdef);
+}
+
+STATIC_OVL boolean
+hmonas(mon, tmp)               /* attack monster as a monster. */
+register struct monst *mon;
+register int tmp;
+{
+       struct attack *mattk, alt_attk;
+       int     i, sum[NATTK], hittmp = 0;
+       int     nsum = 0;
+       int     dhit = 0;
+
+       for(i = 0; i < NATTK; i++) {
+
+           sum[i] = 0;
+           mattk = getmattk(youmonst.data, i, sum, &alt_attk);
+           switch(mattk->aatyp) {
+               case AT_WEAP:
+use_weapon:
+       /* Certain monsters don't use weapons when encountered as enemies,
+        * but players who polymorph into them have hands or claws and thus
+        * should be able to use weapons.  This shouldn't prohibit the use
+        * of most special abilities, either.
+        */
+       /* Potential problem: if the monster gets multiple weapon attacks,
+        * we currently allow the player to get each of these as a weapon
+        * attack.  Is this really desirable?
+        */
+                       if (uwep) {
+                           hittmp = hitval(uwep, mon);
+                           hittmp += weapon_hit_bonus(uwep);
+                           tmp += hittmp;
+                       }
+                       dhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
+                       /* KMH -- Don't accumulate to-hit bonuses */
+                       if (uwep) tmp -= hittmp;
+                       /* Enemy dead, before any special abilities used */
+                       if (!known_hitum(mon,&dhit,mattk)) {
+                           sum[i] = 2;
+                           break;
+                       } else sum[i] = dhit;
+                       /* might be a worm that gets cut in half */
+                       if (m_at(u.ux+u.dx, u.uy+u.dy) != mon) return((boolean)(nsum != 0));
+                       /* Do not print "You hit" message, since known_hitum
+                        * already did it.
+                        */
+                       if (dhit && mattk->adtyp != AD_SPEL
+                               && mattk->adtyp != AD_PHYS)
+                               sum[i] = damageum(mon,mattk);
+                       break;
+               case AT_CLAW:
+                       if (i==0 && uwep && !cantwield(youmonst.data)) goto use_weapon;
+#ifdef SEDUCE
+                       /* succubi/incubi are humanoid, but their _second_
+                        * attack is AT_CLAW, not their first...
+                        */
+                       if (i==1 && uwep && (u.umonnum == PM_SUCCUBUS ||
+                               u.umonnum == PM_INCUBUS)) goto use_weapon;
+#endif
+               case AT_KICK:
+               case AT_BITE:
+               case AT_STNG:
+               case AT_TUCH:
+               case AT_BUTT:
+               case AT_TENT:
+                       if (i==0 && uwep && (youmonst.data->mlet==S_LICH)) goto use_weapon;
+                       if ((dhit = (tmp > rnd(20) || u.uswallow)) != 0) {
+                           int compat;
+
+                           if (!u.uswallow &&
+                               (compat=could_seduce(&youmonst, mon, mattk))) {
+                               You("%s %s %s.",
+                                   mon->mcansee && haseyes(mon->data)
+                                   ? "smile at" : "talk to",
+                                   mon_nam(mon),
+                                   compat == 2 ? "engagingly":"seductively");
+                               /* doesn't anger it; no wakeup() */
+                               sum[i] = damageum(mon, mattk);
+                               break;
+                           }
+                           wakeup(mon);
+                           /* maybe this check should be in damageum()? */
+                           if (mon->data == &mons[PM_SHADE] &&
+                                       !(mattk->aatyp == AT_KICK &&
+                                           uarmf && uarmf->blessed)) {
+                               Your("attack passes harmlessly through %s.",
+                                   mon_nam(mon));
+                               break;
+                           }
+                           if (mattk->aatyp == AT_KICK)
+                                   You("kick %s.", mon_nam(mon));
+                           else if (mattk->aatyp == AT_BITE)
+                                   You("bite %s.", mon_nam(mon));
+                           else if (mattk->aatyp == AT_STNG)
+                                   You("sting %s.", mon_nam(mon));
+                           else if (mattk->aatyp == AT_BUTT)
+                                   You("butt %s.", mon_nam(mon));
+                           else if (mattk->aatyp == AT_TUCH)
+                                   You("touch %s.", mon_nam(mon));
+                           else if (mattk->aatyp == AT_TENT)
+                                   Your("tentacles suck %s.", mon_nam(mon));
+                           else You("hit %s.", mon_nam(mon));
+                           sum[i] = damageum(mon, mattk);
+                       } else
+                           missum(mon, mattk);
+                       break;
+
+               case AT_HUGS:
+                       /* automatic if prev two attacks succeed, or if
+                        * already grabbed in a previous attack
+                        */
+                       dhit = 1;
+                       wakeup(mon);
+                       if (mon->data == &mons[PM_SHADE])
+                           Your("hug passes harmlessly through %s.",
+                               mon_nam(mon));
+                       else if (!sticks(mon->data) && !u.uswallow) {
+                           if (mon==u.ustuck) {
+                               pline("%s is being %s.", Monnam(mon),
+                                   u.umonnum==PM_ROPE_GOLEM ? "choked":
+                                   "crushed");
+                               sum[i] = damageum(mon, mattk);
+                           } else if(i >= 2 && sum[i-1] && sum[i-2]) {
+                               You("grab %s!", mon_nam(mon));
+                               u.ustuck = mon;
+                               sum[i] = damageum(mon, mattk);
+                           }
+                       }
+                       break;
+
+               case AT_EXPL:   /* automatic hit if next to */
+                       dhit = -1;
+                       wakeup(mon);
+                       sum[i] = explum(mon, mattk);
+                       break;
+
+               case AT_ENGL:
+                       if((dhit = (tmp > rnd(20+i)))) {
+                               wakeup(mon);
+                               if (mon->data == &mons[PM_SHADE])
+                                   Your("attempt to surround %s is harmless.",
+                                       mon_nam(mon));
+                               else {
+                                   sum[i]= gulpum(mon,mattk);
+                                   if (sum[i] == 2 &&
+                                           (mon->data->mlet == S_ZOMBIE ||
+                                               mon->data->mlet == S_MUMMY) &&
+                                           rn2(5) &&
+                                           !Sick_resistance) {
+                                       You_feel("%ssick.",
+                                           (Sick) ? "very " : "");
+                                       mdamageu(mon, rnd(8));
+                                   }
+                               }
+                       } else
+                               missum(mon, mattk);
+                       break;
+
+               case AT_MAGC:
+                       /* No check for uwep; if wielding nothing we want to
+                        * do the normal 1-2 points bare hand damage...
+                        */
+                       if (i==0 && (youmonst.data->mlet==S_KOBOLD
+                               || youmonst.data->mlet==S_ORC
+                               || youmonst.data->mlet==S_GNOME
+                               )) goto use_weapon;
+
+               case AT_NONE:
+               case AT_BOOM:
+                       continue;
+                       /* Not break--avoid passive attacks from enemy */
+
+               case AT_BREA:
+               case AT_SPIT:
+               case AT_GAZE:   /* all done using #monster command */
+                       dhit = 0;
+                       break;
+
+               default: /* Strange... */
+                       impossible("strange attack of yours (%d)",
+                                mattk->aatyp);
+           }
+           if (dhit == -1) {
+               u.mh = -1;      /* dead in the current form */
+               rehumanize();
+           }
+           if (sum[i] == 2)
+               return((boolean)passive(mon, 1, 0, mattk->aatyp));
+                                                       /* defender dead */
+           else {
+               (void) passive(mon, sum[i], 1, mattk->aatyp);
+               nsum |= sum[i];
+           }
+           if (!Upolyd)
+               break; /* No extra attacks if no longer a monster */
+           if (multi < 0)
+               break; /* If paralyzed while attacking, i.e. floating eye */
+       }
+       return((boolean)(nsum != 0));
+}
+
+/*     Special (passive) attacks on you by monsters done here.         */
+
+int
+passive(mon, mhit, malive, aatyp)
+register struct monst *mon;
+register boolean mhit;
+register int malive;
+uchar aatyp;
+{
+       register struct permonst *ptr = mon->data;
+       register int i, tmp;
+
+       for(i = 0; ; i++) {
+           if(i >= NATTK) return(malive | mhit);       /* no passive attacks */
+           if(ptr->mattk[i].aatyp == AT_NONE) break;   /* try this one */
+       }
+       /* Note: tmp not always used */
+       if (ptr->mattk[i].damn)
+           tmp = d((int)ptr->mattk[i].damn, (int)ptr->mattk[i].damd);
+       else if(ptr->mattk[i].damd)
+           tmp = d((int)mon->m_lev+1, (int)ptr->mattk[i].damd);
+       else
+           tmp = 0;
+
+/*     These affect you even if they just died */
+
+       switch(ptr->mattk[i].adtyp) {
+
+         case AD_ACID:
+           if(mhit && rn2(2)) {
+               if (Blind || !flags.verbose) You("are splashed!");
+               else    You("are splashed by %s acid!",
+                                       s_suffix(mon_nam(mon)));
+
+               if (!Acid_resistance)
+                       mdamageu(mon, tmp);
+               if(!rn2(30)) erode_armor(&youmonst, TRUE);
+           }
+           if (mhit) {
+               if (aatyp == AT_KICK) {
+                   if (uarmf && !rn2(6))
+                       (void)rust_dmg(uarmf, xname(uarmf), 3, TRUE, &youmonst);
+               } else if (aatyp == AT_WEAP || aatyp == AT_CLAW ||
+                          aatyp == AT_MAGC || aatyp == AT_TUCH)
+                   passive_obj(mon, (struct obj*)0, &(ptr->mattk[i]));
+           }
+           exercise(A_STR, FALSE);
+           break;
+         case AD_STON:
+           if (mhit) {         /* successful attack */
+               long protector = attk_protection((int)aatyp);
+
+               /* hero using monsters' AT_MAGC attack is hitting hand to
+                  hand rather than casting a spell */
+               if (aatyp == AT_MAGC) protector = W_ARMG;
+
+               if (protector == 0L ||          /* no protection */
+                       (protector == W_ARMG && !uarmg && !uwep) ||
+                       (protector == W_ARMF && !uarmf) ||
+                       (protector == W_ARMH && !uarmh) ||
+                       (protector == (W_ARMC|W_ARMG) && (!uarmc || !uarmg))) {
+                   if (!Stone_resistance &&
+                           !(poly_when_stoned(youmonst.data) &&
+                               polymon(PM_STONE_GOLEM))) {
+                       You("turn to stone...");
+                       done_in_by(mon);
+                       return 2;
+                   }
+               }
+           }
+           break;
+         case AD_RUST:
+           if(mhit && !mon->mcan) {
+               if (aatyp == AT_KICK) {
+                   if (uarmf)
+                       (void)rust_dmg(uarmf, xname(uarmf), 1, TRUE, &youmonst);
+               } else if (aatyp == AT_WEAP || aatyp == AT_CLAW ||
+                          aatyp == AT_MAGC || aatyp == AT_TUCH)
+                   passive_obj(mon, (struct obj*)0, &(ptr->mattk[i]));
+           }
+           break;
+         case AD_CORR:
+           if(mhit && !mon->mcan) {
+               if (aatyp == AT_KICK) {
+                   if (uarmf)
+                       (void)rust_dmg(uarmf, xname(uarmf), 3, TRUE, &youmonst);
+               } else if (aatyp == AT_WEAP || aatyp == AT_CLAW ||
+                          aatyp == AT_MAGC || aatyp == AT_TUCH)
+                   passive_obj(mon, (struct obj*)0, &(ptr->mattk[i]));
+           }
+           break;
+         case AD_MAGM:
+           /* wrath of gods for attacking Oracle */
+           if(Antimagic) {
+               shieldeff(u.ux, u.uy);
+               pline("A hail of magic missiles narrowly misses you!");
+           } else {
+               You("are hit by magic missiles appearing from thin air!");
+               mdamageu(mon, tmp);
+           }
+           break;
+         case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
+           if (mhit) {
+               struct obj *obj = (struct obj *)0;
+
+               if (aatyp == AT_KICK) {
+                   obj = uarmf;
+                   if (!obj) break;
+               } else if (aatyp == AT_BITE || aatyp == AT_BUTT ||
+                          (aatyp >= AT_STNG && aatyp < AT_WEAP)) {
+                   break;              /* no object involved */
+               }
+               passive_obj(mon, obj, &(ptr->mattk[i]));
+           }
+           break;
+         default:
+           break;
+       }
+
+/*     These only affect you if they still live */
+
+       if(malive && !mon->mcan && rn2(3)) {
+
+           switch(ptr->mattk[i].adtyp) {
+
+             case AD_PLYS:
+               if(ptr == &mons[PM_FLOATING_EYE]) {
+                   if (!canseemon(mon)) {
+                       break;
+                   }
+                   if(mon->mcansee) {
+                       if (ureflects("%s gaze is reflected by your %s.",
+                                   s_suffix(Monnam(mon))))
+                           ;
+                       else if (Free_action)
+                           You("momentarily stiffen under %s gaze!",
+                                   s_suffix(mon_nam(mon)));
+                       else {
+                           You("are frozen by %s gaze!",
+                                 s_suffix(mon_nam(mon)));
+                           nomul((ACURR(A_WIS) > 12 || rn2(4)) ? -tmp : -127);
+                       }
+                   } else {
+                       pline("%s cannot defend itself.",
+                               Adjmonnam(mon,"blind"));
+                       if(!rn2(500)) change_luck(-1);
+                   }
+               } else if (Free_action) {
+                   You("momentarily stiffen.");
+               } else { /* gelatinous cube */
+                   You("are frozen by %s!", mon_nam(mon));
+                   nomovemsg = 0;      /* default: "you can move again" */
+                   nomul(-tmp);
+                   exercise(A_DEX, FALSE);
+               }
+               break;
+             case AD_COLD:             /* brown mold or blue jelly */
+               if(monnear(mon, u.ux, u.uy)) {
+                   if(Cold_resistance) {
+                       shieldeff(u.ux, u.uy);
+                       You_feel("a mild chill.");
+                       ugolemeffects(AD_COLD, tmp);
+                       break;
+                   }
+                   You("are suddenly very cold!");
+                   mdamageu(mon, tmp);
+               /* monster gets stronger with your heat! */
+                   mon->mhp += tmp / 2;
+                   if (mon->mhpmax < mon->mhp) mon->mhpmax = mon->mhp;
+               /* at a certain point, the monster will reproduce! */
+                   if(mon->mhpmax > ((int) (mon->m_lev+1) * 8))
+                       (void)split_mon(mon, &youmonst);
+               }
+               break;
+             case AD_STUN:             /* specifically yellow mold */
+               if(!Stunned)
+                   make_stunned((long)tmp, TRUE);
+               break;
+             case AD_FIRE:
+               if(monnear(mon, u.ux, u.uy)) {
+                   if(Fire_resistance) {
+                       shieldeff(u.ux, u.uy);
+                       You_feel("mildly warm.");
+                       ugolemeffects(AD_FIRE, tmp);
+                       break;
+                   }
+                   You("are suddenly very hot!");
+                   mdamageu(mon, tmp);
+               }
+               break;
+             case AD_ELEC:
+               if(Shock_resistance) {
+                   shieldeff(u.ux, u.uy);
+                   You_feel("a mild tingle.");
+                   ugolemeffects(AD_ELEC, tmp);
+                   break;
+               }
+               You("are jolted with electricity!");
+               mdamageu(mon, tmp);
+               break;
+             default:
+               break;
+           }
+       }
+       return(malive | mhit);
+}
+
+/*
+ * Special (passive) attacks on an attacking object by monsters done here.
+ * Assumes the attack was successful.
+ */
+void
+passive_obj(mon, obj, mattk)
+register struct monst *mon;
+register struct obj *obj;      /* null means pick uwep, uswapwep or uarmg */
+struct attack *mattk;          /* null means we find one internally */
+{
+       register struct permonst *ptr = mon->data;
+       register int i;
+
+       /* if caller hasn't specified an object, use uwep, uswapwep or uarmg */
+       if (!obj) {
+           obj = (u.twoweap && uswapwep && !rn2(2)) ? uswapwep : uwep;
+           if (!obj && mattk->adtyp == AD_ENCH)
+               obj = uarmg;            /* no weapon? then must be gloves */
+           if (!obj) return;           /* no object to affect */
+       }
+
+       /* if caller hasn't specified an attack, find one */
+       if (!mattk) {
+           for(i = 0; ; i++) {
+               if(i >= NATTK) return;  /* no passive attacks */
+               if(ptr->mattk[i].aatyp == AT_NONE) break; /* try this one */
+           }
+           mattk = &(ptr->mattk[i]);
+       }
+
+       switch(mattk->adtyp) {
+
+       case AD_ACID:
+           if(!rn2(6)) {
+               erode_obj(obj, TRUE, FALSE);
+           }
+           break;
+       case AD_RUST:
+           if(!mon->mcan) {
+               erode_obj(obj, FALSE, FALSE);
+           }
+           break;
+       case AD_CORR:
+           if(!mon->mcan) {
+               erode_obj(obj, TRUE, FALSE);
+           }
+           break;
+       case AD_ENCH:
+           if (!mon->mcan) {
+               if (drain_item(obj) && carried(obj) &&
+                   (obj->known || obj->oclass == ARMOR_CLASS)) {
+                   Your("%s less effective.", aobjnam(obj, "seem"));
+               }
+               break;
+           }
+         default:
+           break;
+       }
+
+       if (carried(obj)) update_inventory();
+}
+
+/* Note: caller must ascertain mtmp is mimicking... */
+void
+stumble_onto_mimic(mtmp)
+struct monst *mtmp;
+{
+       const char *fmt = "Wait!  That's %s!",
+                  *generic = "a monster",
+                  *what = 0;
+
+       if(!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data,AD_STCK))
+           u.ustuck = mtmp;
+
+       if (Blind) {
+           if (!Blind_telepat)
+               what = generic;         /* with default fmt */
+           else if (mtmp->m_ap_type == M_AP_MONSTER)
+               what = a_monnam(mtmp);  /* differs from what was sensed */
+       } else {
+           int glyph = levl[u.ux+u.dx][u.uy+u.dy].glyph;
+
+           if (glyph_is_cmap(glyph) &&
+                   (glyph_to_cmap(glyph) == S_hcdoor ||
+                    glyph_to_cmap(glyph) == S_vcdoor))
+               fmt = "The door actually was %s!";
+           else if (glyph_is_object(glyph) &&
+                   glyph_to_obj(glyph) == GOLD_PIECE)
+               fmt = "That gold was %s!";
+
+           /* cloned Wiz starts out mimicking some other monster and
+              might make himself invisible before being revealed */
+           if (mtmp->minvis && !See_invisible)
+               what = generic;
+           else
+               what = a_monnam(mtmp);
+       }
+       if (what) pline(fmt, what);
+
+       wakeup(mtmp);   /* clears mimicking */
+}
+
+STATIC_OVL void
+nohandglow(mon)
+struct monst *mon;
+{
+       char *hands=makeplural(body_part(HAND));
+
+       if (!u.umconf || mon->mconf) return;
+       if (u.umconf == 1) {
+               if (Blind)
+                       Your("%s stop tingling.", hands);
+               else
+                       Your("%s stop glowing %s.", hands, hcolor(NH_RED));
+       } else {
+               if (Blind)
+                       pline_The("tingling in your %s lessens.", hands);
+               else
+                       Your("%s no longer glow so brightly %s.", hands,
+                               hcolor(NH_RED));
+       }
+       u.umconf--;
+}
+
+int
+flash_hits_mon(mtmp, otmp)
+struct monst *mtmp;
+struct obj *otmp;      /* source of flash */
+{
+       int tmp, amt, res = 0, useeit = canseemon(mtmp);
+
+       if (mtmp->msleeping) {
+           mtmp->msleeping = 0;
+           if (useeit) {
+               pline_The("flash awakens %s.", mon_nam(mtmp));
+               res = 1;
+           }
+       } else if (mtmp->data->mlet != S_LIGHT) {
+           if (!resists_blnd(mtmp)) {
+               tmp = dist2(otmp->ox, otmp->oy, mtmp->mx, mtmp->my);
+               if (useeit) {
+                   pline("%s is blinded by the flash!", Monnam(mtmp));
+                   res = 1;
+               }
+               if (mtmp->data == &mons[PM_GREMLIN]) {
+                   /* Rule #1: Keep them out of the light. */
+                   amt = otmp->otyp == WAN_LIGHT ? d(1 + otmp->spe, 4) :
+                         rn2(min(mtmp->mhp,4));
+                   pline("%s %s!", Monnam(mtmp), amt > mtmp->mhp / 2 ?
+                         "wails in agony" : "cries out in pain");
+                   if ((mtmp->mhp -= amt) <= 0) {
+                       if (flags.mon_moving)
+                           monkilled(mtmp, (char *)0, AD_BLND);
+                       else
+                           killed(mtmp);
+                   } else if (cansee(mtmp->mx,mtmp->my) && !canspotmon(mtmp)){
+                       map_invisible(mtmp->mx, mtmp->my);
+                   }
+               }
+               if (mtmp->mhp > 0) {
+                   if (!flags.mon_moving) setmangry(mtmp);
+                   if (tmp < 9 && !mtmp->isshk && rn2(4)) {
+                       if (rn2(4))
+                           monflee(mtmp, rnd(100), FALSE, TRUE);
+                       else
+                           monflee(mtmp, 0, FALSE, TRUE);
+                   }
+                   mtmp->mcansee = 0;
+                   mtmp->mblinded = (tmp < 3) ? 0 : rnd(1 + 50/tmp);
+               }
+           }
+       }
+       return res;
+}
+
+/*uhitm.c*/
diff --git a/src/vault.c b/src/vault.c
new file mode 100644 (file)
index 0000000..8f8b27e
--- /dev/null
@@ -0,0 +1,826 @@
+/*     SCCS Id: @(#)vault.c    3.4     2003/01/15      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "vault.h"
+
+STATIC_DCL struct monst *NDECL(findgd);
+
+#define g_monnam(mtmp) \
+       x_monnam(mtmp, ARTICLE_NONE, (char *)0, SUPPRESS_IT, FALSE)
+
+#ifdef OVLB
+
+STATIC_DCL boolean FDECL(clear_fcorr, (struct monst *,BOOLEAN_P));
+STATIC_DCL void FDECL(restfakecorr,(struct monst *));
+STATIC_DCL boolean FDECL(in_fcorridor, (struct monst *,int,int));
+STATIC_DCL void FDECL(move_gold,(struct obj *,int));
+STATIC_DCL void FDECL(wallify_vault,(struct monst *));
+
+STATIC_OVL boolean
+clear_fcorr(grd, forceshow)
+register struct monst *grd;
+register boolean forceshow;
+{
+       register int fcx, fcy, fcbeg;
+       register struct monst *mtmp;
+
+       if (!on_level(&(EGD(grd)->gdlevel), &u.uz)) return TRUE;
+
+       while((fcbeg = EGD(grd)->fcbeg) < EGD(grd)->fcend) {
+               fcx = EGD(grd)->fakecorr[fcbeg].fx;
+               fcy = EGD(grd)->fakecorr[fcbeg].fy;
+               if((grd->mhp <= 0 || !in_fcorridor(grd, u.ux, u.uy)) &&
+                                  EGD(grd)->gddone)
+                       forceshow = TRUE;
+               if((u.ux == fcx && u.uy == fcy && grd->mhp > 0)
+                       || (!forceshow && couldsee(fcx,fcy))
+                       || (Punished && !carried(uball)
+                               && uball->ox == fcx && uball->oy == fcy))
+                       return FALSE;
+
+               if ((mtmp = m_at(fcx,fcy)) != 0) {
+                       if(mtmp->isgd) return(FALSE);
+                       else if(!in_fcorridor(grd, u.ux, u.uy)) {
+                           if(mtmp->mtame) yelp(mtmp);
+                           (void) rloc(mtmp, FALSE);
+                       }
+               }
+               levl[fcx][fcy].typ = EGD(grd)->fakecorr[fcbeg].ftyp;
+               map_location(fcx, fcy, 1);      /* bypass vision */
+               if(!ACCESSIBLE(levl[fcx][fcy].typ)) block_point(fcx,fcy);
+               EGD(grd)->fcbeg++;
+       }
+       if(grd->mhp <= 0) {
+           pline_The("corridor disappears.");
+           if(IS_ROCK(levl[u.ux][u.uy].typ)) You("are encased in rock.");
+       }
+       return(TRUE);
+}
+
+STATIC_OVL void
+restfakecorr(grd)
+register struct monst *grd;
+{
+       /* it seems you left the corridor - let the guard disappear */
+       if(clear_fcorr(grd, FALSE)) mongone(grd);
+}
+
+boolean
+grddead(grd)                           /* called in mon.c */
+register struct monst *grd;
+{
+       register boolean dispose = clear_fcorr(grd, TRUE);
+
+       if(!dispose) {
+               /* see comment by newpos in gd_move() */
+               remove_monster(grd->mx, grd->my);
+               newsym(grd->mx, grd->my);
+               place_monster(grd, 0, 0);
+               EGD(grd)->ogx = grd->mx;
+               EGD(grd)->ogy = grd->my;
+               dispose = clear_fcorr(grd, TRUE);
+       }
+       return(dispose);
+}
+
+STATIC_OVL boolean
+in_fcorridor(grd, x, y)
+register struct monst *grd;
+int x, y;
+{
+       register int fci;
+
+       for(fci = EGD(grd)->fcbeg; fci < EGD(grd)->fcend; fci++)
+               if(x == EGD(grd)->fakecorr[fci].fx &&
+                               y == EGD(grd)->fakecorr[fci].fy)
+                       return(TRUE);
+       return(FALSE);
+}
+
+STATIC_OVL
+struct monst *
+findgd()
+{
+       register struct monst *mtmp;
+
+       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+           if(mtmp->isgd && !DEADMONSTER(mtmp) && on_level(&(EGD(mtmp)->gdlevel), &u.uz))
+               return(mtmp);
+       return((struct monst *)0);
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+char
+vault_occupied(array)
+char *array;
+{
+       register char *ptr;
+
+       for (ptr = array; *ptr; ptr++)
+               if (rooms[*ptr - ROOMOFFSET].rtype == VAULT)
+                       return(*ptr);
+       return('\0');
+}
+
+void
+invault()
+{
+#ifdef BSD_43_BUG
+    int dummy;         /* hack to avoid schain botch */
+#endif
+    struct monst *guard;
+    int trycount, vaultroom = (int)vault_occupied(u.urooms);
+
+    if(!vaultroom) {
+       u.uinvault = 0;
+       return;
+    }
+
+    vaultroom -= ROOMOFFSET;
+
+    guard = findgd();
+    if(++u.uinvault % 30 == 0 && !guard) { /* if time ok and no guard now. */
+       char buf[BUFSZ];
+       register int x, y, dd, gx, gy;
+       int lx = 0, ly = 0;
+#ifdef GOLDOBJ
+        long umoney;
+#endif
+       /* first find the goal for the guard */
+       for(dd = 2; (dd < ROWNO || dd < COLNO); dd++) {
+         for(y = u.uy-dd; y <= u.uy+dd; ly = y, y++) {
+           if(y < 0 || y > ROWNO-1) continue;
+           for(x = u.ux-dd; x <= u.ux+dd; lx = x, x++) {
+             if(y != u.uy-dd && y != u.uy+dd && x != u.ux-dd)
+               x = u.ux+dd;
+             if(x < 1 || x > COLNO-1) continue;
+             if(levl[x][y].typ == CORR) {
+                 if(x < u.ux) lx = x + 1;
+                 else if(x > u.ux) lx = x - 1;
+                 else lx = x;
+                 if(y < u.uy) ly = y + 1;
+                 else if(y > u.uy) ly = y - 1;
+                 else ly = y;
+                 if(levl[lx][ly].typ != STONE && levl[lx][ly].typ != CORR)
+                     goto incr_radius;
+                 goto fnd;
+             }
+           }
+         }
+incr_radius: ;
+       }
+       impossible("Not a single corridor on this level??");
+       tele();
+       return;
+fnd:
+       gx = x; gy = y;
+
+       /* next find a good place for a door in the wall */
+       x = u.ux; y = u.uy;
+       if(levl[x][y].typ != ROOM) {  /* player dug a door and is in it */
+               if(levl[x+1][y].typ == ROOM)  x = x + 1;
+               else if(levl[x][y+1].typ == ROOM) y = y + 1;
+               else if(levl[x-1][y].typ == ROOM) x = x - 1;
+               else if(levl[x][y-1].typ == ROOM) y = y - 1;
+               else if(levl[x+1][y+1].typ == ROOM) {
+                       x = x + 1;
+                       y = y + 1;
+               } else if (levl[x-1][y-1].typ == ROOM) {
+                       x = x - 1;
+                       y = y - 1;
+               } else if (levl[x+1][y-1].typ == ROOM) {
+                       x = x + 1;
+                       y = y - 1;
+               } else if (levl[x-1][y+1].typ == ROOM) {
+                       x = x - 1;
+                       y = y + 1;
+               }
+       }
+       while(levl[x][y].typ == ROOM) {
+               register int dx,dy;
+
+               dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
+               dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
+               if(abs(gx-x) >= abs(gy-y))
+                       x += dx;
+               else
+                       y += dy;
+       }
+       if(x == u.ux && y == u.uy) {
+               if(levl[x+1][y].typ == HWALL || levl[x+1][y].typ == DOOR)
+                       x = x + 1;
+               else if(levl[x-1][y].typ == HWALL || levl[x-1][y].typ == DOOR)
+                       x = x - 1;
+               else if(levl[x][y+1].typ == VWALL || levl[x][y+1].typ == DOOR)
+                       y = y + 1;
+               else if(levl[x][y-1].typ == VWALL || levl[x][y-1].typ == DOOR)
+                       y = y - 1;
+               else return;
+       }
+
+       /* make something interesting happen */
+       if(!(guard = makemon(&mons[PM_GUARD], x, y, NO_MM_FLAGS))) return;
+       guard->isgd = 1;
+       guard->mpeaceful = 1;
+       set_malign(guard);
+       EGD(guard)->gddone = 0;
+       EGD(guard)->ogx = x;
+       EGD(guard)->ogy = y;
+       assign_level(&(EGD(guard)->gdlevel), &u.uz);
+       EGD(guard)->vroom = vaultroom;
+       EGD(guard)->warncnt = 0;
+
+       reset_faint();                  /* if fainted - wake up */
+       if (canspotmon(guard))
+           pline("Suddenly one of the Vault's %s enters!",
+                 makeplural(g_monnam(guard)));
+       else
+           pline("Someone else has entered the Vault.");
+       newsym(guard->mx,guard->my);
+       if (youmonst.m_ap_type == M_AP_OBJECT || u.uundetected) {
+           if (youmonst.m_ap_type == M_AP_OBJECT &&
+                       youmonst.mappearance != GOLD_PIECE)
+               verbalize("Hey! Who left that %s in here?", mimic_obj_name(&youmonst));
+           /* You're mimicking some object or you're hidden. */
+           pline("Puzzled, %s turns around and leaves.", mhe(guard));
+           mongone(guard);
+           return;
+       }
+       if (Strangled || is_silent(youmonst.data) || multi < 0) {
+           /* [we ought to record whether this this message has already
+              been given in order to vary it upon repeat visits, but
+              discarding the monster and its egd data renders that hard] */
+           verbalize("I'll be back when you're ready to speak to me!");
+           mongone(guard);
+           return;
+       }
+
+       stop_occupation();              /* if occupied, stop it *now* */
+       if (multi > 0) { nomul(0); unmul((char *)0); }
+       trycount = 5;
+       do {
+           getlin("\"Hello stranger, who are you?\" -", buf);
+           (void) mungspaces(buf);
+       } while (!letter(buf[0]) && --trycount > 0);
+
+       if (u.ualign.type == A_LAWFUL &&
+           /* ignore trailing text, in case player includes character's rank */
+           strncmpi(buf, plname, (int) strlen(plname)) != 0) {
+               adjalign(-1);           /* Liar! */
+       }
+
+       if (!strcmpi(buf, "Croesus") || !strcmpi(buf, "Kroisos")
+#ifdef TOURIST
+               || !strcmpi(buf, "Creosote")
+#endif
+           ) {
+           if (!mvitals[PM_CROESUS].died) {
+               verbalize("Oh, yes, of course.  Sorry to have disturbed you.");
+               mongone(guard);
+           } else {
+               setmangry(guard);
+               verbalize("Back from the dead, are you?  I'll remedy that!");
+               /* don't want guard to waste next turn wielding a weapon */
+               if (!MON_WEP(guard)) {
+                   guard->weapon_check = NEED_HTH_WEAPON;
+                   (void) mon_wield_item(guard);
+               }
+           }
+           return;
+       }
+       verbalize("I don't know you.");
+#ifndef GOLDOBJ
+       if (!u.ugold && !hidden_gold())
+           verbalize("Please follow me.");
+       else {
+           if (!u.ugold)
+               verbalize("You have hidden gold.");
+           verbalize("Most likely all your gold was stolen from this vault.");
+           verbalize("Please drop that gold and follow me.");
+       }
+#else
+        umoney = money_cnt(invent);
+       if (!umoney && !hidden_gold())
+           verbalize("Please follow me.");
+       else {
+           if (!umoney)
+               verbalize("You have hidden money.");
+           verbalize("Most likely all your money was stolen from this vault.");
+           verbalize("Please drop that money and follow me.");
+       }
+#endif
+       EGD(guard)->gdx = gx;
+       EGD(guard)->gdy = gy;
+       EGD(guard)->fcbeg = 0;
+       EGD(guard)->fakecorr[0].fx = x;
+       EGD(guard)->fakecorr[0].fy = y;
+       if(IS_WALL(levl[x][y].typ))
+           EGD(guard)->fakecorr[0].ftyp = levl[x][y].typ;
+       else { /* the initial guard location is a dug door */
+           int vlt = EGD(guard)->vroom;
+           xchar lowx = rooms[vlt].lx, hix = rooms[vlt].hx;
+           xchar lowy = rooms[vlt].ly, hiy = rooms[vlt].hy;
+
+           if(x == lowx-1 && y == lowy-1)
+               EGD(guard)->fakecorr[0].ftyp = TLCORNER;
+           else if(x == hix+1 && y == lowy-1)
+               EGD(guard)->fakecorr[0].ftyp = TRCORNER;
+           else if(x == lowx-1 && y == hiy+1)
+               EGD(guard)->fakecorr[0].ftyp = BLCORNER;
+           else if(x == hix+1 && y == hiy+1)
+               EGD(guard)->fakecorr[0].ftyp = BRCORNER;
+           else if(y == lowy-1 || y == hiy+1)
+               EGD(guard)->fakecorr[0].ftyp = HWALL;
+           else if(x == lowx-1 || x == hix+1)
+               EGD(guard)->fakecorr[0].ftyp = VWALL;
+       }
+       levl[x][y].typ = DOOR;
+       levl[x][y].doormask = D_NODOOR;
+       unblock_point(x, y);            /* doesn't block light */
+       EGD(guard)->fcend = 1;
+       EGD(guard)->warncnt = 1;
+    }
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+STATIC_OVL void
+move_gold(gold, vroom)
+struct obj *gold;
+int vroom;
+{
+       xchar nx, ny;
+
+       remove_object(gold);
+       newsym(gold->ox, gold->oy);
+       nx = rooms[vroom].lx + rn2(2);
+       ny = rooms[vroom].ly + rn2(2);
+       place_object(gold, nx, ny);
+       stackobj(gold);
+       newsym(nx,ny);
+}
+
+STATIC_OVL void
+wallify_vault(grd)
+struct monst *grd;
+{
+       int x, y, typ;
+       int vlt = EGD(grd)->vroom;
+       char tmp_viz;
+       xchar lox = rooms[vlt].lx - 1, hix = rooms[vlt].hx + 1,
+             loy = rooms[vlt].ly - 1, hiy = rooms[vlt].hy + 1;
+       struct monst *mon;
+       struct obj *gold;
+       struct trap *trap;
+       boolean fixed = FALSE;
+       boolean movedgold = FALSE;
+
+       for (x = lox; x <= hix; x++)
+           for (y = loy; y <= hiy; y++) {
+               /* if not on the room boundary, skip ahead */
+               if (x != lox && x != hix && y != loy && y != hiy) continue;
+
+               if (!IS_WALL(levl[x][y].typ) && !in_fcorridor(grd, x, y)) {
+                   if ((mon = m_at(x, y)) != 0 && mon != grd) {
+                       if (mon->mtame) yelp(mon);
+                       (void) rloc(mon, FALSE);
+                   }
+                   if ((gold = g_at(x, y)) != 0) {
+                       move_gold(gold, EGD(grd)->vroom);
+                       movedgold = TRUE;
+                   }
+                   if ((trap = t_at(x, y)) != 0)
+                       deltrap(trap);
+                   if (x == lox)
+                       typ = (y == loy) ? TLCORNER :
+                             (y == hiy) ? BLCORNER : VWALL;
+                   else if (x == hix)
+                       typ = (y == loy) ? TRCORNER :
+                             (y == hiy) ? BRCORNER : VWALL;
+                   else  /* not left or right side, must be top or bottom */
+                       typ = HWALL;
+                   levl[x][y].typ = typ;
+                   levl[x][y].doormask = 0;
+                   /*
+                    * hack: player knows walls are restored because of the
+                    * message, below, so show this on the screen.
+                    */
+                   tmp_viz = viz_array[y][x];
+                   viz_array[y][x] = IN_SIGHT|COULD_SEE;
+                   newsym(x,y);
+                   viz_array[y][x] = tmp_viz;
+                   block_point(x,y);
+                   fixed = TRUE;
+               }
+           }
+
+       if(movedgold || fixed) {
+           if(in_fcorridor(grd, grd->mx, grd->my) || cansee(grd->mx, grd->my))
+               pline_The("%s whispers an incantation.", g_monnam(grd));
+           else You_hear("a distant chant.");
+           if(movedgold)
+               pline("A mysterious force moves the gold into the vault.");
+           if(fixed)
+               pline_The("damaged vault's walls are magically restored!");
+       }
+}
+
+/*
+ * return  1: guard moved,  0: guard didn't,  -1: let m_move do it,  -2: died
+ */
+int
+gd_move(grd)
+register struct monst *grd;
+{
+       int x, y, nx, ny, m, n;
+       int dx, dy, gx, gy, fci;
+       uchar typ;
+       struct fakecorridor *fcp;
+       register struct egd *egrd = EGD(grd);
+       register struct rm *crm;
+       register boolean goldincorridor = FALSE,
+                        u_in_vault = vault_occupied(u.urooms)? TRUE : FALSE,
+                        grd_in_vault = *in_rooms(grd->mx, grd->my, VAULT)?
+                                       TRUE : FALSE;
+       boolean disappear_msg_seen = FALSE, semi_dead = (grd->mhp <= 0);
+#ifndef GOLDOBJ
+       register boolean u_carry_gold = ((u.ugold + hidden_gold()) > 0L);
+#else
+        long umoney = money_cnt(invent);
+       register boolean u_carry_gold = ((umoney + hidden_gold()) > 0L);
+#endif
+       boolean see_guard;
+
+       if(!on_level(&(egrd->gdlevel), &u.uz)) return(-1);
+       nx = ny = m = n = 0;
+       if(!u_in_vault && !grd_in_vault)
+           wallify_vault(grd);
+       if(!grd->mpeaceful) {
+           if(semi_dead) {
+               egrd->gddone =1;
+               goto newpos;
+           }
+           if(!u_in_vault &&
+              (grd_in_vault ||
+               (in_fcorridor(grd, grd->mx, grd->my) &&
+                !in_fcorridor(grd, u.ux, u.uy)))) {
+               (void) rloc(grd, FALSE);
+               wallify_vault(grd);
+               (void) clear_fcorr(grd, TRUE);
+               goto letknow;
+           }
+           if(!in_fcorridor(grd, grd->mx, grd->my))
+               (void) clear_fcorr(grd, TRUE);
+           return(-1);
+       }
+       if(abs(egrd->ogx - grd->mx) > 1 ||
+                       abs(egrd->ogy - grd->my) > 1)
+               return(-1);     /* teleported guard - treat as monster */
+       if(egrd->fcend == 1) {
+           if(u_in_vault &&
+                       (u_carry_gold || um_dist(grd->mx, grd->my, 1))) {
+               if(egrd->warncnt == 3)
+                       verbalize("I repeat, %sfollow me!",
+                               u_carry_gold ? (
+#ifndef GOLDOBJ
+                                         !u.ugold ?
+                                         "drop that hidden gold and " :
+                                         "drop that gold and ") : "");
+#else
+                                         !umoney ?
+                                         "drop that hidden money and " :
+                                         "drop that money and ") : "");
+#endif
+               if(egrd->warncnt == 7) {
+                       m = grd->mx;
+                       n = grd->my;
+                       verbalize("You've been warned, knave!");
+                       mnexto(grd);
+                       levl[m][n].typ = egrd->fakecorr[0].ftyp;
+                       newsym(m,n);
+                       grd->mpeaceful = 0;
+                       return(-1);
+               }
+               /* not fair to get mad when (s)he's fainted or paralyzed */
+               if(!is_fainted() && multi >= 0) egrd->warncnt++;
+               return(0);
+           }
+
+           if (!u_in_vault) {
+               if (u_carry_gold) {     /* player teleported */
+                   m = grd->mx;
+                   n = grd->my;
+                   (void) rloc(grd, FALSE);
+                   levl[m][n].typ = egrd->fakecorr[0].ftyp;
+                   newsym(m,n);
+                   grd->mpeaceful = 0;
+letknow:
+                   if (!cansee(grd->mx, grd->my) || !mon_visible(grd))
+                       You_hear("the shrill sound of a guard's whistle.");
+                   else
+                       You(um_dist(grd->mx, grd->my, 2) ?
+                           "see an angry %s approaching." :
+                           "are confronted by an angry %s.",
+                           g_monnam(grd));
+                   return(-1);
+               } else {
+                   verbalize("Well, begone.");
+                   wallify_vault(grd);
+                   egrd->gddone = 1;
+                   goto cleanup;
+               }
+           }
+       }
+
+       if(egrd->fcend > 1) {
+           if(egrd->fcend > 2 && in_fcorridor(grd, grd->mx, grd->my) &&
+                 !egrd->gddone && !in_fcorridor(grd, u.ux, u.uy) &&
+                 levl[egrd->fakecorr[0].fx][egrd->fakecorr[0].fy].typ
+                                == egrd->fakecorr[0].ftyp) {
+               pline_The("%s, confused, disappears.", g_monnam(grd));
+               disappear_msg_seen = TRUE;
+               goto cleanup;
+           }
+           if(u_carry_gold &&
+                   (in_fcorridor(grd, u.ux, u.uy) ||
+                   /* cover a 'blind' spot */
+                   (egrd->fcend > 1 && u_in_vault))) {
+               if(!grd->mx) {
+                       restfakecorr(grd);
+                       return(-2);
+               }
+               if(egrd->warncnt < 6) {
+                       egrd->warncnt = 6;
+                       verbalize("Drop all your gold, scoundrel!");
+                       return(0);
+               } else {
+                       verbalize("So be it, rogue!");
+                       grd->mpeaceful = 0;
+                       return(-1);
+               }
+           }
+       }
+       for(fci = egrd->fcbeg; fci < egrd->fcend; fci++)
+           if(g_at(egrd->fakecorr[fci].fx, egrd->fakecorr[fci].fy)){
+               m = egrd->fakecorr[fci].fx;
+               n = egrd->fakecorr[fci].fy;
+               goldincorridor = TRUE;
+           }
+       if(goldincorridor && !egrd->gddone) {
+               x = grd->mx;
+               y = grd->my;
+               if (m == u.ux && n == u.uy) {
+                   struct obj *gold = g_at(m,n);
+                   /* Grab the gold from between the hero's feet.  */
+#ifndef GOLDOBJ
+                   grd->mgold += gold->quan;
+                   delobj(gold);
+#else
+                   obj_extract_self(gold);
+                   add_to_minv(grd, gold);
+#endif
+                   newsym(m,n);
+               } else if (m == x && n == y) {
+                   mpickgold(grd);     /* does a newsym */
+               } else {
+                   /* just for insurance... */
+                   if (MON_AT(m, n) && m != grd->mx && n != grd->my) {
+                       verbalize("Out of my way, scum!");
+                       (void) rloc(m_at(m, n), FALSE);
+                   }
+                   remove_monster(grd->mx, grd->my);
+                   newsym(grd->mx, grd->my);
+                   place_monster(grd, m, n);
+                   mpickgold(grd);     /* does a newsym */
+               }
+               if(cansee(m,n))
+                   pline("%s%s picks up the gold.", Monnam(grd),
+                               grd->mpeaceful ? " calms down and" : "");
+               if(x != grd->mx || y != grd->my) {
+                   remove_monster(grd->mx, grd->my);
+                   newsym(grd->mx, grd->my);
+                   place_monster(grd, x, y);
+                   newsym(x, y);
+               }
+               if(!grd->mpeaceful) return(-1);
+               else {
+                   egrd->warncnt = 5;
+                   return(0);
+               }
+       }
+       if(um_dist(grd->mx, grd->my, 1) || egrd->gddone) {
+               if(!egrd->gddone && !rn2(10)) verbalize("Move along!");
+               restfakecorr(grd);
+               return(0);      /* didn't move */
+       }
+       x = grd->mx;
+       y = grd->my;
+
+       if(u_in_vault) goto nextpos;
+
+       /* look around (hor & vert only) for accessible places */
+       for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++) {
+         if((nx == x || ny == y) && (nx != x || ny != y) && isok(nx, ny)) {
+
+           typ = (crm = &levl[nx][ny])->typ;
+           if(!IS_STWALL(typ) && !IS_POOL(typ)) {
+
+               if(in_fcorridor(grd, nx, ny))
+                       goto nextnxy;
+
+               if(*in_rooms(nx,ny,VAULT))
+                       continue;
+
+               /* seems we found a good place to leave him alone */
+               egrd->gddone = 1;
+               if(ACCESSIBLE(typ)) goto newpos;
+#ifdef STUPID
+               if (typ == SCORR)
+                   crm->typ = CORR;
+               else
+                   crm->typ = DOOR;
+#else
+               crm->typ = (typ == SCORR) ? CORR : DOOR;
+#endif
+               if(crm->typ == DOOR) crm->doormask = D_NODOOR;
+               goto proceed;
+           }
+         }
+nextnxy:       ;
+       }
+nextpos:
+       nx = x;
+       ny = y;
+       gx = egrd->gdx;
+       gy = egrd->gdy;
+       dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
+       dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
+       if(abs(gx-x) >= abs(gy-y)) nx += dx; else ny += dy;
+
+       while((typ = (crm = &levl[nx][ny])->typ) != 0) {
+       /* in view of the above we must have IS_WALL(typ) or typ == POOL */
+       /* must be a wall here */
+               if(isok(nx+nx-x,ny+ny-y) && !IS_POOL(typ) &&
+                   IS_ROOM(levl[nx+nx-x][ny+ny-y].typ)){
+                       crm->typ = DOOR;
+                       crm->doormask = D_NODOOR;
+                       goto proceed;
+               }
+               if(dy && nx != x) {
+                       nx = x; ny = y+dy;
+                       continue;
+               }
+               if(dx && ny != y) {
+                       ny = y; nx = x+dx; dy = 0;
+                       continue;
+               }
+               /* I don't like this, but ... */
+               if(IS_ROOM(typ)) {
+                       crm->typ = DOOR;
+                       crm->doormask = D_NODOOR;
+                       goto proceed;
+               }
+               break;
+       }
+       crm->typ = CORR;
+proceed:
+       unblock_point(nx, ny);  /* doesn't block light */
+       if (cansee(nx,ny))
+           newsym(nx,ny);
+
+       fcp = &(egrd->fakecorr[egrd->fcend]);
+       if(egrd->fcend++ == FCSIZ) panic("fakecorr overflow");
+       fcp->fx = nx;
+       fcp->fy = ny;
+       fcp->ftyp = typ;
+newpos:
+       if(egrd->gddone) {
+               /* The following is a kludge.  We need to keep    */
+               /* the guard around in order to be able to make   */
+               /* the fake corridor disappear as the player      */
+               /* moves out of it, but we also need the guard    */
+               /* out of the way.  We send the guard to never-   */
+               /* never land.  We set ogx ogy to mx my in order  */
+               /* to avoid a check at the top of this function.  */
+               /* At the end of the process, the guard is killed */
+               /* in restfakecorr().                             */
+cleanup:
+               x = grd->mx; y = grd->my;
+
+               see_guard = canspotmon(grd);
+               wallify_vault(grd);
+               remove_monster(grd->mx, grd->my);
+               newsym(grd->mx,grd->my);
+               place_monster(grd, 0, 0);
+               egrd->ogx = grd->mx;
+               egrd->ogy = grd->my;
+               restfakecorr(grd);
+               if(!semi_dead && (in_fcorridor(grd, u.ux, u.uy) ||
+                                    cansee(x, y))) {
+                   if (!disappear_msg_seen && see_guard)
+                       pline("Suddenly, the %s disappears.", g_monnam(grd));
+                   return(1);
+               }
+               return(-2);
+       }
+       egrd->ogx = grd->mx;    /* update old positions */
+       egrd->ogy = grd->my;
+       remove_monster(grd->mx, grd->my);
+       place_monster(grd, nx, ny);
+       newsym(grd->mx,grd->my);
+       restfakecorr(grd);
+       return(1);
+}
+
+/* Routine when dying or quitting with a vault guard around */
+void
+paygd()
+{
+       register struct monst *grd = findgd();
+#ifndef GOLDOBJ
+       struct obj *gold;
+#else
+        long umoney = money_cnt(invent);
+       struct obj *coins, *nextcoins;
+#endif
+       int gx,gy;
+       char buf[BUFSZ];
+
+#ifndef GOLDOBJ
+       if (!u.ugold || !grd) return;
+#else
+       if (!umoney || !grd) return;
+#endif
+
+       if (u.uinvault) {
+           Your("%ld %s goes into the Magic Memory Vault.",
+#ifndef GOLDOBJ
+               u.ugold,
+               currency(u.ugold));
+#else
+               umoney,
+               currency(umoney));
+#endif
+           gx = u.ux;
+           gy = u.uy;
+       } else {
+           if(grd->mpeaceful) { /* guard has no "right" to your gold */
+               mongone(grd);
+               return;
+           }
+           mnexto(grd);
+           pline("%s remits your gold to the vault.", Monnam(grd));
+           gx = rooms[EGD(grd)->vroom].lx + rn2(2);
+           gy = rooms[EGD(grd)->vroom].ly + rn2(2);
+           Sprintf(buf,
+               "To Croesus: here's the gold recovered from %s the %s.",
+               plname, mons[u.umonster].mname);
+           make_grave(gx, gy, buf);
+       }
+#ifndef GOLDOBJ
+       place_object(gold = mkgoldobj(u.ugold), gx, gy);
+       stackobj(gold);
+#else
+        for (coins = invent; coins; coins = nextcoins) {
+            nextcoins = coins->nobj;
+           if (objects[coins->otyp].oc_class == COIN_CLASS) {
+               freeinv(coins);
+                place_object(coins, gx, gy);
+               stackobj(coins);
+           }
+        }
+#endif
+       mongone(grd);
+}
+
+long
+hidden_gold()
+{
+       register long value = 0L;
+       register struct obj *obj;
+
+       for (obj = invent; obj; obj = obj->nobj)
+           if (Has_contents(obj))
+               value += contained_gold(obj);
+       /* unknown gold stuck inside statues may cause some consternation... */
+
+       return(value);
+}
+
+boolean
+gd_sound()  /* prevent "You hear footsteps.." when inappropriate */
+{
+       register struct monst *grd = findgd();
+
+       if (vault_occupied(u.urooms)) return(FALSE);
+       else return((boolean)(grd == (struct monst *)0));
+}
+
+#endif /* OVLB */
+
+/*vault.c*/
diff --git a/src/version.c b/src/version.c
new file mode 100644 (file)
index 0000000..b35475c
--- /dev/null
@@ -0,0 +1,185 @@
+/*     SCCS Id: @(#)version.c  3.4     2003/12/06      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "date.h"
+/*
+ * All the references to the contents of patchlevel.h have been moved
+ * into makedefs....
+ */
+#ifdef SHORT_FILENAMES
+#include "patchlev.h"
+#else
+#include "patchlevel.h"
+#endif
+
+/* #define BETA_INFO "" */     /* "[ beta n]" */
+
+/* fill buffer with short version (so caller can avoid including date.h) */
+char *
+version_string(buf)
+char *buf;
+{
+       return strcpy(buf, VERSION_STRING);
+}
+
+/* fill and return the given buffer with the long nethack version string */
+char *
+getversionstring(buf)
+char *buf;
+{
+       Strcpy(buf, VERSION_ID);
+#if defined(BETA) && defined(BETA_INFO)
+       Sprintf(eos(buf), " %s", BETA_INFO);
+#endif
+#if defined(RUNTIME_PORT_ID)
+       append_port_id(buf);
+#endif
+       return buf;
+}
+
+int
+doversion()
+{
+       char buf[BUFSZ];
+
+       pline("%s", getversionstring(buf));
+       return 0;
+}
+
+int
+doextversion()
+{
+       display_file(OPTIONS_USED, TRUE);
+       return 0;
+}
+
+#ifdef MICRO
+boolean
+comp_times(filetime)
+long filetime;
+{
+       return((boolean)(filetime < BUILD_TIME));
+}
+#endif
+
+boolean
+check_version(version_data, filename, complain)
+struct version_info *version_data;
+const char *filename;
+boolean complain;
+{
+       if (
+#ifdef VERSION_COMPATIBILITY
+           version_data->incarnation < VERSION_COMPATIBILITY ||
+           version_data->incarnation > VERSION_NUMBER
+#else
+           version_data->incarnation != VERSION_NUMBER
+#endif
+         ) {
+           if (complain)
+               pline("Version mismatch for file \"%s\".", filename);
+           return FALSE;
+       } else if (
+#ifndef IGNORED_FEATURES
+                  version_data->feature_set != VERSION_FEATURES ||
+#else
+                  (version_data->feature_set & ~IGNORED_FEATURES) !=
+                         (VERSION_FEATURES & ~IGNORED_FEATURES) ||
+#endif
+                  version_data->entity_count != VERSION_SANITY1 ||
+                  version_data->struct_sizes != VERSION_SANITY2) {
+           if (complain)
+               pline("Configuration incompatibility for file \"%s\".",
+                     filename);
+           return FALSE;
+       }
+       return TRUE;
+}
+
+/* this used to be based on file date and somewhat OS-dependant,
+   but now examines the initial part of the file's contents */
+boolean
+uptodate(fd, name)
+int fd;
+const char *name;
+{
+    int rlen;
+    struct version_info vers_info;
+    boolean verbose = name ? TRUE : FALSE;
+
+    rlen = read(fd, (genericptr_t) &vers_info, sizeof vers_info);
+    minit();           /* ZEROCOMP */
+    if (rlen == 0) {
+       if (verbose) {
+           pline("File \"%s\" is empty?", name);
+           wait_synch();
+       }
+       return FALSE;
+    }
+    if (!check_version(&vers_info, name, verbose)) {
+       if (verbose) wait_synch();
+       return FALSE;
+    }
+    return TRUE;
+}
+
+void
+store_version(fd)
+int fd;
+{
+       const static struct version_info version_data = {
+                       VERSION_NUMBER, VERSION_FEATURES,
+                       VERSION_SANITY1, VERSION_SANITY2
+       };
+
+       bufoff(fd);
+       /* bwrite() before bufon() uses plain write() */
+       bwrite(fd,(genericptr_t)&version_data,(unsigned)(sizeof version_data));
+       bufon(fd);
+       return;
+}
+
+#ifdef AMIGA
+const char amiga_version_string[] = AMIGA_VERSION_STRING;
+#endif
+
+unsigned long
+get_feature_notice_ver(str)
+char *str;
+{
+       char buf[BUFSZ];
+       int ver_maj, ver_min, patch;
+       char *istr[3];
+       int j = 0;
+
+       if (!str) return 0L;
+       str = strcpy(buf, str);
+       istr[j] = str;
+       while (*str) {
+               if (*str == '.') {
+                       *str++ = '\0';
+                       j++;
+                       istr[j] = str;
+                       if (j == 2) break;
+               } else if (index("0123456789", *str) != 0) {
+                       str++;
+               } else 
+                       return 0L;
+       }
+       if (j != 2) return 0L;
+       ver_maj = atoi(istr[0]);
+       ver_min = atoi(istr[1]);
+       patch = atoi(istr[2]);
+       return FEATURE_NOTICE_VER(ver_maj,ver_min,patch);
+       /* macro from hack.h */
+}
+
+unsigned long
+get_current_feature_ver()
+{
+       return FEATURE_NOTICE_VER(VERSION_MAJOR,VERSION_MINOR,PATCHLEVEL);
+}
+
+/*version.c*/
diff --git a/src/vision.c b/src/vision.c
new file mode 100644 (file)
index 0000000..e614bdd
--- /dev/null
@@ -0,0 +1,2622 @@
+/*     SCCS Id: @(#)vision.c   3.4     1999/02/18      */
+/* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990.        */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+#include "hack.h"
+
+/* Circles ==================================================================*/
+
+/*
+ * These numbers are limit offsets for one quadrant of a circle of a given
+ * radius (the first number of each line) from the source.  The number in
+ * the comment is the element number (so pointers can be set up).  Each
+ * "circle" has as many elements as its radius+1.  The radius is the number
+ * of points away from the source that the limit exists.  The radius of the
+ * offset on the same row as the source *is* included so we don't have to
+ * make an extra check.  For example, a circle of radius 4 has offsets:
+ *
+ *                             XXX     +2
+ *                             ...X    +3
+ *                             ....X   +4
+ *                             ....X   +4
+ *                             @...X   +4
+ *
+ */
+char circle_data[] = {
+/*  0*/         1, 1,
+/*  2*/         2, 2, 1,
+/*  5*/         3, 3, 2, 1,
+/*  9*/         4, 4, 4, 3, 2,
+/* 14*/         5, 5, 5, 4, 3, 2,
+/* 20*/         6, 6, 6, 5, 5, 4, 2,
+/* 27*/         7, 7, 7, 6, 6, 5, 4, 2,
+/* 35*/         8, 8, 8, 7, 7, 6, 6, 4, 2,
+/* 44*/         9, 9, 9, 9, 8, 8, 7, 6, 5, 3,
+/* 54*/        10,10,10,10, 9, 9, 8, 7, 6, 5, 3,
+/* 65*/        11,11,11,11,10,10, 9, 9, 8, 7, 5, 3,
+/* 77*/        12,12,12,12,11,11,10,10, 9, 8, 7, 5, 3,
+/* 90*/        13,13,13,13,12,12,12,11,10,10, 9, 7, 6, 3,
+/*104*/        14,14,14,14,13,13,13,12,12,11,10, 9, 8, 6, 3,
+/*119*/        15,15,15,15,14,14,14,13,13,12,11,10, 9, 8, 6, 3,
+/*135*/ 16 /* should be MAX_RADIUS+1; used to terminate range loops -dlc */
+};
+
+/*
+ * These are the starting indexes into the circle_data[] array for a
+ * circle of a given radius.
+ */
+char circle_start[] = {
+/*  */   0,    /* circles of radius zero are not used */
+/* 1*/    0,
+/* 2*/   2,
+/* 3*/   5,
+/* 4*/   9,
+/* 5*/  14,
+/* 6*/  20,
+/* 7*/  27,
+/* 8*/  35,
+/* 9*/  44,
+/*10*/  54,
+/*11*/  65,
+/*12*/  77,
+/*13*/  90,
+/*14*/ 104,
+/*15*/ 119,
+};
+
+
+/*===========================================================================*/
+/* Vision (arbitrary line of sight) =========================================*/
+
+/*------ global variables ------*/
+
+#if 0  /* (moved to decl.c) */
+/* True if we need to run a full vision recalculation. */
+boolean        vision_full_recalc = 0;
+
+/* Pointers to the current vision array. */
+char   **viz_array;
+#endif
+char   *viz_rmin, *viz_rmax;           /* current vision cs bounds */
+
+
+/*------ local variables ------*/
+
+
+static char could_see[2][ROWNO][COLNO];                /* vision work space */
+static char *cs_rows0[ROWNO], *cs_rows1[ROWNO];
+static char  cs_rmin0[ROWNO],  cs_rmax0[ROWNO];
+static char  cs_rmin1[ROWNO],  cs_rmax1[ROWNO];
+
+static char  viz_clear[ROWNO][COLNO];          /* vision clear/blocked map */
+static char *viz_clear_rows[ROWNO];
+
+static char  left_ptrs[ROWNO][COLNO];          /* LOS algorithm helpers */
+static char right_ptrs[ROWNO][COLNO];
+
+/* Forward declarations. */
+STATIC_DCL void FDECL(fill_point, (int,int));
+STATIC_DCL void FDECL(dig_point, (int,int));
+STATIC_DCL void NDECL(view_init);
+STATIC_DCL void FDECL(view_from,(int,int,char **,char *,char *,int,
+                            void (*)(int,int,genericptr_t),genericptr_t));
+STATIC_DCL void FDECL(get_unused_cs, (char ***,char **,char **));
+#ifdef REINCARNATION
+STATIC_DCL void FDECL(rogue_vision, (char **,char *,char *));
+#endif
+
+/* Macro definitions that I can't find anywhere. */
+#define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0 ))
+#define v_abs(z)  ((z) < 0 ? -(z) : (z))       /* don't use abs -- it may exist */
+
+/*
+ * vision_init()
+ *
+ * The one-time vision initialization routine.
+ *
+ * This must be called before mklev() is called in newgame() [allmain.c],
+ * or before a game restore.   Else we die a horrible death.
+ */
+void
+vision_init()
+{
+    int i;
+
+    /* Set up the pointers. */
+    for (i = 0; i < ROWNO; i++) {
+       cs_rows0[i] = could_see[0][i];
+       cs_rows1[i] = could_see[1][i];
+       viz_clear_rows[i] = viz_clear[i];
+    }
+
+    /* Start out with cs0 as our current array */
+    viz_array = cs_rows0;
+    viz_rmin  = cs_rmin0;
+    viz_rmax  = cs_rmax0;
+
+    vision_full_recalc = 0;
+    (void) memset((genericptr_t) could_see, 0, sizeof(could_see));
+
+    /* Initialize the vision algorithm (currently C or D). */
+    view_init();
+
+#ifdef VISION_TABLES
+    /* Note:  this initializer doesn't do anything except guarantee that
+             we're linked properly.
+    */
+    vis_tab_init();
+#endif
+}
+
+/*
+ * does_block()
+ *
+ * Returns true if the level feature, object, or monster at (x,y) blocks
+ * sight.
+ */
+int
+does_block(x,y,lev)
+    int x, y;
+    register struct rm    *lev;
+{
+    struct obj   *obj;
+    struct monst *mon;
+
+    /* Features that block . . */
+    if (IS_ROCK(lev->typ) || lev->typ == TREE || (IS_DOOR(lev->typ) &&
+                           (lev->doormask & (D_CLOSED|D_LOCKED|D_TRAPPED) )))
+       return 1;
+
+    if (lev->typ == CLOUD || lev->typ == WATER ||
+                       (lev->typ == MOAT && Underwater))
+       return 1;
+
+    /* Boulders block light. */
+    for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
+       if (obj->otyp == BOULDER) return 1;
+
+    /* Mimics mimicing a door or boulder block light. */
+    if ((mon = m_at(x,y)) && (!mon->minvis || See_invisible) &&
+         ((mon->m_ap_type == M_AP_FURNITURE &&
+         (mon->mappearance == S_hcdoor || mon->mappearance == S_vcdoor)) ||
+         (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER)))
+       return 1;
+
+    return 0;
+}
+
+/*
+ * vision_reset()
+ *
+ * This must be called *after* the levl[][] structure is set with the new
+ * level and the level monsters and objects are in place.
+ */
+void
+vision_reset()
+{
+    int y;
+    register int x, i, dig_left, block;
+    register struct rm    *lev;
+
+    /* Start out with cs0 as our current array */
+    viz_array = cs_rows0;
+    viz_rmin  = cs_rmin0;
+    viz_rmax  = cs_rmax0;
+
+    (void) memset((genericptr_t) could_see, 0, sizeof(could_see));
+
+    /* Reset the pointers and clear so that we have a "full" dungeon. */
+    (void) memset((genericptr_t) viz_clear,        0, sizeof(viz_clear));
+
+    /* Dig the level */
+    for (y = 0; y < ROWNO; y++) {
+       dig_left = 0;
+       block = TRUE;   /* location (0,y) is always stone; it's !isok() */
+       lev = &levl[1][y];
+       for (x = 1; x < COLNO; x++, lev += ROWNO)
+           if (block != (IS_ROCK(lev->typ) || does_block(x,y,lev))) {
+               if(block) {
+                   for(i=dig_left; i<x; i++) {
+                       left_ptrs [y][i] = dig_left;
+                       right_ptrs[y][i] = x-1;
+                   }
+               } else {
+                   i = dig_left;
+                   if(dig_left) dig_left--; /* point at first blocked point */
+                   for(; i<x; i++) {
+                       left_ptrs [y][i] = dig_left;
+                       right_ptrs[y][i] = x;
+                       viz_clear[y][i] = 1;
+                   }
+               }
+               dig_left = x;
+               block = !block;
+           }
+       /* handle right boundary; almost identical for blocked/unblocked */
+       i = dig_left;
+       if(!block && dig_left) dig_left--; /* point at first blocked point */
+       for(; i<COLNO; i++) {
+           left_ptrs [y][i] = dig_left;
+           right_ptrs[y][i] = (COLNO-1);
+           viz_clear[y][i] = !block;
+       }
+    }
+
+    iflags.vision_inited = 1;  /* vision is ready */
+    vision_full_recalc = 1;    /* we want to run vision_recalc() */
+}
+
+
+/*
+ * get_unused_cs()
+ *
+ * Called from vision_recalc() and at least one light routine.  Get pointers
+ * to the unused vision work area.
+ */
+STATIC_OVL void
+get_unused_cs(rows, rmin, rmax)
+    char ***rows;
+    char **rmin, **rmax;
+{
+    register int  row;
+    register char *nrmin, *nrmax;
+
+    if (viz_array == cs_rows0) {
+       *rows = cs_rows1;
+       *rmin = cs_rmin1;
+       *rmax = cs_rmax1;
+    } else {
+       *rows = cs_rows0;
+       *rmin = cs_rmin0;
+       *rmax = cs_rmax0;
+    }
+
+    /* return an initialized, unused work area */
+    nrmin = *rmin;
+    nrmax = *rmax;
+
+    (void) memset((genericptr_t)**rows, 0, ROWNO*COLNO);  /* we see nothing */
+    for (row = 0; row < ROWNO; row++) {                /* set row min & max */
+       *nrmin++ = COLNO-1;
+       *nrmax++ = 0;
+    }
+}
+
+
+#ifdef REINCARNATION
+/*
+ * rogue_vision()
+ *
+ * Set the "could see" and in sight bits so vision acts just like the old
+ * rogue game:
+ *
+ *     + If in a room, the hero can see to the room boundaries.
+ *     + The hero can always see adjacent squares.
+ *
+ * We set the in_sight bit here as well to escape a bug that shows up
+ * due to the one-sided lit wall hack.
+ */
+STATIC_OVL void
+rogue_vision(next, rmin, rmax)
+    char **next;       /* could_see array pointers */
+    char *rmin, *rmax;
+{
+    int rnum = levl[u.ux][u.uy].roomno - ROOMOFFSET; /* no SHARED... */
+    int start, stop, in_door, xhi, xlo, yhi, ylo;
+    register int zx, zy;
+
+    /* If in a lit room, we are able to see to its boundaries. */
+    /* If dark, set COULD_SEE so various spells work -dlc */
+    if (rnum >= 0) {
+       for (zy = rooms[rnum].ly-1; zy <= rooms[rnum].hy+1; zy++) {
+           rmin[zy] = start = rooms[rnum].lx-1;
+           rmax[zy] = stop  = rooms[rnum].hx+1;
+
+           for (zx = start; zx <= stop; zx++) {
+               if (rooms[rnum].rlit) {
+                   next[zy][zx] = COULD_SEE | IN_SIGHT;
+                   levl[zx][zy].seenv = SVALL; /* see the walls */
+               } else
+                   next[zy][zx] = COULD_SEE;
+           }
+       }
+    }
+
+    in_door = levl[u.ux][u.uy].typ == DOOR;
+
+    /* Can always see adjacent. */
+    ylo = max(u.uy - 1, 0);
+    yhi = min(u.uy + 1, ROWNO - 1);
+    xlo = max(u.ux - 1, 1);
+    xhi = min(u.ux + 1, COLNO - 1);
+    for (zy = ylo; zy <= yhi; zy++) {
+       if (xlo < rmin[zy]) rmin[zy] = xlo;
+       if (xhi > rmax[zy]) rmax[zy] = xhi;
+
+       for (zx = xlo; zx <= xhi; zx++) {
+           next[zy][zx] = COULD_SEE | IN_SIGHT;
+           /*
+            * Yuck, update adjacent non-diagonal positions when in a doorway.
+            * We need to do this to catch the case when we first step into
+            * a room.  The room's walls were not seen from the outside, but
+            * now are seen (the seen bits are set just above).  However, the
+            * positions are not updated because they were already in sight.
+            * So, we have to do it here.
+            */
+           if (in_door && (zx == u.ux || zy == u.uy)) newsym(zx,zy);
+       }
+    }
+}
+#endif /* REINCARNATION */
+
+/*#define EXTEND_SPINE*/       /* possibly better looking wall-angle */
+
+#ifdef EXTEND_SPINE
+
+STATIC_DCL int FDECL(new_angle, (struct rm *, unsigned char *, int, int));
+/*
+ * new_angle()
+ *
+ * Return the new angle seen by the hero for this location.  The angle
+ * bit is given in the value pointed at by sv.
+ *
+ * For T walls and crosswall, just setting the angle bit, even though
+ * it is technically correct, doesn't look good.  If we can see the
+ * next position beyond the current one and it is a wall that we can
+ * see, then we want to extend a spine of the T to connect with the wall
+ * that is beyond.  Example:
+ *
+ *      Correct, but ugly                         Extend T spine
+ *
+ *             | ...                                   | ...
+ *             | ...   <-- wall beyond & floor -->     | ...
+ *             | ...                                   | ...
+ * Unseen   -->   ...                                  | ...
+ * spine       +-...   <-- trwall & doorway    -->     +-...
+ *             | ...                                   | ...
+ *
+ *
+ *                @    <-- hero                -->        @
+ *
+ *
+ * We fake the above check by only checking if the horizontal &
+ * vertical positions adjacent to the crosswall and T wall are
+ * unblocked.  Then, _in general_ we can see beyond.  Generally,
+ * this is good enough.
+ *
+ *     + When this function is called we don't have all of the seen
+ *       information (we're doing a top down scan in vision_recalc).
+ *       We would need to scan once to set all IN_SIGHT and COULD_SEE
+ *       bits, then again to correctly set the seenv bits.
+ *     + I'm trying to make this as cheap as possible.  The display &
+ *       vision eat up too much CPU time.
+ *     
+ *
+ * Note:  Even as I write this, I'm still not convinced.  There are too
+ *       many exceptions.  I may have to bite the bullet and do more
+ *       checks.       - Dean 2/11/93
+ */
+STATIC_OVL int
+new_angle(lev, sv, row, col)
+    struct rm *lev;
+    unsigned char *sv;
+    int row, col;
+{
+    register int res = *sv;
+
+    /*
+     * Do extra checks for crosswalls and T walls if we see them from
+     * an angle.
+     */
+    if (lev->typ >= CROSSWALL && lev->typ <= TRWALL) {
+       switch (res) {
+           case SV0:
+               if (col > 0       && viz_clear[row][col-1]) res |= SV7;
+               if (row > 0       && viz_clear[row-1][col]) res |= SV1;
+               break;
+           case SV2:
+               if (row > 0       && viz_clear[row-1][col]) res |= SV1;
+               if (col < COLNO-1 && viz_clear[row][col+1]) res |= SV3;
+               break;
+           case SV4:
+               if (col < COLNO-1 && viz_clear[row][col+1]) res |= SV3;
+               if (row < ROWNO-1 && viz_clear[row+1][col]) res |= SV5;
+               break;
+           case SV6:
+               if (row < ROWNO-1 && viz_clear[row+1][col]) res |= SV5;
+               if (col > 0       && viz_clear[row][col-1]) res |= SV7;
+               break;
+       }
+    }
+    return res;
+}
+#else
+/*
+ * new_angle()
+ *
+ * Return the new angle seen by the hero for this location.  The angle
+ * bit is given in the value pointed at by sv.
+ *
+ * The other parameters are not used.
+ */
+#define new_angle(lev, sv, row, col) (*sv)
+
+#endif
+
+
+/*
+ * vision_recalc()
+ *
+ * Do all of the heavy vision work.  Recalculate all locations that could
+ * possibly be seen by the hero --- if the location were lit, etc.  Note
+ * which locations are actually seen because of lighting.  Then add to
+ * this all locations that be seen by hero due to night vision and x-ray
+ * vision.  Finally, compare with what the hero was able to see previously.
+ * Update the difference.
+ *
+ * This function is usually called only when the variable 'vision_full_recalc'
+ * is set.  The following is a list of places where this function is called,
+ * with three valid values for the control flag parameter:
+ *
+ * Control flag = 0.  A complete vision recalculation.  Generate the vision
+ * tables from scratch.  This is necessary to correctly set what the hero
+ * can see.  (1) and (2) call this routine for synchronization purposes, (3)
+ * calls this routine so it can operate correctly.
+ *
+ *     + After the monster move, before input from the player. [moveloop()]
+ *     + At end of moveloop. [moveloop() ??? not sure why this is here]
+ *     + Right before something is printed. [pline()]
+ *     + Right before we do a vision based operation. [do_clear_area()]
+ *     + screen redraw, so we can renew all positions in sight. [docrt()]
+ *
+ * Control flag = 1.  An adjacent vision recalculation.  The hero has moved
+ * one square.  Knowing this, it might be possible to optimize the vision
+ * recalculation using the current knowledge.  This is presently unimplemented
+ * and is treated as a control = 0 call.
+ *
+ *     + Right after the hero moves. [domove()]
+ *
+ * Control flag = 2.  Turn off the vision system.  Nothing new will be
+ * displayed, since nothing is seen.  This is usually done when you need
+ * a newsym() run on all locations in sight, or on some locations but you
+ * don't know which ones.
+ *
+ *     + Before a screen redraw, so all positions are renewed. [docrt()]
+ *     + Right before the hero arrives on a new level. [goto_level()]
+ *     + Right after a scroll of light is read. [litroom()]
+ *     + After an option has changed that affects vision [parseoptions()]
+ *     + Right after the hero is swallowed. [gulpmu()]
+ *     + Just before bubbles are moved. [movebubbles()]
+ */
+void
+vision_recalc(control)
+    int control;
+{
+    char **temp_array; /* points to the old vision array */
+    char **next_array; /* points to the new vision array */
+    char *next_row;    /* row pointer for the new array */
+    char *old_row;     /* row pointer for the old array */
+    char *next_rmin;   /* min pointer for the new array */
+    char *next_rmax;   /* max pointer for the new array */
+    char *ranges;      /* circle ranges -- used for xray & night vision */
+    int row;           /* row counter (outer loop)  */
+    int start, stop;   /* inner loop starting/stopping index */
+    int dx, dy;                /* one step from a lit door or lit wall (see below) */
+    register int col;  /* inner loop counter */
+    register struct rm *lev;   /* pointer to current pos */
+    struct rm *flev;   /* pointer to position in "front" of current pos */
+    extern unsigned char seenv_matrix[3][3];   /* from display.c */
+    static unsigned char colbump[COLNO+1];     /* cols to bump sv */
+    unsigned char *sv;                         /* ptr to seen angle bits */
+    int oldseenv;                              /* previous seenv value */
+
+    vision_full_recalc = 0;                    /* reset flag */
+    if (in_mklev || !iflags.vision_inited) return;
+
+#ifdef GCC_WARN
+    row = 0;
+#endif
+
+    /*
+     * Either the light sources have been taken care of, or we must
+     * recalculate them here.
+     */
+
+    /* Get the unused could see, row min, and row max arrays. */
+    get_unused_cs(&next_array, &next_rmin, &next_rmax);
+
+    /* You see nothing, nothing can see you --- if swallowed or refreshing. */
+    if (u.uswallow || control == 2) {
+       /* do nothing -- get_unused_cs() nulls out the new work area */
+
+    } else if (Blind) {
+       /*
+        * Calculate the could_see array even when blind so that monsters
+        * can see you, even if you can't see them.  Note that the current
+        * setup allows:
+        *
+        *      + Monsters to see with the "new" vision, even on the rogue
+        *        level.
+        *
+        *      + Monsters can see you even when you're in a pit.
+        */
+       view_from(u.uy, u.ux, next_array, next_rmin, next_rmax,
+               0, (void FDECL((*),(int,int,genericptr_t)))0, (genericptr_t)0);
+
+       /*
+        * Our own version of the update loop below.  We know we can't see
+        * anything, so we only need update positions we used to be able
+        * to see.
+        */
+       temp_array = viz_array; /* set viz_array so newsym() will work */
+       viz_array = next_array;
+
+       for (row = 0; row < ROWNO; row++) {
+           old_row = temp_array[row];
+
+           /* Find the min and max positions on the row. */
+           start = min(viz_rmin[row], next_rmin[row]);
+           stop  = max(viz_rmax[row], next_rmax[row]);
+
+           for (col = start; col <= stop; col++)
+               if (old_row[col] & IN_SIGHT) newsym(col,row);
+       }
+
+       /* skip the normal update loop */
+       goto skip;
+    }
+#ifdef REINCARNATION
+    else if (Is_rogue_level(&u.uz)) {
+       rogue_vision(next_array,next_rmin,next_rmax);
+    }
+#endif
+    else {
+       int has_night_vision = 1;       /* hero has night vision */
+
+       if (Underwater && !Is_waterlevel(&u.uz)) {
+           /*
+            * The hero is under water.  Only see surrounding locations if
+            * they are also underwater.  This overrides night vision but
+            * does not override x-ray vision.
+            */
+           has_night_vision = 0;
+
+           for (row = u.uy-1; row <= u.uy+1; row++)
+               for (col = u.ux-1; col <= u.ux+1; col++) {
+                   if (!isok(col,row) || !is_pool(col,row)) continue;
+
+                   next_rmin[row] = min(next_rmin[row], col);
+                   next_rmax[row] = max(next_rmax[row], col);
+                   next_array[row][col] = IN_SIGHT | COULD_SEE;
+               }
+       }
+
+       /* if in a pit, just update for immediate locations */
+       else if (u.utrap && u.utraptype == TT_PIT) {
+           for (row = u.uy-1; row <= u.uy+1; row++) {
+               if (row < 0) continue;  if (row >= ROWNO) break;
+
+               next_rmin[row] = max(      0, u.ux - 1);
+               next_rmax[row] = min(COLNO-1, u.ux + 1);
+               next_row = next_array[row];
+
+               for(col=next_rmin[row]; col <= next_rmax[row]; col++)
+                   next_row[col] = IN_SIGHT | COULD_SEE;
+           }
+       } else
+           view_from(u.uy, u.ux, next_array, next_rmin, next_rmax,
+               0, (void FDECL((*),(int,int,genericptr_t)))0, (genericptr_t)0);
+
+       /*
+        * Set the IN_SIGHT bit for xray and night vision.
+        */
+       if (u.xray_range >= 0) {
+           if (u.xray_range) {
+               ranges = circle_ptr(u.xray_range);
+
+               for (row = u.uy-u.xray_range; row <= u.uy+u.xray_range; row++) {
+                   if (row < 0) continue;      if (row >= ROWNO) break;
+                   dy = v_abs(u.uy-row);       next_row = next_array[row];
+
+                   start = max(      0, u.ux - ranges[dy]);
+                   stop  = min(COLNO-1, u.ux + ranges[dy]);
+
+                   for (col = start; col <= stop; col++) {
+                       char old_row_val = next_row[col];
+                       next_row[col] |= IN_SIGHT;
+                       oldseenv = levl[col][row].seenv;
+                       levl[col][row].seenv = SVALL;   /* see all! */
+                       /* Update if previously not in sight or new angle. */
+                       if (!(old_row_val & IN_SIGHT) || oldseenv != SVALL)
+                           newsym(col,row);
+                   }
+
+                   next_rmin[row] = min(start, next_rmin[row]);
+                   next_rmax[row] = max(stop, next_rmax[row]);
+               }
+
+           } else {    /* range is 0 */
+               next_array[u.uy][u.ux] |= IN_SIGHT;
+               levl[u.ux][u.uy].seenv = SVALL;
+               next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]);
+               next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]);
+           }
+       }
+
+       if (has_night_vision && u.xray_range < u.nv_range) {
+           if (!u.nv_range) {  /* range is 0 */
+               next_array[u.uy][u.ux] |= IN_SIGHT;
+               levl[u.ux][u.uy].seenv = SVALL;
+               next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]);
+               next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]);
+           } else if (u.nv_range > 0) {
+               ranges = circle_ptr(u.nv_range);
+
+               for (row = u.uy-u.nv_range; row <= u.uy+u.nv_range; row++) {
+                   if (row < 0) continue;      if (row >= ROWNO) break;
+                   dy = v_abs(u.uy-row);       next_row = next_array[row];
+
+                   start = max(      0, u.ux - ranges[dy]);
+                   stop  = min(COLNO-1, u.ux + ranges[dy]);
+
+                   for (col = start; col <= stop; col++)
+                       if (next_row[col]) next_row[col] |= IN_SIGHT;
+
+                   next_rmin[row] = min(start, next_rmin[row]);
+                   next_rmax[row] = max(stop, next_rmax[row]);
+               }
+           }
+       }
+    }
+
+    /* Set the correct bits for all light sources. */
+    do_light_sources(next_array);
+
+
+    /*
+     * Make the viz_array the new array so that cansee() will work correctly.
+     */
+    temp_array = viz_array;
+    viz_array = next_array;
+
+    /*
+     * The main update loop.  Here we do two things:
+     *
+     *     + Set the IN_SIGHT bit for places that we could see and are lit.
+     *     + Reset changed places.
+     *
+     * There is one thing that make deciding what the hero can see
+     * difficult:
+     *
+     *  1.  Directional lighting.  Items that block light create problems.
+     *      The worst offenders are doors.  Suppose a door to a lit room
+     *      is closed.  It is lit on one side, but not on the other.  How
+     *      do you know?  You have to check the closest adjacent position.
+     *     Even so, that is not entirely correct.  But it seems close
+     *     enough for now.
+     */
+    colbump[u.ux] = colbump[u.ux+1] = 1;
+    for (row = 0; row < ROWNO; row++) {
+       dy = u.uy - row;                dy = sign(dy);
+       next_row = next_array[row];     old_row = temp_array[row];
+
+       /* Find the min and max positions on the row. */
+       start = min(viz_rmin[row], next_rmin[row]);
+       stop  = max(viz_rmax[row], next_rmax[row]);
+       lev = &levl[start][row];
+
+       sv = &seenv_matrix[dy+1][start < u.ux ? 0 : (start > u.ux ? 2:1)];
+
+       for (col = start; col <= stop;
+                               lev += ROWNO, sv += (int) colbump[++col]) {
+           if (next_row[col] & IN_SIGHT) {
+               /*
+                * We see this position because of night- or xray-vision.
+                */
+               oldseenv = lev->seenv;
+               lev->seenv |= new_angle(lev,sv,row,col); /* update seen angle */
+
+               /* Update pos if previously not in sight or new angle. */
+               if ( !(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv)
+                   newsym(col,row);
+           }
+
+           else if ((next_row[col] & COULD_SEE)
+                               && (lev->lit || (next_row[col] & TEMP_LIT))) {
+               /*
+                * We see this position because it is lit.
+                */
+               if ((IS_DOOR(lev->typ) || lev->typ == SDOOR ||
+                    IS_WALL(lev->typ)) && !viz_clear[row][col]) {
+                   /*
+                    * Make sure doors, walls, boulders or mimics don't show up
+                    * at the end of dark hallways.  We do this by checking
+                    * the adjacent position.  If it is lit, then we can see
+                    * the door or wall, otherwise we can't.
+                    */
+                   dx = u.ux - col;    dx = sign(dx);
+                   flev = &(levl[col+dx][row+dy]);
+                   if (flev->lit || next_array[row+dy][col+dx] & TEMP_LIT) {
+                       next_row[col] |= IN_SIGHT;      /* we see it */
+
+                       oldseenv = lev->seenv;
+                       lev->seenv |= new_angle(lev,sv,row,col);
+
+                       /* Update pos if previously not in sight or new angle.*/
+                       if (!(old_row[col] & IN_SIGHT) || oldseenv!=lev->seenv)
+                           newsym(col,row);
+                   } else
+                       goto not_in_sight;      /* we don't see it */
+
+               } else {
+                   next_row[col] |= IN_SIGHT;  /* we see it */
+
+                   oldseenv = lev->seenv;
+                   lev->seenv |= new_angle(lev,sv,row,col);
+
+                   /* Update pos if previously not in sight or new angle. */
+                   if ( !(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv)
+                       newsym(col,row);
+               }
+           } else if ((next_row[col] & COULD_SEE) && lev->waslit) {
+               /*
+                * If we make it here, the hero _could see_ the location,
+                * but doesn't see it (location is not lit).
+                * However, the hero _remembers_ it as lit (waslit is true).
+                * The hero can now see that it is not lit, so change waslit
+                * and update the location.
+                */
+               lev->waslit = 0; /* remember lit condition */
+               newsym(col,row);
+           }
+           /*
+            * At this point we know that the row position is *not* in normal
+            * sight.  That is, the position is could be seen, but is dark
+            * or LOS is just plain blocked.
+            *
+            * Update the position if:
+            * o If the old one *was* in sight.  We may need to clean up
+            *   the glyph -- E.g. darken room spot, etc.
+            * o If we now could see the location (yet the location is not
+            *   lit), but previously we couldn't see the location, or vice
+            *   versa.  Update the spot because there there may be an infared
+            *   monster there.
+            */
+           else {
+not_in_sight:
+               if ((old_row[col] & IN_SIGHT)
+                       || ((next_row[col] & COULD_SEE)
+                               ^ (old_row[col] & COULD_SEE)))
+                   newsym(col,row);
+           }
+
+       } /* end for col . . */
+    }  /* end for row . .  */
+    colbump[u.ux] = colbump[u.ux+1] = 0;
+
+skip:
+    /* This newsym() caused a crash delivering msg about failure to open
+     * dungeon file init_dungeons() -> panic() -> done(11) ->
+     * vision_recalc(2) -> newsym() -> crash!  u.ux and u.uy are 0 and
+     * program_state.panicking == 1 under those circumstances
+     */
+    if (!program_state.panicking)
+       newsym(u.ux, u.uy);             /* Make sure the hero shows up! */
+
+    /* Set the new min and max pointers. */
+    viz_rmin  = next_rmin;
+    viz_rmax = next_rmax;
+}
+
+
+/*
+ * block_point()
+ *
+ * Make the location opaque to light.
+ */
+void
+block_point(x,y)
+    int x, y;
+{
+    fill_point(y,x);
+
+    /* recalc light sources here? */
+
+    /*
+     * We have to do a full vision recalculation if we "could see" the
+     * location.  Why? Suppose some monster opened a way so that the
+     * hero could see a lit room.  However, the position of the opening
+     * was out of night-vision range of the hero.  Suddenly the hero should
+     * see the lit room.
+     */
+    if (viz_array[y][x]) vision_full_recalc = 1;
+}
+
+/*
+ * unblock_point()
+ *
+ * Make the location transparent to light.
+ */
+void
+unblock_point(x,y)
+    int x, y;
+{
+    dig_point(y,x);
+
+    /* recalc light sources here? */
+
+    if (viz_array[y][x]) vision_full_recalc = 1;
+}
+
+
+/*===========================================================================*\
+ |                                                                          |
+ |     Everything below this line uses (y,x) instead of (x,y) --- the       |
+ |     algorithms are faster if they are less recursive and can scan        |
+ |     on a row longer.                                                     |
+ |                                                                          |
+\*===========================================================================*/
+
+
+/* ========================================================================= *\
+                       Left and Right Pointer Updates
+\* ========================================================================= */
+
+/*
+ *                     LEFT and RIGHT pointer rules
+ *
+ *
+ * **NOTE**  The rules changed on 4/4/90.  This comment reflects the
+ * new rules.  The change was so that the stone-wall optimization
+ * would work.
+ *
+ * OK, now the tough stuff.  We must maintain our left and right
+ * row pointers.  The rules are as follows:
+ *
+ * Left Pointers:
+ * ______________
+ *
+ * + If you are a clear spot, your left will point to the first
+ *   stone to your left.  If there is none, then point the first
+ *   legal position in the row (0).
+ *
+ * + If you are a blocked spot, then your left will point to the
+ *   left-most blocked spot to your left that is connected to you.
+ *   This means that a left-edge (a blocked spot that has an open
+ *   spot on its left) will point to itself.
+ *
+ *
+ * Right Pointers:
+ * ---------------
+ * + If you are a clear spot, your right will point to the first
+ *   stone to your right.  If there is none, then point the last
+ *   legal position in the row (COLNO-1).
+ *
+ * + If you are a blocked spot, then your right will point to the
+ *   right-most blocked spot to your right that is connected to you.
+ *   This means that a right-edge (a blocked spot that has an open
+ *    spot on its right) will point to itself.
+ */
+STATIC_OVL void
+dig_point(row,col)
+    int row,col;
+{
+    int i;
+
+    if (viz_clear[row][col]) return;           /* already done */
+
+    viz_clear[row][col] = 1;
+
+    /*
+     * Boundary cases first.
+     */
+    if (col == 0) {                            /* left edge */
+       if (viz_clear[row][1]) {
+           right_ptrs[row][0] = right_ptrs[row][1];
+       } else {
+           right_ptrs[row][0] = 1;
+           for (i = 1; i <= right_ptrs[row][1]; i++)
+               left_ptrs[row][i] = 1;
+       }
+    } else if (col == (COLNO-1)) {             /* right edge */
+
+       if (viz_clear[row][COLNO-2]) {
+           left_ptrs[row][COLNO-1] = left_ptrs[row][COLNO-2];
+       } else {
+           left_ptrs[row][COLNO-1] = COLNO-2;
+           for (i = left_ptrs[row][COLNO-2]; i < COLNO-1; i++)
+               right_ptrs[row][i] = COLNO-2;
+       }
+    }
+
+    /*
+     * At this point, we know we aren't on the boundaries.
+     */
+    else if (viz_clear[row][col-1] && viz_clear[row][col+1]) {
+       /* Both sides clear */
+       for (i = left_ptrs[row][col-1]; i <= col; i++) {
+           if (!viz_clear[row][i]) continue;   /* catch non-end case */
+           right_ptrs[row][i] = right_ptrs[row][col+1];
+       }
+       for (i = col; i <= right_ptrs[row][col+1]; i++) {
+           if (!viz_clear[row][i]) continue;   /* catch non-end case */
+           left_ptrs[row][i] = left_ptrs[row][col-1];
+       }
+
+    } else if (viz_clear[row][col-1]) {
+       /* Left side clear, right side blocked. */
+       for (i = col+1; i <= right_ptrs[row][col+1]; i++)
+           left_ptrs[row][i] = col+1;
+
+       for (i = left_ptrs[row][col-1]; i <= col; i++) {
+           if (!viz_clear[row][i]) continue;   /* catch non-end case */
+           right_ptrs[row][i] = col+1;
+       }
+       left_ptrs[row][col] = left_ptrs[row][col-1];
+
+    } else if (viz_clear[row][col+1]) {
+       /* Right side clear, left side blocked. */
+       for (i = left_ptrs[row][col-1]; i < col; i++)
+           right_ptrs[row][i] = col-1;
+
+       for (i = col; i <= right_ptrs[row][col+1]; i++) {
+           if (!viz_clear[row][i]) continue;   /* catch non-end case */
+           left_ptrs[row][i] = col-1;
+       }
+       right_ptrs[row][col] = right_ptrs[row][col+1];
+
+    } else {
+       /* Both sides blocked */
+       for (i = left_ptrs[row][col-1]; i < col; i++)
+           right_ptrs[row][i] = col-1;
+
+       for (i = col+1; i <= right_ptrs[row][col+1]; i++)
+           left_ptrs[row][i] = col+1;
+
+       left_ptrs[row][col]  = col-1;
+       right_ptrs[row][col] = col+1;
+    }
+}
+
+STATIC_OVL void
+fill_point(row,col)
+    int row, col;
+{
+    int i;
+
+    if (!viz_clear[row][col]) return;
+
+    viz_clear[row][col] = 0;
+
+    if (col == 0) {
+       if (viz_clear[row][1]) {                        /* adjacent is clear */
+           right_ptrs[row][0] = 0;
+       } else {
+           right_ptrs[row][0] = right_ptrs[row][1];
+           for (i = 1; i <= right_ptrs[row][1]; i++)
+               left_ptrs[row][i] = 0;
+       }
+    } else if (col == COLNO-1) {
+       if (viz_clear[row][COLNO-2]) {          /* adjacent is clear */
+           left_ptrs[row][COLNO-1] = COLNO-1;
+       } else {
+           left_ptrs[row][COLNO-1] = left_ptrs[row][COLNO-2];
+           for (i = left_ptrs[row][COLNO-2]; i < COLNO-1; i++)
+               right_ptrs[row][i] = COLNO-1;
+       }
+    }
+
+    /*
+     * Else we know that we are not on an edge.
+     */
+    else if (viz_clear[row][col-1] && viz_clear[row][col+1]) {
+       /* Both sides clear */
+       for (i = left_ptrs[row][col-1]+1; i <= col; i++)
+           right_ptrs[row][i] = col;
+
+       if (!left_ptrs[row][col-1])             /* catch the end case */
+           right_ptrs[row][0] = col;
+
+       for (i = col; i < right_ptrs[row][col+1]; i++)
+           left_ptrs[row][i] = col;
+
+       if (right_ptrs[row][col+1] == COLNO-1)  /* catch the end case */
+           left_ptrs[row][COLNO-1] = col;
+
+    } else if (viz_clear[row][col-1]) {
+       /* Left side clear, right side blocked. */
+       for (i = col; i <= right_ptrs[row][col+1]; i++)
+           left_ptrs[row][i] = col;
+
+       for (i = left_ptrs[row][col-1]+1; i < col; i++)
+           right_ptrs[row][i] = col;
+
+       if (!left_ptrs[row][col-1])             /* catch the end case */
+           right_ptrs[row][i] = col;
+
+       right_ptrs[row][col] = right_ptrs[row][col+1];
+
+    } else if (viz_clear[row][col+1]) {
+       /* Right side clear, left side blocked. */
+       for (i = left_ptrs[row][col-1]; i <= col; i++)
+           right_ptrs[row][i] = col;
+
+       for (i = col+1; i < right_ptrs[row][col+1]; i++)
+           left_ptrs[row][i] = col;
+
+       if (right_ptrs[row][col+1] == COLNO-1)  /* catch the end case */
+           left_ptrs[row][i] = col;
+
+       left_ptrs[row][col] = left_ptrs[row][col-1];
+
+    } else {
+       /* Both sides blocked */
+       for (i = left_ptrs[row][col-1]; i <= col; i++)
+           right_ptrs[row][i] = right_ptrs[row][col+1];
+
+       for (i = col; i <= right_ptrs[row][col+1]; i++)
+           left_ptrs[row][i] = left_ptrs[row][col-1];
+    }
+}
+
+
+/*===========================================================================*/
+/*===========================================================================*/
+/* Use either algorithm C or D.  See the config.h for more details. =========*/
+
+/*
+ * Variables local to both Algorithms C and D.
+ */
+static int  start_row;
+static int  start_col;
+static int  step;
+static char **cs_rows;
+static char *cs_left;
+static char *cs_right;
+
+static void FDECL((*vis_func), (int,int,genericptr_t));
+static genericptr_t varg;
+
+/*
+ * Both Algorithms C and D use the following macros.
+ *
+ *      good_row(z)      - Return TRUE if the argument is a legal row.
+ *      set_cs(rowp,col)  - Set the local could see array.
+ *      set_min(z)       - Save the min value of the argument and the current
+ *                           row minimum.
+ *      set_max(z)       - Save the max value of the argument and the current
+ *                           row maximum.
+ *
+ * The last three macros depend on having local pointers row_min, row_max,
+ * and rowp being set correctly.
+ */
+#define set_cs(rowp,col) (rowp[col] = COULD_SEE)
+#define good_row(z) ((z) >= 0 && (z) < ROWNO)
+#define set_min(z) if (*row_min > (z)) *row_min = (z)
+#define set_max(z) if (*row_max < (z)) *row_max = (z)
+#define is_clear(row,col) viz_clear_rows[row][col]
+
+/*
+ * clear_path()                expanded into 4 macros/functions:
+ *
+ *     q1_path()
+ *     q2_path()
+ *     q3_path()
+ *     q4_path()
+ *
+ * "Draw" a line from the start to the given location.  Stop if we hit
+ * something that blocks light.  The start and finish points themselves are
+ * not checked, just the points between them.  These routines do _not_
+ * expect to be called with the same starting and stopping point.
+ *
+ * These routines use the generalized integer Bresenham's algorithm (fast
+ * line drawing) for all quadrants.  The algorithm was taken from _Procedural
+ * Elements for Computer Graphics_, by David F. Rogers.  McGraw-Hill, 1985.
+ */
+#ifdef MACRO_CPATH     /* quadrant calls are macros */
+
+/*
+ * When called, the result is in "result".
+ * The first two arguments (srow,scol) are one end of the path.  The next
+ * two arguments (row,col) are the destination.  The last argument is
+ * used as a C language label.  This means that it must be different
+ * in each pair of calls.
+ */
+
+/*
+ *  Quadrant I (step < 0).
+ */
+#define q1_path(srow,scol,y2,x2,label)                 \
+{                                                      \
+    int dx, dy;                                                \
+    register int k, err, x, y, dxs, dys;               \
+                                                       \
+    x  = (scol);       y  = (srow);                    \
+    dx = (x2) - x;     dy = y - (y2);                  \
+                                                       \
+    result = 0;                 /* default to a blocked path */\
+                                                       \
+    dxs = dx << 1;        /* save the shifted values */\
+    dys = dy << 1;                                     \
+    if (dy > dx) {                                     \
+       err = dxs - dy;                                 \
+                                                       \
+       for (k = dy-1; k; k--) {                        \
+           if (err >= 0) {                             \
+               x++;                                    \
+               err -= dys;                             \
+           }                                           \
+           y--;                                        \
+           err += dxs;                                 \
+           if (!is_clear(y,x)) goto label;/* blocked */\
+       }                                               \
+    } else {                                           \
+       err = dys - dx;                                 \
+                                                       \
+       for (k = dx-1; k; k--) {                        \
+           if (err >= 0) {                             \
+               y--;                                    \
+               err -= dxs;                             \
+           }                                           \
+           x++;                                        \
+           err += dys;                                 \
+           if (!is_clear(y,x)) goto label;/* blocked */\
+       }                                               \
+    }                                                  \
+                                                       \
+    result = 1;                                                \
+}
+
+/*
+ * Quadrant IV (step > 0).
+ */
+#define q4_path(srow,scol,y2,x2,label)                 \
+{                                                      \
+    int dx, dy;                                                \
+    register int k, err, x, y, dxs, dys;               \
+                                                       \
+    x  = (scol);       y  = (srow);                    \
+    dx = (x2) - x;     dy = (y2) - y;                  \
+                                                       \
+    result = 0;                 /* default to a blocked path */\
+                                                       \
+    dxs = dx << 1;        /* save the shifted values */\
+    dys = dy << 1;                                     \
+    if (dy > dx) {                                     \
+       err = dxs - dy;                                 \
+                                                       \
+       for (k = dy-1; k; k--) {                        \
+           if (err >= 0) {                             \
+               x++;                                    \
+               err -= dys;                             \
+           }                                           \
+           y++;                                        \
+           err += dxs;                                 \
+           if (!is_clear(y,x)) goto label;/* blocked */\
+       }                                               \
+                                                       \
+    } else {                                           \
+       err = dys - dx;                                 \
+                                                       \
+       for (k = dx-1; k; k--) {                        \
+           if (err >= 0) {                             \
+               y++;                                    \
+               err -= dxs;                             \
+           }                                           \
+           x++;                                        \
+           err += dys;                                 \
+           if (!is_clear(y,x)) goto label;/* blocked */\
+       }                                               \
+    }                                                  \
+                                                       \
+    result = 1;                                                \
+}
+
+/*
+ * Quadrant II (step < 0).
+ */
+#define q2_path(srow,scol,y2,x2,label)                 \
+{                                                      \
+    int dx, dy;                                                \
+    register int k, err, x, y, dxs, dys;               \
+                                                       \
+    x  = (scol);       y  = (srow);                    \
+    dx = x - (x2);     dy = y - (y2);                  \
+                                                       \
+    result = 0;                 /* default to a blocked path */\
+                                                       \
+    dxs = dx << 1;        /* save the shifted values */\
+    dys = dy << 1;                                     \
+    if (dy > dx) {                                     \
+       err = dxs - dy;                                 \
+                                                       \
+       for (k = dy-1; k; k--) {                        \
+           if (err >= 0) {                             \
+               x--;                                    \
+               err -= dys;                             \
+           }                                           \
+           y--;                                        \
+           err += dxs;                                 \
+           if (!is_clear(y,x)) goto label;/* blocked */\
+       }                                               \
+    } else {                                           \
+       err = dys - dx;                                 \
+                                                       \
+       for (k = dx-1; k; k--) {                        \
+           if (err >= 0) {                             \
+               y--;                                    \
+               err -= dxs;                             \
+           }                                           \
+           x--;                                        \
+           err += dys;                                 \
+           if (!is_clear(y,x)) goto label;/* blocked */\
+       }                                               \
+    }                                                  \
+                                                       \
+    result = 1;                                                \
+}
+
+/*
+ * Quadrant III (step > 0).
+ */
+#define q3_path(srow,scol,y2,x2,label)                 \
+{                                                      \
+    int dx, dy;                                                \
+    register int k, err, x, y, dxs, dys;               \
+                                                       \
+    x  = (scol);       y  = (srow);                    \
+    dx = x - (x2);     dy = (y2) - y;                  \
+                                                       \
+    result = 0;                 /* default to a blocked path */\
+                                                       \
+    dxs = dx << 1;        /* save the shifted values */\
+    dys = dy << 1;                                     \
+    if (dy > dx) {                                     \
+       err = dxs - dy;                                 \
+                                                       \
+       for (k = dy-1; k; k--) {                        \
+           if (err >= 0) {                             \
+               x--;                                    \
+               err -= dys;                             \
+           }                                           \
+           y++;                                        \
+           err += dxs;                                 \
+           if (!is_clear(y,x)) goto label;/* blocked */\
+       }                                               \
+                                                       \
+    } else {                                           \
+       err = dys - dx;                                 \
+                                                       \
+       for (k = dx-1; k; k--) {                        \
+           if (err >= 0) {                             \
+               y++;                                    \
+               err -= dxs;                             \
+           }                                           \
+           x--;                                        \
+           err += dys;                                 \
+           if (!is_clear(y,x)) goto label;/* blocked */\
+       }                                               \
+    }                                                  \
+                                                       \
+    result = 1;                                                \
+}
+
+#else   /* quadrants are really functions */
+
+STATIC_DCL int FDECL(_q1_path, (int,int,int,int));
+STATIC_DCL int FDECL(_q2_path, (int,int,int,int));
+STATIC_DCL int FDECL(_q3_path, (int,int,int,int));
+STATIC_DCL int FDECL(_q4_path, (int,int,int,int));
+
+#define q1_path(sy,sx,y,x,dummy) result = _q1_path(sy,sx,y,x)
+#define q2_path(sy,sx,y,x,dummy) result = _q2_path(sy,sx,y,x)
+#define q3_path(sy,sx,y,x,dummy) result = _q3_path(sy,sx,y,x)
+#define q4_path(sy,sx,y,x,dummy) result = _q4_path(sy,sx,y,x)
+
+/*
+ * Quadrant I (step < 0).
+ */
+STATIC_OVL int
+_q1_path(srow,scol,y2,x2)
+    int scol, srow, y2, x2;
+{
+    int dx, dy;
+    register int k, err, x, y, dxs, dys;
+
+    x  = scol;         y  = srow;
+    dx = x2 - x;       dy = y - y2;
+
+    dxs = dx << 1;        /* save the shifted values */
+    dys = dy << 1;
+    if (dy > dx) {
+       err = dxs - dy;
+
+       for (k = dy-1; k; k--) {
+           if (err >= 0) {
+               x++;
+               err -= dys;
+           }
+           y--;
+           err += dxs;
+           if (!is_clear(y,x)) return 0; /* blocked */
+       }
+    } else {
+       err = dys - dx;
+
+       for (k = dx-1; k; k--) {
+           if (err >= 0) {
+               y--;
+               err -= dxs;
+           }
+           x++;
+           err += dys;
+           if (!is_clear(y,x)) return 0;/* blocked */
+       }
+    }
+
+    return 1;
+}
+
+/*
+ * Quadrant IV (step > 0).
+ */
+STATIC_OVL int
+_q4_path(srow,scol,y2,x2)
+    int scol, srow, y2, x2;
+{
+    int dx, dy;
+    register int k, err, x, y, dxs, dys;
+
+    x  = scol;         y  = srow;
+    dx = x2 - x;       dy = y2 - y;
+
+    dxs = dx << 1;        /* save the shifted values */
+    dys = dy << 1;
+    if (dy > dx) {
+       err = dxs - dy;
+
+       for (k = dy-1; k; k--) {
+           if (err >= 0) {
+               x++;
+               err -= dys;
+           }
+           y++;
+           err += dxs;
+           if (!is_clear(y,x)) return 0; /* blocked */
+       }
+    } else {
+       err = dys - dx;
+
+       for (k = dx-1; k; k--) {
+           if (err >= 0) {
+               y++;
+               err -= dxs;
+           }
+           x++;
+           err += dys;
+           if (!is_clear(y,x)) return 0;/* blocked */
+       }
+    }
+
+    return 1;
+}
+
+/*
+ * Quadrant II (step < 0).
+ */
+STATIC_OVL int
+_q2_path(srow,scol,y2,x2)
+    int scol, srow, y2, x2;
+{
+    int dx, dy;
+    register int k, err, x, y, dxs, dys;
+
+    x  = scol;         y  = srow;
+    dx = x - x2;       dy = y - y2;
+
+    dxs = dx << 1;        /* save the shifted values */
+    dys = dy << 1;
+    if (dy > dx) {
+       err = dxs - dy;
+
+       for (k = dy-1; k; k--) {
+           if (err >= 0) {
+               x--;
+               err -= dys;
+           }
+           y--;
+           err += dxs;
+           if (!is_clear(y,x)) return 0; /* blocked */
+       }
+    } else {
+       err = dys - dx;
+
+       for (k = dx-1; k; k--) {
+           if (err >= 0) {
+               y--;
+               err -= dxs;
+           }
+           x--;
+           err += dys;
+           if (!is_clear(y,x)) return 0;/* blocked */
+       }
+    }
+
+    return 1;
+}
+
+/*
+ * Quadrant III (step > 0).
+ */
+STATIC_OVL int
+_q3_path(srow,scol,y2,x2)
+    int scol, srow, y2, x2;
+{
+    int dx, dy;
+    register int k, err, x, y, dxs, dys;
+
+    x  = scol;         y  = srow;
+    dx = x - x2;       dy = y2 - y;
+
+    dxs = dx << 1;        /* save the shifted values */
+    dys = dy << 1;
+    if (dy > dx) {
+       err = dxs - dy;
+
+       for (k = dy-1; k; k--) {
+           if (err >= 0) {
+               x--;
+               err -= dys;
+           }
+           y++;
+           err += dxs;
+           if (!is_clear(y,x)) return 0; /* blocked */
+       }
+    } else {
+       err = dys - dx;
+
+       for (k = dx-1; k; k--) {
+           if (err >= 0) {
+               y++;
+               err -= dxs;
+           }
+           x--;
+           err += dys;
+           if (!is_clear(y,x)) return 0;/* blocked */
+       }
+    }
+
+    return 1;
+}
+
+#endif /* quadrants are functions */
+
+/*
+ * Use vision tables to determine if there is a clear path from
+ * (col1,row1) to (col2,row2).  This is used by:
+ *             m_cansee()
+ *             m_canseeu()
+ *             do_light_sources()
+ */
+boolean
+clear_path(col1,row1,col2,row2)
+    int col1, row1, col2, row2;
+{
+    int result;
+
+    if(col1 < col2) {
+       if(row1 > row2) {
+           q1_path(row1,col1,row2,col2,cleardone);
+       } else {
+           q4_path(row1,col1,row2,col2,cleardone);
+       }
+    } else {
+       if(row1 > row2) {
+           q2_path(row1,col1,row2,col2,cleardone);
+       } else if(row1 == row2 && col1 == col2) {
+           result = 1;
+       } else {
+           q3_path(row1,col1,row2,col2,cleardone);
+       }
+    }
+#ifdef MACRO_CPATH
+cleardone:
+#endif
+    return((boolean)result);
+}
+
+#ifdef VISION_TABLES
+/*===========================================================================*\
+                           GENERAL LINE OF SIGHT
+                               Algorithm D
+\*===========================================================================*/
+
+
+/*
+ * Indicate caller for the shadow routines.
+ */
+#define FROM_RIGHT 0
+#define FROM_LEFT  1
+
+
+/*
+ * Include the table definitions.
+ */
+#include "vis_tab.h"
+
+
+/* 3D table pointers. */
+static close2d *close_dy[CLOSE_MAX_BC_DY];
+static far2d   *far_dy[FAR_MAX_BC_DY];
+
+STATIC_DCL void FDECL(right_side, (int,int,int,int,int,int,int,char*));
+STATIC_DCL void FDECL(left_side, (int,int,int,int,int,int,int,char*));
+STATIC_DCL int FDECL(close_shadow, (int,int,int,int));
+STATIC_DCL int FDECL(far_shadow, (int,int,int,int));
+
+/*
+ * Initialize algorithm D's table pointers.  If we don't have these,
+ * then we do 3D table lookups.  Verrrry slow.
+ */
+STATIC_OVL void
+view_init()
+{
+    int i;
+
+    for (i = 0; i < CLOSE_MAX_BC_DY; i++)
+       close_dy[i] = &close_table[i];
+
+    for (i = 0; i < FAR_MAX_BC_DY; i++)
+       far_dy[i] = &far_table[i];
+}
+
+
+/*
+ * If the far table has an entry of OFF_TABLE, then the far block prevents
+ * us from seeing the location just above/below it.  I.e. the first visible
+ * location is one *before* the block.
+ */
+#define OFF_TABLE 0xff
+
+STATIC_OVL int
+close_shadow(side,this_row,block_row,block_col)
+    int side,this_row,block_row,block_col;
+{
+    register int sdy, sdx, pdy, offset;
+
+    /*
+     * If on the same column (block_row = -1), then we can see it.
+     */
+    if (block_row < 0) return block_col;
+
+    /* Take explicit absolute values.  Adjust. */
+    if ((sdy = (start_row-block_row)) < 0) sdy = -sdy; --sdy;  /* src   dy */
+    if ((sdx = (start_col-block_col)) < 0) sdx = -sdx;         /* src   dx */
+    if ((pdy = (block_row-this_row))  < 0) pdy = -pdy;         /* point dy */
+
+    if (sdy < 0 || sdy >= CLOSE_MAX_SB_DY || sdx >= CLOSE_MAX_SB_DX ||
+                                                   pdy >= CLOSE_MAX_BC_DY) {
+       impossible("close_shadow:  bad value");
+       return block_col;
+    }
+    offset = close_dy[sdy]->close[sdx][pdy];
+    if (side == FROM_RIGHT)
+       return block_col + offset;
+
+    return block_col - offset;
+}
+
+
+STATIC_OVL int
+far_shadow(side,this_row,block_row,block_col)
+    int side,this_row,block_row,block_col;
+{
+    register int sdy, sdx, pdy, offset;
+
+    /*
+     * Take care of a bug that shows up only on the borders.
+     *
+     * If the block is beyond the border, then the row is negative.  Return
+     * the block's column number (should be 0 or COLNO-1).
+     *
+     * Could easily have the column be -1, but then wouldn't know if it was
+     * the left or right border.
+     */
+    if (block_row < 0) return block_col;
+
+    /* Take explicit absolute values.  Adjust. */
+    if ((sdy = (start_row-block_row)) < 0) sdy = -sdy;         /* src   dy */
+    if ((sdx = (start_col-block_col)) < 0) sdx = -sdx; --sdx;  /* src   dx */
+    if ((pdy = (block_row-this_row))  < 0) pdy = -pdy; --pdy;  /* point dy */
+
+    if (sdy >= FAR_MAX_SB_DY || sdx < 0 || sdx >= FAR_MAX_SB_DX ||
+                                           pdy < 0 || pdy >= FAR_MAX_BC_DY) {
+       impossible("far_shadow:  bad value");
+       return block_col;
+    }
+    if ((offset = far_dy[sdy]->far_q[sdx][pdy]) == OFF_TABLE) offset = -1;
+    if (side == FROM_RIGHT)
+       return block_col + offset;
+
+    return block_col - offset;
+}
+
+
+/*
+ * right_side()
+ *
+ * Figure out what could be seen on the right side of the source.
+ */
+STATIC_OVL void
+right_side(row, cb_row, cb_col, fb_row, fb_col, left, right_mark, limits)
+    int row;           /* current row */
+    int        cb_row, cb_col; /* close block row and col */
+    int        fb_row, fb_col; /* far block row and col */
+    int left;          /* left mark of the previous row */
+    int        right_mark;     /* right mark of previous row */
+    char *limits;      /* points at range limit for current row, or NULL */
+{
+    register int  i;
+    register char *rowp;
+    int  hit_stone = 0;
+    int  left_shadow, right_shadow, loc_right;
+    int  lblock_col;           /* local block column (current row) */
+    int  nrow, deeper;
+    char *row_min;             /* left most */
+    char *row_max;             /* right most */
+    int                  lim_max;      /* right most limit of circle */
+
+#ifdef GCC_WARN
+    rowp = 0;
+#endif
+    nrow    = row + step;
+    deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
+    if(!vis_func) {
+       rowp    = cs_rows[row];
+       row_min = &cs_left[row];
+       row_max = &cs_right[row];
+    }
+    if(limits) {
+       lim_max = start_col + *limits;
+       if(lim_max > COLNO-1) lim_max = COLNO-1;
+       if(right_mark > lim_max) right_mark = lim_max;
+       limits++; /* prepare for next row */
+    } else
+       lim_max = COLNO-1;
+
+    /*
+     * Get the left shadow from the close block.  This value could be
+     * illegal.
+     */
+    left_shadow = close_shadow(FROM_RIGHT,row,cb_row,cb_col);
+
+    /*
+     * Mark all stone walls as seen before the left shadow.  All this work
+     * for a special case.
+     *
+     * NOTE.  With the addition of this code in here, it is now *required*
+     * for the algorithm to work correctly.  If this is commented out,
+     * change the above assignment so that left and not left_shadow is the
+     * variable that gets the shadow.
+     */
+    while (left <= right_mark) {
+       loc_right = right_ptrs[row][left];
+       if(loc_right > lim_max) loc_right = lim_max;
+       if (viz_clear_rows[row][left]) {
+           if (loc_right >= left_shadow) {
+               left = left_shadow;     /* opening ends beyond shadow */
+               break;
+           }
+           left = loc_right;
+           loc_right = right_ptrs[row][left];
+           if(loc_right > lim_max) loc_right = lim_max;
+           if (left == loc_right) return;      /* boundary */
+
+           /* Shadow covers opening, beyond right mark */
+           if (left == right_mark && left_shadow > right_mark) return;
+       }
+
+       if (loc_right > right_mark)     /* can't see stone beyond the mark */
+           loc_right = right_mark;
+
+       if(vis_func) {
+           for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg);
+       } else {
+           for (i = left; i <= loc_right; i++) set_cs(rowp,i);
+           set_min(left);      set_max(loc_right);
+       }
+
+       if (loc_right == right_mark) return;    /* all stone */
+       if (loc_right >= left_shadow) hit_stone = 1;
+       left = loc_right + 1;
+    }
+
+    /*
+     * At this point we are at the first visible clear spot on or beyond
+     * the left shadow, unless the left shadow is an illegal value.  If we
+     * have "hit stone" then we have a stone wall just to our left.
+     */
+
+    /*
+     * Get the right shadow.  Make sure that it is a legal value.
+     */
+    if ((right_shadow = far_shadow(FROM_RIGHT,row,fb_row,fb_col)) >= COLNO)
+       right_shadow = COLNO-1;
+    /*
+     * Make vertical walls work the way we want them.  In this case, we
+     * note when the close block blocks the column just above/beneath
+     * it (right_shadow < fb_col [actually right_shadow == fb_col-1]).  If
+     * the location is filled, then we want to see it, so we put the
+     * right shadow back (same as fb_col).
+     */
+    if (right_shadow < fb_col && !viz_clear_rows[row][fb_col])
+       right_shadow = fb_col;
+    if(right_shadow > lim_max) right_shadow = lim_max;
+
+    /*
+     * Main loop.  Within the range of sight of the previous row, mark all
+     * stone walls as seen.  Follow open areas recursively.
+     */
+    while (left <= right_mark) {
+       /* Get the far right of the opening or wall */
+       loc_right = right_ptrs[row][left];
+       if(loc_right > lim_max) loc_right = lim_max;
+
+       if (!viz_clear_rows[row][left]) {
+           hit_stone = 1;      /* use stone on this row as close block */
+           /*
+            * We can see all of the wall until the next open spot or the
+            * start of the shadow caused by the far block (right).
+            *
+            * Can't see stone beyond the right mark.
+            */
+           if (loc_right > right_mark) loc_right = right_mark;
+
+           if(vis_func) {
+               for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg);
+           } else {
+               for (i = left; i <= loc_right; i++) set_cs(rowp,i);
+               set_min(left);  set_max(loc_right);
+           }
+
+           if (loc_right == right_mark) return;        /* hit the end */
+           left = loc_right + 1;
+           loc_right = right_ptrs[row][left];
+           if(loc_right > lim_max) loc_right = lim_max;
+           /* fall through... we know at least one position is visible */
+       }
+
+       /*
+        * We are in an opening.
+        *
+        * If this is the first open spot since the could see area  (this is
+        * true if we have hit stone), get the shadow generated by the wall
+        * just to our left.
+        */
+       if (hit_stone) {
+           lblock_col = left-1;        /* local block column */
+           left = close_shadow(FROM_RIGHT,row,row,lblock_col);
+           if (left > lim_max) break;          /* off the end */
+       }
+
+       /*
+        * Check if the shadow covers the opening.  If it does, then
+        * move to end of the opening.  A shadow generated on from a
+        * wall on this row does *not* cover the wall on the right
+        * of the opening.
+        */
+       if (left >= loc_right) {
+           if (loc_right == lim_max) {         /* boundary */
+               if (left == lim_max) {
+                   if(vis_func) (*vis_func)(lim_max, row, varg);
+                   else {
+                       set_cs(rowp,lim_max);   /* last pos */
+                       set_max(lim_max);
+                   }
+               }
+               return;                                 /* done */
+           }
+           left = loc_right;
+           continue;
+       }
+
+       /*
+        * If the far wall of the opening (loc_right) is closer than the
+        * shadow limit imposed by the far block (right) then use the far
+        * wall as our new far block when we recurse.
+        *
+        * If the limits are the the same, and the far block really exists
+        * (fb_row >= 0) then do the same as above.
+        *
+        * Normally, the check would be for the far wall being closer OR EQUAL
+        * to the shadow limit.  However, there is a bug that arises from the
+        * fact that the clear area pointers end in an open space (if it
+        * exists) on a boundary.  This then makes a far block exist where it
+        * shouldn't --- on a boundary.  To get around that, I had to
+        * introduce the concept of a non-existent far block (when the
+        * row < 0).  Next I have to check for it.  Here is where that check
+        * exists.
+        */
+       if ((loc_right < right_shadow) ||
+                               (fb_row >= 0 && loc_right == right_shadow)) {
+           if(vis_func) {
+               for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg);
+           } else {
+               for (i = left; i <= loc_right; i++) set_cs(rowp,i);
+               set_min(left);  set_max(loc_right);
+           }
+
+           if (deeper) {
+               if (hit_stone)
+                   right_side(nrow,row,lblock_col,row,loc_right,
+                                                       left,loc_right,limits);
+               else
+                   right_side(nrow,cb_row,cb_col,row,loc_right,
+                                                       left,loc_right,limits);
+           }
+
+           /*
+            * The following line, setting hit_stone, is needed for those
+            * walls that are only 1 wide.  If hit stone is *not* set and
+            * the stone is only one wide, then the close block is the old
+            * one instead one on the current row.  A way around having to
+            * set it here is to make left = loc_right (not loc_right+1) and
+            * let the outer loop take care of it.  However, if we do that
+            * then we then have to check for boundary conditions here as
+            * well.
+            */
+           hit_stone = 1;
+
+           left = loc_right+1;
+       }
+       /*
+        * The opening extends beyond the right mark.  This means that
+        * the next far block is the current far block.
+        */
+       else {
+           if(vis_func) {
+               for (i=left; i <= right_shadow; i++) (*vis_func)(i, row, varg);
+           } else {
+               for (i = left; i <= right_shadow; i++) set_cs(rowp,i);
+               set_min(left);  set_max(right_shadow);
+           }
+
+           if (deeper) {
+               if (hit_stone)
+                   right_side(nrow,   row,lblock_col,fb_row,fb_col,
+                                                    left,right_shadow,limits);
+               else
+                   right_side(nrow,cb_row,    cb_col,fb_row,fb_col,
+                                                    left,right_shadow,limits);
+           }
+
+           return;     /* we're outta here */
+       }
+    }
+}
+
+
+/*
+ * left_side()
+ *
+ * This routine is the mirror image of right_side().  Please see right_side()
+ * for blow by blow comments.
+ */
+STATIC_OVL void
+left_side(row, cb_row, cb_col, fb_row, fb_col, left_mark, right, limits)
+    int row;           /* the current row */
+    int        cb_row, cb_col; /* close block row and col */
+    int        fb_row, fb_col; /* far block row and col */
+    int        left_mark;      /* left mark of previous row */
+    int right;         /* right mark of the previous row */
+    char *limits;
+{
+    register int  i;
+    register char *rowp;
+    int  hit_stone = 0;
+    int  left_shadow, right_shadow, loc_left;
+    int  lblock_col;           /* local block column (current row) */
+    int  nrow, deeper;
+    char *row_min;             /* left most */
+    char *row_max;             /* right most */
+    int                  lim_min;
+
+#ifdef GCC_WARN
+    rowp = 0;
+#endif
+    nrow    = row + step;
+    deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
+    if(!vis_func) {
+       rowp    = cs_rows[row];
+       row_min = &cs_left[row];
+       row_max = &cs_right[row];
+    }
+    if(limits) {
+       lim_min = start_col - *limits;
+       if(lim_min < 0) lim_min = 0;
+       if(left_mark < lim_min) left_mark = lim_min;
+       limits++; /* prepare for next row */
+    } else
+       lim_min = 0;
+
+    /* This value could be illegal. */
+    right_shadow = close_shadow(FROM_LEFT,row,cb_row,cb_col);
+
+    while ( right >= left_mark ) {
+       loc_left = left_ptrs[row][right];
+       if(loc_left < lim_min) loc_left = lim_min;
+       if (viz_clear_rows[row][right]) {
+           if (loc_left <= right_shadow) {
+               right = right_shadow;   /* opening ends beyond shadow */
+               break;
+           }
+           right = loc_left;
+           loc_left = left_ptrs[row][right];
+           if(loc_left < lim_min) loc_left = lim_min;
+           if (right == loc_left) return;      /* boundary */
+       }
+
+       if (loc_left < left_mark)       /* can't see beyond the left mark */
+           loc_left = left_mark;
+
+       if(vis_func) {
+           for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg);
+       } else {
+           for (i = loc_left; i <= right; i++) set_cs(rowp,i);
+           set_min(loc_left);  set_max(right);
+       }
+
+       if (loc_left == left_mark) return;      /* all stone */
+       if (loc_left <= right_shadow) hit_stone = 1;
+       right = loc_left - 1;
+    }
+
+    /* At first visible clear spot on or beyond the right shadow. */
+
+    if ((left_shadow = far_shadow(FROM_LEFT,row,fb_row,fb_col)) < 0)
+       left_shadow = 0;
+
+    /* Do vertical walls as we want. */
+    if (left_shadow > fb_col && !viz_clear_rows[row][fb_col])
+       left_shadow = fb_col;
+    if(left_shadow < lim_min) left_shadow = lim_min;
+
+    while (right >= left_mark) {
+       loc_left = left_ptrs[row][right];
+
+       if (!viz_clear_rows[row][right]) {
+           hit_stone = 1;      /* use stone on this row as close block */
+
+           /* We can only see walls until the left mark */
+           if (loc_left < left_mark) loc_left = left_mark;
+
+           if(vis_func) {
+               for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg);
+           } else {
+               for (i = loc_left; i <= right; i++) set_cs(rowp,i);
+               set_min(loc_left);      set_max(right);
+           }
+
+           if (loc_left == left_mark) return;  /* hit end */
+           right = loc_left - 1;
+           loc_left = left_ptrs[row][right];
+           if (loc_left < lim_min) loc_left = lim_min;
+           /* fall through...*/
+       }
+
+       /* We are in an opening. */
+       if (hit_stone) {
+           lblock_col = right+1;       /* stone block (local) */
+           right = close_shadow(FROM_LEFT,row,row,lblock_col);
+           if (right < lim_min) return;        /* off the end */
+       }
+
+       /*  Check if the shadow covers the opening. */
+       if (right <= loc_left) {
+           /*  Make a boundary condition work. */
+           if (loc_left == lim_min) {  /* at boundary */
+               if (right == lim_min) {
+                   if(vis_func) (*vis_func)(lim_min, row, varg);
+                   else {
+                       set_cs(rowp,lim_min);   /* caught the last pos */
+                       set_min(lim_min);
+                   }
+               }
+               return;                 /* and break out the loop */
+           }
+
+           right = loc_left;
+           continue;
+       }
+
+       /* If the far wall of the opening is closer than the shadow limit. */
+       if ((loc_left > left_shadow) ||
+                                   (fb_row >= 0 && loc_left == left_shadow)) {
+           if(vis_func) {
+               for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg);
+           } else {
+               for (i = loc_left; i <= right; i++) set_cs(rowp,i);
+               set_min(loc_left);      set_max(right);
+           }
+
+           if (deeper) {
+               if (hit_stone)
+                   left_side(nrow,row,lblock_col,row,loc_left,
+                                                       loc_left,right,limits);
+               else
+                   left_side(nrow,cb_row,cb_col,row,loc_left,
+                                                       loc_left,right,limits);
+           }
+
+           hit_stone = 1;      /* needed for walls of width 1 */
+           right = loc_left-1;
+       }
+       /*  The opening extends beyond the left mark. */
+       else {
+           if(vis_func) {
+               for (i=left_shadow; i <= right; i++) (*vis_func)(i, row, varg);
+           } else {
+               for (i = left_shadow; i <= right; i++) set_cs(rowp,i);
+               set_min(left_shadow);   set_max(right);
+           }
+
+           if (deeper) {
+               if (hit_stone)
+                   left_side(nrow,row,lblock_col,fb_row,fb_col,
+                                                    left_shadow,right,limits);
+               else
+                   left_side(nrow,cb_row,cb_col,fb_row,fb_col,
+                                                    left_shadow,right,limits);
+           }
+
+           return;     /* we're outta here */
+       }
+
+    }
+}
+
+/*
+ * view_from
+ *
+ * Calculate a view from the given location.  Initialize and fill a
+ * ROWNOxCOLNO array (could_see) with all the locations that could be
+ * seen from the source location.  Initialize and fill the left most
+ * and right most boundaries of what could be seen.
+ */
+STATIC_OVL void
+view_from(srow,scol,loc_cs_rows,left_most,right_most, range, func, arg)
+    int  srow, scol;                   /* source row and column */
+    char **loc_cs_rows;                        /* could_see array (row pointers) */
+    char *left_most, *right_most;      /* limits of what could be seen */
+    int range;         /* 0 if unlimited */
+    void FDECL((*func), (int,int,genericptr_t));
+    genericptr_t arg;
+{
+    register int i;
+    char        *rowp;
+    int                 nrow, left, right, left_row, right_row;
+    char        *limits;
+
+    /* Set globals for near_shadow(), far_shadow(), etc. to use. */
+    start_col = scol;
+    start_row = srow;
+    cs_rows   = loc_cs_rows;
+    cs_left   = left_most;
+    cs_right  = right_most;
+    vis_func = func;
+    varg = arg;
+
+    /*  Find the left and right limits of sight on the starting row. */
+    if (viz_clear_rows[srow][scol]) {
+       left  = left_ptrs[srow][scol];
+       right = right_ptrs[srow][scol];
+    } else {
+       left  = (!scol) ? 0 :
+           (viz_clear_rows[srow][scol-1] ?  left_ptrs[srow][scol-1] : scol-1);
+       right = (scol == COLNO-1) ? COLNO-1 :
+           (viz_clear_rows[srow][scol+1] ? right_ptrs[srow][scol+1] : scol+1);
+    }
+
+    if(range) {
+       if(range > MAX_RADIUS || range < 1)
+           panic("view_from called with range %d", range);
+       limits = circle_ptr(range) + 1; /* start at next row */
+       if(left < scol - range) left = scol - range;
+       if(right > scol + range) right = scol + range;
+    } else
+       limits = (char*) 0;
+
+    if(func) {
+       for (i = left; i <= right; i++) (*func)(i, srow, arg);
+    } else {
+       /* Row optimization */
+       rowp = cs_rows[srow];
+
+       /* We know that we can see our row. */
+       for (i = left; i <= right; i++) set_cs(rowp,i);
+       cs_left[srow]  = left;
+       cs_right[srow] = right;
+    }
+
+    /* The far block has a row number of -1 if we are on an edge. */
+    right_row = (right == COLNO-1) ? -1 : srow;
+    left_row  = (!left)                   ? -1 : srow;
+
+    /*
+     *  Check what could be seen in quadrants.
+     */
+    if ( (nrow = srow+1) < ROWNO ) {
+       step =  1;      /* move down */
+       if (scol<COLNO-1)
+           right_side(nrow,-1,scol,right_row,right,scol,right,limits);
+       if (scol)
+           left_side(nrow,-1,scol,left_row, left, left, scol,limits);
+    }
+
+    if ( (nrow = srow-1) >= 0 ) {
+       step = -1;      /* move up */
+       if (scol<COLNO-1)
+           right_side(nrow,-1,scol,right_row,right,scol,right,limits);
+       if (scol)
+           left_side(nrow,-1,scol,left_row, left, left, scol,limits);
+    }
+}
+
+
+#else  /*===== End of algorithm D =====*/
+
+
+/*===========================================================================*\
+                           GENERAL LINE OF SIGHT
+                               Algorithm C
+\*===========================================================================*/
+
+/*
+ * Defines local to Algorithm C.
+ */
+STATIC_DCL void FDECL(right_side, (int,int,int,char*));
+STATIC_DCL void FDECL(left_side, (int,int,int,char*));
+
+/* Initialize algorithm C (nothing). */
+STATIC_OVL void
+view_init()
+{
+}
+
+/*
+ * Mark positions as visible on one quadrant of the right side.  The
+ * quadrant is determined by the value of the global variable step.
+ */
+STATIC_OVL void
+right_side(row, left, right_mark, limits)
+    int row;           /* current row */
+    int left;          /* first (left side) visible spot on prev row */
+    int right_mark;    /* last (right side) visible spot on prev row */
+    char *limits;      /* points at range limit for current row, or NULL */
+{
+    int                  right;        /* right limit of "could see" */
+    int                  right_edge;   /* right edge of an opening */
+    int                  nrow;         /* new row (calculate once) */
+    int                  deeper;       /* if TRUE, call self as needed */
+    int                  result;       /* set by q?_path() */
+    register int  i;           /* loop counter */
+    register char *rowp;       /* row optimization */
+    char         *row_min;     /* left most  [used by macro set_min()] */
+    char         *row_max;     /* right most [used by macro set_max()] */
+    int                  lim_max;      /* right most limit of circle */
+
+#ifdef GCC_WARN
+    rowp = row_min = row_max = 0;
+#endif
+    nrow    = row + step;
+    /*
+     * Can go deeper if the row is in bounds and the next row is within
+     * the circle's limit.  We tell the latter by checking to see if the next
+     * limit value is the start of a new circle radius (meaning we depend
+     * on the structure of circle_data[]).
+     */
+    deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
+    if(!vis_func) {
+       rowp    = cs_rows[row]; /* optimization */
+       row_min = &cs_left[row];
+       row_max = &cs_right[row];
+    }
+    if(limits) {
+       lim_max = start_col + *limits;
+       if(lim_max > COLNO-1) lim_max = COLNO-1;
+       if(right_mark > lim_max) right_mark = lim_max;
+       limits++; /* prepare for next row */
+    } else
+       lim_max = COLNO-1;
+
+    while (left <= right_mark) {
+       right_edge = right_ptrs[row][left];
+       if(right_edge > lim_max) right_edge = lim_max;
+
+       if (!is_clear(row,left)) {
+           /*
+            * Jump to the far side of a stone wall.  We can set all
+            * the points in between as seen.
+            *
+            * If the right edge goes beyond the right mark, check to see
+            * how much we can see.
+            */
+           if (right_edge > right_mark) {
+               /*
+                * If the mark on the previous row was a clear position,
+                * the odds are that we can actually see part of the wall
+                * beyond the mark on this row.  If so, then see one beyond
+                * the mark.  Otherwise don't.  This is a kludge so corners
+                * with an adjacent doorway show up in nethack.
+                */
+               right_edge = is_clear(row-step,right_mark) ?
+                                                   right_mark+1 : right_mark;
+           }
+           if(vis_func) {
+               for (i = left; i <= right_edge; i++) (*vis_func)(i, row, varg);
+           } else {
+               for (i = left; i <= right_edge; i++) set_cs(rowp,i);
+               set_min(left);      set_max(right_edge);
+           }
+           left = right_edge + 1; /* no limit check necessary */
+           continue;
+       }
+
+       /* No checking needed if our left side is the start column. */
+       if (left != start_col) {
+           /*
+            * Find the left side.  Move right until we can see it or we run
+            * into a wall.
+            */
+           for (; left <= right_edge; left++) {
+               if (step < 0) {
+                   q1_path(start_row,start_col,row,left,rside1);
+               } else {
+                   q4_path(start_row,start_col,row,left,rside1);
+               }
+rside1:                                        /* used if q?_path() is a macro */
+               if (result) break;
+           }
+
+           /*
+            * Check for boundary conditions.  We *need* check (2) to break
+            * an infinite loop where:
+            *
+            *          left == right_edge == right_mark == lim_max.
+            *
+            */
+           if (left > lim_max) return; /* check (1) */
+           if (left == lim_max) {      /* check (2) */
+               if(vis_func) (*vis_func)(lim_max, row, varg);
+               else {
+                   set_cs(rowp,lim_max);
+                   set_max(lim_max);
+               }
+               return;
+           }
+           /*
+            * Check if we can see any spots in the opening.  We might
+            * (left == right_edge) or might not (left == right_edge+1) have
+            * been able to see the far wall.  Make sure we *can* see the
+            * wall (remember, we can see the spot above/below this one)
+            * by backing up.
+            */
+           if (left >= right_edge) {
+               left = right_edge;      /* for the case left == right_edge+1 */
+               continue;
+           }
+       }
+
+       /*
+        * Find the right side.  If the marker from the previous row is
+        * closer than the edge on this row, then we have to check
+        * how far we can see around the corner (under the overhang).  Stop
+        * at the first non-visible spot or we actually hit the far wall.
+        *
+        * Otherwise, we know we can see the right edge of the current row.
+        *
+        * This must be a strict less than so that we can always see a
+        * horizontal wall, even if it is adjacent to us.
+        */
+       if (right_mark < right_edge) {
+           for (right = right_mark; right <= right_edge; right++) {
+               if (step < 0) {
+                   q1_path(start_row,start_col,row,right,rside2);
+               } else {
+                   q4_path(start_row,start_col,row,right,rside2);
+               }
+rside2:                                        /* used if q?_path() is a macro */
+               if (!result) break;
+           }
+           --right;    /* get rid of the last increment */
+       }
+       else
+           right = right_edge;
+
+       /*
+        * We have the range that we want.  Set the bits.  Note that
+        * there is no else --- we no longer handle splinters.
+        */
+       if (left <= right) {
+           /*
+            * An ugly special case.  If you are adjacent to a vertical wall
+            * and it has a break in it, then the right mark is set to be
+            * start_col.  We *want* to be able to see adjacent vertical
+            * walls, so we have to set it back.
+            */
+           if (left == right && left == start_col &&
+                       start_col < (COLNO-1) && !is_clear(row,start_col+1))
+               right = start_col+1;
+
+           if(right > lim_max) right = lim_max;
+           /* set the bits */
+           if(vis_func)
+               for (i = left; i <= right; i++) (*vis_func)(i, row, varg);
+           else {
+               for (i = left; i <= right; i++) set_cs(rowp,i);
+               set_min(left);      set_max(right);
+           }
+
+           /* recursive call for next finger of light */
+           if (deeper) right_side(nrow,left,right,limits);
+           left = right + 1; /* no limit check necessary */
+       }
+    }
+}
+
+
+/*
+ * This routine is the mirror image of right_side().  See right_side() for
+ * extensive comments.
+ */
+STATIC_OVL void
+left_side(row, left_mark, right, limits)
+    int row, left_mark, right;
+    char *limits;
+{
+    int                  left, left_edge, nrow, deeper, result;
+    register int  i;
+    register char *rowp;
+    char         *row_min, *row_max;
+    int                  lim_min;
+
+#ifdef GCC_WARN
+    rowp = row_min = row_max = 0;
+#endif
+    nrow    = row+step;
+    deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
+    if(!vis_func) {
+       rowp    = cs_rows[row];
+       row_min = &cs_left[row];
+       row_max = &cs_right[row];
+    }
+    if(limits) {
+       lim_min = start_col - *limits;
+       if(lim_min < 0) lim_min = 0;
+       if(left_mark < lim_min) left_mark = lim_min;
+       limits++; /* prepare for next row */
+    } else
+       lim_min = 0;
+
+    while (right >= left_mark) {
+       left_edge = left_ptrs[row][right];
+       if(left_edge < lim_min) left_edge = lim_min;
+
+       if (!is_clear(row,right)) {
+           /* Jump to the far side of a stone wall. */
+           if (left_edge < left_mark) {
+               /* Maybe see more (kludge). */
+               left_edge = is_clear(row-step,left_mark) ?
+                                                   left_mark-1 : left_mark;
+           }
+           if(vis_func) {
+               for (i = left_edge; i <= right; i++) (*vis_func)(i, row, varg);
+           } else {
+               for (i = left_edge; i <= right; i++) set_cs(rowp,i);
+               set_min(left_edge); set_max(right);
+           }
+           right = left_edge - 1; /* no limit check necessary */
+           continue;
+       }
+
+       if (right != start_col) {
+           /* Find the right side. */
+           for (; right >= left_edge; right--) {
+               if (step < 0) {
+                   q2_path(start_row,start_col,row,right,lside1);
+               } else {
+                   q3_path(start_row,start_col,row,right,lside1);
+               }
+lside1:                                        /* used if q?_path() is a macro */
+               if (result) break;
+           }
+
+           /* Check for boundary conditions. */
+           if (right < lim_min) return;
+           if (right == lim_min) {
+               if(vis_func) (*vis_func)(lim_min, row, varg);
+               else {
+                   set_cs(rowp,lim_min);
+                   set_min(lim_min);
+               }
+               return;
+           }
+           /* Check if we can see any spots in the opening. */
+           if (right <= left_edge) {
+               right = left_edge;
+               continue;
+           }
+       }
+
+       /* Find the left side. */
+       if (left_mark > left_edge) {
+           for (left = left_mark; left >= left_edge; --left) {
+               if (step < 0) {
+                   q2_path(start_row,start_col,row,left,lside2);
+               } else {
+                   q3_path(start_row,start_col,row,left,lside2);
+               }
+lside2:                                        /* used if q?_path() is a macro */
+               if (!result) break;
+           }
+           left++;     /* get rid of the last decrement */
+       }
+       else
+           left = left_edge;
+
+       if (left <= right) {
+           /* An ugly special case. */
+           if (left == right && right == start_col &&
+                           start_col > 0 && !is_clear(row,start_col-1))
+               left = start_col-1;
+
+           if(left < lim_min) left = lim_min;
+           if(vis_func)
+               for (i = left; i <= right; i++) (*vis_func)(i, row, varg);
+           else {
+               for (i = left; i <= right; i++) set_cs(rowp,i);
+               set_min(left);      set_max(right);
+           }
+
+           /* Recurse */
+           if (deeper) left_side(nrow,left,right,limits);
+           right = left - 1; /* no limit check necessary */
+       }
+    }
+}
+
+
+/*
+ * Calculate all possible visible locations from the given location
+ * (srow,scol).  NOTE this is (y,x)!  Mark the visible locations in the
+ * array provided.
+ */
+STATIC_OVL void
+view_from(srow, scol, loc_cs_rows, left_most, right_most, range, func, arg)
+    int  srow, scol;   /* starting row and column */
+    char **loc_cs_rows;        /* pointers to the rows of the could_see array */
+    char *left_most;   /* min mark on each row */
+    char *right_most;  /* max mark on each row */
+    int range;         /* 0 if unlimited */
+    void FDECL((*func), (int,int,genericptr_t));
+    genericptr_t arg;
+{
+    register int i;            /* loop counter */
+    char         *rowp;                /* optimization for setting could_see */
+    int                 nrow;          /* the next row */
+    int                 left;          /* the left-most visible column */
+    int                 right;         /* the right-most visible column */
+    char        *limits;       /* range limit for next row */
+
+    /* Set globals for q?_path(), left_side(), and right_side() to use. */
+    start_col = scol;
+    start_row = srow;
+    cs_rows   = loc_cs_rows;   /* 'could see' rows */
+    cs_left   = left_most;
+    cs_right  = right_most;
+    vis_func = func;
+    varg = arg;
+
+    /*
+     * Determine extent of sight on the starting row.
+     */
+    if (is_clear(srow,scol)) {
+       left =  left_ptrs[srow][scol];
+       right = right_ptrs[srow][scol];
+    } else {
+       /*
+        * When in stone, you can only see your adjacent squares, unless
+        * you are on an array boundary or a stone/clear boundary.
+        */
+       left  = (!scol) ? 0 :
+               (is_clear(srow,scol-1) ? left_ptrs[srow][scol-1] : scol-1);
+       right = (scol == COLNO-1) ? COLNO-1 :
+               (is_clear(srow,scol+1) ? right_ptrs[srow][scol+1] : scol+1);
+    }
+
+    if(range) {
+       if(range > MAX_RADIUS || range < 1)
+           panic("view_from called with range %d", range);
+       limits = circle_ptr(range) + 1; /* start at next row */
+       if(left < scol - range) left = scol - range;
+       if(right > scol + range) right = scol + range;
+    } else
+       limits = (char*) 0;
+
+    if(func) {
+       for (i = left; i <= right; i++) (*func)(i, srow, arg);
+    } else {
+       /* Row pointer optimization. */
+       rowp = cs_rows[srow];
+
+       /* We know that we can see our row. */
+       for (i = left; i <= right; i++) set_cs(rowp,i);
+       cs_left[srow]  = left;
+       cs_right[srow] = right;
+    }
+
+    /*
+     * Check what could be seen in quadrants.  We need to check for valid
+     * rows here, since we don't do it in the routines right_side() and
+     * left_side() [ugliness to remove extra routine calls].
+     */
+    if ( (nrow = srow+1) < ROWNO ) {   /* move down */
+       step =  1;
+       if (scol < COLNO-1) right_side(nrow, scol, right, limits);
+       if (scol)           left_side (nrow, left,  scol, limits);
+    }
+
+    if ( (nrow = srow-1) >= 0 ) {      /* move up */
+       step = -1;
+       if (scol < COLNO-1) right_side(nrow, scol, right, limits);
+       if (scol)           left_side (nrow, left,  scol, limits);
+    }
+}
+
+#endif /*===== End of algorithm C =====*/
+
+/*
+ * AREA OF EFFECT "ENGINE"
+ *
+ * Calculate all possible visible locations as viewed from the given location
+ * (srow,scol) within the range specified. Perform "func" with (x, y) args and
+ * additional argument "arg" for each square.
+ *
+ * If not centered on the hero, just forward arguments to view_from(); it
+ * will call "func" when necessary.  If the hero is the center, use the
+ * vision matrix and reduce extra work.
+ */
+void
+do_clear_area(scol,srow,range,func,arg)
+    int scol, srow, range;
+    void FDECL((*func), (int,int,genericptr_t));
+    genericptr_t arg;
+{
+       /* If not centered on hero, do the hard work of figuring the area */
+       if (scol != u.ux || srow != u.uy)
+           view_from(srow, scol, (char **)0, (char *)0, (char *)0,
+                                                       range, func, arg);
+       else {
+           register int x;
+           int y, min_x, max_x, max_y, offset;
+           char *limits;
+
+           if (range > MAX_RADIUS || range < 1)
+               panic("do_clear_area:  illegal range %d", range);
+           if(vision_full_recalc)
+               vision_recalc(0);       /* recalc vision if dirty */
+           limits = circle_ptr(range);
+           if ((max_y = (srow + range)) >= ROWNO) max_y = ROWNO-1;
+           if ((y = (srow - range)) < 0) y = 0;
+           for (; y <= max_y; y++) {
+               offset = limits[v_abs(y-srow)];
+               if((min_x = (scol - offset)) < 0) min_x = 0;
+               if((max_x = (scol + offset)) >= COLNO) max_x = COLNO-1;
+               for (x = min_x; x <= max_x; x++)
+                   if (couldsee(x, y))
+                       (*func)(x, y, arg);
+           }
+       }
+}
+
+/*vision.c*/
diff --git a/src/weapon.c b/src/weapon.c
new file mode 100644 (file)
index 0000000..a595df7
--- /dev/null
@@ -0,0 +1,1319 @@
+/*     SCCS Id: @(#)weapon.c   3.4     2002/11/07      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *     This module contains code for calculation of "to hit" and damage
+ *     bonuses for any given weapon used, as well as weapons selection
+ *     code for monsters.
+ */
+#include "hack.h"
+
+/* Categories whose names don't come from OBJ_NAME(objects[type])
+ */
+#define PN_BARE_HANDED                 (-1)    /* includes martial arts */
+#define PN_TWO_WEAPONS                 (-2)
+#define PN_RIDING                      (-3)
+#define PN_POLEARMS                    (-4)
+#define PN_SABER                       (-5)
+#define PN_HAMMER                      (-6)
+#define PN_WHIP                                (-7)
+#define PN_ATTACK_SPELL                        (-8)
+#define PN_HEALING_SPELL               (-9)
+#define PN_DIVINATION_SPELL            (-10)
+#define PN_ENCHANTMENT_SPELL           (-11)
+#define PN_CLERIC_SPELL                        (-12)
+#define PN_ESCAPE_SPELL                        (-13)
+#define PN_MATTER_SPELL                        (-14)
+
+STATIC_DCL void FDECL(give_may_advance_msg, (int));
+
+#ifndef OVLB
+
+STATIC_DCL NEARDATA const short skill_names_indices[];
+STATIC_DCL NEARDATA const char *odd_skill_names[];
+STATIC_DCL NEARDATA const char *barehands_or_martial[];
+
+#else  /* OVLB */
+
+STATIC_VAR NEARDATA const short skill_names_indices[P_NUM_SKILLS] = {
+       0,                DAGGER,         KNIFE,        AXE,
+       PICK_AXE,         SHORT_SWORD,    BROADSWORD,   LONG_SWORD,
+       TWO_HANDED_SWORD, SCIMITAR,       PN_SABER,     CLUB,
+       MACE,             MORNING_STAR,   FLAIL,
+       PN_HAMMER,        QUARTERSTAFF,   PN_POLEARMS,  SPEAR,
+       JAVELIN,          TRIDENT,        LANCE,        BOW,
+       SLING,            CROSSBOW,       DART,
+       SHURIKEN,         BOOMERANG,      PN_WHIP,      UNICORN_HORN,
+       PN_ATTACK_SPELL,     PN_HEALING_SPELL,
+       PN_DIVINATION_SPELL, PN_ENCHANTMENT_SPELL,
+       PN_CLERIC_SPELL,     PN_ESCAPE_SPELL,
+       PN_MATTER_SPELL,
+       PN_BARE_HANDED,   PN_TWO_WEAPONS,
+#ifdef STEED
+       PN_RIDING
+#endif
+};
+
+/* note: entry [0] isn't used */
+STATIC_VAR NEARDATA const char * const odd_skill_names[] = {
+    "no skill",
+    "bare hands",              /* use barehands_or_martial[] instead */
+    "two weapon combat",
+    "riding",
+    "polearms",
+    "saber",
+    "hammer",
+    "whip",
+    "attack spells",
+    "healing spells",
+    "divination spells",
+    "enchantment spells",
+    "clerical spells",
+    "escape spells",
+    "matter spells",
+};
+/* indexed vis `is_martial() */
+STATIC_VAR NEARDATA const char * const barehands_or_martial[] = {
+    "bare handed combat", "martial arts"
+};
+
+STATIC_OVL void
+give_may_advance_msg(skill)
+int skill;
+{
+       You_feel("more confident in your %sskills.",
+               skill == P_NONE ?
+                       "" :
+               skill <= P_LAST_WEAPON ?
+                       "weapon " :
+               skill <= P_LAST_SPELL ?
+                       "spell casting " :
+               "fighting ");
+}
+
+#endif /* OVLB */
+
+STATIC_DCL boolean FDECL(can_advance, (int, BOOLEAN_P));
+STATIC_DCL boolean FDECL(could_advance, (int));
+STATIC_DCL boolean FDECL(peaked_skill, (int));
+STATIC_DCL int FDECL(slots_required, (int));
+
+#ifdef OVL1
+
+STATIC_DCL char *FDECL(skill_level_name, (int,char *));
+STATIC_DCL void FDECL(skill_advance, (int));
+
+#endif /* OVL1 */
+
+#define P_NAME(type) ((skill_names_indices[type] > 0) ? \
+                     OBJ_NAME(objects[skill_names_indices[type]]) : \
+                     (type == P_BARE_HANDED_COMBAT) ? \
+                       barehands_or_martial[martial_bonus()] : \
+                       odd_skill_names[-skill_names_indices[type]])
+
+#ifdef OVLB
+static NEARDATA const char kebabable[] = {
+       S_XORN, S_DRAGON, S_JABBERWOCK, S_NAGA, S_GIANT, '\0'
+};
+
+/*
+ *     hitval returns an integer representing the "to hit" bonuses
+ *     of "otmp" against the monster.
+ */
+int
+hitval(otmp, mon)
+struct obj *otmp;
+struct monst *mon;
+{
+       int     tmp = 0;
+       struct permonst *ptr = mon->data;
+       boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));
+
+       if (Is_weapon)
+               tmp += otmp->spe;
+
+/*     Put weapon specific "to hit" bonuses in below:          */
+       tmp += objects[otmp->otyp].oc_hitbon;
+
+/*     Put weapon vs. monster type "to hit" bonuses in below:  */
+
+       /* Blessed weapons used against undead or demons */
+       if (Is_weapon && otmp->blessed &&
+          (is_demon(ptr) || is_undead(ptr))) tmp += 2;
+
+       if (is_spear(otmp) &&
+          index(kebabable, ptr->mlet)) tmp += 2;
+
+       /* trident is highly effective against swimmers */
+       if (otmp->otyp == TRIDENT && is_swimmer(ptr)) {
+          if (is_pool(mon->mx, mon->my)) tmp += 4;
+          else if (ptr->mlet == S_EEL || ptr->mlet == S_SNAKE) tmp += 2;
+       }
+
+       /* Picks used against xorns and earth elementals */
+       if (is_pick(otmp) &&
+          (passes_walls(ptr) && thick_skinned(ptr))) tmp += 2;
+
+#ifdef INVISIBLE_OBJECTS
+       /* Invisible weapons against monsters who can't see invisible */
+       if (otmp->oinvis && !perceives(ptr)) tmp += 3;
+#endif
+
+       /* Check specially named weapon "to hit" bonuses */
+       if (otmp->oartifact) tmp += spec_abon(otmp, mon);
+
+       return tmp;
+}
+
+/* Historical note: The original versions of Hack used a range of damage
+ * which was similar to, but not identical to the damage used in Advanced
+ * Dungeons and Dragons.  I figured that since it was so close, I may as well
+ * make it exactly the same as AD&D, adding some more weapons in the process.
+ * This has the advantage that it is at least possible that the player would
+ * already know the damage of at least some of the weapons.  This was circa
+ * 1987 and I used the table from Unearthed Arcana until I got tired of typing
+ * them in (leading to something of an imbalance towards weapons early in
+ * alphabetical order).  The data structure still doesn't include fields that
+ * fully allow the appropriate damage to be described (there's no way to say
+ * 3d6 or 1d6+1) so we add on the extra damage in dmgval() if the weapon
+ * doesn't do an exact die of damage.
+ *
+ * Of course new weapons were added later in the development of Nethack.  No
+ * AD&D consistency was kept, but most of these don't exist in AD&D anyway.
+ *
+ * Second edition AD&D came out a few years later; luckily it used the same
+ * table.  As of this writing (1999), third edition is in progress but not
+ * released.  Let's see if the weapon table stays the same.  --KAA
+ * October 2000: It didn't.  Oh, well.
+ */
+
+/*
+ *     dmgval returns an integer representing the damage bonuses
+ *     of "otmp" against the monster.
+ */
+int
+dmgval(otmp, mon)
+struct obj *otmp;
+struct monst *mon;
+{
+       int tmp = 0, otyp = otmp->otyp;
+       struct permonst *ptr = mon->data;
+       boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));
+
+       if (otyp == CREAM_PIE) return 0;
+
+       if (bigmonst(ptr)) {
+           if (objects[otyp].oc_wldam)
+               tmp = rnd(objects[otyp].oc_wldam);
+           switch (otyp) {
+               case IRON_CHAIN:
+               case CROSSBOW_BOLT:
+               case MORNING_STAR:
+               case PARTISAN:
+               case RUNESWORD:
+               case ELVEN_BROADSWORD:
+               case BROADSWORD:        tmp++; break;
+
+               case FLAIL:
+               case RANSEUR:
+               case VOULGE:            tmp += rnd(4); break;
+
+               case ACID_VENOM:
+               case HALBERD:
+               case SPETUM:            tmp += rnd(6); break;
+
+               case BATTLE_AXE:
+               case BARDICHE:
+               case TRIDENT:           tmp += d(2,4); break;
+
+               case TSURUGI:
+               case DWARVISH_MATTOCK:
+               case TWO_HANDED_SWORD:  tmp += d(2,6); break;
+           }
+       } else {
+           if (objects[otyp].oc_wsdam)
+               tmp = rnd(objects[otyp].oc_wsdam);
+           switch (otyp) {
+               case IRON_CHAIN:
+               case CROSSBOW_BOLT:
+               case MACE:
+               case WAR_HAMMER:
+               case FLAIL:
+               case SPETUM:
+               case TRIDENT:           tmp++; break;
+
+               case BATTLE_AXE:
+               case BARDICHE:
+               case BILL_GUISARME:
+               case GUISARME:
+               case LUCERN_HAMMER:
+               case MORNING_STAR:
+               case RANSEUR:
+               case BROADSWORD:
+               case ELVEN_BROADSWORD:
+               case RUNESWORD:
+               case VOULGE:            tmp += rnd(4); break;
+
+               case ACID_VENOM:        tmp += rnd(6); break;
+           }
+       }
+       if (Is_weapon) {
+               tmp += otmp->spe;
+               /* negative enchantment mustn't produce negative damage */
+               if (tmp < 0) tmp = 0;
+       }
+
+       if (objects[otyp].oc_material <= LEATHER && thick_skinned(ptr))
+               /* thick skinned/scaled creatures don't feel it */
+               tmp = 0;
+       if (ptr == &mons[PM_SHADE] && objects[otyp].oc_material != SILVER)
+               tmp = 0;
+
+       /* "very heavy iron ball"; weight increase is in increments of 160 */
+       if (otyp == HEAVY_IRON_BALL && tmp > 0) {
+           int wt = (int)objects[HEAVY_IRON_BALL].oc_weight;
+
+           if ((int)otmp->owt > wt) {
+               wt = ((int)otmp->owt - wt) / 160;
+               tmp += rnd(4 * wt);
+               if (tmp > 25) tmp = 25; /* objects[].oc_wldam */
+           }
+       }
+
+/*     Put weapon vs. monster type damage bonuses in below:    */
+       if (Is_weapon || otmp->oclass == GEM_CLASS ||
+               otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) {
+           int bonus = 0;
+
+           if (otmp->blessed && (is_undead(ptr) || is_demon(ptr)))
+               bonus += rnd(4);
+           if (is_axe(otmp) && is_wooden(ptr))
+               bonus += rnd(4);
+           if (objects[otyp].oc_material == SILVER && hates_silver(ptr))
+               bonus += rnd(20);
+
+           /* if the weapon is going to get a double damage bonus, adjust
+              this bonus so that effectively it's added after the doubling */
+           if (bonus > 1 && otmp->oartifact && spec_dbon(otmp, mon, 25) >= 25)
+               bonus = (bonus + 1) / 2;
+
+           tmp += bonus;
+       }
+
+       if (tmp > 0) {
+               /* It's debateable whether a rusted blunt instrument
+                  should do less damage than a pristine one, since
+                  it will hit with essentially the same impact, but
+                  there ought to some penalty for using damaged gear
+                  so always subtract erosion even for blunt weapons. */
+               tmp -= greatest_erosion(otmp);
+               if (tmp < 1) tmp = 1;
+       }
+
+       return(tmp);
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+STATIC_DCL struct obj *FDECL(oselect, (struct monst *,int));
+#define Oselect(x)     if ((otmp = oselect(mtmp, x)) != 0) return(otmp);
+
+STATIC_OVL struct obj *
+oselect(mtmp, x)
+struct monst *mtmp;
+int x;
+{
+       struct obj *otmp;
+
+       for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
+           if (otmp->otyp == x &&
+                   /* never select non-cockatrice corpses */
+                   !((x == CORPSE || x == EGG) &&
+                       !touch_petrifies(&mons[otmp->corpsenm])) &&
+                   (!otmp->oartifact || touch_artifact(otmp,mtmp)))
+               return otmp;
+       }
+       return (struct obj *)0;
+}
+
+static NEARDATA const int rwep[] =
+{      DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR,
+       JAVELIN, SHURIKEN, YA, SILVER_ARROW, ELVEN_ARROW, ARROW,
+       ORCISH_ARROW, CROSSBOW_BOLT, SILVER_DAGGER, ELVEN_DAGGER, DAGGER,
+       ORCISH_DAGGER, KNIFE, FLINT, ROCK, LOADSTONE, LUCKSTONE, DART,
+       /* BOOMERANG, */ CREAM_PIE
+       /* note: CREAM_PIE should NOT be #ifdef KOPS */
+};
+
+static NEARDATA const int pwep[] =
+{      HALBERD, BARDICHE, SPETUM, BILL_GUISARME, VOULGE, RANSEUR, GUISARME,
+       GLAIVE, LUCERN_HAMMER, BEC_DE_CORBIN, FAUCHARD, PARTISAN, LANCE
+};
+
+static struct obj *propellor;
+
+struct obj *
+select_rwep(mtmp)      /* select a ranged weapon for the monster */
+register struct monst *mtmp;
+{
+       register struct obj *otmp;
+       int i;
+
+#ifdef KOPS
+       char mlet = mtmp->data->mlet;
+#endif
+
+       propellor = &zeroobj;
+       Oselect(EGG); /* cockatrice egg */
+#ifdef KOPS
+       if(mlet == S_KOP)       /* pies are first choice for Kops */
+           Oselect(CREAM_PIE);
+#endif
+       if(throws_rocks(mtmp->data))    /* ...boulders for giants */
+           Oselect(BOULDER);
+
+       /* Select polearms first; they do more damage and aren't expendable */
+       /* The limit of 13 here is based on the monster polearm range limit
+        * (defined as 5 in mthrowu.c).  5 corresponds to a distance of 2 in
+        * one direction and 1 in another; one space beyond that would be 3 in
+        * one direction and 2 in another; 3^2+2^2=13.
+        */
+       if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 13 && couldsee(mtmp->mx, mtmp->my)) {
+           for (i = 0; i < SIZE(pwep); i++) {
+               /* Only strong monsters can wield big (esp. long) weapons.
+                * Big weapon is basically the same as bimanual.
+                * All monsters can wield the remaining weapons.
+                */
+               if (((strongmonst(mtmp->data) && (mtmp->misc_worn_check & W_ARMS) == 0)
+                       || !objects[pwep[i]].oc_bimanual) &&
+                   (objects[pwep[i]].oc_material != SILVER
+                       || !hates_silver(mtmp->data))) {
+                   if ((otmp = oselect(mtmp, pwep[i])) != 0) {
+                       propellor = otmp; /* force the monster to wield it */
+                       return otmp;
+                   }
+               }
+           }
+       }
+
+       /*
+        * other than these two specific cases, always select the
+        * most potent ranged weapon to hand.
+        */
+       for (i = 0; i < SIZE(rwep); i++) {
+           int prop;
+
+           /* shooting gems from slings; this goes just before the darts */
+           /* (shooting rocks is already handled via the rwep[] ordering) */
+           if (rwep[i] == DART && !likes_gems(mtmp->data) &&
+                   m_carrying(mtmp, SLING)) {          /* propellor */
+               for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+                   if (otmp->oclass == GEM_CLASS &&
+                           (otmp->otyp != LOADSTONE || !otmp->cursed)) {
+                       propellor = m_carrying(mtmp, SLING);
+                       return otmp;
+                   }
+           }
+
+               /* KMH -- This belongs here so darts will work */
+           propellor = &zeroobj;
+
+           prop = (objects[rwep[i]]).oc_skill;
+           if (prop < 0) {
+               switch (-prop) {
+               case P_BOW:
+                 propellor = (oselect(mtmp, YUMI));
+                 if (!propellor) propellor = (oselect(mtmp, ELVEN_BOW));
+                 if (!propellor) propellor = (oselect(mtmp, BOW));
+                 if (!propellor) propellor = (oselect(mtmp, ORCISH_BOW));
+                 break;
+               case P_SLING:
+                 propellor = (oselect(mtmp, SLING));
+                 break;
+               case P_CROSSBOW:
+                 propellor = (oselect(mtmp, CROSSBOW));
+               }
+               if ((otmp = MON_WEP(mtmp)) && otmp->cursed && otmp != propellor
+                               && mtmp->weapon_check == NO_WEAPON_WANTED)
+                       propellor = 0;
+           }
+           /* propellor = obj, propellor to use
+            * propellor = &zeroobj, doesn't need a propellor
+            * propellor = 0, needed one and didn't have one
+            */
+           if (propellor != 0) {
+               /* Note: cannot use m_carrying for loadstones, since it will
+                * always select the first object of a type, and maybe the
+                * monster is carrying two but only the first is unthrowable.
+                */
+               if (rwep[i] != LOADSTONE) {
+                       /* Don't throw a cursed weapon-in-hand or an artifact */
+                       if ((otmp = oselect(mtmp, rwep[i])) && !otmp->oartifact
+                           && (!otmp->cursed || otmp != MON_WEP(mtmp)))
+                               return(otmp);
+               } else for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) {
+                   if (otmp->otyp == LOADSTONE && !otmp->cursed)
+                       return otmp;
+               }
+           }
+         }
+
+       /* failure */
+       return (struct obj *)0;
+}
+
+/* Weapons in order of preference */
+static const NEARDATA short hwep[] = {
+         CORPSE,  /* cockatrice corpse */
+         TSURUGI, RUNESWORD, DWARVISH_MATTOCK, TWO_HANDED_SWORD, BATTLE_AXE,
+         KATANA, UNICORN_HORN, CRYSKNIFE, TRIDENT, LONG_SWORD,
+         ELVEN_BROADSWORD, BROADSWORD, SCIMITAR, SILVER_SABER,
+         MORNING_STAR, ELVEN_SHORT_SWORD, DWARVISH_SHORT_SWORD, SHORT_SWORD,
+         ORCISH_SHORT_SWORD, MACE, AXE, DWARVISH_SPEAR, SILVER_SPEAR,
+         ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, FLAIL, BULLWHIP, QUARTERSTAFF,
+         JAVELIN, AKLYS, CLUB, PICK_AXE,
+#ifdef KOPS
+         RUBBER_HOSE,
+#endif /* KOPS */
+         WAR_HAMMER, SILVER_DAGGER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER,
+         ATHAME, SCALPEL, KNIFE, WORM_TOOTH
+       };
+
+struct obj *
+select_hwep(mtmp)      /* select a hand to hand weapon for the monster */
+register struct monst *mtmp;
+{
+       register struct obj *otmp;
+       register int i;
+       boolean strong = strongmonst(mtmp->data);
+       boolean wearing_shield = (mtmp->misc_worn_check & W_ARMS) != 0;
+
+       /* prefer artifacts to everything else */
+       for(otmp=mtmp->minvent; otmp; otmp = otmp->nobj) {
+               if (otmp->oclass == WEAPON_CLASS
+                       && otmp->oartifact && touch_artifact(otmp,mtmp)
+                       && ((strong && !wearing_shield)
+                           || !objects[otmp->otyp].oc_bimanual))
+                   return otmp;
+       }
+
+       if(is_giant(mtmp->data))        /* giants just love to use clubs */
+           Oselect(CLUB);
+
+       /* only strong monsters can wield big (esp. long) weapons */
+       /* big weapon is basically the same as bimanual */
+       /* all monsters can wield the remaining weapons */
+       for (i = 0; i < SIZE(hwep); i++) {
+           if (hwep[i] == CORPSE && !(mtmp->misc_worn_check & W_ARMG))
+               continue;
+           if (((strong && !wearing_shield)
+                       || !objects[hwep[i]].oc_bimanual) &&
+                   (objects[hwep[i]].oc_material != SILVER
+                       || !hates_silver(mtmp->data)))
+               Oselect(hwep[i]);
+       }
+
+       /* failure */
+       return (struct obj *)0;
+}
+
+/* Called after polymorphing a monster, robbing it, etc....  Monsters
+ * otherwise never unwield stuff on their own.  Might print message.
+ */
+void
+possibly_unwield(mon, polyspot)
+struct monst *mon;
+boolean polyspot;
+{
+       struct obj *obj, *mw_tmp;
+
+       if (!(mw_tmp = MON_WEP(mon)))
+               return;
+       for (obj = mon->minvent; obj; obj = obj->nobj)
+               if (obj == mw_tmp) break;
+       if (!obj) { /* The weapon was stolen or destroyed */
+               MON_NOWEP(mon);
+               mon->weapon_check = NEED_WEAPON;
+               return;
+       }
+       if (!attacktype(mon->data, AT_WEAP)) {
+               setmnotwielded(mon, mw_tmp);
+               MON_NOWEP(mon);
+               mon->weapon_check = NO_WEAPON_WANTED;
+               obj_extract_self(obj);
+               if (cansee(mon->mx, mon->my)) {
+                   pline("%s drops %s.", Monnam(mon),
+                         distant_name(obj, doname));
+                   newsym(mon->mx, mon->my);
+               }
+               /* might be dropping object into water or lava */
+               if (!flooreffects(obj, mon->mx, mon->my, "drop")) {
+                   if (polyspot) bypass_obj(obj);
+                   place_object(obj, mon->mx, mon->my);
+                   stackobj(obj);
+               }
+               return;
+       }
+       /* The remaining case where there is a change is where a monster
+        * is polymorphed into a stronger/weaker monster with a different
+        * choice of weapons.  This has no parallel for players.  It can
+        * be handled by waiting until mon_wield_item is actually called.
+        * Though the monster still wields the wrong weapon until then,
+        * this is OK since the player can't see it.  (FIXME: Not okay since
+        * probing can reveal it.)
+        * Note that if there is no change, setting the check to NEED_WEAPON
+        * is harmless.
+        * Possible problem: big monster with big cursed weapon gets
+        * polymorphed into little monster.  But it's not quite clear how to
+        * handle this anyway....
+        */
+       if (!(mw_tmp->cursed && mon->weapon_check == NO_WEAPON_WANTED))
+           mon->weapon_check = NEED_WEAPON;
+       return;
+}
+
+/* Let a monster try to wield a weapon, based on mon->weapon_check.
+ * Returns 1 if the monster took time to do it, 0 if it did not.
+ */
+int
+mon_wield_item(mon)
+register struct monst *mon;
+{
+       struct obj *obj;
+
+       /* This case actually should never happen */
+       if (mon->weapon_check == NO_WEAPON_WANTED) return 0;
+       switch(mon->weapon_check) {
+               case NEED_HTH_WEAPON:
+                       obj = select_hwep(mon);
+                       break;
+               case NEED_RANGED_WEAPON:
+                       (void)select_rwep(mon);
+                       obj = propellor;
+                       break;
+               case NEED_PICK_AXE:
+                       obj = m_carrying(mon, PICK_AXE);
+                       /* KMH -- allow other picks */
+                       if (!obj && !which_armor(mon, W_ARMS))
+                           obj = m_carrying(mon, DWARVISH_MATTOCK);
+                       break;
+               case NEED_AXE:
+                       /* currently, only 2 types of axe */
+                       obj = m_carrying(mon, BATTLE_AXE);
+                       if (!obj || which_armor(mon, W_ARMS))
+                           obj = m_carrying(mon, AXE);
+                       break;
+               case NEED_PICK_OR_AXE:
+                       /* prefer pick for fewer switches on most levels */
+                       obj = m_carrying(mon, DWARVISH_MATTOCK);
+                       if (!obj) obj = m_carrying(mon, BATTLE_AXE);
+                       if (!obj || which_armor(mon, W_ARMS)) {
+                           obj = m_carrying(mon, PICK_AXE);
+                           if (!obj) obj = m_carrying(mon, AXE);
+                       }
+                       break;
+               default: impossible("weapon_check %d for %s?",
+                               mon->weapon_check, mon_nam(mon));
+                       return 0;
+       }
+       if (obj && obj != &zeroobj) {
+               struct obj *mw_tmp = MON_WEP(mon);
+               if (mw_tmp && mw_tmp->otyp == obj->otyp) {
+               /* already wielding it */
+                       mon->weapon_check = NEED_WEAPON;
+                       return 0;
+               }
+               /* Actually, this isn't necessary--as soon as the monster
+                * wields the weapon, the weapon welds itself, so the monster
+                * can know it's cursed and needn't even bother trying.
+                * Still....
+                */
+               if (mw_tmp && mw_tmp->cursed && mw_tmp->otyp != CORPSE) {
+                   if (canseemon(mon)) {
+                       char welded_buf[BUFSZ];
+                       const char *mon_hand = mbodypart(mon, HAND);
+
+                       if (bimanual(mw_tmp)) mon_hand = makeplural(mon_hand);
+                       Sprintf(welded_buf, "%s welded to %s %s",
+                               otense(mw_tmp, "are"),
+                               mhis(mon), mon_hand);
+
+                       if (obj->otyp == PICK_AXE) {
+                           pline("Since %s weapon%s %s,",
+                                 s_suffix(mon_nam(mon)),
+                                 plur(mw_tmp->quan), welded_buf);
+                           pline("%s cannot wield that %s.",
+                               mon_nam(mon), xname(obj));
+                       } else {
+                           pline("%s tries to wield %s.", Monnam(mon),
+                               doname(obj));
+                           pline("%s %s %s!",
+                                 s_suffix(Monnam(mon)),
+                                 xname(mw_tmp), welded_buf);
+                       }
+                       mw_tmp->bknown = 1;
+                   }
+                   mon->weapon_check = NO_WEAPON_WANTED;
+                   return 1;
+               }
+               mon->mw = obj;          /* wield obj */
+               setmnotwielded(mon, mw_tmp);
+               mon->weapon_check = NEED_WEAPON;
+               if (canseemon(mon)) {
+                   pline("%s wields %s!", Monnam(mon), doname(obj));
+                   if (obj->cursed && obj->otyp != CORPSE) {
+                       pline("%s %s to %s %s!",
+                           Tobjnam(obj, "weld"),
+                           is_plural(obj) ? "themselves" : "itself",
+                           s_suffix(mon_nam(mon)), mbodypart(mon,HAND));
+                       obj->bknown = 1;
+                   }
+               }
+               if (artifact_light(obj) && !obj->lamplit) {
+                   begin_burn(obj, FALSE);
+                   if (canseemon(mon))
+                       pline("%s brilliantly in %s %s!",
+                           Tobjnam(obj, "glow"), 
+                           s_suffix(mon_nam(mon)), mbodypart(mon,HAND));
+               }
+               obj->owornmask = W_WEP;
+               return 1;
+       }
+       mon->weapon_check = NEED_WEAPON;
+       return 0;
+}
+
+int
+abon()         /* attack bonus for strength & dexterity */
+{
+       int sbon;
+       int str = ACURR(A_STR), dex = ACURR(A_DEX);
+
+       if (Upolyd) return(adj_lev(&mons[u.umonnum]) - 3);
+       if (str < 6) sbon = -2;
+       else if (str < 8) sbon = -1;
+       else if (str < 17) sbon = 0;
+       else if (str <= STR18(50)) sbon = 1;    /* up to 18/50 */
+       else if (str < STR18(100)) sbon = 2;
+       else sbon = 3;
+
+/* Game tuning kludge: make it a bit easier for a low level character to hit */
+       sbon += (u.ulevel < 3) ? 1 : 0;
+
+       if (dex < 4) return(sbon-3);
+       else if (dex < 6) return(sbon-2);
+       else if (dex < 8) return(sbon-1);
+       else if (dex < 14) return(sbon);
+       else return(sbon + dex-14);
+}
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+int
+dbon()         /* damage bonus for strength */
+{
+       int str = ACURR(A_STR);
+
+       if (Upolyd) return(0);
+
+       if (str < 6) return(-1);
+       else if (str < 16) return(0);
+       else if (str < 18) return(1);
+       else if (str == 18) return(2);          /* up to 18 */
+       else if (str <= STR18(75)) return(3);           /* up to 18/75 */
+       else if (str <= STR18(90)) return(4);           /* up to 18/90 */
+       else if (str < STR18(100)) return(5);           /* up to 18/99 */
+       else return(6);
+}
+
+
+/* copy the skill level name into the given buffer */
+STATIC_OVL char *
+skill_level_name(skill, buf)
+int skill;
+char *buf;
+{
+    const char *ptr;
+
+    switch (P_SKILL(skill)) {
+       case P_UNSKILLED:    ptr = "Unskilled"; break;
+       case P_BASIC:        ptr = "Basic";     break;
+       case P_SKILLED:      ptr = "Skilled";   break;
+       case P_EXPERT:       ptr = "Expert";    break;
+       /* these are for unarmed combat/martial arts only */
+       case P_MASTER:       ptr = "Master";    break;
+       case P_GRAND_MASTER: ptr = "Grand Master"; break;
+       default:             ptr = "Unknown";   break;
+    }
+    Strcpy(buf, ptr);
+    return buf;
+}
+
+/* return the # of slots required to advance the skill */
+STATIC_OVL int
+slots_required(skill)
+int skill;
+{
+    int tmp = P_SKILL(skill);
+
+    /* The more difficult the training, the more slots it takes.
+     * unskilled -> basic      1
+     * basic -> skilled        2
+     * skilled -> expert       3
+     */
+    if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT)
+       return tmp;
+
+    /* Fewer slots used up for unarmed or martial.
+     * unskilled -> basic      1
+     * basic -> skilled        1
+     * skilled -> expert       2
+     * expert -> master        2
+     * master -> grand master  3
+     */
+    return (tmp + 1) / 2;
+}
+
+/* return true if this skill can be advanced */
+/*ARGSUSED*/
+STATIC_OVL boolean
+can_advance(skill, speedy)
+int skill;
+boolean speedy;
+{
+    return !P_RESTRICTED(skill)
+           && P_SKILL(skill) < P_MAX_SKILL(skill) && (
+#ifdef WIZARD
+           (wizard && speedy) ||
+#endif
+           (P_ADVANCE(skill) >=
+               (unsigned) practice_needed_to_advance(P_SKILL(skill))
+           && u.skills_advanced < P_SKILL_LIMIT
+           && u.weapon_slots >= slots_required(skill)));
+}
+
+/* return true if this skill could be advanced if more slots were available */
+STATIC_OVL boolean
+could_advance(skill)
+int skill;
+{
+    return !P_RESTRICTED(skill)
+           && P_SKILL(skill) < P_MAX_SKILL(skill) && (
+           (P_ADVANCE(skill) >=
+               (unsigned) practice_needed_to_advance(P_SKILL(skill))
+           && u.skills_advanced < P_SKILL_LIMIT));
+}
+
+/* return true if this skill has reached its maximum and there's been enough
+   practice to become eligible for the next step if that had been possible */
+STATIC_OVL boolean
+peaked_skill(skill)
+int skill;
+{
+    return !P_RESTRICTED(skill)
+           && P_SKILL(skill) >= P_MAX_SKILL(skill) && (
+           (P_ADVANCE(skill) >=
+               (unsigned) practice_needed_to_advance(P_SKILL(skill))));
+}
+
+STATIC_OVL void
+skill_advance(skill)
+int skill;
+{
+    u.weapon_slots -= slots_required(skill);
+    P_SKILL(skill)++;
+    u.skill_record[u.skills_advanced++] = skill;
+    /* subtly change the advance message to indicate no more advancement */
+    You("are now %s skilled in %s.",
+       P_SKILL(skill) >= P_MAX_SKILL(skill) ? "most" : "more",
+       P_NAME(skill));
+}
+
+const static struct skill_range {
+       short first, last;
+       const char *name;
+} skill_ranges[] = {
+    { P_FIRST_H_TO_H, P_LAST_H_TO_H, "Fighting Skills" },
+    { P_FIRST_WEAPON, P_LAST_WEAPON, "Weapon Skills" },
+    { P_FIRST_SPELL,  P_LAST_SPELL,  "Spellcasting Skills" },
+};
+
+/*
+ * The `#enhance' extended command.  What we _really_ would like is
+ * to keep being able to pick things to advance until we couldn't any
+ * more.  This is currently not possible -- the menu code has no way
+ * to call us back for instant action.  Even if it did, we would also need
+ * to be able to update the menu since selecting one item could make
+ * others unselectable.
+ */
+int
+enhance_weapon_skill()
+{
+    int pass, i, n, len, longest,
+       to_advance, eventually_advance, maxxed_cnt;
+    char buf[BUFSZ], sklnambuf[BUFSZ];
+    const char *prefix;
+    menu_item *selected;
+    anything any;
+    winid win;
+    boolean speedy = FALSE;
+
+#ifdef WIZARD
+       if (wizard && yn("Advance skills without practice?") == 'y')
+           speedy = TRUE;
+#endif
+
+       do {
+           /* find longest available skill name, count those that can advance */
+           to_advance = eventually_advance = maxxed_cnt = 0;
+           for (longest = 0, i = 0; i < P_NUM_SKILLS; i++) {
+               if (P_RESTRICTED(i)) continue;
+               if ((len = strlen(P_NAME(i))) > longest)
+                   longest = len;
+               if (can_advance(i, speedy)) to_advance++;
+               else if (could_advance(i)) eventually_advance++;
+               else if (peaked_skill(i)) maxxed_cnt++;
+           }
+
+           win = create_nhwindow(NHW_MENU);
+           start_menu(win);
+
+           /* start with a legend if any entries will be annotated
+              with "*" or "#" below */
+           if (eventually_advance > 0 || maxxed_cnt > 0) {
+               any.a_void = 0;
+               if (eventually_advance > 0) {
+                   Sprintf(buf,
+                           "(Skill%s flagged by \"*\" may be enhanced %s.)",
+                           plur(eventually_advance),
+                           (u.ulevel < MAXULEV) ?
+                               "when you're more experienced" :
+                               "if skill slots become available");
+                   add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                            buf, MENU_UNSELECTED);
+               }
+               if (maxxed_cnt > 0) {
+                   Sprintf(buf,
+                 "(Skill%s flagged by \"#\" cannot be enhanced any further.)",
+                           plur(maxxed_cnt));
+                   add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                            buf, MENU_UNSELECTED);
+               }
+               add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                            "", MENU_UNSELECTED);
+           }
+
+           /* List the skills, making ones that could be advanced
+              selectable.  List the miscellaneous skills first.
+              Possible future enhancement:  list spell skills before
+              weapon skills for spellcaster roles. */
+         for (pass = 0; pass < SIZE(skill_ranges); pass++)
+           for (i = skill_ranges[pass].first;
+                i <= skill_ranges[pass].last; i++) {
+               /* Print headings for skill types */
+               any.a_void = 0;
+               if (i == skill_ranges[pass].first)
+                   add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
+                            skill_ranges[pass].name, MENU_UNSELECTED);
+
+               if (P_RESTRICTED(i)) continue;
+               /*
+                * Sigh, this assumes a monospaced font unless
+                * iflags.menu_tab_sep is set in which case it puts
+                * tabs between columns.
+                * The 12 is the longest skill level name.
+                * The "    " is room for a selection letter and dash, "a - ".
+                */
+               if (can_advance(i, speedy))
+                   prefix = "";        /* will be preceded by menu choice */
+               else if (could_advance(i))
+                   prefix = "  * ";
+               else if (peaked_skill(i))
+                   prefix = "  # ";
+               else
+                   prefix = (to_advance + eventually_advance +
+                               maxxed_cnt > 0) ? "    " : "";
+               (void) skill_level_name(i, sklnambuf);
+#ifdef WIZARD
+               if (wizard) {
+                   if (!iflags.menu_tab_sep)
+                       Sprintf(buf, " %s%-*s %-12s %5d(%4d)",
+                           prefix, longest, P_NAME(i), sklnambuf,
+                           P_ADVANCE(i),
+                           practice_needed_to_advance(P_SKILL(i)));
+                   else
+                       Sprintf(buf, " %s%s\t%s\t%5d(%4d)",
+                           prefix, P_NAME(i), sklnambuf,
+                           P_ADVANCE(i),
+                           practice_needed_to_advance(P_SKILL(i)));
+                } else
+#endif
+               {
+                   if (!iflags.menu_tab_sep)
+                       Sprintf(buf, " %s %-*s [%s]",
+                           prefix, longest, P_NAME(i), sklnambuf);
+                   else
+                       Sprintf(buf, " %s%s\t[%s]",
+                           prefix, P_NAME(i), sklnambuf);
+               }
+               any.a_int = can_advance(i, speedy) ? i+1 : 0;
+               add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                        buf, MENU_UNSELECTED);
+           }
+
+           Strcpy(buf, (to_advance > 0) ? "Pick a skill to advance:" :
+                                          "Current skills:");
+#ifdef WIZARD
+           if (wizard && !speedy)
+               Sprintf(eos(buf), "  (%d slot%s available)",
+                       u.weapon_slots, plur(u.weapon_slots));
+#endif
+           end_menu(win, buf);
+           n = select_menu(win, to_advance ? PICK_ONE : PICK_NONE, &selected);
+           destroy_nhwindow(win);
+           if (n > 0) {
+               n = selected[0].item.a_int - 1; /* get item selected */
+               free((genericptr_t)selected);
+               skill_advance(n);
+               /* check for more skills able to advance, if so then .. */
+               for (n = i = 0; i < P_NUM_SKILLS; i++) {
+                   if (can_advance(i, speedy)) {
+                       if (!speedy) You_feel("you could be more dangerous!");
+                       n++;
+                       break;
+                   }
+               }
+           }
+       } while (speedy && n > 0);
+       return 0;
+}
+
+/*
+ * Change from restricted to unrestricted, allowing P_BASIC as max.  This
+ * function may be called with with P_NONE.  Used in pray.c.
+ */
+void
+unrestrict_weapon_skill(skill)
+int skill;
+{
+    if (skill < P_NUM_SKILLS && P_RESTRICTED(skill)) {
+       P_SKILL(skill) = P_UNSKILLED;
+       P_MAX_SKILL(skill) = P_BASIC;
+       P_ADVANCE(skill) = 0;
+    }
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+void
+use_skill(skill,degree)
+int skill;
+int degree;
+{
+    boolean advance_before;
+
+    if (skill != P_NONE && !P_RESTRICTED(skill)) {
+       advance_before = can_advance(skill, FALSE);
+       P_ADVANCE(skill)+=degree;
+       if (!advance_before && can_advance(skill, FALSE))
+           give_may_advance_msg(skill);
+    }
+}
+
+void
+add_weapon_skill(n)
+int n; /* number of slots to gain; normally one */
+{
+    int i, before, after;
+
+    for (i = 0, before = 0; i < P_NUM_SKILLS; i++)
+       if (can_advance(i, FALSE)) before++;
+    u.weapon_slots += n;
+    for (i = 0, after = 0; i < P_NUM_SKILLS; i++)
+       if (can_advance(i, FALSE)) after++;
+    if (before < after)
+       give_may_advance_msg(P_NONE);
+}
+
+void
+lose_weapon_skill(n)
+int n; /* number of slots to lose; normally one */
+{
+    int skill;
+
+    while (--n >= 0) {
+       /* deduct first from unused slots, then from last placed slot, if any */
+       if (u.weapon_slots) {
+           u.weapon_slots--;
+       } else if (u.skills_advanced) {
+           skill = u.skill_record[--u.skills_advanced];
+           if (P_SKILL(skill) <= P_UNSKILLED)
+               panic("lose_weapon_skill (%d)", skill);
+           P_SKILL(skill)--;   /* drop skill one level */
+           /* Lost skill might have taken more than one slot; refund rest. */
+           u.weapon_slots = slots_required(skill) - 1;
+           /* It might now be possible to advance some other pending
+              skill by using the refunded slots, but giving a message
+              to that effect would seem pretty confusing.... */
+       }
+    }
+}
+
+int
+weapon_type(obj)
+struct obj *obj;
+{
+       /* KMH -- now uses the object table */
+       int type;
+
+       if (!obj)
+               /* Not using a weapon */
+               return (P_BARE_HANDED_COMBAT);
+       if (obj->oclass != WEAPON_CLASS && obj->oclass != TOOL_CLASS &&
+           obj->oclass != GEM_CLASS)
+               /* Not a weapon, weapon-tool, or ammo */
+               return (P_NONE);
+       type = objects[obj->otyp].oc_skill;
+       return ((type < 0) ? -type : type);
+}
+
+int
+uwep_skill_type()
+{
+       if (u.twoweap)
+               return P_TWO_WEAPON_COMBAT;
+       return weapon_type(uwep);
+}
+
+/*
+ * Return hit bonus/penalty based on skill of weapon.
+ * Treat restricted weapons as unskilled.
+ */
+int
+weapon_hit_bonus(weapon)
+struct obj *weapon;
+{
+    int type, wep_type, skill, bonus = 0;
+    static const char bad_skill[] = "weapon_hit_bonus: bad skill %d";
+
+    wep_type = weapon_type(weapon);
+    /* use two weapon skill only if attacking with one of the wielded weapons */
+    type = (u.twoweap && (weapon == uwep || weapon == uswapwep)) ?
+           P_TWO_WEAPON_COMBAT : wep_type;
+    if (type == P_NONE) {
+       bonus = 0;
+    } else if (type <= P_LAST_WEAPON) {
+       switch (P_SKILL(type)) {
+           default: impossible(bad_skill, P_SKILL(type)); /* fall through */
+           case P_ISRESTRICTED:
+           case P_UNSKILLED:   bonus = -4; break;
+           case P_BASIC:       bonus =  0; break;
+           case P_SKILLED:     bonus =  2; break;
+           case P_EXPERT:      bonus =  3; break;
+       }
+    } else if (type == P_TWO_WEAPON_COMBAT) {
+       skill = P_SKILL(P_TWO_WEAPON_COMBAT);
+       if (P_SKILL(wep_type) < skill) skill = P_SKILL(wep_type);
+       switch (skill) {
+           default: impossible(bad_skill, skill); /* fall through */
+           case P_ISRESTRICTED:
+           case P_UNSKILLED:   bonus = -9; break;
+           case P_BASIC:       bonus = -7; break;
+           case P_SKILLED:     bonus = -5; break;
+           case P_EXPERT:      bonus = -3; break;
+       }
+    } else if (type == P_BARE_HANDED_COMBAT) {
+       /*
+        *             b.h.  m.a.
+        *      unskl:  +1   n/a
+        *      basic:  +1    +3
+        *      skild:  +2    +4
+        *      exprt:  +2    +5
+        *      mastr:  +3    +6
+        *      grand:  +3    +7
+        */
+       bonus = P_SKILL(type);
+       bonus = max(bonus,P_UNSKILLED) - 1;     /* unskilled => 0 */
+       bonus = ((bonus + 2) * (martial_bonus() ? 2 : 1)) / 2;
+    }
+
+#ifdef STEED
+       /* KMH -- It's harder to hit while you are riding */
+       if (u.usteed) {
+               switch (P_SKILL(P_RIDING)) {
+                   case P_ISRESTRICTED:
+                   case P_UNSKILLED:   bonus -= 2; break;
+                   case P_BASIC:       bonus -= 1; break;
+                   case P_SKILLED:     break;
+                   case P_EXPERT:      break;
+               }
+               if (u.twoweap) bonus -= 2;
+       }
+#endif
+
+    return bonus;
+}
+
+/*
+ * Return damage bonus/penalty based on skill of weapon.
+ * Treat restricted weapons as unskilled.
+ */
+int
+weapon_dam_bonus(weapon)
+struct obj *weapon;
+{
+    int type, wep_type, skill, bonus = 0;
+
+    wep_type = weapon_type(weapon);
+    /* use two weapon skill only if attacking with one of the wielded weapons */
+    type = (u.twoweap && (weapon == uwep || weapon == uswapwep)) ?
+           P_TWO_WEAPON_COMBAT : wep_type;
+    if (type == P_NONE) {
+       bonus = 0;
+    } else if (type <= P_LAST_WEAPON) {
+       switch (P_SKILL(type)) {
+           default: impossible("weapon_dam_bonus: bad skill %d",P_SKILL(type));
+                    /* fall through */
+           case P_ISRESTRICTED:
+           case P_UNSKILLED:   bonus = -2; break;
+           case P_BASIC:       bonus =  0; break;
+           case P_SKILLED:     bonus =  1; break;
+           case P_EXPERT:      bonus =  2; break;
+       }
+    } else if (type == P_TWO_WEAPON_COMBAT) {
+       skill = P_SKILL(P_TWO_WEAPON_COMBAT);
+       if (P_SKILL(wep_type) < skill) skill = P_SKILL(wep_type);
+       switch (skill) {
+           default:
+           case P_ISRESTRICTED:
+           case P_UNSKILLED:   bonus = -3; break;
+           case P_BASIC:       bonus = -1; break;
+           case P_SKILLED:     bonus = 0; break;
+           case P_EXPERT:      bonus = 1; break;
+       }
+    } else if (type == P_BARE_HANDED_COMBAT) {
+       /*
+        *             b.h.  m.a.
+        *      unskl:   0   n/a
+        *      basic:  +1    +3
+        *      skild:  +1    +4
+        *      exprt:  +2    +6
+        *      mastr:  +2    +7
+        *      grand:  +3    +9
+        */
+       bonus = P_SKILL(type);
+       bonus = max(bonus,P_UNSKILLED) - 1;     /* unskilled => 0 */
+       bonus = ((bonus + 1) * (martial_bonus() ? 3 : 1)) / 2;
+    }
+
+#ifdef STEED
+       /* KMH -- Riding gives some thrusting damage */
+       if (u.usteed && type != P_TWO_WEAPON_COMBAT) {
+               switch (P_SKILL(P_RIDING)) {
+                   case P_ISRESTRICTED:
+                   case P_UNSKILLED:   break;
+                   case P_BASIC:       break;
+                   case P_SKILLED:     bonus += 1; break;
+                   case P_EXPERT:      bonus += 2; break;
+               }
+       }
+#endif
+
+    return bonus;
+}
+
+/*
+ * Initialize weapon skill array for the game.  Start by setting all
+ * skills to restricted, then set the skill for every weapon the
+ * hero is holding, finally reading the given array that sets
+ * maximums.
+ */
+void
+skill_init(class_skill)
+const struct def_skill *class_skill;
+{
+       struct obj *obj;
+       int skmax, skill;
+
+       /* initialize skill array; by default, everything is restricted */
+       for (skill = 0; skill < P_NUM_SKILLS; skill++) {
+           P_SKILL(skill) = P_ISRESTRICTED;
+           P_MAX_SKILL(skill) = P_ISRESTRICTED;
+           P_ADVANCE(skill) = 0;
+       }
+
+       /* Set skill for all weapons in inventory to be basic */
+       for (obj = invent; obj; obj = obj->nobj) {
+           skill = weapon_type(obj);
+           if (skill != P_NONE)
+               P_SKILL(skill) = P_BASIC;
+       }
+
+       /* set skills for magic */
+       if (Role_if(PM_HEALER) || Role_if(PM_MONK)) {
+               P_SKILL(P_HEALING_SPELL) = P_BASIC;
+       } else if (Role_if(PM_PRIEST)) {
+               P_SKILL(P_CLERIC_SPELL) = P_BASIC;
+       } else if (Role_if(PM_WIZARD)) {
+               P_SKILL(P_ATTACK_SPELL) = P_BASIC;
+               P_SKILL(P_ENCHANTMENT_SPELL) = P_BASIC;
+       }
+
+       /* walk through array to set skill maximums */
+       for (; class_skill->skill != P_NONE; class_skill++) {
+           skmax = class_skill->skmax;
+           skill = class_skill->skill;
+
+           P_MAX_SKILL(skill) = skmax;
+           if (P_SKILL(skill) == P_ISRESTRICTED)       /* skill pre-set */
+               P_SKILL(skill) = P_UNSKILLED;
+       }
+
+       /* High potential fighters already know how to use their hands. */
+       if (P_MAX_SKILL(P_BARE_HANDED_COMBAT) > P_EXPERT)
+           P_SKILL(P_BARE_HANDED_COMBAT) = P_BASIC;
+
+       /* Roles that start with a horse know how to ride it */
+#ifdef STEED
+       if (urole.petnum == PM_PONY)
+           P_SKILL(P_RIDING) = P_BASIC;
+#endif
+
+       /*
+        * Make sure we haven't missed setting the max on a skill
+        * & set advance
+        */
+       for (skill = 0; skill < P_NUM_SKILLS; skill++) {
+           if (!P_RESTRICTED(skill)) {
+               if (P_MAX_SKILL(skill) < P_SKILL(skill)) {
+                   impossible("skill_init: curr > max: %s", P_NAME(skill));
+                   P_MAX_SKILL(skill) = P_SKILL(skill);
+               }
+               P_ADVANCE(skill) = practice_needed_to_advance(P_SKILL(skill)-1);
+           }
+       }
+}
+
+void
+setmnotwielded(mon,obj)
+register struct monst *mon;
+register struct obj *obj;
+{
+    if (!obj) return;
+    if (artifact_light(obj) && obj->lamplit) {
+       end_burn(obj, FALSE);
+       if (canseemon(mon))
+           pline("%s in %s %s %s glowing.", The(xname(obj)),
+                 s_suffix(mon_nam(mon)), mbodypart(mon,HAND),
+                 otense(obj, "stop"));
+    }
+    obj->owornmask &= ~W_WEP;
+}
+
+#endif /* OVLB */
+
+/*weapon.c*/
diff --git a/src/were.c b/src/were.c
new file mode 100644 (file)
index 0000000..486fc03
--- /dev/null
@@ -0,0 +1,165 @@
+/*     SCCS Id: @(#)were.c     3.4     2002/11/07      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+#ifdef OVL0
+
+void
+were_change(mon)
+register struct monst *mon;
+{
+       if (!is_were(mon->data))
+           return;
+
+       if (is_human(mon->data)) {
+           if (!Protection_from_shape_changers &&
+               !rn2(night() ? (flags.moonphase == FULL_MOON ?  3 : 30)
+                            : (flags.moonphase == FULL_MOON ? 10 : 50))) {
+               new_were(mon);          /* change into animal form */
+               if (flags.soundok && !canseemon(mon)) {
+                   const char *howler;
+
+                   switch (monsndx(mon->data)) {
+                   case PM_WEREWOLF:   howler = "wolf";    break;
+                   case PM_WEREJACKAL: howler = "jackal";  break;
+                   default:            howler = (char *)0; break;
+                   }
+                   if (howler)
+                       You_hear("a %s howling at the moon.", howler);
+               }
+           }
+       } else if (!rn2(30) || Protection_from_shape_changers) {
+           new_were(mon);              /* change back into human form */
+       }
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+STATIC_DCL int FDECL(counter_were,(int));
+
+STATIC_OVL int
+counter_were(pm)
+int pm;
+{
+       switch(pm) {
+           case PM_WEREWOLF:         return(PM_HUMAN_WEREWOLF);
+           case PM_HUMAN_WEREWOLF:   return(PM_WEREWOLF);
+           case PM_WEREJACKAL:       return(PM_HUMAN_WEREJACKAL);
+           case PM_HUMAN_WEREJACKAL: return(PM_WEREJACKAL);
+           case PM_WERERAT:          return(PM_HUMAN_WERERAT);
+           case PM_HUMAN_WERERAT:    return(PM_WERERAT);
+           default:                  return(0);
+       }
+}
+
+void
+new_were(mon)
+register struct monst *mon;
+{
+       register int pm;
+
+       pm = counter_were(monsndx(mon->data));
+       if(!pm) {
+           impossible("unknown lycanthrope %s.", mon->data->mname);
+           return;
+       }
+
+       if(canseemon(mon) && !Hallucination)
+           pline("%s changes into a %s.", Monnam(mon),
+                       is_human(&mons[pm]) ? "human" :
+                       mons[pm].mname+4);
+
+       set_mon_data(mon, &mons[pm], 0);
+       if (mon->msleeping || !mon->mcanmove) {
+           /* transformation wakens and/or revitalizes */
+           mon->msleeping = 0;
+           mon->mfrozen = 0;   /* not asleep or paralyzed */
+           mon->mcanmove = 1;
+       }
+       /* regenerate by 1/4 of the lost hit points */
+       mon->mhp += (mon->mhpmax - mon->mhp) / 4;
+       newsym(mon->mx,mon->my);
+       mon_break_armor(mon, FALSE);
+       possibly_unwield(mon, FALSE);
+}
+
+int
+were_summon(ptr,yours,visible,genbuf)  /* were-creature (even you) summons a horde */
+register struct permonst *ptr;
+register boolean yours;
+int *visible;                  /* number of visible helpers created */
+char *genbuf;
+{
+       register int i, typ, pm = monsndx(ptr);
+       register struct monst *mtmp;
+       int total = 0;
+
+       *visible = 0;
+       if(Protection_from_shape_changers && !yours)
+               return 0;
+       for(i = rnd(5); i > 0; i--) {
+          switch(pm) {
+
+               case PM_WERERAT:
+               case PM_HUMAN_WERERAT:
+                       typ = rn2(3) ? PM_SEWER_RAT : rn2(3) ? PM_GIANT_RAT : PM_RABID_RAT ;
+                       if (genbuf) Strcpy(genbuf, "rat");
+                       break;
+               case PM_WEREJACKAL:
+               case PM_HUMAN_WEREJACKAL:
+                       typ = PM_JACKAL;
+                       if (genbuf) Strcpy(genbuf, "jackal");
+                       break;
+               case PM_WEREWOLF:
+               case PM_HUMAN_WEREWOLF:
+                       typ = rn2(5) ? PM_WOLF : PM_WINTER_WOLF ;
+                       if (genbuf) Strcpy(genbuf, "wolf");
+                       break;
+               default:
+                       continue;
+           }
+           mtmp = makemon(&mons[typ], u.ux, u.uy, NO_MM_FLAGS);
+           if (mtmp) {
+               total++;
+               if (canseemon(mtmp)) *visible += 1;
+           }
+           if (yours && mtmp)
+               (void) tamedog(mtmp, (struct obj *) 0);
+       }
+       return total;
+}
+
+void
+you_were()
+{
+       char qbuf[QBUFSZ];
+
+       if (Unchanging || (u.umonnum == u.ulycn)) return;
+       if (Polymorph_control) {
+           /* `+4' => skip "were" prefix to get name of beast */
+           Sprintf(qbuf, "Do you want to change into %s? ",
+                   an(mons[u.ulycn].mname+4));
+           if(yn(qbuf) == 'n') return;
+       }
+       (void) polymon(u.ulycn);
+}
+
+void
+you_unwere(purify)
+boolean purify;
+{
+       if (purify) {
+           You_feel("purified.");
+           u.ulycn = NON_PM;   /* cure lycanthropy */
+       }
+       if (!Unchanging && is_were(youmonst.data) &&
+               (!Polymorph_control || yn("Remain in beast form?") == 'n'))
+           rehumanize();
+}
+
+#endif /* OVLB */
+
+/*were.c*/
diff --git a/src/wield.c b/src/wield.c
new file mode 100644 (file)
index 0000000..0423116
--- /dev/null
@@ -0,0 +1,800 @@
+/*     SCCS Id: @(#)wield.c    3.4     2003/01/29      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+/* KMH -- Differences between the three weapon slots.
+ *
+ * The main weapon (uwep):
+ * 1.  Is filled by the (w)ield command.
+ * 2.  Can be filled with any type of item.
+ * 3.  May be carried in one or both hands.
+ * 4.  Is used as the melee weapon and as the launcher for
+ *     ammunition.
+ * 5.  Only conveys intrinsics when it is a weapon, weapon-tool,
+ *     or artifact.
+ * 6.  Certain cursed items will weld to the hand and cannot be
+ *     unwielded or dropped.  See erodeable_wep() and will_weld()
+ *     below for the list of which items apply.
+ *
+ * The secondary weapon (uswapwep):
+ * 1.  Is filled by the e(x)change command, which swaps this slot
+ *     with the main weapon.  If the "pushweapon" option is set,
+ *     the (w)ield command will also store the old weapon in the
+ *     secondary slot.
+ * 2.  Can be field with anything that will fit in the main weapon
+ *     slot; that is, any type of item.
+ * 3.  Is usually NOT considered to be carried in the hands.
+ *     That would force too many checks among the main weapon,
+ *     second weapon, shield, gloves, and rings; and it would
+ *     further be complicated by bimanual weapons.  A special
+ *     exception is made for two-weapon combat.
+ * 4.  Is used as the second weapon for two-weapon combat, and as
+ *     a convenience to swap with the main weapon.
+ * 5.  Never conveys intrinsics.
+ * 6.  Cursed items never weld (see #3 for reasons), but they also
+ *     prevent two-weapon combat.
+ *
+ * The quiver (uquiver):
+ * 1.  Is filled by the (Q)uiver command.
+ * 2.  Can be filled with any type of item.
+ * 3.  Is considered to be carried in a special part of the pack.
+ * 4.  Is used as the item to throw with the (f)ire command.
+ *     This is a convenience over the normal (t)hrow command.
+ * 5.  Never conveys intrinsics.
+ * 6.  Cursed items never weld; their effect is handled by the normal
+ *     throwing code.
+ *
+ * No item may be in more than one of these slots.
+ */
+
+
+STATIC_DCL int FDECL(ready_weapon, (struct obj *));
+
+/* used by will_weld() */
+/* probably should be renamed */
+#define erodeable_wep(optr)    ((optr)->oclass == WEAPON_CLASS \
+                               || is_weptool(optr) \
+                               || (optr)->otyp == HEAVY_IRON_BALL \
+                               || (optr)->otyp == IRON_CHAIN)
+
+/* used by welded(), and also while wielding */
+#define will_weld(optr)                ((optr)->cursed \
+                               && (erodeable_wep(optr) \
+                                  || (optr)->otyp == TIN_OPENER))
+
+
+/*** Functions that place a given item in a slot ***/
+/* Proper usage includes:
+ * 1.  Initializing the slot during character generation or a
+ *     restore.
+ * 2.  Setting the slot due to a player's actions.
+ * 3.  If one of the objects in the slot are split off, these
+ *     functions can be used to put the remainder back in the slot.
+ * 4.  Putting an item that was thrown and returned back into the slot.
+ * 5.  Emptying the slot, by passing a null object.  NEVER pass
+ *     zeroobj!
+ *
+ * If the item is being moved from another slot, it is the caller's
+ * responsibility to handle that.  It's also the caller's responsibility
+ * to print the appropriate messages.
+ */
+void
+setuwep(obj)
+register struct obj *obj;
+{
+       struct obj *olduwep = uwep;
+
+       if (obj == uwep) return; /* necessary to not set unweapon */
+       /* This message isn't printed in the caller because it happens
+        * *whenever* Sunsword is unwielded, from whatever cause.
+        */
+       setworn(obj, W_WEP);
+       if (uwep == obj && artifact_light(olduwep) && olduwep->lamplit) {
+           end_burn(olduwep, FALSE);
+           if (!Blind) pline("%s glowing.", Tobjnam(olduwep, "stop"));
+       }
+       /* Note: Explicitly wielding a pick-axe will not give a "bashing"
+        * message.  Wielding one via 'a'pplying it will.
+        * 3.2.2:  Wielding arbitrary objects will give bashing message too.
+        */
+       if (obj) {
+               unweapon = (obj->oclass == WEAPON_CLASS) ?
+                               is_launcher(obj) || is_ammo(obj) ||
+                               is_missile(obj) || (is_pole(obj)
+#ifdef STEED
+                               && !u.usteed
+#endif
+                               ) : !is_weptool(obj);
+       } else
+               unweapon = TRUE;        /* for "bare hands" message */
+       update_inventory();
+}
+
+STATIC_OVL int
+ready_weapon(wep)
+struct obj *wep;
+{
+       /* Separated function so swapping works easily */
+       int res = 0;
+
+       if (!wep) {
+           /* No weapon */
+           if (uwep) {
+               You("are empty %s.", body_part(HANDED));
+               setuwep((struct obj *) 0);
+               res++;
+           } else
+               You("are already empty %s.", body_part(HANDED));
+       } else if (!uarmg && !Stone_resistance && wep->otyp == CORPSE
+                               && touch_petrifies(&mons[wep->corpsenm])) {
+           /* Prevent wielding cockatrice when not wearing gloves --KAA */
+           char kbuf[BUFSZ];
+
+           You("wield the %s corpse in your bare %s.",
+               mons[wep->corpsenm].mname, makeplural(body_part(HAND)));
+           Sprintf(kbuf, "%s corpse", an(mons[wep->corpsenm].mname));
+           instapetrify(kbuf);
+       } else if (uarms && bimanual(wep))
+           You("cannot wield a two-handed %s while wearing a shield.",
+               is_sword(wep) ? "sword" :
+                   wep->otyp == BATTLE_AXE ? "axe" : "weapon");
+       else if (wep->oartifact && !touch_artifact(wep, &youmonst)) {
+           res++;      /* takes a turn even though it doesn't get wielded */
+       } else {
+           /* Weapon WILL be wielded after this point */
+           res++;
+           if (will_weld(wep)) {
+               const char *tmp = xname(wep), *thestr = "The ";
+               if (strncmp(tmp, thestr, 4) && !strncmp(The(tmp),thestr,4))
+                   tmp = thestr;
+               else tmp = "";
+               pline("%s%s %s to your %s!", tmp, aobjnam(wep, "weld"),
+                       (wep->quan == 1L) ? "itself" : "themselves", /* a3 */
+                       bimanual(wep) ?
+                               (const char *)makeplural(body_part(HAND))
+                               : body_part(HAND));
+               wep->bknown = TRUE;
+           } else {
+               /* The message must be printed before setuwep (since
+                * you might die and be revived from changing weapons),
+                * and the message must be before the death message and
+                * Lifesaved rewielding.  Yet we want the message to
+                * say "weapon in hand", thus this kludge.
+                */
+               long dummy = wep->owornmask;
+               wep->owornmask |= W_WEP;
+               prinv((char *)0, wep, 0L);
+               wep->owornmask = dummy;
+           }
+           setuwep(wep);
+
+           /* KMH -- Talking artifacts are finally implemented */
+           arti_speak(wep);
+
+           if (artifact_light(wep) && !wep->lamplit) {
+               begin_burn(wep, FALSE);
+               if (!Blind)
+                   pline("%s to glow brilliantly!", Tobjnam(wep, "begin"));
+           }
+
+#if 0
+           /* we'll get back to this someday, but it's not balanced yet */
+           if (Race_if(PM_ELF) && !wep->oartifact &&
+                           objects[wep->otyp].oc_material == IRON) {
+               /* Elves are averse to wielding cold iron */
+               You("have an uneasy feeling about wielding cold iron.");
+               change_luck(-1);
+           }
+#endif
+
+           if (wep->unpaid) {
+               struct monst *this_shkp;
+
+               if ((this_shkp = shop_keeper(inside_shop(u.ux, u.uy))) !=
+                   (struct monst *)0) {
+                   pline("%s says \"You be careful with my %s!\"",
+                         shkname(this_shkp),
+                         xname(wep));
+               }
+           }
+       }
+       return(res);
+}
+
+void
+setuqwep(obj)
+register struct obj *obj;
+{
+       setworn(obj, W_QUIVER);
+       update_inventory();
+}
+
+void
+setuswapwep(obj)
+register struct obj *obj;
+{
+       setworn(obj, W_SWAPWEP);
+       update_inventory();
+}
+
+
+/*** Commands to change particular slot(s) ***/
+
+static NEARDATA const char wield_objs[] =
+       { ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, TOOL_CLASS, 0 };
+static NEARDATA const char ready_objs[] =
+       { ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, 0 };
+static NEARDATA const char bullets[] = /* (note: different from dothrow.c) */
+       { ALL_CLASSES, ALLOW_NONE, GEM_CLASS, WEAPON_CLASS, 0 };
+
+int
+dowield()
+{
+       register struct obj *wep, *oldwep;
+       int result;
+
+       /* May we attempt this? */
+       multi = 0;
+       if (cantwield(youmonst.data)) {
+               pline("Don't be ridiculous!");
+               return(0);
+       }
+
+       /* Prompt for a new weapon */
+       if (!(wep = getobj(wield_objs, "wield")))
+               /* Cancelled */
+               return (0);
+       else if (wep == uwep) {
+           You("are already wielding that!");
+           if (is_weptool(wep)) unweapon = FALSE;      /* [see setuwep()] */
+               return (0);
+       } else if (welded(uwep)) {
+               weldmsg(uwep);
+               /* previously interrupted armor removal mustn't be resumed */
+               reset_remarm();
+               return (0);
+       }
+
+       /* Handle no object, or object in other slot */
+       if (wep == &zeroobj)
+               wep = (struct obj *) 0;
+       else if (wep == uswapwep)
+               return (doswapweapon());
+       else if (wep == uquiver)
+               setuqwep((struct obj *) 0);
+       else if (wep->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL
+#ifdef STEED
+                       | W_SADDLE
+#endif
+                       )) {
+               You("cannot wield that!");
+               return (0);
+       }
+
+       /* Set your new primary weapon */
+       oldwep = uwep;
+       result = ready_weapon(wep);
+       if (flags.pushweapon && oldwep && uwep != oldwep)
+               setuswapwep(oldwep);
+       untwoweapon();
+
+       return (result);
+}
+
+int
+doswapweapon()
+{
+       register struct obj *oldwep, *oldswap;
+       int result = 0;
+
+
+       /* May we attempt this? */
+       multi = 0;
+       if (cantwield(youmonst.data)) {
+               pline("Don't be ridiculous!");
+               return(0);
+       }
+       if (welded(uwep)) {
+               weldmsg(uwep);
+               return (0);
+       }
+
+       /* Unwield your current secondary weapon */
+       oldwep = uwep;
+       oldswap = uswapwep;
+       setuswapwep((struct obj *) 0);
+
+       /* Set your new primary weapon */
+       result = ready_weapon(oldswap);
+
+       /* Set your new secondary weapon */
+       if (uwep == oldwep)
+               /* Wield failed for some reason */
+               setuswapwep(oldswap);
+       else {
+               setuswapwep(oldwep);
+               if (uswapwep)
+                       prinv((char *)0, uswapwep, 0L);
+               else
+                       You("have no secondary weapon readied.");
+       }
+
+       if (u.twoweap && !can_twoweapon())
+               untwoweapon();
+
+       return (result);
+}
+
+int
+dowieldquiver()
+{
+       register struct obj *newquiver;
+       const char *quivee_types = (uslinging() ||
+                 (uswapwep && objects[uswapwep->otyp].oc_skill == P_SLING)) ?
+                                 bullets : ready_objs;
+
+       /* Since the quiver isn't in your hands, don't check cantwield(), */
+       /* will_weld(), touch_petrifies(), etc. */
+       multi = 0;
+
+       /* Because 'Q' used to be quit... */
+       if (flags.suppress_alert < FEATURE_NOTICE_VER(3,3,0))
+               pline("Note: Please use #quit if you wish to exit the game.");
+
+       /* Prompt for a new quiver */
+       if (!(newquiver = getobj(quivee_types, "ready")))
+               /* Cancelled */
+               return (0);
+
+       /* Handle no object, or object in other slot */
+       /* Any type is okay, since we give no intrinsics anyways */
+       if (newquiver == &zeroobj) {
+               /* Explicitly nothing */
+               if (uquiver) {
+                       You("now have no ammunition readied.");
+                       setuqwep(newquiver = (struct obj *) 0);
+               } else {
+                       You("already have no ammunition readied!");
+                       return(0);
+               }
+       } else if (newquiver == uquiver) {
+               pline("That ammunition is already readied!");
+               return(0);
+       } else if (newquiver == uwep) {
+               /* Prevent accidentally readying the main weapon */
+               pline("%s already being used as a weapon!",
+                     !is_plural(uwep) ? "That is" : "They are");
+               return(0);
+       } else if (newquiver->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL
+#ifdef STEED
+                       | W_SADDLE
+#endif
+                       )) {
+               You("cannot ready that!");
+               return (0);
+       } else {
+               long dummy;
+
+
+               /* Check if it's the secondary weapon */
+               if (newquiver == uswapwep) {
+                       setuswapwep((struct obj *) 0);
+                       untwoweapon();
+               }
+
+               /* Okay to put in quiver; print it */
+               dummy = newquiver->owornmask;
+               newquiver->owornmask |= W_QUIVER;
+               prinv((char *)0, newquiver, 0L);
+               newquiver->owornmask = dummy;
+       }
+
+       /* Finally, place it in the quiver */
+       setuqwep(newquiver);
+       /* Take no time since this is a convenience slot */
+       return (0);
+}
+
+/* used for #rub and for applying pick-axe, whip, grappling hook, or polearm */
+/* (moved from apply.c) */
+boolean
+wield_tool(obj, verb)
+struct obj *obj;
+const char *verb;      /* "rub",&c */
+{
+    const char *what;
+    boolean more_than_1;
+
+    if (obj == uwep) return TRUE;   /* nothing to do if already wielding it */
+
+    if (!verb) verb = "wield";
+    what = xname(obj);
+    more_than_1 = (obj->quan > 1L ||
+                  strstri(what, "pair of ") != 0 ||
+                  strstri(what, "s of ") != 0);
+
+    if (obj->owornmask & (W_ARMOR|W_RING|W_AMUL|W_TOOL)) {
+       char yourbuf[BUFSZ];
+
+       You_cant("%s %s %s while wearing %s.",
+                verb, shk_your(yourbuf, obj), what,
+                more_than_1 ? "them" : "it");
+       return FALSE;
+    }
+    if (welded(uwep)) {
+       if (flags.verbose) {
+           const char *hand = body_part(HAND);
+
+           if (bimanual(uwep)) hand = makeplural(hand);
+           if (strstri(what, "pair of ") != 0) more_than_1 = FALSE;
+           pline(
+            "Since your weapon is welded to your %s, you cannot %s %s %s.",
+                 hand, verb, more_than_1 ? "those" : "that", xname(obj));
+       } else {
+           You_cant("do that.");
+       }
+       return FALSE;
+    }
+    if (cantwield(youmonst.data)) {
+       You_cant("hold %s strongly enough.", more_than_1 ? "them" : "it");
+       return FALSE;
+    }
+    /* check shield */
+    if (uarms && bimanual(obj)) {
+       You("cannot %s a two-handed %s while wearing a shield.",
+           verb, (obj->oclass == WEAPON_CLASS) ? "weapon" : "tool");
+       return FALSE;
+    }
+    if (uquiver == obj) setuqwep((struct obj *)0);
+    if (uswapwep == obj) {
+       (void) doswapweapon();
+       /* doswapweapon might fail */
+       if (uswapwep == obj) return FALSE;
+    } else {
+       You("now wield %s.", doname(obj));
+       setuwep(obj);
+    }
+    if (uwep != obj) return FALSE;     /* rewielded old object after dying */
+    /* applying weapon or tool that gets wielded ends two-weapon combat */
+    if (u.twoweap)
+       untwoweapon();
+    if (obj->oclass != WEAPON_CLASS)
+       unweapon = TRUE;
+    return TRUE;
+}
+
+int
+can_twoweapon()
+{
+       struct obj *otmp;
+
+#define NOT_WEAPON(obj) (!is_weptool(obj) && obj->oclass != WEAPON_CLASS)
+       if (!could_twoweap(youmonst.data)) {
+               if (Upolyd)
+                   You_cant("use two weapons in your current form.");
+               else
+                   pline("%s aren't able to use two weapons at once.",
+                         makeplural((flags.female && urole.name.f) ?
+                                    urole.name.f : urole.name.m));
+       } else if (!uwep || !uswapwep)
+               Your("%s%s%s empty.", uwep ? "left " : uswapwep ? "right " : "",
+                       body_part(HAND), (!uwep && !uswapwep) ? "s are" : " is");
+       else if (NOT_WEAPON(uwep) || NOT_WEAPON(uswapwep)) {
+               otmp = NOT_WEAPON(uwep) ? uwep : uswapwep;
+               pline("%s %s.", Yname2(otmp),
+                   is_plural(otmp) ? "aren't weapons" : "isn't a weapon");
+       } else if (bimanual(uwep) || bimanual(uswapwep)) {
+               otmp = bimanual(uwep) ? uwep : uswapwep;
+               pline("%s isn't one-handed.", Yname2(otmp));
+       } else if (uarms)
+               You_cant("use two weapons while wearing a shield.");
+       else if (uswapwep->oartifact)
+               pline("%s %s being held second to another weapon!",
+                       Yname2(uswapwep), otense(uswapwep, "resist"));
+       else if (!uarmg && !Stone_resistance && (uswapwep->otyp == CORPSE &&
+                   touch_petrifies(&mons[uswapwep->corpsenm]))) {
+               char kbuf[BUFSZ];
+
+               You("wield the %s corpse with your bare %s.",
+                   mons[uswapwep->corpsenm].mname, body_part(HAND));
+               Sprintf(kbuf, "%s corpse", an(mons[uswapwep->corpsenm].mname));
+               instapetrify(kbuf);
+       } else if (Glib || uswapwep->cursed) {
+               if (!Glib)
+                       uswapwep->bknown = TRUE;
+               drop_uswapwep();
+       } else
+               return (TRUE);
+       return (FALSE);
+}
+
+void
+drop_uswapwep()
+{
+       char str[BUFSZ];
+       struct obj *obj = uswapwep;
+
+       /* Avoid trashing makeplural's static buffer */
+       Strcpy(str, makeplural(body_part(HAND)));
+       Your("%s from your %s!",  aobjnam(obj, "slip"), str);
+       dropx(obj);
+}
+
+int
+dotwoweapon()
+{
+       /* You can always toggle it off */
+       if (u.twoweap) {
+               You("switch to your primary weapon.");
+               u.twoweap = 0;
+               update_inventory();
+               return (0);
+       }
+
+       /* May we use two weapons? */
+       if (can_twoweapon()) {
+               /* Success! */
+               You("begin two-weapon combat.");
+               u.twoweap = 1;
+               update_inventory();
+               return (rnd(20) > ACURR(A_DEX));
+       }
+       return (0);
+}
+
+/*** Functions to empty a given slot ***/
+/* These should be used only when the item can't be put back in
+ * the slot by life saving.  Proper usage includes:
+ * 1.  The item has been eaten, stolen, burned away, or rotted away.
+ * 2.  Making an item disappear for a bones pile.
+ */
+void
+uwepgone()
+{
+       if (uwep) {
+               if (artifact_light(uwep) && uwep->lamplit) {
+                   end_burn(uwep, FALSE);
+                   if (!Blind) pline("%s glowing.", Tobjnam(uwep, "stop"));
+               }
+               setworn((struct obj *)0, W_WEP);
+               unweapon = TRUE;
+               update_inventory();
+       }
+}
+
+void
+uswapwepgone()
+{
+       if (uswapwep) {
+               setworn((struct obj *)0, W_SWAPWEP);
+               update_inventory();
+       }
+}
+
+void
+uqwepgone()
+{
+       if (uquiver) {
+               setworn((struct obj *)0, W_QUIVER);
+               update_inventory();
+       }
+}
+
+void
+untwoweapon()
+{
+       if (u.twoweap) {
+               You("can no longer use two weapons at once.");
+               u.twoweap = FALSE;
+               update_inventory();
+       }
+       return;
+}
+
+/* Maybe rust object, or corrode it if acid damage is called for */
+void
+erode_obj(target, acid_dmg, fade_scrolls)
+struct obj *target;            /* object (e.g. weapon or armor) to erode */
+boolean acid_dmg;
+boolean fade_scrolls;
+{
+       int erosion;
+       struct monst *victim;
+       boolean vismon;
+       boolean visobj;
+
+       if (!target)
+           return;
+       victim = carried(target) ? &youmonst :
+           mcarried(target) ? target->ocarry : (struct monst *)0;
+       vismon = victim && (victim != &youmonst) && canseemon(victim);
+       visobj = !victim && cansee(bhitpos.x, bhitpos.y); /* assume thrown */
+
+       erosion = acid_dmg ? target->oeroded2 : target->oeroded;
+
+       if (target->greased) {
+           grease_protect(target,(char *)0,victim);
+       } else if (target->oclass == SCROLL_CLASS) {
+           if(fade_scrolls && target->otyp != SCR_BLANK_PAPER
+#ifdef MAIL
+           && target->otyp != SCR_MAIL
+#endif
+                                       )
+           {
+               if (!Blind) {
+                   if (victim == &youmonst)
+                       Your("%s.", aobjnam(target, "fade"));
+                   else if (vismon)
+                       pline("%s's %s.", Monnam(victim),
+                             aobjnam(target, "fade"));
+                   else if (visobj)
+                       pline_The("%s.", aobjnam(target, "fade"));
+               }
+               target->otyp = SCR_BLANK_PAPER;
+               target->spe = 0;
+           }
+       } else if (target->oerodeproof ||
+               (acid_dmg ? !is_corrodeable(target) : !is_rustprone(target))) {
+           if (flags.verbose || !(target->oerodeproof && target->rknown)) {
+               if (victim == &youmonst)
+                   Your("%s not affected.", aobjnam(target, "are"));
+               else if (vismon)
+                   pline("%s's %s not affected.", Monnam(victim),
+                       aobjnam(target, "are"));
+               /* no message if not carried */
+           }
+           if (target->oerodeproof) target->rknown = TRUE;
+       } else if (erosion < MAX_ERODE) {
+           if (victim == &youmonst)
+               Your("%s%s!", aobjnam(target, acid_dmg ? "corrode" : "rust"),
+                   erosion+1 == MAX_ERODE ? " completely" :
+                   erosion ? " further" : "");
+           else if (vismon)
+               pline("%s's %s%s!", Monnam(victim),
+                   aobjnam(target, acid_dmg ? "corrode" : "rust"),
+                   erosion+1 == MAX_ERODE ? " completely" :
+                   erosion ? " further" : "");
+           else if (visobj)
+               pline_The("%s%s!",
+                   aobjnam(target, acid_dmg ? "corrode" : "rust"),
+                   erosion+1 == MAX_ERODE ? " completely" :
+                   erosion ? " further" : "");
+           if (acid_dmg)
+               target->oeroded2++;
+           else
+               target->oeroded++;
+       } else {
+           if (flags.verbose) {
+               if (victim == &youmonst)
+                   Your("%s completely %s.",
+                       aobjnam(target, Blind ? "feel" : "look"),
+                       acid_dmg ? "corroded" : "rusty");
+               else if (vismon)
+                   pline("%s's %s completely %s.", Monnam(victim),
+                       aobjnam(target, "look"),
+                       acid_dmg ? "corroded" : "rusty");
+               else if (visobj)
+                   pline_The("%s completely %s.",
+                       aobjnam(target, "look"),
+                       acid_dmg ? "corroded" : "rusty");
+           }
+       }
+}
+
+int
+chwepon(otmp, amount)
+register struct obj *otmp;
+register int amount;
+{
+       const char *color = hcolor((amount < 0) ? NH_BLACK : NH_BLUE);
+       const char *xtime;
+       int otyp = STRANGE_OBJECT;
+
+       if(!uwep || (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep))) {
+               char buf[BUFSZ];
+
+               Sprintf(buf, "Your %s %s.", makeplural(body_part(HAND)),
+                       (amount >= 0) ? "twitch" : "itch");
+               strange_feeling(otmp, buf);
+               exercise(A_DEX, (boolean) (amount >= 0));
+               return(0);
+       }
+
+       if (otmp && otmp->oclass == SCROLL_CLASS) otyp = otmp->otyp;
+
+       if(uwep->otyp == WORM_TOOTH && amount >= 0) {
+               uwep->otyp = CRYSKNIFE;
+               uwep->oerodeproof = 0;
+               Your("weapon seems sharper now.");
+               uwep->cursed = 0;
+               if (otyp != STRANGE_OBJECT) makeknown(otyp);
+               return(1);
+       }
+
+       if(uwep->otyp == CRYSKNIFE && amount < 0) {
+               uwep->otyp = WORM_TOOTH;
+               uwep->oerodeproof = 0;
+               Your("weapon seems duller now.");
+               if (otyp != STRANGE_OBJECT && otmp->bknown) makeknown(otyp);
+               return(1);
+       }
+
+       if (amount < 0 && uwep->oartifact && restrict_name(uwep, ONAME(uwep))) {
+           if (!Blind)
+               Your("%s %s.", aobjnam(uwep, "faintly glow"), color);
+           return(1);
+       }
+       /* there is a (soft) upper and lower limit to uwep->spe */
+       if(((uwep->spe > 5 && amount >= 0) || (uwep->spe < -5 && amount < 0))
+                                                               && rn2(3)) {
+           if (!Blind)
+           Your("%s %s for a while and then %s.",
+                aobjnam(uwep, "violently glow"), color,
+                otense(uwep, "evaporate"));
+           else
+               Your("%s.", aobjnam(uwep, "evaporate"));
+
+           useupall(uwep);     /* let all of them disappear */
+           return(1);
+       }
+       if (!Blind) {
+           xtime = (amount*amount == 1) ? "moment" : "while";
+           Your("%s %s for a %s.",
+                aobjnam(uwep, amount == 0 ? "violently glow" : "glow"),
+                color, xtime);
+           if (otyp != STRANGE_OBJECT && uwep->known &&
+                   (amount > 0 || (amount < 0 && otmp->bknown)))
+               makeknown(otyp);
+       }
+       uwep->spe += amount;
+       if(amount > 0) uwep->cursed = 0;
+
+       /*
+        * Enchantment, which normally improves a weapon, has an
+        * addition adverse reaction on Magicbane whose effects are
+        * spe dependent.  Give an obscure clue here.
+        */
+       if (uwep->oartifact == ART_MAGICBANE && uwep->spe >= 0) {
+               Your("right %s %sches!",
+                       body_part(HAND),
+                       (((amount > 1) && (uwep->spe > 1)) ? "flin" : "it"));
+       }
+
+       /* an elven magic clue, cookie@keebler */
+       /* elven weapons vibrate warningly when enchanted beyond a limit */
+       if ((uwep->spe > 5)
+               && (is_elven_weapon(uwep) || uwep->oartifact || !rn2(7)))
+           Your("%s unexpectedly.",
+               aobjnam(uwep, "suddenly vibrate"));
+
+       return(1);
+}
+
+int
+welded(obj)
+register struct obj *obj;
+{
+       if (obj && obj == uwep && will_weld(obj)) {
+               obj->bknown = TRUE;
+               return 1;
+       }
+       return 0;
+}
+
+void
+weldmsg(obj)
+register struct obj *obj;
+{
+       long savewornmask;
+
+       savewornmask = obj->owornmask;
+       Your("%s %s welded to your %s!",
+               xname(obj), otense(obj, "are"),
+               bimanual(obj) ? (const char *)makeplural(body_part(HAND))
+                               : body_part(HAND));
+       obj->owornmask = savewornmask;
+}
+
+/*wield.c*/
diff --git a/src/windows.c b/src/windows.c
new file mode 100644 (file)
index 0000000..3c59080
--- /dev/null
@@ -0,0 +1,146 @@
+/*     SCCS Id: @(#)windows.c  3.4     1996/05/19      */
+/* Copyright (c) D. Cohrs, 1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#ifdef TTY_GRAPHICS
+#include "wintty.h"
+#endif
+#ifdef X11_GRAPHICS
+/* cannot just blindly include winX.h without including all of X11 stuff */
+/* and must get the order of include files right.  Don't bother */
+extern struct window_procs X11_procs;
+extern void NDECL(win_X11_init);
+#endif
+#ifdef QT_GRAPHICS
+extern struct window_procs Qt_procs;
+#endif
+#ifdef GEM_GRAPHICS
+#include "wingem.h"
+#endif
+#ifdef MAC
+extern struct window_procs mac_procs;
+#endif
+#ifdef BEOS_GRAPHICS
+extern struct window_procs beos_procs;
+extern void NDECL(be_win_init);
+#endif
+#ifdef AMIGA_INTUITION
+extern struct window_procs amii_procs;
+extern struct window_procs amiv_procs;
+extern void NDECL(ami_wininit_data);
+#endif
+#ifdef WIN32_GRAPHICS
+extern struct window_procs win32_procs;
+#endif
+#ifdef GNOME_GRAPHICS
+#include "winGnome.h"
+extern struct window_procs Gnome_procs;
+#endif
+#ifdef MSWIN_GRAPHICS
+extern struct window_procs mswin_procs;
+#endif
+
+STATIC_DCL void FDECL(def_raw_print, (const char *s));
+
+NEARDATA struct window_procs windowprocs;
+
+static
+struct win_choices {
+    struct window_procs *procs;
+    void NDECL((*ini_routine));                /* optional (can be 0) */
+} winchoices[] = {
+#ifdef TTY_GRAPHICS
+    { &tty_procs, win_tty_init },
+#endif
+#ifdef X11_GRAPHICS
+    { &X11_procs, win_X11_init },
+#endif
+#ifdef QT_GRAPHICS
+    { &Qt_procs, 0 },
+#endif
+#ifdef GEM_GRAPHICS
+    { &Gem_procs, win_Gem_init },
+#endif
+#ifdef MAC
+    { &mac_procs, 0 },
+#endif
+#ifdef BEOS_GRAPHICS
+    { &beos_procs, be_win_init },
+#endif
+#ifdef AMIGA_INTUITION
+    { &amii_procs, ami_wininit_data },         /* Old font version of the game */
+    { &amiv_procs, ami_wininit_data },         /* Tile version of the game */
+#endif
+#ifdef WIN32_GRAPHICS
+    { &win32_procs, 0 },
+#endif
+#ifdef GNOME_GRAPHICS
+    { &Gnome_procs, 0 },
+#endif
+#ifdef MSWIN_GRAPHICS
+    { &mswin_procs, 0 },
+#endif
+    { 0, 0 }           /* must be last */
+};
+
+STATIC_OVL
+void
+def_raw_print(s)
+const char *s;
+{
+    puts(s);
+}
+
+void
+choose_windows(s)
+const char *s;
+{
+    register int i;
+
+    for(i=0; winchoices[i].procs; i++)
+       if (!strcmpi(s, winchoices[i].procs->name)) {
+           windowprocs = *winchoices[i].procs;
+           if (winchoices[i].ini_routine) (*winchoices[i].ini_routine)();
+           return;
+       }
+
+    if (!windowprocs.win_raw_print)
+       windowprocs.win_raw_print = def_raw_print;
+
+    raw_printf("Window type %s not recognized.  Choices are:", s);
+    for(i=0; winchoices[i].procs; i++)
+       raw_printf("        %s", winchoices[i].procs->name);
+
+    if (windowprocs.win_raw_print == def_raw_print)
+       terminate(EXIT_SUCCESS);
+    wait_synch();
+}
+
+/*
+ * tty_message_menu() provides a means to get feedback from the
+ * --More-- prompt; other interfaces generally don't need that.
+ */
+/*ARGSUSED*/
+char
+genl_message_menu(let, how, mesg)
+char let;
+int how;
+const char *mesg;
+{
+    pline("%s", mesg);
+    return 0;
+}
+
+/*ARGSUSED*/
+void
+genl_preference_update(pref)
+const char *pref;
+{
+       /* window ports are expected to provide
+          their own preference update routine
+          for the preference capabilities that
+          they support.
+          Just return in this genl one. */
+}
+/*windows.c*/
diff --git a/src/wizard.c b/src/wizard.c
new file mode 100644 (file)
index 0000000..c0f67e3
--- /dev/null
@@ -0,0 +1,638 @@
+/*     SCCS Id: @(#)wizard.c   3.4     2003/02/18      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* wizard code - inspired by rogue code from Merlyn Leroy (digi-g!brian) */
+/*            - heavily modified to give the wiz balls.  (genat!mike)   */
+/*            - dewimped and given some maledictions. -3. */
+/*            - generalized for 3.1 (mike@bullns.on01.bull.ca) */
+
+#include "hack.h"
+#include "qtext.h"
+#include "epri.h"
+
+extern const int monstr[];
+
+#ifdef OVLB
+
+STATIC_DCL short FDECL(which_arti, (int));
+STATIC_DCL boolean FDECL(mon_has_arti, (struct monst *,SHORT_P));
+STATIC_DCL struct monst *FDECL(other_mon_has_arti, (struct monst *,SHORT_P));
+STATIC_DCL struct obj *FDECL(on_ground, (SHORT_P));
+STATIC_DCL boolean FDECL(you_have, (int));
+STATIC_DCL long FDECL(target_on, (int,struct monst *));
+STATIC_DCL long FDECL(strategy, (struct monst *));
+
+static NEARDATA const int nasties[] = {
+       PM_COCKATRICE, PM_ETTIN, PM_STALKER, PM_MINOTAUR, PM_RED_DRAGON,
+       PM_BLACK_DRAGON, PM_GREEN_DRAGON, PM_OWLBEAR, PM_PURPLE_WORM,
+       PM_ROCK_TROLL, PM_XAN, PM_GREMLIN, PM_UMBER_HULK, PM_VAMPIRE_LORD,
+       PM_XORN, PM_ZRUTY, PM_ELF_LORD, PM_ELVENKING, PM_YELLOW_DRAGON,
+       PM_LEOCROTTA, PM_BALUCHITHERIUM, PM_CARNIVOROUS_APE, PM_FIRE_GIANT,
+       PM_COUATL, PM_CAPTAIN, PM_WINGED_GARGOYLE, PM_MASTER_MIND_FLAYER,
+       PM_FIRE_ELEMENTAL, PM_JABBERWOCK, PM_ARCH_LICH, PM_OGRE_KING,
+       PM_OLOG_HAI, PM_IRON_GOLEM, PM_OCHRE_JELLY, PM_GREEN_SLIME,
+       PM_DISENCHANTER
+       };
+
+static NEARDATA const unsigned wizapp[] = {
+       PM_HUMAN, PM_WATER_DEMON, PM_VAMPIRE,
+       PM_RED_DRAGON, PM_TROLL, PM_UMBER_HULK,
+       PM_XORN, PM_XAN, PM_COCKATRICE,
+       PM_FLOATING_EYE,
+       PM_GUARDIAN_NAGA,
+       PM_TRAPPER
+};
+
+#endif /* OVLB */
+#ifdef OVL0
+
+/* If you've found the Amulet, make the Wizard appear after some time */
+/* Also, give hints about portal locations, if amulet is worn/wielded -dlc */
+void
+amulet()
+{
+       struct monst *mtmp;
+       struct trap *ttmp;
+       struct obj *amu;
+
+#if 0          /* caller takes care of this check */
+       if (!u.uhave.amulet)
+               return;
+#endif
+       if ((((amu = uamul) != 0 && amu->otyp == AMULET_OF_YENDOR) ||
+            ((amu = uwep) != 0 && amu->otyp == AMULET_OF_YENDOR))
+           && !rn2(15)) {
+           for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
+               if(ttmp->ttyp == MAGIC_PORTAL) {
+                   int du = distu(ttmp->tx, ttmp->ty);
+                   if (du <= 9)
+                       pline("%s hot!", Tobjnam(amu, "feel"));
+                   else if (du <= 64)
+                       pline("%s very warm.", Tobjnam(amu, "feel"));
+                   else if (du <= 144)
+                       pline("%s warm.", Tobjnam(amu, "feel"));
+                   /* else, the amulet feels normal */
+                   break;
+               }
+           }
+       }
+
+       if (!flags.no_of_wizards)
+               return;
+       /* find Wizard, and wake him if necessary */
+       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+           if (!DEADMONSTER(mtmp) && mtmp->iswiz && mtmp->msleeping && !rn2(40)) {
+               mtmp->msleeping = 0;
+               if (distu(mtmp->mx,mtmp->my) > 2)
+                   You(
+    "get the creepy feeling that somebody noticed your taking the Amulet."
+                   );
+               return;
+           }
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+int
+mon_has_amulet(mtmp)
+register struct monst *mtmp;
+{
+       register struct obj *otmp;
+
+       for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+               if(otmp->otyp == AMULET_OF_YENDOR) return(1);
+       return(0);
+}
+
+int
+mon_has_special(mtmp)
+register struct monst *mtmp;
+{
+       register struct obj *otmp;
+
+       for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+               if(otmp->otyp == AMULET_OF_YENDOR ||
+                       is_quest_artifact(otmp) ||
+                       otmp->otyp == BELL_OF_OPENING ||
+                       otmp->otyp == CANDELABRUM_OF_INVOCATION ||
+                       otmp->otyp == SPE_BOOK_OF_THE_DEAD) return(1);
+       return(0);
+}
+
+/*
+ *     New for 3.1  Strategy / Tactics for the wiz, as well as other
+ *     monsters that are "after" something (defined via mflag3).
+ *
+ *     The strategy section decides *what* the monster is going
+ *     to attempt, the tactics section implements the decision.
+ */
+#define STRAT(w, x, y, typ) (w | ((long)(x)<<16) | ((long)(y)<<8) | (long)typ)
+
+#define M_Wants(mask)  (mtmp->data->mflags3 & (mask))
+
+STATIC_OVL short
+which_arti(mask)
+       register int mask;
+{
+       switch(mask) {
+           case M3_WANTSAMUL:  return(AMULET_OF_YENDOR);
+           case M3_WANTSBELL:  return(BELL_OF_OPENING);
+           case M3_WANTSCAND:  return(CANDELABRUM_OF_INVOCATION);
+           case M3_WANTSBOOK:  return(SPE_BOOK_OF_THE_DEAD);
+           default:            break;  /* 0 signifies quest artifact */
+       }
+       return(0);
+}
+
+/*
+ *     If "otyp" is zero, it triggers a check for the quest_artifact,
+ *     since bell, book, candle, and amulet are all objects, not really
+ *     artifacts right now.    [MRS]
+ */
+STATIC_OVL boolean
+mon_has_arti(mtmp, otyp)
+       register struct monst *mtmp;
+       register short  otyp;
+{
+       register struct obj *otmp;
+
+       for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
+           if(otyp) {
+               if(otmp->otyp == otyp)
+                       return(1);
+           }
+            else if(is_quest_artifact(otmp)) return(1);
+       }
+       return(0);
+
+}
+
+STATIC_OVL struct monst *
+other_mon_has_arti(mtmp, otyp)
+       register struct monst *mtmp;
+       register short  otyp;
+{
+       register struct monst *mtmp2;
+
+       for(mtmp2 = fmon; mtmp2; mtmp2 = mtmp2->nmon)
+           /* no need for !DEADMONSTER check here since they have no inventory */
+           if(mtmp2 != mtmp)
+               if(mon_has_arti(mtmp2, otyp)) return(mtmp2);
+
+       return((struct monst *)0);
+}
+
+STATIC_OVL struct obj *
+on_ground(otyp)
+       register short  otyp;
+{
+       register struct obj *otmp;
+
+       for (otmp = fobj; otmp; otmp = otmp->nobj)
+           if (otyp) {
+               if (otmp->otyp == otyp)
+                   return(otmp);
+           } else if (is_quest_artifact(otmp))
+               return(otmp);
+       return((struct obj *)0);
+}
+
+STATIC_OVL boolean
+you_have(mask)
+       register int mask;
+{
+       switch(mask) {
+           case M3_WANTSAMUL:  return(boolean)(u.uhave.amulet);
+           case M3_WANTSBELL:  return(boolean)(u.uhave.bell);
+           case M3_WANTSCAND:  return(boolean)(u.uhave.menorah);
+           case M3_WANTSBOOK:  return(boolean)(u.uhave.book);
+           case M3_WANTSARTI:  return(boolean)(u.uhave.questart);
+           default:            break;
+       }
+       return(0);
+}
+
+STATIC_OVL long
+target_on(mask, mtmp)
+       register int mask;
+       register struct monst *mtmp;
+{
+       register short  otyp;
+       register struct obj *otmp;
+       register struct monst *mtmp2;
+
+       if(!M_Wants(mask))      return(STRAT_NONE);
+
+       otyp = which_arti(mask);
+       if(!mon_has_arti(mtmp, otyp)) {
+           if(you_have(mask))
+               return(STRAT(STRAT_PLAYER, u.ux, u.uy, mask));
+           else if((otmp = on_ground(otyp)))
+               return(STRAT(STRAT_GROUND, otmp->ox, otmp->oy, mask));
+           else if((mtmp2 = other_mon_has_arti(mtmp, otyp)))
+               return(STRAT(STRAT_MONSTR, mtmp2->mx, mtmp2->my, mask));
+       }
+       return(STRAT_NONE);
+}
+
+STATIC_OVL long
+strategy(mtmp)
+       register struct monst *mtmp;
+{
+       long strat, dstrat;
+
+       if (!is_covetous(mtmp->data) ||
+               /* perhaps a shopkeeper has been polymorphed into a master
+                  lich; we don't want it teleporting to the stairs to heal
+                  because that will leave its shop untended */
+               (mtmp->isshk && inhishop(mtmp)))
+           return STRAT_NONE;
+
+       switch((mtmp->mhp*3)/mtmp->mhpmax) {    /* 0-3 */
+
+          default:
+           case 0:     /* panic time - mtmp is almost snuffed */
+                       return(STRAT_HEAL);
+
+           case 1:     /* the wiz is less cautious */
+                       if(mtmp->data != &mons[PM_WIZARD_OF_YENDOR])
+                           return(STRAT_HEAL);
+                       /* else fall through */
+
+           case 2:     dstrat = STRAT_HEAL;
+                       break;
+
+           case 3:     dstrat = STRAT_NONE;
+                       break;
+       }
+
+       if(flags.made_amulet)
+           if((strat = target_on(M3_WANTSAMUL, mtmp)) != STRAT_NONE)
+               return(strat);
+
+       if(u.uevent.invoked) {          /* priorities change once gate opened */
+
+           if((strat = target_on(M3_WANTSARTI, mtmp)) != STRAT_NONE)
+               return(strat);
+           if((strat = target_on(M3_WANTSBOOK, mtmp)) != STRAT_NONE)
+               return(strat);
+           if((strat = target_on(M3_WANTSBELL, mtmp)) != STRAT_NONE)
+               return(strat);
+           if((strat = target_on(M3_WANTSCAND, mtmp)) != STRAT_NONE)
+               return(strat);
+       } else {
+
+           if((strat = target_on(M3_WANTSBOOK, mtmp)) != STRAT_NONE)
+               return(strat);
+           if((strat = target_on(M3_WANTSBELL, mtmp)) != STRAT_NONE)
+               return(strat);
+           if((strat = target_on(M3_WANTSCAND, mtmp)) != STRAT_NONE)
+               return(strat);
+           if((strat = target_on(M3_WANTSARTI, mtmp)) != STRAT_NONE)
+               return(strat);
+       }
+       return(dstrat);
+}
+
+int
+tactics(mtmp)
+       register struct monst *mtmp;
+{
+       long strat = strategy(mtmp);
+
+       mtmp->mstrategy = (mtmp->mstrategy & STRAT_WAITMASK) | strat;
+
+       switch (strat) {
+           case STRAT_HEAL:    /* hide and recover */
+               /* if wounded, hole up on or near the stairs (to block them) */
+               /* unless, of course, there are no stairs (e.g. endlevel) */
+               mtmp->mavenge = 1; /* covetous monsters attack while fleeing */
+               if (In_W_tower(mtmp->mx, mtmp->my, &u.uz) ||
+                       (mtmp->iswiz && !xupstair && !mon_has_amulet(mtmp))) {
+                   if (!rn2(3 + mtmp->mhp/10)) (void) rloc(mtmp, FALSE);
+               } else if (xupstair &&
+                        (mtmp->mx != xupstair || mtmp->my != yupstair)) {
+                   (void) mnearto(mtmp, xupstair, yupstair, TRUE);
+               }
+               /* if you're not around, cast healing spells */
+               if (distu(mtmp->mx,mtmp->my) > (BOLT_LIM * BOLT_LIM))
+                   if(mtmp->mhp <= mtmp->mhpmax - 8) {
+                       mtmp->mhp += rnd(8);
+                       return(1);
+                   }
+               /* fall through :-) */
+
+           case STRAT_NONE:    /* harrass */
+               if (!rn2(!mtmp->mflee ? 5 : 33)) mnexto(mtmp);
+               return(0);
+
+           default:            /* kill, maim, pillage! */
+           {
+               long  where = (strat & STRAT_STRATMASK);
+               xchar tx = STRAT_GOALX(strat),
+                     ty = STRAT_GOALY(strat);
+               int   targ = strat & STRAT_GOAL;
+               struct obj *otmp;
+
+               if(!targ) { /* simply wants you to close */
+                   return(0);
+               }
+               if((u.ux == tx && u.uy == ty) || where == STRAT_PLAYER) {
+                   /* player is standing on it (or has it) */
+                   mnexto(mtmp);
+                   return(0);
+               }
+               if(where == STRAT_GROUND) {
+                   if(!MON_AT(tx, ty) || (mtmp->mx == tx && mtmp->my == ty)) {
+                       /* teleport to it and pick it up */
+                       rloc_to(mtmp, tx, ty);  /* clean old pos */
+
+                       if ((otmp = on_ground(which_arti(targ))) != 0) {
+                           if (cansee(mtmp->mx, mtmp->my))
+                               pline("%s picks up %s.",
+                                   Monnam(mtmp),
+                                   (distu(mtmp->mx, mtmp->my) <= 5) ?
+                                    doname(otmp) : distant_name(otmp, doname));
+                           obj_extract_self(otmp);
+                           (void) mpickobj(mtmp, otmp);
+                           return(1);
+                       } else return(0);
+                   } else {
+                       /* a monster is standing on it - cause some trouble */
+                       if (!rn2(5)) mnexto(mtmp);
+                       return(0);
+                   }
+               } else { /* a monster has it - 'port beside it. */
+                   (void) mnearto(mtmp, tx, ty, FALSE);
+                   return(0);
+               }
+           }
+       }
+       /*NOTREACHED*/
+       return(0);
+}
+
+void
+aggravate()
+{
+       register struct monst *mtmp;
+
+       for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+           if (!DEADMONSTER(mtmp)) {
+               mtmp->msleeping = 0;
+               if(!mtmp->mcanmove && !rn2(5)) {
+                       mtmp->mfrozen = 0;
+                       mtmp->mcanmove = 1;
+               }
+           }
+}
+
+void
+clonewiz()
+{
+       register struct monst *mtmp2;
+
+       if ((mtmp2 = makemon(&mons[PM_WIZARD_OF_YENDOR],
+                               u.ux, u.uy, NO_MM_FLAGS)) != 0) {
+           mtmp2->msleeping = mtmp2->mtame = mtmp2->mpeaceful = 0;
+           if (!u.uhave.amulet && rn2(2)) {  /* give clone a fake */
+               (void) add_to_minv(mtmp2, mksobj(FAKE_AMULET_OF_YENDOR,
+                                       TRUE, FALSE));
+           }
+           mtmp2->m_ap_type = M_AP_MONSTER;
+           mtmp2->mappearance = wizapp[rn2(SIZE(wizapp))];
+           newsym(mtmp2->mx,mtmp2->my);
+       }
+}
+
+/* also used by newcham() */
+int
+pick_nasty()
+{
+    /* To do?  Possibly should filter for appropriate forms when
+       in the elemental planes or surrounded by water or lava. */
+    return nasties[rn2(SIZE(nasties))];
+}
+
+/* create some nasty monsters, aligned or neutral with the caster */
+/* a null caster defaults to a chaotic caster (e.g. the wizard) */
+int
+nasty(mcast)
+       struct monst *mcast;
+{
+    register struct monst      *mtmp;
+    register int       i, j, tmp;
+    int castalign = (mcast ? mcast->data->maligntyp : -1);
+    coord bypos;
+    int count=0;
+
+    if(!rn2(10) && Inhell) {
+       msummon((struct monst *) 0);    /* summons like WoY */
+       count++;
+    } else {
+       tmp = (u.ulevel > 3) ? u.ulevel/3 : 1; /* just in case -- rph */
+       /* if we don't have a casting monster, the nasties appear around you */
+       bypos.x = u.ux;
+       bypos.y = u.uy;
+       for(i = rnd(tmp); i > 0; --i)
+           for(j=0; j<20; j++) {
+               int makeindex;
+
+               /* Don't create more spellcasters of the monsters' level or
+                * higher--avoids chain summoners filling up the level.
+                */
+               do {
+                   makeindex = pick_nasty();
+               } while(mcast && attacktype(&mons[makeindex], AT_MAGC) &&
+                       monstr[makeindex] >= monstr[mcast->mnum]);
+               /* do this after picking the monster to place */
+               if (mcast &&
+                   !enexto(&bypos, mcast->mux, mcast->muy, &mons[makeindex]))
+                   continue;
+               if ((mtmp = makemon(&mons[makeindex],
+                                   bypos.x, bypos.y, NO_MM_FLAGS)) != 0) {
+                   mtmp->msleeping = mtmp->mpeaceful = mtmp->mtame = 0;
+                   set_malign(mtmp);
+               } else /* GENOD? */
+                   mtmp = makemon((struct permonst *)0,
+                                       bypos.x, bypos.y, NO_MM_FLAGS);
+               if(mtmp && (mtmp->data->maligntyp == 0 ||
+                           sgn(mtmp->data->maligntyp) == sgn(castalign)) ) {
+                   count++;
+                   break;
+               }
+           }
+    }
+    return count;
+}
+
+/*     Let's resurrect the wizard, for some unexpected fun.    */
+void
+resurrect()
+{
+       struct monst *mtmp, **mmtmp;
+       long elapsed;
+       const char *verb;
+
+       if (!flags.no_of_wizards) {
+           /* make a new Wizard */
+           verb = "kill";
+           mtmp = makemon(&mons[PM_WIZARD_OF_YENDOR], u.ux, u.uy, MM_NOWAIT);
+       } else {
+           /* look for a migrating Wizard */
+           verb = "elude";
+           mmtmp = &migrating_mons;
+           while ((mtmp = *mmtmp) != 0) {
+               if (mtmp->iswiz &&
+                       /* if he has the Amulet, he won't bring it to you */
+                       !mon_has_amulet(mtmp) &&
+                       (elapsed = monstermoves - mtmp->mlstmv) > 0L) {
+                   mon_catchup_elapsed_time(mtmp, elapsed);
+                   if (elapsed >= LARGEST_INT) elapsed = LARGEST_INT - 1;
+                   elapsed /= 50L;
+                   if (mtmp->msleeping && rn2((int)elapsed + 1))
+                       mtmp->msleeping = 0;
+                   if (mtmp->mfrozen == 1) /* would unfreeze on next move */
+                       mtmp->mfrozen = 0,  mtmp->mcanmove = 1;
+                   if (mtmp->mcanmove && !mtmp->msleeping) {
+                       *mmtmp = mtmp->nmon;
+                       mon_arrive(mtmp, TRUE);
+                       /* note: there might be a second Wizard; if so,
+                          he'll have to wait til the next resurrection */
+                       break;
+                   }
+               }
+               mmtmp = &mtmp->nmon;
+           }
+       }
+
+       if (mtmp) {
+               mtmp->msleeping = mtmp->mtame = mtmp->mpeaceful = 0;
+               set_malign(mtmp);
+               pline("A voice booms out...");
+               verbalize("So thou thought thou couldst %s me, fool.", verb);
+       }
+
+}
+
+/*     Here, we make trouble for the poor shmuck who actually  */
+/*     managed to do in the Wizard.                            */
+void
+intervene()
+{
+       int which = Is_astralevel(&u.uz) ? rnd(4) : rn2(6);
+       /* cases 0 and 5 don't apply on the Astral level */
+       switch (which) {
+           case 0:
+           case 1:     You_feel("vaguely nervous.");
+                       break;
+           case 2:     if (!Blind)
+                           You("notice a %s glow surrounding you.",
+                                 hcolor(NH_BLACK));
+                       rndcurse();
+                       break;
+           case 3:     aggravate();
+                       break;
+           case 4:     (void)nasty((struct monst *)0);
+                       break;
+           case 5:     resurrect();
+                       break;
+       }
+}
+
+void
+wizdead()
+{
+       flags.no_of_wizards--;
+       if (!u.uevent.udemigod) {
+               u.uevent.udemigod = TRUE;
+               u.udg_cnt = rn1(250, 50);
+       }
+}
+
+const char * const random_insult[] = {
+       "antic",
+       "blackguard",
+       "caitiff",
+       "chucklehead",
+       "coistrel",
+       "craven",
+       "cretin",
+       "cur",
+       "dastard",
+       "demon fodder",
+       "dimwit",
+       "dolt",
+       "fool",
+       "footpad",
+       "imbecile",
+       "knave",
+       "maledict",
+       "miscreant",
+       "niddering",
+       "poltroon",
+       "rattlepate",
+       "reprobate",
+       "scapegrace",
+       "varlet",
+       "villein",      /* (sic.) */
+       "wittol",
+       "worm",
+       "wretch",
+};
+
+const char * const random_malediction[] = {
+       "Hell shall soon claim thy remains,",
+       "I chortle at thee, thou pathetic",
+       "Prepare to die, thou",
+       "Resistance is useless,",
+       "Surrender or die, thou",
+       "There shall be no mercy, thou",
+       "Thou shalt repent of thy cunning,",
+       "Thou art as a flea to me,",
+       "Thou art doomed,",
+       "Thy fate is sealed,",
+       "Verily, thou shalt be one dead"
+};
+
+/* Insult or intimidate the player */
+void
+cuss(mtmp)
+register struct monst  *mtmp;
+{
+       if (mtmp->iswiz) {
+           if (!rn2(5))  /* typical bad guy action */
+               pline("%s laughs fiendishly.", Monnam(mtmp));
+           else
+               if (u.uhave.amulet && !rn2(SIZE(random_insult)))
+                   verbalize("Relinquish the amulet, %s!",
+                         random_insult[rn2(SIZE(random_insult))]);
+               else if (u.uhp < 5 && !rn2(2))  /* Panic */
+                   verbalize(rn2(2) ?
+                         "Even now thy life force ebbs, %s!" :
+                         "Savor thy breath, %s, it be thy last!",
+                         random_insult[rn2(SIZE(random_insult))]);
+               else if (mtmp->mhp < 5 && !rn2(2))      /* Parthian shot */
+                   verbalize(rn2(2) ?
+                             "I shall return." :
+                             "I'll be back.");
+               else
+                   verbalize("%s %s!",
+                         random_malediction[rn2(SIZE(random_malediction))],
+                         random_insult[rn2(SIZE(random_insult))]);
+       } else if(is_lminion(mtmp)) {
+               com_pager(rn2(QTN_ANGELIC - 1 + (Hallucination ? 1 : 0)) +
+                             QT_ANGELIC);
+       } else {
+           if (!rn2(5))
+               pline("%s casts aspersions on your ancestry.", Monnam(mtmp));
+           else
+               com_pager(rn2(QTN_DEMONIC) + QT_DEMONIC);
+       }
+}
+
+#endif /* OVLB */
+
+/*wizard.c*/
diff --git a/src/worm.c b/src/worm.c
new file mode 100644 (file)
index 0000000..0380e3f
--- /dev/null
@@ -0,0 +1,748 @@
+/*     SCCS Id: @(#)worm.c     3.4     1995/01/28      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "lev.h"
+
+#define newseg()               (struct wseg *) alloc(sizeof(struct wseg))
+#define dealloc_seg(wseg)      free((genericptr_t) (wseg))
+
+/* worm segment structure */
+struct wseg {
+    struct wseg *nseg;
+    xchar  wx, wy;     /* the segment's position */
+};
+
+STATIC_DCL void FDECL(toss_wsegs, (struct wseg *,BOOLEAN_P));
+STATIC_DCL void FDECL(shrink_worm, (int));
+STATIC_DCL void FDECL(random_dir, (XCHAR_P,XCHAR_P,xchar *,xchar *));
+STATIC_DCL struct wseg *FDECL(create_worm_tail, (int));
+
+/*  Description of long worm implementation.
+ *
+ *  Each monst struct of the head of a tailed worm has a wormno set to
+ *                     1 <= wormno < MAX_NUM_WORMS
+ *  If wormno == 0 this does not mean that the monster is not a worm,
+ *  it just means that the monster does not have a long worm tail.
+ *
+ *  The actual segments of a worm are not full blown monst structs.
+ *  They are small wseg structs, and their position in the levels.monsters[][]
+ *  array is held by the monst struct of the head of the worm.  This makes
+ *  things like probing and hit point bookkeeping much easier.
+ *
+ *  The segments of the long worms on a level are kept as an array of
+ *  singly threaded linked lists.  The wormno variable is used as an index
+ *  for these segment arrays.
+ *
+ *  wtails:    The first (starting struct) of a linked list.  This points
+ *             to the tail (last) segment of the worm.
+ *
+ *  wheads:    The last (end) of a linked list of segments.  This points to
+ *             the segment that is at the same position as the real monster
+ *             (the head).  Note that the segment that wheads[wormno] points
+ *             to, is not displayed.  It is simply there to keep track of
+ *             where the head came from, so that worm movement and display are
+ *             simplified later.
+ *             Keeping the head segment of the worm at the end of the list
+ *             of tail segments is an endless source of confusion, but it is
+ *             necessary.
+ *             From now on, we will use "start" and "end" to refer to the
+ *             linked list and "head" and "tail" to refer to the worm.
+ *
+ *  One final worm array is:
+ *
+ *  wgrowtime: This tells us when to add another segment to the worm.
+ *
+ *  When a worm is moved, we add a new segment at the head, and delete the
+ *  segment at the tail (unless we want it to grow).  This new head segment is
+ *  located in the same square as the actual head of the worm.  If we want
+ *  to grow the worm, we don't delete the tail segment, and we give the worm
+ *  extra hit points, which possibly go into its maximum.
+ *
+ *  Non-moving worms (worm_nomove) are assumed to be surrounded by their own
+ *  tail, and, thus, shrink instead of grow (as their tails keep going while
+ *  their heads are stopped short).  In this case, we delete the last tail
+ *  segment, and remove hit points from the worm.
+ */
+
+struct wseg *wheads[MAX_NUM_WORMS]   = DUMMY, *wtails[MAX_NUM_WORMS] = DUMMY;
+long       wgrowtime[MAX_NUM_WORMS] = DUMMY;
+
+/*
+ *  get_wormno()
+ *
+ *  Find an unused worm tail slot and return the index.  A zero means that
+ *  there are no slots available.  This means that the worm head can exist,
+ *  it just cannot ever grow a tail.
+ *
+ *  It, also, means that there is an optimisation to made.  The [0] positions
+ *  of the arrays are never used.  Meaning, we really *could* have one more
+ *  tailed worm on the level, or use a smaller array (using wormno - 1).
+ *
+ *  Implementation is left to the interested hacker.
+ */
+int
+get_wormno()
+{
+    register int new_wormno = 1;
+
+    while (new_wormno < MAX_NUM_WORMS) {
+       if (!wheads[new_wormno])
+           return new_wormno; /* found an empty wtails[] slot at new_wormno */
+       new_wormno++;
+    }
+
+    return(0); /* level infested with worms */
+}
+
+/*
+ *  initworm()
+ *
+ *  Use if (mon->wormno = get_wormno()) before calling this function!
+ *
+ *  Initialize the worm entry.  This will set up the worm grow time, and
+ *  create and initialize the dummy segment for wheads[] and wtails[].
+ *
+ *  If the worm has no tail (ie get_wormno() fails) then this function need
+ *  not be called.
+ */
+void
+initworm(worm, wseg_count)
+    struct monst *worm;
+    int wseg_count;
+{
+    register struct wseg *seg, *new_tail = create_worm_tail(wseg_count);
+    register int wnum = worm->wormno;
+
+/*  if (!wnum) return;  bullet proofing */
+
+    if (new_tail) {
+       wtails[wnum] = new_tail;
+       for (seg = new_tail; seg->nseg; seg = seg->nseg);
+       wheads[wnum] = seg;
+    } else {
+       wtails[wnum] = wheads[wnum] = seg = newseg();
+       seg->nseg    = (struct wseg *) 0;
+       seg->wx      = worm->mx;
+       seg->wy      = worm->my;
+    }
+    wgrowtime[wnum] = 0L;
+}
+
+
+/*
+ *  toss_wsegs()
+ *
+ *  Get rid of all worm segments on and following the given pointer curr.
+ *  The display may or may not need to be updated as we free the segments.
+ */
+STATIC_OVL
+void
+toss_wsegs(curr, display_update)
+    register struct wseg *curr;
+    register boolean display_update;
+{
+    register struct wseg *seg;
+
+    while (curr) {
+       seg = curr->nseg;
+
+       /* remove from level.monsters[][] */
+
+       /* need to check curr->wx for genocided while migrating_mon */
+       if (curr->wx) {
+           remove_monster(curr->wx, curr->wy);
+
+           /* update screen before deallocation */
+           if (display_update) newsym(curr->wx,curr->wy);
+       }
+
+       /* free memory used by the segment */
+       dealloc_seg(curr);
+       curr = seg;
+    }
+}
+
+
+/*
+ *  shrink_worm()
+ *
+ *  Remove the tail segment of the worm (the starting segment of the list).
+ */
+STATIC_OVL
+void
+shrink_worm(wnum)
+    int wnum;  /* worm number */
+{
+    struct wseg *seg;
+
+    if (wtails[wnum] == wheads[wnum]) return;  /* no tail */
+
+    seg = wtails[wnum];
+    wtails[wnum] = seg->nseg;
+    seg->nseg = (struct wseg *) 0;
+    toss_wsegs(seg, TRUE);
+}
+
+/*
+ *  worm_move()
+ *
+ *  Check for mon->wormno before calling this function!
+ *
+ *  Move the worm.  Maybe grow.
+ */
+void
+worm_move(worm)
+    struct monst *worm;
+{
+    register struct wseg *seg, *new_seg;       /* new segment */
+    register int        wnum = worm->wormno;   /* worm number */
+
+
+/*  if (!wnum) return;  bullet proofing */
+
+    /*
+     *  Place a segment at the old worm head.  The head has already moved.
+     */
+    seg = wheads[wnum];
+    place_worm_seg(worm, seg->wx, seg->wy);
+    newsym(seg->wx,seg->wy);           /* display the new segment */
+
+    /*
+     *  Create a new dummy segment head and place it at the end of the list.
+     */
+    new_seg       = newseg();
+    new_seg->wx   = worm->mx;
+    new_seg->wy   = worm->my;
+    new_seg->nseg = (struct wseg *) 0;
+    seg->nseg     = new_seg;           /* attach it to the end of the list */
+    wheads[wnum]  = new_seg;           /* move the end pointer */
+
+
+    if (wgrowtime[wnum] <= moves) {
+       if (!wgrowtime[wnum])
+           wgrowtime[wnum] = moves + rnd(5);
+       else
+           wgrowtime[wnum] += rn1(15, 3);
+       worm->mhp += 3;
+       if (worm->mhp > MHPMAX) worm->mhp = MHPMAX;
+       if (worm->mhp > worm->mhpmax) worm->mhpmax = worm->mhp;
+    } else
+       /* The worm doesn't grow, so the last segment goes away. */
+       shrink_worm(wnum);
+}
+
+/*
+ *  worm_nomove()
+ *
+ *  Check for mon->wormno before calling this function!
+ *
+ *  The worm don't move so it should shrink.
+ */
+void
+worm_nomove(worm)
+    register struct monst *worm;
+{
+    shrink_worm((int) worm->wormno);   /* shrink */
+
+    if (worm->mhp > 3)
+       worm->mhp -= 3;         /* mhpmax not changed ! */
+    else
+       worm->mhp = 1;
+}
+
+/*
+ *  wormgone()
+ *
+ *  Check for mon->wormno before calling this function!
+ *
+ *  Kill a worm tail.
+ */
+void
+wormgone(worm)
+    register struct monst *worm;
+{
+    register int wnum = worm->wormno;
+
+/*  if (!wnum) return;  bullet proofing */
+
+    worm->wormno = 0;
+
+    /*  This will also remove the real monster (ie 'w') from the its
+     *  position in level.monsters[][].
+     */
+    toss_wsegs(wtails[wnum], TRUE);
+
+    wheads[wnum] = wtails[wnum] = (struct wseg *) 0;
+}
+
+/*
+ *  wormhitu()
+ *
+ *  Check for mon->wormno before calling this function!
+ *
+ *  If the hero is near any part of the worm, the worm will try to attack.
+ */
+void
+wormhitu(worm)
+    register struct monst *worm;
+{
+    register int wnum = worm->wormno;
+    register struct wseg *seg;
+
+/*  if (!wnum) return;  bullet proofing */
+
+/*  This does not work right now because mattacku() thinks that the head is
+ *  out of range of the player.  We might try to kludge, and bring the head
+ *  within range for a tiny moment, but this needs a bit more looking at
+ *  before we decide to do this.
+ */
+    for (seg = wtails[wnum]; seg; seg = seg->nseg)
+       if (distu(seg->wx, seg->wy) < 3)
+           (void) mattacku(worm);
+}
+
+/*  cutworm()
+ *
+ *  Check for mon->wormno before calling this function!
+ *
+ *  When hitting a worm (worm) at position x, y, with a weapon (weap),
+ *  there is a chance that the worm will be cut in half, and a chance
+ *  that both halves will survive.
+ */
+void
+cutworm(worm, x, y, weap)
+    struct monst *worm;
+    xchar x,y;
+    struct obj *weap;
+{
+    register struct wseg  *curr, *new_tail;
+    register struct monst *new_worm;
+    int wnum = worm->wormno;
+    int cut_chance, new_wnum;
+
+    if (!wnum) return; /* bullet proofing */
+
+    if (x == worm->mx && y == worm->my) return;                /* hit on head */
+
+    /* cutting goes best with a bladed weapon */
+    cut_chance = rnd(20);      /* Normally  1-16 does not cut */
+                               /* Normally 17-20 does */
+
+    if (weap && is_blade(weap))        /* With a blade 1- 6 does not cut */
+       cut_chance += 10;       /*              7-20 does */
+
+    if (cut_chance < 17) return;       /* not good enough */
+
+    /* Find the segment that was attacked. */
+    curr = wtails[wnum];
+
+    while ( (curr->wx != x) || (curr->wy != y) ) {
+       curr = curr->nseg;
+       if (!curr) {
+           impossible("cutworm: no segment at (%d,%d)", (int) x, (int) y);
+           return;
+       }
+    }
+
+    /* If this is the tail segment, then the worm just loses it. */
+    if (curr == wtails[wnum]) {
+       shrink_worm(wnum);
+       return;
+    }
+
+    /*
+     *  Split the worm.  The tail for the new worm is the old worm's tail.
+     *  The tail for the old worm is the segment that follows "curr",
+     *  and "curr" becomes the dummy segment under the new head.
+     */
+    new_tail = wtails[wnum];
+    wtails[wnum] = curr->nseg;
+    curr->nseg = (struct wseg *) 0;    /* split the worm */
+
+    /*
+     *  At this point, the old worm is correct.  Any new worm will have
+     *  it's head at "curr" and its tail at "new_tail".
+     */
+
+    /* Sometimes the tail end dies. */
+    if (rn2(3) || !(new_wnum = get_wormno())) {
+       if (flags.mon_moving)
+           pline("Part of the tail of %s is cut off.", mon_nam(worm));
+       else
+           You("cut part of the tail off of %s.", mon_nam(worm));
+       toss_wsegs(new_tail, TRUE);
+       if (worm->mhp > 1) worm->mhp /= 2;
+       return;
+    }
+
+    remove_monster(x, y);              /* clone_mon puts new head here */
+    new_worm = clone_mon(worm, x, y);
+    new_worm->wormno = new_wnum;       /* affix new worm number */
+
+    /* Devalue the monster level of both halves of the worm. */
+    worm->m_lev = ((unsigned)worm->m_lev <= 3) ?
+                  (unsigned)worm->m_lev : max((unsigned)worm->m_lev - 2, 3);
+    new_worm->m_lev = worm->m_lev;
+
+    /* Calculate the mhp on the new_worm for the (lower) monster level. */
+    new_worm->mhpmax = new_worm->mhp = d((int)new_worm->m_lev, 8);
+
+    /* Calculate the mhp on the old worm for the (lower) monster level. */
+    if (worm->m_lev > 3) {
+       worm->mhpmax = d((int)worm->m_lev, 8);
+       if (worm->mhpmax < worm->mhp) worm->mhp = worm->mhpmax;
+    }
+
+    wtails[new_wnum] = new_tail;       /* We've got all the info right now */
+    wheads[new_wnum] = curr;           /* so we can do this faster than    */
+    wgrowtime[new_wnum] = 0L;          /* trying to call initworm().       */
+
+    /* Place the new monster at all the segment locations. */
+    place_wsegs(new_worm);
+
+    if (flags.mon_moving)
+       pline("%s is cut in half.", Monnam(worm));
+    else
+       You("cut %s in half.", mon_nam(worm));
+}
+
+
+/*
+ *  see_wsegs()
+ *
+ *  Refresh all of the segments of the given worm.  This is only called
+ *  from see_monster() in display.c or when a monster goes minvis.  It
+ *  is located here for modularity.
+ */
+void
+see_wsegs(worm)
+    struct monst *worm;
+{
+    struct wseg *curr = wtails[worm->wormno];
+
+/*  if (!mtmp->wormno) return;  bullet proofing */
+
+    while (curr != wheads[worm->wormno]) {
+       newsym(curr->wx,curr->wy);
+       curr = curr->nseg;
+    }
+}
+
+/*
+ *  detect_wsegs()
+ *
+ *  Display all of the segments of the given worm for detection.
+ */
+void
+detect_wsegs(worm, use_detection_glyph)
+    struct monst *worm;
+    boolean use_detection_glyph;
+{
+    int num;
+    struct wseg *curr = wtails[worm->wormno];
+
+/*  if (!mtmp->wormno) return;  bullet proofing */
+
+    while (curr != wheads[worm->wormno]) {
+       num = use_detection_glyph ?
+               detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)) :
+               monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL));
+       show_glyph(curr->wx,curr->wy,num);
+       curr = curr->nseg;
+    }
+}
+
+
+/*
+ *  save_worm()
+ *
+ *  Save the worm information for later use.  The count is the number
+ *  of segments, including the dummy.  Called from save.c.
+ */
+void
+save_worm(fd, mode)
+    int fd, mode;
+{
+    int i;
+    int count;
+    struct wseg *curr, *temp;
+
+    if (perform_bwrite(mode)) {
+       for (i = 1; i < MAX_NUM_WORMS; i++) {
+           for (count = 0, curr = wtails[i]; curr; curr = curr->nseg) count++;
+           /* Save number of segments */
+           bwrite(fd, (genericptr_t) &count, sizeof(int));
+           /* Save segment locations of the monster. */
+           if (count) {
+               for (curr = wtails[i]; curr; curr = curr->nseg) {
+                   bwrite(fd, (genericptr_t) &(curr->wx), sizeof(xchar));
+                   bwrite(fd, (genericptr_t) &(curr->wy), sizeof(xchar));
+               }
+           }
+       }
+       bwrite(fd, (genericptr_t) wgrowtime, sizeof(wgrowtime));
+    }
+
+    if (release_data(mode)) {
+       /* Free the segments only.  savemonchn() will take care of the
+        * monsters. */
+       for (i = 1; i < MAX_NUM_WORMS; i++) {
+           if (!(curr = wtails[i])) continue;
+
+           while (curr) {
+               temp = curr->nseg;
+               dealloc_seg(curr);              /* free the segment */
+               curr = temp;
+           }
+           wheads[i] = wtails[i] = (struct wseg *) 0;
+       }
+    }
+
+}
+
+/*
+ *  rest_worm()
+ *
+ *  Restore the worm information from the save file.  Called from restore.c
+ */
+void
+rest_worm(fd)
+    int fd;
+{
+    int i, j, count;
+    struct wseg *curr, *temp;
+
+    for (i = 1; i < MAX_NUM_WORMS; i++) {
+       mread(fd, (genericptr_t) &count, sizeof(int));
+       if (!count) continue;   /* none */
+
+       /* Get the segments. */
+       for (curr = (struct wseg *) 0, j = 0; j < count; j++) {
+           temp = newseg();
+           temp->nseg = (struct wseg *) 0;
+           mread(fd, (genericptr_t) &(temp->wx), sizeof(xchar));
+           mread(fd, (genericptr_t) &(temp->wy), sizeof(xchar));
+           if (curr)
+               curr->nseg = temp;
+           else
+               wtails[i] = temp;
+           curr = temp;
+       }
+       wheads[i] = curr;
+    }
+    mread(fd, (genericptr_t) wgrowtime, sizeof(wgrowtime));
+}
+
+/*
+ *  place_wsegs()
+ *
+ *  Place the segments of the given worm.  Called from restore.c
+ */
+void
+place_wsegs(worm)
+    struct monst *worm;
+{
+    struct wseg *curr = wtails[worm->wormno];
+
+/*  if (!mtmp->wormno) return;  bullet proofing */
+
+    while (curr != wheads[worm->wormno]) {
+       place_worm_seg(worm,curr->wx,curr->wy);
+       curr = curr->nseg;
+    }
+}
+
+/*
+ *  remove_worm()
+ *
+ *  This function is equivalent to the remove_monster #define in
+ *  rm.h, only it will take the worm *and* tail out of the levels array.
+ *  It does not get rid of (dealloc) the worm tail structures, and it does
+ *  not remove the mon from the fmon chain.
+ */
+void
+remove_worm(worm)
+    register struct monst *worm;
+{
+    register struct wseg *curr = wtails[worm->wormno];
+
+/*  if (!mtmp->wormno) return;  bullet proofing */
+
+    while (curr) {
+       remove_monster(curr->wx, curr->wy);
+       newsym(curr->wx, curr->wy);
+       curr = curr->nseg;
+    }
+}
+
+/*
+ *  place_worm_tail_randomly()
+ *
+ *  Place a worm tail somewhere on a level behind the head.
+ *  This routine essentially reverses the order of the wsegs from head
+ *  to tail while placing them.
+ *  x, and y are most likely the worm->mx, and worm->my, but don't *need* to
+ *  be, if somehow the head is disjoint from the tail.
+ */
+void
+place_worm_tail_randomly(worm, x, y)
+    struct monst *worm;
+    xchar x, y;
+{
+    int wnum = worm->wormno;
+    struct wseg *curr = wtails[wnum];
+    struct wseg *new_tail;
+    register xchar ox = x, oy = y;
+
+/*  if (!wnum) return;  bullet proofing */
+
+    if (wnum && (!wtails[wnum] || !wheads[wnum]) ) {
+       impossible("place_worm_tail_randomly: wormno is set without a tail!");
+       return;
+    }
+
+    wheads[wnum] = new_tail = curr;
+    curr = curr->nseg;
+    new_tail->nseg = (struct wseg *) 0;
+    new_tail->wx = x;
+    new_tail->wy = y;
+
+    while(curr)  {
+       xchar nx, ny;
+       char tryct = 0;
+
+       /* pick a random direction from x, y and search for goodpos() */
+
+       do {
+           random_dir(ox, oy, &nx, &ny);
+       } while (!goodpos(nx, ny, worm, 0) && (tryct++ < 50));
+
+       if (tryct < 50)  {
+           place_worm_seg(worm, nx, ny);
+           curr->wx = ox = nx;
+           curr->wy = oy = ny;
+           wtails[wnum] = curr;
+           curr = curr->nseg;
+           wtails[wnum]->nseg = new_tail;
+           new_tail = wtails[wnum];
+           newsym(nx, ny);
+       } else {                        /* Oops.  Truncate because there was */
+           toss_wsegs(curr, FALSE);    /* no place for the rest of it */
+           curr = (struct wseg *) 0;
+       }
+    }
+}
+
+/*
+ * Given a coordinate x, y.
+ * return in *nx, *ny, the coordinates of one of the <= 8 squares adjoining.
+ *
+ * This function, and the loop it serves, could be eliminated by coding
+ * enexto() with a search radius.
+ */
+STATIC_OVL
+void
+random_dir(x, y, nx, ny)
+    register xchar   x,   y;
+    register xchar *nx, *ny;
+{
+    *nx = x;
+    *ny = y;
+
+    *nx += (x > 1 ?                    /* extreme left ? */
+               (x < COLNO ?             /* extreme right ? */
+                       (rn2(3) - 1)      /* neither so +1, 0, or -1 */
+               :       -rn2(2))         /* 0, or -1 */
+          :    rn2(2));                /* 0, or 1 */
+
+    *ny += (*nx == x ?                 /* same kind of thing with y */
+               (y > 1 ?
+                   (y < ROWNO ?
+                       (rn2(2) ?
+                           1
+                       :   -1)
+                   :   -1)
+               :   1)
+           :   (y > 1 ?
+                   (y < ROWNO ?
+                       (rn2(3) - 1)
+                   :   -rn2(2))
+               :   rn2(2)));
+}
+
+/*  count_wsegs()
+ *
+ *  returns
+ *  the number of visible segments that a worm has.
+ */
+
+int
+count_wsegs(mtmp)
+    struct monst *mtmp;
+{
+    register int i=0;
+    register struct wseg *curr = (wtails[mtmp->wormno])->nseg;
+
+/*  if (!mtmp->wormno) return 0;  bullet proofing */
+
+    while (curr) {
+       i++;
+       curr = curr->nseg;
+    }
+
+    return i;
+}
+
+/*  create_worm_tail()
+ *
+ *  will create a worm tail chain of (num_segs + 1) and return a pointer to it.
+ */
+STATIC_OVL
+struct wseg *
+create_worm_tail(num_segs)
+    int num_segs;
+{
+    register int i=0;
+    register struct wseg *new_tail, *curr;
+
+    if (!num_segs) return (struct wseg *)0;
+
+    new_tail = curr = newseg();
+    curr->nseg = (struct wseg *)0;
+    curr->wx = 0;
+    curr->wy = 0;
+
+    while (i < num_segs) {
+       curr->nseg = newseg();
+       curr = curr->nseg;
+       curr->nseg = (struct wseg *)0;
+       curr->wx = 0;
+       curr->wy = 0;
+       i++;
+    }
+
+    return (new_tail);
+}
+
+/*  worm_known()
+ *
+ *  Is any segment of this worm in viewing range?  Note: caller must check
+ *  invisibility and telepathy (which should only show the head anyway).
+ *  Mostly used in the canseemon() macro.
+ */
+boolean
+worm_known(worm)
+struct monst *worm;
+{
+    struct wseg *curr = wtails[worm->wormno];
+
+    while (curr) {
+       if(cansee(curr->wx,curr->wy)) return TRUE;
+       curr = curr->nseg;
+    }
+    return FALSE;
+}
+
+/*worm.c*/
diff --git a/src/worn.c b/src/worn.c
new file mode 100644 (file)
index 0000000..61a239c
--- /dev/null
@@ -0,0 +1,794 @@
+/*     SCCS Id: @(#)worn.c     3.4     2003/01/08      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+STATIC_DCL void FDECL(m_lose_armor, (struct monst *,struct obj *));
+STATIC_DCL void FDECL(m_dowear_type, (struct monst *,long, BOOLEAN_P, BOOLEAN_P));
+STATIC_DCL int FDECL(extra_pref, (struct monst *, struct obj *));
+
+const struct worn {
+       long w_mask;
+       struct obj **w_obj;
+} worn[] = {
+       { W_ARM, &uarm },
+       { W_ARMC, &uarmc },
+       { W_ARMH, &uarmh },
+       { W_ARMS, &uarms },
+       { W_ARMG, &uarmg },
+       { W_ARMF, &uarmf },
+#ifdef TOURIST
+       { W_ARMU, &uarmu },
+#endif
+       { W_RINGL, &uleft },
+       { W_RINGR, &uright },
+       { W_WEP, &uwep },
+       { W_SWAPWEP, &uswapwep },
+       { W_QUIVER, &uquiver },
+       { W_AMUL, &uamul },
+       { W_TOOL, &ublindf },
+       { W_BALL, &uball },
+       { W_CHAIN, &uchain },
+       { 0, 0 }
+};
+
+/* This only allows for one blocking item per property */
+#define w_blocks(o,m) \
+               ((o->otyp == MUMMY_WRAPPING && ((m) & W_ARMC)) ? INVIS : \
+                (o->otyp == CORNUTHAUM && ((m) & W_ARMH) && \
+                       !Role_if(PM_WIZARD)) ? CLAIRVOYANT : 0)
+               /* note: monsters don't have clairvoyance, so your role
+                  has no significant effect on their use of w_blocks() */
+
+
+/* Updated to use the extrinsic and blocked fields. */
+void
+setworn(obj, mask)
+register struct obj *obj;
+long mask;
+{
+       register const struct worn *wp;
+       register struct obj *oobj;
+       register int p;
+
+       if ((mask & (W_ARM|I_SPECIAL)) == (W_ARM|I_SPECIAL)) {
+           /* restoring saved game; no properties are conferred via skin */
+           uskin = obj;
+        /* assert( !uarm ); */
+       } else {
+           for(wp = worn; wp->w_mask; wp++) if(wp->w_mask & mask) {
+               oobj = *(wp->w_obj);
+               if(oobj && !(oobj->owornmask & wp->w_mask))
+                       impossible("Setworn: mask = %ld.", wp->w_mask);
+               if(oobj) {
+                   if (u.twoweap && (oobj->owornmask & (W_WEP|W_SWAPWEP)))
+                       u.twoweap = 0;
+                   oobj->owornmask &= ~wp->w_mask;
+                   if (wp->w_mask & ~(W_SWAPWEP|W_QUIVER)) {
+                       /* leave as "x = x <op> y", here and below, for broken
+                        * compilers */
+                       p = objects[oobj->otyp].oc_oprop;
+                       u.uprops[p].extrinsic =
+                                       u.uprops[p].extrinsic & ~wp->w_mask;
+                       if ((p = w_blocks(oobj,mask)) != 0)
+                           u.uprops[p].blocked &= ~wp->w_mask;
+                       if (oobj->oartifact)
+                           set_artifact_intrinsic(oobj, 0, mask);
+                   }
+               }
+               *(wp->w_obj) = obj;
+               if(obj) {
+                   obj->owornmask |= wp->w_mask;
+                   /* Prevent getting/blocking intrinsics from wielding
+                    * potions, through the quiver, etc.
+                    * Allow weapon-tools, too.
+                    * wp_mask should be same as mask at this point.
+                    */
+                   if (wp->w_mask & ~(W_SWAPWEP|W_QUIVER)) {
+                       if (obj->oclass == WEAPON_CLASS || is_weptool(obj) ||
+                                           mask != W_WEP) {
+                           p = objects[obj->otyp].oc_oprop;
+                           u.uprops[p].extrinsic =
+                                       u.uprops[p].extrinsic | wp->w_mask;
+                           if ((p = w_blocks(obj, mask)) != 0)
+                               u.uprops[p].blocked |= wp->w_mask;
+                       }
+                       if (obj->oartifact)
+                           set_artifact_intrinsic(obj, 1, mask);
+                   }
+               }
+           }
+       }
+       update_inventory();
+}
+
+/* called e.g. when obj is destroyed */
+/* Updated to use the extrinsic and blocked fields. */
+void
+setnotworn(obj)
+register struct obj *obj;
+{
+       register const struct worn *wp;
+       register int p;
+
+       if (!obj) return;
+       if (obj == uwep || obj == uswapwep) u.twoweap = 0;
+       for(wp = worn; wp->w_mask; wp++)
+           if(obj == *(wp->w_obj)) {
+               *(wp->w_obj) = 0;
+               p = objects[obj->otyp].oc_oprop;
+               u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask;
+               obj->owornmask &= ~wp->w_mask;
+               if (obj->oartifact)
+                   set_artifact_intrinsic(obj, 0, wp->w_mask);
+               if ((p = w_blocks(obj,wp->w_mask)) != 0)
+                   u.uprops[p].blocked &= ~wp->w_mask;
+           }
+       update_inventory();
+}
+
+void
+mon_set_minvis(mon)
+struct monst *mon;
+{
+       mon->perminvis = 1;
+       if (!mon->invis_blkd) {
+           mon->minvis = 1;
+           newsym(mon->mx, mon->my);           /* make it disappear */
+           if (mon->wormno) see_wsegs(mon);    /* and any tail too */
+       }
+}
+
+void
+mon_adjust_speed(mon, adjust, obj)
+struct monst *mon;
+int adjust;    /* positive => increase speed, negative => decrease */
+struct obj *obj;       /* item to make known if effect can be seen */
+{
+    struct obj *otmp;
+    boolean give_msg = !in_mklev, petrify = FALSE;
+    unsigned int oldspeed = mon->mspeed;
+
+    switch (adjust) {
+     case  2:
+       mon->permspeed = MFAST;
+       give_msg = FALSE;       /* special case monster creation */
+       break;
+     case  1:
+       if (mon->permspeed == MSLOW) mon->permspeed = 0;
+       else mon->permspeed = MFAST;
+       break;
+     case  0:                  /* just check for worn speed boots */
+       break;
+     case -1:
+       if (mon->permspeed == MFAST) mon->permspeed = 0;
+       else mon->permspeed = MSLOW;
+       break;
+     case -2:
+       mon->permspeed = MSLOW;
+       give_msg = FALSE;       /* (not currently used) */
+       break;
+     case -3:                  /* petrification */
+       /* take away intrinsic speed but don't reduce normal speed */
+       if (mon->permspeed == MFAST) mon->permspeed = 0;
+       petrify = TRUE;
+       break;
+    }
+
+    for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
+       if (otmp->owornmask && objects[otmp->otyp].oc_oprop == FAST)
+           break;
+    if (otmp)          /* speed boots */
+       mon->mspeed = MFAST;
+    else
+       mon->mspeed = mon->permspeed;
+
+    if (give_msg && (mon->mspeed != oldspeed || petrify) && canseemon(mon)) {
+       /* fast to slow (skipping intermediate state) or vice versa */
+       const char *howmuch = (mon->mspeed + oldspeed == MFAST + MSLOW) ?
+                               "much " : "";
+
+       if (petrify) {
+           /* mimic the player's petrification countdown; "slowing down"
+              even if fast movement rate retained via worn speed boots */
+           if (flags.verbose) pline("%s is slowing down.", Monnam(mon));
+       } else if (adjust > 0 || mon->mspeed == MFAST)
+           pline("%s is suddenly moving %sfaster.", Monnam(mon), howmuch);
+       else
+           pline("%s seems to be moving %sslower.", Monnam(mon), howmuch);
+
+       /* might discover an object if we see the speed change happen, but
+          avoid making possibly forgotten book known when casting its spell */
+       if (obj != 0 && obj->dknown &&
+               objects[obj->otyp].oc_class != SPBOOK_CLASS)
+           makeknown(obj->otyp);
+    }
+}
+
+/* armor put on or taken off; might be magical variety */
+void
+update_mon_intrinsics(mon, obj, on, silently)
+struct monst *mon;
+struct obj *obj;
+boolean on, silently;
+{
+    int unseen;
+    uchar mask;
+    struct obj *otmp;
+    int which = (int) objects[obj->otyp].oc_oprop;
+
+    unseen = !canseemon(mon);
+    if (!which) goto maybe_blocks;
+
+    if (on) {
+       switch (which) {
+        case INVIS:
+           mon->minvis = !mon->invis_blkd;
+           break;
+        case FAST:
+         {
+           boolean save_in_mklev = in_mklev;
+           if (silently) in_mklev = TRUE;
+           mon_adjust_speed(mon, 0, obj);
+           in_mklev = save_in_mklev;
+           break;
+         }
+       /* properties handled elsewhere */
+        case ANTIMAGIC:
+        case REFLECTING:
+           break;
+       /* properties which have no effect for monsters */
+        case CLAIRVOYANT:
+        case STEALTH:
+        case TELEPAT:
+           break;
+       /* properties which should have an effect but aren't implemented */
+        case LEVITATION:
+        case WWALKING:
+           break;
+       /* properties which maybe should have an effect but don't */
+        case DISPLACED:
+        case FUMBLING:
+        case JUMPING:
+        case PROTECTION:
+           break;
+        default:
+           if (which <= 8) {   /* 1 thru 8 correspond to MR_xxx mask values */
+               /* FIRE,COLD,SLEEP,DISINT,SHOCK,POISON,ACID,STONE */
+               mask = (uchar) (1 << (which - 1));
+               mon->mintrinsics |= (unsigned short) mask;
+           }
+           break;
+       }
+    } else {       /* off */
+       switch (which) {
+        case INVIS:
+           mon->minvis = mon->perminvis;
+           break;
+        case FAST:
+         {
+           boolean save_in_mklev = in_mklev;
+           if (silently) in_mklev = TRUE;
+           mon_adjust_speed(mon, 0, obj);
+           in_mklev = save_in_mklev;
+           break;
+         }
+        case FIRE_RES:
+        case COLD_RES:
+        case SLEEP_RES:
+        case DISINT_RES:
+        case SHOCK_RES:
+        case POISON_RES:
+        case ACID_RES:
+        case STONE_RES:
+           mask = (uchar) (1 << (which - 1));
+           /* If the monster doesn't have this resistance intrinsically,
+              check whether any other worn item confers it.  Note that
+              we don't currently check for anything conferred via simply
+              carrying an object. */
+           if (!(mon->data->mresists & mask)) {
+               for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
+                   if (otmp->owornmask &&
+                           (int) objects[otmp->otyp].oc_oprop == which)
+                       break;
+               if (!otmp)
+                   mon->mintrinsics &= ~((unsigned short) mask);
+           }
+           break;
+        default:
+           break;
+       }
+    }
+
+ maybe_blocks:
+    /* obj->owornmask has been cleared by this point, so we can't use it.
+       However, since monsters don't wield armor, we don't have to guard
+       against that and can get away with a blanket worn-mask value. */
+    switch (w_blocks(obj,~0L)) {
+     case INVIS:
+       mon->invis_blkd = on ? 1 : 0;
+       mon->minvis = on ? 0 : mon->perminvis;
+       break;
+     default:
+       break;
+    }
+
+#ifdef STEED
+       if (!on && mon == u.usteed && obj->otyp == SADDLE)
+           dismount_steed(DISMOUNT_FELL);
+#endif
+
+    /* if couldn't see it but now can, or vice versa, update display */
+    if (!silently && (unseen ^ !canseemon(mon)))
+       newsym(mon->mx, mon->my);
+}
+
+int
+find_mac(mon)
+register struct monst *mon;
+{
+       register struct obj *obj;
+       int base = mon->data->ac;
+       long mwflags = mon->misc_worn_check;
+
+       for (obj = mon->minvent; obj; obj = obj->nobj) {
+           if (obj->owornmask & mwflags)
+               base -= ARM_BONUS(obj);
+               /* since ARM_BONUS is positive, subtracting it increases AC */
+       }
+       return base;
+}
+
+/* weapons are handled separately; rings and eyewear aren't used by monsters */
+
+/* Wear the best object of each type that the monster has.  During creation,
+ * the monster can put everything on at once; otherwise, wearing takes time.
+ * This doesn't affect monster searching for objects--a monster may very well
+ * search for objects it would not want to wear, because we don't want to
+ * check which_armor() each round.
+ *
+ * We'll let monsters put on shirts and/or suits under worn cloaks, but
+ * not shirts under worn suits.  This is somewhat arbitrary, but it's
+ * too tedious to have them remove and later replace outer garments,
+ * and preventing suits under cloaks makes it a little bit too easy for
+ * players to influence what gets worn.  Putting on a shirt underneath
+ * already worn body armor is too obviously buggy...
+ */
+void
+m_dowear(mon, creation)
+register struct monst *mon;
+boolean creation;
+{
+#define RACE_EXCEPTION TRUE
+       /* Note the restrictions here are the same as in dowear in do_wear.c
+        * except for the additional restriction on intelligence.  (Players
+        * are always intelligent, even if polymorphed).
+        */
+       if (verysmall(mon->data) || nohands(mon->data) || is_animal(mon->data))
+               return;
+       /* give mummies a chance to wear their wrappings
+        * and let skeletons wear their initial armor */
+       if (mindless(mon->data) && (!creation ||
+           (mon->data->mlet != S_MUMMY && mon->data != &mons[PM_SKELETON])))
+               return;
+
+       m_dowear_type(mon, W_AMUL, creation, FALSE);
+#ifdef TOURIST
+       /* can't put on shirt if already wearing suit */
+       if (!cantweararm(mon->data) || (mon->misc_worn_check & W_ARM))
+           m_dowear_type(mon, W_ARMU, creation, FALSE);
+#endif
+       /* treating small as a special case allows
+          hobbits, gnomes, and kobolds to wear cloaks */
+       if (!cantweararm(mon->data) || mon->data->msize == MZ_SMALL)
+           m_dowear_type(mon, W_ARMC, creation, FALSE);
+       m_dowear_type(mon, W_ARMH, creation, FALSE);
+       if (!MON_WEP(mon) || !bimanual(MON_WEP(mon)))
+           m_dowear_type(mon, W_ARMS, creation, FALSE);
+       m_dowear_type(mon, W_ARMG, creation, FALSE);
+       if (!slithy(mon->data) && mon->data->mlet != S_CENTAUR)
+           m_dowear_type(mon, W_ARMF, creation, FALSE);
+       if (!cantweararm(mon->data))
+           m_dowear_type(mon, W_ARM, creation, FALSE);
+       else
+           m_dowear_type(mon, W_ARM, creation, RACE_EXCEPTION);
+}
+
+STATIC_OVL void
+m_dowear_type(mon, flag, creation, racialexception)
+struct monst *mon;
+long flag;
+boolean creation;
+boolean racialexception;
+{
+       struct obj *old, *best, *obj;
+       int m_delay = 0;
+       int unseen = !canseemon(mon);
+       char nambuf[BUFSZ];
+
+       if (mon->mfrozen) return; /* probably putting previous item on */
+
+       /* Get a copy of monster's name before altering its visibility */
+       Strcpy(nambuf, See_invisible ? Monnam(mon) : mon_nam(mon));
+
+       old = which_armor(mon, flag);
+       if (old && old->cursed) return;
+       if (old && flag == W_AMUL) return; /* no such thing as better amulets */
+       best = old;
+
+       for(obj = mon->minvent; obj; obj = obj->nobj) {
+           switch(flag) {
+               case W_AMUL:
+                   if (obj->oclass != AMULET_CLASS ||
+                           (obj->otyp != AMULET_OF_LIFE_SAVING &&
+                               obj->otyp != AMULET_OF_REFLECTION))
+                       continue;
+                   best = obj;
+                   goto outer_break; /* no such thing as better amulets */
+#ifdef TOURIST
+               case W_ARMU:
+                   if (!is_shirt(obj)) continue;
+                   break;
+#endif
+               case W_ARMC:
+                   if (!is_cloak(obj)) continue;
+                   break;
+               case W_ARMH:
+                   if (!is_helmet(obj)) continue;
+                   /* (flimsy exception matches polyself handling) */
+                   if (has_horns(mon->data) && !is_flimsy(obj)) continue;
+                   break;
+               case W_ARMS:
+                   if (!is_shield(obj)) continue;
+                   break;
+               case W_ARMG:
+                   if (!is_gloves(obj)) continue;
+                   break;
+               case W_ARMF:
+                   if (!is_boots(obj)) continue;
+                   break;
+               case W_ARM:
+                   if (!is_suit(obj)) continue;
+                   if (racialexception && (racial_exception(mon, obj) < 1)) continue;
+                   break;
+           }
+           if (obj->owornmask) continue;
+           /* I'd like to define a VISIBLE_ARM_BONUS which doesn't assume the
+            * monster knows obj->spe, but if I did that, a monster would keep
+            * switching forever between two -2 caps since when it took off one
+            * it would forget spe and once again think the object is better
+            * than what it already has.
+            */
+           if (best && (ARM_BONUS(best) + extra_pref(mon,best) >= ARM_BONUS(obj) + extra_pref(mon,obj)))
+               continue;
+           best = obj;
+       }
+outer_break:
+       if (!best || best == old) return;
+
+       /* if wearing a cloak, account for the time spent removing
+          and re-wearing it when putting on a suit or shirt */
+       if ((flag == W_ARM
+#ifdef TOURIST
+         || flag == W_ARMU
+#endif
+                         ) && (mon->misc_worn_check & W_ARMC))
+           m_delay += 2;
+       /* when upgrading a piece of armor, account for time spent
+          taking off current one */
+       if (old)
+           m_delay += objects[old->otyp].oc_delay;
+
+       if (old) /* do this first to avoid "(being worn)" */
+           old->owornmask = 0L;
+       if (!creation) {
+           if (canseemon(mon)) {
+               char buf[BUFSZ];
+
+               if (old)
+                   Sprintf(buf, " removes %s and", distant_name(old, doname));
+               else
+                   buf[0] = '\0';
+               pline("%s%s puts on %s.", Monnam(mon),
+                     buf, distant_name(best,doname));
+           } /* can see it */
+           m_delay += objects[best->otyp].oc_delay;
+           mon->mfrozen = m_delay;
+           if (mon->mfrozen) mon->mcanmove = 0;
+       }
+       if (old)
+           update_mon_intrinsics(mon, old, FALSE, creation);
+       mon->misc_worn_check |= flag;
+       best->owornmask |= flag;
+       update_mon_intrinsics(mon, best, TRUE, creation);
+       /* if couldn't see it but now can, or vice versa, */
+       if (!creation && (unseen ^ !canseemon(mon))) {
+               if (mon->minvis && !See_invisible) {
+                       pline("Suddenly you cannot see %s.", nambuf);
+                       makeknown(best->otyp);
+               } /* else if (!mon->minvis) pline("%s suddenly appears!", Amonnam(mon)); */
+       }
+}
+#undef RACE_EXCEPTION
+
+struct obj *
+which_armor(mon, flag)
+struct monst *mon;
+long flag;
+{
+       register struct obj *obj;
+
+       for(obj = mon->minvent; obj; obj = obj->nobj)
+               if (obj->owornmask & flag) return obj;
+       return((struct obj *)0);
+}
+
+/* remove an item of armor and then drop it */
+STATIC_OVL void
+m_lose_armor(mon, obj)
+struct monst *mon;
+struct obj *obj;
+{
+       mon->misc_worn_check &= ~obj->owornmask;
+       if (obj->owornmask)
+           update_mon_intrinsics(mon, obj, FALSE, FALSE);
+       obj->owornmask = 0L;
+
+       obj_extract_self(obj);
+       place_object(obj, mon->mx, mon->my);
+       /* call stackobj() if we ever drop anything that can merge */
+       newsym(mon->mx, mon->my);
+}
+
+/* all objects with their bypass bit set should now be reset to normal */
+void
+clear_bypasses()
+{
+       struct obj *otmp, *nobj;
+       struct monst *mtmp;
+
+       for (otmp = fobj; otmp; otmp = nobj) {
+           nobj = otmp->nobj;
+           if (otmp->bypass) {
+               otmp->bypass = 0;
+               /* bypass will have inhibited any stacking, but since it's
+                  used for polymorph handling, the objects here probably
+                  have been transformed and won't be stacked in the usual
+                  manner afterwards; so don't bother with this */
+#if 0
+               if (objects[otmp->otyp].oc_merge) {
+                   xchar ox, oy;
+
+                   (void) get_obj_location(otmp, &ox, &oy, 0);
+                   stack_object(otmp);
+                   newsym(ox, oy);
+               }
+#endif /*0*/
+           }
+       }
+       /* invent and mydogs chains shouldn't matter here */
+       for (otmp = migrating_objs; otmp; otmp = otmp->nobj)
+           otmp->bypass = 0;
+       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+           if (DEADMONSTER(mtmp)) continue;
+           for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+               otmp->bypass = 0;
+       }
+       for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) {
+           for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+               otmp->bypass = 0;
+       }
+       flags.bypasses = FALSE;
+}
+
+void
+bypass_obj(obj)
+struct obj *obj;
+{
+       obj->bypass = 1;
+       flags.bypasses = TRUE;
+}
+
+void
+mon_break_armor(mon, polyspot)
+struct monst *mon;
+boolean polyspot;
+{
+       register struct obj *otmp;
+       struct permonst *mdat = mon->data;
+       boolean vis = cansee(mon->mx, mon->my);
+       boolean handless_or_tiny = (nohands(mdat) || verysmall(mdat));
+       const char *pronoun = mhim(mon),
+                       *ppronoun = mhis(mon);
+
+       if (breakarm(mdat)) {
+           if ((otmp = which_armor(mon, W_ARM)) != 0) {
+               if ((Is_dragon_scales(otmp) &&
+                       mdat == Dragon_scales_to_pm(otmp)) ||
+                   (Is_dragon_mail(otmp) && mdat == Dragon_mail_to_pm(otmp)))
+                   ;   /* no message here;
+                          "the dragon merges with his scaly armor" is odd
+                          and the monster's previous form is already gone */
+               else if (vis)
+                   pline("%s breaks out of %s armor!", Monnam(mon), ppronoun);
+               else
+                   You_hear("a cracking sound.");
+               m_useup(mon, otmp);
+           }
+           if ((otmp = which_armor(mon, W_ARMC)) != 0) {
+               if (otmp->oartifact) {
+                   if (vis)
+                       pline("%s %s falls off!", s_suffix(Monnam(mon)),
+                               cloak_simple_name(otmp));
+                   if (polyspot) bypass_obj(otmp);
+                   m_lose_armor(mon, otmp);
+               } else {
+                   if (vis)
+                       pline("%s %s tears apart!", s_suffix(Monnam(mon)),
+                               cloak_simple_name(otmp));
+                   else
+                       You_hear("a ripping sound.");
+                   m_useup(mon, otmp);
+               }
+           }
+#ifdef TOURIST
+           if ((otmp = which_armor(mon, W_ARMU)) != 0) {
+               if (vis)
+                   pline("%s shirt rips to shreds!", s_suffix(Monnam(mon)));
+               else
+                   You_hear("a ripping sound.");
+               m_useup(mon, otmp);
+           }
+#endif
+       } else if (sliparm(mdat)) {
+           if ((otmp = which_armor(mon, W_ARM)) != 0) {
+               if (vis)
+                   pline("%s armor falls around %s!",
+                                s_suffix(Monnam(mon)), pronoun);
+               else
+                   You_hear("a thud.");
+               if (polyspot) bypass_obj(otmp);
+               m_lose_armor(mon, otmp);
+           }
+           if ((otmp = which_armor(mon, W_ARMC)) != 0) {
+               if (vis) {
+                   if (is_whirly(mon->data))
+                       pline("%s %s falls, unsupported!",
+                                    s_suffix(Monnam(mon)), cloak_simple_name(otmp));
+                   else
+                       pline("%s shrinks out of %s %s!", Monnam(mon),
+                                               ppronoun, cloak_simple_name(otmp));
+               }
+               if (polyspot) bypass_obj(otmp);
+               m_lose_armor(mon, otmp);
+           }
+#ifdef TOURIST
+           if ((otmp = which_armor(mon, W_ARMU)) != 0) {
+               if (vis) {
+                   if (sliparm(mon->data))
+                       pline("%s seeps right through %s shirt!",
+                                       Monnam(mon), ppronoun);
+                   else
+                       pline("%s becomes much too small for %s shirt!",
+                                       Monnam(mon), ppronoun);
+               }
+               if (polyspot) bypass_obj(otmp);
+               m_lose_armor(mon, otmp);
+           }
+#endif
+       }
+       if (handless_or_tiny) {
+           /* [caller needs to handle weapon checks] */
+           if ((otmp = which_armor(mon, W_ARMG)) != 0) {
+               if (vis)
+                   pline("%s drops %s gloves%s!", Monnam(mon), ppronoun,
+                                       MON_WEP(mon) ? " and weapon" : "");
+               if (polyspot) bypass_obj(otmp);
+               m_lose_armor(mon, otmp);
+           }
+           if ((otmp = which_armor(mon, W_ARMS)) != 0) {
+               if (vis)
+                   pline("%s can no longer hold %s shield!", Monnam(mon),
+                                                               ppronoun);
+               else
+                   You_hear("a clank.");
+               if (polyspot) bypass_obj(otmp);
+               m_lose_armor(mon, otmp);
+           }
+       }
+       if (handless_or_tiny || has_horns(mdat)) {
+           if ((otmp = which_armor(mon, W_ARMH)) != 0 &&
+                   /* flimsy test for horns matches polyself handling */
+                   (handless_or_tiny || !is_flimsy(otmp))) {
+               if (vis)
+                   pline("%s helmet falls to the %s!",
+                         s_suffix(Monnam(mon)), surface(mon->mx, mon->my));
+               else
+                   You_hear("a clank.");
+               if (polyspot) bypass_obj(otmp);
+               m_lose_armor(mon, otmp);
+           }
+       }
+       if (handless_or_tiny || slithy(mdat) || mdat->mlet == S_CENTAUR) {
+           if ((otmp = which_armor(mon, W_ARMF)) != 0) {
+               if (vis) {
+                   if (is_whirly(mon->data))
+                       pline("%s boots fall away!",
+                                      s_suffix(Monnam(mon)));
+                   else pline("%s boots %s off %s feet!",
+                       s_suffix(Monnam(mon)),
+                       verysmall(mdat) ? "slide" : "are pushed", ppronoun);
+               }
+               if (polyspot) bypass_obj(otmp);
+               m_lose_armor(mon, otmp);
+           }
+       }
+#ifdef STEED
+       if (!can_saddle(mon)) {
+           if ((otmp = which_armor(mon, W_SADDLE)) != 0) {
+               if (polyspot) bypass_obj(otmp);
+               m_lose_armor(mon, otmp);
+               if (vis)
+                   pline("%s saddle falls off.", s_suffix(Monnam(mon)));
+           }
+           if (mon == u.usteed)
+               goto noride;
+       } else if (mon == u.usteed && !can_ride(mon)) {
+       noride:
+           You("can no longer ride %s.", mon_nam(mon));
+           if (touch_petrifies(u.usteed->data) &&
+                       !Stone_resistance && rnl(3)) {
+               char buf[BUFSZ];
+
+               You("touch %s.", mon_nam(u.usteed));
+               Sprintf(buf, "falling off %s",
+                               an(u.usteed->data->mname));
+               instapetrify(buf);
+           }
+           dismount_steed(DISMOUNT_FELL);
+       }
+#endif
+       return;
+}
+
+/* bias a monster's preferences towards armor that has special benefits. */
+/* currently only does speed boots, but might be expanded if monsters get to
+   use more armor abilities */
+static int
+extra_pref(mon, obj)
+struct monst *mon;
+struct obj *obj;
+{
+    if (obj) {
+       if (obj->otyp == SPEED_BOOTS && mon->permspeed != MFAST)
+           return 20;
+    }
+    return 0;
+}
+
+/*
+ * Exceptions to things based on race. Correctly checks polymorphed player race.
+ * Returns:
+ *      0 No exception, normal rules apply.
+ *      1 If the race/object combination is acceptable.
+ *     -1 If the race/object combination is unacceptable.
+ */
+int
+racial_exception(mon, obj)
+struct monst *mon;
+struct obj *obj;
+{
+    const struct permonst *ptr = raceptr(mon);
+
+    /* Acceptable Exceptions: */
+    /* Allow hobbits to wear elven armor - LoTR */
+    if (ptr == &mons[PM_HOBBIT] && is_elven_armor(obj))
+       return 1;
+    /* Unacceptable Exceptions: */
+    /* Checks for object that certain races should never use go here */
+    /* return -1; */
+
+    return 0;
+}
+/*worn.c*/
diff --git a/src/write.c b/src/write.c
new file mode 100644 (file)
index 0000000..669c7f1
--- /dev/null
@@ -0,0 +1,241 @@
+/*     SCCS Id: @(#)write.c    3.4     2001/11/29      */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+STATIC_DCL int FDECL(cost,(struct obj *));
+
+/*
+ * returns basecost of a scroll or a spellbook
+ */
+STATIC_OVL int
+cost(otmp)
+register struct obj *otmp;
+{
+
+       if (otmp->oclass == SPBOOK_CLASS)
+               return(10 * objects[otmp->otyp].oc_level);
+
+       switch (otmp->otyp) {
+# ifdef MAIL
+       case SCR_MAIL:
+               return(2);
+/*             break; */
+# endif
+       case SCR_LIGHT:
+       case SCR_GOLD_DETECTION:
+       case SCR_FOOD_DETECTION:
+       case SCR_MAGIC_MAPPING:
+       case SCR_AMNESIA:
+       case SCR_FIRE:
+       case SCR_EARTH:
+               return(8);
+/*             break; */
+       case SCR_DESTROY_ARMOR:
+       case SCR_CREATE_MONSTER:
+       case SCR_PUNISHMENT:
+               return(10);
+/*             break; */
+       case SCR_CONFUSE_MONSTER:
+               return(12);
+/*             break; */
+       case SCR_IDENTIFY:
+               return(14);
+/*             break; */
+       case SCR_ENCHANT_ARMOR:
+       case SCR_REMOVE_CURSE:
+       case SCR_ENCHANT_WEAPON:
+       case SCR_CHARGING:
+               return(16);
+/*             break; */
+       case SCR_SCARE_MONSTER:
+       case SCR_STINKING_CLOUD:
+       case SCR_TAMING:
+       case SCR_TELEPORTATION:
+               return(20);
+/*             break; */
+       case SCR_GENOCIDE:
+               return(30);
+/*             break; */
+       case SCR_BLANK_PAPER:
+       default:
+               impossible("You can't write such a weird scroll!");
+       }
+       return(1000);
+}
+
+static NEARDATA const char write_on[] = { SCROLL_CLASS, SPBOOK_CLASS, 0 };
+
+int
+dowrite(pen)
+register struct obj *pen;
+{
+       register struct obj *paper;
+       char namebuf[BUFSZ], *nm, *bp;
+       register struct obj *new_obj;
+       int basecost, actualcost;
+       int curseval;
+       char qbuf[QBUFSZ];
+       int first, last, i;
+       boolean by_descr = FALSE;
+       const char *typeword;
+
+       if (nohands(youmonst.data)) {
+           You("need hands to be able to write!");
+           return 0;
+       } else if (Glib) {
+           pline("%s from your %s.",
+                 Tobjnam(pen, "slip"), makeplural(body_part(FINGER)));
+           dropx(pen);
+           return 1;
+       }
+
+       /* get paper to write on */
+       paper = getobj(write_on,"write on");
+       if(!paper)
+               return(0);
+       typeword = (paper->oclass == SPBOOK_CLASS) ? "spellbook" : "scroll";
+       if(Blind && !paper->dknown) {
+               You("don't know if that %s is blank or not!", typeword);
+               return(1);
+       }
+       paper->dknown = 1;
+       if(paper->otyp != SCR_BLANK_PAPER && paper->otyp != SPE_BLANK_PAPER) {
+               pline("That %s is not blank!", typeword);
+               exercise(A_WIS, FALSE);
+               return(1);
+       }
+
+       /* what to write */
+       Sprintf(qbuf, "What type of %s do you want to write?", typeword);
+       getlin(qbuf, namebuf);
+       (void)mungspaces(namebuf);      /* remove any excess whitespace */
+       if(namebuf[0] == '\033' || !namebuf[0])
+               return(1);
+       nm = namebuf;
+       if (!strncmpi(nm, "scroll ", 7)) nm += 7;
+       else if (!strncmpi(nm, "spellbook ", 10)) nm += 10;
+       if (!strncmpi(nm, "of ", 3)) nm += 3;
+
+       if ((bp = strstri(nm, " armour")) != 0) {
+               (void)strncpy(bp, " armor ", 7);        /* won't add '\0' */
+               (void)mungspaces(bp + 1);       /* remove the extra space */
+       }
+
+       first = bases[(int)paper->oclass];
+       last = bases[(int)paper->oclass + 1] - 1;
+       for (i = first; i <= last; i++) {
+               /* extra shufflable descr not representing a real object */
+               if (!OBJ_NAME(objects[i])) continue;
+
+               if (!strcmpi(OBJ_NAME(objects[i]), nm))
+                       goto found;
+               if (!strcmpi(OBJ_DESCR(objects[i]), nm)) {
+                       by_descr = TRUE;
+                       goto found;
+               }
+       }
+
+       There("is no such %s!", typeword);
+       return 1;
+found:
+
+       if (i == SCR_BLANK_PAPER || i == SPE_BLANK_PAPER) {
+               You_cant("write that!");
+               pline("It's obscene!");
+               return 1;
+       } else if (i == SPE_BOOK_OF_THE_DEAD) {
+               pline("No mere dungeon adventurer could write that.");
+               return 1;
+       } else if (by_descr && paper->oclass == SPBOOK_CLASS &&
+                   !objects[i].oc_name_known) {
+               /* can't write unknown spellbooks by description */
+               pline(
+                 "Unfortunately you don't have enough information to go on.");
+               return 1;
+       }
+
+       /* KMH, conduct */
+       u.uconduct.literate++;
+
+       new_obj = mksobj(i, FALSE, FALSE);
+       new_obj->bknown = (paper->bknown && pen->bknown);
+
+       /* shk imposes a flat rate per use, not based on actual charges used */
+       check_unpaid(pen);
+
+       /* see if there's enough ink */
+       basecost = cost(new_obj);
+       if(pen->spe < basecost/2)  {
+               Your("marker is too dry to write that!");
+               obfree(new_obj, (struct obj *) 0);
+               return(1);
+       }
+
+       /* we're really going to write now, so calculate cost
+        */
+       actualcost = rn1(basecost/2,basecost/2);
+       curseval = bcsign(pen) + bcsign(paper);
+       exercise(A_WIS, TRUE);
+       /* dry out marker */
+       if (pen->spe < actualcost) {
+               pen->spe = 0;
+               Your("marker dries out!");
+               /* scrolls disappear, spellbooks don't */
+               if (paper->oclass == SPBOOK_CLASS) {
+                       pline_The(
+                      "spellbook is left unfinished and your writing fades.");
+                       update_inventory();     /* pen charges */
+               } else {
+                       pline_The("scroll is now useless and disappears!");
+                       useup(paper);
+               }
+               obfree(new_obj, (struct obj *) 0);
+               return(1);
+       }
+       pen->spe -= actualcost;
+
+       /* can't write if we don't know it - unless we're lucky */
+       if(!(objects[new_obj->otyp].oc_name_known) &&
+          !(objects[new_obj->otyp].oc_uname) &&
+          (rnl(Role_if(PM_WIZARD) ? 3 : 15))) {
+               You("%s to write that!", by_descr ? "fail" : "don't know how");
+               /* scrolls disappear, spellbooks don't */
+               if (paper->oclass == SPBOOK_CLASS) {
+                       You(
+       "write in your best handwriting:  \"My Diary\", but it quickly fades.");
+                       update_inventory();     /* pen charges */
+               } else {
+                       if (by_descr) {
+                           Strcpy(namebuf, OBJ_DESCR(objects[new_obj->otyp]));
+                           wipeout_text(namebuf, (6+MAXULEV - u.ulevel)/6, 0);
+                       } else
+                           Sprintf(namebuf, "%s was here!", plname);
+                       You("write \"%s\" and the scroll disappears.", namebuf);
+                       useup(paper);
+               }
+               obfree(new_obj, (struct obj *) 0);
+               return(1);
+       }
+
+       /* useup old scroll / spellbook */
+       useup(paper);
+
+       /* success */
+       if (new_obj->oclass == SPBOOK_CLASS) {
+               /* acknowledge the change in the object's description... */
+               pline_The("spellbook warps strangely, then turns %s.",
+                     OBJ_DESCR(objects[new_obj->otyp]));
+       }
+       new_obj->blessed = (curseval > 0);
+       new_obj->cursed = (curseval < 0);
+#ifdef MAIL
+       if (new_obj->otyp == SCR_MAIL) new_obj->spe = 1;
+#endif
+       new_obj = hold_another_object(new_obj, "Oops!  %s out of your grasp!",
+                                              The(aobjnam(new_obj, "slip")),
+                                              (const char *)0);
+       return(1);
+}
+
+/*write.c*/
diff --git a/src/zap.c b/src/zap.c
new file mode 100644 (file)
index 0000000..991c429
--- /dev/null
+++ b/src/zap.c
@@ -0,0 +1,4146 @@
+/*     SCCS Id: @(#)zap.c      3.4     2003/08/24      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+/* Disintegration rays have special treatment; corpses are never left.
+ * But the routine which calculates the damage is separate from the routine
+ * which kills the monster.  The damage routine returns this cookie to
+ * indicate that the monster should be disintegrated.
+ */
+#define MAGIC_COOKIE 1000
+
+#ifdef OVLB
+static NEARDATA boolean obj_zapped;
+static NEARDATA int poly_zapped;
+#endif
+
+extern boolean notonhead;      /* for long worms */
+
+/* kludge to use mondied instead of killed */
+extern boolean m_using;
+
+STATIC_DCL void FDECL(costly_cancel, (struct obj *));
+STATIC_DCL void FDECL(polyuse, (struct obj*, int, int));
+STATIC_DCL void FDECL(create_polymon, (struct obj *, int));
+STATIC_DCL boolean FDECL(zap_updown, (struct obj *));
+STATIC_DCL int FDECL(zhitm, (struct monst *,int,int,struct obj **));
+STATIC_DCL void FDECL(zhitu, (int,int,const char *,XCHAR_P,XCHAR_P));
+STATIC_DCL void FDECL(revive_egg, (struct obj *));
+#ifdef STEED
+STATIC_DCL boolean FDECL(zap_steed, (struct obj *));
+#endif
+
+#ifdef OVLB
+STATIC_DCL int FDECL(zap_hit, (int,int));
+#endif
+#ifdef OVL0
+STATIC_DCL void FDECL(backfire, (struct obj *));
+STATIC_DCL int FDECL(spell_hit_bonus, (int));
+#endif
+
+#define ZT_MAGIC_MISSILE       (AD_MAGM-1)
+#define ZT_FIRE                        (AD_FIRE-1)
+#define ZT_COLD                        (AD_COLD-1)
+#define ZT_SLEEP               (AD_SLEE-1)
+#define ZT_DEATH               (AD_DISN-1)     /* or disintegration */
+#define ZT_LIGHTNING           (AD_ELEC-1)
+#define ZT_POISON_GAS          (AD_DRST-1)
+#define ZT_ACID                        (AD_ACID-1)
+/* 8 and 9 are currently unassigned */
+
+#define ZT_WAND(x)             (x)
+#define ZT_SPELL(x)            (10+(x))
+#define ZT_BREATH(x)           (20+(x))
+
+#define is_hero_spell(type)    ((type) >= 10 && (type) < 20)
+
+#ifndef OVLB
+STATIC_VAR const char are_blinded_by_the_flash[];
+extern const char * const flash_types[];
+#else
+STATIC_VAR const char are_blinded_by_the_flash[] = "are blinded by the flash!";
+
+const char * const flash_types[] = {   /* also used in buzzmu(mcastu.c) */
+       "magic missile",        /* Wands must be 0-9 */
+       "bolt of fire",
+       "bolt of cold",
+       "sleep ray",
+       "death ray",
+       "bolt of lightning",
+       "",
+       "",
+       "",
+       "",
+
+       "magic missile",        /* Spell equivalents must be 10-19 */
+       "fireball",
+       "cone of cold",
+       "sleep ray",
+       "finger of death",
+       "bolt of lightning",    /* There is no spell, used for retribution */
+       "",
+       "",
+       "",
+       "",
+
+       "blast of missiles",    /* Dragon breath equivalents 20-29*/
+       "blast of fire",
+       "blast of frost",
+       "blast of sleep gas",
+       "blast of disintegration",
+       "blast of lightning",
+       "blast of poison gas",
+       "blast of acid",
+       "",
+       ""
+};
+
+/* Routines for IMMEDIATE wands and spells. */
+/* bhitm: monster mtmp was hit by the effect of wand or spell otmp */
+int
+bhitm(mtmp, otmp)
+struct monst *mtmp;
+struct obj *otmp;
+{
+       boolean wake = TRUE;    /* Most 'zaps' should wake monster */
+       boolean reveal_invis = FALSE;
+       boolean dbldam = Role_if(PM_KNIGHT) && u.uhave.questart;
+       int dmg, otyp = otmp->otyp;
+       const char *zap_type_text = "spell";
+       struct obj *obj;
+       boolean disguised_mimic = (mtmp->data->mlet == S_MIMIC &&
+                                  mtmp->m_ap_type != M_AP_NOTHING);
+
+       if (u.uswallow && mtmp == u.ustuck)
+           reveal_invis = FALSE;
+
+       switch(otyp) {
+       case WAN_STRIKING:
+               zap_type_text = "wand";
+               /* fall through */
+       case SPE_FORCE_BOLT:
+               reveal_invis = TRUE;
+               if (resists_magm(mtmp)) {       /* match effect on player */
+                       shieldeff(mtmp->mx, mtmp->my);
+                       break;  /* skip makeknown */
+               } else if (u.uswallow || rnd(20) < 10 + find_mac(mtmp)) {
+                       dmg = d(2,12);
+                       if(dbldam) dmg *= 2;
+                       if (otyp == SPE_FORCE_BOLT)
+                           dmg += spell_damage_bonus();
+                       hit(zap_type_text, mtmp, exclam(dmg));
+                       (void) resist(mtmp, otmp->oclass, dmg, TELL);
+               } else miss(zap_type_text, mtmp);
+               makeknown(otyp);
+               break;
+       case WAN_SLOW_MONSTER:
+       case SPE_SLOW_MONSTER:
+               if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
+                       mon_adjust_speed(mtmp, -1, otmp);
+                       m_dowear(mtmp, FALSE); /* might want speed boots */
+                       if (u.uswallow && (mtmp == u.ustuck) &&
+                           is_whirly(mtmp->data)) {
+                               You("disrupt %s!", mon_nam(mtmp));
+                               pline("A huge hole opens up...");
+                               expels(mtmp, mtmp->data, TRUE);
+                       }
+               }
+               break;
+       case WAN_SPEED_MONSTER:
+               if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
+                       mon_adjust_speed(mtmp, 1, otmp);
+                       m_dowear(mtmp, FALSE); /* might want speed boots */
+               }
+               break;
+       case WAN_UNDEAD_TURNING:
+       case SPE_TURN_UNDEAD:
+               wake = FALSE;
+               if (unturn_dead(mtmp)) wake = TRUE;
+               if (is_undead(mtmp->data)) {
+                       reveal_invis = TRUE;
+                       wake = TRUE;
+                       dmg = rnd(8);
+                       if(dbldam) dmg *= 2;
+                       if (otyp == SPE_TURN_UNDEAD)
+                               dmg += spell_damage_bonus();
+                       flags.bypasses = TRUE;  /* for make_corpse() */
+                       if (!resist(mtmp, otmp->oclass, dmg, NOTELL)) {
+                           if (mtmp->mhp > 0) monflee(mtmp, 0, FALSE, TRUE);
+                       }
+               }
+               break;
+       case WAN_POLYMORPH:
+       case SPE_POLYMORPH:
+       case POT_POLYMORPH:
+               if (resists_magm(mtmp)) {
+                   /* magic resistance protects from polymorph traps, so make
+                      it guard against involuntary polymorph attacks too... */
+                   shieldeff(mtmp->mx, mtmp->my);
+               } else if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
+                   /* natural shapechangers aren't affected by system shock
+                      (unless protection from shapechangers is interfering
+                      with their metabolism...) */
+                   if (mtmp->cham == CHAM_ORDINARY && !rn2(25)) {
+                       if (canseemon(mtmp)) {
+                           pline("%s shudders!", Monnam(mtmp));
+                           makeknown(otyp);
+                       }
+                       /* dropped inventory shouldn't be hit by this zap */
+                       for (obj = mtmp->minvent; obj; obj = obj->nobj)
+                           bypass_obj(obj);
+                       /* flags.bypasses = TRUE; ## for make_corpse() */
+                       /* no corpse after system shock */
+                       xkilled(mtmp, 3);
+                   } else if (newcham(mtmp, (struct permonst *)0,
+                                      (otyp != POT_POLYMORPH), FALSE)) {
+                       if (!Hallucination && canspotmon(mtmp))
+                           makeknown(otyp);
+                   }
+               }
+               break;
+       case WAN_CANCELLATION:
+       case SPE_CANCELLATION:
+               (void) cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE);
+               break;
+       case WAN_TELEPORTATION:
+       case SPE_TELEPORT_AWAY:
+               reveal_invis = !u_teleport_mon(mtmp, TRUE);
+               break;
+       case WAN_MAKE_INVISIBLE:
+           {
+               int oldinvis = mtmp->minvis;
+               char nambuf[BUFSZ];
+
+               /* format monster's name before altering its visibility */
+               Strcpy(nambuf, Monnam(mtmp));
+               mon_set_minvis(mtmp);
+               if (!oldinvis && knowninvisible(mtmp)) {
+                   pline("%s turns transparent!", nambuf);
+                   makeknown(otyp);
+               }
+               break;
+           }
+       case WAN_NOTHING:
+       case WAN_LOCKING:
+       case SPE_WIZARD_LOCK:
+               wake = FALSE;
+               break;
+       case WAN_PROBING:
+               wake = FALSE;
+               reveal_invis = TRUE;
+               probe_monster(mtmp);
+               makeknown(otyp);
+               break;
+       case WAN_OPENING:
+       case SPE_KNOCK:
+               wake = FALSE;   /* don't want immediate counterattack */
+               if (u.uswallow && mtmp == u.ustuck) {
+                       if (is_animal(mtmp->data)) {
+                               if (Blind) You_feel("a sudden rush of air!");
+                               else pline("%s opens its mouth!", Monnam(mtmp));
+                       }
+                       expels(mtmp, mtmp->data, TRUE);
+#ifdef STEED
+               } else if (!!(obj = which_armor(mtmp, W_SADDLE))) {
+                       mtmp->misc_worn_check &= ~obj->owornmask;
+                       update_mon_intrinsics(mtmp, obj, FALSE, FALSE);
+                       obj->owornmask = 0L;
+                       obj_extract_self(obj);
+                       place_object(obj, mtmp->mx, mtmp->my);
+                       /* call stackobj() if we ever drop anything that can merge */
+                       newsym(mtmp->mx, mtmp->my);
+#endif
+               }
+               break;
+       case SPE_HEALING:
+       case SPE_EXTRA_HEALING:
+               reveal_invis = TRUE;
+           if (mtmp->data != &mons[PM_PESTILENCE]) {
+               wake = FALSE;           /* wakeup() makes the target angry */
+               mtmp->mhp += d(6, otyp == SPE_EXTRA_HEALING ? 8 : 4);
+               if (mtmp->mhp > mtmp->mhpmax)
+                   mtmp->mhp = mtmp->mhpmax;
+               if (mtmp->mblinded) {
+                   mtmp->mblinded = 0;
+                   mtmp->mcansee = 1;
+               }
+               if (canseemon(mtmp)) {
+                   if (disguised_mimic) {
+                       if (mtmp->m_ap_type == M_AP_OBJECT &&
+                           mtmp->mappearance == STRANGE_OBJECT) {
+                           /* it can do better now */
+                           set_mimic_sym(mtmp);
+                           newsym(mtmp->mx, mtmp->my);
+                       } else
+                           mimic_hit_msg(mtmp, otyp);
+                   } else pline("%s looks%s better.", Monnam(mtmp),
+                                otyp == SPE_EXTRA_HEALING ? " much" : "" );
+               }
+               if (mtmp->mtame || mtmp->mpeaceful) {
+                   adjalign(Role_if(PM_HEALER) ? 1 : sgn(u.ualign.type));
+               }
+           } else {    /* Pestilence */
+               /* Pestilence will always resist; damage is half of 3d{4,8} */
+               (void) resist(mtmp, otmp->oclass,
+                             d(3, otyp == SPE_EXTRA_HEALING ? 8 : 4), TELL);
+           }
+               break;
+       case WAN_LIGHT: /* (broken wand) */
+               if (flash_hits_mon(mtmp, otmp)) {
+                   makeknown(WAN_LIGHT);
+                   reveal_invis = TRUE;
+               }
+               break;
+       case WAN_SLEEP: /* (broken wand) */
+               /* [wakeup() doesn't rouse victims of temporary sleep,
+                   so it's okay to leave `wake' set to TRUE here] */
+               reveal_invis = TRUE;
+               if (sleep_monst(mtmp, d(1 + otmp->spe, 12), WAND_CLASS))
+                   slept_monst(mtmp);
+               if (!Blind) makeknown(WAN_SLEEP);
+               break;
+       case SPE_STONE_TO_FLESH:
+               if (monsndx(mtmp->data) == PM_STONE_GOLEM) {
+                   char *name = Monnam(mtmp);
+                   /* turn into flesh golem */
+                   if (newcham(mtmp, &mons[PM_FLESH_GOLEM], FALSE, FALSE)) {
+                       if (canseemon(mtmp))
+                           pline("%s turns to flesh!", name);
+                   } else {
+                       if (canseemon(mtmp))
+                           pline("%s looks rather fleshy for a moment.",
+                                 name);
+                   }
+               } else
+                   wake = FALSE;
+               break;
+       case SPE_DRAIN_LIFE:
+               dmg = rnd(8);
+               if(dbldam) dmg *= 2;
+               if (otyp == SPE_DRAIN_LIFE)
+                       dmg += spell_damage_bonus();
+               if (resists_drli(mtmp))
+                   shieldeff(mtmp->mx, mtmp->my);
+               else if (!resist(mtmp, otmp->oclass, dmg, NOTELL) &&
+                               mtmp->mhp > 0) {
+                   mtmp->mhp -= dmg;
+                   mtmp->mhpmax -= dmg;
+                   if (mtmp->mhp <= 0 || mtmp->mhpmax <= 0 || mtmp->m_lev < 1)
+                       xkilled(mtmp, 1);
+                   else {
+                       mtmp->m_lev--;
+                       if (canseemon(mtmp))
+                           pline("%s suddenly seems weaker!", Monnam(mtmp));
+                   }
+               }
+               break;
+       default:
+               impossible("What an interesting effect (%d)", otyp);
+               break;
+       }
+       if(wake) {
+           if(mtmp->mhp > 0) {
+               wakeup(mtmp);
+               m_respond(mtmp);
+               if(mtmp->isshk && !*u.ushops) hot_pursuit(mtmp);
+           } else if(mtmp->m_ap_type)
+               seemimic(mtmp); /* might unblock if mimicing a boulder/door */
+       }
+       /* note: bhitpos won't be set if swallowed, but that's okay since
+        * reveal_invis will be false.  We can't use mtmp->mx, my since it
+        * might be an invisible worm hit on the tail.
+        */
+       if (reveal_invis) {
+           if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) &&
+                                                       !canspotmon(mtmp))
+               map_invisible(bhitpos.x, bhitpos.y);
+       }
+       return 0;
+}
+
+void
+probe_monster(mtmp)
+struct monst *mtmp;
+{
+       struct obj *otmp;
+
+       mstatusline(mtmp);
+       if (notonhead) return;  /* don't show minvent for long worm tail */
+
+#ifndef GOLDOBJ
+       if (mtmp->minvent || mtmp->mgold) {
+#else
+       if (mtmp->minvent) {
+#endif
+           for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+               otmp->dknown = 1;       /* treat as "seen" */
+           (void) display_minventory(mtmp, MINV_ALL, (char *)0);
+       } else {
+           pline("%s is not carrying anything.", noit_Monnam(mtmp));
+       }
+}
+
+#endif /*OVLB*/
+#ifdef OVL1
+
+/*
+ * Return the object's physical location.  This only makes sense for
+ * objects that are currently on the level (i.e. migrating objects
+ * are nowhere).  By default, only things that can be seen (in hero's
+ * inventory, monster's inventory, or on the ground) are reported.
+ * By adding BURIED_TOO and/or CONTAINED_TOO flags, you can also get
+ * the location of buried and contained objects.  Note that if an
+ * object is carried by a monster, its reported position may change
+ * from turn to turn.  This function returns FALSE if the position
+ * is not available or subject to the constraints above.
+ */
+boolean
+get_obj_location(obj, xp, yp, locflags)
+struct obj *obj;
+xchar *xp, *yp;
+int locflags;
+{
+       switch (obj->where) {
+           case OBJ_INVENT:
+               *xp = u.ux;
+               *yp = u.uy;
+               return TRUE;
+           case OBJ_FLOOR:
+               *xp = obj->ox;
+               *yp = obj->oy;
+               return TRUE;
+           case OBJ_MINVENT:
+               if (obj->ocarry->mx) {
+                   *xp = obj->ocarry->mx;
+                   *yp = obj->ocarry->my;
+                   return TRUE;
+               }
+               break;  /* !mx => migrating monster */
+           case OBJ_BURIED:
+               if (locflags & BURIED_TOO) {
+                   *xp = obj->ox;
+                   *yp = obj->oy;
+                   return TRUE;
+               }
+               break;
+           case OBJ_CONTAINED:
+               if (locflags & CONTAINED_TOO)
+                   return get_obj_location(obj->ocontainer, xp, yp, locflags);
+               break;
+       }
+       *xp = *yp = 0;
+       return FALSE;
+}
+
+boolean
+get_mon_location(mon, xp, yp, locflags)
+struct monst *mon;
+xchar *xp, *yp;
+int locflags;  /* non-zero means get location even if monster is buried */
+{
+       if (mon == &youmonst) {
+           *xp = u.ux;
+           *yp = u.uy;
+           return TRUE;
+       } else if (mon->mx > 0 && (!mon->mburied || locflags)) {
+           *xp = mon->mx;
+           *yp = mon->my;
+           return TRUE;
+       } else {        /* migrating or buried */
+           *xp = *yp = 0;
+           return FALSE;
+       }
+}
+
+/* used by revive() and animate_statue() */
+struct monst *
+montraits(obj,cc)
+struct obj *obj;
+coord *cc;
+{
+       struct monst *mtmp = (struct monst *)0;
+       struct monst *mtmp2 = (struct monst *)0;
+
+       if (obj->oxlth && (obj->oattached == OATTACHED_MONST))
+               mtmp2 = get_mtraits(obj, TRUE);
+       if (mtmp2) {
+               /* save_mtraits() validated mtmp2->mnum */
+               mtmp2->data = &mons[mtmp2->mnum];
+               if (mtmp2->mhpmax <= 0 && !is_rider(mtmp2->data))
+                       return (struct monst *)0;
+               mtmp = makemon(mtmp2->data,
+                               cc->x, cc->y, NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH);
+               if (!mtmp) return mtmp;
+
+               /* heal the monster */
+               if (mtmp->mhpmax > mtmp2->mhpmax && is_rider(mtmp2->data))
+                       mtmp2->mhpmax = mtmp->mhpmax;
+               mtmp2->mhp = mtmp2->mhpmax;
+               /* Get these ones from mtmp */
+               mtmp2->minvent = mtmp->minvent; /*redundant*/
+               /* monster ID is available if the monster died in the current
+                  game, but should be zero if the corpse was in a bones level
+                  (we cleared it when loading bones) */
+               if (!mtmp2->m_id)
+                   mtmp2->m_id = mtmp->m_id;
+               mtmp2->mx   = mtmp->mx;
+               mtmp2->my   = mtmp->my;
+               mtmp2->mux  = mtmp->mux;
+               mtmp2->muy  = mtmp->muy;
+               mtmp2->mw   = mtmp->mw;
+               mtmp2->wormno = mtmp->wormno;
+               mtmp2->misc_worn_check = mtmp->misc_worn_check;
+               mtmp2->weapon_check = mtmp->weapon_check;
+               mtmp2->mtrapseen = mtmp->mtrapseen;
+               mtmp2->mflee = mtmp->mflee;
+               mtmp2->mburied = mtmp->mburied;
+               mtmp2->mundetected = mtmp->mundetected;
+               mtmp2->mfleetim = mtmp->mfleetim;
+               mtmp2->mlstmv = mtmp->mlstmv;
+               mtmp2->m_ap_type = mtmp->m_ap_type;
+               /* set these ones explicitly */
+               mtmp2->mavenge = 0;
+               mtmp2->meating = 0;
+               mtmp2->mleashed = 0;
+               mtmp2->mtrapped = 0;
+               mtmp2->msleeping = 0;
+               mtmp2->mfrozen = 0;
+               mtmp2->mcanmove = 1;
+               /* most cancelled monsters return to normal,
+                  but some need to stay cancelled */
+               if (!dmgtype(mtmp2->data, AD_SEDU)
+#ifdef SEDUCE
+                               && !dmgtype(mtmp2->data, AD_SSEX)
+#endif
+                   ) mtmp2->mcan = 0;
+               mtmp2->mcansee = 1;     /* set like in makemon */
+               mtmp2->mblinded = 0;
+               mtmp2->mstun = 0;
+               mtmp2->mconf = 0;
+               replmon(mtmp,mtmp2);
+       }
+       return mtmp2;
+}
+
+/*
+ * get_container_location() returns the following information
+ * about the outermost container:
+ * loc argument gets set to: 
+ *     OBJ_INVENT      if in hero's inventory; return 0.
+ *     OBJ_FLOOR       if on the floor; return 0.
+ *     OBJ_BURIED      if buried; return 0.
+ *     OBJ_MINVENT     if in monster's inventory; return monster.
+ * container_nesting is updated with the nesting depth of the containers
+ * if applicable.
+ */
+struct monst *
+get_container_location(obj, loc, container_nesting)
+struct obj *obj;
+int *loc;
+int *container_nesting;
+{
+       if (!obj || !loc)
+               return 0;
+
+       if (container_nesting) *container_nesting = 0;
+       while (obj && obj->where == OBJ_CONTAINED) {
+               if (container_nesting) *container_nesting += 1;
+               obj = obj->ocontainer;
+       }
+       if (obj) {
+           *loc = obj->where;  /* outermost container's location */
+           if (obj->where == OBJ_MINVENT) return obj->ocarry;
+       }
+       return (struct monst *)0;
+}
+
+/*
+ * Attempt to revive the given corpse, return the revived monster if
+ * successful.  Note: this does NOT use up the corpse if it fails.
+ */
+struct monst *
+revive(obj)
+register struct obj *obj;
+{
+       register struct monst *mtmp = (struct monst *)0;
+       struct obj *container = (struct obj *)0;
+       int container_nesting = 0;
+       schar savetame = 0;
+       boolean recorporealization = FALSE;
+       boolean in_container = FALSE;
+       if(obj->otyp == CORPSE) {
+               int montype = obj->corpsenm;
+               xchar x, y;
+
+               if (obj->where == OBJ_CONTAINED) {
+                       /* deal with corpses in [possibly nested] containers */
+                       struct monst *carrier;
+                       int holder = 0;
+
+                       container = obj->ocontainer;
+                       carrier = get_container_location(container, &holder,
+                                                       &container_nesting);
+                       switch(holder) {
+                           case OBJ_MINVENT:
+                               x = carrier->mx; y = carrier->my;
+                               in_container = TRUE;
+                               break;
+                           case OBJ_INVENT:
+                               x = u.ux; y = u.uy;
+                               in_container = TRUE;
+                               break;
+                           case OBJ_FLOOR:
+                               if (!get_obj_location(obj, &x, &y, CONTAINED_TOO))
+                                       return (struct monst *) 0;
+                               in_container = TRUE;
+                               break;
+                           default:
+                               return (struct monst *)0;
+                       }
+               } else {
+                       /* only for invent, minvent, or floor */
+                       if (!get_obj_location(obj, &x, &y, 0))
+                           return (struct monst *) 0;
+               }
+               if (in_container) {
+                       /* Rules for revival from containers:
+                          - the container cannot be locked
+                          - the container cannot be heavily nested (>2 is arbitrary)
+                          - the container cannot be a statue or bag of holding
+                            (except in very rare cases for the latter)
+                       */
+                       if (!x || !y || container->olocked || container_nesting > 2 ||
+                           container->otyp == STATUE ||
+                           (container->otyp == BAG_OF_HOLDING && rn2(40)))
+                               return (struct monst *)0;
+               }
+
+               if (MON_AT(x,y)) {
+                   coord new_xy;
+
+                   if (enexto(&new_xy, x, y, &mons[montype]))
+                       x = new_xy.x,  y = new_xy.y;
+               }
+
+               if(cant_create(&montype, TRUE)) {
+                       /* make a zombie or worm instead */
+                       mtmp = makemon(&mons[montype], x, y,
+                                      NO_MINVENT|MM_NOWAIT);
+                       if (mtmp) {
+                               mtmp->mhp = mtmp->mhpmax = 100;
+                               mon_adjust_speed(mtmp, 2, (struct obj *)0); /* MFAST */
+                       }
+               } else {
+                   if (obj->oxlth && (obj->oattached == OATTACHED_MONST)) {
+                           coord xy;
+                           xy.x = x; xy.y = y;
+                           mtmp = montraits(obj, &xy);
+                           if (mtmp && mtmp->mtame && !mtmp->isminion)
+                               wary_dog(mtmp, TRUE);
+                   } else
+                           mtmp = makemon(&mons[montype], x, y,
+                                      NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH);
+                   if (mtmp) {
+                       if (obj->oxlth && (obj->oattached == OATTACHED_M_ID)) {
+                           unsigned m_id;
+                           struct monst *ghost;
+                           (void) memcpy((genericptr_t)&m_id,
+                                   (genericptr_t)obj->oextra, sizeof(m_id));
+                           ghost = find_mid(m_id, FM_FMON);
+                           if (ghost && ghost->data == &mons[PM_GHOST]) {
+                                   int x2, y2;
+                                   x2 = ghost->mx; y2 = ghost->my;
+                                   if (ghost->mtame)
+                                       savetame = ghost->mtame;
+                                   if (canseemon(ghost))
+                                       pline("%s is suddenly drawn into its former body!",
+                                               Monnam(ghost));
+                                   mondead(ghost);
+                                   recorporealization = TRUE;
+                                   newsym(x2, y2);
+                           }
+                           /* don't mess with obj->oxlth here */
+                           obj->oattached = OATTACHED_NOTHING;
+                       }
+                       /* Monster retains its name */
+                       if (obj->onamelth)
+                           mtmp = christen_monst(mtmp, ONAME(obj));
+                       /* flag the quest leader as alive. */
+                       if (mtmp->data->msound == MS_LEADER || mtmp->m_id ==
+                               quest_status.leader_m_id)
+                           quest_status.leader_is_dead = FALSE;
+                   }
+               }
+               if (mtmp) {
+                       if (obj->oeaten)
+                               mtmp->mhp = eaten_stat(mtmp->mhp, obj);
+                       /* track that this monster was revived at least once */
+                       mtmp->mrevived = 1;
+
+                       if (recorporealization) {
+                               /* If mtmp is revivification of former tame ghost*/
+                               if (savetame) {
+                                   struct monst *mtmp2 = tamedog(mtmp, (struct obj *)0);
+                                   if (mtmp2) {
+                                       mtmp2->mtame = savetame;
+                                       mtmp = mtmp2;
+                                   }
+                               }
+                               /* was ghost, now alive, it's all very confusing */
+                               mtmp->mconf = 1;
+                       }
+
+                       switch (obj->where) {
+                           case OBJ_INVENT:
+                               useup(obj);
+                               break;
+                           case OBJ_FLOOR:
+                               /* in case MON_AT+enexto for invisible mon */
+                               x = obj->ox,  y = obj->oy;
+                               /* not useupf(), which charges */
+                               if (obj->quan > 1L)
+                                   obj = splitobj(obj, 1L);
+                               delobj(obj);
+                               newsym(x, y);
+                               break;
+                           case OBJ_MINVENT:
+                               m_useup(obj->ocarry, obj);
+                               break;
+                           case OBJ_CONTAINED:
+                               obj_extract_self(obj);
+                               obfree(obj, (struct obj *) 0);
+                               break;
+                           default:
+                               panic("revive");
+                       }
+               }
+       }
+       return mtmp;
+}
+
+STATIC_OVL void
+revive_egg(obj)
+struct obj *obj;
+{
+       /*
+        * Note: generic eggs with corpsenm set to NON_PM will never hatch.
+        */
+       if (obj->otyp != EGG) return;
+       if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE))
+           attach_egg_hatch_timeout(obj);
+}
+
+/* try to revive all corpses and eggs carried by `mon' */
+int
+unturn_dead(mon)
+struct monst *mon;
+{
+       struct obj *otmp, *otmp2;
+       struct monst *mtmp2;
+       char owner[BUFSZ], corpse[BUFSZ];
+       boolean youseeit;
+       int once = 0, res = 0;
+
+       youseeit = (mon == &youmonst) ? TRUE : canseemon(mon);
+       otmp2 = (mon == &youmonst) ? invent : mon->minvent;
+
+       while ((otmp = otmp2) != 0) {
+           otmp2 = otmp->nobj;
+           if (otmp->otyp == EGG)
+               revive_egg(otmp);
+           if (otmp->otyp != CORPSE) continue;
+           /* save the name; the object is liable to go away */
+           if (youseeit) Strcpy(corpse, corpse_xname(otmp, TRUE));
+
+           /* for a merged group, only one is revived; should this be fixed? */
+           if ((mtmp2 = revive(otmp)) != 0) {
+               ++res;
+               if (youseeit) {
+                   if (!once++) Strcpy(owner,
+                                       (mon == &youmonst) ? "Your" :
+                                       s_suffix(Monnam(mon)));
+                   pline("%s %s suddenly comes alive!", owner, corpse);
+               } else if (canseemon(mtmp2))
+                   pline("%s suddenly appears!", Amonnam(mtmp2));
+           }
+       }
+       return res;
+}
+#endif /*OVL1*/
+
+#ifdef OVLB
+static const char charged_objs[] = { WAND_CLASS, WEAPON_CLASS, ARMOR_CLASS, 0 };
+
+STATIC_OVL void
+costly_cancel(obj)
+register struct obj *obj;
+{
+       char objroom;
+       struct monst *shkp = (struct monst *)0;
+
+       if (obj->no_charge) return;
+
+       switch (obj->where) {
+       case OBJ_INVENT:
+               if (obj->unpaid) {
+                   shkp = shop_keeper(*u.ushops);
+                   if (!shkp) return;
+                   Norep("You cancel an unpaid object, you pay for it!");
+                   bill_dummy_object(obj);
+               }
+               break;
+       case OBJ_FLOOR:
+               objroom = *in_rooms(obj->ox, obj->oy, SHOPBASE);
+               shkp = shop_keeper(objroom);
+               if (!shkp || !inhishop(shkp)) return;
+               if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) {
+                   Norep("You cancel it, you pay for it!");
+                   bill_dummy_object(obj);
+               } else
+                   (void) stolen_value(obj, obj->ox, obj->oy, FALSE, FALSE);
+               break;
+       }
+}
+
+/* cancel obj, possibly carried by you or a monster */
+void
+cancel_item(obj)
+register struct obj *obj;
+{
+       boolean u_ring = (obj == uleft) || (obj == uright);
+       register boolean holy = (obj->otyp == POT_WATER && obj->blessed);
+
+       switch(obj->otyp) {
+               case RIN_GAIN_STRENGTH:
+                       if ((obj->owornmask & W_RING) && u_ring) {
+                               ABON(A_STR) -= obj->spe;
+                               flags.botl = 1;
+                       }
+                       break;
+               case RIN_GAIN_CONSTITUTION:
+                       if ((obj->owornmask & W_RING) && u_ring) {
+                               ABON(A_CON) -= obj->spe;
+                               flags.botl = 1;
+                       }
+                       break;
+               case RIN_ADORNMENT:
+                       if ((obj->owornmask & W_RING) && u_ring) {
+                               ABON(A_CHA) -= obj->spe;
+                               flags.botl = 1;
+                       }
+                       break;
+               case RIN_INCREASE_ACCURACY:
+                       if ((obj->owornmask & W_RING) && u_ring)
+                               u.uhitinc -= obj->spe;
+                       break;
+               case RIN_INCREASE_DAMAGE:
+                       if ((obj->owornmask & W_RING) && u_ring)
+                               u.udaminc -= obj->spe;
+                       break;
+               case GAUNTLETS_OF_DEXTERITY:
+                       if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
+                               ABON(A_DEX) -= obj->spe;
+                               flags.botl = 1;
+                       }
+                       break;
+               case HELM_OF_BRILLIANCE:
+                       if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
+                               ABON(A_INT) -= obj->spe;
+                               ABON(A_WIS) -= obj->spe;
+                               flags.botl = 1;
+                       }
+                       break;
+               /* case RIN_PROTECTION:  not needed */
+       }
+       if (objects[obj->otyp].oc_magic
+           || (obj->spe && (obj->oclass == ARMOR_CLASS ||
+                            obj->oclass == WEAPON_CLASS || is_weptool(obj)))
+           || obj->otyp == POT_ACID || obj->otyp == POT_SICKNESS) {
+           if (obj->spe != ((obj->oclass == WAND_CLASS) ? -1 : 0) &&
+              obj->otyp != WAN_CANCELLATION &&
+                /* can't cancel cancellation */
+                obj->otyp != MAGIC_LAMP &&
+                obj->otyp != CANDELABRUM_OF_INVOCATION) {
+               costly_cancel(obj);
+               obj->spe = (obj->oclass == WAND_CLASS) ? -1 : 0;
+           }
+           switch (obj->oclass) {
+             case SCROLL_CLASS:
+               costly_cancel(obj);
+               obj->otyp = SCR_BLANK_PAPER;
+               obj->spe = 0;
+               break;
+             case SPBOOK_CLASS:
+               if (obj->otyp != SPE_CANCELLATION &&
+                       obj->otyp != SPE_BOOK_OF_THE_DEAD) {
+                   costly_cancel(obj);
+                   obj->otyp = SPE_BLANK_PAPER;
+               }
+               break;
+             case POTION_CLASS:
+               costly_cancel(obj);
+               if (obj->otyp == POT_SICKNESS ||
+                   obj->otyp == POT_SEE_INVISIBLE) {
+           /* sickness is "biologically contaminated" fruit juice; cancel it
+            * and it just becomes fruit juice... whereas see invisible
+            * tastes like "enchanted" fruit juice, it similarly cancels.
+            */
+                   obj->otyp = POT_FRUIT_JUICE;
+               } else {
+                   obj->otyp = POT_WATER;
+                   obj->odiluted = 0; /* same as any other water */
+               }
+               break;
+           }
+       }
+       if (holy) costly_cancel(obj);
+       unbless(obj);
+       uncurse(obj);
+#ifdef INVISIBLE_OBJECTS
+       if (obj->oinvis) obj->oinvis = 0;
+#endif
+       return;
+}
+
+/* Remove a positive enchantment or charge from obj,
+ * possibly carried by you or a monster
+ */
+boolean
+drain_item(obj)
+register struct obj *obj;
+{
+       boolean u_ring;
+
+       /* Is this a charged/enchanted object? */
+       if (!obj || (!objects[obj->otyp].oc_charged &&
+                       obj->oclass != WEAPON_CLASS &&
+                       obj->oclass != ARMOR_CLASS && !is_weptool(obj)) ||
+                       obj->spe <= 0)
+           return (FALSE);
+       if (obj_resists(obj, 10, 90))
+           return (FALSE);
+
+       /* Charge for the cost of the object */
+       costly_cancel(obj);     /* The term "cancel" is okay for now */
+
+       /* Drain the object and any implied effects */
+       obj->spe--;
+       u_ring = (obj == uleft) || (obj == uright);
+       switch(obj->otyp) {
+       case RIN_GAIN_STRENGTH:
+           if ((obj->owornmask & W_RING) && u_ring) {
+               ABON(A_STR)--;
+               flags.botl = 1;
+           }
+           break;
+       case RIN_GAIN_CONSTITUTION:
+           if ((obj->owornmask & W_RING) && u_ring) {
+               ABON(A_CON)--;
+               flags.botl = 1;
+           }
+           break;
+       case RIN_ADORNMENT:
+           if ((obj->owornmask & W_RING) && u_ring) {
+               ABON(A_CHA)--;
+               flags.botl = 1;
+           }
+           break;
+       case RIN_INCREASE_ACCURACY:
+           if ((obj->owornmask & W_RING) && u_ring)
+               u.uhitinc--;
+           break;
+       case RIN_INCREASE_DAMAGE:
+           if ((obj->owornmask & W_RING) && u_ring)
+               u.udaminc--;
+           break;
+       case HELM_OF_BRILLIANCE:
+           if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
+               ABON(A_INT)--;
+               ABON(A_WIS)--;
+               flags.botl = 1;
+           }
+           break;
+       case GAUNTLETS_OF_DEXTERITY:
+           if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
+               ABON(A_DEX)--;
+               flags.botl = 1;
+           }
+           break;
+       case RIN_PROTECTION:
+           flags.botl = 1;
+           break;
+       }
+       if (carried(obj)) update_inventory();
+       return (TRUE);
+}
+
+#endif /*OVLB*/
+#ifdef OVL0
+
+boolean
+obj_resists(obj, ochance, achance)
+struct obj *obj;
+int ochance, achance;  /* percent chance for ordinary objects, artifacts */
+{
+       if (obj->otyp == AMULET_OF_YENDOR ||
+           obj->otyp == SPE_BOOK_OF_THE_DEAD ||
+           obj->otyp == CANDELABRUM_OF_INVOCATION ||
+           obj->otyp == BELL_OF_OPENING ||
+           (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm]))) {
+               return TRUE;
+       } else {
+               int chance = rn2(100);
+
+               return((boolean)(chance < (obj->oartifact ? achance : ochance)));
+       }
+}
+
+boolean
+obj_shudders(obj)
+struct obj *obj;
+{
+       int     zap_odds;
+
+       if (obj->oclass == WAND_CLASS)
+               zap_odds = 3;   /* half-life = 2 zaps */
+       else if (obj->cursed)
+               zap_odds = 3;   /* half-life = 2 zaps */
+       else if (obj->blessed)
+               zap_odds = 12;  /* half-life = 8 zaps */
+       else
+               zap_odds = 8;   /* half-life = 6 zaps */
+
+       /* adjust for "large" quantities of identical things */
+       if(obj->quan > 4L) zap_odds /= 2;
+
+       return((boolean)(! rn2(zap_odds)));
+}
+#endif /*OVL0*/
+#ifdef OVLB
+
+/* Use up at least minwt number of things made of material mat.
+ * There's also a chance that other stuff will be used up.  Finally,
+ * there's a random factor here to keep from always using the stuff
+ * at the top of the pile.
+ */
+STATIC_OVL void
+polyuse(objhdr, mat, minwt)
+    struct obj *objhdr;
+    int mat, minwt;
+{
+    register struct obj *otmp, *otmp2;
+
+    for(otmp = objhdr; minwt > 0 && otmp; otmp = otmp2) {
+       otmp2 = otmp->nexthere;
+       if (otmp == uball || otmp == uchain) continue;
+       if (obj_resists(otmp, 0, 0)) continue;  /* preserve unique objects */
+#ifdef MAIL
+       if (otmp->otyp == SCR_MAIL) continue;
+#endif
+
+       if (((int) objects[otmp->otyp].oc_material == mat) ==
+               (rn2(minwt + 1) != 0)) {
+           /* appropriately add damage to bill */
+           if (costly_spot(otmp->ox, otmp->oy)) {
+               if (*u.ushops)
+                       addtobill(otmp, FALSE, FALSE, FALSE);
+               else
+                       (void)stolen_value(otmp,
+                                          otmp->ox, otmp->oy, FALSE, FALSE);
+           }
+           if (otmp->quan < LARGEST_INT)
+               minwt -= (int)otmp->quan;
+           else
+               minwt = 0;
+           delobj(otmp);
+       }
+    }
+}
+
+/*
+ * Polymorph some of the stuff in this pile into a monster, preferably
+ * a golem of the kind okind.
+ */
+STATIC_OVL void
+create_polymon(obj, okind)
+    struct obj *obj;
+    int okind;
+{
+       struct permonst *mdat = (struct permonst *)0;
+       struct monst *mtmp;
+       const char *material;
+       int pm_index;
+
+       /* no golems if you zap only one object -- not enough stuff */
+       if(!obj || (!obj->nexthere && obj->quan == 1L)) return;
+
+       /* some of these choices are arbitrary */
+       switch(okind) {
+       case IRON:
+       case METAL:
+       case MITHRIL:
+           pm_index = PM_IRON_GOLEM;
+           material = "metal ";
+           break;
+       case COPPER:
+       case SILVER:
+       case PLATINUM:
+       case GEMSTONE:
+       case MINERAL:
+           pm_index = rn2(2) ? PM_STONE_GOLEM : PM_CLAY_GOLEM;
+           material = "lithic ";
+           break;
+       case 0:
+       case FLESH:
+           /* there is no flesh type, but all food is type 0, so we use it */
+           pm_index = PM_FLESH_GOLEM;
+           material = "organic ";
+           break;
+       case WOOD:
+           pm_index = PM_WOOD_GOLEM;
+           material = "wood ";
+           break;
+       case LEATHER:
+           pm_index = PM_LEATHER_GOLEM;
+           material = "leather ";
+           break;
+       case CLOTH:
+           pm_index = PM_ROPE_GOLEM;
+           material = "cloth ";
+           break;
+       case BONE:
+           pm_index = PM_SKELETON;     /* nearest thing to "bone golem" */
+           material = "bony ";
+           break;
+       case GOLD:
+           pm_index = PM_GOLD_GOLEM;
+           material = "gold ";
+           break;
+       case GLASS:
+           pm_index = PM_GLASS_GOLEM;
+           material = "glassy ";
+           break;
+       case PAPER:
+           pm_index = PM_PAPER_GOLEM;
+           material = "paper ";
+           break;
+       default:
+           /* if all else fails... */
+           pm_index = PM_STRAW_GOLEM;
+           material = "";
+           break;
+       }
+
+       if (!(mvitals[pm_index].mvflags & G_GENOD))
+               mdat = &mons[pm_index];
+
+       mtmp = makemon(mdat, obj->ox, obj->oy, NO_MM_FLAGS);
+       polyuse(obj, okind, (int)mons[pm_index].cwt);
+
+       if(mtmp && cansee(mtmp->mx, mtmp->my)) {
+           pline("Some %sobjects meld, and %s arises from the pile!",
+                 material, a_monnam(mtmp));
+       }
+}
+
+/* Assumes obj is on the floor. */
+void
+do_osshock(obj)
+struct obj *obj;
+{
+       long i;
+
+#ifdef MAIL
+       if (obj->otyp == SCR_MAIL) return;
+#endif
+       obj_zapped = TRUE;
+
+       if(poly_zapped < 0) {
+           /* some may metamorphosize */
+           for (i = obj->quan; i; i--)
+               if (! rn2(Luck + 45)) {
+                   poly_zapped = objects[obj->otyp].oc_material;
+                   break;
+               }
+       }
+
+       /* if quan > 1 then some will survive intact */
+       if (obj->quan > 1L) {
+           if (obj->quan > LARGEST_INT)
+               obj = splitobj(obj, (long)rnd(30000));
+           else
+               obj = splitobj(obj, (long)rnd((int)obj->quan - 1));
+       }
+
+       /* appropriately add damage to bill */
+       if (costly_spot(obj->ox, obj->oy)) {
+               if (*u.ushops)
+                       addtobill(obj, FALSE, FALSE, FALSE);
+               else
+                       (void)stolen_value(obj,
+                                          obj->ox, obj->oy, FALSE, FALSE);
+       }
+
+       /* zap the object */
+       delobj(obj);
+}
+
+/*
+ * Polymorph the object to the given object ID.  If the ID is STRANGE_OBJECT
+ * then pick random object from the source's class (this is the standard
+ * "polymorph" case).  If ID is set to a specific object, inhibit fusing
+ * n objects into 1.  This could have been added as a flag, but currently
+ * it is tied to not being the standard polymorph case. The new polymorphed
+ * object replaces obj in its link chains.  Return value is a pointer to
+ * the new object.
+ *
+ * This should be safe to call for an object anywhere.
+ */
+struct obj *
+poly_obj(obj, id)
+       struct obj *obj;
+       int id;
+{
+       struct obj *otmp;
+       xchar ox, oy;
+       boolean can_merge = (id == STRANGE_OBJECT);
+       int obj_location = obj->where;
+
+       if (obj->otyp == BOULDER && In_sokoban(&u.uz))
+           change_luck(-1);    /* Sokoban guilt */
+       if (id == STRANGE_OBJECT) { /* preserve symbol */
+           int try_limit = 3;
+           /* Try up to 3 times to make the magic-or-not status of
+              the new item be the same as it was for the old one. */
+           otmp = (struct obj *)0;
+           do {
+               if (otmp) delobj(otmp);
+               otmp = mkobj(obj->oclass, FALSE);
+           } while (--try_limit > 0 &&
+                 objects[obj->otyp].oc_magic != objects[otmp->otyp].oc_magic);
+       } else {
+           /* literally replace obj with this new thing */
+           otmp = mksobj(id, FALSE, FALSE);
+       /* Actually more things use corpsenm but they polymorph differently */
+#define USES_CORPSENM(typ) ((typ)==CORPSE || (typ)==STATUE || (typ)==FIGURINE)
+           if (USES_CORPSENM(obj->otyp) && USES_CORPSENM(id))
+               otmp->corpsenm = obj->corpsenm;
+#undef USES_CORPSENM
+       }
+
+       /* preserve quantity */
+       otmp->quan = obj->quan;
+       /* preserve the shopkeepers (lack of) interest */
+       otmp->no_charge = obj->no_charge;
+       /* preserve inventory letter if in inventory */
+       if (obj_location == OBJ_INVENT)
+           otmp->invlet = obj->invlet;
+#ifdef MAIL
+       /* You can't send yourself 100 mail messages and then
+        * polymorph them into useful scrolls
+        */
+       if (obj->otyp == SCR_MAIL) {
+               otmp->otyp = SCR_MAIL;
+               otmp->spe = 1;
+       }
+#endif
+
+       /* avoid abusing eggs laid by you */
+       if (obj->otyp == EGG && obj->spe) {
+               int mnum, tryct = 100;
+
+               /* first, turn into a generic egg */
+               if (otmp->otyp == EGG)
+                   kill_egg(otmp);
+               else {
+                   otmp->otyp = EGG;
+                   otmp->owt = weight(otmp);
+               }
+               otmp->corpsenm = NON_PM;
+               otmp->spe = 0;
+
+               /* now change it into something layed by the hero */
+               while (tryct--) {
+                   mnum = can_be_hatched(random_monster());
+                   if (mnum != NON_PM && !dead_species(mnum, TRUE)) {
+                       otmp->spe = 1;  /* layed by hero */
+                       otmp->corpsenm = mnum;
+                       attach_egg_hatch_timeout(otmp);
+                       break;
+                   }
+               }
+       }
+
+       /* keep special fields (including charges on wands) */
+       if (index(charged_objs, otmp->oclass)) otmp->spe = obj->spe;
+       otmp->recharged = obj->recharged;
+
+       otmp->cursed = obj->cursed;
+       otmp->blessed = obj->blessed;
+       otmp->oeroded = obj->oeroded;
+       otmp->oeroded2 = obj->oeroded2;
+       if (!is_flammable(otmp) && !is_rustprone(otmp)) otmp->oeroded = 0;
+       if (!is_corrodeable(otmp) && !is_rottable(otmp)) otmp->oeroded2 = 0;
+       if (is_damageable(otmp))
+           otmp->oerodeproof = obj->oerodeproof;
+
+       /* Keep chest/box traps and poisoned ammo if we may */
+       if (obj->otrapped && Is_box(otmp)) otmp->otrapped = TRUE;
+
+       if (obj->opoisoned && is_poisonable(otmp))
+               otmp->opoisoned = TRUE;
+
+       if (id == STRANGE_OBJECT && obj->otyp == CORPSE) {
+       /* turn crocodile corpses into shoes */
+           if (obj->corpsenm == PM_CROCODILE) {
+               otmp->otyp = LOW_BOOTS;
+               otmp->oclass = ARMOR_CLASS;
+               otmp->spe = 0;
+               otmp->oeroded = 0;
+               otmp->oerodeproof = TRUE;
+               otmp->quan = 1L;
+               otmp->cursed = FALSE;
+           }
+       }
+
+       /* no box contents --KAA */
+       if (Has_contents(otmp)) delete_contents(otmp);
+
+       /* 'n' merged objects may be fused into 1 object */
+       if (otmp->quan > 1L && (!objects[otmp->otyp].oc_merge ||
+                               (can_merge && otmp->quan > (long)rn2(1000))))
+           otmp->quan = 1L;
+
+       switch (otmp->oclass) {
+
+       case TOOL_CLASS:
+           if (otmp->otyp == MAGIC_LAMP) {
+               otmp->otyp = OIL_LAMP;
+               otmp->age = 1500L;      /* "best" oil lamp possible */
+           } else if (otmp->otyp == MAGIC_MARKER) {
+               otmp->recharged = 1;    /* degraded quality */
+           }
+           /* don't care about the recharge count of other tools */
+           break;
+
+       case WAND_CLASS:
+           while (otmp->otyp == WAN_WISHING || otmp->otyp == WAN_POLYMORPH)
+               otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING);
+           /* altering the object tends to degrade its quality
+              (analogous to spellbook `read count' handling) */
+           if ((int)otmp->recharged < rn2(7))  /* recharge_limit */
+               otmp->recharged++;
+           break;
+
+       case POTION_CLASS:
+           while (otmp->otyp == POT_POLYMORPH)
+               otmp->otyp = rnd_class(POT_GAIN_ABILITY, POT_WATER);
+           break;
+
+       case SPBOOK_CLASS:
+           while (otmp->otyp == SPE_POLYMORPH)
+               otmp->otyp = rnd_class(SPE_DIG, SPE_BLANK_PAPER);
+           /* reduce spellbook abuse */
+           otmp->spestudied = obj->spestudied + 1;
+           break;
+
+       case GEM_CLASS:
+           if (otmp->quan > (long) rnd(4) &&
+                   objects[obj->otyp].oc_material == MINERAL &&
+                   objects[otmp->otyp].oc_material != MINERAL) {
+               otmp->otyp = ROCK;      /* transmutation backfired */
+               otmp->quan /= 2L;       /* some material has been lost */
+           }
+           break;
+       }
+
+       /* update the weight */
+       otmp->owt = weight(otmp);
+
+       /* for now, take off worn items being polymorphed */
+       if (obj_location == OBJ_INVENT) {
+           if (id == STRANGE_OBJECT)
+               remove_worn_item(obj, TRUE);
+           else {
+               /* This is called only for stone to flesh.  It's a lot simpler
+                * than it otherwise might be.  We don't need to check for
+                * special effects when putting them on (no meat objects have
+                * any) and only three worn masks are possible.
+                */
+               otmp->owornmask = obj->owornmask;
+               remove_worn_item(obj, TRUE);
+               setworn(otmp, otmp->owornmask);
+               if (otmp->owornmask & LEFT_RING)
+                   uleft = otmp;
+               if (otmp->owornmask & RIGHT_RING)
+                   uright = otmp;
+               if (otmp->owornmask & W_WEP)
+                   uwep = otmp;
+               if (otmp->owornmask & W_SWAPWEP)
+                   uswapwep = otmp;
+               if (otmp->owornmask & W_QUIVER)
+                   uquiver = otmp;
+               goto no_unwear;
+           }
+       }
+
+       /* preserve the mask in case being used by something else */
+       otmp->owornmask = obj->owornmask;
+no_unwear:
+
+       if (obj_location == OBJ_FLOOR && obj->otyp == BOULDER &&
+               otmp->otyp != BOULDER)
+           unblock_point(obj->ox, obj->oy);
+
+       /* ** we are now done adjusting the object ** */
+
+
+       /* swap otmp for obj */
+       replace_object(obj, otmp);
+       if (obj_location == OBJ_INVENT) {
+           /*
+            * We may need to do extra adjustments for the hero if we're
+            * messing with the hero's inventory.  The following calls are
+            * equivalent to calling freeinv on obj and addinv on otmp,
+            * while doing an in-place swap of the actual objects.
+            */
+           freeinv_core(obj);
+           addinv_core1(otmp);
+           addinv_core2(otmp);
+       }
+
+       if ((!carried(otmp) || obj->unpaid) &&
+               get_obj_location(otmp, &ox, &oy, BURIED_TOO|CONTAINED_TOO) &&
+               costly_spot(ox, oy)) {
+           register struct monst *shkp =
+               shop_keeper(*in_rooms(ox, oy, SHOPBASE));
+
+           if ((!obj->no_charge ||
+                (Has_contents(obj) &&
+                   (contained_cost(obj, shkp, 0L, FALSE, FALSE) != 0L)))
+              && inhishop(shkp)) {
+               if(shkp->mpeaceful) {
+                   if(*u.ushops && *in_rooms(u.ux, u.uy, 0) ==
+                           *in_rooms(shkp->mx, shkp->my, 0) &&
+                           !costly_spot(u.ux, u.uy))
+                       make_angry_shk(shkp, ox, oy);
+                   else {
+                       pline("%s gets angry!", Monnam(shkp));
+                       hot_pursuit(shkp);
+                   }
+               } else Norep("%s is furious!", Monnam(shkp));
+           }
+       }
+       delobj(obj);
+       return otmp;
+}
+
+/*
+ * Object obj was hit by the effect of the wand/spell otmp.  Return
+ * non-zero if the wand/spell had any effect.
+ */
+int
+bhito(obj, otmp)
+struct obj *obj, *otmp;
+{
+       int res = 1;    /* affected object by default */
+       xchar refresh_x, refresh_y;
+
+       if (obj->bypass) {
+               /* The bypass bit is currently only used as follows:
+                *
+                * POLYMORPH - When a monster being polymorphed drops something
+                *             from its inventory as a result of the change.
+                *             If the items fall to the floor, they are not
+                *             subject to direct subsequent polymorphing
+                *             themselves on that same zap. This makes it
+                *             consistent with items that remain in the
+                *             monster's inventory. They are not polymorphed
+                *             either.
+                * UNDEAD_TURNING - When an undead creature gets killed via
+                *             undead turning, prevent its corpse from being
+                *             immediately revived by the same effect.
+                *
+                * The bypass bit on all objects is reset each turn, whenever
+                * flags.bypasses is set.
+                *
+                * We check the obj->bypass bit above AND flags.bypasses
+                * as a safeguard against any stray occurrence left in an obj
+                * struct someplace, although that should never happen.
+                */
+               if (flags.bypasses)
+                       return 0;
+               else {
+#ifdef DEBUG
+                       pline("%s for a moment.", Tobjnam(obj, "pulsate"));
+#endif
+                       obj->bypass = 0;
+               }
+       }
+
+       /*
+        * Some parts of this function expect the object to be on the floor
+        * obj->{ox,oy} to be valid.  The exception to this (so far) is
+        * for the STONE_TO_FLESH spell.
+        */
+       if (!(obj->where == OBJ_FLOOR || otmp->otyp == SPE_STONE_TO_FLESH))
+           impossible("bhito: obj is not floor or Stone To Flesh spell");
+
+       if (obj == uball) {
+               res = 0;
+       } else if (obj == uchain) {
+               if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) {
+                   unpunish();
+                   makeknown(otmp->otyp);
+               } else
+                   res = 0;
+       } else
+       switch(otmp->otyp) {
+       case WAN_POLYMORPH:
+       case SPE_POLYMORPH:
+               if (obj->otyp == WAN_POLYMORPH ||
+                       obj->otyp == SPE_POLYMORPH ||
+                       obj->otyp == POT_POLYMORPH ||
+                       obj_resists(obj, 5, 95)) {
+                   res = 0;
+                   break;
+               }
+               /* KMH, conduct */
+               u.uconduct.polypiles++;
+               /* any saved lock context will be dangerously obsolete */
+               if (Is_box(obj)) (void) boxlock(obj, otmp);
+
+               if (obj_shudders(obj)) {
+                   if (cansee(obj->ox, obj->oy))
+                       makeknown(otmp->otyp);
+                   do_osshock(obj);
+                   break;
+               }
+               obj = poly_obj(obj, STRANGE_OBJECT);
+               newsym(obj->ox,obj->oy);
+               break;
+       case WAN_PROBING:
+               res = !obj->dknown;
+               /* target object has now been "seen (up close)" */
+               obj->dknown = 1;
+               if (Is_container(obj) || obj->otyp == STATUE) {
+                   if (!obj->cobj)
+                       pline("%s empty.", Tobjnam(obj, "are"));
+                   else {
+                       struct obj *o;
+                       /* view contents (not recursively) */
+                       for (o = obj->cobj; o; o = o->nobj)
+                           o->dknown = 1;      /* "seen", even if blind */
+                       (void) display_cinventory(obj);
+                   }
+                   res = 1;
+               }
+               if (res) makeknown(WAN_PROBING);
+               break;
+       case WAN_STRIKING:
+       case SPE_FORCE_BOLT:
+               if (obj->otyp == BOULDER)
+                       fracture_rock(obj);
+               else if (obj->otyp == STATUE)
+                       (void) break_statue(obj);
+               else {
+                       if (!flags.mon_moving)
+                           (void)hero_breaks(obj, obj->ox, obj->oy, FALSE);
+                       else
+                           (void)breaks(obj, obj->ox, obj->oy);
+                       res = 0;
+               }
+               /* BUG[?]: shouldn't this depend upon you seeing it happen? */
+               makeknown(otmp->otyp);
+               break;
+       case WAN_CANCELLATION:
+       case SPE_CANCELLATION:
+               cancel_item(obj);
+#ifdef TEXTCOLOR
+               newsym(obj->ox,obj->oy);        /* might change color */
+#endif
+               break;
+       case SPE_DRAIN_LIFE:
+               (void) drain_item(obj);
+               break;
+       case WAN_TELEPORTATION:
+       case SPE_TELEPORT_AWAY:
+               rloco(obj);
+               break;
+       case WAN_MAKE_INVISIBLE:
+#ifdef INVISIBLE_OBJECTS
+               obj->oinvis = TRUE;
+               newsym(obj->ox,obj->oy);        /* make object disappear */
+#endif
+               break;
+       case WAN_UNDEAD_TURNING:
+       case SPE_TURN_UNDEAD:
+               if (obj->otyp == EGG)
+                       revive_egg(obj);
+               else
+                       res = !!revive(obj);
+               break;
+       case WAN_OPENING:
+       case SPE_KNOCK:
+       case WAN_LOCKING:
+       case SPE_WIZARD_LOCK:
+               if(Is_box(obj))
+                       res = boxlock(obj, otmp);
+               else
+                       res = 0;
+               if (res /* && otmp->oclass == WAND_CLASS */)
+                       makeknown(otmp->otyp);
+               break;
+       case WAN_SLOW_MONSTER:          /* no effect on objects */
+       case SPE_SLOW_MONSTER:
+       case WAN_SPEED_MONSTER:
+       case WAN_NOTHING:
+       case SPE_HEALING:
+       case SPE_EXTRA_HEALING:
+               res = 0;
+               break;
+       case SPE_STONE_TO_FLESH:
+               refresh_x = obj->ox; refresh_y = obj->oy;
+               if (objects[obj->otyp].oc_material != MINERAL &&
+                       objects[obj->otyp].oc_material != GEMSTONE) {
+                   res = 0;
+                   break;
+               }
+               /* add more if stone objects are added.. */
+               switch (objects[obj->otyp].oc_class) {
+                   case ROCK_CLASS:    /* boulders and statues */
+                       if (obj->otyp == BOULDER) {
+                           obj = poly_obj(obj, HUGE_CHUNK_OF_MEAT);
+                           goto smell;
+                       } else if (obj->otyp == STATUE) {
+                           xchar oox, ooy;
+
+                           (void) get_obj_location(obj, &oox, &ooy, 0);
+                           refresh_x = oox; refresh_y = ooy;
+                           if (vegetarian(&mons[obj->corpsenm])) {
+                               /* Don't animate monsters that aren't flesh */
+                               obj = poly_obj(obj, MEATBALL);
+                               goto smell;
+                           }
+                           if (!animate_statue(obj, oox, ooy,
+                                               ANIMATE_SPELL, (int *)0)) {
+                               struct obj *item;
+makecorpse:                    if (mons[obj->corpsenm].geno &
+                                                       (G_NOCORPSE|G_UNIQ)) {
+                                   res = 0;
+                                   break;
+                               }
+                               /* Unlikely to get here since genociding
+                                * monsters also sets the G_NOCORPSE flag.
+                                * Drop the contents, poly_obj looses them.
+                                */
+                               while ((item = obj->cobj) != 0) {
+                                   obj_extract_self(item);
+                                   place_object(item, oox, ooy);
+                               }
+                               obj = poly_obj(obj, CORPSE);
+                               break;
+                           }
+                       } else { /* new rock class object... */
+                           /* impossible? */
+                           res = 0;
+                       }
+                       break;
+                   case TOOL_CLASS:    /* figurine */
+                   {
+                       struct monst *mon;
+                       xchar oox, ooy;
+
+                       if (obj->otyp != FIGURINE) {
+                           res = 0;
+                           break;
+                       }
+                       if (vegetarian(&mons[obj->corpsenm])) {
+                           /* Don't animate monsters that aren't flesh */
+                           obj = poly_obj(obj, MEATBALL);
+                           goto smell;
+                       }
+                       (void) get_obj_location(obj, &oox, &ooy, 0);
+                       refresh_x = oox; refresh_y = ooy;
+                       mon = makemon(&mons[obj->corpsenm],
+                                     oox, ooy, NO_MM_FLAGS);
+                       if (mon) {
+                           delobj(obj);
+                           if (cansee(mon->mx, mon->my))
+                               pline_The("figurine animates!");
+                           break;
+                       }
+                       goto makecorpse;
+                   }
+                   /* maybe add weird things to become? */
+                   case RING_CLASS:    /* some of the rings are stone */
+                       obj = poly_obj(obj, MEAT_RING);
+                       goto smell;
+                   case WAND_CLASS:    /* marble wand */
+                       obj = poly_obj(obj, MEAT_STICK);
+                       goto smell;
+                   case GEM_CLASS:     /* rocks & gems */
+                       obj = poly_obj(obj, MEATBALL);
+smell:
+                       if (herbivorous(youmonst.data) &&
+                           (!carnivorous(youmonst.data) ||
+                            Role_if(PM_MONK) || !u.uconduct.unvegetarian))
+                           Norep("You smell the odor of meat.");
+                       else
+                           Norep("You smell a delicious smell.");
+                       break;
+                   case WEAPON_CLASS:  /* crysknife */
+                       /* fall through */
+                   default:
+                       res = 0;
+                       break;
+               }
+               newsym(refresh_x, refresh_y);
+               break;
+       default:
+               impossible("What an interesting effect (%d)", otmp->otyp);
+               break;
+       }
+       return res;
+}
+
+/* returns nonzero if something was hit */
+int
+bhitpile(obj,fhito,tx,ty)
+    struct obj *obj;
+    int FDECL((*fhito), (OBJ_P,OBJ_P));
+    int tx, ty;
+{
+    int hitanything = 0;
+    register struct obj *otmp, *next_obj;
+
+    if (obj->otyp == SPE_FORCE_BOLT || obj->otyp == WAN_STRIKING) {
+       struct trap *t = t_at(tx, ty);
+
+       /* We can't settle for the default calling sequence of
+          bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy)
+          because that last call might end up operating on our `next_obj'
+          (below), rather than on the current object, if it happens to
+          encounter a statue which mustn't become animated. */
+       if (t && t->ttyp == STATUE_TRAP &&
+           activate_statue_trap(t, tx, ty, TRUE) && obj->otyp == WAN_STRIKING)
+           makeknown(obj->otyp);
+    }
+
+    poly_zapped = -1;
+    for(otmp = level.objects[tx][ty]; otmp; otmp = next_obj) {
+       /* Fix for polymorph bug, Tim Wright */
+       next_obj = otmp->nexthere;
+       hitanything += (*fhito)(otmp, obj);
+    }
+    if(poly_zapped >= 0)
+       create_polymon(level.objects[tx][ty], poly_zapped);
+
+    return hitanything;
+}
+#endif /*OVLB*/
+#ifdef OVL1
+
+/*
+ * zappable - returns 1 if zap is available, 0 otherwise.
+ *           it removes a charge from the wand if zappable.
+ * added by GAN 11/03/86
+ */
+int
+zappable(wand)
+register struct obj *wand;
+{
+       if(wand->spe < 0 || (wand->spe == 0 && rn2(121)))
+               return 0;
+       if(wand->spe == 0)
+               You("wrest one last charge from the worn-out wand.");
+       wand->spe--;
+       return 1;
+}
+
+/*
+ * zapnodir - zaps a NODIR wand/spell.
+ * added by GAN 11/03/86
+ */
+void
+zapnodir(obj)
+register struct obj *obj;
+{
+       boolean known = FALSE;
+
+       switch(obj->otyp) {
+               case WAN_LIGHT:
+               case SPE_LIGHT:
+                       litroom(TRUE,obj);
+                       if (!Blind) known = TRUE;
+                       break;
+               case WAN_SECRET_DOOR_DETECTION:
+               case SPE_DETECT_UNSEEN:
+                       if(!findit()) return;
+                       if (!Blind) known = TRUE;
+                       break;
+               case WAN_CREATE_MONSTER:
+                       known = create_critters(rn2(23) ? 1 : rn1(7,2),
+                                       (struct permonst *)0);
+                       break;
+               case WAN_WISHING:
+                       known = TRUE;
+                       if(Luck + rn2(5) < 0) {
+                               pline("Unfortunately, nothing happens.");
+                               break;
+                       }
+                       makewish();
+                       break;
+               case WAN_ENLIGHTENMENT:
+                       known = TRUE;
+                       You_feel("self-knowledgeable...");
+                       display_nhwindow(WIN_MESSAGE, FALSE);
+                       enlightenment(FALSE);
+                       pline_The("feeling subsides.");
+                       exercise(A_WIS, TRUE);
+                       break;
+       }
+       if (known && !objects[obj->otyp].oc_name_known) {
+               makeknown(obj->otyp);
+               more_experienced(0,10);
+       }
+}
+#endif /*OVL1*/
+#ifdef OVL0
+
+STATIC_OVL void
+backfire(otmp)
+struct obj *otmp;
+{
+       otmp->in_use = TRUE;    /* in case losehp() is fatal */
+       pline("%s suddenly explodes!", The(xname(otmp)));
+       losehp(d(otmp->spe+2,6), "exploding wand", KILLED_BY_AN);
+       useup(otmp);
+}
+
+static NEARDATA const char zap_syms[] = { WAND_CLASS, 0 };
+
+int
+dozap()
+{
+       register struct obj *obj;
+       int     damage;
+
+       if(check_capacity((char *)0)) return(0);
+       obj = getobj(zap_syms, "zap");
+       if(!obj) return(0);
+
+       check_unpaid(obj);
+
+       /* zappable addition done by GAN 11/03/86 */
+       if(!zappable(obj)) pline(nothing_happens);
+       else if(obj->cursed && !rn2(100)) {
+               backfire(obj);  /* the wand blows up in your face! */
+               exercise(A_STR, FALSE);
+               return(1);
+       } else if(!(objects[obj->otyp].oc_dir == NODIR) && !getdir((char *)0)) {
+               if (!Blind)
+                   pline("%s glows and fades.", The(xname(obj)));
+               /* make him pay for knowing !NODIR */
+       } else if(!u.dx && !u.dy && !u.dz && !(objects[obj->otyp].oc_dir == NODIR)) {
+           if ((damage = zapyourself(obj, TRUE)) != 0) {
+               char buf[BUFSZ];
+               Sprintf(buf, "zapped %sself with a wand", uhim());
+               losehp(damage, buf, NO_KILLER_PREFIX);
+           }
+       } else {
+
+               /*      Are we having fun yet?
+                * weffects -> buzz(obj->otyp) -> zhitm (temple priest) ->
+                * attack -> hitum -> known_hitum -> ghod_hitsu ->
+                * buzz(AD_ELEC) -> destroy_item(WAND_CLASS) ->
+                * useup -> obfree -> dealloc_obj -> free(obj)
+                */
+               current_wand = obj;
+               weffects(obj);
+               obj = current_wand;
+               current_wand = 0;
+       }
+       if (obj && obj->spe < 0) {
+           pline("%s to dust.", Tobjnam(obj, "turn"));
+           useup(obj);
+       }
+       update_inventory();     /* maybe used a charge */
+       return(1);
+}
+
+int
+zapyourself(obj, ordinary)
+struct obj *obj;
+boolean ordinary;
+{
+       int     damage = 0;
+       char buf[BUFSZ];
+
+       switch(obj->otyp) {
+               case WAN_STRIKING:
+                   makeknown(WAN_STRIKING);
+               case SPE_FORCE_BOLT:
+                   if(Antimagic) {
+                       shieldeff(u.ux, u.uy);
+                       pline("Boing!");
+                   } else {
+                       if (ordinary) {
+                           You("bash yourself!");
+                           damage = d(2,12);
+                       } else
+                           damage = d(1 + obj->spe,6);
+                       exercise(A_STR, FALSE);
+                   }
+                   break;
+
+               case WAN_LIGHTNING:
+                   makeknown(WAN_LIGHTNING);
+                   if (!Shock_resistance) {
+                       You("shock yourself!");
+                       damage = d(12,6);
+                       exercise(A_CON, FALSE);
+                   } else {
+                       shieldeff(u.ux, u.uy);
+                       You("zap yourself, but seem unharmed.");
+                       ugolemeffects(AD_ELEC, d(12,6));
+                   }
+                   destroy_item(WAND_CLASS, AD_ELEC);
+                   destroy_item(RING_CLASS, AD_ELEC);
+                   if (!resists_blnd(&youmonst)) {
+                           You(are_blinded_by_the_flash);
+                           make_blinded((long)rnd(100),FALSE);
+                           if (!Blind) Your(vision_clears);
+                   }
+                   break;
+
+               case SPE_FIREBALL:
+                   You("explode a fireball on top of yourself!");
+                   explode(u.ux, u.uy, 11, d(6,6), WAND_CLASS, EXPL_FIERY);
+                   break;
+               case WAN_FIRE:
+                   makeknown(WAN_FIRE);
+               case FIRE_HORN:
+                   if (Fire_resistance) {
+                       shieldeff(u.ux, u.uy);
+                       You_feel("rather warm.");
+                       ugolemeffects(AD_FIRE, d(12,6));
+                   } else {
+                       pline("You've set yourself afire!");
+                       damage = d(12,6);
+                   }
+                   burn_away_slime();
+                   (void) burnarmor(&youmonst);
+                   destroy_item(SCROLL_CLASS, AD_FIRE);
+                   destroy_item(POTION_CLASS, AD_FIRE);
+                   destroy_item(SPBOOK_CLASS, AD_FIRE);
+                   break;
+
+               case WAN_COLD:
+                   makeknown(WAN_COLD);
+               case SPE_CONE_OF_COLD:
+               case FROST_HORN:
+                   if (Cold_resistance) {
+                       shieldeff(u.ux, u.uy);
+                       You_feel("a little chill.");
+                       ugolemeffects(AD_COLD, d(12,6));
+                   } else {
+                       You("imitate a popsicle!");
+                       damage = d(12,6);
+                   }
+                   destroy_item(POTION_CLASS, AD_COLD);
+                   break;
+
+               case WAN_MAGIC_MISSILE:
+                   makeknown(WAN_MAGIC_MISSILE);
+               case SPE_MAGIC_MISSILE:
+                   if(Antimagic) {
+                       shieldeff(u.ux, u.uy);
+                       pline_The("missiles bounce!");
+                   } else {
+                       damage = d(4,6);
+                       pline("Idiot!  You've shot yourself!");
+                   }
+                   break;
+
+               case WAN_POLYMORPH:
+                   if (!Unchanging)
+                       makeknown(WAN_POLYMORPH);
+               case SPE_POLYMORPH:
+                   if (!Unchanging)
+                       polyself(FALSE);
+                   break;
+
+               case WAN_CANCELLATION:
+               case SPE_CANCELLATION:
+                   (void) cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE);
+                   break;
+
+               case SPE_DRAIN_LIFE:
+                       if (!Drain_resistance) {
+                               losexp("life drainage");
+                               makeknown(obj->otyp);
+                       }
+                       damage = 0;     /* No additional damage */
+                       break;
+
+               case WAN_MAKE_INVISIBLE: {
+                   /* have to test before changing HInvis but must change
+                    * HInvis before doing newsym().
+                    */
+                   int msg = !Invis && !Blind && !BInvis;
+
+                   if (BInvis && uarmc->otyp == MUMMY_WRAPPING) {
+                       /* A mummy wrapping absorbs it and protects you */
+                       You_feel("rather itchy under your %s.", xname(uarmc));
+                       break;
+                   }
+                   if (ordinary || !rn2(10)) { /* permanent */
+                       HInvis |= FROMOUTSIDE;
+                   } else {                    /* temporary */
+                       incr_itimeout(&HInvis, d(obj->spe, 250));
+                   }
+                   if (msg) {
+                       makeknown(WAN_MAKE_INVISIBLE);
+                       newsym(u.ux, u.uy);
+                       self_invis_message();
+                   }
+                   break;
+               }
+
+               case WAN_SPEED_MONSTER:
+                   if (!(HFast & INTRINSIC)) {
+                       if (!Fast)
+                           You("speed up.");
+                       else
+                           Your("quickness feels more natural.");
+                       makeknown(WAN_SPEED_MONSTER);
+                       exercise(A_DEX, TRUE);
+                   }
+                   HFast |= FROMOUTSIDE;
+                   break;
+
+               case WAN_SLEEP:
+                   makeknown(WAN_SLEEP);
+               case SPE_SLEEP:
+                   if(Sleep_resistance) {
+                       shieldeff(u.ux, u.uy);
+                       You("don't feel sleepy!");
+                   } else {
+                       pline_The("sleep ray hits you!");
+                       fall_asleep(-rnd(50), TRUE);
+                   }
+                   break;
+
+               case WAN_SLOW_MONSTER:
+               case SPE_SLOW_MONSTER:
+                   if(HFast & (TIMEOUT | INTRINSIC)) {
+                       u_slow_down();
+                       makeknown(obj->otyp);
+                   }
+                   break;
+
+               case WAN_TELEPORTATION:
+               case SPE_TELEPORT_AWAY:
+                   tele();
+                   break;
+
+               case WAN_DEATH:
+               case SPE_FINGER_OF_DEATH:
+                   if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
+                       pline((obj->otyp == WAN_DEATH) ?
+                         "The wand shoots an apparently harmless beam at you."
+                         : "You seem no deader than before.");
+                       break;
+                   }
+                   Sprintf(buf, "shot %sself with a death ray", uhim());
+                   killer = buf;
+                   killer_format = NO_KILLER_PREFIX;
+                   You("irradiate yourself with pure energy!");
+                   You("die.");
+                   makeknown(obj->otyp);
+                       /* They might survive with an amulet of life saving */
+                   done(DIED);
+                   break;
+               case WAN_UNDEAD_TURNING:
+                   makeknown(WAN_UNDEAD_TURNING);
+               case SPE_TURN_UNDEAD:
+                   (void) unturn_dead(&youmonst);
+                   if (is_undead(youmonst.data)) {
+                       You_feel("frightened and %sstunned.",
+                            Stunned ? "even more " : "");
+                       make_stunned(HStun + rnd(30), FALSE);
+                   } else
+                       You("shudder in dread.");
+                   break;
+               case SPE_HEALING:
+               case SPE_EXTRA_HEALING:
+                   healup(d(6, obj->otyp == SPE_EXTRA_HEALING ? 8 : 4),
+                          0, FALSE, (obj->otyp == SPE_EXTRA_HEALING));
+                   You_feel("%sbetter.",
+                       obj->otyp == SPE_EXTRA_HEALING ? "much " : "");
+                   break;
+               case WAN_LIGHT: /* (broken wand) */
+                /* assert( !ordinary ); */
+                   damage = d(obj->spe, 25);
+#ifdef TOURIST
+               case EXPENSIVE_CAMERA:
+#endif
+                   damage += rnd(25);
+                   if (!resists_blnd(&youmonst)) {
+                       You(are_blinded_by_the_flash);
+                       make_blinded((long)damage, FALSE);
+                       makeknown(obj->otyp);
+                       if (!Blind) Your(vision_clears);
+                   }
+                   damage = 0; /* reset */
+                   break;
+               case WAN_OPENING:
+                   if (Punished) makeknown(WAN_OPENING);
+               case SPE_KNOCK:
+                   if (Punished) Your("chain quivers for a moment.");
+                   break;
+               case WAN_DIGGING:
+               case SPE_DIG:
+               case SPE_DETECT_UNSEEN:
+               case WAN_NOTHING:
+               case WAN_LOCKING:
+               case SPE_WIZARD_LOCK:
+                   break;
+               case WAN_PROBING:
+                   for (obj = invent; obj; obj = obj->nobj)
+                       obj->dknown = 1;
+                   /* note: `obj' reused; doesn't point at wand anymore */
+                   makeknown(WAN_PROBING);
+                   ustatusline();
+                   break;
+               case SPE_STONE_TO_FLESH:
+                   {
+                   struct obj *otemp, *onext;
+                   boolean didmerge;
+
+                   if (u.umonnum == PM_STONE_GOLEM)
+                       (void) polymon(PM_FLESH_GOLEM);
+                   if (Stoned) fix_petrification();    /* saved! */
+                   /* but at a cost.. */
+                   for (otemp = invent; otemp; otemp = onext) {
+                       onext = otemp->nobj;
+                       (void) bhito(otemp, obj);
+                       }
+                   /*
+                    * It is possible that we can now merge some inventory.
+                    * Do a higly paranoid merge.  Restart from the beginning
+                    * until no merges.
+                    */
+                   do {
+                       didmerge = FALSE;
+                       for (otemp = invent; !didmerge && otemp; otemp = otemp->nobj)
+                           for (onext = otemp->nobj; onext; onext = onext->nobj)
+                               if (merged(&otemp, &onext)) {
+                                       didmerge = TRUE;
+                                       break;
+                                       }
+                   } while (didmerge);
+                   }
+                   break;
+               default: impossible("object %d used?",obj->otyp);
+                   break;
+       }
+       return(damage);
+}
+
+#ifdef STEED
+/* you've zapped a wand downwards while riding
+ * Return TRUE if the steed was hit by the wand.
+ * Return FALSE if the steed was not hit by the wand.
+ */
+STATIC_OVL boolean
+zap_steed(obj)
+struct obj *obj;       /* wand or spell */
+{
+       int steedhit = FALSE;
+       
+       switch (obj->otyp) {
+
+          /*
+           * Wands that are allowed to hit the steed
+           * Carefully test the results of any that are
+           * moved here from the bottom section.
+           */
+               case WAN_PROBING:
+                   probe_monster(u.usteed);
+                   makeknown(WAN_PROBING);
+                   steedhit = TRUE;
+                   break;
+               case WAN_TELEPORTATION:
+               case SPE_TELEPORT_AWAY:
+                   /* you go together */
+                   tele();
+                   if(Teleport_control || !couldsee(u.ux0, u.uy0) ||
+                       (distu(u.ux0, u.uy0) >= 16))
+                               makeknown(obj->otyp);
+                   steedhit = TRUE;
+                   break;
+
+               /* Default processing via bhitm() for these */
+               case SPE_CURE_SICKNESS:
+               case WAN_MAKE_INVISIBLE:
+               case WAN_CANCELLATION:
+               case SPE_CANCELLATION:
+               case WAN_POLYMORPH:
+               case SPE_POLYMORPH:
+               case WAN_STRIKING:
+               case SPE_FORCE_BOLT:
+               case WAN_SLOW_MONSTER:
+               case SPE_SLOW_MONSTER:
+               case WAN_SPEED_MONSTER:
+               case SPE_HEALING:
+               case SPE_EXTRA_HEALING:
+               case SPE_DRAIN_LIFE:
+               case WAN_OPENING:
+               case SPE_KNOCK:
+                   (void) bhitm(u.usteed, obj);
+                   steedhit = TRUE;
+                   break;
+
+               default:
+                   steedhit = FALSE;
+                   break;
+       }
+       return steedhit;
+}
+#endif
+
+#endif /*OVL0*/
+#ifdef OVL3
+
+/*
+ * cancel a monster (possibly the hero).  inventory is cancelled only
+ * if the monster is zapping itself directly, since otherwise the
+ * effect is too strong.  currently non-hero monsters do not zap
+ * themselves with cancellation.
+ */
+boolean
+cancel_monst(mdef, obj, youattack, allow_cancel_kill, self_cancel)
+register struct monst  *mdef;
+register struct obj    *obj;
+boolean                        youattack, allow_cancel_kill, self_cancel;
+{
+       boolean youdefend = (mdef == &youmonst);
+       static const char writing_vanishes[] =
+                               "Some writing vanishes from %s head!";
+       static const char your[] = "your";      /* should be extern */
+
+       if (youdefend ? (!youattack && Antimagic)
+                     : resist(mdef, obj->oclass, 0, NOTELL))
+               return FALSE;   /* resisted cancellation */
+
+       if (self_cancel) {      /* 1st cancel inventory */
+           struct obj *otmp;
+
+           for (otmp = (youdefend ? invent : mdef->minvent);
+                           otmp; otmp = otmp->nobj)
+               cancel_item(otmp);
+           if (youdefend) {
+               flags.botl = 1; /* potential AC change */
+               find_ac();
+           }
+       }
+
+       /* now handle special cases */
+       if (youdefend) {
+           if (Upolyd) {
+               if ((u.umonnum == PM_CLAY_GOLEM) && !Blind)
+                   pline(writing_vanishes, your);
+
+               if (Unchanging)
+                   Your("amulet grows hot for a moment, then cools.");
+               else
+                   rehumanize();
+           }
+       } else {
+           mdef->mcan = TRUE;
+
+           if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN)
+               were_change(mdef);
+
+           if (mdef->data == &mons[PM_CLAY_GOLEM]) {
+               if (canseemon(mdef))
+                   pline(writing_vanishes, s_suffix(mon_nam(mdef)));
+
+               if (allow_cancel_kill) {
+                   if (youattack)
+                       killed(mdef);
+                   else
+                       monkilled(mdef, "", AD_SPEL);
+               }
+           }
+       }
+       return TRUE;
+}
+
+/* you've zapped an immediate type wand up or down */
+STATIC_OVL boolean
+zap_updown(obj)
+struct obj *obj;       /* wand or spell */
+{
+       boolean striking = FALSE, disclose = FALSE;
+       int x, y, xx, yy, ptmp;
+       struct obj *otmp;
+       struct engr *e;
+       struct trap *ttmp;
+       char buf[BUFSZ];
+
+       /* some wands have special effects other than normal bhitpile */
+       /* drawbridge might change <u.ux,u.uy> */
+       x = xx = u.ux;  /* <x,y> is zap location */
+       y = yy = u.uy;  /* <xx,yy> is drawbridge (portcullis) position */
+       ttmp = t_at(x, y); /* trap if there is one */
+
+       switch (obj->otyp) {
+       case WAN_PROBING:
+           ptmp = 0;
+           if (u.dz < 0) {
+               You("probe towards the %s.", ceiling(x,y));
+           } else {
+               ptmp += bhitpile(obj, bhito, x, y);
+               You("probe beneath the %s.", surface(x,y));
+               ptmp += display_binventory(x, y, TRUE);
+           }
+           if (!ptmp) Your("probe reveals nothing.");
+           return TRUE;        /* we've done our own bhitpile */
+       case WAN_OPENING:
+       case SPE_KNOCK:
+           /* up or down, but at closed portcullis only */
+           if (is_db_wall(x,y) && find_drawbridge(&xx, &yy)) {
+               open_drawbridge(xx, yy);
+               disclose = TRUE;
+           } else if (u.dz > 0 && (x == xdnstair && y == ydnstair) &&
+                       /* can't use the stairs down to quest level 2 until
+                          leader "unlocks" them; give feedback if you try */
+                       on_level(&u.uz, &qstart_level) && !ok_to_quest()) {
+               pline_The("stairs seem to ripple momentarily.");
+               disclose = TRUE;
+           }
+           break;
+       case WAN_STRIKING:
+       case SPE_FORCE_BOLT:
+           striking = TRUE;
+           /*FALLTHRU*/
+       case WAN_LOCKING:
+       case SPE_WIZARD_LOCK:
+           /* down at open bridge or up or down at open portcullis */
+           if ((levl[x][y].typ == DRAWBRIDGE_DOWN) ? (u.dz > 0) :
+                       (is_drawbridge_wall(x,y) && !is_db_wall(x,y)) &&
+                   find_drawbridge(&xx, &yy)) {
+               if (!striking)
+                   close_drawbridge(xx, yy);
+               else
+                   destroy_drawbridge(xx, yy);
+               disclose = TRUE;
+           } else if (striking && u.dz < 0 && rn2(3) &&
+                       !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) &&
+                       !Underwater && !Is_qstart(&u.uz)) {
+               /* similar to zap_dig() */
+               pline("A rock is dislodged from the %s and falls on your %s.",
+                     ceiling(x, y), body_part(HEAD));
+               losehp(rnd((uarmh && is_metallic(uarmh)) ? 2 : 6),
+                      "falling rock", KILLED_BY_AN);
+               if ((otmp = mksobj_at(ROCK, x, y, FALSE, FALSE)) != 0) {
+                   (void)xname(otmp);  /* set dknown, maybe bknown */
+                   stackobj(otmp);
+               }
+               newsym(x, y);
+           } else if (!striking && ttmp && ttmp->ttyp == TRAPDOOR && u.dz > 0) {
+               if (!Blind) {
+                       if (ttmp->tseen) {
+                               pline("A trap door beneath you closes up then vanishes.");
+                               disclose = TRUE;
+                       } else {
+                               You("see a swirl of %s beneath you.",
+                                       is_ice(x,y) ? "frost" : "dust");
+                       }
+               } else {
+                       You_hear("a twang followed by a thud.");
+               }
+               deltrap(ttmp);
+               ttmp = (struct trap *)0;
+               newsym(x, y);
+           }
+           break;
+       case SPE_STONE_TO_FLESH:
+           if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ||
+                    Underwater || (Is_qstart(&u.uz) && u.dz < 0)) {
+               pline(nothing_happens);
+           } else if (u.dz < 0) {      /* we should do more... */
+               pline("Blood drips on your %s.", body_part(FACE));
+           } else if (u.dz > 0 && !OBJ_AT(u.ux, u.uy)) {
+               /*
+               Print this message only if there wasn't an engraving
+               affected here.  If water or ice, act like waterlevel case.
+               */
+               e = engr_at(u.ux, u.uy);
+               if (!(e && e->engr_type == ENGRAVE)) {
+                   if (is_pool(u.ux, u.uy) || is_ice(u.ux, u.uy))
+                       pline(nothing_happens);
+                   else
+                       pline("Blood %ss %s your %s.",
+                             is_lava(u.ux, u.uy) ? "boil" : "pool",
+                             Levitation ? "beneath" : "at",
+                             makeplural(body_part(FOOT)));
+               }
+           }
+           break;
+       default:
+           break;
+       }
+
+       if (u.dz > 0) {
+           /* zapping downward */
+           (void) bhitpile(obj, bhito, x, y);
+
+           /* subset of engraving effects; none sets `disclose' */
+           if ((e = engr_at(x, y)) != 0 && e->engr_type != HEADSTONE) {
+               switch (obj->otyp) {
+               case WAN_POLYMORPH:
+               case SPE_POLYMORPH:
+                   del_engr(e);
+                   make_engr_at(x, y, random_engraving(buf), moves, (xchar)0);
+                   break;
+               case WAN_CANCELLATION:
+               case SPE_CANCELLATION:
+               case WAN_MAKE_INVISIBLE:
+                   del_engr(e);
+                   break;
+               case WAN_TELEPORTATION:
+               case SPE_TELEPORT_AWAY:
+                   rloc_engr(e);
+                   break;
+               case SPE_STONE_TO_FLESH:
+                   if (e->engr_type == ENGRAVE) {
+                       /* only affects things in stone */
+                       pline_The(Hallucination ?
+                           "floor runs like butter!" :
+                           "edges on the floor get smoother.");
+                       wipe_engr_at(x, y, d(2,4));
+                       }
+                   break;
+               case WAN_STRIKING:
+               case SPE_FORCE_BOLT:
+                   wipe_engr_at(x, y, d(2,4));
+                   break;
+               default:
+                   break;
+               }
+           }
+       }
+
+       return disclose;
+}
+
+#endif /*OVL3*/
+#ifdef OVLB
+
+/* called for various wand and spell effects - M. Stephenson */
+void
+weffects(obj)
+register struct        obj     *obj;
+{
+       int otyp = obj->otyp;
+       boolean disclose = FALSE, was_unkn = !objects[otyp].oc_name_known;
+
+       exercise(A_WIS, TRUE);
+#ifdef STEED
+       if (u.usteed && (objects[otyp].oc_dir != NODIR) &&
+           !u.dx && !u.dy && (u.dz > 0) && zap_steed(obj)) {
+               disclose = TRUE;
+       } else
+#endif
+       if (objects[otyp].oc_dir == IMMEDIATE) {
+           obj_zapped = FALSE;
+
+           if (u.uswallow) {
+               (void) bhitm(u.ustuck, obj);
+               /* [how about `bhitpile(u.ustuck->minvent)' effect?] */
+           } else if (u.dz) {
+               disclose = zap_updown(obj);
+           } else {
+               (void) bhit(u.dx,u.dy, rn1(8,6),ZAPPED_WAND, bhitm,bhito, obj);
+           }
+           /* give a clue if obj_zapped */
+           if (obj_zapped)
+               You_feel("shuddering vibrations.");
+
+       } else if (objects[otyp].oc_dir == NODIR) {
+           zapnodir(obj);
+
+       } else {
+           /* neither immediate nor directionless */
+
+           if (otyp == WAN_DIGGING || otyp == SPE_DIG)
+               zap_dig();
+           else if (otyp >= SPE_MAGIC_MISSILE && otyp <= SPE_FINGER_OF_DEATH)
+               buzz(otyp - SPE_MAGIC_MISSILE + 10,
+                    u.ulevel / 2 + 1,
+                    u.ux, u.uy, u.dx, u.dy);
+           else if (otyp >= WAN_MAGIC_MISSILE && otyp <= WAN_LIGHTNING)
+               buzz(otyp - WAN_MAGIC_MISSILE,
+                    (otyp == WAN_MAGIC_MISSILE) ? 2 : 6,
+                    u.ux, u.uy, u.dx, u.dy);
+           else
+               impossible("weffects: unexpected spell or wand");
+           disclose = TRUE;
+       }
+       if (disclose && was_unkn) {
+           makeknown(otyp);
+           more_experienced(0,10);
+       }
+       return;
+}
+#endif /*OVLB*/
+#ifdef OVL0
+
+/*
+ * Generate the to damage bonus for a spell. Based on the hero's intelligence
+ */
+int
+spell_damage_bonus()
+{
+    int tmp, intell = ACURR(A_INT);
+
+    /* Punish low intellegence before low level else low intellegence
+       gets punished only when high level */
+    if (intell < 10)
+       tmp = -3;
+    else if (u.ulevel < 5)
+       tmp = 0;
+    else if (intell < 14)
+       tmp = 0;
+    else if (intell <= 18)
+       tmp = 1;
+    else               /* helm of brilliance */
+       tmp = 2;
+
+    return tmp;
+}
+
+/*
+ * Generate the to hit bonus for a spell.  Based on the hero's skill in
+ * spell class and dexterity.
+ */
+STATIC_OVL int
+spell_hit_bonus(skill)
+int skill;
+{
+    int hit_bon = 0;
+    int dex = ACURR(A_DEX);
+
+    switch (P_SKILL(spell_skilltype(skill))) {
+       case P_ISRESTRICTED:
+       case P_UNSKILLED:   hit_bon = -4; break;
+       case P_BASIC:       hit_bon =  0; break;
+       case P_SKILLED:     hit_bon =  2; break;
+       case P_EXPERT:      hit_bon =  3; break;
+    }
+
+    if (dex < 4)
+       hit_bon -= 3;
+    else if (dex < 6)
+       hit_bon -= 2;
+    else if (dex < 8)
+       hit_bon -= 1;
+    else if (dex < 14)
+       hit_bon -= 0;           /* Will change when print stuff below removed */
+    else
+       hit_bon += dex - 14; /* Even increment for dextrous heroes (see weapon.c abon) */
+
+    return hit_bon;
+}
+
+const char *
+exclam(force)
+register int force;
+{
+       /* force == 0 occurs e.g. with sleep ray */
+       /* note that large force is usual with wands so that !! would
+               require information about hand/weapon/wand */
+       return (const char *)((force < 0) ? "?" : (force <= 4) ? "." : "!");
+}
+
+void
+hit(str,mtmp,force)
+register const char *str;
+register struct monst *mtmp;
+register const char *force;            /* usually either "." or "!" */
+{
+       if((!cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp) &&
+            !(u.uswallow && mtmp == u.ustuck))
+          || !flags.verbose)
+           pline("%s %s it.", The(str), vtense(str, "hit"));
+       else pline("%s %s %s%s", The(str), vtense(str, "hit"),
+                  mon_nam(mtmp), force);
+}
+
+void
+miss(str,mtmp)
+register const char *str;
+register struct monst *mtmp;
+{
+       pline("%s %s %s.", The(str), vtense(str, "miss"),
+             ((cansee(bhitpos.x,bhitpos.y) || canspotmon(mtmp))
+              && flags.verbose) ?
+             mon_nam(mtmp) : "it");
+}
+#endif /*OVL0*/
+#ifdef OVL1
+
+/*
+ *  Called for the following distance effects:
+ *     when a weapon is thrown (weapon == THROWN_WEAPON)
+ *     when an object is kicked (KICKED_WEAPON)
+ *     when an IMMEDIATE wand is zapped (ZAPPED_WAND)
+ *     when a light beam is flashed (FLASHED_LIGHT)
+ *     when a mirror is applied (INVIS_BEAM)
+ *  A thrown/kicked object falls down at the end of its range or when a monster
+ *  is hit.  The variable 'bhitpos' is set to the final position of the weapon
+ *  thrown/zapped.  The ray of a wand may affect (by calling a provided
+ *  function) several objects and monsters on its path.  The return value
+ *  is the monster hit (weapon != ZAPPED_WAND), or a null monster pointer.
+ *
+ *  Check !u.uswallow before calling bhit().
+ *  This function reveals the absence of a remembered invisible monster in
+ *  necessary cases (throwing or kicking weapons).  The presence of a real
+ *  one is revealed for a weapon, but if not a weapon is left up to fhitm().
+ */
+struct monst *
+bhit(ddx,ddy,range,weapon,fhitm,fhito,obj)
+register int ddx,ddy,range;            /* direction and range */
+int weapon;                            /* see values in hack.h */
+int FDECL((*fhitm), (MONST_P, OBJ_P)), /* fns called when mon/obj hit */
+    FDECL((*fhito), (OBJ_P, OBJ_P));
+struct obj *obj;                       /* object tossed/used */
+{
+       struct monst *mtmp;
+       uchar typ;
+       boolean shopdoor = FALSE, point_blank = TRUE;
+
+       if (weapon == KICKED_WEAPON) {
+           /* object starts one square in front of player */
+           bhitpos.x = u.ux + ddx;
+           bhitpos.y = u.uy + ddy;
+           range--;
+       } else {
+           bhitpos.x = u.ux;
+           bhitpos.y = u.uy;
+       }
+
+       if (weapon == FLASHED_LIGHT) {
+           tmp_at(DISP_BEAM, cmap_to_glyph(S_flashbeam));
+       } else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM)
+           tmp_at(DISP_FLASH, obj_to_glyph(obj));
+
+       while(range-- > 0) {
+           int x,y;
+
+           bhitpos.x += ddx;
+           bhitpos.y += ddy;
+           x = bhitpos.x; y = bhitpos.y;
+
+           if(!isok(x, y)) {
+               bhitpos.x -= ddx;
+               bhitpos.y -= ddy;
+               break;
+           }
+
+           if(is_pick(obj) && inside_shop(x, y) &&
+                                          (mtmp = shkcatch(obj, x, y))) {
+               tmp_at(DISP_END, 0);
+               return(mtmp);
+           }
+
+           typ = levl[bhitpos.x][bhitpos.y].typ;
+
+           /* iron bars will block anything big enough */
+           if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) &&
+                   typ == IRONBARS &&
+                   hits_bars(&obj, x - ddx, y - ddy,
+                             point_blank ? 0 : !rn2(5), 1)) {
+               /* caveat: obj might now be null... */
+               bhitpos.x -= ddx;
+               bhitpos.y -= ddy;
+               break;
+           }
+
+           if (weapon == ZAPPED_WAND && find_drawbridge(&x,&y))
+               switch (obj->otyp) {
+                   case WAN_OPENING:
+                   case SPE_KNOCK:
+                       if (is_db_wall(bhitpos.x, bhitpos.y)) {
+                           if (cansee(x,y) || cansee(bhitpos.x,bhitpos.y))
+                               makeknown(obj->otyp);
+                           open_drawbridge(x,y);
+                       }
+                       break;
+                   case WAN_LOCKING:
+                   case SPE_WIZARD_LOCK:
+                       if ((cansee(x,y) || cansee(bhitpos.x, bhitpos.y))
+                           && levl[x][y].typ == DRAWBRIDGE_DOWN)
+                           makeknown(obj->otyp);
+                       close_drawbridge(x,y);
+                       break;
+                   case WAN_STRIKING:
+                   case SPE_FORCE_BOLT:
+                       if (typ != DRAWBRIDGE_UP)
+                           destroy_drawbridge(x,y);
+                       makeknown(obj->otyp);
+                       break;
+               }
+
+           if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
+               notonhead = (bhitpos.x != mtmp->mx ||
+                            bhitpos.y != mtmp->my);
+               if (weapon != FLASHED_LIGHT) {
+                       if(weapon != ZAPPED_WAND) {
+                           if(weapon != INVIS_BEAM) tmp_at(DISP_END, 0);
+                           if (cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp)) {
+                               if (weapon != INVIS_BEAM) {
+                                   map_invisible(bhitpos.x, bhitpos.y);
+                                   return(mtmp);
+                               }
+                           } else
+                               return(mtmp);
+                       }
+                       if (weapon != INVIS_BEAM) {
+                           (*fhitm)(mtmp, obj);
+                           range -= 3;
+                       }
+               } else {
+                   /* FLASHED_LIGHT hitting invisible monster
+                      should pass through instead of stop so
+                      we call flash_hits_mon() directly rather
+                      than returning mtmp back to caller. That
+                      allows the flash to keep on going. Note
+                      that we use mtmp->minvis not canspotmon()
+                      because it makes no difference whether
+                      the hero can see the monster or not.*/
+                   if (mtmp->minvis) {
+                       obj->ox = u.ux,  obj->oy = u.uy;
+                       (void) flash_hits_mon(mtmp, obj);
+                   } else {
+                       tmp_at(DISP_END, 0);
+                       return(mtmp);   /* caller will call flash_hits_mon */
+                   }
+               }
+           } else {
+               if (weapon == ZAPPED_WAND && obj->otyp == WAN_PROBING &&
+                  glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)) {
+                   unmap_object(bhitpos.x, bhitpos.y);
+                   newsym(x, y);
+               }
+           }
+           if(fhito) {
+               if(bhitpile(obj,fhito,bhitpos.x,bhitpos.y))
+                   range--;
+           } else {
+               if(weapon == KICKED_WEAPON &&
+                     ((obj->oclass == COIN_CLASS &&
+                        OBJ_AT(bhitpos.x, bhitpos.y)) ||
+                           ship_object(obj, bhitpos.x, bhitpos.y,
+                                       costly_spot(bhitpos.x, bhitpos.y)))) {
+                       tmp_at(DISP_END, 0);
+                       return (struct monst *)0;
+               }
+           }
+           if(weapon == ZAPPED_WAND && (IS_DOOR(typ) || typ == SDOOR)) {
+               switch (obj->otyp) {
+               case WAN_OPENING:
+               case WAN_LOCKING:
+               case WAN_STRIKING:
+               case SPE_KNOCK:
+               case SPE_WIZARD_LOCK:
+               case SPE_FORCE_BOLT:
+                   if (doorlock(obj, bhitpos.x, bhitpos.y)) {
+                       if (cansee(bhitpos.x, bhitpos.y) ||
+                           (obj->otyp == WAN_STRIKING))
+                           makeknown(obj->otyp);
+                       if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN
+                           && *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) {
+                           shopdoor = TRUE;
+                           add_damage(bhitpos.x, bhitpos.y, 400L);
+                       }
+                   }
+                   break;
+               }
+           }
+           if(!ZAP_POS(typ) || closed_door(bhitpos.x, bhitpos.y)) {
+               bhitpos.x -= ddx;
+               bhitpos.y -= ddy;
+               break;
+           }
+           if(weapon != ZAPPED_WAND && weapon != INVIS_BEAM) {
+               /* 'I' present but no monster: erase */
+               /* do this before the tmp_at() */
+               if (glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)
+                       && cansee(x, y)) {
+                   unmap_object(bhitpos.x, bhitpos.y);
+                   newsym(x, y);
+               }
+               tmp_at(bhitpos.x, bhitpos.y);
+               delay_output();
+               /* kicked objects fall in pools */
+               if((weapon == KICKED_WEAPON) &&
+                  (is_pool(bhitpos.x, bhitpos.y) ||
+                  is_lava(bhitpos.x, bhitpos.y)))
+                   break;
+#ifdef SINKS
+               if(IS_SINK(typ) && weapon != FLASHED_LIGHT)
+                   break;      /* physical objects fall onto sink */
+#endif
+           }
+           /* limit range of ball so hero won't make an invalid move */
+           if (weapon == THROWN_WEAPON && range > 0 &&
+               obj->otyp == HEAVY_IRON_BALL) {
+               struct obj *bobj;
+               struct trap *t;
+               if ((bobj = sobj_at(BOULDER, x, y)) != 0) {
+                   if (cansee(x,y))
+                       pline("%s hits %s.",
+                             The(distant_name(obj, xname)), an(xname(bobj)));
+                   range = 0;
+               } else if (obj == uball) {
+                   if (!test_move(x - ddx, y - ddy, ddx, ddy, TEST_MOVE)) {
+                       /* nb: it didn't hit anything directly */
+                       if (cansee(x,y))
+                           pline("%s jerks to an abrupt halt.",
+                                 The(distant_name(obj, xname))); /* lame */
+                       range = 0;
+                   } else if (In_sokoban(&u.uz) && (t = t_at(x, y)) != 0 &&
+                              (t->ttyp == PIT || t->ttyp == SPIKED_PIT ||
+                               t->ttyp == HOLE || t->ttyp == TRAPDOOR)) {
+                       /* hero falls into the trap, so ball stops */
+                       range = 0;
+                   }
+               }
+           }
+
+           /* thrown/kicked missile has moved away from its starting spot */
+           point_blank = FALSE;        /* affects passing through iron bars */
+       }
+
+       if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_END, 0);
+
+       if(shopdoor)
+           pay_for_damage("destroy", FALSE);
+
+       return (struct monst *)0;
+}
+
+struct monst *
+boomhit(dx, dy)
+int dx, dy;
+{
+       register int i, ct;
+       int boom = S_boomleft;  /* showsym[] index  */
+       struct monst *mtmp;
+
+       bhitpos.x = u.ux;
+       bhitpos.y = u.uy;
+
+       for (i = 0; i < 8; i++) if (xdir[i] == dx && ydir[i] == dy) break;
+       tmp_at(DISP_FLASH, cmap_to_glyph(boom));
+       for (ct = 0; ct < 10; ct++) {
+               if(i == 8) i = 0;
+               boom = (boom == S_boomleft) ? S_boomright : S_boomleft;
+               tmp_at(DISP_CHANGE, cmap_to_glyph(boom));/* change glyph */
+               dx = xdir[i];
+               dy = ydir[i];
+               bhitpos.x += dx;
+               bhitpos.y += dy;
+               if(MON_AT(bhitpos.x, bhitpos.y)) {
+                       mtmp = m_at(bhitpos.x,bhitpos.y);
+                       m_respond(mtmp);
+                       tmp_at(DISP_END, 0);
+                       return(mtmp);
+               }
+               if(!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ) ||
+                  closed_door(bhitpos.x, bhitpos.y)) {
+                       bhitpos.x -= dx;
+                       bhitpos.y -= dy;
+                       break;
+               }
+               if(bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */
+                       if(Fumbling || rn2(20) >= ACURR(A_DEX)) {
+                               /* we hit ourselves */
+                               (void) thitu(10, rnd(10), (struct obj *)0,
+                                       "boomerang");
+                               break;
+                       } else {        /* we catch it */
+                               tmp_at(DISP_END, 0);
+                               You("skillfully catch the boomerang.");
+                               return(&youmonst);
+                       }
+               }
+               tmp_at(bhitpos.x, bhitpos.y);
+               delay_output();
+               if(ct % 5 != 0) i++;
+#ifdef SINKS
+               if(IS_SINK(levl[bhitpos.x][bhitpos.y].typ))
+                       break;  /* boomerang falls on sink */
+#endif
+       }
+       tmp_at(DISP_END, 0);    /* do not leave last symbol */
+       return (struct monst *)0;
+}
+
+STATIC_OVL int
+zhitm(mon, type, nd, ootmp)                    /* returns damage to mon */
+register struct monst *mon;
+register int type, nd;
+struct obj **ootmp;    /* to return worn armor for caller to disintegrate */
+{
+       register int tmp = 0;
+       register int abstype = abs(type) % 10;
+       boolean sho_shieldeff = FALSE;
+       boolean spellcaster = is_hero_spell(type); /* maybe get a bonus! */
+
+       *ootmp = (struct obj *)0;
+       switch(abstype) {
+       case ZT_MAGIC_MISSILE:
+               if (resists_magm(mon)) {
+                   sho_shieldeff = TRUE;
+                   break;
+               }
+               tmp = d(nd,6);
+               if (spellcaster)
+                   tmp += spell_damage_bonus();
+#ifdef WIZ_PATCH_DEBUG
+               if (spellcaster)
+                   pline("Damage = %d + %d", tmp-spell_damage_bonus(),
+                       spell_damage_bonus());
+#endif
+               break;
+       case ZT_FIRE:
+               if (resists_fire(mon)) {
+                   sho_shieldeff = TRUE;
+                   break;
+               }
+               tmp = d(nd,6);
+               if (resists_cold(mon)) tmp += 7;
+               if (spellcaster)
+                   tmp += spell_damage_bonus();
+#ifdef WIZ_PATCH_DEBUG
+               if (spellcaster)
+                   pline("Damage = %d + %d",tmp-spell_damage_bonus(),
+                       spell_damage_bonus());
+#endif
+               if (burnarmor(mon)) {
+                   if (!rn2(3)) (void)destroy_mitem(mon, POTION_CLASS, AD_FIRE);
+                   if (!rn2(3)) (void)destroy_mitem(mon, SCROLL_CLASS, AD_FIRE);
+                   if (!rn2(5)) (void)destroy_mitem(mon, SPBOOK_CLASS, AD_FIRE);
+               }
+               break;
+       case ZT_COLD:
+               if (resists_cold(mon)) {
+                   sho_shieldeff = TRUE;
+                   break;
+               }
+               tmp = d(nd,6);
+               if (resists_fire(mon)) tmp += d(nd, 3);
+               if (spellcaster)
+                   tmp += spell_damage_bonus();
+#ifdef WIZ_PATCH_DEBUG
+               if (spellcaster)
+                   pline("Damage = %d + %d", tmp-spell_damage_bonus(),
+                       spell_damage_bonus());
+#endif
+               if (!rn2(3)) (void)destroy_mitem(mon, POTION_CLASS, AD_COLD);
+               break;
+       case ZT_SLEEP:
+               tmp = 0;
+               (void)sleep_monst(mon, d(nd, 25),
+                               type == ZT_WAND(ZT_SLEEP) ? WAND_CLASS : '\0');
+               break;
+       case ZT_DEATH:          /* death/disintegration */
+               if(abs(type) != ZT_BREATH(ZT_DEATH)) {  /* death */
+                   if(mon->data == &mons[PM_DEATH]) {
+                       mon->mhpmax += mon->mhpmax/2;
+                       if (mon->mhpmax >= MAGIC_COOKIE)
+                           mon->mhpmax = MAGIC_COOKIE - 1;
+                       mon->mhp = mon->mhpmax;
+                       tmp = 0;
+                       break;
+                   }
+                   if (nonliving(mon->data) || is_demon(mon->data) ||
+                           resists_magm(mon)) {        /* similar to player */
+                       sho_shieldeff = TRUE;
+                       break;
+                   }
+                   type = -1; /* so they don't get saving throws */
+               } else {
+                   struct obj *otmp2;
+
+                   if (resists_disint(mon)) {
+                       sho_shieldeff = TRUE;
+                   } else if (mon->misc_worn_check & W_ARMS) {
+                       /* destroy shield; victim survives */
+                       *ootmp = which_armor(mon, W_ARMS);
+                   } else if (mon->misc_worn_check & W_ARM) {
+                       /* destroy body armor, also cloak if present */
+                       *ootmp = which_armor(mon, W_ARM);
+                       if ((otmp2 = which_armor(mon, W_ARMC)) != 0)
+                           m_useup(mon, otmp2);
+                   } else {
+                       /* no body armor, victim dies; destroy cloak
+                          and shirt now in case target gets life-saved */
+                       tmp = MAGIC_COOKIE;
+                       if ((otmp2 = which_armor(mon, W_ARMC)) != 0)
+                           m_useup(mon, otmp2);
+#ifdef TOURIST
+                       if ((otmp2 = which_armor(mon, W_ARMU)) != 0)
+                           m_useup(mon, otmp2);
+#endif
+                   }
+                   type = -1;  /* no saving throw wanted */
+                   break;      /* not ordinary damage */
+               }
+               tmp = mon->mhp+1;
+               break;
+       case ZT_LIGHTNING:
+               if (resists_elec(mon)) {
+                   sho_shieldeff = TRUE;
+                   tmp = 0;
+                   /* can still blind the monster */
+               } else
+                   tmp = d(nd,6);
+               if (spellcaster)
+                   tmp += spell_damage_bonus();
+#ifdef WIZ_PATCH_DEBUG
+               if (spellcaster)
+                   pline("Damage = %d + %d", tmp-spell_damage_bonus(),
+                       spell_damage_bonus());
+#endif
+               if (!resists_blnd(mon) &&
+                               !(type > 0 && u.uswallow && mon == u.ustuck)) {
+                       register unsigned rnd_tmp = rnd(50);
+                       mon->mcansee = 0;
+                       if((mon->mblinded + rnd_tmp) > 127)
+                               mon->mblinded = 127;
+                       else mon->mblinded += rnd_tmp;
+               }
+               if (!rn2(3)) (void)destroy_mitem(mon, WAND_CLASS, AD_ELEC);
+               /* not actually possible yet */
+               if (!rn2(3)) (void)destroy_mitem(mon, RING_CLASS, AD_ELEC);
+               break;
+       case ZT_POISON_GAS:
+               if (resists_poison(mon)) {
+                   sho_shieldeff = TRUE;
+                   break;
+               }
+               tmp = d(nd,6);
+               break;
+       case ZT_ACID:
+               if (resists_acid(mon)) {
+                   sho_shieldeff = TRUE;
+                   break;
+               }
+               tmp = d(nd,6);
+               if (!rn2(6)) erode_obj(MON_WEP(mon), TRUE, TRUE);
+               if (!rn2(6)) erode_armor(mon, TRUE);
+               break;
+       }
+       if (sho_shieldeff) shieldeff(mon->mx, mon->my);
+       if (is_hero_spell(type) && (Role_if(PM_KNIGHT) && u.uhave.questart))
+           tmp *= 2;
+       if (tmp > 0 && type >= 0 &&
+               resist(mon, type < ZT_SPELL(0) ? WAND_CLASS : '\0', 0, NOTELL))
+           tmp /= 2;
+       if (tmp < 0) tmp = 0;           /* don't allow negative damage */
+#ifdef WIZ_PATCH_DEBUG
+       pline("zapped monster hp = %d (= %d - %d)", mon->mhp-tmp,mon->mhp,tmp);
+#endif
+       mon->mhp -= tmp;
+       return(tmp);
+}
+
+STATIC_OVL void
+zhitu(type, nd, fltxt, sx, sy)
+int type, nd;
+const char *fltxt;
+xchar sx, sy;
+{
+       int dam = 0;
+
+       switch (abs(type) % 10) {
+       case ZT_MAGIC_MISSILE:
+           if (Antimagic) {
+               shieldeff(sx, sy);
+               pline_The("missiles bounce off!");
+           } else {
+               dam = d(nd,6);
+               exercise(A_STR, FALSE);
+           }
+           break;
+       case ZT_FIRE:
+           if (Fire_resistance) {
+               shieldeff(sx, sy);
+               You("don't feel hot!");
+               ugolemeffects(AD_FIRE, d(nd, 6));
+           } else {
+               dam = d(nd, 6);
+           }
+           burn_away_slime();
+           if (burnarmor(&youmonst)) { /* "body hit" */
+               if (!rn2(3)) destroy_item(POTION_CLASS, AD_FIRE);
+               if (!rn2(3)) destroy_item(SCROLL_CLASS, AD_FIRE);
+               if (!rn2(5)) destroy_item(SPBOOK_CLASS, AD_FIRE);
+           }
+           break;
+       case ZT_COLD:
+           if (Cold_resistance) {
+               shieldeff(sx, sy);
+               You("don't feel cold.");
+               ugolemeffects(AD_COLD, d(nd, 6));
+           } else {
+               dam = d(nd, 6);
+           }
+           if (!rn2(3)) destroy_item(POTION_CLASS, AD_COLD);
+           break;
+       case ZT_SLEEP:
+           if (Sleep_resistance) {
+               shieldeff(u.ux, u.uy);
+               You("don't feel sleepy.");
+           } else {
+               fall_asleep(-d(nd,25), TRUE); /* sleep ray */
+           }
+           break;
+       case ZT_DEATH:
+           if (abs(type) == ZT_BREATH(ZT_DEATH)) {
+               if (Disint_resistance) {
+                   You("are not disintegrated.");
+                   break;
+               } else if (uarms) {
+                   /* destroy shield; other possessions are safe */
+                   (void) destroy_arm(uarms);
+                   break;
+               } else if (uarm) {
+                   /* destroy suit; if present, cloak goes too */
+                   if (uarmc) (void) destroy_arm(uarmc);
+                   (void) destroy_arm(uarm);
+                   break;
+               }
+               /* no shield or suit, you're dead; wipe out cloak
+                  and/or shirt in case of life-saving or bones */
+               if (uarmc) (void) destroy_arm(uarmc);
+#ifdef TOURIST
+               if (uarmu) (void) destroy_arm(uarmu);
+#endif
+           } else if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
+               shieldeff(sx, sy);
+               You("seem unaffected.");
+               break;
+           } else if (Antimagic) {
+               shieldeff(sx, sy);
+               You("aren't affected.");
+               break;
+           }
+           killer_format = KILLED_BY_AN;
+           killer = fltxt;
+           /* when killed by disintegration breath, don't leave corpse */
+           u.ugrave_arise = (type == -ZT_BREATH(ZT_DEATH)) ? -3 : NON_PM;
+           done(DIED);
+           return; /* lifesaved */
+       case ZT_LIGHTNING:
+           if (Shock_resistance) {
+               shieldeff(sx, sy);
+               You("aren't affected.");
+               ugolemeffects(AD_ELEC, d(nd, 6));
+           } else {
+               dam = d(nd, 6);
+               exercise(A_CON, FALSE);
+           }
+           if (!rn2(3)) destroy_item(WAND_CLASS, AD_ELEC);
+           if (!rn2(3)) destroy_item(RING_CLASS, AD_ELEC);
+           break;
+       case ZT_POISON_GAS:
+           poisoned("blast", A_DEX, "poisoned blast", 15);
+           break;
+       case ZT_ACID:
+           if (Acid_resistance) {
+               dam = 0;
+           } else {
+               pline_The("acid burns!");
+               dam = d(nd,6);
+               exercise(A_STR, FALSE);
+           }
+           /* using two weapons at once makes both of them more vulnerable */
+           if (!rn2(u.twoweap ? 3 : 6)) erode_obj(uwep, TRUE, TRUE);
+           if (u.twoweap && !rn2(3)) erode_obj(uswapwep, TRUE, TRUE);
+           if (!rn2(6)) erode_armor(&youmonst, TRUE);
+           break;
+       }
+
+       if (Half_spell_damage && dam &&
+          type < 0 && (type > -20 || type < -29)) /* !Breath */
+           dam = (dam + 1) / 2;
+       losehp(dam, fltxt, KILLED_BY_AN);
+       return;
+}
+
+#endif /*OVL1*/
+#ifdef OVLB
+
+/*
+ * burn scrolls and spellbooks on floor at position x,y
+ * return the number of scrolls and spellbooks burned
+ */
+int
+burn_floor_paper(x, y, give_feedback, u_caused)
+int x, y;
+boolean give_feedback; /* caller needs to decide about visibility checks */
+boolean u_caused;
+{
+       struct obj *obj, *obj2;
+       long i, scrquan, delquan;
+       char buf1[BUFSZ], buf2[BUFSZ];
+       int cnt = 0;
+
+       for (obj = level.objects[x][y]; obj; obj = obj2) {
+           obj2 = obj->nexthere;
+           if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) {
+               if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL ||
+                       obj_resists(obj, 2, 100))
+                   continue;
+               scrquan = obj->quan;    /* number present */
+               delquan = 0;            /* number to destroy */
+               for (i = scrquan; i > 0; i--)
+                   if (!rn2(3)) delquan++;
+               if (delquan) {
+                   /* save name before potential delobj() */
+                   if (give_feedback) {
+                       obj->quan = 1;
+                       Strcpy(buf1, (x == u.ux && y == u.uy) ?
+                               xname(obj) : distant_name(obj, xname));
+                       obj->quan = 2;
+                       Strcpy(buf2, (x == u.ux && y == u.uy) ?
+                               xname(obj) : distant_name(obj, xname));
+                       obj->quan = scrquan;
+                   }
+                   /* useupf(), which charges, only if hero caused damage */
+                   if (u_caused) useupf(obj, delquan);
+                   else if (delquan < scrquan) obj->quan -= delquan;
+                   else delobj(obj);
+                   cnt += delquan;
+                   if (give_feedback) {
+                       if (delquan > 1)
+                           pline("%ld %s burn.", delquan, buf2);
+                       else
+                           pline("%s burns.", An(buf1));
+                   }
+               }
+           }
+       }
+       return cnt;
+}
+
+/* will zap/spell/breath attack score a hit against armor class `ac'? */
+STATIC_OVL int
+zap_hit(ac, type)
+int ac;
+int type;      /* either hero cast spell type or 0 */
+{
+    int chance = rn2(20);
+    int spell_bonus = type ? spell_hit_bonus(type) : 0;
+
+    /* small chance for naked target to avoid being hit */
+    if (!chance) return rnd(10) < ac+spell_bonus;
+
+    /* very high armor protection does not achieve invulnerability */
+    ac = AC_VALUE(ac);
+
+    return (3 - chance) < ac+spell_bonus;
+}
+
+/* type ==   0 to   9 : you shooting a wand */
+/* type ==  10 to  19 : you casting a spell */
+/* type ==  20 to  29 : you breathing as a monster */
+/* type == -10 to -19 : monster casting spell */
+/* type == -20 to -29 : monster breathing at you */
+/* type == -30 to -39 : monster shooting a wand */
+/* called with dx = dy = 0 with vertical bolts */
+void
+buzz(type,nd,sx,sy,dx,dy)
+register int type, nd;
+register xchar sx,sy;
+register int dx,dy;
+{
+    int range, abstype = abs(type) % 10;
+    struct rm *lev;
+    register xchar lsx, lsy;
+    struct monst *mon;
+    coord save_bhitpos;
+    boolean shopdamage = FALSE;
+    register const char *fltxt;
+    struct obj *otmp;
+    int spell_type;
+
+    /* if its a Hero Spell then get its SPE_TYPE */
+    spell_type = is_hero_spell(type) ? SPE_MAGIC_MISSILE + abstype : 0;
+
+    fltxt = flash_types[(type <= -30) ? abstype : abs(type)];
+    if(u.uswallow) {
+       register int tmp;
+
+       if(type < 0) return;
+       tmp = zhitm(u.ustuck, type, nd, &otmp);
+       if(!u.ustuck)   u.uswallow = 0;
+       else    pline("%s rips into %s%s",
+                     The(fltxt), mon_nam(u.ustuck), exclam(tmp));
+       /* Using disintegration from the inside only makes a hole... */
+       if (tmp == MAGIC_COOKIE)
+           u.ustuck->mhp = 0;
+       if (u.ustuck->mhp < 1)
+           killed(u.ustuck);
+       return;
+    }
+    if(type < 0) newsym(u.ux,u.uy);
+    range = rn1(7,7);
+    if(dx == 0 && dy == 0) range = 1;
+    save_bhitpos = bhitpos;
+
+    tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, abstype));
+    while(range-- > 0) {
+       lsx = sx; sx += dx;
+       lsy = sy; sy += dy;
+       if(isok(sx,sy) && (lev = &levl[sx][sy])->typ) {
+           mon = m_at(sx, sy);
+           if(cansee(sx,sy)) {
+               /* reveal/unreveal invisible monsters before tmp_at() */
+               if (mon && !canspotmon(mon))
+                   map_invisible(sx, sy);
+               else if (!mon && glyph_is_invisible(levl[sx][sy].glyph)) {
+                   unmap_object(sx, sy);
+                   newsym(sx, sy);
+               }
+               if(ZAP_POS(lev->typ) || cansee(lsx,lsy))
+                   tmp_at(sx,sy);
+               delay_output(); /* wait a little */
+           }
+       } else
+           goto make_bounce;
+
+       /* hit() and miss() need bhitpos to match the target */
+       bhitpos.x = sx,  bhitpos.y = sy;
+       /* Fireballs only damage when they explode */
+       if (type != ZT_SPELL(ZT_FIRE))
+           range += zap_over_floor(sx, sy, type, &shopdamage);
+
+       if (mon) {
+           if (type == ZT_SPELL(ZT_FIRE)) break;
+           if (type >= 0) mon->mstrategy &= ~STRAT_WAITMASK;
+#ifdef STEED
+           buzzmonst:
+#endif
+           if (zap_hit(find_mac(mon), spell_type)) {
+               if (mon_reflects(mon, (char *)0)) {
+                   if(cansee(mon->mx,mon->my)) {
+                       hit(fltxt, mon, exclam(0));
+                       shieldeff(mon->mx, mon->my);
+                       (void) mon_reflects(mon, "But it reflects from %s %s!");
+                   }
+                   dx = -dx;
+                   dy = -dy;
+               } else {
+                   boolean mon_could_move = mon->mcanmove;
+                   int tmp = zhitm(mon, type, nd, &otmp);
+
+                   if (is_rider(mon->data) && abs(type) == ZT_BREATH(ZT_DEATH)) {
+                       if (canseemon(mon)) {
+                           hit(fltxt, mon, ".");
+                           pline("%s disintegrates.", Monnam(mon));
+                           pline("%s body reintegrates before your %s!",
+                                 s_suffix(Monnam(mon)),
+                                 (eyecount(youmonst.data) == 1) ?
+                                       body_part(EYE) : makeplural(body_part(EYE)));
+                           pline("%s resurrects!", Monnam(mon));
+                       }
+                       mon->mhp = mon->mhpmax;
+                       break; /* Out of while loop */
+                   }
+                   if (mon->data == &mons[PM_DEATH] && abstype == ZT_DEATH) {
+                       if (canseemon(mon)) {
+                           hit(fltxt, mon, ".");
+                           pline("%s absorbs the deadly %s!", Monnam(mon),
+                                 type == ZT_BREATH(ZT_DEATH) ?
+                                       "blast" : "ray");
+                           pline("It seems even stronger than before.");
+                       }
+                       break; /* Out of while loop */
+                   }
+
+                   if (tmp == MAGIC_COOKIE) { /* disintegration */
+                       struct obj *otmp2, *m_amulet = mlifesaver(mon);
+
+                       if (canseemon(mon)) {
+                           if (!m_amulet)
+                               pline("%s is disintegrated!", Monnam(mon));
+                           else
+                               hit(fltxt, mon, "!");
+                       }
+#ifndef GOLDOBJ
+                       mon->mgold = 0L;
+#endif
+
+/* note: worn amulet of life saving must be preserved in order to operate */
+#define oresist_disintegration(obj) \
+               (objects[obj->otyp].oc_oprop == DISINT_RES || \
+                obj_resists(obj, 5, 50) || is_quest_artifact(obj) || \
+                obj == m_amulet)
+
+                       for (otmp = mon->minvent; otmp; otmp = otmp2) {
+                           otmp2 = otmp->nobj;
+                           if (!oresist_disintegration(otmp)) {
+                               obj_extract_self(otmp);
+                               obfree(otmp, (struct obj *)0);
+                           }
+                       }
+
+                       if (type < 0)
+                           monkilled(mon, (char *)0, -AD_RBRE);
+                       else
+                           xkilled(mon, 2);
+                   } else if(mon->mhp < 1) {
+                       if(type < 0)
+                           monkilled(mon, fltxt, AD_RBRE);
+                       else
+                           killed(mon);
+                   } else {
+                       if (!otmp) {
+                           /* normal non-fatal hit */
+                           hit(fltxt, mon, exclam(tmp));
+                       } else {
+                           /* some armor was destroyed; no damage done */
+                           if (canseemon(mon))
+                               pline("%s %s is disintegrated!",
+                                     s_suffix(Monnam(mon)),
+                                     distant_name(otmp, xname));
+                           m_useup(mon, otmp);
+                       }
+                       if (mon_could_move && !mon->mcanmove)   /* ZT_SLEEP */
+                           slept_monst(mon);
+                   }
+               }
+               range -= 2;
+           } else {
+               miss(fltxt,mon);
+           }
+       } else if (sx == u.ux && sy == u.uy && range >= 0) {
+           nomul(0);
+#ifdef STEED
+           if (u.usteed && !rn2(3) && !mon_reflects(u.usteed, (char *)0)) {
+                   mon = u.usteed;
+                   goto buzzmonst;
+           } else
+#endif
+           if (zap_hit((int) u.uac, 0)) {
+               range -= 2;
+               pline("%s hits you!", The(fltxt));
+               if (Reflecting) {
+                   if (!Blind) {
+                       (void) ureflects("But %s reflects from your %s!", "it");
+                   } else
+                       pline("For some reason you are not affected.");
+                   dx = -dx;
+                   dy = -dy;
+                   shieldeff(sx, sy);
+               } else {
+                   zhitu(type, nd, fltxt, sx, sy);
+               }
+           } else {
+               pline("%s whizzes by you!", The(fltxt));
+           }
+           if (abstype == ZT_LIGHTNING && !resists_blnd(&youmonst)) {
+               You(are_blinded_by_the_flash);
+               make_blinded((long)d(nd,50),FALSE);
+               if (!Blind) Your(vision_clears);
+           }
+           stop_occupation();
+           nomul(0);
+       }
+
+       if(!ZAP_POS(lev->typ) || (closed_door(sx, sy) && (range >= 0))) {
+           int bounce;
+           uchar rmn;
+
+ make_bounce:
+           if (type == ZT_SPELL(ZT_FIRE)) {
+               sx = lsx;
+               sy = lsy;
+               break; /* fireballs explode before the wall */
+           }
+           bounce = 0;
+           range--;
+           if(range && isok(lsx, lsy) && cansee(lsx,lsy))
+               pline("%s bounces!", The(fltxt));
+           if(!dx || !dy || !rn2(20)) {
+               dx = -dx;
+               dy = -dy;
+           } else {
+               if(isok(sx,lsy) && ZAP_POS(rmn = levl[sx][lsy].typ) &&
+                  !closed_door(sx,lsy) &&
+                  (IS_ROOM(rmn) || (isok(sx+dx,lsy) &&
+                                    ZAP_POS(levl[sx+dx][lsy].typ))))
+                   bounce = 1;
+               if(isok(lsx,sy) && ZAP_POS(rmn = levl[lsx][sy].typ) &&
+                  !closed_door(lsx,sy) &&
+                  (IS_ROOM(rmn) || (isok(lsx,sy+dy) &&
+                                    ZAP_POS(levl[lsx][sy+dy].typ))))
+                   if(!bounce || rn2(2))
+                       bounce = 2;
+
+               switch(bounce) {
+               case 0: dx = -dx; /* fall into... */
+               case 1: dy = -dy; break;
+               case 2: dx = -dx; break;
+               }
+               tmp_at(DISP_CHANGE, zapdir_to_glyph(dx,dy,abstype));
+           }
+       }
+    }
+    tmp_at(DISP_END,0);
+    if (type == ZT_SPELL(ZT_FIRE))
+       explode(sx, sy, type, d(12,6), 0, EXPL_FIERY);
+    if (shopdamage)
+       pay_for_damage(abstype == ZT_FIRE ?  "burn away" :
+                      abstype == ZT_COLD ?  "shatter" :
+                      abstype == ZT_DEATH ? "disintegrate" : "destroy", FALSE);
+    bhitpos = save_bhitpos;
+}
+#endif /*OVLB*/
+#ifdef OVL0
+
+void
+melt_ice(x, y)
+xchar x, y;
+{
+       struct rm *lev = &levl[x][y];
+       struct obj *otmp;
+
+       if (lev->typ == DRAWBRIDGE_UP)
+           lev->drawbridgemask &= ~DB_ICE;     /* revert to DB_MOAT */
+       else {  /* lev->typ == ICE */
+#ifdef STUPID
+           if (lev->icedpool == ICED_POOL) lev->typ = POOL;
+           else lev->typ = MOAT;
+#else
+           lev->typ = (lev->icedpool == ICED_POOL ? POOL : MOAT);
+#endif
+           lev->icedpool = 0;
+       }
+       obj_ice_effects(x, y, FALSE);
+       unearth_objs(x, y);
+       if (Underwater) vision_recalc(1);
+       newsym(x,y);
+       if (cansee(x,y)) Norep("The ice crackles and melts.");
+       if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
+           if (cansee(x,y)) pline("%s settles...", An(xname(otmp)));
+           do {
+               obj_extract_self(otmp); /* boulder isn't being pushed */
+               if (!boulder_hits_pool(otmp, x, y, FALSE))
+                   impossible("melt_ice: no pool?");
+               /* try again if there's another boulder and pool didn't fill */
+           } while (is_pool(x,y) && (otmp = sobj_at(BOULDER, x, y)) != 0);
+           newsym(x,y);
+       }
+       if (x == u.ux && y == u.uy)
+               spoteffects(TRUE);      /* possibly drown, notice objects */
+}
+
+/* Burn floor scrolls, evaporate pools, etc...  in a single square.  Used
+ * both for normal bolts of fire, cold, etc... and for fireballs.
+ * Sets shopdamage to TRUE if a shop door is destroyed, and returns the
+ * amount by which range is reduced (the latter is just ignored by fireballs)
+ */
+int
+zap_over_floor(x, y, type, shopdamage)
+xchar x, y;
+int type;
+boolean *shopdamage;
+{
+       struct monst *mon;
+       int abstype = abs(type) % 10;
+       struct rm *lev = &levl[x][y];
+       int rangemod = 0;
+
+       if(abstype == ZT_FIRE) {
+           struct trap *t = t_at(x, y);
+
+           if (t && t->ttyp == WEB) {
+               /* a burning web is too flimsy to notice if you can't see it */
+               if (cansee(x,y)) Norep("A web bursts into flames!");
+               (void) delfloortrap(t);
+               if (cansee(x,y)) newsym(x,y);
+           }
+           if(is_ice(x, y)) {
+               melt_ice(x, y);
+           } else if(is_pool(x,y)) {
+               const char *msgtxt = "You hear hissing gas.";
+               if(lev->typ != POOL) {  /* MOAT or DRAWBRIDGE_UP */
+                   if (cansee(x,y)) msgtxt = "Some water evaporates.";
+               } else {
+                   register struct trap *ttmp;
+
+                   rangemod -= 3;
+                   lev->typ = ROOM;
+                   ttmp = maketrap(x, y, PIT);
+                   if (ttmp) ttmp->tseen = 1;
+                   if (cansee(x,y)) msgtxt = "The water evaporates.";
+               }
+               Norep(msgtxt);
+               if (lev->typ == ROOM) newsym(x,y);
+           } else if(IS_FOUNTAIN(lev->typ)) {
+                   if (cansee(x,y))
+                       pline("Steam billows from the fountain.");
+                   rangemod -= 1;
+                   dryup(x, y, type > 0);
+           }
+       }
+       else if(abstype == ZT_COLD && (is_pool(x,y) || is_lava(x,y))) {
+               boolean lava = is_lava(x,y);
+               boolean moat = (!lava && (lev->typ != POOL) &&
+                               (lev->typ != WATER) &&
+                               !Is_medusa_level(&u.uz) &&
+                               !Is_waterlevel(&u.uz));
+
+               if (lev->typ == WATER) {
+                   /* For now, don't let WATER freeze. */
+                   if (cansee(x,y))
+                       pline_The("water freezes for a moment.");
+                   else
+                       You_hear("a soft crackling.");
+                   rangemod -= 1000;   /* stop */
+               } else {
+                   rangemod -= 3;
+                   if (lev->typ == DRAWBRIDGE_UP) {
+                       lev->drawbridgemask &= ~DB_UNDER;  /* clear lava */
+                       lev->drawbridgemask |= (lava ? DB_FLOOR : DB_ICE);
+                   } else {
+                       if (!lava)
+                           lev->icedpool =
+                                   (lev->typ == POOL ? ICED_POOL : ICED_MOAT);
+                       lev->typ = (lava ? ROOM : ICE);
+                   }
+                   bury_objs(x,y);
+                   if(cansee(x,y)) {
+                       if(moat)
+                               Norep("The moat is bridged with ice!");
+                       else if(lava)
+                               Norep("The lava cools and solidifies.");
+                       else
+                               Norep("The water freezes.");
+                       newsym(x,y);
+                   } else if(flags.soundok && !lava)
+                       You_hear("a crackling sound.");
+
+                   if (x == u.ux && y == u.uy) {
+                       if (u.uinwater) {   /* not just `if (Underwater)' */
+                           /* leave the no longer existent water */
+                           u.uinwater = 0;
+                           u.uundetected = 0;
+                           docrt();
+                           vision_full_recalc = 1;
+                       } else if (u.utrap && u.utraptype == TT_LAVA) {
+                           if (Passes_walls) {
+                               You("pass through the now-solid rock.");
+                           } else {
+                               u.utrap = rn1(50,20);
+                               u.utraptype = TT_INFLOOR;
+                               You("are firmly stuck in the cooling rock.");
+                           }
+                       }
+                   } else if ((mon = m_at(x,y)) != 0) {
+                       /* probably ought to do some hefty damage to any
+                          non-ice creature caught in freezing water;
+                          at a minimum, eels are forced out of hiding */
+                       if (is_swimmer(mon->data) && mon->mundetected) {
+                           mon->mundetected = 0;
+                           newsym(x,y);
+                       }
+                   }
+               }
+               obj_ice_effects(x,y,TRUE);
+       }
+       if(closed_door(x, y)) {
+               int new_doormask = -1;
+               const char *see_txt = 0, *sense_txt = 0, *hear_txt = 0;
+               rangemod = -1000;
+               switch(abstype) {
+               case ZT_FIRE:
+                   new_doormask = D_NODOOR;
+                   see_txt = "The door is consumed in flames!";
+                   sense_txt = "smell smoke.";
+                   break;
+               case ZT_COLD:
+                   new_doormask = D_NODOOR;
+                   see_txt = "The door freezes and shatters!";
+                   sense_txt = "feel cold.";
+                   break;
+               case ZT_DEATH:
+                   /* death spells/wands don't disintegrate */
+                   if(abs(type) != ZT_BREATH(ZT_DEATH))
+                       goto def_case;
+                   new_doormask = D_NODOOR;
+                   see_txt = "The door disintegrates!";
+                   hear_txt = "crashing wood.";
+                   break;
+               case ZT_LIGHTNING:
+                   new_doormask = D_BROKEN;
+                   see_txt = "The door splinters!";
+                   hear_txt = "crackling.";
+                   break;
+               default:
+               def_case:
+                   if(cansee(x,y)) {
+                       pline_The("door absorbs %s %s!",
+                             (type < 0) ? "the" : "your",
+                             abs(type) < ZT_SPELL(0) ? "bolt" :
+                             abs(type) < ZT_BREATH(0) ? "spell" :
+                             "blast");
+                   } else You_feel("vibrations.");
+                   break;
+               }
+               if (new_doormask >= 0) {        /* door gets broken */
+                   if (*in_rooms(x, y, SHOPBASE)) {
+                       if (type >= 0) {
+                           add_damage(x, y, 400L);
+                           *shopdamage = TRUE;
+                       } else  /* caused by monster */
+                           add_damage(x, y, 0L);
+                   }
+                   lev->doormask = new_doormask;
+                   unblock_point(x, y);        /* vision */
+                   if (cansee(x, y)) {
+                       pline(see_txt);
+                       newsym(x, y);
+                   } else if (sense_txt) {
+                       You(sense_txt);
+                   } else if (hear_txt) {
+                       if (flags.soundok) You_hear(hear_txt);
+                   }
+                   if (picking_at(x, y)) {
+                       stop_occupation();
+                       reset_pick();
+                   }
+               }
+       }
+
+       if(OBJ_AT(x, y) && abstype == ZT_FIRE)
+               if (burn_floor_paper(x, y, FALSE, type > 0) && couldsee(x, y)) {
+                   newsym(x,y);
+                   You("%s of smoke.",
+                       !Blind ? "see a puff" : "smell a whiff");
+               }
+       if ((mon = m_at(x,y)) != 0) {
+               /* Cannot use wakeup() which also angers the monster */
+               mon->msleeping = 0;
+               if(mon->m_ap_type) seemimic(mon);
+               if(type >= 0) {
+                   setmangry(mon);
+                   if(mon->ispriest && *in_rooms(mon->mx, mon->my, TEMPLE))
+                       ghod_hitsu(mon);
+                   if(mon->isshk && !*u.ushops)
+                       hot_pursuit(mon);
+               }
+       }
+       return rangemod;
+}
+
+#endif /*OVL0*/
+#ifdef OVL3
+
+void
+fracture_rock(obj)     /* fractured by pick-axe or wand of striking */
+register struct obj *obj;                 /* no texts here! */
+{
+       /* A little Sokoban guilt... */
+       if (obj->otyp == BOULDER && In_sokoban(&u.uz) && !flags.mon_moving)
+           change_luck(-1);
+
+       obj->otyp = ROCK;
+       obj->quan = (long) rn1(60, 7);
+       obj->owt = weight(obj);
+       obj->oclass = GEM_CLASS;
+       obj->known = FALSE;
+       obj->onamelth = 0;              /* no names */
+       obj->oxlth = 0;                 /* no extra data */
+       obj->oattached = OATTACHED_NOTHING;
+       if (obj->where == OBJ_FLOOR) {
+               obj_extract_self(obj);          /* move rocks back on top */
+               place_object(obj, obj->ox, obj->oy);
+               if(!does_block(obj->ox,obj->oy,&levl[obj->ox][obj->oy]))
+                       unblock_point(obj->ox,obj->oy);
+               if(cansee(obj->ox,obj->oy))
+                   newsym(obj->ox,obj->oy);
+       }
+}
+
+/* handle statue hit by striking/force bolt/pick-axe */
+boolean
+break_statue(obj)
+register struct obj *obj;
+{
+       /* [obj is assumed to be on floor, so no get_obj_location() needed] */
+       struct trap *trap = t_at(obj->ox, obj->oy);
+       struct obj *item;
+
+       if (trap && trap->ttyp == STATUE_TRAP &&
+               activate_statue_trap(trap, obj->ox, obj->oy, TRUE))
+           return FALSE;
+       /* drop any objects contained inside the statue */
+       while ((item = obj->cobj) != 0) {
+           obj_extract_self(item);
+           place_object(item, obj->ox, obj->oy);
+       }
+       if (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && (obj->spe & STATUE_HISTORIC)) {
+           You_feel("guilty about damaging such a historic statue.");
+           adjalign(-1);
+       }
+       obj->spe = 0;
+       fracture_rock(obj);
+       return TRUE;
+}
+
+const char * const destroy_strings[] = {       /* also used in trap.c */
+       "freezes and shatters", "freeze and shatter", "shattered potion",
+       "boils and explodes", "boil and explode", "boiling potion",
+       "catches fire and burns", "catch fire and burn", "burning scroll",
+       "catches fire and burns", "catch fire and burn", "burning book",
+       "turns to dust and vanishes", "turn to dust and vanish", "",
+       "breaks apart and explodes", "break apart and explode", "exploding wand"
+};
+
+void
+destroy_item(osym, dmgtyp)
+register int osym, dmgtyp;
+{
+       register struct obj *obj, *obj2;
+       register int dmg, xresist, skip;
+       register long i, cnt, quan;
+       register int dindx;
+       const char *mult;
+
+       for(obj = invent; obj; obj = obj2) {
+           obj2 = obj->nobj;
+           if(obj->oclass != osym) continue; /* test only objs of type osym */
+           if(obj->oartifact) continue; /* don't destroy artifacts */
+           if(obj->in_use && obj->quan == 1) continue; /* not available */
+           xresist = skip = 0;
+#ifdef GCC_WARN
+           dmg = dindx = 0;
+           quan = 0L;
+#endif
+           switch(dmgtyp) {
+               case AD_COLD:
+                   if(osym == POTION_CLASS && obj->otyp != POT_OIL) {
+                       quan = obj->quan;
+                       dindx = 0;
+                       dmg = rnd(4);
+                   } else skip++;
+                   break;
+               case AD_FIRE:
+                   xresist = (Fire_resistance && obj->oclass != POTION_CLASS);
+
+                   if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
+                       skip++;
+                   if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
+                       skip++;
+                       if (!Blind)
+                           pline("%s glows a strange %s, but remains intact.",
+                               The(xname(obj)), hcolor("dark red"));
+                   }
+                   quan = obj->quan;
+                   switch(osym) {
+                       case POTION_CLASS:
+                           dindx = 1;
+                           dmg = rnd(6);
+                           break;
+                       case SCROLL_CLASS:
+                           dindx = 2;
+                           dmg = 1;
+                           break;
+                       case SPBOOK_CLASS:
+                           dindx = 3;
+                           dmg = 1;
+                           break;
+                       default:
+                           skip++;
+                           break;
+                   }
+                   break;
+               case AD_ELEC:
+                   xresist = (Shock_resistance && obj->oclass != RING_CLASS);
+                   quan = obj->quan;
+                   switch(osym) {
+                       case RING_CLASS:
+                           if(obj->otyp == RIN_SHOCK_RESISTANCE)
+                                   { skip++; break; }
+                           dindx = 4;
+                           dmg = 0;
+                           break;
+                       case WAND_CLASS:
+                           if(obj->otyp == WAN_LIGHTNING) { skip++; break; }
+#if 0
+                           if (obj == current_wand) { skip++; break; }
+#endif
+                           dindx = 5;
+                           dmg = rnd(10);
+                           break;
+                       default:
+                           skip++;
+                           break;
+                   }
+                   break;
+               default:
+                   skip++;
+                   break;
+           }
+           if(!skip) {
+               if (obj->in_use) --quan; /* one will be used up elsewhere */
+               for(i = cnt = 0L; i < quan; i++)
+                   if(!rn2(3)) cnt++;
+
+               if(!cnt) continue;
+               if(cnt == quan) mult = "Your";
+               else    mult = (cnt == 1L) ? "One of your" : "Some of your";
+               pline("%s %s %s!", mult, xname(obj),
+                       (cnt > 1L) ? destroy_strings[dindx*3 + 1]
+                                 : destroy_strings[dindx*3]);
+               if(osym == POTION_CLASS && dmgtyp != AD_COLD) {
+                   if (!breathless(youmonst.data) || haseyes(youmonst.data))
+                       potionbreathe(obj);
+               }
+               if (obj->owornmask) {
+                   if (obj->owornmask & W_RING) /* ring being worn */
+                       Ring_gone(obj);
+                   else
+                       setnotworn(obj);
+               }
+               if (obj == current_wand) current_wand = 0;      /* destroyed */
+               for (i = 0; i < cnt; i++)
+                   useup(obj);
+               if(dmg) {
+                   if(xresist) You("aren't hurt!");
+                   else {
+                       const char *how = destroy_strings[dindx * 3 + 2];
+                       boolean one = (cnt == 1L);
+
+                       losehp(dmg, one ? how : (const char *)makeplural(how),
+                              one ? KILLED_BY_AN : KILLED_BY);
+                       exercise(A_STR, FALSE);
+                   }
+               }
+           }
+       }
+       return;
+}
+
+int
+destroy_mitem(mtmp, osym, dmgtyp)
+struct monst *mtmp;
+int osym, dmgtyp;
+{
+       struct obj *obj, *obj2;
+       int skip, tmp = 0;
+       long i, cnt, quan;
+       int dindx;
+       boolean vis;
+
+       if (mtmp == &youmonst) {        /* this simplifies artifact_hit() */
+           destroy_item(osym, dmgtyp);
+           return 0;   /* arbitrary; value doesn't matter to artifact_hit() */
+       }
+
+       vis = canseemon(mtmp);
+       for(obj = mtmp->minvent; obj; obj = obj2) {
+           obj2 = obj->nobj;
+           if(obj->oclass != osym) continue; /* test only objs of type osym */
+           skip = 0;
+           quan = 0L;
+           dindx = 0;
+
+           switch(dmgtyp) {
+               case AD_COLD:
+                   if(osym == POTION_CLASS && obj->otyp != POT_OIL) {
+                       quan = obj->quan;
+                       dindx = 0;
+                       tmp++;
+                   } else skip++;
+                   break;
+               case AD_FIRE:
+                   if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
+                       skip++;
+                   if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
+                       skip++;
+                       if (vis)
+                           pline("%s glows a strange %s, but remains intact.",
+                               The(distant_name(obj, xname)),
+                               hcolor("dark red"));
+                   }
+                   quan = obj->quan;
+                   switch(osym) {
+                       case POTION_CLASS:
+                           dindx = 1;
+                           tmp++;
+                           break;
+                       case SCROLL_CLASS:
+                           dindx = 2;
+                           tmp++;
+                           break;
+                       case SPBOOK_CLASS:
+                           dindx = 3;
+                           tmp++;
+                           break;
+                       default:
+                           skip++;
+                           break;
+                   }
+                   break;
+               case AD_ELEC:
+                   quan = obj->quan;
+                   switch(osym) {
+                       case RING_CLASS:
+                           if(obj->otyp == RIN_SHOCK_RESISTANCE)
+                                   { skip++; break; }
+                           dindx = 4;
+                           break;
+                       case WAND_CLASS:
+                           if(obj->otyp == WAN_LIGHTNING) { skip++; break; }
+                           dindx = 5;
+                           tmp++;
+                           break;
+                       default:
+                           skip++;
+                           break;
+                   }
+                   break;
+               default:
+                   skip++;
+                   break;
+           }
+           if(!skip) {
+               for(i = cnt = 0L; i < quan; i++)
+                   if(!rn2(3)) cnt++;
+
+               if(!cnt) continue;
+               if (vis) pline("%s %s %s!",
+                       s_suffix(Monnam(mtmp)), xname(obj),
+                       (cnt > 1L) ? destroy_strings[dindx*3 + 1]
+                                 : destroy_strings[dindx*3]);
+               for(i = 0; i < cnt; i++) m_useup(mtmp, obj);
+           }
+       }
+       return(tmp);
+}
+
+#endif /*OVL3*/
+#ifdef OVL2
+
+int
+resist(mtmp, oclass, damage, tell)
+struct monst *mtmp;
+char oclass;
+int damage, tell;
+{
+       int resisted;
+       int alev, dlev;
+
+       /* attack level */
+       switch (oclass) {
+           case WAND_CLASS:    alev = 12;       break;
+           case TOOL_CLASS:    alev = 10;       break; /* instrument */
+           case WEAPON_CLASS:  alev = 10;       break; /* artifact */
+           case SCROLL_CLASS:  alev =  9;       break;
+           case POTION_CLASS:  alev =  6;       break;
+           case RING_CLASS:    alev =  5;       break;
+           default:            alev = u.ulevel; break; /* spell */
+       }
+       /* defense level */
+       dlev = (int)mtmp->m_lev;
+       if (dlev > 50) dlev = 50;
+       else if (dlev < 1) dlev = is_mplayer(mtmp->data) ? u.ulevel : 1;
+
+       resisted = rn2(100 + alev - dlev) < mtmp->data->mr;
+       if (resisted) {
+           if (tell) {
+               shieldeff(mtmp->mx, mtmp->my);
+               pline("%s resists!", Monnam(mtmp));
+           }
+           damage = (damage + 1) / 2;
+       }
+
+       if (damage) {
+           mtmp->mhp -= damage;
+           if (mtmp->mhp < 1) {
+               if(m_using) monkilled(mtmp, "", AD_RBRE);
+               else killed(mtmp);
+           }
+       }
+       return(resisted);
+}
+
+void
+makewish()
+{
+       char buf[BUFSZ];
+       struct obj *otmp, nothing;
+       int tries = 0;
+
+       nothing = zeroobj;  /* lint suppression; only its address matters */
+       if (flags.verbose) You("may wish for an object.");
+retry:
+       getlin("For what do you wish?", buf);
+       if(buf[0] == '\033') buf[0] = 0;
+       /*
+        *  Note: if they wished for and got a non-object successfully,
+        *  otmp == &zeroobj.  That includes gold, or an artifact that
+        *  has been denied.  Wishing for "nothing" requires a separate
+        *  value to remain distinct.
+        */
+       otmp = readobjnam(buf, &nothing, TRUE);
+       if (!otmp) {
+           pline("Nothing fitting that description exists in the game.");
+           if (++tries < 5) goto retry;
+           pline(thats_enough_tries);
+           otmp = readobjnam((char *)0, (struct obj *)0, TRUE);
+           if (!otmp) return;  /* for safety; should never happen */
+       } else if (otmp == &nothing) {
+           /* explicitly wished for "nothing", presumeably attempting
+              to retain wishless conduct */
+           return;
+       }
+
+       /* KMH, conduct */
+       u.uconduct.wishes++;
+
+       if (otmp != &zeroobj) {
+           /* The(aobjnam()) is safe since otmp is unidentified -dlc */
+           (void) hold_another_object(otmp, u.uswallow ?
+                                      "Oops!  %s out of your reach!" :
+                                      (Is_airlevel(&u.uz) ||
+                                       Is_waterlevel(&u.uz) ||
+                                       levl[u.ux][u.uy].typ < IRONBARS ||
+                                       levl[u.ux][u.uy].typ >= ICE) ?
+                                      "Oops!  %s away from you!" :
+                                      "Oops!  %s to the floor!",
+                                      The(aobjnam(otmp,
+                                            Is_airlevel(&u.uz) || u.uinwater ?
+                                                  "slip" : "drop")),
+                                      (const char *)0);
+           u.ublesscnt += rn1(100,50);  /* the gods take notice */
+       }
+}
+
+#endif /*OVL2*/
+
+/*zap.c*/
diff --git a/sys/amiga/Build.ami b/sys/amiga/Build.ami
new file mode 100644 (file)
index 0000000..babca2e
--- /dev/null
@@ -0,0 +1,146 @@
+
+                         Compiling Amiga NetHack 3.4
+                Last Revision: 21 February 2002 for NetHack 3.4.2
+
+
+   We would like to thank each and every one of the people who took
+   the time and effort to report bugs to us.  THANK YOU!  (And keep
+   up the good work!)
+
+I. Introduction
+
+    The Amiga-specific documentation has been split since the 3.1.3 release
+    - please read the file Install.ami for information specific to the
+    Amiga port before continuing.
+
+    If you have problems with compilation, installation, or think you have
+    found a bug in the game, please report it by electronic mail to the
+    development group at nethack-bugs@nethack.org, where it will be routed
+    to the appropriate person.  Include your configuration, the version of
+    NetHack you are playing (use the 'v' command or see
+    include/patchlevel.h), and as much specific information as possible.
+    As NetHack runs on many different machines, be sure to mention that you
+    are playing the Amiga version and also mention if you are using the
+    version for mc68k or ppc.
+
+    If you want to find out about distributing NetHack, read the license
+    (in NetHack:license or type ?i during the game).
+
+II. Compiling Amiga NetHack 3.4
+
+II.A. Compilation Overview
+    Compiling NetHack is not very hard - basically you do a little
+    configuration and start make.  It does, however, require a good amount
+    of disk space and time.  It also needs a good bit of memory, especially
+    for linking.  
+
+II.B. Basic Compilation
+
+    NetHack can be built with SAS/C version 6.5x.  The commercial version
+    of DICE might work, but NetHack version 3.2.2 or later haven't been
+    compiled with it.  The "official" compiler for NetHack 3.4 is SAS/C 6.58
+    - we have dropped support for SAS/C 5.x.
+
+    The Manx/Aztec port has not been tested recently and is certainly
+    broken.  Anyone managing to compile NetHack with this compiler is
+    encouraged to submit context diffs of the required changes.  When last
+    tested, NetHack required version 5.0B of that compiler.
+
+    Compiling with gcc should also work.
+
+II.B.1. Introduction to Compiling NetHack
+    Before doing any compilation, read the README files distributed with
+    the source.  These should familiarize you with the source tree layout
+    and what files are shared with what computers; everything in the
+    sys/amiga directory is used exclusively by the Amiga.
+
+    The makefile (sys/amiga/Makefile.ami) depends on certain assignments,
+    providing the developer with a fairly flexible environment.  See
+    sys/amiga/Makefile.ami for assignment assumptions.  DICE users should
+    see section II.B.3 for information on creating a DMakefile usable with
+    DMake.
+
+    Edit config.h to your liking and system configuration.  The defaults
+    should be satisfactory for most systems.
+
+    Read VERY CAREFULLY through the Makefile to familiarize yourself
+    with which assignments are assumed.  Otherwise, you're going to get
+    something like "Insert NH: in any drive."  You will need uudecode,
+    and, if you need to modify dgn_comp or lev_comp, flex, and bison.
+    The first thing Makefile.ami does is build makedefs, which handles
+    a variety of data file generation, and then lev_comp and dgn_comp
+    which compile the special levels.  Makedefs will then be run to create
+    a few files, followed by a roughly alphabetically sorted compilation
+    of the entire source tree.  This process will compile selected files
+    from the sys/amiga, sys/share, win/tty, and src directories, eventually
+    creating sbin/nethack.  After building the main binary, a make install
+    will build the auxiliary files including help files, special levels,
+    icons, and the font files and will put these files into their final
+    positions - most will be in dlb archives (if DLB was defined in config.h).
+    The first make run should be done in NH:obj and the make install should be
+    done in NetHack:; for both runs, the makefile is NH:sys/amiga/Makefile.ami
+    (or NH:sys/amiga/DMakefile for DMake and NH:sys/amiga/Makefile.agc for
+    gcc).
+
+    Note that not all the source is simple C code.  If you are modifying
+    lev_comp or dgn_comp you may need bison and/or flex (depending on what
+    modifications you are making).  You do not need any of these tools to
+    simply build NetHack - all the C output files are provided in the source
+    distribution.  Also, the ifchange script requires a version of diff that
+    produces standard Unix format context diffs for proper operation - the
+    version shipped with SAS/C is not sufficient.
+
+    If you do not have bison and flex, copy the files from sys/share.  The
+    include files go in include/ and the C files go in util/.  If the compile
+    fails due to prototype errors for malloc and realloc, try deleting
+    the first line of lev_comp.c and dgn_comp.c.
+
+II.B.2. Compiling NetHack with SAS/C version 6.58
+
+    NOTE WELL - Amiga NetHack has dropped support for SAS/C version 5.
+    This version of NetHack was developed with SAS/C 6.58.  Earlier versions
+    than version of the compiler are known to cause problems - don't use them.
+
+    A couple of notes and warnings from the SAS/C users on the team:
+
+       * Included in the SAS/C port is code for generating a SnapShot.tb
+         file upon catching various internal disasters.  That is why the
+         debug=l flag is in the makefile.  This adds about 270K to the disk
+         image, but it does not increase the run time memory requirements.
+
+       * The 5.10b optimizer did not produce correct code for NetHack.  The
+         current optimizer has not been tested.
+
+II.B.3.        Compiling NetHack with the commercial version of DICE
+
+    IMPORTANT NOTE: If you are using DMake, you need to create DMakefile
+    from Makefile.ami.  Do the following:
+
+       cd NH:sys/amiga
+       edit from Makefile.ami to DMakefile with mkdmake opt w255
+
+    Some versions of DMake have been known to crash horribly on the
+    makefile - if this happens, you'll need to download another make
+    utility, such as AMake (ftp://ftp.dragonfire.net/amiga/utils/amake),
+    which will run in DMake-compatibility mode if invoked with the -C switch
+    (e.g. "amake -C -f NH:sys/amiga/DMakefile", or just
+    "alias dmake amake -C").
+
+    SECOND IMPORTANT NOTE: The score list is currently disabled when
+    compiling under DICE, due to an as-yet-unknown problem which causes
+    system crashes when displaying the score list.
+
+    NetHack can be compiled using the commercial version of DICE only.  The
+    registered shareware version had a bug in it which resulted in odd-
+    aligned procedures.  (It is possible to patch DC1 to fix this problem;
+    however, this is not recommended, and you should upgrade to the
+    commercial version.)
+
+    DICE 3.0 (the first commercial release) has a couple of bugs in it which
+    turn up in several of the NetHack sources; the DCC30_BUG define fixes
+    them.  If you have a more recent version of the compiler, you may be
+    able to compile without this (and get slightly more efficient code) by
+    commenting out the define in amiconf.h.
+
+    During compilation, DICE will output a lot of warnings; they can be
+    safely ignored.
diff --git a/sys/amiga/Install.ami b/sys/amiga/Install.ami
new file mode 100644 (file)
index 0000000..9045a16
--- /dev/null
@@ -0,0 +1,200 @@
+
+                   Using and Installing Amiga NetHack 3.4
+      (or Everything You Never Wanted to Know Before NetHacking)
+        (or Not Everything That Happens Always Comes Knocking)
+
+            Last Revision: 28 March 2000 for NetHack 3.4.2
+
+
+0. Pre-intro for NetHack 3.4.2:
+   Amiga-specific changes for 3.4.2:
+     Most (around 99%) known bugs fixed (volunteers welcome).
+     HackWB and HackCli are no longer supported.  Use the main binary.
+
+   We would like to thank each and every one of the people who took
+   the time and effort to report bugs to us.  THANK YOU!
+
+I. Introduction
+
+I.A. Overview
+    Welcome to Amiga NetHack!  If this is your first visit to our fair
+    city, you are in for an amazing but dangerous journey; if you have
+    visited us before, beware! the city has changed in many strange and
+    subtle ways; it has also grown quite a bit.  This missive brings to
+    light those mundane tasks which must be dealt with before beginning
+    your journey; for those of you who are faced with the task of
+    installing the pre-fabricated version of our town, section III
+    (Installing Amiga NetHack 3.4) will guide you through the task at
+    hand.  If you are ready to visit, the local visitors guide is in
+    section II (Using Amiga NetHack 3.4); please also see the general
+    guide packaged separately (the file "GuideBook").
+    
+    To all our visitors, a hearty Welcome! - and please be careful.
+
+    [Those responsible for the previous paragraphs have been sacked.  The
+    documentation has been completed at great expense in a more traditional
+    style. -- The Management]
+
+I.B. Getting Help
+    If you have questions about strategy, weapons, or monsters, the best
+    place to go for help is the Usenet newsgroup rec.games.roguelike.nethack.
+
+    If you have problems with installation or think you have found a bug
+    in the game, please report it by electronic mail to the development
+    team at nethack-bugs@nethack.org, where it will be routed to the
+    appropriate person.  Include your configuration, the version of
+    NetHack you are playing (use the 'v' command), whether or not you are
+    using an official binary release (and if so which one) and as much
+    specific information as possible.  As NetHack runs on many different
+    machines, be sure to mention that you are playing the Amiga version.
+
+I.C. Credits
+    Olaf Seibert first ported NetHack 2.3 and 3.0 to the Amiga.  Richard
+    Addison, Andrew Church, Jochen Erwied, Mark Gooderum, Ken Lorber,
+    Greg Olson, Mike Passaretti, and Gregg Wonderly polished and extended
+    the 3.0 and 3.1 ports.  Andrew Church, Ken Lorber, and Gregg Wonderly
+    are responsible for the 3.2 port.  Janne Salmijärvi resurrected the
+    amigaport for 3.3 and Teemu Suikki joined before 3.4.0.
+
+II. Using Amiga NetHack 3.4
+    Run NetHack from the shell or from some tool that allows that,
+    ie. ToolManager.  See the NetHack.txt file for command line options
+    and other usage.
+
+II.A. Sources of Information
+    Where to go depends on what you want to find out.  If you want to find
+    out about distributing NetHack, read the license (in NetHack:license
+    or type ?i during the game).  For an introduction to NetHack, read
+    the GuideBook file.  To find out what options are compiled into your
+    copy of NetHack, type #v during the game.  Finally, for information
+    during the game on all kinds of things, type ? and select from the
+    menu or by pressing Help key.
+
+II.B. The Amiga NetHack WorkBench Front End
+    Starting from 3.3.0 HackWB is not supported.
+
+II.C. The Amiga NetHack CLI Front End
+    Starting from 3.3.0 CLI Front end is not supported either.
+
+    Instead, use the main binary.  See NetHack.txt file for the standard Unix
+    flags for NetHack.  In addition to those flags, Amiga NetHack accepts
+    the flags -l to force non-interlaced mode and -L to force interlaced mode.
+
+II.D. Amiga-Specific Information for NetHack
+
+    There are several options that are unique to the Amiga version of
+    NetHack that may be specified in the NetHack.cnf file or on an
+    OPTIONS line:
+
+    altmeta     allows the ALT keys to function as META keys.  The default
+                is altmeta.
+    flush       flush discards all characters in the queue except the first,
+                which limits typeahead accidents.  The default is !flush.
+    silent      turn off the audio output.  The default is silent.
+
+    The current version of Amiga NetHack also supports menu accelerators.
+    See Guidebook.txt for a detailed description.  Also supported is
+    selecting the number of stacked objects to drop, used with the (D)rop
+    command.  Type the number and then select an item (or items with
+    accelerators).  Items with a count associated with them are denoted
+    with # in place of -.  I.e. 'd - 3 blessed daggers' becomes
+    'd # 3 blessed daggers'.  You can clear the count by hitting esc
+    while counting or deselect and reselect the item.  The default
+    is to drop all selected items (as before).
+
+    For other options how to configure the screen setting and colors refer
+    to Nethack.cnf.
+
+III. Installing Amiga NetHack 3.4
+
+III.A. General Installation
+    Installation should be easy - basically it consists of putting files
+    where they belong and adding an assign to your startup.  If you are
+    installing from the official binary distribution, simply unpacking
+    the archive in the appropriate directory will put the files in the
+    places they belong.
+
+    IF YOU ALREADY HAVE A PREVIOUS VERSION INSTALLED YOU MUST DELETE THE
+    OLD SAVE AND BONES FILES - THEY WILL NOT WORK!  This includes save
+    and bones files from all previous versions of NetHack (yes, even 3.3.1).
+    If you have a game in progress and want to finish it, use your
+    current version and then update.
+
+Will NetHack fit on your machine?
+    NetHack 3.4 is large.  NetHack 3.4 is very large.  You will need:
+    > Any standard series Amiga: 500, 600, 1000, 1200, 2000, 2500, 3000, 4000.
+    > WorkBench 2.04 or later.
+    > At least 3 meg of RAM.  NetHack will NOT run in 1 meg (probably even 2).
+    > Mass storage:  A hard drive with over 3 meg of free space is highly
+      recommended.
+
+Hard Disk Installation:
+    Unpack the archive to your place of choice.  Since you are reading this
+    you've probably done that already.  Now just assign NetHack: to
+    NetHack directory containing the executable and datafiles and other needed
+    directories.
+
+    Use the table in the next section to see where things should end up.
+    Be sure that the file 8 ends up in NetHack:hack/8. 
+      
+Configuration
+    Using your favorite text editor, edit NetHack:NetHack.cnf to match
+    your system.
+
+    Create the save file directory (makedir NetHack:save) and the levels file
+    directory (makedir NetHack:levels), if they don't already exist.
+
+    Create the score file (echo to NetHack:record) and, if desired, the log
+    file (echo to NetHack:logfile), if they don't already exist. You may
+    leave out logfile, but record is needed.
+
+III.B. File Location Table
+NetHack:
+       amii.hlp        Guidebook.txt   hack.font
+       license         NetHack         NetHack.cnf
+       NetHack.txt     nhdat           nhsdat
+       record          Recover         Recover.txt
+       logfile (optional, but useful)
+NetHack:hack
+       8
+NetHack:tiles
+       monsters.iff    objects.iff     other.iff
+
+IV. BBS Interface
+
+    [Since HackCli and split binary is no longer supported the following
+    probably doesn't apply anymore.  Due to lack of a suitable environment
+    it is also untested.]
+
+    The BBS mode is based on the standard NetHack tty port and is designed
+    for use in a BBS setting - it is specifically not recommended for use
+    on the console.  The current TTY mode has changed significantly since
+    the preliminary version released with 3.1.2.  In particular, BBS mode
+    now works with split binaries (only), and now supports multiple games
+    in progress at the same time for multi-line boards (note however that
+    any individual user should not be allowed to run two instances of
+    NetHack at the same time).
+
+    To set up NetHack for use with a BBS, set OPTIONS=windowtype:tty
+    and unset DUNGEONS, TRAPS, and EFFECTS in NetHack.cnf.  Configure
+    the BBS to expect I/O through stdin and stdout, and have NetHack
+    invoked as:
+       HackCLI :uid -u uname options...
+    where uid is any string (without embedded spaces, colons, or slashes)
+    that is unique for each BBS user and uname is some corresponding human-
+    readable name for that user.  Uid is used in constructing file names
+    to prevent collisions between simultaneous games and to prevent
+    people from using other people's save files.  Uname is the name the
+    character will have in the game and the name that will appear in the
+    record file.
+
+    The terminal is assumed to be a 24x80 ANSI-compatible terminal.
+    The present version does not deal with situations such as low
+    memory gracefully - as NetHack uses a considerable amount of
+    memory this is particularly painful with multiple games in
+    progress.  Sysops are reminded to be familiar with the recover
+    utility, which may be needed from time to time and which should
+    probably not be available directly to users.  Bug reports and
+    suggestions for improvements are requested from the user community -
+    this is still considered alpha software.
+
diff --git a/sys/amiga/Makefile.agc b/sys/amiga/Makefile.agc
new file mode 100644 (file)
index 0000000..ea1d36b
--- /dev/null
@@ -0,0 +1,1337 @@
+#      NetHack Makefile.
+#      SCCS Id: @(#)Makefile.agc       3.2     2000/01/12
+# Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1991,1992,1993,1996.
+# NetHack may be freely redistributed.  See license for details.
+
+###
+### modified for gcc by Teemu Suikki (zu@iki.fi)
+###
+### note: you need to use smake.. sorry
+###
+
+###
+### DIRECTORY STRUCTURE
+###
+
+NH = nh:
+
+SBIN = $(NH)sbin/
+SLIB = $(NH)slib/
+NETHACK = $(NH)NetHack/
+HACKEXE = $(NH)HackExe/
+AMI = $(NH)sys/amiga/
+DAT = $(NH)dat/
+DOC = $(NH)doc/
+I = $(NH)include/
+SHARE = $(NH)sys/share/
+NHS = $(NH)src/
+TTY = $(NH)win/tty/
+WSHARE  = $(NH)win/share/
+UTIL = $(NH)util/
+O = $(NH)obj/
+OO = $(NH)objo/
+#      NB: O and OO MUST be different directories
+
+###
+### INVOCATION
+###
+
+MAKE = smake
+
+# Startup makefile with:
+#
+#      $(MAKE) -f $(AMI)Makefile.amigcc
+#      $(MAKE) -f $(AMI)Makefile.amigcc install
+#
+# You may use following targets on $(MAKE) command lines:
+#   all                do it all (default)
+#   link       just create binary from object files
+#   obj                just create common object files
+#   obja       just create amiga object files
+#   objs       just create shared object files
+#   clean      deletes the object files
+#   spotless   deletes the object files, main binary, and more
+#
+# Note:  We do not build the Guidebook here since it needs tbl
+# (See the file sys/unix/Makefile.doc for more information)
+
+#[SAS5] [and gcc?]
+#   If we were to use the precompiled header file feature in a newer version
+#   of SAS/C, we would comment out these following two lines.
+#   If we don't use precompiled header files, we uncomment it as well.
+
+HDEP   = $(I)hack.h
+CSYM   =
+
+#Pathname for uudecode program:
+UUDEC  = uudecode
+
+# Flex/Bison command assignments -- Useful only if you have flex/bison
+FLEX   = flex
+BISON  = bison
+# FBFIL and FBLIB may be used, if required by your version of flex or bison,
+# to specify additional files or libraries to be linked with
+FBFIL  =
+FBLIB  = #lib lib:compat.lib
+
+# If you're compiling this on a 1.3 system, you'll have to uncomment the
+# following (for use with the ifchange script below).  Also useful instead of
+# "protect ifchange +s"
+EXECUTE = execute
+
+# Headers we depend on
+AMDEP = $(AMI)winproto.h $(AMI)winext.h $(AMI)windefs.h $(I)winami.h
+
+# Pathname for the C compiler being used.
+
+CC = gcc -c
+ASM = as
+
+# Compilation flags for selected C Compiler:
+#   $(CFLAGS) should appear before filename arguments of $(CC) command line.
+
+CFLAGS = -O3 -I $(I)
+
+# Components of various link command lines:
+#   $(LINK) should be the pathname of the linker being used (with any options
+#   that should appear at the beginning of the command line).  The name of the
+#   output file should appear immediately after $(LNSPEC).  $(LIN) should
+#   appear before the list of object files in each link command.  $(LLINK)
+#   should appear as the list of object files in the link command line that
+#   creates the NetHack executable.  $(LLIB) should appear at the end of each
+#   link command line.
+
+LINK = gcc -noixemul -O3
+LIN     =
+LLINK   =
+LLIB    =
+FLLIB   =
+OBJSPEC = -o
+PNSPEC = -o
+LNSPEC = -o
+CCLINK = gcc -noixemul
+CLFLAGS = -O3 
+INCLSPEC = -I
+DEFSPEC = -D
+IGNSPEC = -j
+
+###
+### FILE LISTS
+###
+
+# A more reasonable random number generator (recommended for the Amiga):
+
+RANDOBJ        = $(O)random.o
+
+.PRECIOUS:  $(I)config.h $(I)decl.h $(I)hack.h $(I)permonst.h $(I)you.h
+
+# Almost nothing below this line should have to be changed.
+# (Exceptions are marked by [SAS6], [MANX], etc.)
+#
+# Other things that have to be reconfigured are in config.h,
+# (amiconf.h, pcconf.h), and possibly system.h, tradstdc.h.
+
+# Object files for makedefs:
+
+MAKEOBJS = \
+       $(OO)makedefs.o $(O)monst.o $(O)objects.o
+
+# Object files for special levels compiler:
+
+SPLEVOBJS = \
+       $(OO)lev_yacc.o $(OO)lev_lex.o  $(OO)lev_main.o \
+       $(O)decl.o      $(O)drawing.o   $(O)monst.o \
+       $(O)objects.o   $(OO)panic.o
+
+# Object files for dungeon compiler
+
+DGNCOMPOBJS = \
+       $(OO)dgn_yacc.o $(OO)dgn_lex.o  $(OO)dgn_main.o $(O)alloc.o $(OO)panic.o
+
+# Object files for NetHack:
+
+COMMOBJ = \
+       $(O)allmain.o   $(O)alloc.o     $(O)apply.o     $(O)artifact.o  \
+       $(O)attrib.o    $(O)ball.o      $(O)bones.o     $(O)botl.o      \
+       $(O)cmd.o       $(O)dbridge.o   $(O)decl.o      $(O)detect.o    \
+       $(O)dig.o       $(O)display.o   $(O)dlb.o       $(O)do.o        \
+       $(O)do_name.o   $(O)do_wear.o   $(O)dog.o       $(O)dogmove.o   \
+       $(O)dokick.o    $(O)dothrow.o   $(O)drawing.o   $(O)dungeon.o   \
+       $(O)eat.o       $(O)end.o       $(O)engrave.o   $(O)exper.o     \
+       $(O)explode.o   $(O)extralev.o  $(O)files.o     $(O)fountain.o  \
+       $(O)hack.o      $(O)hacklib.o   $(O)invent.o    $(O)light.o     \
+       $(O)lock.o      $(O)mail.o      $(O)makemon.o   $(O)mapglyph.o  \
+       $(O)mcastu.o    $(O)mhitm.o     $(O)mhitu.o     $(O)minion.o    \
+       $(O)mklev.o     $(O)mkmap.o     $(O)mkmaze.o    $(O)mkobj.o     \
+       $(O)mkroom.o    $(O)mon.o       $(O)mondata.o   $(O)monmove.o   \
+       $(O)monst.o     $(O)mplayer.o   $(O)mthrowu.o   $(O)muse.o      \
+       $(O)music.o     $(O)o_init.o    $(O)objects.o   $(O)objnam.o    \
+       $(O)options.o   $(O)pager.o     $(O)pickup.o    $(O)pline.o     \
+       $(O)polyself.o  $(O)potion.o    $(O)pray.o      $(O)priest.o    \
+       $(O)quest.o     $(O)questpgr.o  $(O)read.o      $(O)rect.o      \
+       $(O)region.o    $(O)restore.o   $(O)rnd.o       $(O)role.o      \
+       $(O)rumors.o    $(O)save.o      $(O)shk.o       $(O)shknam.o    \
+       $(O)sit.o       $(O)sounds.o    $(O)sp_lev.o    $(O)spell.o     \
+       $(O)steal.o     $(O)steed.o     $(O)teleport.o  $(O)timeout.o   \
+       $(O)topten.o    $(O)track.o     $(O)trap.o      $(O)u_init.o    \
+       $(O)uhitm.o     $(O)vault.o     $(O)version.o   $(O)vision.o    \
+       $(O)weapon.o    $(O)were.o      $(O)wield.o     $(O)windows.o   \
+       $(O)wizard.o    $(O)worm.o      $(O)worn.o      $(O)write.o     \
+       $(O)zap.o
+
+MAKEDEFOBJ = \
+       $(O)monstr.o
+
+AMIGAOBJ = \
+       $(O)amidos.o    $(O)amirip.o    $(O)amisnd.o    $(O)amistack.o  \
+       $(O)amiwind.o   $(O)winami.o    $(O)winchar.o   $(O)winfuncs.o  \
+       $(O)winkey.o    $(O)winmenu.o   $(O)winreq.o    $(O)winstr.o
+
+# Objects from assembly sources (because DMake can't handle default rules)
+AMIGAOBJ2 = \
+#      $(O)dispmap.o
+
+SHAREOBJ = \
+       $(O)pcmain.o    $(RANDOBJ)
+
+TTYOBJ = \
+       $(O)getline.o $(O)termcap.o $(O)topl.o $(O)wintty.o $(O)amitty.o \
+       $(O)rip.o
+
+# Yuck yuck yuck.  Have to tell DMake where these are, since they're not
+# all in the same place.
+TTYSRC = \
+       $(TTY)getline.c $(TTY)termcap.c $(TTY)topl.c $(TTY)wintty.c \
+       $(AMI)amitty.c $(NHS)rip.c
+
+# All the object files for NetHack:
+
+HOBJ = $(COMMOBJ) $(AMIGAOBJ) $(AMIGAOBJ2) $(SHAREOBJ) $(MAKEDEFOBJ) $(TTYOBJ)
+
+###
+### DATA FILES
+###
+
+# quest files
+ADFILES1= $(SLIB)Arc-fila.lev $(SLIB)Arc-filb.lev $(SLIB)Arc-loca.lev \
+       $(SLIB)Arc-strt.lev
+ADFILES= $(SLIB)Arc-goal.lev $(ADFILES1)
+
+BDFILES1= $(SLIB)Bar-fila.lev $(SLIB)Bar-filb.lev $(SLIB)Bar-loca.lev \
+       $(SLIB)Bar-strt.lev
+BDFILES= $(SLIB)Bar-goal.lev $(BDFILES1)
+
+CDFILES1= $(SLIB)Cav-fila.lev $(SLIB)Cav-filb.lev $(SLIB)Cav-loca.lev \
+       $(SLIB)Cav-strt.lev
+CDFILES= $(SLIB)Cav-goal.lev $(CDFILES1)
+
+HDFILES1= $(SLIB)Hea-fila.lev $(SLIB)Hea-filb.lev $(SLIB)Hea-loca.lev \
+       $(SLIB)Hea-strt.lev
+HDFILES= $(SLIB)Hea-goal.lev $(HDFILES1)
+
+KDFILES1= $(SLIB)Kni-fila.lev $(SLIB)Kni-filb.lev $(SLIB)Kni-loca.lev \
+       $(SLIB)Kni-strt.lev
+KDFILES= $(SLIB)Kni-goal.lev $(KDFILES1)
+
+MDFILES1= $(SLIB)Mon-fila.lev $(SLIB)Mon-filb.lev $(SLIB)Mon-loca.lev \
+       $(SLIB)Mon-strt.lev
+MDFILES= $(SLIB)Mon-goal.lev $(MDFILES1)
+
+PDFILES1= $(SLIB)Pri-fila.lev $(SLIB)Pri-filb.lev $(SLIB)Pri-loca.lev \
+       $(SLIB)Pri-strt.lev
+PDFILES= $(SLIB)Pri-goal.lev $(PDFILES1)
+
+RDFILES1= $(SLIB)Rog-fila.lev $(SLIB)Rog-filb.lev $(SLIB)Rog-loca.lev \
+       $(SLIB)Rog-strt.lev
+RDFILES= $(SLIB)Rog-goal.lev $(RDFILES1)
+
+RANFILES1= $(SLIB)Ran-fila.lev $(SLIB)Ran-filb.lev $(SLIB)Ran-loca.lev \
+       $(SLIB)Ran-strt.lev
+RANFILES= $(SLIB)Ran-goal.lev $(RANFILES1)
+
+SDFILES1= $(SLIB)Sam-fila.lev $(SLIB)Sam-filb.lev $(SLIB)Sam-loca.lev \
+       $(SLIB)Sam-strt.lev
+SDFILES= $(SLIB)Sam-goal.lev $(SDFILES1)
+
+TDFILES1= $(SLIB)Tou-fila.lev $(SLIB)Tou-filb.lev $(SLIB)Tou-loca.lev \
+       $(SLIB)Tou-strt.lev
+TDFILES= $(SLIB)Tou-goal.lev $(TDFILES1)
+
+VDFILES1= $(SLIB)Val-fila.lev $(SLIB)Val-filb.lev $(SLIB)Val-loca.lev \
+       $(SLIB)Val-strt.lev
+VDFILES= $(SLIB)Val-goal.lev $(VDFILES1)
+
+WDFILES1= $(SLIB)Wiz-fila.lev $(SLIB)Wiz-filb.lev $(SLIB)Wiz-loca.lev \
+       $(SLIB)Wiz-strt.lev
+WDFILES= $(SLIB)Wiz-goal.lev $(WDFILES1)
+
+XDFILES=       $(ADFILES) $(BDFILES) $(CDFILES) $(HDFILES) $(KDFILES) \
+               $(MDFILES) $(PDFILES) $(RDFILES) $(RANFILES) $(SDFILES) $(TDFILES) \
+               $(VDFILES) $(WDFILES)
+
+SOUNDFILES= \
+       $(SBIN)cvtsnd \
+       $(SLIB)sounds \
+       $(SLIB)sounds/Bell $(SLIB)sounds/Bugle \
+       $(SLIB)sounds/Drum_Of_Earthquake \
+       $(SLIB)sounds/Fire_Horn $(SLIB)sounds/Frost_Horn \
+       $(SLIB)sounds/Leather_Drum $(SLIB)sounds/Magic_Flute \
+       $(SLIB)sounds/Magic_Harp $(SLIB)sounds/Tooled_Horn \
+       $(SLIB)sounds/Wooden_Flute $(SLIB)sounds/Wooden_Harp
+
+TILEFILES= \
+       $(SBIN)txt2iff \
+       $(NETHACK)tiles \
+       $(NETHACK)tiles/objects.iff \
+       $(NETHACK)tiles/monsters.iff \
+       $(NETHACK)tiles/other.iff
+
+INSTDUNGEONFILES1= \
+       $(SLIB)air.lev          $(SLIB)asmodeus.lev     $(SLIB)astral.lev \
+       $(SLIB)baalz.lev        $(SLIB)bigrm-1.lev      $(SLIB)bigrm-2.lev \
+       $(SLIB)bigrm-3.lev      $(SLIB)bigrm-4.lev      $(SLIB)bigrm-5.lev \
+       $(SLIB)castle.lev       $(SLIB)dungeon          $(SLIB)earth.lev \
+       $(SLIB)fakewiz1.lev     $(SLIB)fakewiz2.lev     $(SLIB)fire.lev \
+       $(SLIB)juiblex.lev      $(SLIB)knox.lev         $(SLIB)medusa-1.lev \
+       $(SLIB)medusa-2.lev     $(SLIB)minend-1.lev     $(SLIB)minend-2.lev \
+       $(SLIB)minetn-1.lev     $(SLIB)minetn-2.lev     $(SLIB)minefill.lev \
+       $(SLIB)options          $(SLIB)oracle.lev       $(SLIB)orcus.lev \
+       $(SLIB)sanctum.lev      $(SLIB)soko1-1.lev      $(SLIB)soko1-2.lev \
+       $(SLIB)soko2-1.lev      $(SLIB)soko2-2.lev      $(SLIB)soko3-1.lev \
+       $(SLIB)soko3-2.lev      $(SLIB)soko4-1.lev      $(SLIB)soko4-2.lev \
+       $(SLIB)tower1.lev       $(SLIB)tower2.lev       $(SLIB)tower3.lev \
+       $(SLIB)valley.lev       $(SLIB)water.lev        $(SLIB)wizard1.lev \
+       $(SLIB)wizard2.lev      $(SLIB)wizard3.lev \
+       $(XDFILES)
+
+INSTDUNGEONFILES= $(NETHACK)NetHack.cnf $(INSTDUNGEONFILES1)
+
+
+INSTDATAFILES= \
+       $(NETHACK)license       $(NETHACK)logfile       $(NETHACK)record \
+       $(NETHACK)tomb.iff      $(NETHACK)amii.hlp      $(NETHACK)Recover.txt \
+       $(NETHACK)GuideBook.txt $(NETHACK)NetHack.txt   $(NETHACK)Install.ami \
+#      $(NETHACK)HackWB.hlp    $(NETHACK)WBDefaults.def
+
+LIBFILES= \
+       $(INSTDUNGEONFILES1) \
+       $(SLIB)cmdhelp          $(SLIB)data             $(SLIB)dungeon \
+       $(SLIB)help             $(SLIB)hh               $(SLIB)history \
+       $(SLIB)opthelp          $(SLIB)oracles          $(SLIB)rumors \
+       $(SLIB)quest.dat        $(SLIB)wizhelp
+
+###
+### Getting down to business:
+###
+
+all:  $(COMPACT_HEADERS) $(SBIN)lev_comp $(SBIN)dgn_comp $(SBIN)NetHack \
+       $(SBIN)dlb $(NETHACK)recover #$(NETHACK)HackCli $(SBIN)splitter \
+#      $(NETHACK)HackWB 
+
+install: inst-data inst-dungeon inst-fonts inst-sounds inst-tiles \
+        $(NETHACK)recover $(NETHACK)NetHack $(NETHACK)nhdat
+       #$(NETHACK)NetHack.dir inst-icons
+
+$(SBIN)NetHack:  link
+
+$(NETHACK)NetHack: $(SBIN)NetHack
+       copy $(SBIN)NetHack $(NETHACK)NetHack
+
+## uuh this is messy.. smake has weird command line length limit
+link: $(HOBJ)
+       list to t:link lformat="$(O)%s" $(O)\#?.o QUICK NOHEAD
+       echo "\#sh" to t:cc
+       echo "$(LINK) $(LNSPEC) $(SBIN)NetHack $(LIN) $(LLIB) $(LLINK) " >>t:cc noline
+       fmt -u -w 2500 t:link >>t:cc
+       sh t:cc
+       delete t:cc t:link
+
+
+## dlb support
+$(OO)dlb_main.o:       $(UTIL)dlb_main.c $(HDEP) $(I)dlb.h $(I)date.h
+       $(CC) $(CFLAGS) $(OBJSPEC)$(OO)dlb_main.o $(UTIL)dlb_main.c
+
+$(SBIN)dlb:    $(OO)dlb_main.o $(O)dlb.o $(O)alloc.o $(OO)panic.o
+       $(LINK) $(PNSPEC) $(SBIN)dlb $(LIN) $(OO)dlb_main.o $(O)dlb.o \
+         $(O)alloc.o $(OO)panic.o $(LLIB)
+
+obj:  $(HOBJ)
+
+obja:  $(AMIGAOBJ)
+
+objs:  $(SHAREOBJ)
+
+
+SUFFIXES = .lev .des
+.des.lev:
+       $(SBIN)lev_comp $<
+
+# The default method for creating object files:
+
+#$(O)%.o: $(NHS)%.c
+.c.o:
+       $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)$@ $<
+
+clean:
+       -delete $(O)\#?.o $(OO)\#?.o
+
+spotless:  clean
+       -delete $(SBIN)NetHack $(SBIN)lev_comp $(SBIN)makedefs $(SBIN)dgn_comp
+       -delete $(SBIN)cvtsnd $(SBIN)dlb $(SBIN)txt2iff $(SBIN)splitter
+       -delete $(SBIN)tilemap
+       -delete $(SLIB)data $(SLIB)rumors
+       -delete $(SLIB)\#?.lev
+       -delete $(SLIB)dungeon
+       -delete $(SLIB)cmdhelp $(SLIB)help $(SLIB)hh $(SLIB)history
+       -delete $(SLIB)opthelp $(SLIB)options $(SLIB)oracles
+       -delete $(SLIB)quest.dat $(SLIB)wizhelp
+#      -delete $(SLIB)earth.lev $(SLIB)air.lev $(SLIB)fire.lev
+#      -delete $(SLIB)water.lev $(SLIB)astral.lev
+#      -delete $(SLIB)tower1.lev $(SLIB)tower2.lev $(SLIB)tower3.lev
+#      -delete $(SLIB)fakewiz1.lev $(SLIB)fakewiz2.lev
+#      -delete $(SLIB)medusa-1.lev $(SLIB)medusa-2.lev
+#      -delete $(SLIB)oracle.lev $(SLIB)wizard1.lev $(SLIB)wizard2.lev
+#      -delete $(SLIB)wizard3.lev $(DAT)dungeon.pdf $(SLIB)valley.lev
+#      -delete $(SLIB)minefill.lev
+#      -delete $(SLIB)minetn-1 $(SLIB)minetn-2 $(SLIB)minend-1 $(SLIB)minend-2
+#      -delete $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev $(SLIB)soko2-1.lev
+#      -delete $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev $(SLIB)soko3-2.lev
+#      -delete $(SLIB)soko4-1.lev $(SLIB)soko4-2.lev
+#      -delete $(ADFILES)
+#      -delete $(BDFILES)
+#      -delete $(CDFILES)
+#      -delete $(HDFILES)
+#      -delete $(KDFILES)
+#      -delete $(MDFILES)
+#      -delete $(PDFILES)
+#      -delete $(RDFILES)
+#      -delete $(RANFILES)
+#      -delete $(SDFILES)
+#      -delete $(TDFILES)
+#      -delete $(VDFILES)
+#      -delete $(WDFILES)
+       -delete $(I)onames.h $(I)pm.h $(I)date.h
+       -delete $(NHS)tile.c $(NHS)monstr.c
+       -delete $(I)tile.h 
+#      -echo to $(I)onames.h "" noline
+#      -c:wait 2
+#      -echo to $(I)pm.h "" noline
+#      -c:wait 2
+#      -setdate $(UTIL)makedefs.c
+#      -c:wait 2
+
+# Creating precompiled version of $(I)hack.h to save disk I/O.
+
+#
+#      Please note:    The dependency lines for the modules here are
+#                      deliberately incorrect.  Including "hack.h" in
+#                      the dependency list would cause a dependency
+#                      loop.
+#
+
+$(SBIN)makedefs: $(MAKEOBJS)
+       $(LINK) $(LNSPEC) $(SBIN)makedefs $(LIN) $(MAKEOBJS) $(LLIB)
+
+$(OO)makedefs.o:  $(UTIL)makedefs.c $(I)config.h $(I)permonst.h $(I)monsym.h \
+               $(I)objclass.h  $(I)patchlevel.h $(I)qtext.h $(I)artilist.h
+       $(CC) $(DEFSPEC)MAKEDEFS_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)makedefs.c
+
+$(SBIN)lev_comp:  $(SPLEVOBJS)
+       $(LINK) $(LNSPEC) $(SBIN)lev_comp $(LIN) $(SPLEVOBJS) $(FBFIL) $(FLLIB)
+
+$(SBIN)dgn_comp:  $(DGNCOMPOBJS)
+       $(LINK) $(LNSPEC) $(SBIN)dgn_comp $(LIN) $(DGNCOMPOBJS) $(FBFIL) $(FLLIB)
+
+$(OO)lev_yacc.o:  $(UTIL)lev_yacc.c $(HDEP) $(I)sp_lev.h $(I)pm.h $(I)onames.h
+#      setdate $(UTIL)lev_yacc.c
+       $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)PREFIX="NH:slib/" $(CFLAGS) \
+               $(DEFSPEC)alloca=malloc $(OBJSPEC)$@ $(UTIL)lev_yacc.c
+
+$(OO)lev_lex.o: $(UTIL)lev_lex.c $(HDEP) $(I)lev_comp.h $(I)sp_lev.h
+       $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)lev_lex.c
+
+$(OO)lev_main.o:  $(UTIL)lev_main.c $(HDEP) $(I)pm.h $(I)onames.h $(I)date.h
+       $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \
+               $(UTIL)lev_main.c
+
+$(OO)dgn_yacc.o:  $(UTIL)dgn_yacc.c $(HDEP) $(I)dgn_file.h $(I)patchlevel.h
+       $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(DEFSPEC)alloca=malloc \
+               $(OBJSPEC)$@ $(UTIL)dgn_yacc.c
+
+$(OO)dgn_lex.o: $(UTIL)dgn_lex.c $(I)config.h $(I)dgn_comp.h $(I)dgn_file.h
+       $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)dgn_lex.c
+
+$(OO)dgn_main.o: $(UTIL)dgn_main.c $(I)config.h $(I)date.h
+       $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \
+               $(UTIL)dgn_main.c
+
+$(OO)panic.o: $(UTIL)panic.c $(HDEP)
+
+$(OO)recover.o: $(UTIL)recover.c $(I)config.h $(I)date.h
+       $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \
+               $(UTIL)recover.c
+
+$(NETHACK)recover: $(OO)recover.o
+       $(LINK) $(LNSPEC) $(NETHACK)recover $(LIN) $(OO)recover.o $(LLIB)
+
+# [OPTION] -- If you have flex/bison, leave these uncommented.  Otherwise,
+# comment them out and be careful! (You're not guaranteed to have the most
+# up to date *_comp.c, *_comp.h and *_lex.c)
+
+$(I)lev_comp.h: $(UTIL)lev_yacc.c $(I)patchlevel.h
+
+$(UTIL)lev_yacc.c:  $(UTIL)lev_comp.y $(I)patchlevel.h
+       $(BISON) -d $(UTIL)lev_comp.y
+#      copy y.tab.c $(UTIL)lev_yacc.c
+#      copy y.tab.h $(I)lev_comp.h
+       copy $(UTIL)lev_comp.tab.c $(UTIL)lev_yacc.c
+       copy $(UTIL)lev_comp.tab.h $(I)lev_comp.h
+#      delete y.tab.c
+#      delete y.tab.h
+       delete $(UTIL)lev_comp.tab.c
+       delete $(UTIL)lev_comp.tab.h
+
+$(UTIL)lev_lex.c:  $(UTIL)lev_comp.l $(I)patchlevel.h
+       $(FLEX) $(UTIL)lev_comp.l
+       copy lex.yy.c $(UTIL)lev_lex.c
+       delete lex.yy.c
+
+$(I)dgn_comp.h: $(UTIL)dgn_yacc.c $(I)patchlevel.h
+
+$(UTIL)dgn_yacc.c:  $(UTIL)dgn_comp.y $(I)patchlevel.h
+       $(BISON) -d $(UTIL)dgn_comp.y
+#      copy y.tab.c $(UTIL)dgn_yacc.c
+#      copy y.tab.h $(I)dgn_comp.h
+       copy $(UTIL)dgn_comp.tab.c $(UTIL)dgn_yacc.c
+       copy $(UTIL)dgn_comp.tab.h $(I)dgn_comp.h
+#      delete y.tab.c
+#      delete y.tab.h
+       delete $(UTIL)dgn_comp.tab.c
+       delete $(UTIL)dgn_comp.tab.h
+
+$(UTIL)dgn_lex.c:  $(UTIL)dgn_comp.l $(I)patchlevel.h
+       $(FLEX) $(UTIL)dgn_comp.l
+       copy lex.yy.c $(UTIL)dgn_lex.c
+       delete lex.yy.c
+
+#
+#      The following include files depend on makedefs to be created.
+#      As a result, they are not defined in HACKINCL, instead, their
+#      dependencies are explicitly outlined here.
+#
+
+#
+#      date.h should be remade any time any of the source or include code
+#      is modified.  Unfortunately, this would make the contents of this
+#      file far more complex.  Since "hack.h" depends on most of the include
+#      files, we kludge around this by making date.h dependent on hack.h,
+#      even though it doesn't include this file.
+#
+
+$(I)date.h $(DAT)options:  $(HDEP) $(SBIN)makedefs $(AMIGAOBJ) $(I)patchlevel.h
+       $(SBIN)makedefs -v
+       $(EXECUTE) ifchange MOVE $(I)t.date.h $(I)date.h
+       -c:wait 2
+
+$(I)onames.h:  $(SBIN)makedefs
+       $(SBIN)makedefs -o
+       $(EXECUTE) ifchange TOUCH $(I)t.onames.h $(I)onames.h $(I)decl.h
+       $(EXECUTE) ifchange MOVE $(I)t.onames.h $(I)onames.h
+       -c:wait 2
+
+$(I)pm.h:  $(SBIN)makedefs
+       $(SBIN)makedefs -p
+       $(EXECUTE) ifchange TOUCH $(I)t.pm.h $(I)pm.h $(I)decl.h $(I)youprop.h
+       $(EXECUTE) ifchange MOVE $(I)t.pm.h $(I)pm.h
+       -c:wait 2
+
+$(SLIB)quest.dat:      $(DAT)quest.txt $(SBIN)makedefs
+       $(SBIN)makedefs -q
+
+$(NHS)monstr.c:  $(HDEP) $(SBIN)makedefs
+       $(SBIN)makedefs -m
+       -c:wait 2
+
+$(SLIB)oracles:        $(DAT)oracles.txt $(SBIN)makedefs
+       $(SBIN)makedefs -h
+       -c:wait 2
+
+#
+#      The following programs vary depending on what OS you are using.
+#      As a result, they are not defined in HACKSRC and their dependencies
+#      are explicitly outlined here.
+#
+
+$(O)amidos.o:  $(AMI)amidos.c $(HDEP)
+
+$(O)amirip.o:  $(AMI)amirip.c $(HDEP)
+
+$(O)aglue.o:  $(AMI)aglue.a
+       $(ASM) $(AFLAGS) $(AOBJSPEC)$(O)aglue.o $(AMI)aglue.a
+
+$(O)amisnd.o:  $(AMI)amisnd.c $(HDEP)
+
+$(O)winchar.o: $(AMI)winchar.c $(NHS)tile.c $(HDEP)
+
+$(NHS)tile.c:  $(WSHARE)tilemap.c
+       $(CCLINK) $(CFLAGS) $(PNSPEC) $(SBIN)tilemap $(WSHARE)tilemap.c
+       $(SBIN)tilemap
+
+$(O)winstr.o:  $(AMI)winstr.c $(HDEP) $(AMDEP)
+
+$(O)winreq.o:  $(AMI)winreq.c $(HDEP) $(AMDEP) $(AMI)colorwin.c $(AMI)clipwin.c
+
+$(O)winfuncs.o:        $(AMI)winfuncs.c $(HDEP) $(AMDEP) $(I)patchlevel.h
+
+$(O)winkey.o:  $(AMI)winkey.c $(HDEP) $(AMDEP)
+
+$(O)winmenu.o: $(AMI)winmenu.c $(HDEP) $(AMDEP)
+
+$(O)winami.o:  $(AMI)winami.c $(HDEP) $(AMDEP) #$(AMI)char.c $(AMI)randwin.c
+
+#$(O)amilib.o: $(AMI)amilib.c $(HDEP) $(AMDEP)
+
+$(O)amiwind.o:  $(AMI)amiwind.c $(AMI)amimenu.c $(HDEP) $(AMDEP)
+
+$(O)amiwbench.o:  $(AMI)amiwbench.c $(HDEP)
+
+$(O)random.o:  $(SHARE)random.c
+
+$(O)pcmain.o:  $(SHARE)pcmain.c $(HDEP) $(I)dlb.h
+
+$(O)dispmap.o: $(AMI)dispmap.s
+       $(ASM) $(AFLAGS) $(AOBJSPEC)$@ $<
+
+# Stuff to build the front ends
+$(NETHACK)HackWB: $(OO)wb.o $(OO)wbx.o $(OO)loader.o $(OO)multi.o
+       $(LINK) $(LNSPEC) $(NETHACK)HackWB $(LIN) $(OO)wb.o $(OO)wbx.o \
+               $(OO)loader.o $(OO)multi.o $(LLIB)
+
+$(NETHACK)HackCli: $(OO)cli.o $(OO)loader.o $(OO)multi.o
+       $(LINK) $(LNSPEC) $(NETHACK)HackCli $(LIN) $(OO)cli.o $(OO)loader.o \
+               $(OO)multi.o $(LLIB)
+
+# This needs to exist to eliminate the HackWB startup message
+$(NETHACK)WBDefaults.def:
+       echo to $(NETHACK)WBDefaults.def
+
+WBH    = $(AMI)wbdefs.h $(AMI)wbstruct.h $(AMI)wbprotos.h
+ASP    = $(AMI)splitter
+$(OO)wb.o: $(WBH) $(AMI)wb.c $(AMI)wbwin.c $(AMI)wbdata.c $(AMI)wbgads.c \
+               $(I)patchlevel.h
+       $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)wb.o $(AMI)wb.c
+
+$(OO)wbx.o: $(WBH) $(AMI)wbcli.c $(AMI)wbwin.c $(AMI)wbdata.c \
+               $(I)patchlevel.h $(I)date.h
+       $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)wbx.o $(AMI)wbcli.c
+
+$(OO)loader.o: $(ASP)/loader.c $(ASP)/split.h $(ASP)/amiout.h $(ASP)/multi.h
+       $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)loader.o $(ASP)/loader.c
+
+$(OO)multi.o: $(ASP)/multi.c $(ASP)/multi.h
+       $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)multi.o $(ASP)/multi.c
+
+$(OO)cli.o: $(WBH) $(AMI)wbcli.c $(I)patchlevel.h $(I)date.h
+       $(CC) $(WBCFLAGS) $(WBC2FLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)cli.o \
+               $(AMI)wbcli.c
+
+####
+# splitter support
+$(SBIN)splitter:       $(OO)splitter.o $(OO)arg.o
+       $(LINK) $(LNSPEC) $(SBIN)splitter $(LIN) $(OO)splitter.o $(OO)arg.o \
+               $(LLIB)
+
+$(NETHACK)NetHack.dir: $(SBIN)splitter $(SBIN)NetHack
+       $(SBIN)splitter $(SBIN)NetHack
+
+$(OO)splitter.o:       $(ASP)/splitter.c $(ASP)/split.h $(ASP)/amiout.h $(ASP)/arg.h
+       $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)splitter.o \
+               $(ASP)/splitter.c
+
+$(OO)arg.o:    $(ASP)/arg.c $(ASP)/arg.h
+       $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)arg.o $(ASP)/arg.c 
+
+# Create/copy other stuff into NetHack: directory:
+
+$(NETHACK)tomb.iff:    $(SBIN)xpm2iff $(AMI)grave16.xpm
+       $(SBIN)xpm2iff $(AMI)grave16.xpm $(NETHACK)tomb.iff
+
+$(OO)xpm2iff.o:        $(AMI)xpm2iff.c
+       $(CC) $(CFLAGS) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(AMI)xpm2iff.c
+
+$(SBIN)xpm2iff:        $(OO)xpm2iff.o
+       $(LINK) $(LNSPEC) $@ $(LIN) $(OO)xpm2iff.o $(FLLIB)
+
+# Tile installation for the tile version of the game
+inst-tiles: $(TILEFILES)
+
+$(NETHACK)tiles:
+       -makedir $(NETHACK)tiles
+
+$(OO)txt2iff.o:        $(AMI)txt2iff.c
+       $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ \
+               $(AMI)txt2iff.c
+
+$(OO)ppmwrite.o: $(WSHARE)ppmwrite.c
+       $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)ppmwrite.c
+
+$(OO)tiletext.o:       $(WSHARE)tiletext.c $(I)config.h $(WSHARE)tile.h
+       $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)tiletext.c
+
+$(OO)tiletxt.o:        $(WSHARE)tilemap.c $(I)hack.h
+       $(CC) $(CFLAGS) $(CSYM) $(DEFSPEC)TILETEXT $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)tilemap.c
+
+NAMEOBJS = $(O)drawing.o $(O)decl.o $(O)monst.o $(O)objects.o
+
+$(SBIN)txt2ppm:        $(OO)ppmwrite.o $(NAMEOBJS) $(O)alloc.o $(OO)panic.o $(OO)tiletext.o $(OO)tiletxt.o
+       $(LINK) $(LNSPEC) $@ $(LIN) $(OO)ppmwrite.o $(NAMEOBJS) $(OO)tiletext.o $(OO)tiletxt.o $(O)alloc.o $(OO)panic.o $(FLLIB)
+
+$(SBIN)txt2iff: $(OO)txt2iff.o $(NAMEOBJS) $(OO)tiletext.o $(OO)tiletxt.o
+       $(LINK) $(LNSPEC) $@ $(LIN) $(OO)txt2iff.o $(NAMEOBJS) $(OO)tiletext.o \
+               $(OO)tiletxt.o  $(FLLIB)
+
+$(NETHACK)tiles/objects.iff: $(WSHARE)objects.txt $(SBIN)txt2iff
+       $(SBIN)txt2iff $(WSHARE)objects.txt $(NETHACK)tiles/objects.iff
+
+$(NETHACK)tiles/monsters.iff: $(WSHARE)monsters.txt $(SBIN)txt2iff
+       $(SBIN)txt2iff $(WSHARE)monsters.txt $(NETHACK)tiles/monsters.iff
+
+$(NETHACK)tiles/other.iff: $(WSHARE)other.txt $(SBIN)txt2iff
+       $(SBIN)txt2iff $(WSHARE)other.txt $(NETHACK)tiles/other.iff
+
+# Sound installation rules.
+inst-sounds: $(SOUNDFILES)
+       list to T:nhsdat.lst $(SLIB)sounds QUICK NOHEAD
+       echo  >T:make-nhsdat $(SBIN)dlb cCfI $(SLIB)sounds $(NETHACK)nhsdat T:nhsdat.lst
+       echo >>T:make-nhsdat if not exists $(NETHACK)nhsdat
+       echo >>T:make-nhsdat copy $(SLIB)sounds/\#? $(NETHACK)sounds
+       echo >>T:make-nhsdat endif
+       execute T:make-nhsdat
+       -delete T:make-nhsdat
+
+$(SLIB)sounds:
+       -makedir $(SLIB)sounds
+
+$(SBIN)cvtsnd: $(OO)cvtsnd.o
+       $(LINK) $(LNSPEC) $@ $(LIN) $(OO)cvtsnd.o $(FLLIB)
+
+$(OO)cvtsnd.o: $(AMI)cvtsnd.c
+
+$(SLIB)sounds/Bell: $(SHARE)sounds/bell.uu
+       $(UUDEC) $(SHARE)sounds/bell.uu
+       $(SBIN)cvtsnd Bell $(SLIB)sounds/Bell
+       -delete Bell
+
+$(SLIB)sounds/Bugle: $(SHARE)sounds/bugle.uu
+       $(UUDEC) $(SHARE)sounds/bugle.uu
+       $(SBIN)cvtsnd Bugle $(SLIB)sounds/Bugle
+       -delete Bugle
+
+$(SLIB)sounds/Drum_Of_Earthquake: $(SHARE)sounds/erthdrum.uu
+       $(UUDEC) $(SHARE)sounds/erthdrum.uu
+       $(SBIN)cvtsnd Drum_Of_Earthquake $(SLIB)sounds/Drum_Of_Earthquake
+       -delete Drum_Of_Earthquake
+
+$(SLIB)sounds/Fire_Horn: $(SHARE)sounds/firehorn.uu
+       $(UUDEC) $(SHARE)sounds/firehorn.uu
+       $(SBIN)cvtsnd Fire_Horn $(SLIB)sounds/Fire_Horn
+       -delete Fire_Horn
+
+$(SLIB)sounds/Frost_Horn: $(SHARE)sounds/frsthorn.uu
+       $(UUDEC) $(SHARE)sounds/frsthorn.uu
+       $(SBIN)cvtsnd Frost_Horn $(SLIB)sounds/Frost_Horn
+       -delete Frost_Horn
+
+$(SLIB)sounds/Leather_Drum: $(SHARE)sounds/lethdrum.uu
+       $(UUDEC) $(SHARE)sounds/lethdrum.uu
+       $(SBIN)cvtsnd Leather_Drum $(SLIB)sounds/Leather_Drum
+       -delete Leather_Drum
+
+$(SLIB)sounds/Magic_Flute: $(SHARE)sounds/mgcflute.uu
+       $(UUDEC) $(SHARE)sounds/mgcflute.uu
+       $(SBIN)cvtsnd Magic_Flute $(SLIB)sounds/Magic_Flute
+       -delete Magic_Flute
+
+$(SLIB)sounds/Magic_Harp: $(SHARE)sounds/mgcharp.uu
+       $(UUDEC) $(SHARE)sounds/mgcharp.uu
+       $(SBIN)cvtsnd Magic_Harp $(SLIB)sounds/Magic_Harp
+       -delete Magic_Harp
+
+$(SLIB)sounds/Tooled_Horn: $(SHARE)sounds/toolhorn.uu
+       $(UUDEC) $(SHARE)sounds/toolhorn.uu
+       $(SBIN)cvtsnd Tooled_Horn $(SLIB)sounds/Tooled_Horn
+       -delete Tooled_Horn
+
+$(SLIB)sounds/Wooden_Flute: $(SHARE)sounds/wdnflute.uu
+       $(UUDEC) $(SHARE)sounds/wdnflute.uu
+       $(SBIN)cvtsnd Wooden_Flute $(SLIB)sounds/Wooden_Flute
+       -delete Wooden_Flute
+
+$(SLIB)sounds/Wooden_Harp: $(SHARE)sounds/wdnharp.uu
+       $(UUDEC) $(SHARE)sounds/wdnharp.uu
+       $(SBIN)cvtsnd Wooden_Harp $(SLIB)sounds/Wooden_Harp
+       -delete Wooden_Harp
+
+inst-dungeon: $(INSTDUNGEONFILES)
+
+$(NETHACK)options : $(DAT)options
+       copy $(DAT)options $@
+
+# Create compiled dungeon files
+BGM= $(SLIB)bigrm-2.lev $(SLIB)bigrm-3.lev $(SLIB)bigrm-4.lev $(SLIB)bigrm-5.lev
+$(BGM):        $(SLIB)bigrm-1.lev
+
+$(SLIB)bigrm-1.lev: $(DAT)bigroom.des $(SBIN)lev_comp
+
+$(SLIB)castle.lev:  $(DAT)castle.des $(SBIN)lev_comp
+
+ENDGAME1= $(SLIB)air.lev $(SLIB)earth.lev $(SLIB)fire.lev $(SLIB)water.lev
+$(ENDGAME1):   $(SLIB)astral.lev
+
+$(SLIB)astral.lev:     $(DAT)endgame.des $(SBIN)lev_comp
+
+GEHENNOM1= $(SLIB)asmodeus.lev $(SLIB)baalz.lev $(SLIB)juiblex.lev \
+  $(SLIB)orcus.lev $(SLIB)sanctum.lev 
+$(GEHENNOM1):  $(SLIB)valley.lev
+
+$(SLIB)valley.lev:     $(DAT)gehennom.des $(SBIN)lev_comp
+
+$(SLIB)knox.lev: $(DAT)knox.des $(SBIN)lev_comp
+
+MINES1= $(SLIB)minend-1.lev $(SLIB)minend-2.lev $(SLIB)minetn-1.lev $(SLIB)minetn-2.lev
+$(MINES1): $(SLIB)minefill.lev
+
+$(SLIB)minefill.lev: $(DAT)mines.des $(SBIN)lev_comp
+
+$(SLIB)oracle.lev: $(DAT)oracle.des $(SBIN)lev_comp
+
+TOWER1= $(SLIB)tower1.lev $(SLIB)tower2.lev
+$(TOWER1): $(SLIB)tower3.lev
+
+$(SLIB)tower3.lev: $(DAT)tower.des $(SBIN)lev_comp
+
+WIZARD1= $(SLIB)wizard1.lev $(SLIB)wizard2.lev $(SLIB)wizard3.lev \
+       $(SLIB)fakewiz1.lev
+$(WIZARD1):  $(SLIB)fakewiz2.lev
+
+$(SLIB)fakewiz2.lev:  $(DAT)yendor.des $(SBIN)lev_comp
+
+MEDUSA1= $(SLIB)medusa-1.lev
+$(MEDUSA1): $(SLIB)medusa-2.lev
+
+$(SLIB)medusa-2.lev:   $(DAT)medusa.des $(SBIN)lev_comp
+
+SOKOBAN1= $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev $(SLIB)soko2-1.lev \
+       $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev $(SLIB)soko3-2.lev \
+       $(SLIB)soko4-1.lev
+$(SOKOBAN1): $(SLIB)soko4-2.lev
+
+$(SLIB)soko4-2.lev: $(DAT)sokoban.des $(SBIN)lev_comp
+
+$(ADFILES1):   $(SLIB)Arc-goal.lev
+
+$(SLIB)Arc-goal.lev:   $(DAT)Arch.des $(SBIN)lev_comp
+
+$(BDFILES1):   $(SLIB)Bar-goal.lev
+
+$(SLIB)Bar-goal.lev:   $(DAT)Barb.des $(SBIN)lev_comp
+
+$(CDFILES1):   $(SLIB)Cav-goal.lev
+
+$(SLIB)Cav-goal.lev:   $(DAT)Caveman.des $(SBIN)lev_comp
+
+$(HDFILES1):   $(SLIB)Hea-goal.lev
+
+$(SLIB)Hea-goal.lev:   $(DAT)Healer.des $(SBIN)lev_comp
+
+$(KDFILES1):   $(SLIB)Kni-goal.lev
+
+$(SLIB)Kni-goal.lev:   $(DAT)Knight.des $(SBIN)lev_comp
+
+$(MDFILES1):   $(SLIB)Mon-goal.lev
+
+$(SLIB)Mon-goal.lev:   $(DAT)Monk.des $(SBIN)lev_comp
+
+$(PDFILES1):   $(SLIB)Pri-goal.lev
+
+$(SLIB)Pri-goal.lev:   $(DAT)Priest.des $(SBIN)lev_comp
+
+$(RDFILES1):   $(SLIB)Rog-goal.lev
+
+$(SLIB)Rog-goal.lev:   $(DAT)Rogue.des $(SBIN)lev_comp
+
+$(RANFILES1):  $(SLIB)Ran-goal.lev
+
+$(SLIB)Ran-goal.lev:   $(DAT)Ranger.des $(SBIN)lev_comp
+
+$(SDFILES1):   $(SLIB)Sam-goal.lev
+
+$(SLIB)Sam-goal.lev:   $(DAT)Samurai.des $(SBIN)lev_comp
+
+$(TDFILES1):   $(SLIB)Tou-goal.lev
+
+$(SLIB)Tou-goal.lev:   $(DAT)Tourist.des $(SBIN)lev_comp
+
+$(VDFILES1):   $(SLIB)Val-goal.lev
+
+$(SLIB)Val-goal.lev:   $(DAT)Valkyrie.des $(SBIN)lev_comp
+
+$(WDFILES1):   $(SLIB)Wiz-goal.lev
+
+$(SLIB)Wiz-goal.lev:   $(DAT)Wizard.des $(SBIN)lev_comp
+
+$(SLIB)dungeon:  $(DAT)dungeon.def $(SBIN)makedefs $(SBIN)dgn_comp
+       $(SBIN)makedefs -e
+       $(SBIN)dgn_comp $(DAT)dungeon.pdf
+       copy $(DAT)dungeon $(SLIB)dungeon
+       delete $(DAT)dungeon
+
+inst-data: $(INSTDATAFILES)
+
+$(NETHACK)amii.hlp: $(AMI)amii.hlp
+       copy $(AMI)amii.hlp $@
+
+#$(NETHACK)data:  $(DAT)data
+#      copy $(DAT)data $@
+
+$(SLIB)data:  $(DAT)data.base $(I)config.h $(SBIN)makedefs
+       $(SBIN)makedefs -d
+
+#$(NETHACK)rumors:  $(DAT)rumors
+#      copy $(DAT)rumors $@
+
+$(SLIB)rumors:  $(DAT)rumors.tru $(DAT)rumors.fal $(SBIN)makedefs
+       $(SBIN)makedefs -r
+
+$(SLIB)cmdhelp:  $(DAT)cmdhelp
+       copy $(DAT)cmdhelp $@
+
+$(SLIB)help:  $(DAT)help
+       copy $(DAT)help $@
+
+$(SLIB)hh:  $(DAT)hh
+       copy $(DAT)hh $@
+
+$(NETHACK)HackWB.hlp: $(AMI)HackWB.hlp
+       copy $(AMI)HackWB.hlp $@
+
+$(SLIB)history:  $(DAT)history
+       copy $(DAT)history $@
+
+$(NETHACK)license:  $(DAT)license
+       copy $(DAT)license $@
+
+$(SLIB)opthelp:  $(DAT)opthelp
+       copy $(DAT)opthelp $@
+
+$(NETHACK)Recover.txt: $(DOC)Recover.txt
+       copy $(DOC)Recover.txt $@
+
+$(NETHACK)GuideBook.txt: $(DOC)GuideBook.txt
+       copy $(DOC)GuideBook.txt $@
+
+$(NETHACK)NetHack.txt: $(DOC)NetHack.txt
+       copy $(DOC)NetHack.txt $@
+
+$(NETHACK)Install.ami: $(AMI)Install.ami
+       copy $(AMI)Install.ami $@
+
+$(NETHACK)logfile:
+       echo to $@
+
+$(NETHACK)record:
+       echo to $@
+
+$(SLIB)wizhelp: $(DAT)wizhelp
+       copy $(DAT)wizhelp $@
+
+# Create the directories here because NetHack.cnf puts them there by default
+$(NETHACK)NetHack.cnf:  $(AMI)NetHack.cnf
+       copy $(AMI)NetHack.cnf $@
+       -makedir $(NETHACK)save
+       -makedir $(NETHACK)levels
+
+# Unpack and install fonts
+
+INSTFONTFILES=         $(NETHACK)hack.font $(NETHACK)hack $(NETHACK)hack/8
+
+inst-fonts: $(INSTFONTFILES)
+
+$(NETHACK)hack/8:  $(AMI)amifont8.uu $(NETHACK)hack
+       $(UUDEC) $(AMI)amifont8.uu
+       copy 8 $(NETHACK)hack/8
+       delete 8
+
+$(NETHACK)hack.font:  $(AMI)amifont.uu
+       $(UUDEC) $(AMI)amifont.uu
+       copy hack.font $(NETHACK)hack.font
+       delete hack.font
+
+$(NETHACK)hack:
+       -makedir $@
+
+INSTICONFILES= \
+       $(NETHACK)default.icon $(NETHACK)NetHack.info $(NETHACK)NewGame.info \
+       $(NETHACK)HackWB.info
+
+inst-icons: $(INSTICONFILES)
+
+# Unpack the icons into place
+
+$(NETHACK)default.icon:  $(AMI)dflticon.uu
+       $(UUDEC) $(AMI)dflticon.uu
+#      copy default.icon $(NETHACK)default.icon
+#      delete default.icon
+
+$(NETHACK)NetHack.info:  $(AMI)NHinfo.uu
+       $(UUDEC) $(AMI)NHinfo.uu
+#      copy NetHack.info $(NETHACK)NetHack.info
+#      delete NetHack.info
+
+$(NETHACK)NewGame.info:  $(AMI)NewGame.uu
+       $(UUDEC) $(AMI)NewGame.uu
+#      copy NewGame.info $(NETHACK)NewGame.info
+#      delete NewGame.info
+
+$(NETHACK)HackWB.info:  $(AMI)HackWB.uu
+       $(UUDEC) $(AMI)HackWB.uu
+#      copy HackWB.info $(NETHACK)HackWB.info
+#      delete HackWB.info
+
+# If DLB is defined, create the nhdat library file in the playground
+# directory.  If not, move all the data files there.
+$(NETHACK)nhdat:  $(LIBFILES)
+       list to T:nhdat.lst $(SLIB) QUICK NOHEAD FILES
+       echo  >T:make-nhdat $(SBIN)dlb cCfI $(SLIB) $(NETHACK)nhdat T:nhdat.lst
+       echo >>T:make-nhdat if not exists $(NETHACK)nhdat
+       echo >>T:make-nhdat copy $(SLIB)\#? $(NETHACK)
+       echo >>T:make-nhdat endif
+       execute T:make-nhdat
+       -delete T:make-nhdat
+
+# DO NOT DELETE THIS LINE
+
+$(O)allmain.o:  $(NHS)allmain.c $(HDEP)
+
+$(O)alloc.o:  $(NHS)alloc.c $(I)config.h
+
+$(O)apply.o:  $(NHS)apply.c $(HDEP) $(I)edog.h
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)apply.c
+
+$(O)artifact.o:  $(NHS)artifact.c $(HDEP) $(I)artifact.h $(I)artilist.h
+
+$(O)attrib.o:  $(NHS)attrib.c $(HDEP) $(I)artifact.h
+
+$(O)ball.o: $(NHS)ball.c $(HDEP)
+
+$(O)bones.o:  $(NHS)bones.c $(HDEP) $(I)lev.h
+
+$(O)botl.o:    $(NHS)botl.c $(HDEP)
+
+$(O)cmd.o:  $(NHS)cmd.c $(HDEP) $(I)func_tab.h
+
+$(O)dbridge.o:  $(NHS)dbridge.c $(HDEP)
+
+$(O)decl.o:  $(NHS)decl.c $(HDEP) $(I)quest.h
+
+$(O)detect.o: $(NHS)detect.c $(HDEP) $(I)artifact.h
+
+$(O)dig.o: $(NHS)dig.c $(HDEP) $(I)edog.h
+
+$(O)display.o:  $(NHS)display.c $(HDEP)
+
+$(O)dlb.o: $(NHS)dlb.c $(HDEP) $(I)dlb.h
+
+$(O)do.o:  $(NHS)do.c $(HDEP) $(I)lev.h
+
+$(O)do_name.o:  $(NHS)do_name.c $(HDEP)
+
+$(O)do_wear.o:  $(NHS)do_wear.c $(HDEP)
+
+$(O)dog.o:  $(NHS)dog.c $(HDEP) $(I)edog.h
+
+$(O)dogmove.o:  $(NHS)dogmove.c $(HDEP) $(I)mfndpos.h $(I)edog.h
+
+$(O)dokick.o:  $(NHS)dokick.c $(HDEP) $(I)eshk.h
+
+$(O)dothrow.o:  $(NHS)dothrow.c $(HDEP)
+
+$(O)drawing.o:  $(NHS)drawing.c $(HDEP) $(I)tcap.h
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)drawing.c
+
+$(O)dungeon.o:  $(NHS)dungeon.c $(HDEP) $(I)dgn_file.h $(I)dlb.h
+
+$(O)eat.o:  $(NHS)eat.c $(HDEP)
+
+$(O)end.o:  $(NHS)end.c $(HDEP) $(I)eshk.h $(I)dlb.h
+
+$(O)engrave.o:  $(NHS)engrave.c $(HDEP) $(I)lev.h
+
+$(O)exper.o:  $(NHS)exper.c $(HDEP)
+
+$(O)explode.o:  $(NHS)explode.c $(HDEP)
+
+$(O)extralev.o:  $(NHS)extralev.c $(HDEP)
+
+$(O)files.o:  $(NHS)files.c $(HDEP) $(I)dlb.h $(I)date.h
+
+$(O)fountain.o:  $(NHS)fountain.c $(HDEP)
+
+$(O)hack.o:  $(NHS)hack.c $(HDEP)
+
+$(O)hacklib.o:  $(NHS)hacklib.c $(HDEP)
+
+$(O)invent.o:  $(NHS)invent.c $(HDEP) $(I)artifact.h
+
+$(O)light.o:  $(NHS)light.c $(HDEP) $(I)lev.h
+
+$(O)lock.o:  $(NHS)lock.c $(HDEP)
+
+$(O)mail.o:  $(NHS)mail.c $(HDEP) $(I)mail.h
+
+$(O)makemon.o:  $(NHS)makemon.c $(HDEP) $(I)epri.h $(I)emin.h $(I)edog.h
+
+$(O)mapglyph.o:  $(NHS)mapglyph.c $(HDEP)
+
+$(O)mcastu.o:  $(NHS)mcastu.c $(HDEP)
+
+$(O)mhitm.o:  $(NHS)mhitm.c $(HDEP) $(I)artifact.h $(I)edog.h
+
+$(O)mhitu.o:  $(NHS)mhitu.c $(HDEP) $(I)artifact.h $(I)edog.h
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)mhitu.c
+
+$(O)minion.o:  $(NHS)minion.c $(HDEP) $(I)emin.h $(I)epri.h
+
+$(O)mklev.o:  $(NHS)mklev.c $(HDEP)
+
+$(O)mkmap.o:  $(NHS)mkmap.c $(HDEP) $(I)sp_lev.h
+
+$(O)mkmaze.o:  $(NHS)mkmaze.c $(HDEP) $(I)sp_lev.h $(I)lev.h
+
+$(O)mkobj.o:  $(NHS)mkobj.c $(HDEP) $(I)artifact.h $(I)prop.h
+
+$(O)mkroom.o:  $(NHS)mkroom.c $(HDEP)
+
+$(O)mon.o:  $(NHS)mon.c $(HDEP) $(I)mfndpos.h $(I)edog.h
+
+$(O)mondata.o:  $(NHS)mondata.c $(HDEP) $(I)eshk.h $(I)epri.h
+
+$(O)monmove.o:  $(NHS)monmove.c $(HDEP) $(I)mfndpos.h $(I)artifact.h
+
+$(O)monst.o:  $(NHS)monst.c $(I)config.h $(I)permonst.h $(I)monsym.h \
+               $(I)eshk.h $(I)vault.h $(I)epri.h $(I)color.h
+
+$(O)monstr.o:  $(NHS)monstr.c $(HDEP)
+
+$(O)mplayer.o: $(NHS)mplayer.c $(HDEP)
+
+$(O)mthrowu.o:  $(NHS)mthrowu.c $(HDEP)
+
+$(O)muse.o:    $(NHS)muse.c $(HDEP)
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)muse.c
+
+$(O)music.o:  $(NHS)music.c $(HDEP) #interp.c
+
+$(O)o_init.o:  $(NHS)o_init.c $(HDEP) $(I)lev.h
+
+$(O)objects.o:  $(NHS)objects.c $(I)config.h $(I)obj.h $(I)objclass.h \
+               $(I)prop.h $(I)skills.h $(I)color.h
+       $(CC) $(CFLAGS) $(INCLSPEC)$(NHS) $(OBJSPEC)$@ $(NHS)objects.c
+
+$(O)objnam.o:  $(NHS)objnam.c $(HDEP)
+
+$(O)options.o:  $(NHS)options.c $(HDEP) $(I)tcap.h $(I)config.h \
+               $(I)objclass.h $(I)flag.h
+
+$(O)pager.o:  $(NHS)pager.c $(HDEP) $(I)dlb.h
+
+$(O)pickup.o:  $(NHS)pickup.c $(HDEP)
+
+$(O)pline.o:   $(NHS)pline.c $(HDEP) $(I)epri.h
+
+$(O)polyself.o:  $(NHS)polyself.c $(HDEP)
+
+$(O)potion.o:  $(NHS)potion.c $(HDEP)
+
+$(O)pray.o:  $(NHS)pray.c $(HDEP) $(I)epri.h
+
+$(O)priest.o:  $(NHS)priest.c $(HDEP) $(I)mfndpos.h $(I)eshk.h $(I)epri.h \
+               $(I)emin.h
+
+$(O)quest.o:   $(NHS)quest.c $(HDEP) $(I)quest.h $(I)qtext.h
+
+$(O)questpgr.o: $(NHS)questpgr.c $(HDEP) $(I)qtext.h $(I)dlb.h
+
+$(O)read.o:  $(NHS)read.c $(HDEP)
+
+$(O)rect.o:    $(NHS)rect.c $(HDEP)
+
+$(O)region.o:  $(NHS)region.c $(HDEP)
+
+$(O)restore.o:  $(NHS)restore.c $(HDEP) $(I)lev.h $(I)tcap.h $(I)quest.h
+
+$(O)rnd.o:  $(NHS)rnd.c $(HDEP)
+
+$(O)role.o:    $(NHS)role.c $(HDEP)
+
+$(O)rumors.o:  $(NHS)rumors.c $(HDEP) $(I)dlb.h
+
+$(O)save.o:  $(NHS)save.c $(HDEP) $(I)lev.h $(I)quest.h
+
+$(O)shk.o:  $(NHS)shk.c $(HDEP) $(I)eshk.h
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)shk.c
+
+$(O)shknam.o:  $(NHS)shknam.c $(HDEP) $(I)eshk.h
+
+$(O)sit.o:  $(NHS)sit.c $(HDEP) $(I)artifact.h
+
+$(O)sounds.o:  $(NHS)sounds.c $(HDEP) $(I)edog.h
+
+$(O)sp_lev.o:  $(NHS)sp_lev.c $(HDEP) $(I)sp_lev.h $(I)rect.h $(I)dlb.h
+
+$(O)spell.o:  $(NHS)spell.c $(HDEP)
+
+$(O)steal.o:  $(NHS)steal.c $(HDEP)
+
+$(O)steed.o:   $(NHS)steed.c $(HDEP)
+
+$(O)teleport.o:        $(NHS)teleport.c $(HDEP)
+
+$(O)timeout.o:  $(NHS)timeout.c $(HDEP) $(I)lev.h
+
+$(O)topten.o:  $(NHS)topten.c $(HDEP) $(I)dlb.h
+
+$(O)track.o:  $(NHS)track.c $(HDEP)
+
+$(O)trap.o:  $(NHS)trap.c $(HDEP)
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)trap.c
+
+$(O)u_init.o:  $(NHS)u_init.c $(HDEP)
+
+$(O)uhitm.o:  $(NHS)uhitm.c $(HDEP)
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)uhitm.c
+
+$(O)vault.o:  $(NHS)vault.c $(HDEP) $(I)vault.h
+
+$(O)version.o:  $(NHS)version.c $(HDEP) $(I)date.h $(I)patchlevel.h
+
+$(O)vision.o:  $(NHS)vision.c $(HDEP) #$(I)vis_tab.h
+
+$(O)weapon.o:  $(NHS)weapon.c $(HDEP)
+
+$(O)were.o:  $(NHS)were.c $(HDEP)
+
+$(O)wield.o:  $(NHS)wield.c $(HDEP)
+
+$(O)windows.o:  $(NHS)windows.c $(HDEP) $(I)wintty.h
+
+$(O)wizard.o:  $(NHS)wizard.c $(HDEP) $(I)qtext.h
+
+$(O)worm.o:  $(NHS)worm.c $(HDEP) $(I)lev.h
+
+$(O)worn.o:  $(NHS)worn.c $(HDEP)
+
+$(O)write.o:  $(NHS)write.c $(HDEP)
+
+$(O)zap.o:  $(NHS)zap.c $(HDEP)
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)zap.c
+
+$(O)getline.o: $(TTY)getline.c $(HDEP) $(I)wintty.h
+
+$(O)termcap.o: $(TTY)termcap.c $(HDEP) $(I)wintty.h $(I)tcap.h
+
+$(O)topl.o:    $(TTY)topl.c $(HDEP) $(I)wintty.h $(I)tcap.h
+
+$(O)wintty.o:  $(TTY)wintty.c $(HDEP) $(I)wintty.h $(I)tcap.h \
+               $(I)patchlevel.h
+
+$(O)amitty.o:  $(AMI)amitty.c $(HDEP)
+
+$(O)amistack.o:        $(AMI)amistack.c
+       $(CC) $(CFLAGS3) $(CSYM) $(OBJSPEC)$@ $(AMI)amistack.c
+
+$(O)rip.o:     $(NHS)rip.c $(HDEP)
+
+
+$(I)config.h:  $(I)config1.h $(I)tradstdc.h $(I)global.h
+       -setdate $(I)config.h
+       -c:wait 2
+
+# onames.h handled at onames.h target, pm.h
+
+$(I)decl.h:  $(I)quest.h $(I)spell.h $(I)color.h $(I)obj.h $(I)you.h
+       -setdate $(I)decl.h
+       -c:wait 2
+
+$(I)global.h:  $(I)coord.h $(I)pcconf.h $(I)amiconf.h
+       -setdate $(I)global.h
+       -c:wait 2
+
+$(I)hack.h:  $(I)config.h $(I)trap.h $(I)decl.h $(I)dungeon.h $(I)monsym.h \
+               $(I)mkroom.h $(I)objclass.h $(I)flag.h $(I)rm.h $(I)vision.h \
+               $(I)display.h $(I)wintype.h $(I)engrave.h $(I)rect.h \
+               $(I)region.h $(I)trampoli.h
+       -setdate $(I)hack.h
+       -c:wait 2
+
+$(I)permonst.h:  $(I)monattk.h $(I)monflag.h $(I)align.h
+       -setdate $(I)permonst.h
+       -c:wait 2
+
+$(I)you.h:  $(I)align.h $(I)attrib.h $(I)monst.h $(I)youprop.h $(I)skills.h
+       -setdate $(I)you.h
+       -c:wait 2
+
+# pm.h handled at target
+
+$(I)youprop.h:  $(I)prop.h $(I)permonst.h $(I)mondata.h
+       -setdate $(I)youprop.h
+       -c:wait 2
+
+$(I)display.h: $(I)vision.h $(I)mondata.h
+       -setdate $(I)display.h
+       -c:wait 2
+
+$(I)dungeon.h: $(I)align.h
+       -setdate $(I)dungeon.h
+       -c:wait 2
+
+$(I)emin.h: $(I)dungeon.h
+       -setdate $(I)emin.h
+       -c:wait 2
+
+$(I)epri.h: $(I)dungeon.h $(I)align.h
+       -setdate $(I)epri.h
+       -c:wait 2
+
+$(I)eshk.h: $(I)dungeon.h
+       -setdate $(I)eshk.h
+       -c:wait 2
+
+$(I)engrave.h: $(I)trampoli.h $(I)rect.h
+       -setdate $(I)engrave.h
+       -c:wait 2
+
+$(I)mondata.h: $(I)align.h
+       -setdate $(I)mondata.h
+       -c:wait 2
+
+$(I)monst.h: $(I)align.h
+       -setdate $(I)monst.h
+       -c:wait 2
+
+$(I)pcconf.h: $(I)micro.h $(I)system.h
+       -setdate $(I)pcconf.h
+       -c:wait 2
+
+$(I)rm.h: $(I)align.h
+       -setdate $(I)rm.h
+       -c:wait 2
+
+$(I)vault.h: $(I)dungeon.h
+       -setdate $(I)vault.h
+       -c:wait 2
+
+#notes
+#  install keeps doing re-install because it keeps rebuilding lev_comp???
+#  fixed(?) - deleted setdate
diff --git a/sys/amiga/Makefile.ami b/sys/amiga/Makefile.ami
new file mode 100644 (file)
index 0000000..5e334a9
--- /dev/null
@@ -0,0 +1,1679 @@
+#      NetHack Makefile.
+#      SCCS Id: @(#)Makefile.ami       3.4     2002/21/02
+# Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1991,1992,1993,1996.
+# NetHack may be freely redistributed.  See license for details.
+
+###
+### INTRODUCTION
+###
+
+# This makefile is arranged for compiling for the Amiga with SAS/C 6.51 but
+# can be configured for compiling with Manx C 5 or commercial DICE with
+# simple changes.  The appropriate changes are identified by #[compiler]
+# where compiler is one of: SAS6, MANX, or DICE; the options in this
+# makefile as should be set according to the compiler being used.  (But see
+# note 3 below.)
+
+# Note: When using the Manx compiler, an alternate make utility is
+# required. The bundled Aztec make is just too damaged.
+
+# Note 2: The #SFD_xxx lines are used with mkdmake to generate a DMake-
+# compatible makefile (DMakefile) from this file.  Any line beginning with
+# #SFD_INSTEAD replaces, in DMakefile, the following line from Makefile.ami.
+# #SFD_BEGIN, #SFD_ELSE, and #SFD_END bracket multi-line sections for the two
+# makefile formats.
+# When changing this file, #SFD_INSTEAD lines will need to be inserted for
+# the following cases:
+#      - Dependencies with different numbers of filenames (both > 1) on
+#          either side.  The #SFD_INSTEAD line should immediately precede
+#          the line with the colon, and should contain a double colon "::"
+#          instead of a single colon.
+#      - Special command lists that override the default.  A line containing
+#          "#SFD_INSTEAD #none" should precede such a rule.  If the rule is
+#          more than one line long, precede it with "#SFD_BEGIN" and
+#          "#SFD_ELSE", and follow it with "#SFD_END".
+#      - Files not in the src, sys/amiga, sys/share, or win/tty directories
+#          that rely on the default ".c.o" rule.  Following the dependency
+#          should be "#SFD_INSTEAD <default>" with the filename inserted
+#          into the default rule where appropriate, then a line contianing
+#          "#none".
+# In any SFD_BEGIN/ELSE/END block added, put a '##' before every line
+# between the BEGIN and ELSE.  Any line that's really a comment needs three
+# '#'s, e.g. "### DICE comment".
+
+# Note 2A: Whenever an SFD line/block is added, the appropriate repeat count
+#          in mkdmake must be changed.  (The repeat count "0" meaning "repeat
+#          until end of file" doesn't work as advertised.)
+
+# Note 3: mkdmake will automatically substitute DICE flags, etc. for SAS
+#         where appropriate.  Since the makefile is already set up for SAS,
+#         the only people who end up having to make changes here are Manx
+#         users (or people who want to change the defaults).
+
+###
+### DIRECTORY STRUCTURE
+###
+
+NH = NH:
+SBIN = $(NH)sbin/
+SLIB = $(NH)slib/
+NETHACK = $(NH)NetHack/
+HACKEXE = $(NH)HackExe/
+AMI = $(NH)sys/amiga/
+DAT = $(NH)dat/
+DOC = $(NH)doc/
+I = $(NH)include/
+SHARE = $(NH)sys/share/
+NHS = $(NH)src/
+TTY = $(NH)win/tty/
+WSHARE  = $(NH)win/share/
+UTIL = $(NH)util/
+O = $(NH)obj/
+OO = $(NH)objo/
+#      NB: O and OO MUST be different directories
+
+###
+### INVOCATION
+###
+
+#[SAS6]
+#MAKE = smake
+#[MANX]
+#MAKE = make
+#[DICE]
+#MAKE = dmake
+
+# Startup makefile with:
+#
+#[SAS6]
+#[MANX]
+#      $(MAKE) -f $(AMI)Makefile.ami
+#      $(MAKE) -f $(AMI)Makefile.ami install
+#
+#[DICE]
+#      $(MAKE) -f $(AMI)DMakefile
+#      $(MAKE) -f $(AMI)DMakefile install
+#
+#
+# You may use following targets on $(MAKE) command lines:
+#   all                do it all (default)
+#   link       just create binary from object files
+#   obj                just create common object files
+#   obja       just create amiga object files
+#   objs       just create shared object files
+#   clean      deletes the object files
+#   spotless   deletes the object files, main binary, and more
+#
+# Note:  We do not build the Guidebook here since it needs tbl
+# (See the file sys/unix/Makefile.doc for more information)
+
+#X# Precompiled header files:
+#X#   $(HDEP) should appear in any dependency list for an object file where
+#X#   we would want to make use of the precompiled version of $(I)hack.h,
+#X#   while $(CSYM) should appear in the C compiler command line that creates
+#X#   any such object file.  (Changes made here should agree with the $(HDEP):
+#X#   target that appears later in this makefile.)
+#X#
+
+#SFD_BEGIN
+##
+###[DICE]
+###   If we were compiling with DICE and wanted to use the symbol table
+###   pre-loading feature, we would uncomment these following two lines.
+##
+##HDEP = $(I)hack.sym
+##CSYM = -H$(I)hack.sym=hack.h
+##
+#SFD_ELSE
+
+#[SAS5]
+#   If we were to use the precompiled header file feature in a newer version
+#   of SAS/C, we would comment out these following two lines.
+#   If we don't use precompiled header files, we uncomment it as well.
+
+HDEP   = $(I)hack.h $(I)pm.h $(I)onames.h
+CSYM   =
+
+#[MANX]
+#   If we were compiling with Aztec, and wanted to use the symbol table
+#   pre-loading feature, we would uncomment these following two lines.
+
+#HDEP  = Ram:hack.sym
+#CSYM  = +IRam:hack.sym
+
+#SFD_END
+
+#Pathname for uudecode program:
+UUDEC  = uudecode
+
+# Flex/Bison command assignments -- Useful only if you have flex/bison
+FLEX   = flex
+BISON  = bison
+# FBFIL and FBLIB may be used, if required by your version of flex or bison,
+# to specify additional files or libraries to be linked with
+FBFIL  =
+FBLIB  = #lib lib:compat.lib
+
+# If you're compiling this on a 1.3 system, you'll have to uncomment the
+# following (for use with the ifchange script below).  Also useful instead of
+# "protect ifchange +s"
+EXECUTE = execute
+
+# Headers we depend on
+AMDEP = $(AMI)winproto.h $(AMI)winext.h $(AMI)windefs.h $(I)winami.h
+
+# Pathname for the C compiler being used.
+
+#SFD_BEGIN
+##
+###[DICE]
+##CC   = dcc
+##ASM  = das
+##
+#SFD_ELSE
+
+#[SAS6]
+CC     = sc
+ASM    = asm
+
+#[MANX]
+#CC    = cc
+
+#SFD_END
+
+# Compilation flags for selected C Compiler:
+#   $(CFLAGS) should appear before filename arguments of $(CC) command line.
+
+#SFD_BEGIN
+##
+###[DICE]
+##CFLAGS = -c -I$(I) -mC -mD -ms -//
+##CFLAGS2 =
+##WBCFLAGS = -c -I$(I) -mC -mD -ms -//
+##WBC2FLAGS = -DCLI
+##SPLFLAGS = -DSPLIT
+##
+#SFD_ELSE
+
+#[SAS6]
+#   Note: make sure your CLI stack size is large (at least 50K) or lev_comp
+#   and makedefs may fail terribly - stack checking is disabled.
+#
+#  **** WARNING ****   GST support is not fool proof.  You must make makedefs
+#                      without a GST first so that the generated headers
+#                      that are part of the GST can be made.
+#
+#GSTSRC=$(AMI)gst.c
+#
+#GSTHEAD=$(I)hack.h $(I)pm.h $(I)trap.h $(I)onames.h \
+#      $(AMI)winami.p $(AMI)amidos.p $(AMI)amiwind.p
+#
+#GSTFILE=$(O)NetHack.gst
+# undefine this to not compile with GSTs
+#GST=gst=$(GSTFILE)
+#
+DEBUG=debug=symbol
+CPU=cpu=68000
+#OPTFLAGS=opt opttime optpeep optgo optinl optsched optcomp=10 optdep=5 optrdep=5 #optalias +OPTTIME -OPTSIZE
+CFLAGS = data=far nominc $(DEBUG) idir=$(I) $(CPU) nostkchk nover \
+       codename=nhcode dataname=nhdata strmerge $(OPTFLAGS) $(TILES) $(SAVEDS) \
+       afp $(ERRREXX) $(GST)
+# for files that are too large for the standard flags:
+CFLAGS2 = code=far strmerge $(SAVEDS)
+WBCFLAGS = ignore=217,62 data=far ansi nminc code=far idir=$(I) $(CPU) afp \
+       $(DEBUG) $(ERRREXX) define=AMIGA $(GST)
+XXX = data=far ansi nminc idir=$(I) $(CPU) afp opt optinline optinlocal \
+       optloop opttime
+WBC2FLAGS = define=CLI
+SPLFLAGS = define=SPLIT #dollarok
+#for amistack.c
+CFLAGS3        = data=near dataname=__MERGED nominc $(DEBUG) idir=$(I) $(CPU) nover nostkchk \
+       codename=nhcode strmerge $(OPTFLAGS) $(TILES) $(SAVEDS) \
+       afp $(ERRREXX) $(GST)
+
+#[MANX]
+#CFLAGS = -i$(I) -mc -md -ms -pa -ps -bs -wo -qq
+#WBCFLAGS = -mc -md -ms -pa -ps -bs -wo -qq -pp
+
+#SFD_END
+
+# Assembly flags:
+
+#SFD_BEGIN
+##
+###[DICE]
+##AFLAGS =
+##AOBJSPEC = -o
+##
+#SFD_ELSE
+
+#[SAS6]
+AFLAGS = #what to put here?
+AOBJSPEC = -o
+
+#SFD_END
+
+# Components of various link command lines:
+#   $(LINK) should be the pathname of the linker being used (with any options
+#   that should appear at the beginning of the command line).  The name of the
+#   output file should appear immediately after $(LNSPEC).  $(LIN) should
+#   appear before the list of object files in each link command.  $(LLINK)
+#   should appear as the list of object files in the link command line that
+#   creates the NetHack executable.  $(LLIB) should appear at the end of each
+#   link command line.
+
+# Note: amiga.lib added due to missing prototypes/pragmas.
+# Should be deleted when this is resolved.
+
+#SFD_BEGIN
+##
+###[DICE]
+### If you have flex/bison libraries, use the second definition of FLLIB
+### instead of the first.
+##
+##LINK  = dcc -mD
+##LIN   =
+##LLINK         = @$(AMI)ami.lnk
+##LLIB  =
+##FLLIB         =
+###FLLIB        = -l$(FBLIB)
+##OBJSPEC = -o
+##PNSPEC       = -o
+##LNSPEC = -o
+##CCLINK       = dcc
+##CLFLAGS = -I$(I) -mC -mD -ms -//
+##INCLSPEC = -I
+##DEFSPEC = -D
+##IGNSPEC = -j
+##
+#SFD_ELSE
+
+#[SAS6]
+
+LINK   = slink noicons verbose maxhunk 262144 stripdebug
+LIN    = from lib:catch.o
+LLINK  = with $(AMI)ami.lnk
+LLIB   = lib lib:scnb.lib BATCH #lib lib:amiga.lib BATCH #scnb.lib or sc.lib
+FLLIB  = $(FBLIB) lib Lib:sc.lib BATCH
+OBJSPEC = objname=
+PNSPEC = noicons to #pname=
+LNSPEC = to
+CCLINK =  sc link
+INCLSPEC = idir=
+DEFSPEC = define=
+IGNSPEC = ignore=
+COMPACT_HEADERS=$(GSTFILE)
+
+#[MANX]
+
+#LINK  = ln -g +q +ss -o
+#LIN   =
+#LLINK = -f $(AMI)ami.lnk
+#LLIB  = -lcl16
+#FLLIB  = -lcl16
+#OBJSPEC = -o
+#PNSPEC = -o
+#LNSPEC = -o
+#CCLINK = cc
+#INCLSPEC = -i
+#DEFSPEC = -d
+#IGNSPEC = -j
+
+#SFD_END
+
+###
+### FILE LISTS
+###
+
+# A more reasonable random number generator (recommended for the Amiga):
+
+RANDOBJ        = $(O)random.o
+
+#SFD_INSTEAD #none
+.PRECIOUS:  $(I)config.h $(I)decl.h $(I)hack.h $(I)permonst.h $(I)you.h
+
+# Almost nothing below this line should have to be changed.
+# (Exceptions are marked by [SAS6], [MANX], etc.)
+#
+# Other things that have to be reconfigured are in config.h,
+# (amiconf.h, pcconf.h), and possibly system.h, tradstdc.h.
+
+# Object files for makedefs:
+
+MAKEOBJS = \
+       $(OO)makedefs.o $(O)monst.o $(O)objects.o
+
+# Object files for special levels compiler:
+
+SPLEVOBJS = \
+       $(OO)lev_yacc.o $(OO)lev_lex.o  $(OO)lev_main.o \
+       $(O)decl.o      $(O)drawing.o   $(O)monst.o \
+       $(O)objects.o   $(OO)panic.o
+
+# Object files for dungeon compiler
+
+DGNCOMPOBJS = \
+       $(OO)dgn_yacc.o $(OO)dgn_lex.o  $(OO)dgn_main.o $(O)alloc.o $(OO)panic.o
+
+# Object files for NetHack:
+
+COMMOBJ = \
+       $(O)allmain.o   $(O)alloc.o     $(O)apply.o     $(O)artifact.o  \
+       $(O)attrib.o    $(O)ball.o      $(O)bones.o     $(O)botl.o      \
+       $(O)cmd.o       $(O)dbridge.o   $(O)decl.o      $(O)detect.o    \
+       $(O)dig.o       $(O)display.o   $(O)dlb.o       $(O)do.o        \
+       $(O)do_name.o   $(O)do_wear.o   $(O)dog.o       $(O)dogmove.o   \
+       $(O)dokick.o    $(O)dothrow.o   $(O)drawing.o   $(O)dungeon.o   \
+       $(O)eat.o       $(O)end.o       $(O)engrave.o   $(O)exper.o     \
+       $(O)explode.o   $(O)extralev.o  $(O)files.o     $(O)fountain.o  \
+       $(O)hack.o      $(O)hacklib.o   $(O)invent.o    $(O)light.o     \
+       $(O)lock.o      $(O)mail.o      $(O)makemon.o   $(O)mapglyph.o  \
+       $(O)mcastu.o    $(O)mhitm.o     $(O)mhitu.o     $(O)minion.o    \
+       $(O)mklev.o     $(O)mkmap.o     $(O)mkmaze.o    $(O)mkobj.o     \
+       $(O)mkroom.o    $(O)mon.o       $(O)mondata.o   $(O)monmove.o   \
+       $(O)monst.o     $(O)mplayer.o   $(O)mthrowu.o   $(O)muse.o      \
+       $(O)music.o     $(O)o_init.o    $(O)objects.o   $(O)objnam.o    \
+       $(O)options.o   $(O)pager.o     $(O)pickup.o    $(O)pline.o     \
+       $(O)polyself.o  $(O)potion.o    $(O)pray.o      $(O)priest.o    \
+       $(O)quest.o     $(O)questpgr.o  $(O)read.o      $(O)rect.o      \
+       $(O)region.o    $(O)restore.o   $(O)rnd.o       $(O)role.o      \
+       $(O)rumors.o    $(O)save.o      $(O)shk.o       $(O)shknam.o    \
+       $(O)sit.o       $(O)sounds.o    $(O)sp_lev.o    $(O)spell.o     \
+       $(O)steal.o     $(O)steed.o     $(O)teleport.o  $(O)timeout.o   \
+       $(O)topten.o    $(O)track.o     $(O)trap.o      $(O)u_init.o    \
+       $(O)uhitm.o     $(O)vault.o     $(O)version.o   $(O)vision.o    \
+       $(O)weapon.o    $(O)were.o      $(O)wield.o     $(O)windows.o   \
+       $(O)wizard.o    $(O)worm.o      $(O)worn.o      $(O)write.o     \
+       $(O)zap.o
+
+MAKEDEFOBJ = \
+       $(O)monstr.o
+
+AMIGAOBJ = \
+       $(O)amidos.o    $(O)amirip.o    $(O)amisnd.o    $(O)amistack.o \
+       $(O)amiwind.o   $(O)winami.o    $(O)winchar.o   $(O)winfuncs.o  \
+       $(O)winkey.o    $(O)winmenu.o   $(O)winreq.o    $(O)winstr.o
+
+# Objects from assembly sources (because DMake can't handle default rules)
+AMIGAOBJ2 = \
+#      $(O)dispmap.o
+
+SHAREOBJ = \
+       $(O)pcmain.o    $(RANDOBJ)
+
+TTYOBJ = \
+       $(O)getline.o $(O)termcap.o $(O)topl.o $(O)wintty.o $(O)amitty.o \
+       $(O)rip.o
+
+# Yuck yuck yuck.  Have to tell DMake where these are, since they're not
+# all in the same place.
+TTYSRC = \
+       $(TTY)getline.c $(TTY)termcap.c $(TTY)topl.c $(TTY)wintty.c \
+       $(AMI)amitty.c $(NHS)rip.c
+
+# All the object files for NetHack:
+
+HOBJ = $(COMMOBJ) $(AMIGAOBJ) $(AMIGAOBJ2) $(SHAREOBJ) $(MAKEDEFOBJ) $(TTYOBJ)
+
+###
+### DATA FILES
+###
+
+# quest files
+ADFILES1= $(SLIB)Arc-fila.lev $(SLIB)Arc-filb.lev $(SLIB)Arc-loca.lev \
+       $(SLIB)Arc-strt.lev
+ADFILES= $(SLIB)Arc-goal.lev $(ADFILES1)
+
+BDFILES1= $(SLIB)Bar-fila.lev $(SLIB)Bar-filb.lev $(SLIB)Bar-loca.lev \
+       $(SLIB)Bar-strt.lev
+BDFILES= $(SLIB)Bar-goal.lev $(BDFILES1)
+
+CDFILES1= $(SLIB)Cav-fila.lev $(SLIB)Cav-filb.lev $(SLIB)Cav-loca.lev \
+       $(SLIB)Cav-strt.lev
+CDFILES= $(SLIB)Cav-goal.lev $(CDFILES1)
+
+HDFILES1= $(SLIB)Hea-fila.lev $(SLIB)Hea-filb.lev $(SLIB)Hea-loca.lev \
+       $(SLIB)Hea-strt.lev
+HDFILES= $(SLIB)Hea-goal.lev $(HDFILES1)
+
+KDFILES1= $(SLIB)Kni-fila.lev $(SLIB)Kni-filb.lev $(SLIB)Kni-loca.lev \
+       $(SLIB)Kni-strt.lev
+KDFILES= $(SLIB)Kni-goal.lev $(KDFILES1)
+
+MDFILES1= $(SLIB)Mon-fila.lev $(SLIB)Mon-filb.lev $(SLIB)Mon-loca.lev \
+       $(SLIB)Mon-strt.lev
+MDFILES= $(SLIB)Mon-goal.lev $(MDFILES1)
+
+PDFILES1= $(SLIB)Pri-fila.lev $(SLIB)Pri-filb.lev $(SLIB)Pri-loca.lev \
+       $(SLIB)Pri-strt.lev
+PDFILES= $(SLIB)Pri-goal.lev $(PDFILES1)
+
+RDFILES1= $(SLIB)Rog-fila.lev $(SLIB)Rog-filb.lev $(SLIB)Rog-loca.lev \
+       $(SLIB)Rog-strt.lev
+RDFILES= $(SLIB)Rog-goal.lev $(RDFILES1)
+
+RANFILES1= $(SLIB)Ran-fila.lev $(SLIB)Ran-filb.lev $(SLIB)Ran-loca.lev \
+       $(SLIB)Ran-strt.lev
+RANFILES= $(SLIB)Ran-goal.lev $(RANFILES1)
+
+SDFILES1= $(SLIB)Sam-fila.lev $(SLIB)Sam-filb.lev $(SLIB)Sam-loca.lev \
+       $(SLIB)Sam-strt.lev
+SDFILES= $(SLIB)Sam-goal.lev $(SDFILES1)
+
+TDFILES1= $(SLIB)Tou-fila.lev $(SLIB)Tou-filb.lev $(SLIB)Tou-loca.lev \
+       $(SLIB)Tou-strt.lev
+TDFILES= $(SLIB)Tou-goal.lev $(TDFILES1)
+
+VDFILES1= $(SLIB)Val-fila.lev $(SLIB)Val-filb.lev $(SLIB)Val-loca.lev \
+       $(SLIB)Val-strt.lev
+VDFILES= $(SLIB)Val-goal.lev $(VDFILES1)
+
+WDFILES1= $(SLIB)Wiz-fila.lev $(SLIB)Wiz-filb.lev $(SLIB)Wiz-loca.lev \
+       $(SLIB)Wiz-strt.lev
+WDFILES= $(SLIB)Wiz-goal.lev $(WDFILES1)
+
+XDFILES=       $(ADFILES) $(BDFILES) $(CDFILES) $(HDFILES) $(KDFILES) \
+               $(MDFILES) $(PDFILES) $(RDFILES) $(RANFILES) $(SDFILES) $(TDFILES) \
+               $(VDFILES) $(WDFILES)
+
+SOUNDFILES= \
+       $(SBIN)cvtsnd \
+       $(SLIB)sounds \
+       $(SLIB)sounds/Bell $(SLIB)sounds/Bugle \
+       $(SLIB)sounds/Drum_Of_Earthquake \
+       $(SLIB)sounds/Fire_Horn $(SLIB)sounds/Frost_Horn \
+       $(SLIB)sounds/Leather_Drum $(SLIB)sounds/Magic_Flute \
+       $(SLIB)sounds/Magic_Harp $(SLIB)sounds/Tooled_Horn \
+       $(SLIB)sounds/Wooden_Flute $(SLIB)sounds/Wooden_Harp
+
+TILEFILES= \
+       $(SBIN)txt2iff \
+       $(NETHACK)tiles \
+       $(NETHACK)tiles/objects.iff \
+       $(NETHACK)tiles/monsters.iff \
+       $(NETHACK)tiles/other.iff
+
+INSTDUNGEONFILES1= \
+       $(SLIB)air.lev          $(SLIB)asmodeus.lev     $(SLIB)astral.lev \
+       $(SLIB)baalz.lev        $(SLIB)bigrm-1.lev      $(SLIB)bigrm-2.lev \
+       $(SLIB)bigrm-3.lev      $(SLIB)bigrm-4.lev      $(SLIB)bigrm-5.lev \
+       $(SLIB)castle.lev       $(SLIB)dungeon          $(SLIB)earth.lev \
+       $(SLIB)fakewiz1.lev     $(SLIB)fakewiz2.lev     $(SLIB)fire.lev \
+       $(SLIB)juiblex.lev      $(SLIB)knox.lev         $(SLIB)medusa-1.lev \
+       $(SLIB)medusa-2.lev     $(SLIB)minend-1.lev     $(SLIB)minend-2.lev \
+       $(SLIB)minetn-1.lev     $(SLIB)minetn-2.lev     $(SLIB)minefill.lev \
+       $(SLIB)options          $(SLIB)oracle.lev       $(SLIB)orcus.lev \
+       $(SLIB)sanctum.lev      $(SLIB)soko1-1.lev      $(SLIB)soko1-2.lev \
+       $(SLIB)soko2-1.lev      $(SLIB)soko2-2.lev      $(SLIB)soko3-1.lev \
+       $(SLIB)soko3-2.lev      $(SLIB)soko4-1.lev      $(SLIB)soko4-2.lev \
+       $(SLIB)tower1.lev       $(SLIB)tower2.lev       $(SLIB)tower3.lev \
+       $(SLIB)valley.lev       $(SLIB)water.lev        $(SLIB)wizard1.lev \
+       $(SLIB)wizard2.lev      $(SLIB)wizard3.lev \
+       $(XDFILES)
+
+INSTDUNGEONFILES= $(NETHACK)NetHack.cnf $(INSTDUNGEONFILES1)
+
+
+INSTDATAFILES= \
+       $(NETHACK)license       $(NETHACK)logfile       $(NETHACK)record \
+       $(NETHACK)tomb.iff      $(NETHACK)amii.hlp      $(NETHACK)Recover.txt \
+       $(NETHACK)GuideBook.txt $(NETHACK)NetHack.txt   $(NETHACK)Install.ami
+
+LIBFILES= \
+       $(INSTDUNGEONFILES1) \
+       $(SLIB)cmdhelp          $(SLIB)data             $(SLIB)dungeon \
+       $(SLIB)help             $(SLIB)hh               $(SLIB)history \
+       $(SLIB)opthelp          $(SLIB)oracles          $(SLIB)rumors \
+       $(SLIB)quest.dat        $(SLIB)wizhelp
+
+###
+### Getting down to business:
+###
+
+#SFD_INSTEAD all:  $(SBIN)lev_comp $(SBIN)dgn_comp $(SBIN)NetHack \
+all:  $(COMPACT_HEADERS) $(SBIN)lev_comp $(SBIN)dgn_comp $(SBIN)NetHack \
+       $(SBIN)dlb $(NETHACK)recover
+
+install: all inst-data inst-dungeon inst-fonts inst-sounds inst-tiles \
+       $(NETHACK)nhdat $(NETHACK)NetHack
+
+$(SBIN)NetHack:  $(HOBJ) $(AMI)ami.lnk
+       $(LINK) $(LNSPEC) $(SBIN)NetHack $(LIN) $(LLINK) $(LLIB)
+
+$(NETHACK)NetHack: $(SBIN)NetHack
+       copy $(SBIN)NetHack $(NETHACK)NetHack
+
+link:
+       $(LINK) $(LNSPEC) $(SBIN)NetHack $(LIN) $(LLINK) $(LLIB)
+
+$(AMI)ami.lnk: $(AMI)Makefile.ami
+       list to $(AMI)ami.lnk lformat="$(O)%s" $(O)\#?.o QUICK NOHEAD
+
+## dlb support
+$(OO)dlb_main.o:       $(UTIL)dlb_main.c $(HDEP) $(I)dlb.h $(I)date.h
+       $(CC) $(CFLAGS) $(OBJSPEC)$(OO)dlb_main.o $(UTIL)dlb_main.c
+
+$(SBIN)dlb:    $(OO)dlb_main.o $(O)dlb.o $(O)alloc.o $(OO)panic.o
+       $(LINK) $(PNSPEC) $(SBIN)dlb $(LIN) $(OO)dlb_main.o $(O)dlb.o \
+         $(O)alloc.o $(OO)panic.o $(LLIB)
+
+obj:  $(HOBJ)
+
+obja:  $(AMIGAOBJ)
+
+objs:  $(SHAREOBJ)
+
+
+#SFD_BEGIN
+#SFD_ELSE
+SUFFIXES = .lev .des
+.des.lev:
+       $(SBIN)lev_comp $<
+#SFD_END
+
+
+# The default method for creating object files:
+
+#SFD_BEGIN
+##
+###[DICE]
+##
+##$(COMMOBJ): $(COMMOBJ:"$(O)*.o":"$(NHS)%1.c")
+##     $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)%(left) %(right)
+##
+##$(AMIGAOBJ): $(AMIGAOBJ:"$(O)*.o":"$(AMI)%1.c")
+##     $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)%(left) %(right)
+##
+##$(SHAREOBJ): $(SHAREOBJ:"$(O)*.o":"$(SHARE)%1.c")
+##     $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)%(left) %(right)
+##
+##$(TTYOBJ): $(TTYSRC)
+##     $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)%(left) %(right)
+##
+#SFD_ELSE
+
+#[SAS6]
+
+.c.o:
+       $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)$@ $<
+
+#SFD_END
+
+
+clean:
+       -delete $(O)\#?.o $(OO)\#?.o
+
+spotless:  clean
+       -delete $(SBIN)NetHack $(SBIN)lev_comp $(SBIN)makedefs $(SBIN)dgn_comp
+       -delete $(SBIN)cvtsnd $(SBIN)dlb $(SBIN)txt2iff $(SBIN)splitter
+       -delete $(SBIN)tilemap
+       -delete $(SLIB)data $(SLIB)rumors
+       -delete $(SLIB)\#?.lev
+       -delete $(SLIB)dungeon
+       -delete $(SLIB)cmdhelp $(SLIB)help $(SLIB)hh $(SLIB)history
+       -delete $(SLIB)opthelp $(SLIB)options $(SLIB)oracles
+       -delete $(SLIB)quest.dat $(SLIB)wizhelp
+#      -delete $(SLIB)earth.lev $(SLIB)air.lev $(SLIB)fire.lev
+#      -delete $(SLIB)water.lev $(SLIB)astral.lev
+#      -delete $(SLIB)tower1.lev $(SLIB)tower2.lev $(SLIB)tower3.lev
+#      -delete $(SLIB)fakewiz1.lev $(SLIB)fakewiz2.lev
+#      -delete $(SLIB)medusa-1.lev $(SLIB)medusa-2.lev
+#      -delete $(SLIB)oracle.lev $(SLIB)wizard1.lev $(SLIB)wizard2.lev
+#      -delete $(SLIB)wizard3.lev $(DAT)dungeon.pdf $(SLIB)valley.lev
+#      -delete $(SLIB)minefill.lev
+#      -delete $(SLIB)minetn-1 $(SLIB)minetn-2 $(SLIB)minend-1 $(SLIB)minend-2
+#      -delete $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev $(SLIB)soko2-1.lev
+#      -delete $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev $(SLIB)soko3-2.lev
+#      -delete $(SLIB)soko4-1.lev $(SLIB)soko4-2.lev
+#      -delete $(ADFILES)
+#      -delete $(BDFILES)
+#      -delete $(CDFILES)
+#      -delete $(HDFILES)
+#      -delete $(KDFILES)
+#      -delete $(MDFILES)
+#      -delete $(PDFILES)
+#      -delete $(RDFILES)
+#      -delete $(RANFILES)
+#      -delete $(SDFILES)
+#      -delete $(TDFILES)
+#      -delete $(VDFILES)
+#      -delete $(WDFILES)
+       -delete $(I)onames.h $(I)pm.h $(I)date.h
+       -delete $(NHS)tile.c $(NHS)monstr.c
+       -delete $(I)tile.h 
+#      -echo to $(I)onames.h "" noline
+#      -wait 2
+#      -echo to $(I)pm.h "" noline
+#      -wait 2
+#      -setdate $(UTIL)makedefs.c
+#      -wait 2
+
+# Creating precompiled version of $(I)hack.h to save disk I/O.
+
+#SFD_BEGIN
+##
+###[DICE]
+###   If we were compiling with DICE and wanted to use the symbol table
+###   pre-loading feature, we would technically not need a rule to make the
+###   precompiled header file, because DCC handles this automatically;
+###   however, we must delete the precompiled header file if any of the
+###   includes change, and we need to create it manually because the
+###   sys/amiga sources, compiled first, define things differently than the
+###   main sources want them.
+##
+##$(HDEP):  $(I)hack.h $(I)pm.h $(I)onames.h
+##     -delete $(I)hack.sym
+##     echo to Ram:hackincl.c "#include <hack.h>"
+##     $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)Ram:hackincl.o Ram:hackincl.c
+##     -delete Ram:hackincl.c Ram:hackincl.o
+##
+#SFD_ELSE
+
+#X#[SAS5]
+#X#   If we were to use the precompiled header file feature of SAS/C, we
+#X#   would uncomment the following lines.  (Also see defines for HDEP and
+#X#   CSYM near the beginning of this file, as these should be appropriately
+#X#   defined.)
+
+#X#$(HDEP):  $(I)hack.h $(SBIN)makedefs
+#X#    echo to Ram:hackincl.c "#include <$(I)hack.h>"
+#X#    $(CC) $(CFLAGS) -ph $(OBJSPEC)$@ Ram:hackincl.c
+#X#    -delete Ram:hackincl.c
+
+#[MANX]
+#   If we were compiling with Aztec, and wanted to use the symbol table
+#   pre-loading feature, we would uncomment these following two lines.
+
+#$(HDEP):  $(I)hack.h $(SBIN)makedefs
+#      $(CC) $(CFLAGS) -a $(OBJSPEC)Ram:hack.asm +h$@ $(I)hack.h
+#      -delete Ram:hack.asm
+
+#SFD_END
+
+#
+#      Please note:    The dependency lines for the modules here are
+#                      deliberately incorrect.  Including "hack.h" in
+#                      the dependency list would cause a dependency
+#                      loop.
+#
+
+$(SBIN)makedefs:  $(MAKEOBJS)
+       $(LINK) $(LNSPEC) $(SBIN)makedefs $(LIN) $(MAKEOBJS) $(LLIB)
+
+$(OO)makedefs.o:  $(UTIL)makedefs.c $(I)config.h $(I)permonst.h $(I)monsym.h \
+               $(I)objclass.h  $(I)patchlevel.h $(I)qtext.h $(I)artilist.h
+       $(CC) $(DEFSPEC)MAKEDEFS_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)makedefs.c
+
+$(SBIN)lev_comp:  $(SPLEVOBJS)
+       $(LINK) $(LNSPEC) $(SBIN)lev_comp $(LIN) $(SPLEVOBJS) $(FBFIL) $(FLLIB)
+
+$(SBIN)dgn_comp:  $(DGNCOMPOBJS)
+       $(LINK) $(LNSPEC) $(SBIN)dgn_comp $(LIN) $(DGNCOMPOBJS) $(FBFIL) $(FLLIB)
+
+$(OO)lev_yacc.o:  $(UTIL)lev_yacc.c $(HDEP) $(I)sp_lev.h $(I)pm.h $(I)onames.h
+#      setdate $(UTIL)lev_yacc.c
+       $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)PREFIX="NH:slib/" $(CFLAGS) \
+               $(DEFSPEC)alloca=malloc $(OBJSPEC)$@ $(UTIL)lev_yacc.c
+
+$(OO)lev_lex.o: $(UTIL)lev_lex.c $(HDEP) $(I)lev_comp.h $(I)sp_lev.h
+       $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)lev_lex.c
+
+$(OO)lev_main.o:  $(UTIL)lev_main.c $(HDEP) $(I)pm.h $(I)onames.h $(I)date.h
+       $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \
+               $(UTIL)lev_main.c
+
+$(OO)dgn_yacc.o:  $(UTIL)dgn_yacc.c $(HDEP) $(I)dgn_file.h $(I)patchlevel.h
+       $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(DEFSPEC)alloca=malloc \
+               $(OBJSPEC)$@ $(UTIL)dgn_yacc.c
+
+$(OO)dgn_lex.o: $(UTIL)dgn_lex.c $(I)config.h $(I)dgn_comp.h $(I)dgn_file.h
+       $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)dgn_lex.c
+
+$(OO)dgn_main.o: $(UTIL)dgn_main.c $(I)config.h $(I)date.h
+       $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \
+               $(UTIL)dgn_main.c
+
+$(OO)panic.o: $(UTIL)panic.c $(HDEP)
+#SFD_INSTEAD   $(CC) $(CFLAGS) $(OBJSPEC)%(left) $(UTIL)panic.c
+#none
+
+$(OO)recover.o: $(UTIL)recover.c $(I)config.h $(I)date.h
+       $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \
+               $(UTIL)recover.c
+
+$(NETHACK)recover: $(OO)recover.o
+       $(LINK) $(LNSPEC) $(NETHACK)recover $(LIN) $(OO)recover.o $(LLIB)
+
+# [OPTION] -- If you have flex/bison, leave these uncommented.  Otherwise,
+# comment them out and be careful! (You're not guaranteed to have the most
+# up to date *_comp.c, *_comp.h and *_lex.c)
+
+$(I)lev_comp.h: $(UTIL)lev_yacc.c $(I)patchlevel.h
+
+$(UTIL)lev_yacc.c:  $(UTIL)lev_comp.y $(I)patchlevel.h
+       $(BISON) -d $(UTIL)lev_comp.y
+#      copy y.tab.c $(UTIL)lev_yacc.c
+#      copy y.tab.h $(I)lev_comp.h
+       copy $(UTIL)lev_comp.tab.c $(UTIL)lev_yacc.c
+       copy $(UTIL)lev_comp.tab.h $(I)lev_comp.h
+#      delete y.tab.c
+#      delete y.tab.h
+       delete $(UTIL)lev_comp.tab.c
+       delete $(UTIL)lev_comp.tab.h
+
+$(UTIL)lev_lex.c:  $(UTIL)lev_comp.l $(I)patchlevel.h
+       $(FLEX) $(UTIL)lev_comp.l
+       copy lex.yy.c $(UTIL)lev_lex.c
+       delete lex.yy.c
+
+$(I)dgn_comp.h: $(UTIL)dgn_yacc.c $(I)patchlevel.h
+
+$(UTIL)dgn_yacc.c:  $(UTIL)dgn_comp.y $(I)patchlevel.h
+       $(BISON) -d $(UTIL)dgn_comp.y
+#      copy y.tab.c $(UTIL)dgn_yacc.c
+#      copy y.tab.h $(I)dgn_comp.h
+       copy $(UTIL)dgn_comp.tab.c $(UTIL)dgn_yacc.c
+       copy $(UTIL)dgn_comp.tab.h $(I)dgn_comp.h
+#      delete y.tab.c
+#      delete y.tab.h
+       delete $(UTIL)dgn_comp.tab.c
+       delete $(UTIL)dgn_comp.tab.h
+
+$(UTIL)dgn_lex.c:  $(UTIL)dgn_comp.l $(I)patchlevel.h
+       $(FLEX) $(UTIL)dgn_comp.l
+       copy lex.yy.c $(UTIL)dgn_lex.c
+       delete lex.yy.c
+
+#
+#      The following include files depend on makedefs to be created.
+#      As a result, they are not defined in HACKINCL, instead, their
+#      dependencies are explicitly outlined here.
+#
+
+#
+#      date.h should be remade any time any of the source or include code
+#      is modified.  Unfortunately, this would make the contents of this
+#      file far more complex.  Since "hack.h" depends on most of the include
+#      files, we kludge around this by making date.h dependent on hack.h,
+#      even though it doesn't include this file.
+#
+
+#SFD_INSTEAD $(I)date.h $(DAT)options::  $(HDEP) $(SBIN)makedefs $(AMIGAOBJ)
+$(I)date.h $(DAT)options:  $(HDEP) $(SBIN)makedefs $(AMIGAOBJ) $(I)patchlevel.h
+       $(SBIN)makedefs -v
+       $(EXECUTE) $(AMI)ifchange MOVE $(I)t.date.h $(I)date.h
+       -wait 2
+
+$(I)onames.h:  $(SBIN)makedefs
+       $(SBIN)makedefs -o
+       $(EXECUTE) $(AMI)ifchange TOUCH $(I)t.onames.h $(I)onames.h $(I)decl.h
+       $(EXECUTE) $(AMI)ifchange MOVE $(I)t.onames.h $(I)onames.h
+       -wait 2
+
+$(I)pm.h:  $(SBIN)makedefs
+       $(SBIN)makedefs -p
+       $(EXECUTE) $(AMI)ifchange TOUCH $(I)t.pm.h $(I)pm.h $(I)decl.h $(I)youprop.h
+       $(EXECUTE) $(AMI)ifchange MOVE $(I)t.pm.h $(I)pm.h
+       -wait 2
+
+$(SLIB)quest.dat:      $(DAT)quest.txt $(SBIN)makedefs
+       $(SBIN)makedefs -q
+
+$(NHS)monstr.c:  $(HDEP) $(SBIN)makedefs
+       $(SBIN)makedefs -m
+       -wait 2
+
+$(SLIB)oracles:        $(DAT)oracles.txt $(SBIN)makedefs
+       $(SBIN)makedefs -h
+       -wait 2
+
+#
+#      The following programs vary depending on what OS you are using.
+#      As a result, they are not defined in HACKSRC and their dependencies
+#      are explicitly outlined here.
+#
+
+$(O)amidos.o:  $(AMI)amidos.c $(HDEP)
+
+$(O)amirip.o:  $(AMI)amirip.c $(HDEP)
+
+$(O)aglue.o:  $(AMI)aglue.a
+       $(ASM) $(AFLAGS) $(AOBJSPEC)$(O)aglue.o $(AMI)aglue.a
+
+$(O)amisnd.o:  $(AMI)amisnd.c $(HDEP)
+
+$(O)winchar.o: $(AMI)winchar.c $(NHS)tile.c $(HDEP)
+
+$(NHS)tile.c:  $(WSHARE)tilemap.c
+#SFD_INSTEAD   $(CCLINK) $(CLFLAGS) $(PNSPEC) $(SBIN)tilemap $(WSHARE)tilemap.c
+       $(CCLINK) $(CFLAGS) $(PNSPEC) $(SBIN)tilemap $(WSHARE)tilemap.c
+       $(SBIN)tilemap
+
+$(O)winstr.o:  $(AMI)winstr.c $(HDEP) $(AMDEP)
+
+$(O)winreq.o:  $(AMI)winreq.c $(HDEP) $(AMDEP) $(AMI)colorwin.c $(AMI)clipwin.c
+
+$(O)winfuncs.o:        $(AMI)winfuncs.c $(HDEP) $(AMDEP) $(I)patchlevel.h
+
+$(O)winkey.o:  $(AMI)winkey.c $(HDEP) $(AMDEP)
+
+$(O)winmenu.o: $(AMI)winmenu.c $(HDEP) $(AMDEP)
+
+$(O)winami.o:  $(AMI)winami.c $(HDEP) $(AMDEP) #$(AMI)char.c $(AMI)randwin.c
+
+#$(O)amilib.o: $(AMI)amilib.c $(HDEP) $(AMDEP)
+
+$(O)amiwind.o:  $(AMI)amiwind.c $(AMI)amimenu.c $(HDEP) $(AMDEP)
+
+$(O)amiwbench.o:  $(AMI)amiwbench.c $(HDEP)
+
+$(O)random.o:  $(SHARE)random.c
+
+$(O)pcmain.o:  $(SHARE)pcmain.c $(HDEP) $(I)dlb.h
+
+$(O)dispmap.o: $(AMI)dispmap.s
+       $(ASM) $(AFLAGS) $(AOBJSPEC)$@ $<
+
+# Stuff to build the front ends
+$(NETHACK)HackWB: $(OO)wb.o $(OO)wbx.o $(OO)loader.o $(OO)multi.o
+       $(LINK) $(LNSPEC) $(NETHACK)HackWB $(LIN) $(OO)wb.o $(OO)wbx.o \
+               $(OO)loader.o $(OO)multi.o $(LLIB)
+
+$(NETHACK)HackCli: $(OO)cli.o $(OO)loader.o $(OO)multi.o
+       $(LINK) $(LNSPEC) $(NETHACK)HackCli $(LIN) $(OO)cli.o $(OO)loader.o \
+               $(OO)multi.o $(LLIB)
+
+# This needs to exist to eliminate the HackWB startup message
+#SFD_INSTEAD $(NETHACK)WBDefaults.def: $(NETHACK)WBDefaults.def
+$(NETHACK)WBDefaults.def:
+       echo to $(NETHACK)WBDefaults.def
+
+WBH    = $(AMI)wbdefs.h $(AMI)wbstruct.h $(AMI)wbprotos.h
+ASP    = $(AMI)splitter
+$(OO)wb.o: $(WBH) $(AMI)wb.c $(AMI)wbwin.c $(AMI)wbdata.c $(AMI)wbgads.c \
+               $(I)patchlevel.h
+       $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)wb.o $(AMI)wb.c
+
+$(OO)wbx.o: $(WBH) $(AMI)wbcli.c $(AMI)wbwin.c $(AMI)wbdata.c \
+               $(I)patchlevel.h $(I)date.h
+       $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)wbx.o $(AMI)wbcli.c
+
+$(OO)loader.o: $(ASP)/loader.c $(ASP)/split.h $(ASP)/amiout.h $(ASP)/multi.h
+       $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)loader.o $(ASP)/loader.c
+
+$(OO)multi.o: $(ASP)/multi.c $(ASP)/multi.h
+       $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)multi.o $(ASP)/multi.c
+
+$(OO)cli.o: $(WBH) $(AMI)wbcli.c $(I)patchlevel.h $(I)date.h
+       $(CC) $(WBCFLAGS) $(WBC2FLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)cli.o \
+               $(AMI)wbcli.c
+
+####
+# splitter support
+$(SBIN)splitter:       $(OO)splitter.o $(OO)arg.o
+       $(LINK) $(LNSPEC) $(SBIN)splitter $(LIN) $(OO)splitter.o $(OO)arg.o \
+               $(LLIB)
+
+$(NETHACK)NetHack.dir: $(SBIN)splitter $(SBIN)NetHack
+       $(SBIN)splitter $(SBIN)NetHack
+
+$(OO)splitter.o:       $(ASP)/splitter.c $(ASP)/split.h $(ASP)/amiout.h $(ASP)/arg.h
+       $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)splitter.o \
+               $(ASP)/splitter.c
+
+$(OO)arg.o:    $(ASP)/arg.c $(ASP)/arg.h
+       $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)arg.o $(ASP)/arg.c 
+
+# Create/copy other stuff into NetHack: directory:
+
+$(NETHACK)tomb.iff:    $(SBIN)xpm2iff $(AMI)grave16.xpm
+       $(SBIN)xpm2iff $(AMI)grave16.xpm $(NETHACK)tomb.iff
+
+$(OO)xpm2iff.o:        $(AMI)xpm2iff.c
+       $(CC) $(CFLAGS) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(AMI)xpm2iff.c
+
+$(SBIN)xpm2iff:        $(OO)xpm2iff.o
+       $(LINK) $(LNSPEC) $@ $(LIN) $(OO)xpm2iff.o $(FLLIB)
+
+# Tile installation for the tile version of the game
+inst-tiles: $(TILEFILES)
+
+#SFD_INSTEAD $(NETHACK)tiles: $(NETHACK)tiles
+$(NETHACK)tiles:
+       -makedir $(NETHACK)tiles
+
+$(OO)txt2iff.o:        $(AMI)txt2iff.c
+       $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ \
+               $(AMI)txt2iff.c
+
+$(OO)ppmwrite.o: $(WSHARE)ppmwrite.c
+       $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)ppmwrite.c
+
+$(OO)tiletext.o:       $(WSHARE)tiletext.c $(I)config.h $(WSHARE)tile.h
+       $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)tiletext.c
+
+$(OO)tiletxt.o:        $(WSHARE)tilemap.c $(I)hack.h
+       $(CC) $(CFLAGS) $(CSYM) $(DEFSPEC)TILETEXT $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)tilemap.c
+
+NAMEOBJS = $(O)drawing.o $(O)decl.o $(O)monst.o $(O)objects.o
+
+$(SBIN)txt2ppm:        $(OO)ppmwrite.o $(NAMEOBJS) $(O)alloc.o $(OO)panic.o $(OO)tiletext.o $(OO)tiletxt.o
+       $(LINK) $(LNSPEC) $@ $(LIN) $(OO)ppmwrite.o $(NAMEOBJS) $(OO)tiletext.o $(OO)tiletxt.o $(O)alloc.o $(OO)panic.o $(FLLIB)
+
+$(SBIN)txt2iff: $(OO)txt2iff.o $(NAMEOBJS) $(OO)tiletext.o $(OO)tiletxt.o
+       $(LINK) $(LNSPEC) $@ $(LIN) $(OO)txt2iff.o $(NAMEOBJS) $(OO)tiletext.o \
+               $(OO)tiletxt.o  $(FLLIB)
+
+$(NETHACK)tiles/objects.iff: $(WSHARE)objects.txt $(SBIN)txt2iff
+       $(SBIN)txt2iff $(WSHARE)objects.txt $(NETHACK)tiles/objects.iff
+
+$(NETHACK)tiles/monsters.iff: $(WSHARE)monsters.txt $(SBIN)txt2iff
+       $(SBIN)txt2iff $(WSHARE)monsters.txt $(NETHACK)tiles/monsters.iff
+
+$(NETHACK)tiles/other.iff: $(WSHARE)other.txt $(SBIN)txt2iff
+       $(SBIN)txt2iff $(WSHARE)other.txt $(NETHACK)tiles/other.iff
+
+# Sound installation rules.
+inst-sounds: $(SOUNDFILES)
+       list to T:nhsdat.lst $(SLIB)sounds QUICK NOHEAD
+       echo  >T:make-nhsdat $(SBIN)dlb cCfI $(SLIB)sounds $(NETHACK)nhsdat T:nhsdat.lst
+       echo >>T:make-nhsdat if not exists $(NETHACK)nhsdat
+       echo >>T:make-nhsdat copy $(SLIB)sounds/\#? $(NETHACK)sounds
+       echo >>T:make-nhsdat endif
+       execute T:make-nhsdat
+       -delete T:make-nhsdat
+
+#SFD_INSTEAD $(SLIB)sounds: $(SLIB)sounds
+$(SLIB)sounds:
+       -makedir $(SLIB)sounds
+
+$(SBIN)cvtsnd: $(OO)cvtsnd.o
+       $(LINK) $(LNSPEC) $@ $(LIN) $(OO)cvtsnd.o $(FLLIB)
+
+$(OO)cvtsnd.o: $(AMI)cvtsnd.c
+#SFD_INSTEAD $(CC) $(CFLAGS) $(OBJSPEC)%(left) %(right)
+#none
+
+$(SLIB)sounds/Bell: $(SHARE)sounds/bell.uu
+       $(UUDEC) $(SHARE)sounds/bell.uu
+       $(SBIN)cvtsnd Bell $(SLIB)sounds/Bell
+       -delete Bell
+
+$(SLIB)sounds/Bugle: $(SHARE)sounds/bugle.uu
+       $(UUDEC) $(SHARE)sounds/bugle.uu
+       $(SBIN)cvtsnd Bugle $(SLIB)sounds/Bugle
+       -delete Bugle
+
+$(SLIB)sounds/Drum_Of_Earthquake: $(SHARE)sounds/erthdrum.uu
+       $(UUDEC) $(SHARE)sounds/erthdrum.uu
+       $(SBIN)cvtsnd Drum_Of_Earthquake $(SLIB)sounds/Drum_Of_Earthquake
+       -delete Drum_Of_Earthquake
+
+$(SLIB)sounds/Fire_Horn: $(SHARE)sounds/firehorn.uu
+       $(UUDEC) $(SHARE)sounds/firehorn.uu
+       $(SBIN)cvtsnd Fire_Horn $(SLIB)sounds/Fire_Horn
+       -delete Fire_Horn
+
+$(SLIB)sounds/Frost_Horn: $(SHARE)sounds/frsthorn.uu
+       $(UUDEC) $(SHARE)sounds/frsthorn.uu
+       $(SBIN)cvtsnd Frost_Horn $(SLIB)sounds/Frost_Horn
+       -delete Frost_Horn
+
+$(SLIB)sounds/Leather_Drum: $(SHARE)sounds/lethdrum.uu
+       $(UUDEC) $(SHARE)sounds/lethdrum.uu
+       $(SBIN)cvtsnd Leather_Drum $(SLIB)sounds/Leather_Drum
+       -delete Leather_Drum
+
+$(SLIB)sounds/Magic_Flute: $(SHARE)sounds/mgcflute.uu
+       $(UUDEC) $(SHARE)sounds/mgcflute.uu
+       $(SBIN)cvtsnd Magic_Flute $(SLIB)sounds/Magic_Flute
+       -delete Magic_Flute
+
+$(SLIB)sounds/Magic_Harp: $(SHARE)sounds/mgcharp.uu
+       $(UUDEC) $(SHARE)sounds/mgcharp.uu
+       $(SBIN)cvtsnd Magic_Harp $(SLIB)sounds/Magic_Harp
+       -delete Magic_Harp
+
+$(SLIB)sounds/Tooled_Horn: $(SHARE)sounds/toolhorn.uu
+       $(UUDEC) $(SHARE)sounds/toolhorn.uu
+       $(SBIN)cvtsnd Tooled_Horn $(SLIB)sounds/Tooled_Horn
+       -delete Tooled_Horn
+
+$(SLIB)sounds/Wooden_Flute: $(SHARE)sounds/wdnflute.uu
+       $(UUDEC) $(SHARE)sounds/wdnflute.uu
+       $(SBIN)cvtsnd Wooden_Flute $(SLIB)sounds/Wooden_Flute
+       -delete Wooden_Flute
+
+$(SLIB)sounds/Wooden_Harp: $(SHARE)sounds/wdnharp.uu
+       $(UUDEC) $(SHARE)sounds/wdnharp.uu
+       $(SBIN)cvtsnd Wooden_Harp $(SLIB)sounds/Wooden_Harp
+       -delete Wooden_Harp
+
+inst-dungeon: $(INSTDUNGEONFILES)
+
+$(NETHACK)options : $(DAT)options
+       copy $(DAT)options $@
+
+# Create compiled dungeon files
+BGM= $(SLIB)bigrm-2.lev $(SLIB)bigrm-3.lev $(SLIB)bigrm-4.lev $(SLIB)bigrm-5.lev
+$(BGM):        $(SLIB)bigrm-1.lev
+
+$(SLIB)bigrm-1.lev: $(DAT)bigroom.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)bigroom.des
+#none
+
+$(SLIB)castle.lev:  $(DAT)castle.des $(SBIN)lev_comp
+
+ENDGAME1= $(SLIB)air.lev $(SLIB)earth.lev $(SLIB)fire.lev $(SLIB)water.lev
+$(ENDGAME1):   $(SLIB)astral.lev
+
+$(SLIB)astral.lev:     $(DAT)endgame.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)endgame.des
+#none
+
+GEHENNOM1= $(SLIB)asmodeus.lev $(SLIB)baalz.lev $(SLIB)juiblex.lev \
+  $(SLIB)orcus.lev $(SLIB)sanctum.lev 
+$(GEHENNOM1):  $(SLIB)valley.lev
+
+$(SLIB)valley.lev:     $(DAT)gehennom.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)gehennom.des
+#none
+
+$(SLIB)knox.lev: $(DAT)knox.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)knox.des
+#none
+
+MINES1= $(SLIB)minend-1.lev $(SLIB)minend-2.lev $(SLIB)minetn-1.lev $(SLIB)minetn-2.lev
+$(MINES1): $(SLIB)minefill.lev
+
+$(SLIB)minefill.lev: $(DAT)mines.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)mines.des
+#none
+
+$(SLIB)oracle.lev: $(DAT)oracle.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)oracle.des
+#none
+
+TOWER1= $(SLIB)tower1.lev $(SLIB)tower2.lev
+$(TOWER1): $(SLIB)tower3.lev
+
+$(SLIB)tower3.lev: $(DAT)tower.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)tower.des
+#none
+
+WIZARD1= $(SLIB)wizard1.lev $(SLIB)wizard2.lev $(SLIB)wizard3.lev \
+       $(SLIB)fakewiz1.lev
+$(WIZARD1):  $(SLIB)fakewiz2.lev
+
+$(SLIB)fakewiz2.lev:  $(DAT)yendor.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)yendor.des
+#none
+
+MEDUSA1= $(SLIB)medusa-1.lev
+$(MEDUSA1): $(SLIB)medusa-2.lev
+
+$(SLIB)medusa-2.lev:   $(DAT)medusa.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)medusa.des
+#none
+
+SOKOBAN1= $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev $(SLIB)soko2-1.lev \
+       $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev $(SLIB)soko3-2.lev \
+       $(SLIB)soko4-1.lev
+$(SOKOBAN1): $(SLIB)soko4-2.lev
+
+$(SLIB)soko4-2.lev: $(DAT)sokoban.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)sokoban.des
+#none
+
+$(ADFILES1):   $(SLIB)Arc-goal.lev
+
+$(SLIB)Arc-goal.lev:   $(DAT)Arch.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)Arch.des
+#none
+
+$(BDFILES1):   $(SLIB)Bar-goal.lev
+
+$(SLIB)Bar-goal.lev:   $(DAT)Barb.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)Barb.des
+#none
+
+$(CDFILES1):   $(SLIB)Cav-goal.lev
+
+$(SLIB)Cav-goal.lev:   $(DAT)Caveman.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)Caveman.des
+#none
+
+$(HDFILES1):   $(SLIB)Hea-goal.lev
+
+$(SLIB)Hea-goal.lev:   $(DAT)Healer.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)Healer.des
+#none
+
+$(KDFILES1):   $(SLIB)Kni-goal.lev
+
+$(SLIB)Kni-goal.lev:   $(DAT)Knight.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)Knight.des
+#none
+
+$(MDFILES1):   $(SLIB)Mon-goal.lev
+
+$(SLIB)Mon-goal.lev:   $(DAT)Monk.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)Monk.des
+#none
+
+$(PDFILES1):   $(SLIB)Pri-goal.lev
+
+$(SLIB)Pri-goal.lev:   $(DAT)Priest.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)Priest.des
+#none
+
+$(RDFILES1):   $(SLIB)Rog-goal.lev
+
+$(SLIB)Rog-goal.lev:   $(DAT)Rogue.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)Rogue.des
+#none
+
+$(RANFILES1):  $(SLIB)Ran-goal.lev
+
+$(SLIB)Ran-goal.lev:   $(DAT)Ranger.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)Ranger.des
+#none
+
+$(SDFILES1):   $(SLIB)Sam-goal.lev
+
+$(SLIB)Sam-goal.lev:   $(DAT)Samurai.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)Samurai.des
+#none
+
+$(TDFILES1):   $(SLIB)Tou-goal.lev
+
+$(SLIB)Tou-goal.lev:   $(DAT)Tourist.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)Tourist.des
+#none
+
+$(VDFILES1):   $(SLIB)Val-goal.lev
+
+$(SLIB)Val-goal.lev:   $(DAT)Valkyrie.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)Valkyrie.des
+#none
+
+$(WDFILES1):   $(SLIB)Wiz-goal.lev
+
+$(SLIB)Wiz-goal.lev:   $(DAT)Wizard.des $(SBIN)lev_comp
+#SFD_INSTEAD $(SBIN)lev_comp $(DAT)Wizard.des
+#none
+
+$(SLIB)dungeon:  $(DAT)dungeon.def $(SBIN)makedefs $(SBIN)dgn_comp
+       $(SBIN)makedefs -e
+       $(SBIN)dgn_comp $(DAT)dungeon.pdf
+       copy $(DAT)dungeon $(SLIB)dungeon
+       delete $(DAT)dungeon
+
+inst-data: $(INSTDATAFILES)
+
+$(NETHACK)amii.hlp: $(AMI)amii.hlp
+       copy $(AMI)amii.hlp $@
+
+#$(NETHACK)data:  $(DAT)data
+#      copy $(DAT)data $@
+
+$(SLIB)data:  $(DAT)data.base $(I)config.h $(SBIN)makedefs
+       $(SBIN)makedefs -d
+
+#$(NETHACK)rumors:  $(DAT)rumors
+#      copy $(DAT)rumors $@
+
+$(SLIB)rumors:  $(DAT)rumors.tru $(DAT)rumors.fal $(SBIN)makedefs
+       $(SBIN)makedefs -r
+
+$(SLIB)cmdhelp:  $(DAT)cmdhelp
+       copy $(DAT)cmdhelp $@
+
+$(SLIB)help:  $(DAT)help
+       copy $(DAT)help $@
+
+$(SLIB)hh:  $(DAT)hh
+       copy $(DAT)hh $@
+
+$(NETHACK)HackWB.hlp: $(AMI)HackWB.hlp
+       copy $(AMI)HackWB.hlp $@
+
+$(SLIB)history:  $(DAT)history
+       copy $(DAT)history $@
+
+$(NETHACK)license:  $(DAT)license
+       copy $(DAT)license $@
+
+$(SLIB)opthelp:  $(DAT)opthelp
+       copy $(DAT)opthelp $@
+
+$(NETHACK)Recover.txt: $(DOC)Recover.txt
+       copy $(DOC)Recover.txt $@
+
+$(NETHACK)GuideBook.txt: $(DOC)GuideBook.txt
+       copy $(DOC)GuideBook.txt $@
+
+$(NETHACK)NetHack.txt: $(DOC)NetHack.txt
+       copy $(DOC)NetHack.txt $@
+
+$(NETHACK)Install.ami: $(AMI)Install.ami
+       copy $(AMI)Install.ami $@
+
+#SFD_INSTEAD $(NETHACK)logfile: $(NETHACK)logfile
+$(NETHACK)logfile:
+       echo to $@
+
+#SFD_INSTEAD $(NETHACK)record: $(NETHACK)record
+$(NETHACK)record:
+       echo to $@
+
+$(SLIB)wizhelp: $(DAT)wizhelp
+       copy $(DAT)wizhelp $@
+
+# Create the directories here because NetHack.cnf puts them there by default
+$(NETHACK)NetHack.cnf:  $(AMI)NetHack.cnf
+       copy $(AMI)NetHack.cnf $@
+       -makedir $(NETHACK)save
+       -makedir $(NETHACK)levels
+
+#SFD_BEGIN
+#SFD_ELSE
+$(O)NetHack.gst: $(GSTSRC) $(I)hack.h
+       sc makegst=$(GSTFILE) $(CFLAGS) $(GSTSRC)
+#SFD_END
+
+# Unpack and install fonts
+
+INSTFONTFILES=         $(NETHACK)hack.font $(NETHACK)hack $(NETHACK)hack/8
+
+inst-fonts: $(INSTFONTFILES)
+
+$(NETHACK)hack/8:  $(AMI)amifont8.uu $(NETHACK)hack
+       $(UUDEC) $(AMI)amifont8.uu
+       copy 8 $(NETHACK)hack/8
+       delete 8
+
+$(NETHACK)hack.font:  $(AMI)amifont.uu
+       $(UUDEC) $(AMI)amifont.uu
+       copy hack.font $(NETHACK)hack.font
+       delete hack.font
+
+#SFD_INSTEAD $(NETHACK)hack: $(NETHACK)hack
+$(NETHACK)hack:
+       -makedir $@
+
+INSTICONFILES= \
+       $(NETHACK)default.icon $(NETHACK)NetHack.info $(NETHACK)NewGame.info \
+       $(NETHACK)HackWB.info
+
+inst-icons: $(INSTICONFILES)
+
+# Unpack the icons into place
+
+$(NETHACK)default.icon:  $(AMI)dflticon.uu
+       $(UUDEC) $(AMI)dflticon.uu
+#      copy default.icon $(NETHACK)default.icon
+#      delete default.icon
+
+$(NETHACK)NetHack.info:  $(AMI)NHinfo.uu
+       $(UUDEC) $(AMI)NHinfo.uu
+#      copy NetHack.info $(NETHACK)NetHack.info
+#      delete NetHack.info
+
+$(NETHACK)NewGame.info:  $(AMI)NewGame.uu
+       $(UUDEC) $(AMI)NewGame.uu
+#      copy NewGame.info $(NETHACK)NewGame.info
+#      delete NewGame.info
+
+$(NETHACK)HackWB.info:  $(AMI)HackWB.uu
+       $(UUDEC) $(AMI)HackWB.uu
+#      copy HackWB.info $(NETHACK)HackWB.info
+#      delete HackWB.info
+
+# If DLB is defined, create the nhdat library file in the playground
+# directory.  If not, move all the data files there.
+$(NETHACK)nhdat:  $(LIBFILES) $(SBIN)dlb
+       list to T:nhdat.lst $(SLIB) QUICK NOHEAD FILES
+       echo  >T:make-nhdat $(SBIN)dlb cCfI $(SLIB) $(NETHACK)nhdat T:nhdat.lst
+       echo >>T:make-nhdat if not exists $(NETHACK)nhdat
+       echo >>T:make-nhdat copy $(SLIB)\#? $(NETHACK)
+       echo >>T:make-nhdat endif
+       execute T:make-nhdat
+       -delete T:make-nhdat
+
+# DO NOT DELETE THIS LINE
+
+$(O)allmain.o:  $(NHS)allmain.c $(HDEP)
+
+$(O)alloc.o:  $(NHS)alloc.c $(I)config.h
+
+$(O)apply.o:  $(NHS)apply.c $(HDEP) $(I)edog.h
+#SFD_INSTEAD #none
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)apply.c
+
+$(O)artifact.o:  $(NHS)artifact.c $(HDEP) $(I)artifact.h $(I)artilist.h
+
+$(O)attrib.o:  $(NHS)attrib.c $(HDEP) $(I)artifact.h
+
+$(O)ball.o: $(NHS)ball.c $(HDEP)
+
+$(O)bones.o:  $(NHS)bones.c $(HDEP) $(I)lev.h
+
+$(O)botl.o:    $(NHS)botl.c $(HDEP)
+
+$(O)cmd.o:  $(NHS)cmd.c $(HDEP) $(I)func_tab.h
+
+$(O)dbridge.o:  $(NHS)dbridge.c $(HDEP)
+
+$(O)decl.o:  $(NHS)decl.c $(HDEP) $(I)quest.h
+
+$(O)detect.o: $(NHS)detect.c $(HDEP) $(I)artifact.h
+
+$(O)dig.o: $(NHS)dig.c $(HDEP) $(I)edog.h
+
+$(O)display.o:  $(NHS)display.c $(HDEP)
+
+$(O)dlb.o: $(NHS)dlb.c $(HDEP) $(I)dlb.h
+
+$(O)do.o:  $(NHS)do.c $(HDEP) $(I)lev.h
+
+$(O)do_name.o:  $(NHS)do_name.c $(HDEP)
+
+$(O)do_wear.o:  $(NHS)do_wear.c $(HDEP)
+
+$(O)dog.o:  $(NHS)dog.c $(HDEP) $(I)edog.h
+
+$(O)dogmove.o:  $(NHS)dogmove.c $(HDEP) $(I)mfndpos.h $(I)edog.h
+
+$(O)dokick.o:  $(NHS)dokick.c $(HDEP) $(I)eshk.h
+
+$(O)dothrow.o:  $(NHS)dothrow.c $(HDEP)
+
+$(O)drawing.o:  $(NHS)drawing.c $(HDEP) $(I)tcap.h
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)drawing.c
+
+$(O)dungeon.o:  $(NHS)dungeon.c $(HDEP) $(I)dgn_file.h $(I)dlb.h
+
+$(O)eat.o:  $(NHS)eat.c $(HDEP)
+
+$(O)end.o:  $(NHS)end.c $(HDEP) $(I)eshk.h $(I)dlb.h
+
+$(O)engrave.o:  $(NHS)engrave.c $(HDEP) $(I)lev.h
+
+$(O)exper.o:  $(NHS)exper.c $(HDEP)
+
+$(O)explode.o:  $(NHS)explode.c $(HDEP)
+
+$(O)extralev.o:  $(NHS)extralev.c $(HDEP)
+
+$(O)files.o:  $(NHS)files.c $(HDEP) $(I)dlb.h $(I)date.h
+
+$(O)fountain.o:  $(NHS)fountain.c $(HDEP)
+
+$(O)hack.o:  $(NHS)hack.c $(HDEP)
+
+$(O)hacklib.o:  $(NHS)hacklib.c $(HDEP)
+
+$(O)invent.o:  $(NHS)invent.c $(HDEP) $(I)artifact.h
+
+$(O)light.o:  $(NHS)light.c $(HDEP) $(I)lev.h
+
+$(O)lock.o:  $(NHS)lock.c $(HDEP)
+
+$(O)mail.o:  $(NHS)mail.c $(HDEP) $(I)mail.h
+
+$(O)makemon.o:  $(NHS)makemon.c $(HDEP) $(I)epri.h $(I)emin.h $(I)edog.h
+
+$(O)mapglyph.o:  $(NHS)mapglyph.c $(HDEP)
+
+$(O)mcastu.o:  $(NHS)mcastu.c $(HDEP)
+
+$(O)mhitm.o:  $(NHS)mhitm.c $(HDEP) $(I)artifact.h $(I)edog.h
+
+$(O)mhitu.o:  $(NHS)mhitu.c $(HDEP) $(I)artifact.h $(I)edog.h
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)mhitu.c
+
+$(O)minion.o:  $(NHS)minion.c $(HDEP) $(I)emin.h $(I)epri.h
+
+$(O)mklev.o:  $(NHS)mklev.c $(HDEP)
+
+$(O)mkmap.o:  $(NHS)mkmap.c $(HDEP) $(I)sp_lev.h
+
+$(O)mkmaze.o:  $(NHS)mkmaze.c $(HDEP) $(I)sp_lev.h $(I)lev.h
+
+$(O)mkobj.o:  $(NHS)mkobj.c $(HDEP) $(I)artifact.h $(I)prop.h
+
+$(O)mkroom.o:  $(NHS)mkroom.c $(HDEP)
+
+$(O)mon.o:  $(NHS)mon.c $(HDEP) $(I)mfndpos.h $(I)edog.h
+
+$(O)mondata.o:  $(NHS)mondata.c $(HDEP) $(I)eshk.h $(I)epri.h
+
+$(O)monmove.o:  $(NHS)monmove.c $(HDEP) $(I)mfndpos.h $(I)artifact.h
+
+$(O)monst.o:  $(NHS)monst.c $(I)config.h $(I)permonst.h $(I)monsym.h \
+               $(I)eshk.h $(I)vault.h $(I)epri.h $(I)color.h
+
+$(O)monstr.o:  $(NHS)monstr.c $(HDEP)
+#SFD_INSTEAD   $(CC) $(CFLAGS) $(OBJSPEC)%(left) $(NHS)monstr.c
+#none
+
+$(O)mplayer.o: $(NHS)mplayer.c $(HDEP)
+
+$(O)mthrowu.o:  $(NHS)mthrowu.c $(HDEP)
+
+$(O)muse.o:    $(NHS)muse.c $(HDEP)
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)muse.c
+
+$(O)music.o:  $(NHS)music.c $(HDEP) #interp.c
+
+$(O)o_init.o:  $(NHS)o_init.c $(HDEP) $(I)lev.h
+
+$(O)objects.o:  $(NHS)objects.c $(I)config.h $(I)obj.h $(I)objclass.h \
+               $(I)prop.h $(I)skills.h $(I)color.h
+#SFD_INSTEAD #none
+       $(CC) $(CFLAGS) $(INCLSPEC)$(NHS) $(OBJSPEC)$@ $(NHS)objects.c
+
+$(O)objnam.o:  $(NHS)objnam.c $(HDEP)
+
+$(O)options.o:  $(NHS)options.c $(HDEP) $(I)tcap.h $(I)config.h \
+               $(I)objclass.h $(I)flag.h
+
+$(O)pager.o:  $(NHS)pager.c $(HDEP) $(I)dlb.h
+
+$(O)pickup.o:  $(NHS)pickup.c $(HDEP)
+
+$(O)pline.o:   $(NHS)pline.c $(HDEP) $(I)epri.h
+
+$(O)polyself.o:  $(NHS)polyself.c $(HDEP)
+
+$(O)potion.o:  $(NHS)potion.c $(HDEP)
+
+$(O)pray.o:  $(NHS)pray.c $(HDEP) $(I)epri.h
+
+$(O)priest.o:  $(NHS)priest.c $(HDEP) $(I)mfndpos.h $(I)eshk.h $(I)epri.h \
+               $(I)emin.h
+
+$(O)quest.o:   $(NHS)quest.c $(HDEP) $(I)quest.h $(I)qtext.h
+
+$(O)questpgr.o: $(NHS)questpgr.c $(HDEP) $(I)qtext.h $(I)dlb.h
+
+$(O)read.o:  $(NHS)read.c $(HDEP)
+
+$(O)rect.o:    $(NHS)rect.c $(HDEP)
+
+$(O)region.o:  $(NHS)region.c $(HDEP)
+
+$(O)restore.o:  $(NHS)restore.c $(HDEP) $(I)lev.h $(I)tcap.h $(I)quest.h
+
+$(O)rnd.o:  $(NHS)rnd.c $(HDEP)
+
+$(O)role.o:    $(NHS)role.c $(HDEP)
+
+$(O)rumors.o:  $(NHS)rumors.c $(HDEP) $(I)dlb.h
+
+$(O)save.o:  $(NHS)save.c $(HDEP) $(I)lev.h $(I)quest.h
+
+$(O)shk.o:  $(NHS)shk.c $(HDEP) $(I)eshk.h
+#SFD_INSTEAD #none
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)shk.c
+
+$(O)shknam.o:  $(NHS)shknam.c $(HDEP) $(I)eshk.h
+
+$(O)sit.o:  $(NHS)sit.c $(HDEP) $(I)artifact.h
+
+$(O)sounds.o:  $(NHS)sounds.c $(HDEP) $(I)edog.h
+
+$(O)sp_lev.o:  $(NHS)sp_lev.c $(HDEP) $(I)sp_lev.h $(I)rect.h $(I)dlb.h
+
+$(O)spell.o:  $(NHS)spell.c $(HDEP)
+
+$(O)steal.o:  $(NHS)steal.c $(HDEP)
+
+$(O)steed.o:   $(NHS)steed.c $(HDEP)
+
+$(O)teleport.o:        $(NHS)teleport.c $(HDEP)
+
+$(O)timeout.o:  $(NHS)timeout.c $(HDEP) $(I)lev.h
+
+$(O)topten.o:  $(NHS)topten.c $(HDEP) $(I)dlb.h
+
+$(O)track.o:  $(NHS)track.c $(HDEP)
+
+$(O)trap.o:  $(NHS)trap.c $(HDEP)
+#SFD_INSTEAD #none
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)trap.c
+
+$(O)u_init.o:  $(NHS)u_init.c $(HDEP)
+
+$(O)uhitm.o:  $(NHS)uhitm.c $(HDEP)
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)uhitm.c
+
+$(O)vault.o:  $(NHS)vault.c $(HDEP) $(I)vault.h
+
+$(O)version.o:  $(NHS)version.c $(HDEP) $(I)date.h $(I)patchlevel.h
+
+# DMake doesn't grok mid-line comments
+#SFD_INSTEAD $(O)vision.o:  $(NHS)vision.c $(HDEP)
+$(O)vision.o:  $(NHS)vision.c $(HDEP) #$(I)vis_tab.h
+
+$(O)weapon.o:  $(NHS)weapon.c $(HDEP)
+
+$(O)were.o:  $(NHS)were.c $(HDEP)
+
+$(O)wield.o:  $(NHS)wield.c $(HDEP)
+
+$(O)windows.o:  $(NHS)windows.c $(HDEP) $(I)wintty.h
+
+$(O)wizard.o:  $(NHS)wizard.c $(HDEP) $(I)qtext.h
+
+$(O)worm.o:  $(NHS)worm.c $(HDEP) $(I)lev.h
+
+$(O)worn.o:  $(NHS)worn.c $(HDEP)
+
+$(O)write.o:  $(NHS)write.c $(HDEP)
+
+$(O)zap.o:  $(NHS)zap.c $(HDEP)
+       $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)zap.c
+
+$(O)getline.o: $(TTY)getline.c $(HDEP) $(I)wintty.h
+
+$(O)termcap.o: $(TTY)termcap.c $(HDEP) $(I)wintty.h $(I)tcap.h
+
+$(O)topl.o:    $(TTY)topl.c $(HDEP) $(I)wintty.h $(I)tcap.h
+
+$(O)wintty.o:  $(TTY)wintty.c $(HDEP) $(I)wintty.h $(I)tcap.h \
+               $(I)patchlevel.h
+
+$(O)amitty.o:  $(AMI)amitty.c $(HDEP)
+
+$(O)amistack.o:        $(AMI)amistack.c
+       $(CC) $(CFLAGS3) $(CSYM) $(OBJSPEC)$@ $(AMI)amistack.c
+
+$(O)rip.o:     $(NHS)rip.c $(HDEP)
+
+
+$(I)config.h:  $(I)config1.h $(I)tradstdc.h $(I)global.h
+       -setdate $(I)config.h
+       -wait 2
+
+# onames.h handled at onames.h target, pm.h
+
+$(I)decl.h:  $(I)quest.h $(I)spell.h $(I)color.h $(I)obj.h $(I)you.h
+       -setdate $(I)decl.h
+       -wait 2
+
+$(I)global.h:  $(I)coord.h $(I)pcconf.h $(I)amiconf.h
+       -setdate $(I)global.h
+       -wait 2
+
+$(I)hack.h:  $(I)config.h $(I)trap.h $(I)decl.h $(I)dungeon.h $(I)monsym.h \
+               $(I)mkroom.h $(I)objclass.h $(I)flag.h $(I)rm.h $(I)vision.h \
+               $(I)display.h $(I)wintype.h $(I)engrave.h $(I)rect.h \
+               $(I)region.h $(I)trampoli.h
+       -setdate $(I)hack.h
+       -wait 2
+
+$(I)permonst.h:  $(I)monattk.h $(I)monflag.h $(I)align.h
+       -setdate $(I)permonst.h
+       -wait 2
+
+$(I)you.h:  $(I)align.h $(I)attrib.h $(I)monst.h $(I)youprop.h $(I)skills.h
+       -setdate $(I)you.h
+       -wait 2
+
+# pm.h handled at target
+
+$(I)youprop.h:  $(I)prop.h $(I)permonst.h $(I)mondata.h
+       -setdate $(I)youprop.h
+       -wait 2
+
+$(I)display.h: $(I)vision.h $(I)mondata.h
+       -setdate $(I)display.h
+       -wait 2
+
+$(I)dungeon.h: $(I)align.h
+       -setdate $(I)dungeon.h
+       -wait 2
+
+$(I)emin.h: $(I)dungeon.h
+       -setdate $(I)emin.h
+       -wait 2
+
+$(I)epri.h: $(I)dungeon.h $(I)align.h
+       -setdate $(I)epri.h
+       -wait 2
+
+$(I)eshk.h: $(I)dungeon.h
+       -setdate $(I)eshk.h
+       -wait 2
+
+$(I)engrave.h: $(I)trampoli.h $(I)rect.h
+       -setdate $(I)engrave.h
+       -wait 2
+
+$(I)mondata.h: $(I)align.h
+       -setdate $(I)mondata.h
+       -wait 2
+
+$(I)monst.h: $(I)align.h
+       -setdate $(I)monst.h
+       -wait 2
+
+$(I)pcconf.h: $(I)micro.h $(I)system.h
+       -setdate $(I)pcconf.h
+       -wait 2
+
+$(I)rm.h: $(I)align.h
+       -setdate $(I)rm.h
+       -wait 2
+
+$(I)vault.h: $(I)dungeon.h
+       -setdate $(I)vault.h
+       -wait 2
+
+
+#notes
+#  install keeps doing re-install because it keeps rebuilding lev_comp???
+#  fixed(?) - deleted setdate
+#  make nhdat rebuils sys/amiga objects
diff --git a/sys/amiga/NetHack.cnf b/sys/amiga/NetHack.cnf
new file mode 100644 (file)
index 0000000..89794c0
--- /dev/null
@@ -0,0 +1,213 @@
+# A '#' at the beginning of a line means the rest of the line is a comment.
+
+# This is an example configuration file.
+# If several people are to use it, don't specify "name" or personal
+# prefences like "dogname" or "packorder" in OPTIONS.
+
+# To change configuration, comment out the unwanted configurations, and
+# remove the comment from the configuration you want.
+
+# Some options to set personal preferences.  If several people are to
+# use it, options like these should not be set here - use the command line
+#OPTIONS=name:Janet-V,female,dogname:Fido,fruit:apricot
+#OPTIONS=packorder:")[%?+/=!(*0_`,scores:10t/2a,noverbose
+#OPTIONS=gender:male
+#OPTIONS=role:random
+#OPTIONS=race:random 
+#OPTIONS=align:chaotic
+# Other general options
+#OPTIONS=time,rest_on_space,noautopickup
+
+# The search path for files like record, help, opthelp, etc.
+PATH=NetHack:
+
+# My own setup
+#OPTIONS=nolegacy,fruit:lemon,time,autopickup,checkpoint,showexp,showscore,standout,nonews
+#OPTIONS=nomail,flush,eight_bit_tty,scores:10t/2a,pickup_types:$,suppress_alert:3.3.0,autoquiver
+
+# The windowtype option must be set before any options regarding colors and palette
+# are set otherwise previously set values will be overridden by the defaults
+#
+# The font version of the game
+OPTIONS=windowtype:amii
+#
+# New tile version of the game
+#OPTIONS=windowtype:amitile
+#
+# A hard disk configuration.
+#
+HACKDIR=NetHack:
+LEVELS=Nethack:Levels
+SAVE=Nethack:Save
+BONESDIR=Nethack:Levels
+SCOREDIR=Nethack:
+LOCKDIR=Nethack:
+CONFIGDIR=Nethack:
+DATADIR=Nethack:
+TROUBLEDIR=Nethack:
+
+# *** CHARACTER GRAPHICS ***
+#
+# See the on-line help or the Guidebook for which symbols are in which
+# positions.
+#
+# Note that the hack.font has special graphics characters from 192 on.
+
+# An example using the hack.font graphics character set:
+DUNGEON =  032 192 193 194 195 196 197 198 216 214 \
+          215 213 217 145 146 147 148 035 035 217 \
+          218 229 060 062 060 062 095 124 092 035 \
+          123 125 042 125 042 042 035 035 046 035 \
+          125
+
+TRAPS =    094 094 094 094 094 094 094 094 094 094 \
+          094 094 094 094 094 094 094 034 094 094 \
+          094 094
+
+EFFECTS =  241 240 242 243 042 033 123 125        \
+          064 038 042 035                         \
+          244 245 246 247 239 248 249 250         \
+          230 234 231 236 212 237 232 235 233
+
+WARNINGS =  048 049 050 051 052 053
+
+# Monitors vary greatly in their color response.  If the default colors
+# are not good on your monitor, here are some other alternatives for the
+# font version of the game:
+#
+# Last color of the palette is always used for the cursor.
+#
+#CBM 1960, set color/contrast for good pure red, green, and blue. True colors.
+#PENS=000,fff,a61,7bb,0f0,e0c,00f,f00
+#CBM 1960, set color/contrast as above, better colors for NetHack.
+#PENS=667,fff,da1,7bb,2f0,e0d,0af,f42
+#and other suggestions:
+#PENS=888,ffc,840,0b8,4e4,e8b,7be,a04
+#PENS=000,fff,830,7ae,181,c06,23e,c00
+#
+# For an "interlaced"+ line screen, the default font is courier:13.  If you want
+#  a different font, set it here.  The format is "fontname.font:size"; i.e. the
+# .font extension is required.
+#FONT=courier.font:13
+#FONT=topaz.font:8
+#
+# Proportional fonts such as CGTimes are probably not a good idea because they
+# result in many things not being spaced out correctly.
+#FONT=CGTimes.font:15
+#
+# This sized proportional font is readable, but still has spacing problems
+#FONT=CGTimes.font:21
+#
+#   FOR AGA OR OTHER DISPLAYS CAPABLE OF 5 OR MORE PLANES...
+#
+# For a screen of depth 5 the following dripens provide a brown border
+# using pens 16-31.
+#
+# Pens 16-31 can be redefined with PENS= if you want different colors,
+# using the PENS= values below for a 4 plane screen as the first 16 colors.
+#
+#DEPTH=5
+#DRIPENS=0,0,0,17,27,23,1,23,15,0,23,27
+# 
+# The APEN and BPEN values in the various types of windows can be set in
+# the manner shown below.  These values are for the 16 color version of
+# the tile game.
+#
+# These values are specified as APEN,BPEN (foreground,background)
+#
+#MSGPENS=1,12
+#STATUSPENS=1,12
+#MENUPENS=1,23
+#TEXTPENS=1,23
+#OTHERPENS=1,23
+#
+#   FOR ECS OR OTHERS ONLY CAPABLE OF 4 PLANES...
+#
+# These values work good for the TILE version of the game on ECS machines
+# These are the default values for reference purposes.
+#
+#DEPTH=4
+#defaults for tilemode:
+#PENS=000,fff,0bf,f60,00f,090,69b,f00,6f0,ff0,f0f,940,466,c40,ddb,fb9
+#DRIPENS=0,1,0,2,4,12,14,12,7,1,12,4
+#defaults for fontmode:
+#PENS=000,fff,830,7ac,181,c06,23e,c00
+#DRIPENS=0,6,2,1,6,3,1,3,7,1,3,6
+# 
+# The APEN and BPEN values in the various types of windows can be set in
+# the manner shown below.  These values are for a 32 color version of
+# the tile game.
+#
+# These values are specified as APEN,BPEN (foreground,background)
+#
+#MSGPENS=1,12
+#STATUSPENS=1,12
+#MENUPENS=0,14
+#TEXTPENS=0,14
+#OTHERPENS=1,12
+#
+# New alternative color scheme for 16 color font mode.
+# This changes the colors of monsters, objects etc.
+#
+# FGPENS and BGPENS define APEN and BPEN for objects and monsters on the map.
+# The colors are in the following order:
+# black, red, green, brown, blue, magenta, cyan, gray, no color, orange,
+# bright green, yellow, bright blue, bright magenta, bright cyan, white
+#
+DEPTH=4
+PENS=000,fff,830,7ac,181,c06,23e,c00,888,f60,4f4,ff0,4af,f8f,8ff,f00
+FGPENS= 0, 7, 4, 2, 6, 5, 3, 8, 1, 9,10,11,12,13,14, 1
+BGPENS= 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+#
+# Screen mode selections below should all work for either the font or tile
+# version of the game.  Other modes can be tried and as long as they are at
+# least 640x200, the game should adapt to them...
+#
+# Select screenmode with a requester
+#SCREENMODE=Req
+# NTSC_MONITOR_ID
+#SCREENMODE=0x00019000
+# PAL_MONITOR_ID
+#SCREENMODE=0x00029000
+# NTSC_MONITOR_ID+LACE
+#SCREENMODE=0x00019004
+# PAL_MONITOR_ID+LACE
+#SCREENMODE=0x00029004
+# NTSC_MONITOR_ID+HIRES+LACE
+#SCREENMODE=0x00019024
+# PAL_MONITOR_ID+HIRES+LACE
+#SCREENMODE=0x00029024
+# VGA_MONITOR_ID
+#SCREENMODE=0x00031000
+# VGAPRODUCT_KEY
+#SCREENMODE=0x00039024
+# A2024TENHERTZ_KEY
+#SCREENMODE=0x00041000
+# A2024FIFTEENHERTZ_KEY
+#SCREENMODE=0x00049000
+# EURO72_MONITOR_ID
+#SCREENMODE=0x00061000
+# EURO72PRODUCT_KEY
+#SCREENMODE=0x00069024
+# EURO72PRODUCTLACE_KEY
+#SCREENMODE=0x00069025
+# EURO72PRODUCTDBL_KEY
+#SCREENMODE=0x00069020
+# EURO36_MONITOR_ID
+#SCREENMODE=0x00071000
+# SUPER72HIRESDBL_KEY
+#SCREENMODE=0x00089008
+# SUPER72SUPERDBL_KEY
+#SCREENMODE=0x00089028
+# DBLNTSCHIRES_KEY
+#SCREENMODE=0x00099000
+# DBLNTSCHIRESFF_KEY
+#SCREENMODE=0x00099004
+# DBLNTSCHIRESLACE_KEY
+#SCREENMODE=0x00099005
+# DBLPALHIRES_KEY
+#SCREENMODE=0x000a9000
+# DBLPALHIRESFF_KEY
+#SCREENMODE=0x000a9004
+# DBLPALHIRESLACE_KEY
+#SCREENMODE=0x000a9005
diff --git a/sys/amiga/amidos.c b/sys/amiga/amidos.c
new file mode 100644 (file)
index 0000000..e5a975c
--- /dev/null
@@ -0,0 +1,490 @@
+/*    SCCS Id: @(#)amidos.c     3.2    2000/01/12
+/* Copyright (c) Olaf Seibert, Nijmegen, The Netherlands, 1988,1990.    */
+/* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1991,1992,1993,1996.  */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+/*
+ * An assortment of imitations of cheap plastic MSDOS and Unix functions.
+ */
+
+#include "hack.h"
+#include "winami.h"
+
+/* Defined in config.h, let's undefine it here (static function below) */
+#undef strcmpi
+
+#include <libraries/dos.h>
+#include <exec/execbase.h>
+#include <intuition/intuition.h>
+
+#undef COUNT
+#if defined(__SASC_60) || defined(__GNUC__)
+# include <proto/exec.h>
+# include <proto/dos.h>
+#endif
+
+#ifdef AZTEC_50
+# include <functions.h>
+# undef strcmpi
+#endif
+
+/* Prototypes */
+#include "NH:sys/amiga/winami.p"
+#include "NH:sys/amiga/amiwind.p"
+#include "NH:sys/amiga/amidos.p"
+
+extern char Initialized;
+extern struct window_procs amii_procs;
+
+#ifndef __SASC_60
+int Enable_Abort = 0;   /* for stdio package */
+#endif
+
+/* Initial path, so we can find NetHack.cnf */
+char PATH[PATHLEN] = "NetHack:";
+
+static boolean record_exists(void);
+
+void
+flushout()
+{
+    (void) fflush(stdout);
+}
+
+#ifndef getuid
+getuid()
+{
+    return 1;
+}
+#endif
+
+#ifndef getlogin
+char *
+getlogin()
+{
+    return ((char *) NULL);
+}
+#endif
+
+#ifndef AZTEC_50
+int
+abs(x)
+int x;
+{
+    return x < 0? -x: x;
+}
+#endif
+
+#ifdef SHELL
+int
+dosh()
+{
+    int i;
+    char buf[ BUFSZ ];
+    extern struct ExecBase *SysBase;
+
+    /* Only under 2.0 and later ROMs do we have System() */
+    if( SysBase->LibNode.lib_Version >= 37 && !amibbs)
+    {
+       getlin("Enter CLI Command...", buf );
+       if (buf[0] != '\033')
+           i = System( buf, NULL );
+    }
+    else
+    {
+       i = 0;
+       pline("No mysterious force prevented you from using multitasking.");
+    }
+    return i;
+}
+#endif /* SHELL */
+
+#ifdef MFLOPPY
+# include <ctype.h>
+
+# define Sprintf (void) sprintf
+
+#define EXTENSION   72
+
+/*
+ *  This routine uses an approximation of the free bytes on a disk.
+ *  How large a file you can actually write depends on the number of
+ *  extension blocks you need for it.
+ *  In each extenstion block there are maximum 72 pointers to blocks,
+ *  so every 73 disk blocks have only 72 available for data.
+ *  The (necessary) file header is also good for 72 data block pointers.
+ */
+/* TODO: update this for FFS */
+long
+freediskspace(path)
+char *path;
+{
+    register long freeBytes = 0;
+    register struct InfoData *infoData; /* Remember... longword aligned */
+    char fileName[32];
+
+    /*
+     *  Find a valid path on the device of which we want the free space.
+     *  If there is a colon in the name, it is an absolute path
+     *  and all up to the colon is everything we need.
+     *  Remember slashes in a volume name are allowed!
+     *  If there is no colon, it is relative to the current directory,
+     *  so must be on the current device, so "" is enough...
+     */
+    {
+    register char *colon;
+
+    strncpy(fileName, path, sizeof(fileName) - 1);
+    fileName[31] = 0;
+    if (colon = index(fileName, ':'))
+       colon[1] = '\0';
+    else
+       fileName[0] = '\0';
+    }
+    {
+    BPTR fileLock;
+    infoData = (struct InfoData *) alloc(sizeof(struct InfoData));
+    if (fileLock = Lock(fileName, SHARED_LOCK)) {
+       if (Info(fileLock, infoData)) {
+               /* We got a kind of DOS volume, since we can Lock it. */
+               /* Calculate number of blocks available for new file */
+               /* Kludge for the ever-full VOID: (oops RAM:) device */
+           if (infoData->id_UnitNumber == -1 &&
+             infoData->id_NumBlocks == infoData->id_NumBlocksUsed) {
+               freeBytes = AvailMem(0L) - 64 * 1024L;
+                   /* Just a stupid guess at the */
+                   /* Ram-Handler overhead per block: */
+               freeBytes -= freeBytes/16;
+           } else {
+               /* Normal kind of DOS file system device/volume */
+               freeBytes = infoData->id_NumBlocks - infoData->id_NumBlocksUsed;
+               freeBytes -= (freeBytes + EXTENSION) / (EXTENSION + 1);
+               freeBytes *= infoData->id_BytesPerBlock;
+           }
+           if (freeBytes < 0)
+               freeBytes = 0;
+       }
+       UnLock(fileLock);
+    }
+    free(infoData);
+    return freeBytes;
+    }
+}
+
+
+long
+filesize(file)
+char *file;
+{
+    register BPTR fileLock;
+    register struct FileInfoBlock *fileInfoBlock;
+    register long size = 0;
+
+    fileInfoBlock = (struct FileInfoBlock *)alloc(sizeof(struct FileInfoBlock));
+    if (fileLock = Lock(file, SHARED_LOCK)) {
+       if (Examine(fileLock, fileInfoBlock)) {
+           size = fileInfoBlock->fib_Size;
+       }
+       UnLock(fileLock);
+    }
+    free(fileInfoBlock);
+    return size;
+}
+
+#if 0
+void
+eraseall(path, files)
+const char *path, *files;
+{
+    BPTR dirLock, dirLock2;
+    struct FileInfoBlock *fibp;
+    int chklen;
+#ifdef BETA
+    if(files != alllevels)panic("eraseall");
+#endif
+    chklen=(int)index(files,'*')-(int)files;
+
+    if (dirLock = Lock( (char *)path ,SHARED_LOCK)) {
+       dirLock2=DupLock(dirLock);
+       dirLock2= CurrentDir(dirLock2);
+       fibp=AllocMem(sizeof(struct FileInfoBlock),0);
+       if(fibp){
+           if(Examine(dirLock,fibp)){
+               while(ExNext(dirLock,fibp)){
+                   if(!strncmp(fibp->fib_FileName,files,chklen)){
+                       DeleteFile(fibp->fib_FileName);
+                   }
+               }
+           }
+           FreeMem(fibp,sizeof(struct FileInfoBlock));
+       }
+       UnLock(dirLock);
+       UnLock(CurrentDir(dirLock2));
+    }
+}
+#endif
+
+/* This size makes that most files can be copied with two Read()/Write()s */
+
+#if 0 /* Unused */
+#define COPYSIZE    4096
+
+char *CopyFile(from, to)
+const char *from, *to;
+{
+    register BPTR fromFile, toFile;
+    register char *buffer;
+    register long size;
+    char *error = NULL;
+
+    buffer = (char *) alloc(COPYSIZE);
+    if (fromFile = Open( (char *)from, MODE_OLDFILE)) {
+       if (toFile = Open( (char *)to, MODE_NEWFILE)) {
+           while (size = Read(fromFile, buffer, (long)COPYSIZE)) {
+               if (size == -1){
+                   error = "Read error";
+                   break;
+               }
+               if (size != Write(toFile, buffer, size)) {
+                   error = "Write error";
+                   break;
+               }
+           }
+           Close(toFile);
+       } else
+           error = "Cannot open destination";
+       Close(fromFile);
+    } else
+       error = "Cannot open source (this should not occur)";
+    free(buffer);
+    return error;
+}
+#endif
+
+/* this should be replaced */
+saveDiskPrompt(start)
+{
+    char buf[BUFSIZ], *bp;
+    BPTR fileLock;
+
+    if (flags.asksavedisk) {
+           /* Don't prompt if you can find the save file */
+       if (fileLock = Lock(SAVEF, SHARED_LOCK)) {
+           UnLock(fileLock);
+#if defined(TTY_GRAPHICS)
+           if(windowprocs.win_init_nhwindows!=amii_procs.win_init_nhwindows)
+               clear_nhwindow( WIN_MAP );
+#endif
+#if defined(AMII_GRAPHICS)
+           if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows)
+               clear_nhwindow( WIN_BASE );
+#endif
+           return 1;
+       }
+       pline( "If save file is on a SAVE disk, put that disk in now." );
+       if( strlen( SAVEF ) > QBUFSZ - 25 - 22 )
+           panic( "not enough buffer space for prompt" );
+/* THIS IS A HACK */
+#if defined(TTY_GRAPHICS)
+       if(windowprocs.win_init_nhwindows!=amii_procs.win_init_nhwindows){
+           getlin("File name ?",buf);
+           clear_nhwindow( WIN_MAP );
+       }
+#endif
+#if defined(AMII_GRAPHICS)
+       if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows){
+           getlind("File name ?", buf, SAVEF);
+           clear_nhwindow( WIN_BASE );
+       }
+#endif
+       clear_nhwindow( WIN_MESSAGE);
+       if (!start && *buf == '\033')
+           return 0;
+
+    /* Strip any whitespace. Also, if nothing was entered except
+     * whitespace, do not change the value of SAVEF.
+     */
+       for (bp = buf; *bp; bp++) {
+           if (!isspace(*bp)) {
+           strncpy(SAVEF, bp, PATHLEN);
+           break;
+           }
+       }
+    }
+    return 1;
+}
+
+/* Return 1 if the record file was found */
+static boolean
+record_exists()
+{
+    FILE *file;
+
+    if (file = fopenp(RECORD, "r")) {
+       fclose(file);
+       return TRUE;
+    }
+    return FALSE;
+}
+
+#ifdef MFLOPPY
+/*
+ * Under MSDOS: Prompt for game disk, then check for record file.
+ * For Amiga: do nothing, but called from restore.c
+ */
+void
+gameDiskPrompt(){}
+#endif
+
+/*
+ * Add a slash to any name not ending in / or :.  There must
+ * be room for the /.
+ */
+void
+append_slash(name)
+char *name;
+{
+    char *ptr;
+
+    if (!*name)return;
+
+    ptr = eos(name) - 1;
+    if (*ptr != '/' && *ptr != ':') {
+       *++ptr = '/';
+       *++ptr = '\0';
+    }
+}
+
+
+void
+getreturn(str)
+const char *str;
+{
+    int ch;
+
+    raw_printf("Hit <RETURN> %s.", str);
+    while ((ch = nhgetch()) != '\n' && ch != '\r' )
+       continue;
+}
+
+/* Follow the PATH, trying to fopen the file.
+ */
+#define PATHSEP    ';'
+
+FILE *
+fopenp(name, mode)
+register const char *name, *mode;
+{
+    register char *bp, *pp, lastch;
+    register FILE *fp;
+    register BPTR theLock;
+    char buf[BUFSIZ];
+
+    /* Try the default directory first.  Then look along PATH.
+     */
+    if (strlen(name) >= BUFSIZ) return( NULL );
+    strcpy(buf, name);
+    if (theLock = Lock(buf, SHARED_LOCK)) {
+       UnLock(theLock);
+       if (fp = fopen(buf, mode))
+           return fp;
+    }
+    pp = PATH;
+    while (pp && *pp) {
+       bp = buf;
+       while (*pp && *pp != PATHSEP){
+           if( bp > buf + BUFSIZ - 1 ) return( NULL );
+           lastch = *bp++ = *pp++;
+       }
+       if (lastch != ':' && lastch != '/' && bp != buf)
+           *bp++ = '/';
+       if (bp + strlen(name) > buf + BUFSIZ - 1) return( NULL );
+       strcpy(bp, name);
+       if (theLock = Lock(buf, SHARED_LOCK)) {
+           UnLock(theLock);
+           if (fp = fopen(buf, mode)) return fp;
+       }
+       if (*pp)
+           pp++;
+    }
+    return NULL;
+}
+#endif /* MFLOPPY */
+
+#ifdef CHDIR
+
+/*
+ *  A not general-purpose directory changing routine.
+ *  Assumes you want to return to the original directory eventually,
+ *  by chdir()ing to orgdir (which is defined in pcmain.c).
+ *  Assumes -1 is not a valid lock, since 0 is valid.
+ */
+
+#define NO_LOCK     ((BPTR) -1)
+
+static BPTR OrgDirLock = NO_LOCK;
+
+chdir(dir)
+char *dir;
+{
+    extern char orgdir[];
+
+    if (dir == orgdir) {
+           /* We want to go back to where we came from. */
+       if (OrgDirLock != NO_LOCK) {
+           UnLock(CurrentDir(OrgDirLock));
+           OrgDirLock = NO_LOCK;
+       }
+    } else {
+           /*
+            * Go to some new place. If still at the original
+            * directory, save the FileLock.
+            */
+       BPTR newDir;
+
+       if (newDir = Lock( (char *)dir, SHARED_LOCK)) {
+           if (OrgDirLock == NO_LOCK) {
+               OrgDirLock = CurrentDir(newDir);
+           } else {
+               UnLock(CurrentDir(newDir));
+           }
+       } else {
+           return -1;  /* Failed */
+       }
+    }
+    /* CurrentDir always succeeds if you have a lock */
+    return 0;
+}
+
+#endif /* CHDIR */
+
+/* Chdir back to original directory
+ */
+#undef exit
+void
+nethack_exit(code)
+{
+#ifdef CHDIR
+    extern char orgdir[];
+#endif
+
+#ifdef CHDIR
+    chdir(orgdir);      /* chdir, not chdirx */
+#endif
+
+#ifdef AMII_GRAPHICS
+    if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows)
+       CleanUp();
+#endif
+    exit(code);
+}
+
+void
+regularize(s)    /* normalize file name - we don't like :'s or /'s */
+register char *s;
+{
+    register char *lp;
+
+    while((lp = index(s, ':')) || (lp = index(s, '/')))
+       *lp = '_';
+}
diff --git a/sys/amiga/amidos.p b/sys/amiga/amidos.p
new file mode 100644 (file)
index 0000000..ee91b3a
--- /dev/null
@@ -0,0 +1,42 @@
+/*    SCCS Id: @(#)amidos.p    3.1    93/01/08
+/* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1992, 1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* amidos.c */
+void NDECL(flushout );
+#ifndef        getuid
+int NDECL(getuid );
+#endif
+#ifndef        getpid
+int NDECL(getpid );
+#endif
+#ifndef        getlogin
+char *NDECL(getlogin );
+#endif
+#ifndef        abs
+int FDECL(abs, (int ));
+#endif
+int NDECL(tgetch );
+int NDECL(dosh );
+long FDECL(freediskspace, (char *));
+long FDECL(filesize, (char *));
+void FDECL(eraseall, (const char * , const char *));
+char *FDECL(CopyFile, (const char * , const char *));
+void FDECL(copybones, (int ));
+void NDECL(playwoRAMdisk );
+int FDECL(saveDiskPrompt, (int ));
+void NDECL(gameDiskPrompt );
+void FDECL(append_slash, (char *));
+void FDECL(getreturn, (const char *));
+#ifndef msmsg
+void FDECL(msmsg, ( const char *, ... ));
+#endif
+#if !defined(__SASC_60) && !defined(_DCC)
+int FDECL(chdir, (char *));
+#endif
+#ifndef        strcmpi
+int FDECL(strcmpi, (char * , char *));
+#endif
+#if !defined(memcmp) && !defined(AZTEC_C) && !defined(_DCC) && !defined(__GNUC__)
+int FDECL(memcmp, (unsigned char * , unsigned char * , int ));
+#endif
diff --git a/sys/amiga/amifont.uu b/sys/amiga/amifont.uu
new file mode 100644 (file)
index 0000000..3290ddc
--- /dev/null
@@ -0,0 +1,9 @@
+begin 777 hack.font
+M#P```6AA8VLO.```````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+G````````````````````````````````````````````````"`!`
+`
+end
diff --git a/sys/amiga/amifont8.uu b/sys/amiga/amifont8.uu
new file mode 100644 (file)
index 0000000..c6120e1
--- /dev/null
@@ -0,0 +1,59 @@
+begin 644 8
+M```#\P`````````!``````````````)E```#Z0```F5P_TYU```````````,
+M`````!H/@``!``````````````````````````````````````````!&140`
+M```````````,`````!H`````"20`"`!```@`!@`!```@_P```&X`M```!@X`
+M```````````8;&P8`#@8##````````,\&#P\''X<?CP\```,`#`\?!C\//C^
+M_CQF?@[F\(+&./PX_#Q^9L/&P\/^/,`\$``8`.``#@`<`.`8!N`X````````
+M``@````````.&'!RS.?BY^?EY^?GY^?GY.?AY^?__\,8`&;GY^?GY^3GX>?G
+MYVH```!J:A@````8&!@``!@88L!6`%96```8`!@8`*@5P8.BP:@5YP/_[W_^
+M````P,```P`\;&P^QFP8&!AF&`````9F.&9F/&`P9F9F&!@8`!AFQCQF9FQF
+M9F9F&`9F8,;F;&9L9F9:9L/&9L/&,&`,.``8`&``!@`V`&```&`8````````
+M`!@````````8&!B<,Z6BH:&EI*2AI:6EI*2AI*3__\,8`&:DH:6EI:2DH:2D
+MI58```!65CP````8&!@``!@\96-J`&IJ```8`!@8UB/$`\`C+"O4A`/_]Y_Y
+M````P,```P`\`/Y@S&@P,`P\&`````QN&`8&;'Q@!F9F&!@P?@P&WCQFP&9@
+M8,!F&`9L8.[VQF;&9G`89F;&/&:,,#`,;``,/&P\-CPP.VPX!F889GP\W#WL
+M/CYF9F-C9GX8&!@`S.7BY^?GY^?AY^?GY^3GY^?_`.<8`,/GX>?GY^?DY^?G
+MY6K_#_!KZCP````8&!@``!AF8#97_];7`&8<`#@\;&I6)F1I/&F6YP./]]_[
+M#__PP,```P`8`&P\&'8`,`S_?@!^`!A^&!P<S`9\##P^``!@``8,WF9\P&9X
+M>,Y^&`9X8/[>QGS&?#@89F;6&#P8,!@,Q@``!G9F;F9X9G88!FP8=V9F9F9V
+M8!AF9FLV9DQP&`X`,Z6BI*&AH:6AI:&EI:2EI*3_`.<8_P`E(24A)24D)20D
+MI595/5Q55F;_#_`/\/\``-O#?AMJ5:JJ```?__C_JIPY:];X*]I;A`-F[\_S
+M.``<P&``!@`8`/X&,-P`,`P\&````#!V&#`&_@9F&&8&```P``P8WGYFP&9@
+M8,9F&&9L8M;.QF#&;`X89CS^/!@R,`P,````'F9@9GXP9F88!G@8:V9F9F9F
+M/!AF9FL<9A@8&!@`S.?BY^?AY^?AY^'EY^?GY^3_`.<8_P`G(2<A)2<G)R<D
+MIVJJ:JHZK&8`&!@``!@``,/;9NQ5JE95&``</#@`;&O6G#DK^#?LYP/Q[_//
+M8``&P#@`'````&Q\9LP`&!AF&!@`&&!F&&9F#&9F&&8,&!@8?A@`P,-F9FQF
+M8&9F&&9F9L;&;&!L9F889CSN9AAF,`8,````9F9F9F`P/&88!FP88V9F?#Y@
+M!AIF/#8V/#(8&!@`,P````````````````````#_`.<8`,,`````````````
+M`%;_5=8/\,,`&!@``!AS`&889C9KU^K_```8&!@`UB9D:E8\:;0M``/_W_O?
+MP``#P`__\``8`&P8QG8`##```!@`&,`\?GX\'CP\&#PX&!@,`#`8>,/\//C^
+M\#YF?CSF_L;&./`\XSP\/AC&PSS^/`,\````.SP\.SQXQN8\9N8\8V8\8`;P
+M?`P[&#9C&'X.&'``S`````````````````````#__\,8`&8`````````````
+M`&H`:VH``,,`&!@``!B<&#P89F-6:E8``&88&!@`K`/`(\0L(T&"``/_W_F?
+MP``#P````````````````````#```````````````````#``````````````
+M```````````````&`````````````````/X`````````?```/```````\`<`
+M````````<```````,P````````````````````#__\,8`&8`````````````
+M`%8`5E8`````&!@``!@``!@8`,!J5FH````8&!@``,&#J!7!HL&#``/_[_Y_
+MP``#P`````````@`"``(`!``"``8``@`(``(`"@`"``P``@`.``(`$``"`!(
+M``@`4``(`%@`"`!@``@`:``(`'``"`!X``@`@``(`(@`"`"0``@`F``(`*``
+M"`"H``@`L``(`+@`"`#```@`R``(`-``"`#8``@`X``(`.@`"`#P``@`^``(
+M`0``"`$(``@!$``(`1@`"`$@``@!*``(`3``"`$X``@!0``(`4@`"`%0``@!
+M6``(`6``"`%H``@!<``(`7@`"`&```@!B``(`9``"`&8``@!H``(`:@`"`&P
+M``@!N``(`<``"`'(``@!T``(`=@`"`'@``@!Z``(`?``"`'X``@"```(`@@`
+M"`(0``@"&``(`B``"`(H``@",``(`C@`"`)```@"2``(`E``"`)8``@"8``(
+M`F@`"`)P``@">``(`H``"`*(``@"D``(`I@`"`*@``@"J``(`K``"`*X``@"
+MP``(`L@`"`+0``@"V``(`N``"`+H``@"\``(`O@`"`,```@#"``(`Q``"`,8
+M``@#(``(`R@`"`,P``@#.``(`T``"`-(``@#4``(`U@`"`-@``@#:``(`W``
+M"`-X``@#@``(`X@`"`.0``@#F``(`Z``"`.H``@#L``(`[@`"`/```@#R``(
+M`]``"`/8``@#X``(`^@`"`/P``@#^``(!```"``(``@`$``(`!@`"``@``@`
+M*``(`#``"``X``@`0``(`$@`"`!0``@`6``(`&``"`!H``@`<``(`'@`"`"`
+M``@`B``(`)``"`"8``@`H``(`*@`"`"P``@`N``(`,``"`#(``@`T``(`-@`
+M"`#@``@`Z``(`/``"`#X``@$"``(!!``"`08``@$(``(!"@`"`0P``@#J``(
+M!#@`"`.8``@$0``(!$@`"`10``@$6``(!&``"`1H``@$<``(!'@`"`2```@$
+MB``(!)``"`28``@$H``(!*@`"`2P``@$N``(!,``"`3(``@!V``(`>``"`'H
+M``@!\``(`?@`"`(```@$T``(!-@`"`3@``@$Z``(!/``"`3X``@%```(!0@`
+M"`40``@%&``(!2``"`4H``@%,``(!3@`"`5```@%2``(!5``"`58``@%8``(
+M!6@`"`5P``@%>``(!8``"`6(``@%D``(!9@`"`+8``@"X``(`N@`"`+P``@"
+M^``(````"``````#[`````0`````````#@```$0```!<````8@````````/R
+`
+end
diff --git a/sys/amiga/amigst.c b/sys/amiga/amigst.c
new file mode 100644 (file)
index 0000000..04859c4
--- /dev/null
@@ -0,0 +1,43 @@
+/*    SCCS Id: @(#)amigst.c     3.1    93/01/08
+/*    Copyright (c) Gregg Wonderly, Naperville, IL, 1992, 1993   */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include <stdio.h>
+#include <exec/types.h>
+#include <exec/io.h>
+#include <exec/alerts.h>
+#include <exec/devices.h>
+#include <devices/console.h>
+#include <devices/conunit.h>
+#include <graphics/gfxbase.h>
+#include <intuition/intuition.h>
+#include <libraries/dosextens.h>
+#include <ctype.h>
+#undef  strcmpi
+#include <string.h>
+#include <errno.h>
+
+#ifdef __SASC
+#include <dos.h>        /* for __emit */
+#include <string.h>
+#include <proto/dos.h>
+#include <proto/exec.h>
+#include <proto/graphics.h>
+#include <proto/intuition.h>
+#include <proto/diskfont.h>
+#include <proto/console.h>
+#endif
+
+#include "hack.h"
+#include "winprocs.h"
+#include "winami.h"
+
+#ifdef AZTEC
+#include <functions.h>
+#endif
+
+#include "NH:sys/amiga/winami.p"
+#include "NH:sys/amiga/amiwind.p"
+#include "NH:sys/amiga/amidos.p"
+
+/* end amigst.c */
diff --git a/sys/amiga/amii.hlp b/sys/amiga/amii.hlp
new file mode 100644 (file)
index 0000000..c014e42
--- /dev/null
@@ -0,0 +1,31 @@
+            Amiga-specific help file for NetHack 3.4
+
+The Amiga port of NetHack supports a number of additional commands
+and facilities specific to the Amiga.  Listed below are the things
+which are either specific to the Amiga port or might not appear
+in other ports.
+
+While playing NetHack you can press:
+
+        ALT-HELP                Color requestor.
+        CTL-HELP                Scale display (amitile only).
+        SHIFT-HELP              Overview window (amitile only).
+
+Amiga-specific run-time options:
+        altmeta                 use the alt keys as meta keys
+        flush                   throw away keyboard type-ahead
+
+Command line options recognized are
+
+        -n                      No News at game startup.
+        -X                      Play in discovery mode.
+        -D                      Play in debug mode.
+        -L                      Interlaced screen.
+        -l                      Never Interlaced screen.
+        -u                      Play as player given as
+                                an argument.
+        -r                      Pick a race given as an
+                                argument.
+        -p                      Pick a profession given
+                                as an argument
+        -?                      Gives command line usage.
diff --git a/sys/amiga/amimenu.c b/sys/amiga/amimenu.c
new file mode 100644 (file)
index 0000000..422dfba
--- /dev/null
@@ -0,0 +1,95 @@
+/*    SCCS Id: @(#)amimenu.c    3.2    96/02/04                           */
+/*    Copyright (c) Olaf 'Rhialto' Seibert, 1989                  */
+/*    Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1992, 1993, 1996 */
+/*    Copyright (c) Janne Salmijärvi, 2000 */
+/* NetHack may be freely redistributed.  See license for details.  */
+
+/*  Originally by John Toebes.  */
+
+/*  GadTools menus by jhsa */
+
+struct NewMenu GTHackMenu[] = {
+    { NM_TITLE, "Commands",                                0, 0, 0, 0},
+    {  NM_ITEM, "?   Display help menu",                   0, 0, 0, (void *)'?'},
+    {  NM_ITEM, "&   Explain a command",                   0, 0, 0, (void *)'&'},
+    {  NM_ITEM, "O   Set options",                         0, 0, 0, (void *)'O'},
+    {  NM_ITEM, "!   AmigaDos command",                    0, 0, 0, (void *)'!'},
+    {  NM_ITEM, "v   Version number",                      0, 0, 0, (void *)'v'},
+    {  NM_ITEM, "V   Long version and game history",       0, 0, 0, (void *)'V'},
+    {  NM_ITEM, "^R  Redraw screen",                       0, 0, 0, (void *)022},
+    {  NM_ITEM, "^P  Repeat previous messages",            0, 0, 0, (void *)020},
+    {  NM_ITEM, "M-q #quit the game",                      0, 0, 0, (void *)(128+'q')},
+    {  NM_ITEM, "S   Save the game",                       0, 0, 0, (void *)'S'},
+    { NM_TITLE, "Inventory",                               0, 0, 0, 0},
+    {  NM_ITEM, "i   Inventory",                           0, 0, 0, (void *)'i'},
+    {  NM_ITEM, "p   Pay your bill",                       0, 0, 0, (void *)'p'},
+    {  NM_ITEM, "d   Drop an object",                      0, 0, 0, (void *)'d'},
+    {  NM_ITEM, "D   Drop several things",                 0, 0, 0, (void *)'D'},
+    {  NM_ITEM, ",   Pickup an object",                    0, 0, 0, (void *)','},
+    {  NM_ITEM, "@   Toggle pickup",                       0, 0, 0, (void *)'@'},
+    {  NM_ITEM, "/   Identify something",                  0, 0, 0, (void *)'/'},
+    {  NM_ITEM, "C   Christen a monster",                  0, 0, 0, (void *)'C'},
+    {  NM_ITEM, "+   List known spells",                   0, 0, 0, (void *)'+'},
+    {  NM_ITEM, "$   Your gold",                           0, 0, 0, (void *)'$'},
+    { NM_TITLE, "Actions",                                 0, 0, 0, 0},
+    {  NM_ITEM, "a   Apply/use something",                 0, 0, 0, (void *)'a'},
+    {  NM_ITEM, "e   Eat something",                       0, 0, 0, (void *)'e'},
+    {  NM_ITEM, "f   Fire ammunition",                     0, 0, 0, (void *)'f'},
+    {  NM_ITEM, "F   Fight a monster",                     0, 0, 0, (void *)'F'},
+    {  NM_ITEM, "q   Quaff a monster",                     0, 0, 0, (void *)'q'},
+    {  NM_ITEM, "r   Read scroll/book",                    0, 0, 0, (void *)'r'},
+    {  NM_ITEM, "t   Throw something",                     0, 0, 0, (void *)'t'},
+    {  NM_ITEM, "z   Zap a wand",                          0, 0, 0, (void *)'z'},
+    {  NM_ITEM, "Z   Cast a spell",                        0, 0, 0, (void *)'Z'},
+    { NM_TITLE, "Preparations",                            0, 0, 0, 0},
+    {  NM_ITEM, "A   Remove all armor",                    0, 0, 0, (void *)'A'},
+    {  NM_ITEM, "P   Put on a ring",                       0, 0, 0, (void *)'P'},
+    {  NM_ITEM, "R   Remove ring",                         0, 0, 0, (void *)'R'},
+    {  NM_ITEM, "Q   Select ammunition for quiver",        0, 0, 0, (void *)'Q'},
+    {  NM_ITEM, "T   Take off armor",                      0, 0, 0, (void *)'T'},
+    {  NM_ITEM, "w   Wield a weapon",                      0, 0, 0, (void *)'w'},
+    {  NM_ITEM, "W   Wear armor",                          0, 0, 0, (void *)'W'},
+    {  NM_ITEM, "x   Swap wielded and secondary weapons",  0, 0, 0, (void *)'x'},
+    {  NM_ITEM, ")   Current weapon",                      0, 0, 0, (void *)')'},
+    {  NM_ITEM, "[   Current armor",                       0, 0, 0, (void *)'['},
+    {  NM_ITEM, "=   Current rings",                       0, 0, 0, (void *)'='},
+    {  NM_ITEM,"\"   Current amulet",                      0, 0, 0, (void *)'"'},
+    {  NM_ITEM, "(   Current tools",                       0, 0, 0, (void *)'('},
+    {  NM_ITEM, "*   Current equipment",                   0, 0, 0, (void *)'*'},
+    { NM_TITLE, "Movement",                                0, 0, 0, 0},
+    {  NM_ITEM, "o   Open door",                           0, 0, 0, (void *)'o'},
+    {  NM_ITEM, "c   Close door",                          0, 0, 0, (void *)'c'},
+    {  NM_ITEM, "^D  Kick door",                           0, 0, 0, (void *)004},
+    {  NM_ITEM, "s   Search",                              0, 0, 0, (void *)'s'},
+    {  NM_ITEM, "<   Go up stairs",                        0, 0, 0, (void *)'<'},
+    {  NM_ITEM, ">   Go down stairs",                      0, 0, 0, (void *)'>'},
+    {  NM_ITEM, "^T  Teleport",                            0, 0, 0, (void *)024},
+    {  NM_ITEM, ".   Wait a moment",                       0, 0, 0, (void *)'.'},
+    {  NM_ITEM, "E   Engrave message on floor",            0, 0, 0, (void *)'E'},
+    { NM_TITLE, "Extended",                                0, 0, 0, 0},
+    {  NM_ITEM, "M-a  #adjust inventory letters",          0, 0, 0, (void *)(128+'a')},
+    {  NM_ITEM, "M-c  #chat with someone",                 0, 0, 0, (void *)(128+'c')},
+    {  NM_ITEM, "M-d  #dip an object into something",      0, 0, 0, (void *)(128+'d')},
+#ifdef WEAPON_SKILLS
+    {  NM_ITEM, "M-e  #enhance weapon skills",             0, 0, 0, (void *)(128+'e')},
+#endif
+    {  NM_ITEM, "M-f  #force a lock",                      0, 0, 0, (void *)(128+'f')},
+    {  NM_ITEM, "M-i  #invoke an object's special powers", 0, 0, 0, (void *)(128+'i')},
+    {  NM_ITEM, "M-j  #jump to another location",          0, 0, 0, (void *)(128+'j')},
+    {  NM_ITEM, "M-l  #loot a box on the floor",           0, 0, 0, (void *)(128+'l')},
+    {  NM_ITEM, "M-m  Use a #monster's special ability",   0, 0, 0, (void *)(128+'m')},
+    {  NM_ITEM, "M-n  #name an item or type of object",    0, 0, 0, (void *)(128+'n')},
+    {  NM_ITEM, "M-o  #offer a sacrifice to the gods",     0, 0, 0, (void *)(128+'o')},
+    {  NM_ITEM, "M-p  #pray to the gods for help",         0, 0, 0, (void *)(128+'p')},
+    {  NM_ITEM, "M-q  #quit the game",                     0, 0, 0, (void *)(128+'q')},
+    {  NM_ITEM, "M-r  #rub a lamp",                        0, 0, 0, (void *)(128+'r')},
+    {  NM_ITEM, "M-s  #sit down",                          0, 0, 0, (void *)(128+'s')},
+    {  NM_ITEM, "M-t  #turn undead",                       0, 0, 0, (void *)(128+'t')},
+    {  NM_ITEM, "M-u  #untrap something",                  0, 0, 0, (void *)(128+'u')},
+    {  NM_ITEM, "M-v  Long #version information",          0, 0, 0, (void *)(128+'v')},
+    {  NM_ITEM, "M-w  #wipe off your face",                0, 0, 0, (void *)(128+'w')},
+    {  NM_ITEM, "     Your #conduct",                      0, 0, 0, (void *)'#'}, /* "#co\n" */
+    {  NM_ITEM, "     #ride your steed",                   0, 0, 0, (void *)'#'}, /* "#ri\n" */
+    {  NM_ITEM, "M-2  Switch #twoweapon mode on/off",      0, 0, 0, (void *)(128+'2')},
+    {  NM_END,  NULL,                                      0, 0, 0, 0}
+};
diff --git a/sys/amiga/amirip.c b/sys/amiga/amirip.c
new file mode 100644 (file)
index 0000000..c41110a
--- /dev/null
@@ -0,0 +1,405 @@
+/*     SCCS Id: @(#)amirip.c   3.2     96/02/04        */
+/* Copyright (c) Kenneth Lorber, Bethesda, Maryland 1991,1992,1993,1995,1996. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include <exec/types.h>
+#include <exec/io.h>
+#include <exec/alerts.h>
+#include <exec/devices.h>
+#include <devices/console.h>
+#include <devices/conunit.h>
+#include <graphics/gfxbase.h>
+#include <graphics/gfxmacros.h>
+#include <intuition/intuition.h>
+#include <libraries/dosextens.h>
+#include <ctype.h>
+#include <string.h>
+#include "winami.h"
+#include "windefs.h"
+#include "winext.h"
+#include "winproto.h"
+
+static struct RastPort *rp;
+
+#ifdef AMII_GRAPHICS
+
+#undef  NULL
+#define NULL    0
+
+#ifdef AZTEC_C
+# include <functions.h>
+#else
+# ifdef _DCC
+#  include <clib/dos_protos.h>
+#  include <clib/exec_protos.h>
+#  include <clib/console_protos.h>
+#  include <clib/diskfont_protos.h>
+# else
+#  include <proto/dos.h>
+#  include <proto/exec.h>
+#  include <proto/console.h>
+#  include <proto/diskfont.h>
+# endif
+
+static char *load_list[]={"tomb.iff",0};
+static BitMapHeader tomb_bmhd;
+static struct BitMap *tbmp[ 1 ] = {0};
+
+static int cols[2]={154,319};          /* X location of center of columns */
+static int cno = 0;                    /* current column */
+#define TEXT_TOP (65+yoff)
+
+static xoff, yoff;                     /* image centering */
+
+/* terrible kludge */
+/* this is why prototypes should have ONLY types in them! */
+# undef red
+# undef green
+# undef blue
+# undef index
+# ifdef _DCC
+#  include <clib/graphics_protos.h>
+#  include <clib/intuition_protos.h>
+# else
+#  include <proto/graphics.h>
+#  include <proto/intuition.h>
+# endif
+#endif /* AZTEC_C */
+
+extern char *killed_by_prefix[];
+static struct Window *ripwin=0;
+static void tomb_text(char*);
+static void dofade(int,int,int);
+static int search_cmap(int,int,int);
+
+#define STONE_LINE_LEN 13   /* # chars that fit on one line
+                            * (note 1 ' ' border) */
+
+#define DEATH_LINE  10
+#define YEAR_LINE   15
+
+static unsigned short tomb_line;
+
+extern struct amii_DisplayDesc *amiIDisplay;
+extern struct Screen *HackScreen;
+extern int havelace;
+
+static unsigned short transpalette[ AMII_MAXCOLORS ] = { 0x0000,  };
+
+static struct NewWindow newwin =
+{
+    0,0,640,200,1,0,
+    MOUSEBUTTONS|VANILLAKEY|NOCAREREFRESH,
+    BORDERLESS|ACTIVATE|SMART_REFRESH,
+    NULL,NULL,(UBYTE*)NULL,NULL,NULL,-1,-1,0xffff,0xffff,CUSTOMSCREEN
+};
+
+int wh; /* was local in outrip, but needed for SCALE macro */
+
+int cmap_white, cmap_black;
+
+void
+amii_outrip( tmpwin, how )
+winid tmpwin;
+int how;
+{
+    int just_return = 0;
+    int done, rtxth;
+    struct IntuiMessage *imsg;
+    int i;
+    register char *dpx;
+    char buf[ 200 ];
+    int line, tw, ww;
+    char *errstr = NULL;
+
+    if(!WINVERS_AMIV || HackScreen->RastPort.BitMap->Depth < 4)goto cleanup;
+
+    /* Use the users display size */
+    newwin.Height = amiIDisplay->ypix - newwin.TopEdge;
+    newwin.Width = amiIDisplay->xpix;
+    newwin.Screen = HackScreen;
+
+    for( i = 0; i < amii_numcolors; ++i )
+       flags.amii_curmap[i] = GetRGB4( HackScreen->ViewPort.ColorMap, i );
+
+    ripwin = OpenWindow( (void *)&newwin );
+    if( !ripwin ) goto cleanup;
+
+    LoadRGB4( &HackScreen->ViewPort, transpalette, amii_numcolors );
+
+    rp= ripwin->RPort;
+    wh = ripwin->Height;
+    ww = ripwin->Width;
+
+#ifdef HACKFONT
+    if (HackFont)
+       SetFont(rp, HackFont);
+#endif
+
+    tomb_bmhd = ReadImageFiles(load_list, tbmp, &errstr );
+    if(errstr)goto cleanup;
+    if(tomb_bmhd.w > ww || tomb_bmhd.h > wh)goto cleanup;
+
+#define GENOFF(full,used) ((((full)-(used))/2) & ~7)
+    xoff = GENOFF(ww,tomb_bmhd.w);
+    yoff = GENOFF(wh,tomb_bmhd.h);
+    for(i=0;i<SIZE(cols);i++)cols[i]+=xoff;
+
+    cmap_white = search_cmap(0,0,0);
+    cmap_black = search_cmap(15,15,15);
+
+    BltBitMap(*tbmp, 0, 0, rp->BitMap, xoff, yoff, tomb_bmhd.w, tomb_bmhd.h, 0xc0, 0xff, NULL);
+
+    /* Put together death description */
+    switch (killer_format) {
+    default:
+       impossible("bad killer format?");
+    case KILLED_BY_AN:
+       Strcpy(buf, killed_by_prefix[how]);
+       Strcat(buf, an(killer));
+       break;
+    case KILLED_BY:
+       Strcpy(buf, killed_by_prefix[how]);
+       Strcat(buf, killer);
+       break;
+    case NO_KILLER_PREFIX:
+       Strcpy(buf, killer);
+       break;
+    }
+
+    tw = TextLength(rp,buf,STONE_LINE_LEN) + 40;
+
+    {
+       char *p=buf;
+       int x, tmp;
+       for(x=STONE_LINE_LEN;x;x--)*p++='W';
+       *p='\0';
+       tmp = TextLength(rp,buf,STONE_LINE_LEN) + 40;
+       tw = max( tw, tmp);
+    }
+
+    /* There are 5 lines of text on the stone. */
+    rtxth = ripwin->RPort->TxHeight * 5;
+
+    SetAfPt( rp, (UWORD *)NULL, 0 );
+    SetDrPt( rp, 0xFFFF );
+
+    tomb_line=TEXT_TOP;
+
+    SetDrMd(rp,JAM1);
+
+    /* Put name on stone */
+    Sprintf(buf, "%s", plname);
+    buf[STONE_LINE_LEN] = 0;
+    tomb_text(buf);
+
+    /* Put $ on stone */
+    Sprintf(buf, "%ld Au",
+#ifndef GOLDOBJ
+               u.ugold);
+#else
+               done_money);
+#endif
+    buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */
+    tomb_text(buf);
+
+    /* Put together death description */
+    switch (killer_format) {
+    default:
+       impossible("bad killer format?");
+    case KILLED_BY_AN:
+       Strcpy(buf, killed_by_prefix[how]);
+       Strcat(buf, an(killer));
+       break;
+    case KILLED_BY:
+       Strcpy(buf, killed_by_prefix[how]);
+       Strcat(buf, killer);
+       break;
+    case NO_KILLER_PREFIX:
+       Strcpy(buf, killer);
+       break;
+    }
+
+    /* Put death type on stone */
+    for (line=DEATH_LINE, dpx = buf; line<YEAR_LINE; line++)
+    {
+       register int i,i0;
+       char tmpchar;
+
+       if ( (i0=strlen(dpx)) > STONE_LINE_LEN)
+       {
+           for(i=STONE_LINE_LEN;((i0 > STONE_LINE_LEN) && i); i--)
+           {
+               if(dpx[i] == ' ')
+                   i0 = i;
+           }
+           if(!i)
+               i0 = STONE_LINE_LEN;
+       }
+
+       tmpchar = dpx[i0];
+       dpx[i0] = 0;
+       tomb_text(dpx);
+
+       if (tmpchar != ' ')
+       {
+           dpx[i0] = tmpchar;
+           dpx= &dpx[i0];
+       }
+       else
+       {
+           dpx= &dpx[i0+1];
+       }
+    }
+
+    /* Put year on stone */
+    Sprintf(buf, "%4d", getyear());
+    tomb_text(buf);
+
+#ifdef NH320_DEDICATION
+    /* dedication */
+    cno = 1;
+    tomb_line=TEXT_TOP;
+    tomb_text("This release");
+    tomb_text("of NetHack");
+    tomb_text("is dedicated");
+    tomb_text("to the");
+    tomb_text("memory of");
+    tomb_text("");
+    tomb_text("Izchak");
+    tomb_text(" Miller");
+    tomb_text("");
+    tomb_text("1935-1994");
+    tomb_text("");
+    tomb_text("Ascended");
+#endif
+    /* Fade from black to full color */
+    dofade(0,16,1);
+
+    /* Flush all messages to avoid typeahead */
+    while( imsg = (struct IntuiMessage *)GetMsg( ripwin->UserPort ) )
+       ReplyMsg( (struct Message *) imsg );
+    done = 0;
+    while( !done )
+    {
+       WaitPort( ripwin->UserPort );
+       while( imsg = (struct IntuiMessage *)GetMsg(ripwin->UserPort) )
+       {
+           switch( imsg->Class )
+           {
+               case MOUSEBUTTONS:
+               case VANILLAKEY:
+                   done = 1;
+                   break;
+           }
+           ReplyMsg( (struct Message *)imsg );
+       }
+    }
+
+    /* Fade out */
+    dofade(16,0,-1);
+    just_return = 1;
+
+cleanup:
+       /* free everything */
+    if(ripwin){
+       Forbid();
+       while( imsg = (struct IntuiMessage *)GetMsg( ripwin->UserPort ) )
+           ReplyMsg( (struct Message *)imsg );
+       CloseWindow( ripwin );
+       Permit();
+    }
+    LoadRGB4( &HackScreen->ViewPort, flags.amii_curmap, amii_numcolors );
+
+    if(tbmp[0])FreeImageFiles(load_list, tbmp);
+    if(just_return) return;
+       /* fall back to the straight-ASCII version */
+    genl_outrip(tmpwin, how);
+}
+
+static void tomb_text(p)
+char *p;
+{
+    char buf[STONE_LINE_LEN*2];
+    int l;
+
+    tomb_line += rp->TxHeight;
+
+    if( !*p )
+       return;
+    sprintf(buf," %s ",p);
+    l=TextLength(rp,buf,strlen(buf));
+
+    SetAPen(rp,cmap_white);
+    Move(rp,cols[cno]-(l/2)-1, tomb_line);
+    Text(rp,buf,strlen(buf));
+
+    SetAPen(rp,cmap_white);
+    Move(rp,cols[cno]-(l/2)+1, tomb_line);
+    Text(rp,buf,strlen(buf));
+
+    SetAPen(rp,cmap_white);
+    Move(rp,cols[cno]-(l/2), tomb_line-1);
+    Text(rp,buf,strlen(buf));
+
+    SetAPen(rp,cmap_white);
+    Move(rp,cols[cno]-(l/2), tomb_line+1);
+    Text(rp,buf,strlen(buf));
+
+    SetAPen(rp,cmap_black);
+    Move(rp,cols[cno]-(l/2), tomb_line);
+    Text(rp,buf,strlen(buf));
+}
+
+/* search colormap for best match to given color */
+static int
+search_cmap(int r0, int g0, int b0){
+    int best = 0;
+    int bdiff = 0x0fffffff;
+    int x;
+    for(x=0;x<amii_numcolors; x++){
+       int r = r0- ((amiv_init_map[x] >> 8) & 15);
+       int g = g0-((amiv_init_map[x] >> 4) & 15);
+       int b = b0-((amiv_init_map[x] ) & 15);
+       int diff = (r*r) + (g*g) + (b*b);
+       if(diff<bdiff){
+           bdiff = diff;
+           best = x;
+       }
+    }
+    return best;
+}
+
+/* caution: this is NOT general! */
+static void
+dofade(int start, int stop, int inc){
+    int i,j;
+    for( i = start; (i*inc) <= stop; i+=inc )
+    {
+       for( j = 0; j < amii_numcolors; ++j )
+       {
+           int r, g, b;
+
+           r = ( amiv_init_map[ j ] & 0xf00 ) >> 8;
+           g = ( amiv_init_map[ j ] & 0xf0 ) >> 4;
+           b = ( amiv_init_map[ j ] & 0xf );
+           r = ( r * i ) / 16;
+           g = ( g * i ) / 16;
+           b = ( b * i ) / 16;
+           transpalette[ j ] = ((r<<8)|(g<<4)|b);
+       }
+       LoadRGB4( &HackScreen->ViewPort, transpalette, amii_numcolors );
+       Delay( 1 );
+    }
+}
+
+
+
+#endif /* AMII_GRAPHICS */
+
+/*
+TODO:
+       memory leaks
+       fix ReadImageFiles to return error instead of panic on error
+*/
diff --git a/sys/amiga/amisnd.c b/sys/amiga/amisnd.c
new file mode 100644 (file)
index 0000000..85a007d
--- /dev/null
@@ -0,0 +1,284 @@
+/*     SCCS Id: @(#)amisnd.c   3.2     2000/01/12*/
+/*     Copyright (c) 1992, 1993, 1995 by Gregg Wonderly */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file contains music playing code.
+ *
+ * If we were REALLY determined, we would make the sound play
+ * asynchronously, but I'll save that one for a rainy day...
+ */
+
+#include "hack.h"
+#include "dlb.h"
+
+#undef red
+#undef blue
+#undef green
+#include <exec/types.h>
+#include <exec/memory.h>
+#include <exec/io.h>
+#include <devices/audio.h>
+#include <dos/dos.h>
+#include <dos/dosextens.h>
+#include <graphics/gfxbase.h>
+
+#include <proto/exec.h>
+#include <clib/alib_protos.h>
+#include <proto/dos.h>
+#include <proto/graphics.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define        AMII_AVERAGE_VOLUME     60
+
+int amii_volume = AMII_AVERAGE_VOLUME;
+
+typedef struct VHDR
+{
+       char name[4];
+       long len;
+       unsigned long oneshot, repeat, samples;
+       UWORD freq;
+       UBYTE n_octaves, compress;
+       LONG volume;
+} VHDR;
+
+typedef struct IFFHEAD
+{
+       char FORM[4];
+       long flen;
+       char _8SVX[4];
+       VHDR vhdr;
+       char NAME[4];
+       long namelen;
+} IFFHEAD;
+
+extern struct GfxBase *GfxBase;
+
+UBYTE whichannel[] = { 1, 2, 4, 8 };
+void makesound( char *, char *, int vol);
+void amii_speaker( struct obj *instr, char *melody, int vol );
+
+/* A major scale in indexs to freqtab... */
+int notetab[] = { 0, 2, 4, 5, 7, 9, 11, 12 };
+
+/* Frequencies for a scale starting at one octave below 'middle C' */
+long freqtab[] = {
+       220,    /*A */
+       233,    /*Bb*/
+       246,    /*B */
+       261,    /*C */
+       277,    /*Db*/
+       293,    /*D */
+       311,    /*Eb*/
+       329,    /*E */
+       349,    /*F */
+       370,    /*Gb*/
+       392,    /*G */
+       415,    /*Ab*/
+       440,    /*A */
+};
+
+#ifdef TESTING
+main( argc, argv )
+       int argc;
+       char **argv;
+{
+       makesound( "wooden_flute", "AwBwCwDwEwFwGwawbwcwdwewfwgw", 60 );
+       makesound( "wooden_flute", "AhBhChDhEhFhGhahbhchdhehfhgh", 60 );
+       makesound( "wooden_flute", "AqBqCqDqEqFqGqaqbqcqdqeqfqgq", 60 );
+       makesound( "wooden_flute", "AeBeCeDeEeFeGeaebecedeeefege", 60 );
+       makesound( "wooden_flute", "AxBxCxDxExFxGxaxbxcxdxexfxgx", 60 );
+       makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
+       makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
+       makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
+       makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
+       makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
+       makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
+       makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
+       makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
+       makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
+}
+#else
+void
+amii_speaker( struct obj *instr, char *melody, int vol )
+{
+       int typ = instr->otyp;
+       char * actualn = (char *)OBJ_NAME( objects[typ] ) ;
+
+       /* Make volume be relative to users volume level, with 60 being the
+        * average level that will be passed to us.
+        */
+       vol = vol * amii_volume / AMII_AVERAGE_VOLUME;
+
+       makesound( actualn, melody, vol );
+}
+#endif
+
+void
+makesound ( char *actualn , char * melody, int vol )
+{
+       char *t;
+       int c, cycles, dot, dlay;
+       dlb *stream = 0;
+       IFFHEAD iffhead;
+       struct IOAudio *AudioIO = 0;
+       struct MsgPort *AudioMP = 0;
+       struct Message *AudioMSG = 0;
+       ULONG device = -1;
+       BYTE *waveptr = 0;
+       LONG frequency=440, duration=1, clock, samp, samples, samcyc=1;
+       unsigned char name [ 100 ] ;
+
+       if ( flags.silent )
+               return;
+
+       if( GfxBase->DisplayFlags & PAL )
+               clock = 3546895;
+       else
+               clock = 3579545;
+
+       /*
+        * Convert type to file name - if there's nothing to play we
+        * shouldn't be here in the first place.
+        */
+       strncpy(name, actualn,sizeof(name) ) ;
+       for( t = strchr( name, ' ' ); t; t = strchr( name, ' ' ) )
+               *t = '_';
+       if( (stream = dlb_fopen( name, "r" )) == NULL )
+       {
+           perror( name );
+           return;
+       }
+
+       AudioIO = (struct IOAudio *)
+               AllocMem( sizeof( struct IOAudio ), MEMF_PUBLIC|MEMF_CLEAR );
+       if( AudioIO == 0 )
+               goto killaudio;
+
+       AudioMP = CreateMsgPort();
+       if( AudioMP == 0 )
+               goto killaudio;
+
+       AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP;
+       AudioIO->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
+       AudioIO->ioa_Request.io_Command = ADCMD_ALLOCATE;
+       AudioIO->ioa_Request.io_Flags = ADIOF_NOWAIT;
+       AudioIO->ioa_AllocKey = 0;
+       AudioIO->ioa_Data = whichannel;
+       AudioIO->ioa_Length = sizeof( whichannel );
+
+       device = OpenDevice( AUDIONAME, 0L, (struct IORequest *)AudioIO, 0L );
+       if( device != 0 )
+               goto killaudio;
+
+       if( dlb_fread( (genericptr_t)&iffhead, sizeof( iffhead ), 1, stream ) != 1 )
+               goto killaudio;
+
+       /* This is an even number of bytes long */
+       if( dlb_fread( name, (iffhead.namelen+1) & ~1, 1, stream ) != 1 )
+               goto killaudio;
+
+       if( dlb_fread( (genericptr_t)&samples, 4, 1, stream ) != 1 )
+               goto killaudio;
+
+       if( dlb_fread( (genericptr_t)&samples, 4, 1, stream ) != 1 )
+               goto killaudio;
+
+       waveptr = AllocMem( samples, MEMF_CHIP|MEMF_PUBLIC );
+       if( !waveptr )
+               goto killaudio;
+
+       if( dlb_fread( waveptr, samples, 1, stream ) != 1 )
+               goto killaudio;
+
+       while( melody[0] && melody[1] )
+       {
+               c = *melody++;
+               duration = *melody++;
+               dot = 0;
+               if( *melody == '.' )
+               {
+                       dot = 1;
+                       ++melody;
+               }
+               switch( duration )
+               {
+                       case 'w': dlay = 3; duration = 1; cycles = 1; break;
+                       case 'h': dlay = 3; duration = 2; cycles = 1; break;
+                       case 'q': dlay = 2; duration = 4; cycles = 1; break;
+                       case 'e': dlay = 1; duration = 8; cycles = 1; break;
+                       case 'x': dlay = 0; duration = 16; cycles = 1; break;
+                       case 't': dlay = 0; duration = 32; cycles = 1; break;
+                       default: goto killaudio;  /* unrecognized duration */
+               }
+
+               /* Lower case characters are one octave above upper case */
+               switch( c )
+               {
+                       case 'a': case 'b': case 'c':
+                       case 'd': case 'e': case 'f': case 'g':
+                               c -= 'a' - 7;
+                               break;
+
+                       case 'A': case 'B': case 'C':
+                       case 'D': case 'E': case 'F': case 'G':
+                               c -= 'A';
+                               break;
+
+                       default:
+                               continue;
+               }
+
+               samcyc = samples;
+
+               /* lowercase start at middle 'C', upper case are one octave below */
+               frequency = c > 7 ? freqtab[notetab[c%7]]*2 : freqtab[notetab[c]];
+
+               /* We can't actually do a dotted whole note unless we add code for a real
+                * 8SVX sample which includes sustain sample information to tell us how
+                * to hold the note steady...  So when duration == 1, ignore 'dot'...
+                */
+               if( dot && duration > 1 )
+                       samp = ((samples / duration) * 3) / 2;
+               else
+                       samp = samples / duration;
+
+               /* Only use some of the samples based on frequency */
+               samp = frequency * samp / 880;
+
+               /* The 22khz samples are middle C samples, so adjust the play
+                * back frequency accordingly
+                */
+               frequency = (frequency * (iffhead.vhdr.freq*2)/3) / 440L;
+
+               AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP;
+               AudioIO->ioa_Request.io_Command = CMD_WRITE;
+               AudioIO->ioa_Request.io_Flags = ADIOF_PERVOL;
+               AudioIO->ioa_Data = (BYTE *)waveptr;
+               AudioIO->ioa_Length = samp;
+
+               /* The clock rate represents the unity rate, so dividing by
+                * the frequency gives us a period ratio...
+                */
+/*printf( "clock: %ld, freq: %ld, div: %ld\n", clock, frequency, clock/frequency );*/
+               AudioIO->ioa_Period = clock/frequency;
+               AudioIO->ioa_Volume = vol;
+               AudioIO->ioa_Cycles = cycles;
+
+               BeginIO( (struct IORequest *)AudioIO );
+               WaitPort( AudioMP );
+               AudioMSG = GetMsg( AudioMP );
+               if( dlay )
+                       Delay( dlay );
+       }
+
+       killaudio:
+       if( stream ) dlb_fclose( stream );
+       if( waveptr ) FreeMem( waveptr, samples );
+       if( device == 0 ) CloseDevice( (struct IORequest *)AudioIO );
+       if( AudioMP ) DeleteMsgPort( AudioMP );
+       if( AudioIO ) FreeMem( AudioIO, sizeof( *AudioIO ) );
+}
diff --git a/sys/amiga/amistack.c b/sys/amiga/amistack.c
new file mode 100644 (file)
index 0000000..7e0b6fc
--- /dev/null
@@ -0,0 +1,21 @@
+/* SCCS Id: @(#)amistack.c     3.4     2000/05/03                      */
+/* Copyright (c) Janne Salmijärvi, Tampere, Finland, 2000              */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+/*
+ * Increase stack size to allow deep recursions.
+ * 
+ * Note: This is SAS/C specific, using other compiler probably
+ * requires another method for increasing stack.
+ *
+ */
+
+#ifdef __SASC_60
+#include <dos.h>
+
+/*
+ * At the moment 90*1024 would suffice, but just to be on the safe side ...
+ */
+
+long __stack = 128*1024; 
+#endif
diff --git a/sys/amiga/amitty.c b/sys/amiga/amitty.c
new file mode 100644 (file)
index 0000000..236d4b3
--- /dev/null
@@ -0,0 +1,67 @@
+/*    SCCS Id: @(#)amitty.c     3.2    2000/01/12
+/*    Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993,1996  */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* TTY-specific code for the Amiga
+ * This is still experimental.
+ * Still to do:
+ * add real termcap handling - currently requires ANSI_DEFAULT
+ */
+
+#include "hack.h"
+#include "tcap.h"
+#include <stdio.h>
+#include <proto/dos.h>
+
+#ifdef _DCC
+# define getch() getchar()
+#endif
+#ifdef __SASC_60
+# include <clib/dos_protos.h>
+#endif
+
+void NDECL( tty_change_color );
+char *NDECL( tty_get_color_string );
+
+#ifdef TTY_GRAPHICS
+
+int amibbs=0;                  /* BBS mode */
+char bbs_id[80]="";            /* BBS uid equivalent */
+long afh_in, afh_out;          /* BBS mode Amiga filehandles */
+
+void settty(const char *s){
+       end_screen();
+       if(s)raw_print(s);
+       iflags.cbreak=ON;       /* this is too easy: probably wrong */
+#if 1 /* should be version>=36 */
+/*     if(IsInteractive(afh_in)){ */
+               SetMode(afh_in,0);      /* con mode */
+/*     } */
+#endif
+}
+void gettty(){
+#if 1 /* should be VERSION >=36 */
+/*     if(IsInteractive(afh_in)){ */
+               SetMode(afh_in,1);      /* raw mode */
+/*     } */
+#endif
+}
+void setftty(){
+       iflags.cbreak=ON;       /* ditto */
+}
+char kill_char='X'-'@';
+char erase_char='\b';
+tgetch(){
+       char x;
+       Read(afh_in,&x,1);
+       return (x=='\r')?'\n':x;
+}
+void get_scr_size(){
+       CO=80;
+       LI=24;
+}
+
+#endif
+
+void tty_change_color() {}
+char *tty_get_color_string() { return( "" ); }
diff --git a/sys/amiga/amiwind.c b/sys/amiga/amiwind.c
new file mode 100644 (file)
index 0000000..860bc3c
--- /dev/null
@@ -0,0 +1,949 @@
+/*    SCCS Id: @(#)amiwind.c     3.2    2000/01/12
+/*    Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992         */
+/*    Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993,1996  */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "NH:sys/amiga/windefs.h"
+#include "NH:sys/amiga/winext.h"
+#include "NH:sys/amiga/winproto.h"
+
+/* Have to undef CLOSE as display.h and intuition.h both use it */
+#undef CLOSE
+
+#ifdef AMII_GRAPHICS   /* too early in the file? too late? */
+
+#ifdef AMIFLUSH
+static struct Message *FDECL(GetFMsg,(struct MsgPort *));
+#endif
+
+static int BufferGetchar(void);
+static void ProcessMessage( register struct IntuiMessage *message );
+
+#define BufferQueueChar(ch) (KbdBuffer[KbdBuffered++] = (ch))
+
+struct Library *ConsoleDevice;
+
+#include "NH:sys/amiga/amimenu.c"
+
+/* Now our own variables */
+
+struct IntuitionBase *IntuitionBase;
+struct Screen *HackScreen;
+struct Window *pr_WindowPtr;
+struct MsgPort *HackPort;
+struct IOStdReq ConsoleIO;
+struct Menu *MenuStrip;
+APTR *VisualInfo;
+char Initialized = 0;
+WEVENT lastevent;
+
+#ifdef HACKFONT
+struct GfxBase *GfxBase;
+struct Library *DiskfontBase;
+#endif
+
+#define KBDBUFFER   10
+static unsigned char KbdBuffer[KBDBUFFER];
+unsigned char KbdBuffered;
+
+#ifdef HACKFONT
+
+struct TextFont *TextsFont = NULL;
+struct TextFont *HackFont = NULL;
+struct TextFont *RogueFont = NULL;
+
+UBYTE FontName[] = "NetHack:hack.font";
+    /* # chars in "NetHack:": */
+#define         SIZEOF_DISKNAME 8
+
+#endif
+
+struct TextAttr Hack80 = {
+#ifdef HACKFONT
+    &FontName[SIZEOF_DISKNAME],
+#else
+    (UBYTE *) "topaz.font",
+#endif
+    8, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
+       | FPF_ROMFONT
+};
+
+struct TextAttr TextsFont13 = {
+    (UBYTE *) "courier.font",
+    13, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
+#ifndef        HACKFONT
+       | FPF_ROMFONT
+#endif
+};
+
+/* Avoid doing a ReplyMsg through a window that no longer exists. */
+static enum {NoAction, CloseOver} delayed_key_action = NoAction;
+
+/*
+ * Open a window that shares the HackPort IDCMP. Use CloseShWindow()
+ * to close.
+ */
+
+struct Window *OpenShWindow(nw)
+struct NewWindow *nw;
+{
+    register struct Window *win;
+    register ULONG idcmpflags;
+
+    if (!HackPort)  /* Sanity check */
+       return (struct Window *) 0;
+
+    idcmpflags = nw->IDCMPFlags;
+    nw->IDCMPFlags = 0;
+    if (!(win = OpenWindow((void *)nw)))
+    {
+       nw->IDCMPFlags = idcmpflags;
+       return (struct Window *) 0;
+    }
+
+    nw->IDCMPFlags = idcmpflags;
+    win->UserPort = HackPort;
+    ModifyIDCMP(win, idcmpflags);
+    return win;
+}
+
+
+/*
+ * Close a window that shared the HackPort IDCMP port.
+ */
+
+void FDECL(CloseShWindow, (struct Window *));
+void CloseShWindow(win)
+struct Window *win;
+{
+    register struct IntuiMessage *msg;
+
+    if( !HackPort )
+       panic("HackPort NULL in CloseShWindow" );
+    if (!win)
+       return;
+
+    Forbid();
+    /* Flush all messages for all windows to avoid typeahead and other
+     * similar problems...
+     */
+    while( msg = (struct IntuiMessage *)GetMsg( win->UserPort ) )
+       ReplyMsg( (struct Message *) msg );
+    KbdBuffered = 0;
+    win->UserPort = (struct MsgPort *) 0;
+    ModifyIDCMP(win, 0L);
+    Permit();
+    CloseWindow(win);
+}
+
+static int BufferGetchar()
+{
+    register int c;
+
+    if (KbdBuffered > 0) {
+       c = KbdBuffer[0];
+       KbdBuffered--;
+       /* Move the remaining characters */
+       if( KbdBuffered < sizeof( KbdBuffer ) )
+           memcpy( KbdBuffer, KbdBuffer+1, KbdBuffered );
+       return c;
+    }
+
+    return NO_CHAR;
+}
+
+/*
+ *  This should remind you remotely of DeadKeyConvert, but we are cheating
+ *  a bit. We want complete control over the numeric keypad, and no dead
+ *  keys... (they are assumed to be on Alted keys).
+ *
+ *  Also assumed is that the IntuiMessage is of type RAWKEY.  For some
+ *  reason, IECODE_UP_PREFIX events seem to be lost when they  occur while
+ *  our console window is inactive. This is particulary  troublesome with
+ *  qualifier keys... Is this because I never RawKeyConvert those events???
+ */
+
+int ConvertKey(message)
+register struct IntuiMessage *message;
+{
+    static struct InputEvent theEvent;
+    static char       numpad[] = "bjnh.lyku";
+    static char  ctrl_numpad[] = "\x02\x0A\x0E\x08.\x0C\x19\x0B\x15";
+    static char shift_numpad[] = "BJNH.LYKU";
+
+    unsigned char buffer[10];
+    struct Window *w = message->IDCMPWindow;
+    register int length;
+    register ULONG qualifier;
+    char numeric_pad, shift, control, alt;
+
+    if( amii_wins[ WIN_MAP ] )
+       w = amii_wins[ WIN_MAP ]->win;
+    qualifier = message->Qualifier;
+
+    control = (qualifier &  IEQUALIFIER_CONTROL) != 0;
+    shift   = (qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0;
+    alt     = (qualifier & (IEQUALIFIER_LALT   | IEQUALIFIER_RALT  )) != 0;
+
+    /* Allow ALT to function as a META key ... */
+    /* But make it switchable - alt is needed for some non-US keymaps */
+    if(flags.altmeta)
+       qualifier &= ~(IEQUALIFIER_LALT | IEQUALIFIER_RALT);
+    numeric_pad = (qualifier & IEQUALIFIER_NUMERICPAD) != 0;
+
+    /*
+     *  Shortcut for HELP and arrow keys. I suppose this is allowed.
+     *  The defines are in intuition/intuition.h, and the keys don't
+     *  serve 'text' input, normally. Also, parsing their escape
+     *  sequences is such a mess...
+     */
+
+    switch (message->Code) {
+       case RAWHELP:
+           if( alt )
+           {
+               EditColor();
+               return( -1 );
+           }
+#ifdef CLIPPING
+           else if( WINVERS_AMIV && control )
+           {
+               EditClipping();
+
+               CO = ( w->Width - w->BorderLeft - w->BorderRight  ) / mxsize;
+               LI = ( w->Height - w->BorderTop - w->BorderBottom ) / mysize;
+               clipxmax = CO + clipx;
+               clipymax = LI + clipy;
+               if( CO < COLNO || LI < ROWNO )
+               {
+                   clipping = TRUE;
+                   amii_cliparound( u.ux, u.uy );
+               }
+               else
+               {
+                   clipping = FALSE;
+                   clipx = clipy = 0;
+               }
+               BufferQueueChar( 'R'-64 );
+               return(-1);
+           }
+#endif
+           else if( WINVERS_AMIV && shift )
+           {
+               if( WIN_OVER == WIN_ERR )
+               {
+                   WIN_OVER = amii_create_nhwindow( NHW_OVER );
+                   BufferQueueChar( 'R'-64 );
+               }
+               else
+               {
+                   delayed_key_action = CloseOver;
+               }
+               return( -1 );
+           }
+           return( '?' );
+           break;
+       case CURSORLEFT:
+           length = '4';
+           numeric_pad = 1;
+           goto arrow;
+       case CURSORDOWN:
+           length = '2';
+           numeric_pad = 1;
+           goto arrow;
+       case CURSORUP:
+           length = '8';
+           numeric_pad = 1;
+           goto arrow;
+       case CURSORRIGHT:
+           length = '6';
+           numeric_pad = 1;
+           goto arrow;
+    }
+
+    theEvent.ie_Class = IECLASS_RAWKEY;
+    theEvent.ie_Code = message->Code;
+    theEvent.ie_Qualifier = numeric_pad ? IEQUALIFIER_NUMERICPAD : qualifier;
+    theEvent.ie_EventAddress = (APTR) (message->IAddress);
+
+    length = RawKeyConvert(&theEvent, (char *)buffer, 
+      (long) sizeof(buffer), NULL);
+
+    if (length == 1) {   /* Plain ASCII character */
+       length = buffer[0];
+       /*
+        *  If iflags.num_pad is set, movement is by 4286.
+        *  If not set, translate 4286 into hjkl.
+        *  This way, the numeric pad can /always/ be used
+        *  for moving, though best results are when it is off.
+        */
+arrow:
+       if (!iflags.num_pad && numeric_pad && length >= '1' && length <= '9') {
+           length -= '1';
+           if (control) {
+               length = ctrl_numpad[length];
+           } else if (shift) {
+               length = shift_numpad[length];
+           } else {
+               length = numpad[length];
+           }
+       }
+
+       /* Kludge to allow altmeta on eg. scandinavian keymap (# == shift+alt+3)
+           and prevent it from interfering with # command (M-#) */
+       if (length == ('#'|0x80))
+           return '#';
+       if (alt && flags.altmeta)
+           length |= 0x80;
+       return(length);
+    } /* else shift, ctrl, alt, amiga, F-key, shift-tab, etc */
+    else if( length > 1 )
+    {
+       int i;
+
+       if( length == 3 && buffer[ 0 ] == 155 && buffer[ 2 ] == 126 )
+       {
+           int got = 1;
+           switch( buffer[ 1 ] )
+           {
+               case 53: mxsize = mysize = 8; break;
+               case 54: mxsize = mysize = 16; break;
+               case 55: mxsize = mysize = 24; break;
+               case 56: mxsize = mysize = 32; break;
+               case 57: mxsize = mysize = 48; break;
+               default: got = 0; break;
+           }
+#ifdef OPT_DISPMAP
+           dispmap_sanity();
+#endif
+
+           if( got )
+           {
+               CO = (w->Width-w->BorderLeft-w->BorderRight)/mxsize;
+               LI = (w->Height-w->BorderTop-w->BorderBottom)/mysize;
+               clipxmax = CO + clipx;
+               clipymax = LI + clipy;
+               if( CO < COLNO || LI < ROWNO )
+               {
+                   amii_cliparound( u.ux, u.uy );
+               }
+               else
+               {
+                       CO = COLNO;
+                       LI = ROWNO;
+               }
+               reclip = 1;
+               doredraw();
+               flush_screen( 1 );
+               reclip = 0;
+               /*BufferQueueChar( 'R'-64 );*/
+               return( -1 );
+           }
+       }
+       printf( "Unrecognized key: %d ", (int)buffer[0]);
+       for( i = 1; i < length; ++i )
+           printf( "%d ", (int)buffer[i]);
+       printf( "\n" );
+    }
+    return( -1 );
+}
+
+/*
+ *  Process an incoming IntuiMessage.
+ *  It would certainly look nicer if this could be done using a
+ *  PA_SOFTINT message port, but we cannot call RawKeyConvert()
+ *  during a software interrupt.
+ *  Anyway, amikbhit()/kbhit() is called often enough, and usually gets
+ *  ahead of input demands, when the user types ahead.
+ */
+
+static void ProcessMessage(message)
+register struct IntuiMessage *message;
+{
+    int c;
+    int cnt;
+    menu_item *mip;
+    static int skip_mouse=0;    /* need to ignore next mouse event on
+                                * a window activation */
+    struct Window *w = message->IDCMPWindow;
+
+    switch(message->Class) {
+    case ACTIVEWINDOW:
+       if( alwaysinvent && WIN_INVEN != WIN_ERR &&
+                           w == amii_wins[ WIN_INVEN ]->win )
+       {
+           cnt = DoMenuScroll( WIN_INVEN, 0, PICK_NONE, &mip );
+       }
+       else if( scrollmsg && WIN_MESSAGE != WIN_ERR &&
+                           w == amii_wins[ WIN_MESSAGE ]->win )
+       {
+           cnt = DoMenuScroll( WIN_MESSAGE, 0, PICK_NONE, &mip );
+       }
+       else
+       {
+           skip_mouse=1;
+       }
+       break;
+
+    case MOUSEBUTTONS:
+       {
+           if( skip_mouse )
+           {
+               skip_mouse=0;
+               break;
+           }
+
+           if( !amii_wins[ WIN_MAP ] || w != amii_wins[ WIN_MAP ]->win )
+               break;
+
+           if( message->Code == SELECTDOWN )
+           {
+               lastevent.type = WEMOUSE;
+               lastevent.un.mouse.x = message->MouseX;
+               lastevent.un.mouse.y = message->MouseY;
+                   /* With shift equals RUN */
+               lastevent.un.mouse.qual = (message->Qualifier &
+                 (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) != 0;
+           }
+       }
+       break;
+
+    case MENUPICK:
+       {
+           USHORT thismenu;
+           struct MenuItem *item;
+
+           thismenu = message->Code;
+           while (thismenu != MENUNULL)
+           {
+               item = ItemAddress(MenuStrip, (ULONG) thismenu);
+               if (KbdBuffered < KBDBUFFER)
+                   BufferQueueChar((char)(GTMENUITEM_USERDATA(item)));
+               thismenu = item->NextSelect;
+           }
+       }
+       break;
+
+    case REFRESHWINDOW:
+       {
+           if( scrollmsg
+               && amii_wins[ WIN_MESSAGE ]
+               && w == amii_wins[ WIN_MESSAGE ]->win
+           ){
+               cnt = DoMenuScroll( WIN_MESSAGE, 0, PICK_NONE, &mip );
+           }
+       }
+       break;
+
+    case CLOSEWINDOW:
+       if( WIN_INVEN != WIN_ERR && w == amii_wins[ WIN_INVEN ]->win )
+       {
+           dismiss_nhwindow( WIN_INVEN );
+       }
+       if( WINVERS_AMIV
+           && ( WIN_OVER != WIN_ERR && w == amii_wins[ WIN_OVER ]->win )
+       ){
+           destroy_nhwindow( WIN_OVER );
+           WIN_OVER = WIN_ERR;
+       }
+       break;
+
+    case RAWKEY:
+       if (!(message->Code & IECODE_UP_PREFIX)){
+           /* May queue multiple characters
+            * but doesn't do that yet...
+            */
+           if( ( c = ConvertKey(message) ) > 0 )
+               BufferQueueChar( c );
+        }
+        break;
+
+    case GADGETDOWN:
+       if( WIN_MESSAGE != WIN_ERR && w == amii_wins[ WIN_MESSAGE ]->win )
+       {
+           cnt = DoMenuScroll( WIN_MESSAGE, 0, PICK_NONE, &mip );
+       }
+       else if( WIN_INVEN != WIN_ERR && w == amii_wins[ WIN_INVEN ]->win )
+       {
+           cnt = DoMenuScroll( WIN_INVEN, 0, PICK_NONE, &mip );
+       }
+       break;
+
+    case NEWSIZE:
+       if( WIN_MESSAGE != WIN_ERR && w == amii_wins[ WIN_MESSAGE ]->win )
+       {
+           if( WINVERS_AMIV )
+           {
+               /* Make sure that new size is honored for good. */
+               SetAPen( w->RPort, amii_msgBPen );
+               SetBPen( w->RPort, amii_msgBPen );
+               SetDrMd( w->RPort, JAM2 );
+               RectFill( w->RPort, w->BorderLeft, w->BorderTop,
+                 w->Width - w->BorderRight-1,
+                 w->Height - w->BorderBottom-1 );
+           }
+           ReDisplayData( WIN_MESSAGE );
+       }
+       else if( WIN_INVEN != WIN_ERR && w == amii_wins[ WIN_INVEN ]->win )
+       {
+           ReDisplayData( WIN_INVEN );
+       }
+       else if( WINVERS_AMIV
+                && ( WIN_OVER != WIN_ERR && w == amii_wins[ WIN_OVER ]->win )
+       ){
+           BufferQueueChar( 'R'-64 );
+       }
+       else if( WIN_MAP != WIN_ERR && w == amii_wins[ WIN_MAP ]->win )
+       {
+#ifdef CLIPPING
+           CO = (w->Width-w->BorderLeft-w->BorderRight)/mxsize;
+           LI = (w->Height-w->BorderTop-w->BorderBottom)/mysize;
+           clipxmax = CO + clipx;
+           clipymax = LI + clipy;
+           if( CO < COLNO || LI < ROWNO )
+           {
+               amii_cliparound( u.ux, u.uy );
+           }
+           else
+           {
+               clipping = FALSE;
+               clipx = clipy = 0;
+           }
+           BufferQueueChar( 'R'-64 );
+#endif
+       }
+       break;
+    }
+    ReplyMsg((struct Message *) message);
+
+    switch(delayed_key_action){
+    case CloseOver:
+       amii_destroy_nhwindow( WIN_OVER );
+       WIN_OVER = WIN_ERR;
+       delayed_key_action = NoAction;
+    case NoAction:
+       ;       /* null */
+    }
+}
+
+#endif /* AMII_GRAPHICS */
+/*
+ *  Get all incoming messages and fill up the keyboard buffer,
+ *  thus allowing Intuition to (maybe) free up the IntuiMessages.
+ *  Return when no more messages left, or keyboard buffer half full.
+ *  We need to do this since there is no one-to-one correspondence
+ *  between characters and incoming messages.
+ */
+
+#if defined(TTY_GRAPHICS) && !defined(AMII_GRAPHICS)
+int kbhit(){
+       return 0;
+}
+#else
+int
+kbhit()
+{
+    int c;
+# ifdef TTY_GRAPHICS
+               /* a kludge to defuse the mess in allmain.c */
+               /* I hope this is the right approach */
+    if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows)return 0;
+# endif
+    c = amikbhit();
+    if( c <= 0 )
+       return( 0 );
+    return( c );
+}
+#endif
+
+#ifdef AMII_GRAPHICS
+
+int
+amikbhit()
+{
+    register struct IntuiMessage *message;
+    while( KbdBuffered < KBDBUFFER / 2 )
+    {
+#ifdef AMIFLUSH
+       message = (struct IntuiMessage *) GetFMsg(HackPort);
+#else
+       message = (struct IntuiMessage *) GetMsg(HackPort);
+#endif
+       if(message)
+       {
+           ProcessMessage(message);
+           if( lastevent.type != WEUNK && lastevent.type != WEKEY )
+               break;
+       }
+       else
+           break;
+    }
+    return ( lastevent.type == WEUNK ) ? KbdBuffered : -1;
+}
+
+/*
+ *  Get a character from the keyboard buffer, waiting if not available.
+ *  Ignore other kinds of events that happen in the mean time.
+ */
+
+int WindowGetchar( )
+{
+    while ((lastevent.type = WEUNK), amikbhit() <= 0) {
+       WaitPort(HackPort);
+    }
+    return BufferGetchar();
+}
+
+WETYPE WindowGetevent()
+{
+    lastevent.type = WEUNK;
+    while (amikbhit() == 0)
+    {
+       WaitPort(HackPort);
+    }
+
+    if( KbdBuffered )
+    {
+       lastevent.type = WEKEY;
+       lastevent.un.key = BufferGetchar();
+    }
+    return( lastevent.type );
+}
+
+/*
+ *  Clean up everything. But before we do, ask the user to hit return
+ *  when there is something that s/he should read.
+ */
+
+void amii_cleanup()
+{
+    register struct IntuiMessage *msg;
+
+    /* Close things up */
+    if( HackPort )
+    {
+       amii_raw_print("");
+       amii_getret();
+    }
+
+    if (ConsoleIO.io_Device)
+       CloseDevice( (struct IORequest *)&ConsoleIO );
+    ConsoleIO.io_Device = 0;
+
+    if( ConsoleIO.io_Message.mn_ReplyPort )
+       DeleteMsgPort( ConsoleIO.io_Message.mn_ReplyPort );
+    ConsoleIO.io_Message.mn_ReplyPort = 0;
+
+    /* Strip messages before deleting the port */
+    if( HackPort )
+    {
+       Forbid();
+       while (msg = (struct IntuiMessage *) GetMsg(HackPort))
+           ReplyMsg((struct Message *) msg);
+       kill_nhwindows( 1 );
+       DeleteMsgPort( HackPort );
+       HackPort = NULL;
+       Permit();
+    }
+
+    /* Close the screen, under v37 or greater it is a pub screen and there may
+     * be visitors, so check close status and wait till everyone is gone.
+     */
+    if( HackScreen )
+    {
+#ifdef  INTUI_NEW_LOOK
+       if( IntuitionBase->LibNode.lib_Version >= 37 )
+       {
+           if (MenuStrip) FreeMenus(MenuStrip);
+           if (VisualInfo) FreeVisualInfo(VisualInfo);
+           while( CloseScreen( HackScreen ) == FALSE )
+           {
+               struct EasyStruct easy =
+               {
+                   sizeof( struct EasyStruct ),
+                   0,
+                   "Nethack Problem",
+                   "Can't Close Screen, Close Visiting Windows",
+                   "Okay"
+               };
+               EasyRequest( NULL, &easy, NULL, NULL );
+           }
+       }
+       else
+#endif
+       {
+           CloseScreen(HackScreen);
+       }
+       HackScreen = NULL;
+    }
+
+#ifdef HACKFONT
+    if (HackFont)
+    {
+       CloseFont(HackFont);
+       HackFont = NULL;
+    }
+
+    if( TextsFont )
+    {
+       CloseFont( TextsFont );
+       TextsFont = NULL;
+    }
+
+    if( RogueFont )
+    {
+       CloseFont( RogueFont );
+       RogueFont = NULL;
+    }
+
+    if( DiskfontBase )
+    {
+       CloseLibrary(DiskfontBase);
+       DiskfontBase = NULL;
+    }
+#endif
+
+    if (GadToolsBase) {
+       CloseLibrary((struct Library *)GadToolsBase);
+       GadToolsBase=NULL;
+    }
+
+    if (LayersBase) {
+       CloseLibrary((struct Library *)LayersBase);
+       LayersBase = NULL;
+    }
+
+    if (GfxBase) {
+       CloseLibrary((struct Library *)GfxBase);
+       GfxBase = NULL;
+    }
+
+    if (IntuitionBase) {
+       CloseLibrary((struct Library *)IntuitionBase);
+       IntuitionBase = NULL;
+    }
+
+#ifdef SHAREDLIB
+    if (DOSBase) {
+       CloseLibrary((struct Library *)DOSBase);
+       DOSBase = NULL;
+    }
+#endif
+
+    ((struct Process *) FindTask(NULL))->pr_WindowPtr = (APTR) pr_WindowPtr;
+
+    Initialized = 0;
+}
+
+#endif /* AMII_GRAPHICS */
+
+#ifndef        SHAREDLIB
+void Abort(rc)
+long rc;
+{
+    int fault = 1;
+#ifdef CHDIR
+    extern char orgdir[];
+    chdir(orgdir);
+#endif
+#ifdef AMII_GRAPHICS
+    if (Initialized
+      && ConsoleDevice
+      && windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows) {
+      printf("\n\nAbort with alert code %08lx...\n", rc);
+      amii_getret();
+    } else
+#endif
+      printf("\n\nAbort with alert code %08lx...\n",rc);
+      /* Alert(rc);              this is too severe */
+#ifdef __SASC
+# ifdef        INTUI_NEW_LOOK
+    if( IntuitionBase->LibNode.lib_Version >= 37 )
+    {
+       struct EasyStruct es =
+       {
+               sizeof( struct EasyStruct ),
+               0,
+               "NetHack Panic Request",
+               "NetHack is Aborting with code == 0x%08lx",
+               "Continue Abort|Return to Program|Clean up and exit",
+       };
+       fault = EasyRequest( NULL, &es, NULL, (long)rc );
+       if( fault == 2 )
+           return;
+    }
+# endif
+    if( fault == 1 )
+    {
+/*  __emit(0x4afc); */    /* illegal instruction */
+    __emit(0x40fc);     /* divide by */
+    __emit(0x0000);     /*  #0  */
+      /* NOTE: don't move amii_cleanup() above here - */
+      /* it is too likely to kill the system     */
+      /* before it can get the SnapShot out, if  */
+      /* there is something really wrong.    */
+    }
+#endif
+#ifdef AMII_GRAPHICS
+    if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows)
+      amii_cleanup();
+#endif
+#undef exit
+#ifdef AZTEC_C
+    _abort();
+#endif
+    exit((int) rc);
+}
+
+void
+CleanUp()
+{
+       amii_cleanup();
+}
+#endif
+
+#ifdef AMII_GRAPHICS
+
+#ifdef AMIFLUSH
+/* This routine adapted from AmigaMail IV-37 by Michael Sinz */
+static struct Message *
+GetFMsg(port)
+    struct MsgPort *port;
+    {
+    struct IntuiMessage *msg,*succ,*succ1;
+
+    if(msg=(struct IntuiMessage *)GetMsg(port)){
+       if(!flags.amiflush)return((struct Message *)msg);
+       if(msg->Class==RAWKEY){
+           Forbid();
+           succ=(struct IntuiMessage *)(port->mp_MsgList.lh_Head);
+           while(succ1=(struct IntuiMessage *)
+             (succ->ExecMessage.mn_Node.ln_Succ)){
+               if(succ->Class==RAWKEY){
+                   Remove((struct Node *)succ);
+                   ReplyMsg((struct Message *)succ);
+               }
+               succ=succ1;
+           }
+           Permit();
+       }
+    }
+    return((struct Message *)msg);
+}
+#endif
+
+struct NewWindow *
+DupNewWindow( win )
+    struct NewWindow *win;
+{
+    struct NewWindow *nwin;
+    struct Gadget *ngd, *gd, *pgd = NULL;
+    struct PropInfo *pip;
+    struct StringInfo *sip;
+
+    /* Copy the (Ext)NewWindow structure */
+
+    nwin = (struct NewWindow *)alloc( sizeof( struct NewWindow ) );
+    *nwin = *win;
+
+    /* Now do the gadget list */
+
+    nwin->FirstGadget = NULL;
+    for( gd = win->FirstGadget; gd; gd = gd->NextGadget )
+    {
+       ngd = (struct Gadget *)alloc( sizeof( struct Gadget ) );
+       *ngd = *gd;
+       if( gd->GadgetType == STRGADGET )
+       {
+           sip = (struct StringInfo *)alloc( sizeof( struct StringInfo ) );
+           *sip = *((struct StringInfo *)gd->SpecialInfo);
+           sip->Buffer = (UBYTE *) alloc( sip->MaxChars );
+           *sip->Buffer = 0;
+           ngd->SpecialInfo = (APTR)sip;
+       }
+       else if( gd->GadgetType == PROPGADGET )
+       {
+           pip = (struct PropInfo *)alloc( sizeof( struct PropInfo ) );
+           *pip = *((struct PropInfo *)gd->SpecialInfo);
+           ngd->SpecialInfo = (APTR)pip;
+       }
+       if( pgd )
+           pgd->NextGadget = ngd;
+       else
+           nwin->FirstGadget = ngd;
+       pgd = ngd;
+       ngd->NextGadget = NULL;
+       ngd->UserData = (APTR) 0x45f35c3d;  // magic cookie for FreeNewWindow()
+    }
+    return( nwin );
+}
+
+void
+FreeNewWindow( win )
+    struct NewWindow *win;
+{
+    register struct Gadget *gd, *pgd;
+    register struct StringInfo *sip;
+
+    for( gd = win->FirstGadget; gd; gd = pgd ) {
+       pgd = gd->NextGadget;
+       if ((ULONG)gd->UserData == 0x45f35c3d) {
+           if( gd->GadgetType == STRGADGET ) {
+               sip = (struct StringInfo *)gd->SpecialInfo;
+               free( sip->Buffer );
+               free( sip );
+           } else if( gd->GadgetType == PROPGADGET ) {
+               free( (struct PropInfo *)gd->SpecialInfo );
+           }
+           free( gd );
+       }
+    }
+    free( win );
+}
+
+void
+bell()
+{
+    if (flags.silent) return;
+    DisplayBeep(NULL);
+}
+
+void
+amii_delay_output()
+{
+    /* delay 50 ms */
+    Delay(2L);
+}
+
+void
+amii_number_pad(state)
+int state;
+{
+}
+#endif  /* AMII_GRAPHICS */
+
+#ifndef        SHAREDLIB
+void
+amiv_loadlib( void )
+{
+}
+
+void
+amii_loadlib( void )
+{
+}
+
+/* fatal error */
+/*VARARGS1*/
+void error VA_DECL(const char *, s)
+    VA_START(s);
+    VA_INIT(s, char *);
+
+    putchar('\n');
+    vprintf(s, VA_ARGS);
+    putchar('\n');
+
+    VA_END();
+    Abort(0L);
+}
+#endif
diff --git a/sys/amiga/amiwind.p b/sys/amiga/amiwind.p
new file mode 100644 (file)
index 0000000..ca009d4
--- /dev/null
@@ -0,0 +1,40 @@
+/*   SCCS Id: @(#)amiwind.p    3.1     93/01/08                  */
+/*   Copyright (c) Gregg Wonderly, Naperville, IL, 1992, 1993    */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* amiwind.c */
+#ifdef INTUI_NEW_LOOK
+struct Window *FDECL( OpenShWindow, (struct ExtNewWindow *) );
+#else
+struct Window *FDECL( OpenShWindow, (struct NewWindow *) );
+#endif
+void FDECL( CloseShWindow, (struct Window *));
+int NDECL( kbhit );
+int NDECL( amikbhit );
+int NDECL( WindowGetchar );
+WETYPE NDECL( WindowGetevent );
+void NDECL( WindowFlush );
+void FDECL( WindowPutchar, (char ));
+void FDECL( WindowFPuts, (const char *));
+void FDECL( WindowPuts, (const char *));
+void FDECL( WindowPrintf, ( char *,... ));
+void NDECL( CleanUp );
+int FDECL( ConvertKey, ( struct IntuiMessage * ));
+#ifndef        SHAREDLIB
+void FDECL( Abort, (long ));
+#endif
+void FDECL( flush_glyph_buffer, (struct Window *));
+void FDECL( amiga_print_glyph, (winid , int , int ));
+void FDECL( start_glyphout, (winid ));
+void FDECL( amii_end_glyphout, (winid ));
+#ifdef INTUI_NEW_LOOK
+struct ExtNewWindow *FDECL( DupNewWindow, (struct ExtNewWindow *));
+void FDECL( FreeNewWindow, (struct ExtNewWindow *));
+#else
+struct NewWindow *FDECL( DupNewWindow, (struct NewWindow *));
+void FDECL( FreeNewWindow, (struct NewWindow *));
+#endif
+void NDECL( bell );
+void NDECL( amii_delay_output );
+void FDECL( amii_number_pad, (int ));
+void amii_cleanup( void );
diff --git a/sys/amiga/clipwin.c b/sys/amiga/clipwin.c
new file mode 100644 (file)
index 0000000..a5ede30
--- /dev/null
@@ -0,0 +1,268 @@
+static USHORT Palette[] = {
+       0x0AAA, /* color #0 */
+       0x0000, /* color #1 */
+       0x0FFF, /* color #2 */
+       0x058B, /* color #3 */
+       0x000F, /* color #4 */
+       0x0F0F, /* color #5 */
+       0x00FF, /* color #6 */
+       0x0FFF  /* color #7 */
+#define PaletteColorCount 8
+};
+
+#define PALETTE Palette
+
+static SHORT ClipBorderVectors1[] = {
+       0,0,
+       76,0,
+       76,11,
+       0,11,
+       0,0
+};
+static struct Border ClipBorder1 = {
+       -1,-1,  /* XY origin relative to container TopLeft */
+       3,0,JAM1,       /* front pen, back pen and drawmode */
+       5,      /* number of XY vectors */
+       ClipBorderVectors1,     /* pointer to XY vectors */
+       NULL    /* next border in list */
+};
+
+static struct IntuiText ClipIText1 = {
+       4,0,JAM1,       /* front and back text pens, drawmode and fill byte */
+       15,1,   /* XY origin relative to container TopLeft */
+       NULL,   /* font pointer or NULL for default */
+       "Cancel",       /* pointer to text */
+       NULL    /* next IntuiText structure */
+};
+
+static struct Gadget ClipCancel = {
+       NULL,   /* next gadget */
+       240,59, /* origin XY of hit box relative to window TopLeft */
+       75,10,  /* hit box width and height */
+       NULL,   /* gadget flags */
+       RELVERIFY,      /* activation flags */
+       BOOLGADGET,     /* gadget type flags */
+       (APTR)&ClipBorder1,     /* gadget border or image to be rendered */
+       NULL,   /* alternate imagery for selection */
+       &ClipIText1,    /* first IntuiText structure */
+       NULL,   /* gadget mutual-exclude long word */
+       NULL,   /* SpecialInfo structure */
+       GADCANCEL,      /* user-definable data */
+       NULL    /* pointer to user-definable data */
+};
+
+static SHORT ClipBorderVectors2[] = {
+       0,0,
+       78,0,
+       78,11,
+       0,11,
+       0,0
+};
+static struct Border ClipBorder2 = {
+       -1,-1,  /* XY origin relative to container TopLeft */
+       3,0,JAM1,       /* front pen, back pen and drawmode */
+       5,      /* number of XY vectors */
+       ClipBorderVectors2,     /* pointer to XY vectors */
+       NULL    /* next border in list */
+};
+
+static struct IntuiText ClipIText2 = {
+       4,0,JAM1,       /* front and back text pens, drawmode and fill byte */
+       24,1,   /* XY origin relative to container TopLeft */
+       NULL,   /* font pointer or NULL for default */
+       "Okay", /* pointer to text */
+       NULL    /* next IntuiText structure */
+};
+
+static struct Gadget ClipOkay = {
+       &ClipCancel,    /* next gadget */
+       17,60,  /* origin XY of hit box relative to window TopLeft */
+       77,10,  /* hit box width and height */
+       NULL,   /* gadget flags */
+       RELVERIFY,      /* activation flags */
+       BOOLGADGET,     /* gadget type flags */
+       (APTR)&ClipBorder2,     /* gadget border or image to be rendered */
+       NULL,   /* alternate imagery for selection */
+       &ClipIText2,    /* first IntuiText structure */
+       NULL,   /* gadget mutual-exclude long word */
+       NULL,   /* SpecialInfo structure */
+       GADOKAY,        /* user-definable data */
+       NULL    /* pointer to user-definable data */
+};
+
+static struct PropInfo ClipClipXCLIPSInfo = {
+       AUTOKNOB+FREEHORIZ,     /* PropInfo flags */
+       24504,-1,       /* horizontal and vertical pot values */
+       10922,-1,       /* horizontal and vertical body values */
+};
+
+static struct Image ClipImage1 = {
+       43,0,   /* XY origin relative to container TopLeft */
+       24,3,   /* Image width and height in pixels */
+       0,      /* number of bitplanes in Image */
+       NULL,   /* pointer to ImageData */
+       0x0000,0x0000,  /* PlanePick and PlaneOnOff */
+       NULL    /* next Image structure */
+};
+
+static struct IntuiText ClipIText3 = {
+       3,0,JAM1,       /* front and back text pens, drawmode and fill byte */
+       -116,-1,        /* XY origin relative to container TopLeft */
+       NULL,   /* font pointer or NULL for default */
+       "X Clip Border:",       /* pointer to text */
+       NULL    /* next IntuiText structure */
+};
+
+static struct Gadget ClipXCLIP = {
+       &ClipOkay,      /* next gadget */
+       134,37, /* origin XY of hit box relative to window TopLeft */
+       -199,7, /* hit box width and height */
+       GRELWIDTH,      /* gadget flags */
+       RELVERIFY+GADGIMMEDIATE,        /* activation flags */
+       PROPGADGET,     /* gadget type flags */
+       (APTR)&ClipImage1,      /* gadget border or image to be rendered */
+       NULL,   /* alternate imagery for selection */
+       &ClipIText3,    /* first IntuiText structure */
+       NULL,   /* gadget mutual-exclude long word */
+       (APTR)&ClipClipXCLIPSInfo,      /* SpecialInfo structure */
+       XCLIP,  /* user-definable data */
+       NULL    /* pointer to user-definable data */
+};
+
+static struct PropInfo ClipClipYCLIPSInfo = {
+       AUTOKNOB+FREEHORIZ,     /* PropInfo flags */
+       13106,-1,       /* horizontal and vertical pot values */
+       10922,-1,       /* horizontal and vertical body values */
+};
+
+static struct Image ClipImage2 = {
+       22,0,   /* XY origin relative to container TopLeft */
+       24,3,   /* Image width and height in pixels */
+       0,      /* number of bitplanes in Image */
+       NULL,   /* pointer to ImageData */
+       0x0000,0x0000,  /* PlanePick and PlaneOnOff */
+       NULL    /* next Image structure */
+};
+
+static struct IntuiText ClipIText4 = {
+       3,0,JAM1,       /* front and back text pens, drawmode and fill byte */
+       -116,-1,        /* XY origin relative to container TopLeft */
+       NULL,   /* font pointer or NULL for default */
+       "Y Clip Border:",       /* pointer to text */
+       NULL    /* next IntuiText structure */
+};
+
+static struct Gadget ClipYCLIP = {
+       &ClipXCLIP,     /* next gadget */
+       134,46, /* origin XY of hit box relative to window TopLeft */
+       -199,7, /* hit box width and height */
+       GRELWIDTH,      /* gadget flags */
+       RELVERIFY+GADGIMMEDIATE,        /* activation flags */
+       PROPGADGET,     /* gadget type flags */
+       (APTR)&ClipImage2,      /* gadget border or image to be rendered */
+       NULL,   /* alternate imagery for selection */
+       &ClipIText4,    /* first IntuiText structure */
+       NULL,   /* gadget mutual-exclude long word */
+       (APTR)&ClipClipYCLIPSInfo,      /* SpecialInfo structure */
+       YCLIP,  /* user-definable data */
+       NULL    /* pointer to user-definable data */
+};
+
+static struct PropInfo ClipClipXSIZESInfo = {
+       AUTOKNOB+FREEHORIZ,     /* PropInfo flags */
+       26212,-1,       /* horizontal and vertical pot values */
+       10922,-1,       /* horizontal and vertical body values */
+};
+
+static struct Image ClipImage3 = {
+       45,0,   /* XY origin relative to container TopLeft */
+       24,3,   /* Image width and height in pixels */
+       0,      /* number of bitplanes in Image */
+       NULL,   /* pointer to ImageData */
+       0x0000,0x0000,  /* PlanePick and PlaneOnOff */
+       NULL    /* next Image structure */
+};
+
+static struct IntuiText ClipIText5 = {
+       3,0,JAM1,       /* front and back text pens, drawmode and fill byte */
+       -124,-1,        /* XY origin relative to container TopLeft */
+       NULL,   /* font pointer or NULL for default */
+       "X Scale Factor:",      /* pointer to text */
+       NULL    /* next IntuiText structure */
+};
+
+static struct Gadget ClipXSIZE = {
+       &ClipYCLIP,     /* next gadget */
+       134,15, /* origin XY of hit box relative to window TopLeft */
+       -199,7, /* hit box width and height */
+       GRELWIDTH,      /* gadget flags */
+       RELVERIFY+GADGIMMEDIATE,        /* activation flags */
+       PROPGADGET,     /* gadget type flags */
+       (APTR)&ClipImage3,      /* gadget border or image to be rendered */
+       NULL,   /* alternate imagery for selection */
+       &ClipIText5,    /* first IntuiText structure */
+       NULL,   /* gadget mutual-exclude long word */
+       (APTR)&ClipClipXSIZESInfo,      /* SpecialInfo structure */
+       XSIZE,  /* user-definable data */
+       NULL    /* pointer to user-definable data */
+};
+
+static struct PropInfo ClipClipYSIZESInfo = {
+       AUTOKNOB+FREEHORIZ,     /* PropInfo flags */
+       -25937,-1,      /* horizontal and vertical pot values */
+       10922,-1,       /* horizontal and vertical body values */
+};
+
+static struct Image ClipImage4 = {
+       69,0,   /* XY origin relative to container TopLeft */
+       24,3,   /* Image width and height in pixels */
+       0,      /* number of bitplanes in Image */
+       NULL,   /* pointer to ImageData */
+       0x0000,0x0000,  /* PlanePick and PlaneOnOff */
+       NULL    /* next Image structure */
+};
+
+static struct IntuiText ClipIText6 = {
+       3,0,JAM1,       /* front and back text pens, drawmode and fill byte */
+       -124,-1,        /* XY origin relative to container TopLeft */
+       NULL,   /* font pointer or NULL for default */
+       "Y Scale Factor:",      /* pointer to text */
+       NULL    /* next IntuiText structure */
+};
+
+static struct Gadget ClipYSIZE = {
+       &ClipXSIZE,     /* next gadget */
+       134,24, /* origin XY of hit box relative to window TopLeft */
+       -199,7, /* hit box width and height */
+       GRELWIDTH,      /* gadget flags */
+       RELVERIFY+GADGIMMEDIATE,        /* activation flags */
+       PROPGADGET,     /* gadget type flags */
+       (APTR)&ClipImage4,      /* gadget border or image to be rendered */
+       NULL,   /* alternate imagery for selection */
+       &ClipIText6,    /* first IntuiText structure */
+       NULL,   /* gadget mutual-exclude long word */
+       (APTR)&ClipClipYSIZESInfo,      /* SpecialInfo structure */
+       YSIZE,  /* user-definable data */
+       NULL    /* pointer to user-definable data */
+};
+
+#define ClipGadgetList1 ClipYSIZE
+
+static struct NewWindow ClipNewWindowStructure1 = {
+       114,16, /* window XY origin relative to TopLeft of screen */
+       346,76, /* window width and height */
+       0,1,    /* detail and block pens */
+       NEWSIZE+MOUSEMOVE+GADGETDOWN+GADGETUP+CLOSEWINDOW+ACTIVEWINDOW+VANILLAKEY+INTUITICKS,   /* IDCMP flags */
+       WINDOWSIZING+WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE+NOCAREREFRESH, /* other window flags */
+       &ClipYSIZE,     /* first gadget in gadget list */
+       NULL,   /* custom CHECKMARK imagery */
+       "Edit Clipping Parameters",     /* window title */
+       NULL,   /* custom screen pointer */
+       NULL,   /* custom bitmap */
+       350,76, /* minimum width and height */
+       -1,-1,  /* maximum width and height */
+       CUSTOMSCREEN    /* destination screen type */
+};
+
+
+/* end of PowerWindows source generation */
diff --git a/sys/amiga/colorwin.c b/sys/amiga/colorwin.c
new file mode 100644 (file)
index 0000000..a9cf25c
--- /dev/null
@@ -0,0 +1,256 @@
+SHORT Col_BorderVectors1[] = {
+       0,0,
+       59,0,
+       59,12,
+       0,12,
+       0,0
+};
+struct Border Col_Border1 = {
+       -1,-1,  /* XY origin relative to container TopLeft */
+       3,0,JAM1,       /* front pen, back pen and drawmode */
+       5,      /* number of XY vectors */
+       Col_BorderVectors1,     /* pointer to XY vectors */
+       NULL    /* next border in list */
+};
+
+struct IntuiText Col_IText1 = {
+       7,0,JAM1,       /* front and back text pens, drawmode and fill byte */
+       13,1,   /* XY origin relative to container TopLeft */
+       NULL,   /* font pointer or NULL for default */
+       "Save", /* pointer to text */
+       NULL    /* next IntuiText structure */
+};
+
+struct Gadget Col_Save = {
+       NULL,   /* next gadget */
+       9,77,   /* origin XY of hit box relative to window TopLeft */
+       58,11,  /* hit box width and height */
+       NULL,   /* gadget flags */
+       RELVERIFY,      /* activation flags */
+       BOOLGADGET,     /* gadget type flags */
+       (APTR)&Col_Border1,     /* gadget border or image to be rendered */
+       NULL,   /* alternate imagery for selection */
+       &Col_IText1,    /* first IntuiText structure */
+       NULL,   /* gadget mutual-exclude long word */
+       NULL,   /* SpecialInfo structure */
+       GADCOLSAVE,     /* user-definable data */
+       NULL    /* pointer to user-definable data */
+};
+
+SHORT Col_BorderVectors2[] = {
+       0,0,
+       59,0,
+       59,12,
+       0,12,
+       0,0
+};
+struct Border Col_Border2 = {
+       -1,-1,  /* XY origin relative to container TopLeft */
+       3,0,JAM1,       /* front pen, back pen and drawmode */
+       5,      /* number of XY vectors */
+       Col_BorderVectors2,     /* pointer to XY vectors */
+       NULL    /* next border in list */
+};
+
+struct IntuiText Col_IText2 = {
+       7,0,JAM1,       /* front and back text pens, drawmode and fill byte */
+       17,1,   /* XY origin relative to container TopLeft */
+       NULL,   /* font pointer or NULL for default */
+       "Use",  /* pointer to text */
+       NULL    /* next IntuiText structure */
+};
+
+struct Gadget Col_Okay = {
+       &Col_Save,      /* next gadget */
+       128,77, /* origin XY of hit box relative to window TopLeft */
+       58,11,  /* hit box width and height */
+       NULL,   /* gadget flags */
+       RELVERIFY,      /* activation flags */
+       BOOLGADGET,     /* gadget type flags */
+       (APTR)&Col_Border2,     /* gadget border or image to be rendered */
+       NULL,   /* alternate imagery for selection */
+       &Col_IText2,    /* first IntuiText structure */
+       NULL,   /* gadget mutual-exclude long word */
+       NULL,   /* SpecialInfo structure */
+       GADCOLOKAY,     /* user-definable data */
+       NULL    /* pointer to user-definable data */
+};
+
+SHORT Col_BorderVectors3[] = {
+       0,0,
+       59,0,
+       59,12,
+       0,12,
+       0,0
+};
+struct Border Col_Border3 = {
+       -1,-1,  /* XY origin relative to container TopLeft */
+       3,0,JAM1,       /* front pen, back pen and drawmode */
+       5,      /* number of XY vectors */
+       Col_BorderVectors3,     /* pointer to XY vectors */
+       NULL    /* next border in list */
+};
+
+struct IntuiText Col_IText3 = {
+       7,0,JAM1,       /* front and back text pens, drawmode and fill byte */
+       6,1,    /* XY origin relative to container TopLeft */
+       NULL,   /* font pointer or NULL for default */
+       "Cancel",       /* pointer to text */
+       NULL    /* next IntuiText structure */
+};
+
+struct Gadget Col_Cancel = {
+       &Col_Okay,      /* next gadget */
+       244,77, /* origin XY of hit box relative to window TopLeft */
+       58,11,  /* hit box width and height */
+       NULL,   /* gadget flags */
+       RELVERIFY,      /* activation flags */
+       BOOLGADGET,     /* gadget type flags */
+       (APTR)&Col_Border3,     /* gadget border or image to be rendered */
+       NULL,   /* alternate imagery for selection */
+       &Col_IText3,    /* first IntuiText structure */
+       NULL,   /* gadget mutual-exclude long word */
+       NULL,   /* SpecialInfo structure */
+       GADCOLCANCEL,   /* user-definable data */
+       NULL    /* pointer to user-definable data */
+};
+
+struct PropInfo Col_Col_RedPenSInfo = {
+       AUTOKNOB+FREEHORIZ,     /* PropInfo flags */
+       0,0,    /* horizontal and vertical pot values */
+       -1,-1,  /* horizontal and vertical body values */
+};
+
+struct Image Col_Image1 = {
+       0,0,    /* XY origin relative to container TopLeft */
+       263,7,  /* Image width and height in pixels */
+       0,      /* number of bitplanes in Image */
+       NULL,   /* pointer to ImageData */
+       0x0000,0x0000,  /* PlanePick and PlaneOnOff */
+       NULL    /* next Image structure */
+};
+
+struct Gadget Col_RedPen = {
+       &Col_Cancel,    /* next gadget */
+       32,12,  /* origin XY of hit box relative to window TopLeft */
+       271,11, /* hit box width and height */
+       NULL,   /* gadget flags */
+       RELVERIFY+GADGIMMEDIATE+FOLLOWMOUSE,    /* activation flags */
+       PROPGADGET,     /* gadget type flags */
+       (APTR)&Col_Image1,      /* gadget border or image to be rendered */
+       NULL,   /* alternate imagery for selection */
+       NULL,   /* first IntuiText structure */
+       NULL,   /* gadget mutual-exclude long word */
+       (APTR)&Col_Col_RedPenSInfo,     /* SpecialInfo structure */
+       GADREDPEN,      /* user-definable data */
+       NULL    /* pointer to user-definable data */
+};
+
+struct PropInfo Col_Col_GreenPenSInfo = {
+       AUTOKNOB+FREEHORIZ,     /* PropInfo flags */
+       0,0,    /* horizontal and vertical pot values */
+       -1,-1,  /* horizontal and vertical body values */
+};
+
+struct Image Col_Image2 = {
+       0,0,    /* XY origin relative to container TopLeft */
+       263,7,  /* Image width and height in pixels */
+       0,      /* number of bitplanes in Image */
+       NULL,   /* pointer to ImageData */
+       0x0000,0x0000,  /* PlanePick and PlaneOnOff */
+       NULL    /* next Image structure */
+};
+
+struct Gadget Col_GreenPen = {
+       &Col_RedPen,    /* next gadget */
+       32,24,  /* origin XY of hit box relative to window TopLeft */
+       271,11, /* hit box width and height */
+       NULL,   /* gadget flags */
+       RELVERIFY+GADGIMMEDIATE+FOLLOWMOUSE,    /* activation flags */
+       PROPGADGET,     /* gadget type flags */
+       (APTR)&Col_Image2,      /* gadget border or image to be rendered */
+       NULL,   /* alternate imagery for selection */
+       NULL,   /* first IntuiText structure */
+       NULL,   /* gadget mutual-exclude long word */
+       (APTR)&Col_Col_GreenPenSInfo,   /* SpecialInfo structure */
+       GADGREENPEN,    /* user-definable data */
+       NULL    /* pointer to user-definable data */
+};
+
+struct PropInfo Col_Col_BluePenSInfo = {
+       AUTOKNOB+FREEHORIZ,     /* PropInfo flags */
+       0,0,    /* horizontal and vertical pot values */
+       -1,-1,  /* horizontal and vertical body values */
+};
+
+struct Image Col_Image3 = {
+       0,0,    /* XY origin relative to container TopLeft */
+       263,7,  /* Image width and height in pixels */
+       0,      /* number of bitplanes in Image */
+       NULL,   /* pointer to ImageData */
+       0x0000,0x0000,  /* PlanePick and PlaneOnOff */
+       NULL    /* next Image structure */
+};
+
+struct Gadget Col_BluePen = {
+       &Col_GreenPen,  /* next gadget */
+       32,36,  /* origin XY of hit box relative to window TopLeft */
+       271,11, /* hit box width and height */
+       NULL,   /* gadget flags */
+       RELVERIFY+GADGIMMEDIATE+FOLLOWMOUSE,    /* activation flags */
+       PROPGADGET,     /* gadget type flags */
+       (APTR)&Col_Image3,      /* gadget border or image to be rendered */
+       NULL,   /* alternate imagery for selection */
+       NULL,   /* first IntuiText structure */
+       NULL,   /* gadget mutual-exclude long word */
+       (APTR)&Col_Col_BluePenSInfo,    /* SpecialInfo structure */
+       GADBLUEPEN,     /* user-definable data */
+       NULL    /* pointer to user-definable data */
+};
+
+#define Col_GadgetList1 Col_BluePen
+
+struct IntuiText Col_IText6 = {
+       3,0,JAM1,       /* front and back text pens, drawmode and fill byte */
+       17,38,  /* XY origin relative to container TopLeft */
+       NULL,   /* font pointer or NULL for default */
+       "B",    /* pointer to text */
+       NULL    /* next IntuiText structure */
+};
+
+struct IntuiText Col_IText5 = {
+       4,0,JAM1,       /* front and back text pens, drawmode and fill byte */
+       16,26,  /* XY origin relative to container TopLeft */
+       NULL,   /* font pointer or NULL for default */
+       "G",    /* pointer to text */
+       &Col_IText6     /* next IntuiText structure */
+};
+
+struct IntuiText Col_IText4 = {
+       7,0,JAM1,       /* front and back text pens, drawmode and fill byte */
+       16,14,  /* XY origin relative to container TopLeft */
+       NULL,   /* font pointer or NULL for default */
+       "R",    /* pointer to text */
+       &Col_IText5     /* next IntuiText structure */
+};
+
+#define Col_IntuiTextList1 Col_IText4
+
+struct NewWindow Col_NewWindowStructure1 = {
+       175,45, /* window XY origin relative to TopLeft of screen */
+       312,93, /* window width and height */
+       0,1,    /* detail and block pens */
+       MOUSEBUTTONS+MOUSEMOVE+GADGETDOWN+GADGETUP+CLOSEWINDOW+VANILLAKEY+INTUITICKS,   /* IDCMP flags */
+       WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE+NOCAREREFRESH,      /* other window flags */
+       &Col_BluePen,   /* first gadget in gadget list */
+       NULL,   /* custom CHECKMARK imagery */
+       "Edit Screen Colors",   /* window title */
+       NULL,   /* custom screen pointer */
+       NULL,   /* custom bitmap */
+       5,5,    /* minimum width and height */
+       -1,-1,  /* maximum width and height */
+       CUSTOMSCREEN    /* destination screen type */
+};
+
+
+/* end of PowerWindows source generation */
diff --git a/sys/amiga/cvtsnd.c b/sys/amiga/cvtsnd.c
new file mode 100644 (file)
index 0000000..0e5f9c5
--- /dev/null
@@ -0,0 +1,96 @@
+/*     SCCS Id: @(#)cvtsnd.c   3.2     95/09/10                  */
+/*     Copyright (c) 1995, Andrew Church, Olney, Maryland        */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+    short namelen;
+    char name[62];
+    char misc[64];     /* rest of MacBinary header */
+    long FORM;
+    long flen;
+    long AIFF;
+    long SSND;
+    long sndlen;
+} AIFF;
+
+typedef struct {
+    char FORM[4];
+    long flen;
+    char _8SVX[4];
+    char VHDR[4];
+    long vhlen;
+    long oneshot, repeat;
+    long samples;      /* 'samplesPerHiCycle' in the docs - usually 32, so
+                        *    we'll use that */
+    short freq;
+    char octaves, compress;
+    long volume;
+    char NAME[4];
+    long nlen;         /* should be 64; see name[] comment */
+    char name[64];     /* for simplicity, i.e. just fwrite() entiree header */
+    char BODY[4];
+    long blen;
+} IFF;
+
+
+main(int ac, char **av)
+{
+    FILE *in, *out;
+    AIFF aiff;
+    IFF iff;
+    static char buf[16384];
+    long n, len;
+
+    if (ac != 3) {
+       fprintf(stderr, "Usage: %s input-file output-file\n", av[0]);
+       exit(20);
+    }
+    if (!(in = fopen(av[1], "r"))) {
+       fprintf(stderr, "Can't open input file\n");
+       exit(20);
+    }
+    if (!(out = fopen(av[2], "w"))) {
+       fprintf(stderr, "Can't open output file\n");
+       exit(20);
+    }
+
+    fread(&aiff, sizeof(aiff), 1, in);
+    memcpy(iff.FORM, "FORM", 4);
+    iff.flen   = sizeof(iff) + aiff.sndlen - 8;
+    memcpy(iff._8SVX, "8SVX", 4);
+    memcpy(iff.VHDR, "VHDR", 4);
+    iff.vhlen  = 20;
+    iff.oneshot        = aiff.sndlen;
+    iff.repeat = 0;
+    iff.samples        = 32;
+    iff.freq   = 22000;
+    iff.octaves        = 1;
+    iff.compress= 0;
+    iff.volume = 0x10000;
+    memcpy(iff.NAME, "NAME", 4);
+    iff.nlen   = 64;
+    strncpy(iff.name, aiff.name, 62); iff.name[aiff.namelen] = 0;
+    memcpy(iff.BODY, "BODY", 4);
+    iff.blen   = aiff.sndlen;
+    fwrite(&iff, sizeof(iff), 1, out);
+    len = aiff.sndlen;
+    do {
+       if (len >= sizeof(buf))
+           n = fread(buf, 1, sizeof(buf), in);
+       else
+           n = fread(buf, 1, len, in);
+       if (n) {
+           fwrite(buf, 1, n, out);
+           len -= n;
+       }
+    } while (len && n);
+
+    if (len)
+       fprintf(stderr, "Warning: %ld bytes of sample missing\n", len);
+    fclose(in); fclose(out);
+    exit(0);
+}
diff --git a/sys/amiga/grave16.xpm b/sys/amiga/grave16.xpm
new file mode 100644 (file)
index 0000000..bb0466d
--- /dev/null
@@ -0,0 +1,223 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"400 200 16 1",
+/* colors */
+"` c #66686A",
+"a c #797979",
+"b c #929291",
+"c c #43444A",
+"d c #758A74",
+"e c #F2F2F2",
+"f c #D1D0CE",
+"g c #066906",
+"h c #065506",
+"i c #53535C",
+"j c #0C0D0F",
+"k c #A3A5A2",
+"l c #2D332E",
+"m c #C3C4C1",
+"n c #B4B4B2",
+"o c #07840A",
+/* pixels */
+"jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjjjjjjjjjjjjjjljjjjjjjjjjjljljjljljjljjllljljclljlllljlllljlllllllllllllllcicl``clcllclclllclclclcclclclcccccccccccccccccccii`iiccicicicciiciiiiiibiic`iii`a`iiii`icaii`iiii`iiii`ii`ii`iii```iii`i`ii`ii`ii`iiii`iii`ii`iifi`ii`ii`iiiiiiiiiiiiiiiiiiiiii`iciibicicicicciiccciiibiicciiiiccccbicicccccccciccclcccccclc`aiciiiciccclilccccccccccclcccacccccccclccclcclccc",
+"jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjjjjjjljjjjjjljjjjjjajljjljljljljjjjljjljc`baljjllcljjcjlljllllllllllllllllllllllcclllllllclllcclcllclclccccccccclccccccccccccicciicciicicicic`cciiciciciciacicii`iiiiii``iiakii`iiii`ii`ii`iiii`bkb`i`ci``iiiiii`iii`ii``i`iiiiiaiiiiiiiiii`iiiiiiiiiiiiiiiiiiiiiciiciciicicciciiiicllic`iciiiicicciliccccccccccccc`ccccliccccccccciciccclccccclclclclcclccclclclllccclcllccll",
+"ijjjjjjjjjjjjjjjjjjljjjjjjjjljjjjjjjjjjjljjjljjjjjjljljjjjjjjljjjljljljljjjjlljljljljcclljllllljlllljllllllllllllllllcclccclcjcllclclclclllcclclcccccccccccciccccciiic`a`icciiccciciiiiiiiiibi`iiiiii`ii`ci`iii`ii`i`iiiiiiiii`iii``ici`i`i`i``ii`ii`iiiiiiic``iiiiiiiiiiiiiiaiiiiiiiiiiciicicii`iiiiiliiccicicccicccci`ccicccicccclccinccccccccclcccaccccccclccccccccccilcl`lllccclcclcclcllcllclcccclllilcllci",
+"jjjjjjjjjjjjj`cjjjjljjjjjjjjcljljjjjjjjljjljijjljjjjjjjljljljjljljljlljljllljjljllflcjljllljljlljllllcllllllllllllcllllccllcc`clclllcllcclclcccclccccccccciccciciccccccic`iciic`iiiiciiiiiiiaiii`iii`i`icak`c``i`iiiiii`ii`i`iii`i`ii`iiiiiiici`iii`ii`i`ii``iiii`c`iiiiiiiii`iiiiiiiiciiiiiiiiiiiccccciccicicciiccccciaillcccciiciccclcccccccccccccc`cclclccillccllcliibilikaicllcclccccclcccclcccccllccllcclcl",
+"jjcjjjjjjjjljjjjjjjjjjjjjjjjljjjljjjjjjjjjjjljjjjjljjcjjjljjljjljjjljjljljjjlljllljlllcljllllllllllllcclllllllllclllcclccibccclclcclcclcllicicccccccclcccccccciciicciccciaaiciccciiiiiiii`ciiiiii`iiiii`ic`iiiiiiii`ii`iiiiiiiiii`iiiiiciiiii`i`iiiii`ii`iiiciiiiiiiiiiiiiiciiiciiciciiccicciiiiiicicc`cccccccicccccicciiccicccicclilccccccclccccclccllcccilcccclcciclccciclcclccclccclclllcllcllccllcccclaacccl",
+"jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljljjjjjjjlljjjjljljjjjjljjljjljljlljljlljlllllljajljljlllllllllllllllcllllllllclccilcicclc`clalcclclclcclcccicclclccccciiccicciccciciiiiiiciib`iiiiiiiiiii`iiii``i`i`iiiiiiii`iiiiiiiiiiiiiiiiiibaiiici`iiiiibiiiii`iiiic`kaiiiiiiiiiiiiiciiiciiiciiciciccicciiiiciiiciccicicccccccciclcccccciiccccaciclclcccciilcccclcclcclcllclilacclcccclccclclcccccclccclclccllcclllllkblllc",
+"jjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjljjjljjjjjljljjjjjjjljljjljjljljlllljljljljjjjjljllljcjllllllllllllllllllllccclclabclccccciccccllclclcclcclclccccccccciiaiiicciciiicccccciiiiiiiiiciiiiiicii`i`i``i`iiiii`iiiiiiiiiiiiiiiiiiiiiibiciiiicciiii`iiiiiiiiiie`i``ic`iiiiiiiiiciiciciiciciciciciiiciic`cccclcccccccccciccccccciccciicilcillcccccclciccccclclccclibaili`lillccccciicliccccccclcccllallclliiiclcliilcll",
+"jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjljjjjjjjjljjljjjljjjjjljjljljlllllljllljlclllllljlllllllllllllllllllllllllcccclccliiccccciccccclclcclccccccclcciccccciacciciiiccci`iiiiciiiiiiiiiiiiiii`i`c``````i``iiiiciiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii`kciiiiiiiiii`c`iciciiiiiiciiiiiiciccicicicciciiiiii`ifcccciccicccccccccccccccclccccccclcclccclccclclclcllilclcclcllclcliilclclclccicccccccccllllcecclclliaacllcllclc",
+"jjjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjljljjjljjjjlljjljjjljljjlijjllllllllllllljljajlljlalllllllllllllllllllllccccclllccclclccccccccccclcccccc`clcccccccccccicacicciciciciiiiiiib`iiciiiii`c`iiii``iii``ii``ciiiiiiciiiiciiiii`biii`iiiiciiiiciiicib`iiiiiiiiiiiiiiiiicii```cccciciciciiiiiiiciiiciiccccccccccciicciccccccccccccciccccclccclcccllccclclc`ccclcclcccccclcccllclccclclllcllcliccllclmccclcccl`lclclclll",
+"jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjjljjjlljjjllljlljjjljljjjljljlcllllljcljjcljlllijllllllllllllllilcllcccccllicllllclcllcclliccccclccclcccccccccccccccc`iciicicciiiaiciciicl`ici`iiiiiiii`ii`i`ii``iiiiiiiiiiiiiii`iiiiiaciiciiiiiiiciiiciiiiiiicici`ciiciiiiciicciiiciiciciiiciiiiiii`cbi`liicicccccccccclccccccccclclccccccclcilccllccccllcclcccclcclclclllllcllllcllllllclcllccccclllcllilllclllclilillccll",
+"jjjjjjjljljjjjjjjjjjjjjjjjjjljjjjljljjjjjjjjlljjljlllljllljllljlcljjljljcjlllljcljllllcllllllllllim`lljccllcclcbacllcllclccliclcccclccccccccccccccicciciciiciiciiiiiibiiiib``iiii`i`iiaii`ii`iiiiiciiiiiiiiiiicciiiiiii`iiiiiciiiiciciici`cciiciciiiiib`c`aaicciicicciccccciiiiiiiicciiicciilccccclcccccccccccclccccccclccliccccclclclcillccccllcclclccilcccclclcclcccclclclclllcllllcclllllllclllcllcllclcll`cc",
+"jjjjjjjjjjjjjjjjjjjjijljjjjjjjljjljjljjjljjjjjjcjljljlcjjlcljlljkclllllllcllllljllllllljllllllllllliiccccclllllcccllcclcclclclcicccccclcclcccccccicccciicciciiciiiicc`ciii`ciiiiiiiiii``ii`iiiiiiiicii`i`i`iii`iicic`ii``iiiiiiiiiiciciciiiicc`ciicici`cc`iiiciciicicciicicci`iiiiiciciicicccibiccccccclcccccclclcclclcclccicclclcicclikclcllclllcllcllclccccllclclcliclci`cllclllillliccclcllclclbilllclllclcal",
+"jjjjjjcbljjcajjjjjjjljjjljljjjjjljjjjjjljljjljjjlljcjllljlilllllaljlljjl`mllljcillllclllllllllllcllclllciiilccclllclclclcclckaclccccccccclccccccccciiciciiciiciiciiiiii`ic`ii`ii`ii`````i`iiiiiiiiciiciiiiiiiiiiic`ibiiciiiiiiiiicicicicccicicicciciccccicccciiicccciccciccciiiiiiiiciccii`cicbicciccciiciclcccccccclcclcccccllcclllliclclcccccclcclcllclcccclcllclclccllc`lllcllcll`llllllcllllllilllllllclcclc",
+"jjjjjjjljjjlijjjjjjjjljjjjjjjjljjjjjlljjjjljjljljljajljljlljlljcljjlllllljlljijjlllllllllllllllcjcllllaclclllllcccclccclllccclcccccccccccccccccii``a`cccciciciiiiic`i`baba`iiii`ii```ii`ii`iiiiiiiiicciiccciciiiic`ia`iccii`c`iiciciccccccccbcccccic`iciciiiiccciccicicccccccccciiiiciccccccciccccccccccciicii`a``icccccccilclclciaa`iiccciclllcllclcllcllcccllllclllcllllclclcllllamiccaclllllccllllccllclcllcl",
+"ljjjjjjjjljjjjjjjjljljnjjljljljjljllcjljjjljjjlbjllblljljjjljlcljclljlljlljclikllljlllllllllllllcljclccccccccllclllllcccccclcclcccciccciccciabbkakbnaccici`iciiiiiiic`bbnnnnkbaa``iiii`ciiiiicici``ic``ciiiaiiiiiiiciiciciiiiiiicccciciciiccbcciiccccccciccciicicicicccccccccicccicccccccliccicliiccccici```iabkbaccccccccclccclciammnbbbaaicclcclclclclllllllllllclllllclllllllllccijlakillcllllllclllllllcjcll",
+"jjljjjjjjljjjjjljjjjjjjljjjjjjljjjjjljjjljjljljjljjijjljljl`liklljljllllllillljlllllllllllllllllllclllccccllccclcccccllcclcclccccccccciii`abnnbknmnmblciiibiiciicik`i`nbkmnmmnmnnk``i`niiiiciiiiciicccicccibciciiiciciccciciiciccicicccccccciccccccicc`ccccicibfcccccccicccccccccccccccclc`cclcclcci`abbbbaii`nnk`ccccccclllc`cciiknnnnbbakbkkicllclllclclllllclclllcllllclllllllllllclccllcllllllllkalllcljclll",
+"jljjljjjjjljjjliljjljjjjjcljjjjjjljljljljlljjjljljljlljlljlijblljljlljljllcjllllllliklllllllllcllllclccccccclclcccclccclccclcccclccciiaa`babnmnnmnnmkjiiccacciiiiiiiiakkknmmmmmnmnkkbbaiibciiccciciiccccccccccciciicicciccccccciicccccccccccciiiilicicccccccciiiilcccccci`ailciclcccclcccckbcllclciabbkkb`icianmnkcccclllclccccii`ammmnbabknkkaa`iillclllcjcclllllcllli`lllllllllclclllclllllllllllllljcllclllll",
+"jjjljjljlljljjjljjjjjjljcejjlljlljjjjjjjjjjjjlljjljljljljljllkijlllllllcjkllllcllllcallllllllllllclcclilcclclclcllcccllccccccccccc`bk```baabnmnmmmfmklciiciiiiiciiciiakbbknnmnmnnnkbbbbaknicciiiicccciiiccicciccccciicciiccicccccccccccccccccccccicililccccccciiccicccccciiclcclcccclilclliclccli`abbbnkkacciaknmkllllllclllcccii`amnnnnbbakbk`i`aaa`ccicclllcclcljclllclllllllllllllclllccllcllcjcj`alllllllcll",
+"jjjjljljljjjjjjjjljljjjjljjjjljjjjlllljlljjlljjlljljljlllllljilljllljlciacjlljb`llllclllcllllcclclllccciccclclcccclcccccclccllc`aabnkii`bbabbnnnnnmnbljiiiciiiiii`i`i`kkkbknmmmnmnnbbknkak`iccccicicccccccccccccicccccibccccccclcciccccccccccccciciicni`ccccccccccccccclcclccclcclacclcclclliiciabbbbbbnb`cc`bkknnlllllclcllccc`iiamnknnnkaaknaiiabbabbkkcccclccjcclllllllllllllllillllllcllcccllllccelllccclicl",
+"jljjjjjljjjljljljjjjjjljjjjjljbjljjjjjjljjljjlljjljljlljljjljljlllllljlllclllcjllllllllllllcllllll`ccilicccclclc`illcccccccci`bnbaakk``abbb``knbnmmkbllciii`i`i`i`i``akbbbbkmmnnnnbbkkkabnmnb`icccccccciccccccccccccccc`ccccccccciicccccccccccciccccciilcccccccclcclclclcclcclccclicllcllcc`aiiabbbkkbakacl`bnnknklccllllcclciiii`bmnknmmbaabka``akaaaakkicllclccibclllllllllllllc`lllllllcllcllllllcjlccclcc`ll",
+"jjjjljljjjjjjjjjljjljjjljlljjjljljljljljljlljljlljllljlljlcjllllllllllllljcjllmclllljcllllccllllcclcccccclcccccccccclccccciibnmmaaabbbbbbbb``bmbbnmnbljc`ii`ib`iikb``bnkbabbknmmmkbnnkbbbkmmkkaccccccccccccccccccccccclccccclccclcicccclclccclciic`lccciccccccccclclilccclcclcllcllllc`cc`abaliabkkkkkabiciabnmnfnlllllcllllii`i`i`nkbbmmnbbabaakbbba`iknbbbciclcl`llljcllllllllllllllllllllcllllclljclcclllclll",
+"jljjjjjjljjljljjjjjjlljjljjljjjljjjljljliljljljljlljlljllllllljljljllllllllcllallllclllllcbkbaclcciillclcccccccclcccccccciaaaknknbai`bbbbbbb`bmnkmnnalliii`i`aiii`ii``bbbbbbnmmnmmbkkkbbbbnmnnnbaiccccccccccccccccclcccillcccclclccllcclcclclccccclciliccclclclcclclcllclcclclcllcilclbaabb`icaakbbknkbaii`abknmnbclllccllllii`iiiibabbbkkkaa`abbbbkbaaknnkmnalclllclclllllllllllljllllllllccllclljlclclllclclll",
+"jjjljjjjjjljjljljlljjjljlicjljlllljljli`cccjl`cjljlljlllljllllllllllllllljcjlllllllllllllliclclclcmbclicccccccclccccccci`bkbbbbbbaaaabbkbbbbabnmfnbacljici`iiii`ici`iiiaabbbkmmnmnbbbababbnnmknnkbiclc`acccccccclccccclccclccclcllclccccccclccccccicllciccccccccllcclilccllclclclcjccababbicc`bbbbbkknbac`ababbaicllllllllllcii`i`iiiababbbaaaabbbkabbabnnnmmfna`acclclllllllllllllllllllllllllclcalllllclclllll",
+"jjjjjjljjljjjjjl`ailjljjjljjljjljlc`aabkbaba`aiclljllljljcb`ljlllllllllllclllclillllclllllcllclcililclkclcccccccccccccannbabbbbaaaabbbbkkkkbbkmnbiljlllciiiiic`i`i`iiillcakbbknfnkbbnbkbabbkmnnnknnbilccccclccccccccclcaacllcllccclclllcllclccccclclccccccccclllcclclbclclllcllllccl`aaabaicabkkbbkkknka``bkbbilljlllllllllcciiaaijlljcabaaaaaabbbkkkbbknmnnmnnmbillccjlllllllllljlllcllllllllllllllllclllccllll",
+"jljljljjljjlljljcjljjljljjlljljc`bbknnkkkkkkkbbbbbcjllljllllllllllllljlllllllllcclllclllllclllcacclcccclcliliclcclcc`mfnnmkbkkbaai`a`aakmkkbikmmlllljllciiii`iiii`iin`iljcbbdbnmnbbbmknnkaaakmkmmnbbbilclclclclcclclk`abilcaclclcllclcclicccccclillcccclilccclclllclllclllcclllcllibbbaaailiakkkkbbnkkk`bbbaballllcllllllcllci`a`lljlllcba`c`a`aakmbkbabmmnnmnnmbacllccllllljllllllllbjlljljllllllclllllllclllll",
+"jljjjljljjljjljjljljljjjjljjlc`akkkkbkmmnnmnkbkkbkb`cjjllllllllllllllcllllllclacjcllllflclllclc`cclliiicclccclciaciabkkmnmmkkka`cc`a`akbnkkb`knkjllljlll``iiii`aiiiiicccllakkkkkkbbbnnmnmkaabnmnkbbkkbiccccliacllillilccccllli`llllcllllcccclllcailllllcllclcclcclccllllclllllllliabka`i`clibbkknbbkknkbkkbbbillllllllllllllc```llllljjlb`cci``abbknkbianmnnmmnnnallilllljllllcjllljllllllcllllllllllcllllllijjl",
+"ljljjjjjljjljjljljjjjjlljljjibbkmnnkknnfffmnnknnnkbaa`clllllllllllllllllclilllllcccllclclcllccccccclcccccccclcic`cannbbmnnmnbaiiii``akkdknkaabmblljllllciiiabknmniiiiiijljannkkkbbbkkmmnmk``bbkkbbkkkkkaclcclclclclcllclbilcclllillllccllccclclcclcliccll`llilcclllllllclllllllliabba````ccabbbkknbbkkbknkbbbiljcljcljcbnkbabballlljlllc`iii`a`bkbbknbabnnnnmnnnnalcicilllllljllllllljclljljllljljjclllllllla`ll",
+"llljljljjljjljljjlj`ljljljlikbbmnfnnmmnfffmnmnmmmkkbkbiiljlllllllllllllciaiclcllllllclcllclccccclcccclcclaclcilc``bknnbkmnnnka`bba`adbkbbkbaabmkcljllllciicbnmnnkiiiiicljcanmnmnkkbbkmnnn`ibbabbbknkabknbclclllclllcllclcllllllcllcclllllilllilllllliclllllcjliccllclllclclllccci`aa`i`aii`bnkbkkkbabaakbnnkkacllllllc`knmkbbbbljjjjjlj``abba``bkkabkaaaknmnmnnnbacli`acllljllllljlllllllllljlbblljllljcllclabll",
+"jljljljljjljljjljjl`jjljjcabkkbefmmfnfefefffmffmfmfnkkbaillllljlllllcllll`llllllajiclllclcccccclcclcccccc`lciccakbbbknkbnnnmnnnnbaabbbbkbb`iadmmaclllllcclcaknkmmkiiiiicc`knkmmmbkbnnnnnbi`bkbbkbkbbbaakkaiclcclclllcclllcclllllllllllcll`ill`cllcllcllcikllillc`cccclclllllcciii`aa``iii`akkkkbaaaaiakkbknknkaallllcabkknnkabkallllllibkmka`aaabkbbai`akmmnmnnmballcibbillcljllllljlljljlllljcjlllljlllcjlllljl",
+"jlljljjjjljljjljlljljlajl`bkkkkmffffffeffefffmmfffmmnmkbbillllllllllllllcjcllclllilllilclcccccccllclcccccccclcakmnbbbbbkbkmnnmmbabnkbbbkk`cc`bmmmb`ciia`iii`aabnnmaa`c`abkknmnmmbbknmmnkbiababbbaba`ba`aakk`clclllllciccllllcllclllllllllclllllllllclllclllllllliclclcclcclli`aaaaaa`iclc`bbnnkbaiiiibnbnbbknkbb`ccci`knnknnkbbbb`cjjikfmnbabnnbakkk`li`knmnmnnnb`icccaabclilljll`llllllllljllcljlljlljlllllljal",
+"ljljjllljljjljljjjljlabliakknmknmfffefmffefefffffffffnmkkailllllllllllialclcllilcllc`jicccccicccccccclcccciccbnnknnkbbkbbknnnmnbbkmmnkbbbiccabnnmmnknkb`ccii`abmnbbbmknnmmnmmmnmkbkkfmnkaa`aabaaa``ia`akbbkkacllccllliillllllllljiaaillclllclllcclllllllllllllclclllllcllcciaaabkbb`iicciabbkkba`iiiaknbmkbbkkbabknbabnknkknmkkbkabbkmnknnabnmmkbbbbiliabnmmnnnnbbaicii`akallllljilljjllllicljjlljljcljljllllcbl",
+"jljllllcjjljljljlljlljllbbnnmmffffeffeefeefefeeffmmefmmknkbclllllllclllclllclclccccccicccicccclcccccccccclccbnmnnnnmmnbbbbbmnnkknmnnfnbb`i`aabnmmmmnnnbaiii`abbkkbkkknkmmfkmnmmmnkkknnmnaaabkkbaaiii`bknbkbkbcllclclclblllclllllllllllllclllllllcjllclcllllllllllllllllllliabbaaaaa````a`abbkba`a```abbknnkbbbkknkkk`bnmnmnnknnmkbkbabnmnnbnmknfnka`iiaabnmmmnnnnbaci``aabkaljllljlljcljllljllllljlliljlljlljjll",
+"llljljjjljljjljljljjljc`bkbmnfffefeeeefeefeefffeefffmmnnmnkaclllclllclllllclccccccclccccccciccccccliccclbccanmnmmmnknmnbkbbkmnnnnfmmnmnbi`abbaknmnmnnkb``iai`aa`aabknmmnmnnnmnmmmbkbkfnnkbakmnabaabaabnakbbkbbilllllllllllllllllllllllllllllllllllcjallllllllllllllllllllinkbabbba`iaaaa`akbb``````abbbbkfmbabnmmnbakknmmnmnmnnnmkbbbbknnnnnnnmnnmbiiabbakknmmnnkb`````iaa`ailjlljljlljlljlljljlllljljljiclllljl",
+"jljljljljljljljljjllljlbknkfnffffefeeeeefeeeeefeeeefffmmnkkbillllllllllclijcclclclccclclccccccccicinacciiibnmmnnnmnnnmnkbkbamnkmnmmnmmnabdaabbbbmmnnnba``iaii``ii`bnknmnnmnmmmmnnkkbbknmmkbknnbkkbbbabnbbkkbbnaclllllllllllllllllllllllclllllllllllcllllccclllllliclllllikfkbaaaaa``aba```baa`a`aaaabbbbkmnnknmnnkbbknnnnmmmnnnnnnnkbbbknnnnmmmnnnabaaakabbnnmnnba`````c``i`iicjlllljllllljllllijjcjlllllcjjjllj",
+"lljljjljljljljljlcjjllkbknmfnffffeeefeeeeeeeeeefeeefffffmnkkbclllllcl`llllccccklllclclcclcccclcccccilccccbmmnmmnmnmnnnmmkkbbnnnbknmmnmkkmkaabbbaknnkkbaa```c``iiiabkbmmmmnmnnnnmmmkkkkknmnbnmkbkkkaa`bbbbbkkbnkacllljcllllllllllllllllllllllllllllllallllllllllll`cjlljlabkbab`aaa`iaba``abaaaa`aabkkkkkknnnmmnkbabnnnnnnmnnnmnknmnmkbbbnkkbnnnnnkbnnabbbbbbnnnkkaaiii`iaiciaailjjlll`bialjlljjclljljajjljjlljll",
+"jlljjljljjljlljlcjllljanbmmfnffefeefefeeeeeeeeeeeeeeeeffmfnnk`clcllllaclllcclllclcllccciclcccccccccclicc`mmnnnmmnmnnnknmfbbbbdba`abbdbabkaaaabkbbnnnkbaa``ic`iiiaaabbmnbkkbbdbbkbbabkknmnmkmnnabkkbabbkbkbnkkkbb`llcjllllllllllljllllllllllllllllljlllclllljlllljlllcjl`kbbbbbaaaa```a```abaab`ii``aabbabbbbbkkai`bmnnmmmbbkbkmnnnnmka`aaa``aabbbbaknbabbkbbknmkb``a`ii``iiiaaacllijlcklllbljlljljlljijlljla`ljj",
+"ljjllljljljljlljljjljibbknffmfeffeeeeeeeeeeeeeeeeeefeffemfmnkbclllcllclcicbcclillccccclcccccccccclcciclinmnnmnmnnnmmnnnnnnkaai``lllllcllllcllc`abknmnac`i`clclliaaaabnalllclclcclcllcc`kmmnnnkbbbkbkknkknkkkbbaa`iccclljlllljllllljllllljllllllllacljljlllllllllljllcliabnnbaaabbaa``````aababllllllcllllcllcciii`bnnnnnncllllnnnnnnnilcllllllcllllciadkbkkbbnnnb`i``iciilc`aaaaclealljllcecllljjjljljjljljjjjll",
+"jjljljjjlljljljlljllclbbmnmffeefeeeeeeeeeeeeeeeeeeeeefefffmkkb`lclcllllclicciclccclccllccccccccccicccciknmnnmnnmmnnnmnnnkmnbiia`lllllllllllllllliaknnb`i`aclllli``i`abilllllllljllllllliknnnnkbbbbbbknnnkknkbkaiiaillljlllllllljlljlllllllljllllcjjlllcllllllljlllljlcabbbba`babbba```iaaaakkbllllllllllllllclicadkmnmnknlllllmmmnnnmijlllllllllllllccibbkkkkbknna`i```icli``i`aaclljjljljlljjlllljljlljjllllllj",
+"ljljljllljljljlljifccibbmmfffeffeefeeeeeeeeeeeeeeeefefeffffnknaccclccclcccicclcllllclcccccccccccccccccanmnnnknnmnnmnmmmnnnnbi`nilllcllllllllllllliabbkb`aacllll```iiabillllllcllllllllllibnmnnbabbbknnnnnnknbkaiib`ijljcljlljljllllcljcljlllljll`cjlcjjlljllljlllllllibbka``bbbkbba`i``abbbknbcclclllllllclllllladnnnmnnncllllnnnnnnnallllllllllllllllc`bkknbbakbbaaaaaiiii```ciaalllllljljljljjjl`jljllljjjjjjl",
+"ljljljl`llljlljljlcclaakmnfffffeeeeeeeeeeeeeeeeeeeeefefefffmnnacccccllccilcclclccci`cclccccccccccccccinknnmkkmmknnnnnmmmmnbaaakicclc``ai````illlllibbaabaalcllc`aai`abilllciada```aicllllannnmkbbbknnkkkkkbnbk````aklllllljlllllljlillijllljlllljlllllcjlljllllljljllbknbaa`kkbbkbai``abbbbbnbilclcccici`icccccllaknnnkkn`lclcknnfnmndlllc`````aaaaccclldbnnbbbabbaaaa`a`ai`aaiibb`jlljljllljljlll`ljljjjjjlljlj",
+"jjljjljcjljlljlllllllcbnnmneemefeeeeeeeeeeeeeeeeeeeeefeeffmmnbbiccciccccccclcclcccccccccliclicccccicibknnnnnnnnnmnnnnnnmmkabbbbiliclnmmkkkbbkalcclcbbbbaaallllc`ab``abcllllaknffnnnkalllllnkmnbkbbkkknnkkkkkbb```i`alljllllljlljlllilljlljllljlljlllljllljlljljlllljakbkkkaabnmbababbbbkbbbbkacllccciiii``aablllccnkknnnkillcldnnnmnmblllc`kkkknmmnblcillbnnkbbbbabba```aaaaaaa`aabcjlljljljlljljjljjjljlljjjljj",
+"lljlljljlljljlljlllllibnkmnmffefefeeeeeeeeeeeeeeeeeeefffeffmmkkaccccclcillcllclclccccccci`icicccciciakkbknkknnnnnknnnnmnnbadbkkilclcnnmkkbbkkbllllcabbkabblcllcaabaabkilcclakknnnkbkbcilllkbbbbbbbbkbkkbkkbbbaa`iaaaallljjllljljljlclljlllljlllllljljljlbcjllljljjj`nnkbknbbabkbaabkbkkbbbbbbalcllcciabb``bnnilclckkknkkniccccannnnnnalllc`bbbbnnmmnillcldbdnkdabbbbaaaabaabab`aabb`ljlljljljljljljljljjljjljljl",
+"jjljllljljllllccjcljlcbmknnnfefeefeeeeeeeeeeeeeeeeeeeefffemmnkk`cclccli`clbcblilccccccccciccccciial`kkkkknkknnnnnkknnmnnbdaabbkclllcknmnkbkmn`cclliaabbbbbcllclabkdaabilllcbkkkmnkakaliilibbbakbbkbkkbbkkbkkba``ibbaailllljlllllllllljlljljlljljlllillllljlljlljllcaknnbbkkbaaa``abkkkkbbabaa`cllcci`abkkabkkclllcbkknkknilllcannnnnk`clcc`bkbabmnnkllccldkkbkb`abbbbbkbbbbbbbbaabknajljlljljljljljljjljljllljll",
+"ljlljjjljljljlccjlllccamnnnnfemeefeeeeeeeeeeeeeeeeeeeeffmffmfnbacclclllillil`cclcclccccclccccciia`canbkknnnnmnnnmnnknnmkkiidnbbclccl`aa``i``illclc`abbbkkbcllllbbkb``b`llcl````a`a`illicl`bbbbkkabbbbbabbbbkb``i``aaaalljlljjljjljljllljljlljllljlcalljlljllljlibjcbkmkmkbab``iiabbbkbbkbabbaailllcci``iii`icllcl`kkknnnm`cllcannnnnb`lllli```i`ab`ccllccnfnnkdbabbbbkkbakbabkbaiabnkijjljljljljljljjljljlllljlj",
+"lljlljcjlljlljclclljclamnnknnenefeeeeeeeeeeeeeeeeeeeeefemffmmnb`clcllcllcclccclicccccccccccccciiicinnkknknmnnnnnmnmnnnnkbcc`mnklccllllcllllclccll`kkkkbbkkclclcbbkbaabillclcclllclllllllidbbkbnkbkbbkkbkbbkbaii`aiabbklljlllljlljlllljljlljljljlljlcjljllljjjljljlbbannnmba`ii`akbbbbbbbbbkaad`lllclllllllcljlllidmkbnnmn`cllcannnnnb`llccclllllllccllcldkmmnnmkkbbbbkbbbbbbbbbb`babkaljljljljjljljjljllljljljjl",
+"jjljlljljllljllljjcc`l`bnmnnkeffefeeeeeeeeeeeeeeeefeeeeemffnnnb`llclccccclccclciclccccccccicccciccknknkkknnkkkbknnnmnmnka``dnkkllclccllllllcllll`kmnkkbkkkclcllbkabbabclllllllllljlllllibkkabbnkknkbbbbabbkbai`aa`abkkbjljljljljljljljljljljljljljjlljljjlljlicjliakkkmnnkkacc`kkkkbbaababnkabalccclllllcllllllcdnnkkmnkkallll`nnnnnballiclllllllllllll`akkkmmnnkkbkkbbbabbabbbabbbbmnclljljljljljjljljljljljjjj",
+"alljaklllljlllllllllllibknmnneefefeeeeeeeeeeeeeeeeefeeeffmfnmkbicccllclllclcliibcccccccciciiiiiic`nmnnnknnnbbbbkkknknmnkbbkkkbdccclcccllcijcjlcbnmnmnbbkbklllllbkbabbbilcclclllllcllc``kknnbbbkknmnbkkbabbbaa`aaabbabkncljlljjljllljljljljljlljljljljlllljljljjllkbbaannkknac`bkkkkkbbbbbknkbb`lclllllllllcllcibnmnkkmkkb`ccccannnmkbkllllclllllcllllidkbbknnnnnnkkbkkkbbbbbbbbaabbkmmaljjljjljjljljljljjjjjljjl",
+"ljjl`ajljlllljlljllllliinbmnmmefefeeeeeeeeeeeeeeeeeeeeffmnmnnkblclccclccclilillccccccciciciiiicccamnmnknmnkbknnnkbbkkmmknmnmkballclc`aacl`ccibknnmnnmnkbbkclcclkbbbbab`lllc```aaab`iakkkbnmnkbbkkknbbkkbkbaii`babbbbakb`jlaaljllljljljjljljljljljljljljjjlljjljj`nkbbabkknk`cbkkbbkkbbabnkbbbb`lcllcaailllll`bbmmmknnnkkballlcibkkmnnmllclci`iiaaabbkknkbkbnnnnnnnnbbbbbbbbbkabbabkmnmmcljljljjljjljlljljljljjjj",
+"lllljljlllbllljllllllllcaknknmffeffeeeeeeeeeeeefeefeefemmfnnnkacclccclclcccccccccccccccccciii`ciabnmmmnnnnbknnmnmmnkkkknnnmkdballcclbmn`llcll`nknmnknkmnbdlcllcbkbbbbk`lcllkkkknnmnkbbknbnknkbkbnkbbbkbakkaiabaabbbbbbabjljcljljlljjljljljljjlljljljljljljjljjclannbbaanbkacikmnkkbbkkbbnnnkbaacclcibbbilcclcaknmnmknmkbbklllccmkkbnkmclclcai``abbnnknnnkbkkknnnnnknkkbbbbbabkbbkbknmmkaljjlljjjlllljjjjjljjajlj",
+"jljljccjllljllllljllilll`bbnmmfffefefeeeeeeeeeeeefffefenmfmnkbiclccclcccccccccccccccccccciiiiiii`bbknnnnknbbmnmnnnnnnkkkmnkaad`lcllcbkmk`cllll`knmnmnknnnkllllinbbkmnn`clllbnkknknnnkkkkbknnnkbbkkkbkb`iaba`abbbbbknnbbbllilljllljljljljjljjljljljljljjljjlljia`bnkbb`akab`aaknnnnbkbbaabnnbbbdllliibbbailllclabnnnmkbkkbkclcccmnnkkkniclcl`i`akbbknknknnbbkknnmnkknnkbbbabbkbbnknnnnmnnljljjjljljljljljjjjljjlj",
+"klljljjclljlljllllll`cllcakbmmmfefmffeeeeeeeeeeeeefeeffmmfnnbailclccccclccccccccccccccccciiici`iabbbbkkbkkbnmnnknmnnnnnkkkbdab`lcccibknkn`clillakmnnmnkkmkllccinmnknmncjcccknnkkknmmnnbbkbnknnbbbkbabaciaaaabaabaknmnnbbilijljljlljjljjljljjljljjljjljljljjjljjaknkbbaaba``bknnnmnkkbbabbknkbbblllccbbbbailllcc`bkbkkbkbkklclccnnmnnknillcc`c`abbbknnnnnmkbkkknnnnnnnnnkmkbkmnknnmnknnmm`lljjjljjljljjjjljjcjljj",
+"ljlllllljlcljcllllllillll`bbkkmmfffffefffeeeeefeeefefffmmmnkb`ccacclcliccclccccccccicciciiciciaibbbkbkbbakbmmbnnnknnnnnnkkkbbaiclllcbnmknncllllldmfknmnknkllllikbknnnniilllknnkkknnnmmnbkbnknnkkabbbaccaaaaabbabknnnnnnkallljjljjljljjljjljjlljljjjjljjljjjljlcbknkkkbbda`aknnnnnmnkbbbbbbbkbbalcclcknkkbaicllil`bkbbbkdmnlllclnknnnnk`llclii`bbabknkkknnbbbkknnnmnnknnnnnnkbkkknnknnmkkbjjjljjjljljljljjjanjjjj",
+"llmjjljllllllilljlllllllllikbbnmmmfffffefeeeeffeefffmffmmnkbaicclcccccclccccccccccccccciiiiicc``bbkkknkbakbnnknknnkkknnnmnbbbaclcccibnmnmnncllclldmnnmnnnnllclckkkbkmmilllcknnnnbkknmfnnbkknkknnkabaic`bbbabbbbknmnknnnnkljjljljljjjljjljjljjijljljljljjjlljjj`ikkkbnkbaaadnnnkknmmkbbbbbbbkbballlclbbbbbabclllcidnkbbbbnmlccilnkkkknn`llccciabaabnmnnkmnnbbbbnknmmnkkkknmnkbbkbbnnnmnnnflljjljajljljjjjjljjjjjj",
+"illllllllljllclllllllclllll`bbkmnmmfefeffeffefefmeffmffmknkaiclcclclcccccccccccccccicciciicici`aabbbkknkbabknnnkkkknkkkkkknkb`clcllibknnnmkkcllllcdkmfmnnkllllcbbbbabbclcllknnnnkkknnmnbbkkmnknnnkb`c`bbkbbbbbbbknnnnmnknlljljjljjljjljjljjljcjjjjjjjjljljjjllibkkkknnbaabknmnkkkkknkbkkkbbkknklcclcbkbbakdbilllliakkbabkncllllnnnkknkalllliiaaabbbnnnknmnkbbbkbknmmnkkknkbbkbbaabbknnkkniljjjjljjjljljjjjjljjlj",
+"lcljlljlllllljlllllllclllillabbnknmmfmfffffffffffmefmnnnkkaicclcilccbcccccccccicciccciciiciiii`babbbbbbkkakkkmnnknkkkkkkknmnda`clllibbbbbakbacllcl`knmnnnklllc`nmb``bbcllclknnnnnnkknnkbbbknnkknnmna`bbbkbbbbbabkknnnnnnncjjjjjjjljjjjjljjljjjljjljljljljjljjj`anknnmnbbabknmmnnkabnnknmkkbaknkcllllbbkbbakaaillclibkbbbbkiclcckkkknkkaclll`bbkkbaabbkabkbbbabbkkbnmmnnkknmmkkkb`abbkkkbkbjjlljjjljljjjjjjjjjljj",
+"cbjcjllljlllllllllllcllllllclcbbkkmnmnffffffemmmfnmnmknkkbiccccclccliclcccccccciccciccciiiiciciabaabaaabkbnkknnnkkkkknnnknkdakndbkbabbbbbnbkbbaaa`bkbkmfnmbkkbbnna`ammakaaamnnnkkkkkknnkkakknkkkkmnaabakkbbabbbkknnnnnnmkajjljljjjjljljjjjjjljiljjjjjjjjjljjcccknknknnbbdknnnmmnbbbknmmnnnkkbbbabababbbbbkkkbaaa`aiabakdnkdbdbbkbkkkkkkab``bnnnnbkbbbbbbkbkkbbabbbbnnmknnmknmmm``bnmkbkbknjjjjljjjljljljjljjj`jj",
+"lljljlllllllllllllcllllllllllc`abbkknkmfmmfmfknfmmnnnkkba`cclliliccccncccccciicciccciciciiiiii`bbkbaaabbkbnnbkmkkkkkkbkbkkd`bknknnmnkabbnbkkbknbbbbbbbknmnnnnmnbkiannmnnnknnmnnkkkkkkkknnkkknnkknnnbbabbbkbbbbnkbknnmmmmnbcjjjjjjjljjjjlj`jjjlljjjjllljljljlliiknnnnnnkkbkknknfnkknknnnmmnmnmkkbbknkbaabbnknkbbbbaa`bbkbnkbkmnkkkkbbkbkkaabmkknnnnbbakkbkkkkkbakbbbdbmmnmkmnkbbcdnnmnknbkma`ijjjjjjljjjjljjjjljj",
+"ljcbaljllllllllllclllllllclcllcci`bbnbkbnknnmkknkkmkkba`ilccilcclcicl`cccciclcliccicicic`icici`nkkkbaabbkbknkbkfnnkkbbkkbbaannknnnnnnbkbkmkknnkkabaaabbbknnnnmfnk`annnmmnnnnnmnnknnknkknnkkknnnkkkkkkbabkkbbbbbkkknmmnmmfkjjljjlljjjlcljjljjjljjljljjjljjlljii`nknnnmmkbbbbnnnmnknknknnnnnmnmnnnkkkkkbaabkmmnbbnbbaabbkbkkkkknkkkkbkkkkdabknknnnnnnbbbkkkbkkkkbaadbbbkknkkmmfkkibnknnnnknmajjjljjljljljjjjjjjjjj",
+"lljci`cjlllllllllclllllllllccllllc``bbkkkkknknnkbnkba`icccccc`ccccccclcccccccaciciciciciiiiiiiankkmkbbbbbkbbkbbknnnnnkkkbaaknkknnnmmmkbbbnkbknkkbbabbbbbbkmmnmmmb`kmknnnmnknknnnkknnnnknknnkkknnnnkkmnkbbbbbkbbnnkkmmnnnnmjc`ljjjjjjjljjjjlj`jljjjljljjlljlj`c`nnknnnmkbbaabkbbknmnnknknnnnnmnmmnkbnkbbbkbnmnnknnkbbbbbbbkkbknnnnknkbkk`akkkknknnmnnbbknkbkkkkbaaabbabbknmnnmnk`kkknnnnnnbillljjljjjljjjjjjjjljj",
+"jlljcillllllllllclclllllcllllcccclcliiaabbbbbkbabaaiiiiccccccacccclciciccccciaiccicicicici`iiibnnkfnknbbbkaaknkbnnnmnnnkkbknnnkknnnnmkbbbbkbbkkbaaabbbbbbknmnknkbbknnnnnmnnnnnmmnnknknkkkmnnbkknkkkknnkbbbbkknbkkkknnnkknfjjjjjljjlljjjjljjj`jjljljjlljijjjjccaknnkkknnkb`iaabknnmnnnnknnnnnnnnnmnbkkkabkbknmnkkfnkkkbbbabbbbbknnmnnknkaknknnkknnmnnbbbbkabkbbbadaabbaabnmnknkkaknnnnnnnnfkljcjljljljjjjjjjjjjjj",
+"llllcjllllllcllllclllclclclclclcccclclcliiiai``icccccccccccibcccccccccccciciiiiciciciciciiiciinmnkmmnmkkbbbbbabbnnnmknnnkkknknnnnnnnnkkbabbbbkka`aabbbbbabnnnnkknnkmnnmmnmnnmmmnmmnnkkkknnnmkbkknnknnnnnkkkkbmmkkkkkkkkkbnjjjljjjljjjljljlljajljjjjljljjjljjjc`kmnnkknnnba```akmnnnnmnnnnknnnnnnmnkkkkbbkkknnnmknmmmnbbbkbbbbbknnmkknnkknknnknnnnnkkkbabbbbkkbiabbbbbbbdnnkkmbknnknnmnnmkmbjinijljljjjjjjjjjjjjj",
+"llljllllllllllllccclllcllclclllcllcccccccccclcccccccclcccccc`lccccicciccciccicciciciciiiiii`ickmmnmnmnbbbbbclciicccilcciliiilciccicccccclcclicllllcclcccllciiciciiciiiiicciiiicci`iiclliiiciiccciiiicciiiccccamknkkbkbkkkblljljjljjjjjjjjjjljljjlljjljjjjjjlllinmmnnnknmkaacccciiiciiiiiiiciiiciiiicccclciiicc`cciccillccclclciiciclicliicccliiciccccccclccccllllciccccliiciiiakkknnmmnmnnkciijljjjjjjjjjjjjjjjj",
+"ljlcljlllllllllllclllcllllccccccccclccllcccccccccccccccccccclccccccccicccicci`iiciiiicicii`a`ikmnmmmnkbabbijjjjjjjjljljjjjjljjjjjljjjjjjjjljljjjjjjjjjljjjljjjjjjljjljjjjjjjjljjjjljjjjjljjjljjjljjjjjjjjjjjjinnnkkbbbbbkbjjjjjjlljjjjjjjjljjljljjljajjjjjjljccknnnnknnmkbacjjjjjljjjjjljjljjljjjjljjjjjjjjljjljjljjjljjjjjjjjjjjljjljjjljjjjjljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlikkbknnmnnmkncjljjjljjjjjjjjjjjjjj",
+"llllllcllllllllcclclclclccllclclclcclcccccclilccccccccccilicciccicccccciciciibiciciciiciiia``immmmnnmknnkkillljcccjljclljlllccjijljcllljljlljjljljjljlcjlllllllllcllljlcjljjljllljjlclljllilljllclljlcicjclclcknkkkkkabbbkljjjjljjjjjjjjjjjljjljjjjjjjjjjjjjjcianmnnnknmnbacjllclcjcjcjcjllllllllljllllccjlllllljljllcjjllllljlljljjljljjjjlljjjllllllllcjllljllclljjllljljjllabbbbbknknmkn`jjljjjjjjjjjjjjjjjjj",
+"lllllljcllcllllccclllclcclclclclcccccccccmkcccilccccccccccccccicccciccccciciiaiiciiiiiiiciii`immmnmnnmmnnkclnmfffffffeeffmmffmmffmfffffmmffffeffemfffffmmmffffffffffffffffmmmffffffmffmmfffffmffffmffmmmmffmmkkmnnkbbnkabkjailjjjjjjjjjjjjjjjjjjjjjjjljjjjjjlcibknmknnnnmkdidkkkmnnnnmmmnkknkkkkkkkknkkkkkknknknnkkkkkkbkbknknnkkknnkkkbkkbbbbbkkbbbbbbbbnkkbbkbkbbkkkabbkbkda`dbbbbbbkbnmnljljljjjj`jljjjjjjjjj",
+"jlllllcbccnnclclllklclllllcclcclcllccclcciclclciccccccicccccicaiccccciciicciciciiicicicii`ii`innmmnnnmfnmnilmffffeffffffffffffmffmmffffmmfffffffffffmfmmmmffffefffeffeffmffmmmfffmmmffffffffffffffffffmmfffffnbnnkkbbkkkbaljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlcibbmmnknnmkka`bnknmmnnnnnnknnnkkkkkbkknnkbkkknknknnkkkkkkbbbkkkkkkkkkkknnkkkkbbbbkbbbbbkbbbkkkbbbkkkkkkbbbbkkbba`bbabbbabaknniljjjjljjjjjjjjjjjjj`",
+"c`iljllllliclclclkicllicllccccccccccccccaaiciclcccciclilcicccc`cciciccciciiaiiciiiciciiiii`i``nmmnkknmmmmmilmmmfffffmmffffffmmffmfmmfffmfmmfffffemmffffmmfffffffffffffffmffmmnmffmnmmfmmfeffffffffefffmmfffffkbknnmkbbknkbljjjjjjjjjjllcjjjjjjjjjjjjjjiljjjjliibknmkknnnmnnabkkkmnmnkkknknnkkkkknkkkkknkkkbkknknnkkkkkkbbkkbkkkbkbkkkkkkbkkbbbbkbbbbbkbkkkkkkbkbkbkbkkbbbkbkba`bbbbbbaabkknbjljjjjj`jjjjjjjjijjj",
+"lljlcclllllllcccclcllcllccclclcccccclccccccclciccccccciccciccaccccccicicciibiiiciiiiiii`i``i``nmnnnkknmmmnicffffffffmmmmfffmmffmffmmfffffmmmffffffmefefmfffffffnfmmmmmmmmffffffffmmmfffffffffffmefffmmffffffmnbbnnmmkbbbknjjjjjjjjjjjjjjjjjjijjjjjjjjjljjjjjliidbnmnnnknmnnaaknmnnnkkkknknnkkknkkkkbknnknkkbbkknnkkkkkkbbnkknnbbbbkbkkbbbkkkkbkkkbbbbkkkkkbkkbkbkkkbbkbkbkbkkaiabbabkkkbbbbajjjjjjjbljjjjjjjljjj",
+"llllllllcjccjlcllcclalccclclaccccccccccccccccccccciccicicccicbcicicicicicic`iciiiiiiii`iii`ii`nnnnnnknmmnmccmffffffmfmfmffffmffmfffmfeffmfmmffffffmfffmmmmfffffmmmmmmmmmmffffefffffmmffffmfffffffffmmfffefffmnkbkkmmnkbbbkjjjjjjjjjjjjjjljjjjjjjjjjjjjjjjjjjci`bbkmmnkknnnn`annnnnnnnkkknkkkknkkkkkkknnknbkbkkkkkkkkkkkkbnkkkkkbkbbbbbbbbkbknnkkbkbkbkbkbbbkbbbkkkbbbkkkkkkkbbibababbkkkkba`ljjjjjjjjjjjjjjjljjj",
+"llllllcllclliccclllclccllccik`lc`ccicccccclccccccccciclccicccciciciciciciiccciiiciiiiiiiii`ii`nmnkkkknnmnnlcmmmmffmfmffffffmmffmmfffefffmffmfffmmmnmmmmfmfffffmmmfmmmfmmmfffffmmffffmmfffmmfffffffmmmfffmefmnnkkbbknnnkbabjjjjjjjjjjjjjjijjjjjjjjjjjjjjjjjjjlc`kkkbknnnkmnnaakkknknknnkknnkkknkkkkknmnnkkkkkkkkkbbkbbkkkbkkkkkbkbkbbbbkbbbkbkkkbkbkbkbbbkkbkbbkkkbbbbkbbkkbbba`abbbaabknkkb`ljjjjjjjjjjjjjjjcjjj",
+"cllcclllllccccclclclccllcclliccciclcccccciccciccicccicaccciciciiciciciciiciiiiiiiii`i`iiiiiiibnmkkkkkknnnmcifmfmmmmmfmmffffmfffffffeffffmffffefmmfmmffmfmfefmmmmmmfmfmmmnfmmmmnmmffffffefmfffmfffmmmmmmnmfmnmnbkbbbkknnnkbljjcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`bmbbbknmkkkkbannnknkkkkkknnnknnnkkknnnnkkkknknkkkkbkbkkkbkbkkkbbbbkkbkkbbbbbbbbbbbkbkbkkkkbbkkbkbkbbbbbabbkbabb`abbbbaaabkkkbljjjjjjjjjdcjjjjjjjj",
+"lccllcilclllccclllclcccccccclcclccccc`biccccccc`ccicicfiiccciiliiciciciiciiciiciiii``iii`iiiibnmmnkkknnnkklcmmmmmmmmmmmmefffffefffffmmffffmfffffnfmfffnfmfffmmmmfffmfmmmffmnmmmmmnmmfffffmfffnmfnmnmnnmmmfnmfnbkkkkkkknnnmljjljjjjjjjjjjjjjjjjjjjjjjjjljjjjjlciamkba`knnnnbb`nknkkkkkkkkknmkknmnnnkkkkkknknknknnkkkkkknkkbknbbbkkbkbbbbbbkkbbbbbbbbbbbkkkbakkbbbbbbabbababbbbb`aba`aaaabbbbbjjjjljjjjjjjjjjjjjjj",
+"lclccc``cllccclclccclccclcccccccccccccccbaiccci`cicicciicciciciciciciciiiiaiiii````ii`iiii`i``nmmnnkknnmnklammffmfmmmmmmmmffffmffffffffeffffemmmmffffffmmffmmmmffmffmmmmfffmmnmmnfmmmffffffffffmmmmnmnmmmfffmmnkkkknkbkmnnjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjcccbnbbabbbnnknn`nnknnkkkkkkkkknnnkknnnnknkkknnkkbkbbkkkkkkkkkkbbbbkkbkbkbbbkkkbbbbbbbbbbbkkkkbkkkbbbbabbabbbkbbkbbbnbi`ii`abkbbjjjjeajjjjjjjjjjjjjj",
+"ccllllcclclcclcclcllcclccccclcccccccccciciicicccilckciciiciciciciiciiicicii`i`iiii`iiiiii`ii``nnmnnnnnmnnklammfffmfmmmmmmmffmmmmffmfffmfffmffnmmmfmfmfmmnmmmmmmmmmmfmmnmmmmnmmmmmmmnnmmmefffmnmfnnnnmnnmnnffmmkbbkkkbabmnkljljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl``abkbkbbbknnmm`knknnknkkkkkkknkkkkkkbkkkkknnnknbkbbkkkbbbbbbbkbbbbkkbkkkbbbbbbbbbbbbbbbbbbbkkkbbbkbbbbabbaabbbkbaakbiiii`aabbkcljjjjjjjjjjljjjjdkj",
+"clllclclimalccllcclclcccclcccccccccccccccicccciiiciiccicciciciciiciiiiic`iakciiiiiiiiii`ii`iiakmmnnnnnnmnkjanmmfffmfmmmnmmmmmnmmmmmmmmmmfeffmmfmmffmmffmmmmmmmmmmmffmmmmmmmmmmmmmnmmmnnmmfffffmnmnmmmnmnnmffmnnbbbbbbabnmmcjjjj`jjjjjjjjjjjjjjjjjjjjjjjjjcljlii`knkbbbkkbnnn`kknnnnkkkkkbkknkbbkkkkbbkkbknnknkkbkkkkbkkkbbbbkbbbbbbkbkbbbbbbbbbbbbbbbababbkbkbbbbabbbbababbbbb``ka`icc``aabkljjjjjjjjjjjjjjjjjjj",
+"lclcllcccclcllcclc`kcclcclccclcacicciliccccccccccicciciciciciciciiiciciiii`i`iiiiiii`iiaiii`iakmnmnmnnnnnblbmmfmfffmmmmmmfmmmmmffmmnmnmfmffmmmmmmfmmmffnfmmmmnmnmmmmmmmmmmmmmmnmmmmmmmnmmmmffmmmmmmmmmnnffmfmnnnbbbkkbbbbbcjjjjiljjjljjjjjjjjjjjjjjjjjjjjljjlc`aknnkkbbkbbbk`knnnnnnnkkkkkkkkkkkkkkkkkbbkbnkkkkkbkkkbkkkkbbkbbbbbbbbbbkbbkbkbbbbbbbbbbbbbkbbbkbbababbbbbbbbbkba`bb``lciaabkncjjjjjjjjjjjjjjjjjjj",
+"llllllccccllcclccccciclccclc`iliccclccicicciiicccicciiciciiciiiiciiiiiii`iicii`c`iiiiii`iii``annmmnnnmnnnbjbmffffmfmmmnnmmmmmmmfmmffmmmnmmfmmfmmmmfnmfmmnmnmmmmffmnmnmmmnmmmmmmmmnnmmnmmfmknffmknnmmmnmmffffnmnnnkbbkbbba`ljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`annnnnkbbbb`aiknnknknkkkkkkkkkbkknkkbkbkkbkkkkbkkbkkbbbbkbbbbbbbkkkkbbbbbbbbbbbbbbbbbbbbabkbbbkbbbbbabbbakbkbbbb`kbailciankkn`jjjjjjjjjjjljjjjjjj",
+"clllccllllccjcilccllnacllicanaclccn`ccikaicccciicci`cciciciciciiii`iiii`ib`iiiciiiii`iiiii`i`knmmmnmnnmmmblkffffmfmmmmmmmnmmmmmmmmmmmmmnfmfnmffmmmmfmmfmmmfnmmffffmnmmmmmnmnmmnmmmnmmmmfnffffmffmmnmnmmfffffmnnnnnkbbakn``jjjjajji`jjjjjjjjjjjjjljjjjjjjjjjjl`i`nnnnnnbka`ciinnnnnknkkkbkbbkkkkkkkbkkbkbkkkbkbbkkbbkkkkbkkkkbbbnknkbbbbbbbbbbbbbbbbbbbbbkbbbbkbbbbbbbabbbkkkkka`kb`clciannkk`jjjjjjjjjjjjjjjjjjj",
+"clclcclccclicllclcccacciccciicciicacccli`cccccccicimiiciiiciiiiii`i`i`i`iicii`iii`iiii`ii`ii`knnmnnnmmnmmblkmffmfmmmmnmmnmmmmmmfmnmmnmfffmfmmfmmmmmfmffffffmmffmffmnmmmmmmmmmmmmmmmnmmfmfmmmmmffffmmmnmffmffmmnnmnnkbbknblijjljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiannnknkbbi`ciinnnnnkkkkkkkkkkkkkkkkkkkkbkkkkkkkkkbbkkkkkknkkkbkkkkkkbbbkbbbbbbbbbbbbbbbbbbbkkbbbkbkbbbbbbbbkbbbbibbicci`kknnnajjjjjjjjjjjjjjjjjjj",
+"llcllclclcjcccclclcclcccbcccccccccicicicccciciiccccicciiciicicii`iii``iiiiiiicii`a`iii`iiiiiinnnnnmnnmnmnbjkmffmmmmmmmmmmmmmmmmmmmffffeffnmmffmmmmmmmnffmffnmffmmmmnnmmmmmmmmmmmmmmnnmmnnmmfmmmmmnmnnmmmmmmmmnmnnmnnkbbba`jijjjjjjjjjjjjjjjjjjjjjjjjjjjjljjjl`iaknmkkb`iiii``nnnkkkkkkkkkkkkkbbkkbbkknnmnkkkkkkkbkbkkbbbkkkkkkknkkkbbbbbkbbbbkbbbbbbbabbbbabkkbabbbbbabakbbbbbb`ab`````nnnkk`jjjjjjjjjjjjjjjjjjj",
+"lcllccccccclclcccccccccciccccccccccccicciciccciciiciciciiciciiiiaiia`iiiiiiiiiii```i`iii`iiiikkkbmmmnmmnnalnfmmmnmmnmmmmmmmmnmmnmffmffmffffmmfmnmmmmmnmffmfmffffffmmmnnmnnmmmmmmmmmmnnnmmmmmmmnmmmmmmmnnmnnmmmnnmkmnnkabi`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjii`nnnka`ic`a``innknkkkkkkbkkkkkkkkbkkkknkkkknkkkkbbkkbkbbbkkkkkbknbkkbbbbbbbbbbbbbbbbbbbababbkbbbbbbabbbbbabbabbbcibbai`akkmkkbjjjjjjjjjjjjjjjjjjj",
+"lccllccclclccclccccccccccccicccc`ciliciccccciccccciciciciciiiii`faiii`iiiiii`ii`ii`ii`iiiiiiikmnkbmmnmmnfalkmmfmmffnmnmmmmmmmmfmffffffnmfmfmffmmmmmmmmmfmfffffffmffmmmmmmmmmmnnmnnnnmmmmnmmmmmmmmmmmmnnmnnnmmmmnnmnnnkba`ajjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj`i`nnbbaa`iaaa`inkkkkknkkkkkkkkkbkkkkkknknnbkkkkknkkkbkbbkbkkbbkkkkbkkknbbbbbbbbkbbbbbbabbbbbbbbbbbbbbbbbbabbababa``bba`aabbbnfkjjjjjjjjjjjjjjjjjjj",
+"clcllclllclccclcclcccccccccclciccicccccciciiiciiciciciiciiiiii`iicciiiiiiiiiiiiiiiiiii`iiiii`nnmbbkmnmmnk`jnnmmmffmmnmnmmnmmnmfmmmfffffmfmfmffnmmmnmmmmfnfmfmfffffffmnnmmmmnmmnmmmnmnmmmmmmmmmmnmmmmmmmfnnnnnnknnfkkknn``aljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjji``nnnbbbaaabaaikknkknnkbkbkkkkkkbkknkkknnnkkkkkkkbbbbbbbkkbkkkknkknkkkkbbbbbkbbbbbbbbabbbbbbbbbbbbbbbbbbbbbbbabba`aba`abbbkbakkjjjjjjjjjjjjjjjjjjj",
+"lclclccccccllccccccccccccciciccclic`cciiiciiiiciiiicicciiiiiiiciii`iiiiiiii`iii`ii`i`iii`ii`akbmnabnnnmnb`jffffmfffmmmnmmnmmmmfmfmmmffffffffffmfnmmnmmmfmffmmfffmmfmmmmmmnnmmmmmmmmnmnmnmmmmmmmnmnnnmfmmfmmmmnknnmnkknkaabjlljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlic`bkmkbbbabbaainnnknnnkkkkbkkkkkkknkkkkkkknkknkkkkkkkbbbbbbnnkkkbnnkbbbkbbbbbbbbbbkbbbbbbbbbbbbbbbabbbabbbkbbbbbba`baaabkbnbbkbccjjjjjjjjjjjjjjjjj",
+"clcccclcall`lcclccccccccccccbiciicicccicccciicciciciciiii`iiiiiiiiccii`iiiiii`ii`iiiiiiiiiciabbkbbbbmmnnn`jffmmfmfmmmmnfmmmfffffffmmmfffmfffffffffmnmnnmfffmmmffffmmmmnnmnmmfmfmnmmmmmmmmnmnnnnnmnnmmmmmmfmmmnnknknkknbbbkljjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjj`iabknnnkknnkbbinnnnnnnkkkkkkkkknnknnkkkkkkkkkkknnknnkkbkbbbnkkkbbkkkkkkbbbbbbbbkkkbkbbbbbbbbbbbbbabbabbbbbbbbbbbbaabababbbbmnkbljjjjjjjjjjjjjjjjjj",
+"clclclcl`lcmcccccccccccccciikiiiii``iiicicciiccicicicii`iiiiiiiii```iiiiii`iiiiii`ii`iiiiiii`bbbbkbbmmnmmilmfnmmmmmmmmmmmmffffffffmmffmmffmmfmffmmmmmmmffmfnmmffffmmmmnnmmmffmmmmnmmmmmmmnmnmnmmmfffnnnnmnnmmnnkkknnkkbkbkljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjji``mnkkknnmmkbbiknnnkkkknnkkkknknnnnnnnkkkkkkknkkkkkkkkbkbkbkbkkbbbkkbkbkbbbbbbkbkkbbbbbbbbbbbbbabbbbbbbbbbbabbabba`b`bkkkkabmmbljjjjjjjjjjjjjjjjjj",
+"clcccllclcikcc`cccccccciiciib`iiiiabibiiiiiiciiiiiiiiiiiiiiiiiiiiiiciiiiiiii`i`iiiiiiiiiiiic`kbkbbbbnmnnmicmfffmmmfmfmnmfmmfffffmmmmffmffffmmnmmmmmmffmmmmmnmfffnmmmmfffmffffmnmmmmmmmnnmmnmmmmmmffmmnmmnmmnmnnnkkknkkdbbkljjjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjji``mnkbbkknkkbaiknnnkbkknkkkknkknnknkkkkknnnknkkbkbbbkbkkkkkkkkkbbkkkbbbbkkbkbkkkbbbbbbbbbbbbbbabbkbbbkbbbbabababaaiiibknnkkknnnijjjjjjjjjjjjjjjjjj",
+"cclcclcclccclcnicccccciiiiiiciii`ca`iaiciiiciiiiiiiii`iiiiiiiiiiiiii`ic`i`iiiii`iii`iiiiiiii`bknbkkbbnmnnilnfffnmmmmmmmffmfffffmmfnmffffffnmfnmfmfffffmnffmmnfmmmfmmfmmmmffffmmmmmmnmnmmnmmmmmmfmnnnmmnnmnmnnkknkkbnnkbbnbljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjii`kmnkbbkkbbbbiknnnkknkkkkkknkknnnknkbkkkkkkknbkkkkkkkkknnkbkkbbbkbbbkkkbkbbbkknkbbbkbbbbbbbbbbbbkbbbbbbabbbbbabbalilbkkkknnnnmijjjjjjjjjjjjjjjjjj",
+"lccclccclcccccccccccciiiiiiiiciiiiii`i`iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii`ii`iiiiiiiiiiciankbbkbbbkkmmccnfffffffmffffmmnmmmmfmmmfffffmmfffmfffmmfffmmffffffnmmfffmmmfmfffmmmnfmnmmmnmnnmffmnnnnnnnnmmnmmnnnkknnkkbkkkknljjjjajjjjjjjjjjjjjjjjjjjjjjjjjjjjjc`iknmnbbbkbbba`bnmnnnnnnnnnnnkkkkbnkbkkknkkkkknnkbkknkkkkkbkknnkkbkbkkkbkbkkbbkkbkbbkbbbbbbababkbbabbaabbbaabbbaaalccankknkbnbkajjjjjjjjjjjjjjjjjj",
+"lclliclcccccccccccccciiia`ccciiicickkiiiiiiii`ii`iiiiiiiiiiiiiiiiiiiii`ii`iiii`ai`iiiiii`ii``mnkkbbbabkkklcnnffffffffefffmmnfffmffffmmmmfmfmmnmmffmnmmmffffffmmmmmmmmmffmfffffmmmmnmnnmnmmmmnnnnnnmmmnnkmmmnmnbbknnkbbknnnljjjjjjjjjjjjjjljjjjjjjjjjjjjjjjjjjia`kbnmnbbbbbkaabknnnnmnnnnnnnkkkknkkknkkknkkbkbkkkkknkkkkknnkkkknkkbbkbkbbkkkkkkkkkbbbbbbbbbbbbbbbababbbabbbbbbkbalciakkknnknkkdjjjjjjjjjjjjjjjjjj",
+"cclibccaccclcccccccciiicaccciiicic`aai`iiiiiiiiiiiiiiciii`iiiiiii`i`iii`iii`ii`iiiiiiiiciccc`knknkkkbaaa`lifmfmmmfffffffmmnmmffmmfmmmmmmffmfmfffffmfmmmfmfmmnnfnfmmmmnfffffffmmmnmnmmnmmmfmnnmfmfmmfffmmmnmnmnkkbkkkabkknncjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjc``kbknmnbbknnkabnkkbnnnnmnnnnnkkknknnnnkknbknkkkbkkkkkkkkkkbkkkbbbkbkbbbkbbkkkkkbbbbbbbbbabbbbbbbakbkbkkkbabbabbbkci`akknkknkkkajjjjjjjjjjjjjjjjjj",
+"cclc`lcccccccccccccciiiccciiicciicac`ii`ii`i`iiiiiiiiiiiiiiiiiii`iiii`ii`iiiiiiiiiiiiiiciiiiakkknnmnba``ij`mmmmmffffmmnmnmfmmffmfffffmmmffmmmmnmnffffmmmmfnmmmfffnmfnnffmmmmmmmmmnmnnmmfmmnnnffffmmmmmmnmnnnmnknkbabkkkbbkljjjjjjjjjjjjjjjjjjljjjjjjjjjjjjjjji`ikkkkkmmnnnfnbbnknknnnnkknkkkkkkknkkkknnnbknnkkkkbkkknknkbkkkkbbbbkkkbkbbkkkkbbbbbbbbbabbbbkkababkbkbbbbbbbbbbabki`abkkkkkknnkbjjjjjjjjjjjjjjjjjj",
+"lcllccclcccccccccciiiiiccciicciiciciiiiiiii`iiiiiciiiiiiiiiiiiiiii`iiiiii`bb`iiii`iiiciiiccibnkkbknbba`cijafmmfmfffmmmnmnnmffmffffffffffffmmmmffmffffmmnmfnnmnfmfmmfnnmnmmnnnnmmmnnnmmmmmnnnfmmmnmmfffnnnmmffmknkbabbbkkkkljjjjjjjjjjjjjjjjjjjjjjjjjjjjj`ljjjca`bknkknmnmnnmbannnknkkkkknkbkkkkknnknnnknknkkkbkknkkkkkkkkbbkbbbbbkbbkkbbbbbbbbabbbbbbbbbbkbbabbbbbbbbbkbkbaabkkbaakkkkbbbkknnnjjjjjjjjjjkjjjjjlj",
+"cccclcccccccccccccccciiiiciicciccici`ii`i`i`iiiiiiiiiiiiiiiiiii`iiiii`iiiiiicci`iiiiciiiiiciakkkknkaaa`i`jamfmmmmmmfmmnnfnnmffmfmfmfmmffffffffffffmmmfmmmmnmmnfmmmmfmnmnnmmmmmnnmnnmmmmnnnnmfmmnffmmfmmmnnmmmnnnmkbkbbknnbljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjji`ikkknkbkmnnkkbannkkknknnkkbkbkbkknnnnnkkknknnknknkkkkkkkkkbbbkkbbbkkbbkbbabbbbbbbbbbbabbbbbbaabkkbbkkkbkbbbbbbkbbaakkkkkkkbbbknjjjjjjjjjjjjjjjjjj",
+"clcccilcccccccciiciciiicccciciicic`iii``ii`iiiiiciiiiiiiii`iii`ii`iiiiiiiiii`iiiiiiiiiiiiiiibkknnkaaaa`abjanmnnfmmmfmmnnmmnmmmmmffmmnnmmffffmmnnfmfmfffmffmffmmmmfmmnmmnmmmmmnmnnmmmfmnnnnmmmmmfmmnnnnmmnmmnmmnmmnkkkkkkkkljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjc``kbkkkbknmnkkbannkknkkkkkbkkkbkkknkkkkkbbkkknnkkkkbkknkkkkknnkkkkbbbkkbbbbbbbbbbbbbbbbbbbbbabbbbkbbbbbbabbbbbbabbaaknknkknkkbkkljjjjjjjjjjjjjjjjk",
+"lcccbf`cccccciiaccccciiiiciccciiiiim`iaii`iiiciiiiiiiiiiiii`iiiiiii`i`iii`iciiiiiiii```iiiicabbbkb`iba`abjamfnnmfmmmmmmfnffmmmmnnmmmmnmfmmmmmnnnnfffmmfffnmmmfnmmmmnnnmmmmmmnmnmnnnmmnnnnmfmnmmmnnnnnnnnmmfmffmnnmmnkknbbbljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl`ibabbkkkbnnkbkakkbkkkkknkkknkkknknkbbkkkbbkkbkkbkbbbknnkkkkkkbkkkbkbbkbbbbkbbkkbbbabbbbbbbbabbkbbakbabbabbbabbkkka`knknnmnnnbnkljjljjjjjjjjjjjjjj",
+"k`ii`icclccccciccciicc`ccicicciiciicibniiiiiiiiiiiiiiii`caci`ii`i`iiiiiiiiiiiiciiciiiniiiiic`b`abaiiaaabbjbmmmmmnnnmmmfffffmfmnnmnffmnnnmmmnnnmnnmffmmmffmmffmmmnmfmmmnmmmmnnnmnfffmnnmmffmmmnmnnnnmmnmfnmmfmnnmnmmnnkkknbcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjci`akkbkkkbbbmkkanknnkkbkkknnkknnknbbbbnknkbkbkkkbbkbbbkkknbkkbbkkkbbbkknkbbbbkbbbbbbbbkkbbabkbbbbbkbbaaabbabbbbbbbaakknnnkbknnkbijjjjjjjjjjjjjjjjj",
+"ilcciccciccccccciccccii`iiiiciiciiiiiiai`iiiiiiiiiiii`ic`ii`iiaciiiiiiiiiiiciiiiii`iiaiiiccaabaab`iiaabbblkfmmfmmnmmmfmmfffmmnnmnnmmffmmffffmmmmmmmmmmmnmnmmmnnmmmnmmnnmnnnnmmnmmmnmnnmfnmmfmnnnnnnmmmmmmmmmmnnnmmnmnnnkbk`jjjjjjjjjjajjjjjjjjjjjjjjjjjjjjjjjc`iabnkkkbbbbkkk`knnnnbbkknnnnnmnbkbkkkbkknkkkknkkkbbbbkkkkbbkbkbbkbbbbbbbbbbbbbbbbbbbbbbbabbkkbkbkababbbbbkkbbbbbbb`knnnnkbbkkkkijjjjjjjjjjjjjjjjj",
+"cccciciclccicliaccccciliiicciiiiiii`iiiiiiiiiiiiifkiikaiiiiii`c`iiiii`aai`c`iiiiiiiiiciiiac`bb`aacc`bbkkalkmnmfmnnnnmmmnfffnnnnmnmmmmmmmmmnmmmnmmffffmmffmmmmmmmnnnffmnmnnmmfmmmnnmmmnmmnnmnnnnnnnmnffmmnmnnmmnfmnmmnmnnkbljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`bbbbkkkkkbkkk`knkkkkkbbkbkbknnkbbkbbbkkkbkkkkkbkkkkkkkkkkkkkkbbkbkkbbbknbbbbbbbbkbbbbkkbbbbbbbbabbbbbbbbbkbbbbabaannnknnbbknkk`jjjjjjjjjjjjjjjjj",
+"cciccicccccccciicciciiiiiciiiiiiiiiii`iiiiiiiiiiiic`iicii``ii`iiiiiiiii`iaikiiiiiiiciciiikilab`a`ciakkbk`jnmnmmmmmnmmffmmfmnnmmnnmfmnmmfmmmnmmffmmmfmfmmfmmmmmmfnnmffmnmnnknnnknmmfffmnnnnnnnmmmnmfmnmnmnnnnnnmmnmmnnnnnmkljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjic`bkbbbbkkbbnkk`kkknnnnkbnnnknnkbkbbbkknkbkknkkbkbkkkkkkkkkkkkkbkkbkbbbbkkbbbbabbbbbbbbkkkkbbbaabbbbbbbbbbbbbabbaba`knnnnmkbmmnndjjjjjjjjjjjjjjjjj",
+"ccccccciccccciclcicicia`aiiiicciii`iiai`iiiiiiiic`iikb```ii`eic`iiiiiciccnicbiciiccciciciiickai``c`bnkkkajnmmmmmmnmmmfmmmmmnmmmnnmfmmmffmmnnmmfmnmmfmfmfmnmmnmmnnmfmmmfffnnmnnnmmmfffnnnnnnfffmmmmfmnnmnmfmnnnnmmnkknnnnnn`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlicibnnnkbbkkbnkk`nknnkkkkknnnkkkkbkbbkbnnkkbkkkkkbkkkkbbbkkkkkbbkkbbbbbbkkbkkkbbbabbabkkkkkbbbbbkkkkkbbbkbbbabbbbbbb`aaknnknkmmnnbjjjjjjjjjjjjjjjjj",
+"cclicciiccccccciccciccbib`ciiiiiiiiii`iiiiiiiiii`iiia`ica`iciin`iiii`iii``cinciccicccccciccinic``aaknnkkajnmfmmnnnnnnnnnnmnnmfmmffmfmmmmnmfmmmmnmmmffffmmmmfmnmnnmffmmmnmnnnnnnmmmmmnmnnmffffmmmmfmmmmmmnmmmnmnnmnnkknnnkn`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiciibkmnkkkkkkkkk`nmkkbbkbbkbbbbkbbkkkkkkkknkkkkbbkbkkbbbkkkknkbkkkbkkbbbkkkkbkbbbbbbbbkbbkbababkbkbkbbbkkbbbbbbbbbbb`baabnnnkmnnkkjjjjjjjjjjjjjjjjj",
+"cclcccciaicccccciic`icacaiciiii`ii`iiiiiiiiiiiiiiiii`ii`i`i`ciaiiiiiiiiciliaf`ilcciccccccicckic`abkknnnnajmmmnnmmmmnmnmnnnnnmfmmnnnmffffmffffmmnnnmmmmmmmnffmmfmnmfffmmnmmfmmmffmmnmnmmffmmmnnmnfmmmfmmmnmmnmnnnnnmkbbknmkijjjjjjjbjjjjjjjjjjjjjjjjjjjjjjjjjlciibbkknnkknbkkbikkkknknkkkkkkkkbbkkknkbkkknnnnkknkkkbbbkkkbkkkkkkbbbkbbbkkbbbbkbbbkbkkbbbbbbkkkbbbbbbbbkbbbkbbbbbbbakkbbknmnmnnnkjjjjjjjjjjjjjjjjj",
+"ccccciciiiicciccccciiciiii`iiiiiiiiiii`iiiiiiiiiiii```ii`iiiiiiiiiiiiii`cicia`aiicicccccciciaca`aknkknnn`jfmmnnmmnmmmnmmnnnnmnnmmmnnmnmffffffnnnnmmmfmfmnmmfmmmmfmmmmmnmnmffmmmnnnmmmmmfnnnnmfmnmmmfmmnmmnnnnnkknmnkabkknnijjjijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjci`akkkkknnbknkkannbnkkkkkkkkkbkbknbkbkbkbbkbkkkknkbbbbbbbbkkkkbbbnkkbkknkkkbkbkkkkbbbbbbbkkbbbabbbbbbbbkkkbbbbbabbb`bnnbbknmmnnkbjjjjjjjjjjjjjjjjj",
+"cccccciiicccccicicicciiiii``biiii`ii`a`iiiiiiiiiiii`iiiia`ii``iciccici`ciicci`icbicccccccici`i`aknknnnnn`jffnnfmmnmnmmmnnnmmmmmnfmmmnmmmnmmffnmnnnmnnnnfnmmfmmmfmnmmmnnnmnnnmmmmmnmmfmmfnnnnmfmmmmmnnmmfnmnnmnmkknnkbbbbkkcjjjjjjjjjjjjjjjjjjjjjjjljcljjjjjjjci`abkkkknkmbnkn`nkkkkkkkkkkknkbkkkbkkknkkbkkkkbbkmkkbbbbbbbbkbbbknkbkkbbbkbkbbbbbbkkkbakkbkkkbbaabbkbkbabbbbkbbbbbbaannnkbbnnmnnnjjjjjjjjjjjjjjjjj",
+"ccccccciicicicciciaaiccc`iii`iiiiiiiii`iiiiiiiii``iiiii`aiiiaa``ciiiiiiccciciiicilcclcccccciaabkkknnnnnn`jfmnnmnmmnnmmnnnnmmmmfmnnmmfnmfnmmffmmmmnmnnnmmnnnmmnnmmmmmmfffmnmmmmmmmnmmfmmmmnnnnmmnmnnnnmnnnnnmnmmnbnnbbkkbakijjjjcljjjjjjjjjjjjjjbljcjjljjjjjjcjiaakbkkbnknnnmm`nkkkkkkkkkkkbbbkkkkkkkkbknbkkkkbbkkkkkbkbbbbbkbbbkbbbbkbkkbkbkbbbbbbbkbbbkbbkkbkabkbkbbbbabbbbabbbaabnnnnbbbknmnnljjjjjjjjjjjjjjjj",
+"lciccciiciciccicciiiiiciii```i``i`iiiiiiiiiiii`iii`ii``b`iiiiiicicicciiiciccccccccicccccccciabkkknnnnnnnilnnnmnmnnnnnnnmnffmmmmmnmmfmnmffmmmfmfmnmmmnnnmmmmmnmmnnnnmnmmmnnmmmnmmmmmmmmnnmmmmfffmmmmnnmmnmmnnnnnnbkbbbkbbabcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj``iabkbkbkkknknn`kkkkkkkkbkbkbkkknkknkkbkknbkknkkknkknbbkkbbbbbkbbbbbbbbbbkbbkkbbbkbkkbkkkbkbbabkbkbbbbbbaabkbbbbbbaaannnmnbbbkknmcjjjjjjjjjjjjjjjj",
+"iiiccciiiiciciccicicccci``iiii`ii`iiiiiiiiii`iii`i`iiii`iiiiiciiiciciiiiciicccccci`ilccccccaabkknnnnnnnnclmnnmnnnnnnnnmnmfmmmnnmmmmmmnmmmmmmfmmmnnmnmnnnmmmnnmmmnnnnnnnnmnnnffmnmnmmmnnnfmmnmmmmmmmnmmffmmnmnkkknkbkkbabbbcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`abkbkbkkknkkkckkbkkbkbkbkbkkknkkkkbbknkkkbkkkkknkkkbbbkbbbbbkbkkbkkbbbbbbbbbbbbbbkkbbbkbkabbkkbbbknkbkkkbbkkbbbabaamnnnnkbbabbncjjjjj`ljjjjjjjjj",
+"ciicciiiiiiiciicccciiiamb`i`i````iiiiiiiii`iii`iiii`iiciiiiiiiiiiciiiiiciiiccccccciccclccli`kkmmknknknnnccmnnfnnnnnnnnmfnmfnmnnnmmmmmmnnmnmmmmmmnnnmnnnnnnnnmmmmfmnnnnnmnnnmffmmmmmmnnnnnnnnnnmmnfmmnmmfmnnnnnkkkbbkkbabbbcjjjjjbjjjjjjjjjjjjjjjjjcjjjjjjjjjjcci`bbkbbkbkkkbkckkkkkkbbbbbkkkknkkbbbbnnkkkkbkkbbkkkkkbbbbbbbbbbbbbbkkbbbbbbbbbabkkbbbbbbkbabbbbababbbbbbbabkkbbaababnnmnmnbbbbab`jjjjjijjjjjjjjjj",
+"ccccciiciiiiiiiiiiciiccaiii`iiii`iiiiiiiiiii`i`i`iii`i`iiiiiiicciiciii`iiiiiciccclcclccccccaknmmmmnnnkknlcmnnmnnnnnnnnmfmfmmmnnnfmmmffmmmmnnnmnfnmnnmnmnnnnnnmmfnnnmmmnnnmmmnmmmmfmmnknnnnnnmmmfmmmnnmmmmknnnnkbabbbabaakaljjjjjjjjjjjjjjjjjjcjjjjjjjjjjjj`jjli``bkbbbkbkknkkckkkkkbkbkbbkknnknnkbbkkkkknkkkkkbbbbbkkbbbkbbbbabbbkbkbbbbbbbbbbbbkkkkkkkkbdbaabbbkbbbkkbbbbbbbabbabakmnnnkkbkkbbijjjjjjjljjjjjjjj",
+"cccciciiiiiiiiiiciiab`icci`a`ic`i`iii`ii`iiiii`i`iiiicciciiicciiiccicibiiiccccccicccccclcccanmnmmmmnkkkklimnnmnnnnnnnmfffffmnnnnfnnnmffffnmnnmnmmmnmnnnmnnnmmnmmnnmffmmnmmmnnnmmfmnmmnmmmmmnnnnnmmnmmmnmnnnnknkbabkbbbabbaljjjjjjjjjjjbjjjjjjjjjjjjjjjjjjjjijliiabbkbbkkbkkkb`kkkkkkbbkbbknnnnkkkbkbkbbkknkkkkkbbbbkkbkbbbbbbbbbbbbkbbbbkbbbbbbbbbbkbkbbbbbkkbbbbbbbbbbbbbbbbabbba`bnnnnknnbkbb`jjjjjjjjjjjjjjjj",
+"ccccccciiiiiiiiii`iiiiii``iiiiciiiiiii`iiiiii`i`iiiiiiiiiiiciiicciiaicaicciiccccclcclcclllcafmnfnmnnnnnnlcmfnmnmnnnnnmmfmmnnnnnnnnnnmmmmmnmnmfnnfmnnnnnnnnnmnknnnnnnnnnmmnnnnmfmmnnnnmmmmnmnnnmfnnmmmnnmnknkknbbbbbkbaaaaaljjjjjjjjjjjljjji`jjjjjjjjjjjcljjjjj`iabkkkbkkkkkmaaknkkkkbkbbkknnkkkkbbbbnbbbkkkkkbkbnkkbkkkbbbbbbbbkbbbbbabbbbbbbbbbbbbkkbbbbbkbbbbbabbkbabkbbbbbbaaaa`aknnnmnkknbbajjjjjjjjjjjjjjjj",
+"icccci`cciciiiiiii`iiiiiii``iiiiii`iiiii`i```iii``ci`ciiiiiccicicccciciiicicccccccclccccclikmmnmnmnnnnnklammnnknnnnnnnnnmmmnnknmnnnnnnmmmmmmfnnmnmmmmnmnmnnnmmnnnnnnnnnnnnmmmmmfnnnnnfnmmnnnnnkmmnnnmmnnmnmnnkbbabbba`aaailjjcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjliiakbknkkkbknnk`nkkbbkkbkbbbkknkkbbkbkbkbbbkkkkbknbnbbbkbnkbbbkbkbbbbbbbbbabbbbbbbkbbbbbbbabkkkbbbbbbbbbabbbabbbbbaaibbbbknmmknkabjjjjjjjjjjjjjjjj",
+"icciccccciicci`bi``i`iii`i``ciiiciiiiiiiiiiiii`aci`iiiciiiiiiiccciicccccccciciccccccccclclcbnnmmnnnnnnnklaffmnnmnnnnnnmmmmmnnnmmnnknmmmmnnmmfnnnnnmmnmnnnmnnmnmnknmnnmmnmmfmmnnnnnnmmfmmnnnnnnnmmmmmnnnkmnnnnkbababaa`aaicjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjliiakkabkkkkknnnannkkbbkbbkbkkkknkkkbbnbbbbbbkkkkkkbkkbbbkkkkbbbbbbbbbbbabbbbbbbkkkbbbbbabbbkbbbbabbbabkkbbabbabbbabb`abbbkknmmmkbb`ljjjjjjjjjjjjjj",
+"macciiiicicciii`iii`i`i`i`knai`c`iii`iii`ii`ii`aaciiafiiiciiiciacciccccciciiccclccclccllclcaknnmmnnmnnnnjbmffmnnmnnnnnmmmfnmnnmfmnknmmmnmnmnnnmnmmnmmmnnnnnnnnnnnmmmnmmnnmmnnnnnnnnnnnnnnnmnnnmnnnmnnnknnnnnnkabaaaai```iiljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiakbaakkknnnmnankmnkkkkkkbbkkkkkkkbbnkkbbnkkkkbbbbbkbkbnkkkbbbbabbbbbbbkkkkbbbbbbbbbbbbbbabbbbabbabbbbabkabababbbbb`abbbbbknmmnbbljjjjjjjjjjjjjjj",
+"biccclcciicciccii`iiii`iii``ci`ia`iiiii`iii`iii`c`iiii`ciiicccibccciciciiiiiiicccccclccclclabkkkmnnmmnmklanmmnnnmnnnnnnmmfmnnnnmmnknmmnnmnmnnmfmmnmmmmmnnknknnnnmmmmmmnnmnnmmmmmmnmknmmmnmmmmmnnnnnmnnnnknnnmkabbaa```a`iiljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlii`kkbabkbkknmnakknkkbkkkkbbkknkkkkbbnkkbbkkbbbkkkbbknkbkbbkkbabbbbbbbbbkkbbbbbkbbbbbbbbbbbbbbkbbbbkbbbabbabbababbbb`abbbbbabknkkajjjjjjjjjjjjjjjj",
+"cciiiiiicciiccib`iii`ii`i`````ic`ii`iii`i`i`iiiiiiiciiciicciiciiiccciiiciiciccilcclclcllcll``aaknmmnmnmblbnnmnnmmnmnnnnmmmmmnknnmnnnnnnnnnmnmnfnknnnnknnnnnnnnnnnnmmnmnmnmnnmmmmmnfnfmmnnnnmmmmnnnnknnnknnkknkabbaaaabba``cjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjii`baaaabakkbknakkkkbkkkkkkbbkknkkkbbbkkkbbbbbbbkkbbkkbbbbbbbbbbbbbbbkbkbbbkbkbbbkbbkkbbbbbkbbbbbbkkbbabaabaaaabaaaa`i```aabaknnbacjjjjjjjjjjjjjjl",
+"icccciccicciic`b```iiiiii``iiiiiiiii`iii`iiii`iiicii`cicciiciicccccccicciicicciclcclclcllcli``akkmmmnmnbjbnmmnmnmmmmnnnnmmmmnnnkmnnnnnnnkknnnnnnnnnnnknnmnnnnmmmnmmnnnnnnknknnnmmnmnnnnnnnknmmnnkkkknnkknnnknkabbaaabbkabaijjjjjjjjjjjjjjjjjjjjjjjjjjjljjjjjjjcci`ii`abbkkbkkabnkknknknknkbbkknnkkbbbkkbbkkbbbbbkkbkbbbbbbbabbbbbbkbkkkkbbkbbababbbbkbbbbbbabbabbkbabaababbbbbbabaiciii`aabbnnkacjjjjjjjjjjjjjjj",
+"liiicciiiicciiii`i`iiiii``ii``iii`iiii`i`iiiiiiiki`cciciciiccccicccccccccicciiaicccllcllclcaaabknmmnmnnbjkmmfnnnmmfmmnnknmmfmnmnnnnnnnnnnnnnnnnmnnnnnnnnnnnnnnnmmmmnnmmknnnknnmmnnknnmmfmnnmmmnmnnnnnmmnnnnkkbabaaaabkkbnaijjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjjilcic``bkbkkkkbaankkkbkkkkkkkbbkknnkkbkbkbbbkkbbbkkbbbbkbbbbabbbbbabbbbbkbbbbbbbbababbkbbabbkkkbbbbkkkbbbbbabbbbabaaalccciabbbkkkbijjjjjjjjjjjjjjj",
+"icciciccciiciiiiii`iiiiiii`iii`iiiii`i`iii`iiiiiiic`ciiiiicciicccciccccccilcclilclclclccllcbbbbmmmmmmnnbjkmmmnknnmmnmmmnmfmfmmmfnnmmmmnnknmnmnnmnnnnnnnnnnnnnnnnmmmmmmmmnnnnnnnmnnnmnmnnnnknnmmnmnnnnnnnnnnnnkbb`i`aabnnkaijjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjjcllcc`abbbabbkbaannkbbbkkkkkkkkkkknknnkbkbkkkbbbbkbbkbnbbbbbbbbbbbbbbbbkkkkkkkbbbbbabbbababbbabbabbbbbbbbabbbbabbbab`lllciibbabbbbijjjjjjjjjjjjjjj",
+"ccciciicciiciii``c`i`cii``iiiii`ikbn`iiii`iiiiiiiciiiiiccakaiccccccccccciccccclccllcllclllcbbbnmmmmmmnnajmmmnnnnnnmmnnnmnmmmmmmmmnnnnmmnnnmnmmmknmmnknmnnknknnmnmnmmmnnnmnknnnnnnkkmmmnnmnmnnnnknkknmmmnmnmkkkaaii``bkkkbaijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjicllccaakbbbann`bnnkbbkkknkkkkbkknnkknkkbbbbkkbbbbbkkbbbkbbbbbbbbabbbbkkbbbkbbbbbabbabbbabbkkbbbbbbabbbaaabbbbbbbbaaalccc`abkbbbabajjjjjjjjjjjjjjj",
+"ciiil`ciciciciiii`iiiii`ii```iiii`ia`i`iic`ci`iiiiiicciiiciccccciccccccccccllcclcccllclclccbbbnnnnnmmnn`lnmnknnnnnnmmnmnnmfmmmmmmknkknnknnmnmmmnmnnmmnnnnnnnmnnnnknnnnmmnnknnnnnnnnmmnnnmnnnnnnknnnknmnnknnnmka`i``abbknaaijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjicjcii`bkbkkknmaankbkbkbbknkkkkbknnnknkbbbbbbbbbkkbkkkbbbkkbbbbbbbbbkkbabbbbbbkbbabbbbbbbbbbbbbbbbabbbabbaabbbbaabbbblli``bkbbbbaaajjjjjjjjjjjjjjj",
+"ccciina`iicicii`iaiiiiiii``i`iiii`i``ii`i`a`iic`iciciiccciicciccccccclcccccccclclclccllclciabkmnnnnmmnm`jnnnnknnkknmmmmknmfmmnmfmnnnnnmnnmmnnmmmmmmmmnknnnnnmmmnnnnnmmmfkknnkknnmmmmnnnnmnmnnnnknkkknnnmnnnnmna````bbknbaaijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjcila`i`bkbknnnnaabbkkkbbbbnkkkbbkkkkkkknkbbbkkbbbkbkbnkkkkbbbbbbbbbbkkbbabbkbkkbaabababbbbbbbabbkbbbaaabababbbbbbabbbllababkbbbbbbbjjjjjjjjjjjjjjj",
+"iiccik`iiciacii`ibiiii`iii```i`ii`i`iciiiiiiiciciiiiiiiiiccciccccccccccccclccllcieillclllciabknnnnnnnnnilknnnnnnnnmmnmmnnmmmmmmmnnkknmmmmnnnnnmmnfmmnmmknnnnnmmnnnmmmmmmnnknnknnmnnmnnnnnmmnnknnknknkmmmmnkknkaaa`abakkaab`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjicca`iibbbknnnnb`bkbkbbkkkkkknkkknknnkkkbbbbbkkkbbbbbbkkkkbkkkbbbbbkbbbbkbkkkbkbabbbabbbbkbbbabbbbbbabbaabbabbbbbbaablcabbbkkbbbbbbjjjjjjjjjjjjjjj",
+"ciccccicciibiiiiiaiiiiiiiii`i`i``iii```iiiiiiiiiciiiccciciccccicilclcicccilclclclccclclcll`kknnnnmnnnnn`jnknnnnkmmmmnmmmnmmmmmmmmnnnknnnnnknnnnmnnmnnfmmmmnnmnnnmmnnnmmnnnnnknknnmnmmnnknmnnknknnnmnnmmnnnnkkkabaaabbaaibk`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjliccb`iibbbbknknk`kkkkbknknkbnnkbkkknkkkkkbbbkkkkbkbakkkbbkbbkkkbbbkbbbbbkbbbbbkbbbababbbbbbbkbabbbbaabbabbbbbbbbaaabbcibbabbkbbaabbljjjjjjjjjjjjjj",
+"ciciiciicii`iii`i`ii`iiiii`iii``i``iaaai`iici`ciiicc`iccciiiccclccicccciiaillcclcjlallllll`knnnmnmmnnnn`lnnnnnnnmnnnnmmnnnnnnmnnmfmnmmnnnnknnmmmnnmmmmnmmmnmknkkmmnnnmmmnnkknnnnmmmnmmnknnnknnknnnmmnmmnnnmnnkbbb`abba`abkijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiicnk`cakbbknknkabkbkbkkkbkbkkkbbbbkbkkkkkkkbkkbbbbkbkkkbbkkkkkkkkbbbabbkkdkkbkkbabbbbbbbbbkbbabbbabbabbbbbbbbbbabbbaiiabbabkbabbbbjjjjjjjjjjjjjjj",
+"icciiciciicccii`iiiiiiiiiii`i````iiii`iikiiiabiiiiccaa`ibicbbicicc`iccc`ibcclclllacjclllll`bkknmmmnnnnnilnnnnknnnnnnnmmknnknnnnnnmnmmmnnnnnmnmnnmmmmnknnnnknnkknmmmmmmmmknknnmmmmnmnmnnnnnnknnknnnnnnmnnnnmnknkaiiiab`abbk`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjji`cnnic`bbkbknkk`bkkbbkkbkkkknkkbkkkkbkbkkkkkkkbbbkbbnbnbbkbbbbbbbbbbbabkkkkkkkbbababbbkbkbbbbbabbabbbabbbbabbbbabbab`ibbabbbbbbbkbljjjjjjjjjjjjjj",
+"cciiciciciiii`iiii`iii`i`i`iiii`````iiiiiiciiiicciii`iccciccccicccilccccc`lclllcclcllcllll`bbkbknmnnnnnicnnnnknmnnnnnnnnnnnnnnnnkmmmmmnnknnmnmnnnmmnknnnnnnmnnknknmmmnmnnnknnnmnnnmnnnnnnmnknmnnnnnknnnkkbnmnmbilcci``abkkijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjic`kb``akmbakkknakkbbbbkbknbbkbbbbbbbkbbbkkkkbbbbkkkkbbbkkbbbabbbbkbbbbbbbkkbkkbabbbbkkbkbkbbbbbbkbabbbaababbbaaabbbb`ibkabbbbkbbabljjjjjjjjjjjjjj",
+"iciciiiiiccci`i`iiiiiiiiii``i``i``iiiiiiiiiiciciiacciilccccciicciccccccclclclcllllllllllcl`abbbknmmnmnnlcnnkknnnnmnknnnnknnnnnnmmmnmmknnnffmmmnnnmnkknnnknnknnnnnkknnnnnkknnnmmnnmmnnnmnnnnmmmnknknnmnnnnkmnnnii`ciccikkbbijjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjjjic`bb``bkknbbbnnakkbbkkkkkbbbkkbbkbkbbbknkbkkbbbbnkkkbbbkkbabbbbbbbbbbbbababbbbababbbbbbbbbbbkbbakbbbbbbbabkbbbaabbbb``bbkaknbbkkakijjjajjjjjjjjjj",
+"cicciccia``ii``i`i`iiiii`i```i```i`iiiiiciiiiiiic`ciccaiciicciicicccccccclclcllclllllllcjcabbbknnmnmnnnlinnnnknmnnnknnnnnmnmmnmnmmnmnkknknmnmnnmknnnknnnknnnkknknnnknnknnnnmmmmmnmnnnnnmnnmnmnnnnnnmmmnnnnnknk`c`iiciiabbbijjjjjjjjjjjjjjjjcjjjjjjjjjjjjjjjjjjci`bb``bkkkkbbkkakbkbbkkkkbbbkkkbkkkkkkkkkkkkbbbbkkkkkkbbbbbbbabbbbababbbbabbbabbbbkbkkbkbbbabbbbbbbbbbbabbbbbbbabbab``babbbkkbbkkbijjjljjjjjjjjjj",
+"cciciiiciiciii``i`i`i`i`ii`````i`iiiiiii`iicicccciciicb`ciiicicicicccccclcllclllllllllllclakknmnmnnmnmmlinknkknmmnnmnkkmnnnmnmnnmnkmmnnmnmmnmmnmmnnmmkknnnnkknknnnnnnnnknnknnnnnnnnnnknmnmmmnnknknmmnnnnkknkkkiciiclcc`ank`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjic`kb`bbbkkkkbbk`bkbbkkknkkkkkbknbbknkkbkkkkbbbbbkbkkkkkbkbbbbbbbbbbbabbbbbkabbbbbbbbbbkbbbbaabbbkkbbbababbbbbbabaaabaibabbbbkkbbnkajjjjjjjjjjjjjj",
+"ciciciciiciiiiiiii`i`i``a`i```i`iiiiiiiiicic`iiiiccccci`iicccciccicciclccllclllcllcllcll`c`bbbmfmnnmmmnl`nknnkkmnnnmmnnmmnknnnnknnnkkkkknmmmnmnnmmnmnnkknnnnkknknnnnnmnnnmnnnmnnnnnnnknnnnmmnnknknnnnnnkkknknk`iicclcciakkajjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlli`bbbknkkkkkkbbibbkbbbkkkbnkkkkkbbbbbbbkbbbbbbbbkkkkbbbbkbkbbbabkkbbbbbbbbbbbbbbbbbbbbbabbbbbabbkbkbbbabbbbbbabaabakaikaabkbkkbbkkajjjjjjjjjjjjjj",
+"cciciciciiiiiiiiiii````ibaiiiii`iiiiiiiiiciabiiliccciiiiccccccccccciclcllclllcllllllllllcjbnkbbknkmmmnmj`nnnnnknnnnnmmnmnnkknnnnknnkknnnnmmnnnkknnnnnnnnnnnnnknkknnkknnnnmmnmmnmknmnknnnmmnnnnknnnnknnkkknnnmkaiiccici`abbbjjjjjjjjjljjjcajjjjjjjjjjjjjjjjjjjjcciabbknkkkkkkkb`kkkkbbkkbkkkkkkkbbbbbbbbbbbbbbbkkkbbbbbbbkbbbbbbkbbababbbbbabbbkkbbbbbbbbbbbabbbbbbbbaabbbbabaaabbaba`nbabbkkkkbbkkjjjjjnljjjjjjj",
+"iiciciciiciiiii`iiiiiii`a`iiiiiiiiiiiiiib`iciciiiciiiibiccccccccccccclcllllclllllccllllllcbbbkkbkkkmnmnlannmnknnknknnmmnmnkknnnmnknnmmnfmnnnknnnknknnmmnknnnnnknknkkknnnmmmnnnnknnmkknnnmnnnnnnknnkkknkkknknnb`icc`ai`a`aa`jjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjlci`abbknkkkknnk`kkkkkbkbbbbkkkkkkbbbbkkkbbbbkbkkkbbbbbbbbabkkkbbaabbbbabaababbbbkbbkbbabbbbabbbbbbbbbabbbaaaabaabaabbikkbakkbbnkbbbljjjjajjjjjjjj",
+"iiciciiiiiiiiiiiiiiii`iiiii`i`iiiiiiiiii`ccciiciiiiiccalcccccccccclclc`lcllllllllcclllllllbbbnbabbbknmkjannmnnnknnknnmmmmnnnnknmfnmnnnkkmnnnnnnnkkkkknnkknknnnnkknknknknnnmnnnnknnnnknmmmnnnknnnnkkkkkkknnnnnk`cc`ab`a`cii`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlciaabbkknkkknnkakkkkkkbbkbbkkkkkkbbbbkkkkkkkkbbkbbkbbbbbabbbbbbbbbbbbbbababbabbbbbbbbbbbbbabakbkbbbabbbabaaabaabbabbaiakbabbbbbkankijjjjjjjjjjjjj",
+"iiicciciciiiiiiiiii`iii`ii`iii`iiiiiiiiciiiiciiiicciccliccciicclcllclcaclcllclllllclllllllbabbdkdddbnnklannnknnkknknnnnmmnnnkknmmmmnnfnnnknnnnnknnknnnnnkknnnnnkkkknkknnnnnnnnmknnnnmnnnmnnkkknnkkkkkkkknnnknb`c`bkbba`i``ijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjcibbbkkbknknkkn`kkbkkbbbbbkkbkkkbkkbbbknkkbkkbbbbbbbbbbbbbbbbbbbbbkbbbbbbabababbakbbbkabbbbkbbbkkbababbbaabaaaabbkaaa`bnabbkkbabbbkcjjjjjjjjjjjjj",
+"ciiiiciiiiciiiiiiiiii``i`iiiiiii`iiiiiiiciiciiicicccicccililccccclccllllllclllllllllbllllikkabbbbbkbkmblanmnknnknnnkknnnnnnnmmnmmnnnnnnnnnnnknnnnknnnnnnnnnknnnknnnkknnnkkkknnknknmnkknnnnknknnbkkkkkkkknmkkkb`ibknnkbaa``cjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`akkbbkbknnnnnibkbbbbkbkbbbkkbkkkkkkknkkbkbbbbbbbbbbbbbbbbbbbbbabbbbbabbbbbbbbbababbbabbbkabbbbababbbaaabbaaaakbbaaa`bnbbbbnkkbbbbljjjjjjjjjjjjj",
+"icciccicicii`c`ii`i``cc`ii`iii`ai`iic`iiciiciiiiccccccccclcccclcllciilclllllllllllllcjcllannkbbbkkbaknajknnkkkkkknnknmnnnnnnknnmnnnnnnnknnkkkkkkkknkknkkkknnnnkkmnnkkkkknkkknnnnnknnnknknkknknnnkkkkkkkknnmnnk`aknknknkb`d`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl``aknkbbkknnnkkikkbbbbbbbbkbbbkbbbbbbbkkkbbbbkbbbbbbbbbbbbbabbabbbbbbbabkbbaaaabaaababbbabbaabababbaabbbaaaaababbkbbb`ankabbknkbbkbijjjljjjjjjjjj",
+"iccici`c`ciii`kiiiiiiiai`iiiiii`ii`iiiccicciiicccciccccc`mlclclclccccllcllllclllllllllail`bkkbaknkbabkijnnkknknnkkkkknnmnnkkknnmkkkknnnnnknknnkknnnnnkknknnnknkkmmmnnnnkkkknnnnnkkknknkknkkkknnkknnnnnnnnmmnkbaknnnknfnbbnbjjjjjljjjjlcjjjjjjjjjjjjjjjjjjjjjjjl``bnnknkkbkknkk`kbkbkbbbkbkbbkkkbbbbbbkbbbbbbbbbbbbbabbbbbbbbbbbbbbbbbbbkkbbbbbbbbbbbkbbbbabbaabbbabbbaaabbdbbbbbbbaa`amkbbbknknkbbijjjjjjjjjjjjj",
+"ciiiiia`ci`bna`iii`iibfiii``i`iiii`iiiiiiiciiicccccicccclccl`cilcllllllcclllccllllllll``liabbabkkkkbbbilknkknnknnnkkknnnknnnkknnkkknknknknknknknnnnnnknknnnkknnmmnnkkkkknknknnnmknmnkknnnnnmmmnkkknknkknknnkkbbnnnknmmkdakbjjjjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjli`bnknnnkkbbkkmabbbkbkbbkbbbbbkkbkbbbbbbbbbbkbbbbbbbbbbbbbbbbbbbbbababbbkbbbabaabababbbbabbabbbbabbbbabbababbbaabaabaaamnabbkkkkkkkijjjjjjjjjjjjj",
+"c`icciiciiciiiii`ii`ian`i```iiiaiciiciibiciiiicccccccccccccinlclclcccccllllclclllljcljlilibbbbbbaabkkb`jbkkknkknknkkknnnkknkkkkknkknnkkkkkknknnknnnnkkknknnkknnmmmnnkkknnnnnnnkknnnmnknnkkknnnkbkknnkkkkkkknnkbkkknmnkbbknkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl`i`bknknmkkbbbk`bbbbbbkbbkbbbkbbbbbbbbbbbbbbbbbbbbbabbbbbbbbbababbbabbbkkknbababkkbkbbbbkabbabbbabbbbbbaaabbaaabaababa`nkbabbkkkknbaljjjjjjjjjjjj",
+"ibaiiiiiik`ciai`iiiiii`iii`iiii`iciiiciaiiciiccicccccccccllililcclllcclllllllllllclllllllibkbkndaabnkb`jknnkkkknkknnnnkkknknkkkknnnnnknkknkknnnnkkknknknknnnnnnnknnnnkkknmnnnnnnnnkkknnnnnnknmnmknnnkkkkkkkknnbnnknmnbbnnnncjjjjjjjjjjjjjjjjjjl`jjjjjjjjjjjjjjl``abkkkknmkbbbbibbbbbkbbbkbbkbbbkbbbbbbbbbbbbbbbabbbbbbbbbbbabbbabbbbbbbbbkbbbabbbbbbbabbbabbabbabbabbbbabbbaabbaaabaaikbbbabbkkbbbbjjjjjjjjjjjjj",
+"c`iciiiii`i`iiii`a`ii`iiii`iiiiciiiiicciiiiicccccccccccclicjillccllcllcllllllllljlljllljlanmnnnbabnnnbclknnnnnnnkkknnkkkknknknnnnkknkkknnknnknnnknknnnnnknnnnnnnnnnnnnmmnnmnnnnnnkbkknnknnkkknnnnnnnkkkkkkbkkkbnknnkbbkmmnkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl`iakkkmnkknkkbbibkkkkkkbbbbbbbbbbbbkbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbkbbbbbkbbbbbkbkbbbbbaababbbbbaabbbbbbabaaaababaaaikbababbbkkkkbjjjjjjjjji`lj",
+"iiiiiciii`iiiiiiiii`iii``i`ii`i`iiicciiciiicicccccccccicc`ciiilallccllcllllllllllllllllllannmnkbbmkkfkljknnmfnnknkkkkkknkkknnnnnknkkkkkknnkknkknkkkknnnnkknnnmmmnnknkknmmmmmmnnnbknnkkmnnnkknnnnnnkkkkkkkknnkkbnknnbbakmnmbjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl`iiaknnnnknnmnkcakknkbkbkbbbbbbbbbbbbkbbbbbbbabbbbbbbbbbababbbkbabbbbkkkbbbbbabkkbkbkbbaabaaabbbbbbaabbbbbbbaabaaabbabikbbbbaabbknbkjjjjjjjjjjjjj",
+"iiiiiiiiiiiiiiiii`i````ii```ii`iiicicici`iicccccccccccclcclclcclclclllllcllllbllljcbcljllannnnbaknnmnncjnmnnnkkkkkknnkkknnnnnkkkkkkkknnnnknnknkknknnnkkkknmnnnnnmmnnnnnnnnnkkkkkkkkkkkkknnnkknnnnknnnkkknkknnb`knkkbdbnmnmbjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlii`abbkkknnkkmk`kknkkbbbbbbkbbbbbbbkkbbbbbabbbbbbbbbabbbbbbbbbbbbakkbbbbkkbbbkbkbkbbabaababbaaababbabakbbabbbaabbbababcanbaabbabkknkjjjjjjjjjjjjj",
+"ciciiiiiiiiiii`i`i```i`i`icc``i`iiiiiiiiicciciccccclccccccclcccllllllclllllllijllllijllllaknkkabkkknmnclmnknknkbnknnnnkkkkkknnknkkkknknknnkknkkkkknnkkkkkknnkknfnmnnknnnnnkkkkknkkkkkkkbkknmnnnkkkknkkkkknkkkbabnkkkbknnfnmjijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlii`akdbbbbkmmk`cabbbbbbbbbkkkbbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbaabbbbabbbkbbbbbbbbbbaaabbbaaaabaaabbbkbbaaaaabbbaadababiabbbabaaabbkbljjjjjjjjjjjj",
+"iiiiiiiiiiiii`i````iiiiiiii`baiiiiiiiicccccccccccccccccclclclcclclllcccllllllllllllljlljlbknkbankabknncckknknnnmnnnnmnkkknknkkkkkkknnnkknkknkkknknnnnnnnkkkkkknmknnnkkknknnnnnnknkkkkkkknkknnnnnnnnnnnknkkkkkkbknkkkknnnmnajjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiciakbkbkkkbbbaiakbkkkkbkkbkkkbbbbbbbbbbbbbbbbbbbbbbbbbababkbbbbbabbaabkbbbbaaabababbbbababbbabababbbkbbbbbbbbabbabaabc`aaaaaaaabkknijjjjjjjjjjjj",
+"iiiiiiii``i`ii`i``i`i`iii`cciiia`i`i`iiiiiccccccccclccccccclccccclcllilllllllllllllllllllkmkkkknbdabkklcknmmnnnnnkknnnkkkkkknknkkkknknnkkkkkkkkkkknnkknknkkkkkkmkkkkkkknnnnnnkkkknnkknnnnkkkknmnnnkkkbkkknkkbkbnmnnnkknmnnajjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjliiibbbbbbkka`caabkkbkkkkbkbbbkbbbbbbbbbbbbbbbbbbbabababbabbbbbbbbbababbbbaabbabbbbbbkbbaabbabbbbbbbbaabbbbaaaabaababaacc`iaaaa`aabkkijjjjjjjjjjjj",
+"lllllllllllllllllllljlllllllllllllllllljlljlljljlljljljljjljjljljjljjljjljjjljjjljjjljjjjknknmnnbbbbkklcnnnnnnkknkknnnkbkkknkkkknknknkknkkkkkkknnnmnnnmnnnnnknnnkkkkkknnmnnkkkkkkknknkmmnknkknnkkbkkkkkkkkbkkbbnnmmkkkkmmnkjljjjjjjljljjjjjjljljjjjjjjjjjjjjjjli``bbbbbbbaiiiaaakbkbbkbkbbbkbbabbbbbbbbbbbbkbbbbbbbbbbbbbbbbbbkbkbbbbbkbbababbbkbbbaaabbbbabbbbbbbabbbbaaaaaaababaaaaiccii`ii``aaab`jjjjjjjjjjjj",
+"ljljljljljljjljlljljlljljjljjjljjjjjjjljljlljljljjjjljljlljljljjljlllllljllljllljlljljjljbbknmmnkbbbbblinnnnnnnnknkknnnnkkkkknknknkkknkkkkkkknkknknnkknknnmnnnmnkkkkkknnnnkkkkknkkkknnnnknnknnnkkkknnnkkkbkkbbakmmkbbbbknnkjjjlljlljljllljljjljlllllllljlljljll`cibabaaa`cliaba`kkkkkbbkbbbbbkbbbbbbbbbbbbbbbbbbbababbbbbkkbbbbbkkbbbkbbbaababbbkbaabaabaabbbbbbababbkababbbbbbaaaaaaiciiicci```aad`ljllllllljlj",
+"ljlljlljljljljljlllljljljljllljllllhllllljljljjjlllljllllllljljljjljjljljlljjjljllllllljlddknmmnkbkbbbj`mmmnkknnnknkknnnkkkkkkkknkkkkkkkkkknkknknknnnnnnnnnnnnnnknkkbkknnkkknkkkkkbkknnknnkkkknkkknnkkbkkkbkkkaknnbbbbbbknnjljljljllllljllllljlljljljljlllllljl```bbaa`cjlcabbakknkkbkkkbbkbbkkbbbbbbbbbbbbbbbababbbbbbbbbbbbbbbbbkbkbbbbbaaabbabbbbbbaaaaabbbbbbbbaabaababbaaaaaaaab`c``icci`aaaa`iljjjljjljljl",
+"jlljlljlllhllhlhlljhlllljlljlljllhjljhjllhlllllhljljllhjllllhllhlhllhjllljhjlhjlhjjljlljlbkmmmmnmbkbkbj`knknnnnnnnknkknnkkkkkknkkkkkkkkkkkkknnknkkbnnnmnnnknkkkkknnnkknmmkkbkkkbkkkbknnnkkknkbkkkkkkkbkkknkknnbkmnkbbbabbadllllllhlllljhjhjljlljlllllllhjlllllc```bba`clliakkbabbbkbbbkkbkkbbbkbbbbbbbbbbbbbbbbbbbbbbbbbbabbbkkbbbbbbbabbbbbabbbbaaaabababaaabbababaaabaaaaaaaaababbaaiaa``i`a`add`cljhljlljljll",
+"lljhjhlhjllllllllhlljlljhjlljllllllhlllhjllhllljlllljljlljljlllllllllhlllhllljljlllllljljnknmnmmmnkkbal`kkknnnkkkkknkknmkkkkkkkkmnkkkkkkkknmnkknnkkbkkkkkkknknknknnnknnnnkkkkbkkkkkkkbkkkkkkknkbkkkkkknnnmnkknnknmnbbbkbbbbljljljjljljhjljlhlhllhjhlllllljljllli``kkaiclc`bbkkkbbbbkkkkbbbbkbbkkbbbbabbbkbbababbabbkkbabbbaabbabbabbbbbbbbkbabbbbbbaaabaabaaabbbaababaaababaabbbbbbabacbbaaa`i`abb`iljlllljhjljj",
+"llllljljlhllhlllhjllhjhllhlllllljhjljhjlllhjllhlhjhlhlhlhlhlhjhjlljhjljlljlllhlhllhllhllhkknmknmmnkkbbj`nnnnnnnnkkkknnkmnnmnkkkkkkkkkkkkkknnkkkkkkkkkkknkkkkkkkkknmnnnnnkkkkkkkkkkkkbkknkknnnkkknknknnnnknkknmnnnnnbbbbbdbdjlljhlhlhlhlllhlllllljljjhjllllllljhiiiba``ic`bnkbbkbbbkbkkbkbbbkbbbkkkkbbbbbababbbbabbbbbabbbbabbbbbbbbabaabbbkbbbkbbbaabaabaaabaaababbbbbbbabbbbbbbbbababiababba``add`iljhjllljhjhl",
+"llhllhjhjllljhjhjlhjllllllllhjhlhllhlllhjljhljljllljlljljljhlllhlhllhlhlhlhlljllljljlllllkbnmkknmmnkkalakknnkkkknknnkkkkmnnnnnnkkkbkkkknkknnkkkkkkkkkknkkkkkkkkknnmnnnnnkkbkbkbkbkbkkbkkkknnkkkkbkknnkkkknknknbkbkbbbabbbkbhllhllljljljhjjljlljhllhlllhlllhjhlli`i````a`abnnkbb`bkkkbbbbbkbbbbbbkkbbkbbbbabababbbbbkbbbaaabaaaabbaababbbbbkbbkbbaaaaaabaabaaabababbabaaaaabbbbaabaabbbibabnnk`iaaa``llljhjhllllj",
+"lllllhlllhllhlllhlllhlhlhjhjlllljlljlhjlllllllhlhlhlhlhlhlhlllllljlljljljlljlhjhjhjhllllckbbkkbknfmkbalannnnkkbknkkknkkknkbknnnkkkkkkknnnnnnnnkkkknnkkkkkkkkkkkkkknnnnnkbkkkkkkkkkkkkkknkkkkkbbkkkkkbkkbkkknnnbbbbbbabbbbbbllllllhlhlhljhlllllhjljljhjljhlllllhiiciiiaaabbnnmnk`kkkkbbbakbbbkbbbbbbbbkbbbbababbkbbkbbbbbbbbbbbabababbabaabbbbbbbaababaaaaabbababbabaaaaaaaaaaaaaabbbbbiabannnb``addahlllllljljll",
+"jhjhjllhlllhllhlllhllllllllhjhjlllllljhjhjhjhljlllllllhlllllhlhllhlhlhlhlllhljhlllllllllhbbbbbkbknkkb`jamnnnnkkkkkkknnnnnkkkkknkkkkkkkknnnnnnkkkknnnnkkkkkkkkkkkkkkkkkkkkkkkkkkkbkkkknnknnkbkkkkkbkbkkbkbkbnnnkkkkkbbbbkbbdljhjhjljljlllllhlllllhlhllhlhljhlllli`lli`aabbkmmnnmakkkkbbbbbbbbkkkkbbbbbkbbbbbbbbbbbbkbbbkabbkbbbbbababbbaabababaaaababaabaabaabbbbbbaabababaaaababaaabbaibbaknmka`abbbillllllllllj",
+"llljhjhjlllllllllhlllhlhlhllllhlhlhlhllhjllljlllljhjhljljllllllhllllhllllhlllhljlhllllllibdbbbbknkabkajbnnnnnnnkkbkknnnmkkkkkkknkkbkbkknnknmnnnnknnnnkkkkkkkkkkkkkkkkkkbkbkkbkbkbbkkkkknnkbkkkkbkkkkkkkkkkknnkbknkkkkbbbbkdlllllllhlhlhlhlljllllllllljljllllllliilc`abaabbknnnn`kkkkkkkkbabbbkkkbbbbbbbbbbababbbkbbkbkkbbbbbbbabababaabbabaaababaababaaaaaabababbbaaababaabbabaaaaaabb`abknkkka`abbbcljlljljllll",
+"lllhjllllljhjhllljhllllllllhllllllllllllhlhlhlhlhlllljhlhllllljllllljlhjhjllllhlhllhllllibdkbabknnbbkalknnnnmmnnnkkkkknnkbbkknnknkkkkkkkkknnnnnnknnnkkkkkkkkkkkkkkbkkkkkkkkkkkkkbkkbknnknkkkkkkbkkkkkkkbbkbbkkbkkkkkbkbbkkkllhjhllljljljlllhlllhllhlhlhlhlllllhiic`aabbbbbbnmmn`kkbkkkkbbbbbbbbbbbbbbbbbkbbabbbbbbkbbkbbbbkbkbbbbbbaabbabababababaaabababaaabbbbbabaaaaaaaaabaaabaaaab`annnkbka`abbdilllllhllllh",
+"lhlllhlhlhllllhjhlljljllllllllllhjhjhjhllllllllllllhlhllllhllhlhlhlhlhjllhjhlhllllllllll`ddbddaknmkkb`jnmnnknnkkkkkbkknnkknnkknnnkkkkkkknkknkbkknnnnnnnknnnkbkkkkkkkkkkkkkbkbkbkkkkknnnnnnkkbbbkkkkkkkkkkkbkbkbbkkbbbkkbkkbhllllhlllhlhlhllllllljljljlllljhjlll`ciakakbbkbbbknnakkkbkkkbbbkabbbkaabbbbkkbbbbbbbbbbbbbabbbkbbbkbabbbbababbabababbbbababaababbbbbbbbbbaaaababaaaabaaab`aibnmnkbnb`abbb`ljhlllllhll",
+"lllhllllhllhlhlllllhlhlhlhllllllllllllllllhlhllhjlljllllllllhllhlhlhlhhhlhhlhlhhhhhhhhhlodddddddknmkdglknknnnnkkkkkkkkkkkkkkknnmkkkknkkbnkkknkknmnnnnnnknkkkkknbkkkkkknnknkkkkkkkkbnnknnnknnnnkbkbkbbbkbkkkbbbbbbkkbbkkkbkkljhlljlhlllllljhjhlllhlhlhlhllhllhlh`i`ababkbbkmbknmakkkbbkbbbbbbbbbabbbbabbbkbbbbbbabbbbbbbbbbbkbbbbbbbbbaabbababbbbbbbabaabbaabbbabbbabbbbaaaaaaaaabaaaa``annnnkbb`bbad`llllhlljlll",
+"hlhllhlhllhlllhlhllllllllllllllhjhlllhjhlljhjhjhlhlhlhlhlhhhlhhhhhhhhhlhhllhhhhhhhhhhhhhhhhhhhhhghghhhhggghhghhhhhhgg`g`g`o`dddbddbbkkkkkkknnnkmnnmnnnkbnnnkbbbkbkbknkkbnknkkkknnkkkkkknnnnnmnkkkbkbkkkkbkkbkkbbbbkkkknnknklljhjhlljljhjllllljllljlllllhllhllllii`dbbbbbkbnnbkncbbbknkbabbkbbabbbbbbbbbbkbbbbabbbababbbbbbkkbkbbbbbbbabaababbbabababababbababbbbkbbbbbbaaaaaaabaaaabaa``mnmkkbb`bbdddllhllhlhlhl",
+"ljllllllhllhlhllhlhhlhhlhhhhhhhlhlhhhlhhlhhlhhhhhhhhhhhhhhhhgghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghghhghghhhhhhhhhhhhhhhhhhhhhhhchhhco`oddkknnmnnkknnnkknkkbbkkkkkkbkkkkkkkknmnnnnnnnnnkkbkbkbkbbkkbkkkkbbbkknkbknkkhlllhllhlhllhlhlhlhllhlhlllllllljhjlii`abbbbakbmnkkkibbbbkbbbbbkbbbabbbbbbakbkbbbkbabaabbabbkbbkbbkbbbbbbbbbbbaaaaabaaababaabbaabbbbbbbbbbbbabaaadaaaaaaabaa`knnkbdaadd`ddhlhlhlhlllh",
+"lhlhlhlhlhllhlhlhhlhhlhhhlhhlhhhhhhhhhhhhhhhhhhhhhhhgghhggggogoogggghhhhhhhhggggggghhhhhhhhhhhhhhhhhhlghhhhhhhhhgghghhhhlhhhhhghghhhhhhhhhhhhhhhhhhgho`oknknmnnmnkkkbkkkkkkkkkkkkknnnkknnnnnnnkbkbbbkbkbkkkbkkbbkkknnkkkkkblllhllllhlllhlllllllhllllhlhlhjhlllh`i`abbabbbknnnkn`bbbabbbbknkkkbkkbbbbbbbkbbbkkbdbbbbbbbbbbbbkbbkbbabbbbbbbbbaabaabbaabababbbbbbdabbbbbbddadddddddddddddd`kmkdd`higio`ghhhhhhhhhhh",
+"lhlllhllhlhlhlhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhgggghgggggggggggggghghhhhhhhhhhhhhhhhlljhlhhhhhhhhhhhhhhhhhhgggghhhhghggghghhhhhgghhhhhhhgghhhhghhhlhlhhhhhh`oddnnnnkkkkbkkkkkkkkkbkkknnnnnnnnkbkkkbbkkkbkbkbkbbbbbkkkkbkdblhlllllljhlljhlllllllllllljllllljhlli``aaabbanbnnknncaabbbbbbbbbbabbbbbkkbkbbbbbkkdbbdabbbbabbbbbbbkbabbbbbbbkkbbbbbababbbababaaabdbbkbkkbkdddd`oig`og`ghhhhhhhghhhhghhhhhhhhghhhgghh",
+"hhhhhhhhhhhhhhhhghgggggggggggggggggggghghghggggghghghggggogggggogggggghhhhhhggoggggghhghhghggggghhhhhhhhhghghhhhgggggghghhhhgggggggggggghhhhhgghhhhghhhhllhhhhhglhgiodddnknnnnnkkkkkknnnkknnkkbbbbbkkbbkbkkkkkkbbbbbbbbdbbdlljhjhjhlljhllllllllllllllhlhjlllljli`i`baabbbbnnkkblbkkkbbbbkbbbbbbbbbbkbbbbbbbkbdabbdddabbbbbbbabbbbbbbabbabbbkbabbbbabbbbbbbdddddkddd`oihhlhhhhghgggghhhhhhhhhghhhhhhhghghghghgggg",
+"hhhhhhhhhhhhhhghggggghghgghghghgggggggghgggggggggghhhhhhggggggggggggggggggggghhhghghhhhhhhhhhhhhgggghhhhghgggghghggggggggggggggggggghhhhhhghghhhhhhhgghhhhhhhhhhhhlhlhhhhhh`ddkkddbbkkkkkknkkkbkkkkbkkkbbbkbbkknnnnnkbbbkkkllhlllhllhlllhlhlhlhllhllhlllhlhlhlhiii`abbbbakkbba`ibbbbkbbkbbbababbkbbabbkkbbkbdbdbbabbbbbkkbkbbbkbbbbbbbbbabbkkbbbkbkbbdbbddd``o`ohhhhhhhhhhhhhhhlhhhhghggghhhhgghhhggggggggghgggg",
+"gggggggogggggggggggggggggggggggggggghgggggggggggghghgghhhggggghgggggghhhhhggghhghhhhhhhhhhhhhgggghgggggghhhhhghghhhhghhhghghhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhlhhghhhhhhhhhhhhhhhcg`bknnnnnnnnnnnknnnbbbbbbabkknnnnbbbkmnklllllllllllhllljllljlllllljhjllljlll`i`abababkaa`ii````aababbkkkkkkknnkbbbbbbbkbbabbnbkmnnmknknkkbkkkbbbbbkkkkbbkkddkkddd`gcglhhhhhhhhhhhhhhhhghghhhghhhgggggghghhhhhghhhgggghhhhhhhh",
+"ggoggogogogoggggoggogoggggggghggggggghhgggggggggggggghghgggggggggggghghhhhhhhghhgghghhhhghgggggggggggghghgggghghhhhhhhhhhhhhhhghghhhhhghhhhhhhhlhhhhhhhhhhhhhhhhlhhhhhhlhhhhhhhlhlhhh`ddknnnknnnkknbnnnkabbbbbknnmnnnnnknnnhlllhjhjhjljlllhlllhllllllllllllhljhi`idkkbbabaiciiiccciabbabbknbbkkkkkbabbbbbbbbaabnnkkkmkknnnnkbbknkbdkkkknkkddo`ooggghhhghhhhhggggghghgghhhhhhhgghgggggggggghgggghggogghggghhhhggg",
+"ggogoggoggggggoggggggggggggghggghgggggggggggggggghhgghgggggggggghhhhhhhhhhhhhhhhhhhlhhhhhhhhhhhhhhhhhhhhhghhghghhhhhhhhghghhhghgggghhhhhhhhhhhhhhhhhhgghhhhhhhhhhhhhhhhhhhhhhhhhhhhlhhhhhgddknnkkknknnkbbkkbbbkmnnnnnnnnnnncjhjlllllhlhlllljllljhjllllllllljllli`ibkkbbba`i`aaiccc`aka``abbkbkkkknnbkbaaabkbabbnnkbkknnnknnnkdddmkddo`gghhhhhhhchghhghhhghggggghgghhhhggghhhhhhhhhhggggghgggogogggghhhhhhhghgggg",
+"hghghghghghhhhhhhghhhggghhghgggggogggggggggogggghghhgghgggggggggggghhhhhhhhhhghhhhhghhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhghhhhhhhhggghhhhhhhhhhhhhhhhghghhhhhghhhhhhhhhhghghghhhhhhhhhhhhhhlhhhhhgddbkmmmnkakkkbbbkbbbbbbnnmmnnhlllhjhljlljhjhlhlllhllhjhlllllhlhjhi`idbnkkkb```aa`ii``i```i`abbbbknbnkkbaaabbbbbabkmnkbbnnnmnkddo`oghhhhhgghhghhhhgghggghghgggggggggggghghgggghhhhhgogogggggghggggggghgghhghhhhhhhg",
+"hhhghhhhhhhhhhhhhhhhghhghgggggggggggoggogoggggggghgghhgghggggggggghhhhhhhhhhghhghhhhhhhhhhhhhhghhhhghggghhhhhhhhhhgggggghhhhhgghghghhghhhhhhhhhhgghhhghhhhhhhhhhggggggggggghhhhhhhhhlhhhhlhhhhhhhhgdddbbbbbabkkkkbbaabkknmnllhllhllhlhllhllllhllllllllhlhllllhli`iabkknkbaaaa`aa```aa`icl`akkkkkkkkka`abaabbbbbbkndddndkd`oghhhhhhhhhhhhhghghhhghggggggghgggggoggggooggghhgogggghghhhgggggggggghhghghgghgghghggh",
+"ggghghhhhhhhlhhhhgggggghgggghghghggggggoggggggggggghhghhhgggggghhhhhhhhhhghhhhghghhhhhhlllhhhhhhhhhhhhhhhhhhhhhhgghggggggghgggggggggggggggghgggghhhhggghghghhhhhgghghhhhhgghghhhhlhhhhhlhhhhlhhhlhlhhhhi`dkdddbbknkkkkkknnmlllhlllhlllhllhlhllhlhlhlhllllhlhlll````bbbbbabbaaabka`akkbicliannkkkbkkba`abbbdkkkbdkkdo`ghhhhhhhhhggghghhggggghggggghhgghghhggggoggghhhhghhhhhhhghgghhhhggohghhhhhgggogogggggggghgh",
+"hghghghhhhhhhhhhhhgggggggghghghggggghggggggggggggggggggghhhhghghhhhhhhhgghggggggggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhghggggggghghhhghggghghghhhhhhhhhhhhhhhhhhghhhhhhlhhhgggghhhhhhhhhhhhhhhhhhhhhhhlhhlhllhhhhh`dkkdkbbbbbbbkknlhlchlhllhllhlllllhlllllhllhlhlllhlhi`i`bbbbbbbbbabbbbaakkaiiliaknkkbkbbaddbddddddddohhhhhhhhhhhhhhhhggggggggggghhhhhggghghhhhgggoggggggggggghgggggggghghhhhhhhhhghggggggggggggghhhhh",
+"gggggghghhhhhhhhggggggghhhghhhghhhgggggggggggggggogggggghgghgggggggggghhhhhhggggggggghhhhhhhhhhhgggghggghhhhhhhghgggggghhhhhhghghhhhhhhhhhhhhhhghhhghhhhhhhhhhhhhhhlhhhhgghgghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgdnmnnnkbbbkblllllhlchlchlchlhllhlhchlchllchcllcliiiabakbbkbaaaaabaaakaaicciabknbbkbaddbddo`gggghhhhhhhhggggggghhgggggoggggggggogggggghghhhhghgggghhhhghhhhhggggggggggggggggggggggogoogggggggggggg",
+"ghhhhhhhhhhhhghggggggghhhhhhhhhhgggggggggggggoggggggggghggggghghhhhhhhhhhhggghggghgghghghhhhhhhhhhhhhhhhhhhhhghggggggggghghghhghggghhhhllllhhhhgghgggghgghghhhhhhlhhhhhhhgghhhhhhhhhhhhhhhhhhhhhhhhhlhhhhlhlhhlhh`dknmkkbbdlllhlchllhllchllchlchllclllchlllhchlgciabbkbbbbabbbabbabbaailcc`abkkbd`iiihhhhhhhhgghghghgggggggggghhghggggoggogggggggghhhhghgggggggggggghggggghhgggggghggggghggggogogogggggggggghhhh",
+"hhhhhhggggggghghhhhhhhhhhhhhhhhhhhhhhhhhhggggggohggggggggghhhhhhhhhhhhggggggggghghghghhhhhhhhhhhlhlhlhhhhhhgggggggggghghghhghhhhhhhhhhhlhhhhhhhggghhhhhhhhhhghghhhhhhhgggghhhhhhhhhhhhhhhhhhhhlllhhhhhhhhhhhlhhhllhlgakmkdglhlllllclcclllchllchlchlhchllhcllllccciabbabbbbbbababbaaaiiiiii`ddd`dgghhghhggghhhghhgggggggggggggggggggggogggggghhhhhhgggggggghhhhhhgghgggggggggggoggggghghggggggggggggggggghhghgggg",
+"hhgggggggggghhhhhhhhhhlhhhhhhhhhhlhhhhhhgghghhhhhhhhhgggghghhhhhhhhhhhgggggggghgggggggggggggghhhhhhhhhhhhgggggggggggggggghhhhhhhhhghhhhhhlhhhhhhgghhhhjljllhhgggghghhhhghghgghhhhhhlhhhhhhhhhhhhlhlhhhhhhhhhhhhhhhhhhhhg`gchllhlhlljjjjljjljljllllllllllllhllhllhidbbaabaabbkkbbbbaa````igioihhhhghghhhghhgggggggggghhhhgggggggghhhgghgggggghghhgghhhhggggggogggggggggggghggggggoggggggoggghhhhhhhhhhhhhgggggggg",
+"ggggggogggghghhhhhhhhhhhhhhhhhhhhhhhhggghghhhghhhhhhghghgghghhhhhhhhhgggggggggghgggggggggggghghhhhhhhhhgggggggggggghgggghhhghhhhhghghhhhhhhhhhhhhgghhlhjhjhhhhgghhhhhhhhhhghghghhhhhhhhhhhhhlllhhhhhhhhhhhhhhhhhhhhhhjhlhlhlhlhjjjjjjjjjjjjjjjjjjjjjjjjjjljllllhiiidbababbabbbknnkkdido`hhhhhhhhhhghgghghggghhgghgggggggggoggggoggggogggggoggggghgggggghggggggghgggggghhghggggogogghhggggggggggghhhggggggghggggg",
+"ogogoggggggggggghghggggghhhghggghghghggggghghhhghghghhgggggggggghhhhghgggggggggggggggggggghgggggggghggggggggggggggghghhhhghhhhhhggghhhhhhhhhhhhhhgghhhhhhlhjhhhhhhhhghhhhhhhhghhhhhhhhhhhhhhhhhlhhhhhhhhhhhhlhhhhhhhjhhhlhlhlhllljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjc`iibbbbbaaakbdkkkddighhhhhhhhhghgggggggghgghhhhghgggggggggggggggggogggggoggggggggghggggggggggggggogogghghhgggggggghhhhhhhhgghghhghghghhhgggggogo",
+"ggogogogggggghhhhhhhhhhhhhghgghhghhhghhhgggggghhghgggghggggghhhhhhhghhhhgggggggggggggggghhghgggggghghghhghhhhgggggghghhghhhhhhggghghhhhhhhhhhhhhgghghhljhjhhhhhhhhghghgghhhhhhhghhhhhhhhlhhhhhhhhhhhhhghhhhhhhhhhhhhhhllhhhhlhlllljjjjjjjjjjjjjjjjjjjjjjjjjjjjlli``bababbddddddogggghhhhhghghgghgggggggghggghggggggggggoggoggggggggggggggggghgggggggggggggggggogggggghghghgggggogghhhhhhggggggggggggogogggoggogo",
+"oogogogogogghgghhhhhhhhhhhhhhhhhhhhhhhgggggggggghghhhghghghhhhhhhhghgghghhhghhhhhhhhhhhhhghggggghgghghgghgghghhhgghghhghghhhhhhghhhhhhhhhhhhhhhhghghhhhhlhhhhhhhghhhhghhhhhhhhhhhhhhhhhhlhhlhhhhhhhhgghhhghhhhhhhhhhhhhhlhhhhhhhhlhlljjjjjjjjjjjjjjjjjjjjjjjjjjjiiibabbdbd`oghhhhghhghhohhhgggggghghgggghgggggggggggggogggggggogoggggggggogghhggggogoogggggogggggogggggggggggggggggghhgggggggggggggggggggogoogoo",
+"ggogoggggggggghhhhhhhhhhhhhhhhhhhhgggggghhghhhhhhhhhhhhhhhhhhhhhgghggggggghhghhhhhhghggggggghggghghghghgghhhhhghhhghhghghggggggghhhhhhhhhghgggggghhhhhhhhhhhhhghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhghhhlhhhhhlhhhhhlhlhlhhhlhjljjjjjjjjjjjjjjjjjjjjjjjjl```kbbd`ggihhhhgggghhghhghhghhhhggggggghgggggghhghggggggoogggggggggggggggoggggggggghhggogggggoggghhhhhhhgggggghgghghgggggggogogggggggggggggggogg",
+"ggggggogggggghhhhhhhhlllhlhhhhhhgghhhhhhghhhhhhhhhhhhhhhhhhhhhhhhghghghghhhhhhhhhhhhhghggghghghghhhhhhghhhhhhhhhhhhhhhhgghhggghhghghhhhgghgggggggghhhhhhhhhhhghghhhhhhhhhhhhhhhhllhhhhhhhhhhhhhhhhhhhhgghhhhhhhhhhhhhhhlhhhhlhhhhhhhlhlhjjjjjjjjjjjjjjjjjjjjjjlhi``ddihhhhhhhghhhghhhghhghhhhhhggggggggggggghhghgghgggggggogghhhghhgooogggogggggggggggggogoggggggogggggoggghghhhghhggogggghhhhghgggggggggggogggg",
+"gggggggghhhhhhhhhlhhhhhhhhhhhhghghhghghhhghghhhhhhhhhhhhhhhhhhgghgggghghhghhhhhghgggggggghgggggggggggghhhhhhhhhhhhhhhghhhggggggggggghghghghggggghhhhhhlhhhhhhhghhhhhhhhhhhhghghhhhhhhhhhhhghhhhghhhhhhhhhhhhhhhhllhhhhhhhhhhlhhhhhhhlhlhlhjjjjjjjjjjjjjjjjjjhlhcgggghghhhhhgghghgghgghgggggghhhhgggggghggggghhhgghhgggggogoggggghggghhgoogogoogggooogogogoggogogogogoggghhgggghhhhhghhgoghghhghhhhhhhgggoogggggh",
+"ghghhhhhhhhhlhhhhhhhhhhhghhhhghhghghhghghhghggghhhhhhhhhhhhhghhhgghghghggghghghghghhghhghggghghgggggggghhhhhlhlhhhhhhhghhhhghggggggghghghgghgggggghhhhhhhhhghhhhhhhhhghhgghgggghhhhhhhhhghhhhhghhhhhhhhhhhhhhhhhhhllhhhhhhhhhhhhhhhhhhhlhlllljjjjjjjjjjjjljlhllhhghhghghhghgggghgghggggghhhhhhhhhghggggghgggggggghhggggogggogogggggggggggggggoggogggggggggggogoggghggggggghggggogggggggggoggggggoggggggggggggggg",
+"hhhhhhhlhhhhhhhhhhhhhhhhhhghghghghghggggggggggggghhhhhhhhghghggggghghhghhhhhhhhghggghgghghhggggggggggggghhhhhhhhhhhhhhhhghgggghghgghghhghghgghggghhhhhhhhgggghghghghgghghghghhhhhhhhhlhhhhhghhghhhhhhhhhhhhhhlhhhhhhhhhhhhhhhhhlhhhhhlhhhlhhhhjljjjjjjllhhhhhhhhhhhggggogghhghhhggggggggggggghhhhhgghggghgggggggghhhhgggggggogoggggggggggggogogoggggggggggggggggggggggogggggggggogggggggoggggggghggghggggggggggg",
+"hhhhhhhhhhhhhhhhhhhhhhhhhghhggggggggggggggggoggggggghghhghghghgghgghghhhhhhhhhhhghghgggggghghhhghggggghghhhhhhhhhhhhhhghhghhhghghgggghhghghghhhhhhghhhhghghgggggghggghghhhhhhhhhhhhhhhhhhhgggghhhhhhhhllhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhlhhlhlhhhlljjhjhlhlhhhhhhggggggggggggggggggggooggggggggggggggghghggggoggghgghhggggggggogogggooogggggoggogogogoggghghghhggggggggggooghhhhhgogggooggggogggghhhggggggghghghg",
+"hhhhhhhghhhhhhhhhhhhhhhhghggggggggghhhghgggggggggghhghhhgghghghghghghhhhhhhhhgggggggghhghghghgghgggggggggggghhhhhhhhhhhhhhhhhhhggggghhhhhhhhghhhhhhhhhhgghghhhhghgghgghghghghhhhhhlhlhlhhhhhhhghhhhhhhhhhhhhhhhlhhhhhhghghhhhhhhhhhhhhlhhlhlhhlhhlhlhlhhhhhghhggggogggogggggghggggggghhggggggghgggggggggghggogggghghhggogggoggggoogggggggoggggggoggggggggggggggggggggggogggghhhghgggggggogoggggggggggggoggghhhhh",
+"hhhhhhhhhhhhhhhhhhhhhhhggggggggggghghhhghhgggggggggghhghhhhghghggghhhhhhhhhhhghgggggggggghghghgggggogggggghhhghggghgghghhhhhhhhghgghghhhhhhhghghhhhhhghggghghhhhhhghghhghhghhhhhhhhlhjhlhhhhhhghhhhhhhhhhhhhhhhhhhhhhghhghghhhhhhhhhhhhlhlhhhhhhhhhlhhhgghggggggggghggghggghghhggoggghhhggggggggggghhgggghggggggghhhhgggogoggogoggggggggggghghgggggoggggogoogggggogggoggggghggggggoogogggggggghghghggogogogoggog",
+"hhhhhhhhhhhhhggggggggggggggggghghghhhhhhgggggogggghgghhhhhhggggghghhhhhhhhhhghgggggggggghghhghgggogogggghhhhhggghggghghghhhhgggggghhhhhhhhhghggghhhhhhhghgghhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhhgghhghhhhhhghhhhhhhhhhhhgghhhhghhhlhhhhhhhhhhhhhhhhllhhlhhhhggggggoghghggoggoggggggggggghhgggggghggghghgggggggggggghhhhhgoogoggoggggooggghggggggggghggogoggggggggggggoggggggghghhhhggggggoggghgggggggggooooogogoggg",
+"hghhhhhhhhhhggggggggggghhhhhhhhhhhhhhhhgghgggggggghghhhhhghghghhhhhhhhhhhhhggggggggggghhhhghhggggggggghghghgghhghghgggggghggghghgghhhhhhhhhhgggggghhhhhhhhhhgghghhhhhhhhhhhhhhhhlhhhhhhhhhhhhggghhhhhhhgghghhhhhhghghhhghghhhhhhhhhhhhhhhlhlhlhhhhlhhhhhgggggggggghgggggoggggggggggghhhggghggggggggggggggoogggghhhhgoggggggggggggogghhhggggogghhghggghggghgggggggggogooogghhhghhhhhggggghhgggogogogoogogoogogogg",
+"ghghhhhhgggggggghhhhhhhhhhhhhhhhhhhhhhgghgggghghghghghgggggghhhhhhhhhhhhhhggggggggghghghggggghghgghhhhhhhhhhggggggggggggggghgghggghghhhhhhhgghghhhhghhhhhhhhhhhhhhhghhhhhhhhhhllhlhhhhhhhhhhhhghghhgggghhhhhhhhhhhhghghhghhhghhhhhhhhhhlhhhlhlhhlhhhhhhlghhggoggggggogghggogggggggghhghghggghgghggoggogggggggoogggggggggogoggogogggogghhggogghhhhhggggghhggggoooooooogggoggggghhghhhgghggggggogoghgghgggggoggggg",
+"ghghggggggggggggghghhhhhhhhhlhhhhhhhhhhhgghggghggggggggghghhghghhhhhhhghhggggggggggggggggggggggghhghghhhhhhghgghghggggogggggggggggghhhhhhggggghghhhhghhhhhhhhhhhggghhhhhlhlhlhhlhhhhhhhhhhhhhghghghhhghhgghhhhlhlhhhghghhhghhhhhhhhhhhhhhhhlhhhhhhhlhhhhhlhhhggoggggggooggggoggggggghhhhggggghgggggggggggggogogghgggggghhggggggghhgggggogoggggggggggggggggggggogogoggooggggggggggggggogoggggoggggggggghggggogggg",
+"hgggggghghggghghgghghhhhhhhhhhlhhhhhhhhghghhhghgggggghhhghghghhhhhhghghgghghhgggoogogogggghghhgghgghghghghghgghgggggggggggghggggggggghhggggghghhhhghghggghghhhhhhhghhhhhhlhlhlhhhhhhghhhlhhhhhgghhhhhhgghhhhhhhhhhhhhhhghghhhhhhhhhhhghhhhhhhhhhlhhhhhhhlhhhhhhhgggggghhggooggggggoggggggggghghhgooggggogogggggggggghhhhhhgggoghhhggogooggggggggggggogghhggogogoggoggggogggggggggggogogggooogoggoggggggggoggoggg",
+"ghghghhghhhhhghgggggghhhhhhhlhhhlhhhhhghghghhghggggggghhgggghgggggghhhhhhhhggggggggoggggghghhhhghgggggggggggggggggggggoggghghghgggggggghggggggggghhhhghghgghhhhhhhghhlhhlhhlhlhhhhhghhhlhllhhhhhhhhhhhhhhhhhhhhhhhhhhhgggghhhhhhhhlhhhhhhhlhlhhhlhhhhhhhhlhhhhhhhhggggggogoggggggggggggggghggghgggoogogoggoogogggggghhhhhhgggggggggggogggggggooggogoggghgggoogoogoggogogoggghgggggggggggghggggggggggggggoggogogg",
+"hhhhhhhhhghghggggggghhhhhhhhhhhhhhhhhhgggggggggggggghgggghgggghghghhhhhhhhgggggggoggggghhhhhhhhhghgghghhggggggggggggggggggggggggggghghghgghghgghhhhghghgghhhhhhhhggghhlhlhlhlhlhhhghhhhhlhlhhhhhhhhhhhhhhhhhhhhhhhhhhgggghhhhhhhlhhlhlhhlhhlhhhhhhhllhhhhlhhhhhhhhggggghggghggghgghhgggghhggggghggggoggggoggggggggogggghhhgghggggghgggggghgggggggggggggggooggogggggogogoggggghggggoooogoggggggggggggggggggoggggg",
+"hhhhhhhhghggggggggghghhhhhhhhhhhhhhhhggggggggggggggggggggggghghghhhhhhhggggggggoggggghhhhhhhhhhhhghgghggggggghghggggogggogggggghgghggghghghgggggggghghhhhhhhlllhhhghhhhhlhhlhlhhhhhghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhgghhjljhlhhlhlhhlhhhhhhlhhhhlhjhhlhhjhhhhhggghhhoghhgggggghhggggogggghhggggggggoggggggggggggggoggghgggggghhggogggghgggggogggggoggggghghghhhgggggggggggggoggggggggggggogggoggggggogogggg",
+"hhhhggggggggggggggghhhhhhhhhhhhhhhhggggggggggggghhhghghghghgghgghhhghgggghgggggggggghhhhhhhhhhhhghghggghgghhhhhghgggggggggggghggghgghgghhhgghgghghhgghghhhlllhlhhhhhhhhhhhhhhhhhhhgghhhhhhhhhhhhlllhlhhhhhhhhhghhhhhhhhhhhhhhhlhjhlhhlhhhhhhhhhlhlhhhhllhhlhjhllhhlhlhggggogooggggggggogggggoggggggooggogggggggggggggggggggghggggggggogoggggggooogogggggggggghghhhhhhhhhhhhggggggggoggghhhhhggggogggghggggoooogg",
+"gggggghggggggggggghgghhhhhhhhhhghgghghggggggggghggggghghggghggghghggghghhhghgggghghhghhhhhhhhhhghhhghggggggghhghghgggggogoggggghgghghghhghghgghghhhghghhhhlhhlhlhhhhhhhhhhhhhhhhhhhghhhhhhhgghhhhlhjhlhlhhhhhhhhhhhhhhhhhhhhhhhhlljlhhhlhhhhhhhhhhlhjhhhjhlhhhgjhhhhhhhhoggoogggoogghggghgggggggggoggggogoggoogggggghgghggghggggggogogogoooggghggoggggggggghhhhhhhhhhhhhhhhggghgggogoggghhhhhggogoghhhhhhgggggog"
+};
diff --git a/sys/amiga/ifchange b/sys/amiga/ifchange
new file mode 100644 (file)
index 0000000..db3f4ea
--- /dev/null
@@ -0,0 +1,56 @@
+.KEY oper/a,tmp/a,real/a,f1,f2,f3,f4,f5
+
+. ; miscellaneous script functions for the Amiga
+. ; SCCS Id: @(#)ifchange      3.2     96/02/04
+. ; Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1992, 1993, 1996.
+. ; NetHack may be freely redistributed.  See license for details.
+
+FAILAT 6
+IF <oper> EQ "MOVE"
+  IF EXISTS <real>
+  diff >T:mic -c <tmp> <real>
+  search from T:mic SEARCH "---" QUIET
+    IF WARN
+      echo "MOVE: no change"
+      delete <tmp>
+    ELSE
+      echo "MOVE: copy"
+      copy <tmp> <real> clone
+      delete <tmp>
+    ENDIF
+  ELSE
+    echo "MOVE: copy2"
+    copy <tmp> <real> clone
+    delete <tmp>
+  ENDIF
+  QUIT
+ENDIF
+
+IF <oper> EQ "TOUCH"
+  IF EXISTS <real>
+  diff >T:mic -c <tmp> <real>
+  search from T:mic SEARCH "---" QUIET
+    IF NOT WARN
+      echo "TOUCH: touch"
+      IF NOT <f1$@> EQ "@"
+        setdate <f1>
+      ENDIF
+      IF NOT <f2$@> EQ "@"
+        setdate <f2>
+      ENDIF
+      IF NOT <f3$@> EQ "@"
+        setdate <f3>
+      ENDIF
+      IF NOT <f4$@> EQ "@"
+        setdate <f4>
+      ENDIF
+      IF NOT <f5$@> EQ "@"
+        setdate <f5>
+      ENDIF
+    ENDIF
+  ENDIF
+  QUIT
+ENDIF
+
+echo "ifchange: '<oper>' not recognized"
+quit 10
diff --git a/sys/amiga/mkdmake b/sys/amiga/mkdmake
new file mode 100644 (file)
index 0000000..2d80c85
--- /dev/null
@@ -0,0 +1,14 @@
+GE/$@/%(left)/
+GE/$</%(right)/
+GE/\#/#/
+39(F B/#SFD_INSTEAD / ; E/#SFD_INSTEAD // ; N ; D )
+REWIND
+CG
+9(F P/#SFD_BEGIN/; D ; GE /##// ; F P/#SFD_ELSE/ ; CG ; DF P/#SFD_END/ ; D )
+Q
+
+       SCCS Id: @(#)mkdmake    3.3     96/02/17
+Copyright (c) Andrew Church, Olney, Maryland, 1994,1996.
+NetHack may be freely redistributed.  See license for details.
+
+See IV.B.4 of Install.ami for instructions on using this file.
diff --git a/sys/amiga/txt2iff.c b/sys/amiga/txt2iff.c
new file mode 100644 (file)
index 0000000..4edbbea
--- /dev/null
@@ -0,0 +1,457 @@
+/*     SCCS Id: @(#)txt2iff.c  3.2     95/07/28        */
+/*     Copyright (c) 1995 by Gregg Wonderly, Naperville, Illinois */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include <stdlib.h>
+
+#include "config.h"
+#include "tile.h"
+
+#include <dos/dos.h>
+#include <dos/dos.h>
+#include <dos/dosextens.h>
+#include <graphics/gfx.h>
+#include <graphics/gfxbase.h>
+#include <graphics/view.h>
+#include <libraries/iffparse.h>
+#include <libraries/dos.h>
+#include <clib/dos_protos.h>
+#include <clib/iffparse_protos.h>
+#ifndef _DCC
+# include <proto/exec.h>
+# include <proto/iffparse.h>
+# include <proto/dos.h>
+#endif
+
+void panic(const char *);
+void map_colors(void);
+int BestMatch(int, int, int);
+
+extern pixval ColorMap[3][MAXCOLORMAPSIZE];
+extern int colorsinmap;
+
+/*
+ * WARNING:
+ * This program carries forth the assumption that the colormaps in all
+ * of the .txt files are the same.  This is a bug.
+ */
+
+struct {
+       int Height;
+       int Width;
+} IFFScreen;
+
+/*
+ * We are using a hybrid form of our own design which we call a BMAP (for
+ * bitmap) form.  It is an ILBM with the bitmaps already deinterleaved,
+ * completely uncompressed.
+ * This speeds the loading of the images from the games point of view because it
+ * does not have to deinterleave and uncompress them.
+ */
+#define        ID_BMAP MAKE_ID( 'B', 'M', 'A', 'P' )   /* instead of ILBM */
+#define        ID_BMHD MAKE_ID( 'B', 'M', 'H', 'D' )   /* Same as ILBM */
+#define        ID_CAMG MAKE_ID( 'C', 'A', 'M', 'G' )   /* Same as ILBM */
+#define        ID_CMAP MAKE_ID( 'C', 'M', 'A', 'P' )   /* Same as ILBM */
+#define        ID_PDAT MAKE_ID( 'P', 'D', 'A', 'T' )   /* Extra data describing plane
+                                                * size due to graphics.library
+                                                * rounding requirements.
+                                                */
+#define        ID_PLNE MAKE_ID( 'P', 'L', 'N', 'E' )   /* The planes of the image */
+
+
+#ifndef _DCC
+extern
+#endif
+struct Library *IFFParseBase;
+
+int nplanes;
+
+
+/* BMHD from IFF documentation */
+typedef struct {
+    UWORD w, h;
+    WORD x, y;
+    UBYTE nPlanes;
+    UBYTE masking;
+    UBYTE compression;
+    UBYTE reserved1;
+    UWORD transparentColor;
+    UBYTE xAspect, yAspect;
+    WORD pageWidth, pageHeight;
+} BitMapHeader;
+
+typedef struct {
+    UBYTE r, g, b;
+} AmiColorMap;
+
+pixel pixels[TILE_Y][TILE_X];
+AmiColorMap *cmap;
+
+
+int findcolor( register pixel *pix );
+void packwritebody(  pixel (*tile)[TILE_X], char **planes, int tileno );
+
+
+void
+error( char *str )
+{
+    fprintf( stderr, "ERROR: %s\n", str );
+}
+
+/*
+ * This array maps the image colors to the amiga's first 16 colors.  The colors
+ * are reordered to help with maintaining dripen settings.
+ */
+int colrmap[] = { 0, 6, 9, 15, 4, 10, 2, 3, 5, 11, 7, 13, 8, 1, 14, 12 };
+
+/* How many tiles fit across and down. */
+
+#define COLS 20
+#define ROWS ((tiles + COLS-1) / COLS)
+
+main( int argc, char **argv )
+{
+    int colors;
+    struct {
+       long nplanes;
+       long pbytes;
+       long across;
+       long down;
+       long npics;
+       long xsize;
+       long ysize;
+    } pdat;
+    long pbytes;       /* Bytes of data in a plane */
+    int i, cnt;
+    BitMapHeader bmhd;
+    struct IFFHandle *iff;
+    long camg = HIRES|LACE;
+    int tiles=0;
+    char **planes;
+
+    if(argc != 3){
+       fprintf(stderr, "Usage: %s source destination\n", argv[0]);
+       exit(1);
+    }
+
+#if defined(_DCC) || defined(__GNUC__)
+    IFFParseBase = OpenLibrary( "iffparse.library", 0 );
+    if( !IFFParseBase ) {
+       error( "unable to open iffparse.library" );
+       exit( 1 );
+    }
+#endif
+
+    /* First, count the files in the file */
+    if( fopen_text_file( argv[1], "r" ) != TRUE )
+    {
+       perror( argv[1] );
+       return( 1 );
+    }
+
+    nplanes = 0;
+    i = colorsinmap-1; /*IFFScreen.Colors - 1; */
+    while( i != 0 )
+    {
+       nplanes++;
+       i >>= 1;
+    }
+
+    planes = malloc( nplanes * sizeof( char * ) );
+    if( planes == 0 )
+    {
+       error( "can not allocate planes pointer" );
+       exit( 1 );
+    }
+
+    while( read_text_tile( pixels ) == TRUE )
+       ++tiles;
+    fclose_text_file();
+
+    IFFScreen.Width = COLS * TILE_X;
+    IFFScreen.Height = ROWS * TILE_Y;
+
+    pbytes = (COLS * ROWS * TILE_X + 15) / 16 * 2 * TILE_Y;
+
+    for( i = 0; i < nplanes; ++i )
+    {
+       planes[ i ] = calloc( 1, pbytes );
+       if( planes[ i ] == 0 )
+       {
+           error( "can not allocate planes pointer" );
+           exit( 1 );
+       }
+    }
+
+    /* Now, process it */
+    if( fopen_text_file( argv[1], "r" ) != TRUE )
+    {
+       perror( argv[1] );
+       return( 1 );
+    }
+
+    iff = AllocIFF();
+    if( !iff )
+    {
+       error( "Can not allocate IFFHandle" );
+       return( 1 );
+    }
+
+    iff->iff_Stream = Open( argv[2], MODE_NEWFILE );
+    if( !iff->iff_Stream )
+    {
+       error( "Can not open output file" );
+       return( 1 );
+    }
+
+    InitIFFasDOS( iff );
+    OpenIFF( iff, IFFF_WRITE );
+
+    PushChunk( iff, ID_BMAP, ID_FORM, IFFSIZE_UNKNOWN );
+
+    bmhd.w = IFFScreen.Width;
+    bmhd.h = IFFScreen.Height;
+    bmhd.x = 0;
+    bmhd.y = 0;
+    bmhd.nPlanes = nplanes;
+    bmhd.masking = 0;
+    bmhd.compression = 0;
+    bmhd.reserved1 = 0;
+    bmhd.transparentColor = 0;
+    bmhd.xAspect = 100;
+    bmhd.yAspect = 100;
+    bmhd.pageWidth = TILE_X;
+    bmhd.pageHeight = TILE_Y;
+
+    PushChunk( iff, ID_BMAP, ID_BMHD, sizeof( bmhd ) );
+    WriteChunkBytes( iff, &bmhd, sizeof( bmhd ) );
+    PopChunk( iff );
+
+    PushChunk( iff, ID_BMAP, ID_CAMG, sizeof( camg ) );
+    WriteChunkBytes( iff, &camg, sizeof( camg ) );
+    PopChunk( iff );
+
+    /* We need to reorder the colors to get reasonable default pens but
+     * we also need to know where some of the colors are - so go find out.
+     */
+    map_colors();
+
+    cmap = malloc( (colors = (1L<<nplanes)) * sizeof(AmiColorMap) );
+    for( i = 0; i < colors; ++i )
+    {
+       cmap[ colrmap[ i ] ].r = ColorMap[ CM_RED ][ i ];
+       cmap[ colrmap[ i ] ].g = ColorMap[ CM_GREEN ][ i ];
+       cmap[ colrmap[ i ] ].b = ColorMap[ CM_BLUE ][ i ];
+    }
+
+    PushChunk( iff, ID_BMAP, ID_CMAP, IFFSIZE_UNKNOWN );
+    for (i = 0; i < colors; ++i)
+       WriteChunkBytes(iff, &cmap[i], 3);
+    PopChunk( iff );
+
+    cnt = 0;
+    while( read_text_tile( pixels ) == TRUE )
+    {
+       packwritebody( pixels, planes, cnt );
+       if( cnt % 20 == 0 )
+           printf( "%d..", cnt );
+       ++cnt;
+       fflush( stdout );
+    }
+
+    pdat.nplanes = nplanes;
+    pdat.pbytes = pbytes;
+    pdat.xsize = TILE_X;
+    pdat.ysize = TILE_Y;
+    pdat.across = COLS;
+    pdat.down = ROWS;
+    pdat.npics = cnt;
+
+    PushChunk( iff, ID_BMAP, ID_PDAT, IFFSIZE_UNKNOWN );
+    WriteChunkBytes( iff, &pdat, sizeof( pdat ) );
+    PopChunk( iff );
+
+    PushChunk( iff, ID_BMAP, ID_PLNE, IFFSIZE_UNKNOWN );
+    for( i = 0; i < nplanes; ++i )
+       WriteChunkBytes( iff, planes[i], pbytes );
+    PopChunk( iff );
+
+    CloseIFF( iff );
+    Close( iff->iff_Stream );
+    FreeIFF( iff );
+
+    printf( "\n%d tiles converted\n", cnt );
+
+#if defined(_DCC) || defined(__GNUC__)
+    CloseLibrary( IFFParseBase );
+#endif
+    exit( 0 );
+}
+
+findcolor( register pixel *pix )
+{
+    register int i;
+
+    for( i = 0; i < MAXCOLORMAPSIZE; ++i )
+    {
+       if( (pix->r == ColorMap[ CM_RED ][i] ) &&
+           (pix->g == ColorMap[ CM_GREEN ][i] ) &&
+           (pix->b == ColorMap[ CM_BLUE ][i] ) )
+       {
+           return( i );
+       }
+    }
+    return( -1 );
+}
+
+void
+packwritebody( pixel (*tile)[TILE_X], char **planes, int tileno )
+{
+    register int i, j, k, col;
+    register char *buf;
+    register int across, rowbytes, xoff, yoff;
+
+    /* how many tiles fit across? */
+    across = COLS;
+
+    /* How many bytes per pixel row */
+    rowbytes = ((IFFScreen.Width + 15)/16)*2;
+
+    /* How many bytes to account for y distance in planes */
+    yoff = ((tileno / across) * TILE_Y) * rowbytes;
+
+    /* How many bytes to account for x distance in planes */
+    xoff = (tileno % across) * (TILE_X/8);
+
+    /* For each row... */
+    for( i = 0; i < TILE_Y; ++i )
+    {
+       /* For each bitplane... */
+       for( k = 0; k < nplanes; ++k )
+       {
+           const int mask = 1l<<k;
+
+           /* Go across the row */
+           for( j = 0; j < TILE_X; j++ )
+           {
+               col = findcolor( &tile[ i ][ j ] );
+               if( col == -1 )
+               {
+                   error( "can not convert pixel color to colormap index" );
+                   return;
+               }
+               /* Shift the colors around to have good complements and to
+                * know the dripen values.
+                */
+               col = colrmap[ col ];
+
+               /* To top left corner of tile */
+               buf = planes[ k ] + yoff + xoff;
+
+               /*To i'th row of tile and the correct byte for the j'th pixel*/
+               buf += ( i * rowbytes ) + (j/8);
+
+               /* Or in the bit for this color */
+               *buf |= (((col & mask)!=0)<<(7-(j%8)));
+           }
+       }
+    }
+}
+
+/* #define DBG */
+
+/* map_colors
+ * The incoming colormap is in arbitrary order and has arbitrary colors in
+ * it, but we need (some) specific colors in specific places.  Find the
+ * colors we need and fix the mapping table to match.
+ */
+/* What we are aiming for: */
+/* XXX was 0-7 */
+#define CX_BLACK       0
+#define CX_WHITE       1
+#define CX_BROWN       11
+#define CX_CYAN                2
+#define CX_GREEN       5
+#define CX_MAGENTA     10
+#define CX_BLUE                4
+#define CX_RED         7
+/* we don't care about the rest, at least now */
+/* should get: black white blue red grey greyblue ltgrey */
+void
+map_colors(){
+       int x;
+#if 1
+int tmpmap[]={0,2,3,7,4,5,8,9,10,11,13,15,12,1,14,6};
+/* still not right: gray green yellow lost somewhere? */
+#else
+       int tmpmap[16];
+       int x,y;
+       for(x=0;x<16;x++)tmpmap[x]=-1;  /* set not assigned yet */
+
+       tmpmap[BestMatch(0,0,0)] = CX_BLACK;
+       tmpmap[BestMatch(255,255,255)] = CX_WHITE;
+       tmpmap[BestMatch(255,0,0)] = CX_RED;
+       tmpmap[BestMatch(0,255,0)] = CX_GREEN;
+       tmpmap[BestMatch(0,0,255)] = CX_BLUE;
+
+               /* clean up the rest */
+       for(x=0;x<16;x++){
+               for(y=0;y<16;y++)
+                       if(tmpmap[y]==x)goto outer_cont;
+               for(y=0;y<16;y++)
+                       if(tmpmap[y]==-1){
+                               tmpmap[y]=x;
+                               break;
+                       }
+               if(y==16)panic("too many colors?");
+outer_cont: ;
+       }
+       for(x=0;x<16;x++)
+               if(tmpmap[y]==-1)panic("lost color?");
+#endif
+       for(x=0;x<16;x++){
+#ifdef DBG
+               printf("final: c[%d]=%d (target: %d)\n",x,tmpmap[x],colrmap[x]);
+#endif
+               colrmap[x]=tmpmap[x];
+       }
+}
+BestMatch(r,g,b)
+       int r,g,b;
+{
+       int x;
+       int bestslot;
+       int bestrate=99999999L;
+       for(x=0;x<16;x++){
+               int rr = r-ColorMap[CM_RED][x];
+               int gg = g-ColorMap[CM_GREEN][x];
+               int bb = b-ColorMap[CM_BLUE][x];
+               int rate = rr*rr + gg*gg + bb*bb;
+               if(bestrate > rate){
+                       bestrate = rate;
+                       bestslot = x;
+               }
+       }
+#ifdef DBG
+       printf("map (%d,%d,%d) -> %d (error=%d)\n",r,g,b,bestslot,bestrate);
+#endif
+       return bestslot;
+}
+
+
+long *
+alloc( unsigned int n )
+{
+    long *ret = malloc( n );
+    if(!ret){
+       error("Can't allocate memory");
+       exit(1);
+    }
+    return( ret );
+}
+
+void
+panic(const char *msg){
+    fprintf(stderr,"PANIC: %s\n",msg);
+    exit(1);
+}
diff --git a/sys/amiga/winami.c b/sys/amiga/winami.c
new file mode 100644 (file)
index 0000000..7071bfb
--- /dev/null
@@ -0,0 +1,1725 @@
+/*     SCCS Id: @(#)winami.c   3.2     2000/01/12      */
+/* Copyright (c) Gregg Wonderly, Naperville, Illinois,  1991,1992,1993,1996. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "NH:sys/amiga/windefs.h"
+#include "NH:sys/amiga/winext.h"
+#include "NH:sys/amiga/winproto.h"
+#include "dlb.h"
+
+#ifdef AMIGA_INTUITION
+
+static int FDECL( put_ext_cmd, ( char *, int, struct amii_WinDesc *, int ) );
+
+struct amii_DisplayDesc *amiIDisplay;  /* the Amiga Intuition descriptor */
+struct Rectangle lastinvent, lastmsg;
+int clipping = 0;
+int clipx=0;
+int clipy=0;
+int clipxmax=0;
+int clipymax=0;
+int scrollmsg = 1;
+int alwaysinvent = 0;
+int amii_numcolors;
+long amii_scrnmode;
+
+/* Interface definition, for use by windows.c and winprocs.h to provide
+ * the intuition interface for the amiga...
+ */
+struct window_procs amii_procs =
+{
+    "amii",
+    WC_COLOR|WC_HILITE_PET|WC_INVERSE,
+    0L,
+    amii_init_nhwindows,
+    amii_player_selection,
+    amii_askname,
+    amii_get_nh_event,
+    amii_exit_nhwindows,
+    amii_suspend_nhwindows,
+    amii_resume_nhwindows,
+    amii_create_nhwindow,
+    amii_clear_nhwindow,
+    amii_display_nhwindow,
+    amii_destroy_nhwindow,
+    amii_curs,
+    amii_putstr,
+    amii_display_file,
+    amii_start_menu,
+    amii_add_menu,
+    amii_end_menu,
+    amii_select_menu,
+    genl_message_menu,
+    amii_update_inventory,
+    amii_mark_synch,
+    amii_wait_synch,
+#ifdef CLIPPING
+    amii_cliparound,
+#endif
+#ifdef POSITIONBAR
+    donull,
+#endif
+    amii_print_glyph,
+    amii_raw_print,
+    amii_raw_print_bold,
+    amii_nhgetch,
+    amii_nh_poskey,
+    amii_bell,
+    amii_doprev_message,
+    amii_yn_function,
+    amii_getlin,
+    amii_get_ext_cmd,
+    amii_number_pad,
+    amii_delay_output,
+#ifdef CHANGE_COLOR    /* only a Mac option currently */
+    amii_change_color,
+    amii_get_color_string,
+#endif
+    /* other defs that really should go away (they're tty specific) */
+    amii_delay_output,
+    amii_delay_output,
+    amii_outrip,
+    genl_preference_update
+};
+
+/* The view window layout uses the same function names so we can use
+ * a shared library to allow the executable to be smaller.
+ */
+struct window_procs amiv_procs =
+{
+    "amitile",
+    WC_COLOR|WC_HILITE_PET|WC_INVERSE,
+    0L,
+    amii_init_nhwindows,
+    amii_player_selection,
+    amii_askname,
+    amii_get_nh_event,
+    amii_exit_nhwindows,
+    amii_suspend_nhwindows,
+    amii_resume_nhwindows,
+    amii_create_nhwindow,
+    amii_clear_nhwindow,
+    amii_display_nhwindow,
+    amii_destroy_nhwindow,
+    amii_curs,
+    amii_putstr,
+    amii_display_file,
+    amii_start_menu,
+    amii_add_menu,
+    amii_end_menu,
+    amii_select_menu,
+    genl_message_menu,
+    amii_update_inventory,
+    amii_mark_synch,
+    amii_wait_synch,
+#ifdef CLIPPING
+    amii_cliparound,
+#endif
+#ifdef POSITIONBAR
+    donull,
+#endif
+    amii_print_glyph,
+    amii_raw_print,
+    amii_raw_print_bold,
+    amii_nhgetch,
+    amii_nh_poskey,
+    amii_bell,
+    amii_doprev_message,
+    amii_yn_function,
+    amii_getlin,
+    amii_get_ext_cmd,
+    amii_number_pad,
+    amii_delay_output,
+#ifdef CHANGE_COLOR    /* only a Mac option currently */
+    amii_change_color,
+    amii_get_color_string,
+#endif
+    /* other defs that really should go away (they're tty specific) */
+    amii_delay_output,
+    amii_delay_output,
+    amii_outrip,
+    genl_preference_update
+};
+
+unsigned short amii_initmap[ AMII_MAXCOLORS ];
+/* Default pens used unless user overides in nethack.cnf. */
+unsigned short amii_init_map[ AMII_MAXCOLORS ] =
+{
+    0x0000, /* color #0  C_BLACK    */
+    0x0FFF, /* color #1  C_WHITE    */
+    0x0830, /* color #2  C_BROWN    */
+    0x07ac, /* color #3  C_CYAN     */
+    0x0181, /* color #4  C_GREEN    */
+    0x0C06, /* color #5  C_MAGENTA  */
+    0x023E, /* color #6  C_BLUE     */
+    0x0c00, /* color #7  C_RED      */
+};
+
+unsigned short amiv_init_map[ AMII_MAXCOLORS ] =
+{
+    0x0000, /* color #0  C_BLACK    */
+    0x0fff, /* color #1  C_WHITE    */
+    0x00bf, /* color #2  C_CYAN     */
+    0x0f60, /* color #3  C_ORANGE   */
+    0x000f, /* color #4  C_BLUE     */
+    0x0090, /* color #5  C_GREEN    */
+    0x069b, /* color #6  C_GREY     */
+    0x0f00, /* color #7  C_RED      */
+    0x06f0, /* color #8  C_LTGREEN  */
+    0x0ff0, /* color #9  C_YELLOW   */
+    0x0f0f, /* color #10 C_MAGENTA  */
+    0x0940, /* color #11 C_BROWN    */
+    0x0466, /* color #12 C_GREYBLUE */
+    0x0c40, /* color #13 C_LTBROWN  */
+    0x0ddb, /* color #14 C_LTGREY   */
+    0x0fb9, /* color #15 C_PEACH    */
+
+    /* Pens for dripens etc under AA or better */
+    0x0222, /* color #16 */
+    0x0fdc, /* color #17 */
+    0x0000, /* color #18 */
+    0x0ccc, /* color #19 */
+    0x0bbb, /* color #20 */
+    0x0BA9, /* color #21 */
+    0x0999, /* color #22 */
+    0x0987, /* color #23 */
+    0x0765, /* color #24 */
+    0x0666, /* color #25 */
+    0x0555, /* color #26 */
+    0x0533, /* color #27 */
+    0x0333, /* color #28 */
+    0x018f, /* color #29 */
+    0x0f81, /* color #30 */
+    0x0fff, /* color #31 */
+};
+
+#if !defined( TTY_GRAPHICS ) || defined( SHAREDLIB )   /* this should be shared better */
+char morc;  /* the character typed in response to a --more-- prompt */
+#endif
+char spaces[ 76 ] =
+"                                                                           ";
+
+winid WIN_BASE = WIN_ERR;
+winid WIN_OVER = WIN_ERR;
+winid amii_rawprwin = WIN_ERR;
+
+/* Changed later during window/screen opens... */
+int txwidth = FONTWIDTH, txheight = FONTHEIGHT, txbaseline = FONTBASELINE;
+
+/* If a 240 or more row screen is in front when we start, this will be
+ * set to 1, and the windows will be given borders to allow them to be
+ * arranged differently.  The Message window may eventually get a scroller...
+ */
+int bigscreen = 0;
+
+/* This gadget data is replicated for menu/text windows... */
+struct PropInfo PropScroll = { AUTOKNOB|FREEVERT,
+                                       0xffff,0xffff, 0xffff,0xffff, };
+struct Image Image1 = { 0,0, 7,102, 0, NULL, 0x0000,0x0000, NULL };
+struct Gadget MenuScroll = {
+    NULL, -15,10, 15,-19, GRELRIGHT|GRELHEIGHT,
+    RELVERIFY|FOLLOWMOUSE|RIGHTBORDER|GADGIMMEDIATE|RELVERIFY,
+    PROPGADGET, (APTR)&Image1, NULL, NULL, NULL, (APTR)&PropScroll,
+    1, NULL
+};
+
+/* This gadget is for the message window... */
+struct PropInfo MsgPropScroll = { AUTOKNOB|FREEVERT,
+                                       0xffff,0xffff, 0xffff,0xffff, };
+struct Image MsgImage1 = { 0,0, 7,102, 0, NULL, 0x0000,0x0000, NULL };
+struct Gadget MsgScroll = {
+    NULL, -15,10, 14,-19, GRELRIGHT|GRELHEIGHT,
+    RELVERIFY|FOLLOWMOUSE|RIGHTBORDER|GADGIMMEDIATE|RELVERIFY,
+    PROPGADGET, (APTR)&MsgImage1, NULL, NULL, NULL, (APTR)&MsgPropScroll,
+    1, NULL
+};
+
+int wincnt=0;   /* # of nh windows opened */
+
+/* We advertise a public screen to allow some people to do other things
+ * while they are playing...  like compiling...
+ */
+
+#ifdef  INTUI_NEW_LOOK
+extern struct Hook fillhook;
+struct TagItem tags[] =
+{
+    { WA_BackFill, (ULONG)&fillhook },
+    { WA_PubScreenName, (ULONG)"NetHack" },
+    { TAG_DONE, 0 },
+};
+#endif
+
+/*
+ * The default dimensions and status values for each window type.  The
+ * data here is generally changed in create_nhwindow(), so beware that
+ * what you see here may not be exactly what you get.
+ */
+struct win_setup new_wins[] =
+{
+
+    /* First entry not used, types are based at 1 */
+    {{0}},
+
+    /* NHW_MESSAGE */
+    {{0,1,640,11,
+    0xff,0xff,
+    NEWSIZE|GADGETUP|GADGETDOWN|MOUSEMOVE|MOUSEBUTTONS|RAWKEY,
+    BORDERLESS|ACTIVATE|SMART_REFRESH
+#ifdef  INTUI_NEW_LOOK
+    |WFLG_NW_EXTENDED
+#endif
+    ,
+    NULL,NULL,(UBYTE*)"Messages",NULL,NULL,320,40,0xffff,0xffff,
+#ifdef  INTUI_NEW_LOOK
+    PUBLICSCREEN,tags
+#else
+    CUSTOMSCREEN
+#endif
+    },
+    0,0,1,1,80,80},
+
+    /* NHW_STATUS */
+    {{0,181,640,24,
+    0xff,0xff,
+    RAWKEY|MENUPICK|DISKINSERTED,
+    BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP
+#ifdef  INTUI_NEW_LOOK
+    |WFLG_NW_EXTENDED
+#endif
+    ,
+    NULL,NULL,(UBYTE*)"Game Status",NULL,NULL,0,0,0xffff,0xffff,
+#ifdef  INTUI_NEW_LOOK
+    PUBLICSCREEN,tags
+#else
+    CUSTOMSCREEN
+#endif
+    },
+    0,0,2,2,78,78},
+
+    /* NHW_MAP */
+    {{0,0,WIDTH,WINDOWHEIGHT,
+    0xff,0xff,
+    RAWKEY|MENUPICK|MOUSEBUTTONS|ACTIVEWINDOW|MOUSEMOVE,
+    BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP
+#ifdef  INTUI_NEW_LOOK
+    |WFLG_NW_EXTENDED
+#endif
+    ,
+    NULL,NULL,(UBYTE*)"Dungeon Map",NULL,NULL,64,64,0xffff,0xffff,
+#ifdef  INTUI_NEW_LOOK
+    PUBLICSCREEN,tags
+#else
+    CUSTOMSCREEN
+#endif
+    },
+    0,0,22,22,80,80},
+
+    /* NHW_MENU */
+    {{400,10,10,10,
+    0xff,0xff,
+    RAWKEY|MENUPICK|DISKINSERTED|MOUSEMOVE|MOUSEBUTTONS|
+    GADGETUP|GADGETDOWN|CLOSEWINDOW|VANILLAKEY|NEWSIZE|INACTIVEWINDOW,
+    WINDOWSIZING|WINDOWCLOSE|WINDOWDRAG|ACTIVATE|SMART_REFRESH
+#ifdef  INTUI_NEW_LOOK
+    |WFLG_NW_EXTENDED
+#endif
+    ,
+    &MenuScroll,NULL,NULL,NULL,NULL,64,32,0xffff,0xffff,
+#ifdef  INTUI_NEW_LOOK
+    PUBLICSCREEN,tags
+#else
+    CUSTOMSCREEN
+#endif
+    },
+    0,0,1,1,22,78},
+
+    /* NHW_TEXT */
+    {{0,0,640,200,
+    0xff,0xff,
+    RAWKEY|MENUPICK|DISKINSERTED|MOUSEMOVE|
+    GADGETUP|CLOSEWINDOW|VANILLAKEY|NEWSIZE,
+    WINDOWSIZING|WINDOWCLOSE|WINDOWDRAG|ACTIVATE|SMART_REFRESH
+#ifdef  INTUI_NEW_LOOK
+    |WFLG_NW_EXTENDED
+#endif
+    ,
+    &MenuScroll,NULL,(UBYTE*)NULL,NULL,NULL,100,32,0xffff,0xffff,
+#ifdef  INTUI_NEW_LOOK
+    PUBLICSCREEN,tags
+#else
+    CUSTOMSCREEN
+#endif
+    },
+    0,0,1,1,22,78},
+
+    /* NHW_BASE */
+    {{0,0,WIDTH,WINDOWHEIGHT,
+    0xff,0xff,
+    RAWKEY|MENUPICK|MOUSEBUTTONS,
+    BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP
+#ifdef  INTUI_NEW_LOOK
+    |WFLG_NW_EXTENDED
+#endif
+    ,
+    NULL,NULL,(UBYTE*)NULL,NULL,NULL,-1,-1,0xffff,0xffff,
+#ifdef  INTUI_NEW_LOOK
+    PUBLICSCREEN,tags
+#else
+    CUSTOMSCREEN
+#endif
+    },
+    0,0,22,22,80,80},
+
+    /* NHW_OVER */
+    {{320,20,319,179,
+    0xff,0xff,
+    RAWKEY|MENUPICK|MOUSEBUTTONS,
+    BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP
+#ifdef  INTUI_NEW_LOOK
+    |WFLG_NW_EXTENDED
+#endif
+    ,
+    NULL,NULL,(UBYTE*)NULL,NULL,NULL,64,32,0xffff,0xffff,
+#ifdef  INTUI_NEW_LOOK
+    PUBLICSCREEN,tags
+#else
+    CUSTOMSCREEN
+#endif
+    },
+    0,0,22,22,80,80},
+};
+
+const char winpanicstr[] = "Bad winid %d in %s()";
+
+/* The opened windows information */
+struct amii_WinDesc *amii_wins[ MAXWIN + 1 ];
+
+#ifdef  INTUI_NEW_LOOK
+/*
+ * NUMDRIPENS varies based on headers, so don't use it
+ * here, its value is used elsewhere.
+ */
+UWORD amii_defpens[ 20 ];
+
+struct TagItem scrntags[] =
+{
+    { SA_PubName, (ULONG)"NetHack" },
+    { SA_Overscan, OSCAN_TEXT },
+    { SA_AutoScroll, TRUE },
+#if LIBRARY_VERSION >= 39
+    { SA_Interleaved, TRUE },
+#endif
+    { SA_Pens, (ULONG)0 },
+    { SA_DisplayID, 0 },
+    { TAG_DONE, 0 },
+};
+
+#endif
+
+struct NewScreen NewHackScreen =
+{
+    0, 0, WIDTH, SCREENHEIGHT, 3,
+    0, 1,     /* DetailPen, BlockPen */
+    HIRES,
+    CUSTOMSCREEN
+#ifdef  INTUI_NEW_LOOK
+    |NS_EXTENDED
+#endif
+    ,
+    &Hack80,  /* Font */
+    NULL,     /*(UBYTE *)" NetHack X.Y.Z" */
+    NULL,     /* Gadgets */
+    NULL,     /* CustomBitmap */
+#ifdef  INTUI_NEW_LOOK
+    scrntags
+#endif
+};
+
+/*
+ * plname is filled either by an option (-u Player  or  -uPlayer) or
+ * explicitly (by being the wizard) or by askname.
+ * It may still contain a suffix denoting pl_character.
+ * Always called after init_nhwindows() and before display_gamewindows().
+ */
+void
+amii_askname()
+{
+    char plnametmp[300]; /* From winreq.c: sizeof(StrStringSIBuff) */
+    *plnametmp = 0;
+    do {
+       amii_getlin( "Who are you?", plnametmp );
+    } while( strlen( plnametmp ) == 0 );
+
+    strncpy(plname, plnametmp, PL_NSIZ-1); /* Avoid overflowing plname[] */
+    plname[PL_NSIZ-1] = 0;
+
+    if( *plname == '\33' )
+    {
+       clearlocks();
+       exit_nhwindows(NULL);
+       terminate(0);
+    }
+}
+
+/* Discarded ... -jhsa
+#include "NH:sys/amiga/char.c"
+*/
+
+/* Get the player selection character */
+
+#if 0 /* New function at the bottom */
+void
+amii_player_selection()
+{
+    register struct Window *cwin;
+    register struct IntuiMessage *imsg;
+    register int aredone = 0;
+    register struct Gadget *gd;
+    static int once = 0;
+    long class, code;
+
+    amii_clear_nhwindow( WIN_BASE );
+    if (validrole(flags.initrole))
+       return;
+    else {
+       flags.initrole=randrole();
+       return;
+    }
+#if 0 /* Don't query the user ... instead give random character -jhsa */
+
+#if 0  /* OBSOLETE */
+    if( *pl_character ){
+       pl_character[ 0 ] = toupper( pl_character[ 0 ] );
+       if( index( pl_classes, pl_character[ 0 ] ) )
+           return;
+    }
+#endif
+
+    if( !once ){
+       if( bigscreen ){
+           Type_NewWindowStructure1.TopEdge =
+             (HackScreen->Height/2) - (Type_NewWindowStructure1.Height/2);
+       }
+       for( gd = Type_NewWindowStructure1.FirstGadget; gd;
+         gd = gd->NextGadget )
+       {
+           if( gd->GadgetID != 0 )
+               SetBorder( gd );
+       }
+       once = 1;
+    }
+
+    if( WINVERS_AMIV )
+    {
+# ifdef        INTUI_NEW_LOOK
+       Type_NewWindowStructure1.Extension = wintags;
+       Type_NewWindowStructure1.Flags |= WFLG_NW_EXTENDED;
+       fillhook.h_Entry = (ULONG(*)())LayerFillHook;
+       fillhook.h_Data = (void *)-2;
+       fillhook.h_SubEntry = 0;
+#endif
+    }
+
+    Type_NewWindowStructure1.Screen = HackScreen;
+    if( ( cwin = OpenShWindow( (void *)&Type_NewWindowStructure1 ) ) == NULL )
+    {
+       return;
+    }
+#if 0
+    WindowToFront( cwin );
+#endif
+
+    while( !aredone )
+    {
+       WaitPort( cwin->UserPort );
+       while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL )
+       {
+           class = imsg->Class;
+           code = imsg->Code;
+           gd = (struct Gadget *)imsg->IAddress;
+           ReplyMsg( (struct Message *)imsg );
+
+           switch( class )
+           {
+           case VANILLAKEY:
+               if( index( pl_classes, toupper( code ) ) )
+               {
+                   pl_character[0] = toupper( code );
+                   aredone = 1;
+               }
+               else if( code == ' ' || code == '\n' || code == '\r' )
+               {
+                   flags.initrole = randrole();
+#if 0  /* OBSOLETE */
+#ifdef  TOURIST
+                   strcpy( pl_character, roles[ rnd( 11 ) ] );
+#else
+                   strcpy( pl_character, roles[ rnd( 10 ) ] );
+#endif
+#endif
+                   aredone = 1;
+                   amii_clear_nhwindow( WIN_BASE );
+                   CloseShWindow( cwin );
+                   RandomWindow( pl_character );
+                   return;
+               }
+               else if( code == 'q' || code == 'Q' )
+               {
+               CloseShWindow( cwin );
+               clearlocks();
+               exit_nhwindows(NULL);
+               terminate(0);
+               }
+               else
+                   DisplayBeep( NULL );
+               break;
+
+           case GADGETUP:
+               switch( gd->GadgetID )
+               {
+               case 1: /* Random Character */
+                   flags.initrole = randrole();
+#if 0  /* OBSOLETE */
+#ifdef  TOURIST
+                   strcpy( pl_character, roles[ rnd( 11 ) ] );
+#else
+                   strcpy( pl_character, roles[ rnd( 10 ) ] );
+#endif
+#endif
+                   amii_clear_nhwindow( WIN_BASE );
+                   CloseShWindow( cwin );
+                   RandomWindow( pl_character );
+                   return;
+
+               default:
+                   pl_character[0] = gd->GadgetID;
+                   break;
+               }
+               aredone = 1;
+               break;
+
+           case CLOSEWINDOW:
+               CloseShWindow( cwin );
+               clearlocks();
+               exit_nhwindows(NULL);
+               terminate(0);
+               break;
+           }
+       }
+    }
+    amii_clear_nhwindow( WIN_BASE );
+    CloseShWindow( cwin );
+#endif /* Do not query user ... -jhsa */
+}
+#endif /* Function elsewhere */
+
+#if 0 /* Unused ... -jhsa */
+
+#include "NH:sys/amiga/randwin.c"
+
+void
+RandomWindow( name )
+    char *name;
+{
+    struct MsgPort *tport;
+    struct timerequest *trq;
+    static int once = 0;
+    struct Gadget *gd;
+    struct Window *w;
+    struct IntuiMessage *imsg;
+    int ticks = 0, aredone = 0, timerdone = 0;
+    long mask, got;
+
+    tport = CreateMsgPort();
+    trq = (struct timerequest *)CreateIORequest( tport, sizeof( *trq ) );
+    if( tport == NULL || trq == NULL )
+    {
+allocerr:
+       if( tport ) DeleteMsgPort( tport );
+       if( trq ) DeleteIORequest( (struct IORequest *)trq );
+       Delay( 8 * 50 );
+       return;
+    }
+
+    if( OpenDevice( TIMERNAME, UNIT_VBLANK, (struct IORequest *)trq, 0L ) != 0 )
+       goto allocerr;
+
+    trq->tr_node.io_Command = TR_ADDREQUEST;
+    trq->tr_time.tv_secs = 8;
+    trq->tr_time.tv_micro = 0;
+
+    SendIO( (struct IORequest *)trq );
+
+    /* Place the name in the center of the screen */
+    Rnd_IText5.IText = name;
+    Rnd_IText6.LeftEdge = Rnd_IText4.LeftEdge +
+               (strlen(Rnd_IText4.IText)+1)*8;
+    Rnd_NewWindowStructure1.Width = (
+           (strlen( Rnd_IText2.IText )+1) * 8 ) +
+           HackScreen->WBorLeft + HackScreen->WBorRight;
+    Rnd_IText5.LeftEdge = (Rnd_NewWindowStructure1.Width -
+           (strlen(name)*8))/2;
+
+    gd = Rnd_NewWindowStructure1.FirstGadget;
+    gd->LeftEdge = (Rnd_NewWindowStructure1.Width - gd->Width)/2;
+       /* Chose correct modifier */
+    Rnd_IText6.IText = "a";
+    switch( *name )
+    {
+    case 'a': case 'e': case 'i': case 'o':
+    case 'u': case 'A': case 'E': case 'I':
+    case 'O': case 'U':
+       Rnd_IText6.IText = "an";
+       break;
+    }
+
+    if( !once )
+    {
+       if( bigscreen )
+       {
+           Rnd_NewWindowStructure1.TopEdge =
+               (HackScreen->Height/2) - (Rnd_NewWindowStructure1.Height/2);
+       }
+       for( gd = Rnd_NewWindowStructure1.FirstGadget; gd; gd = gd->NextGadget )
+       {
+           if( gd->GadgetID != 0 )
+               SetBorder( gd );
+       }
+       Rnd_NewWindowStructure1.IDCMPFlags |= VANILLAKEY;
+
+       once = 1;
+    }
+
+    if( WINVERS_AMIV )
+    {
+#ifdef INTUI_NEW_LOOK
+       Rnd_NewWindowStructure1.Extension = wintags;
+       Rnd_NewWindowStructure1.Flags |= WFLG_NW_EXTENDED;
+       fillhook.h_Entry = (ULONG(*)())LayerFillHook;
+       fillhook.h_Data = (void *)-2;
+       fillhook.h_SubEntry = 0;
+#endif
+    }
+
+    Rnd_NewWindowStructure1.Screen = HackScreen;
+    if( ( w = OpenShWindow( (void *)&Rnd_NewWindowStructure1 ) ) == NULL )
+    {
+       AbortIO( (struct IORequest *)trq );
+       WaitIO( (struct IORequest *)trq );
+       CloseDevice( (struct IORequest *)trq );
+       DeleteIORequest( (struct IORequest *) trq );
+       DeleteMsgPort( tport );
+       Delay( 50 * 8 );
+       return;
+    }
+
+    PrintIText( w->RPort, &Rnd_IntuiTextList1, 0, 0 );
+
+    mask = (1L << tport->mp_SigBit)|(1L << w->UserPort->mp_SigBit);
+    while( !aredone )
+    {
+       got = Wait( mask );
+       if( got & (1L << tport->mp_SigBit ) )
+       {
+           aredone = 1;
+           timerdone = 1;
+           GetMsg( tport );
+        }
+        while( w && ( imsg = (struct IntuiMessage *) GetMsg( w->UserPort ) ) )
+        {
+           switch( (long)imsg->Class )
+           {
+               /* Must be up for a little while... */
+           case INACTIVEWINDOW:
+               if( ticks >= 40 )
+                   aredone = 1;
+               break;
+
+           case INTUITICKS:
+               ++ticks;
+               break;
+
+           case GADGETUP:
+               aredone = 1;
+               break;
+
+           case VANILLAKEY:
+               if(imsg->Code=='\n' || imsg->Code==' ' || imsg->Code=='\r')
+                   aredone = 1;
+               break;
+           }
+           ReplyMsg( (struct Message *)imsg );
+        }
+    }
+
+    if( !timerdone )
+    {
+       AbortIO( (struct IORequest *)trq );
+       WaitIO( (struct IORequest *)trq );
+    }
+
+    CloseDevice( (struct IORequest *)trq );
+    DeleteIORequest( (struct IORequest *) trq );
+    DeleteMsgPort( tport );
+    if(w) CloseShWindow( w );
+}
+#endif /* Discarded randwin ... -jhsa */
+
+/* this should probably not be needed (or be renamed)
+void
+flush_output(){} */
+
+/* Read in an extended command - doing command line completion for
+ * when enough characters have been entered to make a unique command.
+ */
+int
+amii_get_ext_cmd( void )
+{
+    menu_item *mip;
+    anything id;
+    struct amii_WinDesc *cw;
+#ifdef EXTMENU
+    winid win;
+    int i;
+    char buf[256];
+#endif
+    int colx;
+    int bottom = 0;
+    struct Window *w;
+    char obufp[ 100 ];
+    register char *bufp = obufp;
+    register int c;
+    int com_index, oindex;
+    int did_comp=0;    /* did successful completion? */
+    int sel = -1;
+
+    if( WIN_MESSAGE == WIN_ERR || ( cw = amii_wins[ WIN_MESSAGE ] ) == NULL )
+       panic(winpanicstr, WIN_MESSAGE, "get_ext_cmd");
+    w = cw->win;
+    bottom = amii_msgborder( w );
+    colx = 3;
+
+#ifdef EXTMENU
+    if (iflags.extmenu) {
+    win = amii_create_nhwindow( NHW_MENU );
+    amii_start_menu( win );
+    pline("#");
+    amii_putstr( WIN_MESSAGE, -1, " " );
+
+    for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i )
+    {
+       id.a_char = *extcmdlist[ i ].ef_txt;
+       sprintf( buf, "%-10s - %s ",
+                extcmdlist[ i ].ef_txt,
+                extcmdlist[ i ].ef_desc );
+       amii_add_menu( win, NO_GLYPH, &id, extcmdlist[i].ef_txt[0], 0, 0, buf, MENU_UNSELECTED);
+    }
+
+    amii_end_menu( win, (char*)0 );
+    sel = amii_select_menu( win, PICK_ONE, &mip );
+    amii_destroy_nhwindow( win );
+
+    if( sel == 1 )
+    {
+       sel = mip->item.a_char;
+       for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i )
+       {
+           if( sel == extcmdlist[i].ef_txt[0] )
+               break;
+       }
+
+       /* copy in the text */
+       if( extcmdlist[ i ].ef_txt != NULL )
+       {
+           amii_clear_nhwindow( WIN_MESSAGE );
+           (void) put_ext_cmd( (char *)extcmdlist[i].ef_txt, 0, cw, bottom );
+           return( i );
+       }
+       else
+           DisplayBeep( NULL );
+    }
+
+    return( -1 );
+    } else {
+#else
+
+    amii_clear_nhwindow( WIN_MESSAGE ); /* Was NHW_MESSAGE */
+    if( scrollmsg )
+    {
+       pline("#");
+       amii_addtopl(" ");
+    }
+    else
+    {
+       pline("# ");
+    }
+
+    sel = -1;
+    while((c = WindowGetchar()) != EOF)
+    {
+       amii_curs( WIN_MESSAGE, colx, bottom );
+       if(c == '?' )
+       {
+           int win, i;
+           char buf[ 100 ];
+
+           if(did_comp){
+               while(bufp!=obufp)
+               {
+                   bufp--;
+                   amii_curs(WIN_MESSAGE, --colx, bottom);
+                   Text(w->RPort,spaces,1);
+                   amii_curs(WIN_MESSAGE,colx,bottom);
+                   did_comp=0;
+               }
+           }
+
+           win = amii_create_nhwindow( NHW_MENU );
+           amii_start_menu( win );
+
+           for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i )
+           {
+               id.a_char = extcmdlist[i].ef_txt[0];
+               sprintf( buf, "%-10s - %s ",
+                        extcmdlist[ i ].ef_txt,
+                        extcmdlist[ i ].ef_desc );
+               amii_add_menu( win, NO_GLYPH, &id, extcmdlist[i].ef_txt[0], 0,
+                  0, buf, MENU_UNSELECTED);
+           }
+
+           amii_end_menu( win, (char*)0 );
+           sel = amii_select_menu( win, PICK_ONE, &mip );
+           amii_destroy_nhwindow( win );
+
+           if( sel == 0 )
+           {
+               return( -1 );
+           }
+           else
+           {
+               sel = mip->item.a_char;
+               for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i )
+               {
+                   if( sel == extcmdlist[i].ef_txt[0] )
+                       break;
+               }
+
+               /* copy in the text */
+               if( extcmdlist[ i ].ef_txt != NULL )
+               {
+                   amii_clear_nhwindow( WIN_MESSAGE );
+                   strcpy( bufp = obufp, extcmdlist[ i ].ef_txt );
+                   (void) put_ext_cmd( obufp, colx, cw, bottom );
+                   return( i );
+               }
+               else
+                   DisplayBeep( NULL );
+           }
+       }
+       else if(c == '\033')
+       {
+           return( -1 );
+       }
+       else if(c == '\b')
+       {
+           if(did_comp){
+               while(bufp!=obufp){
+                   bufp--;
+                   amii_curs(WIN_MESSAGE, --colx, bottom);
+                   Text(w->RPort,spaces,1);
+                   amii_curs(WIN_MESSAGE,colx,bottom);
+                   did_comp=0;
+                   sel = -1;
+               }
+           }
+           else if(bufp != obufp)
+           {
+               sel = -1;
+               bufp--;
+               amii_curs( WIN_MESSAGE, --colx, bottom);
+               Text( w->RPort, spaces, 1 );
+               amii_curs( WIN_MESSAGE, colx, bottom);
+           }
+           else
+               DisplayBeep( NULL );
+       }
+       else if( c == '\n' || c == '\r' )
+       {
+           return(sel);
+       }
+       else if( c >= ' ' && c < '\177')
+       {
+               /* avoid isprint() - some people don't have it
+                  ' ' is not always a printing char */
+           *bufp = c;
+           bufp[1] = 0;
+           oindex = 0;
+           com_index = -1;
+
+           while(extcmdlist[oindex].ef_txt != NULL)
+           {
+               if(!strnicmp(obufp, (char *)extcmdlist[oindex].ef_txt, strlen(obufp)))
+               {
+                   if(com_index == -1) /* No matches yet*/
+                       com_index = oindex;
+                   else /* More than 1 match */
+                       com_index = -2;
+               }
+               oindex++;
+           }
+
+           if(com_index >= 0 && *obufp )
+           {
+               Strcpy(obufp, extcmdlist[com_index].ef_txt);
+               /* finish printing our string */
+               colx = put_ext_cmd( obufp, colx, cw, bottom );
+               bufp = obufp; /* reset it */
+               if(strlen(obufp) < BUFSZ-1 && strlen(obufp) < COLNO)
+                   bufp += strlen(obufp);
+               did_comp=1;
+               sel = com_index;
+           }
+           else
+           {
+               colx = put_ext_cmd( obufp, colx, cw, bottom );
+               if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)
+                   bufp++;
+           }
+       }
+       else if(c == ('X'-64) || c == '\177')
+       {
+           colx = 0;
+           amii_clear_nhwindow( WIN_MESSAGE );
+           pline( "# " );
+           bufp = obufp;
+       } else
+           DisplayBeep( NULL );
+    }
+    return(-1);
+#endif
+}
+
+static int
+put_ext_cmd( obufp, colx, cw, bottom )
+    char *obufp;
+    int colx, bottom;
+    struct amii_WinDesc *cw;
+{
+    struct Window *w = cw->win;
+    char *t;
+
+    t = (char *)alloc( strlen( obufp ) + 7 );
+    if( t != NULL )
+    {
+       if( scrollmsg )
+       {
+           sprintf( t, "xxx%s", obufp );
+           t[0] = 1;
+           t[1] = 1;
+           t[2] = '#';
+           amii_curs( WIN_MESSAGE, 0, bottom);
+           SetAPen( w->RPort, C_WHITE );
+           Text(w->RPort, "># ", 3 );
+           /* SetAPen( w->RPort, C_BLACK ); */ /* Black text on black screen doesn't look too well ... -jhsa */
+           Text(w->RPort, t+3, strlen( t ) - 3 );
+       }
+       else
+       {
+           sprintf( t, "# %s", obufp );
+           amii_curs( WIN_MESSAGE, 0, bottom);
+           SetAPen( w->RPort, C_WHITE );
+           Text(w->RPort, t, strlen( t ) );
+       }
+       if( scrollmsg )
+           SetAPen( w->RPort, C_WHITE );
+       if( cw->data[ cw->maxrow - 1 ] )
+           free( cw->data[ cw->maxrow - 1 ] );
+       cw->data[ cw->maxrow - 1 ] = t;
+    }
+    else
+    {
+       amii_curs( WIN_MESSAGE, 0, bottom);
+       SetAPen( w->RPort, C_WHITE );
+       Text(w->RPort, "# ", 2 );
+       /* SetAPen( w->RPort, C_BLACK ); */ /* Black on black ... -jhsa */
+       Text(w->RPort, obufp, strlen( obufp ) );
+       SetAPen( w->RPort, C_WHITE );
+    }
+    amii_curs( WIN_MESSAGE, colx = strlen( obufp ) + 3 + ( scrollmsg != 0 ), bottom);
+    return( colx );
+}
+
+/* Ask a question and get a response */
+
+char amii_yn_function(query, resp, def)
+const char *query,*resp;
+char def;
+/*
+ *   Generic yes/no function. 'def' is the default (returned by space or
+ *   return; 'esc' returns 'q', or 'n', or the default, depending on
+ *   what's in the string. The 'query' string is printed before the user
+ *   is asked about the string.
+ *   If resp is NULL, any single character is accepted and returned.
+ *   If not-NULL, only characters in it are allowed (exceptions:  the
+ *   quitchars are always allowed, and if it contains '#' then digits
+ *   are allowed); if it includes an <esc>, anything beyond that won't
+ *   be shown in the prompt to the user but will be acceptable as input.
+ */
+{
+       register char q;
+       char rtmp[40];
+       boolean digit_ok, allow_num;
+       char prompt[QBUFSZ];
+       register struct amii_WinDesc *cw;
+
+       if( cw = amii_wins[ WIN_MESSAGE ] )
+           cw->disprows = 0;
+       if (resp) {
+           char *rb, respbuf[QBUFSZ];
+
+           allow_num = (index(resp, '#') != 0);
+           Strcpy(respbuf, resp);
+           /* any acceptable responses that follow <esc> aren't displayed */
+           if ((rb = index(respbuf, '\033')) != 0) *rb = '\0';
+           Sprintf(prompt, "%s [%s] ", query, respbuf);
+           if (def) Sprintf(eos(prompt), "(%c) ", def);
+           pline("%s", prompt);
+       } else {
+           amii_putstr(WIN_MESSAGE, 0, query);
+           cursor_on(WIN_MESSAGE);
+           q = WindowGetchar();
+           cursor_off(WIN_MESSAGE);
+           *rtmp = q;
+           rtmp[ 1 ] = 0;
+           amii_addtopl(rtmp);
+           goto clean_up;
+       }
+
+       do {    /* loop until we get valid input */
+           cursor_on(WIN_MESSAGE);
+           q = lowc(WindowGetchar());
+           cursor_off(WIN_MESSAGE);
+#if 0
+/* fix for PL2 */
+           if (q == '\020') { /* ctrl-P */
+               if(!doprev) (void) tty_doprev_message(); /* need two initially */
+               (void) tty_doprev_message();
+               q = (char)0;
+               doprev = 1;
+               continue;
+           } else if(doprev) {
+               tty_clear_nhwindow(WIN_MESSAGE);
+               cw->maxcol = cw->maxrow;
+               doprev = 0;
+               amii_addtopl(prompt);
+               continue;
+           }
+#endif
+           digit_ok = allow_num && isdigit(q);
+           if (q == '\033') {
+               if (index(resp, 'q'))
+                   q = 'q';
+               else if (index(resp, 'n'))
+                   q = 'n';
+               else
+                   q = def;
+               break;
+           } else if (index(quitchars, q)) {
+               q = def;
+               break;
+           }
+           if (!index(resp, q) && !digit_ok) {
+               amii_bell();
+               q = (char)0;
+           } else if (q == '#' || digit_ok) {
+               char z, digit_string[2];
+               int n_len = 0;
+               long value = 0;
+               amii_addtopl("#"),  n_len++;
+               digit_string[1] = '\0';
+               if (q != '#') {
+                   digit_string[0] = q;
+                   amii_addtopl(digit_string),  n_len++;
+                   value = q - '0';
+                   q = '#';
+               }
+               do {    /* loop until we get a non-digit */
+                   cursor_on(WIN_MESSAGE);
+                   z = lowc(WindowGetchar());
+                   cursor_off(WIN_MESSAGE);
+                   if (isdigit(z)) {
+                       value = (10 * value) + (z - '0');
+                       if (value < 0) break;   /* overflow: try again */
+                       digit_string[0] = z;
+                       amii_addtopl(digit_string),  n_len++;
+                   } else if (z == 'y' || index(quitchars, z)) {
+                       if (z == '\033')  value = -1;   /* abort */
+                       z = '\n';       /* break */
+                   } else if ( z == '\b') {
+                       if (n_len <= 1) { value = -1;  break; }
+                       else { value /= 10;  removetopl(1),  n_len--; }
+                   } else {
+                       value = -1;     /* abort */
+                       amii_bell();
+                       break;
+                   }
+               } while (z != '\n');
+               if (value > 0) yn_number = value;
+               else if (value == 0) q = 'n';           /* 0 => "no" */
+               else {  /* remove number from top line, then try again */
+                       removetopl(n_len),  n_len = 0;
+                       q = '\0';
+               }
+           }
+       } while(!q);
+
+       if (q != '#' && q != '\033') {
+           Sprintf(rtmp, "%c", q);
+           amii_addtopl(rtmp);
+       }
+    clean_up:
+       cursor_off(WIN_MESSAGE);
+       clear_nhwindow(WIN_MESSAGE);
+       return q;
+}
+
+void
+amii_display_file(fn, complain)
+const char *fn;
+boolean complain;
+{
+    register struct amii_WinDesc *cw;
+    register int win;
+    register dlb *fp;
+    register char *t;
+    register char buf[ 200 ];
+
+    if( fn == NULL )
+       panic("NULL file name in display_file()");
+
+    if( ( fp = dlb_fopen( fn, RDTMODE ) ) == (dlb *)NULL )
+    {
+       if (complain) {
+           sprintf( buf, "Can't display %s: %s", fn,
+#if defined(_DCC) || defined(__GNUC__)
+                       strerror(errno)
+#else
+# ifdef  __SASC_60
+                       __sys_errlist[ errno ]
+# else
+                       sys_errlist[ errno ]
+# endif
+#endif
+                       );
+           amii_addtopl( buf );
+       }
+       return;
+    }
+    win = amii_create_nhwindow( NHW_TEXT );
+
+    /* Set window title to file name */
+    if( cw = amii_wins[ win ] )
+       cw->morestr = (char *)fn;
+
+    while( dlb_fgets( buf, sizeof( buf ), fp ) != NULL )
+    {
+       if( t = index( buf, '\n' ) )
+           *t = 0;
+       amii_putstr( win, 0, buf );
+    }
+    dlb_fclose( fp );
+
+    /* If there were lines in the file, display those lines */
+
+    if( amii_wins[ win ]->cury > 0 )
+       amii_display_nhwindow( win, TRUE );
+
+    amii_wins[win]->morestr = NULL;            /* don't free title string */
+    amii_destroy_nhwindow( win );
+}
+
+/* Put a 3-D motif border around the gadget.  String gadgets or those
+ * which do not have highlighting are rendered down.  Boolean gadgets
+ * are rendered in the up position by default.
+ */
+
+void
+SetBorder( gd )
+    register struct Gadget *gd;
+{
+    register struct Border *bp;
+    register short *sp;
+    register int i, inc = -1, dec = -1;
+    int borders = 6;
+    int hipen = flags.amii_dripens[ SHINEPEN ], shadowpen = flags.amii_dripens[ SHADOWPEN ];
+#ifdef INTUI_NEW_LOOK
+    struct DrawInfo *dip;
+#endif
+
+#ifdef INTUI_NEW_LOOK
+    if( IntuitionBase->LibNode.lib_Version >= 37 )
+    {
+       if( dip = GetScreenDrawInfo( HackScreen ) )
+       {
+           hipen = dip->dri_Pens[ SHINEPEN ];
+           shadowpen = dip->dri_Pens[ SHADOWPEN ];
+           FreeScreenDrawInfo( HackScreen, dip );
+       }
+    }
+#endif
+    /* Allocate two border structures one for up image and one for down
+     * image, plus vector arrays for the border lines.
+     */
+
+    if( gd->GadgetType == STRGADGET )
+       borders = 12;
+
+    if( ( bp = (struct Border *)alloc( ( ( sizeof( struct Border ) * 2 ) +
+                       ( sizeof( short ) * borders ) ) * 2 ) ) == NULL )
+    {
+       return;
+    }
+
+    /* For a string gadget, we expand the border beyond the area where
+     * the text will be entered.
+     */
+
+    /* Remove any special rendering flags to avoid confusing intuition
+     */
+
+    gd->Flags &= ~(GADGHIGHBITS|GADGIMAGE);
+
+    sp = (short *)(bp + 4);
+    if( gd->GadgetType == STRGADGET || ( gd->GadgetType == BOOLGADGET &&
+                           ( gd->Flags & GADGHIGHBITS ) == GADGHNONE ) )
+    {
+       sp[0] = -1;
+       sp[1] = gd->Height - 1;
+       sp[2] = -1;
+       sp[3] = -1;
+       sp[4] = gd->Width - 1;
+       sp[5] = -1;
+
+       sp[6] = gd->Width + 1;
+       sp[7] = -2;
+       sp[8] = gd->Width + 1;
+       sp[9] = gd->Height + 1;
+       sp[10] = -2;
+       sp[11] = gd->Height + 1;
+
+       sp[12] = -2;
+       sp[13] = gd->Height;
+       sp[14] = -2;
+       sp[15] = -2;
+       sp[16] = gd->Width;
+       sp[17] = -2;
+       sp[18] = gd->Width;
+       sp[19] = gd->Height;
+       sp[20] = -2;
+       sp[21] = gd->Height;
+
+       for( i = 0; i < 3; ++i )
+       {
+           bp[ i ].LeftEdge = bp[ i ].TopEdge = -1;
+           bp[ i ].FrontPen = ( i == 0 || i == 1 ) ? shadowpen : hipen;
+
+           /* Have to use JAM2 so that the old colors disappear. */
+           bp[ i ].BackPen = C_BLACK;
+           bp[ i ].DrawMode = JAM2;
+           bp[ i ].Count = ( i == 0 || i == 1 ) ? 3 : 5;
+           bp[ i ].XY = &sp[ i*6 ];
+           bp[ i ].NextBorder = ( i == 2 ) ? NULL : &bp[ i + 1 ];
+       }
+
+       /* bp[0] and bp[1] two pieces for the up image */
+       gd->GadgetRender = (APTR) bp;
+
+       /* No image change for select */
+       gd->SelectRender = (APTR) bp;
+
+       gd->LeftEdge++;
+       gd->TopEdge++;
+       gd->Flags |= GADGHCOMP;
+    }
+    else
+    {
+       /* Create the border vector values for up and left side, and
+        * also the lower and right side.
+        */
+
+       sp[0] = dec;
+       sp[1] = gd->Height + inc;
+       sp[2] = dec;
+       sp[3] = dec;
+       sp[4] = gd->Width + inc;
+       sp[5] = dec;
+
+       sp[6] = gd->Width + inc;
+       sp[7] = dec;
+       sp[8] = gd->Width + inc;
+       sp[9] = gd->Height + inc;
+       sp[10] = dec;
+       sp[11] = gd->Height + inc;
+
+       /* We are creating 4 sets of borders, the two sides of the
+        * rectangle share the border vectors with the opposite image,
+        * but specify different colors.
+        */
+
+       for( i = 0; i < 4; ++i )
+       {
+           bp[ i ].TopEdge = bp[ i ].LeftEdge = 0;
+
+           /* A GADGHNONE is always down */
+
+           if( gd->GadgetType == BOOLGADGET &&
+                           ( gd->Flags & GADGHIGHBITS ) != GADGHNONE )
+           {
+               bp[ i ].FrontPen =
+                           ( i == 1 || i == 2 ) ? shadowpen : hipen;
+           }
+           else
+           {
+               bp[ i ].FrontPen =
+                           ( i == 1 || i == 3 ) ? hipen : shadowpen;
+           }
+
+           /* Have to use JAM2 so that the old colors disappear. */
+           bp[ i ].BackPen = C_BLACK;
+           bp[ i ].DrawMode = JAM2;
+           bp[ i ].Count = 3;
+           bp[ i ].XY = &sp[ 6 * ((i &1) != 0) ];
+           bp[ i ].NextBorder =
+                           ( i == 1 || i == 3 ) ? NULL : &bp[ i + 1 ];
+       }
+
+       /* bp[0] and bp[1] two pieces for the up image */
+       gd->GadgetRender = (APTR) bp;
+
+       /* bp[2] and bp[3] two pieces for the down image */
+       gd->SelectRender = (APTR) (bp + 2);
+       gd->Flags |= GADGHIMAGE;
+    }
+}
+
+/* Following function copied from wintty.c */
+/* Modified slightly to fit amiga needs */
+
+void
+amii_player_selection()
+{
+       int i, k, n;
+       char pick4u = 'n', thisch, lastch = 0;
+       char pbuf[QBUFSZ], plbuf[QBUFSZ], rolenamebuf[QBUFSZ];
+       winid win;
+       anything any;
+       menu_item *selected = 0;
+
+       rigid_role_checks();
+
+       /* Should we randomly pick for the player? */
+       if (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE ||
+               flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE) {
+           char *prompt = build_plselection_prompt(pbuf, QBUFSZ, flags.initrole,
+                               flags.initrace, flags.initgend, flags.initalign);
+           pline("%s", prompt);
+           do {        /* loop until we get valid input */
+               cursor_on(WIN_MESSAGE);
+               pick4u = lowc(WindowGetchar());
+               cursor_off(WIN_MESSAGE);
+               if (index(quitchars, pick4u)) pick4u = 'y';
+           } while(!index(ynqchars, pick4u));
+           pbuf[0] = pick4u;
+           pbuf[1] = 0;
+           amii_addtopl(pbuf);
+
+           if (pick4u != 'y' && pick4u != 'n') {
+give_up:       /* Quit */
+               if (selected) free((genericptr_t) selected);
+               clearlocks();
+               exit_nhwindows(NULL);
+               terminate(0);
+               /*NOTREACHED*/
+               return;
+           }
+       }
+
+       (void) root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+
+       /* Select a role, if necessary */
+       /* we'll try to be compatible with pre-selected race/gender/alignment,
+        * but may not succeed */
+       if (flags.initrole < 0) {
+           /* Process the choice */
+           if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) {
+               /* Pick a random role */
+               flags.initrole = pick_role(flags.initrace, flags.initgend,
+                                               flags.initalign, PICK_RANDOM);
+               if (flags.initrole < 0) {
+                   amii_putstr(WIN_MESSAGE, 0, "Incompatible role!");
+                   flags.initrole = randrole();
+               }
+           } else {
+               /* Prompt for a role */
+               win = create_nhwindow(NHW_MENU);
+               start_menu(win);
+               any.a_void = 0;         /* zero out all bits */
+               for (i = 0; roles[i].name.m; i++) {
+                   if (ok_role(i, flags.initrace, flags.initgend,
+                                                       flags.initalign)) {
+                       any.a_int = i+1;        /* must be non-zero */
+                       thisch = lowc(roles[i].name.m[0]);
+                       if (thisch == lastch) thisch = highc(thisch);
+                       if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) {
+                               if (flags.initgend == 1  && roles[i].name.f)
+                                       Strcpy(rolenamebuf, roles[i].name.f);
+                               else
+                                       Strcpy(rolenamebuf, roles[i].name.m);
+                       } else {
+                               if (roles[i].name.f) {
+                                       Strcpy(rolenamebuf, roles[i].name.m);
+                                       Strcat(rolenamebuf, "/");
+                                       Strcat(rolenamebuf, roles[i].name.f);
+                               } else 
+                                       Strcpy(rolenamebuf, roles[i].name.m);
+                       }       
+                       add_menu(win, NO_GLYPH, &any, thisch,
+                           0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED);
+                       lastch = thisch;
+                   }
+               }
+               any.a_int = pick_role(flags.initrace, flags.initgend,
+                                   flags.initalign, PICK_RANDOM)+1;
+               if (any.a_int == 0)     /* must be non-zero */
+                   any.a_int = randrole()+1;
+               add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                               "Random", MENU_UNSELECTED);
+               any.a_int = i+1;        /* must be non-zero */
+               add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                               "Quit", MENU_UNSELECTED);
+               Sprintf(pbuf, "Pick a role for your %s", plbuf);
+               end_menu(win, pbuf);
+               n = select_menu(win, PICK_ONE, &selected);
+               destroy_nhwindow(win);
+
+               /* Process the choice */
+               if (n != 1 || selected[0].item.a_int == any.a_int)
+                   goto give_up;               /* Selected quit */
+
+               flags.initrole = selected[0].item.a_int - 1;
+               free((genericptr_t) selected),  selected = 0;
+           }
+           (void) root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+       }
+
+       /* Select a race, if necessary */
+       /* force compatibility with role, try for compatibility with
+        * pre-selected gender/alignment */
+       if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
+           /* pre-selected race not valid */
+           if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) {
+               flags.initrace = pick_race(flags.initrole, flags.initgend,
+                                                       flags.initalign, PICK_RANDOM);
+               if (flags.initrace < 0) {
+                   amii_putstr(WIN_MESSAGE, 0, "Incompatible race!");
+                   flags.initrace = randrace(flags.initrole);
+               }
+           } else {    /* pick4u == 'n' */
+               /* Count the number of valid races */
+               n = 0;  /* number valid */
+               k = 0;  /* valid race */
+               for (i = 0; races[i].noun; i++) {
+                   if (ok_race(flags.initrole, i, flags.initgend,
+                                                       flags.initalign)) {
+                       n++;
+                       k = i;
+                   }
+               }
+               if (n == 0) {
+                   for (i = 0; races[i].noun; i++) {
+                       if (validrace(flags.initrole, i)) {
+                           n++;
+                           k = i;
+                       }
+                   }
+               }
+
+               /* Permit the user to pick, if there is more than one */
+               if (n > 1) {
+                   win = create_nhwindow(NHW_MENU);
+                   start_menu(win);
+                   any.a_void = 0;         /* zero out all bits */
+                   for (i = 0; races[i].noun; i++)
+                       if (ok_race(flags.initrole, i, flags.initgend,
+                                                       flags.initalign)) {
+                           any.a_int = i+1;    /* must be non-zero */
+                           add_menu(win, NO_GLYPH, &any, races[i].noun[0],
+                               0, ATR_NONE, races[i].noun, MENU_UNSELECTED);
+                       }
+                   any.a_int = pick_race(flags.initrole, flags.initgend,
+                                       flags.initalign, PICK_RANDOM)+1;
+                   if (any.a_int == 0) /* must be non-zero */
+                       any.a_int = randrace(flags.initrole)+1;
+                   add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                   "Random", MENU_UNSELECTED);
+                   any.a_int = i+1;    /* must be non-zero */
+                   add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                   "Quit", MENU_UNSELECTED);
+                   Sprintf(pbuf, "Pick the race of your %s", plbuf);
+                   end_menu(win, pbuf);
+                   n = select_menu(win, PICK_ONE, &selected);
+                   destroy_nhwindow(win);
+                   if (n != 1 || selected[0].item.a_int == any.a_int)
+                       goto give_up;           /* Selected quit */
+
+                   k = selected[0].item.a_int - 1;
+                   free((genericptr_t) selected),      selected = 0;
+               }
+               flags.initrace = k;
+           }
+           (void) root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+       }
+
+       /* Select a gender, if necessary */
+       /* force compatibility with role/race, try for compatibility with
+        * pre-selected alignment */
+       if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
+                                               flags.initgend)) {
+           /* pre-selected gender not valid */
+           if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) {
+               flags.initgend = pick_gend(flags.initrole, flags.initrace,
+                                               flags.initalign, PICK_RANDOM);
+               if (flags.initgend < 0) {
+                   amii_putstr(WIN_MESSAGE, 0, "Incompatible gender!");
+                   flags.initgend = randgend(flags.initrole, flags.initrace);
+               }
+           } else {    /* pick4u == 'n' */
+               /* Count the number of valid genders */
+               n = 0;  /* number valid */
+               k = 0;  /* valid gender */
+               for (i = 0; i < ROLE_GENDERS; i++) {
+                   if (ok_gend(flags.initrole, flags.initrace, i,
+                                                       flags.initalign)) {
+                       n++;
+                       k = i;
+                   }
+               }
+               if (n == 0) {
+                   for (i = 0; i < ROLE_GENDERS; i++) {
+                       if (validgend(flags.initrole, flags.initrace, i)) {
+                           n++;
+                           k = i;
+                       }
+                   }
+               }
+
+               /* Permit the user to pick, if there is more than one */
+               if (n > 1) {
+                   win = create_nhwindow(NHW_MENU);
+                   start_menu(win);
+                   any.a_void = 0;         /* zero out all bits */
+                   for (i = 0; i < ROLE_GENDERS; i++)
+                       if (ok_gend(flags.initrole, flags.initrace, i,
+                                                           flags.initalign)) {
+                           any.a_int = i+1;
+                           add_menu(win, NO_GLYPH, &any, genders[i].adj[0],
+                               0, ATR_NONE, genders[i].adj, MENU_UNSELECTED);
+                       }
+                   any.a_int = pick_gend(flags.initrole, flags.initrace,
+                                           flags.initalign, PICK_RANDOM)+1;
+                   if (any.a_int == 0) /* must be non-zero */
+                       any.a_int = randgend(flags.initrole, flags.initrace)+1;
+                   add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                   "Random", MENU_UNSELECTED);
+                   any.a_int = i+1;    /* must be non-zero */
+                   add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                   "Quit", MENU_UNSELECTED);
+                   Sprintf(pbuf, "Pick the gender of your %s", plbuf);
+                   end_menu(win, pbuf);
+                   n = select_menu(win, PICK_ONE, &selected);
+                   destroy_nhwindow(win);
+                   if (n != 1 || selected[0].item.a_int == any.a_int)
+                       goto give_up;           /* Selected quit */
+
+                   k = selected[0].item.a_int - 1;
+                   free((genericptr_t) selected),      selected = 0;
+               }
+               flags.initgend = k;
+           }
+           (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+       }
+
+       /* Select an alignment, if necessary */
+       /* force compatibility with role/race/gender */
+       if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
+                                                       flags.initalign)) {
+           /* pre-selected alignment not valid */
+           if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) {
+               flags.initalign = pick_align(flags.initrole, flags.initrace,
+                                                       flags.initgend, PICK_RANDOM);
+               if (flags.initalign < 0) {
+                   amii_putstr(WIN_MESSAGE, 0, "Incompatible alignment!");
+                   flags.initalign = randalign(flags.initrole, flags.initrace);
+               }
+           } else {    /* pick4u == 'n' */
+               /* Count the number of valid alignments */
+               n = 0;  /* number valid */
+               k = 0;  /* valid alignment */
+               for (i = 0; i < ROLE_ALIGNS; i++) {
+                   if (ok_align(flags.initrole, flags.initrace, flags.initgend,
+                                                       i)) {
+                       n++;
+                       k = i;
+                   }
+               }
+               if (n == 0) {
+                   for (i = 0; i < ROLE_ALIGNS; i++) {
+                       if (validalign(flags.initrole, flags.initrace, i)) {
+                           n++;
+                           k = i;
+                       }
+                   }
+               }
+
+               /* Permit the user to pick, if there is more than one */
+               if (n > 1) {
+                   win = create_nhwindow(NHW_MENU);
+                   start_menu(win);
+                   any.a_void = 0;         /* zero out all bits */
+                   for (i = 0; i < ROLE_ALIGNS; i++)
+                       if (ok_align(flags.initrole, flags.initrace,
+                                                       flags.initgend, i)) {
+                           any.a_int = i+1;
+                           add_menu(win, NO_GLYPH, &any, aligns[i].adj[0],
+                                0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
+                       }
+                   any.a_int = pick_align(flags.initrole, flags.initrace,
+                                           flags.initgend, PICK_RANDOM)+1;
+                   if (any.a_int == 0) /* must be non-zero */
+                       any.a_int = randalign(flags.initrole, flags.initrace)+1;
+                   add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                   "Random", MENU_UNSELECTED);
+                   any.a_int = i+1;    /* must be non-zero */
+                   add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                   "Quit", MENU_UNSELECTED);
+                   Sprintf(pbuf, "Pick the alignment of your %s", plbuf);
+                   end_menu(win, pbuf);
+                   n = select_menu(win, PICK_ONE, &selected);
+                   destroy_nhwindow(win);
+                   if (n != 1 || selected[0].item.a_int == any.a_int)
+                       goto give_up;           /* Selected quit */
+
+                   k = selected[0].item.a_int - 1;
+                   free((genericptr_t) selected),      selected = 0;
+               }
+               flags.initalign = k;
+           }
+       }
+       /* Success! */
+}
+#endif /* AMIGA_INTUITION */
diff --git a/sys/amiga/winami.p b/sys/amiga/winami.p
new file mode 100644 (file)
index 0000000..b34f8e5
--- /dev/null
@@ -0,0 +1,57 @@
+/*    SCCS Id: @(#)winami.p    3.1 93/01/08                     */
+/*    Copyright (c) Gregg Wonderly, Naperville, IL, 1992, 1993  */
+/* NetHack may be freely redistributed. See license for details. */
+/* winami.c */
+void FDECL(amii_raw_print, (const char *));
+void FDECL(amii_raw_print_bold, (const char *));
+void FDECL(amii_start_menu, (winid ));
+void FDECL(amii_add_menu, (winid  , char  , int  , const char *));
+void FDECL(amii_end_menu, (winid  , char  , const char * , const char *));
+char FDECL(amii_select_menu, (winid ));
+void NDECL(amii_update_inventory );
+void NDECL(amii_mark_synch );
+void NDECL(amii_wait_synch );
+void NDECL(amii_setclipped );
+void FDECL(amii_cliparound, (int  , int ));
+void NDECL(amii_askname );
+void NDECL(amii_player_selection );
+void NDECL(flush_output );
+void FDECL(amii_destroy_nhwindow, (winid ));
+int FDECL(amii_create_nhwindow, (int ));
+void NDECL(amii_init_nhwindows );
+int NDECL(amii_get_ext_cmd);
+char FDECL(amii_yn_function, (const char * , const char * , char ));
+void FDECL(amii_addtopl, (const char *));
+void FDECL(TextSpaces, (struct RastPort * , int ));
+void FDECL(amii_putstr, (winid  , int  , const char *));
+void FDECL(amii_putsym, (winid  , int  , int  , CHAR_P ));
+void FDECL(amii_clear_nhwindow, (winid ));
+void FDECL(amii_exit_nhwindows, (const char *));
+int FDECL(amii_nh_poskey, (int * , int * , int *));
+int NDECL(amii_nhgetch );
+void NDECL(amii_get_nh_event );
+void NDECL(amii_remember_topl );
+int NDECL(amii_doprev_message );
+void FDECL(amii_display_nhwindow, (winid  , boolean ));
+void FDECL(amii_display_file, (const char * , boolean ));
+void FDECL(amii_curs, (winid  , int  , int ));
+void FDECL(amii_print_glyph, (winid  , xchar  , xchar  , int ));
+void FDECL(DoMenuScroll, (int  , int ));
+void FDECL(DisplayData, (int  , int  , int ));
+void FDECL(SetPropInfo, (struct Window * , struct Gadget * , long  , long  , long ));
+void FDECL(kill_nhwindows, (int ));
+void FDECL(amii_cl_end, (struct amii_WinDesc * , int ));
+void FDECL(cursor_off, (winid ));
+void FDECL(cursor_on, (winid ));
+void NDECL(amii_getret );
+void FDECL(amii_getlin, (const char * , char *));
+void FDECL(getlind, (const char * , char * , const char *));
+void FDECL(amii_suspend_nhwindows, (char * ));
+void NDECL(amii_resume_nhwindows);
+void NDECL(amii_bell);
+void NDECL(EditColor);
+void FDECL(DrawCol, ( struct Window *, int, UWORD * ) );
+void FDECL( DispCol, ( struct Window *w, int idx, UWORD * ) );
+void FDECL( SetBorder, (struct Gadget *) );
+void NDECL( port_help );
+void FDECL( dismiss_nhwindow, (winid) );
diff --git a/sys/amiga/winchar.c b/sys/amiga/winchar.c
new file mode 100644 (file)
index 0000000..2f6e721
--- /dev/null
@@ -0,0 +1,1246 @@
+/*    SCCS Id: @(#)winchar.c     3.1    93/07/22                       */
+/*    Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992         */
+/*    Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993      */
+/*    Copyright (c) Gregg Wonderly, Naperville Illinois, 1994.         */
+/*    NetHack may be freely redistributed.  See license for details.   */
+
+#include <exec/types.h>
+#include <libraries/iffparse.h>
+#include <graphics/scale.h>
+#ifndef _DCC
+#include <proto/iffparse.h>
+#endif
+
+#ifdef TESTING
+# include "hack.h"
+#else
+# include "NH:src/tile.c"
+#endif
+
+#include "NH:win/share/tile.h"
+
+#include "NH:sys/amiga/windefs.h"
+#include "NH:sys/amiga/winext.h"
+#include "NH:sys/amiga/winproto.h"
+
+#ifdef OPT_DISPMAP
+# define DISPMAP               /* use display_map() from dispmap.s */
+#endif
+
+/* NH:sys/amiga/winvchar.c */
+int main ( int  , char ** );
+struct BitMap *MyAllocBitMap ( int  , int  , int  , long  );
+void MyFreeBitMap ( struct BitMap * );
+void FreeImageFiles ( char **, struct BitMap ** );
+void amiv_flush_glyph_buffer ( struct Window * );
+void amiv_lprint_glyph ( winid  , int  , int  );
+void amii_lprint_glyph ( winid  , int  , int  );
+void amiv_start_glyphout ( winid  );
+void amii_end_glyphout ( winid  );
+void SetMazeType ( MazeType  );
+int GlyphToIcon ( int  );
+void amii_start_glyphout ( winid  );
+void amii_end_glyphout ( winid  );
+void amii_flush_glyph_buffer( struct Window * );
+
+int amii_extraplanes = 0;
+extern int reclip;
+
+struct BitMap *MyAllocBitMap( int xsize, int ysize, int depth, long mflags );
+void MyFreeBitMap( struct BitMap *bmp );
+
+#ifdef DISPMAP
+extern void display_map( struct Window * );
+#endif
+
+/*
+ *  These values will be available from tile.c source
+ *
+ * #define MAXMONTILE 335
+ * #define MAXOBJTILE 722
+ * #define MAXOTHTILE 841
+ */
+
+#define        IMGROWS         12
+#define IMGCOLUMNS     20
+#define IMGPAGESIZE    (IMGROWS*IMGCOLUMNS)
+
+#define ID_BMAP                MAKE_ID('B','M','A','P')        /* The type of form we use */
+#define ID_BMHD                MAKE_ID('B','M','H','D')        /* The ILBM bitmap header */
+#define ID_CAMG                MAKE_ID('C','A','M','G')        /* The ILBM camg (ignored) */
+#define ID_CMAP                MAKE_ID('C','M','A','P')        /* Standard ILBM color map */
+#define ID_PLNE                MAKE_ID('P','L','N','E')        /* The plane data */
+#define ID_PDAT                MAKE_ID('P','D','A','T')        /* The PDAT structure below */
+
+struct PDAT pictdata;
+
+#define NUMTILEIMAGES  3
+char *tileimages[] =
+{
+#define TBLMONTILE     0
+       "NetHack:tiles/monsters.iff",
+#define TBLOBJTILE     1
+       "NetHack:tiles/objects.iff",
+#define TBLOTHTILE     2
+       "NetHack:tiles/other.iff",
+       0,
+};
+
+struct BitMap *ifftimg[ NUMTILEIMAGES ], *tile;
+
+#ifdef TESTING
+short pens[NUMDRIPENS] = { 8, 3, 15, 0, 15, 7, 7, 8, 0 };
+main( int argc, char **argv )
+{
+    BitMapHeader bmhd;
+    struct IntuiMessage *imsg;
+    long code, class;
+    char buf[100];
+    int i, x, y, tbl, done = 0, num;
+    struct Window *w;
+    struct Screen *scr;
+
+    bmhd = ReadTileImageFiles( );
+
+    scr = OpenScreenTags( NULL,
+       SA_Depth, pictdata.nplanes + amii_extraplanes,
+       SA_DisplayID, DBLNTSC_MONITOR_ID|HIRESLACE_KEY,
+       SA_Overscan, OSCAN_TEXT,
+       SA_Top, 0,
+       SA_Left, 0,
+       SA_Width, STDSCREENWIDTH,
+       SA_Height, STDSCREENHEIGHT,
+       SA_Type, CUSTOMSCREEN,
+       SA_DetailPen, 0,
+       SA_BlockPen, 1,
+       SA_Title, "NetHack Chars",
+       SA_Pens, pens,
+       TAG_DONE
+       );
+    if( scr == NULL )
+    {
+       printf( "no screen\n" );
+#undef exit
+       exit( 1 );
+    }
+
+    w = OpenWindowTags( 0,
+               WA_CustomScreen, scr,
+               WA_Flags, WFLG_DRAGBAR|WFLG_SIZEGADGET|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET,
+               WA_IDCMP, IDCMP_CLOSEWINDOW|IDCMP_NEWSIZE|IDCMP_MOUSEBUTTONS,
+               WA_Left, 0, 
+               WA_Top, scr->WBorTop + 1 + 13, 
+               WA_MinWidth, 100,
+               WA_MinHeight, 100,
+               WA_MaxWidth, 700,
+               WA_MaxHeight, 1000,
+               WA_Width, 640, 
+               WA_Height, 340, 
+               WA_SmartRefresh, TRUE,
+               TAG_DONE );
+    if( w )
+    {
+       while( !done )
+       {
+           for( i = 0; i < NUMTILEIMAGES * IMGPAGESIZE; ++i )
+           {
+               int dx, dy;
+               tbl = i/IMGPAGESIZE;
+               x = i % IMGPAGESIZE;
+               y = x / IMGCOLUMNS;
+               x = x % IMGCOLUMNS;
+               dx = i % (IMGCOLUMNS*2);
+               dy = i / (IMGCOLUMNS*2);
+               BltBitMapRastPort( ifftimg[ tbl ],
+                               x * pictdata.xsize, y * pictdata.ysize,
+                               w->RPort,
+                               w->BorderLeft + 1 + dx*pictdata.xsize,
+                               w->BorderTop + 1 + dy*pictdata.ysize,
+                               pictdata.xsize, pictdata.ysize, 0xc0 );
+           }
+           WaitPort( w->UserPort );
+           while( imsg = (struct IntuiMessage *)GetMsg( w->UserPort ) )
+           {
+               class = imsg->Class;
+               code = imsg->Code;
+               ReplyMsg( (struct Message *)imsg );
+               switch( class )
+               {
+               case IDCMP_MOUSEBUTTONS:
+                   {
+                       x = imsg->MouseX - w->BorderLeft;
+                       y = imsg->MouseY - w->BorderTop;
+                       num = ((y/pictdata.ysize)*IMGCOLUMNS*2)+(x/pictdata.xsize);
+                       sprintf( buf, "Char #%d", num );
+                       SetWindowTitles( w, buf, buf );
+                   }
+                   break;
+               case IDCMP_CLOSEWINDOW:
+                   done = 1;
+                   break;
+               }
+           }
+       }
+       CloseWindow( w );
+       CloseScreen( scr );
+    }
+
+    FreeImageFiles(tileimages, ifftimg );
+
+    return(0);
+}
+#endif
+
+BitMapHeader
+ReadTileImageFiles(){
+    char *errstr = NULL;
+    BitMapHeader ret = ReadImageFiles(tileimages, ifftimg, &errstr);
+    if(errstr){
+       panic(errstr);
+    }
+    return ret;
+}
+
+BitMapHeader
+ReadImageFiles(char **filenames, struct BitMap **iffimg, char **errstrp )
+{
+    BitMapHeader *bmhd = NULL, bmhds;
+    unsigned char *cmap;
+    extern int errno;
+    register int i, j;
+    struct IFFHandle *iff;
+    struct StoredProperty *prop;
+
+    IFFParseBase = OpenLibrary( "iffparse.library", 0L );
+    if( !IFFParseBase )
+    {
+       *errstrp = "No iffparse.library";
+       return bmhds;
+    }
+
+/*
+    for( i = 0; filenames[i]; ++i )
+       memset( iffimg[i], 0, sizeof( struct BitMap ) );
+*/
+    for( i = 0; filenames[i]; ++i )
+    {
+       iff = AllocIFF();
+       if( !iff )
+       {
+           FreeImageFiles(filenames, iffimg );
+           *errstrp = "can't start IFF processing";
+           return bmhds;
+       }
+       iff->iff_Stream = Open( filenames[i], MODE_OLDFILE );
+       if( iff->iff_Stream == 0 )
+       {
+           char *buf = malloc(100+strlen(filenames[i]));
+           FreeImageFiles( filenames, iffimg );
+           sprintf(buf, "Can't open %s: %s", filenames[i], strerror( errno ));
+           *errstrp = buf;
+           return bmhds;
+       }
+       InitIFFasDOS( iff );
+       OpenIFF( iff, IFFF_READ );
+       PropChunk( iff, ID_BMAP, ID_BMHD );
+       PropChunk( iff, ID_BMAP, ID_CMAP );
+       PropChunk( iff, ID_BMAP, ID_CAMG );
+       PropChunk( iff, ID_BMAP, ID_PDAT );
+       StopChunk( iff, ID_BMAP, ID_PLNE );
+       if( ( j = ParseIFF( iff, IFFPARSE_SCAN ) ) != 0 )
+       {
+           char *buf = malloc(100);
+           FreeImageFiles( filenames, iffimg );
+           sprintf(buf,"ParseIFF failed for image %d, failure code: %d",i,j);
+           *errstrp = buf;
+           return bmhds;
+       }
+
+       if( prop = FindProp( iff, ID_BMAP, ID_BMHD ) )
+       {
+           bmhd = (BitMapHeader *)prop->sp_Data;
+       }
+       else
+       {
+           FreeImageFiles(filenames, iffimg);
+           CloseIFF( iff );
+           Close( iff->iff_Stream );
+           FreeIFF( iff );
+           *errstrp = "No BMHD CHUNK in file";
+           return bmhds;
+       }
+
+       if( prop = FindProp( iff, ID_BMAP, ID_CMAP ) )
+       {
+           cmap = prop->sp_Data;
+           for( j = 0; j < (1L << bmhd->nPlanes)*3; j+=3 )
+           {
+#if 0
+               /* Some day we will want to use the larger palette
+                * resolution available under v39 and later.  i.e.
+                * 32 instead of 12 bits of color.  Ususally this
+                * just means shifting the color left by 16-20 bits
+                * depending on what intensity looks best.  Experience
+                * says that the higher values are better intensities.
+                *
+                * For now though we won't do this. The color table
+                * structure is incompatible with earlier versions of
+                * intuition.  We would have to do some funny things
+                * to make 3*AMII_MAXCOLORS longs work like 3*AMII_MAXCOLORS
+                * UWORD's at run time...  A union would help, but...
+                */
+               if( IntuitionBase->LibNode.lib_Version >= 39 )
+               {
+                   /* 8 bits of color, so shift to left end. */
+                   amiv_init_map[ j+0 ] = cmap[j+0]<<24;
+                   amiv_init_map[ j+1 ] = cmap[j+1]<<24;
+                   amiv_init_map[ j+2 ] = cmap[j+2]<<24;
+               }
+               else
+#endif
+               {
+                   /* We can only use 4 bits of the 8 that are stored in the
+                    * cmap, so mask them and then shift them into position
+                    * for the UWORD value to store.
+                    */
+#ifndef TESTING
+                   amii_initmap[ j/3 ] = 
+                   amiv_init_map[ j/3 ] =
+                                       ((cmap[j+0]>>4)<<8)|
+                                       ((cmap[j+1]>>4)<<4)|
+                                       (cmap[j+2]>>4);
+#endif
+               }
+           }
+       }
+       else
+       {
+           FreeImageFiles(filenames, iffimg);
+           CloseIFF( iff );
+           Close( iff->iff_Stream );
+           FreeIFF( iff );
+           *errstrp = "No CMAP CHUNK in file";
+           return bmhds;
+       }
+
+       if( prop = FindProp( iff, ID_BMAP, ID_PDAT ) )
+       {
+           struct PDAT *pp;
+
+           pp = (struct PDAT *)prop->sp_Data;
+           pictdata = *pp;
+       }
+       else
+       {
+           FreeImageFiles(filenames, iffimg);
+           CloseIFF( iff );
+           Close( iff->iff_Stream );
+           FreeIFF( iff );
+           *errstrp = "No PDAT CHUNK in file";
+           return bmhds;
+       }
+
+       iffimg[ i ] = MyAllocBitMap( bmhd->w, bmhd->h,
+               pictdata.nplanes + amii_extraplanes, MEMF_CHIP|MEMF_CLEAR );
+       if( iffimg[ i ] == NULL )
+       {
+           char *buf = malloc(80);
+           FreeImageFiles(filenames, iffimg);
+           sprintf(buf, "Can't allocate bitmap for image %d\n", i );
+           *errstrp = buf;
+           return bmhds;
+       }
+       for( j = 0; j < pictdata.nplanes + amii_extraplanes; ++j )
+       {
+           ReadChunkBytes( iff, iffimg[i]->Planes[j], RASSIZE( bmhd->w, bmhd->h ) );
+       }
+       bmhds = *bmhd;
+       CloseIFF( iff );
+       Close( iff->iff_Stream );
+       FreeIFF( iff );
+    }
+    CloseLibrary( IFFParseBase );
+
+    tile = MyAllocBitMap( pictdata.xsize, pictdata.ysize,
+           pictdata.nplanes + amii_extraplanes, MEMF_CHIP|MEMF_CLEAR );
+    if( tile == NULL )
+    {
+       FreeImageFiles(filenames, iffimg);
+       *errstrp = "Can't allocate tile bitmap for scaling";
+    }
+    return( bmhds );
+}
+
+struct MyBitMap
+{
+       struct BitMap bm;
+       long mflags;
+       USHORT xsize, ysize;
+};
+
+struct BitMap *
+MyAllocBitMap( int xsize, int ysize, int depth, long mflags )
+{
+    int j;
+    struct MyBitMap *bm;
+
+    bm = (struct MyBitMap *)alloc( sizeof( *bm ) );
+    if( !bm )
+       return( NULL );
+
+    bm->xsize = xsize;
+    bm->ysize = ysize;
+    InitBitMap( &bm->bm, depth, xsize, ysize );
+    for( j = 0; j < depth; ++j )
+    {
+       if( mflags & MEMF_CHIP )
+           bm->bm.Planes[ j ] = AllocRaster( xsize, ysize );
+       else
+           bm->bm.Planes[ j ] = AllocMem( RASSIZE( xsize, ysize ), mflags );
+
+       if( bm->bm.Planes[ j ] == 0 )
+       {
+           MyFreeBitMap( &bm->bm );
+           return( NULL );
+       }
+       if( mflags & MEMF_CLEAR )
+           memset( bm->bm.Planes[ j ], 0, RASSIZE( xsize, ysize ) );
+    }
+    return( &bm->bm );
+}
+
+void
+MyFreeBitMap( struct BitMap *bmp )
+{
+    int j;
+    struct MyBitMap *bm = (struct MyBitMap *)bmp;
+
+    for( j = 0; j < bm->bm.Depth; ++j )
+    {
+       if( bm->bm.Planes[j] )
+       {
+           if( bm->mflags & MEMF_CHIP )
+               FreeRaster( bm->bm.Planes[j], bm->xsize, bm->ysize );
+           else
+               FreeMem( bm->bm.Planes[j], RASSIZE( bm->xsize, bm->ysize ) );
+       }
+    }
+    free( bm );
+}
+
+#ifdef TESTING
+void
+panic(s,a1,a2,a3,a4)
+       char *s;
+{
+    printf( s, a1, a2, a3, a4 );
+    putchar('\n');
+}
+long *
+alloc(unsigned int x){
+       long *p = (long *)malloc(x);
+       if(!p){panic("malloc failed"); exit(1);}
+       return p;
+}
+#endif
+
+void
+FreeTileImageFiles(){
+       FreeImageFiles(tileimages,ifftimg);
+}
+
+void
+FreeImageFiles(char **filenames, struct BitMap **img )
+{
+    register int i;
+
+    for( i = 0; filenames[i]; ++i )
+    {
+       if( img[ i ] )
+           MyFreeBitMap( img[ i ] );
+    }
+
+       /* REALLY ugly hack alert! */
+    if( tile && img==ifftimg)
+       MyFreeBitMap( tile );
+}
+
+#ifndef TESTING
+/*
+ * Define some stuff for our special glyph drawing routines
+ */
+unsigned short glyph_node_index, glyph_buffer_index;
+#define NUMBER_GLYPH_NODES  80
+#define GLYPH_BUFFER_SIZE   512
+struct amiv_glyph_node {
+    short      odstx, odsty;
+    short      srcx, srcy, dstx, dsty;
+    struct BitMap      *bitmap;
+};
+struct amiv_glyph_node amiv_g_nodes[NUMBER_GLYPH_NODES];
+static char amiv_glyph_buffer[GLYPH_BUFFER_SIZE];
+
+void
+flush_glyph_buffer( vw )
+    struct Window *vw;
+{
+    if( WINVERS_AMIV )
+       amiv_flush_glyph_buffer ( vw );
+    else
+       amii_flush_glyph_buffer ( vw );
+}
+
+/*
+ * Routine to flush whatever is buffered
+ */
+void
+amiv_flush_glyph_buffer( vw )
+    struct Window *vw;
+{
+#if !defined(DISPMAP) || defined(OPT_DISPMAP)
+    int xsize, ysize, x, y;
+    struct BitScaleArgs bsa;
+    struct BitScaleArgs bsm;
+    struct RastPort rast;
+    struct Window *w = NULL;
+    struct BitMap *imgbm = 0, *bm = 0;
+    int i, k;
+    int scaling_needed;
+    register struct RastPort *rp = vw->RPort;
+#endif
+
+    /* If nothing is buffered, return before we do anything */
+    if(glyph_node_index == 0)
+       return;
+
+    cursor_off( WIN_MAP );
+    amiv_start_glyphout( WIN_MAP );
+
+#ifdef OPT_DISPMAP
+    if(flags.fast_map){
+#endif
+#ifdef DISPMAP
+       display_map( vw );
+#endif
+#ifdef OPT_DISPMAP
+    } else {
+#endif
+#if !defined(DISPMAP) || defined(OPT_DISPMAP)
+/* XXX fix indent */
+    /* This is a dynamic value based on this relationship. */
+    scaling_needed = ( pictdata.xsize != mxsize || pictdata.ysize != mysize );
+
+    /* If overview window is up, set up to render the correct scale there */
+    if( WIN_OVER != WIN_ERR && ( w = amii_wins[ WIN_OVER ]->win ) != NULL )
+    {
+       InitRastPort( &rast );
+
+       /* Calculate the x and y size of each tile for a ROWNO by COLNO map */
+       xsize = (w->Width - w->BorderLeft - w->BorderRight) / COLNO;
+       ysize = (w->Height - w->BorderTop - w->BorderBottom) / ROWNO;
+
+       /* Get a chip memory bitmap to blit out of */
+       bm = MyAllocBitMap( pictdata.xsize, pictdata.ysize,
+           pictdata.nplanes + amii_extraplanes, MEMF_CLEAR|MEMF_CHIP );
+       if( bm == NULL )
+       {
+           amii_putstr( WIN_MESSAGE, 0, "Can't allocate bitmap for scaling overview window" );
+       }
+
+       rast.BitMap = bm;
+
+       memset( &bsa, 0, sizeof( bsa ) );
+       bsa.bsa_SrcX = bsa.bsa_SrcY = 0;
+       bsa.bsa_SrcBitMap = tile;
+       bsa.bsa_SrcWidth = pictdata.xsize;
+       bsa.bsa_SrcHeight = pictdata.ysize;
+       bsa.bsa_XSrcFactor = pictdata.xsize;
+       bsa.bsa_YSrcFactor = pictdata.ysize;
+       bsa.bsa_DestX = 0;
+       bsa.bsa_DestY = 0;
+       bsa.bsa_DestWidth = xsize;
+       bsa.bsa_DestHeight = ysize;
+       bsa.bsa_XDestFactor = xsize;
+       bsa.bsa_YDestFactor = ysize;
+       bsa.bsa_DestBitMap = bm;
+    }
+
+    if( scaling_needed )
+    {
+       /* Fill in scaling data for map rendering */
+       memset( &bsm, 0, sizeof( bsm ) );
+       bsm.bsa_SrcX = bsm.bsa_SrcY = 0;
+       bsm.bsa_SrcBitMap = tile;
+
+       bsm.bsa_SrcWidth = pictdata.xsize;
+       bsm.bsa_SrcHeight = pictdata.ysize;
+
+       bsm.bsa_XSrcFactor = pictdata.xsize;
+       bsm.bsa_YSrcFactor = pictdata.ysize;
+
+       bsm.bsa_DestWidth = mxsize;
+       bsm.bsa_DestHeight = mysize;
+
+       bsm.bsa_XDestFactor = mxsize;
+       bsm.bsa_YDestFactor = mysize;
+       bsm.bsa_DestBitMap = rp->BitMap;
+       bsm.bsa_DestY = bsm.bsa_DestX = 0;
+
+       imgbm = MyAllocBitMap( mxsize, mysize,
+           pictdata.nplanes + amii_extraplanes, MEMF_CLEAR|MEMF_CHIP );
+       if( imgbm == NULL )
+       {
+           amii_putstr( WIN_MESSAGE, 0,
+               "Can't allocate scaling bitmap for map window" );
+       }
+       else
+           bsm.bsa_DestBitMap = imgbm;
+    }
+
+    /* Go ahead and start dumping the stuff */
+    for( i=0; i<glyph_node_index; ++i )
+    {
+       /* Do it */
+       register int offx, offy, j;
+       struct BitMap *nodebm = amiv_g_nodes[ i ].bitmap;
+
+       /* Get the unclipped coordinates */
+       x = amiv_g_nodes[ i ].odstx;
+       y = amiv_g_nodes[ i ].odsty;
+
+       /* If image is not in CHIP. copy each plane into tile line by line */
+
+       offx = amiv_g_nodes[ i ].srcx / 8;      /* 8 is bits per byte */
+       offy = amiv_g_nodes[ i ].srcy * nodebm->BytesPerRow;
+       for( j = 0; j < pictdata.nplanes + amii_extraplanes; ++j )
+       {
+           for( k = 0; k < pictdata.ysize; ++k )
+           {
+
+               /* For a 16x16 tile, this could just be short assignments, but
+                * this code is generalized to handle any size tile image...
+                */
+               memcpy( tile->Planes[ j ] + ( ( k * pictdata.ysize ) / 8 ),
+                       nodebm->Planes[ j ] + offx + offy + ( nodebm->BytesPerRow * k ),
+                       pictdata.ysize/8 );
+           }
+       }
+
+       if( !clipping ||
+               ( x >= clipx    && y >= clipy &&
+                 x <  clipxmax && y <  clipymax ) )
+       {
+           /* scaling is needed, do it */
+           if( scaling_needed )
+           {
+               BitMapScale( &bsm );
+               BltBitMapRastPort( imgbm, 0, 0,
+                   rp, amiv_g_nodes[ i ].dstx, amiv_g_nodes[ i ].dsty,
+                   mxsize, mysize, 0xc0 );
+           }
+           else
+           {
+               BltBitMapRastPort( tile, 0, 0,
+                   rp, amiv_g_nodes[ i ].dstx, amiv_g_nodes[ i ].dsty,
+                   pictdata.xsize, pictdata.ysize, 0xc0 );
+           }
+       }
+       /* Draw the overview window unless we are scrolling the map raster around */
+       if( bm && w && reclip != 2 )
+       {
+           BitMapScale( &bsa );
+           BltBitMapRastPort( rast.BitMap, 0, 0,
+                   w->RPort,
+                   w->BorderLeft + amiv_g_nodes[ i ].odstx*xsize,
+                   w->BorderTop + amiv_g_nodes[ i ].odsty*ysize,
+                   xsize, ysize, 0xc0 );
+       }
+    }
+
+    if( imgbm ) MyFreeBitMap( imgbm );
+    if( bm ) MyFreeBitMap( bm );
+#endif /* DISPMAP */
+#ifdef OPT_DISPMAP
+    }
+#endif
+
+    amii_end_glyphout( WIN_MAP );
+
+    /* Clean up */
+    glyph_node_index = glyph_buffer_index = 0;
+}
+
+/*
+ * Glyph buffering routine.  Called instead of WindowPuts().
+ */
+void
+amiv_lprint_glyph(window,color_index, glyph)
+    winid window;
+    int color_index, glyph;
+{
+    int base;
+    struct amii_WinDesc *cw;
+    struct Window *w;
+    int curx;
+    int cury;
+    int tbl, icon;
+    register int xoff, yoff;
+
+    /* Get the real icon index */
+    if( glyph != NO_GLYPH )
+       icon = GlyphToIcon( glyph );
+
+    if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
+       panic("bad winid in amiv_lprint_glyph: %d", window );
+
+    w = cw->win;
+
+    if( glyph != NO_GLYPH && glyph < 10000)
+    {
+       /* decide on which image has the needed picture */
+       if( icon <= MAXMONTILE )
+       {
+           tbl = TBLMONTILE;
+           base = 0;
+       }
+       else if( icon <= MAXOBJTILE )
+       {
+           tbl = TBLOBJTILE;
+           base = MAXMONTILE+1;
+       }
+       else if( icon <= MAXOTHTILE )
+       {
+           tbl = TBLOTHTILE;
+           base = MAXOBJTILE+1;
+       }
+       else
+           panic( "Bad icon #%d, glyph #%d, only %d icons known\n", icon, glyph, MAXOTHTILE );
+
+       /* Get the relative offset in the page */
+
+       /* How many pixels to account for y distance down */
+       yoff = ((icon-base) / pictdata.across) * pictdata.ysize;
+
+       /* How many pixels to account for x distance across */
+       xoff = ((icon-base) % pictdata.across) * pictdata.xsize;
+    }
+
+    if(glyph >= 10000){
+       /* Run a single ASCII character out to the rastport right now */
+       char c= glyph-10000;
+       int xxx,xxy;
+       struct RastPort *rp = w->RPort;
+
+       Move(rp, xxx=(((cw->curx-clipx)*rp->TxWidth) + w->BorderLeft),
+         xxy=(w->BorderTop + (((cw->cury-clipy)+1)* rp->TxHeight)+1));
+       Text(rp,&c,1);
+               /* XXX this shouldn't be necessary: */
+       if(cw->cursx == xxx && cw->cursy == xxy){
+           cw->wflags &= ~FLMAP_CURSUP;
+       }
+       cw->curx += rp->TxWidth;        /* keep things in sync */
+       return;
+    }
+    
+    if( cw->type == NHW_MAP )
+    {
+       curx = cw->curx - clipx;
+       cury = cw->cury - clipy;
+
+       /* See if we're out of glyph nodes */
+       if(glyph_node_index >= NUMBER_GLYPH_NODES)
+           amiv_flush_glyph_buffer( w );
+
+       /* Fill in the node. */
+       amiv_g_nodes[glyph_node_index].dsty = min( w->BorderTop + (cury * mysize),
+                                               w->Height - 1 );
+
+#ifdef OPT_DISPMAP
+       if(flags.fast_map){
+#endif /* keni */
+#ifdef DISPMAP
+       /* display_map() needs byte-aligned destinations, and we don't want to
+        * overwrite the window border.
+        */
+       amiv_g_nodes[glyph_node_index].dstx =
+                               (w->BorderLeft + 8 + (curx * mxsize)) & -8;
+#endif
+#ifdef OPT_DISPMAP
+} else {
+#endif
+#if !defined(DISPMAP) || defined(OPT_DISPMAP)
+       amiv_g_nodes[glyph_node_index].dstx = min( w->BorderLeft + (curx * mxsize),
+                                               w->Width - 1 );
+#endif
+#ifdef OPT_DISPMAP
+}
+#endif
+       amiv_g_nodes[glyph_node_index].odsty = cw->cury;
+       amiv_g_nodes[glyph_node_index].odstx = cw->curx;
+       amiv_g_nodes[glyph_node_index].srcx = xoff;
+       amiv_g_nodes[glyph_node_index].srcy = yoff;
+       amiv_g_nodes[glyph_node_index].bitmap = ifftimg[ tbl ];
+       ++glyph_node_index;
+    }
+    else
+    {
+       /* Do it */
+       register int j, k, x, y, apen;
+       struct RastPort *rp = w->RPort;
+       x = rp->cp_x - pictdata.xsize - 3;
+#ifdef OPT_DISPMAP
+       if(flags.fast_map){
+#endif
+#ifdef DISPMAP
+               x &= -8;
+               if(x==0) x = 8;
+#endif
+#ifdef OPT_DISPMAP
+       }
+#endif
+
+       y = rp->cp_y - pictdata.ysize + 1;
+
+       if( glyph != NO_GLYPH )
+       {
+           struct BitMap *bm = ifftimg[ tbl ];
+
+           /* 8 bits per byte */
+           xoff /= 8;
+           yoff *= bm->BytesPerRow;
+           for( j = 0; j < pictdata.nplanes; ++j )
+           {
+               for( k = 0; k < pictdata.ysize; ++k )
+               {
+                   memcpy( tile->Planes[ j ] + ( ( k * pictdata.ysize ) / 8 ),
+                           bm->Planes[ j ] + xoff + yoff + ( bm->BytesPerRow * k ),
+                           pictdata.ysize/8 );
+               }
+           }
+
+           BltBitMapRastPort( tile, 0, 0,
+               rp, x, y,
+               pictdata.xsize, pictdata.ysize, 0xc0 );
+
+           apen = rp->FgPen;
+           SetAPen( rp, flags.amii_dripens[ SHINEPEN ] );
+           Move( rp, x-1, y + pictdata.ysize );
+           Draw( rp, x-1, y - 1 );
+           Draw( rp, x + pictdata.xsize, y - 1 );
+           SetAPen( rp, flags.amii_dripens[ SHADOWPEN ] );
+           Move( rp, x + pictdata.xsize, y );
+           Draw( rp, x + pictdata.xsize, y + pictdata.ysize );
+           Draw( rp, x, y + pictdata.ysize );
+           SetAPen( rp, apen );
+       }
+       else if( x > w->BorderLeft )
+       {
+           int apen, bpen;
+           apen = rp->FgPen;
+           bpen = rp->BgPen;
+           SetAPen( rp, amii_menuBPen );
+           SetBPen( rp, amii_menuBPen );
+           RectFill( rp, x-1, y-1, x + pictdata.xsize, y + pictdata.ysize );
+           SetAPen( rp, apen );
+           SetBPen( rp, bpen );
+       }
+    }
+}
+
+/*
+ * Define some variables which will be used to save context when toggling
+ * back and forth between low level text and console I/O.
+ */
+static long xsave, ysave, modesave, apensave, bpensave;
+static int usecolor;
+
+/*
+ * The function is called before any glyphs are driven to the screen.  It
+ * removes the cursor, saves internal state of the window, then returns.
+ */
+
+void
+amiv_start_glyphout(window)
+    winid window;
+{
+    struct amii_WinDesc *cw;
+    struct Window *w;
+
+    if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
+       panic( "bad winid %d in start_glyphout()", window );
+
+    if( cw->wflags & FLMAP_INGLYPH )
+       return;
+
+    if( !(w = cw->win ) )
+       panic( "bad winid %d, no window ptr set", window );
+
+    /*
+     * Save the context of the window
+     */
+    xsave = w->RPort->cp_x;
+    ysave = w->RPort->cp_y;
+    modesave = w->RPort->DrawMode;
+    apensave = w->RPort->FgPen;
+    bpensave = w->RPort->BgPen;
+
+    /*
+     * Set the mode, and be done with it
+     */
+    usecolor = iflags.use_color;
+    iflags.use_color = FALSE;
+    cw->wflags |= FLMAP_INGLYPH;
+}
+
+/*
+ * General cleanup routine -- flushes and restores cursor
+ */
+void
+amii_end_glyphout(window)
+    winid window;
+{
+    struct amii_WinDesc *cw;
+    struct Window *w;
+
+    if( ( cw = amii_wins[ window ] ) == (struct amii_WinDesc *)NULL )
+       panic("bad window id %d in amii_end_glyphout()", window );
+
+    if( ( cw->wflags & FLMAP_INGLYPH ) == 0 )
+       return;
+    cw->wflags &= ~(FLMAP_INGLYPH);
+
+    if( !(w = cw->win ) )
+       panic( "bad winid %d, no window ptr set", window );
+
+    /*
+     * Clean up whatever is left in the buffer
+     */
+    iflags.use_color = usecolor;
+
+    /*
+     * Reset internal data structs
+     */
+    SetAPen(w->RPort, apensave);
+    SetBPen(w->RPort, bpensave);
+    SetDrMd(w->RPort, modesave);
+
+    Move(w->RPort, xsave, ysave);
+}
+
+static maze_type=COL_MAZE_BRICK;
+
+void SetMazeType(MazeType t)
+{
+    maze_type=t;
+}
+
+int GlyphToIcon(int glyph)
+{
+    if(glyph>10000)return glyph;
+    return( glyph2tile[glyph] );
+}
+#endif
+
+#ifdef AMII_GRAPHICS
+# ifdef TESTING
+/*
+ * Define some stuff for our special glyph drawing routines
+ */
+static unsigned short glyph_node_index, glyph_buffer_index;
+#  define NUMBER_GLYPH_NODES  80
+#  define GLYPH_BUFFER_SIZE   512
+# endif /* TESTING */
+
+struct amii_glyph_node {
+    short      x;
+    short      y;
+    short      len;
+    unsigned char   bg_color;
+    unsigned char   fg_color;
+    char       *buffer;
+};
+static struct amii_glyph_node amii_g_nodes[NUMBER_GLYPH_NODES];
+static char amii_glyph_buffer[GLYPH_BUFFER_SIZE];
+
+#ifdef TEXTCOLOR
+/*
+ * Map our amiga-specific colormap into the colormap specified in color.h.
+ * See winami.c for the amiga specific colormap.
+ */
+
+int foreg[AMII_MAXCOLORS] = { 0, 7, 4, 2, 6, 5, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
+int backg[AMII_MAXCOLORS] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 1, 6, 5, 3, 1 };
+#if 0
+       #define CLR_BLACK       0
+       #define CLR_RED         1
+       #define CLR_GREEN       2
+       #define CLR_BROWN       3       /* on IBM, low-intensity yellow is brown */
+       #define CLR_BLUE        4
+       #define CLR_MAGENTA     5
+       #define CLR_CYAN        6
+       #define CLR_GRAY        7       /* low-intensity white */
+       #define NO_COLOR        8
+       #define CLR_ORANGE      9
+       #define CLR_BRIGHT_GREEN 10
+       #define CLR_YELLOW      11
+       #define CLR_BRIGHT_BLUE 12
+       #define CLR_BRIGHT_MAGENTA 13
+       #define CLR_BRIGHT_CYAN 14
+       #define CLR_WHITE       15
+       #define CLR_MAX         16
+#endif
+#endif
+
+#ifndef TESTING
+/*
+ * Begin Revamped Text display routines
+ *
+ * Up until version 3.1, the only method for displaying text on the playing
+ * field was by using the console.device.  This was nice for a number of
+ * reasons, the most signifigant of which was a lot of the nuts and bolts was
+ * done for you via escape sequences interpreted by said device.  This did
+ * not come without a price however.  And that price was speed. It has now
+ * come to a point where the speed has now been deemed unacceptable.
+ *
+ * The following series of routines are designed to drop into the current
+ * nethack display code, using hooks provided for such a measure. It works
+ * on similar principals as the WindowPuts(), buffering I/O internally
+ * until either an explicit flush or internal buffering is exceeded, thereby
+ * forcing the flush.  The output (or glyphs) does not go to the
+ * console.device, however.  It is driven directly to the rasterport of the
+ * nethack window via the low-level Text() calls, increasing the speed by
+ * a very signifigant factor.
+ */
+/*
+ * Routine to simply flush whatever is buffered
+ */
+void
+amii_flush_glyph_buffer( w )
+    struct Window *w;
+{
+    short i, x, y;
+    register struct RastPort *rp = w->RPort;
+
+    /* If nothing is buffered, return before we do anything */
+    if(glyph_node_index == 0)
+       return;
+
+    cursor_off( WIN_MAP );
+    amii_start_glyphout( WIN_MAP );
+
+    /* Set up the drawing mode */
+    SetDrMd( rp, JAM2);
+
+    /* Go ahead and start dumping the stuff */
+    for(i=0; i<glyph_node_index; ++i) {
+       /* These coordinate calculations must be synced with the
+        * code in amii_curs() in winfuncs.c.  curs_on_u() calls amii_curs()
+        * to draw the cursor on top of the player
+        */
+       y = w->BorderTop + (amii_g_nodes[i].y-2) * rp->TxHeight +
+           rp->TxBaseline + 1;
+       x = amii_g_nodes[i].x * rp->TxWidth + w->BorderLeft;
+
+       /* Move pens to correct location */
+       Move( rp, (long)x, (long)y);
+
+       /* Setup the colors */
+       SetAPen( rp, (long)amii_g_nodes[i].fg_color);
+       SetBPen( rp, (long)amii_g_nodes[i].bg_color);
+
+       /* Do it */
+       Text( rp, amii_g_nodes[i].buffer, amii_g_nodes[i].len);
+    }
+
+    amii_end_glyphout( WIN_MAP );
+    /* Clean up */
+    glyph_node_index = glyph_buffer_index = 0;
+}
+void
+amiga_print_glyph(window,color_index, glyph)
+    winid window;
+    int color_index, glyph;
+{
+    if( WINVERS_AMIV )
+       amiv_lprint_glyph(window,color_index, glyph);
+    else
+       amii_lprint_glyph(window,color_index, glyph);
+}
+
+/*
+ * Glyph buffering routine.  Called instead of WindowPuts().
+ */
+void
+amii_lprint_glyph(window,color_index, glyph)
+    winid window;
+    int color_index, glyph;
+{
+    int fg_color, bg_color;
+    struct amii_WinDesc *cw;
+    struct Window *w;
+    int curx;
+    int cury;
+
+    if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
+       panic("bad winid in amii_lprint_glyph: %d", window );
+
+    w = cw->win;
+    curx=cw->curx;
+    cury=cw->cury;
+
+#ifdef TEXTCOLOR
+    fg_color = foreg[color_index];
+    bg_color = backg[color_index];
+#else
+    fg_color = 1;
+    bg_color = 0;
+#endif /* TEXTCOLOR */
+
+    /* See if we have enough character buffer space... */
+    if(glyph_buffer_index  >= GLYPH_BUFFER_SIZE)
+       amii_flush_glyph_buffer( w );
+
+    /*
+     * See if we can append it to the current active node of glyph buffer. It
+     * must satisfy the following conditions:
+     *
+     *    * background colors are the same, AND
+     *    * foreground colors are the same, AND
+     *    * they are precisely side by side
+     */
+    if((glyph_buffer_index != 0) &&
+       (fg_color == amii_g_nodes[glyph_node_index-1].fg_color) &&
+       (bg_color == amii_g_nodes[glyph_node_index-1].bg_color) &&
+       (amii_g_nodes[glyph_node_index-1].x+
+       amii_g_nodes[glyph_node_index-1].len == curx) &&
+       (amii_g_nodes[glyph_node_index-1].y == cury)) {
+       /*
+        * Add it to the end of the buffer
+        */
+       amii_glyph_buffer[glyph_buffer_index++] = glyph;
+       amii_g_nodes[glyph_node_index-1].len ++;
+     } else {
+       /* See if we're out of glyph nodes */
+       if(glyph_node_index >= NUMBER_GLYPH_NODES)
+           amii_flush_glyph_buffer( w );
+       amii_g_nodes[glyph_node_index].len = 1;
+       amii_g_nodes[glyph_node_index].x = curx;
+       amii_g_nodes[glyph_node_index].y = cury;
+       amii_g_nodes[glyph_node_index].fg_color = fg_color;
+       amii_g_nodes[glyph_node_index].bg_color = bg_color;
+       amii_g_nodes[glyph_node_index].buffer = &amii_glyph_buffer[glyph_buffer_index];
+       amii_glyph_buffer[glyph_buffer_index] = glyph;
+       ++glyph_buffer_index;
+       ++glyph_node_index;
+    }
+}
+#endif /* !TESTING */
+
+#ifdef TESTING
+/*
+ * Define some variables which will be used to save context when toggling
+ * back and forth between low level text and console I/O.
+ */
+static long xsave, ysave, modesave, apensave, bpensave;
+static int usecolor;
+#endif /* TESTING */
+
+#ifndef TESTING
+/*
+ * The function is called before any glyphs are driven to the screen.  It
+ * removes the cursor, saves internal state of the window, then returns.
+ */
+
+void
+amii_start_glyphout(window)
+    winid window;
+{
+    struct amii_WinDesc *cw;
+    struct Window *w;
+
+    if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
+       panic( "bad winid %d in start_glyphout()", window );
+
+    if( cw->wflags & FLMAP_INGLYPH )
+       return;
+
+    if( !(w = cw->win ) )
+       panic( "bad winid %d, no window ptr set", window );
+
+    /*
+     * Save the context of the window
+     */
+    xsave = w->RPort->cp_x;
+    ysave = w->RPort->cp_y;
+    modesave = w->RPort->DrawMode;
+    apensave = w->RPort->FgPen;
+    bpensave = w->RPort->BgPen;
+
+    /*
+     * Set the mode, and be done with it
+     */
+    usecolor = iflags.use_color;
+    iflags.use_color = FALSE;
+    cw->wflags |= FLMAP_INGLYPH;
+}
+#endif /* !TESTING */
+
+# if 0
+/*
+ * General cleanup routine -- flushes and restores cursor
+ */
+void
+amii_end_glyphout(window)
+    winid window;
+{
+    struct amii_WinDesc *cw;
+    struct Window *w;
+
+    if( ( cw = amii_wins[ window ] ) == (struct amii_WinDesc *)NULL )
+       panic("bad window id %d in amii_end_glyphout()", window );
+
+    if( ( cw->wflags & FLMAP_INGLYPH ) == 0 )
+       return;
+    cw->wflags &= ~(FLMAP_INGLYPH);
+
+    if( !(w = cw->win ) )
+       panic( "bad winid %d, no window ptr set", window );
+
+    /*
+     * Clean up whatever is left in the buffer
+     */
+    iflags.use_color = usecolor;
+
+    /*
+     * Reset internal data structs
+     */
+    SetAPen(w->RPort, apensave);
+    SetBPen(w->RPort, bpensave);
+    SetDrMd(w->RPort, modesave);
+
+    Move(w->RPort, xsave, ysave);
+}
+# endif
+#endif
+
+#ifndef TESTING
+# ifdef OPT_DISPMAP
+/* don't use dispmap unless x & y are 8,16,24,32,48 and equal */
+void
+dispmap_sanity(){
+       if(
+           mxsize != mysize ||
+           dispmap_sanity1(mxsize) ||
+           dispmap_sanity1(mysize)){
+               flags.fast_map = 0;
+       }
+}
+int
+dispmap_sanity1(x)
+       int x;
+{
+       static unsigned char valid[] = {8,16,24,32,48,0};
+       return !!strchr(valid,x);
+}
+# endif /* OPT_DISPMAP */
+#endif /* TESTING */
diff --git a/sys/amiga/windefs.h b/sys/amiga/windefs.h
new file mode 100644 (file)
index 0000000..af017be
--- /dev/null
@@ -0,0 +1,203 @@
+/*    SCCS Id: @(#)windefs.h    3.1    93/04/02 */
+/* Copyright (c) Gregg Wonderly, Naperville, Illinois,  1991,1992,1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include <exec/types.h>
+#include <exec/memory.h>
+#include <exec/io.h>
+#if !defined(_DCC) && !defined(__GNUC__)
+#include <dos.h>
+#endif
+#include <exec/alerts.h>
+#include <exec/devices.h>
+#include <exec/execbase.h>
+#include <devices/console.h>
+#include <devices/conunit.h>
+#include <graphics/gfxbase.h>
+#include <intuition/intuition.h>
+#include <intuition/intuitionbase.h>
+#include <libraries/gadtools.h>
+#include <libraries/dosextens.h>
+#include <libraries/asl.h>
+/* stddef.h is included in the precompiled version of hack.h .  If we include
+ * it here normally (through string.h) we'll get an "illegal typedef" later
+ * on.  This is the easiest way I can think of to fix it without messing
+ * around with the rest of the #includes.  --AMC
+ */
+#if defined(_DCC) && !defined(HACK_H)
+# define ptrdiff_t     ptrdiff_t_
+# define size_t                size_t_
+# define wchar_t       wchar_t_
+#endif
+#include <ctype.h>
+#undef  strcmpi
+#include <string.h>
+#include <errno.h>
+#if defined(_DCC) && !defined(HACK_H)
+# undef ptrdiff_t
+# undef size_t
+# undef wchar_T
+#endif
+
+#ifdef  IDCMP_CLOSEWINDOW
+# ifndef       INTUI_NEW_LOOK
+#  define      INTUI_NEW_LOOK
+# endif
+#endif
+
+#ifndef HACK_H
+#include "hack.h"
+#endif
+#include "wintype.h"
+#include "winami.h"
+#include "func_tab.h"
+
+#ifndef        CLIPPING
+CLIPPING must be defined for the AMIGA version
+#endif
+
+#undef LI
+#undef CO
+
+/*#define   TOPL_GETLINE       /* Don't use a window for getlin() */
+/*#define   WINDOW_YN          /* Use a window for y/n questions */
+
+#ifdef AZTEC_C
+#include <functions.h>
+#else
+#ifdef _DCC
+#include <clib/dos_protos.h>
+#include <clib/exec_protos.h>
+#include <clib/console_protos.h>
+#include <clib/layers_protos.h>
+#include <clib/diskfont_protos.h>
+#include <clib/gadtools_protos.h>
+#else
+#include <proto/dos.h>
+#include <proto/exec.h>
+#include <proto/console.h>
+#include <proto/layers.h>
+#include <proto/diskfont.h>
+#include <proto/gadtools.h>
+#include <proto/asl.h>
+#endif
+
+/* kludge - see amirip for why */
+# undef red
+# undef green
+# undef blue
+#ifdef _DCC
+# include <clib/graphics_protos.h>
+#else
+# include <proto/graphics.h>
+#endif
+
+#ifdef _DCC
+# define __asm         /* DICE doesn't like __asm */
+#endif
+
+#ifndef __SASC_60
+#undef index
+# define index strchr
+#endif
+
+#ifdef _DCC
+#include <clib/intuition_protos.h>
+#else
+#include <proto/intuition.h>
+#endif
+#endif
+
+#ifdef SHAREDLIB
+#include "NH:sys/amiga/lib/libmacs.h"
+#endif
+
+#ifdef INTUI_NEW_LOOK
+#include <utility/tagitem.h>
+#endif
+
+#define        WINVERS_AMII    (strcmp("amii",windowprocs.name)==0)
+#define        WINVERS_AMIV    (strcmp("amitile",windowprocs.name)==0)
+#define        WINVERS_AMIT    (strcmp("amitty",windowprocs.name)==0)
+
+/* cw->data[x] contains 2 characters worth of special information.  These
+ * characters are stored at the offsets as described here.
+ */
+#define VATTR    0     /* Video attribute is in this slot */
+#define SEL_ITEM  1    /* If this is a select item, slot is 1 else 0 */
+#define SOFF     2     /* The string starts here.  */
+
+#undef NULL
+#define NULL 0L
+
+/*
+ * Versions we need of various libraries.  We can't use LIBRARY_VERSION
+ * as defined in <exec/types.h> because some of the libraries we need
+ * don't have that version number in the 1.2 ROM.
+ */
+
+#define LIBRARY_FONT_VERSION   34L
+#define LIBRARY_TILE_VERSION   37L
+
+/* These values are just sorta suggestions in use, but are minimum requirements
+ * in reality...
+ */
+#define WINDOWHEIGHT   192
+#define SCREENHEIGHT   200
+#define WIDTH          640
+
+/* This character is a solid block (cursor) in Hack.font */
+#define CURSOR_CHAR    0x90
+
+#define FONTHEIGHT     8
+#define FONTWIDTH      8
+#define FONTBASELINE   8
+
+#define MAPFTWIDTH     8
+#define MAPFTHEIGHT    8
+#define MAPFTBASELN    6
+
+/* If Compiling with the "New Look", redefine these now */
+#ifdef  INTUI_NEW_LOOK
+#define NewWindow ExtNewWindow
+#define NewScreen ExtNewScreen
+#endif
+
+#define         SIZEOF_DISKNAME 8
+
+#define CSI     '\x9b'
+#define NO_CHAR     -1
+#define RAWHELP     0x5F    /* Rawkey code of the HELP key */
+
+
+#define C_BLACK                0
+#define C_WHITE                1
+#define C_BROWN                (WINVERS_AMIV ? 11 : 2)
+#define C_CYAN         (WINVERS_AMIV ? 2  : 3)
+#define C_GREEN                (WINVERS_AMIV ? 5  : 4)
+#define C_MAGENTA      (WINVERS_AMIV ? 10 : 5)
+#define C_BLUE         (WINVERS_AMIV ? 4  : 6)
+#define C_RED          7
+#define C_ORANGE       3
+#define C_GREY         6
+#define C_LTGREEN      8
+#define C_YELLOW       9
+#define C_GREYBLUE     12
+#define C_LTBROWN      13
+#define C_LTGREY       14
+#define C_PEACH                15
+
+/* Structure describing tile files */
+struct PDAT
+{
+    long nplanes;              /* Depth of images */
+    long pbytes;               /* Bytes in a plane of data */
+    long across;               /* Number of tiles across */
+    long down;                 /* Number of tiles down */
+    long npics;                        /* Number of pictures in this file */
+    long xsize;                        /* X-size of a tile */
+    long ysize;                        /* Y-size of a-tile */
+};
+
+#undef MAXCOLORS
+#define        MAXCOLORS       256
diff --git a/sys/amiga/winext.h b/sys/amiga/winext.h
new file mode 100644 (file)
index 0000000..28e423c
--- /dev/null
@@ -0,0 +1,144 @@
+/*    SCCS Id: @(#)winext.h    3.1    2000/01/12 */
+/* Copyright (c) Gregg Wonderly, Naperville, Illinois,  1991,1992,1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+extern int reclip;
+
+#ifdef CLIPPING
+extern int clipping;
+extern int clipx;
+extern int clipy;
+extern int clipxmax;
+extern int clipymax;
+extern int xclipbord, yclipbord;
+#endif
+
+extern int CO;
+extern int LI;
+extern int scrollmsg;
+extern int alwaysinvent;
+
+#ifndef        SHAREDLIB
+extern unsigned short amii_defpens[ 20 ];
+extern struct amii_DisplayDesc *amiIDisplay;   /* the Amiga Intuition descriptor */
+extern struct window_procs amii_procs;
+extern struct window_procs amiv_procs;
+extern unsigned short amii_initmap[ AMII_MAXCOLORS ];
+extern unsigned short amiv_init_map[ AMII_MAXCOLORS ];
+extern unsigned short amii_init_map[ AMII_MAXCOLORS ];
+extern int bigscreen;
+extern int amii_numcolors;
+extern long amii_scrnmode;
+extern winid amii_rawprwin;
+extern struct Screen *HackScreen;
+extern char Initialized;
+/* These have already been defined elsewhere (and some are conflicting)
+ * ... going ... going once ... going twice .... 
+ * extern const char *roles[];
+ * extern struct Library *ConsoleDevice;
+ * extern char toplines[ TBUFSZ ];
+ * extern NEARDATA winid WIN_MESSAGE;
+ * extern NEARDATA winid WIN_MAP;
+ * extern NEARDATA winid WIN_STATUS;
+ * extern NEARDATA winid WIN_INVEN;
+ * extern winid WIN_OVER;
+ * extern struct GfxBase *GfxBase;
+ * extern struct Library *DiskfontBase;
+ * extern struct IntuitionBase *IntuitionBase;
+ * extern struct Library *LayersBase;
+ */
+extern int amii_msgAPen;
+extern int amii_msgBPen;
+extern int amii_statAPen;
+extern int amii_statBPen;
+extern int amii_menuAPen;
+extern int amii_menuBPen;
+extern int amii_textAPen;
+extern int amii_textBPen;
+extern int amii_otherAPen;
+extern int amii_otherBPen;
+#else
+extern WinamiBASE *WinamiBase;
+#endif
+/* All kinds of shared stuff */
+extern struct TextAttr Hack160;
+extern struct TextAttr Hack40;
+extern struct TextAttr Hack80;
+extern struct TextAttr TextsFont13;
+extern struct Window *pr_WindowPtr;
+extern struct Menu HackMenu[];
+extern struct Menu *MenuStrip;
+extern struct NewMenu GTHackMenu[];
+extern APTR *VisualInfo;
+extern unsigned char KbdBuffered;
+extern struct TextFont *TextsFont;
+extern struct TextFont *HackFont;
+extern struct IOStdReq ConsoleIO;
+extern struct MsgPort *HackPort;
+
+extern int txwidth, txheight, txbaseline;
+#ifdef SUPERBITMAP_MAP
+extern struct BitMap amii_vbm;
+#endif
+
+/* This gadget data is replicated for menu/text windows... */
+extern struct PropInfo PropScroll;
+extern struct Image Image1;
+extern struct Gadget MenuScroll;
+
+/* This gadget is for the message window... */
+extern struct PropInfo MsgPropScroll;
+extern struct Image MsgImage1;
+extern struct Gadget MsgScroll;
+
+extern struct TagItem tags[];
+
+extern struct win_setup
+{
+    struct NewWindow newwin;
+    UWORD offx,offy,maxrow,rows,maxcol,cols;   /* CHECK TYPES */
+} new_wins[];
+
+extern UWORD scrnpens[];
+/* The last Window event is stored here for reference. */
+extern WEVENT lastevent;
+extern const char winpanicstr[];
+extern struct TagItem scrntags[];
+extern struct NewScreen NewHackScreen;
+
+extern int topl_addspace;
+extern char spaces[ 76 ];
+extern int wincnt;   /* # of nh windows opened */
+extern struct Rectangle lastinvent, lastmsg;
+
+typedef struct {
+       UWORD w, h;
+       WORD x, y;
+       UBYTE nPlanes;
+       UBYTE masking;
+       UBYTE compression;
+       UBYTE reserved1;
+       UWORD transparentColor;
+       UBYTE xAspect, yAspect;
+       WORD pageWidth, pageHeight;
+} BitMapHeader;
+
+typedef enum {COL_MAZE_BRICK,COL_MAZE_STONE,COL_MAZE_HEAT,COL_MAZE_WOOD} MazeType;
+extern struct PDAT pictdata;
+extern struct Hook fillhook;
+extern struct TagItem wintags[];
+#ifndef        SHAREDLIB
+#ifndef __GNUC__
+void __asm LayerFillHook(
+    register __a0 struct Hook *hk,
+    register __a2 struct RastPort *rp,
+    register __a1 struct FillParams *fp );
+#else
+#ifdef __PPC__
+struct EmulLibEntry LayerFillHook;
+#else
+void LayerFillHook(void);
+#endif
+#endif
+#endif
+extern int mxsize, mysize;
diff --git a/sys/amiga/winfuncs.c b/sys/amiga/winfuncs.c
new file mode 100644 (file)
index 0000000..81bca7a
--- /dev/null
@@ -0,0 +1,2451 @@
+/*    SCCS Id: @(#)winfuncs.c    3.1    2000/01/12 */
+/* Copyright (c) Gregg Wonderly, Naperville, Illinois,  1991,1992,1993,1996. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "NH:sys/amiga/windefs.h"
+#include "NH:sys/amiga/winext.h"
+#include "NH:sys/amiga/winproto.h"
+#include "patchlevel.h"
+
+extern struct TagItem scrntags[];
+
+static BitMapHeader amii_bmhd;
+static void cursor_common(struct RastPort *, int, int);
+
+#ifdef CLIPPING
+int CO, LI;
+
+/* Changing clipping region, skip clear of screen in overview window. */
+int reclip;
+
+/* Must be set to at least two or you will get stuck! */
+int xclipbord = 4, yclipbord = 2;
+#endif
+
+int mxsize, mysize;
+struct Rectangle amii_oldover;
+struct Rectangle amii_oldmsg;
+
+extern struct TextFont *RogueFont;
+
+int amii_msgAPen;
+int amii_msgBPen;
+int amii_statAPen;
+int amii_statBPen;
+int amii_menuAPen;
+int amii_menuBPen;
+int amii_textAPen;
+int amii_textBPen;
+int amii_otherAPen;
+int amii_otherBPen;
+long amii_libvers = LIBRARY_FONT_VERSION;
+
+void
+ami_wininit_data( void )
+{
+    extern unsigned short amii_init_map[ AMII_MAXCOLORS ];
+    extern unsigned short amiv_init_map[ AMII_MAXCOLORS ];
+    if( !WINVERS_AMIV )
+    {
+# ifdef        TEXTCOLOR
+       amii_numcolors = 8;
+# else
+       amii_numcolors = 4;
+# endif
+       amii_defpens[ 0 ] = C_BLACK;    /* DETAILPEN        */
+       amii_defpens[ 1 ] = C_BLUE;     /* BLOCKPEN         */
+       amii_defpens[ 2 ] = C_BROWN;    /* TEXTPEN          */
+       amii_defpens[ 3 ] = C_WHITE;    /* SHINEPEN         */
+       amii_defpens[ 4 ] = C_BLUE;     /* SHADOWPEN        */
+       amii_defpens[ 5 ] = C_CYAN;     /* FILLPEN          */
+       amii_defpens[ 6 ] = C_WHITE;    /* FILLTEXTPEN      */
+       amii_defpens[ 7 ] = C_CYAN;     /* BACKGROUNDPEN    */
+       amii_defpens[ 8 ] = C_RED;      /* HIGHLIGHTTEXTPEN */
+       amii_defpens[ 9 ] = C_WHITE;    /* BARDETAILPEN     */
+       amii_defpens[ 10 ] = C_CYAN;    /* BARBLOCKPEN      */
+       amii_defpens[ 11 ] = C_BLUE;    /* BARTRIMPEN       */
+       amii_defpens[ 12 ] = (unsigned short) ~0;
+
+       amii_msgAPen = C_WHITE;
+       amii_msgBPen = C_BLACK;
+       amii_statAPen = C_WHITE;
+       amii_statBPen = C_BLACK;
+       amii_menuAPen = C_WHITE;
+       amii_menuBPen = C_BLACK;
+       amii_textAPen = C_WHITE;
+       amii_textBPen = C_BLACK;
+       amii_otherAPen = C_RED;
+       amii_otherBPen = C_BLACK;
+
+       mxsize = 8;
+       mysize = 8;
+
+       amii_libvers = LIBRARY_FONT_VERSION;
+       memcpy( amii_initmap, amii_init_map, sizeof( amii_initmap ) );
+    }
+    else
+    {
+       mxsize = 16;
+       mysize = 16;
+
+       amii_numcolors = 16;
+
+       amii_defpens[ 0 ] = C_BLACK;    /* DETAILPEN        */
+       amii_defpens[ 1 ] = C_WHITE;    /* BLOCKPEN         */
+       amii_defpens[ 2 ] = C_BLACK;    /* TEXTPEN          */
+       amii_defpens[ 3 ] = C_CYAN;     /* SHINEPEN         */
+       amii_defpens[ 4 ] = C_BLUE;     /* SHADOWPEN        */
+       amii_defpens[ 5 ] = C_GREYBLUE; /* FILLPEN          */
+       amii_defpens[ 6 ] = C_LTGREY;   /* FILLTEXTPEN      */
+       amii_defpens[ 7 ] = C_GREYBLUE; /* BACKGROUNDPEN    */
+       amii_defpens[ 8 ] = C_RED;      /* HIGHLIGHTTEXTPEN */
+       amii_defpens[ 9 ] = C_WHITE;    /* BARDETAILPEN     */
+       amii_defpens[ 10] = C_GREYBLUE; /* BARBLOCKPEN      */
+       amii_defpens[ 11] = C_BLUE;     /* BARTRIMPEN       */
+       amii_defpens[ 12] = (unsigned short) ~0;
+
+       amii_msgAPen = C_WHITE;
+       amii_msgBPen = C_GREYBLUE;
+       amii_statAPen = C_WHITE;
+       amii_statBPen = C_GREYBLUE;
+       amii_menuAPen = C_BLACK;
+       amii_menuBPen = C_LTGREY;
+       amii_textAPen = C_BLACK;
+       amii_textBPen = C_LTGREY;
+       amii_otherAPen = C_RED;
+       amii_otherBPen = C_BLACK;
+       amii_libvers = LIBRARY_TILE_VERSION;
+
+       memcpy( amii_initmap, amiv_init_map, sizeof( amii_initmap ) );
+    }
+#ifdef OPT_DISPMAP
+    dispmap_sanity();
+#endif
+    memcpy(flags.amii_dripens,amii_defpens,sizeof(flags.amii_dripens));
+}
+
+# ifdef        INTUI_NEW_LOOK
+struct Hook SM_FilterHook;
+struct Hook fillhook;
+struct TagItem wintags[] =
+{
+       { WA_BackFill, (ULONG)&fillhook },
+       { WA_PubScreenName, (ULONG)"NetHack" },
+       { TAG_END, 0 },
+};
+# endif
+
+void
+amii_destroy_nhwindow(win)      /* just hide */
+    register winid win;
+{
+    int i;
+    int type;
+    register struct amii_WinDesc *cw;
+
+    if( win == WIN_ERR || ( cw = amii_wins[win] ) == NULL )
+    {
+       panic(winpanicstr,win,"destroy_nhwindow");
+    }
+
+    if( WINVERS_AMIV )
+    {
+       if( cw->type == NHW_MAP )
+       {
+           /* If inventory is up, close it now, it will be freed later */
+           if( alwaysinvent && WIN_INVEN != WIN_ERR &&
+                               amii_wins[ WIN_INVEN ] &&
+                               amii_wins[ WIN_INVEN ]->win )
+           {
+               dismiss_nhwindow( WIN_INVEN );
+           }
+
+           /* Tear down overview window if it is up */
+           if( WIN_OVER != WIN_ERR )
+           {
+               amii_destroy_nhwindow( WIN_OVER );
+               WIN_OVER = WIN_ERR;
+           }
+       }
+       else if( cw->type == NHW_OVER )
+       {
+           struct Window *w = amii_wins[ WIN_OVER ]->win;
+           amii_oldover.MinX = w->LeftEdge;
+           amii_oldover.MinY = w->TopEdge;
+           amii_oldover.MaxX = w->Width;
+           amii_oldover.MaxY = w->Height;
+
+           if( WIN_MESSAGE != WIN_ERR && amii_wins[ WIN_MESSAGE ] )
+           {
+               w = amii_wins[ WIN_MESSAGE ]->win;
+               amii_oldmsg.MinX = w->LeftEdge;
+               amii_oldmsg.MinY = w->TopEdge;
+               amii_oldmsg.MaxX = w->Width;
+               amii_oldmsg.MaxY = w->Height;
+               SizeWindow( amii_wins[ WIN_MESSAGE ]->win,
+                       (amiIDisplay->xpix -
+                       amii_wins[ WIN_MESSAGE ]->win->LeftEdge) -
+                       amii_wins[ WIN_MESSAGE ]->win->Width,
+                       0 );
+           }
+       }
+    }
+
+    /* Tear down the Intuition stuff */
+    dismiss_nhwindow(win);
+    type = cw->type;
+
+    if( cw->resp ) {
+       free( cw->resp );
+       cw->resp = NULL;
+    }
+    if( cw->canresp ) {
+       free( cw->canresp );
+       cw->canresp = NULL;
+    }
+    if( cw->morestr ) {
+       free( cw->morestr );
+       cw->morestr = NULL;
+    }
+    if( cw->hook ) {
+       free( cw->hook );
+       cw->hook = NULL;
+    }
+
+    if( cw->data && ( cw->type == NHW_MESSAGE ||
+                           cw->type == NHW_MENU || cw->type == NHW_TEXT ) )
+    {
+       for( i = 0; i < cw->maxrow; ++i )
+       {
+           if( cw->data[ i ] )
+               free( cw->data[ i ] );
+       }
+       free( cw->data );
+    }
+
+    free( cw );
+    amii_wins[win] = NULL;
+
+    /* Set globals to WIN_ERR for known one-of-a-kind windows. */
+    if( win == WIN_MAP) WIN_MAP = WIN_ERR;
+    else if( win == WIN_STATUS) WIN_STATUS = WIN_ERR;
+    else if( win == WIN_MESSAGE) WIN_MESSAGE = WIN_ERR;
+    else if( win == WIN_INVEN) WIN_INVEN = WIN_ERR;
+
+}
+
+#ifdef INTUI_NEW_LOOK
+struct FillParams
+{
+       struct Layer *layer;
+       struct Rectangle bounds;
+       WORD offsetx;
+       WORD offsety;
+};
+
+#ifdef __GNUC__
+#ifdef __PPC__
+void PPC_LayerFillHook(void);
+struct EmulLibEntry LayerFillHook = {TRAP_LIB, 0, (void (*)(void)) PPC_LayerFillHook};
+void PPC_LayerFillHook(void) {
+   struct Hook *hk = (struct Hook*)REG_A0;
+   struct RastPort *rp = (struct RastPort *)REG_A2;
+   struct FillParams *fp = (struct FillParams*)REG_A1;
+#else
+void LayerFillHook(void) {
+    register struct Hook *hk asm("a0");
+    register struct RastPort *rp asm("a2");
+    register struct FillParams *fp asm("a1");
+#endif
+#else
+void
+#ifndef _DCC
+__interrupt
+#endif
+__saveds __asm LayerFillHook(
+    register __a0 struct Hook *hk,
+    register __a2 struct RastPort *rp,
+    register __a1 struct FillParams *fp )
+{
+#endif
+
+    register long x, y, xmax, ymax;
+    register int apen;
+    struct RastPort rptmp;
+
+    memcpy(&rptmp, rp, sizeof(struct RastPort));
+    rptmp.Layer = NULL;
+
+    switch( (int)hk->h_Data )
+    {
+    case NHW_STATUS:
+       apen = amii_statBPen;
+       break;
+    case NHW_MESSAGE:
+       apen = amii_msgBPen;
+       break;
+    case NHW_TEXT:
+       apen = amii_textBPen;
+       break;
+    case NHW_MENU:
+       apen = amii_menuBPen;
+       break;
+    case -2:
+       apen = amii_otherBPen;
+       break;
+    case NHW_BASE:
+    case NHW_MAP:
+    case NHW_OVER:
+    default:
+       apen = C_BLACK;
+       break;
+    }
+
+    x = fp->bounds.MinX;
+    y = fp->bounds.MinY;
+    xmax = fp->bounds.MaxX;
+    ymax = fp->bounds.MaxY;
+
+    SetAPen(&rptmp, apen);
+    SetBPen(&rptmp, apen);
+    SetDrMd(&rptmp, JAM2);
+    RectFill(&rptmp, x, y, xmax, ymax);
+}
+#endif
+
+
+amii_create_nhwindow(type)
+    register int type;
+{
+    register struct Window *w = NULL;
+    register struct NewWindow *nw = NULL;
+    register struct amii_WinDesc *wd = NULL;
+    struct Window *mapwin = NULL, *stwin = NULL, *msgwin = NULL;
+    register int newid;
+    int maph, stath, scrfontysize;
+
+    scrfontysize = HackScreen->Font->ta_YSize;
+
+    /*
+     * Initial mapwindow height, this might change later in tilemode
+     * and low screen
+     */
+    maph = ( 21 * mxsize ) + 2 + (bigscreen ?
+       HackScreen->WBorTop + HackScreen->WBorBottom + scrfontysize + 1 : 0);
+
+    /* Status window height, avoids having to calculate many times */
+    stath = txheight * 2 + 2 + (WINVERS_AMIV || bigscreen ?
+       HackScreen->WBorTop + HackScreen->WBorBottom +
+       ( bigscreen ? scrfontysize + 1 : 0 ) : 0);
+
+    if( WIN_STATUS != WIN_ERR && amii_wins[ WIN_STATUS ] )
+       stwin = amii_wins[ WIN_STATUS ]->win;
+
+    if( WIN_MESSAGE != WIN_ERR && amii_wins[ WIN_MESSAGE ] )
+       msgwin = amii_wins[ WIN_MESSAGE ]->win;
+
+    if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] )
+       mapwin = amii_wins[ WIN_MAP ]->win;
+
+    /* Create Port anytime that we need it */
+
+    if( HackPort == NULL )
+    {
+       HackPort = CreateMsgPort();
+       if( !HackPort )
+           panic( "no memory for msg port" );
+    }
+
+    nw = &new_wins[ type ].newwin;
+    nw->Width = amiIDisplay->xpix;
+    nw->Screen = HackScreen;
+
+    if( WINVERS_AMIV )
+    {
+       nw->DetailPen = C_WHITE;
+       nw->BlockPen = C_GREYBLUE;
+    }
+    else
+    {
+       nw->DetailPen = C_WHITE;
+       nw->BlockPen = C_BLACK;
+    }
+
+    if ( type == NHW_BASE ) {
+       nw->LeftEdge = 0;
+       nw->TopEdge = HackScreen->BarHeight+1;
+       nw->Width = HackScreen->Width;
+       nw->Height = HackScreen->Height - nw->TopEdge;
+    } else if( !WINVERS_AMIV && type == NHW_MAP ) {
+       nw->LeftEdge = 0;
+       nw->Height = maph;
+
+       if( msgwin && stwin ) {
+           nw->TopEdge = stwin->TopEdge - maph;
+       } else {
+           panic( "msgwin and stwin must open before map" );
+       }
+       if (nw->TopEdge < 0)
+           panic( "Too small screen to fit map" );
+    }
+    else if( type == NHW_MAP && WINVERS_AMIV )
+    {
+       struct Window *w;
+
+       w = amii_wins[ WIN_MESSAGE ]->win;
+       nw->LeftEdge = 0;
+       nw->TopEdge = w->TopEdge + w->Height;
+       nw->Width = amiIDisplay->xpix - nw->LeftEdge;
+
+       w = amii_wins[ WIN_STATUS ]->win;
+       nw->Height = w->TopEdge - nw->TopEdge;
+       nw->MaxHeight = 0xffff;
+       nw->MaxWidth = 0xffff;
+
+       if( nw->TopEdge + nw->Height > amiIDisplay->ypix - 1 )
+           nw->Height = amiIDisplay->ypix - nw->TopEdge - 1;
+    }
+    else if( type == NHW_STATUS )
+    {
+       if( !WINVERS_AMIV && ( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] ) )
+           w = amii_wins[ WIN_MAP ]->win;
+       else if( WIN_BASE != WIN_ERR && amii_wins[ WIN_BASE ] )
+           w = amii_wins[ WIN_BASE ]->win;
+       else
+           panic( "No window to base STATUS location from" );
+
+       nw->Height = stath;
+       nw->TopEdge = amiIDisplay->ypix - nw->Height;
+       nw->LeftEdge = w->LeftEdge;
+
+       if( nw->LeftEdge + nw->Width >= amiIDisplay->xpix )
+           nw->LeftEdge = 0;
+
+       if( nw->Width >= amiIDisplay->xpix - nw->LeftEdge )
+           nw->Width = amiIDisplay->xpix - nw->LeftEdge;
+    }
+    else if( WINVERS_AMIV && type == NHW_OVER )
+    {
+       nw->Flags |= WINDOWSIZING|WINDOWDRAG|WINDOWCLOSE;
+       nw->IDCMPFlags |= CLOSEWINDOW;
+       /* Bring up window as half the width of the message window, and make
+        * the message window change to one half the width...
+        */
+       if( amii_oldover.MaxX != 0 )
+       {
+           nw->LeftEdge = amii_oldover.MinX;
+           nw->TopEdge = amii_oldover.MinY;
+           nw->Width = amii_oldover.MaxX;
+           nw->Height = amii_oldover.MaxY;
+           ChangeWindowBox( amii_wins[ WIN_MESSAGE ]->win,
+                       amii_oldmsg.MinX, amii_oldmsg.MinY,
+                       amii_oldmsg.MaxX, amii_oldmsg.MaxY );
+       }
+       else
+       {
+           nw->LeftEdge = (amii_wins[ WIN_MESSAGE ]->win->Width*4)/9;
+           nw->TopEdge = amii_wins[ WIN_MESSAGE ]->win->TopEdge;
+           nw->Width = amiIDisplay->xpix - nw->LeftEdge;
+           nw->Height = amii_wins[ WIN_MESSAGE ]->win->Height;
+           SizeWindow( amii_wins[ WIN_MESSAGE ]->win,
+                   nw->LeftEdge - amii_wins[ WIN_MESSAGE ]->win->Width, 0 );
+       }
+    }
+    else if( type == NHW_MESSAGE )
+    {
+       if( !WINVERS_AMIV && ( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] ) )
+           w = amii_wins[ WIN_MAP ]->win;
+       else if( WIN_BASE != WIN_ERR && amii_wins[ WIN_BASE ] )
+           w = amii_wins[ WIN_BASE ]->win;
+       else
+           panic( "No window to base STATUS location from" );
+
+       nw->TopEdge = bigscreen ? HackScreen->BarHeight+1 : 0;
+
+       /* Assume highest possible message window */
+       nw->Height = HackScreen->Height - nw->TopEdge - maph - stath;
+
+       /* In tilemode we can cope with this */
+       if (WINVERS_AMIV && nw->Height < 0)
+           nw->Height = 0;
+
+       /* If in fontmode messagewindow is too small, open it with 3 lines
+          and overlap it with map */
+       if (nw->Height < txheight+2) {
+           nw->Height = txheight*4 + 3 + HackScreen->WBorTop + HackScreen->WBorBottom;
+       }
+
+       if ((nw->Height-2)/txheight < 3) {
+           scrollmsg = 0;
+           nw->Title = 0;
+       } else {
+           nw->FirstGadget = &MsgScroll;
+           nw->Flags |= WINDOWSIZING|WINDOWDRAG;
+           nw->Flags &= ~BORDERLESS;
+
+           if( WINVERS_AMIV || nw->Height == 0) {
+               if( WINVERS_AMIV ) {
+                   nw->Height = TextsFont->tf_YSize + HackScreen->WBorTop + 3 +
+                               HackScreen->WBorBottom;
+                   if( bigscreen )
+                       nw->Height += ( txheight * 6 );
+                   else
+                       nw->Height += ( txheight * 3 );
+               }
+               else
+               {
+                   nw->Height = HackScreen->Height - nw->TopEdge - stath - maph;
+               }
+           }
+       }
+
+       /* Do we have room for larger message window ?
+        * This is possible if we can show full height map in tile
+        * mode with default scaling.
+        */
+       if (nw->Height + stath + maph < HackScreen->Height - nw->TopEdge )
+           nw->Height = HackScreen->Height - nw->TopEdge - 1 - maph - stath;
+
+#ifdef  INTUI_NEW_LOOK
+       if( IntuitionBase->LibNode.lib_Version >= 37 )
+       {
+           MsgPropScroll.Flags |= PROPNEWLOOK;
+           PropScroll.Flags |= PROPNEWLOOK;
+       }
+#endif
+    }
+
+    nw->IDCMPFlags |= MENUPICK;
+
+    /* Check if there is "Room" for all this stuff... */
+    if( ( WINVERS_AMIV || bigscreen ) &&
+       type != NHW_BASE )
+    {
+       nw->Flags &= ~( BORDERLESS | BACKDROP );
+
+       if( WINVERS_AMIV )
+       {
+           if( type == NHW_STATUS )
+           {
+               nw->Flags &= ~( WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT | WINDOWSIZING );
+               nw->IDCMPFlags &= ~NEWSIZE;
+           }
+           else
+           {
+               nw->Flags |= ( WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT | WINDOWSIZING );
+               nw->IDCMPFlags |= NEWSIZE;
+           }
+       }
+       else
+       {
+           if( HackScreen->Width < 657 )
+           {
+               nw->Flags |= ( WINDOWDRAG | WINDOWDEPTH );
+           }
+           else
+           {
+               nw->Flags |= ( WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT );
+           }
+       }
+    }
+
+    if ( WINVERS_AMII && type == NHW_MAP )
+       nw->Flags &= ~WINDOWSIZING;
+
+    if ( type == NHW_MESSAGE && scrollmsg ) {
+       nw->Flags |= WINDOWDRAG|WINDOWDEPTH|SIZEBRIGHT|WINDOWSIZING;
+       nw->Flags &= ~BORDERLESS;
+    }
+
+    /* No titles on a hires only screen except for messagewindow */
+    if( !(WINVERS_AMIV && type == NHW_MAP) && !bigscreen && type != NHW_MESSAGE )
+       nw->Title = 0;
+
+    wd = (struct amii_WinDesc *)alloc(sizeof(struct amii_WinDesc));
+    memset( wd, 0, sizeof( struct amii_WinDesc ) );
+
+    /* Both, since user may have changed the pen settings so respect those */
+    if( WINVERS_AMII || WINVERS_AMIV )
+    {
+       /* Special backfill for these types of layers */
+       switch( type )
+       {
+       case NHW_MESSAGE:
+       case NHW_STATUS:
+       case NHW_TEXT:
+       case NHW_MENU:
+       case NHW_BASE:
+       case NHW_OVER:
+       case NHW_MAP:
+           if( wd )
+           {
+#ifdef __GNUC__
+               fillhook.h_Entry = (void *)&LayerFillHook;
+#else
+               fillhook.h_Entry = (ULONG(*)())LayerFillHook;
+#endif
+               fillhook.h_Data = (void *)type;
+               fillhook.h_SubEntry = 0;
+               wd->hook = alloc( sizeof( fillhook ) );
+               memcpy( wd->hook, &fillhook, sizeof( fillhook ) );
+               memcpy( wd->wintags, wintags, sizeof( wd->wintags) );
+               wd->wintags[0].ti_Data = (long)wd->hook;
+               nw->Extension = (void *)wd->wintags;
+           }
+           break;
+       }
+    }
+
+    /* Don't open MENU or TEXT windows yet */
+
+    if( type == NHW_MENU || type == NHW_TEXT )
+       w = NULL;
+    else
+       w=OpenShWindow( (void *)nw );
+
+    if( w == NULL && type != NHW_MENU && type != NHW_TEXT )
+    {
+       char buf[ 100 ];
+
+       sprintf( buf, "nw type (%d) dims l: %d, t: %d, w: %d, h: %d",
+               type,
+               nw->LeftEdge, nw->TopEdge,
+               nw->Width, nw->Height );
+       raw_print( buf );
+       panic("bad openwin %d",type);
+    }
+
+    /* Check for an empty slot */
+
+    for(newid = 0; newid<MAXWIN + 1; newid++)
+    {
+       if(amii_wins[newid] == 0)
+           break;
+    }
+
+    if(newid==MAXWIN+1)
+       panic("time to write re-alloc code\n");
+
+    /* Set wincnt accordingly */
+
+    if( newid > wincnt )
+       wincnt = newid;
+
+    /* Do common initialization */
+
+    amii_wins[newid] = wd;
+
+    wd->newwin = NULL;
+    wd->win = w;
+    wd->type = type;
+    wd->wflags = 0;
+    wd->active = FALSE;
+    wd->curx=wd->cury = 0;
+    wd->resp = wd->canresp = wd->morestr = 0;   /* CHECK THESE */
+    wd->maxrow = new_wins[type].maxrow;
+    wd->maxcol = new_wins[type].maxcol;
+
+    if( type != NHW_TEXT && type != NHW_MENU )
+    {
+       if( TextsFont && ( type == NHW_MESSAGE || type == NHW_STATUS ) )
+       {
+           SetFont(w->RPort, TextsFont);
+           txheight = w->RPort->TxHeight;
+           txwidth = w->RPort->TxWidth;
+           txbaseline = w->RPort->TxBaseline;
+           if( type == NHW_MESSAGE )
+           {
+               if (scrollmsg )
+               {
+                   if( WINVERS_AMIV )
+                   {
+                       WindowLimits( w, 100, w->BorderTop +
+                               w->BorderBottom +
+                               ((txheight+1)*2) + 1, 0, 0 );
+                   }
+                   else
+                   {
+                       WindowLimits( w, w->Width, w->BorderTop +
+                               w->BorderBottom +
+                               ((txheight+1)*2) + 1, 0, 0 );
+                   }
+               }
+               else
+               {
+                   WindowLimits( w, w->Width, w->BorderTop +
+                               w->BorderBottom +
+                               txheight + 2, 0, 0 );
+               }
+           }
+       }
+       if ( type != NHW_MAP) {
+           SetFont(w->RPort, TextsFont);
+       }
+#ifdef HACKFONT
+       else if( HackFont )
+           SetFont(w->RPort, HackFont);
+#endif
+    }
+
+    /* Text and menu windows are not opened yet */
+    if( w )
+    {
+       wd->rows = ( w->Height - w->BorderTop -
+           w->BorderBottom - 2 ) / w->RPort->TxHeight;
+       wd->cols = ( w->Width - w->BorderLeft -
+           w->BorderRight - 2 ) / w->RPort->TxWidth;
+    }
+
+    /* Okay, now do the individual type initialization */
+
+    switch(type)
+    {
+       /* History lines for MESSAGE windows are stored in cw->data[?].
+        * maxcol and maxrow are used as cursors.  maxrow is the count
+        * of the number of history lines stored.  maxcol is the cursor
+        * to the last line that was displayed by ^P.
+        */
+       case NHW_MESSAGE:
+           SetMenuStrip(w, MenuStrip);
+           MsgScroll.TopEdge = HackScreen->WBorTop + scrfontysize + 1;
+           iflags.msg_history = wd->rows*10;
+           if (iflags.msg_history < 40)
+               iflags.msg_history = 40;
+           if (iflags.msg_history > 400)
+               iflags.msg_history = 400;
+           iflags.window_inited=TRUE;
+           wd->data = (char **)alloc( iflags.msg_history*sizeof( char * ) );
+           memset( wd->data, 0, iflags.msg_history * sizeof( char * ) );
+           wd->maxrow = wd->maxcol = 0;
+           /* Indicate that we have not positioned the cursor yet */
+           wd->curx = -1;
+           break;
+
+           /* A MENU contains a list of lines in wd->data[?].  These
+            * lines are created in amii_putstr() by reallocating the size
+            * of wd->data to hold enough (char *)'s.  wd->rows is the
+            * number of (char *)'s allocated.  wd->maxrow is the number
+            * used.  wd->maxcol is used to track how wide the menu needs
+            * to be.  wd->resp[x] contains the characters that correspond
+            * to selecting wd->data[x].  wd->resp[x] corresponds to
+            * wd->data[x] for any x. Elements of wd->data[?] that are not
+            * valid selections have the corresponding element of
+            * wd->resp[] set to a value of '\01';  i.e. a ^A which is
+            * not currently a valid keystroke for responding to any
+            * MENU or TEXT window.
+            */
+       case NHW_MENU:
+           MenuScroll.TopEdge = HackScreen->WBorTop + scrfontysize + 1;
+           wd->resp=(char*)alloc(256);
+           wd->resp[0]=0;
+           wd->rows = wd->maxrow = 0;
+           wd->cols = wd->maxcol = 0;
+           wd->data = NULL;
+           break;
+
+           /* See the explanation of MENU above.  Except, wd->resp[] is not
+            * used for TEXT windows since there is no selection of a
+            * a line performed/allowed.  The window is always full
+            * screen width.
+            */
+       case NHW_TEXT:
+           MenuScroll.TopEdge = HackScreen->WBorTop + scrfontysize + 1;
+           wd->rows = wd->maxrow = 0;
+           wd->cols = wd->maxcol = amiIDisplay->cols;
+           wd->data = NULL;
+           wd->morestr = NULL;
+           break;
+
+           /* The status window has only two lines.  These are stored in
+            * wd->data[], and here we allocate the space for them.
+            */
+       case NHW_STATUS:
+           SetMenuStrip(w, MenuStrip);
+           /* wd->cols is the number of characters which fit across the
+            * screen.
+            */
+           wd->data=(char **)alloc(3*sizeof(char *));
+           wd->data[0] = (char *)alloc(wd->cols + 10);
+           wd->data[1] = (char *)alloc(wd->cols + 10);
+           wd->data[2] = NULL;
+           break;
+
+           /* NHW_OVER does not use wd->data[] or the other text
+            * manipulating members of the amii_WinDesc structure.
+            */
+       case NHW_OVER:
+           SetMenuStrip(w, MenuStrip);
+           break;
+
+           /* NHW_MAP does not use wd->data[] or the other text
+            * manipulating members of the amii_WinDesc structure.
+            */
+       case NHW_MAP:
+           SetMenuStrip(w, MenuStrip);
+           if( WINVERS_AMIV )
+           {
+               CO = (w->Width-w->BorderLeft-w->BorderRight)/mxsize;
+               LI = (w->Height-w->BorderTop-w->BorderBottom)/mysize;
+               amii_setclipped();
+               SetFont( w->RPort, RogueFont);
+               SetAPen( w->RPort, C_WHITE);    /* XXX not sufficient */
+               SetBPen( w->RPort, C_BLACK);
+               SetDrMd( w->RPort, JAM2);
+           }
+           else
+           {
+               if( HackFont )
+                   SetFont( w->RPort, HackFont );
+           }
+           break;
+
+           /* The base window must exist until CleanUp() deletes it. */
+       case NHW_BASE:
+           SetMenuStrip(w, MenuStrip);
+           /* Make our requesters come to our screen */
+           {
+               register struct Process *myProcess =
+                                       (struct Process *) FindTask(NULL);
+               pr_WindowPtr = (struct Window *)(myProcess->pr_WindowPtr);
+               myProcess->pr_WindowPtr = (APTR) w;
+           }
+
+           /* Need this for RawKeyConvert() */
+
+           ConsoleIO.io_Data = (APTR) w;
+           ConsoleIO.io_Length = sizeof( struct Window );
+           ConsoleIO.io_Message.mn_ReplyPort = CreateMsgPort();
+           if( OpenDevice("console.device", -1L,
+                               (struct IORequest *) &ConsoleIO, 0L) != 0)
+           {
+               Abort(AG_OpenDev | AO_ConsoleDev);
+           }
+
+           ConsoleDevice = (struct Library *) ConsoleIO.io_Device;
+
+           KbdBuffered = 0;
+
+#ifdef HACKFONT
+           if( TextsFont )
+               SetFont( w->RPort, TextsFont );
+           else if( HackFont )
+               SetFont( w->RPort, HackFont );
+#endif
+           txwidth = w->RPort->TxWidth;
+           txheight = w->RPort->TxHeight;
+           txbaseline = w->RPort->TxBaseline;
+           break;
+
+       default:
+           panic("bad create_nhwindow( %d )\n",type);
+           return WIN_ERR;
+    }
+
+    return( newid );
+}
+
+#ifdef __GNUC__
+#ifdef __PPC__
+int PPC_SM_Filter(void);
+struct EmulLibEntry SM_Filter = {TRAP_LIB, 0, (int (*)(void)) PPC_SM_Filter};
+int PPC_SM_Filter(void) {
+   struct Hook *hk = (struct Hook*)REG_A0;
+   ULONG modeID  = (ULONG)REG_A1;
+   struct ScreenModeRequester *smr = (struct ScreenModeRequester *)REG_A2;
+#else
+int SM_Filter(void) {
+    register struct Hook *hk asm("a0");
+    register ULONG modeID asm("a1");
+    register struct ScreenModeRequester *smr asm("a2");
+#endif
+#else
+int
+#ifndef _DCC
+__interrupt
+#endif
+__saveds __asm SM_Filter(
+    register __a0 struct Hook *hk,
+    register __a1 ULONG modeID,
+    register __a2 struct ScreenModeRequester *smr)
+{
+#endif
+    struct DimensionInfo dims;
+    struct DisplayInfo disp;
+    DisplayInfoHandle handle;
+    handle = FindDisplayInfo(modeID);
+    if (handle) {
+       GetDisplayInfoData(handle, (char *)&dims, sizeof(dims), DTAG_DIMS, modeID);
+       GetDisplayInfoData(handle, (char *)&disp, sizeof(disp), DTAG_DISP, modeID);
+       if (!disp.NotAvailable &&
+            dims.MaxDepth <= 8 &&
+            dims.StdOScan.MaxX >= WIDTH-1 &&
+            dims.StdOScan.MaxY >= SCREENHEIGHT-1) {
+           return 1;
+       }
+    }
+    return 0;
+}
+
+/* Initialize the windowing environment */
+
+void
+amii_init_nhwindows(argcp,argv)
+    int *argcp;
+    char **argv;
+{
+    int i;
+    struct Screen *wbscr;
+    int forcenobig = 0;
+
+    if( HackScreen )
+       panic( "init_nhwindows() called twice", 0 );
+
+       /* run args & set bigscreen from -L(1)/-l(-1) */
+    {
+       int lclargc = *argcp;
+       int t;
+       char **argv_in = argv;
+       char **argv_out = argv;
+
+       for(t=1;t<=lclargc;t++){
+           if(!strcmp("-L",*argv_in) || !strcmp("-l",*argv_in)){
+               bigscreen = (*argv_in[1]=='l') ? -1 : 1;
+               /* and eat the flag */
+               (*argcp)--;
+           } else {
+               *argv_out = *argv_in;   /* keep the flag */
+               argv_out++;
+           }
+           argv_in++;
+       }
+       *argv_out = 0;
+    }
+
+    WIN_MESSAGE = WIN_ERR;
+    WIN_MAP = WIN_ERR;
+    WIN_STATUS = WIN_ERR;
+    WIN_INVEN = WIN_ERR;
+    WIN_BASE = WIN_ERR;
+    WIN_OVER = WIN_ERR;
+
+    if ( (IntuitionBase = (struct IntuitionBase *)
+         OpenLibrary("intuition.library", amii_libvers )) == NULL)
+    {
+       Abort(AG_OpenLib | AO_Intuition);
+    }
+
+    if ( (GfxBase = (struct GfxBase *)
+             OpenLibrary("graphics.library", amii_libvers )) == NULL)
+    {
+       Abort(AG_OpenLib | AO_GraphicsLib);
+    }
+
+    if( (LayersBase = (struct Library *)
+               OpenLibrary("layers.library", amii_libvers )) == NULL)
+    {
+       Abort(AG_OpenLib | AO_LayersLib);
+    }
+
+    if ((GadToolsBase = OpenLibrary("gadtools.library", amii_libvers)) == NULL) {
+       Abort(AG_OpenLib | AO_GadTools);
+    }
+
+    if ((AslBase = OpenLibrary("asl.library", amii_libvers)) == NULL) {
+       Abort(AG_OpenLib);
+    }
+
+    amiIDisplay=(struct amii_DisplayDesc *)alloc(sizeof(struct amii_DisplayDesc));
+    memset( amiIDisplay, 0, sizeof( struct amii_DisplayDesc ) );
+
+    /* Use Intuition sizes for overscan screens... */
+
+    amiIDisplay->xpix = 0;
+#ifdef INTUI_NEW_LOOK
+    if( IntuitionBase->LibNode.lib_Version >= 37 )
+    {
+       if( wbscr = LockPubScreen( "Workbench" ) )
+       {
+           amiIDisplay->xpix = wbscr->Width;
+           amiIDisplay->ypix = wbscr->Height;
+           UnlockPubScreen( NULL, wbscr );
+       }
+    }
+#endif
+    if( amiIDisplay->xpix == 0 )
+    {
+       amiIDisplay->ypix = GfxBase->NormalDisplayRows;
+       amiIDisplay->xpix = GfxBase->NormalDisplayColumns;
+    }
+
+    amiIDisplay->cols = amiIDisplay->xpix / FONTWIDTH;
+
+    amiIDisplay->toplin=0;
+    amiIDisplay->rawprint=0;
+    amiIDisplay->lastwin=0;
+
+    if( bigscreen == 0 )
+    {
+       if( ( GfxBase->ActiView->ViewPort->Modes & LACE ) == LACE )
+       {
+           amiIDisplay->ypix *= 2;
+           NewHackScreen.ViewModes |= LACE;
+           bigscreen = 1;
+       }
+       else if( GfxBase->NormalDisplayRows >= 300 ||
+                amiIDisplay->ypix >= 300 )
+       {
+           bigscreen = 1;
+       }
+    }
+    else if( bigscreen == -1 )
+    {
+       bigscreen = 0;
+       forcenobig = 1;
+    }
+    else if( bigscreen )
+    {
+       /* If bigscreen requested and we don't have enough rows in
+        * noninterlaced mode, switch to interlaced...
+        */
+       if( GfxBase->NormalDisplayRows < 300 )
+       {
+           amiIDisplay->ypix *= 2;
+           NewHackScreen.ViewModes |= LACE;
+       }
+    }
+
+    if( !bigscreen )
+    {
+       alwaysinvent = 0;
+    }
+    amiIDisplay->rows = amiIDisplay->ypix / FONTHEIGHT;
+
+#ifdef HACKFONT
+    /*
+     *  Load the fonts that we need.
+     */
+
+    if( DiskfontBase =
+               OpenLibrary( "diskfont.library", amii_libvers  ) )
+    {
+       Hack80.ta_Name -= SIZEOF_DISKNAME;
+       HackFont = OpenDiskFont( &Hack80 );
+       Hack80.ta_Name += SIZEOF_DISKNAME;
+
+       /* Textsfont13 is filled in with "FONT=" settings. The default is
+        * courier/13.
+        */
+       TextsFont = NULL;
+       if( bigscreen )
+           TextsFont = OpenDiskFont( &TextsFont13 );
+
+       /* Try hack/8 for texts if no user specified font */
+       if( TextsFont == NULL )
+       {
+           Hack80.ta_Name -= SIZEOF_DISKNAME;
+           TextsFont = OpenDiskFont( &Hack80 );
+           Hack80.ta_Name += SIZEOF_DISKNAME;
+       }
+
+       /* If no fonts, make everything topaz 8 for non-view windows.
+        */
+       Hack80.ta_Name = "topaz.font";
+       RogueFont = OpenFont( &Hack80 );
+       if(!RogueFont) panic("Can't get topaz:8");
+       if( !HackFont || !TextsFont )
+       {
+           if( !HackFont )
+           {
+               HackFont = OpenFont( &Hack80 );
+               if( !HackFont )
+                   panic( "Can't get a map font, topaz:8" );
+           }
+
+           if( !TextsFont )
+           {
+               TextsFont = OpenFont( &Hack80 );
+               if( !TextsFont )
+                   panic( "Can't open text font" );
+           }
+       }
+       CloseLibrary(DiskfontBase);
+       DiskfontBase = NULL;
+    }
+#endif
+
+    /* Adjust getlin window size to font */
+
+    if (TextsFont) {
+       extern SHORT BorderVectors1[];
+       extern SHORT BorderVectors2[];
+       extern struct Gadget Gadget2;
+       extern struct Gadget String;
+       extern struct NewWindow StrWindow;
+       BorderVectors1[2] += (TextsFont->tf_XSize-8)*6; /* strlen("Cancel") == 6 */
+       BorderVectors1[4] += (TextsFont->tf_XSize-8)*6;
+       BorderVectors1[5] += TextsFont->tf_YSize-8;
+       BorderVectors1[7] += TextsFont->tf_YSize-8;
+       BorderVectors2[2] += (TextsFont->tf_XSize-8)*6;
+       BorderVectors2[4] += (TextsFont->tf_XSize-8)*6;
+       BorderVectors2[5] += TextsFont->tf_YSize-8;
+       BorderVectors2[7] += TextsFont->tf_YSize-8;
+       Gadget2.TopEdge += TextsFont->tf_YSize-8;
+       Gadget2.Width += (TextsFont->tf_XSize-8)*6;
+       Gadget2.Height += TextsFont->tf_YSize-8;
+       String.LeftEdge += (TextsFont->tf_XSize-8)*6;
+       String.TopEdge += TextsFont->tf_YSize-8;
+       String.Width += TextsFont->tf_XSize-8;
+       String.Height += TextsFont->tf_YSize-8;
+       StrWindow.Width += (TextsFont->tf_XSize-8)*7;
+       StrWindow.Height += (TextsFont->tf_YSize-8)*2; /* Titlebar + 1 row of gadgets */
+    }
+
+    /* This is the size screen we want to open, within reason... */
+
+    NewHackScreen.Width = max( WIDTH, amiIDisplay->xpix );
+    NewHackScreen.Height = max( SCREENHEIGHT, amiIDisplay->ypix );
+    {
+       static char fname[18];
+       sprintf(fname,"NetHack %d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
+       NewHackScreen.DefaultTitle=fname;
+    }
+#if 0
+    NewHackScreen.BlockPen = C_BLACK;
+    NewHackScreen.DetailPen = C_WHITE;
+#endif
+#ifdef INTUI_NEW_LOOK
+    if( IntuitionBase->LibNode.lib_Version >= 37 )
+    {
+       int i;
+       struct DimensionInfo dims;
+       DisplayInfoHandle handle;
+       struct DisplayInfo disp;
+       ULONG modeid = DEFAULT_MONITOR_ID|HIRES_KEY;
+
+       NewHackScreen.Width = STDSCREENWIDTH;
+       NewHackScreen.Height = STDSCREENHEIGHT;
+
+#ifdef HACKFONT
+       if (TextsFont) {
+           NewHackScreen.Font = &TextsFont13;
+       }
+#endif
+
+       if ( amii_scrnmode == 0xffffffff ) {
+           struct ScreenModeRequester *SMR;
+#ifdef __GNUC__
+           SM_FilterHook.h_Entry = (void *)&SM_Filter;
+#else
+           SM_FilterHook.h_Entry = (ULONG(*)())SM_Filter;
+#endif
+           SM_FilterHook.h_Data = 0;
+           SM_FilterHook.h_SubEntry = 0;
+           SMR = AllocAslRequest(ASL_ScreenModeRequest,NULL);
+           if (AslRequestTags(SMR,
+                               ASLSM_FilterFunc, (ULONG)&SM_FilterHook,
+                               TAG_END))
+               amii_scrnmode = SMR->sm_DisplayID;
+           else
+               amii_scrnmode = 0;
+           FreeAslRequest(SMR);
+       }
+
+       if( forcenobig == 0 )
+       {
+           if( ( wbscr = LockPubScreen( "Workbench" ) ) != NULL ||
+               ( wbscr = LockPubScreen( NULL ) ) != NULL )
+           {
+               /* Get the default pub screen's size */
+               modeid = GetVPModeID( &wbscr->ViewPort );
+               if( modeid == INVALID_ID ||
+                   ModeNotAvailable( modeid ) ||
+                   ( handle = FindDisplayInfo( modeid ) ) == NULL ||
+                   GetDisplayInfoData( handle, (char *)&dims, sizeof( dims ),
+                       DTAG_DIMS, modeid ) <= 0 ||
+                   GetDisplayInfoData( handle, (char *)&disp, sizeof( disp ),
+                       DTAG_DISP, modeid ) <= 0 )
+               {
+                   modeid = DEFAULT_MONITOR_ID|HIRES_KEY;
+                   /* If the display database seems to not work, use the screen
+                    * dimensions
+                    */
+                   NewHackScreen.Height = wbscr->Height;
+                   NewHackScreen.Width = wbscr->Width;
+               
+                   /*
+                    * Request LACE if it looks laced.  For 2.1/3.0, we will get
+                    * promoted to the users choice of modes (if promotion is allowed)
+                    * If the user is using a dragable screen, things will get hosed
+                    * but that is life...
+                    */
+                   if( wbscr->ViewPort.Modes & LACE )
+                       NewHackScreen.ViewModes |= LACE;
+                   modeid = -1;
+               }
+               else
+               {
+                   /* Use the display database to get the correct information */
+                   if( disp.PropertyFlags & DIPF_IS_LACE )
+                       NewHackScreen.ViewModes |= LACE;
+                   NewHackScreen.Height = dims.StdOScan.MaxY+1;
+                   NewHackScreen.Width = dims.StdOScan.MaxX+1;
+               }
+               NewHackScreen.TopEdge = 0;
+               NewHackScreen.LeftEdge = 0;
+
+               UnlockPubScreen( NULL, wbscr );
+           }
+       }
+
+       for( i = 0; scrntags[i].ti_Tag != TAG_DONE; ++i )
+       {
+           switch( scrntags[i].ti_Tag )
+           {
+               case SA_DisplayID:
+                   if( !amii_scrnmode || ModeNotAvailable( amii_scrnmode ) )
+                   {
+                       if( ModeNotAvailable( modeid ) )
+                       {
+                           scrntags[i].ti_Tag = TAG_IGNORE;
+                           break;
+                       }
+                       else
+                           scrntags[i].ti_Data = (long)modeid;
+                   }
+                   else
+                       modeid = scrntags[i].ti_Data = (long)amii_scrnmode;
+                   if( ( handle = FindDisplayInfo( modeid ) ) != NULL &&
+                       GetDisplayInfoData( handle, (char *)&dims, sizeof( dims ),
+                           DTAG_DIMS, modeid ) > 0 &&
+                       GetDisplayInfoData( handle, (char *)&disp, sizeof( disp ),
+                           DTAG_DISP, modeid ) > 0 )
+                   {
+                       if( disp.PropertyFlags & DIPF_IS_LACE )
+                           NewHackScreen.ViewModes |= LACE;
+                       NewHackScreen.Height = dims.StdOScan.MaxY+1;
+                       NewHackScreen.Width = dims.StdOScan.MaxX+1;
+                   }
+                   break;
+
+               case SA_Pens:
+                   scrntags[i].ti_Data = (long)flags.amii_dripens;
+                   break;
+           }
+       }
+    }
+#endif
+
+    if( WINVERS_AMIV )
+       amii_bmhd = ReadTileImageFiles( );
+    else
+       memcpy( amii_initmap, amii_init_map, sizeof( amii_initmap ) );
+    memcpy(flags.amii_curmap,amii_initmap,sizeof(flags.amii_curmap));
+
+    /* Find out how deep the screen needs to be, 32 planes is enough! */
+    for( i = 0; i < 32; ++i )
+    {
+       if( ( 1L << i ) >= amii_numcolors )
+           break;
+    }
+
+    NewHackScreen.Depth = i;
+
+    /* If for some reason Height/Width became smaller than the required,
+       have the required one */
+    if (NewHackScreen.Height < SCREENHEIGHT)
+       NewHackScreen.Height = SCREENHEIGHT;
+    if (NewHackScreen.Width < WIDTH)
+       NewHackScreen.Width = WIDTH;
+#ifdef HACKFONT
+    i = max(TextsFont->tf_XSize, HackFont->tf_XSize);
+    if (NewHackScreen.Width < 80*i+4)
+       NewHackScreen.Width = 80*i+4;
+#endif
+
+    /* While openscreen fails try fewer colors to see if that is the problem. */
+    while( ( HackScreen = OpenScreen( (void *)&NewHackScreen ) ) == NULL )
+    {
+#ifdef TEXTCOLOR
+       if( --NewHackScreen.Depth < 3 )
+#else
+       if( --NewHackScreen.Depth < 2 )
+#endif
+           Abort( AN_OpenScreen & ~AT_DeadEnd );
+    }
+    amii_numcolors = 1L << NewHackScreen.Depth;
+    if( HackScreen->Height > 300 && forcenobig == 0 )
+       bigscreen = 1;
+    else
+       bigscreen = 0;
+
+#ifdef  INTUI_NEW_LOOK
+    if( IntuitionBase->LibNode.lib_Version >= 37 )
+       PubScreenStatus( HackScreen, 0 );
+#endif
+
+    amiIDisplay->ypix = HackScreen->Height;
+    amiIDisplay->xpix = HackScreen->Width;
+
+    LoadRGB4(&HackScreen->ViewPort, flags.amii_curmap, amii_numcolors );
+
+    VisualInfo = GetVisualInfo(HackScreen, TAG_END);
+    MenuStrip = CreateMenus(GTHackMenu, TAG_END);
+    LayoutMenus(MenuStrip, VisualInfo, GTMN_NewLookMenus, TRUE, TAG_END);
+
+    /* Display the copyright etc... */
+
+    if( WIN_BASE == WIN_ERR )
+       WIN_BASE = amii_create_nhwindow( NHW_BASE );
+    amii_clear_nhwindow( WIN_BASE );
+    amii_putstr( WIN_BASE, 0, "" );
+    amii_putstr( WIN_BASE, 0, "" );
+    amii_putstr( WIN_BASE, 0, "" );
+    amii_putstr( WIN_BASE, 0, COPYRIGHT_BANNER_A);
+    amii_putstr( WIN_BASE, 0, COPYRIGHT_BANNER_B);
+    amii_putstr( WIN_BASE, 0, COPYRIGHT_BANNER_C);
+    amii_putstr( WIN_BASE, 0, "");
+
+    Initialized = 1;
+}
+
+void
+amii_sethipens( struct Window *w, int type, int attr )
+{
+    switch( type )
+    {
+       default:
+           SetAPen( w->RPort, attr ? C_RED : amii_otherAPen );
+           SetBPen( w->RPort, C_BLACK );
+           break;
+       case NHW_STATUS:
+           SetAPen( w->RPort, attr ? C_WHITE : amii_statAPen );
+           SetBPen( w->RPort, amii_statBPen );
+           break;
+       case NHW_MESSAGE:
+           SetAPen( w->RPort, attr ? C_WHITE : amii_msgAPen );
+           SetBPen( w->RPort, amii_msgBPen );
+           break;
+       case NHW_MENU:
+           SetAPen( w->RPort, attr ? C_BLACK : amii_menuAPen );
+           SetBPen( w->RPort, amii_menuBPen );
+           break;
+       case NHW_TEXT:
+           SetAPen( w->RPort, attr ? C_BLACK : amii_textAPen );
+           SetBPen( w->RPort, amii_textBPen );
+       case -2:
+           SetBPen( w->RPort, amii_otherBPen );
+           SetAPen( w->RPort, attr ? C_RED : amii_otherAPen );
+           break;
+    }
+}
+
+void
+amii_setfillpens( struct Window *w, int type )
+{
+    switch( type )
+    {
+    case NHW_MESSAGE:
+       SetAPen( w->RPort, amii_msgBPen );
+       SetBPen( w->RPort, amii_msgBPen );
+       break;
+    case NHW_STATUS:
+       SetAPen( w->RPort, amii_statBPen );
+       SetBPen( w->RPort, amii_statBPen );
+       break;
+    case NHW_MENU:
+       SetAPen( w->RPort, amii_menuBPen );
+       SetBPen( w->RPort, amii_menuBPen );
+       break;
+    case NHW_TEXT:
+       SetAPen( w->RPort, amii_textBPen );
+       SetBPen( w->RPort, amii_textBPen );
+       break;
+    case NHW_MAP:
+    case NHW_BASE:
+    case NHW_OVER:
+    default:
+       SetAPen( w->RPort, C_BLACK );
+       SetBPen( w->RPort, C_BLACK );
+       break;
+    case -2:
+       SetAPen( w->RPort, amii_otherBPen );
+       SetBPen( w->RPort, amii_otherBPen );
+       break;
+    }
+}
+
+void
+amii_setdrawpens( struct Window *w, int type )
+{
+    switch( type )
+    {
+    case NHW_MESSAGE:
+       SetAPen( w->RPort, amii_msgAPen );
+       SetBPen( w->RPort, amii_msgBPen );
+       break;
+    case NHW_STATUS:
+       SetAPen( w->RPort, amii_statAPen );
+       SetBPen( w->RPort, amii_statBPen );
+       break;
+    case NHW_MENU:
+       SetAPen( w->RPort, amii_menuAPen );
+       SetBPen( w->RPort, amii_menuBPen );
+       break;
+    case NHW_TEXT:
+       SetAPen( w->RPort, amii_textAPen );
+       SetBPen( w->RPort, amii_textBPen );
+       break;
+    case NHW_MAP:
+    case NHW_BASE:
+    case NHW_OVER:
+       SetAPen( w->RPort, C_WHITE );
+       SetBPen( w->RPort, C_BLACK );
+       break;
+    default:
+       SetAPen( w->RPort, amii_otherAPen );
+       SetBPen( w->RPort, amii_otherBPen );
+       break;
+    }
+}
+
+/* Clear the indicated window */
+
+void
+amii_clear_nhwindow(win)
+    register winid win;
+{
+    register struct amii_WinDesc *cw;
+    register struct Window *w;
+
+    if( reclip == 2 ) return;
+
+    if( win == WIN_ERR || ( cw = amii_wins[win] ) == NULL )
+       panic( winpanicstr, win, "clear_nhwindow" );
+
+    /* Clear the overview window too if it is displayed */
+    if( WINVERS_AMIV && ( cw->type == WIN_MAP && WIN_OVER != WIN_ERR && reclip == 0 ) )
+    {
+       amii_clear_nhwindow( WIN_OVER );
+    }
+
+    if( w = cw->win )
+       SetDrMd( w->RPort, JAM2);
+    else
+        return;
+
+    if( (cw->wflags & FLMAP_CURSUP ) )
+    {
+       if( cw->type != NHW_MAP )
+           cursor_off( win );
+       else
+           cw->wflags &= ~FLMAP_CURSUP;
+    }
+
+    amii_setfillpens( w, cw->type );
+    SetDrMd( w->RPort, JAM2 );
+
+    if( cw->type == NHW_MENU || cw->type == NHW_TEXT )
+    {
+       RectFill( w->RPort, w->BorderLeft, w->BorderTop,
+         w->Width - w->BorderRight-1,
+         w->Height - w->BorderBottom-1 );
+    }
+    else
+    {
+       if( cw->type == NHW_MESSAGE )
+       {
+           amii_curs( win, 1, 0 );
+           if( !scrollmsg )
+               TextSpaces( w->RPort, cw->cols );
+       }
+       else
+       {
+           RectFill( w->RPort, w->BorderLeft, w->BorderTop,
+             w->Width - w->BorderRight-1,
+             w->Height - w->BorderBottom-1 );
+       }
+    }
+
+    cw->cury = 0;
+    cw->curx = 0;
+    amii_curs( win, 1, 0 );
+}
+
+/* Dismiss the window from the screen */
+
+void
+dismiss_nhwindow(win)
+    register winid win;
+{
+    register struct Window *w;
+    register struct amii_WinDesc *cw;
+
+    if( win == WIN_ERR || ( cw = amii_wins[win] ) == NULL )
+    {
+       panic(winpanicstr,win, "dismiss_nhwindow");
+    }
+
+    w = cw->win;
+
+    if( w )
+    {
+       /* All windows have this stuff attached to them. */
+       if(     cw->type == NHW_MAP ||
+               cw->type == NHW_OVER ||
+               cw->type == NHW_BASE ||
+               cw->type == NHW_MESSAGE ||
+               cw->type == NHW_STATUS )
+       {
+           ClearMenuStrip( w );
+       }
+
+       /* Save where user like inventory to appear */
+       if( win == WIN_INVEN )
+       {
+           lastinvent.MinX = w->LeftEdge;
+           lastinvent.MinY = w->TopEdge;
+           lastinvent.MaxX = w->Width;
+           lastinvent.MaxY = w->Height;
+       }
+
+       /* Close the window */
+       CloseShWindow( w );
+       cw->win = NULL;
+
+       /* Free copy of NewWindow structure for TEXT/MENU windows. */
+       if( cw->newwin )
+           FreeNewWindow( (void *)cw->newwin );
+       cw->newwin = NULL;
+    }
+}
+
+void
+amii_exit_nhwindows(str)
+    const char *str;
+{
+    /* Seems strange to have to do this... but we need the BASE window
+     * left behind...
+     */
+    kill_nhwindows( 0 );
+    if( WINVERS_AMIV )
+       FreeTileImageFiles( );
+
+    if( str )
+    {
+       raw_print( "" );        /* be sure we're not under the top margin */
+       raw_print( str );
+    }
+}
+
+void
+amii_display_nhwindow(win,blocking)
+    winid win;
+    boolean blocking;
+{
+    menu_item *mip;
+    int cnt;
+    static int lastwin = -1;
+    struct amii_WinDesc *cw;
+
+    if( !Initialized )
+       return;
+    lastwin = win;
+
+    if( win == WIN_ERR || ( cw = amii_wins[win] ) == NULL )
+       panic(winpanicstr,win,"display_nhwindow");
+
+    if( cw->type == NHW_MESSAGE )
+       cw->wflags &= ~FLMAP_SKIP;
+
+    if( cw->type == NHW_MESSAGE || cw->type == NHW_STATUS )
+       return;
+
+    if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] )
+    {
+       flush_glyph_buffer( amii_wins[ WIN_MAP ]->win );
+    }
+
+    if( cw->type == NHW_MENU || cw->type == NHW_TEXT )
+    {
+       cnt = DoMenuScroll( win, blocking, PICK_ONE, &mip );
+    }
+    else if( cw->type==NHW_MAP )
+    {
+       amii_end_glyphout( win );
+       /* Do more if it is time... */
+       if( blocking == TRUE && amii_wins[ WIN_MESSAGE ]->curx )
+       {
+           outmore( amii_wins[ WIN_MESSAGE ] );
+       }
+    }
+}
+
+void
+amii_curs(window, x, y)
+winid window;
+register int x, y;  /* not xchar: perhaps xchar is unsigned and
+              curx-x would be unsigned as well */
+{
+    register struct amii_WinDesc *cw;
+    register struct Window *w;
+    register struct RastPort *rp;
+
+    if( window == WIN_ERR || ( cw = amii_wins[window] ) == NULL )
+       panic(winpanicstr,  window, "curs");
+    if( (w = cw->win) == NULL )
+    {
+       if( cw->type == NHW_MENU || cw->type == NHW_TEXT )
+           return;
+       else
+           panic( "No window open yet in curs() for winid %d\n", window );
+    }
+    amiIDisplay->lastwin = window;
+
+    /* Make sure x is within bounds */
+    if( x > 0 )
+       --x;    /* column 0 is never used */
+    else
+       x = 0;
+
+    cw->curx = x;
+    cw->cury = y;
+
+#ifdef DEBUG
+    if( x<0 || y<0 || y >= cw->rows || x >= cw->cols )
+    {
+       char *s = "[unknown type]";
+       switch(cw->type)
+       {
+           case NHW_MESSAGE: s = "[topl window]"; break;
+           case NHW_STATUS: s = "[status window]"; break;
+           case NHW_MAP: s = "[map window]"; break;
+           case NHW_MENU: s = "[menu window]"; break;
+           case NHW_TEXT: s = "[text window]"; break;
+           case NHW_BASE: s = "[base window]"; break;
+           case NHW_OVER: s = "[overview window]"; break;
+       }
+       impossible("bad curs positioning win %d %s (%d,%d)", window, s, x, y);
+       return;
+    }
+#endif
+
+#ifdef CLIPPING
+    if(clipping && cw->type == NHW_MAP)
+    {
+       x -= clipx;
+       y -= clipy;
+    }
+#endif
+
+    /* Output all saved output before doing cursor movements for MAP */
+
+    if( cw->type == NHW_MAP )
+    {
+       flush_glyph_buffer( w );
+    }
+
+    /* Actually do it */
+
+    rp = w->RPort;
+    if( cw->type == NHW_MENU )
+    {
+       if( WINVERS_AMIV )
+       {
+           if( window == WIN_INVEN )
+           {
+               Move( rp, (x * rp->TxWidth) + w->BorderLeft + 1 + pictdata.xsize + 4,
+                   (y * max(rp->TxHeight,pictdata.ysize + 3) ) +
+                    rp->TxBaseline + pictdata.ysize - rp->TxHeight + w->BorderTop + 4 );
+           }
+           else
+           {
+               Move( rp, (x * rp->TxWidth) + w->BorderLeft + 1,
+                   (y * rp->TxHeight) + rp->TxBaseline + w->BorderTop + 1 );
+           }
+       }
+       else
+       {
+           Move( rp, (x * rp->TxWidth) + w->BorderLeft + 1,
+               (y*rp->TxHeight ) + rp->TxBaseline + w->BorderTop + 1 );
+       }
+    }
+    else if( cw->type == NHW_TEXT )
+    {
+       Move( rp, (x * rp->TxWidth) + w->BorderLeft + 1,
+           (y*rp->TxHeight ) + rp->TxBaseline + w->BorderTop + 1 );
+    }
+    else if( cw->type == NHW_MAP || cw->type == NHW_BASE )
+    {
+       /* These coordinate calculations must be synced with those
+        * in flush_glyph_buffer() in winchar.c.  curs_on_u() will
+        * use this code, all other drawing occurs through the glyph
+        * code.  In order for the cursor to appear on top of the hero,
+        * the code must compute X,Y in the same manner relative to
+        * the RastPort coordinates.
+        *
+        * y = w->BorderTop + (g_nodes[i].y-2) * rp->TxHeight +
+        *   rp->TxBaseline + 1;
+        * x = g_nodes[i].x * rp->TxWidth + w->BorderLeft;
+        */
+
+       if( WINVERS_AMIV )
+       {
+           if( cw->type == NHW_MAP )
+           {
+             if(Is_rogue_level(&u.uz)){
+#if 0
+int qqx= (x * w->RPort->TxWidth) + w->BorderLeft;
+int qqy= w->BorderTop + ( (y+1) * w->RPort->TxHeight ) + 1;
+printf("pos: (%d,%d)->(%d,%d)\n",x,y,qqx,qqy);
+#endif
+               SetAPen(w->RPort,C_WHITE); /* XXX should be elsewhere (was 4)*/
+               Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft,
+                       w->BorderTop + ( (y+1) * w->RPort->TxHeight ) + 1 );
+             } else {
+               Move( rp, (x * mxsize) + w->BorderLeft,
+                               w->BorderTop + ( (y+1) * mysize ) + 1 );
+             }
+           }
+           else
+           {
+               Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft,
+                           w->BorderTop + ( (y + 1) * w->RPort->TxHeight ) +
+                           w->RPort->TxBaseline + 1 );
+           }
+       }
+       else
+       {
+           Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft,
+                       w->BorderTop + ( y * w->RPort->TxHeight ) +
+                       w->RPort->TxBaseline + 1 );
+       }
+    }
+    else if( WINVERS_AMIV && cw->type == NHW_OVER )
+    {
+       Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2,
+                       w->BorderTop + w->RPort->TxBaseline + 3 );
+    }
+    else if( cw->type == NHW_MESSAGE && !scrollmsg )
+    {
+       Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2,
+                       w->BorderTop + w->RPort->TxBaseline + 3 );
+    }
+    else if( cw->type == NHW_STATUS )
+    {
+       Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2,
+                       (y*(w->RPort->TxHeight+1)) + w->BorderTop +
+                       w->RPort->TxBaseline + 1 );
+    }
+    else
+    {
+       Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2,
+                       (y*w->RPort->TxHeight) + w->BorderTop +
+                       w->RPort->TxBaseline + 1 );
+    }
+}
+
+void
+amii_set_text_font( name, size )
+    char *name;
+    int size;
+{
+    register int i;
+    register struct amii_WinDesc *cw;
+    int osize = TextsFont13.ta_YSize;
+    static char nname[ 100 ];
+
+    strncpy( nname, name, sizeof( nname ) - 1 );
+    nname[ sizeof( nname ) - 1 ] = 0;
+
+    TextsFont13.ta_Name = nname;
+    TextsFont13.ta_YSize = size;
+
+    /* No alternate text font allowed for 640x269 or smaller */
+    if( !HackScreen || !bigscreen )
+       return;
+
+    /* Look for windows to set, and change them */
+
+    if( DiskfontBase =
+               OpenLibrary( "diskfont.library", amii_libvers  ) )
+    {
+       TextsFont = OpenDiskFont( &TextsFont13 );
+       for( i = 0; TextsFont && i < MAXWIN; ++i )
+       {
+           if( (cw = amii_wins[ i ]) && cw->win != NULL )
+           {
+               switch( cw->type )
+               {
+               case NHW_STATUS:
+                   MoveWindow( cw->win, 0, -( size - osize ) * 2 );
+                   SizeWindow( cw->win, 0, ( size - osize ) * 2 );
+                   SetFont( cw->win->RPort, TextsFont );
+                   break;
+               case NHW_MESSAGE:
+               case NHW_MAP:
+               case NHW_BASE:
+               case NHW_OVER:
+                   SetFont( cw->win->RPort, TextsFont );
+                   break;
+               }
+           }
+       }
+    }
+    CloseLibrary(DiskfontBase);
+    DiskfontBase = NULL;
+}
+
+void
+kill_nhwindows( all )
+    register int all;
+{
+    register int i;
+    register struct amii_WinDesc *cw;
+
+    /* Foreach open window in all of amii_wins[], CloseShWindow, free memory */
+
+    for( i = 0; i < MAXWIN; ++i )
+    {
+       if( (cw = amii_wins[ i ]) && (cw->type != NHW_BASE || all) )
+       {
+           amii_destroy_nhwindow( i );
+       }
+    }
+}
+
+void
+amii_cl_end( cw, curs_pos )
+    register struct amii_WinDesc *cw;
+    register int curs_pos;
+{
+    register struct Window *w = cw->win;
+    register int oy, ox;
+
+    if( !w )
+       panic("NULL window pointer in amii_cl_end()");
+
+    oy = w->RPort->cp_y;
+    ox = w->RPort->cp_x;
+
+    TextSpaces( w->RPort, cw->cols - curs_pos );
+
+    Move( w->RPort, ox, oy );
+}
+
+void
+cursor_off( window )
+    winid window;
+{
+    register struct amii_WinDesc *cw;
+    register struct Window *w;
+    register struct RastPort *rp;
+    int curx, cury;
+    int x, y;
+    long dmode;
+    short apen, bpen;
+    unsigned char ch;
+
+    if( window == WIN_ERR || ( cw = amii_wins[window] ) == NULL )
+    {
+       iflags.window_inited=0;
+       panic(winpanicstr,window, "cursor_off");
+    }
+
+    if( !(cw->wflags & FLMAP_CURSUP ) )
+       return;
+
+    w = cw->win;
+
+    if( !w )
+       return;
+
+    cw->wflags &= ~FLMAP_CURSUP;
+    rp = w->RPort;
+
+    /* Save the current information */
+    curx = rp->cp_x;
+    cury = rp->cp_y;
+    x = cw->cursx;
+    y = cw->cursy;
+    dmode = rp->DrawMode;
+    apen = rp->FgPen;
+    bpen = rp->BgPen;
+    SetAPen( rp, cw->curs_apen );
+    SetBPen( rp, cw->curs_bpen );
+    SetDrMd( rp, COMPLEMENT );
+/*printf("CURSOR OFF: %d %d\n",x,y);*/
+
+    if( WINVERS_AMIV && cw->type == NHW_MAP)
+    {
+       cursor_common(rp, x, y);
+       if(Is_rogue_level(&u.uz))
+           Move(rp,curx,cury);
+    }
+    else
+    {
+       ch = CURSOR_CHAR;
+       Move( rp, x, y );
+       Text( rp, &ch, 1 );
+
+       /* Put back the other stuff */
+
+       Move( rp, curx, cury );
+    }
+    SetDrMd( rp, dmode );
+    SetAPen( rp, apen );
+    SetBPen( rp, bpen );
+}
+
+void
+cursor_on( window )
+    winid window;
+{
+    int x, y;
+    register struct amii_WinDesc *cw;
+    register struct Window *w;
+    register struct RastPort *rp;
+    unsigned char ch;
+    long dmode;
+    short apen, bpen;
+
+    if( window == WIN_ERR || ( cw = amii_wins[window] ) == NULL )
+    {
+       /* tty does this differently - is this OK? */
+       iflags.window_inited=0;
+       panic(winpanicstr,window, "cursor_on");
+    }
+
+/*printf("CURSOR ON: %d %d\n",cw->win->RPort->cp_x, cw->win->RPort->cp_y);*/
+    if( (cw->wflags & FLMAP_CURSUP ) )
+       cursor_off( window );
+
+    w = cw->win;
+
+    if( !w )
+       return;
+
+    cw->wflags |= FLMAP_CURSUP;
+    rp = w->RPort;
+
+    /* Save the current information */
+
+#ifdef DISPMAP
+    if( WINVERS_AMIV && cw->type == NHW_MAP && !Is_rogue_level(&u.uz))
+       x = cw->cursx = (rp->cp_x & -8) + 8;
+    else
+#endif
+       x = cw->cursx = rp->cp_x;
+    y = cw->cursy = rp->cp_y;
+    apen = rp->FgPen;
+    bpen = rp->BgPen;
+    dmode = rp->DrawMode;
+
+    /* Draw in complement mode. The cursor body will be C_WHITE */
+
+    cw->curs_apen = 0xff; /* Last color/all planes, regardless of depth */
+    cw->curs_bpen = 0xff;
+    SetAPen( rp, cw->curs_apen );
+    SetBPen( rp, cw->curs_bpen );
+    SetDrMd( rp, COMPLEMENT );
+    if( WINVERS_AMIV && cw->type == NHW_MAP)
+    {
+       cursor_common(rp, x, y);
+    }
+    else
+    {
+       Move( rp, x, y );
+       ch = CURSOR_CHAR;
+       Text( rp, &ch, 1 );
+       Move( rp, x, y );
+    }
+
+    SetDrMd( rp, dmode );
+    SetAPen( rp, apen );
+    SetBPen( rp, bpen );
+}
+
+static void
+cursor_common(rp, x, y)
+       struct RastPort *rp;
+       int x,y;
+{
+    int x1,x2,y1,y2;
+
+    if(Is_rogue_level(&u.uz)){
+       x1 = x-2;               y1 = y-rp->TxHeight;
+       x2 = x+rp->TxWidth+1;   y2 = y+3;
+/*printf("COMM: (%d %d) (%d %d)  (%d %d) (%d %d)\n",x1,y1,x2,y2,x1+2,y1+2,x2-2,y2-2);*/
+    } else {
+       x1 = x;                 y1 = y-mysize-1;
+       x2 = x+mxsize-1;        y2 = y-2;
+       RectFill(rp, x1, y1, x2, y2);
+    }
+
+    RectFill(rp, x1+2, y1+2, x2-2, y2-2);
+}
+
+void amii_suspend_nhwindows( str )
+    const char *str;
+{
+    if( HackScreen )
+       ScreenToBack( HackScreen );
+}
+
+void amii_resume_nhwindows()
+{
+    if( HackScreen )
+       ScreenToFront( HackScreen );
+}
+
+void amii_bell()
+{
+    DisplayBeep( NULL );
+}
+
+void
+removetopl(cnt)
+       int cnt;
+{
+    struct amii_WinDesc *cw=amii_wins[WIN_MESSAGE];
+                                       /* NB - this is sufficient for
+                                        * yn_function, but that's it
+                                        */
+    if(cw->curx < cnt)cw->curx=0;
+    else cw->curx -= cnt;
+
+    amii_curs(WIN_MESSAGE, cw->curx+1, cw->cury);
+    amii_cl_end(cw, cw->curx);
+}
+/*#endif /* AMIGA_INTUITION */
+
+#ifdef  PORT_HELP
+void
+port_help()
+{
+    display_file( PORT_HELP, 1 );
+}
+#endif
+
+/*
+ *  print_glyph
+ *
+ *  Print the glyph to the output device.  Don't flush the output device.
+ *
+ *  Since this is only called from show_glyph(), it is assumed that the
+ *  position and glyph are always correct (checked there)!
+ */
+
+void
+amii_print_glyph(win,x,y,glyph)
+    winid win;
+    xchar x,y;
+    int glyph;
+{
+    struct amii_WinDesc *cw;
+    uchar   ch;
+    int     color, och;
+    extern const int zapcolors[];
+    unsigned special;
+
+    /* In order for the overview window to work, we can not clip here */
+    if( !WINVERS_AMIV )
+    {
+#ifdef CLIPPING
+       /* If point not in visible part of window just skip it */
+       if( clipping )
+       {
+           if( x <= clipx || y < clipy || x >= clipxmax || y >= clipymax )
+               return;
+       }
+#endif
+    }
+
+    if( win == WIN_ERR || (cw=amii_wins[win]) == NULL || cw->type != NHW_MAP)
+    {
+       panic(winpanicstr,win,"amii_print_glyph");
+    }
+
+#if 0
+{
+static int x=-1;
+if(u.uz.dlevel != x){
+ fprintf(stderr,"lvlchg: %d (%d)\n",u.uz.dlevel,Is_rogue_level(&u.uz));
+ x = u.uz.dlevel;
+}
+}
+#endif
+    if(
+       WINVERS_AMIV
+#ifdef REINCARNATION
+       && !Is_rogue_level(&u.uz)
+#endif
+    )
+    {
+       amii_curs(win,x,y);
+       amiga_print_glyph(win,0,glyph);
+    }
+    else               /* AMII, or Rogue level in either version */
+    {
+       /* map glyph to character and color */
+       mapglyph(glyph, &och, &color, &special, x, y);
+                               /* XXX next if should be ifdef REINCARNATION */
+       ch = (uchar)och;
+       if( WINVERS_AMIV ){                     /* implies Rogue level here */
+           amii_curs(win,x,y);
+           amiga_print_glyph(win,NO_COLOR,ch + 10000);
+       } else {
+               /* Move the cursor. */
+           amii_curs(win,x,y+2);
+
+#ifdef TEXTCOLOR
+               /* Turn off color if rogue level. */
+# ifdef REINCARNATION
+           if (Is_rogue_level(&u.uz))
+               color = NO_COLOR;
+#  endif
+
+           amiga_print_glyph(win,color,ch);
+#else
+           g_putch(ch);    /* print the character */
+#endif
+           cw->curx++;     /* one character over */
+       }
+    }
+}
+
+/* Make sure the user sees a text string when no windowing is available */
+
+void
+amii_raw_print(s)
+    register const char *s;
+{
+    int argc = 0;
+
+    if( !s )
+       return;
+    if(amiIDisplay)
+       amiIDisplay->rawprint++;
+
+    if (!Initialized) { /* Not yet screen open ... */
+        puts(s);
+        fflush(stdout);
+        return;
+    }
+
+    if( Initialized == 0 && WIN_BASE == WIN_ERR )
+           init_nhwindows(&argc, (char **)0);
+
+    if( amii_rawprwin != WIN_ERR )
+       amii_putstr( amii_rawprwin, 0, s );
+    else if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] )
+       amii_putstr( WIN_MAP, 0, s );
+    else if( WIN_BASE != WIN_ERR && amii_wins[ WIN_BASE ] )
+       amii_putstr( WIN_BASE, 0, s );
+    else
+    {
+       puts( s);
+       fflush(stdout);
+    }
+}
+
+/* Make sure the user sees a bold text string when no windowing
+ * is available
+ */
+
+void
+amii_raw_print_bold(s)
+    register const char *s;
+{
+    int argc = 0;
+
+    if( !s )
+       return;
+
+    if(amiIDisplay)
+       amiIDisplay->rawprint++;
+
+    if (!Initialized) { /* Not yet screen open ... */
+        puts(s);
+        fflush(stdout);
+        return;
+    }
+
+    if( Initialized == 0 && WIN_BASE == WIN_ERR )
+           init_nhwindows(&argc, (char **)0);
+
+    if( amii_rawprwin != WIN_ERR )
+       amii_putstr( amii_rawprwin, 1, s );
+    else if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] )
+       amii_putstr( WIN_MAP, 1, s );
+    else if( WIN_BASE != WIN_ERR && amii_wins[ WIN_BASE ] )
+       amii_putstr( WIN_BASE, 1, s );
+    else
+    {
+       printf("\33[1m%s\33[0m\n",s);
+       fflush(stdout);
+    }
+}
+
+/* Rebuild/update the inventory if the window is up.
+ */
+void
+amii_update_inventory()
+{
+    register struct amii_WinDesc *cw;
+
+    if( WIN_INVEN != WIN_ERR && ( cw = amii_wins[ WIN_INVEN ] ) &&
+                               cw->type == NHW_MENU && cw->win )
+    {
+       display_inventory( NULL, FALSE );
+    }
+}
+
+/* Humm, doesn't really do anything useful */
+
+void
+amii_mark_synch()
+{
+    if(!amiIDisplay)
+       fflush(stderr);
+/* anything else?  do we need this much? */
+}
+
+/* Wait for everything to sync.  Nothing is asynchronous, so we just
+ * ask for a key to be pressed.
+ */
+void
+amii_wait_synch()
+{
+    if(!amiIDisplay || amiIDisplay->rawprint)
+    {
+       if(amiIDisplay) amiIDisplay->rawprint=0;
+    }
+    else
+    {
+       if( WIN_MAP != WIN_ERR )
+       {
+           display_nhwindow(WIN_MAP,TRUE);
+           flush_glyph_buffer( amii_wins[ WIN_MAP ]->win );
+       }
+    }
+}
+
+void
+amii_setclipped()
+{
+#ifdef CLIPPING
+    clipping = TRUE;
+    clipx=clipy=0;
+    clipxmax=CO;
+    clipymax=LI;
+/* some of this is now redundant with top of amii_cliparound XXX */
+#endif
+}
+
+/* XXX still to do: suppress scrolling if we violate the boundary but the
+ * edge of the map is already displayed
+ */
+void
+amii_cliparound(x,y)
+    register int x,y;
+{
+    extern boolean restoring;
+#ifdef CLIPPING
+    int oldx = clipx, oldy = clipy;
+    int oldxmax = clipxmax, oldymax = clipymax;
+    int COx, LIx;
+#define        SCROLLCNT       1       /* Get there in 3 moves... */
+    int scrollcnt = SCROLLCNT; /* ...or 1 if we changed level */
+    if (!clipping)             /* And 1 in anycase, cleaner, simpler, quicker */
+       return;
+
+    if(Is_rogue_level(&u.uz)){
+       struct Window *w = amii_wins[WIN_MAP]->win;
+       struct RastPort *rp = w->RPort;
+
+       COx = (w->Width-w->BorderLeft-w->BorderRight)/rp->TxWidth;
+       LIx = (w->Height-w->BorderTop-w->BorderBottom)/rp->TxHeight;
+    }else{
+       COx = CO;
+       LIx = LI;
+    }
+               /*
+                * On a level change, move the clipping region so that for a
+                * reasonablely large window extra motion is avoided; for
+                * the rogue level hopefully this means no motion at all.
+                */
+    {
+       static d_level saved_level = {127,127};         /* XXX */
+
+       if(!on_level(&u.uz, &saved_level)){
+           scrollcnt = 1;      /* jump with blanking */
+           clipx=clipy=0;
+           clipxmax = COx; clipymax = LIx;
+           saved_level = u.uz;         /* save as new current level */
+       }
+    }
+
+    if (x <= clipx + xclipbord ) {
+       clipx = max(0, x - (clipxmax - clipx)/2 );
+       clipxmax = clipx + COx;
+    }
+    else if (x > clipxmax - xclipbord ) {
+       clipxmax = min(COLNO, x + (clipxmax - clipx)/2 );
+       clipx = clipxmax - COx;
+    }
+
+    if (y <= clipy + yclipbord ) {
+       clipy = max(0, y - (clipymax - clipy) / 2);
+       clipymax = clipy + LIx;
+    }
+    else if (y > clipymax - yclipbord ) {
+       clipymax = min(ROWNO, y + (clipymax - clipy) / 2);
+       clipy = clipymax - LIx;
+    }
+
+    reclip = 1;
+    if (clipx != oldx || clipy != oldy || clipxmax != oldxmax || clipymax != oldymax )
+    {
+#ifndef NOSCROLLRASTER
+       struct Window *w = amii_wins[ WIN_MAP ]->win;
+       struct RastPort *rp = w->RPort;
+       int xdelta, ydelta, xmod, ymod, i;
+       int incx, incy, mincx, mincy;
+       int savex, savey, savexmax, saveymax;
+       int scrx, scry;
+
+       if(Is_rogue_level(&u.uz)){
+           scrx = rp->TxWidth;
+           scry = rp->TxHeight;
+       } else {
+           scrx = mxsize;
+           scry = mysize;
+       }
+
+       /* Ask that the glyph routines not draw the overview window */
+       reclip = 2;
+       cursor_off( WIN_MAP );
+
+       /* Compute how far we are moving in terms of tiles */
+       mincx = clipx - oldx ;
+       mincy = clipy - oldy ;
+
+       /* How many tiles to get there in SCROLLCNT moves */
+       incx = ( clipx - oldx )/scrollcnt;
+       incy = ( clipy - oldy )/scrollcnt;
+
+       /* If less than SCROLLCNT tiles, then move by 1 tile if moving at all */
+       if( incx == 0 ) incx = (mincx != 0);
+       if( incy == 0 ) incy = (mincy != 0);
+
+       /* Get count of pixels to move each iteration and final pixel count */
+       xdelta = ((clipx-oldx )*scrx) / scrollcnt;
+       xmod = ((clipx-oldx )*scrx) % scrollcnt;
+       ydelta = ((clipy-oldy )*scry) / scrollcnt;
+       ymod = ((clipy-oldy )*scry) % scrollcnt;
+
+       /* Preserve the final move location */
+       savex = clipx;
+       savey = clipy;
+       saveymax = clipymax;
+       savexmax = clipxmax;
+
+       /*
+        * Set clipping rectangle to be just the region that will be exposed so
+        * that drawing will be faster
+        */
+#if 0  /* Doesn't seem to work quite the way it should */
+       /* In some cases hero is 'centered' offscreen */
+       if( xdelta < 0 )
+       {
+           clipx = oldx;
+           clipxmax = clipx + incx;
+       }
+       else if( xdelta > 0 )
+       {
+           clipxmax = oldxmax;
+           clipx = clipxmax - incx;
+       }
+       else
+       {
+           clipx = oldx;
+           clipxmax = oldxmax;
+       }
+
+       if( ydelta < 0 )
+       {
+           clipy = oldy;
+           clipymax = clipy + incy;
+       }
+       else if( ydelta > 0 )
+       {
+           clipymax = oldymax;
+           clipy = clipymax - incy;
+       }
+       else
+       {
+           clipy = oldy;
+           clipymax = oldymax;
+       }
+#endif
+       /* Now, in scrollcnt moves, move the picture toward the final view */
+       for( i = 0; i < scrollcnt; ++i )
+       {
+#ifdef DISPMAP
+           if( i == scrollcnt - 1 && (xmod != 0 || ymod != 0) &&
+                       (xdelta != 0 || ydelta != 0) )
+           {
+               incx += (clipx - oldx)%scrollcnt;
+               incy += (clipy - oldy)%scrollcnt;
+               xdelta += xmod;
+               ydelta += ymod;
+           }
+#endif
+           /* Scroll the raster if we are scrolling */
+           if( xdelta != 0 || ydelta != 0 )
+           {
+               ScrollRaster( rp, xdelta, ydelta,
+                           w->BorderLeft, w->BorderTop,
+                           w->Width - w->BorderRight - 1,
+                           w->Height - w->BorderBottom - 1 );
+
+               if( mincx == 0 ) incx = 0;
+               else mincx -= incx;
+
+               clipx += incx;
+               clipxmax += incx;
+
+               if( mincy == 0 ) incy = 0;
+               else mincy -= incy;
+
+               clipy += incy;
+               clipymax += incy;
+
+               /* Draw the exposed portion */
+               if (on_level(&u.uz0, &u.uz) && !restoring)
+                   (void) doredraw();
+               flush_glyph_buffer( amii_wins[ WIN_MAP ]->win );
+           }
+       }
+
+       clipx = savex;
+       clipy = savey;
+       clipymax = saveymax;
+       clipxmax = savexmax;
+#endif
+       if (on_level(&u.uz0, &u.uz) && !restoring && moves > 1)
+           (void) doredraw();
+       flush_glyph_buffer( amii_wins[ WIN_MAP ]->win );
+    }
+    reclip = 0;
+#endif
+}
+
+void
+flushIDCMP( port )
+       struct MsgPort *port;
+{
+       struct Message *msg;
+       while( msg = GetMsg( port ) )
+               ReplyMsg( msg );
+}
diff --git a/sys/amiga/winkey.c b/sys/amiga/winkey.c
new file mode 100644 (file)
index 0000000..7f79864
--- /dev/null
@@ -0,0 +1,106 @@
+/*    SCCS Id: @(#)winkey.c    3.1    93/04/02 */
+/* Copyright (c) Gregg Wonderly, Naperville, Illinois,  1991,1992,1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "NH:sys/amiga/windefs.h"
+#include "NH:sys/amiga/winext.h"
+#include "NH:sys/amiga/winproto.h"
+
+amii_nh_poskey(x, y, mod)
+    int*x, *y, *mod;
+{
+    struct amii_WinDesc *cw;
+    WETYPE type;
+    struct RastPort *rp;
+    struct Window *w;
+
+    if( cw = amii_wins[WIN_MESSAGE] )
+    {
+       cw->wflags &= ~FLMAP_SKIP;
+       if( scrollmsg )
+           cw->wflags |= FLMSG_FIRST;
+       cw->disprows = 0;
+    }
+
+    if( WIN_MAP != WIN_ERR && (cw = amii_wins[ WIN_MAP ]) && ( w = cw->win ) )
+    {
+       cursor_on( WIN_MAP );
+    }
+    else
+       panic( "no MAP window opened for nh_poskey\n" );
+
+    rp = w->RPort;
+
+    while( 1 )
+    {
+       type = WindowGetevent( );
+       if( type == WEMOUSE )
+       {
+           *mod = CLICK_1;
+           if( lastevent.un.mouse.qual )
+               *mod = 0;
+
+           /* X coordinates are 1 based, Y are 1 based. */
+           *x = ( (lastevent.un.mouse.x - w->BorderLeft) / mxsize ) + 1;
+           *y = ( ( lastevent.un.mouse.y - w->BorderTop - MAPFTBASELN ) /
+                       mysize ) + 1;
+#ifdef CLIPPING
+           if( clipping )
+           {
+               *x += clipx;
+               *y += clipy;
+           }
+#endif
+           return( 0 );
+       }
+       else if( type == WEKEY )
+       {
+           lastevent.type = WEUNK;
+           return( lastevent.un.key );
+       }
+    }
+}
+
+int
+amii_nhgetch()
+{
+    int ch;
+    struct amii_WinDesc *cw=amii_wins[WIN_MESSAGE];
+
+    if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] )
+    {
+       cursor_on( WIN_MAP );
+    }
+    if(cw)
+       cw->wflags &= ~FLMAP_SKIP;
+
+    ch = WindowGetchar();
+    return( ch );
+}
+
+void
+amii_get_nh_event()
+{
+    /* nothing now - later I have no idea.  Is this just a Mac hook? */
+}
+
+void
+amii_getret()
+{
+    register int c;
+
+    raw_print( "" );
+    raw_print( "Press Return..." );
+
+    c = 0;
+
+    while( c != '\n' && c != '\r' )
+    {
+       if( HackPort )
+           c = WindowGetchar();
+       else
+           c = getchar();
+    }
+    return;
+}
+
diff --git a/sys/amiga/winmenu.c b/sys/amiga/winmenu.c
new file mode 100644 (file)
index 0000000..b2cf1cf
--- /dev/null
@@ -0,0 +1,1597 @@
+/*     SCCS Id: @(#)winmenu.c  3.2     96/02/17        */
+/* Copyright (c) Gregg Wonderly, Naperville, Illinois,  1991,1992,1993,1996. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "NH:sys/amiga/windefs.h"
+#include "NH:sys/amiga/winext.h"
+#include "NH:sys/amiga/winproto.h"
+
+/* Start building the text for a menu */
+void
+amii_start_menu(window)
+    register winid window;
+{
+    register int i;
+    register struct amii_WinDesc *cw;
+    register amii_menu_item *mip;
+
+    if(window == WIN_ERR || (cw = amii_wins[window]) == NULL || cw->type != NHW_MENU)
+       panic(winpanicstr,window, "start_menu");
+
+    amii_clear_nhwindow(window);
+
+    if( cw->data && ( cw->type == NHW_MESSAGE ||
+           cw->type == NHW_MENU || cw->type == NHW_TEXT ) )
+    {
+       for( i = 0; i < cw->maxrow; ++i )
+       {
+           if( cw->data[ i ] )
+               free( cw->data[ i ] );
+       }
+       free( cw->data );
+       cw->data = NULL;
+    }
+
+    for( mip = cw->menu.items, i = 0; (mip = cw->menu.items) && i < cw->menu.count; ++i )
+    {
+       cw->menu.items = mip->next;
+       free( mip );
+    }
+
+    cw->menu.items = 0;
+    cw->menu.count = 0;
+    cw->menu.chr = 'a';
+
+    if( cw->morestr ) free( cw->morestr );
+    cw->morestr = NULL;
+
+    if( window == WIN_INVEN && cw->win != NULL )
+    {
+       if( alwaysinvent )
+           cw->wasup = 1;
+    }
+    cw->cury = cw->rows = cw->maxrow = cw->maxcol = 0;
+    return;
+}
+
+/* Add a string to a menu */
+void
+amii_add_menu(window,glyph, id, ch, gch, attr, str, preselected)
+    register winid window;
+    register int glyph;
+    register const anything *id;
+    register char ch;
+    register char gch;
+    register int attr;
+    register const char *str;
+    register BOOLEAN_P preselected;
+{
+    register struct amii_WinDesc *cw;
+    amii_menu_item *mip;
+    char buf[ 4+BUFSZ ];
+
+    if(str == NULL)return;
+
+    if(window == WIN_ERR || (cw = amii_wins[window]) == NULL || cw->type != NHW_MENU)
+       panic(winpanicstr,window, "add_menu");
+
+    mip = (amii_menu_item *)alloc( sizeof( *mip ) );
+    mip->identifier = *id;
+    mip->selected = preselected;
+    mip->attr = attr;
+    mip->glyph = Is_rogue_level(&u.uz) ? NO_GLYPH : glyph;
+    mip->selector = 0;
+    mip->gselector = gch;
+    mip->count = -1;
+
+    if (id->a_void && !ch && cw->menu.chr != 0)
+    {
+       ch = cw->menu.chr++;
+       if( ch == 'z' )
+           cw->menu.chr = 'A';
+       if( ch == 'Z' )
+           cw->menu.chr = 0;
+    }
+
+    mip->canselect = ( id->a_void != 0 );
+
+    if( id->a_void && ch != '\0')
+    {
+       Sprintf( buf, "%c - %s", ch, str );
+       str = buf;
+       mip->canselect = 1;
+    }
+
+    mip->selector = ch;
+
+    amii_putstr( window, attr, str );
+
+    mip->str = cw->data[ cw->cury - 1 ];
+    cw->menu.count++;
+
+    mip->next = NULL;
+
+    if( cw->menu.items == 0 )
+       cw->menu.last = cw->menu.items = mip;
+    else
+    {
+       cw->menu.last->next = mip;
+       cw->menu.last = mip;
+    }
+}
+
+/* Done building a menu. */
+
+void
+amii_end_menu(window,morestr)
+    register winid window;
+    register const char *morestr;
+{
+    register struct amii_WinDesc *cw;
+
+    if(window == WIN_ERR || (cw=amii_wins[window]) == NULL
+       || cw->type != NHW_MENU )
+       panic(winpanicstr,window, "end_menu");
+
+    if( morestr && *morestr )
+    {
+       anything any;
+#define PROMPTFIRST /* Define this to have prompt first */
+#ifdef PROMPTFIRST
+       amii_menu_item *mip;
+       int i;
+       char *t;
+       mip = cw->menu.last;
+#endif
+       any.a_void = 0;
+       amii_add_menu( window, NO_GLYPH, &any, 0, 0, ATR_NONE, morestr,
+          MENU_UNSELECTED);
+#ifdef PROMPTFIRST /* Do some shuffling. Last first, push others one forward */
+       mip->next = NULL;
+       cw->menu.last->next = cw->menu.items;
+       cw->menu.items = cw->menu.last;
+       cw->menu.last = mip;
+       t = cw->data[cw->cury-1];
+       for (i=cw->cury-1; i>0; i--) {
+           cw->data[i] = cw->data[i-1];
+       }
+       cw->data[0] = t;
+#endif
+    }
+
+    /* If prompt first, don't put same string in title where in most cases
+       it's not entirely visible anyway */
+#ifndef PROMPTFIRST
+    if( morestr )
+       cw->morestr = strdup( morestr );
+#endif
+}
+
+/* Select something from the menu. */
+
+int
+amii_select_menu(window, how, mip )
+    register winid window;
+    register int how;
+    register menu_item **mip;
+{
+    int cnt;
+    register struct amii_WinDesc *cw;
+
+    if( window == WIN_ERR || ( cw=amii_wins[window] ) == NULL ||
+         cw->type != NHW_MENU )
+       panic(winpanicstr,window, "select_menu");
+
+    cnt = DoMenuScroll( window, 1, how, mip );
+
+    /* This would allow the inventory window to stay open. */
+    if( !alwaysinvent || window != WIN_INVEN )
+       dismiss_nhwindow(window);       /* Now tear it down */
+    return cnt;
+}
+
+amii_menu_item *
+find_menu_item( register struct amii_WinDesc *cw, int idx )
+{
+    amii_menu_item *mip;
+    for( mip = cw->menu.items; idx > 0 && mip; mip = mip->next )
+       --idx;
+
+    return( mip );
+}
+
+int
+make_menu_items( register struct amii_WinDesc *cw, register menu_item **rmip )
+{
+    register int idx = 0;
+    register amii_menu_item *mip;
+    register menu_item *mmip;
+
+    for( mip = cw->menu.items; mip; mip = mip->next )
+    {
+       if( mip->selected )
+           ++idx;
+    }
+
+    if( idx )
+    {
+       mmip = *rmip = (menu_item *)alloc( idx * sizeof( *mip ) );
+       for( mip = cw->menu.items; mip; mip = mip->next )
+       {
+           if( mip->selected )
+           {
+               mmip->item = mip->identifier;
+               mmip->count = mip->count;
+               mmip++;
+           }
+       }
+
+       cw->mi = *rmip;
+    }
+    return( idx );
+}
+
+int
+DoMenuScroll( win, blocking, how, retmip )
+    int win, blocking, how;
+    menu_item **retmip;
+{
+    amii_menu_item *amip;
+    register struct Window *w;
+    register struct NewWindow *nw;
+    struct PropInfo *pip;
+    register struct amii_WinDesc *cw;
+    struct IntuiMessage *imsg;
+    struct Gadget *gd;
+    register int wheight, xsize, ysize, aredone = 0;
+    register int txwd, txh;
+    long mics, secs, class, code;
+    long oldmics = 0, oldsecs = 0;
+    int aidx, oidx, topidx, hidden;
+    int totalvis;
+    SHORT mx, my;
+    static char title[ 100 ];
+    int dosize = 1;
+    struct Screen *scrn = HackScreen;
+    int x1,x2,y1,y2;
+    long counting = FALSE, count = 0, reset_counting = FALSE;
+    char countString[32];
+
+    if( win == WIN_ERR || ( cw = amii_wins[ win ] ) == NULL )
+       panic(winpanicstr,win,"DoMenuScroll");
+
+    /*  Initial guess at window sizing values */
+    txwd = txwidth;
+    if( WINVERS_AMIV )
+    {
+       if( win == WIN_INVEN )
+           txh = max( txheight, pictdata.ysize + 3 ); /* interline space */
+       else
+           txh = txheight; /* interline space */
+    }
+    else
+       txh = txheight; /* interline space */
+
+    /* Check to see if we should open the window, should need to for
+     * TEXT and MENU but not MESSAGE.
+     */
+
+    w = cw->win;
+    topidx = 0;
+
+    if( w == NULL )
+    {
+
+#ifdef  INTUI_NEW_LOOK
+       if( IntuitionBase->LibNode.lib_Version >= 37 )
+       {
+           PropScroll.Flags |= PROPNEWLOOK;
+       }
+#endif
+       nw = (void *)DupNewWindow( (void *)(&new_wins[ cw->type ].newwin) );
+       if( !alwaysinvent || win != WIN_INVEN )
+       {
+           xsize = scrn->WBorLeft + scrn->WBorRight + MenuScroll.Width + 1 +
+                               (txwd * cw->maxcol);
+           if( WINVERS_AMIV )
+           {
+               if( win == WIN_INVEN )
+                   xsize += pictdata.xsize + 4;
+           }
+           if( xsize > amiIDisplay->xpix )
+               xsize = amiIDisplay->xpix;
+
+           /* If next row not off window, use it, else use the bottom */
+
+           ysize = ( txh * cw->maxrow ) +                /* The text space */
+                   HackScreen->WBorTop + txheight + 1 +  /* Top border */
+                   HackScreen->WBorBottom + 3;           /* The bottom border */
+           if( ysize > amiIDisplay->ypix )
+               ysize = amiIDisplay->ypix;
+
+           /* Adjust the size of the menu scroll gadget */
+
+           nw->TopEdge = 0;
+           if( cw->type == NHW_TEXT && ysize < amiIDisplay->ypix )
+               nw->TopEdge += ( amiIDisplay->ypix - ysize ) / 2;
+           nw->LeftEdge = amiIDisplay->xpix - xsize;
+           if( cw->type == NHW_MENU )
+           {
+               if( nw->LeftEdge > 10 )
+                   nw->LeftEdge -= 10;
+               else
+                   nw->LeftEdge = 0;
+               if( amiIDisplay->ypix - nw->Height > 10 )
+                   nw->TopEdge += 10;
+               else
+                   nw->TopEdge = amiIDisplay->ypix - nw->Height - 1;
+           }
+           if( cw->type == NHW_TEXT && xsize < amiIDisplay->xpix )
+               nw->LeftEdge -= ( amiIDisplay->xpix - xsize ) / 2;
+       }
+       else if( win == WIN_INVEN )
+       {
+           struct Window *mw = amii_wins[ WIN_MAP ]->win;
+           struct Window *sw = amii_wins[ WIN_STATUS ]->win;
+
+           xsize = scrn->WBorLeft + scrn->WBorRight + MenuScroll.Width + 1 +
+                               (txwd * cw->maxcol);
+
+           /* Make space for the glyph to appear at the left of the description */
+           if( WINVERS_AMIV )
+               xsize += pictdata.xsize + 4;
+
+           if( xsize > amiIDisplay->xpix )
+               xsize = amiIDisplay->xpix;
+
+           /* If next row not off window, use it, else use the bottom */
+
+           ysize = sw->TopEdge - (mw->TopEdge + mw->Height) - 1;
+           if( ysize > amiIDisplay->ypix )
+               ysize = amiIDisplay->ypix;
+
+           /* Adjust the size of the menu scroll gadget */
+
+           nw->TopEdge = mw->TopEdge + mw->Height;
+           nw->LeftEdge = 0;
+       }
+       cw->newwin = (void *)nw;
+       if( nw == NULL )
+           panic("No NewWindow Allocated" );
+
+       nw->Screen = HackScreen;
+
+       if( win == WIN_INVEN )
+       {
+           sprintf( title, "%s the %s's Inventory", plname, pl_character );
+           nw->Title = title;
+           if( lastinvent.MaxX != 0 )
+           {
+               nw->LeftEdge = lastinvent.MinX;
+               nw->TopEdge = lastinvent.MinY;
+               nw->Width = lastinvent.MaxX;
+               nw->Height = lastinvent.MaxY;
+           }
+       }
+       else if( cw->morestr )
+           nw->Title = cw->morestr;
+
+       /* Adjust the window coordinates and size now that we know
+        * how many items are to be displayed.
+        */
+
+       if( ( xsize > amiIDisplay->xpix - nw->LeftEdge ) &&
+           ( xsize < amiIDisplay->xpix ) )
+       {
+           nw->LeftEdge = amiIDisplay->xpix - xsize;
+           nw->Width = xsize;
+       }
+       else
+       {
+           nw->Width = min( xsize, amiIDisplay->xpix - nw->LeftEdge );
+       }
+       nw->Height = min( ysize, amiIDisplay->ypix - nw->TopEdge );
+
+       if( WINVERS_AMIV || WINVERS_AMII )
+       {
+           /* Make sure we are using the correct hook structure */
+           nw->Extension = cw->wintags;
+       }
+
+       /* Now, open the window */
+       w = cw->win = OpenShWindow( (void *)nw );
+
+       if( w == NULL )
+       {
+           char buf[ 130 ];
+
+           sprintf( buf, "No Window Opened For Menu (%d,%d,%d-%d,%d-%d)",
+               nw->LeftEdge, nw->TopEdge, nw->Width, amiIDisplay->xpix,
+               nw->Height, amiIDisplay->ypix );
+           panic( buf );
+       }
+
+#ifdef HACKFONT
+       if( TextsFont )
+           SetFont(w->RPort, TextsFont );
+       else if( HackFont )
+           SetFont(w->RPort, HackFont );
+#endif
+       txwd = w->RPort->TxWidth;
+       if( WINVERS_AMIV )
+       {
+           if( win == WIN_INVEN )
+               txh = max( w->RPort->TxHeight, pictdata.ysize + 3 ); /* interline space */
+           else
+               txh = w->RPort->TxHeight; /* interline space */
+       }
+       else
+           txh = w->RPort->TxHeight; /* interline space */
+
+       /* subtract 2 to account for spacing away from border (1 on each side) */
+       wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) / txh;
+       if( WINVERS_AMIV )
+       {
+           if( win == WIN_INVEN )
+           {
+               cw->cols = ( w->Width - w->BorderLeft -
+                           w->BorderRight - 4 - pictdata.xsize - 3 ) / txwd;
+           }
+           else
+           {
+               cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd;
+           }
+       }
+       else
+       {
+           cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd;
+       }
+       totalvis = CountLines( win );
+    }
+    else
+    {
+       txwd = w->RPort->TxWidth;
+       if( WINVERS_AMIV )
+       {
+           if( win == WIN_INVEN )
+               txh = max( w->RPort->TxHeight, pictdata.ysize + 3 ); /* interline space */
+           else
+               txh = w->RPort->TxHeight; /* interline space */
+       }
+       else
+       {
+           txh = w->RPort->TxHeight; /* interline space */
+       }
+
+       /* subtract 2 to account for spacing away from border (1 on each side) */
+       wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) / txh;
+       if( WINVERS_AMIV )
+       {
+           if( win == WIN_INVEN )
+           {
+               cw->cols = ( w->Width - w->BorderLeft -
+                           w->BorderRight - 4 - pictdata.xsize - 3) / txwd;
+           }
+           else
+               cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd;
+       }
+       else
+       {
+           cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd;
+       }
+
+       totalvis = CountLines( win );
+
+       for( gd = w->FirstGadget; gd && gd->GadgetID != 1; )
+           gd = gd->NextGadget;
+
+       if( gd )
+       {
+           pip = (struct PropInfo *)gd->SpecialInfo;
+           hidden = max( totalvis - wheight, 0 );
+           topidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16;
+       }
+    }
+
+    for( gd = w->FirstGadget; gd && gd->GadgetID != 1; )
+       gd = gd->NextGadget;
+
+    if( !gd ) panic("Can't find scroll gadget" );
+
+    morc = 0;
+    oidx = -1;
+
+#if 0
+    /* Make sure there are no selections left over from last time. */
+/* XXX potential problem for preselection if this is really needed */
+  for( amip = cw->menu.items; amip; amip = amip->next )
+       amip->selected = 0;
+#endif
+
+    DisplayData( win, topidx );
+
+    /* Make the prop gadget the right size and place */
+
+    SetPropInfo( w, gd, wheight, totalvis, topidx );
+    oldsecs = oldmics = 0;
+
+    /* If window already up, don't stop to process events */
+    if( cw->wasup )
+    {
+       aredone = 1;
+       cw->wasup = 0;
+    }
+
+    while( !aredone )
+    {
+       /* Process window messages */
+
+       WaitPort( w->UserPort );
+       while( imsg = (struct IntuiMessage * ) GetMsg( w->UserPort ) )
+       {
+           class = imsg->Class;
+           code = imsg->Code;
+           mics = imsg->Micros;
+           secs = imsg->Seconds;
+           gd = (struct Gadget *) imsg->IAddress;
+           mx = imsg->MouseX;
+           my = imsg->MouseY;
+
+           /* Only do our window or VANILLAKEY from other windows */
+
+           if( imsg->IDCMPWindow != w && class != VANILLAKEY &&
+                                                       class != RAWKEY )
+           {
+               ReplyMsg( (struct Message *) imsg );
+               continue;
+           }
+
+           /* Do DeadKeyConvert() stuff if RAWKEY... */
+           if( class == RAWKEY )
+           {
+               class = VANILLAKEY;
+               code = ConvertKey( imsg );
+           }
+           ReplyMsg( (struct Message *) imsg );
+
+           switch( class )
+           {
+               case NEWSIZE:
+
+                   /*
+                    * Ignore every other newsize, no action needed,
+                    * except RefreshWindowFrame() in case borders got overwritten
+                    * for some reason. It should not happen, but ...
+                    */
+
+                   if( !dosize )
+                   {
+                       RefreshWindowFrame(w);
+                       dosize = 1;
+                       break;
+                   }
+
+                   if( win == WIN_INVEN )
+                   {
+                       lastinvent.MinX = w->LeftEdge;
+                       lastinvent.MinY = w->TopEdge;
+                       lastinvent.MaxX = w->Width;
+                       lastinvent.MaxY = w->Height;
+                   }
+                   else if( win == WIN_MESSAGE )
+                   {
+                       lastmsg.MinX = w->LeftEdge;
+                       lastmsg.MinY = w->TopEdge;
+                       lastmsg.MaxX = w->Width;
+                       lastmsg.MaxY = w->Height;
+                   }
+
+                   /* Find the gadget */
+
+                   for( gd = w->FirstGadget; gd && gd->GadgetID != 1; )
+                       gd = gd->NextGadget;
+
+                   if( !gd )
+                       panic("Can't find scroll gadget" );
+
+                   totalvis = CountLines( win );
+                   wheight = ( w->Height - w->BorderTop -
+                                               w->BorderBottom - 2) / txh;
+                   if( WINVERS_AMIV )
+                   {
+                       if( win == WIN_INVEN )
+                       {
+                           cw->cols = ( w->Width - w->BorderLeft -
+                                       w->BorderRight - 4 - pictdata.xsize - 3) / txwd;
+                       }
+                       else
+                           cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd;
+                   }
+                   else
+                   {
+                       cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd;
+                   }
+
+                   if( wheight < 2 )
+                       wheight = 2;
+
+                   /*
+                    * Clear the right side & bottom. Parts of letters are not erased by
+                    * amii_cl_end if window shrinks and columns decrease.
+                    */
+
+                   if ( WINVERS_AMII || WINVERS_AMIV ) {
+                       amii_setfillpens(w, cw->type);
+                       SetDrMd(w->RPort, JAM2);
+                       x2 = w->Width - w->BorderRight;
+                       y2 = w->Height - w->BorderBottom;
+                       x1 = x2 - w->IFont->tf_XSize - w->IFont->tf_XSize;
+                       y1 = w->BorderTop;
+                       if (x1 < w->BorderLeft)
+                           x1 = w->BorderLeft;
+                       RectFill(w->RPort, x1, y1, x2, y2);
+                       x1 = w->BorderLeft;
+                       y1 = y1 - w->IFont->tf_YSize;
+                       RectFill(w->RPort, x1, y1, x2, y2);
+                       RefreshWindowFrame(w);
+                   }
+
+                   /* Make the prop gadget the right size and place */
+
+                   DisplayData( win, topidx );
+                   SetPropInfo( w, gd, wheight, totalvis, topidx );
+
+                   /* Force the window to a text line boundary <= to
+                    * what the user dragged it to.  This eliminates
+                    * having to clean things up on the bottom edge.
+                    */
+
+                   SizeWindow( w, 0, ( wheight * txh) +
+                           w->BorderTop + w->BorderBottom + 2 - w->Height );
+
+                   /* Don't do next NEWSIZE, we caused it */
+                   dosize = 0;
+                   oldsecs = oldmics = 0;
+                   break;
+
+               case VANILLAKEY:
+#define CTRL(x)     ((x)-'@')
+                   morc = code = map_menu_cmd(code);
+                   if (code == MENU_SELECT_ALL) {
+                       if (how == PICK_ANY) {
+                           amip = cw->menu.items;
+                           while (amip) {
+                               if (amip->canselect && amip->selector) {
+                               /*
+                                * Select those yet unselected
+                                * and apply count if necessary
+                                */
+                                   if (!amip->selected) {
+                                       amip->selected = TRUE;
+                                       if (counting) {
+                                           amip->count = count;
+                                           reset_counting = TRUE;
+                                       /*
+                                        * This makes the assumption that 
+                                        * the string is in format "X - foo"
+                                        * with additional selecting and formatting
+                                        * data in front (size SOFF)
+                                        */
+                                           amip->str[SOFF+2] = '#';
+                                       } else {
+                                           amip->count = -1;
+                                           amip->str[SOFF+2] = '-';
+                                       }
+                                   }
+                               }
+                               amip=amip->next;
+                           }
+                           DisplayData(win, topidx);
+                       }
+                   } else if (code == MENU_UNSELECT_ALL) {
+                       if (how == PICK_ANY) {
+                           amip = cw->menu.items;
+                           while (amip) {
+                               if (amip->selected) {
+                                   amip->selected = FALSE;
+                                   amip->count = -1;
+                                   amip->str[SOFF+2] = '-';
+                               }
+                               amip=amip->next;
+                           }
+                           DisplayData(win, topidx);
+                       }
+                   } else if (code == MENU_INVERT_ALL) {
+                       if (how == PICK_ANY) {
+                           amip = cw->menu.items;
+                           while (amip) {
+                               if (amip->canselect && amip->selector) {
+                                   amip->selected = !amip->selected;
+                                   if (counting && amip->selected) {
+                                       amip->count = count;
+                                       amip->str[SOFF+2] = '#';
+                                       reset_counting = TRUE;
+                                   } else {
+                                       amip->count = -1;
+                                       amip->str[SOFF+2] = '-';
+                                   }
+                               }
+                               amip=amip->next;
+                           }
+                           DisplayData(win, topidx);
+                       }
+                   } else if (code == MENU_SELECT_PAGE) {
+                       if (how == PICK_ANY) {
+                           int i = 0;
+                           amip = cw->menu.items;
+                           while (amip && i++ < topidx)
+                               amip = amip->next;
+                           for (i=0;i < wheight && amip; i++, amip=amip->next) {
+                               if (amip->canselect && amip->selector) {
+                                   if (!amip->selected) {
+                                       if (counting) {
+                                           amip->count = count;
+                                           reset_counting = TRUE;
+                                           amip->str[SOFF+2] = '#';
+                                       } else {
+                                           amip->count = -1;
+                                           amip->str[SOFF+2] = '-';
+                                       }
+                                   }
+                                   amip->selected = TRUE;
+                               }
+                           }
+                           DisplayData(win, topidx);
+                       }
+                   } else if (code == MENU_UNSELECT_PAGE) {
+                       if (how == PICK_ANY) {
+                           int i = 0;
+                           amip = cw->menu.items;
+                           while (amip && i++ < topidx)
+                               amip = amip->next;
+                           for (i=0;i < wheight && amip; i++, amip=amip->next) {
+                               if (amip->selected) {
+                                   amip->selected = FALSE;
+                                   amip->count = -1;
+                                   amip->str[SOFF+2] = '-';
+                               }
+                           }
+                           DisplayData(win, topidx);
+                       }
+                   } else if (code == MENU_INVERT_PAGE) {
+                       if (how == PICK_ANY) {
+                           int i = 0;
+                           amip = cw->menu.items;
+                           while (amip && i++ < topidx)
+                               amip = amip->next;
+                           for (i=0;i < wheight && amip; i++, amip=amip->next) {
+                               if (amip->canselect && amip->selector) {
+                                   amip->selected = !amip->selected;
+                                   if (counting && amip->selected) {
+                                       amip->count = count;
+                                       amip->str[SOFF+2] = '#';
+                                       reset_counting = TRUE;
+                                   } else {
+                                       amip->count = -1;
+                                       amip->str[SOFF+2] = '-';
+                                   }
+                               }
+                           }
+                           DisplayData(win, topidx);
+                       }
+                   } else if (code == MENU_SEARCH && cw->type == NHW_MENU) {
+                       if (how == PICK_ONE || how == PICK_ANY) {
+                           char buf[BUFSZ];
+                           amip = cw->menu.items;
+                           amii_getlin("Search for:", buf);
+                           if (!*buf || *buf == '\033')
+                               break;
+                           while (amip) {
+                               if (amip->canselect && amip->selector && amip->str &&
+                                   strstri(&amip->str[SOFF], buf)) {
+                                   if (how == PICK_ONE) {
+                                       amip->selected = TRUE;
+                                       aredone = 1;
+                                       break;
+                                   }
+                                   amip->selected = !amip->selected;
+                                   if (counting && amip->selected) {
+                                       amip->count = count;
+                                       reset_counting = TRUE;
+                                       amip->str[SOFF+2] = '#';
+                                   } else {
+                                       amip->count = -1;
+                                       reset_counting = TRUE;
+                                       amip->str[SOFF+2] = '-';
+                                   }
+                               }
+                               amip = amip->next;
+                           }
+                       }
+                       DisplayData(win, topidx);
+                   } else if (how == PICK_ANY && isdigit(code) &&
+                              (counting || (!counting && code !='0'))) {
+                       if (count < LARGEST_INT) {
+                           count = count*10 + (long)(code-'0');
+                           if (count > LARGEST_INT)
+                               count = LARGEST_INT;
+                           if (count > 0) {
+                               counting = TRUE;
+                               reset_counting = FALSE;
+                           } else {
+                               reset_counting = TRUE;
+                           }
+                           sprintf(countString, "Count: %d", count);
+                           pline(countString);
+                       }
+                   } else if( code == CTRL('D') || code == CTRL('U') ||
+                              code == MENU_NEXT_PAGE || code == MENU_PREVIOUS_PAGE ||
+                              code == MENU_FIRST_PAGE || code == MENU_LAST_PAGE )
+                   {
+                       int endcnt, i;
+
+                       for( gd = w->FirstGadget; gd && gd->GadgetID != 1; )
+                           gd = gd->NextGadget;
+
+                       if( !gd )
+                           panic("Can't find scroll gadget" );
+
+                       endcnt = wheight; /* /2; */
+                       if( endcnt == 0 )
+                           endcnt = 1;
+
+                       if (code == MENU_FIRST_PAGE) {
+                           topidx = 0;
+                       } else if (code == MENU_LAST_PAGE) {
+                           topidx = cw->maxrow - wheight;
+                       } else for( i = 0; i < endcnt; ++i )
+                       {
+                           if (code == CTRL('D') || code == MENU_NEXT_PAGE)
+                           {
+                               if( topidx + wheight < cw->maxrow )
+                                   ++topidx;
+                               else
+                                   break;
+                           }
+                           else if (code = CTRL('U') || code == MENU_PREVIOUS_PAGE)
+                           {
+                               if( topidx > 0 )
+                                   --topidx;
+                               else
+                                   break;
+                           }
+                       }
+                       /* Make prop gadget the right size and place */
+
+                       DisplayData( win, topidx );
+                       SetPropInfo( w,gd, wheight, totalvis, topidx );
+                       oldsecs = oldmics = 0;
+                   }
+                   else if( code == '\b' )
+                   {
+                       for( gd = w->FirstGadget; gd && gd->GadgetID != 1; )
+                           gd = gd->NextGadget;
+
+                       if( !gd )
+                           panic("Can't find scroll gadget" );
+
+                       if( topidx - wheight - 2 < 0 )
+                       {
+                           topidx = 0;
+                       }
+                       else
+                       {
+                           topidx -= wheight - 2;
+                       }
+                       DisplayData( win, topidx );
+                       SetPropInfo( w, gd, wheight, totalvis, topidx );
+                       oldsecs = oldmics = 0;
+                   }
+                   else if( code == ' ' )
+                   {
+                       for( gd = w->FirstGadget; gd && gd->GadgetID != 1; )
+                           gd = gd->NextGadget;
+
+                       if( !gd )
+                           panic("Can't find scroll gadget" );
+
+                       if( topidx + wheight >= cw->maxrow )
+                       {
+                           morc = 0;
+                           aredone = 1;
+                       }
+                       else
+                       {
+                           /*  If there are still lines to be seen */
+
+                           if( cw->maxrow > topidx + wheight )
+                           {
+                               if( wheight > 2 )
+                                   topidx += wheight - 2;
+                               else
+                                   ++topidx;
+                               DisplayData( win, topidx );
+                               SetPropInfo( w, gd, wheight,
+                                                   totalvis, topidx );
+                           }
+                           oldsecs = oldmics = 0;
+                       }
+                   }
+                   else if( code == '\n' || code == '\r' )
+                   {
+                       for( gd = w->FirstGadget; gd && gd->GadgetID != 1; )
+                           gd = gd->NextGadget;
+
+                       if( !gd )
+                           panic("Can't find scroll gadget" );
+
+                       /* If all line displayed, we are done */
+
+                       if( topidx + wheight >= cw->maxrow )
+                       {
+                           morc = 0;
+                           aredone = 1;
+                       }
+                       else
+                       {
+                           /*  If there are still lines to be seen */
+
+                           if( cw->maxrow > topidx + 1 )
+                           {
+                               ++topidx;
+                               DisplayData( win, topidx );
+                               SetPropInfo( w, gd, wheight,
+                                                   totalvis, topidx );
+                           }
+                           oldsecs = oldmics = 0;
+                       }
+                   }
+                   else if( code == '\33' )
+                   {
+                       if (counting) {
+                           reset_counting = TRUE;
+                       } else {
+                           aredone = 1;
+                       }
+                   }
+                   else
+                   {
+                       int selected = FALSE;
+                       for( amip = cw->menu.items; amip; amip = amip->next )
+                       {
+                           if( amip->selector == code )
+                           {
+                               if( how == PICK_ONE )
+                                   aredone = 1;
+                               amip->selected = !amip->selected;
+                               if (counting && amip->selected) {
+                                   amip->count = count;
+                                   reset_counting = TRUE;
+                                   amip->str[SOFF+2] = '#';
+                               } else {
+                                   amip->count = -1;
+                                   reset_counting = TRUE;
+                                   amip->str[SOFF+2] = '-';
+                               }
+                               selected = TRUE;
+                           } else if (amip->gselector == code )
+                           {
+                               amip->selected = !amip->selected;
+                               if (counting) {
+                                   amip->count = count;
+                                   reset_counting = TRUE;
+                                   amip->str[SOFF+2] = '#';
+                               } else {
+                                   amip->count = -1;
+                                   reset_counting = TRUE;
+                                   amip->str[SOFF+2] = '-';
+                               }
+                               selected = TRUE;
+                           }
+                       }
+                       if (selected)
+                           DisplayData( win, topidx );
+                   }
+                   break;
+
+               case CLOSEWINDOW:
+                   if( win == WIN_INVEN )
+                   {
+                       lastinvent.MinX = w->LeftEdge;
+                       lastinvent.MinY = w->TopEdge;
+                       lastinvent.MaxX = w->Width;
+                       lastinvent.MaxY = w->Height;
+                   }
+                   else if( win == WIN_MESSAGE )
+                   {
+                       lastmsg.MinX = w->LeftEdge;
+                       lastmsg.MinY = w->TopEdge;
+                       lastmsg.MaxX = w->Width;
+                       lastmsg.MaxY = w->Height;
+                   }
+                   aredone = 1;
+                   morc = '\33';
+                   break;
+
+               case GADGETUP:
+                   if( win == WIN_MESSAGE )
+                       aredone = 1;
+                   for( gd = w->FirstGadget; gd && gd->GadgetID != 1; )
+                       gd = gd->NextGadget;
+
+                   pip = (struct PropInfo *)gd->SpecialInfo;
+                   totalvis = CountLines( win );
+                   hidden = max( totalvis - wheight, 0 );
+                   aidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16;
+                   if( aidx != topidx )
+                       DisplayData( win, topidx = aidx );
+                   break;
+
+               case MOUSEMOVE:
+                   for( gd = w->FirstGadget; gd && gd->GadgetID != 1; )
+                       gd = gd->NextGadget;
+
+                   pip = (struct PropInfo *)gd->SpecialInfo;
+                   totalvis = CountLines( win );
+                   hidden = max( totalvis - wheight, 0 );
+                   aidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16;
+                   if( aidx != topidx )
+                       DisplayData( win, topidx = aidx );
+                   break;
+
+               case INACTIVEWINDOW:
+                   if( win == WIN_MESSAGE || ( win == WIN_INVEN && alwaysinvent ) )
+                       aredone = 1;
+                   break;
+
+               case MOUSEBUTTONS:
+                   if( ( code == SELECTUP || code == SELECTDOWN ) &&
+                                       cw->type == NHW_MENU && how != PICK_NONE )
+                   {
+                       /* Which one is the mouse pointing at? */
+
+                       aidx = ( ( my - w->BorderTop - 1 ) / txh ) + topidx;
+
+                       /* If different lines, don't select double click */
+
+                       if( aidx != oidx )
+                       {
+                           oldsecs = 0;
+                           oldmics = 0;
+                       }
+
+                       /* If releasing, check for double click */
+
+                       if( code == SELECTUP )
+                       {
+                           amip = find_menu_item( cw, aidx );
+                           if( aidx == oidx )
+                           {
+                               if( DoubleClick( oldsecs,
+                                                   oldmics, secs, mics ) )
+                               {
+                                   aredone = 1;
+                               }
+                               oldsecs = secs;
+                               oldmics = mics;
+                           }
+                           else
+                           {
+                               amip = find_menu_item( cw, oidx );
+                               amip->selected = 0;
+                               amip->count = -1;
+                               reset_counting = TRUE;
+                               if (amip->canselect && amip->selector)
+                                   amip->str[SOFF+2] = '-';
+                           }
+                           if (counting && amip->selected && amip->canselect && amip->selector) {
+                               amip->count = count;
+                               reset_counting = TRUE;
+                               amip->str[SOFF+2] = '#';
+                           }
+                           DisplayData( win, topidx );
+                       }
+                       else if( aidx - topidx < wheight &&
+                               aidx < cw->maxrow && code == SELECTDOWN )
+                       {
+                           /* Remove old highlighting if visible */
+
+                           amip = find_menu_item( cw, oidx );
+                           if( amip && oidx != aidx &&
+                                   ( oidx > topidx && oidx - topidx < wheight ) )
+                           {
+                               if( how != PICK_ANY ) {
+                                   amip->selected = 0;
+                                   amip->count = -1;
+                                   reset_counting = TRUE;
+                                   if (amip->canselect && amip->selector)
+                                       amip->str[SOFF+2] = '-';
+                               }
+                               oidx = -1;
+                           }
+                           amip = find_menu_item( cw, aidx );
+
+                           if( amip && amip->canselect && amip->selector && how != PICK_NONE )
+                           {
+                               oidx = aidx;
+                               if( !DoubleClick( oldsecs,
+                                                   oldmics, secs, mics ) )
+                               {
+                                   amip->selected = !amip->selected;
+                                   if (counting && amip->selected) {
+                                       amip->count = count;
+                                       reset_counting = TRUE;
+                                       amip->str[SOFF+2] = '#';
+                                   } else {
+                                       amip->count = -1;
+                                       reset_counting = TRUE;
+                                       if (amip->canselect && amip->selector)
+                                           amip->str[SOFF+2] = '-';
+                                   }
+                               }
+                           }
+                           else
+                           {
+                               DisplayBeep( NULL );
+                               oldsecs = 0;
+                               oldmics = 0;
+                           }
+                           DisplayData( win, topidx );
+                       }
+                   }
+                   else
+                   {
+                       DisplayBeep( NULL );
+                   }
+                   break;
+           }
+           if (!counting && morc == '\33') {
+               amip = cw->menu.items;
+               while (amip) {
+                   if (amip->canselect && amip->selector) {
+                       amip->selected = FALSE;
+                       amip->count = -1;
+                       amip->str[SOFF+2] = '-';
+                   }
+                   amip=amip->next;
+               }
+           }
+           if (reset_counting) {
+               count = 0;
+               if (counting)
+                   pline("Count: 0");
+               counting = FALSE;
+           }
+       }
+    }
+    /* Force a cursor reposition before next message output */
+    if( win == WIN_MESSAGE )
+       cw->curx = -1;
+    return( make_menu_items( cw, retmip ) );
+}
+
+void
+ReDisplayData( win )
+    winid win;
+{
+    int totalvis;
+    register struct amii_WinDesc *cw;
+    register struct Window *w;
+    register struct Gadget *gd;
+    unsigned long hidden, aidx, wheight;
+    struct PropInfo *pip;
+    
+    if( win == WIN_ERR || !(cw = amii_wins[win]) || !( w = cw->win ) )
+       return;
+
+    for( gd = w->FirstGadget; gd && gd->GadgetID != 1; )
+       gd = gd->NextGadget;
+
+    if( !gd )
+       return;
+
+    wheight = (w->Height - w->BorderTop - w->BorderBottom-2)/w->RPort->TxHeight;
+
+    pip = (struct PropInfo *)gd->SpecialInfo;
+    totalvis = CountLines( win );
+    hidden = max( totalvis - wheight, 0 );
+    aidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16;
+    clear_nhwindow( win );
+    DisplayData( win, aidx );
+}
+
+long
+FindLine( win, line )
+    winid win;
+    int line;
+{
+    int txwd;
+    register char *t;
+    register struct amii_WinDesc *cw;
+    register struct Window *w;
+    register int i, disprow, len;
+    int col = -1;
+
+    if( win == WIN_ERR || !(cw = amii_wins[win]) || !( w = cw->win ) )
+    {
+       panic( winpanicstr, win, "No Window in FindLine" );
+    }
+    txwd = w->RPort->TxWidth;
+    if( WINVERS_AMIV )
+    {
+       if( win == WIN_INVEN )
+       {
+           cw->cols = ( w->Width - w->BorderLeft -
+                       w->BorderRight - 4 - pictdata.xsize - 3) / txwd;
+       }
+       else
+           cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd;
+    }
+    else
+    {
+       cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd;
+    }
+
+    disprow = 0;
+    for( col = i = 0; line > disprow && i < cw->maxrow; ++i )
+    {
+       t = cw->data[ i ] + SOFF;
+       if( cw->data[i][1] >= 0 )
+       {
+           ++disprow;
+           col = 0;
+       }
+
+       while( *t )
+       {
+           len = strlen( t );
+           if( col + len > cw->cols )
+               len = cw->cols - col;
+           while( len > 0 )
+           {
+               if( !t[len] || t[len] == ' ' )
+                   break;
+               --len;
+           }
+           if( len == 0 ) {
+               while ( *t && *t != ' ') {
+                   t++; col++;
+               }
+           } else {
+               t += len;
+               col += len;
+           }
+           if( *t )
+           {
+               while( *t == ' ' )
+                   ++t;
+               col = 0;
+               ++disprow;
+           }
+       }
+    }
+    return( i );
+}
+
+long
+CountLines( win )
+    winid win;
+{
+    int txwd;
+    amii_menu_item *mip;
+    register char *t;
+    register struct amii_WinDesc *cw;
+    register struct Window *w;
+    register int i, disprow, len;
+    int col = -1;
+
+    if( win == WIN_ERR || !(cw = amii_wins[win]) || !( w = cw->win ) )
+    {
+       panic( winpanicstr, win, "No Window in CountLines" );
+    }
+
+    txwd = w->RPort->TxWidth;
+    if( WINVERS_AMIV )
+    {
+       if( win == WIN_INVEN )
+       {
+           cw->cols = ( w->Width - w->BorderLeft -
+                       w->BorderRight - 4 - pictdata.xsize - 3) / txwd;
+       }
+       else
+           cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd;
+    }
+    else
+    {
+       cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd;
+    }
+
+    disprow = cw->maxrow;
+    mip = cw->menu.items;
+    for( col = i = 0; i < cw->maxrow; ++i )
+    {
+       t = cw->data[ i ] + SOFF;
+       if( cw->type == NHW_MESSAGE && cw->data[ i ][ SEL_ITEM ] < 0 )
+           --disprow;
+       else
+           col = 0;
+       while( *t )
+       {
+           len = strlen( t );
+           if( col + len > cw->cols )
+               len = cw->cols - col;
+           while( len > 0 )
+           {
+               if( !t[len] || t[len] == ' ' )
+                   break;
+               --len;
+           }
+           if( len == 0 ) {
+               while ( *t && *t != ' ') {
+                   t++; col++;
+               }
+           } else {
+               t += len;
+               col += len;
+           }
+           if( *t )
+           {
+               while( *t == ' ' )
+                   ++t;
+               col = 0;
+               ++disprow;
+           }
+       }
+    }
+    return( disprow );
+}
+
+void
+DisplayData( win, start )
+    winid win;
+    int start;
+{
+    int txwd;
+    amii_menu_item *mip;
+    register char *t;
+    register struct amii_WinDesc *cw;
+    register struct Window *w;
+    register struct RastPort *rp;
+    register int i, disprow, len, wheight;
+    int whichcolor = -1;
+    int col;
+
+    if( win == WIN_ERR || !(cw = amii_wins[win]) || !( w = cw->win ) )
+    {
+       panic( winpanicstr, win, "No Window in DisplayData" );
+    }
+
+    rp = w->RPort;
+    SetDrMd( rp, JAM2 );
+    if( WINVERS_AMIV && win == WIN_INVEN )
+    {
+       wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) /
+                   max( rp->TxHeight, pictdata.ysize + 3 );
+    }
+    else
+    {
+       wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) /
+                   rp->TxHeight;
+    }
+
+    cw->rows = wheight;
+    txwd = rp->TxWidth;
+    if( WINVERS_AMIV )
+    {
+       if( win == WIN_INVEN )
+       {
+           cw->cols = ( w->Width - w->BorderLeft -
+                       w->BorderRight - 4 - pictdata.xsize - 3) / txwd;
+       }
+       else
+           cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd;
+    }
+    else
+    {
+       cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd;
+    }
+
+    /* Get the real line to display at */
+    start = FindLine( win, start );
+
+    mip = cw->menu.items;
+    for( i = 0; mip && i < start; ++i )
+    {
+       mip = mip->next;
+    }
+
+    /* Skip any initial response to a previous line */
+    if( cw->type == NHW_MESSAGE && mip && mip->selected < 0 )
+       ++start;
+    if( WINVERS_AMIV && cw->type == NHW_MESSAGE )
+       SetAPen( rp, amii_msgAPen );
+    
+    for( disprow = i = start; disprow < wheight + start; i++ )
+    {
+       /* Just erase unused lines in the window */
+       if( i >= cw->maxrow )
+       {
+           if (WINVERS_AMIV && win == WIN_INVEN) {
+               amii_curs( win, 0, disprow - start );
+               amiga_print_glyph( win, 0, NO_GLYPH);
+           }
+           amii_curs( win, 1, disprow - start );
+           amii_cl_end( cw, 0 );
+           ++disprow;
+           continue;
+       }
+
+       /* Any string with a highlighted attribute goes
+        * onto the end of the current line in the message window.
+        */
+       if( cw->type == NHW_MESSAGE )
+           SetAPen( rp, cw->data[ i ][ SEL_ITEM ] < 0 ? C_RED : amii_msgAPen );
+
+       /* Selected text in the message window goes onto the end of the current line */
+       if( cw->type != NHW_MESSAGE || cw->data[ i ][ SEL_ITEM ] >= 0 )
+       {
+           amii_curs( win, 1, disprow - start );
+           if( WINVERS_AMIV && win == WIN_INVEN )
+           {
+               if( mip )
+                   amiga_print_glyph( win, 0, mip->glyph );
+               amii_curs( win, 1, disprow - start );
+           }
+           col = 0;
+       }
+
+       /* If this entry is to be highlighted, do so */
+       if( mip && mip->selected != 0 )
+       {
+           if( whichcolor != 1 )
+           {
+               SetDrMd( rp, JAM2 );
+               if( WINVERS_AMIV )
+               {
+                   SetAPen( rp, amii_menuBPen );
+                   SetBPen( rp, C_BLUE );
+               }
+               else
+               {
+                   SetAPen( rp, C_BLUE );
+                   SetBPen( rp, amii_menuAPen );
+               }
+               whichcolor = 1;
+           }
+       }
+       else if( whichcolor != 2 )
+       {
+           SetDrMd( rp, JAM2 );
+           if( cw->type == NHW_MESSAGE )
+           {
+               SetAPen( rp, amii_msgAPen );
+               SetBPen( rp, amii_msgBPen );
+           }
+           else if( cw->type == NHW_MENU )
+           {
+               SetAPen( rp, amii_menuAPen );
+               SetBPen( rp, amii_menuBPen );
+           }
+           else if( cw->type == NHW_TEXT )
+           {
+               SetAPen( rp, amii_textAPen );
+               SetBPen( rp, amii_textBPen );
+           }
+           whichcolor = 2;
+       }
+
+       /* Next line out, wrap if too long */
+
+       t = cw->data[ i ] + SOFF;
+       ++disprow;
+       col = 0;
+       while( *t )
+       {
+           len = strlen( t );
+           if( len > (cw->cols - col) )
+               len = cw->cols - col;
+           while( len > 0 )
+           {
+               if( !t[len] || t[len] == ' ' )
+                   break;
+               --len;
+           }
+           if( len == 0 ) {
+               Text( rp, t, cw->cols - col );
+               while ( *t && *t != ' ') {
+                   t++; col++;
+               }
+           } else {
+               Text( rp, t, len );
+               t += len;
+               col += len;
+           }
+           amii_cl_end( cw, col );
+           if( *t )
+           {
+               ++disprow;
+               /* Stop at the bottom of the window */
+               if( disprow > wheight + start )
+                   break;
+               while( *t == ' ' )
+                   ++t;
+               amii_curs( win, 1, disprow - start - 1 );
+               if( mip && win == WIN_INVEN && WINVERS_AMIV )
+               {
+                   /* Erase any previous glyph drawn here. */
+                   amiga_print_glyph( win, 0, NO_GLYPH );
+                   amii_curs( win, 1, disprow - start - 1 );
+               }
+               Text( rp, "+", 1 );
+               col = 1;
+           }
+       }
+
+       if( cw->type == NHW_MESSAGE )
+       {
+           SetAPen( rp, amii_msgBPen );
+           SetBPen( rp, amii_msgBPen );
+       }
+       else if( cw->type == NHW_MENU )
+       {
+           SetAPen( rp, amii_menuBPen );
+           SetBPen( rp, amii_menuBPen );
+       }
+       else if( cw->type == NHW_TEXT )
+       {
+           SetAPen( rp, amii_textBPen );
+           SetBPen( rp, amii_textBPen );
+       }
+       amii_cl_end( cw, col );
+       whichcolor = -1;
+       if( mip ) mip = mip->next;
+    }
+    RefreshWindowFrame(w);
+    return;
+}
+
+void SetPropInfo( win, gad, vis, total, top )
+    register struct Window *win;
+    register struct Gadget *gad;
+    register long vis, total, top;
+{
+    long mflags;
+    register long hidden;
+    register int body, pot;
+
+    hidden = max( total-vis, 0 );
+
+    /* Force the last section to be just to the bottom */
+
+    if( top > hidden )
+       top = hidden;
+
+    /* Scale the body position. */
+    /* 2 lines overlap */
+
+    if( hidden > 0 && total > 2)
+       body = (ULONG) ((vis - 2) * MAXBODY) / (total - 2);
+    else
+       body = MAXBODY;
+
+    if( hidden > 0 )
+       pot = (ULONG) (top * MAXPOT) / hidden;
+    else
+       pot = 0;
+
+    mflags = AUTOKNOB|FREEVERT;
+#ifdef  INTUI_NEW_LOOK
+    if( IntuitionBase->LibNode.lib_Version >= 37 )
+    {
+       mflags |= PROPNEWLOOK;
+    }
+#endif
+
+    NewModifyProp( gad, win, NULL,
+                           mflags, 0, pot, MAXBODY, body, 1 );
+}
diff --git a/sys/amiga/winproto.h b/sys/amiga/winproto.h
new file mode 100644 (file)
index 0000000..d0106a0
--- /dev/null
@@ -0,0 +1,151 @@
+/*     SCCS Id: @(#)winproto.h 3.2     96/01/15        */
+/* Copyright (c) Gregg Wonderly, Naperville, Illinois,  1991,1992,1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* winreq.c */
+void EditColor ( void );
+void EditClipping( void );
+void DrawCol ( struct Window *w , int idx , UWORD *colors );
+void DispCol ( struct Window *w , int idx , UWORD *colors );
+void amii_change_color( int, long, int );
+char *amii_get_color_string( );
+void amii_getlin ( const char *prompt , char *bufp );
+void getlind ( const char *prompt , char *bufp , const char *dflt );
+char *amii_get_color_string( void );
+int filecopy( char *from, char *to );
+char *basename( char *str );
+char *dirname( char *str );
+
+/* winstr.c */
+void amii_putstr ( winid window , int attr , const char *str );
+void outmore ( struct amii_WinDesc *cw );
+void outsubstr ( struct amii_WinDesc *cw , char *str , int len, int fudge );
+void amii_putsym ( winid st , int i , int y , CHAR_P c );
+void amii_addtopl ( const char *s );
+void TextSpaces ( struct RastPort *rp , int nr );
+void amii_remember_topl ( void );
+long CountLines( winid );
+long FindLine( winid, int );
+int amii_doprev_message ( void );
+void flushIDCMP( struct MsgPort * );
+int amii_msgborder( struct Window * );
+void amii_scrollmsg( register struct Window *w, register struct amii_WinDesc *cw );
+
+/* winkey.c */
+int amii_nh_poskey ( int *x , int *y , int *mod );
+int amii_nhgetch ( void );
+void amii_get_nh_event ( void );
+void amii_getret ( void );
+
+/* winmenu.c */
+void amii_start_menu ( winid window );
+void FDECL(amii_add_menu, (winid,int,const anything *,CHAR_P,CHAR_P,int,const char *,BOOLEAN_P));
+void FDECL(amii_end_menu, (winid, const char *));
+int FDECL(amii_select_menu, (winid, int, menu_item **));
+int DoMenuScroll ( int win , int blocking, int how, menu_item ** );
+void ReDisplayData ( winid win );
+void DisplayData ( winid win , int start );
+void SetPropInfo ( struct Window *win , struct Gadget *gad , long vis , long total , long top );
+
+/* amiwind.c */
+struct Window *OpenShWindow ( struct NewWindow *nw );
+void CloseShWindow ( struct Window *win );
+int ConvertKey ( struct IntuiMessage *message );
+int kbhit ( void );
+int kbhit ( void );
+int amikbhit ( void );
+int WindowGetchar ( void );
+WETYPE WindowGetevent ( void );
+void amii_cleanup ( void );
+#ifndef        SHAREDLIB
+void Abort ( long rc );
+#endif
+void CleanUp ( void );
+void flush_glyph_buffer ( struct Window *w );
+void amiga_print_glyph ( winid window , int color_index , int glyph );
+void start_glyphout ( winid window );
+void amii_end_glyphout ( winid window );
+struct NewWindow *DupNewWindow ( struct NewWindow *win );
+void FreeNewWindow ( struct NewWindow *win );
+void bell ( void );
+void amii_delay_output ( void );
+void amii_number_pad ( int state );
+#ifndef        SHAREDLIB
+void amiv_loadlib ( void );
+void amii_loadlib ( void );
+#endif
+void preserve_icon( void );
+void clear_icon( void );
+
+/* winfuncs.c */
+void amii_destroy_nhwindow ( winid win );
+int amii_create_nhwindow ( int type );
+void amii_init_nhwindows ( int *, char ** );
+void amii_setdrawpens( struct Window *, int type );
+void amii_sethipens( struct Window *, int type, int attr );
+void amii_setfillpens( struct Window *, int type );
+void amii_clear_nhwindow ( winid win );
+void dismiss_nhwindow ( winid win );
+void amii_exit_nhwindows ( const char *str );
+void amii_display_nhwindow ( winid win , boolean blocking );
+void amii_curs ( winid window , int x , int y );
+void kill_nhwindows ( int all );
+void amii_cl_end ( struct amii_WinDesc *cw , int i );
+void cursor_off ( winid window );
+void cursor_on ( winid window );
+void amii_suspend_nhwindows ( const char *str );
+void amii_resume_nhwindows ( void );
+void amii_bell ( void );
+void removetopl ( int cnt );
+void port_help ( void );
+void amii_print_glyph ( winid win , xchar x , xchar y , int glyph );
+void amii_raw_print ( const char *s );
+void amii_raw_print_bold ( const char *s );
+void amii_update_inventory ( void );
+void amii_mark_synch ( void );
+void amii_wait_synch ( void );
+void amii_setclipped ( void );
+void amii_cliparound ( int x , int y );
+void amii_set_text_font( char *font, int size );
+BitMapHeader ReadImageFiles( char **, struct BitMap **, char ** );
+BitMapHeader ReadTileImageFiles(void);
+void FreeImageFiles( char **, struct BitMap ** );
+void FreeTileImageFiles();
+
+/* winami.c */
+#ifdef SHAREDLIB
+int __UserLibInit ( void );
+void __UserLibCleanup ( void );
+#endif
+void amii_askname ( void );
+void amii_player_selection ( void );
+void RandomWindow ( char *name );
+int amii_get_ext_cmd ( void );
+char amii_yn_function ( const char *prompt , const char *resp , char def );
+char amii_yn_function ( const char *query , const char *resp , char def );
+void amii_display_file ( const char *fn , boolean complain );
+void SetBorder ( struct Gadget *gd );
+void *malloc ( register unsigned size );
+void free ( void *q );
+
+#ifdef SHAREDLIB
+/* amilib.c */
+void amii_loadlib ( void );
+void amiv_loadlib ( void );
+void CleanUp ( void );
+void setup_librefs ( WinamiBASE *base );
+#else
+void Abort ( long rc );
+#endif
+
+/* amirip.c */
+void FDECL(amii_outrip, ( winid tmpwin, int how ));
+
+/* winchar.c */
+void SetMazeType(MazeType);
+int GlyphToIcon(int glyph);
+#ifdef OPT_DISPMAP
+void dispmap_sanity(void);
+int dispmap_sanity1(int);
+#endif
+void FreeTileImageFiles(void);
diff --git a/sys/amiga/winreq.c b/sys/amiga/winreq.c
new file mode 100644 (file)
index 0000000..fac7ee6
--- /dev/null
@@ -0,0 +1,1177 @@
+/*    SCCS Id: @(#)winreq.c    3.1    93/04/02 */
+/* Copyright (c) Gregg Wonderly, Naperville, Illinois,  1991,1992,1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "NH:sys/amiga/windefs.h"
+#include "NH:sys/amiga/winext.h"
+#include "NH:sys/amiga/winproto.h"
+
+#define GADBLUEPEN      2
+#define GADREDPEN       3
+#define GADGREENPEN     4
+#define GADCOLOKAY         5
+#define GADCOLCANCEL       6
+#define GADCOLSAVE         7
+
+UBYTE UNDOBUFFER[300];
+SHORT BorderVectors1[] = { 0,0, 57,0, 57,11, 0,11, 0,0 };
+struct Border Border1 = { -1,-1, 3,0,JAM1, 5, BorderVectors1, NULL };
+struct IntuiText IText1 = { 3,0,JAM1, 4,1, NULL, (UBYTE *)"Cancel", NULL };
+struct Gadget Gadget2 = {
+    NULL, 9,15, 56,10, NULL, RELVERIFY, BOOLGADGET, (APTR)&Border1,
+    NULL, &IText1, NULL, NULL, 1, NULL
+};
+UBYTE StrStringSIBuff[300];
+struct StringInfo StrStringSInfo = {
+    StrStringSIBuff, UNDOBUFFER, 0, 300, 0, 0,0,0,0,0, 0, 0, NULL
+};
+SHORT BorderVectors2[] = { 0,0, 439,0, 439,11, 0,11, 0,0 };
+struct Border Border2 = { -1,-1, 3,0,JAM1, 5, BorderVectors2, NULL };
+struct Gadget String = {
+    &Gadget2, 77,15, 438,10, NULL, RELVERIFY+STRINGCENTER, STRGADGET,
+    (APTR)&Border2, NULL, NULL, NULL, (APTR)&StrStringSInfo, 2, NULL
+};
+
+#define StrString \
+   ((char *)(((struct StringInfo *)(String.SpecialInfo))->Buffer))
+
+struct NewWindow StrWindow = {
+    57,74, 526,31, 0,1, GADGETUP+CLOSEWINDOW+ACTIVEWINDOW+VANILLAKEY,
+    WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE+NOCAREREFRESH,
+    &String, NULL, NULL, NULL, NULL, 5,5, 0xffff,0xffff, CUSTOMSCREEN
+};
+
+#include "NH:sys/amiga/colorwin.c"
+
+#define        XSIZE   2
+#define YSIZE  3
+#define XCLIP  4
+#define YCLIP  5
+#define GADOKAY        6
+#define GADCANCEL      7
+
+#include "NH:sys/amiga/clipwin.c"
+
+void ClearCol( struct Window *w );
+
+void
+EditColor( )
+{
+    extern const char *configfile;
+    int i, done = 0, okay = 0;
+    long code, qual, class;
+    register struct Gadget *gd, *dgad;
+    register struct Window *nw;
+    register struct IntuiMessage *imsg;
+    register struct PropInfo *pip;
+    register struct Screen *scrn;
+    long aidx;
+    int msx, msy;
+    int curcol = 0, drag = 0;
+    int bxorx, bxory, bxxlen, bxylen;
+    static UWORD colors[ AMII_MAXCOLORS ];
+    static UWORD svcolors[ AMII_MAXCOLORS ];
+    static int once = 0;
+    scrn = HackScreen;
+
+    if( !once )
+    {
+               if( WINVERS_AMIV )
+               {
+                       Col_NewWindowStructure1.Width += 300;
+                       Col_NewWindowStructure1.Height += 20;
+                       Col_NewWindowStructure1.LeftEdge -= 150;
+                       Col_BluePen.Width += 300;
+                       Col_RedPen.Width += 300;
+                       Col_GreenPen.Width += 300;
+                       Col_Cancel.LeftEdge += 300;
+                       Col_Okay.LeftEdge += 150;
+                       Col_Cancel.TopEdge += 20;
+                       Col_Save.TopEdge += 20;
+                       Col_Okay.TopEdge += 20;
+               }
+               SetBorder( &Col_Okay );
+               SetBorder( &Col_Cancel );
+               SetBorder( &Col_Save );
+               once = 1;
+    }
+
+    bxylen = Col_NewWindowStructure1.Height -
+                           ( Col_BluePen.TopEdge + Col_BluePen.Height + 6 );
+    bxxlen = Col_BluePen.Width;
+    bxorx = Col_BluePen.LeftEdge;
+    bxory = Col_BluePen.TopEdge + Col_BluePen.Height + 2;
+
+    /* Save the current colors */
+    for( i = 0; i < amii_numcolors; ++i )
+               svcolors[ i ] = colors[ i ] = GetRGB4( scrn->ViewPort.ColorMap, i );
+
+    Col_NewWindowStructure1.Screen = scrn;
+#ifdef  INTUI_NEW_LOOK
+    if( IntuitionBase->LibNode.lib_Version >= 37 )
+    {
+               ((struct PropInfo *)Col_BluePen.SpecialInfo)->Flags |= PROPNEWLOOK;
+               ((struct PropInfo *)Col_RedPen.SpecialInfo)->Flags |=  PROPNEWLOOK;
+               ((struct PropInfo *)Col_GreenPen.SpecialInfo)->Flags |= PROPNEWLOOK;
+    }
+#endif
+       if( WINVERS_AMIV || WINVERS_AMII )
+       {
+#ifdef INTUI_NEW_LOOK
+               Col_NewWindowStructure1.Extension = wintags;
+               Col_NewWindowStructure1.Flags |= WFLG_NW_EXTENDED;
+# ifdef __GNUC__
+               fillhook.h_Entry = (void *)&LayerFillHook;
+# else
+               fillhook.h_Entry = (ULONG(*)())LayerFillHook;
+# endif
+               fillhook.h_Data = (void *)-2;
+               fillhook.h_SubEntry = 0;
+#endif
+       }
+
+    nw = OpenWindow( (void *)&Col_NewWindowStructure1 );
+
+    if( nw == NULL )
+    {
+       DisplayBeep( NULL );
+       return;
+    }
+
+    PrintIText( nw->RPort, &Col_IntuiTextList1, 0, 0 );
+
+    ClearCol( nw );
+    DrawCol( nw, curcol, colors );
+    while( !done )
+    {
+       WaitPort( nw->UserPort );
+
+       while( imsg = (struct IntuiMessage * )GetMsg( nw->UserPort ) )
+       {
+           gd = (struct Gadget *)imsg->IAddress;
+           code = imsg->Code;
+           class = imsg->Class;
+           qual = imsg->Qualifier;
+           msx = imsg->MouseX;
+           msy = imsg->MouseY;
+
+           ReplyMsg( (struct Message *)imsg );
+
+           switch( class )
+           {
+           case VANILLAKEY:
+               if( code == 'v' && qual == AMIGALEFT )
+                   okay = done = 1;
+               else if( code == 'b' && qual == AMIGALEFT )
+                   okay = 0, done = 1;
+               else if( code == 'o' || code == 'O' )
+                   okay = done = 1;
+               else if( code == 'c' || code == 'C' )
+                   okay = 0, done = 1;
+               break;
+
+           case CLOSEWINDOW:
+               done = 1;
+               break;
+
+           case GADGETUP:
+               drag = 0;
+               if( gd->GadgetID == GADREDPEN ||
+                                       gd->GadgetID == GADBLUEPEN ||
+                                       gd->GadgetID == GADGREENPEN )
+               {
+                   pip = (struct PropInfo *)gd->SpecialInfo;
+                   aidx = pip->HorizPot / (MAXPOT/15);
+                   if( gd->GadgetID == GADREDPEN )
+                   {
+                       colors[ curcol ] =
+                           ( colors[ curcol ] & ~0xf00 ) | (aidx << 8);
+                       LoadRGB4( &scrn->ViewPort, colors, amii_numcolors );
+                   }
+                   else if( gd->GadgetID == GADBLUEPEN )
+                   {
+                       colors[ curcol ] =
+                           ( colors[ curcol ] & ~0xf ) | aidx;
+                       LoadRGB4( &scrn->ViewPort, colors, amii_numcolors );
+                   }
+                   else if( gd->GadgetID == GADGREENPEN )
+                   {
+                       colors[ curcol ] = ( colors[ curcol ] & ~0x0f0 ) | (aidx << 4);
+                       LoadRGB4( &scrn->ViewPort, colors, amii_numcolors );
+                   }
+                   DispCol( nw, curcol, colors );
+               }
+               else if( gd->GadgetID == GADCOLOKAY )
+               {
+                   done = 1;
+                   okay = 1;
+               }
+               else if( gd->GadgetID == GADCOLSAVE )
+               {
+                   FILE *fp, *nfp;
+                   char buf[ 300 ], nname[ 300 ], oname[ 300 ];
+                   int once = 0;
+
+                   fp = fopen( configfile, "r" );
+                   if( !fp )
+                   {
+                       pline( "can't find NetHack.cnf" );
+                       break;
+                   }
+
+                   strcpy( oname, dirname( (char *)configfile ) );
+                   if( oname[ strlen(oname)-1 ] != ':' )
+                   {
+                       sprintf( nname, "%s/New_NetHack.cnf", oname );
+                       strcat( oname, "/" );
+                       strcat( oname, "Old_NetHack.cnf" );
+                   }
+                   else
+                   {
+                       sprintf( nname, "%sNew_NetHack.cnf", oname );
+                       strcat( oname, "Old_NetHack.cnf" );
+                   }
+
+                   nfp = fopen( nname, "w" );
+                   if( !nfp )
+                   {
+                       pline( "can't write to New_NetHack.cnf" );
+                       fclose( fp );
+                       break;
+                   }
+                   while( fgets( buf, sizeof( buf ), fp ) )
+                   {
+                       if( strncmp( buf, "PENS=", 5 ) == 0 )
+                       {
+                           once = 1;
+                           fputs( "PENS=", nfp );
+                           for( i = 0; i < amii_numcolors; ++i )
+                           {
+                               fprintf( nfp, "%03x", colors[i] );
+                               if(( i + 1 ) < amii_numcolors)
+                                   putc( '/', nfp );
+                           }
+                           putc( '\n', nfp );
+                       }
+                       else
+                       {
+                           fputs( buf, nfp );
+                       }
+                   }
+
+                   /* If none in the file yet, now write it */
+                   if( !once )
+                   {
+                       fputs( "PENS=", nfp );
+                       for( i = 0; i < amii_numcolors; ++i )
+                       {
+                           fprintf( nfp, "%03x", colors[i] );
+                           if(( i + 1 ) < amii_numcolors)
+                               putc( ',', nfp );
+                       }
+                           putc( '\n', nfp );
+                   }
+                   fclose( fp );
+                   fclose( nfp );
+                   unlink( oname );
+                   if( filecopy( (char *)configfile, oname ) == 0 )
+                       if( filecopy( nname, (char *)configfile ) == 0 )
+                           unlink( nname );
+                   done = 1;
+                   okay = 1;
+               }
+               else if( gd->GadgetID == GADCOLCANCEL )
+               {
+                   done = 1;
+                   okay = 0;
+               }
+               break;
+
+           case GADGETDOWN:
+               drag = 1;
+               dgad = gd;
+               break;
+
+           case MOUSEMOVE:
+               if( !drag )
+                   break;
+               pip = (struct PropInfo *)dgad->SpecialInfo;
+               aidx = pip->HorizPot / (MAXPOT/15);
+               if( dgad->GadgetID == GADREDPEN )
+               {
+                   colors[ curcol ] =
+                           ( colors[ curcol ] & ~0xf00 ) | (aidx << 8);
+                   LoadRGB4( &scrn->ViewPort, colors, amii_numcolors );
+               }
+               else if( dgad->GadgetID == GADBLUEPEN )
+               {
+                   colors[ curcol ] = ( colors[ curcol ] & ~0xf ) | aidx;
+                   LoadRGB4( &scrn->ViewPort, colors, amii_numcolors );
+               }
+               else if( dgad->GadgetID == GADGREENPEN )
+               {
+                   colors[ curcol ] =
+                           ( colors[ curcol ] & ~0x0f0 ) | (aidx << 4);
+                   LoadRGB4( &scrn->ViewPort, colors, amii_numcolors );
+               }
+               DispCol( nw, curcol, colors );
+               break;
+
+           case MOUSEBUTTONS:
+               if( code == SELECTDOWN )
+               {
+                   if( msy > bxory && msy < bxory + bxylen - 1 &&
+                           msx > bxorx && msx < bxorx + bxxlen - 1 )
+                   {
+                       curcol = ( msx - bxorx )/(bxxlen / amii_numcolors);
+                       if( curcol >= 0 && curcol < amii_numcolors )
+                       DrawCol( nw, curcol, colors );
+                   }
+               }
+               break;
+           }
+       }
+    }
+
+    if( okay )
+    {
+       for( i = 0; i < ( amii_numcolors ); ++i )
+               flags.amii_curmap[ i ] = colors[ i ];
+       LoadRGB4( &scrn->ViewPort, flags.amii_curmap, amii_numcolors );
+    }
+    else
+       LoadRGB4( &scrn->ViewPort, svcolors, amii_numcolors );
+    CloseWindow( nw );
+}
+
+void
+ShowClipValues( struct Window *nw )
+{
+    char buf[ 50 ];
+    struct Gadget *gd;
+
+    SetAPen( nw->RPort, 5 );
+    SetBPen( nw->RPort, amii_otherBPen );
+    SetDrMd( nw->RPort, JAM2 );
+
+    sprintf( buf, "%d ", mxsize );
+    gd = &ClipXSIZE;
+    Move( nw->RPort, gd->LeftEdge + (nw->Width + gd->Width) + 8,
+               gd->TopEdge + nw->RPort->TxBaseline );
+    Text( nw->RPort, buf, strlen( buf ) );
+
+    sprintf( buf, "%d ", mysize );
+    gd = &ClipYSIZE;
+    Move( nw->RPort, gd->LeftEdge + (nw->Width + gd->Width) + 8,
+               gd->TopEdge + nw->RPort->TxBaseline );
+    Text( nw->RPort, buf, strlen( buf ) );
+
+    sprintf( buf, "%d ", xclipbord );
+    gd = &ClipXCLIP;
+    Move( nw->RPort, gd->LeftEdge + (nw->Width + gd->Width) + 8,
+               gd->TopEdge + nw->RPort->TxBaseline );
+    Text( nw->RPort, buf, strlen( buf ) );
+
+    sprintf( buf, "%d ", yclipbord );
+    gd = &ClipYCLIP;
+    Move( nw->RPort, gd->LeftEdge + (nw->Width + gd->Width) + 8,
+               gd->TopEdge + nw->RPort->TxBaseline );
+    Text( nw->RPort, buf, strlen( buf ) );
+}
+
+void
+EditClipping( void )
+{
+    int i;
+    long mflags;
+    static int sizes[] = { 8, 16, 20, 24, 28, 32, 36 };
+    char buf[ 40 ];
+    int done = 0, okay = 0;
+    long code, qual, class;
+    register struct Gadget *gd, *dgad;
+    register struct Window *nw;
+    register struct IntuiMessage *imsg;
+    register struct PropInfo *pip;
+    register struct Screen *scrn;
+    long aidx;
+    int lmxsize = mxsize, lmysize = mysize;
+    int lxclipbord = xclipbord, lyclipbord = yclipbord;
+    int msx, msy;
+    int drag = 0;
+    static int once = 0;
+
+    scrn = HackScreen;
+
+    if( !once )
+    {
+       SetBorder( &ClipOkay );
+       SetBorder( &ClipCancel );
+       once = 1;
+    }
+    ClipNewWindowStructure1.Screen = scrn;
+#ifdef  INTUI_NEW_LOOK
+    if( IntuitionBase->LibNode.lib_Version >= 37 )
+    {
+       ((struct PropInfo *)ClipXSIZE.SpecialInfo)->Flags |= PROPNEWLOOK;
+       ((struct PropInfo *)ClipYSIZE.SpecialInfo)->Flags |= PROPNEWLOOK;
+       ((struct PropInfo *)ClipXCLIP.SpecialInfo)->Flags |= PROPNEWLOOK;
+       ((struct PropInfo *)ClipYCLIP.SpecialInfo)->Flags |= PROPNEWLOOK;
+    }
+#endif
+    if( WINVERS_AMIV || WINVERS_AMII )
+    {
+# ifdef        INTUI_NEW_LOOK
+       ClipNewWindowStructure1.Extension = wintags;
+       ClipNewWindowStructure1.Flags |= WFLG_NW_EXTENDED;
+#  ifdef __GNUC__
+       fillhook.h_Entry = (void *)&LayerFillHook;
+#  else
+       fillhook.h_Entry = (ULONG(*)())LayerFillHook;
+#  endif
+       fillhook.h_Data = (void *)-2;
+       fillhook.h_SubEntry = 0;
+# endif
+    }
+
+    nw = OpenWindow( (void *)&ClipNewWindowStructure1 );
+
+    if( nw == NULL )
+    {
+       DisplayBeep( NULL );
+       return;
+    }
+
+    ShowClipValues( nw );
+    mflags = AUTOKNOB|FREEHORIZ;
+#ifdef  INTUI_NEW_LOOK
+    if( IntuitionBase->LibNode.lib_Version >= 37 )
+    {
+       mflags |= PROPNEWLOOK;
+    }
+#endif
+
+    for( i = 0; i < 7; ++i )
+    {
+       if( mxsize <= sizes[ i ] )
+           break;
+    }
+    NewModifyProp( &ClipXSIZE, nw, NULL, mflags, (i * MAXPOT ) / 6, 0,
+                                                           MAXPOT/6, 0, 1 );
+    for( i = 0; i < 7; ++i )
+    {
+       if( mysize <= sizes[ i ] )
+           break;
+    }
+    NewModifyProp( &ClipYSIZE, nw, NULL, mflags, (i * MAXPOT ) / 6, 0,
+                                                           MAXPOT/6, 0, 1 );
+
+    NewModifyProp( &ClipXCLIP, nw, NULL, mflags, ((xclipbord-2) * MAXPOT ) / 6, 0,
+                                                           MAXPOT/6, 0, 1 );
+    NewModifyProp( &ClipYCLIP, nw, NULL, mflags, ((yclipbord-2) * MAXPOT ) / 6, 0,
+                                                           MAXPOT/6, 0, 1 );
+
+    while( !done )
+    {
+       WaitPort( nw->UserPort );
+
+       while( imsg = (struct IntuiMessage * )GetMsg( nw->UserPort ) )
+       {
+           gd = (struct Gadget *)imsg->IAddress;
+           code = imsg->Code;
+           class = imsg->Class;
+           qual = imsg->Qualifier;
+           msx = imsg->MouseX;
+           msy = imsg->MouseY;
+
+           ReplyMsg( (struct Message *)imsg );
+
+           switch( class )
+           {
+           case VANILLAKEY:
+               if( code == '\33' )
+                   okay = 0, done = 1;
+               else if( code == 'v' && qual == AMIGALEFT )
+                   okay = done = 1;
+               else if( code == 'b' && qual == AMIGALEFT )
+                   okay = 0, done = 1;
+               else if( code == 'o' || code == 'O' )
+                   okay = done = 1;
+               else if( code == 'c' || code == 'C' )
+                   okay = 0, done = 1;
+               break;
+
+           case CLOSEWINDOW:
+               done = 1;
+               break;
+
+           case GADGETUP:
+               drag = 0;
+               if( gd->GadgetID == XSIZE || gd->GadgetID == YSIZE ||
+                   gd->GadgetID == XCLIP || gd->GadgetID == YCLIP )
+               {
+                   pip = (struct PropInfo *)gd->SpecialInfo;
+                   aidx = pip->HorizPot / (MAXPOT/6);
+                   if( gd->GadgetID == XSIZE )
+                   {
+                       mxsize = sizes[ aidx ];
+                   }
+                   else if( gd->GadgetID == YSIZE )
+                   {
+                       mysize = sizes[ aidx ];
+                   }
+                   else if( gd->GadgetID == XCLIP )
+                   {
+                       xclipbord = aidx + 2;
+                   }
+                   else if( gd->GadgetID == YCLIP )
+                   {
+                       yclipbord = aidx + 2;
+                   }
+                   ShowClipValues( nw );
+#ifdef OPT_DISPMAP
+                   dispmap_sanity();
+#endif
+               }
+               else if( gd->GadgetID == GADOKAY )
+               {
+                   done = 1;
+                   okay = 1;
+               }
+               else if( gd->GadgetID == GADCANCEL )
+               {
+                   done = 1;
+                   okay = 0;
+               }
+               ReportMouse( 0, nw );
+               reclip = 2;
+               doredraw();
+               flush_glyph_buffer( amii_wins[ WIN_MAP ]->win );
+               reclip = 0;
+               break;
+
+           case GADGETDOWN:
+               drag = 1;
+               dgad = gd;
+               ReportMouse( 1, nw );
+               break;
+
+           case MOUSEMOVE:
+               if( !drag )
+                   break;
+               pip = (struct PropInfo *)dgad->SpecialInfo;
+               aidx = pip->HorizPot / (MAXPOT/6);
+               Move( nw->RPort, dgad->LeftEdge + (nw->Width + dgad->Width) + 8,
+                           dgad->TopEdge + nw->RPort->TxBaseline );
+               if( dgad->GadgetID == XSIZE )
+               {
+                   mxsize = sizes[ aidx ];
+                   sprintf( buf, "%d ",lmxsize );
+               }
+               else if( dgad->GadgetID == YSIZE )
+               {
+                   mysize = sizes[ aidx ];
+                   sprintf( buf, "%d ", mysize );
+               }
+               else if( dgad->GadgetID == XCLIP )
+               {
+                   xclipbord = aidx + 2;
+                   sprintf( buf, "%d ", xclipbord );
+               }
+               else if( dgad->GadgetID == YCLIP )
+               {
+                   yclipbord = aidx + 2;
+                   sprintf( buf, "%d ", yclipbord );
+               }
+               SetAPen( nw->RPort, 5 );
+               SetBPen( nw->RPort, amii_otherBPen );
+               SetDrMd( nw->RPort, JAM2 );
+               Text( nw->RPort, buf, strlen( buf ) );
+#ifdef OPT_DISPMAP
+                dispmap_sanity();
+#endif
+               break;
+           }
+       }
+    }
+
+    CloseWindow( nw );
+
+    /* Restore oldvalues if cancelled. */
+    if( !okay )
+    {
+       mxsize = lmxsize;
+       mysize = lmysize;
+       xclipbord = lxclipbord;
+       yclipbord = lyclipbord;
+    }
+}
+
+char *dirname( str )
+    char *str;
+{
+    char *t, c;
+    static char dir[ 300 ];
+
+    t = strrchr( str, '/' );
+    if( !t )
+       t = strrchr( str, ':' );
+    if( !t )
+       t = str;
+    else
+    {
+       c = *t;
+       *t = 0;
+       strcpy( dir, str );
+       *t = c;
+    }
+    return( dir );
+}
+
+char *basename( str )
+    char *str;
+{
+    char *t;
+
+    t = strrchr( str, '/' );
+    if( !t )
+       t = strrchr( str, ':' );
+    if( !t )
+       t = str;
+    else
+       ++t;
+    return( t );
+}
+
+filecopy( from, to )
+    char *from, *to;
+{
+    char *buf;
+    int i = 0;
+
+    buf = (char *)alloc( strlen(to) + strlen(from) + 20 );
+    if( buf )
+    {
+       sprintf( buf, "c:copy \"%s\" \"%s\" clone", from, to );
+
+       /* Check SysBase instead?  Shouldn't matter  */
+#ifdef INTUI_NEW_LOOK
+       if( IntuitionBase->LibNode.lib_Version >= 37 )
+           i = System( buf, NULL );
+       else
+#endif
+           Execute( buf, NULL, NULL );
+       free( buf );
+    }
+    else
+    {
+       return( -1 );
+    }
+    return( i );
+}
+
+/* The colornames, and the default values for the pens */
+static struct COLDEF
+{
+    char *name, *defval;
+};
+struct COLDEF amii_colnames[ AMII_MAXCOLORS ] =
+{
+    "Black","(000)",
+    "White","(fff)",
+    "Brown","(830)",
+    "Cyan","(7ac)",
+    "Green","(181)",
+    "Magenta","(c06)",
+    "Blue","(23e)",
+    "Red","(c00)",
+};
+
+struct COLDEF amiv_colnames[ AMII_MAXCOLORS ] =
+{
+    "Black","(000)",
+    "White","(fff)",
+    "Cyan","(0bf)",
+    "Orange","(f60)",
+    "Blue","(00f)",
+    "Green","(090)",
+    "Grey","(69b)",
+    "Red","(f00)",
+    "Light Green","(6f0)",
+    "Yellow","(ff0)",
+    "Magenta","(f0f)",
+    "Brown","(940)",
+    "Grey Blue","(466)",
+    "Light Brown","(c40)",
+    "Light Grey","(ddb)",
+    "Peach","(fb9)",
+    "Col 16","(222)",
+    "Col 17","(eee)",
+    "Col 18","(000)",
+    "Col 19","(ccc)",
+    "Col 20","(bbb)",
+    "Col 21","(aaa)",
+    "Col 22","(999)",
+    "Col 23","(888)",
+    "Col 24","(777)",
+    "Col 25","(666)",
+    "Col 26","(555)",
+    "Col 27","(444)",
+    "Col 28","(333)",
+    "Col 29","(18f)",
+    "Col 30","(f81)",
+    "Col 31","(fff)",
+};
+
+void
+ClearCol( struct Window *w )
+{
+    int bxorx, bxory, bxxlen, bxylen;
+    int incx, incy;
+
+    bxylen = Col_Okay.TopEdge - ( Col_BluePen.TopEdge + Col_BluePen.Height ) - 1
+               - txheight - 3;
+    bxxlen = Col_BluePen.Width - 2;
+    bxorx = Col_BluePen.LeftEdge + 1;
+    bxory = Col_BluePen.TopEdge + Col_BluePen.Height + 2;
+
+    incx = bxxlen / amii_numcolors;
+    incy = bxylen - 2;
+
+    bxxlen /= incx;
+    bxxlen *= incx;
+    bxxlen += 2;
+
+    SetAPen( w->RPort, C_WHITE );
+    SetDrMd( w->RPort, JAM1 );
+    RectFill( w->RPort, bxorx, bxory, bxorx + bxxlen + 1, bxory + bxylen );
+
+    SetAPen( w->RPort, C_BLACK );
+    RectFill( w->RPort, bxorx+1, bxory+1,
+                                   bxorx + bxxlen, bxory + bxylen - 1);
+}
+
+void
+DrawCol( w, idx, colors )
+    struct Window *w;
+    int idx;
+    UWORD *colors;
+{
+    int bxorx, bxory, bxxlen, bxylen;
+    int i, incx, incy, r, g, b;
+    long mflags;
+
+    bxylen = Col_Okay.TopEdge - ( Col_BluePen.TopEdge + Col_BluePen.Height ) - 1
+               - txheight - 3;
+    bxxlen = Col_BluePen.Width - 2;
+    bxorx = Col_BluePen.LeftEdge + 1;
+    bxory = Col_BluePen.TopEdge + Col_BluePen.Height + 2;
+
+    incx = bxxlen / amii_numcolors;
+    incy = bxylen - 2;
+
+    bxxlen /= incx;
+    bxxlen *= incx;
+    bxxlen += 2;
+
+    for( i = 0; i < amii_numcolors; ++i )
+    {
+       int x, y;
+       x = bxorx + 2 + (i*incx);
+       y = bxory + 2;
+
+       if( i == idx )
+       {
+               SetAPen( w->RPort, flags.amii_dripens[ SHADOWPEN ] );
+               Move( w->RPort, x, y+bxylen-4 );
+               Draw( w->RPort, x, y );
+               Draw( w->RPort, x+incx-1, y );
+
+               Move( w->RPort, x+1, y+bxylen-5 );
+               Draw( w->RPort, x+1, y+1 );
+               Draw( w->RPort, x+incx-2, y+1 );
+
+               SetAPen( w->RPort, flags.amii_dripens[ SHINEPEN ] );
+               Move( w->RPort, x+incx-1, y+1 );
+               Draw( w->RPort, x+incx-1, y+bxylen-4 );
+               Draw( w->RPort, x, y+bxylen-4 );
+
+               Move( w->RPort, x+incx-2, y+2 );
+               Draw( w->RPort, x+incx-2, y+bxylen-5 );
+               Draw( w->RPort, x+1, y+bxylen-5 );
+       }
+       else
+       {
+               SetAPen( w->RPort, C_BLACK );
+               Move( w->RPort, x, y );
+               Draw( w->RPort, x +incx-1, y );
+               Draw( w->RPort, x +incx-1, y +bxylen - 4 );
+               Draw( w->RPort, x, y + bxylen - 4 );
+               Draw( w->RPort, x, y );
+               SetAPen( w->RPort, C_BLACK );
+               Move( w->RPort, x+1, y+1 );
+               Draw( w->RPort, x +incx-2, y+1 );
+               Draw( w->RPort, x +incx-2, y +bxylen - 6 );
+               Draw( w->RPort, x+1, y + bxylen - 6 );
+               Draw( w->RPort, x+1, y+1 );
+       }
+
+       SetAPen( w->RPort, i );
+       RectFill( w->RPort, x + 3, y + 3, x + incx - 4, y + bxylen - 6 );
+    }
+
+    DispCol( w, idx, colors );
+
+    r = (colors[ idx ] & 0xf00) >> 8;
+    g = (colors[ idx ] & 0x0f0) >> 4;
+    b = colors[ idx ] & 0x00f;
+
+    mflags = AUTOKNOB|FREEHORIZ;
+#ifdef  INTUI_NEW_LOOK
+    if( IntuitionBase->LibNode.lib_Version >= 37 )
+    {
+       mflags |= PROPNEWLOOK;
+    }
+#endif
+    NewModifyProp( &Col_RedPen, w, NULL, mflags, (r * MAXPOT ) / 15, 0,
+                                                           MAXPOT/15, 0, 1 );
+    NewModifyProp( &Col_GreenPen, w, NULL, mflags, (g * MAXPOT ) / 15, 0,
+                                                           MAXPOT/15, 0, 1 );
+    NewModifyProp( &Col_BluePen, w, NULL, mflags, (b * MAXPOT ) / 15, 0,
+                                                           MAXPOT/15, 0, 1 );
+}
+
+void
+DispCol( w, idx, colors )
+    struct Window *w;
+    int idx;
+    UWORD *colors;
+{
+    char buf[ 50 ];
+    char *colname, *defval;
+
+    if( WINVERS_AMIV )
+    {
+       colname = amiv_colnames[idx].name;
+       defval = amiv_colnames[idx].defval;
+    }
+    else
+    {
+       colname = amii_colnames[idx].name;
+       defval = amii_colnames[idx].defval;
+    }
+
+    if( colname == NULL )
+    {
+       colname = "unknown";
+       defval = "unknown";
+    }
+    Move( w->RPort, Col_Save.LeftEdge,
+       Col_Save.TopEdge - 7 );
+    sprintf( buf, "%s=%03x default=%s%s", colname, colors[idx], defval,
+       "              "+strlen(colname)+1 );
+    SetAPen( w->RPort, C_RED );
+    SetBPen( w->RPort, amii_otherBPen );
+    SetDrMd( w->RPort, JAM2 );
+    Text( w->RPort, buf, strlen( buf ) );
+}
+
+void
+amii_setpens( int count )
+{
+#ifdef INTUI_NEW_LOOK
+    struct EasyStruct ea = {
+       sizeof( struct EasyStruct ),
+       0l,
+       "NetHack Request",
+       "Number of pens requested(%ld) not correct",
+       "Use default pens|Use requested pens"
+    };
+    struct EasyStruct ea2 = {
+       sizeof( struct EasyStruct ),
+       0l,
+       "NetHack Request",
+       "Number of pens requested(%ld) not\ncompatible with game configuration(%ld)",
+       "Use default pens|Use requested pens"
+    };
+#endif
+    /* If the pens in amii_curmap are
+     * more pens than in amii_numcolors, then we choose to ignore
+     * those pens.
+     */
+#ifdef INTUI_NEW_LOOK
+    if( IntuitionBase && IntuitionBase->LibNode.lib_Version >= 39 )
+    {
+       if( count != amii_numcolors )
+       {
+           long args[2];
+           args[0] = count;
+           args[1] = amii_numcolors;
+           if( EasyRequest( NULL, &ea2, NULL, args ) == 1 )
+           {
+               memcpy( flags.amii_curmap, amii_initmap,
+                       amii_numcolors*sizeof(amii_initmap[0]));
+           }
+       }
+    }
+    else if( IntuitionBase && IntuitionBase->LibNode.lib_Version >= 37 )
+    {
+       if( count != amii_numcolors )
+       {
+           if( EasyRequest( NULL, &ea, NULL, NULL ) == 1 )
+           {
+               memcpy( flags.amii_curmap, amii_initmap,
+                       amii_numcolors*sizeof(amii_initmap[0]));
+           }
+       }
+    }
+    else
+#endif
+    if( count != amii_numcolors )
+    {
+       memcpy( flags.amii_curmap, amii_initmap,
+               amii_numcolors*sizeof(amii_initmap[0]));
+    }
+
+    /* If the pens are set in NetHack.cnf, we can get called before
+     * HackScreen has been opened.
+     */
+    if( HackScreen != NULL )
+    {
+       LoadRGB4( &HackScreen->ViewPort, flags.amii_curmap, amii_numcolors );
+    }
+}
+
+/* Generate a requester for a string value. */
+
+void amii_getlin(prompt,bufp)
+    const char *prompt;
+    char *bufp;
+{
+    getlind(prompt,bufp,0);
+}
+
+/* and with default */
+void getlind(prompt,bufp, dflt)
+    const char *prompt;
+    char *bufp;
+    const char *dflt;
+{
+#ifndef TOPL_GETLINE
+    register struct Window *cwin;
+    register struct IntuiMessage *imsg;
+    register long class, code, qual;
+    register int aredone = 0;
+    register struct Gadget *gd;
+    static int once;
+
+    *StrString = 0;
+    if( dflt )
+       strcpy( StrString, dflt );
+    StrWindow.Title = (UBYTE *)prompt;
+    StrWindow.Screen = HackScreen;
+
+    if( !once )
+    {
+       if( bigscreen ) {
+           StrWindow.LeftEdge = (HackScreen->Width/2) - (StrWindow.Width/2);
+           if (amii_wins[WIN_MAP]) {
+               StrWindow.TopEdge = amii_wins[WIN_MAP]->win->TopEdge;
+           } else {
+               StrWindow.TopEdge = (HackScreen->Height/2) - (StrWindow.Height/2);
+           }
+       }
+       SetBorder( &String );
+       SetBorder( &Gadget2 );
+       once = 1;
+    }
+
+    if( WINVERS_AMIV || WINVERS_AMII )
+    {
+#ifdef INTUI_NEW_LOOK
+       StrWindow.Extension = wintags;
+       StrWindow.Flags |= WFLG_NW_EXTENDED;
+# ifdef __GNUC__
+       fillhook.h_Entry = (void *)&LayerFillHook;
+# else
+       fillhook.h_Entry = (ULONG(*)())LayerFillHook;
+# endif
+       fillhook.h_Data = (void *)-2;
+       fillhook.h_SubEntry = 0;
+#endif
+    }
+
+    if( ( cwin = OpenWindow( (void *)&StrWindow ) ) == NULL )
+    {
+       return;
+    }
+
+    while( !aredone )
+    {
+       WaitPort( cwin->UserPort );
+       while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL )
+       {
+           class = imsg->Class;
+           code = imsg->Code;
+           qual = imsg->Qualifier;
+           gd = (struct Gadget *) imsg->IAddress;
+
+           switch( class )
+           {
+           case VANILLAKEY:
+               if( code == '\033' && (qual &
+                       (IEQUALIFIER_LALT|IEQUALIFIER_RALT|
+                       IEQUALIFIER_LCOMMAND|IEQUALIFIER_RCOMMAND) ) == 0 )
+               {
+                   if( bufp )
+                   {
+                       bufp[0]='\033';
+                       bufp[1]=0;
+                   }
+                   aredone = 1;
+               }
+               else
+               {
+                   ActivateGadget( &String, cwin, NULL );
+               }
+               break;
+
+           case ACTIVEWINDOW:
+               ActivateGadget( &String, cwin, NULL );
+               break;
+
+           case GADGETUP:
+               switch( gd->GadgetID )
+               {
+                   case 2:
+                       aredone = 1;
+                       if( bufp )
+                           strcpy( bufp, StrString );
+                       break;
+
+                   case 1:
+                       if( bufp )
+                       {
+                           bufp[0]='\033';
+                           bufp[1]=0;
+                       }
+                       aredone = 1;
+                       break;
+               }
+               break;
+
+           case CLOSEWINDOW:
+               if( bufp )
+               {
+                   bufp[0]='\033';
+                   bufp[1]=0;
+               }
+               aredone = 1;
+               break;
+           }
+           ReplyMsg( (struct Message *) imsg );
+       }
+    }
+
+    CloseWindow( cwin );
+#else
+    struct amii_WinDesc *cw;
+    struct Window *w;
+    int colx, ocolx, c;
+    char *obufp;
+
+    amii_clear_nhwindow( WIN_MESSAGE );
+    amii_putstr( WIN_MESSAGE, 0, prompt );
+    cw = amii_wins[ WIN_MESSAGE ];
+    w = cw->win;
+    ocolx = colx = strlen( prompt ) + 1;
+
+    obufp = bufp;
+    cursor_on(WIN_MESSAGE);
+    while((c = WindowGetchar()) != EOF)
+    {
+       cursor_off(WIN_MESSAGE);
+       amii_curs( WIN_MESSAGE, colx, 0 );
+       if(c == '\033')
+       {
+           *obufp = c;
+           obufp[1] = 0;
+           return;
+       }
+       else if(c == '\b')
+       {
+           if(bufp != obufp)
+           {
+               bufp--;
+               amii_curs( WIN_MESSAGE, --colx, 0);
+               Text( w->RPort, "\177 ", 2 );
+               amii_curs( WIN_MESSAGE, colx, 0);
+           }
+           else
+               DisplayBeep( NULL );
+       }
+       else if( c == '\n' || c == '\r' )
+       {
+           *bufp = 0;
+           amii_addtopl( obufp );
+           return;
+       }
+       else if(' ' <= c && c < '\177')
+       {
+               /* avoid isprint() - some people don't have it
+                  ' ' is not always a printing char */
+           *bufp = c;
+           bufp[1] = 0;
+
+           Text( w->RPort, bufp, 1 );
+           Text( w->RPort, "\177", 1 );
+           if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)
+           {
+               colx++;
+               bufp++;
+           }
+       }
+       else if(c == ('X'-64) || c == '\177')
+       {
+           amii_curs( WIN_MESSAGE, ocolx, 0 );
+           Text( w->RPort,
+               "                                                            ",
+               colx - ocolx );
+           amii_curs( WIN_MESSAGE, colx = ocolx, 0 );
+       } else
+           DisplayBeep( NULL );
+       cursor_on(WIN_MESSAGE);
+    }
+    cursor_off(WIN_MESSAGE);
+    *bufp = 0;
+#endif
+}
+
+void amii_change_color( pen, val, rev )
+    int pen, rev;
+    long val;
+{
+    if( rev )
+       flags.amii_curmap[ pen ] = ~val;
+    else
+       flags.amii_curmap[ pen ] = val;
+
+    if( HackScreen )
+       LoadRGB4( &HackScreen->ViewPort, flags.amii_curmap, amii_numcolors );
+}
+
+char *
+amii_get_color_string( )
+{
+    int i;
+    char s[ 10 ];
+    static char buf[ BUFSZ ];
+
+    *buf = 0;
+    for( i = 0; i < min(32,amii_numcolors); ++i )
+    {
+       sprintf( s, "%s%03lx", i ? "/" : "", (long)flags.amii_curmap[ i ] );
+       strcat( buf, s );
+    }
+
+    return( buf );
+}
diff --git a/sys/amiga/winstr.c b/sys/amiga/winstr.c
new file mode 100644 (file)
index 0000000..0ff2f7d
--- /dev/null
@@ -0,0 +1,522 @@
+/*    SCCS Id: @(#)winstr.c    3.1    93/04/02 */
+/* Copyright (c) Gregg Wonderly, Naperville, Illinois,  1991,1992,1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "NH:sys/amiga/windefs.h"
+#include "NH:sys/amiga/winext.h"
+#include "NH:sys/amiga/winproto.h"
+
+/* Put a string into the indicated window using the indicated attribute */
+
+void
+amii_putstr(window,attr,str)
+    winid window;
+    int attr;
+    const char *str;
+{
+    int fudge;
+    int len;
+    struct Window *w;
+    register struct amii_WinDesc *cw;
+    char *ob;
+    int i, j, n0, bottom, totalvis, wheight;
+    static int wrapping = 0;
+
+    /* Always try to avoid a panic when there is no window */
+    if( window == WIN_ERR )
+    {
+       window = WIN_BASE;
+       if( window == WIN_ERR )
+           window = WIN_BASE = amii_create_nhwindow( NHW_BASE );
+    }
+
+    if( window == WIN_ERR || ( cw = amii_wins[window] ) == NULL )
+    {
+       iflags.window_inited=0;
+       panic(winpanicstr,window, "putstr");
+    }
+
+    w = cw->win;
+
+    if(!str) return;
+    amiIDisplay->lastwin = window;    /* do we care??? */
+
+    /* NHW_MENU windows are not opened immediately, so check if we
+     * have the window pointer yet
+     */
+
+    if( w )
+    {
+       /* Set the drawing mode and pen colors */
+       SetDrMd( w->RPort, JAM2 );
+       amii_sethipens( w, cw->type, attr );
+    }
+    else if( cw->type != NHW_MENU && cw->type != NHW_TEXT )
+    {
+       panic( "NULL window pointer in putstr 2: %d", window );
+    }
+
+    /* Okay now do the work for each type */
+
+    switch(cw->type)
+    {
+    case NHW_MESSAGE:
+       if( WINVERS_AMIV )
+           fudge = 2;
+       else
+       {
+           /* 8 for --more--, 1 for preceeding sp, 1 for putstr pad */
+           fudge = 10;
+       }
+
+       /* There is a one pixel border at the borders, so subtract two */
+       bottom = amii_msgborder( w );
+
+       wheight = ( w->Height - w->BorderTop -
+                           w->BorderBottom - 3 ) / w->RPort->TxHeight;
+       
+       if (scrollmsg || wheight > 1)
+           fudge = 0;
+
+       amii_scrollmsg( w, cw );
+
+       while (isspace(*str)) str++;
+       strncpy( toplines, str, TBUFSZ );
+       toplines[ TBUFSZ - 1 ] = 0;
+
+       /* For initial message to be visible, we need to explicitly position the
+        * cursor.  This flag, cw->curx == -1 is set elsewhere to force the
+        * cursor to be repositioned to the "bottom".
+        */
+       if( cw->curx == -1 )
+       {
+           amii_curs( WIN_MESSAGE, 1, bottom );
+           cw->curx = 0;
+       }
+
+       /* If used all of history lines, move them down */
+       if( cw->maxrow >= iflags.msg_history )
+       {
+           if( cw->data[ 0 ] )
+               free( cw->data[ 0 ] );
+           memcpy( cw->data, &cw->data[ 1 ],
+               ( iflags.msg_history - 1 ) * sizeof( char * ) );
+           cw->data[ iflags.msg_history - 1 ] =
+                           (char *) alloc( strlen( toplines ) + 5 );
+           strcpy( cw->data[ i = iflags.msg_history - 1 ] +
+                               SOFF + (scrollmsg!=0), toplines );
+       }
+       else
+       {
+           /* Otherwise, allocate a new one and copy the line in */
+           cw->data[ cw->maxrow ] = (char *)
+                                       alloc( strlen( toplines ) + 5 );
+           strcpy( cw->data[ i = cw->maxrow++ ] +
+                               SOFF + (scrollmsg!=0), toplines );
+       }
+       cw->data[ i ][ SEL_ITEM ] = 1;
+       cw->data[ i ][ VATTR ] = attr+1;
+
+       if( scrollmsg )
+       {
+           cw->curx = 0;
+           cw->data[ i ][2] = (cw->wflags & FLMSG_FIRST ) ? '>' : ' ';
+       }
+
+       str = cw->data[i] + SOFF;
+       if( cw->curx + strlen(str) >= (cw->cols-fudge) )
+       {
+           int i;
+           char *ostr = (char *)str;
+           char *p;
+
+           while( cw->curx + strlen( str ) >= (cw->cols-fudge) )
+           {
+               for(p=((char *)&str[ cw->cols-1 - cw->curx ])-fudge; !isspace(*p) && p > str;)
+                   --p;
+               if (p < str) p = (char *)str;
+
+               if( p == str ) {
+               /*    p = (char *)&str[ cw->cols ]; */
+                   outmore(cw);
+                   continue;
+               }
+
+               i = (long)p-(long)str;
+               outsubstr( cw, (char *)str, i, fudge );
+               cw->curx += i;
+
+               while(isspace(*p)) p++;
+               str = p;
+
+#if 0
+               if( str != ostr ) {
+                   outsubstr( cw, "+", 1, fudge );
+                   cw->curx+=2;
+               }
+#endif
+               if(*str)
+                   amii_scrollmsg( w, cw );
+               amii_cl_end( cw, cw->curx );
+           }
+
+           if( *str )
+           {
+               if( str != ostr )
+               {
+                   outsubstr( cw, "+", 1, fudge );
+                   cw->curx+=2;
+               }
+               while ( isspace( *str ) )
+                   ++str;
+               outsubstr( cw, (char *)str, i = strlen( (char *)str ), fudge );
+               cw->curx += i;
+               amii_cl_end( cw, cw->curx );
+           }
+       }
+       else
+       {
+           outsubstr( cw, (char *)str, i = strlen( (char *)str ), fudge );
+           cw->curx += i;
+           amii_cl_end( cw, cw->curx );
+       }
+       cw->wflags &= ~FLMSG_FIRST;
+       len = 0;
+       if( scrollmsg )
+       {
+           totalvis = CountLines( window );
+           SetPropInfo( w, &MsgScroll,
+             ( w->Height-w->BorderTop-w->BorderBottom ) / w->RPort->TxHeight,
+             totalvis, totalvis );
+       }
+       i = strlen( toplines + SOFF );
+       cw->maxcol = max( cw->maxcol, i );
+       cw->vwy = cw->maxrow;
+       break;
+
+    case NHW_STATUS:
+       if( cw->data[ cw->cury ] == NULL )
+           panic( "NULL pointer for status window" );
+       ob = &cw->data[cw->cury][j = cw->curx];
+       if(flags.botlx) *ob = 0;
+
+           /* Display when beam at top to avoid flicker... */
+       WaitTOF();
+       Text(w->RPort,(char *)str,strlen((char *)str));
+       if( cw->cols > strlen( str ) )
+           TextSpaces( w->RPort, cw->cols - strlen( str ) );
+
+       (void) strncpy(cw->data[cw->cury], str, cw->cols );
+       cw->data[cw->cury][cw->cols-1] = '\0'; /* null terminate */
+       cw->cury = (cw->cury+1) % 2;
+       cw->curx = 0;
+       break;
+
+    case NHW_MAP:
+    case NHW_BASE:
+       if (cw->type == NHW_BASE && wrapping) {
+           amii_curs(window, cw->curx+1, cw->cury);
+           TextSpaces(w->RPort, cw->cols);
+           if (cw->cury < cw->rows) {
+               amii_curs(window, cw->curx+1, cw->cury+1);
+               TextSpaces(w->RPort, cw->cols);
+               cw->cury--;
+           }
+       }
+       amii_curs(window, cw->curx+1, cw->cury);
+       Text(w->RPort,(char *)str,strlen((char *)str));
+       cw->curx = 0;
+           /* CR-LF is automatic in these windows */
+       cw->cury++;
+       if (cw->type == NHW_BASE && cw->cury >= cw->rows) {
+           cw->cury = 0;
+           wrapping = 1;
+       }
+       break;
+
+    case NHW_MENU:
+    case NHW_TEXT:
+
+       /* always grows one at a time, but alloc 12 at a time */
+
+       if( cw->cury >= cw->rows || !cw->data )
+       {
+           char **tmp;
+
+               /* Allocate 12 more rows */
+           cw->rows += 12;
+           tmp = (char**) alloc(sizeof(char*) * cw->rows);
+
+               /* Copy the old lines */
+           for(i=0; i<cw->cury; i++)
+               tmp[i] = cw->data[i];
+
+           if( cw->data ) {
+               free( cw->data );
+               cw->data = NULL;
+           }
+
+           cw->data = tmp;
+
+               /* Null out the unused entries. */
+           for(i=cw->cury; i<cw->rows; i++)
+               cw->data[i] = 0;
+       }
+
+       if( !cw->data )
+           panic("no data storage");
+
+           /* Shouldn't need to do this, but... */
+
+       if( cw->data && cw->data[cw->cury] ) {
+           free( cw->data[cw->cury] );
+           cw->data[cw->cury] = NULL;
+       }
+
+       n0 = strlen(str)+1;
+       cw->data[cw->cury] = (char*) alloc(n0+SOFF);
+
+           /* avoid nuls, for convenience */
+       cw->data[cw->cury][VATTR] = attr+1;
+       cw->data[cw->cury][SEL_ITEM] = 0;
+       Strcpy( cw->data[cw->cury] + SOFF, str);
+
+       if(n0 > cw->maxcol) cw->maxcol = n0;
+       if(++cw->cury > cw->maxrow) cw->maxrow = cw->cury;
+       break;
+
+    default:
+       panic("Invalid or unset window type in putstr()");
+    }
+}
+
+void
+amii_scrollmsg( w, cw )
+    register struct Window *w;
+    register struct amii_WinDesc *cw;
+{
+    int bottom, wheight;
+
+    bottom = amii_msgborder( w );
+
+    wheight = ( w->Height - w->BorderTop -
+                       w->BorderBottom - 3 ) / w->RPort->TxHeight;
+       
+    if( scrollmsg )
+    {
+       if( ++cw->disprows > wheight )
+       {
+           outmore( cw );
+           cw->disprows = 1; /* count this line... */
+       }
+       else
+       {
+           ScrollRaster( w->RPort, 0, w->RPort->TxHeight,
+                   w->BorderLeft, w->BorderTop + 1,
+                   w->Width - w->BorderRight-1,
+                   w->Height - w->BorderBottom - 1 );
+       }
+       amii_curs( WIN_MESSAGE, 1, bottom );
+    }
+}
+
+int
+amii_msgborder( w )
+    struct Window *w;
+{
+    register int bottom;
+
+    /* There is a one pixel border at the borders, so subtract two */
+    bottom = w->Height - w->BorderTop - w->BorderBottom - 2;
+    bottom /= w->RPort->TxHeight;
+    if( bottom > 0 )
+       --bottom;
+    return( bottom );
+}
+
+void
+outmore( cw )
+    register struct amii_WinDesc *cw;
+{
+    struct Window *w = cw->win;
+
+    if((cw->wflags & FLMAP_SKIP) == 0)
+    {
+       if( scrollmsg )
+       {
+           int bottom;
+
+           bottom = amii_msgborder( w );
+
+           ScrollRaster( w->RPort, 0, w->RPort->TxHeight,
+                       w->BorderLeft, w->BorderTop+1,
+                       w->Width - w->BorderRight-1,
+                       w->Height - w->BorderBottom - 1 );
+           amii_curs( WIN_MESSAGE, 1, bottom ); /* -1 for inner border */
+           Text( w->RPort, "--more--", 8 );
+       }
+       else
+           Text( w->RPort, " --more--", 9 );
+
+       /* Make sure there are no events in the queue */
+       flushIDCMP( HackPort );
+
+       /* Allow mouse clicks to clear --more-- */
+       WindowGetchar();
+       if( lastevent.type == WEKEY && lastevent.un.key == '\33' )
+           cw->wflags |= FLMAP_SKIP;
+    }
+    if( !scrollmsg )
+    {
+       amii_curs( WIN_MESSAGE, 1, 0 );
+       amii_cl_end( cw, cw->curx );
+    }
+}
+
+void
+outsubstr( cw, str, len, fudge )
+    register struct amii_WinDesc *cw;
+    char *str;
+    int len;
+    int fudge;
+{
+    struct Window *w = cw->win;
+
+    if( cw->curx )
+    {
+       /* Check if this string and --more-- fit, if not,
+        * then put out --more-- and wait for a key.
+        */
+       if( (len + fudge ) + cw->curx >= cw->cols )
+       {
+           if( !scrollmsg )
+               outmore( cw );
+       }
+       else
+       {
+           /* Otherwise, move and put out a blank separator */
+           Text( w->RPort, spaces, 1 );
+           cw->curx += 1;
+       }
+    }
+
+    Text(w->RPort,str,len);
+}
+
+/* Put a graphics character onto the screen */
+
+void
+amii_putsym( st, i, y, c )
+    winid st;
+    int i, y;
+    CHAR_P c;
+{
+    amii_curs( st, i, y );
+    Text(amii_wins[st]->win->RPort, &c, 1);
+}
+
+/* Add to the last line in the message window */
+
+void
+amii_addtopl(s)
+    const char *s;
+{
+    register struct amii_WinDesc *cw = amii_wins[WIN_MESSAGE];
+
+    while(*s) {
+       if(cw->curx == cw->cols - 1)
+           amii_putstr(WIN_MESSAGE, 0, "");
+       amii_putsym(WIN_MESSAGE, cw->curx + 1, amii_msgborder(cw->win), *s++);
+       cw->curx++;
+    }
+}
+
+void
+TextSpaces( rp, nr )
+    struct RastPort *rp;
+    int nr;
+{
+    if( nr < 1 )
+       return;
+
+    while (nr > sizeof(spaces) - 1)
+    {
+       Text(rp, spaces, (long)sizeof(spaces) - 1);
+       nr -= sizeof(spaces) - 1;
+    }
+    if (nr > 0)
+       Text(rp, spaces, (long)nr);
+}
+
+void
+amii_remember_topl()
+{
+    /* ignore for now.  I think this will be done automatically by
+     * the code writing to the message window, but I could be wrong.
+     */
+}
+
+int
+amii_doprev_message()
+{
+    struct amii_WinDesc *cw;
+    struct Window *w;
+    char *str;
+
+    if( WIN_MESSAGE == WIN_ERR ||
+       ( cw = amii_wins[ WIN_MESSAGE ] ) == NULL || ( w = cw->win ) == NULL )
+    {
+       panic(winpanicstr,WIN_MESSAGE, "doprev_message");
+    }
+
+    /* When an interlaced/tall screen is in use, the scroll bar will be there */
+    /* Or in some other cases as well */
+    if( scrollmsg )
+    {
+       struct Gadget *gd;
+       struct PropInfo *pip;
+       int hidden, topidx, i, total, wheight;
+
+       for( gd = w->FirstGadget; gd && gd->GadgetID != 1; )
+           gd = gd->NextGadget;
+
+       if( gd )
+       {
+           pip = (struct PropInfo *)gd->SpecialInfo;
+           wheight = ( w->Height - w->BorderTop -
+                           w->BorderBottom - 2 ) / w->RPort->TxHeight;
+           hidden = max( cw->maxrow - wheight, 0 );
+           topidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16;
+           for( total = i = 0; i < cw->maxrow; ++i )
+           {
+               if( cw->data[i][1] != 0 )
+                   ++total;
+           }
+
+           i = 0;
+           topidx -= wheight/4 + 1;
+           if (topidx < 0)
+               topidx = 0;
+           SetPropInfo( w, &MsgScroll, wheight, total, topidx );
+           DisplayData( WIN_MESSAGE, topidx );
+       }
+       return(0);
+    }
+
+    if( --cw->vwy < 0 )
+    {
+       cw->maxcol = 0;
+       DisplayBeep( NULL );
+       str = "\0\0No more history saved...";
+    }
+    else
+       str = cw->data[ cw->vwy ];
+
+    amii_cl_end(cw, 0);
+    amii_curs( WIN_MESSAGE, 1, 0 );
+    amii_setdrawpens( amii_wins[WIN_MESSAGE]->win, NHW_MESSAGE );
+    Text(w->RPort,str+SOFF,strlen(str+SOFF));
+    cw->curx = cw->cols + 1;
+
+    return( 0 );
+}
diff --git a/sys/amiga/xpm2iff.c b/sys/amiga/xpm2iff.c
new file mode 100644 (file)
index 0000000..82bbb01
--- /dev/null
@@ -0,0 +1,353 @@
+/*     SCCS Id: @(#)xpm2iff.c  3.2     95/08/04        */
+/*     Copyright (c) 1995 by Gregg Wonderly, Naperville, Illinois */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include <stdlib.h>
+
+#include "config.h"
+#include "tile.h"
+
+#include <dos/dos.h>
+#include <dos/dos.h>
+#include <dos/dosextens.h>
+#include <graphics/gfx.h>
+#include <graphics/gfxbase.h>
+#include <graphics/view.h>
+#include <libraries/iffparse.h>
+#include <libraries/dos.h>
+#ifndef _DCC
+# include <proto/iffparse.h>
+# include <proto/dos.h>
+# include <proto/exec.h>
+#endif
+
+struct xpmscreen {
+       int     Width;
+       int     Height;
+       int     Colors;
+       int     ColorResolution;
+       int     Background;
+       int     AspectRatio;
+       int     Interlace;
+       int     BytesPerRow;
+} XpmScreen;
+
+/* translation table from xpm characters to RGB and colormap slots */
+struct Ttable {
+       char flag;
+       char r,g,b;
+       int slot;       /* output colortable index */
+}ttable[256];
+
+pixval ColorMap[3][MAXCOLORMAPSIZE];
+int colorsinmap;
+
+/*
+ * We are using a hybrid form of our own design which we call a BMAP (for
+ * bitmap) form.  It is an ILBM with the bitmaps already deinterleaved,
+ * completely uncompressed.
+ * This speeds the loading of the images from the games point of view because it
+ * does not have to deinterleave and uncompress them.
+ */
+#define        ID_BMAP MAKE_ID( 'B', 'M', 'A', 'P' )   /* instead of ILBM */
+#define        ID_BMHD MAKE_ID( 'B', 'M', 'H', 'D' )   /* Same as ILBM */
+#define        ID_CAMG MAKE_ID( 'C', 'A', 'M', 'G' )   /* Same as ILBM */
+#define        ID_CMAP MAKE_ID( 'C', 'M', 'A', 'P' )   /* Same as ILBM */
+#define        ID_PDAT MAKE_ID( 'P', 'D', 'A', 'T' )   /* Extra data describing plane
+                                                * size due to graphics.library
+                                                * rounding requirements.
+                                                */
+#define        ID_PLNE MAKE_ID( 'P', 'L', 'N', 'E' )   /* The planes of the image */
+
+int nplanes;
+
+/* BMHD from IFF documentation */
+typedef struct {
+    UWORD w, h;
+    WORD x, y;
+    UBYTE nPlanes;
+    UBYTE masking;
+    UBYTE compression;
+    UBYTE reserved1;
+    UWORD transparentColor;
+    UBYTE xAspect, yAspect;
+    WORD pageWidth, pageHeight;
+} BitMapHeader;
+
+typedef struct {
+    UBYTE r, g, b;
+} AmiColorMap;
+
+pixel pixels[TILE_Y][TILE_X];
+AmiColorMap *cmap;
+
+void
+error( char *str )
+{
+    fprintf( stderr, "ERROR: %s\n", str );
+}
+
+char **planes;
+
+main( int argc, char **argv )
+{
+    int colors;
+    struct {
+       long nplanes;
+       long pbytes;
+       long across;
+       long down;
+       long npics;
+       long xsize;
+       long ysize;
+    } pdat;
+    long pbytes;       /* Bytes of data in a plane */
+    int i, cnt;
+    BitMapHeader bmhd;
+    struct IFFHandle *iff;
+    long camg = HIRES|LACE;
+    int tiles=0;
+    int index;
+
+#if defined(_DCC) || defined (__GNUC__)
+    IFFParseBase = OpenLibrary( "iffparse.library", 0 );
+    if( !IFFParseBase ) {
+       error( "unable to open iffparse.library" );
+       exit( 1 );
+    }
+#endif
+
+    if( fopen_xpm_file( argv[1], "r" ) != TRUE )
+    {
+       perror( argv[1] );
+       return( 1 );
+    }
+
+    nplanes = 0;
+    i = XpmScreen.Colors - 1;
+    while( i != 0 )
+    {
+       nplanes++;
+       i >>= 1;
+    }
+
+    planes = malloc( nplanes * sizeof( char * ) );
+    if( planes == 0 )
+    {
+       error( "can not allocate planes pointer" );
+       exit( 1 );
+    }
+
+    XpmScreen.BytesPerRow = ((XpmScreen.Width + 15)/16)*2;
+    pbytes = XpmScreen.BytesPerRow * XpmScreen.Height;
+    for( i = 0; i < nplanes; ++i )
+    {
+       planes[ i ] = malloc( pbytes );
+       if( planes[ i ] == 0 )
+       {
+           error( "can not allocate planes pointer" );
+           exit( 1 );
+       }
+       memset( planes[i], 0, pbytes );
+    }
+
+    iff = AllocIFF();
+    if( !iff )
+    {
+       error( "Can not allocate IFFHandle" );
+       return( 1 );
+    }
+
+    iff->iff_Stream = Open( argv[2], MODE_NEWFILE );
+    if( !iff->iff_Stream )
+    {
+       error( "Can not open output file" );
+       return( 1 );
+    }
+
+    InitIFFasDOS( iff );
+    OpenIFF( iff, IFFF_WRITE );
+
+    PushChunk( iff, ID_BMAP, ID_FORM, IFFSIZE_UNKNOWN );
+
+    bmhd.w = XpmScreen.Width;
+    bmhd.h = XpmScreen.Height;
+    bmhd.x = 0;
+    bmhd.y = 0;
+    bmhd.nPlanes = nplanes;
+    bmhd.masking = 0;
+    bmhd.compression = 0;
+    bmhd.reserved1 = 0;
+    bmhd.transparentColor = 0;
+    bmhd.xAspect = 100;
+    bmhd.yAspect = 100;
+    bmhd.pageWidth = 0;                        /* not needed for this program */
+    bmhd.pageHeight = 0;               /* not needed for this program */
+
+    PushChunk( iff, ID_BMAP, ID_BMHD, sizeof( bmhd ) );
+    WriteChunkBytes( iff, &bmhd, sizeof( bmhd ) );
+    PopChunk( iff );
+
+    PushChunk( iff, ID_BMAP, ID_CAMG, sizeof( camg ) );
+    WriteChunkBytes( iff, &camg, sizeof( camg ) );
+    PopChunk( iff );
+
+#define SCALE(x) (x)
+    cmap = malloc( (colors = (1L<<nplanes)) * sizeof(AmiColorMap) );
+    if(cmap == 0){
+       error("Can't allocate color map");
+       exit(1);
+    }
+    for(index = 0; index<256; index++){
+       if(ttable[index].flag){
+           cmap[ttable[index].slot].r = SCALE(ttable[index].r);
+           cmap[ttable[index].slot].g = SCALE(ttable[index].g);
+           cmap[ttable[index].slot].b = SCALE(ttable[index].b);
+       }
+    }
+#undef SCALE
+
+    PushChunk( iff, ID_BMAP, ID_CMAP, IFFSIZE_UNKNOWN );
+    WriteChunkBytes( iff, cmap, colors*sizeof(*cmap) );
+    PopChunk( iff );
+
+    conv_image();
+
+    pdat.nplanes = nplanes;
+    pdat.pbytes = pbytes;
+    pdat.xsize = XpmScreen.Width;
+    pdat.ysize = XpmScreen.Height;
+    pdat.across = 0;
+    pdat.down = 0;
+    pdat.npics = 1;
+
+    PushChunk( iff, ID_BMAP, ID_PDAT, IFFSIZE_UNKNOWN );
+    WriteChunkBytes( iff, &pdat, sizeof( pdat ) );
+    PopChunk( iff );
+
+    PushChunk( iff, ID_BMAP, ID_PLNE, IFFSIZE_UNKNOWN );
+    for( i = 0; i < nplanes; ++i )
+       WriteChunkBytes( iff, planes[i], pbytes );
+    PopChunk( iff );
+
+    CloseIFF( iff );
+    Close( iff->iff_Stream );
+    FreeIFF( iff );
+
+#if defined(_DCC) || defined (__GNUC__)
+    CloseLibrary( IFFParseBase );
+#endif
+    exit( 0 );
+}
+
+#define SETBIT(Plane, Plane_offset, Col, Value)                                \
+       if(Value){                                                      \
+           planes[Plane][Plane_offset + (Col/8)] |= 1<<(7-(Col & 7));  \
+       }
+
+conv_image(){
+    int row, col, planeno;
+
+    for(row = 0;row<XpmScreen.Height;row++){
+       char *xb = xpmgetline();
+       int plane_offset;
+       if(xb==0)return;
+       plane_offset = row*XpmScreen.BytesPerRow;
+       for(col = 0;col<XpmScreen.Width;col++){
+           int slot;
+           int color = xb[col];
+           if(!ttable[color].flag){
+               fprintf(stderr, "Bad image data\n");
+           }
+           slot = ttable[color].slot;
+           for(planeno = 0; planeno<nplanes; planeno++){
+               SETBIT(planeno, plane_offset, col, slot & (1<<planeno));
+           }
+       }
+    }
+}
+
+long *
+alloc( unsigned int n )
+{
+    long *ret = malloc( n );
+    if(!ret){
+       error("Can't allocate memory");
+       exit(1);
+    }
+    return( ret );
+}
+
+FILE *xpmfh = 0;
+char initbuf[200];
+char *xpmbuf = initbuf;
+
+/* version 1.  Reads the raw xpm file, NOT the compiled version.  This is
+ * not a particularly good idea but I don't have time to do the right thing
+ * at this point, even if I was absolutely sure what that was. */
+fopen_xpm_file(const char *fn, const char *mode){
+       int temp;
+       char *xb;
+       if(strcmp(mode, "r"))return FALSE;      /* no choice now */
+       if(xpmfh)return FALSE;                  /* one file at a time */
+       xpmfh = fopen(fn, mode);
+       if(!xpmfh)return FALSE;                 /* I'm hard to please */
+
+               /* read the header */
+       xb = xpmgetline();
+       if(xb == 0)return FALSE;
+       if(4 != sscanf(xb,"%d %d %d %d",
+         &XpmScreen.Width, &XpmScreen.Height,
+         &XpmScreen.Colors, &temp))return FALSE;       /* bad header */
+               /* replace the original buffer with one big enough for
+                * the real data
+                */
+/* XXX */
+       xpmbuf = malloc(XpmScreen.Width * 2);
+       if(!xpmbuf){
+               error("Can't allocate line buffer");
+               exit(1);
+       }
+       if(temp != 1)return FALSE;              /* limitation of this code */
+
+       {
+               /* read the colormap and translation table */
+           int ccount = -1;
+           while(ccount++ < (XpmScreen.Colors-1)){
+               char index;
+               int r, g, b;
+               xb = xpmgetline();
+               if(xb==0)return FALSE;
+               if(4 != sscanf(xb,"%c c #%2x%2x%2x",&index,&r,&g,&b)){
+                   fprintf(stderr,"Bad color entry: %s\n",xb);
+                   return FALSE;
+               }
+               ttable[index].flag = 1; /* this color is valid */
+               ttable[index].r = r;
+               ttable[index].g = g;
+               ttable[index].b = b;
+               ttable[index].slot = ccount;
+           }
+       }
+       return TRUE;
+}
+
+/* This deserves better.  Don't read it too closely - you'll get ill. */
+#define bufsz 2048
+char buf[bufsz];
+xpmgetline(){
+       char *bp;
+       do {
+           if(fgets(buf, bufsz, xpmfh) == 0)return 0;
+       } while(buf[0] != '"');
+               /* strip off the trailing <",> if any */
+       for(bp = buf;*bp;bp++);
+       bp--;
+       while(isspace(*bp))bp--;
+       if(*bp==',')bp--;
+       if(*bp=='"')bp--;
+       bp++;
+       *bp = '\0';
+
+       return &buf[1];
+}
diff --git a/sys/atari/Install.tos b/sys/atari/Install.tos
new file mode 100644 (file)
index 0000000..76d1084
--- /dev/null
@@ -0,0 +1,124 @@
+       Instructions for compiling and installing NetHack 3.4
+                         on a TOS system
+       =====================================================
+                 (or, How to make ST NetHack 3.4)
+                    Last revision: 2 February 2000
+
+1.  Make sure all the NetHack files are in the appropriate directory structure.
+    You should have a main directory with subdirectories dat, doc, include,
+    src, util, sys\atari, sys\share, sys\unix, and at least one of win\tty
+    and win\gem.  You may have other subdirectories under sys and win, but
+    they needn't concern you.  If you do not follow this structure, the
+    Makefiles will not function properly.  The .c files for the main program
+    belong in src, those for utility programs in util, and Atari-specific
+    ones in sys\atari.  All the .h files belong in include, the documentation
+    in doc, and assorted data files in dat.  You may also use random.c from
+    sys\share.  The Makefiles belong in sys\unix.  (A more detailed
+    explanation of the directory structure may be found in Files, which
+    should be in the top directory.)
+
+2.  If you don't already have a good command line interpreter, get one.
+    Doing all of the following from the desktop or a GEM shell will
+    probably be a *big* pain.  If you can get a Bourne shell compatible
+    one, and put it in \bin\sh, then you'll save yourself some trouble
+    with the Makefiles.  There are several good shells on various
+    FTP sites (including atari.archive.umich.edu).
+
+    Run the "setup.g" shell script in sys\atari.  This will setup all the
+    makefiles and other files in the appropriate directories.  It assumes
+    that your compiler prefers \ to / as a directory separator.  If not,
+    simply copy the makefiles instead of running sed on them.
+
+3.  Now go to the include subdirectory to edit a couple of the header files
+    there.
+
+    First edit config.h according to the comments to match your system and
+    desired set of features.  In particular:
+       make sure that UNIX is *not* defined, and TOS is (if you're using
+          the MiNT library, and/or the -mint option to gcc, this will
+         be done automatically)
+       make sure that HACKDIR is defined properly (or not at all)
+       make sure that COMPRESS is not defined
+
+    Also edit tosconf.h; this shouldn't need much changing. If you are not
+    going to include random.c you will need to comment out RANDOM. Gcc users
+    don't need RANDOM, since the gcc and MiNT libraries have a Berkeley
+    derived srandom() function already. If you have no termcap support and
+    don't want to use the supplied termcap.uu, comment out TERMLIB. Gcc has
+    a termcap library, so TERMLIB should always be "on" with gcc (and you
+    don't need to worry about termcap.uu at all).
+
+4.  If you want to change the high score list behavior, examine the top of
+    topten.c, in the src directory.  You may want to change the definitions of
+    PERSMAX, POINTSMIN, and ENTRYMAX.  I set POINTSMIN to 51 and ENTRYMAX to
+    50 to keep the size of the score list down.
+
+5.  Go to the src directory and edit your Makefile.  You'll want the Systos
+    target configuration; the comments explain most of what needs to be done,
+    at least for the gcc.
+
+    Next, go to the top, util, dat, and doc directories, and edit the Makefiles
+    there, as necessary.  You'll need nroff and/or TeX to do the files in doc;
+    if you don't have one/both of these, you can skip it (docs?? we don't need
+    no steenking docs :-)).
+
+    If you elected to use Fred Fish's termcap library (bundled in as
+    termcap.arc), you will have to generate termcap.a from those sources.
+
+    If you are recompiling after patching your sources, or if you got your
+    files from somewhere other than the official distribution, "touch
+    makedefs.c" to ensure that certain files (onames.h and pm.h) are remade,
+    lest potentially troublesome timestamps fool "make."
+
+8.  Now, enter "make all", and take a long siesta; your computer will be
+    occupied for a long time.  If all goes well, you will get an executable.
+    If you tried to compile in too many features, you will probably get a
+    dysfunctional executable, and will have to start over.
+
+       Hint 1:  If you're short on memory, you might enter "make -n all
+       >make.bat," and then run script.bat with some sort of batch
+        program or with the gulam command "script make.bat."
+
+       Hint 2: You'll save yourself a lot of grief if you use the GNU
+       version of the "make" program. Some of the smaller makes aren't
+       completely compatible. GNU software for the Atari is widely
+       available; for example, by anonymous FTP from atari.archive.umich.edu.
+
+9.  Make sure the support files -- data, rumors, cmdhelp, opthelp, help, hh,
+    history, license, and oracles, or simply nhdat if DLB was defined --
+    were copied to the game directory.  If not, move them there from the
+    dat directory yourself.  rumors can be created manually by entering
+    "makedefs -r;" data by entering "makedefs -d."
+
+    Also, make sure that the various level files (*.lev, from the dat
+    subdirectory) were copied over correctly. If you're not sure what files
+    should have been made, double check with Makefile.dat.
+
+10. Go to the src\atari directory.  Copy atari.cnf to your game directory
+    as NetHack.cnf. Edit it to reflect your particular setup and personal
+    preferences, following the comments.
+
+    If you compiled in the TERMLIB feature, also move the "termcap" file to
+    your game directory.  (Note:  gcc's termcap routines have built-in
+    defaults, so the termcap file is not necessary with that compiler.)
+
+    If you're running NetHack from the MultiTOS desktop, and you want a
+    more useful set of drop down menus than the plain system "File/Edit"
+    ones, copy nethack.mnu to your games directory. This file contains a
+    menu definition that puts a lot of the common commands into the menu.
+
+11. Play NetHack.  If it works, you're done!
+
+
+Notes
+-----
+
+1)  Save files and bones files from previous versions will not work with
+    NetHack 3.4.  Don't bother trying to keep them.  
+
+2)  To install an update of NetHack after changing something, enter "make"
+    from the src directory.  If you add, delete, or reorder monsters or
+    objects, or you change the format of saved level files, delete any save
+    and bones files.  (Trying to use such files sometimes produces amusing
+    confusions on the game's part, but more often produces crashes.)
diff --git a/sys/atari/atarifnt.uue b/sys/atari/atarifnt.uue
new file mode 100644 (file)
index 0000000..7abba9d
--- /dev/null
@@ -0,0 +1,119 @@
+table
+ !"#$%&'()*+,-./0123456789:;<=>?
+@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
+begin 644 hackfnt.arc
+M&@A(04-+1DY4+E!21P  E!,  #\48JO>BQ\=   ,8#0  #" S4 ,! ! &@!Bz
+M8 "#D!2 > .  !Q_P%!5= 'D!0(GN10.X('EB9,Z1L+0"<,&1!DY<M[(T0$By
+MC9LY=<R823,F31DW=$"T*=-&9IX&"@8B.<<#APF*($8L&[@!CY*0 #8 ,J-@x
+M!+^!"1=J?;$ I$-.)@" 6 . 0;1U "B\!< A"3P< TPPP,//&"$0*RI" K *w
+M  (1 PP$&MA0$B B@4HJ"401@#<0.:@BD@((#P%8A,18&0<(QPX$!ISL R( v
+M0%(/ %0 H ' !XH!V HC&$%L8,$1P32#,>*5L<@-B,#H(!<(N' 8XIH'SYK<u
+M!(@ Y  Y=DX=#(:KFME N X-*_(1P#2_ <,WF7E$(!(#<@@@K;7W(!9 &R0Bt
+M, '%__P##@"R -*&#2XL\<TP5@E1Q L#D/5# 3\0X$00WGS%0%J=./-"9ED1s
+M\B%5<(R8%1UF 2" -!FVA4<"*O @$@8O4&AA$%P\D18>3.CQSX057EA26DQ\r
+MPP$/)REU#@XPB$ 1!G0 0$(: &!033IT8:&$"0KPY1<)0XR@#%5_4<F"$A"<q
+MX00#$  0A!D\,( " %( $( 9-,@)P!$JFL&"GE809 8)>O90D1D<"*$)%H((p
+M\1T&9O C)HDD(,.H$I#R \9 B%1Z::9HFB&+HHQ*\Q4@$&2 !" R (!$,"!Lo
+MB<0;",#!#S"!4 -(-<!H.6E6<)#PE9V:0"$(& 1(D<04@3 0@5IG&. L  G@n
+M.9D;[(#APK0@G$'!M-5J  8#W$8+KAD(,*OLM>P(L0$8"*1J 3#1,GNM,T),m
+M8$< (PQ#%1UHGB%!I5*81\>GD8;JCA"2@"  %H 4R0 ')RW% P@\ZO " !H l
+M>>.0 !1) ))U+(4#""D*H,^.3/PP0)!!@"PRQ76  @!Z5/%1,5,HZ_(//"#Dk
+MD3,#:   P3_2<!4"'[[!\8\Z8(@0]-!%(X"TTDP#,('34"N !!XJ.N$S("5-j
+MG14>)LS)@#4:4< V708,0A\>,3@X(80P0Z%CR-^,G"0D)$00%@$8 ("#0CD i
+MH9 +/!B@4 E@R- J) ;$PX.,"_&PD$(&M E) 0B(=+E"&Q0."08%@,(T'ZM_h
+MKA !"\P)">$ , W)#6UN"HD&#F PX.P&% X&!U4"L"D&8.C$0&W"(P^ 3@ Xg
+M()(!LTNN4 %@Z#Z Y &(!(,>>IC1N4A;C)[Y["3$-E D(N%#EPT#F>] UAY(f
+M#PD"A1M^^.?^>,\ '_YP1_<,@P<<I$X7 M"!#@2!"USH8G-@ T #L%$EG?C e
+M#&S @ &2]SH#\  #// # _S  3^8KP!-P0 ?>( '/_CA@GXP #/ 8 PXK1 ?d
+M/O"#3FIH!C]X@#UM@H/Q . XZ7F' <#87^\P (/XF8$!/# ##. 711C R8H?c
+M!( )I<@#*RX$ QXP P8<P(#9@>\@C&G(0L!G*"UB@ E,>"(?],"Z+YAO).@#b
+M !5:PSX9@0,$/O!! $PH(S^X@7A?[%__%@*!IOC  Q#P0=; 8(#>#80-68,!a
+M#/#0/Q#B@ ,X\(<Q B C!P !"*DS!O4&8 Q@ ,,8FU,<$><$J1YB$ ,,L*+Iz
+M$N,'#+APA"'<7/0   X_K-"%?/##0GHH0QKV<"'\<.$.=>)#]ASN<)MR'&R.y
+MF$2%',!TP6/B0'182PP03R?E7(@? ( /=(K1# ?! 9P\@('9P1&-:@%!_N"Xx
+M3@ LDG 04(8QC%&%.VJ. .E306O6N4YPQ& ,-A@ (;7H!OAE;IW]4Q$$_- 2w
+M"&RTDW!P0 8P@ $!$"%K>$!"_GA  A;00!?^L,8 Q/@ .* 2%*I<2"M?N3DAv
+M N  T*C@/\# !AR8$P=97(@!S"#/B8$!#DL5HSG]  <SF$.'9G #&):I06R u
+MP1UFF-T,:\E#!B / X<C7C:+MRD  ,-TW^0<29OX/(4TX'+KI"#EHMA%='+Nt
+MCB,8@>D(8(;N84-S QA(0 4AB"@85)WPI,(9W+A.6&3 !S:XX.ATTBHSB,&Ss
+M @ #;(QI!F/ @'7@,$8O/UDZ#/@ DTH1Y_-(8(XS2((?DAC ,'B0@%,V !8Yr
+M9:4K83D /LC2!6V"U% 98-3,[9(!3'TB![(759+BP _R%$98";#5F7;UJW8(q
+MZP#&NL,HFA4&&# (%%?H@P]*$@<,8$9Z+\<'2>9PFCV<JQAJJ;D$X$"=?@"#p
+M'0Z[3,CZP8IB; I?S9##_)D@+9F+8@_\@ UE)M9HRM"%+J+P WX< !P!ZO _o
+MSA&;,_# #KX$ "8:D%D^F.$?//B'&5 ,@7O8PPQ@.+ \^R($8V# &M9X92]!n
+M6;K:X>!P'T ">@<R#!(,(AC6X(<N#! )'B  "#CXK2 2J -=-% 0&O9#!',Pm
+MH%KR 0-PJ.< _L'0MHC1K#S@P[A"2%(A<H !VNAA\ECGAEX: !Y@\$=X%\*,l
+M-)?W@TQ,;T5RF,S/P9<;&/"',@^ 7^RB51[(ZZ$/9M?H ?QWICC^@S<L'%8#k
+MP("</KBN+9>:/Q:P  ,:@$4.^_P/;XA7L<H0A2H T.$'P"/$_/B'OZA0#A]Hj
+MX;IM.8 -;! ,/\#X'W9H+P0RP0T<\R.]805 HXS! TE(XI5:=$":?:DX1B(!i
+M#$@82"#.\61CX ,'5+;R0#J BX'PP76L<]Q"#E=!!J-9S6S68I7<@$L0&A.*h
+M/B#I@,AH#3/(V>%\Z+,& 6T-'4+3J#JQ!@CK20!C#&2IR;/EF_$1Z;!BKY;6g
+M,"\\P.@+'H2<>MP5KYIUPH<-V/I^8(!!G&,(J85$6XP'68@-L+%4-YAA&S>_f
+M<$!%(0M>\^,#^ #V/XRF@EJ8 \8R(L !,#L(9\?8#@Y@:B80(6=4,*"&,!"$e
+M'VKH[;ZX$)0D]4-K%@*-K]'U'(&HK37TH0M&=(*%'N! #CBQ95SH8"$(U(4.d
+M*GD >,P( /\PM3>JM/$9H1B7;#! +\4W$#B0\,<Z3%[VT&D KU;<EOC@ ,KGc
+MJF:/UP;'[GSSRAL^NZ>B/(H86+D'.$&"D&\ZYE\$,!_VT$Z<^P-2KNVY1'5(b
+M5QC((+ULN* =W+"-"NM0)'H0A2X  '41_RC8 $ !%7HQ#QGS "/?R&P.GVV a
+MI>+@'8C ,0K.+L5&L8%AMU4M6E5?.!^()*B?0P+#X%*2( ^2P B!P /X  $2z
+MD >>H$K L$JJI$I^  $/X#Y?!'D&8 .31U))-0"ZA'FLQGF&8VG<$'HX%G+?y
+M90Q&YV+8T#LZX0\?A%YF)1(HN'DC]V/;!08?%(/(9U2' WO*A#T6IF8N! ;_x
+M4'P)<&IBM'F0)44N9'08@ TVH$-VX ??8'WPM! *H N[YFO>)V+#  $JP $[w
+MH 4]A!' L&S)Q'X>Q 9F4&U@@ (8@':-@@+X!VYHUCL+D348  770P),Q0&Zv
+M8 _6@ W#0%4<P %QX @0*($&H$I/] 'L<#VVQ R4)U55HDM6%$-2)#XD13QIu
+M!@P[J()F,$,L"'O,$#QP(H-G58/+!'O>@4X,@ TZ6'LP>'Y5-%< ( 0ZD3RUt
+M-SLSAV/8@ UAA0 'AGSOM!!&!V#3X S0)UX#9HR;PX6,]5/@$(;!1F)4@ 'Ss
+MX ;#\ _^  _P@%G!\&(QUGZ*=F-S" -H5T.J8 9 )F3($SRV*$L\($0!V$7,r
+M90[&@ 4O9C04T(B/J%.1N%0"@!"6Z&*8"$KP5#B9QD0B9T5+)#T#(@[BI56Fq
+MB(J_J :K""D\ %9G%3PB\8LXYDMO)E\U5'NL&)(AA%[B- PF&8R$$XM@4(PFp
+MAU5=I$+*.#O21$D&H $8,'3;A9/5.  *,%"BLSEX!4\J\ ]7%8Y\0(XV\ >#o
+M "<RTGY,X'%B(&<H0%1_  +)Y [&Q >IM4Y?I%<CHT8HE#]\X [N  <\T"8,n
+M& :&@$"&ET")IP.?%Q8#D#^%TS^YA$;(HTP$,$('9D(D-2,ZA$P!UIAKMW9Zm
+MQ@?ZUTLUY$L>8 !@TS]#Z%IPP@#.P ,U9&$YY@&6R6"])$YL!@D+@%C45&M#l
+MF$.]] ?IY4LAA%7M%6#2\GRQ9ICB2$TBH0"LLY2)A5CI0P4OY&S_P ?\P \Vk
+M, 8Y-#KMQP:NQP:;X@\XT 5&PP-L,)<;Y7%%B FO8SH-T$3[,P!!( BKLYZUj
+MLT)&XY> "0!V0$1M!9$\Z$)Q<CDZ9U2[!$(.QT(!%D4FI%HUY'(V8 QG]D&"i
+MT(29N9FU45]?M%1QPFT%6E]@P <.D' +JGF\"  \L&D*X)H])&J(%4@>]$'_h
+M@#QPT%X?"CT>2DD8\ /YTUZ\P M_H)/!>3V(Y:$+D5"7LPQLQIS\$$C)))T&g
+M<)Y@X'C]DQZ>,P#P$$G@^47Z* $-X3D1X &8XP!-! E:JA KT$^V@SWZ=@#Kf
+MU#L#TA:<LSR0L%'7 P2ZHWEH.0 ?D)"O PCSP:4[:IQZM$Z)4%<!8@,<D![Fe
+M<P#E1@#S83L#\#MQ!0DG< %4H! .H$:1ZJ4H=3V4Y$VV<Z2<LS\08#LID*>8d
+M8P"A T\!8ACS83Y"J1!PYH$C-D@D18ZIPP<&P#H(ZCIXT'B"4T'%8U3B=CT"c
+M\$$A!$P3143&<SDJ!* O!"<@5Z%Q%D*5Y@% @ =-NE9J15)@H$2]HX\S9592b
+M!)&?&)'+(Z/=ZD5_R0&(X@%E1  T0!N?HY0;@ WKVAH \ <PL*Y/! !ZX$)Ya
+M\%@(]3K^ DTS@$@C@3D#(#WP1#S^)#H#<6>U(2-,M#R+>60#<601Q%*@E G"z
+MIEL\$*C D$H2Z$J1Z'%@<(&Q4T'1=TL.N4ON)UW4A4ZX!  (%D48U%UB9 #6y
+MZ0Z#5@!DI1/!XQV'DQYKU41MY1W>!$YJYAT.^Y"%\Y#/0U>%@P</"71?I -Fx
+M8 /H-3M8@ 7&.A#,(%\VP 99RP.M88M96R4!-0S#\ +\FE "D$,(("/PL '+w
+M-@,3Y0<VL $U!@ VT#]F !M5<CDV@ $04%6]M!!+) .P!0!LP 8,P+<D8 ]Ov
+M, S^D D&, T\8 '^\ T>JU,@.U L1(D35$'^0%3--1+/17#!$V?C@D[JI$%&u
+M)XM<I9F!9G'<15;FE6@&P8/L%6?OA7SLL$+U55]8Q4.%.P"8MH4C$3\>.IZ^t
+M1&&6R%<ZYW"<LU0B48R*"S_/$T(4M+PP@ /*T N]\*D$BU@CID<G, Z(LD[<s
+M\ !WX /,@)7/8P--D0GA90;^T+ULL$5F4$ /IT6Y5&1,(+$/D$'\-@SL%@SGr
+MP \\P B6"P'8L V_96_X)JO>\1^TI+@?)$0D%7#KA $H1BZ9EZ#^![-MP0!Jq
+MX'![%G%^!@=@<'HNMD*K]T&SXW$P '(Z@6 DE4'^8'*S6%KF18.>0 /)<SDGp
+MRH-P\FF7 P8VYYJ?<Z$JM)]1Y&(7Y%I\L&Q3N &7XP;4YPTD!4\8%@JEP'WXo
+MX&M2![,J4 =[\ ]5" #&\ >8I47/9@?FR@;4Q@=BD$&+"RDZQ U4<'K%6SIHn
+M23AL  /+ P#G, Q/-@SYD D/7('>\ ^_59"L=) NA!! 53R9!P,=6'D+$8*:m
+MMU16%#R;0U)])HLJ*+NI*&"95TNN2(.[=$')<V NBP>WR%T]*(_(-SL,0 /4l
+M9  ^T'XY%GR@Q@=_4'P(D'-5Q(H^=\.$O 8$QP8VL%1V8 =9>#E># %Z$ HAk
+MX6M05\9(0 7=@+[R.XYKZ -TRW[090SO@ PX-LAY+%[,T,<<]+!3" "M4B78j
+M@$D1)(B0FPGS, QP,(9IY@$9@ F2/(&L!@$$@%PBX0\,21?R)$X1:470]8EFi
+MA4L'9CSB99VF:)T\1%3N%))BY!TD:9,X!@-37)LKR5TMR5Y7FUAB$$4YUD,Fh
+MU%U&&&!&60 7=$60<FK*YP;ME7,,, P:][46AQO4J'0*T NM0)P>&F/G  ,Jg
+MX%I^, ;+R0_E> ?O*YU0M*!R"(=Y'$4DP XX8 V$.R.VR 0'H8\%0 (;BU3Gf
+M< X@, PXL'(;X("RFF]ZO4(>@*5DALD88 3SV:LDC % <)OYV45- ;..XQT7e
+MM$(M! ::): %"@8V "?)=YD^)  .*DD?VD42"I(5Z@,7FJ'8IGG9JD4(T%Z_d
+M][:40TU86**__*&^I$*2?3D[/1!2Q "&\ D8\*[MI4XW>GU<B+9.K:?("0##c
+M\ ?+^0_."3\3)2W;:P=RQ@;829O^B0>G=4%:)*6#M:5M68T$4(%MU8BJZJC[b
+MTP"ZHP-9P]:7"@D'X(<BL3\EW:GXI#L'L*, \  E30"GI-MP$IPN=-P]JKS+a
+M-!!3A[!WI*U@@ _IYE:-)!)@X#DEO0!DH -<< 9N4 =<P 9S5P!G, 9C\ 5Cz
+M\ 9M  <?_@5?, <K(0=T$ -S-S)?  =A( =S4 8U/G<#$ "<\ 4U?@;SN1#=y
+M(Q9PX.-R$.(B,>0#L %T@ 9A, 9KD%5TX (Z+@"X$.(C7N(G7N6XH.)B$ 8Wx
+M3A]B@0<JW@9A8!,#4>72\ 4+P1(V409*O@%\H.)E@ =I$"4J(A)63N)OP 9Rw
+M\ 5D$ 9^N35L/@!$4 1&$ 15$.> H.)H@.-P\.5^61 JSN(U'B4I7A1N\ : v
+M+N@B,0!%7@9T4.=XKN.4_A-VD 8QX09Q3@B53@=K, =IH =QC@A?\!)RL.EBu
+MON2,<.MV'B4+P>5?8.9H'NQZK@]?8!-WKN=Z#@^W'N@K 1;'$>IN0 :O$^>#t
+M(1(0$,T,@  Z@ +2H@ *X  (H  &H  0( .KQ !"8*)6P  ZP $0X #C3@$ s
+# !H r
+ q
+end
diff --git a/sys/atari/nethack.mnu b/sys/atari/nethack.mnu
new file mode 100644 (file)
index 0000000..6a7d7d2
--- /dev/null
@@ -0,0 +1,53 @@
+# Sample .mnu file for NetHack
+# This will work only with MINIWIN v1.1
+# or TOSWIN v2.0 (or better)
+
+#%title "NetHack"
+#%about "About NetHack" "v"
+
+File
+       "Shell"         "!"
+       "Options"       "O"
+       ---
+       "Save Game"     "S"
+       ---
+       "Quit"          ?"[1][Really quit?][ Yes | No ]":%A"#quit y":!
+Edit
+       "Copy"          %C
+       "Paste"         %P
+       "Paste Options..."      %O
+       ---
+       "Set Font..."   %F
+Inventory
+       "Show Inventory"        "i"
+       --
+       "Put on jewelry" "P"
+       "Remove jewelry" "R"
+       "Wear armor"    "W"
+       "Take off armor" "T"
+       "Wield weapon"  "w"
+       "Exchange weapons"      "x"
+       "Ready ammo in quiver"  "Q"
+       ---
+       "Eat"           "e"
+       "Quaff potion"  "q"
+       ---
+       "Drop"          "d"
+       "Throw"         "t"
+       "Fire"          "f"
+Move
+       "North" "k"     4800
+       "South" "j"     5000
+       "East"  "l"     4d00
+       "West"  "h"     4b00
+       ---
+       "Rest"  "."
+       ---
+       "Open door" "o"
+       "Close door" "c"
+Misc
+       "Help"  "?"     6200
+       "List known spells" "+"
+       "Cast spell" "Z"
+       ---
+       "Abort" 001b    6100
diff --git a/sys/atari/setup.g b/sys/atari/setup.g
new file mode 100644 (file)
index 0000000..bcdff67
--- /dev/null
@@ -0,0 +1,17 @@
+# gulam shell script -- should work with tcsh and many
+# other Atari shells, too
+
+# UNIX shells use '/' in file names, but at least some Atari shells need '\'
+# so we process the UNIX makefiles to make that switch
+
+# sed script not included as a here document in this script because at
+# least some Atari shells don't do that
+
+sed -f unx2atar.sed < ..\unix\Makefile.top > ..\..\Makefile
+sed -f unx2atar.sed < ..\unix\Makefile.dat > ..\..\dat\Makefile
+sed -f unx2atar.sed < ..\unix\Makefile.doc > ..\..\doc\Makefile
+sed -f unx2atar.sed < ..\unix\Makefile.src > ..\..\src\Makefile
+sed -f unx2atar.sed < ..\unix\Makefile.utl > ..\..\util\Makefile
+
+# KLUDGE to fix a Makefile problem
+echo > ..\..\include\win32api.h
diff --git a/sys/atari/tos.c b/sys/atari/tos.c
new file mode 100644 (file)
index 0000000..e1f003e
--- /dev/null
@@ -0,0 +1,372 @@
+/*     SCCS Id: @(#)tos.c      3.1     90/14/08
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *  TOS system functions.
+ */
+
+#define NEED_VARARGS
+#include "hack.h"
+
+#ifdef TTY_GRAPHICS
+# include "tcap.h"
+#else
+/* To avoid error for tos.c; will be removed later */
+static char *nh_HE="\033q";
+#endif
+
+#ifdef TOS
+
+# include <osbind.h>
+# ifndef WORD
+#  define WORD short           /* 16 bits -- redefine if necessary */
+# endif
+
+#include <ctype.h>
+
+static char NDECL(DOSgetch);
+static char NDECL(BIOSgetch);
+static void NDECL(init_aline);
+char *_a_line;                 /* for Line A variables */
+# ifdef TEXTCOLOR
+boolean colors_changed = FALSE;
+# endif
+
+int
+tgetch()
+{
+       char ch;
+
+       /* BIOSgetch can use the numeric key pad on IBM compatibles. */
+       if (iflags.BIOS)
+               ch = BIOSgetch();
+       else
+               ch = DOSgetch();
+       return ((ch == '\r') ? '\n' : ch);
+}
+
+/*
+ *  Keyboard translation tables.
+ */
+#define KEYPADLO       0x61
+#define KEYPADHI       0x71
+
+#define PADKEYS        (KEYPADHI - KEYPADLO + 1)
+#define iskeypad(x)    (KEYPADLO <= (x) && (x) <= KEYPADHI)
+
+/*
+ * Keypad keys are translated to the normal values below.
+ * When iflags.BIOS is active, shifted keypad keys are translated to the
+ *    shift values below.
+ */
+static const struct pad {
+       char normal, shift, cntrl;
+} keypad[PADKEYS] = {
+                       {C('['), 'Q', C('[')},          /* UNDO */
+                       {'?', '/', '?'},                /* HELP */
+                       {'(', 'a', '('},                /* ( */
+                       {')', 'w', ')'},                /* ) */
+                       {'/', '/', '/'},                /* / */
+                       {C('p'), '$', C('p')},          /* * */
+                       {'y', 'Y', C('y')},             /* 7 */
+                       {'k', 'K', C('k')},             /* 8 */
+                       {'u', 'U', C('u')},             /* 9 */
+                       {'h', 'H', C('h')},             /* 4 */
+                       {'.', '.', '.'},
+                       {'l', 'L', C('l')},             /* 6 */
+                       {'b', 'B', C('b')},             /* 1 */
+                       {'j', 'J', C('j')},             /* 2 */
+                       {'n', 'N', C('n')},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+}, numpad[PADKEYS] = {
+                       {C('['), 'Q', C('[')}   ,       /* UNDO */
+                       {'?', '/', '?'},                /* HELP */
+                       {'(', 'a', '('},                /* ( */
+                       {')', 'w', ')'},                /* ) */
+                       {'/', '/', '/'},                /* / */
+                       {C('p'), '$', C('p')},          /* * */
+                       {'7', M('7'), '7'},             /* 7 */
+                       {'8', M('8'), '8'},             /* 8 */
+                       {'9', M('9'), '9'},             /* 9 */
+                       {'4', M('4'), '4'},             /* 4 */
+                       {'.', '.', '.'},                /* 5 */
+                       {'6', M('6'), '6'},             /* 6 */
+                       {'1', M('1'), '1'},             /* 1 */
+                       {'2', M('2'), '2'},             /* 2 */
+                       {'3', M('3'), '3'},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+};
+
+/*
+ * Unlike Ctrl-letter, the Alt-letter keystrokes have no specific ASCII
+ * meaning unless assigned one by a keyboard conversion table, so the
+ * keyboard BIOS normally does not return a character code when Alt-letter
+ * is pressed. So, to interpret unassigned Alt-letters, we must use a
+ * scan code table to translate the scan code into a letter, then set the
+ * "meta" bit for it.  -3.
+ */
+#define SCANLO         0x10
+
+static const char scanmap[] = {        /* ... */
+       'q','w','e','r','t','y','u','i','o','p','[',']', '\n',
+       0, 'a','s','d','f','g','h','j','k','l',';','\'', '`',
+       0, '\\', 'z','x','c','v','b','N','m',',','.','?'        /* ... */
+};
+
+#define inmap(x)       (SCANLO <= (x) && (x) < SCANLO + SIZE(scanmap))
+
+/*
+ * BIOSgetch gets keys directly with a BIOS call.
+ */
+#define SHIFT          (0x1 | 0x2)
+#define CTRL           0x4
+#define ALT            0x8
+
+static char
+BIOSgetch()
+{
+       unsigned char scan, shift, ch;
+       const struct pad *kpad;
+
+       long  x;
+
+       /* Get scan code.
+        */
+       x = Crawcin();
+       ch = x & 0x0ff;
+       scan = (x & 0x00ff0000L) >> 16;
+       /* Get shift status.
+        */
+       shift = Kbshift(-1);
+
+       /* Translate keypad keys */
+       if (iskeypad(scan)) {
+               kpad = iflags.num_pad ? numpad : keypad;
+               if (shift & SHIFT)
+                       ch = kpad[scan - KEYPADLO].shift;
+               else if (shift & CTRL)
+                       ch = kpad[scan - KEYPADLO].cntrl;
+               else
+                       ch = kpad[scan - KEYPADLO].normal;
+       }
+       /* Translate unassigned Alt-letters */
+       if ((shift & ALT) && !ch) {
+               if (inmap(scan))
+                       ch = scanmap[scan - SCANLO];
+               return (isprint(ch) ? M(ch) : ch);
+       }
+       return ch;
+}
+
+static char
+DOSgetch()
+{
+       return (Crawcin() & 0x007f);
+}
+
+
+long
+freediskspace(path)
+char *path;
+{
+       int drive = 0;
+       struct {
+               long freal; /*free allocation units*/
+               long total; /*total number of allocation units*/
+               long bps;   /*bytes per sector*/
+               long pspal; /*physical sectors per allocation unit*/
+       } freespace;
+       if (path[0] && path[1] == ':')
+               drive = (toupper(path[0]) - 'A') + 1;
+       if (Dfree(&freespace,drive)<0) return -1;
+       return freespace.freal*freespace.bps*freespace.pspal;
+}
+
+/*
+ * Functions to get filenames using wildcards
+ */
+int
+findfirst(path)
+char *path;
+{
+       return (Fsfirst(path, 0) == 0);
+}
+
+int
+findnext()
+{
+       return (Fsnext() == 0);
+}
+
+char *
+foundfile_buffer()
+{
+       return (char *)Fgetdta() + 30;
+}
+
+long
+filesize(file)
+char *file;
+{
+       if (findfirst(file))
+               return  (* (long *) ((char *)Fgetdta() + 26));
+       else
+               return -1L;
+}
+
+/*
+ * Chdrive() changes the default drive.
+ */
+void
+chdrive(str)
+char *str;
+{
+       char *ptr;
+       char drive;
+
+       if ((ptr = index(str, ':')) != (char *)0) {
+               drive = toupper(*(ptr - 1));
+               (void)Dsetdrv(drive - 'A');
+       }
+       return;
+}
+
+
+void
+get_scr_size()
+{
+# ifdef MINT
+#  include <ioctl.h>
+       struct winsize win;
+       char *tmp;
+
+       if((tmp=nh_getenv("LINES")))
+               LI = atoi(tmp);
+       else if((tmp=nh_getenv("ROWS")))
+               LI = atoi(tmp);
+       if(tmp && (tmp=nh_getenv("COLUMNS")))
+               CO = atoi(tmp);
+       else {
+           ioctl(0,TIOCGWINSZ, &win);
+           LI = win.ws_row;
+           CO = win.ws_col;
+       }
+# else
+       init_aline();
+       LI = (*((WORD  *)(_a_line + -42L))) + 1;
+       CO = (*((WORD  *)(_a_line + -44L))) + 1;
+# endif
+}
+
+# define BIGBUF  8192
+
+int
+_copyfile(from, to)
+char *from, *to;
+{
+       int fromfd, tofd, r;
+       char *buf;
+
+       if ((fromfd = open(from, O_RDONLY|O_BINARY, 0)) < 0)
+               return -1;
+       if ((tofd = open(to, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, FCMASK)) < 0)
+               return -1;
+       buf = (char *)alloc((size_t)BIGBUF);
+       while ( (r = read(fromfd, buf, BIGBUF)) > 0)
+               write(tofd, buf, r);
+       close(fromfd);
+       close(tofd);
+       free(buf);
+       return 0;       /* successful */
+}
+
+int kbhit()
+{
+       return Cconis();
+}
+
+static void
+init_aline()
+{
+# ifdef __GNUC__
+/* line A calls nuke registers d0-d2,a0-a2; not all compilers regard these
+   as scratch registers, though, so we save them
+ */
+       asm(" moveml d0-d2/a0-a2, sp@-");
+       asm(" .word 0xa000; movel d0, __a_line");
+       asm(" moveml sp@+, d0-d2/a0-a2");
+# else
+       asm(" movem.l d0-d2/a0-a2, -(sp)");
+       asm(" .dc.w 0xa000");   /* tweak as necessary for your compiler */
+       asm(" move.l d0, __a_line");
+       asm(" movem.l (sp)+, d0-d2/a0-a2");
+# endif
+}
+
+# ifdef TEXTCOLOR
+/* used in termcap.c to decide how to set up the hilites */
+unsigned long tos_numcolors = 2;
+
+void
+set_colors()
+{
+       static char colorHE[] = "\033q\033b0";
+
+       if (!iflags.BIOS)
+               return;
+       init_aline();
+       tos_numcolors = 1 << (((unsigned char *) _a_line)[1]);
+       if (tos_numcolors <= 2) {                       /* mono */
+               iflags.use_color = FALSE;
+               return;
+       } else {
+               colors_changed = TRUE;
+               nh_HE = colorHE;
+       }
+}
+
+void
+restore_colors()
+{
+       static char plainHE[] = "\033q";
+
+       if (colors_changed)
+               nh_HE = plainHE;
+       colors_changed = FALSE;
+}
+# endif /* TEXTCOLOR */
+
+# ifdef SUSPEND
+
+#include       <signal.h>
+
+#   ifdef MINT
+extern int __mint;
+#   endif
+
+int
+dosuspend() {
+#   ifdef MINT
+       extern int kill();
+       if (__mint == 0) {
+#   endif
+               pline("Sorry, it seems we have no SIGTSTP here.  Try ! or S.");
+#   ifdef MINT
+       }
+       else if(signal(SIGTSTP, SIG_IGN) == SIG_DFL) {
+               suspend_nhwindows((char *)0);
+               (void) signal(SIGTSTP, SIG_DFL);
+               (void) kill(0, SIGTSTP);
+               get_scr_size();
+               resume_nhwindows();
+       } else {
+               pline("I don't think your shell has job control.");
+       }
+#   endif /* MINT */
+       return(0);
+}
+# endif /* SUSPEND */
+
+#endif /* TOS */
diff --git a/sys/atari/unx2atar.sed b/sys/atari/unx2atar.sed
new file mode 100644 (file)
index 0000000..8d44330
--- /dev/null
@@ -0,0 +1,23 @@
+: loop
+/\\$/N
+/\\$/b loop
+# for each line, append any continuation lines before trying to classify it
+/^     / {
+# if it starts with a tab, it's meant for the shell, and we should think
+#  about reversing the slashes
+s;cd ../util;cd ..\\util;
+s;cd ../src;cd ..\\src;
+/librarian/ s;dat/options;dat\\options;
+/$(MAKE)/b
+/$(CC)/b
+s;/;\\;g
+}
+# unfortunately, we do not want to reverse *all* the slashes, as even the
+#  Atari make and gcc like forward ones, and it's messy to avoid the ones in
+#  sed addresses
+# so, flip the first one in e.g.
+#      @( cd ../util ; $(MAKE) ../include/onames.h )
+# flip the librarian-related ones in dat/options
+# ignore other lines related to make and gcc
+# and flip any slashes left over, which include a number of UNIX-only things
+#  that we didn't need to do but don't hurt
diff --git a/sys/be/README b/sys/be/README
new file mode 100644 (file)
index 0000000..22e97db
--- /dev/null
@@ -0,0 +1,63 @@
+This file is sys/be/README.  It is for those intending to compile
+NetHack 3.3 on a BeOS 4.5 system.
+
+BeOS NetHack currently only supports the TTY windowing system.  In
+order to compile it, it would benefit you greatly to think of your Be
+system as a UNIX variant.  It is possible to compile using BeIDE.
+However, there are four executables and several steps involved in making
+NetHack.  Unless you are extremely familiar with the build sequence and
+are willing to modify the code somewhat, I suggest you avoid it for now.
+Let the UNIX Makefiles take care of all that for you.
+
+
+Known problems:
++ No special characters for walls.  None of the fonts available for use
+  in a tty window has the graphics characters needed to improve the look.
+  If such a font existed, then all you need to do is set the dungeon,
+  object, and/or monter mappings in your defaults file.
++ The arrow keys don't work.
+
+
+
+Build instructions.  From a freshly unpacked source tree:
+
+1. Copy the Makfiles in sys/unix to their proper spots.  You may
+   use setup.sh or copy them by hand.  Using setup.sh to create
+   links instead of copying the Makefiles will work, but BeOS will
+   not let you edit a link.   It may be helpful to read
+   sys/unix/Install.unx.
+
+2. Edit src/Makefile:
+       o Change System to SysBe.
+       o Comment out the UNIX versions of SYSSRC and SYSOBJ variables.
+       o Uncomment the BeOS versions of SYSRC and SYSOBJ.
+       o Uncomment the BeOS versions of CC, CFLAGS, LD, and LFLAGS.  The
+         flags are different for Intel vs BeBox/Mac.
+       o Uncomment one of the Intel or BeBox/Mac BeOS versions of CC, CFLAGS,
+         LD, and LFLAGS.
+       o Comment out the default CFLAGS and LFLAGS.
+       o Change WINTTYLIB to be -ltermcap.
+
+3. Edit util/Makefile:
+       o If on a BeBox/Mac:
+         - Uncomment the BeOS versions of CC and CFLAGS
+         - Comment out the default CFLAGS and LFLAGS.
+       o If on Intel:
+         - the default values of CFLAGS and LFLAGS work fine
+       o Change YACC and LEX to be bison -y and flex respectively.
+
+4. Edit include/config.h to change HACKDIR to be the location of your
+   install directory.
+
+5. Edit top level Makefile and change GAMEDIR to match HACKDIR in
+   include/config.h.  Make sure the path to GAMEDIR exists.  Change
+   SHELLDIR to a "throw away" directory, like /tmp.  We don't use the
+   shell.  Change CHOWN and CHGRP commands to "true", there really
+   aren't groups on the BeOS.
+
+6. Type "make install" at the top level.
+
+
+
+It is possible that some necessary steps needed to make the game have been
+omitted.  Feel free to ad-lib as necessary.
diff --git a/sys/be/bemain.c b/sys/be/bemain.c
new file mode 100644 (file)
index 0000000..acebb15
--- /dev/null
@@ -0,0 +1,268 @@
+/*     SCCS Id: @(#)bemain.c   3.4     1998/07/15      */
+/* Copyright (c) Dean Luick, 1996. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "dlb.h"
+#include <fcntl.h>
+
+static void whoami(void);
+static void process_options(int argc, char **argv);
+static void chdirx(const char *dir);
+static void getlock(void);
+
+#ifdef __begui__
+       #define MAIN nhmain
+       int nhmain(int argc, char **argv);
+#else
+       #define MAIN main
+#endif
+
+
+int MAIN(int argc, char **argv)
+{
+       int fd;
+       char *dir;      
+
+       dir = nh_getenv("NETHACKDIR");
+       if (!dir) dir = nh_getenv("HACKDIR");
+
+       choose_windows(DEFAULT_WINDOW_SYS);
+       chdirx(dir);
+       initoptions();
+
+       init_nhwindows(&argc, argv);
+       whoami();
+
+       /*
+        * It seems you really want to play.
+        */
+       u.uhp = 1;      /* prevent RIP on early quits */
+       process_options(argc, argv);    /* command line options */
+
+
+#ifdef WIZARD
+       if (wizard)
+               Strcpy(plname, "wizard");
+       else
+#endif
+       if(!*plname || !strncmp(plname, "player", 4)
+                   || !strncmp(plname, "games", 4))
+               askname();
+       plnamesuffix();         /* strip suffix from name; calls askname() */
+                                               /* again if suffix was whole name */
+                                               /* accepts any suffix */
+
+       Sprintf(lock,"%d%s", getuid(), plname);
+       getlock();
+
+
+       dlb_init();                     /* must be before newgame() */
+
+       /*
+        * Initialization of the boundaries of the mazes
+        * Both boundaries have to be even.
+        */
+       x_maze_max = COLNO-1;
+       if (x_maze_max % 2)
+               x_maze_max--;
+       y_maze_max = ROWNO-1;
+       if (y_maze_max % 2)
+               y_maze_max--;
+
+       /*
+        * Initialize the vision system.  This must be before mklev() on a
+        * new game or before a level restore on a saved game.
+        */
+       vision_init();
+
+       display_gamewindows();
+
+       if ((fd = restore_saved_game()) >= 0) {
+#ifdef WIZARD
+               /* Since wizard is actually flags.debug, restoring might
+                * overwrite it.
+                */
+               boolean remember_wiz_mode = wizard;
+#endif
+#ifdef NEWS
+               if(iflags.news) {
+                       display_file(NEWS, FALSE);
+                       iflags.news = FALSE;    /* in case dorecover() fails */
+               }
+#endif
+               pline("Restoring save file...");
+               mark_synch();   /* flush output */
+               if(!dorecover(fd))
+                       goto not_recovered;
+#ifdef WIZARD
+               if(!wizard && remember_wiz_mode) wizard = TRUE;
+#endif
+               check_special_room(FALSE);
+               if (discover)
+                       You("are in non-scoring discovery mode.");
+
+               if (discover || wizard) {
+                       if(yn("Do you want to keep the save file?") == 'n')
+                           (void) delete_savefile();
+                       else {
+                           compress(fqname(SAVEF, SAVEPREFIX, 0));
+                       }
+               }
+
+               flags.move = 0;
+       } else {
+not_recovered:
+               player_selection();
+               newgame();
+               if (discover)
+                       You("are in non-scoring discovery mode.");
+
+               flags.move = 0;
+               set_wear();
+               (void) pickup(1);
+       }
+
+       moveloop();
+       return 0;
+}
+
+static void whoami(void)
+{
+       /*
+        * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS
+        *                      2. Use $USER or $LOGNAME        (if 1. fails)
+        * The resulting name is overridden by command line options.
+        * If everything fails, or if the resulting name is some generic
+        * account like "games", "play", "player", "hack" then eventually
+        * we'll ask him.
+        */
+       char *s;
+
+       if (*plname) return;
+       if (s = nh_getenv("USER")) {
+               (void) strncpy(plname, s, sizeof(plname)-1);
+               return;
+       }
+       if (s = nh_getenv("LOGNAME")) {
+               (void) strncpy(plname, s, sizeof(plname)-1);
+               return;
+       }
+}
+
+/* normalize file name - we don't like .'s, /'s, spaces */
+void regularize(char *s)
+{
+       register char *lp;
+
+       while((lp=strchr(s, '.')) || (lp=strchr(s, '/')) || (lp=strchr(s,' ')))
+               *lp = '_';
+}
+
+static void process_options(int argc, char **argv)
+{
+       int i;
+
+       while (argc > 1 && argv[1][0] == '-') {
+               argv++;
+               argc--;
+               switch (argv[0][1]) {
+               case 'D':
+#ifdef WIZARD
+                       wizard = TRUE;
+                       break;
+#endif
+                       /* otherwise fall thru to discover */
+               case 'X':
+                       discover = TRUE;
+                       break;
+#ifdef NEWS
+               case 'n':
+                       iflags.news = FALSE;
+                       break;
+#endif
+               case 'u':
+                       if(argv[0][2])
+                               (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
+                       else if (argc > 1) {
+                               argc--;
+                               argv++;
+                               (void) strncpy(plname, argv[0], sizeof(plname)-1);
+                       } else
+                               raw_print("Player name expected after -u");
+                       break;
+               case 'p': /* profession (role) */
+                       if (argv[0][2]) {
+                           if ((i = str2role(&argv[0][2])) >= 0)
+                               flags.initrole = i;
+                       } else if (argc > 1) {
+                               argc--;
+                               argv++;
+                           if ((i = str2role(argv[0])) >= 0)
+                               flags.initrole = i;
+                       }
+                       break;
+               case 'r': /* race */
+                       if (argv[0][2]) {
+                           if ((i = str2race(&argv[0][2])) >= 0)
+                               flags.initrace = i;
+                       } else if (argc > 1) {
+                               argc--;
+                               argv++;
+                           if ((i = str2race(argv[0])) >= 0)
+                               flags.initrace = i;
+                       }
+                       break;
+               case '@':
+                       flags.randomall = 1;
+                       break;
+               default:
+                       raw_printf("Unknown option: %s", *argv);
+                       break;
+               }
+       }
+}
+
+static void chdirx(const char *dir)
+{
+       if (!dir) dir = HACKDIR;
+
+       if (chdir(dir) < 0)
+               error("Cannot chdir to %s.", dir);
+
+       /* Warn the player if we can't write the record file */
+       /* perhaps we should also test whether . is writable */
+       check_recordfile(dir);
+}
+
+void getlock(void)
+{
+       int fd;
+
+       regularize(lock);
+       set_levelfile_name(lock, 0);
+       fd = creat(lock, FCMASK);
+       if(fd == -1) {
+               error("cannot creat lock file.");
+       } else {
+               if(write(fd, (genericptr_t) &hackpid, sizeof(hackpid))
+                   != sizeof(hackpid)){
+                       error("cannot write lock");
+               }
+               if(close(fd) == -1) {
+                       error("cannot close lock");
+               }
+       }
+}
+
+#ifndef __begui__
+/*
+ * If we are not using the Be GUI, then just exit -- we don't need to
+ * do anything extra.
+ */
+void nethack_exit(int status);
+void nethack_exit(int status)
+{
+       exit(status);
+}
+#endif /* !__begui__ */
diff --git a/sys/mac/Files.r b/sys/mac/Files.r
new file mode 100644 (file)
index 0000000..7842e92
--- /dev/null
@@ -0,0 +1,148 @@
+#include <MacTypes.r>
+#include "date.h"
+#include "patchlevel.h"
+
+resource 'plst' (0, purgeable) {
+};
+
+resource 'vers' (1, purgeable) {
+       VERSION_MAJOR, (VERSION_MINOR<<4) | PATCHLEVEL, final, EDITLEVEL, verUS,
+       VERSION_STRING,
+       VERSION_STRING
+};
+
+resource 'vers' (2, purgeable) {
+       VERSION_MAJOR, (VERSION_MINOR<<4) | PATCHLEVEL, final, EDITLEVEL, verUS,
+       VERSION_STRING,
+       "devteam@nethack.org"
+};
+
+read 'File' (1000,"cmdhelp") ":dat:cmdhelp";
+read 'File' (1001,"help") ":dat:help";
+read 'File' (1002,"hh") ":dat:hh";
+read 'File' (1003,"history") ":dat:history";
+read 'File' (1004,"license") ":dat:license";
+read 'File' (1005,"MacHelp") ":sys:mac:MacHelp";
+read 'File' (1006,"News") ":sys:mac:News";
+read 'File' (1007,"opthelp") ":dat:opthelp";
+read 'File' (1008,"wizhelp") ":dat:wizhelp";
+read 'File' (1009,"air.lev") ":lib:air.lev";
+read 'File' (1010,"asmodeus.lev") ":lib:asmodeus.lev";
+read 'File' (1011,"astral.lev") ":lib:astral.lev";
+read 'File' (1012,"baalz.lev") ":lib:baalz.lev";
+read 'File' (1013,"bigrm-1.lev") ":lib:bigrm-1.lev";
+read 'File' (1014,"bigrm-2.lev") ":lib:bigrm-2.lev";
+read 'File' (1015,"bigrm-3.lev") ":lib:bigrm-3.lev";
+read 'File' (1016,"bigrm-4.lev") ":lib:bigrm-4.lev";
+read 'File' (1017,"bigrm-5.lev") ":lib:bigrm-5.lev";
+read 'File' (1018,"castle.lev") ":lib:castle.lev";
+read 'File' (1019,"data") ":lib:data";
+read 'File' (1020,"dungeon") ":lib:dungeon";
+read 'File' (1021,"earth.lev") ":lib:earth.lev";
+read 'File' (1022,"fakewiz1.lev") ":lib:fakewiz1.lev";
+read 'File' (1023,"fakewiz2.lev") ":lib:fakewiz2.lev";
+read 'File' (1024,"fire.lev") ":lib:fire.lev";
+read 'File' (1025,"juiblex.lev") ":lib:juiblex.lev";
+read 'File' (1026,"knox.lev") ":lib:knox.lev";
+read 'File' (1027,"medusa-1.lev") ":lib:medusa-1.lev";
+read 'File' (1028,"medusa-2.lev") ":lib:medusa-2.lev";
+read 'File' (1029,"minefill.lev") ":lib:minefill.lev";
+read 'File' (1030,"minend-1.lev") ":lib:minend-1.lev";
+read 'File' (1031,"minend-2.lev") ":lib:minend-2.lev";
+read 'File' (1032,"minend-3.lev") ":lib:minend-3.lev";
+read 'File' (1033,"minend-4.lev") ":lib:minend-4.lev";
+read 'File' (1034,"minetn-1.lev") ":lib:minetn-1.lev";
+read 'File' (1035,"minetn-2.lev") ":lib:minetn-2.lev";
+read 'File' (1036,"minetn-3.lev") ":lib:minetn-3.lev";
+read 'File' (1037,"minetn-4.lev") ":lib:minetn-4.lev";
+read 'File' (1038,"minetn-5.lev") ":lib:minetn-5.lev";
+read 'File' (1039,"minetn-6.lev") ":lib:minetn-6.lev";
+read 'File' (1040,"minetn-7.lev") ":lib:minetn-7.lev";
+read 'File' (1041,"options") ":lib:options";
+read 'File' (1042,"oracle.lev") ":lib:oracle.lev";
+read 'File' (1043,"oracles") ":lib:oracles";
+read 'File' (1044,"orcus.lev") ":lib:orcus.lev";
+read 'File' (1045,"quest.dat") ":lib:quest.dat";
+read 'File' (1046,"rumors") ":lib:rumors";
+read 'File' (1047,"sanctum.lev") ":lib:sanctum.lev";
+read 'File' (1048,"soko1-1.lev") ":lib:soko1-1.lev";
+read 'File' (1049,"soko1-2.lev") ":lib:soko1-2.lev";
+read 'File' (1050,"soko2-1.lev") ":lib:soko2-1.lev";
+read 'File' (1051,"soko2-2.lev") ":lib:soko2-2.lev";
+read 'File' (1052,"soko3-1.lev") ":lib:soko3-1.lev";
+read 'File' (1053,"soko3-2.lev") ":lib:soko3-2.lev";
+read 'File' (1054,"soko4-1.lev") ":lib:soko4-1.lev";
+read 'File' (1055,"soko4-2.lev") ":lib:soko4-2.lev";
+read 'File' (1056,"tower1.lev") ":lib:tower1.lev";
+read 'File' (1057,"tower2.lev") ":lib:tower2.lev";
+read 'File' (1058,"tower3.lev") ":lib:tower3.lev";
+read 'File' (1059,"valley.lev") ":lib:valley.lev";
+read 'File' (1060,"water.lev") ":lib:water.lev";
+read 'File' (1061,"wizard1.lev") ":lib:wizard1.lev";
+read 'File' (1062,"wizard2.lev") ":lib:wizard2.lev";
+read 'File' (1063,"wizard3.lev") ":lib:wizard3.lev";
+read 'File' (1100,"Arc-fila.lev") ":lib:Arc-fila.lev";
+read 'File' (1101,"Arc-filb.lev") ":lib:Arc-filb.lev";
+read 'File' (1102,"Arc-goal.lev") ":lib:Arc-goal.lev";
+read 'File' (1103,"Arc-loca.lev") ":lib:Arc-loca.lev";
+read 'File' (1104,"Arc-strt.lev") ":lib:Arc-strt.lev";
+read 'File' (1105,"Bar-fila.lev") ":lib:Bar-fila.lev";
+read 'File' (1106,"Bar-filb.lev") ":lib:Bar-filb.lev";
+read 'File' (1107,"Bar-goal.lev") ":lib:Bar-goal.lev";
+read 'File' (1108,"Bar-loca.lev") ":lib:Bar-loca.lev";
+read 'File' (1109,"Bar-strt.lev") ":lib:Bar-strt.lev";
+read 'File' (1110,"Cav-fila.lev") ":lib:Cav-fila.lev";
+read 'File' (1111,"Cav-filb.lev") ":lib:Cav-filb.lev";
+read 'File' (1112,"Cav-goal.lev") ":lib:Cav-goal.lev";
+read 'File' (1113,"Cav-loca.lev") ":lib:Cav-loca.lev";
+read 'File' (1114,"Cav-strt.lev") ":lib:Cav-strt.lev";
+read 'File' (1115,"Hea-fila.lev") ":lib:Hea-fila.lev";
+read 'File' (1116,"Hea-filb.lev") ":lib:Hea-filb.lev";
+read 'File' (1117,"Hea-goal.lev") ":lib:Hea-goal.lev";
+read 'File' (1118,"Hea-loca.lev") ":lib:Hea-loca.lev";
+read 'File' (1119,"Hea-strt.lev") ":lib:Hea-strt.lev";
+read 'File' (1120,"Kni-fila.lev") ":lib:Kni-fila.lev";
+read 'File' (1121,"Kni-filb.lev") ":lib:Kni-filb.lev";
+read 'File' (1122,"Kni-goal.lev") ":lib:Kni-goal.lev";
+read 'File' (1123,"Kni-loca.lev") ":lib:Kni-loca.lev";
+read 'File' (1124,"Kni-strt.lev") ":lib:Kni-strt.lev";
+read 'File' (1125,"Mon-fila.lev") ":lib:Mon-fila.lev";
+read 'File' (1126,"Mon-filb.lev") ":lib:Mon-filb.lev";
+read 'File' (1127,"Mon-goal.lev") ":lib:Mon-goal.lev";
+read 'File' (1128,"Mon-loca.lev") ":lib:Mon-loca.lev";
+read 'File' (1129,"Mon-strt.lev") ":lib:Mon-strt.lev";
+read 'File' (1130,"Pri-fila.lev") ":lib:Pri-fila.lev";
+read 'File' (1131,"Pri-filb.lev") ":lib:Pri-filb.lev";
+read 'File' (1132,"Pri-goal.lev") ":lib:Pri-goal.lev";
+read 'File' (1133,"Pri-loca.lev") ":lib:Pri-loca.lev";
+read 'File' (1134,"Pri-strt.lev") ":lib:Pri-strt.lev";
+read 'File' (1135,"Ran-fila.lev") ":lib:Ran-fila.lev";
+read 'File' (1136,"Ran-filb.lev") ":lib:Ran-filb.lev";
+read 'File' (1137,"Ran-goal.lev") ":lib:Ran-goal.lev";
+read 'File' (1138,"Ran-loca.lev") ":lib:Ran-loca.lev";
+read 'File' (1139,"Ran-strt.lev") ":lib:Ran-strt.lev";
+read 'File' (1140,"Rog-fila.lev") ":lib:Rog-fila.lev";
+read 'File' (1141,"Rog-filb.lev") ":lib:Rog-filb.lev";
+read 'File' (1142,"Rog-goal.lev") ":lib:Rog-goal.lev";
+read 'File' (1143,"Rog-loca.lev") ":lib:Rog-loca.lev";
+read 'File' (1144,"Rog-strt.lev") ":lib:Rog-strt.lev";
+read 'File' (1145,"Sam-fila.lev") ":lib:Sam-fila.lev";
+read 'File' (1146,"Sam-filb.lev") ":lib:Sam-filb.lev";
+read 'File' (1147,"Sam-goal.lev") ":lib:Sam-goal.lev";
+read 'File' (1148,"Sam-loca.lev") ":lib:Sam-loca.lev";
+read 'File' (1149,"Sam-strt.lev") ":lib:Sam-strt.lev";
+read 'File' (1150,"Tou-fila.lev") ":lib:Tou-fila.lev";
+read 'File' (1151,"Tou-filb.lev") ":lib:Tou-filb.lev";
+read 'File' (1152,"Tou-goal.lev") ":lib:Tou-goal.lev";
+read 'File' (1153,"Tou-loca.lev") ":lib:Tou-loca.lev";
+read 'File' (1154,"Tou-strt.lev") ":lib:Tou-strt.lev";
+read 'File' (1155,"Val-fila.lev") ":lib:Val-fila.lev";
+read 'File' (1156,"Val-filb.lev") ":lib:Val-filb.lev";
+read 'File' (1157,"Val-goal.lev") ":lib:Val-goal.lev";
+read 'File' (1158,"Val-loca.lev") ":lib:Val-loca.lev";
+read 'File' (1159,"Val-strt.lev") ":lib:Val-strt.lev";
+read 'File' (1160,"Wiz-fila.lev") ":lib:Wiz-fila.lev";
+read 'File' (1161,"Wiz-filb.lev") ":lib:Wiz-filb.lev";
+read 'File' (1162,"Wiz-goal.lev") ":lib:Wiz-goal.lev";
+read 'File' (1163,"Wiz-loca.lev") ":lib:Wiz-loca.lev";
+read 'File' (1164,"Wiz-strt.lev") ":lib:Wiz-strt.lev";
diff --git a/sys/mac/Install.mw b/sys/mac/Install.mw
new file mode 100644 (file)
index 0000000..51580cf
--- /dev/null
@@ -0,0 +1,289 @@
+Building a PPC NetHack 3.4 with the Metrowerks compilers
+
+
+You must be familiar with the Metrowerks compiler and know how to construct
+projects.  The NetHack source may come with the four pre-made projects that
+are needed to build NetHack and the files it needs.  These four projects are
+in :sys:mac and are MakeDefs.u, DgnComp.u, LevComp.u, and NetHack.u.  If you
+do not have them, or wish to construct them yourself, see the section "Project
+Contents" below.
+
+
+1. Move the projects MakeDefs.u, DgnComp.u, LevComp.u, and NetHack.u to the
+top level of the NetHack tree.  If you are building your own, create each
+project as needed, in the order given below.
+
+2. Create a folder "lib" in the top level.  This is where the files used by
+NetHack will be deposited by MakeDefs, DgnComp, and LevComp.
+
+3. Build and run MakeDefs.
+
+You will be presented with a list of options.  Initially choose them all (the
+default).  Later you may wish to only run a few of them.  The options are
+"odemvpqrhz", each of which makes a file:
+
+                               -o creates :include:onames.h
+                               -p creates :include:pm.h
+                               -z creates :src:vis_tab.c
+                               -m creates :src:monstr.c
+                               -e creates :dat:dundeon.pdf
+                               -v creates :lib:options
+                               -d creates :lib:data
+                               -r creates :lib:rumors
+                               -h creates :lib:oracles
+                               -q creates :lib:quest.dat
+
+
+4. If you are _not_ using DLB, follow these directions.  As of v3.3, DLB is ON
+for the Mac.  Copy the following files.  You may want to change News or NHDeflts.
+
+               a. copy ':sys:mac:MacHelp' to ':lib:MacHelp'
+               b. copy ':sys:mac:News' to ':lib:News'
+               c. copy ':sys:mac:NHDeflts' to ':lib:NetHack Defaults'
+
+               d. copy ':dat:cmdhelp' to ':lib:cmdhelp'
+               e. copy ':dat:help' to ':lib:help'
+               f. copy ':dat:hh' to 'lib:hh'
+               g. copy ':dat:history' to ':lib:history'
+               h. copy ':dat:license' to ':lib:license'
+               i. copy ':dat:opthelp' to ':lib:opthelp'
+               j. copy ':dat:wizhelp' to ':lib:wizhelp'
+
+5. Create an empty file, ':lib:record'
+
+6. Build and run DgnComp.
+               This will create a file "dungeon" in the lib directory.
+
+7. Build and run LevComp.
+               This will build the level files (*.lev) in the lib directory.
+
+8. Build NetHack.
+               Move NetHack in the lib directory.
+
+
+------------------------
+
+
+Building NetHack with MetroWerks IDE 1.x (DR7-DR10, DR11 was never used)
+
+
+To build NetHack, you will need to create four projects at the top level of
+the NetHack directory tree.  These four projects are MakeDefs.u, DgnComp.u,
+LevComp.u, and NetHack.u.  The projects don't have to end in ".u", but you
+should append some form of ".XXX" to the end of the project's name to
+distinguish the project from the executable that it produces.  The files
+and libraries to include in these projects are listed in the "Project
+Contents" section below.  You must create and run Makedefs before creating
+NetHack because MakeDefs will create files used by NetHack.
+
+Use the MacOS C/C++ template for each of the projects.  The libraries included
+will be overkill for all the projects (e.g. the C++ libraries are not needed).
+Add the .c and resource files as indicated below.  Unless otherwise noted, the
+projects can use the default preferences:
+
+       Font
+               The tabbing on all non-mac files is 8.  All mac files have a
+                       tab of 4.
+       PPC Processor
+               All projects must have the same alignment to build a consistent
+                       NetHack.  To share save files with 68K, the alignments
+                       must match for their projects, as well.
+               Turn on Global Optimization (official version is compiled
+                       with level 1).  If you don't turn it on, some files may
+                       not compile because of register overflow.  [NetHack
+                       only]
+       PPC Project
+               Set name to <MakeDefs, LevComp DgnComp, NetHack>
+               Other settings [NetHack only]
+                       creator:                        nh31
+                       preferred heap size:2500
+                       minimum heap size:      2000
+                       stack size:                     128             [PPC only]
+
+
+The SIOUX library may be replaced with console.stubs.c for the NetHack
+project.
+
+NOTE: As NetHack 3.3, you must turn on OLDROUTINENAMES -- so you can't use
+the default pre-compiled header.  You should either remove it from the
+preferences or insert another precompiled header that has this define off.
+
+
+------------------------
+
+
+Building NetHack with MetroWerks IDE 2.0.
+
+This is for building a PowerPC version only.  This doesn't take advantage
+of the IDE's subprojects.  These will be investigated later.
+
+
+MakeDefs.u, DgnComp.u, LevComp.u:  Select ANSI C Console PPC.
+       Settings:
+               PPC Target
+                       + Change File Name to MakeDefs, DgnComp, or LevComp respectively.
+               C/C++ Language
+                       + Turn off ANSI strict, ANSI Keywords Only, Expand Trigraphs
+               PPC Processor
+                       + Turn on global optimization (at least to level 1)
+
+NetHack.u: Basic ToolBox PPC
+               PPC Target
+                       + Change File Name to NetHack.  Other settings
+                               creator:                        nh31
+                               preferred heap size:2500
+                               minimum heap size:      2000
+                               stack size:                     128             [PPC only]
+               C/C++ Language
+                       + Options ANSI strict, ANSI Keywords Only, Expand Trigraphs
+                         are already turned off, so you don't have to do anything.
+               PPC Processor
+                       + Turn on global optimization (at least to level 1)
+
+
+------------------------
+Creating projects for NetHack with MetroWerks IDE 3.3 (Pro 4)
+
+This is what I changed from the default settings when creating a 68K version.  Some of
+the settings may not be necessary.  For example, NetHack doesn't use floating point,
+so I didn't have to check 8 byte doubles.  Some are interrelated.  For example, the
+codegen and the Math and MSL libraries used.
+
+For MakeDefs.u, DgnComp.u, LevComp.u: 
+1. Select File>>New Project...>>MacOS>>C_C++>>Standard Console>>Std C Console 68K
+2. 68K Settings:
+       Target Settings:
+               + Set "Target Name" to {MakeDefs,DgnComp,LevComp}.
+       68K Target:
+               + Set "File Name" to {MakeDefs,DgnComp,LevComp}.
+       C/C++ Language:
+               + Check Require Function Prototypes, uncheck everything else.
+               + Clear "Prefix File".
+       68K Processor:
+               + Set "Code Model" to Large.
+               + Check 68020 Codegen, 4-Byte Ints, 8-Byte Doubles, Far Data, Far Method Tables,
+                       Far String Constants.  Uncheck everything else.
+3. Libraries 68K
+       + Remove the C++ Library (it is not needed).
+       + Change math library to MathLib68K Fa(4i_8d).Lib.
+       + Change MSL C library to MSL C.68K Fa(4i_8d).Lib.
+       Note: The actual libraries used must match the CodeGen options in 68K Processor.
+
+
+For NetHack.u:
+1. Select File>>New Project...>>MacOS>>C_C++>>MacOS ToolBox>>MacOS ToolBox 68K
+2. 68K Settings
+       Target Settings:
+               + Set "Target Name" to NetHack Debug and NetHack Final.
+       68K Target:
+               + Set "File Name" to NetHack Debug and NetHack Final.
+               + Set "Creator" to 'nh31'.
+               + Set "Preferred Heap Size (k)" to 2500.
+               + Set "Minimum Heap Size (k)" to 1500.
+       C/C++ Language:
+               + Check Require Function Prototypes, uncheck everything else.
+               + Set "Prefix File" to LocalDefines.h.  I use this header to define
+                 OLDROUTINENAMES because the pre-compiled header doesn't have it set
+                 any more.  One of these days we'll fix up the code...
+       68K Processor:
+               + Set "Code Model" to Large.
+               + Check 68020 Codegen, 4-Byte Ints, 8-Byte Doubles, Far Data, Far Method Tables,
+                       Far String Constants.  Uncheck everything else.
+3. Libraries 68K
+       + Remove the C++ Library (it is not needed).
+       + Change math library to MathLib68K Fa(4i_8d).Lib.
+       + Change MSL C library to MSL C.68K Fa(4i_8d).Lib.
+       Note: The actual libraries used must match the CodeGen options in 68K Processor.
+       
+
+For Recover.u:
+1. Select File>>New Project...>>MacOS>>C_C++>>MacOS ToolBox>>MacOS ToolBox 68K
+2. 68K Settings
+       Target Settings:
+               + Set "Target Name" to Recover Debug and Recover Final.
+       68K Target:
+               + Set "File Name" to Recover Debug and Recover Final.
+               + Set "Creator" to 'nhRc'.
+       C/C++ Language:
+               + Check Require Function Prototypes, uncheck everything else.
+               + Set "Prefix File" to LocalDefines.h.  I use this header to define
+                 OLDROUTINENAMES because the pre-compiled header doesn't have it set
+                 any more.  One of these days we'll fix up the code...
+       68K Processor:
+               + Set "Code Model" to Large.
+               + Check 68020 Codegen, 4-Byte Ints, 8-Byte Doubles, Far Data, Far Method Tables,
+                       Far String Constants.  Uncheck everything else.
+3. Libraries 68K
+       + Remove the C++ Library (it is not needed).
+       + Change math library to MathLib68K Fa(4i_8d).Lib.
+       + Change MSL C library to MSL C.68K Fa(4i_8d).Lib.
+       Note: The actual libraries used must match the CodeGen options in 68K Processor.
+
+
+------------------------
+
+Project Contents:
+
+MakeDefs.u should contain the following source files:
+
+       src
+               objects.c
+               monst.c
+       util
+               makedefs.c
+
+
+DgnComp.u should contain the following source files:
+
+       src
+               alloc.c
+       sys:share
+               dgn_lex.c
+               dgn_yacc.c
+       util
+               dgn_main.c
+               panic.c
+
+
+LevComp.u should contain the following source files:
+
+       src
+               alloc.c
+               decl.c
+               drawing.c
+               monst.c
+               objects.c
+       sys:mac
+               macerrs.c
+               macfile.c
+       sys:share
+               lev_lex.c
+               lev_yacc.c
+       util
+               lev_main.c
+               panic.c
+       
+
+NetHack.u should contain the following source files:
+
+       src
+               *.c                     [can do an add all]
+       sys:mac
+               *.c     except mrecover.c
+               NetHack.rsrc
+               machelp.bh      [for baloon help]
+               Sound.rsrc      [if you wish to have a few, crude sounds]
+               Files.r         [if you use DLB (on by default)]
+       sys:share
+               random.c
+       win:tty
+               *.c                     [can do an add all - termcap.c is not needed, but will compile to nothing]
+
+       Note: src:monstr.c and src:vis_tab.c are created by MakeDefs -m and -s
+       respectively.
+
+Recover.u should contain the following source files:
+
+       sys:mac
+               mrecover.c
+               mrecover.rsrc
diff --git a/sys/mac/MacHelp b/sys/mac/MacHelp
new file mode 100644 (file)
index 0000000..3197aed
--- /dev/null
@@ -0,0 +1,158 @@
+            Macintosh-specific help file for NetHack 3.4
+
+The following are options, features, or concerns specific to the
+MacOS Classic port of NetHack.  Bug reports, suggestions, comments,
+and so on, should be addressed to:
+
+    To: nethack-bugs@nethack.org
+    Subject: Mac NetHack 3.4
+
+or you can use our on-line bug reporting form at
+
+    http://www.nethack.org
+
+Please include your machine-type, system software version and other
+relevant information (i.e. system extensions, monitor, accelerators
+and so on).
+
+
+=== Configuration of a playground
+    NetHack is packaged in a Dungeon Folder which includes:
+        NetHack - the application file itself.
+        NetHack Defaults - text file for default option settings.
+        License - licensing terms for nethack.
+        Guidebook - description of the game in long format.
+        Recover - the application to restore save files from crashed games.
+    Previous versions had a large number of data files in the Dungeon
+    Folder.  These are now packaged as resources inside the application
+    file and will no longer appear in the Dungeon Folder.
+
+    During play another file type appears:
+        Player level files (labelled "iName.n", i is a constant number,
+            Name is the player name and n is the dungeon level).
+
+    Two other types of files will appear in the Dungeon Folder
+    as a result of playing NetHack:
+        Bones files (of previously deceased players).
+        Saved games (labelled "save/iName", i is a number, same as above,
+            and Name is the player name).
+
+    The following files or file types may be thrown away:
+        logfile - if it becomes too large.  A new one will be generated.
+        Player level files _not_ belonging to a game in progress.
+            Alternatively, these files may be processed by Recover,
+            which may be able to restore a save file from the level files.
+        Old bones files and saved games.
+
+
+=== Resuming a saved game
+    Double-click (or open) the desired saved game file or open NetHack
+    and answer the "Who are you?" dialog with the player name of
+    the saved game in the Dungeon Folder.
+
+
+=== Windows
+    The Dungeon Map and Message windows are the essential windows used
+    during window-mode play.  During tty-mode play there is only one
+    window which displays the map, messages, lists and other info.
+    For window-mode play, lists (e.g. the list of objects that may
+    be wielded) and special info windows appear as needed.  Windows
+    may be closed in the normal ways (i.e. clicking their close box,
+    choosing 'Close' from the File menu or typing the command
+    equivalent for 'Close', cmd-W) and the list windows may also be
+    dismissed by hitting the space bar (or Return or Enter Keys).
+    Hitting the ESCape key will dismiss special windows without
+    scrolling to the end.
+
+    The command "Reposition" on the File menu may be used to restore the
+    the startup sizes and locations of the various windows.  The
+    window positions are saved in a file labelled "NetHack Windows"
+    in the appropriate preferences folder.
+
+
+=== Default options
+    The following options are specific to the Macintosh port:
+    background:  - black or white
+    MACgraphics  - use enhanced dungeon map symbols [TRUE]
+    page_wait    - display  --MORE--  after messages [TRUE]
+
+    Default options may be set by editing the NetHack Defaults text
+    file (using SimpleText or your favorite editor).  The following
+    notation is used:
+
+        OPTIONS=name:Arnold,time,!tombstone
+
+    It should also be mentioned here that there are two graphic
+    interface modes available: 'mac' and 'tty'.  Choosing between
+    these interfaces is accomplished by the option:
+    window:mac - the default multi-window Macintosh(tm) interface.
+    window:tty - traditional Unix(tm)-style TTY window interface.
+
+    See option help (?f or ?g) for more details.
+
+
+=== Movement by mouse
+    The shape (direction) of the cursor over the Dungeon Map window,
+    typically, indicates the direction that you desire to move in when
+    the mouse is clicked.  Modifier keys affect mouse-movement in the
+    same way that they affect keyboard movement.  Clicking on yourself
+    means rest one turn and Shift-clicking on yourself means "open door"
+    in the subsequently indicated direction.
+
+
+=== Sounds
+    Real sounds (resources) have been added for various instruments.
+    The option "silent" [FALSE] controls whether or not a sound will
+    be heard when an instrument is applied.
+
+
+=== Explore and Debug Modes
+    As of version 3.1.2, you can enter Explore (aka Discover) mode or
+    Debug (aka Wizard) mode by choosing the appropriate entries on the
+    'Mode' popup-menu section of the "Who are you?" startup dialog.
+    This same dialog allows you to specify your role, race, gender,
+    alignment, and name, of course.
+
+    Starting in Explore mode is essentially the same as playing in
+    Regular mode except that if you are killed then you are given an
+    opportunity to override your death.  Because of this advantage,
+    your Explore mode scores are not entered on the scoreboard record.
+    You also get a wand of wishing in your starting inventory and can
+    see your intrinsic abilities using the command ctl-X (also available
+    on the 'Explore' submenu on the File menu).
+
+    Starting in Debug mode is only intended for developers and others
+    interested in characterizing bugs.  Using this mode for other
+    purposes will have confusing results and eliminate your enjoyment
+    of the game!
+
+
+=== Menus
+    As of version 3.1.2, the menus have been reworked to provide access
+    to all the NetHack commands and a special 'Kbd' menu was added to
+    facilitate play using only the mouse.  In some cases, a command may
+    appear on more than one menu.  In general, the commands have been
+    grouped to appear on an appropriate menu:
+    File  - commands related to windows, start mode and play control.
+    Help  - info commands generally not related to a specific game (i.e.
+            (key descriptions, version info, internal option editor).
+    Info  - commands that are generally game-specific (i.e. inventory
+            related, describe features seen on the map or name things).
+    Equip - commands related to things you might wield or wear.
+    Act   - commands for actions that you might do alone (i.e. wait,
+            jump) or do with another dungeon denizen (i.e. pay, chat).
+    Magic - commands for things that you might do with items (drop,
+            eat, read) or spell-related.
+    Bits  - commands for things you might do to dungeon pieces (i.e.
+            open door, loot chest, engrave on the floor, climb stairs).
+
+    The key related to a command generally appears to the left of the
+    menu entry for that command (i.e. w for wield and W for wear). A
+    leftmost # denotes an extended command (without a related key) and
+    a left cloverleaf or command symbol denotes a command that requires
+    either a control or command key modifier (i.e. holding down the
+    control or command key while hitting the related key).
+
+
+===
+The members of the Macintosh NetHack port team hope you enjoy this game.
diff --git a/sys/mac/NHDeflts b/sys/mac/NHDeflts
new file mode 100644 (file)
index 0000000..12a9c3d
--- /dev/null
@@ -0,0 +1,161 @@
+# SCCS Id: @(#)NetHack Defaults        3.4     2002/03/15
+# Copyright (c) 2002 by Dean Luick, Mark Modrall, and Kevin Hugo
+# NetHack may be freely redistributed.  See license for details.
+#
+# Default settings for the Macintosh port of NetHack.
+# Lines beginning with a `#' character are "comments" and are
+# ignored all the way to the end of the line.  Using this
+# method, some of the lines below have been disabled so you
+# can see an example without having those options actually
+# set.  Remove the `#' character to "uncomment" the line and
+# allow those options to take effect.
+
+
+### Display ###
+# Uncomment for the traditional single-window tty interface
+#OPTIONS=win:tty
+
+# Boulder symbol
+#OPTIONS=boulder:0
+
+# Color
+OPTIONS=color
+
+# Fonts
+#OPTIONS=font_map:NewHackFont,font_size_map:9
+#OPTIONS=font_menu:geneva,font_size_menu:9
+#OPTIONS=font_message:PSHackFont,font_size_message:9
+#OPTIONS=font_status:monaco,font_size_status:9
+#OPTIONS=font_text:geneva,font_size_text:9
+
+# Don't make dark corridors look like lit corridors
+OPTIONS=!lit_corridor
+
+# Enable sound and beeps
+OPTIONS=sound,!silent
+
+
+### Start-up and ending ###
+# Don't display the game introduction and new feature list at start
+#OPTIONS=!legacy,!news
+
+# Save game state periodically in case of crashes (recommended)
+OPTIONS=checkpoint
+
+# How to prompt for things after death
+#OPTIONS=disclose:+i na -v yg nc
+
+# Show tombstone and top scores at death
+OPTIONS=tombstone,scores:10t/3a/o
+
+# Show top ten list in its own window
+#OPTIONS=toptenwin
+
+
+### User input and feedback ###
+# Choose between menus or text prompts
+# (traditional, combination, partial, or full)
+OPTIONS=menustyle:full
+
+# Extended (`#') commands by menu
+#OPTIONS=extmenu
+
+# Increase the number of message lines remembered
+#OPTIONS=msghistory:60
+
+# Enable the number pad keys
+OPTIONS=number_pad
+
+# Pause for --more-- and make it boldface
+OPTIONS=page_wait,standout
+
+# Ask for confirmation with the #pray command
+OPTIONS=prayconfirm
+
+# Allow spacebar as rest command
+#OPTIONS=rest_on_space
+
+# Display experience, score, and time on status line
+OPTIONS=showexp,showscore,time
+
+# Turn off animations
+#OPTIONS=!sparkle
+
+# Display a little more information with some commands
+#OPTIONS=suppress_alert:3.3.0
+OPTIONS=verbose
+
+
+### Character ###
+# A Valkyrie...
+#OPTIONS=name:Brunhilda,role:Val
+
+# The old way works, too:
+#OPTIONS=name:Brunhilda-V
+
+# How about an Elven Ranger?
+#OPTIONS=name:Silwa,role:Ranger,race:Elf,gender:Male
+
+# Always a human female
+#OPTIONS=race:human,female
+
+# Or leave them commented out and the game will ask you
+
+
+### Inventory ###
+# Automatically dig if wielding a pick
+#OPTIONS=autodig
+
+# Disable autopickup (toggle it with the `@' command)
+#OPTIONS=!autopickup,pickup_types:$*
+
+# Automatically fill the quiver
+#OPTIONS=autoquiver
+
+# Don't use fixed inventory letters
+OPTIONS=!fixinv,perm_invent,sortpack
+
+# What you want to call slime molds
+#OPTIONS=fruit:grape
+
+# Desired inventory display order
+#OPTIONS=packorder:)[(
+
+# How much you're willing to carry without confirmation
+#OPTIONS=pickup_burden:B
+
+# Put weapon in secondary slot when wielding another
+#OPTIONS=pushweapon
+
+
+### Pets ###
+# What to call your starting pet, and its type
+#OPTIONS=dogname:Quinn,catname:Vladimir,horsename:Silver,pettype:dog
+
+# Don't intentionally attack your pets
+OPTIONS=confirm,!hilite_pet,safe_pet
+
+
+### Unused options ###
+
+# Now obsolete
+#
+# background, large_font, popup_dialog, use_stone
+
+# Obsolete way to obtain reverse video; use at your own risk
+#OPTIONS=palette:000/c22/2c2/ca0/22c/a2a/2aa/ccc/999/f00/0f0/dd0/00f/d0d/0dd/fff/999/444/622/62c/-222
+
+# Options used in tty window mode, but not mac window mode
+#
+# menu_..., msg_window, timed_delay, use_inverse, vary_msgcount
+
+# Options used by other ports but not Macintosh:
+#
+# align_message, align_status, ascii_map, BIOS, checkspace,
+# decgraphics, eight_bit_tty, ibmgraphics, ignintr, mail,
+# map_mode, null, player_selection, preload_tiles, rawio,
+# splash_screen, tiled_map, tile_..., videocolors, videoshades,
+# windowcolors
+
+
+# End-of-file
diff --git a/sys/mac/NHrsrc.hqx b/sys/mac/NHrsrc.hqx
new file mode 100644 (file)
index 0000000..cc3db83
--- /dev/null
@@ -0,0 +1,991 @@
+(This file must be converted with BinHex 4.0)
+:$%jPG%KKBfXZFR0bB`"58e*$8P0&4!%!N!I4j"fk!*!%!3#3!mRS!!$)k!!!"r`
+!N!30!"!!,3!`S!)!U!#3"4B!1!!R!1')'&0dE`a1CA4)B@0V,R*cFQ0UFfecFQ0
+PER4c+f036(0`F'pM!!"58e*$8P0&4!%!!&-"%!#3%V0,SqB!N!CM'`!!b!%`!!%
+!N!J,Z3#3""8!N!AQ!9`!!3#3#!Zi!*!%&3"3!'i!qJ'i!!%!N!J(e!#3""8!8!"
+Z!2S"Z!!"!*!)"p-!N!39!&!!EJ$k!EJ!!3#3#!I5!*!%&3"3!'i!qJ'i!*!$(!%
+)!!J"5J$`!*!+"dePFh0KCf8i#J#3!a`",J!%!9)"bJ#3#JC6G'&dGA0V1!S!N!-
+@!(`!fJ$i!BS!N!3"!*!'66J+!*!$'J#q!!B"8!%b!*!%!3#3"34*EQC[)$J+!*!
+$)J!S!#J!M!#L!*!%!3#3"3e1G@aX)&GTEQ4[Gb!K1!S!N!-m$NjeE@*PFL"[CL"
+VCAPc6d019!8UN!9-8e4$"dYPH@0[C'9)3PP8"%0SBA*$5%&5"5U3"8a69%8!N!-
+J!#J!+!&+!Hi!N!S,4(9ZCf9[EL"0BA!i#J#3!b!!+!!S!+`"c!#3"!%!N!8,4'P
+KCfj[Fh4TBh-i#J#3!aB!!400B@-J6Q9d5'&MDb")C@a`b5mr!*!$J!#3#`rr!*!
+%r`$a!I!!N!2lm!m3(`#3!`qr$`%"m!#3!r[r%"$`!!$`$lrrmI!!$`rrqr!2!!!
+2%"$r[`#3!`m"!I$lm!#3!r!3m!qr!*!$$`%2!2[`!*!$rr!!$lm!N!Ilm!#3"Jq
+r!*!(r`#3!i!!rj!%m!#3!r!!N!2r!*!$m!#3!rc`!!$`!*!$rrm!!2!!N!32!!$
+`$r!!!!m!!2$rr`!!$`!!m2rr$rm2!!$`$r!!!!m!!2!!N!32!!$`$r!!!!m!!2$
+`$`r`$`!!m2!2!!!2!!$`$r!!!!m!!2!!N!32!!$rN!B!N!4!!!!"`$)J14!G#!m
+)*qKIN!"$`%,J)R!41!iF!!i!"`!$!!!"`$2J1I!Gq!ri*rKrN!"r`(lJ2R!I1!i
+F!!i!"`!$!*!$3$rJ)$!J+#!m)!3Q"#m%,h3Q"#!%*J3TC#N%*J3J"$rm2q!rm$r
+i2r`rr$rm2r`rr$rm2r`rr$rm2r`rr$rm2r`!!!%!N!B2J!!!-'!!%#!3!"`3#!!
+1%!J!$a!%!!H3!!3!!r!%!!(J"!!!m!3!-2[N!%mq'!"!(J!!3!m!!%!2J!"!%m!
+!3"(J!#!3m!!J%(J!%!Jm!!`B(J!$i!m!N!-(J!!!!m!!!!(J!*!$m!#3!hJ!N!-
+m!*!$(J#3!`i!N!-%!*!&$i!!!$rJ!"!rm!!F(rJ!$Kri!!mIr!!(Rr`!!rrm!!(
+rr!!!rr`!-2rm!(rq'!"rrJ!!Irm!!(rrJ!"rmm!!Ir(J!$r`m!!rm(J!(rJm!!r
+i(J!$i!m!N!-(J!!!!m!!!!(J!*!$m!#3!hJ!N!-m!*!$(J#3!`i!N!-%!!!"!!r
+rr!!)!!B!#!i&!!Q4")!*b)4!#1K%)!Ki4r!*2d!3#[b!%!SH!"!+&`!3#41!%!L
+*`"!)F1!3#!"`%!J!1"!)!"J3#'!!%!L3!!!3#@J!%!PTrK!)N!!!%!KJ!"!)!!!
+3#'!!%!L3!!!3#3J!%!N*[j!!#*!!!"!)B!!3#!!!%!rrrr!2rr`!$rrq!!rrr`!
+2rrq!$rrr`!rrrq!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!
+2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!
+2rrr`$rrrm!rrrr!2rrr`$rrrm!!!!J#3&rrrm!#3$2m3%"r`!*!($`#3!r%"N!-
+2!*!($rm!!!m3N!6`!*!(qr!!$`'3"2!!N!Il[`!2%*!%(`#3"`qlm!m"N!32!*!
+)qlrr%*!%(`#3#!qlm3'3"!m!N!Rl[a#3""m!N!Er!!$rZr(rrr%2!*!&$a$rra$
+l[r!!$r!!N!82!C!%$l[`!*!)$a#3"IZr!*!)$`'3"Iqlm!#3"`m3N!3I!2Zr!*!
+($`'3"!m!$l[`!*!(m"#3!am!!2Zr!*!(m3'3!`m!!!qlm!#3"Jm3N!6`!!$l[`#
+3"rm"!3r`!!!2Zr!!N!Irrr!!N!6l[`#3$Jqlm!#3$[Zr!*!1$l[`!*!1qlm!N!i
+2Zr!!N!ll[`#3$Jqlm!#3$[[`!*!1$`#3!`)!N!2rN!N!N!I`!*!($r!!N!E`!*!
+$rr!!!!r2!*!'m!r`$a!I!!!2c2!!N!A`$lm!m3(`!!r-c`#3"I!!qr$`%"m!$mc
+-m!#3"2!!$lra!3m!$rq3!`#3"2!2!2[rram!N!32!*!%m2$rrlm!m!#3"!m!N!6
+`m3%2qr!!N!82!*!%m2!3(`qr!*!&$`#3"2!2!3m!qr!!N!32!*!%m!$`%2!2[`#
+3"!m!N!6`!!rr!!$lm!#3!`m!N!6`!*!&$lm!N!-2!*!%m!#3"[[`!!!2!*!%m!#
+3"Jr`!!!2!*!%m!!2m!#3"`m!N!6`!2!2!*!($`#3"2!2$r$`!*!'$`#3"2!2$r$
+`$rq3!r!!$`#3"2!!m!m!N!F2!*!%m!!2m!#3"`m!N!6`!*!+$`#3"2!!$r!!N!F
+2!*!%m!$`$`#3"`m!N!6`$`!!m!#3"Jm!N!6`$`!!m!r`rj!$m!m!N!6`!2!2!*!
+($`#3"2!!$r!!N!F2!*!%m!#3#Jm!N!6rN!`!N!8-!&S!EJ$Z!C)!J84%!*!$6!!
+#!*!&H!$'!)S"%!3#6dX!N!8+!%B!F`%3L"a$Eh9XC#"ZEh3JAM)JBQ9MBA9cC5"
+H-#iJ)&ia!*!&#J!8!#S!0+!#!*!%!3!2rr`!#!!'!!J1"3!*N35!#FL%3!MS4#!
+)H%I`#6p!%!VmJ"!+(J!3#KF!%!N6J"!)LF!3#($J%!J!F"!)!$J3#!!B%!Q8aP!
++95P3#P8T8!T9+9!+95P3#C6'8!J!!"!+C6'3!!U95P!+P8T3#T9+8!U95P!+C6'
+3!!J!!"!2rrr`$rrm!!rrrJ!2rrm!$rrrJ!rrrm!2rrrJ$rrrm!rrrr!2rrr`$rr
+rm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rr
+rm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!!N!0!2q!
+J-#!S)$`J"#5N+U3UT#5N)!3T*#UN+U3T*#!%2r`ri$r`2rJrr$rm2r`rr$rm2r`
+rr$rm2r`rr$rm2r`rr!!!!J#3!rq3#3#3"r!!N!F2m!#3"[!!N!2rm!!!$mm!N!E
+`$r!2%"m!!!r-m!#3"I!2[`$a!I!!$mc2!*!&m!$lm2!3(`!2c-c`!*!%m!!2[r%
+"$`!2rj!$!*!%m!m!qrrr(`#3"!m!N!6`m2rr[`$`!*!%$`#3"2$a!3rlm!#3"3m
+!N!6`m"!I$lm!N!82!*!%m!m"$`$lm!#3"!m!N!6`!2!3m!qr!*!%$`#3"2!!$rm
+!!2[`!*!$$`#3"2!!N!82[`#3!`m!N!6`!*!'qr!!!!m!N!6`!*!'$r!!!!m!N!6
+`$r!2$`$r!!r`$`m!N!6`m!q3"!$`m!q3!`#3"2$`$j!%!2$`$j!$!*!%m2!2N!3
+!m2!2N!-!N!6`m!q3"!$`m!q3!`#3"2!2m!m2!2m!$r!2$`#3"2!!N!S2!*!%m2!
+2m!m2!2m!$r!2!*!%m*!$$j!%!2$`$`m!N!6`N!-2N!3!m2!2$`#3"2#3!`q3"!$
+`m!m2!*!%m*!$$j!%!2$`$`m!N!6`m!r`$`m!r`!2m!m!N!6`!*!+$`#3"2q3$!#
+3"5)!!3#3"9!"4!"N!Ai%!Np,!*!&"J!i!%B"I)J#AM!!N!1!!2q3"2!!N!2`!*!
+$r`#3!r!!N!2mm!!!m!#3!rrr!!$`!*!%$`!!m!m!m2!2!!$`N!82!!$`N!82!!$
+`$`$`m!m!!2!!N!32!!$`m!m!m!m!!2#3"3m!!2#3"3m!!2$`$`$`$`!!m!#3"!m
+!!2q3"J#3!`Q)N!!!N!6q!!B!!2rh!!B!#`1l!!N!!J#3!cm!N$2B!*!'&%%!N!8
+T3!!!-!!!'J!!!KK!"@YBL8!(i$P%))"!"*A!F"`"`K3!&3!8))r!rr!"q!#3!h1
+!)!#3"5!!!!jJ!3!3!*![F!"3L!)B"!%#J+)!"!))J!!!B!"")K0X!!!#+)!!!IL
+*3!@J+83JJ%!%P8"3&!&#&!!9!"3JMm$rm!d)!*!$*%"3![2!!!3J!`!*N!!'e6R
+X6#!!"FZF,l[ZF!!1Flc[Iqk2$'%BZmlc[aM'-ImD!J3!%"JK--!!N!-#!*!%UDl
+j&+%N#P#YA1q"kP%846SJP(a#4#@Ll%!#55!&DeL*3!@J+83JJ%!%P8"3&!&#&!!
+9!"3JMm$rm"-!2J!fG&a!"I`J%KSJ")!*)26IeV+5U3!'2'*S3$'))*'-BaM#%BS
+-SEc'-Ba*'-94$3d""!!3)#!33!#3!`)!N!5UdIJ!!"J!N!-M'!+!!*!$4L5#SN!
+!!$-b!!+U!!!"q)P!"D!T4##!3!593&!8!8)8!"8!&##2`2r`)`!5!!QXBL!pr$q
+4+L3-Z$P!PB95e#&a!!TS3Upi-BeI3HaM#-)3LJdK@XBaM!NBa*%8L!"rR2Gcr6*
+pChRfImBeM(kS%&1Hplh1Fj*M'$U1Fk-BaLlRiZI1MDXb3!&9B!9V@2P"rErTI##
+!3!6eIprhrhq9q"Ai&IL2`2rhC3I)r)L[iZh,r#"mb#"cI#RqPiqj5#'[ciUSM5$
+%6SL!)Urp#2[6qJiK'FI4miNBa)SNL!#-BaLNBc4VQ-BjJNBe9%8%%&4M'-BaM&*
+rreI4M'-BaM@"2%M4MQEXMriCDC!!!Iq2IM'aMmIrN!5A-``c$#"q"rmRrLIrN!2
+iT3+&&)LXBaV,r$q4+$q)I%!1N!#&&E8K)3!6+32`a*&iAd6dB`M#%BU0)4M'%BK
+*'05%4%J!M'%IT'-mDaM'-(*'054)U""hiaM'(rr5BaKqNBaM'-BdKq4)dBaL!3J
+%)I*0DeMj5rfpq$a!!N!%pIIrGrprJIP"r4Ai6rrm#+-#L45)G'-Gdr`J%KJJF(p
+!$T!!!&Db%J%!%LSL+-54###!K'-B`K'+M+%BaK'-549Y4)4)!*aK'#4M-QXBaM!
++69988+J4*#FjcK#%%Q-B8T'-CcM'0BNZ5G'FBrmB"%"b5!(iL8SPT3!!3!*!"*3
+8!93"3!!K3#88)%rrr!LM!T-8L#49%&2m2i!)*)!iJ!#3!)!k63`!%'(2h#FiMR8
+!"(4mlhi1Mh4r',S1LiML4L6q12a[R[HMic&V&hR`mE5+LrkS$L2DeVA[Hp*M(pl
+ZFjVAZFla*%E1E')!i!"`DC9V@)P+*D8!!%!#3!58&!&8!8!!)8!P&#"2rr`(E3+
+qjdKcYZ!pr#"rq5!!!)!!m!!3!*!$%#!!N!8"!*!-!3#3"L!!N!9!)!!!3#!!N!4
+!F!*`!*!$J!#3#B!%!!C!!*!*!IL*5L@P!!"!!N!%P"3"9!&!!#&!*43J6rrm!#!
+!!!3!N!3Krq!!#5!!N!SJ!*!'!J#3'!1!`!!!3#!!N!-$J!!%!*!$!3#3#3F!N!-
+"J!#3#!9V@)P+*qF!!%!#3!58(!(F!F!!)8!P&#"2rr`!N!3%!*!%3!#3!`M!!*"
++!3!%!!N!$J!6!"J!'J!G!#!!*3!U!#`!-3!b!$B!1`!p!%)!4`"-!&%!9J"E!'!
+!C3"Q!'J!D`"`!(-!H!"p!))!K`#-!*%!PJ#E!+!!T3#S!+d!XJ#h!,`!`3$'!-X
+!d!$9!0S!h`$N!1N!lJ$c!2J!r3$r!3-""3%)!3i"%!%9!4S"(`%N!5N",3%b!6F
+"1!%l!8!"3J&(!8`"83&@!9X"B!&P!@N"EJ&c!AJ"I3'#!BF"LJ',!Bi"N`'6!CJ
+"R3'L!DF"V!'a!EB"Z`(!!F8"bJ(0!G!"dJ(A!G`"i3(Q!HX"m!(e!IS"r`)%!JN
+#$J)6!KJ#(3)L!LF#,!)a!M-#1!)p!N)#4`*,!Nm#9!*C!Pi#C!*U!QX#F!*e!RS
+#I`+%!S8#L3+0!T)#P`+E!U!#S`+S!Ud#XJ+f!VS#[3,$!XN#c!,5!YJ#f`,I!Z-
+#j`,Y![-#p`,p!j!$#3-2!a8$'`-I!b)$*3-T!bm$03-j!c`$3J0)!dX$6J08!eS
+$A`0P!fS$E`0e!hS$J!1&!iS$M`18!jN$R`1P!kX$X31f!lN$[!1r!m-$b!20!p%
+$eJ2A!p`$i!2N!qF$l3!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B
+!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!D3!`)'!3B!"J!'!!B!"J)'!3B
+#"J!'!!B""J!'!JB""J!'!JB!"J!'!!B!"J!'!!B!"J!'!JB""J%'!!B""J!'!!B
+!"J!'!!B!"J!'!!B!"J!'!3B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B
+!"J!'!JB""J)'!3B!"J%'!!B!"J!'!!B!"J%'!!B!"J)'!!B!"J%'!!B!"J!'!!B
+!"J!'!!B""J!'!!B!"J!'!!B!"J)'!JB""J!'!*!$"J!'!!B!"J!'!!B!"J!'!!B
+!"J!'!3B""J%'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B
+#"J!'!!B!"J!'!3B""J!'!!B!"J!'!!B$"J!'!!B!"J!'!!B$"J!'!!B!"J!'!!B
+!"J)'!!B!"J!'!!B!"J-'!!B!"J-'!!B!"J-'!JB#"J)'!!B!"J)'!!B!"J!'!!B
+!"J!'!JB$"J-'!JB!"J!'!!B$"J!'!!B!"J-'!!B!"J!'!!B!"J!'!!B!"J!'!!B
+!"J!'!!B!"J!'!!B!"J!'!!B""J%'!`B!"J!'!!B""J!'!JB!"J!'!!B""J!'rrm
+!!![HN!!!N!6r!!F!!2rp!!F!$`6P!!`!!`#3!d)!N$`i!*!-"S!!N!99UeBL8!(
+i$P%)%!)!#)T`"`"`!F%&!!#N!!S)%2i$rrJ!N!dJ!*"!"84!!*!%#P!!!!`!!!X
+!N!-JJ!!!!IiL8!&S#P%)%!)!#)T3"3"3!8%&!!#N!!S)%2i$rrJ!N!N$`!!!)!!
+!#Q!!!"!!$!#3(("`!*!3(!#3"!B!N!4%J!#3#"!!N!BJJ!"9UeBL8!&S#P%)%!)
+!#)T3"3"3!8%&!!#N!!S)%2i$rrJ!N!8i!"J!p#!!!#!!!!f3!!$915a5)!!#jFi
+AcIFi!!(!1mlhrZM`aK',[1mlmBaM(mJ5!)%!"!B)6!#3#5TVJ#)!L3%!J+Fli(X
+!JL!1L!dI%%L%f,h%!#++!!!"rL*3!@J+83J3!J!)LP!&!&!"338!!+3!#JJ3rJ2
+rq!li2J!!%FiJ!I`J!#!J!`!j)(hIeV*5U!!$(M%d%"M%##)J4M'-)4LJbKZ-BaM
+%NBaM%-J9!%%!"!J)6$!!N!5!!*!$+V4845K*!T4,@-B!T*4&%9')%+L3!*%*D-B
+N!#55!&@V9L*3!@J+83J3!J!)LP!&!&!"338!!+3!#JJ3rJ2rq"&))J!ENM%J"I`
+J"%`J")!T6d698Y*KF3!&&#&8)"M%%"![4M'-)3LJdKA-BaM!NBaM%-3BJ!%!"!J
+)""!!N!5!!*!$+J4!!!!'!*!$#-B!S!#3!a'*%IL3!!!!$-BJ!!JJ!!!"rL*3!@J
++83J3!J!)LP!&!&!"338!!+3!#JJ3rJ2rqh&!%!!N1M%3"I`r)T)N")!Trd5&-G3
+KF3!&0#DA[#G'TmK3ap#-)3LJiK'XBaM!NBa9%833!"rR2Gcr6*pjhRfGdBeM(kS
+%)ZHplh1Fj*M'$U1Fk-BaLj!!5,RcSfV'*!!@5PT9UeBq8(p[qPm)%!)!#2TIrIr
+IrhrP2i#Rq!Tr%2i$rrb54mMm4%BaH"hm)#&5)%Xi)!p%MjL))Dr!#94"q'*)aX!
+%P[i`MldrS-)4R(dI1*'-5+*#%!!M'-BT'-dDaM'1BT'094&*"#-BaM'-Ba5BapA
+mBaM'-Bejra)dBjQpa2rTQU8!!IrMhiaXBr(rN!@,aM"JaJ`3(m"rr%IrL2q3"2b
+53S8N4%IaMZ[m2rS`2l"m)!p%K498)5%2LC5"%'*)[#I)PXB`M#%BS1)4M'%BK*'
+-9%4#%!!M'%IT'-iDaM'-A*'054)U"#2iaM'(rr5IrKHNBaM'-Bd35")dBaL!#)"
+"+d,9UeBq8[p[IJm3!#)!#2Tqrr[IrhrJ2j3(r3Tr#2rrr!0a3SNN4%BaM@[m)#3
+4)%Kq)!p%!"@bS3%!%48"%'*)K"!3&mB`M#%BU0)4M'%BK*'0BNK"%!!M'%B*'-d
+DaM'-!T'0543U"#-)aM'%)35BaK5NBaM'-Bd554)dBaMrm)"#Id+!!IiL8SPT3!!
+3!#)!#)S#J!T3!8!!""3!43S)#2rrr!!43T%N4%BUMZ[m2b$a*,"pS!p%J&Da%J!
+384B4&'*)LSJJN!"'-B`K'+M+%BaK'-549Z*)34!!*aM'+4M-QXBaM#+6998B+J4
+R'FjcM'%8Q-B9T'-CcM'08NZ5G'FBJ"%!"!UP9DY@)P+*D8!!%!!L!!L+!S!+8!&
+!!!38!%8+#!Mrrr`!%8+M*-3k+SJVr#!(%-!!1'!!4)!k6T)!%'$RlK1F4c+!!)p
+(c[IJk2G(mBZJk,L1*'*2`*!!Ia[R2FMic&V&hR`FE5+LrkS$QZDeVA1Hj*M(lVZ
+FjVAZFla*%E1E')!1!!m+@J!"rL*5L@P!!"!!)J!)LJ+!#P!"3!!%&!"&#JJ)rrr
+m!"C#[XG#%GY`(IrJq"!!N!-J!(d!%!!-!"!J!*!'J!#3$%!!N!9`m!#3"4!)!!!
+3#!#3""!F!3#3"#!!N!NJ!3!"%!#3#9@V9L*5L@P!!"!!)J!)LJ+!#P!"3!!%&!"
+&#JJ)rrrm!"!!!!3!%!!!%IJ!!"!!N!XJ!*!'!3#3$5!!N!X"%!J!!"!)!*!$!4!
+!!3#3"#!!N!NJ!!!"i!#3#J(q)P+*D8!!%!!L!!L+!S!+8!&!!!38!%8+#!Mrrr`
+!N!3%!$J!!"!!N!-3!*!Yi$!!N!MJ!!)!N!4!!*!)!F!!N!e9UeBL8SRj`!!3!#)
+!#)S$J!j`!F!!""3!43S)#2rrr!#3$4!!N%X"!!3!#3!1!"-!'3!D!"d!)!!P!#S
+!,!!a!$)!0`!m!$i!3`")!%d!8J"A!&`!B3"Q!'F!D3"Y!()!GJ"l!)%!KJ#,!*!
+!!*8!QJ#I!+3!U3#X!,%!YJ#l!-!!a3$+!-m!e!$C!0i!i`$S!1d!mJ$h!2`"N!-
+%!3N"$!%4!4J"'J%I!53"+3%Z!6-"0`%m!8%"3J&&!8S"6!&4!9B"@`&J!@8"DJ&
+[!A-"H!&p!B)"K`'-!C%"P!'9!CJ"R3'G!D)"T`'X!E%"YJ'l!F!"a3(+!Fm"e!(
+A!GS"h!(K!HB"k`(`!I8"qJ(r!J3##3)1!K-#'!)G!L)#*`)X!M%#0J)l!Md#3J*
+(!N`#83*@!PX#B!*P!QS#F!*f!RF#I!+"!SJ#M`+@!TF#Q`+I!U3#U3+Y!V)#Y3+
+k!Vm#a!,)!X`#d!,A!Yi#iJ,T![!#p!,j![i$N!-+!a%$&J-G!b3$+`-b!cN$3!0
+&!dN$6305!eN$B!0N!fJ$E`0f!hS$IJ1&!iX$N!!$P31D!jm$T31U!l%$YJ1l!m!
+$a32+!mm$e32E!q!$j32S!qX$l`2c!rJ$r33""!B%"`3-""!%&!3B""J%(`!(!!F
+!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F
+!"`!(!!F!"`!(!!F!"`-(!JF""`%(!3F!"`-(!JF#"`%(!3F#"`%(!`F""`%(!JF
+""`%(!3F""`%(!3F""`%(!`F#"`%(!3F#"`%(!!F""`%(!3F""`%(!3F""`%(!JF
+""`%(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!JF""`)(!3F!"`-(!3F
+""`%(!3F""`)(!3F""`-(!3F""`)(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F
+""`)(!`F#"`%(!!!""`%(!3F""`%(!3F""`%(!3F""`%(!JF#"`)(!3F""`%(!3F
+""`%(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F$"`%(!3F""`%(!3F""`%(!3F
+""`%(!3F$"`%(!3F!"`!(!!F$"`!(!!F!"`!(!!F!"`)(!!F!"`!(!!F!"`-(!!F
+!"`-(!!F!"`-(!JF#"`)(!!F!"`)(!!F!"`!(!!F!"`!(!JF$"`-(!JF!"`!(!!F
+$"`!(!!F!"`-(!!F""`%(!3F""`%(!3F""`!(!3F""`%(!3F""`%(!3F""`%(!3F
+#"`)(!`F!"`%(!3F""`%(!`F""`!(!!F""`!"!!Irr`#3!d)!m!#A!*![!3!"!!N
+!!%Z*!!`!!%Z-!*!$&J!+@APEDeae9QKAEeKX8f*8DP9Z8L`!N!-@!!TC@9Y,A&9
+@5&G[@%a63P4+98j5,!#3!d*J!!#B!*![!3!"!!N!!$J*!!`!!$J-!!!)`T!!!*!
+%l`!+!!$rpJ!+!!`$C`!+!!)!N!-d!*!a!i"0!*!G(i(!!*!'F"`(!(!!N$T83*C
+5J!!"J!#3%J+J!*!%&S&!!*!%J!"3&!8!8!#3#383!-$!!!#!!*!A!FB!N!i$J!1
+!!!!*#"C!N3'3!&*%"54!6!!i!!(Ki!#3#4D"6J#3!`d!!&!8"3"3!!&93!!!$c`
+!hlRp*58!!,PhaI0pcJ!"MK21jrZM$')1AHGjhiaJaMp#J))!3-)6'!#3!`3!N!-
+&65%GqA43P@Q"#UCYT#UD3URb3d32FK)ALd!qGU!!L$2rP[P4!!#J#3!!9j3&!&!
+!!TC!)N!I`rM99NP'%K!"4iL0"!Ba""*4%M'84'--SajM'-BNM'$')b0!3J""!J%
+)!*!$"!#3!`9@)5-CM%!!N!Y5j%(9MFc+h!43L!3N9)NTGXpJJ$3!%35!A2B&JGJ
+!!UU)8!qI``L2dP##(j!!!88*&HJ+-D[SCUS`M%3M$5+YBaM'")a9+88L!"ZCfjq
+h,fjZHhmaJaRe3(+K&BaGhGhCQC[fjQCQQCP09$[eM5d+U$j3QU4#r*5*4ZaJ[NL
+J%lL%cF2mr`YJ!*!$LM"I``L&1EP5%Rcb441N(`R2%!5UUp#2G2m1)NeMk2R%LT8
+3L4)!"QCP*P0-QCQFK5T8U5JJFU(9M'D3"@95QC!&38j(pEA0#SJ)r+JIJ55N5AD
+[i-PC2k&&5Aer$F2FN!!!!$m'-2r$#)!8CL)9%!*&)(iBNL%,k5Vq-)a%BidL$1-
+)d#5+LLL4%J!HBRdQ8ibCQCKP+P4*48$ri41-CT!$Brrp8TQ3"3&81qq0,-J!2T!
+!bU4#r+5*&UJ46fSLS6P5"3(GIP6rr!!!LM"r``J!9+C5%"!%484&'*)L""!R4M'
+84'1-SJcM#XSNL3T%N3S!*QCK*P0-QCQB&53SUB9!M'-6M'D3"#)K8TQ3"3$NKF@
++%K!!%4#)"#3NT5N@U!T)5Q*"3LN&!&8!9)!!!!K5,jr$#)!j'BNJ!3`jqi6R%Fb
+J!4"(cZI$Sh4q$&d(4F4a#N5I#MmIQGNH8bbCERMLj#NAp8#-AI&cRGhGfGQG8TC
+QCRGh!%p%"E(Ki!!"(h+rrbGEk4Di'ckaS%%$j)F!93"6i!#3!b(SRm2i!"!!!-!
+"!*!()!!1!*!*!3#3"3''!*!%"!)!!!J3!*!$!31!!!J!N!8)!*!+1!#3#J3!!"q
+!!*!%!3#3"&F!F!#3"5!IrJ#3"J)!N!G!!*!A'!`!!!J3!*!$"J#3!a!!N!83!*!
+9"!#3#!)!N!4`!*!'!F!!N%J"!!3!#3!1!"B!(3!H!#%!*!!T!#i!-!!d!$8!13!
+q!%!!43"+!%m!9!"C!&i!B`"S!'N!D`"Z!(-!GJ"k!)%!KJ#,!*!!!*8!Q3#G!+)
+!T`#S!+d!XJ#f!,d!`J$(!-`!d3$@!0X!i!$P!1S!m3$f!2X!r`'3!`8""`%+!4!
+"%J%@!4S"(J%L!5B"+J%Z!6)"0!%h!6X"23&%!8J"6!&3!93"@!&F!9m"B`&S!@m
+"G!&i!A`"I`'!!B-"L!')!Bd"NJ'A!CX"S!'P!DS"VJ'b!EB"ZJ'q!F)"aJ(+!Fi
+"dJ(@!GJ"fJ(G!H!"j!(S!H`"m!(d!IJ"r!)!!J3##!),!Jm#&!)C!Ki#)`)S!Ld
+#03)p!N8#4`*+!Nm#9`*H!Q-#D!*X!R!#G3*k!Ri#J`+*!Si#N3+9!TS#S3+S!Ui
+#XJ+c!VF#[J,"!XB#b`,4!Y8#f3,I!Z8#k3,[![8#r!-!!`B$#J-1!a!$%J-A!ai
+$)`-V!bX$+`-V!bX$+`-V!bX$+`-V!bX$+`-V!bX$+`-V!bX$+`-V!bX$+`-a!cF
+$2J#3$2q3"JB'rj!'!!$rN"`!"rq3"J-$!3-""3%(!!B!#3!)!3-!"!!%!3F!"J%
+%!!8"!`%'!!B""J!'!!B!"J!'!!B!"J!'!!B#"!%%!38!"J%&!3B!#!%(!!B!"J!
+'!!8!"3!'!!B"!`!'!!B!"3!)!!B!"J!'!!B!"J!'!!B!"J!'!!J!"J!'!!8""!%
+'!33!"!!'!!-!"3!&!!8!"3!&!!3!"3!&!!-!"!!&!!-!#!!&!!8!"3!&!!8!"3!
+%!!8!"J!)!!B!"J!&!!3!!J!%!!B!N!-'!3F!"J!&!!B!"J!'!!8!"3!&!!8!"3!
+&!!8!"3!&!!8!"3!$!!-!"!!%!!8!"3!&!!8!"3!&!!8!"3!&!!8!"!!&!!B!"J!
+'!!B!"J!'!!N!#3!*!33!"!!'!!N!"`%+!!B!"3!&!!B!"J!&!!B!"`-)!J8""3!
+&!!J"#3!'!3B"!`!&!!J""3!'!3F!#!!)!3J!"J!(!`F!"J!*!!J!"3!(!3F#"`%
+%!33!"J!)!!B!#Iq3+!!'!!B!"`#3"!XQN!!!N!6[!!m!!2rd!!m!$`5C!!`!!`!
+"!$i!N$Y`!6)!N!3'!*!@!93!N!8IJ1!!N!S1!$J!N!X&!*!k+)J#6**!!!!*!*!
+G&S#J!*!($RcJ#J!S!*!)m!!!"3!%!!!`!!!%!*!G"``!N"%(!!#)!*!$"#%!f3#
+))"N'L33$4))"!*!,!93!N!8@r+!!N!3-!!!+4+!+!#J!!!P+J!!$!I[!!!A46Rj
+K55!!"-6[`Ajhlc`!!2!!MjlcrhSB--)1,hchchq'$!Bar38!3)!#!`36$!#3"!)
+!N!3+Q4"alq,d+"+9CJ%%8UEE%)T9L%8VX!ai!mi!!(4D!(jk!!!4!-rrPX5RJ!!
+%J!L!!!TFS!S!+!!!%Nb!"%B"r#r`"GIeNT&)`!!*,4#$3)!``J!"#H#)BBS3KKJ
+a3ai`````L)B-"M%-KS!JJ!)%"!%%!*!%!J#3"!UQ%#)BB``J!*!0!8N5K!94(Ki
+Qi!#JK93!#J!N84EdU%!!N!-4!#!+8+!+!#J!!"+9!%!-!I`S%!@#P*5JKr)!#KB
+4"8%!8-)%%3S45'#'%))B-N+Y-----!L'$%94&)3!$[1HlRfh&XeRHIGh4M%BaqU
+!+&))8``ZFjcR1FjcT5XjcR1M'-9,N!#"k9%K)59!!+#-!)5I4")4&T5`,Z1NJ"%
+!)!T3TrS!+1i!N!-3T&rer#J3"Br-D%#%`J!5&"-*II"23dJ)&1P2S)B3JKJd3Nd
+`````#)8558S84!!4M'-8MP-R-jM'1)T'-4M%+S!S8JK6$$'-BaM'-BaP,-BaM'-
+Ba693HrP5A-bN3"%JP95)4%4a%ADAX$%84)!MXP!+8+3EJ1m4!*!$!44rrI`S%!@
+&"K#JK5qI%K3JN3-)N!$#%q3P+LKJKpkIq$K#$,$p$mm)K4+SLL4%!!q-)a5-8dB
+M'-B`JNBUT8453%5+$dX-,h[Hpm)aM'8SaM'-BaM%"6L(q9&5d)!"qIbN!r!r4*!
+!N8D@-#m8b2`K6&#Edlpiri-4!*!$IJarqI`S%!@!"5d8K!)!)K4!B3-)N!#q)!*
+&+LKJKK#''$4#$,$"$3#)K++T4%3N!"'-)r5-8iBM'-B`FN9+SN5+J%5+#%X--Ba
+M'-2rrq8SaM'-BaM%"4#(p9$Fd)!!)L$&9)K%44%4GTIS8I93KN%!L5M5#8["lar
+ri!!#$%2jr#J3"B!&8`L%!J!L&)"rJ`N3JK!%42IiB)B3KK`b3Ja``3b!L)5K%84
+%*!!4M#-%M&0')aM'-!T&4%9&#S$rrJK($$'-BaM#%)3P+-BaM'-Ba!83Hr23dXb
+!!%)JK!#%K%85%4D8#&%'8B9"-ST2mrP+IbN3!*!$%44'(r`S%!8!&C-85!!!358
+)J8-*%)3,k!)%'''+%)BF-8)-F-%X8)L%34)NK"3!%BaM&)a6*L-BaM#+6)4)aJU
+!J`BB4``aM'-BaM'-C5M'-BaR1F`&83AK85%K!!(m)B98!!4&*&%@R!54&&'!J8d
+&)!!"5J!T%3#3"+4)!I`S%!@!$ScL5!!J`-Ih!6ca$cP%%%(%(jlcm(SEd2i-,d$
+d,`Ki34)Nr"4rMr1Hj(a6&L-AHI"aY)4)[qU!J`A[`[22HplhZFjcT5LjcR1DeV3
+$[S3"GKiH!!#%2RJ$rq4kcp%@J!c1kik!J3(mN!!!!8S!+1i!N!4$`!(m,r!&!!3
+!!$!!)!#3#%!!N!i)!*!'"J`!N!8)!J#3!d!J!*!%"!F!N!0!!*!'%!#3#J%!H!#
+3#!&8!!"!!!!@J!#3"3%!N!3"5J!S!*!'3!!(i!!&!*!'3!#3#)!!N"b)!J#3!d!
+J!*!%4!#3"#!!N!BJ!*!CJ!!!&S!!N!8"!*!%!FS!+!#3"34!!*!%"3#3,(!-!*!
+*1!#3"%!!N"`"9!#3"4q!!*!&!J#3"3i!1!#3"31!!*!%"3#343%!"!!,!"!!&`!
+I!#!!)`!Q!#`!-3!c!$J!13!q!%3!4J"-!&)!@3"I!'8!D`"a!(F!H!"k!(i!J`#
+(!)d!P3#F!+)!U!#Z!,-!Z!#q!-3!a3$,!0%!eJ$G!1-!k3$[!28!q`'3!`J"$J%
+9!4i")`%S!5d",`%d!6B"13&"!8-"5!&0!9)"9`&F!@!"C3&U!@`"E`&d!AB"I`'
+%!BN"MJ'6!CJ"R3'K!DB"U`'d!EN"[J($!FB"a`(+!G!"d!(A!Gi"j!(T!Hm"p3(
+l!J!#"3)+!Jm#&!)C!Ki#)`)S!Ld#-J)d!MB#13)m!N%#4J*,!P!#93*D!Pm#C!*
+T!Qi#F3*e!RS#J!+'!S`#NJ+C!U%#U3+b!V3#Y`+p!XF#c`,@!YX#h`,M!ZJ#l`,
+d![S$!3-'!`N$$J-6!aX$*!-V!c!$-3-f!ci$330(!di$9!0C!ei$C30X!h%$H!0
+r!iJ$M!16!jJ$R31I!k%$TJ1Y!l)$[`1r!lm$[`1r!lm$[`1r!lm$[`1r!lm$[`1
+r!lm$[`1r!lm$[`1r!lm$a32,!p8!!2rr!*!)rj!'#!MrN!B!!2q3*!3%!3-""3%
+*!3F"#3!*!3-""3%&!3J""`%%!3F"!`%(!3J$#!%)!3J"#!%)!3J"#!%)!3J"!`%
+%!3B""`%'!3J"#J%*!3J"#!%)!3F""`%)!3J#"3!(!3J""`%*!3J"#!%)!3J"#!%
+)!!J"#!%*!3X""`%(!3F""!%(!33""!!)!33""`%(!3F""`%(!3B""`%(!38""J%
+(!38"#`%(!3F""`%(!3B""`%'!3F""`%,!3F""`%(!38"!`%&!3J!!!%*!3N"#!%
+(!3J"#!%)!3F""`%(!3F""`%(!3F""`%(!3F""`)&!38""3%&!3F""`%(!3F""`%
+(!3F""`%(!3F""3%'!3F"#!%)!3J"#!%*!3S"#J%,!33""3%)!3`!#!!,!3F""J%
+'!3F"#3%(!3J"#3)+!38!"J!'!3S"#`!(!3J#"!%(!3S""3%)!3N"#!%)!JS!#!%
+*!JN"#!--!3X""J%*!3F""`%%!33""`%*!3J"$rq3+!)*!JN!#VEE!*!$4!#3#3J
+!$!"k!%%!HJ!-!!J!N"-)!!`!IJ"r!(i!$!!)!*!,"`!*!*!$4!#3%J(!!8!"3!G
+`!L!"3!#!!*!5!F!"`!(!"r!$i!(!!)!!#3!)!*!$4!#3#K!!-!"H!))!AJ!`!"!
+!N"-3!$!!IJ$q!(i!-!!3!*!+#!!'!*!$4!#3&4!!+3!A!!N!#3!I!*!9%!!j!"m
+!$`!2!"m!#`!,!*!$4!#3&!J!P!$S!*!!!*!!!2J!N"8)!*`!q!$`!2!!q!!!#`!
+%!*!$42J!N!!!N!!!k!#8!!J!N"Ai!2!!m!$i!*`!#!#3&J3!"!#3!d3!N!32m!J
+3#"!)%!J3#"!)%!J3#"!)%!r`!*!)$r!Iq"L3%Kri$r!!N!8(!!F!N!0%!3!#J!4
+!$Z!#J!+!!i!!N")"!!1!"m!2i!1!!i!$J!#3%`B!"`#3!d3!(`!*!!N!&`!T!"!
+!N"8I!!m!$`!I!$N!%!#3&33!#`#3!b!!-!!3!8)"l3!%!*!)#d4eEQGPEfiJ6@&
+`+!S!N!-f0DP6G'PMD(4TEQFJ6@&dD'9YBA4TFf0S)%0PER4bG@dX)%&YFh4PFQ4
+KE5`J-6Ni0G!a1C!$!*!$J!$rN!6`!*!$m!#3!rm!N!2`!*!$r2!!!2!!N!2rr`!
+!m!#3"!m!!2!!N!32!!$`!2rr!!m!!2!2!3(`$`!!m2!Im"m2!!$`mI%2N!-!!2#
+3!amI$`!!m2%2rr!2!!$`$a#3!`m!!2!!rrr`$`!!m!#3"!m!!2q3"J#3")!!rj!
+%m!#3!r!!N!2r!*!$m!#3!rc`!!$`!*!$rrm!!2!!N!32!!$`!2rr!!m!!2!2%"$
+`$`!!m2(a$j!$!!$`N!-I(`m!!2$a!3%2$`!!m!m3%2!2!!$`$`ram!m!!2!2%"$
+`$`!!m!$rr`!2!!$`!*!%$`!!rj!'!*!%3$rJ)$!J+#!m)!3J"#2%*#3TP#T8+P3
+Tj#3%)q3J"$rm2q!rm$ri2r`rr$rm2r`rr$rm2r`rr$rm2r`rr$rm2r`!N!0!2q!
+J-#!S)$`J"#2%*#3U9#T8+"3N*#@N*#3Ma#!%2r`ri$r`2rJrr$rm2r`rr$rm2r`
+rr$rm2r`rr$rm2r`rr!!!!3!2rr`!#!!'!!J1"3!*N35!#FL%3!MS4#!)H%I`#6p
+!%!VmJ"!+(J!3#KF!%!N6J"!)LF!3#($J%!J!F"!)!$J3#!!B%!J!!"!)!!!3#!!
+!%!J$`"!)"#!3#!Q3!"!)#P!3#!T3%!J*i"!)"!!3#!2J%!J!!"!)!!!3#!!!%!r
+rrr!2rr`!$rrq!!rrr`!2rrq!$rrr`!rrrq!2rrr`$rrrm!rrrr!2rrr`$rrrm!r
+rrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!r
+rrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!!!!3!2rr`!#!!'!!J
+1"3!*N35!#FL%3!MS4#!)H%I`#6p!%!VmJ"!+(J!3#KF!%!N6J"!)LF!3#($J%!J
+!F"!)!$J3#!!B%!L(`K!*@$83#@!0%!SXD*!!#Y+@N!!*8T83#%aN%!NJ#4!+d"D
+3!!SAd*!!#5JT%!P)*4!)amB3#!!!%!rrrr!2rr`!$rrq!!rrr`!2rrq!$rrr`!r
+rrq!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!r
+rrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!r
+rrr!2rrr`$rrrm!!!!J#3!rq3#3#3"r!!N!F2m!#3"[!!N!2rm!!!$mm!N!E`$r!
+2%"m!!!r-m!#3"I!2[`$a!I!!$mc2!*!&m!$lm2!3(`!2c-c`!*!%m!!2[r%"$`!
+2rj!$!*!%m!m!qrrr(`#3"!m!N!6`m2rr[`$`!*!%$`#3"2$a!3rlm!#3"3m!N!6
+`m"!I$lm!N!82!*!%m!m"$`$lm!#3"!m!N!6`!2!3m!qr!*!%$`#3"2!!$rm!!2[
+`!*!$$`#3"2!!N!82[`#3!`m!N!6`!*!'qr!!!!m!N!6`!*!'$r!!!!m!N!6`!*!
++$`#3"2!!N!S2!*!%m!#3#Jm!N!6`!*!%rrm!N!32!*!%m!#3!`m"!I!!N!-2!*!
+%m!#3!r!Im"m!N!-2!*!%m!#3!r(a$`m!N!-2!*!%m!#3!r$`(am!N!-2!*!%m!#
+3!r%2rr!!N!-2!*!%m!#3!`m3N!-!N!-2!*!%m!#3"2rrm!#3!`m!N!6`!*!+$`#
+3"2!!N!S2!*!%m!#3#Jm!N!6rN!`!N!3#!*!$rj!*!*!(m!#3"`r`!*!'m!#3!rr
+`!!!2c`#3"[!2m!m3(`!!$mc`!*!&m!qr!2%"m!!2c-m!N!A`!2[`m"!I!!r-c2!
+!N!6`!!qrm3%2!!rrN!-!N!6`$`$lrrmI!*!%$`#3"2$`rrqr!2!!N!32!*!%m2%
+"$r[`!*!&$`#3"2$`%"m2[`#3"3m!N!6`$`%2!2[`!*!%$`#3"2!!m"$`$lm!N!3
+2!*!%m!!2r`!!qr!!N!-2!*!%m!#3"3qr!*!$$`#3"2!!N!Elm!!!$`#3"2!!N!B
+2m!!!$`#3"2!!m!!2rrm!!2!!$`#3"2!2(`r`%"$r$am!$`#3"2!2$r%"N!6r$`!
+2!*!%m2!3m2m3(r$`%2!2!*!%m2(r$mcar-m2mI!2!*!%m!m2(mc`r-mI$`!2!*!
+%m!!2!Im"$r%2!!!2!*!%m!m!m"#3"2!2!!m!N!6`mIm2!C!$$`ram!m!N!6`m"!
+I(rrr(a!3m!m!N!6`$`(`m3%"m2%2!!m!N!6`$am!m"!3m!mI!!m!N!6`!2m!$rr
+r!!r`!!m!N!6`!*!+$`#3"2q3$!#3"3G"8&"-!*!'"e"548B!!3#3"!G%394"!!)
+!N!3(8d&@43!$!*!%"d*26N8!"!#3"$aZD$-a!*!$!8C548B!"!#3!i!!!3#"!!)
+!JJ!$!)-!"!#%5801)`!%!!!$k!!"!qN!!J2U!!-$k`!%!q`!N!-1!$i!6J#k!E)
+6L3!%-!S!N!1&!)%!N!Mrrre2"%CTE'8+8Q9NFQ&h)%eKF!"5%3!-8(*PGQP[GA-
+J6A0R!&!4!!T5CA"[FfPdD@pZ!%i!!!%Y!*!%"e*PCh9XBA)!'mJ!$89ZG'9b)%9
+iF'a[FQ8!!&J!!5d!N!3%8f&fC3"68`!",3#3"!44G@Pd!&&4!*!&5!##!*!)rj!
+$q`4&C'Pd"&9ZC'm!@J!!!5d!N!3$3h9d!&J!!!4$Eh"j!%-!!!93BA0dC3"@!!!
+&3faPBA)!N!LX!)-!N!Mrrrhr!dYLC!a$EfjdFQpX)%YPHA-!'mN!#e"eEQ0dG@&
+dD@pZ!"[+!!K#FQ&MDf9dF`!Eb`!&B5!Y)'d!'m`!"@iJ,5"k!"[0!!9")#dJ63!
+EcJ!&6L!Y)&S!'mm!"6!J,5!j!"[3!!%Y!*!%##KPFf0KF'8T!*!%"bKcF'&MC5N
+!N!3)+'4PE'9dC5N!N!3)+(*PG(9bELN!N!Kc!)3!N!MrN!2E"%KPE(!(6h"dD@p
+ZF`!!6`!",3#3"!4)C@a`!!!r!!a%CA0MFQPLC5",CAN!!#B!!5d!N!3(9Q9bFfP
+[EJ!!GJ!(5'PcG'pbH3!!9J!39Q9bFfP[EL"'C@&dGA*PF`!!)`#3"5S!J!#3#2q
+3!rX"&!j"BQpeG#"1CA4)B@0Vb3#3"!%Y!*!)aJ#&!*!)rrrpl`4*EQC[$8PZGQ9
+ZG'pbH5""E'`!!'N!%%PZGQ9ZG'pbH5"6C@aPBh3!!%N!"N&NDR9cG!!!)`!",3#
+3"!P-EfpV)%4[Gfi!!$S!$%4PFf0bD@*P)%pZC3!!1`!04'9cBh*TBQ8J6@&ZH3!
+!,`!04'9cBh*TBQ8J9(*KF!!!AJ!",3#3"!a$B@aX)%e[ER0dCA)!!%-!#djKE@8
+J6f*UC@0d!!!M!!Y%DA0MEhCPFQPPF`!!A!#3"EN!L!#3#2rrqpm&6@&RD@-*4(*
+[F#"*G'9Y!!"N!!Y%FQp`)&0PE'9MG!!!4!!'8'PMDh9`!!!X!!e8EfGRE'8JF'P
+MDh9`!!"!!!%Y!*!%!d9KG!!!C3!%8Q9KC!!!FJ!&8A9KCQB!!(%!!d4TF!!!)`!
+",3#3"!Y-DA0d)&0`C@aXF`!!+`!+3f&cG#"6F'9XE!!!@J!$@Q&`!!"k!!C*ERC
+[Df8!!#-!!e*eBJ!!)`#3"EF!L3#3#2rrZlm%3QPdF`C6C@&bBfJ!!(-!#N0XEh0
+P)%4[Eh)!!'-!#8p`C@iJ4'p[FJ!!E`!&3A"`E(N!!'%!"%YTBfX!4"%!!5d!N!3
+'9@jdFQ&`!!!M!!9'Eh*MC3!!)`!%6'p[G!!!)`!",3#3"!G&EQGbBACP!!"&!!0
+%DA!!!#-!!e0TG!!!)`!",3!!)`))3faTEA!J9A!!!$`!#N0XD@eL)%4[Gfi!!$i
+!N!@,!-S!N!MrN!3,F(9ZBh4eBA4TEfi#)#i!N!3#)#`!N!3#)$X!N!3#)$S!N!3
+#)#%!N!3#)$m!N!3#)#X!N!3#)#d!N!3#)$d!N!3#)#-!N!3#)#3!N!3#)%!!N!3
+#)#B!N!3#)#S!N!3#)(i!N!3#)&m!N!Ki!-X!N!MrN!3)BR*KBfYPG(-"@`#3"!&
+G!*!%!5J!N!3"+3#3"!&l!*!%!Ad!N!3"2!#3"!%q!*!%!9i!N!3"B!#3"!%R!*!
+%!5)!N!3"A!#3"!%[!*!%!A`!N!3"*3#3#'-!c!#3#2q3"!9K)#dJE3&K!*!%!@)
+!N!3"B`#3"!&N!*!%!@8!N!3"CJ#3"!&R!*!%!@J!N!3"D3#3"!&U!*!%!@X!N!3
+"E!#3"!&Y!*!)B`$0!*!)rj!%"@iJ,5"k!@i!N!3"E`#3"!&`!*!%!A%!N!3"FJ#
+3"!&c!*!%!A3!N!3"G3#3"!&f!*!%!AF!N!3"H!#3"!&j!*!%!AS!N!KM!-i!N!M
+rN!3&35!Y)%d"33#3"!&#!*!%!8-!N!3"4!#3"!&&!*!%!8B!N!3"4`#3"!&)!*!
+%!8N!N!3"5J#3"!&,!*!%!8`!N!3"63#3#'-!c`#3#2q3"!91)#dJ@J&1!*!%!8m
+!N!3"8!#3"!&4!*!%!9)!N!3"8`#3"!&8!*!%!98!N!3"9J#3"!&A!*!%!9J!N!3
+"@3#3"!&D!*!)DJ$*!*!)rrrpr`aMEfjdFQpX)'YPHA-"BJ!a!!!"DJ!b!!!"EJ!
+c!!!"D!!d!!!"E!!f!!!"H3!h!!!"D`!i!!!"G3!j!!!",3#3"!&N!%3!!!&`!&!
+!!!&b!&)!!!&d!&3!N!C4!0!!N!MrN!3&-#!Y)$N"-!#3"!%a!*!%!6)!N!3"-`#
+3"!%d!*!%!68!N!3"0J#3"!%h!*!%!6J!N!3"13#3#*%!b!#3#2q3"!ChDATKFQ3
++3A4dFQPLGA4PF`!!H!!04'9dC@0d)&9ZFf9PEJ!!C3!*4Qa[Eh)J6@&`!!"Q!""
+(C@jPFQ&dC5"0EfjcG'9b!!"R!!K*C'9ZG'PQH3!!D3!*6'pMBA4TEfjc!!"[!!j
+-CACPE#"8C@aPF'pbG!!!GJ!%9fPcD!!!G`#3"9m!d3#3#2q3"!GMGA*bC@jd"PG
+PBA"[EJ!!+3!&3A*YEh)!!&X!"9*TEQGc!!!p!!C"EA9XCA3!!#)!"94[Efac!!!
+S!!4(EfaN!!!N!!C6F'9XE(-!!#X!N!8X!)!!#J#!!*!$J3#3!i)!N!1$!*!$K!#
+3!i8!N!1'!*!$K`#3!iJ!N!1*!*!&,!$)!!S!b!#3!mN!N!2+!*!$b`#3!m`!N!2
+0!*!$cJ#3!mm!N!23!*!$d3#3"C!!!!d4T6)`-5"$EfjdFQpX)%YPHA-3T6)`-L"
+3G@jMG(9KG'P[EJfP-M!c)%*bB@0VCA4c#U8b-$3JB5!Y)'d+T6)`05"Z)#dJHJU
+P-M!f)%%J,5"0#U8b-$FJ6L!Y)&S+T6)`1#!`)#dJ13+P,3JET@9cBf&`C3FJTA0
+`B@0P#!LPC'9XCA4P#!fPFQ9dGA*Z!*!$C3!0"`+PBh4X,@)(#U9MG'`YDJF1T@0
+dE#eZ"`LPBh4X,@J($+9MG'`YE!FCT@0dE#ej"`ZPBh4X,@X(&D9MG'`YG3+P,3F
+%T@0dE#eN"a#PBh4X,A!(%U9MG'`YFJF8T@0dE#ed!*!$)J!3!5i",!%l!6S")3%
+r!5X",3%p!5-"*!&!!5B"+J&q!9m!N!-L!"!"@`&G!5J"+3&l!Ad"2!%q!9i"B!%
+R!5)"A!%[!A`"*3#3!a`!$3&K!@)"B`&N!@8"CJ&R!@J"D3&U!@X"E!&Y!*!$(!!
+0!@i"E`&`!A%"FJ&c!A3"G3&f!AF"H!&j!AS!N!-F!!d"33&#!8-"4!&&!8B"4`&
+)!8N"5J&,!8`"63#3!a`!$3&1!8m"8!&4!9)"8`&8!98"9J&A!9J"@3&D!*!$&J!
++!6!"-3%b!6-"0!%e!6B"0`%i!6N!N!0#!!J('+9MG'`YH!F&T@0dE#eP"`DPBh4
+X,@B("k9MG'`YC`F*T@0dE#eT"`qPBh4X,@m(&U9MG'`YGJFAT@0dE#eh!*!$%!!
+(!5N"@`%p!5)"+!%N!5X!N!0,#c&cG#"YC@je)%P%4&G54!SM)'pQ)%e&6P9c6d0
+19!8UN!9-8e4$"P*PFb"*4%4A8N3)8Q9cCA*fC@4'9e*%"5U3"8a69%8!N!-E!!J
+"6`+P,3%r!5B#T5d"GJ&@##0fCA*cD@pZ!*!$*J!-!@N"53FMB@4UGA0d!U8Y!6S
+"1`%[!9i#T5d"3`8MEQ&YC3&F!*!$0!!#!*!&C`%%!(X"9!3#6dX!N!8,!&%!@!&
+JL!4H-&ia!*!&#J!B!#S!1+!#!!%!N!0%!!-!N!9G!3i!F3&+"!*1E`#3"9d!A3"
+a!*N%!ePPF`#3"JS!6`"3!91)!Pi`!*!&#J!@!#S!0U!#!*!&$J"%!%3!XJ(9!)"
+%4$!+!*!$$J"+!'S!d`(A%iJ!"$!+!*!$3!!3!A-"B`&[!@%("+9MG'`YC!+P,3F
+MG@jdFQ&`"L0QEh*MC38ME'p[G!+P,3&&"#0NDA!%)h0TG!+P,3%m!6i!N!-8%dj
+PG%KKBfXJ8(*PCQ9bC@jMCA-!N!06!!m",J+P,3J8T5"MG'`YG!8MDR9YF!JME@p
+ZFh4PFJ8MGfP`C3+P,3&K!A!("+9MG'`YC!8MBfKKG!BMEfCQCA)&)h"bBAN&)h*
+TC'8&)h4eFQi!N!1F!)F!N!MrN!0l!d&MG!4AB@Pd!!!Z!!%Y!*!%#&4PE'9`Eh*
+d!&34!!4+G@e`!!!M!!G0EfjcG'9b!!!M!!4ADA"P!!!M!!%Y!*!%"8&`F'aj!!"
+K!!03BAN!!(!!"%YTBfX!4"%!"%0SBA3!!#-!"8pQCQ9b!!!M!!43FQ&j!!!M!!4
+5D@4P!!!M!!48GA*Z!!!M!*!&,J!2!@3"4!%X!8!#T5d"C3&b!A%%)f4TF!+P,3%
+V!9S"HJFMD@jfEfYP"#0bG@)!N!0#!"%-T6)`15"$GA*bC@jd!U8Y!AF"H!&4!@B
+"G!&K##0PEQKKEQ0P#L0dGfphC@&`Efi#T5d"9`&8!8%#T5d"8!&5!*!$m3#'!*!
+)rrphq`9&FA9TF!G$GA*bC@jd!"[4!!%Y!*!%$&GTC@aN)&GPBA"[EJ!!G`!24AK
+MD'&ZCf8J9f9KF'pZ!!"i!!e6C@aPBh3J8A9TGQ9b!!"4!!Y'DA*P)&&eDACPFJ!
+!CJ!&9'KbEhF!!(3!"8&`F'aj!!"K!!G&EQKKEQ0P!!!M!"&8GfmJ9f9KF'pZ)%0
+[E@*KG!!!)`!",3#3"!TAC@&b)%&bE@pb!!"A!!K8B@YP)%pQCJ!!9!!+3A0V)&*
+PE@pfC3!!33!",3#3"!C3GA3J6fi!!&!!"P*PE@pfC3!!8J#3"6!!N!F%!!$GN!B
+!!3#3"`)!N!F$!*!("2q3"J#3!bS!3J!Z!1)"XJ!&!3#3"aG`%P0PE'9MG#"K)%0
+SBA*KBh4PFMB`#J#3!e3!N#!J!!"!!*!Srj!'!*!%!5i!%!#3"5J"%J!m!@)%"&"
+XBAN!N!91!4)!BJ&L"!44G@Pd!*!&*!%1!%!"CS!!N!C3!%J!B3"k!*!(8!#k!'%
+!lJ#3"hJ!5!#*!(S!N!Gi!,`!L3$Z!*!(H!%q!)N"B3#3"bN!5J!j!2!3"%jKE@8
+!N!8B!"3!1!!dS!)!!3#3"9!!*!"J!%L)"9*[E'8k!*!'8!#@!'!!ZSJ&8Q&MC6T
+P!*!&H!!8!)J!5)J(4f9ZC'9b1J#3"RJ!PJ#)!,b)"N&XD@GZ1J#3"AJ"%J#)!6k
+)"8e[C'8kD!#3"4-!5!!N!2+)$&GSEb"KFQ8JH@pe2`#3$!%%!!%AF!#3!c!!N!F
+%!!$GN!B!!3#3"`)!N!F$!*!("2q3"J#3!c!!N!F%!!$GN!B!!3#3"`)!N!F$!*!
+("2q3"J#3!c!!N!F%!!$GN!B!!3#3"`)!N!F$!*!("2q3"J#3!c!!N!F%!!$GN!B
+!!3#3"`)!N!F$!*!("2q3"J!!#-i!!3#3!a`!N!01!*!%rrm!N"#!)!#3"8!!3!#
+3#8J!N!0)!*!&"!!"!!3!N!B)6J#3"#)c-L+3"5-L%4)L)MYiXL+3"K)M-bY$1l-
+LN!-c-L+3"5-L)K)5[(h$)T!')5)M-b9$)eXb)L)c)T!*)eHA8b+3#50$1d-bZd)
+L)L3b)T!$-L)M0,CpRFXL)b)L)b+3"M1l3c)PBb)L)l-cZfc'E(ICU[fb)e-M-b+
+3#E4$-b1mXd0,HCQCUT!$rkUBa6-L*M-c)T!()b1d3c-b*'amb0aP9EZlE'9EY&D
+c-L46-c)K)c)5)lY8+l4$-M-b*FCXZd-L)K&,4%ZdYV-c-eXc-L)MZj!$3V3VY$1
+3"E-L@d-b)L'lN!0%4E3c4,8c)LYPXb+3!bXl4$0%-dZl-c1l-c-L)9ZlY%3cY%4
+%1l-MCM)LN!3N*83d0%5l3c-b46-c)L*8Zl4%3lY%4$0EA&-b)T!&*84$0%5d-c)
+L*6-c-L0EZl4%3cY%5c*FDc-LN!BQZd0$Y%3c-L)V3c-L+l5lZdXc+d4%-V@d-L+
+3"%)L0E4%-c4$-c)L)d3c)L@dZd4%3cY$0$)f4$)LN!3b)PY$-c3cN!3L)N-b)LC
+,Zd4%-b3d4$)QY$)LN!4#)V4$-c3l-j!$)L)c-L+eZlZd4$-MY8-b*N-b)T!%3b+
+l4$0$-j!$0$)L)M)LDlZlY%3c+eDd-MBc-b+3"$3LY%-c0$13"$)L)M-PDlZd4%-
+c1eCPXN8c-b+3!a%V)N3cN!BM)T!$-caEZl4$-c0,9E99Zc-b)T!$%4Xb0$13!c)
+M-b)L)5)b9EZ3!c-L1l9EZl[--b+3""%E3c3c-c)L)c)LN!3c@lZ3!d-M5e9EZl4
+ADc)LN!-4%e-l-b-b)M)b)T!$)$C9@lZlXcZe@lZlY,aQY$)L)K%5`c3b-c)L-M)
+LN!-Vc&@lZl3c4E9EZlY$YV[&Y#)K%4,,*$-M-L-LN!3V8la9ZlZc0&YEZj!$-f@
+e9QGfZlYSfc4$)M)LN!3VC6-m9EZdY,@lN!5d3f@lZeA-amc-M$3c)T!&1maE3c9
+VZlY9DlZ3!l4$1f@l4,Z3"$0V4$)L)L-L)XaV4$-cbe9QCEZ3!d4%-c9EXc-d4$1
+3!eZlN!1e9V9F@l-c-b*P9P@lN!0%3d-c0VY$-j!&0'Xc-l0&E-c'3c-c)L+m9PZ
+lZl4$0$-c0VY%-j!&ZlXb-cAF@lY%3c-b)L%X99Y%4%-cN!3fY$13"#)NY$1c)he
+EZl4%3b-L)c*'9E3cN!3b)c1fXc13"#)VXc06@0@l4*!$-L)L098d@l-b)T!%)c+
+l3c13!c)L+d-bE0GEZlY%-c-L)VZlXeZc)T!'-VXd4$-c-L)NXc*&@lY%4$-c)L+
+l-c0#Zl3LN!BbZd-cN!-b)L08-d5d4%-c-b-L+d-L)M0&Y$)cN!-L-c0E3c13!c)
+L)QZl-l-c3c-b)L*$-L)L-c5l3c-c-L)M-fXc-c4%-L%Pbc)N8c1d-b)L1l-b)L)
+c-l4$-cZdY%4EZj!$99Xb*'@c)M1c0&@c)L-l-c-b)MZlN!1d3c-b)VY%Zl-cYEY
+Q4$)L-N)VaV-K%83L)c-b0%4%3c)dY$-L@d53!c5l9V)N3b)c0$5e-L%5Xc13!c)
+VZl5d-dY$-L+l-c0%-c5l-L+d-c-N4,Zd-L)b)c0%-LZlY%-cN!-M)VXcN!BL)MY
+$-c1lZc3c5c)M-c-b+d3c-c)L-b)L5c-M-j!%)L)MYEZ3!c-L-cXb)c0$-L4%0$)
+L)b+3!cXb)c-c-L)M)T!$)c13!c)L*E-cN!-b*%Xc-L-c)T!$06-M-j!$)L)b)L)
+c-b-c3b*#1c13!c)N5d-cN!-LN!-Q3b-cN!-LN!8M-L)L-c3L)d-c-c)MZd-cN!-
+b)L)QXc-d-c-L-c)L)M)b)L)M3L)L)d3c-b1l-j!&)L)PY$13!d-LN!NM-L+3!c@
+c-cZd-j!&-M)PY$13"#+3"6-b)T!&-b)lY8)eZd3cN!3L)LZc-j!%)T!+)b-c)L-
+d99@l4,-c3c-L)LYL-j!%)T!$-L+3"M-M-c)L-c)L-j!$3d-c)L)MBc-L)M-LN!J
+l@d-cN!-L-L+3!b-lY$-c)L)MDc)cY@Xb)T!'+eZl@c0$3c-LN!-c-N1d-c1c)L+
+mZl9EY$)L)M)LN!-VZl3c0#-c3c0%-b)N-N4$-c5l3dI'@d4%-c-L)L-L)MZlY$)
+LN!8M-L1c-d4$-b)L1l@d1c-c0%-b-c-b)VZ3!c-LN!BVZl)b-c-b)T!$5l-N3c-
+dZd1lZl4$@lZl-b)L-j!&YN)L)c)LN!3M-L+dYEZlY9Zl4,9EY%Y$)L-c-b)L)cX
+b)T!*)f@d-d4,3c13!l0$0%)L)c-LN!-b)l)LN!-K)T!&Zd-b)M-c-M3c4%-c0E)
+L)L-LN!-K%V)LN!F4*&3c)K)K)L)l4$1c-d8b)T!%)5)L)E3LN!BK%5Bd-L+3"6Z
+l3d-d9$)LN!FK+c)LN!-M)L%4YM-LN!3K)NZl3dZl3c)LN!-M)L)5)4-b%4)L)b)
+K%FXLN!84)N5lY,Zc-b)K%M)LN!853b%4)M)L)5Yc)T!(-d3lZlXc)L)!N!F1!!$
+ZN!B!!Gf3"J!#c*!'!!1lN!B!"+U3"J!&L*!'!!ChN!B!"e@3"J!)4*!'!!NLN!B
+!#K'3"J!,QC!'!!aQN!B!$613"J!2!*!*3J$`!*N!N#m"!!%!#3!!6)N!$!!!6)`
+!!!Q)N!!!N!6q!!B!!2rh!!B!#`1l!!N!!J#3!cm!N!H!!*!("!#3%#!!N"!"!!E
+!!*!'SJJ!N!3"5J!!!B!!!0!!!"$#!#YDa%S!ri2P%))"!"*AKm(Jq)8!"8!&##2
+`2r`!IJ#3!acJ#!#3"5!!!!jJ!!!3!*!&J!#3"`i!N"!J!*!3!i!#K%!3`#!)&!8
+3!#!34!!!!`!##4#EB!!!%83!&!r%5J#ZqU83JJ%!%P@pIlqSK3!&3!8))r!rr!0
+#!*!$#4!8!,R!!!3J!`!*N!!!e6RX6#!!!6PcKIGpcJ!"a(HGlrh4iB`M&hRHGq-
+BaMr3d"!J!)$"#BB!N!33!*!$"8ehb+8*)&+&DZGm$e+)SLR4"+2L%L%Y&f)!%NN
+!+eV%5J$Glf83JJ%!%PEZkh[BK3!&3!8))r!rr!6!$i!0R4F3!8IJ%KSJ")!*)2(
+IeV+5U3!"4ia0#!Ba"")ZM'-B3M&"P$HBaM'*)aLU)C!!D!JJ!)%"!))!N!33!*!
+$"9D2`!!!`!!!!4M!&!#3!`)a*"85!!!"QC!!!"93!"32a%S!VYDP%))"!"*9hAH
+eU)8!"8!&##2`2r`)`!5!!QXBL!p(rj%U*!bi18#4K9,8)A%!!Nd)9Hm'-D[S2ia
+K'%)43D3V@-BaJ5-BNL+)3!2mjlZIkC2V1mqcrM'XBr9!JTch[HjcR*-B`G4cR4M
+'-AFr&cjdE9Q5!!UV!#YDamS2hHpPm))"!"2@lZYlhq9q"Ai&IL2`2rhC3I)r)L[
+iZh,(i(c))(0m+Ik9MlP))Dr2`P84T"L*d4!%9IqK(hTr3F3M12SqF5-BN85)3!4
+M'-8M'D0FaM(-%M'USLNJJU-BaM'-BT2rqVk-BaM'-D`*iND-FcGNIr$,6*32r([
+aVYDr(rq3!rjGhAHeU"q"rmRrLIq3!riT3+&&)LXBaV,(rj%S2iKm3!k9K4@e)5%
+!"'8JIKL5,`[SPBaK'%)a8D3M'-)a#5-DN!#)K%!%B`Mp)aRM@-BaJj)aU5*&3)1
+r'-B`rrk6'-2dM'-BaM'N2b*'M'-3#%!K$j*V@XI+Aph[B2%!#3!6eZlVHprJIP"
+r4Ai6rrm#+-#L45)G'-Gdaq!5'#"`Id!1P3"@XK)"!!4&4%8BNL%%%!k-BaK#-9'
+8)aM#-BNLVDL3!)4!"1-)`5-CNeM'-B"5DUULK8#*)6R1F)3JNaM#P)aM1FBaV%P
+b6ScM(rM!)J159!r%5P'ZeU!"!!N!%PAGGl@S!!K3#88)%rrr!LM!T-8L#49%&-I
+rJ!JNJ$L!!*'!1Nd-!"!S1IZ%ja(1S!#+Mjh[`G(ZMq-A3G&a(%M%Rm,(ihch[4m
+CLeLlciH0T&4Ip8"a(YDeVh[HNaMqph1FeVh1GiNL0R0M%!F!!i0-UeV%5P(Glf!
+"!!N!%PEZkh[B!!K3#88)%rrr!GY!VlR5(1fi$dIJIrNJ!!#!!2%!%!#3!a!)!*!
+')!!+!*!+)!#3"3)!N!8#!3!!!J%!N!3#!i!6J!!!"!#3#33!)!!b!*!*&!r%5P(
+rrm!"!!N!%P2rN!2i!!K3#88)%rrr!!J!!!%!N!3)Iq!!#5!!N!SJ%!#3"N!!'`#
+3%!%!N!8F"J!!!J%!N!3F!3!J!*!$#!#3#6J!N!--!*!*!9V%5P%!N!-"!!N!%P!
+!N!8)8!P&#"2rr`#3"!%!N!33!*!$#-!!N%S"!!3!#3!1!"-!'!!D!"d!)!!P!#S
+!,!!b!$-!13!q!%!!43"+!%m!9!"C!&i!B`"S!'N!D`"Z!(-!GJ"l!)!!K3#+!)m
+!P!#C!*i!S`#S!+X!X!#e!,S![`$%!-N!cJ$6!0J!h3$L!1F!l!$a!2B!q`%!!3)
+"#!%+!3d"%`%9!4S"(`%N!5N",J%b!6F"2!%p!8!"43&(!8`"83&@!9X"B!&P!@S
+"EJ&c!AJ"I3'#!BF"M!'2!C!!!C-"Q!'B!Cd"SJ'R!D`"X3'f!EX"`!(&!FS"c`(
+5!G8"e`(F!H%"jJ(V!I!"p3(k!Im#"!)*!Ji#%`)B!Kd#)J)R!L`#-3)f!MJ#23*
+#!NF#6!*3!P3#@3*H!Q-#D3*[!R!#G3*k!Rm#K!+*!SS#MJ+5!TF#R!+J!U8#U3+
+Z!V-#Z!+m!X!#``,*!Xm#dJ,B!Yi#i3,P!ZN#l3,b![F#q`-!!`8$#`-4!aF$(3-
+K!b3$*`-V!c%$0`-l!ci$4!0+!dd$8!0@!e`$B30R!f`$F30h!h`$JJ1(!i`$N31
+@!jX$S31Q!kX$X31f!lN$[!1r!m-$b!20!p%$eJ2A!p`$i!2N!qF$l3!'!!B!"J!
+'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!
+'!!B!"J!'!!D3!`)'!3B!"J!'!!B!"J)'!3B#"J!'!!B""J!'!JB!"J!'!JB!"J!
+'!!B!"J!'!!B!"J!'!JB""J%'!!B""J!'!!B!"J!'!!B!"J!'!!B!"J!'!3B!"J!
+'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!JB!"J)'!3B!"J%'!!B!"J!
+'!!B!"J%'!!B!"J)'!!B!"J%'!!B!"J!'!!B!"J!'!!B""J!'!!B!"J!'!!B!"J)
+'!JB""J!'!*!$"J!'!!B!"J!'!!B!"J!'!!B!"J!'!3B""J%'!!B!"J!'!!B!"J!
+'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B#"J!'!!B!"J!'!3B""J!'!!B!"J!
+'!!B$"J!'!!B!"J!'!!B$"J!'!!B!"J!'!!B!"J%'!!B!"J!'!!B!"J-'!!B!"J-
+'!!B!"J-'!JB""J%'!!B!"J%'!!B!"J!'!!B!"J!'!JB$"J-'!JB!"J!'!!B$"J!
+'!!B!"J-'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B""J%
+'!`B!"J!'!!B""J!'!JB!"J!'!!B""J!'rrm!!![mN!!!N!6r!!F!!2rp!!F!$`6
+d!!`!!`#3!d-!N$0!!*!)!F!!N!`d!*!&!UUeBL8!Ir!r+)3)!3!%46i2`2JIL#J
+!"5!!8%#(m"rr`!#3#!Fi!!!%!*!'!`#3"b!!N!K!!*!2!3#3%N!!N!JU)J#3"9+
+!!!"J!!"B!!!""!!"8"rL*3"A[l8SK!J"!!4&+[VrVr@)+!!&)!"33)I`(rr!!*!
+)#2`!!!3!!!&-!!!$!"!!$!#3!b!!N!MJ!*!2$`1!!*!3i!#3"$!!N!-#*!#3#B!
+!N!8""!!#UV9L*3"V@ZXSK!J"!!4&0leVhAU)+!!&)!"33)I`(rr!!*!%!F!!`!M
+m!!!%!!!"XJ!!!p8j,&)J!!"1A1&mhh1!!"a(HGlrh4iB`M&hRHGq-BaMq)#3!!3
+)!#!`3Q!!N!J"8e`"%!4)#!3&1Gm$f!34!(4!D2L#4#E&lL!"&&!"8"rL*3"A[A8
+SK!J"!!4&+eVeVV@)+!!&)!"33)I`(rr!Gm(`!!#1F3!)r!!%"!"J"b32J!2IeV*
+5U!!!8H-633'-3))Lk-BaK#-8'80aM'-BNM'-BKL!U!))!#"!3Q'!!*!$"!#3!`&
+9SU)T3NJ8SPV'-!8NSLL+M%#&4)5)5dBa)!%NN!!#UV9L*3"V@ZXSK!J"!!4&0le
+VhAU)+!!&)!"33)I`(rr!LN%3!0b4L3!Sr!#*K!#3!!8Tk)!$e9,5BA%!!*&#&8)
+"M%%"!rM'-B3K&"T#ZBaM'")aM')B3-3!#!!J3%!JJ!#3!`3!N!-"8#)!N!-`!*!
+$4M!&!*!%M%L2a)!!!'Ba!!""!!&3(q)P!&HpG5L%#!%!"%8V@[@ZYBJS!!8J!&"
+!Kr!IrpZ+!)!")G')J#Mrj&*%J*!!"6rSJ!1&-G3KF3!!Nd*THm*dDRb&@2S4K#%
+8(%)eM'-B%M'+SLK!J!$r1HlRqQ6lc[2XlSaV'2e3)4FplhZFjb6'-(8FjdBaM&b
+#4FqG'eBa)!#b8Y+UY@2P"qYDkbq%#!%!"(dh[@[GH[mTr!8r`&2iKr!Irq552NI
+L)M',`1Mm"#T%#@F%!HL!!iqBL#'[`!%94"q'*)aX!%PIaK(hTr3B3M12SqF5-BN
+85##!!4M'-8M'D0BaM(-8M'USLNJK'-BaM'-BT-BqVq-BaM'-DmriND-FcHiRrdc
+9+9!IrMhieleeq2q3"FAV@[@ZYB$q!rrL2ra(rj!%j*)8+5)L2iah@2rr4JIf$i3
+"k)!$K498)5%2i4P)%3BNLm*mL9M'%B3M&"a#-B`M%*)aLSL)))!"'-)r5-C`eM'
+-BZ5-DNL48#%IaM'-2rqNrr#p)aM'-BaSJN#4SaM%!%3##9S@UV9Mj5rV@ZX(L!!
+4!!4p0leVhAVr!IbJ2qK6q%Irrq!ELK4*)L)aM'YBr!5#*!N2a!(SJ!-!&E+K!3!
+#%9!4"L5)33%!5-B4K#-9'N)aM#-3NM'X53J3J!%B`M")aQM@-BaJ&)aU5+&3)4K
+'-B`K##6'-+8M'-BaM'L55*'M'-IrK!)6qK93(q)P+0HpG3!)!"%!"%8V@[@ZYB!
+!)+!#+&"!4rrri!#+&)NL)M&8GeMrj"iNPJqd!HL!!i"@X4)!%")4B4&'*)LSJJM
+SaM'%)a8C3M'-)aL5+Ya*#"#!!6M'-8M'C0BaM'%8QUUS`9!M1-jcR'-)T-B`V5-
+BcR'-DT*FNk-ia!#)!#"9+UUeBL8SkeVV!!J!%3!%46HpDpekJ!!JS!)S8%"(rrr
+J!)S9'5BKd94"@2`!iKJ!"``!#)!$J$T1NJ!3&!jqi6R%FbJ!#+Mjh[`G(ZMq-A3
+G&a(%M%Ri#)2ihcRZ4mCLeLlci10T&4Ip8"cA0DeVR2FNaMpeh1FeVh1GiNL0R0M
+%!(!!H&,48"rL*5MA[A8!#!!4!!4&+eVeVV@!!##J!LK33%Irrq!!XKAf1K#1fi$
+Sr"m#!*!$"!!2J!-!%!!-!"!%!*!'#!!!S!#3#3J!N!81#i!!N!@!3!!!J%!!N!5
+!i!J!N!-"!*!*!3!)!!L!!*!)!UUeBL8SkeVV!!J!%3!%46HpDpekJ!!JS!)S8%"
+(rrrJ!)!!!#!!J!!!L2`!!J#3"`-!N!8J#!#3"K!!!+!!N!N%!*!'"!#3"3L!3!!
+!J%!!N!-)J%!)!*!$!3#3#3%!N!-2!*!*!9!IiL8Srrrq!!J!%3!%44rrN!5!!##
+J!LK33%Irrq!!N!3J!F!!!)rm!!)!N!F$!*!'#!#3#!'`!*!3"!#3"3F"J!#3"`F
+!3"!!N!-#!*!*$J#3$JUeBL8SJ!#3!`J!%3!%43#3"b#J!LK33%Irrq!!N!`#!*!
+(!`#343%!"!!*!!i!%`!C!"S!(3!J!#8!+J!X!$-!0!!l!%!!3J"(!%`!83"@!&X
+!B!"P!'S!D`"Y!(%!GJ"k!(m!K!#*!)i!N`#B!*d!SJ#R!+`!V`#d!,N![J$$!-J
+!c3$5!0F!h!$K!1B!k`$`!28!qJ$r!33""`%1!4%"&J%G!4m"*!%T!5i"-`%i!6`
+"33&'!8F"5J&2!9%"9J&E!@!"C3&U!@m"G!&i!Ad"JJ'(!B`"N3'@!CN"QJ'G!D)
+"SJ'R!D`"X3'f!EX"`!(&!FS"c`(8!GN"h!(I!H%"jJ(V!I!"p3(k!Im#"!)*!Ji
+#%`)B!Kd#)J)R!L`#-3)f!MX#3!*#!NF#6!*4!PB#@`*J!Q8#DJ*[!R8#H`*m!S%
+#KJ+-!T-#QJ+E!Tm#S`+S!Ud#X3+h!V`#`J,)!Xd#d3,9!YN#i!,R!ZX#mJ,j![d
+$!J-(!``$%J-B!ad$)`-T!c!$0`-q!d8$5J01!e)$9`0H!f8$D30Y!h3$H`0r!i-
+$LJ13!!19!jS$R`1N!kS$V`1f!lX$`!2&!mS$c`28!pN$hJ2M!qJ$k`2Z!r)$pJ2
+l"!!%N!-*"!S%$`36""F%'`3E"#)!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!
+(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F$"`)(!3F""`%
+(!!F$"`)(!JF""`%(!JF!"`-(!!F""`)(!3F""`%(!3F""`%(!3F""`-(!JF""`%
+(!JF""`%(!3F""`%(!3F""`%(!3F""`)(!3F""`%(!3F""`%(!3F""`%(!3F""`%
+(!3F""`%(!3F""`)(!!F#"`%(!!F$"`%(!3F""`%(!3F#"`%(!3F$"`%(!3F#"`%
+(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F#"`-(!JF""`!!!3F""`%(!3F""`%
+(!3F""`%(!3F""`)(!JF#"`%(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F""`%
+(!3F""`%(!`F""`%(!3F""`%(!3F""`%(!3F""`%(!`F""`%(!!F!"`!(!`F!"`!
+(!!F!"`!(!!F""`!(!!F!"`!(!!F$"`!(!!F$"`!(!!F$"`)(!3F""`!(!!F""`!
+(!!F!"`!(!!F!"`)(!`F$"`)(!!F!"`!(!`F!"`!(!!F$"`!(!3F""`%(!3F""`%
+(!3F!"`%(!3F""`%(!3F""`%(!3F""`%(!JF#"`-(!!F""`%(!3F""`-(!3F!"`!
+(!3F!!3!(rrm!!"%Q!!%!N!-F!*!$6J#3"2rr!*!3J%!!N!9!!%!!N!P)!*!$5!#
+3"3J!!3!)!*!'%%i!N!3%N!-&"*!,"C!%!J%#!33&"33%"3F4%JS&N!`#!J@3!`F
+("!N("3H3"!8&"*!%"`8&"*!,"C!$"*!$!3)""3F,%483"`@3$3)#"38(N!-%#3F
+&"3F*"`8&"*!%"353%`8&#a%A%3X("C!)"!@3"!3&!3)&"!3'N!-*"`F&"3F*"`8
+&"*!%"`53"`8%N!8&"j!$#a%@&a)2#33&N!B%"38%"33&"33%"33&"!3'"!H3"!8
+&"!X,"`8&"!3&"`F&N!-(#JX4$!X,$4%5%KFB'4N5#J3%"`N("C!'"!8%N!J&"*!
+&#3H3!`@3!`B($3N&"`8("a%A&K3B&"L3"4Q3""J8%K%*"`8%"!8,"`@3"!53#`8
+&"!F%"!N(N!-&N!3%"`X0%!d4%4-3#j!%#T!%#a!,N!-+"`F,#`F("33%"JN("C!
+%"!%%"!8%!33%"3F(#3F%"j!&"33&N!-%"!X0$!X,"JF("353"!%""j!*#`H3!`3
+'"!N("C!&"!3(#3N("`N("`3("`3*"j!&"!8&"`D3"33%#`F("C!&"!%(N!N*"j!
+(#`F&N!3,N!-("33&N!-%"38("!N(N!B&"`F'#3N'"*!$"j!$"C!%"!3"#3H3#!B
+*"j!'#3F&"!8,#`F&N!B%N!-&"`3*"j!*"T!$"353!`F*"`F&"33&"!3*"j!3"3X
+(#a!,"`8%"353"J@3!`3,"j!$"JH3#!8%N!3*"j!$"C!$"!3,"j!*"!H3"J8,%!X
+("`8&"*!-#`H3#J8&"!3&"!3(N!-&N!-%"!F*"j!*"!H3"J3'#`F("C!$"*!("`5
+3!`B,"j!+"C!$"*!%"j!%"C!$"!X(N!S%"`B(N!3%"JX("`8&"*!)"C!%#`N(N!S
+&N!3%N!3(N!-&N!-%#`H3#33%"`B(N!3%"!X(N!-&"*!)"`8%"!H3#`@3"!F%N!3
+'"C!&"`X(N!N%"!B'#3F("J3%#`F("C!$"*!("`8&"!H3#33(N!-&"3F&"353"!@
+3!`30#3H3#!8%"!B,#`F("*!$#`F&N!3%N!F("`3%"j!%"3H3"38("`@3"353"!8
+&"!X,"j!*"T!%#3d0#3B%"JX&N!8%N!8"!33("38(N!3&"`F&N!8("33&N!-%N!3
+&"3B0#3H3"`B%"T!$"`Q3"!X*#3F&N!8%N!8"!33*"38(N!-&N!i%"!%%"!8%#3X
+(N!F'"!3'#!B,#3N(N!33$3F&N!-%"33&"!3"N!-("`8(N!-&N!3%"C!&"*!$"35
+3"3F'#`F*"`N(N!3'"!D3!`X,#3H3"!B*%!X("C!$"*!%!C!%"`X&"!F("C!%"!3
+&N!F%N!8!"JX*N!3(N!B%"`B,#`N(N!F0#`X*"`8%N!8"N!-%$38&"`F&N!X%N!3
+&"!3'$3d,#C!$"j!&"JB*"JX*#3H3"JN,#3N0#3N("*!$!C!%""!("!F("C!+"*!
+%"38(#`B($3X*"j!&"T!$#`B*#3F*"j!&"!X,"`N*#`d4%!X(N!-+#a)@"`8("`@
+3"33&N!-%N!3&"`X,"`8($3N*"j!$"T!$"`X*#3H3#3B0#3H3"!N,$C!$%!f3""%
+0"!F("C!$"!8%"C!%"!F($3d*"j!$"3X,#3N("`N*#`X*N!-(N!S,#3H3$JX*"`F
+&N!-%"33%"33&N!-4$3X(N!3&N!-0"`N*#`d,#`F*"j!+"JN,"j!+"38%"!8,#3H
+3"3Q3"!X*#3X1#3H3"3@3!`3,N!--#`N*"`N(N!S&"!X*"j!'"3F&N!8("`X*"C!
+$"`F&"`X,$C!%#`H3"3@3!`3%"`d,$!N*"j!0"3B,"j!("C!'"`F*"j!$"C!%#a%
+0#`N(N!J&"353"3d,#`N(N!J&N!F'$3H3!`8("`8("C!&"j!$"3F("38(%"8,"j!
+)"C!%"!3("!3'#`X*#3F("38("C!'"!@3!`F,"j!$"C!$"`F&N!3%"j!$"38,"3X
+5%`X(N!J&N!8%"!N,#`B'#`H3!`8&"!8%"C!%"*!$"38(#3H3"!8(N!-&"33&"!F
+("C!$#`d9%3X(N!N&N!-%N!-(#3H3"!X(N!-&"!8%N!J&N!-*"j!'"38("38%N!-
+(N!-&"3F,#3H3#3@3!`53!`H3!`8%"!F%#3N,"`53"J8&"*!$"38%#3H3!`@3"`5
+3"!8*"`F&"`B*"j!("C!%"*!$"`F&"33&"3F("JN("`8&"!3("C!$"*!$"38%#`H
+3!`@3"`53"3X("`B%"JN'"j!%"C!("!F'"38%N!3'"!B'#3F("38("C!%"*!&"JX
+(N!-&"3H3"!8%N!3,$3F'"!3'#`B%"j!%"38%N!-'N!3&"33&"!3("!3'"JH3$3X
+(N!F*#`N'"J3%"`X,"JB%N!-'#3B%"``*"`8%N!3'"`F&N!F(N!3*#3H3"`8("C!
+$#3H3#JQ3!`X,"T!$"*!$"J3'!`3($3d("*!$!3%'"`@3#!3(N!F&N!-(N!-&N!3
+,"j!,#`X*"!3("`53!`F%"!B%"`N*"`53!`%%#3@3"!H3!`8%"!H3"`8&"j!%"C!
+%#3H3$38%"33(N!-%"`3%"JB(N!-'N!-%N!-&N!3(N!3&"!3(N!F&N!N%"JF("C!
+$"j!%"C!&"!3&"3N("JF&"!3(N!3'N!8("C!&"j!$"33%"JH3"3@3#J3'"`@3"!F
+("C!("*!$"33(#3F*N!-("`B%N!-'"!B("`@3"!H3!`8&"!B(N!8&N!S%"JN&N!i
+%N!J&N!-("3F("*!%#`F&N!B("38%"JH3"3@3#`3,"`@3$J53"3@3"33&"`F%N!-
+'"!F("C!)"!B(N!3&N!`%#`F&N!3(N!-&N!3%N!-&"*!&"C!+"`3&N!-("`8("C!
+$"*!$"j!%"3F&"3F("C!&"!3,"`@3"!H3"!@3"J53!`8%"C!'"!8%"3F%"!@3!`3
+(N!3&"`3%"JN(N!-&N!3("`@3"33%#`N("C!$"j!%"C!&"*!("33&"*!*"38%N!-
+(#`F'N!3*#3H3!`8%"j!$"3F&N!3%"!N*"`8("C!)"*!&"33&N!3%N!3&"!3&N!N
+("`N'"!B,"j!)"C!&"*!%#3N'"3F&N!F%N!B&N!8%N!J&N!S("`N*#`X(#3H3"38
+("C!&"*!$"`X%"C!&"!8&"*!'"C!%"*!+"C!&"`@3#!3%"J3%"JB(N!8&N!B%"!d
+%N!J&N!-%N!3&"353#!F*#`N("`@3!`F&N!J%N!F(N!B&N!8%"!X'"*!%"`X,#38
+&"*!&"353"`F*"j!$#3F&"3H3!`@3#!3%"38%"JB(N!3&"j!$"353!`F0"`F,N!-
+(N!-&N!3%"C!&"*!&#3H3"38("`8&"j!*"38%"!F%"!H3"J3(N!3%"a!0#`X(N!B
+&"`53"!8%"C!$"*!$"`F*"`F&N!N%"!8%"!F&"!8("C!$"j!&"C!$"!3("`N*"`B
+'"`3'"j!&"JB%N!-&N!3%"!H3"J@3"!3%"38%"38%"!8&"`F*"`@3#33&"!8%"!H
+3!`B%"JB%"JH3!`N*"JB,#3N(N!8,"j!'"C!$"!@3#`F,"`@3$J3&"3F%N!-*"JF
+,"j!%#3X,"`N*"j!$#`X(N!B&N!i(N!3&N"%%N!-'#j!$"`8(N!B&"`F&"3H3!`B
+(N!-'"J@3$!3("!8&"`@3#!%&N!-%"C!%"!3'N!-%"C!$"!3'"J8&"!H3"`B("33
+*"J@3#J)&"!3#!J8("C!+"!@3"!)#"!B*"JB&N!-""!3""!8&"!H3#!8&"`X&N!X
+""38#"3)#"`F&N!-%N!B&N!3"!3)&#`B("`@3"!53"!@3!`H3#!8(#3F&N!S%"C!
+$!T!%"3F&N!-""*!&"`8%"3)#!3F,"C!*!38#"38(N!J*#3F&N!8%"!8&"!8&"*!
+$!38&!J%("`8"N!-%"!@3"J)"!JX("C!+!J%&"3H3"`N(N!-&N!3""!3&"353"`8
+%!J%%"`8#!C!$"!3&"33%"3%&#K%&N!`#"C!$"j!$"!F*"j!%"C!%"!#3"aN!!2q
+3"*QC!!(rN!4QCJ!#rj!%-c-!!rrrc-bCQ3!%rrr-c'CQ!!Arrmc--c-!"[rrQCP
+QCJ!(rrqCQ6-c!!MrrfD3"!!*rrpQCM-c!!V-c*QC-c-!#mc-CQBc-`!-c-aQCJ#
+3!`h-c$13"!!1c-`c-`#3!`qCQ@CQ-c-!%*QC-j!%!"'CQ6-c!*!$%QCQ-c-!N!-
+6CQB!N!88-c-!N!89GhF!N!8@998!N!8A4%3!N!8B)L)!N!8C%4%!N!B)[J!"!*!
+$(!#3!di!N!6rr`#3%)!J!*!&3!"!!*!*5!#3!dJ!N!8%!!%!"!#3"JK1!*!%E-C
+Xc-c'Gfc-c'c'TRT'c-E-aQE-c+CR%A4(DQc-E-aQUNGQChHU4Xc'c-c'aUE-N!2
+'E-c-5RUUGUCk4QCXE(DNCXCN&X4-c*!$aNChT-E'c-aXE-4QGk&(4NC-afTXT+T
+RDNT-a(E-N!4UV'DQc-CXc-aQaRTkGNCfGdCQc'GQCdG+UNG'aXc'aQI-ChCQc*!
+%C+Ch4NCf&QCdCXaUc%DQ4'4'4QGXc-aQI'aRc'aQCRTRC(4RDKCfUQ4QCmaQ4+H
+U&NCR4(CQc+GQaRE'c'TdCU5K4dGRCdGQG'TfE-c'UNTf5RC'5QE'GkGXCmE-CU6
+-HRTf4(S@G%HQ4kCQc-aXC"URCRCk3@c'HQc-CXb3"'G'4RB@C%CQC'Td4-b3"'H
+UCRGQGQChaQCQC'a%CRDNCfS@Gk4N4NCf4XCXc*!%TR4'GNGXCmaXCfc'CQE+CdG
+RCdGhGRGfC'6-aXb3!m6'ThCk4UahChc*aRafaN&kG(SATf4R4fD3"-b3"-I-akG
+fGfGhc%GNCkCmCXCfTNCNC'GKC'CUC-b3"XCmGj!$CQCR6%V+4'I'4NGfCkCfS@G
+UGT!$E-b3"'c'I+CQGk4dG%4d5RCQDXCfCQChGRCdGQHNCQc-N!4Xc(c"GhDQ4RB
+@C'4'GdTfCQI+TRbKCd4kaQE-E-b3!dE"c'E'CRGU&RHNC%CRTdaR5Q4fGQG%CQC
+%E-E-CXc'CRc'N!2%GfGR4hGfGQ4NI'bKa%HKCaC%C'c-c-E-I-CXaXaXChGdHKH
+RC'GNC(E'E-a(B@C%CXGhc-c'GhE(Cmb3"AGf4Q4NChThCf4fGQV-ChT'4'aNE-c
+%GhCfE-I-c-E-a'CRTRDRC'5NE%G-b'CQGhGRHQV'c-CRN!0%E-E-N!0XaQChGK5
+NUNG(CfG#I(V'4R4mE-CXI'Gda%V-I-b3!f6(CRCdTkDUGN4k&R4'&TGXGm&Uc-E
+(FDaQUXb3"FI(4'Tm3@4f4RB@C%CU"T4QDNHXE-aQ5Nc+'XD3!mb3!fCXaXI%DQD
+NTRHNC'GX&mUKG(E'E%akUQ'NE-b3"@ahCdV%CfahCQCdE'I(N!#N5N4Qc'c'c%'
+K&Qc-c'E-c-E'4%GNG(CNCRGhc(Cf&KP+T'CXE-c'a"&Qc-c'CXc-E'CNT(4NGR4
+h4RCQCXI'G"CdI-c'E'E-a-b3!fE-N!6(4RC%aRDQT(GhTQE(DQ&"c'b3!mc-aXc
+-E-CQE-c-E'I-ChGU`AHRGQ4fTU4'4%5Qc-E-CXCXE-aXE'4'c-c'C%SDG(&fGNC
++5UU3!k&+4d&XCXE-CXE-N!4UTmaXE'5N%8Tk38T+UU4"SDT+GfCNTQc-CQE-E-a
+XCU'UGQc'C%T%C'T+HQTUUX4'4Xb3!fc*TXE'E(c'CQCf%4UNGXCRHUT%G+3@4dG
+'aQI-N!2'aQbTE'c%c-E-E'CN%D&faXGd5QT"a%UU5USAE-c'aQE-N!1@E'I-c'a
+XaXE"URE(E'G+UNTU5NUUUNI-CXCQaXaQE&PQGmaQCQGQCmG"GQCRT+5USD&+S8U
+Ua'c-c(aXE-c-aaT+DUCQI(GQE('XE-ad4(&"4%T%T%4NaXc'aQCXN!3CN4UQ4mE
+-aXCN4QbNG%TdE-E(5NUK5@aQaQaQCXc-aKT8NCSDE(aXN!9mBDT'aXaK4*!%GQC
+NE'D3!fc-SA%4N!-Fc*!$aXCXCXCfV-E'bNT+DQTXE-aXN!6-CUT"4"%4('CXE'D
+3!fGUa%V+CQUUT+T'Gmc'N!6-CQ`4&"4%%4GQCmI+bNUUCRUQc-c%UNC+4(4Qc'C
+RCfE-aNT+4+UK&dGQN!0N&(TfBD(-E'aUT''THRaQE'GXafc'&+CU%4&"5RCfG(T
+%F8TaS4UU&QURDNUKTQaQafCXc'`D4Q3D4+4hGXaRCkC(G%SD&"5R5RT"3DUNTQb
+3"-CQUUUKUUUKCh('N!0RCQDRHN53!a4%3D&"T"&-E'E-akC"UUSDT%4fGfaRCfT
++&dT+4%5N4'UNS8UK34C'E-c'TK5NDUTQYQE'CRC'T+UK3A&"UT!$5U'K5U38UQC
+%CQC(UU%AUN4kUQE-c'C%UR4h4(4%G%6%5N&"UUSDUUG+CN4(4(5N58CkI'aXTa&
+"S@&kHNSDS8UKT*!$C'UN5RCa5RCRTkC+GNGQ4XCm`DT"4+5N4%TdT%T+DUTmCU'
+3!a%4aQ4QaQI'Gfamc-c'TQGUHT!$UNUUT+HUSDc%UN4d5NV-SDUKV'D3"-c-C%4
+U4NUUUNUU&-E(ah4mc+GXbUUUaUSD3@E'UXamc'a+5Q4KG%T+UNT(E'c(C+c'N!5
+T%@GUT%CQCQQQCQCf38&%4NDUTU&"GXc'aQ3@c'c'CN5U%CURDUC'Ci&XC%U3!d5
+NTUDU'U&%GfE(a+E-aQC+DK3@4QS@E-aX4'aQT%TRTNTh4mC"3Ac(E-aXUXc-bRT
+d4%UNG-6'CN&Qc'HUUNT'5N4fc-DNTXE-E-bUV-c-CQa+3Dc-5XaXa+4QDUU3!dC
+K5Rc-CK%AaXCQCUSAaQCXaQT%4Xc'aXb3"'UUDN&kHUTmE-bR4XaXc'GfCQc-N!4
+Qc-c'c*!&aNTkGRGUG"E-CNCXN!0QUUT"GXE'c-bRE-aXI-c-CXc'F84aGd5UNfa
+Q4Qc'DT!$GQT%c*!&CXE+aXCQCXaQG'4fI-4Q4'5UI-4Q5UUU3A&a4QE'c!#3"``
+!!*Q3"J!"CT!'!!*QCM-cCQB!!c-cCT!%!!3c-fCQ-c-!"613"'CQ!!BcN!B!"`!
+!998!N!-)UT!'!!PhN!B!#P@3"J!,4*!'!!`LN!B!!"%@!!%!N!-F!*!$6J#3"2r
+r!*!3J%!!N!9!!%!!N!P)!*!$5!#3"3J!!3!)!*!'%%i!N!36"a)*"`S5%`J#!`)
+4%K86#3B(!`)$!K)4!`F5!`)4!`B#!K!#!`8#N!3"!T!$"J-3!`8'N!-#!K!$!K%
+$"K)(%a-)%JB#!K!4%JN)%JJ("`B'!K!#%`)#%3F#%3-'%JF5%JF'!K%3!a!$%3-
+#N!84!J-(!J-4"K%(%JB(%`S6%J+3!`-4!`B(%4%6%4)4!`B(%a-'!J-'"J)(%3B
+(!`-'%JJ9#48(%j!$"K)5%"!("JN6"K%'"a-(#3B*N!-#!`)#%J-3!J)(!`)(!J)
+$!T!$%K)(!`B'"`-4!J-#!a%#!J-#%3F$%a3(N!-*"a)("K)("a-("a13!a)+"a%
+$"a%#"J)#%3B5!`)'!K!#!3)'%JF'!`8'"`B#!a!'"a!#!K-8&3F$!JB#!K%$!K!
+$%JJ(%K)#"J-*"a)#!K%(%4!'%JB'%K-(%K-6"J-$%JB6#3N)%K%%%JJ$"JF6N!-
+(%a3*#3B$%a-(%JB#"JB$!J-#%`F'!a%(%3-4!`)3!J)(!J)$"JF(%JF$"JF'#K-
+0#JJ5"`-4%a)4!K)*#K-'%K-*#3F(&!F6"`B3!JB#"a)4#4)3!J-5#!B(!JB$%T!
+$!`B6"JF'"K-#"a%'%T!$"`-5"`-4"`F4!`S6%J-#%3J6#K%$"J)$"J)$"`d6#4)
+#"a-$!`B4!K%(%3B$%4)(%a%("JF'"`J(%K)(N!-'"`-'%3)'"`N'"`F6"JF4%`J
+("a%#N!-'%`B'%K-5"`F*$480%`S6"`d("J-4%4-6#!)'"`F*&!N5"J-'"K)(!K%
+#"JF5%JF$"K)6"`-4"`F5%3)'!`B*%`F$"a-6#3B5"`-5!`F5"a30&4-(N!-+%J)
+4"a)$"J)#"`B(!J-$%!-("K)("J-4%3-'%J)("T!$!J)'%4%(!`-5#K-*"`)(%J)
+4!K!#!K%$!J-#%JB*!`)$"J-#"`-'"K!#!K!$"3-5%4-(%3-(%JH3!`)$%K)("`B
+'!JF(#3N@"a%#!J%5!J-'%J+3!`-'"a'3!`-'!`)4!K%5%`B(%JF5N!-("K)(%JF
+5!J-'%3)4"K)5%`F5!`B'#"-0#4)+%a%'!`B(!`)4%3)3%a)6#JB5!`F'"`B5"JJ
+5"`N6N!-'"`F5"a)(#4-*"a)(%3)$!`)$!J-$!K%#!JF6"a)("J)$!JB$%3-#"JF
+$%`F'"a)(%JF5"JS'!a%("K-)"`F$!K%#"K)$%JF#!`)$%3)'%j!$!JB#!K!#!a-
+4!a%#%3)4!J-#%3F'%JF'"`B'#")(%J+3!a-#%3F(%j!$%3B4!a)$%JF#%3B#%3)
+4%3B6#K-'!K)5%`B#!`B$"`F'!K%#!`B5"`N'"JF5&3d8"a-5!`)3%K)(!`B'%JF
+(!T!%!`B(%`B5!`)$%JF5%3F(%`F(#3N(!`)5%K-5%J)5%JB$"J)("J-#"a-("JN
+$%JF5"`B8#")'!J)(!a)5%!)5"JF5!`+3!`B'%J-#!`F6%`)3!J)$!K%5"`N+#3B
+'"`F$"J)5"JF4!a)$!JB#!`F'!a%(%JF6"`N*%JB$!K)("JB6!K)'!`B(N!-5%a-
+5!`)3!J-5!4!#!K%5!`-'#JB5"a%(%JF'%3B#%4-("K)'"3-'N!-5!J-#!`B("a)
+$%K-("JF'!K)6%K-5%JF'"`B4!`F5%3B(%K38"a%5"`B$!J-4!`-'!JF'"`B$!J-
+("JF'!T!%%!)3"`-'%3)(%`F5!`B#%a-("a-)"`B#!a%$%K)'"`B$%JF(!`S6%J-
+#%3)$#3F'!`)$!`B(%4)4!J-2!K%$"J-#!`)3!`)$%JB$"J)'%JJ("JF'%3-4"a-
+(%JF(%J)'"a+3!a-'!JB#!JB$"`8'%3F5%K-(!`B("J)#"K)(%`F5"K)5"`B#"JJ
+6%`B'"a%#!a)6""%4"T!$%JF5"a%)#4-(%a-(!a)#%3-6#3N6"`B(%3F("JB("J-
+5#3F)#3F'%JF+#4-(#3S6"`-("`B6%JN+"J8$"j!%%a-5!`B("a-9#3F'!T!$%4-
+(%a)(%JJ'"K%$%4))"K-("K-5"`B(!`B'"`-6#3N'!JB'!a))"a-'!a+3!a36%JF
+#!`F5%`N(%J)'!`B'%JS6"a)#!J-#!JB(%JF6%3F(!`F$!K%$%3F(%JF5%`J(!a%
+$%3F("JB(!a%(!a%$%3N6%K-'"`B'!J-$%3)'"a36"a)$%3)'"K-+%`F5"`-'!a%
+3!JB#"JB5%JF5"a)5%4%#!K%5"a%$!3+3!`F(%`F$!J)$%JF$"JF5"`-'!`B#!a!
+("JF5#JN8%`F5%a)'"a%#!K)(%JH3!`B'!J-'!J-#"K-(%J)(%3)5N!-'%J)3!J)
+'%JF'"JF*"a)&"a%5"a%6"`-'N!-)#3F'"`B#"J-#%JN8%a-(%JB$!J-3!T!$!a%
+$"J-5%`F5#K)(%J-#"J)5"`B#!K)6"JB#%J-(#3F5"`)5!`F'"`)3!a)$"`B#%JJ
+6"`)$!`B'!`B'!`F'%3F("JF(%JB#!j!$%J-'%J-5%J-#%4-(!`)#%!-'%`)'"a)
+5"K%'!`)3!K%4%JF'"a)4!`)'"JF$!J)4"a-'N!-5%JF'"J+3!a%&"J)#"3-4"`B
+#"JF(%K%'!JB("JF5"K)$"JH3!a)5&"3,"a%$!3)$"a%4!T!$%3B'"a)("`J("JF
+5!`B#!`B'!J-'%K-(%a)'"a-5%J-#%3-9%JF$"JN(!JF'%`N,%a)("JF6"`B("K%
+#!`)$%!-'"a-5%`D3!`-'%4%$!a)6"a)6"`F6"a-("a)(&!F'!JB6"`B$!JB$!K)
+'"J-4!J)'"`B5!J-'%JF("K%'%`F*"a)(&3J4!J-("J)$"4%(!J-6"`B5!`F5%J-
+'"J)4!JN)"`)4!K)("J-#!J-(%4%(%J-'!J%4"a)6%JF(%JF6#4-'#!F#!K%("J)
+$!JB(!`B(!`-("JB5!T!$%3-3!K)(%4-)%a)5!J%#!a)(%3F6N!-(!`)(%a)(!J-
+5%`S*#JB("`B3%!)4!`F'%4%("K)(%K-5%J-(!K%4!J-#"K-(!a-#"`-("`B#%4%
+'!`B'"a%$!K!#"K%$"T!$!`)3!a!(#!B'!J-)%K)'!`F'"`J(%a-(%`F4!`%$"JF
+5%`F#%"%#!`)"%3)#%`J("a)(#a-$!J)3!K)(%JF'"a%("J)4%J)'"`D3!`F5!JB
+'#"-'%K-(%JB#%4%("a)'"a)#"J)#%"!$"J)3!`B##3N+%`F#%")6%JJ5"`N(%JB
+(%JF9#K-6#!B("a)("K)6"`N'"`S6%JF'!JF(%K-(#!B#"J)$%JF6%3F5&K8("JB
+5N!-$"JF4!`F9#!N'!`)$"JJ8%JS6"`B$!J-$"a%$%3B$"a)6%JF$!a-5%JF'%J)
+$%JB$%K)@&3X6%`F4"K3+%`-#!JF'"JF5"`B("J)4%4-6!`B'!`-#%4%'"J)$%`F
+(%JB'!J)$%3F'!`F$"J)$%J)(#3S+#3)(%3F5!`)'N!-4"JB"!J)'%a))!`)$"a8
++%JF6"`B#%3F5"a)'%JB5"JF("K)5"a)'!`)4!J-6$"-*%T!$%`B6"J-4N!-+%J3
+#N!-$%K-("`B("3)3%4-("K)5"`D3!`F5"a)("a-("a-("J-#"K!#N!-5"K-0#")
+("a-)%JF#%3-8"`F5"a%5%`B'%JF5#3N(%J-3"`F5"`B$!K!#!K%$%JB(%3-#%a)
+)%JF'"a)(%JB'!a%6"JF'"J-(%3B$!`)'!J)3"`-'!`)##!F4!`-#%3-#!JB'#")
+'!T!$!a!#N!-$%JB6#4)(%a)(&!F5!a%$"a-(#!F$!J)5%JB%!K)(%J)3!J-#N!-
+3%J-3!a%#%!-#%!-4%`B#!K!'%J)#%!-4"`-(%JF$"K%$"J-#!J-#"K)4!`8$!K%
+'"`F5%")5"`B$"a-5%K!5"`-#N!-5%`S5!`8(&3S("J-'"a)$%K%("K%4"`)$"J-
+#!J-#%"!#"JN("`N5!K%(%K)#!`B(!`B#"K-6!`F("T!%%JF6%K)#"JJ0#3B$"a-
+)%J8$"K)*#JF)"K)'"a%#"K!#%3F*$3F5#3B#"K-(#3F*%`F'%3)$%JF#"a-5%JF
+#"a)9&3F#!3F6%JF$%4!#!J-#"J)("a-'%JF)%`)#%JF(%K)(%J)$"J)#"JF5"a)
+'"`)$!JB$%a-(%K-#!a%(&4-,%`F'"JS6"J)#%!F'%K)#!K))&43'"`D3!`)$%K-
+5"JB)!`)4!J)3"JB5!`B$"J)4%3-4"3-#%3B$%K%("JJ6%JB'!`F5"a-6%J-#!a%
+("JN(&!N6"a)("J)'%3F5!`)4!K!(!`B4!`F$"`F*%JF'"a%5"a-6#!B(!J)(%`N
+(%3)#!`8$!a!#N!34"a%$"K)("J)"%!)#!`-#"a)$!J-#!`B3!K%#"a)(%K)#"`B
+(%`F6%JF'!JF5%JJ*N!-'"J)(%3)'%4%$%!-4%JJ5!T!$%3)$!`B#%3+3!a3*%`F
+3%3F4!a-(%K-5"a)$"J-#!`)5!JF'!a-8"JF5%J-#!J-'"J-("JF(%K-("JF'!K)
+5%`N5"a)4"a+3!a3(!J%#"a%'"a-6%JS5"a)4"a)'"J-#!`B'!K-)%3B("`B("K%
+$!J-'"a)(%`F'"JJ6"J-'"`N)%a%$!K)(#3N+"J)#%3)2!a%4!a)("K)("a%'!JF
+'%`B$!JB("J)$%!)#"J-(%`S6%JB$%JB$"JF6"`F6"a)(!`)#"JJ5%JF'%J)'%`B
+5&3S(#T!$%J)$%K)*"a)(%4)#"`B(!`%"!J)6%JB'"a)5"J)("JF'"a-(%J)$"K)
++&K-'"J)5"`J(%J-5%J)$#K38&3N5%`-6#4-)"a%("K-#"JB(%`F#%a-9&!F(%JF
+5!JB(%`N(%JB$"J-5%`F6%`)$%3F5%JF'%`F$!a%(%a)$"`B$%J-'%3F#!J%#%!)
+#!`F'%`-#%Jd,#4-6#3S6"J-#!a%$%3-4"a-5%`F6#"%#N!-$#4)6"`)3%3)$"K)
+(%JB#N!-4"`F$%!)!%J)$%3)$"a%#%!X6%JB(!a)3!J)3!JB'!T!$"JF$!J-'"JF
+$"T!$%`F(%a)6%`F*#4-+"a%5!K)'!JB$%4)5$3S6&"%5!a%$%K81%3B#!J-#!J%
+"!J-5"`B5#3F'!K%'!`F4!J)$%JS*&!-(%3-5"a)6"a!#!K!#!`N("JF'!`)"!J%
+#%3F5"a-(%!-("J-"N!-#%JJ8%JB(#4-*"JF5!`F5!`B'%JF5!`)'!a%(%`)'!K!
+#%3-5%K-("JB$!J)4!J-4"`-'!a-("J)#!3+3!`B(%`N6"`F5#!F(!a%5"a3*"K%
+4!a%5!K%$!J)6"`)$!K!#%JF0&`J6"J)("JB*!`B#"JN+$489%`-5%JF4%3-5&!S
+6%a)6"a)4!`B("a-6"`)("a)+%a)(%4%'"K!3%4)5#"-6#K%(#3F)%J)'!JB+&!d
+0#3B'"`F4#3F6%JF6%`F$!J)$!`B'"`N(%K%$!K!#!`B(%JF5!K)("`)#!`#3"aF
+!!2rrc*!%!!(-N!B!!Xb3"*QC!!2-c*Q3"!!%c-bCQ@CQ!!@CQFc-QCN!"TQ3"J!
+(QC!%CQB!#*QCCT!%!!PQN!B!#QD3"$-c!!YQCM13"!!--c0QCM-c!!dcN!B!$J!
+!)L)!N!-2hC!'!"#lN!B!%DU3"J!5L*!'!"0hN!B!&&@3"J!94*!'!"BLN!B!&a'
+3"J!!#)B!!3#3!a`!N!01!*!%rrm!N"#!)!#3"8!!3!#3#8J!N!0)!*!&"!!"!!3
+!N!B)6J#3"%4!0%3c-%0$4$-c3c4%!$-`-%4%-c3d-d%d4%3d-$13!d0$-$-d&%4
+%-j!$4$-$4!"%&$3c3d%4%c-d-$-c3c4%-c-$-d4%3d-!-!4%-$-c0$&%-d4"%84
+%-c3cN!4"3c0$3c0$-c3d-c0$0#-cN!0"0$4%384$-d4$-c-d4"4%-6"!4$!`3d-
+`-c!`-c0!-a4%3d4%0$4%3d-$0%4%3c-c!c383d-c-`!c0$4%3d3d0$13!d-c!d3
+`!c4$4$-d-d4$4"-c-$-`!$3d383c-d4%0$3c-`-d3c-%4$!80%-c3c0$!c-d0$-
+$3d53!c"$4%4$3c0$-d3c-d0%0$4$-`-c3d-d-$0$3$53!a-c!d0%4$4$!c!d0$1
+3"8%$!c13"%0%-d4$384"-c0$0$3c4%3$0%3cN!3d4%-`4$"%-c0%-d4%-$4%4$4
+"-a0%4$3cN!0%-c!c-a3c3c-a-d4$3d3c"$-c&%3dN!-c0%-84$-c3d-$0%3c4*!
+$-a3c4$4$-c0$-c-80"4$0$4%4$0%0$0%-!3c3d-44%0%4$4%0%4%3c3c0%3c3$0
+%3d4$4"4%3d-$4$0%3a4%0%4%3d0"-c-`4$-c3c3$"%3c3d0"4%4$!$0$0%3c3d-
+d3d&%-c3d4$-`!c0%3d0%3c4$3d4$3`3c-a3c4%4"%838&%-c&$3d!$-c"$0$3d4
+$4$3c4%-`4$0%4$4"-49"0%4"0%3c4$13"%-c0$4"3a-$-d-d0%!`-d-c4%380$-
+84%3c3`-d!c3c3%13!d4%-$-a0%&$-`4$3$4%4%0%0%4"-c0$4%3c-`-$4!0%0$-
+$343c3d0%0!-d4$-44%%d4$-c-%0%N!0$-%0$0%0$!c4$&$4$-c-d0$-d4*!%3d3
+d0%4"4%-c-d4%3838&%0%N!0$4$3c-d53""&%4%0%4%-c%84$-c"%3d4%&%3d-d3
+63c4%0$4!0%4%%8-84*!$0$383c!c-"3d4%4"3d4%38&%0!4%4$380%343d&$4%3
+`0%4$-j!$3d-84"%c4$0%4$3c3d-d4%0"384$&"4%N!-8363c0%4%3d4$4$0$3d3
+4-c3d-d3d3a384*!$0$4%-a4"-`"%4%0%-d4$3d3d%83c4%0%36-c4%0%0%-d4%3
+c&%0!-%3d-d-c0%-d4"4%3`-c0%36-d&%0%4%0%4$4$4$0$!c4$0$3`-$4$4%&"3
+cN!0%4$-d4%0%4$4$&%53!c3c!d53!c-d3d%d!d-c-$-c0"3c3c4$0%4%0%4%3d3
+c4%3d-c3c3d9%4%13!d!!4$0"3d3$4$-c3c!d-d%c4%-c!c0%0%-d4%0%0%-d!c0
+%-d-$3`0%4$3`0%0"&$0%3c-d0$0%3c4"3a4$-d-%-d-c0$3c0%3c4$4%4%%63d3
+cN!-`-d-c&%&$0$4$0%4%3c0$-j!$3c-c4%38%63d4$-c0$-$4$4%4%0$4%0%4%-
+c0$0$-j!%4%0"&%0%4"&$-d3c3a-c&$-d3c-$3d-c-d4%0%4$4$4%-43d4"&"363
+c0%4$3d%d4%-c-d53!c-c4%0%3d0%4%0"4*!$38383c0%0$0"4$-d0%-c0$0$-c4
+$4$3c"$0%-d3d4%36360%N!0$-d&"3d4$-d4%-c-%0$0$3c"%0%4$4$4%N!Bc-c"
+%3c-c4$3d-%3$-d3c4%%c0%3dN!0$4%-d4$3c3`3c0$4%-c4$0%3d0!4$3d4%&$3
+c4%3c4*!$0$3c0$!c4$3c3c!d3`0%-c0%-c0$3d%d0%0%0$36-d4$4*!%0$0$N!-
+c4%!$0$3%4$0%-c0%%8-`&%0"-%%d-d4%&%3c4$!d3`4$!d4%0$4$-c4%-83d0$-
+40%-c4$0$&%4%0%4$N!3c3c4$3c%c3c4$4*!$36-d&%4$0"-c3d4%0%%$3`-c4%0
+"3c0"4$4%-c4$3c0$4$0"3d-c3c4%0"0%-6-!-d4%384$-d53!d0$-d-c-c3d3a0
+$3c3d4%0%0%0%0$4$0$-c0$-d&$3d-`0$-c!`0$3c4$3d-$0$-c0$4%3d4!0%3c3
+d-%3c4%-c4!-c-c53!c-dN!-$0$-d4*!$3d!c3c3d3c3d4%&%0%-c4$3c4$4$&%0
+%-`0%4%0%N!3c-c!a4$0%4"4%4$3`0%-c&%!8360$-c!d&%&%&$3cN!4%3c-d3d3
+dN!0$0"-d0%0%3d53"!4$4$4%N!0$4$-d-d4$-853!c4%3d3d3d4%-d4"-83d0%-
+8384$0$3`0%13!c0"4$0%-d4%0$-c0%4%0"0$3c-d3c3c-d4$-c3c0$!c-d3d4%%
+d4$-d3c3d3c!8-c3`-c%!4$13!c3c3$-d-c3c4%4$&%4%-c4%N!-c-d-d3c0$3c3
+6-c3d3c-d-d0%4%0%3d53"N0%3c-c3d4%0!-d-j!$0%4%0%-c3c!c-d%d0!4$"$-
+d4$13"%3c3j!$&%3d4%4$-c"%-`!d0!4%4$0%-d0$4%-cN!-a3d4%3d4%-%4$N!-
+c-d%c!%4%0%3d4"4%4%-d3c-d0%3$4%-c4$-%4*!$3d3d3`!c-d-d4$4"3d3d-%-
+d-c3d4$4%-c0%3c4%4%0$4%0%3$4%N!0$4%3c&%-d3d0%3a4$4*!%3c0%4%"!-d3
+d4$"%4%0%N!0$0%4%-c0%0%38-d4$384$3a%8-$-c4%%8!%3d-d4$4%4$4$3c%a4
+%-d3c36&%0!-84$-c4$&%N!-!N!F&!!"QN!B!!613"J!#Gj!'!!09N!B!"%53"J!
+&)T!'!!!)IJ!"!*!$(!#3!di!N!6rr`#3%)!J!*!&3!"!!*!*5!#3!dJ!N!8%!!%
+!"!#3"JK1!*!%%c!#-`#3""-$!`)J-!!b!$#3!c)b-$!J)!#3!a!L)K!c!!"!!!!
+`!!!J!J!!-!!K%J#3!b)5)J#3"#!#!!%3!%!`!$!%!!)`%#)J!$-!!J)J!`!")5%
+!)3-#!L)!!!)J!3!c!J!`)!!4)!)$-$!!)*!$!L)4!3!5)J!L)J!J!")J%!!c!!)
+!!!)5)c!c-#!$)3!L)K%J)J!!!5)!)3!#)"%!%!!`!J#3!b%"*!!!-J)"!J)!N!3
+J!J!b!c!#%#-J)5!!-3)!!$!`)#!!!#%`%K%K)J#3!a)L!!!J!#!#!L)4)L!!!J!
+#!`!4)J!`)$!L)3!!!L!L%3)J!#-#)#-J%4%")!!3)J)J)"!3)!-#!L!")J-L!4!
+K!K!!!#3%!J!K)4%!)!%5)J!`%3!#3$-!!M%K)"!!)J)5)!)!%J!J)#)K%!%J)T!
+$)!)4)!!`!b!3)J!`!L)")L!!!!)J)J!!)K)5!!)$3J)J)!!5-!-b!L!L!!"#)3)
+3%6!!%K!#!`!!)J!`!5)!)5!#-J-!-#!#-#%#!L)$)K)30!)#)#!c!b!L!#!L)!)
+!)5!J!$)#)!)5%L!L%J!"!M)K!!)J!!0!)K%J!!)$!J%!)6)#!`!L)J%!!K)J!#%
+!!L%!)!!"-a!#%L-J)J!!!`!"!`-#N!-!)J)K!3!!!L)5%#)5)3%5!L!L!3!`!!)
+L)J#3!`)J)!!b)J!L)3)!-L#3!b)#%3-3!J"!!!!#)"!!3!3#!!!3!#)5!J%J!5%
+L!#!#%J)L)!)!N!-")J!#N!-5!!)L!"%#!L)J!J)L)K)J%#)5)5!K%J%J%K%3-`!
+!!K)$!L)#!5!#%!)4!J!#%K)J)!!!!L)5)M-5)L-c)!!3!$-`!#)!)!)L!L%3)J!
+L!L!K%!%L)3!#!!)"!J)J!5!J!!)$%3)%%K-!%3!#!!!#)J!3!*!$-#!!%3!4)L)
+J!J!!)4!`!L!!)L!4)!#3!a!"!#!J)M-#!#)5)4)L)#)J-!%K!#!$)`!!)#)#!!-
+J!L!J)J)$!#!J!!)`)L)6)!)!!L)$)!)3)#)d!J!#!b%K!J!J!J%!!J)J!J)L)L-
+d)`!K!5-6)!)L!L!!!!)L!6)4)!!M!!!J!"!#!K!#%b!J)L!K)L)M)b)J!L!!%5!
+#N!-3-!%`!!-!%!!!%3%$!3!!-J)5)J)4)5!!!3!3%%)K%L!!N!B#!#%#!!!%)3)
+!%L)K!5)J)!!K!J)!!"!!!!)!!J!!!j!$!L!K-#)5)L)4%L)J)!)M)4%5)b!!)J)
+#-!!!!b-N)!-J-J)!-5!J%"%J)J%4!K!#%L%b-#!!)3!M"#)!!!)!!#%$)!!"!$)
+L)5)!)5!3%#%L!M)#!J#3!b!J!$-#!#)b!5-M3#!L!K)4)T!%%4!!)!-!)$!!!`)
+!!L"$)$)b!`)`)`)#)L%5!K!L)K%M)!)!)!)!!J-b-5!5!!&!)*!$!$#3!b!M)L!
+4)K)#)K)!)#)c-3)J-`!c)J!3)$)!-J!#)`-`%b!!)5%c)L!L%#!#)J!$-!#3!c!
+a!L!J%K)c!!!b!`-5!!)K!M-!%"!J3J!!)$3!N!-#!!)L%3)L)$!$!!!$!`!b%!)
+!N!-L)J-#!J!#)J)#!!-!!L!!!5)J!`-`-$)`%J!L)J!c-#)J-d!!-!!!%5!!-`)
+!!J)K%5)J!`%J!`!L!!)`"$"!)M!!!!)#!")K)J-J-`!#-J%5)L!!)$-!)#!!N!N
+#)!!L!"%33L%#)J)!)K)`!J!4!!!5!J!J!`!!)!!!-J)J)!%!!K!#)J&!)5!L)M!
+#)#)!!a!#!#!#-$)J)$0!)!)b)#!#)!!5!J!L%L%3!#)`)#!#)#)J)b!#!L)$"!)
+b)L!L!*!$-#)#)!)#!!)!)4-J-c!#!!!`!L!`!$!d-!)$)#-J-!)!)3-!!!)`)J%
+3)#-$"$-!-!)!N!3#!d0!)")J"$!c!*!$!L!J!#)J!J!b!$"$3!0#)$3!!!3d3`-
+!%L!%!`3J!$-!!J"!!#!J!`!J)#)c!!!d!b-#!%!c)c)$!3!!%`!J!#)L!*!$-!-
+`-#!L!b!!)!-!-!-!!`!#-!)")#%!)#)J)#)#!!!b-"!!%#!J!J-!-!!M!!)!3%!
+#!")J%!-!!!)4)33#!b%#-M)M-#-$!$!c-`!`)*!$-!-#)!)#!#!!)5!J!`)$!5!
+#-`)`3c!!!#-$!!!L!!!3)!!L)6)J!`%#)#-!!K3!!!-d-$-!-$!!!#33)J!a!#!
+#!`!!!`-!!3*!!!)L!$!$!`!J!#!M-%!!N!-L!#)#)!)$!`!`!M-#)!#3!a%c"$!
+%!b!!"!!`-#!!)$!M!J!5)`!!-$!L)!!"!!3J!#-`)!-`!J!!)J"!-L)!N!-$)#!
+L!L!"-#*!-!0$!!)J-!)!-`!!!J!M-!!#!`#3"#)`)3!L)$!%!$!#%`!J!$!")!!
+b!J!J)!!b)#)#)L!#%J!J!!!$-$!$!$!#!#!!!!%J)c!!N!-#)#-5*!)%%#)K!3!
+J!c3$)#-!3`-!!#!#)!)`0$!L!J-!!J!L)!!$!K)#)L)`)`!J-!!!-c!J-#!#)%0
+!4$!!N!-M)*!$!!!M-J-b)J!$!!!#)J!`!j!$)$)c)`3!!b!!)%!L-M!L!J#3""!
+J!!*!)"%"!!!d-J-#!!-!!$!!)#)!N!-c-!)#!$)#!`!J!$)#)b)!)!3!-#!!-c-
+$-$-J!J%!-*!$!`-!3J-`)J#3!a!3)!!J!`#3"`3!!*Q3"J!"Zj!'!!+UN!B!!iL
+3"J!%Gj!'!!!)PJ!"!*!$(!#3!di!N!6rr`#3%)!J!*!&3!"!!*!*5!#3!dJ!N!8
+%!!%!"!#3"JK1!*!%35)R)RBR&L%aFR)L*aG"&8F@%4)LF84(%4%5*b4%&4%Q%L*
+eBRB8%LBK*fBQ%Q&b)@%4CfGfGK*fCAFR&P%4&@FQ*b4#*Q8QBKChGfB5*N8L%KB
+LCb)5CfBACK*K)5&K*fBP9d*fCL4@*")A&a)N38&b&L)RFRFR)RGdB5&Q&b*Q%A)
+4GR)RB8BP&eF5G(Bf!L%5Gb*L%@GK*bB4%KFR%5FK%LCh)KCQC"%Q)4CK3LCR)R%
+Q*h*L)4&K)K*'Gb%4*K&K)@)Q&QB9&a*fCb35%d-4%R)RB5GK%@&a0N4b)L%L)K)
+N3@&KBK%Q4K)ACL48&8CeFR*RFK349RB54"*LGf)bGRB8CaBK&b)b*R*LC@08-(C
+5GbBA*K)9BQ%d&h)5&eC"%5)d)4%KCK*LBA)93"96GQ*L&aFL%A3LGP3R)LC5%L%
+8%8F5BR*f*b*L*Q)RFL&Q&"*K*b94BL*hN!0Q)K)A*L*48L*LBLBQ)L*#&(Ca34&
+N&a*L&K9$*b*h&hFL%4*bFKFPGb*LB4)QB5GRGK4K%RCh)K*K%8%LGbFL*R*RFKF
+L)5BL*Q*LF4%84RBR%5Ca4hFK&a&PCb*QCRF5FQCKF@B@GLFQ)QF@34-@BL%9)A&
+"&hCLB4%KFR)8*f89CL)L3NF4GfCQB484%4)Q*Q9K*%%5)L)K*'Gb)Q%R&")Q9(*
+A)4%4*QCR%4&#FPGKCK*a%83A&a0N4b)N)K4%-5&K%N)K8K&LBQGa34&"&5&KCbC
+'*NGhB54"*P3P99&#)Q*L)5GKB8*LCh)R)dC"FR)RGa%43RBQ%d&h&eB@99*a%53
+MGh%4&bFLF5)LC8%L&hGb%4%@)LGP3R*e&PC8Ch0"BQ84Ca&h*a&b%L)Q3A0%4hF
+@&K4L*hH3!aGa3988)9-5GeBQ%L*&348KFRC#4&3@)K&4%b*b*h%R)LG84f*K4P%
+QB@)N%@&"GL%4%RBN4"*fF4&#)LGbFL)R)QBLF4Gb)5)L*R3A)QCL%4&a)Q*K%K%
+K&N*L)Q)LCQGL*L%L%C!$*R*b)5BR)5F@&K4b)A)44hB8FR&44'BAFRBLGh)4%@3
+5*L*K&LFLFL%5%R)L*"*A*bGR&&-@&d4LFLG"BKBK%4FQ9aF83")QCL*h*bFL&Q)
+Q%KCA&44'&K*LF@3A)5%@&a8K)5)@3KB8)@%LF8*L*Q%@&h&&-@%Q*aCfCb)L)4*
+#*MGK%4*LCQ95GRC"35*LB5)L%L%aFLBA)A&b&@Gh)4*5)4F44"GKCPFL*f&hFQB
+4&R&Q%LBK*hF5GLBK&b&R)LB5*534FACKF@GfFK)LF9BN)4%QBKBL&h*fCK8LBRF
+KCK)K3@Gd*f*9*fCKGb)KBL%K%54@*#CK&bGb*@)RFKCRBL*b)K34)P)QB9FR)Q%
+A*hGa&8)R)Q)8*LFL)4GKGb)RC5*K*Q*K)Q)5%M4LF5Gd3R9N*h)QN!4KB5%5*hC
+f)6F89f*4)@*hF5%M84FLGb-QFR*e99%LB5CRB4*f%NGN8K9#Gf&h*RF5%@BN*Q)
+L4"C')K&84")MBQ%5!5)@)L)R%@)K%R%ABQFRCA9(*8-4FK4b&9*8B5%L*#CdF53
+5)4%R*h&")R&K*h&a)LFP-4Ca9#GQ9$33FLFR%f)5%L%@%4)RCd%5)AGa8KB9BL4
+%-435BK45&`%9BR*M4NGh)4%8%K)@44BA)L)5%4&R&&38FK%A)QCQF94#*9944a%
+L&K%4CR34CaC@*R%4BLF5GK*LF@%A)R*f9R8!84F4)8)Q%5CbCR)Q)4G&4bGK%LB
+L3R)4&&)LGQGb%e4aFAF4"'BRBA%L%5BK&e&KCa%@CK%@)4%84b*PGbG%4#*Q*#*
+%4'F4)5CaCQBLF4*"FA35)4%KBA8@&RFQ&P8%Gf&R&R3"FLGb&hFK%K864#*Q)Q%
+R%5*K%5%4GLB598B4)Q)4*f)R*LBLBLB54P0%GL*aF4-LFKB4N!-KB4%M4"%5BR%
+54#GaB4G@GQ)L88!5GbC"Ch&QFL)4G#9"44%Q&h*bB4)8Cb&K&f4hCL)L85)KF8)
+Q%RBKCh)8)K35FL)LFLBLF50L*QB4FQ)L4#*a&b*aCRCR%4BAF4!AFL*L%5&%4#8
+5FRGf%@*RChBN%8)ACf*b*KCbBL*aC%GbGLB4)83d%d&4*L*LFM%Q8K&#G(FQ*Q)
+R)A&LCLC4!QGbGR)L384N4K*%*N&"&a%N&%*N3Q%QBQ)QC(FR)435)d)Q&Q*d%A%
+5ChG"FL4bFQ)4Cf)@*L*4*%B93Q%Q&%)P"hCQCLFLC6)R)44"%6*b%N%hB@Ga!K3
+K%9%A&(BQCR*L"N)P84)N&KB4&%3N45FL-8CQCL9")5*P%@%LCK)R45%8&#C8%KG
+QGK8434*"*')4BKCQ%NBL3A&8)LCQ&dF53Q*@3K-bGK*4GK9(-4BAB5GfCT!$*QC
+LC%*K*QCA%L4(*QC%)R)@F63b*LBa%4)@B5CQCe%QBQBK)K&RBP*L*KGb)K-P"aF
+4*4)5*b&%GQD3!f)KB4)QGf*b%5*LF5&K*RCR3"%Q%90P38GRBN*QCP*Q&fBL4LG
+a)L*hGf)KCb)5CK%@Gf*R&L&#%83L*bCK*#)5B"*&B4&R)L)R*e&#Cb*(3K*#GK%
+L%a)P%aF43L%8%K3K*4853QGa*hFQC4&N)Q&L&R*KF4BL*fBd&L8$8Q*c%!&f%a%
+L)N)P3LCL)5C'F83%4#F8*Q%KF488C4&"*f493(*f)8%5G4*$%4&fCKC`4!#3"`F
+!!2q3"J!"QC!'!!*QN!B!!pf3"J!%Zj!'!!@UN!B!"RH3"J!(4*!'!!!4$J!"!*!
+$(!#3!di!N!6rr`#3%)"!!*!&3!"!!*!*5!#3!dJ!N!8)!!%!#!#3"K"1!*!%#43
+9&!Q3"43-#438%38&%4%&N!36&Im1r`lr$JN&%C!'"4)*$!i,$!@3!a)'%`N8#a8
+5"4-*N!F8#C!'&"@3!`8'%C!&"C!$%K)6"`N8ra8(""'3"!84"4)*&Im-$4%&N!-
+5%`N9&3i*%K)*N!B8#C!(&!`1r`88%C!'"385%a)6#485"385%a'3"!8&%a39r`i
+9%K%&"4)6&"6r&3N&%K-*N!89#3N8#C!%&!crra),%C!'"385%a-8&!@3"")*"4%
+4"385#431$K81&"%4"3B*#3`2&"+3"!Q3"")8#C!(&"Arr`B8"4%&N!85%K-*#K%
+&N!8'#4%&N!-6&"81#a8-%`88"4)*&3i9%T!$"JN6%`8&%K3*N!F9&Im,#43*%38
+5"4)5%`N8&384N!3&"4)*%J85#439$K8-$48("!N$"3S1&!@3!`B6&383%386&!N
+*%a-*N!-9$!`8$!N&N!35%JN*&!`&%3-4%3@3""-8&"81&488&"8-&!B!%K!&&!i
+&N!85&"3%"388&")6#3J*#439$Im9#4%&%JB6%a39#3F5%C!("3B6&3crN!-&"4)
+'#43%""%$"438"3B&N!35&436#4Ar%JB*N!-8#C!$&3i&N!-5"K-(%`N9#`N4%"!
+4N!-&N!-5&3i-rrm&"4)6#3N8"J-3"3N8%4-&N!3'#Im,#4Ar&!F*N!-(%J8&"K3
+5%385%JB5%JN8&Im8%3-4N!3&"3N9N!-1r`8&%K)(#3N'!a!&#3X&%J@3"3N-"4%
+*rj!$&3N5"K'3!`86#4%&%38&%K)6#46r$K33%"'3!`8&#4@3"2m&N!-'%K)*&"!
+$"431"C!$%3@3!`F8"4%*$[m-#3N&"4'3!`8'#4'3!`@3!a)5#439r``&%C!%"38
+*$"@3!`i5"385N!-6&!83"48,"4%&N!85#384#Im9%`B&"4%3%"%&"3S&%C!%"C!
+$%JN8r`i0%4!4"386$!i8%aAr#38'"3B5%JN*%3B9&!83"C!&%K3&%3N8"33&&2m
+&%"%3%388#4'3"!8&%JN*&"Ar&3N4%385&3i*"K)9ra35%J85"K)(&"%5#a8&%3@
+3!`B5#435"4-&%C!$%`i-"3-3"388ra)4N!-&N!-(#439$[m1%`8&"`N5"38($!i
+9%`B&"4)'#3`&"`N5"K)&N!-5"JN8%J85#384""%8$"33%4%5&2m9"C!&%K-8&3m
+9$[m*"385N!88$[m1&4)&"3B5#Im*"C!$%K-,#38%"`N8"C!%%a)4%3B,$4)4"3B
+0r``8"C!%%JN8&C!$$!N4"C!%%T!%&2q3!a8&%385$434"C!%"JN9!33-#4%&N!3
+5#4%4"3N9$K-&#481&38&#"3)%a-9&3N*&"%&%38&%K)'%K)*&Im-#4%4"385&"3
+&N!35#3X"""34%3@3"")*"4%4#3i-&4-8$JX&N!-'#K8&%C!$"3B5%"%&"4)'%T!
+%%a6r$K34N!-&"3B9&!@3!a)6&")*"4%&N!B*"4%&&!`9&3d9ra)4"385#3N4N!3
+&%`83%3@3!a+3!`B6%a39&434%4!&N!-*$4)'%K)6&!S&%384"C!%%K-6%388$[m
+9r``9%4%&"4)*#4%%%4%&#4%3%4%&%T!&"K)8$`i*%C!$"385%K39%K)6#438%"%
+&N!B5%`N4"KArN!-1$")4%!8&%JF*%C!$"3B8%C!$"385N!3'%JN*&3i6%4%$%4%
+&%JN1&!B6#485%4%&N!85%JN*"46r$Jcrr`N3%4%&N!-*#K)4%3B+#a'3!`8&"K+
+3""-*&!i-"4'3"!8&%JN0&3J5#434N!-&N!85%JQ3!`lrN!--#4'3"!@3!`N8"`8
+5#3`-"4%4"385N!-6%JN*&2m9%3-4""'3!`86&C!$%K36%"%&N!85"3B8#439$[r
+r%a!$""'3"!8*&485#48-#4'3!`8&%T!$%a)6#48-#4!4%384%38&%K39&43+%!3
+4"C!&%K)(&!84%Jcr&!85%K'3"!8&#43-#4)$#3N&%4%&"4)5%a)6#4Ar&")3%"'
+3!`@3!`B8r`i-#4!$"C!(%K3*"386&2q3!a3*&!84%38&#489%`8$"3S5%4%&"4)
+5%a-*#Im1&4'3"`8&%K6r$K8*%"%&N!B5%`N4%386&3X8%J@3!`B8&!N5#489%J-
+%"4)*%J8&%T!$%`N*&3i-&!-4N!B&"4)9&4-'#3N4%3@3"4)*"4%4%a6r#3@3"4)
+5&"@3"!8#"4'3!`8'#488#4-6#481$[m8""!3%C!%"386&435N!-*#4%&N!3'#4-
+4%4-9&"%4"C!&%JB(&"@3!`3$%4!3%4%&"K-8$"88&Im9#C!%%C!&"385#3i5"4)
+5%a8)"38'%JN6%38*ra)3%3@3"a)5#"6r&433%!-3N!-4"38*&"81rrm9#3J(#3N
+4N!8&%K3*"C!$%K)*&4)&"4-*"JN9ra3#%"%&N!-5"C!%%K)*&480%K%3N!84"38
+*&Iq3!``8#3N6#434N!-&"K3*"C!%%K)*ra85#435%`N*$!N#!a%&N!-5"4)&%T!
+$%a39&3N4%3-3%4!4%38&&"Ar$J`9&43(%a6r&"-*&"-4%3@3"")6#`i8%a)&"4)
+5&"3#%"%&N!J'%K)*&3lr"4'3"`85#46r$J`9N!-6%`N1rrm6%`N4%3@3"4-9&4)
+5"C!%%K-8!K!3"C!'%T!&#4@3!a3&%38&%C!$"3B*&3i-&C!$$JB6#Im8"385&!N
+4"384"385&"35"4%&"4)&%JN4%"%4"C!&%J85N!-6&3`8#4)'%J8&%38&%K39r`i
+-&48*%a-8#38&%K)6&"34"4%&"4)9%`84"385N!36#4!$%4%&N!B5%JB*$43&N!3
+5%K-&"4)*&2rr$J`8#")6%`N&"4+3!`J*&4-4"4%&%K35%4%&"4+3"!B8%K!4%3@
+3"4)5"K)*&4)4N!3%"38*&!N8$!lr&")'%a)6%K%&N!-5N!-6#484%38&#3N&%4%
+&"4)5"JB5#484%"%&%3@3""+3!`N9%K!4%"%$%!8&#Irr$J`1&!85N!-*"4%&N!-
+5"K)6#436"38'&!8&%4%&"4+3!`B6#488!a%4"C!&%K)*&!i&%C!%%"!4%JIr$!i
+9&3i*%K)6#4%4"C!$%T!$"JN8&3N5&384"384"385"K)6%JN9$")4N!3&%J85"a6
+rr`84%334%"!&"3F9r`i9#481%a)(%a!4"C!$%T!$"K-*$2m-$K%&N!-4"385N!-
+6%JN9$K85%3@3"")6&2m1ra)4!a%3%"%&"3N9&3i*"JVrra38#4%&N!-5"4+3!a-
+8r`lr$!N&%3@3""+3!a-6#43-&3`9%J8&%a-*#439$!N%%C!&"4)*&Im*"4)*&3l
+rra33%3@3""+3!a-*$[m1&48&N!B5"K)5#3N9$K81rj!$&!@3!a)*&"31"4'3!`3
+4"4)+ra8&"4)*$"89$"83%3@3"4)5%`Rr$K3)#43&N!85%JF)#439$K8-$J`*"38
+4"3B*#439#4'3"!8'#489"4%&"JN9$K88r`84%38&%JB5%K-*&3i*%`N8%a%&%T!
+%%`N*&"@3!rm1%`84%38'%K-*#4Ar"J@3!`B*$"34"!8&%JN1$!N6#`N4N!-&"4)
+5%a-8$K85%K-*&!85%K-5%`Q3!a89$K89%K'3"!85N!-6#489&!B&"JN9&4)4%38
+&%K3-&")'&2m5%3@3!a)5%`N8&3N5N!-6#486%K13!a)'"4)8&!i&N!-4"C!$"K)
+5%`N*"4%&%T!$"JN8$K)&"3Ir$385%JN9ra)4"385%JN*&43&%T!%#43-%a-8#4%
+4"3B*$!d4%3@3"")'%JB6%K%4"3B&"4)'%`N8$4)5&2m*"C!$%``1$JN&"3B6#"8
+9"C!&"K)*&38&%K%&"JN8$2m8%"!4%38'%T!&%4%&N!35N!-'"JN9&3Rrr`@3!a)
+5&!i9"`8&%a3-%K%4"4%&N!-'"a34"C!&%K)*&"33%4%&"4)5%a-'"4!4"4%&N!-
+5N!-6%`RrN!35"C!$%K6r%K!4"4)*&"84N!-&N!35#43&%3@3"4)'%a3'%4%&%K-
+*#4-'%4!4"C!'%JB5%JN9rrm1#3@3!a)*&!-3"C!$%JN8&"%4"4%&"3B(&"-&N!F
+'%K-8#38&"JN8#3F6!a!3%3@3"K)'%JN9rj!$$!@3!`B8"4!3%38&"K-8&384"38
+4"4)6&!i&"4%4"C!$%J85%K8*"3B8&!N6%`)$%"%&N!-5"C!$%K)*&!i9%K-8&"-
+5#3-3%4%&"4)(#438%3@3"!B*$!`5"C!$%4%&N!3'#3`*#438#3S*!K!4%3@3"JB
+&"JN8$"3&"4-8&C!$%"!4"C!$%K-*&"8'"C!%%K3*&")&%C!'"385#3i-&488#`N
+5!K!4%3@3!a)&"K+3!`N8$K-&N!-6&481#3-4%38&"K)6&"Ar#385%a-5#3N6%C!
+("385#480$"89#4)&!J)$%3@3!a)&%T!$#3N,$J84"38'#3lr$!84"C!$%K)*&"6
+r&4)5"K13!`Q3!a%&"4%4"C!$%JN9&3lr&3@3!`-!%"%%"385"4)5%`J*&484%3@
+3!a-8ra88%38&"K)5%`N8r`N5%K-6#C!%&4)4N!-&%38&%a3-&3`9%K%&"4%!!J-
+4%3@3!a+3!a-8&434N!-&"4)8r``9%`8&%JB5#!N8&4+3!a13!`Q3!a38%C!%"38
+5#4@3!`i5%4%&%38!!K%3%3@3!a)5%`N8$!N4N!3&"JN1&488"C!$%K)6#43-%J8
+'%`Q3"439%4%%%385#3X1#a36!K%&N!34!J-3!`84"3B6#439&384%"%4"4)*r``
+9&4)&"4)5%`N8&4)&%K-*N!B9"4%4"JN8$!i9#433%"%4"4%4%K)3!`-4N!-&%`N
+9$JN4%4!4%385#3`9N!-'"385%K-*#485"4)6#C!&&"35%3B*#439&385"K3&N!3
+4"385#4%$%3-4"3B8&3N4N!8&"4)6$!i9&4-&"4)'%`N8&!8&%K)6#C!&&43&#C!
+%&!`*"3N1%a%&N!B5&43'"38(&3i1%a'3"J8&#3`9N!-'"C!$%JF*&"3+"4)5#C!
+&!*!(&J!!c-bCN!3!!Fc-QCPQCJ!#QC!'!!1CN!4QCJ!%QCPQN!3!"@D3"J!'CT!
+%-c-!"fCQ-j!%!!Jc-fCQ-c-!#613"J!+-j!%!*!$#b)L!*!&$"%4!*!&$3!!)L)
+!N!-1!!!4%3#3!`m!N!34%3!3L*!'!"&hN!B!%P@3"J!64*!'!"3LN!B!&4'3"J$
+r!*!)!3#3!mRS!!$)k!!!"r`$XkJd!hS!N!-F"TB!&eG*6N3!"`$#9%e36!!"!5*
+1G@e`!!%"1N&-8P3!!`&54%P86!!%!B*69&)M!"%"[QPMFc3!"!+@D@0c)`!%!Y*
+*3diM!!3$$QPME$3!"!0+4%a24`!!!iC'6dj8!!8$NNC26N3!!J2D3e958`!)!rj
+ZD$-a!!!%DNC548B!"!4f3Nj%6!!!",*048j9!"-%[Ne195-!!3@Z8e45)!!!"FC
+NBh4L!!!&dQPMG')!!!AHB@0dBJ!$"HT`F'&d!!F''J#!!#d!N!0i!*!&J3#3#i)
+!#!#3!b!!N!@$!!m!N!2H!*!&K!!A!*!$3!#3"B8!(!#3!eS!N!@'!#%!!!%#!*!
+&K`"f!!!jh!#3"B!!-J#3!ji!N!@"!2d!!%h1!*!&J!!h!!!LkJ#3"B%!33!!)`3
+!N!@"rrmJ!!MJ!l1Qf!#!rrm!!%lQ!l1PV"1)!58!!%li!l1Q%"1*!6%!!%*4!l1
+Pm!#"rrmJ!!M`!l1PK!#!rrm!!!b-!l1QB"1)rrm!!%jQ!l1QL"1*rrm!!%kH!l1
+PZ"G`rrm!!&+%!l1P[!#!!'JJ!!%Q!l1Q,!#$!*%!!%Z4!l1P(!#%!*8!!%iG!l1
+Pi!#&!*S!!%im!l1Pr!#'!4%!!&#2!l1Pj!#(!*m!!%pQ!l1Pf!#)!+-!!&"G!l1
+PJ!#*!+N!!%m+!l1Q0!$*!+i!!%`P!l1QR!$+!,X!!%b1!l1Rk!$,!-F!!%bd!l1
+PM!$-!0!!!%cD!l1Q2!$0!0B!!%ck!l1PX!$1!0`!!%dD!l1PD!$2!1)!!%dk!l1
+Q"!$3!1J!!%eD!l1PT!$)!1i!!%ed!l14Y!$4!28!!%fk!l1Q)!2Srrm!!!&!!*!
+%!qRrr`!!!F3!N!3$k[rr!!!-XJ#3"!2VrrmJ!$Sk!*!%!qcrrb!!1Vi!N!3$k2r
+r!!!#5!#3"!2Trrm!!!+-!*!%!qVrr`!!#N3!N!3$krrr)!!l3J#3"!2XrrmJ!$Z
+'!*!%!qMrr`!!!Y!!N!3$kIrr!!!$e!#3"!2Urrm!!!P!!*!%!q[rrb!!1mS!N!3
+$l2rr)!!mcJ#3"!2Srrm!!!6B!*!%!qRrr`!!"Y`!N!3$k[rr!!!+L!#3"!2Vrrm
+J!$h5!*!%!qcrrb!!2pB!N!3AF!%A!!"4rJ1cT0",LIrr)!!00J1cTe4,M2rr!!!
+@`J1cTe"-$!"G)!!X+J1cTda-LIrr)!"GRJ1cTdK-M2rr!!"R+J1cTd4-#3&C)!!
+MC!1cTd!!P`"*"!!LT!1cTc`!Q!"5"!!M(J1cTcJ!Q3&0"!"G@!1cTc3#!2rr)!!
+j"!#3"!)$rrmJ!$P-!*!%!J6rrb!!1C3!N!3#"Irr)!!h9!#3"!)(rrmJ!$HF!*!
+%!J(rrb!!0q3!N!3#"[rr)!!i,!#3"!))rrmJ!$Kd!*!%!J,rrb!!1,`!N!Errb!
+!1J#3"S$rrb!!3GS!N!@"rrmJ!%(P!*!&J[rr)!""m!#3"B2rrb!!3IX!N!@%rrm
+J!%)'!*!&J2rr)!"#%3#3"B(rr`!!3Q-!N!@#rrm!!%,X!*!&Jrrr!!"$1!#3"B6
+rr`!!3qJ!N!@!rrm!!%4I!*!&KIrr!!"%M3#3"BErr`!!808!N!@(rrm!!%qp!*!
+&L2rr!!"&9`#3"BRrr`!!4K3!N!A+rrm!!%E2!*!&brrr!!"(AJ#3"Fcrr`!!4pS
+!N!A0rrm!!%K"!*!&c[rr!!")U!#3"Frrr`!!53m!N!A*rrm!!%Pf!*!&d2rr!!"
+*j!#3"FMrr`!!5MN!N!A4rrm!!%V1!*!&J!#"&!",-31cT0J!J3#*&!",B31cT53
+!J!%#!!"26J1cT5`AF!%I!!"4bJ1cTG!AF2rr!!"5,!#3""1)!6N!!&1f!l1QG"1
+*!88!!&2U!l1Qa!#!rrm!!&3H!l1Ph!#"rrm!!&45!l1N%!#!rrm!!&5'!*!&J[r
+r!!"c+J#3"B(rr`!!K&3!N!@$rrm!!)d@!*!&K2rr!!#H-!#3"BArr`!!TVS!N!@
+'rrm!!+mm!*!&Krrr!!#heJ#3"!G0CA0cB@GP"P0dBA4eF`G%G@jRC@pZ"%ePER8
+%9'9iG!Y%D@&REQpcG'PMF`4198a-"%jeEA!*9@jcD'PQG'9N"e0SD@CdC@3)5'&
+MDdC[ER3+8&0)B@0V4QpZG!T38dKKBfY'Efjd$8eTFf-Z)&0dFQPZCh-+9&4C)&G
+TEQ4[G`GYC@jeBQ&b"h0eBQePER8$5f*N"%KPE(!%5@jQE`0"Bh3&6@&RD@-%3QP
+dF`aMEfjdFQpX)'YPHA-,F(9ZBh4eBA4TEfi)BR*KBfYPG(-&B5!Y)'d&EL!Y)(S
+&35!Y)%d&6L!Y)&S&-#!Y)$N'GfPkBA*N"f0eFR*PER3%68j9)`j3FQ9Q)%CTE'8
+J6Q&YC39&FA9TF!GKFfYZB@eP"90dBA*d#d&LEh9d,f9bFQpb"d0[EQCTFQd,3@*
+[GA3[CA*bEh)(3fpZCQPbE3Y1CAG)B@0V4QpZG!a38dKKBfY'Efjd)$Q6)`:
diff --git a/sys/mac/NHsound.hqx b/sys/mac/NHsound.hqx
new file mode 100644 (file)
index 0000000..f0cebe9
--- /dev/null
@@ -0,0 +1,4197 @@
+(This file must be converted with BinHex 4.0)
+
+:#e0[G@jNFbjbFh*M!(*cFQ058d9%!!!!!!!!!!-,a@BE!!!!!!%!!!-+K!!$#B3
+!!!&"!!!"MJ!)Tc`pR`!!$rF!!!'1!!LR2$fI!!!2q!!!!Bi,8fpeEQ4c,R*cFQ-
+#!!!!FR0bBe*6483"!2rrrrm!!!!!FR0bBe*6483"!2rrrrm!!!!!!!!!!!!!!!!
+!!!!!$hQR2DiI!!!!!!!$#m83X3!!!C8!#+Fm2eJ!!"$"!!!"P3!)Tc`r@!!!%-3
+!!!'9!!LR2$q"!!!3e!!!!C8!#+Fm2kX!!"$P!!!"P3!)Tc`rd!!!%2X!!!'1!!L
+R2$rR!!!4"`!!!Bi!#+Fm2qJ!!"%)!!!"S!!)Tc`rlJ!!%3d!!!'J!!LR2%!"!!!
+4(3!!!!!h3!!"!!%!"3!!!+!!!B"4!!!!!!!8!!!!!!!!0aC@lSZM!!!h&!!!0a8
+!2)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#
+!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIi#!JB+$Ji5&KBD'KSD'KB@%K)1
+#JS'"J)"rIhprIhprIhprJ)#!J)'"JB+#JS1$Ji1$Ji+#JS+#JS'"J)"rIhjpIAY
+kHAGfG(0aF'p[EQp[F(*cGRKlIB#%KSL,MBq3!*!!N!#3!)q0M)Z*L)D%Ji'!Ihj
+qIAepIAepIAepIRjrIi#"JB+$K)5&KB@&KB@&KB@%Ji1#JB"rIRelHAGeFR"YDfP
+RC@9PC@GTE("dHAf#KSU1NT@AQ*QBPjD8NBq-LSL'K)+!IhemI(YlHhYlHhYmI(e
+pIRq!JB1$K)5&KBD'KiL)LBQ)KiD%Ji&rIAYjGR*ZDQ9KA9YC9eGC@ejMD'jeHi+
+)MT5CR*qKSU'JRTbCPT12M)U(KB1"IhjmHhTkHRTkHRTkHhYmIAk!JB+$K)@'KiL
+)LBU,LiZ+LBL'KB1"IRYiG'pUC9pD9P*26Np38eGEB@CYG(Z%M*1DS+5SUUUUU+@
+LRTZANiq-LBD$JAppI(YkHRTjHAPkHRYmIAk!JB+$Ji5%KBD(L)Q*LSU+LBL(KS@
+$J(ekGR&XCf&E99&058P*5de499YLDA*lKBkAS+HXX,+bXDqVTk1HQC@4MBQ'Ji"
+qI(YkHAPjH(KiHAPkI(erJ)'#JS1%KBD(L)Q,M)f0MBb+LBL'K)&qHR9aDQ0G9e&
+,4d0"3%*%5%e8A'9[HSD4R+DZY,LkZVLeX+ZQSCZ@NSf*KB*rIAYkHAKhGhGhGhK
+iHAYmIS#"JS+$K)@(L)Q+Lib-M)Z+LBL(KS1!IAKcE@CI9e")3cik1$Sm38K4@Q9
+[HiH5RUH`YVUm[,UhXkfSSTfBNiq,Ki5!IRakHAKiGhGhGhGiHATmIRq!JB+%KBD
+)LBZ0MSq3!)q1MBZ+L)5!I(KcE@CI9Nj(3$Se-M%c0Me&8&aTGiD9SUki[m2&a-+
+qZ,+VTCqCP)q,Ki5"IRakHAKhGhGhGhKjHAYpIRq!JB'#Ji5&KiL+Lib0MBf-M)Z
++L)@"IAGbDf4E8da%2MJc-#ma0$T#6PYVHiZEUVDraFR+b-5rZ,'USjfANBf*KB+
+!IRalHRPjHAKiHAPkHhapIRjrIi#!JB+$KBD(LBU,M)b,LiZ+L)@#IRPcE'9F98a
+&2MJc-#ma0$T#6PYVI)kHVER"amV+b-1pYUkRS*U8MiZ)KB+!IhjpI(amHhYlHha
+mIAeqIRjqIRjqIRq!JB1&KiQ+Lib0MBf-LSH%J(aeEQCH98j(3$Sd-6!`-MBq5&C
+RHBZGVEV%bXh0bX@qYkqQRjQ6MSU'K)+!IhjpIAamI(amI(amIAeqIRjpIAepIRj
+rJB+%KSL*LBU+LSU*L)D%JAeiF@TM@P0-4$ik0cBf1$Y#5P9NG)@@TE+ma-M*am1
+qYkqSS*U8MiZ)KB+!IhjqIAepIAamI(apIAjqIRjqIRjqIRq!JS1&KSH)LBU,LiZ
+*L)D$IhTdE'9F98a%2MJc-$!a0$Y%8@&cKCHSYX()c-h,am#jX+QJQT51LSD$JB"
+rIRjpIAepIAjqIRprJ)"rIhjqIRjqIRq"JS5'KiL)LBQ+LBL(KB0rHR9ZCejA6dK
+!1M8a-$!b0Mj+@@TqND1c`-M1d-r,a,bdUk+EP)q,Ki5#JB"rIhjqIRjqIRjqIhp
+rJ)"rIhjqIAepIAk!JS1&KiL+Lib-LiU)KB*pH(&UBeT66%3q1$-`,c!b0d"0AA#
+&QDZkaXl4dXr+`lU`TjqANBb)KB1"J)"rIhprIhprIhq!J)'"JB"rIhjpI(amI(j
+rJB1&KSL*LSZ-M)U)KB&pH(&UBPY66%8r163a-$!b0d"-AA''Qkfmb-r6dp$*`VQ
+[TTf@N!#,Ki5$JB#!J(prIhpqIRjrIhq!J)"rIhjqIAepIAeqJ)'$KBD(L)Q*LSQ
+)Ki@$IhTcE'4G98j'3$Xh0$-d0MY$6Pe[JjDSYm2,cp(1bF+jX+HIPj'-L)@$JS'
+!J(prIhjqIRjqIhq!J)#!IhjqIAepIAjrJ)+$KBD(KiL*LSU+LBH%J(YdE'9F8da
+$2$Bb,bi[-MP%8Q4iMD#b[mR2dY(0alkfV+1EP)k+KS5#JB"rIRjqIRjqIRjrIi#
+"JB'!IhpqIRepIAjrJB1&KiQ+LSZ,LiQ)KS5!Hh9ZCej@688q0c%Y+b`[0$j,@fq
+&QUbmamr6dp$+`lU`TjkANBb)KB1"J(prIRjqIRjqIRprIi#!JB'!IhpqIAepIAk
+!JB1&KiL)LBU,LSU)KS5!HR4XC&e86%-m0M!X+bd`06p-AR1*RDqqbY(8e0$*`VL
+[TTf@N!#,Ki@$JS'!IhpqIRjqIRjqIhq!J)'"J(prIRepIAeqJ)+%KSH*LSZ,LiZ
++L)H%J(YdE@4F8da$2$Ba,LdY,c3q5eaaKjb[[mV5eGA4bX+iVk@FPC!!LiH&Ji+
+"J(prIRjqIRjqIRjqIi#!J(prIRepIAepIS#"Ji@'L)Q+LSZ,LiU*KS0pGfpRAPC
+046dh-LiX,#ic2%PDES5CV,c)d069dF[$ZV#RRjH4MBQ'K)+"J(prIRjqIRjqIRj
+qIhprJ(prIRepIAeqIS#"Ji@(L)Q+LSU,LiU)KB*qH(&SB&G24cmi-LmY,M!f2NY
+FEi5BUVR&cG$4cXR#ZE#SRjL5MSU(KB1"J(pqIRjpIAepIRjqIRprJ)"rIhjqIAj
+qIRq"Ji@(LBZ-M)f-LiU)KB&pGQpQA94,3cXd,LXU+bmf3%pKGSZIX,l*cp,4cXM
+!YkqQRTL5MBU(K)+!IhjpIAepIAepIAeqIRprIhprIRepIAeqIi##K)D)LSU,Lib
+,LiQ(KB&mG@jPA94,3MNb,#NS+5`d3&"MHBqMYF2-dY66cXHrYUfNRCD4MBQ(KB1
+"J(pqIAepIAepIAeqIRprIhprIRepI(epIS##Ji@(LBU,M)f0MBb+Ki0qGfpQA94
+,3MNb,#JQ*LNa2%aKH)kMYF20dpA8cmLrYUfNR*D4MBQ(KB1"J(pqIAepIAepIAe
+qIRjrIhpqIAamI(apIRq!JS5'L)U,M)f0MBZ*KS0rHR0UBPP35$mi-LiU+5S[1%C
+BES@DVEh)d026d-R#ZE#RS*Q6MiZ*Ki5#JApqIAepI(amI(apIAjqIRpqIRepIAe
+pIS#"JS5'L)U,Lib-M)b+L)5!Hh9YCPe85d-m0M%Z,5ia1846CRZ2SV2!bFr3cm[
+%Zl5XSjfANSk,L)D%JS"qIAemI(amI(amI(amIAepIAemI(apIi##K)D)LBZ-M)b
+,LiZ+Ki5"I(C[Cej@6N8q0M%Y+b`[0N&3C(Q1SV2!bY$4d-c&[,@XT*kBNiq-L)D
+%JApqIAamHhYlHhYlI(amIAepIAemI(epIS##K)D(L)U,M)b-M)Z+Ki5"I(G`D&p
+@683l05mV+LSY08"3CAU2Sl6"bp$5dFc&[V@YTCqCP*!!M)Q'Ji&rIRemHhYlHhY
+lHhYmI(apIAamI(amIAk!JB1&KiQ+M)b0MBf-LiQ'JhjiF@TK9dj&2$8[+LJR+M%
+m6'&hMD'c`F[4dp,0aVqfVUDJQT53!)f+Ki5"IhjmI(YlHhYlHhamI(apIAemI(Y
+lHhapIS##K)D*Lib0MSf0M)Z)KB*rHR0VBPP35$mi-5dU+5X`1NPFFBHEVEc)cY(
+4cXM"Z+qSSCZ@NSk,L)D$JApqIAamI(alHhYlHhYlI(amHhYlHhYpIS#"Ji@(LBU
+-MBk1MSf-LBD#IRG`D&p@683l0#mV+5JV-Mj3CAZ4TEE$c0,6dFc&[,@XTCkCPC'
+0LSH%JAppI(YlHRTkHRTkHRYlI(amI(alHhYmIRq"JS5'L)U-MSk0MBf-LBD$IRP
+bDQ&C8%K"1cBa,LdZ-Ma+A('(QkflaXh3d-h(`,H`U++FPj12LiL&JS"qIAalHRT
+kHAPjHAPkHRYlHhYlI(apIi##K)D)LBZ-MBf0MBf,LBH$IhTcDf0D8%Fq0c%X+#F
+U-$Y+AR5+RV#qb-r5dFl)`EQ`UD+FPj12LiH&JAppI(YkHRTkHRTkHAPjHAPjHRP
+jHRYmIS'$KBH*LSZ-M)b,LiU*L)@#IhTdE@CG98a%2$Fa,5XV,MC%9QZ"PUQjaFh
+4dXr+`lbcUk@IQC@4MBU'K)&qIAYkHAPjHAPjHAPjHATkHRTkHRYmIAq"Ji@(LBZ
+0MSk0MBb,LBH%JAefEQGH98a$1c8[+bJR+M*!8fQ!PUUlb0$8e0(-aEfdV+@HQC@
+4MBQ'Ji"qIAYkHRTkHRTkHRTkHRTkHRTjHATlI(k!JS5&KiL*Lib0MSf0MBZ)KB&
+mG@aN@e*)2cJa+bFP*b`h4eadLk'c`Xc5eG22b-'iVkLLR*H6MiZ)K)+!IRalHRP
+jHAPjHAPjHRTlHhTkHRTkHherJB1%KSL+M)f1MSk0M)Z)KB*pGh"RAP904$`e,bS
+Q*LSc399XJjQX[-M3e064bm5mXkbPRjQ8N!#-L)@#IhemHhTkHAPjHAKiH(KjHAT
+jHAPjHRYmIS'$KBH)LSb0MSk1MSf-LBD$IRPbDQ&B6N8m0#iS*#-Q,ce4DB#AUl[
+)d069dXc&[E5XTCkCP*!!M)Q&JRppHhTjHAPjHAPjHAPkHRYlHhYkHRTlI(erJB1
+&L)U-MBk1Mik0M)U'JRjiF@TK@%p(2cJb,#JR+#ml6'*jN!#NYX61dp66cXHqYkk
+RSCZ@NSk+KS1!IRalHRPjHAKiH(KiH(PjHRTkHATkHhaqJ)+%KSH*Lif0MSk1MBf
+,L)@"Hh4XBeT458!j-L`S*LFY1%PHGBbKXm,0dp66cmM"Z,#SSCbANSk,Ki1"IRa
+lHRPjHATkHAPjHATkHRTjHAKjHRYmIS##K)H*Lib0MSk0MBb,L)@#IAKaDQ&C8%F
+q0c!U*5-P,Me4DS1DVVr+dYE9dX[%Zl1VT*kBP*!!MBQ&JRppHhTjHAPjHAPjHAP
+kHRYlHhTkHRTmIAq!JS5&KiQ+Lib0MSk1MBU(K(pjFQYK@%p&2$3Y+#3M*Lim8'L
+!PkZmbG(9eG,-aEfdV+@IQC53!)b*KB*rIAakHRPjHATkHAPjHATkHRTjHAPkHha
+qJ)+%KBH*Lib0MBk1MSf+Ki@!HR0XBPP34cih,bSQ*#FZ1djNI*1RZ-E2e0A5cFD
+rYUfQS*U9NBf*KS1!IAYkHAPjHAPjHAPjHAPkHRTjHAPjHRaqJ)+$KBH*M)f1Mj!
+!Miq1M)Q&JAaeE@4E8NP!1$%V*L-N+M9(A(1-SV6$cY29e-r)`,H[Tk'EPT+1LSH
+%JAjmHhTjHATkHRTkHRTkHhYlHRTjHATlI(jrJB5'LBb0MSq2MSk0M)Q'JRehF'G
+I9Ne%2$3Z+#-L*Lmr9@k'RV,#cG6AeY(+`VQaU+'FPT+1LiH%J(jmHRPiH(PjHAT
+kHRTkHRTkHRTjHATlI(k!JS5'L)U-MSk2Miq1MBZ)K(pkFfYL@P&)2cF`+53L*5X
+j6'0mP+QlbG(@ep61alkeVD@IQC@4MBQ&JRppHhPiH(KiHAPjHAPjHATkHRTjHAP
+kHherJB5'L)Z0MSq2N!#3!*!!Mib*KS&mG@eN@e**3$Na+L3L)bJd4PaeMU5faFr
+9eYA3bF#hVkHKQjD4MBU'Ji"pHhTjH(PjHATkHRTkHRTlHRTjHAPkHherJB1&KiQ
+,M)b0MSk1MBb*KS*pGh"SAeC04$Xd,LJN)LBa3PKaLU#c`ml8eYA4bX+jX+QLR*H
+5MSZ(Ji&qI(TjH(KiH(KjHAPjHRTlHhTkHRTlI(erJ)+&KiQ,MBq3!*!!N!#3!)q
+0LSH$IRG`CPa658!i-#FI'aXJ,8&DG)kPZFM5f0R@dFV"Z+qRSCZ9NBf*KB*rIAY
+jH(KiHAPkHRYlHhYlHhYkHAKiHATmIS##K)D*Lif1MSk0MBb,LBD#IAKaD'"A6N8
+q0LmR)L%M,$a5E)@GXF(0e0I@dFV$ZV'TSTbANiq,L)5"IhelHRTkHRTkHRTkHRY
+lHhYkHAKiHATlIAq"Ji@(LBZ-MBk2Miq1M)Q&J(YdE'0D8NP!1$!R)4mJ*cC,C(q
+BVVr-e0MAe-h&[,1USjbANiq,L)@"IhelHRPjHRTkHRTkHRYlHhYkHAPjHATlIAq
+"Ji@)LSZ0MSq3!*!!N!#2MBU'JAaeE@4E8NJr0biP(KXE)M&(BAf@VF$0eGRCeFr
+([V@XT*kBNiq-L)5#IhelHRPjHAPkHRTlHhYlHhYlHRPiH(PkI(k!JS@(LSb0Mj!
+!NC'3!)q0LB@"Hh4YC&Y558!h,bJL(KdN-8GKHjDX[Xc8fGR9cXHqYDbNRTL8N!#
+-L)@#IhelHRPjHAPkHRTlHhYmI(alHRPjHAPkI(k!JS5(LSb0MSq2Miq0M)Q'JRe
+fEQCF8dT"1#mR)4XD)#j%ARU8Ull,eGRCeXr)[V@XT*fBNiq,L)5"IRakHAKiHAP
+kHRYlHhamI(amHRPjHAPlI(k!JS5'L)Z0MSq2N!#3!)q0LiL%IRG`CPa658!i,bB
+I'KNI,%&EGj+U[Fc9fY[AdFQrYUfNRCL6Mib)KB*rIAYkHAPjHRTlHhYlHhamI(Y
+kHAPiH(PlI(k"Ji@(LSb1Mj!!Miq2MSb*K(pjFQPJ9dj&263X*"iD(#Bi8Qf*SVI
+(dpREf02,`VL[TU#DPC'0LBD$J(jmHRPjHAPkHhYlHhYmI(amHhTjH(PjHherJS5
+'KiQ,MBk2Mj!!N!#2MBU'JAYcDf*C8%Bp05XL("FC)M41DiHKYmM6fYcDe-c$ZE#
+SS*U9NBf*KS+!IAYjH(KiHATkHhYmI(amI(alHRPjHATlIAq"Ji@)LSf3!*+6P*1
+5NBk+KB"jFQPI9Na#16%S)"N@'#-f8'b)SVI)e0[GfYA0a,UaU+'DPC'0LBD$Ihe
+lHRPjHATlI(amI(amI(alHRPiGhGiHRarJB5(LBb1N!#4NC'3!)q0LiL%J(PbD@"
+A6dBp05`N(4ND)M*,Ci1HY-E5fGcDe-h%ZV'SSCU9NBk+KS5"IRakHAPjHATlI(a
+mIAepIAalHAKiH(PkI(q"Ji@)LSb0Mj!!N!#4N!#2M)Q&JAYdE'*C8%Fq0biP(KN
+B(bp)C)'FXX64fGcEeXl&[,+TSTZ@NSk+KS5!IRakHAPjHRTlHhamI(apIAalHRT
+jHAPkHhf!JS5(LSb1Mj!!N!#3!)q1M)U(JRefE@9F8dT"16%R(KF8'5P"ARbBX-2
+5fYhFep$([E5VSjbANiq,L)5"IRakHAKiHAPkHhYmI(apIAemHhTjHAPkI(k!JS5
+'L)U-MBk2Miq2MBZ)K(piF'GG9%Y#16!R(KF9'LJr@hQ9VF$2f0cFf0()[V5VSjf
+ANiq-L)@#IhelHRPjHATkHhYlI(amI(amHhTjHAPkI(k!JS5(LSb1Miq2Miq2MSb
+*KB"jF@KH98Y#15mP("34&L3m@AH8VF(3fYlHfY2+`,DYTCkBNiq,L)5"IRakHAK
+iHAPkHhYmI(amI(amHhTjH(KjHhf!JS5(LSb1Mj!!NC+5NBq0LB@!HA"SAP9-3cS
+`*K`8%"-J0e4cND[!cpRHhYV6bX#fVD@HQ*12M)L&JRpmHRPiH(PkHhYmI(amI(a
+mI(YjH(KiHAYpIS#$KSQ-Mj'5Nj15NT!!MBU'J(PaCee658!f,#)A%!d6)caDHCD
+[`p,DhYhCdXLqY+ZMR*H5MSZ(KB&rIAYjHAPjHRYmI(epIAepIAemHRPiH(KkHhf
+!JS5(Lif2N!#4NC+4Mif+KS"jF@KI9Na$1M!Q("32%Kmf8h14UVr3fYrIfp6+`,H
+ZTCkBNiq-LB@#IhelHRPjHATkHhYmI(amI(amHhTiH(KjHRapJ)+&L)Z0Mj!!NC+
+6Nj'2M)L#I(9XBeT34cie,#)C%4!C+dCPK+#hbGAFhYc@cX5kXDQKQjD5MSU(Ji"
+pHhTjHAPjHRYmI(apIAepI(akHAKhH(PlIB#$KBL-MSq3!*'5NT+4MSZ(JhaeE'0
+D8NP"1#mP("88'LT$BAqEXXA5fYhEeXr&Zl+TSTb@NSk,Ki5"IRakHAKjHATlHha
+mI(apIAemHhTjH(KjHhaqJ)1'LSf2NC+6P*56NBk+KApiEf9F8NJr0LdM'K34&bB
+qA(UAVm,4fGhFf0()[V@XT*fBP*!!M)Q&JRpmHRPiH(PkHhYmI(alHhYlHhTjH(K
+iHAYpJ)1&L)U-MT!!NC+6Nj+3!)f*KB"jF'GH98Y"1#mQ(4B6&b8l9h@5UVl0ep[
+Ef0(*[lDYTCqCP*!!MBQ'JhppHhPiH(KjHRYlI(amI(amI(YkHRPkHhaqIi'$KBL
+,MBk2N!#4NT+4MSU'J(PaCej85d%i,L3C%Jm9*$aCGj5Y`G$ChGcBdFLqYDbNRTL
+8N!#-L)@#IhelHRPjHATlI(apIAepIAemHhTiH(KiHRaqJ)+%KiZ1N!#5NT16Nj'
+1LSD"HR&SAeG146`d+Km@%"%F-8eXLkDlc0MGhY[8c-+jX+HKQjD5MSU(Ji"pHhP
+iH(KjHATlHhamI(epIAakHAKiHATmIS#$KBH+M)k3!*'5Nj15N!#0LB4pGQePA&*
+*3$J[*4`@&"XU3PppQ,$$d0RFfpE2aVfcUk1GQ*52M)L&JAppHhTjHAPkHRYlHhY
+lHhamI(YkHAPjHRYpIi'$KSQ0Mj!!NT18P*+3!)f+KApiF'GH98a$1M!Q("33&#)
+k9hD6V-$2fGhGfG,*[lDYTCkCPC'0LB@#IhakHAKiH(PkHRTlHhTkHhYlHhTjHAT
+lIAq!JS5'L)Z0Mj'5Nj15N!#0LS@!HA*TAeC04$Xb+5!B&4FM1&0`M+5jbG6CfYI
+5bX'iVkHKQjD5MSU(Ji"pHhPiH(KiHATkHRTkHRTlHhTjHAKjHRYqJ)+%KiU0Mj'
+5Nj16NT!!MSZ(JRYdDf*B6N8l-LFG%`i4(643EifR[-c@fpcCdX["Z+qRS*U9NBk
++KS0rIATiGhGiHATlHhamI(amI(YlHRKiH(KkI(k!JiD*M)k3!*+6Nj15N!#1LiH
+"Hh4VBPP34cid+L!A%4%E,NTTKk1jbYEFhG[9cF5kXDLLR*H6MiZ(K)&qI(TjH(K
+jHATlHhYlHhYmHhYkHAKiHATmIS#$KSL,MT!!NC'5NT+4Mib*K(efEfCF8dP!0b`
+J&3d,&#P&C)1IYXR@h0lFeXr'[,1USjfANiq,L)5!IRYjH(KiHATlHhamI(amI(a
+lHRKhGhKjHRaqJ)1'LSk3!*'5Nj16NBq0LSD!HA"SAe9-3cN[*"J2#a!K1eTkPl(
+%dp[HhGM4alkeV+5HQ*53!)b)KB&rI(TjH(KjHATlHhamI(amI(akHAKiH(TlIAq
+"JiD)LSf2N!#4NC'4Mif+KS*lG'aM@P&)2c8V(a82%"Xb6fk-TV[-eY[FfG,+`EL
+[Tk#DPT+1LSD#IhakHAKhH(PkHhYlHhYlHhalHRPiH(KiHAYqJ)1'L)Z0Mj'5Nj1
+6NBk,Ki*mG@eN@e**3$BX)KJ4%"SZ5@L(SVM*e0[FfY6-`lUaU++FPT+1LiH$J(e
+lHAKiH(PkHhYlHhYlHhYlHRPiH(KjHherJB1'L)Z1N!#4NT16NT'2M)L%IACYC&Y
+45$id+4d5#`X@,%PTLD5lc0MHhpc9cX5lXUULR*D5MSU'JhppHhPhGhKiHATlI(a
+mI(amI(YjH(GhH(TmIS##KBH*M)q4NT58NT'2LiL$IRG[CPe656me+Ki6#`X9+NG
+RKk+jbpIGhY[@cF5kXDQLR*H5MSU(Ji&qHhPiH(KjHRYmI(amI(amHhTjH(GhGhP
+lIAq"JiD)Lik3!*+8P*58NSq,KS&kF@KH9%Y"0LSG%3F&$b4#C)5KZF[AhYrFeXr
+&Zl+USTbANSk,Ki5"IRYjH(KiHATlI(epIAemI(YlHAKhGhGiHRaqJ)1'LBf2NC1
+8P*56NBk+KB"jFQPJ9de%1M!M&``($4mj@RUBXXA8h0rHf0(([V5VSjfANiq,L)@
+#IhakHAKiH(PkHhamI(amI(alHRPhGhGiHAYpIi+&L)b2NC18P*58NBk+KS&kFQT
+K@%p'26-T(4)-$KXc8A'3!+UrcpRGhGV6bX#hVUDIQC@4MBQ'JhppHhPiH(PjHRY
+lI(amI(YlHhTjGhGhGhPlIAq#KBL-MT!!NT59PC55MiZ(JRefE@4E8dT#16!N'4%
+2&LP%C)5IYXR9fphEe-h%ZV'SSCZ@NSk+Ki5"IRYjH(KiHATkHhamI(amI(YlHRP
+iH(PkI(k!JS5'LSf2NC18PC56NBf*K(jhEfGH98a#15iM'!m-%L9!B)#FY-I8fpl
+Fep$([E5VT*fBNiq,Ki5"IAYjH(KiHATlI(amI(amHhTjH(GhGhKkI(k"Ji@)LSf
+2NC+6Nj+4MSZ)JhjhF'KI9dj&1c!N'!m,%L-qARqFY-I8fplFemr'[E5VT*fBNj!
+!M)L&JRjmHRKhGhKjHRYmI(amI(alHRPhGRChHAYpIi+&KiU1N!#4Nj58P*14MiZ
+&J(PbD&p@683l-5FF%3d4(cK@GT5Z`Y$ChGcBdFLqYDbPRTQ9NBf+Ki1!IATjH(G
+iHATlI(apIAamI(YjH(GhH(PlI(jrJS@)Lik3!*+6P*@8Niq,Ki*lFQPJ9dj&1c%
+Q'a%-$ade8h15V-(3fYlGfG,+`,DYTCqCP*!!M)L&JRppHhPiH(KjHhamIAepI(a
+lHRPiGhCfH(PlIAq"K)H+MT+8PCD@PC13!)f)JhaeE'0D88Jq05SH%``-&ba*DBL
+MZX[@h0hDe-c$ZE#SSTb@NSk,Ki5"IAYjH(KiHATlHhamI(amHhYkH(GhGhKjHhk
+"JiD*M)q4NT18P*14Mib*K(piF'KI9Ne%15dJ&!S)%54"BS1JYmV@hGrFeFl&Zl+
+TSTbANSk,Ki5"IAYjGhGhH(PkHhamIAamI(alHAKiH(KjHhf!JS5(LBb2NC18PC5
+6NBk*K(piEfGH9%Y#15iL&3`*%54!B)'HYXR9h0rFeXr&[,1USjfANiq,L)@#IRa
+kH(KiH(PkHhamI(amI(YkH(GfGRGiHRaqJB@)Liq4NT59PC56NBk+KB"kFfTK@%p
+'2$%P'3i)$"dh9RH@Vm24fplGf0()[V@XTCfBP*!!M)Q&Ji"pHRKiH(KjHRYmI(a
+mI(amHhTiGhGiHATmIS##K)H+MC!!NT18P*55Mib)JhaeE'*C8%Bm-LFE%3`1'c0
+4FC!!UVr1f0hGfG,*`,HZTTqCP*!!M)Q&JhppHhPiH(KjHRYmI(amI(amHhTjH(G
+hGhPlIAq#KBL-N!#6PTHAPT@6N!#-Ki&lG'YK@8p'2$)R'a!*#KF[6Qq2UVr3fYl
+HfY2,`EL[Tk#DPC'0LBD#IhakHAKhH(PkHhapIAepI(alHRPhGhGiHATmIS'%KiZ
+2NT19PTD9Nj!!MBQ$IACYC&Y45$me+am8$3dA,%KSKk1jbYEEh0V6bm1jX+QKQjD
+5MSU(K)&qI(TjH(KjHRYmIAepIAamHhTjH(GhH(PlI(q#KBL-MT!!NC+6Nj+4Mif
++KApiF@KI9Na$15dK&!X)%59$C)@KZ-V@hGlEeFl&Zl+TSTbANSk,Ki5"IRYjH(G
+iH(PlI(apIAepI(alHRPhGhGhHAYpJ)1(LSk4Nj58P*@8NSq,KS"jF@KI9Na$15d
+K%`J$#KipB)'JZ-[Bhq(Hf0$'[,1USjbANSk+Ki5"IRYjH(GiHATlI(epIAemI(Y
+kH(GfGA9fH(TpJ)1(Lik4Nj59PC@8NT!!M)H#Hh4VBPK246Xa*4N2#JdE-e*cNUc
+"d0RGhGR5bEqfVD5HQ*53!)f*KS0rIAYjH(KiHATlI(amI(amI(YkHAGhGhKjHhe
+qJB5(Lik4Nj5@PjD8NBf)JhadDf*C6dBm-LBD$`N+'$"2FC!!Um$3fYrHfY2+`EH
+ZTU#DPC'0LBD#IhakHAKiH(PkHhapIAemI(alHRKhGhGiHAYpJ)1'LBb2NC18PC@
+8NT!!M)H$I(9XBeT45$mf+Ki5#JS9,%YXM+LpcYMGhYV8bm+iVkLJQT@4MBQ'JS"
+pHRKhGhKjHRYmI(amI(amHhTjH(GhH(TlIB##KBL,MT'6P*@9P*+3!)b)JhefEQ9
+F8NJq0#NG%``,&La*DSUP[-hBhGlEe-c#ZE#RSCZ9NBf+Ki5"IRakHAPjHATmI(e
+pIAepI(YkHAGfGRGjHhf!Ji@)M)k3!*+6Nj56NBq-L)0pGQePA&0*3$BX)"3-#a8
+V5@U+TEc0f0hHfp6,`VL[Tk#DPT+1LSH%JAjlHAKhH(PkHhapIRjqIRemHRPhGRC
+hH(TpIi'$KSQ-MT!!NT19PC56N!#,KS&kF@KI98Y"0b`I%3B##b&!BS1KZFcChq$
+Gf-r&[,1USTb@NSk+KS1!IRYjH(GhH(PlI(epIAepI(YkH(GfGAChHAYpJ)5(LSf
+2NC+8P*58NSq-Ki*lFfTK9dj%1LmM&3N$#4Xh@AZDY-M@hZ$HfG$([E1USjbANiq
+-LB@#IhakH(GhH(PkHhapIAjqIAelHRPhGhGiHRYpIi+&LBZ0Mj'5Nj56NT!!M)L
+$I(0VBPK04$S`*"J0#!`F0PCiPl$&e0cIhYR4b,keV+5HQ*12LiL%JAjmHRKhGhK
+jHRapIRjqIRepHhTiGhGhH(TlIB##KBQ-Mj'6PC@9P*13!)b(JRYcDQ"A683k-#-
+9#J8*'MCAHCQcapEHiGrCdXLrYDbPRTL6MiZ)K)&qI(TiGhKiHAYmIAjqIRjqIAa
+kH(GhGhKjHhf!Ji@)M)k3!*'6P*56NSq-L)0mFfYK@%j%15iJ%38!"KSiA(qIZFc
+Ci1,IfG(([E5VSjfANSk+KS5"IAYjH(GiH(TlIAjrIhprIRemHRKhGA9fH(TpJ)1
+'LBb2NC+6Nj16NBk,KS&lFfTK@%p'26)Q'3d(#KJb8h@9X-A8hH$IfY,)[V5VT*b
+ANiq,L)@#J(elHAKiHATlI(eqIRprIRemHRPhGhGhHATmIS'%KiU0Mj'5Nj16NSq
+-LB4pGQeNA&0+36FV(3m&"4!S5'b1UX(5hH,Kh06,`EHZTCqCP*!!M)Q'JS"pHhP
+iH(KjHRapIRprIhpqI(YjH(GfGhKkI(k!JiD*M)q3!*+6Nj15Mib)JhefEQ9F8dT
+#1#dJ%JJ'%#G(DSbT[p$Ei1$FeF["YkkPRjQ8N!#-L)D$J(elHAKhH(PkHhepIRj
+qIRemHhTiGhGiHATmIS#%KiU1NC18PC@8Nj'1LS9qGfjP@e*)2M8T'`m'"4%S4QQ
++U,r3fq(KhGE0`lQ`Tk#DP*!!M)Q'Ji"pHhPhGhKjHRapIRprIhpqIAYjH(GhGhP
+kI(k"K)H-N!#5P*D@PT@6N!#0L)0mG'YL@%j%1LmM&JS%"K8a8R@@XFE9hZ(Jfp2
+*[l@XT*kBNiq,Ki@#IhelHAKiHATmIAjrJ)#!IhjmHRKhGR9fGhTmIi+%KiZ0MT!
+!NT16Nj+3!)f*K(jhEfCG9%Y#15iK&3X($b0"Bi@MZmlDi1$GeXl$ZE#SS*U9NBf
++Ki5"IRakH(GhH(TlI(jrIhprIRemHRKhGhGiHATpJ)+&LBb3!*+6P*58Nj+2LiD
+!HA"QA94,3MNZ)K3+"JdJ2&k!RlR-fH$KhYM2aEZaU+'EPT+1LiL%JAjmHAKhGhK
+jHheqIRprIhjpHhTiGhGhH(TmIS#$KSL,MT!!NC18P*14MSU'J(PbD&pA6N8p-bB
+D$`S0(6GAHCLbaY6FhphBd-HpY+ZMRCH6MiZ)KB*rI(TjH(KiHATmIAjqIRjqI(Y
+kHAKhGhKkI(k!Ji@)Lif2NC+5Nj15Mib)JRadE'0D88Jr0#JD$JF*&c&4Fj5[a02
+Fi0rDdmR!YUfPRjQ8N!#-LB@#IhakH(GhH(PkI(epIRjqIAalHAKhGRCiHAYqJB5
+(LSf3!*+6Nj56NT!!MBU'JATcDf*C8%Fp-bFF%3X0'c06GC5Z`p,EhYhCdFQrYUf
+PRTL6Mib*KB+!I(TjGhGiHATmIAjqIRjqIAakHAKhGhPkI(k!JiD*MBq4Nj58Nj1
+4MSU'J(PbD@"A6dBp-bFD$`N-'M*5G*1Z`p2Gi0rEdmV!YkkPRjQ8N!#-L)D$Ihe
+lHAKiH(PkI(eqIRpqIRalHAKhGRGiHAaqJ)1&L)Z1N!#5NT16NT'1LiL#I(9YC&Y
+558!h,#!9$3`@+NGSL+@mcGMHhY[9c-+jX+HKQj@4MBU(K)&qI(TiH(KjHRYmIAj
+qIRjpI(TjH(GiH(PlI(erJS@*M)q4Nj59PC55MiZ&IhG[C9a656me+Kd5#JJ5*d0
+NKU1lcGMHhpc@cF5kXDQKQjD4MBU(K)&qI(TjH(KjHRYmIAjqIRjpI(YjH(GhGhK
+kI(q#K)H+MBq4Nj58P*14MSU&IRG[CPa55$ic*aS0!`)0*89UM+R"dYhLiYlAcX@
+kXDLKQj@4MBQ&JRpmHAKhGhGiHRapIRprIhpqI(YjGhCfGhKkI(k"K)H,MT'6P*@
+8Nj+2M)L$IA9YC&T45$me+ai5#JS8+8GRL+@mcYVIi0c9cF5kXDLKQj@4MBU'K)&
+qI(TjH(KjHRapIRprIhjpI(TjGhCfGRKkI(k"JiD+MC!!NT18P*56NBf+KApiF'G
+H9%T!0LSG%!F%$L4$CSLP[Y$EiH,Heml%ZV'SS*U9N!#-LSH%JAjlHAKhH(KkHhe
+qIhq!IhjpHhPiGhCfGhPlIB'%KiU1N!#4NT18P*14MSU&IhK`Cej@6%-k,Km4"3%
+)($YJJk1mcp[LiprBcm@lXUQLQjD5MSU(K)&qI(TiGhKiHAYmIAjqIRjpI(YjH(G
+fGhKjHRf!JS@*M)k4Nj@9P*15MiZ'J(PbD9p@683k,b%6"`)*(6aJJU'kcGRIi0h
+@cF1kXDLKQT@4MBQ(K)&qHhTiGhKiHRYpIRprIhpqI(YjH(GfGRGjHhf!JS@)Lik
+4Nj58P*14MSZ'JATcDf0D8NJr0#FD$`N0(6KCHTLaaG,Ch0V8cF5kXDQKQjD5MSZ
+)KB*rI(TjH(KjHRYmIAjrIhpqIAYjH(KiH(KjHherJB5)M)q3!*'6P*16NBq,Ki*
+lG'aL@9")2c8S'Jm,%#%mA(fEXmE5fG[Ce-[#ZE#SS*U8N!#-LBD$J(jmHRPiHAP
+kI(eqIhprIhjpHhTiGhGhH(PlIAq#K)H,MT!!NT16Nj+3!)k,KS&mG@eNA&0+3MJ
+X(a32%b)m@hZBVm,1eGI9d-R!YkqRS*U9NBf*Ki5"IhakHAKiHATmIAjrIhprIRe
+mHRPiGhGiHRYpIi+&L)Z0Mj'5NT+4Mif+KS&mG@jQAeC24Mdb*adB'53j9(12TlV
+(d026cmM!Z+qSSCZ@NSk+L)@#J(jmHRPjHATlIAjqIhprIRelHRPiH(KiHAYmIi'
+$KSQ,MBq3!*'4NC!!MSb)K(jhF'PJ@9"*3$8T(aNC)cK6FBfNYmA0dG$0aVqfVUH
+JQT@4MBU(K)+!IAYkHAKjHAYmIAjrIhpqIRalHRKiH(KjHRYpIi+&LBb2NC+5NT+
+4Mib)JhpjFQTM@e*,3cN[*4iG*6G3E)HHXX$*cFh+aEkhVUHKQj@4MSZ)KB1!IRa
+kHAPjHRYmIAjrIhpqIAalHRPiH(PkHhaqJB1&LBb0Mj!!N!#3!)q1M)U(K(pjFfa
+PA9C24cdc+L3L+6P2DB5EVVc&bX[)`lffVUHJQT@4MBZ)KS1"IhelHRPjHRYmIAj
+qIhjqIAalHRPjHAPkHhaqJ)+&L)U-MT!!N!#3!*!!Mik,L)4rHR0XC9jA8%P#1#m
+T*L`j6@H!PUQi`FE)aX+lY+fQS*U9NBk,L)D$JAppHhTjHATlI(eqIRprIRjpI(Y
+kHAPkHhapIi##K)D*Lif1Mj!!Mik0LSH%J(TeEQKK@P404$Xb+LFX18jRJ*DSYVr
+%aX6!ZE1XTCqCP*!!MBU)KB1"IhelHRPkHRYmIAjrIhprIRemHRTjHAPkHhaqJ)+
+%KSQ,M)f0MBf0M)U)KB&mGh&VC&jB88P!0bmU+cG+BRZ4Sl+l`F2#[VLbUk@HQC@
+4MBU)KS1"IhelHRTkHRYmIAjqIhprIRemHhTkHATkHhapIi'$KBL,MBk2Mik0M)U
+(K)&mGh*VC&jA88T!0c!X-$Y0C(b4Sl#k[m'rZlD`UD1GQ*53!)b+Ki@$JAppI(Y
+kHRYlI(eqIhprIhjpI(YkHAPjHRYmIRq"Ji@)LSb0MSk1MBb+Ki5"I(GbE'CJ@P4
+04$Xe-M9!8'9lMk#YYEZpZlLcVULLR*H6Mib*Ki@$JB"qIAalHhYmIAeqIhprIhj
+pI(YkHRPkHRYmIRq"Ji5'L)U,M)f0MBb+L)D#IRTdEfPMA9G34cmh0$Br6f0iM*f
+UXlLkZEHbVDHJQjD5MSb*Ki@$JS"qIAalHhYmI(eqIRprIhjpIAalHRTkHhapIS#
+#Ji@(LBU+LiZ,LiU*Ki5"IRTeEfTPB&Y96N8q1MNr6&pcKjLPVl@iZ,@aV+DKQjH
+6Mib+L)D%JS"rIAalHhYlI(eqIRprIhjqIAalHhTkHRYmIAq"JS5'KiQ+Lib-M)Z
+*Ki@#IhYfF@aRB9a@6dFr1MT!6Q"dKjHNVE1eYE1[UU5IQTD5MSZ*Ki@$JApqI(Y
+lHhYlI(eqIRprIhjqIAalHRTkHRYmIAq!JS1&L)U,M)b-LiZ*Ki@#IhYhFQeTC&p
+D8da&3$j$6PpaJj+IU+kaXV#YU+1HQC@4MBZ*Ki@%JS"rIRemHhYmI(eqIRjqIRj
+qIAamHhYkHhYmIAk!JB1&KiL*LiZ,LiZ+L)D$J(ejG'pUC@"F9e"+480(8&eYISf
+DT+UZVkkVU+1HQTD5Mib*Ki@$JS"rIRemI(amIAeqIRprIhjqIAemHhYlHhapIRq
+!JB+$KBH)LBU+LSQ)KiD%JAjkGR*ZD@9KA&G46%P+8&YTH)H8RD@TUkZTTU+HQTD
+5MSb+L)D%Ji&rIRemI(amI(epIRjqIRjqIAepI(amI(apIAjrJB1%KSH)LBQ+LSQ
+)Ki@$JAjlH(4`E'KNAeT86dY,8&TSGi@5Qk+RUDQRTD'GQC@4MSb*KiD%Ji&rIRe
+mI(amI(epIRjqIRjqIRepI(amI(apIAjrJ)+$KBD(L)Q*LBQ)Ki@$JApmH(4aE@P
+PB&Y@8Np29&eTGS52Q*qMTUDNSTqEPj53!)f,LBH'K)1"J(pqIAamI(epIRjqIRp
+rIRjqIAamI(amIAeqIi#"JS5&KSD(KiL)KiD&K)+!IAThFh"XD'4J@eG88eCGCh1
+!Lj5ERk+MSU#GQTD6N!#0LiQ(KS5$JS&rIRepI(apIAeqIRjqIRjqIRepI(amI(e
+pIRq!JB+$KBD(KiL)L)H'KB1#J(jlH(9bEQYSC'"F@&CBA@9`I)H3!*DERk#JRTb
+CPT12MBZ*KiD%Ji+"J(pqIAepIAepIRjqIRjqIRjpIAepI(epIAjrJ)#"JS5&KSH
+(KiH(KS@%JS&rI(PfFh"XDQGMAeaD@PjQF(U%MC1BR*fGR*UBPC+2MBZ*KiD%Ji+
+"J(pqIRepIAeqIRjqIRjqIRjqIAepIAepIAjrIi#"JS1%KBD'KSD'KS@$JS&rIAY
+iGA0`E@TRC'&IAf&QEACrL)k8Q*QDQTL@P*'2M)U)KiD%Ji+"J)"rIRjpIAeqIRj
+qIRjqIRjpIAepIAepIRjrIi#"JS1%KB@'KSD'KB@%Ji'!IRakGh4bEfaTCQ*JB'&
+QERCrKif5PTHBQ*D8NT!!MSb+L)H&K)1#JB"rIhjqIAepIRjqIRprIhjqIRjpIAe
+pIAeqIRq!JB+#Ji5&KB@&KB5%Ji+"IhjmHRKfG(&[E@PRC@4PD@pfIS5+Mj+8PC@
+8NT'2M)Z*KiD&K)1#JB#!IhjqIRjqIRjqIRprIhpqIRjqIAepIRjqIRq!J)'#Ji1
+%K)5%K)5%Ji+"J(pqI(TiGR0aEfaTCfCRDQpfIB1*MC!!NT16NT'2MBZ+L)H&K)1
+#JB'!IhpqIRjqIRjqIhprIhprIhjqIRjqIRjqIRjrIi#"JB+$Ji1%K)5%Ji1#JB&
+rIRelHAGfG(*[E@YTD@a`GRb#KiZ1Mj!!N!#3!)k0LiU)KiD%K)1#JB'!J(prIRj
+qIRjrIhprIhprIhpqIRjqIRjqIRprIi#!JB+#Ji1$Ji1$Ji+#JB"rIRemHRPhGR4
+cF@pYE@pbGRZ!K)L,M)f1MBb,LSL(KS@%Ji+#JB'!J(prIhjqIRjrIhprIhprIhp
+rIRjqIRjqIRprIi#!JB'#JS+#JS+#JS+"JB"rIhjmHhTjH(GeG(*aFA*dGhYrJiD
+)LSZ,LiU*L)H'KB5$JS+"JB'!J(prIhprIhprIhprIhprIhprIhprIhprIhprIi#
+!J)'"JB'"JS+#JB'"JB#!IhjpIAalHRPiGhCeG(9fH(YrJB5'KiL)L)L(KS@&K)1
+#JS'"JB#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#"JB'"JB'"JB'
+"J)#!IhpqIRemI(YkHRPiH(KjHRaqJ)+%KB@&KB@&K)5$JS+#JB'"J)#!J)"rIhp
+rIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!JB'!J)#!J)#!IhprIRjqIAe
+pI(alHhYlI(erJ)'#JS1$Ji1#JS+"JB'"J)#!J)#!J)"rIhprIhprIhprIhprIhp
+rIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhjqIRjqIhprJ)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)!!!%*!!!%!!3!&!!!!S!!
+"J&%!!!!!!"3!!!!!!!"#&PEZLk-!!%)8!!"#&3!mJ)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhpqIRjqIRepIAa
+mI(amHhKhGhGiGh9dG(CkIAjrJ)'#JS+"J(jlHAKiHi##JS+#JS+#JS+#JS1"H')
+p)"dJ(b-R,$)f1MSh1$BY'`B!#!`1$`S$#KNR-cJk2N0)6P0DAQ&J99&CB@adGA9
+fHAk&LBZ0N!#5NT+4N!#2MBU)L)Q0NC'4N!#3!*!!N!#3!*!!N!#3!)q2MiPkBe*
+26Nj38eCDAQ"IAPpG98-`+5SV,#`Q)b`i3da38P9DAQ0RDfj`E'*LDh4qJi+#JiD
+-NT@AQCZGRCfFQjQAPC56PCQEQjZEQjZDQTUDQTUCQ*1#E&pF@PTFAf0QD@YUD@T
+SANXl0cJi1$Fa-6Y'89KDA@&PD@eaGAGiFQTZGhq)LiU,M)q9QTbHSD1NT+5MSU#
+HR*ZERU+LSU+LSD'KSD'JS+#JS*U(FQGPBf0NCfYZFA*bFA*`C&"$38"!3$ii1N9
+3@Q"LC@KXF(4iHhemGA&hIiL2N!#3!*!!NT@DRk'MTDHTUDLSTU5LSD#JSkDQTUD
+QTU@PTD@PT+5NT*k-GfeUD'KUE("cGRGfGRGfD99+5%C'4N-p3%Y9Af9RDQeaG(K
+mIi"qGh9mK)f6Nj16PCQHSU5QU+UXV+ZVUDHPT+1NTkQTUDQTU+LSU+LRTkHRTk+
+4I(*[E'YYEh*fHATjHATkE9P16%T+5NC"4%jBBQKUEA"cGhYqJB*rH(KrKSq9PC@
+9PjUJSk@RUDZYVUfYUkQRTU@QUDZVUkZUUUUUUUQTUDQSU+@@J(CcEfj[FA4iHRa
+mI(amF&e58%e-5dK#49"CBfPVER*eHAarJB1"HAQ"L*'APTDAQ*ZJT+DSUUbZVkq
+ZVDZTTkDRUkfXV+bXV+ZVUkZUUUUUUDLEKATeF@p[FA9iHhamIAepFf"98Np06%P
+$48pBBQPXEh*fHAarJS1!HAQ"LC'APjHAQ*ZJT+DSUUbZX+q[VDZTU+HSUkfYVDb
+XV+bXUkZVUkUUUDQJM(eiFh"`FA0hHRapIAeqG@0A9&"168Y&4%e@B'KVER*eH(a
+qJ)&rH(L!LC'APjHAQ*UISkDRUDZYVkq[VDbUU+HSUkfYVDbXV+bVUkZVUUUUUUQ
+MNS*kGA&[F(*eHAYmI(apGfCC9&"06%T&3NP6A'9UE("cGRTmIS"qGh9qKiq@PjD
+@PjQGSU5QU+UXVUq[VDbUU+HRUUfYV+bXV+ZVUkZUUUUUUUQQQBKpH(*[Eh"cGRP
+lHhamH'YF9P*05dT'3%419f&SDQjaGAKkI(jpGh0jK)f9PTD@PTHDRk1PTkQVVDq
+ZVDbUU+HRUDbXV+bXUkZVUkUUUUUTUDQRRiq"Hh9`EQj`G(GjHRTlH@pK@9426%T
+(38"+8eaPD@a[FhCiHRamGh&fJ)Q5PT@9PCDBRD'MTDHTUkfZVDbUU+HQU+ZXV+Z
+VUkZUUUUUUDQTUDQSSjH*IhKbEfeZFA4hH(PkHA*PA&G46%T)3Me%69CJCQPYF(0
+fH(TkH("aHS51PC58P*5@QCkKSk@RUDZYVDbUU+HQTUQVUkZUUUUUUDQTUDLSU+L
+RTCf2K(eeF'eYER"dGRGhH(4TAPP66NT(4$ip4NpBBQGUER&dGRKiGh"YG(k)NT5
+6Nj18PTZISD1PTkQVV+bUU+DPTDHUUUUUUDQTUDLSU+LRTkHQTU+@LS*lFfpXE'e
+`Fh9eGR9XBPa@8%Y(48!l2NK3@f0QDQe`Fh9fGA&UEAH!Lj+5NT+5NjDERU#LT+D
+SUUZUU+DPT+@SUDQTU+LSU+HRTkDQTUDQTD5GN!#(JAPaE@YUE'paFh0dF'9I@e4
+15NC$2$P!59*GBfCTEA"bG(4bE'K`HB11NC'4NC'6PTZHRk'MTDHTUULQTD5MTDL
+SU+LRTkHRTUDQTD@PTD@NSTQ,KB"hF'aUDQYZF(*bFQTJAPT568K%3$Ni3NT8AQ0
+QDQe[FA*bEQGSFRZ'Mj!!N!#3!*!!N!#5PjZGRk'MTDHSU+HPT+1MTUHRTkHQTUD
+QTD@PTD5NT+5MRj1(K(jeEfYTD@YYEh"aEf9HAPK35dC#1c8j3NY@AQ*QD@a[FA&
+`DQ9UG(f)MSq2MSq3!*1AQTbHS++NTUHRTU5MSU1QTkDQTUDPTD@PT+5NT+1MSk'
+CM)@$I(0YDQKTDfeZEh"XB9eH@&"+4$mf-cY%69KHB@9SE'j[F'jRBfYeISQ0MBf
+0MBq6PjQERCqKSk@RTk@MSU+MTDDQTD@PTD5NT+1MSk1LSU'GNB@%JAKaDfKSD'T
+XE@j[DPpGAPK358)j-63q4P"CA'"ND'YYEfpXC'0XGAq*M)Z,Lib2NjDBQTbHRk'
+MTD@NSU'KSk@PT+5NT+1MSk1LSU+LSD'IPiQ$JhjdEQPRCfKUDfaZEfPIA9pD8%F
+q-Lmi38T69eYJC'KVE@pZDf0MEAD!LBU+LSU-N!#6PCHBQTbHS++NT+1LSD'LT+5
+NT+1MSk1LSU+LSD'KRjU0Ji1"HA*XD'GRD'PUE@p`D9pHB&T246FZ-ca%6P0@@f"
+ND'YYEfjUBf0ZGi#)LBL)LSf4Nj5@Q*QERCqKSk5MSD#KSk5NSk1MSk+LSU+KSD'
+KRjb4K)+$IR9ZDQGRD'PTDfj`F'KIAf"D6Mmb-6P!5Np59PYJC'KXEQpZD@*PF(L
+#L)H(L)U1NC+8PCHCQjfISD+MSU'JSD1NSk1MSk+LSU+KSD'KS*f6KS'$J(PaE'K
+RCfKSDQe`FR&RAepI@%Ni-cJq4de28PGEB'9TE'j[E@GLD(*kJiH'KSQ-Mj!!NC1
+9PTLDR*kJSU1LSD#KSk1MSk+LSU+KSD'KS+#GPBL#JS&mG@eTCfGRCfPXEh*dF'9
+HAPa53$Fk2N9,68p59eaKCQTYEfpYCQ0VG(f%KB@(LSf1Mj'5P*DBQTbHS+'LSD#
+JSD1MSU+LSU'KSD'JS*qGPSL"JS*qGfpVD'GRCfGUER&dG@eKA9a94cdp3%9,6%e
+29&KHBfGVER"[Df4PEhGrK)5'LBb0MSq4NT5@Q*QERCqKSD'JS++MSU+LSU'KSD#
+JS*qGPBL"JS*rHA&XD@GRCQGUEA&eGR4SAPY@5d9%4%K-6%a1899DB'9UER"`EfK
+MDR0kJB5&LBU,MBk2NC+8PTLDR*kIS+'JS+'LSU+LSU'KSD'JS*qGPBH"JS+!Hh0
+YDQKRCQGUEA&eH(G`BPY95dP-5de168e06e0BA@0SE'paF@ePCQphIB1'L)U,M)f
+1N!#4Nj5@Q*UFRTqJSD#JSU+LSU+KSD'KS+#IR*+'JB+#JAadEfYSCfCRDQeaGAK
+jG@GE8dY-8P*58Np16Nj49PYKCQY[FA*`D@9XG(Z#KSL*LSZ-MBk3!*'6PCHBQTb
+HRk#JS+'LSU+LSD'KSD#JRjZ2Ji+#JS&pG@pVD@GQCfTZFRCjHRGV@e"+6PCB@&9
+46dj18&4CAf9UER&cFQeQDA*iJ)H)L)Q+Lib0Mj!!NT19PjQERCkIS+#JSU+LSD'
+KSD#JS*kBM)+#JS+"IAC`DfPRCQGUER*fHATiEPa16&*BA9jB8e&26P"6@&eMD'e
+aFh0[CfG`Ghq'KiH)LBU,M)k2NC+8PTLDQjfHRjqJSU+KSD'KSD#JRjf9L)+$JS'
+"IAC`E'PRCQKVEh0hHATjF&e-6P9DB@0F9e048&"59eaLD'eaG(4aD@G[Ghk'KiH
+)LBU,M)f1N!#4Nj@AQCUFRCkIS+'LSD'KSD#JS*kENB@#Ji+#JRefF'aTCfGTE("
+dH(TlHA"F6&&CA@4QB&T@8e&48eGFB@GYFA4eFfYSEhGqKSL(L)Q+LSZ0MSq4NT5
+@Q*UER*kIS+'LSU'KSD'JS*kBLi1%K)+#JRafF'aTCfKUEA&eHAYlH'jD6e9FB@C
+QBejB99048eGFB@KYFA9fG'eTF(KrKSL(L)Q*LSZ-MSq3!*+8PCHCQjbGRU#KSU+
+KSD'KS*qFNSD$K)5$Ji&mG("XD'GTDfpcGhTmHhCV@90CAf9RCf9J@PG88P4AA'&
+SEA&eGR4YDR&jJ)D(KiL)LBU,M)f1N!#4Nj@AQ*UER*kJSD+KSD'KS*qGPiZ%K)5
+$Ji1"HR0[DfKSDQeaGAKkHhPcCPTBA@4RCfKSBeeC9P489eaLCfebGACdEQYcHS#
+'KiH)L)Q+LSZ0MSq4NT5@Q*QER*fISD'KSD'KS*kEN!#&K)@%Ji1$IhKbE@TSD@a
+[FhGkHhYhE@9JA@&SD'KTD@CJ@eG99PKGBfKZFhChG@jYGAb"KSH(L)L*LBU,MBk
+2NC+8PTHCQTZGRk'KSD'KSCqFP)L%KB@%Ji1#IACaE'PTDfjbGRPlHhPbDQKMB'G
+UD'KTDQGLA9PA9eTIC'P[GAGiG@p`H(f#KiL)L)L*LSZ,MBk2NC+8PTHCQTZGRk+
+LSD'KS*fALi@'KS5%K)5"HR4ZDfTVEA&eHAYlHR9YE@eQCQTTD@PUDfPMAeYB@9a
+JC@YaGAGiGA"bHRq%L)L)L)L*LSZ-MBk2NC+8PTHCQTZGS++LSD'JRTL0KBD'KB@
+%KB0pGR&XDQYYF(4iHRalGQpZFfpTD@TUDQTVE'TPB&aD@eeLCfebGRKiGA&eI)'
+'L)L)L)Q*LSZ-MBk2NC+8PTHCQTZGS++LSD#HQSq'KiH&KB@&KB&kFfjVDfe[FhG
+jHhTfF'peG@pUDQYVDQYXE@YPB&eEA&pNDQpdGhPjG(*jIi1(L)L)L)Q*LSZ-MBk
+2NC+8PTHBQTZHS+'KS*kDMiD(KiD&KB@&JhaeEfaXE@pcGRPlHhG`FAGkGfpUDfY
+VDfaYEfaQB&eGAQ&RE(&eH(TiFh9pJ)@)L)L)L)Q*LSZ-MBk2NC+8PTHCQTbISD'
+JRTU2KiH)KSD&KBD%IRGaEQaYEh*fHATkGh"bHAamGQaVE'aXE'e[F'aQB9pIB@9
+UER0hHRYeFRQ!K)L)L)L)LBQ+LSZ-MBq3!*'6PCDBQCZGRk+KRTQ1KiL)KiD'KSD
+&J(KcEfeZF(0fHATkGh&cHhjrI("VE@eXE@eZF(&XCQ*JB@0REA*fHRajFhGqJSH
+*L)L)LBQ*LSZ-MBk2NC+8PCHBQTbHS+#HQ)f(LBQ(KiD'KiD#HR4`EQj`FhCiHRT
+fFA4mIi+!G@aXE@eYE@j`FR"UC@*LBfCVF(9jI(YeGAb#KSQ*L)L*LBQ+LSZ-MBk
+3!*'6P*DBQCUGRk#HQ)f(LBQ)KiH'KiH%I(9aEfj`FR9iHRPfFR9pJB1#H@jXEQe
+YE@j[FA*ZD'4LBf9TER0hHhYhG(U"KBQ+LBL)LBQ*LSZ-MBk2N!#5Nj@@Q*QERTq
+HQ)k)LBQ)KiH(KiH&IhGcF'p`FR9iHAPfFR4pJB1$I(&XEQjZEQj[FA0aE'GNBf9
+SE(&fHRYiG(Q!K)L+LBL)L)Q*LSU,M)f1N!#4Nj5@PjLDRCkGQT!!L)Q+LBL(KiH
+(Ki*kGA&[F(&dGhPjGh*dIB'$K(jbE'jZEQjZEh"bFfpTC@4NCfY`G(KkHA4iJ)5
+)LSQ*LBQ*LBU+Lib0MSq4NT59PjLDR*fGQT'*LBU*L)L(KiH)KAjhFh&`FA0fH(P
+hFh0lJB5&Ih4YEQpZEQj[F(*dF@YRC@4QDQjcGhPjGAH!KBL,LSQ*LBQ*LSU,M)f
+1Mj!!NT19PjLDR*kGR*5,LBZ+LBL(KiL)Ki0lGR*aFA0eGhKiG(*jJB5&JAGZEQp
+[EQj[F(&cFfjSCQ9QD'aaG(GiGACrKBL,LiU*LBQ*LSU,M)f1Mj!!NC18PTHCQjf
+GR*L1LBZ,LSQ)L)L)L)D!HA9bFA*dGRKiGA*hJ)1%JhP[EQp[EQjZEh&bG("UCf9
+PCfTZFR9fG(CqKBL-LiU+LBQ*LBU+Lib0MSq4NT59PTLDR*fGQT+*LSZ+LBL)L)L
+)L)4qH(4bFR0eGRGfFR0mJS1$I(&YEfpZEQj[F(&cFQeSC@4QD'a`Fh9dG(Z$KiZ
+-LiU*LBQ*LSU,M)b1Mj!!NC18PTHCQjfGQjD-LBZ,LSQ)L)L)L)L$HhGdFR*dGRG
+hG(*iJB1%J(9ZEfpZEQjZEh"bFh&VCf9PCfTYFA0cFRL#KiU0M)U+LSQ*LSU,Lib
+0MSq4NT59PTLDR*fFQT++LSb,LSQ)L)L)L)H"HhGcFR0dGACeFR0mJi1$HR"[F'p
+ZEQj[F(&cFfpTCQ9PD'YZFA*aFhk'LBf0M)Z+LSU+LSU,M)f1Mj!!NT18PTHCQjf
+GR*L1LSb-LSU*L)L*LBQ(JAYhG(0cG(9fG(&fJ)1$Ih4[F("ZEQjZEh"aFh*YD@C
+PCQKXEh&`F(H$L)b1MBb,LSU+LSU,Lib0MSq4NT19PTLDR*fFQj@-LSb-LiU*LBQ
+*LBQ(JAYhG(0cG(9eFR&jJB1#Hh&`F@pZEQeZEh"aFR&XCf9PCQKVEQpZF(b'LSk
+1MBb,LSU+LSZ,M)b0MT!!NC+8PCHCQjfGR*U5LSZ0M)Z+LBQ*LBQ*Ki*lGh4cFh4
+dFh"bI)+#J(G[FA&[EQeYEQp`FA*`DfGPC@CSDfeYEA1!L)b1MSf-LiU+LSU,Lib
+0MSq3!*'6P*DAQCZGRCZBN!#+M)f-LiU*LBQ*LBQ(JRYhG(0cG(4bEh4qJS*qFfp
+aF'pZE@eZEh"`FR"XCf9PCQKUE'YXGS+*MBq1MBb,LSU+LSZ,M)f1Mj!!NC18PTL
+CQjfFQTH1LSf0M)Z+LBQ*LBQ*L)0mH(9dFh0cF@peIi+"I(*`FR"[EQeYEQp`F(*
+aE'KQC@CSDQYUE(Q%LSq2MSf-LiZ,LiZ,M)b0MSq3!*'6PCDBQTbGR*U9MBZ1MBb
+,LSQ*LBQ*LBQ%IRPfG(4cFh&[Gi#"JATaFA*`EfjYE@j[Eh"bF@aSCQ9PCfPTD'e
+kKBU2N!#2MSf-LiZ,LiZ-M)f1Mj!!NT19PTLDR*fFQT@0Lik1M)Z+LSQ*LSQ*LBD
+!HRGeG(0bF'phIi'!HA&aFR"[EQeYEQj[F(&bEQPQC@9QD'KRE(Q%Lj!!N!#2MSf
+-LiZ,LiZ-M)f1Mj!!NT18PTLDQjfEQC@1Lik1M)Z+LSU+LSU*LBH#I(KeG(0bEfj
+fIi'!H("aFR"[E@eYE@j[Eh"bEfTRC@9QCfGQDhQ$LSq3!)q1MBb,LiZ,LiZ-MBk
+2N!#4NT5@PjQERCZCPBf,MSk0M)U+LSU+LSQ*LB9qHRGeFh*[EA4pJ(piFA*cF@p
+YE@eYEQj[F(*`DfKQC@9QCQ9UH)+*Mj!!Miq0MBb,LiZ,Lib0MBk3!*'5P*@AQCU
+FR*U@MiZ1MSf-LiU+LSU+LBQ+L)*mH(CdFQpYFRarIhKaFR0aEfjYE@eYEQp`FA&
+YD'CPC@9PBfKfJBH0N!#3!)q1MBb,LiZ,Lib-MBk2N!#5Nj@@Q*UFR*UAN!#,MBq
+1M)Z+LSU+LSU*LSU&IhYhGA0`EA"jIRjjFR*dFR"ZE@eYE@j[Eh"bF'YSCQ9PC'*
+QFhk'M*!!N!#2Mik0M)Z,Lib-M)f1Mj!!NC18PTHCQjbDQ*+-M)q1MBb,LSU+LSU
++LSU)JhjkGR4aEQjfI(ejFh*dFh&[EQeYE@jZEh"aF@eTCf9NBf*NEhb$LSk3!*!
+!Mik0M)Z,LiZ-M)f0MSq4NT19PjLDR*UBP)f,MSk0M)Z+LSU+LSU+LSU(JAajGA0
+[EA*kIATdFA4dFR"ZE@eYE@jZEh"bF'YSCQ4MB@&UH)#(M)k2Mik0M)b,LiZ,M)b
+0MSq3!*'5P*@AQCZDQ*D3!)Z0MSf-LiU+LBU+LBQ*LSU'J(aiG(&YERClHR9aFh4
+bF@pYE@eYE@jZEh&bEQTRC@0KB'9cIB1*M)k2Mik0M)Z,LiZ,M)b0MSq3!*'6P*D
+BQTZCPj1-Lik1MBb,LSU+LSU*LBU,LS9rHhGcEfe`H(TfFA*dFh*`EQeYE@eZEQp
+`FR&YD@CNBPpKE(L!KSZ0Miq1MBf-LiZ,Lib-MBf1Mj!!NT19PTLDQTL@MiU-Mik
+0M)Z+LSU+LSU+LSZ+KApkGR*ZEA0jH(0aG(9cFA"ZE@eYEQjZEh&cF@aSCQ0JAf9
+bI)+)Lif2Mik0M)b,LiZ,M)b0MBk3!*'5P*@AQCUCPj50LSk2MSf,LSU+LSU+LSU
++LiU&IhTfF@eZGAPeFA*eG(*aEfjZEQjZEQp`FR0`E'KPBPjJDhCpK)Q,MBq2MSf
+-LiZ,LiZ-M)f1Mj!!NC+8PCHCQTL@NBZ,Miq0M)Z+LSU+LSQ*LSU-LS9rHR9`E@p
+fGh*`Fh9dFR&[EQjZE@jZEh"bFh"VCf4JA@*[HAq&L)Z0Miq1MBb,LiZ,Lib-MBk
+2N!#4NT59PjQBPT51LBb2MSf-LiU+LSQ*LBQ+LSb+K(jjG'pYFRGeF(&dG(0bF'p
+ZEQjZEQj[F(*cF'YRBepHCR*kJ)D)Lif2MSf0M)Z,LiZ,Lib0MBk3!*'5P*@AQ*D
+8NBU)MBq1MBZ+LSU+LSQ*LBU,M)U%IRKbEQpeH(4`FR9dFh*`EQjZE@jZEQpaFh4
+aE'GMAepTG(Z"KSQ,MBq1MBb-LiZ,LiZ,M)b0MSq3!*+6PCH@P*+-KiQ1MSf-LiU
++LSU*LBQ+LSZ-L)*mGR"[G(PjG("bGA4cFR"[EQjZEQj[F(&cGA*YD'4JB@YfI)+
+(LBb1Mik0MBb,LiZ,LiZ-M)f1Mj!!NT19PT55MSH'Lik1MBb,LSU+LSU+LSU,MBb
+(J(TcEh0kHhTdF(0eG(0aF'pZEQjZEQp`FA4fG'jTC@"LERGpJiH+M)q2MSk0M)Z
+,LiZ,Lib-MBk2N!#4Nj58NBk)JiH,M)f-LiU+LSU+LSU+Lib0Li4qGh&bHRepI(4
+`G(9dFh&[EQjZEQjZEh"bG(CeF'YPB@4[H(k%L)U0Miq1MSf-LiZ+LSZ,Lib0MBk
+3!*'6NT!!MSL#K)Q+Lib,LiU+LSU+LSU+Lib0LB&kFh"iIhprI(4aG(9dFR"[EQj
+YEQjZEh"bG(GfF@aQBQGbHRq&L)Z1Miq1MBb-LiU+LSU+LiZ-MBk2NC'1M)L"JBD
+)LBU,LiU+LSU+LSU+Lib0Li4pGR&hIi+"J(TbFR9eG(*`EfjZEQjZEh"aFh9hH(0
+YCf4UGAb"KSQ-MSq2MSf0M)Z+LSU+LSZ,M)f1N!#3!)k,Ki"rJiD(L)Q+LiU+LSU
++LSU,M)k0Ki"iFhCqJi5#IhKaFh9eFh&`EQjZEQj[Eh"bG(CiH(0YCfC[H(k$KiZ
+0MSq1MSf-M)Z+LSU+LSZ,M)f1Mif+Ki"pJS@'KiH*LSZ,LiU+LSU,M)f1Li0kG(G
+qJiD&JAefFA4fG(0aEfjZEQj[Eh"aFh9hHRPdE@GUG(Z!KBQ-MSk2MSk0M)Z,LSU
++LSU,Lib0MBZ*KAjlJ)1%KBD(L)U,LiZ+LSU,M)f1Li4lGAKrJiD(Ji"kFh*eGA0
+aF'jZEQjZEh"`FR4fHAYjFfaTEhPqJiL,MBk1MSk0MBb,LSU+LSU+LSZ-MBU(Jha
+kIi+#Ji5&KiQ+LiZ,LSZ,M)f1M)9mGRQ!JiD)KB*qGR&dGA4bF'pZEQjZEfp`FA0
+eH(TmHA*XEACpJSD*M)f0MSk1MBb,LSU*LBQ+LSU,LiL&JATjIS#"JB+$KBH*LiZ
+,LSZ,M)f1M)CpH(b#K)H*Ki1!HR0bGA4cF@pZEQjZEfp`FA0eGhPmI(G`EA4mJ)@
+)Lif0MBk1MBf-LiU+LBQ*LSU,LSD$IRKjIAq!J)'#K)D)LSZ,LiZ-M)f1M)CpHAq
+%KBH)L)@#IA9aG(9cFR"ZEQjZEh"`FA*dGhPlIAaeEh0lJ)5)LSZ-MBf1MBf-LiZ
++LBQ*LBU+L)5"HhCjIAjrIi#"Ji@(LBZ,LiZ-MBf1MB9pI)'&KSL)LBH$IhGbFh9
+dFR"[EQjZEh"`FA0dGRPlIAjkFh0lJ)1)LSZ-M)f0MBf-LiZ+LBQ*LBQ*KS0rH(9
+jI(eqIRq!JS5'L)U,LiZ-MBf0M)9qIi5'KiL)LBH$J(TbFR9dFR&[EQj[Eh"aFR0
+dGRPlIAppGR4lJB5(LSU,M)b0MBf-LiZ+LBQ*LBQ)K)&mGACkI(amIAjrJB1&KiQ
++LiZ-MBf0Li0rJSH(L)L)LBL%JAYcFR9dFR&`Efj[Eh"aFR0dGRKlIAprHAClJS5
+(LBQ+Lib-M)b-LiZ+LBQ)L)L&JAjiFhClHhYlI(eqJ)+%KSL+LiZ-M)f0LB1"KSL
+(L)H(LBL%JAYdFR4dFh&`Efp[Eh"aFR0dGRKlIAq!I(KpJi@)LBQ*LSZ-M)b-LiZ
++LBQ)L)H$IhYdG(KkHRTlHhaqIi'$KBH*LiZ-MBb-L)1&LBL)L)H)LBL%JAYdFR4
+dFh&`Efp[F("aFR0eGhPlIAq"IRTqK)D)LBQ*LSU,Lib,LiU+LBL)L)5!IACbGAP
+jHRTkHhapIi'$KBH*Lib-M)b+KS@*LSQ)KiH)LBL%JAYdFR9dFh*`F("`F(&bFh4
+eGhPmIS#"Ihf"KSL*LSQ*LBU,LiZ,LiU+LBL)KS&qHA0cGhPjHAPjHRYpIi'$K)D
+*Lib-M)b*KSQ,LSQ)KiH)LBL%JAYdFR9dFh*aF("`FA&bFh4fH(TmIS#"J(q$L)Q
++LBL)LBQ+LiZ,LiU+L)L(JhjlG(*fH(KiH(KjHRYpIi##K)D)Lib-LiU*LSb,LBL
+(KiH)LBL$J(TcFR9dFh*aF("aFA*cG(9hHAYpIi'"JS+'LSU+LBL)L)Q+LSZ,LSU
+*LBL%IhYeFA4hH(GhGhKiHRYpIi##K)D)Lib,LSQ,MSf,LBL(KiH)LBH#IhKbFh9
+dFh*aF(&aFR0dGAChHAYqJ)'#JS5*M)b,LBL)L)Q*LSU+LSQ*L)@!I(GaFhGhGhG
+fGhGiHRYpIS##K)D)LSZ+LSb2MSb+L)H(KiL*LBD"IRGbG(9dFh*aFA&bFh4dGRG
+iHRarJB+#K)L0MSb+L)H(L)L*LBU+LSQ*KS&pH(*cGRGhGRCfGRGjHRapIS##K)D
+)LSU*M*!!N!#0LiL(KiH(L)Q)K)"lG(*eGA4cFR*bFR*cG(9fH(PlIS#"JS1'M)q
+1M)U)KiH(L)Q*LBQ*LBD"IAKbFRChGhCfGAChH(PlI(erJ)1&KiQ*LBf5NBk-LBH
+(KiH)L)Q'JRjiFh0eGA4cFR*bFh0dGAChHAYpIi'#Ji5+N!#4MSb*KiH(KiL)LBQ
+*LBD"IAKcFhChGRCeGA9fGhKkHhapIi'$KBH)LBf6Niq-LBL(KSH(L)L)K)"lGA*
+dGA9dFh*bFh0dGAChH(TmIS##Ji1'MT14MSZ*KiH(KiL)L)Q*KS&pH(0cGRGfGR9
+eGA9fGhPkHhaqIi'$KBD)MT56N!#0LSH'KSD(KiL)KB&qH(0cGR9eG(0cFh0dGAC
+hH(TlIAq"Ji1%Lj16Mif+L)D'KSH(L)L)KB"pH(0dGhGfGR9dG(9fGhKjHRYpIS#
+#Ji5'MT@8N!#0LSL'KSD'KiH)Ki*qHh9cGACeGA4cFh4dGAChH(PlIAq!JS1%L*'
+9NSk,LBH'KSD'KiH)KB"pH(4eH(GhGR9eGA9fGhKjHATmIAq"JS1&M*@9NBk+L)D
+'KSD'KiH(K(pmGR0eGRCeGA4dG(4eGRGiHAYmIS#"Ji1&MC@8N!#0LBH'KSD'KSH
+(KB"pH(4eH(KhGR9eGA9fGhKiHATlIAk!JB+%Lj5@NSq,L)H'KBD'KiH(KB&pH(4
+dGhGfGA4dG(4eGRGiHATmIAq"JS1%Lj59NSq,L)H'KBD'KSH&JAjjGA9iH(KhGR9
+eGA9fGhKjHRYmIRq"JS1*NTD8N!#-LBH'KB@'KSD(KB&qHR4dGhGfGR9dG(9eGRG
+iHATlIAk!JB+$L*+@Nj!!M)Q(KS@&KBD'KB&qHhCeH(PiGhCeGA9fGRGiHAPkI(e
+rJ)'#Kiq@PC'0LBH'KB@&KBD'KB&qHR9dGhGhGR9eG(9eGRGiH(PkI(jrJ)'#Kiq
+9P*'0LBH'KB@&KBD&JRjlGh9iHAKhGhCeGA9fGhKiHATlI(jrJ)'&M*5@Niq,L)D
+&KB@&KBD&JAjlGR9hH(GfGA9eGA9fGhKiHATlIAk!JB+&MC59NSk+L)D&KB@&KBD
+$IhejGAGjHAKhGRCfGRChH(PjHRYmIAq!JB1*NC@9NBf*KiD&K)5&KB@#IhahGAG
+iH(GfGA9eGAChGhKjHAYmIAq!JB1+NT@6MiZ*Ki@%K)@&KB5!IAThGhPkHAKhGRC
+fGRGiHAPjHRYpIRq!JSD1Nj@6MiZ)KS@%K)5&KB0rIAPeGhPiH(GfGA9eGRGhH(K
+jHRYpIRq!JSL2P*54MBU)KS@%K)@&KB*qI(KfHATkHAKhGhCfGhKjHAPkHhapIi#
+"K)U4PC54MBU)KS@%K)5&K)"qHRGhHAPiGhCfGA9fGRGiH(PjHRapIRq!K)Z4P*1
+2M)Q(KB5%K)@&K)"pHRGhHRTkHAKhGhChGhKjHATlHheqIi#"KBf5P*53!)b*Ki@
+%K)5%K)&qI(KfH(PjH(GfGR9fGRGhH(KjHRYmIAjrJSL1NT55MSU)KS@%K)5%KB*
+qI(PfH(YkHAKiGhGhGhKjHATkHhapIRq!JSL1NT56MiZ*KS@%K)5%JRppHRGhHRT
+jH(GfGRCfGRGhH(KjHRYmIAjrK)Z3!*+6N!#-LBH&K)5%K)5$J(elH(GkHhTjHAK
+hGhGiH(PjHRTlI(eqIi#$LT!!NT55MiZ)KS@%K)5$J(jmH(GjHRTjH(GfGRCfGhG
+iH(KjHRYmIAk!KSb2NC+2LiQ'KB5$K)5%JhppHRGiHhYkHAPiGhGhH(PjHRTlHha
+pIRq"K)Z3!*+6NSk,L)D&K)1$JRppHhGiHRTkHAKhGRCfGhGiH(KjHATlI(eqJSQ
+0Mj'4MSZ)KS@%Ji1%K)&qI(PhHAYlHhTjH(KiH(KjHRTkHhapIRq!JBD0N!#5Nj+
+1LSL'KB5$Ji&qI(PhHAYlHRPiGhGfGRGiH(KiHAPkHhapIi1+MBq4NBk+L)D%K)1
+$K)5"IRajH(TmHhYkHAKiH(KjHATkHRYmIAjqIi'(MC!!NC+4MSU)KS5$Ji1!IAY
+iGhPlHhTjH(GhGhGhH(KiH(PjHRYmIAq%LSf2N!#3!)k,L)D%Ji1$Ji1!IAajH(T
+mHhYkHAKiH(KjHATkHRYmI(eqIi+)MBq4NT'1LiL'K)1$JRppHhKhHRYlHRPiGhG
+hGhGiH(KiHAPkHhapIi@,MBk3!*!!MSU)KS5$Ji1$JRppHhPiHRalHhTjH(KiH(P
+jHRTkHhYmIAjrJSH0Mj!!NC'2LiL'KB5$JRjmHhKiHRYlHRPiGhGhGhKiH(KiHAP
+kHhapJ)@+M)k2Mik,L)D%Ji1$Ji*rIAYjH(YmHhYkHAKiH(KjHATkHRYlI(eqIi'
+'M)k3!*'4Mib*Ki@%Ji*qI(TiH(YmHhTjH(KhGhGiH(KiH(PjHRYmIB#&LSb0MSq
+1M)Q'KB5$Ji1#IhelHAKlI(alHRPjH(KiHATkHRTlHhapIRq"KSZ1Mj!!NC!!MBU
+)KS5$JRjmHRKiHhalHhTjH(GhGhKiH(KiHAPkHhYmIi5*M)f1Mik-LBH&K)1$Ji1
+!IAakH(TmI(YkHRPjH(KjHRTkHRYlI(eqIS#&LSf2N!#3!*!!MSZ)KS5$JRjmHRK
+iHhamHhTjH(KhGhKiH(KiHAPkHRYmIi5*Lib0MSk-LSL'K)1$Ji1!IAakH(TmI(a
+lHRPjH(KjHRTkHRTlI(apIS#%LBb1Mj!!N!#2MBU(KB5#IRakH(KkI(alHRPiH(G
+hH(KiH(KiHAPkHhYqJiL+Lib0MSf,L)D%Ji1#JS&qI(YjHAYmI(YkHAPiH(PjHRT
+kHRYlI(eqIi+(Lif1Mj!!N!#1LiL'K)0rI(YiGhTmI(YkHRPiH(KiH(KiH(KjHAT
+kHhf#KiQ,Lib1MSb*Ki@%Ji1$JRpmHhPjHhamHhYkHAPjHAPkHRTkHhYmI(eqJ)@
++M)k2Miq2MBU(KB5!IAYjGhPmI(YlHRPiH(KiH(KiH(KiHAPkHhb!KBL+Lib-MBb
++L)D%Ji1#JS"pI(TjHRamI(YkHRPjHAPkHRTkHRYmI(eqIi+)Lif1Miq2MSb*Ki@
+#IRakGhKlI(alHRTjH(KiH(KiH(KiHAPkHRYqJiH*LSZ-MBf,LBH&K)1#JS&qI(Y
+jHAYpI(alHRPjHAPkHRTkHRYlI(epIS#&LSb0MSq2Mik,L)D%IhalH(KkI(alHhT
+jHAKiH(KiH(KiH(PjHRYmJBD)LBU,M)f-LSL'KB5$JS+!IAakHATmIAalHhTjHAP
+jHRTkHRTlHhapIRq#KiZ-MBk2Miq0LSL'JAelHAGjHhamHhTkHAPiH(PiH(KiH(P
+jHATlIS1(L)Q+LiZ-LiQ)KS5$Ji+"IhalHRPlI(amHhTkHAPjHATkHRTkHhYmIAj
+rJiL,M)f1Miq1MBU)K)"pHhKiHRamHhYkHRPjH(PjH(KiH(KjHAPkI)'&KiL*LSZ
+,M)Z*Ki@%Ji+#JAjmHhPkI(epI(YkHRPjHATkHRTkHhYmI(eqJ)@*Lib0MSk1MSf
++Ki0rI(TiHAYmI(YlHRTjHAPjHAKiH(KjHAPkHhf#KSH)LBU+Lib+L)H&K)1#JS"
+pI(TjHRepIAalHRTjHATkHRTkHRYlI(epIi+'LSZ-MBk1MSk-LSD#IRajH(TmI(a
+lHhTkHAPjHAPjH(KiHAPjHRYrJiD(L)Q+LSZ,LSL(KB5$JS&qI(YkHAYpIAamHhT
+kHAPkHRTkHRTlHhapIRq$L)U,M)f1MSk1M)Q&JAelH(KkI(amHhYkHRPjHAPjHAK
+iHAPjHATmJ)5'KiL*LSU,LiU*Ki@%Ji+!IAalHATmIAemHhYkHRPkHRTkHRTkHhY
+mIAk"KBQ+Lib-MBk1MBZ)K)"pHhKjHhamI(YlHRTjHAPjHAPjHAPjHATlIB'&KSH
+)LBQ+LiZ+LBH&K)1"IRalHAPlIAepI(YkHRTjHRTkHRTkHRYlI(erJiH*LSU,M)f
+0MBb+Ki0rI(TiHAYmI(alHhTkHAPjHAPjHAPjHAPkHhf#KBD(L)Q+LSZ-LiQ(KB5
+#IhalHRPkIAepI(alHRTkHRTkHRTkHRTlHhaqJ)@)LBQ+Lib-MBf,LBD#IRakH(P
+lI(amHhTkHRPjHRTjHAPjHAPkHRYqJS@(L)L*LSU,M)b+Ki@%JAemHRPkI(epIAa
+lHhTkHRTkHRTkHRTkHhYmIi1'L)L*LSZ,M)f-LSL&JAjmHRKkI(amI(YlHRTkHRT
+kHAPjHAPkHRYmIi1'KiL)LBU,Lib-LSH'JhpmHhPjHhepIAamHhYkHRTkHRTkHRT
+kHRYmIS+&KiL)LBU+Lib-LiL'K)"pHhPiHRepIAalHhTkHRTkHRTjHAPkHRYlIB#
+%KSH)LBQ+LiZ-M)Q(K)"pHhPjHhepIAamHhYkHRTkHRTkHRPkHRYlIB#%KSH(L)Q
+*LSZ,LiQ(KB0rI(YjHAYpIAemHhYkHRTkHRTkHAPkHRTlI(f"KBH(L)Q*LSZ-M)Z
+*KS*qI(TjHRapIAamHhYlHRYlHRTkHRPkHRTlIB#%KBD(KiL)LBU+LiU)KS5"IAa
+kHATmIAemI(YlHRTkHRTkHRPkHRTlHharJiD(L)L*LSU,M)b,L)0rIAYkHhapI(a
+mHhYlHhYlHRTkHRTjHRTlI(q$KB@'KSH)L)Q+LSQ)KS5#IhalHRPlIAepI(alHRT
+kHRTkHRTkHRTlHhaqJB@(KiL*LBU,M)b,LS@"IRYkHhamI(amHhYlHhYlHhTkHRT
+jHRTlI(q$K)@&KSD(KiL*LBQ)KS@$J(emHhPkI(epIAalHhTkHRTlHRTkHRTlHha
+pIi1'KiL)LBU+LiZ,LSD#IhalI(epI(amHhYlHhYlHhYkHRTkHRTlI)#$K)5&KBD
+'KiL)LBQ(KS@$JAjmHhTkHhepIAamHhYkHRYlHRTkHhYlHhapIS+&KiL)LBQ+LiZ
+,LSD$J(emIAepI(amHhYlHhYlHhYkHRTkHRTlIB#$Ji5%KB@'KSH(L)L(KB5$JS"
+pI(YkHhepIAemHhYlHRYlHhYlHhYlHhamIS'%KSH)LBQ+LSZ,LBD%JAjpIRjpI(a
+lHhYlHhamHhYkHRTkHRTlIB'$Ji5%K)@&KSD(KiH'KB5$JS"pI(YkHRapIAemI(Y
+lHhYlHhYlHhYlHhamIAq$KSH)L)Q*LSU+L)@%JRpqIhjpI(alHhYlHhamHhYlHRT
+kHRTmIS'#Ji1%K)5&KBD'KiH'K)1$JS&qI(YkHRapIAemI(YlHhYlHhYlHhYlI(a
+pIAq#KBH(L)Q*LSU*KS@%JS#!J(pqIAalHhYlI(amHhYlHRTkHRYmIi+#Ji1$K)5
+%KB@'KSD&K)1#JS&qI(akHRapIAepI(alHhYlHhYlHhYmI(apIAq#KBH(L)L*LSU
+)KB5$JS'"JApqIAalHhYmI(amI(YlHhYkHhYpJ)+#JS1$Ji5%KB@&KSD%Ji+#JS&
+rIAalHRaqIRepI(alHhYlHhYmHhamI(apIRq#KBD(L)L*LBQ(KB5$JS1#JApqIAa
+mHhYmI(amI(YlHhYlHharJB+#JS+$Ji1%K)@&KB@%Ji+#JB&rIAalHhaqIRepI(a
+lHhYlI(amI(amI(epIRq#KBD(L)L*LBH&K)1#Ji5$JB"qI(amHhamI(amI(YlHhY
+lI(k!JB+#JS+$Ji1$K)5&KB5$JS'"JB&rIAalHhaqIRepI(amHhYlI(amI(amI(e
+pIRq#KBH(KiL)L)D%Ji+#K)@$JB"qIAamHhamI(amI(YlHhYmIAq"JB'#JS+#Ji1
+$K)5%K)1#JB'"JB"qIAalHhaqIRepI(amHhYmI(amI(amIAepIS##KBD(KiL)KS5
+%Ji+$KB@$JS"qIAamI(amI(amI(YlHhapIi#"JB'#JS+#JS1$Ji5%Ji+"JB#!J)"
+qIAalHheqIRepI(alHhYmI(amI(apIAeqIS#$KBD(KiL'KB5$JS1%KB@$JB"qIAa
+mI(amI(amI(amI(aqJ)'"JB'"JS+#JS1$Ji1$JS'"J)#!J)"qIAalHheqIRepIAa
+mI(amIAepIAepIAjqIi'%KSH(KiH&K)1#JS5&KB5$JB"qIAepI(amI(amI(amIAk
+!JB'"JB'"JB+#JS+$Ji1$JB'!J)#!J(pqIAalI(eqIRepI(amI(apIAepIAepIAj
+qIi'%KSD(KS5$Ji+#K)@&K)5$JApqIAepI(amI(amI(apIS#"JB'"JB'"JB+#JS+
+$Ji1"JB"rIhq!J(ppIAamI(jqIRepI(amI(apIAepIAepIRjrJ)+&KSD'K)1$JS+
+$K)5%K)1#J(pqIRepI(amI(amI(eqJ)'"JB'"JB'"JB'#JS+#JS'!J(prIhq!Ihj
+pIAamIAjqIRemI(amI(epIAepIAeqIRprJB1&KS@%Ji1#JS1%K)5%Ji1#J(pqIRe
+pI(amI(amIAk!JB'"JB'"JB'"JB'#JS+#JB#!IhprIhq!IhjpI(apIRjqIAepI(a
+pIAepIAepIRjqIRq!JS5&KB5$JS+#Ji5%K)5$Ji+"J(pqIRemI(amI(apIS#"JB'
+"JB'"JB'"JB'"JS+"J)"rIhprIhprIRepI(apIRjqIAepIAepIAeqIRjqIRjqIi#
+"Ji@&Ji1#JS+$K)5%K)1$Ji+"J(pqIAemI(amIAerJ)'"JB'!J)'"JB'"JB'"JS'
+!J(prIhprIhpqIAemI(eqIRjpIAepIAepIRjqIRjqIRjrIi'$K)5$JS+#JS1%K)5
+$Ji1$JS+"J(pqIAemI(apIAq!JB'"JB#!J)'"JB'"JB'"JB#!IhpqIRprIhppIAe
+mIAjqIRjpIAepIAeqIRjqIRjqIRprJ)+%K)1#JS+#Ji5%K)1$Ji+#JS'!IhjpIAa
+mI(epIi#"JB'"J)#!J)#"JB'"JB'"JB"rIhjqIRprIhjpIAamIRjqIRepIAepIAj
+qIRjqIRjqIhq!JB1$JS+#JB+$K)5$Ji1$JS+#JS'!IhjpIAapIAeqJ)'"JB'!J)#
+!J)#"JB'"JB'"J(prIRjqIhprIRepIAepIRjqIRepIAepIRjqIRjqIRjrIi#"Ji1
+#JS+"JB1%K)1$Ji1#JS+#JB"rIRepIAepIAk!JB'"JB#!J)#!J)#"JB'"JB'!J(p
+rIRjrIhpqIAepIAeqIRjqIRepIAeqIRjqIRjqIRjrIi'#Ji+#JS'"JS1$Ji1$Ji+
+#JS+#J(pqIRepIAepIRq!JB'"J)#!J)#!J)#"JB'"JB'!IhprIRprIhjpIAepIAj
+rIRjqIRepIAjqIRjqIRjqIRprJ)+$JS'"JB'#Ji1$Ji1$JS+#JS+"J(pqIAepIAe
+qIi#"JB'!J)#!J)#!J)#"JB'"JB#!IhprIhprIRepIAepIRpqIRjqIRepIRjqIRj
+qIRjqIhq!JB1$JS'"JB'#Ji1$Ji1#JS+#JS'!IhjqIAepIAjrJ)#!J)#!J)#!J)#
+!J)#!JB'"JB#!IhprIhpqIAepIAeqIhjqIRjqIRjqIRjqIRjqIRjqIhq"JS1#JB'
+"JB+$Ji1$JS+#JS+#JS'!IhjqIAepIAjrJ)#!J)#!J)#!J)#!J)#!JB'"JB"rIhp
+rIhjpIAepIAjrIhjqIRjqIRjqIRjqIRjqIRjrIi#"JS+"JB'"JB+$Ji1$JS+#JS+
+#JB#!IhjqIAepIRq!J)#!J)#!J)#!J)#!J)#!JB'"JB"rIhprIhjpIAepIAjrIhj
+qIRjqIRjqIRjqIRjqIRjrJ)'#JS'"JB'"JB+$Ji1#JS+#JS+#JB"rIhjqIAeqIRq
+!J)#!J)#!J)#!J)#!J)#!JB'"J)"rIhprIRepIAepIRprIhjqIRjqIRjqIRjqIRj
+qIRprJ)'#JS'"JB'"JS+$Ji+#JS+#JS+#JB"rIRjqIRjqIhq!J)#!J)#!J)#!J)#
+!J)#!JB'"J)"rIhprIRepIAeqIRprIRjqIRjqIRjqIRjqIRjqIRprJ)+#JB'!J)#
+"JS+#JS+#JS+#JS+"JB"rIRjqIRjqIi#!J)#!J)#!J)#!J)#!J)#!J)'"J)"rIhp
+qIAepIAeqIhprIRjqIRjqIRjqIRjqIRjqIhq!JB+#JB#!J)#"JS+#JS+#JS'"JB+
+"JB"rIRjqIRjqIi#!J)#!J)#!J)#!J)#!J)#!J)'"J)"rIhpqIAepIAeqIhprIRj
+qIRjqIRjqIRjqIRjqIhq!JB+"JB#!J)#"JS+#JS+#JS'"JB'"J)"rIhjqIRjqIi#
+!J)#!J)#!J)#!J)#!J)#!J)#"J)#!IhpqIAepIAjrIhprIRjqIRjqIRjqIRjqIRj
+qIhq!JB'"J)#!J)#"JS+#JS+#JB'"JB'"J)"rIhjqIRjrIi#!J)#!J)#!J)#!J)#
+!J)#!J)#"J)#!IhpqIAepIAjrIhprIRjqIRjqIRjqIRjqIRjrIhq!JB'"J)#!J)#
+"JS+#JS+"JB'"JB'"J)"rIhjqIRjrIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihp
+qIAepIAjrIhprIRjqIRjqIRjqIRjqIRjrIhq!JB'"J)#!J)#"JS+#JS+"JB'"JB'
+"JB"rIhjqIRjrIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhpqIAepIAjrIhprIhj
+qIRjqIhpqIRjqIRjrIhq!JB'"J)#!J)#"JS+#JS'"JB'"JB'"JB"rIhpqIRjrIi#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhpqIAepIAjrIhprIhjqIRjqIhpqIRjqIRj
+rIhq!JB'"J)#!J)#"JB+#JB'"JB'"JB'"JB#!IhpqIRjrIi#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J(pqIRepIAjrIhprIhjqIRjrIhprIRjqIRjrIhq!JB'"J)#!J)#
+!JB'"JB'"JB'"JB'"JB#!IhprIRjrIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(p
+qIRjpIRjrIhprIhpqIRjrIhprIhjqIRprIhq!J)'"J)#!J)#!JB'"JB'"JB'"JB'
+"JB#!IhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIRjqIRjrIhprIhp
+rIhprIhprIhpqIRprIhq!J)'"J)#!J)#!J)'"JB'"JB'"JB'"JB'!J(prIhprIhq
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIRjqIRjqIhprIhprIhprIhprIhprIhp
+rIhprJ)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'!J(prIhprIhq!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)"rIhjqIRjqIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!Ihq
+!J)#"JB'"JB'"JB'"JB'"J)"rIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!IhpqIRjqIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!IhprJ)#!JB'"JB'"JB'
+"JB'"J)#!IhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(pqIRjqIhprIhp
+rIhprIhprIhprIhprIhprIi#!J)#!J(prIi#!J)'"JB'"JB#!J)'"J)#!J(prIhp
+rIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhjqIRprIhprIhprIhprIhprIhp
+rIhprIi#!J)#!J(prIhq!J)#"JB'"JB#!J)#!J)#!J(prIhprIhq!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)"rIhpqIRprIhprIhprIhprIhprIhprIhprIhq!J)#!J)"
+rIhprJ)#!JB'"JB#!J)#!J)#!J)"rIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!IhprIRprIhprIhprIhprIhprIhprIhprIhprJ)#!J)"rIhprJ)#!J)#!J)#
+!J)#!J)#!J)#!IhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIi#!J)#!IhprIi#!J)#!J)#!J)#!J)#!J)#!J(p
+rIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp
+rIhprIhprIi#!J)#!IhprIi#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIi#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#
+!J(prIhq!J)#!J)#!J)#!J)#!J)#!J)#!J(prIi#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J(prIhq!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIi#!J(prIhprJ)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J(prJ)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhp
+rIhprIhprIhprIhq!J(prIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"
+rIi#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhq
+!J(prIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ii#!J)#!J)#!J)#
+!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihq!J)#!J)#!J)#!J)#!J)#!J)"rIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J(prJ)#!J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J(prIi#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhq!J)#!J)#
+!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIhq!J)#!J)#!J)#!J)#!J)#!Ihp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)"rIhq!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!Ihq!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)!!!%0!!!%!!3!&!!!!S!!"J&%!!!!!!"3!!!!!!!"$&PE
+ZLk-!!%-8!!"$&3!mJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!Ihq!Ii#!J)"rJ)#!J)#!J(q!J)"rIhprIhprIhprIhprIhp
+rIhq!IhprIhprIhprIhprIi"rJ)#!J(q!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB#
+!J)"rIi#!J)#!J(q!JB#!JB'!J)#"JS'"JB'#JB'"JB'"JB'!Ii'!Ii"qIi"rIhp
+rJ(prIhq!Ihq!IRk"J(prJ)"qJ)&rIi"rIi"rJ)"rJ)&rIRprIRjrIhpqIi"rJ)"
+rIi'"Ii#"J)#!J)"mIS4pH)"rHhemHhepHhTqIAYqIAk!IAf"JAjqJ(prJ(jqJAp
+rJ(q!J(jrJ)"rIi"rJ)"rIRjqJ)"qIB'!Hhk$J(aqJAppIRq!J(eqJ)"rIhjrJ)#
+"Ihb#KRYpKi&pJS#!K(pqKSCrJ)@%JS&rJB&pJS9pIB@&IAb!K)*pI(q#JAf"KAp
+lJBU!GB+(Hhb'J(f&Jhf"JRk!K(pkJBCiI)f!GB'(K(q"KAPkK(TqL(KeLiYcFSU
+*G(q)H(b&Ii1#G(H1MRCbJB'%M(aTHTH-DhQ5I(H0IR+(KA0rM(PcIhk'L(GcHBH
+1G(',J('"JhGmLRT[KRTfN!"pFi4kI)0mIAafJBClIS4pJB4pKiTkIB@*MhaZIBU
+-I'jrLi&cFRamJRe`LBP[HiU*H@k%QS&VK*L+EhfEJ'f(MB&iFAD,LA"jI@q0P'K
+bQiP`K*5)JBH%LBejHC@9Df@JS9YMPB4UG)'"IB&pFAq6JR+(M(+#RS&aMT4rI)k
+*H)#%GAb#GhD!IfYlQR*NRBGIMTTVGTk*GC!!LA#2RR"ZPB*UJSC[GiKbG)afCS1
+8Hf4qQ)CaJ*H)HC'CJ(Q'MB*fIB&dGAecGACbH@pTG)5+E'Q3!)YlMSb$JS#0N!#
+&IAD'N!"eFBGjEAYcF(pUB)1$FhTmK)GpL*+0LB#(PjH(G)@8JAaeDhjfBh9dCQe
+mKQeBKjpjFAU(R*1"L*',M*Z@HhQ(JRq%G@&XK(GID(KlHhT`GT@'ECLSGR@XVS&
+qQC@+K(Z2Lf*VHQpfE&plI'CbK(aXGiq-IAf-R*f3!)Z9Q)Z-L(Z'MB*XA(#$GQ9
+NF(TfI(pbDA@9PATpP+1@J*UUJ@b#R*PZBhpjDR4dDQp`GBTe8AQMG&L,RB+%QTk
+2LBq+L)U#JieeD)Cf8'U-HeGMJ(GZEh9pGA#'RiefMDLGIRf6Lhf3!*&aERajF'j
+XEhTfE(CfERGbGi0aHTZ5K*DGN!"rKjf'HjL-FRC`FApbDA&pH9eYL@pKH(KVJjD
+"KU+9LTL5J)LINAQ0KPejS(eEFSCmGR4RCRKfB'b0K(L8Qib@QBZ*LSH-NiplE)@
+1ER@5Gf+!HPpaFeaUIR"`N!#@JSqLN!##N!#6Kj@BJBH(H(q,L(KeI'pVH@YCA@C
+jFf&rR)q%N!#GNi5$LD'FG)#IKh12NAYpHfpSF(0E@QYHCBPpDC+NL(k2PRGpUjK
+pNS*bS*p[HTKk9Qk$CP"GEQ"AH)YhFSDESS9YKk+MMhQ-QBk8LAZHS@PKIR9TE&Y
+1@f0`KAjUFjfVJ'b3!*b6PBarKD5JHC1hKQ5%K'*QD%a@Ef*GGiPkGT1@H)1KNB1
+9QBk6S*'B[TGbSip(CT&D2fPF3h@&AR1@FQQAQQjZVV4cGkZTNTkfU)U"K)&cCQ0
+F9&9FC'KZHRjUCiq3!'9rVj4jN!#HT,5PMDh(Le5)U&`pEfP#@@YHFhY9AT9r9iL
+CFiZNKSqrV)HhcTU2Q(TaJRP33&aMC'Y4AS"TAQG[K(GmR)0lT,+PRUh%UiZ6M(e
+hCeY989KRDPYADA"L@(D+EA@@MRqJ`jkAeX@EVjZ&LRGf@$TTFdG2DQKE@@9DAhe
+bFiU"MV@JN!$*eUHZc*YYKjCk9dY@DR&66QaM694TEPYQLhj`Sl@ATFV5ZE+hT*1
+)IATS69TfC8T2Bej29eC9CAKfBhqVTCbUaFc$bl'BPiD(L@C2BQpI9PK@68K@A99
+5BS0eAk$"QD6%dZ'mP,'cMAjeE@*QFf**8ej(29*94e0kG9"dUU5UZ,6@jVbNVlU
+9FSGbAi*R2PYM8$mV6Q4'6P9FGhH-Tk5c[GMXVU$AYB1)I(KeC'PI89K006e(89X
+i4RaXFCLGVF62h-r"aV+QT)"cKS"Q@@4U6$ir0%G8-M9HC@9fQ+QUa0,1f-V!`k+
+CPR4qIeeeIN)e@88M3PSi+8pZDhLBSV[CbF6HcmE#NTUVIQKhIR0H66dl46%Y8$3
+H@faHL+5DYq65Zq$SZl1bQ*H*DA+$G%Xp6NFX)N&*)cGKB@4qTX2!aG21iH$%Z)b
+8[RT'G(YQB$`U26XR,$3S5R"@G+UYaq(FdZ$dflLVSCf2A&"fE%3c,bJX3$)E,8a
++8(D'PFRB[0([f0RU[DZhQj9iBiec9P8Z-8Bc("NX1#dd@(f8Ql(#[Z(cd-r0Ylq
+eJQq6QQ&1CN3X6MiB-6dV1NpULk1XUEhFiF@qdlbHRi"bJR"dG%a19P0F0b&,8$j
+$5(5IPTbVY-l8a,bmZDfaQR@@TA9aH&T)@9`K&dFX%6G(9B5-K+R)cXh0cFR&X+f
+YLBfCJ(TT8Pe0068k4LNJ9PGFMSqAXlR2[kE&[U1JRTk+KTb%H)*cF8i`683Y,bi
+[0f@%BhZcVE#p`mh"aFQ`[VH5Y+KaI'a155dS+KFE*#ip8S"qJX6'SVE+cF1MX,b
+*Kkk6FBCq8&9N5$Y)589$9Q4QJBq8Tk@LXE#VSkLRPD5DKCZEL)*M594'1cdH+$i
+Y8'pKH*QPUlV9`lAIhm#cVmHVIUUJ8P&H0L-V&4Fr,aK+HAQ"PTZNZEbjYVZjTkq
+aS+#6P+1"Bf0G@8)p68&(5%aeI("hKjkDMjHQ[E1JTkbkXDDmPeeeI$id65J826i
+V5fKJHCk@P+h+aVE5flLZb-fSN!#PNeTH5b9#1K)N1640DQeRFC!!PBQLZ*kC[X#
+QXF5`UE@PNT&qA&CM6bBm@5ibCP*3H@9@JU1@Ll$&VlRFem$"Xk@4GRC1+dJk&bF
+q2c93C@'1MfHIekbCb1+lS-MBXTUGMfKRBMT*@b!XEP%kD(&8E)YXDU1GFC[#S*U
+jYUHecl"pNTG`DQaG6da69dC0CNa1EP4SViPNXm'G[-qiUm2#LSb2A9KH98%hB9B
+TA)03AC0hCTbeMSr-Zi1[`D'`SSClFS&f9NYAC'9VA&4lGPCKE("ZFT+4JTbPQk'
+EXG+YLCUPNheVHAa18QTA9f*&,9*V9@5'HB5dZDQ`YlV!Y*D5T)9VE9pK@&*939e
+b9eYICA4dN!#VQSkF[VD0TVb0JT1-M(&JHQYLEePTENYNE9"+8@jlEAkDQC+KXD5
+Vf,5([-+@Tk&`F(KK6e&,2Mib06e)AeC`RC!!M,'qT+M0[SqXaj@1U)alGh&V8R9
+e3'YV0QD)C@1,N!"THk'&JT*iJk19MCHJRi#3!+D!G)4mEPpB8dYMDNPLLfpMMj0
+qQlqQR,Hca-HMRj!!L)pL9Qe@3cNk6$p(A%YaRA4`Tjf&UUf3!++XT,HhRSb6S(a
+IJTPi@'CVAhCY8'YVAR4Y9f4rG'*rQBqCYDfPZl+5KBkHLPp@G'%mAQ0$6ejaC&5
+3!*U&RTQTZVEIbjHcUiZ(CQ&cAdp+4dp09Pj4CRGQG)*fJjq'E+qlL,I)RTqKQ)U
+,Q)CpK@pkM'aN@NaUDP064Q5&APk+N!#9Ul1USlUQJT+-Ghq$CeahG@KV9PeqFQU
+#M(q3!,+DL+qiSk#6K)b!@P&VF&CFG@9RKhKSIh0ZLB*lHhU4LS#@N!#5UD#&L+#
+9GB1AKS11Ji#1FPpkANYQ8e9aA@'$HR58R*ZAN!#VX*H'J)L@NRPaMjKaCQjYG@C
+VGQ"pPA+&PhQ1Rhq%Nh9pRRYFEi15I@f2JQH*K'GYGhGJCiaeFjTqFD+EKk+8LU@
+DJiHAQBZ"HS+2ENpH9Pjc6%e`DfTmJh5*Rhk'YCTrSjL'Sj@$Piq(PjChEhTZGh&
+NI(akG'#!LQThF@L2Kh+#IB@3!)H'L*Q@JT!!JA@&F('$CA@KDQ@JIh'3!)1!LBH
+0LTfKJSf,FibTMeKIK@92D9p6EhKGDSGcGiL"J)@JTSQ@[UQ3!+bHMU'NMhQ-F6j
+`INpKD'GE6Bq!5RpX8+16AjH[P*!!SjerNkU*Lj!!FR*LCSTbAA+*J@U(NA#+Nf*
+YR*@2XijRRU'#L)"bE(ab4e0[9&4[FA&MBT'+F*&dGUf0T-fiUil%fAQJ`S@'EPY
+Y@9GF8dj)@eP1F&j,J(*8J+'ENU5kXjqEREUmIB'EI@TmM&eCNh*1J)YT8fL0CNL
+,VipqMkfINCq4S+P[Dijk6dq0E6"fDNChBPTlHfYHQVq'Vp+@XFR!b)qFY9U'Y%*
+5INj188p*A(p+-h&k@&Z!Q)@)VTq)RV5pRSZMTD5)G*q5C(')HQf(GN&GK(9PAfb
+#JRq%K*HUQif+Pk9eBSGZA@9(@PT)LAp%DiQ%N!#9P*He[k@bXUc-XhGrUCYH6Qp
+K05a5HPNpF(&CIhGLHAPiJjPlAm#jE,'hKlh"N!#5QiarJhGNNSY,E(pIBfeZ8cp
+ZFeb,QikNRT+VZCPcHSCq9bKDN!"C2(''GiZJNSDZVA5DXBqYXBqIPhZ4N@0CAdF
+rAf-dCDeRAkUPJAfCKeGbI9P[Lj!!N!#&TEHSX+1IU(aRHS@)D@&fDfalFR"XA@4
+hE&H!YCD*[lQ5U+*cGQa35c8mAQ"QFS#HTk2%c*LF[Tb"L)Q8MfTGHiG[AeYHD&T
+-Bi#-P)k8TS1"ThCGIfe-5PpkFAUBMkM4XTkcXTf%J(T2B)9H6h"dD(YmAAkdI81
+*`ijhP)b8T(K6D(TL5P"15@q,Gh@efkUak,0cVGCf1hGqA'05@B1"Bf'AP9aaL(Y
+qIRpeHDZL8(DM5'QJ5&+6JAQ6UCZEi-jiR,f'GATN8&YQ4%@+P&acTj&iKT1$Kjq
+$Eib-KSTaEReI8QpN@PjIKi0KSHA&QU62[(Z(N!"bDfC95Qb+FRfCMi9mMijMISa
+RC@4[M)KL5h@$2NZ*CQ'6JSl5dF2IfE'TSBU)8bjX@b"5E'4rGS+LP(GVQDYSCk5
+*3@HcDc+&H6YCF'0TPkKhR1'hVGDeQDQ*F(TYAQ*YD@4YI*1KNB@2JQChG8G9FP3
+p8A"RBRKcFS1BQj'VYUZcTkc5`CbIQi"iI'G9Bh"B9B&p@RZEGPPLD9jDF(&8DBG
+`KTq!L*Z8PSU'MhZBZ)H6[l#STk'1GCDK4%#LILj-IP`PGjNcAT9BGSjNKTq"LTQ
++GhQAI&k5QAGcNm#ANpZXLXD`L*Z9Gf9N4bG)9L8[G(a@Dk1PMCUZP)HMM@*rKPG
+AD@GUJ+#'HDqRR,UVYmfQJiQ8GdeAA$Bq6MpFFfjkQU1$RFLEIBPcChKJ5PGFDRT
+ZECA$ViHbil1)`XKrJ(T'8Q!r4QK21hD2BA+cX)b@QjfMJ)L$8A119%amGfb'FQQ
+FTk'SRBf&RBT0AR45DRp,@U#IK*qbQjkXMSbPJfeXEB"QARGKEBaT@A#0MA+#Ihk
+LM'jmHfekIQCdLBDCRS#%b0b3!(bbUATSBfGaEP41G)0aISQ(LS#(Heq)M%T4B&H
+!H8eeRiq*QT5Dam1,MF$&Q(f5SSTI5Q0RCA0KHieGKlGjDjZLF$a9C$T,A6YBGQf
+6SC+ZcXLMRX,&TB*mUE"S9S'$M'meG*4YJ(&dL'PhL@T8A'eD3NG0@9aQMj@4XVU
+XVG,JQ)h%UB4mKTYeGjCiHiQ'H95"Md&`Kb!rH%Be2&&D9@jFDjq@Pk1ki-Lk[+[
+-b*UUTRYeJ)&TETed1A5@9%4cE%P54M&ME6KDKQPXNUUbTDDmZUH8NDk[MQp`Pi9
+NIS1&NhKbP++-KCU&G(KYD6SrH%8ZB&*3H(b"KT1fP(1`ZReaQDk0H*'FKS+NVD+
+CQE@cLAk4RiG@18",0a-22&Sl5SebGFkkRVl"ZU#5NTDbR'GVLi*hKhU$P(YpJiL
+0Ij9i8R4S894*4PeV69'(VV@YY,1V[jk'TS"38dpHC%SqCj'"JkZpTCDp`*5FUCD
+#E9pQGP8R29GC@%eSLRq1TCfYYTfLSSL3!'e9K'P3M+@(JDl!STQFN!"hE'")@9%
+d89a6CA&VFk#YLj5`Ul1p[-+fVVq24'&a3Lm`2eCF5fUVIPZka@eVPiGZK*@%H(f
+3!+UmRh#2YTG[BRL2FQH(Ff9m@&f&@e*iG(L$DRHiY)U6UTf-U*0DIhp#DT!!C&G
+qKR+'Nh*aPTD$Ii'&Kj+,L,#ZKC@SL("qDNGK9Lj8D%06HRTdG)12IC!!TTHXZ+q
+PSG6&LULEGi9U8PCUGeY`P(jLE)&F3&K40$G@E(GlKkqi[-c-bV'p`S#-YC4`D(P
+Z5ea9,Mj59@9SGSfRYD1ablU5G)U*A&YQ@&pbER9kFjQdPSKfD*'3!'PeN!#,B&b
+ETRZ,Uk'KTTUFPiZ4Qj0T4PGD3c3G+die+PpeLEQaXGVQfFr9cVHPIR#2HNKCG'0
+PGP3mD)"33'pY9QGZJCb9KAkGVB#%V+5CSUQPQ+#iRAb%C%GE5LNe@'pIARZ0UUk
+BQUUlS(U(I(UKK&YhLReM9fGXH@8d@(p`Ij+$JV#kLSD[bk+)T)QCZ(9eVijJCQ4
+$-8G20c!`3h*ZDERGT+64ZTfeZCf-MiCdJ(U)VhjLK(*JA90HC9Y469eaG)"fE*U
+3!'f0Q*qUVYR&TG$0S)&lJ%mJ*b8L1%43Dhf8YkUPcEkKVU#"JiprEhfAK&4EEfK
+cC9C`GAapGTQaRi"rK'CIG(CRDiqLPD(0bEhAZBKfA&T5)"Bl3#BX9A*mMjH+SXk
+hNV6EfF#GUlfDJS"kC$e!86T#B@CbJi*hGSk+BQ*`FQ"'FC@&QlbrZ,R*XC@`S(9
+iB6e4F'pF8faN6h4S6BbNI(5@VU1MYV1PS)KSFR&-9fe58h9jJBk(LC5'C@Z$J(U
+"LBkTZkfRUELeMRTXC@j6-d&FBP03B(0dBQprHi52LT1VUVcA[*58XDf'GhKpG&K
+LFAD+Jh"XBeC29%dk6RCX8A@hdEUddpI!VjD,PSGM9PYC8fGb9&9hF&48CBHbN@q
+aak'RX*fAP(&3AQeCEB9FC+qXHibPNRKS9dKHDP&@E)#HPiDK`F#YS+1PPTD6D&q
+)LdddCeic2N&#Ci*iH+6$`m'kY,QkMQL$H%j9B&pFBi'1JAk1PiKUBhKpE'"VKiT
+dGj+MNAf0PjDEP)Z5QjQ(KC&`@'YG3cBc9f&0HCq4QkDS[UQ9V*&rMfaLJS9lHAf
+"HRD'JeYVMQ4KMRq!QSQ$LS1&LB9qFh'*P(GlR*U"Gi+(HQGJC@9I@'&fMjZ!KUD
+SUBf$U*KpPiPfQ*0dIj0pCRjm68aYCNY8EQaULiGSLCk2Pi9pT+5AQD'YS+1IKjb
+BA9PZBej28R*VG(Y`Q)TFHBejDh0jI)Q%Mk+8QTf,RT9`H)"rG@H!Ih+-NS0aChP
+lFhejJTD2NjH9TjjiBhZ%3cYa96YSI@eaNk+-M+#-Lk+#M,bCKU5GPD'LJR+)I@e
+aD'CTE@jTB9TUEeT*8Q4PCh'1TjDGb-A![TbU[TZ!IAebCQ4KDh*fGA@(EPPpJhT
+aCi&pG)CjL*YkI)0XK*!!JC0rEC@JQCk2KTq,6(542NZ4F'Q8P+5bR+5GKSPaCRT
+K5'*VBh4kGRaiJ)KMEjb+IikDYV+BTk+(M)&PB@j[A'k)HBUMNSZ-JfKKF9G3C&e
+VGh13!*bIU)q3!+kBL**rPUjfEBqCL9jXIPpMBePEB(PpF(H4QSQDQA+&N!"RH(p
+DJl#(F*@bUC5DTCD%I'KHIAa6D)&PFiG`EhGrJ8p5IfTNJiqFUCk*QDQ&GT+#CB@
+)DTDlRB@EXSaREA&X@%TEDR4dHBf0JRpmG'4FBQTTC(bERTqGTEZPJBfMNSL3!)L
+&RU1*P*&ZKi&*9Q426f0N5@kLD9+*E&'(H90pK@H#Sk'XcG1l[XZdT+qTMA0QC@*
+EAeYHDPG)69ph984`G'*PICq@JSqUU(YfVTpaPU+"RmHUSFLjM)'@Ld4(I9-V@RK
+YG(4lNheHFB*G4fTVESb%IS+3!*TpJ*1%FiLMMBLfd0A&U*q`UA&FF@C4-cGkD%"
+iF9L(DMK@DQCSBh#$N!#SV*UF`,H&TEb+N!#GQE@MMDbjPfjrNeB[6%Xp06TK8NC
+kF9aqKhjfICHAK*!!ZEbSVXl2PTUiMB5)E@aQEi*IED*q@hb!D9jDBQ*45f*YBR#
+8Qik3!)b,MSk3!)'DYi@,bUQBZ*!!Kj4SEA"8C'PbJ'L!V*Q#I(Z!@MY38dC!4QK
+qJ)1&RV@HM*qfYk#J`,bRZmDHIiZ)B%G*88Nd1PTaFhU"J)jb8'CTA&aCBRLAQ*+
+ecX,!d-LKPV#fMA#1R(CLD'4B5N8k(6CJ480XKjQ@Q*Z@U+H*IR4aI(&UKCqRT+'
+i[DZNMj'GHfe[C(1!F9KMI9Nl@@C*3fjd8e+#Z*q&UCb(RiKUIC')FBLkXDA'e-H
+[T+5'F(GmB%&5@NaA68*E5MC+15eMGf0rRUE!j-qIb1QULULYPjL,IE+iH(LFJda
+LIcd[@dmr4PTLD(aY@@*`IA0QIjqHMC[%bkqVaEbDS+&fEC5%@@TrJ)KiJCaqF)9
+T4f9j@&KP68aKBepKBA&jBR+,Mk+HV0c1YpEL`,#jQA4kE9TVHhGLDh0DB'YG66d
+f1$9&C9P8LC4rL*ZYUk+ITX$%YVhHilZbV)f(D%TB66Nl6PC'9RjbBAKaDRPL9R*
+rG(Q*JiqdRALCUjk2JTqMPl@JPE16LCTdEBad8@0Z68GUFQjrGQ0XGRpR9(GZ8A1
+-Fh@NYjk8SE5rVU+aYCQ3!*f*KTb5J'pIBeB[1&Fk0%0&DApmIB'9PS@*MiqFUCb
+AVlZ`VELkUj0qGQTGA&PYEdTIK&K0H'C*9eaNEfYbJCUeSC5XQSqYRRTrNTD0KBq
+KXDb2JRjZEh"B8Qp[9PCFEhYLBRKS5QYj5RLLDhQLQk+LT+qSV+L)QDD5Yl4jLUL
+AJACUC("I-LNf5PG+-%*lE&GrGhqIIRqMRTDK[,LYeXQNYUfKUjarDAU4E&0rJf9
+cC$a!6NNe18Nl8RTTCj'VSBH4UTfAS*bU[UDD`-bcTkqZMR4bFR"QCQpZCPaKC9e
+23%"%58P#9'PkK(H3!+f6QE1HUF1NSEHcYEl"ZV#NRCKiEiaQ4@C+,8j28e)j9'*
+(49"BCh0XCBURQCLfd,U`cVqLVVLUS+5AM*Q,IijqFQC(4%K"2N"19NP5I)*IEj'
+!D@TrIhb1MTbSTDkJUY#mQTZIQ*LKRBk-PSKRDR"A6d`m26`j490HCB1%BB@bMPT
+fYUCdLE@NLDE*Z*@J[kH%R*YcMj9DAA9F9@PG4%j93e9U9P"dPhT[Ul#2TEDEJSb
+VR(L'Q)Z+N!#)QUH5N!#6NSPbDeaQLQJl@AjJ5AGf@(4pCPKXMS'+TT+0X,'*P,f
+MHiL5I(@CTB1&Q)*rMfYDIQ9(98p8C@TIAiQ$B)5IH@f1NB5FU*HN[+bMYTjrM*H
++EQKdDR"jB8jAGACB9&jRF'4XKS0qLj@&JTqUNAb)PSU&N!#3!*1TR(D(SC'4Mh9
+iKRK96@KUA9C5@Q&YF'GpLAq(IS#MQ)14S+DBMk'@N!#fSR'(NSLINR+%PB&SCf9
+CBe)[4eFm5fCID)18KRZJVjqFSDb`VD+GUVbaLBbIK(k%GA"dL)0GCA4A8Q4@4%j
+F@8P6GhYeHAD5RhZ0[l5IUV#LU-5[NUkMHSZ9IAU0L@aXG@PI8&CE5&CA194jAPP
+kFQCrJ(D+PBkEYUbM[-2$[E'bSC@DP*q6F)@%C@YF6e!q38a!1PCJ49f+G&epNAQ
+%QSb4SD+SV+Ubam#JSU'PYT'+QS+'H'PL2eTM,6j518aN4db&HePfNSD"LCbkTBk
+TUjkNUl#5M+qDLDDQPTHQN@*RD9TK4MjA3N"@A'*FDA0UHhGZQTpmQDfDTDQSVjf
+CR)f-Q*QDSCZ9QjD(Gh"mA#jBC6T"8&KM9eKUEhb+FQ@9YCCqRVDYVV5kUC+[VBb
+BMiDDNi&TAhaa6'0P38T-3P&FDf96G*5(J)kKVCb*QCqCYUk"RED9MjfHQSq-IfC
+TDPP-9A"R5ePXC'f!FPTZN!#(GhL@V*+3!*U(LCL4JSH6PB9pPDQLS+HAIS9mA@4
+S5N4L8caUHP9TN!"fDBb'FSqELT'4Jj1QPifAP)HAUC+8XkD@U*L!K(&HB8dq5cS
+L0NG"6@efBS5`RD1[VF5aPD@LRUfJLT@DP*!!KBH@R)KbIfp-CfT(@Pim3dG$@f*
+PC''-Tj+HYmE6YD'YRTDDP)plEi+,HhU3!*@+JRPmJ'KQJQe+@fj95'GY9&*RF@4
+XMik*TUH8PULkXU@GPD5QNTLGR+LFKiD%Ff4MBe&&8N-b3dC-@&TECRPdHj@@VV#
+%TpQZRmR"Tl+fSik1QTD-J@eNC99186e$9#ihB99PF'U2Lfq4U*UAS*k5M*@PPS@
+BRjb6KjHIRk'5LSb0IfefGep89Na!4eeH8f*dFRZ3!)arN!#NN!#'PB5%RBKfQDL
+6MjZXYDDYYC@5SRYIG'aA9d)e6NBk8PP6@'q$GS@dVTq`TjUXUk#EKiZ9KBQ1KU'
+iLAHPP9eTIQ949eBl5R&C9(*GAiKqC)1VQSDMYDHDUE@JP*''LiGYHCU&GTZ6FAZ
+'Hh&eD%09FeT3Ch"PC(CmF(+1M)'5J(qYVjbCRkqdS(q,XTb!NSjbIiaSBR0KAPG
+!8f4889jVB&9YK(aiLjkHKB@cVi1DaUk8VUL@ZEH2Mj11Kfj869eA2MSh3PP46fG
+`D'jjHBQAQDDDRl#ERl'NPTqTL(LFQ)HGPi10NR*ADApN1MK+8&&EE'4YKR4ZIi'
+5Rik,M)5GU)H@UC!!NjD,PjqFNT5YS)LBPiZ&D9KI6MG$8NBm6e4'DAe4C+@GG)@
+eXBbDbF'ETlUXTUZINUbREA+@GejcDde+9Nim3P*GA9&0BAU#GRbUZ*54V+'S[C+
+C`*@1T*LFQT54HRL!G'4GAeYJBdY,FApQCi"V@B#(Bh+2LB@"LCb0KTD6P*Z0Jjr
+"TjUqRiLXPh&`Hfe066SRC(T,@hCABiTdAi1BIRU+K)fKRCkNRT@CT*bGVUZPRC5
+JRB*jFQaE-#p"-$G,4%pKDS')K*'T[CU*[,+)RkqDLC+@JSUEM(q0PhjpLR&hNB"
+TB&Y89@*24'aU1P')IA1EZ+#9X,+KRDDfQ@KiM)@0Ji5KPhYfI)4rLBK9B)KJ6h"
+eC'G[8$eTH&YMG(U2RjQEZXbYSlbAJl@THBLIMhb%I'YqL'T5@P94A8e2GR9EAR&
+hEfYbJBGqFAkCTVHkTl$"YUbRU+fFLBeh9&edE9YA4dGE1$Pd9e+#B@',MSQ$SE#
+*LCD*Mjq8L*'BTk++Um'8Rl*cGkaU1RCm48&E5#p@G'&@9@k&F'k-TkH,KCQMQj'
+@P*!!N!"iDCbiMjZrUjZJRTL5M)"U9%!k5%T&2MYBB%4AJ(jrQ*Q-QkqUT,DhT+5
+CLT+CQ)KlQDClGD#3!'q6LdG8G8ik8Na%9Na(DRPdI)U5ND#JNUr"SD+cQBqHQ*!
+!J)DJJ'4[HBb#F(plEfPEDQjJF'j66f*VDA&lK)f!FiQHRU1GN!#DUTPiSFf6HU1
+HG(5-F@Z&CNYGCepMFfTJC@PdGh"VGSKqI)&qPTH0RCU5Qk+CPE'hQjfFN!#IN!"
+JDieT-%480daJ9PeRFA4mJAkEVC&iKkHJL)ZHS*!!LB'#PjL6Q*@APBq)ISL&E@Y
+I2$eG@NG5@9jaH(L8XTD#TkqIPBHCUjU)K(9aT+GTGU@FJ(k)LSQ1L'KECQ4H9&0
+F8%aBCQ4RPjGlS,'FR+UhX*UBRT&mKTZ"GT@CKQYXLi"hJ'j[D9TXFfCRD9aBAPC
+MGQekKS1BP)QaeV5+T,UEL*QDNk@9GSH(DA"rG'426ep6@'YPE'4@DfaPGh9cJhY
+kMT'5Y-kKP-HeP+LRQkDLI'L"KfpQB@&U9$K'C@P8@A9bDAk&HSb@I)'9G@q8MS'
+DRiCqREDGRVkVND'QKR1"M(jVC&9-B'G@6e038'GTA(1,L)Q3!)Z+P*QCN!#1L)D
+DQjZVVVM!Y*Z*Qk&lDfpI58"28N"1A8!pAfTPCAL1R+HCQEkqTE@VJS#&GAU+I(b
+DPRb)QTDIQ'ePL(0%@i&`9eCPEfGSDQb%K@jkJi'KVCZ8NTL3!(H"M(H$R(j[SD+
+)SkqNPi#&M'jLFfG#2%pB8NpFCh"aD(9pK+@PK*V*UiU[XTkSTik!MBp`FiemD(C
+hDQTQEfj18f4D99KVLBaqKCfJPU#KRUfEGi19MC+@LSf0HA"XEAYfC&KGDRb0H'Z
+ARQjXNBGRIj0qG)#2K)ZVP(H#KRTZGB"qIB15NBQ2SDD1KSG`EhpVB(ahAQYbFh0
+EIC4JC)9rG(bKSBkSSSbLUSppP++,H@emRC+!K(4aGeY5B&9B8d&FE&YSLk#@P+1
+MSTZS`DQ+PkbBKCQDK)&qF'CFA("[5e#"H9KbJR&qG&CQI(YYCS1FQTk6PV1RP+L
+IJSL#H(jhM*&[KTYlF(Z(Kf*DH@pFCS#'AQZ3!'"'DA"RFA0UFAq1SDU`YUDCV+k
+@Qj1-UTjrK*!!Q*+%FQCQ88C%2%G-2d0GC9eiL(CrQT@"L+5q[D@fcV1TXkbFQCP
+fDAGcG'jdI'"JG'YF6%jR86KPEP0iKRZMX*!!LjZFR*Z+MD@0HCQ4LU18MTL)IB@
+9JAQ6JR*hI(*PKhJr8@&-3NCPF'9pJf50`U'4QU#ULiQJNjkKSE'6NEDTLBZ@Gep
+aAdYKC9P*4eeN8N*AGR9SDhb,Sl@NU-1jTkkHM*5,JB4qFQq-Ti9RJBpdC@PNBQT
+M9'4dB'*iHiq,9QQFLi#9Mi@IV)q1RC+RURC`MBTlIBGrJC5)Bh'4Gh*[9'Kb86p
+PL@GKLRYSMD*lI+'5NCQ+NjQTXTDBT*@EQhTbNBCE@@CNDh*HA(KZ89&QIhPUF)'
+-Kj'RSjbIPT@HLhqFRS'%Qjf!J+QEGhP`BQP93@TY3PYhB@4eHif+IiQ-NTHPUSU
+@Y*Q#M*H%GB@(IRG`IjD@Ji@0IR9kEeTGC99AANjDEi'(Fj!!S(16ZC1AU*QGRC5
+-KT'6KRprF'5-QQadS)PMHheBBRTX5$p@8&CeD'q2IiDPTULRTl+SSkf6LUU9JT4
+hCAjmD@PpJ'CMG'"EKhP'9("U8&&ZHR0VJT@+Ql#UV+fRX,+GQTb1NSZ"JPpZQQT
+3JAj-6R"U8PPYFfTICAU(HhD3!)K`Mjq)Nk5PTUQZPSURTBk,NReTKj!!FhQ,I'G
+QCPK)8'4C4eGYE@0qSiejN!#6Kj!!PTU6MD@VR*@GVk'6SjYlGT'-HSL,H9pQF%P
+%9N!i5dC%AfYfRTaqPEHpU)QIcUGhS+k)L*qPQSQ!I)56J(##Hf"ID&P%9&%h8eX
+b5RekF)+DQjfkZU5m`*ZNYBCUNCGeH)0kEA12N!#$L)1#LAaF8'Yb99&B5P&SE'e
+`EhD+STCrUX5ETEqNN!#AU+GqFCH0CAf4JBf0ISTlA9aIA&&)8%a)@Q9UGRZ(LB+
+8TkZSX-#fX+kYZ+@IU)"KFR9NDR4MBQTIDPp4F@**EAGM@QfFPfb$TT@9QiZGXT*
+pU,Z0HTfcRReiJRThHQeaF'CfF&46DAPP@feXCA50LA5#Mi+2PSD6TCQ)PkZ,IUD
+RNk+2ET1XKfq$M@YGEPFj5e9&6PC1A'eeHi+6PTDCPk5`UkDdV)f8STk2JT@8F@4
+iLhTYFQjjCdC089"15&C25RQ*H)kKPTqhXk#EZmZ2LVZ4I*Z%H)Z%F'4JEhplC'#
+*M&Y8D@PKBQ*DC@CPKiGhM*ULSBbDZUbBRU@SPB5CPifCIf4lN!"qE(*kHA9ZBPP
+AA9eG@djDDfTfGR+6PiZ5Mkc(TTfl`kbGTl1lThYhLAjTBfPD6@PP,cCJ5d*H@%e
+QH(1)PBQHUTbJU+qaTULhXkH6KkHhMhU$HfjcBdPQHNp%B&!h5'PbBPG`MAjjPU+
+APTq3!)#IVj5,RkkAGSkVN!#%Q*CiDSUII&pfMA&069Y928CG69TVA(Z6KSb1PTf
+0PCq9R+qdTU#PQUI#Rhf*LiGkA@0dF@K559)l1&T&19eB6R59NT'RXE1ZS+biTk5
+[ST58Nj!!S+'&IAY`D'ehBeT`DP*6AeP9DQYACR&PITU&JDHLKT1XXCb@UkL9M)'
+*Tk@#H)U&HS&pGRGhG9j59e09@9PC@@4SDi+0HBDQLAUPUTkUZ-1eQ*bPRkqEDAb
+%B'ehA@f$CePG@PG*8'4E99pSHSU*PUZBK*'JT*kCUELPMk'QPUDJHRGlB&TVC'"
+YE'"EC'4GD'TNCQ*TH(k2MS5DRBD-QTQJTCbGRT16RkQILjQ3!'"ZLQaIE@TEA@4
+95daHI'Y3BR&lMB+"QC+'PjD5XEULRUqVN!#5UU58N!"mEhKkG'pVD&pG96j"6eC
+LAPYRF(k8RjkHR)Z1TU5DVEQJPU5ENCQ9M)9Y@@TkEQTZDh&hDP"2A9pLBPeMD(Q
+8Q*19Pj14NBk6SU5AN!#XVi+,VCL,LfYVKR*PG(ChDfTR58jQB&KHA%CDMijpNTk
+0LC@HTDLXY,QRM*5TSTZFI'0fIQ9GGA"FB9*'9Ne%A'TLBQ9PKD1HPSkET*'BTE#
+rS*A$XhL"T*KeDQeKB(G`B(&pGA*V8e"X@8PfDdPdPSb)R+D*MUD(HCqYSD#HT+1
+-NCfFN@eUGQ9VJAehJRpG9fTJ8eK86Nj4BhL&P*HARTbJSDE%[Tf[`k5+QDLINhe
+RBQ0bEeaFBfKB5PKE99eKD@K9DBZ1Qk@9MTkcXjqTblbMXkQ)IBH5JfCDC@CEDR4
+XC'GqDN0EH'eMH(4@EjfDJifPM(D1NS'+Sl@ZRULMLjf[LhU0EPGhHQKbHh4X@e4
+IA8a,B&e"@)H+JT'LQSf5QBq0V,1BUm#PQD1RXU*hERKX@eCRE&"3AdT#B&Sp8R0
+X@'b@R*bdZk@CT+5ESkZRRCZ4IS52M)L&F9pZE'&[FQGA@'"0@h*6AiY`6A'RTCD
+JQjLBP*59RjU4SU'3!)Z(Lj''IAPiJ(plKi0aFA&J894@3ceDAe&IGSU*ND58NU5
+CN!#@V-'dVVZbRC1CUTKTARPe8&0jG&KD9NY95d"5A&TC9h'5PUDrX*fTXDDETlH
+aUk55QCf2MB&hH&G(B@PK@eCDCfYHA@PSFS*T8A'8NSq6NT@CPSb+Q+DSPBQKUik
+*Qjk9KAepF'q)J9P2C@K,3&"BA@"ECA4dG)HBNS50QSU)SV'bV+qpYDHIRD5BKRj
+RChp`@eeB9P!h1%Fm39TQB&b$UU5QX+LNUU12QUZJSU@IV+1#MDU0C'ecA9j`Ef&
+PF@GE@eCCAfCVBPjZM*U9R+bRQjL)L*fFMSL6R)k*PU#GMBD(IRGlIRTeF'KMAPT
+8699NA%G2E(4iKBf5NCbYSk+m`UkNV+kQN!#&SU*fF)Pf@A&rA8YE9$a!88j0AQj
+ZCQq-R*D6S+@6Pl+cVEUkUDDZSS0dH(KSA9P6@f0UH@p8EAj36@YMDi+!FR@CUif
+-Sj'%Jh1#Q*'@TD+JV*k0RD1-FQ*TE@K`HA"PEA9Q6P&XDeGBB'*cJS14QT@8LiU
+BS+LGPV@dSDq[U,'SN!"hGS0K3Q4S28G80MeC@9*KH(0ZHBLNTC+GX+kERVU`QUQ
+URjZ-JRq-MhKeF'KcE@GaCP06@Nj!8f9THRphKC!!PkHJMC@HN!"pLD@LSUL9R+D
++Jiq-KRTZE'jeL)TXF)0K590*5eY56f0UD)#GQSUFU)Q-UkHNUU#R`,DBP*ZCPS0
+TB&YJEfKHBPpFBee)4ejSA9THDAk)Mj@AV+qCSl+XX+fRX+@CN!#"Q+"jE'jKA'*
+RC9a1A(051@"eCfYqIQafP)b!NT@+KSkSTjDXYk+MVD++JTLGIh&`CQb!G9TEAeC
+956j9C'"XGA0rNjH1N!#9Nj!!LT5ER+k[SkfZVD+#N!#YK9pUG'jPE'j@AQe33%P
+09f&QB@U,Ki5VT)kUU)Z5T+58RDDCT+Q8KiQKRACVD'epEeaPE@KJ6Na@8PC9@(&
+XDiD4NTZVUT19YEkJPVHeR*f5JT+LM@CXK'aJF@9LD&TC@Nj'9@GB9R"lFQarPC@
+@RTZAUlURTVLfV+DGK)@BLRCZG(CKB'0THPp*Aee*5e9HEhCXEAk)Kj@HJhUBVDL
+AS,qqVEQZND'IJS9mEQaC@A&eB9"GEe-p8eP4Ah&fDR'4QCDHPTQJMj5MRkU[T+U
+fVC+2TU5'FhGS8@9b@8jDAPG33N0JCPjSFhPqLCbEQ,#SLD@pQjQ[RCU`TSk1NT5
+HL@GfK'48CQC09@)q-PPH5@5$DQQ,MBUAU+Q-LkkfSTUVVjqRViaiMCZ@K'jhIQ0
+SI@YJB&C83MK8@8KVKf4JLD#AN!#DNBqUTCDFTDkbVU1PRiD6UBGRFhKMBh0S@&j
+L9NY%2NPGDA"N@hDHV*Q3!+1VT*qGV+qJUE+MRjk4LSfENfG3CA&E9&j34@&N0$K
+TEQCcG(1&PjbBQUHVUDHBSDqEQkUBPTU#IT1CMhjVE(KSAQGD8Q4I1$9GE'&NFA+
+"PS'#U+D9QCU8QkkYSU+RV+H6KT5JPSCZERPNB@eI8e*13$G#590RCQ&fK)HNV*L
+LY+HGUl@SSkbVX+q(I+'HKApR9f9K99pI4P"`@$K)@@&VD'TcJT+,PE1RPk5QTD1
+BPk5YR)kEQBH+PT0lBQGYB'CK6QGa8N4'8fGPBh0bCRD+MT+ESCH3!++[Sjkc[DH
+IUk54NDLSGPebFPpJAdT-@P!r180-8fK[DA*jLTk@P+DYSTUMX,1ZVlbmU*qKQ*1
+@J@aR@P*BAP9'99a'4%T'A(0UEi0lJU#KSkZFQU#4QD@@S,5LQ+HHKjDSM(&cFQ&
+CCfYG99YI8N93BeaCFAPXFBZALBZPSif(RV'GPV+aRk1TRjHQUBjpG'e[DQ&D89"
+@8N)j39"MF@GJGiU4QTQATDDBQUHTTE#fU+'LNSLJTRpVF@GGC@aG5P9P@N3k3eY
+fGPjMJ*1ER*QETkD4PUQHNk'ZST@HQ)b8N!#&I'4JGh&CAfKcGeY2B&P6C(*aBQC
+rLSb4PTUIPBD9Sj1BUU#CSjk0ND@IK(PhF'j[DQCHAA"S4NTFAQGQCh&TGjL6K*b
+`P)LNV*qLVkZITDU@Kj+5J(PiDePDD&a5A9P@@9"4BA"pIA&fN!#JQTLPST1BT*f
+6QkHNQjD9PBU$MSGaCepJE@YA@h0S@'"C9'acDA@"GhQDTT18QjHANSq8PjkLQTq
+PPSqEQSk%FQKVCeT5@@4L9&"C9NpCC@eaF(@(QT59VkqAQDZSR+5TR+1bSif1QTD
+)GfKLAP&1@90&9@"-3&CTCQTfH(f0PjDDUV+NR+5RTTkCU+H@PT5+NCD%G(0VCfY
+E8Q9M5P4I59*X@&4rLR4mPTQ9TUL0Mk5NQTQLSk@URTbRR*+3!)"cEh&cC&9JC9C
+A@8T,@P4)AhabD)#BRD'NR*UVVC@6UUfXVD#MVU@6Nj9qDQ9IB&aGBP&-CQ&&8Q"
+6@R"fER',QCfVT*kYSTDRUCHCUDH9NTU9MC!!L(9[F@GAB'e@5faU5e4QCf9REQa
+eL)5'PTHAQ*!!PUHMP*DUXk@0KkZjM(5!IhelD@"SCQ&R@%*6Bdp4D'CYJRelMC@
+CR*!!LjbPQCbKRl+hQ*'LSSjlI(9SFQ03E(CD@fYJ@&jGAejQJRY`MTLDU*H1RjU
+BRik)RUDFP*5KRSZ%JRYbFfPADhKL@QC[BeTTCPKXIQe`JB51PTLIPj'FSTb4N!#
+LU)q*S*b*NT9rF(CjD@PaBPCGBeeB9eaRD'4bJB+#K)fLSj'8SDUVQTQRUU18MBk
+)KiCmF'YaH@pG@@&SCeC)@QTDA'e`JBTqLjqGPCDKRjHDRjqBR+ZJMBZ*LB9fDQ0
+XIA"CB(*cC9pNAf&SA&a[HAeiH*1HNC5MS*QHSTH5TV5GLT@KQBTmER*iE9a8CA*
+L8eYUE9j9B'jQAh5%JS+(QkQGQULZTjqMTCkMU*H3!*k9JAKiIQa3AR0J4%pQAeT
+I@@&[F(0iISH&KT5HQC5HSk+LQTZSUD1DM)qENApiHAKXDA&T99&JC900@&aMDfK
+`JB+'N!#2N!#EPj!!R+1CQ*kDRDZQNT5HNS"rJ(CaH(4UBPaSEPC09eTD8PGZFR5
+%KSLASk@CPkHKMSqHSjfCQ*L5NippHhjiF@KSEf9JCQCJ99YXB&0LER*mKBL'QE'
+LPkZRP*UJPSk6P)U*MBQ"HAZ!GfjdF@CVD'4XCeeUF&YIHA9[Ji9mMCQ0P+LFN!#
+GT*QATD'4M)H*N!#(G(+"J("`FfaLD(4M89pUB&aUFR+$LhL%STH2SU1BQTUFTUD
+BNTL6L)CqEfY[Fh*VB'0aF@GIB'Y[Bf9dFA5*MS'0STUDS*@HTSf&N!#8Q)q$KBU
+2IfYkJA"`DQ4iDeCdH&aXI'PKERCeIBCmJ*fCKjDSRj'3!*bCL)Z@Li5+MBKkGAq
+#H@aaGQCDA@GTB9YFDA&XDRL(JB#6P*DRSTUNUTf6SU54N!#5M)9pJS&[ERTdB9e
+UCf&XANjUFeYMER*qIS@8MT5PSCZISD+EPT+1QTq+J)L1M(CTI)0aEA9[B'CbCfC
+bC&TSDQ&ZK(T`MD'9N!#FSD@NPT'CS*U+Ljk@K)f,HAf&H@TYFf9KC&eLDQ"9@'9
+PCA4eGj19KCQSS+U`SCDASTq0Nj1+NiYmK)&fH(CUCQeZCPjKCQ0I@Q"UB'9lGB1
+HL)5SVTk@RDZNMj'DNT!!N!#(LSk"GA4mIR"UGA&JCR"UC9jIDQ"8DAYaFAq+Nj5
+5QU1RS*56QjkANj+5MSq3!(ekKAeiGQTVFfPHCQPQCee@C'aRDR9pKBk,LCULQTq
+NPBqGSC@-NTQ6LBH'JAPfG'aVE@GPBQ9YC@0TCQP`FRTrIikCMSUFUCU,PCH1PT'
+)NC+3!*1,Ihk)Jh*fGfT[E&YQGfjGA@TZD@ehHi#3!*'#LjfFRCZ,KCDIL)'5Mif
+AM)+%IiL&E(5%F&jNEh"UCPTDD@YMD(Q&L)k0MTbJRk@6KCQCK)12PBZ(N!#'HSL
+*GA0kGA0ZC'T`E@PJA@&JBfPZHi"rN!#EP*UUUCb8QTZ-KiL*N!#+J)D&H(KqHA&
+cFfeUD@jjEejQF'TQCfphI)Q)HiqRRjbPRT!!P*q8IiH@Li+)JhKiGRPmF'jbCfa
+hFR&`D'YZCfTdGhQ"Ki5&NjLERTHAPTLFNC!!R*H5NBQ%IACjGQeYE'*KEACbB9e
+XE&pNFA*kL)5#P*Z9Q++IPj@9PTH@NC1CQC5'HAYpGfeMB@KRAQG[CQYTBQPQDRe
+qHi@1P*16RD+KRC+1N!#*LBq-NTZ-JSQ$JBCkE'aYD@KSCfTXBeYJDfGQH(YlKSH
+&MTbNQj1BR*f8KBfGNSL0Nib!J)+$JA0bF'4SE'GH@@CR8eTUERb$HS18N!#4T+L
+EQD'KPif4QjD5Mi5%JRCeIAeaC'KbF'eXDQjRA@&NCQTdJiH!KTH@P+'JQCkAKik
+DNSZ4Q*@)JAq!KAp`E(&aDfY[EfjYDfGJB@0UHRYfHS#3!*b4PDDDQ*k5PC@0PTD
+2N!#2K(k*KA9`F'aNC@YRB@PYBPeSDQGiJA9kMBU$PD@DPD+LPC+9Q*UBMS1(MS*
+cHB&kF'GQER4XAf*YCPaHCQaeIi'$KBH8R*58QCQ9Lib8NT'4MBq3!)TrHAYqH@p
+XE'TbG@KNEh*P@PjUFhCiI)''M*HHPjUNQ)H1NSL0PBf)MT1+I(k+KhPYDR"bD@G
+UD@GQBf&KChKlFAU%K*'CQD+JQjU9PTL3!)Z9PB5&M(plKB4pG'peFQaYD'4SD@9
+EA'jcFB#"HBZ4MCZJQCH8QCU1MC18PSq#JSL$HRGjIAKYERGcDfjdE'*KB@0UFhK
+eHSD)MTQBP*5FQib+P*H8P*!!LSf2KRekJ)&ZCR"[DA&[C@e[B'9VCA&rGA#$MiD
+,PjHFRC52NT11P*U1Kif2LRpiIS9hCQKYDfTSCfPVDQ&QG(*aJSClJ*!!Nj'ARCQ
+1MjD6N!#2NT5*Kj!!LhphIiKfDR&[DfpcDf"XEf&NDh&dH)@$HSU9Mj+BQC@0MC+
+3!*!!MT'CNBH,Li4rJAjfGQpSFh&MDA4UA'CTAh&rFhb+Ji5AS*H5Qjq8MBq5Nj@
+3!)f0LSQ$Hhf!GfjYDfT`E'T[D@4NCfjXEhaqHi'+NjD9QjfAP*'6NSk8PSZ'Lib
+"IS4lEhGdCfacD'TaDfTZCQ9[G(ChHB+&KT'5NTZDP*58Nik1Pj@(KBq*HAarHRK
+cEQeXEQjYDfPPBQK`ER"lHhZ$JBH@N!#4Q*'6PT!!NjD@PC@4M)Z%IS1"H("[E'G
+[G@aLBQTSB@4RF(amH(b)N!#6QT@1RD#1LTD9N!#ANi@*NBepH)0qG("UE(&`F'e
+SDh"SB@adG(TlH)'2N!#0NjQCQT@(LTf8KT'2KSq-IAk,KAGfFQpfGQjRDh*SB@T
+TD@pYG(jpIi@2PT5DRC56QTQ4Mj58M)5*Khf"K(KbGA&`F'eaF@TTD@KXDQPfIAC
+pKRk*SC@*QTk6P*11PCQ4KSD*K(q"HA0lG@CYGR"bG'j[EfpbE@CcK(TZH)H0MSb
+*MjU@MSb0NCQ@KS55N!#%K)&iIS&[CA"jG'aYF("`D@4[HhCZH)"lJSq+LCLCN!#
+1Mj1CPik+Mj!!Mif!IS9pGh9UDh9`C@PaEfPPDh*aGRalIB@)Lj59NTH@NC!!NT!
+!MC!!MB@'MBPqIi+!I(4`FR4bF(&XEA4VCA"cF(PqHhk$LC'4MC5DM)D8NiL-N!#
++LBQ'Ki5#KRpeH(G[G(9[F'jTDfYSCfY`GhjlHS54PC'5PT18Pik-PT'+NBb$LSY
+qHAjrFfTcGh"XE@eZEQTQCfTaHAPdI)Q0N!#5PC@3!*HFN!#)MT@ALRf&NSThH)0
+qG(0[E(9hE@P[GQeLEA0UFB"kG)#0MSU1PC15PBk-P*10LBH0M)1$J(q"I(4`FhG
+cE'e[E'aTC@PbFA&rJ(+#Pib+NT+5P*54P*52NC1+LBZ&JB"qHRGhFfpcFh"VDA&
+YBQT`E(9pHRf(Lif2NC58NT!!MT!!N!#0MT'+KSb*K)&pIhTdH(4bHR9TE(9eE'0
+VGA0dGhL!LSH)P*+0Nj'3!*+*Lj@-KBU+LBL!J)4rHh9cHA9[FA*ZE@jSDh4YEAY
+jGRk%LSq+LC'9NSb1Nik0LiD)KSH'I(k"HRGkHA4cFR"`EQj[D@abGAKjHi''KSH
+2MSZ3!*+2M*!!NSf0MBL'KB4rI(ppHACdGhPfFA"dFQj`E@efHATkIBH*LBk-Lj'
+3!)f,Lj!!M)Q-LBL*KB@"IApqH(9iHA0bGR4aFR"[FR4hGhGqJB+(LBQ1NBq,MBf
+0MBZ,KiQ+JiH(IB'&Hh4kI("aG@pZF@pZF(*eHRPkJ)1)LBQ3!)f0Nik,MSq1LiL
+)Ki1$JhjrJAYhH(PhFR"dF@e`F'e`GA9jJ(k!LBQ*MBZ,N!#,KSb1LBH*LB5"K)1
+"I(TqHhTkG(CiGA9bF(&ZE(&hGR4mJ(k&LSH+MBb0M)U(L)q2KB''L)D#I(f%Ih9
+eHRTdEh9dER"`ER"eGRClIRZ$MSL)N!#2MT!!MiU0NSb(LBH'KB'!IRq"HR9kHhC
+bG(CaG(CXF(YhH(pqIB+*LSH*MSf-M)H,N!#0L)H(KS@#Ii'$J(ajHheiGRKhFh0
+eFQpcGRGjHRZ!K)D(KiQ-LSZ+M)f+LiU*LSH&K)1!JB*mHAaiG(4dG(0bEfecH(*
+dIReqJi1&LBf1LSZ0LiZ+LSZ)JS+&K)1"IRjqHRKjGhGhFh*dFR&dGRChHRaqJ)'
+$LBZ(L)b-LiU*LBU'JS1&JB#&J(U"JRPjHRKjGh4aFh4bG(9eHRajHi##JiL*KBL
+0LSH*LSZ*KS5%KS@"Ihq#J(PhHATiGAGdFRGeFR9eGhjpHRk#KBD'LBZ*LBZ+LBb
+)KBQ)Ji1&JAq#IhPlIAGeHhGcH(GdGRPiHAjpI)#"JS@*LBL)LBZ+KiQ+KS@&KB@
+$Ji0rI)"qH(PlHRKfGh9hHAGfHRelHi##Ii+)L)D'L)b'JiZ*KBH%JiH(JS##JB&
+qH(PmHA9fGR9eGA9hGRKmI(eqJB1%KSH*L)D)LBH)L)@$KSD"JB5"IAq!HhTlH(K
+iGAGhGA9eH(TkHherJ)'#KBH)KiH(KiL)KBD'JS5%JS*rIi"mHhalHRKjHRThGRG
+fH(PiHRYqJ(k"Ji5(KiH(KSL*KB5(K)+'Ji'#IhepIAakHATjHRKhHAPiH(KiHRe
+qI(f#K)5&KSL*L)D'L)L&K)5%K)5!IS&rHhjpHAPkHRPjHRGjI(PjHharJAjqK)@
+$KBH'KSQ(KBH'KBD%Ji1%JAf!JAamI(TlHRKlHhGjH(PkHRaqIAq"J)1(Ji1)Ki5
+&KiD&KS@%K)1%Ji"rIhpmIAjjH(YmHRPjHAPkHhTlJ(pqJB'$KS@%KSD&KB@%K)@
+%JB+%JS'!IhjqIRakHRTkI(PhHhajHRTjIS"rIRq%KB5%JiD*KS5$KBD$JS+"JS0
+qIB#"IAamHhamHhTjHhYkHRPlIRjrIhq"JS+%K)5&KB@%Ji5%Ji'"JS&rIRf!IRT
+mIRelHhalHhalHAYmI(eqIhq!JB'%K)5&Ji1&K)1$K)1"JS+!J(jqJ(jkI(emI(a
+mI(YmI(YpI(arIhjrJ)'$JS1$Ji@&JS+&K)+#JS'"JAprIhppIAelIAplHhemIAj
+mI(f"J(erJB+#JS1$JS1$JS1$Ji1"J)'#JAjrJ(pqIRepIRemIAelIAjmIAjqIhq
+!Ii#$JB#$Ji+#Ji1#JS+#JB'#JApqJB"qIRjpIAjqIAapIRamI(eqIRprIi#"JB+
+#JS1#JS+#JB'#JAq"JAprJ(pqIRpqIAjqIRepIRjpIAjqIRprIhq!JB'#JS'#JB'
+#JB'"JAq!JB"rIi#!IhprIRjqIRjqIRjqIReqIhjrIhprJB'"JB'"JB'"JB'"J)#
+!J)#!Ii"rIhpqIhpqIRjqIhpqIRjrIhprIi#!J)#"JB#"JB#!JB#"JB#!J)"rIi#
+!IhprIhprIhprIhprIhprIhprJ(q!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhp
+rIhprIhprIhprIhprJ(prIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J!!
+!4US!!3!"!!8!!!#J!!'!83!!!!!!&!!!!!!!!%D!9Zk,S`!!4Ri!!%Cr!$b!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihp
+rJ)"rJ)1#JB'!J(prL)k%H(9hIB&jGRb!J(pmI(ajG("aG(9eGACjHAKiHR0VDfj
+bG(9iGh*aFAD#L)b2M)Q+MjH9MSf(IRU"N!#CQ*56PTLES+#8LSD#J)@0Nj52LSQ
+,KRjkH(GhGRU$KB+%Ki0lG@eUIjUJQT5,JApkGR"SC&jGDA4fE@ahF@9KB@GXCPG
+,46`l59KKBPaCA&pHAf&LC@acHS#"J)+&Lj5FT+bdZVQfZ,l"`XM6fplJiq,GeF[
+%`m1rZ+fMQC!!L)0rHA0VBeeD9e&-5%9%36Xf-c)d06Bi1cXh-5m`-M3f0M8d-c-
+i3NY49eaME(*fHAYmIS+(M*'9PjUIT+LYXV@fYlHhYV5bXV+bY,HkZlblZVUkZVQ
+hY,1bX+qVTk@NSk'JRjqGQTD4MSZ*Ki0rHR9`E@PQBPeC9&"+3MSd,LNQ*#-M)b3
+P*L8Q*bS[0$T!48K+6P*9@9pND@jcHB#&Lj'@QjqMTULVVV+dYVLk[,r$b-c4eGE
+@eY64cFR&`EfjYV+[UU@JQjD4MBQ'Ji"pHA9bEfaTCQ4LB&pGA&YC@&KB9e958%j
+,58G%3N&"38*$48G)58P*58P+5de18&0CAf9XFRKrK)U3!*@CRU+PU+b[XlDj[Er
+"`X2%a-6&a-2#`F#r[VflZ,@bVkfUTk5KRTZANj!!M)L%IhTeF'aRBepE@&968%e
++4N*!2M`l16Ji1$Jj1ce!3dC)5dj499KD@eaHB'*PD'Y[FRCjHhk!K)H+MT'8PTQ
+ERD#LTDLXVl5j[X2)c-r3d0(3cmc*aX+qZE1[UU@LRTUAP*'1LSD#IRTfF@eSBep
+D99"-4d0"2cir2cmr2cmr2d"!3%&#3d9(5Nj499PHBfKXF(4iHhq#KSU0N!#6PCH
+BQTbHS++NTULTUkbXVDfYVDkYVDbVUkUUUUQTU+LTUDLRTD1JRCZCPj55Mif,L)D
+$J(ejGA&YD'0H@PG68%a*4N4"2cmr2ciq2Mp!38*$48C(58Y06e*9@&YIC'PZG(T
+rKBU2PCUGSD5RUkqbYEHiZEQkZlZm[,blZVLfY,1`VUZST+#GQTH8NBk,L)5"IAP
+fFh&ZE'YTD'GQC@9QCfKSD'GRCQ9NBf&IA9YC9eG@99C@9PGA9eKC@PYFAQ"MCQK
+VER&dGhYqJB5)Lik3!*+8PjQERCqKSk@RUDUXVDqbYEHjZVZlZlUiYV5aVUURSk#
+FQ*53!)b)K)"mH(4[DfKNB&eC9P458%p168e06Nj16dp389089PKEAQ*PD@eaGAP
+mIS#"JS+$Ji1$Ji1$K)5&KiL+Lif2N!#4NC+6PCDAQ*QDQTZFR*fHRTkHRTqIRjq
+HRCbFQjUCQ*LAPC15N!#2MBZ*KS5"IhajGR*ZDQ9KA9P@8e"05dP(4N9&4NG(5%T
+,68p38P9B@PeKC@PXF(0iI)'&LBk6PTUGSD5QUDZYVUq`X,#`VkkXUkQRTD1JRCU
+BPT56NC!!MSf,LBL(KB5#JApqIAYkH(CdFR"[EQjYE@aXE@eYE@eYE@eXE'YVDfT
+TD@KRCfGRCQCPC@9NC'0MBf0NC@CSDQa[FA4iHhk"KBL-Mj1@QCbHSD5QTkQVVUq
+aXl5eYE@eY,1aX+kXUDDLRjZANiq,Ki0rHhKdF@jVD'CMB@"IAPjHAPeGA9eGA9a
+FA&eGAPpJBQ0PCfPXER&cGAGjHherJB+$K)@'KSD'KSH(KiL)L)Q*LBQ+LSZ,M)b
+0MSq3!*'5Nj@@PjQDQjbFR*bFR*bFQjZEQTUCPjD8NT!!MSb+Ki5#IhajGR0`E@T
+RC'&HA&PA99468P&48&&489*699CB@PaIBQ9SDfjaG(GkIB#$KSL,MT!!Nj@@Q*U
+FRTqJSD+MSk1LSU'JRjkFQjQBPT@6NT'3!)q1MBb+LBL)KiD&K)1#JB"rIRemHhY
+kHAPiGhCeGA4cFR&`EfjYE'TSCf9NBf*KB&pIAejHAepIB'&MC'CRD@YYEh*dGhT
+mIi'%KiU0N!#5PCLDRCqKT+DRU+QUUkZXUkZUUDLRTD5LRjfEQ*D6NBk-LBD%JAj
+mHAGeFh&[EQeXDfTSCfCPC@9NC@9PC@9QCQCRCfKTDQYXE@j[F(*cG(9fGhKjHAT
+lI(epIRq!J)'#K)@'KiL+M)f2NC+6P*@@PjLCQTUER*bFR*fGR*bEQjUCQ*H@P*1
+4N!#1M)U)KB1!IRYjGR4aEfaUD'CNBQ&JAejGA9aFA&eGAPpJB@*NC@GTDQaZF(*
+dGRKkHherJB+%KBH)LSb1Mj!!NT16P*59PC@9PC@8P*58Nj15NT'4NC!!N!#3!*!
+!Miq2Mik1MBf-LiQ)Ki@%Ji+!IhjmHhTjGhCeGA4cFR&`EQeXDfTTD'GQC@4NBf0
+MC'4NC@CRD'TVE@paG(CjHhf!JS@(LBZ0N!#5Nj@AQ*QEQjbFRCkHRTkHRjkHRCf
+FQjQBPj@8NT'2MSb+L)D&Ji&rIAakHAKhGR9dFh0bFA&`F("`F("`F("`F("[Efp
+[Efp`F("`F(&aFA*cFh4eGAChH(PkHhYmIAeqIhq!JB+%KBD)LBZ0MT!!NT19PTL
+CQTZFR*fGRCbFQjUCQ*H9P*+4Mif,LSL'K)+!IRelHAGeFh&[EQaUD@GQC@4MBf*
+LBQ0MC'9PCfKTDfeZF(&cG(ChH(PlI(eqIhq!JB+$K)@'KiH)LBQ*LSU+Lib-MBf
+1MSk1Miq1MSk1MSk1MSk1MBf0MBf-M)b-M)Z,LSU+LBL(KB5$JB"qIAYkH(CdFR&
+[EQaVDQPTD'KSD'KSD'KSD@PTDQYXE@j[F(*cGAGiHRaqJ)1&KiU-MT!!NT18PCD
+AQ*LBQ*LBQ*HAPT@8Nj+4N!#3!)q1MBb,LSQ(KS@%Ji+"J(pqIRemI(YlHRTjHAP
+jHAPjHAPjHAPjHAKiH(GhGhCfGA9dG(0cFR*bFR*bFR*bFR0cG(9fGhKjHRYpIRq
+"JS1%KSH*LSb0MT!!NC+6P*@@PjHBQ*QCQCLBPjH@PC15NBq0M)U)KS5#J(jmHRK
+hGA4bFA"[EQeXDfYUDQTUDQTVDfaYE@j[F(&bFh4fGhKkHhapIi#"JB+$Ji5%KB@
+&KBD'KS@&KB@&KB@'KSD(KiH(L)L)L)Q*LSU+LiZ,LiZ-M)b-M)b-M)b-M)Z,LSU
+*L)H'KB5#JApqIAYjH(CeG(*aF'pZE@aVDQTTD@PTD@TUDfaYEQp`FR0dGRGjHRa
+qIi'$KBD)LSZ-MSq3!*!!NC+6Nj16Nj16Nj+5NC!!N!#2MSf0M)Z+LBL(KS@%Ji1
+#JB'!IhpqIAemI(amHhYlHhYlHhYlHRTkHRTkHAPjH(KiGhGfGR9eGA4dG(4dFh0
+cG(4dG(9fGRGiHAPkHheqIi##Ji5'KiL+Lib0MSq3!*'5NT16P*58P*56Nj15NC!
+!Mik0LiU)Ki@%JS&rIRalHRKhGR9dFh0bFR&aF("`F("`FA&aFA*bFh4dGAChH(P
+kHhapIRprJ)#"JB'#JS+$Ji1$Ji1$Ji1$Ji1$Ji5%K)@&KBD'KSH(L)L)LBQ+LSU
++LSU+LSU,LiZ,LiZ+LSU*LBL(KS@%Ji+"IhjpHhTjGhCeG(0bFA"`Efp[EQjZEQp
+[Eh"aFR0dGAChH(PlI(eqJ)'#K)@'KiL+Lib-MBk1Miq3!*!!N!#3!*!!Miq1MBf
+-LiU*LBL(KS@&K)1#JB'!J(prIhjqIRjpIAepIAamI(amI(amI(YlHhYlHhYlHRT
+kHRTjHAPjH(KiGhGhGhCfGRCfGRChGhGiHATlHhapIRq"JS1%KBD(L)Q+Lib-MBk
+1Miq2N!#3!*!!N!#3!)q2Mik1MBb,LiU)KiD&K)+"IhjmHhTiGhCeG(4cFR*bFA&
+aFA&bFR0cG(9eGRGiH(PkHRYmI(eqIRprJ)#"JB+#JS1$Ji1$K)5%K)5%Ji1$Ji5
+%K)5%K)5%K)5%KB@&KSD'KiH)L)L*LBQ*LBQ*LBQ)L)L(KSD&K)5$JS+"J(pqIAa
+lHRPiH(GfGA4dFh0bFR*aFA&aFR*bFh4eGRGiHATmIAjrJ)+$K)@(L)Q*LSZ,M)b
+-MBf0MBf0MBb-LiZ+LSQ)L)H'KS@%Ji+"JB"rIRjpIAamI(YlHhYlHhYlHhYmI(a
+pIAepIAepIAjpIAepIAepI(amI(alHhYlHhTkHRTkHRTkHRTlHhYlI(apIAjrIi#
+"JS1%KBD'KiL*LSU,M)b0MBf0MSk0MBf-M)Z+LBQ)KiD&Ji+"J(pqIAalHAKhGhC
+eGA4dFh0cFR*bFR0cFh4eGAChH(PkHRYmIAjrJ)'#JS1%K)@&KSD'KSD(KiH(KiD
+'KS@&KB@%K)5%K)5$Ji1$Ji+#JS+#JS+#JS+#Ji1$Ji1$Ji5%K)5%K)5%Ji1$JS+
+"JB"rIhjqIAamHhTjHAKiGhGfGR9eGA9eGA9eGRChH(KjHRYmIAjrJ)'#Ji5&KSH
+)LBU+LiZ-M)f0MBf0MBf-M)b,LSU*L)H'KB5$Ji+"J(pqIAalHRTjHAPiH(KiH(K
+iH(KiH(PjHATkHhYmI(apIAeqIRjrIhq!J)#!J)"rIhprIhprIhprIhprIRjqIRp
+rIhprIi#!J)'"JS+$Ji5%KB@'KSH(KiL)L)L)L)L)L)L)KiH'KS@%Ji1#JB"rIRj
+pI(YkHAKhGhCfGA9eG(4dG(4dGA9fGRGiHAPkHhapIRq!JB+$K)@'KSH(L)L*LBQ
+*LBQ*LBQ*LBL)L)H'KS@&K)5$Ji+"JB#!IhpqIRjqIAepIAepIAepIAeqIRjqIhp
+rIhq!J)#!J)#!J)#!J)"rIhprIhjqIRjpIAepIAepIAepIAepIAjqIRprJ)#!JB+
+#Ji1%K)@'KSH(KiL)LBQ*LBQ*LBQ)L)L(KiD'KB5$JS'!IhpqIAamHhTkHAKiGhG
+fGRCfGRCfGRCfGhGhH(PjHRYlI(eqIRq!JB'#Ji1%K)@&KB@&KSD'KB@&KB@&KB5
+%K)1$Ji+#JS'"JB'"JB#!J)#!J)#!J)#!J)#!J)#!J)#!J)'"JB'"J)#!J)#!Ihp
+rIRjqIAepI(alHhYkHRTjHAPjHAPjHATkHRYlHhamIAeqIhq!JB'#JS1%K)@'KSH
+(L)L)LBQ*LBQ*L)L)L)H(KSD&K)5$JS'!J(pqIRemI(YlHRTkHAPjHAPjHAPjHRT
+kHRYlI(apIAjqIhq!J)'"JS+$Ji1%K)5%K)5%K)5%K)5%Ji1$Ji+#JS+#JB'"JB'
+"JB'"JB'"JB'"JB+#JS+#JS+#JS+#JS+#JS+#JS'"JB'"J)#!IhpqIRepI(amHhY
+lHhTkHRTkHAPjHRTkHRYlI(apIAjqIhq!JB+#Ji5%KB@'KSD(KiH)L)L)L)L(KiH
+(KSD'KB@%K)1#JS'!J(pqIRepI(alHhYkHRTkHRTkHRTkHRTlHhYlI(amIAeqIRj
+rIhq!J)#!JB'"JB'"JB'#JS+"JB+"JB'"JB'"JB'"JB'"JB'"JB'"JS+#JS1$Ji1
+$K)5%K)5%K)5%K)5%Ji1$Ji+#JB'"J)"rIhjqIAamHhYkHRTjHAPjHAPiH(KiH(P
+jHATkHhYmI(epIRprJ)'#JS1%K)@&KSD(KiH)L)L)L)L)L)H(KiD'KS@&K)5$Ji+
+#JB#!IhprIRjpIAemI(amI(YlHhYlHhYlHhamI(apIAepIAjqIRjqIhprIhprIhp
+rIhprIhprIhprIhprIhprIhq!J)#!J)'"JB'#JS+$Ji1%K)5&KB@&KB@&KB@&KB@
+&KB5%Ji1#JS'"J)"rIRjpIAalHhTkHAPiH(KiGhGhGhGhH(KiH(PjHRTlHhapIAj
+rIi#"JB+$Ji5&KBD'KiH(L)L)L)L)L)L)L)H(KiH'KS@&KB5%Ji1#JS'"J)"rIhp
+qIRjqIAepIAepIAepI(amI(apIAepIAepIAepIAepIAepIAepIAepIAepIAepIAe
+qIRjqIRprIi#!JB'#JS1$K)5&KB@'KSH(L)L)L)L*LBQ)L)L)L)H(KSD'KB5%Ji+
+"JB"rIhjpIAalHhTkHAPiH(KiGhGhGhKiH(KiHAPjHRTlHhamIAjqIhq!JB'#JS1
+$Ji5%KB@&KBD'KSD'KSD'KSD&KB@%K)5%Ji1$JS+#JS'"JB#!J)#!IhprIhprIhp
+rIRjqIRjqIAepIAepIAamI(alHhYlHhYlHhTkHRTkHRTkHhYlHhamI(epIAjqIi#
+!JB'#Ji1%K)@'KSH(KiL)L)Q*LBQ*LBQ*L)L)KiH'KS@%K)1$JS'!J(pqIAemI(Y
+kHRPjH(KiGhGhGhGhGhGhH(KiHAPjHRTlHhamIAjqIhq!J)'"JS+$Ji1%K)5%KB@
+&KB@&KB@&KB@&KB@&KB5%K)5%K)5%K)1$Ji1$Ji+#JS+#JS+#JB'"JB#!IhprIRj
+qIAepI(alHhYkHRTjHAPjHAPiH(KiHAPjHATkHRYlI(apIAjqIi#!JB+#Ji5%KBD
+'KiH)L)L*LBQ*LBQ*LBQ*L)L)KiD'KB@%Ji1#JB'!IhjqIAamHhYkHRPjHAKiH(K
+iH(KiH(KjHAPjHRTlHhYmI(epIRjrIi#!JB'#JS+$Ji1%K)5%KB@&KB@&KB@&KB@
+&KB@&KB@&KB@&KB5%K)5%K)1$Ji1#JS+"JB'"J)"rIhpqIRjpIAamHhYlHRTkHAP
+jHAPiH(KiH(KiH(PjHATkHRYlI(apIRjrJ)#"JS+$K)5&KBD(KiL)LBQ*LBU+LSU
++LSQ*LBQ)L)H(KS@&K)1$JS'"J(pqIRemI(YkHRTjHAKiH(KiGhGhH(KiH(KjHAP
+jHRTkHhYmI(epIAjqIhq!J)#"JB+#JS1$Ji1%K)5%K)@&KB@&KB@&KB@&KB@&KB@
+&KB@&KB@%K)5%Ji1#JS+"JB#!IhpqIRepI(alHhTkHAPjH(KiH(GhGhGhGhGhGhG
+iH(KjHATkHhYmIAeqIi#"JB+$K)5&KSD(KiL)LBQ*LSU+LSU+LSU*LBQ*L)L(KSD
+&K)5$JS+"J(prIRepI(YlHRTjHAPiH(KiH(KiH(KiH(KiH(PjHATkHRYlHhamI(e
+pIRjrIhq!J)'"JS+$Ji1%K)5&KBD'KSD(KiH(KiL)L)L)L)L)L)L(KiH(KSD'KB@
+%K)1$JS+"J)"rIhjpIAalHhTkHAPiH(GhGhCfGRCfGRCfGRCfGhGiH(PjHRYlI(e
+pIRq!JB'#Ji5&KBD(KiL*LBU+LSU,LiZ,LSU+LSU*LBL)KiH'KB@%Ji1#JB#!Ihj
+qIAamHhYkHRPjHAKiH(KhGhGhGhGhGhGiH(KiHAPjHRTkHhYmI(apIAjqIhq!J)'
+"JS+$Ji5%KB@&KSD(KiH(L)L)L)L)LBQ*L)L)L)L(KiH'KS@&K)5$Ji+"J)"rIRe
+pI(YlHRPjH(GhGRCeGA9dG(4dG(4dG(9eGACfGhGiHATkHhapIRq!JB+#Ji5&KSH
+(L)Q*LSU,Lib-M)b-M)b-LiZ,LSU*L)L(KSD&K)1$JS'!J(pqIAemHhYkHAPiH(K
+hGhCfGRCfGRCfGRCfGRGhGhGiH(PjHRTlHhamIAeqIRq!J)'"JS1$K)5&KBD'KiH
+)L)Q*LBQ+LSU+LSU+LSU+LSU*LBQ)L)H'KS@%Ji1#JB"rIRepI(YkHAPiGhCfGA4
+dFh0cFh*bFR*cFh0cG(4eGAChH(KjHRYmIAjrJ)'#Ji5&KSH(L)Q+LSZ-M)b0MBf
+0MBf0MBf-M)Z,LSU*L)H(KS@%K)1#JB"rIRjpI(YlHRPjH(KhGhCfGR9eGA9eGA9
+eGA9eGACfGRGhH(KjHATkHhamIAjqIi#"JB+$K)5&KSH(L)Q*LSU,Lib-M)b0MBf
+0MBf0M)b-LiZ+LBQ)KiD&K)5$JS'!IhjpI(YkHAKhGR9eG(0cFR*bFA&aFA&aFA&
+bFR0cG(9eGRGiHATlI(eqIi#"JS1%KBD(L)Q+LiZ-MBf1MSk1MSk1MSk1MBf0M)Z
+,LSQ)L)H'KB5$JS'!IhjpI(YkHRPiGhGfGA9dG(4cFh*bFR*bFR*bFR0cFh4dG(9
+fGRGiH(PkHhapIAjrJ)'#Ji5&KSH)LBU+Lib-MBf1MSk2Miq2Miq2MSk0MBb-LiU
+*L)H'KB5$JS&rIRemHhPiGhCeG(0bFA&`F'p[EQjZEQjZEQp[Eh"aFR*cG(9fGhK
+jHhapIS#"JS5&KSH*LSZ-MBf1Mj!!N!#4NC+5NT+5NC'4N!#3!)q2MSf-LiU*L)H
+'KB5$JB"rIRemHhTjH(GfGA4cFh*aFA"`F("[Efp[Eh"`F(&aFR*cG(4eGRGiHAT
+lI(erJ)'#Ji@'KiL*LSZ-MBk2N!#4NC+5NT16Nj16Nj+5NC'3!)q2MSf,LSQ)Ki@
+%JS&rIRelHRKhGR9cFR&`EfjZE@aXDfYVDfYVDfaXE@eZEh"aFR0dGAGiHAYmIAq
+!JS1&KSL*LSb0MSq3!*'5NT18P*58PC@9P*58Nj+5NC!!Mik0M)Z+L)H'K)1#J(p
+pI(YjH(GfGA0bFA"[EfjYE@aXDfYVDfYVDfYXE'eYEQp[F(&bG(9fGhPkI(erJ)+
+$KBD)LBU-MBq3!*'5Nj59PCD@PjHAPjHAPTD9PC56NT'2MSf,LSL'KB1"J(jmHRP
+hGR4cFA"[EQeXDfTTD'KSCfGRCfKSD@PUDfYYEQp`FA0dGRGjHhaqJ)'$K)D)LBZ
+-MBq3!*'5Nj59PTDAPjHAQ*HAPjD@PC@8Nj+4Mik0LiU*Ki@%JS&rIAakHAGfGA0
+bFA"ZE@eXDfTUD@PSD'KSD'KSD@PUDQYXE@j[F(*cG(ChHAYmIS#"Ji@(L)U-MBq
+3!*+6P*DAQ*LCQTUDQjZEQTUDQCLAPT@8Nj'2MSb+L)H&Ji&rIAYjGhCdFR&[EQa
+VDQPSCfCQC@9PC'4PC@9QCQGSD@TVE@j[FA0dGRKjHherJ)+%KSH*Lib1N!#4NT5
+9PTHBQCQDQjZEQjZEQTUCQ*LAPT56NT!!Mif,LSL'K)1"IhelHAKfG(0aF'pYE'Y
+UD@KRCQCPC@9PC@9PC@CRCfKTDQYXEQpaFR4fGhPlIAq"Ji@'L)U-MT!!NC19PTH
+CQTZFR*fGRCkGRCfFR*ZDQCL@PC15N!#1M)U)KS5#J(jlHAKfG(*`EfeXDQPSCfC
+PC@4NC'0MBf4NC@9QCfKTDQYXEQpaFR4fGhPlIAq!JS5'L)Q,MBk3!*+6P*DAQ*Q
+CQTZEQjZEQjZEQTUCQ*H@P*15N!#1MBZ*Ki@$JAppHhTiGR4cF@pZE'YUD@KRCQ9
+NC'4MBf0MBf4NC@CQCfPUDfaZF(&cGACiHRaqJ)+%KSL+M)k3!*+6PCHBQCUER*f
+GRTkHRTfGR*bEQTQBPT@6NC!!MSb+L)D%JAppHhPhGA4bF'pYE'YTD'GRCQ9PC'4
+NC'4NC@9QCQGSD@TVE@j[FA0dGRGjHheqJ)+%KBH*Lif1N!#4Nj5@PjLCQTZER*b
+FR*bFR*ZEQTQBPjD8Nj'3!)k-LSQ(KB1"IhelHAGeFh*`EfeXDfPSCfGQC@9NC'4
+NC'4PC@CQCfKTDQaYEh"bFh9hHAYpIS##K)D)LSb1N!#4Nj5@PjQDQjZFRCfGRCf
+GR*bEQTQBPjD8Nj'2MBZ+L)D%JS"qI(TiGR4bF@pZE@YUD@KRCfCQC@9PC@9PCQC
+RCfKTDQYXE@p`FR0eGRKjHherJ)+%KBH*LSb1Mj'5Nj@@PjLCQCUDQTZEQjUDQCQ
+BPjD9P*+4N!#1M)Z*Ki@$JAppHhPiGR4cF@pZE@YUD@KSCfCQC@9PC@9QCQCRD'P
+TDQaYER"aFR4fGhPlI(k!JS1&KiQ+M)k2NC+8PCDAQ*QDQTZEQjZEQTUCQCLAPT5
+6NT!!MSf,LBH&K)+!IRakH(GeFh*aEfjYE'YUD@PSD'GRCfGRCfGSD'PUDfaYEQp
+`FA0dGAGiHRYpIS##Ji@'L)U,MBk3!*'5P*@@PTHBQ*QCQCQCQCLBPjD9P*15NBq
+1M)Z*Ki@%JS"qI(YjGhCdFh&`EfeXDfTUD@KSCfGRCfGRCfKSD@TVE'eZEh"bFh9
+fH(PlIAk!JS1&KiL+M)f1N!#4NT59PTDAQ*LBQCQCQ*LAPjD9P*15NC!!MSf-LSL
+(KB1#J(jpHhTiGh9dFh&`EfjYE@aVDfTUDQTUDQTUDQYVE'eZEh"aFR0dGAGiHAY
+mIRq!JS1&KSL*Lib1Mj!!NC+6P*@@PjHAQ*LBQ*HAPTD9P*15NC!!Mif-LSL(KB1
+"J(jmHhPhGR4cFR"[EQeXE'YUDQPTD@PTD@PUDQYVE'eZEh"aFR4eGRKjHhaqIi'
+$K)D(LBU,MBk2NC+6P*59PTDAPjHAPjD@PT@8P*15NBq1MBZ+L)H&K)+!IhelHRP
+hGR4cFR&`EfjYE@aXDfYVDQTUDfYVDfaXE@j[F(&bFh4eGRGjHRYpIRq"JS5&KSL
+*LSb0MSq3!*'5Nj58PC@@PTD@PT@9P*56NT'3!)q1MBZ+LBH'K)+"IhemHRKhGR4
+cFR"[EQeYE'YVDQTUDQPUDQTUDfaXE@j[F(&bFh9fGhPkHheqJ)'$K)D(L)U,M)k
+2N!#4NT16P*@9PCD@PTD9PC58Nj+5NC!!Mif-LiQ)Ki@$JS"rIAakHAKfGA4cFR&
+`EfpZE@eYE'aXE'aXE'eYEQj[F("aFR0dGACiHATlI(jrJ)+$K)D(L)U,M)f1Mj!
+!NC+5Nj18P*@9PC@8P*56Nj+4N!#2MSf-LiQ)KS@$JS&rIRalHAKhGA4cFR&`Efj
+ZE@eXE'aXE'aXE'eYEQj[F("aFR0eGRGiHAYmIAk!JB+%KBD)LBU,M)f1Mj!!NC+
+6Nj18P*58P*58Nj15NC'3!)q1MBb+LBL'KB5#JApqIAYkH(GfGA4cFR&`EfpZEQe
+YE@eYE@eYE@jZEfp`FA&bFh4eGRGjHRYmIAq!JB1%KBD)LBU,M)f1Mj!!NC'5NT1
+6Nj58Nj16Nj+5NC!!Mik0M)Z+LBL'KB1#JApqI(YkH(GfGA4cFR&`EfpZEQeYE@e
+XE@eYE@jZEfp`FA*cG(9fGhKjHRapIRq"JS1%KSH)LBU,M)f1Miq3!*'4NT+5NT1
+6NT+5NT'4N!#2Mik0M)Z+LBH'KB1#JApqIAYkHAKfGA4cFR&aF'p[EQjYE@eYE@e
+YE@jZEfp`FA&bFh4eGRGiHRYmIAk!JB+$KBD(L)Q+M)f1Miq3!*'4NT+6Nj16Nj1
+6Nj+5NC!!N!#2MSf-LSQ)KS@%JS'!IRelHRPhGR9dFh*aF("[EfjZE@eYE@eYE@j
+ZEfp`F(&bFh4eGRGiHATlIAjrJ)'#K)@'KiL*LSZ-MBk2Mj!!NC'4NT+5NT+5NT+
+4NC!!N!#2MSf-LiU*L)H'KB1#JApqIAalHAKhGR9dFh0bFA&`F'p[EfpZEQp[Efp
+`F(&aFR0cG(9fGhKjHRYmIAq!JB+$K)D(L)Q+Lib0MSq2N!#4NC+5NT+5NT+5NT'
+4N!#2Mik0M)Z+LBL'KB5#JB"qIAalHAKhGR9dFh*aFA"`EfpZEQjZEQjZEfp`F(&
+aFR0dG(9fGhKjHRYmIRq!JB+$K)@'KiL*LSZ-MBk1Miq3!*!!NC'4NC'4NC'3!*!
+!Miq1MBb-LiU*KiD&K)1"J(pqIAYkHAKhGR9dFh*bFA&`F'p[Efp[Efp[Eh"`FA&
+bFR0dG(9fGhKjHRYmIAjrJB+$K)@'KiL*LSZ-MBk1Mj!!N!#4NC'4NC'4NC!!N!#
+3!)q1MSf-LiU*L)H'K)1#JB"qIAalHRPiGhCeG(0bFR&aF("`Efp[Efp`F("`FA&
+bFh0dGACfGhKjHRYmIAjrJ)'#K)@'KiL*LSU,M)f0MSq2N!#3!*!!N!#4NC'3!*!
+!N!#3!)q2MSf0M)Z+LBL(KS@%Ji'!IhjpHhTjH(GfGA4dFh*aFA"`F("[Efp[F("
+`F(&aFR0cG(9fGhGiHATlIAjrJ)'#Ji5&KSH)LBU,M)f1MSq2N!#3!*!!NC'4NC'
+3!*!!N!#2Mik0MBb,LSQ)KiD&Ji+"J(ppI(YkHAKhGR9dG(0bFR&aFA"`F("`F("
+aFA&bFR0cG(9eGRGiHATlI(eqIi#"JS1%KBD'KiL*LSZ-M)f0MSk2Miq2Miq2Miq
+2MSk1MBb-LiU*L)H'KB5$JS'!IhjpHhTjH(GhGR9dFh0bFR&aFA"`F("`F(&aFA*
+bFh0dGA9fGhKjHRYlIAjrJ)'#Ji5&KSH)LBQ+Lib0MBk1Miq2Mj!!N!#3!)q2Miq
+1MSf-M)Z+LBL(KS@%Ji+"J(jpI(YkHAKhGR9eG(0cFR*aFA&aFA"`FA&aFA*bFR0
+dG(9fGRGiHATlI(eqIi#"JS1%K)@'KiL*LSZ,M)b0MBk1MSq2Miq2Mik1MSf0M)b
+,LSQ)KiD&K)1#JB"rIRemHhTjH(GfGA4dFh*bFR&aFA&`F(&aFA&aFR*cG(4eGRC
+hH(PkHhapIRq!JB+$K)@'KiH)LBU,Lib0MBk1MSq2Miq2Miq1MSk0MBb-LiU*L)L
+(KS@%JS'!IhjpI(YkHAKhGRCeG(4cFh*bFR&aFA&aFA*bFR0cG(4eGAChGhKjHRY
+mIAjqIi#"JS1%KBD(L)Q+LSZ-M)f1MSk2Miq2Miq2Miq1MSf0M)Z,LSQ)KiD&K)1
+#JB"qIAalHRPiGhGfGA4dFh*bFR&aFA&aFA&aFR*bFh0dGA9fGhKiHATlI(eqIi#
+"JS1%K)@'KiL*LSU,M)b0MBk1MSk2Miq1MSk1MBf-M)Z+LSQ)KiD&K)1#JB"rIRe
+mHhTjH(GfGR9dG(0cFR*bFR*aFA&bFR*bFh0dG(9eGRGhH(PkHhamIAjrJ)'#Ji5
+&KSH(L)Q+LSZ-M)f0MBk1MSk1MSk0MBf-M)Z,LSQ)L)H'KB5$JS'!IhjpI(YkHAK
+hGhCeGA4cFh0bFR*bFR*bFR*cFh0dG(9eGRGhH(PkHhamIAjrJ)'#Ji5%KBD(L)L
+*LSU,Lib-M)f0MBf0MBf0M)b-LiZ+LSQ)KiH'KB5$JS'!IhjqIAalHRPiH(GfGR9
+eG(4dFh0cFh0cFh0dG(4eGACfGhGiHAPkHhamIAjrJ)'"JS1%KB@'KiL)LBU+LiZ
+-M)b-M)f0MBf-M)b-LiZ+LSQ)L)H'KB5$Ji+"J(pqIAalHRTjH(GhGRCeGA4dG(4
+dFh4dG(4dG(9eGRChGhKjHATlHhapIRprJ)'#JS1%KB@'KiH)LBQ+LSU,LiZ,Lib
+-M)Z,LiZ+LSU*LBL(KiD&KB5$JS+"J(pqIAemHhTkHAKiGhGfGR9eGA9eG(4eGA9
+eGA9fGRGhH(KjHATlHhapIAjrJ)#"JS1$K)@'KSH(L)L*LBU+LSZ,LiZ,LiZ,LSU
++LBQ*L)L(KSD&K)5$JS'"J(pqIAemHhYkHAPiH(GhGRCfGA9eGA9eGA9eGRCfGhG
+iH(PjHRTlI(apIRjrJ)#"JS1$K)@&KSD(KiL)L)Q*LBQ*LSU+LBQ*LBQ*L)L(KiD
+'KB@%K)1#JS'!J(pqIRemI(YkHRPjH(KhGhGfGRCfGRCfGRCfGRGhGhKiH(PjHRT
+lI(apIAjrIi#"JB+$Ji5%KB@'KSH(L)L)LBQ*LBQ*LBQ*LBQ*L)L)KiH'KS@&K)1
+$JS'"J(prIRemI(YlHRTjHAKiGhGhGhCfGRCfGRGhGhGiH(KjHATkHhYmI(epIRp
+rJ)'"JS+$K)5&KBD'KiH(L)L)L)Q*LBQ*LBL)L)L)KiH(KSD&KB5%Ji1#JS'!J(p
+rIRjpI(alHhYkHRPjHAKiH(KiH(KiH(KiH(KjHAPkHRYlHhamIAeqIRq!J)'"JS+
+$Ji5%KB@'KSD(KiH(L)L)L)L)L)L)KiH(KiD'KS@&K)5$Ji+#JB'!J(prIRepI(a
+lHhYkHRPjHAPiH(KiH(KiH(KiHAPjHATkHRYlI(apIAjqIhq!J)'#JS1$K)5&KB@
+'KSD(KiH(KiH)L)H(KiH(KiD'KS@&KB5%Ji1#JS'"J)"rIhjpIAamHhYlHRTkHAP
+jH(KiH(KiH(KiH(KjHAPjHRTkHhYmI(epIRjrIi#!JB'#JS1$K)5&KBD'KSH(KiH
+(KiH(KiH(KiH(KSD'KB@&K)5$Ji+#JB'!J(pqIRepI(alHhYkHRPjHAPiH(KiH(K
+iH(KiH(PjHAPkHRYlHhamIAeqIRprJ)#"JB+#Ji1%K)@&KSD'KiH(KiH)L)L)L)L
+(KiH(KiD'KS@&K)5$Ji+#JB'!J(pqIRepI(alHhYkHRPjHAPiH(KiH(KiH(KiH(K
+jHAPkHRTlHhamIAeqIRprJ)#"JB+$Ji5%KB@&KSD(KiH(L)L)L)L)L)L)L)L(KiH
+'KSD&KB5%Ji1#JS'"J)"rIRjpIAamHhYlHRTjHAPiH(KiH(KiH(KiH(KjHAPkHRT
+lHhamIAeqIRprJ)#"JB+#Ji1%K)5&KBD'KSH(KiH(KiH)KiH(KiH(KiD'KSD&KB5
+%K)1$JS+"JB#!IhpqIRepI(alHhYkHRTjHAPjH(KiH(KiH(KjHAPjHATkHhYlI(a
+pIAjqIhq!J)'"JS+$Ji5%KB@&KSD'KiH(KiH)L)L)L)H(KiH(KSD'KB@%K)5$Ji+
+"JB#!IhpqIAemI(YlHhTkHAPjH(KiH(KiH(KiH(KiH(PjHATkHRYlI(apIAjqIhq
+!J)'"JS+$Ji5%KB@&KSD'KSH(KiH(KiH(KiH(KiD'KSD&KB5%K)1$JS+"JB#!Ihp
+qIRepI(alHhYkHRTjHAPjH(KiH(KiH(KiHAPjHATkHRYlI(amIAeqIRprJ)#"JB+
+#Ji1%K)@&KBD'KSD(KiH(KiH(KiH(KiD'KSD&KB5%K)1$JS+"JB#!IhpqIRepI(a
+mHhYkHRTkHAPjHAPjHAPjHAPjHAPkHRTlHhYmI(epIAjqIhq!J)'"JS+$Ji5%KB@
+&KSD'KiH(KiH(KiH(KiH(KiH'KSD&KB@%K)1$JS+"JB#!IhpqIRepI(amHhYkHRT
+kHAPjHAPjHAPjHAPjHAPkHRTlHhYmI(apIAjqIhq!J)'"JS+$Ji5%KB@&KSD'KiH
+(KiH(L)L(KiH(KiH'KSD'KB@%K)1$JS+"JB#!IhpqIRepI(alHhYkHRTjHAPjHAP
+iH(KiHAPjHAPkHRTkHhYlI(apIAjqIhq!J)'"JS+$Ji5%K)@&KSD'KSH(KiH(KiH
+(KiH(KSD'KS@&KB5%Ji1$JS+"JB"rIhjqIAepI(alHhTkHRPjHAPjH(KiH(KiH(K
+jHAPjHATkHRYlI(amIAeqIRprJ)#"JB+#Ji1%K)@&KBD'KSH(KiH(KiH(KiH(KiD
+'KSD&KB@%K)1$JS+"JB#!IhpqIAepI(alHhTkHRPjHAPjHAKiH(KiH(PjHAPjHRT
+kHhYmI(apIAjqIhq!J)'"JS+$Ji1%K)@&KBD'KSD(KiH(KiH(KiH(KSD'KS@&KB5
+%K)1$JS+"JB#!IhpqIRepIAamHhYlHRTkHAPjHAPjHAPjHAPjHATkHRTlHhYmI(a
+pIAjqIhq!J)'"JS+$Ji5%K)@&KBD'KSH(KiH(KiH(KiH(KiD'KSD&KB5%K)1$JS+
+"JB#!IhpqIRepIAamHhYlHRTkHRTjHAPjHAPjHAPjHRTkHRYlHhYmI(epIAjqIhq
+!J)'"JS+$Ji1%K)@&KBD'KSD'KiH(KiH(KiH'KSD'KB@&KB5%Ji1#JS'"JB#!Ihp
+qIRepIAamHhYlHhTkHRTkHAPjHAPjHAPkHRTkHRYlHhamI(epIAjqIhq!J)'"JB+
+#Ji1%K)5&KB@'KSD'KSD(KiH'KSD'KSD'KB@&K)5%Ji1#JS'"J)"rIhjqIAepI(a
+lHhYkHRTkHAPjHAPjHAPjHAPjHATkHRTlHhYmI(apIAjqIhprJ)#"JB+#Ji1$K)5
+%KB@&KSD'KSD'KSD'KSD'KSD'KB@&K)5%Ji1$JS+"JB#!IhpqIRepIAamHhYlHRT
+kHRPjHAPjHAPjHAPjHAPjHRTkHhYlI(amIAeqIRprJ)#"JB+#JS1$K)5%KB@&KSD
+'KSD'KSH(KiD'KSD'KSD&KB@%K)5$Ji+#JB'!J)"rIhjqIAemI(alHhYkHRTkHRT
+jHAPjHAPjHRTkHRTlHhYlI(apIAeqIRprJ)#!JB'#JS1$Ji5%KB@&KBD'KSD'KSD
+'KSD'KSD'KS@&KB@%K)5$Ji+#JB'"J)"rIhjqIRepI(amHhYlHhTkHRTkHRTkHRT
+kHRTkHRYlHhYmI(apIAeqIRprJ)#!JB'#JS1$Ji5%K)@&KB@'KSD'KSD'KSD'KSD
+'KB@&KB5%K)1$Ji+#JB'"J)"rIhjqIRepIAamI(YlHhTkHRTkHRTkHRTkHRTkHRT
+lHhYlI(amIAepIRjrIi#!J)'"JS+#Ji1%K)5%KB@&KB@'KSD'KSD'KB@&KB@&K)5
+%Ji1$JS+"JB'!J(prIhjqIAepI(amHhYlHhTkHRTkHRTkHRTkHRTkHRTlHhYmI(a
+pIAeqIRjrIi#!JB'"JS+#Ji1%K)5%KB@&KB@&KBD'KS@&KB@&KB@%K)5%Ji1$JS+
+"JB'!J(prIhjqIRepIAamI(YlHhYlHRTkHRTkHRTkHRTkHhYlHhYmI(apIAeqIRj
+rIi#!J)'"JB+#Ji1$K)5%K)@&KB@&KB@&KB@&KB@&KB@%K)5%Ji1$JS+#JB'!J)"
+rIhpqIRjpIAemI(amHhYlHhYlHRTkHRTkHhYlHhYlI(amI(epIAjqIRprIi#!JB'
+"JS+$Ji1%K)5%KB@&KB@&KB@'KSD&KB@&KB@&K)5%K)1$Ji+#JS'"J)#!IhpqIRj
+pIAemI(amHhYlHhYkHRTkHRTkHRYlHhYlHhamI(apIAeqIRjrIhq!J)'"JB+#JS1
+$Ji5%K)5&KB@&KB@&KB@&KB@&KB@&K)5%K)1$Ji+#JS'"JB#!IhprIRjpIAepI(a
+mHhYlHhYlHRTkHRTkHRYlHhYlHhYmI(apIAepIRjqIhq!J)#"JB'#JS+$Ji1$K)5
+%K)5&KB@&KB@&KB@&KB5%K)5%Ji1$Ji+#JS'"JB#!IhprIRjqIAepI(amI(YlHhY
+lHRTkHRTkHRTkHRTlHhYlHhamI(epIAjqIRprIi#!JB'"JS+$Ji1$K)5%K)@&KB@
+&KB@&KB@&KB@&K)5%K)1$Ji+#JS'"JB#!IhprIRjqIAepI(amHhYlHhYlHRTkHRT
+kHRTkHhYlHhYmI(amI(epIAjqIhprJ)#!JB'#JS+$Ji1$K)5%K)@&KB@&KB@&KB@
+&KB@&KB@%K)5%Ji1$JS+#JB'!J)"rIhpqIRepIAemI(amHhYlHhYlHhTkHRTlHhY
+lHhYlI(amI(epIAjqIRprIi#!JB'"JS+#Ji1$K)5%K)@&KB@&KB@&KB@&KB@&KB@
+%K)5%Ji1$JS+#JB'"J)#!IhprIRjpIAepI(amI(YlHhYlHhYlHhYlHhYlHhYmI(a
+mI(epIAjqIRjrIhq!J)#"JB+#JS+$Ji1%K)5%K)5&KB@&KB@&KB@&KB@%K)5%Ji1
+$Ji+#JS'"J)#!IhprIRjqIAepI(amHhYlHhYlHRTkHRTkHRTkHhYlHhYmI(amIAe
+pIRjqIhq!J)#"JB'#JS+$Ji1%K)5%KB@&KB@&KB@&KB@&KB@%K)5%Ji1$Ji+#JS'
+"J)#!IhprIRjpIAemI(amHhYlHhTkHRTkHRTkHRTkHRYlHhYlI(amIAepIRjqIhp
+rJ)#!JB'"JS+#Ji1$Ji5%K)5&KB@&KB@&KB@&KB@&K)5%K)5$Ji1#JS+"JB'!J(p
+rIhjqIRepIAamI(alHhYlHhYlHRTkHRTkHhYlHhYlI(amI(epIAjqIRprIi#!J)'
+"JS+#Ji1$Ji5%K)5%KB@&KB@&KB@&KB@&KB5%K)5%Ji1$JS+#JB'"J)#!IhpqIRj
+pIAepI(amI(YlHhYlHhYlHhYlHhYlHhYmI(amIAepIAjqIRprIi#!J)'"JB+#JS1
+$Ji5%K)5%KB@&KB@&KB@&KB@&KB5%K)5%Ji1$JS+#JB'"J)#!IhprIRjqIAepI(a
+mI(alHhYlHhYlHhYlHhYlHhYmI(amI(epIAjqIRjrIi#!J)'"JB+#JS+$Ji1%K)5
+%K)@&KB@&KB@&KB@%K)5%K)5$Ji1$JS+#JB'"J)#!IhprIRjqIAepIAamI(alHhY
+lHhYlHhYlHhYlHhYlI(amI(apIAepIRjqIhprJ)#!JB'"JS+#JS1$Ji1%K)5%K)5
+%K)@&K)5%K)5%K)5%Ji1$Ji+#JS'"JB#!IhprIRjqIAepI(amI(YlHhYlHhYkHRT
+kHhYlHhYlHhYmI(amIAepIRjqIhprJ)#!JB'"JS+#JS1$Ji1%K)5%K)@&KB@&KB@
+&KB5%K)5%K)1$Ji1#JS+"JB'!J)"rIhjqIRepIAemI(amHhYlHhYlHhYlHhYlHhY
+lHhYmI(amIAepIAjqIRprIi#!J)'"JB+#JS1$Ji1%K)5%K)@&KB@&KB@&KB@&K)5
+%K)5%Ji1$Ji+#JS'"JB#!IhprIRjqIAepIAamI(amHhYlHhYlHhYlHhYlHhamI(a
+mIAepIAjqIRprIi#!J)'"JB+#JS1$Ji1%K)5%K)5&KB@&KB@&KB@&K)5%K)5$Ji1
+$JS+#JB'"J)#!IhprIRjqIAepIAamI(alHhYlHhYlHhYlHhYlHhamI(amI(epIAe
+qIRjrIhq!J)#"JB'#JS+$Ji1$K)5%K)5%KB@&KB@&KB@&KB5%K)5%K)1$Ji+#JS'
+"JB#!J(prIRjqIAepI(amI(YlHhYlHhYkHRTkHhYlHhYlHhYmI(amI(epIAjqIRp
+rIhq!J)#"JB'#JS+$Ji1$K)5%K)5%KB@&KB@&KB@&K)5%K)5%Ji1$JS+#JB'"J)#
+!IhpqIRjpIAemI(amHhYlHhYlHRTkHRTkHRTlHhYlHhYmI(amIAepIRjqIhprJ)#
+!JB'"JS+#Ji1$Ji5%K)5%KB@&KB@&KB@&KB@&K)5%K)5$Ji1#JS+"JB'!J(prIhj
+qIRepIAamI(alHhYlHhYlHhYlHhYlHhYlHhYmI(amIAepIAjqIRprIi#!J)'"JB+
+#JS1$Ji5%K)5%KB@&KB@&KB@&KB@&KB@&K)5%K)1$Ji+#JS'"JB#!IhprIRjqIAe
+pI(amHhYlHhYlHhTkHRTkHRYlHhYlHhamI(apIAeqIRjrIhq!J)#"JB'#JS+$Ji1
+%K)5%KB@&KB@&KB@&KB@&KB@&KB@&K)5%K)1$Ji+#JB'"J)"rIhpqIRepIAamI(a
+lHhYlHhTkHRTkHRTkHRTlHhYlHhamI(epIAeqIRjrIhq!J)'"JB+#JS1$Ji1%K)5
+%K)@&KB@&KB@&KB@&KB@%K)5%K)1$Ji+#JS'"J)#!IhpqIRjpIAemI(alHhYlHhY
+kHRTkHRTkHRTkHhYlHhYmI(amIAepIAjqIRprIi#!JB'"JS+#JS1$Ji5%K)5%KB@
+&KB@&KB@&KB@&K)5%K)5$Ji1#JS+"JB'!J(prIhjqIRepIAamI(YlHhYlHRTkHRT
+kHRTkHRYlHhYlHhamI(apIAeqIRjrIhq!J)#"JB'#JS+$Ji1$K)5%K)@&KB@&KB@
+&KB@&KB@&K)5%K)5$Ji1#JS+"JB'!J(prIhjqIRepIAamI(alHhYlHhYlHhYlHhY
+lHhYlHhYmI(amIAepIAjqIRprJ)#!JB'"JS+#Ji1$Ji5%K)5&KB@&KB@&KB@&KB@
+&KB@&K)5%K)1$Ji+#JS'"JB#!IhprIRjqIAepI(amI(YlHhYlHhYlHhYlHhYlHhY
+lI(amI(apIAeqIRjrIhq!J)#"JB'#JS+$Ji1$K)5%K)5&KB@&KB@&KB@&KB@&KB5
+%K)5$Ji1$JS+#JB'!J)"rIhpqIRjpIAemI(amHhYlHhYlHhYlHhYlHhYlHhYlI(a
+mI(epIAeqIRjrIhq!J)#"JB'#JS+#Ji1$Ji5%K)5%KB@&KB@&KB@&K)5%K)5%Ji1
+$Ji+#JS'"JB#!IhprIRjqIAepI(amI(YlHhYlHhYlHRTkHRYlHhYlHhYmI(amIAe
+pIAjqIRprIi#!J)'"JB+#JS+$Ji1$K)5%K)5%KB@&KB@&KB5%K)5%K)1$Ji1#JS+
+"JB'!J)"rIhpqIRjpIAemI(amHhYlHhYlHhYlHhYlHhYlHhYlI(amI(apIAeqIRj
+rIhprJ)#!JB'"JS+#Ji1$Ji5%K)5%K)@&KB@&KB@&KB5%K)5%K)1$Ji1#JS+"JB'
+!J)"rIhpqIRjpIAepI(amI(alHhYlHhYlHhYlHhYlI(amI(apIAepIRjqIRprIi#
+!J)'"JB'#JS+$Ji1$Ji5%K)5%K)@&KB@&KB@%K)5%K)5%Ji1$Ji+#JS'"JB#!J(p
+rIhjqIRjpIAepI(amI(amI(YlHhYlHhYmI(amI(amI(epIAeqIRjqIhprJ)#!J)'
+"JB+#JS+$Ji1$Ji5%K)5%K)5%K)5%K)5%K)5%K)5$Ji1$JS+#JB'"J)#!IhprIRj
+qIAepIAamI(amI(YlHhYlHhYlHhYlHhamI(amI(epIAeqIRjqIhprJ)#!J)'"JB'
+#JS+#Ji1$Ji1%K)5%K)5%K)5%K)5%K)5$Ji1$Ji+#JS'"JB'!J)"rIhpqIRjqIAe
+pIAamI(amI(YlHhYlHhYlHhYlI(amI(amIAepIAeqIRjqIhprJ)#!J)'"JB'#JS+
+#Ji1$Ji1%K)5%K)5%K)5%K)5%K)1$Ji1$JS+#JS'"JB'!J)"rIhpqIRjqIAepIAa
+mI(amI(amI(amI(amI(amI(amI(epIAepIRjqIRprIhq!J)#"JB'"JS+#JS+$Ji1
+$Ji1$K)5%K)5%K)5%Ji1$Ji1$Ji+#JS+#JB'"JB#!J(prIhpqIRjqIRepIAepIAe
+pI(amI(amI(amI(epIAepIAepIRjqIRjrIhprJ)#!J)'"JB'#JS+#JS1$Ji1$Ji1
+%K)5%K)5%K)5%Ji1$Ji1$Ji+#JS+"JB'!J)#!IhprIhjqIRjpIAepIAemI(amI(a
+mI(amI(amI(epIAepIAjqIRjqIhprIi#!J)#"JB'"JB+#JS+#Ji1$Ji1$Ji1$Ji1
+$Ji1$Ji1$Ji1#JS+#JS'"JB'"J)#!J(prIhpqIRjqIRepIAepIAepIAepIAamIAe
+pIAepIAepIAepIRjqIRjqIhprIi#!J)#!JB'"JB'#JS+#JS+#Ji1$Ji1$Ji1$Ji1
+$Ji1#JS+#JS+"JB'"JB#!J)"rIhprIRjqIRjpIAepIAepIAamI(amI(amI(apIAe
+pIAepIAjqIRjqIRprIhprJ)#!J)#"JB'"JB+#JS+#JS+$Ji1$Ji1$Ji1$Ji1$Ji+
+#JS+#JS+"JB'"JB#!J)"rIhprIhjqIRjqIRepIAepIAepIAepIAepIAepIAepIAe
+pIRjqIRjqIhprIhq!J)#!J)'"JB'"JS+#JS+#JS1$Ji1$Ji1$Ji1$Ji1$Ji1#JS+
+#JS+"JB'"JB#!J)#!IhprIhpqIRjqIRjqIAepIAepIAepIAepIAepIAeqIRjqIRj
+qIhprIhprJ)#!J)#!JB'"JB'"JS+#JS+#JS+$Ji1$Ji1$Ji1$Ji1$JS+#JS+#JS+
+"JB'"JB#!J)#!IhprIhpqIRjqIRjqIAepIAepIAepIAepIAepIAepIAjqIRjqIRj
+rIhprIhq!J)#!JB'"JB'"JS+#JS+#JS+$Ji1$Ji1$Ji1$JS+#JS+#JS+"JB'"JB#
+!J)#!IhprIhpqIRjqIRjpIAepIAepIAepIAepIAepIAepIAeqIRjqIRjqIRprIhp
+rIi#!J)#!JB'"JB'"JB+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JB'"JB'"J)#!J)"
+rIhprIhpqIRjqIRjqIAepIAepIAepIAepIAepIAepIAepIRjqIRjqIRprIhprIi#
+!J)#!JB'"JB'"JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JB'"JB'"J)#!J)#!Ihp
+rIhprIRjqIRjqIRjqIRjqIAepIAepIAepIAjqIRjqIRjqIRjrIhprIhprJ)#!J)#
+!JB'"JB'"JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS'"JB'"JB#!J)#!J)"rIhp
+rIhprIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIhprIhprIhq!J)#!J)#!JB'
+"JB'"JB'#JS+#JS+#JS+#JS+#JS+#JS+#JS'"JB'"JB'"J)#!J)#!J(prIhprIhp
+rIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIhprIhprIhprJ)#!J)#!J)'"JB'
+"JB'"JS+#JS+#JS+#JS+#JS+#JB'"JB'"JB'"J)#!J)#!J)"rIhprIhprIhjqIRj
+qIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRprIhprIhq!J)#!J)#!J)'"JB'"JB'
+"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)#!J)"rIhprIhprIhprIRjqIRj
+qIRjqIRjqIRjqIRjqIRjqIRjqIRprIhprIhprIi#!J)#!J)#!JB'"JB'"JB'"JB'
+"JB'"JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)#!J)#!IhprIhprIhprIhprIRjqIRj
+qIRjqIRjqIRjqIRprIhprIhprIhprIi#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'
+"JB'"JB'"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhpqIRj
+qIRjqIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"JB'
+"JB'"JB'"JB'"JB#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIRjqIRjqIRjqIRj
+qIRjrIhprIhprIhprIhprJ)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'"JB'"JB'
+"JB'"JB#!J)#!J)#!J)#!J(prIhprIhprIhprIhjqIRjqIRjqIRjqIRjqIRjqIRj
+qIRprIhprIhprIhprIi#!J)#!J)#!J)#!JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'
+"JB'!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhjqIRjqIRjqIRjqIRprIhp
+rIhprIhprIhprIi#!J)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'
+"JB'!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIi#!J)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'
+"J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprJ)#!J)#!J)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)#
+!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!JB'"JB'"JB'"JB#"J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!IhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!!!"&3!!"!!%!"3!!!+!!!B"4!!!!!!!8!!!!!!!
+!44C@lSZM!!"&&!!!448!2)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!IhprIhprIhprIRTjHRTlHRCfH(*ZEfYSFR9eKBeeAeP28'CeHiU4J(CdCQ&L9PT
+fJAZ#J@TME@P[LBaiEfePCh"ZGib,K)Q!E@KI6&Z"M)kGPS"kEPYJEh"eK)@%LRY
+TG(piJ*!!KRaqEPeYJ)#*P)q1LR*KD'GPIC+3!*LMMAChDeeVIAk*NB*lJAYdIAj
+mNC9lG(PRAhZ,LjZBI(L!F@*NDhf9QC5HPA4QC@"aLiChK)alGhplJ)U(KSq+Hh4
+UB(@0LBqHMA*[Df0cKS'(QTUAP(eSE@jRHSf'KBThES1*IBH@M)D'GR"jFQYrMj+
+FPRPZG'GLHif4S+',KBTiCQGUGiD%J)k4Hh4rJSZFNRYlHfCLFhf'NBU,QT!!G'P
+MA(#1P*qcS(TcG@YbHQYVK)U&M)KrL)KqMU+6IhTQ@A5)JBqNPi5!HhGhDQ@"Qk#
+YVj*qH@*BHSjpHi4mISk,KT'0JSU1KBKqB'&hHB@VVBPiF@*RHReqLj'EUjprG'e
+FB'pdJTH5GA1*PCU@K(CiI(q'HfG[Hi1JVSPTG(GPFSZ+Lj+2NCZBL(GK@h"kH*+
+LK('!KSLIRhPYIRjjHhPlI(4mQk52JQj*8i'-MUZVJ(5(JAGkDePNHBL9PiCiD9q
+'ZUk'FQ*CES4pJ*++J)k8LheM69ChNUUiRB"lF'GqMACPFAL"QCQ#HAClNk#AN!"
+m8NGUJSQBNR0aKRj`GQjDBRbBX+k6H@KJFik$FhjkBh1FRB@#JRk0PSYmCP4CDhZ
+AVTKeF@TIF(jXCS'4MjkQNRjU9Q&qMC',EQ1'PiUBT)CcKBf"IQp,5(@KXk@+I("
+@9(H)ISQ6Ii#BNhYaD&eUJSZ-IfKSHAq1TTerHhTPCRPZ@fZ(PD'MLh4J8Q1!MCb
+TPRk*NAYfJ("RHS*kHAGUCfplPkL5IAGJ6f9lFAD4NBfHQAeXBeYNJTZLPi5$L(G
+YK)afG)9pGB&lF(k1N!#9Q)q!CNY6DQaiQTq-MC&mEA*VC(Z@TDUGLiCqGiD9MBf
+8JR5%Lhf%R*U4PBTdC9G19@*dMj0lGRKG6@0XCRbEQC@GNAjfEQplHhU"GepRI(Q
+)VDb9PC&eDQaHARU-Q+@NQ)9N8fH!LD5rUSb2KQeXG'KRJjL5GeP6@epeRVDZT)j
+@-d&$3@U9RD+cXU#+E&TKF)fVUTL9L'PdQCL+MB4bFR*F699QJCfZ[Dpa2d"*6R@
+JSCZMNRKlJQjIG*UiZU'0H&G@GibFX+"`BA"N9fYlHB5AQije@%G%8)'aTSf+G90
+AE'9QJBf-QD@HMAk!QV#f[DjmA&e9@)+DIh+'LA9QA&KJEB@NXDZJI8Y*DQjLGSK
+rKTqNT+kRQ*kVVCYf@9YF@RUGPBQ+GQ*fMRpbJ)H!K)PrDPGBCfa`K)PZDAY`DSq
+SQ*!!Rjb3!*53!)"`C@q"I'pZBdpHJSf9V+D(L*Q0FfKPB&jLFiD)KiKmHjZaSCZ
+RPRU!M(YUCPT19@KeEQ&ZLBf5XVfCKT')I)H$Be0EB@PrNTL3!)'*T,#[VTPmJj0
+qDh&P5%CGD'GUE("eHj!!SjkBP(PGC(4N9@0SD)5PX,'iZ+qVVE1aQSZ,Ih*lH9j
+@BPP4Di*pGAf+QDHTS)a[APP)3PCF5daPFA@(KR"YIif6Q*b@KA0cJB0qIR4UHC'
+2M+HeV,2#ZTjqC&&*6f&dHAf,KhZ0S**qK)Q#ND'9I@aNB@*UFfjA6f9bFiZNUVM
+!U)k@Q(09@'PfJBZ4M)5(P*+3!+#HI@jhE&06A9*1@&TEBfTN@@&qQk+MVkD"E'j
+VEB'+J)qh`lDYUDQSVXACe,qXM'KYHf04BfYC@'YS99*EFBUGTj&H1$!Y+6jB@9a
+`I(f&M(YMFTQcZVDUMA"XIBfDTTjqGj+HNj!!R+'P[Y6)TAeB1cG9Fh9TE(CZEiD
+0IRb*P+'aThT65%a39fq$G9eIGBHEXl'RZFQpU*f'B9&PKCZLST9c@fU!KBqNRSZ
+4NhPH6$NZ2PPNBPeC8deEJ*LCR*k2JBb0FQ9ZF(')V,QcV+kf[ml@`UDJSjZHXl#
+0HRKSA'CX@%KAF)L@NS"F3e4XDPeA35Ne8f4dM*@,LU#eVjCrIBDAXlULK@j00e1
+$P*bZYl[$aE56HA"`F("jFeK1A'PlT,LFJSH0M)k#E'C[HS1&GQ"(-6PBEhk2P*5
+Xcp'qY+5&DfTeHA9cG(D%TVkXNj19LS5)IQjZEQPaJB*N1bJ[394VJSk8QBprHA9
+K6&4[L*bKPSZ&M*@GV,ZmVU+PT*qNTk+LUkQ0EP8r0dCQLkc$al+5IA9P5M`k3&K
+bH'PJC'4MES@CRjD'ISZNUSppLBjiC&Y@9f&[LERLk0#YQT&h9e"HCfTeIiD9N@j
+9C)#3!*D9Li5#JB&mHi4lA%C5B9aGF)@K`pE4[kCr9%*0CRU0TV+[YEZUMiH)JSQ
+GS*D8PiapISf1E6iS,$%j499iTm#hVUU,@cFZ2@'(QCQ9P*1)ISkYY+fe`m5kUSk
+"P+HKMAjV45N`8h+&Q+5CMBTf8$Xk0MpRKS*cDQCPFBZLUkqhYk'@S*U%IB@(KB4
+b8dC-ARZVi2(6VCL*F'"KAf"cJ(eqKRC44f1(SUbRNh9MDACqLBprEhb"C%3p4&9
+qX0,JelD*D@CfJB1*PTQARTZ$EfppP,I3`*PkEQpkLT'#E@&9363j1$*,H*HNTjC
+U3$4$B)'DSjU5PjD%FR5!MUh5hp6!UC10RDbNMATV@8K-Ah#%R+baXk4i5$!Y190
+bJhpcD@"@9f9cHikSYVQjVjH1Qk5KRjb'Be*GFBQQa-frY+Q0E9e869f"P*!!LAj
+P58CFFAZ"KB&pK)GeD'eZB9TE8d9#4e9qZ0hFbELKJ@0FC@4UKCq[[lqIH("mJSL
+9SD#ANC'@QjH$CPKB5c-U,M0(GU1j[E#0BNK(694QIik5QU'6I(ChH)QU[EUeX+#
+8Q++GLhe`A8e0@'&fRll$a,fED8Y!0ceCFhYjHR9J6&"LFAk9TUU`XCU%LTUBMif
+"C8j-@@Q$U-6-bmQaKfpR8dPII)+"Jh&869eNA@0jJRPjLBPiGAelHB1!D&C86e"
+[RVUq[EURLhYdDQf'S+Ha`V+&D'T[Ehq5PBk-MB9pJB"XB'KS6MSm1MPDL*bHSja
+k9da+4%9HI)Q9UDU5IhKZEj+eYUqj[+@4PTb6LSGiA&"A8NCBISq@V,D@DP!l+64
+FGA9mM)ThFRelFi+IVVI'[TQ'NjqKUlDVMRajFh'#Q*bJZXDRIQ4&)LG5EhH$LRG
+B68`q-N&CB'H!LR*EAf4LG)k"@dBr0$aNMk'[bpE&XkZ@GAQK[FVHjX5@K)*mJ*@
+KQjUMQ(edHR&JD(ac8M`S#!)S8QZ(TU@(F@TD5P4bKC'UZ*jlF@eNFjkkYl#YRSU
+(N!#2MTLHLfeD4LBF0eYeNUDCG9a21c*'CR9lLj+$EQ9I@@kBXE1eXTQ#KjkZZmV
+)VjD+H&a5Ci'@Y-l#QA9E3N"GGAPiI(CM9P923NKJE@ebFeP!5&TQHjDCIQ4@4M)
+a4PpfP+k`Sj@!C@@1YF,*d-1TQ)q&KC@PTD+XX*YrHAjqKjH5FeFp'`SL5fKiLjL
+6JQpG58GGGi5@UCprDfTXGSkLTU5STjH(L)b(L*56Hf*,+K8P49efN!#9K(0ZD@"
+GD(4lK*!!Mi0pHh4lQl5aU+HJNj5LVV5iYkL4Ih&E599hNUM#bE+5H@"5A'PRAf"
+PANe%4NG+A(4lH(*K5NPHFAf)MApQ8N-d-%&II*l#d,qRQBYpKk#VVE'bV+Q[XUD
+FSkkRPj1-GfpjJ)'+Lh*53$%K)cYCEhb,NSU#Ih4NDS'(J)D0JR4dGRH"M)k*KBZ
+5Mj+KTCL6P)"I56BN+%0FDA4rHQPKC@GG@QK`GB@8MiH,MifCVlHVRjZFRkZj[,D
+cVjZ!G@Y@6f@#Nk+VRSZ!H'aPD@aPAQ&QBPYFA&CFE("SD@YJ@QCiJB&qG@GE98j
+'5Q*hJjHYVTb1L)+&NCLFTV+cUkLbYUqXXV5TSCU+JSZ3!)f2PBGS6d%p2N98C'e
+fIha`EQjJ@@b"KBH*JRPpKSfCTkbPRD#QRC!!NTQ6MBk%E9a32MG+BQKPCQPM8NT
+06%Y8A&eTJ)4lLD1[Y,r%[V5SR*QKVV@ZUV1cR)D#HR1"PCkSYDk8JAYeE'GTE'T
+XGhGXDR*aEhq,HQGK9dP+A@abG(4YBPYG9NK4DR4iLTH1KBD&JBQ8P*!!PU'NRk'
+YXkqd[V@NQiPbG)L3!*!!PTU0H@KD6dP-9epVJBq'IS+#H(Z(K(eqHhCkKj@IUE'
+dUCH3!)q'K*!!Q*LDPAaM@P&!1dGBAf&PDfeUD@CF@@"B5%T68&4YM++f`EkeV+1
+GR+HlamE*d-HaST@)LTQIRD'PRT@6PjZ8KRPYA9&*2cY,@f0cKiCeDQ4IB'CUE'a
+YE@056eC@@'apJ)L3!)Z'MC14NC52K(elIAk#NkH`Ym#mVDLQQ*1HSjZ8MAp`Cf0
+NDA&qJAGdIAjjJBq3!*!!P)TiEQPKAh#,RkLUVDbKPj@4Mj@8Ki#"G@&FB@9QBea
+86%G)6P4MFhCaF@T94NG+8'9pMTqZX+UQTUUVUUqiYDfUT*QFTD1JU+QGNSq2N!#
+5PTbHPB9b@NY-68pKGRPcGA9XBea@99TKBepFA9pFB'aaEQeVAeeSF(*rNTbKSk#
+CMi@%MCZ[`F1q`m1`T+DMPSq2M)Z*I@pVFheqFfGJ8d9)99jXIi@(N!#1H@9F@&P
+MGBZFSD+PTD5ST*D4Q*@,Lib$HhCZE'eL6MSb1NP5A(+!I(CbBP*268TAGC!!S+U
+aYE5[Vl+aVl+bVVE"[,Dl[,1YTjU+J(b!LjDJTU1ENRYI9&K46&PTER*bDfGSCQ*
+NDA"[B9GFB9jIBPeGBea5A'a[F)#ATkfTSTf@NT5CSl5lX+UeYkbQTDDUVDLFNSK
+pFfpfIhY[DfGF@@&QEi16PC@@L'jA69*IEAf,Mj+CR*UNXl1ZY,DSPB4aC'*MC'9
+N@d`l18K@B(+'LB0rFPT-5djDGT'FQC@8NT!!PUHeZm'rXUZXT*16SDHPSjf6M)Q
+1QUUl`V@IN!"m@8!p3846C@aYEQKH@f0YF@p`FQTE8e06@&pE@@&P@%pBCh@(QkU
+[TT1$IB14Q*UQYlQaVkqSSk5MT+QPNRTVD'TVERGlFfTM9e"@A'9qR+LINS&ZB&T
+IEAk1QCQ@QTk9N!#DSk@TUCb*I(9`FRPmG@GD88Br3dj@CRk+K(PQ5$-f4&0PHiZ
+5PCQFQCLJUDbbYkZAMiZ#JSqGTUQNQBk-NCUMVlfpUjQ,FeY489KTI)&jF'PJ@&G
+LF(GfGA"RCQ4E@'9`E@PSAP06@QL!RDk[TCH)H'ehLTDP[FV(`EDJNjQMSk'KQSC
+aD@TXEhZ&JAGY9d!k3NTCGT!!Q*1*HQYNC@YbJ*1AL(q"IACqMjfXZE5KPT+*IRk
+*NBKhCP-r06Fq8'epGfjVA88k3P0TJ*1FQT5,IRH#NTHEUE+YUULJQCfQUDLJMRC
+PCA5&PDZp[E+SPATTAe02A@aVB&G04%&*@'0UFA"PBQKQA@CmKS"iE&Y04dP@F)f
+IR*@APSKrKj5LYm5qYV+PN!#+PD'RUDUMNAphFh*lKS&dE@*+1Mj,@R+1SUQQQB0
+UB'9YFi'4NSH#IhKiIi1)PCqEN!#)KiU3!*fZXUD4H9j069"6CAk0MSKmCdp"4&&
+PHB@#HRGdEA'%NjZQVkZHNSL#KT1HSCb8KhCYHBqKXmI3cmQjQi"bE'PaJ)L"EeY
+04N9,8&GNFA"RD'YTD("hHhacB903@'4cLkHfYE'TQ)4iFhH+T+qZV+LGNBk8R+#
+MS*@*Ih4RBfa`D'*J98C!4%jJHC!!Rk5KNhaTCQY[HBU6NT!!M)"dGRf$MTqXUU#
+EQjZGT+5CMB&YA&PIBff"PCZ@L'e11$!b2&"RF@pZEfKMDR0mLTbNRCH8N!#2QDQ
+dXkUINB0qK)ZCVm$$a-'YMhGUBf*VGhYhF'CD8eTMC@PeHA"SCf4KD("aFhCaBPC
+CC(&rNk@TTTk2Hh0dGAL+RkDQTD#CP*+5P*UIQ)GrJS"jISb2L(pbB&436%jHH)b
+4MiTrE&eC@&YTHAq$M)q)KSk9Qk+RSTD1M)f5S+fZU+5CJh&YDQ9UH)+)Li&T8de
+38PKUI(aeGACbFRGiHiQAPBZ,Miq3!*URVl#TQiZ&KS@%N!#QXV5fXk@5Jh9[GiH
+0LB5#HfeQDQeVD'KMAf"I@9YRFACjH@pE58*%6&jcJBQ6QT@3!*'2KiQ@SULVUU5
+HR+'QU+LMPSU-Nj'-M)U&JAKS9dj*3dKEG)+$JAjiFh*aERH)N!#4Q*k@Ki5,NC@
+@NSZ(L)U)MCQEMi4qF&j66%0'@@efHhppG'p`FR"ZFhCcG(TjGRZ#KSqFRjL8Nj!
+!LiZ4Q*H9NiTrHhYdF(f3!*fSXV1USCQ3!)k8QCD-KiL#GQjSB@"RE@jeHh&PC'T
+VCf&C6d8r2Mp'@@YfKjfST*qCM(ppJiU8RD'LT+QYUkUZXDbUVDUHPSk$HhKaBe9
+04Mir5eaZJ*+DQjQ5JA0cGR*bIB@$JS+#JiU6QCfRX+kNS+#BMSQ$GfaL8dG)8Pe
+PF(arGfjQA&069eGIFAajGhk"JSL6Qk#LRjL8PjZCPTUFNiU)K(erLjLT[-M'Zkk
+HLAKbF@eSDfjTC'9PBfPbGhU!JReiHRjrIAPcD@&E8NP+9Q"VIC!!Q*@1JR9[Eh0
+jKT@HS+1UVkbUUkbVUkDCN!#1LS&mIhjdD@4JA&eRFAU*P*++Ki&cD@aaG(KmI(P
+jH(9fJT+9NTHJSU#KRjQBQC+)JAKQ9P0DBfYeI(K[D&e24dT08&pcI(f!K)D,PCZ
+DQ*H5LSH+LB+#MT@9P*'*JS5,PDDh[EH[UCq1J(PiGhKmHRCbE'*KEAGeFh9cE'9
+MCQehJ)"lHA0H5NG3@QChKik4M(jcG(b"K)fESCqJSTqGSkUYXV+PNBD"HA"`GRC
+`E'TMAf4UEAH+PjQDQSjqGACjI)"rHA0aEQPVGi1,NjU@MBL%IS#,NSf&J(9QA9Y
+E@f&[IB+%IQeIB@TZFAPqHA*ZE'pkKBQ,Mj11JAPeFA5%PCbHQSq%JSD,NTkVXl5
+cX+DBMib+LSZ&GfeSAeKHDh&aF'jVCQ*IA@&YHAalGQG33d0*9'4dJ)Z5Mi9pIB+
+&LT1AMS0lG(4qLT'ARjq8LB4rHhPlJSZ4NBChF'p[GiQDS+#GPSf'K)+%LBb)JAa
+iF@KTGB')Mj+0LB4pH(f)LiH#IA0Q@9*6@fKdHAYlGQPKBf4MBQ&F@&9489PRGAf
+$MC10JhpqJ)QASDZeYDQGPj@@Qk1XXE+cXDbUVDZNS*b2I@pK9P4EC@aaFQaL@PK
+B@fCeHR4ZCPC'2ce%@'jlJSL+KRjkHRepIS"rI(YjG(L(NT@BR*U4KhjjI)1)Lj+
+EQialGA9bFhf(MC5DR+'TUk5FPik!FfeYE@aaH(q(Mib'K)&lGhGiGh9`D'*G@PT
+FBQeeGhf&JRKaDf4KBQ*NDQjXDfphI(jrJB*rIhppJ)Z5PCbMRT+(JS+(MC5FTV#
+hZVUlZ+ZJR*H1KRjeFhKpIAYlGfeK@P9158pCAPpG8N8q2$a'@@PbI)L2NBk*K)"
+rKBU+LSU%Ii50N!#5QCfDPT!!LSH,NC+3!*'5LhYXC'&MEAL#N!#ISCZCQC@0LBQ
+*KAplHRf#KSH*MSb"G@pSBQ&NCfYYD@"B8e059&jXGi'(KS&rI(9bGRPhFh&`FRG
+qK)L1PCL5LS4qIBL8Q*ZLSCL2LSD&KSL0NjfNSCZFSkHPT++BMSGrHRTpI(KkIRY
+[B9P88&4GC'PXCPK389"08&PMERGjGhKmJ)'"L)b)Ji1#J)@-N!#9RU@QT*qAN!#
+0NCHCQCZDNSZ(IhGiI(YkIi+#JiL-MSf+KAjfF'PMC@jcGS#)Ki&qHRGiHhalJ)D
+$H'pVCepHBfGXFR4aFAGhFA"dGRCdG(0aFhGlJBZ3!)U"J)"qJBf@R+1VV+LJPSZ
+$JB+"J)1+MC+CQjH9NiTrHR9XC@CYGAYrJAafGA9cFRGhFR0dE@&B88Y)5e&BAf9
+SD'ahIRajJ)5$KBH&KSf6PTZKSTfAP*@@Q*fHRD#PSTZAMAPTC'4NCQeeI)1+M)L
+$Ih9VDQeUCQP`G(f,Nj15N!#+Ji'"J(apK)@"IRGR9Nj,6&KVG(CkJ)"mHRTjH(K
+pJ)@,Li5$Lik+L)U)KB@+NCUKT+'GQ)jlD'&LBfk#NjbLSTD1Mif%I(b!JS+'M)k
+1MSb+MT'&FfTTD'TeHhK`CPK+3$Ne0d*5BQeiK)D$K)L,NCLCPTQIS*kJTDDLS+1
+KPSU$Ii12PT55N!#$E@"GA@"RF(Z$L)L#HRCdEfjjJS1#KBL0PjfGR*ZAM)"mIS'
+#KSZ,KRaS88C%3802B'aeI)"rHhGdFhGrKSQ1PCD6Q++PSTf8L(ehGRU$MC@BQ*H
+2J(9bFR0kKSk9QjU4MBk0LBH)M)f,LSU0P*H5Mj'2JACfHAPjHhThF@9A5dC$2MT
+"6eTKD'jcHB'$KBk@Q*DAR++SVE+cVUHHP)f,L)@*P*UDQ*'$FfCHA'"SF(CpK)Q
+)KiZ,KS1%JhpqJ)1-PTZFR*bCMi@"IhYkJ)5%JRPQ8dP"1ce*9f*SDfaXDfTUERU
++NC'8Pj@4NTDCRTkCNSf*K)#$M*@DR*b6KAP[CfPdJ)L6R*bANiq-LBH)M*!!Nj5
+3!)f3!*'1MT16Li9rH(4cFR9kI(9R@&"+36T!69GIC@KXFR9eGhq(LBL*Mj5@QCZ
+HSkLMPj!!M)5!KT@NUkZNQj+(H@aQDQpcHB#%JAprJBD-M)H$JB#"KSf9QjqKRC1
+(IRCdHS@0P*D0I'TH9P&49f&YGAKhG(*[D@CUEQaRCQT`Ghq*PCkGNSH!HR9bHSf
+JV,1dVkLGN!#(LBq6Nj@BQCH6NC+8PT@3!)Z*KAaiISH2PCD3!)GlEQ9NDR"cGAP
+jEQ0G@945@@0ZGhakHAYlH(ChHAPkI(jrJiU3!*LLTjq4KhjiHS13!*ZMTUDPSTb
+3!)*mIS'$LC!!NT+5NT+8NiU!HhYlHhk&MC1AQTH1JR9TCQadHAk$JATeF@YNAf"
+QF(PlGh0cFh&bG(0[DfTSCfY`GAf'M)Q!Gh&VDR1"MTUNU+LSSjU9PCQGSD@RTk@
+LRjfHS*k9MBGrHRTrKSq8NSPrFf4A899FB@G[GA9`D&pC9eKGC@jcFh0fHhq#Ji*
+rHhCbFhZ'M*'@Pj+*IR0ZF(9rM*QMTkDLR*5-LSf3!*5APjDCR*fFQjQ6Li@#JS+
+&M*+@QC5+J(GYC'9YGAk%L)U*JhKYCQ4QCQCTDQPTER*eH(GcF'eTC@9UFRZ%MC!
+!LAedDfCTF(Q(QUHXVl'ZUD1LTUZ[XE#ZUkQPSD'LR*11LiL&KBD-P*D3!)GqG@T
+G999FC'pjIi&pEep@8e*48eTLCfPYGRarI(GeGhGbFRKrKSf9Qjb9KhKaEQpfJT+
+KU+LQSjb@NBf0P*QCQ*UDPT'0LBH&K)1$JB'$L*'BPBb$GQGJBQPcIiQ0MBQ!F@&
+B9ePFB@KUDQKQCQY[EQYVE'YQBQ&REhQ&LiU#G@CE@PpTHSqHTDHRTD+HR+#SX,5
+bVUfVTU+LSk#BMSD%K)5)NCZKSCL+H'"*2N06ChKrIRYbC9P66de18PaSEQjVDQe
+hIi5'Ki&iFh9pL*+AQCD0J(*PB@9ZHikITD+FPC!!MSf0P*kNTkLQSjkBPCD9MiG
+qGA&dHS@6QCD0JhGVB9YFChL(NT@4KhCM@&C@9ePGB'4SDh"hIApqI(TfEQGQDh@
+$N!#9NiYkD9jEA@4aJBqDRTfCPC1@Qk'VXDqVUDQTUUUTTTq9LB"iFh0jKTDDNB0
+`@dY(6&GQFRTqIRGVA9"+58e9B'GSCQ4QEhPqIAYjG(&bGi'1Q*fHQT!!IfTD9Pa
+QGB54QTkFPj58NT'9R++QTUDQTkQXV+DHNi4iGA4dH(k"J(YaD'*JB@4VFhk%JRa
+eE@PTDQKQC&pHBfGVFRU$L)H#IRKZDQjjLTUHQ)k!EPj88PGMF(b(Mj+4MBZ1NTD
+DRU#IRk#PVVDjYl5ZS)YiF("fIBD0MBGkDPjFA&aLEA9jHA9ZCPa99&GGBQ9NC'C
+RDh@!KBD%IhYlI(k'NTfLSCb5JQpLB'C`I)D0Nj@5M)Q)L)U-NTZJSD+NU+bXUD@
+KPS9jG(0fHi'&L)4kEf9IAf&SG(q#IA9YCQ*HA'"SE@eYEh*fH(b%LiZ'IR4XDQa
+fL*LHR*@+IR*RB'&PDR0lJB1"IAb#LT'DRjqISD+QV,+eYE+USC5)Ji5)N!#DRjf
+8JfpL@eTHC@jeH(0YCep96Ne4@&jIAQ"ND'piJ)@'J(KcEfpaHBHCTkZPQSTlF'T
+UFhb!JiH)Ki5$KBZ4PjfJS*kEQ*ZPV+fUST@&H(&bHB'(MBk+J(*L@PYJD(4pIRT
+`C9pHAPjKCQPTCQ4REA0pLC!!NijrF@YVF(f2RD5LQ)f$GfaPBQC`H(YlHhKdGRk
+)NjQBPTHCQjqQVV5fXUZIMi&mISQDTDHKPS9bC&eFB@CVF(&YC9Y46%T,6e9B8dj
+16e9IDRD"L)L"HA9jJBbEUDqZTCH'HR&UEAL$Liq4NBf&Ii'(MT+6NT'2LSH0QU5
+RTjq8LB"mIiL5QCbFQ)emDQ"E@Q"QDfp[D@"FA&eF@9KEA9YC@Q*[ISU4P)q#GR*
+dIBZDTkqZTCD%FfGLBfajJS@%J(emIS'%LBZ-M)b-MT1ETV#cVkDCMSH&LjLRX,'
+VRiaiCPaDAQ0RDQaTB9G48&"28&056NT*6&CPFhq&L)@!HRKmK*'IUUkYSj'!G@p
+ZFhf&M)q0LSL&Ji1'Lj!!N!#-LBH&L*!!R+HXUU1DNBU'Kif@QjbDP)KhD@*JC'T
+VE'aTB&K999GA9PPGAepHAfGeJSZ5PC'(IhTmKT+GTUQPQieqFQTRCfjhI(jpHA9
+dGAGpJ(pqIRk!KBbAT,#fYDZGNBU)MjbTVl#URj+%Gh"[FRCjHACX@dT"2d**8&0
+88e"08&KLDh4lJ)+!I(f$MTkXY,LeTj5&HhCfHAk'M)q0KRplHAKjI(ppH(4cHB5
+1PCfLS*U6LS&mIB@3!*ZJRjH-JRTfHB#%K)1!HA"QA9C899CCA&jIA9jRFhk%KS*
+kG(0dIBZBSUUYUU#4JRKcFR9kIS&rGh"ZEQp`FhCkIRprJSD-NjZLTU5EMiL&L*!
+!QCqNTD#CNib'JS'&M*'4Li"bC&aA9eTF@PG98e09@&jQEA&eGR4aFRU+QkL`XUf
+JNSH!IS+&LBk3!)f&I(CfHi#'M)q-Ki"lHRf#LT1DQT5+IhGcG(f+PCUBMi9mGA&
+hJBf9Q*50K(T`DQGRD'GQC@4JAQ0YH(pqH(&YDfadJT+ITDDPRj1'IAPjI(pqHR0
+UC@CXFhU!K)H)KS1!J)5,NTLFQ)f#HhZ#M*@HTUDHNiH!IS'(NCZHQBk"G@aPB'&
+MC'0J@9*-5NY4@f4UDfKPC@K`Ij+KV,#XTCb4Ki5&L)b-LSL%IAYqKBb6PT11KRY
+fGRPrKSb2MSGpFfp`GAq)N!#9PBk)K)1)NCUKT+#BMB&fEfaYEh"YCf&F9P4BB'P
+`F@jUCQ0NDRD*QkDVUCq4KRjpJSD)Ki@"I(GbF(0kJ)D+M)Z(JAq$LBq6NSb&IhP
+iIB@1PCfKSTk@N!#2NCHITDDKPSCkFh"ZE@YSC&j@6dY)5P"AAf*LAejICA'"NCk
+QU+@JQT10Lif6PjD6MSCpGhCjJ)L,M)Z)JRelIB+(LBU+Ki&mGhL!LT1DRCZ8M)D
+%KiZ1NC58NBZ%IAG`E'YTCf4JA9eKC@PZF'pYDQPUEh@!MTULTU1FPT!!LiU0MBQ
+%IhYfEfPRD@abHAaqIRakI)+*MBk,L)H&K)L3!*QJTUHQSjZ5MSf1NC59PT5-JRT
+dF'jUCQ0JA&G88P0BA@4VEfjUD'P[H)'*NTUGRCbDQ*H9PC@6MSL"HRCeGAKpIhe
+kGA&aFRGrKif2N!#1LSD$JiU6QTkIR*H5M)H'LBZ0MSq1LAphFh&[E@YSC@&F@ep
+QDQe`Fh4aE@aZFRL#MTQKT+'IRTkFQTL8N!#+JhaiFfjVDQeaFQpZEh*hI)''LBQ
+'KBD)LSf3!*@ERU#KRjU@PCDCQjL4LS0mGh4cG(0`E'KPB9eD@PjND'YYEQaTCQC
+YGAZ#LT'@Q*H@Q*QDR*fGQT@-KB1"IhjpHRCdFR*cGRPqK)Q0M)H%JAemIi@+MBq
+2NC15Mib)KB1"JS1#IRakGR0ZD'*HA&aJCQaaFh0dGRGhGA0bFh9jJ)L,MBf1NC5
+9P*13!)f)K(pjGA"YEA"bFh9jIS1(LBb1MBZ*L)H'Ji'%LBf5PjQEQjD5Mib)K)+
+#JRpkGR&VCQ&GA&jJAejLD'aZE@eZF(&aFR0dGhb#LBf1N!#5Nj56NBk0LiL'KiH
+(KB&qI(YlIB#%L)b3!*5@P*!!M)Q&JApqIi1(Lik2MBU&J(jqIRq#Ji*rH(&VCQ&
+GAQ0SEA&eH(TlIS+'Ki0mH(KiH(TpJSD+M)q4N!#0LSL*LSD!I(PcE@TTD@ebH)+
+-NT56P*HAP*+3!)b'Ji1&LT!!NjDERjkCNSU%J(q"K)*lG'aQBf&IAf*PCfYZEh&
+bFR4iHAGbEQaXF(CrKiZ1MSZ*L)D$Ji@(L)Q)KB*mGh9hHAk#K)Q1N!#4PCLAPC!
+!LiH$IherK)U2NC'3!)U"I(YmJ)@'JhpkFfeSC'4QD@peGRChHRk#KSD&JRYeF'e
+XEA*kJSL,LSH$IhjqIS#!I(KeF@eUD@Y`HB#&LSk3!*!!MSq6PTD@Niq,L)@%L)k
+6Q*Q@MiL!IAapJ)+"IAPcE'PSCfCSDfjbG(9iHhaqIhjmGfjSCQGTFAb&Liq1LiH
+#IATjHhk!J(ppH(9dGRU#L)U0NC58PjQCQ*LAPC'0LBD%Kib3!*!!MSQ"HA9cG(Z
+!Ji@%IhK[D'*LC'TaGhb"Ji@)LiZ*LBH"HR0ZE'pfISH-Miq)IhPeFA"aFA"[E'K
+PC@KZGS'*Mj'5P*DAQjqKSU#CN!#+K)#$Lj5GSD#ENiQ"IRq$L)U)KB"fDf9KB@C
+YG(TpI(PiHAf!IRajFfYPBQ0XH)52Q*U8LS"iFh"[FA4hGhGfG(GjHRf%LSq8Q*U
+FRCfIS*kAMB&iFh0hJBZ3!*!!MSH"HhGeHB+*MBq0L)"fF'pbGAGiHAYmHRPpJS@
+&KB0qH'pTD@jhJ)D*LSCpGR*`F(&bFh4bE@GPCQP[Gi'+N!#6PCQFRCfEQTQ5L(p
+iG(4iJSkCRTbAN!#,Ki@'Lik-LBH%J(ajGR4dFh*cG(0bFA0hH(GfGA"VD'KYGhq
+&M*+6MSGrHAGeGRGiGh4`EA"eHRk%LSk3!*'4NC+5NT+5N!#+J(KcFR4kJSZ3!*+
+2LSH$Ihq%Lj5CQTH6M)4qHhTlHR9bFR*aFRGlIAq!IRYfF'e[GS#)M)k0KhpjGA&
+aFR"ZE@YRC@4REA9pKBL*LSU,MC'8PCD8MiH!HRCfHi10PCQCPC!!M)Q(LT'9PjH
+@NBU#HA0aFR0eGA4cFA"bGACeFQeRC'0PEAH"LT+APT!!KhjiGA4fGR9dFh&`FA4
+hHi#%L)b-LBD&KSU1N!#5MSCrHhPlIS'&Lik1M)U&JB'&Lj+9PC'-KS1"J)'$Ji'
+!IhajGR4dGhTlH(4`Efj[GRq'M)q0L)4qHA9dG(*`Eh"aFA&dGRKjHAKjHhamJ)@
+,N!#9PC13!)U$Ihq#Kib4PTL@Nj+5NC+5N!#1M)H!I(TiH(TpJ)"mGh&YE'aYEh*
+cFR&aEfj[G(f*NCDCPT!!KhpkHRalHAYmHRPjHAPkHRKiHAGeG(4hHhq&LBU*L)@
+#JS@(LT!!P*D6MSL(KiL,MBk2M)H$JAppIS'"J(afF@eXEA*jJBD(JhjjFh"bGhk
+(M)k2Li0kGA*bG(CiH(9`E'TTDfj[EQp`EfpbGAU"Kib2Mik,LBZ4Q*qQV+fUT*k
+ANSq1Mj+6MSCpGR*`Eh&cF'YQBQ0QD@acHRjqHR0XCQ9TFi'1PTL@NBU$Ii##K)D
+)Ki&kF@YUE'pcGRGfF@TQCQP[GRYrK)H(KiU1NjLHT+LQSCZ@NBq3!*!!N!#2LB*
+mGh*[E@aYEfpXD@KTEA4qL)f,KS&kGA0dH)#)MC!!NBk)J(YlIi5'KB"jFQYNAej
+IAPjKBf0MBQ9VGAq*N!#5NBf+M*'ARkL`Y,DcVDHLR*H9PC52KRadE'CMBf0LBQ*
+LC@PVEA*hHhjpH(0`Eh0kK)f9PjD8NSf,Lib1Mib'J(P`DQKTEA"`EQTNAeeIC'a
+fISD+LSL%JS1+NTfPUUURSTkEQTUDQjU6M)4lFfjVE'pbFR&YDfYYFAL"KSL'JAY
+hGA0eIBD0NT56MiU'KBH*LSH!H(&VCQ4PCQKUD'4LB'&PEAL'MT'3!)f(JB#%Lj@
+JTUUXUU@KRCbISk@LQj'&HR"XE'paG(4aE@TSD'Y`GhamH(0YD@TZGAq,NjLCPBk
+*KiD)M)q0KhedE@TUEh9kI(TfF'aUDR"kJSL,LiL%J(k$M*DITDHQSCQ5N!#4NT5
+8NSk*J(KeGRKmIi'"Hh&UCfPZGAb"K)&jFh&cGhq*NjUFQ*+,K)"rJ)5)Ki"hF'P
+PC@T[GAGdEfaUDQacISH-N!#3!)Z&JB''NCfQV+kVTCb9NC'6PCLCPSk&I(GiHhq
+#JhphF'PPC'9TER0eG("VDQjeJ)bAR*bAMiL%JB#$KiL'J(KaE'TYGAk%KB&lGA&
+ZF(H!L)f3!*!!MBU'KSZ8RD@STU#@Li5%KBL-MBb*K(pmI(q&LBb+JhKXBejIC@j
+hIB'"IATjHRq(N!#AQjU9Li*mHharK)@!GfpRB@&QEA9kHhG`D'4PDR*pL*!!P*5
+4N!#4NjDGTDUVTTb6M)L(Lj!!Nj13!)Z'JRprJSD)LB9pFfPJA&jNEA9iHACbEh"
+dHi@2PTQANSb'Ji'#K)0rHA"TBf&PE(9mJS0qGQeSCfefIiL3!*@@PT56PCQGSD'
+GQ*11L)D'KSL+Ki5"IRalIB'&Ki@!HA&VD'GXFhTqIhejGA0cHS@4QTqJR*@-KS+
+#JB'!I(9YC&jFAQ&PDQjZDf4IAf*UGS11PTZFQTUCQCZISk5KR*L8NT'5PCHBPT!
+!LS4qHRKiH(TkGh0`E@YVER*fH(GdF@p[FhU%MT@BQ*D2LBD'KiQ*Ki*lF@KLAf"
+ND@pcG(0aEQYZGS#+NTHCQ*D6NC'5PTQDQCH5MSU)LBU0MSb(JAYhG(4eGRCiH(C
+cF'eXER0iIB#!IRemIB+*Mj5@PT53!)U'KBD)L)H#I(9VBPaC@PeKC@KUDQPUERH
+"LT+9PC'0LSQ,MT+AR*kGQTH8NSq0Mj'3!)Z'J(ThGA9iHhYkH(0[E'TVF(9jI(e
+lHAGfGhb#KSL*L)D&K)1$K)D'JhefE@4IAf9XFhPmIAYjH(Z"Kif5P*53!)Z)KiL
+*MT5BQjUAP*!!LS@$JS+"IRakHAPjHhk!JApkGR*[F(9kIi@)Ki@"IRerJiH,MSq
+2M)L&JS'"J(jjG'aPAeeICQecH(YlHAGeGAPrKSb2Mif,LSU,MBq6PC@9Niq-LSQ
+*LBU*KS*qHhYmIAepHhPeFR"[FA9mJB5'KB&pHRKjIS+&KiH(KB1!IRalHAGbE@P
+PBf4TF(KqJS5$J(ajHAf$LBf3!*'3!)k-M)f3!*18P*+2LSD%Ji1$JB'!IRakH(K
+iH(PkHA4`E'TVF(9lJ)1$JS'!JS5)MC1AQ*H4LS4qHACfGRCcEfYSC@9SEA*fHAP
+hG(&`FRGmJSH*LSU+LBZ0Mj'4NC!!Mik-M)b0Miq1M)L$IAPhGhPkH(CdF@pZEQp
+bGhb!JS"pHhYqK)Z3!*15MiU%J(aiGA9hGR4`DQ4JB@K`H(k"JB"rIReqJ)5)M*!
+!NC!!MSU(KSQ-MSq1MSf,L)L)KS5#J(jkGA&[Efp`FA&`EfeXER0hHherJB5'KiQ
+0NTHDQjZAN!#*JhjlHhYkH(9ZCf*HA9jLD@pdGhKjH(KjIB''LBQ)Ki@%KBD(LSZ
+-MT!!N!#3!)q1N!#4N!#0LS9rHA9bFA"ZE@jZEQjZER"cGRb"K)@&KSH*Lib-M)Z
+*L)H&JRpmHAGeF@TMA9YEAQ9ZGAYrJS5'KB5%KSL+LiZ+L)D%K)5&KSH)Lik2Mif
+,L)5"IRTfFQpYE'aXDfYYEQjZF(0iIB#%L)Z,LSU+M)q3!*'6Nj'0L)5"IAPfFQj
+TBPY@9PTICQjeHhjrIRepIi'$KB@'KB@%JS"rJ)1)M*!!NT+4NC+4MSb(J(TeFA"
+`Efj[FA0dG(0cGAPqK)Q,LSL%JS#"JiH*Lik2M)Q'JAelH(4ZCf"E@&KFBfTbHAq
+$KSD'KSH*Lif0M)Q&J(jmHhk#KSQ0Miq1M)L'JhplGh9bEQeZFA0bFh4cFh4fHAk
+$KiQ,LiZ*KS5&L)b3!*+5N!#0LBH&JRplGR&VC9pE@&PGCR"iIS#!IhjqIi#!JB1
+%Ji&qI(apIi1(LBQ*LBL*LBQ(JhjkHAPiH(KiHAPjHAPiH(PmJSL,MBk0LSD$JS#
+!JB1'L)L)KS1"IRakGR&UBeeD@PjME(CqJiD(KiD%Ji5(LBZ,L)D%K)5&KiL*LBL
+)Ki@"IRakHAKhGR9cFR0eGRGiHAYpIi##K)D)LSZ,LBD$Ji5(Lik3!)q1LiQ(K)"
+pHhKeF@aQBQ"LCfjfIB+%K)1"IhepIS'&LBb-LBH'KSH(KS@%JS"rIi"rIAYlI(Y
+jGR4cFh4hHhq"JS5'LBb1Miq1M)L&JAppIS'&LBZ,LB@"IRakGh4[DQCLB@&MCQY
+aHS''KiD&Ji1(LSf3!*'2MSf-LSQ)KiL)L)H%IhYjGhKiGh9cEfeYE@j`G(KpJSD
+)L)L)LBZ-M)b+L)D&KBD*Lib0MBf,Ki*pHA9cF@jVD@GRD'a`G(KlIAprIRepIi+
+'Liq5NT!!MBU(KSD&KBD%Ji1#J(ekH(GfGR9cFA&bGRTqJ)+&KiL+M)k1MSk0M)Q
+%IhamIB'&LBU*KS0qHRCcEfaUDQTUDfaZF(0iIB'#JS'!JS5(M*!!P*D@P*+1LSH
+(L)U+Ki@$JApmHACbF("`F(&aFA*dH(b!Ji@(KiQ-MSq3!*!!MBU(Ji'"JiD+MSq
+1LiD"I(GdFh*bFA"ZER"aFh9iHRaqIAYjGhKlJBL1NC+4Mib+LSL(KiH(KiD&Ji"
+pHhYkHAKhGhGfGRGkI(f"K)L,MBf1MSk-LS@"IhepJ)5(LBL&JAjmHAGfGA9fGh9
+cFA*bFh4iHRYmI(apIi'$KiZ1Mj!!N!#2MSb-MBk1MSf-LSL'KB5"IRYiG(*aFA&
+bFhCkIS#"JB'#Ji5(LBQ)KiD&KBD)LSb0LiQ&JAelHherJ)"rI(TjH(GfGA9fH(K
+fG(0dH(f#KSU-M)Z+LSU,M)k3!*!!NC!!Mif,LBQ)KS*rI(PhGhKiH(KjHRYmI(e
+qJ)5)M)f,L)@$JS1&KiQ*Ki1"J(jmHhaqJ)'!IATfGA4dGACfGhGhGhPlIB'%KiU
+,LiU)KiQ-N!#8PTD9P*+3!)q0M)Q'JhpmHRGdFh4eGRGfGA4bFhCkIi5(L)L(KB5
+%K)D)LSb,LBD%JS'"JB+#JS"pHhPiGhCfGRGhGR9dG(9iIB+&KiH(KB1#JiD+Mj+
+8PC13!)k0MBk1MBZ)K)'!IRakHAPiGR9dG(9hHi'(LSU(K)&rIRq#KBH)L)H&JAj
+mIAjrJB"qHhGeGA4eGhGiHATjHATlIS+'LBU)KS1"J)+(M*!!NT15NT'2Miq3!*!
+!Mif*K(pkGhChHRamHR9aF(&cGRYrJS1#J(jmI(k"KSU-M)U'Ji"rJ)#!J(pqIAa
+kH(KjHheqIAajGR9hHi#%KSD'K)&rIRq#KBL,MBb,LSQ+M)k3!*!!Mib)KB+!Ii#
+"JS+!IAPeG(CiI)##JS&rIAamIS#$KBD&Ji"pHhTkHhapIAakH(9cG(CjHheqIRe
+lHRYqJB@(L)H&JRprJ)+&LBZ-MBb-LiU+M)k1M)Q&JAjpIS'$K)5"IAKdFA"aFhG
+kI(emHRPjHhf!Ji@&K)+"IhjqIRjrIhemHRPjHRarJS1#J(ajH(PlIS'#Ji5#J(j
+mI(k"K)H)L)D&K)5'L)Q,LiZ*L)D&KBD(L)Q(JhjjGR4eH(TmIRjqIAepI(eqIi#
+!IhekH(GhH(KjHAGeGAChHAYpIi#"J(ppI(aqJ)1'KSD&KB@&KBD(KiH)KiD&KBD
+(L)Q+LBH%JS'"JS5'KiD%J(aiGA4dGRKkHhamHhYlI(jrJB'"J(jlHAKhGhGiHAP
+jHRTlIB##Ji+"IhjpIAjrJB+%KSD'KSD&K)5&KS@%Ji'"JB'#Ji5&KB@&KB5$Ji1
+&KSD&Ji"qI(apIAepIAeqIRprIi#!J)"rIAThGA9dG(4dFh4eGRGiH(PkHheqIAa
+mIAk"K)D)L)L)KiH)L)L)KiD'KSH(KiH(KiD&Ji&qI(YlIAq!JS+"J(ppI(YlI(a
+pIAalHhYpIi#"JB#!IhelHRPhGRChH(KhGhGjHhapIAemHhYlI(q"JS1&KSD&Ji'
+"JS1%K)1#JS1$K)@&KB5$JS'!IRalIAq"Ji5%K)1#JS+#Ji+#JB#!J(prJ)'#JS'
+!IRakH(GfGA9dFh0bFR*cGACiHATkHAKhHAb!Ji5&KSD'KSD(KiH)L)Q*LBL(KiH
+)L)L'Ji"pHhTkHhaqIi#!IhjqIRq!JS1$JRppI(amIAk!J)'#JB'!IRalHRTjGhC
+dG(9hHRaqIRjmHRKhGhPlIS#$KB@%Ji+#K)@'KiL)KiD&K)1#JS+#JS&rIRemI(a
+qIRprIhq!JB1&KB@&KB@%K)1#JS+$Ji1#JApqIAalHAKhGA0bFA&cG(GjHRTjGh9
+cFh9hHhf!Ji@&KS@&KBH)Lif2N!#1M)Z*L)D%Ji'!IhjpIAamIAepIAemI(erJB1
+$Ji1"JB'#Ji1%K)5%K)1"J(pqIAakHAKfGRChHATlI(amHhTiGR9fH(YpIi'"JB#
+!JB1&KiQ-MBf-LSH%JS'"JB+!IRemIAk!JB+"J(jpIAeqJ)'%KiQ*L)H'KSD(L)H
+'KB1!IRepHhTiGhCfGA9eGA9hH(PjH(CdFh0dGRKkIAq"JS+#Ji@)Lik3!*!!Mif
+,LSU+LBH'K)+!IRjqIi##Ji+!IAPhGhKlIi+&KiH&K)+"JB+%KiL)Ki@#J(jpI(Y
+kH(KiH(PkHRYmIAepI(TjGhCfGhPlI(apIRq"K)L+LiZ,LBH&K)5&KSD'KB1!IRe
+qJ)+%KB@$JAejH(KlJ)@+MBf+Ki5#JS1&KSH)KiD%JRppHhTkHAKhGR9eGRGiHAT
+kHRKfG(0cG(GkI(k!JB+$KSL+LiZ+LBQ*LSU-M)b,LBH%JS'"JB+$K)5"IAPhGRG
+kIS1'KiD%JS"qIAerJS@(L)H&Ji'!IhjqIAalHRTjHAPlI(eqIAakH(ChH(PlIAj
+rJ)'$K)5&KB@&KB@&KBD)LSU*Ki@#J(q!J)+$K)5$JAjlHATpJ)5)LBQ)KS5$JB'
+"JS5&KSD&K)+"JB'!IhekH(GfGRGjHRYlHhPhGR4dGAKlIS'#JS+#JS1%KBD'KiH
+)LBQ*LSQ*L)H'KB5$JS+$Ji+"IRakHRTmIi'$K)@%Ji&rIReqIi#"JB'"JB+$Ji1
+#J(jmHRKiH(TpIi#!IhelHAPjHAYpIi#"JB#!Ii#"JS1%K)5$Ji+$Ji1$JS+"JB'
+#JS+$Ji1$JAppI(erJS@(L)L(KS@%Ji+#JS+"JB'!J)'"JB'!IRYiGR9fH(TpIhp
+qIAYjGhCfH(YpIhprIRepIRq"Ji5&KSD&K)5%K)@'KS@&K)1$Ji5%K)1#JApqIAj
+qJ)'#Ji1#JB"rIhprIi"rIhprIhprIhjpI(YjH(KjI(q"Ji1#J(jmHhYmIAprIhj
+pI(YlI(k!JS1%Ji+"J)#!JS1$JS&rIRjqJ)+$K)@%Ji'!Ihq!JB1%KB@&K)1$JS+
+#Ji1$Ji+"J(pqIRepHhPiH(KjHheqIhpqI(TkHATlIAq!IhelHRPkI(k!JS1%K)5
+$Ji1$K)@&K)5#JB#"JS1%KB@%JS"rIRjqIi'#Ji1$JB#!Ihq!JB'"J)"rIhprIRj
+pI(YlHRTlIAjrJ)#!J(prJ)#!J)#!IhemHhYlI(jrJ)'#JS'#JS+$JS+"J(jpIAe
+qIi'#Ji5$JS"qIRjrJB1%KB@&K)1$Ji5&KB@%Ji+!J)#!J)"qIAYkHAPjHRYmIAe
+qIRepI(apIAjqIRemHhYlHheqIi'#Ji1%K)5&KB5%Ji+"J)#!JB'#JS+"JB"rIhq
+!JB+$Ji+"J)#!JB+$Ji1"J(prIhprJ)"rIRemHRTkHhaqJ)'#JS'!IhjpIAeqIRj
+qIRepIAepIAjrIi#"JS1$Ji+"J(prIRepIRjrJ)#!IhjqIi#"JS1$Ji+#JB'#K)@
+'KSD%Ji+"J)#!J)#!IhemHhTkHhapIRq!IhemHRTkHhYmIAepIAemI(amIAk!JB+
+$Ji5&KB@&KB5$JS'!IhprIi#!J)"rIhprIhprIhprIhq!JS+$Ji+#JB'!IhjqIRj
+qIRepIAepIRq!JB+#JB"qIAamI(amIAepI(alHhYlI(eqJ)'"JS+#JS+"JB'!Ihj
+qIRjqIhprIhprIRjqIRjrJ)'#JS1%K)@&KB@%K)1#JB"rIRjpI(apIAjrIi#"JB#
+!IhemHhTkHRTkHhYkHRPjHATlIAjrJ)'"JS+$Ji1$K)5%Ji+"JB#!J)#!J(pqIAe
+mI(apIRq!JB'#JS+#JS+#JB'"J(prIRjpIAepIRq!JB+#JS+"JB"rIRepI(amI(a
+mHhYlHhYmIAjqIi#"JB'#JS+#JS+"JB#!J)#!J)#!IhjpIAamI(eqIhq!JB+$Ji5
+%KB@&K)5$JS'!IhpqIRjrIi#"JB'"JB"rIhjpI(alHhYlHhTkHRTlHhamIAepIRq
+!JB+#Ji1$Ji1$Ji+#JS+#JS+"J(pqIAamIAepIRjrIi#!JB+$Ji1$Ji+"J(prIhp
+rIhq!J)'"JB#!J)#!J)"rIRjpIAjqIRepIAemI(amI(apIRq!JB'#JS+"JB'!J)#
+!J)#!J)#!IhjqIAamI(epIRjqIhq!JB+$K)@&KB5$JS'!J)#!JB'#JS+#JB"rIhp
+rIRjqIAemI(amI(amI(YlHhYlI(epIRq!JB'#JS1$Ji1$JS+#JB'#JS+"JB"rIRe
+pIAeqIRjqIhprJ)#"JS+#JS+"JB#!J)#!JB+#JS+"J)"rIhprIhprIRjpIAepIRj
+qIRemI(amI(epIRq!J)'#JS+#JS+#JB'!J)#!J)#!J(prIRjqIRjqIRprIhprJ)#
+"JS1%K)5$Ji+#JS+#JS+$JS+"JB'!J)#!IhpqIAamI(amI(epIAamI(amI(epIRj
+rIi#"JS1%K)5$JS'"JB'"JB'"JB'!IhpqIRjqIRjqIRjqIRprJ)'#JS+#JS'"JB'
+#JS+"JB#!J)'"JS+"J(pqIAamI(apIRjqIRjqIAepIAepIRprIi#"JS1$Ji+#JB"
+rIi#!J)#!J)#!IhjqIRjqIAepIAjqIi#"JS+$Ji1$Ji1$Ji+#JS+#JB'"JB+#JS+
+"J(ppI(YkHRTlHhapIAepIAepIAapIAjqIi##JS1$Ji1#JB'"JB'#JS+#JS'"J(p
+qIRjpIAepIRjqIhq!JB'"JB'"JS+#JS+#JS+"JB'"JB+#Ji1#JB"qIAalHhYmI(e
+qIRjqIRjqIRjqIhprJ)#"JS+$Ji+#JB#!J)#"JB'#JB'!IhpqIRepIAepIRjqIi#
+"JB'#JS+#JS1$Ji1$Ji+#JB'"JS+$Ji1#JB"rIAalHRTlHhYmI(epIAepIRjqIRj
+qIhq!JB+$Ji1#JS+"JS+#JS1$JS+"J)"rIRjqIRjqIRjqIhq!J)#!J)'"JB+#JS+
+#JS'"JB'"JB+#Ji+#JB"rIRepI(apIAepIAeqIRjqIhprIhjqIhq!J)'#JS+#JS+
+"JB'"JS+#JS'"J(pqIRjqIRjqIRjrIhq!J)#"JB'"JS+#JS+#JS+"JB'"JB+#JS+
+#JB"rIRjpIAamI(apIAepIAjqIRjqIRjqIRprJ)#"JB+#JS+#JS+$Ji1$JS+"J)"
+rIhprIhprIhprIhprIi#!J)#!J)'"JB'"JB#!J)#!J)#"JB'"JB"rIhjqIRjqIRj
+qIRjqIRjqIRjqIRjqIhprJ)#!JB'"JB'"JB'#JS+#JB'!J(prIhprIhprIhprIhp
+rJ)#!JB'"JB'"JB'"JB#!J)#!J)#"JB'"JB#!IhjqIRjqIRjqIRjqIRjqIRjqIRj
+qIRjrIi#!J)'"JB'"JB+#JS+#JS'"J)"rIhprIi#!J)#!J(prIi#!J)'"JB'!J)#
+!IhprIhprIhq!J)#!J)#!IhprIRjqIRprIhprIhpqIRjqIRjqIRprIi#!J)#"J)#
+!J)'"JB+#JB'!IhprIhprIhprJ)#!J)#!J)#"JB'"JB'"J)#!J)"rIhprIhprJ)#
+!J)#!J(pqIRjqIRjrIhprIhjqIRjqIRjqIRprIhprJ)#!J)#!JB'"JS+#JB'!J)"
+rIhprIhprJ)#!J)#!J)'"JB#!J)#!J)"rIhprIRjqIRjrIhq!J)#!IhprIhprIhp
+rIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)'"J)#!J(prIhprIhprIi#!J)#
+"JB'"JB'!J)#!J)#!J(prIhjqIhprIhq!J)#!IhprIhprIhprIhjqIRjqIhprIhp
+rIhprIhprIi#!J)#!J)#!J)'"JB#!J)"rIhprIhq!J)#!J)#!JB'"JB#!J)#!J(p
+rIhprIhpqIRjqIRprIhprIhprIhprIhprIhprIhprIhq!J)"rIhprIhprJ)#!J)#
+!J)#!J)#!J)"rIhprIhprIhprIi#!J)#!JB'"JB'!J)#!J)#!J)"rIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!Ihp
+rIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprJ)#!J)#!J)#!J)#!IhprIi#!J)#!J(prIhprIhprIhprJ)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq
+!J)#!J)#!J)#!J(q!J)#!J)#!J(prIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#
+!J)#!J)#!IhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhp
+rIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp
+rIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIi#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIi#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!!!!X3!!"!!%!"3!!!+!!!B"4!!!
+!!!!8!!!!!!!!,"C@lSZM!!!X&!!!,"8!2)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J(prIhq!J)#!J)#
+!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIRjqIRekH(KpJB*rHh"H6%%m2$j!2$%
+R,d989dp&26Fd0MY"4de6@&jMCfY[FA4jJ)U@SUqla-[4ephKjHRYlr,cp2AfprI
+fp[Eep22cmr,blqV9Rh&pRDHXXE+aVUHJQ*!!L)"e8"3!'c8p4%P*4N!i,bJP*#F
+X-cT"4da49PTHB@4QDR"iJBfCT+kf[-,(c0$8f0[Hi1(Mj1AQjqIRk1MRjqIQj0r
+8VRjXHBQ8Qk+QUDLPS*Q5LApZ443%%L)X06a!3N!m0M%Y,#da0Ma"4NT18PCCA&j
+JBfKYGAq*P*kRVV1i[-$%b-[1dG,8eYMCfY[Fh0hGh0[DeXqlNR&XFRZ%M*1DRk'
+JRCL5LAjV3aS,$aBI+#mh1cdm1MFe0$8i1d"%5%Y1894A@9YGAf*RE(9rL*+ESDH
+XX,5i[,r#a-I*bXc1cp$4dY26dp(2blqQJfjVEA&iIiD1P*LDQCD4LAjU5#88%K3
+B(L8X-MFk1cXl1c`r3N9)5dj38P9A@9YFA@"MD'phJ)Q4QCqMTkZ[XV@iZll!`X2
+&amM*bXV,bmR'[l'BI@jXE'eaGRf%Lj!!P*@8NBTrE9%b(aXC'4`J*5Xa0MSp2d&
+$4NP-6e&69&CA@9YFA9jJBQCVFRU$Lj+BRU+PUDb[XV5hZEZp[X$"`m6%aFA$[lD
+RNAa`E@eYEh*hIB1*MT'5N!#,JA&D35dP)L!J)5-S,6-i28&&5%a38P9A@9TDA&e
+HAf"JBQ0QDh"hISD0P*UHSD5RUkf[XV5fZ,Ul[Ekr`-(![VQ`SBjpFfp[Eh"aG(P
+qK)U1N!#2M)4fC%dk,bSS*bBQ*bX`06Y"4Na39&KEA9jIAf"KB@*LBf4PCfT[G(Z
+$LC!!PTUHSD5RUDbZX,+dYVHjZVbp[EbkYDZGMApeFR&aFR*dGRZ!KBU0MSb'HfY
+C4cSc-#iX+bXX,M-j2dC-8PGFB'*MC'4NC'9PC@CQCfPVEh4jIiD-NTHERk'NTUL
+VVDqaXV5fYlQkZVQfX+HEMB&iG(0cFh4eGRPpJSH,M)Z(IR&L8N8p0c8c-6!`-$-
+i284-8PKHBQ9RD'KSD'KSD@PTD@YXEh0iIB1*Mj@CR*qKT+DSUUbZX,+dYEHhYlD
+cVD5CMS4mGh9eGRChH(TmJ)@*LiZ)JAGUA&"'2cXj1$Be06Bi280+8PPJC'KVE'a
+XE'aXE'aXE'eZF(0hI)+(MC1AQjkJSU5RUDZYVl'bY,@fYV5aUk1CMiCrHRKhH(P
+kHRapJ)5)LSZ*K(aaC9P35%0!2Mdm1cSl2N0+89PIC@TYEh"`F("`Efp[Eh"`FR4
+iI)''M*'@QTfJSU5QU+UXVV#bXl@eYE1`UU1DNBQ#IAYkHRYmIAjrJB5(LSZ+KS"
+hE@*B8%T'3d*"3$mr384+8&GIC@Y[FA0cFh0cFR*bFR*bG(9iI)#&LT!!P*LFRk'
+MTDHUV+k`XV1dY,5bVUQLQj+,KB"pI(apIi#"JS1&KiQ,LiL$I(0TB&G46%K'489
+%4%9(5P"@A@4UER*dGA9eGA9dG(4dG(9fHAarK)Q1NTHERU#LTDHTUkf[XE+cXl1
+aVDLLQj10Ki*rIRjrJ)'#Ji5&KiQ+LSQ&IhGZCPe@88e+58K)5%K+6&"9A'*SER*
+dGRGhGhCfGR9eGAChHAYqJSH-N!#9QCfISU5QU+UXVV#aXV+aVkbRSTZ8MBL%JAp
+rJ)'$K)@'KiL*LSU*Ki*lG'YMA9G56Na,5dY-68p59PYKCfaaG(ChH(KiH(GhGhG
+hH(PlIS'&LSq6PjZISD1QU+UXVUqaXV'aVkZQSTZ9MiU'Ji'!JB+%KSH)L)Q+LiZ
++L)4rH("TBPaA8e"26Nj28&*89eYKCQY`G(CiHAPjHAPjHAPjHATmIS'&LBf5PTU
+HSD1PU+UXVUqaXE'`VUZRSTb@N!#-L)5$JS+%KBH*LSU,Lib-LiU(JRaeEQGK@eG
+88P&48P099ePGB@CUEh0fH(PkHRTkHRTkHRTlI(k"K)L-N!#9QCfJSkDSUUbZVl#
+aXE#ZUkDKR*H4MBQ'K)1$K)D)LSZ-M)b0MBb,L)4rHA*XCQ"E9e968e499ePEAQ&
+PD@eaGAGjHRTlHhYkHRTlHhaqJ)1'LSq6PjZISU@RUDZYVUq`X+qXUDDKR*H5MBQ
+(K)1$K)D)LSZ-MBf0MBb,LBD"I(C[D@4I@eG9999@@&TGAf*PD'a`FhChHATkHRY
+kHRYlHhapIi+&L)b4PCQGS+1QU+UVVDkZVUfVU+5JQjD5MBQ(KB5$K)D)LSZ0MBk
+1MBf-LSH$IRPcE@GLAPTB9eGA@9YHB@0QD@a[FR4fH(PkHRTkHRTlHhapIS'%KiU
+1NjHERk+PTkQVV+bYV+ZTTU1IQTD5MSU(KB5%K)D)LSb1Miq2MSf-LSH$IhTeF'T
+QBPjE@9PC@eeIBQ9RDQaZF(*dGRGhH(PjHAPkHRYmIB#$KBQ0NC@CRD'NTULTUUZ
+VUUQRT+'GQC@4MSU)KS@&KBD)Lif2N!#4N!#3!)k0LiL&JAaiFfjUCQ*IA9YEA&j
+KC'GTDfe[FA*cG(9fGhKiH(PjHRYmIAq#KBL-N!#8Q*bJSkDSUDQUUDLRTD+IR*L
+9NBk,LBH'KBD(L)Z0Mj'5NT'3!)k-LBD$IhTfF@eTC@*JAPeHAf&NCfTXER"aFR0
+dG(9fGhGiH(PjHRYpIi'%KiZ2NjHERk+NTUHSU+LRTD1KRTUAP*'0LiQ(KS@&KSL
++MBq3!*+5NC!!Mib+Ki5!I(KdEfYSC@*JAepJB@4RDQe[F(&bFh0cG(9eGRGhH(P
+jHRaqJ)1'LBf4PCQFS++NTDDQTU@MSCqFQCD6N!#0LSL'KB@&KBH*Lif2NC+4NBq
+0LiL%JAjkGR*ZDQCNBQ"JB'*NCQTXER"bFR0cFh0dG(9fGRGiHATlIAq"K)H,Mj+
+@QTkJSU5PTD5MSU#HQjL9NBq-LBH'KB5%KBD)LSf2N!#4NC'3!)k-LBD$IhaiG("
+XD@CNBQ&KBQ4QD@aZF(*cFh0cFh4dG(9fGhGiHRYmIS'%KSQ0NC@BR*kKSk1MSk+
+KRjfDPj54MSZ*Ki@%K)5%KBH*M)k3!*'5NC!!Mif+L)5"IRTfFfpVD@CNBf0MC'C
+TE'j`FR0dG(4dG(4dGAChGhKjHhaqJ)+&LBb2NjDCRCqKSU+LSD#HR*QAP*'1LiQ
+(KB5$Ji5&KSL,MBq3!*'4NBq1LiQ'Ji"mH(9aE@YSCQ9NC'4QD'YYF(*cG(4dG(4
+dG(9eGRGiHATmIAq#K)H+MT'8PjUGRk#KSD#IRCZBPT13!)f+L)D%Ji+#JS1&KiQ
+,MSq3!*'3!*!!MSb+Ki5"IATfFfpXDQKQC@4PCQGTE'paFR0dG(4dG(4dGA9fGhK
+jHhaqJ)+&L)Z2NT@BQTbHRjqHRCZCPj54Mib*Ki@$JS'"JB+$KBH*M)k2N!#3!)q
+1M)U(K)*qHhKdF@eVD@GQC@9PCfPVE@paFh0dG(0cFh0dG(9fGhKkHherJB1'LBb
+2NT@BQTbGRCfFQTL@Nj!!MSZ)KS5#JB#!J)##Ji@)LSb1Miq2MSb+L)D$J(ejGR*
+[E'TSCfCPC@CSDQaZF(*cG(4dFh0cG(4eGRGiHAYmIS##KBL+MC!!NjDBQTZEQjU
+CPj@5Mif+Ki@$JB"rIhq!JB+%KiQ,MBk2MSk0LiQ(K)&qHhKeF@jXDQKRCQCRD'T
+XER"bFh4dG(4dG(4dGAChH(PkI(k!JS5(LSb2NT5@Q*UDQTUBPj@5N!#0LSL&Ji'
+!IhjqIi#"Ji@)LSb0MSk1MBb+L)@$J(ejGR0`E@YTD'GRCfKTDfe[FA0dG(4dG(4
+dG(9fGhKjHRYpIi'$KBL,MT!!Nj@@Q*QCQCL@P*+2M)Q(K)+!IhjpIAjrJ)+%KSQ
+,M)f1MSf-LSL'K)&qHhKeFQpYDfPSD'GSD@TXER"bFh4dG(4dG(4dGAChH(PlI(k
+!JS5'LBb1NC18PTHAPjD9Nj'1LiL'Ji&rIRemI(apIS##KBH*Lib0MBb,LSQ'K)*
+rHhPfFR"YDfTTD'KSD'TVE@paFR0dG(4dFh4dG(9fGhKkHherJB1&KiU-MT!!NT5
+9PC@9P*+2MBZ)KB1"IhemHhYlI(erJB1&KiQ,M)b-LiU*Ki@$J(ekGh4aEfeVD@K
+SD'KTDfaZF(&cFh4dG(4dG(4eGRGiHAYmIS##K)D)Lif2NC+6P*58Nj'2MBU(KB+
+!IRemHhYlHhaqJ)+%KSL+Lib-LiU*L)D%JApmHACcF'jXDfTTD@PUDfaZEh&bFh4
+dG(4dG(9eGRGiHAYmIS##K)D)LSb1N!#4Nj16Nj+4Mif+L)@$J(jpI(YkHRYmIAq
+"JiD)LBZ-M)b,LSQ(KB+!IRYiGA*`EQaVDQTUDQYXE@paFR0dG(9eGA9eGRChH(P
+lI(jrJB1&KiQ,MBq3!*'5NT+5N!#2MBU(KB+!IRelHRTkHRYmIS##KBH*LSZ-LiZ
++LBL'K)&rI(PhG(&[E@aVDQTUDfaYER"aFh4dGA9eGA9fGRGiHATmIAq!JS5'L)U
+-MBq3!*'4NC!!Mik-LSH%JS"qI(YkHAPjHRYpIi'$KBH*LSU,LiU*L)D%JS"pHRG
+eFh"ZE@YUDQTVDfaZEh"bFh4dGA9eGA9fGRGiHRYmIRq"Ji@(LBU-MBk2N!#3!)q
+1MBZ*KS5#IhelHRPiH(KjHRapIi+%KSH*LSU+LSQ)KS@$J(jmHACdF@pZE'YVDfY
+VE'e[F(&bFh4dGA9eGACfGhKjHhapIi'#K)D)LBZ-MBk2Mik0M)Z*KS5#IhelHRP
+iH(KjHAYpIS'$KBH)LBU+LSQ)Ki@%JRppHhKeFh&[E@aXDfYXE'e[F(&bFh4eGA9
+fGRChH(KkHhaqIi'#K)D(LBU-MBf1MSk0M)Z*Ki5#J(jmHRPiH(KjHAYmIS##K)D
+)LBU+LSU*L)H&Ji&rI(TiGA0aEfjYE@eYE@j[F(&bFh4eGRCfGhGiH(PkHhaqIi'
+#K)@(L)U,M)f0MBf0M)U*Ki5#J(jmHhPiH(KiHATmIAq"Ji@(L)Q+LSU*L)H'K)+
+!IRYjGh4bF@pZEQeYE@j[F(&bFh4eGRChGhGiH(PkHhaqIi##Ji@'L)Q+Lib-MBb
+-LiU)KS5#J(jmHRPiH(KiHATlI(k!JS5'KiL*LBQ*L)H'KB1"IhekH(CdFR"[EQj
+YEQj[Eh"aFh4eGAChGhGiH(PkHhapIS#"Ji5&KiL*LSZ,LiZ,LSQ(KS5#J(jmHRP
+iGhGhH(PkHherJB1&KSH)LBQ*L)H'KB1#J(elHAGeFh&`EfjZEQj[Eh"aFR0dGAC
+fGhGiH(PkHhapIRq"JS1&KSH)LBU+LiZ+LBL(KB5#J(jmHRPiGhGhH(KkHheqJ)+
+%KBH)L)Q*L)L(KS5$JAppHhKfG(0aF'p[Efp[F("aFR0dGAChGhKiHAPkHhapIRq
+"JS5&KSH)LBU+LSU+LBL(KB5#J(jmHhPiH(GhH(PkHhaqJ)+%KBH)L)Q*LBL)Ki@
+%JS"qI(TiGR9cFR&`F("`F(&bFh4eGRChH(PjHRTlI(apIi#"JS5&KSH)LBU+LSU
++LBL(KS5#JAppHhTjH(KiH(PkHhaqJ)'$KBD(L)Q*LBQ)KiD&Ji+!IRakH(CdFh*
+aFA&aFA&bFh4eGRChH(PjHRYlI(eqIi#"JS5&KSH)LBQ+LSU*LBL(KB5#JAppI(T
+jH(KiH(KjHRapIi'#K)@(L)L*LBQ)KiH'K)+"IhelHAGfG(0bFA&aFA&bFh0dGAC
+hH(PjHRTlI(apIRq"JS1%KBD(L)L*LBQ)L)H'KB1#J(jpHhTjH(GhGhKjHRYmIS#
+"Ji5'KiH)L)L)KiH'K)1"J(jmHRKfGA4cFR&aFA*bFh0dGAChH(KjHRTlI(apIRq
+!JB1%KBD(KiL)L)L)KiD'K)1#J(jpHhTjH(KhGhKiHATmIAq"JS5&KSH)L)L)L)H
+'KB5#JAppHhPiGR9dFh*bFR*bFh0dGAChH(KjHRYlI(eqIRq!JB1%KBD'KiL)L)L
+)KiD&K)1#J(ppI(YkHAKiH(KjHATmIAq!JS1&KSH(L)L)L)L(KS@%JS"rIAYkH(G
+eG(4cFh0cG(4eGRChH(PkHhamIAjqIi#"JS1%KBD(KiL)L)L)KiH'KB1#JApqI(Y
+kHAPiH(KjHRYmIAq!JS1&KSH(L)L)L)L)KiD&Ji+!IRelHRKhGR9dG(4dG(9eGRG
+iH(PkHhapIAjrIi#"JS1%KBD(KiL)L)L)KiH'KB1#JApqIAYlHRPiH(PjHRTmIAk
+!JB1%KBD(L)L)L)L)KiD&K)1"IhjmHhPiGhCeGA4dGA9eGRGhH(PkHhamIAjrIi#
+"JS1%KB@'KiH)L)L(KiD&K)1#J(pqI(YkHAPiH(KjHATlI(erJ)+$K)@'KiH)L)L
+(KiD&K)1#J(jpHhTiGhCfGA9eGA9eGRChH(PjHRYmIAjqIi#"JB+$K)@'KSH(KiH
+(KSD&K)1"J(ppI(YkHAPiH(KiHATlI(eqJ)'#K)@&KSH(KiH(KiD'KB5#JApqI(Y
+kH(GhGR9eGA9fGRGhH(PkHRYmIAjrIi#"JS+$K)@'KSH(KiH(KSD&K)1"J(pqIAY
+lHRPjH(KjHATlI(eqIi'#Ji5&KSH(KiH(KiH'KB5$JS&rIRalHRPiGhGfGRCfGhG
+iH(PkHhapIRjrJ)'"JS1%K)@'KSH(KiH(KiD&K)1#JB"qIAalHRTjHAPjHRTlI(e
+qIi'#Ji5&KSH(L)L)L)H(KS@%Ji+"IhjmHhTjH(KhGhGhGhKiHATkHhapIRprJ)'
+#JS1%KB@'KiH(KiH(KiD&K)1#JB"rIRamHhTkHAPjHRTlI(eqIi##Ji5&KSD(KiL
+)L)L(KiD&K)1"J(ppI(YkHAKiH(KiH(KiHATkHhapIRprJ)'#JS1%K)@'KSH(KiH
+(KSD&K)1#JB"rIAalHhTkHAPjHRTlHhapIS#"JS1%KB@'KiH(KiH(KSD&K)1#J(p
+qIAYkHRPiH(KiH(KiHAPkHhYmIAjrJ)'"JS1$K)@&KSD'KiD'KS@&K)1#J(pqIAa
+lHhTjHAPjHATkHhapIRq!JB+$K)@&KSD(KiH(KSD&K)1#JB"rIAalHRPjH(KiH(K
+iHAPkHhYmIAjrJ)'"JS1$K)@&KSD'KSD'KS@&K)1#JB"qIAamHhTkHAPjHATkHha
+pIRq!JB+$K)5&KSD(KiH(KiD'KB5$JS'!IRemHhTkHAPjHAPjHATkHhamIAjrJ)'
+#JS1%K)@'KSD(KiH(KSD&K)1#JB"rIRemHhYkHRTkHRTlHhapIRq!JB+$K)5&KSD
+(KiH(KiH'KS@%Ji+"J(pqI(alHRTkHAPkHRTlHhapIRprJ)'#Ji1%KB@'KSH(KiH
+(KSD&K)5$JS"rIRjpI(YlHhTkHhYlI(apIRq!JB+$Ji5&KSD'KiH(KiH'KS@&K)1
+#J(pqIAamHhYkHRTkHRYlHhapIRjrJ)'#Ji1%KB@'KSD(KiH(KSD&K)1$JS"rIhj
+pI(YlHhTkHRYlHhapIRjrJ)'#Ji5%KB@'KSD(KiD'KS@%K)1#JB"rIRemHhYkHRT
+kHRTlHhamIAjrJ)#"JS1$K)@&KSD'KSD'KS@&K)1#JB"rIRemI(YlHRTkHRTlHha
+mIAjrIi#"JS1$K)@&KBD'KSD'KS@&K)1#JB"rIRemI(YlHRTkHRTlHhYmIAjqIi#
+"JS+$K)5&KBD'KSD'KS@&K)1#JB"rIRjpI(YlHhTkHRTlHhamIAjqIi#"JS+$K)5
+&KBD'KSD'KS@&K)1$JS'!IhjpI(alHhYlHhYlHhamIAjrIi#"JS1$K)5&KBD'KSD
+'KS@&K)1$JS'!IhjpIAamHhYlHhYlI(apIAjrIi#"JS+$K)5&KBD'KSD'KSD&KB5
+$Ji+"J(pqIAemI(alHhamI(apIAjrJ)#"JS1%K)@&KSD'KSD'KSD&KB5$JS'!Ihp
+qIAamI(YlHhYmI(apIAjrIi#"JS+$K)5&KBD'KSD'KSD'KB@%Ji+"JB"rIRjpI(a
+mI(amI(epIRjrJ)#"JS1$K)@&KSD'KSD'KSD&KB5$JS'!J(pqIAemI(alHhamI(a
+pIAjrIi#"JB+#Ji5%KB@&KSD'KSD'KB@%Ji1#JB"rIRjpIAamI(amI(apIAjqIi#
+"JB+$Ji5&KB@'KSD'KB@&K)1$JS'!IhjqIAamI(YlHhYlI(amIAeqIhq!J)'#JS1
+$K)5&KB@&KB@&KB5%Ji+#JB"rIhjpIAamI(amI(amIAeqIhq!JB+#Ji5%KB@&KB@
+&KB@%K)1$JS'!IhjqIAamI(YlHhYlI(amIAeqIRq!J)'"JS+$Ji5%KB@&KB@&KB@
+%Ji1#JB'!IhjqIAemI(amI(apIAjqIhq!JB'#Ji1%K)@&KB@&KB@%K)1$JS'!J(p
+qIAemI(amI(amI(apIAjqIhq!J)'"JS1$K)5%KB@&KBD&KB@&K)5$JS'"J(prIRj
+pIAepIAepIRjrIi#!JB+#Ji5%KB@&KSD'KB@&K)5$JS+"J(prIRepIAamI(amI(e
+pIAjqIhq!J)'"JS+$Ji5%KB@&KBD'KB@&K)5$Ji+"JB"rIhjqIRepIAeqIRjrIi#
+!JB+#Ji5%KB@&KSD'KB@&K)5$Ji+"J)"rIRjpIAemI(amIAepIAjqIhq!J)'"JS+
+$Ji1%K)@&KB@&KB@&KB5%Ji+#JB#!IhjqIRepIAepIRjqIhq!JB'#Ji1%K)5&KB@
+&KB@%K)1$JS'"J(prIRepI(amI(amI(apIAeqIRprJ)#!JB'#JS1$Ji5%K)5&KB@
+%K)5$Ji+"JB#!IhjqIRepIAepIAjqIRprJ)'"JS+$K)5%K)@&K)5%K)1$JS'"J(p
+qIRepI(amI(amI(amIAepIRjrIi#!JB'"JS+$Ji1%K)5%K)5%K)5$Ji+#JB'!Ihp
+qIRjpIAepIAjqIRprJ)#"JS+$Ji5%K)5&K)5%K)1$JS'"J(prIRjpIAamI(amI(a
+pIAeqIRjrIi#!J)'"JS+$Ji1%K)5%KB@%K)5%Ji1#JS'"J)"rIhjqIRjqIRjqIhq
+!J)'"JS1$K)5%KB@&KB@%K)5$Ji+"JB"rIhjqIAepIAepIAepIAjqIRprIi#!JB'
+#JS+$Ji1%K)5&KB@&KB5%K)1$JS+"JB#!IhprIRjqIRprIhq!J)'"JS1$K)5%KB@
+&KB@%K)5$Ji+"JB#!IhjqIRepIAepIAepIAjqIRprIi#!JB'"JS+#Ji1$K)5%K)@
+&KB5%K)1$Ji+"JB#!J(prIhpqIRjrIhq!J)'"JS+$Ji5%K)5%K)5%K)1$JS+"JB"
+rIhjqIAepIAemIAepIAepIRjqIhprJ)#"JB'#JS+$Ji1%K)5%K)5%Ji1$JS+"JB#
+!IhprIRjqIRjqIRprJ)#!JB'#JS1$K)5%K)5%Ji1$JS'"J)"rIRjqIAepI(amI(a
+pIAepIAjqIRprJ)#!J)'"JS+#Ji1$Ji1%K)5$Ji1$JS+"JB#!IhprIhjqIRjqIhp
+rJ)#!JB'#JS1$Ji5%K)5$Ji1#JS'"J)"rIhjqIAepIAamI(epIAepIRjqIRprIi#
+!J)'"JB+#JS1$Ji1%K)5%Ji1$JS+#JB'!J)"rIhprIhprIhprJ)#"JB+#JS1$K)5
+%K)5%K)1$JS+"JB#!IhpqIRjpIAepIAepIAeqIRjrIhprJ)#!JB'"JS+#Ji1$Ji5
+%K)5%K)5$Ji1#JS'"JB#!J(prIhprIhq!J)#"JB+#Ji1$K)5%K)5%K)1$Ji+#JB'
+!J(prIRjqIAepIAepIRjqIRjrIhprJ)#!JB'"JB+#JS1$Ji1%K)5%K)5$Ji1#JS+
+"JB#!J)"rIhprIhq!J)#"JB'#JS1$Ji5%K)5%K)1$Ji+#JB'!J(prIRjqIAepIAe
+pIAjqIRjqIRprIi#!J)#"JB'"JS+#JS1$Ji1$Ji1$Ji+#JS'"JB#!J(prIhprIhp
+rIi#!J)'"JS+#Ji1$Ji1$Ji1#JS+"JB#!IhpqIRjpIAepIAepIAepIAjqIRjrIhp
+rJ)#!J)'"JB'#JS+#Ji1$Ji1$JS+#JS'"J)#!IhprIhprIhprIhq!J)#"JB+#JS1
+$Ji1$Ji1#JS+"JB#!IhpqIRjpIAepIAepIAepIAjqIRjrIhprIi#!J)#"JB'"JS+
+#JS1$Ji1$Ji+#JS'"JB#!J)"rIhprIhprIi#!J)'"JB+#JS1$Ji1$Ji1$JS+"JB'
+!J(prIhjqIRjpIAepIRjqIRjqIRprIhq!J)#!J)'"JB'#JS+#Ji1$Ji1$Ji1$JS+
+#JB'"J)#!J)"rJ)#!J)#!JB'"JS+#Ji1$Ji1$Ji1$Ji+#JB'!J)"rIhpqIRjqIRj
+qIRjqIRjqIhprIhq!J)#!J)'"JB'#JS+#Ji1$Ji1$Ji1$JS+#JS'"JB#!J)#!J)#
+!J)#!J)'"JS+#JS1$Ji1$Ji1$JS+#JB'!J)"rIhpqIRjqIRjqIRjqIRjqIRprIhp
+rJ)#!J)#!JB'"JS+#JS+#Ji1$Ji+#JS+#JB'"J)#!J(prIhprIi#!J)#"JB'"JS+
+#JS1#JS+#JS+"JB#!J(prIhjqIRjpIAepIAepIRjqIRjqIRprIhprJ)#!J)#"JB'
+"JB+#JS+#JS+#JS+"JB'!J)#!IhprIhprIhprJ)#!JB'"JB+#JS+#JS+#JS'"JB#
+!J(prIRjqIRjpIAepIAeqIRjqIRjqIRprIhprIi#!J)#!JB'"JB+#JS+#JS+#JS+
+"JB'"J)#!J(prIhprIhprJ)#!J)'"JB+#JS+#JS+#JS+"JB'!J(prIhpqIRjqIRj
+qIRjqIRjqIRprIhprIhq!J)#!J)'"JB'"JS+#JS+#JS+#JS+#JS'"JB'!J)#!J)#
+!J)#!J)#"JB'"JS+#JS+#Ji+#JS+#JB'"J)#!IhprIhjqIRjqIRjqIRjrIhprIhp
+rJ)#!J)#!J)'"JB'"JS+#JS+#JS+#JS+#JS+"JB'"JB#!J)#!J)#!J)#"JB'"JS+
+#JS+#JS+#JS+#JB'"J)#!IhprIhjqIRjqIRjqIRjqIhprIhprIi#!J)#!J)#"JB'
+"JB+#JS+#JS+#JS+#JS'"JB'"J)#!J)#!J)#!J)#!J)'"JB'"JS+#JS+#JS'"JB'
+!J(prIhpqIRjqIRjqIRjqIRjqIRjqIhprIhprIhprJ)#!J)#!JB'"JB'"JS+#JS+
+"JB'"JB#!J)#!IhprIhprIi#!J)#!JB'"JB'"JB'"JB'"JB#!J(prIhjqIRjqIRj
+qIRjqIRjqIRjqIRjrIhprIhprIi#!J)#!JB'"JB'"JB'#JS'"JB'"JB#!J)#!J(p
+rIhprIi#!J)#!JB'"JB'"JB'"JB'"JB#!J)"rIhpqIRjqIRjqIRjqIRjqIRjqIRp
+rIhprIhprJ)#!J)#!JB'"JB'#JS+#JS+#JS+"JB'"JB#!J)#!J)#!J)#!J)'"JB'
+"JB+#JS+#JS'"JB'!J)#!IhprIhpqIRjqIRjqIRjrIhprIhprIhq!J)#!J)#!J)#
+"JB'"JB+#JS+#JS+#JS+#JS'"JB'"J)#!J)#!J)#!JB'"JB'"JS+#JS+#JS+"JB'
+"J)#!J(prIhprIhjqIRjqIRprIhprIhprIhprJ)#!J)#!J)#!JB'"JB'#JS+#JS+
+#JS+#JB'"JB'"J)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'!J)#!IhprIhjqIRj
+qIRjqIRjqIRjqIRjrIhprIhprIhq!J)#!J)#!JB'"JB'"JB'"JB'"JB'"JB#!J)#
+!J)#!J)#!J)#!J)#!JB'"JB'"JB'!J)#!J(prIhprIRjqIRjqIRjqIRjqIRjqIRj
+qIRprIhprIhprIi#!J)#!J)#"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)#!J)#
+!JB'"JB'"JB'"J)#!J(prIhprIRjqIRjqIRjqIRjqIRjqIRjqIhprIhprIhprIi#
+!J)#!J)'"JB'"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)#!JB'"JB'"JB'"JB'"JB'
+!J)#!J(prIhprIhjrIRjqIRjrIhprIhprIhprIhprJ)#!J)#!J)#!JB'"JB'"JB+
+#JS+#JS'"JB'"JB'"J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"J)#!J)"rIhprIhp
+rIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!JB'"JB'"JB'#JS+"JS'"JB'"JB'
+"J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'!J)#!J(prIhprIhpqIRjqIRjqIRjrIhp
+rIhprIhprIhprIhprJ)#!J)#!J)'"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)#
+!J)#"JB'"JB#!J)#!J)"rIhprIhjqIRjqIRjqIRjqIRjqIRjqIRjqIhprIhprIhp
+rIhprJ)#!J)#!J)'"JB'"JB'"JB#!J)#!J)#!J)#!J)#!J)#!J)#!J)#"J)#!J)#
+!J)"rIhprIhpqIRjqIRjqIRjqIRjqIRjqIRjrIhprIhprIhprIhprJ)#!J)#!J)'
+"JB'"JB'"JB'"JB#!J)#!J)#!J)#!J)#!J)'"JB'"JB'"JB#!J)#!J)"rIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'
+"JB'"J)#!J)#"JB'"JB'"JB'"JB'"JB'"J)#!J)#!IhprIhprIhprIhprIhprIhp
+rIhprIhprIhprJ)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'"JB'"J)#!J)#"JB'
+"JB'"JB'"JB'"JB'!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIi#!J)#!J)#!J)#!JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!IhprIhprIhprIRjqIRjqIRjqIRjqIRjqIhprIhprIhprIhprIhprJ)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhprIhp
+rIRjqIRjqIRjqIRjqIRprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'!J)#!J)#!J)#
+!JB'"JB'"JB'"JB'!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIi#
+!J)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)#"JB'"JB'"JB'"JB#
+!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#
+!J)#!JB'"JB'"JB'!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIRprIhp
+rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhq!J)#!J)#!J)#!J)#"J)'"JB'"J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#
+!J)#!JB'"JB'"JB'"JB'"JB'"JB#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihp
+rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!JB'"JB'
+"JB#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihp
+rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)'"JB'
+"JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhp
+rIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!JB'"JB'"JB'"JB#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhp
+rIhprIhprIhprIhq!J)#!J)#!J)#!J)!!!#K!!!%!!3!&!!!!S!!"J&%!!!!!!"3
+!!!!!!!!S&PEZLk-!!#J8!!!S&3!mJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)'"JS1%KBD(LBU,MC@
+KUDLSX,Hl[lfcTk@``YANl2(bm1VJdmHlVk5FPSq)L*h$hqAHi[6rr2VikG5rV*q
+BNSb'JAYjHAPkJT[%j[AaiFQhYF(2dmr'YkDR`Y[A`kqCIQPD8P&DFTLrf1$DcVq
+aVE5jYl+bYVLeVUDCLA4H6%0-Dj5cZUZ5Gej,5eTUFRPrIhKXC'"HA9pLB9eA9Pp
+fP+bbSSZ#MUM#f1AKeY$*[,'XUkZTTk+CMSUDZYILhXqlTC58Skq[Tjb1IAZ5VlH
+`Tj4hA%Bi2PCeM*QGR*qLRTD3!)PqFQTTEh0aDf&@890DD)Lkir(Yh-#RRk+VZ-#
+rZlZm[,fqZl1QQ)TpF@0@8&GME'aJ5M3a5'9bG(4R8cmV'!i1&L%T,5dX-%9QJik
+(G@&45%eHER0aE'094dTCB&4'1#`T,cjFIT1AMRYN9PjfMTbMS*H2LSD#IRGXA8X
+h*KiV8AkETk13!(aS9%T2AQppLBPpE@"E@PYHB@0JA&pZJBkARTb3!)*qN!#SX+Z
+NQ)PqGQeN@P"-5dT(3$j+BRL#JAGZD'0LCQPN@8j#05db4eaMBee01c!`3ephKib
+*K)QCUlHl[EU[RSf"IB#)P*qJPB4hITbjaF@mVCq8LS*qHA&UCfKYG(k(LS9mF'*
+@9fZ(QCZ1Gee+3P*pTV@aSB4M56Xk38K19&KC994FEAk&J(4UD@j`FR0aE'CLBQ"
+HAfTfIS1(KAppK*Qa`,qbTD+TXEDeXUqVST5'I(CdFR&ZCeT15&9mUEqmUj0pF'j
+hKBk2KhTVA9GHDh0`CPK*2Mp3F)Q3!)PmE9j48QU)PT@4LS"jFQTM@e415dY19'0
+hJB*rHA&VC&jB88Jq0#XP)LFqBharG@&(,L-Y5QKjI(CYC&pMFS#&JRefEQ9IA9Y
+A8Nj'1c%d8AkLYEDTQjD6N!#1Li*fD@0NCfPYG(K`AdSi-d9PJ)b-KAaeHj1NRBT
+jCeP68PGGB&pE9%Y)9'TpKS0eCf&QEhGmIAKYB&YSM,6-dF@TMAf#R,R'`V1LPj+
+6Qk'IQC!!LSH%JAjfD9Y668-m4Q@%N!#,IQeLB@PaFh*bFR4kJB5!HhTmIRemKTb
+YVk',Ff9RGjLh`,DPN!"pE&T,4dY16Na)4PClSEHhU)jeBPYJCfedHRGVB'0hM*1
+4JQPA9fKpLiZ!FQYXG(q&Ki@#K)fETDQNPi9hF("qSFRKj0M$V*fCRUDQS*Q9NT!
+!MSZ'IhalGQP@4NC9CQYSA%Si-N9RH(CZAdj"0LXU0%416dFr4Q"mLBKrFfTQCfK
+QAeC048"!6QYqIR9S9%0$@AZ4PSq#G'peJ)H0NBq(IA*SAPKA@ea84cSf5h+4R*H
+(GfpXE'j`F("aEfPJ@P438PTLD(+(RU5CK@jC6NjLK*ZHQBarHheqJBD)KB1"JSb
+FU+QMPSGlEf0E@&G988a)3d44CA&eF'CHBA#(QUDSTD+JRk@VUkDJQC'-LSH"H(&
+ZE@adN!#mhZRPeEbQQTQPXVLdV+HQTU@MRj@&FPp148PHGB&pEPT*3NeTJB@"G@0
+98&&AA@4VFhCdGAq-N!#0Jh*K@9aPERChG'jVEAQ4TkUGLR*H9PebMk@[X+fTTU@
+NSTkEQ*1*IhC`ER&jIheeF)+R`XR%Xjb0KiH0PTZDNiZ!FQ*86%T089GDA'GpN!#
+8LhaVBQL#R+5IPib!HRGiHhYfE'*A6%G5DRf#HfeE56dl3de699&)2$P)@PpG9NN
+q1N"9GT+GQBb"I(YqJB+"K)b6P*',JhPZBP4+5Pq&SkZPNRYUBf0SE'aUE(*hH(9
+[D@GUE@TPBQf%PjZ8KA0NCRkARjU,Fej46%pCBfCPC'"GBA@@XlkiU*5%I)+5Rk+
+ENSZ5VmlCdEkMLRKaIk$!cp$+`Vr$aX5lVk#3!)*fF'e[GAKeE@*@8&ekMj+&EPC
+)5&0PHBU6PT10KB"rJ(adD&T,3dpVKC'0I'CDCB@KV+ZJM(KUC'9TEA*fG@pRB@G
+eIRjiFh0eGR4ZC9a@8e0GFi5$H@pMA&YHDS#BU+fQQT5@R+1TVV+cXl'ZV+fbYDq
+KMi52XG,Khp#pX+QSUkq`VUbSSCL2KRpeE'4H9dj*8'"VDf"12$Y5FS&qG'*56%a
+4@&aC8%8l-L`U-N4FE("R@8j09f9`F'GC6%TFHiq8PC!!K(CP8NK9GTDRVDQIPBb
+%IRK[CPeA88T%3%"#4NG%4&&VLTqMPS*bERH)QD@VU+'FR*qLSk+GPSf$GfTTICZ
+XUTU$G)'JXl@YR)9bC'&UGAKhI)+&JAPaF(Z(Li9kEQPYGAb$K(jdCf0`JB4pHR4
+XD'CPDhfCVlQhVkUVXEQr[E1PPiZ$JB1(LB4jD9YDET'daF#`RBYqHi'*MBf*JRK
+ZCPpD9&"-58G'4%*&6ePF@&*9Chf,N!#1J(&YF(CpJ(pmHRTkGh9iKk#jaX5hUD1
+PUV#aUTb-JibKVl5hVTb,IA&ZGikSZ,QbUUHRUDfYTTb5LiH)M*'6Mi0bB9PKFSQ
+HTk#BNBb1PCUFR*Q6MBD"I(CZCf4LAeT446e%@@TYC9eNHSZ3!*'-IQpL@9CB@&4
+389496d-f0dTKE'aSB9aGC@pfFfGA6eYaHRGaC9G268e19@L"P*ZAMB0mH(KlIi&
+rHhPjHRaqIAG`EAH'MC+FRjH3!)b*MTHISU+IQT52LS@!HA"P@%T!1cT"9(#$KRP
+TDRZ-Q+'JPiq)JAppH(4cGAGhGA"XFibUZlfeTjL,JAq!IhGXCh#&PCbIQ)CfE@G
+PES+JZmV-`V5QRjkMTk5EN!#)KBL-M)CmEf&A@QTpN!#RZ,HXRSamGACqL)q2LB"
+iFQeUD'GPBPjC8Ne6CAb,Mif5Sl'`UU#3!)1!JSH1NBq+KS+!IAKaEA"lJi0qGh&
+`GS#)M)PqEfPaJ)H*LB0kGA*[ER&pPE,)dmr"XDDLTl6"aX1jVD+@LRpiFQe[JTQ
+PVEUpXkQIPj59PjZIS*fBNib$I(4UB&4(2cXj1dCFEh&Q@&&ECfKNB&9,4N4&58Y
++4dC(58T+58K3Chq-LhpZA9&2@'CcHi#-RUDIPBb!FfPH99"8CS@KVUZIN!#%IRk
+!JAjhF@aTCQ"D9P*-4dTBDA@&Qk@KQ)TmGRKpKBk9QCZGRCQ4LS4rHR0UB9aIF)k
+TYVDbZ-("ZVDZT*b@N!#0LiQ)LBL%IRG[CQ*VJC@FPSGdC&aFC@e[CPaHEhq%K(p
+bCQ&KBfKcLkc(dXh!YE#[XVHkYUfNQj+*J(PfGhGkKTDEPCLLT*qDNSU&K)@(Ki9
+rH(0XBeK35dT-6Np168pDDA*`D@4VHS1*Mj!!Miq-Ki"kG(&bG(KmIhprLD#lcG(
+*Z+LKSkbbXDQKTV[0cF@jTj5)JAjrJikPZX#jV*f8N!#4NT'1KhjjGR*VC&pHAQ&
+ZL*bGQCkJR*Q9MSZ*LBU+L)H+MBf*JhafEQCD5c`Z*Le&C(KlHAf'KS&rI(9XBPC
+058K+8&CB9P&)2ca)Ah9pHQpL@9CAA'"H@Q"hNjkDNB"VAeYC@&TNH*1TXl5`UU1
+HR*ZCNib%IhalI(q$K)'"LTHANCDIRTL6M)H'LC!!Q*fDMi&bC&TB@epJA9K346`
+m6@KqKiL4SUZRSCZ3!)CrGR"ZEQpbGAKpJB"iEQTfLTHCNSCqIS+)LiL!GRH*Qjf
+@Mi4jFh"ZE@adL*qXUk+8KRprL*5GSD+HPBTqG@jRB&eKERU#MTqQU+ZQQj52LiU
++LSQ+Lik3!*!!MBCqG@pYE'TVFhk&KB+(Ql#iZ,5PN!"qEQ9NDA"hIAjpHhCaER1
+%RDkdVk5@LAaaDQCLB'KrQD@MQSPhEh"cGRQ!NDDh[m'r[VbhXUZNRC5-KiD(LSf
+1LiD%M*HGSkQRRTH1Ki1#JS5(Ki"hE@0D8Nj+4N4!1c-Y,6K-@PeC@QQ!LiU(IR"
+PAPPDAQ0TEA&bF@aK9P0KHSf8Nif(K)+!IRP`DQf"QD#CMi*`B9G36e9QJjkVUTq
+5L)*rIi1(KS&jEf095%&$4dP,9'&YHif@P*'0KApmHRPjGh9eGhKhG'pVD@KRC@0
+LDAU4SD+AL)HCV,'`UTf6MSb-MBf-LB0lEf0B8ePYKTQJR*'&Ii#(MT'0KS+0TVZ
+pXkD5Ih0YDh@,Um60bEb[Tk@SV+fUT*kEQjZCP)YqF'*B@@Z*UEl"YULCLS'!JB+
+#IRGZD'9NC@4LAeP88%a+8'"cIRpfD@0[KjLGQSTeD@9REhKpJB@)L)0rJ)fQ[m[
+)ZD@9MBf6QCfGPT!!P+Hl[V#ILhCTCQKbKk+bXkZJPBq1N!#4N!#-L)5#JB'$KB@
+!G@CA8PjpRV+iVjk-Hh"[Gi+0P*D8N!#,K(aaD@0H@9026ePZJSQ(Ih0ZHBf@P)b
+!F'0F@9KA8de'2cXi1%"9Ehq!H'aI9P&389&25NC&6fL(Q*H1J'aF8e&GGT1QV+L
+GNBCrIB+*Mj'1LB4qHAGhH(GcEQKVJCqd[,LUQSf$IAaqK)U0M)U*L)H#Hh*TB&T
+A@'4lNCU6J@aJDBHQY,@XQ)4eD@9UF(4fGR4[D@b!RE6"`lbcV+QUUkUQRjL2L)b
+HUk@ALRGL@&PPITLSUUDJQTD5Mib)JhjjGR9iIB'$JRecCeaFFjLc[EQUPSCjFhL
+!Ji*rHhCcFR0cF@eRB&P89f4kMjQ9Kh9TDhkBTUDFL(0TDA"hHhjqI(PfGS#8U,'
+ZSjH0LBZ6RD+JPiTqG(@'RUbaX+12IA0hMDDdYE#RSCkLUV'dXkqTSCL4MBU)KS&
+iDepKHCbbY+bFL(KXCfTZFA"ZDfGLAPTB9e414d!m2dpTHhjeC99)5f1#NBf#G@4
+@8%j4@&pLC'CQCh'&PjbCMi*fF(*hI(q"J(jkFfjcJSk0LB"[AeaRIC!!PC')IAC
+dH)#)L)&iEfKPBf"H@eP@88Y(6'5-UV1ZS)PeDQYiLC@BPj@5MSU'IR0SBPpGA@G
+pPD@SS*+&HA5$SEDiVTk'F@CQE(9lI(GaDQ4UIT@LSjb6MBZ-MSq0LB@!Hh4YF)'
+8QTH1IQeSFS@CTUHKRU'RXEc#`VZbU*f5LB5&M*1@P)PpHSbV[,Q[ST!!IR0cHS+
+%JATaD'"B8e"168e06P*EDA0hG'YJ@9CBBRQ4RD'KPiU$J(jqIRelHAZ&Ql2#`lL
+SQBf)MCDFRCfFQT@0Ji@ATkQLQBPlJ*@UYE@XS*H6NjDCQjbEQ*51Ki"hEfKNAeY
+BA(#4VVLaSj1"FQYVEQp[E'YXF(4hHAThF@GF9PjiNjqHPSPmF'9JDS#2MSCmE&Y
+46%a18%j'2$Fr9h'!JAGUB&aFB'*MBf0MBf0JAQClLiU"G@9IEBDAQjD*HR&dIif
+5MiCmG'paHB1)L)*hD9P26PalRE#`U*U)H(*cH(k#Ji"lGR"SBPpKC@CREi+CTD5
+CLhpiGhKqMUDeXDHHP)Z(KBD(KAphGB#BXm6&ZkbKQjQES+5PT+'FPSf!F@afKBU
+(JAKlM*UHQj1*JB#'MC+6NBf+L)D$IRG`DfGLA&TKF)5GXlQYRBaiD'0ND@eaGAK
+mIi'"J(eiF@PND(L1RCq@LAacEfj`HSbDQj@0Ih0YDQKRD@PRDA5&PU+PSTb@Nj5
+BQjL4LiU-N!#5N!#2PUD`UTk6MC@TZEklY+kYXVQr`,beVUHJQC12MBZ*KApeE'P
+ZGS+5QC1+Ih&RBepGAPpG@&436%Y08946894MGi+#HQpJ8NK$3N42ChTmG@eL@&4
+69&KFA9ePHBkANS9dCPpKDhH"KSH'JATcDf&B9fCjIhejHB53!*12KhedEh&hHAK
+iHAapHhKeFh&[E'CH9e9FDAQ3!+QdX+QINib+L)Q,LiL&K)5$Ji1"I(9bIC+NUD1
+BLAacFAClIiQDTU1DMhpbE@YXEQeUES'HY,fkVCk5LSH(LBQ(K)"lG'jRB@"YKjU
+HQTHFTDDFMi&hG(U)Pk#JQC',KAplH(GjHACaDQ9THBfKYX1qVk'6KAjmIB#$Jhp
+jGR4cFh*ZCf"GBh&rKB0kEfGPDA*iISfKUkLLPS4fF'paGRTmKCDSX+qRR*@@RDH
+[X+ZNRTbDPj++J(b%PCqHRCqPVV'XSTH3!)f4QD#LRjQ4L)"hF'TQC'CSD@GREhb
+"K)fCQT@2LB&kF@KLB@4SE("aE'9F99"6BRb3!*H8LAY`D'9NBf"FBR*mI(TdDQ&
+D88T&2cY#@("mI(GbEfj`G(KjGA&[F("YD'"A9@*jJhpmJ)@)KS&lHAb"Lj@DQCD
+5MBQ(KS@$J(ahFQaQCh@'MjDKUDLKQT!!L)@"IAKcE'4HA@"MC@GSCfCYHSD,L)&
+iFQjYEQeUEAk8RCQ4K(0SBQ&ND'eiMU[!b-5hUCqFR*kJS*kFQjZCPBq'JBDATU+
+AP*UMU+DJQT51L)L-N!#0LBD'KiH'KB@$IhGVAPCAB@aeKCbXVUZMPBQ!HA0aFhC
+iHRTiGA"UBepMFB@5P)f#GQpXE@p`F(0rLSf-L)5#K)D%IhPdGB5CUV'YT*fCQTq
+PTk@IPj!!M)b0LS*mISZ6N!#2QkUdYUkNR*QDRU1RTk+FP)q0MT'6NSq*JA9SB'0
+[GRCjJSH%IhTbDQ4H@PPB9P*48e966NFq1$Y,B'j`CeP26&*EB'&HBR+%L)9qF@9
+H@eTEA&eRIC1IRjQ4M)Z1NjH@NBb(KB1!Hh4XC'9bHhC`Gi5-MSU$I(KiHRq%K(p
+hE@4IAPjHAPjH@eC36eTVGRf*R+QRRC5+KSH(LBk8PT54N!#4NT'0KRjpLTZLSCQ
+2KS"pIAYcDQPhKSQ&Ih4SB9eGAPjJDRk6SU5GNSU)MCDFR*H4LS@"IATiGRU*S+b
+UU+fbYV@aUk@KRjqKSCfANSq0LiQ&IRG`DfCK@eeTGRYpL*UMSjq9KhedE'CNBPj
+D@&KC@eeGA&eRH)L4NBTrGR"`G(KmJT1TY,1UR)f%J(epIAf"N!#T`Fh1aVbcVUZ
+TTk@MSU'IRTZ6KhTdISf3!)f3!*HER*H1KAjmIB#&L)D"Hh9`E'PRC'*H9de$1ca
+,AQafKT14KRY`BejIBfefI(prIhekGQpQ@eTSJ*!!NSU!HRPmIi&qGh0kKiZ)JhG
+TB&YA9&09AR+-Rk1EMB&lI)+)LSQ(KS@#I(4VBejNGiU-KiU5QCZANBU'KSL0NT5
+9PC55MiZ%I(0VCQ&F9eCGDh9kK*+CPC'-Ki5$J(epJB5$JAjkGA"UC'"RIjURTCU
+,HfaJ@9KDAQZ"NjLBNS4eD&pFA&jMFSbNX,+URC+-LSZ0LiD"JB5(Ki0mFQaaIiL
+(KiqET+@HPBf+Lj!!PTbHR*H3!)Q$IRTeEfKLA9PA@fPpM*LQX+fPRjQ8NT!!MSf
+,L)@#IhajGR&UB9aJF)10MSL!H(9cFh"VD('#M)f+J(*QAPPDA@&UICHYYV#KNB4
+mHRf!JB"rIi#!IAK`DQk"PTZ@PCULU+DKQC14P*UIS*bAMiCqH(4bF@eSBejD9PG
+LEA9rMTLBP*!!LBD'KB&rIRakGh0[DfKNB@"QGikHSCZ4L)+"Ji@%JiZETUDJPSG
+jEQCJAPjJDi5JXE@ZSTD2LiZ2NC'1LS@!HR*SA&9EEhjrI)#*P*D3!)PrGh*aGRY
+mHAGeFh*`EQPNA94-4N0&6PaUGiLCRjbBNSU'JAYfFh*bGAb#KB*lFQPMCRD*P*5
+0K(ahH(aqIAq0RCq@M(p`Cf0KB@*KBQf!P*qLR*+,L)Q0MSU#HhCeG(0bEQPUGS1
+'JB',RDQTSTZAPjbNVE5bV++AM)0lGA"ZE@eUCQGbKjDDRD1MQT+*IhCdG(9hGh9
+aE@PQBepD9P*5AA'#L)&dD'4QDfpaFRU,PjD4KhKUC'0NCfPVGBZNYVUbT*H1M*+
+DRTqIRCL5Li4lF'TbK)k*JiH6Rk5KQC+0MBq4NT'2M)Q(KiD%IhCXBPP68&0JFS#
+)NCbJRCQ@N!#-Ki+!J(pjFh"bGRKfF@TPEB#5QCL4L(pjH(PiFQa`J)f,K(YZC&j
+E@9KA@QGrPU+KPiU"J)@-N!#2LB&fE'4IA9YDAQPkJi@-Q+'LRT@-KiH,PCkNTD1
+HQ*'+JhehFQaRBPjHDAb)L)5*NTD5Li"cE@jbGAKiG'eQB&aE@PKBBR@)N!#0JR9
+VD'T[G(9bFi'8QT1+IR"SCfCRDh5'Rl5r`,Q[Tk+JS*kEPj56NBb(J(K[CQ4XGhq
+*QD+KRTL4MSq4NT!!MBL$IAG`D@"C99046dj08Q*jMC55NTfQSjZ8LAeeF'eZFR9
+jIS+"Hh0TC'b#PTqGNiL#J)'#J(TbDQalLSk,JhCUBPaB@@*aJSk6Nj+8PjQFRTk
+EP)f'J(TdEfTPB@"SHj+RY,1TRTD5PCbKSCkCP*!!MBQ$IRPcE@GLA&KDCA@$L)C
+mGi+BT+1HNi9jF@aVE'TPAeaFA&eKEAq3!*H@MiD#JS@)L)*iE@9QH*'JSTf2I'a
+MB@f(S+k`UU1GQjZHSD'HQTH8NT!!M)CmF@CG994KI*@JRBprFh"fJ)Q0M)H"HR9
+bF'jUC@&G@999AfpmIhYcD'*VJjbRTCU+H@pUDR"hHRGaE'KREi'6R*b@MB@#JiQ
+0M)GrG@PH@Q9fIRjjE9j@9fCpNCH6MBQ)Lj!!P*13!)Q#I(PkIB'%K(jeE'GZKUI
+!bF@hT*H4NTHHSD#HQjH4Li@!HhC[CQ"IDRZ*MSU"G@YNBfq'PjU9LhaXB&K89&C
+@994@BR@+Q*Z@MBD!I(TiGR0[DfKNB&jNGB5(JACUCQjqMCQIRTZES+DTTk+GQC@
+5MSQ%IRPcE'9LBfTjNUUeXUUJPBk-LiU*Ki5!IRakGh4[DQCMD(H*P*QBP)q*JRY
+cFRq8SD1HPBGlF@KMBQ*NE(b0PjQ9N!#-LBQ*L)@$Ji1"IAPbDQ*GBQeeH(f$L)U
+,LSU0NC'2M)Q%J(ajH(PkH(0ZD'0H@PaNE'pYERZ5SUDMQiq'IhPkJ)D*LBH$I(9
+XCfYjL)q2LB*qIAq"JAY`BeaNH)L-LS0fD9jA@@9cIB+'L)H&Ji5(LBD!HA0[EQp
+aFA"XCf&JE)1CTUQJN!##HRKmKBU0N!#6PTQDQTH5Li4lFh*lLjHDPj',Ki1'P+H
+YTjk6KATdEQYVE'TSDA+!M*'5N!#-L)@#J(jlGh*YD@CLA&KGDh9eFR*eHi'%KB@
+'KSL-N!#5N!#-Ki*mGR&YDQKSDR*mKBQ&I(ClM*bLSTb5L)0rIAjrI(KfG(0eISU
+6PjD6MSL%Ji5'L)H%IACcHibBQCD3!)Q+NTLER*UAP*18PTLBPT+1LiH"HR0ZDfe
+dIB&qGQe[IBU-LS4kFQeTD'PUD@CNB@"LE(f2QCL3!)GqGh&YER*fH(9[DQq!Mj+
+-JRKfJBf5Nj'0LSU-N!#8PTH@NSf(J(YeEfaUD@ekKBCrIiU6P*'0KApmI(k!J(j
+kGR*`E'GPDhb2Pj5,Ih0VCfP`GhPhFhH'PTU@MAp[BPTEE)15PT50Ki&pI(k#K)1
+!I(KeFh*`E'CJ@9GLHj+GQT'#FfYVFhq)LiZ*KS&mHAKiGA"VERZ,PTU@MiQ$IAP
+hIj!!Rk'EP)TrHAGhH(KhISZARCbANBf,LSU,LiL%J(elGh*VBPYA@fTrP*qHPSb
+#Gh"XEA"eGhKhGhKiGhCdF@eTDh5"LBb+JhP`ERb4RU'HP)GqHAChHATjH(U#MCH
+DQC52LB5#JiH,LiQ&JAadE'CVH)1+NCDCQCD3!)U%IhYkIi1&KSD(LBU*KRphEQG
+PE(U'L)0kFRD$MT!!N!#0KS&rIRk!Ji1"IRTiIBQ6Pj@1KhpkH(Z!KSL'JAT`D'G
+bIS+!HhKlKBU,LSQ(KB@&KiZ1MSf,Ki*pGh*ZDfP[I)Q1LS5%MTLDQ*50Ki1"J)#
+!IRYjGh0ZD@ahJiL(JheiGA4fHRjrHR*TCQjlJAjiEQ&CA@YiIRjkGA&ZEh0kJ)+
+#J(YeF'eVDfTRC@9VFRb,Qk+KRCD4Mj'5NT14MSU'JAppIAb!LjLIRTU6M)4rHhT
+jGh0aHBQ9PT'+Ih0UBf*VHiD,M)Q&JRppI(eqI(TiH(KhGA0[DQ9LCR@0Rk@LQBf
+#I(TlIi'"IhjqIRq!J)"pHAKmKSf2MBL"HR4`EQjcIik@P)q(IRCaE'TVFAZ%LSk
+3!*!!MSZ(K)@(LBQ+LiZ+L)@#IAKdHBUET+@JPj!!MBZ+Lib0MBb,LBL(KS0qH(*
+aGS#,NC!!Li*iEfKMD(H,PTH6Li"hEQKNBf0QEhZ&LSZ)KB&pHRKjI)#$JS"pHAC
+bE@TXGiD6RCqFPj+1LiQ'K)+#Ji5'KS5"IATfFQjYG(q(L)D"Hh4ZERL'MBb*Jha
+hFfpYDfPRCQYfJSb2MSZ)K)'!JB1%K)*qH(0ZDQKTEhCkIS5)L)D$IhTfG(4fHAb
+!Ji*rHhCbF("[E@e`GRYpI(PeFR4pKSU-MBZ)KB1!IRakHATlJ)Q3!*58NSq-LSQ
+(KiD'KSD&Ji&pHAPrK)5%LBk6Niq*JRYeFR0iIB'$K)+"IRTfFQpYDfYaHS#$J(T
+dG(b%L)U*KS1"IhelHAKhGRCfHS+0PTZDPT+0LB@$Ji5%K)0rHRGlK)Z0LiL&KiZ
+0MBb*KS+!Ii#$KSL*LBL'Ji"pHA9aF(&hIS+"Ihq'MT'3!)k+K)"pHRPiGhCdG(0
+dGRb'N!#9PC+2LiQ'KB5$JRjkG@pZFhk(LBL$IAYqJi@'KS1!IRk!Ji@&K)1#JB&
+rI(TiGR0bG(PmI(TpKT!!Nj!!M)L&K)1"IhemHRKhGhKlIi5*MBk0LiH%JS"rIAY
+jGR0`ER&lK)D$IhTfGhf$KiL'Ji&rIAamI(YkHRTkHRPhFQeRBf&KC@Y`FhCpJi@
+"IAYiGhGhHAaqIhjpHhPhGRKpKBf5Nj'-KS*qIAk"Ji1!HhKmKSk4MiU%IRb"L)Z
+-LiQ'K)1$KBL+Lib,LBD#IhakH(CcFA&dH(TpJiZ1MBU(K)+#Ji1#J(aiG(*cG(4
+dGRPqJB1#JApqIAakGh9dFh0cFh9mJiD%JAejH(YrJS1%Ji1%KB@'KiD'KSD(KiL
+(KS@%Ji+"JS@)L)D&LC+APT54MSf,LBD%Ji+!IRakHAPkIB+)LiZ)K)"qIAepJ)1
+%K)*qHRGjJ)D'JRplHATrKBH'JhpmHhf#KSQ+L)D%Ji'!IRajGR0aFA9mJSD(KB5
+(Mj58Nj!!M)Q&JS#!IhjpI(TiGR4eHAk#JS+!IhjqIi#"JB"qI(PfFh&[FRPpHhG
+dG(Q!K)@$J(aiGhKlIS#!IhemHhYlHRPhG(&`FAGrKSQ(JRYhHB1,MSq-KS&pHRT
+mIAelH(CeG(9jIi1'KS5"Ihq"Ji5$JS"qI(TiGR9dGRZ"JAprJB5(KiD%JB#!JS5
+'L)L(KB1"JB+%K)*rI(PfGRZ#KSH&J(TfGAb'LiZ*KB"mHhTjHAGeFh&aFhQ!KSL
+(JhjkGhGkIAprIhjpHhTiGh9cFhClJ)5*MT'5NBf)KB+"JB'#Ji@(L)H(KSD'KiD
+$JB#"KBb2N!#1LiD#IRf"Lj+8NSq,Ki1"IhjmHRGdFR0hIiD+LiU)KB1"J)#!J)#
+!IhprIRajGh4aFRGmJSQ-LiL&JRppIAeqIRepIAjrIRjpI(amI(YlI(q&Lif,L)5
+#J(ejHS')LiU)KB"mHRPjHRTjHAPmJSH+LiU)KS5#JB#!J)"rIhprIhelH(9cFA*
+fJ)Q1Mif*KB+!IhpqI(YjH(GfGRCfG(0bFA&bFhClJ)1$JAppHhTkHAGfGhf%LSZ
+*KS*qHhPiHATmIi+&KiH'KB@&KBD(KiD&K)5$JAppHRKfGA9eGACkJSQ1MSb)KB+
+!IRjpIAemHhTiGhCeGACiHRk"K)D)KiD$JB"rIAemI(amI(f!KSQ+Ki5"IRalHha
+qJB5&KB@%Ji&rIRjrJ)'"J(ppHhPiH(KjHAPkHRYmIS#$KiU,LiQ'K)1$Ji+"J(p
+qIRepI(apIRq#K)H,M)b,L)D%JS'!J(prIRemI(YmIB'&KS5#IhemIS#$KB5$JAj
+pI(apIAjqIRjrIi#!IhpqIAepIAepIS#$KB@$JB'$KiQ*KiD%Ji1$Ji1#JB'!J)#
+"J)"rIi##K)@&K)1#J(pqIi#!JB'!IRelHAKhGhTqJB+!IRalI)##JS'!IhjpIAj
+qIRjqIRjqIhq!J(pqI(YkHAKhGhPmJ)+#JB"pHhPkIS+$Ji+"J(prIRemI(YlHRT
+jHAPlIi5(L)L'KB1#JB'#JS1#JS'"J(pqIRjpI(YlIS+%KBD)LBQ)KS5$JB#!J)#
+!J(prIhjqIAepIRjqIAalHAKiHhq#Ji1"IhjmHRPhH(b"K)5$JAppI(YkHAPiHAP
+kI)#%KSD'K)+"J)#!J)'"JS1%K)1#JB"qIAamI(amIS''LSb-LSH%JS'!J)#"JB'
+#Ji1$JS+"J(pqIRjpIAjrJ)'$K)1$JS#!IhprIhjpIAamIi1(KiD%JS"qIAamI(a
+qJ)1&KB@%Ji+"J(pqIRjrIi#"JB'"J(pqIAalHhYlHRYlIAq$KSH'K)+!IRjqIRj
+qIRjrIhprIhprIRjqIRprJ)+$KB@%K)1#JB"rIhprIRjpI(alHhk"Ji1$JB"qIAe
+mI(eqIi#!J)"rIRjpI(amIAepIAjqIRprIRjqIAjqIRjpIAamI(amIS#$KB@&K)1
+#JB'!J)'"JB'"JB'"JB#!IhjqIAeqJ)+%K)5$JS'!J(pqIRemI(YlHRTlI(q"JS+
+"J(jpIAamI(eqJ)+$Ji+!IhjqIRjqIhq!J)#"JB'"JB#!IhprIRjpIAamI(apJ)1
+&KB@%Ji+"J(prIRprJ)#"JB'!J)#!J)#!J(prIRjqIS'$KB@%Ji+"J)"rIhprIhp
+rIi#!JB'"JB'"JB#!IhjpIAeqJ)+#JS+"J(prIRjqIRjqIhq!JB'!J(prIhjqIRe
+pIAemIAeqJ)+$JS+"JB'#JS'"J)#!J)#"JB'"JB'"J)"rIhjqIRjrJ)'#Ji1$JS+
+"JB#!J(prIRjpIAepIRjrIhprIhjqIRjqIRjqIhq!JB'"J)#!J(prIhprIhprIhq
+!J)#!J)"rIhpqIRepIRjqIRprJ)'"J)#!IhpqIRjqIRjrIi#!J)#!J)#!J)#!Ihp
+rIhprIhprIi#!JB'"JB'!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhq!JB+
+#JB'!J(prIhprIhprIhprIhjrIhprIhprIhjqIRjqIRjqIRprJ)'"JB'!J(prIhp
+rIhpqIhprJ)'#JS+"JB#!J)#!J)#!J(prIhq!JB'"JB'!J)"rIhprIi#!J)#!J)#
+!IhprIhprIhprIhjqIRjqIRprJ)'#JS'"J)#!IhprIhprJ)#!J)#!J(prIi#!J)#
+!J)"rIhprIhprJ)#"JB'"J)#!IhprIhprIhprIhprJ)#!J)#!J)#!IhprIhprIhp
+rIhq!J)#!J)#!J(prIhprIhprIi#!J)#!J(prIhprIhprIhprIhprIhprIi#!J)#
+!J)"rIhprIhprIhprIhprJ)#!J)#!IhprIhprIhprIhprIi#!J)#!J)#!J)#!J(p
+rIhprIhprIhprIi#!J)#!J)#!J)#!IhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J!!!0%!!!3!"!!8!!!#J!!'!83!!!!!!&!!!!!!!!$3@9Zk,S`!!0"3!!$3
+9!$b!J)#!J)#!J)#!IhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!JB'
+!JB'!JB'"JB#!JB'"J)'"JB'"JB'"JB'"JB'"JB'"IhjrJ(prJB'!IhekHAk"JiU
+0L)Q0L)1"Ii'$K)@&KS@!I(TkH(4dH(U%M)*hIAphG(CrLSf*JRapIRk$JS"rHiD
+DNiD(KB"qJSf9PC+)I(&XF(YlE'CXE@GSDQ9MD'CLEAPlIiU&HAq%ISUDQj52Mj'
+2Ki#'M)9iDQKcG'CHC@995e0LE'GLD@TTF(Q-R*++PCD5RUUMN!#2S+LINT+AQT@
+(HA*qMRPNDf*+3%GHCeC9BQ4PFAPcH)Q0Lj@RXDqaYE+XUkkQU,UrXjk8Qj4kDfa
+TB'"G6%G46Mmj2NpMEAQ0QCZDQ+'[YE[#`XA-`lV)fY#qZ+fIQj5$Ef&95%4%26d
+r,b)S18Y19'KlQ+kGNU@XV,rDhFDqeq$4cXDl[,LMLAU$M(9-,b3M+5mZ,MFj-6)
+m4P4KG)Z-M+Hqc0V3ZEI$aXcPlYrEelqPNhpVC'0@2cBf,LBY-5)9'bSj6QCeJBZ
+4Nj1DU,V2f0(-cYAHhG2&XU1JRSk!I@e53c8R-6de-63b0$K$@'9XH(q&Nk@i`-A
+1bm(%b,klcH6E[,#[Rj55He!k3%3k1%"#1#mQ("BL5@ebEi'APT5Y[lD[Y,r-f1R
+jpqI*S)Q4RTH+LAYA3Mij,b3H*#JN,NY46'"`BP9HGBqYcYl5b-@hU+feYm2+`+Z
+ISjU'E8`c+5B`3%8q1#mH%ada3e"A@fL#Q+#MU+LJR+@[[Fh6ep1lTD'HLR9cFf"
+49&4&1MBZ)a`C'#)k6P9KDf0FDRk3!++ZY-('[-,@e,qaV++ESDfZQhaG46e"1Li
+Z-bdQ,$Y$36Y#8PCBDiUMVl@dVV'fXUf`YEc0hYR&Y+LGK@426&0BA@9G3#XR*#%
+L,NCIF(aqJjbXRT+CRkM%i16Cdp2*Yl#cVU@HNi0aD'KK6Mij0c%e1M3e4%pACR*
+eGhk-R+Q`Ylh$c-['`,+ZYlbdV+qbTT4j9$p'6Ne,4N&#48)q05ml6&CVMDQl`,1
+HMT+V`F'iZmhEf-ZiRib%J(9MA@PaC9!r063i-#8U3&CLERCcGB@8Q*'*NkLl`EZ
+fZ,5SSU'KUkqSST0lF'TG8dBk0cFj2N4$16%c294XHSH3!*DKTD'GRDHcXUqc`Fr
+1`,@VRC'*J(&J99YK96id0cJf-Lie3NTBF)')P*Z@N!#-N!#KY,l#`Ebm`m1mXTZ
+(Ji5*Mi0S88-h,bi[-$9!46ml5'9fH(YkHBk[[E'UXlLbV+qeZ-25cE@RRj'&Hfj
+J88a14$Jl3d-l-bdT-e0dJS5-PC!!M+#iXk+PVDZbbYrGbE1JM)##LB*`Df*,3dK
+#05mZ+5Jf8'GVERb"HAq0Nk5rbX6"a-+jXEI'alQXSTQ4LiTmA83k0cJr5Nj$1$3
+a0dPFDR0iHS+G[-@fTU5NR*DSb0E6e-ZcR*+1Jh0VCPpE9Np*4M`V)bNe2NaTKj'
+'Ii1)ND'd[lqp[Er%dGR1[EHXQTHHR*!!HPj*16)j3d!f-c-c0d"3Af*TFh1!RDq
+h[lkXR+'c`FR2cX@qYUZNQik&FeT-68p26%8h+bFX0%"@DQa`IiU)M+1fXkURVVD
+i`Y(3`lL[S*bMS*!!J(&E4N*(5N8m-bSL+$T%5PaQA9aeNCbNVEHeU+Lf[,h"a,b
+[UUZUUU15H&p24$j#5dj%0c%U*bp!5djCEhq%MD#VTU'GQUDj`XV1aEffUkHUTTU
+5K@G16P4346JZ+bFR-$8h3Ne4@'9iLjHGRjbHUlUq[mA$ZVHdUUQf[Db-FfGG88G
+'5d3j1$8`06e%5NY0@@q,RU+IRU#JS+Ud[FA'[lDdZm'lUCL)FfCPB9C-48%q0#X
+Y-M3m4%0+BAZ-NjHDQCfUVkklcp$"[VffZ-($ZU@4K(a`@dJr16Fh0$)e1MSi16Y
+"8fk'Q+5SU+LRVEHj[-E)bmr+bmQjUCZ&Fh&cDPa02c3a-$%e0MFj0ce-@@CjLC5
+@NjZ[Z,5f[EqlZEUraX@jTT@+Ih9ZDPp+1cJf,bXa16Sd-MT%9@emJBUBSUU`XV@
+r`lfhYX,1c-LpU*@+LB*Y@eG42bmX-$3c,bma-cP$8Q9eIiQ6PTHNYVqpYE1l`mR
+1cFI"YD#1IRChEeP)2$)c-bma0$)b06K"8@*`I)1,Pk1[ZVkm[,r"`mR0cp(+XCZ
+APiPfD&j226-b-6)c-#iZ-$G(@Q4TGBD8R+@`ZEl!Zl5e[FVAeXQpYDUFLAKaD&K
+'1cJh0$%Z+b3N,cT(9epUIiD"MULf[m+l[F6"`F[3d-QmXkqNPSPjCNmq1M`m0c)
+[+#3N*Lp"6PPXHhq'P+1YY,Up[-$(cpA4b-M%YUQPRj*rCNp"163d06)Y+#JV,$!
+p6&KKD(Q4S+Lf[VHb[FM(ap$Bemh!ZEDZSBpjDPT(2d%p0M3c,5FQ,6a&5P4KEhk
+2SV'fZX($[m(2hGh9d0$0a,ZaSj0qCP4+36Sl2cBR)5FY,6%q6&CKEAf6T+LZZm,
+!ap6BeGACeXc&`,ZjVT4pE9C"2Mdd,LiZ,#JQ,68k3%eEDRk4SDqeYER"aFM2f0l
+DdFh0b-#eTC&pE&a03$Nh-LdT*L8T-$8i2%96D(k4RkL`Yll#`XM8hGV6c-R+b,k
+[S)ekDPY24MXb,5NL(L-X-6%f2dC3BR@(QkbeYl["ap$6d-r3dY20aX+fSBjrD8p
+'58)c+LFS*b-N,$3f1d98CRU2SDHSX,l(bFc5fYh8bm[1bm@jSSGhF@K@36Bd-LS
+M)5BY-M3e1$p1CRU&N!#LYlkk[XV4e0E5dG24dY6)XCf8KQeC6NT(1LNN*5BS+#`
+a0Me(8PaXL+'XVE'pbY29dXh0dY68e0,,`Uf+EQCQ@dSq16BZ*#!M*#F[1$a!6@9
+pL)U5Sl1raml9fYM4bFI,dGE4[+HCM(CH6dK!0LmX+LJS+LNS+6%q8@ChJj'GSUU
+f`XhCh021dYE6dG(+ZUQEM(jYA8`p-5FN+LiV+#JU,#mi6'"cKC+DTDqlb-r1cY,
+8dpADfYA,ZUHAMB*cBP!r-#`Y+5NX+bNU,M3q6&eYISkFTE#qb0$6cF[1dGEIiYR
++ZkZGMRpcCP9$0#`V,#dX*L3R+M"!89jZIiH2RUkpbY(5dFl0dp[IfY$(ZDQKQip
+pCNSh-bdQ*Li`+#-P+5ii4PCQFRq8UVLp`FA(aX,&e1$PjGM"XUbKNS9jEPY#-bm
+V+LSQ)L)L*M*!59&IERQ%QE2$bml+`X62fGlJi0V1`,#MQ)pqCNiq0LmX,#NL(Ki
+J*Ldk5PCGCR5*RV#p`XM4cXE,eGVFhGM)Z,@bSBajBdXl-bm`-LmP(KdH)5`p5%p
+FEAb,Qkbl`m2$aFlDi1(Jh-kqYl1XST@!CN`l06!Y+bBL)"iJ+$)l3dY6AA#*TEV
+"[m((bXR0fH,KfY,-aEUZT**e@NP#2$Ba-#XI&aBH+$!i4e4BBA5+S,+la-c*bGE
+HhGhDdp(,`F'mTipjA%3p1cJf-#BI(4`F*$!k2dPEDRQ4U+q[YX$'d0lPjZAGcm6
+&aX'kV*L!C%p%1M%Y+5)H(b)P+M%e0Me-ARLBYF#lZX$#b0ALk16LiGR2bX5dRST
+dB&9-3cXa*4S9&aSJ+c3i1Me*ARD+RV,!aF2(e0lJhY[CeYECeXZkT)edAe"'3$`
+d+"dD'4NH*#S[0N*5BA5-SUqbYVr0hqRSj1(Bcmr8e-brVT4eAeG-2#mS*#!G(5%
+M*5BR+c9&BS5GU+faYm,+cpcVl16KiGhEemDYQ)PpF'493cBV(4-4&KdP+bST-$K
+%@R@+QDZma-R@iH,HfpRFiH2MhXqjSSYeC9a64cSX)"ND'KJG*#-P,cp-AA5'P+1
+a[-[CiqMQhYM@f0cIfp,"Tj!!IQaB5N)h+5)I(4iK)4XC(bNh6@GlLCDLUlA"dGh
+LjZINiprGi0M&XD#4L)"[@NBb)a`D'4`I)b8M)LNf3e4TI*!!S+r#dYIBh0cAdpE
+Jl1lJc,HMNB"aCea*0b`N(4XH(KNA'b-Y1daBC(U-PUDmcYhQiYE6f0cJjHAIdX#
+XQ)GkE&P%0#dU*4mI(aN5&"mU08PKEh9qM+1lbG$Eiq(KiqARj0cBd,fYUD'*E&C
+$-bFJ)#3L(aiD'4`M-%"1B(@,RkqmbY,@e06EjZhbm1MFblQYT*1$H'0*1#`N)b!
+E'4F8&b-X-Me,9Q9kN!#T`Y$@eY28fq(Ql1cPiGE$YDZFLR"@4MX`+LFL'488&"B
+F)c!r5P9MGT+XZXM9e0(DiZAVlZVNfXr([+qNN!"c@dNk,bSP)4iC&439(#J`-ca
+2CAkAUl[(c-h0dYrTlr2[j0M4c-#XQj'%DNmp0#XM(KS@%a3F*#NV,cY,@'k1V-,
+2d-c-dYVMkHhYlqcHcX'dT)jaAP9-36BV(a83%4)@(LNb16j%6fQ+S,$!cYEEhYr
+IiH2PiYVDfp2#USabB9&#16)X*L!A%!m8'b8V,MP+A(#&QDbla-[5eq$Ym1AGh0l
+IfmkmUCQ%DP4'1c)U)KS8&4NE("dK+MG$9@f#PUZh[FE3fH$NjqRQj12GeFl$VCD
+#EPa-2c8U(4BA&a-9(#8T+c*!8fKmMU@laXV9iH2IiHAMh0cRkYV$VjQ#DPG-3cB
+V*L3I'"-6&aXJ+cP'9@PrNCZPYXI6hqVYk1,IiZ6JfG6,Z+#)G'453$3V)aXA'4X
+B&4NL+6%p6fCmMTbUZFI9iHAPjZATkqAIh0R0ZU1,GQ993c3T)KdC'4NC'"NG*Li
+j5f4lLCDS[XV2eYcIiqISkHMRiY6#XD'1IQj@4$JV)amD&KFA&4JI*M%q59P[KCL
+SYmE2eH$Uk1ASkqIKfpA,ZkUAJ'TC5$8Q(a`F("N9&KNH)LSf4eTYK*QUYmE@fpI
+Cj[$ZlHhQhYA)Z+UDK@jD56JV*"mF'"8@'"NF*#dh4&GVJ*5PYFM5eYlNjH[Yk1M
+Ti0A1`+bBKA4F3c8[*KmF'4B@&48C)5`h4&4PHT'PZFM0e1$RkZcYl1VRh0,,`,+
+LLQpA4$Sa*KX@'"S@%4)E*#S`28eLIT5MXVr0h1(IiqV`mHhPfY21`V+FJR&Q8MN
+U*"mE&!i3&KJF)LBY1NPHFSHL[-[3dpMJk1cVjqMVkq63[E+LL'jB58)h+4iA%3i
+4%K-A(5Ff2N08FSbIXEr+fqEQjHVam1cTipV5bVkPLRCN8d%[*5%E&4)3%"-C)#B
+U-80FF)'AVm24epMKkqlZm2,VjHAHbl1JNS"S88%f,#%C&!m0%"8C(#-X08*5CS'
+DVEh,eH(XlZcZlHITlZVHclfRN!"iC&9&1#`I&K-4$`i1%KSM,$G%8@4mMk+ibpR
+Nkq[Ul[$VkHAKhpI$V*4pD&9"-LSM("B4$3i6&4JG*6"$9@9iM*kaaGAIjqrdmHM
+NjqVSiY+qVjZ"E&K#0#`M'aB2$a35$")G+$9!5epkMk#b`-cFk[,hmZVVm1lLeY(
+,ZCU!EPa+1bXG&a89&"!0%"FE)bik6fCfKCU[`02Rl1ETpIMak1ARjGI$XD#2H9p
+)0bSL(4F4$Ji6&aF@(bip69aYK*kd`mh8i[,dlZlZl[(UhYE)XTq2H&j*1biN'a3
+4%a)2$"!D*5mk4e9XL*UMYY$MkHRVpIM`l1[MhGI+ZD51H@C61bJI("N@%Jm1%"3
+A(#Be4Pa`I)qV`-cAiZRYm22dp2,UhY2'Xk5@J@T415dS(4-5%K!2%"!A)5Fa39"
+QIC+T`-c9iHVZlZrbp[6Xj0E%Z+L4IQe92c8T'a85$`i2$a%@(bXh38PCGT1QYmh
+Ik1VUlI,cmI$Xj0I+`V1BI@P@3c%P)"dB%K%2#JdA)5FY1e*QGSLLZX[9h1AZm26
+mqr$Sj0h2ZkLFMh9B3c8V)KX@%3d1%4-6'LJh2N49FBkMYmM5h1IZmrAcmIEdip(
+*aEQJK("I5MFT)4`9$3i5%!mB)5BV0NCBESDGYX[Chq6SkZrhqI(TjH2FaDkGLR"
+C56S[*amB%JX)$4)@'b)Y1dC8DB'DX,r-fH2XmrAbm1lTjZ(6aEUPLh4H5MX`+#!
+A%!i-$3m6'b3X08"4D)#AV-$2eplUpIRfmZhSjGr@cF#TMRTN6$dc+"i@%K%2$K!
+8'"dR-d&6CRbAVER'eqETkI(lqZrSk1ADblbZQ(YM8N3e+#%E%`d-$a%8&amT-$a
+1CAk6TVV'cGcZprEbmr6[jZ$Hdm#VPB&X9%)h,5!8%K34%")6&KdP-$j0B(b8Skr
+!e1,VmIAhpqrSk1AGd-+bQRpV@8Bd+#!E&3m1%438&"FI+MP0CRf2S,6$bG2Nm[E
+cmrAdkYlCd,bSQ)PfA8Jm,am8%"!4%K)9'K`I+$9&@h+,S+qqdYrMjZhbmZrYlHV
+Kdm5YP)&aB&"",L!D&!i-%")6&4NI+6G'9QZ%QUc!dq(Rl2$bm1hZmI,Tf-DaR)K
+aAP&"-5FH&4!2%"!3%KJK+cK*@@TrP+@hcH(Zmr2bmI([l1IPfmLdTC4pCe-q,53
+H'4B9&"%4%a8F*c0$9fYqP+QpcpVJjqrfp[2dp2$RfFLhTC*qDeK&05JG&a-4%4)
+4%43D*64%8f0hM+#fc0rTl1cXmr[jm1cUhXUiUjU%EeT%-b8G'aN8$``0%"-B*$)
+q6@"bKCkhb0AJkI(blr2hpHrQfFr%XCZ)FeT$-bJI&a8A&K%1$!iA*#mj4ejeLCf
+caY2FiqEXp[clq22SfXr"VjZ*Gf001LXL("F4$!N-%43B)bih4&9TIjQdbYIIj1V
+Zm[6eprAVhY,(Yk'1H9j(1c)S(KB6%!d,$4)C)bde3P9RI*Lb`p,JkHcXmIIemZl
+Uj0R,ZUH5H9p,1LiQ)4mD%3`-$!d5(5Nh4&*SJjQTZmh@fH2br[rlqI2Pemh&[Dq
+AI@YA2bmQ("84$a%4$a-D(L3Z1NYPIjLb`XRAiq,Nl[AjqI6VipV+YkHAI@&54cJ
+V)a`8$JX-$K%A(LB`2%KEH*+RZXI6hHEZmr6cmr$QiGl4`+qDJ'K84$BY+#%B%!i
+1$3m8'b3Z2%pJFibMXX,6hHIcq2RkpqrNhp[3`lHPLfpA46JX)K`A&434$K)@'4i
+S0N9EH*+QYF64fH$Rl[6kqrA`kq$6`kkCKA4N8N!c+5%C$`S-$a)A(53X0N09E)1
+FYFM5fZIcp[$YlZlYkH6EblDJL'pC5%!i,"m@%3m1$!X3&b!X1849EiD9TEE-i1h
+dpI2cm1[QiprCdm1QM(KK66d`*amE'"84%"%3%4NM-N9CFBHATVM(dYlUm[IjpI$
+Xjpr8alDLNB&Z@%3e*K`B%`m3%4)8&KXN-$e2C(Z@UlR+fq(Mkr,al[$bl1AGcVQ
+MMheX@NSl,5)D&K)2$`m2&"`Q-6e3D(U*RE,#eZMZlr([l[$XjZ$Dd-+[QB9cA8B
+e,#-E'4N@%!m5%aBI,6j4C(H-SE2"c0IPl[,bmHrVkHIEb,HYSBejC8`j-#FF&a8
+@'"F3$4BL,6T+AA5+RV,%dGVJjHVZpIVflHAFcEZUR)YjD&C$-LBH'KB3$!m5&4`
+P,MP%8fL!NkV(fGcKkHhZkqIUlZMHeFLiSielCNir0LdP)"XA%`m,$aJL,6K%9@T
+rNkQpbpEMk1RXm22cl12FdF+hV*ClD&C$05dN(4NA%`m0%"FJ+cK$6f0lNDHpcYM
+Ei1[am[2bkZ$CdFHkUTD#EPK'0bdS)KS8%3i2&"NK+c-q69jdN!#S[Fr9f1(XmI,
+Zk1ERiYI,[+kGJfG54$Xe,53F&a%0$!i9(bXf3%YHH*!!SDqqdH(Skr$epZlNfp2
+0c-QkRS"VA%Xj,LNN(aS8$a!8'4dL+cT2C(H-Rl,%cG(Gl[MjpZlPhGVAc,qdTj*
+h@dBk05mM'489&K88&"NL,$P(@AD9U,@m`XlJkr(fpHrXkGh6cF1bS)YdC9G'1#i
+M'a84%4)8'"iL+69'@h1(PkLkbpMKlIAhp1cMhGcFeFQjSielDP9%15dM'aB8&KJ
+A&KJG*6*%@@k&QUUhapAHk1ramHcQjZMJdF5fTj*kCeY225`M(aX9%a39%a8G+$0
+!9R1*PD#``0$Hk2$emH[Ukq6BcmHfRiq%H'G83#iK'"8@'"JC'aXE)Lp#9QChMU@
+haG,Hk1hYkqMNjHMPf-5bTCQ(FPe036BS'aBA'4SB%a)B*$0"6f0lND+`[F[Hkqh
+Sjql[kZAJeXLeSC1)HQTC4M%L(4mI'"-6&4JG*6!r8@0cJC'U`pEIi1,UlHEPk16
+GemLdT*H0JQT22MBX)adD'4J9&4BD*$0"69PTJCb``0$GjZRPiHAUlHlPdF+lVjk
+,H@KB5$JY*5%G'aJ4$"-I+6%p5PPXISkM[Y,Fi12Pk1hZkH6EdXQpV*f5KR*F4M8
+Y+#)I("F8&aJF*c!k59GLGjHba-h8h0rKk1cXlHVJeXUkUk1AK@pF6$id,#3J'aB
+8&4FH+6-k4&&MHC!!TVh2f0cEhHMcp1hRiGA([E5UQS9bB%`p05mT)KN6%a3A(bJ
+a18*2Ah1,TEc)cGIMjqR[m1VJeFr0a,Q`SBTbA%Xr0LmU*KmB&4BA'b)X0N"0Ah@
++SEI"aXh@jI(clqcNeXh*`VbcRiakB%T#2$)T)a`A&KB@'b3X-MT*AA''RV1paY$
+EjH[Ym1hLep$+b-+`Rj&jB&0*26-Y*KdA%a3D(b)S-ce'9Qq(QDLfa-rDjHcam1E
+EeY(-bF@kTSpkCeC)2cJ[*"dD'"SF("mR,69&@h1)Q+@c[mM9iqhdmZMKfY,2blq
+cTT5!F'"236JX)KdE'KXI)#!N+M4$9'Z%QD@`[-M9iZRYlHIKhGM4bm1eSj!!IR*
+V@NBj,b-F'KSF(b%L*#Ja3&*UJC!!Rl#laYAKjHVXjq(FeGIBa+kLNi4kE&T-2Lm
+N(KSC(5%L)L%P-d45BA1*S+feaYVNkHMMi1$Jhpc4`E@SPSCiDf"42biP)4dI)4d
+D(53U-Me0C(U*Nk+hbpMGiqMPj1AKfpM8blbQNSQ#GfC226-X*5!H(4mK(b!S-N&
+6Afb!Nk5ibp6EiqEPj1,JiGr9a,1RRj1$FQ*33cFT)#!L)KmE(#)T-6j0@farND+
+daYEKjGrEhqITj0[3aVfZQBZ&HQPA4$3Y+58K(4`F(5)U-d"1@@4eKjbeb0AGhG[
+NjprDhYh9bEQTT*Q&G'443MF[+bJM)"iE'KiR-d&-9Q4bKCk`[FrCfGhQjH$JhYE
+1aEUZSjL+HfK33$Nb+bFP)KmF'L!U-ca)9Q4aK*kb[XV9fYcFhqEShpA2`l@`VCq
++GfKC56Sa,b`S)"SE(b%S06j#6&jcKCHT[Fh4dYEGiqENhG2,alqcTTb5JfT64N%
+k-L`Q)L!H(L-U-$Y+9&TRJ*b`ZX21eYhJi1AShFr,albdXDD4HfKD68)i-LmX*4m
+H)#-U-cT"5PYeLT5KXm(*dGMHjZVPh0,(`X'pXU+5KA4H68-m0LmT*#)L*#FU,68
+q5PYZJCDUYVh#bYAIjZRRh0(,aEkjVk+8K'pI9%P!0bdS*5)K*5SX-$8l4PCTJ*H
+QVlR'cpAEi1,Kh0I2aX'pXU'3!)"bCPa02cF`*b-N*53Q,M3f1%*AE(f0Rl#k`Xc
+@h0rJhYM4bmV+`l'INiCdC9T24MXa+b8K*LXV+LSb2NP9DAk1RDZf`-[6h12Mfp6
+8e-l'Zl#MP)4hEQ*95MXX*LBS+5XX+c!e1%*8D(b+QDQh`mrBfpI9fG[Ad-h1aV+
+IMi&hF'CA56`d,LJN*#JV,5ie3%P4Ah+%NU#ebG(6fYrAcXl3dpM4`VHTNi*iE'&
+A6%)h,LdX+58L*#Xe2dYECh&pLTLV[-cEj0r8dpE3bXR([EDZRSk"FPp346Xc-$%
+a-#XQ*LNZ0N0@Ch@#MCUY[F60epI@f0RBe-r*`,#LQT1(GfTB4M`f-LiZ,b`R*bX
+`1NK6A@amM*fa[mI0dG$3epVBep6(ZV1RR*@'G'TH6$ij06-a,#JR+5ie2NC2@fT
+fKCU[[XV5dY(8f0I@e-l(`EQZSTH-IQP64N%q163c-#XS*bNb28C0@QelL*kb[-(
+'bp$9ep[IhG,$YUqXTTZ1I@YF6N!k1$8a,5NU,M!d280)8f"cMD1[ZX6(a-M5fGR
+Bep(([lHVSCU1H@CD8dY$1M-[+bSU+c!h280*8f"[KTkZYEc'c-h4epRBdmR!Zlb
+jV*b1HQ0@8%Y$26Sd,#FT,M%d18"*9Q4eL*UQVlV"a-hCiGr9bXE#ZlHfVk+4I@Y
+I9%P!2$Fb-M%[-$)h1MY"6Q&iMTfTXlLl`FV3eYVEemc![m#iUCL*I("N@e90363
+Z,#SU-6Sp1Ma'8PeVJ*DSXEDrcG6@ep,+amE*cFDjX+'+GfPI@eC,3M`b,$!`,#m
+h1cj$6f*jL)kATV5la06Ef0A4b,qq`mE"Xjq-IR9U@8p+36Se-#md0cFd-64"8&p
+dLT5ETl#h`Fc4dp65cmR(b-+dU*f3!(pbEfPD5Mme,5da-c8f0$Bm3dYBEB#-Pk@
+c`-V3dmr*aXE*cmr)[l'HLheeEQ4E6d)k068d-c)a-$-l490PFRZ&MjQSZFR@ep,
+,b-M(aF6$[,'NPiYqEf*95$ik2$dj0MFf,b`c3&"MGB5,MjUTYX$&bp2Adml-bmL
+rX+@KQT'0JQY@5Mme-63k2Mdj0$-h2NK@CA1(RUZ[ZF2&aF2#aXrAf-r%Z+QCN!#
+,JhY`BP4'1MFj0c8c-M-j3%4-@@C[HSQCUlh+c-I$`X2,dFh*`lZbTjL2L(eV@8Y
+&4%%m1MJa,5md1804A'0ZIBLAU,E!aFE(bXc0cFc&[V@UT+5FMhaS@e&&3$mm1MX
+j0$-f18*-8PPSIC'KUl5l[lkp`X[2d020[l+YUU'8KhYaCPK-4d-q0c-a-cBl3NK
++6PTSFi'AV,V"a-#k[m[0bmM"[X#kUjkBMAYUAPK568P%1c3a-M8i2NK39&YSGS5
+8T,'i[-,(bFV+bFE!YV5fXDULNRpZ@e&5680!3cdc-cFl26p%6eYPH)qJU+Q[YlQ
+pbG$5cmHqZVDaUkLJNB&aC&a@6N9!1M3h2$Xl3%4(6&9MGSHATl'`Xlh%aXV,b-@
+rZVLfY+bGM)"bBeaD88G"2$Nh0$P!3%"%5e9MGiUBSD@UXl[#b-[1cF1jZEQcX+b
+JMS&fD@&E88Fr1cXj18"#3$p#4e*PHSQAS+DYX,@ramc1bF,![ELdVD@FN!#&I(*
+RA94)16%e2d0$38&#3843Afq#PU@XVDqkaF6!`F,$a-1rZl+PQ)YmFh0bCP9*2cS
+k1$Fp3N*$4NY4B(@%LT+KX,V!`m$#b-DmZEfr[VLTQ)b"IAKUA9C13cdk1$a"36p
+!3NKCD("kL*5KVE+mb-M$`,kp[Efq[,#MRC@'HR0XCea*26Sl2d*"2Mj"48Y8Afe
+qLjDIU,6$b-6![EQp`m+q[EDSQSq&I(CaC9C,4N%q2Mik16a"4djACR9jI)LFV,D
+paXV([VLm`VqiYE+UR*+2Kh4PAeP13cj!3d%m1c`q3NaFDh"dJ)fATEE!aXR%[Vf
+mZ,UpYkfSTTU)IRPZB&&*5%C%4%!l1MXq48eABQpkJBQAU,Lr`,qr`FE$[,ZkXl#
+UR*12L(e[Ae&-5dP%2MXp2M`p5&4CB'TeIiZATV5q`X,$aF+k[-1mVDHQSTf@LRa
+ZB&G24N0(4d0!1cY#4NT@BQGaJiqCTV#j`,fi[FM,aEbfVk5ISk1@LS*eBe9-5dT
+&3$mr2Mp#48T5A'KaHSLEV,1bXlV!`X,%aVqdXDfIPjfINS"bC9a96dK#3%!p2%*
+'58p9@PpQG)UHUUqdZEbq`-(#[lLeX+LSUU5DM(KUCPp@8e403MXl26a"58p9@f"
+ZJ)b5R+QbYV["a-A*aEU`UD@SUU+CNB9eDQ"A8Ne'3d!p2%"(69"289jZHS@6TE+
+bVlM$aFE)`EL[UDbYTU#FNB*cD@*F@%p'36Xk3dY*5%a499KKH*!!QU+XXV+f[X6
+%[VUlZE'UUUZMP)CmG@pUCep45%)l1$P"6&*46e0GCh@%N!#ESkQf`F(#b-DkXDZ
+RV,+YSTU3!)&cE@TN@%e)3M`m38K,4N0-9&YRH)L9QCZRXlDmb-V#ZE1`VUUQTk@
+BKi#!HQeNAP*$1MY!4NY-5dY*5eGRGB'1Qk+RVVDr`lqlZ,1ZX,+bV*f-Ki4lGAC
+bCP9%16Np3NK,6%a-89aREhZ(MjLQY-(,bEqhX+b`YE@cVU5@L(pkHACXB9C,3cp
+!3N9'4%9,8Pp[H(b!L*5LVlc*cX5jYE'XV+q[Uk5AMBH#IA9TAe4(3dC'4NK'38*
+(8Q&VFRq(KBkJVV[*bF'lYV+cY+qTT*fCNSH#K)&[@8T)5NC&58P%38*(8PjSGB#
+!JSqKXm(%`VqlYE'dYDqXUCZ-MC12K(CTAP9-4N9'5%4!380)9'4XEh*iK*DLVEh
+)aVkhXlDkYUqQRTZDP*12JhKX@P&25NT15d%p2d&*9f"QF(GkJ)kLYEr![EHf[X#
+jXDfSS*D6Q*U5KhYU@P&388j*4%*#3N"&9'*SDQecK*UQV,DmZlZq[,c![E#LQ*5
+@QCZALhj[AP0368Y,48&#3%46@9CFC@TdKC5NZ,UdY,@i[X(![+qLQTDAQCQ6M(j
+VB9eA8de#28"!3%YB@PCBA'*[KCUTXV@dZEUfZX6#YUbNRCbFQjZ6Jh9XD'4E99*
+(2$Jk38T39PYF@Q*bJC!!T,+cVl#i`FA#[E@TRTQCSD+DNSYjD'0NC&a13$`m2N0
+,89999PTKF)DCSD5UXEDl`-A&[E'QRTbISU+GN!#!HAC`C9a@8%3j1N&)6e048P0
+6A(D,P*kTVDfaZm6'`VQ`UD5ISkLNPSU"HA4[EQjK5MXj16j+8P*58%j@BR#$Njb
+LTkfi`XE)`lDUSk+QUkZNQBTpGR4eG@aE5Mmk1N&*68p16P*CCA1#NCHBRl#raXR
+*`E@TSU1QUDQQR)k"H(9fF@4A683p2dG-6%P&48PBEAU$MC59QULi`m[-`E5XTD'
+RVkUEN!#0LB&mHR9T9N3p2N"&69&,4%*+@'GdJSU0N!#FX,r(b-+mYUbSU+LXVD+
+8Khk!KB"aC9C'3%"$5%Y)4N9#4PCYHAk%KSfFVV[)cmHjXDURUDfZUD#4L)Z*IRP
+dCe9'3N9+6NT%26Sr6&eYGhk%KBUAU,V(bmLrYl1cXUUKRCbAMik8PBCY@8a$3%C
+28dj(3d%q3P"MG(k!Jj+NXEZq[EZhYVQiYVLbSSq(Lj1@NSGiCP4*38"'5dT*4Mm
+r6PpMBfYeJ*+SZ-(%[l@ZXE@j[EZ`STD4Miq1LS0jDeP058Y-4$Xk2N**8PeNC@G
+[HBHFYXE'[lHcYVLfXV#VSjbBPjQ9Mi0Z@e058P&15%!l1$P%8PaJC@PVHC'LX,Q
+jZ,ZkZ,Zr[E@QPT!!PCfLR)jqEf4D8Ne16%Br2$a#5e*A@9KGE(q5T,'j[,UcX,I
+#`lQ`UU'ER*bDQC!!I@aPBPa@9%`r1$Fl3dY4@&eHB'4bLU1aZ,UiYlh![EbkVk+
+ERDHUSjU1H@KLAepJ@8Y!1cFf2dY589*DBQerNCZMVV1bY,r*bm5fTTbDRk1QTjk
+0I(*UB9TC98Nl1$j#4NY06Nj29fCrPU1SV+qZXEl'aEqjXUDFRUHTSC5(IAGaDf9
+H8$mh16Sq59*56%G*9fTlM*bPUl#cZF,&[lLaTk@SV+fSRjH(GR"`F@aK8N8p16T
+!48G(58j@A@KmN!#APjbTYm('bFR"X++LT++QV+UFLRjmGfaJ9dp)2cY$5dT(4$m
+r5PadL)f5RU+MVEV$bmQpYDkMTV#VRjZAMiH"I(GZ@dBl2$j!5P013d&&5P4SIBZ
+6QTqSYm6&[lfiX+fXVDq[UU#2JS'%IA4YB%e"2d&$4%9#384*89eZI)+&MTfUY-,
+1bVbcVkQPUDfYUTk5MSb&H@pQ@%P%48G*5%C#1cJr6@&dIAq(NCQNXll"`F#kXDf
+[XDbMRC@3!)q2MBGpD99(2MT!4da04Mip49&BB@jjKT5KVlc#`,QaUUbcZ,LaUD5
+EM)5(LS9lEf&3480%3Mik2%C,6&*HD'eZFi@HXEr,blfdX+ZRUDkbXDZJPC+3!)C
+lF'0C9PG35%G$1cFi28GAC@Y[GAZ$NU@f`F2![VUcVl+aUU'FQjkIQSq"Ff9@6dj
+-6%Y(3M`k2%96A'*TFAk3!*fQXVkqZ,1cZEqlXUbPQC5ERCD4LRTTB&C+5%P&36i
+q3%908eGFBfYeK*ba[F#jXlHjY,1cVDLSTU5KQj@4JfjLA&TG@%T$3cdh1%"*8&K
+MD@YfM*bMUl1h[F#pZlfjVD'DR+'PTU'6J(0XB9C26Np+3Mml2%9,5Ne9BA'%Mj5
+IVV@dYEQp[m#kVk@IRTqIRTbBLRCXCee56%K!28"$48G'59"A@@&hMTfTXVDhY,1
+k[lL`XE'QSD5RT*Q(I(TaC@*L@%Fm1cXj2NK,6&"6@fThJC!!SkZ[YVUm`-'jXDb
+NSDUXT+#FNSClF'PM@9",3cXk389&4%9+89PQGSD9Rk@ZZ,Ui[,kiXkqXV+HLTkL
+DLiCrFfjVAe0)2$Np2d&%48P-699PFhf1R+@YYE[!`,ZfXDZXVDQUVkLEMi*jGR9
+YBP4)3Mmk1Mj"4%G*8&YRFhZ%NTqVZ-,%`EkkVU#GUE5cVDHKPiPqGQYKA&T85$i
+p3d3m0MY&6eYTGi1*NCULU,6%bF+jXUfZVD1LUUQHPj''HR9`Ada%4%C&3cmm3%9
+%4e4MFRk)MCDMXm$$ZlLlZ,#YUkUYV+DLQBf)KhYS@P0-5%-r389!1ce$6&9KF(U
+!LTZSVlM!a-1jVUbYVl'`V+HLR*1*Ih0VBP91584%48%l16Nq5ePNEhU%Lj+HV,H
+r`lkiYV@bXE#TSU'KRjU3!)CrFPa058T)3d&$36`j28P@A@4aISL5Sl@kYV@l[VL
+`Vl+bVD@LSCb@Nik!E&jA6dG%3d0#3$`l2d90@fPZGiQESkLa[,qiXE5jYV5aUkH
+NSU+GNS9mFfC@68a058!k1$Jm3dG0@'*[ISD-QUUdZ,LfZ,Zp[,5RSDDSSCqLRSp
+qF@4C88P&4%0!2Mp!26e+@f&NFSDBT+Z[XV5fZ,HfYlLeVkDJSD5HPSq#G'YL98a
+&3%%r16Nr4da,6&CMEi'@SkUbYE@eXl@kZVDaV+UXUk+BNSZ$H@YJ@e9,36Nf16j
+"3dG-6eKSFRH*SDf[XVDiZVbjY,'`VUQTUkDKQSk#GfYMA94)3$dl2%"!2d*&5eG
+JEB59R+@XV,'jZEHkZlLbV+USTD@KPSk(IA4VANp$2MXl2N&!3NC&5&&GDhk1QU5
+XXEDjYlDjYV5dXDqXUDDKQ)U"IhPVA9*04MSd1$e!3d9'5e&GERU$NCqUXlQl[Eb
+jY,#XU+kiYkZLR*+%G@aYCeP358!m1cXm2$Y"6&PNERZ'MC@IUE1raX5jXl@cV+D
+QVV5YRj1+Ih9XBPC048&&3cSj3%&!4NpEERf#LCHMUV+l[lbiYV@aVUk`XUfJQ*D
+2K(Y[BeY24%%q16e$3$Y!59*GCfpmLT5HV,Hp[m#kX+QVX,5eY+fQRj@,JhGXC&j
+85N4"2Mil1$Sr49"HDR9rK)ZDTkkh`-+qYkq[XDkYVUURSTL4M)&bC&C-5%9$4%3
+q16Nl3NpECR0pK)ZATE+jZEUmZE@cXl'ZUkDMSCb@NBGdB9905%4"3NG&2$Sp38G
+6BQefK*1HTUbcZ,HeXl1iZE@bVD5IRTkENB&fF9p+4NK'48-p16Sq48j@A'CfK)k
+9RUbk[E@[XVbrYl#ZU+HQSCZCPBarDe9-68Y(4$mq2ciq3NT5A@YbGB5EV,+aX,1
+iZE@bY,HdUU5MSU'KPS0dD9pE9%P$4%-r1MFm4e&A@&aUISZ9SkQ[ZE@ZY,UjYlD
+[TD5SU+DJNiClEf&98&*346`i0ce(58G-@@9YG)#9TDQXVl#cZEfmYkkRTkQQSD'
+LRBplD'"KA8j$3N%q3dC#48e48ePMG)LBSUHVVUq[XlDfYV1YUkHJTUbJMS4pG@j
+P@P424$dq3%9+6&"68eGNFi@5QU'VVkkaXl5hY+UQU+DRVkbEMB9lFfpVBeG04N*
+"384+8&"-89eVGi#,Q+#KT+beYlDhXkLLT+LUUD1GPSYrGh"RB&Y546p$6&"15NY
+399TLFiD2NTZLSUD`YlLbU+5SUDDPTU@GNSGrHAGbC94+58T*5%Y48Np08&PQGB'
+*N!#8QDDaXDfYVkfPS+@VVUQHPC'*IhamFf4E98a'5%j588e+6ePKD(4qJB@3!*Z
+LUDqfYkbIRD+PU+UQS*U4LB4pH(0TA9*-6&*58%p06%pAB'YeIB'%LT5JUl1dVkL
+MSk1KT+LQRjQ9MSH"Hh0R@P0499G889&368pABQadHS#(Lj1HTkfYUDHRTD+PU+@
+JQT12MSk+Ih*SAP959&CA9e436e0CB'aeGRD!MjLGT+QVUD+ISkDQTU1HQC54NSq
+'IA9VB&P@@9YC99*38eKHBQG[GATrKT+JTkHNSk'JSU@QT*qEQCH5MSf-JR4RB&e
+GA&TD@&069PGEBfY`FhKlKjHGRU'LSU#JT+DPSjkANT'6PC++IhGZCPpE@eaE@PK
+@9ejNCQ4PEAGrLC@HSU'FQCbHS+@SSTZAPTD6Mib)JAP`D@CPB9aB9PCCA@"MCQT
+XE'pjL*5ERTqFQTfJRjfGRTbDQ*@9PBq$HR4`EQeUC@"F@9GBA@&QDQYVER4mKSf
+4PCUHS*qHRk'HPT'8PjLAPBq(IRGaE@PSCf4JA9aHB@0MC'CVF(CqKif4PTD8Pjk
+KSCqEPj@6NT19P)k'J(PdFR"UCQ*HAQ&MBf9QCQGTE(0rL)f2NC1@QCZER*bCPC5
+9PCD9NBU$IATjGh*XCf0KB@&LC@KRCQKXF(GqJSH-MSq6QCbFQjU@NT!!NT5@P*!
+!M)D"I(KeFfjSC@4NC@KSCQGRD'T`HB#%KSQ0MT'9Q*ZEQ*55Nj15Nj+0L)@$J(e
+jG'eTCQ9PCfTVDQPSD@ebGhZ"KBL,MT1@PTD@P*'2NT@9Nj!!M)L%J(jpHhKbE'P
+SD'PVE'TTDfe[FRKpIi#$L)f6PCD9P*'2MT!!NC'5NBf)Ji'"IRTfFQjYE'aYEQa
+UDQYYFRCkIAk!JiD+MT'8P*+3!)q3!)q2Mif,LBL(KB*qI(PbE@aYEh"`EfpZE@j
+bGAGkIS+%KiZ2N!#2MBf1MSk2NC!!MBU(KB1$JS&pH(9cF'p[F("`EfpaFh4hHRP
+kIS+'LSf1Mik-LiZ0MBb0MBU(KiD$JAppHACdFh0cFh&aFA&bG(CiHRYpIi#$KiU
+,Lib-LiZ-LiU*L)H(KiD&JS"pHAGeGA9eGACdFh0dGACiHRYpIi'%KSL)L)L*LBZ
+,LiQ)KiD&K)5$Ji&qHhPiGhCfGR9fGRChGhPkHRYmIB#%KSH(L)H(KiH(L)H(KS@
+&K)5$JAppI(YlHRPjH(KhGhGiHRYlHhapIi#"Ji5&KBD'KSD'KB@%Ji5%K)1#JB"
+qIAamI(YlHhTkHRTkHRYmIAeqIi#"JS+#Ji1$K)5%Ji1$JS+#JS+"JB"rIRjpIAe
+mI(amIAepIAepIAjqIi#!JB'"JB'"JB'"JB'"JB'"JB#!J(prIhprIhprIhprIhp
+rIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J!!!,d!!!3!
+"!!8!!!#J!!'!83!!!!!!&!!!!!!!!#m@9Zk,S`!!,a3!!#m9!$b!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhq!J)#!J)#!J)#!J(prIhq!J)#!J)#!J)#!J)#!J)#!J)"rIhp
+rIhprIhprIhprIhprIhprIi#!J)#!J(prIi##JS&qHRf!JB&pJ)D$IRPdGAPkHAb
+%L)&fEh1!KB#!M*QJR)PeER*dFR4hK)TlHhpqJ(KdIT!!Rjk6JfeXGfaNERU#J(4
+XCf9UC'b2S+HSMB')MSekI*HMXVDJQ)jlHhk$PDZcSSb#GfPRCQGqN!#,M)GiE'C
+dI)1HTT4rHRpbE(0cKD'MQjQ(GAk!Gi5CU++&F'CJBP*(@QCVHRGQ@946@fjbE@K
+PAe4HB8!m@'9VF@eSD'p`F)16NBL!KBGqIA4XG(q"HR&ZEQpfJ(q0QS&fIR9iIhC
+mMU'[U*H+NU#JUV+VY,#CSE#HLiL(ND'IJf&99&KRFhf)KRjZ8$Xi28eHEi18PRe
+NCh+)RkHia,fQM(jaFB'2R+qcT*&e@P4RE@TrNj+%FQ&-3%01D)@9PSKfD@TlMU#
+bbY1kSC'$Hhk0SDfaXCq!DQYcER&jI)*iANe&1$%j9)#CPik!I)++RVE+fH(C[jf
+2N!#-M*@TZVQaQ(C[F@GKER4iJAPR8N!q1$eJHi4qC9025P"IEAQ&N!#8Mi0ZA9T
+THRk"J'C05da2@'&LChCS56Nc-M!lA(*kH@PRE'4NFB#(M*+%FQYMDRL&QUUSRT1
+0KAYfGAD"QU+2G@CHA&e@9faiE&Y699TJDAH4UUqEJhGeJ)f+Mk#SSj*pEQ4MCfY
+rP*ZCKQjKCh9fIjDIRjf5KS"qJBbKVkqJJh0pLT5FV-("Zl1FMSGqI)QIV+bTPRC
+PCQplLj1)Hh"MA&aICAZHVUqeTSZ#JS5(NkHLNB9pHA*aGi@NYDZ9F94+6&pcHi1
+(L(aVD@TVFAH%NBpqBP&39QGqNTkNSCQ0JACeJC'Zc-kiQATPBhQ3!*fTS)PjBdT
+!5PT[Mk@HMATQA&jSG(k)LS0lEf"45P0ZLjbHNhpI4d4*9fq%MC'0HfaZE9jNJBq
+1Mi0VDRQ#N!#HU,'iYU#(HA"XHTHQTU@DKRTeG(*YER5"KQpJC'0FCAf,S,bTKB1
+#H(GhEfT`E9P18Ne+BS1+JRGKAh4kEfKYFA1)P)&bFh4aFhq&IR0M@QGjIAb#KBH
+&HA0pK)5)QUb`U*H0P+QcRSb5PC1DS*k@MApjMUHTRC!!Lj!!RDQQRUUdTCD+H'Y
+M98eFEQeL@PCDF)*lHSU1KiH+MC!!M)kBVF#hTCqALiL1N!#@U+qMQjD&F@"-49T
+UBeTMD@*[JRTpM)b+NjZ5I@jG9'Q(SVUhQAYfIATiIS##LiTkEQGE9&TLC@KVC'*
+bGfYTEh0pMBPZBfefGh*bH)+*I@jcI(b#M*+DS*H*IRC[Eh9iGR*U@8e38e9PF(D
+,PBKmGh0fIifDTUkRQC!!LAq#Q++LT**aAeY348Y26P464Mp$46Xq9@*[J(YVCQY
+`GAeqIRe`C@G`HAZ"PDDYUj4eDQCJCh"bFfjTD'jdFA1$NjbEP)PiEfGLG*@STUQ
+[Rj@@Mif4RVI$Yk56L)@0Rl'bT**rGR0UE(Z(NTfLR)YkE@Z!TlZ`STL(IS#'M*Q
+[ZVbpXCCkD'9`KTkMPi*cD@*IBA#%NjQ@Mi0eDfPiPDQbXk@8L)')Q*qKUE5hXCk
+$EQ9XGhf+MB"cCf*ND(+"M*'1JQjPC'b'QCUBNBL#JiL4T+kQSk5IQ*+,KBb@QC+
+"EPeAB'jlKSb(Hh0Q8dp26PPVGh0L99CHB@9ZIj16K(9F4NY99&aZH(Y[984"5&Y
+XFhZ"JhpfEfCJ@PpqQCQ#D9C2D(ahHi1#H'jcGQYNB@0aH@pA4%0'6&0BAfPYCPe
+CA@9UF(0eGfT34P4VJj5AN!#-L(acF@jRDAL!IAGS9%T5B'ajJATXBQ&RFi1'L*1
+FQSk!G@eVF)5HUU@GR*bFSkbRUEHbRiYiCQ"UFRH0STU*JhppJib3!*@QXUD2I@Y
+LFAf'QUDDJA9`D'CSFBUJT+#CN!"qC9KMJ++QMi@0MAq"MTUfb,HXVUHGLh0cMD5
+TUDqiZ+LHRU@eZ+QJSkDLPSfAUkDANSb8RCUGT,E)`lblYD10LSkKZE+NSjqBN!#
++KBH8Piq"FQeJ5d0$@A0XAeYD9d8a0&&`J)q4HQ"126%qBR9eIB4rH("M@QCkL*@
+4FeP168j3@'KaFh*Q9%T08&CVKU'TNA9UFhpeFB+9R*'!GA*XCh5*R+kQKA&cFQK
+XJ*HUUCH*JA9R@epeQEl%TReQAP9CFiqJQiQ%KApbBQ9qRD50F&eD9%P@DAkFQB"
+lIR9TC@f"QU@9I(4lGh*rL*'GPiGkI(efHB+1QC!!E8-[,MC,BA&kIAGQ@Np$8@b
+"PTqIQ(YB-LC(GC'AMi9rH&j'8h50P*@6H%mf-6eCITHHSU5CKA0dKjkjb-DlU)9
+H@S@[ZELhTj+#DeYED)+IXlblRh&58'Z,QCbKUkQ1Efk&R,(#bX[)Vi"HBAZAVEL
+dU*Q)H(L%L*5XVTQ"B8Bl3eY[IBD'K(CI@QGkLjZ``EUJL(TjN!#`bGA1ZjKdDhQ
+1QjD1NTQ)B$`L+6j-B'aYD&!k-MY8C'f"Q*b*GQ4+4&4UKk'QNA*UGi50N!#3!*Q
+PRi4U@8p,8QQ"MSf!GA&hHh4aFS'3!)k)KSZ6NBkLcH$#Nh4fMTH1KAq'Li&[D(C
+jDQYZDQT[EfPbIAaqJhaVEAKYEAejEA@,MSZBMS5MZlQaTjk@NBTlGAPlFh&hE&P
+9C)+8Niq)JAejIB+(ND#UT*bIS++PRjqTYVUZQS"XFAefEhZ)J@aE5ca$@h5%KS0
+dAP96AA"lIAabA%3k0M9-E)QLVl'MM(abGB+-NBf,M(aT@%P8FTDdVj4pE'&FDAk
+*PU#8Ji+-JfpcJCHbXjq2J(4eIBD8RjZ9PBakE'YdKkQkVTU*K(P`L+1bZkQ*G'T
+G8Q"cJD'dUjqCMS11S*kCPB&VC'*94%YPJTZ9IR&UC9pLITbKPSYkDfPSC'0bMjq
+GQ)PdEh*iKSq,L)GiCf"KD'GSG)'(Hf**3PCZKTbKQiYa@%K%5e4NHC@[XTZ'Kj@
+LVV1SR*U6JhCeH(9lM*HFM@T9@QeeG)19P)Z"JT1@I9P-C(b$Gf&GE(PiEA@0PC'
+*JB1)IfPMFSD9KQPVK*U@L*LbZkkCQ*kENAeeLk@`U*LGY,Z`STLEQRpcJSq0Ih*
+eKT!!M)4jHSD,NTbMUU#+LCQFNB4jGi12LS+"JiD%JB1,PBjqHRepGfTSGS'%Hh9
+`B@*[HSb8NiYlF@eL88G0BAL(MB9X@9j[HhK`F'CE@dp&89eKBPeQH'j858K9E(b
+"Ji0kE@jfG@p[GAb+N!"qCeP@C(*dGB+0KB*rDQk*NC'ETULJQCHHTUHXYF'rTjZ
+GPSb-M)U6RT4qGRk*NCD5NC@+GQeVEhU+P*!!Li4mHh4aKC!!ND#URj!!MSKpISH
+AVEQ[RT@+IhTmJ)@,M)4fE(*YA9KIFi&hE@GIA&TNIBD(MBGmGA4ZAf"fMTD5MSQ
+0NBq@QT@*HR4SAfCPDAL)MRjTB&GA@fU+RCL+K)5%MC15RDkcUD'BL(GRBh'+Q)"
+NA9PFDQaUGSH1MB&eI)*[CRH3!*b8Ki+#LT52JAq&LC5DQk#GNC@XYDD8LAPTC'a
+YCh4jEA9iC9YKAeYZJACPBQCMCRL%Ki@!JBL-LiL$HS5GSjL$E'4H9epQB'4VB&4
+96%0-8%P3CfpPAPj@8&aN@9T[J*'EPj+1LBZGVDHEQT!!IhYqHA&hKT+DRjD!G@j
+RG)@%IhppHAPhHS*lI)f9Q*Q6J'GQJT@1MU1RRjk1Ghk6QU5i[V1NNB+)RU#-L*D
+IRC*i@eaSDhqBS+1DJAH(T,'MR*f5KRj[A@9hGRZ8TCb+IR*fLiYlIB&fFhppCPp
+RFibQUk#ISTqNVULFRD1@Ji1#FQemKSZ8PiGbFS',P*b6JRKXAf0XA8P4ChQ+Pj!
+!Ihk'LTbZT)k"GQPUCe"2DRf$IAGjGR&hIiZEQS0YBQ0pP(pNDhKlHACcGAf'MCD
+QTjD-LT'ENhacISk4MBQ-MSH8XE+INB*ZDAQ'KAaeHB53!*H3!)f)KT@LRTLCKep
+9BfCNB9aEAQ"D9f9`FiQHLR*jH'&FERq%IA"ZHhaXChD'PUDFIR9qG&K4DRaaA8S
+j1Mia,djYHSZ5IQpYA%"(ESGrCPPJEATdDS#NVD'1GA&qFeGAHjQ-EQPXDfTC5fU
+5Q*QNNRKaB8eHLkH9G@TRC'&JBR#'NTUGN!#!H'eTITH@I(0qJACaG(@$PjfU`,q
+KKR9`JTHELRk1QBf4SkLRUDkeX+'0IAamHhpdA@"jKiL1PB&aIiUCVD11MBjpFSL
+@KRq,N!#@TkfHRkba[,UPPjD9LB@8P(YbI(GeKiG`DRq-NCbDLRaY@e0EC9a@C'e
+bI)*rKTUJPT!!KR"C6%YCDfT@8QGcDQ0F6e&SGAqASSebBPeeQ*4lHSq6J(9hIBq
+QY,'XVTYmG(1!QCQ(IiH-K(KYC@9iMBf4RT4lFAQ#K(piHBL4NBf*LBH3!+U`PRG
+N@P&299TRD@CT@e9SEepFHT+5NipmFR*aGAq'IR9mG'CZHRQ$R+LUU*0iEA*hH(K
+dCfGeE9PG@d9)BfaZKTU'EQGIAf"B9@&lM*1APC@ES++[a-+TQT''JR9JC(k8SkQ
+KMRCLA&pXLCf@Mj54J&p*69KLEAU%I@489@"fLSk(P+'3!(CG3cG&Ah1,RT4jBPa
+MBhD4Lj!!SC9lC9ePEhL)RVHpUC!!K)QEU+'9NiaqGQYJC'ekM*LBMSH%HhGiJT1
+1H@pdIRafGhk0PT'4R+QZVDHXbp#YPBk$IAeeDh&rJh0UFfpZIhpjNjpi9dj"3P"
+@C(b-KhCqP*kQTjqQ`Ef*D@0A9PTDFSb&GRKiFhPkHB+)MSYrK(PIA'0XJj*qDi#
+,J)D9RD@fZTq8RT5!HA4cLU#4Jj+EPj15N!#6PSU'PT!!F9a36fkBS)f*Q*@%KBU
+2PT!!Mj@CN!"[9PGHAf&cKj15K)'%J)4kBQL*RS4C69455e0[Lk1TPik6PT!!Ji@
+FYm1cNhGTA%)e4fCmGfGUF@GA589HL*PpAe4%,4iU9(U,PTqUXTjqERH4SkLLQC!
+!F8Nk2e&SIj'DR*4pC&TIBhHFSSTY55dS0%K56fH0NSClD@&dKBD4TD+,F&0%8QY
+`F*@hUTD@Li#)JRkEShaE8NpFG)'"LUL[P*5YVkHUTDHiU)0hHR&ZH(KdIBZ'D9e
+RD'YYCB+MJP42AfYfKj+PYkqMSU@ZYVQjaH2IVj!!KhYiH@TRIiYmHS1&Mj@6R+f
+kVSPS9NY6BfTrQCDATkHHQjUIUDQDKhpjE&eDDR9eDQ"UG("ZD'*fPT'%Pj!!D%m
+j+N*PD9K5BAH'LB'#SVkZRk+JPB"J8(#4KR9hK)KiER0mMk#IR+HRL'K69RU*JSH
+,NjU5KAq)R+DVV*k0J("GAA9kEfphKBCmH(erJ)H2Q+LSNheZCf*TIiU,Nj+(KSZ
+(KTHUUjf8MS0c@Nj058Y06&"CBejFE(TmFQ9LAe%k,$0"8QCTE(k(GfYdJjU`TSk
+,NSKbE(U(L)*eD'PYCPjIFBb+IB'#G93i0$e1@94GDQjU@eadMU1TTk'9LA*EBAU
+'Hh*mIQaKCA+"QlDdTk#BLhTjLjQGSkHUTk#CNj1CSE#mYU#0JAPqLj15LiQ*I@p
+UERU'KBQ9MAZ"LSD(Mj!!NCDAMiL'JS56RkfkYkD8Mik-M)D$L)*ZAPpSDfedJ*5
+HN!"cB'*I9ejUH)D%HRb)N!#,IB'9SU1EM)Q4M)'#L)k5KfaJD@TG@fGbJ)CfEAq
+,Gf9ZGh4aFA"lNjZ4Mj'CT*q@NjkKN!#1RCf6KhGeJSQ'Kif3!)Z"K)CfITL@PUD
+LNB&dFRClKj5IQS"cG@j[JT!!MTLRMQeUBPTSG(KlHfpF9&KE9Q&pL)Q&Ef&QAeG
+NHiU4M)"pJiL"HBqVU+#8FeT@5$P2GAafEPC(58p,4eCQCQ"54Ne99Pk!R*H2LiH
+3!*''JBfZb-+RP)TqF'"NK*b5Gf4JA9GBA@k2Nfj86%%q2N&FK*5%FQj[FR9kJT5
+SRiU,MB&rHh'!Q*H-L)0mG@ebJBU3!)q-Li&hHhKhP,'QNj1,LjQBSDqRSkHZYUQ
+FS*f8QCQ*KSPiG)5)NU'8JS5+J@j`KC'5PCL9Pj@0Q+UdbY+jVl5RQ)q*Nk+DM)9
+lGR4aFR@$NB0R@eYF@e05EB"lKT+(H'eSFS16QjL6NBk0MBQ+N!#!Fi10H@a[GS+
+)K)Z@LRPlI@jND@aG9@YiD@akIik@M*!!QC+*Ji+*NTQCM)bHR)4pKjLSSj@HUT9
+mHRf"J'pH99CQF'GKES"qGS@EQiKpIS54LRKmIAQ&JQpYGR4RChf5PBamFi'%AdP
+BBfGZE'GZIRpZEBUQTT+"K)TZ4d*+8Q&SBQ0ZDPG*8'YlG'TTEfY20$G)89YRFRe
+pF@PKE*1RQj1AQT*jCh&kFAD&MC@4JR*RG)qBPCH6KA4F4%&$3P"LE@TCA'GVJCZ
+KSU+2IRP[DhZ#IBbPT)YhHS+&ND+UZF'MN!#6Jh9lI)'JXTf$I)+'JjDme1(5T)f
+-JRq(JB+DR)4bDfp`DALDYXV'VD@QNhedFRq4MBQ0MC13!)+5[pR6Zk1GR)TcD@e
+eH(9dGAb)J'akPj10NiZ,NS9aD'GQC@0ND@jiGQYqPCLLS)q9Q)L&LAp`DQYVEhG
+kG(D)LAb#Ki#"JB@0Hf"A@PeMD@YZFhZ0QTLJS)b*L)1+KAPhG(4fFhD(PjbIRjL
+GRj@9NT55G'CaG(9jFR+"KRb%QUDdZD@8MSGhC@0MB9p@6eYZCPYYJ)LETCkLTCH
+!C&TA6eGSG)&mC@"hNTkTVULNPAPJ6e"86dp6A@jU8deDC@KXGR9XD@KH6dj258a
+FDh*VB@9bK*LRYEf`PSGlD@amJ)5*JR&K@PpXHS5)M(jE4NpD@f0N@9TJA&YB8ep
+fN!#QZXHcNB&lEQCiKB+&H'9XF'GZKU1b[XD`NB1%LSkCT++3!(PhJS&pJj@acGI
+5[Tk-LS1$NjqBJ@PKC@CXHiQIXUfZUC!!IR0`HSL-GeY6A'YcH)QFYFI"am5MMSk
+2N!#CNh&E@&eSFAPqKC51IiD'GA"cFA0qF&*'3djPG)#,Mj@ARV@iUD+JSD+FLhC
+TBQGeISD2Li&cFS+$Hhf#Ji1(K("M@Q&iJSL&Ghb%M+#NQ*58MB*pG@YUFSQNXDq
+BKBb0MjqCM*+8JQTSDQ*MC@f&NSThERZ'MD+USU@JJfpaDPP@@&edL)"ZDR9hJU'
+USD+@HfGC5%*29QD%LRYdGS#(PkbaVkD2H'jU@8T6A@TpH@&15NY)9R"rJAKXC9Y
+02$jBDRH+LAGYEAH$P+qhUk'@LRpbCf4YHB+0MhpZCQ0JD(arH(9[E'GJ9%Y8BQk
+"JfjNC@KeMCkDMiPrI(aU@&pVEAqFSC@6NT5KTkZZUD1FPBf!G@pUF)'DSBk)MTQ
+XX,#dUCkIS*q1H'eUF)5DQSf0NC1BNjQQQBH(LSGkCe91B(qGTjkGTUbVUEDqV*@
+2PCQ3!(9A8Q4iLipqGhTaCfahIhCVFRYhBdJp49"PKTD@RCU'K*DSU*D+N!#EPi"
+UAQChJj1IR*4qDQjmLBZ#IifEM'jE9PYRGT1PSCH#Eh@0Rk+BP*U@KQjMFi#%NkQ
+XS*Q*Eh5)NC5,JRpdC&*$5PpVHTUUQSf$FRkHXEZkU*Q+G9p08'4dKjb8IATY@Qb
++PU1NLR*RA%Fj3PKaMk#@Lj55KT+RVlDYLh*YC&KCBQjmJAaaCf"44&9eL*!!JQ4
+A9%Bk2dpNHi0hERH(L)16VE1SP(efI(PXFBLCSTL#HATdC@*hMj+(G&a28%a'9Qp
+[D@YPAf9[FRZDTj@*IQGIAPKIFSD-L)9eFB'-MTLXVTL4L@jQC&pRHiZ-NC5+LT'
+8RlE0cEfdU*1(J(Z#LiL&MT''JSD0PD'YUTZDQSGkFQYVDQY`J)Q&M*@DUVV'aE1
+TST@2LiD$KBL+N!#,JBH)KS4rLC'!GA0R@eG33N&4AQPVDAU,LSU3!+'TQSPmH)#
+!H(CmKSQ,KRk(MB*jIBU*IRYhH(PU@eKID@j`Dh#(M)+$ND1UT*U4M)4mHS#(KBD
+(J)DANB1'Pk+CLi@#H@YE99YMDA&lIB'1N!#-P*qSTD5XU**fCQCVFR4dHAGfJ(p
+lIibDPiq6MAGM@P*39PKID'CSH)1"KjDJSD#PTjCpF'YZH)#%IQKAC'jRCfebGA0
+YAdir1cp&8Q&SC&PHGiL)MCbPTCq@NSPfE("qP+HPMhKVEAKlIiL3!*!!Ki"lE&P
+389CQH(&F894MG(b*Qjq6KBH1Kh"EA(52PSPiEfpjKT'QZ,@LNj+4Kh9MCAf9QBP
+iEfq$PTQTZ,#KQjZIS*4rHB58SCq4JAL#M)fETTU0KiD&JRYXB'"XHheaC@ClPk5
+PT*kCPCHGS*k6Jhq+Q*D(I(9pLS&mKiGjD@*QD@052Me9DfYNBfb%Pj12PTL3!)4
+kJj15JR0bKCQEKhGfIS&dDhD#KS*pK)k%DeYDC(0hF'pcGhTjISL0NT!!NkDVPAp
+iHB#*N!#1M)k-LB4rJSU1M)H(JR"F8PKTHB5(LBQ)MBf+NjZMUD5FP)b!Ghk,PU+
+MR*'*KhpiISQET*D$IAGR@@"ZGi+(IhZ%LS0qKj1MVD@BNSepFAf0N!#-JAGjHR*
+M@Q*XFA&N9PK84804C'eSB@&UGAYiGS@5N!#'IATkGA0jM*kGMRehI(YmHR@!KhT
+aFQeK@&&IHi0cAe48@PjSGAU"K(TcGAGdEfq$QCb9LAjkIB+1PT!!N!#5L)5(KRT
+ZFAb(MBQ"HA0fISqKRC@BQTUBPT11MT+AQCbJQ)f(L*UJKhQ"JAPiH(9fGhClKBU
+,KhYfJT+5J(Z$JS50NTUKPiH(PCbIRBq(LSf!E'T`E'9MD(0hC9PKEAGqJ(YlKiY
+rFhU!GfpcHi1*JRKkKC'CR*@+J(PcER9rFf4SE@eXC'0[I)5$J(KTBf9SDhk8NB@
+)L)'!IRTpLjQJUUH1HA4bGSbKP(ppH'YRCQ*VJC'CS*Q$GRGiHj+ZUjL3!)Q'M)Q
+(MCDMXVL`RBPmFh+&S*TqF@GJC'KYHSqIS+#BL(jcEhL4Uk'#Gh9fIAjpLCLDP*1
+4KhPN9PakNS*I6da-6dp@E(eqGhKlGQjL@@U*PS*RB@*QE@abLCL8Lik3!)U"F@T
+fLT1!BP048e98BRf#H(*[E@PJ9&0SK)eqD@*LAf4`IC!!QjQ3!)Z1M)*iH)@5Qj0
+lF'jVE@pfLTUCNC'5Mib)L)kGVUD2LBZ)Ki@'NCfMSCUDQC!!KS5*MSq$F@a[FA4
+bG)@9Pj'4PC+-IhKrKSb'G(#!LSCqIiU1Mik0Mj'*HAL"IRKYAPpZG'TLCQjiJAp
+pKSKhEhf*KAaaC@Z!KRaiJBU,N!#@PCD4IR@&NiGhDPGACfaTEA4kIS1,LiGqFA5
+2Tk+5KhPaGRTpJS1%M*HGQBepGB#BU+19LACTE(0lJAalKj1DP)0cEhqATD5CLhT
+XDA*rLBD&MCQIQSepG)'BTk@BJfC269PXHhf"Lj!!MiTqF'YeLTZHPi9XAf0[HiD
+)K)L0M)ClEQGYHiL,JQp826T,A'GUDQeZFA0`DfKXHiL(IA0P@Pp[I)D*Ki+#KiD
+%KSH,P*H-I'pF4dKHFRjrH'pVE'TREAL"Liq%G@pP8eGbKj!!Mi9pHRejF(Q-PTq
+KNS*rG&jGFB#*LB&mH(9ZD(Q1PTbJQ)Z)JR0eLTH@N!#2N!#2LiD'PULVT*k5Ki*
+fD('#KB@(Kif1Ki+#LjL6LSZ%Hhq$JB@3!*!!Ki&qJ)*qIB')Mj'-JhK[F(9hHAe
+eE'PSDR"cGAZ$KS0rGfPKDhZ%LSb)IhCcFR0hI)#*NT@4JfaGB'piHRprGQaRDA*
+rKiD+NC+2KR0QEAf$KSZ+L)0rJSH0Nj'9RD#LRSjrKC'1LBf-JRGaFhU$L)+"KSD
+'KAYhJj16Mik)J(ajHi13!*D5P*D1LSTpFRf+K(k!I(4[D@TfKSq2LB"eFR0YDRb
+1N!#1MB9pHA*YG)#%JRjeEfeVCQ9bIhPaF'jVCPYBDATqIRPYC'"C99eaIhadFR9
+jG@p`HS1'KS5!J(ecFhq-Mi9hF(*dF'a[Ghk#JAadE'4IDS'3!*5+I(CiHRKlKBb
+0M)U*KAjfFS+FUDD@JRKiFh0rKiZ3!*+4NBf"Fh'#Q+5QQiU$IhPlKSq6P*@AQ*1
+$GRH%PU@PNAefFR4rMT53!*!!Mib0KhYbG)'2QTb2JATcFi',L)5$HhTqHA"YG)+
+-P*H+HA&UE(f-N!#1KhekHh9[EA"jKBf-K(KaEh&rLSD$JRYhGh*[FR0jIhpqH@P
+IAQ9kK(plGh&ZE@Y[GA9iIRaqIR4bH)54P)f(KB0rJ)#$LBQ0P*!!MBU!IB')NjD
++K)9mFhL"M*D9MiZ"I(aiHB+-PTL2LBH"IB##K)L'Ji9qFfpZFAL%N!#5M)b1JhC
+hI)#)LiU-KhaiGhU!K)L&IAq#HA4eF@pdG(4kH("`GRYpIS5$I(f"I(PiFQpcG(9
+jEfCZGhq%K)H&HhZ$K)H0LB5&JRjkDf0YHSD0LiL$G@jaGRYqHRQ"KB&pEf4YHiH
+2MSf-J(CiIS'$KBD,LiH"F'GcIBH8Nj!!MiGqJBH1NBb,NT52KhP[G(U%MSb*L)&
+mJSb5N!#-M*!!MiCpG'pkJSD3!*!!M)KmGS#0NT++Ji5"Gh0bFAU"K)L$HA*SDhU
+'MSk'JS9rE@KVEAL&LSb,KAT[F(Z(MSq+KB&kE@ecGS'+Lif*IR*UF(f*NC10LSP
+pDQ*JA'CdHRelG@pUEAL#KS5"IRPaE'pcG)'0Li9pFfj[G)#,MBU'J(jmGhPpIB5
+2MSCpHS#$K)kES*b9M)D!HRb"JBH1KA9UCfjeI)L@Qj5-JhjrIRerISH3!)9hF(*
+qL)Z8RTqBMS@$JAf"KiD,Mi*aC@0XGAb'Mj!!L(pjGRChI)&qJB9jDfCQF(q)MBq
+,JhekHhajIiU*LSf!F'TTF(b#L)q4Li1!JAjpJiCpHRaZB@4SFB+0MSf,Ki1"J)#
+"Ji4rIRjbD@PSEAb"JB1$JB#"Ji5&L)Q%JS*jFA0hJBk8PC53!)k3!*'2N!#4M)@
+"IhYbE'ebHiD,M)b+LSf0MT'4MSk*JAY`CQK[HB1+NT50LBQ+M)k-KB*rI(KYAea
+LDR"iIRjrJB"rJB&pH(GhGRPcDQYaGAZ!JiD)Lib0Nj@3!)Q&IRTpHR&[Eh"cFQp
+[GRq$L)f,KAacEQe[EfeaFh0iHhCjJSH+MT5ANSKqGR0eGACkHhPpI(9fIB5-PCq
+NS*D-KS@&JS1*LSH+LSD(NCQFSUHTST5(JAafFR0iHhPlI(GiIi1'MC5DPiPrHRG
+fGA9iHRYqJi@'M*HHRjqIQif"I(GbF("`F'jZFR*[FRb&LSb0M)0fF'j`G(9dFA"
+aG(4bGi@5PjQCPBYrH(0`FA0bF'jZEh"[FAk*Mj'5N!#(H'jVEA&hH(CfHAamHhk
+(NjQCQTH-J(KdFh4fFh&aFh9dFhD!LSq3!*19N!#&IRTjHhppHRKjIAq!KT!!QCf
+FQC5,J(TeF("cGAGkHRYlHi'*Mj+6NSk(IRPiGRGkHRPkHhalHB14PjZGQ*5,I(4
+`DfYYDQPYF(*bFAL'M)k2LS4rHAGhGRKkH(CeFR4iHAq-NjHDPT!!L(jkI(KdGA0
+`F("cGhKrLSq5Niq)J(GeH(4aFh0bFR"bG(4kK)Z4PC'-L(jhGhCeHhpmHRTrJAq
+$Lj'@QjZCPBb&KB1"KSL&Ji5(L)H,NjQHRjUANiCkH(CfHhekHAf&Ki&qKBU0MBb
+0M)*jH(KjI(YiHS'*LiH+NC@9Nik1N!#'H(0bFh0aE'acHRemIB1&JS"pIS&kFR9
+kHhYhF'j`GATlJBU-LiU(KiGqGA9fGh9[D@T[FRCjI)+&KB@#J(jfFR9jHhalGhC
+fH(apIi@(KSH(KS*mGhGfGACdFA&aFRKpIS##KBQ,LSL$J)+"J)#"IhelIS@*L)U
+-M)k1LiD!IRjpHhYlHRYqJSH+LBQ)KSD(L)H%JB+"Ii#"IherJiQ1Miq3!)q1M)L
+$IRPfG(*bG(9dG(ClIRerJB'$KB1#IhalHhTlIAelH(GlJB5&KSH,MBU&J(TiGhC
+fHAepI(TmJ)'#KBH+LiL'JRYfG(*cGhYkGh9iI(q#K)H,M)U)JhahGA0cGAKkHRY
+qJB'$L)f4NC!!N!#2Li@#Ii##KBH'KSU-Lif3!*!!NC'2MSb&IRThGRGjI(elIB'
+#Ji@'KSD&KSH#IATiH(KkIAprJiH(KiU+LBH$Ji0pG("[ER"cGA4cGAPmIAq"Ji5
+"IhppHAGeFR*hI(YjHhq#KBL+MBk-LB9rH(0bFR0hHhYjHAYpJ)1%KSD%Ji1"I(P
+iH(PmIRjqJB1$JSD+MSk-LSH$IAKeG(9iHRPjHhk!JiL,MBq3!)k+KS+!J(jlI(q
+"JB1'KiL,M)Z,LBD$IhThGhCfH(TjH(f#K)5(LBQ*Ki5#J(akHhYjHRYiGRZ#KBD
+(LBQ)KAjlHA9cFh0cGACcF(4lIAk"K)L,L)*rIATiH(PjHhjkH(f$KSD(LSf2M)D
+"IAKeFh*bGRTjHAk$KB1$KBL+L)@%JhplHRPiGhGhHAk$Ji'"Ji@%JS'!J(eiGA4
+bF(*bG(Z%KiH(LBZ-LiQ)LBQ)Ki@$JB'!J)@0N!#3!)k0M)Q&Ji'"JS'"JAjlHRK
+kIiD+LiZ+LBL&J(epIRjqIRapIhemJBL-MBb,LSH#I(KhH(KiH(KhGR4cGRarJB+
+#K)1"IRTjHAGfGhKjHhYlIi@)L)L*LiU'J(akH(4`F(&cGA9hIB'#JS'#Ji5$JB"
+qHhKhGR9fHAYqJiH'K)5%Ji+!IhjqIAKeFh0dGRPpJiQ,LSL*LiU)L)Q*L)D#IRY
+lIS'$KBQ,LiU*L)H&KB5$Ji&rIAamIRq#KBL*Ki@&Ki@!I(aqIAakHAKjI(apJSH
+)KS1$K)0qHAGfGR9cFA"bGRGfH(erIheqJS1"IhemHhPhGhKjI(q"Ji@%JS'$KiD
+"IRajGR*[F(0fHReqIi'"IRk!K)D%Ji+!IAPeG(4fHRjrJ)+#J)"rJ)'!J)"qHRC
+dFh0eHRq$KBD&KB5%K)D&KBD'K)5$JS+$KBL*LSb,LSQ*LSU*L)H$JApmHRTmIi1
+'KB1$K)5$K)5$Ji0rIAepI(eqJB5'KSD'KiH'K)1"J(plH(CeGAKjHhq"JB"rIhq
+"Ji5%K)0rHhTjHATmJ)1&KB1#JS'!J(prJ(pmHAGdFR0eH(f!J)#!JB#!IhjqIi"
+qI(TjH(GhH(YpIRq"JS+#IhemIAemHhTjH(GhH(YqJ)'%KB@&KB5$JB#!J)#"JB'
+#JS1$JS+%KSH)KiD$JB"rIRemHhYpIRq"JB#"JS1$JS+!IRepHhTkI(k!JB+$JRp
+qIRprIRepHhYlHRKfGRGjHhf!J(jqIhpqI(erIRjqIRemI(aqIi'%K)+"JS1#J(j
+qIAamI(YkHAPkHharIhjrJB+"IhprIRjpIAjqIhq"JS+$Ji1%KBD'K)1$JRpqIRj
+qIAerJ)'#JS'#K)@&Ji1$Ji+#JS+#Ji5(LBQ+LBH'KB5$Ji+$Ji+"JB&rIAapIi#
+#Ji+$KB@%JAprIhprIhpqIRjqJ)'$Ji5&KS@$J(emIAalI(eqIRemI(amHhYqJB1
+$JAjmHhTjHATmIRjrJ)'"J(jrJB'"JB#!JAppI(TkI(apIi"rIAapIRprIRjrJ(p
+pIAalHhYpIi'#J)#!JB&rIAk!JB&rIRalHRTmIi'#JS#!J(pqI(apIi'#Ji+"J)#
+!JB+%KB@&K)1!IRepIRq"JS'!IhjrJ)#"JB'#Ji1"IRamI(epIAjrIhjqIhprIhp
+rJ)'!IRalI(epI(amI(aqJ)#!IhjpIAjpI(amI(eqIRprIhq!Ji1$JS'"JS'!IRe
+pIi#!J)"rIAapIi#!J(jpIRjmHhYmIS'#JS+#JAq!JS1%KBD'KS@#IhepIi'#JS1
+#J(jqJ)'#Ji5%K)5"IhepIi+%KBD(Ki@%Ji1$K)5%KSD$JApqIS#$K)5%K)1#JS+
+$Ji1$Ji1"IhemI(eqIi#"JB#!J)#!JB#!JS+!IRemI(eqIRjqIhjpIAjqIRemI(Y
+jH(GhH(TmIRjqIRjqIRjqIRjqIRelHRPjHATmIRjqIAepIAjqIRjqIRjlHRTlIAj
+rJ)"rIi#!J)#"JB'"J)"qIAamIS#"JB'!Ii#"JS+%KB@%Ji&qIAeqIi+%KB@%JS'
+#Ji1$Ji1$JS&rIAeqJ)'#Ji1$JS'"JS+$Ji1%Ji&qI(YlI(erJ)#!J(prJ)#!Ihq
+!IhjpI(YlHhapIRjrIhprIhpqIRjrIhppI(alHhapIi#"Ji1%K)1#J)#!J(prIRj
+qIRepIAepIi#"JB'!IhjrIhpqIRjqIRq!J)#!JB+$Ji1#JB'!J)"rIRjrJ)'"J(p
+rJ)'#JS1$Ji+"JB"rIhjqIS##JS'"JB'#JS'"JB'"JB"rIRepIRq!J)'"J)#!J)#
+!J)#!JB'!IRepIAjrJ)#!JB'#Ji1$JS+"JB'"JB#!J)#"J)"rIhq!JB#!J)"rIhp
+qIRjqIRjqIRjqIRq!JB'!IhpqIRjpIAeqIRpqIRjqIAjrJ)'"J)"rIRjqIRjqIi"
+rIhprIRq!JB'"JB+"J(prIhprIi#!J(prIReqJ)#!J)'"J(pqIRepIRprJ)'"J)#
+!J)#!J)'#JS'"J(prIRq!JB+$JS'!J)#!Ii#"JB+#JB"rIRjqIi#"JB'"JB'!Ihp
+rJ)#"JB"rIRemI(epIAjqIhjpIAepIAepIRq!IhprIhpqIRq!JS+"JB'"J(pqIRq
+!J)#!J)#!IhjqIRq!J)'!J)"rIhprIi#!J)#!IhprJ(q!JB'"JB#!J)#!J)#"JB'
+"J(prIhprJ)'"JB'!IhjqIhq!JB+#JB#!Ihq!J)#"JB'"J)"rIhprJ)#"JB'!J)"
+rJ)#!J)#!IhprIhprJ)#!J)#!JB'"JB'"J)#!J)#!JB'"J)#!IhjqIhprIhq!J(p
+rIhprIhq!IhprIhjqIi#!J)#!IhpqIRprJ)#!J)#!IhjqIRq!J)#!J(prIRprIi#
+"JB#!J(prIi#"JB'"JB#!J)#!J)#"JB'"JB"rIhq!J)#!JB#!J)"rIhq!J)#!J)#
+!J)#!J)#!J(prIhq!J)#!J)#"JB#!J)#!JB#!J(prIhprIhprIhprIhprIhq!J(p
+rIhjqIRjqIRjqIhprIRjpIAjqIRprIRjqIRjqIhjqIhprIhjqIRjrIi#!IhprIhp
+rIi#!J)#!J(prIhjrIhq!J(prJ)#!J)#!J)#!J)#!J)#!JB'!J)#!J)#!J)#!J)#
+!J)#!J)#!JB#!J)#!J)#"JB'"JB#!J(prIi#!J)#!J(prIhq!J)#!J)#!J)#!J)#
+!J)#!J(prIi#!J)#!J)#!J)#!J)'"JB#!J(prIi#!J)"rIhprIhprIi#!J)#!Ihp
+rIi#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIi#!J(p
+rIhprIhq!J)#!J)"rIhprJ)#!J(prIhprIi#!J)#!J(prIhprJ)#!J(prIhprIhq
+!J)#!J(prIhq!J)#!J)"rIhq!J)#!J)#!J)#!J)#!J)#!J)"rIi#!J)#!J)#!J)#
+!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprJ(prIhprIhprJ)#!J)#
+!IhprIhprIhprIhprIhprIi#!J)#!IhprIhprIhq!J)#!J)#!J)#!J)#!J(prIhp
+rIhprIi#!J)#!J)#!J)#!J)#!J)"rIhprJ)#!J)#!J)#!J)#!J)#!J)#!J(prIi#
+!J)#!J)#!J)#!J(q!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIi#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J!!!NLS!!3!"!!8!!!#J!!'!83!!!!!!&!!
+!!!!!!*)!9Zk,S`!!NIi!!*(r!$b!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhjqIAamHhTjH(GfG(0aF'pZE'YUD'CNBf&
+HA9YC9e988e&36Na+5%C&4%*!2cip2$`m1cSk16Nj16Sk1cXl1cXl2$dr3%""3N0
+%48C(5%P,6%e16e&699GC@PaHB'0PD'YYEh"bG(CiHRaqJ)+$KBL,MBk1N!#6PTH
+APTLFSUDRTU5PUDkaVkURU+keZlZhXDkbZm2'`lZcXEE!bp28cF#aTD1V[-hCfY(
+!V*U0KSbHZp[amr$Ud+f9NTDAPjD8MiZ(KSqSb0[FdXDmXULIPSq)JAafF@aRB9a
+A8Na(3Mik0c8d06Bj28&(6PGKDhH$N!#FUE6!bY6FjHc[lr$`lqlZlZhZlHlYl1h
+YlZlZlqr`m1rYkZINhp[Ae026eGEBfYcGiHEXmI6dm[$YkZMSkHVXl[$bp2AcmHr
+[lZlXk1,Gf0E6d-c*aX2![VZkZ,HeYE5dY,@eYEDfYVDeY,1aVUZSTD+HQTD5MSQ
+&J(aiGhGfGA9eGA9eGA9eGA4dFh*bFA"`EfpZEQeYE'aVDQPSCfCPBf*JAeeF@eT
+C9e9689&48%j*3d!q1cNi0cFh0cFh0cFh0cBf06-`,#JP)KmG'aSD'aXE'4F@&KJ
+E(L%L)4mH("`E("iK*#FT+LSV,6!c0MJj1MSl28"$4NK+5NP(4%*#3d9)5Na06%T
+&2MF`+5-H'aSF)#BX-MJm26dp2N"$48K,6P*@@f&QE'pbFh9fGhKiHAKhGA0cG(G
+mJ)5(LSZ,LiZ,LiZ,M)b,LBD#IhelI)#(MjQLUl1j[Er#aXh5d-c3fH$KhZ$Pj0I
+'Z,@iYkfGNSk2MBGrI(q'MC!!N!#,JA4UCQGXFRGmJBH0NTDCRD#MU,#mc0[PkZl
+`lq[NemDeUkLNQj!!LB@#IAKfFQYK9NT!1cT!5%e-4d)p0LiU+LXT*L3L(4-)!!!
+!!381'LJd284(5%K*58P+68j)2M8c1$p#3N&#4dj69PGBA@G`G'pQA&0,48*"38&
+"3$mq26dm1cSj1MXh-5SN)"`B'"JA%!F"!!3*$K8G)bBL'3m)#K8N-6Y$5e&58eC
+HC'GPBfCZHSD3!*HHT+UVTk'FQCQAP*+4NjHDQTbJSkLZXl@eYV[$b-V0dYMDep2
+3cp,9e066cF5jVkQRUDbYUk@IPj!!LSD'LBb2NC5BQCD2KS"lGR"ZEh4iHRTlI(a
+kGhClJSL*K(ekISL6RD@VVV#`X+qYTjk6LiL+MBq0LB5%L*'GTkkbYEQp`F,$`m6
+%a-'r[Vr&cYRPm2MqrrrrrrrrrrhflHAJh0M5cFR)bFR)amM,cp2@f0E2aVfjZEZ
+q[lkkXULGP)k+L)H)LBZ0N!#5P*HDR*ZCQCZIT+DPRjL3!)Q"HhGfGRGiGhCcEfP
+PC'9SDfaXDfecHS#$K)5$JAprJSD+MSq0LB@#JS5)MC!!Nj14MBU(KB5%K)1"Ihe
+kG@pSC'*LC@TbHS51QD'MS*U6M)H%Ji+$KBQ0NTHERTqIRTfCP*!!M)Q)LSk8QTk
+JRTL4LiD$IhTdDf&B8%K#2M`l1MSj1cj#5%e69eTGAf"IA&P86dY*5%T3@@9bI)1
+(LSU+LSQ'IR*M9%K!2$Xm1cJe-5mZ,5i[-63f16`r48a9B'YfIB"rHhGdFQjVD'9
+MBQ&KB@&KBQ0NC'4J@P49AQKTC'"IA&PDB'9PBf0NBeeA8P9C@P0*3Mp"5PKQEh"
+UB&C9BR@!Ji*rIRamHhTkHACcEfaTCQ0KAPYB9P014cmh-#`V,M%d0MFi16`r3dG
+-6e09@&YKDA&fGhC`CPaEB'4KAPYA99499PGB@&PEB'KcIB5&Ji1+P*fKSU@SUkZ
+UU+1CM)"fFR*hIi@,N!#6PCD@PC55N!#2MSk1Mj!!Mik,Ki0qH(4`EQe[G(f*PU'
+SUkQPSTkEQCQCQjbFQjQ@P*58PC@@PTD9PC56NC!!MSb,LiZ-MBk2Mj!!NC+6NBb
+$H'aNB'"JB@4RE(0qLjURX,5dXDkYVUq[VUbTTkDPTUHUV+k`X+q[VkkUTCk@Mif
+9S+LSSk#JSkHVVUkUSC1&IS+2RDHTSjQ-Ih4YC9jA9&CFC'PZFRGpJ)&rIAYkI(q
+$L)k9RDHb[XVBjHh`l12@bEkfXDqZX,1fZEHbUD'EQCQDPSf"GQpXD@TXER"[E'G
+KAPjLDR0mJiL+LB@"IAf$MjUHQT53!)k3!*'3!)Z'JRpmHA9aD9p@8P*9@f0`JC!
+!QjkBMAjbE'aZF'pVC&jD@9PGC'jkK)U-M)Z+L)L,N!#8P*'1LB@#JS+"IRamI(e
+pIS''Lj+BR*kGQjH4M)L*M)q1LiL$IRTlIi5'K)&qHhGaD@0HA9eHA9aB9%p06P*
+BAQ*MB&aB9909A'4RBeY@9PTKDR0mK)Q+Ki0qHA0YE("dGR9dGRTrJB'!JS5%J(a
+jGA*`FA9lJBH,MBb)JRYdEQTTDfjZF(H$MT16PTfNUUbXV+qfZVQfZ,l#`,bk[,f
+fU*U2KhpjH(YmH'pRCQYdIS5"H(*dHATjHi#%JhefEQCF8%G%5P"2580$4NT-69"
+@AQ4SDQjeISH5R+@TV+kZVDQLPif*LSZ'IACaDf9LA94+4%9+6Nj*36j$5NY$16F
+r58j+4dY@BQTYFACjGQpP@8`q-#3F&aJF)5BT,6-l4%a16Ne39ejLBQ0PD'PTD@T
+YFA9lJ)@+M)k2Miq2N!#6PT@3!)Z2Q++SUUZYXEHlZE1`YX64eY2*ZkqQSk1QUUb
+XUU@JQjQBQ*QCPjD6NBq2Mj!!N!#3!)q1MSq5PTUGRCbHT+QUUD@LRjZBPC56Nj+
+3!)k-LSL'K)1!IATiGR4aDPj44$dj-bSK'aSG)L8P*#3P+#SR(aB6&KXH(K`D'K`
+H)53T,cBl2$Sm38G)48!q26`f,5BQ,$%f1d&'5e*FCQeaFh4fI)51PjkJRCD2Ki"
+jGR9cE@0D999CB'PdJ)Q1MBZ-N!#4MSD!Ii&rHR4`FACrLT5CQTUDQCH@PC54MSZ
+*L)U0MBZ)KB+!IhjqJ)+$JhplGh9eGRGjHRYjG'pXE'jaFR"TAeC6@Q9ZG(KkGfp
+SC@KYF("VC&pIC'PYEh"eIB@,MT'9R+5TUUHKQjZJU+fYUD1HQjQBQCQBPT'+Jha
+fFR&bFh0bF'j[FR9kIi@-P*kUZFA,bX5qZlUiY,#ZVl'`V++9LS5'MCDISk5QV,+
+cVU+9LiL*M)k4N!#0LSU2Pk'TVDZRSk1QUUbVT*U0JRGZCf9XHikHUDfVSjQ3!)k
+3!*+8NBb&IRYlIRppHAChH(CYB9P@@&YHAeaEA@4[H(k"Ji5$JRpkG(*fIiU6PT5
+3!)k2NjHCQTbHRjfFQjbGRCbDPT!!KhecE'CNC'CVFA9hGhGiHRk#KSZ4PTUFRD'
+TYF((aVfaTU'LTkfcZEh"aFM+bXM'aFE%`EfmZVHeYVh&bm['`X2'aF'q`FI+b-+
+lXUfZXlDdVkbZY,h$aXE'aFE*cYIJj1,FeXl'[VLbVUbUUUfcYV5XTUDUX,Dl[lk
+lYlDfYE5bX,#bYEHhYlHeVU@GQCLBNB4fE@KSDh*mL*1ES+#FPC!!N!#5P*11L)&
+lHheqI(TlIi5*M)f1MBb+LBH%JAjkH(GhGR*[E@YVE'j`G(KlHhTjGh9dH(q%Jhp
+iF'TRCQGQC@*IA9YE@PG98e058%a&2ce!48P+5%9#26Jd-M)b-6!b06Sr3N9'3ci
+j0MBi1Ma!489"2$e'9@*XG(U!KBQ1P*LDQCQGTDfcYE@cVULLRTZFR*ZCPjZLTk5
+EN!#*KSH-NTQHRTL1KB#!JB&rHhPiHATjGhGiHhq$L*!!QD+RUDUVUU@HQ*DBR*q
+MTULSTU1JRTZCPBk%I(KhH(YqJ)"mGR*dGhGcDQ"C9eKHD(*iHRYmJBU9Rk5LQBq
+(KBD(KB"lGR0cGhq,Pk'TV+ZPR*'&HhCiJ)bAS+DSU+DKQjH8MiKqG@jTCQ*JB'4
+UER"aFR0eGhGfGhTrK)L+M)b,M)k6QCfGQjD4MBZ,M)q4Nj+4Mj'ARCkDNif*KS@
+'L)Z1NC16Nj@CS+HXVDZRT+1NTUHQSTfBNSf)KB*rI(PeFR"ZE'YVE'eXDfPQBPe
+A88a(2cF`,#NP)L)Q,M-a+#%J*bia,LNR,$3k2d&$3d*$48G)4dC%3N*$4NY28P0
+68e0899CA9eC99&966NC!2Mdl1$8e0cSj05mX,M3l3NC*6%j389"16%a28eKE@P9
+25%0"3dP39PTFAQ&ND@jdHS#$JRaeEQKNC@TbHi+(Lik4NT'1LS9rH(*XD'CPC'4
+NCQT[GRf%LBb1MBU'JS"pHA0UB&C14d%m1MNj1$Nj0c3[,5md16e!3NC-8PC98Ne
+-6%e-5NP+6%j48e*-4$Xc,bma0$8e-c!Y+LFM)L-Q+bmb06Sr4Na49&CBA&pI@e*
+)3$dq4%a6@&TD@9TGB@9UF(KrKBZ8RkUcZEl&cG,8dF[%Zl5ZUD5IR*UAN!#(I(0
+[F(4jHRGdFhClJ)"qHhPlI(TdDf0G@ejQFAb)NjZGQT53!*'9Qk'QUDZVUD5FNBH
+!IB#(M)b)K)1$K)5(MjQMU+HLRCZFS+'IQjH6MSL#I(YqJS4rGh"VDQa[FRCjHRY
+pJifCTUqcY,1cXl@eYE5bXDkVTk5KRjfEPBb$IAapIATfGAGmJB@'K)&qI(f"L)k
+6Q*bJSk1MSk+MSU#ENS9hDQ&GAQ&QD@PQB9jF@eYHC'ehJ)H,LSH"IAf#L)k3!)q
+0M)b0M)Q&JAjlHhk"KBH)KS"hEQTXFRGiGhCiHhq"KBZ8RkHXVUqaYELk[,l"`m6
+%`lqkYE#XUDLUVl5j[-,+dGEAdml*aX2![lr#aXV-bmM&aXR1cml+aF'pZV[!aX[
+-b-1r[X$#`EkjYVHpaFc2cFM"ZV1VSjfEQTQANj!!Miq4NT5AQjkJS*kEQ*@6NBq
+-LSH&K)*rI(PiH(TlI(eqJiZ6QCfJSCqCP*1@Qk#LTDLVVV#`VkbRSTqJSU1NTDH
+UV+bUTk@PTD@NSCfCP)q)J(PeF@eSC'*KAeeE@9KA@&TGBQCTDfpeIiZBSUQYVUf
+YVDfYV+QMRCL9PCDAR+1XXV+YTU'IRjkFPj+0L)5!IAakHAKiGhCfGRKkIApqHA&
+UC'*LB9pGA&aE@eaIC@TUD'CSEhU'NCQFQj@1KS"pHhTlHRTiGR*ZE'YVDQKRD'T
+YFRGlI(YiGA9fHAk%LSf3!*+8PjD6MSQ&JS"rIi#"JS@*MC'8PjUFRk5SVDqaXV1
+eYVDeY,1f[-60e0VIiZ,Jh0I5cFI!YUbMR*LAQ*bIS*qGQjQCR++SV+ZSTD1NTUL
+XX,Dm`FA(b-R+bXR&`,bl[EfjX+@GQTbJT+1HPiq+LBQ*KS1"JS1&KB1"IheqIRj
+lG'aNAeYC@9YKD'e`EfaSCQ9NC'0MC'GVE@eVDh"iJB@&JAYeFh0iIS@,Mj1AQjk
+KSU1PTUHSU+DLQj+)IhPeFh&[E@aZFACmJ)+$K)L-MSf)JAPcFR4iI(q!IRPdFA"
+bFh0`DQ*C8Nj,5NP)4dK,6e4CA9pIAPY@9&9FC@aYD@&F@epND'PUDfe[EfYPAPK
+98Na$1MFi28C4A'0NAeK589GICfaaGRTpIRprIRTdE@PSCfCNC'CQBPK03MXh0MJ
+k26p"3N%r26`m2$Xh-#NP*5FU,#i[-$!`-6-f1Mdr3N4&489&4NT39PaLCQY`G(9
+dFR&eI)1%IR9[FAGqIhTbDfKTDfYRAeC48PGJDA"cFR*dGhTmIAjrJS1#IA9XCQ4
+NBPjD9eC@9P988Np06&"AAfCTDQTXEh&aEfjXE'e`Fh9eFfjTC@*JA&9+26%S)Kd
+E'KXG(amI)LXe1MNd-$)i2d0$3%"$59"9@Q&TF(*`E@jdHi#"IRPdF'j`FhKmIi'
+#K)Q1N!#0Ki&kFfeSC'"G@9946Na,6%Y(36p"4NT,589#38&#3N4*8PYLD'abHAk
+"Ji1$J(elHAGfGA4bEfTPB&pIB'&KB&pG@eK99&GGC'PZFRCiHAPiH(TqJi@#HR0
+`FRCjHRf"L)b0LiQ*LSU*KS5#JiL4QU#KR*@1LSD$IRThGRKkI(jrJ)'"JB+#IhP
+`CejA8eCGCfjbFR&[E'KQCfTXEQpZE@j[FA*cFh0cFh0cGA9bE@GLAPeHA9K66Na
+,5dP(4N9'5%Y28eGDA&jKC'KXEQjYDQKRD'YZEfjXD@GNBQ&KBQ4PCfTYFA9iHhk
+!JB'$KSQ-N!#6PCHESUU`Y,1aXVDkZVHdXl@k[X#r[El#am[1cp(5dY$-b-E)bXc
+,alqhXE'jaG,GjHVXl1RMhYR9e065cmc+cG6Hk1rbm[$Vk1ISkqh`mI,alqcTjH$
+DeG,3cXl1c-M#ZUqPR*HARD@YXE'[VDUUV+k`Xl@fYE1`VDUSTU1KRjkHRk#IRCL
+9PCDAPjLCQjbEQ*11LSH'KSD%J(TbDQ4IA9aE@PG888j068e2894A@ejMD@jeIiU
+8Q*H8NC'6QCqQUUZST*qDPC'3!*18Nj!!MBb0MSk-LBQ-NC55MSZ+MBf+K)"rIhj
+lHi+2RDHXVV'dYV1URj@3!)q1M)L'L)f6QCbDPT'0LSH'Ji"pHRPiH(GiI)#%KiQ
+0NTDBPjLESDL[YEUmZV@`VDbYVDbXUkZTTkDSUUbYV+USTD5RVEM$c0$8f0cJiZ(
+Ihq$Liq(JiZETjq2Gf061b-'mZVQfXDUMR*1,KB5(LSZ*KS@'KiL'JRjlHRTmIi5
+*M)b+L)H'K)&qIAk!J)+&Lj1DRk'JR*L@PjZJSk@NSk1MT+5MSD#JRjqIRjkFQC@
+5N!#2N!#3!*'5Nj59PjQDR*bDQ*@5N!#0LBD$JAjmHhTkHRYqJiU3!*@APjH@PT@
+6MiL"H("UC@"GA&eHAPjIBfTZFA0fHi##JAajHRf!Ji*rIAYmIAepHhKfGA4dG(G
+lJBH0Mif'IRGbEQTTDQe`FR*`EQeXER&eHAaqJ)5)M*!!Nj@CRD#LSU'IQjH4LiD
+#IhYfF'PMB@0SER0hHAaqJB5(LBZ-MBb*K(eiG(&[EQp[EfjXDfPSCfGRCQ4MBf0
+KA&G88e4@@9eJB9jB8Nj-5dY08PKFA&C258C(58P(4%0%58j599TKCfPSC@*JB&p
+HA&YHB@0LAeY@88T$2MSh0MFl2d*%48C'4N9!2$Sl2Mmq1cSk1cj#4NY39PeMD@j
+aG(GkIS'#JAjpIS+%JhplH(CeFQeQAPG899TJCQPUCf0JA9eHB'0RDQPRBf"G@99
+468a,5NK'3d&!2d"#48T49eYFA9eGA9eFA9jKBf4MB&jE@PPEAQ0RCf4KB@*KAPT
+C@ejJAeT99&CDA&eGAQ*QD'GPC'4NC'*JAejHA9eF@eTD@eeJBQ&JAejHAPjHAQ"
+MCfTZFR9fGA0dGRTpIhjpHhKiHAf"KBQ-Miq2Mik2Miq4NC'1LiL'KB@'KSD&K)+
+!IAPhGA0`E'9I9e"+4N)q1$%V+#BP*5FV0$p0@@"LB@"LCQPSBeeB9P998e089eP
+C9eCA@PpMCfPXF(0fGhGeG(0cFh*`E@TTDQaZEQeVDQTXE@eXE'eYE@eVD@GNBPp
+G@eTD@eYE@9G@9ePEAPpKBfCSD@PUE@paFR0dGA9bEQaXF(9kIi1&Ji&qI(YjG@p
+SB&P888e*4N9(5Np8@9pND@jaFh*`EQjZF(*dH(b!Ji5$JAjlHRPjHAKhGR9eGRG
+hGR9fHAf"KSZ4PjbJSU+KRTU@NSq1MBb*KB"pI(k#KBH&JRjmHhf!KBZ5QU#LS*f
+BPC'1LBD%JS"mH(4bFR4hHRYmIi+&KB*pGh4bG(GlIAajGhGjHRPhGA4cF@eSC'0
+MBf*I@eG999KFB@P`Ghb!JS@(L)L(KSD*MBq2MBU*Lj!!Q*fIRTfGS++MSU'LTDZ
+`Y,DfYV@cXDkXV+faYVc#aXR)aF#kY+kVUUQRSjkEQjfJSD'LT+LVVUq`XE1hZVb
+mZVHcX+ZRSCZ@NT'5PCLDRU+PU+LRTD5LSD#IRk#IRCQ8Mib*KS@&KSL)L)L*LSU
+*LBU+L)*kFQj[FhPrJi5$JS'#Ji@(Lj!!PCLBPT14NC+8Q*fLTUUZYEc#b-c0bmI
+%`X#r[EZkZEUm[m6)bmc*aF#mZVZp`-,$a-E'`lbdVDQSUDUSSjfCQCkQVlDm[Vk
+p[,UhYE1eZ,c!a-R2dpIAe-r*`VZfXl+cXl1aX+k[XVHm[Vqq[Vr$amc5f0lKi0h
+CeG25dY(2bmM'aFA%`EfkZ,HhYlHiZEQjZlr'cG2@eG,-aX'r[lklYl1bY,Lm[lq
+q[,bm[,ZkYl5aVUZUUDLRTD+KSD5SUkfYV+UUUkbYVDbUUDLQSjf8Li@"IhajH(T
+qJiL-Mj'5Nj@BRD'NTD5JQj@2LB@"IhajH(PlI(epHhPiH(KjHRTlI(eqIRq#KSU
+0Miq2Mj'5NT+5Nj15N!#-L)5!HhCcF("`FA&aFA"aFR4jIS+'LBb1N!#3!*'3!)k
++KB&pHhPiGh4aE@PQBQ"HAPjHAPjHAf&NCQ9MB&eGA9pKC'CQCQ9QCQGRCQ4KB'"
+KC'KUE'aVDQPVEA"cGACfGhKkHhalHACbEfaUD'GQBf"G@ePA9949@&TE@PK@9&*
+58e49994589"26Nj38eKEAPpHAPpKC@acH(apIRq"K)U4PjfJSU5PTUDPSTkEQ*H
+@Nik(J(TfFh0dGhYpIRYiGA0cG(KqKBb3!)q-Ki+!IhjrJB1&KiD$J(akHRarJB+
+#JS+#JS"mGh&VC@"F@9K@99499eTFA9YA8e&48e056de1894A@9YGAf&KAeeF@eT
+C9P036%P(4dK,6e0@9eC68%e06e*@9e9468T+69&89&",4d0!26Sh06-a,bdX,#d
+a0$Fi0cFh16e#4dT-6%e39PjQER9lIi&qGh"UCfGTDQKPB9jGAf0SER4iHRTjH(K
+kHhalHRKeF@aSC'*KB&pHAPpJAejE9Np*4dP089488e*588p069"@@PeE@&0368T
+(484$38!r2Mip2$Xm2N"#4%9'4dP,5dT*5%K*58G$2$8Y*L%I(amI(4N@%a)3$J`
++#3J)#!N,$!m5&adN+c%e0cJk1cj"48Y5@9pNCQCMB&aC@&PD@9C35dK)58e49ea
+JB@&KBQCUEh0iI(q!IhajHATpIi#"JB'"JB1&L)Z0MSf-LiU+Ki*mGA&`FhGmJ)+
+%KSU2PCUHSUHXXE@iZELhY,'ZUkQRT+'GQCLBQjkIRjfBNik+Ki@$JB"rIi#!J(p
+pI(amI(amI(alHACeH(k'MT5BQjfIS++NTULTUDLRTkHPSTkFR*kKT+HTUUQTU+D
+MRTH4M)L&JAekH(GhH(TmIi1'KiH'K)+"JB+"J(jmHRKfFfpXDfa[Fh9eFh&aFA0
+fHRq&Lik2MSk1Miq2Mif-LSH#IAKeFh0cG(CjHhamHRTlIAq!J(pmHRGeG(9hHi'
+(MC+8PC56Nj18PCD@PT@8PCHCQTQAPC@@PTD8NT'4NC+8PjQCQ*D9P*15Mib*KiD
+'KSH(L)L,N!#ASDUcZVr#`m'q[,UiYV+ZUD5HPj+2Mj'9Q*UER*qLT+DRTU@LRjk
+ISkHXXEDjZVQfXUkVUUHNS*fDQTZEQjUBPT56NT'3!)q1MSb,LBL(L)Q-NC@CQCH
+9Nj19PjUEQjL6Mif-MSq2N!#2MBU'Ji1%KSL*LBQ(KiH(L)Q)KS@&KSH)L)H&Ji&
+rIRk!JB+#JS'!J)#"J(prJ)1(LSf0MT!!Nj@AQ*LCQjkMU+faY,DhZ,HfYE5cXV+
+bXDkTSTU5M)H%JApqJ)+'LBZ-MBk1Mj!!NC5AQTbEQTH@PC@9PCDAPjHAQ*QERU#
+MTDDSU+LSTU@MSCqHRCfHS++NT+5NTDDTUUZVUkbXUULNSCkGR*bISU5PSk#GQjb
+ISkHTTk5IQjQCQTbISD1NSk#EPT'3!*5DS+@SUDQTUl#i`-I,cFr2cmh*aF,"`F'
+rZlDbVUbTTD'GQTL8N!#0LSQ*LSb2NT15Mib*L)U0N!#8PTLBQ*H9PCDCR*fGRCf
+ISD1PTUHTUkf`XV5eYE@bVUUNRjZAPC56NT+8PjZGR*UAPC56Nj5@Qk#NTkLSU+L
+STkHRTU5IQC11LSQ*Lif2Miq2Mj'9QCqNU+bZVUUPRTQ9Nj+4NC+8PT@8Nj5BRU1
+RUkk`XE'bY,Ll[EfmZlZlZlZlZVLdXE#[VkfTT*f@N!#0M)f0MSf-LSQ(KiL(KB&
+lGR*[E@aXE'eYE@j[FA0cG(9hHhq#K)5#IhaiFfaPAPPA9PC88e"05NG&4NG+6P&
+99eKC@9KB@&PD@PPB9PCB@9PC@9TGB@0NBf&JB@*NC'0KAPYC9e956de-6%a-68e
+28%p15dT+5da05dK%36im1cNi0cBe06Bj1c`m1cXm2N&&5%Y-68e16e"69eaJBf4
+MBQ*MC'9PC'0LB@"HA&P@8e"26P"599KEA9jIAepIAPY@8%T'3d*#3N0%489&4%*
+"389,8PPIC'KVER&eHAf!JS&qHhGfGRChGhGhGhCeFh&[E@aVDQTXER"ZDQ4H@PK
+B@PYE@PG568K&4%C*69*@@&G66NT)5Nj69eKA9&&3890A@f"NCfGPBQ"IAepIB'&
+JA9K3580!3%*&4dG&3N"!38*&5%e6@&YE9e*15dT,5dY+58G&4%0&5%e48e068P"
+15dP(4dP-8&0999469&9@@&KC@9K@8Ne*4N9&4NG)58P)58T089088e&168j49&G
+A9eGA@&PDA9pKBQ0MC'4MB9pG@eK988j,5NP*5Ne39&GDA&eKCQaaFh4eGhTmHhP
+dEfYTD'PUE'paFh4dG(CjIB'$KSL+LSQ'K)1$JS"qHhPhGA4dGRKlIRprIRYiGR9
+fGA4cFh4hHReqIhprJB1'LSf0M)U)KiH(L)Q*LSU*L)H'KB@&K)1"IRTfFh*cGAG
+iGh9bFA&cGhb!K)D(KB5$K)D*M)q4P*@9P*!!MBZ*L)D%Ji5'LBb1NC19PjQEQjU
+BPjHAPjH@P*'1LiL'KB1!IAPeF'aUDQYXEQjYE'YUDfe`FhCjIS1+NTUKTULQSjq
+EQTQDR*kHRCQ8MBCrHhYpJ)1%K)1%K)@&Ji+!J)#"JS1#JAplH(CiI)##JS"mGR&
+`FA0fI)+)Lib-LB0mGh4`E'YZGAf&M*+8NSf(JhpmHhk"K)D)M*5ERjf@LRpjHAf
+"Ji1"Ii##KBL-N!#9Q*UDQTQBQTkNUUqeZVl![VZhXl'[Vl#aXE+bXl5fZ,c"amh
+4dp,1aVkfXDkXUkUTUUkcYlLdV+1DNiq0MC!!P*UKTDQUUDDKR*H9P*@BRkLbZm$
+"[VZjZ,Um[EfmZlbp[m$"`XA*c-[(`,DYTk1LSD'KSD'KRjbBNiq+KS1$KBL0P*Z
+NUl'f[-$%aXI(aXA$`F$"a-I+cFr3dG(3cml-bFM*bml4dpA@eG(*[lD[UkHMRjb
+DQjqNUDbXUkQQSk#GQTQES+DYXlLq`mR3eGRCeY(-bFM)b-I'amV0d0$1bF+lYE#
+YV+f[XE+cXV'ZV+ZYX,@iZVZm[EqrZl@ZU+@PTUHPSTfBNiq*JhjlIB''Lj!!NT5
+9PC13!)Z'JAajGR4fHS')MT'5NBk-LSQ*L)L)L)Q,MBq3!)q0L)*kFfjUD'CNBf*
+MC@KUEA"bFh0`E@aXER&eHAf!JS1#J(ejGR9fHRq&LSf2N!#4NC!!Mj!!NTDERU#
+IRTkIS*qFPSk'IRKeFh4fH(PiGA&ZER"cGA9dFR*bG(GlIAjpIAerJSD*LSU,M)q
+5PCQFRTqHRCbFRCqMTkZXUkUSU+LSTU1HQC@5NC+8PC53!)Z'Ji'"JB'"J)"rJB5
+)Liq6PTQER*bCPT+1M)b0MBf,LBL*Lik4Nj58P*@AQCZEQCH8Nj'3!)f+Ki5"IhY
+hF@aSC'&HA&K66NY*58K)4dG(5%P+58G&3Mmq2$Nf-c%b0$Bh1$Nm2N&#36mq2Mi
+p2$Si0cFi1$Fe0$8i1MXl2$`m2d4+8&*588p26e"38%p05dT*58Y28P068Np,5%9
+#38""3N4&4NG'4%%r26j!4%K08PCCA'&QEA&cFR&aFR0cEfTPB@"JBQ4QD@YZF(0
+eGhPjH(GeFh0cGA9eFh"[EQpaFR*bFA&aFA"[F(&bG(4cFh0cFh0aF'pZEfp[F("
+aFR0dG(0aEQYUD'CPC'CRD@TUDQTUCf0H@&968e4@9P946NY,69"699956dY+5Ne
+49&998e"16P"69eTFA9eHBQGXF(&bFA*bG(9hHAYlHhKfFh*bFh9fGhPlIS'&L)U
+-MBk3!*+8PTHCQTUCPT+2M)U)L)D$IAGaE'KPB9jE@&C688j06%j59eeLC'*I@eP
+DAQ4SDQPRC@4NBf*KAeeC8dj*4dG)5%G%3N!r380%4%0%4NP,6P&8@9aHAPeF@PK
+@88a'36dk1$Fh1$Sm2$Xj0#mV+LSY,c%b-c-d0MJi0cBd0$8i2%"%5%a28P4A@Pj
+LC@CMA9G468a18&*899KEAQ"LBf0MC'9QCQGTDfpcGhPkHRKhGRKjHhYlHRKiH(K
+kHhepHhTiGhGiHRf!Ji5$JS+#JS5&KiL(KS5#JS1&KSH(KiH*M*'@R++RV+qaXE#
+XTk'EPBq+KiD'KB1"J(pqIAYjH(KiHAKhGA4eGA0aEfpaG(ChGh9eGhTqJSD*LSU
+,MT1AQCQDQjfFQTH9Nj+4Mif-M)k3!*'4NC+8PjLBPC'1LiH#IAapJB5&Ji'#KBU
+4PjQBPT58PCD@PT@@QCkLSk1IQjH8NT+8QD#QUDHMRjfHRjqGQjQCQ*LBQ*H9NSk
+,L)D'KB@'KSD'KSD(LBb2NC'2MSq5PTZJT+QZXV@fYVDiZVh!`,fiXUfXVE+fZlr
+#aXM,c-h0cFl2cX[%ZV#SSU'LTDQVUkQRTkQYXlV"b-r6e024cFR'a-2"[VbjZ,Q
+l[Vqr[,HaUU5IRCfIT+Q[Y,Hk[,fpZlQiYV5aVDZTUDLSTkHRTU5LS+#KSk1LS*k
+HSUHZYEc#b-[-c-V*bFR*amA"[ELdVUHIPj14NT+4Mik2NTHFS+1PU+Z[XV1aVUU
+QSTkDPC+3!*'6PCD6MBD!IRk#L)q8PjH@P*16P*DBQTbIS+#FPT!!LiL)L)Q+LSU
+*LSb1NC@CRD'PTkQTU+DNSk'KRjfEQ*D@PjLCQ*52LB5$Ji@*M)k1LiH"IATkHhq
+%LBk5P*56Nj+5NC'6PCHBQ*H9NT!!MBb,LSZ-M)Z*KS1!IhjrJ)'$KBH)L)D&KSL
+-Mj!!N!#2Mj!!NT5AQCUBPC'1LiU,M)q5PTLCQCQCQjbGR*UAP*'1M)Q(KSD)Lj'
+@R+#MTUHSUUfaY,HiZELfY,'ZV+QRTU@PT+1LSU'LSkDTVDq`VUQNS*qKTDQYVkq
+YV+UTUDLRT*qCPC19Q*bISD'JSD'LSk5PT+1MT+DQTD'FPT+3!)q1MBU'JAemIAq
+"Ji@&KSD(L)L)KS@&KSL,MT!!NT5AQCUEQTQBPT53!)b)KiD%JRjjGA"YDQPUDQY
+UD'9LB@"KB@&JA9TA9PGA9eC@9eG@9P99@&eNE(*fGhGfGR9dFh"VC9j@8%Y)5%K
+)4N0!26Xm2N&%4dP,6%e-5dP*5Na16Na*4%!p26ir3%!r2Mdp26dp2N"$4NP-8&4
+B@9TC@&KB@&KB@&KB@&PC@ejKCQTYEh"`Efp`FA*dGA9eG(9fGhKjH(GdF@pZE@j
+`FR*aEQTQBf*MC@PXEQp`FA4iIB'$K)1#JB+%KiQ,LiQ'JAjkGh4aEfj[F(*cG(9
+eGRGhGR0YCPpC9&&15dK&3d*$48G+5da068a-6%Y+4d4#38""3dC)5de068e,58G
+%3N!r2MXi06)[,#JN)4iF'a`H)L8S+LSV,#ia0$8d-c%[,Li`0$P!4NY289*48%e
+*4N)r2$Sj1$Jf0$%Z,#`X,5mc1$j%58a28&"26dj068e168a-6%j49&GDA&eF@eT
+D@eeIB&pHA&YD@eaHB'&LBQ0MBf0MC'CRD'KSD@TVDfYVDQPSCfGSDQjcH(YpIRq
+!JB'"J(pqIAYkH(GfGA4cF'aSC&pE9eC999489&9A@&PEA9pLC@KUE'jaGAKmIS#
+!JB+$KSQ0N!#5P*@@PjLCQTUER*fHS+1QUDUVUDHNSU#IS+'LT+5NSk+JRTbER*b
+FQC++J(KcF'jZE@YUD'KTDfe[FA0eGhKiHATlIAjqI(ThGA0aF'pZE@aXDfYVDfY
+UD'KSDfe`FR0cF@pXD@KSD@YYF(0eGA4bF'p`FR0cF'jXE'jaGAPpJSD*LSZ,LSU
+*L)L(KS5"IRYjGhCfGhKjHAPjH(KiHAYmI(YiFfjUCQ0KB'&MCQGSD'PYFRPqJ)"
+rIhjmGh*YDQKSDfpcGRGhGRGjHhf!K)Z5QCfJSk@SUUUSTU5LS*qKTUfcYlQiYE+
+ZU+#CP*+9QU#NTkLSUDQUUkf[XE1eZ,c"amh4e0E9dmr,aX2![VZjYl@eYlUr`mM
+,cFl2d0,8eYIBfYlLjq[Zm2$[l1MMhYM6cml0cFc+am+mYV#XUDQTUDUVVV1k`FA
+)b-R+c-r4dG$2cmr4dY,3cFR&`VkkYl5cXl1dYEDfY,+[VDURTD@TVl@jZVZkZ,D
+cXDqYV+USTU5MT+@QTkDPSk+MT+5KR*@2M)f3!*5BQTbGRk#JRjkFQCD6N!#1MBb
++L)@#IhemI(apIRpqI(ThG(*`EfjZE@eYE@YUD'KSDQe`FhCjI(k!JB1%KB@$J(j
+mI(apIRepIRq"JS+"IhajGR*ZE'YVE'jZEQp`FA0eGRCbE@CKAPeHAf"KBQ0MBQ&
+KBfGXFRL!KiqARU5TV+k`X,#[V+QRTULTUDHMS*bDQCL@P*'1M)b-MBq3!*+8PTH
+APjD@PjLDQjbFR*bFR*bGRCfGRTqIS++PUDb[XE+cXl5cXE#ZV+USU+UYX,+bXE#
+[Vl#aXE'[V+LNS*kEQCLAQCZFRCbEQTZHSUDUVDqZV+LNSCkFQTLAPjD@PC@9PC@
+9PCDCRU1QTkDNSU#JS+'JRTZ@NSk-MBk1MBQ$IAPhGA0`E@YUDQPRC@0LBQ0PCfT
+XEh&bFR&aFA*dGRPlIAjpHRGcF'eVDQYZFR9hGR9eGACiHAYpIi'%KSQ,LiU)KB&
+rI(ThFfpVCf9MBQ"IAejHAPjHAPpIAejHAQ"KBf4NBf&JB@4SER0fGhGfGA4dFh*
+`Efj[F(&bFR*aEfeTCQ4MBf0MBf0LB&pGA9aD9e036Na*4dG+8&GEA9eF@eYE@PK
+@9&*489*89&456dY'3Mim16Fd-M!`-$%c0MNl1cXl2$dr384)5dj38&"48P058%e
++58T18PCC@eaIB@9SDfeZEQj[F(&aFR0dGACfG(&YDQGQC@4MB9pGA&aHB'*MBQ&
+IA&TB9PC@9eGB@&KB@&TGB'*KAPT988p38eGEA9pKC'GVE@j`FR9fGR4cFh9iHAG
+cEQPPBPpGA&aGA9eGB'4SDfaZEfp[Eh&fI)1*MT'5NBq1MSq1M)H"HR*UBPT66NY
+*4N)p1MNl28"#3N&!2Miq3%*&4dP-6e&58P&36dj068j499THB&pF@9968e4@9eK
+A9PC@9PKC@eaF@PG66de06Np38%p26dp48P*699GEAf*QD@a`FhChGR4cFR&bFR0
+cG(9fGRCfGA4cFR"ZDfGNBQ&MCQKSCf9LAPTB9PGDA@"LC'9RD@eaGhf$L)b1MBZ
++LSU,MBk2MSZ(Ji"qIi'$K)5%Ji&qHA9bFA&aF'jUCQ0KB&pIAf"LC'CPB9aA999
+AA'&PCfGRCQGSDfeZE@YTD'PXFAGmIi'!IRYjGh9dFQpYE'e[FhGlIAq!JS5'KiL
+)LSb4PTUGRCbER*kJS*kEQCLCQTUCQ*LCQCUCQCLAPT@4MBL%JS1'LSk4Nj58Nj1
+6NT'4NC'5NT+4NC19PjD4M)L(L)Z-M)U)KiL)Ki@$JS1&KiL(KS@'L)b3!*@DRU+
+PTkLSU+LTUDUUUUQSTkHRTkDPSk#GQjL@P*+3!)q3!*'5P*58Nj15Nj59PT@8NBq
+-LiZ0N!#5Nj+3!)k0MBb-LiZ-MBk2NC1@Q*QDQCHAQ*UGRk#MTUZ[Xl5dXl1cY,D
+iZVbq[m#r[lr!`X6(b-M(a-,![Vfp[Vr![lfjYE'ZVDfZVl+eZ,UlZlZlZlZm[Ek
+q[EZjYV@eYVHj[,kr[VUfXDfVUUZXVV#aXV+aX+kXUD@KRCUCQTfJSkDSUDQTTk@
+MS*fEQTUDQjbHRk'MTDHSU+LSU+QUV+fZVUkYVDbXUkUST+'IRTkJSU5QTkLSTk5
+JR*UERD#LSk+KSD+NTkZ[XV5eYE5bX+qZVUq`XV'`VDZSTkDNSU#GQjQCQTUEQjZ
+EQTUEQjZCPj@6NT!!Mif-M)Z+LBL'Ji"pHhTlIS'$Ji&rI(YlIAq#KBQ1NjLFRk#
+JRTZBPT@8PC@9P*14MSb+LBQ*LSZ0MSq2Miq2MSk2N!#6PCHAPT55N!#2MSf,LBQ
++MBq4NC!!MSf,LSL(KS@&KBD(L)L(KS@&K)5%K)5%K)5$Ji1%KBD(KiD&K)5&KSL
+*LSU+LSZ0MSq2MSf0MT!!NjHERU'NUDkbYVLjZEQiYlHhYVDeY,1aVkbSTD1LSk1
+LSD#JSU@RUUZXV+ZVUkURT+'HR*ZDPj11LBD&K)1"IRTfFh&aF'eSBPaC@9YHB@*
+KB'&MCQPVE'aYE@j[F("[EQeYE'YTCQ0JAPYC9e99999@9PC98e&36Na+4d4#3$m
+p2$Sj16Sm2N&#3N%r26`m26p"3N*#3N0&5%a38P*58P09@9YGA9aD9e988e489&4
+56dY(3cml1$Ji16Sk16Fe-c)b-M3f16e!4%C)58T-6P"699GC@PTD@9G@9eTGB'*
+KAeaD@9KA9eG@99048%p38P9B@ejIB'"JB'"IAPaE@eYE@PK98e&26%P&36dk16J
+i1$Fe-LmX+LNT+L`[-M3f16`r3dC*5da-6%e16e&58e9@@9aJC'KXF(4fGR4bF'p
+`FR0dFh*aF'pZE@aUD'CMB@"IAPeFA&aHAf&MC'4PC@9QCQGSDfjbGRTqJSD*M)k
+3!*'6PTQERCbCPC!!M)Q)KiD&Ji&qHhKeFR&aFA&[DfGNBQ&JB'"IAepHA&YD@PY
+FA9jHAPjGA&TB99*48&&48P089&9@9ePEA9pJAeeD@&GA@9YGAPpIAf"JB&pHA9a
+FA&jJBQ4PC'0LBQ0NCQPVE@jZEQeYEh&dGRKjHAGeG(4fHAaqIRjqIAjrJ)+%KSH
+)LBQ)KS5#JB#!JB1%KB@#J(ekHRYpIi"rI(TiGhGhH(PkHhapIAepIRq!JB"rI(P
+hGR9fGRCfGA0aEfaTCfCRD'PUE'jbGhZ!JiD*LBL'K)*rI(PfG(0bFh0dGA9hHAb
+!KBL+LiZ*Ki5#JS1'L)Z1N!#4NT18PCHAQ*LDR*kKSU+LSD#IRTbDQ*D8NT'4NC1
+@QTfIS+'MSk1LRjfEQjbISU@PT+'IRCZER*bGRCkHS++NTUHRTUDQTkLTUUZXV+f
+[XE'`VkfXV+bYV+ZSTU1KRjkHRjqIRTfFRCkKSU+KRTZCQ*LCQTUCPj54MSb0MT'
+5Nj16P*DCRU+QU+QTUDUVVDk[X,'bY,DiZ,DcX+fVU+DMS*fFR*fHRjqHRCZDQCQ
+CQCQDQjbFQjbGRU#KSCqHR*ZEQjbFRCfHRTkHRCbFQjZFR*fHS+'LSk1LS*kGRCf
+HRTbCPT14NC1AQTbGRU#MTUUYVkq[VUfYVl#aXV1dXl+`VDZVUkZUTk+GQ*@8PCD
+AQ*UFRCqKSU1NT+5NSU'HR*UBPT54MSb+LBQ+Lib0Mj'6PTQERCkIS+#JS+#IRTb
+EQTUDQCLAQ*QERCqKSU+JRCU@NT!!Miq3!*'5P*@@PjLBPjD@PTHBQTbHS++MT+@
+PTD5LRjbCPjD@PTD9P*+3!)k-LSL&Ji+"J)"rIhjqJ)+%KB@$J(elHhaqJB@*MBq
+3!*!!Miq2MSf,LBH'KSH(L)L(KiD(KiL*LSU+LiZ-MBk1MBZ(JRjkGhCfGhKjHRT
+kHRTkHherJ)'#Ji1&KiL+LSU+LBQ*LBL'K)*rIAYlHhYmI(epIS##KBH*LiZ,LSU
++LSb0N!#6PTLERCfGR*bER*fGRTkIS++NTD@PSk#GQ*54MSb+LBL(KB5#JB"qI(T
+hGA4dG(9eGA9fGRCeGRGjI(k!J)#!J)'"Ji5&KiU-Mj+8P*55NC!!N!#3!)q1M)U
+*L)L)L)L(KS5"IRYiGhChHATlHhTjGh9bEfeVDQPSCfCPC'4NC@9RD@aZF("[E@Y
+UD@TVE'aXE'YVE'j`FhCiHATlHhapIAakHAPjHRYkH(CcFR"`F(&bFh4dFh&`Efj
+ZE@TSC'"G@PC88P&38&"36Ne-6P&9@f"NCfKRCQCPC@CRD@YYEQp`F("`F("aFhC
+iHRPiGA0aFA0hI)'&KSD%JS#!J)"rIAYiGA0bF'jVD'CQCQCRD@TVE'aXDfPSCQ9
+MBQ*KB@&KB@&LBQ*MBQ&IAPeFA9jJB'"IA9TA9&*48%p168Y)480#38&"3N4'58Y
+-68j26e"489&58e999P999&069&499PGB@9TD@eYGB'4SDfj[EfpYDfPRC@*I@eK
+@994688p168e06%Y*5%K*5Na16Nj068e-5NP)58e499PEA&eIBQ9SDfeZEQeVD@G
+QCQGTDQTTCf4KB'"LC'CSDQYVDQPRC@*IA&P@8e"05NK(4NC'4NC'4NC'4dG)58a
+28eGD@eYE@eeHB'*MBf4NC'4PCQGSD'KRCQ4LAeaC9P989&4999CA@9YIBfKXF(4
+fGRCeFh*`EfjYE@aUD'9LAejIB@4QCfKSD@TVE'j[FA4eGRCeFh&`Efp`FA*cFh4
+eGRGiHATlIAeqIAalHhapIRjpHRCcEfeVDQPSCf9LB&pIAepHA9YC@&KB@PjLCQP
+YF(0fHAYmI(apIi'%KiU0Mj'4NT+6Nj15NC!!N!#3!)q0LiL&JS"rIRemHhapIi'
+#K)@(LBb1N!#4N!#1M)Q'Ji&rIRjqIRprJ)#"JB+%KSU1NT@@PT@6NBq1MBb,LBD
+#IhepI(apIAerJB5(L)L(KSD(LSf2Mik-LSQ*Lik3!*'3!)k,LBH'KiQ+LiU)KS5
+#JS1&KiL*LSZ-MT!!NC+6Nj15N!#2MSk2NC+8P*58PCHDRU+NTUHSUkkbYEHjZEL
+iYlDfYVLk[F$"`F(!`-(#`m2#`,kq[m,&aXE%`F#r`F6(b-R*b-I(b-R*bFM)b-M
+*bXV,bmV*amA$`F$!`-$!`,qr[lqr[lflZ,@bXE'bXl1bX+kYV+fZX,+cY,@dY,1
+bXE'aXV1eYVLk[F(%aXE&a-'r[Vfq[Vqr[VblZVUl[,blZ,1ZUUHPSk+KS*kHRTk
+HRk#KSU+LSU+MT+@RUUbYVDbVUDHPSk+KSD'JS*qHRTfHRk#LSk1LRjZBPC16Nj+
+4N!#2MSf0MSk3!*+@QCbHRTkGR*ZDQ*H@PC15NC!!N!#2Mik1MSk2NC5@Q*UEQjZ
+FRCqKSU+LSD#IR*Q@Nj!!Mik2N!#4NC'3!)q3!*+@QTkLTDHRU+LTUkbXUULPSk'
+KSD'KSD#IRCbDQCQBQ*D6Mib+LSZ-MBk0M)b-MBq5PCHDQjZDQCLCQTZGRjqHRCZ
+CPjD9PC@AQCZGRTfFQTQBPjD9P*15NT+5NC'3!)q1M)U)KB*qHhKfGR9dFh&`EQa
+UD@PTD@YXE@j[F("aFR*cFh*bFR4fHAarJS@(L)Q*L)H'KB@&KSD'KB5%Ji+#JB#
+!J)'#K)@&KB5&KSL+M)b,L)D&KBD)LBU+LBL)LBZ0Mj'6PCHDR*kIRTbCPj55Mik
+-LSL'KB@'KiH(KS5#J(q!JB+$K)5%K)1#JB#!J)+$K)5#J(ajGA*`E@TRC'&IA9a
+E@PPB@&PEAQ*PCfGRCfCQC@9PCQ9PC'0LBQ*KB@"IA9eFA&aE@PK@99999PGA9PC
+99&*36dj06Np389*58P*48P*699GB@9TD@9PC@9PD@9KA9PCB@PYFA&aD@9KA9P9
+68P&38%p26Nj168e,5NP(4NC%3d&!2cip26dm2$Xj1$Fh1$Xq380$3d0#3N*#3N*
+!2M`k16Nj1M`q2d"!38&#3d0$3N&!2cmr2d""3N4&4NG)5%G(4NC(5%P+6%j389&
+46dj06%Y-69"69PKD@eaGA9aGA9jHAPeE@PKA9PCA@&TEA9pJBQ4PCfKTDQYXE'Y
+VDQPSD'KRCQ4MBf4PCQKSD'GPBQ"HA&TB9P988P*58e9B@ejKBf4PC'4NC'4NBf*
+KB'"IAPjHA9eGA9eHAQ"LC@KUDfYVDQTUDQYVDfYUDQPTD'KSD@PUDQTTCfCQCfK
+TDfaXE'aXE'eYEQjZEQp`FA*cGACiHRerJB5'LBb1N!#4N!#1LiQ)KS@%K)1$Ji+
+#JAppHRKfGRCfGhKiGhCfGRGjI(k!JB'!IhjqIRjqIi##K)@(LBU,M)f1MSk-LSH
+$IhelHRPiGA0aF'p`F(&aFA&aFA&aF'pZE'YTCf9NBf*JAeeFA&eHAf&LC'9QCfG
+SD@YYEh"bFh4eGRCfGRChHAYpIRjpI(YkHAKhGR9eGACfGR9eGAChH(PjHRYmIAp
+rJ(prIRepIAamI(alHRPiH(TpJSD+M)b,LBL)L)L)KS@#JB"rJ)#"Ji@(LBU+LSU
++Lik4Nj@9PC15NT16Nj+3!)k-LiZ-M)f-LiZ+LSU,Lib-MBk3!*1BRD'NTUDPTD5
+PTULUV+fYVDfYVDfYV+bXV+fZVkq`X,'bXl5dXl+bXV+dYEDfYV5cXV+bXl5eYVH
+iZVZlZlZlZlbm[Er"`m6%aFA%`m,![VZjZ,HiZEUm[Vr!`,qpZlQiYlLiZ,DdXDk
+VUDHQT+'HQTH8NT!!N!#3!*!!NC'5P*@AQCUER*bFR*bFR*bEQTQCQCUER*bDQCL
+APTD@PTHAQ*LBQ*LBPjHAPT@8Nj+4N!#1MSk2N!#5Nj56NT'3!)q1MSq3!*+8PjQ
+FRk'KSD#IRk'NU+b[XV5fYlHhYV@cX+bRSTfCPC+3!)k0M)Z,M)k2NT5AQTkKTDL
+UV+fYVDbXUkQSTkDPSk+KSD'MT+DRU+LTUUbYVl#aXE'`VUkZVl#aXV#ZUULQTUD
+SUDUTTk5KRTbFR*fGRTqJSU@SV+qbY,DiZEZp[m$![lflZELfYE1aVkfYVUq`XE'
+bXV'[VUfVUUQSTk@MSCkEPj54MSf0M)Z*L)D&KBD(LBZ-M)b-MBk2N!#5Nj58P*5
+8PCDAQ*QCQCQDQTZFR*bEQTQBPjD@PTD9P*+3!)k0M)U)KS5"IhjpI(YkHAKiGhG
+hGhGiH(KiGhGiHAYpIRq!JB'!IhelHRTkHhYmHhYkHRTlHhYkHAPiHATmIS'$K)@
+%K)5%KBH*LSb-MBf-LiU+LSU,M)f1MSk0LiQ)KiH)LBU,LSL'Ji+#K)D*M)f1MSf
+0MBf0M)b0MBk0LiQ(KB1#J(jmHACaE@TRC@4NC@9QCfKTDfaYEQj[Efp`FA0dGA9
+eGA9dFh&ZDQGNBf0MC'4NBf*KB@"KB@&KB@*LBQ*LBQ*LBQ*MBf4NC'4MBf0NC@C
+PC'&IAPjIB'*MBf*LB@*MC@KUE'eYDfTTD'GRCfCQC@9QCQGRD'KRCfGRCQ4MBQ&
+KB&pG@eK98Np-5NK(4N9&4NG)58T08&4B@PaFA&eHB'"KB@&LBf9QCfGQC@4MBQ"
+IA9YD@&G@9P9999998e&16%P(484#3$mp26`p2Miq26dp2N""3N0&4NG(4dG&3d%
+q2$Nh063c-M)d0MJl2N"$4%C(58Y-68e06%a-68j389*48%j-5dY-6%e-5dP)4dC
+&480"2cdm2$dq2Mp!3%&"3N*#3N*#3d0%48C'4N9&489&4NC(58a28PCDAQ&PD'T
+YER"`FA&aF@pZE'TSC@0KAejGA&aFAQ"LBf4PCQGRD'PTDQYXEQp`F(&aFA*cFh0
+aEfaUD@PTDfaZF(&bFR0dG(9fGR9dFR&aFA*dGRKjHAPhGA0aEfaTCf9NC'0KB&j
+GA9eHB'*MC@CQCfPUE'jaFh9hGhGfGR9fGhPlIAprJ(prIRjrIhprIRjqIRjrIhp
+rIRakH(CdFh*aFR*cG(9dFh"XD'4KAepIB'*MC'4MBf0NCQKVE@paFhCkIS+'LSb
+0MBf-LiU*L)H'K)1#JB"rIRepI(alHhTkHAPjHRTjHAKiHAPjH(GfGACfGRChH(P
+lIAq"Ji1$JAppI(YlHhYkHAKhGR4bFR*bFh4fGhTpJB5'L)U+LiZ,LSQ*L)Q+M)k
+2N!#4NC'3!*!!Mik0MBf0MSk1Miq3!*'6P*DAQ*QCQCQCQCQCQCUEQjUBPjD@PjH
+BQ*LBQCZGRTqJSU5RUUbZVkq`XV5fZ,QkZELfY,1bXE'aX+qYV+ZUUkbZX,#`Vkk
+XUkZVUkbXV+bXV+bZVl'bXV+aX+qZVUkYV+USTkHRU+QUUUQSU+LTUkk`XV5eYlQ
+l[X(%amV-cFl2cmr3d0(4dG(3d-r1cXh0cFc+amA$`F,$a-E'aF2![EUiYV@eYE5
+dY,1cXl5dXl+aVkfUUDQTUDQSTU5MSD#JRjqJSU5QU+UXVl'cYEDiZEQjZELfXl#
+YUUHNSCkEQCH8NT!!Mik2N!#5P*@@PjD8NSk+Ki5#J(jpIAeqJ)1&KSH(KiH)LBU
+-MBk1MSk1MBf0MBf-LiU+LiZ-MBk1MSk2N!#3!*'5Nj18P*15NC!!MSf-LiU*L)L
+)LBU-MBk1MBf-M)b-M)f0MSk1MSf-LiQ)KiD&Ji"pHRKfGRChHAYpIi#"JB+%KSQ
+0N!#5PCHDR*kJSD'KSU+MT+@PTD5MSk1NT+@PTD5NSk1MSk+LSk5PTUHRTkLSU+L
+SU+LTUUZYVUq[X,'aXV+aX,#[VUfVUDDNSk+LSk5NTD@PTUDQTUDPT++KRjbDPT1
+2LiH%JS'!J)'"JS1%KBD(L)Q+Lib0MBk0MBb-LiU+LSQ)Ki@%JS"rIRakH(9cFR*
+bFA"ZDQCMBQ*MC'9NBf*KBQ0PCfKTDQPTCfCNBQ"HA&TC9eC999489&489&499PG
+C@PYFA&eHB'&MC@9PC@4NC'CSDQaZEQjZE@jZEfp`FA*cG(4cFR&`F("aFR*cFh0
+dG(9eGA9fGhPlIS'%KSL+M)k3!*'5Nj+4Mik-LSL(KS@%Ji'!IhjqIAalH(4aE@Y
+UD@PTDQTUDQTUDfYXE@eXDQKPBf*KB@*NC@9QC@9NC'4PCfTYEh&cGAGjHheqIRj
+pI(PhFfpVCf0KAPaE@PKA990589"389&48P0899CA@&KC@9PC@9PD@PYFA9jIB@0
+PCfKTD'CNB9jF@eTC@&G@9&468P&36dj-5dT*5%K*58P+5da06Np38&"38&"48P4
+99PGB@&PC@PYFA9jIAf"KBQ0NC@4NBf0LB@&JAepIB'"JB&jF@eTD@eYE@eYD@9K
+A9eGB@9PD@9K@9&&05NG&3d&!2cmr3%&"38&"3N0%4NG)5Na28PCDA@"KBf9QD'P
+UDfe[FR0cFh0cFh0bFA"ZE@aVDfYUD@KQBf&HA9aFA&YE@PKA9eGB@9TE@eaGA9j
+HA9aD@9KB@&KC@PYE@eTC@9PEA@"MCfTZFA0eGRGiH(KiGhCdFh&`EfjYE'aXDfT
+UD@KSD@TVE'eYEQj[F(&bFA&`Efp[EQeVD@KQC@9PC@4NBf0MC'9QD@YZF(*dGRG
+jHhapIAepIAepIAjqIhq!J)"rIi#!JB+$Ji5%K)@'KiL+M)f0MBb,LSQ)KiD&K)1
+"J(jpI(YkHAKiH(PlI(eqIRjpIAamHRPfG(0bFR0dGRGjHRYmIAeqIi#"JS+$Ji1
+$K)5%Ji'!IRalHAKhGhGiHAYmIi'%KSL+Lib-M)Z+LSQ+LSb0N!#5PCLERD'NTkZ
+ZXE1eYlLiYl@cX+fUTD#EPT+2MSf1N!#5P*DCQjbGRTfGRTqJSU1NSk1LSD#JSD'
+KS+#IRjqIRjqIRTZBP*!!M)H%JAprIi#!IhjpHhYlI(k!Ji@(L)Q)KiD&K)1$K)@
+'KiL)L)H(KS@&KBD(L)L*LSb1N!#4NT'4N!#3!)q2Mj!!NC'4N!#1M)Q(KSD'KiL
++Lib0MSk2NC19PjQERCkJSD1PTkQVVV#dYlQl[,kr`F2&amM)amA#[lbkZVUl[,b
+mZlUjZEUl[Ekq[VfmZlZkZELhYE5bX+fVUDLRTU@MSU'KSU5QTkLTU+LSU+LSTk@
+MSCqHRCfFR*bGRCkIS+'LSk5NTD@PTULSUDQSU+DPSk+JRjfEQTLBPjH@PT@9PC@
+@PjLBQCLBQCQER*kJSD+MT+DRU+UVVDk[X,'aX+qYV+bVUkZXV+bVUkQTU+HRTU@
+NSU'JS+'LSk5PT+1JRTbEQjbHRk#IRjqISD1PTkHRTk@NT+@QTkLSTk@NSCqGQjL
+@P*'1LiL'K)1#JApmHACcFA"`FA*bFh0bF@pYDfKQC'0MBf4QD'TYEQpZEQeXE'Y
+VD@KRCfPUE@p`FA&bFR0eGhKkI(q!JS1%KSL*Lif1Mik1M)Z+LSU+LSQ*L)H'KB5
+#JAprIhjqIAakHAKhGhKjHherJB1&KSH)LSZ-MBf0MBf0MBk2Mj!!NC'5NT59PjL
+CQ*H9Nj!!MSb,LiU+LSU,LiZ,M)b-M)Z+Ki@#IhemHhamIAeqIi##KBL,MBq4Nj5
+9PTHAQ*HAPC55N!#1MBb-M)b0MBk2NC1@Q*UER*fGRCbEQCLAPjDAPjHBQ*QCQjb
+GRk#JSD+LSk1MSk1KRjbCPT13!)k-LiU*L)H&Ji+"J)#!IhpqIAepIRjqIRjpI(T
+iGhCeGA4cFR"YDQCMB&pHAf"KB@*LBQ&KB'"HA9aE@PPB9eC88P"05dP(4N9'4NG
+)5%P*58P*58K)4dG(4dG(4dG'489%4%0$3d*"3%!r2cip2$Xj0cBe0MFj1M`p2Mp
+!3N0%48G)5Na06Np28&&489&36de068e16Nj168e16e&699GB@9PB@&KB@&PD@ea
+GAQ"KBQ*MC'CRD@TXE'eYEQj[F(*cG(4dFh&`Efp[EQeXDfYUDQPTCfCNBQ"G@eP
+A99046Na*4d9$3N*$4%C(58T-68p38P0899C@9eKC@eaFA&YD@9G@99468e*488p
+16%Y+5NP+5NY,6%a-6%a06P"48P089&9999CA@&PD@PTC@9PC@PYHB'*NC@GSD@Y
+XE@eZEQjYE@aXE'aXE@jZEfpZEQjZEQp[F("`F("`EfjYE@eYEQp`FA*bFh0cG(9
+fH(TlI(epIAemHhTiGR9dG(4dG(0aEfaTCf9NBf4PCQGSD@PTD@PTD@PUDfe[FR9
+hHATkHRTkHRPjH(GfGA4cFA"ZE'YUD@PTD@TUDfaXE'aXDfTTD'KTD@TVDfaXDfY
+XE@pbGAKlIB##K)@'KiH(KiH'KS@&K)5%KB@&KB@&KB5%K)1$Ji5&KSL*LBU,M)f
+2NC18PCDAPjLBQ*H@PTDAQTfKT+DQTUDPTD@QTkQUUkUTTk@MSU'JRjkGR*ZDQCL
+@PC14Mif,LBH&Ji'!Ihq!JB1%KBD(KiH)LBZ1N!#6PCHCR*kKSk5PTD@NT+5NTDD
+SUDZXV+bVUUUTUDQTU+HQT+1LS+#JS+#JS*qIRTfFQjUBPj@8Nj+4NC'4NC'5P*@
+@PTD@PTHCQjqLTDLTUUUUUDQTU+LSTkHQTUDQTUDQTU@PT+5NSk1LSU'JRTfEQTL
+APjD@PjLCQTZER*fGRTqIS+'MT+@RU+LRTU@NSU'KS*qIRTkGRCbEQjZFRCkGR*Z
+EQTUDQTUCQ*H9Nj!!Mif-M)b-M)f0MBk1Mj'5Nj@@PjQERU#MT+DRU+QUV+f[Vkq
+ZVUk[X,+dY,5dXl+aX,#[VUbTU+HRU+QUUUUTU+DPT++KS*qGR*ZDQCLAPC13!)k
+,L)D&K)1$K)D(LBZ0Mj'6P*@9PC@@PjQDQjZEQTLAPTD@PTD@PTD9PC@9PC@9PC5
+6NT'4NT19PTLCQTUDQTUDQTUDQTUDQCQBQ*LBQ*LBPjD9P*16NT+5NT+6P*59PjL
+CQTUCQ*HAPjHBQ*LCQCUEQjbFQjZEQjbGRU#LSk1LSCqHRCfGR*ZCPj55N!#2Miq
+2Mik1MBf0MBf0MBk1Miq2MSf-LiQ(KB1"J(jmHRKfG(0bFA"[EQjYE@eYE'aUD@G
+PBf*KB@&LBf0MBf*LBQ0PCQKUDfaYEQj[F(*cG(0cFR&aFR0fH(TlI(epIRq!J)'
+"JB'"J)#!J)#!IhprIRjpIAamI(aqJ)+%KBD(L)L*LSU,LSU*L)D'KSD'KSD'KS@
+%Ji&rIRepIAemHhPhGR4dG(9fGhKiHAPjHAPiH(KiGhCdF@jVCf0JAPaE@PPB9eC
+@99468P*58e499PKC@PYFA9jIB@*MC'9RD'TVE'eYE@aXDQPSCfCQCQCQC@4MBf0
+MBf*LBQ&KBQ*MC'9QD'PUDfYVDfYVE'j`FR4fGhKiHATmIAjqIhpqIRjpIAamHhT
+jH(GhGhKjHRYlI(amHhYjH(CdFR&[E@YTCf4KAeaE@PTEA&jIB'"JB'&KB@*MBf0
+MBf0LB&eD9P*25dP'3d!q2$Xl1MSj0cBe068f0cJk2$dq2d&#3d4'4dG(4N4$3d0
+%48G)58Y,6%a-6%Y,5dY-68j389&58e9@9eKD@eaHAf"JB@*LBQ&JAepHAf"KBQ0
+NC'9RD@YYEh"aFR0dGAChH(KiGhCeFh&[EQaXDfTTD'GQC@4MBf*LBQ*LBf9RD@Y
+YEQp[F(&bFR0cFh0bFA"[EQeXE'YUD@KQC@9PC@9PCQGSD@TVE@j[F(&bFh0cFh0
+dG(9eGA9dFh*aFA&bFR0cFh*bFR0eH(TpIi#"JS1%KBH)LBU*L)D&Ji+"JB'!Ihj
+pI(YkHRTkHRPjHAPkHhamIAepIRjqIRepI(YjGhCeG(4dGA9eGAChGhKjHATjHAP
+jHRTlHhYkHAPiH(KiHATkHRTjHAKiH(KiHATlHhYlHRTkHAPjHATkHhaqIhq!J)#
+"JB+%KBD'KSD'KiH)LBU,LiU)KS@%Ji1%KBD(L)L)L)L)L)L*LiZ-MBf1Mj'6P*D
+BQCUEQjZEQjZER*bGRCfGR*ZDQCH@PC56Nj16Nj15NC!!Mik-LiU*L)L)L)Q*LBQ
+*LSU,Lib-MBk3!*'5P*@@PTHAPjH@PTD@PC@9PC@9PC58P*59PCD@PC56NT'4NC'
+3!*!!Mik0M)b-MBk1Mj!!N!#3!*'4NC'4NC'3!*!!Mik0LiU*L)L(KiD&KB@'KiL
++M)f1Miq1MBf-M)f1Mj'5Nj59PTHBQ*LAPjD9P*58P*58P*58P*58P*58PC@AQ*Q
+CQCLAPC15N!#2Mj!!N!#4NC!!Mik-LiU+Lib0Mj!!NC+5P*@AQ*UFRCfGRTqJSU5
+PTUDPT+5NT+5PTUHSU+HPSk'JRjqIS+#KSD'LSk5QU+UXVDq`X,'bXl5eYVDfYE5
+cXV'`X+qZVUfYV+bXVDf[X,'aXV1cXl1cXl1cXl+bXV+bXl1cXV+aVkkXUULQTD5
+NT+5MSk1MSk5PTD@QTUDQTUDQTU@NSk'JRjqHRTkGR*ZDQ*D9P*58P*58P*58Nj1
+6NT+5NC+5NT16Nj59PjLDQjZEQjUCQCLAPT@8P*59PC@9PC55N!#1MBf0MSq3!*+
+6P*@9PC58P*15NC!!Mif-M)Z,LiZ,M)b-LiZ+LSQ*LSU,M)b-MBb-MBf0MSk2Miq
+2MSk0M)Z+LSQ*L)L(KSD'KiH(L)H(KS@&KB@'KSD&K)1#JB#!J)"rIhpqIRjrIi#
+!J)#!IhjpHhYkHRYmIAjrIhprIAalHhYlI(YlHRPjH(KiH(GfGA4dG(4dG(4dG(4
+dG(4dG(4dFh0bFA"[EQeXDfTTD'GQCQCQCQGRCfCPC@9PC@CQCQCRD'PVE@paFR*
+cFh4eGhKjHRTjH(GfGA0bF@pZE@aXDfTTD'GRCfGRCfKSD'PTDQYXE'eZEQp[Efj
+XDfTTD@PTD@KSCfCPC'0MBQ*KB@&KB@&LBQ0MC'4MBQ&HA&YC9eC88e&38&"38P0
+8999@9PGB@9TFAQ"KBQ*MBf4PCQGRCfGRCQCQCQCRD'PTD@KSCfCQCQCQC@9NC'*
+KAejGA&eHAf&LBQ*LBQ&KB@&KB@&KB@"JB&pIAepIB'"JB'&KBQ0PCQGSD'PTD@P
+TD'KSCfCQCQCQCQCPC@4LB@"IAPpIB'&LBf0MBQ*MBf4QCfKTDQTTD@KQC@4MBQ*
+LB@&KB'&KBQ*MBf4NC'9QCfKTDQTUDQTUDQTUDQTTD'GQC@4MBQ&JB&pIAepIB'&
+LBf0MC'4MBf4NCQGSD@PSCfGQCQGSD'PUDQYVDfYXE'eYE@aXE@eZEQjYE'TTD'G
+RCfGRCfCQCQCQCQ9PC'4MC'4NC@9PC@CQCQ9PC'0LBQ*LBQ*MBf0NC'4NC'4MBf0
+MC'4PC@9QC@9QCfKUE'paFh4eGRCfGRGhGhGiH(KiGhCeG(*aF("`F("`EfjYE'Y
+VDQTUDQPSCQ9PCQKUE'pbG(GjHhk!JS1%Ji1#JB#!JB'"JB"rIRepI(apI(amHhT
+kHAPjHAPiH(KiH(KiH(PjHATkHhYlHRTkHRTlI(erJ)'#Ji5&KSH)LSf2NC18P*5
+8PC@9PC@9PC@@PTDAPjD@PjLCQTZFR*bFR*fIS+'KSD#IRjkHRCfFQjUBPT55NC!
+!Miq2Miq2Miq3!*!!NC'6P*@AQCZGRk'LSk1MSk+KS*qGQjUBPjH@PC@8NT'3!)k
+0MBf0MSq2N!#3!*!!Miq2N!#3!*!!N!#3!*'4NC'5NT16P*59PTD@PT@9PCD@PjL
+CQTUDQTZFR*fHRTqJSD'LSU+LSU+LSU'KSD#IRjkGR*UCQ*H@PC@9PC@@PTH@PT@
+9P*16P*58PC58Nj16Nj58PC@9PC@9PCD@PjLBQCQDQjbGRTqJSD#JRjkGR*ZDQTU
+CQCLAPjD@PTD@PjHBQCUER*fGRCfFQTQAPT56Nj+4N!#2Mik1MSk2Miq2N!#3!*!
+!N!#2Mj!!N!#3!*'5Nj18P*16NT+6Nj58PC@9PC@8P*56NT'4N!#3!*!!N!#4Nj5
+9PTHAPjHBQ*QDQjZER*bGRCkHRTkIS+#KSU1MSk1MSk1NT+5MSk+LSCqGQjQ@PC1
+5NC!!MSb,LSQ*LSU,MBk2N!#4Nj59PTHBQ*LBPjHAPTD@PTD@PT@9PCD@PjQERCk
+JSD+MSk1MSk1MSk1NT+@PTUDQTD@PT+1MSU+KSD'KSU1MSk1MSU'JS*qHRCZDQCH
+9P*15NT18PTLDR*fISD1PTkQTUDHPSk'JRTfEQTLAPT56NT'4NC+6P*58P*15NC!
+!N!#2Mik0M)Z+L)D&K)5$Ji1$JS'!IhjpI(alHhYkHRPiGhCeGA9eGA9eGA9dFh0
+cFh*bFR&`EfjZEQj[Efp[Efp[F(&cG(ChH(PjHATlHhYlHhYlHhYlHRTjHAPjH(K
+iH(KjHRYpIRq!JB'!J(pqIRjpIAjqIRq!J)'"JS1$K)5%Ji1$Ji+"IhjmHRKfGA0
+bFR&aF(&aFR*cFh4eGACfGRGhH(PjHAPiH(GfGA9eGAChGhKjHATlI(amI(YlHha
+pIAepIAalHhYlHhYmI(apIRjrJ)#!J)#"JS+#JS'!J)#!J)#!IhpqIAamHhTjH(G
+eG(0bFA"`Efp[Efp[EfpZEQj[Efp[Efp[EQj[Eh"aFR*bFR*bFR0cG(4dFR"ZE'T
+TD'GQCQCPC@0LB&pGA9eGAPjGA&TB9P989&488e068P*58e068e068e068e*589&
+48P*68e058P*489&489&489&489&489*68e068P&36dp26dp26dp26e&59&GB@PY
+FA&jIB@*MC'4MBf*LB@"JAeeFA&aFA9eHA9aF@eYEA&eHAf&LC'CRD'PUE'eZEh&
+aFR0dGAGiH(KiGhGfGRCfGRCfGRCfGRCfGA9eGA4cFh&`EfjYE'aXE'YUD@KRCfG
+RCfGQC@9NBf0MBQ*KB&pHAPeFA&aFA9eGA9eGA9eGAPpJB@&KB&pHA9eGAPpJB@&
+LBQ0MC'9QCQCQCQCQC@9QCQGRD'KRCfCPC@9PCQGRCfGRCfGRD'KSD'KRCfCQC@9
+PC@9QCQGRCfGRCfKSD'PTD@KRCQ9MBQ"HA9aE@PTC@9PD@eaGAPpJB@&LBf4PCQG
+SD'KSD'KRCfKSD@TVE'j[F(&bFh0cFh0bFR*aFA&aFA*bFh4eGRGjHRaqJ)'$KBD
+(L)L)L)H(KiH(L)L)L)L)L)L*LBQ*LBL(KiD&KB5%K)1$JS'"J)#!JB'"JS+#Ji1
+$JS+#JS1$K)@&KS@&KB@&KB@&KBD(KiL*LSZ,M)b-MBk2NC18PTHBQCUDQTUCQCQ
+BQ*LBPjHAPjLCQTbHRk#KSD'KSD#JRjkFQjQAPT@8Nj+4N!#2MSk0MBf1Mj!!NT1
+8PCDAPjHAQ*LBQ*QCQCLBQ*LAPjD9P*15NT+4NC'3!*!!N!#3!*'5Nj@AQCZGRk#
+LSk5PTUHSUDUVUkZUUUQSU+QTUDUUUDQSU+LSUDUUUkZXV+fZX,+cY,@fYE@dXV'
+[VUfXUkUSTk@MSD#HRCbFR*bGRCfGRCkHRjqJS*qJS+'KSU1MSU+KSD'KSU+LSD#
+IRTfEQjUDQTUER*fHRTqJS+'LSk5QTkQUUUZUUUQSTkDPT+1KRjfDQ*D9Nj'3!)k
+-LiU*LBQ*LSb0MT!!NC+5Nj58PCDBQCUER*bGRCfGR*bGRCfGRCfGR*fGRCkHRTk
+GR*bEQTUCQ*LAPT@9P*58PC58P*16Nj16P*59PC@9P*15NC'4NC'5NT16Nj59PTH
+BQ*LCQCQDQjZEQjUCQ*H@PT@8P*14N!#3!)q1MSf0MBf0MBf-M)b-M)b-M)b,LSL
+(KS@%Ji+"J(pqIAeqIRjrIhq!J)+$KBH*Lib0MSq3!*!!NC'4NC'3!*!!Mik0M)b
+,LSQ*L)Q*LSZ-MBk2Mj!!N!#4NC+5Nj@@PjHAPTD9P*15NT+4NC!!Mik0MBf1Mj!
+!N!#4N!#3!)q2Miq2N!#3!*!!N!#3!)q1MSf0M)b-M)f0MBk1MSk1MSk0M)Z,LSU
++LBQ)L)H'KB@%K)5&KSH)L)L)KiH'KSH(L)L)L)L(KiD&KB@%K)1#JB"rIhq!J)"
+rIhprIhprIhpqIRemHhTkHAKhGR9dG(4dFh0bFR*aFA&aFA&bFR*bFR0cFh0cG(4
+eGRGiH(PjH(KiGhCfGA4cFR&`F'pZE@aXE'aXE'YVDfTUD@KSCQ9PC'0MBf4NC'9
+QCQCQCQ9NBf*KB@&LBQ*LBQ*KB@*LBf4NC@9PC@CQCfGSD'KSCfCPC@9PC@9PC'4
+NBf0MBf0MBf*LBQ&KB&pHA9aFA&aGA9eHAPjHAf"KBQ0MBf0LB@"HA9aE@eYFA9j
+HAf"KBf9RD@TXE@jZEfp`F("`F(&aFA&aFA&`F'p[EfjZE@eYE'aVDfTUD@PTD'K
+RCfGRD'KTD@PTD@KRCQ9MBQ&KB'"JB'"JB'"JB&pIAepIAepIAepIAepIAepIAf"
+JB'&KBQ*LBQ*KB@&KBQ0MBf0MBf*LBf0PCQGSD@PTD@TUDQTUD@KQC@4NBf0MC'4
+MBf0MBf0NC'9QCQGSD'PTDQYXEQpaFh4fH(TlI(epIAemI(alHhTjH(GhGR9dFh*
+aF("`F("aFA&`EfpZE@YVDQPRCQ9NBf*LB@&KB@"JB'"JB'"JB@&KB'"JB&pIAep
+IAepJB'"JB@&LBf0MBf0MBf*LBQ*MBf0MBf0MBf0NC'9PC@9PCQCQCQCQCQ9PC@9
+PCQCRCfKRCfGQCQCQCfKTDQYXE'eZEh"`FA*bFh4dGA9eG(4dFh0bFR*bFR0dGAC
+iHATlIAk!JB1&KSH)L)Q*LBL)KiH(KiH(KiH(KSD'KiH(L)L*LSU,M)b-M)Z,LiZ
+,LiU+LBQ*LBQ+LiZ-LiZ,LiZ-MBf1Mj!!N!#3!*!!N!#2Miq1MBf0MBf-M)Z+LSU
++LSU,LiU+LSQ*L)L)L)L*LSZ-MBk2Mj!!N!#4NC'4NC'4NC'4N!#2MBb-M)f1Mj'
+5Nj@@Q*QDQjZFR*bFRCfGR*bFQjZDQCQCQCQCQCQCQ*LBPjD@PC56NT'3!*!!N!#
+3!)q2Mik1MBf-M)Z,LiZ,LSU+LBQ*L)L)L)L*LBU,Lib0MBk2Mj!!N!#4NC+5NT+
+5NC'4N!#3!*!!N!#3!*!!N!#3!*!!N!#3!*'4NT19PTHBQCQCQCQCQ*LBPjHAPjH
+APjHAPjLBQCQDQjZFR*fGRTqKSU1NTD@QTUDPTD@PTD@PTUDQTkHRU+LSTkHQTU@
+NT+1LSU'KS*qHRTfGRTkHRTfGRCbEQjZER*bGRTkIS+#JSD'KSU1NT+@PTD5NSk1
+LS*qHRCbEQjZEQTUDQTUDQTQBPjD9P*56Nj+5NC!!MSf-LiU*L)H(KiH(KiH'KSD
+(L)L*LBU+LiZ,M)b-MBf0MSk1MSk1MSk2Mj!!N!#4NC'3!*!!N!#3!*!!N!#3!*!
+!N!#3!*!!N!#3!*!!N!#3!*!!N!#3!*'4NC!!Miq1MBb-M)b0MBf0MBb,LiU+LSU
+,Lib-M)f0MBk1Miq3!*'5Nj18P*@9PC@9PC@8P*16Nj18P*58PC@8P*16NC!!Mif
+-LSQ*L)H'KB5#JB#!J)#!J)'"JB'"JB'#JS1%KB@'KiL*LBU,M)f2N!#4NT16Nj5
+8P*58Nj16NT'3!)q1MSf0MBf-M)b-M)f0MBk1Miq2Miq2MSf0M)Z+LBL)L)L*LBU
++LSQ*L)L)L)L(KiH'KS@&KB@&KBD'KS@&KB@%K)5%Ji1$Ji1#JS+#JB'!IhjpIAa
+mHhTjH(GfG(0cFR*aFA"`Efp[Eh"`FA*bFh0dGAChGhKiHAPjHAPjH(GhGRCeGA9
+eG(4dFh0cG(4eGA9eG(9eGA9eGA9eGA4dFh0bFR&aF'pZEQeZEQjZEQp[Eh"`FA*
+cGAChHAYmIRjrIhprIRjpIAalHhTjGhCeGA4cFh*bFA&`F("`F("`F("`F'p[EQe
+YE'aVDfYUDQPSCfCQC@9NC'4MBf*LBQ0MC'9QCfKTD@TUDfaYEQp[EQjYE'YVDQT
+UDQPTD'GRCQ9PC'4MB@"IAPeGA9eGA9eHAPjHA9eGA9eHAPpIAejGA9aFA&aGAPp
+JB@*LBQ*LB@&JB'"IAepIB'"JB'&KB@&JB'"IAepJB'"JB'&KBQ0NC@9QCQCQCQ9
+PC@9PC@4NBf0LB9pIAPjGA9eGA9aFA&aFA&aFA9eHAepJB@&KBQ*LBf0NC@CRCfK
+SD@PUDfaYEQj[Efp`F(&aFA&aFA&aFA*bFR&aF'p[EQjZEQeYE'aXE'aXE@eZEQp
+`F(&bFh0cG(4eGAChGhKiH(KjHAPkHRYlHhYlHhYmI(apIAepIAamI(amI(apIAa
+mI(YlHhYlI(apIRjrJ)'#JS1$Ji1$JS+#JB'"JS+#JB'"J)#"JB'"J(pqIAalHhY
+lHhTkHRTkHAPkHRTkHRPjHAKiGhCeGA4dFh0bFR*bFR*bFh4eGRGiH(KiH(KhGRC
+eFh0bFA"`F("`FA&aFR*cFh4dGA9eGA4dFh0cFh0cFh0dG(4eGACfGhKiHAPkHRP
+jHAPjHATkHRYlI(apIRjqIhprIhpqIRjqIRjpIAepIAepIAepIAjqJ)'#Ji5%KB@
+%K)5$Ji+"JB#!J(prIhprJ)#!JB'"JS+#JS+#JS+#JS+#JS+$K)@'KiL*LSU,M)f
+1Miq3!*!!N!#3!*!!N!#3!*!!N!#4NT+6P*@@PTHCQTZGRU#KSD+LSU+KSD'JS*q
+IRTkHRTkHRTfGRCfGRCkHRTkGRCfGRCfHRjqJSD'KSD'KS+#IRjqHRTkHRCfFQjZ
+DQTUDQTZER*bGRCfHRTkHRjqIRTkGRCbFR*bFQjZDQTQBQ*LBPjHAPjHAPjD@PC@
+9PC@@PTDAPjHAPjHBQ*LBQCQCQCQBQ*LBPjD@PT@@PjHBQ*QBQ*LBPjHAPjHAPTD
+@PC56Nj+4NC!!N!#3!*!!N!#3!)q2N!#3!*'5Nj16P*58PCD@PjHAPjD9P*56Nj+
+5NT+5NT+5Nj18P*@@PTHAPjD@PC@9PC@9P*58Nj16Nj15NT+4N!#2MSk0MBf0MBk
+1Miq3!*!!NC+6Nj59PC@9PC@@PTD@PC@9P*56Nj16Nj16Nj16Nj16NT+4N!#2MSk
+0M)Z,LSU+LSZ,Lib0MBk1Miq2Miq2Mik1MBf-M)b-LiZ+LSQ*LBQ+LSQ*LBL)LBQ
++LSU,LiZ,M)b0MBk2N!#3!*!!Mik0M)Z+LBL(KSD&K)1$JS+#JB'!J)'"JB+#JS+
+#JS+#JS+#JS'"J)#!J)'"JB'!J)#!J)'"JS+#JS1$Ji1$JS+"J(pqIAalHRPjH(G
+hGhCfGR9eGACfGhGiHAPkHRYmI(eqIhq!JB+#JS1$Ji1$Ji1$JS+#JB'"J)#!J(p
+rIhjqIRepIAamHhYlI(apIAeqIRjqIRprJ)#!J)"rIRemHRTjH(GhGR9eG(4dGA9
+eGRCfGR9eGA4dFh0cFR*aF'pZEQeYE'aVDfYVDfYVDfYVDfYVDfTTD@KSD'KSD@P
+UDfaYE@jZEQeYE@eZEQp`FA*cG(ChH(PkHhamI(amI(amI(amHhYkHAPiGhCeG(0
+cFR*bFh0dG(4eGA9eGA9fGRCfGR9eG(4cFh0cFh4dGA9eGA9eGA9fGhKjHAPjHAK
+iGhCfGA4cFR&`F'p[Efp[EQjYE@aXDfYUDQTTD@KSCfCQC@9PC@4NBf0LBQ*KB@&
+JB&pHAPeGA9eGA9jHAf"KB@&LBQ*LBQ0MC'4NC'4NC'4MBf*LBQ*LBf4PCQGRCfG
+RCfGRCfKTD@TUDQTUDQYVDfaXE'aVDfYVDfYVDfaXE'aYE@jZEh"`FA*bFh0dG(9
+eGA9eGRCfGRCfGA9eGA9eGA4dG(4dFh0cFh0cG(4cFh0bFA"[EfjYE@eYE@eYEQj
+ZEQjZEQjZEQp[EQjZEQj[Eh"`F("[Efp[Eh"`FA*bFR*bFR&aFA&aFA"`F("`FA*
+cG(9fGhKiHATlI(epIRq!J)#"J)"rIhjpI(YlHhYmI(eqIi#!JB+#Ji1$Ji1$Ji1
+$Ji+#JB'!IhprIhprIhpqIRjqIRjqIRepIAamI(amI(apIAepIRjqIRprIhq!J)"
+rIhjqIAamHhYkHRTjHAPjHRTlHheqIi'#Ji5&KSD'KiD'KS@%K)1$JS+"J(pqIAa
+mI(YlHhYmI(epIRjqIhprIhq!J)#!J(prIhq!J)'#Ji5%KB@'KSD(KiH(L)L*LBU
+,M)b0MSk2Miq3!*!!N!#3!*!!Miq1MSf-M)Z,LiZ,M)b0MBk1MSk1MSk2N!#4NT1
+8PCD@PTH@PT@9P*16NT'4N!#2MSb,LBH'K)1#JB#!J)#!J)'"JS+#Ji1$K)5%K)5
+%K)5&KBD'KSH(KiH(KSD&KB@&K)5&KB@'KSH)LBQ+LiZ-M)b0M)b-LiU*LBL)KiH
+(KSD'KSD(L)Q+LSZ,LiZ-M)f1Miq3!*'4NC'4NC'4NT+6P*@9PTHAPjH@PT@9P*1
+6Nj+5NT+5NT16P*@9PTD@PjHAQ*LBQ*HAPjD9P*15NT'4NC'5NT+5NT+5NT+5Nj1
+8P*59PC@9PC@9PC@9PC@9P*58P*56Nj16Nj58P*58P*58P*56Nj15NT+5NT+5Nj1
+6Nj16P*@9PTHBQCUER*bGRTqIS+'KSD#JS*qIRTkGR*bEQTQCQ*H@PC56NT'4N!#
+3!)q2MSf-M)b-M)f0MSk2Miq3!*!!N!#3!)q2MSf-LiU*LBL(KiH'KSD'KSD'KSH
+(KiH(KiH'KSD'KSD'KS@&K)5$Ji1#JS'"J)"rIhprJ)#"JS1%K)@&KB@&KB@%K)1
+#JB"rIhprIhprIi#!J)#!JB'"JS+$K)5%K)1$Ji1$Ji1$Ji1#JS+#JS+#JS1$Ji1
+$Ji1$K)5&KB@&KB@&KB5%K)1$JS+#Ji5%KBD(L)L)L)Q*LSZ-M)f0MSk1MSf0MBb
+-LiZ+LSQ*L)L)L)L(KiH(KSD'KSH(KiH(L)L)L)Q*L)L)KiD&K)5$JS+"J(pqIAe
+qIRprJ)'"JS1%K)@&KB@&K)1$JS'"JB#!J(prIhpqIRjqIRjqIRjqIRprIhq!J)#
+"JB'"JB'!J(prIhprIhjpIAalHRPiGR9dFR&aF("`F("`F("aFA&aFR*cG(4eGRC
+fGRCfGA9dFh*aF'pZEQeYE@aXE'aXDfYVE'aXE'aYE@eYE@eXE'aVDfTUD@KSCfG
+RCfGRCfGQC@9NC'4PC@CQCQGRCfKSD'PTDQYXE'eZEQp[F("aFA&bFR*cFh0cFh0
+bFR&aF("[F("`F(&aFA&aFA&bFR0dG(9eGRCfGRCfGhKiHAPkHRPjHAKiGhGfGRC
+eGA9eGA9eGA4dG(0cFh0bFR*bFR*cFh0cFh0cG(4cFh0cFR*aFA"[EfjYE'YUDQP
+SD'GRCfKSD'PTD@TUD@PTD'GRCQ9PC@9PC'4NC'4PC@CQCfGSD'PTDQTUDQTTD@P
+SD'KSD'GRCfCQCQ9PC'0MBQ*LBQ*LBQ*LBQ*LBf0NC@9QCfKTDQYXE@eZEQp[F(&
+aFR*bFR&aF'pZEQeYE@eYE'aXDfYUDQPTD@PSD'KSD'KSD'GRCfGRCfGRCfKSD'K
+TD@PTDQTUDQTUDQPTD@PTDQTUDfYXE'eZEQj[Efp`F(&aFR*cG(4eGACfGRChGhG
+iH(PjHATkHRPjHAKiGhGhGhKiH(PjHATkHhYlHhamI(amHhYlHhYlHhYmI(amIAe
+qIhq!J)'"JB'"JS+#Ji1$Ji1%K)5&KB@'KSD'KSH(KiD'KB@%K)5%K)5%K)5&KBD
+(KiL*LBQ*LSU+LSU*LBQ)L)H(KiH(KiD'KSD(KiL)LBQ*LSU+LBQ*LBQ*L)L(KiD
+'KB@%K)5%K)5%K)@&KB@&KSD'KSD'KS@&KBD'KSH(KiH)L)Q+Lib-M)b-LiZ,LSU
++LSU+LSU+LSU+LSU+LiZ,LiZ,LiZ,LiZ,LiZ,LiZ,LiZ,M)b0MBf1MSk2Mj!!N!#
+3!*'4NC+5Nj16P*58PC@9PC@9PC@@PTD@PTD@PjHAPjHAPjHAPTD9PC56Nj15Nj1
+6Nj16Nj16Nj16P*58P*@9PC@9PC58P*58Nj15NT+4NC'4NC+5NT+5NT+5NT16Nj1
+6Nj18P*59PC@9PC@9PC@9PC58P*16NT+4NC!!N!#3!)q3!*!!N!#3!*!!N!#3!*!
+!NC'4NT+5Nj16Nj58P*58PC@9PC@@PTDAPjHAQ*LAPjHAPjHAPTD@PC@9PCD@PjH
+AQ*LBQ*LAPjHAPTD@PTD9PC@9PC58P*58PC@8P*16NT'3!)q1MBb-LiU*L)H'KB5
+%Ji1#JS+#JS+#JS+$Ji5%K)5%K)5%Ji1$Ji1$Ji1$Ji1$K)5&KBD(L)Q*LSU,Lib
+0MBk1MSk1MSk1MBf0MBf0MBf0MBf0MBf0MBk1MSq2Mj!!N!#4NC'5NT+6NT+5NC'
+4NC!!N!#4NC'4NT+5NT+5NT+4NC'3!*!!N!#3!*!!N!#3!)q2Miq2Miq2Miq2MSk
+0MBb-M)b-LiZ,LSU*LBL)KiH'KSD'KSD'KiH(L)L*LBU,LiZ,M)Z,LiZ+LSU+LBQ
+)L)H'KB5$JB"rIRepI(YlHRPjH(KhGhGhGhGhGhGhGhGhGhGfGRChGhGhGhGhGhG
+hGhGfGRCfGA9eGA9dG(4dG(9eGA9eGA9eGA9eGA9dG(4cFh*bFR*bFR*cFh0dG(9
+eGACfGhKiH(KiH(GhGhCfGR9eGA4eGA9eGA9eG(4cFh0cFh0cFh0cFh4dG(9eGAC
+fGhKiHAPkHRTkHRTjHAKiGhGhGhGhGhGiH(KjHAPjHAPjHAPjHAPjHAKiH(KiH(K
+iH(KjHATkHRTkHRTkHRTkHRPjHAPjHAKiGhGfGR9eGA9eGA9dG(4dG(4dGA9eGA9
+eGA9eGA9eGA4dFh0bFR*aFA&aFA&aFA*bFR*bFR&aF'p[EQjYE@eYE'aXE'YVDfY
+VDfYXE'aXE'eYE@eYE@eYE'aXE'YVDfYVDQTTD'GRCQCPC@9PC@9QCQCRCfGSD'K
+SD'KSD'KSD'GRCfGQCQ9PC'4NBf4NC@9QCQGRCfKSD'PTD@TUDQTUDQTUDfYVDfY
+VDfYVDQTVDfYVE'aYEQp`F(&bFR0cFh0cFh0cFh0cFh0bFR*bFR*cFh0cG(4dGA9
+eGRChGhKjHATkHRTkHAPiH(KhGhCfGRCfGRCeGA9dG(4dG(4dG(0cFh0bFR*bFA&
+aF("`F(&aFA&aFA&bFR*cFh4dG(4cFh0dG(4dG(4dG(9eGAChGhKiHATlHhamI(e
+pIAepIAamHhYlHRTkHRTkHRTkHRTkHRYlHhYlHhamI(alHhYlHhTkHRPjHAKiH(K
+iH(KiGhGhGhCfGhGhGhGhGhGhGhGhGhKiH(PjHAPjH(KiH(KiH(KiH(KiH(KjHAP
+kHRTlHhapIAjrIi#!JB'"JB'#JS+$Ji1$Ji1%K)5%K)1$Ji5%K)@&KSD'KiH(KiH
+(KSD&KB@&KB@&KB@&KB@&KSD'KSD&KB5%K)1$Ji1$Ji1$Ji5%KBD(L)L*LBU+LSZ
+,LiZ,LiZ,LiZ,LiU+LSQ*LBQ)L)L)L)L)L)L(KiH(KiH(KiD'KSD&KB@&KBD'KiH
+(KiL)L)Q*LSZ,LiZ,LiZ,LiU+LSU+LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBU
++LiZ,Lib-M)b-M)b,LiU+LBQ)L)L)KiH(KiD(KiL)LBQ+LSZ,Lib-MBf1MSq2N!#
+3!*!!N!#3!*!!Miq2Miq2Miq2Mik1MSq2Mj!!N!#3!*!!N!#3!*!!N!#4NC'4NC'
+4NC!!N!#3!)q2Miq1MSk1MBf-M)b-M)b0MBk1Mj!!NC'5Nj58PC@9PC@9PC@9PC@
+@PTD@PTD@PTD@PTD@PjHAPjLBQCUDQTZER*bGRCfHRTkHRTkGRCfFR*bFR*bFR*b
+FR*ZEQjZDQTUCQCLBPjHAPTD@PT@9PC@9PC@9PC@@PTDAPjHBQ*LBQ*LBQ*HAPjH
+@PT@8P*15NT'4N!#3!*!!Miq2Mj!!N!#3!*!!NC'3!*!!N!#3!)q2Miq2Miq2Mik
+1MSf-M)Z,LiZ,LSU+LSQ*L)L)L)L(KiH(KSD'KS@&KB@&K)5%K)5$Ji1$Ji1$Ji1
+#JS+"JB'!J)#!J)#"JB'"JB'"JB'"JB#!J(prIhpqIRprIhprIi#!JB'#Ji1%K)5
+%K)5%Ji+#JB#!IhpqIRjqIRjqIRjqIRprIi#!J)#"JB'"JB#!IhprIRjqIRjqIRj
+qIRjqIRjrIhq!J)#"JB'#JS+#Ji1$K)5$Ji1#JS+"J)"rIhpqIRjqIRjqIRjrIhp
+rIhprIhprIhq!J)#!J)#!J)#!J(prIRjqIRjqIRjqIRjqIRjqIRjqIhprIRjqIAe
+mI(amHhYkHRPjHAKiH(GhGRCfGRCfGR9eGA9eGA9eG(4dFh0bFR&aFA&aFA&aFA*
+bFA&aFR*bFh0cG(4dFh0cFh0cFh0cFh0cFh0cFh0dG(4dG(4cFh0cFh0cFh0bFR*
+bFR*aFA&`F'p[EfjZEQeYE@aXE'YVDfYVDfYVDfYVDfYUDQTUDQTUDfYVDfaVDfY
+UDQTUD@PTDQTUDQYVDfaXE@eZEQp[F("`FA&aFA&aFA&`F("`F("`FA&aFA*bFR*
+bFR*bFR*bFR*bFR*bFR*bFR*bFR*bFh0cFh4dG(4cFh0cFh0dG(9eGRChGhKiHAT
+kHRTkHAPjH(KiGhGhGhCfGA9dG(4dG(9eGA9eGRChGhKiH(KiH(KhGhGhGRCfGA9
+dG(4dG(4dG(9eGAChGhKjHRTlI(apIAeqIRjqIAepIAamHhYkHRPiH(KiH(GhGhG
+fGRCfGRCfGRCfGR9eGA9eGA9eGA4dG(0cFh*bFR*bFR*aFA&aFA&aFA&aFA&aFA&
+bFR*bFh0dG(9eGA9eGA9eGA9eGA9dG(0cFR*bFA&aF("`F("aFA*bFh4dGA9fGRC
+hGhGhGhGhGhCfGA9eGA9eGRCfGRChGhGiH(KiH(KiH(KiHAPjHAPjHRTkHhamIAe
+qIRjrIhprJ)#!JB'"JB'"JB'#JS+$Ji1$K)5%K)5%K)5%K)5%K)5$Ji1$Ji1$Ji1
+$K)5%K)5&KB@&KB@&KB@&KB5%K)5%Ji1$Ji1$JS+#JS+$Ji1$K)5&KB@'KSD(KiH
+)L)L)L)L)L)L)L)L)L)L)KiH(KiH(KSD'KS@&KB@&KB@&KB@&KB@&KB@&KB@%K)5
+$Ji+#JS'"JB'"JB'"JB+$Ji5%K)5&KB@&KB@&KB@&KB5%K)1$Ji1$Ji5%Ji1$Ji1
+$JS1$Ji1%K)5&KB@'KSD(KiH(KSD'KSD'KS@&KB@&KB@&KB@&KSD'KiH)L)Q*LBU
++LSZ,LiZ,LiZ,M)b-MBf0MBk1MSk1MSk2Miq1MSk2Miq2Mj!!N!#3!*!!NC'4NT+
+5NT+5Nj+5NT'4NC!!N!#3!)q2Miq1MSk1MSk1Miq2Miq2Mj!!N!#3!*'4NC'4NC'
+4N!#3!*!!N!#3!)q2Miq1MSk1MBf0MBf-M)b-M)b0MBf0MBf0MBf0MSk1MSk1MSf
+0MBf0M)b-M)b-LiZ,LiZ,Lib-M)b0MBf1MSk1MSk1MBf0M)b,LiU+LSQ*LBQ)L)L
+)L)L)LBQ*LBU+LSU,Lib-M)f0MBf0M)b-M)b,LiZ,LiZ+LSU+LSU*LBQ*LBQ*LBQ
+)L)L)L)H(KSD&KB@&KB5%K)5%K)5%K)5%K)5%K)5%K)5%KB@&KB@'KSH(KiH)L)L
+(KiH'KSD'KB@&KB@&KB5%K)5%K)5%KB@&KB@'KSD'KSD'KS@&KB@%K)5$Ji1#JS'
+"JB'!J)#"JB'"JS+#Ji1%K)@&KBD'KS@&KB@&KB@&KB@&KB@&KB@'KS@&KB@'KSD
+'KSD'KiH(KiL)L)L)L)L)L)L)L)H(KiH(KSD'KSD'KSD'KB@&KB@&KB@&KB@&KB@
+%K)5$Ji+"JB#!IhpqIRjpIAemI(amI(amI(YlHhYlHhYlHhYmI(amHhYkHRTjHAP
+jHAKiGhGfGR9eGA4dFh0cFR*bFR*bFR0cFh0dG(9eGRCfGRCfGRCfGRChGhGhH(K
+iHAPjHAPjHAPiH(KiH(KiH(KiH(KiH(KiH(PjHAPjHAPjHAPjH(KhGhCfGRCfGRC
+hGhGhH(KiH(PjHAPjHAPjHRTkHhYmI(epIAepIRjqIAepI(YlHRPiH(KhGhGfGRC
+fGRGhGhKiH(KiH(KiH(KiGhGfGR9eG(4dG(0cFh0cG(4dGA9eGRCfGhGhGhGhGhC
+fGRCfGA9eG(4dG(4dG(4dG(4dG(4dFh0cFh0bFR*bFR*cFh0cFh4dG(4dGA9eGA9
+fGRCfGRCfGRCfGRCfGR9eGA9dG(4dG(4cFh0dG(4dG(4dFh0cFh*bFA&`F("`F("
+`F("`F("`FA&bFR*cFh0dG(4dG(4dFh0cFh0cFh0cFh0cFh0dG(4dG(4dG(0cFh0
+cFR*bFR*cFh0cFh0cFh0cG(4dG(9eGA9eGA9eGRCfGRCfGRGhGhGhH(KiH(KjHAP
+kHRTlHhYmI(amI(epIAepIAepIAemI(YlHRTkHAPjHAPjHAPkHRTkHRTkHRPjHAP
+iH(GhGRCfGRCfGRChGhGiH(KjHATkHhYmI(apIAeqIRjqIRjpIAepIAepI(amI(a
+lHhYlHhYkHRTkHRTkHRTkHRTkHRYlHhYlHhYmI(amI(YlHhTkHRPjHAPiH(KjHAP
+kHRYlI(amIAeqIRprIi#!J)#!J)#!JB'"JB+#JS+#JS+#JS+#JB'"JB'#JS+$Ji1
+%K)5%K)@&KBD'KSD'KSH(KiH(KiH(KiH(KiH(KiH(KSD'KSD'KSD'KSD'KSD(KiH
+(KiH(KiH(KiH(KiL)L)L)LBQ*LBQ+LSU,LiZ,LiZ+LSU+LBQ*LBL)L)L)L)L)LBQ
+*L)L)L)L)L)L)L)L*LBQ*LBU+LSU+LSU*LBQ*L)L)L)H(KiH(KiL)L)L)LBQ*LBQ
++LSU+LSU+LSQ*L)L(KiD'KS@'KSD'KSD(KiH(KiH(KiH(KiH)L)L)L)L(KiH(KiH
+(KiL)L)L)L)L)L)Q*LBU*LBQ)L)L(KiH'KSD'KSD'KSD'KS@&KB@&KB@%K)5%K)5
+%Ji1$Ji1%K)5&KB@'KSH(L)L)L)L)L)L)L)L)L)H(KiH(KiD'KSD'KSD'KiH(KiH
+(L)L)L)L)LBQ*LBQ*LBQ*LSU+LiZ,M)b0MBf0MSk1MSk1MSf0MBb-M)b-M)b-M)b
+0MBf0MBk1MSk2Miq3!*!!N!#3!*!!N!#3!*!!N!#2Miq2Miq2Miq2MSk1MSk0MBf
+0MBf0MBb-M)b-M)b-M)b-M)Z,LiU+LSQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBL)L)L
+(KiH'KSD'KB@&KB@&KB@&K)5%K)5%K)5%K)5%K)5%K)1$Ji1#JS+#JB'"JB'"JS+
+#JS+$Ji1%K)5%K)5%K)1$JS+#JB'"JB'!J)#!J)#!J)#!J)#!J)"rIhprIhprIhj
+qIRjqIRjpIAepIAemI(amI(amI(amI(amI(amIAepIAjqIRjqIhprIhprIhprIhp
+rIhjqIRjqIRjpIAepIAepIAepIAepIRjqIRjqIRprIhprIRjqIRjqIRjqIRjqIRj
+qIhprJ)#!J)#"JB'#JS+#Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$JS+#JS'"JB'!J)#!J)#
+!J)#!IhprIhjqIRjpIAepIAepI(amHhYlHRTkHAPkHRTkHRTkHRYlHhTkHRTjHAP
+jH(KiH(KhGhGhGRCfGR9eGA9eGA9eGA9eGA9eGA9eGA9eGA9eGA9eGA9eGA4dG(4
+dG(4cFh0cFh0dG(4dG(4dG(4dG(4dG(4dGA9eGACfGRCfGRCfGRCfGA9eG(4dFh0
+cFh0cG(4dGA9fGRChGhGhGhGhGRCfGRCfGRCfGA9fGRCfGRCfGRGhGhGhGhGiH(K
+iH(KhGhGhGhGhGRCfGRCfGR9eG(4dG(0cFh0cFh*bFR*bFR*cFh0cFh0cFh4dG(4
+dG(4cFh0cFh0cFh0cG(4eGA9fGRChGhGhGhKiH(KiH(KiH(PjHAPjHAPjH(KiH(K
+iH(GhGhGhGhGhGhGhGhGhH(KiH(KiH(KiHAPjHAPjHAPiH(KiGhGhGRCfGRChGhG
+hH(KiH(PjHAPkHAPjHAKiH(KhGhGhGhCfGRChGhGhGhGhH(KiH(KiH(KiH(KiH(P
+jHRTlHhamI(epIAepIAepIAepI(amI(amIAepIAepIRjqIhprIhprIhprIi#!J)"
+rIhprIhprIhprIhpqIRjqIRprIhprJ)#!JB'#JS1$Ji1$Ji1%K)5%K)5%K)1$Ji+
+#JS+#JS+#JS+#JS+#JS+$Ji1$Ji1$Ji1$K)5%K)5%K)5%K)5%K)5$K)5%K)5%KB@
+&KB@&KB@&KBD'KSD(KiH(KSD'KS@&KB@&KB@%K)5%K)5%K)5%K)5%K)5%K)5%K)5
+%K)5$Ji1$Ji1$Ji1$Ji1%K)5%K)5%K)5%K)@&KBD(KiL)L)Q*LBU+LSU+LSU+LSU
++LBQ*L)L)L)L)L)L)L)L)L)L)L)L)L)L(KiH'KSD'KB@&K)5%K)5$Ji1$Ji1$Ji1
+$Ji1$K)5%K)5%K)5&KB@&KB@&KB@%K)5%K)5%K)1$Ji1$Ji1$Ji1$K)5%K)5%K)@
+&KB@&KB@&KB@%K)5%K)5$Ji1$Ji1%K)5%K)@&KBD'KSD(KiH(L)L)L)H(KiH(KiH
+(KSD'KSD'KSD(KiH(L)L)L)L)L)L)L)L(KiH(KiH(KiH)L)L)LBQ*LBQ*LBQ*LBQ
+*LBQ*LBQ)L)L(KiH(KiD'KSD'KB@&KB@&KB@&KB@&KBD'KSD(KiH)L)L*LBQ*LBQ
+*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LSU+LBQ*LBL)L)L)KiH(KiD'KSD'KiH(KiL)L)L
+)L)H(KiH(KiH(KSD'KSD'KSD'KSH(KiH(KiH(L)L)KiH(KiH(KSD'KSD'KSD&KB@
+&K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5$Ji1#JS+#JS'"JB'"JB'"JB'"JB'"JB'
+"JB'"JB'"JB'"JB'"JB'"JB'"JB'"J)#!J)#!IhprIhprIhq!J)#!J)#!J)#"JB'
+"JB'"JB'"JB'"JB+#JS+#JS+#JS+#JS+#JB'"JB#!J)#!IhprIhprIhq!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)'"JB'"J)#!J)"rIhpqIRjpIAepIAepI(a
+mI(amI(amI(amI(amI(amI(amHhYlHhYlHRTkHRTkHAPjHAPjHAPjHRTkHRTkHRT
+jHRTkHRTkHAPjHAPiH(KiH(KhGhGhGhGiH(KiH(KiH(KiH(KiH(KiH(KiGhGhGhG
+hGhGhGhGhGhKiH(KiHAPjHAPjHAPjHAKiH(GhGhGfGRCfGA9eGA9fGRCfGhGhGhG
+hH(KiH(PjHAPjHAPkHRTkHRTjHAPjHAPjHAPiH(KiH(PjHAPjHAPjHAPkHRTkHRT
+kHhYlHhYlHhYlHhYkHRTkHRTjHAPjH(KiH(KiH(KiH(KiH(PjHAPjHAPjHAPjHAP
+jH(KiH(KiH(KhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhKiH(K
+iH(KiH(KiHAPjHATkHRYlHhYmI(amHhYlHhYlHhYlHhYlHRTkHRTkHRTkHRTkHRY
+lHhYkHRTkHRTlHhYlHhYlHhamI(amI(amI(amI(amI(amHhamI(amI(alHhamI(a
+mI(alHhYlHhTkHRTkHRPjHAPjHATkHRTkHRTkHhYlHhYmI(amI(amI(amI(amI(a
+mI(amI(amI(amIAepIAepIAeqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIAepIAe
+pIAepIAepIAepIAeqIRjqIRjqIRprIhprIhprIhprIhprIRjqIRjpIAepI(amI(Y
+lHhYlHhTkHRTkHRTlHhYlHhYlHhYlI(amI(amI(apIAepIRjqIRjqIRjqIhprIhp
+qIRjqIRjqIRjqIhprIhq!J)#!J)#"JB'"JB'"JB'"JS+#JS+#JS+#JS+#JS+#JS+
+#JS+#JS+#JS+$Ji1$Ji5%K)5%K)@&KB@&KB@'KSD'KS@&KB@&KB@&KB@&KB@&KBD
+'KSD'KSD'KB@&KB@&KSD'KSD'KSH(KiH(L)L)L)L)L)L)LBQ*LBQ*LBU+LSU+LSU
++LSU+LiZ+LSU+LSU+LSU*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBL)L)L
+)L)H(KiH(KSD'KSH(KiH(L)L)L)L*LBQ*LBQ*LBQ*LBQ*LBL)L)H(KiH(KSD'KSD
+'KB@&KB@&KBD'KSD'KSD(KiH(KiH(KiH(KiH'KSD'KS@&KB@%K)5%K)5%K)5%K)5
+%K)5%K)5%K)1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji5%K)5
+%K)5%KB@&KB@&KB@'KSD'KSD'KiH(KiH(KiH(KiH(KiH(L)L)L)L)L)L)L)L)L)L
+)L)L)L)L)L)L)L)L)L)H(L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L
+)L)L)KiH(KiH(KiH(KSD'KSD'KS@&KB@&KB@&K)5%K)5%K)1$Ji1$JS+#JS+"JB'
+"JB#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhpqIRjqIRjqIRe
+pIAepIAepIAepIAepIAepIAepIAepIAepIAepIAjqIRepIAepIAepIAepIAepIAe
+pIAepIAepIAepIAepIAepI(amI(amI(YlHhYlHhYlHhYlHhYlHhYlHhYlHhYlHhY
+lHhYlHhYlHhYkHRTkHRTkHAPjHAPjHAPjHATkHRTkHRYlHhYlHhYlHhYlHhYlHhY
+lHhamI(amI(amI(amI(amI(amI(amHhYlHhYlHhamI(amI(amIAepIAepIAepIAe
+pI(amI(amI(amI(amI(amI(YlHhYlHhYlHhYlHhYlHhYlHhYlHhamI(amI(amI(a
+mI(amHhYlHhYlHRTkHRTkHRPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPiH(K
+iH(KiH(KiH(KiHAPjHAPjHAPjHAPjH(KiH(KiH(KiH(KiH(KiH(PjHAPjHAPjHAP
+jHRTkHRTkHRTkHRTkHRPjHAPjHAKiH(KiH(KiH(KiH(KiH(PjHAPkHRTlHhYlHhY
+lHhYlHhYlHhYlHhYlHhYlHhYmI(amI(amI(amI(alHhYlHhYlHhamI(amI(amI(a
+mI(amI(epIAamI(amI(amI(amI(amI(amI(amIAepIAepIAepIAepIAepIRjqIRj
+qIRjqIhprIhprIhprIhq!J)#!J)#"JB'"JB'"JB'"JB'"JB'"JB#!J)#!J)#!J)#
+!IhprIhprIhprIhprIhprIhprIhprIRjqIRjqIRjqIRjqIRjpIAepIAepIAepIAe
+mI(amI(amI(amI(amI(amI(epIAepIAepIAepIAepIAepIAepIRjqIRjqIRjqIRj
+qIRjqIRjqIRjqIRprIhprIhprIhprJ)#!J)#"JB'"JB'"JB'"JB+#JS+#JS+"JB'
+"JB'"JB'"JB'!J)#"JB'"JB'"JB'"JS+#JS+#JS+#JS+#JS+"JB'"JB'"JB+#JS+
+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JB'"JB'"JB'"JB'"JB'"JB'
+"JS+#JS+#JS1$Ji1$K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5
+%K)5%K)5%K)5%K)5%K)5%K)@&KB@&KB@&KB@&KB@%K)5%K)5%K)5%K)5%K)5%K)5
+%K)5%K)5%K)5%K)5%K)5%K)5%K)1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1
+$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1#JS+#JS+#JS+#JS+#Ji1$Ji1$Ji1
+$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$JS+#JS+#JS+
+#JS+"JB'"JB'"JB'#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+
+#JS+#Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1#JS+#JS+#JS+#JS+#JS+#JS+
+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS1$Ji1$Ji1$Ji1$Ji1$Ji+
+#JS+#JS+#JS+#JS+"JB+"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'
+"JB'"JB'"JB'"JB'"JB#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprJ)#
+!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J(p
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprJ(prIhprIhprIhprIhpqIRjqIRj
+qIRepIAepIAepIAepIAepIAepI(amI(amI(amI(amI(amI(amI(alHhYlHhYlHhY
+lHhamI(amI(amI(amI(amI(amI(amI(amI(amI(amI(amI(epIAepIAepIAepIAe
+pIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAamI(a
+mI(amI(amI(amI(amI(apIAepIAepIAepIAepIAepIAepIAemI(amI(amI(amI(a
+mI(amI(epIAepIAepIAepIAepIAemI(amI(amI(amI(amI(amI(amI(amI(amI(a
+lHhYlHhYlHhYlHhYlHhYlHhYlHhYlHhYmI(amI(amI(amI(apIAamI(amI(amI(e
+pIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAe
+pIAepIAepIAepIAepIAepIAepIAepIAepIAepIAeqIRjqIRjqIRjqIRjqIRjqIRj
+qIRjqIRjqIRjqIRjqIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!JB'"JB'
+"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'
+"JB'"JB'"JB'"JB'"JB'#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+
+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+
+#JS+#JS+#JS+#JS+#JS+#JS+"JB'"JB'"JB'#JS+#JS+#JS+#JS+#JS+#JS+#JS+
+#JS+#JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'
+"JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)#!J)#"JB'!J)#!J)#!J)#!J)#!J)#!JB'
+"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'
+"J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIRjqIRjqIRjqIRjqIRjqIRj
+qIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRj
+qIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRj
+qIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRj
+qIRjqIRjrIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp
+rIhprIhprIhprIhprIhprIhprIhq!J)#!IhprIhprIhprIhprIhprIhprIhq!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J!!!0%!!!3!"!!8
+!!!#J!!'!83!!!!!!&!!!!!!!!$3@9Zk,S`!!0"3!!$39!$b!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!IhprIi#!JB+#JS+#JS+#JS+"JS+"J)#!IhjqIi#!JB+#Ji1$K)5
+'LBf2N!#3!)Z$H@eLA&YEA@*UFhb"K)5$J(elHRPiH(PmIi'#JB#!JB'!IhprIi#
+"Ji5$JS'"JB+#JS+#JS1$JS'!IhjqIAepIS##K)D)LSk8Q*UDQC@3!)Z%Hh"M9e*
+59epSFAKmIAPaD@0KBQG`Ghb!JS1&KiH&K)5%Ji+!J)'$KSH(KS@%Ji1&KiL(KS@
+%JS'"J(pqIRjqIi##Ji5(LSb-LiZ-Mj+9Q*UCPj@6N!#-K(KS9$md0$8j490MFRb
+"J(elHRKfGRKlJ)@,M)U'K)+!J)#!JS5&KiQ+LSU*L)D%Ji1$Ji+#JB'"IhprIhq
+"Ji@(LBZ0MSk-LiU+MC'9QTfIS++HNAjM5$-S*b`e2dG199aQFAKmIRelHAGjJSf
+8PT52LBD'KSH*LSQ)Ki@&KiL)KS5$JS+#K)D)L)D&K)1#JB'"JS1%KBD(KiH)LSb
+1MT!!NjQJTULSTCq4Hf&)0#NP*#3V1%C2@@GfI(eqJS1"Ii'*NTH9MiZ,LSL(KSD
+(L)D%K)D)LBL(KiD&Ji5(LSb,LSL'Ji"pHRTmIS'$KBL+LiZ+LSU,MBk3!*1AR+'
+RUkQDJ@4*-b)A$J`B+cpAFB5-N!#3!)k*JRamJSb8Pj+1LiH"Ii##JS'"J)''LSk
+2MSb*Ki@#JiD)KiH(Ki@%JRppIAamIAq$KiU-M)Z+LBL)Lj'ARD1RV+kSPATC04S
+1$K3L08GCEi1,M)U(KB*lGRL!M*@AP)q+K(epIi'#JS1%L)b1MSk1M)Q&JB#"KBH
+)LBQ)KB*pHAKhH(PmJB@*Lib-LiU)L)Q-NTUKTkkbVU+,ENmc(J`!"4Nd9hQ2QCH
+-JAalH(9fIBD1NC!!Mib(JhprJ)"qIAq%Lj!!NT+3!)f*KS5$Ji@)LBL(KS5#IRT
+iGhCfHAq&Liq4NC!!M)Q(KSH,NCHESUQXTT9pAd)S&!S2)$TCH)kAPSf#HRCdFA&
+iJSZ4PC53!)Z%IhepIAapJ)@+MT+8PC12LSD#J)'%KiL)L)H&JRjlGh9dGRZ!KBQ
+0N!#4Mib*KiH+Mj5DSDHUU*k,F&8p*a!###0(EBUCR*1(I(GeFh&cHi5,MT!!Mif
+,Ki*rIRjpIS+(M*!!Nj@@Nik*KB'!JB5'KiH(KS1!HhKfG(4hI)+)MC!!NC!!MSU
+)KiQ0NTLGSUDNQiPa@%!V&``9-&"[KjDBN!#%HhCdF@pbHS1,Mj'5NBk*Ji#!Ihe
+qJBD-N!#8PTD8MiU'JS#!JS5'KSD&Ji"pHACdFh9kJ)D-NC16NBk-LiZ1NC@DRU'
+IPiG`9$SX+#FR,N*KIC!!PT''IAKfG(*bH)+0P*@5M)L&K)1#J(jrJBD,Mj1@Q*H
+6M)D"IRq#K)@&KB5$JAjlH(GhH(TrK)U1NC'3!)k,LBQ,Mj1BRD#KQieiB8Xe)43
+4(MjQKCLGPSU!HRGdFR4jJ)H0NC+4N!#1LSD$IhamIi@+Mj1@PjD6MSQ&JB#!JS+
+#Ji5&Ji&qHRGfGhTrK)Q1NC+5Mif,LSZ-N!#@QjkIQiplBdXf*KX9(6TKJTDFQ)k
+&IAPeFh0iJ)L1NC'2MBf-LSD#IheqJiL0NC@@PT11LB@#JB+#JS+$K)5$JAjkGh9
+eGhb$LSk4Nj+2MBb-MBq4P*QGRjZ1HQ0+0#FH'#!kAS#@RTU3!)CrHhGeG(GqKSb
+2Miq1MSf,Ki*qHhb"KSZ2NjDAP)q+KS1#Ji1#JS+#JS+"IhajGhGjIB'(MC!!NT+
+2M)Z,MBq5PTZHRjb4IfP41bJB$"3hBS1BRjQ2Ki&pHACfHAq'LSf0MBk2MSZ(JAe
+mIB#&LSk5P*55MSU(KB1#JB#!J)+$Ji+!IATiGhKlJBH,MT!!Mik-Lib0MT!!Nj@
+CQjL2J'a@3#iI&4`mC)@CRjQ2KRpkH(9eH(q'LSb-M)f1MBU'JAemIB'&LBf4Nj1
+5MSU(KB1#J(prJ)'#JS&rI(ThGhPmJBH-MT!!Mik-LSQ,MC'6PCLCPSk!E9G#-5)
+A(cpQKjUHQ)k'J(ekGh9iIS5*M)f0MBk0LS@"IReqJ)5)M*!!NT14MSU(KB1#JB#
+!J)'#JS&rIAYjHAPmJBH,MSk1MBZ*LBU0NC@AQCQAMi&Z@83b)48I3'L*QTfAMSD
+!I(KfGRPrKBU0MBf0MSf+KB&pHharK)L-N!#6Nj'1LSH&Ji'!Ihq!JB+$JS"qHhP
+iHAb"KSU0MSf-LiQ*LSb2NjDAQ*H2JR&F4c)I&L4)EifERCD0KS"mHAKiHRk$KiU
+,M)f2MSU&J(emIB#%L)Z2NC+3!)f+Ki@$JB"rIi##JS+#J(elHAKjI)+'LSb0MBZ
++LBL*M)q6PTHAPBq%Fej*-ad6*NphNCZDNiZ&IhYkHATmIi1(LBU-MSq1LB0qI(a
+pJ)5)M)q4NBq0LSL'Ji"qIRq!JS1$JB"pHRKhHAb"KSU,M)b,LBL)LBZ0NC5@PT5
+2K(9K5M)G&La@Hj'EQC+,KAplHAPjHhk"KBL+M)k2MSQ%IhYkI)#$KSU1NC'2MBU
+)KS1!IReqJ)'#JS+!IATiGhPmJBD*Lib-LiQ)L)Q+MC!!Nj59P)q%G'"*-"`C-Pf
+!P*UAN!#+K(jlHRTkI(k"K)H*Lik3!)k*K(pmI(f!JiD+MT'4Mif,LBD$J(jqIS#
+"JB+"IhekH(KjIB+'LSb-M)Z*L)L*Lik4Nj@9NSb"F9a&,4XG2'D&PTU8MSL#IAY
+kHRYmIS'%KSL,MT!!MSQ%IhepIS#$KSU1NC!!MSf,LBH$IhepIRq!JB'"IhakH(K
+jIB+'LBZ,LiU*LBQ+M)q4NT58Nib!EPK!+"JK4h#,PjL6MBH"IAYlHhapIi'$KSL
+,Mj!!MSQ%J(jqIi#$KiZ1N!#2MSf-LSH$J(jqIRq!JB'"IhekH(PlIS1(LBU,LiU
+*LBQ+M)q4Nj56N!#)HfK51L-A,&GlNCQ@MiU&IhYkHhapIRq"Ji@(Lik2MBL$J(p
+rJ)'$KiZ1Miq0M)b+Ki1!IRjqIhq!J)"rIATiHAZ!K)H*LSU+LBL)LBb1N!#4NT+
+4MS9hC8ie(KNhBi18Q*50L)0pHRYmIAjrJ)'#K)D+MBk-L)1"J)#!JB5)M)f1MBb
+-LiQ'Ji"rIRjrIi#!J(pmHRPkIB'&KiL*LSQ*L)L+M)q5NT'4MiTrEeP#+KNQ6hD
+0Q*H3!)U&J(akHhaqIi#!JB+%KiZ0M)U'Ji+"JB'#KBQ-MBf-M)b,LBD#J(pqIRj
+qIRprIAYjHAb!K)D)LBQ*LBL)LBZ1NC+5NBq-KAPS8MSN($9IJ*+BP)f(JRekHha
+qJ)#!JB'#JiD+M)U(KB1$Ji1#JiD+M)f-M)b-LiQ&JS"rIRjqIRjqIRekHAYqJSD
+(L)L)L)L)L)U-Mj'5NT+3!)Z#G&p(,"JK5A',Q*L4LS@!HhTmIRq"JB'"JB+&L)U
+,LBD%Ji1$Ji1&L)Z-M)Z,M)Z+Ki5#J(prIhprIRjpI(PjI)#%KiL*LBL)L)L*LSf
+2N!#4NC'0KhYU8cSM(6GKJC5CNib'JAekHRarJB+#JS'"JS@)LSQ(KB5%K)5$K)D
+*M)b-LiZ-LiQ'K)+"IhprIRepIAakHATqJiH)LBQ)L)H(L)Q-Mj'4NT'2LS"aA88
+X'LC1GBkCPiq)JhjkHAYpJB1$JS+"JB+&KiL(KB5%KB@%K)@)Lif-LiZ,LiZ*KS5
+$JAprIRepI(YkHAPmJB@)LBU*L)H(KiL+MC!!NC+4MiZ%HQP814dB1'@'PjU6Li9
+rHRKjI(q#K)5$JB'"Ji@(KS@%K)5&KB5%KSQ-M)U+LiZ,LSH&K)1"IhjqIAemHhP
+jHRq$KiQ+LSQ(KiH'L)U1N!#4N!#3!)k)Ih&G45F9+eTqP*Z@MBH"I(PiHRf"K)@
+%JS'"JS5'KS5$Ji5&KB@&KSL+LiU*LSZ,LSL'KB5#J(jqIAamHhPiHAb"KBL+LiU
+)KiD'KiQ0N!#4N!#2MBU$GfC40"SK5R11QjQ3!)Q$I(KhHAYrJiD'Ji'"JB1&KB5
+$Ji5&KSD'KSH*LiZ+LBU,LiQ(KSD&Ji"qIRemHhPhH(Z!K)H*LiZ*KiD'KSL,MT!
+!N!#3!)k,KRaX9MNH(d*XLCLDNSU%IAKfH(TqJS@'K)+"JS1%K)1#JS+%KSD'KSD
+)LSZ+LBU+LSQ(KB@'KB&rIRemHhPiH(TqJSD)LSZ,LBH'KSH+MT!!NC'2M)GrF&a
+"*4`hBB+@Qj@0KRpjGRGjI)#%KSD%JS+#Ji1#JB'#K)D(KiH'L)U,LiU*LSU*L)H
+'KiH%JAjpI(YjGhCjIB'&KiQ,LiQ(KSD'LBb3!*'3!)q-L)*hC%XU&LP@Hj+FQ)q
+)JATfGRKlIi1&KS@$JS+#Ji+"J)'$KBH(KiD(LBZ+LBQ*LBQ)KiD(L)D$J(ppHhP
+hGRGlJ)5'L)Z-LiL(KS@(Lik3!*'3!)k*JRPT9$8C)%TcMTbENiZ%I(CeGhTqJS@
+(KS5#JB'#JS#!JB+&KiH(KSH*LSZ+L)L*L)L(KSH*L)@"IhemHRKfGhTrJi@(LSb
+-LSL'KSH+MBq2Mik+JhYY@MmL'caTLCUGPSf'IAGdGRPpJB@(L)D%JS'"JB"rIi+
+%KiL(KiH)LSZ+LBQ*L)H'KSH*LSH$J(jpHhKfGAKpJB@(LBb-LSL'KBD*M)k2N!#
+2M)CrFf*++aJY@i#@RTQ2L)&jG(9iI(q%KiL(KB1"JB'!Ihq"Ji@(KiH(L)U-LiQ
+*L)L(KS@'LBZ+KS&rIRakGR4fHi#%KSL+M)b,LBH'KiZ0Mj!!MSb)J(9N6M!A*&&
+lNjkFNiU$HR4cGRTqJSD)L)D%JS'"J(jqJ)+&KiH(KiL+M)b+L)L)KS@&KBL,LiH
+$J(jpHRGdGAPqJS@(LSb0M)U)KSD*M)k2Mif*JhPV9c`J($pYLjZHPBb&IA9bG(K
+pJB@)LBL&JS#!J(pqIi'%KSH(KiH*Lib,LBL)KiD%K)H,M)U%J(pqI(PeG(GmJB5
+'LBZ-M)Z*L)H*M)k2Mik+K(YY@6iK'$CQLCZIQ)q)IhGcFhGlJ)5)LBQ'Ji'!J(p
+qIS#%KSH(KiH)Lib,LBL)Ki@%K)@*M)Z'JRpqI(TfG(ClJ)1&L)U-M)Z*L)H)LSk
+3!)q1LS9qFQ&+,4ST9Ab9RjZ5LS*jFh*eHRq$KiQ*Ki@#J)"rIRk!JiD)L)H(L)Z
+0M)U)L)H'KB5&LBb-LB5!IhekGh9eHAk#KBH+M)b,LSQ)L)U0Mj!!Mib)JAGP6M!
+@(8ThNTqHPBb&I(9cG(KpJSD)LBL'Ji'!IhjqIi+&KiH(KiL*M)b+L)L)KS@%K)H
+,MBU&JApqI(PfGAKpJB5'LBZ,LiU*KiH*MBq3!)q0L)&iDPBq*"ilD)QERTL2Khp
+fFR0fHi#&L)U*Ki5"J(pqIRq"K)D(KiH(LBb0LiQ)L)H&Ji1'LSf-Ki1!IhekGh9
+hI)#$KBL+LiZ+LSQ)LSb2NC!!MSU$HQaB3#BD-@#&QU#DNBQ"H(0cGAPqJiH+LSL
+&JS"rIReqJ)1'KiH'KiQ,MBb+L)L(KB1$KBQ0MBL$J(jpHhKfGRYrJS5'LBZ,LSQ
+*L)Q,MT!!NC!!M)9pF&j),KSP6hU8Rjf8Li4lGA*dH(f"KSQ+LBD$JB"rIAk!JS@
+(KiD(L)U-M)U)KiH'KB5%Kib0LS@"IhjmHAChHRk#K)D)LSU+LSQ*LBZ1NC'3!)f
+)J(9N6M8F(%*aMjkIPSk(IRCbFhGlJ)@*LiQ(Ji'!IhjpIi+%KiH'KSH+M)b,LBL
+(KS@%K)D+MBZ'JS"qIAThGRKpJB1&L)U,LSQ*LBQ+MC!!NC!!MiZ%HQY@2#%@-Q+
+(R+'CN!#*J(KcFhCkIi1(LSZ)K)+!J(jpIS#$KSH'KSH*M)f-LBH(KS@&K)@*MBf
+)Ji"rIAYhGRKpJB1%KiQ,LiU*L)Q+M*!!NC'2Li4lEPY%+4JT9hqAS*b5LS0kG(0
+eHAf#KSU,LB@$JB"rIRk!Ji@(KiD(L)Z0M)U)KiH'KB5&L)b0LS5!IhjmH(ChHi#
+$KBD)LSU+LBQ+LSb2NC'3!)f'IR&J5M%E)%KfNTqIPBb&I(9bG(KmJ)@*LiQ(Ji'
+!IhepIi+&KiH'KSL,MBf+L)H'KB@%KBL,M)U&JApqI(PhGhTrJS1&L)U,LSQ*LBQ
+,Mj'4N!#0L)"dBdie("Y!EifGS*H1KhphFh0fHRk%L)U+L)@#J)"qIAk"K)H(KiD
+(LBb0LiQ(KiD&K)@(LSb,Ki*rIRekGhGkIS+%KBH*LSU*LBQ*Lik3!*'3!)k*JRK
+T96`K&c0MKjZKQT!!LB&jG(0fHAk#KSQ+L)D$JB"rIAk!JiD(KiD'L)Z-LiQ(KiD
+&K)@'LBb-L)1!IRelH(CjIS+%KBH*LSU+LBQ*LSb1N!#3!)q+JhPX@%!P'#jGJjQ
+JQj+,JhTdFh9iIB'&LBU*KS1"J(ppIAq#KBL)KiH)LSb-LSL(KS@%K)D)M)f+KB&
+qIAYiGhKpJB5&KSL+LSQ*LBQ+M)k3!*!!Mib'I'pF45SB*P0mPD#GP)b&I(CcG(K
+mJ)@*LSU(K)+!IhemIS+&L)L)KiL+M)f,L)H'KB5%KBH,MBZ'JRpqI(PhH(b"Ji5
+&KiQ+LBQ*LBU-MT!!NC!!MBGpF&j),KJK6(L6S*k9MSGqGR0dGhYrK)L+LSL&JS"
+rIAeqJB5(L)L(L)U-M)U)KiD&K)5&KiZ0M)L$IhjmHAGhHi#$K)@(LBU+LBQ*LSZ
+0MT!!N!#1L)"cBN`b'Ke%FSqIS*D1L(phFh0fHRk#KSQ+L)D$JAppI(f!JiD)KiH
+(LBZ-LiQ(KS@%K)5'LSf-L)5!IRakH(GkIi1&KBD)LBQ*LBQ*Lif2N!#3!)k+JRG
+R86BD&ceYMCfJQ*!!LB&iFh0eHAk#KSQ+LBH$JAppI(erJSD(KiH(LBZ-LiQ)Ki@
+%Ji1&LBb0LS@"IRelH(GjIS+&KB@(LBQ*LBQ*Lib1Mj!!MSQ#GfP925)E1@H*Qk#
+CN!#+JRPdFR4iIB'&L)U*Ki5"IhemI(q#KBH)KiH)Lib-LSL(KS5$Ji@)M)f,KS*
+rIAYiGhPqJi@&KSL+LSQ*LBQ+Lif2N!#2M)9kE&P"*4J`B)@DSCU5Li4kG(*dH(b
+"KBL+LBL&JS"qI(aqJS@(L)H(L)Z-M)U)KiD%Ji1%KiZ0M)L$IhjmHAGiIB'%KB@
+(LBU*LBQ*Lib1Miq1Li4jE&Y&+aXX@(q@S*b6MBCpGR0cGRZ!K)H*LSL&JS"qI(a
+qJB@(L)L(L)U-MBZ*KiD%Ji1$KSU0M)Q%J(jmHAGhHi#%KB@(LBQ*LBQ*LSb0MT!
+!Mib(IA"I55dB*&"kP+#GP)k(IRCbFR9kIi1(LBU)KS1!IRalIB'%KiL)KiL+M)b
+,LBH'KB1$Ji@+MBf*KB&rIAThGhU!Ji@&KiL*LBQ*LBU,MBk3!*!!MSKrFf*0-KS
+I4h54Rjq@MiKrGh*bGAPqJSD*LSQ(K)&qI(YpJ)1'L)L(KiQ-MBb*KiD&Ji+#KBQ
+0MBU'JRppHhKfHAk$KSD'L)Q*L)L)LBU-MT!!NBk*JACR8cNG'$YVM*fJQ*!!LS*
+jG(0eHAk#KSL*LBH%JApmHhf!JiD(KiH(LBZ0M)Q(KS@$JS+%L)b0LiD#IhelH(C
+iIB+&KSD)LSU*L)L*LSb1N!#4MiU#H'P@25)C0Q5(Qk#CNBZ$HR4bG(KpJB@)LBQ
+)KB*rIAYpIi+&KiL(KiQ,MBf,L)D&K)1#JiL-MSZ(Ji"qHhKfGhb#KBD'L)Q*LBL
+)L)Q,MBq4N!#-KRaZA%3Q&#TDJCLKR*+-KAaeFh4hI)'&KiQ*Ki5#J(emI(q#KBH
+(KiH)LSb0LiL(KS5$JS+'Lif-L)5"IhajGRGmJB5'KSH*LBQ)L)L*Lif2NC!!MBC
+qFQ"+,aNM6RQ6Rjf8MSGqGR0cGRYrJiH*LBL&JS"qI(aqJB5'KiH(L)U-MBZ)KiD
+%Ji+#KBU0M)L%JAppHRCfHAq%KSD(LBU*L)L)LBU-Mj'4MSQ"G'01-KNF4A13!*k
+IPSk*J(KdFh9jIi1(LBQ)KB1!IRemIS'%KSH(KiH*M)f-LBH'K)1#JS@*MBf*KB&
+rIAThGRKqK)D'KiL+LBL)L)L+M)k3!*!!MSU$H@T@2"mA1'H*R+#BMiU#HA4cGAP
+qJSD)LBL&Ji&rIAeqJ)1&KiH'KiQ,MBb*KiD&K)1#K)L-MBU'JS"qHhGeH(f$KSD
+'L)Q*L)L(L)Q,MT!!N!#2M)CpF&e%*43X@i+BS*U4Li9lGA0dH(f"KBH*LBD$JB"
+qIAerJS@'KiH(L)Z0MBU(KS@$JS+$L)b0LiH$JApmH(ChI)'&KSH)LSU*L)L)L)U
+-Mj'3!)f'IA&J5LmD*P&kP*qFNif'IACcG(GmJ)5(LBQ(K)+!IRepIi+&KSH(KSH
++M)f,L)D&K)1#JiD,MBZ(K)&qI(PfGhZ!KBD'L)U+LBL)KiH*M)q4N!#0L)"fCe-
+j(Ka"ESfHRjD1L(piG(4hHi#%KSL*Ki5#J(pqIAq"JiD(KiH(LBb0LiL'KB5$JS+
+'LSf-L)5"IhekGhCjIS1'KSH*LSQ*L)L*LSf2N!#3!)k*JACR86BG(%"VLTbIPiq
+*JRTeFh9kIi1'L)Q)KB+!IhjpIi'%KSH(KiH*Lif,L)D&K)1$JS@+MBf*KB&rIAY
+hGRKqJiD'KiL+LSQ)KiH)Lik3!*!!MiZ%I'pG45F@+eU!Pk#ENBZ%Hh9cGAPqJSD
+)LBL&JS"rIRjqJ)+&KiH'KSL,MBb*KiD&Ji1$K)Q0MBU'JS"qHhKfGhb"KBD'L)U
++LBL(KiL+MT!!NC!!MBGrFPp'*a)P9Ak@S*b5M)9pGh4eH(f"KBH*LBD$JB"qIAk
+!JS@(KiH(L)U-M)Q(KB@%Ji+%L)b1LiH$J(jmHACfHi'&KSH)LSU*LBL)L)U0Mj!
+!Mif)J(4M66-G)dYeN!#HRC5-KhjhG(9hI)#%KiQ*Ki5"IhjpIAq"K)D(KiD(LBb
+0LSH&KB5$Ji5(Lik-Ki1!IRajGRCkJ)5'KiL*LSQ)KiH'L)b2NC'2M)9lE9Jp(K8
+hCiLERjH2LB*kGA4hHhq$KSL*Ki5#J(pqIAk!Ji@(KiH(LBZ0LiH&KB5$JS1'LSf
+0LB@"IhekGhCiIB+&KSH)LSQ*L)H(L)Z1N!#3!)q-KAa[@d!M&c0JK*QJQBq+JhY
+eFh9jIS+&L)Q)KB+!IhjpIS##KBH(KiH)Lif-L)@%Ji1$Ji@*MBf+KB+!IRYhGAG
+mJB5'KiQ,LiQ)KSD(LBf3!*'3!)f)J(9P6M%C)8TfNTqFNiZ'IACcG(KpJB@(LBQ
+'Ji&rIRepIi'%KSH(KiL,MBb*KS@%Ji1$K)L-MSZ(Ji"qI(KeGAU!Ji@'L)U+LBL
+(KiH*M)q3!*!!MSU%HQY@14N@2Qk-R*k9MBL!HA9eGhYrJiH*LBH$JB"rIRjrJB5
+'KiH(L)Q-MBU'KB5$Ji1%KiZ0M)L%JAppHRCeHAk#KBD)Lib,LBL(KiL,MSq3!)k
+,KAYY@6mN($KPKjUIPiq*JRTeG(CkIi1'LBU)K)'!IhjqIS#$KSH(KiH*M)f,Ki@
+%K)1$JiD+MSf*KB&rIAPfGAKpJS5'KiU,LSQ(KB@'LBf3!*'3!)f)JhPT8c3A(%P
+hNTkFNiZ&IACdGAPpJB@(LBL&JS"rIhjqIi'%KSH'KiL,MBb)KB5$JS+$KBQ0MBU
+'JS"rI(KeGRU!Ji@'L)U+LBL(KSH*M)q2Mif+K(aY9MJC&d&aMjfHP)b(J(KdG(G
+lJ)5(LBL'JS#!IhjqIi'%KSH(KiH+M)b*KB5$JS+$K)L-MBZ(Ji"qI(KeGAPqJS5
+'LBZ,LSQ(KSD(LSf2Mif+KRpcB%FS'$"IJjLIQ)q*JRTdFhClJ)5(LBQ'Ji'!Ihp
+qIS##KBH(KSD)M)f,Ki@%Ji1$K)H,MBb)K)&rIATfGAGmJ)1&KiQ,LSQ(KiD(LBb
+1Miq0L)0jD9)b&Kp1HC1IQj'+KAehG(CjIS+&L)Q(K)+!J)"rIS##K)D(KSH)LSf
+-L)@%Ji1$K)@*MBb*KB'!IRajGAClJ)1%KSQ,LiU)KiD'L)Z0MBf0LiCqEPJk'KT
+#F)kHRT5-Ki"iG(9iI)#%KiQ)KB+!J)"rIRq"K)H)KiH)LSb-LBD%Ji1$K)@)M)f
++KS+!IhajGA9jIS+$KBL,LiU*L)H(L)Z0MBf0LiH!Fep&)a8cC)DDRjL1LB*jG(4
+hHi#%KiQ)KB1"J)"rIRq!JiD(KiD'L)Z-LSH&K)1$K)@)M)k-Ki1!IhekGR9iIB'
+$KBH*LiU)KiH'KiU-MSk1M)L$H'C0+K-Q9Rq@RjU4LS0mGR4fHRk#KSL)KS5"J)"
+rIRk!Ji@(KiD'KiU-LSH&K)1$K)5'LBf-L)5"IhelGh9hI)#$K)@)LSU*L)H(KiQ
+0MSk0LiL$HQY80KXJ5A53!*fFNib'IRGdGAKpJB@)LBL&JS#!IhepIi'&KiH(KSH
++M)b*KB5$JS1%KBQ-MBU&JS"qI(KfGRTrJB1&L)U,LSL(KSH)M)k1MSf+KRpcAd-
+L&MGRL*ZIPSk)JAPdG(GlIi1(LBL'Ji'!J(jpIS#%KSH(KSH*Lib*KS5%Ji1%KBL
+-MSZ(Ji"rIAThGRPqJB1&KiQ+LSL(KSD(LSk3!*!!MSZ'JACP65`@+PPrPTqENBQ
+$Hh9cGRTqJSD*LBH%JB#!IheqJ)1'KiH(KiL+M)U(KB5$Ji1%KSU1MBL%JAppHhG
+eGhb!JS5'LBZ+LBH'KBD*MBq2Mif+KAe[@6SD'8*aMTkHP)b&IAGdGAKpJB@)LBL
+'JS#!IhepIi'&KiH'KSH+M)b*KS5$JS1%KBQ0MSZ'JS"rI(KeGRTqJS1&L)U,LBL
+(KSD)Lik2MSf,L)&eB83K%c4PKjUIPik)JAPdG(GlIi1(LBQ'Ji'!J(jpIS'$KSH
+(KiH*Lib+KS5$Ji1$K)H-MSZ'JS"rIAPfGAKpJB1%KiU,LSL(KSD(LSf2Mif,Ki*
+jD9%`&b96I*5IQj++JhYeFR9jIS+'LBQ(K)'!J(ppIS#$KBH(KSD)Lib,Ki@%Ji1
+%K)D+MBb)Ji"rIAYhGAGlIi+%KSQ+LSQ(KiD(LBf1MSk0LSGrF&Sm("JrESbGRj@
+-KAjhFh4iI)'&L)Q)KB+!J)"qIRq"K)D(KSD(LBb-LB@%Ji1$K)D*M)f+KB+!IRa
+jGRCjIS'$KBL+LSQ)KiD'L)Z1MSk0LiQ$GQ*')a-[BS@CS*Q2L)&kG(4hHhq$KiQ
+*Ki1"J)"rIRq"JiD(KiD(L)Z-LSD%K)1$K)@(Lif,KS+!IhajGR9iIB##K)L+LiU
+*KiD'KiZ1Mif-LSL%HfT4-"8N8RZ6Rjb4LS0lGA0eHRk#KSQ*Ki5"J)"rIRk!JS@
+(KiD'L)U-LSH&K)1$K)@(Lif-L)1!IhelH(ChHhq"JiD*LiZ*L)H'KiQ-MSf0MBZ
+(Ih"D2KmC2@b,RCq@MBCrH(0dGhb"KBL*L)D#J)"rIRjrJS5'KiH'KiQ-M)Q'K)1
+$K)@'LBb0LS@"J(jmHAGhHRk"Ji@)LSU+LBL(KSL-MSk0MBZ)JA4J4588,f'&QD#
+CMiL"HR4dGRTrK)H*L)D%JB#!IReqJB1'KiH'KSL,M)Q'KB5$Ji5&KiZ0LiD#J(j
+mHRGfH(b!JS5(LSZ+LBL(KSH+MBk1MSb+KATT86%@)8piNU#GNSU$I(9cGAPqJSD
+*LBH&JB#!IheqJ)1&KiH'KSH+M)Z(KB5$Ji5&KiU0MBL%J(jpHhKfGhYrJB1'L)U
++LBL(KSD*M)k1MSk,KRjZ@$XE'%"[MTqJPSb'IhKcG(KmJ)@)LBL'JS#!J(jqIi'
+%KSH'KSH*LiZ)KS@%Ji5&KSL-MBU&JApqI(PhGhTqJB1&L)U,LSQ)KiD*MBq1MBb
++Ki&cAN)K&6CQKjbKQ)k)JAPdFhClIi5)LBQ(Ji'!IhjpIS#%KSH(KSH)Lib*KS@
+%Ji1%KBL-MSZ'JS"qI(ThGRPpJ)+&KiQ,LSQ)KiD(Lik2MSk-LB4iC8XU&#GAIjH
+JQj'+JhYeFh9jIB+'LBQ)K)'!IhjpIB#$KBH(KSD)LSZ+Ki@%Ji1%KBD+MSf)Ji"
+rIAYiGRKmJ)+$KSL+LSQ)KiH)Lik2MSk-L)0jD9!`&5&3Hj5JRC1-KAeeFR4iI)'
+&L)Q)KS+!J(ppIAq#KBH(KiD(LBZ,L)@%Ji1%K)D)M)f+K)"qIAYiGRGlIi+$KBL
++LSU*L)H(LBf1MSf-LB4mEPJk("e&FBfHRj@0KRphFR0hHi#%L)Q*Ki5"IhppI(k
+!JiD)KiD(LBZ-LBD&K)1%K)@(Lif,KS*rIRajGhGkIS'$K)H*LSU*KiH(LBb1MSk
+1LiD!FPe")4FiD)LES*L2LB*jFh0fHRk$KiQ*L)@"IhppI(f!JiD)L)H(L)U-LSH
+&K)1$K)5'LSf0LB5!IhekH(CjIB'$K)D*LSU*L)H'KiU0Miq2M)H"GQ4+*a-XAS+
+BSCb4LS0kG(*eHAf#KSQ+L)D#J(pqI(erJSD)L)H'L)U-LiH&K)1$Ji5&LBf1LS@
+"IhelGhCiI)##Ji@)LSU*L)L(KiU1N!#2MSZ'JRTV9$-B)NpjNjqGP)b&IA9bG(K
+mJB@)LSQ(Ji"rIRamIS'%KiL(KiH*Lib*KS@%Ji1%KBL-MSZ'JRppI(PfGhTqJB1
+&KiQ*LBQ)L)L+MBk1MSf+KAeY968@'dPeN!#IRT@0KhphFR0hHi#%KiQ+L)5"Ihj
+mI(k"K)H)KiD'L)Z-LBH&K)1$Ji1'LSk0Ki*rIRajGRCkIS'$K)H*LSQ*L)L(L)Z
+0MSk0LSCqF9`r(KNqE)ZGS*H2L)"hFR*eHRq$KiQ+L)D#IhjmHherJiD)KiD(L)Z
+-LSH&K)1$Ji1&LSf0LB5!IRekGR9iIS'$K)H*LSU*L)L)LBZ1MSk0LiCqF9`q(4F
+lDSUFS*L3!)U#HA0bG(PqJSD)LSQ'JS"qI(YmIS+'L)L(KiL+LiU)KS@%Ji1$KBQ
+0MSU&JAjpHhGeH(f"Ji5'LBU+LBQ)L)L+M)f1MSZ'Ih4L5#JC-f#$Q+#DNSZ%HR4
+bG(KqJS@)LSQ(K)"rIAYmIS'&L)L(KSL+M)Z)KS@%Ji1$K)L-MSZ'JRpqHhKfH(f
+"Ji5&KiQ*LBQ)L)Q,M)f1MSb)JA4L4bFD-f#$Q*qDNSb&I(9bG(KmJB@(LBQ(K)&
+rIAYlIB#%KiL(KSH*LiZ*Ki@%Ji+#JiD-MSb)Ji"qI(PhH(b!Ji5&KiQ*LBQ)L)L
+*M)k1MSb(J(9P6#dF-&YrPCqENib&IA9bG(GmJ)5(LBQ(KB&rIAYlIB#$KiL(KSH
+*LSZ*Ki@%Ji+#JS@+MBb)K)"qI(PfGhb!Ji5%KSL)L)L)KiL*Lif2Mib(JAGT8c-
+E+PCmNTkENSb(IRGdG(GlJ)5'L)Q)KB+!IAYlI(q$KSL(KSD)LSZ*Ki@%Ji+"JS5
+)M)b*KB&rIATiGhTrJS5%KBH)L)L(KiH)LBZ-MBb)JhTY@MdN+NpfMTbFNif(J(K
+dG(ClIi1&KiL)KS+!IAYlI(q#KSH(KSD)LSZ*Ki@&Ji+"JB1(Lib+KS+!IRYiGhT
+qJS5%KBH)L)L)KiH)LBZ0MSf*JRTY@d%R+8edM*ZFNif)JAPdG(CkIS+&KiQ)KS1
+!IRalI(k"KBH(KSD(LSZ+L)D&Ji+"J)+'LSb+Ki1!IRYiGhPqJS5%KBD)L)H(KiH
+)LBU-MBb*KAjbBNNX*dCZLCLFPBf)JRTeG(CkIS+%KSL)Ki1"IhalI(k!K)D'KSD
+(LBZ+L)D&Ji+"J)'&LSb+Ki1"IhajGhKpJB5%K)D(KiH(KiH(L)Q,M)b+KApeC8d
+[*N0VKTHDNif*JhafG(CjIB'%KSL)KS1"IhelI(k!JiD'KB@'L)U+L)D%Ji'!J)'
+&LBZ*Ki5"IhekGhKmJ)1%K)@(KiH(KiD(L)Q+LiZ*KApeCP%h,80SK*5CP)f*K(a
+fGACjIB'$KBD(KS1"IhelI(f!Ji@'KB@'L)U+L)D&K)+"J)#$L)U*Ki5"IhekH(P
+mJ)1%K)@'KiH(KiD'L)U+M)b*K(phDPBp,MpNJC+CPBk+KAehGACjI)#$KBD(KS5
+"IhemI(erJi@&KB@'KiQ+L)D%K)+"J)#$KiU+Ki5#J(jlHAKlIi1%K)@'KiH'KSD
+'L)Q+LiZ+Ki&jE&P!,ceJIT!!Q*@1LS9rHACfH(b!Ji@'KiD%JS"qI(apJ)+%KS@
+&KBH*LBL'K)5#JB#!JSD*LBH&JS"qI(PiHhq#K)5&KSD'KSD'KSH)LBU,LSL$Hfp
+I4c)i@RU0PTD2LSD!HRCfH(YrJi5'KiD%JS"qI(apIi+%KB@%KBD)LBL'K)5$JAp
+rJB@*LBH&JS"qI(PiHRk#K)5%KSH(KSD&KBD)LBU+LBD"HR"L6$Fl@RL,PTD2LBD
+!HRGfH(arJS5&KSD&JS"qIAapIi'$KB@%K)D)LBL'K)5$JB"rJB5)LBH&Ji&rI(T
+jHRk#Ji5%KBD'KSD&KBD(L)Q+LSL$IA0Q86`k9(1(Nj@2LSH"HhGhH(YrJS5&KSD
+&JS"rIAapIS'$K)5%K)@(LBL'K)1$JB"rJ)1(LBL&Ji&rIATjHRf"Ji1%KBD'KSD
+&KBD(L)Q*LBH$IRCT9Mmk8R'&NT52LSH$I(KhHAYqJB1%KBD&JS&rIAapIS##K)5
+%K)@(L)L'K)1#JB"rJ)1(L)H&Ji'!IRYjHRf"Ji1%K)@'KS@&KB@'KiL*LBH%IhG
+X@dFq8'f$Mj53!)U(JhjjGhKlIS'$K)@'KB+!IhjpIAk!JS5%K)5&KSL)KS5$Ji+
+"J)##KSL(KB1"J(jmHRTpJ)+$Ji5&KS@&KB5&KSH)LBQ(K)&kF@*02NTSIif6NBZ
+(JhjkH(KlIB'$K)@&KB1"IhjpIAk!JS1%K)5%KSH)KS5$Ji+"Ihq"KBL(KB1#JAp
+mHRTmJ)+$Ji5%KBD&KB@&KBD(L)L(K)"jF'033NeSISb5N!#,Ki4rHRKiHRf!JS5
+%KB@$JApqIAeqJ)'$K)5$K)@(L)H&Ji1#J(prJB5(Ki@$JB&rIATkI(q"Ji1%KB@
+&KB@&K)@'KiH)Ki@#IA4R984+BhU*NC!!LiH%IhYiH(TpJ)+$K)@&Ji&rIRepIRq
+"JS1$Ji1&KSH'KB1#JS'!Ii#$KSH&Ji+"IhelHRYqJB1$Ji5&KB@&K)5%KBD(L)H
+&JReeDPK(5Q*jL*!!N!#,Ki@!I(PjHRf!JS1%K)5$JB"rIReqIi'#Ji1$Ji5'KiD
+&Ji+#JB"rJ)1'Ki@$JB'!IRakHhq"JS1$K)@&KB5%K)5&KSD(Ki@"IACVA%e1BAH
+'MSq,Ki@"I(PjHRerJB1%K)5$JB"rIReqIi'#Ji1$Ji5&KSD&Ji+#JB"rJ)+&Ki@
+$JB#!IRalI(k"JS1$K)5&KB@%K)5&KBD'KS5#IRP`BP*0AA1$M)q-L)@"IATkHha
+rJB+$K)5$JS"rIRjqIi##Ji1$Ji5&KSD&Ji1#JB"rIi+&KSD%JS#!IhelHhf!JS+
+#Ji5%K)5%K)5%KBD(KS@#IRK`Be42Ah5$M)k,Ki@#IRYkHRaqJB+$K)5$JS"rIRj
+qIi#"JS1$Ji1%KBD&Ji+#JB"rIi'%KS@%JS'!IhelI(k!JB+#Ji5%K)5%Ji1%KB@
+'KS@#IhYcD&T4@h"rLBf,Ki@#IhYkHRaqJ)+$Ji5$JS"rIReqIi#"JS1$JS1%KBD
+&Ji+#JB"rIi'%KS@%JS'!IhemHherJB+#JS1%K)5%K)5%K)5&KS@$J(adD9Y6A("
+rL)f,Ki@#IhakHhaqJ)'#Ji1$JS"rIRjqIi#"JS1$JS1$K)@&Ji+#JB"rIi'$KB@
+%JS'!IhjmI(erJB+#JS1%K)5$Ji1$Ji5&KB@$JAehEf&9@QemKSb,Ki@$IhalHha
+qJ)'#Ji1$JS&rIRjqIhq"JS+#JS+$K)@%Ji+#JB#!Ii##K)@%JS'!IhjpI(erJB+
+#JS1$Ji1$Ji1$K)5&KB5$JAjjF@9EA'YkKBU,Ki@$J(elHhaqIi'#Ji1$JS'!Ihj
+qIhq!JB+#JS+$K)@%Ji+#JB#!Ii##K)@%JS'!J(ppI(eqJ)'#JS+$Ji1$Ji+#Ji5
+%KB@$JAplG'TH@fKiJiQ,L)@$J(emHhapIi'#JS1$JS'!IhjqIhq!JB+#JS+#Ji5
+%Ji+"JB#!Ii#"Ji5$JS'!J(ppI(aqJ)'"JS+$Ji1$JS+#Ji1%K)5$JApmGQjLA@G
+fJBH+L)@$JAjmI(apIi#"JS+$JS'!IhjqIRq!JB'#JS+#Ji5%Ji+"JB#!Ihq"Ji5
+$JS'!J(pqI(aqJ)'"JB+#Ji1#JS+#Ji1$K)5$JS"pH("QB'CdIiD*L)@$JAppI(a
+pIi#"JS+#JS'!IhpqIhq!J)'#JS'#JS1%Ji+"JB#!Ihq"JS1$JS'!J(pqIAeqIi'
+"JB+#JS+#JS+#JS1$Ji1$JS"pHA*UBfGdIi@)Ki@$JAppI(apIS#"JB+#JS'!Ihp
+qIhq!J)'"JB'"JS1$Ji+"JB#!Ihq!JS1$JS'!J(pqIAeqIi#"JB'#JS+#JS+#JS+
+$Ji1$JS&rHh9ZCQGbIB1(Ki@$JS"qIAepIS#"JB+#JS'!J(prIhq!J)'"JB'"JS+
+$Ji+"JB'!J(q!JB1$JS'!J(prIReqIi#"JB'"JS+#JS'"JS+#JS1$JS&rIAKaD@K
+`Hi+'Ki@$JS"qIAepIRq!JB'#JB'!J(prIhprJ)'"JB'"JB+$JS'"JB#!J(q!JB+
+#JS'!J)"rIReqIi#!JB'"JS+#JS'"JB+#JS+#JB&rIATeEQY`HB#%KS@$JS"qIAe
+pIRq!JB'"JB'!J(prIhprJ)#"JB'"JB'#JS+"JB#!J(q!JB+#JS'!J)"rIRjqIi#
+!J)'"JB'"JB'"JB'#JS+#JS'!IRYhF@e`HAq$KB5$JS"rIReqIRq!J)'"JB'!J(p
+rIhprJ)#!JB'"JB'#JS'"JB#!J)#!J)'#JS'!J)"rIhjqIi#!J)#"JB'"JB'"JB'
+"JB+#JB'!IhejG("bH(k#K)5$JS&rIRjqIRq!J)'"JB'!J(prIhprJ)#!JB'!J)'
+"JB'"J)#!J)#!J)'"JB'!J)"rIhjqIhq!J)#!JB'"JB'"JB'"JB'"JB'!IhjlGh0
+bGhf"Ji5#JB'!IhjqIRprJ)#"JB'!J(prIhprJ)#!J)#!J)'"JB'"J)#!J)#!J)#
+"JB'!J)"rIhpqIi#!J)#!J)'"JB'!J)#"JB'"JB'!J(jpHRCdGhb!JS1#JB'!Ihj
+qIRprJ)#!J)#!J)"rIhprIi#!J)#!J)#"JB'!J)#!J)#!J)#"JB'!J)#!IhprIhq
+!J)#!J)#!J)#!J)#!JB'"JB'!J(pqI(KhH(arJB+#JB#!IhprIhprJ)#!J)#!J)"
+rIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhq!J)#!J)#!J)#!J)#
+!J)#!J)#!J(pqIAakHRarJ)'"JB#!IhprIhprJ)#!J)#!J)"rIhprIhq!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)"rIhj
+mI(erJ)#"J)#!J(prIhprIi#!J)#!J)#!IhprIhq!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!IhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhprJ)#!J)#!J(p
+rIhprIi#!J)#!J)#!J(prJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J!!!3N!!!3!"!!8!!!#J!!'!83!!!!!!&!!!!!!!!%)
+@9Zk,S`!!3K3!!%)9!$b!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rJ)#!J(q!J(prIRk!JB1
+$IAeqHAZ'Li9pGh0lJ)#(MhKXIhaqJ)D(IhjZH)PjGiU8H'D'I@b,P)CaFReiJAp
+qL(YiL)0hG(&jLi9rPS49Ci9rMU5(DhCP9)LXMhf!J'44GTfFLSk'B9eNF+LJH*@
+(6df'Qi+AM(Pk8'LEJAqJLeTdM'&lRAKqPh"VMRPSL)afLSYUIi*XJ)4mLiPSGTP
+ZAjD5HB"pIS"TC*DPFA10G'KYJjU1IRehCA#6IhZFI'TmH(5'M(Q#Lh&cL(KfL)C
+qG)#%HhacLSTVHSq&DhLAGQQ1NAGaI(PjLi#)Q(&LGhadLD5-FATRB(q)NjL5F9p
+lD@HDU)CeK(G@DBkCPhjlJ'aLGSq9MRpaGi"SG*Z4I(GrHfalLB&qKiTZFT0eCiq
+5FAH4Hh'#Gh@4Kfk(PR0JIC&mH)11LfPNKT4eFj@2FR"lHB1(GS19G@H(K@f"Qh9
+VNS*RIBZ!I(jqIBYcE*Q'DRD0KfYqKS'(Fh@0I'f)NATbMApMIi9rMS&mIAP`F)f
+*J)epG(0aJS@!KC!!JQG`K)"pKSH&H@eiKB&rLB4hH(CjLiKdJ)j`CiQ)ISGqG(k
+$EhUCJACpFhjpH)Z3!(KXL)"IM*KkK)&aFS*kHj@*F(erGAKiNj*VH*4mARkBGhL
+1HRjmGB*rIi+%HRZ'Ehb3!'akRRjNM*!!ARLAHAZ-I(GkFB#1I(Q4I'q*IQk'L(5
+!KRPmL(GeM(phJB@'H(D%Ih0hMBKkL(abJhTZLTjrChq)FA*mNjTeDAq0G'Q1QS9
+[DBU'D(UIQ@9UMRYZJj+1GA'$Gh5*P)"`KhY[KRb(PhKXJiKMHk4qHBKfFhYeL*Y
+pF*+!9iLBDhbAJ@prKB4mCS5NF'5IQ'*MKSZ'GAUSL8Y`S(pUM*U#FfGiQ(0YSTC
+UEBGqFi1(MB0ZJB4YIC@$GS1&Hh9hJT!!G@qCKQb'J('!KRU,P'TaMR&ZNj*rJhC
+YJS4mM*&hGAe[I)f%KBTlFB"mFiZ5K(TcH(ahHjH@FAL!Eh5)Mj!!L'jTKRjPMUQ
+(E('!GR+)NBq"F(*fIRq'PiCfH(9hJS@'LiC[GBK[HjYqDiU-Eh51JhU+H(H-G@b
+%P)TfHB0jGRZ-MhGaKB9eH)q-ChH9IhL'IR&lKhZ,Q@pZJh0dMj4lHBCeE(k*N!#
+#G)@(F@D&Q)"cL)paE(Z%MSCeJBpdBBZ8Ehb4IR1(Ih1$JRKpMS9rHA"qJ(b+N!#
+"H(GjFi+2I)Q-DfL(M'k$TATSKAjQG*f4ISChFh"VLkD0FhU%G'"pMiq9FhQ*BfD
+3!+*mG*Cm@A+@L(4kMSCiJRYlGQf$R)pVHiGKCSqIM(elFhCXGCf4JAamDfL)JB@
+3!)KmE(YlDifBI(U-H9pqM(D'Q(PYLRYXJi4jK*&rGS&bGB*cN!#LG'+%K@*hSj9
+lI(0YHRCpPT0lI)pQ6BbLKB14J&PHHT5QJRD@G%PXQjZ&JiGlCe9rVSPiPiGL@hU
+2LBk4MA*EERjqN!#DMi4VAh@"ISfJM("fFQGiL*56J(f"D9Q$RB1#NSK`BQb#Ni1
+(RAPPER@"LjD&Ki4BD)H&MiU-JR"UD)Z4KSZ!JAaNEBq6J)',H'0fLiQ$J*D)9@k
+3!)KdJ*U#EQGqQAGYP*jZA*+3!'&ePjP[CiQ(H'Z(QhKTJj4kBi5LJPKpURP*KV*
+eA)1FKf"[NjG`DTL0D@ppN!#'DhqAIef&S@jUP)aQG*1+FAL'HRTkJT5*Fh#'IPq
+#Uj*ZD(ppDhDKVh49I)9LH+5@KAPDF)jcGkfMB'U%D@b,Pj+%EA4iDS'INR*jJQT
+hJSQIJ@"VMS4QMD1'C@D'K(k-KRjlGQppN!#&Ji*kFAb"KC*jHhjUFSfBISL-APU
+!PSb2PAaT@&k-T*q1Jh459B'SSiQ$G'*5EE'QFS18CNeqRj!!Ji*rG@CYN!#BK)1
+*F&plPSapIB9lBRUHNA*eJ(&lLjUDBe*rMhH&UT&R@QL0Nhb5Uh*)GBYcK+H2Fh0
+VE(q8PBf+FPKRMiq(RC0K@R0pMD#4Ii"KA)51NTk%BACl@SZlKQf#FQ+!MSUPLP9
+MJAU$TTf"F'"GFCLSQiK`CeCRM*keP@YPDQ"TTkZ,JA*ZF'CdVUCPH*jZ8AZ-LCU
+"E)b%@'kJM(L*KA4hGh@1KhL,K@phKAGrPi9eJRe[H(q'PB9bH(YqIS"qMBpUG)D
+#HhL#LiTeI)abEBQ'I*!!KA"qH'f)PRGkPAKbJRKmKB#+QA&DLi9HK+Q5GfpZIRp
+ZMkTqCReiDi#*M*0mGS"YDj!!PRD,MQ*aI(D2QAaePA*4LjQ$Ji'"G@YYN!#DH)D
++Dff&JRf2NAKUHSCfGT51F)+*D(H2HhfCI@@+If5)PAL%L'YqL'plRRYTPhTQM)Y
+bHj9jG)edHiaiGiL*FhZ-HR1#MAjcKBPcHC!!IAH%JhKkL(f#Jh9rIRq#JS#%L@a
+aMS4fL**`G)*`GC5DH(b(E'0mP)U-MhCQE(arLU#6H'KZGh5'R+#!A@YrHAHAT)a
+YBA##K(kES'jMHh4VM+10KS"MD(KjMUk2EhaQ9(UNQj',G@pHB*'QMS@+FPYbIS@
+ENi*iGfpYJj'4JRZ'G@TmL)b(IAH(K@YlNi4kIAU#LRYfM)4XJ)YqKSaiGRpiI)Z
++Ii9jDB1,HBD@KfTbJh@'MS+(JACPICD%LB&rJfpVIjk(FSZ#GRGhJ)q0GB#2H@P
+kLiTqHj!!L@PaKS5!LS9jKhP[JB5'KhemLRaSJC0kJT!!Fh@*G@f5QhPcKRjdGi1
+@L(9hJ)"iHSZAJQelM(YdJ)Q2Hff&MA*ePS9cL)*dJ)GiJBT[IT*fGCQ*AS#6FhL
+8NAKdER13!)9rPC!!EQ'$JRq2L)TrE@GpPAQ%S)"PFB4pIj@*J)0XD)@5J)#3!)"
+XG(k'N!#"I)PiDAf4IhZ8Iff#I(5$N!#+J)&aGS4jJC!!LhTaHB#$Ii'5J@jkIi5
+#IB'$Ih9rKAf)IhL-K'jjM(eiMS&lKh4`M)ChM*!!Fh#"HAU*LBq&E(Z!ERUBNAU
+'H@CjIS5CNAjpFQ4kMBQ8NR"eGPb&VSCbQiK)DC')NSf!J(CGFCf2KC*kDRGeGC5
+EI(KqEfk-MSU3!)"VCS+*ISq9IQGXHi15NSH+GeTVLBZ5PB&dGfeNNU#)KhafG(9
+[LUPmDBU(E@q1MB5%GAk'I(D#N!"rG(Z#KBH!Hi0rGRQ(MSL!FhL(H(H2N!"rGi"
+jGSH%KBjrGRGmIhZ-NSKjEAYqJBD+PiCTChq'GifILA*YGh@$N!#2NReUF(jmJCL
+-HS0lE(L-L)Q(GB5)BfLLR@CrRhPRGS+'Li1!P(GEJSpiIjL4Hh4[G)*rKTZ2H(9
+bEAH4QBZ&JhGNDiL2LiU%JhjXDiQ2JSb2HA&iEhb8MB@+J@abIRq0NS&lIh4`JSk
+&JSZ%GR0qJAk,M)9lDRU&JB#+PRGcIAf+Gh++PB4aKAjXH)D6MS4mH@jUKj!!Mib
+#HA*`DBkLJiL*F&pbMSQ2MiL&@eZ1Q(q)SB"MDQf0R)'!N!"k@ALBJAq*K(YeJ)5
+*IA5'J(H'LhplK(jbHSb,JRjmJhTZHiZ8J(f*G("mKi@%MhCaKRTjMiYjI)"cJT*
+hI*9fBAq2KSZ-G(KrCAbIM(b(IQ&kMhk)N!#"GhPhH)b+J)4jHB&pJSZ*HA*jJS1
+"NSpcD(Q"J*+1Ki4NAB1BKikJF9P[H)'AUC&aC@"dKiqKSB"G@hD!JCfVMQGMEfe
+pPk1FGfK`D@b4VSelK@jFH*+5Mi4hGh9aKD'*EAZ$H(+,S)K[FS"hG*19L(jbGhG
+hKTL0H(pkES5+I)f,F(1,JhQ@K'KqIA5-RBChJh"LIj!!PT@%HR0QC)UPN!#)Nh4
+9CiH5NC@+J(&AF*DCLBQ3!(0GFBL2MBk,GfKbJiL(N!#3!(9YGhZ$LC1)HhYYGi@
+*LBD,HA&kIBU'JiH%HR"mK)D'J)@'GA#)LR9rPi9VHiKqG(b8NAYdJ)4`HBq2MAa
+kI@j[KjU)JT&qAQU,Mi@-Pi"ICB#,K)kDJfeXH)+$Mj!!KRTXGS1!JC59EQU*J@k
+&Ri4`HhpkH)@6Lh4hKhP`Lj0qI)4mHATmLSemHBZ!ChL5LRQ%PAeLGSq!HT16GQp
+jGhk)M*5*Eh1!Fh+1R)ejFhYlD(LNS(TcJ(&PIj56LRpfFA4jKjQ4HR*pG@f'Qj!
+!GhPhERQ&Pj@$GQpaEi1CQ)TiEQaeISUMPA9[G'j`Njf)JAP`Ehb)NC'"G(4fHSL
+6M(efGh*mN!#8M(ebEA*qM*k4HRKXBRUIPBH2HQ&QH)QJQhTlH&jVNTf2LhpXE'P
+pS*U#J)"KCSL1N!#9L@eTH(Z(NC!!Lh9XFi5*Jif,I'YbL)Q(L)*rFferNSq#L(a
+SGiD!LjU&Eh&eHSQ,LC*rCR'&Ji@5MAacF(D(LBQ3!)CcEAQ$K)f0L(j[F(Q)LS@
+4LhCTGSKrIiq8KA"cIhakJC'6JAGjHh4eMTL+K(pfCff)NT'1MRYHDB@+LCLFHQ&
+SGS+1NjH2EejYKBD(STTfBfTiGibHNi4eE@PfMjD3!)@"H'4VMCD'K)GpF(*qMjG
+qGiPrDADBLhD(JA0fKSb#KS+!HR#%M)"kKSTdGiQ'IhaqKi9fI*'(ERL-I(D,Li'
+!JAKcIi5)Li5#HR&cIiU&Lj*rF(0mIRq+Mj&rCR5$GhQAQhjiHQjfJSD6NRjbGh0
+cLj'0N!"mDR0mHiLCMRjjD@b$Lif5LRP[ERD&NC'+HfpiGR54QSChHRTZH)bANA9
+dIA0eKC@8Jh&VIi"eMTf(FA*fFi13!*!!LAjfE(1*MiH*LR&NHBU-MSTmGQpYJjH
+@KhYbEA0mN!#EM)"hD'@#PSZ4Q(CDE(k"NCk0HR&MESk3!)b6LQjNGRb*PBZ&I'j
+XIiZ,NSPbFRPaICQ6I(jpEA+'Lif4IA&jH(+$QBYlJhaZGiH0L)@!HRKcIiZ(Ji*
+qHAerIib,Hhb"HRH&Khq&KAajJB+!Ji5"Ii+!HAq(IhL"LS*qJi*rHAU$L)5"KAp
+fHAq$KSD)KAYfI)"jKC!!LRjhHATlJ)U8Kh9iHhjrKBb'IAGpIRk)K(q&K(TmK(a
+pMBKlIRpfHS@&LBeqGRYlHB@1LB@"H(*dHiZ9LB+'GfCbL)Z2PB&cG@a[LjU0L)T
+`CAL!Kj'6KR9dF(@$M*H+I(PeGhU)N!#,JhCdGRq+KBU*Gh*qJRf3!**dGS0cGC+
+5IiD"DRD&JT!!P(YdI'paLBq8P(GRH(aaLk'1JhPQChk)LCZ@I'YUG(b-PC5&Fh&
+ZG)@1P)arFh&iHBQ3!)U'H(4iI(f)Ni4hIAekIS5+L(adIB4qIiD$JAjmIi+!IB+
+#IS+#IRjrJ(epKB9pIB@$FhZ0KRf!KAjfH(b+MhapKApcH)H'LBKlHAPfHB+0NBT
+lEhPiGBbAM(pkF@PfK)qEMRGfH'YUNU1)IBGeA(#,MC59JRC`ChD4NBL3!)"QEAQ
+!P*D%KATFFCL'I*k1A'L#Hi5BNi4lCfH&LS@8PhYKD(f&L)qDLfYPFRq)NC1'H(0
+[F)+BNS#"HfpdJ)D2NRYcIhKbL*H%IB*iG(U)LBD,I(9fIS9qLSU%I'jmKS5!K*!
+!IR*hIS9rJSk)Gh@"J(U%MSGqHhYiHB@*KSQ$HhGdHBL6Ji+2H'*eLB@+NiPkG'Y
+fMSL*NiG`DhKjKT1,LS"bF(5&Lj!!LAPpGR*lLTD(IApfGAf&Lif'FhQ#FAbAMAZ
+#JA"iKi#*NhjbH(f!JB'+NRjYIBClIi1'LS"bH)U#Fi15KhGkKhehJ)+(LB4eHiG
+hGiU-L)4kFRf"H)H8L(piFRKrJiZ9KR4jGA#$Mif1L(0THhpmMjH*HA*YFSH2LBk
+-G@C[JBZ-N!#0HQeXH)'-QBq#FQPaHSH4PieiEfGcKBU6QBKXEA4`K*H8MS4[ChC
+lJjU8JRpaBh@,LSq9JA&bERH0P)k'HA"bGB#4N!#(JAKYGB+%MieqI(CdH)10LiG
+hHB&cI)f*JB"lFhq)IB1)IRYpIAk(LApkJ)"hHiU+IRf!HRZ!JBU+IAPpHhL%KB1
+*IhKrI(Q(LRZ#MAKbJS*lJiPrJS4fHB+!JBD*I(U"H(H"LSU!JRahI(Z$LiQ$I(K
+bHSD$LBk"HAKdHBZ2JS1'FfjqJS12MRYfIRCdLC1)J(afG(TpLTQ(FhTpGRQ,MSb
+&F(9rHAf-P)&qIR"jJSH+Ki*iI(KeKik&IB5"F(Q-Khb&KRPiIAq&LRYkMS&bISL
+$J)1!Ji*eISPmI)f)H(q&HAb'IB'1JR9pKRKjL)D+KRPiJ)"hK)k%JRjiHS##JBZ
+'IAepHhk%K)1$IhalIi@%IS+'I(KpKSYrHB+%GRH*Ki1)IAD#IAD'N!##IBGjF)#
+#KBb'JRekGAQ(L)Z&HRekHAf$MSb#HhGiHS@'JSf'F(5"Ii5-Ji#'G@b%M(f'MAa
+iHRU"Li9qKhjcHS''L)9rHhjkHS'*MRjjI(b!IB'+MAeZJS4cJiZ$JB0iGSClHj'
+'GS'$GAQ'JS1)Ihf"HAQ)JAb(L(afIhpqKB'%KRjiH)+%IS@%I(arIRZ'LhprIAP
+rJB+#Ki"hIRYqLBD!JS*cGSL#JBQ'HA4kISQ*J)@'G@YrM)H&KB&jG(1!NBL$L(e
+ZF)D(JSb+Ih*bIi'&LBL$GRGrIRq%M)9fHhppJB##Ki&hH)L$HSQ'GhL!JB#'KS'
+!H(9rKiL'JAprH(9pLiZ!IB&rGRL)L)+#JhjiHRk(KRU%LhPeJiQ!I(q!K(jlKS0
+iHiL%H)5+I(GrL(pqKB+"IRepJB&pKiKlHS'"I)'&KS9kH(q!I)5+J)D$FRD'KAb
+)MAejH(H!KSH*LAjcH(prKBb*Ih9hI(k(LiU"HhPiI)12LhakI(KiKBU,LhYdHha
+mLj5"IAp`ES+5LiL'HA9dI)H-LB*rG(0qK)H)KS0mGR@$LS+$L(e`HBD&J)H*I(0
+lKS5%KAYqIhCpM)TqJ(edISU#JSb!FhKqJ)D+KB0pFAU'JS5-KhTeH(b%Ki@*JRG
+iIAaqMiekH)5"F(Z2L(f!JAYmIRZ+MATmKhaYJT'#I)1%HR0jL)f!JBPmFRQ"JBH
+,JAjlFRH&LS5*M(GXHS&pKT1'HAacFS@0KSb-G@efHS+1M)D%G@YhJiQ0M)*pFfY
+lLBD*Mi&`G(arJSU1KhGbHRerK)@-KA&bL)KdK*&rG(Q!J)+"JiTmFAk'Ji#)KRY
+eGS1(Ji1)J(CfI)1$L)H#I(GmIi+$JiH!GhTrJS'&Jhq"HAL#LAppK(pjI)1!KBK
+pHhprI)''JS+#H(Q!K)#!KS9rG(Q*KAU$LheeIAq!L)0mKB0cGiZ'I)@$GhL#JS+
+&JApqHhq%K)+"IRZ!IRq'KhpjIherKS5"JB0kGB''Ji+&IhCpIhb)MS*kJAPcJSQ
+#KiYiFRjqIib0K)"iF(Q%KBf1I(KjF(b5Li1+JQPaKB1'MiPlHA4dJiU+LB4lFh9
+qKiQ*Li"bFRf$JiU-K(9bIRq"LSq&H(CeIB1%LBk&FRGpHi'+Mi9kGRKlHSH5LRp
+hHATlIiL3!)4mH(GlIiH)M)9lH(0kKSQ(KS*eGRamL*!!KhepHA4qJiH-JhTlI(P
+rLSQ(J(GpI(H#MiTlIhefHRf+NS0jI(jcHSU,LAaiJ(jeIT+(HhppHhYpJif&GS+
+$F(L,LAf"K(ekGhk,L(YrLAedHS@(JAq#JhTfKBGmIiD#H(b(JRPqK)0pIB#"Jhe
+pL)&eIBKrGBD*HAU&K(epIS#(IRU%K(PlJhq$KRerJhTfK)0pL)ChHS0iHif(Hi#
+#GhH#K)L&I(emHAL#M)Q#HhajGS#,LB1$Hh9eHSQ-L)@"H@ekJS+1Li*lGR"hMBD
+%Mi9aF(epJib*K(jiFRQ$Kik(IhTeH(k$KSZ)GR*mJB+&LB9qHA9iK)Q%JS9qG(C
+qKBZ-KAKfGAU$L)f'IAGeI)+,L)'"IAKiJiD%JReqIReqKSGqJ(jpJ(b"Ki4mHB&
+pJ)H"Ji4jGS5%IiD'GhU&HS'+JB#$HR@)LAQ%KhemIAf$LAepKhejJBH"J)&rJRY
+pL)GqHRprIAk&MS*jIhYhJSb$KS9bH)*iIjL0G(jrF(U*KiZ,H(*pHRZ1MB##Hh0
+mIB'1MRTdJRPfKBb,J(PhHi"qK)b*Hh*mJhU!NSPiHRajIiL'K)CkHB"kIiU&IS'
+#HRf!ISL(HB#(HRH%JRL#LB'!JRjmI(U$MB4pIRahH)#(MBPqHh9fIiD)LiPjEh9
+pJSU-L(pdFhZ"Kib+Ih4cH)1'Kik(FQjpJi+(MB9eFRL!K)D,K(aeG(q'K)H*IR*
+hIRq'LB5!HR4qK(k(M(jdIApjKBL"JRYfJSClIif"Fhk#J)&rHi+%HAk+K(YmIRb
+"KB1$J(TiHi''Ki@"HRKlIi5(KApqH(H"KB@$JRjjI(f$Li*mIRaeIif%JB9kFAf
+%J)Z-IRChH(b*LS@)Hh*fI)+)Li0rHh*mKS'$M)0cH)#!JS1$JAakI)''L)"kIRj
+lJiH!J)0jGi@'J)5"HRarJS1$J)&mFhk+Ki+#IAClHhq2MhpiHAGhK)f+KS&fEAD
+'LiZ,KA9YGS'*MBQ&Hfj[J)Z*MBPlG(&fKC!!LS@%FQapKS1,Ni&dG(L#KBH*L(T
+ZIB&pL)k)HACmJB&lKT!!JA&eJS5!KBf%GR9rJi++KRKeHS5(K)5%I("kLSZ'K(j
+cG(Z'MiH!JAYaGSL1LS4lHRCbISq3!)9rGR4jIiQ3!)YpG(0fK)L(Mi9`E(b'KBU
++KAaXEi11LSD&IR4`HSb0KB5!Fh5"KSQ&JB"jGhf(KS'#HhTrJ)5&JheqI(5#Mi*
+mJAjlHhq)M)&iIAjiJ)Q)JATiI(pmKT'#FhL"Hhf+L)0pGAD!KS1)L(efH(f"KiL
+%IRGfHi+&L)PqGhTlISH0J(TqG(@%LSH&J(CfIhk$MBGkH(TiIB@'LB0hGRb"JS@
+&IhjjH)+)JRb!IRPrKi5!JRjjHi#'Ki&kIAphHiQ,Ji"pH(TmJBQ*IRarG(D*MB0
+qJhYeHB+1L(YlJATbKBf%J(pmH(jqJiZ"HReqH(b,KS#!IhTjJB1'K(ppH(b$KS+
+!KAadISH%Ii1"H(YqJSQ%HRk"HAH*MRpmIhjjGi@-K(f"JA9hKSL$K)&lHhTqLSK
+qIS*jGB1+KAq!J(GhK)Z&JB*lGRU!KSQ'IhYkHAk&L)KqI(eiHS1+K)5"FhQ%Ii'
+0LhGdI(k$KBD)J(4fJB+&LiClH(TkJSH(LB"eGS1&I)H,IRGkJ)'%K(q"J(Z"K(e
+rKRpkJS4pIi5"J(jpJB*rJSL"GAZ"Ii+(Ki&mGAQ(KS'&KRKbIS+#L)4qJ(aeISb
+(Ii+!HATmJSb*IAYrHhZ%KSL(HR4mJ(k'MS*kI(KiKBq'J)&iFRb&L)Q$I(YlGhf
+1M(ppI(akHS1-LATjJRekJ)D'JRelJRpiJBU"HAk$IRf"K)9rGhZ'K(q"K(eiI)'
+'K)'"HAQ"Ji'#KRjfHhq%KS*qIhpfHBQ+J(b!IRCjKBU%IRjmH(b"KBU'IAPjHhf
+&LB+#Ih9fJ)U$JBCpGAL#KB+'JRYkHAq'KRprK(TfIiH'JRjqIhGpKi4rJi0cHBQ
+!I)D(HhTqHi1'IS#$IAQ"KB'"J(amIRq&K(q!IhTlK)5"KB4lGAf%Ii#(KRYhIRq
+#JS+'JAGjKB*pK)9mH(jrKSGmJB4iGi5(IS5%H(k"IAq&KRppI(q$I(k)JRPmJS#
+#KB'!IRKpKSD"K)&iGRk'KB5'JRGeIi+"LSPqGhTlIBD(KB0lHAZ"JS1(K(jfHi@
+"Ii5'J(PpIS5'IRq%JAYmJiD"I)#'IAL*LAPmJhppIi5+Kh0bL)0iKC+%F(@#Jhk
+$Mi9cGB'"IS@*KRadIB0qIiZ,HA4pJRalMT*lEhk%G(f5M)"hGRarIB+8Lh*hJ(Y
+kKSb(IhClJRZ!MB9kIi&jIi4rJi*mJ)9mHSH$Hhq&KAemJB&kHBQ,IRerIRPmK)U
+-I(CqI(KrMBf"HhGlIAq)LSL!GR4jJi@&LBClFhD!KiH(KAeeGAZ%LBU'IhGcHi'
+&LSZ"GRCkI)'(MBKkGAerGi'4LAakI(eiHB@2KhPqJhPdISZ*Ii#%I("iLBD#Ki9
+jFhQ!K)H(KAecGAk%K)H,K(0ZIS9qK*!!LA4aHRf"KSZ,IR*cIB1"KiZ'H'plK(q
+"LiPlH(PlJ)D'JS5"HACmK)5$Ji&qHAPqKBH#Ii&qGRQ&Ki#!K(piHRq%KS*qJAp
+kHS#'JhpqJS"iIS1$JRk!J(pjHiL&IB#&JRKhJ)H$IB+%I(KmJSD%J)&rHRTrJS5
+&JAf!IRYrJi5$Ihk!JATkKSD!IS+$HRU!KS4qK)&jI(q#JS@$IRpkHi'%KB1"IRa
+mIB+'KS0kHB#!Hi51KAGiIAerKBQ)J(GiHhq(LSL#Hh9iJB1*LS&pHhPkK)Q$JS*
+mHAZ$KS1$K(jfHi1#JiD#IRYjIiD&J)5%H(L#KB&rKB4mHAq%Ihk%K)&qIAprIS#
+%KB&rIhTkJ)5'Ji5#HRClK)5'LS&jHRKjK)b,K(jeG(b!LC!!LRjdFhCrLBf2JhC
+cFRL(Nif$J(9VGB12NiCpH(*bI)b2LS"hHRKiKBZ'JB"kGhk"JSD$J(plHi##J)'
+$Ihk!IRprIS+%JAk#JAPlJ)+%KB5!HhKlJ)1(LS0iGhKlJ)H-LApdGRemJBZ-JRK
+hHAb!KBf'GhPqHhb(Li&kHRZ!JB'(KAaeIS4rJ)5$IAKmJS1#Ji*mHAk#J)'$JRa
+iIS1&JAq#JATfJSZ$IS"pHATqJiU(I(YpHAf&Ki9rI(TmJ)''KRjmIAjpJB@#JAa
+jJ)&qJSD"HRf!I)#%JS"pIRprIi'(JAKmJB&pJSL#HhKqK)'"KB4jGAk%JS1'K(Y
+eHS5'JS1)I(0mJS+&KS&mHhPrKi+$KRYfIB+#JSD%J(KeKBKqK)L!GRTqIiH%JB5
+!HAYrJ)5(JAprHhjrIS5'IRf$J(b#JRq#JS+!I(arIRf'L)#!IRTqJS#(LAekIhT
+fKSb%Ji"kHAKqLif"IS*eFB'*L)L$IAYfGSD3!)1"KATbGi5+L)1!J(GfJiQ'JS*
+qGhQ"LB5!JhpiHS1(K)#!JRefIBQ&IB'#IRYmJSD#IS+$Hhf%JAq!JB'!J)'%IhP
+rKB*rJB0qHRb"K)+$K(jjHi'#JS5%JAPjIi+!JSL'I(ClJS'!LBTpGRKqK)1%L)*
+hGi#$JSD$IRajI)5'Ji*rHRZ"JB+)JRTkIAq"Ji1&JAGjJi+!K)@!HhYlIi5$JB&
+qI(b!Ji5#IAamIS'$KB*mHRk!J)1(JhKhIS1!J)L'I(9jJB1&K)@#GR4pKSD%KRp
+hGhf"K)Q'I(KiI)'%KiGqH(KpJB@&Ji0mGAb&JS#&JRPjIi+$Ji+"IAKmK)@#Ihk
+!IRPrLS9lIB"lIB1$K)0mHAf!JS@$IhjlHi#$K)9qHRepIB+)JheqI(f"JSD%IRT
+mIAk&KB+#I(KpJB1)KRakI(KpLBU$IATjIB#%LiGjH(apJ)@(KAphH)#$K)H$Iha
+iHi1&KB@"HRPqJ)1&JS4qGRZ#Ji5&JRemHRf(KB'$IRPlJB1&KAprIAQ"KS+!JRp
+lIS#$KS"pJApkJ)H#IhpqJ(jqKSL"I(jpIB1%KB9pHAjrIBH+JAprHAQ"KB@&IRe
+qGhk*Ki'#J(PmIS'*KRaqJ(KmLBL#J(emIAQ!MSCmIhpjI)'"KiPrHhjmIB+"K)U
+!H(aqIS'$K)@!HAq$I(q'JRprIS#!I(k%JAq&JRaqIRf#K)+#IhTmIRk%LS*pIha
+lIS+)KRakJ(jjJBL'JAalIRjmK)H"IhemI)#%Ji'!J(jlIS5$Ii'#I(U!Ji+"JB0
+mHS#"JS1#IhaqI(q&JS'"IAU!Jhq!Ji"lHi+&Ihk$J(GmKS0rJB*mH)#&JAk"JRj
+lI)'%JRq"K(ahIi0rJ)H$H(b#IRk&KhplHhk"Ii#%JRemJ(prJS+"IherJAepKB4
+lIi9rHRq$Ii##J)#"I(b#JAb%KhelIhjpJB5%JhekIhjmJSD$JAjjI)*qJ)L$HAZ
+!IAk%K)*rI(aqJB'$Ji"mI)#!J)5&IhapIAk!JiD#I(b!IRZ&Ki'!IRaqIRq%LAp
+jJB"mIi1%JhpjIS4pIiD#IAjqIS'!Ii4rHi#$JAq"J)"rHS''J(f"JRjpJ)5$J(q
+!IRf"Ji'%JRjqIAq"K)1#JAYlIRq$KB5$IAPqJS+#KB0pI(apJS5$K)&mIAppJBH
+%Ii"pHRq"JS@$IRjrHRk(K)#"J(emIAq'KRjrJRjlIi+#JS+!J(emJB1#JB1$IAa
+mJ)1$JB#$IhPqKB*rJi0pIApqJB5"J)*pHS+%IRq%JAjqIS1$IAq$IhZ"K(q"JAf
+"J(aqKS0kJB*mIS+%J)#!IRppJ)1$J(aqIhjqJSH#I(k!IRb"KS0rIRemIi+$Ji*
+qIAepIiD'IRb!IAPrLBD!IhplH(k%Ki9rIRajHS#)L)0pIAehI)@'K)1!GhPrIS1
+(K)&pHRTrJS+%JRjpHRf#JS'%JhTlJhjmJS@"IRapJhplJiL"HAk$IRYrKi4lIS0
+rHAb%K(pqJB*mHS#'JAf#JRajJ)4rIi5$IAZ!J)##JB'!Hhb!J(q#K(emIi#!Ii1
+&IhGpK(pqJi4rIAjpJS0qK)0mHhq#I)#&K)&lJ)*qIS'#IhprIi+!Ii#!J(q%Jhb
+!JRalJB@#Ii'#HhU"K)@"J)"pHAU'LB&pIi&kHB+*L(YlJRYfJ)Z(JAjjIApjJC!
+!L(ClJRPiKBQ(K(YiIhekKSb$IAjpHRf#KSH!I)"rHhq)KAerJAjpJ)5"J(jqJS"
+pJiKmGS1%Hhq'KRjlI)'%Hi'+JhGkKB"lIiD)I(Q!K(jjKBGrIRk#IheqJiCmIS1
+!IAf$JS#!J)0pHS'$J(q%JheqIAq$JB'%JRTlJi&pK)D"HhTrJS"qKSCkH)##IRq
+(KAjiHi1"IS1+JR0kJi"lK)b!HRTrJRerL)YkFS1#H(f(LAelIB'!Gi+,JRKpKRe
+kIi5'IRb"JhpjJB0rIi'%Hhb"IRk!K)&pIhf!J(f$KRjiIS0qIS+%KAYfJBClI)Q
+&HRTmIi0rISL'G(H&JAb!Ki4mGRb(J(U'KhahIB#"Jhb"KAPjJS0mJSClIB"qJ)#
+#JB"lHiD!IS+"IhYqIi1$Hi'#HhU#L(pqJ(jmHB'%JS*qIReqIB++IhZ!IATrK)+
+$JAPmJ(b"Ki0qJ(YjJi*rKS4iH)"pISL'IhplGhk%JS@(IRKkI(k%L)1!IRPlIS'
+%KS0kIApjISH(Ii##HharJBD$I(b%IRH&L(jmJB"pJRf"L(YjK)4jISGqIS'!J)&
+rIB*qHi@$IRq#IhU!JB1%IS'$HRH#LAjrKS&kHRq%Ji*rK)&hHi1'JRq$J(elIiL
+#IS+!HhU%JS#'JAYpJ(arLS0pJhpjISD!J)GpHRpqIi1%Ii+"HAq#IB+'IhZ$IAL
+'KRf"KRaiK(jpKi0pIi0lI)@!JS@!IAk"IB##Ii@"Hi#%IAU%K(k!J(q!Ihf!KAp
+mJi*pI)1$IAk#JhpmJ)'!Ihk$JRjrJ)"pJB+!JAjrJAjrJS*mJ)9mIS5!IB##Ii*
+qHSD$HAq'J(Q!J)#%IAk&J(GrKherKApqIhemKB0mK)&mIS"pIiQ"HS+!Hhb"K)+
+#HRb%IAU#LRpiJB"pIi#$K(jiJ)CkI)H$I(eqIB1!HS@'H(Z&J(f%J(Z#IhQ"KRj
+qJhamJRjrKB*lIRppJS&rKB0jHi1"I)1$J(jlIS+$J)#%J(alIi5!Ii'"IRb!J)+
+#IS#!IRjrJS*rI)'$I(k&J(b!Ihf$Jhf#JRPmK(prKB*mIRamK)+!KS0hHi0mISL
+'IRjqHAq#IiD)IAKrJ(Z!L)@!IAamIi##Ki0mIS"pI)5%IB+"I(q"IS#&IRZ&J(Q
+"KRjpK(pqJRk!Ji&mJS4lIi*rJ)&rIi9rHS5#I)'&J(k%IAZ$JAk$KRjmJRpqJS+
+#JRppIi&rJi*qJB&mIB5$Ii+!IB#!Hi+*IhU$JRYmK)@"Ihk$IhKrKi4mIi*qIRf
+!L)0lIi4pGi1'IS'%J(arIi#&JRk$J(YpJi&rJi*rIRerJi&rKB0kHi1"IB1&J(p
+pIB+$IS#)J(GqK)"mJiD!IRZ!JhppJSGpH)+%Ihk"JRpqIS'&IRk%J(PrKB'!Jhp
+qJ(arKB&qJi&jIB0qJ)@!IS&mI)1"IS5%HRb#JB'"J)'"HAZ'JRb#JReqIRk%KRa
+mKAjhJ)@#J)"rIhplJB9rIB#!IRq"JS*qI)'#I(k&JRPqJhemKS4lJB*lI)+#JB4
+mHi5!HB'*JAPrJB"rI)@)HRL$JhQ!LB&pIRYqJRprLB9hI)0pHS5(J(jqIAapJi@
+$IRjrIAerK)0rIhk!IAb$Ji&pJ)4jI)5#Ii#$IhprHi#$J(q#JRYqJ(k"JB+#Ihp
+qIhjrK)'"JAjpJ)"qJS0rIS"qI)1$J)+!IReqIi#&JAq!I(q!J)+&JhYpJReqK)5
+!J(plJ)*qJBH"HRk!I)#%JS1"I(f"Ihf'K(arJ(YqJi+!KB"lJB"pJS9rIi0mHS+
+#Ii5%IS&rH(q'JAk&KRTmJ(q%JB#$JRajJi0qJi5"IhjmJ)5!J)5!I(f"IS+%J)'
+!IRerJi'$JAf"J(apK)CqIi&rIAf"Ji0rJ)*qI(q#Ji#"J)+!HAk&JRq"K(jpJ(k
+"Ji'"JB"pIi"rJi0rJ)"qIS+"JB*rI)'"I(q(JAb!JAprJB#$JhTpJi"mJBCrIB"
+rIi#!JS0rHi+"Hi'$J(q"IRf%Ihf'JRTqJhelKS*pJS"mIi*rJB4qIS*qIB'#IS'
+!I)+"I)#&J(U"JAarJB'"IharJhprK)*pIApqJB'!JhjlIi&rIiD$HRk!Ihq!Ji&
+rI(f$Ihk$K(jlJB&qIi+$IRarJS"qJi4qI(q#Ii#$J(pmHi#$J)#'JAPrJheqK)*
+qIAerJS"rKB0kHi&rJ)1!J)"pHi'%Ii'$IAarIRk$KAjqJ(emIi+"JS"mIS"qIi5
+%Ii"qI)#"Ii#%JAZ"Ihf#JB#"JAepJhjpJS'!JB"qJ)"mJB1!J)+!I)#"Ii+"J)#
+!IAf$JAq"JAppIi##JRq"J(jpJ)1"JB"rJ(erJi5!IS0rHB#%JAq#JRjqIB#'JAf
+#JRamJi+"JAk!JAeqKi*lJi4kI)@#Ii+"IS"qIB5%IB#%IhZ!K)'!Ii'#IRf#K(p
+qJS&qJB1!Ii"qIi#"JB+#I(f#Ihq%JhaqJRerK)*rJAplJS4rJS*rIRprJB4rIi0
+qIB'$J(q"Ihq"IS'%JAarK(ppJi4rIAprIi##KS&pIB"qI)5)JRepJ(jpJ)D(IAU
+"IhZ!Ki1!IheqIRq#KB"pJAjkJB5#IRk"IhemJiCpIB1"Hhk%JB#"IhprIAq%JRk
+!JRepJS&rJ(pqIi#"JS&qIRppIi5$IRprHhb#Ji1$J(apIAb&KhjrJRYjJ)1"Ji*
+mIApmJ)5$J)"qHRq#J)+#IhalIS'%JS#$IRPpJi1!JS&pI(aqJi@!Ii&pHRf$JS+
+$IhjpIB##K)'!IhjqIB'&JAk!JAapJS#"JB"qIS"qIi+!J)#!J(prIRq"J)'!J)"
+pI)#$Ihq%JhYkJB"rJS+#J(elIi4qIi@"I(f!Ii#$J)'!HRk#Ii#%JRf!J(b#KB#
+!JRjmJS"qKB4mI)+!I)+%JS&pIB#"IAq&JRjpJ)'!Ihq%JAYrK)"lJ)0qJ)'!JB#
+!Ii+!IB1#IRk#JAb!Ji'!IS'$IRb!KAppJi*rIS#"JB"rJS"lJ)5"IB+$IAk!JS*
+rIS#"I(k&JhprJApqIi'%JAf!JApqJB1!JB"qJ(q!JB+#IB'#I(k#JAq!Jhq!JAk
+!JRprJi&qJB"rJAprJS*mIi4rIB'#IS##IS##IAk$JAf#JRarJhpqJS&qJB"rJhp
+mJS0pIB5!HS+"IS'!Ii'#I(k&IRf&JRarJReqJRq!JRjqJAppJi*pJ)*qI)#"J)*
+rJ)&qIB'$Ihq$IRerJ)#!JS#!Ihb"JAprJS&lIi&qIi##J(pqIS+!IS+"IAk"Ihk
+#J(q"IRk#J(Z"JhaqK(pmJB&pJ)&rJAppJ)*pIS1"IRpqJ)&qIS'#IAk#Ihk!JRj
+qJS"qJB&rIi&qIB+!Ii+#IRq#IAk#Ii#"IRq"IRb%K(Z!K(jmJB"qJRppJS&pIi0
+rIB&rJB*rJ)&rIB#"I)+$IAf"JRerJS'!IRq!J(pqJi&pJ)+!IB'#Ii"qJ)*rIB+
+%I(k%Ihb"JAk!JAq#JAb!JReqK)&qJi&mJ)"pJS*qJB4mHi+!IS+$Ihq!I)##IS'
+$J(k!J(f"JAq#JRjqJB"qJB'"JS"qIi+!IS+#Ihq!J(q"JB'#J)#"J(k!JS#!JAp
+rJ)"rJS+!JS"mIi&rIS1#IS"rIi#"JB##J(jrJ)#!JB'!Ihk"JRprJS&qJ)&qJB&
+rJ)'!IS+#IS+"IRq"JAq!J)##Ihk$J(jrJS'!JS#!J(jrJS"rJB*rIB#!IS'#J)'
+"IhprIi#$JAf"JRepJB*rJB&rJAjpJB*rIi*rIS&rIi+!IS'"Hhq$IRq#J(k!J(f
+!JRq"J(jrJ(prJS#!JReqJRpmJ)4rIS&rIRq!JB&rIS'!IRq"JRpqIi'"I)#$J(e
+rJhjpJS&rIB'"IS"rJB&qIi'!IAq$J(erJS"qJ)+#IAb#JReqJS*pIS#!J(q!JB"
+qIS&rIS#"J(q!J(prJ)&rIi'!IhprJ(prIi'"IhprJ)"rJ)+#IRk"Ihk!JB'!IRk
+!J(k!Ji&qIS#!IAk#K(jpJB"pIi+"J)"qJ(pqJ)+!Ii#!IRprJB*rJ)+!I)#$IRk
+#JRjqJ)#!Ihq#JAprJ)"qJ)#"JAk!JAprJB0rIi&rIRq!JB'"J(prIi#!JS+!IS"
+rIB##JB'!J(pqIi#$JB#!J(ppJ)+"JB'"Ihk!J)'!Ii+!IRq"J(q"JB"rJ)#"J(q
+#JRjrJS&rJ)'"J(pqJB&rJ)+!IS#"Ii#"JB"rIi#!Ii#"J)"rIi'!Ii##J(k"JAp
+rJB'!J(q!JAk!Ji"rJB&qIi'!JB&qJ)&rIS+$IRk"J(q!JB'"Ihk"JAq!JS'!Ihp
+rJ)#"JB&rIS#!J)##JB#!IRk"JAq!JhpqJ(q!JB#!J)*rIS#!Ihk!JB#!J)#!Ihp
+rJ)&rJ)'!IhjrJB&rIi'!IB#"Ii#"Ihk!Ihk"JRq!J(prJ)"rJB&qIS#!J(q"JRp
+qIi#!IS#"JApqJ(prJ(q!JB"pJ)*qIB'"IS#"IS#!IAq#J(f!JRpqJ(q!J(q!JAp
+qJ)"qJ)&qIi&rIRq"J(q!Ihq!Ihq!JAjqJi"pJ)'!IS#!Ii"qJ)*qIS'"IS#"IRq
+!Ii#"Ihq!IRk"JB#!JAprIhq"J(k"JAjqJB"rJB"rJ(jrJB"qJ)*rIS#!J)#!Ii#
+!IS##J)#"J(prJAjrJRprJB"qJ)&qIi*rIi*rIB'"IS##Ii##Ihq"Ihk#JRq!JRj
+rJAjrJS"rJB"pJ)&rJB&rIi#!J)#!J)*rIB'!Ii#"J(q"IRq"Ii##J(k!JAq!JB#
+#J(erJRppJS*rIi&rIi'!J)+"Ii#"IRq"J)#"JAprJ(q!JAq"JRprJB&pJ)0rJ)'
+!Ii#!Ii+#IAq"Ihq"JB#!Ihq"Ihq"JAq!JAprJAq!JRprJB"rJ)"rJ)#!JB&rJ)&
+pIi+!Ii'"IS#!Ii'"Ii#"Ihf!JAq!J)'!IS#!JB"rJB"rJ)#!Ii#!Ii#!J)#"J(k
+!J(q"JAq!JAjrJB"rJ)&rIhpqJB&qIi"rIS#"Ii'!IRprJ)#"JAprIRq!J)#!JB"
+rIRq"J(q"J(prIhq"JAprJ(prJB#!J(jqJ(prJB&rIhprJ)"rJ)"rIS#!IhprJ)"
+qIi&rJ)&rIS#"Ii#"IRprIRq"JAq!J(erJ)#"JB"rIhjrJB"rJB"qIS'!IS'"Ihk
+!J(q!J)#"J(jrJApqJB&qIi'!J)"qJ)"rJ)+!IS'!I)##J(q!J(prIS#$J(q"J(e
+pJ)'"J(q!IherJB'!J)"rIhq!JB"rJ(pqIi'"JB"rIRq!J)'"J(prIi#"JB#!J)"
+rJ)'!IhprIi"rJ)+!IRprIi'"J)'"IRf"JAq"JAprIhk!JS#!JS"pIi#!JB'!J)"
+rIi#!J)'!Ii#"J(q"JB#!J)#"J(q!JAq!J)#!J)#!J)"rJB&rJ(pqJ)#"JB#!Ii"
+rIi'"J)"rIhprJB'"J(prIhq!J)'!J(prJ)#!J)"rIi"rJ)+"IhprIhq"JB'!Ihq
+!Ii#"JB"rJ(prJB'!Ihq!J)#!JB&rIS"rIi#"J(prIRq!J)'"J(pqIS#"JB'!IRp
+rIS#"J)#!Ihq!J)#"J(jrIhk!JB#!JApqJ)#!J(q!J(prJ)&rIi#!J(q!JS"qIi#
+!J)#!J(pqJ)#!J)'!IRprIhq!JB"qIRprJ)#!J(prJ)#!J)'!IRq!J(q!JB"qIRq
+#JAq!J(jpJ)#!JB"rIhpqJ)'!J)&qIB#!Ii'"IhjqIS#"J)#!IhjrJ)'!J)#!Ihq
+!J)#!J)"rIi"rIi#!J(prJ)#!Ihq!J(prJ)"rIhprIi#"J(prIhprJ)'!J(jrJ)#
+!JB&rIi"rIi#!J)"rIi#!Ii#"Ii#"Ihk!J(q!J(q!J(q!JAprJ)"rIi#!J(prJ)"
+rJ)#!Ii#!Ii#"J(prJ)#!J)#!J(prJ)"rJ)'!IhprJ)#!JB&rIi#!J)#!J)"rIi#
+!J)#"J(q!Ii#"J)#"Ihk!J(q!JB#!J(q!JB'!J)"rIi"rJ)#!J)#!J)#!Ii#!J(q
+"JAprJ)#!J)#!JApqJ)"rJ)#"JB"qJ)"rJ)'!J(q!J)"rJ)&rIi'"Ihq!J(prJB'
+!Ihq!J(q"JB#!IhprIi#!JB#!J(prJ)'!Ii#!Ihk!JB"rJ)"rJ)#"JB"rIhprJ)#
+!J)"rIi#!JB"rIi"rIi#"J(prJ)"qJ)+!IRq!Ii#!J)#!IRq!IRq"JAprJ)"rIi'
+#Ihk!JAjrJB"rIi#!Ii#!J(prJ)"rIi#!J(jrJB"qJ)&rIRq!J(prJ)"qIi#!Ii'
+!Ihq!IhprJ)"rIRq!Ihq"JB"qIi#!Ii#"Ihk!Ihq!JB"rJ(q!J(k!JApqJ)'!J)#
+!IhprJ)&rIi&rIi#!Ihq!J(pqJ)#!Ihq!J(prJ)'!Ihq!Ii#!J)#!Ihq!Ihq!J)#
+!IhprJ(q!JB"rIhprJ)#!J)"rIRprJ)#"J(prIhprJ)'!IhprIhprJB'!Ihq!Ihq
+!J)#!J(q!J(q!J(q!J(prJ)#!J)#!J(prJ)"rIi#!J)"rIi"rJ)#!Ii"rIi#!J)"
+rIi"rIi#"Ihq!J)#!Ii#"Ihq!J(q!JAprJ)#!J)#"J(prJAprJB&rIhq!J(prJB&
+rIi#!Ii#!JB"qJ)'!Ii#!Ii#!J)"rJ)'!Ihq"J(q!J)"rIi#!Ii#!J(q!Ii#!J)#
+"Ihq!J(q!JB"rJ(prJB#!JB"rJ)"rJ)#!J)"qIi#!J)#!IhprIi#"J(q!J)"rIi'
+!J(q!J)#!Ii#!Ihq!J(q!Ihq!J)"rIi#!Ihq!J(prJ(prIi#!J)#!J(q!J)#!Ii#
+!Ihq!JAprJ)"rIi#!J)"rIi#!Ii#"IhprIi"rJ)#!IhprIhq!J)"rIi"rIi#"JAp
+rJ)"rIS#"IhjrJ(prJ)'!IRk"J(k!JApqIhq!J(q"JAjqIi"rIi+!IRprJ)"rJB+
+!IRq!Ihq!JB"rIhprIhq!JAprJ)"qIi'!Ihq!J(prJ)#!IRq"J(jrJ)"rIi#!J(p
+rJ)"rJ)"rIi'!IS#"IhjrJ)#!J)#!IhjrJB"rJB"qIhq!J)#!J)"qIi'!Ii#"Ihk
+!J)#!Ihq!Ihk!JB#!IhprIi#!JB'!Ihq!Ii#"JB"rIhq!J)#"JApqIhprJB'!Ihp
+rIi#!JB&rIS#!IRq#JApqJ)"rIi#"J(jrJ)"rJB&rIS#!Ihq"J(prIi#"Ihq#JAj
+rJB"rJ)#!J(prJB"rJ)"rIi'!Ihq!J(q!JB'!Ihq!J(q!JS"rIi"rIi#!J)"rIi#
+!Ii#"Ihq!J(q!J)#!Ihq!J(q!JApqJ)#!J)#"J(prJ)"rJ)#!J(prJ)#!JB&rIhp
+rJB"rJ)"rIi#!Ii#!IhprIi'"Ihq"J(jrJB'!Ihq!Ihq!JB"rJ)"rIi#!J)"rJ(p
+rJ)'!IhprIhjrJB&rIi#!Ihq!JB"rIi&rIi#!Ii#!Ii"rIi#!Ihq"Ihq!J)"rIi#
+!J(q!J(prJ)#!J(prJ(prJ)"rJ(prIhq!J)"rJ(prIi"rJ)"rIi"rIi#!IhprIhq
+!Ii#!IRq!J(q!JB"rIhq!Ii#"J(jqJ)"rJ)'!IhjrJ(prJB&qIRq!J)#!JB"pIS#
+!J)#!J(pqIi'!J)'!IRq!Ii#!J)"rIRq"J(q!J(prIi#!J(q!J(prJ(q!J(prIhq
+!JB"rJ(prIhq!J)"rJ)"rJ)#!J)#!IhprIi#!J)"rIi#!Ii#!J)"rIi#!Ihq!J(q
+!Ii#!Ihq!Ihq!J(q!Ihq!J(q!JAprJ(q!J)#!JB"rJ)"rJ)#!J)#!J)"rJ)#!Ii#
+!J)"rJ)#!Ii#!J(q!Ii"rIi#!Ihq!J)#!J)"rIi#!J(q"JAprJ)"rJ)#!J(prJ)#
+!J)"rIi"rJ)#!J)"rIi"rIi#!IhprIi"rIi'!Ihq!J(q!J)#!Ii#!Ii#!J(prJ(p
+rJ(q!J(prJ(prJ)#!J(q!J(prJ)"rIi"rIhq!J)"rIi#!Ii"rJ)#!Ii"rIi#!Ii#
+!Ii#!Ihq!Ihq!J(q!J(q!Ihq!J(prJ(prJ)#!J(prJ)"rJ)"rJ)"rJ)#!J(prJ)"
+rIi#!J)"rJ)"rIi#!Ii#!Ihq!Ihq!Ihq!J(q!Ihq!J(q!Ihq!J(q!J(q!J(prJ(q
+!J)"rJ(prIi#!J)"rIhprJ)&rIhprIi#!J)"rIi#!Ii#"J(q!Ii#!Ii#!J(prIhq
+!Ihq!IhprJ(q!J)"rIhprIi#!J(prJ(prJ)"rIhprJ)"rJ)#!IhprJ)"rIi"rIi#
+!Ihq!IhprIi#!Ii#!J(q!J)"rIi#!Ii#!J(prIi#"J)#"J(jrJ(q!JB"rIhprJ(q
+!JB"rIi"rJ(q!J(prJ)"rIi'!Ii#!Ii#!J)#!Ii#!J)#!Ihq!Ii#!J)#!Ihq!JB#
+!J(prIhq!J(q!J(prJ)#!J(prJ)"rJ)"rJ)"rIi#!Ii#!Ihq!Ii#!J)"rIi#!J(p
+rJ)"rIi#"J(q!J(prIi#!J(q!J(prJ)#!Ii#!J(q!J)"rJ)"rIi"rIi#!Ii"rJ)#
+!Ii#!Ii#!J(prJ)"rIi#!Ihq!J(q!J)#!J)#!J(q!J)"rIi#!Ii#!J(q!J(q!J)"
+rIi#!Ii#!IhprIi#!Ihq!J(prJ)"rJ)"rJ)"rJ)"rIi#!Ihq!J)#!Ii"rIi#!J(q
+!Ii#!Ihq!J(q!J)"rJ(q!Ihq!J(q!J(q!J(q!J)"rJ(prIi"rJ)"rIhprJ)#!Ii"
+rIi#!Ii#!Ihq!Ihq!J)#!J(prJ)"rJ)"rJ(prJ(q!J(q!J(prJ)#!J(prJ(prIi#
+!Ihq!J)#!J)"rJ)"rJ)#!Ii"rIi"rIi"rJ)"rIi#!Ihq!J(prIi#!IhprJ(prIi#
+!Ihq!J(prIi"rJ(q!J(prJ(prJ(prJ(prIi#!J)#!Ii"rIi#!J(q!IhprJ)#!J)"
+rIi"rJ(q!J(q!Ihq!J)#!J)#!Ii#!J)#!IhprJ)#!J)"rJ)#!J)#!J(prJ)"rIi#
+!J(prJ)#!Ii#!IhprJ)"rIi"rIi#!J)#!J(prIi#!Ii#!IhprJ(q!J)"rIhq!J(q
+!Ii#!Ii"rJ)#!J(prJ)"rJ)#!Ii"rIi#!J)#!Ihq!J)#!Ii"rIi#!Ii#!Ii#!Ihq
+!J(q!J(prJ)"rJ)#!Ii#!Ihq!J)"rJ)"rIi#!J)"rIi#!Ii#!J(q!Ihq!J(prJ(q
+!J(q!J(q!J(q!J)#!J(prJ)"rJ)"rJ)"rIi#!J)"rIhq!Ii#!J)#!Ihq!Ihq!J(p
+rIhprJ)#!J(prJ(q!J)"rIi"rIi#!J)#!IhprIi#!J)#!IhprJ)#!Ii#!IhprJ(q
+!Ii"rIhprIi"rIi"rIi#!J(prJ)"rIhprJ)#!Ii#!Ii"rIi#!Ii#!Ihq!J(prJ(p
+rIi"rJ)"rJ(prJ)#!J(prJ)"rJ)#!Ii"rIhq!Ii#!J(prJ(q!J)"rIi#!J)"rJ)#
+!Ii#!Ihq!Ihq!Ii#!Ii#!Ihq!J(q!J(prJ)#!J)#!J(prJ)"rIi"rIi#!J)"rJ)#
+!Ii#!J(prJ)"rIi#!J)"rIi"rIi#!Ihq!Ihq!J)#!J(q!Ihq!J)#!J)"rJ)#!J)#
+!J)"rJ)#!J)"rIi#!Ii#!J)#!Ihq!J)#!J)"rIi"rJ)#!J(q!J(q!J)#!J)"rJ(q
+!J)"rJ)"rIi#!J(prJ)"rJ)#!Ii#!Ii#!J)#!Ihq!J(q!J)"rJ)"rJ)#!J)#!Ihq
+!J)#!J)#!Ii"rJ)#!J)#!Ii#!J)#!J(prJ)#!J)#!J)#!Ii#!J)#!J(q!Ii#!J)#
+!J)"rIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#
+!J)#!J)#!J)#!J)#!J)#!J!!!!3!!!`U%!!-*K!!!!8%!di-8&i)!!!!F!,B!!(0
+ZC#!!#`!+90m!!#!!!!!!di(S8%N!$#!!0d3!di(`4!-!&b!!HBJ!di(N*8S!)b!
+![-`!di(J8L8!-#!"!hS!di(FGdN!Ib!"5,i!di(B,83!2b!"G3)!di(8+f3!FL!
+"R8B!di(38KX!5L!"dBS!di(-++X!9#!#!-i!di()2VF!Cb!#N[`!di(%C'd!E5!
+#ad!!di(!#e4[EfaPC#")Eh*Z#NeKCfPM)%KKFR!,6@&RD@-J4QaeG'8-6'9KG'K
+PFL"%FR9Y$NK[FQiJ6fBJ8'aPER4j#NCbEh0d)%K[FQi*4QPbC5")Eh*Z%N4bG@d
+J6fBJ4@&bG'KaG@&VC39#G@GXC34#C@aX$&G[Ef4PEL"'E(9dC3YAEfpNC@iJ5'&
+bF"31:
diff --git a/sys/mac/News b/sys/mac/News
new file mode 100644 (file)
index 0000000..ddbc48d
--- /dev/null
@@ -0,0 +1,9 @@
+Welcome to NetHack 3.4 for MacOS 7.0 - 9.x
+
+Unfortunately, the 68k version is no longer supported.
+
+This game is brought to you by Dean Luick, Kevin Hugo, and Mark Modrall.
+
+Bug reports, suggestions, comments, etc., should be e-mailed to the
+Internet address nethack-bugs@nethack.org, or fill out our comment
+form on the web at http://www.nethack.org.
diff --git a/sys/mac/README b/sys/mac/README
new file mode 100644 (file)
index 0000000..dae2192
--- /dev/null
@@ -0,0 +1,36 @@
+Jan 2002
+
+The MPW compilers are now supported again.
+
+Support for 68k has been discontinued due to a lack of a debugging
+system for 68k binaries.
+
+Note that the tiled MacOS X port uses the Qt windowport and the UNIX
+build system, not this windowport code.
+
+
+26 Nov, 1999
+
+NetHack 3.3.0 was built with Metrowerk's Pro 4 compiler on a PPC
+system.  We are still compiling with 68K alignment because we know
+it works.  No one has checked lately if the PPC alignment bug
+still exists.
+
+
+23 May, 1996
+NetHack 3.2.1 was built with Metrowerk's DR8 compiler on a PPC system.
+The official 68K and PPC versions were compiled with 68K Alignment
+to share files.  The 3.2.0 versions were compiled with PPC alignment,
+but it was discovered that the Metrowerks 68K compiler has a bug with
+PPC alignment and structures that can be aligned to a single byte.  This
+bug _may_ be fixed in DR10, it is not fixed in DR9.  Why bother with PPC
+alignment at all?  Because the space saving from 68K alignment is small
+and the PowerPC version will run better.  The 68K version was compiled
+with 4 byte ints using the far model.
+Only the Metrowerks compiler has been used to compile the code in a
+long time.  It is _very_ likely that the other compilers, Think C and
+MPW C, will no longer be able to compile NetHack out of the box.  They
+and their files have been moved to the "old" directory until such time
+that someone can compile with them.
diff --git a/sys/mac/dprintf.c b/sys/mac/dprintf.c
new file mode 100644 (file)
index 0000000..e646716
--- /dev/null
@@ -0,0 +1,47 @@
+/*     SCCS Id: @(#)dprintf.c  3.1     94/01/29                  */
+/* Copyright (c) Jon W{tte, 1993.                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "macwin.h"
+
+static Boolean
+KeyDown (unsigned short code) {
+unsigned char keys [16];
+
+       GetKeys ((void *) keys);
+       return ((keys [code >> 3] >> (code & 7)) & 1) != 0;
+}
+
+
+void
+dprintf (char *format, ...)
+{
+char buffer [500];
+va_list list;
+int doit;
+#define DO_DEBUGSTR 1
+#define DO_PLINE 2
+
+       if (flags.debug) {
+               doit = 0;
+               if (macFlags.hasDebugger && KeyDown (0x39)) {                                   /* Caps Lock */
+                       doit = DO_DEBUGSTR;
+               } else if (KeyDown (0x3B) && iflags.window_inited &&                    /* Control */
+                       (WIN_MESSAGE != -1) && theWindows [WIN_MESSAGE].its_window) {
+                       doit = DO_PLINE;
+               }
+               
+               if (doit) {
+                       va_start (list, format);
+                       vsprintf (&buffer [1], format, list);
+                       va_end (list) ;
+
+                       if (doit == DO_DEBUGSTR) {
+                               buffer [0] = strlen (&buffer [1]);
+                               DebugStr ((uchar *) buffer);
+                       } else if (doit == DO_PLINE)            
+                               pline ("%s", &buffer [1]);
+               }
+       }
+}
diff --git a/sys/mac/maccurs.c b/sys/mac/maccurs.c
new file mode 100644 (file)
index 0000000..13d9f8f
--- /dev/null
@@ -0,0 +1,223 @@
+/*     SCCS Id: @(#)maccurs.c  3.1     93/01/24                  */
+/* Copyright (c) Jon W{tte, 1992.                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "mactty.h"
+#include "macwin.h"
+
+#if !TARGET_API_MAC_CARBON
+#include <Folders.h>
+#include <TextUtils.h>
+#include <Resources.h>
+#endif
+
+
+static Boolean winFileInit = 0;
+static unsigned char winFileName [32] = "\pNetHack Preferences";
+static long winFileDir;
+static short winFileVol;
+
+typedef struct WinPosSave {
+       char    validPos;
+       char    validSize;
+       short           top;
+       short           left;
+       short           height;
+       short           width;
+} WinPosSave;
+
+static WinPosSave savePos [kLastWindowKind + 1];
+
+
+static void
+InitWinFile (void)
+{
+       StringHandle sh;
+       long len;
+       short ref = 0;
+
+       if (winFileInit) {
+               return;
+       }
+/* We trust the glue. If there's an error, store in game dir. */
+       if (FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder ,
+               &winFileVol, &winFileDir)) {
+               winFileVol = 0;
+               winFileDir = 0;
+       }
+       sh = GetString (128);
+       if (sh && *sh) {
+               BlockMove (*sh, winFileName, **sh + 1);
+               ReleaseResource ((Handle) sh);
+       }
+       if (HOpen (winFileVol, winFileDir, winFileName, fsRdPerm, &ref)) {
+               return;
+       }
+       len = sizeof (savePos);
+       if (!FSRead (ref, &len, savePos)) {
+               winFileInit = 1;
+       }
+       FSClose (ref);
+}
+
+
+static void
+FlushWinFile (void)
+{
+       short ref;
+       long len;
+
+       if (!winFileInit) {
+               if (!winFileName [0]) {
+                       return;
+               }
+               HCreate (winFileVol, winFileDir, winFileName, MAC_CREATOR, PREF_TYPE);
+               HCreateResFile (winFileVol, winFileDir, winFileName);
+       }
+       if (HOpen (winFileVol, winFileDir, winFileName, fsWrPerm, &ref)) {
+               return;
+       }
+       winFileInit = 1;
+       len = sizeof (savePos);
+       (void) FSWrite (ref, &len, savePos); /* Don't care about error */
+       FSClose (ref);
+}
+
+Boolean
+RetrievePosition (short kind, short *top, short *left) {
+Point p;
+
+       if (kind < 0 || kind > kLastWindowKind) {
+               dprintf ("Retrieve Bad kind %d", kind);
+               return 0;
+       }
+       InitWinFile ();
+       if (!savePos [kind].validPos) {
+               dprintf ("Retrieve Not stored kind %d", kind);
+               return 0;
+       }
+       p.v = savePos [kind].top;
+       p.h = savePos [kind].left;
+       *left = p.h;
+       *top = p.v;
+       dprintf ("Retrieve Kind %d Pt (%d,%d)", kind, p.h, p.v);
+       return (PtInRgn (p, GetGrayRgn ()));
+}
+
+
+Boolean
+RetrieveSize (short kind, short top, short left, short *height, short *width)
+{
+       Point p;
+
+       if (kind < 0 || kind > kLastWindowKind) {
+               return 0;
+       }
+       InitWinFile ();
+       if (!savePos [kind].validSize) {
+               return 0;
+       }
+       *width = savePos [kind].width;
+       *height = savePos [kind].height;
+       p.h = left + *width;
+       p.v = top + *height;
+       return PtInRgn (p, GetGrayRgn ());
+}
+
+
+static void
+SavePosition (short kind, short top, short left)
+{
+       if (kind < 0 || kind > kLastWindowKind) {
+               dprintf ("Save bad kind %d", kind);
+               return;
+       }
+       InitWinFile();
+       savePos[kind].validPos = 1;
+       savePos[kind].top = top;
+       savePos[kind].left = left;
+       dprintf("Save kind %d pt (%d,%d)", kind, left, top);
+       FlushWinFile();
+}
+
+
+static void
+SaveSize (short kind, short height, short width)
+{
+       if (kind < 0 || kind > kLastWindowKind) {
+               dprintf ("Save bad kind %d", kind);
+               return;
+       }
+       InitWinFile ();
+       savePos [kind].validSize = 1;
+       savePos [kind].width = width;
+       savePos [kind].height = height;
+       FlushWinFile ();
+}
+
+
+static short
+GetWinKind (WindowPtr win)
+{
+       short kind;
+
+       if (!CheckNhWin (win)) {
+               return -1;
+       }
+       kind = GetWindowKind(win) - WIN_BASE_KIND;
+       if (kind < 0 || kind > NHW_TEXT) {
+               return -1;
+       }
+       dprintf ("In win kind %d (%lx)", kind, win);
+       switch (kind) {
+       case NHW_MAP :
+       case NHW_STATUS :
+       case NHW_BASE :
+               kind = kMapWindow;
+               break;
+       case NHW_MESSAGE :
+               kind = kMessageWindow;
+               break;
+       case NHW_MENU :
+               kind = kMenuWindow;
+               break;
+       default :
+               kind = kTextWindow;
+               break;
+       }
+       dprintf ("Out kind %d", kind);
+       return kind;
+}
+
+
+Boolean
+RetrieveWinPos(WindowPtr win, short *top, short *left)
+{
+       return RetrievePosition(GetWinKind (win), top, left);
+}
+
+
+void
+SaveWindowPos(WindowPtr win)
+{
+       Rect r;
+
+
+       GetWindowBounds(win, kWindowContentRgn, &r);
+       SavePosition(GetWinKind(win), r.top, r.left);
+}
+
+
+void
+SaveWindowSize(WindowPtr win)
+{
+       short width, height;
+       Rect r;
+
+
+       GetWindowBounds(win, kWindowContentRgn, &r);
+       width = r.right - r.left;
+       height = r.bottom - r.top;
+       SaveSize(GetWinKind (win), height, width);
+}
diff --git a/sys/mac/macerrs.c b/sys/mac/macerrs.c
new file mode 100644 (file)
index 0000000..12d419b
--- /dev/null
@@ -0,0 +1,170 @@
+/*     SCCS Id: @(#)macerrs.c  3.1     93/01/24                  */
+/* Copyright (c) Michael Hamel, 1991 */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#if defined(macintosh) && defined(__SC__) && !defined(__FAR_CODE__)
+/* this needs to be resident always */
+#pragma segment Main
+#endif
+
+#include "hack.h"
+#include "macwin.h"
+#if !TARGET_API_MAC_CARBON
+#include <Dialogs.h>
+#include <TextUtils.h>
+#include <Resources.h>
+#endif
+
+
+void error(const char *format,...)
+{
+       Str255 buf;
+       va_list ap;
+
+       va_start(ap, format);
+       vsprintf((char *)buf, format, ap);
+       va_end(ap);
+
+       C2P((char *)buf, buf);
+       ParamText(buf, (StringPtr)"", (StringPtr)"", (StringPtr)"");
+       Alert(128, (ModalFilterUPP) NULL);
+       ExitToShell();
+}
+
+
+#if 0  /* Remainder of file is obsolete and will be removed */
+
+#define stackDepth  1
+#define errAlertID 129
+#define stdIOErrID 1999
+
+static Str255 gActivities[stackDepth] = {""};
+static short gTopactivity = 0;
+
+void showerror(char * errdesc, const char * errcomment)
+{
+       short           itemHit;
+       Str255          paserr,
+                               pascomment;
+                               
+       SetCursor(&qd.arrow);
+       if (errcomment == nil) errcomment = "";
+       C2P (errcomment, pascomment);
+       C2P (errdesc, paserr);
+       ParamText(paserr,pascomment,gActivities[gTopactivity],(StringPtr)"");
+       itemHit = Alert(errAlertID, (ModalFilterUPP)nil);
+}
+
+Boolean itworked(short errcode)
+/* Return TRUE if it worked, do an error message and return false if it didn't. Error
+   strings for native C errors are in STR#1999, Mac errs in STR 2000-errcode, e.g
+   2108 for not enough memory */
+
+{
+       if (errcode != 0) {
+               short            itemHit;
+               Str255           errdesc;
+               StringHandle strh;
+       
+               errdesc[0] = '\0';
+               if (errcode > 0) GetIndString(errdesc,stdIOErrID,errcode);  /* STDIO file rres, etc */
+               else {
+                       strh = GetString(2000-errcode);
+                       if (strh != (StringHandle) nil) {
+                               memcpy(errdesc,*strh,256);
+                               ReleaseResource((Handle)strh);
+                       }
+               }
+               if (errdesc[0] == '\0') {  /* No description found, just give the number */
+                       sprintf((char *)&errdesc[1],"a %d error occurred",errcode);
+                       errdesc[0] = strlen((char*)&errdesc[1]);
+               }
+               SetCursor(&qd.arrow);
+               ParamText(errdesc,(StringPtr)"",gActivities[gTopactivity],(StringPtr)"");
+               itemHit = Alert(errAlertID, (ModalFilterUPP)nil);
+       }
+       return(errcode==0);
+}
+
+void mustwork(short errcode)
+/* For cases where we can't recover from the error by any means */
+{
+       if (itworked(errcode)) ;
+       else ExitToShell();
+}
+
+
+#if defined(USE_STDARG) || defined(USE_VARARGS)
+# ifdef USE_STDARG
+static void vprogerror(const char *line, va_list the_args);
+# else
+static void vprogerror();
+# endif
+
+/* Macro substitute for error() */
+void error VA_DECL(const char *, line)
+       VA_START(line);
+       VA_INIT(line, char *);
+       vprogerror(line, VA_ARGS);
+       VA_END();
+}
+
+# ifdef USE_STDARG
+static void
+vprogerror(const char *line, va_list the_args) {
+# else
+static void
+vprogerror(line, the_args) const char *line; va_list the_args; {
+# endif
+
+#else  /* USE_STDARG | USE_VARARG */
+
+void
+error VA_DECL(const char *, line)
+#endif
+/* Do NOT use VA_START and VA_END in here... see above */
+       char pbuf[BUFSZ];
+
+       if(index(line, '%')) {
+               Vsprintf(pbuf,line,VA_ARGS);
+               line = pbuf;
+       }
+       showerror("of an internal error",line);
+}
+
+
+void attemptingto(char * activity)
+/* Say what we are trying to do for subsequent error-handling: will appear as x in an
+   alert in the form "Could not x because y" */
+{      C2P(activity,gActivities[gTopactivity]);
+}
+
+void comment(char *s, long n)
+{
+       Str255 paserr;
+       short itemHit;
+       
+       sprintf((char *)&paserr[1], "%s - %d",s,n);
+       paserr[0] = strlen ((char*)&paserr[1]);
+       ParamText(paserr,(StringPtr)"",(StringPtr)"",(StringPtr)"");
+       itemHit = Alert(128, (ModalFilterUPP)nil);
+}
+
+void pushattemptingto(char * activity)
+/* Push a new description onto stack so we can pop later to previous state */
+{
+       if (gTopactivity < stackDepth) {
+               gTopactivity++;
+               attemptingto(activity);
+       }
+       else error("activity stack overflow");
+}
+
+void popattempt(void)
+/* Pop to previous state */
+{
+       if (gTopactivity > 1) --gTopactivity;
+       else error("activity stack underflow");
+}
+
+#endif /* Obsolete */
diff --git a/sys/mac/macfile.c b/sys/mac/macfile.c
new file mode 100644 (file)
index 0000000..535bf60
--- /dev/null
@@ -0,0 +1,465 @@
+/*     SCCS Id: @(#)macfile.c  3.1     93/01/24                  */
+/* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */
+/* NetHack may be freely redistributed.  See license for details. */
+/*
+ * macfile.c
+ * MAC file I/O routines
+ */
+
+#include "hack.h"
+#include "macwin.h"
+
+#ifndef __MACH__
+#include <files.h>
+#include <errors.h>
+#include <resources.h>
+#include <memory.h>
+#include <TextUtils.h>
+#include <ToolUtils.h>
+#endif
+
+#include "dlb.h"
+
+/*
+ * We should get the default dirID and volRefNum (from name) from prefs and
+ * the situation at startup... For now, this will have to do.
+ */
+
+
+/* The HandleFiles are resources built into the application which are treated
+   as read-only files: if we fail to open a file we look for a resource */
+   
+#define FIRST_HF 32000   /* file ID of first HandleFile */
+#define MAX_HF 6                /* Max # of open HandleFiles */
+
+#define APP_NAME_RES_ID                (-16396)
+
+typedef struct handlefile {
+       long            type;  /* Resource type */
+       short           id;     /* Resource id */
+       long            mark;  /* Current position */
+       long            size;  /* total size */
+       Handle          data;  /* The resource, purgeable */
+} HandleFile;
+
+static  HandleFile *FDECL(IsHandleFile,(int));
+static int FDECL(OpenHandleFile,(const unsigned char *, long));
+static int FDECL(CloseHandleFile,(int));
+static int FDECL(ReadHandleFile,(int, void *, unsigned));
+static long FDECL(SetHandleFilePos,(int, short, long));
+
+HandleFile theHandleFiles [MAX_HF];
+MacDirs theDirs;               /* also referenced in macwin.c */
+
+
+static HandleFile *
+IsHandleFile(int fd)
+{
+       HandleFile *hfp = NULL;
+
+       if (fd >= FIRST_HF && fd < FIRST_HF+MAX_HF) {
+               /* in valid range, check for data */
+               hfp = &theHandleFiles[fd-FIRST_HF];
+               if (!hfp->data) hfp = NULL;
+       }
+       return hfp;
+}
+
+
+static int
+OpenHandleFile (const unsigned char *name, long fileType)
+{
+       int i;
+       Handle h;
+       Str255 s;
+
+       for (i = 0; i < MAX_HF; i ++) {
+               if (theHandleFiles[i].data == 0L) break;
+       }
+       
+       if (i >= MAX_HF)
+               return -1;
+
+       h = GetNamedResource (fileType, name);
+       if (!h) return (-1);
+       
+       theHandleFiles[i].data = h;
+       theHandleFiles[i].size = GetHandleSize (h);
+       GetResInfo (h, &theHandleFiles[i].id, (void*) &theHandleFiles[i].type, s);
+       theHandleFiles[i].mark = 0L;
+
+       return(i + FIRST_HF);
+}
+
+
+static int
+CloseHandleFile (int fd)
+{
+       if (!IsHandleFile (fd)) {
+          return -1;
+       }
+       fd -= FIRST_HF;
+       ReleaseResource (theHandleFiles[fd].data);
+       theHandleFiles[fd].data = 0L;
+       return(0);
+}
+
+
+static int
+ReadHandleFile (int fd, void *ptr, unsigned len)
+{
+       unsigned maxBytes;
+       Handle h;
+
+       if (!IsHandleFile (fd)) return -1;
+       
+       fd -= FIRST_HF;
+       maxBytes = theHandleFiles[fd].size - theHandleFiles[fd].mark;
+       if (len > maxBytes) len = maxBytes;
+       
+       h = theHandleFiles[fd].data;
+       
+       HLock(h);
+       BlockMove (*h + theHandleFiles[fd].mark, ptr, len);
+       HUnlock(h);
+       theHandleFiles[fd].mark += len;
+       
+       return(len);
+}
+
+
+static long
+SetHandleFilePos (int fd, short whence, long pos)
+{
+       long curpos;
+       
+       if (!IsHandleFile (fd)) return -1;
+       
+       fd -= FIRST_HF;
+       
+       curpos = theHandleFiles [fd].mark;
+       switch (whence) {
+               case SEEK_CUR : 
+                       curpos += pos;
+                       break;
+               case SEEK_END : 
+                       curpos = theHandleFiles[fd].size  - pos;
+                       break;
+               default : /* set */
+                       curpos = pos;
+                       break;
+       }
+
+       if (curpos < 0)
+               curpos = 0;
+       else if (curpos > theHandleFiles [fd].size)
+               curpos = theHandleFiles [fd].size;
+       
+       theHandleFiles [fd].mark = curpos;
+       
+       return curpos;
+}
+
+
+void
+C2P (const char *c, unsigned char *p)
+{
+       int len = strlen (c), i;
+
+       if (len > 255) len = 255;
+
+       for (i = len; i > 0; i--)
+               p[i] = c[i-1];
+       p[0] = len;
+}
+
+void
+P2C (const unsigned char *p, char *c)
+{
+       int idx = *p++;
+       for (; idx > 0; idx--)
+               *c++ = *p++;
+       *c = '\0';
+}
+
+
+static void
+replace_resource(Handle new_res, ResType its_type, short its_id, Str255 its_name)
+{
+       Handle old_res;
+
+       SetResLoad(false);
+       old_res = Get1Resource(its_type, its_id);
+       SetResLoad(true);
+       if (old_res) {
+               RemoveResource(old_res);
+               DisposeHandle(old_res);
+       }
+
+       AddResource(new_res, its_type, its_id, its_name);
+}
+
+
+int
+maccreat (const char *name, long fileType){
+       return macopen (name, O_RDWR | O_CREAT | O_TRUNC, fileType);
+}
+
+
+int
+macopen (const char *name, int flags, long fileType)
+{
+       short refNum;
+       short perm;
+       Str255 s;
+
+       C2P (name, s);
+       if (flags & O_CREAT) {
+               if (HCreate (theDirs.dataRefNum, theDirs.dataDirID, s ,
+                       TEXT_CREATOR, fileType) && (flags & O_EXCL)) {
+                       return -1;
+               }
+
+               if (fileType == SAVE_TYPE) {
+                       short resRef;
+                       HCreateResFile(theDirs.dataRefNum, theDirs.dataDirID, s);
+                       resRef = HOpenResFile(theDirs.dataRefNum, theDirs.dataDirID, s,
+                                                                 fsRdWrPerm);
+                       if (resRef != -1) {
+                               Handle name;
+                               Str255 plnamep;
+
+                               C2P(plname, plnamep);
+                               name = (Handle)NewString(plnamep);
+                               if (name)
+                                       replace_resource(name, 'STR ', PLAYER_NAME_RES_ID,
+                                                                       "\pPlayer Name");
+
+                               /* The application name resource.  See IM VI, page 9-21. */
+                               name = (Handle)GetString(APP_NAME_RES_ID);
+                               if (name) {
+                                       DetachResource(name);
+                                       replace_resource(name, 'STR ', APP_NAME_RES_ID,
+                                                                        "\pApplication Name");
+                               }
+
+                               CloseResFile(resRef);
+                       }
+               }
+
+       }
+       /*
+        * Here, we should check for file type, maybe a SFdialog if
+        * we fail with default, etc. etc. Besides, we should use HOpen
+        * and permissions.
+        */
+       if ((flags & O_RDONLY) == O_RDONLY) {
+               perm = fsRdPerm;
+       }
+       if ((flags & O_WRONLY) == O_WRONLY) {
+               perm = fsWrPerm;
+       }
+       if ((flags & O_RDWR) == O_RDWR) {
+               perm = fsRdWrPerm;
+       }
+       if (HOpen (theDirs.dataRefNum, theDirs.dataDirID, s, perm, &refNum)) {
+               return OpenHandleFile (s, fileType);
+       }
+       if (flags & O_TRUNC) {
+               if (SetEOF (refNum, 0L)) {
+                       FSClose (refNum);
+                       return -1;
+               }
+       }
+       return refNum;
+}
+
+
+int
+macclose (int fd)
+{
+       if (IsHandleFile (fd)) {
+               CloseHandleFile (fd);
+       } else {
+               if (FSClose (fd)) {
+                       return -1;
+               }
+               FlushVol ((StringPtr) 0, theDirs . dataRefNum);
+       }
+       return 0;
+}
+
+
+int
+macread (int fd, void *ptr, unsigned len)
+{
+       long amt = len;
+       
+       if (IsHandleFile (fd)) {
+               return ReadHandleFile (fd, ptr, amt);
+       } else {
+               short err = FSRead (fd, &amt, ptr);
+
+               return ((err == noErr) || (err == eofErr && len)) ? amt : -1;
+       }
+}
+
+
+#if 0 /* this function isn't used, if you use it, uncomment prototype in macwin.h */
+char *
+macgets (int fd, char *ptr, unsigned len)
+{
+        int idx = 0;
+        char c;
+
+        while (-- len > 0) {
+                if (macread (fd, ptr + idx, 1) <= 0)
+                        return (char *)0;
+                c = ptr[idx++];
+                if (c  == '\n' || c == '\r')
+                        break;
+        }
+        ptr [idx] = '\0';
+        return ptr;
+}
+#endif /* 0 */
+
+
+int
+macwrite (int fd, void *ptr, unsigned len)
+{
+       long amt = len;
+
+       if (IsHandleFile (fd)) return -1;
+       if (FSWrite(fd, &amt, ptr) == noErr)
+               return (amt);
+       else
+               return (-1);
+}
+
+
+long
+macseek (int fd, long where, short whence)
+{
+       short posMode;
+       long curPos;
+
+       if (IsHandleFile (fd)) {
+               return SetHandleFilePos (fd, whence, where);
+       }
+
+       switch (whence) {
+               default :
+                       posMode = fsFromStart;
+                       break;
+               case SEEK_CUR :
+                       posMode = fsFromMark;
+                       break;
+               case SEEK_END :
+                       posMode = fsFromLEOF;
+                       break;
+       }
+
+       if (SetFPos(fd, posMode, where) == noErr && GetFPos(fd, &curPos) == noErr)
+               return (curPos);
+       else
+               return(-1);
+}
+
+
+int
+macunlink(const char *name)
+{
+       Str255 pname;
+
+
+       C2P(name, pname);
+       return (HDelete(theDirs.dataRefNum, theDirs.dataDirID, pname) == noErr ? 0 : -1);
+}
+
+
+
+/* ---------------------------------------------------------------------- */
+
+boolean rsrc_dlb_init(void) {
+       return TRUE;
+}
+
+void rsrc_dlb_cleanup(void) {
+}
+
+boolean rsrc_dlb_fopen(dlb *dp, const char *name, const char *mode) {
+#if defined(__SC__) || defined(__MRC__)
+# pragma unused(mode)
+#endif
+       Str255 pname;
+       
+       C2P(name, pname);
+       dp->fd = OpenHandleFile(pname, 'File'); /* automatically read-only */
+       return dp->fd >= 0;
+}
+
+int rsrc_dlb_fclose(dlb *dp) {
+       return CloseHandleFile(dp->fd);
+}
+
+int rsrc_dlb_fread(char *buf, int size, int quan, dlb *dp) {
+       int nread;
+
+       if (size < 0 || quan < 0) return 0;
+       nread = ReadHandleFile(dp->fd, buf, (unsigned)size * (unsigned)quan);
+       
+       return nread/size;      /* # of whole pieces (== quan in normal case) */
+}
+
+int rsrc_dlb_fseek(dlb *dp, long pos, int whence) {
+       return SetHandleFilePos(dp->fd, whence, pos);
+}
+
+char *rsrc_dlb_fgets(char *buf, int len, dlb *dp) {
+       HandleFile *hfp = IsHandleFile(dp->fd);
+       char *p;
+       int bytesLeft, n = 0;
+
+       if (hfp && hfp->mark < hfp->size) {
+               bytesLeft = hfp->size - hfp->mark;
+               if (bytesLeft < len)
+                       len = bytesLeft;
+
+               HLock(hfp->data);
+               for (n = 0, p = *hfp->data+hfp->mark; n < len; n++, p++) {
+                       buf[n] = *p;
+                       if (*p == '\r') buf[n] = '\n';
+                       if (buf[n] == '\n') {
+                               n++;            /* we want the return in the buffer */
+                               break;
+                       }
+               }
+               HUnlock(hfp->data);
+
+               hfp->mark += n;
+               if (n != 0)
+                       buf[n] = '\0';  /* null terminate result */
+       }
+
+       return n ? buf : NULL;
+}
+
+int rsrc_dlb_fgetc(dlb *dp) {
+       HandleFile *hfp = IsHandleFile(dp->fd);
+       int ret;
+
+       if (!hfp || hfp->size <= hfp->mark) return EOF;
+
+       ret = *(unsigned char *)(*hfp->data + hfp->mark);
+       hfp->mark++;
+       return ret;
+}
+
+long rsrc_dlb_ftell(dlb *dp) {
+       HandleFile *hfp = IsHandleFile(dp->fd);
+
+       if (!hfp) return 0;
+       return hfp->mark;
+}
+
diff --git a/sys/mac/machelp.hqx b/sys/mac/machelp.hqx
new file mode 100644 (file)
index 0000000..5f92520
--- /dev/null
@@ -0,0 +1,67 @@
+(This file must be converted with BinHex 4.0)
+
+:#QeKBfKPE(!ZBQJ!9%9B9%0A588"#!!!#PX!!!'XRNmM#90$3e-J5@3k)%!S)bP
+YB@0SC@a`,Q*S#6-Z-`Nj15m`-bma03dM#80[F(PbD@GSG#!SBbNJ-6Nj1#da16N
+j)'*j)%YPGQPZ)%KeCfm0)b"1CA4)B@0V)'eKH5"LC5"QFQ9PE(NJFQ9NDA0dFQP
+LGA4PC#iJ)&0PC5"XD@0PER0P)'C[FL"NCA4KD@ac,Jd0$5-M)b""FfYZB@eP)'4
+TB@a[Cb!M)b-04%P"6%p()$B`-$!JBA0VEQ&YC3d0)b"3E'&j)'*eG(4[EJda,Q9
+ZB@*XC@3J3faTBfXJD'9bC5"dEb"`E'&j)(4SDA-JBfKKFQ&MG'9b,Jda,Q4TFf&
+LE'9N)%0XD@0V)'KPFQ8JG'mJF'aKH5"dD'Pc)'0SBA*KBh4PFLl#$5!J6Qpd)'&
+fB@PXB@*XC5"LC@0KGA0P)(P[G5"SBACPELGd)(4jF'9N)'PZ)'%JEQ&YC5i0$5-
+J8A9TG#"LGA4dEfi0-LiU)%0XD@0V)'KPFQ8JG'mJFA9TG#"dD'8JF(*[Ch*KE5i
+0$5-J8QpXC5"`Eh"eF#"YC@je$63Z+L"6C@aPBh3JH@peFL"NCA0TFQ9N)(*[E'8
+J+%&bBfKPEfa[CfPcG#`J3Q&bBQ&bD@&Z,#"PG'-Z+F)0)(GTG'JJG'KTFb"`Eh"
+eF#"YC@je,Jd0)b"5B@0P)("[F(9`)'ePER8005iU)&0PE'9MG#"jEh9b)'4PFfP
+bC@3JFQ&MC5!S5(9YB@iX)%9XCL`JCA4M,LR#$5"hDA4S)(4SDA-JF'p`GA!JE@9
+ZG5i0$5-J4f9ZC'9b)("[F(9`)'ePER800LiU)&0PE'9MG#"jEh9b)'GPEQ4PFL!
+SE@&XC5"[FL"QC@eKE'8T)(GTG'JJG'KTFb"`Eh"eF#"YC@je,Jd0)b""E'PREQe
+PER3JF'p`GA!JE@9ZG3dh,LSJ8f9XC@0d)(P[GA)JB@aTCfjYC@jd)#KXBAGQG@`
+X)'jPGA4bB@`X)'pb)'0SB@pdD@-T`JdJGfPdD#"dD'Pc)("[F(9`)'ePER8Z$3d
+M)%e[C'8JF'p`GA!JE@9ZG3di,LSJ9A0P)(4SDA-JF'p`GA!JE@9ZG5"dEb"cC@a
+PBh3JFQ9RG@aKFL"`E'&j)'e[C'8X`JdJCAK`E'pbC5"YEf4P,#"[FL"NC@*eCfG
+TEQFJE@pNC5i0$5-J6Q&YC5"dCAKd)'PdC@d015iU)&4jF'8JD@iJH@peFL"MD'&
+bB@0dCA)RFb"ZB@eP)'KPFQ8Z$3dM)%PMEfi0-6!Z+L"AD'mJDA-JG'KTFb"RGAN
+r$3e&6N3Y4%P"6%p($3d0689195!a-MJJ3A"`E'80$6%ZC@jKBQaPC#"%DA0`E'&
+jFb"TEQC[FQeKG'P[EL"KBQpeG#"dD'Pc)(CPFR0TEfiZ$3e&6N3Y689193d0$8e
+&6P8J-6)j)%CTE'80$6!ZC@jKBQaPC#"'D@aP)%ePERA#`P9cC5"dD'Pc)'ePER8
+JG'mJE@&ZDA"eE'&dC5"hD@jNEhGc`JdJEfiJG'KP)(0MFQ9PEL`JB@jN)(4[)(0
+KGQ8JEh)JFA9TG#"dD'8JCf&YC5i0$6%Z+L"0B@YPFb"dD'8JE@&`)'&`F'9KFL"
+[EL"dD'8JFf0bC@9Z,#"TEL"MBA0P)(P[G5"ME'pcC@6#$5"TG(-JGfPZC'ph,Jd
+0-LiU)%C[FQ0PFb"dD'8JE@&`)(4[)'*P)(*PC(*KGfiZ$3dc,LSJ8f0bEfaXFb"
+dD'8J6@9cFf&RCA-JGfPZC'ph)'*KBfXJEfjP)'ePFh0KCf8Z$3dd,LSJ8Q9`Eh0
+TG'P[ER-JB@aX)(GTEQ4[Gh-JFfmJG'KPH5"KFQ8JEfiYFf0bC@9Z,Jd005iU)%0
+XEh0PFb"dD'8JCR*[ER4YEh0d)(GTEQ4[Gbi0$6JZ+L"&ER4PFR-JCAK`E'pbC5"
+YEf4P,#"hD'PMD#"TFb"K)'G[Ef3JGf&j)(4[)'aPBA*Z)(4SC5"RB@eP,Jd0-6!
+Z+L"6BACPFb"dD'8JCf&YC5`JB@jN)(4SC@iJFA9TG(-JG'KP)("bEfGbB@dZ$3d
+a-LiU)&&eDA4c)(4SC5"`FQpRFQ&Y)(GTG'K[GA3JFf&fD@jR)(4SC5"RB@eP,Jd
+048j%,8e&6P80$3e048j9)$%c-#"&C'Pd$3d`,Q9ZB@*XC@3J4@4TG#"0C@je`X*
+9Ff8JG'KTFb"YC@je)(4[)'9NDA3JG'9iG#"[FL"eEQ4[`JdJB@iJB@0dD@pZ,Jd
+`,Q4TFf&LE'9N)%9NDA3J6@9ZGF,#9A0P)(4SDA-JE@9ZG5"dEb"PC'Pd)(4PH(3
+JEh)JG@jNEm)0)'&Z)'&MG'P[ELiJ)%&fB@PXB@*XC5"[EQaj)'C[FL"NCA0V)'&
+MBf9cFfpbD@9c,Jd048j%,8e&6P80$3e048j9)$%c-5",BQ30$6!ZC@jKBQaPC#"
+,CAPLEf&bC#"0C@je`X*9Ff8JG'KTFb"YC@je)(4[)(0TEA9XBA4P`JdJF(*PFh0
+TEQFJDf9jFb"[EL"K)'YPH@*[BA*N,#"cEb"jEh8JBf&Z)("XBANJC@jdDA*PE(R
+#$5"LH5"YEh9cC5i0$8914#e048j9$3d0689195!a-c)J5'9XF!d0-#jPEQ&LE'9
+N)%KPE(!J6@9ZGF,#9A0P)(4SDA-JE@9ZG5"dEb"PH("XB@PZ)'K[Gm)0)(4SC5"
+RB@eP)(G[FQYc,#"[FL"dEb"cCA3JEh"dD@pZFbi0$8914#e048j9$3d0689195!
+a-c-J5@jQE`d0-#jPEQ&LE'9N)%PZCQmJ6@9ZGF,#9A0P)(4SDA-JE@9ZG5"dEb"
+XEfpV)'&d)'pb`JdJE@&ZDA"eE'&dC5"jEh9b)'PZGQ9ZG'pbH5`JCAK`E'&TEL"
+cEfePG'KTEQFJEfiJG'KP`JdJFf0bC@9Z,#"[FL"RDACP)'&Z)'pLDQ9MG#"[FL"
+YEfjcG'9b)'%JEQ&YC5i0$8914#e048j9$3d0689195!a-c3J4A&eDA!0$6!ZC@j
+KBQaPC#"&FA9TF'ePER3J6@9ZGF,#9A0P)(4SDA-JE@9ZG5"dEb"YB@jTF(9XBA4
+P`JdJGf9KF'pZFb`JBA*YEh)X)'&ZC#"[G'KPFL"hEh*Z)'PdC@ec,Jd048j%,8e
+&6P80$3e048j9)$%c05""Bh30$6!ZC@jKBQaPC#""Bh4TEfiJ6@9ZGF,#9A0P)(4
+SDA-JE@9ZG5"dEb"`CA*QEh*Y)'&Z)'&MG'P[ELi0$8914#e048j9$3d0689195!
+a-cBJ6@&RD@-0$6!ZC@jKBQaPC#"0B@GTBb"0C@je`X*9Ff8JG'KTFb"YC@je)(4
+[)'eKEQP`G@aKG'8JE@&RD@2#$5"TG'9YFbi0$8914#e048j9$3e048j9)$%c0b"
+#DA4c$3d`,Q9ZB@*XC@3J3QPdFb"0C@je`X*9Ff8JG'KTFb"YC@je)(4[)("PFQC
+[FQh#$5"YDA0MC@aXB@jPEh9c)'&MG'P[ER-Z$3e&6N3Y689193d048j%$5dp!!!
+"!!!!!9S!!!"D!!!!8KY`!4m!6VVdjL!ZrqU`RfF-2`B["5m-U"YJ!!$+9Bmr#Qe
+KBfKPE(!ZBQKbUL"*4%8J8(*PCR0TEfjMCA0PFfi!$&4&@&4$9dP&!3Mrrrrr!!!
+!!!!!!!!!!!!!!!!!!!K$XNab!!!!#PX!!!'XmNkkqQSq(fCU9Bmr,[r`5'lrpNK
+ZrrK)E[rm6VVpU$iICP"9Mh!!,`!r"Lm&6VVkKMiICJS[$+Qa9BqTVciIF!+`V[r
+iCKC9Mh!!,`!r,[r`,blrmNkkqPik(f!39Bp`!#m!2blrm%kkpFJk(dT(CJ)q"6(
+(#Q"-lK$JrpT1AL"I6`!!!%J!#8e[EQ&ME`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!)!"!!V!+F"dJ*H!#X!T`(5!Pkc58b!!!!!!!!!#PX!!!!!!3!!!!!#!!!
+!!!!%!!%!!!!!!3!!!!&D!!!!@J!!!&)"ITa%(YS!!!!F!&)!!8e38e)!!3!569G
+#3J!!!#S$lIrr!!!!!!!!!!!$lrrr!!!!6!!!!!!$m2rr!!!!8J!!!!#PK!:
diff --git a/sys/mac/macmain.c b/sys/mac/macmain.c
new file mode 100644 (file)
index 0000000..670283a
--- /dev/null
@@ -0,0 +1,288 @@
+/*     SCCS Id: @(#)macmain.c  3.1     97/01/22        */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* main.c - Mac NetHack */
+
+#include "hack.h"
+#include "dlb.h"
+#include "macwin.h"
+#include "mactty.h"
+
+#if !TARGET_API_MAC_CARBON
+#include <OSUtils.h>
+#include <files.h>
+#include <Types.h>
+#include <Dialogs.h>
+#include <Packages.h>
+#include <ToolUtils.h>
+#include <Resources.h>
+#include <Errors.h>
+#endif
+
+#ifndef O_RDONLY
+#include <fcntl.h>
+#endif
+
+static void finder_file_request(void);
+int main(void);
+
+#if __SC__ || __MRC__
+QDGlobals qd;
+#endif
+
+
+int
+main (void)
+{
+       register int fd = -1;
+       int argc = 1;
+
+       windowprocs = mac_procs;
+       InitMac ();
+
+       hname = "Mac Hack";
+       hackpid = getpid();
+
+       /*
+        * Initialisation of the boundaries of the mazes
+        * Both boundaries have to be even.
+        */
+
+       x_maze_max = COLNO-1;
+       if (x_maze_max % 2)
+               x_maze_max--;
+       y_maze_max = ROWNO-1;
+       if (y_maze_max % 2)
+               y_maze_max--;
+
+       setrandom();
+       initoptions();
+       init_nhwindows(&argc, (char **)&hname);
+
+       /*
+        * It seems you really want to play.
+        */
+       u.uhp = 1;      /* prevent RIP on early quits */
+
+       finder_file_request ();
+
+       dlb_init();             /* must be before newgame() */
+
+       /*
+        *  Initialize the vision system.  This must be before mklev() on a
+        *  new game or before a level restore on a saved game.
+        */
+       vision_init();
+
+       display_gamewindows();
+
+#ifdef WIZARD
+       if (wizard)
+               Strcpy(plname, "wizard");
+       else
+#endif
+       if(!*plname || !strncmp(plname, "player", 4) || !strncmp(plname, "games", 4))
+               askname();
+       plnamesuffix();         /* strip suffix from name; calls askname() */
+                               /* again if suffix was whole name */
+                               /* accepts any suffix */
+
+       Sprintf (lock, "%d%s", getuid (), plname);
+       getlock ();
+
+       if ((fd = restore_saved_game()) >= 0) {
+#ifdef WIZARD
+               /* Since wizard is actually flags.debug, restoring might
+                * overwrite it.
+                */
+               boolean remember_wiz_mode = wizard;
+#endif
+#ifdef NEWS
+               if(iflags.news) {
+                       display_file(NEWS, FALSE);
+                       iflags.news = FALSE;    /* in case dorecover() fails */
+               }
+#endif
+               pline("Restoring save file...");
+               mark_synch();   /* flush output */
+               game_active = 1;
+               if (dorecover(fd)) {
+#ifdef WIZARD
+                       if(!wizard && remember_wiz_mode) wizard = TRUE;
+#endif
+                       check_special_room(FALSE);
+
+                       if (discover || wizard) {
+                               if(yn("Do you want to keep the save file?") == 'n')
+                                       (void) delete_savefile();
+                               else {
+                                       compress(fqname(SAVEF, SAVEPREFIX, 0));
+                               }
+                       }
+               }
+               else {
+                       fd = -1; /* set bad status */
+               }
+       }
+       if (fd < 0) {
+               player_selection();
+               game_active = 1;        /* done with selection, draw active game window */
+               newgame();
+               set_wear();
+               (void) pickup(1);
+       }
+
+       if (discover)
+               You("are in non-scoring discovery mode.");
+       flags.move = 0;
+
+       UndimMenuBar (); /* Yes, this is the place for it (!) */
+       
+       moveloop();
+
+       exit(EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
+
+
+static OSErr
+copy_file(short src_vol, long src_dir, short dst_vol, long dst_dir,
+               Str255 fName,
+               pascal OSErr (*opener)(short vRefNum, long dirID,
+                                                               ConstStr255Param fileName,
+                                                               signed char permission, short *refNum)) {
+       short src_ref, dst_ref;
+       OSErr err = (*opener)(src_vol, src_dir, fName, fsRdPerm, &src_ref);
+       if (err == noErr) {
+               err = (*opener)(dst_vol, dst_dir, fName, fsWrPerm, &dst_ref);
+               if (err == noErr) {
+
+                       long file_len;
+                       err = GetEOF(src_ref, &file_len);
+                       if (err == noErr) {
+                               Handle buf;
+                               long count = MaxBlock();
+                               if (count > file_len)
+                                       count = file_len;
+
+                               buf = NewHandle(count);
+                               err = MemError();
+                               if (err == noErr) {
+
+                                       while (count > 0) {
+                                               OSErr rd_err = FSRead(src_ref, &count, *buf);
+                                               err = FSWrite(dst_ref, &count, *buf);
+                                               if (err == noErr)
+                                                       err = rd_err;
+                                               file_len -= count;
+                                       }
+                                       if (file_len == 0)
+                                               err = noErr;
+
+                                       DisposeHandle(buf);
+
+                               }
+                       }
+                       FSClose(dst_ref);
+               }
+               FSClose(src_ref);
+       }
+
+       return err;
+}
+
+static void
+force_hdelete(short vol, long dir, Str255 fName)
+{
+       HRstFLock(vol, dir, fName);
+       HDelete (vol, dir, fName);
+}
+
+
+void
+process_openfile (short src_vol, long src_dir, Str255 fName, OSType ftype)
+{
+       OSErr   err = noErr;
+       
+       if (ftype != SAVE_TYPE)
+               return;         /* only deal with save files */
+               
+       if (src_vol != theDirs.dataRefNum || src_dir != theDirs.dataDirID &&
+                CatMove(src_vol, src_dir, fName, theDirs.dataDirID, "\p:") != noErr) {
+
+               HCreate(theDirs.dataRefNum, theDirs.dataDirID, fName, MAC_CREATOR, SAVE_TYPE);
+               err = copy_file(src_vol, src_dir, theDirs.dataRefNum, theDirs.dataDirID,
+                                               fName, &HOpen); /* HOpenDF is only there under 7.0 */
+               if (err == noErr)
+                       err = copy_file(src_vol, src_dir, theDirs.dataRefNum, theDirs.dataDirID,
+                                                       fName, &HOpenRF);
+               if (err == noErr)
+                       force_hdelete(src_vol, src_dir, fName);
+               else
+                       HDelete(theDirs.dataRefNum, theDirs.dataDirID, fName);
+       }
+
+       if (err == noErr) {
+               short ref;
+
+               ref = HOpenResFile(theDirs.dataRefNum, theDirs.dataDirID, fName, fsRdPerm);
+               if (ref != -1) {
+                       Handle name = Get1Resource('STR ', PLAYER_NAME_RES_ID);
+                       if (name) {
+                               Str255 save_f_p;
+                               P2C(*(StringHandle)name, plname);
+                               set_savefile_name();
+                               C2P(fqname(SAVEF, SAVEPREFIX, 0), save_f_p);
+                               force_hdelete(theDirs.dataRefNum, theDirs.dataDirID, save_f_p);
+
+                               if (HRename(theDirs.dataRefNum, theDirs.dataDirID, fName, save_f_p) == noErr)
+                                       macFlags.gotOpen = 1;
+                       }
+                       CloseResFile(ref);
+               }
+       }
+}
+
+
+static void
+finder_file_request(void)
+{
+       if (macFlags.hasAE) {
+               /* we're capable of handling Apple Events, so let's see if we have any */
+               EventRecord event;
+               long toWhen = TickCount () + 20;        /* wait a third of a second for all initial AE */
+
+               while (TickCount () < toWhen) {
+                       if (WaitNextEvent (highLevelEventMask, &event, 3L, 0)) {
+                               AEProcessAppleEvent(&event);
+                               if (macFlags.gotOpen)
+                                       break;
+                       }
+               }       
+       }
+#if 0
+#ifdef MAC68K
+       else {
+               short finder_msg, file_count;
+               CountAppFiles(&finder_msg, &file_count);
+               if (finder_msg == appOpen && file_count == 1) {
+                       OSErr   err;
+                       AppFile src;
+                       FSSpec filespec;
+
+                       GetAppFiles(1, &src);
+                       err = FSMakeFSSpec(src.vRefNum, 0, src.fName, &filespec);
+                       if (err == noErr && src.fType == SAVE_TYPE) {
+                               process_openfile (filespec.vRefNum, filespec.parID, filespec.name, src.fType);
+                               if (macFlags.gotOpen)
+                                       ClrAppFiles(1);
+                       }
+               }
+       }
+#endif /* MAC68K */
+#endif /* 0 */
+}
+
+/*macmain.c*/
diff --git a/sys/mac/macmenu.c b/sys/mac/macmenu.c
new file mode 100644 (file)
index 0000000..9366865
--- /dev/null
@@ -0,0 +1,1196 @@
+/*     SCCS Id: @(#)macmenu.c  3.4     1999/11/24      */
+/*      Copyright (c) Macintosh NetHack Port Team, 1993.          */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/****************************************\
+ * Extended Macintosh menu support
+ *
+ * provides access to all keyboard commands from cmd.c
+ * provides control key functionality for classic keyboards
+ * provides key equivalent references and logical menu groups
+ * supports various menu highlighting modes
+\****************************************/
+
+/****************************************\
+ * Edit History:
+ *
+ * 930512      - More bug fixes and getting tty to work again, Jon W{tte
+ * 930508      - Bug fixes in-flight, Jon W{tte
+ * 04/29/93 - 1st Release Draft, David Hairston
+ * 04/11/93 - 1st Draft, David Hairston
+\****************************************/
+
+/******** Application Defines ********/
+#include "hack.h"
+#include "mactty.h"
+#include "macwin.h"
+#include "macpopup.h"
+#include "patchlevel.h"
+
+/******** Toolbox Defines ********/
+#if !TARGET_API_MAC_CARBON
+#include <Menus.h>
+#include <Devices.h>
+#include <Resources.h>
+#include <TextUtils.h>
+#include <ToolUtils.h>
+#include <Sound.h>
+#endif
+
+/* Borrowed from the Mac tty port */
+extern WindowPtr _mt_window;
+
+/******** Local Defines ********/
+
+/* 'MNU#' (menu list record) */
+typedef union menuRefUnn
+{
+       short           mresID;         /* MENU resource ID (before GetMenu) */
+       MenuHandle      mhnd;           /* MENU handle (after GetMenu) */
+} menuRefUnn;
+
+typedef struct menuListRec
+{
+       short           firstMenuID;
+       short           numMenus;
+       menuRefUnn      mref[];
+} menuListRec, *menuListPtr, **menuListHandle;
+
+/* indices and resource IDs of the menu list data */
+enum
+{
+       listMenubar,
+       listSubmenu,
+
+       menuBarListID = 128,
+       subMenuListID
+};
+
+/* the following mref[] indices are reserved */
+enum
+{
+       /* menu bar */
+       menuApple,
+       menuFile,
+       menuEdit,
+
+       /* submenu */
+       menuWizard = 0
+};
+
+/* the following menu items are reserved */
+enum
+{
+       /* apple */
+       menuAppleAboutBox = 1,
+       ____Apple__1,
+
+       /* File */
+       menuFileRedraw = 1,
+       menuFilePrevMsg,
+       menuFileCleanup,
+       ____File___1,
+       menuFilePlayMode,
+       menuFileEnterExplore,
+       ____File___2,
+       menuFileSave,
+       ____File___3,
+       menuFileQuit,
+
+       /* standard minimum Edit menu items */
+
+       /* Wizard */
+       menuWizardAttributes = 1
+};
+
+
+/*
+ * menuListRec data (preloaded and locked) specifies the number of menus in
+ * the menu bar, the number of hierarchal or submenus and the menu IDs of
+ * all of those menus.  menus that go into in the menu bar are specified by
+ * 'MNU#' 128 and submenus are specified by 'MNU#' 129.  the fields of the
+ * menuListRec are:
+ * firstMenuID - the menu ID (not resource ID) of the 1st menu.  subsequent
+ *     menus in the list are _forced_ to have consecutively incremented IDs.
+ * numMenus - the total count of menus in a given list (and the extent of
+ *     valid menu IDs).
+ * mref[] - initially the MENU resource ID is stored in the placeholder for
+ *     the resource handle.  after loading (GetResource), the menu handle
+ *     is stored and the menu ID, in memory, is set as noted above.
+ *
+ * NOTE: a ResEdit template editor is supplied to edit the 'MNU#' resources.
+ *
+ * NOTE: the resource IDs do not need to match the menu IDs in a menu list
+ * record although they have been originally set that way.
+ *
+ * NOTE: the menu ID's of menus in the submenu list record may be reset, as
+ * noted above.  it is the programmers responsibility to make sure that
+ * submenu references/IDs are valid.
+ *
+ * WARNING: the existence of the submenu list record is assumed even if the
+ * number of submenus is zero.  also, no error checking is done on the
+ * extents of the menu IDs.  this must be correctly setup by the programmer.
+ */
+
+#define ID1_MBAR       pMenuList[listMenubar]->firstMenuID
+#define ID1_SUBM       pMenuList[listSubmenu]->firstMenuID
+
+#define NUM_MBAR       pMenuList[listMenubar]->numMenus
+#define NUM_SUBM       pMenuList[listSubmenu]->numMenus
+
+#define MHND_APPLE     pMenuList[listMenubar]->mref[menuApple].mhnd
+#define MHND_FILE      pMenuList[listMenubar]->mref[menuFile].mhnd
+#define MHND_EDIT      pMenuList[listMenubar]->mref[menuEdit].mhnd
+
+#define MBARHND(x)     pMenuList[listMenubar]->mref[(x)].mhnd
+
+#define MHND_WIZ       pMenuList[listSubmenu]->mref[menuWizard].mhnd
+
+
+/* mutually exclusive (and prioritized) menu bar states */
+enum
+{
+       mbarDim,
+       mbarNoWindows,
+       mbarDA,
+       mbarNoMap,
+       mbarRegular,
+       mbarSpecial                                     /* explore or debug mode */
+};
+
+#define WKND_MAP               (WIN_BASE_KIND + NHW_MAP)
+
+
+/* menu routine error numbers */
+enum
+{
+       errGetMenuList,
+       errGetMenu,
+       errGetANDlogTemplate,
+       errGetANDlogItems,
+       errGetANDialog,
+       errANNewMenu,
+       err_Menu_total
+};
+
+
+/* menu 'STR#' comment char */
+#define mstrEndChar            0xA5            /* '\245' or option-* or "bullet" */
+
+/* 'ALRT' */
+enum
+{
+       alrt_Menu_start = 5000,
+       alrtMenuNote = alrt_Menu_start,
+       alrtMenu_NY,
+       alrt_Menu_limit
+};
+
+#define beepMenuAlertErr       1               /* # of SysBeep()'s before exitting */
+enum
+{
+       bttnMenuAlertNo = 1,
+       bttnMenuAlertYes
+};
+
+
+/******** Globals ********/
+static unsigned char *menuErrStr[err_Menu_total] = 
+       {
+               "\pAbort: Bad \'MNU#\' resource!",              /* errGetMenuList */
+               "\pAbort: Bad \'MENU\' resource!",              /* errGetMenu */
+               "\pAbort: Bad \'DLOG\' resource!",              /* errGetANDlogTemplate */
+               "\pAbort: Bad \'DITL\' resource!",              /* errGetANDlogItems */
+               "\pAbort: Bad Dialog Allocation!",              /* errGetANDialog */
+               "\pAbort: Bad Menu Allocation!",                /* errANNewMenu */
+       };
+static menuListPtr     pMenuList[2];
+static short           theMenubar = mbarDA;    /* force initial update */
+static short           kAdjustWizardMenu = 1;
+
+
+/******** Prototypes ********/
+#if !TARGET_API_MAC_CARBON
+static void alignAD(Rect *, short);
+#endif
+static void mustGetMenuAlerts(void);
+static void menuError(short);
+static void aboutNetHack(void);
+static void askSave(void);
+static void askQuit(void);
+
+
+/*** Askname dialog box ***/
+
+#define RSRC_ASK                       6000    /* Askname dialog and item list */
+#define RSRC_ASK_PLAY                  1       /*      Play button */
+#define RSRC_ASK_QUIT                  2       /*      Quit button */
+#define RSRC_ASK_DEFAULT               3       /*      Default ring */
+#define RSRC_ASK_ROLE                  4       /*      Role popup menu */
+#define RSRC_ASK_RACE                  5       /*      Race popup menu */
+#define RSRC_ASK_GEND                  6       /*      Gender popup menu */
+#define RSRC_ASK_ALIGN                 7       /*      Alignment popup menu */
+#define RSRC_ASK_MODE                  8       /*      Mode popup menu */
+#define RSRC_ASK_NAME                  9       /*      Name text field */
+#define RSRC_ASK_MAX                   10      /*      Maximum enabled item */
+
+#define KEY_MASK       0xff00
+#define KEY_RETURN     0x2400
+#define KEY_ENTER      0x4c00
+#define KEY_ESCAPE     0x3500
+#define CH_MASK                0x00ff
+#define CH_RETURN      0x000d
+#define CH_ENTER       0x0003
+#define CH_ESCAPE      0x001b
+
+static void ask_restring(const char *cstr, unsigned char *pstr);
+static void ask_enable(DialogRef wind, short item, int enable);
+static pascal void ask_redraw(DialogRef wind, DialogItemIndex item);
+static pascal Boolean ask_filter(DialogRef wind, EventRecord *event, DialogItemIndex *item);
+#define noresource(t,n)        {SysBeep(3); ExitToShell();}
+#define fatal(s)       {SysBeep(3); ExitToShell();}
+
+static MenuHandle askmenu[RSRC_ASK_MAX];
+static int askselect[RSRC_ASK_MAX];
+#define currrole       askselect[RSRC_ASK_ROLE]
+#define currrace       askselect[RSRC_ASK_RACE]
+#define currgend       askselect[RSRC_ASK_GEND]
+#define curralign      askselect[RSRC_ASK_ALIGN]
+#define currmode       askselect[RSRC_ASK_MODE]
+
+static RGBColor
+       blackcolor = {0x0000, 0x0000, 0x0000},
+//     indentcolor = {0x4000, 0x4000, 0x4000},
+       darkcolor = {0x8000, 0x8000, 0x8000},
+       backcolor = {0xdddd, 0xdddd, 0xdddd},
+       lightcolor = {0xffff, 0xffff, 0xffff},
+       whitecolor = {0xffff, 0xffff, 0xffff};
+
+
+/* Convert a mixed-case C string to a Capitalized Pascal string */
+static void
+ask_restring (const char *cstr, unsigned char *pstr)
+{
+       int i;
+
+
+       for (i = 0; *cstr && (i < 255); i++)
+           pstr[i+1] = *cstr++;
+       pstr[0] = i;
+       if ((pstr[1] >= 'a') && (pstr[1] <= 'z'))
+           pstr[1] += 'A' - 'a';
+       return;
+}
+
+
+/* Enable the dialog item with the given index */
+static void
+ask_enable (DialogRef wind, short item, int enable)
+{
+       short type;
+       Handle handle;
+       Rect rect;
+
+
+       /* Enable or disable the appropriate item */
+       GetDialogItem(wind, item, &type, &handle, &rect);
+       if (enable)     type &= ~itemDisable;
+       else            type |= itemDisable;
+       HiliteControl((ControlHandle)handle, enable ? 0 : 255);
+       SetDialogItem(wind, item, type, handle, &rect);
+       return;
+}
+
+
+static pascal void
+ask_redraw (DialogRef wind, DialogItemIndex item)
+{
+       short type;
+       Handle handle;
+       Rect rect;
+       static char     *modechar = "NED";
+
+
+       /* Which item shall we redraw? */
+       GetDialogItem(wind, item, &type, &handle, &rect);
+       switch (item) {
+               case RSRC_ASK_DEFAULT:
+                       PenSize(3, 3);
+                       FrameRoundRect(&rect, 16, 16);
+                       break;
+
+               case RSRC_ASK_ROLE:
+               case RSRC_ASK_RACE:
+               case RSRC_ASK_GEND:
+               case RSRC_ASK_ALIGN:
+               case RSRC_ASK_MODE:
+                       if (macFlags.color) {
+                               RGBForeColor(&blackcolor);
+                               RGBBackColor(&backcolor);
+                       }
+                       PenNormal();
+                       TextMode(srcOr);
+                       EraseRect(&rect);
+
+                       /* Draw the frame and drop shadow */
+                       rect.right--;
+                       rect.bottom--;
+                       FrameRect(&rect);
+                       MoveTo(rect.right, rect.top+1);
+                       LineTo(rect.right, rect.bottom);
+                       LineTo(rect.left+1, rect.bottom);
+
+                       /* Draw the menu character */
+                       MoveTo(rect.left+4, rect.top+12);
+                       switch (item) {
+                       case RSRC_ASK_ROLE:
+                               DrawText(roles[askselect[item]].filecode, 0, 3);
+                               break;
+                       case RSRC_ASK_RACE:
+                               DrawText(races[askselect[item]].filecode, 0, 3);
+                               break;
+                       case RSRC_ASK_GEND:
+                               DrawText(genders[askselect[item]].filecode, 0, 3);
+                               break;
+                       case RSRC_ASK_ALIGN:
+                               DrawText(aligns[askselect[item]].filecode, 0, 3);
+                               break;
+                       case RSRC_ASK_MODE:
+                               DrawChar(modechar[askselect[item]]);
+                               break;
+                       }
+
+                       /* Draw the popup symbol */
+                       MoveTo(rect.right - 16, rect.top + 5);
+                       LineTo(rect.right -  6, rect.top + 5);
+                       LineTo(rect.right - 11, rect.top + 10);
+                       LineTo(rect.right - 15, rect.top + 6);
+                       LineTo(rect.right -  8, rect.top + 6);
+                       LineTo(rect.right - 11, rect.top + 9);
+                       LineTo(rect.right - 13, rect.top + 7);
+                       LineTo(rect.right - 10, rect.top + 7);
+                       LineTo(rect.right - 11, rect.top + 8);
+
+                       /* Draw the shadow */
+                       InsetRect(&rect, 1, 1);
+                       if (macFlags.color) {
+                               RGBColor color;
+
+
+                               /* Save the foreground color */
+                               GetForeColor(&color);
+
+                               /* Draw the top and left */
+                               RGBForeColor(&lightcolor);
+                               MoveTo(rect.left, rect.bottom-1);
+                               LineTo(rect.left, rect.top);
+                               LineTo(rect.right-1, rect.top);
+
+                               /* Draw the bottom and right */
+                               RGBForeColor(&darkcolor);
+                               MoveTo(rect.right-1, rect.top+1);
+                               LineTo(rect.right-1, rect.bottom-1);
+                               LineTo(rect.left+1, rect.bottom-1);
+
+                               /* Restore the foreground color */
+                               RGBForeColor(&color);
+                       }
+                       break;
+
+               case RSRC_ASK_NAME:
+                       PenNormal();
+                       if (macFlags.color) {
+                               RGBForeColor(&whitecolor);
+                               RGBBackColor(&whitecolor);
+                               TextMode(srcOr);
+                       } else {
+                               PenMode(notPatCopy);
+                               TextMode(srcBic);
+                       }
+                       InsetRect(&rect, -1, -1);
+                       FrameRect(&rect);
+                       InsetRect(&rect, -1, -1);
+                       FrameRect(&rect);
+                       InsetRect(&rect, -2, -2);
+                       if (macFlags.color) {
+                               /* Draw the top and left */
+                               RGBForeColor(&darkcolor);
+                               MoveTo(rect.left, rect.bottom-1);
+                               LineTo(rect.left, rect.top);
+                               LineTo(rect.right-1, rect.top);
+
+                               /* Draw the bottom and right */
+                               RGBForeColor(&lightcolor);
+                               MoveTo(rect.right-1, rect.top+1);
+                               LineTo(rect.right-1, rect.bottom-1);
+                               LineTo(rect.left+1, rect.bottom-1);
+
+                               /* Restore the colors */
+                               RGBForeColor(&blackcolor);
+                               RGBBackColor(&backcolor);
+                       }
+                       break;
+       }
+       return;
+}
+
+
+static pascal Boolean
+ask_filter (DialogRef wind, EventRecord *event, DialogItemIndex *item)
+{
+       short ch, key;
+
+
+       switch (event->what) {
+               case keyDown:
+               case autoKey:
+                       ch = event->message & CH_MASK;
+                       key = event->message & KEY_MASK;
+                       /* Handle equivalents for OK */
+                       if ((ch == CH_RETURN) || (key == KEY_RETURN) ||
+                               (ch == CH_ENTER) || (key == KEY_ENTER)) {
+                               if (GetDialogTextEditHandle(wind)[0]->teLength) {
+                                       FlashButton(wind, RSRC_ASK_PLAY);
+                                       *item = RSRC_ASK_PLAY;
+                               } else
+                                       *item = 0;
+                               return (TRUE);
+                       }
+                       /* Handle equivalents for Normal/Explore/Debug */
+                       if ((event->modifiers & cmdKey) && (ch == 'n')) {
+                               currmode = 0;
+                               ask_redraw(wind, RSRC_ASK_MODE);
+                               *item = RSRC_ASK_MODE;
+                               return (TRUE);
+                       }
+                       if ((event->modifiers & cmdKey) && (ch == 'e')) {
+                               currmode = 1;
+                               ask_redraw(wind, RSRC_ASK_MODE);
+                               *item = RSRC_ASK_MODE;
+                               return (TRUE);
+                       }
+                       if ((event->modifiers & cmdKey) && (ch == 'd')) {
+                               currmode = 2;
+                               ask_redraw(wind, RSRC_ASK_MODE);
+                               *item = RSRC_ASK_MODE;
+                               return (TRUE);
+                       }
+                       /* Handle equivalents for Cancel and Quit */
+                       if ((ch == CH_ESCAPE) || (key == KEY_ESCAPE) ||
+                               ((event->modifiers & cmdKey) && (ch == 'q')) ||
+                               ((event->modifiers & cmdKey) && (ch == '.'))) {
+                               FlashButton(wind, RSRC_ASK_QUIT);
+                               *item = RSRC_ASK_QUIT;
+                               return (TRUE);
+                       }
+                       return (FALSE);
+               case updateEvt:
+                       ask_redraw(wind, RSRC_ASK_NAME);
+                       return (FALSE);
+               default:
+                       return (FALSE);
+       }
+}
+
+
+void mac_askname ()
+{
+       GrafPtr oldport;
+       DialogRef askdialog;
+       short i, j, item, type;
+       Handle handle;
+       Rect rect;
+       Str255 str;
+       Point pt;
+       UserItemUPP redraw = NewUserItemUPP(ask_redraw);
+       ModalFilterUPP filter = NewModalFilterUPP(ask_filter);
+
+
+       /* Create the dialog */
+       if (!(askdialog = GetNewDialog(RSRC_ASK, NULL, (WindowRef)-1)))
+           noresource('DLOG', RSRC_ASK);
+       GetPort(&oldport);
+       SetPortDialogPort(askdialog);
+
+       /* Initialize the name text item */
+       ask_restring(plname, str);
+       if (plname[0]) {
+           GetDialogItem(askdialog, RSRC_ASK_NAME, &type, &handle, &rect);
+           SetDialogItemText(handle, str);
+       }
+#if 0
+       {
+       Str32 pName;
+               pName [0] = 0;
+               if (plname && plname [0]) {
+                       strcpy ((char *) pName, plname);
+                       c2pstr ((char *) pName);
+               } else {
+                       Handle h;
+                       h = GetResource ('STR ', -16096);
+                       if (((Handle) 0 != h) && (GetHandleSize (h) > 0)) {
+                               DetachResource (h);
+                               HLock (h);
+                               if (**h > 31) {
+                                       **h = 31;
+                               }
+                               BlockMove (*h, pName, **h + 1);
+                               DisposeHandle (h);
+                       }
+               }
+               if (pName [0]) {
+                       GetDialogItem(askdialog, RSRC_ASK_NAME, &type, &handle, &rect);
+                       SetDialogItemText(handle, pName);
+                       if (pName [0] > 2 && pName [pName [0] - 1] == '-') {
+                           short role = (*pANR).anMenu[anRole];
+                           char suffix = (char) pName[pName[0]],
+                               *sfxindx = strchr(pl_classes, suffix);
+
+                           if (sfxindx)
+                               role = (short) (sfxindx - pl_classes);
+                           else if (suffix == '@')
+                               role = (short) rn2((int) strlen(pl_classes));
+                           (*pANR).anMenu[anRole] = role;
+                       }
+               }
+       }
+#endif
+       SelectDialogItemText(askdialog, RSRC_ASK_NAME, 0, 32767);
+
+       /* Initialize the role popup menu */
+       if (!(askmenu[RSRC_ASK_ROLE] = NewMenu(RSRC_ASK_ROLE, "\p")))
+           fatal("\pCannot create role menu");
+       for (i = 0; roles[i].name.m; i++) {
+           ask_restring(roles[i].name.m, str);
+           AppendMenu(askmenu[RSRC_ASK_ROLE], str);
+       }
+       InsertMenu(askmenu[RSRC_ASK_ROLE], hierMenu);
+       if (flags.initrole >= 0)
+           currrole = flags.initrole;
+       /* Check for backward compatibility */
+       else if ((currrole = str2role(pl_character)) < 0)
+           currrole = randrole();
+
+       /* Initialize the race popup menu */
+       if (!(askmenu[RSRC_ASK_RACE] = NewMenu(RSRC_ASK_RACE, "\p")))
+           fatal("\pCannot create race menu");
+       for (i = 0; races[i].noun; i++) {
+           ask_restring(races[i].noun, str);
+           AppendMenu(askmenu[RSRC_ASK_RACE], str);
+       }
+       InsertMenu(askmenu[RSRC_ASK_RACE], hierMenu);
+       if (flags.initrace >= 0)
+           currrace = flags.initrace;
+       else
+           currrace = randrace(currrole);
+
+       /* Initialize the gender popup menu */
+       if (!(askmenu[RSRC_ASK_GEND] = NewMenu(RSRC_ASK_GEND, "\p")))
+           fatal("\pCannot create gender menu");
+       for (i = 0; i < ROLE_GENDERS; i++) {
+           ask_restring(genders[i].adj, str);
+           AppendMenu(askmenu[RSRC_ASK_GEND], str);
+       }
+       InsertMenu(askmenu[RSRC_ASK_GEND], hierMenu);
+       if (flags.initgend >= 0)
+           currgend = flags.initgend;
+       else if (flags.female)
+           currgend = 1;
+       else
+           currgend = randgend(currrole, currrace);
+
+       /* Initialize the alignment popup menu */
+       if (!(askmenu[RSRC_ASK_ALIGN] = NewMenu(RSRC_ASK_ALIGN, "\p")))
+           fatal("\pCannot create alignment menu");
+       for (i = 0; i < ROLE_ALIGNS; i++) {
+           ask_restring(aligns[i].adj, str);
+           AppendMenu(askmenu[RSRC_ASK_ALIGN], str);
+       }
+       InsertMenu(askmenu[RSRC_ASK_ALIGN], hierMenu);
+       if (flags.initalign >= 0)
+           curralign = flags.initalign;
+       else
+           curralign = randalign(currrole, currrace);
+
+       /* Initialize the mode popup menu */
+       if (!(askmenu[RSRC_ASK_MODE] = NewMenu(RSRC_ASK_MODE, "\p")))
+           fatal("\pCannot create mode menu");
+       AppendMenu(askmenu[RSRC_ASK_MODE], "\pNormal");
+       AppendMenu(askmenu[RSRC_ASK_MODE], "\pExplore");
+#ifdef WIZARD
+       AppendMenu(askmenu[RSRC_ASK_MODE], "\pDebug");
+#endif
+       InsertMenu(askmenu[RSRC_ASK_MODE], hierMenu);
+       currmode = 0;
+
+       /* Set the redraw procedures */
+       for (item = RSRC_ASK_DEFAULT; item <= RSRC_ASK_MODE; item++) {
+           GetDialogItem(askdialog, item, &type, &handle, &rect);
+           SetDialogItem(askdialog, item, type, (Handle)redraw, &rect);
+       }
+
+       /* Handle dialog events */
+       do {
+           /* Adjust the Play button */
+           ask_enable(askdialog, RSRC_ASK_PLAY,
+                               GetDialogTextEditHandle(askdialog)[0]->teLength);
+
+           /* Adjust the race popup menu */
+           i = j = currrace;
+           do {
+               if (validrace(currrole, j)) {
+                       EnableMenuItem(askmenu[RSRC_ASK_RACE], j+1);
+                       CheckMenuItem(askmenu[RSRC_ASK_RACE], j+1,
+                                       currrace == j);
+               } else {
+                       DisableMenuItem(askmenu[RSRC_ASK_RACE], j+1);
+                       CheckMenuItem(askmenu[RSRC_ASK_RACE], j+1, FALSE);
+                       if ((currrace == j) && !races[++currrace].noun)
+                               currrace = 0;
+               }
+               if (!races[++j].noun) j = 0;
+           } while (i != j);
+           if (currrace != i) {
+               GetDialogItem(askdialog, RSRC_ASK_RACE, &type, &handle, &rect);
+               InvalWindowRect(GetDialogWindow(askdialog), &rect);
+           }
+
+           /* Adjust the gender popup menu */
+           i = j = currgend;
+           do {
+               if (validgend(currrole, currrace, j)) {
+                       EnableMenuItem(askmenu[RSRC_ASK_GEND], j+1);
+                       CheckMenuItem(askmenu[RSRC_ASK_GEND], j+1,
+                                       currgend == j);
+               } else {
+                       DisableMenuItem(askmenu[RSRC_ASK_GEND], j+1);
+                       CheckMenuItem(askmenu[RSRC_ASK_GEND], j+1, FALSE);
+                       if ((currgend == j) && (++currgend >= ROLE_GENDERS))
+                               currgend = 0;
+               }
+               if (++j >= ROLE_GENDERS) j = 0;
+           } while (i != j);
+           if (currgend != i) {
+               GetDialogItem(askdialog, RSRC_ASK_GEND, &type, &handle, &rect);
+               InvalWindowRect(GetDialogWindow(askdialog), &rect);
+           }
+
+           /* Adjust the alignment popup menu */
+           i = j = curralign;
+           do {
+               if (validalign(currrole, currrace, j)) {
+                       EnableMenuItem(askmenu[RSRC_ASK_ALIGN], j+1);
+                       CheckMenuItem(askmenu[RSRC_ASK_ALIGN], j+1,
+                                       curralign == j);
+               } else {
+                       DisableMenuItem(askmenu[RSRC_ASK_ALIGN], j+1);
+                       CheckMenuItem(askmenu[RSRC_ASK_ALIGN], j+1, FALSE);
+                       if ((curralign == j) && (++curralign >= ROLE_ALIGNS))
+                               curralign = 0;
+               }
+               if (++j >= ROLE_ALIGNS) j = 0;
+           } while (i != j);
+           if (curralign != i) {
+               GetDialogItem(askdialog, RSRC_ASK_ALIGN, &type, &handle, &rect);
+               InvalWindowRect(GetDialogWindow(askdialog), &rect);
+           }
+
+           /* Adjust the role popup menu */
+           for (i = 0; roles[i].name.m; i++) {
+               ask_restring((currgend && roles[i].name.f) ?
+                               roles[i].name.f : roles[i].name.m, str);
+               SetMenuItemText(askmenu[RSRC_ASK_ROLE], i+1, str);
+               CheckMenuItem(askmenu[RSRC_ASK_ROLE], i+1, currrole == i);
+           }
+
+           /* Adjust the mode popup menu */
+           CheckMenuItem(askmenu[RSRC_ASK_MODE], 1, currmode == 0);
+           CheckMenuItem(askmenu[RSRC_ASK_MODE], 2, currmode == 1);
+#ifdef WIZARD
+           CheckMenuItem(askmenu[RSRC_ASK_MODE], 3, currmode == 2);
+#endif
+
+           /* Wait for an action on an item */
+           ModalDialog(filter, &item);
+           switch (item) {
+           case RSRC_ASK_PLAY:
+               break;
+           case RSRC_ASK_QUIT:
+               currmode = -1;
+               break;
+           case RSRC_ASK_ROLE:
+           case RSRC_ASK_RACE:
+           case RSRC_ASK_ALIGN:
+           case RSRC_ASK_GEND:
+           case RSRC_ASK_MODE:
+               GetDialogItem(askdialog, item, &type, &handle, &rect);
+               pt = *(Point *)&rect;
+               LocalToGlobal(&pt);
+               if (!!(i = PopUpMenuSelect(askmenu[item], pt.v, pt.h,
+                               askselect[item] + 1)))
+                       askselect[item] = LoWord(i) - 1;
+               InvalWindowRect(GetDialogWindow(askdialog), &rect);
+               break;
+           case RSRC_ASK_NAME:
+#if 0
+           /* limit the data here to 25 chars */
+           {
+               short beepTEDelete = 1;
+
+               while ((**dRec.textH).teLength > 25)
+               {
+                       if (beepTEDelete++ <= 3)
+                               SysBeep(3);
+                       TEKey('\b', dRec.textH);
+               }
+           }
+
+           /* special case filter (that doesn't plug all the holes!) */
+           if (((**dRec.textH).teLength == 1) && (**((**dRec.textH).hText) < 32))
+               TEKey('\b', dRec.textH);
+#endif
+               break;
+           }
+       } while ((item != RSRC_ASK_PLAY) && (item != RSRC_ASK_QUIT));
+
+       /* Process the name */
+       GetDialogItem(askdialog, RSRC_ASK_NAME, &type, &handle, &rect);
+       GetDialogItemText(handle, str);
+       if (str[0] > PL_NSIZ-1) str[0] = PL_NSIZ-1;
+       BlockMove(&str[1], plname, str[0]);
+       plname[str[0]] = '\0';
+
+       /* Destroy the dialog */
+       for (i = RSRC_ASK_ROLE; i <= RSRC_ASK_MODE; i++) {
+           DeleteMenu(i);
+           DisposeMenu(askmenu[i]);
+       }
+       SetPort(oldport);
+       DisposeDialog(askdialog);
+       DisposeRoutineDescriptor(filter);
+       DisposeRoutineDescriptor(redraw);
+
+       /* Process the mode */
+#ifdef WIZARD
+       wizard =
+#endif
+       discover = 0;
+       switch (currmode) {
+       case 0:         /* Normal */
+           break;
+       case 1:         /* Explore */
+           discover = 1;
+           break;
+#ifdef WIZARD
+       case 2:         /* Debug */
+           wizard = 1;
+           strcpy(plname, WIZARD);
+           break;
+#endif
+       default:        /* Quit */
+           ExitToShell();
+       }
+
+       /* Process the role */
+       strcpy(pl_character, roles[currrole].name.m);
+       flags.initrole = currrole;
+
+       /* Process the race */
+       flags.initrace = currrace;
+
+       /* Process the gender */
+       flags.female = flags.initgend = currgend;
+
+       /* Process the alignment */
+       flags.initalign = curralign;
+
+       return;
+}
+
+
+
+/*** Menu bar routines ***/
+
+#if !TARGET_API_MAC_CARBON
+static void
+alignAD(Rect *pRct, short vExempt)
+{
+       BitMap qbitmap;
+
+
+       GetQDGlobalsScreenBits(&qbitmap);
+       (*pRct).right -= (*pRct).left;          /* width */
+       (*pRct).bottom -= (*pRct).top;          /* height */
+       (*pRct).left = (qbitmap.bounds.right - (*pRct).right) / 2;
+       (*pRct).top = (qbitmap.bounds.bottom - (*pRct).bottom - vExempt) / 2;
+       (*pRct).top += vExempt;
+       (*pRct).right += (*pRct).left;
+       (*pRct).bottom += (*pRct).top;
+}
+#endif
+
+
+static void
+mustGetMenuAlerts()
+{
+       short           i;
+       Rect            **hRct;
+
+       for (i = alrt_Menu_start; i < alrt_Menu_limit; i++)
+       {
+               if (! (hRct = (Rect **) GetResource('ALRT', i)))        /* AlertTHndl */
+               {
+                       for (i = 0; i < beepMenuAlertErr; i++)
+                               SysBeep(3);
+                       ExitToShell();
+               }
+
+#if !TARGET_API_MAC_CARBON
+               alignAD(*hRct, GetMBarHeight());
+#endif
+       }
+}
+
+static void
+menuError(short menuErr)
+{
+       short   i;
+
+       for (i = 0; i < beepMenuAlertErr; i++)
+               SysBeep(3);
+
+       ParamText(menuErrStr[menuErr], "\p", "\p", "\p");
+       (void) Alert(alrtMenuNote, (ModalFilterUPP) 0L);
+
+       ExitToShell();
+}
+
+void
+InitMenuRes()
+{
+       static Boolean was_inited = 0;
+       short                   i, j;
+       menuListHandle  mlHnd;
+       MenuHandle              menu;
+
+       if (was_inited)
+               return;
+       was_inited = 1;
+
+       mustGetMenuAlerts();
+
+       for (i = listMenubar; i <= listSubmenu; i++) {
+               if (! (mlHnd = (menuListHandle) GetResource('MNU#', (menuBarListID + i))))
+                       menuError(errGetMenuList);
+
+               pMenuList[i] = (menuListPtr) NewPtr(GetHandleSize((Handle) mlHnd));
+               *pMenuList[i] = **mlHnd;
+
+               for (j = 0; j < pMenuList[i]->numMenus; j++)
+               {
+                       if (! (menu = (MenuHandle) GetMenu((**mlHnd).mref[j].mresID))) {
+                       Str31 d;
+                               NumToString ((**mlHnd).mref[j].mresID, d);
+                               menuError(errGetMenu);
+                       }
+
+                       pMenuList[i]->mref[j].mhnd = menu;
+                       SetMenuID(menu, j + (**mlHnd).firstMenuID);     /* consecutive IDs */
+
+                       /* expand apple menu */
+                       if ((i == listMenubar) && (j == menuApple)) {
+                               AppendResMenu(menu, 'DRVR');
+                       }
+
+                       InsertMenu(menu, ((i == listSubmenu) ? hierMenu : 0));
+               }
+       }
+       DrawMenuBar();
+       return;
+}
+
+void
+AdjustMenus(short dimMenubar)
+{
+       short           newMenubar = mbarRegular;
+       WindowRef win = FrontWindow();
+       short           i;
+
+       /*
+        *      if (windowprocs != mac_procs) {
+        *              return;
+        *      }
+        */
+       /* determine the new menubar state */
+       if (dimMenubar)
+               newMenubar = mbarDim;
+       else if (!win)
+               newMenubar = mbarNoWindows;
+       else if (GetWindowKind(win) < 0)
+               newMenubar = mbarDA;
+       else if (!IsWindowVisible(_mt_window))
+               newMenubar = mbarNoMap;
+
+       if (newMenubar != mbarRegular)
+               ;                                                       /* we've already found its state */
+#ifdef WIZARD
+       else if (wizard)
+       {
+               newMenubar = mbarSpecial;
+
+               if (kAdjustWizardMenu)
+               {
+                       kAdjustWizardMenu = 0;
+
+                       SetMenuItemText(MHND_FILE, menuFilePlayMode, "\pDebug");
+               }
+       }
+#endif
+
+       else if (discover)
+       {
+               newMenubar = mbarSpecial;
+
+               if (kAdjustWizardMenu)
+               {
+                       kAdjustWizardMenu = 0;
+
+                       SetMenuItemText(MHND_FILE, menuFilePlayMode, "\pExplore");
+
+                       for (i = CountMenuItems(MHND_WIZ); i > menuWizardAttributes; i--)
+                               DeleteMenuItem(MHND_WIZ, i);
+               }
+       }
+
+       /* adjust the menubar, if there's a state change */
+       if (theMenubar != newMenubar)
+       {
+               switch(theMenubar = newMenubar)
+               {
+               case mbarDim:
+                       /* disable all menus (except the apple menu) */
+                       for (i = menuFile; i < NUM_MBAR; i++)
+                               DisableMenuItem(MBARHND(i), 0);
+                       break;
+
+               case mbarNoWindows:
+               case mbarDA:
+               case mbarNoMap:
+                       /* enable the file menu, but ... */
+                       EnableMenuItem(MHND_FILE, 0);
+
+                       /* ... disable the window commands! */
+                       for (i = menuFileRedraw; i <= menuFileEnterExplore; i++)
+                               DisableMenuItem(MHND_FILE, i);
+
+                       /* ... and disable the rest of the menus */
+                       for (i = menuEdit; i < NUM_MBAR; i++)
+                               DisableMenuItem(MBARHND(i), 0);
+
+                       if (theMenubar == mbarDA)
+                               EnableMenuItem(MHND_EDIT, 0);
+
+                       break;
+
+               case mbarRegular:
+               case mbarSpecial:
+                       /* enable all menus ... */
+                       for (i = menuFile; i < NUM_MBAR; i++)
+                               EnableMenuItem(MBARHND(i), 0);
+
+                       /* ... except the unused Edit menu */
+                       DisableMenuItem(MHND_EDIT, 0);
+
+                       /* ... enable the window commands */
+                       for (i = menuFileRedraw; i <= menuFileEnterExplore; i++)
+                               EnableMenuItem(MHND_FILE, i);
+
+                       if (theMenubar == mbarRegular)
+                               DisableMenuItem(MHND_FILE, menuFilePlayMode);
+                       else
+                               DisableMenuItem(MHND_FILE, menuFileEnterExplore);
+
+                       break;
+               }
+
+               DrawMenuBar();
+       }
+}
+
+void
+DoMenuEvt(long menuEntry)
+{
+       short menuID = HiWord(menuEntry);
+       short menuItem = LoWord(menuEntry);
+
+       switch(menuID - ID1_MBAR)       /* all submenus are default case */
+       {
+       case menuApple:
+               if (menuItem == menuAppleAboutBox)
+                       aboutNetHack();
+#if !TARGET_API_MAC_CARBON
+               else
+               {
+                       unsigned char daName[32];
+
+                       GetMenuItemText(MHND_APPLE, menuItem, * (Str255 *) daName);
+                       (void) OpenDeskAcc(daName);
+               }
+#endif
+               break;
+
+       /*
+        * Those direct calls are ugly: they should be installed into cmd.c .
+        * Those AddToKeyQueue() calls are also ugly: they should be put into
+        * the 'STR#' resource.
+        */
+       case menuFile:
+               switch(menuItem)
+               {
+               case menuFileRedraw:
+                       AddToKeyQueue ('R' & 0x1f, 1);
+                       break;
+
+               case menuFilePrevMsg:
+                       AddToKeyQueue ('P' & 0x1f, 1);
+                       break;
+
+               case menuFileCleanup:
+                       (void) SanePositions();
+                       break;
+
+               case menuFileEnterExplore:
+                       AddToKeyQueue ('X', 1);
+                       break;
+
+               case menuFileSave:
+                       askSave();
+                       break;
+
+               case menuFileQuit:
+                       askQuit();
+                       break;
+               }
+               break;
+
+       case menuEdit:
+#if !TARGET_API_MAC_CARBON
+               (void) SystemEdit(menuItem - 1);
+#endif
+               break;
+
+       default:        /* get associated string and add to key queue */
+               {
+                       Str255  mstr;
+                       short   i;
+
+                       GetIndString(mstr, menuID, menuItem);
+                       if (mstr[0] > QUEUE_LEN)
+                               mstr[0] = QUEUE_LEN;
+
+                       for (i = 1; ((i <= mstr[0]) && (mstr[i] != mstrEndChar)); i++)
+                               AddToKeyQueue(mstr[i], false);
+               }
+               break;
+       }
+
+       HiliteMenu(0);
+}
+
+
+static void
+aboutNetHack() {
+       if (theMenubar >= mbarRegular) {
+               (void) doversion();                             /* is this necessary? */
+       } else {
+               unsigned char aboutStr[32] = "\pNetHack 3.4.";
+
+               if (PATCHLEVEL > 10) {
+                       aboutStr[++aboutStr[0]] = '0'+PATCHLEVEL/10;
+               }
+
+               aboutStr[++aboutStr[0]] = '0' + (PATCHLEVEL % 10);
+
+               ParamText(aboutStr, "\p\rdevteam@www.nethack.org", "\p", "\p");
+               (void) Alert(alrtMenuNote, (ModalFilterUPP) 0L);
+               ResetAlertStage();
+       }
+}
+
+
+static void
+askSave()
+{
+       Boolean doSave = 1;
+       Boolean doYes = 0;
+
+       if (theMenubar < mbarRegular) {
+       short   itemHit;
+
+               ParamText("\pReally Save?", "\p", "\p", "\p");
+               itemHit = Alert(alrtMenu_NY, (ModalFilterUPP) 0L);
+               ResetAlertStage();
+
+               if (itemHit != bttnMenuAlertYes) {
+                       doSave = 0;
+               } else {
+                       doYes = 1;
+               }
+       }
+       if (doSave) {
+               AddToKeyQueue ('S', 1);
+               if (doYes) {
+                       AddToKeyQueue ('y', 1);
+               }
+       }
+}
+
+static void
+askQuit()
+{
+       Boolean doQuit = 1;
+       Boolean doYes = 0;
+       Boolean winMac;
+       char *quitinput;
+
+       if (!strcmp (windowprocs.name, "mac"))
+               winMac = 1;
+       else
+               winMac = 0;
+               
+       if (theMenubar < mbarRegular) {
+       short   itemHit;
+
+               ParamText("\pReally Quit?", "\p", "\p", "\p");
+               itemHit = Alert(alrtMenu_NY, (ModalFilterUPP) 0L);
+               ResetAlertStage();
+
+               if (itemHit != bttnMenuAlertYes) {
+                       doQuit = 0;
+               } else {
+                       doYes = 1;
+               }
+       }
+       if (doQuit) {
+               /* MWM -- forgive me lord, an even uglier kludge to deal with differences
+                       in command input handling
+                */
+                if (winMac)
+                       quitinput = "#quit\r";
+               else
+                       quitinput = "#q\r";
+                       
+               /* KMH -- Ugly kludge */
+               while (*quitinput)
+                       AddToKeyQueue(*quitinput++, 1);
+               if (doYes) {
+                       if (winMac)
+                               quitinput = "y\rq\r\r\r";
+                       else
+                               quitinput = "yq\r";
+                       while (*quitinput)
+                               AddToKeyQueue(*quitinput++, 1);
+               }
+       }
+}
+
diff --git a/sys/mac/macsnd.c b/sys/mac/macsnd.c
new file mode 100644 (file)
index 0000000..39add1f
--- /dev/null
@@ -0,0 +1,107 @@
+/*     SCCS Id: @(#)macsnd.c   3.1     92/11/28        */
+/*     Copyright (c) 1992 by Jon Watte */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file contains music playing code.
+ *
+ * If we were REALLY determinated, we would make the sound play
+ * asynchronously, but I'll save that one for a rainy day...
+ *
+ * This may break A/UX, since it defines MAC but we need to
+ * check that the toolbox is booted. I'll defer that one too.
+ *
+ * - h+ 921128
+ */
+
+#include "hack.h"
+#include "mactty.h"
+#include "macwin.h"
+#if !TARGET_API_MAC_CARBON
+# include <Sound.h>
+# include <Resources.h>
+#else
+# define freqDurationCmd 40
+#endif
+
+#define SND_BUFFER(s) (&(*s)[20])
+#define SND_LEN(s) (GetHandleSize(s)-42)
+
+
+void
+mac_speaker (struct obj *instr, char *melody) {
+       SndChannelPtr theChannel = (SndChannelPtr) 0;
+       SndCommand theCmd;
+       Handle theSound;
+       unsigned char theName [32];
+       char *n = (char *) &theName [1];
+       int typ = instr->otyp;
+       const char *actualn = OBJ_NAME (objects [typ]);
+
+       /*
+        * First: are we in the library ?
+        */
+       if (flags.silent) {
+               return;
+       }
+
+       /*
+        * Is this a known instrument ?
+        */
+       strcpy (n, actualn);
+       theName [0] = strlen (n);
+       theSound = GetNamedResource ('snd ', theName);
+       if (! theSound) {
+               return;
+       }
+       HLock (theSound);
+
+       /*
+        * Set up the synth
+        */
+       if (SndNewChannel(&theChannel, sampledSynth, initMono +
+               initNoInterp, (void *) 0) == noErr) {
+               char midi_note [] = {57, 59, 60, 62, 64, 65, 67};
+
+               short err;
+               short snd_len = SND_LEN (theSound) / 18;
+
+               theCmd.cmd = soundCmd;
+               theCmd.param1 = 0;
+               theCmd.param2 = (long) SND_BUFFER (theSound);
+               err = SndDoCommand (theChannel, &theCmd, false);
+
+       /*
+        * We rack 'em up all in a row
+        * The mac will play them correctly and then end, since
+        * we do a sync close below.
+        *
+        */
+               while (*melody && ! err) {
+                       while (*melody > 'G') {
+                               *melody -= 8;
+                       }
+                       while (*melody < 'A') {
+                               *melody += 8;
+                       }
+                       theCmd.cmd = freqDurationCmd;
+                       theCmd.param1 = snd_len;
+                       theCmd.param2 = midi_note [*melody - 'A'];
+                       err = SndDoCommand (theChannel, &theCmd, false);
+                       melody ++;
+               }
+               SndDisposeChannel (theChannel, false);  /* Sync wait for completion */
+               ReleaseResource (theSound);
+       }
+}
+
+void tty_nhbell (void) {
+       Handle h = GetNamedResource ('snd ', "\pNetHack Bell");
+
+       if (h) {
+               HLock (h);
+               SndPlay ((SndChannelPtr) 0, (SndListHandle) h, 0);
+               ReleaseResource (h);
+       } else
+               SysBeep (30);
+}
diff --git a/sys/mac/mactopl.c b/sys/mac/mactopl.c
new file mode 100644 (file)
index 0000000..b9979e3
--- /dev/null
@@ -0,0 +1,65 @@
+/*     SCCS Id: @(#)mactopl.c  3.1     91/07/23 */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "mactty.h"
+#include "macwin.h"
+#include "macpopup.h"
+
+char
+queued_resp(char *resp) {
+       char buf[30];
+       if (try_key_queue(buf)) {
+               if (!resp || strchr(resp, buf[0]))
+                       return buf[0];
+               if (digit(buf[0]) && strchr(resp, '#')) {
+                       yn_number = atoi(buf);
+                       return '#';
+               }
+       }
+       return '\0';
+}
+
+
+char
+topl_yn_function(const char *query, const char *resp, char def) {
+       char buf[30];
+       char c = queued_resp((char *) resp);
+       if (!c) {
+               enter_topl_mode((char *) query);
+               topl_set_resp((char *) resp, def);
+
+               do {
+                       c = readchar();
+                       if (c && resp && !strchr(resp, c)) {
+                               nhbell();
+                               c = '\0';
+                       }
+               } while (!c);
+
+               topl_set_resp("", '\0');
+               leave_topl_mode(buf);
+               if (c == '#')
+                       yn_number = atoi(buf);
+       }
+       return c;
+}
+
+
+char
+mac_yn_function(query, resp, def)
+const char *query,*resp;
+char def;
+/*
+ *   Generic yes/no function. 'def' is the default (returned by space or
+ *   return; 'esc' returns 'q', or 'n', or the default, depending on
+ *   what's in the string. The 'query' string is printed before the user
+ *   is asked about the string.
+ *   If resp is NULL, any single character is accepted and returned.
+ */
+{
+               return topl_yn_function(query, resp, def);
+}
+
+/* mactopl.c */
diff --git a/sys/mac/mactty.c b/sys/mac/mactty.c
new file mode 100644 (file)
index 0000000..554f39b
--- /dev/null
@@ -0,0 +1,1225 @@
+/*     SCCS Id: @(#)mactty.c   3.1     93/03/01                        */
+/* Copyright (c) Jon W{tte 1993.                                       */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+/*
+ * mactty.c
+ *
+ * This file contains the actual code for the tty library. For a 
+ * description, see the file mactty.h, which contains all you
+ * need to know to use the library.
+ */
+
+#include "hack.h"      /* to get flags */
+#include "mttypriv.h"
+#if !TARGET_API_MAC_CARBON
+#include <Resources.h>
+#endif
+
+char game_active = 0;  /* flag to window rendering routines not to use ppat */
+
+/* these declarations are here because I can't include macwin.h without including the world */
+extern void dprintf(char *, ...);      /* dprintf.c */
+
+/*
+ * Borrowed from the Mac tty port
+ */
+extern WindowPtr _mt_window;
+
+static void select_onscreen_window (tty_record *record);
+static void select_offscreen_port (tty_record *record);
+
+#define MEMORY_MARGIN 30000
+
+/*
+ * Convenience macro for most functions - put last in declaration
+ */
+#define RECORD_EXISTS(record) \
+       tty_record * record; \
+       if (!window || !(record = (tty_record *) GetWRefCon (window))) \
+               return general_failure; 
+
+
+/*
+ * Simple macro for deciding wether we draw at once or delay
+ */
+#define DRAW_DIRECT (TA_ALWAYS_REFRESH & record->attribute [TTY_ATTRIB_FLAGS])
+
+
+/*
+ * Table of special characters. Zero is ALWAYS special; it means
+ * end of string and would be MISSED if it was not included here.
+ */
+#define COOKED_CONTROLS 0X00002581
+#define RAW_CONTROLS 1
+static unsigned long s_control = COOKED_CONTROLS;
+
+
+/*
+ * Memory-related error
+ */
+static short
+mem_err (void) {
+       short ret_val = MemError();
+       if (!ret_val) {
+               ret_val = general_failure;
+       }
+       return ret_val;
+}
+
+
+/*
+ * Make a rectangle empty
+ */
+static void
+empty_rect (Rect *r) {
+       r->right = -20000;
+       r->left = 20000;
+       r->top = 20000;
+       r->bottom = -20000;
+}
+
+
+/*
+ * Union twp rect together
+ */
+static void
+union_rect (Rect *r1, Rect *r2, Rect *dest) {
+       dest->left = min (r1->left, r2->left);
+       dest->top = min (r1->top, r2 ->top);
+       dest->bottom = max (r1->bottom, r2->bottom);
+       dest->right = max (r1->right, r2->right);
+}
+
+
+/*
+ * Dispose a pointer using the set memory-allocator
+ */
+static short
+dispose_ptr (void *ptr) {
+       if (!ptr) {
+               return noErr; /* Silently accept disposing nulls */
+       }
+       DisposePtr (ptr);
+       return MemError ();
+}
+
+
+#if 0  /* Use alloc.c instead */
+/*
+ * Allocate a pointer using the set memory-allocator
+ */
+static short
+alloc_ptr (void **ptr, long size) {
+       *ptr = NewPtr (size);
+       return MemError ();
+}
+#endif
+
+
+/*
+ * Set up a GWorld in the record
+ */
+static short
+allocate_offscreen_world (tty_record *record) {
+GWorldPtr gw = (GWorldPtr)0;
+GWorldFlags world_flags = 0;
+long mem_here, mem_there, other, required_mem;
+Point p = {0, 0};
+Rect r_screen;
+GDHandle gdh;
+short s_err;
+
+       select_onscreen_window (record);
+       LocalToGlobal (&p);
+       r_screen = record->its_bits.bounds;
+       OffsetRect (&r_screen, p.h, p.v);
+
+       gdh = GetMaxDevice (&r_screen);
+       required_mem = (long) (*((*gdh)->gdPMap))->pixelSize *
+               ((long) record->its_bits.bounds.right *
+               record->its_bits.bounds.bottom) >> 3;
+
+       PurgeSpace (&other, &mem_here);
+       if (other < mem_here + MEMORY_MARGIN) {
+               mem_here = other - MEMORY_MARGIN;
+       }
+       dprintf ("Heap %ld Required %ld", mem_here, required_mem);
+       if (required_mem > mem_here) {
+               mem_there = required_mem;
+               if (required_mem > TempMaxMem (&mem_there)) {
+                       dprintf ("No memory");
+                       return memFullErr;
+               }
+               world_flags |= useTempMem;
+       }
+       s_err = NewGWorld (&gw, 0, &r_screen, (CTabHandle) 0, (GDHandle) 0, world_flags);
+       if (!s_err) {
+               record->offscreen_world = gw;
+               select_offscreen_port (record);
+               SetOrigin (0, 0);
+               select_onscreen_window (record);
+               dprintf ("New GWorld @ %lx;dm", gw);
+       }
+       return s_err;
+}
+
+
+/*
+ * Done with GWorld, release data
+ */
+static short
+deallocate_gworld (tty_record *record) {
+       if (record->offscreen_world) {
+               DisposeGWorld (record->offscreen_world);
+               record->offscreen_world = (GWorldPtr) 0;
+       }
+       return noErr;
+}
+
+
+
+
+/*
+ * Get rid of offscreen bitmap
+ */
+static short
+free_bits (tty_record *record) {
+       short s_err;
+
+       if (record->uses_gworld) {
+               s_err = deallocate_gworld (record);
+#if !TARGET_API_MAC_CARBON
+       } else {
+               s_err = dispose_ptr (record->its_bits.baseAddr);
+               if (!s_err) {
+                       record->its_bits.baseAddr = (char *)0;
+                       if (record->offscreen_port) {
+                               ClosePort (record->offscreen_port);
+                               s_err = dispose_ptr (record->offscreen_port);
+                               if (!s_err) {
+                                       record->offscreen_port = (GrafPtr) 0;
+                               }
+                       }
+               }
+#endif
+       }
+       return s_err;
+}
+
+
+/*
+ * Snatch a window from the resource fork. Create the record.
+ * Otherwise, do nothing.
+ */
+
+short
+create_tty (WindowRef *window, short resource_id, Boolean in_color)
+{
+       tty_record * record;
+       Boolean was_allocated = !!*window;
+
+       if (in_color) {
+               *window = GetNewCWindow (resource_id, (Ptr) *window, (WindowRef) -1L);
+       } else {
+               *window = GetNewWindow (resource_id, (Ptr) *window, (WindowRef) -1L);
+       }
+       if (!*window) {
+               return mem_err ();
+       }
+
+       record = (tty_record *) NewPtrClear (sizeof (tty_record));
+       if (!record) {
+#if !TARGET_API_MAC_CARBON
+               if (was_allocated) {
+                       CloseWindow (*window);
+               } else {
+#endif
+                       DisposeWindow (*window);
+#if !TARGET_API_MAC_CARBON
+               }
+#endif
+               return mem_err ();
+       }
+       record->its_window = *window;
+       SetWRefCon (*window, (long) record);
+       record->was_allocated = was_allocated;
+       record->its_bits.baseAddr = (char *)0;
+       record->curs_state = TRUE;
+
+/*
+ * We need to keep the window world around if we switch worlds
+ */
+       record->offscreen_world = (GWorldPtr) 0;
+       record->uses_gworld = in_color;
+       if (in_color) {
+       GDHandle gh;
+
+               SetPortWindowPort(*window);
+               GetGWorld(&(record->its_window_world), &gh);
+       } else {
+               record->its_window_world = (GWorldPtr)0;
+       }
+
+#if CLIP_RECT_ONLY
+       empty_rect (&(record->invalid_rect));
+#else
+       record->invalid_part = NewRgn ();
+       if (!record->invalid_part) {
+               return destroy_tty (*window);
+       }
+#endif
+
+       return noErr;
+}
+
+
+short
+init_tty_number (WindowPtr window, short font_number, short font_size,
+       short x_size, short y_size) {
+RECORD_EXISTS (record);
+
+       record->font_number = font_number;
+       record->font_size = font_size;
+       record->x_size = x_size;
+       record->y_size = y_size;
+
+       return force_tty_coordinate_system_recalc (window);
+}
+
+
+/*
+ * Done with a window - destroy it. Release the memory only if
+ * it wasn't allocated when we got it!
+ */
+short
+destroy_tty (WindowPtr window) {
+short s_err;
+RECORD_EXISTS (record);
+
+       s_err = free_bits (record);
+       if (!s_err) {
+#if !TARGET_API_MAC_CARBON
+               if (record->was_allocated) {
+                       CloseWindow (window);
+               } else {
+#endif
+                       DisposeWindow (window);
+#if !TARGET_API_MAC_CARBON
+               }
+#endif
+               s_err = dispose_ptr (record);
+       }
+       
+       return s_err;
+}
+
+
+static void
+do_set_port_font (tty_record *record) {
+
+       PenNormal ();
+       TextFont (record->font_number);
+       TextSize (record->font_size);
+       if (0L != (record->attribute [TTY_ATTRIB_FLAGS] & TA_OVERSTRIKE)) {
+               TextMode (srcOr);
+       } else {
+               TextMode (srcCopy);
+       }
+}
+
+
+/*
+ * Fill in some fields from some other fields that may have changed
+ */
+static void
+calc_font_sizes (tty_record *record) {
+FontInfo font_info;
+
+       do_set_port_font (record);
+
+       GetFontInfo (&font_info);
+       record->char_width = font_info.widMax;
+       record->ascent_height = font_info.ascent + font_info.leading;
+       record->row_height = record->ascent_height + font_info.descent;
+}
+
+
+/*
+ * Allocate memory for the bitmap holding the tty window
+ */
+static short
+alloc_bits (tty_record *record) {
+short s_err;
+
+       SetRect (&record->its_bits.bounds, 0, 0,
+               record->char_width * record->x_size,
+               record->row_height * record->y_size);
+
+/*
+ * Clear two highest and lowest bit - not a color pixMap, and even in size
+ */
+       record->its_bits.rowBytes = ((record->its_bits.bounds.right + 15)
+               >> 3) & 0x1ffe;
+
+       if (record->uses_gworld) {
+               s_err = allocate_offscreen_world (record);
+#if !TARGET_API_MAC_CARBON
+       } else {
+               s_err = alloc_ptr ((void **) &(record->its_bits.baseAddr),
+                       record->its_bits.rowBytes * record->its_bits.bounds.bottom);
+               if (!s_err) {
+                       s_err = alloc_ptr ((void **) &(record->offscreen_port),
+                               sizeof (GrafPort));
+               }
+               if (!s_err) {
+                       OpenPort (record->offscreen_port);
+                       SetPort (record->offscreen_port);
+                       ClipRect (&(record->its_bits.bounds));
+                       SetPortBits (&(record->its_bits));
+               }
+#endif
+       }
+       return s_err;
+}
+
+
+/*
+ * Save the current port/world in a safe place for later retrieval
+ */
+static void
+save_port (tty_record *record, void *save) {
+GWorldPtr gw;
+GDHandle gh;
+GrafPtr gp;
+
+       if (record->uses_gworld) {
+               GetGWorld (&gw, &gh);
+               *(GWorldPtr *) save = gw;
+       } else {
+               GetPort (&gp);
+               *(GrafPtr *) save = gp;
+       }
+}
+
+
+/*
+ * Restore current port/world after a save
+ */
+static void
+use_port (tty_record *record, void *port) {
+       if (record->uses_gworld) {
+               PixMapHandle pix_map;
+
+               SetGWorld ((GWorldPtr) port, (GDHandle) 0);
+               pix_map = GetGWorldPixMap (record->offscreen_world);
+               if (pix_map) {
+                       if (port == record->offscreen_world)
+                               LockPixels (pix_map);
+                       else
+                               UnlockPixels (pix_map);
+               }
+       } else {
+               SetPort ((GrafPtr) port);
+       }
+}
+
+
+/*
+ * Use offscreen drawing - lock the pixels through use_port
+ */
+static void
+select_offscreen_port (tty_record *record) {
+       if (record->uses_gworld) {
+               use_port (record, record->offscreen_world);
+       } else {
+               use_port (record, record->offscreen_port);
+       }
+}
+
+
+/*
+ * Use the window - unlock pixels
+ */
+static void
+select_onscreen_window (tty_record *record) {
+       if (record->uses_gworld) {
+               use_port (record, record->its_window_world);
+               SetPortWindowPort(record->its_window);
+       } else {
+               use_port(record, record->its_window);
+       }
+}
+
+
+/*
+ * Do bits copy depending on if we're using color or not
+ */
+static void
+copy_bits(tty_record *record, Rect *bounds, short xfer_mode, RgnHandle mask_rgn)
+{
+       GWorldFlags pix_state;
+       BitMap * source;
+
+       if (record->uses_gworld) {
+               pix_state = GetPixelsState (GetGWorldPixMap (record->offscreen_world));
+               LockPixels (GetGWorldPixMap (record->offscreen_world));
+               source = (BitMapPtr) *GetGWorldPixMap(record->offscreen_world);
+       }
+       else    source = &record->its_bits;
+
+       SetPortWindowPort(record->its_window);
+       CopyBits(source, GetPortBitMapForCopyBits(GetWindowPort(record->its_window)),
+               bounds, bounds, xfer_mode, mask_rgn);
+
+       if (record->uses_gworld) {
+               SetPixelsState (GetGWorldPixMap (record->offscreen_world), pix_state);
+       }
+}
+
+
+/*
+ * Fill an area with the background color
+ */
+static void
+erase_rect (tty_record *record, Rect *area) {
+       if (game_active && u.uhp > 0 && iflags.use_stone && record->its_window == _mt_window) {
+               PixPatHandle ppat;
+               
+               ppat = GetPixPat(iflags.use_stone + 127);       /* find which pat to get */
+               if (ppat) {     /* in game window, using backgroung pattern, and have pattern */
+                       FillCRect (area, ppat);
+                       DisposePixPat (ppat);
+                       return;
+               }
+       }
+       EraseRect (area);
+}
+
+
+/*
+ * Recalculate the window based on new size, font, extent values,
+ * and re-allocate the bitmap.
+ */
+short
+force_tty_coordinate_system_recalc (WindowPtr window) {
+short s_err;
+RECORD_EXISTS (record);
+
+       s_err = free_bits (record);
+       if (s_err) {
+               return s_err;
+       }
+       calc_font_sizes (record);
+
+       s_err = alloc_bits (record);
+       if (s_err) {
+/*
+ * Catastrophe! We could not allocate memory for the bitmap! Things may go very
+ * much downhill from here!
+ */
+               dprintf ("alloc_bits returned null in force_tty_coordinate_system_recalc!");
+               return s_err;
+       }
+       select_offscreen_port (record);
+       do_set_port_font (record);
+       return clear_tty (window);
+}
+
+
+#if 0
+/*
+ * Update TTY according to new color environment for the window
+ */
+static short
+tty_environment_changed (tty_record *record) {
+Point p = {0, 0};
+Rect r_screen;
+
+       if (record->uses_gworld) {
+               r_screen = record->its_bits.bounds;
+               LocalToGlobal (&p);
+               OffsetRect (&r_screen, p.h, p.v);
+               UpdateGWorld (&(record->offscreen_world), 0, &r_screen,
+                       (CTabHandle) 0, (GDHandle) 0, stretchPix);
+               select_offscreen_port (record);
+               SetOrigin (0, 0);
+               select_onscreen_window (record);
+       }
+       return 0;
+}
+#endif
+
+
+/*
+ * Read a lot of interesting and useful information from the current tty
+ */
+short
+get_tty_metrics (WindowPtr window, short *x_size, short *y_size,
+       short *x_size_pixels, short *y_size_pixels, short *font_number,
+       short *font_size, short *char_width, short *row_height) {
+RECORD_EXISTS (record);
+
+/*
+ * First, test that we actually have something to draw to...
+ */
+       if ((((char *)0 == record->its_bits.baseAddr) && !record->uses_gworld) ||
+               (((GWorldPtr)0 == record->offscreen_world) && record->uses_gworld)) {
+               return general_failure;
+       }
+
+       *x_size = record->x_size;
+       *y_size = record->y_size;
+       *x_size_pixels = record->its_bits.bounds.right;
+       *y_size_pixels = record->its_bits.bounds.bottom;
+       *font_number = record->font_number;
+       *font_size = record->font_size;
+       *char_width = record->char_width;
+       *row_height = record->row_height;
+
+       return noErr;
+}
+
+
+/*
+ * Map a position on the map to screen coordinates
+ */
+static void
+pos_rect (tty_record *record, Rect *r, short x_pos, short y_pos,
+       short x_end, short y_end) {
+       SetRect (r, x_pos * (record->char_width), y_pos * (record->row_height),
+               (1 + x_end) * (record->char_width) , (1 + y_end) *
+               (record->row_height));
+}
+
+
+static void
+accumulate_rect (tty_record *record, Rect *rect) {
+#if CLIP_RECT_ONLY
+       union_rect (rect, &(record->invalid_rect), &(record->invalid_rect));
+#else
+RgnHandle rh = NewRgn ();
+
+       RectRgn (rh, rect);
+       UnionRgn (record->invalid_part, rh, record->invalid_part);
+       DisposeRgn (rh);
+#endif
+}
+
+
+/*
+ * get and set window invalid region.  exposed for HandleUpdateEvent in macwin.c
+ * to correct display problem
+ */
+
+short get_invalid_region (WindowPtr window, Rect *inval_rect) {
+       RECORD_EXISTS (record);
+#if CLIP_RECT_ONLY
+       if (record->invalid_rect.right <= record->invalid_rect.left ||
+               record->invalid_rect.bottom <= record->invalid_rect.top) {
+               return general_failure;
+       }
+       *inval_rect = record->invalid_rect;
+#else
+       if (EmptyRgn (record->invalid_part)) {
+               return general_failure;
+       }
+       *inval_rect = (*(record->invalid_part))->rgnBBox;
+#endif
+       return noErr;
+}
+
+short set_invalid_region (WindowPtr window, Rect *inval_rect) {
+       RECORD_EXISTS (record);
+       accumulate_rect (record, inval_rect);
+       return noErr;
+}
+
+
+/*
+ * Invert the specified position
+ */
+static void
+curs_pos (tty_record *record, short x_pos, short y_pos, short to_state) {
+Rect r;
+
+       if (record->curs_state == to_state) {
+               return;
+       }
+       record->curs_state = to_state;
+       pos_rect (record, &r, x_pos, y_pos, x_pos, y_pos);
+
+       if (DRAW_DIRECT) {
+       void *old_port;
+
+               save_port (record, &old_port);
+               select_onscreen_window (record);
+               InvertRect (&r);
+               use_port (record, old_port);
+       } else {
+               accumulate_rect (record, &r);
+       }
+}
+
+
+/*
+ * Move the cursor (both as displayed and where drawing goes)
+ * HOWEVER: The cursor is NOT stored in the bitmap!
+ */
+short
+move_tty_cursor (WindowPtr window, short x_pos, short y_pos) {
+RECORD_EXISTS (record);
+
+       if (record->x_curs == x_pos && record->y_curs == y_pos) {
+               return noErr;
+       }
+       if (record->x_size <= x_pos || x_pos < 0 ||
+               record->y_size <= y_pos || y_pos < 0) {
+               return general_failure;
+       }
+       curs_pos (record, record->x_curs, record->y_curs, 0);
+       record->x_curs = x_pos;
+       record->y_curs = y_pos;
+       curs_pos (record, x_pos, y_pos, 1);
+
+       return noErr;
+}
+
+
+/*
+ * Update the screen to match the current bitmap, after adding stuff
+ * with add_tty_char etc.
+ */
+short
+update_tty (WindowPtr window) {
+Rect r;
+RECORD_EXISTS (record);
+
+#if CLIP_RECT_ONLY
+       if (record->invalid_rect.right <= record->invalid_rect.left ||
+               record->invalid_rect.bottom <= record->invalid_rect.top) {
+               return noErr;
+       }
+       r = record->invalid_rect;
+#else
+       if (EmptyRgn (record->invalid_part)) {
+               return noErr;
+       }
+       r = (*(record->invalid_part))->rgnBBox;
+#endif
+       select_onscreen_window (record);
+       copy_bits (record, &r, srcCopy, (RgnHandle) 0);
+#if CLIP_RECT_ONLY
+       empty_rect (&(record->invalid_rect));
+#else
+       SetEmptyRgn (record->invalid_part);
+#endif
+       if (record->curs_state) {       
+               pos_rect (record, &r, record->x_curs, record->y_curs,
+                       record->x_curs, record->y_curs);
+               InvertRect (&r);
+       }
+
+       return noErr;
+}
+
+
+/*
+ * Low level add to screen
+ */
+static void
+do_add_string (tty_record *record, char *str, short len) {
+Rect r;
+
+       if (len < 1) {
+               return;
+       }
+       select_offscreen_port (record);
+
+       MoveTo (record->x_curs * record->char_width, record->y_curs *
+               record->row_height + record->ascent_height);
+       DrawText (str, 0, len);
+
+       pos_rect (record, &r, record->x_curs, record->y_curs,
+               record->x_curs + len - 1, record->y_curs);
+       select_onscreen_window (record);
+       if (DRAW_DIRECT) {
+               copy_bits (record, &r, srcCopy, (RgnHandle)0);
+       } else {
+               accumulate_rect (record, &r);
+       }
+}
+
+
+/*
+ * Low-level cursor handling routine
+ */
+static void
+do_add_cursor (tty_record *record, short x_pos) {
+
+       record->x_curs = x_pos;
+       if (record->x_curs >= record->x_size) {
+               if (0L != (record->attribute [TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND)) {
+                       record->y_curs ++;
+                       record->x_curs = 0;
+                       if (record->y_curs >= record->y_size) {
+                               if (0L != (record->attribute [TTY_ATTRIB_FLAGS] &
+                                       TA_INHIBIT_VERT_SCROLL)) {
+                                       record->y_curs = record->y_size;
+                               } else {
+                                       scroll_tty (record->its_window, 0, 1 + record->y_curs -
+                                               record->y_size);
+                               }
+                       }
+               } else {
+                       record->x_curs = record->x_size;
+               }
+       }
+}
+
+
+/*
+ * Do control character
+ */
+static void
+do_control (tty_record *record, short character) {
+       int recurse = 0;
+
+/*
+ * Check recursion because nl_add_cr and cr_add_nl may both be set and invoke each other
+ */
+       do {
+               switch (character) {
+               case CHAR_CR :
+                       record->x_curs = 0;
+                       if (!recurse && (record->attribute [TTY_ATTRIB_CURSOR] & TA_CR_ADD_NL)) {
+                               recurse = 1;
+                       }
+                       else {
+                               recurse = 0;
+                               break;
+                       }       /* FALL-THROUGH: if CR-LF, don't bother with loop */
+               case CHAR_LF :
+                       record->y_curs++;
+                       if (record->y_curs >= record->y_size) {
+                               scroll_tty (record->its_window, 0, 1 + record->y_curs - record->y_size);
+                       }
+                       if (!recurse && (record->attribute [TTY_ATTRIB_CURSOR] & TA_NL_ADD_CR)) {
+                               character = CHAR_CR;
+                               recurse = 1;
+                       }
+                       else recurse = 0;
+                       break;
+               case CHAR_BELL :
+                       tty_nhbell();
+                       break;
+               case CHAR_BS :
+                       if (record->x_curs > 0)
+                               record->x_curs --;
+               default :
+                       break;
+               }
+       } while (recurse);
+}
+
+
+/*
+ * Add a single character. It is drawn directly if the correct flag is set,
+ * else deferred to the next update event or call of update_tty()
+ */
+short
+add_tty_char (WindowPtr window, short character) {
+register char is_control;
+char ch;
+RECORD_EXISTS (record);
+
+       if (!(record->attribute [TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND) && 
+               record->x_curs >= record->x_size)
+               return noErr;           /* Optimize away drawing across border without wrap */
+
+       if (record->curs_state != 0)
+               curs_pos (record, record->x_curs, record->y_curs, 0);
+
+       ch = character;
+       is_control = (ch < sizeof(long) * 8) && ((s_control & (1 << ch)) != 0L);
+       if (is_control)
+               do_control (record, ch);
+       else {
+               do_add_string (record, (char *)&ch, 1);
+               do_add_cursor (record, record->x_curs + 1);
+       }
+
+       return noErr;
+}
+
+
+/*
+ * Add a null-terminated string of characters
+ */
+short
+add_tty_string(WindowPtr window, const char *string)
+{
+       register const unsigned char * start_c;
+       register const unsigned char * the_c;
+       register unsigned char ch, is_control = 0, tty_wrap;
+       register short max_x, pos_x;
+       RECORD_EXISTS (record);
+
+       if (record->curs_state != 0)
+               curs_pos (record, record->x_curs, record->y_curs, 0);
+
+       the_c = (const unsigned char *) string;
+       max_x = record->x_size;
+       tty_wrap = (record->attribute [TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND);
+       for (;;) {
+               pos_x = record->x_curs;
+               if (!tty_wrap && pos_x >= max_x) 
+                       break;          /* Optimize away drawing across border without wrap */
+
+               start_c = the_c;
+               ch = *the_c;
+               while (pos_x < max_x) {
+                       is_control = (ch < sizeof(long) * 8) && ((s_control & (1 << ch)) != 0L);
+                       if (is_control)
+                               break;
+                       the_c ++; ch = *the_c;
+                       pos_x ++;
+               }
+               do_add_string (record, (char *) start_c, the_c - start_c);
+               do_add_cursor (record, pos_x);
+               if (!ch)
+                       break;
+
+               if (is_control) {
+                       do_control (record, ch);
+                       the_c ++;
+               }
+       }
+
+       return noErr;
+}
+
+
+/*
+ * Read or change attributes for the tty. Note that some attribs may
+ * very well clear and reallocate the bitmap when changed, whereas
+ * others (color, highlight, ...) are guaranteed not to.
+ */
+short get_tty_attrib (WindowPtr window, tty_attrib attrib, long *value) {
+RECORD_EXISTS (record);
+
+       if (attrib < 0 || attrib >= TTY_NUMBER_ATTRIBUTES) {
+               return general_failure;
+       }
+       *value = record->attribute [attrib];
+
+       return noErr;
+}
+
+
+short set_tty_attrib (WindowPtr window, tty_attrib attrib, long value) {
+RGBColor rgb_color;
+RECORD_EXISTS (record);
+
+       if (attrib < 0 || attrib >= TTY_NUMBER_ATTRIBUTES) {
+               return general_failure;
+       }
+       record->attribute [attrib] = value;
+       /*
+        * Presently, no attributes generate a new bitmap.
+        */
+       switch (attrib) {
+       case TTY_ATTRIB_CURSOR :
+/*
+ * Check if we should change tables
+ */
+               if (0L != (value & TA_RAW_OUTPUT)) {
+                       s_control = RAW_CONTROLS;
+               } else {
+                       s_control = COOKED_CONTROLS;
+               }
+               break;
+       case TTY_ATTRIB_FLAGS :
+/*
+ * Check if we should flush the output going from cached to draw-direct
+ */
+               if (0L != (value & TA_ALWAYS_REFRESH)) {
+                       update_tty (window);
+               }
+               break;
+       case TTY_ATTRIB_FOREGROUND :
+/*
+ * Set foreground color
+ */
+               TA_TO_RGB (value, rgb_color);
+               select_offscreen_port (record);
+               RGBForeColor (&rgb_color);
+               select_onscreen_window (record);
+               break;
+       case TTY_ATTRIB_BACKGROUND :
+/*
+ * Set background color
+ */
+               TA_TO_RGB (value, rgb_color);
+               select_offscreen_port (record);
+               RGBBackColor (&rgb_color);
+               select_onscreen_window (record);
+               break;
+       default :
+               break;
+       }
+       return noErr;
+}
+
+
+/*
+ * Scroll the window. Positive is up/left. scroll_tty ( window, 0, 1 ) is a line feed.
+ * Scroll flushes the accumulated update area by calling update_tty().
+ */
+
+short scroll_tty (WindowPtr window, short delta_x, short delta_y) {
+RgnHandle rgn;
+short s_err;
+RECORD_EXISTS (record);
+
+       s_err = update_tty (window);
+
+       rgn = NewRgn ();
+
+       select_offscreen_port (record);
+       ScrollRect (&(record->its_bits.bounds), -delta_x * record->char_width,
+               -delta_y * record->row_height, rgn);
+       EraseRgn (rgn);
+       SetEmptyRgn (rgn);
+
+       select_onscreen_window (record);
+       ScrollRect (&(record->its_bits.bounds), -delta_x * record->char_width,
+               -delta_y*record->row_height, rgn);
+       EraseRgn (rgn);
+       DisposeRgn (rgn);
+
+       record->y_curs -= delta_y;
+       record->x_curs -= delta_x;
+
+       return noErr;
+}
+
+
+/*
+ * Clear the screen. Immediate.
+ */
+short clear_tty (WindowPtr window) {
+RECORD_EXISTS (record);
+
+       record->curs_state = 0;
+       select_offscreen_port (record);
+       erase_rect (record, &(record->its_bits.bounds));
+       accumulate_rect (record, &(record->its_bits.bounds));
+       update_tty (window);
+
+       return noErr;
+}
+
+
+/*
+ * Blink cursor on window if necessary
+ */
+short blink_cursor (WindowPtr window, long when) {
+       RECORD_EXISTS (record);
+
+       if ((record->attribute [TTY_ATTRIB_CURSOR] & TA_BLINKING_CURSOR)) {
+               if (when > record->last_cursor + GetCaretTime ()) {
+                       curs_pos (record, record->x_curs, record->y_curs, !record->curs_state);
+                       record->last_cursor = when;
+                       update_tty (window);
+               }
+       }
+       return 0;
+}
+
+
+/*
+ * Draw an image of the tty - used for update events and can be called
+ * for screen dumps.
+ */
+short
+image_tty (EventRecord *theEvent, WindowPtr window) {
+#if defined(__SC__) || defined(__MRC__)
+# pragma unused(theEvent)
+#endif
+RECORD_EXISTS (record);
+
+#if CLIP_RECT_ONLY
+       record->invalid_rect = record->its_bits.bounds;
+#else
+RgnHandle rh = NewRgn ();
+
+       RectRgn (rh, record ->its_bits.bounds);
+       UnionRgn (record->invalid_part, rh, record->invalid_part);
+       DisposeRgn (rh);
+#endif
+       return update_tty (window);
+}
+
+
+
+/*
+ * Clear an area
+ */
+short clear_tty_window (WindowPtr window, short from_x, short from_y,
+       short to_x, short to_y) {
+Rect r;
+RECORD_EXISTS (record);
+
+       if (from_x > to_x || from_y > to_y) {
+               return general_failure;
+       }
+       pos_rect (record, &r, from_x, from_y, to_x, to_y);
+       select_offscreen_port (record);
+       erase_rect (record, &r);
+       accumulate_rect (record, &r);
+       if (DRAW_DIRECT) {
+               update_tty (window);
+       } else
+               select_onscreen_window (record);
+       return noErr;
+}
+
+
+#if EXTENDED_SUPPORT
+/*
+ * Delete or insert operations used by many terminals can bottleneck through
+ * here. Note that the order of executin for row/colum insertions is NOT
+ * specified. Negative values for num_ mean delete, zero means no effect.
+ */
+short mangle_tty_rows_columns (WindowPtr window, short from_row, short num_rows,
+       short from_column, short num_columns) {
+Rect r;
+RgnHandle rh = NewRgn ();
+RECORD_EXISTS (record);
+
+       update_tty (window); /* Always make sure screen is OK */
+       curs_pos (record, record->x_curs, record->y_curs, 0);
+
+       if (num_rows) {
+               pos_rect (record, &r, 0, from_row, record->x_size - 1,
+                       record->y_size - 1);
+               select_offscreen_port (record);
+               ScrollRect (&r, 0, num_rows * record->row_height, rh);
+               EraseRgn (rh);
+               SetEmptyRgn (rh);
+               select_onscreen_window (record);
+               ScrollRect (&r, 0, num_rows * record->row_height, rh);
+               EraseRgn (rh);
+               SetEmptyRgn (rh);
+       }
+       if (num_columns) {
+               pos_rect (record, &r, from_column, 0, record->x_size - 1,
+                       record->y_size - 1);
+               select_offscreen_port (record);
+               ScrollRect (&r, num_columns * record->char_width, 0, rh);
+               EraseRgn (rh);
+               SetEmptyRgn (rh);
+               select_onscreen_window (record);
+               ScrollRect (&r, num_columns * record->char_width, 0, rh);
+               EraseRgn (rh);
+               SetEmptyRgn (rh);
+       }
+       DisposeRgn (rh);
+       if (record->x_curs >= from_column) {
+               record->x_curs += num_columns;
+       }
+       if (record->y_curs >= from_row) {
+               record->y_curs += num_rows;
+       }
+       curs_pos (record, record->x_curs, record->y_curs, 1);
+
+       return noErr;
+}
+
+/*
+ * Frame an area in an aesthetically pleasing way.
+ */
+short frame_tty_window (WindowPtr window, short from_x, short from_y ,
+       short to_x, short to_y, short frame_fatness) {
+Rect r;
+RECORD_EXISTS (record);
+
+       if (from_x > to_x || from_y > to_y) {
+               return general_failure;
+       }
+       pos_rect (record, & r, from_x, from_y, to_x, to_y);
+       select_offscreen_port (record);
+       PenSize (frame_fatness, frame_fatness);
+       FrameRect (&r);
+       PenNormal ();
+       accumulate_rect (record, &r);
+       if (DRAW_DIRECT) {
+               update_tty (window);
+       } else
+               select_onscreen_window (record);
+}
+
+
+/*
+ * Highlighting a specific part of the tty window
+ */
+short invert_tty_window (WindowPtr window, short from_x, short from_y ,
+       short to_x, short to_y) {
+Rect r;
+RECORD_EXISTS (record);
+
+       if (from_x > to_x || from_y > to_y) {
+               return general_failure;
+       }
+       pos_rect (record, &r, from_x, from_y, to_x, to_y);
+       select_offscreen_port (record);
+       InvertRect ( &r);
+       accumulate_rect (record, &r);
+       if (DRAW_DIRECT) {
+               update_tty (window);
+       } else
+               select_onscreen_window (record);
+}
+
+
+static void
+canonical_rect (Rect * r, short x1, short y1, short x2, short y2) {
+       if (x1 < x2) {
+               if (y1 < y2) {
+                       SetRect (r, x1, x2, y1, y2);
+               } else {
+                       SetRect (r, x1, x2, y2, y1);
+               }
+       } else {
+               if (y1 < y2) {
+                       SetRect (r, x2, x1, y1, y2);
+               } else {
+                       SetRect (r, x2, x1, y2, y1);
+               }
+       }
+}
+
+
+/*
+ * Line drawing - very device dependent
+ */
+short draw_tty_line (WindowPtr window, short from_x, short from_y ,
+       short to_x, short to_y) {
+Rect r;
+RECORD_EXISTS (record);
+
+       select_offscreen_port (record);
+       MoveTo (from_x, from_y);
+       LineTo (to_x, to_y);
+       canonical_rect (&r, from_x, from_y, to_x, to_y);
+       accumulate_rect (record, &r);
+       if (DRAW_DIRECT) {
+               update_tty (window);
+       } else
+               select_onscreen_window (record);
+}
+
+
+#endif /* EXTENDED_SUPPORT */
diff --git a/sys/mac/macunix.c b/sys/mac/macunix.c
new file mode 100644 (file)
index 0000000..aedcc0e
--- /dev/null
@@ -0,0 +1,38 @@
+/*     SCCS Id: @(#)macunix.c  3.1     94/11/07        */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* This file collects some Unix dependencies */
+
+#include "hack.h"
+
+void
+regularize(char *s)
+{
+       register char *lp;
+
+       for (lp = s; *lp; lp++) {
+               if (*lp == '.' || *lp == ':')
+                       *lp = '_';
+       }
+}
+
+void
+getlock(void)
+{
+       int fd;
+       int pid = getpid(); /* Process ID */
+       
+       set_levelfile_name (lock, 0);
+
+       if ((fd = open (lock, O_RDWR | O_EXCL | O_CREAT, LEVL_TYPE)) == -1) {
+               raw_printf ("Could not lock the game %s.", lock);
+               panic ("Another game in progress?");
+       }
+
+       if (write (fd, (char *)&pid, sizeof (pid)) != sizeof (pid))  {
+               raw_printf ("Could not lock the game %s.", lock);
+               panic("Disk locked?");
+       }
+       close (fd);
+}
diff --git a/sys/mac/macwin.c b/sys/mac/macwin.c
new file mode 100644 (file)
index 0000000..a54f454
--- /dev/null
@@ -0,0 +1,2650 @@
+/*     SCCS Id: @(#)macwin.c   3.4     1996/01/15      */
+/* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "func_tab.h"
+#include "macwin.h"
+#include "mactty.h"
+#include "wintty.h"
+
+#if !TARGET_API_MAC_CARBON
+#include <LowMem.h>
+#include <AppleEvents.h>
+#include <Gestalt.h>
+#include <TextUtils.h>
+#include <DiskInit.h>
+#include <ControlDefinitions.h>
+#endif
+
+NhWindow *theWindows = (NhWindow *) 0;
+Cursor qdarrow;
+
+/* Borrowed from the Mac tty port */
+extern WindowPtr _mt_window;
+
+/* Some useful #defines for the scroll bar width and height */
+#define                SBARWIDTH       15
+#define                SBARHEIGHT      15
+
+/*
+ * We put a TE on the message window for the "top line" queries.
+ * top_line is the TE that holds both the query and the user's
+ * response.  The first topl_query_len characters in top_line are
+ * the query, the rests are the response.  topl_resp is the valid
+ * response to a yn query, while topl_resp[topl_def_idx] is the
+ * default response to a yn query.
+ */
+static TEHandle top_line = (TEHandle) nil;
+static int     topl_query_len;
+static int     topl_def_idx = -1;
+static char    topl_resp[10] = "";
+
+#define CHAR_ANY '\n'
+
+/*
+ * inSelect means we have a menu window up for selection or
+ * something similar. It makes the window with win number ==
+ * inSelect a movable modal (unfortunately without the border)
+ * and clicking the close box forces an RET into the key
+ * buffer. Don't forget to set inSelect to WIN_ERR when you're
+ * done...
+ */
+static winid inSelect = WIN_ERR;
+
+/*
+ * The key queue ring buffer where Read is where to take from, 
+ * Write is where next char goes and count is queue depth.
+ */
+static unsigned char keyQueue [QUEUE_LEN];
+static int keyQueueRead = 0,
+       keyQueueWrite = 0,
+       keyQueueCount = 0;
+
+static Boolean gClickedToMove = 0;     /* For ObscureCursor */
+
+static Point clicked_pos;      /* For nh_poskey */
+static int clicked_mod;
+static Boolean cursor_locked = false;
+
+static ControlActionUPP MoveScrollUPP;         /* scrolling callback, init'ed in InitMac */
+
+void
+lock_mouse_cursor(Boolean new_cursor_locked) {
+       cursor_locked = new_cursor_locked;
+}
+
+
+/*
+ * Add key to input queue, force means flush left and replace if full
+ */
+void
+AddToKeyQueue (unsigned char ch, Boolean force) {
+       if (keyQueueCount < QUEUE_LEN) {
+               keyQueue [keyQueueWrite++] = ch;
+               keyQueueCount++;
+       }
+       else if (force) {
+               keyQueue [keyQueueWrite++] = ch;
+               keyQueueRead++;
+               if (keyQueueRead >= QUEUE_LEN)
+                       keyQueueRead = 0;
+               keyQueueCount = QUEUE_LEN;
+       }
+       if (keyQueueWrite >= QUEUE_LEN)
+               keyQueueWrite = 0;
+}
+
+
+/*
+ * Get key from queue
+ */
+unsigned char
+GetFromKeyQueue (void) {
+       unsigned char ret;
+
+       if (keyQueueCount) {
+               ret = keyQueue [keyQueueRead++];
+               keyQueueCount--;
+               if (keyQueueRead >= QUEUE_LEN)
+                       keyQueueRead = 0;
+       }
+       else
+               ret = 0;
+       return ret;
+}
+
+
+/*
+ * Cursor movement
+ */
+static RgnHandle gMouseRgn = (RgnHandle) 0;
+
+/*
+ * _Gestalt madness - we rely heavily on the _Gestalt glue, since we
+ * don't check for the trap...
+ */
+MacFlags macFlags;
+
+/*
+ * The screen layouts on the small 512x342 screen need special cares.
+ */
+Boolean small_screen = 0;
+
+#ifdef NHW_BASE
+# undef NHW_BASE
+#endif
+#define NHW_BASE 0
+
+static int FDECL(filter_scroll_key,(const int, NhWindow *));
+
+static void FDECL(GeneralKey, (EventRecord *, WindowPtr));
+static void FDECL(macKeyMenu, (EventRecord *, WindowPtr));
+static void FDECL(macKeyText, (EventRecord *, WindowPtr));
+
+static void FDECL(macClickMessage, (EventRecord *, WindowPtr));
+static void FDECL(macClickTerm, (EventRecord *, WindowPtr));
+static void FDECL(macClickMenu, (EventRecord *, WindowPtr));
+static void FDECL(macClickText, (EventRecord *, WindowPtr));
+
+static short FDECL(macDoNull, (EventRecord *, WindowPtr));
+static short FDECL(macUpdateMessage, (EventRecord *, WindowPtr));
+static short FDECL(macUpdateMenu, (EventRecord *, WindowPtr));
+static short FDECL(GeneralUpdate, (EventRecord *, WindowPtr));
+
+static void FDECL(macCursorTerm, (EventRecord *, WindowPtr, RgnHandle));
+static void FDECL(GeneralCursor, (EventRecord *, WindowPtr, RgnHandle));
+
+static void FDECL(DoScrollBar,(Point, short, ControlHandle, NhWindow *));
+static pascal void FDECL(MoveScrollBar, (ControlHandle, short));
+
+typedef void (*CbFunc) (EventRecord *, WindowPtr);
+typedef short (*CbUpFunc) (EventRecord *, WindowPtr);
+typedef void (*CbCursFunc) (EventRecord *, WindowPtr, RgnHandle);
+
+#define NUM_FUNCS 6
+static const CbFunc winKeyFuncs [NUM_FUNCS] = {
+       GeneralKey, GeneralKey, GeneralKey, GeneralKey, macKeyMenu, macKeyText
+};
+
+static const CbFunc winClickFuncs [NUM_FUNCS] = {
+       (CbFunc)macDoNull, macClickMessage, macClickTerm, macClickTerm, macClickMenu,
+       macClickText
+};
+
+static const CbUpFunc winUpdateFuncs [NUM_FUNCS] = {
+       macDoNull, macUpdateMessage, image_tty, image_tty,
+       macUpdateMenu, GeneralUpdate
+};
+
+static const CbCursFunc winCursorFuncs [NUM_FUNCS] = {
+       (CbCursFunc) macDoNull, GeneralCursor, macCursorTerm, macCursorTerm,
+       GeneralCursor, GeneralCursor
+};
+
+
+static NhWindow *
+GetNhWin(WindowPtr mac_win) {
+       if (mac_win == _mt_window)      /* term window is still maintained by both systems, and */
+               return theWindows;              /* WRefCon still refers to tty struct, so we have to map it */
+       else {
+               NhWindow *aWin = (NhWindow *)GetWRefCon (mac_win);
+               if (aWin >= theWindows && aWin < &theWindows[NUM_MACWINDOWS])
+                       return aWin;
+       }
+       return ((NhWindow *) nil);
+}
+
+
+Boolean CheckNhWin (WindowPtr mac_win) {
+       return GetNhWin (mac_win) != nil;
+}
+
+
+static pascal OSErr
+AppleEventHandler (const AppleEvent* inAppleEvent, AppleEvent* outAEReply, long inRefCon) {
+#if defined(__SC__) || defined(__MRC__)
+# pragma unused(outAEReply,inRefCon)
+#endif
+       Size     actualSize;
+       DescType typeCode;
+       AEEventID EventID;
+       OSErr    err;
+
+       /* Get Event ID */
+       err = AEGetAttributePtr (inAppleEvent, keyEventIDAttr, typeType, &typeCode,
+                                                               &EventID, sizeof (EventID), &actualSize);
+       if (err == noErr) {
+               switch (EventID) {
+                       default :
+                       case kAEOpenApplication :
+                               macFlags.gotOpen = 1;
+                               /* fall through */
+                       case kAEPrintDocuments :
+                               err = errAEEventNotHandled;
+                               break;
+                       case kAEQuitApplication :
+                               /* Flush key queue */
+                               keyQueueCount = keyQueueWrite = keyQueueRead = 0;
+                               AddToKeyQueue ('S', 1);
+                               break;
+                       case kAEOpenDocuments : {
+                               FSSpec      fss;
+                               FInfo fndrInfo;
+                               AEKeyword   keywd;
+                               AEDescList  docList;
+                               long     index, itemsInList;
+
+                               if((err = AEGetParamDesc(inAppleEvent, keyDirectObject, typeAEList, &docList)) != noErr ||
+                                       (err = AECountItems(&docList, &itemsInList)) != noErr){
+                                       if (err == errAEDescNotFound)
+                                               itemsInList = 0;
+                                       else
+                                               break;
+                               }
+
+                               for(index = 1; index <= itemsInList; index++){
+                                       err = AEGetNthPtr(&docList, index, typeFSS, &keywd, &typeCode, (Ptr)&fss,
+                                                               sizeof(FSSpec), &actualSize);
+                                       if(noErr != err)
+                                               break;
+
+                                       err = FSpGetFInfo (&fss, &fndrInfo);
+                                       if (noErr != err)
+                                               break;
+
+                                       if (fndrInfo.fdType != SAVE_TYPE) 
+                                               continue;       /* only look at save files */
+
+                                       process_openfile (fss.vRefNum, fss.parID, fss.name, fndrInfo.fdType);
+                                       if (macFlags.gotOpen)
+                                               break;  /* got our save file */
+                               }
+                               err = AEDisposeDesc(&docList);
+                               break;
+                       }
+               }
+       }                       
+
+       /* Check to see if all required parameters for this type of event are present */
+       if (err == noErr) {
+               err = AEGetAttributePtr (inAppleEvent, keyMissedKeywordAttr, 
+                                                               typeWildCard, &typeCode, NULL, 0, &actualSize);
+               if (err == errAEDescNotFound)                                                                                    
+                       err = noErr;            /* got all the required parameters */
+               else if (err == noErr)  /* missed a required parameter */
+                       err = errAEEventNotHandled;
+       }
+
+       return err;
+}
+
+
+short win_fonts [NHW_TEXT + 1];
+
+void
+InitMac(void) {
+       short i;
+       long l;
+       Str255 volName;
+
+
+#if !TARGET_API_MAC_CARBON
+       if (LMGetDefltStack() < 50 * 1024L) {
+               SetApplLimit ((void *) ((long) LMGetCurStackBase() - (50 * 1024L)));
+       }
+       MaxApplZone ();
+       for (i = 0; i < 5; i ++)
+               MoreMasters ();
+
+       InitGraf (&qd.thePort);
+       InitFonts ();
+       InitWindows ();
+       InitMenus ();
+       InitDialogs (0L);
+       TEInit ();
+#endif
+
+       memset (&macFlags, 0, sizeof(macFlags));
+       if (!Gestalt (gestaltOSAttr, & l)) {
+               macFlags.processes = (l & (1 << gestaltLaunchControl)) ? 1 : 0;
+               macFlags.tempMem = (l & (1 << gestaltRealTempMemory)) ? 1 : 0;
+               macFlags.hasDebugger = (l & (1 << gestaltSysDebuggerSupport)) ? 1 : 0;
+       }
+       if (!Gestalt (gestaltQuickdrawVersion, & l))
+               macFlags.color = (l >= gestalt8BitQD) ? 1 : 0;
+
+       if (!Gestalt (gestaltFindFolderAttr, & l))
+               macFlags.folders = (l & (1 << gestaltFindFolderPresent)) ? 1 : 0;
+               
+       if (!Gestalt (gestaltHelpMgrAttr, & l))
+               macFlags.help = (l & (1 << gestaltHelpMgrPresent)) ? 1 : 0;
+
+       if (!Gestalt (gestaltFSAttr, & l))
+               macFlags.fsSpec = (l & (1 << gestaltHasFSSpecCalls)) ? 1 : 0;
+
+       if (!Gestalt (gestaltFontMgrAttr, & l))
+               macFlags.trueType = (l & (1 << gestaltOutlineFonts)) ? 1 : 0;
+
+       if (!Gestalt (gestaltAUXVersion, & l))
+               macFlags.aux = (l >= 0x200) ? 1 : 0;
+
+       if (!Gestalt (gestaltAliasMgrAttr, & l))
+               macFlags.alias = (l & (1 << gestaltAliasMgrPresent)) ? 1 : 0;
+
+       if (!Gestalt (gestaltStandardFileAttr, & l))
+               macFlags.standardFile = (l & (1 << gestaltStandardFile58)) ? 1 : 0;
+
+       gMouseRgn = NewRgn ();
+       InitCursor();
+       GetQDGlobalsArrow(&qdarrow);
+       ObscureCursor ();
+       
+       MoveScrollUPP = NewControlActionUPP(MoveScrollBar);
+
+       /* Set up base fonts for all window types */
+       GetFNum ("\pHackFont", &i);
+       if (i == 0)
+               i = kFontIDMonaco;
+       win_fonts [NHW_BASE] = win_fonts [NHW_MAP] = win_fonts [NHW_STATUS] = i;
+       GetFNum ("\pPSHackFont", &i);
+       if (i == 0)
+               i = kFontIDGeneva;
+       win_fonts [NHW_MESSAGE] = i;
+       win_fonts [NHW_TEXT] = kFontIDGeneva;
+
+       macFlags.hasAE = 0;
+       if(!Gestalt(gestaltAppleEventsAttr, &l) && (l & (1L << gestaltAppleEventsPresent))){
+               if (AEInstallEventHandler (kCoreEventClass, typeWildCard,
+                                                       NewAEEventHandlerUPP(AppleEventHandler),
+                                                       0,
+                                                       FALSE) == noErr)
+                       macFlags.hasAE = 1;
+       }
+
+#if TARGET_API_MAC_CARBON
+       HGetVol(volName, &theDirs.dataRefNum, &theDirs.dataDirID);
+#else
+       /*
+        * We should try to get this data from a rsrc, in the profile file
+        * the user double-clicked...  This data should be saved with the
+        * save file in the resource fork, AND be saveable in "stationary"
+        */
+       GetVol (volName, &theDirs.dataRefNum );
+       GetWDInfo (theDirs.dataRefNum, &theDirs.dataRefNum, &theDirs.dataDirID, &l);
+#endif
+       if (volName [0] > 31) volName [0] = 31;
+       for (l = 1; l <= volName [0]; l++) {
+               if (volName [l] == ':') {
+                       volName [l] = 0;
+                       volName [0] = l - 1;
+                       break;
+               }
+       }
+       BlockMove (volName, theDirs.dataName, l);
+       BlockMove (volName, theDirs.saveName, l);
+       BlockMove (volName, theDirs.levelName, l);
+       theDirs.saveRefNum = theDirs.levelRefNum = theDirs.dataRefNum;
+       theDirs.saveDirID = theDirs.levelDirID = theDirs.dataDirID;
+
+       /* Create the "record" file, if necessary */
+       check_recordfile("");
+       return;
+}
+
+
+/*
+ * Change default window fonts.
+ */
+short
+set_tty_font_name (int window_type, char *font_name) {
+       short fnum;
+       Str255 new_font;
+       
+       if (window_type < NHW_BASE || window_type > NHW_TEXT)
+               return general_failure;
+               
+       C2P (font_name, new_font);
+       GetFNum (new_font, &(fnum));
+       if (!fnum)
+               return general_failure;
+       win_fonts [window_type] = fnum;
+       return noErr;
+}
+
+
+static void
+DrawScrollbar (NhWindow *aWin)
+{
+       WindowPtr theWindow = aWin->its_window;
+       Rect crect, wrect;
+       Boolean vis;
+       short val, lin, win_height;
+
+
+       if (!aWin->scrollBar)
+               return;
+       GetControlBounds(aWin->scrollBar, &crect);
+       GetWindowBounds(aWin->its_window, kWindowContentRgn, &wrect);
+       OffsetRect(&wrect, -wrect.left, -wrect.top);
+       win_height = wrect.bottom - wrect.top;
+
+       if (crect.top != wrect.top - 1 ||
+                crect.left != wrect.right - SBARWIDTH) {
+               MoveControl (aWin->scrollBar, wrect.right - SBARWIDTH, wrect.top - 1);
+       }
+       if (crect.bottom != wrect.bottom - SBARHEIGHT ||
+                crect.right != wrect.right + 1) {
+               SizeControl (aWin->scrollBar, SBARWIDTH+1, win_height - SBARHEIGHT + 2);
+       }
+       vis = (win_height > (50 + SBARHEIGHT));
+       if (vis != IsControlVisible(aWin->scrollBar)) {
+               /* current status != control */
+               if (vis)/* if visible, show */
+                       ShowControl (aWin->scrollBar);
+               else    /* else hide */
+                       HideControl (aWin->scrollBar);
+       }
+       lin = aWin->y_size;
+       if (aWin == theWindows + WIN_MESSAGE) {
+               /* calculate how big scroll bar is for message window */
+               lin -= (win_height - SBARHEIGHT) / aWin->row_height;
+               if (lin < 0)
+                       lin = 0;                
+               val = 0;                        /* always have message scrollbar active */
+       }
+       else {
+               /* calculate how big scroll bar is for other windows */
+               lin -= win_height / aWin->row_height;
+               if (lin < 0)
+                       lin = 0;
+               if (lin)        val = 0;        /* if there are 1+ screen lines, activate scrollbar */
+               else            val = 255;      /* else grey it out */
+       }
+       SetControlMaximum (aWin->scrollBar, lin);
+       HiliteControl (aWin->scrollBar, val);
+       val = GetControlValue (aWin->scrollBar);
+       if (val != aWin->scrollPos) {
+               InvalWindowRect(theWindow, &wrect);
+               aWin->scrollPos = val;
+       }
+}
+
+
+#define MAX_HEIGHT 100
+#define MIN_HEIGHT 50
+#define MIN_WIDTH 300
+
+/*
+ * This function could be overloaded with any amount of intelligence...
+ */
+int
+SanePositions (void)
+{
+#if TARGET_API_MAC_CARBON
+       ConstrainWindowToScreen(_mt_window, kWindowStructureRgn,
+               kWindowConstrainMoveRegardlessOfFit, NULL, NULL);
+#else
+       short left, top, width, height;
+       int ix, numText = 0, numMenu = 0;
+       int mbar_height = GetMBarHeight();
+       BitMap qbitmap;
+       Rect screenArea;
+       WindowPtr theWindow;
+       NhWindow *nhWin;
+
+
+       screenArea = GetQDGlobalsScreenBits(&qbitmap)->bounds;
+       OffsetRect (&screenArea, - screenArea.left, - screenArea.top);
+
+/* Map Window */
+       height = _mt_window->portRect.bottom - _mt_window->portRect.top;
+       width = _mt_window->portRect.right - _mt_window->portRect.left;
+
+       if (!RetrievePosition (kMapWindow, &top, &left)) {
+               top = mbar_height + (small_screen ? 2 : 20);
+               left = (screenArea.right - width) / 2;
+       }
+       MoveWindow (_mt_window, left, top, 1);
+
+/* Message Window */
+       if (!RetrievePosition (kMessageWindow, &top, &left)) {
+               top += height;
+               if (!small_screen)
+                       top += 20;
+       }
+
+       if (!RetrieveSize (kMessageWindow, top, left, &height, &width)) {
+               height = screenArea.bottom - top - (small_screen ? 2-SBARHEIGHT : 2);
+               if (height > MAX_HEIGHT) {
+                       height = MAX_HEIGHT;
+               } else if (height < MIN_HEIGHT) {
+                       height = MIN_HEIGHT;
+                       width = MIN_WIDTH;
+                       left = screenArea.right - width;
+                       top = screenArea.bottom - MIN_HEIGHT;
+               }
+       }
+
+/* Move these windows */
+       nhWin = theWindows + WIN_MESSAGE;
+       theWindow = nhWin->its_window;
+
+       MoveWindow (theWindow, left, top, 1);
+       SizeWindow (theWindow, width, height, 1);
+       if (nhWin->scrollBar)
+               DrawScrollbar (nhWin);
+
+       /* Handle other windows */
+       for (ix = 0; ix < NUM_MACWINDOWS; ix ++) {
+               if (ix != WIN_STATUS && ix != WIN_MESSAGE && ix != WIN_MAP && ix != BASE_WINDOW) {
+                       theWindow = theWindows [ix].its_window;
+                       if (theWindow && ((WindowPeek) theWindow)->visible) {
+                               int shift;
+                               if (((WindowPeek)theWindow)->windowKind == WIN_BASE_KIND + NHW_MENU) {
+                                       if (!RetrievePosition (kMenuWindow, &top, &left)) {
+                                               top = mbar_height * 2;
+                                               left = 2;
+                                       }
+                                       top += (numMenu * mbar_height);
+                                       numMenu++;
+                                       shift = 20;
+                               } else {
+                                       if (!RetrievePosition (kTextWindow, &top, &left)) {
+                                               top = mbar_height * 2;
+                                               left = screenArea.right - 3 - 
+                                                       (theWindow->portRect.right - theWindow->portRect.left);
+                                       }
+                                       top += (numText * mbar_height);
+                                       numText++;
+                                       shift = -20;
+                               }
+                               while (top > screenArea.bottom - MIN_HEIGHT) {
+                                       top -= screenArea.bottom - mbar_height * 2;
+                                       left += shift;
+                               }
+                               MoveWindow (theWindow, left, top, 1);
+                       }
+               }
+       }
+#endif
+       return (0);
+}
+
+
+winid
+mac_create_nhwindow (int kind) {
+       int i;
+       NhWindow *aWin;
+       FontInfo fi;
+
+       if (kind < NHW_BASE || kind > NHW_TEXT) {
+               error ("cre_win: Invalid kind %d.", kind);
+               return WIN_ERR;
+       }
+
+       for (i = 0; i < NUM_MACWINDOWS; i ++) {
+               if (!theWindows [i].its_window)
+                       break;
+       }
+       if (i >= NUM_MACWINDOWS) {
+               error ("cre_win: Win full; freeing extras");
+               for (i = 0; i < NUM_MACWINDOWS; i ++) {
+                       if (IsWindowVisible(theWindows [i].its_window) || i == WIN_INVEN ||
+                               GetWindowKind(theWindows [i].its_window) != WIN_BASE_KIND + NHW_MENU &&
+                               GetWindowKind(theWindows [i].its_window) != WIN_BASE_KIND + NHW_TEXT)
+                               continue;
+                       mac_destroy_nhwindow(i);
+                       goto got1;
+               }
+               error ("cre_win: Out of ids!");
+               return WIN_ERR;
+       }
+
+got1 :
+       aWin = &theWindows [i];
+       aWin->windowTextLen = 0L;
+       aWin->scrollBar = (ControlHandle) 0;
+       aWin->menuInfo = 0;
+       aWin->menuSelected = 0;
+       aWin->miLen = 0;
+       aWin->miSize = 0;
+       aWin->menuChar = 'a';
+       
+       dprintf ("cre_win: New kind %d", kind);
+
+       if (kind == NHW_BASE || kind == NHW_MAP || kind == NHW_STATUS) {
+               short x_sz, x_sz_p, y_sz, y_sz_p;
+               if (kind != NHW_BASE) {
+                       if (i != tty_create_nhwindow(kind)) {
+                               dprintf ("cre_win: error creating kind %d", kind);
+                       }
+                       if (kind == NHW_MAP) {
+                               wins[i]->offy = 0;      /* the message box is in a separate window */
+                       }
+               }
+               aWin->its_window = _mt_window;
+               get_tty_metrics(aWin->its_window, &x_sz, &y_sz, &x_sz_p, &y_sz_p,
+                                        &aWin->font_number, &aWin->font_size,
+                                        &aWin->char_width, &aWin->row_height);
+               return i;
+       }
+
+       aWin->its_window = GetNewWindow (WIN_BASE_RES + kind, (WindowPtr) 0L, (WindowPtr) -1L);
+       SetWindowKind(aWin->its_window, WIN_BASE_KIND + kind);
+       SetWRefCon(aWin->its_window, (long) aWin);
+       if (!(aWin->windowText = NewHandle (TEXT_BLOCK))) {
+               error ("cre_win: NewHandle fail(%ld)", (long) TEXT_BLOCK);
+               DisposeWindow (aWin->its_window);
+               aWin->its_window = (WindowPtr) 0;
+               return WIN_ERR;
+       }
+       aWin->x_size = aWin->y_size = 0;
+       aWin->x_curs = aWin->y_curs = 0;
+       aWin->drawn = TRUE;
+       mac_clear_nhwindow (i);
+
+       SetPortWindowPort(aWin->its_window);
+
+       if (kind == NHW_MESSAGE) {
+               aWin->font_number = win_fonts [NHW_MESSAGE];
+               aWin->font_size = iflags.wc_fontsiz_message? iflags.wc_fontsiz_message :
+                       iflags.large_font ? 12 : 9;
+               if (!top_line) {
+                       const Rect out_of_scr = {10000, 10000, 10100, 10100};
+                       TextFont(aWin->font_number);
+                       TextSize(aWin->font_size);
+                       TextFace(bold);
+                       top_line = TENew(&out_of_scr, &out_of_scr);
+                       TEActivate(top_line);
+                       TextFace(normal);
+               }
+       } else {
+               aWin->font_number = win_fonts [NHW_TEXT];
+               aWin->font_size = iflags.wc_fontsiz_text ? iflags.wc_fontsiz_text : 9;
+       }
+
+       TextFont (aWin->font_number); 
+       TextSize (aWin->font_size);
+
+       GetFontInfo (&fi);
+       aWin->ascent_height = fi.ascent + fi.leading;
+       aWin->row_height = aWin->ascent_height + fi.descent;
+       aWin->char_width = fi.widMax;
+
+       if (kind == NHW_MENU || kind == NHW_TEXT || kind == NHW_MESSAGE) {
+               Rect r;
+
+               GetWindowBounds(aWin->its_window, kWindowContentRgn, &r);
+               r.right -= (r.left - 1);
+               r.left = r.right - SBARWIDTH;
+               r.bottom -= (r.top + SBARHEIGHT);
+               r.top = -1;
+               aWin->scrollBar = NewControl (aWin->its_window, &r, "\p", (r.bottom > r.top + 50), 0, 0, 0, 16, 0L);
+               aWin->scrollPos = 0;
+       }
+       return i;
+}
+
+
+void
+mac_init_nhwindows (int *argcp, char **argv)
+{
+#if !TARGET_API_MAC_CARBON
+       Rect scr = (*GetGrayRgn())->rgnBBox;
+       small_screen = scr.bottom - scr.top <= (iflags.large_font ? 12*40 : 9*40);
+#endif
+       Rect r;
+
+
+       InitMenuRes ();
+
+       theWindows = (NhWindow *) NewPtrClear (NUM_MACWINDOWS * sizeof (NhWindow));
+       if (MemError())
+               error("mac_init_nhwindows: Couldn't allocate memory for windows.");
+
+       DimMenuBar ();
+
+       tty_init_nhwindows(argcp, argv);
+       iflags.window_inited = TRUE;
+
+       /* Some ugly hacks to make both interfaces happy:
+        * Mac port uses both tty interface (for main map) and extra windows.  The winids need to
+        * be kept in synch for both interfaces to map.  Also, the "blocked" display_nhwindow case
+        * for the map automatically calls the tty interface for the message box, so some version
+        * of the message box has to exist in the tty world to prevent a meltdown, even though most
+        * messages are handled in mac window.
+        */
+       mac_create_nhwindow(NHW_BASE);
+       tty_create_nhwindow(NHW_MESSAGE);
+       RetrievePosition(kMessageWindow, &r.top, &r.left);
+       RetrieveSize(kMessageWindow, r.top, r.left, &r.bottom, &r.right);
+       MoveWindow(theWindows[NHW_MESSAGE].its_window, r.left, r.top, false);
+       SizeWindow(theWindows[NHW_MESSAGE].its_window, r.right, r.bottom, true);
+       ConstrainWindowToScreen(theWindows[NHW_MESSAGE].its_window, kWindowStructureRgn,
+               kWindowConstrainMoveRegardlessOfFit, NULL, NULL);
+       return;
+}
+
+
+void
+mac_clear_nhwindow (winid win) {
+       long l;
+       Rect r;
+       NhWindow *aWin = &theWindows [win];
+       WindowPtr theWindow = aWin->its_window;
+
+       if (win < 0 || win >= NUM_MACWINDOWS || !theWindow) {
+               error ("clr_win: Invalid win %d.", win);
+               return;
+       }
+       if (theWindow == _mt_window) {
+               tty_clear_nhwindow(win);
+               return;
+       }
+       if (!aWin->drawn)
+               return;
+
+       SetPortWindowPort(theWindow);
+       GetWindowBounds(theWindow, kWindowContentRgn, &r);
+       OffsetRect(&r, -r.left, -r.top);
+       if (aWin->scrollBar)
+               r.right -= SBARWIDTH;
+
+       switch (GetWindowKind(theWindow) - WIN_BASE_KIND) {
+       case NHW_MESSAGE :
+               if (aWin->scrollPos == aWin->y_size - 1)        /* if no change since last clear */
+                       return;                                                                 /* don't bother with redraw */
+               r.bottom -= SBARHEIGHT;
+               for (l = 0; aWin->y_size > iflags.msg_history;) {
+                       const char cr = CHAR_CR;
+                       l = Munger(aWin->windowText, l, &cr, 1, nil, 0) + 1;
+                       --aWin->y_size;
+               }
+               if (l) {
+                       aWin->windowTextLen -= l;
+                       BlockMove(*aWin->windowText + l, *aWin->windowText, aWin->windowTextLen);
+               }
+               aWin->last_more_lin = aWin->y_size;
+               aWin->save_lin  = aWin->y_size;
+               aWin->scrollPos = aWin->y_size ? aWin->y_size - 1 : 0;
+               break;
+       case NHW_MENU:
+               if (aWin->menuInfo) {
+                       DisposeHandle((Handle)aWin->menuInfo);
+                       aWin->menuInfo = NULL;
+               }
+               if (aWin->menuSelected) {
+                       DisposeHandle((Handle)aWin->menuSelected);
+                       aWin->menuSelected = NULL;
+               }
+               aWin->menuChar = 'a';
+               aWin->miSelLen = 0;
+               aWin->miLen = 0;
+               aWin->miSize = 0;
+               /* Fall-Through */
+       default :
+               SetHandleSize (aWin->windowText, TEXT_BLOCK);
+               aWin->windowTextLen = 0L;
+               aWin->x_size = 0;
+               aWin->y_size = 0;
+               aWin->scrollPos = 0;
+               break;
+       }
+       if (aWin->scrollBar) {
+               SetControlMaximum (aWin->scrollBar, aWin->y_size);
+               SetControlValue(aWin->scrollBar, aWin->scrollPos);
+       }
+       aWin->y_curs = 0;
+       aWin->x_curs = 0;
+       aWin->drawn = FALSE;
+       InvalWindowRect(theWindow, &r);
+}
+
+
+static Boolean
+ClosingWindowChar(const int c) {
+       return c == CHAR_ESC || c == CHAR_BLANK || c == CHAR_LF || c == CHAR_CR ||
+                       c == 'q';
+}
+
+
+static Boolean
+in_topl_mode(void)
+{
+       Rect rect;
+
+
+       GetWindowBounds(theWindows[WIN_MESSAGE].its_window, kWindowContentRgn, &rect);
+       OffsetRect(&rect, -rect.left, -rect.top);
+       return (WIN_MESSAGE != WIN_ERR && top_line &&
+               (*top_line)->viewRect.left < rect.right);
+}
+
+
+#define BTN_IND 2
+#define BTN_W  40
+#define BTN_H  (SBARHEIGHT-3)
+
+static void
+topl_resp_rect(int resp_idx, Rect *r)
+{
+       Rect rect;
+
+
+       GetWindowBounds(theWindows[WIN_MESSAGE].its_window, kWindowContentRgn, &rect);
+       OffsetRect(&rect, -rect.left, -rect.top);
+       r->left   = (BTN_IND + BTN_W) * resp_idx + BTN_IND;
+       r->right  = r->left + BTN_W;
+       r->bottom = rect.bottom - 1;
+       r->top    = r->bottom - BTN_H;
+       return;
+}
+
+
+void
+enter_topl_mode(char *query) {
+       if (in_topl_mode())
+               return;
+
+       putstr(WIN_MESSAGE, ATR_BOLD, query);
+
+       topl_query_len = strlen(query);
+       (*top_line)->selStart = topl_query_len;
+       (*top_line)->selEnd = topl_query_len;
+       (*top_line)->viewRect.left = 0;
+       PtrToXHand(query, (*top_line)->hText, topl_query_len);
+       TECalText(top_line);
+
+       DimMenuBar();
+       mac_display_nhwindow(WIN_MESSAGE, FALSE);
+}
+
+
+void
+leave_topl_mode(char *answer) {
+       unsigned char *ap, *bp;
+
+       int ans_len = (*top_line)->teLength - topl_query_len;
+       NhWindow *aWin = theWindows + WIN_MESSAGE;
+
+       if (!in_topl_mode())
+               return;
+
+       /* Cap length of reply */
+       if (ans_len >= BUFSZ)
+               ans_len = BUFSZ-1;
+
+       /* remove unprintables from the answer */
+       for (ap = *(*top_line)->hText + topl_query_len, bp = answer; ans_len > 0; ans_len--, ap++) {
+               if (*ap >= ' ' && *ap < 128) {
+                       *bp++ = *ap;
+               }
+       }
+       *bp = 0;
+       
+       if (aWin->windowTextLen && (*aWin->windowText)[aWin->windowTextLen-1] == CHAR_CR) {
+               -- aWin->windowTextLen;
+               -- aWin->y_size;
+       }
+       putstr(WIN_MESSAGE, ATR_BOLD, answer);
+
+       (*top_line)->viewRect.left += 10000;
+       UndimMenuBar();
+}
+
+/*
+ * TESetSelect flushes out all the pending key strokes.  I hate it.
+ */
+static void
+topl_set_select(short selStart, short selEnd) {
+       TEDeactivate(top_line);
+       (*top_line)->selStart   = selStart;
+       (*top_line)->selEnd     = selEnd;
+       TEActivate(top_line);
+}
+
+
+static void
+topl_replace(char *new_ans) {
+       topl_set_select(topl_query_len, (*top_line)->teLength);
+       TEDelete(top_line);
+       TEInsert(new_ans, strlen(new_ans), top_line);
+}
+
+
+Boolean
+topl_key(unsigned char ch, Boolean ext) {
+       switch (ch) {
+               case CHAR_ESC:
+                       topl_replace("\x1b");
+               case CHAR_ENTER: case CHAR_CR: case CHAR_LF:
+                       return false;
+
+               case 0x1f & 'P':
+                       mac_doprev_message();
+                       return true;
+               case '\x1e'/* up arrow */:
+                       topl_replace ("");
+                       return true;
+               case CHAR_BS: case '\x1c'/* left arrow */:
+                       if ((*top_line)->selEnd <= topl_query_len)
+                               return true;
+                       else if (ext) {
+                               topl_replace ("");
+                               return true;
+                       }
+               default:
+                       TEKey(ch, top_line);
+                       if (ext) {
+                               int com_index = -1, oindex = 0;
+                               while(extcmdlist[oindex].ef_txt != (char *)0) {
+                                       if(!strncmpi(*(*top_line)->hText + topl_query_len,
+                                                                extcmdlist[oindex].ef_txt,
+                                                                (*top_line)->teLength - topl_query_len)) {
+                                               if(com_index == -1) /* No matches yet*/
+                                                       com_index = oindex;
+                                               else /* More than 1 match */ {
+                                                       com_index = -2;
+                                                       break;
+                                               }
+                                       }
+                                       oindex++;
+                               }
+                               if(com_index >= 0)
+                                       topl_replace((char *) extcmdlist[com_index].ef_txt);
+                       }
+                       return true;
+       }
+}
+
+
+static void
+topl_flash_resp(int resp_idx) {
+       unsigned long dont_care;
+       Rect frame;
+       SetPortWindowPort(theWindows[WIN_MESSAGE].its_window);
+       topl_resp_rect(resp_idx, &frame);
+       InsetRect(&frame, 1, 1);
+       InvertRect(&frame);
+       Delay(GetDblTime() / 2, &dont_care);
+       InvertRect(&frame);
+}
+
+
+static void
+topl_set_def(int new_def_idx) {
+       Rect frame;
+       SetPortWindowPort(theWindows[WIN_MESSAGE].its_window);
+       topl_resp_rect(topl_def_idx, &frame);
+       InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame);
+       topl_def_idx = new_def_idx;
+       topl_resp_rect(new_def_idx, &frame);
+       InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame);
+}
+
+
+void
+topl_set_resp(char *resp, char def) {
+       char *loc;
+       Rect frame;
+       int r_len, r_len1;
+
+       if (!resp) {
+               const char any_str[2] = {CHAR_ANY, '\0'};
+               resp = (char *) any_str;
+               def = CHAR_ANY;
+       }
+
+       SetPortWindowPort(theWindows[WIN_MESSAGE].its_window);
+       r_len1 = strlen(resp);
+       r_len  = strlen(topl_resp);
+       if (r_len < r_len1)
+               r_len = r_len1;
+       topl_resp_rect(0, &frame);
+       frame.right = (BTN_IND + BTN_W) * r_len;
+       InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame);
+
+       strcpy(topl_resp, resp);
+       loc = strchr (resp, def);
+       topl_def_idx = loc ? loc - resp : -1;
+}
+
+
+static char
+topl_resp_key(char ch) {
+       if (strlen(topl_resp) > 0) {
+               char *loc = strchr(topl_resp, ch);
+
+               if (!loc) {
+                       if (ch == '\x9'/* tab */) {
+                               topl_set_def(topl_def_idx<=0 ? strlen(topl_resp)-1 : topl_def_idx-1);
+                               ch = '\0';
+                       } else if (ch == CHAR_ESC) {
+                               loc = strchr(topl_resp, 'q');
+                               if (!loc) {
+                                       loc = strchr(topl_resp, 'n');
+                                       if (!loc && topl_def_idx >= 0)
+                                               loc = topl_resp + topl_def_idx;
+                               }
+                       } else if (ch == (0x1f & 'P')) {
+                               mac_doprev_message();
+                               ch = '\0';
+                       } else if (topl_def_idx >= 0) {
+                               if (ch == CHAR_ENTER || ch == CHAR_CR || ch == CHAR_LF ||
+                                        ch == CHAR_BLANK || topl_resp[topl_def_idx] == CHAR_ANY)
+                                       loc = topl_resp + topl_def_idx;
+
+                               else if (strchr(topl_resp, '#')) {
+                                       if (digit(ch)) {
+                                               topl_set_def(strchr(topl_resp, '#') - topl_resp);
+                                               TEKey(ch, top_line);
+                                               ch = '\0';
+
+                                       } else if (topl_resp[topl_def_idx] == '#') {
+                                               if (ch == '\x1e'/* up arrow */) {
+                                                       topl_set_select(topl_query_len, topl_query_len);
+                                                       ch = '\0';
+                                               } else if (ch == '\x1d'/* right arrow */ ||
+                                                          ch == '\x1f'/* down arrow */ ||
+                                                          ch == CHAR_BS || ch == '\x1c'/* left arrow */ &&
+                                                          (*top_line)->selEnd > topl_query_len) {
+                                                       TEKey(ch, top_line);
+                                                       ch = '\0';
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               if (loc) {
+                       topl_flash_resp(loc - topl_resp);
+                       if (*loc != CHAR_ANY)
+                               ch = *loc;
+                       TEKey(ch, top_line);
+               }
+       }
+
+       return ch;
+}
+
+
+static void
+adjust_window_pos(NhWindow *aWin, short width, short height)
+{
+       WindowRef theWindow = aWin->its_window;
+#if TARGET_API_MAC_CARBON
+       Rect r;
+
+
+       GetWindowBounds(theWindow, kWindowContentRgn, &r);
+       RetrieveWinPos(theWindow, &r.top, &r.left);
+       MoveWindow(theWindow, r.left, r.top, false);
+       SizeWindow(theWindow, width, height, true);
+       ConstrainWindowToScreen(theWindow, kWindowStructureRgn,
+               kWindowConstrainMoveRegardlessOfFit, NULL, NULL);
+#else
+       Rect scr_r = (*GetGrayRgn())->rgnBBox;
+       const Rect win_ind = {2, 2, 3, 3};
+       const short     min_w = theWindow->portRect.right - theWindow->portRect.left,
+                               max_w = scr_r.right - scr_r.left - win_ind.left - win_ind.right;
+       Point pos;
+       short max_h;
+
+       SetPortWindowPort(theWindow);
+       if (!RetrieveWinPos(theWindow, &pos.v, &pos.h)) {
+               pos.v = 0;      /* take window's existing position */
+               pos.h = 0;
+               LocalToGlobal(&pos);
+       }
+
+       max_h = scr_r.bottom - win_ind.bottom - pos.v;
+       if (height > max_h)             height = max_h;
+       if (height < MIN_HEIGHT)        height = MIN_HEIGHT;
+       if (width < min_w)              width = min_w;
+       if (width > max_w)              width = max_w;
+       SizeWindow(theWindow, width, height, true);
+
+       if (pos.v + height + win_ind.bottom > scr_r.bottom)
+               pos.v = scr_r.bottom - height - win_ind.bottom;
+       if (pos.h + width + win_ind.right > scr_r.right)
+               pos.h = scr_r.right      - width - win_ind.right;
+       MoveWindow(theWindow, pos.h, pos.v, false);
+       if (aWin->scrollBar)    
+               DrawScrollbar (aWin);
+#endif
+       return;
+}
+
+
+/*
+ * display/select/update the window.
+ * If f is true, this window should be "modal" - don't return
+ * until presumed seen.
+ */
+void
+mac_display_nhwindow (winid win, BOOLEAN_P f) {
+       NhWindow *aWin = &theWindows [win];
+       WindowPtr theWindow = aWin->its_window;
+
+       if (win < 0 || win >= NUM_MACWINDOWS || !theWindow) {
+               error ("disp_win: Invalid window %d.", win);
+               return;
+       }
+
+       if (theWindow == _mt_window) {
+               tty_display_nhwindow(win, f);
+               return;
+       }
+
+       if (f && inSelect == WIN_ERR && win == WIN_MESSAGE) {
+               topl_set_resp ((char *)0, 0);
+               if (aWin->windowTextLen > 0 &&
+                        (*aWin->windowText) [aWin->windowTextLen - 1] == CHAR_CR) {
+                       -- aWin->windowTextLen;
+                       -- aWin->y_size;
+               }
+               putstr (win, flags.standout ? ATR_INVERSE : ATR_NONE, " --More--");
+       }
+
+       if (!IsWindowVisible(theWindow)) {
+               if (win != WIN_MESSAGE)
+                       adjust_window_pos(aWin, aWin->x_size + SBARWIDTH+1, aWin->y_size *aWin->row_height);
+
+               SelectWindow (theWindow);
+               ShowWindow (theWindow);
+       }
+
+       if (f && inSelect == WIN_ERR) {
+               int ch;
+
+               DimMenuBar();
+               inSelect = win;
+               do {
+                       ch = mac_nhgetch ();
+               } while (!ClosingWindowChar (ch));
+               inSelect = WIN_ERR;
+               UndimMenuBar();
+
+               if (win == WIN_MESSAGE)
+                       topl_set_resp ("", '\0');
+               else
+                       HideWindow (theWindow);
+
+       }
+}
+
+
+void
+mac_destroy_nhwindow (winid win) {
+       WindowPtr theWindow;
+       NhWindow *aWin = &theWindows [win];
+       int kind;
+
+       if (win < 0 || win >= NUM_MACWINDOWS) {
+               if (iflags.window_inited) error ("dest_win: Invalid win %d.", win);
+               return;
+       }
+       theWindow = aWin->its_window;
+       if (!theWindow) {
+               error ("dest_win: Not allocated win %d.", win);
+               return;
+       }
+
+       /*
+        * Check special windows.  The base window should never go away.
+        * Other "standard" windows should not go away unless we've exitted nhwindows.
+        */
+       if (theWindow == _mt_window) {
+               return;
+       }
+       if (win == WIN_INVEN || win == WIN_MESSAGE) {
+               if (iflags.window_inited) {
+                       if (flags.tombstone && killer) {
+                               /* Prepare for the coming of the tombstone window. */
+                               win_fonts [NHW_TEXT] = kFontIDMonaco;
+                       }
+                       return;
+               }
+               if (win == WIN_MESSAGE)
+                       WIN_MESSAGE = WIN_ERR;
+       }
+
+       kind = GetWindowKind(theWindow) - WIN_BASE_KIND;
+
+       if ((!IsWindowVisible(theWindow) || (kind != NHW_MENU && kind != NHW_TEXT))) {
+               DisposeWindow (theWindow);
+               if (aWin->windowText) {
+                       DisposeHandle(aWin->windowText);
+               }
+               aWin->its_window = (WindowPtr) 0;
+               aWin->windowText = (Handle) 0;
+       }
+}
+
+
+void
+mac_number_pad (int pad) {
+       iflags.num_pad = pad;
+}
+
+
+void
+trans_num_keys(EventRecord *theEvent) {
+#if defined(__SC__) || defined(__MRC__)
+# pragma unused(theEvent)
+#endif
+/* KMH -- Removed this translation.
+ * Number pad keys should always emit digit characters.
+ * That's consistent with the default MacOS behavior.
+ * The number_pad option controls how digits are interpreted.
+ */
+#if 0
+       if (iflags.num_pad) {
+               Handle h = GetResource('Nump', theEvent->modifiers & shiftKey ? 129 : 128);
+               if (h) {
+                       short inkey = (theEvent->message & keyCodeMask), *ab = (short *)*h;
+                       int i = ab[0];
+                       for (; i; i--) {
+                               if (inkey == (ab[i] & keyCodeMask)) {
+                                       theEvent->message = ab[i];
+                                       break;
+                               }
+                       }
+               }
+       }
+#endif
+}
+
+
+/*
+ * Note; theWindow may very well be null here, since keyDown may call
+ * it when theres no window !!!
+ */
+static void
+GeneralKey (EventRecord *theEvent, WindowPtr theWindow) {
+#if defined(__SC__) || defined(__MRC__)
+# pragma unused(theWindow)
+#endif
+#if 0
+       trans_num_keys (theEvent);
+#endif
+       AddToKeyQueue (topl_resp_key (theEvent->message & 0xff), TRUE);
+}
+
+
+/*
+ * Routine used to select and de-select elements in a menu window, used by KeyMenu,
+ * ClickMenu, and UpdateMenu.  Takes the NhWindow and a line ref relative to the scrollbar.
+ */
+static void ToggleMenuSelect (NhWindow *aWin, int line) {
+       Rect r;
+
+
+       GetWindowBounds(aWin->its_window, kWindowContentRgn, &r);
+       OffsetRect(&r, -r.left, -r.top);
+       if (aWin->scrollBar)
+               r.right -= SBARWIDTH;                   
+       r.top = line * aWin->row_height;
+       r.bottom = r.top + aWin->row_height;
+
+       LMSetHiliteMode((UInt8) (LMGetHiliteMode() & 0x7F));
+       InvertRect(&r);
+}
+
+/*
+ * Check to see if given item is selected, return index if it is
+ */
+static int
+ListItemSelected (NhWindow *aWin, int item) {
+       int             i;
+
+       HLock ((char**)aWin->menuSelected);
+       /* Find item in selection list */
+       for (i = aWin->miSelLen - 1; i >= 0; i--) {
+               if ((*aWin->menuSelected) [i] == item)
+                       break;
+       }
+       HUnlock ((char**)aWin->menuSelected);
+       return i;
+}
+
+/*
+ * Add item to selection list if it's not selected already
+ * If it is selected already, remove it from the list.
+ */
+static void
+ToggleMenuListItemSelected (NhWindow *aWin, short item) {
+       int i = ListItemSelected (aWin, item);
+
+       HLock ((char**)aWin->menuSelected);
+       if (i < 0) {    /* not there, so add */
+               (*aWin->menuSelected) [aWin->miSelLen] = item;
+               aWin->miSelLen++;
+       }
+       else {                  /* there, so remove */
+               short *mi = &(*aWin->menuSelected)[i];
+               aWin->miSelLen --;
+               memcpy (mi, mi + 1, (aWin->miSelLen - i)*sizeof(short));
+       }
+       HUnlock ((char**)aWin->menuSelected);
+}
+
+
+/*
+ * Find menu item in list given a line number on the window
+ */
+static short
+ListCoordinateToItem (NhWindow *aWin, short Row) {
+       int                                     i, item = -1;
+       MacMHMenuItem *         mi;
+
+       HLock ((char**)aWin->menuInfo);
+       for (i = 0, mi = *aWin->menuInfo; i < aWin->miLen; i++, mi++) {
+               if (mi->line == Row + aWin->scrollPos) {
+                       item = i;
+                       break;
+               }
+       }
+       HUnlock ((char**)aWin->menuInfo);
+       return item;
+}
+
+
+static void
+macKeyMenu (EventRecord *theEvent, WindowPtr theWindow) {
+       NhWindow *aWin = GetNhWin(theWindow);
+       MacMHMenuItem *mi;
+       int l, ch = theEvent->message & 0xff;
+
+       if (aWin && aWin->menuInfo) {
+               HLock ((char**)aWin->menuInfo);
+               for (l = 0, mi = *aWin->menuInfo; l < aWin->miLen; l++, mi++) {
+                       if (mi->accelerator == ch) {
+                               ToggleMenuListItemSelected (aWin, l);
+                               if (mi->line >= aWin->scrollPos && mi->line <= aWin->y_size) {
+                                       SetPortWindowPort(theWindow);
+                                       ToggleMenuSelect (aWin, mi->line - aWin->scrollPos);
+                               }                               
+                               /* Dismiss window if only picking one item */
+                               if (aWin->how != PICK_ANY)
+                                       AddToKeyQueue(CHAR_CR, 1);
+                               break;
+                       }
+               }
+               HUnlock ((char**)aWin->menuInfo);
+               /* add key if didn't find it in menu and not filtered */
+               if (l == aWin->miLen && filter_scroll_key (ch, aWin))
+                       GeneralKey (theEvent, theWindow);
+       }
+}
+
+
+static void
+macClickMenu (EventRecord *theEvent, WindowRef theWindow) {
+       Point p;
+       NhWindow *aWin = GetNhWin(theWindow);
+       Rect wrect;
+
+
+       GetWindowBounds(theWindow, kWindowContentRgn, &wrect);
+       OffsetRect(&wrect, -wrect.left, -wrect.top);
+       if (aWin->scrollBar && IsControlVisible(aWin->scrollBar)) {
+               short code;
+               ControlHandle theBar;
+
+               p = theEvent->where;
+               GlobalToLocal (&p);
+               code = FindControl (p, theWindow, &theBar);
+               if (code) {
+                       DoScrollBar (p, code, theBar, aWin);
+                       return;
+               }
+       }
+       if (inSelect != WIN_ERR && aWin->how != PICK_NONE) {
+               short           currentRow = -1, previousRow = -1;
+               short           previousItem = -1, item = -1;
+               Boolean         majorSelectState, firstRow = TRUE;
+
+               do {
+#if !TARGET_API_MAC_CARBON
+                       SystemTask ();
+#endif
+                       GetMouse (&p);
+                       currentRow = p.v / aWin->row_height;
+                       if (p.h < wrect.left || p.h > wrect.right ||
+                               p.v < 0 || p.v > wrect.bottom || currentRow >= aWin->y_size) {
+                               continue;       /* not in window range */
+                       }
+
+                       item = ListCoordinateToItem (aWin, currentRow);
+
+                       if (item != previousItem) {
+                               /* Implement typical Mac multiple-selection behavior
+                                * (ie, not the UI implemented by the Finder)
+                                */
+                               Boolean itemIsSelected = (ListItemSelected (aWin,item) >= 0);
+
+                               if (firstRow) {
+                                       /* this is first valid row, so major state is opposite of what this row is */
+                                       majorSelectState = !itemIsSelected;
+                                       firstRow = FALSE;
+                               }
+
+                               if (aWin->how == PICK_ONE && previousItem != -1) {
+                                       /* if previous row was selected and we're only selecting one object,
+                                        * deselect previous row!
+                                        */
+                                       ToggleMenuListItemSelected (aWin, previousItem);
+                                       ToggleMenuSelect (aWin, previousRow);
+                                       previousItem = -1;
+                               }
+
+                               if (item == -1)
+                                       continue;       /* header line */
+                                       
+                               if (majorSelectState != itemIsSelected) {
+                                       ToggleMenuListItemSelected (aWin, item);
+                                       ToggleMenuSelect (aWin, currentRow);
+                               }
+
+                               previousRow             = currentRow;
+                               previousItem    = item;
+                       }
+               } while (StillDown ());
+
+               /* Dismiss window if only picking one item */
+               if (aWin->how == PICK_ONE)
+                       AddToKeyQueue(CHAR_CR, 1);
+       }
+}
+
+
+static void
+macKeyText (EventRecord *theEvent, WindowPtr theWindow) {
+       NhWindow *aWin = GetNhWin (theWindow);
+       char c = filter_scroll_key (theEvent->message & 0xff, aWin);
+       if (c) {
+               if (inSelect == WIN_ERR && ClosingWindowChar (c)) {
+                       HideWindow (theWindow);
+                       mac_destroy_nhwindow (aWin - theWindows);
+               } else {
+                       GeneralKey (theEvent, theWindow);
+               }
+       }
+}
+
+
+static void
+macClickText (EventRecord *theEvent, WindowPtr theWindow) {
+       NhWindow *aWin = GetNhWin (theWindow);
+
+       if (aWin->scrollBar && IsControlVisible(aWin->scrollBar)) {
+               short code;
+               Point p = theEvent->where;
+               ControlHandle theBar;
+
+               GlobalToLocal (&p);
+               code = FindControl (p, theWindow, &theBar);
+               if (code) {
+                       DoScrollBar (p, code, theBar, aWin);
+               }
+       }
+}
+
+
+static void
+macClickMessage (EventRecord *theEvent, WindowPtr theWindow) {
+       int r_idx = 0;
+       Point mouse = theEvent->where;
+
+       GlobalToLocal(&mouse);
+       while (topl_resp[r_idx]) {
+               Rect frame;
+               topl_resp_rect(r_idx, &frame);
+               InsetRect(&frame, 1, 1);
+               if (PtInRect(mouse, &frame)) {
+                       Boolean in_btn = true;
+
+                       InvertRect(&frame);
+                       while (WaitMouseUp()) {
+#if !TARGET_API_MAC_CARBON
+                               SystemTask();
+#endif
+                               GetMouse(&mouse);
+                               if (PtInRect(mouse, &frame) != in_btn) {
+                                       in_btn = !in_btn;
+                                       InvertRect(&frame);
+                               }
+                       }
+                       if (in_btn) {
+                               InvertRect(&frame);
+                               AddToKeyQueue (topl_resp [r_idx], 1);
+                       }
+                       return;
+
+               }
+               ++r_idx;
+       }
+
+       macClickText(theEvent, theWindow);
+}
+
+
+static void
+macClickTerm (EventRecord *theEvent, WindowPtr theWindow) {
+       NhWindow *nhw = GetNhWin(theWindow);
+       Point where = theEvent->where;
+
+       GlobalToLocal(&where);
+       where.h = where.h / nhw->char_width + 1;
+       where.v = where.v / nhw->row_height;
+       clicked_mod = (theEvent->modifiers & shiftKey) ? CLICK_2 : CLICK_1;
+
+       if (strchr(topl_resp, *click_to_cmd(where.h, where.v, clicked_mod)))
+               nhbell();
+       else {
+#if !TARGET_API_MAC_CARBON
+               if (cursor_locked)
+                       while (WaitMouseUp())
+                               SystemTask();
+#endif
+
+               gClickedToMove = TRUE;
+               clicked_pos = where;
+       }
+}
+
+static pascal void
+MoveScrollBar (ControlHandle theBar, short part) {
+       EventRecord fake;
+       Rect r;
+       RgnHandle rgn;
+       int now, amtToScroll;
+       WindowPtr theWin;
+       NhWindow *winToScroll;
+       
+       if (!part)
+               return;
+
+       theWin = GetControlOwner(theBar);
+       GetWindowBounds(theWin, kWindowContentRgn, &r);
+       OffsetRect(&r, -r.left, -r.top);
+       winToScroll = (NhWindow*)(GetWRefCon(theWin));
+       now = GetControlValue (theBar);
+
+       if (part == kControlPageUpPart || part == kControlPageDownPart) 
+               amtToScroll = (r.bottom - r.top) / winToScroll->row_height;
+       else
+               amtToScroll = 1;
+
+       if (part == kControlPageUpPart || part == kControlUpButtonPart) {
+               int bound = GetControlMinimum (theBar);
+               if (now - bound < amtToScroll)
+                       amtToScroll = now - bound;
+               amtToScroll = -amtToScroll;
+       } else {
+               int bound = GetControlMaximum (theBar);
+               if (bound - now < amtToScroll)
+                       amtToScroll = bound - now;
+       }
+       
+       if (!amtToScroll)
+               return;
+
+       SetControlValue (theBar, now + amtToScroll);
+       winToScroll->scrollPos = now + amtToScroll;
+       r.right -= SBARWIDTH;
+       if (winToScroll == theWindows + WIN_MESSAGE)
+               r.bottom -= SBARHEIGHT;
+       rgn = NewRgn ();
+       ScrollRect (&r, 0, -amtToScroll * winToScroll->row_height, rgn);
+       if (rgn) {
+               InvalWindowRgn(theWin, rgn);
+               BeginUpdate(theWin);
+       }
+       winUpdateFuncs [GetWindowKind(theWin) - WIN_BASE_KIND] (&fake, theWin);
+       if (rgn) {
+               EndUpdate(theWin);
+               DisposeRgn(rgn);
+       }
+}
+
+
+static void
+DoScrollBar (Point p, short code, ControlHandle theBar, NhWindow *aWin)
+{
+       ControlActionUPP func = NULL;
+       Rect rect;
+
+       if (code == kControlUpButtonPart || code == kControlPageUpPart ||
+               code == kControlDownButtonPart || code == kControlPageDownPart)
+               func = MoveScrollUPP;
+       (void) TrackControl(theBar, p, func);
+       if (!func) {
+               if (aWin->scrollPos != GetControlValue (theBar)) {
+                       aWin->scrollPos = GetControlValue (theBar);
+                       GetWindowBounds(aWin->its_window, kWindowContentRgn, &rect);
+                       OffsetRect(&rect, -rect.left, -rect.top);
+                       InvalWindowRect(aWin->its_window, &rect);
+               }
+       }
+}
+
+
+static int
+filter_scroll_key(const int ch, NhWindow *aWin) {
+       if (aWin->scrollBar && GetControlValue(aWin->scrollBar) < GetControlMaximum(aWin->scrollBar)) {
+               short part = 0;
+               if (ch == CHAR_BLANK) {
+                       part = kControlPageDownPart;
+               }
+               else if (ch == CHAR_CR || ch == CHAR_LF) {
+                       part = kControlDownButtonPart;
+               }
+               if (part) {
+                       SetPortWindowPort(aWin->its_window);
+                       MoveScrollBar(aWin->scrollBar, part);
+                       return 0;
+               }
+       }
+       return ch;
+}
+
+
+int
+mac_doprev_message(void) {
+       if (WIN_MESSAGE) {
+               NhWindow *winToScroll = &theWindows[WIN_MESSAGE];
+               mac_display_nhwindow(WIN_MESSAGE, FALSE);
+               SetPortWindowPort(winToScroll->its_window);
+               MoveScrollBar(winToScroll->scrollBar, kControlUpButtonPart);
+       }       
+       return 0;
+}
+
+
+static short
+macDoNull (EventRecord *theEvent, WindowPtr theWindow) {
+       return 0;
+}
+
+
+static void
+draw_growicon_vert_only(WindowPtr wind)
+{
+       GrafPtr org_port;
+       RgnHandle org_clip = NewRgn();
+       Rect r;
+
+       GetPort(&org_port);
+       SetPortWindowPort(wind);
+       GetClip(org_clip);
+       GetWindowBounds(wind, kWindowContentRgn, &r);
+       OffsetRect(&r, -r.left, -r.top);
+       r.left = r.right - SBARWIDTH;
+       ClipRect(&r);
+       DrawGrowIcon(wind);
+       SetClip(org_clip);
+       DisposeRgn(org_clip);
+       SetPort(org_port);
+}
+
+
+static short
+macUpdateMessage (EventRecord *theEvent, WindowPtr theWindow)
+{
+       RgnHandle org_clip = NewRgn(), clip = NewRgn();
+       Rect r;
+       NhWindow *aWin = GetNhWin(theWindow);
+       int l;
+
+       if (!theEvent)
+               return 0;
+
+       GetClip(org_clip);
+       GetWindowBounds(theWindow, kWindowContentRgn, &r);
+       OffsetRect(&r, -r.left, -r.top);
+
+       DrawControls(theWindow);
+       DrawGrowIcon(theWindow);
+
+       for (l = 0; topl_resp[l]; l++) {
+               StringPtr name;
+               unsigned char tmp[2];
+               FontInfo font;
+               Rect frame;
+               topl_resp_rect(l, &frame);
+               switch (topl_resp[l]) {
+                       case 'y':
+                               name = "\pyes";
+                               break;
+                       case 'n':
+                               name = "\pno";
+                               break;
+                       case 'N':
+                               name = "\pNone";
+                               break;
+                       case 'a':
+                               name = "\pall";
+                               break;
+                       case 'q':
+                               name = "\pquit";
+                               break;
+                       case CHAR_ANY:
+                               name = "\pany key";
+                               break;
+                       default:
+                               tmp[0] = 1;
+                               tmp[1] = topl_resp[l];
+                               name = tmp;
+                               break;
+               }
+               TextFont(kFontIDGeneva);
+               TextSize(9);
+               GetFontInfo(&font);
+               MoveTo ((frame.left + frame.right - StringWidth(name)) / 2,
+                       (frame.top + frame.bottom + font.ascent-font.descent-font.leading-1) / 2);
+               DrawString(name);
+               PenNormal();
+               if (l == topl_def_idx)
+                       PenSize(2, 2);
+               FrameRoundRect(&frame, 4, 4);
+       }
+
+       r.right -= SBARWIDTH;
+       r.bottom -= SBARHEIGHT;
+       /* Clip to the portrect - scrollbar/growicon *before* adjusting the rect
+               to be larger than the size of the window (!) */
+       RectRgn(clip, &r);
+       SectRgn(clip, org_clip, clip);
+       if (r.right < MIN_RIGHT)
+               r.right = MIN_RIGHT;
+       r.top -= aWin->scrollPos * aWin->row_height;
+
+#if 0
+       /* If you enable this band of code (and disable the next band), you will get
+          fewer flickers but a slower performance while drawing the dot line. */
+       {       RgnHandle dotl_rgn = NewRgn();
+               Rect dotl;
+               dotl.left       = r.left;
+               dotl.right      = r.right;
+               dotl.bottom = r.top + aWin->save_lin * aWin->row_height;
+               dotl.top        = dotl.bottom - 1;
+               FillRect(&dotl, &qd.gray);
+               RectRgn(dotl_rgn, &dotl);
+               DiffRgn(clip, dotl_rgn, clip);
+               DisposeRgn(dotl_rgn);
+               SetClip(clip);
+       }
+#endif
+
+       if (in_topl_mode()) {
+               RgnHandle topl_rgn = NewRgn();
+               Rect topl_r = r;
+               topl_r.top += (aWin->y_size - 1) * aWin->row_height;
+               l = (*top_line)->destRect.right - (*top_line)->destRect.left;
+               (*top_line)->viewRect = topl_r;
+               (*top_line)->destRect = topl_r;
+               if (l != topl_r.right - topl_r.left)
+                       TECalText(top_line);
+               TEUpdate(&topl_r, top_line);
+               RectRgn(topl_rgn, &topl_r);
+               DiffRgn(clip, topl_rgn, clip);
+               DisposeRgn(topl_rgn);
+               SetClip(clip);
+       }
+
+       DisposeRgn(clip);
+
+       TextFont (aWin->font_number);
+       TextSize (aWin->font_size);
+       HLock (aWin->windowText);
+       TETextBox (*aWin->windowText, aWin->windowTextLen, &r, teJustLeft);
+       HUnlock (aWin->windowText);
+
+#if !TARGET_API_MAC_CARBON
+       r.bottom = r.top + aWin->save_lin * aWin->row_height;
+       r.top    = r.bottom - 1;
+       FillRect(&r, (void *) &qd.gray);
+#endif
+
+       SetClip(org_clip);
+       DisposeRgn(org_clip);
+       return 0;
+}
+
+
+static short 
+macUpdateMenu (EventRecord *theEvent, WindowPtr theWindow) {
+       NhWindow *aWin = GetNhWin (theWindow);
+       int i, line;
+       MacMHMenuItem *mi;
+       
+       GeneralUpdate (theEvent, theWindow);
+       HLock ((char**)aWin->menuInfo);
+       HLock ((char**)aWin->menuSelected);
+       for (i = 0; i < aWin->miSelLen; i++) {
+               mi = &(*aWin->menuInfo) [(*aWin->menuSelected) [i]];
+               line = mi->line;
+               if (line > aWin->scrollPos && line <= aWin->y_size)
+                       ToggleMenuSelect (aWin, line - aWin->scrollPos);
+       }
+       HUnlock ((char**)aWin->menuInfo);
+       HUnlock ((char**)aWin->menuSelected);
+       return 0;
+}
+
+
+static short
+GeneralUpdate (EventRecord *theEvent, WindowPtr theWindow) {
+       Rect r, r2;
+       NhWindow *aWin = GetNhWin (theWindow);
+       RgnHandle h;
+       Boolean vis;
+
+
+       if (!theEvent)
+               return 0;
+
+       GetWindowBounds(theWindow, kWindowContentRgn, &r);
+       OffsetRect(&r, -r.left, -r.top);
+       r2 = r;
+       r2.left = r2.right - SBARWIDTH;
+       r2.right += 1;
+       r2.top -= 1;
+       vis = (r2.bottom > r2.top + 50);
+
+       draw_growicon_vert_only(theWindow);
+       DrawControls (theWindow);
+
+       h = (RgnHandle) 0;
+       if (vis && (h = NewRgn ())) {
+               RgnHandle tmp = NewRgn ();
+               if (!tmp) {
+                       DisposeRgn (h);
+                       h = (RgnHandle) 0;
+               } else {
+                       GetClip (h);
+                       RectRgn (tmp, &r2);
+                       DiffRgn (h, tmp, tmp);
+                       SetClip (tmp);
+                       DisposeRgn (tmp);
+               }
+       }
+       if (r.right < MIN_RIGHT)
+               r.right = MIN_RIGHT;
+       r.top -= aWin->scrollPos * aWin->row_height;
+       r.right -= SBARWIDTH;
+       HLock (aWin->windowText);
+       TETextBox (*aWin->windowText, aWin->windowTextLen, &r, teJustLeft);
+       HUnlock (aWin->windowText);
+       if (h) {
+               SetClip (h);
+               DisposeRgn (h);
+       }
+       return 0;
+}
+
+
+static void
+macCursorTerm (EventRecord *theEvent, WindowPtr theWindow, RgnHandle mouseRgn) {
+       char *dir_bas, *dir;
+       CursHandle ch;
+       GrafPtr gp;
+       NhWindow *nhw = GetNhWin (theWindow);
+       Rect r = {0, 0, 1, 1};
+
+       GetPort (&gp);
+       SetPortWindowPort(theWindow);
+
+       if (cursor_locked)
+               dir = (char *)0;
+       else {
+               Point where = theEvent->where;
+
+               GlobalToLocal (&where);
+               dir_bas = iflags.num_pad ? (char *) ndir : (char *) sdir;
+               dir = strchr (dir_bas, *click_to_cmd (where.h / nhw->char_width + 1 ,
+                                                       where.v / nhw->row_height, CLICK_1));
+       }
+       ch = GetCursor (dir ? dir - dir_bas + 513 : 512);
+       if (ch) {
+               HLock ((Handle) ch);
+               SetCursor (*ch);
+               HUnlock ((Handle) ch);
+
+       } else {
+               SetCursor(&qdarrow);
+       }
+       OffsetRect (&r, theEvent->where.h, theEvent->where.v);
+       RectRgn (mouseRgn, &r);
+       SetPort (gp);
+}
+
+
+static void
+GeneralCursor (EventRecord *theEvent, WindowPtr theWindow, RgnHandle mouseRgn) {
+#if defined(__SC__) || defined(__MRC__)
+# pragma unused(theWindow)
+#endif
+       Rect r = {-1, -1, 2, 2};
+
+       SetCursor(&qdarrow);
+       OffsetRect (&r, theEvent->where.h, theEvent->where.v);
+       RectRgn (mouseRgn, &r);
+}
+
+
+static void
+HandleKey (EventRecord *theEvent) {
+       WindowPtr theWindow = FrontWindow ();
+
+       if (theEvent->modifiers & cmdKey) {
+               if (theEvent->message & 0xff == '.') {
+                       /* Flush key queue */
+                       keyQueueCount = keyQueueWrite = keyQueueRead = 0;
+                       theEvent->message = '\033';
+                       goto dispatchKey;
+               } else {
+                       UndimMenuBar ();
+                       DoMenuEvt (MenuKey (theEvent->message & 0xff));
+               }
+       } else {
+
+dispatchKey :
+               if (theWindow) {
+                       int kind = GetWindowKind(theWindow) - WIN_BASE_KIND;
+                       winKeyFuncs [kind] (theEvent, theWindow);
+               } else {
+                       GeneralKey (theEvent, (WindowPtr) 0);
+               }
+       }
+}
+
+
+static void
+WindowGoAway (EventRecord *theEvent, WindowPtr theWindow) {
+       NhWindow *aWin = GetNhWin(theWindow);
+
+       if (!theEvent || TrackGoAway (theWindow, theEvent->where)) {
+               if (aWin - theWindows == BASE_WINDOW && !iflags.window_inited) {
+                       AddToKeyQueue ('\033', 1);
+               } else {
+                       HideWindow (theWindow);
+                       if (aWin - theWindows != inSelect)
+                               mac_destroy_nhwindow (aWin - theWindows);
+                       else                                                            /* if this IS the inSelect window put a close char */
+                               AddToKeyQueue (CHAR_CR, 1);             /* in queue to exit and maintain inSelect */
+               }
+       }
+}
+
+
+static void
+HandleClick (EventRecord *theEvent) {
+       int code;
+       unsigned long l;
+       WindowPtr theWindow;
+       NhWindow *aWin;
+       Rect r;
+       Boolean not_inSelect;
+
+       InsetRect(GetRegionBounds(GetGrayRgn(), &r), 4, 4);
+
+       code = FindWindow (theEvent->where, &theWindow);
+       aWin = GetNhWin (theWindow);
+       not_inSelect = (inSelect == WIN_ERR || aWin - theWindows == inSelect);
+       
+       switch (code) {
+       case inContent :
+               if (not_inSelect) {
+                       int kind = GetWindowKind(theWindow) - WIN_BASE_KIND;
+                       winCursorFuncs [kind] (theEvent, theWindow, gMouseRgn);
+                       SelectWindow (theWindow);
+                       SetPortWindowPort(theWindow);
+                       winClickFuncs [kind] (theEvent, theWindow);
+               } else {
+                       nhbell ();
+               }
+               break;
+
+       case inDrag :
+               if (not_inSelect) {
+                       SetCursor(&qdarrow);
+                       DragWindow (theWindow, theEvent->where, &r);
+                       SaveWindowPos(theWindow);
+               } else {
+                       nhbell ();
+               }
+               break;
+
+       case inGrow :
+               if (not_inSelect) {
+                       SetCursor(&qdarrow);
+                       SetRect (&r, 80, 2 * aWin->row_height + 1, r.right, r.bottom);
+                       if (aWin == theWindows + WIN_MESSAGE)
+                               r.top += SBARHEIGHT;
+                       l = GrowWindow (theWindow, theEvent->where, &r);
+                       SizeWindow (theWindow, l & 0xffff, l >> 16, FALSE);
+                       SaveWindowSize(theWindow);
+                       SetPortWindowPort(theWindow);
+                       GetWindowBounds(theWindow, kWindowContentRgn, &r);
+                       OffsetRect(&r, -r.left, -r.top);
+                       InvalWindowRect(theWindow, &r);
+                       if (aWin->scrollBar) {
+                               DrawScrollbar (aWin);
+                       }
+               } else {
+                       nhbell ();
+               }
+               break;
+
+       case inGoAway :
+               WindowGoAway(theEvent, theWindow);
+               break;
+
+       case inMenuBar :
+               DoMenuEvt (MenuSelect (theEvent->where));
+               break;
+
+#if !TARGET_API_MAC_CARBON
+       case inSysWindow :
+               SystemClick(theEvent, theWindow);
+#endif
+       default :
+               break;
+       }
+}
+
+
+static void
+HandleUpdate (EventRecord *theEvent) {
+       WindowPtr theWindow = (WindowPtr) theEvent->message;
+       NhWindow *aWin = GetNhWin (theWindow);
+       Rect r;
+
+
+       char existing_update_region = FALSE;
+       Rect rect;
+       
+       if (theWindow == _mt_window) {
+               existing_update_region = (get_invalid_region (theWindow, &rect) == noErr);
+       }
+       BeginUpdate (theWindow);
+       SetPortWindowPort(theWindow);
+       GetWindowBounds(theWindow, kWindowContentRgn, &r);
+       OffsetRect(&r, -r.left, -r.top);
+       EraseRect(&r);
+       winUpdateFuncs [GetWindowKind(theWindow) - WIN_BASE_KIND] 
+                               (theEvent, theWindow);
+
+       if (theWindow == _mt_window && existing_update_region) {
+               set_invalid_region (theWindow, &rect);
+       }
+       aWin->drawn = TRUE;
+       EndUpdate (theWindow);
+}
+
+
+static void
+DoOsEvt (EventRecord *theEvent) {
+       WindowRef win;
+       short code;
+
+       if ((theEvent->message & 0xff000000) == 0xfa000000) {
+               /* Mouse Moved */
+
+               code = FindWindow (theEvent->where, &win);
+               if (code != inContent) {
+                       Rect r = {-1, -1, 2, 2};
+
+                       SetCursor(&qdarrow);
+                       OffsetRect (&r, theEvent->where.h, theEvent->where.v);
+                       RectRgn (gMouseRgn, &r);
+               } else {
+                       int kind = GetWindowKind(win) - WIN_BASE_KIND;
+                       if (kind >= 0 && kind <= NHW_TEXT) {
+                               winCursorFuncs [kind] (theEvent, win, gMouseRgn);
+                       }
+               }
+       }
+}
+
+
+void
+HandleEvent (EventRecord *theEvent) {
+       switch (theEvent->what) {
+       case autoKey :
+       case keyDown :
+               HandleKey (theEvent);
+               break;
+       case updateEvt :
+               HandleUpdate (theEvent);
+               break;
+       case mouseDown :
+               HandleClick (theEvent);
+               break;
+#if !TARGET_API_MAC_CARBON
+       case diskEvt :
+               if ((theEvent->message & 0xffff0000) != 0) {
+                       Point p = {150, 150};
+                       (void) DIBadMount (p, theEvent->message);
+               }
+               break;
+#endif
+       case osEvt :
+               DoOsEvt (theEvent);
+               break;
+       case kHighLevelEvent:
+               AEProcessAppleEvent(theEvent);
+       default :
+               break;
+       }
+}
+
+
+void
+mac_get_nh_event(void) {
+       EventRecord anEvent;
+
+       /* KMH -- Don't proceed if the window system isn't set up */
+       if (!iflags.window_inited)
+               return;
+
+       (void) WaitNextEvent (everyEvent, &anEvent, -1, gMouseRgn);
+       HandleEvent(&anEvent);
+}
+
+
+int
+mac_nhgetch(void) {
+       int ch;
+       long doDawdle;
+       EventRecord anEvent;
+
+       /* We want to take care of keys in the buffer as fast as
+        * possible
+        */
+       if (keyQueueCount)
+               doDawdle = 0L;
+       else {
+               long total, contig;
+               static char warn = 0;
+
+               doDawdle = (in_topl_mode() ? GetCaretTime () : 120L);
+               /* Since we have time, check memory */
+               PurgeSpace (&total, &contig);
+               if (contig < 25000L || total < 50000L) {
+                       if (!warn) {
+                               pline ("Low Memory!");
+                               warn = 1;
+                       }
+               } else {
+                       warn = 0;
+               }
+       }
+
+       do {
+               (void) WaitNextEvent (everyEvent, &anEvent, doDawdle, gMouseRgn);
+               HandleEvent (&anEvent);
+               ch = GetFromKeyQueue ();
+       } while (!ch && !gClickedToMove);
+
+       if (!gClickedToMove)
+               ObscureCursor ();
+       else
+               gClickedToMove = 0;
+
+#ifdef THINK_C
+       if (ch == '\r') ch = '\n';
+#endif
+
+       return ch;
+}
+
+
+void
+mac_delay_output(void) {
+       long destTicks = TickCount () + 1;
+
+       while (TickCount () < destTicks) {
+               mac_get_nh_event ();
+       }
+}
+
+
+#ifdef CLIPPING
+static void
+mac_cliparound (int x, int y) {
+#if defined(__SC__) || defined(__MRC__)
+# pragma unused(x,y)
+#endif
+       /* TODO */
+}
+#endif
+
+void
+mac_exit_nhwindows (const char *s) {
+       clear_screen ();
+       tty_exit_nhwindows (s);
+       mac_destroy_nhwindow (WIN_MESSAGE);
+       mac_destroy_nhwindow (WIN_INVEN);
+}
+
+
+/*
+ * Don't forget to decrease in_putstr before returning...
+ */
+void
+mac_putstr (winid win, int attr, const char *str) {
+       long len, slen;
+       NhWindow *aWin = &theWindows [win];
+       static char in_putstr = 0;
+       short newWidth, maxWidth;
+       Rect r;
+       char *src, *sline, *dst, ch;
+
+       if (win < 0 || win >= NUM_MACWINDOWS || !aWin->its_window) {
+               error ("putstr: Invalid win %d (Max %d).", win, NUM_MACWINDOWS, attr);
+               return;
+       }
+
+       if (aWin->its_window == _mt_window) {
+               tty_putstr(win, attr, str);
+               return;
+       }
+
+       if (in_putstr > 3)
+               return;
+
+       in_putstr ++;
+       slen = strlen (str);
+
+       SetPortWindowPort(aWin->its_window);
+       GetWindowBounds(aWin->its_window, kWindowContentRgn, &r);
+       OffsetRect(&r, -r.left, -r.top);
+       if (win == WIN_MESSAGE) {
+               r.right  -= SBARWIDTH;
+               r.bottom -= SBARHEIGHT;
+               if (flags.page_wait && 
+                       aWin->last_more_lin <= aWin->y_size - (r.bottom - r.top) / aWin->row_height) {
+                       aWin->last_more_lin = aWin->y_size;
+                       mac_display_nhwindow(win, TRUE);
+               }
+       }
+
+       /*
+        * A "default" text window - uses TETextBox
+        * We just add the text, without attributes for now
+        */
+       len = GetHandleSize (aWin->windowText);
+       while (aWin->windowTextLen + slen + 1 > len) {
+               len = (len > 2048) ? (len + 2048) : (len * 2);
+               SetHandleSize (aWin->windowText, len);
+               if (MemError ()) {
+                       error ("putstr: SetHandleSize");
+                       aWin->windowTextLen = 0L;
+                       aWin->save_lin = 0;
+                       aWin->y_curs = 0;
+                       aWin->y_size = 0;
+               }
+       }
+       
+       len = aWin->windowTextLen;
+       dst = *(aWin->windowText) + len;
+       sline = src = (char *)str;
+       maxWidth = newWidth = 0;
+       for (ch = *src; ch; ch = *src) {
+               if (ch == CHAR_LF)
+                       ch = CHAR_CR;
+               *dst++ = ch;
+               if (ch == CHAR_CR) {
+                       aWin->y_curs ++;
+                       aWin->y_size ++;
+                       aWin->x_curs = 0;
+                       newWidth = TextWidth (sline, 0, src - sline);
+                       if (newWidth > maxWidth) {
+                               maxWidth = newWidth;
+                       }
+                       sline = src+1;  /* keep track of where new line begins */
+               }
+               else
+                       aWin->x_curs ++;
+               src++;
+       }
+
+       newWidth = TextWidth (sline, 0, src - sline);
+       if (newWidth > maxWidth) {
+               maxWidth = newWidth;
+       }
+
+       aWin->windowTextLen += slen;
+       
+       if (ch != CHAR_CR) {
+               (*(aWin->windowText)) [len + slen] = CHAR_CR;
+               aWin->windowTextLen ++;
+               aWin->y_curs ++;
+               aWin->y_size ++;
+               aWin->x_curs = 0;
+       }
+
+       if (win == WIN_MESSAGE) {
+               short min = aWin->y_size - (r.bottom - r.top) / aWin->row_height;
+               if (aWin->scrollPos < min) {
+                       aWin->scrollPos = min;
+                       SetControlMaximum (aWin->scrollBar, aWin->y_size);
+                       SetControlValue(aWin->scrollBar, min);
+               }
+               InvalWindowRect(aWin->its_window, &r);
+       }
+       else    /* Message has a fixed width, other windows base on content */
+               if (maxWidth > aWin->x_size)
+                       aWin->x_size = maxWidth;
+       in_putstr --;
+}
+
+
+void
+mac_curs (winid win, int x, int y) {
+       NhWindow *aWin = &theWindows [win];
+
+       if (aWin->its_window == _mt_window) {
+               tty_curs(win, x, y);
+               return;
+       }
+
+       SetPortWindowPort(aWin->its_window);
+       MoveTo (x * aWin->char_width, (y * aWin->row_height) + aWin->ascent_height);
+       aWin->x_curs = x;
+       aWin->y_curs = y;
+}
+
+
+int
+mac_nh_poskey (int *a, int *b, int *c) {
+       int ch = mac_nhgetch();
+       *a = clicked_pos.h;
+       *b = clicked_pos.v;
+       *c = clicked_mod;
+       return ch;
+}
+
+
+void
+mac_start_menu (winid win) {
+       HideWindow (theWindows [win].its_window);
+       mac_clear_nhwindow (win);
+}
+
+
+void
+mac_add_menu (winid win, int glyph, const anything *any, CHAR_P menuChar, CHAR_P groupAcc, int attr, const char *inStr, int preselected) {
+#if defined(__SC__) || defined(__MRC__)
+# pragma unused(glyph)
+#endif
+       NhWindow *aWin = &theWindows [win];
+       const char *str;
+       char locStr[4+BUFSZ];
+       MacMHMenuItem *item;
+
+       if (!inStr) return;
+
+       if (any->a_void != 0) {
+
+#define kMenuSizeBump 26
+               if (!aWin->miSize) {
+                       aWin->menuInfo = (MacMHMenuItem **)NewHandle(sizeof(MacMHMenuItem) * kMenuSizeBump);
+                       if (!aWin->menuInfo) {
+                               error("Can't alloc menu handle");
+                               return;
+                       }
+                       aWin->menuSelected = (short **)NewHandle(sizeof(short) * kMenuSizeBump);
+                       if (!aWin->menuSelected) {
+                               error("Can't alloc menu select handle");
+                               return;
+                       }
+                       aWin->miSize = kMenuSizeBump;
+               }
+
+               if (aWin->miLen >= aWin->miSize) {
+                       SetHandleSize((Handle)aWin->menuInfo, sizeof(MacMHMenuItem) * (aWin->miLen+kMenuSizeBump));
+                       if (MemError()) {
+                               error("Can't resize menu handle");
+                               return;
+                       }
+                       SetHandleSize((Handle)aWin->menuSelected, sizeof(short) * (aWin->miLen+kMenuSizeBump));
+                       if (MemError()) {
+                               error("Can't resize menu select handle");
+                               return;
+                       }
+                       aWin->miSize += kMenuSizeBump;
+               }
+
+               if (menuChar == 0) {    
+                       if (('a' <= aWin->menuChar && aWin->menuChar <= 'z') ||
+                               ('A' <= aWin->menuChar && aWin->menuChar <= 'Z')) {
+                               menuChar = aWin->menuChar++;
+                               if (menuChar == 'z')
+                                       aWin->menuChar = 'A';
+                       }
+               }
+               
+               Sprintf(locStr, "%c - %s", (menuChar ? menuChar : ' '), inStr);
+               str = locStr;
+               HLock ((char**)aWin->menuInfo);
+               HLock ((char**)aWin->menuSelected);
+               (*aWin->menuSelected)[aWin->miLen] = preselected;
+               item = &(*aWin->menuInfo)[aWin->miLen];
+               aWin->miLen++;
+               item->id = *any;
+               item->accelerator = menuChar;
+               item->groupAcc = groupAcc;
+               item->line = aWin->y_size;
+               HUnlock ((char**)aWin->menuInfo);
+               HUnlock ((char**)aWin->menuSelected);
+       } else
+               str = inStr;
+
+       putstr (win, attr, str);
+}
+
+
+/*
+ * End a menu in this window, window must a type NHW_MENU.
+ * str is a list of cancel characters (values that may be input)
+ * morestr is a prompt to display, rather than the default.
+ * str and morestr might be ignored by some ports.
+ */
+void
+mac_end_menu (winid win, const char *morestr) {
+       Str255 buf;
+       NhWindow *aWin = &theWindows [win];
+
+       buf [0] = 0;
+       if (morestr) 
+               C2P (morestr, buf);
+       SetWTitle (aWin->its_window, buf);
+}
+
+
+int
+mac_select_menu (winid win, int how, menu_item **selected_list) {
+       int c;
+       NhWindow *aWin = &theWindows [win];
+       WindowPtr theWin = aWin->its_window;
+
+       inSelect = win;
+
+       mac_display_nhwindow (win, FALSE);
+
+       aWin->how = (short) how;
+       for (;;) {
+               c = map_menu_cmd (mac_nhgetch());
+               if (c == CHAR_ESC) {
+                       /* deselect everything */
+                       aWin->miSelLen = 0;
+                       break;
+               } else if (ClosingWindowChar(c)) {
+                       break;
+               } else {
+                       nhbell();
+               }
+       }
+
+       HideWindow (theWin);
+
+       if (aWin->miSelLen) {
+               menu_item *mp;
+               MacMHMenuItem *mi;
+               *selected_list = mp = (menu_item *) alloc(aWin->miSelLen * sizeof(menu_item));
+               HLock ((char**)aWin->menuInfo);
+               HLock ((char**)aWin->menuSelected);
+               for (c = 0; c < aWin->miSelLen; c++) {
+                       mi = &(*aWin->menuInfo)[(*aWin->menuSelected) [c]];
+                       mp->item = mi->id;
+                       mp->count = -1L;
+                       mp++;
+               }
+               HUnlock ((char**)aWin->menuInfo);
+               HUnlock ((char**)aWin->menuSelected);
+       } else
+               *selected_list = 0;
+
+       inSelect = WIN_ERR;
+
+       return aWin->miSelLen;
+}
+
+#include "dlb.h"
+
+static void
+mac_display_file (name, complain)
+const char *name;      /* not ANSI prototype because of boolean parameter */
+boolean complain;
+{
+       Ptr buf;
+       int win;
+       dlb *fp = dlb_fopen(name, "r");
+       
+       if (fp) {
+               long l = dlb_fseek(fp, 0, SEEK_END);
+               (void) dlb_fseek(fp, 0, 0L);
+               buf = NewPtr(l+1);
+               if (buf) {
+                       l = dlb_fread(buf, 1, l, fp);
+                       if (l > 0) {
+                               buf[l] = '\0';
+                               win = create_nhwindow(NHW_TEXT);
+                               if (WIN_ERR == win) {
+                                       if (complain) error ("Cannot make window.");
+                               } else {
+                                       putstr(win, 0, buf);
+                                       display_nhwindow(win, FALSE);
+                               }
+                       }
+                       DisposePtr(buf);
+               }
+               dlb_fclose(fp);
+       } else if (complain)
+               error("Cannot open %s.", name);
+}
+
+
+void
+port_help () {
+       display_file (PORT_HELP, TRUE);
+}
+
+
+static void
+mac_unimplemented (void) {
+}
+
+
+static void
+mac_suspend_nhwindows (const char *foo) {
+#if defined(__SC__) || defined(__MRC__)
+# pragma unused(foo)
+#endif
+       /*      Can't really do that :-)                */
+}
+
+
+int
+try_key_queue (char *bufp) {
+       if (keyQueueCount) {
+               char ch;
+               for (ch = GetFromKeyQueue(); ; ch = GetFromKeyQueue()) {
+                       if (ch == CHAR_LF || ch == CHAR_CR)
+                               ch = 0;
+                       *bufp++ = ch;
+                       if (ch == 0)
+                               break;
+               }
+               return 1;
+       }
+       return 0;
+}
+
+/* Interface definition, for windows.c */
+struct window_procs mac_procs = {
+       "mac",
+       WC_COLOR | WC_HILITE_PET |
+       WC_FONT_MAP | WC_FONT_MENU | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_TEXT |
+       WC_FONTSIZ_MAP | WC_FONTSIZ_MENU | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_TEXT,
+       0L,
+       mac_init_nhwindows,
+       mac_unimplemented,      /* see macmenu.c:mac_askname() for player selection */
+       mac_askname,
+       mac_get_nh_event,
+       mac_exit_nhwindows,
+       mac_suspend_nhwindows,
+       mac_unimplemented,
+       mac_create_nhwindow,
+       mac_clear_nhwindow,
+       mac_display_nhwindow,
+       mac_destroy_nhwindow,
+       mac_curs,
+       mac_putstr,
+       mac_display_file,
+       mac_start_menu,
+       mac_add_menu,
+       mac_end_menu,
+       mac_select_menu,
+       genl_message_menu,
+       mac_unimplemented,
+       mac_get_nh_event,
+       mac_get_nh_event,
+#ifdef CLIPPING
+       mac_cliparound,
+#endif
+#ifdef POSITIONBAR
+       donull,
+#endif
+       tty_print_glyph,
+       tty_raw_print,
+       tty_raw_print_bold,
+       mac_nhgetch,
+       mac_nh_poskey,
+       tty_nhbell,
+       mac_doprev_message,
+       mac_yn_function,
+       mac_getlin,
+       mac_get_ext_cmd,
+       mac_number_pad,
+       mac_delay_output,
+#ifdef CHANGE_COLOR
+       tty_change_color,
+       tty_change_background,
+       set_tty_font_name,
+       tty_get_color_string,
+#endif
+/* other defs that really should go away (they're tty specific) */
+       0, //    mac_start_screen,
+       0, //    mac_end_screen,
+       genl_outrip,
+       genl_preference_update,
+};
+
+/*macwin.c*/
diff --git a/sys/mac/mgetline.c b/sys/mac/mgetline.c
new file mode 100644 (file)
index 0000000..35c3849
--- /dev/null
@@ -0,0 +1,74 @@
+/*     SCCS Id: @(#)getline.c  3.1     90/22/02 */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "mactty.h"
+#include "macwin.h"
+#include "macpopup.h"
+#include "func_tab.h"
+
+extern int NDECL(extcmd_via_menu);     /* cmd.c */
+
+typedef Boolean FDECL ((* key_func), (unsigned char));
+
+int
+get_line_from_key_queue (char * bufp) {
+       * bufp = 0;
+       if (try_key_queue (bufp)) {
+               while (* bufp) {
+                       if (* bufp == 10 || * bufp == 13) {
+                               * bufp = 0;
+                       }
+                       bufp ++;
+               }
+               return true;
+       }
+       return false;
+}
+
+
+static void
+topl_getlin(const char *query, char *bufp, Boolean ext) {
+       if (get_line_from_key_queue (bufp))
+               return;
+
+       enter_topl_mode((char *) query);
+       while (topl_key(nhgetch(), ext))
+               ;
+       leave_topl_mode(bufp);
+}
+
+
+/*
+ * Read a line closed with '\n' into the array char bufp[BUFSZ].
+ * (The '\n' is not stored. The string is closed with a '\0'.)
+ * Reading can be interrupted by an escape ('\033') - now the
+ * resulting string is "\033".
+ */
+void
+mac_getlin(const char *query, char *bufp) {
+       topl_getlin (query, bufp, false);
+}
+
+
+/* Read in an extended command - doing command line completion for
+ * when enough characters have been entered to make a unique command.
+ * This is just a modified getlin() followed by a lookup.   -jsb
+ */
+int
+mac_get_ext_cmd() {
+       char bufp[BUFSZ];
+       int i;
+
+       if (iflags.extmenu) return extcmd_via_menu();
+       topl_getlin("# ", bufp, true);
+       for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++)
+               if (!strcmp(bufp, extcmdlist[i].ef_txt)) break;
+       if (extcmdlist[i].ef_txt == (char *)0) i = -1;    /* not found */
+
+       return i;
+}
+
+
+/* macgetline.c */
diff --git a/sys/mac/mmodal.c b/sys/mac/mmodal.c
new file mode 100644 (file)
index 0000000..40959ba
--- /dev/null
@@ -0,0 +1,30 @@
+/*     SCCS Id: @(#)mmodal.c   3.1     93/01/24                  */
+/* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#if !TARGET_API_MAC_CARBON
+# include <Dialogs.h>
+# include <ControlDefinitions.h>
+#else
+# include <Carbon/Carbon.h>
+#endif
+
+#include "macpopup.h"
+
+/* Flash a dialog button when its accelerator key is pressed */
+void
+FlashButton(DialogRef wind, short item) {
+       short type;
+       Handle handle;
+       Rect rect;
+       unsigned long ticks;
+
+       /* Apple recommends 8 ticks */
+       GetDialogItem(wind, item, &type, &handle, &rect);
+       HiliteControl((ControlHandle)handle, kControlButtonPart);
+       Delay(8, &ticks);
+       HiliteControl((ControlHandle)handle, 0);
+       return;
+}
+
+
diff --git a/sys/mac/mrecover.c b/sys/mac/mrecover.c
new file mode 100644 (file)
index 0000000..8a76d93
--- /dev/null
@@ -0,0 +1,1419 @@
+/*     SCCS Id: @(#)mrecover.c 3.4             1996/07/24        */
+/*      Copyright (c) David Hairston, 1993.                       */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* Macintosh Recovery Application */
+
+/* based on code in util/recover.c.  the significant differences are:
+ * - GUI vs. CLI.  the vast majority of code here supports the GUI.
+ * - Mac toolbox equivalents are used in place of ANSI functions.
+ * - void restore_savefile(void) is event driven.
+ * - integral type substitutions here and there.
+ */
+
+/*
+ * Think C 5.0.4 project specs:
+ * signature: 'nhRc'
+ * SIZE (-1) info: flags: 0x5880, size: 65536L/65536L (64k/64k)
+ * libraries: MacTraps [yes], MacTraps2 (HFileStuff) [yes], ANSI [no]
+ * compatibility: system 6 and system 7
+ * misc: sizeof(int): 2, "\p": unsigned char, enum size varies,
+ *   prototypes required, type checking enforced, no optimizers,
+ *   FAR CODE [no], FAR DATA [no], SEPARATE STRS [no], single segment,
+ *   short macsbug symbols
+ */
+/*
+ * To do (maybe, just maybe):
+ * - Merge with the code in util/recover.c.
+ * - Document launch (e.g. GUI equivalent of 'recover basename').
+ * - Drag and drop.
+ * - Internal memory tweaks (stack and heap usage).
+ * - Use status file to allow resuming aborted recoveries.
+ * - Bundle 'LEVL' files with recover (easier document launch).
+ * - Prohibit recovering games "in progress".
+ * - Share AppleEvents with NetHack to auto-recover crashed games.
+ */
+
+
+#include "config.h"
+
+/**** Toolbox defines ****/
+
+/* MPW C headers (99.44% pure) */
+#include <Errors.h>
+#include <OSUtils.h>
+#include <Resources.h>
+#include <Files.h>
+#ifdef applec
+#include <SysEqu.h>
+#endif
+#include <Menus.h>
+#include <Devices.h>
+#include <Events.h>
+#include <DiskInit.h>
+#include <Notification.h>
+#include <Packages.h>
+#include <Script.h>
+#include <StandardFile.h>
+#include <ToolUtils.h>
+#include <Processes.h>
+#include <Fonts.h>
+#include <TextUtils.h>
+
+#ifdef THINK   /* glue for System 7 Icon Family call (needed by Think C 5.0.4) */
+pascal OSErr GetIconSuite(Handle *theIconSuite, short theResID, long selector)
+       = {0x303C, 0x0501, 0xABC9};
+#endif
+
+
+/**** Application defines ****/
+
+/* Memory */
+typedef struct memBytes        /* format of 'memB' resource, preloaded/locked */
+{
+       short   memReserved;
+       short   memCleanup;     /* 4   - memory monitor activity limit */
+       long    memPreempt;     /* 32k - start iff FreeMem() > */
+       long    memWarning;     /* 12k - warn if MaxMem() < */
+       long    memAbort;       /* 4k  - abort if MaxMem() < */
+       long    memIOBuf;       /* 16k - read/write buffer size */
+} memBytes, *memBytesPtr, **memBytesHandle;
+
+#define membID                 128                             /* 'memB' resource ID */
+
+
+/* Cursor */
+#define CURS_FRAME             4L                              /* 1/15 second - spin cursor */
+#define CURS_LATENT            60L                             /* pause before spin cursor */
+#define curs_Init              (-1)                    /* token for set arrow */
+#define curs_Total             8                               /* maybe 'acur' would be better */
+#define cursorOffset   128                             /* GetCursor(cursorOffset + i) */
+
+
+/* Menu */
+enum
+{
+       mbar_Init = -1,
+       mbarAppl,                                                       /* normal mode */
+       mbarRecover,                                            /* in recovery mode */
+       mbarDA                                                          /* DA in front mode */
+};
+enum
+{
+       menuApple,
+       menuFile,
+       menuEdit,
+       menu_Total,
+
+       muidApple = 128,
+       muidFile,
+       muidEdit
+};
+enum
+{
+       /* Apple menu */
+       mitmAbout = 1,
+       mitmHelp,
+       ____128_1,
+
+       /* File menu */
+       mitmOpen = 1,
+       ____129_1,
+       mitmClose_DA,
+       ____129_2,
+       mitmQuit
+
+       /* standard minimum required Edit menu */
+};
+
+
+/* Alerts */
+enum
+{
+       alrtNote,                                                       /* general messages */
+       alrtHelp,                                                       /* help message */
+       alrt_Total,
+
+       alertAppleMenu = 127,                           /* menuItem to alert ID offset */
+       alidNote,
+       alidHelp
+};
+
+#define aboutBufSize   80                              /* i.e. 2 lines of 320 pixels */
+
+
+/* Notification */
+#define nmBufSize              (32 + aboutBufSize + 32)
+typedef struct notifRec
+{
+       NMRec                           nmr;
+       struct notifRec *       nmNext;
+       short                           nmDispose;
+       unsigned char           nmBuf[nmBufSize];
+} notifRec, *notifPtr;
+
+#define nmPending              nmRefCon                        /* &in.Notify */
+#define iconNotifyID   128
+#define ics_1_and_4            0x00000300
+
+/* Dialogs */
+enum
+{
+       dlogProgress = 256
+};
+enum
+{
+       uitmThermo = 1
+};
+enum
+{
+       initItem,
+       invalItem,
+       drawItem
+};
+
+
+/* Miscellaneous */
+typedef struct modeFlags
+{
+       short   Front;                  /* fg/bg event handling */
+       short   Notify;                 /* level of pending NM notifications */
+       short   Dialog;                 /* a modeless dialog is open */
+       short   Recover;                /* restoration progress index */
+} modeFlags;
+
+/* convenient define to allow easier (for me) parsing of 'vers' resource */
+typedef struct versXRec
+{
+       NumVersion              numVers;
+       short                   placeCode;
+       unsigned char   versStr[];      /* (small string)(large string) */
+} versXRec, *versXPtr, **versXHandle;
+
+
+
+/**** Global variables ****/
+modeFlags              in = {1};                               /* in Front */
+EventRecord            wnEvt;
+SysEnvRec              sysEnv;
+unsigned char  aboutBuf[aboutBufSize]; /* vers 1 "Get Info" string */
+memBytesPtr            pBytes;                                 /* memory management */
+unsigned short memActivity;                    /* more memory management */
+MenuHandle             mHnd[menu_Total];
+CursPtr                        cPtr[curs_Total];               /* busy cursors */
+unsigned long  timeCursor;                             /* next cursor frame time */
+short                  oldCursor = curs_Init;  /* see adjustGUI() below */
+notifPtr               pNMQ;                                   /* notification queue pointer */
+notifRec               nmt;                                    /* notification template */
+DialogTHndl            thermoTHnd;
+DialogRecord   dlgThermo;                              /* progress thermometer */
+#define DLGTHM ((DialogPtr) &dlgThermo)
+#define WNDTHM ((WindowPtr) &dlgThermo)
+#define GRFTHM ((GrafPtr) &dlgThermo)
+
+Point                  sfGetWhere;                             /* top left corner of get file dialog */
+Ptr                            pIOBuf;                                 /* read/write buffer pointer */
+short                  vRefNum;                                /* SFGetFile working directory/volume refnum */
+long                   dirID;                                  /* directory i.d. */
+NMUPP                  nmCompletionUPP;                /* UPP for nmCompletion */
+FileFilterUPP  basenameFileFilterUPP;  /* UPP for basenameFileFilter */
+UserItemUPP            drawThermoUPP;                  /* UPP for progress callback */
+
+#define MAX_RECOVER_COUNT      256
+
+#define APP_NAME_RES_ID                (-16396)        /* macfile.h */
+#define PLAYER_NAME_RES_ID     1001            /* macfile.h */
+
+/* variables from util/recover.c */
+#define SAVESIZE       FILENAME
+unsigned char  savename[SAVESIZE];             /* originally a C string */
+unsigned char  lock[256];                              /* pascal string */
+
+int                    hpid;                                   /* NetHack (unix-style) process i.d. */
+short                  saveRefNum;                             /* save file descriptor */
+short                  gameRefNum;                             /* level 0 file descriptor */
+short                  levRefNum;                              /* level n file descriptor */
+
+
+/**** Prototypes ****/
+static void warmup(void);
+static Handle alignTemplate(ResType, short, short, short, Point *);
+pascal void nmCompletion(NMRec *);
+static void noteErrorMessage(unsigned char *, unsigned char *);
+static void note(short, short, unsigned char *);
+static void adjustGUI(void);
+static void adjustMemory(void);
+static void optionMemStats(void);
+static void RecoverMenuEvent(long);
+static void eventLoop(void);
+static void cooldown(void);
+
+pascal void drawThermo(WindowPtr, short);
+static void itemizeThermo(short);
+pascal Boolean basenameFileFilter(ParmBlkPtr);
+static void beginRecover(void);
+static void continueRecover(void);
+static void endRecover(void);
+static short saveRezStrings(void);
+
+/* analogous prototypes from util/recover.c */
+static void set_levelfile_name(long);
+static short open_levelfile(long);
+static short create_savefile(unsigned char *);
+static void copy_bytes(short, short);
+static void restore_savefile(void);
+
+/* auxiliary prototypes */
+static long read_levelfile(short, Ptr, long);
+static long write_savefile(short, Ptr, long);
+static void close_file(short *);
+static void unlink_file(unsigned char *);
+
+
+/**** Routines ****/
+
+main()
+{
+       /* heap adjust */
+       MaxApplZone();
+       MoreMasters();
+       MoreMasters();
+
+       /* manager initialization */
+       InitGraf(&qd.thePort);
+       InitFonts();
+       InitWindows();
+       InitMenus();
+       TEInit();
+       InitDialogs(0L);
+       InitCursor();
+       nmCompletionUPP = NewNMProc(nmCompletion);
+       basenameFileFilterUPP = NewFileFilterProc(basenameFileFilter);
+       drawThermoUPP = NewUserItemProc(drawThermo);
+
+       /* get system environment, notification requires 6.0 or better */
+       (void) SysEnvirons(curSysEnvVers, &sysEnv);
+       if (sysEnv.systemVersion < 0x0600)
+       {
+               ParamText("\pAbort: System 6.0 is required", "\p", "\p", "\p");
+               (void) Alert(alidNote, (ModalFilterUPP) 0L);
+               ExitToShell();
+       }
+
+       warmup();
+       eventLoop();
+
+       /* normally these routines are never reached from here */
+       cooldown();
+       ExitToShell();
+       return 0;
+}
+
+static void
+warmup()
+{
+       short           i;
+
+       /* pre-System 7 MultiFinder hack for smooth launch */
+       for (i = 0; i < 10; i++)
+       {
+               if (WaitNextEvent(osMask, &wnEvt, 2L, (RgnHandle) 0L))
+                       if (((wnEvt.message & osEvtMessageMask) >> 24) == suspendResumeMessage)
+                               in.Front = (wnEvt.message & resumeFlag);
+       }
+
+#if 0 // ???
+       /* clear out the Finder info */
+       {
+               short   message, count;
+
+               CountAppFiles(&message, &count);
+               while(count)
+                       ClrAppFiles(count--);
+       }
+#endif
+
+       /* fill out the notification template */
+       nmt.nmr.qType = nmType;
+       nmt.nmr.nmMark = 1;
+       nmt.nmr.nmSound = (Handle) -1L;         /* system beep */
+       nmt.nmr.nmStr = nmt.nmBuf;
+       nmt.nmr.nmResp = nmCompletionUPP;
+       nmt.nmr.nmPending = (long) &in.Notify;
+
+
+#if 1
+       {
+               /* get the app name */
+               ProcessInfoRec info;
+               ProcessSerialNumber psn;
+
+               info.processInfoLength = sizeof(info);
+               info.processName = nmt.nmBuf;
+               info.processAppSpec = NULL;
+               GetCurrentProcess(&psn);
+               GetProcessInformation(&psn, &info);
+       }
+#else
+       /* prepend app name (31 chars or less) to notification buffer */
+       {
+               short   apRefNum;
+               Handle  apParams;
+
+               GetAppParms(* (Str255 *) &nmt.nmBuf, &apRefNum, &apParams);
+       }
+#endif
+
+       /* add formatting (two line returns) */
+       nmt.nmBuf[++(nmt.nmBuf[0])] = '\r';
+       nmt.nmBuf[++(nmt.nmBuf[0])] = '\r';
+
+       /**** note() is usable now but not aesthetically complete ****/
+
+       /* get notification icon */
+       if (sysEnv.systemVersion < 0x0700)
+       {
+               if (! (nmt.nmr.nmIcon = GetResource('SICN', iconNotifyID)))
+                       note(nilHandleErr, 0, "\pNil SICN Handle");
+       }
+       else
+       {
+               if (GetIconSuite(&nmt.nmr.nmIcon, iconNotifyID, ics_1_and_4))
+                       note(nilHandleErr, 0, "\pBad Icon Family");
+       }
+
+       /* load and align various dialog/alert templates */
+       (void) alignTemplate('ALRT', alidNote, 0, 4, (Point *) 0L);
+       (void) alignTemplate('ALRT', alidHelp, 0, 4, (Point *) 0L);
+
+       thermoTHnd = (DialogTHndl) alignTemplate('DLOG', dlogProgress, 20, 8, (Point *) 0L);
+
+       (void) alignTemplate('DLOG', getDlgID, 0, 6, (Point *) &sfGetWhere);
+
+       /* get the "busy cursors" (preloaded/locked) */
+       for (i = 0; i < curs_Total; i++)
+       {
+               CursHandle              cHnd;
+
+               if (! (cHnd = GetCursor(i + cursorOffset)))
+                       note(nilHandleErr, 0, "\pNil CURS Handle");
+
+               cPtr[i] = *cHnd;
+       }
+
+       /* get the 'vers' 1 long (Get Info) string - About Recover... */
+       {
+               versXHandle             vHnd;
+
+               if (! (vHnd = (versXHandle) GetResource('vers', 1)))
+                       note(nilHandleErr, 0, "\pNil vers Handle");
+
+               i = (**vHnd).versStr[0] + 1;            /* offset to Get Info pascal string */
+
+               if ((aboutBuf[0] = (**vHnd).versStr[i]) > (aboutBufSize - 1))
+                       aboutBuf[0] = aboutBufSize - 1;
+
+               i++;
+
+               MoveHHi((Handle) vHnd);                 /* DEE - Fense ... */
+               HLock((Handle) vHnd);
+               BlockMove(&((**vHnd).versStr[i]), &(aboutBuf[1]), aboutBuf[0]);
+               ReleaseResource((Handle) vHnd);
+       }
+
+       /* form the menubar */
+       for (i = 0; i < menu_Total; i++)
+       {
+               if (! (mHnd[i] = GetMenu(i + muidApple)))
+                       note(nilHandleErr, 0, "\pNil MENU Handle");
+
+               /* expand the apple menu */
+               if (i == menuApple)
+                       AddResMenu(mHnd[menuApple], 'DRVR');
+
+               InsertMenu(mHnd[i], 0);
+       }
+
+       /* pre-emptive memory check */
+       {
+               memBytesHandle  hBytes;
+               Size                    grow;
+
+               if (! (hBytes = (memBytesHandle) GetResource('memB', membID)))
+                       note(nilHandleErr, 0, "\pNil Memory Handle");
+
+               pBytes = *hBytes;
+
+               if (MaxMem(&grow) < pBytes->memPreempt)
+                       note(memFullErr, 0, "\pMore Memory Required\rTry adding 16k");
+
+               memActivity = pBytes->memCleanup;               /* force initial cleanup */
+       }
+
+       /* get the I/O buffer */
+       if (! (pIOBuf = NewPtr(pBytes->memIOBuf)))
+               note(memFullErr, 0, "\pNil I/O Pointer");
+}
+
+/* align a window-related template to the main screen */
+static Handle
+alignTemplate(ResType rezType, short rezID, short vOff, short vDenom, Point *pPt)
+{
+       Handle  rtnHnd;
+       Rect    *pRct;
+
+       vOff += GetMBarHeight();
+
+       if (! (rtnHnd = GetResource(rezType, rezID)))
+               note(nilHandleErr, 0, "\pNil Template Handle");
+
+       pRct = (Rect *) *rtnHnd;
+
+       /* don't move memory while aligning rect */
+       pRct->right -= pRct->left;              /* width */
+       pRct->bottom -= pRct->top;              /* height */
+       pRct->left = (qd.screenBits.bounds.right - pRct->right) / 2;
+       pRct->top = (qd.screenBits.bounds.bottom - pRct->bottom - vOff) / vDenom;
+       pRct->top += vOff;
+       pRct->right += pRct->left;
+       pRct->bottom += pRct->top;
+
+       if (pPt)
+               *pPt = * (Point *) pRct;        /* top left corner */
+
+       return rtnHnd;
+}
+
+/* notification completion routine */
+pascal void
+nmCompletion(NMRec * pNMR)
+{
+       (void) NMRemove(pNMR);
+
+       (* (short *) (pNMR->nmPending))--;      /* decrement pending note level */
+       ((notifPtr) pNMR)->nmDispose = 1;       /* allow DisposPtr() */
+}
+
+/*
+ * handle errors inside of note().  the error message is appended to the
+ * given message but on a separate line and must fit within nmBufSize.
+ */
+static void
+noteErrorMessage(unsigned char *msg, unsigned char *errMsg)
+{
+       short   i = nmt.nmBuf[0] + 1;           /* insertion point */
+
+       BlockMove(&msg[1], &nmt.nmBuf[i], msg[0]);
+       nmt.nmBuf[i + msg[0]] = '\r';
+       nmt.nmBuf[0] += (msg[0] + 1);
+
+       note(memFullErr, 0, errMsg);
+}
+
+/*
+ * display messages using Notification Manager or an alert.
+ * no run-length checking is done.  the messages are created to fit
+ * in the allocated space (nmBufSize and aboutBufSize).
+ */
+static void
+note(short errorSignal, short alertID, unsigned char *msg)
+{
+       if (! errorSignal)
+       {
+               Size    grow;
+
+               if (MaxMem(&grow) < pBytes->memAbort)
+                       noteErrorMessage(msg, "\pOut of Memory");
+       }
+
+       if (errorSignal || !in.Front)
+       {
+               notifPtr        pNMR;
+               short           i = nmt.nmBuf[0] + 1;   /* insertion point */
+
+               if (errorSignal)                /* use notification template */
+               {
+                       pNMR = &nmt;
+
+                       /* we're going to abort so add in this prefix */
+                       BlockMove("Abort: ", &nmt.nmBuf[i], 7);
+                       i += 7;
+                       nmt.nmBuf[0] += 7;
+               }
+               else                                    /* allocate a notification record */
+               {
+                       if (! (pNMR = (notifPtr) NewPtr(sizeof(notifRec))))
+                               noteErrorMessage(msg, "\pNil New Pointer");
+
+                       /* initialize it */
+                       *pNMR = nmt;
+                       pNMR->nmr.nmStr = (StringPtr) &(pNMR->nmBuf);
+
+                       /* update the notification queue */
+                       if (!pNMQ)
+                               pNMQ = pNMR;
+                       else
+                       {
+                               notifPtr        pNMX;
+
+                               /* find the end of the queue */
+                               for (pNMX = pNMQ; pNMX->nmNext; pNMX = pNMX->nmNext)
+                                       ;
+
+                               pNMX->nmNext = pNMR;
+                       }
+               }
+
+               /* concatenate the message */
+               BlockMove(&msg[1], &((pNMR->nmBuf)[i]), msg[0]);
+               (pNMR->nmBuf)[0] += msg[0];
+
+               in.Notify++;                    /* increase note pending level */
+
+               NMInstall((NMRec *) pNMR);
+
+               if (errorSignal)
+                       cooldown();
+
+               return;
+       }
+
+       /* in front and no error so use an alert */
+       ParamText(msg, "\p", "\p", "\p");
+       (void) Alert(alertID, (ModalFilterUPP) 0L);
+       ResetAlrtStage();
+
+       memActivity++;
+}
+
+static void
+adjustGUI()
+{
+       static short    oldMenubar = mbar_Init; /* force initial update */
+       short                   newMenubar;
+       WindowPeek              frontWindow;
+
+       /* oldCursor is external so it can be reset in endRecover() */
+       static short    newCursor = curs_Init;
+       unsigned long   timeNow;
+       short                   useArrow;
+
+       /* adjust menubar 1st */
+       newMenubar = in.Recover ? mbarRecover : mbarAppl;
+
+       /* desk accessories take precedence */
+       if (frontWindow = (WindowPeek) FrontWindow())
+               if (frontWindow->windowKind < 0)
+                       newMenubar = mbarDA;
+
+       if (newMenubar != oldMenubar)
+       {
+               /* adjust menus */
+               switch (oldMenubar = newMenubar)
+               {
+               case mbarAppl:
+                       EnableItem(mHnd[menuFile], mitmOpen);
+                       SetItemMark(mHnd[menuFile], mitmOpen, noMark);
+                       DisableItem(mHnd[menuFile], mitmClose_DA);
+                       DisableItem(mHnd[menuEdit], 0);
+                       break;
+
+               case mbarRecover:
+                       DisableItem(mHnd[menuFile], mitmOpen);
+                       SetItemMark(mHnd[menuFile], mitmOpen, checkMark);
+                       DisableItem(mHnd[menuFile], mitmClose_DA);
+                       DisableItem(mHnd[menuEdit], 0);
+                       break;
+
+               case mbarDA:
+                       DisableItem(mHnd[menuFile], mitmOpen);
+                       EnableItem(mHnd[menuFile], mitmClose_DA);
+                       EnableItem(mHnd[menuEdit], 0);
+                       break;
+               }
+
+               DrawMenuBar();
+       }
+
+       /* now adjust the cursor */
+       if (useArrow = (!in.Recover || (newMenubar == mbarDA)))
+               newCursor = curs_Init;
+       else if ((timeNow = TickCount()) >= timeCursor)         /* spin cursor */
+       {
+               timeCursor = timeNow + CURS_FRAME;
+               if (++newCursor >= curs_Total)
+                       newCursor = 0;
+       }
+
+       if (newCursor != oldCursor)
+       {
+               oldCursor = newCursor;
+
+               SetCursor(useArrow ? &qd.arrow : cPtr[newCursor]);
+       }
+}
+
+static void
+adjustMemory()
+{
+       Size            grow;
+
+       memActivity = 0;
+
+       if (MaxMem(&grow) < pBytes->memWarning)
+               note(noErr, alidNote, "\pWarning: Memory is running low");
+
+       (void) ResrvMem((Size) FreeMem());              /* move all handles high */
+}
+
+/* show memory stats: FreeMem, MaxBlock, PurgeSpace, and StackSpace */
+static void
+optionMemStats()
+{
+       unsigned char   *pFormat = "\pFree:#k  Max:#k  Purge:#k  Stack:#k";
+       char                    *pSub = "#";            /* not a pascal string */
+       unsigned char   nBuf[16];
+       long                    nStat, contig;
+       Handle                  strHnd;
+       long                    nOffset;
+       short                   i;
+
+       if (wnEvt.modifiers & shiftKey)
+               adjustMemory();
+
+       if (! (strHnd = NewHandle((Size) 128)))
+       {
+               note(noErr, alidNote, "\pOops: Memory stats unavailable!");
+               return;
+       }
+       
+       SetString((StringHandle) strHnd, pFormat);
+       nOffset = 1L;
+
+       for (i = 1; i <= 4; i++)
+       {
+               /* get the replacement number stat */
+               switch (i)
+               {
+               case 1: nStat = FreeMem();                              break;
+               case 2: nStat = MaxBlock();                             break;
+               case 3: PurgeSpace(&nStat, &contig);    break;
+               case 4: nStat = StackSpace();                   break;
+               }
+
+               NumToString((nStat >> 10), * (Str255 *) &nBuf);
+
+               **strHnd += nBuf[0] - 1;
+               nOffset = Munger(strHnd, nOffset, (Ptr) pSub, 1L, (Ptr) &nBuf[1], nBuf[0]);
+       }
+
+       MoveHHi(strHnd);
+       HLock(strHnd);
+       note(noErr, alidNote, (unsigned char *) *strHnd);
+       DisposHandle(strHnd);
+}
+
+static void
+RecoverMenuEvent(long menuEntry)
+{
+       short menuID = HiWord(menuEntry);
+       short menuItem = LoWord(menuEntry);
+
+       switch (menuID)
+       {
+       case muidApple:
+               switch (menuItem)
+               {
+               case mitmAbout:
+                       if (wnEvt.modifiers & optionKey)
+                               optionMemStats();
+                       /* fall thru */
+               case mitmHelp:
+                       note(noErr, (alertAppleMenu + menuItem), aboutBuf);
+                       break;
+
+               default:        /* DA's or apple menu items */
+                       {
+                               unsigned char   daName[32];
+
+                               GetItem(mHnd[menuApple], menuItem, * (Str255 *) &daName);
+                               (void) OpenDeskAcc(daName);
+
+                               memActivity++;
+                       }
+                       break;
+               }
+               break;
+
+       case muidFile:
+               switch (menuItem)
+               {
+               case mitmOpen:
+                       beginRecover();
+                       break;
+
+               case mitmClose_DA:
+                       {
+                               WindowPeek      frontWindow;
+                               short           refNum;
+
+                               if (frontWindow = (WindowPeek) FrontWindow())
+                                       if ((refNum = frontWindow->windowKind) < 0)
+                                               CloseDeskAcc(refNum);
+
+                               memActivity++;
+                       }
+                       break;
+
+               case mitmQuit:
+                       cooldown();
+                       break;
+               }
+               break;
+
+       case muidEdit:
+               (void) SystemEdit(menuItem - 1);
+               break;
+       }
+
+       HiliteMenu(0);
+}
+
+static void
+eventLoop()
+{
+       short   wneMask = (in.Front ? everyEvent : (osMask + updateMask));
+       long    wneSleep = (in.Front ? 0L : 3L);
+
+       while (1)
+       {
+               if (in.Front)
+                       adjustGUI();
+
+               if (memActivity >= pBytes->memCleanup)
+                       adjustMemory();
+
+               (void) WaitNextEvent(wneMask, &wnEvt, wneSleep, (RgnHandle) 0L);
+
+               if (in.Dialog)
+                       (void) IsDialogEvent(&wnEvt);
+
+               switch (wnEvt.what)
+               {
+               case osEvt:
+                       if (((wnEvt.message & osEvtMessageMask) >> 24) == suspendResumeMessage)
+                       {
+                               in.Front = (wnEvt.message & resumeFlag);
+                               wneMask = (in.Front ? everyEvent : (osMask + updateMask));
+                               wneSleep = (in.Front ? 0L : 3L);
+                       }
+                       break;
+
+               case nullEvent:
+                       /* adjust the FIFO notification queue */
+                       if (pNMQ && pNMQ->nmDispose)
+                       {
+                               notifPtr pNMX = pNMQ->nmNext;
+
+                               DisposPtr((Ptr) pNMQ);
+                               pNMQ = pNMX;
+
+                               memActivity++;
+                       }
+
+                       if (in.Recover)
+                               continueRecover();
+                       break;
+
+               case mouseDown:
+                       {
+                               WindowPtr       whichWindow;
+                               
+                               switch(FindWindow( wnEvt . where , &whichWindow))
+                               {
+                               case inMenuBar:
+                                       RecoverMenuEvent(MenuSelect( wnEvt . where ));
+                                       break;
+
+                               case inSysWindow:
+                                       SystemClick(&wnEvt, whichWindow);
+                                       break;
+
+                               case inDrag:
+                                       {
+                                               Rect    boundsRect = qd.screenBits.bounds;
+                                               Point   offsetPt;
+
+                                               InsetRect(&boundsRect, 4, 4);
+                                               boundsRect.top += GetMBarHeight();
+
+                                               DragWindow(whichWindow, * ((Point *) &wnEvt.where), &boundsRect);
+
+                                               boundsRect = whichWindow->portRect;
+                                               offsetPt = * (Point *) &(whichWindow->portBits.bounds);
+                                               OffsetRect(&boundsRect, -offsetPt.h, -offsetPt.v);
+
+                                               * (Rect *) *thermoTHnd = boundsRect;
+                                       }
+                                       break;
+                               }
+                       }
+                       break;
+
+               case keyDown:
+                       {
+                               char    key = (wnEvt.message & charCodeMask);
+
+                               if (wnEvt.modifiers & cmdKey)
+                               {
+                                       if (key == '.')
+                                       {
+                                               if (in.Recover)
+                                               {
+                                                       endRecover();
+                                                       note(noErr, alidNote, "\pSorry: Recovery aborted");
+                                               }
+                                       }
+                                       else
+                                               RecoverMenuEvent(MenuKey(key));
+                               }
+                       }
+                       break;
+
+               /* without windows these events belong to our thermometer */
+               case updateEvt:
+               case activateEvt:
+               {
+                       DialogPtr       dPtr;
+                       short           itemHit;
+
+                       (void) DialogSelect(&wnEvt, &dPtr, &itemHit);
+               }
+
+               case diskEvt:
+                       if (HiWord(wnEvt.message))
+                       {
+                               Point   pt = {60, 60};
+
+                               (void) DIBadMount(pt, wnEvt.message);
+                               DIUnload();
+
+                               memActivity++;
+                       }
+                       break;
+               }                       /* switch (wnEvt.what) */
+       }                               /* while (1) */
+}
+
+static void
+cooldown()
+{
+       if (in.Recover)
+               endRecover();
+
+       /* wait for pending notifications to complete */
+       while (in.Notify)
+               (void) WaitNextEvent(0, &wnEvt, 3L, (RgnHandle) 0L);
+
+       ExitToShell();
+}
+
+/* draw the progress thermometer and frame.  1 level <=> 1 horiz. pixel */
+pascal void
+drawThermo(WindowPtr wPtr, short inum)
+{
+       itemizeThermo(drawItem);
+}
+
+/* manage progress thermometer dialog */
+static void
+itemizeThermo(short itemMode)
+{
+       short   iTyp, iTmp;
+       Handle  iHnd;
+       Rect    iRct;
+
+       GetDItem(DLGTHM, uitmThermo, &iTyp, &iHnd, &iRct);
+
+       switch(itemMode)
+       {
+       case initItem:
+               SetDItem(DLGTHM, uitmThermo, iTyp, (Handle) drawThermoUPP, &iRct);
+               break;
+
+       case invalItem:
+               {
+                       GrafPtr oldPort;
+
+                       GetPort(&oldPort);
+                       SetPort(GRFTHM);
+
+                       InsetRect(&iRct, 1, 1);
+                       InvalRect(&iRct);
+
+                       SetPort(oldPort);
+               }
+               break;
+
+       case drawItem:
+                       FrameRect(&iRct);
+                       InsetRect(&iRct, 1, 1);
+
+                       iTmp = iRct.right;
+                       iRct.right = iRct.left + in.Recover;
+                       PaintRect(&iRct);
+
+                       iRct.left = iRct.right;
+                       iRct.right = iTmp;
+                       EraseRect(&iRct);
+               break;
+       }
+}
+
+/* show only <pid-plname>.0 files in get file dialog */
+pascal Boolean
+basenameFileFilter(ParmBlkPtr pPB)
+{
+       unsigned char   *pC;
+
+       if (! (pC = (unsigned char *) pPB->fileParam.ioNamePtr))
+               return true;
+
+       if ((*pC < 4) || (*pC > 28))                                            /* save/ 1name .0 */
+               return true;
+
+       if ((pC[*pC - 1] == '.') && (pC[*pC] == '0'))           /* bingo! */
+               return false;
+
+       return true;
+}
+
+static void
+beginRecover()
+{
+       SFTypeList              levlType = {'LEVL'};
+       SFReply                 sfGetReply;
+
+       SFGetFile(sfGetWhere, "\p", basenameFileFilterUPP, 1, levlType,
+                               (DlgHookUPP) 0L, &sfGetReply);
+
+       memActivity++;
+
+       if (! sfGetReply.good)
+               return;
+
+       /* get volume (working directory) refnum, basename, and directory i.d. */
+       vRefNum = sfGetReply.vRefNum;
+       BlockMove(sfGetReply.fName, lock, sfGetReply.fName[0] + 1);
+       {
+               static CInfoPBRec       catInfo;
+
+               catInfo.hFileInfo.ioNamePtr = (StringPtr) sfGetReply.fName;
+               catInfo.hFileInfo.ioVRefNum = sfGetReply.vRefNum;
+               catInfo.hFileInfo.ioDirID = 0L;
+
+               if (PBGetCatInfoSync(&catInfo))
+               {
+                       note(noErr, alidNote, "\pSorry: Bad File Info");
+                       return;
+               }
+
+               dirID = catInfo.hFileInfo.ioFlParID;
+       }
+
+       /* open the progress thermometer dialog */
+       (void) GetNewDialog(dlogProgress, (Ptr) &dlgThermo, (WindowPtr) -1L);
+       if (ResError() || MemError())
+               note(noErr, alidNote, "\pOops: Progress thermometer unavailable");
+       else
+       {
+               in.Dialog = 1;
+               memActivity++;
+
+               itemizeThermo(initItem);
+
+               ShowWindow(WNDTHM);
+       }
+
+       timeCursor = TickCount() + CURS_LATENT;
+       saveRefNum = gameRefNum = levRefNum = -1;
+       in.Recover = 1;
+}
+
+static void
+continueRecover()
+{
+       restore_savefile();
+
+       /* update the thermometer */
+       if (in.Dialog && ! (in.Recover % 4))
+               itemizeThermo(invalItem);
+
+       if (in.Recover <= MAX_RECOVER_COUNT)
+               return;
+
+       endRecover();
+
+       if (saveRezStrings())
+               return;
+
+       note(noErr, alidNote, "\pOK: Recovery succeeded");
+}
+
+/* no messages from here (since we might be quitting) */
+static void
+endRecover()
+{
+       in.Recover = 0;
+
+       oldCursor = curs_Init;
+       SetCursor(&qd.arrow);
+
+       /* clean up abandoned files */
+       if (gameRefNum >= 0)
+               (void) FSClose(gameRefNum);
+
+       if (levRefNum >= 0)
+               (void) FSClose(levRefNum);
+
+       if (saveRefNum >= 0)
+       {
+               (void) FSClose(saveRefNum);
+               (void) FlushVol((StringPtr) 0L, vRefNum);
+               /* its corrupted so trash it ... */
+               (void) HDelete(vRefNum, dirID, savename);
+       }
+
+       saveRefNum = gameRefNum = levRefNum = -1;
+
+       /* close the progress thermometer dialog */
+       in.Dialog = 0;
+       CloseDialog(DLGTHM);
+       DisposHandle(dlgThermo.items);
+       memActivity++;
+}
+
+/* add friendly, non-essential resource strings to save file */
+static short
+saveRezStrings()
+{
+       short                   sRefNum;
+       StringHandle    strHnd;
+       short                   i, rezID;
+       unsigned char   *plName;
+
+       HCreateResFile(vRefNum, dirID, savename);
+
+       sRefNum = HOpenResFile(vRefNum, dirID, savename, fsRdWrPerm);
+       if (sRefNum <= 0)
+       {
+               note(noErr, alidNote, "\pOK: Minor resource map error");
+               return 1;
+       }
+
+       /* savename and hpid get mutilated here... */
+       plName = savename + 5;                          /* save/ */
+       *savename -= 5;
+       do
+       {
+               plName++;
+               (*savename)--;
+               hpid /= 10;
+       }
+       while (hpid);
+       *plName = *savename;
+
+       for (i = 1; i <= 2; i++)
+       {
+               switch (i)
+               {
+               case 1:
+                       rezID = PLAYER_NAME_RES_ID;
+                       strHnd = NewString(* (Str255 *) plName);
+                       break;
+
+               case 2:
+                       rezID = APP_NAME_RES_ID;
+                       strHnd = NewString(* (Str255 *) "\pNetHack");
+                       break;
+               }
+
+               if (! strHnd)
+               {
+                       note(noErr, alidNote, "\pOK: Minor \'STR \' resource error");
+                       CloseResFile(sRefNum);
+                       return 1;
+               }
+
+               /* should check for errors... */
+               AddResource((Handle) strHnd, 'STR ', rezID, * (Str255 *) "\p");
+       }
+
+       memActivity++;
+
+       /* should check for errors... */
+       CloseResFile(sRefNum);
+       return 0;
+}
+
+static void
+set_levelfile_name(long lev)
+{
+       unsigned char   *tf;
+
+       /* find the dot.  this is guaranteed to happen. */
+       for (tf = (lock + *lock); *tf != '.'; tf--, lock[0]--)
+               ;
+
+       /* append the level number string (pascal) */
+       if (tf > lock)
+       {
+               NumToString(lev, * (Str255 *) tf);
+               lock[0] += *tf;
+               *tf = '.';
+       }
+       else    /* huh??? */
+       {
+               endRecover();
+               note(noErr, alidNote, "\pSorry: File Name Error");
+       }
+}
+
+static short
+open_levelfile(long lev)
+{
+       OSErr   openErr;
+       short   fRefNum;
+
+       set_levelfile_name(lev);
+       if (! in.Recover)
+               return (-1);
+
+       if ((openErr = HOpen(vRefNum, dirID, lock, fsRdWrPerm, &fRefNum))
+                       && (openErr != fnfErr))
+       {
+               endRecover();
+               note(noErr, alidNote, "\pSorry: File Open Error");
+               return (-1);
+       }
+
+       return (openErr ? -1 : fRefNum);
+}
+
+static short
+create_savefile(unsigned char *savename)
+{
+       short   fRefNum;
+
+       /* translate savename to a pascal string (in place) */
+       {
+               unsigned char   *pC;
+               short                   nameLen;
+
+               for (pC = savename; *pC; pC++);
+
+               nameLen = pC - savename;
+
+               for ( ; pC > savename; pC--)
+                       *pC = *(pC - 1);
+
+               *savename = nameLen;
+       }
+
+       if (HCreate(vRefNum, dirID, savename, MAC_CREATOR, SAVE_TYPE)
+               || HOpen(vRefNum, dirID, savename, fsRdWrPerm, &fRefNum))
+       {
+               endRecover();
+               note(noErr, alidNote, "\pSorry: File Create Error");
+               return (-1);
+       }
+
+       return fRefNum;
+}
+
+static void
+copy_bytes(short inRefNum, short outRefNum)
+{
+       char    *buf = (char *) pIOBuf;
+       long    bufSiz = pBytes->memIOBuf;
+
+       long    nfrom, nto;
+
+       do
+       {
+               nfrom = read_levelfile(inRefNum, buf, bufSiz);
+               if (! in.Recover)
+                       return;
+
+               nto = write_savefile(outRefNum, buf, nfrom);
+               if (! in.Recover)
+                       return;
+
+               if (nto != nfrom)
+               {
+                       endRecover();
+                       note(noErr, alidNote, "\pSorry: File Copy Error");
+                       return;
+               }
+       }
+       while (nfrom == bufSiz);
+}
+
+static void
+restore_savefile()
+{
+       static int      savelev;
+       long            saveTemp, lev;
+       xchar           levc;
+       struct version_info version_data;
+
+       /* level 0 file contains:
+        *      pid of creating process (ignored here)
+        *      level number for current level of save file
+        *      name of save file nethack would have created
+        *      and game state
+        */
+
+       lev = in.Recover - 1;
+       if (lev == 0L)
+       {
+               gameRefNum = open_levelfile(0L);
+
+               if (in.Recover)
+                       (void) read_levelfile(gameRefNum, (Ptr) &hpid, sizeof(hpid));
+
+               if (in.Recover)
+                       saveTemp = read_levelfile(gameRefNum, (Ptr) &savelev, sizeof(savelev));
+
+               if (in.Recover && (saveTemp != sizeof(savelev)))
+               {
+                       endRecover();
+                       note(noErr, alidNote, "\pSorry: \"checkpoint\" was not enabled");
+                       return;
+               }
+
+               if (in.Recover)
+                       (void) read_levelfile(gameRefNum, (Ptr) savename, sizeof(savename));
+               if (in.Recover)
+                       (void) read_levelfile(gameRefNum,
+                                   (Ptr) &version_data, sizeof version_data);
+
+               /* save file should contain:
+                *      current level (including pets)
+                *      (non-level-based) game state
+                *      other levels
+                */
+               if (in.Recover)
+                       saveRefNum = create_savefile(savename);
+
+               if (in.Recover)
+                       levRefNum = open_levelfile(savelev);
+
+               if (in.Recover)
+                       (void) write_savefile(saveRefNum,
+                                   (Ptr) &version_data, sizeof version_data);
+               if (in.Recover)
+                       copy_bytes(levRefNum, saveRefNum);
+
+               if (in.Recover)
+                       close_file(&levRefNum);
+
+               if (in.Recover)
+                       unlink_file(lock);
+
+               if (in.Recover)
+                       copy_bytes(gameRefNum, saveRefNum);
+
+               if (in.Recover)
+                       close_file(&gameRefNum);
+
+               if (in.Recover)
+                       set_levelfile_name(0L);
+
+               if (in.Recover)
+                       unlink_file(lock);
+       }
+       else if (lev != savelev)
+       {
+               levRefNum = open_levelfile(lev);
+               if (levRefNum >= 0)
+               {
+                       /* any or all of these may not exist */
+                       levc = (xchar) lev;
+
+                       (void) write_savefile(saveRefNum, (Ptr) &levc, sizeof(levc));
+
+                       if (in.Recover)
+                               copy_bytes(levRefNum, saveRefNum);
+
+                       if (in.Recover)
+                               close_file(&levRefNum);
+
+                       if (in.Recover)
+                               unlink_file(lock);
+               }
+       }
+
+       if (in.Recover == MAX_RECOVER_COUNT)
+               close_file(&saveRefNum);
+
+       if (in.Recover)
+               in.Recover++;
+}
+
+static long
+read_levelfile(short rdRefNum, Ptr bufPtr, long count)
+{
+       OSErr   rdErr;
+       long    rdCount = count;
+
+       if ((rdErr = FSRead(rdRefNum, &rdCount, bufPtr)) && (rdErr != eofErr))
+       {
+               endRecover();
+               note(noErr, alidNote, "\pSorry: File Read Error");
+               return (-1L);
+       }
+
+       return rdCount;
+}
+
+static long
+write_savefile(short wrRefNum, Ptr bufPtr, long count)
+{
+       long    wrCount = count;
+
+       if (FSWrite(wrRefNum, &wrCount, bufPtr))
+       {
+               endRecover();
+               note(noErr, alidNote, "\pSorry: File Write Error");
+               return (-1L);
+       }
+
+       return wrCount;
+}
+
+static void
+close_file(short *pFRefNum)
+{
+       if (FSClose(*pFRefNum) || FlushVol((StringPtr) 0L, vRefNum))
+       {
+               endRecover();
+               note(noErr, alidNote, "\pSorry: File Close Error");
+               return;
+       }
+
+       *pFRefNum = -1;
+}
+
+static void
+unlink_file(unsigned char *filename)
+{
+       if (HDelete(vRefNum, dirID, filename))
+       {
+               endRecover();
+               note(noErr, alidNote, "\pSorry: File Delete Error");
+               return;
+       }
+}
+
diff --git a/sys/mac/mrecover.hqx b/sys/mac/mrecover.hqx
new file mode 100644 (file)
index 0000000..2cf115d
--- /dev/null
@@ -0,0 +1,69 @@
+(This file must be converted with BinHex 4.0)
+
+:$@ebC@0[GQ9b,R*cFQ-!FR0bBe*6483!!!!!!!!!!!aI55J!!!!!!3!!!!TJ!!!
+*B!!!!Im!!'1M#Q&$E'YTEQPd,Q1!!J!!!&4&@&4,38K-!3!!-"*YFQ9MEhCPFLj
+`FQpU,R*cFQ0b!J!!!(*cFQ058d9%!!"bFh*M8P0&4!%!!0!!J!!!!!!!!!!!!!!
+!!!!!!!!!!+lTZ(B!!!!!!!!-F`!!!!!!!!!!%!!!!'1M#Q&$E'YXEfp`,Q1!!J!
+!!&4&@&4,38K-!3!!B!"X!!!!!'1V!!!!!&Le!!"F!!!!!!!!!!!!!!#Mk`QeT3H
+i4`!!!!"hD3!!!!!!!!!!!!!!!!!!!!!p93!A!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!L!!%!!!!!!$J!EJ"-!1B%!Np,!!!!!!!+!!S!+J&+L!*H-!!!!!`
+!+!!S!))"I!#!!!3!!!!-!#J!+!$#!A`!J3!%!!!!5!##!!!!!!!!!!$rrrrl"%9
+NDA3%9@jNE`"D!!!",3!!!!!$3h9d!&J!!!4$Eh"j!%-!!!93BA0dC3"@!!!&3fa
+PBA)!!!!!!!!!!$J!J!!!!!!!!!!!rrrrp`%8%%&LEh9d)&*PBfpfCA)Z,Li!!!!
+!"dKPE(!Z,Li!!!!!!5d!!!!!!!!!!%3!!!2!!X!$`!'!!m!--!J3%#J35"H)%!J
+)%!``!m!!!!2!"q!(i!IJ!m!2m"ri(rJrr$rm2r`rr"ri(rJ2m!2!!!N!"`!!!%!
+'J!l!CZ!hB"r!6mcq%[mUkG6XL#N3-V!&@!5-!`3!!"r!Ir"rq2rmrrlrr[rrrrr
+rrrrrIrprrcrr(ri2rJ2i!!!!('jS8Q-!!!!"4P*&4J!!!!!!J%P$6L-!!!!!!)!
+!!!!(39"36!!!!!!!!"364'&fD@3J5'&TFR0dEfiJ-bmj-`!!!3!!!!!!!"m!!!"
+r`!!JIm!!1$q`!"3rF!!512J!#6Gi!!6rH!!#IlJ!!6ri!''Iq!$rc$$Jrq3"-1l
+b!T!!kIN&82IPLU$[ip9!6Z%LJ!(Jb3!2m))!$r%N!!I#LJ!!"9N!!!UNJ!!93N!
+!%S&J!"N!d!!1!&!!!!!`!!!!!!!!!!!2r`!!2rr!!(rrm!"rrrJ!rrrm!2rrrJ$
+rrrm!rrrrJ2rrrm$rrrrJrrrrm2rrrrMrrrrmrrrrr2rrrrlrrrrqrrrrrhrrrrp
+rrrrr2rrrrcrrrrmIrrrr$rrrr`Irrrm$rrrr!Irrr`$rrrm!Irrr!$rrrJ!Irri
+!"rrm!!(rm!!!!J!!!!!!!!!!!!!!!!!!!!!!!!!!!!$rrrm!!!!!!!!!!!!!!!!
+2%4%4r`!!!!!!!!!!m!!!$a%4%4m!!!!!!!!!!2r`!!$a%4%Ir`!!!!!!!!!2h`!
+!m4%4m4m!!!!!!!!!$ph`!2%Ira%4m!!!!!!!!!$ph`$am4(a%I!!!!!!!!!!$ph
+r%4%4m4(`!!!!!!!!!!$pha%4%4m4m!!!!!!!!!!!$pha%4%4%I!!!!!!!!r`!!r
+pha(rra(`!!!!!!$a(rra(phr!!$r!!$rm!!!m4%4%4(ph`!!!!!242m!!2%I%4m
+4(ph`!!!!p242!!$a(ara%Irph`!!$dp26`!!m4(a%4(`$p$`!26dp2!!!2%I%4%
+4m!$`$`p26dm!!!!2ra%I%I!!$phd426`!!!!!!rrm4(`!!$r4242!!!!!!!2%4%
+4(`!!p%4%m!!!!!!!$r%4%4m!$d6d6`!!!!!!!!!2rrr`!26d42h`!!!!!!!!!!!
+!!!p26drph`!!!!!!!!!!!!$dp26`$ph`!!!!!!!!!!!26dp2!!$ph`!!!!!!!!!
+!$d6dm!!!$p$`!!!!!!!!!!rd6`!!!!$`h`!!!!!!!!!!rr!!!!!!$pm!!!!!!!!
+!!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)!
+!!!rrm!!!!!!!m4mI!!!!$G!2(a(`!!!!h3m4mI!!!!!0ha%I!!!!$`$Grrm!r`$
+arrh3!!p%m2%4(pd!p26`m4mI$Gp26`$rram!p%6`!!!!m!p%6`!!!!!!p26p!!!
+!!!p26`h3!!!!$d6`!0d!!!!!r`!!$3!!!!!!!!!!!!!!!#!'J!l!CZ!hB"r!6mc
+q%[mUkG6XL#N3-V!&@!5-!`3!!!!!!2B!!3!!!!!!H!"Z!)`!jJ3#6dX!!!!!!!S
+!#J"U!8U)e6%T)&0PE'9MG#!L6h"PELiZ,L)JCR*[E5"dD'8J4QPXC5"YC@je,Jd
+b+5"6C@aPBh3JG'KP)'GKE@8JG'mJFQ9MEhCPFL"QFQpY)(4SC5"ND@&XEfFZ$6-
+T)&GKDA3JCQpb)(4SC5"bCA0eE(3J+%p,)'pb)&0[FR*j+5i0$84[)'j[G#"KG(4
+PEA"d)(4[)(*PBfpfCA)JB5"RB@eP)(4SBA3JDA-J)QPZ)("bEfGbCA0c)L!SD5j
+P,L"cG'PXE#"bG@jZD@jR)'PZ)%jPG%KKBfXT)3!!!!"#!)%!!!!!!!!!!2rrrqX
+%4QPXC3G2F'9Z,LiZ!%m!!!%Y!!!!!!K$E'pcC5"%33"A!!!",3!!!!!%8A9TG!"
+4!!!!!!!!&!!!!!3!!)!!!!!`!!!!%!!!!%!!!!!!3J43FQPf4PG54!G$E'9KER9
+`4&G54!G3FQ9PEA"d4%a14`GABA*ZD@jR4%a14`9"BQpbG%4-6NF'58mJ3R9Q4%a
+14`!!!%3!!!2!!d!$`!'!!B!#3!4J"#!%B!@J"#!%B!*!!B!!!!2!"q!(i!IJ!m!
+$`!IJ$r!2m!r`$r!2m!r`"q!$`!'!!!N!"`!!!%3!!!2!!X!$`!'!!B!#3!2!!N!
+(`!C!!m!#3!2!!B!!!!2!"q!(i!IJ!m!$`!IJ"q!(i!rJ$q!(i!IJ"q!$`!'!!!N
+!"`!!!"d!+!!S!%!"3!!%!!!!!!!!!!!"!!K3FQpRFQ9cF`!!!"!!!!!!!!!!"`!
+,!"%"$B!!!!!!4!!!!m!$3!2!!B!"J!*!"Q!%)!CJ"D!')!4J!d!"J!!!!m!(i!I
+J"q!$`!2!"q!2m!r`$r!2m!r`$r!(i!2!!B!!#3!(!!!!4!!!!m!$3!2!!B!"J!0
+!"L!&B!8J"@!&)!9J!N!"J!!!!m!(i!IJ"q!$`!2!"q!2m!r`$r!2m!r`$r!(i!2
+!!B!!#3!(!!!!4!!!!m!#`!2!!B!"J!*!!m!#3!2J!Q!$`!*!!m!"J!!!!m!(i!I
+J"q!$`!2!"q!(i!IJ"r!(m!IJ"q!(i!2!!B!!#3!(!!!!4!!!!m!#`!2!!B!$J!q
+3!!`3'CJCQ"QB'CJ*N!!-%!2!!!!$`!IJ"q!(i!2!$r!Iq"ri2r`rr$rm2r`Iq"r
+i$r!$`!!*!!F!!!"%!!!$`!0!!m!"J!'!!m!&)!DJ"+!'S!5J"U!$3!'!!!!$`!I
+J"q!(i!2!!m!(i!r`$r!2m!r`$r!2m!IJ!m!"J!!*!!F!!!!U!c#!!!!!!c-Z-ap
+5C@0[GQ9b)$-Z-`eNCACdC@&Y3'jPG'KKBfXZEh*R!!!!&J-`J!!!!!-c,M-,8Q9
+MEhCPFL!c,M-!!!%!!!!+B!!!#@!!!!(r"-)(q#qq!!!!(!(k!!p"6&*8!!%!JN4
+*9%`!!J#D689193!#!,j$99*6!!F!iNP$6L-!!!&#D@0c)`!!!8j#6N4-!!!"@Qj
+S8Q-!!!&Q4P*&4J!!!A*fCA*c!!%"IQPME$3!!!'@D@0c0!!!!D*65801!!!"VQe
+PE8)!!!'k9%e36!!!!FC%6%p(!!!"dJ#!rrm!!!!Q!!!!!!#"rrm!!!!f!!!!!!#
+!rrmJ!!!!!!!!!!#"rrmJ!!90!!!!!!%!rrmJ!!HF!!!!!!##rrm!!!"'!!!!!!#
+!rrm!!!#5!!!!!!#"rrm!!!C(!!!!!!#!rrm8!!$1!!!!!!#"rrm8!!EV!!!!!!#
+#rrm8!!Fc!!!!!!#(rrm8!!H`!!!!!!#&rrm8!!Ii!!!!!!#'rrm8!!K!!!!!!!#
+%rrm8!!L)!!!!!!#$rrm8!!M3!!!!!!#!rrm!!!'G!!!!!!#!rrm!!!%@!!!!!!#
+!rrm!!!&D!!!!!!!!rrm!!!'&!!!!!!#!rrm!!!&k!!!!!!!"rrm!!!NB!!!!!!!
+#rrm!!!P'!!!!!!#!rrm!!!+K!!!!!!#!rrm!!!5P!!!!!!#!rrm!!!8T!!!!!!#
+!rrm8!!D0!!!!!!#!!!!!!!DP!!!!!!%!rrm!!!Gl!!!!!!4YC@e#8i3:
diff --git a/sys/mac/mttymain.c b/sys/mac/mttymain.c
new file mode 100644 (file)
index 0000000..16b4512
--- /dev/null
@@ -0,0 +1,586 @@
+/*     SCCS Id: @(#)mttymain.c 3.1     93/02/26                        */
+/* Copyright (c) Jon W{tte, 1993                                       */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+#include "hack.h"
+#include "macwin.h"
+#include "mttypriv.h"
+#include "mactty.h"
+#include "wintty.h"
+
+#if !TARGET_API_MAC_CARBON
+#include <Palettes.h>
+#endif
+
+#define MT_WINDOW 135
+#define MT_WIDTH 80
+#define MT_HEIGHT 24
+
+
+/*
+ * Names:
+ *
+ * Statics are prefixed _
+ * Mac-tty becomes mt_
+ */
+
+static long _mt_attrs [5] [2] = {
+       { 0x000000, 0xffffff }, /* Normal */
+       { 0xff8080, 0xffffff }, /* Underline */
+       { 0x40c020, 0xe0e0e0 }, /* Bold */
+       { 0x003030, 0xff0060 }, /* Blink */
+       { 0xff8888, 0x000000 }, /* Inverse */
+};
+
+
+static char _attrs_inverse [5] = {
+       0, 0, 0, 0, 0 ,
+};
+
+
+/* see color.h */
+
+static long _mt_colors [CLR_MAX] [2] = {
+       { 0x000000, 0x808080 }, /* Black */
+       { 0x880000, 0xffffff }, /* Red */
+       { 0x008800, 0xffffff }, /* Green */
+       { 0x553300, 0xffffff }, /* Brown */
+       { 0x000088, 0xffffff }, /* Blue */
+       { 0x880088, 0xffffff }, /* Magenta */
+       { 0x008888, 0xffffff }, /* Cyan */
+       { 0x888888, 0xffffff }, /* Gray */
+       { 0x000000, 0xffffff }, /* No Color */
+       { 0xff4400, 0xffffff }, /* Orange */
+       { 0x00ff00, 0xffffff }, /* Bright Green */
+       { 0xffff00, 0x606060 }, /* Yellow */
+       { 0x0033ff, 0xffffff }, /* Bright Blue */
+       { 0xff00ff, 0xffffff }, /* Bright Magenta */
+       { 0x00ffff, 0xffffff }, /* Bright Cyan */
+       { 0xffffff, 0x505050 }, /* White */
+};
+
+static char _colors_inverse [CLR_MAX] = {
+       1, 0, 0, 0 ,
+       0, 0, 0, 0 ,
+       0, 0, 0, 0 ,
+       0, 0, 0, 0 ,
+};
+
+
+#ifdef CHANGE_COLOR
+
+#define POWER_LIMIT 22
+#define SECONDARY_POWER_LIMIT 16
+#define CHANNEL_LIMIT 14
+#define SECONDARY_CHANNEL_LIMIT 12
+
+void
+tty_change_color (int color, long rgb, int reverse) {
+long inverse, working_rgb = rgb;
+int total_power = 0, max_channel = 0;
+int cnt = 3;
+
+       working_rgb >>= 4;
+       while (cnt -- > 0) {
+               total_power += working_rgb & 0xf;
+               max_channel = max (max_channel, working_rgb & 0xf);
+               working_rgb >>= 8;
+       }
+
+       if (total_power >= POWER_LIMIT ||
+               (total_power >= SECONDARY_POWER_LIMIT &&
+                       max_channel >= SECONDARY_CHANNEL_LIMIT) ||
+                       max_channel >= CHANNEL_LIMIT)
+               inverse = 0x000000;
+       else
+               inverse = 0xffffff;
+
+       if (reverse) {
+               working_rgb = rgb;
+               rgb = inverse;
+               inverse = working_rgb;
+       }
+
+       if (color >= CLR_MAX) {
+               if (color - CLR_MAX >= 5)
+                       impossible ("Changing too many colors");
+               else {
+                       _mt_attrs [color - CLR_MAX] [0] = rgb;
+                       _mt_attrs [color - CLR_MAX] [1] = inverse;
+                       _attrs_inverse [color - CLR_MAX] = reverse;
+               }
+       } else if (color >= 0) {
+               _mt_colors [color] [0] = rgb;
+               _mt_colors [color] [1] = inverse;
+               _colors_inverse [color] = reverse;
+       } else
+               impossible ("Changing negative color");
+}
+
+void tty_change_background (int white_or_black) {
+       register int i;
+       
+       for (i = 0; i < CLR_MAX; i++) {
+               if (white_or_black)
+                       _mt_colors [i] [1] = 0xffffff;  /* white */
+               else
+                       _mt_colors [i] [1] = 0x000000;  /* black */
+       }
+       
+       /* special cases */
+       if (white_or_black) {
+               _mt_colors [CLR_BLACK] [1] = 0x808080;  /* differentiate black from no color */
+               _mt_colors [CLR_WHITE] [1] = 0x505050;  /* highlight white with grey background */
+               _mt_colors [CLR_YELLOW] [1] = 0x606060; /* highlight yellow with grey background */
+               _mt_colors [CLR_BLUE] [0] = 0x000088;   /* make pure blue */
+               _mt_colors [NO_COLOR] [0] = 0x000000; /* make no_color black on white */
+               _mt_attrs [0] [0] = 0x000000;           /* "normal" is black on white */
+               _mt_attrs [0] [1] = 0xffffff;
+       } else {
+               _mt_colors [NO_COLOR] [0] = 0xffffff; /* make no_color white on black */
+               _mt_colors [CLR_BLACK] [1] = 0x808080;  /* differentiate black from no color */
+               _mt_colors [CLR_BLUE] [0] = 0x222288;   /* lighten blue - it's too dark on black */
+               _mt_attrs [0] [0] = 0xffffff;           /* "normal" is white on black */
+               _mt_attrs [0] [1] = 0x000000;
+       }
+}
+
+char *
+tty_get_color_string (void) {
+char *ptr;
+int count;
+static char color_buf [5 * (CLR_MAX + 5) + 1];
+
+       color_buf [0] = 0;
+       ptr = color_buf;
+
+       for (count = 0; count < CLR_MAX; count ++) {
+       int flag = _colors_inverse [count] ? 1 : 0;
+
+               sprintf (ptr, "%s%s%x%x%x", count ? "/" : "" ,
+                       flag ? "-" : "" ,
+                       (int)(_mt_colors [count] [flag] >> 20) & 0xf ,
+                       (int)(_mt_colors [count] [flag] >> 12) & 0xf ,
+                       (int)(_mt_colors [count] [flag] >> 4) & 0xf);
+               ptr += strlen (ptr);
+       }
+       for (count = 0; count < 5; count ++) {
+       int flag = _attrs_inverse [count] ? 1 : 0;
+
+               sprintf (ptr, "/%s%x%x%x" ,
+                       flag ? "-" : "" ,
+                       (int)(_mt_attrs [count] [flag] >> 20) & 0xf ,
+                       (int)(_mt_attrs [count] [flag] >> 12) & 0xf ,
+                       (int)(_mt_attrs [count] [flag] >> 4) & 0xf);
+               ptr += strlen (ptr);
+       }
+
+       return color_buf;
+}
+#endif
+
+
+extern struct DisplayDesc *ttyDisplay; /* the tty display descriptor */
+
+char kill_char = CHAR_ESC;
+char erase_char = CHAR_BS;
+
+WindowRef _mt_window = (WindowRef) 0;
+static Boolean _mt_in_color = 0;
+extern short win_fonts [NHW_TEXT + 1];
+
+static void
+_mt_init_stuff (void) {
+long resp, flag;
+short num_cols, num_rows, win_width, win_height, font_num, font_size;
+short char_width, row_height;
+short hor, vert;
+
+       LI = MT_HEIGHT;
+       CO = MT_WIDTH;
+
+       if (!strcmp(windowprocs.name, "mac")) {
+               dprintf ("Mac Windows");
+               LI -= 1;
+       } else {
+               dprintf ("TTY Windows");
+       }
+       
+       /*
+        * If there is at least one screen CAPABLE of color, and if
+        * 32-bit QD is there, we use color. 32-bit QD is needed for the
+        * offscreen GWorld
+        */
+       if (!Gestalt (gestaltQuickdrawVersion, &resp) && resp > 0x1ff) {
+               GDHandle gdh = GetDeviceList ();
+               while (gdh) {
+                       if (TestDeviceAttribute (gdh, screenDevice)) {
+                               if (HasDepth (gdh, 4, 1, 1) ||
+                                       HasDepth (gdh, 8, 1, 1) ||
+                                       HasDepth (gdh, 16, 1, 1) ||
+                                       HasDepth (gdh, 32, 1, 1)) {
+                                       _mt_in_color = 1;
+                                       break;
+                               }
+                       }
+                       gdh = GetNextDevice (gdh);
+               }
+       }
+
+       if (create_tty (&_mt_window, WIN_BASE_KIND + NHW_MAP, _mt_in_color) != noErr)
+               error("_mt_init_stuff: Couldn't create tty.");
+       SetWindowKind(_mt_window, WIN_BASE_KIND + NHW_MAP);
+       SelectWindow(_mt_window);
+       SetPortWindowPort(_mt_window);
+       SetOrigin(-1, -1);
+
+       font_size = iflags.wc_fontsiz_map ? iflags.wc_fontsiz_map :
+               (iflags.large_font && !small_screen) ? 12 : 9;
+       if (init_tty_number (_mt_window, win_fonts [NHW_MAP], font_size, CO, LI) != noErr)
+               error("_mt_init_stuff: Couldn't init tty.");
+
+       if (get_tty_metrics (_mt_window, &num_cols, &num_rows, &win_width ,
+               &win_height, &font_num, &font_size, &char_width, &row_height))
+               error("_mt_init_stuff: Couldn't get tty metrics.");
+
+       SizeWindow (_mt_window, win_width + 2, win_height + 2, 1);
+       if (RetrievePosition (kMapWindow, &vert, &hor)) {
+               dprintf ("Moving window to (%d,%d)", hor, vert);
+               MoveWindow (_mt_window, hor, vert, 1);
+       }
+       ShowWindow (_mt_window);
+
+       /* Start in raw, always flushing mode */
+       get_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, &flag);
+       flag |= TA_ALWAYS_REFRESH | TA_WRAP_AROUND;
+       set_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, flag);
+
+       get_tty_attrib(_mt_window, TTY_ATTRIB_CURSOR, &flag);
+       flag |= (TA_BLINKING_CURSOR | TA_NL_ADD_CR);
+       set_tty_attrib(_mt_window, TTY_ATTRIB_CURSOR, flag);
+
+       set_tty_attrib(_mt_window, TTY_ATTRIB_FOREGROUND, _mt_colors[NO_COLOR][0]);
+       set_tty_attrib(_mt_window, TTY_ATTRIB_BACKGROUND, _mt_colors[NO_COLOR][1]);
+       clear_tty (_mt_window);
+
+       InitMenuRes ();
+}
+
+
+int
+tgetch (void) {
+EventRecord event;
+long sleepTime = 0;
+int ret = 0;
+
+       for (;!ret;) {
+               WaitNextEvent (-1, &event, sleepTime, 0);
+               HandleEvent (&event);
+               blink_cursor (_mt_window, event.when);
+               if (event.what == nullEvent) {
+                       sleepTime = GetCaretTime ();
+               } else {
+                       sleepTime = 0;
+               }
+               ret = GetFromKeyQueue ();
+               if (ret == CHAR_CR) ret = CHAR_LF;
+       }
+       return ret;
+}
+
+
+void
+getreturn (char *str) {
+       FlushEvents (-1, 0);
+       msmsg ("Press space %s", str);
+       (void) tgetch ();
+}
+
+
+int
+has_color (int color) {
+#if defined(__SC__) || defined(__MRC__)
+# pragma unused(color)
+#endif
+       Rect r;
+//     Point p = {0, 0};
+       GDHandle gh;
+
+
+       if (!_mt_in_color)
+               return 0;
+
+       GetWindowBounds(_mt_window, kWindowContentRgn, &r);
+//     SetPortWindowPort(_mt_window);
+//     LocalToGlobal (&p);
+//     OffsetRect (&r, p.h, p.v);
+
+       gh = GetMaxDevice (&r);
+       if (!gh) {
+               return 0;
+       }
+
+       return (*((*gh)->gdPMap))->pixelSize > 4; /* > 4 bpp */
+}
+
+
+void
+tty_delay_output (void) {
+EventRecord event;
+long toWhen = TickCount () + 3;
+
+       while (TickCount () < toWhen) {
+               WaitNextEvent (updateMask, &event, 3L, 0);
+               if (event.what == updateEvt) {
+                       HandleEvent (&event);
+                       blink_cursor (_mt_window, event.when);
+               }
+       }
+}
+
+
+void
+cmov (int x, int y) {
+       move_tty_cursor (_mt_window, x, y);
+       ttyDisplay->cury = y;
+       ttyDisplay->curx = x;
+}
+
+
+void
+nocmov (int x, int y) {
+       cmov (x, y);
+}
+
+
+static void
+_mt_set_colors (long *colors) {
+short err;
+
+       if (!_mt_in_color) {
+               return;
+       }
+       err = set_tty_attrib (_mt_window, TTY_ATTRIB_FOREGROUND, colors [0]);
+       err = set_tty_attrib (_mt_window, TTY_ATTRIB_BACKGROUND, colors [1]);
+}
+
+
+void
+term_end_attr (int attr) {
+#if defined(__SC__) || defined(__MRC__)
+# pragma unused (attr)
+#endif
+       _mt_set_colors (_mt_attrs [0]);
+}
+
+
+void
+term_start_attr (int attr) {
+       switch (attr) {
+               case ATR_ULINE:
+                       _mt_set_colors (_mt_attrs [1]);
+                       break;
+               case ATR_BOLD:
+                       _mt_set_colors (_mt_attrs [2]);
+                       break;
+               case ATR_BLINK:
+                       _mt_set_colors (_mt_attrs [3]);
+                       break;
+               case ATR_INVERSE:
+                       _mt_set_colors (_mt_attrs [4]);
+                       break;
+               default:
+                       _mt_set_colors (_mt_attrs [0]);
+                       break;
+       }
+}
+
+
+void
+standoutend (void) {
+       term_end_attr (ATR_INVERSE);
+}
+
+
+void
+standoutbeg (void) {
+       term_start_attr (ATR_INVERSE);
+}
+
+
+void
+term_end_color (void) {
+       _mt_set_colors (_mt_colors [NO_COLOR]);
+}
+
+
+void
+cl_end (void) {
+       _mt_set_colors (_mt_attrs [0]);
+       clear_tty_window (_mt_window, ttyDisplay->curx, ttyDisplay->cury,
+               CO - 1, ttyDisplay->cury);
+}
+
+
+void
+clear_screen (void) {
+       _mt_set_colors (_mt_attrs [0]);
+       clear_tty (_mt_window);
+}
+
+
+void
+cl_eos (void) {
+       _mt_set_colors (_mt_attrs [0]);
+       clear_tty_window (_mt_window, ttyDisplay->curx, ttyDisplay->cury, CO - 1,
+               LI - 1);
+}
+
+
+void
+home (void) {
+       cmov (0,0);
+}
+
+
+void
+backsp (void) {
+char eraser [] = { CHAR_BS, CHAR_BLANK, CHAR_BS, 0 };
+short err;
+
+       err = add_tty_string (_mt_window, eraser);
+       err = update_tty (_mt_window);
+}
+
+
+void
+msmsg (const char *str, ...) {
+va_list args;
+char buf [1000];
+
+       va_start (args, str);
+       vsprintf (buf, str, args);
+       va_end (args);
+
+       xputs (buf);
+}
+
+
+void
+term_end_raw_bold (void) {
+       term_end_attr (ATR_INVERSE);
+}
+
+
+void
+term_start_raw_bold (void) {
+       term_start_attr (ATR_INVERSE);
+}
+
+
+void
+term_start_color (int color) {
+       if (color >= 0 && color < CLR_MAX) {
+               _mt_set_colors (_mt_colors [color]);
+       }
+}
+
+
+void
+setftty (void)
+{
+       long flag;
+
+       /* Buffered output for the game */
+       get_tty_attrib (_mt_window, TTY_ATTRIB_FLAGS, &flag);
+       flag &= ~ TA_ALWAYS_REFRESH;
+       flag |= TA_INHIBIT_VERT_SCROLL; /* don't scroll */
+       set_tty_attrib (_mt_window, TTY_ATTRIB_FLAGS, flag);
+       iflags.cbreak = 1;
+}
+
+
+void
+tty_startup (int *width, int *height ) {
+       _mt_init_stuff ();
+       *width = CO;
+       *height = LI;
+}
+
+
+void
+gettty (void) {
+}
+
+
+void
+settty (const char *str)
+{
+       long flag;
+
+       update_tty (_mt_window);
+
+       /* Buffered output for the game, raw in "raw" mode */
+       get_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, &flag);
+       flag &= ~ TA_INHIBIT_VERT_SCROLL; /* scroll */
+       flag |= TA_ALWAYS_REFRESH;
+       set_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, flag);
+
+       tty_raw_print ("\n");
+       if (str) {
+               tty_raw_print (str);
+       }
+}
+
+
+void
+tty_number_pad (int arg) {
+#if defined(__SC__) || defined(__MRC__)
+# pragma unused(arg)
+#endif
+}
+
+
+void
+tty_start_screen (void) {
+       iflags.cbreak = 1;
+}
+
+
+void
+tty_end_screen (void) {
+}
+
+
+void
+xputs (const char *str) {
+       add_tty_string (_mt_window, str);
+}
+
+
+int
+term_puts (const char *str) {
+       xputs (str);
+       return strlen (str);
+}
+
+
+int
+term_putc (int c) {
+short err;
+
+       err = add_tty_char (_mt_window, c);
+       return err ? EOF : c;
+}
+
+
+int
+term_flush (void *desc) {
+       if (desc == stdout || desc == stderr) {
+               update_tty (_mt_window);
+       } else {
+               impossible ("Substituted flush for file");
+               return fflush (desc);
+       }
+       return 0;
+}
diff --git a/sys/msdos/Install.dos b/sys/msdos/Install.dos
new file mode 100644 (file)
index 0000000..735d9a8
--- /dev/null
@@ -0,0 +1,268 @@
+       SCCS Id: @(#)Install.dos         3.4
+
+          Copyright (c) NetHack PC Development Team 1990-2002.
+       NetHack may be freely redistributed.  See license for details.
+       ==============================================================
+              Instructions for compiling and installing
+                    NetHack 3.4 on a DOS system
+         ======================================================
+                   (or, How to make PC NetHack 3.4)
+                 Last revision: $Date: 2003/06/13 19:57:52 $
+
+Credit for a runnable full PC NetHack 3.4 goes to the PC Development team
+of Paul Winner, Kevin Smolkowski, Michael Allison, Yitzhak Sapir, Bill Dyer, 
+Timo Hakulinen, Yamamoto Keizo, Mike Threepoint, Mike Stephenson, 
+Stephen White, Ken Washikita and Janet Walz.  The present port is based
+on the previous effort of Pierre Martineau, Stephen Spackman, Steve Creps, Mike
+Threepoint, Mike Stephenson, Norm Meluch and Don Kneller.
+
+There has been very little port-specific maintenance for NetHack on DOS since 
+NetHack 3.3.0.
+
+CONTENTS:
+
+        I.  Dispelling the Myths
+        II. Compiling on a DOS machine
+        Appendix A - Building the "official binary"
+        Appendix B - DJGPP Compiler (gcc ported to msdos) notes
+        Appendix C - Additional Notes
+        Appendix D - Contacting Us
+
+I.  Dispelling the Myths:
+
+    Compiling NetHack is not as easy as it sounds, nor as hard as it looks,
+    however it will behoove you to read this entire file through before
+    beginning the task.
+
+    We have provided a proper Makefile for building NetHack using the
+    following compilers:
+       djgpp V2.03 or later
+
+    For specific details concerning the djgpp compiler, please see the
+    appendix B.
+
+    The makefile named Makefile.GCC is for use with GNU Make that
+    accompanies djgpp.
+
+    If you want to build a copy of NetHack that is identical to the
+    "official binary", please see appendix A.
+
+    The unsupported sys/msdos/Makefile.MSC was for the old 16 bit
+    Microsoft Visual C 1.52c compiler and has not been made compliant
+    with 3.4.x.
+
+    You may find it useful to obtain copies of lex (flex) and yacc (bison
+    or byacc).  While not strictly necessary to compile nethack, they are 
+    required should you desire to make any changes to the level and dungeon 
+    compilers.  Flex and Bison are included with the DJGPP distribution and 
+    are also available on many archive sites. 
+
+    Also be sure to pick up djgpp v2gnu/fil41b.zip to get ls.exe and 
+    touch.exe, since the Makefile uses them by default.
+
+II. To compile your copy of NetHack on a DOS machine:
+    (or "just follow these few 'simple' steps outlined below.")
+
+1.  It almost goes without saying that you should make sure that your tools
+    are set up and running correctly.
+
+2.  Make sure all the NetHack files are in the appropriate directory
+    structure.  You should have a main directory with subdirectories
+    dat, doc, include, src, sys\share, sys\msdos, util, win\tty and
+    win\share.  Other subdirectories may also be included in your
+    distribution, but they are not necessary for use with DOS.  You can
+    delete them to save space.
+
+    Required Source Directories for DOS NetHack:
+
+                           (top)
+                             |
+        ------------------------------------------------- 
+        |       |     |        |       |     |          | 
+       util    dat   doc    include   src   sys        win
+                                             |          |
+                                          ------      ----- 
+                                          |    |      |   |  
+                                       share msdos   tty share
+
+    Check the file "Files" in your top level directory for an exact
+    listing of what files are in which directory.  In order for the
+    Makefiles to work, all the source files must be in the proper
+    locations.
+
+    If you downloaded or ftp'd the sources from a UNIX system, the lines
+    will probably end in UNIX-style newlines, instead of the carriage
+    return and line feed pairs used by DOS.  Some programs have trouble
+    with them, so you may need to convert them (with a utility like
+    Rahul Dhesi's "flip").
+
+3.  Go to the sys/msdos directory and ensure that the file setup.bat
+    has MSDOS style end-of-line characters rather than UNIX style
+    end-of-line characters.  You can do that using a utility like
+    Rahul Dhesi's "flip", or by invoking the MSDOS edit utility on
+    setup.bat and saving the file without making any changes. Failure to
+    do this will prevent the bat file from executing completely, yet no
+    warning message will be given.
+
+    Run the setup.bat batch file with the following as the argument:
+
+       GCC        For djgpp and GNU MAKE.
+
+    The appropriate and necessary Makefile movement will be accomplished
+    for you, as well as verifying a few files and fixing a few file names
+    on FAT systems with long file name support.
+
+4.  Now go to the include subdirectory to check a couple of the header
+    files there.  Things *should* work as they are, but since you have
+    probably set up your system in some sort of custom configuration
+    it doesn't hurt to check out the following:
+
+    First check config.h according to the comments to match your system and
+    desired set of features.  Mostly you need to check the WIZARD option,
+    and check TERMLIB and COMPRESS.  Also be sure to leave DLB support 
+    commented out in config.h.  MSDOS has support for DLB, but it must be 
+    done through the Makefile, rather than config.h, to ensure that the 
+    necessary packaging steps are done.
+
+    We've managed to enable all the special features.  You may include all
+    or as few of them as you wish.  To conserve disk space, you may wish
+    to disable LOGFILE and NEWS.
+
+    Also check pcconf.h, which should not need much editing (if you are
+    including random.c, and if you do not require termcap for screen
+    management).  If you are not including random.c you will need to
+    comment out RANDOM.
+
+    If using DJGPP, you can choose between SCREEN_BIOS
+    and SCREEN_DJGPPFAST.  Never, never, ever choose both.  Bad things
+    will happen.  We are not kidding.
+
+5.  If you want to change the high score list behavior, examine the top of
+    topten.c, in the src directory.  You may want to change the definitions of
+    PERSMAX, POINTSMIN, and ENTRYMAX.  We set POINTSMIN to 51 and ENTRYMAX to
+    50 to keep the size of the score list down.
+
+6.  Go to the src directory and edit the top of your Makefile.  Be sure the
+    directory you want the game installed in (GAMEDIR) actually exists.
+
+7.  Now that everything is set up,
+
+       Go to the src directory, and using the GNU Make utility,
+       "make install".
+
+    Depending on your particular machine and compiler, you can either
+    grab a cup of coffee or go home for the day.  Your computer will be
+    occupied for quite some time.  If all goes well, you will get an
+    NetHack executable.
+
+9.  If you chose DLB support (recommended), make sure that the file nhdat 
+    got copied into the game directory.
+
+    If you didn't choose DLB support, make sure the support files --
+    data, rumors, cmdhelp, opthelp, help, hh,history, guidebook.txt
+    license, and all the *.lev files -- were copied to the game directory.  
+    If not, move them there from the dat directory yourself.  rumors can 
+    be created manually be entering "makedefs -r", data by entering 
+    "makedefs -d".
+
+    Make sure the files NetHack1.tib and NetHacko.tib made it to your game
+    directory.  Copy them from src to the game directory yourself if
+    necessary.
+
+    Make sure the files defaults.nh and termcap made it to your game
+    directory.  If not, go to sys\share and copy NetHack.cnf to
+    your game directory as defaults.nh.  The name in previous versions was
+    nethack.cnf, but the CNF extension conflicted with the MS Windows
+    speed-dialer, making the file hidden on many machines.
+
+    If you changed your build settings to include TERMCAP support, copy
+    termcap to your game directory.  
+
+    Also, make sure the file msdoshlp.txt made it to your game directory.
+    If it didn't, move it from sys\msdos to your game directory
+    yourself.
+
+10. In your game directory, review the settings in defaults.nh and adjust
+    them according to your style of play.
+
+11. Play NetHack.  If it works, you're done!
+
+Appendix A - Building the "official binary"
+
+    If you wish to build a copy of NetHack identical to the one that
+    the pc team distributes, simply do the following:
+
+    The 32-bit Protected Mode DPMI version built with 32-bit djgpp 
+    compiler V2.03 or greater, make no changes to any of the defines and use 
+    the Makefile.GCC as distributed, and as moved in step 3.
+
+    Paths below are relative to the top of your unpacked
+    NetHack source distribution:
+
+       md \nethack\binary   (must match Makefile)
+       cd sys\msdos
+       setup GCC
+       cd ..\..\src
+       make install
+
+
+    Make sure the following files have been converted from the
+    unix style "^J" end of line, to the msdos style "^M^J":
+      license, defaults.nh.
+
+    Place all the files in a clean directory and test.
+
+Appendix B - DJGPP Compiler (gcc ported to msdos)
+
+    If you have a 386 or better machine, you are in luck.  You can compile
+    NetHack without spending money on a compiler.  DJGPP is available free
+    from many archive sites.
+    At the time of this release in April 2002, the URL
+       http://www.delorie.com/djgpp/zip-picker.html/
+    had information on how to obtain djgpp and what pieces to get.
+    Be sure to pick up djgpp v2gnu/fil41b.zip to get ls.exe and 
+    touch.exe, since the Makefile uses them by default (or change
+    the Makefile to use alternatives).
+
+    Special note for Windows 2000 / Windows XP users: You must have a 
+    recent djgpp distribution for the build process, and the generated
+    executables to work properly on those platforms.
+
+    Setting up DJGPP is more than adequately explained in the documentation
+    that comes with it.  Be sure to pick up the yacc and flex built with
+    DJGPP if you intend to do any modification of the special levels or
+    dungeon compilers.  They should be available at the same place you got
+    djgpp.
+
+    The latest version of djgpp, V2.03 with the most recent refresh
+    will produce a binary that will run under Microsoft Windows, or any 
+    other DPMI provider.  djgpp also comes with a DPMI provider called CWSDPMI.  
+    Place CWSDPMI.EXE in your path and it will be used in the absence of any 
+    other DPMI provider.
+
+    If you want to use the built-in DJGPP screen routines, uncomment
+    SCREEN_DJGPPFAST in pcconf.h (the default for djgpp).
+
+Appendix C - Additional Notes
+
+1)  Save files and bones files from versions of NetHack prior to 3.4.0 will not
+    work with this NetHack.  Don't bother trying to keep them.
+
+2)  To install an update of NetHack after changing something, type 'make' 
+    for DJGPP from the src directory.  If you add, delete, or reorder monsters or
+    objects, or you change the format of saved level files, delete any save
+    and bones files.  (Trying to use such files sometimes produces amusing
+    confusions on the game's part, but usually crashes.)
+
+
+Appendix D - Contacting the Development Team
+
+    If you discover a bug and wish to report it, or if you have comments
+    or suggestions we recommend using
+    our "Contact Us" web page at:
+        http://www.nethack.org/common/contact.html
+
+    If you don't have access to the web, or you want to send us a patch
+    to the NetHack source code feel free to drop us a line c/o:
+        DevTeam (at) nethack.org
+
diff --git a/sys/msdos/Makefile.BC b/sys/msdos/Makefile.BC
new file mode 100644 (file)
index 0000000..7008160
--- /dev/null
@@ -0,0 +1,2081 @@
+#      SCCS Id: @(#)Makefile.BC        3.4     2002/03/17
+# Copyright (c) Yitzhak Sapir, 1999-2002.
+# NetHack may be freely distributed.  See license for details.
+#
+
+# PC NetHack 3.4 Makefile for Borland C++ 3.1 and 4.5.
+#
+# Nota Bene:   Before you get to here you should have already read
+#              the Install.dos file located in the sys/msdos directory.
+#              Additionally, you should run this makefile with the -N
+#              Microsoft Compatibility option.
+#
+# This Makefile is for use with Borland C++ version 3.1 and 4.5, but might
+# also work with more up to date versions.
+#
+# This Makefile is specific to Borland's MAKE which is supplied with the
+# compiler.  It supports only one overlay management facility - VROOMM.
+# (This Makefile won't work with make45l or NDMAKE)
+
+#
+# Game Installation Variables.
+# NOTE: Make sure GAMEDIR exists before nmake is started.
+#
+
+GAME   = NetHack
+GAMEDIR = ..\binary
+
+#
+#
+# Directories
+#
+
+DAT    = ..\dat
+DOC    = ..\doc
+INCL   = ..\include
+SRC    = ..\src
+OBJ    = o
+MSYS   = ..\sys\msdos
+SYS    = ..\sys\share
+UTIL   = ..\util
+WTTY   = ..\win\tty
+WSHR   = ..\win\share
+
+
+#
+# Compiler File Info.
+# ($(MAKE) macro is often predefined, so we use $(MAKEBIN) instead.)
+#
+
+CC      = bcc          # Compiler
+LINK    = tlink        # Linker
+ASM     = tasm         # Assembler (not currently needed for BC)
+MAKEBIN  = make
+UUDECODE = uudecode    # Unix style uudecoder
+
+#BCTOP  = c:\borlandc  # main Borland C++ directory
+BCTOP   = c:\bc31
+
+#
+# Yacc/Lex ... if you got 'em.
+#
+# If you have yacc and lex programs (or work-alike such as bison
+# and flex), comment out the upper two lines below, and uncomment
+# the lower two.
+#
+# On Borland C++, the newest versions of flex and bison provide
+# problems when run from MAKE.
+#
+
+DO_YACC = YACC_MSG
+DO_LEX  = LEX_MSG
+#DO_YACC  = YACC_ACT
+#DO_LEX   = LEX_ACT
+
+#
+# - Specify your yacc and lex programs (or work-alikes for each) here.
+#
+
+YACC   = bison -y
+#YACC   = yacc
+#YACC   = byacc
+
+LEX     = flex
+#LEX    = lex
+
+#
+# - Specify your flex skeleton file (if needed).
+#
+FLEXSKEL =
+#FLEXSKEL = -Sc:\tools16\flex.ske
+
+#
+# - Your yacc (or work-alike) output files
+#
+YTABC  = y_tab.c
+YTABH  = y_tab.h
+#YTABC  = ytab.c
+#YTABH  = ytab.h
+
+#
+# - Your lex (or work-alike) output files
+#
+LEXYYC = lexyy.c
+#LEXYYC        = lex.yy.c
+
+#
+# Optional high-quality BSD random number generation routines
+# (see pcconf.h). Set to nothing if not used.
+#
+
+RANDOM = $(OBJ)\random.o
+#RANDOM        =
+
+#
+# If TERMLIB is #defined in the source (in include\pcconf.h),
+# comment out the upper line and uncomment the lower.  Make sure
+# that TERMLIB contains the full pathname to the termcap library.
+
+TERMLIB =
+#TERMLIB = $(SYS)\termcap.lib
+
+#
+# MEMORY USAGE AND OVERLAYING
+#
+# Overlay Schema 1
+#
+#   - Minimal extended memory available, lots of 640K base RAM free
+#     Minimize overlay turns. Requires that a minimum of
+#     607K RAM be free as follows:
+#     462K  Executable load requirement
+#     115K  for malloc() calls
+#      30K  Overlay buffer
+#     607K  Total memory requirement
+#
+# Overlay Schema 2
+#
+#   - Favor small load size, requires extended memory for bearable performance.
+#     If you have very little base 640K RAM available, but lots of extended
+#     memory for caching overlays, you might try this. (eg. A machine with
+#     lots of TSR's or network drivers).  Do not try to set SCHEMA = 2
+#     without a disk cache and extended memory.
+#     381K  Executable load requirement
+#     115K  for malloc() calls
+#      30K  Overlay buffer
+#     526K  Total memory requirement
+#
+# On Borland C++, you have to make a full rebuild of all object modules each
+# time you change schemas.
+#
+
+SCHEMA = 2
+
+#
+# OPTIONAL TILE SUPPORT.
+#
+#      This release of NetHack allows you to build a version of NetHack
+#      that will draw 16x16 color tiles on the display to represent
+#      NetHack maps, objects, monsters, etc. on machines with appropriate
+#      display hardware.  Currently the only supported video hardware is
+#      VGA.
+#
+#      Note:  You can build NetHack with tile support and then choose
+#      whether to use it or not at runtime via the defaults.nh file option
+#      "video".
+#
+
+TILESUPPORT = Y
+
+#
+#  C COMPILER AND LINKER SETTINGS
+#
+#   For debugging ability, comment out the upper three
+#   macros and uncomment the lower three.  You can also
+#   uncomment only either LDFLAGSU or LDFLAGSN if you
+#   want to include debug information only in the utilities
+#   or only in the game file.
+
+#   On Borland C++, you cannot include debug information for
+#   all the object modules because the linker cannot handle
+#   it.
+
+#CDFLAGS  =
+LDFLAGSN  =
+#LDFLAGSU =
+
+CDFLAGS          = -v -vi              # use debug info (compiler)
+#LDFLAGSN = /v                 # use debug info (linker - game)
+LDFLAGSU  = /v                 # use debug info (linker - utilities)
+
+#
+# - Don't warn about unreachable code because flex generates a whole bunch
+#   of unreachable code warnings, which stops the compile process.
+#
+
+CW = -w-rch
+
+#
+#   Select whether to use pre-compiled headers or not.
+#   Set PRECOMPHEAD to Y to use pre-compiled headers, set it to anything
+#   else and pre-compiled headers will not be used.
+#   (Pre-compiled headers speed up compiles, but require a bit more
+#   disk space during the build.  The pre-compiled headers can be deleted
+#   afterwards via DEL *.PCH if desired).
+#
+
+PRECOMPHEAD = N
+
+#
+#   C Compiler Flags
+#
+
+CFLAGS = -c
+
+#  Uncomment the line below if you want to store all the level files,
+#  help files, etc. in a single library file (recommended).
+
+USE_DLB = Y
+
+#
+########################################################################
+########################################################################
+#
+#  Nothing below here should have to be changed.
+#
+########################################################################
+########################################################################
+#
+#  Warning:
+#
+#  Changing anything below here means that you should be *very*
+#  familiar with your compiler's workings, *very* knowledgeable
+#  about the overlay structure and mechanics of NetHack, and *very*
+#  confident in your understanding of Makefiles and Make utilities.
+#
+########################################################################
+#
+# Default Make Procedure
+#
+
+default: $(GAME)
+
+#
+########################################################################
+# Tile preparation
+#
+
+! IF ("$(TILESUPPORT)"=="Y")
+
+TILEGAME  = $(OBJ)\tile.o      $(OBJ)\pctiles.0        $(OBJ)\pctiles.b
+
+#
+#   -  VGA Tile Support, uncomment these three lines.
+#
+
+TILEVGA    = $(OBJ)\vidvga.0 $(OBJ)\vidvga.1 $(OBJ)\vidvga.2 $(OBJ)\vidvga.b
+PLANAR_TIB = NetHack1.tib
+OVERVIEW_TIB = NetHacko.tib
+
+#
+# Leave this line uncommented and unchanged.
+TILEUTIL  =  $(TILEGAME) $(TILEVGA) $(UTIL)\tile2bin.exe $(UTIL)\til2bin2.exe \
+                $(PLANAR_TIB) $(OVERVIEW_TIB)
+
+! ENDIF
+
+! IF ("$(USE_DLB)"=="Y")
+DLB = nhdat
+! ELSE
+DLB =
+! ENDIF
+
+#
+#############################################################################
+#
+# General Overlay Schema Settings
+#
+
+OVLINIT =$(OBJ)\ovlinit.o
+
+
+#
+#############################################################################
+#
+# C Compiler and Linker Setup Options
+# (To Maintainer; modify only if absolutely necessary)
+#
+
+BCINCL  = $(BCTOP)\include     # include directory for main BC headers
+BCLIB   = $(BCTOP)\lib         # library directory for main BC libraries
+BCCFG   = nethack.cfg          # name of the nethack configuration file
+VROOMMCFG= vroomm.cfg          # name of file with code segment information
+
+#
+# Model
+#
+
+MODEL   = h
+
+#
+# - Optional C library specifier for those with non-standard
+#   libraries or a multiple-target library setup.
+#
+
+CLIB    =
+
+#
+# Borland C++ libraries
+#
+
+BCOVL  = $(BCLIB)\OVERLAY
+BCMDL  = $(BCLIB)\C$(MODEL)
+
+#
+# Compiler Options
+#
+
+CNOLNK = -c                    # just generate .OBJ
+CPCHUSE        = -Hu                   # use precompiled headers
+CPCHGEN        = -H                    # generate precompiled headers
+CPCHNAM        = -H=                   # set the name of the precompiled header file
+CPCHEXT = .PCH                 # precompiled header extension
+CDEFINE        = -D                    # define a macro
+CSTKSZ = -DSTKSIZ=             # set stack size
+CCSNAM = -zC                   # set the code segment name
+COBJNAM        = -o                    # name the .OBJ file
+
+#
+# Linker Options
+#
+
+LWCASE = /c                    # treat case as significant
+LMAP   = /m                    # create map file
+LINIT  = $(BCLIB)\C0$(MODEL)   # initialization object file
+LOVL   = /oOVLY                # overlay all needed segments
+
+#
+# Stack Sizes
+#
+
+STKSUTL        = 4096                  # Utilities Stack Size
+STKSNRM = 5120                 # Normal Stack Size
+
+CUSTACK        = $(CSTKSZ)$(STKSUTL)   # Utilities Stack Set for Compiler
+CNSTACK        = $(CSTKSZ)$(STKSNRM)   # Normal Stack Set for Compiler
+
+
+#
+########################################################################
+# DLB preparation
+#
+
+! IF ("$(USE_DLB)"=="Y")
+DLBFLG = $(CDEFINE)DLB
+! ELSE
+DLBFLG =
+! ENDIF
+
+#
+########################################################################
+# tile preparation
+#
+
+! IF ("$(TILESUPPORT)"=="Y")
+TILFLG = $(CDEFINE)USE_TILES
+! ELSE
+TILFLG =
+! ENDIF
+
+#############################################################################
+#
+# Overlay switches
+#
+
+COVL0  = $(CDEFINE)OVL0
+COVL1  = $(CDEFINE)OVL1
+COVL2  = $(CDEFINE)OVL2
+COVL3  = $(CDEFINE)OVL3
+COVLB  = $(CDEFINE)OVLB
+
+#
+# Flags
+#
+
+FLAGOPT = $(DLBFLG) $(TILFLG)
+
+#
+# Precompiled Header Section
+#
+
+#common options (placed in $(BCCFG))
+CFLGTOT = $(CDFLAGS) $(CFLAGS) $(FLAGOPT) $(CW)
+#util builds
+CFLAGSU        = $(CUSTACK) +$(VROOMMCFG)
+#normal build, no PCH
+CFLAGSN = $(CNSTACK) +$(VROOMMCFG)
+#no optimizations
+CFLAGNO = $(CNOOPT) $(CFLAGSN)
+
+! IF ("$(PRECOMPHEAD)"!="Y")
+
+CFLAGCO = $(COVLO)
+CFLAGUO = $(COVLO)
+CFLAGC0 = $(COVL0)
+CFLAGU0 = $(COVL0)
+CFLAGC1 = $(COVL1)
+CFLAGU1 = $(COVL1)
+CFLAGC2 = $(COVL2)
+CFLAGU2 = $(COVL2)
+CFLAGC3 = $(COVL3)
+CFLAGU3 = $(COVL3)
+CFLAGCB = $(COVLB)
+CFLAGUB = $(COVLB)
+PCHO =
+PCH0 =
+PCH1 =
+PCH2 =
+PCH3 =
+PCHB =
+
+precomp.msg:
+       @echo Not using precompiled headers...
+
+! ELSE
+
+# .o files
+CFLAGUO        = $(CPCHUSE) $(CPCHNAM)PHO$(CPCHEXT) $(COVLO)
+CFLAGCO        = $(CPCHGEN) $(CPCHNAM)PHO$(CPCHEXT) $(COVLO)
+PCHO = PHO$(CPCHEXT)
+# .0 files
+CFLAGU0        = $(CPCHUSE) $(CPCHNAM)PH0$(CPCHEXT) $(COVL0)
+CFLAGC0        = $(CPCHGEN) $(CPCHNAM)PH0$(CPCHEXT) $(COVL0)
+PCH0 = PH0$(CPCHEXT)
+# .1 files
+CFLAGU1        = $(CPCHUSE) $(CPCHNAM)PH1$(CPCHEXT) $(COVL1)
+CFLAGC1        = $(CPCHGEN) $(CPCHNAM)PH1$(CPCHEXT) $(COVL1)
+PCH1 = PH1$(CPCHEXT)
+# .2 files
+CFLAGU2        = $(CPCHUSE) $(CPCHNAM)PH2$(CPCHEXT) $(COVL2)
+CFLAGC2        = $(CPCHGEN) $(CPCHNAM)PH2$(CPCHEXT) $(COVL2)
+PCH2 = PH2$(CPCHEXT)
+# .3 files
+CFLAGU3        = $(CPCHUSE) $(CPCHNAM)PH3$(CPCHEXT) $(COVL3)
+CFLAGC3        = $(CPCHGEN) $(CPCHNAM)PH3$(CPCHEXT) $(COVL3)
+PCH3 = PH3$(CPCHEXT)
+# .B files
+CFLAGUB        = $(CPCHUSE) $(CPCHNAM)PHB$(CPCHEXT) $(COVLB)
+CFLAGCB        = $(CPCHGEN) $(CPCHNAM)PHB$(CPCHEXT) $(COVLB)
+PCHB = PHB$(CPCHEXT)
+
+precomp.msg:
+       @echo Using precompiled headers...
+
+! ENDIF
+
+
+FLAGCO  = $(CNSTACK) +$(VROOMMCFG)
+FLAGUO  = $(CNSTACK) +$(VROOMMCFG)
+FLAGC0  = $(CNSTACK) +$(VROOMMCFG)
+FLAGU0  = $(CNSTACK) +$(VROOMMCFG)
+FLAGC1  = $(CNSTACK) +$(VROOMMCFG)
+FLAGU1  = $(CNSTACK) +$(VROOMMCFG)
+FLAGC2  = $(CNSTACK) +$(VROOMMCFG)
+FLAGU2  = $(CNSTACK) +$(VROOMMCFG)
+FLAGC3  = $(CNSTACK) +$(VROOMMCFG)
+FLAGU3  = $(CNSTACK) +$(VROOMMCFG)
+FLAGCB  = $(CNSTACK) +$(VROOMMCFG)
+FLAGUB  = $(CNSTACK) +$(VROOMMCFG)
+
+# End of Pre-compiled header section
+#===========================================================================
+
+#
+# Basic Borland C++ option line
+#
+BCOPTS1 = -Y -O -Z -Oe -Ob -Os -Ff -I$(BCINCL);$(INCL) -m$(MODEL)
+BCOPTS2 = $(CDEFINE)__IO_H $(CFLGTOT) -DSTRNCMPI
+
+#
+# Linker options for building various things.
+#
+
+LFLAGSU        = $(LDFLAGSU) $(LUSTACK) $(LINIT)
+LFLAGSN        = $(LDFLAGSN) $(LNSTACK) $(LWCASE) $(LMAXSEG) $(INTOVL) $(LMAXALL) \
+         $(LINFO) $(LINIT) $(LOVL)
+
+#
+# Make Roolz dude.
+# Due to the inadequacy of some makes these must accord with a
+# topological sort of the generated-from relation... output on
+# the left, input on the right. Trust me.
+#
+
+.SUFFIXES:  .exe .0 .1 .2 .3 .B .o .til .uu .c .y .l
+
+#
+# Rules for files in src
+#
+
+
+.c{$(OBJ)}.o:
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG)
+       $(CC) $(FLAGUO) $(COBJNAM)$@ $<
+
+{$(SRC)}.c{$(OBJ)}.o:
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG)
+       $(CC) $(FLAGUO) $(COBJNAM)$@ $<
+
+{$(SRC)}.c{$(OBJ)}.0:
+       @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG)
+       $(CC) $(FLAGU0) $(COBJNAM)$@ $<
+
+{$(SRC)}.c{$(OBJ)}.1:
+       @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG)
+       $(CC) $(FLAGU1) $(COBJNAM)$@ $<
+
+{$(SRC)}.c{$(OBJ)}.2:
+       @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG)
+       $(CC) $(FLAGU2) $(COBJNAM)$@ $<
+
+{$(SRC)}.c{$(OBJ)}.3:
+       @type schema$(SCHEMA).bc | find "$(@B)_3" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU3) >> $(VROOMMCFG)
+       $(CC) $(FLAGU3) $(COBJNAM)$@ $<
+
+{$(SRC)}.c{$(OBJ)}.B:
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG)
+       $(CC) $(FLAGUB) $(COBJNAM)$@ $<
+
+#
+# Rules for files in sys\share
+#
+
+{$(SYS)}.c{$(OBJ)}.o:
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG)
+       $(CC) $(FLAGUO) $(COBJNAM)$@ $<
+
+{$(SYS)}.c{$(OBJ)}.0:
+       @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG)
+       $(CC) $(FLAGU0) $(COBJNAM)$@ $<
+
+{$(SYS)}.c{$(OBJ)}.1:
+       @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG)
+       $(CC) $(FLAGU1) $(COBJNAM)$@ $<
+
+{$(SYS)}.c{$(OBJ)}.2:
+       @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG)
+       $(CC) $(FLAGU2) $(COBJNAM)$@ $<
+
+{$(SYS)}.c{$(OBJ)}.3:
+       @type schema$(SCHEMA).bc | find "$(@B)_3" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU3) >> $(VROOMMCFG)
+       $(CC) $(FLAGU3) $(COBJNAM)$@ $<
+
+{$(SYS)}.c{$(OBJ)}.B:
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG)
+       $(CC) $(FLAGUB) $(COBJNAM)$@ $<
+
+#
+# Rules for files in sys\msdos
+#
+
+{$(MSYS)}.c{$(OBJ)}.o:
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG)
+       $(CC) $(FLAGUO) $(COBJNAM)$@ $<
+
+{$(MSYS)}.c{$(OBJ)}.0:
+       @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG)
+       $(CC) $(FLAGU0) $(COBJNAM)$@ $<
+
+{$(MSYS)}.c{$(OBJ)}.1:
+       @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG)
+       $(CC) $(FLAGU1) $(COBJNAM)$@ $<
+
+{$(MSYS)}.c{$(OBJ)}.2:
+       @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG)
+       $(CC) $(FLAGU2) $(COBJNAM)$@ $<
+
+{$(MSYS)}.c{$(OBJ)}.3:
+       @type schema$(SCHEMA).bc | find "$(@B)_3" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU3) >> $(VROOMMCFG)
+       $(CC) $(FLAGU3) $(COBJNAM)$@ $<
+
+{$(MSYS)}.c{$(OBJ)}.B:
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG)
+       $(CC) $(FLAGUB) $(COBJNAM)$@ $<
+
+{$(MSYS)}.h{$(INCL)}.h:
+       @copy $< $@
+
+#
+# Rules for files in util
+#
+
+{$(UTIL)}.c{$(OBJ)}.o:
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) (COBJNAM)$@ $<
+
+#
+# Rules for files in win\share
+#
+
+{$(WSHR)}.c.o:
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG)
+       @$(CC) $(FLAGUO) $(COBJNAM)$@ $<
+
+{$(WSHR)}.c{$(OBJ)}.o:
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG)
+       @$(CC) $(FLAGUO) $(COBJNAM)$@ $<
+
+{$(WSHR)}.h{$(INCL)}.h:
+       @copy $< $@
+
+{$(WSHR)}.txt{$(DAT)}.txt:
+       @copy $< $@
+
+#
+# Rules for files in win\tty
+#
+
+{$(WTTY)}.c{$(OBJ)}.o:
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG)
+       $(CC) $(FLAGUO) $(COBJNAM)$@ $<
+
+{$(WTTY)}.c{$(OBJ)}.0:
+       @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG)
+       $(CC) $(FLAGU0) $(COBJNAM)$@ $<
+
+{$(WTTY)}.c{$(OBJ)}.1:
+       @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG)
+       $(CC) $(FLAGU1) $(COBJNAM)$@ $<
+
+{$(WTTY)}.c{$(OBJ)}.2:
+       @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG)
+       $(CC) $(FLAGU2) $(COBJNAM)$@ $<
+
+{$(WTTY)}.c{$(OBJ)}.3:
+       @type schema$(SCHEMA).bc | find "$(@B)_3" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU3) >> $(VROOMMCFG)
+       $(CC) $(FLAGU3) $(COBJNAM)$@ $<
+
+{$(WTTY)}.c{$(OBJ)}.B:
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG)
+       $(CC) $(FLAGUB) $(COBJNAM)$@ $<
+
+#
+# NETHACK OBJECTS
+#
+# This section creates shorthand macros for many objects
+# referenced later on in the Makefile.
+#
+
+#
+# Shorten up the location for some files
+#
+
+O  = $(OBJ)\                           # comment so \ isn't last char
+
+U  = $(UTIL)\                          # comment so \ isn't last char
+
+SPLEVDES = $(DAT)\Arch.des $(DAT)\Barb.des $(DAT)\bigroom.des \
+       $(DAT)\castle.des $(DAT)\Caveman.des $(DAT)\endgame.des \
+       $(DAT)\gehennom.des $(DAT)\Healer.des $(DAT)\Knight.des \
+       $(DAT)\knox.des $(DAT)\Monk.des $(DAT)\medusa.des \
+       $(DAT)\mines.des $(DAT)\oracle.des $(DAT)\Priest.des \
+       $(DAT)\Ranger.des $(DAT)\Rogue.des $(DAT)\Samurai.des \
+       $(DAT)\Tourist.des $(DAT)\tower.des $(DAT)\Valkyrie.des \
+       $(DAT)\Wizard.des $(DAT)\yendor.des
+
+#
+# Utility Objects.
+#
+
+MAKESRC        = $(U)makedefs.c
+
+SPLEVSRC       = $(U)lev_yacc.c        $(U)lev_$(LEX).c $(U)lev_main.c  $(U)panic.c
+
+DGNCOMPSRC     = $(U)dgn_yacc.c        $(U)dgn_$(LEX).c $(U)dgn_main.c
+
+MAKEOBJS       = $(O)makedefs.o        $(O)monst.o     $(O)objects.o
+
+SPLEVOBJS      =$(O)lev_yacc.o $(O)lev_$(LEX).o $(O)lev_main.o \
+               $(O)alloc.o $(O)decl.o $(O)drawing.o $(O)monst.o \
+               $(O)objects.o $(O)panic.o $(O)stubvid.o 
+
+DGNCOMPOBJS    =$(O)dgn_yacc.o $(O)dgn_$(LEX).o $(O)dgn_main.o \
+               $(O)alloc.o $(O)panic.o 
+
+RECOVOBJS      = $(O)recover.o
+
+GIFREADERS     =$(O)gifread.o $(O)alloc.o $(O)panic.o 
+
+TEXT_IO        =$(O)tiletext.o $(O)tiletxt.o $(O)drawing.o \
+               $(O)decl.o $(O)monst.o $(O)objects.o $(O)stubvid.o 
+
+PPMWRITERS     = $(O)ppmwrite.o        $(O)alloc.o     $(O)panic.o
+
+GIFREAD2       =$(O)gifread2.o $(O)alloc.o $(O)panic.o 
+
+TEXT_IO2       =$(O)tiletex2.o $(O)tiletxt2.o $(O)drawing.o \
+               $(O)decl.o $(O)monst.o $(O)objects.o $(O)stubvid.o 
+
+PPMWRIT2       = $(O)ppmwrit2.o $(O)alloc.o    $(O)panic.o
+
+TILEFILES      = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt
+
+TILEFILES2     = $(WSHR)\monthin.txt $(WSHR)\objthin.txt $(WSHR)\oththin.txt
+
+DLBOBJS        = $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o
+
+#
+#  Object files for the game itself.
+#
+
+OBJ01 =        $(O)alloc.o     $(RANDOM)       $(O)decl.o      $(O)objects.o   \
+       $(O)muse.o      $(O)display.o   $(O)vision.o    $(O)mapglyph.o  \
+       $(O)rect.o      $(O)vis_tab.o   $(O)monst.o     $(O)wintty.o    \
+       $(O)files.o     $(O)sys.o       $(O)monstr.o    $(O)minion.o    \
+       $(O)worm.o      $(O)detect.o    $(O)exper.o     $(O)mplayer.o   \
+       $(O)uhitm.o     $(O)pager.o     $(O)windows.o   $(O)quest.o     \
+       $(O)questpgr.o  $(O)write.o     $(O)drawing.o   $(O)dokick.o    \
+       $(O)dothrow.o   $(O)pickup.o    $(O)pray.o      $(O)spell.o     \
+       $(O)ball.o      $(O)wield.o     $(O)worn.o      $(O)fountain.o  \
+       $(O)music.o     $(O)rumors.o    $(O)dlb.o       $(O)sit.o       \
+       $(O)bones.o     $(O)mklev.o     $(O)save.o      $(O)restore.o   \
+       $(O)mkmaze.o    $(O)mkmap.o     $(O)end.o       $(O)o_init.o    \
+       $(O)options.o   $(O)rip.o       $(O)sound.o     $(O)teleport.o  \
+       $(O)topten.o    $(O)tty.o       $(O)u_init.o    $(O)extralev.o  \
+       $(O)sp_lev.o    $(O)dig.o       $(O)pckeys.o    $(O)role.o      \
+       $(O)steed.o     $(O)region.o
+
+OVL0 = $(O)allmain.0   $(O)apply.0     $(O)artifact.0  $(O)attrib.0  \
+       $(O)botl.0      $(O)cmd.0       $(O)dbridge.0   $(O)do.0      \
+       $(O)do_name.0   $(O)do_wear.0   $(O)dogmove.0   $(O)dungeon.0 \
+       $(O)eat.0       $(O)engrave.0   $(O)hacklib.0   $(O)invent.0  \
+       $(O)lock.0      $(O)pcmain.0    $(O)mail.0      $(O)makemon.0 \
+       $(O)mcastu.0    $(O)mhitm.0     $(O)mhitu.0     $(O)mkobj.0   \
+       $(O)mkroom.0    $(O)mon.0       $(O)mondata.0   $(O)monmove.0 \
+       $(O)mthrowu.0   $(O)objnam.0    $(O)polyself.0  $(O)priest.0  \
+       $(O)rnd.0       $(O)shknam.0    $(O)sounds.0    $(O)steal.0   \
+       $(O)timeout.0   $(O)track.0     $(O)trap.0      $(O)vault.0   \
+       $(O)weapon.0    $(O)were.0      $(O)wizard.0    $(O)msdos.0   \
+       $(O)termcap.0   $(O)video.0     $(O)vidtxt.0    $(O)zap.0     \
+       $(O)explode.0   $(O)shk.0
+
+OVL1 = $(O)allmain.1   $(O)apply.1     $(O)artifact.1  $(O)attrib.1 \
+       $(O)botl.1      $(O)cmd.1       $(O)dbridge.1   $(O)do.1     \
+       $(O)do_wear.1   $(O)dog.1       $(O)dungeon.1   $(O)eat.1    \
+       $(O)engrave.1   $(O)hack.1      $(O)hacklib.1   $(O)invent.1 \
+       $(O)makemon.1   $(O)mhitu.1     $(O)mkobj.1     $(O)mon.1    \
+       $(O)mondata.1   $(O)monmove.1   $(O)mthrowu.1   $(O)objnam.1 \
+       $(O)pcmain.1    $(O)polyself.1  $(O)rnd.1       $(O)shk.1    \
+       $(O)steal.1     $(O)timeout.1   $(O)track.1     $(O)trap.1   \
+       $(O)weapon.1    $(O)getline.1   $(O)termcap.1   $(O)topl.1   \
+       $(O)video.1     $(O)zap.1       $(O)explode.1
+
+OVL2 = $(O)attrib.2    $(O)do.2        $(O)do_name.2   $(O)do_wear.2 \
+       $(O)dog.2       $(O)engrave.2   $(O)hack.2      $(O)hacklib.2 \
+       $(O)invent.2    $(O)makemon.2   $(O)mon.2       $(O)mondata.2 \
+       $(O)monmove.2   $(O)getline.2   $(O)shk.2       $(O)topl.2    \
+       $(O)trap.2      $(O)zap.2
+
+OVL3 = $(O)do.3        $(O)hack.3      $(O)invent.3    $(O)light.3   \
+       $(O)shk.3       $(O)trap.3      $(O)zap.3
+
+
+OVLB = $(O)allmain.B   $(O)apply.B     $(O)artifact.B  $(O)attrib.B    \
+       $(O)botl.B      $(O)cmd.B       $(O)dbridge.B   $(O)do.B        \
+       $(O)do_name.B   $(O)do_wear.B   $(O)dog.B       $(O)dogmove.B   \
+       $(O)eat.B       $(O)engrave.B   $(O)hack.B      $(O)hacklib.B   \
+       $(O)invent.B    $(O)lock.B      $(O)mail.B      $(O)makemon.B   \
+       $(O)mcastu.B    $(O)mhitm.B     $(O)mhitu.B     $(O)mkobj.B     \
+       $(O)mkroom.B    $(O)mon.B       $(O)mondata.B   $(O)monmove.B   \
+       $(O)mthrowu.B   $(O)objnam.B    $(O)pcmain.B    $(O)pline.B     \
+       $(O)polyself.B  $(O)potion.B    $(O)priest.B    $(O)read.B      \
+       $(O)rnd.B       $(O)shk.B       $(O)shknam.B    $(O)sounds.B    \
+       $(O)steal.B     $(O)timeout.B   $(O)track.B     $(O)trap.B      \
+       $(O)vault.B     $(O)weapon.B    $(O)were.B      $(O)wizard.B    \
+       $(O)msdos.B     $(O)pcunix.B    $(O)termcap.B   $(O)topl.B      \
+       $(O)video.B     $(O)vidtxt.B    $(O)zap.B
+
+TILOBJ = $(TILEGAME) $(TILEVGA)
+
+VVOBJ =        $(O)version.o
+
+NVOBJ = $(OBJ01)       $(OVL0)         $(OVL1)         $(OVL2) \
+       $(OVL3)         $(OVLB)         $(TILOBJ)
+
+ALLOBJ= $(NVOBJ) $(VVOBJ) $(OVLINIT)
+
+#
+# Header objects
+#
+
+# This comment copied from sys/unix/Makefile.src,
+# extern.h is ignored, even though its declared function types may affect the
+# compilation of all the .c files, since extern.h changes every time the
+# type of an external function does, and we would spend all our time recompiling
+# if we did not ignore it.
+#EXTERN_H    = $(INCL)\extern.h
+EXTERN_H    =
+PCCONF_H    = $(INCL)\pcconf.h $(INCL)\micro.h $(INCL)\system.h
+PERMONST_H  = $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\align.h
+YOUPROP_H   = $(INCL)\prop.h $(PERMONST_H) $(INCL)\pm.h $(INCL)\youprop.h \
+             $(INCL)\mondata.h
+YOU_H      = $(INCL)\attrib.h $(INCL)\monst.h $(YOUPROP_H) $(INCL)\align.h
+DECL_H      = $(INCL)\quest.h $(INCL)\spell.h $(INCL)\color.h \
+             $(INCL)\obj.h $(YOU_H) $(INCL)\onames.h $(INCL)\pm.h
+
+CONFIG_H    = $(INCL)\config1.h $(INCL)\tradstdc.h $(INCL)\coord.h $(PCCONF_H) \
+             $(INCL)\config.h
+HACK_H      = $(CONFIG_H) $(INCL)\dungeon.h $(INCL)\align.h $(INCL)\monsym.h \
+              $(INCL)\mkroom.h $(INCL)\objclass.h $(DECL_H) \
+             $(INCL)\timeout.h $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \
+             $(INCL)\vision.h $(INCL)\mondata.h $(INCL)\wintype.h \
+             $(INCL)\engrave.h $(INCL)\rect.h $(EXTERN_H) \
+             $(INCL)\winprocs.h $(INCL)\trampoli.h $(INCL)\display.h
+TILE_H      = $(INCL)\tile.h $(INCL)\pctiles.h
+PCVIDEO_H   = $(INCL)\portio.h $(INCL)\pcvideo.h
+ALIGN_H     = $(INCL)\align.h
+ARTIFACT_H  = $(INCL)\artifact.h
+ARTILIST_H  = $(INCL)\artilist.h
+COLOR_H     = $(INCL)\color.h
+DATE_H      = $(INCL)\date.h
+DGN_FILE_H  = $(INCL)\dgn_file.h
+DLB_H      = $(INCL)\dlb.h
+EMIN_H      = $(INCL)\emin.h
+EPRI_H      = $(INCL)\epri.h
+ESHK_H      = $(INCL)\eshk.h
+EDOG_H      = $(INCL)\edog.h
+FUNC_TAB_H  = $(INCL)\func_tab.h
+LEV_H       = $(INCL)\lev.h
+LEV_COMP_H  = $(INCL)\lev_comp.h
+MAIL_H      = $(INCL)\mail.h
+MFNDPOS_H   = $(INCL)\mfndpos.h
+MONSYM_H    = $(INCL)\monsym.h
+OBJ_H       = $(INCL)\obj.h
+OBJCLASS_H  = $(INCL)\objclass.h
+OBJECTS_H   = $(INCL)\objects.h
+PROP_H      = $(INCL)\prop.h
+QTEXT_H     = $(INCL)\qtext.h
+QUEST_H     = $(INCL)\quest.h
+SP_LEV_H    = $(INCL)\sp_lev.h
+TERMCAP_H   = $(INCL)\tcap.h
+VAULT_H     = $(INCL)\vault.h
+VIS_TAB_H   = $(INCL)\vis_tab.h
+WINTTY_H    = $(INCL)\wintty.h
+
+#
+# In the unix distribution this file is patchlevel.h, make it 8.3 here
+# to avoid an nmake warning under dos.
+#
+
+PATCHLEVEL_H   = $(INCL)\patchlev.h
+
+
+#
+#  The name of the game.
+#
+
+GAMEFILE = $(GAMEDIR)\$(GAME).exe
+
+#
+# make data.base an 8.3 filename to prevent an nmake warning
+#
+
+DATABASE = $(DAT)\data.bas
+
+#######################################################################
+#
+#  TARGETS
+
+#
+#  The main target.
+#
+
+$(GAME): obj.tag envchk $(U)utility.tag $(GAMEFILE)
+       @echo $(GAME) is up to date.
+
+#
+#  Everything
+#
+
+all :  install
+
+install: $(GAME) install.tag
+       @echo Done.
+
+
+install.tag:   $(DAT)\data     $(DAT)\rumors   $(DAT)\dungeon \
+               $(DAT)\oracles  $(DAT)\quest.dat $(DAT)\sp_lev.tag $(DLB)
+! IF ("$(USE_DLB)"=="Y")
+       copy nhdat                $(GAMEDIR)
+       copy $(DAT)\license       $(GAMEDIR)
+! ELSE
+       copy $(DAT)\*.            $(GAMEDIR)
+       copy $(DAT)\*.dat         $(GAMEDIR)
+       copy $(DAT)\*.lev         $(GAMEDIR)
+       copy $(MSYS)\msdoshlp.txt $(GAMEDIR)
+       if exist $(GAMEDIR)\makefile del $(GAMEDIR)\makefile
+! ENDIF
+       copy $(SYS)\termcap       $(GAMEDIR)
+       if exist $(DOC)\guideb*.txt copy $(DOC)\guideb*.txt  $(GAMEDIR)
+       if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt  $(GAMEDIR)\NetHack.txt
+       if exist $(DOC)\recover.txt copy $(DOC)\recover.txt  $(GAMEDIR)
+       copy $(SYS)\NetHack.cnf   $(GAMEDIR)\defaults.nh
+       copy $(MSYS)\NHAccess.nh  $(GAMEDIR)
+       copy $(U)recover.exe  $(GAMEDIR)
+       if exist *.tib copy *.tib $(GAMEDIR)
+       echo install done > $@
+
+$(DAT)\sp_lev.tag: $(U)utility.tag $(SPLEVDES)
+       cd $(DAT)
+       $(U)lev_comp bigroom.des
+       $(U)lev_comp castle.des
+       $(U)lev_comp endgame.des
+       $(U)lev_comp gehennom.des
+       $(U)lev_comp knox.des
+       $(U)lev_comp mines.des
+       $(U)lev_comp medusa.des
+       $(U)lev_comp oracle.des
+       $(U)lev_comp sokoban.des
+       $(U)lev_comp tower.des
+       $(U)lev_comp yendor.des
+       $(U)lev_comp arch.des
+       $(U)lev_comp barb.des
+       $(U)lev_comp caveman.des
+       $(U)lev_comp healer.des
+       $(U)lev_comp knight.des
+       $(U)lev_comp monk.des
+       $(U)lev_comp priest.des
+       $(U)lev_comp ranger.des
+       $(U)lev_comp rogue.des
+       $(U)lev_comp samurai.des
+       $(U)lev_comp tourist.des
+       $(U)lev_comp valkyrie.des
+       $(U)lev_comp wizard.des
+       cd $(SRC)
+       echo sp_levs done > $(DAT)\sp_lev.tag
+
+$(U)utility.tag: envchk                        $(INCL)\date.h  $(INCL)\onames.h \
+               $(INCL)\pm.h            $(SRC)\monstr.c $(SRC)\vis_tab.c \
+               $(U)lev_comp.exe        $(VIS_TAB_H)    $(U)dgn_comp.exe \
+               $(U)recover.exe         $(TILEUTIL)
+             @echo utilities made >$@
+            @echo utilities made.
+
+tileutil: $(U)gif2txt.exe $(U)txt2ppm.exe
+       @echo Optional tile development utilities are up to date.
+
+#
+#  Inline files :
+#                      Specifying the "<<" means to start an inline file.
+#                      Another "<<" at the start of a line closes the
+#                      inline file.
+#
+#  DO NOT INDENT THE << below!
+#
+
+$(GAMEFILE) :  $(ALLOBJ)
+       @echo Linking....
+       $(LINK) $(LFLAGSN) @<<$(GAME).lnk
+               $(ALLOBJ)
+               $(GAMEFILE)
+               $(GAME)
+               $(TERMLIB) $(MOVETR) $(CLIB) $(BCOVL) $(BCMDL)
+<<
+       @if exist $(GAMEDIR)\$(GAME).bak del $(GAMEDIR)\$(GAME).bak
+
+#
+# Makedefs Stuff
+#
+
+$(U)makedefs.exe:      $(MAKEOBJS)
+       @$(LINK) $(LFLAGSU) $(MAKEOBJS), $@,, $(CLIB) $(BCMDL);
+
+$(O)makedefs.o: $(CONFIG_H)        $(PERMONST_H)      $(OBJCLASS_H) \
+                $(MONSYM_H)    $(QTEXT_H)      $(PATCHLEVEL_H) \
+                $(U)makedefs.c
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)makedefs.c
+
+#
+#  date.h should be remade every time any of the source or include
+#  files is modified.
+#
+
+$(INCL)\date.h : $(U)makedefs.exe
+       $(U)makedefs -v
+       @echo A new $@ has been created.
+
+$(INCL)\onames.h : $(U)makedefs.exe
+       $(U)makedefs -o
+
+$(INCL)\pm.h : $(U)makedefs.exe
+       $(U)makedefs -p
+
+#$(INCL)\trap.h : $(U)makedefs.exe
+#      $(U)makedefs -t
+
+$(SRC)\monstr.c: $(U)makedefs.exe
+       $(U)makedefs -m
+
+$(INCL)\vis_tab.h: $(U)makedefs.exe
+       $(U)makedefs -z
+
+$(SRC)\vis_tab.c: $(U)makedefs.exe
+       $(U)makedefs -z
+
+#
+# Level Compiler Stuff
+#
+
+$(U)lev_comp.exe:  $(SPLEVOBJS)
+       @echo Linking $@...
+       $(LINK) $(LFLAGSU) @&&!
+               $(O)stubvid.o $(O)panic.o $(O)objects.o $(O)monst.o +
+               $(O)drawing.o $(O)decl.o $(O)alloc.o $(O)lev_main.o +
+               $(O)lev_$(LEX).o $(O)lev_yacc.o 
+               $@
+               $(@B)
+               $(BCMDL);
+!
+
+$(O)lev_yacc.o:  $(HACK_H)   $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)lev_yacc.c
+
+$(O)lev_$(LEX).o:  $(HACK_H)   $(INCL)\lev_comp.h $(SP_LEV_H) \
+       $(U)lev_$(LEX).c
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)lev_$(LEX).c
+
+$(O)lev_main.o:        $(U)lev_main.c $(HACK_H)   $(SP_LEV_H)
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)lev_main.c
+
+$(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y
+!      IF "$(DO_YACC)"=="YACC_ACT"
+          $(YACC) -d -l $(U)lev_comp.y
+          copy $(YTABC) $(U)lev_yacc.c
+          copy $(YTABH) $(INCL)\lev_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+!      ELSE
+          @echo.
+          @echo $(U)lev_comp.y has changed.
+          @echo To update $(U)lev_yacc.c and $(INCL)\lev_comp.h run $(YACC).
+          @echo.
+          @echo For now, we will copy the prebuilt lev_yacc.c
+          @echo from $(SYS) to $(U)lev_yacc.c, and copy the prebuilt
+          @echo lev_comp.h from $(SYS) to $(UTIL)\lev_comp.h
+          @echo and use those.
+          @echo.
+          copy $(SYS)\lev_yacc.c $@ >nul
+          touch $@
+          copy $(SYS)\lev_comp.h $(INCL)\lev_comp.h >nul
+          touch $(INCL)\lev_comp.h
+!      ENDIF
+
+$(U)lev_$(LEX).c:  $(U)lev_comp.l
+!      IF "$(DO_LEX)"=="LEX_ACT"
+          $(LEX) $(FLEXSKEL) $(U)lev_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+!      ELSE
+          @echo.
+          @echo $(U)lev_comp.l has changed. To update $@ run $(LEX).
+          @echo.
+          @echo For now, we will copy a prebuilt lev_lex.c
+          @echo from $(SYS) to $@ and use it.
+          @echo.
+          copy $(SYS)\lev_lex.c $@ >nul
+          touch $@
+!      ENDIF
+
+#
+# Dungeon Stuff
+#
+
+$(U)dgn_comp.exe: $(DGNCOMPOBJS)
+    @echo Linking $@...
+       $(LINK) $(LFLAGSU) @&&!
+               $(O)panic.o $(O)alloc.o $(O)dgn_main.o $(O)dgn_$(LEX).o +
+               $(O)dgn_yacc.o 
+               $@
+               $(@B)
+               $(BCMDL);
+!
+
+$(O)dgn_yacc.o:        $(HACK_H)   $(DGN_FILE_H) $(INCL)\dgn_comp.h \
+       $(U)dgn_yacc.c
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)dgn_yacc.c
+
+$(O)dgn_$(LEX).o: $(HACK_H)   $(DGN_FILE_H)  $(INCL)\dgn_comp.h \
+       $(U)dgn_$(LEX).c
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)dgn_$(LEX).c
+
+$(O)dgn_main.o:        $(HACK_H) $(U)dgn_main.c
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)dgn_main.c
+
+$(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y
+!      IF "$(DO_YACC)"=="YACC_ACT"
+          $(YACC) -d -l $(U)dgn_comp.y
+          copy $(YTABC) $(U)dgn_yacc.c
+          copy $(YTABH) $(INCL)\dgn_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+!      ELSE
+          @echo.
+          @echo $(U)dgn_comp.y has changed. To update $@ and
+          @echo $(INCL)\dgn_comp.h run $(YACC).
+          @echo.
+          @echo For now, we will copy the prebuilt dgn_yacc.c from
+          @echo $(SYS) to $(U)dgn_yacc.c, and copy the prebuilt
+          @echo dgn_comp.h from $(SYS) to $(INCL)\dgn_comp.h
+          @echo and use those.
+          @echo.
+          copy $(SYS)\dgn_yacc.c $@ >nul
+          touch $@
+          copy $(SYS)\dgn_comp.h $(INCL)\dgn_comp.h >nul
+          touch $(INCL)\dgn_comp.h
+!      ENDIF
+
+$(U)dgn_$(LEX).c:  $(U)dgn_comp.l
+!      IF "$(DO_LEX)"=="LEX_ACT"
+          $(LEX) $(FLEXSKEL)  $(U)dgn_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+!      ELSE
+          @echo.
+          @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX).
+          @echo.
+          @echo For now, we will copy a prebuilt dgn_lex.c
+          @echo from $(SYS) to $@ and use it.
+          @echo.
+          copy $(SYS)\dgn_lex.c $@ >nul
+          touch $@
+!      ENDIF
+
+
+obj.tag:
+       @if not exist $(O)*.* mkdir $(OBJ)
+       @echo directory $(OBJ) created
+       @echo directory $(OBJ) created >$@
+
+envchk: precomp.msg
+!      IF "$(TILEGAME)"==""
+          @echo.
+          @echo NOTE: This build will NOT include tile support.
+          @echo.
+!      ELSE
+          @echo.
+          @echo This build includes tile support.
+          @echo.
+!      ENDIF
+
+#
+# SECONDARY TARGETS
+#
+
+#
+# Header files NOT distributed in ..\include
+#
+
+$(INCL)\tile.h: $(WSHR)\tile.h
+       copy $(WSHR)\tile.h $@
+
+$(INCL)\pctiles.h: $(MSYS)\pctiles.h
+       copy $(MSYS)\pctiles.h $@
+
+$(INCL)\pcvideo.h: $(MSYS)\pcvideo.h
+       copy $(MSYS)\pcvideo.h $@
+
+$(INCL)\portio.h: $(MSYS)\portio.h
+       copy $(MSYS)\portio.h $@
+
+#
+#  Recover Utility
+#
+
+$(U)recover.exe: $(RECOVOBJS)
+       @$(LINK) $(LFLAGSU) $(RECOVOBJS),$@,, $(CLIB) $(BCMDL);
+
+#
+#  Tile Mapping
+#
+
+$(SRC)\tile.c: $(U)tilemap.exe
+       @echo A new $@ is being created.
+       @$(U)tilemap
+
+$(U)tilemap.exe: $(O)tilemap.o
+       @$(LINK) $(LFLAGSU) $(O)tilemap.o,$@,, $(CLIB) $(BCMDL);
+
+$(O)tilemap.o:  $(WSHR)\tilemap.c $(HACK_H)
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\tilemap.c
+
+
+#
+# Tile Utilities
+#
+
+#
+#  Optional (for development)
+#
+
+
+
+#
+
+$(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO)
+       @$(LINK) $(LFLAGSU) << $(@B).lnk
+               $(GIFREADERS) $(TEXT_IO)
+               $@,,$(CLIB) $(BCMDL)
+<<
+
+$(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO)
+       @$(LINK) $(LFLAGSU) << $(@B).lnk
+               $(PPMWRITERS) $(TEXT_IO)
+               $@,,$(CLIB) $(BCMDL);
+<<
+
+$(U)gif2txt2.exe: $(GIFREAD2) $(TEXT_IO2)
+       @$(LINK) $(LFLAGSU) << $(@B).lnk
+               $(GIFREAD2) $(TEXT_IO2)
+               $@,,$(CLIB) $(BCMDL);
+<<
+
+$(U)txt2ppm2.exe: $(PPMWRIT2) $(TEXT_IO2)
+       @$(LINK) $(LFLAGSU) << $(@B).lnk
+               $(PPMWRIT2) $(TEXT_IO2)
+               $@,,$(CLIB) $(BCMDL);
+<<
+
+#
+#  Required for tile support
+#
+
+NetHack1.tib: $(TILEFILES) $(U)tile2bin.exe
+       @echo Creating binary tile files (this may take some time)
+       @$(U)tile2bin
+
+NetHackO.tib: thintile.tag $(TILEFILES2) $(U)til2bin2.exe
+       @echo Creating overview binary tile files (this may take some time)
+       @$(U)til2bin2
+
+thintile.tag: $(U)thintile.exe $(TILEFILES)
+       $(U)thintile
+       @echo thintiles created >thintile.tag
+
+$(U)tile2bin.exe: $(O)tile2bin.o $(TEXT_IO)
+    @echo Linking $@...
+       $(LINK) $(LFLAGSU) @&&!
+               $(O)tile2bin.o+
+               $(O)stubvid.o $(O)objects.o $(O)monst.o $(O)decl.o +
+               $(O)drawing.o $(O)tiletxt.o $(O)tiletext.o 
+               $@
+               $(@B)
+               $(BCMDL);
+!
+
+$(U)til2bin2.exe: $(O)til2bin2.o $(TEXT_IO2)
+    @echo Linking $@...
+       $(LINK) $(LFLAGSU) @&&!
+               $(O)til2bin2.o+
+               $(O)stubvid.o $(O)objects.o $(O)monst.o $(O)decl.o +
+               $(O)drawing.o $(O)tiletxt2.o $(O)tiletex2.o 
+               $@
+               $(@B)
+               $(BCMDL);
+!
+
+
+$(U)thintile.exe: $(O)thintile.o
+       @$(LINK) $(LFLAGSU) $(O)thintile.o,$@,, $(CLIB) $(BCMDL);
+
+$(O)thintile.o:  $(HACK_H) $(INCL)\tile.h $(WSHR)\thintile.c
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\thintile.c
+
+$(O)tile2bin.o:  $(HACK_H) $(TILE_H) $(PCVIDEO_H)
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(COBJNAM)$@ $(MSYS)\tile2bin.c
+
+$(O)til2bin2.o:  $(HACK_H) $(TILE_H) $(PCVIDEO_H)
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(CDEFINE)TILE_X=8 $(CDEFINE)OVERVIEW_FILE \
+               $(COBJNAM)$@ $(MSYS)\tile2bin.c
+
+
+#
+# DLB stuff
+#
+
+nhdat: $(U)dlb_main.exe
+       @copy $(MSYS)\msdoshlp.txt $(DAT)
+       @cd $(DAT)
+       @echo data >dlb.lst
+       @echo oracles >>dlb.lst
+       @echo options >>dlb.lst
+       @echo quest.dat >>dlb.lst
+       @echo rumors >>dlb.lst
+       @echo help >>dlb.lst
+       @echo hh >>dlb.lst
+       @echo cmdhelp >>dlb.lst
+       @echo history >>dlb.lst
+       @echo opthelp >>dlb.lst
+       @echo wizhelp >>dlb.lst
+       @echo dungeon >>dlb.lst
+       @echo license >>dlb.lst
+       @echo msdoshlp.txt >>dlb.lst
+       @for %%N in (*.lev) do echo %%N >>dlb.lst
+       $(U)dlb_main cvIf dlb.lst $(SRC)\nhdat
+       @cd $(SRC)
+
+$(U)dlb_main.exe: $(DLBOBJS)
+       @$(LINK) $(LFLAGSU) $(DLBOBJS),$@,, $(CLIB) $(BCMDL);
+
+$(O)dlb_main.o: $(U)dlb_main.c $(INCL)\config.h $(DLB_H)
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)dlb_main.c
+
+#
+# Housekeeping
+#
+
+spotless: clean
+       rmdir $(OBJ)
+       if exist $(DATE_H)    del $(DATE_H)
+       if exist $(INCL)\onames.h  del $(INCL)\onames.h
+       if exist $(INCL)\pm.h      del $(INCL)\pm.h
+       if exist $(VIS_TAB_H) del $(VIS_TAB_H)
+       if exist $(SRC)\vis_tab.c  del $(SRC)\vis_tab.c
+       if exist $(SRC)\tile.c     del $(SRC)\tile.c
+       if exist $(DAT)\rumors     del $(DAT)\rumors
+       if exist $(DAT)\data            del $(DAT)\data
+       if exist $(DAT)\dungeon         del $(DAT)\dungeon
+       if exist $(DAT)\dungeon.pdf     del $(DAT)\dungeon.pdf
+       if exist $(DAT)\options         del $(DAT)\options
+       if exist $(DAT)\oracles         del $(DAT)\oracles
+       if exist $(DAT)\rumors          del $(DAT)\rumors
+       if exist $(DAT)\quest.dat       del $(DAT)\quest.dat
+       if exist $(DAT)\*.lev           del $(DAT)\*.lev
+       if exist $(DAT)\sp_lev.tag      del $(DAT)\sp_lev.tag
+       if exist $(SRC)\monstr.c        del $(SRC)\monstr.c
+       if exist $(SRC)\vis_tab.c       del $(SRC)\vis_tab.c
+       if exist $(SRC)\$(PLANAR_TIB)   del $(SRC)\$(PLANAR_TIB)
+       if exist $(SRC)\$(OVERVIEW_TIB) del $(SRC)\$(OVERVIEW_TIB)
+       if exist $(U)recover.exe        del $(U)recover.exe
+
+clean:
+       if exist $(O)*.o del $(O)*.o
+       if exist $(O)*.0 del $(O)*.0
+       if exist $(O)*.1 del $(O)*.1
+       if exist $(O)*.2 del $(O)*.2
+       if exist $(O)*.3 del $(O)*.3
+       if exist $(O)*.b del $(O)*.b
+       if exist $(U)utility.tag   del $(U)utility.tag
+       if exist $(U)makedefs.exe  del $(U)makedefs.exe
+       if exist $(U)lev_comp.exe  del $(U)lev_comp.exe
+       if exist $(U)dgn_comp.exe  del $(U)dgn_comp.exe
+       if exist $(U)dlb_main.exe  del $(U)dlb_main.exe
+       if exist $(SRC)\*.lnk      del $(SRC)\*.lnk
+       if exist $(SRC)\*.map      del $(SRC)\*.map
+       if exist $(SRC)\*$(CPCHEXT) del $(SRC)\*$(CPCHEXT)
+       if exist $(SRC)\*.cfg      del $(SRC)\*.cfg
+       if exist $(DAT)\dlb.lst    del $(DAT)\dlb.lst
+
+pch.c: $(HACK_H)
+       @echo ^#include "hack.h" > $@
+       @echo main(int argc, char *argv[]) >> $@
+       @echo { >> $@
+       @echo } >> $@
+       @echo. >> $@
+
+#
+# OTHER DEPENDENCIES
+#
+
+#
+# Precompiled Header dependencies
+# (We need to force the generation of these at the beginning)
+#
+
+PHO$(CPCHEXT): $(HACK_H) pch.c
+       @echo Generating new precompiled header for .O files
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGCO) >> $(VROOMMCFG)
+       @$(CC) $(FLAGCO) pch.c
+PH0$(CPCHEXT): $(HACK_H) pch.c
+       @echo Generating new precompiled header for .0 files
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGC0) >> $(VROOMMCFG)
+       @$(CC) $(FLAGC0) pch.c
+PH1$(CPCHEXT): $(HACK_H) pch.c
+       @echo Generating new precompiled header for .1 files
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGC1) >> $(VROOMMCFG)
+       @$(CC) $(FLAGC1) pch.c
+PH2$(CPCHEXT): $(HACK_H) pch.c
+       @echo Generating new precompiled header for .2 files
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGC2) >> $(VROOMMCFG)
+       @$(CC) $(FLAGC2) pch.c
+PH3$(CPCHEXT): $(HACK_H) pch.c
+       @echo Generating new precompiled header for .3 files
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGC3) >> $(VROOMMCFG)
+       @$(CC) $(FLAGC3) pch.c
+PHB$(CPCHEXT): $(HACK_H) pch.c
+       @echo Generating new precompiled header for .B files
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGCB) >> $(VROOMMCFG)
+       @$(CC) $(FLAGCB) pch.c
+
+
+# Overlay initialization routines used by pcmain() at startup to
+# determine EMS/XMS memory usage.
+
+# Comment out the following line if you don't want Borland C++ to check for
+# extended memory.
+RECOGNIZE_XMS = $(CDEFINE)RECOGNIZE_XMS
+
+
+$(O)ovlinit.o: $(MSYS)\ovlinit.c $(HACK_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(RECOGNIZE_XMS) $(COBJNAM)$@ $(MSYS)\ovlinit.c
+
+#
+# dat dependencies
+#
+
+$(DAT)\data: $(U)utility.tag    $(DATABASE)
+       $(U)makedefs -d
+
+$(DAT)\rumors: $(U)utility.tag    $(DAT)\rumors.tru   $(DAT)\rumors.fal
+       $(U)makedefs -r
+
+$(DAT)\quest.dat: $(U)utility.tag  $(DAT)\quest.txt
+       $(U)makedefs -q
+
+$(DAT)\oracles: $(U)utility.tag    $(DAT)\oracles.txt
+       $(U)makedefs -h
+
+$(DAT)\dungeon: $(U)utility.tag  $(DAT)\dungeon.def
+       $(U)makedefs -e
+       cd $(DAT)
+       $(U)dgn_comp dungeon.pdf
+       cd $(SRC)
+
+#
+#  Util Dependencies.
+#
+
+$(O)panic.o:   $(U)panic.c $(CONFIG_H)
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)panic.c
+
+$(O)recover.o: $(CONFIG_H) $(U)recover.c
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)recover.c
+
+#
+#  from win\share
+#
+
+$(O)tiletxt.o:  $(WSHR)\tilemap.c $(HACK_H)
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(CDEFINE)TILETEXT $(COBJNAM)$@ $(WSHR)\tilemap.c
+
+$(O)tiletxt2.o:  $(WSHR)\tilemap.c $(HACK_H)
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(CDEFINE)TILETEXT \
+               $(CDEFINE)TILE_X=8 $(COBJNAM)$@ $(WSHR)\tilemap.c
+
+$(O)gifread.o:  $(WSHR)\gifread.c  $(CONFIG_H) $(INCL)\tile.h
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\gifread.c
+
+$(O)gifread2.o:  $(WSHR)\gifread.c  $(CONFIG_H) $(INCL)\tile.h
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(COBJNAM)$@ $(CDEFINE)TILE_X=8 $(WSHR)\gifread.c
+
+$(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(INCL)\tile.h
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\ppmwrite.c
+
+$(O)ppmwrit2.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(INCL)\tile.h
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(COBJNAM)$@ $(CDEFINE)TILE_X=8 $(WSHR)\ppmwrite.c
+
+$(O)tiletext.o:   $(WSHR)\tiletext.c  $(CONFIG_H) $(INCL)\tile.h
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\tiletext.c
+
+$(O)tiletex2.o:   $(WSHR)\tiletext.c  $(CONFIG_H) $(INCL)\tile.h
+       @echo $(BCOPTS1) > $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSU) $(CDEFINE)TILE_X=8 $(COBJNAM)$@ $(WSHR)\tiletext.c
+
+#
+#  from win\tty
+#
+
+$(O)getline.1:  $(PCH1) $(WTTY)\getline.c  $(HACK_H) $(WINTTY_H) $(FUNC_TAB_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG)
+       $(CC) $(FLAGU1) $(COBJNAM)$@ $(WTTY)\getline.c
+
+$(O)getline.2:  $(PCH2) $(WTTY)\getline.c  $(HACK_H) $(WINTTY_H) $(FUNC_TAB_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG)
+       $(CC) $(FLAGU2) $(COBJNAM)$@ $(WTTY)\getline.c
+
+$(O)termcap.0:  $(PCH0) $(WTTY)\termcap.c  $(HACK_H) $(WINTTY_H) $(TERMCAP_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG)
+       $(CC) $(FLAGU0) $(COBJNAM)$@ $(WTTY)\termcap.c
+
+$(O)termcap.1:  $(PCH1) $(WTTY)\termcap.c  $(HACK_H) $(WINTTY_H) $(TERMCAP_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG)
+       $(CC) $(FLAGU1) $(COBJNAM)$@ $(WTTY)\termcap.c
+
+$(O)termcap.B:  $(PCHB) $(WTTY)\termcap.c  $(HACK_H) $(WINTTY_H) $(TERMCAP_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG)
+       $(CC) $(FLAGUB) $(COBJNAM)$@ $(WTTY)\termcap.c
+
+$(O)topl.1:     $(PCH1) $(WTTY)\topl.c     $(HACK_H) $(TERMCAP_H) $(WINTTY_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG)
+       $(CC) $(FLAGU1) $(COBJNAM)$@ $(WTTY)\topl.c
+
+$(O)topl.2:     $(PCH2) $(WTTY)\topl.c     $(HACK_H) $(TERMCAP_H) $(WINTTY_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG)
+       $(CC) $(FLAGU2) $(COBJNAM)$@ $(WTTY)\topl.c
+
+$(O)topl.B:     $(PCHB) $(WTTY)\topl.c     $(HACK_H) $(TERMCAP_H) $(WINTTY_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG)
+       $(CC) $(FLAGUB) $(COBJNAM)$@ $(WTTY)\topl.c
+
+$(O)wintty.o: $(PCHO) $(CONFIG_H) $(WTTY)\wintty.c $(PATCHLEVEL_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG)
+       $(CC) $(FLAGUO) $(COBJNAM)$@ $(WTTY)\wintty.c
+
+#
+# from sys\share
+#
+
+$(O)pcmain.0:   $(PCH0) $(HACK_H) $(SYS)\pcmain.c
+       @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG)
+       $(CC)  $(FLAGU0) $(COBJNAM)$@ $(SYS)\pcmain.c
+
+$(O)pcmain.1:   $(PCH1) $(HACK_H) $(SYS)\pcmain.c
+       @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG)
+       $(CC)  $(FLAGU1) $(COBJNAM)$@ $(SYS)\pcmain.c
+
+$(O)pcmain.B:   $(PCHB) $(HACK_H) $(SYS)\pcmain.c
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG)
+       $(CC)  $(FLAGUB) $(COBJNAM)$@ $(SYS)\pcmain.c
+
+$(O)pcunix.B:   $(PCHB) $(SYS)\pcunix.c   $(HACK_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG)
+       $(CC) $(FLAGUB) $(COBJNAM)$@ $(SYS)\pcunix.c
+
+$(O)tty.o:     $(HACK_H) $(WINTTY_H) $(SYS)\pctty.c
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC)  $(CFLAGSN) $(COBJNAM)$@  $(SYS)\pctty.c
+
+$(O)sys.o:    $(HACK_H) $(SYS)\pcsys.c
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC)  $(CFLAGSN) $(COBJNAM)$@ $(SYS)\pcsys.c
+
+$(O)random.o: $(PCHO) $(HACK_H) $(SYS)\random.c
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG)
+       $(CC) $(FLAGUO) $(COBJNAM)$@ $(SYS)\random.c
+
+#
+# from sys\msdos
+#
+
+$(O)msdos.0: $(MSYS)\msdos.c   $(HACK_H) $(PCVIDEO_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COVL0) $(COBJNAM)$@ $(MSYS)\msdos.c
+
+$(O)msdos.B: $(MSYS)\msdos.c   $(HACK_H) $(PCVIDEO_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2)  >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COVLB) $(COBJNAM)$@ $(MSYS)\msdos.c
+
+$(O)pctiles.0: $(PCH0) $(MSYS)\pctiles.c $(HACK_H) $(TILE_H) $(PCVIDEO_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG)
+       $(CC) $(FLAGU0) $(COBJNAM)$@ $(MSYS)\pctiles.c
+
+$(O)pctiles.B: $(PCHB) $(MSYS)\pctiles.c $(HACK_H) $(TILE_H) $(PCVIDEO_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG)
+       $(CC) $(FLAGUB) $(COBJNAM)$@ $(MSYS)\pctiles.c
+
+$(O)sound.o: $(PCH0) $(MSYS)\sound.c   $(HACK_H) $(INCL)\portio.h
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG)
+       $(CC) $(FLAGUO) $(COBJNAM)$@ $(MSYS)\sound.c
+
+$(O)pckeys.o: $(PCHO) $(MSYS)\pckeys.c   $(HACK_H) $(PCVIDEO_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG)
+       $(CC) $(FLAGUO) $(COBJNAM)$@ $(MSYS)\pckeys.c
+
+$(O)stubvid.o : $(MSYS)\video.c $(HACK_H)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG)
+       $(CC) $(FLAGUO) $(CDEFINE)STUBVIDEO $(COBJNAM)$@ $(MSYS)\video.c
+
+$(O)video.0: $(PCH0) $(MSYS)\video.c   $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \
+                $(TILE_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG)
+       $(CC) $(FLAGU0) $(COBJNAM)$@ $(MSYS)\video.c
+
+$(O)video.1: $(PCH1) $(MSYS)\video.c   $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \
+                $(TILE_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG)
+       $(CC) $(FLAGU1) $(COBJNAM)$@ $(MSYS)\video.c
+
+$(O)video.B: $(PCHB) $(MSYS)\video.c   $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \
+                $(TILE_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG)
+       $(CC) $(FLAGUB) $(COBJNAM)$@ $(MSYS)\video.c
+
+$(O)vidtxt.0: $(MSYS)\vidtxt.c  $(HACK_H) $(WINTTY_H) $(PCVIDEO_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COVL0) $(COBJNAM)$@ $(MSYS)\vidtxt.c
+
+$(O)vidtxt.B: $(MSYS)\vidtxt.c  $(HACK_H) $(WINTTY_H) $(PCVIDEO_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COVLB) $(COBJNAM)$@ $(MSYS)\vidtxt.c
+
+$(O)vidvga.0: $(PCH0) $(MSYS)\vidvga.c  $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \
+               $(TILE_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG)
+       $(CC) $(FLAGU0) $(COBJNAM)$@ $(MSYS)\vidvga.c
+
+$(O)vidvga.1: $(PCH1) $(MSYS)\vidvga.c  $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \
+               $(TILE_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG)
+       $(CC) $(FLAGU1) $(COBJNAM)$@ $(MSYS)\vidvga.c
+
+$(O)vidvga.2: $(PCH2) $(MSYS)\vidvga.c  $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \
+               $(TILE_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG)
+       $(CC) $(FLAGU2) $(COBJNAM)$@ $(MSYS)\vidvga.c
+
+$(O)vidvga.B: $(PCHB) $(MSYS)\vidvga.c  $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \
+               $(TILE_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG)
+       $(CC) $(FLAGUB) $(COBJNAM)$@ $(MSYS)\vidvga.c
+
+#
+# from src
+#
+
+$(O)alloc.o:     $(SRC)\alloc.c    $(CONFIG_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\alloc.c
+$(O)ball.o:      $(PCHO) $(SRC)\ball.c     $(HACK_H)
+$(O)bones.o:     $(PCHO) $(SRC)\bones.c    $(HACK_H) $(LEV_H)
+$(O)decl.o:      $(PCHO) $(SRC)\decl.c     $(HACK_H) $(QUEST_H)
+$(O)detect.o:    $(PCHO) $(SRC)\detect.c   $(HACK_H) $(ARTIFACT_H)
+$(O)dig.o:      $(PCHO) $(SRC)\dig.c      $(HACK_H) $(EDOG_H) # check dep
+$(O)display.o:  $(PCHO) $(SRC)\display.c  $(HACK_H)
+$(O)dlb.o:      $(SRC)\dlb.c      $(DLB_H) $(HACK_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\dlb.c
+$(O)dokick.o:    $(PCHO) $(SRC)\dokick.c   $(HACK_H) $(ESHK_H)
+$(O)dothrow.o:   $(PCHO) $(SRC)\dothrow.c  $(HACK_H)
+$(O)drawing.o:   $(SRC)\drawing.c  $(HACK_H) $(TERMCAP_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\drawing.c
+$(O)end.o:       $(SRC)\end.c      $(HACK_H) $(ESHK_H) $(DLB_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\end.c
+$(O)exper.o:     $(PCHO) $(SRC)\exper.c    $(HACK_H)
+$(O)extralev.o:  $(PCHO) $(SRC)\extralev.c $(HACK_H)
+$(O)files.o:    $(PCHO) $(SRC)\files.c    $(HACK_H) $(DLB_H)
+$(O)fountain.o:  $(PCHO) $(SRC)\fountain.c $(HACK_H)
+$(O)mapglyph.o:  $(PCHO) $(SRC)\mapglyph.c $(HACK_H)
+$(O)minion.o:    $(PCHO) $(SRC)\minion.c   $(HACK_H) $(EMIN_H) $(EPRI_H)
+$(O)mklev.o:     $(PCHO) $(SRC)\mklev.c    $(HACK_H)
+$(O)mkmap.o:     $(PCHO) $(SRC)\mkmap.c    $(HACK_H) $(SP_LEV_H)
+$(O)mkmaze.o:   $(PCHO) $(SRC)\mkmaze.c   $(HACK_H) $(SP_LEV_H) $(LEV_H)
+$(O)monst.o:     $(SRC)\monst.c    $(CONFIG_H) $(PERMONST_H) $(MONSYM_H) \
+                $(ESHK_H) $(EPRI_H) $(COLOR_H) $(ALIGN_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\monst.c
+$(O)monstr.o:    $(SRC)\monstr.c   $(CONFIG_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\monstr.c
+$(O)mplayer.o:   $(PCHO) $(SRC)\mplayer.c  $(HACK_H)
+$(O)muse.o:      $(PCHO) $(SRC)\muse.c     $(HACK_H)
+$(O)music.o:     $(PCHO) $(SRC)\music.c    $(HACK_H)
+$(O)o_init.o:   $(PCHO) $(SRC)\o_init.c   $(HACK_H) $(LEV_H)
+$(O)objects.o:   $(SRC)\objects.c  $(CONFIG_H) $(OBJ_H) $(OBJCLASS_H) \
+                 $(PROP_H) $(COLOR_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\objects.c
+$(O)options.o:  $(SRC)\options.c  $(HACK_H) $(TERMCAP_H) $(OBJCLASS_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\options.c
+$(O)pager.o:    $(SRC)\pager.c    $(HACK_H) $(DLB_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGNO) $(COBJNAM)$@ $(SRC)\pager.c
+$(O)pickup.o:    $(PCHO) $(SRC)\pickup.c   $(HACK_H)
+$(O)pray.o:      $(PCHO) $(SRC)\pray.c     $(HACK_H) $(EPRI_H)
+$(O)quest.o:     $(PCHO) $(SRC)\quest.c    $(HACK_H) $(QUEST_H) $(QTEXT_H)
+$(O)questpgr.o:  $(PCHO) $(SRC)\questpgr.c $(HACK_H) $(QTEXT_H) $(DLB_H)
+$(O)rect.o:      $(PCHO) $(SRC)\rect.c     $(HACK_H)
+$(O)region.o:    $(PCHO) $(SRC)\region.c   $(HACK_H)
+$(O)restore.o:   $(PCHO) $(SRC)\restore.c  $(HACK_H) $(LEV_H) $(TERMCAP_H) \
+                $(QUEST_H)
+$(O)rip.o:       $(PCHO) $(SRC)\rip.c      $(HACK_H)
+$(O)role.o:       $(PCHO) $(SRC)\role.c     $(HACK_H)
+$(O)rumors.o:   $(PCHO) $(SRC)\rumors.c   $(HACK_H) $(DLB_H)
+$(O)save.o:      $(PCHO) $(SRC)\save.c     $(HACK_H) $(LEV_H) $(QUEST_H)
+$(O)sit.o:       $(PCHO) $(SRC)\sit.c      $(HACK_H) $(ARTIFACT_H)
+$(O)steed.o:      $(PCHO) $(SRC)\steed.c    $(HACK_H)
+$(O)sp_lev.o:   $(PCHO) $(SRC)\sp_lev.c   $(HACK_H) $(SP_LEV_H) $(DLB_H)
+$(O)spell.o:     $(PCHO) $(SRC)\spell.c    $(HACK_H)
+$(O)teleport.o:  $(PCHO) $(SRC)\teleport.c $(HACK_H)   # check dep
+$(O)tile.o:      $(PCHO) $(SRC)\tile.c     $(HACK_H)
+$(O)topten.o:   $(PCHO) $(SRC)\topten.c   $(HACK_H) $(DLB_H) $(PATCHLEVEL_H)
+$(O)u_init.o:    $(PCHO) $(SRC)\u_init.c   $(HACK_H)
+$(O)uhitm.o:     $(PCHO) $(SRC)\uhitm.c    $(HACK_H)
+$(O)version.o:   $(PCHO) $(SRC)\version.c  $(HACK_H) $(PATCHLEVEL_H)
+$(O)vision.o:    $(PCHO) $(SRC)\vision.c   $(HACK_H) $(VIS_TAB_H)
+$(O)vis_tab.o:   $(SRC)\vis_tab.c  $(HACK_H) $(VIS_TAB_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\vis_tab.c
+$(O)wield.o:     $(PCHO) $(SRC)\wield.c    $(HACK_H)
+$(O)windows.o:   $(PCHO) $(SRC)\windows.c  $(HACK_H) $(WINTTY_H)
+$(O)worm.o:      $(PCHO) $(SRC)\worm.c     $(HACK_H) $(LEV_H)
+$(O)worn.o:      $(PCHO) $(SRC)\worn.c     $(HACK_H)
+$(O)write.o:     $(PCHO) $(SRC)\write.c    $(HACK_H)
+
+#
+# Overlays
+#
+
+# OVL0
+#
+
+$(O)allmain.0:  $(PCH0) $(SRC)\allmain.c  $(HACK_H)
+$(O)apply.0:    $(PCH0) $(SRC)\apply.c    $(HACK_H) $(EDOG_H)
+$(O)artifact.0: $(PCH0) $(SRC)\artifact.c $(HACK_H) $(ARTIFACT_H) $(ARTILIST_H)
+$(O)attrib.0:   $(PCH0) $(SRC)\attrib.c   $(HACK_H)
+$(O)botl.0:     $(PCH0) $(SRC)\botl.c     $(HACK_H)
+$(O)cmd.0:      $(PCH0) $(SRC)\cmd.c      $(HACK_H) $(FUNC_TAB_H)
+$(O)dbridge.0:  $(PCH0) $(SRC)\dbridge.c  $(HACK_H)
+$(O)do.0:       $(PCH0) $(SRC)\do.c       $(HACK_H) $(LEV_H)
+$(O)do_name.0:  $(PCH0) $(SRC)\do_name.c  $(HACK_H)
+$(O)do_wear.0:  $(PCH0) $(SRC)\do_wear.c  $(HACK_H)
+$(O)dogmove.0:  $(PCH0) $(SRC)\dogmove.c  $(HACK_H) $(MFNDPOS_H) $(EDOG_H)
+$(O)dungeon.0: $(PCH0) $(SRC)\dungeon.c  $(HACK_H) $(ALIGN_H) $(DGN_FILE_H) \
+               $(DLB_H)
+$(O)eat.0:      $(PCH0) $(SRC)\eat.c      $(HACK_H)
+$(O)engrave.0:  $(PCH0) $(SRC)\engrave.c  $(HACK_H) $(LEV_H)
+$(O)explode.0:  $(PCH0) $(SRC)\explode.c  $(HACK_H)
+$(O)hacklib.0:  $(PCH0) $(SRC)\hacklib.c  $(HACK_H)
+$(O)invent.0:   $(PCH0) $(SRC)\invent.c   $(HACK_H) $(ARTIFACT_H)
+$(O)lock.0:     $(PCH0) $(SRC)\lock.c     $(HACK_H)
+$(O)mail.0:     $(PCH0) $(SRC)\mail.c     $(HACK_H) $(MAIL_H) $(DATE_H)
+$(O)makemon.0:  $(PCH0) $(SRC)\makemon.c  $(HACK_H) $(EPRI_H) $(EMIN_H)
+$(O)mcastu.0:   $(PCH0) $(SRC)\mcastu.c   $(HACK_H)
+$(O)mhitm.0:    $(PCH0) $(SRC)\mhitm.c    $(HACK_H) $(ARTIFACT_H) $(EDOG_H)
+$(O)mhitu.0:    $(PCH0) $(SRC)\mhitu.c    $(HACK_H) $(ARTIFACT_H) $(EDOG_H)
+$(O)mkobj.0:    $(PCH0) $(SRC)\mkobj.c    $(HACK_H) $(ARTIFACT_H) $(PROP_H)
+$(O)mkroom.0:   $(PCH0) $(SRC)\mkroom.c   $(HACK_H)
+$(O)mon.0:      $(PCH0) $(SRC)\mon.c      $(HACK_H) $(MFNDPOS_H) $(EDOG_H)
+$(O)mondata.0:  $(PCH0) $(SRC)\mondata.c  $(HACK_H) $(ESHK_H) $(EPRI_H)
+$(O)monmove.0:  $(PCH0) $(SRC)\monmove.c  $(HACK_H) $(MFNDPOS_H) $(ARTIFACT_H)
+$(O)mthrowu.0:  $(PCH0) $(SRC)\mthrowu.c  $(HACK_H)
+$(O)objnam.0:   $(PCH0) $(SRC)\objnam.c   $(HACK_H)
+$(O)polyself.0: $(PCH0) $(SRC)\polyself.c $(HACK_H)
+$(O)priest.0:   $(PCH0) $(SRC)\priest.c   $(HACK_H) $(MFNDPOS_H) $(ESHK_H) \
+               $(EPRI_H) $(EMIN_H)
+$(O)rnd.0:      $(PCH0) $(SRC)\rnd.c      $(HACK_H)
+$(O)shk.0:      $(PCH0) $(SRC)\shk.c      $(HACK_H) $(ESHK_H)
+$(O)shknam.0:   $(PCH0) $(SRC)\shknam.c   $(HACK_H) $(ESHK_H)
+$(O)sounds.0:   $(PCH0) $(SRC)\sounds.c   $(HACK_H) $(EDOG_H)
+$(O)steal.0:    $(PCH0) $(SRC)\steal.c    $(HACK_H)
+$(O)timeout.0: $(PCH0) $(SRC)\timeout.c  $(HACK_H) $(LEV_H)
+$(O)track.0:    $(PCH0) $(SRC)\track.c    $(HACK_H)
+$(O)trap.0:     $(PCH0) $(SRC)\trap.c     $(HACK_H)
+$(O)vault.0:    $(PCH0) $(SRC)\vault.c    $(HACK_H) $(VAULT_H)
+$(O)weapon.0:   $(PCH0) $(SRC)\weapon.c   $(HACK_H)
+$(O)were.0:     $(PCH0) $(SRC)\were.c     $(HACK_H)
+$(O)wizard.0:   $(PCH0) $(SRC)\wizard.c   $(HACK_H) $(QTEXT_H)
+$(O)zap.0:      $(PCH0) $(SRC)\zap.c      $(HACK_H)
+
+#
+# OVL1
+#
+
+$(O)allmain.1:  $(PCH1) $(SRC)\allmain.c  $(HACK_H)
+$(O)apply.1:    $(PCH1) $(SRC)\apply.c    $(HACK_H) $(EDOG_H)
+$(O)artifact.1: $(PCH1) $(SRC)\artifact.c $(HACK_H) $(ARTIFACT_H) $(ARTILIST_H)
+$(O)attrib.1:   $(PCH1) $(SRC)\attrib.c   $(HACK_H)
+$(O)botl.1:     $(PCH1) $(SRC)\botl.c     $(HACK_H)
+$(O)cmd.1:      $(PCH1) $(SRC)\cmd.c      $(HACK_H) $(FUNC_TAB_H)
+$(O)dbridge.1:  $(PCH1) $(SRC)\dbridge.c  $(HACK_H)
+$(O)do.1:       $(PCH1) $(SRC)\do.c       $(HACK_H) $(LEV_H)
+$(O)do_wear.1:  $(PCH1) $(SRC)\do_wear.c  $(HACK_H)
+$(O)dog.1:      $(PCH1) $(SRC)\dog.c      $(HACK_H) $(EDOG_H)
+$(O)dungeon.1: $(PCH1) $(SRC)\dungeon.c  $(HACK_H) $(ALIGN_H) $(DGN_FILE_H) $(DLB_H)
+$(O)eat.1:      $(PCH1) $(SRC)\eat.c      $(HACK_H)
+$(O)engrave.1:  $(PCH1) $(SRC)\engrave.c  $(HACK_H) $(LEV_H)
+$(O)explode.1:  $(PCH1) $(SRC)\explode.c  $(HACK_H)
+$(O)hack.1:     $(PCH1) $(SRC)\hack.c     $(HACK_H)
+$(O)hacklib.1:  $(PCH1) $(SRC)\hacklib.c  $(HACK_H)
+$(O)invent.1:   $(PCH1) $(SRC)\invent.c   $(HACK_H) $(ARTIFACT_H)
+$(O)makemon.1:  $(PCH1) $(SRC)\makemon.c  $(HACK_H) $(EPRI_H) $(EMIN_H)
+$(O)mhitu.1:    $(PCH1) $(SRC)\mhitu.c    $(HACK_H) $(ARTIFACT_H) $(EDOG_H)
+$(O)mkobj.1:    $(PCH1) $(SRC)\mkobj.c    $(HACK_H) $(ARTIFACT_H) $(PROP_H)
+$(O)mon.1:      $(PCH1) $(SRC)\mon.c      $(HACK_H) $(MFNDPOS_H) $(EDOG_H)
+$(O)mondata.1:  $(PCH1) $(SRC)\mondata.c  $(HACK_H) $(ESHK_H) $(EPRI_H)
+$(O)monmove.1:  $(PCH1) $(SRC)\monmove.c  $(HACK_H) $(MFNDPOS_H) $(ARTIFACT_H)
+$(O)mthrowu.1:  $(PCH1) $(SRC)\mthrowu.c  $(HACK_H)
+$(O)objnam.1:   $(PCH1) $(SRC)\objnam.c   $(HACK_H)
+$(O)polyself.1: $(PCH1) $(SRC)\polyself.c $(HACK_H)
+$(O)rnd.1:      $(PCH1) $(SRC)\rnd.c      $(HACK_H)
+$(O)shk.1:      $(PCH1) $(SRC)\shk.c      $(HACK_H) $(ESHK_H)
+$(O)steal.1:    $(PCH1) $(SRC)\steal.c    $(HACK_H)
+$(O)timeout.1: $(PCH1) $(SRC)\timeout.c  $(HACK_H) $(LEV_H)
+$(O)track.1:    $(PCH1) $(SRC)\track.c    $(HACK_H)
+$(O)trap.1:     $(PCH1) $(SRC)\trap.c     $(HACK_H)
+$(O)weapon.1:   $(PCH1) $(SRC)\weapon.c   $(HACK_H)
+$(O)zap.1:      $(PCH1) $(SRC)\zap.c      $(HACK_H)
+
+#
+# OVL2
+#
+
+$(O)attrib.2:   $(PCH2) $(SRC)\attrib.c   $(HACK_H)
+$(O)do.2:       $(PCH2) $(SRC)\do.c       $(HACK_H) $(LEV_H)
+$(O)do_name.2:  $(PCH2) $(SRC)\do_name.c  $(HACK_H)
+$(O)do_wear.2:  $(PCH2) $(SRC)\do_wear.c  $(HACK_H)
+$(O)dog.2:      $(PCH2) $(SRC)\dog.c      $(HACK_H) $(EDOG_H)
+$(O)engrave.2:  $(PCH2) $(SRC)\engrave.c  $(HACK_H) $(LEV_H)
+$(O)hack.2:     $(PCH2) $(SRC)\hack.c     $(HACK_H)
+$(O)hacklib.2:  $(PCH2) $(SRC)\hacklib.c  $(HACK_H)
+$(O)invent.2:   $(PCH2) $(SRC)\invent.c   $(HACK_H) $(ARTIFACT_H)
+$(O)makemon.2:  $(PCH2) $(SRC)\makemon.c  $(HACK_H) $(EPRI_H) $(EMIN_H)
+$(O)mon.2:      $(PCH2) $(SRC)\mon.c      $(HACK_H) $(MFNDPOS_H) $(EDOG_H)
+$(O)mondata.2:  $(PCH2) $(SRC)\mondata.c  $(HACK_H) $(ESHK_H) $(EPRI_H)
+$(O)monmove.2:  $(PCH2) $(SRC)\monmove.c  $(HACK_H) $(MFNDPOS_H) $(ARTIFACT_H)
+$(O)shk.2:      $(PCH2) $(SRC)\shk.c      $(HACK_H) $(ESHK_H)
+$(O)trap.2:     $(PCH2) $(SRC)\trap.c     $(HACK_H)
+$(O)zap.2:      $(PCH2) $(SRC)\zap.c      $(HACK_H)
+
+#
+# OVL3
+#
+
+$(O)do.3:       $(PCH3) $(SRC)\do.c       $(HACK_H) $(LEV_H)
+$(O)hack.3:     $(PCH3) $(SRC)\hack.c     $(HACK_H)
+$(O)invent.3:  $(PCH3) $(SRC)\invent.c   $(HACK_H) $(ARTIFACT_H)
+$(O)light.3:   $(PCH3) $(SRC)\light.c    $(HACK_H)
+$(O)shk.3:      $(PCH3) $(SRC)\shk.c      $(HACK_H) $(ESHK_H)
+$(O)trap.3:     $(PCH3) $(SRC)\trap.c     $(HACK_H)
+$(O)zap.3:      $(PCH3) $(SRC)\zap.c      $(HACK_H)
+
+#
+# OVLB
+#
+
+$(O)allmain.B:  $(PCHB) $(SRC)\allmain.c  $(HACK_H)
+$(O)apply.B:    $(PCHB) $(SRC)\apply.c    $(HACK_H) $(EDOG_H)
+$(O)artifact.B: $(PCHB) $(SRC)\artifact.c $(HACK_H) $(ARTIFACT_H) $(ARTILIST_H)
+$(O)attrib.B:   $(PCHB) $(SRC)\attrib.c   $(HACK_H)
+$(O)botl.B:     $(PCHB) $(SRC)\botl.c     $(HACK_H)
+$(O)cmd.B:      $(PCHB) $(SRC)\cmd.c      $(HACK_H) $(FUNC_TAB_H)
+$(O)dbridge.B:  $(PCHB) $(SRC)\dbridge.c  $(HACK_H)
+$(O)do.B:       $(PCHB) $(SRC)\do.c       $(HACK_H) $(LEV_H)
+$(O)do_name.B:  $(PCHB) $(SRC)\do_name.c  $(HACK_H)
+$(O)do_wear.B:  $(PCHB) $(SRC)\do_wear.c  $(HACK_H)
+$(O)dog.B:      $(PCHB) $(SRC)\dog.c      $(HACK_H) $(EDOG_H)
+$(O)dogmove.B:  $(PCHB) $(SRC)\dogmove.c  $(HACK_H) $(MFNDPOS_H) $(EDOG_H)
+$(O)eat.B:      $(PCHB) $(SRC)\eat.c      $(HACK_H)
+$(O)engrave.B:  $(PCHB) $(SRC)\engrave.c  $(HACK_H) $(LEV_H)
+$(O)hack.B:     $(PCHB) $(SRC)\hack.c     $(HACK_H)
+$(O)hacklib.B:  $(PCHB) $(SRC)\hacklib.c  $(HACK_H)
+$(O)invent.B:   $(PCHB) $(SRC)\invent.c   $(HACK_H) $(ARTIFACT_H)
+$(O)lock.B:     $(PCHB) $(SRC)\lock.c     $(HACK_H)
+$(O)mail.B:     $(PCHB) $(SRC)\mail.c     $(HACK_H) $(MAIL_H) $(DATE_H)
+$(O)makemon.B:  $(PCHB) $(SRC)\makemon.c  $(HACK_H) $(EPRI_H) $(EMIN_H)
+$(O)mcastu.B:   $(PCHB) $(SRC)\mcastu.c   $(HACK_H)
+$(O)mhitm.B:    $(PCHB) $(SRC)\mhitm.c    $(HACK_H) $(ARTIFACT_H) $(EDOG_H)
+$(O)mhitu.B:    $(PCHB) $(SRC)\mhitu.c    $(HACK_H) $(ARTIFACT_H) $(EDOG_H)
+$(O)mkobj.B:    $(PCHB) $(SRC)\mkobj.c    $(HACK_H) $(ARTIFACT_H) $(PROP_H)
+$(O)mkroom.B:   $(PCHB) $(SRC)\mkroom.c   $(HACK_H)
+$(O)mon.B:      $(PCHB) $(SRC)\mon.c      $(HACK_H) $(MFNDPOS_H) $(EDOG_H)
+$(O)mondata.B:  $(PCHB) $(SRC)\mondata.c  $(HACK_H) $(ESHK_H) $(EPRI_H)
+$(O)monmove.B:  $(PCHB) $(SRC)\monmove.c  $(HACK_H) $(MFNDPOS_H) $(ARTIFACT_H)
+$(O)mthrowu.B:  $(PCHB) $(SRC)\mthrowu.c  $(HACK_H)
+$(O)objnam.B:   $(PCHB) $(SRC)\objnam.c   $(HACK_H)
+$(O)pline.B:    $(SRC)\pline.c    $(HACK_H) $(EPRI_H)
+       @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG)
+       @echo $(BCOPTS1) >> $(VROOMMCFG)
+       @echo $(BCOPTS2) >> $(VROOMMCFG)
+       $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\pline.c
+$(O)polyself.B: $(PCHB) $(SRC)\polyself.c $(HACK_H)
+$(O)potion.B:   $(PCHB) $(SRC)\potion.c   $(HACK_H)
+$(O)priest.B:   $(PCHB) $(SRC)\priest.c   $(HACK_H) $(MFNDPOS_H) $(ESHK_H) \
+               $(EPRI_H) $(EMIN_H)
+$(O)read.B:     $(PCHB) $(SRC)\read.c     $(HACK_H)
+$(O)rnd.B:      $(PCHB) $(SRC)\rnd.c      $(HACK_H)
+$(O)shk.B:      $(PCHB) $(SRC)\shk.c      $(HACK_H) $(ESHK_H)
+$(O)shknam.B:   $(PCHB) $(SRC)\shknam.c   $(HACK_H) $(ESHK_H)
+$(O)sounds.B:   $(PCHB) $(SRC)\sounds.c   $(HACK_H) $(EDOG_H)
+$(O)steal.B:    $(PCHB) $(SRC)\steal.c    $(HACK_H)
+$(O)timeout.B: $(PCHB) $(SRC)\timeout.c  $(HACK_H) $(LEV_H)
+$(O)track.B:    $(PCHB) $(SRC)\track.c    $(HACK_H)
+$(O)trap.B:     $(PCHB) $(SRC)\trap.c     $(HACK_H)
+$(O)vault.B:    $(PCHB) $(SRC)\vault.c    $(HACK_H) $(VAULT_H)
+$(O)weapon.B:   $(PCHB) $(SRC)\weapon.c   $(HACK_H)
+$(O)were.B:     $(PCHB) $(SRC)\were.c     $(HACK_H)
+$(O)wizard.B:   $(PCHB) $(SRC)\wizard.c   $(HACK_H) $(QTEXT_H)
+$(O)zap.B:      $(PCHB) $(SRC)\zap.c      $(HACK_H)
+
+# end of file
diff --git a/sys/msdos/Makefile.GCC b/sys/msdos/Makefile.GCC
new file mode 100644 (file)
index 0000000..64fe610
--- /dev/null
@@ -0,0 +1,1260 @@
+#      SCCS Id: @(#)Makefile.GCC             3.4     $Date: 2003/06/15 15:56:45 $
+#      Copyright (c) NetHack PC Development Team 1996-2003.
+#      PC NetHack 3.4 Makefile for djgpp V2
+#
+#      Gnu gcc compiler for msdos (djgpp)
+#      Requires Gnu Make utility (V3.79.1 or greater) supplied with djgpp
+#
+#      For questions or comments: devteam@nethack.org
+#
+#      In addition to your C compiler,
+#
+#       if you want to change     you will need a
+#       files with suffix         workalike for
+#        .y                         yacc
+#        .l                         lex
+#
+#      Note that flex (lex) and bison (yacc) are included with the
+#      djgpp distribution and work quite well.  This makefile assumes
+#      you have them installed correctly.
+
+# Game Installation Variables
+# NOTE: Make sure GAMEDIR exists before make is started.
+
+GAME = nethack
+# The GNU Make has a problem if you include a drive spec below (unfortunately).
+GAMEDIR =../binary
+
+#
+# Directories, gcc likes unix style directory specs
+#
+
+OBJ  = o
+DAT  = ../dat
+DOC  = ../doc
+INCL = ../include
+MSYS = ../sys/msdos
+SRC  = ../src
+SSHR = ../sys/share
+UTIL = ../util
+WIN  = ../win/tty
+WSHR = ../win/share
+
+#
+#  Executables.
+
+CC    = gcc
+LINK  = gcc
+MAKEBIN  = make
+
+#
+# Special libraries and how to link them in.
+
+LIBS = -lpc
+
+# If TERMLIB is defined in pcconf.h, comment out the upper line and
+# uncomment the lower. Note that you must build the termc library
+# and place it in djgpp's lib directory.  See termcap.zip for details
+
+TERMLIB =
+#TERMLIB = -ltermc
+
+LIBRARIES = $(LIBS) $(TERMLIB)
+
+#
+#  Yacc/Lex ... if you got 'em.
+#
+# If you have yacc/lex or a work-alike set YACC_LEX to Y
+#
+YACC_LEX = Y
+ifeq ($(YACC_LEX),Y)
+DO_YACC = YACC_ACT
+DO_LEX  = LEX_ACT
+endif
+
+# If YACC_LEX is Y above, set the following to values appropriate for
+# your tools.
+#
+YACC   = bison -y
+LEX    = flex
+YTABC  = y_tab.c
+YTABH  = y_tab.h
+#If your tool produces y.tab.c and y.tab.h DOS might require
+#the following instead.
+#YTABC  = ytab~1.c
+#YTABH  = ytab~1.h
+LEXYYC = lexyy.c
+
+#
+# Uncomment the line below if you want to store all the level files,
+# help files, etc. in a single library file.
+
+USE_DLB = Y
+
+# djgpp includes ls.exe and touch.exe in fil41b.zip from the v2gnu 
+# folder so be sure to include that when downloading djgpp. Doing
+# so will make changing this unnecessary.
+
+LS = ls -1             # ls.exe from djgpp distribution
+#LS = dir /l/b         # DOS command
+
+# To build a binary without any graphics
+# suitable for blind players,
+# set SUPPRESS_GRAPHICS to Y
+# (Note: binary will require ANSI.SYS driver or equivalent loaded)
+# SUPPRESS_GRAPHICS = Y
+SUPPRESS_GRAPHICS = 
+
+#===============================================
+#======= End of Modification Section ===========
+#===============================================
+################################################
+#                                              #
+# Nothing below here should have to be changed.#
+#                                              #
+################################################
+
+GAMEFILE = $(GAMEDIR)/$(GAME).exe
+
+# Changing this conditional block is not recommended
+ifeq ($(USE_DLB),Y)
+DLBFLG = -DDLB
+else
+DLBFLG =
+endif
+
+#
+#  Flags.
+#
+ifeq ($(SUPPRESS_GRAPHICS),Y)
+TERMLIB =
+# Build NetHack suitable for blind players
+
+# Debugging
+#cflags = -pg -c -I../include $(DLBFLG) -DSUPPRESS_GRAPHICS
+#LFLAGS = -pg
+
+cflags = -c -O -I../include $(DLBFLG) -DSUPPRESS_GRAPHICS
+LFLAGS =
+
+else
+
+# Debugging
+#cflags = -pg -c -I../include $(DLBFLG) -DUSE_TILES
+#LFLAGS = -pg
+
+#    Normal
+cflags = -c -O -I../include $(DLBFLG) -DUSE_TILES
+LFLAGS =
+endif
+
+#==========================================
+#================ RULES ==================
+#==========================================
+
+.SUFFIXES: .exe .o .tib .til .uu .c .y .l
+
+#==========================================
+# Rules for files in src
+#==========================================
+
+$(OBJ)/%.o : /%.c
+       $(CC) $(cflags) -o$@ $<
+
+$(OBJ)/%.o : $(SRC)/%.c
+       $(CC) $(cflags) -o$@ $<
+
+#==========================================
+# Rules for files in sys/share
+#==========================================
+
+$(OBJ)/%.o : $(SSHR)/%.c
+       $(CC) $(cflags) -o$@ $<
+
+#==========================================
+# Rules for files in sys/msdos
+#==========================================
+
+$(OBJ)/%.o : $(MSYS)/%.c
+       $(CC) $(cflags) -I../sys/msdos -o$@ $<
+
+#==========================================
+# Rules for files in util
+#==========================================
+
+$(OBJ)/%.o : $(UTIL)/%.c
+       $(CC) $(cflags) -o$@ $<
+
+#==========================================
+# Rules for files in win/share
+#==========================================
+
+$(OBJ)/%.o : $(WSHR)/%.c
+       $(CC) $(cflags) -I../win/share -o$@ $<
+
+#{$(WSHR)}.txt{$(DAT)}.txt:
+#      copy $< $@
+
+#==========================================
+# Rules for files in win/tty
+#==========================================
+
+$(OBJ)/%.o : $(TTY)/%.c
+       $(CC) $(cflags) -o$@ $<
+
+#==========================================
+#================ MACROS ==================
+#==========================================
+# This section creates shorthand macros for many objects
+# referenced later on in the Makefile.
+#
+#
+# Shorten up the location for some files
+#
+
+O  = $(OBJ)/
+
+U  = $(UTIL)/
+
+#==========================================
+#  Utility Objects.
+#==========================================
+
+VGAOBJ      = $(O)vidvga.o
+
+MAKESRC            = makedefs.c
+
+SPLEVSRC    = lev_yacc.c  lev_$(LEX).c  lev_main.c  panic.c
+
+DGNCOMPSRC  = dgn_yacc.c  dgn_$(LEX).c  dgn_main.c
+
+MAKEOBJS    = $(O)makedefs.o  $(O)monst.o       $(O)objects.o
+
+SPLEVOBJS   = $(O)lev_yacc.o  $(O)lev_$(LEX).o $(O)lev_main.o  $(O)alloc.o     \
+               $(O)monst.o         $(O)objects.o           $(O)panic.o  \
+               $(O)drawing.o   $(O)decl.o      $(O)stubvid.o
+
+DGNCOMPOBJS = $(O)dgn_yacc.o  $(O)dgn_$(LEX).o $(O)dgn_main.o  $(O)alloc.o      \
+               $(O)panic.o
+
+RECOVOBJS   = $(O)recover.o
+
+
+#==========================================
+#  Tile related object files.
+#==========================================
+
+ifeq ($(SUPPRESS_GRAPHICS),Y)
+TILOBJ       =
+TEXTIO       =
+TEXTIO2      =
+PLANAR_TIB   =
+OVERVIEW_TIB =
+TILEUTIL     = 
+TILEFILES    = 
+TILEFILES2   = 
+GIFREADERS   = 
+GIFREAD2     = 
+PPMWRITERS   = 
+PPMWRIT2     = 
+
+else
+
+TILOBJ      = $(O)tile.o $(O)pctiles.o $(VGAOBJ)
+
+TEXTIO      = $(O)tiletext.o $(O)tiletxt.o $(O)drawing.o $(O)decl.o $(O)monst.o \
+               $(O)objects.o $(O)stubvid.o
+
+TEXTIO2     = $(O)tiletex2.o $(O)tiletxt2.o $(O)drawing.o $(O)decl.o $(O)monst.o \
+               $(O)objects.o $(O)stubvid.o
+
+PLANAR_TIB  = $(DAT)/NetHack1.tib
+
+OVERVIEW_TIB = $(DAT)/NetHacko.tib
+
+TILEUTIL    = $(TILOBJ) $(U)tile2bin.exe $(U)til2bin2.exe $(PLANAR_TIB) $(OVERVIEW_TIB)
+
+TILEFILES   = $(WSHR)/monsters.txt $(WSHR)/objects.txt $(WSHR)/other.txt
+
+TILEFILES2  = $(WSHR)/monthin.txt $(WSHR)/objthin.txt $(WSHR)/oththin.txt
+
+GIFREADERS  = $(O)gifread.o $(O)alloc.o $(O)panic.o
+
+GIFREAD2    = $(O)gifread2.o $(O)alloc.o $(O)panic.o
+
+PPMWRITERS  = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o
+
+PPMWRIT2    = $(O)ppmwrit2.o $(O)alloc.o $(O)panic.o
+endif
+
+
+DLBOBJ = $(O)dlb.o
+
+#  Object files for the game itself.
+
+
+VOBJ01 = $(O)allmain.o  $(O)alloc.o   $(O)apply.o    $(O)artifact.o $(O)attrib.o
+VOBJ02 = $(O)ball.o     $(O)bones.o   $(O)botl.o     $(O)cmd.o      $(O)dbridge.o
+VOBJ03 = $(O)decl.o     $(O)detect.o  $(O)display.o  $(O)do.o       $(O)do_name.o
+VOBJ04 = $(O)do_wear.o  $(O)dog.o     $(O)dogmove.o  $(O)dokick.o   $(O)dothrow.o
+VOBJ05 = $(O)drawing.o  $(O)dungeon.o $(O)eat.o      $(O)end.o      $(O)engrave.o
+VOBJ06 = $(O)exper.o    $(O)explode.o $(O)extralev.o $(O)files.o    $(O)fountain.o
+VOBJ07 = $(O)getline.o  $(O)hack.o    $(O)hacklib.o  $(O)invent.o   $(O)lock.o
+VOBJ08 = $(O)mail.o     $(O)main.o    $(O)makemon.o  $(O)mapglyph.o $(O)mcastu.o $(O)mhitm.o
+VOBJ09 = $(O)mhitu.o    $(O)minion.o  $(O)mkmap.o    $(O)mklev.o    $(O)mkmaze.o
+VOBJ10 = $(O)mkobj.o    $(O)mkroom.o  $(O)mon.o      $(O)mondata.o  $(O)monmove.o
+VOBJ11 = $(O)monst.o    $(O)monstr.o  $(O)mplayer.o  $(O)mthrowu.o  $(O)muse.o
+VOBJ12 = $(O)music.o    $(O)o_init.o  $(O)objects.o  $(O)objnam.o   $(O)options.o
+VOBJ13 = $(O)pickup.o   $(O)pline.o   $(O)polyself.o $(O)potion.o   $(O)quest.o
+VOBJ14 = $(O)questpgr.o $(O)pager.o   $(O)pray.o     $(O)priest.o   $(O)read.o
+VOBJ15 = $(O)rect.o     $(O)restore.o $(O)rip.o      $(O)rnd.o      $(O)role.o
+VOBJ16 = $(O)rumors.o   $(O)save.o    $(O)shk.o      $(O)shknam.o   $(O)sit.o
+VOBJ17 = $(O)sounds.o   $(O)sp_lev.o  $(O)spell.o    $(O)steal.o    $(O)steed.o
+VOBJ18 = $(O)termcap.o  $(O)timeout.o $(O)topl.o     $(O)topten.o   $(O)track.o
+VOBJ19 = $(O)trap.o     $(O)u_init.o  $(O)uhitm.o    $(O)vault.o    $(O)vision.o
+VOBJ20 = $(O)vis_tab.o  $(O)weapon.o  $(O)were.o     $(O)wield.o    $(O)windows.o
+VOBJ21 = $(O)wintty.o   $(O)wizard.o  $(O)worm.o     $(O)worn.o     $(O)write.o
+VOBJ22 = $(O)zap.o      $(O)light.o   $(O)dlb.o      $(O)dig.o      $(O)teleport.o
+VOBJ23 = $(O)region.o
+
+SOBJ   = $(O)msdos.o    $(O)sound.o   $(O)sys.o      $(O)tty.o     $(O)unix.o \
+        $(O)video.o    $(O)vidtxt.o  $(O)pckeys.o
+
+VVOBJ  = $(O)version.o
+
+VOBJ  = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \
+       $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \
+       $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \
+       $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \
+       $(VOBJ21) $(VOBJ22) $(VOBJ23)
+
+ALLOBJ = $(VOBJ) $(SOBJ) $(TILOBJ) $(VVOBJ)
+
+#==========================================
+# Header file macros
+#==========================================
+
+PATCHLEV_H = $(INCL)/patchlev.h
+DGN_FILE_H = $(INCL)/align.h   $(INCL)/dgn_file.h
+DUNGEON_H  = $(INCL)/align.h   $(INCL)/dungeon.h
+EMIN_H    = $(DUNGEON_H)       $(INCL)/emin.h
+EPRI_H    = $(DUNGEON_H)       $(INCL)/align.h     $(INCL)/epri.h
+ESHK_H    = $(DUNGEON_H)       $(INCL)/eshk.h
+MONDATA_H  = $(INCL)/align.h   $(INCL)/mondata.h
+MONST_H           = $(INCL)/align.h    $(INCL)/monst.h
+PERMONST_H = $(INCL)/monattk.h $(INCL)/monflag.h   $(INCL)/align.h   \
+           $(INCL)/permonst.h
+REGION_H   = $(INCL)/region.h
+RM_H      = $(INCL)/align.h    $(INCL)/rm.h
+SKILLS_H   = $(INCL)/skills.h
+SP_LEV_H   = $(INCL)/align.h   $(INCL)/sp_lev.h
+VAULT_H           = $(DUNGEON_H)       $(INCL)/vault.h
+YOUPROP_H  = $(PERMONST_H)     $(MONDATA_H)        $(INCL)/prop.h    \
+           $(INCL)/pm.h       $(INCL)/youprop.h
+YOU_H     = $(MONST_H)         $(YOUPROP_H)        $(INCL)/align.h   \
+            $(INCL)/attrib.h   $(INCL)/you.h
+DISPLAY_H  = $(MONDATA_H)      $(INCL)/vision.h    $(INCL)/display.h
+PCCONF_H   = $(INCL)/micro.h   $(INCL)/system.h    $(INCL)/pcconf.h \
+           $(MSYS)/pcvideo.h
+CONFIG_H   = $(GLOBAL_H)       $(INCL)/tradstdc.h  $(INCL)/config1.h \
+           $(INCL)/config.h
+DECL_H    = $(YOU_H)           $(INCL)/spell.h     $(INCL)/color.h   \
+            $(INCL)/obj.h      $(INCL)/onames.h    $(INCL)/pm.h      \
+             $(INCL)/decl.h
+GLOBAL_H   = $(PCCONF_H)       $(INCL)/coord.h     $(INCL)/global.h
+HACK_H    = $(CONFIG_H)        $(DUNGEON_H)        $(DECL_H)         \
+              $(DISPLAY_H)       $(INCL)/monsym.h    $(INCL)/mkroom.h  \
+             $(INCL)/objclass.h $(INCL)/trap.h      $(INCL)/flag.h    \
+             $(RM_H)            $(INCL)/vision.h    $(INCL)/wintype.h \
+             $(INCL)/engrave.h  $(INCL)/rect.h   \
+              $(INCL)/trampoli.h $(INCL)/hack.h $(REGION_H)
+DLB_H      = $(INCL)/dlb.h
+
+ifeq ($(SUPPRESS_GRAPHICS),Y)
+TILE_H     =
+else
+TILE_H    = $(WSHR)/tile.h $(MSYS)/pctiles.h
+endif
+
+ifeq ($(USE_DLB),Y)
+DLB = dlb
+DLBOBJS = $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o
+else
+DLB =
+DLBOBJS =
+endif
+
+ifdef DJGPP
+DJ1 = $(dir $(DJGPP))
+CWSDPMI = $(subst /,\,$(DJ1))bin\CWSDPMI.*
+endif
+
+#==========================================
+#  Primary Targets.
+#==========================================
+
+#  The default target.
+
+all :   install
+
+install: $(GAMEFILE) $(O)install.tag 
+       @echo Done.
+
+default: $(GAMEFILE)
+
+util: $(O)utility.tag
+
+$(O)utility.tag: $(INCL)/date.h $(INCL)/trap.h    $(INCL)/onames.h            \
+       $(INCL)/pm.h      monstr.c   vis_tab.c  \
+       $(U)lev_comp.exe $(U)dgn_comp.exe $(TILEUTIL)
+       $(subst /,\,echo utilities made > $@)
+
+tileutil: $(U)gif2txt.exe $(U)txt2ppm.exe
+       @echo Optional tile development utilities are up to date.
+
+recover: $(U)recover.exe
+       @$(subst /,\,if exist $(U)recover.exe copy $(U)recover.exe $(GAMEDIR))
+       @$(subst /,\,if exist $(DOC)/recover.txt copy $(DOC)/recover.txt $(GAMEDIR))
+
+$(O)install.tag: $(O)dat.tag $(GAMEFILE)
+ifeq ($(USE_DLB),Y)
+       @$(subst /,\,copy $(DAT)/nhdat $(GAMEDIR))
+       @$(subst /,\,copy $(DAT)/license $(GAMEDIR))
+else
+       @$(subst /,\,copy $(DAT)/*. $(GAMEDIR))
+       @$(subst /,\,copy $(DAT)/*.dat $(GAMEDIR))
+       @$(subst /,\,copy $(DAT)/*.lev $(GAMEDIR))
+       @$(subst /,\,copy $(MSYS)/msdoshlp.txt $(GAMEDIR))
+       @$(subst /,\,if exist $(GAMEDIR)/makefile. del $(GAMEDIR)/makefile.)
+endif
+ifdef TERMLIB
+       @$(subst /,\,copy $(SSHR)/termcap $(GAMEDIR))
+endif
+       @$(subst /,\,if exist $(DAT)/*.tib copy $(DAT)/*.tib $(GAMEDIR))
+       @$(subst /,\,copy $(SSHR)/NetHack.cnf  $(GAMEDIR)/defaults.nh)
+       @$(subst /,\,copy $(MSYS)/NHAccess.nh  $(GAMEDIR))
+       @$(subst /,\,copy $(DOC)/guidebo*.txt  $(GAMEDIR))
+       @$(subst /,\,if exist $(DOC)/nethack.txt copy $(DOC)/nethack.txt $(GAMEDIR))
+ifdef CWSDPMI
+       @$(subst /,\,if exist $(CWSDPMI) copy $(CWSDPMI) $(GAMEDIR))
+else
+       @$(subst /,\,echo Could not find a copy of CWSDPMI.EXE to put into $(GAMEDIR))
+endif
+       @$(subst /,\,echo install done > $@)
+
+#==========================================
+#  The main target.
+#==========================================
+
+$(GAMEFILE): $(O)obj.tag $(PATCHLEV_H) $(O)utility.tag $(ALLOBJ) $(O)$(GAME).lnk
+       $(LINK) $(LFLAGS) -o$(GAME).exe @$(O)$(GAME).lnk $(LIBRARIES)
+       @$(subst /,\,stubedit $(GAME).exe minstack=2048K)
+       @$(subst /,\,copy $(GAME).exe $(GAMEFILE))
+       @$(subst /,\,del $(GAME).exe)
+
+$(O)$(GAME).lnk: $(ALLOBJ)
+        echo $(VOBJ01) > $(subst /,\,$@)
+        echo $(VOBJ02) >> $(subst /,\,$@)
+        echo $(VOBJ03) >> $(subst /,\,$@)
+        echo $(VOBJ04) >> $(subst /,\,$@)
+        echo $(VOBJ05) >> $(subst /,\,$@)
+        echo $(VOBJ06) >> $(subst /,\,$@)
+        echo $(VOBJ07) >> $(subst /,\,$@)
+        echo $(VOBJ08) >> $(subst /,\,$@)
+        echo $(VOBJ09) >> $(subst /,\,$@)
+        echo $(VOBJ10) >> $(subst /,\,$@)
+        echo $(VOBJ11) >> $(subst /,\,$@)
+        echo $(VOBJ12) >> $(subst /,\,$@)
+        echo $(VOBJ13) >> $(subst /,\,$@)
+        echo $(VOBJ14) >> $(subst /,\,$@)
+        echo $(VOBJ15) >> $(subst /,\,$@)
+        echo $(VOBJ16) >> $(subst /,\,$@)
+        echo $(VOBJ17) >> $(subst /,\,$@)
+        echo $(VOBJ18) >> $(subst /,\,$@)
+        echo $(VOBJ19) >> $(subst /,\,$@)
+        echo $(VOBJ20) >> $(subst /,\,$@)
+        echo $(VOBJ21) >> $(subst /,\,$@)
+        echo $(VOBJ22) >> $(subst /,\,$@)
+        echo $(VOBJ23) >> $(subst /,\,$@)
+        echo $(SOBJ)   >> $(subst /,\,$@)
+        echo $(TILOBJ) >> $(subst /,\,$@)
+        echo $(VVOBJ)  >> $(subst /,\,$@)
+
+
+#==========================================
+#  Housekeeping.
+#==========================================
+
+clean:
+       $(subst /,\,if exist $(O)*.o del $(O)*.o)
+       $(subst /,\,if exist $(O)dat.tag del $(O)dat.tag)
+       $(subst /,\,if exist $(O)install.tag del $(O)install.tag)
+       $(subst /,\,if exist $(O)$(GAME).lnk del $(O)$(GAME).lnk)
+       $(subst /,\,if exist $(O)obj.tag del $(O)obj.tag)
+       $(subst /,\,if exist $(O)sp_lev.tag del $(O)sp_lev.tag)
+       $(subst /,\,if exist $(O)thintile.tag del $(O)thintile.tag)
+       $(subst /,\,if exist $(O)utility.tag del $(O)utility.tag)
+
+spotless: clean
+
+       $(subst /,\,if exist $(U)lev_flex.c del $(U)lev_flex.c)
+       $(subst /,\,if exist $(U)lev_lex.c del $(U)lev_lex.c)
+       $(subst /,\,if exist $(U)lev_yacc.c del $(U)lev_yacc.c)
+       $(subst /,\,if exist $(U)dgn_flex.c del $(U)dgn_flex.c)
+       $(subst /,\,if exist $(U)dgn_lex.c del $(U)dgn_lex.c)
+       $(subst /,\,if exist $(U)dgn_yacc.c del $(U)lev_yacc.c)
+       $(subst /,\,if exist $(U)makedefs.exe del $(U)makedefs.exe)
+       $(subst /,\,if exist $(U)lev_comp.exe del $(U)lev_comp.exe)
+       $(subst /,\,if exist $(U)dgn_comp.exe del $(U)dgn_comp.exe)
+       $(subst /,\,if exist $(U)recover.exe del $(U)recover.exe)
+       $(subst /,\,if exist $(U)tilemap.exe del $(U)tilemap.exe)
+       $(subst /,\,if exist $(U)tile2bin.exe del $(U)tile2bin.exe)
+       $(subst /,\,if exist $(U)til2bin2.exe del $(U)til2bin2.exe)
+       $(subst /,\,if exist $(U)thintile.exe del $(U)thintile.exe)
+       $(subst /,\,if exist $(U)dlb_main.exe del $(U)dlb_main.exe)
+       $(subst /,\,if exist $(INCL)/vis_tab.h del $(INCL)/vis_tab.h)
+       $(subst /,\,if exist $(INCL)/onames.h del $(INCL)/onames.h)
+       $(subst /,\,if exist $(INCL)/pm.h del $(INCL)/pm.h)
+       $(subst /,\,if exist $(INCL)/date.h del $(INCL)/date.h)
+       $(subst /,\,if exist $(INCL)/dgn_comp.h del $(INCL)/dgn_comp.h)
+       $(subst /,\,if exist $(INCL)/lev_comp.h del $(INCL)/lev_comp.h)
+       $(subst /,\,if exist $(SRC)/monstr.c del $(SRC)/monstr.c)
+       $(subst /,\,if exist $(SRC)/vis_tab.c del $(SRC)/vis_tab.c)
+       $(subst /,\,if exist $(SRC)/tile.c del $(SRC)/tile.c)
+       $(subst /,\,if exist $(DAT)/options del $(DAT)/options)
+       $(subst /,\,if exist $(DAT)/data del $(DAT)/data)
+       $(subst /,\,if exist $(DAT)/rumors del $(DAT)/rumors)
+       $(subst /,\,if exist $(DAT)/dungeon.pdf del $(DAT)/dungeon.pdf)
+       $(subst /,\,if exist $(DAT)/dungeon del $(DAT)/dungeon)
+       $(subst /,\,if exist $(DAT)/oracles del $(DAT)/oracles)
+       $(subst /,\,if exist $(DAT)/quest.dat del $(DAT)/quest.dat)
+       $(subst /,\,if exist $(DAT)/dlb.lst del $(DAT)/dlb.lst)
+       $(subst /,\,if exist $(DAT)/nhdat del $(DAT)/nhdat)
+       $(subst /,\,if exist $(DAT)/*.lev del $(DAT)/*.lev)
+       $(subst /,\,if exist $(PLANAR_TIB) del $(PLANAR_TIB))
+       $(subst /,\,if exist $(OVERVIEW_TIB) del $(OVERVIEW_TIB))
+       $(subst /,\,if exist $(WSHR)/monthin.txt del $(WSHR)/monthin.txt)
+       $(subst /,\,if exist $(WSHR)/objthin.txt del $(WSHR)/objthin.txt)
+       $(subst /,\,if exist $(WSHR)/oththin.txt del $(WSHR)/oththin.txt)
+
+#==========================================
+# Create directory for holding object files
+#==========================================
+
+$(O)obj.tag:
+       -$(subst /,\,@if not exist $(OBJ)/*.* mkdir $(OBJ))
+       @$(subst /,\,@echo directory created > $@)
+
+#===========================================
+# Work around some djgpp long file name woes
+#===========================================
+
+$(PATCHLEV_H):
+       @$(subst /,\,if not exist $@ copy $(INCL)/patchlevel.h $(INCL)/patchlev.h)
+
+#==========================================
+#=========== SECONDARY TARGETS ============
+#==========================================
+#
+#  The following include files depend on makedefs to be created.
+#
+#  date.h should be remade every time any of the source or include
+#  files is modified.
+
+
+$(INCL)/date.h : $(U)makedefs.exe
+       -$(subst /,\,$(U)makedefs -v)
+
+$(INCL)/onames.h: $(U)makedefs.exe
+       -$(subst /,\,$(U)makedefs -o)
+
+$(INCL)/pm.h: $(U)makedefs.exe
+       -$(subst /,\,$(U)makedefs -p)
+
+monstr.c: $(U)makedefs.exe
+       -$(subst /,\,$(U)makedefs -m)
+
+$(INCL)/vis_tab.h: $(U)makedefs.exe
+       -$(subst /,\,$(U)makedefs -z)
+
+vis_tab.c: $(U)makedefs.exe
+       -$(subst /,\,$(U)makedefs -z)
+
+#==========================================
+#  Makedefs Stuff
+#==========================================
+
+$(U)makedefs.exe:  $(MAKEOBJS)
+       $(LINK) $(LFLAGS) -o$@ $(MAKEOBJS)
+
+$(O)makedefs.o:  $(CONFIG_H)   $(PERMONST_H)      $(INCL)/objclass.h \
+               $(INCL)/monsym.h   $(INCL)/qtext.h $(U)makedefs.c
+
+#==========================================
+#  Level Compiler Dependencies
+#==========================================
+
+$(U)lev_comp.exe:  $(SPLEVOBJS)
+       $(LINK) $(LFLAGS) -o$@ $(SPLEVOBJS)
+
+ifeq ($(YACC_LEX),Y)
+
+$(O)lev_yacc.o:  $(HACK_H)      $(SP_LEV_H)    $(U)lev_yacc.c
+       $(CC) $(cflags) -o$@ $(U)lev_yacc.c
+
+else
+
+$(O)lev_yacc.o:  $(HACK_H)      $(SP_LEV_H) $(INCL)/lev_comp.h $(U)lev_yacc.c
+       $(CC) $(cflags) -o$@ $(U)lev_yacc.c
+
+endif
+
+$(O)lev_$(LEX).o:  $(HACK_H)   $(SP_LEV_H)       $(INCL)/lev_comp.h \
+       $(U)lev_$(LEX).c
+       $(CC) $(cflags) -o$@ $(U)lev_$(LEX).c
+
+$(O)lev_main.o:  $(HACK_H) $(INCL)/sp_lev.h $(INCL)/date.h $(U)lev_main.c
+
+ifeq  "$(DO_YACC)" "YACC_ACT"
+
+$(INCL)/lev_comp.h: $(U)lev_yacc.c
+
+$(U)lev_yacc.c $(INCL)/lev_comp.h : $(U)lev_comp.y
+       @$(subst /,\,chdir $(UTIL))
+       @$(subst /,\,$(YACC) -d lev_comp.y)
+       @$(subst /,\,copy $(YTABC) lev_yacc.c)
+       @$(subst /,\,copy $(YTABH) $(INCL)/lev_comp.h)
+       @$(subst /,\,@del $(YTABC))
+       @$(subst /,\,@del $(YTABH))
+       @$(subst /,\,chdir $(SRC))
+else
+
+$(U)lev_yacc.c: $(SSHR)/lev_yacc.c
+       @echo ---
+       @echo For now, we will copy the prebuilt
+       @echo lev_comp.c from $(SSHR) into $(U) and use that.
+       @$(subst /,\,copy $(SSHR)/lev_yacc.c $(U)lev_yacc.c)
+       @$(subst /,\,echo.>>$(U)lev_yacc.c)
+
+$(INCL)/lev_comp.h : $(SSHR)/lev_comp.h
+       @echo ---
+       @echo For now, we will copy the prebuilt lev_comp.h
+       @echo from $(SSHR) into $(INCL) and use that.
+       @$(subst /,\,copy $(SSHR)/lev_comp.h $(INCL)/lev_comp.h)
+       @$(subst /,\,echo.>>$(INCL)/lev_comp.h)
+
+endif
+
+$(U)lev_$(LEX).c: $(U)lev_comp.l
+ifeq  "$(DO_LEX)" "LEX_ACT"
+       @$(subst /,\,chdir $(UTIL))
+       @$(subst /,\,$(LEX) $(FLEXSKEL) lev_comp.l)
+       @$(subst /,\,if exist $@ del $@)
+       @$(subst /,\,copy $(LEXYYC) $@)
+       @$(subst /,\,del $(LEXYYC))
+       @$(subst /,\,chdir $(SRC))
+else
+       @echo ---
+       @echo For now, we will copy the prebuilt lev_lex.c
+       @echo from $(SSHR) into $(U) and use it.
+       @$(subst /,\,copy $(SSHR)/lev_lex.c $@)
+       @$(subst /,\,echo.>>$@)
+endif
+
+#==========================================
+#  Dungeon Dependencies
+#==========================================
+
+$(U)dgn_comp.exe:  $(DGNCOMPOBJS)
+       $(LINK) $(LFLAGS) -o$@ $(DGNCOMPOBJS)
+
+ifeq  "$(DO_YACC)" "YACC_ACT"
+$(U)dgn_yacc.c $(INCL)/dgn_comp.h : $(U)dgn_comp.y
+       @$(subst /,\,chdir $(UTIL))
+       @$(subst /,\,$(YACC) -d dgn_comp.y)
+       @$(subst /,\,copy $(YTABC) dgn_yacc.c)
+       @$(subst /,\,copy $(YTABH) $(INCL)/dgn_comp.h)
+       @$(subst /,\,@del $(YTABC))
+       @$(subst /,\,@del $(YTABH))
+       @$(subst /,\,chdir $(SRC))
+else
+$(U)dgn_yacc.c: $(SSHR)/dgn_yacc.c
+       @echo ---
+       @echo For now, we will copy the prebuilt $(U)dgn_yacc.c and
+       @echo dgn_comp.h from $(SSHR) into $(U) and use that.
+       @$(subst /,\,copy $(SSHR)/dgn_yacc.c $(U)dgn_yacc.c)
+       @$(subst /,\,echo.>>$(U)dgn_yacc.c)
+
+$(INCL)/dgn_comp.h: $(SSHR)/dgn_comp.h
+       @echo ---
+       @echo For now, we will copy the prebuilt dgn_comp.h
+       @echo from $(SSHR) into $(INCL) and use that.
+       @$(subst /,\,copy $(SSHR)/dgn_comp.h $(INCL)/dgn_comp.h)
+       @$(subst /,\,echo.>>$(INCL)/dgn_comp.h)
+
+endif
+
+ifeq  "$(DO_LEX)" "LEX_ACT"
+
+$(U)dgn_$(LEX).c: $(U)dgn_comp.l $(INCL)/dgn_comp.h
+       @$(subst /,\,chdir $(UTIL))
+       @$(subst /,\,$(LEX) $(FLEXSKEL) dgn_comp.l)
+       @$(subst /,\,if exist $@ del $@)
+       @$(subst /,\,copy $(LEXYYC) $@)
+       @$(subst /,\,del $(LEXYYC))
+       @$(subst /,\,chdir $(SRC))
+else
+
+$(U)dgn_$(LEX).c: $(SSHR)/dgn_lex.c $(INCL)/dgn_comp.h
+       @echo ---
+       @echo For now, we will copy the prebuilt dgn_lex.c
+       @echo from $(SSHR) into $(U) and use it.
+       @$(subst /,\,copy $(SSHR)/dgn_lex.c $@)
+       @$(subst /,\,echo.>>$@)
+
+endif
+
+#==========================================
+#  Recover Utility
+#==========================================
+
+$(U)recover.exe:   $(RECOVOBJS)
+       $(LINK) $(LFLAGS) -o$@ $(O)recover.o
+
+$(O)recover.o:   $(CONFIG_H) $(U)recover.c
+       $(CC) $(cflags) -o$@ $(U)recover.c
+
+#==========================================
+#  Header file moves required for tile support
+#==========================================
+
+ifeq ($(SUPPRESS_GRAPHICS),Y)
+
+else
+#
+#  Tile Mapping
+#
+
+$(SRC)/tile.c: $(U)tilemap.exe
+       @$(subst /,\,$(U)tilemap.exe)
+       @echo A new $@ has been created
+
+$(U)tilemap.exe: $(O)tilemap.o
+       $(LINK) $(LFLAGS) -o$@ $(O)tilemap.o
+
+$(O)tilemap.o: $(WSHR)/tilemap.c $(HACK_H) $(TILE_H)
+       $(CC) $(cflags) -I$(WSHR) -I$(MSYS) -o$@ $(WSHR)/tilemap.c
+
+
+#==========================================
+#   Tile Utilities
+#  Required for tile support
+#==========================================
+
+$(DAT)/NetHack1.tib: $(TILEFILES) $(U)tile2bin.exe
+       @echo Creating binary tile files (this may take some time)
+       @$(subst /,\,chdir $(DAT))
+       @$(subst /,\,$(U)tile2bin.exe)
+       @$(subst /,\,chdir $(SRC))
+
+$(DAT)/NetHacko.tib: $(O)thintile.tag $(TILEFILES2) $(U)til2bin2.exe
+       @echo Creating overview binary tile files (this may take some time)
+       @$(subst /,\,chdir $(DAT))
+       @$(subst /,\,$(U)til2bin2.exe)
+       @$(subst /,\,chdir $(SRC))
+
+$(U)tile2bin.exe: $(O)tile2bin.o $(TEXTIO)
+       $(LINK) $(LFLAGS) -o$@ $(O)tile2bin.o $(TEXTIO)
+
+$(U)til2bin2.exe: $(O)til2bin2.o $(TEXTIO2)
+       $(LINK) $(LFLAGS) -o$@ $(O)til2bin2.o $(TEXTIO2)
+
+$(U)thintile.exe: $(O)thintile.o 
+       $(LINK) $(LFLAGS) -o$@ $(O)thintile.o
+
+$(O)thintile.o:  $(HACK_H) $(WSHR)/tile.h $(WSHR)/thintile.c
+       $(CC) $(cflags) -o$@ $(WSHR)/thintile.c
+
+$(O)thintile.tag: $(U)thintile.exe $(TILEFILES)
+       @$(subst /,\,$(U)thintile.exe)
+       @$(subst /,\,echo thintiles created >$@)
+
+$(O)tile2bin.o:  $(HACK_H) $(TILE_H) $(MSYS)/pctiles.h $(MSYS)/pcvideo.h $(MSYS)/tile2bin.c
+       $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/tile2bin.c
+
+$(O)til2bin2.o:  $(HACK_H) $(TILE_H) $(MSYS)/pctiles.h $(MSYS)/pcvideo.h $(MSYS)/tile2bin.c
+       $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILE_X=8 -DOVERVIEW_FILE -o$@ $(MSYS)/tile2bin.c
+
+$(O)tiletext.o:  $(CONFIG_H) $(TILE_H) $(WSHR)/tiletext.c
+       $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(WSHR)/tiletext.c
+
+$(O)tiletex2.o:  $(CONFIG_H) $(TILE_H) $(WSHR)/tiletext.c
+       $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILE_X=8 -o$@ $(WSHR)/tiletext.c
+
+$(O)tiletxt.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tilemap.c
+       $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILETEXT -o$@ $(WSHR)/tilemap.c
+  
+$(O)tiletxt2.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tilemap.c
+       $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILETEXT -DTILE_X=8 -o$@ $(WSHR)/tilemap.c
+#
+# Optional GIF Utilities (for development)
+#
+
+$(U)gif2txt.exe: $(GIFREADERS) $(TEXTIO)
+       $(LINK) $(LFLAGS) -o$@ $(GIFREADERS) $(TEXTIO)
+
+$(U)gif2txt2.exe: $(GIFREAD2) $(TEXTIO2)
+       $(LINK) $(LFLAGS) -o$@ $(GIFREAD2) $(TEXTIO2)
+
+$(U)txt2ppm.exe: $(PPMWRITERS) $(TEXTIO)
+       $(LINK) $(LFLAGS) -o$@ $(PPMWRITERS) $(TEXTIO)
+
+$(U)txt2ppm2.exe: $(PPMWRIT2) $(TEXTIO2)
+       $(LINK) $(LFLAGS) -o$@ $(PPMWRIT2) $(TEXTIO2)
+
+$(O)gifread.o: $(CONFIG_H) $(WSHR)/tile.h $(WSHR)/gifread.c
+
+$(O)gifread2.o: $(CONFIG_H) $(WSHR)/tile.h $(WSHR)/gifread.c
+       $(CC) $(cflags) -DTILE_X=8 -o$@ $(WSHR)/gifread.c
+
+ppmwrite.c: $(WSHR)/ppmwrite.c
+       @$(subst /,\,copy $(WSHR)/ppmwrite.c .)
+
+$(O)ppmwrite.o: $(CONFIG_H)    $(WSHR)/tile.h
+
+$(O)ppmwrit2.o:  $(CONFIG_H) $(WSHR)/tile.h ppmwrite.c
+       $(CC) $(cflags) -DTILE_X=8 -o$@ ppmwrite.c
+
+#
+#  Optional tile viewer (development sources only)
+#
+
+$(U)viewtib.exe: $(O)viewtib.o
+       $(LINK) $(LFLAGS) -o$@ $(O)viewtib.o $(LIBRARIES)
+
+$(O)viewtib.o: $(MSYS)/viewtib.c
+
+endif
+
+#==========================================
+#  Other Util Dependencies.
+#==========================================
+
+$(O)alloc.o: $(CONFIG_H)        alloc.c
+       $(CC) $(cflags) -o$@ alloc.c
+
+$(O)drawing.o: $(CONFIG_H) drawing.c $(MSYS)/pcvideo.h
+       $(CC) $(cflags) -I$(MSYS) -o$@ drawing.c
+
+$(O)decl.o: $(CONFIG_H) decl.c
+       $(CC) $(cflags) -o$@ decl.c
+
+$(O)monst.o: $(CONFIG_H)            $(PERMONST_H)      $(ESHK_H)          \
+       $(EPRI_H)             $(VAULT_H)         $(INCL)/monsym.h   \
+       $(INCL)/color.h  monst.c
+       $(CC) $(cflags) -o$@ monst.c
+
+$(O)objects.o: $(CONFIG_H)           $(INCL)/obj.h      $(INCL)/objclass.h \
+       $(INCL)/prop.h      $(INCL)/color.h    objects.c
+       $(CC) $(cflags) -o$@ objects.c
+
+$(O)panic.o:   $(CONFIG_H)       $(U)panic.c
+
+#============================================================
+# make data.base an 8.3 filename to prevent an make warning
+#============================================================
+
+DATABASE = $(DAT)/data.bas
+
+
+$(O)dat.tag: $(DAT)/nhdat
+       @$(subst /,\,echo dat done >$@)
+
+$(DAT)/data: $(O)utility.tag   $(DATABASE)
+       @$(subst /,\,$(U)makedefs.exe -d)
+
+$(DAT)/rumors:      $(O)utility.tag    $(DAT)/rumors.tru       $(DAT)/rumors.fal
+       @$(subst /,\,$(U)makedefs.exe -r)
+
+$(DAT)/quest.dat: $(O)utility.tag  $(DAT)/quest.txt
+       @$(subst /,\,$(U)makedefs.exe -q)
+
+$(DAT)/oracles:             $(O)utility.tag    $(DAT)/oracles.txt
+       @$(subst /,\,$(U)makedefs.exe -h)
+
+$(O)sp_lev.tag: $(O)utility.tag $(DAT)/bigroom.des  $(DAT)/castle.des \
+       $(DAT)/endgame.des $(DAT)/gehennom.des $(DAT)/knox.des \
+       $(DAT)/medusa.des  $(DAT)/oracle.des   $(DAT)/tower.des \
+       $(DAT)/yendor.des  $(DAT)/arch.des     $(DAT)/barb.des \
+       $(DAT)/caveman.des   $(DAT)/healer.des   $(DAT)/knight.des \
+       $(DAT)/monk.des      $(DAT)/priest.des   $(DAT)/ranger.des \
+       $(DAT)/rogue.des     $(DAT)/samurai.des  $(DAT)/tourist.des \
+       $(DAT)/valkyrie.des  $(DAT)/wizard.des
+       @$(subst /,\,cd $(DAT))
+       @$(subst /,\,$(U)lev_comp bigroom.des)
+       @$(subst /,\,$(U)lev_comp castle.des)
+       @$(subst /,\,$(U)lev_comp endgame.des)
+       @$(subst /,\,$(U)lev_comp gehennom.des)
+       @$(subst /,\,$(U)lev_comp knox.des)
+       @$(subst /,\,$(U)lev_comp mines.des)
+       @$(subst /,\,$(U)lev_comp medusa.des)
+       @$(subst /,\,$(U)lev_comp oracle.des)
+       @$(subst /,\,$(U)lev_comp sokoban.des)
+       @$(subst /,\,$(U)lev_comp tower.des)
+       @$(subst /,\,$(U)lev_comp yendor.des)
+       @$(subst /,\,$(U)lev_comp arch.des)
+       @$(subst /,\,$(U)lev_comp barb.des)
+       @$(subst /,\,$(U)lev_comp caveman.des)
+       @$(subst /,\,$(U)lev_comp healer.des)
+       @$(subst /,\,$(U)lev_comp knight.des)
+       @$(subst /,\,$(U)lev_comp monk.des)
+       @$(subst /,\,$(U)lev_comp priest.des)
+       @$(subst /,\,$(U)lev_comp ranger.des)
+       @$(subst /,\,$(U)lev_comp rogue.des)
+       @$(subst /,\,$(U)lev_comp samurai.des)
+       @$(subst /,\,$(U)lev_comp tourist.des)
+       @$(subst /,\,$(U)lev_comp valkyrie.des)
+       @$(subst /,\,$(U)lev_comp wizard.des)
+       @$(subst /,\,cd $(SRC))
+       @$(subst /,\,echo sp_levs done > $@)
+
+$(DAT)/dungeon:          $(O)utility.tag  $(DAT)/dungeon.def
+       @$(subst /,\,$(U)makedefs.exe -e)
+       @$(subst /,\,cd $(DAT))
+       @$(subst /,\,$(U)dgn_comp.exe dungeon.pdf)
+       @$(subst /,\,cd $(SRC))
+
+#==========================================
+# DLB stuff
+#==========================================
+
+#note that dir below assumes bin/dir.exe from djgpp distribution
+#
+$(DAT)/nhdat:  $(U)dlb_main.exe $(DAT)/data $(DAT)/rumors $(DAT)/dungeon \
+           $(DAT)/oracles $(DAT)/quest.dat $(O)sp_lev.tag
+       @$(subst /,\,echo dat done >$(O)dat.tag)
+       @$(subst /,\,cd $(DAT))
+       @$(subst /,\,copy $(MSYS)/msdoshlp.txt .)
+       @$(subst /,\,echo data >dlb.lst)
+       @$(subst /,\,echo dungeon >>dlb.lst)
+       @$(subst /,\,echo oracles >>dlb.lst)
+       @$(subst /,\,echo options >>dlb.lst)
+       @$(subst /,\,echo quest.dat >>dlb.lst)
+       @$(subst /,\,echo rumors >>dlb.lst)
+       @$(subst /,\,echo help >>dlb.lst)
+       @$(subst /,\,echo hh >>dlb.lst)
+       @$(subst /,\,echo cmdhelp >>dlb.lst)
+       @$(subst /,\,echo history >>dlb.lst)
+       @$(subst /,\,echo opthelp >>dlb.lst)
+       @$(subst /,\,echo wizhelp >>dlb.lst)
+       @$(subst /,\,echo license >>dlb.lst)
+       @$(subst /,\,echo msdoshlp.txt >>dlb.lst)
+       $(LS) $(subst /,\,*.lev) >>dlb.lst
+       @$(subst /,\,$(U)dlb_main cvIf dlb.lst nhdat)
+       @$(subst /,\,cd $(SRC))
+
+$(U)dlb_main.exe: $(DLBOBJS)
+       $(LINK) $(LFLAGS) -o$@ $(DLBOBJS)
+
+$(O)dlb_main.o: $(U)dlb_main.c $(INCL)/config.h $(DLB_H)
+       $(CC) $(cflags) -o$@ $(U)dlb_main.c
+
+#==========================================
+# Game Dependencies
+#==========================================
+
+# sys/share
+$(O)main.o:     $(HACK_H) $(DLB_H) $(SSHR)/pcmain.c
+       $(CC) $(cflags) -o$@ $(SSHR)/pcmain.c
+
+$(O)tty.o:      $(HACK_H) $(INCL)/wintty.h $(SSHR)/pctty.c
+       $(CC) $(cflags) -o$@ $(SSHR)/pctty.c
+
+$(O)unix.o:     $(HACK_H) $(SSHR)/pcunix.c
+       $(CC) $(cflags) -o$@ $(SSHR)/pcunix.c
+
+$(O)sys.o : $(HACK_H) $(SSHR)/pcsys.c
+       $(CC) $(cflags) -o$@ $(SSHR)/pcsys.c
+
+# sys/msdos
+$(O)msdos.o : $(HACK_H)  $(MSYS)/msdos.c
+#      $(CC) $(cflags) -o$@ $(MSYS)/msdos.c
+
+$(O)pckeys.o : $(HACK_H)  $(MSYS)/pckeys.c
+#      $(CC) $(cflags) -o$@ $(MSYS)/pckeys.c
+
+$(O)pctiles.o : $(HACK_H)  $(MSYS)/pctiles.c $(MSYS)/portio.h
+       $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/pctiles.c
+
+$(O)sound.o : $(HACK_H)  $(MSYS)/sound.c $(MSYS)/portio.h
+#      $(CC) $(cflags) -o$@ $(MSYS)/sound.c
+
+$(O)video.o : $(HACK_H)  $(MSYS)/pcvideo.h $(MSYS)/portio.h $(MSYS)/video.c
+#      $(CC) $(cflags) -o$@ -I$(MSYS) $(MSYS)/video.c
+
+$(O)vidvga.o : $(HACK_H)  $(MSYS)/pcvideo.h $(MSYS)/portio.h $(TILE_H) $(MSYS)/vidvga.c
+       $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/vidvga.c
+
+$(O)vidtxt.o : $(HACK_H)  $(MSYS)/pcvideo.h $(MSYS)/portio.h $(TILE_H) $(MSYS)/vidtxt.c
+#      $(CC) $(cflags) -o$@ -I$(MSYS) $(MSYS)/vidtxt.c
+
+$(O)stubvid.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/video.c
+       $(CC) $(cflags) -I$(MSYS) -DSTUBVIDEO -o$@ $(MSYS)/video.c
+
+
+# src dependencies
+
+#
+# The rest are stolen from sys/unix/Makefile.src,
+# with the following changes:
+#  o -c (which is included in cflags) substituted with -o$@ , 
+#  o an explicit build instruction for dlb.o because it requires 
+#    a .h file in ../sys/msdos.
+#  o the PATCHLEV_H macro is substitued for $(INCL)/patchlevel.h 
+#    to work around a long filename issue.
+#  o $(CFLAGS) changed to $(cflags)
+# Other than that, these dependencies are untouched.
+# That means that there is some irrelevant stuff
+# in here, but maintenance should be easier.
+#
+$(O)tos.o: ../sys/atari/tos.c $(HACK_H) $(INCL)/tcap.h
+       $(CC) $(cflags) -o$@ ../sys/atari/tos.c
+$(O)pcmain.o: ../sys/share/pcmain.c $(HACK_H) $(INCL)/dlb.h \
+               #$(INCL)/win32api.h
+       $(CC) $(cflags) -o$@ ../sys/share/pcmain.c
+$(O)pcsys.o: ../sys/share/pcsys.c $(HACK_H)
+       $(CC) $(cflags) -o$@ ../sys/share/pcsys.c
+$(O)pctty.o: ../sys/share/pctty.c $(HACK_H)
+       $(CC) $(cflags) -o$@ ../sys/share/pctty.c
+$(O)pcunix.o: ../sys/share/pcunix.c $(HACK_H)
+       $(CC) $(cflags) -o$@ ../sys/share/pcunix.c
+$(O)random.o: ../sys/share/random.c $(HACK_H)
+       $(CC) $(cflags) -o$@ ../sys/share/random.c
+$(O)ioctl.o: ../sys/share/ioctl.c $(HACK_H) $(INCL)/tcap.h
+       $(CC) $(cflags) -o$@ ../sys/share/ioctl.c
+$(O)unixtty.o: ../sys/share/unixtty.c $(HACK_H)
+       $(CC) $(cflags) -o$@ ../sys/share/unixtty.c
+$(O)unixmain.o: ../sys/unix/unixmain.c $(HACK_H) $(INCL)/dlb.h
+       $(CC) $(cflags) -o$@ ../sys/unix/unixmain.c
+$(O)unixunix.o: ../sys/unix/unixunix.c $(HACK_H)
+       $(CC) $(cflags) -o$@ ../sys/unix/unixunix.c
+$(O)unixres.o: ../sys/unix/unixres.c $(CONFIG_H)
+       $(CC) $(cflags) -o$@ ../sys/unix/unixres.c
+$(O)bemain.o: ../sys/be/bemain.c $(HACK_H) $(INCL)/dlb.h
+       $(CC) $(cflags) -o$@ ../sys/be/bemain.c
+$(O)getline.o: ../win/tty/getline.c $(HACK_H) $(INCL)/func_tab.h
+       $(CC) $(cflags) -o$@ ../win/tty/getline.c
+$(O)termcap.o: ../win/tty/termcap.c $(HACK_H) $(INCL)/tcap.h
+       $(CC) $(cflags) -o$@ ../win/tty/termcap.c
+$(O)topl.o: ../win/tty/topl.c $(HACK_H) $(INCL)/tcap.h
+       $(CC) $(cflags) -o$@ ../win/tty/topl.c
+$(O)wintty.o: ../win/tty/wintty.c $(HACK_H) $(INCL)/dlb.h \
+               $(PATCHLEV_H) $(INCL)/tcap.h
+       $(CC) $(cflags) -o$@ ../win/tty/wintty.c
+$(O)Window.o: ../win/X11/Window.c $(INCL)/xwindowp.h $(INCL)/xwindow.h \
+               $(CONFIG_H)
+       $(CC) $(cflags) -o$@ ../win/X11/Window.c
+$(O)dialogs.o: ../win/X11/dialogs.c $(CONFIG_H)
+       $(CC) $(cflags) -o$@ ../win/X11/dialogs.c
+$(O)winX.o: ../win/X11/winX.c $(HACK_H) $(INCL)/winX.h $(INCL)/dlb.h \
+               $(PATCHLEV_H) ../win/X11/nh72icon \
+               ../win/X11/nh56icon ../win/X11/nh32icon
+       $(CC) $(cflags) -o$@ ../win/X11/winX.c
+$(O)winmap.o: ../win/X11/winmap.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/dlb.h \
+               $(INCL)/winX.h $(INCL)/tile2x11.h
+       $(CC) $(cflags) -o$@ ../win/X11/winmap.c
+$(O)winmenu.o: ../win/X11/winmenu.c $(HACK_H) $(INCL)/winX.h
+       $(CC) $(cflags) -o$@ ../win/X11/winmenu.c
+$(O)winmesg.o: ../win/X11/winmesg.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/winX.h
+       $(CC) $(cflags) -o$@ ../win/X11/winmesg.c
+$(O)winmisc.o: ../win/X11/winmisc.c $(HACK_H) $(INCL)/func_tab.h \
+               $(INCL)/winX.h
+       $(CC) $(cflags) -o$@ ../win/X11/winmisc.c
+$(O)winstat.o: ../win/X11/winstat.c $(HACK_H) $(INCL)/winX.h
+       $(CC) $(cflags) -o$@ ../win/X11/winstat.c
+$(O)wintext.o: ../win/X11/wintext.c $(HACK_H) $(INCL)/winX.h $(INCL)/xwindow.h
+       $(CC) $(cflags) -o$@ ../win/X11/wintext.c
+$(O)winval.o: ../win/X11/winval.c $(HACK_H) $(INCL)/winX.h
+       $(CC) $(cflags) -o$@ ../win/X11/winval.c
+$(O)tile.o: tile.c $(HACK_H)
+$(O)gnaskstr.o: ../win/gnome/gnaskstr.c ../win/gnome/gnaskstr.h \
+               ../win/gnome/gnmain.h
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnaskstr.c
+$(O)gnbind.o: ../win/gnome/gnbind.c ../win/gnome/gnbind.h ../win/gnome/gnmain.h \
+               ../win/gnome/gnaskstr.h ../win/gnome/gnyesno.h
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnbind.c
+$(O)gnglyph.o: ../win/gnome/gnglyph.c ../win/gnome/gnglyph.h $(INCL)/tile2x11.h
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnglyph.c
+$(O)gnmain.o: ../win/gnome/gnmain.c ../win/gnome/gnmain.h ../win/gnome/gnsignal.h \
+               ../win/gnome/gnbind.h ../win/gnome/gnopts.h $(HACK_H) \
+               $(INCL)/date.h
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmain.c
+$(O)gnmap.o: ../win/gnome/gnmap.c ../win/gnome/gnmap.h ../win/gnome/gnglyph.h \
+               ../win/gnome/gnsignal.h $(HACK_H)
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmap.c
+$(O)gnmenu.o: ../win/gnome/gnmenu.c ../win/gnome/gnmenu.h ../win/gnome/gnmain.h \
+               ../win/gnome/gnbind.h
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmenu.c
+$(O)gnmesg.o: ../win/gnome/gnmesg.c ../win/gnome/gnmesg.h ../win/gnome/gnsignal.h
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmesg.c
+$(O)gnopts.o: ../win/gnome/gnopts.c ../win/gnome/gnopts.h ../win/gnome/gnglyph.h \
+               ../win/gnome/gnmain.h ../win/gnome/gnmap.h $(HACK_H)
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnopts.c
+$(O)gnplayer.o: ../win/gnome/gnplayer.c ../win/gnome/gnplayer.h \
+               ../win/gnome/gnmain.h $(HACK_H)
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnplayer.c
+$(O)gnsignal.o: ../win/gnome/gnsignal.c ../win/gnome/gnsignal.h \
+               ../win/gnome/gnmain.h
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnsignal.c
+$(O)gnstatus.o: ../win/gnome/gnstatus.c ../win/gnome/gnstatus.h \
+               ../win/gnome/gnsignal.h ../win/gnome/gn_xpms.h \
+               ../win/gnome/gnomeprv.h
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnstatus.c
+$(O)gntext.o: ../win/gnome/gntext.c ../win/gnome/gntext.h ../win/gnome/gnmain.h \
+               ../win/gnome/gn_rip.h
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gntext.c
+$(O)gnworn.o: ../win/gnome/gnworn.c ../win/gnome/gnworn.h ../win/gnome/gnglyph.h \
+               ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnworn.c
+$(O)gnyesno.o: ../win/gnome/gnyesno.c ../win/gnome/gnbind.h ../win/gnome/gnyesno.h
+       $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnyesno.c
+$(O)wingem.o: ../win/gem/wingem.c $(HACK_H) $(INCL)/func_tab.h $(INCL)/dlb.h \
+               $(PATCHLEV_H) $(INCL)/wingem.h
+       $(CC) $(cflags) -o$@ ../win/gem/wingem.c
+$(O)wingem1.o: ../win/gem/wingem1.c $(INCL)/gem_rsc.h $(INCL)/load_img.h \
+               $(INCL)/gr_rect.h $(INCL)/wintype.h $(INCL)/wingem.h
+       $(CC) $(cflags) -o$@ ../win/gem/wingem1.c
+$(O)load_img.o: ../win/gem/load_img.c $(INCL)/load_img.h
+       $(CC) $(cflags) -o$@ ../win/gem/load_img.c
+$(O)gr_rect.o: ../win/gem/gr_rect.c $(INCL)/gr_rect.h
+       $(CC) $(cflags) -o$@ ../win/gem/gr_rect.c
+$(O)tile.o: tile.c $(HACK_H)
+$(O)qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) $(INCL)/func_tab.h \
+               $(INCL)/dlb.h $(PATCHLEV_H) $(INCL)/tile2x11.h \
+               $(INCL)/qt_win.h $(INCL)/qt_clust.h $(INCL)/qt_kde0.h \
+               $(INCL)/qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc
+       $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_win.cpp
+$(O)qt_clust.o: ../win/Qt/qt_clust.cpp $(INCL)/qt_clust.h
+       $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_clust.cpp
+$(O)qttableview.o: ../win/Qt/qttableview.cpp $(INCL)/qttableview.h
+       $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qttableview.cpp
+$(O)monstr.o: monstr.c $(CONFIG_H)
+$(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)/vis_tab.h
+$(O)allmain.o: allmain.c $(HACK_H)
+$(O)alloc.o: alloc.c $(CONFIG_H)
+$(O)apply.o: apply.c $(HACK_H) $(INCL)/edog.h
+$(O)artifact.o: artifact.c $(HACK_H) $(INCL)/artifact.h $(INCL)/artilist.h
+$(O)attrib.o: attrib.c $(HACK_H)
+$(O)ball.o: ball.c $(HACK_H)
+$(O)bones.o: bones.c $(HACK_H) $(INCL)/lev.h
+$(O)botl.o: botl.c $(HACK_H)
+$(O)cmd.o: cmd.c $(HACK_H) $(INCL)/func_tab.h
+$(O)dbridge.o: dbridge.c $(HACK_H)
+$(O)decl.o: decl.c $(HACK_H)
+$(O)detect.o: detect.c $(HACK_H) $(INCL)/artifact.h
+$(O)dig.o: dig.c $(HACK_H) $(INCL)/edog.h
+$(O)display.o: display.c $(HACK_H)
+$(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)/dlb.h
+       $(CC) $(cflags) -I../sys/msdos -o$@ dlb.c
+$(O)do.o: do.c $(HACK_H) $(INCL)/lev.h
+$(O)do_name.o: do_name.c $(HACK_H)
+$(O)do_wear.o: do_wear.c $(HACK_H)
+$(O)dog.o: dog.c $(HACK_H) $(INCL)/edog.h
+$(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/edog.h
+$(O)dokick.o: dokick.c $(HACK_H) $(INCL)/eshk.h
+$(O)dothrow.o: dothrow.c $(HACK_H)
+$(O)drawing.o: drawing.c $(HACK_H) $(INCL)/tcap.h
+$(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)/dgn_file.h $(INCL)/dlb.h
+$(O)eat.o: eat.c $(HACK_H)
+$(O)end.o: end.c $(HACK_H) $(INCL)/eshk.h $(INCL)/dlb.h
+$(O)engrave.o: engrave.c $(HACK_H) $(INCL)/lev.h
+$(O)exper.o: exper.c $(HACK_H)
+$(O)explode.o: explode.c $(HACK_H)
+$(O)extralev.o: extralev.c $(HACK_H)
+$(O)files.o: files.c $(HACK_H) $(INCL)/dlb.h
+$(O)fountain.o: fountain.c $(HACK_H)
+$(O)hack.o: hack.c $(HACK_H)
+$(O)hacklib.o: hacklib.c $(HACK_H)
+$(O)invent.o: invent.c $(HACK_H)
+$(O)light.o: light.c $(HACK_H) $(INCL)/lev.h
+$(O)lock.o: lock.c $(HACK_H)
+$(O)mail.o: mail.c $(HACK_H) $(INCL)/mail.h
+$(O)makemon.o: makemon.c $(HACK_H) $(INCL)/epri.h $(INCL)/emin.h \
+               $(INCL)/edog.h
+$(O)mapglyph.o: mapglyph.c $(HACK_H)
+$(O)mcastu.o: mcastu.c $(HACK_H)
+$(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)/artifact.h $(INCL)/edog.h
+$(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)/artifact.h $(INCL)/edog.h
+$(O)minion.o: minion.c $(HACK_H) $(INCL)/emin.h $(INCL)/epri.h
+$(O)mklev.o: mklev.c $(HACK_H)
+$(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)/sp_lev.h
+$(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)/sp_lev.h $(INCL)/lev.h
+$(O)mkobj.o: mkobj.c $(HACK_H)
+$(O)mkroom.o: mkroom.c $(HACK_H)
+$(O)mon.o: mon.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/edog.h
+$(O)mondata.o: mondata.c $(HACK_H) $(INCL)/eshk.h $(INCL)/epri.h
+$(O)monmove.o: monmove.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/artifact.h \
+               $(INCL)/epri.h
+$(O)monst.o: monst.c $(CONFIG_H) $(INCL)/permonst.h $(INCL)/align.h \
+               $(INCL)/monattk.h $(INCL)/monflag.h $(INCL)/monsym.h \
+               $(INCL)/dungeon.h $(INCL)/eshk.h $(INCL)/vault.h \
+               $(INCL)/epri.h $(INCL)/color.h
+$(O)mplayer.o: mplayer.c $(HACK_H)
+$(O)mthrowu.o: mthrowu.c $(HACK_H)
+$(O)muse.o: muse.c $(HACK_H) $(INCL)/edog.h
+$(O)music.o: music.c $(HACK_H) #interp.c
+$(O)o_init.o: o_init.c $(HACK_H) $(INCL)/lev.h
+$(O)objects.o: objects.c $(CONFIG_H) $(INCL)/obj.h $(INCL)/objclass.h \
+               $(INCL)/prop.h $(INCL)/skills.h $(INCL)/color.h
+$(O)objnam.o: objnam.c $(HACK_H)
+$(O)options.o: options.c $(CONFIG_H) $(INCL)/objclass.h $(INCL)/flag.h \
+               $(HACK_H) $(INCL)/tcap.h
+$(O)pager.o: pager.c $(HACK_H) $(INCL)/dlb.h
+$(O)pickup.o: pickup.c $(HACK_H)
+$(O)pline.o: pline.c $(HACK_H) $(INCL)/epri.h $(INCL)/edog.h
+$(O)polyself.o: polyself.c $(HACK_H)
+$(O)potion.o: potion.c $(HACK_H)
+$(O)pray.o: pray.c $(HACK_H) $(INCL)/epri.h
+$(O)priest.o: priest.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/eshk.h \
+               $(INCL)/epri.h $(INCL)/emin.h
+$(O)quest.o: quest.c $(HACK_H) $(INCL)/qtext.h
+$(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)/dlb.h $(INCL)/qtext.h
+$(O)read.o: read.c $(HACK_H)
+$(O)rect.o: rect.c $(HACK_H)
+$(O)region.o: region.c $(HACK_H) $(INCL)/lev.h
+$(O)restore.o: restore.c $(HACK_H) $(INCL)/lev.h $(INCL)/tcap.h
+$(O)rip.o: rip.c $(HACK_H)
+$(O)rnd.o: rnd.c $(HACK_H)
+$(O)role.o: role.c $(HACK_H)
+$(O)rumors.o: rumors.c $(HACK_H) $(INCL)/lev.h $(INCL)/dlb.h
+$(O)save.o: save.c $(HACK_H) $(INCL)/lev.h
+$(O)shk.o: shk.c $(HACK_H) $(INCL)/eshk.h
+$(O)shknam.o: shknam.c $(HACK_H) $(INCL)/eshk.h
+$(O)sit.o: sit.c $(HACK_H) $(INCL)/artifact.h
+$(O)sounds.o: sounds.c $(HACK_H) $(INCL)/edog.h
+$(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)/dlb.h $(INCL)/sp_lev.h
+$(O)spell.o: spell.c $(HACK_H)
+$(O)steal.o: steal.c $(HACK_H)
+$(O)steed.o: steed.c $(HACK_H)
+$(O)teleport.o: teleport.c $(HACK_H)
+$(O)timeout.o: timeout.c $(HACK_H) $(INCL)/lev.h
+$(O)topten.o: topten.c $(HACK_H) $(INCL)/dlb.h $(PATCHLEV_H)
+$(O)track.o: track.c $(HACK_H)
+$(O)trap.o: trap.c $(HACK_H)
+$(O)u_init.o: u_init.c $(HACK_H)
+$(O)uhitm.o: uhitm.c $(HACK_H)
+$(O)vault.o: vault.c $(HACK_H) $(INCL)/vault.h
+$(O)version.o: version.c $(HACK_H) $(INCL)/date.h $(PATCHLEV_H)
+$(O)vision.o: vision.c $(HACK_H) $(INCL)/vis_tab.h
+$(O)weapon.o: weapon.c $(HACK_H)
+$(O)were.o: were.c $(HACK_H)
+$(O)wield.o: wield.c $(HACK_H)
+$(O)windows.o: windows.c $(HACK_H) $(INCL)/wingem.h $(INCL)/winGnome.h
+$(O)wizard.o: wizard.c $(HACK_H) $(INCL)/qtext.h $(INCL)/epri.h
+$(O)worm.o: worm.c $(HACK_H) $(INCL)/lev.h
+$(O)worn.o: worn.c $(HACK_H)
+$(O)write.o: write.c $(HACK_H)
+$(O)zap.o: zap.c $(HACK_H)
+
+# end of file
+
diff --git a/sys/msdos/Makefile.MSC b/sys/msdos/Makefile.MSC
new file mode 100644 (file)
index 0000000..53d418a
--- /dev/null
@@ -0,0 +1,1113 @@
+#      SCCS Id: @(#)Makefile.MSC             3.4     2002/09/10
+#      Copyright (c) NetHack PC Development Team 1997 - 2002.
+#      PC NetHack 3.3x Makefile for MSC V1.52c (16 bit compiler)
+#
+#      For questions or comments: nethack-bugs@nethack.org
+#
+#      In addition to your C compiler,
+#
+#       if you want to change        you will need a
+#       files with suffix            workalike for
+#            .y                        yacc
+#            .l                        lex
+#
+#
+
+# Game Installation Variables
+# NOTE: Make sure GAMEDIR exists before make is started.
+
+GAME = nethack
+GAMEDIR =..\binary
+
+#
+# Directories
+#
+
+DAT  = ..\dat
+DOC  = ..\doc
+INCL = ..\include
+MSYS = ..\sys\msdos
+SRC  = ..\src
+SSHR = ..\sys\share
+UTIL = ..\util
+WIN  = ..\win\tty
+WSHR = ..\win\share
+
+#
+#  Executables.
+
+CC    = cl
+LINK  = link
+MAKEBIN  = nmake
+
+# if you have a uudecode program, add its name here
+# otherwise leave blank
+UUDECODE =
+
+#
+#  Yacc/Lex ... if you got 'em.
+#
+# If you have yacc/lex or a work-alike set YACC_LEX to Y
+#
+YACC_LEX = N
+
+# If YACC_LEX is Y above, set the following to values appropriate for
+# your tools.
+#
+YACC   = bison -y
+LEX    = flex
+YTABC  = y_tab.c
+YTABH  = y_tab.h
+LEXYYC = lexyy.c
+
+
+#
+# Uncomment this line if you want to include support for ALT-numeric
+# sequences, such as ALT-2 for toggling #twoweapon mode.  
+# Note that this code did not get a thorough testing prior to 3.4.x
+#NEWALT=/DNEW_ALT
+
+#############################################################################
+#
+# nothing below this line should have to be changed
+#
+
+LNKOPT = SCHEMA3.DEF
+
+#
+# Controls whether MOVE tracing is enabled in the executable
+# This should be left commented unless you are tinkering with the
+# overlay structure of NetHack.  The executable runs _very_
+# slowly when the movetr.lib is linked in.
+#
+
+#MOVETR= movetr.lib
+
+# do not change this
+! IF ("$(MOVETR)"!="")
+MVTRCL = /DMOVE_PROF
+! ELSE
+MVTRCL =
+! ENDIF
+
+#
+# Uncomment the line below if you want to store all the level files,
+# help files, etc. in a single library file.
+
+USE_DLB = Y
+
+! IF ("$(USE_DLB)"=="Y")
+DLBFLG = -DDLB
+! ELSE
+DLBFLG =
+! ENDIF
+
+LIBRARIES = $(LIBS) $(TERMLIB)
+
+GAMEFILE = $(GAMEDIR)\$(GAME).exe
+
+#
+#  Flags.
+#
+# Debugging
+#CFLAGS = /Zi /DFUNCTION_LEVEL_LINKING /DUSE_TILES /DDLB
+#LFLAGS = /CODEVIEW /NOI/MAP /CPARM:1 /INFO
+
+#    Normal
+LFLAGS = /NOI/MAP /CPARM:1 /INFO
+CFLAGS = /DFUNCTION_LEVEL_LINKING /DUSE_TILES /DDLB
+SPECOPTS =
+#
+# Leaving MACHINE_CODE undefined will allow it to run
+# on any Intel 8088 machines and above.
+# Set to 1 for 80186 and above only
+# Set to 2 for 80286 and above only
+# Set to 3 for 80386 and above only
+# 
+MACHINE_CODE = 
+
+#
+#  Utility Objects.
+#
+#
+# Shorten up the location for some files
+#
+
+O  = $(OBJ)\                           # comment so \ isn't last char
+
+U  = $(UTIL)\                          # comment so \ isn't last char
+
+SPLEVDES = $(DAT)\Arch.des $(DAT)\Barb.des $(DAT)\bigroom.des \
+       $(DAT)\castle.des $(DAT)\Caveman.des $(DAT)\endgame.des \
+       $(DAT)\gehennom.des $(DAT)\Healer.des $(DAT)\Knight.des \
+       $(DAT)\knox.des $(DAT)\Monk.des $(DAT)\medusa.des \
+       $(DAT)\mines.des $(DAT)\oracle.des $(DAT)\Priest.des \
+       $(DAT)\Ranger.des $(DAT)\Rogue.des $(DAT)\Samurai.des \
+       $(DAT)\Tourist.des $(DAT)\tower.des $(DAT)\Valkyrie.des \
+       $(DAT)\Wizard.des $(DAT)\yendor.des
+
+VGAOBJ      = vidvga.o
+
+MAKESRC            = $(U)makedefs.c
+
+SPLEVSRC    = $(U)lev_yacc.c  $(U)lev_$(LEX).c  $(U)lev_main.c  \
+               $(U)panic.c
+
+DGNCOMPSRC  = $(U)dgn_yacc.c  $(U)dgn_$(LEX).c  $(U)dgn_main.c
+
+MAKEOBJS    = makedefs.o  monst.o       objects.o
+
+SPLEVOBJS   = lev_yacc.o  lev_$(LEX).o lev_main.o  alloc.o     \
+               monst.o     objects.o       panic.o  \
+               drawing.o       decl.o  stubvid.o
+
+DGNCOMPOBJS = dgn_yacc.o  dgn_$(LEX).o dgn_main.o  alloc.o      \
+               panic.o
+
+RECOVOBJS   = recover.o
+
+
+#  Tile related object files.
+
+TILOBJ      = tile.o pctiles.o $(VGAOBJ)
+
+TEXTIO      = tiletext.o tiletxt.o drawing.o decl.o monst.o objects.o stubvid.o
+
+TEXTIO2     = tiletex2.o tiletxt2.o drawing.o decl.o monst.o objects.o stubvid.o
+
+
+PLANAR_TIB  = NetHack1.tib
+
+OVERVIEW_TIB = NetHacko.tib
+
+TILEUTIL    = $(TILOBJ) tile2bin.exe til2bin2.exe $(PLANAR_TIB) $(OVERVIEW_TIB)
+
+TILEFILES   = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt
+
+TILEFILES2  = $(WSHR)\monthin.txt $(WSHR)\objthin.txt $(WSHR)\oththin.txt
+
+GIFREADERS  = gifread.o alloc.o panic.o
+
+GIFREAD2    = gifread2.o alloc.o panic.o
+
+PPMWRITERS  = ppmwrite.o alloc.o panic.o
+
+PPMWRIT2    = ppmwrit2.o alloc.o panic.o
+
+DLBOBJS     = dlb_main.o dlb.o alloc.o panic.o
+
+#  Object files for the game itself.
+
+VOBJ01 = allmain.o  alloc.o    apply.o   artifact.o attrib.o
+VOBJ02 = ball.o            bones.o    botl.o     cmd.o      dbridge.o
+VOBJ03 = decl.o            detect.o   display.o  do.o       do_name.o
+VOBJ04 = do_wear.o  dog.o      dogmove.o  dokick.o   dothrow.o
+VOBJ05 = drawing.o  dungeon.o  eat.o     end.o      engrave.o
+VOBJ06 = exper.o    explode.o  extralev.o files.o    fountain.o
+VOBJ07 = getline.o  hack.o     hacklib.o  invent.o   lock.o
+VOBJ08 = mail.o            main.o     makemon.o  mapglyph.o mcastu.o   mhitm.o
+VOBJ09 = mhitu.o    minion.o   mkmap.o   mklev.o    mkmaze.o
+VOBJ10 = mkobj.o    mkroom.o   mon.o     mondata.o  monmove.o
+VOBJ11 = monst.o    monstr.o   mplayer.o  mthrowu.o  muse.o
+VOBJ12 = music.o    o_init.o   objects.o  objnam.o   options.o
+VOBJ13 = pickup.o   pline.o    polyself.o potion.o   quest.o
+VOBJ14 = questpgr.o pager.o    pray.o    priest.o   read.o
+VOBJ15 = rect.o            restore.o  rip.o      rnd.o      role.o
+VOBJ16 = rumors.o   save.o        shk.o      shknam.o   sit.o
+VOBJ17 = sounds.o   sp_lev.o   spell.o    steal.o       steed.o
+VOBJ18 = termcap.o  timeout.o  topl.o    topten.o   track.o
+VOBJ19 = trap.o     u_init.o   uhitm.o    vault.o    vision.o
+VOBJ20 = vis_tab.o  weapon.o   were.o    wield.o    windows.o
+VOBJ21 = wintty.o   wizard.o   worm.o    worn.o     write.o
+VOBJ22 = zap.o     light.o    dlb.o      dig.o      teleport.o
+VOBJ23 = random.o   region.o
+
+SOBJ   = msdos.o    sound.o    sys.o     tty.o      unix.o    video.o \
+       vidtxt.o    pckeys.o
+
+VVOBJ  = version.o
+
+VOBJ   = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \
+       $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \
+       $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \
+       $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \
+       $(VOBJ21) $(VOBJ22) $(VOBJ23)
+
+ALLOBJ = $(VOBJ) $(SOBJ) $(TILOBJ) $(VVOBJ)
+
+#
+#  Header Objects.
+#
+
+DGN_FILE_H = $(INCL)\align.h   $(INCL)\dgn_file.h
+DUNGEON_H  = $(INCL)\align.h   $(INCL)\dungeon.h
+EMIN_H    = $(DUNGEON_H)       $(INCL)\emin.h
+EPRI_H    = $(DUNGEON_H)       $(INCL)\align.h     $(INCL)\epri.h
+ESHK_H    = $(DUNGEON_H)       $(INCL)\eshk.h
+MONDATA_H  = $(INCL)\align.h   $(INCL)\mondata.h
+MONST_H           = $(INCL)\align.h    $(INCL)\monst.h
+PERMONST_H = $(INCL)\monattk.h $(INCL)\monflag.h   $(INCL)\align.h   \
+           $(INCL)\permonst.h
+RM_H      = $(INCL)\align.h    $(INCL)\rm.h
+SP_LEV_H   = $(INCL)\align.h   $(INCL)\sp_lev.h
+VAULT_H           = $(DUNGEON_H)       $(INCL)\vault.h
+YOUPROP_H  = $(PERMONST_H)     $(MONDATA_H)        $(INCL)\prop.h    \
+           $(INCL)\pm.h       $(INCL)\youprop.h
+YOU_H     = $(MONST_H)         $(YOUPROP_H)        $(INCL)\align.h   \
+            $(INCL)\attrib.h   $(INCL)\you.h
+DISPLAY_H  = $(MONDATA_H)      $(INCL)\vision.h    $(INCL)\display.h
+PCCONF_H   = $(INCL)\micro.h   $(INCL)\system.h    $(INCL)\pcconf.h \
+           $(MSYS)\pcvideo.h
+CONFIG_H   = $(GLOBAL_H)       $(INCL)\tradstdc.h  $(INCL)\config1.h \
+           $(INCL)\config.h
+DECL_H    = $(YOU_H)           $(INCL)\spell.h     $(INCL)\color.h   \
+            $(INCL)\obj.h      $(INCL)\onames.h    $(INCL)\pm.h      \
+             $(INCL)\decl.h
+GLOBAL_H   = $(PCCONF_H)       $(INCL)\coord.h     $(INCL)\global.h
+HACK_H    = $(CONFIG_H)        $(DUNGEON_H)        $(DECL_H)         \
+              $(DISPLAY_H)       $(INCL)\monsym.h    $(INCL)\mkroom.h  \
+             $(INCL)\objclass.h $(INCL)\trap.h      $(INCL)\flag.h    \
+             $(RM_H)            $(INCL)\vision.h    $(INCL)\wintype.h \
+             $(INCL)\engrave.h  $(INCL)\rect.h   \
+              $(INCL)\trampoli.h $(INCL)\hack.h
+DLB_H      = $(INCL)\dlb.h
+TILE_H    = $(WSHR)\tile.h $(MSYS)\pctiles.h
+
+
+# Make Roolz dude.
+# Due to the inadequacy of some makes these must accord with a
+# topological sort of the generated-from relation... output on
+# the left, input on the right. Trust me.
+#
+
+.SUFFIXES:  .exe .o .til .uu .c .y .l
+
+#
+# Rules for files in src
+#
+
+
+.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+.c.o:
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+{$(SRC)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+{$(SRC)}.c.o:
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+#
+# Rules for files in sys\share
+#
+
+{$(SYS)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+{$(SYS)}.c.o:
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+#
+# Rules for files in sys\msdos
+#
+
+{$(MSYS)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+{$(MSYS)}.c.o:
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+{$(MSYS)}.h{$(INCL)}.h:
+       @copy $< $@
+
+#
+# Rules for files in util
+#
+
+{$(UTIL)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+{$(UTIL)}.c.o:
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+#
+# Rules for files in win\share
+#
+
+{$(WSHR)}.c.o:
+       @@$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+{$(WSHR)}.c{$(OBJ)}.o:
+       @@$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+{$(WSHR)}.h{$(INCL)}.h:
+       @copy $< $@
+
+{$(WSHR)}.txt{$(DAT)}.txt:
+       @copy $< $@
+
+#
+# Rules for files in win\tty
+#
+
+{$(WTTY)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+{$(WTTY)}.c.o:
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $<
+
+
+! IF ("$(USE_DLB)"=="Y")
+DLB = nhdat
+! ELSE
+DLB =
+! ENDIF
+
+########################################################
+#  
+# TARGETS
+
+
+#
+#  The default make target (so just typing 'nmake' is useful).
+#
+default : envchk $(GAMEFILE)
+
+#  The default target.
+
+$(GAME): $(O)utility.tag $(GAMEFILE)
+       @echo $(GAME) is up to date.
+
+#
+#  Everything
+#
+
+all: install
+
+install: envchk $(GAME) $(O)install.tag
+       @echo Done.
+
+$(O)install.tag:       $(DAT)\data     $(DAT)\rumors    $(DAT)\dungeon \
+               $(DAT)\oracles  $(DAT)\quest.dat $(O)sp_lev.tag $(DLB)
+! IF ("$(USE_DLB)"=="Y")
+       copy $(SRC)\nhdat         $(GAMEDIR)
+       copy $(DAT)\license       $(GAMEDIR)
+! ELSE
+       copy $(DAT)\*.            $(GAMEDIR)
+       copy $(DAT)\*.dat         $(GAMEDIR)
+       copy $(DAT)\*.lev         $(GAMEDIR)
+       if exist $(GAMEDIR)\makefile del $(GAMEDIR)\makefile
+! ENDIF
+       copy $(SSHR)\termcap      $(GAMEDIR)
+       copy *.tib                $(GAMEDIR)
+       copy $(SSHR)\NetHack.cnf  $(GAMEDIR)\defaults.nh
+       copy $(MSYS)\NHAccess.nh  $(GAMEDIR)
+       copy $(U)recover.exe          $(GAMEDIR)
+       if exist $(DOC)\guideb*.txt copy $(DOC)\guideb*.txt $(GAMEDIR)
+       if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR)
+       if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt $(GAMEDIR)
+       echo install done > $@
+
+$(O)sp_lev.tag: $(O)utility.tag $(SPLEVDES)
+       cd $(DAT)
+       $(U)lev_comp bigroom.des
+       $(U)lev_comp castle.des
+       $(U)lev_comp endgame.des
+       $(U)lev_comp gehennom.des
+       $(U)lev_comp knox.des
+       $(U)lev_comp mines.des
+       $(U)lev_comp medusa.des
+       $(U)lev_comp oracle.des
+       $(U)lev_comp sokoban.des
+       $(U)lev_comp tower.des
+       $(U)lev_comp yendor.des
+       $(U)lev_comp arch.des
+       $(U)lev_comp barb.des
+       $(U)lev_comp caveman.des
+       $(U)lev_comp healer.des
+       $(U)lev_comp knight.des
+       $(U)lev_comp monk.des
+       $(U)lev_comp priest.des
+       $(U)lev_comp ranger.des
+       $(U)lev_comp rogue.des
+       $(U)lev_comp samurai.des
+       $(U)lev_comp tourist.des
+       $(U)lev_comp valkyrie.des
+       $(U)lev_comp wizard.des
+       cd $(SRC)
+#      -@if exist $(O)sp_lev.tag del $(O)sp_lev.tag
+       @echo sp_levs done >$(O)sp_lev.tag
+       
+$(O)utility.tag: $(INCL)\date.h $(INCL)\trap.h  \
+        $(INCL)\onames.h $(INCL)\pm.h monstr.c vis_tab.c \
+       $(U)lev_comp.exe $(U)dgn_comp.exe $(U)recover.exe $(TILEUTIL)
+       -@if exist $(O)utility.tag del $(O)utility.tag
+       @echo utilities made > $@
+
+tileutil: gif2txt.exe txt2ppm.exe
+       @echo Optional tile development utilities are up to date.
+
+.PHONEY: envchk
+
+envchk:
+!      IF ("$(MACHINE_CODE)"!="")
+          @SET MC=/G$(MACHINE_CODE)
+!      ELSE
+          @SET MC=
+!      ENDIF
+!      IF ("$(CL)"=="")
+          @echo CL Environment variable is defined as follows:
+          SET CL=/AL $(MC) /Oo /Gy /Gs /Gt14 /Zp1 /W0 /I$(INCL) /I$(MSYS) /I$(WSHR) /nologo /c
+!      ELSE
+          @echo Warning CL Environment variable is defined:
+          @echo CL=$(CL)
+          @echo Overriding that definition as follows:
+          SET CL=/AL $(MC) /Oo /Gy /Gs /Gt14 /Zp1 /W0 /I$(INCL) /I$(MSYS) /I$(WSHR) /nologo /c
+!      ENDIF
+
+#  The main target.
+
+$(GAMEFILE) :  $(LNKOPT) $(ALLOBJ)
+       @echo Linking....
+       $(LINK) $(LFLAGS) /SE:1000 /DYNAMIC:2135 /NOE /ST:6000 @<<$(GAME).lnk
+               $(ALLOBJ:^      =+^
+               )
+               $(GAMEFILE)
+               $(GAME)
+               $(TERMLIB) $(MOVETR) $(CLIB) $(BCOVL) $(BCMDL)
+               $(LNKOPT);
+<<
+       @if exist $(O)install.tag del $(O)install.tag
+       @if exist $(GAMEDIR)\$(GAME).bak del $(GAMEDIR)\$(GAME).bak
+
+#
+#  Housekeeping.
+#
+
+clean:
+       del *.o
+       del *.map
+       del $(U)dlb_main.exe
+
+spotless: clean
+       if exist $(O)utility.tag           del $(O)utility.tag
+       if exist $(O)install.tag   del $(O)install.tag
+       if exist $(GAME).lnk       del $(GAME).lnk
+       if exist $(U)makedefs.exe  del $(U)makedefs.exe
+       if exist $(U)lev_comp.exe  del $(U)lev_comp.exe
+       if exist $(U)dgn_comp.exe  del $(U)dgn_comp.exe
+       if exist $(SRC)\lev_lex.c  del $(SRC)\lev_lex.c
+       if exist $(SRC)\lev_yacc.c del $(SRC)\lev_yacc.c
+       if exist $(SRC)\dgn_lex.c  del $(SRC)\dgn_lex.c
+       if exist $(SRC)\dgn_yacc.c del $(SRC)\dgn_yacc.c
+       if exist $(U)recover.exe   del $(U)recover.exe
+       if exist $(INCL)\onames.h  del $(INCL)\onames.h
+       if exist $(INCL)\pm.h      del $(INCL)\pm.h
+       if exist $(INCL)\vis_tab.h del $(INCL)\vis_tab.h
+       if exist $(INCL)\pcvideo.h del $(INCL)\pcvideo.h
+       if exist $(MSYS)\pctiles.h del $(MSYS)\pctiles.h
+       if exist $(INCL)\portio.h  del $(MSYS)\portio.h
+       if exist $(WSHR)\tile.h    del $(WSHR)\tile.h
+       if exist monstr.c          del monstr.c
+       if exist vis_tab.c         del vis_tab.c
+       if exist $(SRC)\panic.c    del $(SRC)\panic.c
+       if exist $(SRC)\makedefs.c del $(SRC)\makedefs.c
+       if exist $(SRC)\recover.c  del $(SRC)\recover.c
+       if exist $(SRC)\lev_main.c del $(SRC)\lev_main.c
+       if exist $(SRC)\dlb_main.c del $(SRC)\dlb_main.c
+       if exist $(SRC)\dgn_main.c del $(SRC)\dgn_main.c
+       if exist $(SRC)\wintty.c   del $(SRC)\wintty.c
+       if exist $(SRC)\topl.c     del $(SRC)\topl.c
+       if exist $(SRC)\getline.c  del $(SRC)\getline.c
+       if exist $(SRC)\termcap.c  del $(SRC)\termcap.c
+       if exist $(SRC)\tile2bin.c del $(SRC)\tile2bin.c
+       if exist $(SRC)\msdos.c    del $(SRC)\msdos.c
+       if exist $(SRC)\pckeys.c   del $(SRC)\pckeys.c
+       if exist $(SRC)\video.c    del $(SRC)\video.c
+       if exist $(SRC)\sound.c    del $(SRC)\sound.c
+       if exist $(SRC)\tilemap.c  del $(SRC)\tilemap.c
+       if exist $(SRC)\gifread.c  del $(SRC)\gifread.c
+       if exist $(SRC)\ppmwrite.c del $(SRC)\ppmwrite.c
+       if exist $(SRC)\pcmain.c   del $(SRC)\pcmain.c
+       if exist $(SRC)\pcunix.c   del $(SRC)\pcunix.c
+       if exist $(SRC)\pcsys.c    del $(SRC)\pcsys.c
+       if exist $(SRC)\pctty.c    del $(SRC)\pctty.c
+       if exist $(SRC)\tile.c     del $(SRC)\tile.c
+       if exist $(INCL)\date.h    del $(INCL)\date.h
+       if exist $(INCL)\onames.h  del $(INCL)\onames.h
+       if exist $(INCL)\pm.h      del $(INCL)\pm.h
+       if exist $(INCL)\vis_tab.h del $(INCL)\vis_tab.h
+       if exist vis_tab.c         del vis_tab.c
+       if exist *.lnk             del *.lnk
+       if exist *.def             del *.def
+       if exist *.map             del *.map
+       if exist a.out             del a.out
+       if exist tilemap.exe       del tilemap.exe
+       if exist tile2bin.exe      del tile2bin.exe
+       if exist $(DAT)\data       del $(DAT)\data
+       if exist $(DAT)\*.lev      del $(DAT)\*.lev
+       if exist $(DAT)\data       del $(DAT)\data
+       if exist $(DAT)\dungeon    del $(DAT)\dungeon
+       if exist $(DAT)\options    del $(DAT)\options
+       if exist $(DAT)\oracles    del $(DAT)\oracles
+       if exist $(DAT)\rumors     del $(DAT)\rumors
+       if exist $(DAT)\quest.dat  del $(DAT)\quest.dat
+       if exist $(SRC)\nhdat      del $(SRC)\nhdat
+       if exist $(DAT)\dlb.lst    del $(DAT)\dlb.lst
+       if exist $(DAT)\msdoshlp.txt del $(DAT)\msdoshlp.txt
+       if exist $(DAT)\dlb_main.exe del $(DAT)\dlb_main.exe
+       if exist $(DAT)\lev_comp.exe del $(DAT)\lev_comp.exe
+       if exist $(DAT)\dgn_comp.exe del $(DAT)\dgn_comp.exe
+       if exist $(O)sp_lev.tag        del $(O)sp_lev.tag
+       if exist $(PLANAR_TIB)     del $(PLANAR_TIB)
+       if exist $(OVERVIEW_TIB)   del $(OVERVIEW_TIB)
+
+
+#
+#  Secondary Targets.
+#
+#
+#  Makedefs Stuff
+#
+
+$(U)makedefs.exe:  $(MAKEOBJS)
+        @echo Linking....
+        @$(LINK) $(LFLAGS) @<<$(@B).lnk
+                $(MAKEOBJS:^      =+^
+                )
+                $@
+                $(@B)
+                ;
+<<
+
+makedefs.o:  $(CONFIG_H)       $(PERMONST_H)      $(INCL)\objclass.h \
+               $(INCL)\monsym.h   $(INCL)\qtext.h $(UTIL)\makedefs.c
+
+#  The following include files depend on makedefs to be created.
+#
+#  date.h should be remade every time any of the source or include
+#  files is modified.
+
+
+$(INCL)\date.h : $(U)makedefs.exe
+       -$(U)makedefs -v
+
+$(INCL)\onames.h: $(U)makedefs.exe
+       -$(U)makedefs -o
+
+$(INCL)\pm.h: $(U)makedefs.exe
+       -$(U)makedefs -p
+
+monstr.c: $(U)makedefs.exe
+       -$(U)makedefs -m
+
+$(INCL)\vis_tab.h: $(U)makedefs.exe
+       -$(U)makedefs -z
+
+vis_tab.c: $(U)makedefs.exe
+       -$(U)makedefs -z
+
+#
+# Level Compiler Stuff
+#
+
+$(U)lev_comp.exe:  $(SPLEVOBJS)
+       @echo Linking $@...
+       @$(LINK) $(LFLAGS) @<<$(@B).lnk
+               $(SPLEVOBJS:^   =+^
+               )
+               $@
+               $(@B)
+               $(BCMDL);
+<<
+
+$(O)lev_yacc.o:  $(HACK_H)   $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c
+
+$(O)lev_$(LEX).o:  $(HACK_H)   $(INCL)\lev_comp.h $(SP_LEV_H) \
+       $(U)lev_$(LEX).c
+
+$(O)lev_main.o:        $(U)lev_main.c $(HACK_H)   $(SP_LEV_H)
+
+$(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y
+!      IF "$(DO_YACC)"=="YACC_ACT"
+          $(YACC) -d -l $(U)lev_comp.y
+          copy $(YTABC) $(U)lev_yacc.c
+          copy $(YTABH) $(INCL)\lev_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+!      ELSE
+          @echo.
+          @echo $(U)lev_comp.y has changed.
+          @echo To update $(U)lev_yacc.c and $(INCL)\lev_comp.h run $(YACC).
+          @echo.
+          @echo For now, we will copy the prebuilt lev_yacc.c
+          @echo from $(SSHR) to $(U)lev_yacc.c, and copy the prebuilt
+          @echo lev_comp.h from $(SYS) to $(UTIL)\lev_comp.h
+          @echo and use those.
+          @echo.
+          copy $(SSHR)\lev_yacc.c $@ >nul
+          touch $@
+          copy $(SSHR)\lev_comp.h $(INCL)\lev_comp.h >nul
+          touch $(INCL)\lev_comp.h
+!      ENDIF
+
+$(U)lev_$(LEX).c:  $(U)lev_comp.l
+!      IF "$(DO_LEX)"=="LEX_ACT"
+          $(LEX) $(FLEXSKEL) $(U)lev_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+!      ELSE
+          @echo.
+          @echo $(U)lev_comp.l has changed. To update $@ run $(LEX).
+          @echo.
+          @echo For now, we will copy a prebuilt lev_lex.c
+          @echo from $(SSHR) to $@ and use it.
+          @echo.
+          copy $(SSHR)\lev_lex.c $@ >nul
+          touch $@
+!      ENDIF
+
+#
+# Dungeon Stuff
+#
+
+$(U)dgn_comp.exe: $(DGNCOMPOBJS)
+    @echo Linking $@...
+       @$(LINK) $(LFLAGS) @<<$(@B).lnk
+               $(DGNCOMPOBJS:^ =+^
+               )
+               $@
+               $(@B)
+               $(BCMDL);
+<<
+
+$(O)dgn_yacc.o:        $(HACK_H)   $(DGN_FILE_H) $(INCL)\dgn_comp.h \
+       $(U)dgn_yacc.c
+
+$(O)dgn_$(LEX).o: $(HACK_H)   $(DGN_FILE_H)  $(INCL)\dgn_comp.h \
+       $(U)dgn_$(LEX).c
+
+$(O)dgn_main.o:        $(HACK_H) $(U)dgn_main.c
+
+$(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y
+!      IF "$(DO_YACC)"=="YACC_ACT"
+          $(YACC) -d -l $(U)dgn_comp.y
+          copy $(YTABC) $(U)dgn_yacc.c
+          copy $(YTABH) $(INCL)\dgn_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+!      ELSE
+          @echo.
+          @echo $(U)dgn_comp.y has changed. To update $@ and
+          @echo $(INCL)\dgn_comp.h run $(YACC).
+          @echo.
+          @echo For now, we will copy the prebuilt dgn_yacc.c from
+          @echo $(SSHR) to $(U)dgn_yacc.c, and copy the prebuilt
+          @echo dgn_comp.h from $(SSHR) to $(INCL)\dgn_comp.h 
+          @echo and use those.
+          @echo.
+          copy $(SSHR)\dgn_yacc.c $@ >nul
+          touch $@
+          copy $(SSHR)\dgn_comp.h $(INCL)\dgn_comp.h >nul
+          touch $(INCL)\dgn_comp.h
+!      ENDIF
+
+$(U)dgn_$(LEX).c:  $(U)dgn_comp.l
+!      IF "$(DO_LEX)"=="LEX_ACT"
+          $(LEX) $(FLEXSKEL)  $(U)dgn_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+!      ELSE
+          @echo.
+          @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX).
+          @echo.
+          @echo For now, we will copy a prebuilt dgn_lex.c
+          @echo from $(SSHR) to $@ and use it.
+          @echo.
+          copy $(SSHR)\dgn_lex.c $@ >nul
+          touch $@
+!      ENDIF
+
+#
+#  Recover Utility
+#
+
+$(U)recover.exe:   $(RECOVOBJS)
+        @echo Linking....
+        @$(LINK) $(LFLAGS) @<<$(@B).lnk
+                $(RECOVOBJS:^      =+^
+                )
+                $@
+                $(@B)
+                ;
+<<
+
+recover.o:   $(CONFIG_H) $(UTIL)\recover.c
+
+#
+#  Header file moves required for tile support
+#
+
+#$(WSHR)\tile.h: $(WSHR)\tile.h
+#      copy $(WSHR)\tile.h $@
+
+#$(MSYS)\pctiles.h: $(MSYS)\pctiles.h
+#      copy $(MSYS)\pctiles.h $@
+
+#$(INCL)\pcvideo.h: $(MSYS)\pcvideo.h
+#      copy $(MSYS)\pcvideo.h $@
+
+#$(MSYS)\portio.h: $(MSYS)\portio.h
+#      copy $(MSYS)\portio.h $@
+
+#
+#  Tile Mapping
+#
+
+tile.c: tilemap.exe
+       @tilemap
+       @echo A new $@ has been created
+
+tilemap.exe: tilemap.o
+        @echo Linking....
+        @$(LINK) $(LFLAGS) @<<$(@B).lnk
+               tilemap.o
+                $@
+                $(@B)
+                ;
+<<
+
+tilemap.c: $(WSHR)\tilemap.c
+       copy $(WSHR)\tilemap.c .
+
+tilemap.o: tilemap.c $(HACK_H) $(TILE_H)
+
+#
+#   Tile Utilities
+#
+#
+#  Required for tile support
+#
+
+NetHack1.tib: $(TILEFILES) tile2bin.exe
+       @echo Creating binary tile files (this may take some time)
+       @tile2bin
+
+NetHacko.tib: thintile.tag $(TILEFILES2) til2bin2.exe
+       @echo Creating overview binary tile files (this may take some time)
+       @til2bin2
+
+tile2bin.exe: tile2bin.o $(TEXTIO)
+       @$(LINK) $(LFLAGS) tile2bin.o $(TEXTIO),$@,$(@B);
+
+til2bin2.exe: til2bin2.o $(TEXTIO2)
+       @$(LINK) $(LFLAGS) til2bin2.o $(TEXTIO2),$@,$(@B);
+
+thintile.exe: thintile.o 
+       @$(LINK) $(LFLAGS) thintile.o,$@,$(@B);
+
+thintile.o:  $(HACK_H) $(WSHR)\tile.h $(WSHR)\thintile.c
+
+thintile.tag: thintile.exe $(TILEFILES)
+       thintile
+       @echo thintiles created >thintile.tag
+
+tile2bin.o:  $(HACK_H) $(WSHR)\tile.h $(MSYS)\pctiles.h $(MSYS)\pcvideo.h \
+       $(MSYS)\tile2bin.c
+
+til2bin2.o:  $(HACK_H) $(WSHR)\tile.h $(MSYS)\pctiles.h $(MSYS)\pcvideo.h \
+       $(MSYS)\tile2bin.c
+       -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 -DOVERVIEW_FILE /Zg $(MSYS)\tile2bin.c >$(@B).pro
+       @$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 -DOVERVIEW_FILE /Fo$@ $(MSYS)\tile2bin.c
+
+tiletext.o:  $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\tiletext.c
+
+tiletex2.o:  $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\tiletext.c
+       -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 /Zg $(WSHR)\tiletext.c >$(@B).pro
+       @$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 /Fo$@ $(WSHR)\tiletext.c
+
+tiletxt.o: $(CONFIG_H) $(WSHR)\tile.h tilemap.c
+       -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILETEXT /Zg tilemap.c >$(@B).pro
+       @$(CC) $(CFLAGS) $(SPECOPTS) -DTILETEXT /Fo$@ tilemap.c
+  
+tiletxt2.o: $(CONFIG_H)        $(WSHR)\tile.h tilemap.c
+       -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILETEXT /Zg tilemap.c >$(@B).pro
+       @$(CC) $(CFLAGS) $(SPECOPTS) -DTILETEXT -DTILE_X=8 /Fo$@ tilemap.c
+#
+# Optional GIF Utilities (for development)
+#
+
+gif2txt.exe: $(GIFREADERS) $(TEXTIO)
+       @$(LINK) $(LFLAGS) $(GIFREADERS) $(TEXTIO),$@,$(@B);
+
+gif2txt2.exe: $(GIFREAD2) $(TEXTIO2)
+       @$(LINK) $(LFLAGS) $(GIFREAD2) $(TEXTIO2),$@,$(@B);
+
+txt2ppm.exe: $(PPMWRITERS) $(TEXTIO)
+       @$(LINK) $(LFLAGS) $(PPMWRITERS) $(TEXTIO),$@,$(@B);
+
+txt2ppm2.exe: $(PPMWRIT2) $(TEXTIO2)
+       @$(LINK) $(LFLAGS) $(PPMWRIT2) $(TEXTIO2),$@,$(@B);
+
+gifread.o: $(CONFIG_H) $(WSHR)\tile.h
+
+gifread2.o: $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\gifread.c
+       -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 /Zg gifread.c >$(@B).pro
+       @$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 $(WSHR)\gifread.c
+
+ppmwrite.o: $(CONFIG_H)        $(WSHR)\tile.h $(WSHR)\ppmwrite.c
+
+ppmwrit2.o:  $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\ppmwrite.c
+       -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 /Zg ppmwrite.c >$(@B).pro
+       @$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 $(WSHR)\ppmwrite.c
+
+#
+#  Optional tile viewer (development sources only)
+#
+
+viewtib.exe: viewtib.o
+       @$(LINK) $(LFLAGS) -oviewtib.exe viewtib.o $(LIBRARIES)
+
+viewtib.o: $(MSYS)\viewtib.c
+
+#
+#  Other Util Dependencies.
+#
+
+alloc.o: $(CONFIG_H)    alloc.c
+drawing.o: $(CONFIG_H) drawing.c $(MSYS)\pcvideo.h
+decl.o: $(CONFIG_H) decl.c
+monst.o: $(CONFIG_H)        $(PERMONST_H)      $(ESHK_H)          \
+       $(EPRI_H)             $(VAULT_H)         $(INCL)\monsym.h   \
+       $(INCL)\color.h  monst.c
+
+objects.o: $(CONFIG_H)       $(INCL)\obj.h      $(INCL)\objclass.h \
+       $(INCL)\prop.h      $(INCL)\color.h    objects.c
+
+panic.o:   $(CONFIG_H)   $(UTIL)\panic.c
+
+
+
+#
+# make data.base an 8.3 filename to prevent an nmake warning
+#
+
+DATABASE = $(DAT)\data.bas
+
+$(DAT)\data:    $(O)utility.tag        $(DATABASE)
+       $(U)makedefs -d
+
+$(DAT)\rumors:      $(O)utility.tag    $(DAT)\rumors.tru       $(DAT)\rumors.fal
+       $(U)makedefs -r
+
+$(DAT)\quest.dat: $(O)utility.tag  $(DAT)\quest.txt
+       $(U)makedefs -q
+
+$(DAT)\oracles:             $(O)utility.tag    $(DAT)\oracles.txt
+       $(U)makedefs -h
+
+$(DAT)\dungeon: $(O)utility.tag  $(DAT)\dungeon.def
+       $(U)makedefs -e
+       cd $(DAT)
+       $(U)dgn_comp dungeon.pdf
+       cd $(SRC)
+
+#
+# DLB stuff
+#
+#
+nhdat: $(U)dlb_main.exe $(DAT)\data $(DAT)\oracles $(DAT)\options \
+       $(DAT)\quest.dat $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp \
+       $(DAT)\history $(DAT)\opthelp $(DAT)\wizhelp $(DAT)\dungeon \
+       $(DAT)\license $(O)sp_lev.tag
+       @copy $(MSYS)\msdoshlp.txt $(DAT)
+       @cd $(DAT)
+       @echo data >dlb.lst
+       @echo oracles >>dlb.lst
+       @echo options >>dlb.lst
+       @echo quest.dat >>dlb.lst
+       @echo rumors >>dlb.lst
+       @echo help >>dlb.lst
+       @echo hh >>dlb.lst
+       @echo cmdhelp >>dlb.lst
+       @echo history >>dlb.lst
+       @echo opthelp >>dlb.lst
+       @echo wizhelp >>dlb.lst
+       @echo dungeon >>dlb.lst
+       @echo license >>dlb.lst
+       @echo msdoshlp.txt >>dlb.lst
+       @for %%N in (*.lev) do echo %%N >>dlb.lst
+       $(U)dlb_main cvIf dlb.lst $(SRC)\nhdat
+       @cd $(SRC)
+
+$(U)dlb_main.exe: $(DLBOBJS)
+       link $(LFLAGS) /ST:5120 $(DLBOBJS),$@,$(@B);
+
+dlb_main.o: $(U)dlb_main.c $(INCL)\config.h $(DLB_H)
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(U)dlb_main.c
+
+# Game Dependencies
+
+# sys/share
+main.o: $(SSHR)\pcmain.c $(HACK_H) $(INCL)\dlb.h \
+               #$(INCL)\win32api.h
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\pcmain.c
+sys.o: $(SSHR)\pcsys.c $(HACK_H)
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\pcsys.c
+tty.o: $(SSHR)\pctty.c $(HACK_H)
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\pctty.c
+unix.o: $(SSHR)\pcunix.c $(HACK_H)
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\pcunix.c
+random.o: $(SSHR)\random.c $(HACK_H)
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\random.c
+
+# sys/msdos
+msdos.o : $(HACK_H)  $(MSYS)\msdos.c
+       @$(CC) $(CFLAGS) $(SPECOPTS) $(NEWALT) /Fo$@ $(MSYS)\msdos.c
+pckeys.o : $(HACK_H)  $(MSYS)\pckeys.c
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\pckeys.c
+pctiles.o : $(HACK_H)  $(MSYS)\pctiles.c $(MSYS)\portio.h
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\pctiles.c
+sound.o : $(HACK_H)  $(MSYS)\sound.c $(MSYS)\portio.h
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\sound.c
+video.o : $(HACK_H)  $(MSYS)\pcvideo.h $(MSYS)\portio.h $(MSYS)\video.c
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\video.c
+vidvga.o : $(HACK_H)  $(MSYS)\pcvideo.h $(MSYS)\portio.h $(TILE_H) \
+       $(MSYS)\vidvga.c
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\vidvga.c
+vidtxt.o : $(HACK_H)  $(MSYS)\pcvideo.h $(MSYS)\portio.h $(TILE_H) \
+       $(MSYS)\vidtxt.c
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\vidtxt.c
+stubvid.o : $(HACK_H) $(MSYS)\video.c
+       @$(CC) $(CFLAGS) $(SPECOPTS) -DSTUBVIDEO /Fo$@ $(MSYS)\video.c
+
+# win/tty
+getline.o: $(WIN)\getline.c $(HACK_H) $(INCL)\func_tab.h
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(WIN)\getline.c
+termcap.o: $(WIN)\termcap.c $(HACK_H) $(INCL)\tcap.h
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(WIN)\termcap.c
+topl.o: $(WIN)\topl.c $(HACK_H) $(INCL)\tcap.h
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(WIN)\topl.c
+wintty.o: $(WIN)\wintty.c $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\patchlev.h $(INCL)\tcap.h
+       @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(WIN)\wintty.c
+
+# src dependencies
+allmain.o: allmain.c $(HACK_H)
+alloc.o: alloc.c $(CONFIG_H)
+apply.o: apply.c $(HACK_H) $(INCL)\edog.h
+artifact.o: artifact.c $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h
+attrib.o: attrib.c $(HACK_H) $(INCL)\artifact.h
+ball.o: ball.c $(HACK_H)
+bones.o: bones.c $(HACK_H) $(INCL)\lev.h
+botl.o: botl.c $(HACK_H)
+cmd.o: cmd.c $(HACK_H) $(INCL)\func_tab.h
+dbridge.o: dbridge.c $(HACK_H)
+decl.o: decl.c $(HACK_H)
+detect.o: detect.c $(HACK_H) $(INCL)\artifact.h
+dig.o: dig.c $(HACK_H) $(INCL)\edog.h
+display.o: display.c $(HACK_H)
+dlb.o: dlb.c $(CONFIG_H) $(INCL)\dlb.h
+do.o: do.c $(HACK_H) $(INCL)\lev.h
+do_name.o: do_name.c $(HACK_H)
+do_wear.o: do_wear.c $(HACK_H)
+dog.o: dog.c $(HACK_H) $(INCL)\edog.h
+dogmove.o: dogmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+dokick.o: dokick.c $(HACK_H) $(INCL)\eshk.h
+dothrow.o: dothrow.c $(HACK_H)
+drawing.o: drawing.c $(HACK_H) $(INCL)\tcap.h
+dungeon.o: dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h
+eat.o: eat.c $(HACK_H)
+end.o: end.c $(HACK_H) $(INCL)\eshk.h $(INCL)\dlb.h
+engrave.o: engrave.c $(HACK_H) $(INCL)\lev.h
+exper.o: exper.c $(HACK_H)
+explode.o: explode.c $(HACK_H)
+extralev.o: extralev.c $(HACK_H)
+files.o: files.c $(HACK_H) $(INCL)\dlb.h
+fountain.o: fountain.c $(HACK_H)
+hack.o: hack.c $(HACK_H)
+hacklib.o: hacklib.c $(HACK_H)
+invent.o: invent.c $(HACK_H) $(INCL)\artifact.h
+light.o: light.c $(HACK_H) $(INCL)\lev.h
+lock.o: lock.c $(HACK_H)
+mail.o: mail.c $(HACK_H) $(INCL)\mail.h
+makemon.o: makemon.c $(HACK_H) $(INCL)\epri.h $(INCL)\emin.h \
+               $(INCL)\edog.h
+mapglyph.o: mapglyph.c $(HACK_H)
+mcastu.o: mcastu.c $(HACK_H)
+mhitm.o: mhitm.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+mhitu.o: mhitu.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+minion.o: minion.c $(HACK_H) $(INCL)\emin.h $(INCL)\epri.h
+mklev.o: mklev.c $(HACK_H)
+mkmap.o: mkmap.c $(HACK_H) $(INCL)\sp_lev.h
+mkmaze.o: mkmaze.c $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev.h
+mkobj.o: mkobj.c $(HACK_H) $(INCL)\artifact.h
+mkroom.o: mkroom.c $(HACK_H)
+mon.o: mon.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+mondata.o: mondata.c $(HACK_H) $(INCL)\eshk.h $(INCL)\epri.h
+monmove.o: monmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h
+monst.o: monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \
+               $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\monsym.h \
+               $(INCL)\dungeon.h $(INCL)\eshk.h $(INCL)\vault.h \
+               $(INCL)\epri.h $(INCL)\color.h
+mplayer.o: mplayer.c $(HACK_H)
+mthrowu.o: mthrowu.c $(HACK_H)
+muse.o: muse.c $(HACK_H) $(INCL)\edog.h
+music.o: music.c $(HACK_H) #interp.c
+o_init.o: o_init.c $(HACK_H) $(INCL)\lev.h
+objects.o: objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \
+               $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h
+objnam.o: objnam.c $(HACK_H)
+options.o: options.c $(CONFIG_H) $(INCL)\objclass.h $(INCL)\flag.h \
+               $(HACK_H) $(INCL)\tcap.h
+pager.o: pager.c $(HACK_H) $(INCL)\dlb.h
+       @$(CC) $(CFLAGS) $(SPECOPTS) /f- /Od /Fo$@ pager.c
+pickup.o: pickup.c $(HACK_H)
+pline.o: pline.c $(HACK_H) $(INCL)\epri.h
+polyself.o: polyself.c $(HACK_H)
+potion.o: potion.c $(HACK_H)
+pray.o: pray.c $(HACK_H) $(INCL)\epri.h
+priest.o: priest.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\eshk.h \
+               $(INCL)\epri.h $(INCL)\emin.h
+quest.o: quest.c $(HACK_H) $(INCL)\qtext.h
+questpgr.o: questpgr.c $(HACK_H) $(INCL)\dlb.h $(INCL)\qtext.h
+read.o: read.c $(HACK_H)
+rect.o: rect.c $(HACK_H)
+region.o: region.c $(HACK_H)
+restore.o: restore.c $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h
+rip.o: rip.c $(HACK_H)
+rnd.o: rnd.c $(HACK_H)
+role.o: role.c $(HACK_H)
+rumors.o: rumors.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h
+save.o: save.c $(HACK_H) $(INCL)\lev.h
+shk.o: shk.c $(HACK_H) $(INCL)\eshk.h
+shknam.o: shknam.c $(HACK_H) $(INCL)\eshk.h
+sit.o: sit.c $(HACK_H) $(INCL)\artifact.h
+sounds.o: sounds.c $(HACK_H) $(INCL)\edog.h
+sp_lev.o: sp_lev.c $(HACK_H) $(INCL)\dlb.h $(INCL)\sp_lev.h
+spell.o: spell.c $(HACK_H)
+steal.o: steal.c $(HACK_H)
+steed.o: steed.c $(HACK_H)
+teleport.o: teleport.c $(HACK_H)
+timeout.o: timeout.c $(HACK_H) $(INCL)\lev.h
+topten.o: topten.c $(HACK_H) $(INCL)\dlb.h $(INCL)\patchlev.h
+track.o: track.c $(HACK_H)
+trap.o: trap.c $(HACK_H)
+u_init.o: u_init.c $(HACK_H)
+uhitm.o: uhitm.c $(HACK_H)
+vault.o: vault.c $(HACK_H) $(INCL)\vault.h
+version.o: version.c $(HACK_H) $(INCL)\date.h $(INCL)\patchlev.h
+vision.o: vision.c $(HACK_H) $(INCL)\vis_tab.h
+weapon.o: weapon.c $(HACK_H)
+were.o: were.c $(HACK_H)
+wield.o: wield.c $(HACK_H)
+windows.o: windows.c $(HACK_H) $(INCL)\wingem.h
+wizard.o: wizard.c $(HACK_H) $(INCL)\qtext.h
+worm.o: worm.c $(HACK_H) $(INCL)\lev.h
+worn.o: worn.c $(HACK_H)
+write.o: write.c $(HACK_H)
+zap.o: zap.c $(HACK_H)
+
+# end of file
diff --git a/sys/msdos/NHAccess.nh b/sys/msdos/NHAccess.nh
new file mode 100644 (file)
index 0000000..2fb6731
--- /dev/null
@@ -0,0 +1,134 @@
+#      SCSS Id: @(#)NHAccess.nh        3.4         1999/11/28
+#      Copyright (c) NetHack PC Development Team 1993, 1996, 1999
+#      NetHack may be freely redistributed.  See license for details.
+#
+# Modified defaults.nh for blind access.  Copy to working directory as
+# defaults.nh.
+#
+# A '#' at the beginning of a line means the rest of the line is a comment.
+#
+# This configuration file is set up for two cases, for a hard disk
+# (as drive C:), and for two floppy disks.
+#
+# Some options MUST be set in this file, other options can be toggled while
+# playing.  For a list of options available see the <opthelp.> file.  If
+# the game plays slowly you might notice some improvement by setting
+# !time and !showexp, which will reduce screen I/O somewhat.
+#
+# To change the configuration, comment out the unwanted lines, and
+# uncomment the configuration you want.
+
+
+# *** OPTIONS ***
+#
+# The three options on this line should be used for most setups.  
+# If your machine isn't very IBM-compatible, and NetHack doesn't work, 
+# try commenting out this line.
+#
+# Note to blind players:
+#
+# Turn off IBMgraphics, using the exclamation-mark, as done below.
+#
+OPTIONS=rawio,BIOS,!IBMgraphics
+# Some versions of NetHack use the pc speaker to play the notes given when
+# playing music instruments in NetHack.  To use this feature, if available,
+# uncomment the following line:
+#OPTIONS=soundcard:autodetect
+# If your machine is NEC PC-9800, use:
+#OPTIONS=rawio,BIOS,video:default
+#
+#
+# General options.  You might also set "silent" so as not to attract
+# the boss's attention.
+#
+# Note for blind players:
+#
+# A lot of speech access programs use the number-pad to review the screen.
+# If this is the case, exclamation-mark out the number_pad option (as done
+# below) and use the traditional Rogue-like commands.
+#
+OPTIONS=notime,noshowexp,!number_pad,lit_corridor,!rest_on_space
+#
+#
+# Some options to set personal preferences.  Uncomment and change these to
+# suit your personal preference.  If several people are to use the same
+# configuration, options like these should not be set.
+#
+# Note to blind players:
+#
+# Use menustyle:traditional for the best interface to speech synthesizers.
+#
+#OPTIONS=name:Janet-V,female,dogname:Fido,catname:Morris,fruit:apricot
+#OPTIONS=autopickup,pickup_types:$"=/!?+
+#OPTIONS=packorder:")[%?+/=!(*0_`
+#OPTIONS=scores:10 top/2 around/own
+#OPTIONS=nolegacy,noverbose
+OPTIONS=nolegacy,menustyle:traditional
+
+
+# *** HARD DISK CONFIGURATION ***
+#
+#HACKDIR=c:\games\nethack
+# 
+# Note: Under MSDOS ports HACKDIR defaults to the location 
+#       of the NetHack.exe file. Setting HACKDIR above will override that.
+#
+#   LEVELS and SAVE default to HACKDIR
+#
+#LEVELS=c:\games\nethack\bones
+#SAVE=c:\games\nethack\bones;n
+#
+#   appending a ";n" to SAVE means don't prompt to insert a disk.
+SAVE=;n
+#
+# Note that RAMDISK must *not* be the same (or even implicitly
+# get expanded to the same path by the OS) as HACKDIR.
+#
+#RAMDISK=d:
+
+
+# *** 2-FLOPPY CONFIGURATION ***
+#
+# HACKDIR=a:\
+# LEVELS=b:\
+# SAVE=b:\
+# RAMDISK=c:
+
+
+# *** CHARACTER GRAPHICS ***
+#
+# See the on-line help or the Guidebook for which symbols are in which
+# positions.
+#
+# Note to blind players:
+#
+# You very probably do not want to use these character graphics.
+#
+# If you merely set the IBMgraphics option, NetHack will use IBM
+# extended ASCII for dungeon characters.  If you don't like the selections,
+# you can make up your own via these graphics options, but you should still
+# set IBMgraphics if you are using IBM graphics characters to get the correct
+# processing.
+#
+#DUNGEON=  032 124 045 124 124 124 124 045 045 045 \
+#          124 124 046 045 124 043 043 035 035 046 \
+#          035 035 060 062 060 062 095 124 092 035 \
+#          126 126 126 126 042 042 035 035 032 035 \
+#          126
+#
+#TRAPS=    094 094 094 094 094 094 094 094 094 094 \
+#          094 094 094 094 094 094 094 094 094 094 \
+#          094 094
+#
+#EFFECTS=  124 095 092 047 042 033 041 040         \
+#          048 035 064 042                         \
+#          047 045 092 058 058 092 045 047         \
+#          047 045 092 058 032 058 092 045 047
+
+# =================================================
+# *** VIDEOCOLORS AND VIDEOSHADES ***
+#
+# While playing on NEC PC-9800, default game display may be difficult to
+# read.  Try following setting.
+#
+#OPTIONS=videocolors:4-2-6-1-5-3-4-2-6-1-5-3,videoshades:normal-normal-normal
diff --git a/sys/msdos/moveinit.pat b/sys/msdos/moveinit.pat
new file mode 100644 (file)
index 0000000..fc8ab0c
--- /dev/null
@@ -0,0 +1,37 @@
+ These are patches for MOVEINIT.C, supplied    
+ with the MSVC compiler in the compiler's SOURCE\MOVE  
+ subdirectory. (Copy that and the MOVEAPI.H    
+ file into your NetHack src directory and apply this patch) 
+
+
+*** ../linc/src/moveinit.c     Tue Nov 23 08:01:00 1993
+--- src/moveinit.c     Sun Mar 13 10:13:10 1994
+***************
+*** 13,18 ****
+--- 13,19 ----
+  *******************************************************************************/
+  
+  #include "moveapi.h"
++ extern unsigned memavail(unsigned);
+  
+  #ifndef MOVE_ENV
+  
+***************
+*** 125,132 ****
+      /* attempt to allocate the overlay heap. ignore return value (heap size).
+       * note that MOVE will abort if not enough memory to alloc minimum size.
+       */
+! 
+!     _movesetheap ($$COVL, cparaLarge, cparaMax);
+  
+      /* get available cache ressource amount */
+  
+--- 126,133 ----
+      /* attempt to allocate the overlay heap. ignore return value (heap size).
+       * note that MOVE will abort if not enough memory to alloc minimum size.
+       */
+!     cparaMax = memavail(cparaMin);
+!     _movesetheap ($$COVL, cparaMin, cparaMax);
+  
+      /* get available cache ressource amount */
+  
diff --git a/sys/msdos/msdos.c b/sys/msdos/msdos.c
new file mode 100644 (file)
index 0000000..29e19fb
--- /dev/null
@@ -0,0 +1,520 @@
+/*     SCCS Id: @(#)msdos.c     3.4     2000/07/30                       */
+/* Copyright (c) NetHack PC Development Team 1990, 1991, 1992, 1993, 1994 */
+/* NetHack may be freely redistributed.  See license for details.         */
+
+/*
+ *  MSDOS system functions.
+ *  Many thanks to Don Kneller who originated the DOS port and
+ *  contributed much to the cause.
+ */
+
+#define NEED_VARARGS
+#include "hack.h"
+
+#ifdef MSDOS
+#include "pcvideo.h"
+
+#include <dos.h>
+#include <ctype.h>
+
+/*
+ * MS-DOS functions
+ */
+#define DIRECT_INPUT    0x07    /* Unfiltered Character Input Without Echo */
+#define FATINFO     0x1B    /* Get Default Drive Data */
+/* MS-DOS 2.0+: */
+#define GETDTA      0x2F    /* Get DTA Address */
+#define FREESPACE   0x36    /* Get Drive Allocation Info */
+#define GETSWITCHAR 0x3700  /* Get Switch Character */
+#define FINDFIRST   0x4E    /* Find First File */
+#define FINDNEXT    0x4F    /* Find Next File */
+#define SETFILETIME 0x5701  /* Set File Date & Time */
+/*
+ * BIOS interrupts
+ */
+#ifdef PC9800
+#define KEYBRD_BIOS 0x18
+#else
+#define KEYBRD_BIOS 0x16
+#endif
+
+/*
+ * Keyboard BIOS functions
+ */
+#define READCHAR    0x00    /* Read Character from Keyboard */
+#define GETKEYFLAGS 0x02    /* Get Keyboard Flags */
+/*#define KEY_DEBUG     */   /* print values of unexpected key codes - devel*/
+
+void FDECL(get_cursor,(int *, int *));
+
+#ifdef OVL0
+
+/* direct bios calls are used only when iflags.BIOS is set */
+
+static char NDECL(DOSgetch);
+static char NDECL(BIOSgetch);
+#ifndef __GO32__
+static char * NDECL(getdta);
+#endif
+static unsigned int FDECL(dos_ioctl, (int,int,unsigned));
+#ifdef USE_TILES
+extern boolean FDECL(pckeys,(unsigned char, unsigned char));   /* pckeys.c */
+#endif
+
+int
+tgetch()
+{
+       char ch;
+
+       /* BIOSgetch can use the numeric key pad on IBM compatibles. */
+# ifdef SIMULATE_CURSOR
+       if (iflags.grmode && cursor_flag) DrawCursor();
+# endif
+       if (iflags.BIOS)
+               ch = BIOSgetch();
+       else
+               ch = DOSgetch();
+# ifdef SIMULATE_CURSOR
+       if (iflags.grmode && cursor_flag) HideCursor();
+# endif
+       return ((ch == '\r') ? '\n' : ch);
+}
+
+
+
+/*
+ *  Keyboard translation tables.
+ */
+#ifdef PC9800
+#define KEYPADLO       0x38
+#define KEYPADHI       0x50
+#else
+#define KEYPADLO       0x47
+#define KEYPADHI       0x53
+#endif
+
+#define PADKEYS        (KEYPADHI - KEYPADLO + 1)
+#define iskeypad(x)    (KEYPADLO <= (x) && (x) <= KEYPADHI)
+
+/*
+ * Keypad keys are translated to the normal values below.
+ * When iflags.BIOS is active, shifted keypad keys are translated to the
+ *    shift values below.
+ */
+static const struct pad {
+       char normal, shift, cntrl;
+} keypad[PADKEYS] = {
+#ifdef PC9800
+                       {'>', '>', '>'},                /* Ins */
+                       {'<', '<', '<'},                /* Del */
+                       {'k', 'K', C('k')},             /* Up */
+                       {'h', 'H', C('h')},             /* Left */
+                       {'l', 'L', C('l')},             /* Right */
+                       {'j', 'J', C('j')},             /* Down */
+                       { 0 ,  0 ,  0 },                /* HomeClr */
+                       {'?', '?', '?' },               /* Help */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'/', '/', '/'},                /* / */
+                       {'y', 'Y', C('y')},             /* 7 */
+                       {'k', 'K', C('k')},             /* 8 */
+                       {'u', 'U', C('u')},             /* 9 */
+                       {'*', '*', '*'},                /* * */
+                       {'h', 'H', C('h')},             /* 4 */
+                       {'g', 'g', 'g'},                /* 5 */
+                       {'l', 'L', C('l')},             /* 6 */
+                       {'p', 'P', C('p')},             /* + */
+                       {'b', 'B', C('b')},             /* 1 */
+                       {'j', 'J', C('j')},             /* 2 */
+                       {'n', 'N', C('n')},             /* 3 */
+                       {'=', '=', '='},                /* = */
+                       {'i', 'I', C('i')},             /* 0 */
+                       {',', ':', ':'},                /* , */
+                       {'.', '.', '.'}                 /* . */
+#else
+                       {'y', 'Y', C('y')},             /* 7 */
+                       {'k', 'K', C('k')},             /* 8 */
+                       {'u', 'U', C('u')},             /* 9 */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'h', 'H', C('h')},             /* 4 */
+                       {'g', 'g', 'g'},                /* 5 */
+                       {'l', 'L', C('l')},             /* 6 */
+                       {'p', 'P', C('p')},             /* + */
+                       {'b', 'B', C('b')},             /* 1 */
+                       {'j', 'J', C('j')},             /* 2 */
+                       {'n', 'N', C('n')},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+#endif
+}, numpad[PADKEYS] = {
+#ifdef PC9800
+                       {'>', '>', '>'},                /* Ins */
+                       {'<', '<', '<'},                /* Del */
+                       {'8', M('8'), '8'},             /* Up */
+                       {'4', M('4'), '4'},             /* Left */
+                       {'6', M('6'), '6'},             /* Right */
+                       {'2', M('2'), '2'},             /* Down */
+                       { 0 ,  0 ,  0 },                /* HomeClr */
+                       {'?', '?', '?'},                /* Help */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'/', '/', '/'},                /* / */
+                       {'7', M('7'), '7'},             /* 7 */
+                       {'8', M('8'), '8'},             /* 8 */
+                       {'9', M('9'), '9'},             /* 9 */
+                       {'*', '*', '*'},                /* * */
+                       {'4', M('4'), '4'},             /* 4 */
+                       {'g', 'G', 'g'},                /* 5 */
+                       {'6', M('6'), '6'},             /* 6 */
+                       {'p', 'P', C('p')},             /* + */
+                       {'1', M('1'), '1'},             /* 1 */
+                       {'2', M('2'), '2'},             /* 2 */
+                       {'3', M('3'), '3'},             /* 3 */
+                       {'=', '=', '='},                /* = */
+                       {'i', 'I', C('i')},             /* 0 */
+                       {',', ':', ':'},                /* , */
+                       {'.', '.', '.'}                 /* . */
+#else
+                       {'7', M('7'), '7'},             /* 7 */
+                       {'8', M('8'), '8'},             /* 8 */
+                       {'9', M('9'), '9'},             /* 9 */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'4', M('4'), '4'},             /* 4 */
+                       {'5', M('5'), '5'},             /* 5 */
+                       {'6', M('6'), '6'},             /* 6 */
+                       {'p', 'P', C('p')},             /* + */
+                       {'1', M('1'), '1'},             /* 1 */
+                       {'2', M('2'), '2'},             /* 2 */
+                       {'3', M('3'), '3'},             /* 3 */
+                       {'0', M('0'), '0'},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+#endif
+};
+
+/*
+ * Unlike Ctrl-letter, the Alt-letter keystrokes have no specific ASCII
+ * meaning unless assigned one by a keyboard conversion table, so the
+ * keyboard BIOS normally does not return a character code when Alt-letter
+ * is pressed. So, to interpret unassigned Alt-letters, we must use a
+ * scan code table to translate the scan code into a letter, then set the
+ * "meta" bit for it.  -3.
+ */
+#ifdef PC9800
+#define SCANLO         0x5
+#else
+#define SCANLO         0x10
+#endif /* PC9800 */
+
+static const char scanmap[] = {        /* ... */
+#ifdef PC9800
+                        0,  0,  0,  0,  0,  0, '-','^','\\','\b',
+       '\t','q','w','e','r','t','y','u','i','o','p','@','[', '\n',
+       'a','s','d','f','g','h','j','k','l',';',':', ']',
+       'z','x','c','v','b','N','m',',','.','/' /* ... */
+#else
+       'q','w','e','r','t','y','u','i','o','p','[',']', '\n',
+       0, 'a','s','d','f','g','h','j','k','l',';','\'', '`',
+       0, '\\', 'z','x','c','v','b','n','m',',','.','?'        /* ... */
+#endif /* PC9800 */
+};
+
+#define inmap(x)       (SCANLO <= (x) && (x) < SCANLO + SIZE(scanmap))
+
+#ifdef NEW_ALT
+#define NUMERIC_SCANLO         0x78
+static const char numeric_scanmap[] = {        /* ... */
+       '1','2','3','4','5','6','7','8','9','0','-','='
+};
+# define in_numericmap(x)      (NUMERIC_SCANLO <= (x) && \
+                                       (x) < NUMERIC_SCANLO + SIZE(numeric_scanmap))
+# endif
+
+/*
+ * BIOSgetch gets keys directly with a BIOS call.
+ */
+#ifdef PC9800
+#define SHIFT          0x1
+#define KANA           0x4
+#define GRPH           0x8
+#define CTRL           0x10
+#else
+#define SHIFT          (0x1 | 0x2)
+#define CTRL           0x4
+#define ALT            0x8
+#endif /* PC9800 */
+
+static char
+BIOSgetch()
+{
+      unsigned char scan, shift, ch=0;
+      const struct pad *kpad;
+      union REGS regs;
+
+      do {
+       /* Get scan code.
+        */
+       regs.h.ah = READCHAR;
+       int86(KEYBRD_BIOS, &regs, &regs);
+       ch = regs.h.al;
+       scan = regs.h.ah;
+       /* Get shift status.
+        */
+       regs.h.ah = GETKEYFLAGS;
+       int86(KEYBRD_BIOS, &regs, &regs);
+       shift = regs.h.al;
+
+       /* Translate keypad keys */
+       if (iskeypad(scan)) {
+               kpad = iflags.num_pad ? numpad : keypad;
+               if (shift & SHIFT)
+                       ch = kpad[scan - KEYPADLO].shift;
+               else if (shift & CTRL)
+                       ch = kpad[scan - KEYPADLO].cntrl;
+               else
+                       ch = kpad[scan - KEYPADLO].normal;
+       }
+#ifdef USE_TILES
+       /* Check for special interface manipulation keys */
+       if (pckeys(scan, shift)) {
+               ch = 0xFF;
+               continue;
+       }
+#endif
+       /* Translate unassigned Alt-letters */
+#ifdef PC9800
+       if (shift & KANA)
+               return 0;
+       if ((shift & GRPH) && (ch >= 0x80)) {
+#else
+       if ((shift & ALT) && !ch) {
+#endif
+#if 0
+               pline("Scan code: %d 0x%03X", scan, scan);
+#endif
+               if (inmap(scan))
+                       ch = scanmap[scan - SCANLO];
+#ifdef NEW_ALT
+               else if (in_numericmap(scan))
+                       ch = numeric_scanmap[scan - NUMERIC_SCANLO];
+#endif
+               return (isprint(ch) ? M(ch) : ch);
+       }
+      } while (ch == 0xFF);
+      return ch;
+}
+
+static char
+DOSgetch()
+{
+       union REGS regs;
+       char ch;
+       struct pad (*kpad)[PADKEYS];
+
+       regs.h.ah = DIRECT_INPUT;
+       intdos(&regs, &regs);
+       ch = regs.h.al;
+
+#ifdef PC9800
+       if (ch < 0)     /* KANA letters and GRPH-shifted letters(?) */
+               ch = 0; /* munch it */
+#else
+       /*
+        * The extended codes for Alt-shifted letters, and unshifted keypad
+        * and function keys, correspond to the scan codes.  So we can still
+        * translate the unshifted cursor keys and Alt-letters.  -3.
+        */
+       if (ch == 0) {          /* an extended key */
+               regs.h.ah = DIRECT_INPUT;
+               intdos(&regs, &regs);   /* get the extended key code */
+               ch = regs.h.al;
+
+               if (iskeypad(ch)) {     /* unshifted keypad keys */
+                       kpad = (void *)(iflags.num_pad ? numpad : keypad);
+                       ch = (*kpad)[ch - KEYPADLO].normal;
+               } else if (inmap(ch)) { /* Alt-letters */
+                       ch = scanmap[ch - SCANLO];
+                       if (isprint(ch)) ch = M(ch);
+               } else ch = 0;          /* munch it */
+       }
+#endif
+       return (ch);
+}
+
+char
+switchar()
+{
+       union REGS regs;
+
+       regs.x.ax = GETSWITCHAR;
+       intdos(&regs, &regs);
+       return regs.h.dl;
+}
+
+long
+freediskspace(path)
+char *path;
+{
+       union REGS regs;
+
+       regs.h.ah = FREESPACE;
+       if (path[0] && path[1] == ':')
+               regs.h.dl = (toupper(path[0]) - 'A') + 1;
+       else
+               regs.h.dl = 0;
+       intdos(&regs, &regs);
+       if (regs.x.ax == 0xFFFF)
+               return -1L;             /* bad drive number */
+       else
+               return ((long) regs.x.bx * regs.x.cx * regs.x.ax);
+}
+
+#ifndef __GO32__
+/*
+ * Functions to get filenames using wildcards
+ */
+int
+findfirst_file(path)
+char *path;
+{
+       union REGS regs;
+       struct SREGS sregs;
+
+       regs.h.ah = FINDFIRST;
+       regs.x.cx = 0;          /* attribute: normal files */
+       regs.x.dx = FP_OFF(path);
+       sregs.ds = FP_SEG(path);
+       intdosx(&regs, &regs, &sregs);
+       return !regs.x.cflag;
+}
+
+int
+findnext_file() {
+       union REGS regs;
+
+       regs.h.ah = FINDNEXT;
+       intdos(&regs, &regs);
+       return !regs.x.cflag;
+}
+
+char *
+foundfile_buffer()
+{
+       return (getdta() + 30);
+}
+
+
+/* Get disk transfer area */
+static char *
+getdta()
+{
+       union REGS regs;
+       struct SREGS sregs;
+       char *ret;
+
+       regs.h.ah = GETDTA;
+       intdosx(&regs, &regs, &sregs);
+#   ifdef MK_FP
+       ret = (char *)MK_FP(sregs.es, regs.x.bx);
+#   else
+       FP_OFF(ret) = regs.x.bx;
+       FP_SEG(ret) = sregs.es;
+#   endif
+       return ret;
+}
+
+long
+filesize_nh(file)
+char *file;
+{
+       char *dta;
+
+       if (findfirst_file(file)) {
+               dta = getdta();
+               return  (* (long *) (dta + 26));
+       } else
+               return -1L;
+}
+
+#endif /* __GO32__ */
+
+/*
+ * Chdrive() changes the default drive.
+ */
+void
+chdrive(str)
+char *str;
+{
+#  define SELECTDISK   0x0E
+       char *ptr;
+       union REGS inregs;
+       char drive;
+
+       if ((ptr = index(str, ':')) != (char *)0) {
+               drive = toupper(*(ptr - 1));
+               inregs.h.ah = SELECTDISK;
+               inregs.h.dl = drive - 'A';
+               intdos(&inregs, &inregs);
+       }
+       return;
+}
+
+
+/* Use the IOCTL DOS function call to change stdin and stdout to raw
+ * mode.  For stdin, this prevents MSDOS from trapping ^P, thus
+ * freeing us of ^P toggling 'echo to printer'.
+ * Thanks to Mark Zbikowski (markz@microsoft.UUCP).
+ */
+
+#define DEVICE         0x80
+#define RAW            0x20
+#define IOCTL          0x44
+#define STDIN          fileno(stdin)
+#define STDOUT         fileno(stdout)
+#define GETBITS                0
+#define SETBITS                1
+
+static unsigned        int old_stdin, old_stdout;
+
+void
+disable_ctrlP()
+{
+
+       if (!iflags.rawio) return;
+
+    old_stdin = dos_ioctl(STDIN, GETBITS, 0);
+    old_stdout = dos_ioctl(STDOUT, GETBITS, 0);
+       if (old_stdin & DEVICE)
+        dos_ioctl(STDIN, SETBITS, old_stdin | RAW);
+       if (old_stdout & DEVICE)
+        dos_ioctl(STDOUT, SETBITS, old_stdout | RAW);
+       return;
+}
+
+void
+enable_ctrlP()
+{
+       if (!iflags.rawio) return;
+       if (old_stdin)
+        (void) dos_ioctl(STDIN, SETBITS, old_stdin);
+       if (old_stdout)
+        (void) dos_ioctl(STDOUT, SETBITS, old_stdout);
+       return;
+}
+
+static unsigned int
+dos_ioctl(handle, mode, setvalue)
+int handle, mode;
+unsigned setvalue;
+{
+       union REGS regs;
+
+       regs.h.ah = IOCTL;
+       regs.h.al = mode;
+       regs.x.bx = handle;
+       regs.h.dl = setvalue;
+       regs.h.dh = 0;                  /* Zero out dh */
+       intdos(&regs, &regs);
+       return (regs.x.dx);
+}
+
+# endif /* OVLB */
+
+#endif /* MSDOS */
diff --git a/sys/msdos/msdoshlp.txt b/sys/msdos/msdoshlp.txt
new file mode 100644 (file)
index 0000000..621f46e
--- /dev/null
@@ -0,0 +1,188 @@
+            MSDOS specific help file for NetHack 3.4.3
+                 (Last Revision: March 16, 2003)
+
+Copyright (c) NetHack PC Development Team 1993-2003.
+NetHack may be freely distributed.  See license for details.
+
+New players should be sure to read GuideBoo.txt which contains essential
+information about playing NetHack.  It can be found in the same
+directory as your NetHack executable.
+
+The MSDOS port of NetHack supports some additional or enhanced commands
+as well as some defaults.nh file options specific to configuration choices 
+used during the building of PC NetHack.  Listed below are those commands
+and defaults.nh file options.
+
+Recognized MSDOS specific defaults.nh entries are outlined below.
+
+Boolean Options:
+
+        IBMgraphics             Use IBM extended characters for the dungeon
+                                Default: [FALSE]
+        BIOS                    Allow the use of IBM ROM BIOS calls
+                                Default: [FALSE]
+        rawio                   Allow the use of raw I/O (may only be set
+                                on startup)
+                                Default: [FALSE]
+        preload_tiles           Preload tiles into RAM at start of game.
+                                Faster, but uses more memory.
+                                Default: [TRUE]
+
+Color Options:
+
+OPTIONS=!color
+
+               Players will need this if they have a real, true, (old)
+               monochrome adapter, and they are seeing underlined,
+               and flashing, and reverse-video characters on the
+               screen. Or they find that some things are missing from
+               the display.  This means that the auto-detection
+               for monochromes has failed.  The color support
+               stuff is active in video.c, but may be (will have
+               to be) overridden by adding an OPTIONS=nocolor to
+               defaults.nh.
+
+OPTIONS=VIDEO
+               (defaults.nh only)
+
+               ie: OPTIONS=video:autodetect
+
+               Possible values are: AUTODETECT, DEFAULT, VGA
+
+               AUTODETECT Checks for a supported hi-res video
+                           adaptor, and if it detects one, NetHack 
+                           will run in "TILE MODE." 
+
+               DEFAULT    NetHack will run in TTY mode.  This is
+                           the same as not specifying OPTIONS=VIDEO
+                           at all.
+
+               VGA        Forces use of VGA specific video routines.
+                           Any forcing of specific video routines has
+                           potential to cause machine lock-ups if 
+                           the specified video hardware is not present.        
+
+OPTIONS=VIDEOSHADES
+               (defaults.nh only)
+               Players may wish to add this option because one of their
+               shades of gray is difficult to read on their video
+               display hardware.  Allows a level of intensity to be
+               assigned to the 3 possible shades of gray in NetHack,
+               those being BLACK, GRAY, WHITE.  To each of those
+               shades, the player may assign a DARK, NORMAL, or LIGHT value.
+               Here is the default if not specified:
+
+               ie. OPTIONS=VIDEOSHADES:dark-normal-light
+
+               Anytime the same intensity value (DARK NORMAL LIGHT) is used
+               for more than one shade of gray, it will not be possible
+               to visually distinguish those two shades from each
+               other.
+
+               ie. OPTIONS=VIDEOSHADES:normal-normal-light
+
+               This, while eliminating the dark shade normally used for
+               displaying black items, means that the player won't be
+               able to distinguish black items and creatures from gray
+               items and creatures visually.
+
+               Note also that the controversial gray schema used in
+               pl 3.1.2 as the default, corresponded to:
+
+               OPTIONS=VIDEOSHADES:normal-dark-normal
+
+               This is NOT the default in pl 3.1.3 and above, so many people
+               will probably not even need to use this option, and will find
+               the default just fine. The maps are built using gray,
+               and in pl 3.1.3, that is mapped to normal by default. In
+               3.1.2, it was mapped to dark (as above).
+
+OPTIONS=VIDEOCOLORS
+               (defaults.nh only)
+               This option is only provided because some people on
+               r.g.r.n mentioned how they liked to modify the color
+               values from the default ANSI.SYS behaviour, and were
+               "upset" to find out that they could no longer do so
+               under 3.1.2.  The color map is as accurate as possible
+               on standard PC video hardware as it stands, and any
+               deviation from the default, will mean that people
+               are mapping blue to green for example.  The option is
+               available to provide as much flexibility as possible,
+               but it is not encouraged to be used.
+
+               One possible use might be for the dark blue in
+               fountains.  On video hardware that has trouble
+               displaying blacks, there may also be problems displaying
+               the darker blue used in fountains.  If that is the case
+               then the default map:
+
+               OPTIONS=VIDEOCOLORS:4-2-6-1-5-3-12-10-14-9-13-11
+
+               could be changed to the following to map blue to br.
+               blue:
+
+               OPTIONS=VIDEOCOLORS:4-2-6-9-5-3-12-10-14-9-13-11
+
+               The mapping order for the options:
+
+                       red, green, brown, blue, magenta, cyan
+                       br.red, br.green, yellow, br.blue,
+                       br.magenta, br.cyan
+
+               The PC hardware uses the following values:
+
+               red(4), green(2), brown(6), blue(1), magenta(5),
+               cyan(3), bright red(12), bright green(10), yellow(14),
+               bright blue(9), bright magenta(13), bright cyan(11),
+                normal white(7), bright white(15).
+
+
+The following options are NOT currently recognized under the MSDOS
+port of PC NetHack:
+
+        LEVELS=                 Where to store/create per level
+                                data files.
+        SAVE=                   Where to save games.
+        BONES=                  Where to store bones files.
+
+
+MSDOS Additional/Enhanced Commands:
+
+If you have opted to use the "graphical" or "tiled" option, (usually set via
+OPTIONS=VIDEO:AUTODETECT ((see above)), then the following function keys are
+active:
+
+F3     cycle through the current position indicator, or halo.  Usually this
+       halo highlights the player's tile, unless the game is asking you for
+       an answer to a question that requires positional information, (ie,
+       the discover command).
+F4     toggle level overview mode on/off
+F5     toggle tiled display on/off.  (Switches between tiled and traditional
+       ASCII display.)
+
+While playing NetHack under MSDOS you can press the ALT key in combination 
+with another key to execute an extended command as an alternative method
+to pressing a # key sequence:
+
+Alt-2    twoweapon      - toggle two-weapon combat
+Alt-a    adjust         - adjust inventory letters.
+Alt-c    chat           - talk to someone or something.
+Alt-d    dip            - dip an object into something.
+Alt-e    enhance        - enhance your skill with a weapon.
+Alt-f    force          - force a lock.
+Alt-i    invoke         - invoke an object's powers.
+Alt-j    jump           - jump to a location.
+Alt-l    loot           - loot a box on the floor.
+Alt-m    monster        - use a monster's special ability.
+Alt-n    name           - name an item or type of object.
+Alt-o    offer          - offer a sacrifice to the gods.
+Alt-p    pray           - pray to the gods for help.
+Alt-q    quit           - quit the game. (Same as #quit)
+Alt-r    rub            - rub a lamp.
+Alt-s    sit            - sit down.
+Alt-t    turn           - turn undead.
+Alt-u    untrap         - untrap something.
+Alt-v    version        - list compile time options for this version of NetHack.
+Alt-w    wipe           - wipe off your face.
+
+If you are playing on NEC PC-9800, use the GRPH key instead of the ALT key.
diff --git a/sys/msdos/nhico.uu b/sys/msdos/nhico.uu
new file mode 100644 (file)
index 0000000..c2cfbef
--- /dev/null
@@ -0,0 +1,25 @@
+section 1 of uuencode 4.13 of file NETHACK.ICO    by R.E.M.
+
+begin 644 NETHACK.ICO
+M```!``$`("`0``````#H`@``%@```"@````@````0`````$`!```````@`(`.
+M``````````````````````````````"```"`````@(``@````(``@`"`@```6
+M@("``,#`P````/\``/\```#__P#_````_P#_`/__``#___\`]F9F9F9F9F9F*
+M9F9F9F9F9O]F9F9F9F9F9F9F9F9F9F;_B(B(B(B(B(B(B(B(B&9F_XB(B(B(D
+MB(B(B(B(B(AF9O^(B(B(A555B(B(B(B(9F;_B(B(B`!5!8B(B(B(B&9F_XB('
+MB(@```6(B(B(B(AF9O^(B%554`!56(B(B(B(9F;_B(N[N[`.XU6(B(B(B&9F[
+M_XB[N[L`ONXU6(B(B(AF9O^+N[N[N[ONXUB(B(B(9F;_B[N[N[N[ONY3B(B(N
+MB&9F_XN[NYF9F[ONXSB(B(AF9O^+N[F9F9F[ONXSB(B(9F;_B[N9F9F9F[ON?
+MXSB(B&9F_XNYF9F9F9F[7NXSB(AF9O^+N9F9F9F9NUCNXSB(9F;_B[F9F9F9J
+MF;M8CNXSB&9F_XNYF9F9F9F[6(CNXXAF9O^+N9F9F9F9NUB(CNZ(9F;_B[N9]
+MF9F9F[M8B(CNB&9F_XN[N9F9F;N[6(B(B(AF9O^+N[N9F9N[NUB(B(B(9F;_R
+MB[N[N[N[N[M8B(B(B&9F_XN[N[N[N[N[B(B(B(AF9O^+NXB(B(B+NXB(B(B(F
+M9F;_B[B(B(B(B+N(B(B(B&9F_XB(B(B(B(B(B(B(B(AF9O^(B(B(B(B(B(B(J
+MB(B(9F;_B(B(B(B(B(B(B(B(B&9F___________________V9O__________%
+M__________\`````````````````````````````````````````````````R
+M`````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````````
+!`````
+``
+end
+sum -r/size 23881/1107 section (from "begin" to "end")
+sum -r/size 55184/766 entire input file
diff --git a/sys/msdos/nhpif.uu b/sys/msdos/nhpif.uu
new file mode 100644 (file)
index 0000000..11a8326
--- /dev/null
@@ -0,0 +1,16 @@
+begin 666 nethack.pif
+M`%M00R!.971H86-K(#,N,2`@("`@("`@("`@("`@(""``(``0SI<3D542$%#
+M2UQ.151(04-++D5810`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@$`!#.EQ.151(04-+`"`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@````````````````````
+M````````````````````````````````````````````````````````````
+M```````!`/\94```!P``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````.`@34E#4D]33T94(%!)1D58`(<!``!Q`5=)3D1/5U,@,S@V(#,N
+M,``%`IT!:`"``@`"9``R`/__``#__P```!`"`!\`````````````````````
+M```````@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@(%=)3D1/5U,@,C@V(#,N,`#__QL"!@``
+%```````@
+`
+end
diff --git a/sys/msdos/ovlinit.c b/sys/msdos/ovlinit.c
new file mode 100644 (file)
index 0000000..fc0ff22
--- /dev/null
@@ -0,0 +1,154 @@
+/*     SCCS Id: @(#)ovlinit.c  3.4     1994/03/20                */
+/* Copyright (c) NetHack PC Development Team 1995                 */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include <dos.h>
+#include <stdio.h>
+
+
+#ifdef _MSC_VER
+
+#define RESERVED_PARAGRAPHS    5120    /* leave 80K for malloc and inits */
+                                       /* subject to change before release */
+
+/*
+ * memavail() Returns the amount of RAM available (in paragraphs which are 16
+ *  bytes) - the amount to be reserved for heap allocations.
+ *
+ */
+unsigned memavail(minovl)
+unsigned minovl;                       /* minimum size of overlay heap */
+{
+       unsigned available;
+
+       unsigned farparaavail;
+       unsigned tmp;
+
+        /*
+         * _dos_allocmem will return the maximum block size available.
+         * It uses DOS (int 21h) service 0x48.
+         */
+
+       _dos_allocmem(0xFFFF, &farparaavail);
+       available = farparaavail - RESERVED_PARAGRAPHS;
+       tmp = RESERVED_PARAGRAPHS + minovl;
+       if (farparaavail < tmp) {
+          panic("Not enough free RAM to begin a game of NetHack (%ld bytes)",
+                       (long)((long)tmp * 16L));
+       }
+       return available;
+}
+#endif /*_MSC_VER*/
+
+#ifdef __BORLANDC__
+
+#define RSRVD_MALLOC   65 * 1024L      /* malloc() calls use about 65K    */
+#define RSRVD_CRTL     50 * 1024L      /* C runtime library uses 50K      */
+#define RSRVD_TOTAL    115 * 1024L     /* reserved for use in malloc()    */
+                                       /* as well as by C runtime library */
+                                       /* routines which allocate memory  */
+                                       /* after this routine runs.        */
+#define MIN_OVRBUF     30 * 1024L      /* Overlay buffer gets minimum of  */
+#define MAX_OVRBUF     200 * 1024L     /* 30K and maximum of 200K.        */
+
+#define RESIZE_OVL
+#ifdef RESIZE_OVL
+
+extern unsigned _ovrbuffer = 0;    /* Use default size initially */
+unsigned appFail = 0;              /* Fail flag if not enough RAM */
+unsigned memAlloc = 0;
+unsigned long ProgramSize;
+unsigned long runAlloc;
+unsigned far *mem_top;
+unsigned total;
+signed long tmpbuffer;
+int emsstatus;
+int xmsstatus;
+
+void NDECL(_resizeOvrBuffer);
+
+void _resizeOvrBuffer()
+{
+   mem_top = (unsigned far *) MK_FP( _psp, 0x02 );
+   total = *mem_top - _psp;
+
+   ProgramSize = * (unsigned far *) MK_FP( _psp - 1, 0x03 );
+   tmpbuffer = total - ProgramSize - RSRVD_TOTAL / 16;
+   memAlloc = min (MAX_OVRBUF / 16, tmpbuffer);
+   if (tmpbuffer >= MIN_OVRBUF / 16)
+       _ovrbuffer = memAlloc;
+   else {
+       _ovrbuffer = 1;
+       appFail = 1;
+   };
+
+
+/*
+ * Remember, when inside this code, nothing has been setup on
+ * the system, so do NOT call any RTL functions for I/O or
+ * anything else that might rely on a startup function.  This
+ * includes accessing any global objects as their constructors
+ * have not been called yet.
+ */
+
+}
+
+#pragma startup _resizeOvrBuffer 0      /* Put function in table */
+
+void
+startup ()
+{
+       if (appFail) {
+           printf ("NetHack fits in memory, but it cannot allocate memory");
+           printf (" for the overlay buffer\nand the runtime functions.  ");
+           printf ("Please free up just %ld more bytes.",
+                       (long)(MIN_OVRBUF - tmpbuffer * 16L));
+           exit (-1);
+       } else {
+
+       /* Now try to use expanded memory for the overlay manager */
+       /* If that doesn't work, we revert to extended memory */
+
+       emsstatus = _OvrInitEms (0, 0, 0);
+#ifdef RECOGNIZE_XMS
+       xmsstatus = (emsstatus) ? _OvrInitExt (0, 0) : -1;
+#endif
+
+     }
+}
+
+void
+show_borlandc_stats(win)
+winid win;
+{
+       char buf[BUFSZ];
+
+       putstr(win, 0, "");
+       putstr(win, 0, "");
+       putstr(win, 0, "Memory usage stats"); putstr(win, 0, "");
+       putstr(win, 0, "");
+       Sprintf (buf, "Overlay buffer memory allocation: %ld bytes.",
+           memAlloc * 16L); putstr(win, 0, buf);
+       Sprintf (buf, "_ovrbuffer = %u.", _ovrbuffer); putstr(win, 0, buf);
+       Sprintf (buf, "Startup memory usage: 0x%X", ProgramSize);
+       putstr(win, 0, buf);
+       runAlloc = * (unsigned far *) MK_FP( _psp - 1, 0x03);
+       Sprintf (buf, "Current memory usage: 0x%X", runAlloc);
+       putstr(win, 0, buf);
+       if (emsstatus) Sprintf (buf, "EMS search failed (%d).", emsstatus);
+       else Sprintf (buf, "EMS search successful.");
+       putstr(win, 0, buf);
+#ifdef RECOGNIZE_XMS
+       if (xmsstatus) Sprintf (buf, "XMS search failed (%d).", xmsstatus);
+       else Sprintf (buf, "XMS search successful.");
+       putstr(win, 0, buf);
+#endif
+
+
+}
+
+#endif  /* #ifdef RESIZE_OVL */
+#endif /* #ifdef __BORLANDC__ */
+
+/*ovlinit.c*/
diff --git a/sys/msdos/pckeys.c b/sys/msdos/pckeys.c
new file mode 100644 (file)
index 0000000..d2783b4
--- /dev/null
@@ -0,0 +1,88 @@
+/*     SCCS Id: @(#)pckeys.c    3.4     1996/05/11               */
+/* Copyright (c) NetHack PC Development Team 1996                 */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *  MSDOS tile-specific key handling.
+ */
+
+#include "hack.h"
+
+#ifdef MSDOS
+# ifdef USE_TILES
+#include "wintty.h" 
+#include "pcvideo.h"
+
+boolean FDECL(pckeys, (unsigned char, unsigned char));
+
+extern struct WinDesc *wins[MAXWIN];   /* from wintty.c */
+extern boolean inmap;                  /* from video.c */
+
+#define SHIFT          (0x1 | 0x2)
+#define CTRL           0x4
+#define ALT            0x8
+
+/*
+ * Check for special interface manipulation keys.
+ * Returns TRUE if the scan code triggered something.
+ *
+ */
+boolean
+pckeys(scancode, shift)
+unsigned char scancode;
+unsigned char shift;
+{
+   boolean opening_dialog;
+
+   opening_dialog = pl_character[0] ? FALSE : TRUE;
+#  ifdef SIMULATE_CURSOR
+    switch(scancode) {
+       case 0x3d:      /* F3 = toggle cursor type */
+               HideCursor();
+               cursor_type += 1;
+               if (cursor_type >= NUM_CURSOR_TYPES) cursor_type = 0;
+               DrawCursor();
+               break;
+#  endif
+       case 0x74:      /* Control-right_arrow = scroll horizontal to right */
+               if ((shift & CTRL) && iflags.tile_view && !opening_dialog)
+                       vga_userpan(1);
+               break;
+
+       case 0x73:      /* Control-left_arrow = scroll horizontal to left */
+               if ((shift & CTRL) && iflags.tile_view && !opening_dialog)
+                       vga_userpan(0);
+               break;
+       case 0x3E:      /* F4 = toggle overview mode */
+               if (iflags.tile_view && 
+                   !opening_dialog
+#ifdef REINCARNATION
+                               && !Is_rogue_level(&u.uz)
+#endif
+                                                       ) {
+                       iflags.traditional_view = FALSE;
+                       vga_overview(iflags.over_view ? FALSE : TRUE);
+                       vga_refresh();
+               }
+               break;
+       case 0x3F:      /* F5 = toggle traditional mode */
+               if (iflags.tile_view &&
+                   !opening_dialog
+#ifdef REINCARNATION
+                               && !Is_rogue_level(&u.uz)
+#endif
+                                                       ) {
+                       iflags.over_view = FALSE;
+                       vga_traditional(iflags.traditional_view ? FALSE : TRUE);
+                       vga_refresh();
+               }
+               break;
+       default:
+               return FALSE;
+    }
+    return TRUE;
+}
+# endif /* USE_TILES */
+#endif /* MSDOS */
+
+/*pckeys.c*/
diff --git a/sys/msdos/pctiles.c b/sys/msdos/pctiles.c
new file mode 100644 (file)
index 0000000..66a6587
--- /dev/null
@@ -0,0 +1,259 @@
+/*   SCCS Id: @(#)pctiles.c   3.4     1995/07/31                    */
+/*   Copyright (c) NetHack PC Development Team 1993, 1994           */
+/*   NetHack may be freely redistributed.  See license for details. */
+/*                                                                  */
+/*
+ * pctiles.c - PC Graphical Tile Support Routines
+ *                                                  
+ *Edit History:
+ *     Initial Creation              M. Allison      93/10/30
+ *
+ */
+
+#include "hack.h"
+
+#ifdef USE_TILES
+
+#if defined(__GO32__) || defined(__DJGPP__)
+#include <unistd.h>
+#define TILES_IN_RAM   /* allow tiles to be read into ram */
+#endif
+
+# if defined(_MSC_VER)
+#  if _MSC_VER >= 700
+#pragma warning(disable:4018)  /* signed/unsigned mismatch */
+#pragma warning(disable:4127)  /* conditional expression is constant */
+#pragma warning(disable:4131)  /* old style declarator */
+#pragma warning(disable:4309)  /* initializing */
+#  endif
+#include <conio.h>
+# endif
+
+#include "pcvideo.h"
+#include "tile.h"
+#include "pctiles.h"
+
+STATIC_VAR FILE *tilefile;
+STATIC_VAR FILE *tilefile_O;
+extern short glyph2tile[];              /* in tile.c (made from tilemap.c) */
+
+#ifdef TILES_IN_RAM
+struct planar_cell_struct *ramtiles;
+struct overview_planar_cell_struct *oramtiles;
+boolean tiles_in_ram = FALSE;
+boolean otiles_in_ram = FALSE;
+extern int total_tiles_used;           /* tile.c */
+#endif
+
+# ifdef OVLB
+
+/*
+ * Read the header/palette information at the start of the
+ * NetHack.tib file.
+ *
+ * There is 1024 bytes (1K) of header information
+ * at the start of the file, including a palette.
+ *
+ */
+int ReadTileFileHeader(tibhdr, filestyle)
+struct tibhdr_struct *tibhdr;
+boolean filestyle;
+{
+       FILE *x;
+       x = filestyle ? tilefile_O : tilefile;
+       if (fseek(x,0L,SEEK_SET)) {
+               return 1;
+       } else {
+               fread(tibhdr, sizeof(struct tibhdr_struct), 1, x);
+       }
+       return 0;
+} 
+
+/*
+ * Open the requested tile file.
+ *
+ * NetHack1.tib file is a series of
+ * 'struct planar_tile_struct' structures, one for each
+ * glyph tile.
+ *
+ * NetHack2.tib file is a series of
+ * char arrays [TILE_Y][TILE_X] in dimensions, one for each
+ * glyph tile.
+ *
+ * There is 1024 bytes (1K) of header information
+ * at the start of each .tib file. The first glyph tile starts at
+ * location 1024.
+ *
+ */
+int
+OpenTileFile(tilefilename, filestyle)
+char *tilefilename;
+boolean filestyle;
+{
+#ifdef TILES_IN_RAM
+       int k;
+#endif
+       if (filestyle) { 
+               tilefile_O = fopen(tilefilename,"rb");
+               if (tilefile_O == (FILE *)0) return 1;
+       } else {
+               tilefile = fopen(tilefilename,"rb");
+               if (tilefile == (FILE *)0) return 1;
+       }
+#ifdef TILES_IN_RAM
+    if (iflags.preload_tiles) {
+       if (filestyle) {
+           struct overview_planar_cell_struct *gp;
+           long ram_needed = sizeof(struct overview_planar_cell_struct) *
+                               total_tiles_used;
+           if (fseek(tilefile_O,(long)TIBHEADER_SIZE, SEEK_SET)) { /*failure*/
+           }
+           oramtiles = (struct overview_planar_cell_struct *)alloc(ram_needed);
+           /* Todo: fall back to file method here if alloc failed */
+           gp = oramtiles;
+           for(k=0; k < total_tiles_used; ++k) {
+               fread(gp, sizeof(struct overview_planar_cell_struct), 
+                       1, tilefile_O);
+               ++gp;
+           }
+#ifdef DEBUG_RAMTILES
+           pline("%d overview tiles read into ram.", k);
+           mark_synch();
+#endif
+           otiles_in_ram = TRUE;
+       } else {
+           struct planar_cell_struct *gp;
+           long ram_needed = sizeof(struct planar_cell_struct) *
+                               total_tiles_used;
+           if (fseek(tilefile,(long)TIBHEADER_SIZE, SEEK_SET)) { /*failure*/
+           }
+           ramtiles = (struct planar_cell_struct *)alloc(ram_needed);
+           /* Todo: fall back to file method here if alloc failed */
+           gp = ramtiles;
+           for(k=0; k < total_tiles_used; ++k) {
+               fread(gp, sizeof(struct planar_cell_struct), 
+                       1, tilefile);
+               ++gp;
+           }
+#ifdef DEBUG_RAMTILES
+           pline("%d tiles read into ram.", k);
+           mark_synch();
+#endif
+           tiles_in_ram = TRUE;
+       }
+    }
+#endif
+       return 0;
+}
+
+void
+CloseTileFile(filestyle)
+boolean filestyle;
+{
+       fclose(filestyle ? tilefile_O : tilefile);
+#ifdef TILES_IN_RAM
+       if (!filestyle && tiles_in_ram) {
+               if (ramtiles) free((genericptr_t) ramtiles);
+               tiles_in_ram = FALSE;
+       } else if (filestyle && otiles_in_ram) {
+               if (oramtiles) free((genericptr_t) oramtiles);
+               otiles_in_ram = FALSE;
+       }
+#endif
+}
+# endif /* OVLB      */
+
+# ifdef OVL0
+
+struct planar_cell_struct plancell;
+struct overview_planar_cell_struct oplancell;
+
+/* This routine retrieves the requested NetHack glyph tile
+ * from the planar style binary .tib file.
+ * This is currently done 'on demand', so if the player
+ * is running without a disk cache (ie. smartdrv) operating,
+ * things can really be slowed down.  We don't have any
+ * base memory under MSDOS, in which to store the pictures.
+ *
+ * Todo: Investigate the possibility of loading the glyph
+ *       tiles into extended or expanded memory using
+ *       the MSC virtual memory routines.
+ *
+ * Under an environment like djgpp, it should be possible to
+ * read the entire set of glyph tiles into a large
+ * array of 'struct planar_cell_struct' structures at
+ * game initialization time, and recall them from the array
+ * as needed.  That should speed things up (at the cost of
+ * increasing the memory requirement - can't have everything).
+ *
+ */
+#  ifdef PLANAR_FILE
+int ReadPlanarTileFile(tilenum,gp)
+int tilenum;
+struct planar_cell_struct **gp;
+{
+       long fpos;
+
+#ifdef TILES_IN_RAM
+       if (tiles_in_ram) {
+           *gp = ramtiles + tilenum;
+           return 0;
+       }
+#endif
+       fpos = ((long)(tilenum) * (long)sizeof(struct planar_cell_struct)) +
+               (long)TIBHEADER_SIZE;
+       if (fseek(tilefile,fpos,SEEK_SET)) {
+               return 1;
+       } else {
+             fread(&plancell, sizeof(struct planar_cell_struct), 1, tilefile);
+       }
+       *gp = &plancell;
+       return 0;
+}
+int ReadPlanarTileFile_O(tilenum,gp)
+int tilenum;
+struct overview_planar_cell_struct **gp;
+{
+       long fpos;
+
+#ifdef TILES_IN_RAM
+       if (otiles_in_ram) {
+           *gp = oramtiles + tilenum;
+           return 0;
+       }
+#endif
+       fpos = ((long)(tilenum) * 
+               (long)sizeof(struct overview_planar_cell_struct)) +
+               (long)TIBHEADER_SIZE;
+       if (fseek(tilefile_O,fpos,SEEK_SET)) {
+               return 1;
+       } else {
+               fread(&oplancell, sizeof(struct overview_planar_cell_struct),
+                       1, tilefile_O);
+       }
+       *gp = &oplancell;
+       return 0;
+}
+#  endif
+
+#  ifdef PACKED_FILE
+int ReadPackedTileFile(tilenum,pta)
+int tilenum;
+char (*pta)[TILE_X];
+{
+       long fpos;
+       
+       fpos = ((long)(tilenum) * (long)(TILE_Y * TILE_X) +
+               (long)TIBHEADER_SIZE;
+       if (fseek(tilefile,fpos,SEEK_SET)) {
+               return 1;
+       } else {
+               fread(pta, (TILE_Y * TILE_X), 1, tilefile);
+       }
+       return 0;
+}
+#  endif
+# endif /* OVL0 */
+#endif /* USE_TILES */
+
+/* pctiles.c */
diff --git a/sys/msdos/pctiles.h b/sys/msdos/pctiles.h
new file mode 100644 (file)
index 0000000..1750592
--- /dev/null
@@ -0,0 +1,65 @@
+/*   SCCS Id: @(#)pctiles.h   3.4     1994/04/04                        */
+/*   Copyright (c) NetHack PC Development Team 1993, 1994             */
+/*   NetHack may be freely redistributed.  See license for details.   */
+/*                                                                    */
+/*
+ * pctiles.h - Definitions for PC graphical tile support
+ *                                                  
+ *Edit History:
+ *     Initial Creation              M. Allison      93/10/30
+ *
+ */
+
+#ifdef USE_TILES
+#define NETHACK_PLANAR_TILEFILE "NetHack1.tib" /* Planar style tiles */
+#define NETHACK_PACKED_TILEFILE "NetHack2.tib" /* Packed style tiles */
+#define NETHACK_OVERVIEW_TILEFILE "NetHacko.tib" /* thin overview tiles */
+
+#define ROWS_PER_TILE  TILE_Y
+#define COLS_PER_TILE   TILE_X
+#define EMPTY_TILE     -1
+#define TIBHEADER_SIZE 1024    /* Use this for size, allows expansion */
+#define PLANAR_STYLE   0
+#define PACKED_STYLE   1
+#define DJGPP_COMP     0
+#define MSC_COMP       1
+#define BC_COMP                2
+#define OTHER_COMP     10
+
+struct tibhdr_struct {
+       char  ident[80];        /* Identifying string           */
+       char  timestamp[26];    /* Ascii timestamp              */
+       char  tilestyle;        /* 0 = planar, 1 = pixel        */
+       char  compiler;         /* 0 = DJGPP, 1 = MSC, 2= BC etc. see above */
+       short tilecount;        /* number of tiles in file      */
+       short numcolors;        /* number of colors in palette  */
+       char  palette[256 * 3]; /* palette                      */
+};
+
+
+/* Note on packed style tile file:
+ * Each record consists of one of the following arrays:
+ *     char packtile[TILE_Y][TILE_X];
+ */
+extern void FDECL(CloseTileFile, (BOOLEAN_P));
+extern int  FDECL(OpenTileFile, (char *, BOOLEAN_P));
+extern int  FDECL(ReadTileFileHeader, (struct tibhdr_struct *, BOOLEAN_P));
+
+# ifdef PLANAR_FILE
+#  ifdef SCREEN_VGA
+extern int  FDECL(ReadPlanarTileFile,(int, struct planar_cell_struct **));
+extern int  FDECL(ReadPlanarTileFile_O,
+                       (int, struct overview_planar_cell_struct **));
+#  endif
+# endif
+
+# ifdef PACKED_FILE
+extern int  FDECL(ReadPackedTileFile, (int, char (*)[TILE_X]));
+# endif
+
+extern short glyph2tile[MAX_GLYPH];      /* in tile.c (made from tilemap.c) */
+
+#endif /* USE_TILES */
+
+/* pctiles.h */
diff --git a/sys/msdos/pcvideo.h b/sys/msdos/pcvideo.h
new file mode 100644 (file)
index 0000000..41d3061
--- /dev/null
@@ -0,0 +1,283 @@
+/*   SCCS Id: @(#)pcvideo.h   3.4     1994/06/07                      */
+/*   Copyright (c) NetHack PC Development Team 1993, 1994           */
+/*   NetHack may be freely redistributed.  See license for details. */
+/*                                                                  */
+/*
+ * pcvideo.h - Hardware video support definitions and prototypes
+ *                                                  
+ *Edit History:
+ *     Initial Creation              M. Allison      93/10/30
+ *
+ */
+
+#ifndef PCVIDEO_H
+#define PCVIDEO_H
+
+#include "portio.h"
+
+# ifdef SCREEN_BIOS
+#  if !defined(PC9800)
+# define MONO_CHECK            /* Video BIOS can do the check       */ 
+#  endif
+# endif
+
+# ifdef SCREEN_DJGPPFAST
+/*# define MONO_CHECK          /* djgpp should be able to do check  */
+# endif
+
+/*
+ * PC interrupts
+ */
+# ifdef PC9800
+#define CRT_BIOS       0x18
+#define DOS_EXT_FUNC   0xdc
+#define DIRECT_CON_IO  0x10
+# else
+#define VIDEO_BIOS  0x10
+# endif
+#define DOSCALL            0x21
+
+
+/*
+ * Video BIOS functions
+ */
+# if defined(PC9800)
+#define SENSEMODE      0x0b    /* Sense CRT Mode */
+
+#define PUTCHAR                0x00    /* Put Character */
+#define SETATT         0x02    /* Set Attribute */
+#define SETCURPOS      0x03    /* Set Cursor Position */
+#define CURSOR_RIGHT   0x08    /* Move Cursor Right */
+#define CURSOR_LEFT    0x09    /* Move Cursor Left */
+#define SCREEN_CLEAR   0x0a    /* Clear Screen */
+#define LINE_CLEAR     0x0b    /* Clear Line */
+# else
+#define SETCURPOS   0x02    /* Set Cursor Position */
+# endif
+
+#define GETCURPOS   0x03    /* Get Cursor Position */
+#define GETMODE     0x0f    /* Get Video Mode */
+#define SETMODE     0x00    /* Set Video Mode */
+#define SETPAGE     0x05    /* Set Video Page */
+#define FONTINFO    0x1130  /* Get Font Info */
+#define SCROLL      0x06    /* Scroll or initialize window */
+#define PUTCHARATT  0x09    /* Write attribute & char at cursor */
+
+/*
+ * VGA Specific Stuff
+ */
+# ifdef SCREEN_VGA
+/* #define HW_PANNING          /* Hardware panning enabled */
+#define USHORT         unsigned short
+#define MODE640x480    0x0012  /* Switch to VGA 640 x 480 Graphics mode */
+#define MODETEXT       0x0003  /* Switch to Text mode 3 */
+
+#ifdef HW_PANNING
+#define PIXELINC 16    /* How much to increment by when panning */
+/*#define PIXELINC 1   /* How much to increment by when panning */
+#define SCREENBYTES   128
+#define CharRows  30
+#define VERT_RETRACE     {while (!(inportb(crt_status) & 0x08)); }
+#define VERT_RETRACE_END  {while ( (inportb(crt_status) & 0x08)); }
+#else
+#define SCREENBYTES    80
+#endif
+
+#define CharacterWidth 8
+#define SCREENHEIGHT   480
+#define SCREENWIDTH (SCREENBYTES * CharacterWidth)
+#define VIDEOSEG       0xa000
+#define FONT_PTR_SEGMENT 0x0000
+#define FONT_PTR_OFFSET         0x010C
+#define SCREENPLANES   4
+#define COLORDEPTH     16
+#define egawriteplane(n)       { outportb(0x3c4,2); outportb(0x3c5,n); }
+#define egareadplane(n)                { outportb(0x3ce,4); outportb(0x3cf,n); }
+#define col2x8(c)      ((c) * 8) 
+#define col2x16(c)     ((c) * 16)
+#define col2x(c)       ((c) * 2)
+#define row2y(c)       ((c) * 16)
+#define MAX_ROWS_PER_CELL 16
+#define MAX_COLS_PER_CELL 16
+#define MAX_BYTES_PER_CELL 2           /* MAX_COLS_PER_CELL/8 */
+#define ROWS_PER_CELL  MAX_ROWS_PER_CELL
+#define COLS_PER_CELL  MAX_COLS_PER_CELL
+#define BYTES_PER_CELL MAX_BYTES_PER_CELL
+
+struct cellplane {
+       char image[MAX_ROWS_PER_CELL][MAX_BYTES_PER_CELL];
+};
+       
+struct planar_cell_struct {
+       struct cellplane plane[SCREENPLANES];
+};
+
+struct overview_cellplane {
+       char image[MAX_ROWS_PER_CELL][1];
+};
+
+struct overview_planar_cell_struct {
+       struct overview_cellplane plane[SCREENPLANES];
+};
+
+
+
+# endif        /* SCREEN_VGA */
+
+
+/*
+ * Default color Indexes for hardware palettes
+ * 
+ * Do not change the values below.
+ * These are the color mappings defined by the particular video 
+ * hardware/mode.  You can rearrange the NetHack color mappings at
+ * run-time via the defaults.nh "videocolors" and "videoshades"
+ * settings.
+ *
+ */
+
+# if defined(SCREEN_BIOS) || defined(SCREEN_DJGPPFAST) 
+#define M_BLACK                8
+#define M_WHITE                15
+#define M_GRAY                 7       /* low-intensity white */
+#define M_RED                  4
+#define M_GREEN                2
+#define M_BROWN                6       /* low-intensity yellow */
+#define M_BLUE                 1
+#define M_MAGENTA              5
+#define M_CYAN                 3
+#define M_ORANGE               12
+#define M_BRIGHTGREEN          10
+#define M_YELLOW               14
+#define M_BRIGHTBLUE           9
+#define M_BRIGHTMAGENTA        13
+#define M_BRIGHTCYAN           11
+
+#define M_TEXT                M_GRAY
+#define BACKGROUND_COLOR      0
+#define ATTRIB_NORMAL         M_TEXT   /* Normal attribute */
+#define ATTRIB_INTENSE        M_WHITE  /* Intense White */
+#define ATTRIB_MONO_NORMAL    0x01     /* Underlined,white */
+#define ATTRIB_MONO_UNDERLINE 0x01     /* Underlined,white */
+#define ATTRIB_MONO_BLINK     0x87     /* Flash bit, white */
+#define ATTRIB_MONO_REVERSE   0x70     /* Black on white */
+# endif /*SCREEN_BIOS || SCREEN_DJGPPFAST */
+
+# if  defined(SCREEN_VGA) || defined(SCREEN_8514)
+#define BACKGROUND_VGA_COLOR   0
+#define ATTRIB_VGA_NORMAL     CLR_GRAY /* Normal attribute */
+#define ATTRIB_VGA_INTENSE    13       /* Intense White 94/06/07 palette chg*/
+# endif /*SCREEN_VGA || SCREEN_8514*/
+
+# if defined(PC9800)
+static unsigned char attr98[CLR_MAX] = {
+       0xe1,  /*  0 white            */
+       0x21,  /*  1 blue             */
+       0x81,  /*  2 green            */
+       0xa1,  /*  3 cyan             */
+       0x41,  /*  4 red              */
+       0x61,  /*  5 magenta          */
+       0xc1,  /*  6 yellow           */
+       0xe1,  /*  7 white            */
+       0xe1,  /*  8 white            */
+       0x25,  /*  9 reversed blue    */
+       0x85,  /* 10 reversed green   */
+       0xa5,  /* 11 reversed cyan    */
+       0x45,  /* 12 reversed red     */
+       0x65,  /* 13 reversed magenta */
+       0xc5,  /* 14 reversed yellow  */
+       0xe5,  /* 15 reversed white   */
+};
+# endif
+
+# ifdef SIMULATE_CURSOR
+#define CURSOR_HEIGHT    3     /* this should go - MJA */
+/* cursor styles */
+#define CURSOR_INVIS     0     /* cursor not visible at all            */
+#define CURSOR_FRAME     1     /* block around the current tile        */
+#define CURSOR_UNDERLINE 2     /* thin line at bottom of the tile      */
+#define CURSOR_CORNER    3     /* cursor visible at the 4 tile corners */
+#define NUM_CURSOR_TYPES 4     /* number of different cursor types     */
+#define CURSOR_DEFAULT_STYLE CURSOR_CORNER 
+#define CURSOR_DEFAULT_COLOR M_GRAY
+/* global variables for cursor */
+extern int cursor_type;
+extern int cursor_flag;
+extern int cursor_color;
+# endif
+
+
+/*
+ *   Function Prototypes
+ *
+ */
+
+#define E extern
+
+/* ### video.c ### */
+
+# ifdef SIMULATE_CURSOR
+E void NDECL(DrawCursor);
+E void NDECL(HideCursor);
+# endif
+
+/* ### vidtxt.c ### */
+
+# ifdef NO_TERMS
+E void NDECL(txt_backsp);
+E void NDECL(txt_clear_screen);
+E void FDECL(txt_cl_end,(int,int));
+E void NDECL(txt_cl_eos);
+E void NDECL(txt_get_scr_size);
+E void FDECL(txt_gotoxy,(int,int));
+E int  NDECL(txt_monoadapt_check);
+E void NDECL(txt_nhbell);
+E void FDECL(txt_startup,(int*,int*));
+E void FDECL(txt_xputs, (const char *, int, int));
+E void FDECL(txt_xputc, (CHAR_P, int));
+
+/* ### vidvga.c ### */
+
+#  ifdef SCREEN_VGA
+E void NDECL(vga_backsp);
+E void FDECL(vga_clear_screen,(int));
+E void FDECL(vga_cl_end,(int,int));
+E void FDECL(vga_cl_eos,(int));
+E int  NDECL(vga_detect);
+#   ifdef SIMULATE_CURSOR
+E void NDECL(vga_DrawCursor);
+#   endif
+E void FDECL(vga_DisplayCell, (struct planar_cell_struct *, int, int));
+E void FDECL(vga_DisplayCell_O, 
+                       (struct overview_planar_cell_struct *, int, int));
+E void NDECL(vga_Finish);
+E char __far *NDECL(vga_FontPtrs);
+E void NDECL(vga_get_scr_size);
+E void FDECL(vga_gotoloc,(int,int));
+#   ifdef POSITIONBAR
+E void FDECL(vga_update_positionbar, (char *));
+#   endif
+#   ifdef SIMULATE_CURSOR
+E void NDECL(vga_HideCursor);
+#   endif
+E void NDECL(vga_Init);
+E void FDECL(vga_SwitchMode, (unsigned int));
+E void FDECL(vga_SetPalette, (char *));
+E void NDECL(vga_tty_end_screen);
+E void FDECL(vga_tty_startup,(int*,int*));
+E void FDECL(vga_WriteChar, (int, int, int, int));
+E void FDECL(vga_WriteStr, (char *, int, int, int, int));
+E void FDECL(vga_xputs, (const char *, int, int));
+E void FDECL(vga_xputc, (CHAR_P, int));
+E void FDECL(vga_xputg, (int, int, unsigned));
+E void FDECL(vga_userpan, (BOOLEAN_P));
+E void FDECL(vga_overview, (BOOLEAN_P));
+E void FDECL(vga_traditional, (BOOLEAN_P));
+E void NDECL(vga_refresh);
+#  endif /* SCREEN_VGA */
+# endif /* NO_TERMS   */
+
+#undef E
+
+#endif /* PCVIDEO_H  */
+/* pcvideo.h */
diff --git a/sys/msdos/portio.h b/sys/msdos/portio.h
new file mode 100644 (file)
index 0000000..c1d64de
--- /dev/null
@@ -0,0 +1,71 @@
+/*   SCCS Id: @(#)portio.h   3.4     1995/08/05                       */
+/*   Copyright (c) NetHack PC Development Team 1995                 */
+/*   NetHack may be freely redistributed.  See license for details. */
+/*                                                                  */
+/*
+ * portio.h - PC port I/O Hardware support definitions and other
+ *            low-level definitions.
+ *                                                  
+ */
+
+#ifndef PORTIO_H
+#define PORTIO_H
+
+# if defined(__GO32__) || defined(__DJGPP__)
+#define __far
+#include <go32.h>
+#include <dpmi.h>
+#include <sys/farptr.h>
+#endif
+
+# if defined(_MSC_VER)
+#define outportb _outp
+#define outportw _outpw
+#define inportb _inp
+# endif
+# if defined(__BORLANDC__)
+#define outportw outport
+/* #define inportb inport */
+# endif
+
+# ifndef MK_PTR
+/*
+ * Depending on environment, this is a macro to construct either:
+ *
+ *     -  a djgpp long 32 bit pointer from segment & offset values
+ *     -  a far pointer from segment and offset values
+ *
+ */
+#  if defined(_MSC_VER) || defined(__BORLANDC__)
+#define MK_PTR(seg, offset) (void __far *)(((unsigned long)seg << 16) \
+     + (unsigned long)(unsigned)offset)
+#define READ_ABSOLUTE(x) *(x)
+#define READ_ABSOLUTE_WORD(x) *(x)
+#define WRITE_ABSOLUTE(x,y) *(x) = (y)
+#define WRITE_ABSOLUTE_WORD(x,y) *(x) = (y)
+#  endif
+
+#  if defined(__GO32__) || defined(__DJGPP__)
+#define MK_PTR(seg, offset) (void *)(((unsigned)seg << 4) + (unsigned)offset)
+#define READ_ABSOLUTE(x) \
+       (_farpeekb(_go32_conventional_mem_selector(), (unsigned)x))
+#define READ_ABSOLUTE_WORD(x) \
+       (_farpeekw(_go32_conventional_mem_selector(), (unsigned)x))
+#define WRITE_ABSOLUTE(x,y) \
+       _farpokeb(_go32_conventional_mem_selector(), (unsigned)x, (y))
+#define WRITE_ABSOLUTE_WORD(x,y) \
+       _farpokew(_go32_conventional_mem_selector(), (unsigned)x, (y))
+#  endif
+
+#  ifdef OBSOLETE   /* old djgpp V1.x way of mapping 1st MB */
+#define MK_PTR(seg, offset) (void *)(0xE0000000+((((unsigned)seg << 4) \
+     + (unsigned)offset)))
+#define READ_ABSOLUTE(x) *(x)
+#define READ_ABSOLUTE_WORD(x) *(x)
+#define WRITE_ABSOLUTE(x,y) *(x) = (y)
+#define WRITE_ABSOLUTE_WORD(x,y) *(x) = (y)
+#  endif
+# endif /* MK_PTR */
+
+#endif /* PORTIO_H  */
+/* portio.h */
diff --git a/sys/msdos/schema1.BC b/sys/msdos/schema1.BC
new file mode 100644 (file)
index 0000000..3f51531
--- /dev/null
@@ -0,0 +1,252 @@
+/* SCCS Id: @(#)schema1.BC     3.4      1999/10/28 */
+/* Copyright (c) Yitzhak Sapir, 1999 */
+/*  */
+/*  NetHack Overlay Schema */
+/*  Minimal extended memory available, lots of 640K base RAM free */
+/*  Overlay buffer size will be (20 + 20 + 19) = 59K (sum of 3 largest overlays). */
+/*  Requires about 490K (for exe load plus overlay buffer), but */
+/*  an additional 70K free (minimum) will be needed for malloc calls, */
+/*  bringing the total requirement to about 560K. */
+/*  Optimized for minimal overlay turns. */
+/*  */
+
+
+-zCallmain_0 -zAOVLY -zCOVL1
+-zCallmain_1 -zAOVLY -zCOVL2
+-zCallmain_b -zAOVLY -zCOVL3
+-zCalloc_o
+-zCapply_0 -zAOVLY -zCOVL4
+-zCapply_1 -zAOVLY -zCOVL5
+-zCapply_b -zAOVLY -zCOVL6
+-zCartifact_0 -zAOVLY -zCOVL7
+-zCartifact_1 -zAOVLY -zCOVL8
+-zCartifact_b -zAOVLY -zCOVL9
+-zCattrib_0
+-zCattrib_1 -zAOVLY -zCOVL10
+-zCattrib_2 -zAOVLY -zCOVL11
+-zCattrib_b -zAOVLY -zCOVL12
+-zCball_o -zAOVLY -zCOVL13
+-zCbones_o -zAOVLY -zCOVL14
+-zCbotl_0
+-zCbotl_1 -zAOVLY -zCOVL15
+-zCbotl_b -zAOVLY -zCOVL16
+-zCcmd_0
+-zCcmd_1 -zAOVLY -zCOVL17
+-zCcmd_b -zAOVLY -zCOVL18
+-zCdbridge_0
+-zCdbridge_1 -zAOVLY -zCOVL19
+-zCdbridge_b -zAOVLY -zCOVL20
+-zCdecl_o -zAOVLY -zCOVL21
+-zCdetect_o
+-zCdig_o -zAOVLY -zCOVL22
+-zCdisplay_o
+-zCdlb_o -zAOVLY -zCOVL23
+-zCdo_0 -zAOVLY -zCOVL24
+-zCdo_1 -zAOVLY -zCOVL25
+-zCdo_2 -zAOVLY -zCOVL26
+-zCdo_3 -zAOVLY -zCOVL27
+-zCdo_b -zAOVLY -zCOVL28
+-zCdo_name_0 -zAOVLY -zCOVL29
+-zCdo_name_2 -zAOVLY -zCOVL30
+-zCdo_name_b -zAOVLY -zCOVL31
+-zCdo_wear_0 -zAOVLY -zCOVL32
+-zCdo_wear_1 -zAOVLY -zCOVL33
+-zCdo_wear_2 -zAOVLY -zCOVL34
+-zCdo_wear_b -zAOVLY -zCOVL35
+-zCdog_1 -zAOVLY -zCOVL36
+-zCdog_2 -zAOVLY -zCOVL37
+-zCdog_b -zAOVLY -zCOVL38
+-zCdogmove_0 -zAOVLY -zCOVL39
+-zCdogmove_b
+-zCdokick_o -zAOVLY -zCOVL40
+-zCdothrow_o -zAOVLY -zCOVL41
+-zCdrawing_o -zAOVLY -zCOVL42
+-zCdungeon_0
+-zCdungeon_1 -zAOVLY -zCOVL43
+-zCeat_0 -zAOVLY -zCOVL44
+-zCeat_1 -zAOVLY -zCOVL45
+-zCeat_b -zAOVLY -zCOVL46
+-zCend_o -zAOVLY -zCOVL47
+-zCengrave_0
+-zCengrave_1 -zAOVLY -zCOVL48
+-zCengrave_2 -zAOVLY -zCOVL49
+-zCengrave_b -zAOVLY -zCOVL50
+-zCexper_o -zAOVLY -zCOVL51
+-zCexplode_0 -zAOVLY -zCOVL52
+-zCexplode_1 -zAOVLY -zCOVL53
+-zCextralev_o -zAOVLY -zCOVL54
+-zCfiles_o -zAOVLY -zCOVL55
+-zCfountain_o -zAOVLY -zCOVL56
+-zCgetline_1 -zAOVLY -zCOVL57
+-zCgetline_2 -zAOVLY -zCOVL58
+-zChack_1
+-zChack_2 -zAOVLY -zCOVL59
+-zChack_3
+-zChack_b -zAOVLY -zCOVL60
+-zChacklib_0
+-zChacklib_1
+-zChacklib_2
+-zChacklib_b -zAOVLY -zCOVL61
+-zCinvent_0
+-zCinvent_1 -zAOVLY -zCOVL62
+-zCinvent_2 -zAOVLY -zCOVL63
+-zCinvent_3 -zAOVLY -zCOVL64
+-zCinvent_b -zAOVLY -zCOVL65
+-zClight_3 -zAOVLY -zCOVL66
+-zClock_0 -zAOVLY -zCOVL67
+-zClock_b -zAOVLY -zCOVL68
+-zCmail_0 -zAOVLY -zCOVL68
+-zCmail_b -zAOVLY -zCOVL69
+-zCmakemon_0 -zAOVLY -zCOVL70
+-zCmakemon_1 -zAOVLY -zCOVL71
+-zCmakemon_2 -zAOVLY -zCOVL72
+-zCmakemon_b -zAOVLY -zCOVL73
+-zCmcastu_0 -zAOVLY -zCOVL74
+-zCmcastu_b -zAOVLY -zCOVL75
+-zCmhitm_0 -zAOVLY -zCOVL76
+-zCmhitm_b -zAOVLY -zCOVL77
+-zCmhitu_0 -zAOVLY -zCOVL78
+-zCmhitu_1 -zAOVLY -zCOVL79
+-zCmhitu_b -zAOVLY -zCOVL80
+-zCminion_o -zAOVLY -zCOVL81
+-zCmklev_o -zAOVLY -zCOVL82
+-zCmkmap_o -zAOVLY -zCOVL83
+-zCmkmaze_o -zAOVLY -zCOVL84
+-zCmkobj_0 -zAOVLY -zCOVL85
+-zCmkobj_1 -zAOVLY -zCOVL86
+-zCmkobj_b -zAOVLY -zCOVL87
+-zCmkroom_0 -zAOVLY -zCOVL88
+-zCmkroom_b -zAOVLY -zCOVL89
+-zCmon_0
+-zCmon_1 -zAOVLY -zCOVL90
+-zCmon_2 -zAOVLY -zCOVL91
+-zCmon_b -zAOVLY -zCOVL92
+-zCmondata_0
+-zCmondata_1 -zAOVLY -zCOVL93
+-zCmondata_2 -zAOVLY -zCOVL94
+-zCmondata_b -zAOVLY -zCOVL95
+-zCmonmove_0
+-zCmonmove_1
+-zCmonmove_2
+-zCmonmove_b -zAOVLY -zCOVL96
+-zCmonst_o -zAOVLY -zCOVL97
+-zCmonstr_o -zAOVLY -zCOVL98
+-zCmplayer_o -zAOVLY -zCOVL99
+-zCmsdos_0
+-zCmsdos_b -zAOVLY -zCOVL100
+-zCmthrowu_0 -zAOVLY -zCOVL101
+-zCmthrowu_1 -zAOVLY -zCOVL102
+-zCmthrowu_b -zAOVLY -zCOVL103
+-zCmuse_o -zAOVLY -zCOVL104
+-zCmusic_o -zAOVLY -zCOVL105
+-zCo_init_o -zAOVLY -zCOVL106
+-zCobjects_o -zAOVLY -zCOVL107
+-zCobjnam_0 -zAOVLY -zCOVL108
+-zCobjnam_1 -zAOVLY -zCOVL109
+-zCobjnam_b -zAOVLY -zCOVL110
+-zCoptions_o -zAOVLY -zCOVL111
+-zCovlinit_o
+-zCpager_o -zAOVLY -zCOVL112
+-zCpckeys_o
+-zCpcmain_0
+-zCpcmain_1 -zAOVLY -zCOVL113
+-zCpcmain_b -zAOVLY -zCOVL114
+-zCpctiles_0
+-zCpctiles_b
+-zCpcunix_b -zAOVLY -zCOVL115
+-zCpickup_o -zAOVLY -zCOVL116
+-zCpline_b -zAOVLY -zCOVL117
+-zCpolyself_0 -zAOVLY -zCOVL118
+-zCpolyself_1 -zAOVLY -zCOVL119
+-zCpolyself_b -zAOVLY -zCOVL120
+-zCpotion_b -zAOVLY -zCOVL121
+-zCpray_o -zAOVLY -zCOVL122
+-zCpriest_0 -zAOVLY -zCOVL123
+-zCpriest_b -zAOVLY -zCOVL124
+-zCquest_o -zAOVLY -zCOVL125
+-zCquestpgr_o -zAOVLY -zCOVL126
+-zCrandom_o
+-zCread_b -zAOVLY -zCOVL127
+-zCrect_o -zAOVLY -zCOVL128
+-zCregion_o -zAOVLY -zCOVL129
+-zCrestore_o -zAOVLY -zCOVL130
+-zCrip_o -zAOVLY -zCOVL131
+-zCrnd_0
+-zCrnd_1 -zAOVLY -zCOVL132
+-zCrnd_b -zAOVLY -zCOVL133
+-zCrole_o -zAOVLY -zCOVL113
+-zCrumors_o -zAOVLY -zCOVL134
+-zCsave_o -zAOVLY -zCOVL135
+-zCshk_0 -zAOVLY -zCOVL136
+-zCshk_1 -zAOVLY -zCOVL137
+-zCshk_2 -zAOVLY -zCOVL138
+-zCshk_3 -zAOVLY -zCOVL139
+-zCshk_b -zAOVLY -zCOVL140
+-zCshknam_0 -zAOVLY -zCOVL141
+-zCshknam_b -zAOVLY -zCOVL142
+-zCsit_o -zAOVLY -zCOVL143
+-zCsound_o
+-zCsounds_0 -zAOVLY -zCOVL144
+-zCsounds_b -zAOVLY -zCOVL145
+-zCsp_lev_o -zAOVLY -zCOVL146
+-zCspell_o -zAOVLY -zCOVL147
+-zCsteal_0 -zAOVLY -zCOVL148
+-zCsteal_1 -zAOVLY -zCOVL149
+-zCsteal_b -zAOVLY -zCOVL150
+-zCsteed_o -zAOVLY -zCOVL188
+-zCsys_o -zAOVLY -zCOVL151
+-zCteleport_o -zAOVLY -zCOVL152
+-zCtermcap_0 -zAOVLY -zCOVL153
+-zCtermcap_1 -zAOVLY -zCOVL154
+-zCtermcap_b -zAOVLY -zCOVL155
+-zCtile_o
+-zCtimeout_0 -zAOVLY -zCOVL156
+-zCtimeout_1 -zAOVLY -zCOVL157
+-zCtimeout_b -zAOVLY -zCOVL158
+-zCtopl_1 -zAOVLY -zCOVL159
+-zCtopl_2 -zAOVLY -zCOVL160
+-zCtopl_b -zAOVLY -zCOVL161
+-zCtopten_o -zAOVLY -zCOVL162
+-zCtrack_0 -zAOVLY -zCOVL163
+-zCtrack_1 -zAOVLY -zCOVL164
+-zCtrack_b -zAOVLY -zCOVL165
+-zCtrap_0
+-zCtrap_1 -zAOVLY -zCOVL166
+-zCtrap_2 -zAOVLY -zCOVL167
+-zCtrap_3 -zAOVLY -zCOVL168
+-zCtrap_b -zAOVLY -zCOVL169
+-zCtty_o -zAOVLY -zCOVL170
+-zCu_init_o -zAOVLY -zCOVL171
+-zCuhitm_o -zAOVLY -zCOVL172
+-zCvault_0 -zAOVLY -zCOVL173
+-zCvault_b -zAOVLY -zCOVL174
+-zCversion_o -zAOVLY -zCOVL175
+-zCvideo_0
+-zCvideo_1
+-zCvideo_b
+-zCvidtxt_0
+-zCvidtxt_b
+-zCvidvga_0
+-zCvidvga_1
+-zCvidvga_2 -zAOVLY -zCOVL176
+-zCvidvga_b
+-zCvis_tab_o -zAOVLY -zCOVL177
+-zCvision_o
+-zCweapon_0 -zAOVLY -zCOVL178
+-zCweapon_1 -zAOVLY -zCOVL179
+-zCweapon_b -zAOVLY -zCOVL180
+-zCwere_0 -zAOVLY -zCOVL181
+-zCwere_b -zAOVLY -zCOVL182
+-zCwield_o -zAOVLY -zCOVL183
+-zCwindows_o -zAOVLY -zCOVL184
+-zCwintty_o
+-zCwizard_0 -zAOVLY -zCOVL185
+-zCwizard_b -zAOVLY -zCOVL186
+-zCworm_o -zAOVLY -zCOVL187
+-zCworn_o -zAOVLY -zCOVL188
+-zCwrite_o -zAOVLY -zCOVL189
+-zCzap_0 -zAOVLY -zCOVL190
+-zCzap_1 -zAOVLY -zCOVL191
+-zCzap_2 -zAOVLY -zCOVL192
+-zCzap_3 -zAOVLY -zCOVL193
+-zCzap_b -zAOVLY -zCOVL194
diff --git a/sys/msdos/schema2.BC b/sys/msdos/schema2.BC
new file mode 100644 (file)
index 0000000..3d15f5c
--- /dev/null
@@ -0,0 +1,248 @@
+/* SCCS Id: @(#)schema2.BC     3.4      1999/10/28 */
+/* Copyright (c) Yitzhak Sapir, 1999 */
+/*  */
+/*  NetHack Overlay Schema */
+/*  Small Root footprint, with extended memory available for caching. */
+/*  Almost everything is overlaid. */
+/*  */
+
+
+-zCallmain_0 -zAOVLY -zCOVL1
+-zCallmain_1 -zAOVLY -zCOVL2
+-zCallmain_b -zAOVLY -zCOVL3
+-zCalloc_o
+-zCapply_0 -zAOVLY -zCOVL4
+-zCapply_1 -zAOVLY -zCOVL5
+-zCapply_b -zAOVLY -zCOVL6
+-zCartifact_0 -zAOVLY -zCOVL7
+-zCartifact_1 -zAOVLY -zCOVL8
+-zCartifact_b -zAOVLY -zCOVL9
+-zCattrib_0 -zAOVLY -zCOVL10
+-zCattrib_1 -zAOVLY -zCOVL11
+-zCattrib_2 -zAOVLY -zCOVL12
+-zCattrib_b -zAOVLY -zCOVL13
+-zCball_o -zAOVLY -zCOVL14
+-zCbones_o -zAOVLY -zCOVL15
+-zCbotl_0 -zAOVLY -zCOVL16
+-zCbotl_1 -zAOVLY -zCOVL17
+-zCbotl_b -zAOVLY -zCOVL18
+-zCcmd_0 -zAOVLY -zCOVL19
+-zCcmd_1 -zAOVLY -zCOVL20
+-zCcmd_b -zAOVLY -zCOVL21
+-zCdbridge_0 -zAOVLY -zCOVL22
+-zCdbridge_1 -zAOVLY -zCOVL23
+-zCdbridge_b -zAOVLY -zCOVL24
+-zCdecl_o -zAOVLY -zCOVL25
+-zCdetect_o -zAOVLY -zCOVL26
+-zCdig_o -zAOVLY -zCOVL27
+-zCdisplay_o -zAOVLY -zCOVL28
+-zCdlb_o -zAOVLY -zCOVL29
+-zCdo_0 -zAOVLY -zCOVL30
+-zCdo_1 -zAOVLY -zCOVL31
+-zCdo_2 -zAOVLY -zCOVL32
+-zCdo_3 -zAOVLY -zCOVL33
+-zCdo_b -zAOVLY -zCOVL34
+-zCdo_name_0 -zAOVLY -zCOVL35
+-zCdo_name_2 -zAOVLY -zCOVL36
+-zCdo_name_b -zAOVLY -zCOVL37
+-zCdo_wear_0 -zAOVLY -zCOVL38
+-zCdo_wear_1 -zAOVLY -zCOVL39
+-zCdo_wear_2 -zAOVLY -zCOVL40
+-zCdo_wear_b -zAOVLY -zCOVL41
+-zCdog_1 -zAOVLY -zCOVL42
+-zCdog_2 -zAOVLY -zCOVL43
+-zCdog_b -zAOVLY -zCOVL44
+-zCdogmove_0 -zAOVLY -zCOVL45
+-zCdogmove_b -zAOVLY -zCOVL46
+-zCdokick_o -zAOVLY -zCOVL47
+-zCdothrow_o -zAOVLY -zCOVL48
+-zCdrawing_o -zAOVLY -zCOVL49
+-zCdungeon_0 -zAOVLY -zCOVL50
+-zCdungeon_1 -zAOVLY -zCOVL51
+-zCeat_0 -zAOVLY -zCOVL52
+-zCeat_1 -zAOVLY -zCOVL53
+-zCeat_b -zAOVLY -zCOVL54
+-zCend_o -zAOVLY -zCOVL55
+-zCengrave_0 -zAOVLY -zCOVL56
+-zCengrave_1 -zAOVLY -zCOVL57
+-zCengrave_2 -zAOVLY -zCOVL58
+-zCengrave_b -zAOVLY -zCOVL59
+-zCexper_o -zAOVLY -zCOVL60
+-zCexplode_0 -zAOVLY -zCOVL61
+-zCexplode_1 -zAOVLY -zCOVL62
+-zCextralev_o -zAOVLY -zCOVL63
+-zCfiles_o -zAOVLY -zCOVL64
+-zCfountain_o -zAOVLY -zCOVL65
+-zCgetline_1 -zAOVLY -zCOVL66
+-zCgetline_2 -zAOVLY -zCOVL67
+-zChack_1 -zAOVLY -zCOVL68
+-zChack_2 -zAOVLY -zCOVL69
+-zChack_3
+-zChack_b -zAOVLY -zCOVL70
+-zChacklib_0 -zAOVLY -zCOVL71
+-zChacklib_1 -zAOVLY -zCOVL72
+-zChacklib_2 -zAOVLY -zCOVL73
+-zChacklib_b -zAOVLY -zCOVL74
+-zCinvent_0 -zAOVLY -zCOVL75
+-zCinvent_1 -zAOVLY -zCOVL76
+-zCinvent_2 -zAOVLY -zCOVL77
+-zCinvent_3 -zAOVLY -zCOVL78
+-zCinvent_b -zAOVLY -zCOVL79
+-zClight_3 -zAOVLY -zCOVL80
+-zClock_0 -zAOVLY -zCOVL81
+-zClock_b -zAOVLY -zCOVL82
+-zCmail_0 -zAOVLY -zCOVL82
+-zCmail_b -zAOVLY -zCOVL83
+-zCmakemon_0 -zAOVLY -zCOVL84
+-zCmakemon_1 -zAOVLY -zCOVL85
+-zCmakemon_2 -zAOVLY -zCOVL86
+-zCmakemon_b -zAOVLY -zCOVL87
+-zCmcastu_0 -zAOVLY -zCOVL88
+-zCmcastu_b -zAOVLY -zCOVL89
+-zCmhitm_0 -zAOVLY -zCOVL90
+-zCmhitm_b -zAOVLY -zCOVL91
+-zCmhitu_0 -zAOVLY -zCOVL92
+-zCmhitu_1 -zAOVLY -zCOVL93
+-zCmhitu_b -zAOVLY -zCOVL94
+-zCminion_o -zAOVLY -zCOVL95
+-zCmklev_o -zAOVLY -zCOVL96
+-zCmkmap_o -zAOVLY -zCOVL97
+-zCmkmaze_o -zAOVLY -zCOVL98
+-zCmkobj_0 -zAOVLY -zCOVL99
+-zCmkobj_1 -zAOVLY -zCOVL100
+-zCmkobj_b -zAOVLY -zCOVL101
+-zCmkroom_0 -zAOVLY -zCOVL102
+-zCmkroom_b -zAOVLY -zCOVL103
+-zCmon_0 -zAOVLY -zCOVL104
+-zCmon_1 -zAOVLY -zCOVL105
+-zCmon_2 -zAOVLY -zCOVL106
+-zCmon_b -zAOVLY -zCOVL107
+-zCmondata_0 -zAOVLY -zCOVL108
+-zCmondata_1 -zAOVLY -zCOVL109
+-zCmondata_2 -zAOVLY -zCOVL110
+-zCmondata_b -zAOVLY -zCOVL111
+-zCmonmove_0 -zAOVLY -zCOVL112
+-zCmonmove_1 -zAOVLY -zCOVL113
+-zCmonmove_2 -zAOVLY -zCOVL114
+-zCmonmove_b -zAOVLY -zCOVL115
+-zCmonst_o -zAOVLY -zCOVL116
+-zCmonstr_o -zAOVLY -zCOVL117
+-zCmplayer_o -zAOVLY -zCOVL118
+-zCmsdos_0 -zAOVLY -zCOVL119
+-zCmsdos_b -zAOVLY -zCOVL120
+-zCmthrowu_0 -zAOVLY -zCOVL121
+-zCmthrowu_1 -zAOVLY -zCOVL122
+-zCmthrowu_b -zAOVLY -zCOVL123
+-zCmuse_o -zAOVLY -zCOVL124
+-zCmusic_o -zAOVLY -zCOVL125
+-zCo_init_o -zAOVLY -zCOVL126
+-zCobjects_o -zAOVLY -zCOVL127
+-zCobjnam_0 -zAOVLY -zCOVL128
+-zCobjnam_1 -zAOVLY -zCOVL129
+-zCobjnam_b -zAOVLY -zCOVL130
+-zCoptions_o -zAOVLY -zCOVL131
+-zCovlinit_o
+-zCpager_o -zAOVLY -zCOVL132
+-zCpckeys_o -zAOVLY -zCOVL119
+-zCpcmain_0
+-zCpcmain_1 -zAOVLY -zCOVL133
+-zCpcmain_b -zAOVLY -zCOVL134
+-zCpctiles_0
+-zCpctiles_b
+-zCpcunix_b -zAOVLY -zCOVL135
+-zCpickup_o -zAOVLY -zCOVL136
+-zCpline_b -zAOVLY -zCOVL137
+-zCpolyself_0 -zAOVLY -zCOVL138
+-zCpolyself_1 -zAOVLY -zCOVL139
+-zCpolyself_b -zAOVLY -zCOVL140
+-zCpotion_b -zAOVLY -zCOVL141
+-zCpray_o -zAOVLY -zCOVL142
+-zCpriest_0 -zAOVLY -zCOVL143
+-zCpriest_b -zAOVLY -zCOVL144
+-zCquest_o -zAOVLY -zCOVL145
+-zCquestpgr_o -zAOVLY -zCOVL146
+-zCrandom_o -zAOVLY -zCOVL147
+-zCread_b -zAOVLY -zCOVL148
+-zCrect_o -zAOVLY -zCOVL149
+-zCregion_o -zAOVLY -zCOVL150
+-zCrestore_o -zAOVLY -zCOVL151
+-zCrip_o -zAOVLY -zCOVL152
+-zCrnd_0 -zAOVLY -zCOVL153
+-zCrnd_1 -zAOVLY -zCOVL154
+-zCrnd_b -zAOVLY -zCOVL155
+-zCrole_o -zAOVLY -zCOVL133
+-zCrumors_o -zAOVLY -zCOVL156
+-zCsave_o -zAOVLY -zCOVL157
+-zCshk_0 -zAOVLY -zCOVL158
+-zCshk_1 -zAOVLY -zCOVL159
+-zCshk_2 -zAOVLY -zCOVL160
+-zCshk_3 -zAOVLY -zCOVL161
+-zCshk_b -zAOVLY -zCOVL162
+-zCshknam_0 -zAOVLY -zCOVL163
+-zCshknam_b -zAOVLY -zCOVL164
+-zCsit_o -zAOVLY -zCOVL165
+-zCsound_o
+-zCsounds_0 -zAOVLY -zCOVL166
+-zCsounds_b -zAOVLY -zCOVL167
+-zCsp_lev_o -zAOVLY -zCOVL168
+-zCspell_o -zAOVLY -zCOVL169
+-zCsteal_0 -zAOVLY -zCOVL170
+-zCsteal_1 -zAOVLY -zCOVL171
+-zCsteal_b -zAOVLY -zCOVL172
+-zCsteed_o -zAOVLY -zCOVL173
+-zCsys_o -zAOVLY -zCOVL174
+-zCteleport_o -zAOVLY -zCOVL175
+-zCtermcap_0 -zAOVLY -zCOVL176
+-zCtermcap_1 -zAOVLY -zCOVL177
+-zCtermcap_b -zAOVLY -zCOVL178
+-zCtile_o
+-zCtimeout_0 -zAOVLY -zCOVL179
+-zCtimeout_1 -zAOVLY -zCOVL180
+-zCtimeout_b -zAOVLY -zCOVL181
+-zCtopl_1 -zAOVLY -zCOVL182
+-zCtopl_2 -zAOVLY -zCOVL183
+-zCtopl_b -zAOVLY -zCOVL184
+-zCtopten_o -zAOVLY -zCOVL185
+-zCtrack_0 -zAOVLY -zCOVL186
+-zCtrack_1 -zAOVLY -zCOVL187
+-zCtrack_b -zAOVLY -zCOVL188
+-zCtrap_0 -zAOVLY -zCOVL189
+-zCtrap_1 -zAOVLY -zCOVL190
+-zCtrap_2 -zAOVLY -zCOVL191
+-zCtrap_3 -zAOVLY -zCOVL192
+-zCtrap_b -zAOVLY -zCOVL193
+-zCtty_o -zAOVLY -zCOVL194
+-zCu_init_o -zAOVLY -zCOVL195
+-zCuhitm_o -zAOVLY -zCOVL196
+-zCvault_0 -zAOVLY -zCOVL197
+-zCvault_b -zAOVLY -zCOVL198
+-zCversion_o -zAOVLY -zCOVL199
+-zCvideo_0
+-zCvideo_1
+-zCvideo_b
+-zCvidtxt_0
+-zCvidtxt_b
+-zCvidvga_0
+-zCvidvga_1
+-zCvidvga_2 -zAOVLY -zCOVL200
+-zCvidvga_b
+-zCvis_tab_o -zAOVLY -zCOVL201
+-zCvision_o -zAOVLY -zCOVL202
+-zCweapon_0 -zAOVLY -zCOVL203
+-zCweapon_1 -zAOVLY -zCOVL204
+-zCweapon_b -zAOVLY -zCOVL205
+-zCwere_0 -zAOVLY -zCOVL206
+-zCwere_b -zAOVLY -zCOVL207
+-zCwield_o -zAOVLY -zCOVL208
+-zCwindows_o -zAOVLY -zCOVL209
+-zCwintty_o -zAOVLY -zCOVL210
+-zCwizard_0 -zAOVLY -zCOVL211
+-zCwizard_b -zAOVLY -zCOVL212
+-zCworm_o -zAOVLY -zCOVL213
+-zCworn_o -zAOVLY -zCOVL173
+-zCwrite_o -zAOVLY -zCOVL214
+-zCzap_0 -zAOVLY -zCOVL215
+-zCzap_1 -zAOVLY -zCOVL216
+-zCzap_2 -zAOVLY -zCOVL217
+-zCzap_3 -zAOVLY -zCOVL218
+-zCzap_b -zAOVLY -zCOVL219
diff --git a/sys/msdos/schema3.MSC b/sys/msdos/schema3.MSC
new file mode 100644 (file)
index 0000000..df254e9
--- /dev/null
@@ -0,0 +1,429 @@
+; SCCS Id: @(#)schema3.MSC     3.4      2003/08/03
+; Copyright (c) NetHack PC Development Team, 2000
+;
+; NetHack Overlay Schema
+; This overlay schema is for use only when NetHack is built
+; using packaged-functions for function-level linking.
+;
+; Overlay tuning level: 0
+;
+functions:0 _main _dosave0 _moveloop _bputc _bwrite _random _rn2 _newsym _show_glyph _on_level _txt_gotoxy _txt_get_cursor
+functions:0 _xputc _txt_xputc _t_at _tty_curs _acurr _dist2 _tty_print_glyph _isok _back_to_glyph
+functions:0 _show_map_spot _adjust_cursor_flags _lowc _g_putch _has_color _is_pool _mread
+functions:0 _is_lava _welded _magic_map_background _end_glyphout _visible_region_at _domove 
+functions:0 _engr_at _rnd _run_regions _mcalcmove _depth _done _distmin _does_block _eos 
+functions:0 _move _move_bc _in_rooms _map_background _map_invisible _map_location _alloc
+functions:0 _impossible _in_container _in_fcorridor _In_hell _In_mines _in_or_out_menu _In_quest
+functions:0 _do_positionbar _iswall _iswall_or_stone _itimeout _is_solid _Is_special
+functions:0 _is_swallow_sym _check_here _check_leash _check_map_spot _check_pos 
+functions:0 _monsndx _m_move _lcase _tty_create_nhwindow _tty_delay_output _tty_destroy_nhwindow 
+functions:0 _tty_dismiss_nhwindow _gender _genl_outrip _get_cost _get_free_room_loc _get_level 
+functions:0 _get_location _get_map _get_mleash
+;
+functions:1 _move_update _movebubbles _movecmd _movemon _moverock _movobj _mpickgold
+functions:1 _doaltarobj _doapply _dobreathe _docall _docast
+;
+functions:2 _do_vicinity_map
+functions:3 _pcmain
+functions:4 _spell_let_to_idx _cursed_book _deadbook _learn _getspell _spelltypemnemonic
+functions:5 _dospellmenu _percent_success _throwspell _cast_protection _isqrt
+;
+functions:6 _a_gname _a_gname_at _a_monnam _abon _abuse_dog _accessible _activate_statue_trap
+functions:7 _add_branch _add_damage _add_debug_extended_commands _add_door _add_id_mapping _add_level
+functions:8 _add_menu_cmd_alias _add_one_tobill _add_rect _add_room _add_subroom _add_to_billobjs _add_to_buried _add_to_container
+functions:9 _add_to_migration _add_to_minv _add_valid_menu_class _add_weapon_skill _addinv _addtobill _addtopl _addupbill
+functions:10 _Adjmonnam
+functions:11 _align_gname
+functions:12 _altar_wrath _Amonnam _amulet _Amulet_off _Amulet_on _An _an _angry_guards
+functions:13 _angry_priest _angry_shk_exists _any_light_source _aobjnam _append_slash _append_str _Armor_gone _Armor_off
+functions:14 _Armor_on _armor_to_dragon _armoroff _arti_invoke _artifact_exists _artifact_hit _artifact_name _artiname
+functions:15 _artitouch _askchain _assign_graphics _assign_level _assign_rnd_level _assign_rogue_graphics _assign_soundcard _assign_video
+functions:16 _assign_videocolors _assign_videoshades _assigninvlet _at_dgn_entrance _attach_egg_hatch_timeout _attack _attack_checks _attacks
+functions:17 _awaken_monsters _awaken_soldiers
+functions:18 _backfire _backsp _bad_location _bad_negation _bad_rock _badoption _bail _ballfall
+functions:19 _bc_order _bclose _bcsign _beg _begin_burn _bflush _bhit _bhitm
+functions:20 _bhito _bhitpile _big_to_little _bill_box_content _bill_dummy_object _bite _bless _blessorcurse
+functions:21 _Blindf_off _Blindf_on _block_door _block_entry _block_point _blow_up_landmine _body_part
+functions:22 _boomhit _Boots_off _Boots_on _bot _bot1 _bot2 _boulder_hits_pool _bound_digging
+functions:23 _boxlock _br_string _break_armor _break_statue _breakarm _breakmsg
+functions:24 _breakobj _breaks _breaksink _breaktest _breamu _bribe _bufoff _bufon
+functions:25 _build_room _burn_floor_paper _burn_object _burnarmor _bury_an_obj _bury_objs _buzz _buzzmu
+functions:26 _Can_dig_down
+functions:27 _Can_fall_thru _can_make_bones _can_ooze _can_pray _can_reach_floor _Can_rise_up _can_track
+functions:28 _cancel_bonesfile _cancel_don _cancel_item _cancel_monst _candle_light_range _canletgo _cant_create _canwearobj
+functions:29 _carry_count _carrying _castmu _ceiling _center _change_inv_order _change_luck _change_sex
+functions:30 _charm_monsters _charm_snakes _chat_with_guardian _chat_with_leader _chat_with_nemesis _chdirx _chdrive _cheapest_item
+functions:31 _check_capacity _check_contained _check_credit _check_recordfile
+functions:32 _check_room _check_shop_obj _check_special_room _check_unpaid _check_unpaid_usage _check_version _checkfile _chest_shatter_msg
+functions:33 _chest_trap _choke _choke_dialogue _choose_classes_menu _choose_windows _christen_monst _chwepon _ck_bag
+functions:34 _ckmailstatus _ckunpaid _cl_end _cl_eos _classmon _clear_fcorr _clear_glyph_buffer
+functions:35 _clear_id_mapping _clear_level_structures _clear_path _clear_screen _clear_stale_map _clear_unpaid _clearlocks _clearpriests
+functions:36 _click_to_cmd _Cloak_off _Cloak_on _clone_mon _cloneu _clonewiz _close_drawbridge _close_library
+functions:37 _closed_door _CloseTileFile _cls _cmov _cnv_trap_obj _co_false _collect_obj_classes _com_pager
+functions:38 _commit_bonesfile _compactify _compress _compress_bonesfile _compress_str _comspec_exists _confdir _construct_qtlist
+functions:39 _consume_offering _contained _contained_cost _contained_gold _container_contents _container_weight _convert_arg _convert_line
+functions:40 _copybones _copyfile _corpse_chance _corpse_xname _corr _correct_branch_type _cost _cost_per_charge
+functions:41 _costly_cancel _costly_gold _costly_spot _could_seduce _count_categories _count_obj _count_unpaid _count_wsegs
+functions:42 _counter_were _courtmon _cpostfx _cprefx _create_altar _create_bonesfile _create_corridor _create_critters
+functions:43 _create_door _create_drawbridge _create_engraving _create_feature _create_gold _create_levelfile _create_monster _create_mplayers
+functions:44 _create_object _create_particular _create_polymon _create_room _create_savefile _create_secret_door _create_stairs _create_subroom
+functions:45 _create_trap _create_worm_tail _curr_mon_load _currentlevel_rewrite _curs_on_u _curse _cursed _cursed_object_at
+functions:46 _cursetxt _cuss _cutworm _cvt_sdoor_to_door _d _damageum _dbon _ddocall
+functions:47 _ddoinv _dead_species _dealloc_obj _decl_init _deepest_lev_reached _def_char_to_monclass _def_char_to_objclass _def_raw_print
+functions:48 _defends _deferred_goto _del_engr _del_engr_at _del_light_source _delallobj _delete_bonesfile _delete_contents
+functions:49 _delete_levelfile _delete_savefile _delfloortrap _deliver_by_pline _deliver_by_window _delobj _deltrap _demon_talk
+functions:50 _demonpet _destroy_arm _destroy_drawbridge _destroy_item _destroy_mitem _dev_name _dig
+functions:51 _dig_check _dig_corridor _dig_point _dig_typ _digactualhole _dighole _digit _dipfountain
+functions:52 _disable_ctrlP _disarm_landmine _disarm_shooting_trap _disarm_squeaky_board _discard_minvent _disclose _discover_object
+functions:53 _diseasemu _display_binventory _display_cinventory _display_gamewindows _display_inventory _display_minventory
+functions:54 _distant_name _distfleeck _disturb _djinni_from_bottle _dlb_cleanup _dlb_fclose
+functions:55 _dlb_fgets _dlb_fopen _dlb_fread _dlb_fseek _dlb_ftell _dlb_init _dlord _dmgtype
+functions:56 _dmgval _dmonsfree _dmore _dname_to_dnum _do_break_wand _do_clear_area _do_comp _do_dknown_of
+functions:57 _do_earthquake _do_entity _do_genocide _do_improvisation _do_light_sources _do_look _do_mapping _do_mname
+functions:57 _vga_xputg _vga_xputs _video_update_positionbar _view_from _view_init _visctrl _vision_init _vision_recalc
+functions:58 _do_oname _do_osshock _do_play_instrument _do_reset_eat _do_room_or_subroom _do_storms _do_takeoff
+functions:60 _doclose _doconsult _docorner _docrt _doddoremarm _doddrop _dodip
+functions:61 _adjust_prefix _build_plselection_prompt _duplicate_opt_detection _enter_explore_mode _maybe_wail
+functions:62 _doextcmd _doextlist _doextversion _dofindgem _dofiretrap _doforce _dog_eat _dog_goal
+functions:63 _dog_hunger _dog_invent _dog_move _dog_nutrition _dogfood _dogushforth _dohelp _dohide
+functions:64 _dohistory _doidtrap _doinvbill _doinvoke _dojump _dokick _dolook _doloot
+functions:65 _domagicportal 
+functions:66 _done_eating _done_in_by _done_intr _done1 _done2 _donning _donull _doopen
+functions:67 _doorganize _doorlock _dopay _dopayobj _dopickup _dopotion _dopramulet _doprarm
+functions:68 _dopray _doprev_message _doprgold _doprring _doprtool _doprwep _doputon _doquickwhatis
+functions:69 _doread _dorecover _doredraw _doremove _doremring _dorub _dosacrifice _dosave
+functions:70 _dosdoor _dosearch _dosearch0 _doseduce _doset _doset_add_menu _dosh
+functions:71 _dosinkfall _dosinkring _dosit _dosounds _dospinweb _dospit _dosummon _dotakeoff
+functions:72 _dotalk _dotele _dothrow _dotogglepickup _dotrap _doturn _dotypeinv _dounpaid
+functions:73 _dountrap _doup _doversion _dovspell _dowaterdemon _dowaternymph _dowatersnakes _dowear
+functions:74 _dowhatdoes _dowhatis _dowield _dowipe _down_gate _dowrite _dozap _dprince
+functions:75 _drag_ball _drag_down _drain_en _DrawCursor _drinkfountain _drinksink _drop _drop_ball
+functions:76 _drop_throw _drop_to _drop_upon_death _drop_weapon _DROPPABLES _dropped_container _dropx _dropy
+functions:77 _drown _dryup _dtoxy _dungeon_branch _dunlev _dunlevs_in_dungeon _e_at _e_died
+functions:78 _e_jumps _e_missed _e_nam _E_phrase _e_survives_at _eataccessory _eatcorpse _eaten_stat
+functions:79 _eatfood _eatmdone _eatspecial _egg_type_from_parent _emergency_disrobe _enable_ctrlP _encumber_msg _end_burn
+functions:80 _end_engulf
+;functions:81 
+functions:82 _exclam _exepath _exerchk _exercise _exerper _exist_artifact _expels _experience
+functions:83 _explmm _explmu _explode _explum _expulsion _ext_cmd_getlin_hook _extend_spine _extract_nexthere
+functions:84 _extract_nobj _fall_asleep _fall_through _feel_cockatrice _feel_location _fightm _filesize_nh _fill_pit
+functions:85 _nh_getenv _promptsep _rigid_role_checks _set_duplicate_opt_detection _tool_in_use
+functions:86 _find_drawbridge _find_hell _find_lev_obj _find_level _find_mac _find_mid _find_misc _find_offensive
+functions:87 _find_oid _find_roll_to_hit _find_skates _find_unpaid _finddpos _findfirst_file _findgd _findit
+functions:88 _findnext_file _findone _findpriest _finish_map _finish_paybill _fix_stair_rooms _fix_worst_trouble _fixup_special
+functions:89 _flash_hits_mon _float_down _float_up _floating_above _flood_fill_rm _flooreffects _floorfood _flush_screen _term_start_color
+functions:90 _flushout _fmt_ptr _food_detect _food_disappears _food_xname _foodword _fopen_config_file _fopen_datafile
+functions:91 _fopenp _forcelock _forget_levels _forget_map _forget_objects _forget_traps _foundfile_buffer _fpostfx
+functions:92 _fprefx _fracture_rock _free_dungeons _free_rooms _free_ttlist _free_window_info _freediskspace _freedynamicdata
+functions:93 _freefruitchn _freehand _freeinv _friday_13th _fruitadd _fry_by_god _fully_identify_obj _g_at
+functions:94 _gainstr _gameDiskPrompt _gazemm _gazemu _gd_move _gd_sound _gem_accept
+functions:95 _display_warning _dlb_fgetc _doattributes _dochug _dochugw
+functions:96 _fill_point _fill_room _fill_zoo _fillholetyp _find_ac _find_branch _find_branch_room _find_defensive
+functions:96 _get_mon_location _get_mplname _get_obj_location _get_rect _get_rect_ind _get_room_loc _get_scr_size _get_shop_item
+functions:97 _get_uchars _get_unused_cs _get_valuables _get_wall_for_db _get_wet _get_wormno _getbones _getdir
+functions:98 _gethungry 
+functions:99 _gettty _getversionstring _getyear _ggetobj _ghitm _ghod_hitsu _ghost_from_bottle _ghostfruit
+functions:100 _givit _glibr _Gloves_off _Gloves_on _glyph_at _god_zaps_you _gods_angry _gods_upset
+functions:101 _godvoice _gold_detect _golemeffects _golemhp _goodfruit _goodpos _goto_hell _goto_level
+functions:102 _gr_finish _gr_init _graphics_opts _grddead _grease_protect _grow_up _growl _growl_sound
+functions:103 _guardname _gulpmm _gulpmu _gulpum _gush _hack_artifacts _has_dnstairs
+functions:104 _has_shrine _has_upstairs _hatch_egg _hates_silver _have_lizard _hcolor _heal_legs _healup
+functions:105 _Hear_again _Helmet_off _Helmet_on _help_menu _help_monster_out _hero_breaks _hidden_gold _HideCursor
+functions:106 _highc _histemple_at _hit _hitfloor _hitmm _hitmsg _hitmu _hitum
+functions:107 _hitval _hmon _hmon_hitmon _hmonas _hold_another_object _holetime _home _home_shk
+functions:108 _homebase _hooked_tty_getlin _hot_pursuit _hurtarmor _hurtle _identify _identify_pack _impact_drop
+functions:110 _in_trouble _In_V_tower _In_W_tower _in_your_sanctuary _incr_itimeout _induced_align _inherits _inhishop
+functions:111 _init_artifacts _init_attr _init_dungeons _init_fill _init_level _init_map _init_objects
+functions:112 _init_oracles _init_rect _init_rumors _init_ttycolor _init_uhunger _initedog _initoptions _initrack
+functions:113 _initworm _insert_branch _insert_timer _inside_room _inside_shop _instapetrify _intemple _interesting_to_discover
+functions:114 _intermed _intervene _intrinsic_possible _inv_cnt _inv_weight _invault _invdisp_nothing _inven_inuse
+functions:115 _invert_all _invert_all_on_page _Invocation_lev _invocation_message _invocation_pos _Is_botlevel _Is_branchlev _is_chargeable
+functions:116 _is_db_wall _is_drawbridge_wall _is_edible _is_fainted _is_flammable _is_fshk _is_home_elemental _is_ice
+;functions:117 
+functions:118 _is_worn _is_worn_by_type _isbig _isclearpath 
+functions:119 _itimeout_incr _its_dead _itsstuck _Japanese_item_name _join _join_map _jump _keepdogs
+functions:119 _sticks _still_chewing _stock_room _stolen_container _stolen_value _stone_luck _stoned_dialogue _stop_occupation
+functions:120 _kick_monster _kick_object _kickdmg _kickstr _kill_egg _kill_eggs _kill_genocided_monsters _killed
+functions:121 _kind_name _known_hitum _kops_gone _l_monnam _lantern_message _launch_obj _lava_effects 
+functions:122 _ldrname _leader_speaks _learn_egg_type _ledger_no _ledger_to_dlev _ledger_to_dnum
+functions:123 _left_side _lesshungry _let_to_name _letter _lev_by_name _level_difficulty _level_distance _level_range
+functions:124 _level_tele _level_tele_trap _levl_follower _lifesaved_monster _lift_object _light_cocktail _light_region _lined_up
+functions:125 _linedup _list_genocided _list_vanquished _litroom _litter _little_to_big _llord _lminion
+functions:126 _load_common_data _load_maze _load_one_engraving _load_one_monster _load_one_object _load_qtlist _load_rooms _load_special
+functions:127 _loadfruitchn _lock_action _lock_file _locomotion _lookaround _lookat _lookup_id_mapping _lose_weapon_skill
+functions:128 _losedogs _losehp _losespells _losestr _losexp _m_arrival
+functions:129 _m_carrying _m_detach _m_dowear _m_dowear_type _m_initgrp _m_initinv _m_initthrow _m_initweap
+functions:130 _m_lose_armor 
+functions:131 _m_useup _make_angry_shk _make_blinded _make_confused _make_corpse _make_engr_at _make_familiar _make_hallucinated
+functions:132 _make_happy_shk _make_lockname _make_niches _make_sick _make_stunned _make_vomiting _makecorridors _makedog
+functions:133 _makekops _makelevel _makemaz _makemon _makeniche _makeplural _makerogueghost _makeroguerooms
+functions:134 _makerooms
+functions:135 _map_menu_cmd _map_object _map_trap _match_optname _mattackm _mattacku _max_capacity _max_mon_load
+functions:136 _max_passive_dmg _max_rank_sz _maxledgerno _may_dig _may_passwall _maybe_write_ls _maybe_write_timer _mayberem
+functions:137 _maze0xy _maze1xy _mazexy _mb_trapped _mbag_explodes _mbhit _mbhitm _mcalcdistress
+functions:138 _md_rush _md_start _md_stop _mdig_tunnel
+functions:139 _meatobj _melt_ice _menu_drop _menu_identify _menu_loot _menu_remarm _mergable _merge_choice
+functions:140 _merged _mfndpos _midnight _migrate_to_level _mineralize _minit _miniwalk _minstapetrify
+functions:140 _On_stairs _on_start _On_W_tower_level _oname _onbill _online2 _only_here _onlyspace
+functions:141 _mintrap 
+functions:142 _mk_bubble _mk_knox_portal _mk_mplayer _mk_named_object _mk_roamer _mk_tt_object _mkaltar _mkbox_cnts
+functions:143 _mkcavearea _mkcavepos _mkclass _mkcorpstat _mkfount _mkgold _mkgoldobj _mkinvokearea
+functions:144 _mkinvpos _mklev _mkmap _mkobj _mkobj_at _mkportal _mkroll_launch _mkroom
+functions:145 _mkshobj_at _mkshop _mksink _mksobj _mksobj_at _mkstairs _mkswamp _mktemple
+functions:146 _mktrap _mkundead _mkzoo _mlevel_tele_trap _mlifesaver _mnearto _mnexto _mon_arrive
+functions:147 _mon_break_armor _mon_catchup_elapsed_time _mon_chain _mon_has_amulet _mon_has_arti _mon_has_special _mon_invent_chain _mon_is_local
+functions:148 _mon_nam _mon_nam_too _mon_owns _mon_reflects _mon_regen _mon_set_minvis _mon_to_stone _mon_wield_item
+functions:149 _mondead _mondied _mongets _mongone _monkilled _Monnam _monnear 
+functions:150 _monst_init _monster_detect _monster_nearby _monstinroom _monstone _monstr_init _more _more_experienced
+functions:151 _morehungry _morguemon _move_gold _move_into_trap _move_special
+functions:153 _mpickobj 
+functions:154 _mselftouch _msg_in _msleep _msmsg _mstatusline _msummon _mswings _mswingsm
+functions:155 _mtele_trap _mungspaces _munstone _mv_bubble _mvault_tele _mzapmsg _n_or_more _name_to_mon
+functions:156 _nameshk _nartifact_exist _nasty _ndemon _near_capacity _nemdead _nemesis_speaks _neminame
+functions:157 _nethack_exit _new_light_source _new_were _newcham _newexplevel _newgame _newhp _newmail
+functions:158 _newman _newuexp _newuhs _next_level _next_opt _next_shkp _next_to_u
+functions:159 _nexttodoor _nh_timeout _nhusage _night _nmcpy _no_bones_level _noattacks _nocmov
+functions:160 _nohandglow _noises _nomul _Norep _not_capable _not_fully_identified _number_leashed _o_in
+functions:161 _o_on _o_unleash _obfree _obj_chain _obj_delivery _obj_extract_self _obj_here _obj_ice_effects
+functions:162 _obj_is_burning _obj_is_local _obj_is_pname _obj_merge_light_sources _obj_move_light_source _obj_move_timers _obj_resists _obj_sanity_check
+functions:163 _obj_sheds_light _obj_shudders _obj_split_light_source _obj_split_timers _obj_stop_timers _obj_to_let _object_detect _objects_init
+functions:164 _observable_depth _obstructed _oc_to_str _occupied _off_msg _ohitmon _oinit _ok_to_quest
+functions:165 _okay
+functions:167 _onquest _onscary _open_bonesfile _open_drawbridge _open_levelfile _open_library _open_savefile _openit
+functions:168 _openone _OpenTileFile _opentin _option_help _oselect _other_mon_has_arti _otransit_msg
+functions:169 _out_container _outentry _outheader _outoracle _outrumor _p_coaligned _pacify_guards _pacify_shk
+functions:170 _panic _parent_dlevel _parent_dnum _parse _parse_config_line _parseoptions _pass_one _pass_three
+functions:171 _pass_two _passive _passivemm _passiveum _pay _pay_for_damage _paybill _paygd
+functions:172 _pckeys _peace_minded _peek_at_iced_corpse_age _peffects _pet_type _pgetchar _phase_of_the_moon
+functions:173 _pick_level _pick_lock _pick_obj _pick_room _picked_container _picking_at _picking_lock _picklock
+functions:174 _pickup _pickup_object _place_branch _place_level _place_lregion _place_niche _place_object _place_worm_tail_randomly
+functions:175 _place_wsegs _placebc _playwoRAMdisk _pleased _pline _pline_The _plnamesuffix _pluslvl
+functions:176 _pmatch _poisoned _poisontell _poly_gender _poly_obj _poly_when_stoned _polyman _polymon
+functions:177 _polyself _polyuse _port_help _pos_to_room _positionbar _possible_places _possibly_unwield _potionbreathe
+functions:178 _potionhit _prayer_done _precheck _prev_level _pri_move _price_quote _priest_talk _priestini
+functions:179 _priestname _print_branch _print_dungeon _print_queue _prinv _probe_monster _process_menu_window _process_text_window
+functions:180 _pronoun_gender _protects _prscore _punish _pushch _put_monsters_to_sleep _putsyms
+functions:181 _qt_montype _qt_pager _query_category _query_classes _query_objlist _quest_chat _quest_info
+functions:182 _quest_stat_check _quest_talk _random_dir _random_engraving _random_teleport_level _ranged_attk
+functions:183 _rank _rank_of _raw_printf _read_config_file _read_engr_at _readchar _readentry
+functions:184 _readmail _readobjnam _ReadPlanarTileFile _ReadPlanarTileFile_O _ReadTileFileHeader _reassign _recalc_wt _recharge
+functions:185 _record_exists _redist_attr _redotoplin _regularize _rehumanize _rejectoption _relink_light_sources _relink_timers
+functions:186 _relmon _remember_topl _remove_damage _remove_object _remove_rect _remove_timer _remove_worm
+functions:187 _removetopl _reorder_invent _repair_damage _replmon _replshk _rescham _reset_attribute_clock
+functions:188 _reset_eat _reset_faint _reset_hostility _reset_occupations _reset_pick _reset_remarm _reset_rndmonst _reset_trapset
+functions:189 _resetobjs _resist _resists_blnd _resists_drli _resists_magm _rest_engravings _rest_room _rest_rooms
+functions:190 _rest_worm _restartcham _restdamage _restfakecorr _restgamestate _restlevchn _restlevelfile _restlevelstate
+functions:191 _restmonchn _restnames _restobjchn _restore_artifacts _restore_attrib _restore_dungeon _restore_light_sources _restore_oracles
+functions:192 _restore_saved_game _restore_timers _restore_waterlevel _restpriest _restrap _restrict_name _restshk _resurrect
+functions:193 _reverse _revive _revive_corpse _revive_egg _revive_mon _revive_nasty _reward_untrap _rhack
+functions:194 _right_side _rile_shk _Ring_gone _Ring_off _Ring_off_or_gone _Ring_on _rloc _rloc_engr
+functions:195 _rloc_pos_ok _rloc_to _rloco _rm_waslit _rnd_class _rnd_defensive_item
+functions:196 _rnd_misc_item _rnd_offensive_item _rnd_rect _rndcurse _rnddoor _rndexp _rndghostname _rndmonnam
+functions:197 _rndmonnum _rndmonst _rndtrap _rne _rnl _rnz _rogue_vision _roguecorr
+functions:198 _roguejoin _roguename _rot_corpse _rot_organic _rottenfood _rounddiv _row_refresh _run_timers
+functions:199 _rust_dmg _s_suffix _safe_teleds _saleable _same_price _sanity_check _save_artifacts _save_currentstate
+functions:200 _save_dungeon _save_engravings _save_light_sources _save_oracles _save_room _save_rooms _save_savefile_name _save_timers
+functions:201 _save_waterlevel _save_worm _savebones _savech _savedamage _saveDiskPrompt _savefruitchn _savegamestate
+functions:202 _savelev _savelev0 _savelevchn _savelife _savemonchn _savenames _saveobjchn _savestateinlock
+functions:203 _savetrapchn _scatter _schedule_goto _score_wanted _search_door _search_special _searches_for_item _see_lamp_flicker
+functions:204 _see_monsters _see_objects _see_traps _see_wsegs _seemimic _seetrap _seffects _select_hwep
+functions:205 _select_off _select_rwep _selftouch _sellobj _sellobj_state _sengr_at _sense_trap
+functions:206 _set_all_on_page _set_apparxy _set_artifact_intrinsic _set_bc _set_bonesfile_name _set_bonestemp_name _set_corn _set_cost
+functions:207 _set_crosswall _set_entity _set_item_state _set_itimeout _set_levelfile_name _set_lit _set_lock_and_bones _set_malign
+functions:208 _set_mimic_blocking _set_mimic_sym _set_mon_data _set_moreluck _set_occupation _set_repo_loc _set_residency _set_savefile_name
+functions:209 _set_seenv _set_trap _set_twall _set_uasmon _set_wall _set_wall_property _set_wall_state _set_wear
+functions:210 _set_wounded_legs _set_wportal _setclipped _setftty _setgemprobs _setmangry _setnotworn _setpaid
+functions:211 _setrandom _settrack _settty _setup_waterlevel _setuwep _setworn _sgn _Shield_off
+functions:212 _shieldeff _ship_object _shk_chat _shk_embellish _shk_move _shk_names_obj _shk_owns _shk_your
+functions:213 _Shk_Your _shkcatch _shkgone _shkinit _shkname _sho_obj_return_to_u _shop_debt _shop_keeper
+functions:214 _shop_object _shopdig _shopper_financial_report _shrine_pos _shrink_worm _shuffle
+functions:215 _shuffle_all _shuffle_tiles _simple_look _singular _sitoa _skill_advance _skill_init _skill_level_name
+functions:216 _skinback _sleep_monst _slept_monst _slip_or_trip _sliparm _slots_required _snuff_candle _snuff_light_source
+functions:217 _snuff_lit _sobj_at _some_armor _somegold _somex _somexy _somey _sort_rooms
+functions:218 _sort_valuables _sp_lev_shuffle _spec_ability _spec_abon _spec_applies _spec_dbon _spell_damage_bonus _spell_hit_bonus
+functions:219 _spell_skilltype _spelleffects _spitmu _splatter_burning_oil _split_mon _split_rects _splitbill _splitobj
+functions:220 _spoteffects _squadmon _srandom _stackobj _standoutbeg _standoutend _start_corpse_timeout _start_eating
+functions:221 _start_engulf _start_timer _start_tin _steal _steal_it _stealamulet _stealarm _stealgold
+functions:223 _stop_timer _store_version _strange_feeling _strategy _string_for_env_opt _string_for_opt _strncmpi _strprepend
+functions:224 _strstri _study_book _stumble_onto_mimic _sub_one_frombill _subfrombill _substitute_tiles _summon_minion _surface
+functions:225 _swallow_to_glyph _swapin_file _swapout_oldest _switch_graphics _switchar _t_warn
+functions:226 _tabexpand _tactics _take_gold _take_off _tamedog _target_on _tele _tele_jump_ok
+functions:227 _tele_restrict _tele_trap _teleds _teleok _teleport_pet _temple_occupied _tended_shop _term_end_attr
+functions:228 _term_end_color
+functions:229 _The _this_type_only _thitm _thitmonst _thitu _throw_gold _throwing_weapon _throwit
+functions:230 _thrwmu _tileview _timed_occupation _timer_is_local _timer_sanity_check _tinnable _title_to_mon _tmp_at
+functions:231 _topl_putsym _topologize _topten _topten_print _topten_print_bold _toss_up _toss_wsegs _touch_artifact
+functions:232 _touchfood _trap_detect _trickery _try_disarm _try_lift _trycall _tt_oname _tty_add_menu
+functions:233 _tty_askname _tty_clear_nhwindow _tty_cliparound 
+functions:234 _tty_display_file _tty_display_nhwindow _tty_doprev_message _tty_end_menu _tty_end_screen _tty_exit_nhwindows _tty_get_ext_cmd _tty_get_nh_event
+functions:235 _tty_getlin _tty_init_nhwindows _tty_mark_synch _tty_message_menu _tty_nh_poskey _tty_nhbell _tty_nhgetch _tty_number_pad
+functions:236 _tty_player_selection _tty_raw_print _tty_raw_print_bold _tty_resume_nhwindows _tty_select_menu
+functions:237 _tty_start_menu _tty_start_screen _tty_startup _tty_suspend_nhwindows _tty_update_inventory _tty_yn_function
+functions:238 _txt_backsp _txt_cl_end _txt_cl_eos _txt_clear_screen _txt_get_scr_size _txt_monoadapt_check
+functions:239 _txt_nhbell _txt_startup _u_entered_shop _u_gname _u_init
+functions:240 _u_left_shop _u_on_dnstairs _u_on_newpos _u_on_sstairs _u_on_upstairs _u_slip_free _u_slow_down _u_teleport_mon
+functions:241 _u_to_e _u_wipe_engr _ugolemeffects _um_dist _unbless _unblock_point _uncommon _uncompress
+functions:242 _unconscious _uncurse _undead_to_corpse _under_ground _under_water _undiscover_object _unearth_objs _unfaint
+functions:243 _unleash_all _unload_qtlist _unlock_file _unmap_object _unmul _unpaid_cost _unplacebc _unpunish
+functions:244 _unrestrict_weapon_skill _unset_all_on_page _unsetup_waterlevel _unstuck _untrap _untrap_prob _unturn_dead _update_mon_intrinsics
+functions:245 _update_topl _uptodate _urustm _use_bell _use_camera _use_candelabrum _use_candle _use_container
+functions:246 _use_crystal_ball _use_defensive _use_figurine _use_grease _use_lamp _use_leash _use_magic_whistle _use_mirror
+functions:247 _use_misc _use_offensive _use_pick_axe _use_skill _use_stethoscope _use_tinning_kit _use_towel _use_trap
+functions:248 _use_unicorn_horn _use_whip _use_whistle _useup _useupall _useupf _ustatusline _uunstick
+functions:249 _uwepgone _vault_occupied _vault_tele _verbalize _vga_backsp _vga_cl_end _vga_cl_eos _vga_clear_screen
+functions:250 _vga_cliparound _vga_detect _vga_DisplayCell _vga_DisplayCell_O _vga_DrawCursor _vga_Finish _vga_FontPtrs _vga_get_scr_size
+functions:251 _vga_gotoloc _vga_HideCursor _vga_Init _vga_overview _vga_redrawmap _vga_refresh _vga_SetPalette _vga_SwitchMode
+functions:252 _vga_traditional _vga_tty_end_screen _vga_tty_startup _vga_update_positionbar _vga_userpan _vga_WriteChar _vga_WriteStr _vga_xputc
+functions:254 _vision_reset _dodiscovered _dodoor _dodown _dodrink _dodrop _doeat _doengrave
+functions:255 _wallification _wallify_map _wallify_vault _wantdoor  _watch_on_duty _water_damage _water_friction
+functions:256 _water_prayer _weapon_dam_bonus _weapon_hit_bonus _weapon_type _wearing_armor _weffects _weight
+functions:257 _weight_cap
+functions:258 _whimper _wield_tool _wildmiss _win_tty_init _wipe_engr_at _wipeoff _wipeout_text
+functions:259 _wiz_detect _wiz_genesis _wiz_identify _wiz_level_tele _wiz_light_sources _wiz_map _wiz_show_seenv _wiz_show_vision
+functions:260 _wiz_show_wmodes _wiz_timeout_queue _wiz_where _wiz_wish _wizdead _worm_known _worm_move _worm_nomove
+functions:261 _wormgone _wormhitu _worn_wield_only _write_ls _writeentry _wrong_elem_type _x_monnam _xcrypt _xkilled _xlev_to_rank _xname _xprname 
+functions:263 _xytod _yelp _yname _Yname2 _You _you_aggravate _You_cant _You_feel _you_have _You_hear _you_unwere _you_were _Your _zap_dig
+functions:265 _zap_hit _zap_over_floor _zap_updown _zapdir_to_glyph _zapnodir _zappable _zapyourself _zhitm _zhitu _put_lregion_here _role_init 
+; tuning
+; this was 23
+functions:266 _bp_to_obj
+; the next two were 238
+functions:268 _aggravate
+; the following were 118
+;functions:269 
+; the following were 261
+;functions:270  
+functions:271 _xputg 
+functions:272 _xputs _xwaitforspace
+; the following were 158
+functions:273 _enermod _enlightenment
+; the following was 214
+;functions:274 _enter_explore_mode
+; the following were 26
+functions:275 _bydoor 
+functions:276 _calc_capacity _call_kops _calm_nymphs
+functions:277 _can_advance _can_be_hatched 
+functions:278 _can_carry
+; the following were 239
+functions:279  _equipname
+functions:280 _txt_xputs
+; the following were 80
+functions:281 _enexto
+;functions:282 
+functions:283 _enhance_weapon_skill 
+; the following were 165
+functions:284 _okdoor
+functions:285 _omon_adj
+functions:286 _on_goal
+functions:287 _on_ground 
+functions:288 _b_trapped
+functions:289 _on_locate 
+functions:290 _on_msg
+; the following were 182
+functions:291 _y_monnam 
+; the following were 195
+;functions:293 
+; the following were 225
+functions:294 _erode_armor
+functions:295 _swallowed
+; the following were 7
+functions:298 _acurrstr
+; the following were 17
+functions:299 _attacktype
+functions:300 _attrcurse
+functions:301 _automiss
+functions:302 _autopick 
+; the following were 10
+functions:303 _adj_abon
+functions:304 _adj_lev
+functions:305 _adjabil 
+functions:306 _adjalign
+functions:307 _adjattrib 
+; was 53
+functions:308 _display_monster
+functions:309 _error
+; was 117
+;functions:310 
+functions:311 _is_ok_location
+;functions:312 
+functions:313 _is_pure
+functions:314 _is_quest_artifact 
+; was 236
+functions:316 _tty_putstr _tty_putsym 
+; was 81
+functions:318 _escapes
+functions:319 _erase_menu_or_text 
+functions:320 _eraseall
+; tuning 2
+; was 269
+functions:321 _weldmsg _were_change _were_summon 
+functions:322 _where_name _which_armor _which_arti
+functions:325 _term_end_raw_bold 
+functions:326 _term_start_attr
+;functions:327 
+functions:328 _term_start_raw_bold 
+functions:329 _terminate
+functions:330 _tgetch 
+functions:331 _the
+functions:332 _m_monnam 
+functions:333 _domagictrap _domindblast _domonability 
+functions:334 _m_respond
+functions:335 _m_slips_free 
+functions:336 _m_throw 
+functions:337 _m_to_e 
+functions:338 _m_unleash
+functions:339 _mpickstuff
+functions:340 _mplayer_talk 
+functions:341 _mpoisons_subj
+functions:342 _mquaffmsg
+functions:343 _miss
+functions:344 _mreadmsg
+functions:345 _mrustm
+functions:346 _vomit _vomiting_dialogue 
+functions:347 _wake_nearby 
+functions:348 _wake_nearto 
+functions:349 _wakeup 
+functions:350 _walkfrom 
+functions:351 _wall_angle
+functions:352 _able_to_loot _add_mon_to_reg _add_rect_to_reg _add_region _addinv_core1
+functions:352 _addinv_core2 _age_spells _align_gtitle _align_shift  _align_str _all_but_uchain 
+functions:353 _allow_all _allow_category  _already_wearing _already_wearing2 _angrygods
+functions:354 _animate_statue _antholemon _arti_speak _assign_warnings _attach_fig_transform_timeout _blocked_boulder
+functions:355 _book_substitution _burn_away_slime _can_blnd _can_ride _can_saddle _can_twoweapon
+functions:356 _carry_obj_effects _clear_regions _container_at _coyotename _create_gas_cloud _create_region
+functions:357 _describe_level _dfeature_at _dig_up_grave _discover_artifact _dismount_steed _disp_artifact_discoveries
+functions:359 _doconduct _dofire _doprinuse _doride _doswapweapon _dotwoweapon
+functions:360 _dowieldquiver _drain_item _exercise_steed _expire_gas_cloud _extcmd_via_menu _feature_alert_opts
+functions:361 _fig_transform _figurine_location_checks _final_level _find_trap _finish_quest _fix_petrification
+functions:362 _food_substitution _fqname _free_invbuf _free_region _free_youbuf _freeinv_core
+functions:363 _fuzzymatch _get_compopt_value _get_current_feature_ver _get_feature_notice_ver _get_mtraits _getlev 
+functions:364 _getlock _getobj  _getpos  _give_may_advance_msg _Goodbye _halu_gname
+functions:365 _Hello _hurtle_step _hurtmarmor _in_out_region _initialspell _inside_gas_cloud
+functions:366 _inside_rect _inside_region _kick_steed _look_here _m_in_out_region _make_grave
+functions:367 _mbodypart _mdamagem _mdamageu _minimal_enlightenment _mk_mplayer_armor _mm_aggression
+functions:368 _mon_adjust_speed _mon_animal_list _mon_beside _mon_in_region _montraits _mount_steed
+functions:369 _noit_mon_nam _noit_Monnam _noncoalignment _num_genocides _obj_attach_mid _obj_timer_checks
+functions:370 _obj_typename _ok_align _ok_gend _ok_race _ok_role _ordin
+functions:371 _pick_align _pick_animal _pick_gend _pick_nasty _pick_race _pick_role
+functions:372 _place_monster _pm_to_cham _prisoner_speaks _process_options _randalign _randgend
+functions:373 _randrace _randrole _realloc_obj _relobj _remove_mon_from_reg _remove_region
+functions:374 _remove_worn_item _replace_object _reset_oattached_mids _rest_regions _restore_cham _rnd_treefruit_at
+functions:375 _save_regions _select_newcham_form _self_invis_message _setuqwep _setuswapwep _show_conduct
+functions:376 _show_region _simple_typename _slime_dialogue _sokoban_detect _spec_m2 _special_handling
+functions:377 _str2align _str2gend _str2race _str2role _There _throw_obj
+functions:378 _tmiss _tty_update_positionbar _tty_wait_synch  _undiscovered_artifact _untwoweapon _update_mlstmv
+functions:379 _update_monster_region _update_player_regions _uqwepgone _ureflects _use_grapple _use_pole
+functions:380 _use_saddle _uswapwepgone _uwep_skill_type _validalign _validgend _validrace
+functions:381 _validrole _violated_vegetarian _walk_path _warning_opts _wary_dog _welcome
+functions:382 _write_timer _yyyymmdd _zap_steed
+functions:383 _getprice _getreturn _getrumor _gettrack
+functions:384 _ini_inv _knows_object _knows_class _restricted_spell_discipline _ready_weapon
+functions:385 _doname _Doname2
+functions:386 _minliquid 
+functions:387 _missmm 
+functions:388 _missmu 
+functions:389 _missum 
+functions:390 _mixtype _mk_artifact
+functions:391 _makesingular 
+functions:392 _maketrap _makevtele _makewish 
+
diff --git a/sys/msdos/setup.bat b/sys/msdos/setup.bat
new file mode 100644 (file)
index 0000000..62278c5
--- /dev/null
@@ -0,0 +1,167 @@
+@echo off\r
+REM    SCCS Id: @(#)setup.bat   2002/03/17\r
+REM    Copyright (c) NetHack PC Development Team 1990 - 2002\r
+REM    NetHack may be freely redistributed.  See license for details.\r
+\r
+echo.\r
+echo   Copyright (c) NetHack PC Development Team 1990 - 2002\r
+echo   NetHack may be freely redistributed.  See license for details.\r
+echo.\r
+REM setup batch file for msdos, see Install.dos for details.\r
+\r
+if not %1.==. goto ok_parm\r
+goto err_set\r
+\r
+:ok_parm\r
+echo Checking to see if directories are set up properly ...\r
+if not exist ..\..\include\hack.h  goto err_dir\r
+if not exist ..\..\src\hack.c      goto err_dir\r
+if not exist ..\..\dat\wizard.des  goto err_dir\r
+if not exist ..\..\util\makedefs.c goto err_dir\r
+if not exist ..\..\win\tty\wintty.c goto err_dir\r
+if not exist ..\share\lev_yacc.c   goto err_dir\r
+echo Directories OK.\r
+\r
+if not exist ..\..\binary\* mkdir ..\..\binary\r
+if NOT exist ..\..\binary\license copy ..\..\dat\license ..\..\binary\license >nul\r
+\r
+if exist ..\..\dat\data.bas goto long1ok\r
+if exist ..\..\dat\data.base goto long1a\r
+if exist ..\..\dat\data~1.bas goto long1b\r
+goto err_long\r
+:long1a\r
+echo Changing some long-named distribution file names:\r
+echo "Copying ..\..\dat\data.base -> ..\..\dat\data.bas"\r
+copy ..\..\dat\data.base ..\..\dat\data.bas\r
+if exist ..\..\dat\data.old del /Q ..\..\dat\data.old\r
+ren ..\..\dat\data.base data.old\r
+goto long1ok\r
+:long1b\r
+echo Changing some long-named distribution file names:\r
+echo "Copying ..\..\dat\data~1.bas -> ..\..\dat\data.bas"\r
+copy ..\..\dat\data~1.bas ..\..\dat\data.bas\r
+if exist ..\..\dat\data.old del /Q ..\..\dat\data.old\r
+ren ..\..\dat\data~1.bas data.old\r
+:long1ok\r
+\r
+if exist ..\..\include\patchlev.h goto long2ok\r
+if exist ..\..\include\patchlevel.h goto long2a\r
+if exist ..\..\include\patchl~1.h goto long2b\r
+goto err_long\r
+:long2a\r
+echo "Copying ..\..\include\patchlevel.h -> ..\..\include\patchlev.h"\r
+copy ..\..\include\patchlevel.h ..\..\include\patchlev.h\r
+if exist ..\..\include\patchlev.old del /Q ..\..\include\patchlev.old\r
+ren ..\..\include\patchlevel.h patchlev.old\r
+goto long2ok\r
+:long2b\r
+echo "Copying ..\..\include\patchl~1.h -> ..\..\include\patchlev.h"\r
+copy ..\..\include\patchl~1.h ..\..\include\patchlev.h\r
+if exist ..\..\include\patchlev.old del /Q ..\..\include\patchlev.old\r
+ren ..\..\include\patchl~1.h patchlev.old\r
+:long2ok\r
+\r
+REM Missing guidebook is not fatal to the build process\r
+if exist ..\..\doc\guideboo.txt goto long3ok\r
+if exist ..\..\doc\guidebook.txt goto long3a\r
+if exist ..\..\doc\guideb~1.txt goto long3b\r
+goto warn3long\r
+:long3a\r
+echo "Copying ..\..\doc\guidebook.txt -> ..\..\doc\guideboo.txt"\r
+copy ..\..\doc\guidebook.txt ..\..\doc\guideboo.txt\r
+if exist ..\..\doc\guideboo.old del /Q ..\..\doc\guideboo.old\r
+ren ..\..\doc\guidebook.txt guideboo.old\r
+goto long3ok\r
+:long3b\r
+echo "Copying ..\..\doc\guideb~1.txt -> ..\..\doc\guideboo.txt"\r
+copy ..\..\doc\guideb~1.txt ..\..\doc\guideboo.txt\r
+if exist ..\..\doc\guideboo.old del /Q ..\..\doc\guideboo.old\r
+ren ..\..\doc\guideb~1.txt guideboo.old\r
+goto long3ok\r
+:warn3long\r
+echo "Warning - There is no NetHack Guidebook (..\..\doc\guideboo.txt)"\r
+echo "          included in your distribution.  Build will proceed anyway."\r
+:long3ok\r
+\r
+if "%1"=="GCC"   goto ok_gcc\r
+if "%1"=="gcc"   goto ok_gcc\r
+if "%1"=="nmake" goto ok_msc\r
+if "%1"=="NMAKE" goto ok_msc\r
+if "%1"=="BC"   goto ok_bc\r
+if "%1"=="bc"   goto ok_bc\r
+if "%1"=="MSC"   goto ok_msc\r
+if "%1"=="msc"   goto ok_msc\r
+goto err_set\r
+\r
+:ok_gcc\r
+echo Symbolic links, msdos style\r
+echo "Makefile.GCC -> ..\..\src\makefile"\r
+copy makefile.GCC ..\..\src\makefile\r
+goto done\r
+\r
+:ok_msc\r
+echo Copying Makefile for Microsoft C and Microsoft NMAKE.\r
+echo "Makefile.MSC -> ..\..\src\makefile"\r
+copy Makefile.MSC ..\..\src\makefile\r
+echo Copying overlay schemas to ..\..\src\r
+copy schema*.MSC ..\..\src\schema*.DEF\r
+:ok_cl\r
+goto done\r
+\r
+:ok_bc\r
+echo Copying Makefile for Borland C and Borland's MAKE.\r
+echo "Makefile.BC -> ..\..\src\makefile"\r
+copy Makefile.BC ..\..\src\makefile\r
+echo Copying overlay schemas to ..\..\src\r
+copy schema*.BC ..\..\src\r
+goto done\r
+\r
+:err_long\r
+echo.\r
+echo ** ERROR - New file system with "long file name support" problem. **\r
+echo A couple of NetHack distribution files that are packaged with \r
+echo a long filename ( exceeds 8.3) appear to be missing from your \r
+echo distribution.\r
+echo The following files need to exist under the names on the\r
+echo right in order to build NetHack:\r
+echo.\r
+echo  ..\..\dat\data.base        needs to be copied to ..\..\dat\data.bas\r
+echo  ..\..\include\patchlevel.h needs to be copied to ..\..\include\patchlev.h\r
+echo.\r
+echo setup.bat was unable to perform the necessary changes because at least\r
+echo one of the files doesn't exist under its short name, and the \r
+echo original (long) file name to copy it from was not found either.\r
+echo.\r
+goto end\r
+\r
+:err_set\r
+echo.\r
+echo Usage:\r
+echo "%0 <GCC | MSC | BC >"\r
+echo.\r
+echo    Run this batch file specifying on of the following:\r
+echo            GCC, MSC, BC\r
+echo.\r
+echo    (depending on which compiler and/or make utility you are using).\r
+echo.\r
+echo    The GCC argument is for use with djgpp and the NDMAKE utility.\r
+echo.\r
+echo    The MSC argument is for use with Microsoft C and the NMAKE utility\r
+echo    that ships with it (MSC 7.0 or greater only, including Visual C).\r
+echo.\r
+echo    The BC argument is for use with Borland C and Borland's MAKE utility\r
+echo    that ships with it (Borland C++ 3.1 only).\r
+echo.\r
+goto end\r
+\r
+:err_dir\r
+echo/\r
+echo Your directories are not set up properly, please re-read the\r
+echo Install.dos and README documentation.\r
+goto end\r
+\r
+:done\r
+echo Setup Done!\r
+echo Please continue with next step from Install.dos.\r
+\r
+:end\r
diff --git a/sys/msdos/sound.c b/sys/msdos/sound.c
new file mode 100644 (file)
index 0000000..b283f59
--- /dev/null
@@ -0,0 +1,332 @@
+/*   SCCS Id: @(#)sound.c   3.4     1996/02/19                        */
+/*   Copyright (c) NetHack PC Development Team 1993,1995            */
+/*   NetHack may be freely redistributed.  See license for details. */
+/*                                                                  */
+/*
+ * sound.c - Hardware sound support
+ *
+ *Edit History:
+ *     Initial Creation                              93/10/01
+ *     Added PC Speaker Support for BC compilers     95/06/14
+ *     Completed various fixes                      96/02/19
+ *
+ */
+
+#include "hack.h"
+#include <stdio.h>
+#include "portio.h"
+
+#include <dos.h>
+#include <ctype.h>
+
+#ifndef TESTING
+
+#define printf pline
+
+int
+assign_soundcard(sopt)
+char *sopt;
+{
+
+       iflags.hassound = 0;
+#  ifdef PCMUSIC
+       iflags.usepcspeaker = 0;
+#  endif
+
+       if (strncmpi(sopt,"def",3) == 0) {              /* default */
+               /* do nothing - default */
+       }
+#  ifdef PCMUSIC
+       else if (strncmpi(sopt,"speaker",7) == 0) {     /* pc speaker */
+               iflags.usepcspeaker = 1;
+       }
+#  endif
+       else if (strncmpi(sopt,"auto",4) == 0) {        /* autodetect */
+       /*
+        * Auto-detect Priorities (arbitrary for now):
+        *      Just pcspeaker
+        */
+               if (0) ;
+#  ifdef PCMUSIC
+               else iflags.usepcspeaker = 1;
+#  endif
+       } else {
+               return 0;
+       }
+       return 1;
+
+}
+#endif
+
+#ifdef PCMUSIC
+
+/* 8254/3 Control Word Defines */
+
+#define CTR0SEL (0<<6)
+#define        CTR1SEL (1<<6)
+#define        CTR2SEL (2<<6)
+#define RDBACK (3<<6)
+
+#define LATCH  (0<<4)
+#define        RW_LSB  (1<<4)
+#define RW_MSB (2<<4)  /* If both LSB and MSB are read, LSB is done first */
+
+#define MODE0  (0<<1)  /* Interrupt on terminal count */
+#define MODE1  (1<<1)  /* Hardware One-Shot */
+#define MODE2  (2<<1)  /* Pulse Generator */
+#define MODE3  (3<<1)  /* Square Wave Generator */
+#define MODE4  (4<<1)  /* Software Triggered Strobe */
+#define MODE5  (5<<1)  /* Hardware Triggered Strobe */
+
+#define BINARY (0<<0)  /* Binary counter (16 bits) */
+#define BCD    (1<<0)  /* Binary Coded Decimal (BCD) Counter (4 Decades) */
+
+/* Misc 8254/3 Defines */
+
+#define TIMRFRQ (1193180UL)    /* Input frequency to the clock (Hz) */
+
+/* Speaker Defines */
+
+#define TIMER  (1<<0)  /* Timer 2 Output connected to Speaker */
+#define SPKR_ON        (1<<1)  /* Turn on/off Speaker */
+
+/* Port Definitions */
+
+/* 8254/3 Ports */
+
+#define CTR0   0x40
+#define CTR1   0x41
+#define CTR2   0x42
+#define CTRL   0x43
+
+/* Speaker Port */
+
+#define SPEAKER        0x61
+
+void
+startsound (unsigned freq)
+{
+       /* To start a sound on the PC:
+        *
+        * First, set the second counter to have the correct frequency:
+        */
+
+       unsigned count;
+
+       if (freq == 0) freq = 523;
+
+       count = TIMRFRQ / freq; /* Divide frequencies to get count. */
+
+#ifdef TESTING
+       printf ("freq = %u, count = %u\n", freq, count);
+#endif
+
+       outportb (CTRL, CTR2SEL|RW_LSB|RW_MSB|MODE3|BINARY);
+       outportb (CTR2, count & 0x0FF);
+       outportb (CTR2, count / 0x100);
+
+       /* Next, turn on the speaker */
+
+        outportb (SPEAKER, inportb(SPEAKER)|TIMER|SPKR_ON);
+}
+
+void
+stopsound (void)
+{
+        outportb (SPEAKER, inportb(SPEAKER) & ~(TIMER|SPKR_ON));
+}
+
+static unsigned tempo, length, octave, mtype;
+
+/* The important numbers here are 287700UL for the factors and 4050816000UL
+ * which gives the 440 Hz for the A below middle C. "middle C" is assumed to
+ * be the C at octave 3. The rest are computed by multiplication/division of
+ * 2^(1/12) which came out to 1.05946 on my calculator.  It is assumed that
+ * no one will request an octave beyond 6 or below 0.  (At octave 7, some
+ * notes still come out ok, but by the end of the octave, the "notes" that
+ * are produced are just ticks.
+
+ * These numbers were chosen by a process based on the C64 tables (which
+ * weren't standardized) and then were 'standardized' by giving them the
+ * closest value.  That's why they don't seem to be based on any sensible
+ * number.
+ */
+
+unsigned long notefactors[12] = { 483852, 456695, 431063, 406869, 384033,
+       362479, 342135, 322932, 304808, 287700, 271553, 256312 };
+
+void
+note (long notenum)
+{
+       startsound ((unsigned) (4050816000UL / notefactors[notenum % 12]
+                          >> (7 - notenum / 12)));
+}
+
+int notes[7] = { 9, 11, 0, 2, 4, 5, 7 };
+
+char *
+startnote (char *c)
+{
+       long n;
+
+       n = notes[toupper(*c++) - 'A'] + octave * 12;
+       if (*c == '#' || *c == '+') { n++; c++; }
+       else if (*c == '-') { if (n) n--; c++; }
+
+       note (n);
+
+       return --c;
+}
+
+void
+delaytime (unsigned time)
+{
+       /* time and twait are in units of milliseconds */
+
+       unsigned twait;
+
+       switch (toupper (mtype)) {
+          case 'S': twait = time / 4; break;
+          case 'L': twait = 0; break;
+          default: twait = time / 8; break;
+       }
+
+       msleep (time - twait);
+       stopsound ();
+       msleep (twait);
+}
+
+char *
+delaynote (char *c)
+{
+       unsigned time = 0;
+
+       while (isdigit(*c)) time = time * 10 + (*c++ - '0');
+
+       if (!time) time = length;
+
+       time = (unsigned)(240000 / time / tempo);
+
+       while (*c == '.') { time = time * 3 / 2; c++; }
+
+       delaytime (time);
+
+       return c;
+}
+
+void
+initspeaker (void)
+{
+       tempo = 120, length = 4, octave = 3, mtype = 'N';
+}
+
+
+void
+play (char *tune)
+{
+       char *c, *n;
+       unsigned num;
+
+       for (c = tune; *c; ) {
+           sscanf (c + 1, "%u", &num);
+           for (n = c + 1; isdigit(*n); n++) /* do nothing */;
+           if (isspace(*c)) c++;
+           else switch (toupper(*c)) {
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+                   c = startnote (c);
+               case 'P':
+                   c = delaynote (++c);
+                   break;
+#if 0
+               case 'M': c++; mtype = *c; c++; break;
+               case 'T':
+                   if (num) tempo = num;
+                   else printf ("Zero Tempo (%s)!\n", c);
+                   c = n;
+                   break;
+               case 'L':
+                   if (num) length = num;
+                   else printf ("Zero Length (%s)!\n", c);
+                   c = n;
+                   break;
+               case 'O':
+                   if (num <= 7)
+                       octave = num;
+                   c = n;
+                   break;
+               case 'N':
+                   note (num);
+                   delaytime ((240000/length/tempo));
+                   c = n;
+                   break;
+               case '>': if (octave < 7) octave++; c++; break;
+               case '<': if (octave) octave--; c++; break;
+#endif
+               case ' ': c++; break;
+               default:
+                   printf ("Unrecognized play value (%s)!\n", c);
+                    return;
+           }
+       }
+}
+
+#ifndef TESTING
+void
+pc_speaker (struct obj *instr, char *tune)
+{
+    if (!iflags.usepcspeaker) return;
+    initspeaker ();
+    switch (instr->otyp)
+    {
+       case WOODEN_FLUTE:
+       case MAGIC_FLUTE:
+           octave = 5; /* up one octave */
+           break;
+       case TOOLED_HORN:
+       case FROST_HORN:
+       case FIRE_HORN:
+           octave = 2; /* drop two octaves */
+           break;
+       case BUGLE:
+           break;
+       case WOODEN_HARP:
+       case MAGIC_HARP:
+           length = 8;
+           mtype = 'L'; /* fast, legato */
+           break;
+    }
+    play (tune);
+}
+
+#else
+
+main ()
+{
+       char s[80];
+       int tool;
+
+       initspeaker();
+       printf ("1) flute\n2) horn\n3) harp\n4) other\n");
+       fgets (s, 80, stdin);
+       sscanf (s, "%d", &tool);
+       switch (tool) {
+       case 1: octave = 5; break;
+       case 2: octave = 2; break;
+       case 3: length = 8; mtype = 'L'; break;
+       default: break;
+       }
+       printf ("Enter tune:");
+       fgets(s, 80, stdin);
+       play (s);
+}
+#endif
+
+#endif /* PCMUSIC */
+
+/* sound.c */
diff --git a/sys/msdos/tile2bin.c b/sys/msdos/tile2bin.c
new file mode 100644 (file)
index 0000000..ee4e894
--- /dev/null
@@ -0,0 +1,312 @@
+/*   SCCS Id: @(#)tile2bin.c   3.4     1995/01/26                     */
+/*   Copyright (c) NetHack PC Development Team 1993, 1994, 1995     */
+/*   NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Edit History:
+ *
+ *     Initial Creation                        M.Allison       93/10/21
+ *     ifndef MONITOR_HEAP for heaputil.c      P.Winner        94/03/12
+ *      added Borland C _stklen variable       Y.Sapir         94/05/01
+ *     fixed to use text tiles from win/share  M.Allison       95/01/31
+ *
+ */
+
+
+#include "hack.h"
+#include "pcvideo.h"
+#include "tile.h"
+#include "pctiles.h"
+
+#include <dos.h>
+#ifndef MONITOR_HEAP
+#include <stdlib.h>
+#endif
+#include <time.h>
+
+#ifdef __GO32__
+#include <unistd.h>
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 700
+#pragma warning(disable:4309)  /* initializing */
+#pragma warning(disable:4018)  /* signed/unsigned mismatch */
+#pragma warning(disable:4131)  /* old style declarator */
+#pragma warning(disable:4127)  /* conditional express. is constant */
+#endif
+
+#ifdef __BORLANDC__
+extern unsigned _stklen = STKSIZ;
+#endif
+
+extern char *FDECL(tilename, (int, int));
+
+#ifdef PLANAR_FILE
+char masktable[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
+char charcolors[MAXCOLORMAPSIZE];
+#ifdef OVERVIEW_FILE
+struct overview_planar_cell_struct planetile;
+#else
+struct planar_cell_struct planetile;
+#endif
+FILE *tibfile1;
+#endif
+
+#ifdef PACKED_FILE
+char packtile[TILE_Y][TILE_X];
+FILE *tibfile2;
+#endif
+
+int num_colors;
+pixel pixels[TILE_Y][TILE_X];
+struct tibhdr_struct tibheader;
+
+static void FDECL(write_tibtile, (int));
+static void FDECL(write_tibheader, (FILE *, struct tibhdr_struct *));
+static void FDECL(build_tibtile,  (pixel (*)[TILE_X]));
+
+#ifndef OVERVIEW_FILE
+char *tilefiles[] = {  "../win/share/monsters.txt",
+                       "../win/share/objects.txt",
+                       "../win/share/other.txt"};
+#else
+char *tilefiles[] = {  "../win/share/monthin.txt",
+                       "../win/share/objthin.txt",
+                       "../win/share/oththin.txt"};
+#endif
+
+int tilecount;
+int filenum;
+int paletteflag;
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       int i;
+       struct tm *newtime;
+       time_t aclock;
+       char *paletteptr;
+
+       if (argc != 1) {
+               Fprintf(stderr, "usage: tile2bin (from the util directory)\n");
+               exit(EXIT_FAILURE);
+       }
+
+#ifdef PLANAR_FILE
+# ifndef OVERVIEW_FILE
+       tibfile1 = fopen(NETHACK_PLANAR_TILEFILE, WRBMODE);
+# else
+       tibfile1 = fopen(NETHACK_OVERVIEW_TILEFILE, WRBMODE);
+# endif
+       if (tibfile1 == (FILE *)0) {
+               Fprintf(stderr, "Unable to open output file %s\n",
+# ifndef OVERVIEW_FILE
+                               NETHACK_PLANAR_TILEFILE);
+#else
+                               NETHACK_OVERVIEW_TILEFILE);
+#endif
+               exit(EXIT_FAILURE);
+       }
+#endif
+
+#ifdef PACKED_FILE
+       tibfile2 = fopen(NETHACK_PACKED_TILEFILE, WRBMODE);
+       if (tibfile2 == (FILE *)0) {
+               Fprintf(stderr, "Unable to open output file %s\n",
+                               NETHACK_PACKED_TILEFILE);
+               exit(EXIT_FAILURE);
+       }
+#endif
+       time(&aclock);
+       newtime = localtime(&aclock);
+
+       tilecount = 0;
+       paletteflag = 0;        
+       filenum = 0;
+       while (filenum < 3) {
+               if (!fopen_text_file(tilefiles[filenum], RDTMODE)) {
+                       Fprintf(stderr,
+                        "usage: tile2bin (from the util or src directory)\n");
+                       exit(EXIT_FAILURE);
+               }
+               num_colors = colorsinmap;
+               if (num_colors > 62) {
+                       Fprintf(stderr, "too many colors (%d)\n", num_colors);
+                       exit(EXIT_FAILURE);
+               }
+
+               if (!paletteflag) {
+                       paletteptr = tibheader.palette;
+                       for (i = 0; i < num_colors; i++) {
+                               *paletteptr++ = ColorMap[CM_RED][i],
+                               *paletteptr++ = ColorMap[CM_GREEN][i],
+                               *paletteptr++ = ColorMap[CM_BLUE][i];
+                       }
+                       paletteflag++;
+               }
+
+                               
+               while (read_text_tile(pixels)) {
+                       build_tibtile(pixels);
+                       write_tibtile(tilecount);
+                       tilecount++;
+               }
+
+               (void) fclose_text_file();
+               ++filenum;
+       }
+
+#  if defined(_MSC_VER)
+       tibheader.compiler = MSC_COMP;
+#  elif defined(__BORLANDC__)
+       tibheader.compiler = BC_COMP;
+#  elif defined(__GO32__)
+       tibheader.compiler = DJGPP_COMP;
+#  else
+       tibheader.compiler = OTHER_COMP;
+#  endif
+       
+       strncpy(tibheader.ident,
+               "NetHack 3.4 MSDOS Port binary tile file", 80);
+       strncpy(tibheader.timestamp, asctime(newtime), 24);
+       tibheader.timestamp[25] = '\0';
+       tibheader.tilecount = tilecount;
+       tibheader.numcolors = num_colors;
+# ifdef PLANAR_FILE
+       tibheader.tilestyle = PLANAR_STYLE;
+       write_tibheader(tibfile1, &tibheader);
+       (void) fclose(tibfile1);
+#  ifndef OVERVIEW_FILE
+       Fprintf(stderr, "Total of %d planar tiles written to %s.\n", 
+               tilecount, NETHACK_PLANAR_TILEFILE);
+#  else
+       Fprintf(stderr, "Total of %d planar tiles written to %s.\n", 
+               tilecount, NETHACK_OVERVIEW_TILEFILE);
+#  endif
+# endif
+
+# ifdef PACKED_FILE
+       tibheader.tilestyle = PACKED_STYLE;
+       write_tibheader(tibfile2, &tibheader);
+       Fprintf(stderr, "Total of %d packed tiles written to %s.\n", 
+               tilecount, NETHACK_PACKED_TILEFILE);
+       (void) fclose(tibfile2);
+# endif
+
+       exit(EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
+
+
+static void
+write_tibheader(fileptr,tibhdr)
+FILE *fileptr;
+struct tibhdr_struct *tibhdr;
+{
+
+       if (fseek(fileptr,0L,SEEK_SET)) {
+               Fprintf(stderr, "Error writing header to tile file\n");
+       }
+       fwrite(tibhdr, sizeof(struct tibhdr_struct), 1, fileptr);
+}
+
+static void
+build_tibtile(pixels)
+pixel (*pixels)[TILE_X];
+{
+       int i, j, k, co_off;
+       unsigned char co_mask,tmp;
+
+#ifndef OVERVIEW_FILE
+       memset((void *)&planetile,0,sizeof(struct planar_cell_struct));
+#else
+       memset((void *)&planetile,0,
+               sizeof(struct overview_planar_cell_struct));
+#endif
+       for (j = 0; j < TILE_Y; j++) {
+               for (i = 0; i < TILE_X; i++) {
+                       for (k = 0; k < num_colors; k++) {                              
+                               if (ColorMap[CM_RED][k] == pixels[j][i].r &&
+                                   ColorMap[CM_GREEN][k] == pixels[j][i].g &&
+                                   ColorMap[CM_BLUE][k] == pixels[j][i].b)
+                                       break;
+                       }
+                       if (k >= num_colors)
+                               Fprintf(stderr, "color not in colormap!\n");
+#ifdef PACKED_FILE
+                       packtile[j][i] = k;
+#endif
+
+#ifdef PLANAR_FILE
+                       if (i > 7) {
+                               co_off = 1;
+                               co_mask = masktable[i - 8];
+                       } else {
+                               co_off = 0;
+                               co_mask = masktable[i];
+                       }
+
+                       tmp  = planetile.plane[0].image[j][co_off];
+                       planetile.plane[0].image[j][co_off] = (k & 0x0008) ?
+                               (tmp | co_mask) :
+                               (tmp & ~co_mask);
+
+                       tmp  = planetile.plane[1].image[j][co_off];
+                       planetile.plane[1].image[j][co_off] = (k & 0x0004) ?
+                               (tmp | co_mask) :
+                               (tmp & ~co_mask);
+
+                       tmp  = planetile.plane[2].image[j][co_off];
+                       planetile.plane[2].image[j][co_off] = (k & 0x0002) ?
+                               (tmp | co_mask) :
+                               (tmp & ~co_mask);
+
+                       tmp  = planetile.plane[3].image[j][co_off];
+                       planetile.plane[3].image[j][co_off] = (k & 0x0001) ?
+                               (tmp | co_mask) :
+                               (tmp & ~co_mask);
+#endif /* PLANAR_FILE */
+               }
+       }
+}
+
+static void
+write_tibtile(recnum)
+int recnum;
+{
+       long fpos;
+
+#ifdef PLANAR_FILE
+# ifndef OVERVIEW_FILE
+       fpos = ((long)(recnum) * (long)sizeof(struct planar_cell_struct)) +
+               (long)TIBHEADER_SIZE;
+# else
+       fpos = ((long)(recnum) * 
+                       (long)sizeof(struct overview_planar_cell_struct)) +
+                       (long)TIBHEADER_SIZE;
+# endif
+       if (fseek(tibfile1,fpos,SEEK_SET)) {
+               Fprintf(stderr, "Error seeking before planar tile write %d\n",
+                       recnum);
+       }
+# ifndef OVERVIEW_FILE
+       fwrite(&planetile, sizeof(struct planar_cell_struct), 1, tibfile1);
+# else
+       fwrite(&planetile,
+               sizeof(struct overview_planar_cell_struct), 1, tibfile1);
+# endif
+#endif
+
+#ifdef PACKED_FILE
+       fpos = ((long)(recnum) * (long)sizeof(packtile)) +
+               (long)TIBHEADER_SIZE;
+       if (fseek(tibfile2,fpos,SEEK_SET)) {
+               Fprintf(stderr, "Error seeking before packed tile write %d\n",
+                       recnum);
+       }
+       fwrite(&packtile, sizeof(packtile), 1, tibfile2);
+#endif
+}
diff --git a/sys/msdos/video.c b/sys/msdos/video.c
new file mode 100644 (file)
index 0000000..48460bb
--- /dev/null
@@ -0,0 +1,969 @@
+/*   SCCS Id: @(#)video.c   3.4     2001/04/07                     */
+/*   Copyright (c) NetHack PC Development Team 1993, 1994, 2001            */
+/*   NetHack may be freely redistributed.  See license for details. */
+/*                                                                 */
+/*
+ * video.c - Hardware video support front-ends
+ *
+ *Edit History:
+ *     Initial Creation             M. Allison      1993/04/04
+ *     Add djgpp support            K. Smolkowski   1993/04/26
+ *     Add txt/graphics mode support M. Allison      1993/10/30
+ *     Add graphics mode cursor sim. M. Allison      1994/02/19
+ *     Add hooks for decals on vga   M. Allison      2001/04/07
+ */
+
+#include "hack.h"
+
+#ifndef STUBVIDEO
+#include "pcvideo.h"
+#include "pctiles.h"
+
+#if defined(_MSC_VER)
+# if _MSC_VER >= 700
+#pragma warning(disable:4018)  /* signed/unsigned mismatch */
+#pragma warning(disable:4127)  /* conditional expression is constant */
+#pragma warning(disable:4131)  /* old style declarator */
+#pragma warning(disable:4305)  /* prevents complaints with MK_FP */
+#pragma warning(disable:4309)  /* initializing */
+#pragma warning(disable:4759)  /* prevents complaints with MK_FP */
+# endif
+#endif
+/*=========================================================================
+ * General PC Video routines.
+ *
+ * The following routines are the video interfacing functions.
+ * In general these make calls to more hardware specific
+ * routines in other source files.
+ *
+ * Assumptions (94/04/23):
+ *
+ *   - Supported defaults.nh file video options:
+ *
+ *          If OPTIONS=video:autodetect is defined in defaults.nh then 
+ *          check for a VGA video adapter.  If one is detected, then 
+ *          use the VGA code, otherwise resort to using the 'standard' 
+ *          video BIOS routines.
+ *
+ *          If OPTIONS=video:vga is defined in defaults.nh, then use 
+ *          the VGA code.
+ *
+ *          If OPTIONS=video:default is defined in defaults.nh use the
+ *          'standard' video BIOS routines (in the overlaid version), 
+ *          or DJGPPFAST routines (under djgpp). This is equivalent to 
+ *          having no OPTIONS=video:xxxx entry at all.
+ *
+ * Notes (94/04/23):
+ *
+ *   - The handler for defaults.nh file entry: 
+ * 
+ *           OPTIONS=video:xxxxx 
+ *
+ *     has now been added.  The handler is in video.c and is called 
+ *     from options.c.
+ *
+ *   - Handling of videocolors and videoshades are now done with 
+ *     OPTIONS= statements.  The new syntax separates the colour
+ *     values with dashes ('-') rather than spaces (' ').
+ *
+ * To Do (94/04/23):
+ *
+ *
+ *=========================================================================
+ */
+
+
+#ifdef OVLB
+void
+get_scr_size()
+{
+#  ifdef SCREEN_VGA
+       if (iflags.usevga) {
+               vga_get_scr_size();
+       } else
+#  endif
+               txt_get_scr_size();
+}
+#endif /*OVLB*/
+
+/*
+ * --------------------------------------------------------------
+ * The rest of this file is only compiled if NO_TERMS is defined.
+ * --------------------------------------------------------------
+ */
+
+#ifdef NO_TERMS
+
+#include <ctype.h>
+#include "wintty.h"
+
+# ifdef __GO32__
+#include <pc.h>
+#include <unistd.h>
+#if !(__DJGPP__ >= 2)
+typedef long clock_t;
+#endif
+# endif
+
+# ifdef __BORLANDC__
+#include <dos.h>               /* needed for delay() */
+# endif
+
+# ifdef SCREEN_DJGPPFAST       /* parts of this block may be unecessary now */
+#define get_cursor(x,y) ScreenGetCursor(y,x)
+# endif
+
+# ifdef SCREEN_BIOS
+void FDECL(get_cursor, (int *, int *));
+# endif
+
+void FDECL(adjust_cursor_flags, (struct WinDesc *));
+void FDECL(cmov, (int, int));
+void FDECL(nocmov, (int, int));
+STATIC_DCL void NDECL(init_ttycolor);
+
+# ifdef OVLB
+int savevmode;           /* store the original video mode in here */
+int curcol,currow;       /* graphics mode current cursor locations */
+int g_attribute;         /* Current attribute to use */
+int monoflag;            /* 0 = not monochrome, else monochrome */
+int attrib_text_normal;   /* text mode normal attribute */
+int attrib_gr_normal;    /* graphics mode normal attribute */
+int attrib_text_intense;  /* text mode intense attribute */
+int attrib_gr_intense;   /* graphics mode intense attribute */
+boolean traditional = FALSE; /* traditonal TTY character mode */
+boolean inmap = FALSE;   /* in the map window */
+#  ifdef TEXTCOLOR
+char ttycolors[CLR_MAX];       /* also used/set in options.c */
+#  endif /* TEXTCOLOR */
+# else
+extern int savevmode;
+extern int curcol,currow;
+extern int g_attribute;
+extern int monoflag;
+extern int attrib_text_normal;
+extern int attrib_gr_normal;
+extern int attrib_text_intense;
+extern int attrib_gr_intense;
+extern boolean traditonal;
+extern boolean inmap;
+#  ifdef TEXTCOLOR
+extern char ttycolors[CLR_MAX];        /* also used/set in options.c */
+#  endif /* TEXTCOLOR */
+# endif /* OVLB */
+
+# ifdef OVLB
+void
+backsp()
+{
+       if (!iflags.grmode) {
+               txt_backsp();
+#  ifdef SCREEN_VGA
+       } else if (iflags.usevga) {
+               vga_backsp();
+#  endif
+       }
+}
+# endif /* OVLB */
+
+# ifdef OVL0
+void
+clear_screen()
+{
+       if (!iflags.grmode) {
+               txt_clear_screen();
+#  ifdef SCREEN_VGA
+       } else if (iflags.usevga) {
+               vga_clear_screen(BACKGROUND_VGA_COLOR);
+#  endif
+       }
+}
+
+void
+cl_end()       /* clear to end of line */
+{
+       int col,row;
+
+       col = (int)ttyDisplay->curx;
+       row = (int)ttyDisplay->cury;
+       if (!iflags.grmode) {
+               txt_cl_end(col,row);
+#  ifdef SCREEN_VGA
+       } else if (iflags.usevga) {
+               vga_cl_end(col,row);
+#  endif
+       }
+       tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1,
+                                               (int)ttyDisplay->cury);
+}
+
+void
+cl_eos()       /* clear to end of screen */
+{
+       int cy = (int)ttyDisplay->cury+1;
+
+       if (!iflags.grmode) {
+               txt_cl_eos();
+#  ifdef SCREEN_VGA
+       } else if (iflags.usevga) {
+               vga_cl_eos(cy);
+#  endif
+       }
+       tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1,
+                                               (int)ttyDisplay->cury);
+}
+
+void
+cmov(col, row)
+register int col, row;
+{
+       ttyDisplay->cury = (uchar)row;
+       ttyDisplay->curx = (uchar)col;
+       if (!iflags.grmode) {
+               txt_gotoxy(col,row);
+#  ifdef SCREEN_VGA
+       } else if (iflags.usevga) {
+               vga_gotoloc(col,row);
+#  endif
+       }
+}
+# endif /* OVL0 */
+
+# ifdef OVLB
+int
+has_color(int color)
+{
+       ++color;                /* prevents compiler warning (unref. param) */
+#  ifdef TEXTCOLOR
+       return  (monoflag) ? 0 : 1;
+#  else
+       return 0;
+#  endif
+}
+# endif /* OVLB */
+
+# ifdef OVL0
+void
+home()
+{
+       tty_curs(BASE_WINDOW, 1, 0);
+       ttyDisplay->curx = ttyDisplay->cury = (uchar)0;
+       if (!iflags.grmode) {
+               txt_gotoxy(0,0);
+#  ifdef SCREEN_VGA
+       } else if (iflags.usevga) {
+               vga_gotoloc(0,0);
+#  endif
+       }
+}
+
+void
+nocmov(col, row)
+int col,row;
+{
+       if (!iflags.grmode) {
+               txt_gotoxy(col,row);
+#  ifdef SCREEN_VGA
+       } else if (iflags.usevga) {
+               vga_gotoloc(col,row);
+#  endif
+       }
+}
+
+void
+standoutbeg()
+{
+       g_attribute = iflags.grmode ? attrib_gr_intense
+                                  : attrib_text_intense;
+}
+
+void
+standoutend()
+{
+       g_attribute = iflags.grmode ? attrib_gr_normal
+                                  : attrib_text_normal;
+}
+# endif /* OVL0 */
+
+
+# ifdef OVLB
+void
+term_end_attr(int attr)
+{
+       switch(attr) {
+               case ATR_ULINE:
+               case ATR_BOLD:
+               case ATR_BLINK:
+               case ATR_INVERSE:
+               default:
+               g_attribute = iflags.grmode ? attrib_gr_normal
+                                          : attrib_text_normal;
+       }
+}
+
+void
+term_end_color(void)
+{
+       g_attribute = iflags.grmode ? attrib_gr_normal
+                                  : attrib_text_normal;
+}
+
+void
+term_end_raw_bold(void)
+{
+    standoutend();
+}
+
+
+void
+term_start_attr(int attr)
+{
+    switch(attr){
+
+       case ATR_ULINE:
+               if (monoflag) {
+                       g_attribute = ATTRIB_MONO_UNDERLINE;
+               } else {
+                       g_attribute = iflags.grmode ? attrib_gr_intense
+                                                  : attrib_text_intense;
+               }
+               break;
+       case ATR_BOLD:
+               g_attribute = iflags.grmode ? attrib_gr_intense
+                                          : attrib_text_intense;
+               break;
+       case ATR_BLINK:
+               if (monoflag) {
+                       g_attribute = ATTRIB_MONO_BLINK;
+               } else {
+                       g_attribute = iflags.grmode ? attrib_gr_intense
+                                                  : attrib_text_intense;
+               }
+               break;
+       case ATR_INVERSE:
+               if (monoflag) {
+                       g_attribute = ATTRIB_MONO_REVERSE;
+               } else {
+                       g_attribute = iflags.grmode ? attrib_gr_intense
+                                                  : attrib_text_intense;
+               }
+               break;
+       default:
+               g_attribute = iflags.grmode ? attrib_gr_normal
+                                          : attrib_text_normal;
+               break;
+    }
+}
+
+
+void
+term_start_color(int color)
+{
+#  ifdef TEXTCOLOR
+       if (monoflag) {
+                       g_attribute = attrib_text_normal;
+       } else {
+               if (color >= 0 && color < CLR_MAX) {
+                       if (iflags.grmode)
+                               g_attribute = color;
+                       else
+                               g_attribute = ttycolors[color];
+               }
+       }
+#  endif
+}
+
+void
+term_start_raw_bold(void)
+{
+    standoutbeg();
+}
+# endif /* OVLB */
+
+# ifdef OVL0
+void
+tty_delay_output()
+{
+#ifdef TIMED_DELAY
+       if (flags.nap) {
+           (void) fflush(stdout);
+           msleep(50);         /* sleep for 50 milliseconds */
+           return;
+       }
+#endif
+}
+
+# endif /* OVL0 */
+
+# ifdef OVLB
+void
+tty_end_screen()
+{
+
+       if (!iflags.grmode) {
+               txt_clear_screen();
+#  ifdef PC9800
+               fputs("\033[>1l", stdout);
+#  endif
+#  ifdef SCREEN_VGA
+       } else if (iflags.usevga) {
+               vga_tty_end_screen();
+#  endif
+       }
+}
+
+void
+tty_nhbell()
+{
+       txt_nhbell();
+}
+
+
+void
+tty_number_pad(state)
+int state;
+{
+       ++state;                /* prevents compiler warning (unref. param) */
+}
+
+void
+tty_startup(wid, hgt)
+int *wid, *hgt;
+{
+
+       /* code to sense display adapter is required here - MJA */
+
+       attrib_text_normal  = ATTRIB_NORMAL;
+       attrib_text_intense = ATTRIB_INTENSE;
+
+       /* These are defaults and may get overridden */
+       attrib_gr_normal    = attrib_text_normal;
+       attrib_gr_intense   = attrib_text_intense;
+       g_attribute = attrib_text_normal;       /* Give it a starting value */
+
+#  ifdef SCREEN_VGA
+       if (iflags.usevga) {
+               vga_tty_startup(wid, hgt);
+       } else
+#  endif
+       txt_startup(wid, hgt);
+
+       *wid = CO;
+       *hgt = LI;
+
+#  ifdef CLIPPING
+       if (CO < COLNO || LI < ROWNO+3) setclipped();
+#  endif
+
+#  ifdef TEXTCOLOR
+       init_ttycolor();
+#  endif
+
+#  ifdef MONO_CHECK
+       monoflag = txt_monoadapt_check();
+#  else
+       monoflag = 0;
+#  endif
+
+}
+
+void
+tty_start_screen()
+{
+#  ifdef PC9800
+       fputs("\033[>1h", stdout);
+#  endif
+       if (iflags.num_pad) tty_number_pad(1);  /* make keypad send digits */
+}
+
+void
+gr_init(){
+       if (iflags.usevga)      {
+# ifdef SCREEN_VGA
+               vga_Init();
+# endif
+# ifdef SCREEN_VESA
+       } else if (iflags.usevesa) {
+               vesa_Init();
+
+# endif
+# ifdef SCREEN_8514
+       } else if (iflags.use8514) {
+               v8514_Init();
+# endif
+       }
+}
+
+void
+gr_finish()
+{
+       if (iflags.grmode) {
+          if (iflags.usevga) {
+# ifdef SCREEN_VGA
+               vga_Finish();
+# endif
+# ifdef SCREEN_VESA
+          } else if (iflags.usevesa) {
+               vesa_Finish();
+# endif
+# ifdef SCREEN_8514
+          } else if (iflags.use8514) {
+               v8514_Finish();
+# endif
+          }
+       }
+}
+
+# endif /* OVLB */
+
+/*
+ * Screen output routines (these are heavily used).
+ *
+ * These are the 3 routines used to place information on the screen
+ * in the NO_TERMS PC tty port of NetHack.  These are the routines
+ * that get called by routines in other NetHack source files (such
+ * as those in win/tty).
+ *
+ * xputs - Writes a c null terminated string at the current location.
+ *        Depending on compile options, this could just be a series
+ *        of repeated calls to xputc() for each character.
+ *
+ * xputc - Writes a single character at the current location. Since
+ *        various places in the code assume that control characters
+ *        can be used to control, we are forced to interpret some of
+ *        the more common ones, in order to keep things looking correct.
+ *
+ * xputg - If using a graphics mode display mechanism (such as VGA, this
+ *        routine is used to display a graphical representation of a
+ *        NetHack glyph at the current location.  For more information on
+ *        NetHack glyphs refer to the comments in include/display.h.
+ *
+ * NOTES:
+ *        wintty.h uses macros to redefine common output functions
+ *        such as puts, putc, putchar, so that they get steered into
+ *        either xputs (for strings) or xputc (for single characters).
+ *        References to puts, putc, and putchar in other source files
+ *        (that include wintty.h) are actually using these routines.
+ */
+
+# ifdef OVL0
+void
+xputs(s)
+const char *s;
+{
+       int col,row;
+
+       col = (int)ttyDisplay->curx;
+       row = (int)ttyDisplay->cury;
+
+       if (!iflags.grmode) {
+               txt_xputs(s,col,row);
+#  ifdef SCREEN_VGA
+       } else if (iflags.usevga) {
+               vga_xputs(s,col,row);
+#  endif
+       }
+}
+
+void
+xputc(ch)      /* write out character (and attribute) */
+char ch;
+{
+       int i;
+       char attribute;
+
+       i = iflags.grmode ? attrib_gr_normal
+                        : attrib_text_normal;
+
+       attribute = (char)((g_attribute == 0) ? i : g_attribute);
+       if (!iflags.grmode) {
+               txt_xputc(ch,attribute);
+#  ifdef SCREEN_VGA
+       } else if (iflags.usevga) {
+               vga_xputc(ch,attribute);
+#  endif /*SCREEN_VGA*/
+       }
+}
+
+void
+xputg(glyphnum,ch,special)     /* write out a glyph picture at current location */
+int glyphnum;
+int ch;
+unsigned special;
+{
+       if (!iflags.grmode || !iflags.tile_view) {
+               xputc((char)ch);
+#  ifdef SCREEN_VGA
+       } else {
+               vga_xputg(glyphnum, ch, special);
+#  endif
+       }
+}
+
+#  ifdef POSITIONBAR
+void
+video_update_positionbar(posbar)
+char *posbar;
+{
+       if (!iflags.grmode) 
+               return;
+#   ifdef SCREEN_VGA
+       else
+               vga_update_positionbar(posbar);
+#   endif
+}
+#  endif
+
+void
+adjust_cursor_flags(cw)
+struct WinDesc *cw;
+{
+#  ifdef SIMULATE_CURSOR
+#   if 0
+    if (cw->type == NHW_MAP) cursor_flag = 1;
+    else cursor_flag = 0;
+#   else
+    if (cw->type == NHW_MAP) {
+       inmap = 1;
+       cursor_flag = 1;
+    } else {
+       inmap = 0;
+       cursor_flag = 1;
+    }
+#   endif /* 0 */
+#  endif /* SIMULATE_CURSOR */
+}
+
+#  ifdef SIMULATE_CURSOR
+
+/* change the defaults in pcvideo.h, not here */
+int cursor_type  = CURSOR_DEFAULT_STYLE;       
+int cursor_color = CURSOR_DEFAULT_COLOR;
+int cursor_flag;
+
+/* The check for iflags.grmode is made BEFORE calling these. */
+void
+DrawCursor()
+{
+#  ifdef SCREEN_VGA
+       vga_DrawCursor();
+#  endif
+}
+
+void
+HideCursor()
+{
+#  ifdef SCREEN_VGA
+       vga_HideCursor();
+#  endif
+}
+
+#  endif /* SIMULATE_CURSOR */
+# endif /* OVL0 */
+
+# ifdef TEXTCOLOR
+/*
+ * CLR_BLACK           0
+ * CLR_RED             1
+ * CLR_GREEN           2
+ * CLR_BROWN           3       low-intensity yellow
+ * CLR_BLUE            4
+ * CLR_MAGENTA         5
+ * CLR_CYAN            6
+ * CLR_GRAY            7       low-intensity white
+ * NO_COLOR            8
+ * CLR_ORANGE          9
+ * CLR_BRIGHT_GREEN    10
+ * CLR_YELLOW          11
+ * CLR_BRIGHT_BLUE     12
+ * CLR_BRIGHT_MAGENTA  13
+ * CLR_BRIGHT_CYAN     14
+ * CLR_WHITE           15
+ * CLR_MAX             16
+ * BRIGHT              8
+ */
+
+#  ifdef VIDEOSHADES
+/* assign_videoshades() is prototyped in extern.h */
+/* assign_videocolors() is prototyped in extern.h */
+/* assign_video()      is prototyped in extern.h */
+
+#   ifdef OVLB
+int shadeflag;                                 /* shades are initialized */
+int colorflag;                                 /* colors are initialized */
+char *schoice[3] = {"dark","normal","light"};
+char *shade[3];
+#   else
+extern int shadeflag;
+extern int colorflag;
+extern char *schoice[3];
+extern char *shade[3];
+#   endif /* OVLB */
+
+#  endif /* VIDEOSHADES */
+
+#  ifdef OVLB
+STATIC_OVL void
+init_ttycolor()
+{
+#   ifdef VIDEOSHADES
+       if (!shadeflag) {
+               ttycolors[CLR_BLACK] = M_BLACK; /*  8 = dark gray */
+               ttycolors[CLR_WHITE] = M_WHITE; /* 15 = bright white */
+               ttycolors[CLR_GRAY]  = M_GRAY;  /*  7 = normal white */
+               shade[0] = schoice[0];
+               shade[1] = schoice[1];
+               shade[2] = schoice[2];
+       }
+#   else
+       ttycolors[CLR_BLACK] = M_GRAY;          /*  mapped to white */
+       ttycolors[CLR_WHITE] = M_GRAY;          /*  mapped to white */
+       ttycolors[CLR_GRAY]  = M_GRAY;          /*  mapped to white */
+#   endif
+
+#   ifdef VIDEOSHADES
+       if (!colorflag) {
+#   endif
+               ttycolors[CLR_RED]            = M_RED;
+               ttycolors[CLR_GREEN]          = M_GREEN;
+               ttycolors[CLR_BROWN]          = M_BROWN;
+               ttycolors[CLR_BLUE]           = M_BLUE;
+               ttycolors[CLR_MAGENTA]        = M_MAGENTA;
+               ttycolors[CLR_CYAN]           = M_CYAN;
+               ttycolors[BRIGHT]             = M_WHITE;
+               ttycolors[CLR_ORANGE]         = M_ORANGE;
+               ttycolors[CLR_BRIGHT_GREEN]   = M_BRIGHTGREEN;
+               ttycolors[CLR_YELLOW]         = M_YELLOW;
+               ttycolors[CLR_BRIGHT_BLUE]    = M_BRIGHTBLUE;
+               ttycolors[CLR_BRIGHT_MAGENTA] = M_BRIGHTMAGENTA;
+               ttycolors[CLR_BRIGHT_CYAN]    = M_BRIGHTCYAN;
+#   ifdef VIDEOSHADES
+       }
+#   endif
+}
+#  endif /* OVLB */
+
+#  ifdef OVL1
+       static int FDECL(convert_uchars,(char *, uchar *, int));
+#   ifdef VIDEOSHADES
+int assign_videoshades(char *choiceptr)
+{
+       char choices[120];
+       char *cptr, *cvalue[3];
+       int i,icolor = CLR_WHITE;
+
+       strcpy(choices,choiceptr);
+       cvalue[0] = choices;
+
+       /* find the next ' ' or tab */
+       cptr = index(cvalue[0], '-');
+       if (!cptr) cptr = index(cvalue[0], ' ');
+       if (!cptr) cptr = index(cvalue[0], '\t');
+       if (!cptr) return 0;
+       *cptr = '\0';
+       /* skip  whitespace between '=' and value */
+       do { ++cptr; } while (isspace(*cptr) || (*cptr == '-'));
+       cvalue[1] = cptr;
+
+       cptr = index(cvalue[1], '-');
+       if (!cptr) cptr = index(cvalue[0], ' ');
+       if (!cptr) cptr = index(cvalue[0], '\t');
+       if (!cptr) return 0;
+       *cptr = '\0';
+       do { ++cptr; } while (isspace(*cptr) || (*cptr == '-'));
+       cvalue[2] = cptr;
+
+       for (i=0; i < 3; ++i) {
+               switch(i) {
+                       case 0: icolor = CLR_BLACK;
+                               break;
+                       case 1: icolor = CLR_GRAY;
+                               break;
+                       case 2: icolor = CLR_WHITE;
+                               break;
+               }
+
+               shadeflag = 1;
+               if ((strncmpi(cvalue[i],"black",5) == 0) ||
+                   (strncmpi(cvalue[i],"dark",4) == 0)) {
+                       shade[i] = schoice[0];
+                       ttycolors[icolor] = M_BLACK;    /* dark gray */
+               } else if ((strncmpi(cvalue[i],"gray",4) == 0) ||
+                          (strncmpi(cvalue[i],"grey",4) == 0) ||
+                          (strncmpi(cvalue[i],"medium",6) == 0) ||
+                          (strncmpi(cvalue[i],"normal",6) == 0)) {
+                       shade[i] = schoice[1];
+                       ttycolors[icolor] = M_GRAY;     /* regular gray */
+               } else if ((strncmpi(cvalue[i],"white",5) == 0) ||
+                          (strncmpi(cvalue[i],"light",5) == 0)) {
+                       shade[i] = schoice[2];
+                       ttycolors[icolor] = M_WHITE;  /* bright white */
+               } else {
+                       shadeflag = 0;
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+/*
+ * Process defaults.nh OPTIONS=videocolors:xxx
+ * Left to right assignments for:
+ *     red green brown blue magenta cyan orange br.green yellow
+ *     br.blue br.mag br.cyan
+ *
+ * Default Mapping (BIOS): 4-2-6-1-5-3-12-10-14-9-13-11
+ */
+int assign_videocolors(char *colorvals)
+{
+       int i,icolor;
+       uchar *tmpcolor;
+
+       init_ttycolor();        /* in case defaults.nh entry wasn't complete */
+       i = strlen(colorvals);
+       tmpcolor = (uchar *)alloc(i);
+       (void)convert_uchars(colorvals,tmpcolor,i);
+       icolor = CLR_RED;
+       for( i = 0; tmpcolor[i] != 0; ++i) {
+               if (icolor < (CLR_WHITE)) {
+                       ttycolors[icolor++] = tmpcolor[i];
+                       if ((icolor > CLR_CYAN) && (icolor < CLR_ORANGE)) {
+                                icolor = CLR_ORANGE;
+                       }
+               }
+       }
+       colorflag = 1;
+       free((genericptr_t)tmpcolor);
+       return 1;
+}
+
+static int
+convert_uchars(bufp,list,size)
+    char *bufp;        /* current pointer */
+    uchar *list;       /* return list */
+    int size;
+{
+    unsigned int num = 0;
+    int count = 0;
+
+    while (1) {
+       switch(*bufp) {
+           case ' ':  case '\0':
+           case '\t': case '-':
+           case '\n':
+               if (num) {
+                   list[count++] =  num;
+                   num = 0;
+               }
+               if ((count==size) || !*bufp) return count;
+               bufp++;
+               break;
+
+           case '0': case '1': case '2': case '3':
+           case '4': case '5': case '6': case '7':
+           case '8': case '9':
+               num = num*10 + (*bufp-'0');
+               bufp++;
+               break;
+               return count;
+       }
+    }
+    /*NOTREACHED*/
+}
+
+#   endif /* VIDEOSHADES */
+#  endif /* OVL1 */
+# endif /* TEXTCOLOR */
+
+/*
+ * Process defaults.nh OPTIONS=video:xxxx
+ *
+ *    where (current) legitimate values are:
+ *
+ *    autodetect (attempt to determine the adapter type)
+ *    default   (force use of the default video method for environment)
+ *    vga       (use vga adapter code)
+ */
+# ifdef OVL1
+int
+assign_video(sopt)
+char *sopt;
+{
+
+/*
+ * debug
+ *
+ *     printf("video is %s",sopt);
+ *     getch();
+ */
+       iflags.grmode  = 0;
+       iflags.hasvga  = 0;
+       iflags.usevga  = 0;
+
+       if (strncmpi(sopt,"def",3) == 0) {              /* default */
+               /* do nothing - default */
+#  ifdef SCREEN_VGA
+       } else if (strncmpi(sopt,"vga",3) == 0) {       /* vga */
+               iflags.usevga  = 1;
+               iflags.hasvga  = 1;
+#  endif
+#  ifdef SCREEN_VESA
+       } else if (strncmpi(sopt,"vesa",4) == 0) {      /* vesa */
+               iflags.hasvesa = 1;
+               iflags.usevesa = 1;
+#  endif
+#  ifdef SCREEN_8514
+       } else if (strncmpi(sopt,"8514",4) == 0) {      /* 8514/A */
+               iflags.use8514 = 1;
+               iflags.has8514 = 1;
+#  endif
+       } else if (strncmpi(sopt,"auto",4) == 0) {      /* autodetect */
+#  ifdef SCREEN_VESA
+               if (vesa_detect()) {
+                       iflags.hasvesa = 1;
+               }
+#  endif
+#  ifdef SCREEN_8514
+               if (v8514_detect()) {
+                       iflags.has8514 = 1;
+               }
+#  endif
+#  ifdef SCREEN_VGA
+               if (vga_detect()) {
+                       iflags.hasvga  = 1;
+               }
+#  endif
+       /*
+        * Auto-detect Priorities (arbitrary for now):
+        *      VGA
+        */
+               if (iflags.hasvga)      {
+                       iflags.usevga  = 1;
+                       /* VGA depends on BIOS to enable function keys*/
+                       iflags.BIOS = 1;
+                       iflags.rawio = 1;
+               }
+       } else {
+               return 0;
+       }
+       return 1;
+}
+# endif /* OVL1 */
+# ifdef OVL0
+
+void tileview(enable)
+boolean enable;
+{
+#ifdef SCREEN_VGA
+       if (iflags.grmode) vga_traditional(enable ? FALSE : TRUE);
+#endif
+}
+# endif /* OVL0 */
+#endif /* NO_TERMS  */
+#else  /* STUBVIDEO */
+void tileview(enable)
+boolean enable;
+{
+}
+#endif /* STUBVIDEO */
+
diff --git a/sys/msdos/vidtxt.c b/sys/msdos/vidtxt.c
new file mode 100644 (file)
index 0000000..692659e
--- /dev/null
@@ -0,0 +1,472 @@
+/*   SCCS Id: @(#)vidtxt.c   3.4     1994/04/04                     */
+/*   Copyright (c) NetHack PC Development Team 1993                 */
+/*   NetHack may be freely redistributed.  See license for details. */
+/*                                                                  */
+/*
+ * vidtxt.c - Textmode video hardware support (BIOS and DJGPPFAST)
+ *                                                  
+ *Edit History:
+ *     Initial Creation              M. Allison      93/04/04
+ *     Add djgpp support             K. Smolkowski   93/04/26
+ *     Add runtime monoadapter check M. Allison      93/05/09
+ */
+
+#define VIDEO_TEXT
+
+#include "hack.h"
+#include "pcvideo.h"
+#include "wintty.h"
+
+#include <dos.h>
+#include <ctype.h>
+
+#if defined(_MSC_VER)
+# if _MSC_VER >= 700
+#pragma warning(disable:4018)  /* signed/unsigned mismatch */
+#pragma warning(disable:4127)  /* conditional expression is constant */
+#pragma warning(disable:4131)  /* old style declarator */
+#pragma warning(disable:4305)  /* prevents complaints with MK_FP */
+#pragma warning(disable:4309)  /* initializing */
+#pragma warning(disable:4759)  /* prevents complaints with MK_FP */
+# endif
+#endif
+
+/* void FDECL(txt_xputc,(char, int)); */ /* write out character (and attribute) */
+
+extern int attrib_text_normal; /* text mode normal attribute */
+extern int attrib_gr_normal;   /* graphics mode normal attribute */
+extern int attrib_text_intense;        /* text mode intense attribute */
+extern int attrib_gr_intense;  /* graphics mode intense attribute */
+
+#ifdef OVLB
+
+void
+txt_get_scr_size()
+{
+       union REGS regs;
+
+       if (!iflags.BIOS) {
+               CO = 80;
+               LI = 24;
+               return;
+       }
+
+# ifdef PC9800
+       regs.h.ah = SENSEMODE;
+       (void) int86(CRT_BIOS, &regs, &regs);
+
+       CO = (regs.h.al & 0x02) ? 40 : 80;
+       LI = (regs.h.al & 0x01) ? 20 : 25;
+# else 
+       regs.x.ax = FONTINFO;
+       regs.x.bx = 0;                  /* current ROM BIOS font */
+       regs.h.dl = 24;                 /* default row count */
+                                       /* in case no EGA/MCGA/VGA */
+       (void) int86(VIDEO_BIOS, &regs, &regs); /* Get Font Information */
+
+       /* MDA/CGA/PCjr ignore INT 10h, Function 11h, but since we
+        * cleverly loaded up DL with the default, everything's fine.
+        *
+        * Otherwise, DL now contains rows - 1.  Also, CX contains the
+        * points (bytes per character) and ES:BP points to the font
+        * table.  -3.
+        */
+
+       regs.h.ah = GETMODE;
+       (void) int86(VIDEO_BIOS, &regs, &regs); /* Get Video Mode */
+
+       /* This goes back all the way to the original PC.  Completely
+        * safe.  AH contains # of columns, AL contains display mode,
+        * and BH contains the active display page.
+        */
+
+       LI = regs.h.dl + 1;
+       CO = regs.h.ah;
+# endif /* PC9800 */
+}
+#endif /*OVLB*/
+
+/*
+ * --------------------------------------------------------------
+ * The rest of this file is only compiled if NO_TERMS is defined.
+ * --------------------------------------------------------------
+ */
+
+#ifdef NO_TERMS
+/* #include "wintty.h" */
+
+# ifdef SCREEN_DJGPPFAST
+#include <pc.h>
+#include <unistd.h>
+# endif
+
+void FDECL(txt_gotoxy, (int,int));
+
+# if defined(SCREEN_BIOS) && !defined(PC9800)
+void FDECL(txt_get_cursor, (int *, int *));
+# endif
+
+# ifdef SCREEN_DJGPPFAST
+#define txt_get_cursor(x,y) ScreenGetCursor(y,x)
+# endif
+
+extern int  g_attribute;       /* Current attribute to use */
+extern int  monoflag;          /* 0 = not monochrome, else monochrome */
+
+# ifdef OVLB
+void
+txt_backsp()
+{
+#  ifdef PC9800
+       union REGS regs;
+
+       regs.h.dl = 0x01;                 /* one column */
+       regs.h.ah = CURSOR_LEFT;
+       regs.h.cl = DIRECT_CON_IO;
+
+       int86(DOS_EXT_FUNC, &regs, &regs);
+
+#  else
+       int col,row;
+
+       txt_get_cursor(&col, &row);
+       if (col > 0) col = col-1;
+       txt_gotoxy(col,row);
+#  endif
+}
+
+void
+txt_nhbell()
+{
+        union REGS regs;
+
+        if (flags.silent) return;
+        regs.h.dl = 0x07;                      /* bell */
+        regs.h.ah = 0x02;                      /* Character Output function */
+        (void) int86(DOSCALL, &regs, &regs);
+}
+# endif /* OVLB */
+
+# ifdef OVL0
+void
+txt_clear_screen()
+/* djgpp provides ScreenClear(), but in version 1.09 it is broken
+ * so for now we just use the BIOS Routines
+ */
+{
+       union REGS regs;
+#  ifdef PC9800
+       regs.h.dl = attr98[attrib_text_normal];
+       regs.h.ah = SETATT;
+       regs.h.cl = DIRECT_CON_IO;
+
+       (void) int86(DOS_EXT_FUNC, &regs, &regs);
+
+       regs.h.dl = 0x02;               /* clear whole screen */
+       regs.h.ah = SCREEN_CLEAR;
+       regs.h.cl = DIRECT_CON_IO;
+
+       (void) int86(DOS_EXT_FUNC, &regs, &regs);
+#  else
+       regs.h.dl = (char)(CO - 1);     /* columns */
+       regs.h.dh = (char)(LI - 1);     /* rows */
+       regs.x.cx = 0;                  /* CL,CH = x,y of upper left */
+       regs.x.ax = 0;  
+       regs.x.bx = 0;
+       regs.h.bh = (char)attrib_text_normal;
+       regs.h.ah = (char)SCROLL;
+                                               /* DL,DH = x,y of lower rt */
+       (void) int86(VIDEO_BIOS, &regs, &regs); /* Scroll or init window   */
+       txt_gotoxy(0,0);
+#  endif
+}
+
+void
+txt_cl_end(col,row)    /* clear to end of line */
+int col,row;
+{
+       union REGS regs;
+#  ifndef PC9800
+       int count;
+#  endif
+
+#  ifdef PC9800
+       regs.h.dl = attr98[attrib_text_normal];
+       regs.h.ah = SETATT;
+       regs.h.cl = DIRECT_CON_IO;
+
+       (void) int86(DOS_EXT_FUNC, &regs, &regs);
+
+       regs.h.dl = 0x00;               /* clear to end of line */
+       regs.h.ah = LINE_CLEAR;
+       regs.h.cl = DIRECT_CON_IO;
+
+       (void) int86(DOS_EXT_FUNC, &regs, &regs);
+#  else
+       count = CO - col;
+       txt_gotoxy(col,row);
+       regs.h.ah = PUTCHARATT;      /* write attribute & character */  
+       regs.h.al = ' ';             /* character */
+       regs.h.bh = 0;               /* display page */
+                                    /* BL = attribute */
+       regs.h.bl = (char)attrib_text_normal;
+       regs.x.cx = count;
+       if (count != 0)
+               (void) int86(VIDEO_BIOS, &regs, &regs); /* write attribute 
+                                                          & character */
+#  endif
+}
+
+void
+txt_cl_eos()   /* clear to end of screen */
+{
+       union REGS regs;
+#  ifndef PC9800
+       int col,row;
+#  endif
+
+#  ifdef PC9800
+       regs.h.dl = attr98[attrib_text_normal];
+       regs.h.ah = SETATT;
+       regs.h.cl = DIRECT_CON_IO;
+
+       (void) int86(DOS_EXT_FUNC, &regs, &regs);
+
+       regs.h.dl = 0x00;               /* clear to end of screen */
+       regs.h.ah = SCREEN_CLEAR;
+       regs.h.cl = DIRECT_CON_IO;
+
+       (void) int86(DOS_EXT_FUNC, &regs, &regs);
+#  else
+       txt_get_cursor(&col, &row);
+       txt_cl_end(col,row);                    /* clear to end of line */
+       txt_gotoxy(0,(row < (LI-1) ? row+1 : (LI-1)));          
+       regs.h.dl = (char) (CO-1);      /* X  of lower right */
+       regs.h.dh = (char) (LI-1);      /* Y  of lower right */
+       regs.h.cl = 0;                  /* X  of upper left */
+                                       /* Y (row)  of upper left */
+       regs.h.ch = (char) (row < (LI-1) ? row+1 :(LI-1));
+       regs.x.cx = 0; 
+       regs.x.ax = 0;
+       regs.x.bx = 0;
+       regs.h.bh = (char)attrib_text_normal;
+       regs.h.ah = SCROLL;
+       (void) int86(VIDEO_BIOS, &regs, &regs); /* Scroll or initialize window */
+# endif
+}
+# endif /* OVL0 */
+
+# ifdef OVLB
+void
+txt_startup(wid, hgt)
+    int *wid, *hgt;
+{
+       txt_get_scr_size();
+       *wid = CO;
+       *hgt = LI;
+
+       attrib_gr_normal    = attrib_text_normal;
+       attrib_gr_intense   = attrib_text_intense;
+       g_attribute         = attrib_text_normal;               /* Give it a starting value */
+}
+# endif /* OVLB */
+
+/*
+ * Screen output routines (these are heavily used).
+ *
+ * These are the 3 routines used to place information on the screen
+ * in the NO_TERMS PC tty port of NetHack.  These are the routines
+ * that get called by routines in other NetHack source files (such
+ * as those in win/tty).
+ *
+ * txt_xputs - Writes a c null terminated string at the current location.
+ *         Depending on compile options, this could just be a series
+ *         of repeated calls to xputc() for each character.
+ * txt_xputc - Writes a single character at the current location. Since
+ *         various places in the code assume that control characters
+ *         can be used to control, we are forced to interpret some of
+ *         the more common ones, in order to keep things looking correct.
+ *
+ * NOTES:
+ *         wintty.h uses macros to redefine common output functions
+ *         such as puts, putc, putchar, so that they get steered into
+ *         either xputs (for strings) or xputc (for single characters).
+ *         References to puts, putc, and putchar in other source files
+ *         (that include wintty.h) are actually using these routines.
+ */
+
+# ifdef OVL0
+void
+txt_xputs(s,col,row)
+const char *s;
+int col,row;
+{
+       char c;
+
+       if (s != (char *)0) {
+               while (*s != '\0') {
+                       txt_gotoxy(col,row);
+                       c = *s++;
+                       txt_xputc(c,g_attribute);
+                       if (col < (CO-1)) col++;
+                       txt_gotoxy(col,row);
+               }
+       }
+}
+
+void
+txt_xputc(ch,attr)     /* write out character (and attribute) */
+char ch;
+int attr;
+{
+#  ifdef PC9800
+       union REGS regs;
+
+       regs.h.dl = attr98[attr];
+       regs.h.ah = SETATT;
+       regs.h.cl = DIRECT_CON_IO;
+
+       (void) int86(DOS_EXT_FUNC, &regs, &regs);
+
+       if (ch == '\n') {
+               regs.h.dl = '\r';
+               regs.h.ah = PUTCHAR;
+               regs.h.cl = DIRECT_CON_IO;
+
+               (void) int86(DOS_EXT_FUNC, &regs, &regs);
+       }
+       regs.h.dl = ch;
+       regs.h.ah = PUTCHAR;
+       regs.h.cl = DIRECT_CON_IO;
+
+       (void) int86(DOS_EXT_FUNC, &regs, &regs);
+#  else
+#   ifdef SCREEN_BIOS
+       union REGS regs;
+#   endif
+       int col,row;
+
+       txt_get_cursor(&col,&row);
+       switch(ch) {
+           case '\n':  
+#if 0
+                       col = 0;
+                       ++row;
+#endif
+                       break;
+           default:
+#   ifdef SCREEN_DJGPPFAST
+                       ScreenPutChar((int)ch,attr,col,row);
+#   endif
+#   ifdef SCREEN_BIOS
+                       regs.h.ah = PUTCHARATT;  /* write att & character */
+                       regs.h.al = ch;          /* character             */
+                       regs.h.bh = 0;           /* display page          */
+                       regs.h.bl = (char)attr;        /* BL = attribute        */
+                       regs.x.cx = 1;           /* one character         */
+                       (void) int86(VIDEO_BIOS, &regs, &regs);
+#   endif
+                       if (col < (CO -1 )) ++col;
+                       break;
+       } /* end switch */
+       txt_gotoxy(col,row);
+#  endif /* PC9800 */
+}
+# endif /* OVL0 */
+
+/*
+ * This marks the end of the general screen output routines that are
+ * called from other places in NetHack.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * Cursor location manipulation, and location information fetching
+ * routines.
+ * These include:
+ *
+ * txt_get_cursor(x,y)  - Returns the current location of the cursor.  In
+ *                    some implementations this is implemented as a
+ *                    function (BIOS), and in others it is a macro
+ *                    (DJGPPFAST).
+ *
+ * txt_gotoxy(x,y)      - Moves the cursor on screen to the specified x and
+ *                    y location.  This routine moves the location where
+ *                    screen writes will occur next, it does not change
+ *                    the location of the player on the NetHack level.
+ */
+# ifdef OVL0
+#  if defined(SCREEN_BIOS) && !defined(PC9800)
+/*
+ * This is implemented as a macro under DJGPPFAST.
+ */
+void
+txt_get_cursor(x,y)    /* get cursor position */
+int *x, *y;
+{
+       union REGS regs;
+
+       regs.x.dx = 0;
+       regs.h.ah = GETCURPOS;           /* get cursor position */
+       regs.x.cx = 0;
+       regs.x.bx = 0;  
+       (void) int86(VIDEO_BIOS, &regs, &regs); /* Get Cursor Position */
+       *x = regs.h.dl;
+       *y = regs.h.dh;
+}
+#  endif /* SCREEN_BIOS && !PC9800 */
+
+void
+txt_gotoxy(x,y)
+int x,y;
+{
+#  ifdef SCREEN_BIOS
+       union REGS regs;
+
+#   ifdef PC9800
+       regs.h.dh = (char)y;            /* row */
+       regs.h.dl = (char)x;            /* column */
+       regs.h.ah = SETCURPOS;
+       regs.h.cl = DIRECT_CON_IO;
+       (void) int86(DOS_EXT_FUNC, &regs, &regs); /* Set Cursor Position */
+#   else
+       regs.h.ah = SETCURPOS;
+       regs.h.bh = 0;                  /* display page */
+       regs.h.dh = (char)y;            /* row */
+       regs.h.dl = (char)x;            /* column */
+       (void) int86(VIDEO_BIOS, &regs, &regs); /* Set Cursor Position */
+#   endif
+#  endif
+#  if defined(SCREEN_DJGPPFAST)
+       ScreenSetCursor(y,x);
+#  endif
+       /* The above, too, goes back all the way to the original PC.  If
+        * we ever get so fancy as to swap display pages (i doubt it),
+        * then we'll need to set BH appropriately.  This function
+        * returns nothing.  -3.
+        */
+}
+# endif /* OVL0 */
+
+/*
+ * This marks the end of the cursor manipulation/information routines.
+ * -------------------------------------------------------------------
+ */ 
+
+# ifdef OVLB
+#  ifdef MONO_CHECK
+int txt_monoadapt_check()
+{
+       union REGS regs;
+
+       regs.h.al = 0;
+       regs.h.ah = GETMODE;                    /* get video mode */
+       (void) int86(VIDEO_BIOS, &regs, &regs);
+       return (regs.h.al == 7) ? 1 : 0;        /* 7 means monochrome mode */
+}
+#  endif /* MONO_CHECK */
+# endif /* OVLB */
+#endif /* NO_TERMS  */
+
+/* vidtxt.c */
diff --git a/sys/msdos/vidvga.c b/sys/msdos/vidvga.c
new file mode 100644 (file)
index 0000000..00a1475
--- /dev/null
@@ -0,0 +1,1480 @@
+/*   SCCS Id: @(#)vidvga.c   3.4     1996/02/16                          */
+/*   Copyright (c) NetHack PC Development Team 1995                 */
+/*   NetHack may be freely redistributed.  See license for details. */
+/*
+ * vidvga.c - VGA Hardware video support
+ */
+
+#include "hack.h"
+
+#ifdef SCREEN_VGA              /* this file is for SCREEN_VGA only    */
+#include "pcvideo.h"
+#include "tile.h"
+#include "pctiles.h"
+
+#include <dos.h>
+#include <ctype.h>
+#include "wintty.h"
+
+# ifdef __GO32__
+#include <pc.h>
+#include <unistd.h>
+# endif
+
+/*=========================================================================
+ * VGA Video supporting routines (for tiles).
+ *
+ * The following routines carry out the lower level video functions required
+ * to make PC NetHack work with VGA graphics.
+ *
+ *   - The binary files NetHack1.tib and NetHacko.tib must be in your
+ *     game directory.  Currently, unpredictable results may occur if they 
+ *     aren't since the code hasn't been tested with it missing (yet).
+ *
+ * Notes (96/02/16):
+ *
+ *   - Cursor emulation on the map is now implemented.  The input routine
+ *     in msdos.c calls the routine to display the cursor just before
+ *     waiting for input, and hides the cursor immediately after satisfying 
+ *     the input request.
+ *
+ *   - A check for a VGA adapter is implemented.
+ *
+ *   - With 640 x 480 resolution, the use of 16 x 16 icons allows only 40
+ *     columns for the map display.  This makes it necessary to support the
+ *     TTY CLIPPING code.  The right/left scrolling with this can be
+ *     a little annoying.  Feel free to rework the routines.
+ *
+ *   - NetHack1.tib is built from text files derived from bitmap files 
+ *     provided by Warwick Allison, using routines developed and supplied 
+ *     by Janet Walz.  The icons are very well done and thanks to 
+ *     Warwick Allison for an excellent effort!
+ *
+ *   - The text fonts that this is using while in graphics mode come from
+ *     the Video BIOS ROM on board the VGA adapter.  Code in vga_WriteChar
+ *     copies the appropriate pixels from the video ROM to the Video buffer.
+ *
+ *   - Currently, most of the routines are in an ifdef OVLB.
+ *     If you change that, you may have to muck with some of the 
+ *     variable declarations which now assume this.  This is not a 
+ *     problem in a non-overlaid environment (djgpp for example).
+ *
+ *   - VGA 640 by 480, 16 colour mode (0x12) uses an odd method to 
+ *     represent a colour value from the palette. There are four 
+ *     planes of video memory, all overlaid at the same memory location.
+ *     For example, if a pixel has the colour value 7:
+ *
+ *           0 1 1 1
+ *            \ \ \ \
+ *             \ \ \ plane 0 
+ *              \ \ plane 1
+ *               \ plane 2
+ *                plane 3
+ *
+ *   - VGA write mode 2 requires that a read be done before a write to
+ *     set some latches on the card.  The value read had to be placed
+ *     into a variable declared 'volatile' to prevent djgpp from
+ *     optimizing away the entire instruction (the value was assigned
+ *     to a variable which was never used).  This corrects the striping
+ *     problem that was apparent with djgpp.
+ *
+ *   - A check for valid mode switches has been added.
+ *
+ *   - No tiles are displayed on the Rogue Level in keeping with the
+ *     original Rogue.  The display adapter remains in graphics mode 
+ *     however.
+ *
+ *   - Added handling for missing NetHackX.tib files, and resort to using
+ *     video:default and tty if one of them can't be located.
+ *
+ * ToDo (96/02/17):
+ *
+ *   - Nothing prior to release.
+ *=========================================================================
+ */
+
+
+# if defined(_MSC_VER)
+#  if _MSC_VER >= 700
+#pragma warning(disable:4018)  /* signed/unsigned mismatch */
+#pragma warning(disable:4127)  /* conditional expression is constant */
+#pragma warning(disable:4131)  /* old style declarator */
+#pragma warning(disable:4305)  /* prevents complaints with MK_FP */
+#pragma warning(disable:4309)  /* initializing */
+#    if _MSC_VER > 700
+#pragma warning(disable:4759)  /* prevents complaints with MK_FP */
+#    endif
+#  endif
+# include <conio.h>
+# endif
+
+/* STATIC_DCL void FDECL(vga_NoBorder, (int));  */
+void FDECL(vga_gotoloc, (int,int));  /* This should be made a macro */
+void NDECL(vga_backsp);
+#ifdef SCROLLMAP
+STATIC_DCL void FDECL(vga_scrollmap,(BOOLEAN_P));
+#endif
+STATIC_DCL void FDECL(vga_redrawmap,(BOOLEAN_P));
+void FDECL(vga_cliparound,(int, int));
+STATIC_OVL void FDECL(decal_planar,(struct planar_cell_struct *, unsigned));
+
+#ifdef POSITIONBAR
+STATIC_DCL void NDECL(positionbar);
+static void FDECL(vga_special,(int, int, int));
+#endif
+
+extern int clipx, clipxmax;    /* current clipping column from wintty.c */
+extern boolean clipping;       /* clipping on? from wintty.c */
+extern int savevmode;          /* store the original video mode */
+extern int curcol,currow;      /* current column and row        */
+extern int g_attribute;
+extern int attrib_text_normal; /* text mode normal attribute */
+extern int attrib_gr_normal;   /* graphics mode normal attribute */
+extern int attrib_text_intense;        /* text mode intense attribute */
+extern int attrib_gr_intense;  /* graphics mode intense attribute */
+extern boolean inmap;          /* in the map window */
+
+/*
+ * Global Variables
+ */ 
+
+STATIC_VAR unsigned char __far *font;
+STATIC_VAR char *screentable[SCREENHEIGHT];
+
+STATIC_VAR char *paletteptr;
+STATIC_VAR struct map_struct {
+       int glyph;
+       int ch;
+       int attr;
+       unsigned special;
+}  map[ROWNO][COLNO];  /* track the glyphs */
+
+# define vga_clearmap() { int x,y; for (y=0; y < ROWNO; ++y) \
+       for (x=0; x < COLNO; ++x) { map[y][x].glyph = cmap_to_glyph(S_stone); \
+       map[y][x].ch = S_stone; map[y][x].attr = 0; map[y][x].special = 0;} }
+# define TOP_MAP_ROW 1
+#  if defined(OVLB)
+STATIC_VAR int vgacmap[CLR_MAX] = {0,3,5,9,4,8,12,14,11,2,6,7,1,8,12,13};
+STATIC_VAR int viewport_size = 40;
+/* STATIC_VAR char masktable[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; */
+/* STATIC_VAR char bittable[8]= {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; */
+#if 0
+STATIC_VAR char defpalette[] = {       /* Default VGA palette         */
+       0x00, 0x00, 0x00,
+       0x00, 0x00, 0xaa,
+       0x00, 0xaa, 0x00,
+       0x00, 0xaa, 0xaa,
+       0xaa, 0x00, 0x00,
+       0xaa, 0x00, 0xaa,
+       0xaa, 0xaa, 0x00,
+       0xaa, 0xaa, 0xaa,
+       0x55, 0x55, 0x55,
+       0xcc, 0xcc, 0xcc,
+       0x00, 0x00, 0xff,
+       0x00, 0xff, 0x00,
+       0xff, 0x00, 0x00,
+       0xff, 0xff, 0x00,
+       0xff, 0x00, 0xff,
+       0xff, 0xff, 0xff
+       };
+#endif
+
+#   ifndef ALTERNATE_VIDEO_METHOD
+int vp[SCREENPLANES] = {8,4,2,1};
+#   endif
+int vp2[SCREENPLANES] = {1,2,4,8};
+#  else
+extern int vgacmap[CLR_MAX];
+extern int viewport_size;
+extern char masktable[8];
+extern char bittable[8];
+extern char defpalette[];
+#   ifndef ALTERNATE_VIDEO_METHOD
+extern int vp[SCREENPLANES];
+#   endif
+extern int vp2[SCREENPLANES];
+#  endif /* OVLB */
+
+STATIC_VAR struct planar_cell_struct *planecell;
+STATIC_VAR struct overview_planar_cell_struct *planecell_O;
+
+# if defined(USE_TILES)
+STATIC_VAR struct tibhdr_struct tibheader;
+/* extern FILE *tilefile; */ /* Not needed in here most likely */
+# endif
+
+/* STATIC_VAR int  g_attribute;        */      /* Current attribute to use */
+
+#ifdef OVLB
+void
+vga_get_scr_size()
+{
+       CO = 80;
+       LI = 29;
+}
+#endif /*OVLB*/
+
+
+
+# ifdef OVLB
+
+void
+vga_backsp()
+{
+       int col,row;
+
+       col = curcol;           /* Character cell row and column */
+       row = currow;
+
+       if (col > 0) col = col-1;
+       vga_gotoloc(col,row);
+}
+
+# endif /* OVLB */
+# ifdef OVL0
+
+void
+vga_clear_screen(colour)
+int colour;
+{
+       char __far *pch;
+       int y,j;
+       char volatile a;
+
+       outportb(0x3ce,5);
+       outportb(0x3cf,2);
+
+       for (y=0; y < SCREENHEIGHT; ++y) {
+               pch = screentable[y];
+               for (j=0; j < SCREENBYTES; ++j) {
+                       outportb(0x3ce,8);
+                       outportb(0x3cf,255);
+                       a = READ_ABSOLUTE(pch); /* Must read , then write */
+                       WRITE_ABSOLUTE(pch, (char)colour);
+                       ++pch;
+               }
+       }
+       outportb(0x3ce,5);
+       outportb(0x3cf,0);
+       if (iflags.tile_view) vga_clearmap();
+       vga_gotoloc(0,0);       /* is this needed? */
+}
+
+void
+vga_cl_end(col,row)    /* clear to end of line */
+int col,row;
+{
+       int count;
+
+       /*
+        * This is being done via character writes.
+        * This should perhaps be optimized for speed by using VGA write
+        * mode 2 methods as did clear_screen()
+        */
+       for (count = col; count < (CO-1); ++count) {
+               vga_WriteChar(' ',count,row,BACKGROUND_VGA_COLOR);
+       }
+}
+
+void
+vga_cl_eos(cy) /* clear to end of screen */
+int cy;
+{
+       int count;
+
+       cl_end();
+       while(cy <= LI-2) {
+               for (count = 0; count < (CO-1); ++count) {
+                       vga_WriteChar(' ',count,cy,
+                               BACKGROUND_VGA_COLOR);
+               }
+               cy++;
+       }
+}
+
+
+# endif /* OVL0 */
+
+# ifdef OVLB
+void
+vga_tty_end_screen()
+{
+       vga_clear_screen(BACKGROUND_VGA_COLOR);
+       vga_SwitchMode(MODETEXT);
+}
+
+
+void
+vga_tty_startup(wid, hgt)
+    int *wid, *hgt;
+{
+
+       /* code to sense display adapter is required here - MJA */
+
+       vga_get_scr_size();
+       if (CO && LI) {
+               *wid = CO;
+               *hgt = LI;
+       }
+
+       attrib_gr_normal    = ATTRIB_VGA_NORMAL;
+       attrib_gr_intense   = ATTRIB_VGA_INTENSE;
+       g_attribute         = attrib_gr_normal; /* Give it a starting value */
+}
+# endif /* OVLB */
+
+/*
+ * Screen output routines (these are heavily used).
+ *
+ * These are the 3 routines used to place information on the screen
+ * in the VGA PC tty port of NetHack.  These are the routines
+ * that get called by the general interface routines in video.c.
+ *
+ * vga_xputs -Writes a c null terminated string at the current location.
+ *
+ * vga_xputc -Writes a single character at the current location. Since
+ *            various places in the code assume that control characters
+ *            can be used to control, we are forced to interpret some of
+ *            the more common ones, in order to keep things looking correct.
+ *
+ * vga_xputg -This routine is used to display a graphical representation of a
+ *            NetHack glyph (a tile) at the current location.  For more
+ *            information on NetHack glyphs refer to the comments in
+ *            include/display.h.
+ *
+ */
+
+# ifdef OVL0
+void
+vga_xputs(s,col,row)
+const char *s;
+int col,row;
+{
+
+       if (s != (char *)0) {
+               vga_WriteStr((char *)s,strlen(s),col,row,g_attribute);
+       }
+}
+
+void
+vga_xputc(ch,attr)     /* write out character (and attribute) */
+char ch;
+int attr;
+{
+       int col,row;
+
+       col = curcol;
+       row = currow;
+
+       switch(ch) {
+           case '\n':  
+                       col = 0;
+                       ++row;
+                       break;
+           default:
+                       vga_WriteChar((unsigned char)ch,col,row,attr);
+                       if (col < (CO -1 )) ++col;
+                       break;
+       } /* end switch */
+       vga_gotoloc(col,row);
+}
+
+#  if defined(USE_TILES)
+void
+vga_xputg(glyphnum,ch, special)        /* Place tile represent. a glyph at current location */
+int glyphnum;
+int ch;
+unsigned special;      /* special feature: corpse, invis, detected, pet, ridden - hack.h */
+{
+       int col,row;
+       int attr;
+       int ry;
+
+       row = currow;
+       col = curcol;
+       if ((col < 0 || col >= COLNO) ||
+           (row < TOP_MAP_ROW || row >= (ROWNO + TOP_MAP_ROW))) return;
+       ry = row - TOP_MAP_ROW;
+       map[ry][col].glyph = glyphnum;
+       map[ry][col].ch = ch;
+       map[ry][col].special = special;
+       attr = (g_attribute == 0) ? attrib_gr_normal : g_attribute;
+       map[ry][col].attr = attr;
+       if (iflags.traditional_view) {
+           vga_WriteChar((unsigned char)ch,col,row,attr);
+       } else if (!iflags.over_view) {
+           if ((col >= clipx) && (col <= clipxmax)) {
+               if (!ReadPlanarTileFile(glyph2tile[glyphnum], &planecell)) {
+                       if (map[ry][col].special) decal_planar(planecell, special);
+                       vga_DisplayCell(planecell, 
+                                       col - clipx, row);
+               } else
+                       pline("vga_xputg: Error reading tile (%d,%d) from file",
+                                       glyphnum,glyph2tile[glyphnum]);
+           }
+       } else {
+           if (!ReadPlanarTileFile_O(glyph2tile[glyphnum], &planecell_O))
+                       vga_DisplayCell_O(planecell_O, col, row);
+           else
+                       pline("vga_xputg: Error reading tile (%d,%d) from file",
+                                       glyphnum,glyph2tile[glyphnum]);
+       }
+       if (col < (CO - 1 )) ++col;
+       vga_gotoloc(col,row);
+}
+#  endif /* USE_TILES */
+
+/*
+ * Cursor location manipulation, and location information fetching
+ * routines.
+ * These include:
+ *
+ * vga_gotoloc(x,y)     - Moves the "cursor" on screen to the specified x
+ *                      and y character cell location.  This routine
+ *                       determines the location where screen writes
+ *                       will occur next, it does not change the location
+ *                       of the player on the NetHack level.
+ */
+void
+vga_gotoloc(col,row)
+int col,row;
+{
+       curcol = min(col,CO - 1); /* protection from callers */
+       currow = min(row,LI - 1);
+}
+
+#  if defined(USE_TILES) && defined(CLIPPING)
+void
+vga_cliparound(x, y)
+int x, y;
+{
+       extern boolean restoring;
+       int oldx = clipx;
+
+       if (!iflags.tile_view || iflags.over_view || iflags.traditional_view)
+               return;
+
+       if (x < clipx + 5) {
+               clipx = max(0, x - (viewport_size / 2));
+               clipxmax = clipx + (viewport_size - 1);
+       }
+       else if (x > clipxmax - 5) {
+               clipxmax = min(COLNO - 1, x + (viewport_size / 2));
+               clipx = clipxmax - (viewport_size - 1);
+       }
+       if (clipx != oldx) {
+           if (on_level(&u.uz0, &u.uz) && !restoring)
+               /* (void) doredraw(); */
+               vga_redrawmap(1);
+       }
+}
+
+STATIC_OVL void
+vga_redrawmap(clearfirst)
+boolean clearfirst;
+{
+       int j,x,y,t;
+       char __far *pch;
+       char volatile a;
+       
+       if (clearfirst) {
+               /* y here is in pixel rows */
+               outportb(0x3ce,5);
+               outportb(0x3cf,2);
+               t = TOP_MAP_ROW * ROWS_PER_CELL;
+               for (y = t; y < (ROWNO * ROWS_PER_CELL) + t; ++y) {
+                       pch = screentable[y];
+                       for (j=0; j < SCREENBYTES; ++j) {
+                               outportb(0x3ce,8);
+                               outportb(0x3cf,255);
+                                /* On VGA mode2, must read first, then write */
+                               a = READ_ABSOLUTE(pch);
+                               WRITE_ABSOLUTE(pch, (char)BACKGROUND_VGA_COLOR);
+                               ++pch;
+                       }
+               }
+               outportb(0x3ce,5);
+               outportb(0x3cf,0);
+       }
+       /* y here is in screen rows*/
+#    ifdef ROW_BY_ROW
+       for (y = 0; y < ROWNO; ++y)
+               for (x = clipx; x <= clipxmax; ++x) {
+#    else
+       for (x = clipx; x <= clipxmax; ++x)
+               for (y = 0; y < ROWNO; ++y) {
+#    endif
+                   if (iflags.traditional_view) {
+                       if (!(clearfirst && map[y][x].ch == S_stone))
+                               vga_WriteChar(
+                                       (unsigned char)map[y][x].ch,
+                                       x,y + TOP_MAP_ROW,map[y][x].attr);
+                   } else {
+                     t = map[y][x].glyph;
+                     if (!(clearfirst && t == cmap_to_glyph(S_stone))) {
+                       if (!iflags.over_view) {
+                               if (!ReadPlanarTileFile(glyph2tile[t], 
+                                   &planecell)) {
+                                       if (map[y][x].special)
+                                               decal_planar(planecell, map[y][x].special);
+                                       vga_DisplayCell(planecell,
+                                               x - clipx, y + TOP_MAP_ROW);
+                               } else
+                             pline("vga_redrawmap: Error reading tile (%d,%d)",
+                                        t,glyph2tile[t]);
+                       } else {
+                               if (!ReadPlanarTileFile_O(glyph2tile[t], 
+                                    &planecell_O)) {
+                                       vga_DisplayCell_O(planecell_O,
+                                               x, y + TOP_MAP_ROW);
+                               } else
+                            pline("vga_redrawmap: Error reading tile (%d,%d)",
+                                       t,glyph2tile[t]);
+                       }
+                     }
+                   }
+               }
+}
+#  endif /* USE_TILES && CLIPPING */
+# endif /* OVL0 */
+# ifdef OVL2
+
+void
+vga_userpan(left)
+boolean left;
+{
+       int x;
+
+/*     pline("Into userpan"); */
+       if (iflags.over_view || iflags.traditional_view) return;
+       if (left)
+               x = min(COLNO - 1, clipxmax + 10);
+       else 
+               x = max(0, clipx - 10);
+       vga_cliparound(x, 10);  /* y value is irrelevant on VGA clipping */
+       positionbar();
+       vga_DrawCursor();
+}
+
+
+void vga_overview(on)
+boolean on;
+{
+/*     vga_HideCursor(); */
+       if (on) {
+               iflags.over_view = TRUE;
+               clipx = 0;
+               clipxmax = CO - 1;
+       } else {
+               iflags.over_view = FALSE;
+               clipx = max(0, (curcol - viewport_size / 2));
+               if (clipx > ((CO - 1) - viewport_size)) 
+                       clipx = (CO - 1) - viewport_size;
+               clipxmax = clipx + (viewport_size - 1);
+       }
+}
+
+void vga_traditional(on)
+boolean on;
+{
+/*     vga_HideCursor(); */
+       if (on) {
+/*             switch_graphics(ASCII_GRAPHICS); */
+               iflags.traditional_view = TRUE;
+               clipx = 0;
+               clipxmax = CO - 1;
+       } else {
+               iflags.traditional_view = FALSE;
+               if (!iflags.over_view) {
+                       clipx = max(0, (curcol - viewport_size / 2));
+                       if (clipx > ((CO - 1) - viewport_size)) 
+                               clipx = (CO - 1) - viewport_size;
+                       clipxmax = clipx + (viewport_size - 1);
+               }
+       }
+}
+
+void vga_refresh()
+{
+       positionbar();
+       vga_redrawmap(1);
+       vga_DrawCursor();
+}
+
+#  ifdef SCROLLMAP
+STATIC_OVL void
+vga_scrollmap(left)
+boolean left;
+{
+       int j,x,y,t;
+       int i,pixx,pixy,x1,y1,x2,y2;
+       int byteoffset, vplane;
+       char __far *tmp1;
+       char __far *tmp2;
+       unsigned char source[SCREENPLANES][80];
+       unsigned char first,second;
+
+       
+       pixy = row2y(TOP_MAP_ROW);                /* convert to pixels */
+       pixx = col2x(x1);
+       if (left) {
+               x1 = 20;
+               x2 = 0;
+       } else {
+               x1 = 0;
+               x2 = 20;
+       }
+       /* read each row, all columns but the one to be replaced */
+       for(i = 0;i < (ROWNO-1) * ROWS_PER_CELL; ++i) {
+           tmp1 = screentable[i + pixy];
+           tmp1 += x1;
+           for(vplane=0; vplane < SCREENPLANES; ++vplane) {
+               egareadplane(vplane);
+               for (byteoffset = 0; byteoffset < 20; ++byteoffset) {
+                       tmp2 = tmp1 + byteoffset;
+                       source[vplane][byteoffset] = READ_ABSOLUTE(tmp2);
+               }
+           }
+           tmp1 = screentable[i + pixy];
+           tmp1 += x2;
+           for(vplane=0; vplane < SCREENPLANES; ++vplane) {
+               egawriteplane(vp2[vplane]);
+               for (byteoffset = 0; byteoffset < 20; ++byteoffset) {
+                       tmp2 = tmp1 + byteoffset;
+                       WRITE_ABSOLUTE(tmp2,source[vplane][byteoffset]);
+               }
+           }
+           egawriteplane(15);
+       }
+
+       if (left) {
+               i = clipxmax - 1;
+               j = clipxmax;
+       } else {
+               i = clipx;
+               j = clipx + 1;
+       }
+       for (y = 0; y < ROWNO; ++y) {
+           for (x = i; x < j; x += 2) {
+               t = map[y][x].glyph;
+               if (!ReadPlanarTileFile(glyph2tile[t], &planecell))
+                       if (map[y][x].special) decal_planar(planecell, map[y][x].special);
+                       vga_DisplayCell(planecell, x - clipx, y + TOP_MAP_ROW);
+               else
+                       pline("vga_shiftmap: Error reading tile (%d,%d)",
+                               t, glyph2tile[t]);              
+           }
+       }
+}
+#   endif /* SCROLLMAP */
+# endif /* OVL2 */
+
+# ifdef OVLB
+STATIC_OVL void
+decal_planar(gp, special)
+struct planar_cell_struct *gp;
+unsigned special;
+{
+    if (special & MG_CORPSE) {
+    } else if (special & MG_INVIS)  {
+    } else if (special & MG_DETECT) {
+    } else if (special & MG_PET)    {
+    } else if (special & MG_RIDDEN) {
+    }
+}
+
+/*
+ * Open tile files,
+ * initialize the SCREEN, switch it to graphics mode,
+ * initialize the pointers to the fonts, clear
+ * the screen.
+ *
+ */
+void vga_Init(void)
+{
+     int i;
+
+#   ifdef USE_TILES
+     int tilefailure = 0;
+/*
+ * Attempt to open the required tile files. If we can't
+ * don't perform the video mode switch, use TTY code instead.
+ *
+ */
+     if (OpenTileFile(NETHACK_PLANAR_TILEFILE, FALSE)) tilefailure |= 1;
+     if (OpenTileFile(NETHACK_OVERVIEW_TILEFILE, TRUE)) tilefailure |= 2;      
+     if (ReadTileFileHeader(&tibheader, FALSE)) tilefailure |= 4;
+
+     if (tilefailure) {
+       raw_printf("Reverting to TTY mode, tile initialization failure (%d).",
+               tilefailure);
+       wait_synch();
+       iflags.usevga = 0;
+       iflags.tile_view = FALSE;
+       iflags.over_view = FALSE;
+       CO = 80;
+       LI = 25;
+/*     clear_screen()  */ /* not vga_clear_screen() */
+       return;
+     }
+#   endif
+
+     if (iflags.usevga) {
+       for (i=0; i < SCREENHEIGHT; ++i) {
+               screentable[i]=MK_PTR(VIDEOSEG, (i * SCREENBYTES));
+       }
+     }
+     vga_SwitchMode(MODE640x480);
+     windowprocs.win_cliparound = vga_cliparound;
+/*     vga_NoBorder(BACKGROUND_VGA_COLOR); */  /* Not needed after palette mod */
+#   ifdef USE_TILES
+     paletteptr = tibheader.palette;
+     iflags.tile_view = TRUE;
+     iflags.over_view = FALSE;
+#   else
+     paletteptr = defpalette;
+#   endif
+     vga_SetPalette(paletteptr);
+     g_attribute  = attrib_gr_normal;
+     font = vga_FontPtrs();
+     clear_screen();
+     clipx = 0;
+     clipxmax = clipx + (viewport_size - 1);
+}
+
+/*
+ * Switches modes of the video card.
+ *
+ * If mode == MODETEXT (0x03), then the card is placed into text
+ * mode.  If mode == 640x480, then the card is placed into vga
+ * mode (video mode 0x12). No other modes are currently supported.
+ *
+ */
+void vga_SwitchMode(unsigned int mode)
+{
+       union REGS regs;
+
+       if ((mode == MODE640x480) || (mode == MODETEXT)) {
+               if (iflags.usevga && (mode == MODE640x480)) {
+                       iflags.grmode = 1;
+               } else {
+                       iflags.grmode = 0;
+               }
+               regs.x.ax = mode;
+               (void) int86(VIDEO_BIOS, &regs, &regs);
+       } else {
+               iflags.grmode = 0;      /* force text mode for error msg */
+               regs.x.ax = MODETEXT;
+               (void) int86(VIDEO_BIOS, &regs, &regs);
+               g_attribute  = attrib_text_normal;
+               impossible("vga_SwitchMode: Bad video mode requested 0x%X",
+                       mode);
+       }
+}
+
+/*
+ * This allows grouping of several tasks to be done when
+ * switching back to text mode. This is a public (extern) function.
+ *
+ */
+void vga_Finish(void)
+{
+     CloseTileFile(0);
+     CloseTileFile(1);
+     vga_SwitchMode(MODETEXT);
+     windowprocs.win_cliparound = tty_cliparound;
+     g_attribute  = attrib_text_normal;
+     iflags.tile_view = FALSE;
+}
+
+#if 0
+/*
+ * Turn off any border colour that might be enabled in the VGA card
+ * register.
+ *
+ * I disabled this after modifying tile2bin.c to remap black & white
+ * to a more standard values - MJA 94/04/23.
+ *
+ */
+STATIC_OVL void 
+vga_NoBorder(int bc)
+{
+       union REGS regs;
+
+       regs.h.ah = (char)0x10;
+       regs.h.al = (char)0x01;
+       regs.h.bh = (char)bc;
+       regs.h.bl = 0;
+       (void) int86(VIDEO_BIOS, &regs, &regs); 
+}
+#endif
+
+/*
+ * 
+ * Returns a far pointer (or flat 32 bit pointer under djgpp) to the
+ * location of the appropriate ROM font for the _current_ video mode
+ * (so you must place the card into the desired video mode before
+ * calling this function).
+ *
+ * This function takes advantage of the video BIOS loading the
+ * address of the appropriate character definition table for
+ * the current graphics mode into interrupt vector 0x43 (0000:010C).
+ */
+char __far  *vga_FontPtrs(void)
+{
+       USHORT  __far *tmp;
+       char __far *retval;
+       USHORT fseg, foff;
+       tmp  = (USHORT __far *)MK_PTR(((USHORT)FONT_PTR_SEGMENT),
+                                       ((USHORT)FONT_PTR_OFFSET));
+       foff = READ_ABSOLUTE_WORD(tmp);
+       ++tmp;
+       fseg = READ_ABSOLUTE_WORD(tmp);
+       retval = (char __far *)MK_PTR(fseg,foff);
+       return retval;
+}
+
+/*
+ * This will verify the existance of a VGA adapter on the machine.
+ * Video function call 0x1a returns 0x1a in AL if successful, and
+ * returns the following values in BL for the active display:
+ *
+ * 0=no display, 1=MDA, 2=CGA, 4=EGA(color-monitor), 
+ * 5=EGA(mono-monitor), 6=PGA, 7=VGA(mono-monitor), 8=VGA(color-monitor),
+ * 0xB=MCGA(mono-monitor), 0xC=MCGA(color-monitor), 0xFF=unknown)
+ */
+int vga_detect()
+{
+       union REGS regs;
+       
+       regs.h.al = 0;
+       regs.h.ah = 0x1a;
+       (void) int86(VIDEO_BIOS, &regs, &regs);
+/*
+ * debug
+ *
+ *     printf("vga_detect returned al=%02x, bh=%02x, bl=%02x\n",
+ *                     (int)regs.h.al, (int)regs.h.bh, (int)regs.h.bl);
+ *     getch();
+ */
+       if ((int)regs.h.al == 0x1a) { 
+               if (((int)regs.h.bl == 8) || ((int)regs.h.bl == 7)) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Write character 'ch', at (x,y) and
+ * do it using the colour 'colour'.
+ *
+ */
+void 
+vga_WriteChar(chr,col,row,colour)
+int chr,col,row,colour;
+{
+       int i;
+       int x,pixy;
+
+       char volatile tc;
+       char __far *cp;
+       unsigned char __far *fp = font;
+       unsigned char fnt;
+       int actual_colour = vgacmap[colour];
+
+
+       x = min(col,(CO-1));           /* min() used protection from callers */
+       pixy = min(row,(LI-1)) * 16; /* assumes 8 x 16 char set */
+/*     if (chr < ' ') chr = ' ';  */  /* assumes ASCII set */
+
+       outportb(0x3ce,5);
+       outportb(0x3cf,2);
+                       
+       chr = chr<<4;
+       for (i=0; i < MAX_ROWS_PER_CELL; ++i) {
+               cp = screentable[pixy+i] + x;
+               fnt = READ_ABSOLUTE((fp + chr + i));
+               outportb(0x3ce,8);
+               outportb(0x3cf,fnt);
+               tc = READ_ABSOLUTE(cp); /* wrt mode 2, must read, then write */
+               WRITE_ABSOLUTE(cp, (char)actual_colour);
+               outportb(0x3ce,8);
+               outportb(0x3cf,~fnt);
+               tc = READ_ABSOLUTE(cp); /* wrt mode 2, must read, then write */
+               WRITE_ABSOLUTE(cp, (char)BACKGROUND_VGA_COLOR);
+       }
+       outportb(0x3ce,5);
+       outportb(0x3cf,0);
+       outportb(0x3ce,8);
+       outportb(0x3cf,255);
+}
+
+/*
+ * This is the routine that displays a high-res "cell" pointed to by 'gp'
+ * at the desired location (col,row).
+ *
+ * Note: (col,row) in this case refer to the coordinate location in
+ * NetHack character grid terms, (ie. the 40 x 25 character grid),
+ * not the x,y pixel location.
+ *
+ */
+void
+vga_DisplayCell(gp,col,row)
+struct planar_cell_struct *gp;
+int col,row;
+{
+       int i,pixx,pixy;
+       char __far *tmp_s;      /* source pointer */
+       char __far *tmp_d;      /* destination pointer */
+       int vplane;
+
+       pixy = row2y(row);              /* convert to pixels */
+       pixx = col2x(col);
+       for(vplane=0; vplane < SCREENPLANES; ++vplane) {
+               egawriteplane(vp[vplane]);
+               for(i=0;i < ROWS_PER_CELL; ++i) {
+                       tmp_d = screentable[i+pixy];
+                       tmp_d += pixx;
+               /*
+                * memcpy((void *)tmp,(void *)gp->plane[vplane].image[i],
+                *         BYTES_PER_CELL);
+                */
+                       tmp_s = gp->plane[vplane].image[i];
+                       WRITE_ABSOLUTE(tmp_d, (*tmp_s));
+                       ++tmp_s; ++tmp_d;
+                       WRITE_ABSOLUTE(tmp_d, (*tmp_s));
+               }
+       }
+       egawriteplane(15);
+}
+
+void
+vga_DisplayCell_O(gp,col,row)
+struct overview_planar_cell_struct *gp;
+int col,row;
+{
+       int i,pixx,pixy;
+       char __far *tmp_s;      /* source pointer */
+       char __far *tmp_d;      /* destination pointer */
+       int vplane;
+
+       pixy = row2y(row);              /* convert to pixels */
+       pixx = col;
+       for(vplane=0; vplane < SCREENPLANES; ++vplane) {
+               egawriteplane(vp[vplane]);
+               for(i=0;i < ROWS_PER_CELL; ++i) {
+                       tmp_d = screentable[i+pixy];
+                       tmp_d += pixx;
+               /*
+                * memcpy((void *)tmp,(void *)gp->plane[vplane].image[i],
+                *         BYTES_PER_CELL);
+                */
+                       tmp_s = gp->plane[vplane].image[i];
+                       WRITE_ABSOLUTE(tmp_d, (*tmp_s));
+               }
+       }
+       egawriteplane(15);
+}
+
+/*
+ * Write the character string pointed to by 's', whose maximum length
+ * is 'len' at location (x,y) using the 'colour' colour.
+ *
+ */
+void 
+vga_WriteStr(s,len,col,row,colour)
+char *s;
+int len,col,row,colour;
+{
+       unsigned char *us;
+       int i = 0;
+
+       /* protection from callers */
+       if (row > (LI-1)) return;
+
+       i  = 0;
+       us = (unsigned char *)s;
+       while( (*us != 0) && (i < len) && (col < (CO - 1))) {
+               vga_WriteChar(*us,col,row,colour);
+               ++us;
+               ++i;
+               ++col;
+       }
+}
+
+# endif /* OVLB */
+
+
+# ifdef OVLB
+/*
+ * Initialize the VGA palette with the desired colours. This
+ * must be a series of 48 bytes for use with a card in
+ * 16 colour mode at 640 x 480.
+ *
+ */
+void
+vga_SetPalette(p)
+       char *p;
+{
+       union REGS regs;
+       int i;
+
+       outportb(0x3c6,0xff);
+       for(i=0;i < COLORDEPTH; ++i) {
+               outportb(0x3c8,i);
+               outportb(0x3c9,(*p++) >> 2);
+               outportb(0x3c9,(*p++) >> 2);
+               outportb(0x3c9,(*p++) >> 2);
+       }
+       regs.x.bx = 0x0000;
+       for(i=0;i < COLORDEPTH; ++i) {
+               regs.x.ax = 0x1000;
+               (void) int86(VIDEO_BIOS,&regs,&regs);
+               regs.x.bx += 0x0101;
+       }
+}
+
+/*static unsigned char colorbits[]={0x01,0x02,0x04,0x08}; */ /* wrong */
+static unsigned char colorbits[]={0x08,0x04,0x02,0x01}; 
+
+#ifdef POSITIONBAR
+
+#define PBAR_ROW (LI - 4)
+#define PBAR_COLOR_ON    15    /* slate grey background colour of tiles */
+#define PBAR_COLOR_OFF   12    /* bluish grey, used in old style only */
+#define PBAR_COLOR_STAIRS  9   /* brown */
+#define PBAR_COLOR_HERO   14   /* creamy white */
+
+static unsigned char pbar[COLNO];
+
+void 
+vga_update_positionbar(posbar)
+char *posbar;
+{
+       char *p = pbar;
+       if (posbar) while (*posbar) *p++ = *posbar++;
+       *p = 0;
+}
+
+STATIC_OVL void 
+positionbar()
+{
+       char *posbar = pbar;
+       int feature, ucol;
+       int k, y, colour, row;
+       char __far *pch;
+
+       int startk, stopk;
+       char volatile a;
+       boolean nowhere = FALSE;
+       int pixy = (PBAR_ROW * MAX_ROWS_PER_CELL);
+       int tmp;
+
+       if (!iflags.grmode || !iflags.tile_view) return;
+       if ((clipx < 0)  || (clipxmax <= 0) || (clipx >= clipxmax)) 
+               nowhere = TRUE;
+       if (nowhere) {
+#ifdef DEBUG
+               pline("Would have put bar using %d - %d.",clipx,clipxmax);
+#endif
+               return;
+        }
+#ifdef OLD_STYLE
+       outportb(0x3ce,5);
+       outportb(0x3cf,2);
+       for (y=pixy; y < (pixy + MAX_ROWS_PER_CELL); ++y) {
+               pch = screentable[y];
+               for (k=0; k < SCREENBYTES; ++k) {
+                       if ((k < clipx) || (k > clipxmax)) {
+                               colour = PBAR_COLOR_OFF;                        
+                       } else colour = PBAR_COLOR_ON;
+                       outportb(0x3ce,8);
+                       outportb(0x3cf,255);
+                       a = READ_ABSOLUTE(pch); /* Must read , then write */
+                       WRITE_ABSOLUTE(pch, (char)colour);
+                       ++pch;
+               }
+       }
+       outportb(0x3ce,5);
+       outportb(0x3cf,0);
+#else
+       colour = PBAR_COLOR_ON;
+       outportb(0x3ce,5);
+       outportb(0x3cf,2);
+       for (y=pixy, row = 0; y < (pixy + MAX_ROWS_PER_CELL); ++y, ++row) {
+               pch = screentable[y];
+               if ((!row) || (row == (ROWS_PER_CELL-1))) {
+                       startk = 0;
+                       stopk  = SCREENBYTES;
+               } else {
+                       startk = clipx;
+                       stopk  = clipxmax;
+               }
+               for (k=0; k < SCREENBYTES; ++k) {
+                       if ((k < startk) || (k > stopk))
+                               colour = BACKGROUND_VGA_COLOR;
+                       else
+                               colour = PBAR_COLOR_ON;
+                       outportb(0x3ce,8);
+                       outportb(0x3cf,255);
+                       a = READ_ABSOLUTE(pch); /* Must read , then write */
+                       WRITE_ABSOLUTE(pch, (char)colour);
+                       ++pch;
+               }
+       }
+       outportb(0x3ce,5);
+       outportb(0x3cf,0);
+#endif
+       ucol = 0;
+       if (posbar) {
+           while (*posbar != 0) {
+               feature = *posbar++;
+               switch (feature) {
+                   case '>':
+                       vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS);
+                       break;
+                   case '<':
+                       vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS);
+                       break;
+                   case '@':
+                       ucol = (int)*posbar++;
+                       vga_special(feature, ucol, PBAR_COLOR_HERO);
+                       break;
+                   default: /* unanticipated symbols */
+                       vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS);
+                       break;
+               }
+           }
+       }
+#  ifdef SIMULATE_CURSOR
+       if (inmap) {
+               tmp = curcol + 1;
+               if ((tmp != ucol) && (curcol >= 0))     
+                       vga_special('_', tmp, PBAR_COLOR_HERO);
+       }
+#  endif
+}
+
+void
+vga_special(chr,col,color)
+int chr,col,color;
+{
+       int i,y,pixy;
+       char __far *tmp_d;      /* destination pointer */
+       int vplane;
+       char fnt;
+       char bits[SCREENPLANES][ROWS_PER_CELL];
+
+       pixy = PBAR_ROW * MAX_ROWS_PER_CELL;
+       for(vplane=0; vplane < SCREENPLANES; ++vplane) {
+               egareadplane(vplane);
+               y = pixy;
+               for(i=0;i < ROWS_PER_CELL; ++i) {
+                       tmp_d = screentable[y++] + col;
+                       bits[vplane][i] = READ_ABSOLUTE(tmp_d);
+                       fnt = READ_ABSOLUTE((font + ((chr<<4) + i)));
+                       if (colorbits[vplane] & color)
+                               bits[vplane][i] |= fnt;
+                       else
+                               bits[vplane][i] &= ~fnt;
+               }
+       }
+       for(vplane=0; vplane < SCREENPLANES; ++vplane) {
+               egawriteplane(vp[vplane]);
+               y = pixy;
+               for(i=0;i < ROWS_PER_CELL; ++i) {
+                       tmp_d = screentable[y++] + col;
+                       WRITE_ABSOLUTE(tmp_d, (bits[vplane][i]));
+               }
+       }
+       egawriteplane(15);
+}
+
+#  endif POSITIONBAR
+
+#  ifdef SIMULATE_CURSOR
+
+static struct planar_cell_struct undercursor;
+static struct planar_cell_struct cursor;
+
+void
+vga_DrawCursor()
+{
+       int i,pixx,pixy,x,y,p;
+       char __far *tmp1;
+       char __far *tmp2;
+       unsigned char first,second;
+/*     char on[2] =  {0xFF,0xFF}; */
+/*     char off[2] = {0x00,0x00}; */
+#ifdef REINCARNATION
+       boolean isrogue = Is_rogue_level(&u.uz);
+       boolean singlebyte = (isrogue || iflags.over_view
+                             || iflags.traditional_view || !inmap);
+#else
+       boolean singlebyte = (iflags.over_view
+                             || iflags.traditional_view || !inmap);
+#endif
+       int curtyp;
+
+       if (!cursor_type && inmap) return;      /* CURSOR_INVIS - nothing to do */
+
+       x = min(curcol,(CO - 1)); /* protection from callers */
+       y = min(currow,(LI - 1));                 /* protection from callers */
+       if (!singlebyte && ((x < clipx) || (x > clipxmax))) return;
+           pixy = row2y(y);              /* convert to pixels */
+           if (singlebyte)
+                   pixx = x;
+           else
+                   pixx = col2x((x-clipx));
+
+           for(i=0;i < ROWS_PER_CELL; ++i) {
+               tmp1 = screentable[i+pixy];
+               tmp1 += pixx;
+               tmp2 = tmp1 + 1;
+               egareadplane(3);
+               /* memcpy(undercursor.plane[3].image[i],tmp1,BYTES_PER_CELL); */
+               undercursor.plane[3].image[i][0] = READ_ABSOLUTE(tmp1);
+               if (!singlebyte)
+                       undercursor.plane[3].image[i][1] = READ_ABSOLUTE(tmp2);
+
+               egareadplane(2);
+               /* memcpy(undercursor.plane[2].image[i],tmp1,BYTES_PER_CELL); */
+               undercursor.plane[2].image[i][0] = READ_ABSOLUTE(tmp1);
+               if (!singlebyte)
+                       undercursor.plane[2].image[i][1] = READ_ABSOLUTE(tmp2);
+
+               egareadplane(1);
+               /* memcpy(undercursor.plane[1].image[i],tmp1,BYTES_PER_CELL); */
+               undercursor.plane[1].image[i][0] = READ_ABSOLUTE(tmp1);
+               if (!singlebyte)
+                       undercursor.plane[1].image[i][1] = READ_ABSOLUTE(tmp2);
+
+               egareadplane(0);
+               /* memcpy(undercursor.plane[0].image[i],tmp1,BYTES_PER_CELL); */
+               undercursor.plane[0].image[i][0] = READ_ABSOLUTE(tmp1);
+               if (!singlebyte)
+                       undercursor.plane[0].image[i][1] = READ_ABSOLUTE(tmp2);
+           }
+
+           /*
+             * Now we have a snapshot of the current cell.
+             * Make a copy of it, then manipulate the copy
+             * to include the cursor, and place the tinkered
+             * version on the display.
+             */ 
+
+           cursor = undercursor;
+           if (inmap) curtyp = cursor_type;
+           else curtyp = CURSOR_UNDERLINE;
+
+           switch(curtyp) {
+
+               case CURSOR_CORNER:
+                   for(i = 0; i < 2; ++i) {
+                       if (!i) {
+                               if (singlebyte) first = 0xC3;
+                               else first  = 0xC0;
+                               second = 0x03;
+                       } else {
+                               if (singlebyte) first = 0x81;
+                               else first  = 0x80;
+                               second = 0x01;
+                       }
+                       for (p=0; p < 4; ++p) {
+                               if (cursor_color & colorbits[p]) {
+                                       cursor.plane[p].image[i][0] |= first;
+                                       if (!singlebyte)
+                                       cursor.plane[p].image[i][1] |= second;
+                               } else {
+                                       cursor.plane[p].image[i][0] &= ~first;
+                                       if (!singlebyte)
+                                       cursor.plane[p].image[i][1] &= ~second;
+                               }
+                       }
+                   }
+
+                   for(i = ROWS_PER_CELL - 2; i < ROWS_PER_CELL; ++i) {
+                       if (i != (ROWS_PER_CELL-1)) {
+                               if (singlebyte) first = 0x81;
+                               else first  = 0x80;
+                               second = 0x01;
+                       } else {
+                               if (singlebyte) first = 0xC3;
+                               else first  = 0xC0;
+                               second = 0x03;
+                       }
+                       for (p=0; p < SCREENPLANES; ++p) {
+                               if (cursor_color & colorbits[p]) {
+                                       cursor.plane[p].image[i][0] |= first;
+                                       if (!singlebyte)
+                                       cursor.plane[p].image[i][1] |= second;
+                               } else {
+                                       cursor.plane[p].image[i][0] &= ~first;
+                                       if (!singlebyte)
+                                       cursor.plane[p].image[i][1] &= ~second;
+                               }
+                       }
+                   }
+                   break;
+
+               case CURSOR_UNDERLINE:
+
+                   i = ROWS_PER_CELL - 1;
+                   first  = 0xFF;
+                   second = 0xFF;
+                   for (p=0; p < SCREENPLANES; ++p) {
+                       if (cursor_color & colorbits[p]) {
+                               cursor.plane[p].image[i][0] |= first;
+                               if (!singlebyte)
+                               cursor.plane[p].image[i][1] |= second;
+                       } else {
+                               cursor.plane[p].image[i][0] &= ~first;
+                               if (!singlebyte)
+                               cursor.plane[p].image[i][1] &= ~second;
+                       }
+                   }
+                   break;
+
+               case CURSOR_FRAME:
+
+                   /* fall through */
+
+               default:                        
+                   for(i = 0; i < ROWS_PER_CELL; ++i) {
+
+                       if ((i == 0) || (i == (ROWS_PER_CELL-1))) {
+                               first  = 0xFF;
+                               second = 0xFF;
+                       } else {
+                               if (singlebyte) first = 0x81;
+                               else first  = 0x80;
+                               second = 0x01;
+                       }
+                       for (p=0; p < SCREENPLANES; ++p) {
+                               if (cursor_color & colorbits[p]) {
+                                       cursor.plane[p].image[i][0] |= first;
+                                       if (!singlebyte)
+                                       cursor.plane[p].image[i][1] |= second;
+                               } else {
+                                       cursor.plane[p].image[i][0] &= ~first;
+                                       if (!singlebyte)
+                                       cursor.plane[p].image[i][1] &= ~second;
+                               }
+                       }
+                   }
+                   break;
+           }
+
+          /*
+            * Place the new cell onto the display.
+            *
+            */
+           
+           for(i=0;i < ROWS_PER_CELL; ++i) {
+               tmp1 = screentable[i+pixy];
+               tmp1 += pixx;
+               tmp2 = tmp1 + 1;
+               egawriteplane(8);
+               /* memcpy(tmp1,cursor.plane[3].image[i],BYTES_PER_CELL); */
+               WRITE_ABSOLUTE(tmp1,cursor.plane[3].image[i][0]);
+               if (!singlebyte)
+               WRITE_ABSOLUTE(tmp2,cursor.plane[3].image[i][1]);
+
+               egawriteplane(4);
+               /* memcpy(tmp1,cursor.plane[2].image[i],BYTES_PER_CELL); */
+               WRITE_ABSOLUTE(tmp1,cursor.plane[2].image[i][0]);
+               if (!singlebyte)
+               WRITE_ABSOLUTE(tmp2,cursor.plane[2].image[i][1]);
+
+               egawriteplane(2);
+               /* memcpy(tmp1,cursor.plane[1].image[i],BYTES_PER_CELL); */
+               WRITE_ABSOLUTE(tmp1,cursor.plane[1].image[i][0]);
+               if (!singlebyte)
+               WRITE_ABSOLUTE(tmp2,cursor.plane[1].image[i][1]);
+
+               egawriteplane(1);
+               /* memcpy(tmp1,cursor.plane[0].image[i],BYTES_PER_CELL); */
+               WRITE_ABSOLUTE(tmp1,cursor.plane[0].image[i][0]);
+               if (!singlebyte)
+               WRITE_ABSOLUTE(tmp2,cursor.plane[0].image[i][1]);
+           }
+           egawriteplane(15);
+#ifdef POSITIONBAR
+           if (inmap) positionbar();
+#endif
+}
+
+void
+vga_HideCursor()
+{
+
+       int i,pixx,pixy,x,y;
+       char __far *tmp1;
+       char __far *tmp2;
+#ifdef REINCARNATION
+       boolean isrogue = Is_rogue_level(&u.uz);
+       boolean singlebyte = (isrogue || iflags.over_view
+                             || iflags.traditional_view || !inmap);
+#else
+       boolean singlebyte = (iflags.over_view
+                             || iflags.traditional_view || !inmap);
+#endif
+       int curtyp;
+       
+       if (inmap && !cursor_type) return;      /* CURSOR_INVIS - nothing to do */
+       /* protection from callers */
+       x = min(curcol,(CO - 1)); 
+       y = min(currow,(LI-1));
+       if (!singlebyte && ((x < clipx) || (x > clipxmax))) return;
+
+           pixy = row2y(y);            /* convert to pixels */
+           if (singlebyte)
+                   pixx = x;
+           else
+                   pixx = col2x((x-clipx));
+
+           if (inmap) curtyp = cursor_type;
+           else curtyp = CURSOR_UNDERLINE;
+
+           if (curtyp == CURSOR_UNDERLINE)  /* optimization for uline */
+               i = ROWS_PER_CELL - 1;
+           else
+               i = 0;
+
+           for(;i < ROWS_PER_CELL; ++i) {
+               tmp1 = screentable[i+pixy];
+               tmp1 += pixx;
+               tmp2 = tmp1 + 1;
+               egawriteplane(8);
+               /* memcpy(tmp,undercursor.plane[3].image[i],BYTES_PER_CELL); */
+               WRITE_ABSOLUTE(tmp1,undercursor.plane[3].image[i][0]);
+               if (!singlebyte)
+               WRITE_ABSOLUTE(tmp2,undercursor.plane[3].image[i][1]);
+
+               egawriteplane(4);
+               /* memcpy(tmp,undercursor.plane[2].image[i],BYTES_PER_CELL); */
+               WRITE_ABSOLUTE(tmp1,undercursor.plane[2].image[i][0]);
+               if (!singlebyte)
+               WRITE_ABSOLUTE(tmp2,undercursor.plane[2].image[i][1]);
+
+               egawriteplane(2);
+               /* memcpy(tmp,undercursor.plane[1].image[i],BYTES_PER_CELL); */
+               WRITE_ABSOLUTE(tmp1,undercursor.plane[1].image[i][0]);
+               if (!singlebyte)
+               WRITE_ABSOLUTE(tmp2,undercursor.plane[1].image[i][1]);
+
+               egawriteplane(1);
+               /* memcpy(tmp,undercursor.plane[0].image[i],BYTES_PER_CELL); */
+               WRITE_ABSOLUTE(tmp1,undercursor.plane[0].image[i][0]);
+               if (!singlebyte)
+               WRITE_ABSOLUTE(tmp2,undercursor.plane[0].image[i][1]);
+           }
+           egawriteplane(15);
+}
+#  endif /* SIMULATE_CURSOR */
+# endif /* OVLB */
+#endif /* SCREEN_VGA  */
+
+/* vidvga.c */
diff --git a/sys/os2/Install.os2 b/sys/os2/Install.os2
new file mode 100644 (file)
index 0000000..aafd0fa
--- /dev/null
@@ -0,0 +1,276 @@
+             Instructions for compiling and installing NetHack 3.4
+                               on an OS/2 system
+             =====================================================
+                                Timo Hakulinen
+                        Last revision: 29 October 1996
+
+0.  Read this entire file before starting, and come back to the Notes below if
+    you have any problems.
+
+1.  Make sure all the NetHack files are in the appropriate directory
+    structure.  You should have a top directory (e.g. nh33, or whatever you
+    like) with subdirectories dat, doc, include, src, util, sys\share,
+    sys\os2, and win\tty.  You may have other subdirectories under sys and
+    win, but they will not affect compilation for an OS/2 system.  If you do
+    not follow this structure, the makefile will not function properly.  The
+    .c files for the main program belong in src, those for utility programs in
+    util, and OS/2-specific ones in sys\os2.  All the .h files belong in
+    include, the documentation in doc, and assorted data files in dat.  There
+    are also some necessary files in sys\share (pc*.c, random.c, dgn_*.*,
+    lev_*.*).  A more detailed explanation of the directory structure is found
+    in file Files, which should be in the top directory.
+
+    If you downloaded or ftp'd the sources from a UNIX system, the lines may
+    end in UNIX-style newlines instead of the carriage return and line feed
+    pairs used by DOS and OS/2.  You'll have to convert them (with a utility
+    like Rahul Dhesi's "flip").  Also, every file should end with a carriage
+    return / line feed pair, because Microsoft C has had a habit of ignoring
+    the last line of each file otherwise.  Besides, even editing UNIX-style
+    files with DOS editors is often a royal pain.
+
+2.  The makefile for OS/2, Makefile.os2, is found in directory sys\os2.  Copy
+    it to directory src and rename it Makefile.  From now on, Makefile.os2
+    will be referred to as "the makefile" in this document.
+
+    The makefile supports the following make utilities:
+
+    NDMAKE      a public domain make utility for DOS by Don Kneller
+    NMAKE       make shipped with Microsoft languages and IBM C Set/2
+    DMAKE       a public domain make for DOS and OS/2 by Dennis Vadura
+
+    Both NDMAKE and DMAKE are available at major archive sites.  The
+    following compilers are supported:
+
+    compiler:                           runs in:            compiles for:
+
+    Microsoft C 5.1                     DOS / OS/2 1.0-Warp OS/2 1.x
+    Microsoft 6.0A (see note 5)         - " -               - " -
+    IBM C Set/2 1.00, Toolkit/2 2.00    OS/2 2.x, Warp      OS/2 2.x, Warp
+    IBM CSet++ 2.00                     OS/2 2.x, Warp      OS/2 2.x, Warp
+    GCC emx 0.8f (see note 6)           OS/2 2.x, Warp      OS/2 2.x, Warp
+
+    Note that code compiled for OS/2 versions 1.0-1.3 runs unmodified in OS/2
+    versions 2.0 and up.  In principle it should be possible to cross compile
+    NetHack 3.4 for OS/2 in DOS using NDMAKE and MSC, but this is not
+    recommended (see note 3).
+
+    If you're using some other compiler than one listed above, you will have
+    to adapt the makefile to your needs.  In particular, change the CC,
+    CFLAGS, LINK, and LFLAGS macros to your C compiler's and linker's liking.
+    See the makefile for more information.
+
+    If you are going to be constructing Fred Fish's termcap library, you'll
+    need Makefile.lib in sys\share (see note 4).
+
+3.  Go to the include subdirectory.  First edit config.h according to the
+    comments to match your system and desired set of features.  In particular,
+    make sure that OS2 is defined, and that UNIX, HACKDIR, and COMPRESS are
+    *not* defined.  If you want to try out the new DLB data file library
+    scheme, uncomment DLB.  Note that although the makefile contains some
+    support for this scheme, it's new in NetHack 3.3 and hasn't been tested.
+    If your compiler is ANSI compliant (like practically all OS/2 compilers
+    are), it's probable that nothing else needs to be configured in config.h.
+
+    Next look at os2conf.h.  This file shouldn't need much changing.  If you
+    want to use the hardcoded OS/2 system definitions in def_os2.h instead of
+    the compiler's standard headers, comment out OS2_USESYSHEADERS.  This may
+    become necessary if you are using a compiler which doesn't come with
+    proper system headers by default.  In this case you may have to edit the
+    definitions there, because every compiler has its own way of declaring
+    the necessary system functions and data structures.  In general you
+    should prefer the compiler's offerings, if possible.
+
+    If you are going to compile the game on an HPFS drive, uncomment OS2_HPFS,
+    which enables the use of longer file names during compilation.  The
+    generated executable will only use file names compatible with FAT drives,
+    however.
+
+    If you are using a 32 bit compiler other than GCC emx 0.8f or C Set/2 in
+    OS/2 2.x, force OS2_32BITAPI to be defined.  Otherwise it is defined only
+    for the above mentioned compilers.
+
+    If you are not going to include random.c, because you are using the
+    random number generator provided by your compiler, you will need to
+    comment out RANDOM.
+
+    If you want to muck with different termcap settings, uncomment TERMLIB to
+    enable the use of termcap routines (see note 4).  This is not necessary to
+    create a fully functional game, however.
+
+4.  If you are using another compiler than MSC, GCC, or IBM C Set/2, you may
+    want to look through system.h in the include directory.  This file matches
+    the return and parameter types for system calls and library routines with
+    various flavors of compilers and operating systems.  Leaving this file
+    alone is unlikely to cause problems, but if you get compile errors with
+    any functions in the standard library, it's worth checking the
+    declarations there.
+
+5.  If you want to change the high score list behavior, examine the top of
+    topten.c, in the src directory.  You may want to change the definitions of
+    PERSMAX, POINTSMIN, and ENTRYMAX.
+
+6.  Go to the src directory and edit the top of the makefile.  Be sure that
+    the directory you want the game installed to actually exists.
+
+    You'll need nroff and/or TeX/LaTeX to do the files in doc.  If you don't
+    have either of these, you can skip it.
+
+    If you elected not to use the high quality BSD random number routines by
+    commenting out RANDOM in os2conf.h, comment out (or set equal to nothing)
+    the RANDOM macro in the makefile.
+
+    If you elected to use Fred Fish's termcap library (bundled in as
+    termcap.uu in directory sys\share), you will have to generate termlib.lib
+    from those sources by typing "make -f makefile.lib termlib.lib".  You must
+    set the TERMLIB option in the makefile to link the resulting termlib.lib
+    into the game.
+
+    If you are recompiling after patching your sources, or if you got your
+    files from somewhere other than the official distribution, "touch
+    makedefs.c" to ensure that certain files (onames.h and pm.h) are remade,
+    lest potentially troublesome time stamps fool make.
+
+    If you have lex and yacc programs, or the equivalent flex and bison
+    programs, you can set up the makefile to generate the appropriate .h and
+    .c files from their .l and .y counterparts whenever you recompile.  This
+    is done by changing the do_yacc and do_lex targets in the makefile to
+    depend on targets yacc_act and lex_act instead of yacc_cpy and lex_cpy.
+    Otherwise the makefile will copy pre-generated yacc and lex output files
+    dgn_*.* and lev_*.* from directory sys\share to util and include.
+
+    Now, enter "make all", and take a siesta; your computer will be occupied
+    for a fair amount of time.  If all goes well, you will get an executable.
+
+7.  All the support data files should have been copied to the game directory
+    by the make process.  Here is the complete list in alphabetical order of
+    all the files that should have gotten there during a full build:
+
+    Arc-fila.lev   Arc-filb.lev   Arc-goal.lev   Arc-loca.lev   Arc-strt.lev
+    Bar-fila.lev   Bar-filb.lev   Bar-goal.lev   Bar-loca.lev   Bar-strt.lev
+    Cav-fila.lev   Cav-filb.lev   Cav-goal.lev   Cav-loca.lev   Cav-strt.lev
+    Hea-fila.lev   Hea-filb.lev   Hea-goal.lev   Hea-loca.lev   Hea-strt.lev
+    Kni-fila.lev   Kni-filb.lev   Kni-goal.lev   Kni-loca.lev   Kni-strt.lev
+    Mon-fila.lev   Mon-filb.lev   Mon-goal.lev   Mon-loca.lev   Mon-strt.lev
+    Pri-fila.lev   Pri-filb.lev   Pri-goal.lev   Pri-loca.lev   Pri-strt.lev
+    Ran-fila.lev   Ran-filb.lev   Ran-goal.lev   Ran-loca.lev   Ran-strt.lev
+    Rog-fila.lev   Rog-filb.lev   Rog-goal.lev   Rog-loca.lev   Rog-strt.lev
+    Sam-fila.lev   Sam-filb.lev   Sam-goal.lev   Sam-loca.lev   Sam-strt.lev
+    Tou-fila.lev   Tou-filb.lev   Tou-goal.lev   Tou-loca.lev   Tou-strt.lev
+    Val-fila.lev   Val-filb.lev   Val-goal.lev   Val-loca.lev   Val-strt.lev
+    Wiz-fila.lev   Wiz-filb.lev   Wiz-goal.lev   Wiz-loca.lev   Wiz-strt.lev
+    air.lev        asmodeus.lev   astral.lev     baalz.lev      bigrm-1.lev
+    bigrm-2.lev           bigrm-3.lev    bigrm-4.lev    bigrm-5.lev    castle.lev
+    cmdhelp        data           dungeon        earth.lev      fakewiz1.lev
+    fakewiz2.lev   fire.lev       help           hh             history
+    juiblex.lev    knox.lev       license        medusa-1.lev   medusa-2.lev
+    minefill.lev   minend-1.lev   minend-2.lev   minetn-1.lev   minetn-2.lev
+    nethack.cmd    nethack.cnf    nethack.exe    nethack.ico    opthelp
+    options        oracle.lev     oracles        orcus.lev      quest.dat
+    recover.exe    rumors         sanctum.lev    soko1-1.lev    soko1-2.lev
+    soko2-1.lev    soko2-2.lev    soko3-1.lev    soko3-2.lev    soko4-1.lev
+    soko4-2.lev    tower1.lev     tower2.lev     tower3.lev     valley.lev
+    water.lev      wizard1.lev    wizard2.lev    wizard3.lev    wizhelp
+
+    Yes.  It's 112 files for a full featured NetHack 3.4.  If any of the files
+    are missing, try to rerun make.  If that doesn't help, you'll have to try
+    to decipher the makefile to find out how to manually create the missing
+    files.  These kinds of troubles shouldn't happen except for two reasons:
+    You've run out of disk space while compiling or your make utility doesn't
+    understand the makefile properly for some reason.  In either case, you
+    should get some warnings from the make, though.
+
+    If you have old record, logfile, or news files in the game directory, they
+    are not overwritten.  Of course, old records from NetHack 3.1 and 3.2 are
+    not worth keeping with 3.4, since these games are really quite different.
+
+    Edit file nethack.cnf in the game directory to reflect your particular
+    setup and personal preferences, following the comments there.  More info
+    about settable options can be found in the file opthelp and the guidebook.
+
+    If you compiled in the TERMLIB feature, also move the sys\share\termcap
+    file to your game directory.
+
+8.  If you'll be running NetHack from a different subdirectory, you will want
+    to "set HACKDIR=c:\games\nh33" (or whatever directory you want to use).
+    Add it to your config.sys, if you'll be playing often.
+
+    You can also create a special NetHack entry in your Presentation Manager /
+    Workplace Shell desktop.  This will use the included NetHack icon.
+    The following is a sample program description for OS/2 1.3 desktop, but
+    it's similar for OS/2 2.0:
+
+    Program title:          NetHack 3.4
+    Path and file name:     c:\games\nh33\nethack.cmd
+    Parameters:
+    Working directory:      c:\games\nh33
+    Program type:           OS/2 Full screen
+
+    Naturally you must fill in your own game directory and parameters if you
+    want to set any.  The program type can be either OS/2 Full screen or OS/2
+    Windowed.  Note that you should set the executable path to use the .cmd
+    file generated by the makefile.  This file generates an extra pause after
+    the program exit, because otherwise you wouldn't get to see the high score
+    list upon quitting due to PM/WPS automatically closing the program window.
+    When starting NetHack normally from OS/2 command prompt, the command
+    processor starts nethack.exe instead, so no extra pause is generated.
+
+9.  If you want to clear up the temporary files and objects created by the
+    compilation process, you may issue "make spotless".  This will return your
+    source tree to near-distribution condition.  Naturally, it will not affect
+    your newly built game files in any way.
+
+10. Play NetHack.  If it works, you're done!
+
+
+Notes
+-----
+
+1)  Save-files and bones-files from previous versions will not work with
+    NetHack 3.4.  Don't bother trying to keep them.
+
+2)  To install an update of NetHack after changing something, enter "make"
+    from the src directory.  If you add, delete, or reorder monsters or
+    objects, or you change the format of saved level files, delete any save
+    and bones files.  (Trying to use such files sometimes produces amusing
+    confusions on the game's part, but usually crashes.)
+
+3)  When cross-compiling for OS/2 in DOS, NDMAKE is the best choice because it
+    requires the least RAM for itself.  Note however, that cross-compilation
+    in DOS is discouraged, because it is considered obsolete (OS/2 is really
+    a much better place to compile).  If you still want to try, here are some
+    suggestions:
+
+    During linking, Microsoft linker will need temporary storage space.  Make
+    sure you have about 1 MB of free disk where ever you have defined your
+    temporary storage.  It is also a good idea to compile with as much free
+    RAM as possible.  It may otherwise get crowded with the bigger, more
+    complex source files (compiler bombs with "out of heap space" or similar).
+    If this happens, strip your configuration, zap TSR's, get a better memory
+    manager etc.
+
+4)  The file sys\share\termcap.uu is the fixed version of the Fred Fish
+    termcap library.  You will need to run a uudecode utility on it to
+    generate the file termcap.zip.  termcap.zip contains several files of
+    termcap routines.  Using them with NetHack involves very little knowledge
+    of the UNIX concept of a termcap database; mostly you need to know enough
+    to set a TERM environment variable.  You can unzip termcap.zip in the
+    sys\share directory, but if you are going to use it, it is probably best
+    to unzip a copy in the src directory.  That way you will not miss copying
+    any files over.  Wherever you unzip it, get rid of the included makefile
+    since a better version has been provided as Makefile.lib.  After creating
+    the termcap library file termlib.lib, copy it to src before compiling the
+    game main source.
+
+5)  When compiling with MSC 6.0, the maintenance version 6.0A should be used
+    instead of the original 6.0, which was all too buggy to successfully build
+    NetHack.
+
+6)  Note that emx 0.8f is the first version of GCC for OS/2 that can properly
+    compile NetHack.  Earlier versions do not work, because they don't support
+    the 16 bit API calls of OS/2.
+
+    GCC emx 0.8f does not currently work properly when fseek() function is
+    used with text files.  This is well documented in the compiler's
+    documentation.  Unfortunately NetHack uses fseek() in several places in
+    connection with text data.  This means that some help texts may not come
+    out right, but no serious problems should emerge.
diff --git a/sys/os2/Makefile.os2 b/sys/os2/Makefile.os2
new file mode 100644 (file)
index 0000000..f6abd8a
--- /dev/null
@@ -0,0 +1,1782 @@
+#      SCCS Id: @(#)Makefile.os2       3.4.3   1996/10/29
+#      OS/2 NetHack 3.4.3 Makefile for OS/2 versions 2.x
+#      Copyright (C) 1990, 1991, 1992, 1993, 1996 Timo Hakulinen
+#
+#      Several compilers exist for OS/2 but, currently only GCC emx is tested
+#      and used for releases.  make programs other than dmake are not tested.
+#
+#      Supported compilers: GCC emx 0.9g
+#
+#      DMAKE is required.  Credit for the makefile improvements goes to 
+#      Pekka Rousu.
+#
+#      Copy this file into $(SRC) directory, rename it to "makefile"
+#      (important, many targets rely on it), compile and link inside
+#      $(SRC).  If required, termcap library can be built from termcap
+#      sources using makefile.lib in "sys\share" directory.
+#
+#      "GCC" refers to GCC emx only.  No other ports of GCC are supported.
+#      Additional credits for honing GCC support for 3.2 go to Ronald
+#      Van Iwaarden (ron@vaniwaarden.org) and Stefan Neis (neis@cs.uni-sb.de).
+#
+#      "OMF" is short for "Object Module Format" and refers to the
+#      standard OS/2 object format, which e.g. link386 uses.  MSC and
+#      CSet/2 always produce OMF object files, and GCC can be instructed
+#      to produce them with proper switches (see below).
+#
+#      "a.out" refers to Unix object file format, which is used by GCC
+#      in its default compilation mode.  These object files must be
+#      linked using GCC's own linker to produce a proper OS/2 executable.
+#      GDB debugger shipped with GCC can only be used with a.out object
+#      format.
+#
+#      Note that the default setup in this makefile is my personal setup,
+#      which you will have to adapt to your configuration.
+#
+
+#
+#      Compiler and linker selection.
+#
+
+#format        = omf
+format = a.out
+
+.IF $(format) == a.out
+with_x11 = yes
+#debug = yes
+.END
+
+
+CC     = gcc           # GCC
+
+.IF $(format) == a.out
+LINK    = gcc
+#LINK  = link386       # GCC OMF, CSet/2
+.ELSE
+LINK   = link386       # GCC OMF, CSet/2
+LFLAGS = /noig /stack:40000
+.END
+
+.IF $(with_x11) == yes
+WINX11OBJ01 = $(OBJ)/Window.o
+WINX11OBJ02 = $(OBJ)/dialogs.o
+WINX11OBJ03 = $(OBJ)/winX.o
+WINX11OBJ04 = $(OBJ)/winmap.o
+WINX11OBJ05 = $(OBJ)/winmenu.o
+WINX11OBJ06 = $(OBJ)/winmesg.o
+WINX11OBJ07 = $(OBJ)/winmisc.o
+WINX11OBJ08 = $(OBJ)/winstat.o
+WINX11OBJ09 = $(OBJ)/wintext.o
+WINX11OBJ10 = $(OBJ)/winval.o
+WINX11OBJ11 = $(OBJ)/tile.o
+X11ROOT = e:/xfree86
+WINX11CFLAGS = -DUSE_XPM -DX11_GRAPHICS \
+            -I$(X11ROOT)/include -Zmtd
+WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11 -lXpm -L$(X11ROOT)/lib -lc_app
+WINX11SRC = ../win/X11/Window.c ../win/X11/dialogs.c ../win/X11/winX.c \
+       ../win/X11/winmap.c  ../win/X11/winmenu.c ../win/X11/winmesg.c \
+       ../win/X11/winmisc.c ../win/X11/winstat.c ../win/X11/wintext.c \
+       ../win/X11/winval.c tile.c
+WINX11OBJ = $(WINX11OBJ01) $(WINX11OBJ02) $(WINX11OBJ03) $(WINX11OBJ04) \
+       $(WINX11OBJ05) $(WINX11OBJ06) $(WINX11OBJ07) $(WINX11OBJ08) \
+       $(WINX11OBJ09) $(WINX11OBJ10) $(WINX11OBJ11)
+WINX11VARDAT=x11tiles pet_mark.xbm rip.xpm
+X11ECHO        = $(CMD) @echo
+.END
+
+
+
+
+MAKEB  = dmake
+CMD    = cmd /C
+AB     = $(@:B).c
+CB     = $$(@:B).c
+BEG    = $(CMD) "
+END    = "
+SEP    = &
+P      = %
+
+#
+#      Most makes execute actions automatically inside a subshell,
+#      which makes even the shell internals work ok.
+#
+
+ECHO   = $(CMD) @echo
+RM     = $(CMD) del
+CP     = $(CMD) copy
+CAT    = $(CMD) type
+
+#
+#      For those of us who have these on PC.
+#
+
+#YACC  = yacc
+#LEX   = lex
+YACC   = bison -y
+LEX    = flex
+
+#
+#      For extracting NetHack icon.
+#
+
+UUDECODE = uudecode
+
+#
+#      For people with TeX and LaTeX.
+#
+
+LATEX  = latex
+
+#
+#      If you have TOUCH, some things become slightly easier.
+#
+
+TOUCH  = touch
+
+#
+#      Standard file naming for LEX and YACC output may vary in PC
+#      installations.  These three are probably the most generally used
+#      names.
+#
+
+YTABC  = y_tab.c
+YTABH  = y_tab.h
+LEXYYC = lexyy.c
+
+#
+#      Source tree base directory.
+#
+
+NHSRC  = \nethack
+
+#
+#      Source directories.  Makedefs hardcodes these, don't change them.
+#
+
+INCL   = $(NHSRC)\include      # NetHack include files
+DAT    = $(NHSRC)\dat          # NetHack data files
+DOC    = $(NHSRC)\doc          # NetHack documentation files
+UTIL   = $(NHSRC)\util         # Utility source
+SRC    = $(NHSRC)\src          # Main source
+WIN    = $(NHSRC)\win\tty      # Window system specific source
+WINX11 = $(NHSRC)\win\x11      # Window system specific source
+SYS    = $(NHSRC)\sys\os2      # System specific source
+SSYS   = $(NHSRC)\sys\share    # Shared system files
+WINSHARE= $(NHSRC)\win\share   # Shared system files
+
+#
+#      Modifiable directories.  Set these according to your setup and
+#      preferences.  They must all be present prior to compilation.
+#      OBJ, TEMP and GAMEDIR should all preferably be separate and,
+#      in particular, not the same as any of the source directories.
+#      Note that DMAKE may dislike drive designators in paths because
+#      it misinterprets the colon as being part of a make rule.  In that
+#      case, all directories have to reside on the same drive.
+#
+
+OBJ    = \tmp\obj              # Object files
+TEMP   = \tmp\bin              # Temporary files during make process
+GAMEDIR = \games\nh343x11      # Game directory
+PLIBP  = c:\emx\lib            # Protected mode C libraries
+RLIBP  = c:\emx\lib            # Possible real mode C libraries
+
+#
+#      The game name and description.
+#
+
+GAME   = nethack
+GAMEDES = "NetHack 3.4.3"
+
+#
+#      The uppermost two lines for MSC, the middle two for GCC, and
+#      the lowermost two for CSet/2.
+#
+#      GCC: compile only, compiler id, object format selection, warnings,
+#      include file path, debug flags, ANSI conformance.
+#
+
+CFLAGS = -c $(GCCO) $(WARN) -I$(INCL) $(CDFLAGS) $(STDC) $(WINX11CFLAGS)
+#OPT   = -s -O -o
+OPT    = -o
+
+#
+#      Compiler warning levels.  These are really for development, so
+#      they are commented out in general distribution to save the user
+#      from masses of benign warnings.  If any problems arise, however,
+#      they may help in finding the trouble.
+#
+#      GCC: max. reasonable GCC warning levels.  Can't use -Wall, because then
+#      it would whine about all the zillions of unused declarations etc.
+#      Even with these switches you'll get a lot of warnings, but they should
+#      all be benign.
+#
+
+WARN   = #-W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN # GCC
+
+#
+#      GCC object format selection.  The upper line for standard OS/2 OMF
+#      object format, the lower for Unix style a.out format.
+#
+
+.IF $(format) == omf
+GCCO   = -Zomf -Zsys
+.ELSE
+GCCO   =
+.END
+
+#
+#      MSC 5.1 needs the large model first pass of the compiler.
+#      Not needed for later versions.
+#
+
+BIGC   =
+
+#
+#      Unset CL to avoid troubles with conflicting switches in MSC 6.0.
+#
+
+CL     =
+
+#
+#      Prepare for a debugger.
+#
+
+.IF $(debug) == yes
+CDFLAGS =
+LDFLAGS =
+.ELSE
+CDFLAGS = -O -s
+LDFLAGS = -s
+.END
+
+#
+#      How to produce the most ANSI-like environment.
+#
+
+STDC   = -ansi         # GCC
+
+#
+#      Possible system object files required during linking.
+#
+
+.IF $(format) == omf
+SYSOBJ = $(PLIBP)\crt0.obj     $(PLIBP)\end.lib# GCC OMF
+.ELSE
+SYSOBJ =                       # MSC, GCC a.out, CSet/2
+.END
+
+#
+#      Compiler library selection.  Change if necessary.
+#
+#      GCC emx 0.9 OMF: C single-threaded libs, Unix system call alias lib,
+#      extra GCC lib, single threaded system lib, OS/2 API entry points.
+#      Note that emx changed library naming convention between 0.8 and 0.9.
+#
+#      GCC a.out: extra GCC lib, C standard lib, extra GCC lib (again),
+#      OS/2 API entry points.
+#
+
+.IF $(format) == omf
+PLIBS  = $(PLIBP)\st\c $(PLIBP)\st\c_app $(PLIBP)\c_alias $(PLIBP)\gcc $(PLIBP)\st\sys $(PLIBP)\os2    # GCC emx 0.9 OMF
+.ELSE
+PLIBS  = -lgcc -lc -lgcc -los2 $(X11LIBS)      # GCC a.out
+.END
+
+#
+#      C libraries used by makedefs, lev_comp and dgn_comp (change if
+#      necessary).  If compilation is done in DOS, enable the upper line
+#      possibly setting the library name to something else, if in OS/2,
+#      enable the lower line (protected mode libraries).
+#
+
+#RLIBS = $(RLIBP)\llibcer
+RLIBS  = $(PLIBS)
+
+SRCCC  = $(CC) $(CFLAGS) $(OPT) $@ $(AB)
+UTILCC = $(BEG) cd $(UTIL) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ $(AB) $(END)
+SYSCC  = $(BEG) cd $(SYS) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ $(AB) $(END)
+SSYSCC = $(BEG) cd $(SSYS) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ $(AB) $(END)
+PSYSCC = $(BEG) cd $(SSYS) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ pc$(AB) $(END)
+WINCC  = $(BEG) cd $(WIN) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ $(AB) $(END)
+
+#
+#      Default linker skeletons.  The upper six lines for everything
+#      that uses standard OS/2 object format (GCC OMF),  The lower six
+#      for GCC a.out format.
+#
+
+.IF $(format) == omf
+GAMELN = $(LINK) @$(TEMP)\$(GAME).rsp
+MKDFLN = $(LINK) @$(TEMP)\makedefs.rsp
+LEVCLN = $(LINK) @$(TEMP)\lev_comp.rsp
+DGNCLN = $(LINK) @$(TEMP)\dgn_comp.rsp
+RCVRLN = $(LINK) @$(TEMP)\recover.rsp
+DLBRLN = $(LINK) @$(TEMP)\dlb.rsp
+.ELSE
+GAMELN = $(CC) $(LDFLAGS) -o $(GAMEDIR)\$(GAME).exe @$(TEMP)\$(GAME).r $(PLIBS) $(WINX11CFLAGS) $(WINX11LIB)
+MKDFLN = $(CC) $(LDFLAGS) -o $(TEMP)\makedefs.exe $(TEMP)\$(MKDFDEF) $(SYSOBJ) $(MAKEOBJS) $(PLIBS)
+LEVCLN = $(CC) $(LDFLAGS) -o $(TEMP)\lev_comp.exe $(TEMP)\$(LEVCDEF) $(SYSOBJ) $(SPLEVOBJS) $(PLIBS)
+DGNCLN = $(CC) $(LDFLAGS) -o $(TEMP)\dgn_comp.exe $(TEMP)\$(DGNCDEF) $(SYSOBJ) $(DGNCOMPOBJS) $(PLIBS)
+RCVRLN = $(CC) $(LDFLAGS) -o $(GAMEDIR)\recover.exe $(TEMP)\$(RCVRDEF) $(SYSOBJ) $(RECOVOBJS) $(PLIBS)
+ DLBRLN = $(CC) $(LDFLAGS) -o $(TEMP)\dlb.exe $(TEMP)\$(DLBDEF) $(SYSOBJ) $(DLBOBJS) $(PLIBS)
+.END
+
+#
+#      OS/2 module definition files for NetHack,
+#      makedefs, dgn_comp, lev_comp, recover, dlb.
+#
+
+GAMEDEF        = $(GAME).def
+MKDFDEF        = makedefs.def
+LEVCDEF        = lev_comp.def
+DGNCDEF        = dgn_comp.def
+RCVRDEF        = recover.def
+DLBDEF = dlb.def
+
+#
+#      For compilation in DOS, enable the lower three lines and
+#      disable the upper three.
+#
+
+MKDFMD = $(TEMP)\$(MKDFDEF)
+LEVCMD = $(TEMP)\$(LEVCDEF)
+DGNCMD = $(TEMP)\$(DGNCDEF)
+#MKDFMD        =
+#LEVCMD        =
+#DGNCMD        =
+
+#
+#      Optional high-quality BSD random number generation routines
+#      (see os2conf.h).  Set to nothing if not used.
+#
+
+RANDOM = $(OBJ)\random.o
+#RANDOM        =
+
+#
+#      If TERMLIB is defined in os2conf.h, comment out the upper line and
+#      uncomment the lower.  If the termcap-library doesn't exist, use
+#      sys\share\makefile.lib to build it.
+#
+
+TERMLIB =
+#TERMLIB = termlib.lib
+
+#
+#      Short / long file name selection for FAT and HPFS.
+#      Only three files need consideration.
+#
+
+#GUIDEBOO = Guideboo   # FAT
+#PATCHLEV = patchlev   # - " -
+#DATABASE = data.bas   # - " -
+GUIDEBOO = Guidebook   # HPFS
+PATCHLEV = patchlevel  # - " -
+DATABASE = data.base   # - " -
+
+
+#
+#      If you have LaTeX and want to create the NetHack Guidebook in TeX
+#      device-independent file format, comment out the upper line and
+#      uncomment the lower.
+#
+
+GUIDE  =
+#GUIDE = $(TEMP)\$(GUIDEBOO).dvi
+
+#
+#      Set WINOBJ lines corresponding to your desired combination
+#      of windowing systems.  Also set windowing systems in config.h.
+#
+#      A straight tty port using no native windowing system is the
+#      only choice for now.
+#
+
+WINOBJ1 = $(OBJ)\getline.o
+WINOBJ2 = $(OBJ)\termcap.o
+WINOBJ3 = $(OBJ)\topl.o
+WINOBJ4 = $(OBJ)\wintty.o
+WINOBJ = $(WINOBJ1) $(WINOBJ2) $(WINOBJ3) $(WINOBJ4) $(WINX11OBJ)
+
+#
+#      The default make target, so just typing 'make' is useful.
+#      Has to be the first target in the makefile.
+#
+
+default : all
+
+#
+#      If you have yacc and lex programs and make any changes, uncomment
+#      the lowermost two lines and comment out the others.  If you make
+#      changes to the .y and .l files but prefer processing the files
+#      separately elsewhere, activate the middle two lines, so your changes
+#      don't get overwritten.
+#
+
+do_yacc : yacc_cpy     # use pre-generated files
+do_lex :  lex_cpy      #       - " -
+#do_yacc : yacc_msg    # show message if changed
+#do_lex :  lex_msg     #       - " -
+#do_yacc : yacc_act    # re-process files
+#do_lex :  lex_act     #       - " -
+
+#
+#      If you have the TOUCH utility the upper line is ok.  Otherwise
+#      the lower one does the same albeit in an ugly manner.  Besides,
+#      the latter method only works for text files.
+#
+
+#do_touch : realtouch
+do_touch : faketouch
+
+#
+#      If you don't have uudecode program, use the upper line.
+#      If you still want the icon, you'll have to extract the
+#      file manually somewhere else.
+#
+
+do_icon : icon_msg     # show message if changed
+#do_icon : icon_act    # extract icon file
+
+#
+#      If you don't want to generate nethack.cmd, use the upper line.
+#      This could be the case, e.g., if you use a different shell than
+#      the standard cmd.exe.
+#
+
+#do_cmd : cmd_msg      # show message
+do_cmd : cmd_act       # generate nethack.cmd
+
+#
+#      If you want to try the data librarian scheme to reduce
+#      the amount of data files in the NetHack home directory, comment
+#      out the lower line and uncomment the upper.  Also, make sure
+#      that DLB is defined in config.h.
+#
+
+do_dlb : dlb_yup
+#do_dlb : dlb_nope
+
+######################################################################
+#
+#      Nothing below this line should have to be changed.
+#
+#      Other things that have to be reconfigured are in
+#      config.h, os2conf.h and possibly system.h.
+#
+
+#
+#      The game filename.
+#
+
+GAMEFILE = $(GAMEDIR)\$(GAME).exe
+
+#
+#      Object files for makedefs.
+#
+
+MAKEOBJS = $(OBJ)\makedefs.o $(OBJ)\monst.o $(OBJ)\objects.o
+
+#
+#      Object files for special levels compiler.
+#
+
+SOBJ01 = $(OBJ)\lev_yacc.o $(OBJ)\lev_lex.o $(OBJ)\lev_main.o $(OBJ)\alloc.o
+SOBJ02 = $(OBJ)\monst.o $(OBJ)\objects.o $(OBJ)\panic.o $(OBJ)\decl.o
+SOBJ03 = $(OBJ)\drawing.o
+
+SPLEVOBJS = $(SOBJ01) $(SOBJ02) $(SOBJ03)
+
+#
+#      Object files for dungeon compiler.
+#
+
+DOBJ01 = $(OBJ)\dgn_yacc.o $(OBJ)\dgn_lex.o $(OBJ)\dgn_main.o
+DOBJ02 = $(OBJ)\panic.o $(OBJ)\alloc.o
+
+DGNCOMPOBJS = $(DOBJ01) $(DOBJ02)
+
+#
+#      Object files for recovery utility.
+#
+
+RECOVOBJS = $(OBJ)\recover.o
+
+#
+#      Object files for dlb.
+#
+
+DLBOBJS = $(OBJ)\dlb_main.o $(OBJ)\dlb.o $(OBJ)\alloc.o $(OBJ)\panic.o
+
+#
+#      Data files for dlb.
+#
+
+DATHELP = \
+ help hh cmdhelp history opthelp wizhelp
+
+SPEC_LEVS = \
+ asmodeus.lev baalz.lev    bigrm-1.lev \
+ bigrm-2.lev  bigrm-3.lev  bigrm-4.lev castle.lev   fakewiz1.lev fakewiz2.lev \
+ juiblex.lev  knox.lev     medusa-1.lev medusa-2.lev minend-1.lev minend-2.lev \
+ minend-3.lev minefill.lev minetn-1.lev minetn-2.lev minetn-3.lev minetn-4.lev \
+ minetn-5.lev minetn-6.lev minetn-7.lev oracle.lev   orcus.lev    sanctum.lev \
+ tower1.lev   tower2.lev   tower3.lev valley.lev   wizard1.lev  wizard2.lev \
+ wizard3.lev  astral.lev   air.lev earth.lev    fire.lev     water.lev \
+ soko1-1.lev  soko1-2.lev  soko2-1.lev  soko2-2.lev  \
+ soko3-1.lev  soko3-2.lev  soko4-1.lev  soko4-2.lev
+
+QUEST_LEVS = \
+ Arc-goal.lev Arc-fila.lev Arc-filb.lev Arc-loca.lev Arc-strt.lev \
+ Bar-goal.lev Bar-fila.lev Bar-filb.lev Bar-loca.lev Bar-strt.lev \
+ Cav-goal.lev Cav-fila.lev Cav-filb.lev Cav-loca.lev Cav-strt.lev \
+ Hea-goal.lev Hea-fila.lev Hea-filb.lev Hea-loca.lev Hea-strt.lev \
+ Kni-goal.lev Kni-fila.lev Kni-filb.lev Kni-loca.lev Kni-strt.lev \
+ Mon-goal.lev Mon-fila.lev Mon-filb.lev Mon-loca.lev Mon-strt.lev \
+ Pri-goal.lev Pri-fila.lev Pri-filb.lev Pri-loca.lev Pri-strt.lev \
+ Ran-goal.lev Ran-fila.lev Ran-filb.lev Ran-loca.lev Ran-strt.lev \
+ Rog-goal.lev Rog-fila.lev Rog-filb.lev Rog-loca.lev Rog-strt.lev \
+ Sam-goal.lev Sam-fila.lev Sam-filb.lev Sam-loca.lev Sam-strt.lev \
+ Tou-goal.lev Tou-fila.lev Tou-filb.lev Tou-loca.lev Tou-strt.lev \
+ Val-goal.lev Val-fila.lev Val-filb.lev Val-loca.lev Val-strt.lev \
+ Wiz-goal.lev Wiz-fila.lev Wiz-filb.lev Wiz-loca.lev Wiz-strt.lev
+VARDATD = \
+ data oracles options quest.dat rumors $(WINX11VARDAT)
+
+DATDLB = $(DATHELP) dungeon $(SPEC_LEVS) $(QUEST_LEVS) $(VARDATD) \
+        $(do_dlb)
+
+#
+#      Object files for the game itself.
+#
+
+VOBJ011 = $(OBJ)\allmain.o
+VOBJ012 = $(OBJ)\alloc.o
+VOBJ013 = $(OBJ)\apply.o
+VOBJ014 = $(OBJ)\artifact.o
+VOBJ021 = $(OBJ)\attrib.o 
+VOBJ022 = $(OBJ)\ball.o
+VOBJ023 = $(OBJ)\bones.o
+VOBJ024 = $(OBJ)\botl.o
+VOBJ031 = $(OBJ)\cmd.o
+VOBJ032 = $(OBJ)\dbridge.o
+VOBJ033 = $(OBJ)\decl.o
+VOBJ034 = $(OBJ)\detect.o
+VOBJ041 = $(OBJ)\dig.o
+VOBJ042 = $(OBJ)\display.o
+VOBJ043 = $(OBJ)\dlb.o
+VOBJ044 = $(OBJ)\do.o
+VOBJ051 = $(OBJ)\do_name.o
+VOBJ052 = $(OBJ)\do_wear.o
+VOBJ053 = $(OBJ)\dog.o
+VOBJ054 = $(OBJ)\dogmove.o
+VOBJ061 = $(OBJ)\dokick.o
+VOBJ062 = $(OBJ)\dothrow.o
+VOBJ063 = $(OBJ)\drawing.o
+VOBJ064 = $(OBJ)\dungeon.o
+VOBJ071 = $(OBJ)\eat.o
+VOBJ072 = $(OBJ)\end.o
+VOBJ073 = $(OBJ)\engrave.o
+VOBJ074 = $(OBJ)\exper.o
+VOBJ071 = $(OBJ)\eat.o
+VOBJ072 = $(OBJ)\end.o
+VOBJ073 = $(OBJ)\engrave.o
+VOBJ074 = $(OBJ)\exper.o
+VOBJ081 = $(OBJ)\explode.o
+VOBJ082 = $(OBJ)\extralev.o
+VOBJ083 = $(OBJ)\files.o
+VOBJ084 = $(OBJ)\fountain.o
+VOBJ091 = $(OBJ)\hack.o
+VOBJ092 = $(OBJ)\hacklib.o
+VOBJ093 = $(OBJ)\invent.o
+VOBJ094 = $(OBJ)\light.o
+VOBJ101 = $(OBJ)\lock.o
+VOBJ102 = $(OBJ)\mail.o
+VOBJ103 = $(OBJ)\main.o
+VOBJ104 = $(OBJ)\makemon.o
+VOBJ111 = $(OBJ)\mapglyph.o
+VOBJ112 = $(OBJ)\mcastu.o
+VOBJ113 = $(OBJ)\mhitm.o
+VOBJ114 = $(OBJ)\mhitu.o
+VOBJ115 = $(OBJ)\minion.o
+VOBJ121 = $(OBJ)\mklev.o
+VOBJ122 = $(OBJ)\mkmap.o
+VOBJ123 = $(OBJ)\mkmaze.o
+VOBJ124 = $(OBJ)\mkobj.o
+VOBJ131 = $(OBJ)\mkroom.o
+VOBJ132 = $(OBJ)\mon.o
+VOBJ133 = $(OBJ)\mondata.o
+VOBJ134 = $(OBJ)\monmove.o
+VOBJ141 = $(OBJ)\monst.o
+VOBJ142 = $(OBJ)\monstr.o
+VOBJ143 = $(OBJ)\mplayer.o
+VOBJ144 = $(OBJ)\mthrowu.o
+VOBJ151 = $(OBJ)\muse.o
+VOBJ152 = $(OBJ)\music.o
+VOBJ153 = $(OBJ)\o_init.o
+VOBJ154 = $(OBJ)\objects.o
+VOBJ161 = $(OBJ)\objnam.o
+VOBJ162 = $(OBJ)\options.o
+VOBJ163 = $(OBJ)\os2.o
+VOBJ164 = $(OBJ)\pager.o
+VOBJ171 = $(OBJ)\pcsys.o
+VOBJ172 = $(OBJ)\pickup.o
+VOBJ173 = $(OBJ)\pline.o
+VOBJ174 = $(OBJ)\polyself.o
+VOBJ181 = $(OBJ)\potion.o
+VOBJ182 = $(OBJ)\pray.o
+VOBJ183 = $(OBJ)\priest.o
+VOBJ184 = $(OBJ)\quest.o
+VOBJ191 = $(OBJ)\questpgr.o
+VOBJ192 = $(OBJ)\read.o
+VOBJ193 = $(OBJ)\rect.o
+VOBJ194 = $(OBJ)\region.o
+VOBJ195 = $(OBJ)\restore.o
+VOBJ201 = $(OBJ)\rip.o
+VOBJ202 = $(OBJ)\rnd.o
+VOBJ203 = $(OBJ)\rumors.o
+VOBJ204 = $(OBJ)\save.o
+VOBJ211 = $(OBJ)\shk.o
+VOBJ212 = $(OBJ)\shknam.o
+VOBJ213 = $(OBJ)\sit.o
+VOBJ214 = $(OBJ)\sounds.o
+VOBJ221 = $(OBJ)\sp_lev.o
+VOBJ222 = $(OBJ)\spell.o
+VOBJ223 = $(OBJ)\steal.o
+VOBJ224 = $(OBJ)\teleport.o
+VOBJ231 = $(OBJ)\timeout.o
+VOBJ232 = $(OBJ)\topten.o
+VOBJ233 = $(OBJ)\track.o
+VOBJ234 = $(OBJ)\trap.o
+VOBJ241 = $(OBJ)\tty.o
+VOBJ242 = $(OBJ)\u_init.o
+VOBJ243 = $(OBJ)\uhitm.o
+VOBJ244 = $(OBJ)\unix.o
+VOBJ251 = $(OBJ)\vault.o
+VOBJ252 = $(OBJ)\vision.o
+VOBJ253 = $(OBJ)\vis_tab.o
+VOBJ254 = $(OBJ)\weapon.o
+VOBJ261 = $(OBJ)\were.o
+VOBJ262 = $(OBJ)\wield.o
+VOBJ263 = $(OBJ)\windows.o
+VOBJ264 = $(OBJ)\wizard.o
+VOBJ271 = $(OBJ)\worm.o
+VOBJ272 = $(OBJ)\worn.o
+VOBJ273 = $(OBJ)\write.o
+VOBJ274 = $(OBJ)\zap.o
+VOBJ281 = $(OBJ)\role.o
+VOBJ282 = $(OBJ)\steed.o
+
+VOBJ01 = $(VOBJ011) $(VOBJ012) $(VOBJ013) $(VOBJ014)
+VOBJ02 = $(VOBJ021) $(VOBJ022) $(VOBJ023) $(VOBJ024)
+VOBJ03 = $(VOBJ031) $(VOBJ032) $(VOBJ033) $(VOBJ034)
+VOBJ04 = $(VOBJ041) $(VOBJ042) $(VOBJ043) $(VOBJ044)
+VOBJ05 = $(VOBJ051) $(VOBJ052) $(VOBJ053) $(VOBJ054)
+VOBJ06 = $(VOBJ061) $(VOBJ062) $(VOBJ063) $(VOBJ064)
+VOBJ07 = $(VOBJ071) $(VOBJ072) $(VOBJ073) $(VOBJ074)
+VOBJ08 = $(VOBJ081) $(VOBJ082) $(VOBJ083) $(VOBJ084)
+VOBJ09 = $(VOBJ091) $(VOBJ092) $(VOBJ093) $(VOBJ094)
+VOBJ10 = $(VOBJ101) $(VOBJ102) $(VOBJ103) $(VOBJ104)
+VOBJ11 = $(VOBJ111) $(VOBJ112) $(VOBJ113) $(VOBJ114) $(VOBJ115)
+VOBJ12 = $(VOBJ121) $(VOBJ122) $(VOBJ123) $(VOBJ124)
+VOBJ13 = $(VOBJ131) $(VOBJ132) $(VOBJ133) $(VOBJ134)
+VOBJ14 = $(VOBJ141) $(VOBJ142) $(VOBJ143) $(VOBJ144)
+VOBJ15 = $(VOBJ151) $(VOBJ152) $(VOBJ153) $(VOBJ154)
+VOBJ16 = $(VOBJ161) $(VOBJ162) $(VOBJ163) $(VOBJ164)
+VOBJ17 = $(VOBJ171) $(VOBJ172) $(VOBJ173) $(VOBJ174)
+VOBJ18 = $(VOBJ181) $(VOBJ182) $(VOBJ183) $(VOBJ184)
+VOBJ19 = $(VOBJ191) $(VOBJ192) $(VOBJ193) $(VOBJ194) $(VOBJ195)
+VOBJ20 = $(VOBJ201) $(VOBJ202) $(VOBJ203) $(VOBJ204)
+VOBJ21 = $(VOBJ211) $(VOBJ212) $(VOBJ213) $(VOBJ214)
+VOBJ22 = $(VOBJ221) $(VOBJ222) $(VOBJ223) $(VOBJ224)
+VOBJ23 = $(VOBJ231) $(VOBJ232) $(VOBJ233) $(VOBJ234)
+VOBJ24 = $(VOBJ241) $(VOBJ242) $(VOBJ243) $(VOBJ244)
+VOBJ25 = $(VOBJ251) $(VOBJ252) $(VOBJ253) $(VOBJ254)
+VOBJ26 = $(VOBJ261) $(VOBJ262) $(VOBJ263) $(VOBJ264)
+VOBJ27 = $(VOBJ271) $(VOBJ272) $(VOBJ273) $(VOBJ274)
+VOBJ28 = $(VOBJ281) $(VOBJ282)
+VOBJ29 = $(WINOBJ) $(RANDOM)
+HHOBJ  = $(OBJ)\version.o
+
+VOBJ =  $(VOBJ01)  $(VOBJ02)  $(VOBJ03)  $(VOBJ04)  $(VOBJ05)  $(VOBJ06)  $(VOBJ07) \
+        $(VOBJ08)  $(VOBJ09)  $(VOBJ10)  $(VOBJ11)  $(VOBJ12)  $(VOBJ13)  $(VOBJ14) \
+        $(VOBJ15)  $(VOBJ16)  $(VOBJ17)  $(VOBJ18)  $(VOBJ19)  $(VOBJ20)  $(VOBJ21) \
+        $(VOBJ22)  $(VOBJ23)  $(VOBJ24)  $(VOBJ25)  $(VOBJ26)  $(VOBJ27)  $(VOBJ28) \
+        $(VOBJ29)
+HOBJ =  $(VOBJ)  $(HHOBJ)
+
+EXTERN_H   = # $(INCL)\extern.h
+OS2CONF_H  = $(INCL)\os2conf.h $(INCL)\micro.h $(INCL)\system.h $(EXTERN_H)
+GLOBAL_H   = $(INCL)\global.h $(INCL)\coord.h $(OS2CONF_H)
+CONFIG_H   = $(INCL)\config.h $(INCL)\config1.h $(INCL)\tradstdc.h $(GLOBAL_H)
+TRAP_H    = $(INCL)\trap.h
+PERMONST_H = $(INCL)\permonst.h $(INCL)\monattk.h $(INCL)\monflag.h
+YOU_H     = $(INCL)\you.h $(INCL)\attrib.h $(PERMONST_H) $(INCL)\mondata.h \
+            $(INCL)\monst.h $(INCL)\youprop.h $(INCL)\prop.h $(INCL)\pm.h
+DECL_H    = $(INCL)\decl.h $(INCL)\spell.h $(INCL)\obj.h $(YOU_H) \
+            $(INCL)\onames.h $(INCL)\color.h
+HACK_H    = $(CONFIG_H) $(DECL_H) $(INCL)\monsym.h $(INCL)\mkroom.h \
+            $(INCL)\objclass.h $(TRAP_H) $(INCL)\engrave.h $(INCL)\flag.h \
+            $(INCL)\rm.h $(INCL)\dungeon.h $(INCL)\hack.h $(INCL)\display.h \
+            $(INCL)\vision.h $(INCL)\wintty.h $(INCL)\wintype.h $(INCL)\align.h \
+            $(INCL)\winprocs.h
+
+#
+#      The default target.
+#
+
+all :  makedefs dgn_comp lev_comp recover $(GAME) dat $(GUIDE)
+       $(ECHO) Done.
+
+#
+#      Definition file creation.
+#
+
+$(TEMP)\$(GAMEDEF) :
+       $(MAKEB) DD_NAME=$(GAME) DD_DESC=$(GAMEDES) DD_TARG=$@ do_def
+$(TEMP)\$(MKDFDEF) :
+       $(MAKEB) DD_NAME=makedefs DD_DESC="Definitions compiler" DD_TARG=$@ do_def
+$(TEMP)\$(DGNCDEF) :
+       $(MAKEB) DD_NAME=dgn_comp DD_DESC="Dungeon compiler" DD_TARG=$@ do_def
+$(TEMP)\$(LEVCDEF) :
+       $(MAKEB) DD_NAME=lev_comp DD_DESC="Level compiler" DD_TARG=$@ do_def
+$(TEMP)\$(RCVRDEF) :
+       $(MAKEB) DD_NAME=recover DD_DESC="Recovery utility" DD_TARG=$@ do_def
+$(TEMP)\$(DLBDEF) :
+       $(MAKEB) DD_NAME=dlb DD_DESC="Archive utility" DD_TARG=$@ do_def
+
+do_def :
+       $(ECHO) NAME $(DD_NAME) WINDOWCOMPAT> $(DD_TARG)
+       $(ECHO) DESCRIPTION '$(DD_DESC)'>> $(DD_TARG)
+       $(ECHO) PROTMODE>> $(DD_TARG)
+       $(ECHO) EXETYPE OS2>> $(DD_TARG)
+
+#
+#      The main target.
+#
+
+$(GAME) : $(GAMEDIR)\$(GAME).exe
+$(GAME).exe : $(GAMEDIR)\$(GAME).exe
+$(GAMEDIR)\$(GAME).exe : $(TEMP)\$(GAME).rsp $(TEMP)\$(GAME).r
+       $(GAMELN)
+
+$(TEMP)\$(GAME).r : $(HOBJ) $(TEMP)\$(GAMEDEF)
+       $(ECHO) $(VOBJ011) > $@
+       $(ECHO) $(VOBJ012) >> $@
+       $(ECHO) $(VOBJ013) >> $@
+       $(ECHO) $(VOBJ014) >> $@
+       $(ECHO) $(VOBJ021) >> $@
+       $(ECHO) $(VOBJ022) >> $@
+       $(ECHO) $(VOBJ023) >> $@
+       $(ECHO) $(VOBJ024) >> $@
+       $(ECHO) $(VOBJ031) >> $@
+       $(ECHO) $(VOBJ032) >> $@
+       $(ECHO) $(VOBJ033) >> $@
+       $(ECHO) $(VOBJ034) >> $@
+       $(ECHO) $(VOBJ041) >> $@
+       $(ECHO) $(VOBJ042) >> $@
+       $(ECHO) $(VOBJ043) >> $@
+       $(ECHO) $(VOBJ044) >> $@
+       $(ECHO) $(VOBJ051) >> $@
+       $(ECHO) $(VOBJ052) >> $@
+       $(ECHO) $(VOBJ053) >> $@
+       $(ECHO) $(VOBJ054) >> $@
+       $(ECHO) $(VOBJ061) >> $@
+       $(ECHO) $(VOBJ062) >> $@
+       $(ECHO) $(VOBJ063) >> $@
+       $(ECHO) $(VOBJ064) >> $@
+       $(ECHO) $(VOBJ071) >> $@
+       $(ECHO) $(VOBJ072) >> $@
+       $(ECHO) $(VOBJ073) >> $@
+       $(ECHO) $(VOBJ074) >> $@
+       $(ECHO) $(VOBJ081) >> $@
+       $(ECHO) $(VOBJ082) >> $@
+       $(ECHO) $(VOBJ083) >> $@
+       $(ECHO) $(VOBJ084) >> $@
+       $(ECHO) $(VOBJ091) >> $@
+       $(ECHO) $(VOBJ092) >> $@
+       $(ECHO) $(VOBJ093) >> $@
+       $(ECHO) $(VOBJ094) >> $@
+       $(ECHO) $(VOBJ101) >> $@
+       $(ECHO) $(VOBJ102) >> $@
+       $(ECHO) $(VOBJ103) >> $@
+       $(ECHO) $(VOBJ104) >> $@
+       $(ECHO) $(VOBJ111) >> $@
+       $(ECHO) $(VOBJ112) >> $@
+       $(ECHO) $(VOBJ113) >> $@
+       $(ECHO) $(VOBJ114) >> $@
+       $(ECHO) $(VOBJ115) >> $@
+       $(ECHO) $(VOBJ121) >> $@
+       $(ECHO) $(VOBJ122) >> $@
+       $(ECHO) $(VOBJ123) >> $@
+       $(ECHO) $(VOBJ124) >> $@
+       $(ECHO) $(VOBJ131) >> $@
+       $(ECHO) $(VOBJ132) >> $@
+       $(ECHO) $(VOBJ133) >> $@
+       $(ECHO) $(VOBJ134) >> $@
+       $(ECHO) $(VOBJ141) >> $@
+       $(ECHO) $(VOBJ142) >> $@
+       $(ECHO) $(VOBJ143) >> $@
+       $(ECHO) $(VOBJ144) >> $@
+       $(ECHO) $(VOBJ151) >> $@
+       $(ECHO) $(VOBJ152) >> $@
+       $(ECHO) $(VOBJ153) >> $@
+       $(ECHO) $(VOBJ154) >> $@
+       $(ECHO) $(VOBJ161) >> $@
+       $(ECHO) $(VOBJ162) >> $@
+       $(ECHO) $(VOBJ163) >> $@
+       $(ECHO) $(VOBJ164) >> $@
+       $(ECHO) $(VOBJ171) >> $@
+       $(ECHO) $(VOBJ172) >> $@
+       $(ECHO) $(VOBJ173) >> $@
+       $(ECHO) $(VOBJ174) >> $@
+       $(ECHO) $(VOBJ181) >> $@
+       $(ECHO) $(VOBJ182) >> $@
+       $(ECHO) $(VOBJ183) >> $@
+       $(ECHO) $(VOBJ184) >> $@
+       $(ECHO) $(VOBJ191) >> $@
+       $(ECHO) $(VOBJ192) >> $@
+       $(ECHO) $(VOBJ193) >> $@
+       $(ECHO) $(VOBJ194) >> $@
+       $(ECHO) $(VOBJ195) >> $@
+       $(ECHO) $(VOBJ201) >> $@
+       $(ECHO) $(VOBJ202) >> $@
+       $(ECHO) $(VOBJ203) >> $@
+       $(ECHO) $(VOBJ204) >> $@
+       $(ECHO) $(VOBJ211) >> $@
+       $(ECHO) $(VOBJ212) >> $@
+       $(ECHO) $(VOBJ213) >> $@
+       $(ECHO) $(VOBJ214) >> $@
+       $(ECHO) $(VOBJ221) >> $@
+       $(ECHO) $(VOBJ222) >> $@
+       $(ECHO) $(VOBJ223) >> $@
+       $(ECHO) $(VOBJ224) >> $@
+       $(ECHO) $(VOBJ231) >> $@
+       $(ECHO) $(VOBJ232) >> $@
+       $(ECHO) $(VOBJ233) >> $@
+       $(ECHO) $(VOBJ234) >> $@
+       $(ECHO) $(VOBJ241) >> $@
+       $(ECHO) $(VOBJ242) >> $@
+       $(ECHO) $(VOBJ243) >> $@
+       $(ECHO) $(VOBJ244) >> $@
+       $(ECHO) $(VOBJ251) >> $@
+       $(ECHO) $(VOBJ252) >> $@
+       $(ECHO) $(VOBJ253) >> $@
+       $(ECHO) $(VOBJ254) >> $@
+       $(ECHO) $(VOBJ261) >> $@
+       $(ECHO) $(VOBJ262) >> $@
+       $(ECHO) $(VOBJ263) >> $@
+       $(ECHO) $(VOBJ264) >> $@
+       $(ECHO) $(VOBJ271) >> $@
+       $(ECHO) $(VOBJ272) >> $@
+       $(ECHO) $(VOBJ273) >> $@
+       $(ECHO) $(VOBJ274) >> $@
+       $(ECHO) $(VOBJ281) >> $@
+       $(ECHO) $(VOBJ282) >> $@
+       $(ECHO) $(WINOBJ1) >> $@
+       $(ECHO) $(WINOBJ2) >> $@
+       $(ECHO) $(WINOBJ3) >> $@
+       $(ECHO) $(WINOBJ4) >> $@
+       $(ECHO) $(HHOBJ) >> $@
+       $(ECHO) $(RANDOM) >> $@
+.IF $(with_x11) == yes
+       $(X11ECHO) $(WINX11OBJ01) >> $@
+       $(X11ECHO) $(WINX11OBJ02) >> $@
+       $(X11ECHO) $(WINX11OBJ03) >> $@
+       $(X11ECHO) $(WINX11OBJ04) >> $@
+       $(X11ECHO) $(WINX11OBJ05) >> $@
+       $(X11ECHO) $(WINX11OBJ06) >> $@
+       $(X11ECHO) $(WINX11OBJ07) >> $@
+       $(X11ECHO) $(WINX11OBJ08) >> $@
+       $(X11ECHO) $(WINX11OBJ09) >> $@
+       $(X11ECHO) $(WINX11OBJ10) >> $@
+       $(X11ECHO) $(WINX11OBJ11) >> $@
+.END
+
+
+
+$(TEMP)\$(GAME).rsp : $(HOBJ) $(TEMP)\$(GAMEDEF)
+       $(ECHO) $(SYSOBJ) $(VOBJ01) +> $@
+       $(ECHO) $(VOBJ02) +>> $@
+       $(ECHO) $(VOBJ03) +>> $@
+       $(ECHO) $(VOBJ04) +>> $@
+       $(ECHO) $(VOBJ05) +>> $@
+       $(ECHO) $(VOBJ06) +>> $@
+       $(ECHO) $(VOBJ07) +>> $@
+       $(ECHO) $(VOBJ08) +>> $@
+       $(ECHO) $(VOBJ09) +>> $@
+       $(ECHO) $(VOBJ10) +>> $@
+       $(ECHO) $(VOBJ11) +>> $@
+       $(ECHO) $(VOBJ12) +>> $@
+       $(ECHO) $(VOBJ13) +>> $@
+       $(ECHO) $(VOBJ14) +>> $@
+       $(ECHO) $(VOBJ15) +>> $@
+       $(ECHO) $(VOBJ16) +>> $@
+       $(ECHO) $(VOBJ17) +>> $@
+       $(ECHO) $(VOBJ18) +>> $@
+       $(ECHO) $(VOBJ19) +>> $@
+       $(ECHO) $(VOBJ20) +>> $@
+       $(ECHO) $(VOBJ21) +>> $@
+       $(ECHO) $(VOBJ22) +>> $@
+       $(ECHO) $(VOBJ23) +>> $@
+       $(ECHO) $(VOBJ24) +>> $@
+       $(ECHO) $(VOBJ25) +>> $@
+       $(ECHO) $(VOBJ26) +>> $@
+       $(ECHO) $(VOBJ27) +>> $@
+       $(ECHO) $(VOBJ28) +>> $@
+       $(ECHO) $(VOBJ29) +>> $@
+       $(ECHO) $(VOBJ30) +>> $@
+       $(ECHO) $(HHOBJ)>> $@
+       $(ECHO) $(GAMEDIR)\$(GAME).exe>> $@
+       $(ECHO) $(TEMP)\$(GAME)>> $@
+       $(ECHO) $(PLIBS) $(TERMLIB)>> $@
+       $(ECHO) $(TEMP)\$(GAMEDEF) $(LFLAGS);>> $@
+
+#
+#      Targets for makedefs.
+#
+
+makedefs : $(TEMP)\makedefs.exe
+$(TEMP)\makedefs.exe : $(TEMP)\makedefs.rsp
+       $(MKDFLN)
+
+$(TEMP)\makedefs.rsp : $(MAKEOBJS) $(TEMP)\$(MKDFDEF)
+       $(ECHO) $(SYSOBJ) $(MAKEOBJS)> $@
+       $(ECHO) $(TEMP)\makedefs.exe>> $@
+       $(ECHO) nul>> $@
+       $(ECHO) $(RLIBS)>> $@
+       $(ECHO) $(MKDFMD) $(LFLAGS);>> $@
+
+$(OBJ)\makedefs.o : $(UTIL)\$(CB) $(CONFIG_H) $(INCL)\permonst.h $(INCL)\objclass.h \
+                   $(INCL)\monsym.h $(INCL)\artilist.h $(INCL)\qtext.h
+       $(UTILCC)
+
+#
+#      Targets for the special levels compiler.
+#
+
+lev_comp : $(TEMP)\lev_comp.exe
+$(TEMP)\lev_comp.exe : $(TEMP)\lev_comp.rsp
+       $(LEVCLN)
+
+$(TEMP)\lev_comp.rsp : $(SPLEVOBJS) $(TEMP)\$(LEVCDEF)
+       $(ECHO) $(SYSOBJ) $(SOBJ01) +> $@
+       $(ECHO) $(SOBJ02) +>> $@
+       $(ECHO) $(SOBJ03)>> $@
+       $(ECHO) $(TEMP)\lev_comp.exe>> $@
+       $(ECHO) nul>> $@
+       $(ECHO) $(RLIBS)>> $@
+       $(ECHO) $(LEVCMD) $(LFLAGS);>> $@
+
+$(OBJ)\lev_yacc.o : $(UTIL)\$(CB) $(HACK_H) $(INCL)\sp_lev.h
+       $(UTILCC)
+$(OBJ)\lev_lex.o  : $(UTIL)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev_comp.h
+       $(UTILCC)
+$(OBJ)\lev_main.o : $(UTIL)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(INCL)\tcap.h
+       $(UTILCC)
+
+$(UTIL)\lev_yacc.c : $(UTIL)\lev_comp.y
+       $(MAKEB) YY=lev do_yacc
+
+$(UTIL)\lev_lex.c  : $(UTIL)\lev_comp.l
+       $(MAKEB) YY=lev do_lex
+
+#
+#      Targets for the dungeon compiler.
+#
+
+dgn_comp : $(TEMP)\dgn_comp.exe
+$(TEMP)\dgn_comp.exe : $(TEMP)\dgn_comp.rsp
+       $(DGNCLN)
+
+$(TEMP)\dgn_comp.rsp : $(DGNCOMPOBJS) $(TEMP)\$(DGNCDEF)
+       $(ECHO) $(SYSOBJ) $(DOBJ01) +> $@
+       $(ECHO) $(DOBJ02)>> $@
+       $(ECHO) $(TEMP)\dgn_comp.exe>> $@
+       $(ECHO) nul>> $@
+       $(ECHO) $(RLIBS)>> $@
+       $(ECHO) $(DGNCMD) $(LFLAGS);>> $@
+
+$(OBJ)\dgn_yacc.o : $(UTIL)\$(CB) $(CONFIG_H) $(INCL)\date.h $(INCL)\dgn_file.h
+       $(UTILCC)
+$(OBJ)\dgn_lex.o  : $(UTIL)\$(CB) $(CONFIG_H) $(INCL)\dgn_comp.h $(INCL)\dgn_file.h
+       $(UTILCC)
+$(OBJ)\dgn_main.o : $(UTIL)\$(CB) $(CONFIG_H)
+       $(UTILCC)
+
+$(UTIL)\dgn_yacc.c : $(UTIL)\dgn_comp.y
+       $(MAKEB) YY=dgn do_yacc
+
+$(UTIL)\dgn_lex.c  : $(UTIL)\dgn_comp.l
+       $(MAKEB) YY=dgn do_lex
+
+#
+#      For both lev_comp and dgn_comp.
+#
+
+$(OBJ)\panic.o : $(UTIL)\$(CB) $(CONFIG_H)
+       $(UTILCC)
+
+#
+#      Yacc and Lex targets.
+#
+
+yacc_cpy :
+       $(CP) $(SSYS)\$(YY)_yacc.c $(UTIL)
+       $(CP) $(SSYS)\$(YY)_comp.h $(INCL)
+       $(MAKEB) TT=$(UTIL)\$(YY)_yacc.c do_touch
+       $(MAKEB) TT=$(INCL)\$(YY)_comp.h do_touch
+
+yacc_msg :
+       $(ECHO) $(YY)_comp.y has changed. To update $(YY)_yacc.c and $(YY)_comp.h run $(YACC).
+
+yacc_act :
+       $(YACC) -d $(UTIL)\$(YY)_comp.y
+       $(CP) $(YTABC) $(UTIL)\$(YY)_yacc.c
+       $(CP) $(YTABH) $(INCL)\$(YY)_comp.h
+       $(RM) $(YTABC)
+       $(RM) $(YTABH)
+
+lex_cpy :
+       $(CP) $(SSYS)\$(YY)_lex.c $(UTIL)
+       $(MAKEB) TT=$(UTIL)\$(YY)_lex.c do_touch
+
+lex_msg :
+       $(ECHO) $(YY)_comp.l has changed. To update $(YY)_lex.c run $(LEX).
+
+lex_act :
+       $(LEX) $(UTIL)\$(YY)_comp.l
+       $(CP) $(LEXYYC) $(UTIL)\$(YY)_lex.c
+       $(RM) $(LEXYYC)
+
+#
+#      Why must this be so kludgy?
+#
+
+realtouch :
+       $(TOUCH) $(TT)
+
+faketouch :
+       $(BEG) $(CAT) $(TT) > $(TEMP)\foo.bar $(SEP) $(CP) $(TEMP)\foo.bar $(TT) $(SEP) $(RM) $(TEMP)\foo.bar $(END)
+
+#
+#      Targets for the recovery utility.
+#
+
+recover : $(GAMEDIR)\recover.exe
+$(GAMEDIR)\recover.exe : $(TEMP)\recover.rsp
+       $(RCVRLN)
+
+$(TEMP)\recover.rsp : $(RECOVOBJS) $(TEMP)\$(RCVRDEF)
+       $(ECHO) $(SYSOBJ) $(RECOVOBJS)> $@
+       $(ECHO) $(GAMEDIR)\recover.exe>> $@
+       $(ECHO) nul>> $@
+       $(ECHO) $(PLIBS)>> $@
+       $(ECHO) $(TEMP)\$(RCVRDEF) $(LFLAGS);>> $@
+
+$(OBJ)\recover.o : $(UTIL)\$(CB) $(CONFIG_H)
+       $(UTILCC)
+
+#
+#      Targets for the dlb.
+#
+
+dlb : $(TEMP)\dlb.exe
+$(TEMP)\dlb.exe : $(TEMP)\dlb.rsp
+       $(DLBRLN)
+
+$(TEMP)\dlb.rsp : $(DLBOBJS) $(TEMP)\$(DLBDEF)
+       $(ECHO) $(SYSOBJ) $(DLBOBJS)> $@
+       $(ECHO) $(TEMP)\dlb.exe>> $@
+       $(ECHO) nul>> $@
+       $(ECHO) $(PLIBS)>> $@
+       $(ECHO) $(TEMP)\$(DLBDEF) $(LFLAGS);>> $@
+
+$(OBJ)\dlb_main.o : $(UTIL)\$(CB) $(CONFIG_H) $(INCL)\dlb.h
+       $(UTILCC)
+
+$(GAMEDIR)\nhdat : $(WINX11VARDAT)
+       $(MAKEB) do_dlb
+
+dlb_yup : dlb
+       $(TEMP)\dlb cCf $(GAMEDIR) $(GAMEDIR)\nhdat $(DATDLB)
+       -$(RM) $(GAMEDIR)\help
+       -$(RM) $(GAMEDIR)\hh
+       -$(RM) $(GAMEDIR)\cmdhelp
+       -$(RM) $(GAMEDIR)\history
+       -$(RM) $(GAMEDIR)\opthelp
+       -$(RM) $(GAMEDIR)\wizhelp
+       -$(RM) $(GAMEDIR)\asmodeus.lev
+       -$(RM) $(GAMEDIR)\baalz.lev
+       -$(RM) $(GAMEDIR)\bigrm-?.lev
+       -$(RM) $(GAMEDIR)\castle.lev
+       -$(RM) $(GAMEDIR)\fakewiz?.lev
+       -$(RM) $(GAMEDIR)\juiblex.lev
+       -$(RM) $(GAMEDIR)\knox.lev
+       -$(RM) $(GAMEDIR)\medusa-?.lev
+       -$(RM) $(GAMEDIR)\minend-?.lev
+       -$(RM) $(GAMEDIR)\minefill.lev
+       -$(RM) $(GAMEDIR)\minetn-?.lev
+       -$(RM) $(GAMEDIR)\oracle.lev
+       -$(RM) $(GAMEDIR)\orcus.lev
+       -$(RM) $(GAMEDIR)\sanctum.lev
+       -$(RM) $(GAMEDIR)\tower?.lev
+       -$(RM) $(GAMEDIR)\valley.lev
+       -$(RM) $(GAMEDIR)\wizard?.lev
+       -$(RM) $(GAMEDIR)\astral.lev
+       -$(RM) $(GAMEDIR)\air.lev
+       -$(RM) $(GAMEDIR)\earth.lev
+       -$(RM) $(GAMEDIR)\fire.lev
+       -$(RM) $(GAMEDIR)\water.lev
+       -$(RM) $(GAMEDIR)\???-goal.lev
+       -$(RM) $(GAMEDIR)\???-fil?.lev
+       -$(RM) $(GAMEDIR)\???-loca.lev
+       -$(RM) $(GAMEDIR)\???-strt.lev
+       -$(RM) $(GAMEDIR)\data
+       -$(RM) $(GAMEDIR)\oracles
+       -$(RM) $(GAMEDIR)\options
+       -$(RM) $(GAMEDIR)\quest.dat
+       -$(RM) $(GAMEDIR)\rumors
+       -$(RM) $(GAMEDIR)\dungeon
+       -$(RM) $(GAMEDIR)\soko?-?.lev
+#      -$(RM) $(GAMEDIR)\pet_mark.xbm
+#      -$(RM) $(GAMEDIR)\rip.xpm
+
+dlb_nope :
+       $(ECHO) DLB not requested.
+
+#
+#      The following files depend on makedefs to be created.
+#
+#      date.h should be remade every time any of the source or include
+#      files is modified.
+#
+
+$(INCL)\date.h : $(VOBJ) $(TEMP)\makedefs.exe
+       $(TEMP)\makedefs -v
+       $(CP) $(DAT)\options $(GAMEDIR)
+       $(RM) $(DAT)\options
+
+$(INCL)\onames.h : $(TEMP)\makedefs.exe
+       $(TEMP)\makedefs -o
+
+$(INCL)\pm.h : $(TEMP)\makedefs.exe
+       $(TEMP)\makedefs -p
+
+monstr.c : $(TEMP)\makedefs.exe
+       $(TEMP)\makedefs -m
+
+$(OBJ)\monstr.o : $(CB)
+       $(SRCCC)
+
+$(GAMEDIR)\data : $(DAT)\$(DATABASE) $(TEMP)\makedefs.exe
+       $(TEMP)\makedefs -d
+       $(CP) $(DAT)\data $(GAMEDIR)
+       $(RM) $(DAT)\data
+
+$(GAMEDIR)\rumors : $(DAT)\rumors.tru $(DAT)\rumors.fal $(TEMP)\makedefs.exe
+       $(TEMP)\makedefs -r
+       $(CP) $(DAT)\rumors $(GAMEDIR)
+       $(RM) $(DAT)\rumors
+
+$(GAMEDIR)\oracles : $(DAT)\oracles.txt $(TEMP)\makedefs.exe
+       $(TEMP)\makedefs -h
+       $(CP) $(DAT)\oracles $(GAMEDIR)
+       $(RM) $(DAT)\oracles
+
+$(GAMEDIR)\quest.dat : $(DAT)\quest.txt $(TEMP)\makedefs.exe
+       $(TEMP)\makedefs -q
+       $(CP) $(DAT)\quest.dat $(GAMEDIR)
+       $(RM) $(DAT)\quest.dat
+
+#
+#      Vision tables for algorithm D.
+#
+
+vis_tab.c : $(INCL)\vis_tab.h
+$(INCL)\vis_tab.h : $(TEMP)\makedefs.exe
+       $(TEMP)\makedefs -z
+
+$(OBJ)\vis_tab.o : $(CB)
+       $(SRCCC)
+
+#
+#      The following programs vary depending on what OS you are using.
+#
+
+$(OBJ)\main.o : $(SSYS)\pc$(CB) $(HACK_H) $(INCL)\dlb.h
+       $(PSYSCC)
+$(OBJ)\tty.o  : $(SSYS)\pc$(CB) $(HACK_H) $(INCL)\func_tab.h
+       $(PSYSCC)
+$(OBJ)\unix.o : $(SSYS)\pc$(CB) $(HACK_H)
+       $(PSYSCC)
+
+#
+#      Other system specific modules.
+#
+
+$(OBJ)\os2.o   : $(SYS)\$(CB) $(HACK_H) $(INCL)\tcap.h $(INCL)\def_os2.h
+       $(SYSCC)
+$(OBJ)\pcsys.o : $(SSYS)\$(CB) $(HACK_H)
+       $(SSYSCC)
+
+#
+#      Berkeley random(3) routines.
+#
+
+$(OBJ)\random.o : $(SSYS)\$(CB)
+       $(SSYSCC)
+
+#
+#      Window source.
+#
+
+$(OBJ)\getline.o : $(WIN)\$(CB) $(HACK_H) $(INCL)\func_tab.h
+       $(WINCC)
+$(OBJ)\termcap.o : $(WIN)\$(CB) $(HACK_H) $(INCL)\tcap.h
+       $(WINCC)
+$(OBJ)\topl.o    : $(WIN)\$(CB) $(HACK_H) $(INCL)\tcap.h
+       $(WINCC)
+$(OBJ)\wintty.o  : $(WIN)\$(CB) $(HACK_H) $(INCL)\tcap.h
+       $(WINCC)
+
+#
+#      Secondary targets.
+#
+
+dat :  spec_lev help_fil $(GAMEDIR)\dungeon $(GAMEDIR)\data $(GAMEDIR)\rumors \
+       $(GAMEDIR)\oracles $(GAMEDIR)\quest.dat $(GAMEDIR)\$(GAME).ico \
+       $(GAMEDIR)\$(GAME).cmd $(GAMEDIR)\nethack.cnf $(GAMEDIR)\nhdat \
+       $(WINX11VARDAT)
+
+help_fil : $(GAMEDIR)\cmdhelp $(GAMEDIR)\help $(GAMEDIR)\hh $(GAMEDIR)\history \
+       $(GAMEDIR)\license $(GAMEDIR)\opthelp $(GAMEDIR)\wizhelp
+
+$(GAMEDIR)\cmdhelp : $(DAT)\cmdhelp
+       $(CP) $(DAT)\cmdhelp $(GAMEDIR)
+$(GAMEDIR)\help : $(DAT)\help
+       $(CP) $(DAT)\help $(GAMEDIR)
+$(GAMEDIR)\hh : $(DAT)\hh
+       $(CP) $(DAT)\hh $(GAMEDIR)
+$(GAMEDIR)\history : $(DAT)\history
+       $(CP) $(DAT)\history $(GAMEDIR)
+$(GAMEDIR)\license : $(DAT)\license
+       $(CP) $(DAT)\license $(GAMEDIR)
+$(GAMEDIR)\opthelp : $(DAT)\opthelp
+       $(CP) $(DAT)\opthelp $(GAMEDIR)
+$(GAMEDIR)\wizhelp : $(DAT)\wizhelp
+       $(CP) $(DAT)\wizhelp $(GAMEDIR)
+
+$(GAMEDIR)\dungeon : $(DAT)\dungeon.def $(TEMP)\makedefs.exe $(TEMP)\dgn_comp.exe
+       $(TEMP)\makedefs -e
+       $(TEMP)\dgn_comp $(DAT)\dungeon.pdf
+       $(CP) $(DAT)\dungeon $(GAMEDIR)
+       $(RM) $(DAT)\dungeon.pdf
+       $(RM) $(DAT)\dungeon
+
+AFILES = $(GAMEDIR)\Arc-goal.lev
+BFILES = $(GAMEDIR)\Bar-goal.lev
+CFILES = $(GAMEDIR)\Cav-goal.lev
+HFILES = $(GAMEDIR)\Hea-goal.lev
+KFILES = $(GAMEDIR)\Kni-goal.lev
+MFILES = $(GAMEDIR)\Mon-goal.lev
+PFILES = $(GAMEDIR)\Pri-goal.lev
+RANFILES = $(GAMEDIR)\Ran-goal.lev
+RFILES = $(GAMEDIR)\Rog-goal.lev
+SFILES = $(GAMEDIR)\Sam-goal.lev
+TFILES = $(GAMEDIR)\Tou-goal.lev
+VFILES = $(GAMEDIR)\Val-goal.lev
+WFILES = $(GAMEDIR)\Wiz-goal.lev
+
+XFILES = $(AFILES) $(BFILES) $(CFILES) $(HFILES) $(KFILES) $(MFILES) \
+        $(PFILES) $(RANFILES) $(RFILES) $(SFILES) $(TFILES) $(VFILES) $(WFILES)
+
+spec_lev : $(GAMEDIR)\astral.lev $(GAMEDIR)\bigrm-1.lev $(GAMEDIR)\castle.lev \
+          $(GAMEDIR)\knox.lev $(GAMEDIR)\medusa-1.lev $(GAMEDIR)\minefill.lev \
+          $(GAMEDIR)\oracle.lev $(GAMEDIR)\tower1.lev $(GAMEDIR)\valley.lev \
+          $(GAMEDIR)\wizard1.lev $(GAMEDIR)\soko1-1.lev $(XFILES)
+
+#      Single special level files
+
+$(GAMEDIR)\castle.lev : $(DAT)\castle.des $(TEMP)\lev_comp.exe
+       $(MAKEB) LF=castle do_slev
+$(GAMEDIR)\knox.lev : $(DAT)\knox.des $(TEMP)\lev_comp.exe
+       $(MAKEB) LF=knox do_slev
+$(GAMEDIR)\oracle.lev : $(DAT)\oracle.des $(TEMP)\lev_comp.exe
+       $(MAKEB) LF=oracle do_slev
+
+do_slev :
+       $(TEMP)\lev_comp $(DAT)\$(LF).des
+       $(CP) $(LF).lev $(GAMEDIR)
+       $(RM) $(LF).lev
+
+#      Multiple special level files
+
+$(GAMEDIR)\astral.lev : $(DAT)\endgame.des $(TEMP)\lev_comp.exe
+       $(TEMP)\lev_comp $(DAT)\endgame.des
+       $(CP) air.lev $(GAMEDIR)
+       $(CP) astral.lev $(GAMEDIR)
+       $(CP) earth.lev $(GAMEDIR)
+       $(CP) fire.lev $(GAMEDIR)
+       $(CP) water.lev $(GAMEDIR)
+       $(RM) air.lev
+       $(RM) astral.lev
+       $(RM) earth.lev
+       $(RM) fire.lev
+       $(RM) water.lev
+
+$(GAMEDIR)\bigrm-1.lev : $(DAT)\bigroom.des $(TEMP)\lev_comp.exe
+       $(TEMP)\lev_comp $(DAT)\bigroom.des
+       $(CP) bigrm-?.lev $(GAMEDIR)
+       $(RM) bigrm-?.lev
+
+$(GAMEDIR)\medusa-1.lev : $(DAT)\medusa.des $(TEMP)\lev_comp.exe
+       $(TEMP)\lev_comp $(DAT)\medusa.des
+       $(CP) medusa-?.lev $(GAMEDIR)
+       $(RM) medusa-?.lev
+
+$(GAMEDIR)\minefill.lev : $(DAT)\mines.des $(TEMP)\lev_comp.exe
+       $(TEMP)\lev_comp $(DAT)\mines.des
+       $(CP) minend-?.lev $(GAMEDIR)
+       $(CP) minefill.lev $(GAMEDIR)
+       $(CP) minetn-?.lev $(GAMEDIR)
+       $(RM) minend-?.lev
+       $(RM) minefill.lev
+       $(RM) minetn-?.lev
+
+$(GAMEDIR)\tower1.lev : $(DAT)\tower.des $(TEMP)\lev_comp.exe
+       $(TEMP)\lev_comp $(DAT)\tower.des
+       $(CP) tower?.lev $(GAMEDIR)
+       $(RM) tower?.lev
+
+$(GAMEDIR)\valley.lev : $(DAT)\gehennom.des $(TEMP)\lev_comp.exe
+       $(TEMP)\lev_comp $(DAT)\gehennom.des
+       $(CP) asmodeus.lev $(GAMEDIR)
+       $(CP) baalz.lev $(GAMEDIR)
+       $(CP) juiblex.lev $(GAMEDIR)
+       $(CP) orcus.lev $(GAMEDIR)
+       $(CP) sanctum.lev $(GAMEDIR)
+       $(CP) valley.lev $(GAMEDIR)
+       $(RM) asmodeus.lev
+       $(RM) baalz.lev
+       $(RM) juiblex.lev
+       $(RM) orcus.lev
+       $(RM) sanctum.lev
+       $(RM) valley.lev
+
+$(GAMEDIR)\wizard1.lev : $(DAT)\yendor.des $(TEMP)\lev_comp.exe
+       $(TEMP)\lev_comp $(DAT)\yendor.des
+       $(CP) wizard?.lev $(GAMEDIR)
+       $(CP) fakewiz?.lev $(GAMEDIR)
+       $(RM) wizard?.lev
+       $(RM) fakewiz?.lev
+
+$(GAMEDIR)\soko1-1.lev : $(DAT)\sokoban.des $(TEMP)\lev_comp.exe
+       $(TEMP)\lev_comp $(DAT)\sokoban.des
+       $(CP) soko?-?.lev $(GAMEDIR)
+       $(RM) soko?-?.lev
+
+
+#      Quest dungeons
+
+$(AFILES) : $(DAT)\Arch.des $(TEMP)\lev_comp.exe
+       $(MAKEB) QQ=Arc QF=Arch do_quest
+$(BFILES) : $(DAT)\Barb.des $(TEMP)\lev_comp.exe
+       $(MAKEB) QQ=Bar QF=Barb do_quest
+$(CFILES) : $(DAT)\Caveman.des $(TEMP)\lev_comp.exe
+       $(MAKEB) QQ=Cav QF=Caveman do_quest
+$(HFILES) : $(DAT)\Healer.des $(TEMP)\lev_comp.exe
+       $(MAKEB) QQ=Hea QF=Healer do_quest
+$(KFILES) : $(DAT)\Knight.des $(TEMP)\lev_comp.exe
+       $(MAKEB) QQ=Kni QF=Knight do_quest
+$(MFILES) : $(DAT)\Monk.des $(TEMP)\lev_comp.exe
+       $(MAKEB) QQ=Mon QF=Monk do_quest
+$(PFILES) : $(DAT)\Priest.des $(TEMP)\lev_comp.exe
+       $(MAKEB) QQ=Pri QF=Priest do_quest
+$(RANFILES) : $(DAT)\Ranger.des $(TEMP)\lev_comp.exe
+       $(MAKEB) QQ=Ran QF=Ranger do_quest
+$(RFILES) : $(DAT)\Rogue.des $(TEMP)\lev_comp.exe
+       $(MAKEB) QQ=Rog QF=Rogue do_quest
+$(SFILES) : $(DAT)\Samurai.des $(TEMP)\lev_comp.exe
+       $(MAKEB) QQ=Sam QF=Samurai do_quest
+$(TFILES) : $(DAT)\Tourist.des $(TEMP)\lev_comp.exe
+       $(MAKEB) QQ=Tou QF=Tourist do_quest
+$(VFILES) : $(DAT)\Valkyrie.des $(TEMP)\lev_comp.exe
+       $(MAKEB) QQ=Val QF=Valkyrie do_quest
+$(WFILES) : $(DAT)\Wizard.des $(TEMP)\lev_comp.exe
+       $(MAKEB) QQ=Wiz QF=Wizard do_quest
+
+do_quest :
+       $(TEMP)\lev_comp $(DAT)\$(QF).des
+       $(CP) $(QQ)-fil?.lev $(GAMEDIR)
+       $(CP) $(QQ)-goal.lev $(GAMEDIR)
+       $(CP) $(QQ)-loca.lev $(GAMEDIR)
+       $(CP) $(QQ)-strt.lev $(GAMEDIR)
+       $(RM) $(QQ)-fil?.lev
+       $(RM) $(QQ)-goal.lev
+       $(RM) $(QQ)-loca.lev
+       $(RM) $(QQ)-strt.lev
+
+#
+#      NetHack icon for Presentation Manager.
+#
+
+$(GAMEDIR)\$(GAME).ico : $(SYS)\nhpmico.uu
+       $(MAKEB) do_icon
+
+icon_msg :
+       $(ECHO) Icon file not extracted.  Extract manually if required.
+
+icon_act :
+       $(UUDECODE) $(SYS)\nhpmico.uu
+       $(CP) nethack.ico $(GAMEDIR)\$(GAME).ico
+       $(RM) nethack.ico
+
+#
+#      NetHack command file to use with Presentation Manager.
+#
+
+$(GAMEDIR)\$(GAME).cmd :
+       $(MAKEB) CMDF=$@ do_cmd
+
+cmd_msg :
+       $(ECHO) Command file not created.  Create manually if required.
+
+cmd_act :
+       $(ECHO) @echo off> $(CMDF)
+       $(ECHO) REM Command file for starting nethack.exe from PM/WPS Desktop>> $(CMDF)
+       $(ECHO) $(GAME).exe $(P)1 $(P)2 $(P)3 $(P)4 $(P)5 $(P)6 $(P)7>> $(CMDF)
+       $(ECHO) pause>> $(CMDF)
+
+#
+#      NetHack configuration file.  Will not overwrite an existing file.
+#
+
+$(GAMEDIR)\nethack.cnf :
+       $(CP) $(SSYS)\nethack.cnf $(GAMEDIR)
+
+#
+#      Documentation.
+#
+
+$(TEMP)\$(GUIDEBOO).dvi : $(DOC)\$(GUIDEBOO).tex
+       $(LATEX) $(DOC)\$(GUIDEBOO).tex
+       $(CP) $(GUIDEBOO).dvi $(TEMP)
+       $(CP) $(GUIDEBOO).aux $(TEMP)
+       $(CP) $(GUIDEBOO).log $(TEMP)
+       $(RM) $(GUIDEBOO).dvi
+       $(RM) $(GUIDEBOO).aux
+       $(RM) $(GUIDEBOO).log
+
+#
+#      Housekeeping.
+#
+
+clean :
+       -$(RM) $(OBJ)\*.o
+
+spotless : clean
+       -$(RM) $(INCL)\date.h
+       -$(RM) $(INCL)\onames.h
+       -$(RM) $(INCL)\pm.h
+       -$(RM) $(INCL)\vis_tab.h
+       -$(RM) vis_tab.c
+       -$(RM) monstr.c
+       -$(RM) *.lev
+       -$(RM) nethack.ico
+       -$(RM) $(TEMP)\makedefs.exe
+       -$(RM) $(TEMP)\lev_comp.exe
+       -$(RM) $(TEMP)\dgn_comp.exe
+       -$(RM) $(TEMP)\*.rsp
+       -$(RM) $(TEMP)\*.def
+       -$(RM) $(TEMP)\*.map
+       -$(RM) $(TEMP)\$(GUIDEBOO).dvi
+       -$(RM) $(TEMP)\$(GUIDEBOO).aux
+       -$(RM) $(TEMP)\$(GUIDEBOO).log
+
+#
+#      Main source.
+#
+#      Default rules are sooo difficult for so many make
+#      programs that we do this the most straightforward way.
+#
+
+$(OBJ)\allmain.o  : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\alloc.o    : $(SRC)\$(CB) $(CONFIG_H)
+       $(SRCCC)
+$(OBJ)\apply.o    : $(SRC)\$(CB) $(HACK_H) $(INCL)\edog.h
+       $(SRCCC)
+$(OBJ)\artifact.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h
+       $(SRCCC)
+$(OBJ)\attrib.o   : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h
+       $(SRCCC)
+$(OBJ)\ball.o     : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\bones.o    : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h
+       $(SRCCC)
+$(OBJ)\botl.o     : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\cmd.o      : $(SRC)\$(CB) $(HACK_H) $(INCL)\func_tab.h
+       $(SRCCC)
+$(OBJ)\dbridge.o  : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\decl.o     : $(SRC)\$(CB) $(HACK_H) $(INCL)\quest.h
+       $(SRCCC)
+$(OBJ)\detect.o   : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h
+       $(SRCCC)
+$(OBJ)\dig.o      : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\display.o  : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\dlb.o      : $(SRC)\$(CB) $(CONFIG_H) $(INCL)\dlb.h
+       $(SRCCC)
+$(OBJ)\do.o       : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h
+       $(SRCCC)
+$(OBJ)\do_name.o  : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\do_wear.o  : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\dog.o      : $(SRC)\$(CB) $(HACK_H) $(INCL)\edog.h
+       $(SRCCC)
+$(OBJ)\dogmove.o  : $(SRC)\$(CB) $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+       $(SRCCC)
+$(OBJ)\dokick.o   : $(SRC)\$(CB) $(HACK_H) $(INCL)\eshk.h
+       $(SRCCC)
+$(OBJ)\dothrow.o  : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\drawing.o  : $(SRC)\$(CB) $(HACK_H) $(INCL)\tcap.h
+       $(SRCCC)
+$(OBJ)\dungeon.o  : $(SRC)\$(CB) $(HACK_H) $(INCL)\dgn_file.h
+       $(SRCCC)
+$(OBJ)\eat.o      : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\end.o      : $(SRC)\$(CB) $(HACK_H) $(INCL)\eshk.h
+       $(SRCCC)
+$(OBJ)\engrave.o  : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h
+       $(SRCCC)
+$(OBJ)\exper.o    : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\explode.o  : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\extralev.o : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\files.o    : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\fountain.o : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\hack.o     : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\hacklib.o  : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\invent.o   : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h
+       $(SRCCC)
+$(OBJ)\light.o    : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\lock.o     : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\mail.o     : $(SRC)\$(CB) $(HACK_H) $(INCL)\mail.h
+       $(SRCCC)
+$(OBJ)\makemon.o  : $(SRC)\$(CB) $(HACK_H) $(INCL)\epri.h $(INCL)\emin.h
+       $(SRCCC)
+$(OBJ)\mapglyph.o : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\mcastu.o   : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\mhitm.o    : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+       $(SRCCC)
+$(OBJ)\mhitu.o    : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+       $(SRCCC)
+$(OBJ)\minion.o   : $(SRC)\$(CB) $(HACK_H) $(INCL)\emin.h $(INCL)\epri.h
+       $(SRCCC)
+$(OBJ)\mklev.o    : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\mkmap.o    : $(SRC)\$(CB) $(HACK_H) $(INCL)\sp_lev.h
+       $(SRCCC)
+$(OBJ)\mkmaze.o   : $(SRC)\$(CB) $(HACK_H) $(INCL)\sp_lev.h
+       $(SRCCC)
+$(OBJ)\mkobj.o    : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h
+       $(SRCCC)
+$(OBJ)\mkroom.o   : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\mon.o      : $(SRC)\$(CB) $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+       $(SRCCC)
+$(OBJ)\mondata.o  : $(SRC)\$(CB) $(HACK_H) $(INCL)\eshk.h $(INCL)\epri.h
+       $(SRCCC)
+$(OBJ)\monmove.o  : $(SRC)\$(CB) $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h
+       $(SRCCC)
+$(OBJ)\monst.o    : $(SRC)\$(CB) $(CONFIG_H) $(PERMONST_H) $(INCL)\monsym.h $(INCL)\eshk.h $(INCL)\vault.h $(INCL)\epri.h $(INCL)\color.h
+       $(SRCCC)
+$(OBJ)\mplayer.o  : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\mthrowu.o  : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\muse.o     : $(SRC)\$(CB) $(HACK_H) $(INCL)\edog.h
+       $(SRCCC)
+$(OBJ)\music.o    : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\o_init.o   : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\objects.o  : $(SRC)\$(CB) $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h $(INCL)\prop.h $(INCL)\color.h
+       $(SRCCC)
+$(OBJ)\objnam.o   : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\options.o  : $(SRC)\$(CB) $(HACK_H) $(INCL)\tcap.h
+       $(SRCCC)
+$(OBJ)\pager.o    : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\pickup.o   : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\pline.o    : $(SRC)\$(CB) $(HACK_H) $(INCL)\epri.h
+       $(SRCCC)
+$(OBJ)\polyself.o : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\potion.o   : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\pray.o     : $(SRC)\$(CB) $(HACK_H) $(INCL)\epri.h
+       $(SRCCC)
+$(OBJ)\priest.o   : $(SRC)\$(CB) $(HACK_H) $(INCL)\mfndpos.h $(INCL)\eshk.h $(INCL)\epri.h $(INCL)\emin.h
+       $(SRCCC)
+$(OBJ)\quest.o    : $(SRC)\$(CB) $(HACK_H) $(INCL)\quest.h $(INCL)\qtext.h
+       $(SRCCC)
+$(OBJ)\questpgr.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\qtext.h
+       $(SRCCC)
+$(OBJ)\read.o     : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\region.o     : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\rect.o     : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\restore.o  : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h $(INCL)\quest.h
+       $(SRCCC)
+$(OBJ)\rip.o      : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\rnd.o      : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\role.o     : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\rumors.o   : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\save.o     : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(INCL)\quest.h
+       $(SRCCC)
+$(OBJ)\shk.o      : $(SRC)\$(CB) $(HACK_H) $(INCL)\eshk.h
+       $(SRCCC)
+$(OBJ)\shknam.o   : $(SRC)\$(CB) $(HACK_H) $(INCL)\eshk.h
+       $(SRCCC)
+$(OBJ)\sit.o      : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h
+       $(SRCCC)
+$(OBJ)\sounds.o   : $(SRC)\$(CB) $(HACK_H) $(INCL)\edog.h $(INCL)\eshk.h
+       $(SRCCC)
+$(OBJ)\sp_lev.o   : $(SRC)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(INCL)\rect.h
+       $(SRCCC)
+$(OBJ)\spell.o    : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\steal.o    : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\steed.o    : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\teleport.o : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\timeout.o  : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\topten.o   : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\track.o    : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\trap.o     : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\u_init.o   : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\uhitm.o    : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\vault.o    : $(SRC)\$(CB) $(HACK_H) $(INCL)\vault.h
+       $(SRCCC)
+$(OBJ)\version.o  : $(SRC)\$(CB) $(HACK_H) $(INCL)\date.h $(INCL)\$(PATCHLEV).h
+       $(SRCCC)
+$(OBJ)\vision.o   : $(SRC)\$(CB) $(HACK_H) $(INCL)\vis_tab.h
+       $(SRCCC)
+$(OBJ)\weapon.o   : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\were.o     : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\wield.o    : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\windows.o  : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\wizard.o   : $(SRC)\$(CB) $(HACK_H) $(INCL)\qtext.h
+       $(SRCCC)
+$(OBJ)\worm.o     : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h
+       $(SRCCC)
+$(OBJ)\worn.o     : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\write.o    : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+$(OBJ)\zap.o      : $(SRC)\$(CB) $(HACK_H)
+       $(SRCCC)
+
+$(OBJ)/Window.o: $(WINX11)\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \
+               $(CONFIG_H)
+       $(CC) -o$(OBJ)\Window.o $(CFLAGS) -c $(WINX11)\Window.c
+$(OBJ)/dialogs.o: $(WINX11)\dialogs.c $(CONFIG_H)
+       $(CC) -o$(OBJ)\dialogs.o $(CFLAGS) -c $(WINX11)\dialogs.c
+$(OBJ)/winX.o: $(WINX11)\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h $(WINX11)\nh72icon \
+               $(WINX11)\nh56icon $(WINX11)\nh32icon
+       $(CC) $(CFLAGS) -c $(WINX11)\winX.c -o$(OBJ)\winX.o
+$(OBJ)/winmap.o: $(WINX11)\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\winX.h $(INCL)\tile2x11.h
+       $(CC) $(CFLAGS) -c $(WINX11)\winmap.c -o $(OBJ)\winmap.o
+$(OBJ)/winmenu.o: $(WINX11)\winmenu.c $(HACK_H) $(INCL)\winX.h
+       $(CC) $(CFLAGS) -c $(WINX11)\winmenu.c -o $(OBJ)\winmenu.o
+$(OBJ)/winmesg.o: $(WINX11)\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h
+       $(CC) $(CFLAGS) -c $(WINX11)\winmesg.c -o$(OBJ)\winmesg.o
+$(OBJ)/winmisc.o: $(WINX11)\winmisc.c $(HACK_H) $(INCL)\func_tab.h \
+               $(INCL)\winX.h
+       $(CC) $(CFLAGS) -c $(WINX11)\winmisc.c -o$(OBJ)\winmisc.o
+$(OBJ)/winstat.o: $(WINX11)\winstat.c $(HACK_H) $(INCL)\winX.h
+       $(CC) $(CFLAGS) -c $(WINX11)\winstat.c -o$(OBJ)\winstat.o
+$(OBJ)/wintext.o: $(WINX11)\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h
+       $(CC) $(CFLAGS) -c $(WINX11)\wintext.c -o$(OBJ)\wintext.o
+$(OBJ)/winval.o: $(WINX11)\winval.c $(HACK_H) $(INCL)\winX.h
+       $(CC) $(CFLAGS) -c $(WINX11)\winval.c -o$(OBJ)\winval.o
+
+$(OBJ)/tile.o: $(NHSRC)\src\tile.c $(HACK_H)
+       $(CC) $(CFLAGS) -c $(NHSRC)\src\tile.c -o$(OBJ)\tile.o
+
+$(TEMP)\tilemap.exe: ..\win\share\tilemap.c $(HACK_H)
+       $(CC) $(GCCO) $(WARN) -I$(INCL) $(CDFLAGS) $(STDC) $(WINX11CFLAGS) $(LFLAGS) -o $(TEMP)\tilemap.exe ..\win\share\tilemap.c $(LIBS)
+$(NHSRC)\src\tile.c: $(TEMP)\tilemap.exe
+       $(TEMP)\tilemap
+
+x11tiles: $(TEMP)\tile2x11.exe $(WINSHARE)\monsters.txt \
+                               $(WINSHARE)\objects.txt \
+                               $(WINSHARE)\other.txt
+       $(TEMP)\tile2x11.exe $(WINSHARE)\monsters.txt $(WINSHARE)\objects.txt \
+                               $(WINSHARE)\other.txt
+       $(CP) x11tiles $(GAMEDIR)\x11tiles
+
+TEXT_IO = $(OBJ)\tiletext.o \
+         $(OBJ)\tiletxt.o \
+         $(OBJ)\drawing.o \
+         $(OBJ)\decl.o \
+         $(OBJ)\monst.o \
+         $(OBJ)\objects.o
+
+$(OBJ)\tiletext.o: ../win/share/tiletext.c $(CONFIG_H) $(WINSHARE)\tile.h
+       $(CC) $(CFLAGS) -c $(WINSHARE)\tiletext.c -o$(OBJ)\tiletext.o
+$(OBJ)\tiletxt.o: $(WINSHARE)\tilemap.c $(HACK_H)
+       $(CC) $(CFLAGS) -c -DTILETEXT $(WINSHARE)\tilemap.c -o$(OBJ)\tiletxt.o
+
+$(TEMP)\tile2x11.exe: $(OBJ)\tile2x11.o $(TEXT_IO)
+       $(CC) $(LFLAGS) -o $(TEMP)\tile2x11.exe $(OBJ)\tile2x11.o $(TEXT_IO) $(LIBS)
+
+pet_mark.xbm: $(WINX11)\pet_mark.xbm
+       $(CP) $(WINX11)\pet_mark.xbm $(GAMEDIR)\pet_mark.xbm
+
+rip.xpm: $(WINX11)\rip.xpm
+       $(CP) $(WINX11)\rip.xpm $(GAMEDIR)\rip.xpm
+
+$(OBJ)\tile2x11.o : $(WINX11)\tile2x11.c $(INCL)\tile2x11.h
+       $(CC) $(CFLAGS) -o$(OBJ)\tile2x11.o -c $(WINX11)\tile2x11.c \
+               -I$(WINSHARE)
+
diff --git a/sys/os2/nhpmico.uu b/sys/os2/nhpmico.uu
new file mode 100644 (file)
index 0000000..b381156
--- /dev/null
@@ -0,0 +1,23 @@
+begin 644 nethack.ico
+M0D$H``````````````!#21H`````````>`````P````@`$```0`!`````/___
+M_T-)&@````````!X`0``#````"``(``!``0```````"``(```("`@```@`"`L
+M@(``@("`P,#```#_`/\``/___P``_P#___\`____````````````````````!
+M`````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````````
+M`````````````````````/9F9F9F9F9F9F9F9F9F9F;_9F9F9F9F9F9F9F9F7
+M9F9F_XB(B(B(B(B(B(B(B(AF9O^(B(B(B(B(B(B(B(B(9F;_B(B(B(5558B("
+MB(B(B&9F_XB(B(@`506(B(B(B(AF9O^(B(B(```%B(B(B(B(9F;_B(A555``@
+M55B(B(B(B&9F_XB+N[NP#N-5B(B(B(AF9O^(N[N[`+[N-5B(B(B(9F;_B[N[E
+MN[N[[N-8B(B(B&9F_XN[N[N[N[[N4XB(B(AF9O^+N[N9F9N[[N,XB(B(9F;_)
+MB[NYF9F9N[[N,XB(B&9F_XN[F9F9F9N[[N,XB(AF9O^+N9F9F9F9NU[N,XB(<
+M9F;_B[F9F9F9F;M8[N,XB&9F_XNYF9F9F9F[6([N,XAF9O^+N9F9F9F9NUB(]
+M[N.(9F;_B[F9F9F9F;M8B([NB&9F_XN[F9F9F9N[6(B([HAF9O^+N[F9F9F[#
+MNUB(B(B(9F;_B[N[F9F;N[M8B(B(B&9F_XN[N[N[N[N[6(B(B(AF9O^+N[N[)
+MN[N[NXB(B(B(9F;_B[N(B(B(B[N(B(B(B&9F_XNXB(B(B(B[B(B(B(AF9O^(/
+MB(B(B(B(B(B(B(B(9F;_B(B(B(B(B(B(B(B(B&9F_XB(B(B(B(B(B(B(B(AFN
+A9O__________________]F;_____________________?
+``
+end
diff --git a/sys/os2/os2.c b/sys/os2/os2.c
new file mode 100644 (file)
index 0000000..676774e
--- /dev/null
@@ -0,0 +1,364 @@
+/*     SCCS Id: @(#)os2.c      3.4     1996/02/29 */
+/*     Copyright (c) Timo Hakulinen, 1990, 1991, 1992, 1993, 1996. */
+/*     NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *  OS/2 system functions.
+ */
+
+#define NEED_VARARGS
+#include "hack.h"
+
+#ifdef OS2
+
+#include "tcap.h"
+
+/* OS/2 system definitions */
+
+#ifdef __EMX__
+#undef CLR_BLACK
+#undef CLR_WHITE
+#undef CLR_BLUE
+#undef CLR_RED
+#undef CLR_GREEN
+#undef CLR_CYAN
+#undef CLR_YELLOW
+#undef CLR_BROWN
+#endif
+
+#include "def_os2.h"
+
+#include <ctype.h>
+
+static char NDECL(DOSgetch);
+static char NDECL(BIOSgetch);
+
+int
+tgetch()
+{
+       char ch;
+
+       /* BIOSgetch can use the numeric key pad on IBM compatibles. */
+       if (iflags.BIOS)
+               ch = BIOSgetch();
+       else
+               ch = DOSgetch();
+       return ((ch == '\r') ? '\n' : ch);
+}
+
+/*
+ *  Keyboard translation tables.
+ */
+#define KEYPADLO       0x47
+#define KEYPADHI       0x53
+
+#define PADKEYS        (KEYPADHI - KEYPADLO + 1)
+#define iskeypad(x)    (KEYPADLO <= (x) && (x) <= KEYPADHI)
+
+/*
+ * Keypad keys are translated to the normal values below.
+ * When iflags.BIOS is active, shifted keypad keys are translated to the
+ *    shift values below.
+ */
+static const struct pad {
+       char normal, shift, cntrl;
+} keypad[PADKEYS] = {
+                       {'y', 'Y', C('y')},             /* 7 */
+                       {'k', 'K', C('k')},             /* 8 */
+                       {'u', 'U', C('u')},             /* 9 */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'h', 'H', C('h')},             /* 4 */
+                       {'g', 'g', 'g'},                /* 5 */
+                       {'l', 'L', C('l')},             /* 6 */
+                       {'p', 'P', C('p')},             /* + */
+                       {'b', 'B', C('b')},             /* 1 */
+                       {'j', 'J', C('j')},             /* 2 */
+                       {'n', 'N', C('n')},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+}, numpad[PADKEYS] = {
+                       {'7', M('7'), '7'},             /* 7 */
+                       {'8', M('8'), '8'},             /* 8 */
+                       {'9', M('9'), '9'},             /* 9 */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'4', M('4'), '4'},             /* 4 */
+                       {'g', 'G', 'g'},                /* 5 */
+                       {'6', M('6'), '6'},             /* 6 */
+                       {'p', 'P', C('p')},             /* + */
+                       {'1', M('1'), '1'},             /* 1 */
+                       {'2', M('2'), '2'},             /* 2 */
+                       {'3', M('3'), '3'},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+};
+
+/*
+ * Unlike Ctrl-letter, the Alt-letter keystrokes have no specific ASCII
+ * meaning unless assigned one by a keyboard conversion table, so the
+ * keyboard BIOS normally does not return a character code when Alt-letter
+ * is pressed. So, to interpret unassigned Alt-letters, we must use a
+ * scan code table to translate the scan code into a letter, then set the
+ * "meta" bit for it.  -3.
+ */
+#define SCANLO         0x10
+#define SCANHI         0x32
+#define SCANKEYS       (SCANHI - SCANLO + 1)
+#define inmap(x)       (SCANLO <= (x) && (x) <= SCANHI)
+
+static const char scanmap[SCANKEYS] = {        /* ... */
+       'q','w','e','r','t','y','u','i','o','p','[',']', '\n',
+       0, 'a','s','d','f','g','h','j','k','l',';','\'', '`',
+       0, '\\', 'z','x','c','v','b','N','m'    /* ... */
+};
+
+/*
+ * BIOSgetch emulates the MSDOS way of getting keys directly with a BIOS call.
+ */
+#define SHIFT_KEY      (0x1 | 0x2)
+#define CTRL_KEY       0x4
+#define ALT_KEY                0x8
+
+static char
+BIOSgetch()
+{
+       unsigned char scan, shift, ch;
+       const struct pad *kpad;
+
+       KBDKEYINFO CharData;
+       USHORT IOWait = 0;
+       HKBD KbdHandle = 0;
+
+       KbdCharIn(&CharData,IOWait,KbdHandle);
+       ch = CharData.chChar;
+       scan = CharData.chScan;
+       shift = CharData.fsState;
+
+       /* Translate keypad keys */
+       if (iskeypad(scan)) {
+               kpad = iflags.num_pad ? numpad : keypad;
+               if (shift & SHIFT_KEY)
+                       ch = kpad[scan - KEYPADLO].shift;
+               else if (shift & CTRL_KEY)
+                       ch = kpad[scan - KEYPADLO].cntrl;
+               else
+                       ch = kpad[scan - KEYPADLO].normal;
+       }
+       /* Translate unassigned Alt-letters */
+       if ((shift & ALT_KEY) && !ch) {
+               if (inmap(scan))
+                       ch = scanmap[scan - SCANLO];
+               return (isprint(ch) ? M(ch) : ch);
+       }
+       return ch;
+}
+
+static char
+DOSgetch()
+{
+       KBDKEYINFO CharData;
+       USHORT IOWait = 0;
+       HKBD KbdHandle = 0;
+
+       KbdCharIn(&CharData,IOWait,KbdHandle);
+       if (CharData.chChar == 0) {     /* an extended code -- not yet supported */
+               KbdCharIn(&CharData,IOWait,KbdHandle);     /* eat the next character */
+               CharData.chChar = 0;            /* and return a 0 */
+       }
+       return (CharData.chChar);
+}
+
+char
+switchar()
+{
+       return '/';
+}
+
+int
+kbhit()
+{
+       KBDKEYINFO CharData;
+       HKBD KbdHandle = 0;
+
+       KbdPeek(&CharData,KbdHandle);
+       return (CharData.fbStatus & (1 << 6));
+}
+
+long
+freediskspace(path)
+char *path;
+{
+       FSALLOCATE FSInfoBuf;
+#ifdef OS2_32BITAPI
+       ULONG
+#else
+       USHORT
+#endif
+               DriveNumber, FSInfoLevel = 1, res;
+
+       if (path[0] && path[1] == ':')
+               DriveNumber = (toupper(path[0]) - 'A') + 1;
+       else
+               DriveNumber = 0;
+       res =
+#ifdef OS2_32BITAPI
+               DosQueryFSInfo(DriveNumber,FSInfoLevel,(PVOID)&FSInfoBuf,(ULONG)sizeof(FSInfoBuf));
+#else
+               DosQFSInfo(DriveNumber,FSInfoLevel,(PBYTE)&FSInfoBuf,(USHORT)sizeof(FSInfoBuf));
+#endif
+       if (res)
+               return -1L;             /* error */
+       else
+               return ((long) FSInfoBuf.cSectorUnit * FSInfoBuf.cUnitAvail *
+                              FSInfoBuf.cbSector);
+}
+
+/*
+ * Functions to get filenames using wildcards
+ */
+
+#ifdef OS2_32BITAPI
+static FILEFINDBUF3 ResultBuf;
+#else
+static FILEFINDBUF ResultBuf;
+#endif
+static HDIR DirHandle;
+
+int
+findfirst(path)
+char *path;
+{
+#ifdef OS2_32BITAPI
+       ULONG
+#else
+       USHORT
+#endif
+               res, SearchCount = 1;
+
+       DirHandle = 1;
+       res =
+#ifdef OS2_32BITAPI
+               DosFindFirst((PSZ)path,&DirHandle,0L,(PVOID)&ResultBuf,(ULONG)sizeof(ResultBuf),&SearchCount,1L);
+#else
+               DosFindFirst((PSZ)path,&DirHandle,0,&ResultBuf,(USHORT)sizeof(ResultBuf),&SearchCount,0L);
+#endif
+       return(!res);
+}
+
+int
+findnext()
+{
+#ifdef OS2_32BITAPI
+       ULONG
+#else
+       USHORT
+#endif
+               res, SearchCount = 1;
+
+       res =
+#ifdef OS2_32BITAPI
+               DosFindNext(DirHandle,(PVOID)&ResultBuf,(ULONG)sizeof(ResultBuf),&SearchCount);
+#else
+               DosFindNext(DirHandle,&ResultBuf,(USHORT)sizeof(ResultBuf),&SearchCount);
+#endif
+       return(!res);
+}
+
+char *
+foundfile_buffer()
+{
+       return(ResultBuf.achName);
+}
+
+long
+filesize(file)
+char *file;
+{
+       if (findfirst(file)) {
+               return  (* (long *) (ResultBuf.cbFileAlloc));
+       } else
+               return -1L;
+}
+
+/*
+ * Chdrive() changes the default drive.
+ */
+void
+chdrive(str)
+char *str;
+{
+       char *ptr;
+       char drive;
+
+       if ((ptr = index(str, ':')) != (char *)0) {
+               drive = toupper(*(ptr - 1));
+#ifdef OS2_32BITAPI
+               DosSetDefaultDisk((ULONG)(drive - 'A' + 1));
+#else
+               DosSelectDisk((USHORT)(drive - 'A' + 1));
+#endif
+       }
+}
+
+void
+disable_ctrlP()
+{
+       KBDINFO KbdInfo;
+       HKBD KbdHandle = 0;
+
+       if (!iflags.rawio) return;
+       KbdInfo.cb = sizeof(KbdInfo);
+       KbdGetStatus(&KbdInfo,KbdHandle);
+       KbdInfo.fsMask &= 0xFFF7; /* ASCII off */
+       KbdInfo.fsMask |= 0x0004; /* BINARY on */
+       KbdSetStatus(&KbdInfo,KbdHandle);
+}
+
+void
+enable_ctrlP()
+{
+       KBDINFO KbdInfo;
+       HKBD KbdHandle = 0;
+
+       if (!iflags.rawio) return;
+       KbdInfo.cb = sizeof(KbdInfo);
+       KbdGetStatus(&KbdInfo,KbdHandle);
+       KbdInfo.fsMask &= 0xFFFB; /* BINARY off */
+       KbdInfo.fsMask |= 0x0008; /* ASCII on */
+       KbdSetStatus(&KbdInfo,KbdHandle);
+}
+
+void
+get_scr_size()
+{
+       VIOMODEINFO ModeInfo;
+       HVIO VideoHandle = 0;
+
+       ModeInfo.cb = sizeof(ModeInfo);
+
+       (void) VioGetMode(&ModeInfo,VideoHandle);
+
+       CO = ModeInfo.col;
+       LI = ModeInfo.row;
+}
+
+void
+gotoxy(x,y)
+int x,y;
+{
+       HVIO VideoHandle = 0;
+
+       x--; y--;                       /* (0,0) is upper right corner */
+
+       (void) VioSetCurPos(x, y, VideoHandle);
+}
+
+
+char* get_username(lan_username_size)
+int *lan_username_size;
+{
+  return (char*)0;
+}
+#ifdef X11_GRAPHICS
+int errno;
+#endif
+#endif /* OS2 */
diff --git a/sys/share/Makefile.lib b/sys/share/Makefile.lib
new file mode 100644 (file)
index 0000000..dbf9705
--- /dev/null
@@ -0,0 +1,21 @@
+#      SCCS Id: @(#)Makefile.lib       3.4     1990/22/02
+#      Nethack makefile for Fred fish termlib -- Norman Meluch
+#
+CC     = cl /c
+MODEL  = L
+CFLAGS = /A$(MODEL) /Os /Oa /Gs /Zp1 /W0
+#
+# Termcap routines.
+TERMLIB = termlib.lib
+#
+TL_LOBJECTS =  tgetent.o       tgetflag.o      tgetnum.o       \
+               tgetstr.o       tgoto.o         tputs.o         \
+               isdigit.o       fgetlr.o
+#
+.SUFFIXES: .exe .o .c .obj .asm
+#
+.c.o:
+       $(CC) $(CFLAGS) /Fo$*.o $*.c
+#
+$(TERMLIB):    $(TL_LOBJECTS)
+       lib $(TERMLIB) -+ $(TL_LOBJECTS);
diff --git a/sys/share/NetHack.cnf b/sys/share/NetHack.cnf
new file mode 100644 (file)
index 0000000..d174109
--- /dev/null
@@ -0,0 +1,168 @@
+#      NetHack Copyright (c) NetHack PC Development Team 1993, 1996, 1999
+#      NetHack may be freely redistributed.  See license for details.
+#
+# A '#' at the beginning of a line means the rest of the line is a comment.
+#
+# Some options MUST be set in this file, other options can be toggled while
+# playing.  For a list of options available see the <opthelp.> file.  If
+# the game plays slowly you might notice some improvement by setting
+# !time and !showexp, which will reduce screen I/O somewhat.
+#
+# To change the configuration, comment out the unwanted lines, and
+# uncomment the configuration you want.
+#
+# Note: For blind players, please use the file NHAccess.nh as a template.
+#
+
+# *** OPTIONS ***
+#
+# The three options on this line should be used for most setups.  
+# If your machine isn't very IBM-compatible, and NetHack doesn't work, 
+# try commenting out this line.
+OPTIONS=rawio,BIOS,IBMgraphics
+
+# To use VGA graphical tiles on an MS-DOS PC with VGA or better,uncomment 
+# this:
+#OPTIONS=video:autodetect
+
+# Some versions of NetHack use the pc speaker to play the notes given when
+# playing music instruments in NetHack.  To use this feature, if available,
+# uncomment the following line:
+#OPTIONS=soundcard:autodetect
+
+# If your machine is NEC PC-9800, use:
+#OPTIONS=rawio,BIOS,video:default
+# If you use an Atari and want tty use:
+#OPTIONS=windowtype:tty,rawio,BIOS
+
+
+# Some options to set personal preferences.  Uncomment and change these to
+# suit your personal preference.  If several people are to use the same
+# configuration, options like these should not be set.
+#
+#OPTIONS=name:Janet,role:Valkyrie,race:Human,gender:female,align:lawful
+#OPTIONS=dogname:Fido,catname:Morris,fruit:guava
+#OPTIONS=horsename:Silver
+#OPTIONS=autopickup,pickup_types:$"=/!?+
+#OPTIONS=packorder:")[%?+/=!(*0_`
+#OPTIONS=scores:10 top/2 around/own
+#OPTIONS=nolegacy,noverbose
+#OPTIONS=menustyle:traditional
+
+# If you wish to change the symbol used to display boulders use:
+OPTIONS=boulder:0
+#
+# General options.  You might also set "silent" so as not to attract
+# the boss's attention.
+#
+# number_pad option can have an optional value of 0 (off), 1 (on), 
+# or 2(on,legacy-mode) which causes 5='g', alt-5='G', alt-0='I'
+#
+OPTIONS=time,noshowexp,number_pad:2,lit_corridor
+
+# Treat space bar as rest. Warning: may be dangerous for new players.
+# OPTIONS=rest_on_space
+
+#
+# If you want to get rid of "use #quit to quit..." use:
+#OPTIONS=suppress_alert:3.3.1
+#
+#
+# *** LOCATIONS ***
+# Some platforms allow you to change the location where various things are kept.
+# IMPORTANT: If you change any of these locations, the directories they
+# point at must exist.  NetHack will not create them for you.
+#
+# The default location for everything.
+# Note: On Windows HACKDIR defaults to the location 
+#       of the NetHack.exe or NetHackw.exe file so
+#       setting HACKDIR below to override that is 
+#       not usually necessary or recommended.
+#HACKDIR=c:\games\nethack
+#
+# The location that level files in progress are stored (default=HACKDIR, writeable)
+#LEVELDIR=c:\nethack\levels
+#
+# The location where saved games are kept (default=HACKDIR, writeable)
+#SAVEDIR=c:\nethack\save
+#
+# The location that bones files are kept (default=HACKDIR, writeable)
+#BONESDIR=c:\nethack\save
+#
+# The location that file synchronization locks are stored (default=HACKDIR, writeable)
+#LOCKDIR=c:\nethack\levels
+#
+# The location that a record of game aborts and self-diagnosed game problems
+# is kept (default=HACKDIR, writeable)
+#TROUBLEDIR=c:\nethack\trouble
+#
+# *** CHARACTER GRAPHICS ***
+#
+# See the on-line help or the Guidebook for which symbols are in which
+# positions.
+#
+# If you merely set the IBMgraphics option as above, NetHack will use IBM
+# extended ASCII for dungeon characters.  If you don't like the selections,
+# you can make up your own via these graphics options, but you should still
+# set IBMgraphics if you are using IBM graphics characters to get the correct
+# processing.
+#
+# ================================================
+# The defaults using the IBM graphics character set:
+#DUNGEON = 032 179 196 218 191 192 217 197 193 194 \
+#          180 195 250 254 254 043 043 240 241 250 \
+#          176 177 243 242 060 062 095 124 092 035 \
+#          244 247 250 247 250 250 035 035 032 035 \
+#          247
+#
+# ================================================
+# Some alternatives:
+#DUNGEON=  032 186 205 201 187 200 188 206 202 203 \
+#         185 204 249 239 239 254 254 240 241 249 \
+#         177 177 060 062 060 062 095 124 092 035 \
+#         244 247 249 247 042 042 179 196 046 035 \
+#         247
+#
+#TRAPS=    094 094 094 094 094 094 094 094 094 094 \
+#         094 094 094 094 094 034 094 094 094 094 \
+#         094 094
+
+# ================================================
+# Here is a recommendation sent in by Michael Feir
+# for use by blind NetHack players.
+#
+#DUNGEON=  032 124 045 124 124 124 124 045 045 045 \
+#          124 124 046 045 124 043 043 046 035 035 \
+#          060 062 060 062 095 092 035 126 126 126 \
+#          126 042 042 035 035 032 035 126
+#
+#TRAPS=    094 094 094 094 094 094 094 094 094 094 \
+#          094 094 094 094 094 094 094 094 094 094 \
+#          094 094
+#
+#EFFECTS=  124 095 092 047 042 033 041 040         \
+#          048 035 064 042                         \
+#          047 045 092 058 058 092 045 047         \
+#          047 045 092 058 032 058 092 045 047
+
+# ================================================
+# Example using the DEC Rainbow/ANSI line-drawing character set:
+#
+# If you have compiled with TERMLIB, merely set the DECgraphics option as
+# above.  NetHack will then switch into the VTxxx line-drawing character set
+# (aka ANSI ruling character set '0') for dungeon characters.  If you don't
+# like the selections, you can make up your own via the graphics options,
+# adding 128 to the value of any line-drawing character you want to use.
+# (But you should still set DECgraphics to get the correct processing.)
+
+# =================================================
+# *** VIDEOCOLORS AND VIDEOSHADES ***
+#
+# While playing on NEC PC-9800, default game display may be difficult to
+# read.  Try following setting.
+#
+#OPTIONS=videocolors:4-2-6-1-5-3-4-2-6-1-5-3,videoshades:normal-normal-normal
+#
+# DEC Rainbows will hang if rawio is set, so they should instead use:
+#OPTIONS=BIOS,DECgraphics
+
diff --git a/sys/share/dgn_comp.h b/sys/share/dgn_comp.h
new file mode 100644 (file)
index 0000000..8f3ecfd
--- /dev/null
@@ -0,0 +1,27 @@
+#define INTEGER 257
+#define A_DUNGEON 258
+#define BRANCH 259
+#define CHBRANCH 260
+#define LEVEL 261
+#define RNDLEVEL 262
+#define CHLEVEL 263
+#define RNDCHLEVEL 264
+#define UP_OR_DOWN 265
+#define PROTOFILE 266
+#define DESCRIPTION 267
+#define DESCRIPTOR 268
+#define LEVELDESC 269
+#define ALIGNMENT 270
+#define LEVALIGN 271
+#define ENTRY 272
+#define STAIR 273
+#define NO_UP 274
+#define NO_DOWN 275
+#define PORTAL 276
+#define STRING 277
+typedef union
+{
+       int     i;
+       char*   str;
+} YYSTYPE;
+extern YYSTYPE yylval;
diff --git a/sys/share/dgn_lex.c b/sys/share/dgn_lex.c
new file mode 100644 (file)
index 0000000..054a25d
--- /dev/null
@@ -0,0 +1,1475 @@
+/* A lexical scanner for NetHack generated by flex */
+
+/* Scanner skeleton version:
+ * flexhack.skl 3.3.0 (from .../flex/RCS/flex.skl,v 2.85 95/04/24 10:48:47)
+ */
+#define FLEXHACK_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include "config.h"
+#define yyconst const  /* some code inserted by flex will refer to yyconst */
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+               *yy_cp = yy_hold_char; \
+               yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+               YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+               } \
+       while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+       {
+       FILE *yy_input_file;
+
+       char *yy_ch_buf;                /* input buffer */
+       char *yy_buf_pos;               /* current position in input buffer */
+
+       /* Size of input buffer in bytes, not including room for EOB
+        * characters.
+        */
+       yy_size_t yy_buf_size;
+
+       /* Number of characters read into yy_ch_buf, not including EOB
+        * characters.
+        */
+       int yy_n_chars;
+
+       /* Whether we "own" the buffer - i.e., we know we created it,
+        * and can realloc() it to grow it, and should free() it to
+        * delete it.
+        */
+       int yy_is_our_buffer;
+
+       /* Whether this is an "interactive" input source; if so, and
+        * if we're using stdio for input, then we want to use getc()
+        * instead of fread(), to make sure we stop fetching input after
+        * each newline.
+        */
+       int yy_is_interactive;
+
+       /* Whether we're considered to be at the beginning of a line.
+        * If so, '^' rules will be active on the next match, otherwise
+        * not.
+        */
+       int yy_at_bol;
+
+       /* Whether to try to fill the input buffer when we reach the
+        * end of it.
+        */
+       int yy_fill_buffer;
+
+       int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+       /* When an EOF's been seen but there's still some text to process
+        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+        * shouldn't try reading from the input source any more.  We might
+        * still have a bunch of tokens to match, though, because of
+        * possible backing-up.
+        *
+        * When we actually see the EOF, we change the status to "new"
+        * (via yyrestart()), so that the user can continue scanning by
+        * just pointing yyin at a new input file.
+        */
+#define YY_BUFFER_EOF_PENDING 2
+       };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars;         /* number of characters read into yy_ch_buf */
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;                /* whether we need to initialize */
+static int yy_start = 0;       /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void FDECL(yyrestart, (FILE *));
+
+void FDECL(yy_switch_to_buffer, (YY_BUFFER_STATE));
+void NDECL(yy_load_buffer_state);
+YY_BUFFER_STATE FDECL(yy_create_buffer, (FILE *,int));
+void FDECL(yy_delete_buffer, (YY_BUFFER_STATE));
+void FDECL(yy_init_buffer, (YY_BUFFER_STATE,FILE *));
+void FDECL(yy_flush_buffer, (YY_BUFFER_STATE));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+static genericptr_t FDECL(yy_flex_alloc, (yy_size_t));
+static genericptr_t FDECL(yy_flex_realloc2, (genericptr_t,yy_size_t,int));
+static void FDECL(yy_flex_free, (genericptr_t));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+       { \
+       if ( ! yy_current_buffer ) \
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+       yy_current_buffer->yy_is_interactive = is_interactive; \
+       }
+
+#define yy_set_bol(at_bol) \
+       { \
+       if ( ! yy_current_buffer ) \
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+       yy_current_buffer->yy_at_bol = at_bol; \
+       }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type NDECL(yy_get_previous_state);
+static yy_state_type FDECL(yy_try_NUL_trans, (yy_state_type));
+static int NDECL(yy_get_next_buffer);
+static void FDECL(yy_fatal_error, (const char *));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+       yytext_ptr = yy_bp; \
+       yyleng = (int) (yy_cp - yy_bp); \
+       yy_hold_char = *yy_cp; \
+       *yy_cp = '\0'; \
+       yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 35
+#define YY_END_OF_BUFFER 36
+static yyconst short int yy_accept[196] =
+    {   0,
+        0,    0,   36,   34,   33,   32,   34,   34,   29,   34,
+       34,   34,   34,   34,   34,   34,   34,   34,   34,   34,
+       34,   34,   34,   34,   34,   34,   34,   34,   34,   33,
+       32,    0,   30,   29,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    2,    0,   31,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    3,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,   14,    0,    0,    0,    0,    0,    0,
+        4,    0,   25,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    6,    0,    0,    0,    5,    0,    0,   23,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,   20,    0,    0,    0,    0,    8,    0,    0,    0,
+        0,    0,    0,    1,    0,    0,    0,    0,    0,   22,
+       15,    0,   21,    7,   19,    0,    0,    0,    0,    0,
+        0,   13,    0,    0,    0,   26,   16,    0,    0,   12,
+        0,    0,    0,   11,    9,    0,   17,   18,    0,   27,
+        0,   28,   24,   10,    0
+
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    4,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    5,    6,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    7,    1,    1,    7,    7,    7,
+        7,    7,    7,    7,    7,    7,    7,    1,    1,    1,
+        1,    1,    1,    1,    8,    9,   10,   11,   12,   13,
+       14,   15,   16,    1,    1,   17,   18,   19,   20,   21,
+        1,   22,   23,   24,   25,   26,    1,    1,   27,    1,
+        1,    1,    1,    1,   28,    1,   29,    1,   30,   31,
+
+       32,   33,   34,   35,   36,    1,   37,   38,   39,   40,
+       41,   42,    1,   43,   44,   45,   46,    1,   47,    1,
+        1,   48,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[49] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1
+    } ;
+
+static yyconst short int yy_base[198] =
+    {   0,
+        0,  213,  218,  220,  215,  220,  213,  210,  207,  196,
+      190,  196,   37,  191,  197,  186,  188,  171,  164,  172,
+      174,  173,   18,  160,  159,  154,  157,   11,  194,  194,
+      220,  190,  220,  187,  177,  184,  183,  167,  170,  164,
+      161,  166,  174,  155,  136,  144,  134,  132,  133,   26,
+      135,  143,  147,  128,  145,  220,  170,  220,  158,  152,
+      154,  159,  154,  145,   44,  142,   47,  124,  124,  125,
+      129,  129,  115,   27,  121,  113,  111,  120,  115,  116,
+      134,  142,  132,  128,  137,  121,  130,  129,  125,  129,
+      131,   97,  220,  105,   94,  101,   95,   96,   94,   99,
+
+      105,  101,   89,  220,   95,  112,  114,   51,  112,  107,
+      220,  110,  114,  111,  106,   96,   85,   76,   81,   82,
+       88,   69,  220,   81,   76,   75,  220,   78,   99,  220,
+       88,   97,   87,   88,   92,   93,   88,   91,   90,   71,
+       65,  220,   62,   60,   57,   56,  220,   59,   54,   74,
+       84,   65,   66,  220,   70,   65,   70,   60,   68,  220,
+      220,   52,  220,  220,  220,   46,   50,   57,   61,   67,
+       62,  220,   67,   64,   63,  220,  220,   42,   41,  220,
+       61,   53,   49,  220,  220,   50,  220,  220,   51,  220,
+       46,  220,  220,  220,  220,   62,   60
+
+    } ;
+
+static yyconst short int yy_def[198] =
+    {   0,
+      195,    1,  195,  195,  195,  195,  195,  196,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  197,  195,
+      195,  196,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  197,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,    0,  195,  195
+
+    } ;
+
+static yyconst short int yy_nxt[269] =
+    {   0,
+        4,    5,    6,    7,    8,    4,    9,   10,   11,   12,
+       13,   14,    4,    4,    4,    4,   15,    4,    4,    4,
+       16,   17,    4,    4,    4,    4,    4,    4,    4,   18,
+       19,    4,    4,    4,   20,    4,    4,   21,   22,   23,
+        4,   24,   25,   26,   27,   28,    4,    4,   38,   49,
+       55,   87,   56,   74,   75,   88,   90,   98,   50,  131,
+       57,   39,   32,   91,  194,  193,  192,  132,  191,  190,
+      189,  188,   99,  187,  186,  185,  184,  183,  182,  181,
+      180,  179,  178,  177,  176,  175,  174,  173,  172,  171,
+      170,  169,  168,  167,  166,  165,  164,  163,  162,  161,
+
+      160,  159,  158,  157,  156,  155,  154,  153,  152,  151,
+      150,  149,  148,  147,  146,  145,  144,  143,  142,  141,
+      140,  139,  138,  137,  136,  135,  134,  133,  130,  129,
+      128,  127,  126,  125,  124,  123,  122,  121,  120,  119,
+      118,  117,  116,  115,  114,  113,  112,  111,  110,  109,
+      108,  107,  106,  105,  104,  103,  102,  101,  100,   97,
+       96,   95,   94,   93,   92,   89,   86,   85,   84,   83,
+       82,   81,   58,   80,   79,   78,   77,   76,   73,   72,
+       71,   70,   69,   68,   67,   66,   65,   64,   63,   62,
+       61,   60,   59,   34,   33,   30,   58,   54,   53,   52,
+
+       51,   48,   47,   46,   45,   44,   43,   42,   41,   40,
+       37,   36,   35,   34,   33,   31,   30,  195,   29,    3,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195
+    } ;
+
+static yyconst short int yy_chk[269] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,   13,   23,
+       28,   65,   28,   50,   50,   65,   67,   74,   23,  108,
+      197,   13,  196,   67,  191,  189,  186,  108,  183,  182,
+      181,  179,   74,  178,  175,  174,  173,  171,  170,  169,
+      168,  167,  166,  162,  159,  158,  157,  156,  155,  153,
+      152,  151,  150,  149,  148,  146,  145,  144,  143,  141,
+
+      140,  139,  138,  137,  136,  135,  134,  133,  132,  131,
+      129,  128,  126,  125,  124,  122,  121,  120,  119,  118,
+      117,  116,  115,  114,  113,  112,  110,  109,  107,  106,
+      105,  103,  102,  101,  100,   99,   98,   97,   96,   95,
+       94,   92,   91,   90,   89,   88,   87,   86,   85,   84,
+       83,   82,   81,   80,   79,   78,   77,   76,   75,   73,
+       72,   71,   70,   69,   68,   66,   64,   63,   62,   61,
+       60,   59,   57,   55,   54,   53,   52,   51,   49,   48,
+       47,   46,   45,   44,   43,   42,   41,   40,   39,   38,
+       37,   36,   35,   34,   32,   30,   29,   27,   26,   25,
+
+       24,   22,   21,   20,   19,   18,   17,   16,   15,   14,
+       12,   11,   10,    9,    8,    7,    5,    3,    2,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,  195,  195,  195,  195,  195,  195
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+char *yytext;
+#define INITIAL 0
+/*     SCCS Id: @(#)dgn_lex.c  3.4     2002/03/27      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet */
+/*     Copyright (c) 1990 by M. Stephenson          */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#define DGN_COMP
+
+#include "config.h"
+#include "dgn_comp.h"
+#include "dgn_file.h"
+
+/*
+ * Most of these don't exist in flex, yywrap is macro and
+ * yyunput is properly declared in flex.skel.
+ */
+#if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER)
+int FDECL(yyback, (int *,int));
+int NDECL(yylook);
+int NDECL(yyinput);
+int NDECL(yywrap);
+int NDECL(yylex);
+       /* Traditional lexes let yyunput() and yyoutput() default to int;
+        * newer ones may declare them as void since they don't return
+        * values.  For even more fun, the lex supplied as part of the
+        * newer unbundled compiler for SunOS 4.x adds the void declarations
+        * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain
+        * int) while the bundled lex and the one with the older unbundled
+        * compiler do not.  To detect this, we need help from outside --
+        * sys/unix/Makefile.utl.
+        *
+        * Digital UNIX is difficult and still has int in spite of all
+        * other signs.
+        */
+# if defined(NeXT) || defined(SVR4) || defined(_AIX32)
+#  define VOIDYYPUT
+# endif
+# if !defined(VOIDYYPUT) && defined(POSIX_TYPES)
+#  if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS)
+#   define VOIDYYPUT
+#  endif
+# endif
+# if !defined(VOIDYYPUT) && defined(WEIRD_LEX)
+#  if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1)
+#   define VOIDYYPUT
+#  endif
+# endif
+# if defined(VOIDYYPUT) && defined(__osf__)
+#  undef VOIDYYPUT
+# endif
+# ifdef VOIDYYPUT
+void FDECL(yyunput, (int));
+void FDECL(yyoutput, (int));
+# else
+int FDECL(yyunput, (int));
+int FDECL(yyoutput, (int));
+# endif
+#endif /* !FLEX_SCANNER && !FLEXHACK_SCANNER */
+
+#ifdef FLEX_SCANNER
+#define YY_MALLOC_DECL \
+              genericptr_t FDECL(malloc, (size_t)); \
+              genericptr_t FDECL(realloc, (genericptr_t,size_t));
+#endif
+
+
+void FDECL(init_yyin, (FILE *));
+void FDECL(init_yyout, (FILE *));
+
+/* this doesn't always get put in dgn_comp.h
+ * (esp. when using older versions of bison)
+ */
+
+extern YYSTYPE yylval;
+
+int line_number = 1;
+
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+extern int NDECL(yywrap);
+#endif
+
+#ifndef YY_NO_UNPUT
+static void FDECL(yyunput, (int,char *));
+#endif
+
+#ifndef yytext_ptr
+static void FDECL(yy_flex_strncpy, (char *,const char *,int));
+#endif
+
+#ifndef YY_NO_INPUT
+static int NDECL(input);
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+       if ( yy_current_buffer->yy_is_interactive ) \
+               { \
+               int c = '*', n; \
+               for ( n = 0; n < max_size && \
+                            (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+                       buf[n] = (char) c; \
+               if ( c == '\n' ) \
+                       buf[n++] = (char) c; \
+               if ( c == EOF && ferror( yyin ) ) \
+                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
+               result = n; \
+               } \
+       else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+                 && ferror( yyin ) ) \
+               YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+       if ( yyleng > 0 ) \
+               yy_current_buffer->yy_at_bol = \
+                               (yytext[yyleng - 1] == '\n'); \
+       YY_USER_ACTION
+
+int NDECL(yylex);
+int yylex()
+       {
+       register yy_state_type yy_current_state;
+       register char *yy_cp, *yy_bp;
+       register int yy_act;
+
+
+
+       if ( yy_init )
+               {
+               yy_init = 0;
+
+#ifdef YY_USER_INIT
+               YY_USER_INIT;
+#endif
+
+               if ( ! yy_start )
+                       yy_start = 1;   /* first start state */
+
+               if ( ! yyin )
+                       yyin = stdin;
+
+               if ( ! yyout )
+                       yyout = stdout;
+
+               if ( ! yy_current_buffer )
+                       yy_current_buffer =
+                               yy_create_buffer( yyin, YY_BUF_SIZE );
+
+               yy_load_buffer_state();
+               }
+
+       while ( 1 )             /* loops until end-of-file is reached */
+               {
+               yy_cp = yy_c_buf_p;
+
+               /* Support of yytext. */
+               *yy_cp = yy_hold_char;
+
+               /* yy_bp points to the position in yy_ch_buf of the start of
+                * the current run.
+                */
+               yy_bp = yy_cp;
+
+               yy_current_state = yy_start;
+               yy_current_state += YY_AT_BOL();
+yy_match:
+               do
+                       {
+                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+                       if ( yy_accept[yy_current_state] )
+                               {
+                               yy_last_accepting_state = yy_current_state;
+                               yy_last_accepting_cpos = yy_cp;
+                               }
+                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                               {
+                               yy_current_state = (int) yy_def[yy_current_state];
+                               if ( yy_current_state >= 196 )
+                                       yy_c = yy_meta[(unsigned int) yy_c];
+                               }
+                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+                       ++yy_cp;
+                       }
+               while ( yy_base[yy_current_state] != 220 );
+
+yy_find_action:
+               yy_act = yy_accept[yy_current_state];
+               if ( yy_act == 0 )
+                       { /* have to back up */
+                       yy_cp = yy_last_accepting_cpos;
+                       yy_current_state = yy_last_accepting_state;
+                       yy_act = yy_accept[yy_current_state];
+                       }
+
+               YY_DO_BEFORE_ACTION;
+
+
+do_action:     /* This label is used only to access EOF actions. */
+
+
+               switch ( yy_act )
+       { /* beginning of action switch */
+                       case 0: /* must back up */
+                       /* undo the effects of YY_DO_BEFORE_ACTION */
+                       *yy_cp = yy_hold_char;
+                       yy_cp = yy_last_accepting_cpos;
+                       yy_current_state = yy_last_accepting_state;
+                       goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+return(A_DUNGEON);
+       YY_BREAK
+case 2:
+YY_RULE_SETUP
+{ yylval.i=1; return(UP_OR_DOWN); }
+       YY_BREAK
+case 3:
+YY_RULE_SETUP
+{ yylval.i=0; return(UP_OR_DOWN); }
+       YY_BREAK
+case 4:
+YY_RULE_SETUP
+return(ENTRY);
+       YY_BREAK
+case 5:
+YY_RULE_SETUP
+return(STAIR);
+       YY_BREAK
+case 6:
+YY_RULE_SETUP
+return(NO_UP);
+       YY_BREAK
+case 7:
+YY_RULE_SETUP
+return(NO_DOWN);
+       YY_BREAK
+case 8:
+YY_RULE_SETUP
+return(PORTAL);
+       YY_BREAK
+case 9:
+YY_RULE_SETUP
+return(PROTOFILE);
+       YY_BREAK
+case 10:
+YY_RULE_SETUP
+return(DESCRIPTION);
+       YY_BREAK
+case 11:
+YY_RULE_SETUP
+return(LEVELDESC);
+       YY_BREAK
+case 12:
+YY_RULE_SETUP
+return(ALIGNMENT);
+       YY_BREAK
+case 13:
+YY_RULE_SETUP
+return(LEVALIGN);
+       YY_BREAK
+case 14:
+YY_RULE_SETUP
+{ yylval.i=TOWN ; return(DESCRIPTOR); }
+       YY_BREAK
+case 15:
+YY_RULE_SETUP
+{ yylval.i=HELLISH ; return(DESCRIPTOR); }
+       YY_BREAK
+case 16:
+YY_RULE_SETUP
+{ yylval.i=MAZELIKE ; return(DESCRIPTOR); }
+       YY_BREAK
+case 17:
+YY_RULE_SETUP
+{ yylval.i=ROGUELIKE ; return(DESCRIPTOR); }
+       YY_BREAK
+case 18:
+YY_RULE_SETUP
+{ yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); }
+       YY_BREAK
+case 19:
+YY_RULE_SETUP
+{ yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); }
+       YY_BREAK
+case 20:
+YY_RULE_SETUP
+{ yylval.i=D_ALIGN_LAWFUL ; return(DESCRIPTOR); }
+       YY_BREAK
+case 21:
+YY_RULE_SETUP
+{ yylval.i=D_ALIGN_NEUTRAL ; return(DESCRIPTOR); }
+       YY_BREAK
+case 22:
+YY_RULE_SETUP
+{ yylval.i=D_ALIGN_CHAOTIC ; return(DESCRIPTOR); }
+       YY_BREAK
+case 23:
+YY_RULE_SETUP
+return(BRANCH);
+       YY_BREAK
+case 24:
+YY_RULE_SETUP
+return(CHBRANCH);
+       YY_BREAK
+case 25:
+YY_RULE_SETUP
+return(LEVEL);
+       YY_BREAK
+case 26:
+YY_RULE_SETUP
+return(RNDLEVEL);
+       YY_BREAK
+case 27:
+YY_RULE_SETUP
+return(CHLEVEL);
+       YY_BREAK
+case 28:
+YY_RULE_SETUP
+return(RNDCHLEVEL);
+       YY_BREAK
+case 29:
+YY_RULE_SETUP
+{ yylval.i=atoi(yytext); return(INTEGER); }
+       YY_BREAK
+case 30:
+YY_RULE_SETUP
+{ yytext[yyleng-1] = 0; /* Discard the trailing \" */
+                 yylval.str = (char *) alloc(strlen(yytext+1)+1);
+                 Strcpy(yylval.str, yytext+1); /* Discard the first \" */
+                 return(STRING); }
+       YY_BREAK
+case 31:
+YY_RULE_SETUP
+{ line_number++; }
+       YY_BREAK
+case 32:
+YY_RULE_SETUP
+{ line_number++; }
+       YY_BREAK
+case 33:
+YY_RULE_SETUP
+;      /* skip trailing tabs & spaces */
+       YY_BREAK
+case 34:
+YY_RULE_SETUP
+{ return yytext[0]; }
+       YY_BREAK
+case 35:
+YY_RULE_SETUP
+ECHO;
+       YY_BREAK
+case YY_STATE_EOF(INITIAL):
+       yyterminate();
+
+       case YY_END_OF_BUFFER:
+               {
+               /* Amount of text matched not including the EOB char. */
+               int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+               /* Undo the effects of YY_DO_BEFORE_ACTION. */
+               *yy_cp = yy_hold_char;
+
+               if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+                       {
+                       /* We're scanning a new file or input source.  It's
+                        * possible that this happened because the user
+                        * just pointed yyin at a new source and called
+                        * yylex().  If so, then we have to assure
+                        * consistency between yy_current_buffer and our
+                        * globals.  Here is the right place to do so, because
+                        * this is the first action (other than possibly a
+                        * back-up) that will match for the new input source.
+                        */
+                       yy_n_chars = yy_current_buffer->yy_n_chars;
+                       yy_current_buffer->yy_input_file = yyin;
+                       yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+                       }
+
+               /* Note that here we test for yy_c_buf_p "<=" to the position
+                * of the first EOB in the buffer, since yy_c_buf_p will
+                * already have been incremented past the NUL character
+                * (since all states make transitions on EOB to the
+                * end-of-buffer state).  Contrast this with the test
+                * in input().
+                */
+               if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+                       { /* This was really a NUL. */
+                       yy_state_type yy_next_state;
+
+                       yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+                       yy_current_state = yy_get_previous_state();
+
+                       /* Okay, we're now positioned to make the NUL
+                        * transition.  We couldn't have
+                        * yy_get_previous_state() go ahead and do it
+                        * for us because it doesn't know how to deal
+                        * with the possibility of jamming (and we don't
+                        * want to build jamming into it because then it
+                        * will run more slowly).
+                        */
+
+                       yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+                       yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+                       if ( yy_next_state )
+                               {
+                               /* Consume the NUL. */
+                               yy_cp = ++yy_c_buf_p;
+                               yy_current_state = yy_next_state;
+                               goto yy_match;
+                               }
+
+                       else
+                               {
+                               yy_cp = yy_c_buf_p;
+                               goto yy_find_action;
+                               }
+                       }
+
+               else switch ( yy_get_next_buffer() )
+                       {
+                       case EOB_ACT_END_OF_FILE:
+                               {
+                               yy_did_buffer_switch_on_eof = 0;
+
+                               if ( yywrap() )
+                                       {
+                                       /* Note: because we've taken care in
+                                        * yy_get_next_buffer() to have set up
+                                        * yytext, we can now set up
+                                        * yy_c_buf_p so that if some total
+                                        * hoser (like flex itself) wants to
+                                        * call the scanner after we return the
+                                        * YY_NULL, it'll still work - another
+                                        * YY_NULL will get returned.
+                                        */
+                                       yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+                                       yy_act = YY_STATE_EOF(YY_START);
+                                       goto do_action;
+                                       }
+
+                               else
+                                       {
+                                       if ( ! yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+                                       }
+                               break;
+                               }
+
+                       case EOB_ACT_CONTINUE_SCAN:
+                               yy_c_buf_p =
+                                       yytext_ptr + yy_amount_of_matched_text;
+
+                               yy_current_state = yy_get_previous_state();
+
+                               yy_cp = yy_c_buf_p;
+                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               goto yy_match;
+
+                       case EOB_ACT_LAST_MATCH:
+                               yy_c_buf_p =
+                               &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+                               yy_current_state = yy_get_previous_state();
+
+                               yy_cp = yy_c_buf_p;
+                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               goto yy_find_action;
+                       }
+               break;
+               }
+
+       default:
+               YY_FATAL_ERROR(
+                       "fatal flex scanner internal error--no action found" );
+       } /* end of action switch */
+               } /* end of scanning one token */
+       } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *     EOB_ACT_LAST_MATCH -
+ *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *     EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+       {
+       register char *dest = yy_current_buffer->yy_ch_buf;
+       register char *source = yytext_ptr;
+       register int number_to_move, i;
+       int ret_val;
+
+       if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+               YY_FATAL_ERROR(
+               "fatal flex scanner internal error--end of buffer missed" );
+
+       if ( yy_current_buffer->yy_fill_buffer == 0 )
+               { /* Don't try to fill the buffer, so this is an EOF. */
+               if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+                       {
+                       /* We matched a singled characater, the EOB, so
+                        * treat this as a final EOF.
+                        */
+                       return EOB_ACT_END_OF_FILE;
+                       }
+
+               else
+                       {
+                       /* We matched some text prior to the EOB, first
+                        * process it.
+                        */
+                       return EOB_ACT_LAST_MATCH;
+                       }
+               }
+
+       /* Try to read more data. */
+
+       /* First move last chars to start of buffer. */
+       number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+       for ( i = 0; i < number_to_move; ++i )
+               *(dest++) = *(source++);
+
+       if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+               /* don't do the read, it's not guaranteed to return an EOF,
+                * just force an EOF
+                */
+               yy_n_chars = 0;
+
+       else
+               {
+               int num_to_read =
+                       yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+               while ( num_to_read <= 0 )
+                       { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+                       YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+                       /* just a shorter name for the current buffer */
+                       YY_BUFFER_STATE b = yy_current_buffer;
+
+                       int yy_c_buf_p_offset =
+                               (int) (yy_c_buf_p - b->yy_ch_buf);
+
+                       if ( b->yy_is_our_buffer )
+                               {
+                               int old_size = b->yy_buf_size + 2;
+                               int new_size = b->yy_buf_size * 2;
+
+                               if ( new_size <= 0 )
+                                       b->yy_buf_size += b->yy_buf_size / 8;
+                               else
+                                       b->yy_buf_size *= 2;
+
+                               b->yy_ch_buf = (char *)
+                                       /* Include room in for 2 EOB chars. */
+                                       yy_flex_realloc2( (genericptr_t) b->yy_ch_buf,
+                                                        b->yy_buf_size + 2, old_size );
+                               }
+                       else
+                               /* Can't grow it, we don't own it. */
+                               b->yy_ch_buf = 0;
+
+                       if ( ! b->yy_ch_buf )
+                               YY_FATAL_ERROR(
+                               "fatal error - scanner input buffer overflow" );
+
+                       yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+                       num_to_read = yy_current_buffer->yy_buf_size -
+                                               number_to_move - 1;
+#endif
+                       }
+
+               if ( num_to_read > YY_READ_BUF_SIZE )
+                       num_to_read = YY_READ_BUF_SIZE;
+
+               /* Read in more data. */
+               YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+                       yy_n_chars, num_to_read );
+               }
+
+       if ( yy_n_chars == 0 )
+               {
+               if ( number_to_move == YY_MORE_ADJ )
+                       {
+                       ret_val = EOB_ACT_END_OF_FILE;
+                       yyrestart( yyin );
+                       }
+
+               else
+                       {
+                       ret_val = EOB_ACT_LAST_MATCH;
+                       yy_current_buffer->yy_buffer_status =
+                               YY_BUFFER_EOF_PENDING;
+                       }
+               }
+
+       else
+               ret_val = EOB_ACT_CONTINUE_SCAN;
+
+       yy_n_chars += number_to_move;
+       yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+       yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+       yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+       return ret_val;
+       }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+       {
+       register yy_state_type yy_current_state;
+       register char *yy_cp;
+
+       yy_current_state = yy_start;
+       yy_current_state += YY_AT_BOL();
+
+       for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+               {
+               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+               if ( yy_accept[yy_current_state] )
+                       {
+                       yy_last_accepting_state = yy_current_state;
+                       yy_last_accepting_cpos = yy_cp;
+                       }
+               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                       {
+                       yy_current_state = (int) yy_def[yy_current_state];
+                       if ( yy_current_state >= 196 )
+                               yy_c = yy_meta[(unsigned int) yy_c];
+                       }
+               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+               }
+
+       return yy_current_state;
+       }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *     next_state = yy_try_NUL_trans( current_state );
+ */
+
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+       {
+       register int yy_is_jam;
+       register char *yy_cp = yy_c_buf_p;
+
+       register YY_CHAR yy_c = 1;
+       if ( yy_accept[yy_current_state] )
+               {
+               yy_last_accepting_state = yy_current_state;
+               yy_last_accepting_cpos = yy_cp;
+               }
+       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+               {
+               yy_current_state = (int) yy_def[yy_current_state];
+               if ( yy_current_state >= 196 )
+                       yy_c = yy_meta[(unsigned int) yy_c];
+               }
+       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+       yy_is_jam = (yy_current_state == 195);
+
+       return yy_is_jam ? 0 : yy_current_state;
+       }
+
+
+#ifndef YY_NO_UNPUT
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+       {
+       register char *yy_cp = yy_c_buf_p;
+
+       /* undo effects of setting up yytext */
+       *yy_cp = yy_hold_char;
+
+       if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+               { /* need to shift things up to make room */
+               /* +2 for EOB chars. */
+               register int number_to_move = yy_n_chars + 2;
+               register char *dest = &yy_current_buffer->yy_ch_buf[
+                                       yy_current_buffer->yy_buf_size + 2];
+               register char *source =
+                               &yy_current_buffer->yy_ch_buf[number_to_move];
+
+               while ( source > yy_current_buffer->yy_ch_buf )
+                       *--dest = *--source;
+
+               yy_cp += (int) (dest - source);
+               yy_bp += (int) (dest - source);
+               yy_n_chars = yy_current_buffer->yy_buf_size;
+
+               if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
+               }
+
+       *--yy_cp = (char) c;
+
+
+       yytext_ptr = yy_bp;
+       yy_hold_char = *yy_cp;
+       yy_c_buf_p = yy_cp;
+       }
+#endif /* ifndef YY_NO_UNPUT */
+
+
+static int input()
+       {
+       int c;
+
+       *yy_c_buf_p = yy_hold_char;
+
+       if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+               {
+               /* yy_c_buf_p now points to the character we want to return.
+                * If this occurs *before* the EOB characters, then it's a
+                * valid NUL; if not, then we've hit the end of the buffer.
+                */
+               if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+                       /* This was really a NUL. */
+                       *yy_c_buf_p = '\0';
+
+               else
+                       { /* need more input */
+                       yytext_ptr = yy_c_buf_p;
+                       ++yy_c_buf_p;
+
+                       switch ( yy_get_next_buffer() )
+                               {
+                               case EOB_ACT_END_OF_FILE:
+                                       {
+                                       if ( yywrap() )
+                                               {
+                                               yy_c_buf_p =
+                                               yytext_ptr + YY_MORE_ADJ;
+                                               return EOF;
+                                               }
+
+                                       if ( ! yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+                                       return input();
+                                       }
+
+                               case EOB_ACT_CONTINUE_SCAN:
+                                       yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+                                       break;
+
+                               case EOB_ACT_LAST_MATCH:
+                                       YY_FATAL_ERROR(
+                                       "unexpected last match in input()" );
+                               }
+                       }
+               }
+
+       c = *(unsigned char *) yy_c_buf_p;      /* cast for 8-bit char's */
+       *yy_c_buf_p = '\0';     /* preserve yytext */
+       yy_hold_char = *++yy_c_buf_p;
+
+       yy_current_buffer->yy_at_bol = (c == '\n');
+
+       return c;
+       }
+
+
+void yyrestart( input_file )
+FILE *input_file;
+       {
+       if ( ! yy_current_buffer )
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+       yy_init_buffer( yy_current_buffer, input_file );
+       yy_load_buffer_state();
+       }
+
+
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+       {
+       if ( yy_current_buffer == new_buffer )
+               return;
+
+       if ( yy_current_buffer )
+               {
+               /* Flush out information for old buffer. */
+               *yy_c_buf_p = yy_hold_char;
+               yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+               yy_current_buffer->yy_n_chars = yy_n_chars;
+               }
+
+       yy_current_buffer = new_buffer;
+       yy_load_buffer_state();
+
+       /* We don't actually know whether we did this switch during
+        * EOF (yywrap()) processing, but the only time this flag
+        * is looked at is after yywrap() is called, so it's safe
+        * to go ahead and always set it.
+        */
+       yy_did_buffer_switch_on_eof = 1;
+       }
+
+
+void yy_load_buffer_state()
+       {
+       yy_n_chars = yy_current_buffer->yy_n_chars;
+       yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+       yyin = yy_current_buffer->yy_input_file;
+       yy_hold_char = *yy_c_buf_p;
+       }
+
+
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+       {
+       YY_BUFFER_STATE b;
+
+       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_buf_size = size;
+
+       /* yy_ch_buf has to be 2 characters longer than the size given because
+        * we need to put in 2 end-of-buffer characters.
+        */
+       b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+       if ( ! b->yy_ch_buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_is_our_buffer = 1;
+
+       yy_init_buffer( b, file );
+
+       return b;
+       }
+
+
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+       {
+       if ( ! b )
+               return;
+
+       if ( b == yy_current_buffer )
+               yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+       if ( b->yy_is_our_buffer )
+               yy_flex_free( (genericptr_t) b->yy_ch_buf );
+
+       yy_flex_free( (genericptr_t) b );
+       }
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int FDECL(isatty, (int));
+#endif
+#endif
+
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+       {
+       yy_flush_buffer( b );
+
+       b->yy_input_file = file;
+       b->yy_fill_buffer = 1;
+
+#ifdef YY_ALWAYS_INTERACTIVE
+       b->yy_is_interactive = 1;
+#else
+#ifdef YY_NEVER_INTERACTIVE
+       b->yy_is_interactive = 0;
+#else
+       b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+       }
+
+
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+       {
+       b->yy_n_chars = 0;
+
+       /* We always need two end-of-buffer characters.  The first causes
+        * a transition to the end-of-buffer state.  The second causes
+        * a jam in that state.
+        */
+       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+       b->yy_buf_pos = &b->yy_ch_buf[0];
+
+       b->yy_at_bol = 1;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       if ( b == yy_current_buffer )
+               yy_load_buffer_state();
+       }
+
+
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error( msg )
+const char msg[];
+       {
+       (void) fprintf( stderr, "%s\n", msg );
+       exit( YY_EXIT_FAILURE );
+       }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+               yytext[yyleng] = yy_hold_char; \
+               yy_c_buf_p = yytext + n - YY_MORE_ADJ; \
+               yy_hold_char = *yy_c_buf_p; \
+               *yy_c_buf_p = '\0'; \
+               yyleng = n; \
+               } \
+       while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+const char *s2;
+int n;
+       {
+       register int i;
+       for ( i = 0; i < n; ++i )
+               s1[i] = s2[i];
+       }
+#endif
+
+
+static genericptr_t yy_flex_alloc( size )
+yy_size_t size;
+       {
+       return (genericptr_t) alloc((unsigned)size);
+       }
+
+/* we want to avoid use of realloc(), so we require that caller supply the
+   size of the old block of memory */
+static genericptr_t yy_flex_realloc2( ptr, size, old_size )
+genericptr_t ptr;
+yy_size_t size;
+int old_size;
+       {
+       genericptr_t outptr = yy_flex_alloc(size);
+
+       if (ptr) {
+           char *p = (char *) outptr, *q = (char *) ptr;
+
+           while (--old_size >= 0) *p++ = *q++;
+           yy_flex_free(ptr);
+       }
+       return outptr;
+       }
+
+static void yy_flex_free( ptr )
+genericptr_t ptr;
+       {
+       free( ptr );
+       }
+
+/*flexhack.skl*/
+
+
+/* routine to switch to another input file; needed for flex */
+void init_yyin( input_f )
+FILE *input_f;
+{
+#if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER)
+       if (yyin)
+           yyrestart(input_f);
+       else
+#endif
+           yyin = input_f;
+}
+/* analogous routine (for completeness) */
+void init_yyout( output_f )
+FILE *output_f;
+{
+       yyout = output_f;
+}
+
+/*dgn_comp.l*/
diff --git a/sys/share/dgn_yacc.c b/sys/share/dgn_yacc.c
new file mode 100644 (file)
index 0000000..fe5657b
--- /dev/null
@@ -0,0 +1,1054 @@
+#ifndef lint
+static char yysccsid[] = "@(#)yaccpar  1.9 (Berkeley) 02/21/93";
+#endif
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define yyclearin (yychar=(-1))
+#define yyerrok (yyerrflag=0)
+#define YYRECOVERING (yyerrflag!=0)
+#define YYPREFIX "yy"
+/*     SCCS Id: @(#)dgn_comp.c 3.4     1996/06/22      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet */
+/*     Copyright (c) 1990 by M. Stephenson                               */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file contains the Dungeon Compiler code
+ */
+
+/* In case we're using bison in AIX.  This definition must be
+ * placed before any other C-language construct in the file
+ * excluding comments and preprocessor directives (thanks IBM
+ * for this wonderful feature...).
+ *
+ * Note: some cpps barf on this 'undefined control' (#pragma).
+ * Addition of the leading space seems to prevent barfage for now,
+ * and AIX will still see the directive in its non-standard locale.
+ */
+
+#ifdef _AIX
+ #pragma alloca                /* keep leading space! */
+#endif
+
+#include "config.h"
+#include "date.h"
+#include "dgn_file.h"
+
+void FDECL(yyerror, (const char *));
+void FDECL(yywarning, (const char *));
+int NDECL(yylex);
+int NDECL(yyparse);
+int FDECL(getchain, (char *));
+int NDECL(check_dungeon);
+int NDECL(check_branch);
+int NDECL(check_level);
+void NDECL(init_dungeon);
+void NDECL(init_branch);
+void NDECL(init_level);
+void NDECL(output_dgn);
+
+#define Free(ptr)              free((genericptr_t)ptr)
+
+#ifdef AMIGA
+# undef        printf
+#ifndef        LATTICE
+# define    memset(addr,val,len)    setmem(addr,len,val)
+#endif
+#endif
+
+#define ERR            (-1)
+
+static struct couple couple;
+static struct tmpdungeon tmpdungeon[MAXDUNGEON];
+static struct tmplevel tmplevel[LEV_LIMIT];
+static struct tmpbranch tmpbranch[BRANCH_LIMIT];
+
+static int in_dungeon = 0, n_dgns = -1, n_levs = -1, n_brs = -1;
+
+extern int fatal_error;
+extern const char *fname;
+extern FILE *yyin, *yyout;     /* from dgn_lex.c */
+
+typedef union
+{
+       int     i;
+       char*   str;
+} YYSTYPE;
+#define INTEGER 257
+#define A_DUNGEON 258
+#define BRANCH 259
+#define CHBRANCH 260
+#define LEVEL 261
+#define RNDLEVEL 262
+#define CHLEVEL 263
+#define RNDCHLEVEL 264
+#define UP_OR_DOWN 265
+#define PROTOFILE 266
+#define DESCRIPTION 267
+#define DESCRIPTOR 268
+#define LEVELDESC 269
+#define ALIGNMENT 270
+#define LEVALIGN 271
+#define ENTRY 272
+#define STAIR 273
+#define NO_UP 274
+#define NO_DOWN 275
+#define PORTAL 276
+#define STRING 277
+#define YYERRCODE 256
+short yylhs[] = {                                        -1,
+    0,    0,    5,    5,    6,    6,    6,    6,    7,    1,
+    1,    8,    8,    8,   12,   13,   15,   15,   14,   10,
+   10,   10,   10,   10,   16,   16,   17,   17,   18,   18,
+   19,   19,   20,   20,    9,    9,   22,   23,    3,    3,
+    3,    3,    3,    2,    2,    4,   21,   11,
+};
+short yylen[] = {                                         2,
+    0,    1,    1,    2,    1,    1,    1,    1,    6,    0,
+    1,    1,    1,    1,    3,    1,    3,    3,    3,    1,
+    1,    1,    1,    1,    6,    7,    7,    8,    3,    3,
+    7,    8,    8,    9,    1,    1,    7,    8,    0,    1,
+    1,    1,    1,    0,    1,    1,    5,    5,
+};
+short yydefred[] = {                                      0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    3,    5,    6,    7,    8,
+   12,   13,   14,   16,   20,   21,   22,   23,   24,   35,
+   36,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    4,    0,    0,    0,    0,    0,
+    0,    0,   19,   17,   29,   18,   30,   15,   46,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   11,    9,    0,   40,
+   41,   42,   43,    0,    0,    0,    0,    0,    0,    0,
+    0,   45,   37,    0,   27,    0,    0,    0,    0,    0,
+   38,   28,   33,    0,   48,   47,   34,
+};
+short yydgoto[] = {                                      14,
+   78,   93,   84,   60,   15,   16,   17,   18,   19,   20,
+   68,   21,   22,   23,   24,   25,   26,   27,   28,   29,
+   70,   30,   31,
+};
+short yysindex[] = {                                   -237,
+  -46,  -45,  -44,  -39,  -38,  -30,  -22,  -21,  -20,  -19,
+  -18,  -17,  -16,    0, -237,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0, -262, -234, -233, -232, -230, -229, -228, -227, -217,
+ -216, -215, -214, -202,    0, -221,   -7, -219, -221, -221,
+ -221, -221,    0,    0,    0,    0,    0,    0,    0,   19,
+   20,   21,   -2,   -1, -212, -211, -190, -189, -188, -271,
+   19,   20,   20,   27,   28,   29,    0,    0,   30,    0,
+    0,    0,    0, -193, -271, -182, -180,   19,   19, -179,
+ -178,    0,    0, -193,    0, -177, -176, -175,   42,   43,
+    0,    0,    0, -172,    0,    0,    0,
+};
+short yyrindex[] = {                                     86,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,   87,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,   16,    0,    1,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,   31,    1,   46,    0,    0,    0,    0,
+    0,    0,    0,   31,    0,   61,   76,    0,    0,    0,
+    0,    0,    0,   91,    0,    0,    0,
+};
+short yygindex[] = {                                      0,
+    0,   -6,    4,  -43,    0,   75,    0,    0,    0,    0,
+  -71,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+  -62,    0,    0,
+};
+#define YYTABLESIZE 363
+short yytable[] = {                                      85,
+   39,   80,   81,   82,   83,   63,   64,   65,   66,   86,
+   87,   32,   33,   34,   46,   10,   97,   98,   35,   36,
+    1,    2,    3,    4,    5,    6,    7,   37,    8,    9,
+   44,   10,   11,   12,   13,   38,   39,   40,   41,   42,
+   43,   44,   47,   48,   49,   25,   50,   51,   52,   53,
+   54,   55,   56,   57,   58,   59,   61,   62,   67,   69,
+   26,   72,   73,   71,   74,   75,   76,   77,   79,   88,
+   89,   92,   90,   91,   95,   31,   96,   99,  100,  102,
+  103,  104,  105,  106,  107,    1,    2,  101,   94,   45,
+   32,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   39,   39,
+   39,   39,   39,   39,   39,   39,   39,   39,    0,   39,
+   39,   39,   39,   10,   10,   10,   10,   10,   10,   10,
+    0,   10,   10,    0,   10,   10,   10,   10,   44,   44,
+   44,   44,   44,   44,   44,    0,   44,   44,    0,   44,
+   44,   44,   44,   25,   25,   25,   25,   25,   25,   25,
+    0,   25,   25,    0,   25,   25,   25,   25,   26,   26,
+   26,   26,   26,   26,   26,    0,   26,   26,    0,   26,
+   26,   26,   26,   31,   31,   31,   31,   31,   31,   31,
+    0,   31,   31,    0,   31,   31,   31,   31,   32,   32,
+   32,   32,   32,   32,   32,    0,   32,   32,    0,   32,
+   32,   32,   32,
+};
+short yycheck[] = {                                      71,
+    0,  273,  274,  275,  276,   49,   50,   51,   52,   72,
+   73,   58,   58,   58,  277,    0,   88,   89,   58,   58,
+  258,  259,  260,  261,  262,  263,  264,   58,  266,  267,
+    0,  269,  270,  271,  272,   58,   58,   58,   58,   58,
+   58,   58,  277,  277,  277,    0,  277,  277,  277,  277,
+  268,  268,  268,  268,  257,  277,   64,  277,   40,   40,
+    0,   64,   64,   43,  277,  277,  257,  257,  257,   43,
+   43,  265,   44,   44,  257,    0,  257,  257,  257,  257,
+  257,  257,   41,   41,  257,    0,    0,   94,   85,   15,
+    0,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  258,  259,
+  260,  261,  262,  263,  264,  265,  266,  267,   -1,  269,
+  270,  271,  272,  258,  259,  260,  261,  262,  263,  264,
+   -1,  266,  267,   -1,  269,  270,  271,  272,  258,  259,
+  260,  261,  262,  263,  264,   -1,  266,  267,   -1,  269,
+  270,  271,  272,  258,  259,  260,  261,  262,  263,  264,
+   -1,  266,  267,   -1,  269,  270,  271,  272,  258,  259,
+  260,  261,  262,  263,  264,   -1,  266,  267,   -1,  269,
+  270,  271,  272,  258,  259,  260,  261,  262,  263,  264,
+   -1,  266,  267,   -1,  269,  270,  271,  272,  258,  259,
+  260,  261,  262,  263,  264,   -1,  266,  267,   -1,  269,
+  270,  271,  272,
+};
+#define YYFINAL 14
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 277
+#if YYDEBUG
+char *yyname[] = {
+"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,"'('","')'",0,"'+'","','",0,0,0,0,0,0,0,0,0,0,0,0,0,"':'",0,0,0,0,0,
+"'@'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"INTEGER",
+"A_DUNGEON","BRANCH","CHBRANCH","LEVEL","RNDLEVEL","CHLEVEL","RNDCHLEVEL",
+"UP_OR_DOWN","PROTOFILE","DESCRIPTION","DESCRIPTOR","LEVELDESC","ALIGNMENT",
+"LEVALIGN","ENTRY","STAIR","NO_UP","NO_DOWN","PORTAL","STRING",
+};
+char *yyrule[] = {
+"$accept : file",
+"file :",
+"file : dungeons",
+"dungeons : dungeon",
+"dungeons : dungeons dungeon",
+"dungeon : dungeonline",
+"dungeon : dungeondesc",
+"dungeon : branches",
+"dungeon : levels",
+"dungeonline : A_DUNGEON ':' STRING bones_tag rcouple optional_int",
+"optional_int :",
+"optional_int : INTEGER",
+"dungeondesc : entry",
+"dungeondesc : descriptions",
+"dungeondesc : prototype",
+"entry : ENTRY ':' INTEGER",
+"descriptions : desc",
+"desc : DESCRIPTION ':' DESCRIPTOR",
+"desc : ALIGNMENT ':' DESCRIPTOR",
+"prototype : PROTOFILE ':' STRING",
+"levels : level1",
+"levels : level2",
+"levels : levdesc",
+"levels : chlevel1",
+"levels : chlevel2",
+"level1 : LEVEL ':' STRING bones_tag '@' acouple",
+"level1 : RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER",
+"level2 : LEVEL ':' STRING bones_tag '@' acouple INTEGER",
+"level2 : RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER INTEGER",
+"levdesc : LEVELDESC ':' DESCRIPTOR",
+"levdesc : LEVALIGN ':' DESCRIPTOR",
+"chlevel1 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple",
+"chlevel1 : RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER",
+"chlevel2 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER",
+"chlevel2 : RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER INTEGER",
+"branches : branch",
+"branches : chbranch",
+"branch : BRANCH ':' STRING '@' acouple branch_type direction",
+"chbranch : CHBRANCH ':' STRING STRING '+' rcouple branch_type direction",
+"branch_type :",
+"branch_type : STAIR",
+"branch_type : NO_UP",
+"branch_type : NO_DOWN",
+"branch_type : PORTAL",
+"direction :",
+"direction : UP_OR_DOWN",
+"bones_tag : STRING",
+"acouple : '(' INTEGER ',' INTEGER ')'",
+"rcouple : '(' INTEGER ',' INTEGER ')'",
+};
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 500
+#define YYMAXDEPTH 500
+#endif
+#endif
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+short yyss[YYSTACKSIZE];
+YYSTYPE yyvs[YYSTACKSIZE];
+#define yystacksize YYSTACKSIZE
+
+void
+init_dungeon()
+{
+       if(++n_dgns > MAXDUNGEON) {
+           (void) fprintf(stderr, "FATAL - Too many dungeons (limit: %d).\n",
+                   MAXDUNGEON);
+           (void) fprintf(stderr, "To increase the limit edit MAXDUNGEON in global.h\n");
+           exit(EXIT_FAILURE);
+       }
+
+       in_dungeon = 1;
+       tmpdungeon[n_dgns].lev.base = 0;
+       tmpdungeon[n_dgns].lev.rand = 0;
+       tmpdungeon[n_dgns].chance = 100;
+       Strcpy(tmpdungeon[n_dgns].name, "");
+       Strcpy(tmpdungeon[n_dgns].protoname, "");
+       tmpdungeon[n_dgns].flags = 0;
+       tmpdungeon[n_dgns].levels = 0;
+       tmpdungeon[n_dgns].branches = 0;
+       tmpdungeon[n_dgns].entry_lev = 0;
+}
+
+void
+init_level()
+{
+       if(++n_levs > LEV_LIMIT) {
+
+               yyerror("FATAL - Too many special levels defined.");
+               exit(EXIT_FAILURE);
+       }
+       tmplevel[n_levs].lev.base = 0;
+       tmplevel[n_levs].lev.rand = 0;
+       tmplevel[n_levs].chance = 100;
+       tmplevel[n_levs].rndlevs = 0;
+       tmplevel[n_levs].flags = 0;
+       Strcpy(tmplevel[n_levs].name, "");
+       tmplevel[n_levs].chain = -1;
+}
+
+void
+init_branch()
+{
+       if(++n_brs > BRANCH_LIMIT) {
+
+               yyerror("FATAL - Too many special levels defined.");
+               exit(EXIT_FAILURE);
+       }
+       tmpbranch[n_brs].lev.base = 0;
+       tmpbranch[n_brs].lev.rand = 0;
+       Strcpy(tmpbranch[n_brs].name, "");
+       tmpbranch[n_brs].chain = -1;
+}
+
+int
+getchain(s)
+       char    *s;
+{
+       int i;
+
+       if(strlen(s)) {
+
+           for(i = n_levs - tmpdungeon[n_dgns].levels + 1; i <= n_levs; i++)
+               if(!strcmp(tmplevel[i].name, s)) return i;
+
+           yyerror("Can't locate the specified chain level.");
+           return(-2);
+       }
+       return(-1);
+}
+
+/*
+ *     Consistancy checking routines:
+ *
+ *     - A dungeon must have a unique name.
+ *     - A dungeon must have a originating "branch" command
+ *       (except, of course, for the first dungeon).
+ *     - A dungeon must have a proper depth (at least (1, 0)).
+ */
+
+int
+check_dungeon()
+{
+       int i;
+
+       for(i = 0; i < n_dgns; i++)
+           if(!strcmp(tmpdungeon[i].name, tmpdungeon[n_dgns].name)) {
+               yyerror("Duplicate dungeon name.");
+               return(0);
+           }
+
+       if(n_dgns)
+         for(i = 0; i < n_brs - tmpdungeon[n_dgns].branches; i++) {
+           if(!strcmp(tmpbranch[i].name, tmpdungeon[n_dgns].name)) break;
+
+           if(i >= n_brs - tmpdungeon[n_dgns].branches) {
+               yyerror("Dungeon cannot be reached.");
+               return(0);
+           }
+         }
+
+       if(tmpdungeon[n_dgns].lev.base <= 0 ||
+          tmpdungeon[n_dgns].lev.rand < 0) {
+               yyerror("Invalid dungeon depth specified.");
+               return(0);
+       }
+       return(1);      /* OK */
+}
+
+/*
+ *     - A level must have a unique level name.
+ *     - If chained, the level used as reference for the chain
+ *       must be in this dungeon, must be previously defined, and
+ *       the level chained from must be "non-probabilistic" (ie.
+ *       have a 100% chance of existing).
+ */
+
+int
+check_level()
+{
+       int i;
+
+       if(!in_dungeon) {
+               yyerror("Level defined outside of dungeon.");
+               return(0);
+       }
+
+       for(i = 0; i < n_levs; i++)
+           if(!strcmp(tmplevel[i].name, tmplevel[n_levs].name)) {
+               yyerror("Duplicate level name.");
+               return(0);
+           }
+
+       if(tmplevel[i].chain == -2) {
+               yyerror("Invaild level chain reference.");
+               return(0);
+       } else if(tmplevel[i].chain != -1) {    /* there is a chain */
+           /* KMH -- tmplevel[tmpbranch[i].chain].chance was in error */
+           if(tmplevel[tmplevel[i].chain].chance != 100) {
+               yyerror("Level cannot chain from a probabilistic level.");
+               return(0);
+           } else if(tmplevel[i].chain == n_levs) {
+               yyerror("A level cannot chain to itself!");
+               return(0);
+           }
+       }
+       return(1);      /* OK */
+}
+
+/*
+ *     - A branch may not branch backwards - to avoid branch loops.
+ *     - A branch name must be unique.
+ *       (ie. You can only have one entry point to each dungeon).
+ *     - If chained, the level used as reference for the chain
+ *       must be in this dungeon, must be previously defined, and
+ *       the level chained from must be "non-probabilistic" (ie.
+ *       have a 100% chance of existing).
+ */
+
+int
+check_branch()
+{
+       int i;
+
+       if(!in_dungeon) {
+               yyerror("Branch defined outside of dungeon.");
+               return(0);
+       }
+
+       for(i = 0; i < n_dgns; i++)
+           if(!strcmp(tmpdungeon[i].name, tmpbranch[n_brs].name)) {
+
+               yyerror("Reverse branching not allowed.");
+               return(0);
+           }
+
+       if(tmpbranch[i].chain == -2) {
+
+               yyerror("Invaild branch chain reference.");
+               return(0);
+       } else if(tmpbranch[i].chain != -1) {   /* it is chained */
+
+           if(tmplevel[tmpbranch[i].chain].chance != 100) {
+               yyerror("Branch cannot chain from a probabilistic level.");
+               return(0);
+           }
+       }
+       return(1);      /* OK */
+}
+
+/*
+ *     Output the dungon definition into a file.
+ *
+ *     The file will have the following format:
+ *
+ *     [ nethack version ID ]
+ *     [ number of dungeons ]
+ *     [ first dungeon struct ]
+ *     [ levels for the first dungeon ]
+ *       ...
+ *     [ branches for the first dungeon ]
+ *       ...
+ *     [ second dungeon struct ]
+ *       ...
+ */
+
+void
+output_dgn()
+{
+       int     nd, cl = 0, nl = 0,
+                   cb = 0, nb = 0;
+       static struct version_info version_data = {
+                       VERSION_NUMBER, VERSION_FEATURES,
+                       VERSION_SANITY1, VERSION_SANITY2
+       };
+
+       if(++n_dgns <= 0) {
+           yyerror("FATAL - no dungeons were defined.");
+           exit(EXIT_FAILURE);
+       }
+
+       if (fwrite((char *)&version_data, sizeof version_data, 1, yyout) != 1) {
+           yyerror("FATAL - output failure.");
+           exit(EXIT_FAILURE);
+       }
+
+       (void) fwrite((char *)&n_dgns, sizeof(int), 1, yyout);
+       for (nd = 0; nd < n_dgns; nd++) {
+           (void) fwrite((char *)&tmpdungeon[nd], sizeof(struct tmpdungeon),
+                                                       1, yyout);
+
+           nl += tmpdungeon[nd].levels;
+           for(; cl < nl; cl++)
+               (void) fwrite((char *)&tmplevel[cl], sizeof(struct tmplevel),
+                                                       1, yyout);
+
+           nb += tmpdungeon[nd].branches;
+           for(; cb < nb; cb++)
+               (void) fwrite((char *)&tmpbranch[cb], sizeof(struct tmpbranch),
+                                                       1, yyout);
+       }
+       /* apparently necessary for Think C 5.x, otherwise harmless */
+       (void) fflush(yyout);
+}
+
+/*dgn_comp.y*/
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+yyparse()
+{
+    register int yym, yyn, yystate;
+#if YYDEBUG
+    register char *yys;
+    extern char *getenv();
+
+    if ((yys = getenv("YYDEBUG")) != 0)
+    {
+        yyn = *yys;
+        if (yyn >= '0' && yyn <= '9')
+            yydebug = yyn - '0';
+    }
+#endif
+
+    yynerrs = 0;
+    yyerrflag = 0;
+    yychar = (-1);
+
+    yyssp = yyss;
+    yyvsp = yyvs;
+    *yyssp = yystate = 0;
+
+yyloop:
+    if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
+    if (yychar < 0)
+    {
+        if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, reading %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+    }
+    if ((yyn = yysindex[yystate]) != 0 && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: state %d, shifting to state %d\n",
+                    YYPREFIX, yystate, yytable[yyn]);
+#endif
+        if (yyssp >= yyss + yystacksize - 1)
+        {
+            goto yyoverflow;
+        }
+        *++yyssp = yystate = yytable[yyn];
+        *++yyvsp = yylval;
+        yychar = (-1);
+        if (yyerrflag > 0)  --yyerrflag;
+        goto yyloop;
+    }
+    if ((yyn = yyrindex[yystate]) != 0 && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+        yyn = yytable[yyn];
+        goto yyreduce;
+    }
+    if (yyerrflag) goto yyinrecovery;
+#ifdef lint
+    goto yynewerror;
+#endif
+yynewerror:
+    yyerror("syntax error");
+#ifdef lint
+    goto yyerrlab;
+#endif
+yyerrlab:
+    ++yynerrs;
+yyinrecovery:
+    if (yyerrflag < 3)
+    {
+        yyerrflag = 3;
+        for (;;)
+        {
+            if ((yyn = yysindex[*yyssp]) != 0 && (yyn += YYERRCODE) >= 0 &&
+                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
+#endif
+                if (yyssp >= yyss + yystacksize - 1)
+                {
+                    goto yyoverflow;
+                }
+                *++yyssp = yystate = yytable[yyn];
+                *++yyvsp = yylval;
+                goto yyloop;
+            }
+            else
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: error recovery discarding state %d\n",
+                            YYPREFIX, *yyssp);
+#endif
+                if (yyssp <= yyss) goto yyabort;
+                --yyssp;
+                --yyvsp;
+            }
+        }
+    }
+    else
+    {
+        if (yychar == 0) goto yyabort;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+        yychar = (-1);
+        goto yyloop;
+    }
+yyreduce:
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+                YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+    yym = yylen[yyn];
+    yyval = yyvsp[1-yym];
+    switch (yyn)
+    {
+case 2:
+{
+                       output_dgn();
+                 }
+break;
+case 9:
+{
+                       init_dungeon();
+                       Strcpy(tmpdungeon[n_dgns].name, yyvsp[-3].str);
+                       tmpdungeon[n_dgns].boneschar = (char)yyvsp[-2].i;
+                       tmpdungeon[n_dgns].lev.base = couple.base;
+                       tmpdungeon[n_dgns].lev.rand = couple.rand;
+                       tmpdungeon[n_dgns].chance = yyvsp[0].i;
+                       Free(yyvsp[-3].str);
+                 }
+break;
+case 10:
+{
+                       yyval.i = 0;
+                 }
+break;
+case 11:
+{
+                       yyval.i = yyvsp[0].i;
+                 }
+break;
+case 15:
+{
+                       tmpdungeon[n_dgns].entry_lev = yyvsp[0].i;
+                 }
+break;
+case 17:
+{
+                       if(yyvsp[0].i <= TOWN || yyvsp[0].i >= D_ALIGN_CHAOTIC)
+                           yyerror("Illegal description - ignoring!");
+                       else
+                           tmpdungeon[n_dgns].flags |= yyvsp[0].i ;
+                 }
+break;
+case 18:
+{
+                       if(yyvsp[0].i && yyvsp[0].i < D_ALIGN_CHAOTIC)
+                           yyerror("Illegal alignment - ignoring!");
+                       else
+                           tmpdungeon[n_dgns].flags |= yyvsp[0].i ;
+                 }
+break;
+case 19:
+{
+                       Strcpy(tmpdungeon[n_dgns].protoname, yyvsp[0].str);
+                       Free(yyvsp[0].str);
+                 }
+break;
+case 25:
+{
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, yyvsp[-3].str);
+                       tmplevel[n_levs].boneschar = (char)yyvsp[-2].i;
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmpdungeon[n_dgns].levels++;
+                       Free(yyvsp[-3].str);
+                 }
+break;
+case 26:
+{
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, yyvsp[-4].str);
+                       tmplevel[n_levs].boneschar = (char)yyvsp[-3].i;
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmplevel[n_levs].rndlevs = yyvsp[0].i;
+                       tmpdungeon[n_dgns].levels++;
+                       Free(yyvsp[-4].str);
+                 }
+break;
+case 27:
+{
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, yyvsp[-4].str);
+                       tmplevel[n_levs].boneschar = (char)yyvsp[-3].i;
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmplevel[n_levs].chance = yyvsp[0].i;
+                       tmpdungeon[n_dgns].levels++;
+                       Free(yyvsp[-4].str);
+                 }
+break;
+case 28:
+{
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, yyvsp[-5].str);
+                       tmplevel[n_levs].boneschar = (char)yyvsp[-4].i;
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmplevel[n_levs].chance = yyvsp[-1].i;
+                       tmplevel[n_levs].rndlevs = yyvsp[0].i;
+                       tmpdungeon[n_dgns].levels++;
+                       Free(yyvsp[-5].str);
+                 }
+break;
+case 29:
+{
+                       if(yyvsp[0].i >= D_ALIGN_CHAOTIC)
+                           yyerror("Illegal description - ignoring!");
+                       else
+                           tmplevel[n_levs].flags |= yyvsp[0].i ;
+                 }
+break;
+case 30:
+{
+                       if(yyvsp[0].i && yyvsp[0].i < D_ALIGN_CHAOTIC)
+                           yyerror("Illegal alignment - ignoring!");
+                       else
+                           tmplevel[n_levs].flags |= yyvsp[0].i ;
+                 }
+break;
+case 31:
+{
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, yyvsp[-4].str);
+                       tmplevel[n_levs].boneschar = (char)yyvsp[-3].i;
+                       tmplevel[n_levs].chain = getchain(yyvsp[-2].str);
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       if(!check_level()) n_levs--;
+                       else tmpdungeon[n_dgns].levels++;
+                       Free(yyvsp[-4].str);
+                       Free(yyvsp[-2].str);
+                 }
+break;
+case 32:
+{
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, yyvsp[-5].str);
+                       tmplevel[n_levs].boneschar = (char)yyvsp[-4].i;
+                       tmplevel[n_levs].chain = getchain(yyvsp[-3].str);
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmplevel[n_levs].rndlevs = yyvsp[0].i;
+                       if(!check_level()) n_levs--;
+                       else tmpdungeon[n_dgns].levels++;
+                       Free(yyvsp[-5].str);
+                       Free(yyvsp[-3].str);
+                 }
+break;
+case 33:
+{
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, yyvsp[-5].str);
+                       tmplevel[n_levs].boneschar = (char)yyvsp[-4].i;
+                       tmplevel[n_levs].chain = getchain(yyvsp[-3].str);
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmplevel[n_levs].chance = yyvsp[0].i;
+                       if(!check_level()) n_levs--;
+                       else tmpdungeon[n_dgns].levels++;
+                       Free(yyvsp[-5].str);
+                       Free(yyvsp[-3].str);
+                 }
+break;
+case 34:
+{
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, yyvsp[-6].str);
+                       tmplevel[n_levs].boneschar = (char)yyvsp[-5].i;
+                       tmplevel[n_levs].chain = getchain(yyvsp[-4].str);
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmplevel[n_levs].chance = yyvsp[-1].i;
+                       tmplevel[n_levs].rndlevs = yyvsp[0].i;
+                       if(!check_level()) n_levs--;
+                       else tmpdungeon[n_dgns].levels++;
+                       Free(yyvsp[-6].str);
+                       Free(yyvsp[-4].str);
+                 }
+break;
+case 37:
+{
+                       init_branch();
+                       Strcpy(tmpbranch[n_brs].name, yyvsp[-4].str);
+                       tmpbranch[n_brs].lev.base = couple.base;
+                       tmpbranch[n_brs].lev.rand = couple.rand;
+                       tmpbranch[n_brs].type = yyvsp[-1].i;
+                       tmpbranch[n_brs].up = yyvsp[0].i;
+                       if(!check_branch()) n_brs--;
+                       else tmpdungeon[n_dgns].branches++;
+                       Free(yyvsp[-4].str);
+                 }
+break;
+case 38:
+{
+                       init_branch();
+                       Strcpy(tmpbranch[n_brs].name, yyvsp[-5].str);
+                       tmpbranch[n_brs].chain = getchain(yyvsp[-4].str);
+                       tmpbranch[n_brs].lev.base = couple.base;
+                       tmpbranch[n_brs].lev.rand = couple.rand;
+                       tmpbranch[n_brs].type = yyvsp[-1].i;
+                       tmpbranch[n_brs].up = yyvsp[0].i;
+                       if(!check_branch()) n_brs--;
+                       else tmpdungeon[n_dgns].branches++;
+                       Free(yyvsp[-5].str);
+                       Free(yyvsp[-4].str);
+                 }
+break;
+case 39:
+{
+                       yyval.i = TBR_STAIR;    /* two way stair */
+                 }
+break;
+case 40:
+{
+                       yyval.i = TBR_STAIR;    /* two way stair */
+                 }
+break;
+case 41:
+{
+                       yyval.i = TBR_NO_UP;    /* no up staircase */
+                 }
+break;
+case 42:
+{
+                       yyval.i = TBR_NO_DOWN;  /* no down staircase */
+                 }
+break;
+case 43:
+{
+                       yyval.i = TBR_PORTAL;   /* portal connection */
+                 }
+break;
+case 44:
+{
+                       yyval.i = 0;    /* defaults to down */
+                 }
+break;
+case 45:
+{
+                       yyval.i = yyvsp[0].i;
+                 }
+break;
+case 46:
+{
+                       char *p = yyvsp[0].str;
+                       if (strlen(p) != 1) {
+                           if (strcmp(p, "none") != 0)
+                  yyerror("Bones marker must be a single char, or \"none\"!");
+                           *p = '\0';
+                       }
+                       yyval.i = *p;
+                       Free(p);
+                 }
+break;
+case 47:
+{
+                       if (yyvsp[-3].i < -MAXLEVEL || yyvsp[-3].i > MAXLEVEL) {
+                           yyerror("Abs base out of dlevel range - zeroing!");
+                           couple.base = couple.rand = 0;
+                       } else if (yyvsp[-1].i < -1 ||
+                               ((yyvsp[-3].i < 0) ? (MAXLEVEL + yyvsp[-3].i + yyvsp[-1].i + 1) > MAXLEVEL :
+                                       (yyvsp[-3].i + yyvsp[-1].i) > MAXLEVEL)) {
+                           yyerror("Abs range out of dlevel range - zeroing!");
+                           couple.base = couple.rand = 0;
+                       } else {
+                           couple.base = yyvsp[-3].i;
+                           couple.rand = yyvsp[-1].i;
+                       }
+                 }
+break;
+case 48:
+{
+                       if (yyvsp[-3].i < -MAXLEVEL || yyvsp[-3].i > MAXLEVEL) {
+                           yyerror("Rel base out of dlevel range - zeroing!");
+                           couple.base = couple.rand = 0;
+                       } else {
+                           couple.base = yyvsp[-3].i;
+                           couple.rand = yyvsp[-1].i;
+                       }
+                 }
+break;
+    }
+    yyssp -= yym;
+    yystate = *yyssp;
+    yyvsp -= yym;
+    yym = yylhs[yyn];
+    if (yystate == 0 && yym == 0)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+        yystate = YYFINAL;
+        *++yyssp = YYFINAL;
+        *++yyvsp = yyval;
+        if (yychar < 0)
+        {
+            if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+            if (yydebug)
+            {
+                yys = 0;
+                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+                if (!yys) yys = "illegal-symbol";
+                printf("%sdebug: state %d, reading %d (%s)\n",
+                        YYPREFIX, YYFINAL, yychar, yys);
+            }
+#endif
+        }
+        if (yychar == 0) goto yyaccept;
+        goto yyloop;
+    }
+    if ((yyn = yygindex[yym]) != 0 && (yyn += yystate) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+        yystate = yytable[yyn];
+    else
+        yystate = yydgoto[yym];
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yyssp, yystate);
+#endif
+    if (yyssp >= yyss + yystacksize - 1)
+    {
+        goto yyoverflow;
+    }
+    *++yyssp = yystate;
+    *++yyvsp = yyval;
+    goto yyloop;
+yyoverflow:
+    yyerror("yacc stack overflow");
+yyabort:
+    return (1);
+yyaccept:
+    return (0);
+}
diff --git a/sys/share/ioctl.c b/sys/share/ioctl.c
new file mode 100644 (file)
index 0000000..8349281
--- /dev/null
@@ -0,0 +1,187 @@
+/*     SCCS Id: @(#)ioctl.c    3.4     1990/22/02 */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* This cannot be part of hack.tty.c (as it was earlier) since on some
+   systems (e.g. MUNIX) the include files <termio.h> and <sgtty.h>
+   define the same constants, and the C preprocessor complains. */
+
+#include "hack.h"
+
+#if defined(BSD_JOB_CONTROL) || defined(_BULL_SOURCE)
+# ifdef HPUX
+#include <bsdtty.h>
+# else
+#  if defined(AIX_31) && !defined(_ALL_SOURCE)
+#   define _ALL_SOURCE /* causes struct winsize to be present */
+#   ifdef _AIX32
+#    include <sys/ioctl.h>
+#   endif
+#  endif
+#  if defined(_BULL_SOURCE)
+#   include <termios.h>
+struct termios termio;
+#   undef TIMEOUT              /* defined in you.h and sys/tty.h */
+#   include <sys/tty.h>                /* define winsize */
+#   include <sys/ttold.h>      /* define struct ltchars */
+#   include <sys/bsdioctl.h>   /* define TIOGWINSZ */
+#  else
+#   ifdef LINUX
+#    include <bsd/sgtty.h>
+#   else
+#    include <sgtty.h>
+#   endif
+#  endif
+# endif
+struct ltchars ltchars;
+struct ltchars ltchars0 = { -1, -1, -1, -1, -1, -1 }; /* turn all off */
+#else
+
+# ifdef POSIX_TYPES
+#include <termios.h>
+struct termios termio;
+#  if defined(BSD) || defined(_AIX32)
+#   if defined(_AIX32) && !defined(_ALL_SOURCE)
+#    define _ALL_SOURCE
+#   endif
+#include <sys/ioctl.h>
+#  endif
+# else
+#include <termio.h>    /* also includes part of <sgtty.h> */
+#  if defined(TCSETS) && !defined(AIX_31)
+struct termios termio;
+#  else
+struct termio termio;
+#  endif
+# endif
+# ifdef AMIX
+#include <sys/ioctl.h>
+# endif /* AMIX */
+#endif
+
+#ifdef SUSPEND /* BSD isn't alone anymore... */
+#include       <signal.h>
+#endif
+
+#if defined(TIOCGWINSZ) && (defined(BSD) || defined(ULTRIX) || defined(AIX_31) || defined(_BULL_SOURCE) || defined(SVR4))
+#define USE_WIN_IOCTL
+#include "tcap.h"      /* for LI and CO */
+#endif
+
+#ifdef _M_UNIX
+extern void NDECL(sco_mapon);
+extern void NDECL(sco_mapoff);
+#endif
+#ifdef __linux__
+extern void NDECL(linux_mapon);
+extern void NDECL(linux_mapoff);
+#endif
+
+#ifdef AUX
+void
+catch_stp()
+{
+    signal(SIGTSTP, SIG_DFL);
+    dosuspend();
+}
+#endif /* AUX */
+
+void
+getwindowsz()
+{
+#ifdef USE_WIN_IOCTL
+    /*
+     * ttysize is found on Suns and BSD
+     * winsize is found on Suns, BSD, and Ultrix
+     */
+    struct winsize ttsz;
+
+    if (ioctl(fileno(stdin), (int)TIOCGWINSZ, (char *)&ttsz) != -1) {
+       /*
+        * Use the kernel's values for lines and columns if it has
+        * any idea.
+        */
+       if (ttsz.ws_row)
+           LI = ttsz.ws_row;
+       if (ttsz.ws_col)
+           CO = ttsz.ws_col;
+    }
+#endif
+}
+
+void
+getioctls()
+{
+#ifdef BSD_JOB_CONTROL
+       (void) ioctl(fileno(stdin), (int) TIOCGLTC, (char *) &ltchars);
+       (void) ioctl(fileno(stdin), (int) TIOCSLTC, (char *) &ltchars0);
+#else
+# ifdef POSIX_TYPES
+       (void) tcgetattr(fileno(stdin), &termio);
+# else
+#  if defined(TCSETS) && !defined(AIX_31)
+       (void) ioctl(fileno(stdin), (int) TCGETS, &termio);
+#  else
+       (void) ioctl(fileno(stdin), (int) TCGETA, &termio);
+#  endif
+# endif
+#endif
+       getwindowsz();
+#ifdef AUX
+       ( void ) signal ( SIGTSTP , catch_stp ) ;
+#endif
+}
+
+void
+setioctls()
+{
+#ifdef BSD_JOB_CONTROL
+       (void) ioctl(fileno(stdin), (int) TIOCSLTC, (char *) &ltchars);
+#else
+# ifdef POSIX_TYPES
+       (void) tcsetattr(fileno(stdin), TCSADRAIN, &termio);
+# else
+#  if defined(TCSETS) && !defined(AIX_31)
+       (void) ioctl(fileno(stdin), (int) TCSETSW, &termio);
+#  else
+       (void) ioctl(fileno(stdin), (int) TCSETAW, &termio);
+#  endif
+# endif
+#endif
+}
+
+#ifdef SUSPEND         /* No longer implies BSD */
+int
+dosuspend()
+{
+# ifdef SIGTSTP
+       if(signal(SIGTSTP, SIG_IGN) == SIG_DFL) {
+               suspend_nhwindows((char *)0);
+#  ifdef _M_UNIX
+               sco_mapon();
+#  endif
+#  ifdef __linux__
+               linux_mapon();
+#  endif
+               (void) signal(SIGTSTP, SIG_DFL);
+#  ifdef AUX
+               ( void ) kill ( 0 , SIGSTOP ) ;
+#  else
+               (void) kill(0, SIGTSTP);
+#  endif
+#  ifdef _M_UNIX
+               sco_mapoff();
+#  endif
+#  ifdef __linux__
+               linux_mapoff();
+#  endif
+               resume_nhwindows();
+       } else {
+               pline("I don't think your shell has job control.");
+       }
+# else
+       pline("Sorry, it seems we have no SIGTSTP here.  Try ! or S.");
+# endif
+       return(0);
+}
+#endif /* SUSPEND */
diff --git a/sys/share/lev_comp.h b/sys/share/lev_comp.h
new file mode 100644 (file)
index 0000000..8152d60
--- /dev/null
@@ -0,0 +1,79 @@
+#define CHAR 257
+#define INTEGER 258
+#define BOOLEAN 259
+#define PERCENT 260
+#define MESSAGE_ID 261
+#define MAZE_ID 262
+#define LEVEL_ID 263
+#define LEV_INIT_ID 264
+#define GEOMETRY_ID 265
+#define NOMAP_ID 266
+#define OBJECT_ID 267
+#define COBJECT_ID 268
+#define MONSTER_ID 269
+#define TRAP_ID 270
+#define DOOR_ID 271
+#define DRAWBRIDGE_ID 272
+#define MAZEWALK_ID 273
+#define WALLIFY_ID 274
+#define REGION_ID 275
+#define FILLING 276
+#define RANDOM_OBJECTS_ID 277
+#define RANDOM_MONSTERS_ID 278
+#define RANDOM_PLACES_ID 279
+#define ALTAR_ID 280
+#define LADDER_ID 281
+#define STAIR_ID 282
+#define NON_DIGGABLE_ID 283
+#define NON_PASSWALL_ID 284
+#define ROOM_ID 285
+#define PORTAL_ID 286
+#define TELEPRT_ID 287
+#define BRANCH_ID 288
+#define LEV 289
+#define CHANCE_ID 290
+#define CORRIDOR_ID 291
+#define GOLD_ID 292
+#define ENGRAVING_ID 293
+#define FOUNTAIN_ID 294
+#define POOL_ID 295
+#define SINK_ID 296
+#define NONE 297
+#define RAND_CORRIDOR_ID 298
+#define DOOR_STATE 299
+#define LIGHT_STATE 300
+#define CURSE_TYPE 301
+#define ENGRAVING_TYPE 302
+#define DIRECTION 303
+#define RANDOM_TYPE 304
+#define O_REGISTER 305
+#define M_REGISTER 306
+#define P_REGISTER 307
+#define A_REGISTER 308
+#define ALIGNMENT 309
+#define LEFT_OR_RIGHT 310
+#define CENTER 311
+#define TOP_OR_BOT 312
+#define ALTAR_TYPE 313
+#define UP_OR_DOWN 314
+#define SUBROOM_ID 315
+#define NAME_ID 316
+#define FLAGS_ID 317
+#define FLAG_TYPE 318
+#define MON_ATTITUDE 319
+#define MON_ALERTNESS 320
+#define MON_APPEARANCE 321
+#define CONTAINED 322
+#define STRING 323
+#define MAP_ID 324
+typedef union
+{
+       int     i;
+       char*   map;
+       struct {
+               xchar room;
+               xchar wall;
+               xchar door;
+       } corpos;
+} YYSTYPE;
+extern YYSTYPE yylval;
diff --git a/sys/share/lev_lex.c b/sys/share/lev_lex.c
new file mode 100644 (file)
index 0000000..776e048
--- /dev/null
@@ -0,0 +1,2088 @@
+/* A lexical scanner for NetHack generated by flex */
+
+/* Scanner skeleton version:
+ * flexhack.skl 3.3.0 (from .../flex/RCS/flex.skl,v 2.85 95/04/24 10:48:47)
+ */
+#define FLEXHACK_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include "config.h"
+#define yyconst const  /* some code inserted by flex will refer to yyconst */
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+               *yy_cp = yy_hold_char; \
+               yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+               YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+               } \
+       while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+       {
+       FILE *yy_input_file;
+
+       char *yy_ch_buf;                /* input buffer */
+       char *yy_buf_pos;               /* current position in input buffer */
+
+       /* Size of input buffer in bytes, not including room for EOB
+        * characters.
+        */
+       yy_size_t yy_buf_size;
+
+       /* Number of characters read into yy_ch_buf, not including EOB
+        * characters.
+        */
+       int yy_n_chars;
+
+       /* Whether we "own" the buffer - i.e., we know we created it,
+        * and can realloc() it to grow it, and should free() it to
+        * delete it.
+        */
+       int yy_is_our_buffer;
+
+       /* Whether this is an "interactive" input source; if so, and
+        * if we're using stdio for input, then we want to use getc()
+        * instead of fread(), to make sure we stop fetching input after
+        * each newline.
+        */
+       int yy_is_interactive;
+
+       /* Whether we're considered to be at the beginning of a line.
+        * If so, '^' rules will be active on the next match, otherwise
+        * not.
+        */
+       int yy_at_bol;
+
+       /* Whether to try to fill the input buffer when we reach the
+        * end of it.
+        */
+       int yy_fill_buffer;
+
+       int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+       /* When an EOF's been seen but there's still some text to process
+        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+        * shouldn't try reading from the input source any more.  We might
+        * still have a bunch of tokens to match, though, because of
+        * possible backing-up.
+        *
+        * When we actually see the EOF, we change the status to "new"
+        * (via yyrestart()), so that the user can continue scanning by
+        * just pointing yyin at a new input file.
+        */
+#define YY_BUFFER_EOF_PENDING 2
+       };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars;         /* number of characters read into yy_ch_buf */
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;                /* whether we need to initialize */
+static int yy_start = 0;       /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void FDECL(yyrestart, (FILE *));
+
+void FDECL(yy_switch_to_buffer, (YY_BUFFER_STATE));
+void NDECL(yy_load_buffer_state);
+YY_BUFFER_STATE FDECL(yy_create_buffer, (FILE *,int));
+void FDECL(yy_delete_buffer, (YY_BUFFER_STATE));
+void FDECL(yy_init_buffer, (YY_BUFFER_STATE,FILE *));
+void FDECL(yy_flush_buffer, (YY_BUFFER_STATE));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+static genericptr_t FDECL(yy_flex_alloc, (yy_size_t));
+static genericptr_t FDECL(yy_flex_realloc2, (genericptr_t,yy_size_t,int));
+static void FDECL(yy_flex_free, (genericptr_t));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+       { \
+       if ( ! yy_current_buffer ) \
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+       yy_current_buffer->yy_is_interactive = is_interactive; \
+       }
+
+#define yy_set_bol(at_bol) \
+       { \
+       if ( ! yy_current_buffer ) \
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+       yy_current_buffer->yy_at_bol = at_bol; \
+       }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type NDECL(yy_get_previous_state);
+static yy_state_type FDECL(yy_try_NUL_trans, (yy_state_type));
+static int NDECL(yy_get_next_buffer);
+static void FDECL(yy_fatal_error, (const char *));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+       yytext_ptr = yy_bp; \
+       yyleng = (int) (yy_cp - yy_bp); \
+       yy_hold_char = *yy_cp; \
+       *yy_cp = '\0'; \
+       yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 112
+#define YY_END_OF_BUFFER 113
+static yyconst short int yy_accept[640] =
+    {   0,
+        0,    0,    0,    0,  113,  111,  108,  107,  111,  111,
+      111,  111,  105,    4,  111,  111,  111,  111,  111,  111,
+      111,  111,  111,  111,  111,  111,  111,  111,  111,  111,
+      111,  111,  111,  111,  111,  111,  111,  111,  111,  111,
+      111,  111,  111,  111,  111,  111,  111,  111,  111,  111,
+      111,    2,  111,  108,  111,  111,  105,  111,  111,  111,
+      111,  111,  111,  111,  111,  111,  111,  111,  111,  108,
+      107,    0,  106,    0,    0,  105,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       87,    0,    0,    3,    0,    2,    2,    0,  108,    0,
+      105,    0,    0,    0,    0,    0,    0,    0,    0,    2,
+        0,    0,  110,    0,  110,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,   72,    0,    0,   67,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       65,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,  109,    0,    0,    0,    0,    0,   17,
+        0,    0,    0,    0,    0,   40,    0,    0,    0,    6,
+        0,    0,   42,    0,    0,    0,   33,    0,    0,    0,
+
+       36,   32,    0,    0,    0,   16,    0,    0,  104,    0,
+        0,    0,    0,    0,    0,    0,    0,   93,    0,    0,
+        0,    0,    0,    0,   88,   91,   51,    0,    0,    0,
+        0,    0,    0,   60,    0,    0,    0,    0,    0,   94,
+        0,    0,    0,    0,    0,    0,   55,    0,    0,    0,
+       45,    0,    0,    0,    0,    0,    0,    0,    0,   90,
+        0,    0,    0,   53,   12,    0,    0,    0,    0,    0,
+       25,    0,    0,    0,    0,    0,    0,   10,    0,    0,
+        0,    0,    8,    0,    0,    0,    7,    0,    0,    0,
+        0,    0,    0,   27,    0,    0,    0,   59,   86,    0,
+
+        0,   80,    0,    0,    0,    0,   74,    0,    0,    0,
+        0,    0,   89,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,   50,    0,
+        0,    0,   58,    0,   64,    0,    0,    0,   52,    0,
+        0,   68,    0,    0,   30,   43,    0,    0,    0,    0,
+        0,    0,    0,   26,    0,    0,    0,    0,    0,   13,
+       28,    0,   21,    0,    0,    0,    0,   79,    0,   66,
+       49,   62,   46,    0,    0,   97,    0,   69,    0,    0,
+        0,    0,    0,   47,    0,    0,    0,    0,    0,    0,
+       48,  101,    0,    0,   56,    0,   54,    0,    0,   85,
+
+        0,    0,    1,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    5,   15,    0,    0,    0,   37,    0,   20,
+        0,   95,    0,    0,   92,    0,    0,    0,   78,    0,
+        0,    0,    0,   57,   73,   71,    0,    0,    0,   84,
+        0,    0,    0,    0,   39,    0,    0,   31,   11,    9,
+       19,    0,    0,    0,    0,    0,    0,    0,  102,    0,
+        0,    0,    0,    0,    0,    0,    0,   83,    0,    0,
+       77,    0,   96,   70,   14,    0,   41,    0,    0,    0,
+        0,    0,    0,    0,   75,   98,   61,    0,  100,   44,
+       81,   82,    0,    0,    0,   18,    0,    0,    0,    0,
+
+        0,    0,    0,   63,    0,   99,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,   34,   35,    0,    0,
+        0,    0,    0,   76,  103,    0,    0,    0,   24,    0,
+        0,    0,   22,    0,    0,   23,   29,   38,    0
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    4,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    5,    1,    6,    7,    1,    8,    1,    9,    1,
+        1,    1,   10,    1,   11,   12,    1,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   14,    1,    1,
+        1,    1,    1,    1,   15,   16,   17,   18,   19,   20,
+       21,   22,   23,   24,   25,   26,   27,   28,   29,   30,
+        1,   31,   32,   33,   34,   35,   36,    1,   37,   38,
+       39,   40,   41,    1,   42,    1,   43,   44,   45,   46,
+
+       47,   48,   49,   50,   51,   52,   53,   54,   55,   56,
+       57,   58,    1,   59,   60,   61,   62,   63,   64,    1,
+        1,    1,   12,   12,   12,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[65] =
+    {   0,
+        1,    2,    3,    2,    2,    1,    2,    1,    1,    2,
+        2,    2,    2,    1,    2,    2,    2,    1,    1,    2,
+        1,    2,    2,    1,    2,    2,    1,    1,    1,    2,
+        1,    2,    2,    1,    1,    2,    1,    1,    1,    2,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1
+    } ;
+
+static yyconst short int yy_base[645] =
+    {   0,
+        0,   58,   83,   62,  796,  797,   65,  797,  792,  788,
+      753,  779,  778,  797,  764,  758,   44,   43,  760,   42,
+       62,  759,   60,   63,   68,  770,  756,   92,   91,   91,
+      769,   71,   72,   76,   87,   55,   84,   77,   61,   96,
+      103,   95,  104,  103,  108,  111,   99,  107,  736,  779,
+      151,  797,  778,  169,  173,  179,  182,  185,  194,  197,
+      752,  180,  185,  193,  181,  194,  202,  214,  241,   75,
+      797,  773,  797,  769,  768,  763,  742,  759,  758,  136,
+      743,  756,  749,  754,  734,  738,  740,  742,  746,  728,
+      724,  729,  732,  732,  151,  734,  162,  729,  735,  726,
+
+      726,  738,  736,  725,  735,  723,  225,  224,  143,  704,
+      693,  703,  698,  683,  686,  683,  685,  697,  682,  162,
+      679,  673,  676,  675,  685,  679,  678,  180,  671,  666,
+      172,  668,  683,  192,  668,  670,  663,  229,  672,  676,
+      679,  678,  664,  670,  662,  203,  655,  658,  653,  235,
+      797,  654,  710,  797,  212,  797,  797,  709,  274,  264,
+      265,  269,  277,  247,  282,  283,  285,  293,  294,  797,
+      708,    0,  797,  701,  700,  693,  679,  678,  672,  673,
+      672,  666,  670,  679,  671,  671,  679,  663,  677,  675,
+      674,  660,  659,  671,  674,  646,  668,  660,  652,  666,
+
+      660,  655,  656,  657,  648,  659,  647,  650,  254,  626,
+      631,  616,  625,  618,  610,  608,  615,  611,  605,  608,
+      604,  609,  601,  601,  604,  598,  597,  598,  596,  601,
+      606,  607,  591,  797,  590,  591,  797,  596,  601,  590,
+      602,  592,  584,  582,  588,  584,  585,  272,  578,  591,
+      590,  580,  590,  589,  587,  582,  586,  571,  578,  567,
+      797,  580,  564,  574,  573,  562,  266,  303,  299,  595,
+      308,  311,  309,  797,  590,  603,  602,  603,  594,  797,
+      600,  600,  582,  580,  593,  797,  569,  591,  583,  572,
+      592,  573,  797,  575,  306,  587,  797,  588,  573,  572,
+
+      797,  797,  569,  570,  568,  797,  574,  304,  797,  540,
+      536,  535,  546,  545,  531,  533,  542,  797,  541,  527,
+      539,  534,  541,  536,  797,  797,  797,  539,  534,  533,
+      568,  530,  526,  797,  529,  528,  531,  517,  520,  797,
+      510,  511,  518,  511,  524,  509,  797,  515,  510,  518,
+      797,  515,  514,  503,  498,  497,  496,  500,  505,  797,
+      495,  499,  491,  797,  797,  548,  317,  535,  320,  321,
+      797,  527,  529,  524,  528,  514,  509,  797,  528,  509,
+      514,  509,  797,  524,  517,  518,  797,  513,  520,  501,
+      507,  505,  503,  797,  501,  500,  508,  797,  797,  480,
+
+      468,  797,  478,  469,  467,  463,  797,  475,  471,  468,
+      472,  454,  797,  470,  293,  461,  460,  464,  466,  450,
+      450,  462,  461,  464,  457,  446,  446,  460,  797,  455,
+      440,  452,  797,  444,  797,  436,  437,  449,  797,  435,
+      440,  797,  463,  333,  797,  797,  464,  462,  467,  466,
+      465,  456,  471,  797,  459,  465,  452,  461,  449,  797,
+      797,  438,  797,  452,  447,  440,  433,  797,  429,  797,
+      797,  797,  797,  418,  417,  797,  425,  797,  424,  419,
+      412,  421,  416,  797,  404,  404,  419,  404,  408,  405,
+      797,  797,  406,  401,  797,  396,  797,  402,  405,  797,
+
+      408,  407,  797,  332,  434,  421,  433,  422,  421,  411,
+      417,  421,  797,  797,  424,  412,  341,  797,  410,  797,
+      388,  797,  394,  393,  797,  391,  389,  380,  797,  379,
+      376,  387,  372,  797,  797,  797,  381,  374,  376,  797,
+      380,  382,  381,  395,  797,  404,  403,  797,  797,  797,
+      797,  408,  386,  392,  391,  403,  392,  375,  797,  370,
+      369,  353,  363,  353,  355,  363,  350,  797,  359,  348,
+      797,  356,  797,  797,  797,  386,  797,  388,  388,  371,
+      373,  376,  384,  367,  797,  797,  797,  336,  797,  797,
+      797,  797,  340,  334,  333,  797,  367,  366,  360,  358,
+
+      370,  371,  368,  797,  339,  797,  338,  365,  341,  343,
+      332,  347,  344,  339,  313,  311,  797,  797,  338,  322,
+      293,  278,  277,  797,  797,  253,  224,  209,  797,  161,
+      138,  123,  797,  101,   69,  797,  797,  797,  797,  371,
+      374,  376,  378,  381
+    } ;
+
+static yyconst short int yy_def[645] =
+    {   0,
+      639,    1,    1,    3,  639,  639,  639,  639,  639,  640,
+      641,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  642,
+      639,  639,  639,  643,  643,  643,  643,  643,  643,  643,
+      639,   60,   60,   60,   60,   60,   60,   60,  642,  639,
+      639,  640,  639,  639,  644,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  642,  639,  639,  639,  639,  639,   60,   60,
+       60,   60,   60,  639,   60,   60,   60,   60,   60,  639,
+      642,   69,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,   60,   60,  639,
+       60,   60,   60,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,   60,  639,   60,   60,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,   60,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+
+      639,  639,  639,   60,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,    0,  639,
+      639,  639,  639,  639
+    } ;
+
+static yyconst short int yy_nxt[862] =
+    {   0,
+        6,    7,    8,    9,    7,   10,    6,    6,   11,   12,
+       12,    6,   13,   14,   15,   16,   17,   18,   19,   20,
+       21,    6,   22,    6,    6,   23,   24,   25,   26,   27,
+       28,   29,   30,    6,    6,   31,    6,    6,   32,    6,
+        6,    6,   33,   34,   35,   36,   37,   38,    6,   39,
+        6,    6,    6,   40,   41,   42,   43,   44,   45,   46,
+       47,   48,    6,   49,   50,   79,   70,   84,   69,   70,
+       85,   81,   80,   82,   89,  107,   70,   91,   90,   70,
+       86,   92,   94,  108,   51,   52,   53,   54,   51,   55,
+       87,   93,   56,   56,   55,   57,   95,   58,   59,   60,
+
+      638,   61,   62,  128,   55,   63,   98,   55,   64,  104,
+       99,  122,   65,  101,   66,   67,  123,  129,   68,  126,
+      100,  105,   55,  102,  103,  109,  124,  127,  637,  113,
+      110,  111,  114,  117,  115,  112,  118,  116,  130,  125,
+      119,  137,  131,  120,  134,  135,  132,  139,  121,  141,
+      143,  138,  133,  145,  636,  148,  142,  149,  144,  136,
+      146,  140,  150,  179,  151,  155,  180,  147,  635,   92,
+       70,  157,  158,  159,  639,  157,  158,  195,  196,   93,
+      639,  157,  158,  639,  157,  158,  639,  157,  158,  634,
+      198,  161,  199,  210,  161,  639,  157,  158,  639,  157,
+
+      158,  160,  160,  211,  222,  165,  160,  166,   85,   97,
+      162,   90,   88,  639,  160,  160,  167,  223,  163,  235,
+      104,  639,  639,  160,   78,   80,  168,  103,  169,  107,
+      639,  209,  105,  231,  236,  160,  108,  108,  232,  239,
+      633,  267,  639,  170,  171,  172,  240,  172,  241,  191,
+      172,  172,  172,  172,  632,  172,  172,  172,  308,  258,
+      172,  259,  172,  172,  270,  172,  172,  183,  365,  366,
+      172,  245,  172,  172,  246,   70,  172,  161,  159,  263,
+      172,  631,  264,  247,  248,  160,  160,  249,  265,  250,
+      160,  269,  639,  639,  309,  160,  271,  639,  160,  630,
+
+      189,  268,  639,  160,  160,  639,  160,  272,  308,  629,
+      639,  639,  203,  639,  160,  160,  346,  367,  347,  273,
+      160,  639,  639,  388,  160,  628,  277,  639,  283,  160,
+      160,  639,  160,  369,  370,  389,  639,  639,  160,  639,
+      627,  160,  160,  444,  309,  639,  479,  371,  639,  639,
+      394,  480,  504,  160,  160,  626,  625,  554,  624,  623,
+      639,  639,  622,  621,  620,  619,  618,  555,  520,  556,
+      557,   72,   72,   72,   74,   74,  153,  153,  153,  160,
+      160,  174,  174,  617,  616,  615,  614,  613,  612,  611,
+      610,  609,  608,  607,  606,  605,  604,  603,  602,  601,
+
+      600,  599,  598,  597,  596,  595,  594,  593,  592,  591,
+      590,  589,  588,  587,  586,  585,  584,  583,  582,  581,
+      580,  579,  578,  577,  576,  575,  574,  573,  572,  571,
+      570,  569,  568,  567,  566,  565,  564,  563,  562,  561,
+      560,  559,  558,  553,  552,  551,  550,  549,  548,  547,
+      546,  545,  544,  543,  542,  541,  540,  539,  538,  537,
+      536,  535,  534,  533,  532,  531,  530,  529,  528,  527,
+      526,  525,  524,  523,  522,  521,  520,  519,  518,  517,
+      516,  515,  514,  513,  512,  511,  510,  509,  508,  507,
+      506,  505,  503,  502,  501,  500,  499,  498,  497,  496,
+
+      495,  494,  493,  492,  491,  490,  489,  488,  487,  486,
+      485,  484,  483,  482,  481,  478,  477,  476,  475,  474,
+      473,  472,  471,  470,  469,  468,  467,  466,  465,  464,
+      463,  462,  461,  460,  459,  458,  457,  456,  455,  454,
+      453,  452,  451,  450,  449,  448,  447,  446,  445,  443,
+      365,  442,  441,  440,  439,  438,  437,  436,  435,  434,
+      433,  432,  431,  430,  429,  428,  427,  426,  425,  424,
+      423,  422,  421,  420,  419,  418,  417,  416,  415,  414,
+      413,  412,  411,  410,  409,  408,  407,  406,  405,  404,
+      403,  402,  401,  400,  399,  398,  397,  396,  395,  394,
+
+      393,  392,  391,  390,  387,  386,  385,  384,  383,  382,
+      381,  380,  379,  378,  377,  376,  375,  374,  373,  372,
+      371,  368,  364,  363,  362,  361,  360,  359,  358,  357,
+      356,  355,  354,  353,  352,  351,  350,  349,  348,  345,
+      344,  343,  342,  341,  340,  339,  338,  337,  336,  335,
+      334,  333,  332,  331,  330,  329,  328,  327,  326,  325,
+      324,  323,  322,  321,  320,  319,  318,  317,  316,  315,
+      314,  313,  312,  311,  310,  307,  306,  305,  304,  303,
+      302,  301,  300,  299,  298,  297,  296,  295,  294,  293,
+      292,  291,  290,  289,  288,  287,  286,  285,  284,  283,
+
+      282,  281,  280,  279,  278,  277,  276,  275,  274,  274,
+      170,  157,  154,  266,  262,  261,  260,  257,  256,  255,
+      254,  253,  252,  251,  244,  243,  242,  238,  237,  234,
+      233,  230,  229,  228,  227,  226,  225,  224,  221,  220,
+      219,  218,  217,  216,  215,  214,  213,  212,  208,  207,
+      206,  205,  204,  203,  202,  201,  200,  197,  194,  193,
+      192,  191,  190,  189,  188,  187,  186,  185,  184,  183,
+      182,  181,  178,  177,  176,   76,  175,  173,   73,  164,
+      156,  154,  152,  106,   97,   96,   88,   83,   78,   77,
+       76,   76,   75,   73,   71,  639,    5,  639,  639,  639,
+
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639
+    } ;
+
+static yyconst short int yy_chk[862] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    2,   17,    7,   20,    4,    7,
+       20,   18,   17,   18,   23,   32,   70,   24,   23,   70,
+       21,   24,   25,   32,    2,    3,    3,    3,    4,    3,
+       21,   24,    3,    3,    3,    3,   25,    3,    3,    3,
+
+      635,    3,    3,   39,    3,    3,   28,    3,    3,   30,
+       28,   36,    3,   29,    3,    3,   36,   39,    3,   38,
+       28,   30,    3,   29,   29,   33,   37,   38,  634,   34,
+       33,   33,   34,   35,   34,   33,   35,   34,   40,   37,
+       35,   42,   40,   35,   41,   41,   40,   43,   35,   44,
+       45,   42,   40,   46,  632,   47,   44,   47,   45,   41,
+       46,   43,   48,   80,   48,   51,   80,   46,  631,   51,
+       54,   54,   54,   54,   55,   55,   55,   95,   95,   51,
+       56,   56,   56,   57,   57,   57,   58,   58,   58,  630,
+       97,   56,   97,  109,   57,   59,   59,   59,   60,   60,
+
+       60,   62,   65,  109,  120,   62,   63,   64,   62,   65,
+       58,   64,   63,   63,   64,   66,   66,  120,   60,  131,
+       67,   64,   66,   67,   59,   60,   66,   66,   68,  107,
+       67,  108,   67,  128,  131,   68,  108,  107,  128,  134,
+      628,  155,   68,   69,   69,   69,  134,   69,  134,  155,
+       69,   69,   69,   69,  627,   69,   69,   69,  209,  146,
+       69,  146,   69,   69,  164,   69,   69,  164,  267,  267,
+       69,  138,   69,   69,  138,  159,   69,  161,  159,  150,
+       69,  626,  150,  138,  138,  160,  161,  138,  150,  138,
+      162,  163,  160,  161,  209,  159,  165,  162,  163,  623,
+
+      166,  162,  159,  165,  166,  163,  167,  168,  308,  622,
+      165,  166,  167,  167,  168,  169,  248,  268,  248,  169,
+      269,  168,  169,  295,  268,  621,  269,  269,  271,  271,
+      273,  268,  272,  272,  273,  295,  271,  273,  367,  272,
+      620,  369,  370,  370,  308,  367,  415,  367,  369,  370,
+      369,  415,  444,  504,  444,  619,  616,  517,  615,  614,
+      504,  444,  613,  612,  611,  610,  609,  517,  504,  517,
+      517,  640,  640,  640,  641,  641,  642,  642,  642,  643,
+      643,  644,  644,  608,  607,  605,  603,  602,  601,  600,
+      599,  598,  597,  595,  594,  593,  588,  584,  583,  582,
+
+      581,  580,  579,  578,  576,  572,  570,  569,  567,  566,
+      565,  564,  563,  562,  561,  560,  558,  557,  556,  555,
+      554,  553,  552,  547,  546,  544,  543,  542,  541,  539,
+      538,  537,  533,  532,  531,  530,  528,  527,  526,  524,
+      523,  521,  519,  516,  515,  512,  511,  510,  509,  508,
+      507,  506,  505,  502,  501,  499,  498,  496,  494,  493,
+      490,  489,  488,  487,  486,  485,  483,  482,  481,  480,
+      479,  477,  475,  474,  469,  467,  466,  465,  464,  462,
+      459,  458,  457,  456,  455,  453,  452,  451,  450,  449,
+      448,  447,  443,  441,  440,  438,  437,  436,  434,  432,
+
+      431,  430,  428,  427,  426,  425,  424,  423,  422,  421,
+      420,  419,  418,  417,  416,  414,  412,  411,  410,  409,
+      408,  406,  405,  404,  403,  401,  400,  397,  396,  395,
+      393,  392,  391,  390,  389,  388,  386,  385,  384,  382,
+      381,  380,  379,  377,  376,  375,  374,  373,  372,  368,
+      366,  363,  362,  361,  359,  358,  357,  356,  355,  354,
+      353,  352,  350,  349,  348,  346,  345,  344,  343,  342,
+      341,  339,  338,  337,  336,  335,  333,  332,  331,  330,
+      329,  328,  324,  323,  322,  321,  320,  319,  317,  316,
+      315,  314,  313,  312,  311,  310,  307,  305,  304,  303,
+
+      300,  299,  298,  296,  294,  292,  291,  290,  289,  288,
+      287,  285,  284,  283,  282,  281,  279,  278,  277,  276,
+      275,  270,  266,  265,  264,  263,  262,  260,  259,  258,
+      257,  256,  255,  254,  253,  252,  251,  250,  249,  247,
+      246,  245,  244,  243,  242,  241,  240,  239,  238,  236,
+      235,  233,  232,  231,  230,  229,  228,  227,  226,  225,
+      224,  223,  222,  221,  220,  219,  218,  217,  216,  215,
+      214,  213,  212,  211,  210,  208,  207,  206,  205,  204,
+      203,  202,  201,  200,  199,  198,  197,  196,  195,  194,
+      193,  192,  191,  190,  189,  188,  187,  186,  185,  184,
+
+      183,  182,  181,  180,  179,  178,  177,  176,  175,  174,
+      171,  158,  153,  152,  149,  148,  147,  145,  144,  143,
+      142,  141,  140,  139,  137,  136,  135,  133,  132,  130,
+      129,  127,  126,  125,  124,  123,  122,  121,  119,  118,
+      117,  116,  115,  114,  113,  112,  111,  110,  106,  105,
+      104,  103,  102,  101,  100,   99,   98,   96,   94,   93,
+       92,   91,   90,   89,   88,   87,   86,   85,   84,   83,
+       82,   81,   79,   78,   77,   76,   75,   74,   72,   61,
+       53,   50,   49,   31,   27,   26,   22,   19,   16,   15,
+       13,   12,   11,   10,    9,    5,  639,  639,  639,  639,
+
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+char *yytext;
+#define INITIAL 0
+/*     SCCS Id: @(#)lev_lex.c  3.4     2002/03/27      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#define LEV_LEX_C
+
+#include "hack.h"
+#include "lev_comp.h"
+#include "sp_lev.h"
+
+/* Most of these don't exist in flex, yywrap is macro and
+ * yyunput is properly declared in flex.skel.
+ */
+#if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER)
+int FDECL(yyback, (int *,int));
+int NDECL(yylook);
+int NDECL(yyinput);
+int NDECL(yywrap);
+int NDECL(yylex);
+       /* Traditional lexes let yyunput() and yyoutput() default to int;
+        * newer ones may declare them as void since they don't return
+        * values.  For even more fun, the lex supplied as part of the
+        * newer unbundled compiler for SunOS 4.x adds the void declarations
+        * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain
+        * int) while the bundled lex and the one with the older unbundled
+        * compiler do not.  To detect this, we need help from outside --
+        * sys/unix/Makefile.utl.
+        *
+        * Digital UNIX is difficult and still has int in spite of all
+        * other signs.
+        */
+# if defined(NeXT) || defined(SVR4) || defined(_AIX32)
+#  define VOIDYYPUT
+# endif
+# if !defined(VOIDYYPUT) && defined(POSIX_TYPES)
+#  if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS)
+#   define VOIDYYPUT
+#  endif
+# endif
+# if !defined(VOIDYYPUT) && defined(WEIRD_LEX)
+#  if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1)
+#   define VOIDYYPUT
+#  endif
+# endif
+# if defined(VOIDYYPUT) && defined(__osf__)
+#  undef VOIDYYPUT
+# endif
+# ifdef VOIDYYPUT
+void FDECL(yyunput, (int));
+void FDECL(yyoutput, (int));
+# else
+int FDECL(yyunput, (int));
+int FDECL(yyoutput, (int));
+# endif
+#endif /* !FLEX_SCANNER && !FLEXHACK_SCANNER */
+
+#ifdef FLEX_SCANNER
+#define YY_MALLOC_DECL \
+             genericptr_t FDECL(malloc, (size_t)); \
+             genericptr_t FDECL(realloc, (genericptr_t,size_t));
+#endif
+
+void FDECL(init_yyin, (FILE *));
+void FDECL(init_yyout, (FILE *));
+
+/*
+ * This doesn't always get put in lev_comp.h
+ * (esp. when using older versions of bison).
+ */
+extern YYSTYPE yylval;
+
+int line_number = 1, colon_line_number = 1;
+static char map[4096];
+static int map_cnt = 0;
+
+#define MAPC 1
+
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+extern int NDECL(yywrap);
+#endif
+
+#ifndef YY_NO_UNPUT
+static void FDECL(yyunput, (int,char *));
+#endif
+
+#ifndef yytext_ptr
+static void FDECL(yy_flex_strncpy, (char *,const char *,int));
+#endif
+
+#ifndef YY_NO_INPUT
+static int NDECL(input);
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+       if ( yy_current_buffer->yy_is_interactive ) \
+               { \
+               int c = '*', n; \
+               for ( n = 0; n < max_size && \
+                            (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+                       buf[n] = (char) c; \
+               if ( c == '\n' ) \
+                       buf[n++] = (char) c; \
+               if ( c == EOF && ferror( yyin ) ) \
+                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
+               result = n; \
+               } \
+       else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+                 && ferror( yyin ) ) \
+               YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+       if ( yyleng > 0 ) \
+               yy_current_buffer->yy_at_bol = \
+                               (yytext[yyleng - 1] == '\n'); \
+       YY_USER_ACTION
+
+int NDECL(yylex);
+int yylex()
+       {
+       register yy_state_type yy_current_state;
+       register char *yy_cp, *yy_bp;
+       register int yy_act;
+
+
+
+       if ( yy_init )
+               {
+               yy_init = 0;
+
+#ifdef YY_USER_INIT
+               YY_USER_INIT;
+#endif
+
+               if ( ! yy_start )
+                       yy_start = 1;   /* first start state */
+
+               if ( ! yyin )
+                       yyin = stdin;
+
+               if ( ! yyout )
+                       yyout = stdout;
+
+               if ( ! yy_current_buffer )
+                       yy_current_buffer =
+                               yy_create_buffer( yyin, YY_BUF_SIZE );
+
+               yy_load_buffer_state();
+               }
+
+       while ( 1 )             /* loops until end-of-file is reached */
+               {
+               yy_cp = yy_c_buf_p;
+
+               /* Support of yytext. */
+               *yy_cp = yy_hold_char;
+
+               /* yy_bp points to the position in yy_ch_buf of the start of
+                * the current run.
+                */
+               yy_bp = yy_cp;
+
+               yy_current_state = yy_start;
+               yy_current_state += YY_AT_BOL();
+yy_match:
+               do
+                       {
+                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+                       if ( yy_accept[yy_current_state] )
+                               {
+                               yy_last_accepting_state = yy_current_state;
+                               yy_last_accepting_cpos = yy_cp;
+                               }
+                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                               {
+                               yy_current_state = (int) yy_def[yy_current_state];
+                               if ( yy_current_state >= 640 )
+                                       yy_c = yy_meta[(unsigned int) yy_c];
+                               }
+                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+                       ++yy_cp;
+                       }
+               while ( yy_base[yy_current_state] != 797 );
+
+yy_find_action:
+               yy_act = yy_accept[yy_current_state];
+               if ( yy_act == 0 )
+                       { /* have to back up */
+                       yy_cp = yy_last_accepting_cpos;
+                       yy_current_state = yy_last_accepting_state;
+                       yy_act = yy_accept[yy_current_state];
+                       }
+
+               YY_DO_BEFORE_ACTION;
+
+
+do_action:     /* This label is used only to access EOF actions. */
+
+
+               switch ( yy_act )
+       { /* beginning of action switch */
+                       case 0: /* must back up */
+                       /* undo the effects of YY_DO_BEFORE_ACTION */
+                       *yy_cp = yy_hold_char;
+                       yy_cp = yy_last_accepting_cpos;
+                       yy_current_state = yy_last_accepting_state;
+                       goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+{
+                 BEGIN(INITIAL);
+                 yylval.map = (char *) alloc(map_cnt + 1);
+                 (void) strncpy(yylval.map, map, map_cnt);
+                 yylval.map[map_cnt] = 0;
+                 map_cnt = 0;
+                 return MAP_ID;
+               }
+       YY_BREAK
+case 2:
+YY_RULE_SETUP
+{
+                 int len = yyleng;
+                 /* convert \r\n to \n */
+                 if (len >= 2 && yytext[len - 2] == '\r') len -= 1;
+                 line_number++;
+                 (void) strncpy(map + map_cnt, yytext, len);
+                 map_cnt += len;
+                 map[map_cnt - 1] = '\n';
+                 map[map_cnt] = '\0';
+               }
+       YY_BREAK
+case 3:
+YY_RULE_SETUP
+{ line_number++; }
+       YY_BREAK
+case 4:
+YY_RULE_SETUP
+{ colon_line_number = line_number; return ':'; }
+       YY_BREAK
+case 5:
+YY_RULE_SETUP
+return MESSAGE_ID;
+       YY_BREAK
+case 6:
+YY_RULE_SETUP
+return MAZE_ID;
+       YY_BREAK
+case 7:
+YY_RULE_SETUP
+return NOMAP_ID;
+       YY_BREAK
+case 8:
+YY_RULE_SETUP
+return LEVEL_ID;
+       YY_BREAK
+case 9:
+YY_RULE_SETUP
+return LEV_INIT_ID;
+       YY_BREAK
+case 10:
+YY_RULE_SETUP
+return FLAGS_ID;
+       YY_BREAK
+case 11:
+YY_RULE_SETUP
+return GEOMETRY_ID;
+       YY_BREAK
+case 12:
+YY_RULE_SETUP
+{ BEGIN(MAPC); line_number++; }
+       YY_BREAK
+case 13:
+YY_RULE_SETUP
+return OBJECT_ID;
+       YY_BREAK
+case 14:
+YY_RULE_SETUP
+return COBJECT_ID;
+       YY_BREAK
+case 15:
+YY_RULE_SETUP
+return MONSTER_ID;
+       YY_BREAK
+case 16:
+YY_RULE_SETUP
+return TRAP_ID;
+       YY_BREAK
+case 17:
+YY_RULE_SETUP
+return DOOR_ID;
+       YY_BREAK
+case 18:
+YY_RULE_SETUP
+return DRAWBRIDGE_ID;
+       YY_BREAK
+case 19:
+YY_RULE_SETUP
+return MAZEWALK_ID;
+       YY_BREAK
+case 20:
+YY_RULE_SETUP
+return WALLIFY_ID;
+       YY_BREAK
+case 21:
+YY_RULE_SETUP
+return REGION_ID;
+       YY_BREAK
+case 22:
+YY_RULE_SETUP
+return RANDOM_OBJECTS_ID;
+       YY_BREAK
+case 23:
+YY_RULE_SETUP
+return RANDOM_MONSTERS_ID;
+       YY_BREAK
+case 24:
+YY_RULE_SETUP
+return RANDOM_PLACES_ID;
+       YY_BREAK
+case 25:
+YY_RULE_SETUP
+return ALTAR_ID;
+       YY_BREAK
+case 26:
+YY_RULE_SETUP
+return LADDER_ID;
+       YY_BREAK
+case 27:
+YY_RULE_SETUP
+return STAIR_ID;
+       YY_BREAK
+case 28:
+YY_RULE_SETUP
+return PORTAL_ID;
+       YY_BREAK
+case 29:
+YY_RULE_SETUP
+return TELEPRT_ID;
+       YY_BREAK
+case 30:
+YY_RULE_SETUP
+return BRANCH_ID;
+       YY_BREAK
+case 31:
+YY_RULE_SETUP
+return FOUNTAIN_ID;
+       YY_BREAK
+case 32:
+YY_RULE_SETUP
+return SINK_ID;
+       YY_BREAK
+case 33:
+YY_RULE_SETUP
+return POOL_ID;
+       YY_BREAK
+case 34:
+YY_RULE_SETUP
+return NON_DIGGABLE_ID;
+       YY_BREAK
+case 35:
+YY_RULE_SETUP
+return NON_PASSWALL_ID;
+       YY_BREAK
+case 36:
+YY_RULE_SETUP
+return ROOM_ID;
+       YY_BREAK
+case 37:
+YY_RULE_SETUP
+return SUBROOM_ID;
+       YY_BREAK
+case 38:
+YY_RULE_SETUP
+return RAND_CORRIDOR_ID;
+       YY_BREAK
+case 39:
+YY_RULE_SETUP
+return CORRIDOR_ID;
+       YY_BREAK
+case 40:
+YY_RULE_SETUP
+return GOLD_ID;
+       YY_BREAK
+case 41:
+YY_RULE_SETUP
+return ENGRAVING_ID;
+       YY_BREAK
+case 42:
+YY_RULE_SETUP
+return NAME_ID;
+       YY_BREAK
+case 43:
+YY_RULE_SETUP
+return CHANCE_ID;
+       YY_BREAK
+case 44:
+YY_RULE_SETUP
+return LEV;
+       YY_BREAK
+case 45:
+YY_RULE_SETUP
+{ yylval.i=D_ISOPEN; return DOOR_STATE; }
+       YY_BREAK
+case 46:
+YY_RULE_SETUP
+{ yylval.i=D_CLOSED; return DOOR_STATE; }
+       YY_BREAK
+case 47:
+YY_RULE_SETUP
+{ yylval.i=D_LOCKED; return DOOR_STATE; }
+       YY_BREAK
+case 48:
+YY_RULE_SETUP
+{ yylval.i=D_NODOOR; return DOOR_STATE; }
+       YY_BREAK
+case 49:
+YY_RULE_SETUP
+{ yylval.i=D_BROKEN; return DOOR_STATE; }
+       YY_BREAK
+case 50:
+YY_RULE_SETUP
+{ yylval.i=W_NORTH; return DIRECTION; }
+       YY_BREAK
+case 51:
+YY_RULE_SETUP
+{ yylval.i=W_EAST; return DIRECTION; }
+       YY_BREAK
+case 52:
+YY_RULE_SETUP
+{ yylval.i=W_SOUTH; return DIRECTION; }
+       YY_BREAK
+case 53:
+YY_RULE_SETUP
+{ yylval.i=W_WEST; return DIRECTION; }
+       YY_BREAK
+case 54:
+YY_RULE_SETUP
+{ yylval.i = -1; return RANDOM_TYPE; }
+       YY_BREAK
+case 55:
+YY_RULE_SETUP
+{ yylval.i = -2; return NONE; }
+       YY_BREAK
+case 56:
+YY_RULE_SETUP
+return O_REGISTER;
+       YY_BREAK
+case 57:
+YY_RULE_SETUP
+return M_REGISTER;
+       YY_BREAK
+case 58:
+YY_RULE_SETUP
+return P_REGISTER;
+       YY_BREAK
+case 59:
+YY_RULE_SETUP
+return A_REGISTER;
+       YY_BREAK
+case 60:
+YY_RULE_SETUP
+{ yylval.i=1; return LEFT_OR_RIGHT; }
+       YY_BREAK
+case 61:
+YY_RULE_SETUP
+{ yylval.i=2; return LEFT_OR_RIGHT; }
+       YY_BREAK
+case 62:
+YY_RULE_SETUP
+{ yylval.i=3; return CENTER; }
+       YY_BREAK
+case 63:
+YY_RULE_SETUP
+{ yylval.i=4; return LEFT_OR_RIGHT; }
+       YY_BREAK
+case 64:
+YY_RULE_SETUP
+{ yylval.i=5; return LEFT_OR_RIGHT; }
+       YY_BREAK
+case 65:
+YY_RULE_SETUP
+{ yylval.i=1; return TOP_OR_BOT; }
+       YY_BREAK
+case 66:
+YY_RULE_SETUP
+{ yylval.i=5; return TOP_OR_BOT; }
+       YY_BREAK
+case 67:
+YY_RULE_SETUP
+{ yylval.i=1; return LIGHT_STATE; }
+       YY_BREAK
+case 68:
+YY_RULE_SETUP
+{ yylval.i=0; return LIGHT_STATE; }
+       YY_BREAK
+case 69:
+YY_RULE_SETUP
+{ yylval.i=0; return FILLING; }
+       YY_BREAK
+case 70:
+YY_RULE_SETUP
+{ yylval.i=1; return FILLING; }
+       YY_BREAK
+case 71:
+YY_RULE_SETUP
+{ yylval.i= AM_NONE; return ALIGNMENT; }
+       YY_BREAK
+case 72:
+YY_RULE_SETUP
+{ yylval.i= AM_LAWFUL; return ALIGNMENT; }
+       YY_BREAK
+case 73:
+YY_RULE_SETUP
+{ yylval.i= AM_NEUTRAL; return ALIGNMENT; }
+       YY_BREAK
+case 74:
+YY_RULE_SETUP
+{ yylval.i= AM_CHAOTIC; return ALIGNMENT; }
+       YY_BREAK
+case 75:
+YY_RULE_SETUP
+{ yylval.i= AM_SPLEV_CO; return ALIGNMENT; }
+       YY_BREAK
+case 76:
+YY_RULE_SETUP
+{ yylval.i= AM_SPLEV_NONCO; return ALIGNMENT; }
+       YY_BREAK
+case 77:
+YY_RULE_SETUP
+{ yylval.i=1; return MON_ATTITUDE; }
+       YY_BREAK
+case 78:
+YY_RULE_SETUP
+{ yylval.i=0; return MON_ATTITUDE; }
+       YY_BREAK
+case 79:
+YY_RULE_SETUP
+{ yylval.i=1; return MON_ALERTNESS; }
+       YY_BREAK
+case 80:
+YY_RULE_SETUP
+{ yylval.i=0; return MON_ALERTNESS; }
+       YY_BREAK
+case 81:
+YY_RULE_SETUP
+{ yylval.i= M_AP_FURNITURE; return MON_APPEARANCE; }
+       YY_BREAK
+case 82:
+YY_RULE_SETUP
+{ yylval.i= M_AP_MONSTER;   return MON_APPEARANCE; }
+       YY_BREAK
+case 83:
+YY_RULE_SETUP
+{ yylval.i= M_AP_OBJECT;    return MON_APPEARANCE; }
+       YY_BREAK
+case 84:
+YY_RULE_SETUP
+{ yylval.i=2; return ALTAR_TYPE; }
+       YY_BREAK
+case 85:
+YY_RULE_SETUP
+{ yylval.i=1; return ALTAR_TYPE; }
+       YY_BREAK
+case 86:
+YY_RULE_SETUP
+{ yylval.i=0; return ALTAR_TYPE; }
+       YY_BREAK
+case 87:
+YY_RULE_SETUP
+{ yylval.i=1; return UP_OR_DOWN; }
+       YY_BREAK
+case 88:
+YY_RULE_SETUP
+{ yylval.i=0; return UP_OR_DOWN; }
+       YY_BREAK
+case 89:
+YY_RULE_SETUP
+{ yylval.i=0; return BOOLEAN; }
+       YY_BREAK
+case 90:
+YY_RULE_SETUP
+{ yylval.i=1; return BOOLEAN; }
+       YY_BREAK
+case 91:
+YY_RULE_SETUP
+{ yylval.i=DUST; return ENGRAVING_TYPE; }
+       YY_BREAK
+case 92:
+YY_RULE_SETUP
+{ yylval.i=ENGRAVE; return ENGRAVING_TYPE; }
+       YY_BREAK
+case 93:
+YY_RULE_SETUP
+{ yylval.i=BURN; return ENGRAVING_TYPE; }
+       YY_BREAK
+case 94:
+YY_RULE_SETUP
+{ yylval.i=MARK; return ENGRAVING_TYPE; }
+       YY_BREAK
+case 95:
+YY_RULE_SETUP
+{ yylval.i=1; return CURSE_TYPE; }
+       YY_BREAK
+case 96:
+YY_RULE_SETUP
+{ yylval.i=2; return CURSE_TYPE; }
+       YY_BREAK
+case 97:
+YY_RULE_SETUP
+{ yylval.i=3; return CURSE_TYPE; }
+       YY_BREAK
+case 98:
+YY_RULE_SETUP
+{ return CONTAINED; }
+       YY_BREAK
+case 99:
+YY_RULE_SETUP
+{ yylval.i=NOTELEPORT; return FLAG_TYPE; }
+       YY_BREAK
+case 100:
+YY_RULE_SETUP
+{ yylval.i=HARDFLOOR; return FLAG_TYPE; }
+       YY_BREAK
+case 101:
+YY_RULE_SETUP
+{ yylval.i=NOMMAP; return FLAG_TYPE; }
+       YY_BREAK
+case 102:
+YY_RULE_SETUP
+{ yylval.i=ARBOREAL; return FLAG_TYPE; }       /* KMH */
+       YY_BREAK
+case 103:
+YY_RULE_SETUP
+{ yylval.i=SHORTSIGHTED; return FLAG_TYPE; }
+       YY_BREAK
+case 104:
+YY_RULE_SETUP
+{ yylval.i = atoi(yytext + 1); return PERCENT; }
+       YY_BREAK
+case 105:
+YY_RULE_SETUP
+{ yylval.i=atoi(yytext); return INTEGER; }
+       YY_BREAK
+case 106:
+YY_RULE_SETUP
+{ yytext[yyleng-1] = 0; /* Discard the trailing \" */
+                 yylval.map = (char *) alloc(strlen(yytext+1)+1);
+                 Strcpy(yylval.map, yytext+1); /* Discard the first \" */
+                 return STRING; }
+       YY_BREAK
+case 107:
+YY_RULE_SETUP
+{ line_number++; }
+       YY_BREAK
+case 108:
+YY_RULE_SETUP
+;
+       YY_BREAK
+case 109:
+YY_RULE_SETUP
+{ yylval.i = yytext[2]; return CHAR; }
+       YY_BREAK
+case 110:
+YY_RULE_SETUP
+{ yylval.i = yytext[1]; return CHAR; }
+       YY_BREAK
+case 111:
+YY_RULE_SETUP
+{ return yytext[0]; }
+       YY_BREAK
+case 112:
+YY_RULE_SETUP
+ECHO;
+       YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(MAPC):
+       yyterminate();
+
+       case YY_END_OF_BUFFER:
+               {
+               /* Amount of text matched not including the EOB char. */
+               int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+               /* Undo the effects of YY_DO_BEFORE_ACTION. */
+               *yy_cp = yy_hold_char;
+
+               if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+                       {
+                       /* We're scanning a new file or input source.  It's
+                        * possible that this happened because the user
+                        * just pointed yyin at a new source and called
+                        * yylex().  If so, then we have to assure
+                        * consistency between yy_current_buffer and our
+                        * globals.  Here is the right place to do so, because
+                        * this is the first action (other than possibly a
+                        * back-up) that will match for the new input source.
+                        */
+                       yy_n_chars = yy_current_buffer->yy_n_chars;
+                       yy_current_buffer->yy_input_file = yyin;
+                       yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+                       }
+
+               /* Note that here we test for yy_c_buf_p "<=" to the position
+                * of the first EOB in the buffer, since yy_c_buf_p will
+                * already have been incremented past the NUL character
+                * (since all states make transitions on EOB to the
+                * end-of-buffer state).  Contrast this with the test
+                * in input().
+                */
+               if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+                       { /* This was really a NUL. */
+                       yy_state_type yy_next_state;
+
+                       yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+                       yy_current_state = yy_get_previous_state();
+
+                       /* Okay, we're now positioned to make the NUL
+                        * transition.  We couldn't have
+                        * yy_get_previous_state() go ahead and do it
+                        * for us because it doesn't know how to deal
+                        * with the possibility of jamming (and we don't
+                        * want to build jamming into it because then it
+                        * will run more slowly).
+                        */
+
+                       yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+                       yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+                       if ( yy_next_state )
+                               {
+                               /* Consume the NUL. */
+                               yy_cp = ++yy_c_buf_p;
+                               yy_current_state = yy_next_state;
+                               goto yy_match;
+                               }
+
+                       else
+                               {
+                               yy_cp = yy_c_buf_p;
+                               goto yy_find_action;
+                               }
+                       }
+
+               else switch ( yy_get_next_buffer() )
+                       {
+                       case EOB_ACT_END_OF_FILE:
+                               {
+                               yy_did_buffer_switch_on_eof = 0;
+
+                               if ( yywrap() )
+                                       {
+                                       /* Note: because we've taken care in
+                                        * yy_get_next_buffer() to have set up
+                                        * yytext, we can now set up
+                                        * yy_c_buf_p so that if some total
+                                        * hoser (like flex itself) wants to
+                                        * call the scanner after we return the
+                                        * YY_NULL, it'll still work - another
+                                        * YY_NULL will get returned.
+                                        */
+                                       yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+                                       yy_act = YY_STATE_EOF(YY_START);
+                                       goto do_action;
+                                       }
+
+                               else
+                                       {
+                                       if ( ! yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+                                       }
+                               break;
+                               }
+
+                       case EOB_ACT_CONTINUE_SCAN:
+                               yy_c_buf_p =
+                                       yytext_ptr + yy_amount_of_matched_text;
+
+                               yy_current_state = yy_get_previous_state();
+
+                               yy_cp = yy_c_buf_p;
+                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               goto yy_match;
+
+                       case EOB_ACT_LAST_MATCH:
+                               yy_c_buf_p =
+                               &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+                               yy_current_state = yy_get_previous_state();
+
+                               yy_cp = yy_c_buf_p;
+                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               goto yy_find_action;
+                       }
+               break;
+               }
+
+       default:
+               YY_FATAL_ERROR(
+                       "fatal flex scanner internal error--no action found" );
+       } /* end of action switch */
+               } /* end of scanning one token */
+       } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *     EOB_ACT_LAST_MATCH -
+ *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *     EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+       {
+       register char *dest = yy_current_buffer->yy_ch_buf;
+       register char *source = yytext_ptr;
+       register int number_to_move, i;
+       int ret_val;
+
+       if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+               YY_FATAL_ERROR(
+               "fatal flex scanner internal error--end of buffer missed" );
+
+       if ( yy_current_buffer->yy_fill_buffer == 0 )
+               { /* Don't try to fill the buffer, so this is an EOF. */
+               if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+                       {
+                       /* We matched a singled characater, the EOB, so
+                        * treat this as a final EOF.
+                        */
+                       return EOB_ACT_END_OF_FILE;
+                       }
+
+               else
+                       {
+                       /* We matched some text prior to the EOB, first
+                        * process it.
+                        */
+                       return EOB_ACT_LAST_MATCH;
+                       }
+               }
+
+       /* Try to read more data. */
+
+       /* First move last chars to start of buffer. */
+       number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+       for ( i = 0; i < number_to_move; ++i )
+               *(dest++) = *(source++);
+
+       if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+               /* don't do the read, it's not guaranteed to return an EOF,
+                * just force an EOF
+                */
+               yy_n_chars = 0;
+
+       else
+               {
+               int num_to_read =
+                       yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+               while ( num_to_read <= 0 )
+                       { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+                       YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+                       /* just a shorter name for the current buffer */
+                       YY_BUFFER_STATE b = yy_current_buffer;
+
+                       int yy_c_buf_p_offset =
+                               (int) (yy_c_buf_p - b->yy_ch_buf);
+
+                       if ( b->yy_is_our_buffer )
+                               {
+                               int old_size = b->yy_buf_size + 2;
+                               int new_size = b->yy_buf_size * 2;
+
+                               if ( new_size <= 0 )
+                                       b->yy_buf_size += b->yy_buf_size / 8;
+                               else
+                                       b->yy_buf_size *= 2;
+
+                               b->yy_ch_buf = (char *)
+                                       /* Include room in for 2 EOB chars. */
+                                       yy_flex_realloc2( (genericptr_t) b->yy_ch_buf,
+                                                        b->yy_buf_size + 2, old_size );
+                               }
+                       else
+                               /* Can't grow it, we don't own it. */
+                               b->yy_ch_buf = 0;
+
+                       if ( ! b->yy_ch_buf )
+                               YY_FATAL_ERROR(
+                               "fatal error - scanner input buffer overflow" );
+
+                       yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+                       num_to_read = yy_current_buffer->yy_buf_size -
+                                               number_to_move - 1;
+#endif
+                       }
+
+               if ( num_to_read > YY_READ_BUF_SIZE )
+                       num_to_read = YY_READ_BUF_SIZE;
+
+               /* Read in more data. */
+               YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+                       yy_n_chars, num_to_read );
+               }
+
+       if ( yy_n_chars == 0 )
+               {
+               if ( number_to_move == YY_MORE_ADJ )
+                       {
+                       ret_val = EOB_ACT_END_OF_FILE;
+                       yyrestart( yyin );
+                       }
+
+               else
+                       {
+                       ret_val = EOB_ACT_LAST_MATCH;
+                       yy_current_buffer->yy_buffer_status =
+                               YY_BUFFER_EOF_PENDING;
+                       }
+               }
+
+       else
+               ret_val = EOB_ACT_CONTINUE_SCAN;
+
+       yy_n_chars += number_to_move;
+       yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+       yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+       yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+       return ret_val;
+       }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+       {
+       register yy_state_type yy_current_state;
+       register char *yy_cp;
+
+       yy_current_state = yy_start;
+       yy_current_state += YY_AT_BOL();
+
+       for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+               {
+               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+               if ( yy_accept[yy_current_state] )
+                       {
+                       yy_last_accepting_state = yy_current_state;
+                       yy_last_accepting_cpos = yy_cp;
+                       }
+               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                       {
+                       yy_current_state = (int) yy_def[yy_current_state];
+                       if ( yy_current_state >= 640 )
+                               yy_c = yy_meta[(unsigned int) yy_c];
+                       }
+               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+               }
+
+       return yy_current_state;
+       }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *     next_state = yy_try_NUL_trans( current_state );
+ */
+
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+       {
+       register int yy_is_jam;
+       register char *yy_cp = yy_c_buf_p;
+
+       register YY_CHAR yy_c = 1;
+       if ( yy_accept[yy_current_state] )
+               {
+               yy_last_accepting_state = yy_current_state;
+               yy_last_accepting_cpos = yy_cp;
+               }
+       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+               {
+               yy_current_state = (int) yy_def[yy_current_state];
+               if ( yy_current_state >= 640 )
+                       yy_c = yy_meta[(unsigned int) yy_c];
+               }
+       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+       yy_is_jam = (yy_current_state == 639);
+
+       return yy_is_jam ? 0 : yy_current_state;
+       }
+
+
+#ifndef YY_NO_UNPUT
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+       {
+       register char *yy_cp = yy_c_buf_p;
+
+       /* undo effects of setting up yytext */
+       *yy_cp = yy_hold_char;
+
+       if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+               { /* need to shift things up to make room */
+               /* +2 for EOB chars. */
+               register int number_to_move = yy_n_chars + 2;
+               register char *dest = &yy_current_buffer->yy_ch_buf[
+                                       yy_current_buffer->yy_buf_size + 2];
+               register char *source =
+                               &yy_current_buffer->yy_ch_buf[number_to_move];
+
+               while ( source > yy_current_buffer->yy_ch_buf )
+                       *--dest = *--source;
+
+               yy_cp += (int) (dest - source);
+               yy_bp += (int) (dest - source);
+               yy_n_chars = yy_current_buffer->yy_buf_size;
+
+               if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
+               }
+
+       *--yy_cp = (char) c;
+
+
+       yytext_ptr = yy_bp;
+       yy_hold_char = *yy_cp;
+       yy_c_buf_p = yy_cp;
+       }
+#endif /* ifndef YY_NO_UNPUT */
+
+
+static int input()
+       {
+       int c;
+
+       *yy_c_buf_p = yy_hold_char;
+
+       if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+               {
+               /* yy_c_buf_p now points to the character we want to return.
+                * If this occurs *before* the EOB characters, then it's a
+                * valid NUL; if not, then we've hit the end of the buffer.
+                */
+               if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+                       /* This was really a NUL. */
+                       *yy_c_buf_p = '\0';
+
+               else
+                       { /* need more input */
+                       yytext_ptr = yy_c_buf_p;
+                       ++yy_c_buf_p;
+
+                       switch ( yy_get_next_buffer() )
+                               {
+                               case EOB_ACT_END_OF_FILE:
+                                       {
+                                       if ( yywrap() )
+                                               {
+                                               yy_c_buf_p =
+                                               yytext_ptr + YY_MORE_ADJ;
+                                               return EOF;
+                                               }
+
+                                       if ( ! yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+                                       return input();
+                                       }
+
+                               case EOB_ACT_CONTINUE_SCAN:
+                                       yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+                                       break;
+
+                               case EOB_ACT_LAST_MATCH:
+                                       YY_FATAL_ERROR(
+                                       "unexpected last match in input()" );
+                               }
+                       }
+               }
+
+       c = *(unsigned char *) yy_c_buf_p;      /* cast for 8-bit char's */
+       *yy_c_buf_p = '\0';     /* preserve yytext */
+       yy_hold_char = *++yy_c_buf_p;
+
+       yy_current_buffer->yy_at_bol = (c == '\n');
+
+       return c;
+       }
+
+
+void yyrestart( input_file )
+FILE *input_file;
+       {
+       if ( ! yy_current_buffer )
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+       yy_init_buffer( yy_current_buffer, input_file );
+       yy_load_buffer_state();
+       }
+
+
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+       {
+       if ( yy_current_buffer == new_buffer )
+               return;
+
+       if ( yy_current_buffer )
+               {
+               /* Flush out information for old buffer. */
+               *yy_c_buf_p = yy_hold_char;
+               yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+               yy_current_buffer->yy_n_chars = yy_n_chars;
+               }
+
+       yy_current_buffer = new_buffer;
+       yy_load_buffer_state();
+
+       /* We don't actually know whether we did this switch during
+        * EOF (yywrap()) processing, but the only time this flag
+        * is looked at is after yywrap() is called, so it's safe
+        * to go ahead and always set it.
+        */
+       yy_did_buffer_switch_on_eof = 1;
+       }
+
+
+void yy_load_buffer_state()
+       {
+       yy_n_chars = yy_current_buffer->yy_n_chars;
+       yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+       yyin = yy_current_buffer->yy_input_file;
+       yy_hold_char = *yy_c_buf_p;
+       }
+
+
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+       {
+       YY_BUFFER_STATE b;
+
+       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_buf_size = size;
+
+       /* yy_ch_buf has to be 2 characters longer than the size given because
+        * we need to put in 2 end-of-buffer characters.
+        */
+       b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+       if ( ! b->yy_ch_buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_is_our_buffer = 1;
+
+       yy_init_buffer( b, file );
+
+       return b;
+       }
+
+
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+       {
+       if ( ! b )
+               return;
+
+       if ( b == yy_current_buffer )
+               yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+       if ( b->yy_is_our_buffer )
+               yy_flex_free( (genericptr_t) b->yy_ch_buf );
+
+       yy_flex_free( (genericptr_t) b );
+       }
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int FDECL(isatty, (int));
+#endif
+#endif
+
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+       {
+       yy_flush_buffer( b );
+
+       b->yy_input_file = file;
+       b->yy_fill_buffer = 1;
+
+#ifdef YY_ALWAYS_INTERACTIVE
+       b->yy_is_interactive = 1;
+#else
+#ifdef YY_NEVER_INTERACTIVE
+       b->yy_is_interactive = 0;
+#else
+       b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+       }
+
+
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+       {
+       b->yy_n_chars = 0;
+
+       /* We always need two end-of-buffer characters.  The first causes
+        * a transition to the end-of-buffer state.  The second causes
+        * a jam in that state.
+        */
+       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+       b->yy_buf_pos = &b->yy_ch_buf[0];
+
+       b->yy_at_bol = 1;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       if ( b == yy_current_buffer )
+               yy_load_buffer_state();
+       }
+
+
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error( msg )
+const char msg[];
+       {
+       (void) fprintf( stderr, "%s\n", msg );
+       exit( YY_EXIT_FAILURE );
+       }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+               yytext[yyleng] = yy_hold_char; \
+               yy_c_buf_p = yytext + n - YY_MORE_ADJ; \
+               yy_hold_char = *yy_c_buf_p; \
+               *yy_c_buf_p = '\0'; \
+               yyleng = n; \
+               } \
+       while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+const char *s2;
+int n;
+       {
+       register int i;
+       for ( i = 0; i < n; ++i )
+               s1[i] = s2[i];
+       }
+#endif
+
+
+static genericptr_t yy_flex_alloc( size )
+yy_size_t size;
+       {
+       return (genericptr_t) alloc((unsigned)size);
+       }
+
+/* we want to avoid use of realloc(), so we require that caller supply the
+   size of the old block of memory */
+static genericptr_t yy_flex_realloc2( ptr, size, old_size )
+genericptr_t ptr;
+yy_size_t size;
+int old_size;
+       {
+       genericptr_t outptr = yy_flex_alloc(size);
+
+       if (ptr) {
+           char *p = (char *) outptr, *q = (char *) ptr;
+
+           while (--old_size >= 0) *p++ = *q++;
+           yy_flex_free(ptr);
+       }
+       return outptr;
+       }
+
+static void yy_flex_free( ptr )
+genericptr_t ptr;
+       {
+       free( ptr );
+       }
+
+/*flexhack.skl*/
+
+#ifdef AMIGA
+long *alloc(n)
+       unsigned n;
+{
+       return ((long *)malloc (n));
+}
+#endif
+
+/* routine to switch to another input file; needed for flex */
+void init_yyin( input_f )
+FILE *input_f;
+{
+#if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER)
+       if (yyin)
+           yyrestart(input_f);
+       else
+#endif
+           yyin = input_f;
+}
+/* analogous routine (for completeness) */
+void init_yyout( output_f )
+FILE *output_f;
+{
+       yyout = output_f;
+}
+
+/*lev_comp.l*/
diff --git a/sys/share/lev_yacc.c b/sys/share/lev_yacc.c
new file mode 100644 (file)
index 0000000..44dcdc0
--- /dev/null
@@ -0,0 +1,2418 @@
+#ifndef lint
+static char yysccsid[] = "@(#)yaccpar  1.9 (Berkeley) 02/21/93";
+#endif
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define yyclearin (yychar=(-1))
+#define yyerrok (yyerrflag=0)
+#define YYRECOVERING (yyerrflag!=0)
+#define YYPREFIX "yy"
+/*     SCCS Id: @(#)lev_yacc.c 3.4     2000/01/17      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file contains the Level Compiler code
+ * It may handle special mazes & special room-levels
+ */
+
+/* In case we're using bison in AIX.  This definition must be
+ * placed before any other C-language construct in the file
+ * excluding comments and preprocessor directives (thanks IBM
+ * for this wonderful feature...).
+ *
+ * Note: some cpps barf on this 'undefined control' (#pragma).
+ * Addition of the leading space seems to prevent barfage for now,
+ * and AIX will still see the directive.
+ */
+#ifdef _AIX
+ #pragma alloca                /* keep leading space! */
+#endif
+
+#include "hack.h"
+#include "sp_lev.h"
+
+#define MAX_REGISTERS  10
+#define ERR            (-1)
+/* many types of things are put in chars for transference to NetHack.
+ * since some systems will use signed chars, limit everybody to the
+ * same number for portability.
+ */
+#define MAX_OF_TYPE    128
+
+#define New(type)              \
+       (type *) memset((genericptr_t)alloc(sizeof(type)), 0, sizeof(type))
+#define NewTab(type, size)     (type **) alloc(sizeof(type *) * size)
+#define Free(ptr)              free((genericptr_t)ptr)
+
+extern void FDECL(yyerror, (const char *));
+extern void FDECL(yywarning, (const char *));
+extern int NDECL(yylex);
+int NDECL(yyparse);
+
+extern int FDECL(get_floor_type, (CHAR_P));
+extern int FDECL(get_room_type, (char *));
+extern int FDECL(get_trap_type, (char *));
+extern int FDECL(get_monster_id, (char *,CHAR_P));
+extern int FDECL(get_object_id, (char *,CHAR_P));
+extern boolean FDECL(check_monster_char, (CHAR_P));
+extern boolean FDECL(check_object_char, (CHAR_P));
+extern char FDECL(what_map_char, (CHAR_P));
+extern void FDECL(scan_map, (char *));
+extern void NDECL(wallify_map);
+extern boolean NDECL(check_subrooms);
+extern void FDECL(check_coord, (int,int,const char *));
+extern void NDECL(store_part);
+extern void NDECL(store_room);
+extern boolean FDECL(write_level_file, (char *,splev *,specialmaze *));
+extern void FDECL(free_rooms, (splev *));
+
+static struct reg {
+       int x1, y1;
+       int x2, y2;
+}              current_region;
+
+static struct coord {
+       int x;
+       int y;
+}              current_coord, current_align;
+
+static struct size {
+       int height;
+       int width;
+}              current_size;
+
+char tmpmessage[256];
+digpos *tmppass[32];
+char *tmpmap[ROWNO];
+
+digpos *tmpdig[MAX_OF_TYPE];
+region *tmpreg[MAX_OF_TYPE];
+lev_region *tmplreg[MAX_OF_TYPE];
+door *tmpdoor[MAX_OF_TYPE];
+drawbridge *tmpdb[MAX_OF_TYPE];
+walk *tmpwalk[MAX_OF_TYPE];
+
+room_door *tmprdoor[MAX_OF_TYPE];
+trap *tmptrap[MAX_OF_TYPE];
+monster *tmpmonst[MAX_OF_TYPE];
+object *tmpobj[MAX_OF_TYPE];
+altar *tmpaltar[MAX_OF_TYPE];
+lad *tmplad[MAX_OF_TYPE];
+stair *tmpstair[MAX_OF_TYPE];
+gold *tmpgold[MAX_OF_TYPE];
+engraving *tmpengraving[MAX_OF_TYPE];
+fountain *tmpfountain[MAX_OF_TYPE];
+sink *tmpsink[MAX_OF_TYPE];
+pool *tmppool[MAX_OF_TYPE];
+
+mazepart *tmppart[10];
+room *tmproom[MAXNROFROOMS*2];
+corridor *tmpcor[MAX_OF_TYPE];
+
+static specialmaze maze;
+static splev special_lev;
+static lev_init init_lev;
+
+static char olist[MAX_REGISTERS], mlist[MAX_REGISTERS];
+static struct coord plist[MAX_REGISTERS];
+
+int n_olist = 0, n_mlist = 0, n_plist = 0;
+
+unsigned int nlreg = 0, nreg = 0, ndoor = 0, ntrap = 0, nmons = 0, nobj = 0;
+unsigned int ndb = 0, nwalk = 0, npart = 0, ndig = 0, nlad = 0, nstair = 0;
+unsigned int naltar = 0, ncorridor = 0, nrooms = 0, ngold = 0, nengraving = 0;
+unsigned int nfountain = 0, npool = 0, nsink = 0, npass = 0;
+
+static int lev_flags = 0;
+
+unsigned int max_x_map, max_y_map;
+
+static xchar in_room;
+
+extern int fatal_error;
+extern int want_warnings;
+extern const char *fname;
+
+typedef union
+{
+       int     i;
+       char*   map;
+       struct {
+               xchar room;
+               xchar wall;
+               xchar door;
+       } corpos;
+} YYSTYPE;
+#define CHAR 257
+#define INTEGER 258
+#define BOOLEAN 259
+#define PERCENT 260
+#define MESSAGE_ID 261
+#define MAZE_ID 262
+#define LEVEL_ID 263
+#define LEV_INIT_ID 264
+#define GEOMETRY_ID 265
+#define NOMAP_ID 266
+#define OBJECT_ID 267
+#define COBJECT_ID 268
+#define MONSTER_ID 269
+#define TRAP_ID 270
+#define DOOR_ID 271
+#define DRAWBRIDGE_ID 272
+#define MAZEWALK_ID 273
+#define WALLIFY_ID 274
+#define REGION_ID 275
+#define FILLING 276
+#define RANDOM_OBJECTS_ID 277
+#define RANDOM_MONSTERS_ID 278
+#define RANDOM_PLACES_ID 279
+#define ALTAR_ID 280
+#define LADDER_ID 281
+#define STAIR_ID 282
+#define NON_DIGGABLE_ID 283
+#define NON_PASSWALL_ID 284
+#define ROOM_ID 285
+#define PORTAL_ID 286
+#define TELEPRT_ID 287
+#define BRANCH_ID 288
+#define LEV 289
+#define CHANCE_ID 290
+#define CORRIDOR_ID 291
+#define GOLD_ID 292
+#define ENGRAVING_ID 293
+#define FOUNTAIN_ID 294
+#define POOL_ID 295
+#define SINK_ID 296
+#define NONE 297
+#define RAND_CORRIDOR_ID 298
+#define DOOR_STATE 299
+#define LIGHT_STATE 300
+#define CURSE_TYPE 301
+#define ENGRAVING_TYPE 302
+#define DIRECTION 303
+#define RANDOM_TYPE 304
+#define O_REGISTER 305
+#define M_REGISTER 306
+#define P_REGISTER 307
+#define A_REGISTER 308
+#define ALIGNMENT 309
+#define LEFT_OR_RIGHT 310
+#define CENTER 311
+#define TOP_OR_BOT 312
+#define ALTAR_TYPE 313
+#define UP_OR_DOWN 314
+#define SUBROOM_ID 315
+#define NAME_ID 316
+#define FLAGS_ID 317
+#define FLAG_TYPE 318
+#define MON_ATTITUDE 319
+#define MON_ALERTNESS 320
+#define MON_APPEARANCE 321
+#define CONTAINED 322
+#define STRING 323
+#define MAP_ID 324
+#define YYERRCODE 256
+short yylhs[] = {                                        -1,
+    0,    0,   36,   36,   37,   37,   38,   39,   32,   23,
+   23,   14,   14,   19,   19,   20,   20,   40,   40,   45,
+   42,   42,   46,   46,   43,   43,   49,   49,   44,   44,
+   51,   52,   52,   53,   53,   35,   50,   50,   56,   54,
+   10,   10,   59,   59,   57,   57,   60,   60,   58,   58,
+   55,   55,   61,   61,   61,   61,   61,   61,   61,   61,
+   61,   61,   61,   61,   61,   62,   63,   64,   15,   15,
+   13,   13,   12,   12,   31,   11,   11,   41,   41,   75,
+   76,   76,   79,    1,    1,    2,    2,   77,   77,   80,
+   80,   80,   47,   47,   48,   48,   81,   83,   81,   78,
+   78,   84,   84,   84,   84,   84,   84,   84,   84,   84,
+   84,   84,   84,   84,   84,   84,   84,   84,   84,   84,
+   84,   99,   65,   98,   98,  100,  100,  100,  100,  100,
+   66,   66,  102,  101,  103,  103,  104,  104,  104,  104,
+  105,  105,  106,  107,  107,  108,  108,  108,   85,   67,
+   86,   92,   93,   94,   74,  109,   88,  110,   89,  111,
+  113,   90,  114,   91,  112,  112,   22,   22,   69,   70,
+   71,   95,   96,   87,   68,   72,   73,   25,   25,   25,
+   28,   28,   28,   33,   33,   34,   34,    3,    3,    4,
+    4,   21,   21,   21,   97,   97,   97,    5,    5,    6,
+    6,    7,    7,    7,    8,    8,  117,   29,   26,    9,
+   82,   24,   27,   30,   16,   16,   17,   17,   18,   18,
+  116,  115,
+};
+short yylen[] = {                                         2,
+    0,    1,    1,    2,    1,    1,    5,    7,    3,    0,
+   13,    1,    1,    0,    3,    3,    1,    0,    2,    3,
+    0,    2,    3,    3,    0,    1,    1,    2,    1,    1,
+    1,    0,    2,    5,    5,    7,    2,    2,   12,   12,
+    0,    2,    5,    1,    5,    1,    5,    1,    5,    1,
+    0,    2,    1,    1,    1,    1,    1,    1,    1,    1,
+    1,    1,    1,    1,    1,    3,    3,    9,    1,    1,
+    1,    1,    1,    1,    5,    1,    1,    1,    2,    3,
+    1,    2,    5,    1,    1,    1,    1,    0,    2,    3,
+    3,    3,    1,    3,    1,    3,    1,    0,    4,    0,
+    2,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+    1,    0,   10,    0,    2,    2,    2,    2,    2,    3,
+    2,    2,    0,    9,    1,    1,    0,    7,    5,    5,
+    1,    1,    1,    1,    1,    0,    2,    2,    5,    6,
+    7,    5,    1,    5,    5,    0,    8,    0,    8,    0,
+    0,    8,    0,    6,    0,    2,    1,   10,    3,    3,
+    3,    3,    3,    8,    7,    5,    7,    1,    1,    1,
+    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+    1,    0,    2,    4,    1,    1,    1,    1,    1,    1,
+    1,    1,    1,    1,    1,    1,    4,    4,    4,    4,
+    1,    1,    1,    1,    1,    1,    0,    1,    1,    1,
+    5,    9,
+};
+short yydefred[] = {                                      0,
+    0,    0,    0,    0,    0,    2,    0,    5,    6,    0,
+    0,    0,    0,    0,    4,  214,    0,    9,    0,    0,
+    0,    0,    0,    0,   15,    0,    0,    0,    0,   21,
+   76,   77,   75,    0,    0,    0,    0,   81,    7,    0,
+   88,    0,   19,    0,   16,    0,   20,    0,   79,    0,
+   82,    0,    0,    0,    0,    0,   22,   26,    0,   51,
+   51,    0,   84,   85,    0,    0,    0,    0,    0,   89,
+    0,    0,    0,    0,   31,    8,   29,    0,   28,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,  153,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,  102,  103,  105,  112,
+  113,  118,  119,  117,  101,  104,  106,  107,  108,  109,
+  110,  111,  114,  115,  116,  120,  121,  213,    0,   23,
+  212,    0,   24,  191,    0,  190,    0,    0,   33,    0,
+    0,    0,    0,    0,    0,   52,   53,   54,   55,   56,
+   57,   58,   59,   60,   61,   62,   63,   64,   65,    0,
+   87,   86,   83,   90,   92,    0,   91,    0,  211,  218,
+    0,  131,  132,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,  198,  199,    0,
+  197,    0,    0,  195,  196,    0,    0,    0,    0,    0,
+    0,    0,  156,    0,  167,  172,  173,  158,  160,  163,
+  215,  216,    0,    0,  169,   94,   96,  200,  201,    0,
+    0,    0,    0,   69,   70,    0,   67,  171,  170,   66,
+    0,    0,    0,  182,    0,  181,    0,  183,  179,    0,
+  178,    0,  180,  189,    0,  188,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+   99,    0,    0,    0,    0,    0,  149,    0,    0,  152,
+    0,    0,  204,    0,  202,    0,  203,  154,    0,    0,
+    0,  155,    0,    0,    0,  176,  219,  220,    0,   44,
+    0,    0,   46,    0,    0,    0,   35,   34,    0,    0,
+  221,    0,  187,  186,  133,    0,  185,  184,    0,  150,
+  207,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+  161,  164,    0,    0,    0,    0,    0,    0,    0,    0,
+  208,    0,  209,    0,  151,    0,    0,    0,  206,  205,
+  175,    0,    0,    0,    0,  177,    0,   48,    0,    0,
+    0,   50,    0,    0,    0,   71,   72,    0,   12,   13,
+   11,    0,  122,    0,    0,  174,  210,    0,  157,  159,
+    0,  162,    0,    0,    0,    0,    0,    0,   73,   74,
+    0,    0,  136,  135,    0,  124,    0,    0,    0,  166,
+   43,    0,    0,   45,    0,    0,   36,   68,    0,  134,
+    0,    0,    0,    0,    0,    0,   40,    0,   39,  142,
+  141,  143,    0,    0,    0,  125,  222,  194,    0,   47,
+   42,   49,    0,    0,  127,  128,    0,  129,  126,  168,
+  145,  144,    0,    0,    0,  130,    0,    0,  139,  140,
+    0,  147,  148,  138,
+};
+short yydgoto[] = {                                       3,
+   65,  163,  265,  135,  210,  240,  306,  371,  307,  437,
+   33,  411,  388,  391,  246,  233,  171,  319,   13,   25,
+  396,  223,   21,  132,  262,  263,  129,  257,  258,  136,
+    4,    5,  339,  335,  243,    6,    7,    8,    9,   28,
+   39,   44,   56,   76,   29,   57,  130,  133,   58,   59,
+   77,   78,  139,   60,   80,   61,  325,  384,  322,  380,
+  146,  147,  148,  149,  150,  151,  152,  153,  154,  155,
+  156,  157,  158,  159,   40,   41,   50,   69,   42,   70,
+  167,  168,  204,  115,  116,  117,  118,  119,  120,  121,
+  122,  123,  124,  125,  126,  127,  224,  431,  416,  446,
+  172,  362,  415,  430,  443,  444,  464,  469,  277,  279,
+  280,  402,  375,  281,  225,  214,  215,
+};
+short yysindex[] = {                                   -166,
+  -18,    4,    0, -233, -233,    0, -166,    0,    0, -222,
+ -222,   32, -134, -134,    0,    0,   88,    0, -173,   76,
+ -114, -114, -230,  105,    0,  -99,  115, -124, -114,    0,
+    0,    0,    0, -173,  127, -143,  128,    0,    0, -124,
+    0, -132,    0, -236,    0,  -67,    0, -155,    0, -156,
+    0,  137,  138,  140,  142,  -94,    0,    0, -263,    0,
+    0,  161,    0,    0,  162,  149,  150,  151, -105,    0,
+  -47,  -46, -276, -276,    0,    0,    0,  -79,    0, -142,
+ -142,  -45, -151,  -47,  -46,  173,  -44,  -44,  -44,  -44,
+  160,  163,  165,    0,  166,  167,  168,  170,  171,  172,
+  174,  175,  176,  177,  178,  179,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,  187,    0,
+    0,  194,    0,    0,  195,    0,  197,  184,    0,  185,
+  186,  188,  189,  190,  191,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,  206,
+    0,    0,    0,    0,    0,  -43,    0,    0,    0,    0,
+  193,    0,    0,  196,  198, -239,   45,   45,  180,   45,
+   45,   58,  180,  180,  -37,  -37,  -37, -232,   45,   45,
+  -47,  -46, -218, -218,  205, -238,   45,  -41,   45,   45,
+ -222,   -6,  211,  213, -234, -237, -268,    0,    0,  214,
+    0,  169,  215,    0,    0,  217,  -39,  218,  219,  220,
+  225,   12,    0,  296,    0,    0,    0,    0,    0,    0,
+    0,    0,  300,  306,    0,    0,    0,    0,    0,  317,
+  319,  112,  329,    0,    0,  341,    0,    0,    0,    0,
+  342,  129,  173,    0,  315,    0,  366,    0,    0,  320,
+    0,  368,    0,    0,  374,    0,   45,  200,  120,  124,
+  385, -218, -201,  116,  202,  389,  390,  118,  399,  401,
+  405,   45, -254,  -38,   -9,  407,  -36, -239, -218,  411,
+    0,  207, -267,  238, -260,   45,    0,  360,  410,    0,
+  239,  412,    0,  386,    0,  415,    0,    0,  454,  242,
+  -37,    0,  -37,  -37,  -37,    0,    0,    0,  457,    0,
+  246,  492,    0,  279,  495,  237,    0,    0,  497,  498,
+    0,  456,    0,    0,    0,  458,    0,    0,  506,    0,
+    0, -239,  509, -276,  298, -259,  299,   72,  510,  517,
+    0,    0, -222,  518,   -1,  519,   28,  520, -119, -227,
+    0,  522,    0,   45,    0,  316,  531,  483,    0,    0,
+    0,  533,  264, -222,  537,    0,  321,    0, -155,  539,
+  328,    0,  330,  543, -229,    0,    0,  545,    0,    0,
+    0,   38,    0,  546,  318,    0,    0,  333,    0,    0,
+  281,    0,  552,  555,   28,  559,  557, -222,    0,    0,
+  561, -229,    0,    0,  560,    0,  338,  563,  566,    0,
+    0, -151,  571,    0,  345,  571,    0,    0, -243,    0,
+  575,  579,  362,  367,  585,  371,    0,  586,    0,    0,
+    0,    0,  590,  591, -209,    0,    0,    0,  597,    0,
+    0,    0, -240, -228,    0,    0, -222,    0,    0,    0,
+    0,    0,  595,  599,  599,    0, -228, -264,    0,    0,
+  599,    0,    0,    0,
+};
+short yyrindex[] = {                                    641,
+    0,    0,    0, -172,  307,    0,  645,    0,    0,    0,
+    0,    0, -146,  355,    0,    0,    0,    0,    0,    0,
+  -72,  351,    0,  282,    0,    0,    0,    0,  346,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,  104,
+    0,    0,    0,  157,    0,    0,    0,    0,    0,  491,
+    0,    0,    0,    0,    0,   57,    0,    0,  159,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   91,    0,
+    0,    0,    0,    0,    0,    0,    0,  106,    0,  267,
+  388,    0,    0,    0,    0,    0,  589,  589,  589,  589,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,  201,    0,
+    0,  240,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,  446,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,  535,    0,    0,    0,
+    0,    0,    0,    0,  572,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    6,    0,    0,  606,    0,    0,
+    0,    0,  146,    0,    0,  146,    0,    0,    0,    0,
+   43,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,  109,  109,    0,    0,    0,    0,    0,
+  109,    0,    0,    0,
+};
+short yygindex[] = {                                      0,
+  269,  230,    0,  -60, -269, -184,  209,    0,    0,  229,
+    0,  244,    0,    0,    0,    0,  113,    0,  652,  624,
+    0, -178,  646,  453,    0,    0,  459,    0,    0,  -10,
+    0,    0,    0,    0,  375,  656,    0,    0,    0,   24,
+  625,    0,    0,    0,    0,    0,  -73,  -68,  608,    0,
+    0,    0,    0,    0,  607,    0,    0,  266,    0,    0,
+    0,    0,    0,    0,  600,  603,  605,  609,  611,    0,
+    0,  612,  613,  614,    0,    0,    0,    0,    0,    0,
+  422,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0, -165,    0,    0,    0,
+  588,    0,    0,    0,    0,  224, -416, -384,    0,    0,
+    0,    0,    0,    0,  -40,  -81,    0,
+};
+#define YYTABLESIZE 900
+short yytable[] = {                                      17,
+   18,  321,  217,  242,  169,  137,  228,  229,  230,  241,
+  164,  213,  216,  137,  219,  220,  165,  461,  329,  131,
+  244,   54,  128,  234,  235,  231,   31,  134,  409,  461,
+  324,  389,  472,  248,  249,  264,  333,  465,  379,   10,
+   52,   53,  123,  337,  369,   30,   16,  317,   54,  318,
+  471,   55,   43,  370,   16,   16,   32,  440,  473,  208,
+  441,   11,   16,  462,  209,  245,  259,  383,  260,  254,
+  255,  232,  365,   32,  410,  462,  390,  166,   55,  442,
+  470,  238,  442,   12,  166,  239,  474,  302,   14,   19,
+   80,   14,   14,   14,  303,    1,    2,  222,  304,  305,
+   16,  297,  303,   78,  330,   30,  304,  305,  146,  455,
+  456,  457,  331,   16,   10,  366,  316,  236,   10,   10,
+   66,   67,   68,  237,   87,   88,   89,   90,  140,   20,
+  340,   23,  349,   26,  350,  351,  352,   96,  218,  141,
+   37,   38,  226,  227,   24,   41,   27,  142,   34,  104,
+  105,  106,  143,  144,   63,   64,   25,   35,   27,  161,
+  162,   87,   88,   89,   90,   91,   92,   93,   94,   95,
+   46,  169,   36,  145,   96,   97,   98,   99,  100,   47,
+  101,  102,  103,  386,  387,   48,  104,  105,  106,   62,
+  250,   51,   18,   18,   71,   72,  266,   73,  393,   74,
+   93,  174,  175,   75,   82,   83,   84,   85,   86,  128,
+  131,  138,  166,  160,  203,  170,  247,  176,  271,  217,
+  177,  327,  178,  179,  180,  181,  414,  182,  183,  184,
+  191,  185,  186,  187,  188,  189,  190,  192,  193,   95,
+  194,  195,  196,  197,  242,  198,  199,  200,  201,  202,
+  205,  221,  251,  206,  252,  207,  253,  267,  269,  268,
+  270,  272,  273,  274,  275,  320,   37,  137,  137,  276,
+  137,  137,  137,  137,  137,  137,  137,  137,  137,  137,
+  137,   17,  334,  367,  338,  137,  137,  137,  137,  137,
+  137,  137,  137,  137,  323,  137,  137,  137,  137,  137,
+  137,  137,  378,  137,  123,  123,   14,  123,  123,  123,
+  123,  123,  123,  123,  123,  123,  123,  123,   32,   32,
+  137,  137,  123,  123,  123,  123,  123,  123,  123,  123,
+  123,  382,  123,  123,  123,  123,  123,  123,  123,  278,
+  123,  211,  376,  282,  212,   18,  221,   32,  211,  283,
+   18,  212,   80,   80,   10,   80,   80,  123,  123,  413,
+  284,  211,  285,  400,  212,   78,   78,   30,   30,  286,
+  146,  146,  287,  146,  146,  146,  146,  146,  146,  146,
+  146,  146,  146,  146,  288,  289,  290,   38,  146,  146,
+  146,  146,  146,  146,  146,  146,  146,  426,  146,  146,
+  146,  146,  146,  146,  146,  292,  146,   41,   41,  293,
+  294,  295,   41,   41,   41,   41,   41,  296,   25,   25,
+   27,   27,  299,  146,  146,   41,  300,   41,  301,  308,
+   41,  312,  310,  311,  459,   41,   41,   41,   41,   41,
+   41,   41,  313,   41,  314,   97,  466,   25,  315,   27,
+  326,  331,  341,  342,   25,  344,   27,  298,  346,  309,
+   41,   41,   93,   93,  332,   93,   93,   93,   93,   93,
+   93,   93,   93,   93,   93,   93,  345,   93,   93,   93,
+   93,   93,   93,   93,   93,   93,   93,   93,   93,   98,
+  100,   93,   93,   93,   93,  336,  343,  347,   93,  348,
+  353,   95,   95,  354,   95,   95,   95,   95,   95,   95,
+   95,   95,   95,   95,   95,   93,   95,   95,   95,   95,
+   95,   95,   95,   95,   95,   95,   95,   95,   37,   37,
+   95,   95,   95,   95,  192,  355,  356,   95,  357,  358,
+  359,  360,   17,   17,   17,   17,   17,   17,  361,  364,
+  363,   37,  366,  373,   95,  368,  372,   37,   17,   17,
+  374,  377,  381,  385,   37,  392,   17,   14,   14,   14,
+   14,  165,   17,  394,  395,  397,  398,  399,  403,   17,
+  401,   37,  405,   14,   14,  406,  408,  407,  412,  417,
+  419,   14,  421,  418,  420,  432,   17,   14,  422,  424,
+  425,  427,  438,  429,   14,  193,  433,   18,   18,  434,
+   18,   18,   18,   18,  436,   10,   10,   10,  445,  447,
+  448,   14,   18,   18,  449,  450,  452,   18,   18,  451,
+   18,   10,   10,  453,  454,   18,   18,  460,  467,   10,
+    1,   18,  468,   18,    3,   10,  217,  404,   18,   38,
+   38,  435,   10,  458,  439,  428,   14,   45,  261,   22,
+   18,  328,   15,  256,   49,   18,   79,   81,  107,   10,
+  423,  108,   38,  109,  291,  173,  463,  110,   38,  111,
+  112,  113,  114,    0,    0,   38,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,   38,    0,    0,    0,    0,   97,   97,    0,
+   97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+   97,    0,   97,   97,   97,   97,   97,   97,   97,   97,
+    0,   97,   97,   97,    0,    0,    0,   97,   97,   97,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,  100,  100,    0,  100,  100,  100,  100,  100,
+  100,  100,  100,  100,  100,  100,    0,    0,    0,    0,
+  100,  100,  100,  100,  100,    0,  100,  100,  100,    0,
+    0,    0,  100,  100,  100,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,  192,  192,    0,  192,
+  192,  192,  192,  192,  192,  192,  192,  192,  192,  192,
+    0,    0,    0,    0,  192,  192,  192,  192,  192,    0,
+  192,  192,  192,    0,    0,    0,  192,  192,  192,    0,
+    0,    0,    0,  165,  165,    0,  165,  165,  165,  165,
+  165,  165,  165,  165,  165,  165,  165,    0,    0,    0,
+    0,  165,  165,  165,  165,  165,    0,  165,  165,  165,
+    0,    0,    0,  165,  165,  165,    0,  193,  193,    0,
+  193,  193,  193,  193,  193,  193,  193,  193,  193,  193,
+  193,    0,    0,    0,    0,  193,  193,  193,  193,  193,
+    0,  193,  193,  193,    0,    0,    0,  193,  193,  193,
+};
+short yycheck[] = {                                      10,
+   11,   40,   40,   40,   86,    0,  185,  186,  187,  194,
+   84,  177,  178,   74,  180,  181,   85,  258,  288,  257,
+  259,  285,  257,  189,  190,  258,  257,  304,  258,  258,
+   40,  259,  297,  199,  200,  304,  304,  454,   40,   58,
+  277,  278,    0,  304,  304,   22,  323,  302,  285,  304,
+  467,  315,   29,  313,  323,  323,    0,  301,  323,  299,
+  304,   58,  323,  304,  304,  304,  304,   40,  306,  304,
+  305,  304,  342,  304,  304,  304,  304,   40,  315,  323,
+  465,  300,  323,  317,   40,  304,  471,  272,  261,   58,
+    0,  264,  265,  266,  304,  262,  263,   40,  308,  309,
+  323,  267,  304,    0,  289,    0,  308,  309,    0,  319,
+  320,  321,   41,  323,  261,   44,  282,  191,  265,  266,
+  277,  278,  279,  192,  267,  268,  269,  270,  271,  264,
+  296,   44,  311,   58,  313,  314,  315,  280,  179,  282,
+  265,  266,  183,  184,  318,    0,  261,  290,   44,  292,
+  293,  294,  295,  296,  310,  311,    0,  257,    0,  311,
+  312,  267,  268,  269,  270,  271,  272,  273,  274,  275,
+   44,  253,   58,  316,  280,  281,  282,  283,  284,  323,
+  286,  287,  288,  303,  304,   58,  292,  293,  294,  257,
+  201,  324,  265,  266,   58,   58,  207,   58,  364,   58,
+    0,   89,   90,  298,   44,   44,   58,   58,   58,  257,
+  257,  291,   40,  259,  258,  260,  258,   58,  258,   40,
+   58,  258,   58,   58,   58,   58,  392,   58,   58,   58,
+   44,   58,   58,   58,   58,   58,   58,   44,   44,    0,
+   44,   58,   58,   58,   40,   58,   58,   58,   58,   44,
+   58,  289,  259,   58,   44,   58,   44,   44,   44,   91,
+   44,   44,   44,   44,   40,  304,    0,  262,  263,  258,
+  265,  266,  267,  268,  269,  270,  271,  272,  273,  274,
+  275,    0,  293,  344,  295,  280,  281,  282,  283,  284,
+  285,  286,  287,  288,  304,  290,  291,  292,  293,  294,
+  295,  296,  304,  298,  262,  263,    0,  265,  266,  267,
+  268,  269,  270,  271,  272,  273,  274,  275,  262,  263,
+  315,  316,  280,  281,  282,  283,  284,  285,  286,  287,
+  288,  304,  290,  291,  292,  293,  294,  295,  296,   44,
+  298,  304,  353,   44,  307,    0,  289,  291,  304,   44,
+    0,  307,  262,  263,    0,  265,  266,  315,  316,  322,
+   44,  304,   44,  374,  307,  262,  263,  262,  263,  258,
+  262,  263,   44,  265,  266,  267,  268,  269,  270,  271,
+  272,  273,  274,  275,   44,   44,  258,    0,  280,  281,
+  282,  283,  284,  285,  286,  287,  288,  408,  290,  291,
+  292,  293,  294,  295,  296,   91,  298,  262,  263,   44,
+   91,   44,  267,  268,  269,  270,  271,   44,  262,  263,
+  262,  263,  303,  315,  316,  280,  303,  282,   44,  314,
+  285,  314,   44,   44,  445,  290,  291,  292,  293,  294,
+  295,  296,   44,  298,   44,    0,  457,  291,   44,  291,
+   44,   41,   93,   44,  298,   44,  298,  258,   44,  258,
+  315,  316,  262,  263,  258,  265,  266,  267,  268,  269,
+  270,  271,  272,  273,  274,  275,   91,  277,  278,  279,
+  280,  281,  282,  283,  284,  285,  286,  287,  288,   44,
+    0,  291,  292,  293,  294,  258,  258,   44,  298,  258,
+   44,  262,  263,  258,  265,  266,  267,  268,  269,  270,
+  271,  272,  273,  274,  275,  315,  277,  278,  279,  280,
+  281,  282,  283,  284,  285,  286,  287,  288,  262,  263,
+  291,  292,  293,  294,    0,   44,  258,  298,   44,  303,
+   44,   44,  261,  262,  263,  264,  265,  266,   93,   44,
+   93,  285,   44,   44,  315,  258,  258,  291,  277,  278,
+   44,   44,   44,   44,  298,   44,  285,  261,  262,  263,
+  264,    0,  291,  258,   44,   93,   44,  314,  258,  298,
+   44,  315,   44,  277,  278,  258,   44,  258,   44,   44,
+  258,  285,   41,  276,  314,  258,  315,  291,   44,   41,
+   44,   41,  258,   44,  298,    0,   44,  262,  263,   44,
+  265,  266,  262,  263,   44,  261,  262,  263,   44,   41,
+  259,  315,  277,  278,  258,   41,   41,  277,  278,  259,
+  285,  277,  278,   44,   44,  285,  291,   41,   44,  285,
+    0,  291,   44,  298,    0,  291,   58,  379,  298,  262,
+  263,  422,  298,  445,  426,  412,    5,   34,  206,   14,
+  315,  287,    7,  205,   40,  315,   59,   61,   69,  315,
+  405,   69,  285,   69,  253,   88,  453,   69,  291,   69,
+   69,   69,   69,   -1,   -1,  298,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,  315,   -1,   -1,   -1,   -1,  262,  263,   -1,
+  265,  266,  267,  268,  269,  270,  271,  272,  273,  274,
+  275,   -1,  277,  278,  279,  280,  281,  282,  283,  284,
+   -1,  286,  287,  288,   -1,   -1,   -1,  292,  293,  294,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,  262,  263,   -1,  265,  266,  267,  268,  269,
+  270,  271,  272,  273,  274,  275,   -1,   -1,   -1,   -1,
+  280,  281,  282,  283,  284,   -1,  286,  287,  288,   -1,
+   -1,   -1,  292,  293,  294,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,  262,  263,   -1,  265,
+  266,  267,  268,  269,  270,  271,  272,  273,  274,  275,
+   -1,   -1,   -1,   -1,  280,  281,  282,  283,  284,   -1,
+  286,  287,  288,   -1,   -1,   -1,  292,  293,  294,   -1,
+   -1,   -1,   -1,  262,  263,   -1,  265,  266,  267,  268,
+  269,  270,  271,  272,  273,  274,  275,   -1,   -1,   -1,
+   -1,  280,  281,  282,  283,  284,   -1,  286,  287,  288,
+   -1,   -1,   -1,  292,  293,  294,   -1,  262,  263,   -1,
+  265,  266,  267,  268,  269,  270,  271,  272,  273,  274,
+  275,   -1,   -1,   -1,   -1,  280,  281,  282,  283,  284,
+   -1,  286,  287,  288,   -1,   -1,   -1,  292,  293,  294,
+};
+#define YYFINAL 3
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 324
+#if YYDEBUG
+char *yyname[] = {
+"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,"'('","')'",0,0,"','",0,0,0,0,0,0,0,0,0,0,0,0,0,"':'",0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'['",0,"']'",0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"CHAR",
+"INTEGER","BOOLEAN","PERCENT","MESSAGE_ID","MAZE_ID","LEVEL_ID","LEV_INIT_ID",
+"GEOMETRY_ID","NOMAP_ID","OBJECT_ID","COBJECT_ID","MONSTER_ID","TRAP_ID",
+"DOOR_ID","DRAWBRIDGE_ID","MAZEWALK_ID","WALLIFY_ID","REGION_ID","FILLING",
+"RANDOM_OBJECTS_ID","RANDOM_MONSTERS_ID","RANDOM_PLACES_ID","ALTAR_ID",
+"LADDER_ID","STAIR_ID","NON_DIGGABLE_ID","NON_PASSWALL_ID","ROOM_ID",
+"PORTAL_ID","TELEPRT_ID","BRANCH_ID","LEV","CHANCE_ID","CORRIDOR_ID","GOLD_ID",
+"ENGRAVING_ID","FOUNTAIN_ID","POOL_ID","SINK_ID","NONE","RAND_CORRIDOR_ID",
+"DOOR_STATE","LIGHT_STATE","CURSE_TYPE","ENGRAVING_TYPE","DIRECTION",
+"RANDOM_TYPE","O_REGISTER","M_REGISTER","P_REGISTER","A_REGISTER","ALIGNMENT",
+"LEFT_OR_RIGHT","CENTER","TOP_OR_BOT","ALTAR_TYPE","UP_OR_DOWN","SUBROOM_ID",
+"NAME_ID","FLAGS_ID","FLAG_TYPE","MON_ATTITUDE","MON_ALERTNESS",
+"MON_APPEARANCE","CONTAINED","STRING","MAP_ID",
+};
+char *yyrule[] = {
+"$accept : file",
+"file :",
+"file : levels",
+"levels : level",
+"levels : level levels",
+"level : maze_level",
+"level : room_level",
+"maze_level : maze_def flags lev_init messages regions",
+"room_level : level_def flags lev_init messages rreg_init rooms corridors_def",
+"level_def : LEVEL_ID ':' string",
+"lev_init :",
+"lev_init : LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled",
+"walled : BOOLEAN",
+"walled : RANDOM_TYPE",
+"flags :",
+"flags : FLAGS_ID ':' flag_list",
+"flag_list : FLAG_TYPE ',' flag_list",
+"flag_list : FLAG_TYPE",
+"messages :",
+"messages : message messages",
+"message : MESSAGE_ID ':' STRING",
+"rreg_init :",
+"rreg_init : rreg_init init_rreg",
+"init_rreg : RANDOM_OBJECTS_ID ':' object_list",
+"init_rreg : RANDOM_MONSTERS_ID ':' monster_list",
+"rooms :",
+"rooms : roomlist",
+"roomlist : aroom",
+"roomlist : aroom roomlist",
+"corridors_def : random_corridors",
+"corridors_def : corridors",
+"random_corridors : RAND_CORRIDOR_ID",
+"corridors :",
+"corridors : corridors corridor",
+"corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec",
+"corridor : CORRIDOR_ID ':' corr_spec ',' INTEGER",
+"corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')'",
+"aroom : room_def room_details",
+"aroom : subroom_def room_details",
+"subroom_def : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill",
+"room_def : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill",
+"roomfill :",
+"roomfill : ',' BOOLEAN",
+"room_pos : '(' INTEGER ',' INTEGER ')'",
+"room_pos : RANDOM_TYPE",
+"subroom_pos : '(' INTEGER ',' INTEGER ')'",
+"subroom_pos : RANDOM_TYPE",
+"room_align : '(' h_justif ',' v_justif ')'",
+"room_align : RANDOM_TYPE",
+"room_size : '(' INTEGER ',' INTEGER ')'",
+"room_size : RANDOM_TYPE",
+"room_details :",
+"room_details : room_details room_detail",
+"room_detail : room_name",
+"room_detail : room_chance",
+"room_detail : room_door",
+"room_detail : monster_detail",
+"room_detail : object_detail",
+"room_detail : trap_detail",
+"room_detail : altar_detail",
+"room_detail : fountain_detail",
+"room_detail : sink_detail",
+"room_detail : pool_detail",
+"room_detail : gold_detail",
+"room_detail : engraving_detail",
+"room_detail : stair_detail",
+"room_name : NAME_ID ':' string",
+"room_chance : CHANCE_ID ':' INTEGER",
+"room_door : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos",
+"secret : BOOLEAN",
+"secret : RANDOM_TYPE",
+"door_wall : DIRECTION",
+"door_wall : RANDOM_TYPE",
+"door_pos : INTEGER",
+"door_pos : RANDOM_TYPE",
+"maze_def : MAZE_ID ':' string ',' filling",
+"filling : CHAR",
+"filling : RANDOM_TYPE",
+"regions : aregion",
+"regions : aregion regions",
+"aregion : map_definition reg_init map_details",
+"map_definition : NOMAP_ID",
+"map_definition : map_geometry MAP_ID",
+"map_geometry : GEOMETRY_ID ':' h_justif ',' v_justif",
+"h_justif : LEFT_OR_RIGHT",
+"h_justif : CENTER",
+"v_justif : TOP_OR_BOT",
+"v_justif : CENTER",
+"reg_init :",
+"reg_init : reg_init init_reg",
+"init_reg : RANDOM_OBJECTS_ID ':' object_list",
+"init_reg : RANDOM_PLACES_ID ':' place_list",
+"init_reg : RANDOM_MONSTERS_ID ':' monster_list",
+"object_list : object",
+"object_list : object ',' object_list",
+"monster_list : monster",
+"monster_list : monster ',' monster_list",
+"place_list : place",
+"$$1 :",
+"place_list : place $$1 ',' place_list",
+"map_details :",
+"map_details : map_details map_detail",
+"map_detail : monster_detail",
+"map_detail : object_detail",
+"map_detail : door_detail",
+"map_detail : trap_detail",
+"map_detail : drawbridge_detail",
+"map_detail : region_detail",
+"map_detail : stair_region",
+"map_detail : portal_region",
+"map_detail : teleprt_region",
+"map_detail : branch_region",
+"map_detail : altar_detail",
+"map_detail : fountain_detail",
+"map_detail : mazewalk_detail",
+"map_detail : wallify_detail",
+"map_detail : ladder_detail",
+"map_detail : stair_detail",
+"map_detail : gold_detail",
+"map_detail : engraving_detail",
+"map_detail : diggable_detail",
+"map_detail : passwall_detail",
+"$$2 :",
+"monster_detail : MONSTER_ID chance ':' monster_c ',' m_name ',' coordinate $$2 monster_infos",
+"monster_infos :",
+"monster_infos : monster_infos monster_info",
+"monster_info : ',' string",
+"monster_info : ',' MON_ATTITUDE",
+"monster_info : ',' MON_ALERTNESS",
+"monster_info : ',' alignment",
+"monster_info : ',' MON_APPEARANCE string",
+"object_detail : OBJECT_ID object_desc",
+"object_detail : COBJECT_ID object_desc",
+"$$3 :",
+"object_desc : chance ':' object_c ',' o_name $$3 ',' object_where object_infos",
+"object_where : coordinate",
+"object_where : CONTAINED",
+"object_infos :",
+"object_infos : ',' curse_state ',' monster_id ',' enchantment optional_name",
+"object_infos : ',' curse_state ',' enchantment optional_name",
+"object_infos : ',' monster_id ',' enchantment optional_name",
+"curse_state : RANDOM_TYPE",
+"curse_state : CURSE_TYPE",
+"monster_id : STRING",
+"enchantment : RANDOM_TYPE",
+"enchantment : INTEGER",
+"optional_name :",
+"optional_name : ',' NONE",
+"optional_name : ',' STRING",
+"door_detail : DOOR_ID ':' door_state ',' coordinate",
+"trap_detail : TRAP_ID chance ':' trap_name ',' coordinate",
+"drawbridge_detail : DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state",
+"mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION",
+"wallify_detail : WALLIFY_ID",
+"ladder_detail : LADDER_ID ':' coordinate ',' UP_OR_DOWN",
+"stair_detail : STAIR_ID ':' coordinate ',' UP_OR_DOWN",
+"$$4 :",
+"stair_region : STAIR_ID ':' lev_region $$4 ',' lev_region ',' UP_OR_DOWN",
+"$$5 :",
+"portal_region : PORTAL_ID ':' lev_region $$5 ',' lev_region ',' string",
+"$$6 :",
+"$$7 :",
+"teleprt_region : TELEPRT_ID ':' lev_region $$6 ',' lev_region $$7 teleprt_detail",
+"$$8 :",
+"branch_region : BRANCH_ID ':' lev_region $$8 ',' lev_region",
+"teleprt_detail :",
+"teleprt_detail : ',' UP_OR_DOWN",
+"lev_region : region",
+"lev_region : LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'",
+"fountain_detail : FOUNTAIN_ID ':' coordinate",
+"sink_detail : SINK_ID ':' coordinate",
+"pool_detail : POOL_ID ':' coordinate",
+"diggable_detail : NON_DIGGABLE_ID ':' region",
+"passwall_detail : NON_PASSWALL_ID ':' region",
+"region_detail : REGION_ID ':' region ',' light_state ',' room_type prefilled",
+"altar_detail : ALTAR_ID ':' coordinate ',' alignment ',' altar_type",
+"gold_detail : GOLD_ID ':' amount ',' coordinate",
+"engraving_detail : ENGRAVING_ID ':' coordinate ',' engraving_type ',' string",
+"monster_c : monster",
+"monster_c : RANDOM_TYPE",
+"monster_c : m_register",
+"object_c : object",
+"object_c : RANDOM_TYPE",
+"object_c : o_register",
+"m_name : string",
+"m_name : RANDOM_TYPE",
+"o_name : string",
+"o_name : RANDOM_TYPE",
+"trap_name : string",
+"trap_name : RANDOM_TYPE",
+"room_type : string",
+"room_type : RANDOM_TYPE",
+"prefilled :",
+"prefilled : ',' FILLING",
+"prefilled : ',' FILLING ',' BOOLEAN",
+"coordinate : coord",
+"coordinate : p_register",
+"coordinate : RANDOM_TYPE",
+"door_state : DOOR_STATE",
+"door_state : RANDOM_TYPE",
+"light_state : LIGHT_STATE",
+"light_state : RANDOM_TYPE",
+"alignment : ALIGNMENT",
+"alignment : a_register",
+"alignment : RANDOM_TYPE",
+"altar_type : ALTAR_TYPE",
+"altar_type : RANDOM_TYPE",
+"p_register : P_REGISTER '[' INTEGER ']'",
+"o_register : O_REGISTER '[' INTEGER ']'",
+"m_register : M_REGISTER '[' INTEGER ']'",
+"a_register : A_REGISTER '[' INTEGER ']'",
+"place : coord",
+"monster : CHAR",
+"object : CHAR",
+"string : STRING",
+"amount : INTEGER",
+"amount : RANDOM_TYPE",
+"chance :",
+"chance : PERCENT",
+"engraving_type : ENGRAVING_TYPE",
+"engraving_type : RANDOM_TYPE",
+"coord : '(' INTEGER ',' INTEGER ')'",
+"region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'",
+};
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 500
+#define YYMAXDEPTH 500
+#endif
+#endif
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+short yyss[YYSTACKSIZE];
+YYSTYPE yyvs[YYSTACKSIZE];
+#define yystacksize YYSTACKSIZE
+
+/*lev_comp.y*/
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+yyparse()
+{
+    register int yym, yyn, yystate;
+#if YYDEBUG
+    register char *yys;
+    extern char *getenv();
+
+    if ((yys = getenv("YYDEBUG")) != 0)
+    {
+        yyn = *yys;
+        if (yyn >= '0' && yyn <= '9')
+            yydebug = yyn - '0';
+    }
+#endif
+
+    yynerrs = 0;
+    yyerrflag = 0;
+    yychar = (-1);
+
+    yyssp = yyss;
+    yyvsp = yyvs;
+    *yyssp = yystate = 0;
+
+yyloop:
+    if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
+    if (yychar < 0)
+    {
+        if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, reading %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+    }
+    if ((yyn = yysindex[yystate]) != 0 && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: state %d, shifting to state %d\n",
+                    YYPREFIX, yystate, yytable[yyn]);
+#endif
+        if (yyssp >= yyss + yystacksize - 1)
+        {
+            goto yyoverflow;
+        }
+        *++yyssp = yystate = yytable[yyn];
+        *++yyvsp = yylval;
+        yychar = (-1);
+        if (yyerrflag > 0)  --yyerrflag;
+        goto yyloop;
+    }
+    if ((yyn = yyrindex[yystate]) != 0 && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+        yyn = yytable[yyn];
+        goto yyreduce;
+    }
+    if (yyerrflag) goto yyinrecovery;
+#ifdef lint
+    goto yynewerror;
+#endif
+yynewerror:
+    yyerror("syntax error");
+#ifdef lint
+    goto yyerrlab;
+#endif
+yyerrlab:
+    ++yynerrs;
+yyinrecovery:
+    if (yyerrflag < 3)
+    {
+        yyerrflag = 3;
+        for (;;)
+        {
+            if ((yyn = yysindex[*yyssp]) != 0 && (yyn += YYERRCODE) >= 0 &&
+                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
+#endif
+                if (yyssp >= yyss + yystacksize - 1)
+                {
+                    goto yyoverflow;
+                }
+                *++yyssp = yystate = yytable[yyn];
+                *++yyvsp = yylval;
+                goto yyloop;
+            }
+            else
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: error recovery discarding state %d\n",
+                            YYPREFIX, *yyssp);
+#endif
+                if (yyssp <= yyss) goto yyabort;
+                --yyssp;
+                --yyvsp;
+            }
+        }
+    }
+    else
+    {
+        if (yychar == 0) goto yyabort;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+        yychar = (-1);
+        goto yyloop;
+    }
+yyreduce:
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+                YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+    yym = yylen[yyn];
+    yyval = yyvsp[1-yym];
+    switch (yyn)
+    {
+case 7:
+{
+                       unsigned i;
+
+                       if (fatal_error > 0) {
+                               (void) fprintf(stderr,
+                               "%s : %d errors detected. No output created!\n",
+                                       fname, fatal_error);
+                       } else {
+                               maze.flags = yyvsp[-3].i;
+                               (void) memcpy((genericptr_t)&(maze.init_lev),
+                                               (genericptr_t)&(init_lev),
+                                               sizeof(lev_init));
+                               maze.numpart = npart;
+                               maze.parts = NewTab(mazepart, npart);
+                               for(i=0;i<npart;i++)
+                                   maze.parts[i] = tmppart[i];
+                               if (!write_level_file(yyvsp[-4].map, (splev *)0, &maze)) {
+                                       yyerror("Can't write output file!!");
+                                       exit(EXIT_FAILURE);
+                               }
+                               npart = 0;
+                       }
+                       Free(yyvsp[-4].map);
+                 }
+break;
+case 8:
+{
+                       unsigned i;
+
+                       if (fatal_error > 0) {
+                           (void) fprintf(stderr,
+                             "%s : %d errors detected. No output created!\n",
+                                       fname, fatal_error);
+                       } else {
+                               special_lev.flags = (long) yyvsp[-5].i;
+                               (void) memcpy(
+                                       (genericptr_t)&(special_lev.init_lev),
+                                       (genericptr_t)&(init_lev),
+                                       sizeof(lev_init));
+                               special_lev.nroom = nrooms;
+                               special_lev.rooms = NewTab(room, nrooms);
+                               for(i=0; i<nrooms; i++)
+                                   special_lev.rooms[i] = tmproom[i];
+                               special_lev.ncorr = ncorridor;
+                               special_lev.corrs = NewTab(corridor, ncorridor);
+                               for(i=0; i<ncorridor; i++)
+                                   special_lev.corrs[i] = tmpcor[i];
+                               if (check_subrooms()) {
+                                   if (!write_level_file(yyvsp[-6].map, &special_lev,
+                                                         (specialmaze *)0)) {
+                                       yyerror("Can't write output file!!");
+                                       exit(EXIT_FAILURE);
+                                   }
+                               }
+                               free_rooms(&special_lev);
+                               nrooms = 0;
+                               ncorridor = 0;
+                       }
+                       Free(yyvsp[-6].map);
+                 }
+break;
+case 9:
+{
+                       if (index(yyvsp[0].map, '.'))
+                           yyerror("Invalid dot ('.') in level name.");
+                       if ((int) strlen(yyvsp[0].map) > 8)
+                           yyerror("Level names limited to 8 characters.");
+                       yyval.map = yyvsp[0].map;
+                       special_lev.nrmonst = special_lev.nrobjects = 0;
+                       n_mlist = n_olist = 0;
+                 }
+break;
+case 10:
+{
+                       /* in case we're processing multiple files,
+                          explicitly clear any stale settings */
+                       (void) memset((genericptr_t) &init_lev, 0,
+                                       sizeof init_lev);
+                       init_lev.init_present = FALSE;
+                       yyval.i = 0;
+                 }
+break;
+case 11:
+{
+                       init_lev.init_present = TRUE;
+                       init_lev.fg = what_map_char((char) yyvsp[-10].i);
+                       if (init_lev.fg == INVALID_TYPE)
+                           yyerror("Invalid foreground type.");
+                       init_lev.bg = what_map_char((char) yyvsp[-8].i);
+                       if (init_lev.bg == INVALID_TYPE)
+                           yyerror("Invalid background type.");
+                       init_lev.smoothed = yyvsp[-6].i;
+                       init_lev.joined = yyvsp[-4].i;
+                       if (init_lev.joined &&
+                           init_lev.fg != CORR && init_lev.fg != ROOM)
+                           yyerror("Invalid foreground type for joined map.");
+                       init_lev.lit = yyvsp[-2].i;
+                       init_lev.walled = yyvsp[0].i;
+                       yyval.i = 1;
+                 }
+break;
+case 14:
+{
+                       yyval.i = 0;
+                 }
+break;
+case 15:
+{
+                       yyval.i = lev_flags;
+                       lev_flags = 0;  /* clear for next user */
+                 }
+break;
+case 16:
+{
+                       lev_flags |= yyvsp[-2].i;
+                 }
+break;
+case 17:
+{
+                       lev_flags |= yyvsp[0].i;
+                 }
+break;
+case 20:
+{
+                       int i, j;
+
+                       i = (int) strlen(yyvsp[0].map) + 1;
+                       j = (int) strlen(tmpmessage);
+                       if (i + j > 255) {
+                          yyerror("Message string too long (>256 characters)");
+                       } else {
+                           if (j) tmpmessage[j++] = '\n';
+                           (void) strncpy(tmpmessage+j, yyvsp[0].map, i - 1);
+                           tmpmessage[j + i - 1] = 0;
+                       }
+                       Free(yyvsp[0].map);
+                 }
+break;
+case 23:
+{
+                       if(special_lev.nrobjects) {
+                           yyerror("Object registers already initialized!");
+                       } else {
+                           special_lev.nrobjects = n_olist;
+                           special_lev.robjects = (char *) alloc(n_olist);
+                           (void) memcpy((genericptr_t)special_lev.robjects,
+                                         (genericptr_t)olist, n_olist);
+                       }
+                 }
+break;
+case 24:
+{
+                       if(special_lev.nrmonst) {
+                           yyerror("Monster registers already initialized!");
+                       } else {
+                           special_lev.nrmonst = n_mlist;
+                           special_lev.rmonst = (char *) alloc(n_mlist);
+                           (void) memcpy((genericptr_t)special_lev.rmonst,
+                                         (genericptr_t)mlist, n_mlist);
+                         }
+                 }
+break;
+case 25:
+{
+                       tmproom[nrooms] = New(room);
+                       tmproom[nrooms]->name = (char *) 0;
+                       tmproom[nrooms]->parent = (char *) 0;
+                       tmproom[nrooms]->rtype = 0;
+                       tmproom[nrooms]->rlit = 0;
+                       tmproom[nrooms]->xalign = ERR;
+                       tmproom[nrooms]->yalign = ERR;
+                       tmproom[nrooms]->x = 0;
+                       tmproom[nrooms]->y = 0;
+                       tmproom[nrooms]->w = 2;
+                       tmproom[nrooms]->h = 2;
+                       in_room = 1;
+                 }
+break;
+case 31:
+{
+                       tmpcor[0] = New(corridor);
+                       tmpcor[0]->src.room = -1;
+                       ncorridor = 1;
+                 }
+break;
+case 34:
+{
+                       tmpcor[ncorridor] = New(corridor);
+                       tmpcor[ncorridor]->src.room = yyvsp[-2].corpos.room;
+                       tmpcor[ncorridor]->src.wall = yyvsp[-2].corpos.wall;
+                       tmpcor[ncorridor]->src.door = yyvsp[-2].corpos.door;
+                       tmpcor[ncorridor]->dest.room = yyvsp[0].corpos.room;
+                       tmpcor[ncorridor]->dest.wall = yyvsp[0].corpos.wall;
+                       tmpcor[ncorridor]->dest.door = yyvsp[0].corpos.door;
+                       ncorridor++;
+                       if (ncorridor >= MAX_OF_TYPE) {
+                               yyerror("Too many corridors in level!");
+                               ncorridor--;
+                       }
+                 }
+break;
+case 35:
+{
+                       tmpcor[ncorridor] = New(corridor);
+                       tmpcor[ncorridor]->src.room = yyvsp[-2].corpos.room;
+                       tmpcor[ncorridor]->src.wall = yyvsp[-2].corpos.wall;
+                       tmpcor[ncorridor]->src.door = yyvsp[-2].corpos.door;
+                       tmpcor[ncorridor]->dest.room = -1;
+                       tmpcor[ncorridor]->dest.wall = yyvsp[0].i;
+                       ncorridor++;
+                       if (ncorridor >= MAX_OF_TYPE) {
+                               yyerror("Too many corridors in level!");
+                               ncorridor--;
+                       }
+                 }
+break;
+case 36:
+{
+                       if ((unsigned) yyvsp[-5].i >= nrooms)
+                           yyerror("Wrong room number!");
+                       yyval.corpos.room = yyvsp[-5].i;
+                       yyval.corpos.wall = yyvsp[-3].i;
+                       yyval.corpos.door = yyvsp[-1].i;
+                 }
+break;
+case 37:
+{
+                       store_room();
+                 }
+break;
+case 38:
+{
+                       store_room();
+                 }
+break;
+case 39:
+{
+                       tmproom[nrooms] = New(room);
+                       tmproom[nrooms]->parent = yyvsp[-1].map;
+                       tmproom[nrooms]->name = (char *) 0;
+                       tmproom[nrooms]->rtype = yyvsp[-9].i;
+                       tmproom[nrooms]->rlit = yyvsp[-7].i;
+                       tmproom[nrooms]->filled = yyvsp[0].i;
+                       tmproom[nrooms]->xalign = ERR;
+                       tmproom[nrooms]->yalign = ERR;
+                       tmproom[nrooms]->x = current_coord.x;
+                       tmproom[nrooms]->y = current_coord.y;
+                       tmproom[nrooms]->w = current_size.width;
+                       tmproom[nrooms]->h = current_size.height;
+                       in_room = 1;
+                 }
+break;
+case 40:
+{
+                       tmproom[nrooms] = New(room);
+                       tmproom[nrooms]->name = (char *) 0;
+                       tmproom[nrooms]->parent = (char *) 0;
+                       tmproom[nrooms]->rtype = yyvsp[-9].i;
+                       tmproom[nrooms]->rlit = yyvsp[-7].i;
+                       tmproom[nrooms]->filled = yyvsp[0].i;
+                       tmproom[nrooms]->xalign = current_align.x;
+                       tmproom[nrooms]->yalign = current_align.y;
+                       tmproom[nrooms]->x = current_coord.x;
+                       tmproom[nrooms]->y = current_coord.y;
+                       tmproom[nrooms]->w = current_size.width;
+                       tmproom[nrooms]->h = current_size.height;
+                       in_room = 1;
+                 }
+break;
+case 41:
+{
+                       yyval.i = 1;
+                 }
+break;
+case 42:
+{
+                       yyval.i = yyvsp[0].i;
+                 }
+break;
+case 43:
+{
+                       if ( yyvsp[-3].i < 1 || yyvsp[-3].i > 5 ||
+                           yyvsp[-1].i < 1 || yyvsp[-1].i > 5 ) {
+                           yyerror("Room position should be between 1 & 5!");
+                       } else {
+                           current_coord.x = yyvsp[-3].i;
+                           current_coord.y = yyvsp[-1].i;
+                       }
+                 }
+break;
+case 44:
+{
+                       current_coord.x = current_coord.y = ERR;
+                 }
+break;
+case 45:
+{
+                       if ( yyvsp[-3].i < 0 || yyvsp[-1].i < 0) {
+                           yyerror("Invalid subroom position !");
+                       } else {
+                           current_coord.x = yyvsp[-3].i;
+                           current_coord.y = yyvsp[-1].i;
+                       }
+                 }
+break;
+case 46:
+{
+                       current_coord.x = current_coord.y = ERR;
+                 }
+break;
+case 47:
+{
+                       current_align.x = yyvsp[-3].i;
+                       current_align.y = yyvsp[-1].i;
+                 }
+break;
+case 48:
+{
+                       current_align.x = current_align.y = ERR;
+                 }
+break;
+case 49:
+{
+                       current_size.width = yyvsp[-3].i;
+                       current_size.height = yyvsp[-1].i;
+                 }
+break;
+case 50:
+{
+                       current_size.height = current_size.width = ERR;
+                 }
+break;
+case 66:
+{
+                       if (tmproom[nrooms]->name)
+                           yyerror("This room already has a name!");
+                       else
+                           tmproom[nrooms]->name = yyvsp[0].map;
+                 }
+break;
+case 67:
+{
+                       if (tmproom[nrooms]->chance)
+                           yyerror("This room already assigned a chance!");
+                       else if (tmproom[nrooms]->rtype == OROOM)
+                           yyerror("Only typed rooms can have a chance!");
+                       else if (yyvsp[0].i < 1 || yyvsp[0].i > 99)
+                           yyerror("The chance is supposed to be percentile.");
+                       else
+                           tmproom[nrooms]->chance = yyvsp[0].i;
+                  }
+break;
+case 68:
+{
+                       /* ERR means random here */
+                       if (yyvsp[-2].i == ERR && yyvsp[0].i != ERR) {
+                    yyerror("If the door wall is random, so must be its pos!");
+                       } else {
+                           tmprdoor[ndoor] = New(room_door);
+                           tmprdoor[ndoor]->secret = yyvsp[-6].i;
+                           tmprdoor[ndoor]->mask = yyvsp[-4].i;
+                           tmprdoor[ndoor]->wall = yyvsp[-2].i;
+                           tmprdoor[ndoor]->pos = yyvsp[0].i;
+                           ndoor++;
+                           if (ndoor >= MAX_OF_TYPE) {
+                                   yyerror("Too many doors in room!");
+                                   ndoor--;
+                           }
+                       }
+                 }
+break;
+case 75:
+{
+                       maze.filling = (schar) yyvsp[0].i;
+                       if (index(yyvsp[-2].map, '.'))
+                           yyerror("Invalid dot ('.') in level name.");
+                       if ((int) strlen(yyvsp[-2].map) > 8)
+                           yyerror("Level names limited to 8 characters.");
+                       yyval.map = yyvsp[-2].map;
+                       in_room = 0;
+                       n_plist = n_mlist = n_olist = 0;
+                 }
+break;
+case 76:
+{
+                       yyval.i = get_floor_type((char)yyvsp[0].i);
+                 }
+break;
+case 77:
+{
+                       yyval.i = -1;
+                 }
+break;
+case 80:
+{
+                       store_part();
+                 }
+break;
+case 81:
+{
+                       tmppart[npart] = New(mazepart);
+                       tmppart[npart]->halign = 1;
+                       tmppart[npart]->valign = 1;
+                       tmppart[npart]->nrobjects = 0;
+                       tmppart[npart]->nloc = 0;
+                       tmppart[npart]->nrmonst = 0;
+                       tmppart[npart]->xsize = 1;
+                       tmppart[npart]->ysize = 1;
+                       tmppart[npart]->map = (char **) alloc(sizeof(char *));
+                       tmppart[npart]->map[0] = (char *) alloc(1);
+                       tmppart[npart]->map[0][0] = STONE;
+                       max_x_map = COLNO-1;
+                       max_y_map = ROWNO;
+                 }
+break;
+case 82:
+{
+                       tmppart[npart] = New(mazepart);
+                       tmppart[npart]->halign = yyvsp[-1].i % 10;
+                       tmppart[npart]->valign = yyvsp[-1].i / 10;
+                       tmppart[npart]->nrobjects = 0;
+                       tmppart[npart]->nloc = 0;
+                       tmppart[npart]->nrmonst = 0;
+                       scan_map(yyvsp[0].map);
+                       Free(yyvsp[0].map);
+                 }
+break;
+case 83:
+{
+                       yyval.i = yyvsp[-2].i + (yyvsp[0].i * 10);
+                 }
+break;
+case 90:
+{
+                       if (tmppart[npart]->nrobjects) {
+                           yyerror("Object registers already initialized!");
+                       } else {
+                           tmppart[npart]->robjects = (char *)alloc(n_olist);
+                           (void) memcpy((genericptr_t)tmppart[npart]->robjects,
+                                         (genericptr_t)olist, n_olist);
+                           tmppart[npart]->nrobjects = n_olist;
+                       }
+                 }
+break;
+case 91:
+{
+                       if (tmppart[npart]->nloc) {
+                           yyerror("Location registers already initialized!");
+                       } else {
+                           register int i;
+                           tmppart[npart]->rloc_x = (char *) alloc(n_plist);
+                           tmppart[npart]->rloc_y = (char *) alloc(n_plist);
+                           for(i=0;i<n_plist;i++) {
+                               tmppart[npart]->rloc_x[i] = plist[i].x;
+                               tmppart[npart]->rloc_y[i] = plist[i].y;
+                           }
+                           tmppart[npart]->nloc = n_plist;
+                       }
+                 }
+break;
+case 92:
+{
+                       if (tmppart[npart]->nrmonst) {
+                           yyerror("Monster registers already initialized!");
+                       } else {
+                           tmppart[npart]->rmonst = (char *) alloc(n_mlist);
+                           (void) memcpy((genericptr_t)tmppart[npart]->rmonst,
+                                         (genericptr_t)mlist, n_mlist);
+                           tmppart[npart]->nrmonst = n_mlist;
+                       }
+                 }
+break;
+case 93:
+{
+                       if (n_olist < MAX_REGISTERS)
+                           olist[n_olist++] = yyvsp[0].i;
+                       else
+                           yyerror("Object list too long!");
+                 }
+break;
+case 94:
+{
+                       if (n_olist < MAX_REGISTERS)
+                           olist[n_olist++] = yyvsp[-2].i;
+                       else
+                           yyerror("Object list too long!");
+                 }
+break;
+case 95:
+{
+                       if (n_mlist < MAX_REGISTERS)
+                           mlist[n_mlist++] = yyvsp[0].i;
+                       else
+                           yyerror("Monster list too long!");
+                 }
+break;
+case 96:
+{
+                       if (n_mlist < MAX_REGISTERS)
+                           mlist[n_mlist++] = yyvsp[-2].i;
+                       else
+                           yyerror("Monster list too long!");
+                 }
+break;
+case 97:
+{
+                       if (n_plist < MAX_REGISTERS)
+                           plist[n_plist++] = current_coord;
+                       else
+                           yyerror("Location list too long!");
+                 }
+break;
+case 98:
+{
+                       if (n_plist < MAX_REGISTERS)
+                           plist[n_plist++] = current_coord;
+                       else
+                           yyerror("Location list too long!");
+                 }
+break;
+case 122:
+{
+                       tmpmonst[nmons] = New(monster);
+                       tmpmonst[nmons]->x = current_coord.x;
+                       tmpmonst[nmons]->y = current_coord.y;
+                       tmpmonst[nmons]->class = yyvsp[-4].i;
+                       tmpmonst[nmons]->peaceful = -1; /* no override */
+                       tmpmonst[nmons]->asleep = -1;
+                       tmpmonst[nmons]->align = - MAX_REGISTERS - 2;
+                       tmpmonst[nmons]->name.str = 0;
+                       tmpmonst[nmons]->appear = 0;
+                       tmpmonst[nmons]->appear_as.str = 0;
+                       tmpmonst[nmons]->chance = yyvsp[-6].i;
+                       tmpmonst[nmons]->id = NON_PM;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Monster");
+                       if (yyvsp[-2].map) {
+                           int token = get_monster_id(yyvsp[-2].map, (char) yyvsp[-4].i);
+                           if (token == ERR)
+                               yywarning(
+                             "Invalid monster name!  Making random monster.");
+                           else
+                               tmpmonst[nmons]->id = token;
+                           Free(yyvsp[-2].map);
+                       }
+                 }
+break;
+case 123:
+{
+                       if (++nmons >= MAX_OF_TYPE) {
+                           yyerror("Too many monsters in room or mazepart!");
+                           nmons--;
+                       }
+                 }
+break;
+case 126:
+{
+                       tmpmonst[nmons]->name.str = yyvsp[0].map;
+                 }
+break;
+case 127:
+{
+                       tmpmonst[nmons]->peaceful = yyvsp[0].i;
+                 }
+break;
+case 128:
+{
+                       tmpmonst[nmons]->asleep = yyvsp[0].i;
+                 }
+break;
+case 129:
+{
+                       tmpmonst[nmons]->align = yyvsp[0].i;
+                 }
+break;
+case 130:
+{
+                       tmpmonst[nmons]->appear = yyvsp[-1].i;
+                       tmpmonst[nmons]->appear_as.str = yyvsp[0].map;
+                 }
+break;
+case 131:
+{
+                 }
+break;
+case 132:
+{
+                       /* 1: is contents of preceeding object with 2 */
+                       /* 2: is a container */
+                       /* 0: neither */
+                       tmpobj[nobj-1]->containment = 2;
+                 }
+break;
+case 133:
+{
+                       tmpobj[nobj] = New(object);
+                       tmpobj[nobj]->class = yyvsp[-2].i;
+                       tmpobj[nobj]->corpsenm = NON_PM;
+                       tmpobj[nobj]->curse_state = -1;
+                       tmpobj[nobj]->name.str = 0;
+                       tmpobj[nobj]->chance = yyvsp[-4].i;
+                       tmpobj[nobj]->id = -1;
+                       if (yyvsp[0].map) {
+                           int token = get_object_id(yyvsp[0].map, yyvsp[-2].i);
+                           if (token == ERR)
+                               yywarning(
+                               "Illegal object name!  Making random object.");
+                            else
+                               tmpobj[nobj]->id = token;
+                           Free(yyvsp[0].map);
+                       }
+                 }
+break;
+case 134:
+{
+                       if (++nobj >= MAX_OF_TYPE) {
+                           yyerror("Too many objects in room or mazepart!");
+                           nobj--;
+                       }
+                 }
+break;
+case 135:
+{
+                       tmpobj[nobj]->containment = 0;
+                       tmpobj[nobj]->x = current_coord.x;
+                       tmpobj[nobj]->y = current_coord.y;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Object");
+                 }
+break;
+case 136:
+{
+                       tmpobj[nobj]->containment = 1;
+                       /* random coordinate, will be overridden anyway */
+                       tmpobj[nobj]->x = -MAX_REGISTERS-1;
+                       tmpobj[nobj]->y = -MAX_REGISTERS-1;
+                 }
+break;
+case 137:
+{
+                       tmpobj[nobj]->spe = -127;
+       /* Note below: we're trying to make as many of these optional as
+        * possible.  We clearly can't make curse_state, enchantment, and
+        * monster_id _all_ optional, since ",random" would be ambiguous.
+        * We can't even just make enchantment mandatory, since if we do that
+        * alone, ",random" requires too much lookahead to parse.
+        */
+                 }
+break;
+case 138:
+{
+                 }
+break;
+case 139:
+{
+                 }
+break;
+case 140:
+{
+                 }
+break;
+case 141:
+{
+                       tmpobj[nobj]->curse_state = -1;
+                 }
+break;
+case 142:
+{
+                       tmpobj[nobj]->curse_state = yyvsp[0].i;
+                 }
+break;
+case 143:
+{
+                       int token = get_monster_id(yyvsp[0].map, (char)0);
+                       if (token == ERR)       /* "random" */
+                           tmpobj[nobj]->corpsenm = NON_PM - 1;
+                       else
+                           tmpobj[nobj]->corpsenm = token;
+                       Free(yyvsp[0].map);
+                 }
+break;
+case 144:
+{
+                       tmpobj[nobj]->spe = -127;
+                 }
+break;
+case 145:
+{
+                       tmpobj[nobj]->spe = yyvsp[0].i;
+                 }
+break;
+case 147:
+{
+                 }
+break;
+case 148:
+{
+                       tmpobj[nobj]->name.str = yyvsp[0].map;
+                 }
+break;
+case 149:
+{
+                       tmpdoor[ndoor] = New(door);
+                       tmpdoor[ndoor]->x = current_coord.x;
+                       tmpdoor[ndoor]->y = current_coord.y;
+                       tmpdoor[ndoor]->mask = yyvsp[-2].i;
+                       if(current_coord.x >= 0 && current_coord.y >= 0 &&
+                          tmpmap[current_coord.y][current_coord.x] != DOOR &&
+                          tmpmap[current_coord.y][current_coord.x] != SDOOR)
+                           yyerror("Door decl doesn't match the map");
+                       ndoor++;
+                       if (ndoor >= MAX_OF_TYPE) {
+                               yyerror("Too many doors in mazepart!");
+                               ndoor--;
+                       }
+                 }
+break;
+case 150:
+{
+                       tmptrap[ntrap] = New(trap);
+                       tmptrap[ntrap]->x = current_coord.x;
+                       tmptrap[ntrap]->y = current_coord.y;
+                       tmptrap[ntrap]->type = yyvsp[-2].i;
+                       tmptrap[ntrap]->chance = yyvsp[-4].i;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Trap");
+                       if (++ntrap >= MAX_OF_TYPE) {
+                               yyerror("Too many traps in room or mazepart!");
+                               ntrap--;
+                       }
+                 }
+break;
+case 151:
+{
+                       int x, y, dir;
+
+                       tmpdb[ndb] = New(drawbridge);
+                       x = tmpdb[ndb]->x = current_coord.x;
+                       y = tmpdb[ndb]->y = current_coord.y;
+                       /* convert dir from a DIRECTION to a DB_DIR */
+                       dir = yyvsp[-2].i;
+                       switch(dir) {
+                       case W_NORTH: dir = DB_NORTH; y--; break;
+                       case W_SOUTH: dir = DB_SOUTH; y++; break;
+                       case W_EAST:  dir = DB_EAST;  x++; break;
+                       case W_WEST:  dir = DB_WEST;  x--; break;
+                       default:
+                           yyerror("Invalid drawbridge direction");
+                           break;
+                       }
+                       tmpdb[ndb]->dir = dir;
+                       if (current_coord.x >= 0 && current_coord.y >= 0 &&
+                           !IS_WALL(tmpmap[y][x])) {
+                           char ebuf[60];
+                           Sprintf(ebuf,
+                                   "Wall needed for drawbridge (%02d, %02d)",
+                                   current_coord.x, current_coord.y);
+                           yyerror(ebuf);
+                       }
+
+                       if ( yyvsp[0].i == D_ISOPEN )
+                           tmpdb[ndb]->db_open = 1;
+                       else if ( yyvsp[0].i == D_CLOSED )
+                           tmpdb[ndb]->db_open = 0;
+                       else
+                           yyerror("A drawbridge can only be open or closed!");
+                       ndb++;
+                       if (ndb >= MAX_OF_TYPE) {
+                               yyerror("Too many drawbridges in mazepart!");
+                               ndb--;
+                       }
+                  }
+break;
+case 152:
+{
+                       tmpwalk[nwalk] = New(walk);
+                       tmpwalk[nwalk]->x = current_coord.x;
+                       tmpwalk[nwalk]->y = current_coord.y;
+                       tmpwalk[nwalk]->dir = yyvsp[0].i;
+                       nwalk++;
+                       if (nwalk >= MAX_OF_TYPE) {
+                               yyerror("Too many mazewalks in mazepart!");
+                               nwalk--;
+                       }
+                 }
+break;
+case 153:
+{
+                       wallify_map();
+                 }
+break;
+case 154:
+{
+                       tmplad[nlad] = New(lad);
+                       tmplad[nlad]->x = current_coord.x;
+                       tmplad[nlad]->y = current_coord.y;
+                       tmplad[nlad]->up = yyvsp[0].i;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Ladder");
+                       nlad++;
+                       if (nlad >= MAX_OF_TYPE) {
+                               yyerror("Too many ladders in mazepart!");
+                               nlad--;
+                       }
+                 }
+break;
+case 155:
+{
+                       tmpstair[nstair] = New(stair);
+                       tmpstair[nstair]->x = current_coord.x;
+                       tmpstair[nstair]->y = current_coord.y;
+                       tmpstair[nstair]->up = yyvsp[0].i;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Stairway");
+                       nstair++;
+                       if (nstair >= MAX_OF_TYPE) {
+                               yyerror("Too many stairs in room or mazepart!");
+                               nstair--;
+                       }
+                 }
+break;
+case 156:
+{
+                       tmplreg[nlreg] = New(lev_region);
+                       tmplreg[nlreg]->in_islev = yyvsp[0].i;
+                       tmplreg[nlreg]->inarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->inarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->inarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->inarea.y2 = current_region.y2;
+                 }
+break;
+case 157:
+{
+                       tmplreg[nlreg]->del_islev = yyvsp[-2].i;
+                       tmplreg[nlreg]->delarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->delarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->delarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->delarea.y2 = current_region.y2;
+                       if(yyvsp[0].i)
+                           tmplreg[nlreg]->rtype = LR_UPSTAIR;
+                       else
+                           tmplreg[nlreg]->rtype = LR_DOWNSTAIR;
+                       tmplreg[nlreg]->rname.str = 0;
+                       nlreg++;
+                       if (nlreg >= MAX_OF_TYPE) {
+                               yyerror("Too many levregions in mazepart!");
+                               nlreg--;
+                       }
+                 }
+break;
+case 158:
+{
+                       tmplreg[nlreg] = New(lev_region);
+                       tmplreg[nlreg]->in_islev = yyvsp[0].i;
+                       tmplreg[nlreg]->inarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->inarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->inarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->inarea.y2 = current_region.y2;
+                 }
+break;
+case 159:
+{
+                       tmplreg[nlreg]->del_islev = yyvsp[-2].i;
+                       tmplreg[nlreg]->delarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->delarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->delarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->delarea.y2 = current_region.y2;
+                       tmplreg[nlreg]->rtype = LR_PORTAL;
+                       tmplreg[nlreg]->rname.str = yyvsp[0].map;
+                       nlreg++;
+                       if (nlreg >= MAX_OF_TYPE) {
+                               yyerror("Too many levregions in mazepart!");
+                               nlreg--;
+                       }
+                 }
+break;
+case 160:
+{
+                       tmplreg[nlreg] = New(lev_region);
+                       tmplreg[nlreg]->in_islev = yyvsp[0].i;
+                       tmplreg[nlreg]->inarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->inarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->inarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->inarea.y2 = current_region.y2;
+                 }
+break;
+case 161:
+{
+                       tmplreg[nlreg]->del_islev = yyvsp[0].i;
+                       tmplreg[nlreg]->delarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->delarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->delarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->delarea.y2 = current_region.y2;
+                 }
+break;
+case 162:
+{
+                       switch(yyvsp[0].i) {
+                       case -1: tmplreg[nlreg]->rtype = LR_TELE; break;
+                       case 0: tmplreg[nlreg]->rtype = LR_DOWNTELE; break;
+                       case 1: tmplreg[nlreg]->rtype = LR_UPTELE; break;
+                       }
+                       tmplreg[nlreg]->rname.str = 0;
+                       nlreg++;
+                       if (nlreg >= MAX_OF_TYPE) {
+                               yyerror("Too many levregions in mazepart!");
+                               nlreg--;
+                       }
+                 }
+break;
+case 163:
+{
+                       tmplreg[nlreg] = New(lev_region);
+                       tmplreg[nlreg]->in_islev = yyvsp[0].i;
+                       tmplreg[nlreg]->inarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->inarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->inarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->inarea.y2 = current_region.y2;
+                 }
+break;
+case 164:
+{
+                       tmplreg[nlreg]->del_islev = yyvsp[0].i;
+                       tmplreg[nlreg]->delarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->delarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->delarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->delarea.y2 = current_region.y2;
+                       tmplreg[nlreg]->rtype = LR_BRANCH;
+                       tmplreg[nlreg]->rname.str = 0;
+                       nlreg++;
+                       if (nlreg >= MAX_OF_TYPE) {
+                               yyerror("Too many levregions in mazepart!");
+                               nlreg--;
+                       }
+                 }
+break;
+case 165:
+{
+                       yyval.i = -1;
+                 }
+break;
+case 166:
+{
+                       yyval.i = yyvsp[0].i;
+                 }
+break;
+case 167:
+{
+                       yyval.i = 0;
+                 }
+break;
+case 168:
+{
+/* This series of if statements is a hack for MSC 5.1.  It seems that its
+   tiny little brain cannot compile if these are all one big if statement. */
+                       if (yyvsp[-7].i <= 0 || yyvsp[-7].i >= COLNO)
+                               yyerror("Region out of level range!");
+                       else if (yyvsp[-5].i < 0 || yyvsp[-5].i >= ROWNO)
+                               yyerror("Region out of level range!");
+                       else if (yyvsp[-3].i <= 0 || yyvsp[-3].i >= COLNO)
+                               yyerror("Region out of level range!");
+                       else if (yyvsp[-1].i < 0 || yyvsp[-1].i >= ROWNO)
+                               yyerror("Region out of level range!");
+                       current_region.x1 = yyvsp[-7].i;
+                       current_region.y1 = yyvsp[-5].i;
+                       current_region.x2 = yyvsp[-3].i;
+                       current_region.y2 = yyvsp[-1].i;
+                       yyval.i = 1;
+                 }
+break;
+case 169:
+{
+                       tmpfountain[nfountain] = New(fountain);
+                       tmpfountain[nfountain]->x = current_coord.x;
+                       tmpfountain[nfountain]->y = current_coord.y;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Fountain");
+                       nfountain++;
+                       if (nfountain >= MAX_OF_TYPE) {
+                           yyerror("Too many fountains in room or mazepart!");
+                           nfountain--;
+                       }
+                 }
+break;
+case 170:
+{
+                       tmpsink[nsink] = New(sink);
+                       tmpsink[nsink]->x = current_coord.x;
+                       tmpsink[nsink]->y = current_coord.y;
+                       nsink++;
+                       if (nsink >= MAX_OF_TYPE) {
+                               yyerror("Too many sinks in room!");
+                               nsink--;
+                       }
+                 }
+break;
+case 171:
+{
+                       tmppool[npool] = New(pool);
+                       tmppool[npool]->x = current_coord.x;
+                       tmppool[npool]->y = current_coord.y;
+                       npool++;
+                       if (npool >= MAX_OF_TYPE) {
+                               yyerror("Too many pools in room!");
+                               npool--;
+                       }
+                 }
+break;
+case 172:
+{
+                       tmpdig[ndig] = New(digpos);
+                       tmpdig[ndig]->x1 = current_region.x1;
+                       tmpdig[ndig]->y1 = current_region.y1;
+                       tmpdig[ndig]->x2 = current_region.x2;
+                       tmpdig[ndig]->y2 = current_region.y2;
+                       ndig++;
+                       if (ndig >= MAX_OF_TYPE) {
+                               yyerror("Too many diggables in mazepart!");
+                               ndig--;
+                       }
+                 }
+break;
+case 173:
+{
+                       tmppass[npass] = New(digpos);
+                       tmppass[npass]->x1 = current_region.x1;
+                       tmppass[npass]->y1 = current_region.y1;
+                       tmppass[npass]->x2 = current_region.x2;
+                       tmppass[npass]->y2 = current_region.y2;
+                       npass++;
+                       if (npass >= 32) {
+                               yyerror("Too many passwalls in mazepart!");
+                               npass--;
+                       }
+                 }
+break;
+case 174:
+{
+                       tmpreg[nreg] = New(region);
+                       tmpreg[nreg]->x1 = current_region.x1;
+                       tmpreg[nreg]->y1 = current_region.y1;
+                       tmpreg[nreg]->x2 = current_region.x2;
+                       tmpreg[nreg]->y2 = current_region.y2;
+                       tmpreg[nreg]->rlit = yyvsp[-3].i;
+                       tmpreg[nreg]->rtype = yyvsp[-1].i;
+                       if(yyvsp[0].i & 1) tmpreg[nreg]->rtype += MAXRTYPE+1;
+                       tmpreg[nreg]->rirreg = ((yyvsp[0].i & 2) != 0);
+                       if(current_region.x1 > current_region.x2 ||
+                          current_region.y1 > current_region.y2)
+                          yyerror("Region start > end!");
+                       if(tmpreg[nreg]->rtype == VAULT &&
+                          (tmpreg[nreg]->rirreg ||
+                           (tmpreg[nreg]->x2 - tmpreg[nreg]->x1 != 1) ||
+                           (tmpreg[nreg]->y2 - tmpreg[nreg]->y1 != 1)))
+                               yyerror("Vaults must be exactly 2x2!");
+                       if(want_warnings && !tmpreg[nreg]->rirreg &&
+                          current_region.x1 > 0 && current_region.y1 > 0 &&
+                          current_region.x2 < (int)max_x_map &&
+                          current_region.y2 < (int)max_y_map) {
+                           /* check for walls in the room */
+                           char ebuf[60];
+                           register int x, y, nrock = 0;
+
+                           for(y=current_region.y1; y<=current_region.y2; y++)
+                               for(x=current_region.x1;
+                                   x<=current_region.x2; x++)
+                                   if(IS_ROCK(tmpmap[y][x]) ||
+                                      IS_DOOR(tmpmap[y][x])) nrock++;
+                           if(nrock) {
+                               Sprintf(ebuf,
+                                       "Rock in room (%02d,%02d,%02d,%02d)?!",
+                                       current_region.x1, current_region.y1,
+                                       current_region.x2, current_region.y2);
+                               yywarning(ebuf);
+                           }
+                           if (
+               !IS_ROCK(tmpmap[current_region.y1-1][current_region.x1-1]) ||
+               !IS_ROCK(tmpmap[current_region.y2+1][current_region.x1-1]) ||
+               !IS_ROCK(tmpmap[current_region.y1-1][current_region.x2+1]) ||
+               !IS_ROCK(tmpmap[current_region.y2+1][current_region.x2+1])) {
+                               Sprintf(ebuf,
+                               "NonRock edge in room (%02d,%02d,%02d,%02d)?!",
+                                       current_region.x1, current_region.y1,
+                                       current_region.x2, current_region.y2);
+                               yywarning(ebuf);
+                           }
+                       } else if(tmpreg[nreg]->rirreg &&
+               !IS_ROOM(tmpmap[current_region.y1][current_region.x1])) {
+                           char ebuf[60];
+                           Sprintf(ebuf,
+                                   "Rock in irregular room (%02d,%02d)?!",
+                                   current_region.x1, current_region.y1);
+                           yyerror(ebuf);
+                       }
+                       nreg++;
+                       if (nreg >= MAX_OF_TYPE) {
+                               yyerror("Too many regions in mazepart!");
+                               nreg--;
+                       }
+                 }
+break;
+case 175:
+{
+                       tmpaltar[naltar] = New(altar);
+                       tmpaltar[naltar]->x = current_coord.x;
+                       tmpaltar[naltar]->y = current_coord.y;
+                       tmpaltar[naltar]->align = yyvsp[-2].i;
+                       tmpaltar[naltar]->shrine = yyvsp[0].i;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Altar");
+                       naltar++;
+                       if (naltar >= MAX_OF_TYPE) {
+                               yyerror("Too many altars in room or mazepart!");
+                               naltar--;
+                       }
+                 }
+break;
+case 176:
+{
+                       tmpgold[ngold] = New(gold);
+                       tmpgold[ngold]->x = current_coord.x;
+                       tmpgold[ngold]->y = current_coord.y;
+                       tmpgold[ngold]->amount = yyvsp[-2].i;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Gold");
+                       ngold++;
+                       if (ngold >= MAX_OF_TYPE) {
+                               yyerror("Too many golds in room or mazepart!");
+                               ngold--;
+                       }
+                 }
+break;
+case 177:
+{
+                       tmpengraving[nengraving] = New(engraving);
+                       tmpengraving[nengraving]->x = current_coord.x;
+                       tmpengraving[nengraving]->y = current_coord.y;
+                       tmpengraving[nengraving]->engr.str = yyvsp[0].map;
+                       tmpengraving[nengraving]->etype = yyvsp[-2].i;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Engraving");
+                       nengraving++;
+                       if (nengraving >= MAX_OF_TYPE) {
+                           yyerror("Too many engravings in room or mazepart!");
+                           nengraving--;
+                       }
+                 }
+break;
+case 179:
+{
+                       yyval.i = - MAX_REGISTERS - 1;
+                 }
+break;
+case 182:
+{
+                       yyval.i = - MAX_REGISTERS - 1;
+                 }
+break;
+case 185:
+{
+                       yyval.map = (char *) 0;
+                 }
+break;
+case 187:
+{
+                       yyval.map = (char *) 0;
+                 }
+break;
+case 188:
+{
+                       int token = get_trap_type(yyvsp[0].map);
+                       if (token == ERR)
+                               yyerror("Unknown trap type!");
+                       yyval.i = token;
+                       Free(yyvsp[0].map);
+                 }
+break;
+case 190:
+{
+                       int token = get_room_type(yyvsp[0].map);
+                       if (token == ERR) {
+                               yywarning("Unknown room type!  Making ordinary room...");
+                               yyval.i = OROOM;
+                       } else
+                               yyval.i = token;
+                       Free(yyvsp[0].map);
+                 }
+break;
+case 192:
+{
+                       yyval.i = 0;
+                 }
+break;
+case 193:
+{
+                       yyval.i = yyvsp[0].i;
+                 }
+break;
+case 194:
+{
+                       yyval.i = yyvsp[-2].i + (yyvsp[0].i << 1);
+                 }
+break;
+case 197:
+{
+                       current_coord.x = current_coord.y = -MAX_REGISTERS-1;
+                 }
+break;
+case 204:
+{
+                       yyval.i = - MAX_REGISTERS - 1;
+                 }
+break;
+case 207:
+{
+                       if ( yyvsp[-1].i >= MAX_REGISTERS )
+                               yyerror("Register Index overflow!");
+                       else
+                               current_coord.x = current_coord.y = - yyvsp[-1].i - 1;
+                 }
+break;
+case 208:
+{
+                       if ( yyvsp[-1].i >= MAX_REGISTERS )
+                               yyerror("Register Index overflow!");
+                       else
+                               yyval.i = - yyvsp[-1].i - 1;
+                 }
+break;
+case 209:
+{
+                       if ( yyvsp[-1].i >= MAX_REGISTERS )
+                               yyerror("Register Index overflow!");
+                       else
+                               yyval.i = - yyvsp[-1].i - 1;
+                 }
+break;
+case 210:
+{
+                       if ( yyvsp[-1].i >= 3 )
+                               yyerror("Register Index overflow!");
+                       else
+                               yyval.i = - yyvsp[-1].i - 1;
+                 }
+break;
+case 212:
+{
+                       if (check_monster_char((char) yyvsp[0].i))
+                               yyval.i = yyvsp[0].i ;
+                       else {
+                               yyerror("Unknown monster class!");
+                               yyval.i = ERR;
+                       }
+                 }
+break;
+case 213:
+{
+                       char c = yyvsp[0].i;
+                       if (check_object_char(c))
+                               yyval.i = c;
+                       else {
+                               yyerror("Unknown char class!");
+                               yyval.i = ERR;
+                       }
+                 }
+break;
+case 217:
+{
+                       yyval.i = 100;  /* default is 100% */
+                 }
+break;
+case 218:
+{
+                       if (yyvsp[0].i <= 0 || yyvsp[0].i > 100)
+                           yyerror("Expected percentile chance.");
+                       yyval.i = yyvsp[0].i;
+                 }
+break;
+case 221:
+{
+                       if (!in_room && !init_lev.init_present &&
+                           (yyvsp[-3].i < 0 || yyvsp[-3].i > (int)max_x_map ||
+                            yyvsp[-1].i < 0 || yyvsp[-1].i > (int)max_y_map))
+                           yyerror("Coordinates out of map range!");
+                       current_coord.x = yyvsp[-3].i;
+                       current_coord.y = yyvsp[-1].i;
+                 }
+break;
+case 222:
+{
+/* This series of if statements is a hack for MSC 5.1.  It seems that its
+   tiny little brain cannot compile if these are all one big if statement. */
+                       if (yyvsp[-7].i < 0 || yyvsp[-7].i > (int)max_x_map)
+                               yyerror("Region out of map range!");
+                       else if (yyvsp[-5].i < 0 || yyvsp[-5].i > (int)max_y_map)
+                               yyerror("Region out of map range!");
+                       else if (yyvsp[-3].i < 0 || yyvsp[-3].i > (int)max_x_map)
+                               yyerror("Region out of map range!");
+                       else if (yyvsp[-1].i < 0 || yyvsp[-1].i > (int)max_y_map)
+                               yyerror("Region out of map range!");
+                       current_region.x1 = yyvsp[-7].i;
+                       current_region.y1 = yyvsp[-5].i;
+                       current_region.x2 = yyvsp[-3].i;
+                       current_region.y2 = yyvsp[-1].i;
+                 }
+break;
+    }
+    yyssp -= yym;
+    yystate = *yyssp;
+    yyvsp -= yym;
+    yym = yylhs[yyn];
+    if (yystate == 0 && yym == 0)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+        yystate = YYFINAL;
+        *++yyssp = YYFINAL;
+        *++yyvsp = yyval;
+        if (yychar < 0)
+        {
+            if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+            if (yydebug)
+            {
+                yys = 0;
+                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+                if (!yys) yys = "illegal-symbol";
+                printf("%sdebug: state %d, reading %d (%s)\n",
+                        YYPREFIX, YYFINAL, yychar, yys);
+            }
+#endif
+        }
+        if (yychar == 0) goto yyaccept;
+        goto yyloop;
+    }
+    if ((yyn = yygindex[yym]) != 0 && (yyn += yystate) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+        yystate = yytable[yyn];
+    else
+        yystate = yydgoto[yym];
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yyssp, yystate);
+#endif
+    if (yyssp >= yyss + yystacksize - 1)
+    {
+        goto yyoverflow;
+    }
+    *++yyssp = yystate;
+    *++yyvsp = yyval;
+    goto yyloop;
+yyoverflow:
+    yyerror("yacc stack overflow");
+yyabort:
+    return (1);
+yyaccept:
+    return (0);
+}
diff --git a/sys/share/nhlan.c b/sys/share/nhlan.c
new file mode 100644 (file)
index 0000000..27b1783
--- /dev/null
@@ -0,0 +1,191 @@
+/*     SCCS Id: @(#)nhlan.c    3.4     1999/11/21      */
+/* Copyright (c) Michael Allison, 1997                  */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Currently shared by the following ports:
+ *     WIN32
+ *
+ * The code in here is used to take advantage of added features
+ * that might be available in a Local Area Network environment.
+ *
+ *     Network Username of player
+ *     Mail
+ * Futures
+ *     Shared bones
+ *             To implement this: code, data files, and configuration
+ *             files need to be separated from writeable files such
+ *             as level files, bones files, and save files.
+ *
+ */
+
+#include "hack.h"
+#include <ctype.h>
+
+#ifdef LAN_FEATURES
+
+#ifdef LAN_MAIL
+/* Port specific code needs to implement these routines for LAN_MAIL */
+extern char *FDECL(get_username, (int *));
+extern boolean NDECL(mail_check);
+extern boolean FDECL(mail_fetch, (struct lan_mail_struct *)); 
+extern void FDECL(mail_init, (char *));
+extern void NDECL(mail_finish);
+
+struct lan_mail_struct mailmessage;
+#endif /* LAN_MAIL */
+
+
+void init_lan_features()
+{
+       lan_username();
+#ifdef LAN_MAIL
+       lan_mail_init();
+#endif
+#ifdef LAN_SHARED_BONES
+#endif
+}
+/*
+ * The get_lan_username() call is a required call, since some of
+ * the other LAN features depend on a unique username being available.
+ *
+ */
+char lusername[MAX_LAN_USERNAME];
+int lusername_size = MAX_LAN_USERNAME;
+
+char *lan_username()
+{
+       char *lu;
+       lu = get_username(&lusername_size);
+       if (lu) {
+        Strcpy(lusername, lu);
+        return lusername;
+       } else return (char *)0;
+}
+
+# ifdef LAN_MAIL
+#if 0
+static void
+mail_by_pline(msg)
+struct lan_mail_struct *msg;
+{
+       long    size;
+
+       for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) {
+           (void) dlb_fgets(in_line, 80, msg_file);
+           convert_line();
+           pline(out_line);
+       }
+
+}
+#endif /* 0 */
+
+static void
+mail_by_window(msg)
+struct lan_mail_struct *msg;
+{
+       char buf[BUFSZ];
+       winid datawin = create_nhwindow(NHW_TEXT);
+       char *get, *put;
+       int ccount = 0;
+       
+       get = msg->body;
+       put = buf;
+       while (*get) {
+            if (ccount > 79) {
+               *put = '\0';
+               putstr(datawin, 0, buf);
+               put = buf;
+               ccount = 0;
+            }
+            if (*get == '\r') {
+               get++;
+            } else if (*get == '\n') { 
+               *put = '\0';
+               putstr(datawin, 0, buf);
+               put = buf;
+               get++;
+               ccount = 0;
+            } else if (!isprint(*get)) {
+               get++;
+            } else {
+               *put++ = *get++;
+               ccount++;
+            }
+       }
+       *put = '\0';
+       putstr(datawin, 0, buf);
+       putstr(datawin, 0, "");        
+       display_nhwindow(datawin, TRUE);
+       destroy_nhwindow(datawin);
+}
+
+/* this returns TRUE if there is mail ready to be read */
+boolean lan_mail_check()
+{
+       if (flags.biff) {
+               if (mail_check()) return TRUE;
+       }
+       return FALSE;
+}
+
+void lan_mail_read(otmp)
+struct obj *otmp;
+{
+       if (flags.biff) {
+               (void) mail_fetch(&mailmessage);
+               /* after a successful fetch iflags.lan_mail_fetched
+                * should be TRUE.  If it isn't then we don't
+                * trust the contents of mailmessage.  This
+                * ensures that things work correctly across
+                * save/restores where mailmessage isn't
+                * saved (nor should it be since it may be
+                * way out of context by then).
+                */
+                if (iflags.lan_mail_fetched) {
+                   if (mailmessage.body_in_ram) {
+                       mail_by_window(&mailmessage);
+                       return;
+                   }
+                }
+       }
+       pline_The("text has faded and is no longer readable.");
+}
+
+void lan_mail_init()
+{
+       if (!flags.biff) return;
+       (void) mail_init(lusername);
+}
+
+void lan_mail_finish()
+{
+       if (iflags.lan_mail)
+               (void) mail_finish();
+}
+
+/* If ever called, the underlying mail system ran into trouble
+ * and wants us to cease bothering it immediately.
+ * Don't call mail_finish() because the underlying mail system
+ * may already be unavailable. Just clean up the NetHack side
+ * of things to prevent a crash.
+ */
+void lan_mail_terminate()
+{
+       /* Step 1. Clear iflags.lan_mail to indicate "not inited" */
+       iflags.lan_mail = FALSE;
+
+       /* Step 2. Clear iflags.lan_mail_fetched */
+       iflags.lan_mail_fetched = FALSE;
+
+       /* Once having gotten to this point, the only
+          way to resume NetHack mail features again is
+          to Save/Quit game, or for the user to clear
+          iflags.biff and then set it once again,
+          which triggers mail initialization */
+}
+
+# endif /*LAN_MAIL*/
+
+#endif /*LAN_FEATURES*/
+/*nhlan.c*/
diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c
new file mode 100644 (file)
index 0000000..8b59a6b
--- /dev/null
@@ -0,0 +1,714 @@
+/*     SCCS Id: @(#)pcmain.c   3.4     2002/08/22      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* main.c - MSDOS, OS/2, ST, Amiga, and NT NetHack */
+
+#include "hack.h"
+#include "dlb.h"
+
+#ifndef NO_SIGNAL
+#include <signal.h>
+#endif
+
+#include <ctype.h>
+
+#if !defined(AMIGA) && !defined(GNUDOS)
+#include <sys\stat.h>
+#else
+# ifdef GNUDOS
+#include <sys/stat.h>
+# endif
+#endif
+
+#ifdef WIN32
+#include "win32api.h"                  /* for GetModuleFileName */
+#endif
+
+#ifdef __DJGPP__
+#include <unistd.h>                    /* for getcwd() prototype */
+#endif
+
+#ifdef OVL0
+#define SHARED_DCL
+#else
+#define SHARED_DCL extern
+#endif
+
+
+SHARED_DCL char orgdir[PATHLEN];       /* also used in pcsys.c, amidos.c */
+
+#ifdef TOS
+boolean run_from_desktop = TRUE;       /* should we pause before exiting?? */
+# ifdef __GNUC__
+long _stksize = 16*1024;
+# endif
+#endif
+
+#ifdef AMIGA
+extern int bigscreen;
+void NDECL( preserve_icon );
+#endif
+
+STATIC_DCL void FDECL(process_options,(int argc,char **argv));
+STATIC_DCL void NDECL(nhusage);
+
+#if defined(MICRO) || defined(WIN32) || defined(OS2)
+extern void FDECL(nethack_exit,(int));
+#else
+#define nethack_exit exit
+#endif
+
+#ifdef WIN32
+extern boolean getreturn_enabled;      /* from sys/share/pcsys.c */
+#endif
+
+#if defined(MSWIN_GRAPHICS)
+extern void NDECL(mswin_destroy_reg);
+#endif
+
+#ifdef EXEPATH
+STATIC_DCL char *FDECL(exepath,(char *));
+#endif
+
+#ifdef OVL0
+int FDECL(main, (int,char **));
+#endif
+
+extern void FDECL(pcmain, (int,char **));
+
+
+#if defined(__BORLANDC__) && !defined(_WIN32)
+void NDECL( startup );
+# ifdef OVLB
+unsigned _stklen = STKSIZ;
+# else
+extern unsigned _stklen;
+# endif
+#endif
+
+#ifdef OVL0
+/* If the graphics version is built, we don't need a main; it is skipped
+ * to help MinGW decide which entry point to choose. If both main and 
+ * WinMain exist, the resulting executable won't work correctly.
+ */
+#ifndef MSWIN_GRAPHICS
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+     pcmain(argc,argv);
+#ifdef LAN_FEATURES
+     init_lan_features();
+#endif
+     moveloop();
+     nethack_exit(EXIT_SUCCESS);
+     /*NOTREACHED*/
+     return 0;
+}
+#endif /*MSWIN_GRAPHICS*/
+#endif /*OVL0*/
+#ifdef OVL1
+
+void
+pcmain(argc,argv)
+int argc;
+char *argv[];
+{
+
+       register int fd;
+       register char *dir;
+#if defined(WIN32)
+       char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ];
+#endif
+#ifdef NOCWD_ASSUMPTIONS
+       char failbuf[BUFSZ];
+#endif
+
+#if defined(__BORLANDC__) && !defined(_WIN32)
+       startup();
+#endif
+
+#ifdef TOS
+       long clock_time;
+       if (*argv[0]) {                 /* only a CLI can give us argv[0] */
+               hname = argv[0];
+               run_from_desktop = FALSE;
+       } else
+#endif
+               hname = "NetHack";      /* used for syntax messages */
+
+       choose_windows(DEFAULT_WINDOW_SYS);
+
+#if !defined(AMIGA) && !defined(GNUDOS)
+       /* Save current directory and make sure it gets restored when
+        * the game is exited.
+        */
+       if (getcwd(orgdir, sizeof orgdir) == (char *)0)
+               error("NetHack: current directory path too long");
+# ifndef NO_SIGNAL
+       signal(SIGINT, (SIG_RET_TYPE) nethack_exit);    /* restore original directory */
+# endif
+#endif /* !AMIGA && !GNUDOS */
+
+       dir = nh_getenv("NETHACKDIR");
+       if (dir == (char *)0)
+               dir = nh_getenv("HACKDIR");
+#ifdef EXEPATH
+       if (dir == (char *)0)
+               dir = exepath(argv[0]);
+#endif
+       if (dir != (char *)0) {
+               (void) strncpy(hackdir, dir, PATHLEN - 1);
+               hackdir[PATHLEN-1] = '\0';
+#ifdef NOCWD_ASSUMPTIONS
+               {
+                   int prefcnt;
+
+                   fqn_prefix[0] = (char *)alloc(strlen(hackdir)+2);
+                   Strcpy(fqn_prefix[0], hackdir);
+                   append_slash(fqn_prefix[0]);
+                   for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++)
+                       fqn_prefix[prefcnt] = fqn_prefix[0];
+               }
+#endif
+#ifdef CHDIR
+               chdirx (dir, 1);
+#endif
+       }
+#ifdef AMIGA
+# ifdef CHDIR
+       /*
+        * If we're dealing with workbench, change the directory.  Otherwise
+        * we could get "Insert disk in drive 0" messages. (Must be done
+        * before initoptions())....
+        */
+       if(argc == 0)
+               chdirx(HACKDIR, 1);
+# endif
+       ami_wininit_data();
+#endif
+       initoptions();
+
+#ifdef NOCWD_ASSUMPTIONS
+       if (!validate_prefix_locations(failbuf)) {
+               raw_printf("Some invalid directory locations were specified:\n\t%s\n",
+                               failbuf);
+                nethack_exit(EXIT_FAILURE);
+       }
+#endif
+
+#if defined(TOS) && defined(TEXTCOLOR)
+       if (iflags.BIOS && iflags.use_color)
+               set_colors();
+#endif
+       if (!hackdir[0])
+#if !defined(LATTICE) && !defined(AMIGA)
+               Strcpy(hackdir, orgdir);
+#else
+               Strcpy(hackdir, HACKDIR);
+#endif
+       if(argc > 1) {
+           if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') {
+               /* avoid matching "-dec" for DECgraphics; since the man page
+                * says -d directory, hope nobody's using -desomething_else
+                */
+               argc--;
+               argv++;
+               dir = argv[0]+2;
+               if(*dir == '=' || *dir == ':') dir++;
+               if(!*dir && argc > 1) {
+                       argc--;
+                       argv++;
+                       dir = argv[0];
+               }
+               if(!*dir)
+                   error("Flag -d must be followed by a directory name.");
+               Strcpy(hackdir, dir);
+           }
+           if (argc > 1) {
+
+               /*
+                * Now we know the directory containing 'record' and
+                * may do a prscore().
+                */
+               if (!strncmp(argv[1], "-s", 2)) {
+#if !defined(MSWIN_GRAPHICS)
+# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
+                       chdirx(hackdir,0);
+# endif
+                       prscore(argc, argv);
+#else
+                       raw_printf("-s is not supported for the Graphical Interface\n");
+#endif /*MSWIN_GRAPHICS*/
+                       nethack_exit(EXIT_SUCCESS);
+               }
+
+#ifdef MSWIN_GRAPHICS
+               if (!strncmpi(argv[1], "-clearreg", 6)) {       /* clear registry */
+                       mswin_destroy_reg();
+                       nethack_exit(EXIT_SUCCESS);
+               }
+#endif
+               /* Don't initialize the window system just to print usage */
+               if (!strncmp(argv[1], "-?", 2) || !strncmp(argv[1], "/?", 2)) {
+                       nhusage();
+                       nethack_exit(EXIT_SUCCESS);
+               }
+           }
+       }
+
+       /*
+        * It seems you really want to play.
+        */
+#ifdef TOS
+       if (comp_times((long)time(&clock_time)))
+               error("Your clock is incorrectly set!");
+#endif
+       u.uhp = 1;      /* prevent RIP on early quits */
+       u.ux = 0;       /* prevent flush_screen() */
+
+       /* chdir shouldn't be called before this point to keep the
+        * code parallel to other ports.
+        */
+#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
+       chdirx(hackdir,1);
+#endif
+
+#ifdef MSDOS
+       process_options(argc, argv);
+       init_nhwindows(&argc,argv);
+#else
+       init_nhwindows(&argc,argv);
+       process_options(argc, argv);
+#endif
+
+#ifdef WIN32CON
+       toggle_mouse_support(); /* must come after process_options */
+#endif
+
+#ifdef MFLOPPY
+       set_lock_and_bones();
+# ifndef AMIGA
+       copybones(FROMPERM);
+# endif
+#endif
+
+       if (!*plname)
+               askname();
+       plnamesuffix();         /* strip suffix from name; calls askname() */
+                               /* again if suffix was whole name */
+                               /* accepts any suffix */
+#ifdef WIZARD
+       if (wizard) {
+# ifdef KR1ED
+               if(!strcmp(plname, WIZARD_NAME))
+# else
+               if(!strcmp(plname, WIZARD))
+# endif
+                       Strcpy(plname, "wizard");
+               else {
+                       wizard = FALSE;
+                       discover = TRUE;
+               }
+       }
+#endif /* WIZARD */
+#if defined(PC_LOCKING)
+       /* 3.3.0 added this to support detection of multiple games
+        * under the same plname on the same machine in a windowed
+        * or multitasking environment.
+        *
+        * That allows user confirmation prior to overwriting the
+        * level files of a game in progress.
+        *
+        * Also prevents an aborted game's level files from being
+        * overwritten without confirmation when a user starts up
+        * another game with the same player name.
+        */
+# if defined(WIN32)
+       /* Obtain the name of the logged on user and incorporate
+        * it into the name. */
+       Sprintf(fnamebuf, "%s-%s", get_username(0), plname);
+       (void)fname_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.",
+                               '%', fnamebuf, encodedfnamebuf, BUFSZ);
+       Sprintf(lock, "%s",encodedfnamebuf);
+       /* regularize(lock); */ /* we encode now, rather than substitute */
+# else
+       Strcpy(lock,plname);
+       regularize(lock);
+# endif
+       getlock();
+#else   /* What follows is !PC_LOCKING */
+# ifdef AMIGA /* We'll put the bones & levels in the user specified directory -jhsa */
+       Strcat(lock,plname);
+       Strcat(lock,".99");
+# else
+#  ifndef MFLOPPY
+       /* I'm not sure what, if anything, is left here, but MFLOPPY has
+        * conflicts with set_lock_and_bones() in files.c.
+        */
+       Strcpy(lock,plname);
+       Strcat(lock,".99");
+       regularize(lock);       /* is this necessary? */
+                               /* not compatible with full path a la AMIGA */
+#  endif
+# endif
+#endif /* PC_LOCKING */
+
+       /* Set up level 0 file to keep the game state.
+        */
+       fd = create_levelfile(0, (char *)0);
+       if (fd < 0) {
+               raw_print("Cannot create lock file");
+       } else {
+#ifdef WIN32
+               hackpid = GetCurrentProcessId();
+#else
+               hackpid = 1;
+#endif
+               write(fd, (genericptr_t) &hackpid, sizeof(hackpid));
+               close(fd);
+       }
+#ifdef MFLOPPY
+       level_info[0].where = ACTIVE;
+#endif
+
+       /*
+        * Initialisation of the boundaries of the mazes
+        * Both boundaries have to be even.
+        */
+
+       x_maze_max = COLNO-1;
+       if (x_maze_max % 2)
+               x_maze_max--;
+       y_maze_max = ROWNO-1;
+       if (y_maze_max % 2)
+               y_maze_max--;
+
+       /*
+        *  Initialize the vision system.  This must be before mklev() on a
+        *  new game or before a level restore on a saved game.
+        */
+       vision_init();
+
+       dlb_init();
+
+       display_gamewindows();
+#ifdef WIN32
+       getreturn_enabled = TRUE;
+#endif
+
+       if ((fd = restore_saved_game()) >= 0) {
+#ifdef WIZARD
+               /* Since wizard is actually flags.debug, restoring might
+                * overwrite it.
+                */
+               boolean remember_wiz_mode = wizard;
+#endif
+#ifndef NO_SIGNAL
+               (void) signal(SIGINT, (SIG_RET_TYPE) done1);
+#endif
+#ifdef NEWS
+               if(iflags.news){
+                   display_file(NEWS, FALSE);
+                   iflags.news = FALSE;
+               }
+#endif
+               pline("Restoring save file...");
+               mark_synch();   /* flush output */
+
+               if(!dorecover(fd))
+                       goto not_recovered;
+#ifdef WIZARD
+               if(!wizard && remember_wiz_mode) wizard = TRUE;
+#endif
+               check_special_room(FALSE);
+               if (discover)
+                       You("are in non-scoring discovery mode.");
+
+               if (discover || wizard) {
+                       if(yn("Do you want to keep the save file?") == 'n'){
+                               (void) delete_savefile();
+                       }
+               }
+
+               flags.move = 0;
+       } else {
+not_recovered:
+               player_selection();
+               newgame();
+               if (discover)
+                       You("are in non-scoring discovery mode.");
+
+               flags.move = 0;
+               set_wear();
+               (void) pickup(1);
+               read_engr_at(u.ux,u.uy);
+       }
+
+#ifndef NO_SIGNAL
+       (void) signal(SIGINT, SIG_IGN);
+#endif
+#ifdef OS2
+       gettty(); /* somehow ctrl-P gets turned back on during startup ... */
+#endif
+       return;
+}
+
+STATIC_OVL void
+process_options(argc, argv)
+int argc;
+char *argv[];
+{
+       int i;
+
+
+       /*
+        * Process options.
+        */
+       while(argc > 1 && argv[1][0] == '-'){
+               argv++;
+               argc--;
+               switch(argv[0][1]){
+               case 'a':
+                       if (argv[0][2]) {
+                           if ((i = str2align(&argv[0][2])) >= 0)
+                               flags.initalign = i;
+                       } else if (argc > 1) {
+                               argc--;
+                               argv++;
+                           if ((i = str2align(argv[0])) >= 0)
+                               flags.initalign = i;
+                       }
+                       break;
+               case 'D':
+#ifdef WIZARD
+                       /* If they don't have a valid wizard name, it'll be
+                        * changed to discover later.  Cannot check for
+                        * validity of the name right now--it might have a
+                        * character class suffix, for instance.
+                        */
+                       wizard = TRUE;
+                       break;
+#endif
+               case 'X':
+                       discover = TRUE;
+                       break;
+#ifdef NEWS
+               case 'n':
+                       iflags.news = FALSE;
+                       break;
+#endif
+               case 'u':
+                       if(argv[0][2])
+                         (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
+                       else if(argc > 1) {
+                         argc--;
+                         argv++;
+                         (void) strncpy(plname, argv[0], sizeof(plname)-1);
+                       } else
+                               raw_print("Player name expected after -u");
+                       break;
+#ifndef AMIGA
+               case 'I':
+               case 'i':
+                       if (!strncmpi(argv[0]+1, "IBM", 3))
+                               switch_graphics(IBM_GRAPHICS);
+                       break;
+           /*  case 'D': */
+               case 'd':
+                       if (!strncmpi(argv[0]+1, "DEC", 3))
+                               switch_graphics(DEC_GRAPHICS);
+                       break;
+#endif
+               case 'g':
+                       if (argv[0][2]) {
+                           if ((i = str2gend(&argv[0][2])) >= 0)
+                               flags.initgend = i;
+                       } else if (argc > 1) {
+                               argc--;
+                               argv++;
+                           if ((i = str2gend(argv[0])) >= 0)
+                               flags.initgend = i;
+                       }
+                       break;
+               case 'p': /* profession (role) */
+                       if (argv[0][2]) {
+                           if ((i = str2role(&argv[0][2])) >= 0)
+                               flags.initrole = i;
+                       } else if (argc > 1) {
+                               argc--;
+                               argv++;
+                           if ((i = str2role(argv[0])) >= 0)
+                               flags.initrole = i;
+                       }
+                       break;
+               case 'r': /* race */
+                       if (argv[0][2]) {
+                           if ((i = str2race(&argv[0][2])) >= 0)
+                               flags.initrace = i;
+                       } else if (argc > 1) {
+                               argc--;
+                               argv++;
+                           if ((i = str2race(argv[0])) >= 0)
+                               flags.initrace = i;
+                       }
+                       break;
+#ifdef MFLOPPY
+# ifndef AMIGA
+               /* Player doesn't want to use a RAM disk
+                */
+               case 'R':
+                       ramdisk = FALSE;
+                       break;
+# endif
+#endif
+#ifdef AMIGA
+                       /* interlaced and non-interlaced screens */
+               case 'L':
+                       bigscreen = 1;
+                       break;
+               case 'l':
+                       bigscreen = -1;
+                       break;
+#endif
+               case '@':
+                       flags.randomall = 1;
+                       break;
+               default:
+                       if ((i = str2role(&argv[0][1])) >= 0) {
+                           flags.initrole = i;
+                               break;
+                       } else raw_printf("\nUnknown switch: %s", argv[0]);
+                       /* FALL THROUGH */
+               case '?':
+                       nhusage();
+                       nethack_exit(EXIT_SUCCESS);
+               }
+       }
+}
+
+STATIC_OVL void 
+nhusage()
+{
+       char buf1[BUFSZ], buf2[BUFSZ], *bufptr;
+
+       buf1[0] = '\0';
+       bufptr = buf1;
+
+#define ADD_USAGE(s)   if ((strlen(buf1) + strlen(s)) < (BUFSZ - 1)) Strcat(bufptr, s);
+
+       /* -role still works for those cases which aren't already taken, but
+        * is deprecated and will not be listed here.
+        */
+       (void) Sprintf(buf2,
+"\nUsage:\n%s [-d dir] -s [-r race] [-p profession] [maxrank] [name]...\n       or",
+               hname);
+       ADD_USAGE(buf2);
+
+       (void) Sprintf(buf2,
+        "\n%s [-d dir] [-u name] [-r race] [-p profession] [-[DX]]",
+               hname);
+       ADD_USAGE(buf2);
+#ifdef NEWS
+       ADD_USAGE(" [-n]");
+#endif
+#ifndef AMIGA
+       ADD_USAGE(" [-I] [-i] [-d]");
+#endif
+#ifdef MFLOPPY
+# ifndef AMIGA
+       ADD_USAGE(" [-R]");
+# endif
+#endif
+#ifdef AMIGA
+       ADD_USAGE(" [-[lL]]");
+#endif
+       if (!iflags.window_inited)
+               raw_printf("%s\n",buf1);
+       else
+               (void) printf("%s\n",buf1);
+#undef ADD_USAGE
+}
+
+#ifdef CHDIR
+void
+chdirx(dir, wr)
+char *dir;
+boolean wr;
+{
+# ifdef AMIGA
+       static char thisdir[] = "";
+# else
+       static char thisdir[] = ".";
+# endif
+       if(dir && chdir(dir) < 0) {
+               error("Cannot chdir to %s.", dir);
+       }
+
+# ifndef AMIGA
+       /* Change the default drive as well.
+        */
+       chdrive(dir);
+# endif
+
+       /* warn the player if we can't write the record file */
+       /* perhaps we should also test whether . is writable */
+       /* unfortunately the access system-call is worthless */
+       if (wr) check_recordfile(dir ? dir : thisdir);
+}
+#endif /* CHDIR */
+#endif /*OVL1*/
+#ifdef OVLB
+
+#ifdef PORT_HELP
+# if defined(MSDOS) || defined(WIN32)
+void
+port_help()
+{
+    /* display port specific help file */
+    display_file( PORT_HELP, 1 );
+}
+# endif /* MSDOS || WIN32 */
+#endif /* PORT_HELP */
+
+#ifdef EXEPATH
+# ifdef __DJGPP__
+#define PATH_SEPARATOR '/'
+# else
+#define PATH_SEPARATOR '\\'
+# endif
+
+#define EXEPATHBUFSZ 256
+char exepathbuf[EXEPATHBUFSZ];
+
+char *exepath(str)
+char *str;
+{
+       char *tmp, *tmp2;
+       int bsize;
+
+       if (!str) return (char *)0;
+       bsize = EXEPATHBUFSZ;
+       tmp = exepathbuf;
+# ifndef WIN32
+       Strcpy (tmp, str);
+# else
+       #ifdef UNICODE
+       {
+               TCHAR wbuf[BUFSZ];
+               GetModuleFileName((HANDLE)0, wbuf, BUFSZ);
+               WideCharToMultiByte(CP_ACP, 0, wbuf, -1, tmp, bsize, NULL, NULL);
+       }
+       #else
+               *(tmp + GetModuleFileName((HANDLE)0, tmp, bsize)) = '\0';
+       #endif
+# endif
+       tmp2 = strrchr(tmp, PATH_SEPARATOR);
+       if (tmp2) *tmp2 = '\0';
+       return tmp;
+}
+#endif /* EXEPATH */
+#endif /*OVLB*/
+/*pcmain.c*/
diff --git a/sys/share/pcsys.c b/sys/share/pcsys.c
new file mode 100644 (file)
index 0000000..b67661c
--- /dev/null
@@ -0,0 +1,541 @@
+/*     SCCS Id: @(#)pcsys.c    3.4     2002/01/22                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *  System related functions for MSDOS, OS/2, TOS, and Windows NT
+ */
+
+#define NEED_VARARGS
+#include "hack.h"
+#include "wintty.h"
+
+#include <ctype.h>
+#include <fcntl.h>
+#if !defined(MSDOS) && !defined(WIN_CE)        /* already done */
+#include <process.h>
+#endif
+#ifdef __GO32__
+#define P_WAIT         0
+#define P_NOWAIT       1
+#endif
+#ifdef TOS
+#include <osbind.h>
+#endif
+#if defined(MSDOS) && !defined(__GO32__)
+#define findfirst findfirst_file
+#define findnext findnext_file
+#define filesize filesize_nh
+#endif
+
+
+#if defined(MICRO) || defined(WIN32) || defined(OS2)
+void FDECL(nethack_exit,(int));
+#else
+#define nethack_exit exit
+#endif
+static void NDECL(msexit);
+
+
+#ifdef MOVERLAY
+extern void __far __cdecl _movepause( void );
+extern void __far __cdecl _moveresume( void );
+extern unsigned short __far __cdecl _movefpause;
+extern unsigned short __far __cdecl _movefpaused;
+#define     __MOVE_PAUSE_DISK    2   /* Represents the executable file */
+#define     __MOVE_PAUSE_CACHE   4   /* Represents the cache memory */
+#endif /* MOVERLAY */
+
+#ifdef MFLOPPY
+STATIC_DCL boolean NDECL(record_exists);
+# ifndef TOS
+STATIC_DCL boolean NDECL(comspec_exists);
+# endif
+#endif
+
+#ifdef WIN32CON
+extern int GUILaunched;    /* from nttty.c */
+#endif
+
+#if defined(MICRO) || defined(WIN32)
+
+void
+flushout()
+{
+       (void) fflush(stdout);
+       return;
+}
+
+static const char *COMSPEC =
+# ifdef TOS
+"SHELL";
+# else
+"COMSPEC";
+# endif
+
+#define getcomspec() nh_getenv(COMSPEC)
+
+# ifdef SHELL
+int
+dosh()
+{
+       extern char orgdir[];
+       char *comspec;
+# ifndef __GO32__
+       int spawnstat;
+# endif
+#if defined(MSDOS) && defined(NO_TERMS)
+       int grmode = iflags.grmode;
+#endif
+       if ((comspec = getcomspec())) {
+#  ifndef TOS  /* TOS has a variety of shells */
+               suspend_nhwindows("To return to NetHack, enter \"exit\" at the system prompt.\n");
+#  else
+#   if defined(MSDOS) && defined(NO_TERMS)
+               grmode = iflags.grmode;
+#   endif
+               suspend_nhwindows((char *)0);
+#  endif /* TOS */
+#  ifndef NOCWD_ASSUMPTIONS
+               chdirx(orgdir, 0);
+#  endif
+#  ifdef __GO32__
+               if (system(comspec) < 0) {  /* wsu@eecs.umich.edu */
+#  else
+#   ifdef MOVERLAY
+       /* Free the cache memory used by overlays, close .exe */
+       _movefpause |= __MOVE_PAUSE_DISK;
+       _movefpause |= __MOVE_PAUSE_CACHE;
+       _movepause();
+#   endif
+               spawnstat = spawnl(P_WAIT, comspec, comspec, (char *)0);
+#   ifdef MOVERLAY
+                _moveresume();
+#   endif
+
+               if ( spawnstat < 0) {
+#  endif
+                       raw_printf("Can't spawn \"%s\"!", comspec);
+                       getreturn("to continue");
+               }
+#  ifdef TOS
+/* Some shells (e.g. Gulam) turn the cursor off when they exit */
+               if (iflags.BIOS)
+                       (void)Cursconf(1, -1);
+#  endif
+#  ifndef NOCWD_ASSUMPTIONS
+               chdirx(hackdir, 0);
+#  endif
+               get_scr_size(); /* maybe the screen mode changed (TH) */
+#  if defined(MSDOS) && defined(NO_TERMS)
+               if (grmode) gr_init();
+#  endif
+               resume_nhwindows();
+       } else
+               pline("Can't find %s.",COMSPEC);
+       return 0;
+}
+# endif /* SHELL */
+
+# ifdef MFLOPPY
+
+void
+eraseall(path, files)
+const char *path, *files;
+{
+       char buf[PATHLEN];
+       char *foundfile;
+
+       foundfile = foundfile_buffer();
+       Sprintf(buf, "%s%s", path, files);
+       if (findfirst(buf))
+           do {
+              Sprintf(buf, "%s%s", path, foundfile);
+               (void) unlink(buf);
+           } while (findnext());
+       return;
+}
+
+/*
+ * Rewritten for version 3.3 to be faster
+ */
+void
+copybones(mode)
+int mode;
+{
+       char from[PATHLEN], to[PATHLEN], last[13];
+       char *frompath, *topath;
+       char *foundfile;
+#  ifndef TOS
+       int status;
+       char copy[8], *comspec;
+#  endif
+
+       if (!ramdisk)
+               return;
+
+       /* Find the name of the last file to be transferred
+        */
+       frompath = (mode != TOPERM) ? permbones : levels;
+       foundfile = foundfile_buffer();
+       last[0] = '\0';
+       Sprintf(from, "%s%s", frompath, allbones);
+       topath = (mode == TOPERM) ? permbones : levels;
+#  ifdef TOS
+       eraseall(topath, allbones);
+#  endif
+       if (findfirst(from))
+               do {
+#  ifdef TOS
+                       Sprintf(from, "%s%s", frompath, foundfile);
+                       Sprintf(to, "%s%s", topath, foundfile);
+                       if (_copyfile(from, to))
+                               goto error_copying;
+#  endif
+                       Strcpy(last, foundfile);
+               } while (findnext());
+#  ifdef TOS
+       else
+               return;
+#  else
+       if (last[0]) {
+               Sprintf(copy, "%cC copy",switchar());
+
+               /* Remove any bones files in `to' directory.
+                */
+               eraseall(topath, allbones);
+
+               /* Copy `from' to `to' */
+               Sprintf(to, "%s%s", topath, allbones);
+               comspec = getcomspec();
+               status =spawnl(P_WAIT, comspec, comspec, copy, from,
+                       to, "> nul", (char *)0);
+       } else
+               return;
+#  endif /* TOS */
+
+       /* See if the last file got there.  If so, remove the ramdisk bones
+        * files.
+        */
+       Sprintf(to, "%s%s", topath, last);
+       if (findfirst(to)) {
+               if (mode == TOPERM)
+                       eraseall(frompath, allbones);
+               return;
+       }
+
+#  ifdef TOS
+error_copying:
+#  endif
+       /* Last file didn't get there.
+        */
+       Sprintf(to, "%s%s", topath, allbones);
+       msmsg("Can't copy \"%s\" to \"%s\" -- ", from, to);
+#  ifndef TOS
+       if (status < 0)
+           msmsg("can't spawn \"%s\"!", comspec);
+       else
+#  endif
+           msmsg((freediskspace(topath) < filesize(from)) ?
+           "insufficient disk space." : "bad path(s)?");
+       if (mode == TOPERM) {
+               msmsg("Bones will be left in \"%s\"\n",
+                       *levels ? levels : hackdir);
+       } else {
+               /* Remove all bones files on the RAMdisk */
+               eraseall(levels, allbones);
+               playwoRAMdisk();
+       }
+       return;
+}
+
+void
+playwoRAMdisk()
+{
+       int c;
+
+       msmsg("Do you wish to play without a RAMdisk? [yn] (n)");
+
+       /* Set ramdisk false *before* exit-ing (because msexit calls
+        * copybones)
+        */
+       ramdisk = FALSE;
+       c = tgetch(); if (c == 'Y') c = 'y';
+       if (c != 'y') {
+               settty("Be seeing you...\n");
+               nethack_exit(EXIT_SUCCESS);
+       }
+       set_lock_and_bones();
+       return;
+}
+
+int
+saveDiskPrompt(start)
+int start;
+{
+       char buf[BUFSIZ], *bp;
+       char qbuf[QBUFSZ];
+
+       int fd;
+
+       if (flags.asksavedisk) {
+               /* Don't prompt if you can find the save file */
+               if ((fd = open_savefile()) >= 0) {
+                       (void) close(fd);
+                       return 1;
+               }
+               clear_nhwindow(WIN_MESSAGE);
+               pline("If save file is on a save disk, insert that disk now.");
+               mark_synch();
+               Sprintf(qbuf,"File name (default \"%s\"%s) ?", SAVEF,
+                       start ? "" : ", <Esc> cancels save");
+               getlin(qbuf, buf);
+               clear_nhwindow(WIN_MESSAGE);
+               if (!start && *buf == '\033')
+                       return 0;
+
+               /* Strip any whitespace. Also, if nothing was entered except
+                * whitespace, do not change the value of SAVEF.
+                */
+               for (bp = buf; *bp; bp++)
+                       if (!isspace(*bp)) {
+                               strncpy(SAVEF, bp, PATHLEN);
+                               break;
+                       }
+       }
+       return 1;
+}
+
+/* Return 1 if the record file was found */
+STATIC_OVL boolean
+record_exists()
+{
+       FILE *fp;
+
+       fp = fopen_datafile(RECORD, "r", TRUE);
+       if (fp) {
+               fclose(fp);
+               return TRUE;
+       }
+       return FALSE;
+}
+#endif /* MFLOPPY */
+
+# ifdef TOS
+#define comspec_exists() 1
+# else
+#  ifdef MFLOPPY
+/* Return 1 if the comspec was found */
+STATIC_OVL boolean
+comspec_exists()
+{
+       int fd;
+       char *comspec;
+
+       if ((comspec = getcomspec()))
+               if ((fd = open(comspec, O_RDONLY)) >= 0) {
+                       (void) close(fd);
+                       return TRUE;
+               }
+       return FALSE;
+}
+#  endif /* MFLOPPY */
+# endif
+
+
+# ifdef MFLOPPY
+/* Prompt for game disk, then check for record file.
+ */
+void
+gameDiskPrompt()
+{
+       if (flags.asksavedisk) {
+               if (record_exists() && comspec_exists())
+                       return;
+               (void) putchar('\n');
+               getreturn("when the game disk has been inserted");
+       }
+       if (comspec_exists() && record_exists())
+               return;
+
+       if (!comspec_exists())
+               msmsg("\n\nWARNING: can't find command processor \"%s\"!\n", getcomspec());
+       if (!record_exists())
+               msmsg("\n\nWARNING: can't find record file \"%s\"!\n", RECORD);
+       msmsg("If the game disk is not in, insert it now.\n");
+       getreturn("to continue");
+       return;
+}
+# endif /* MFLOPPY */
+#endif /* MICRO */
+
+/*
+ * Add a backslash to any name not ending in /, \ or :  There must
+ * be room for the \
+ */
+void
+append_slash(name)
+char *name;
+{
+       char *ptr;
+
+       if (!*name)
+               return;
+       ptr = name + (strlen(name) - 1);
+       if (*ptr != '\\' && *ptr != '/' && *ptr != ':') {
+               *++ptr = '\\';
+               *++ptr = '\0';
+       }
+       return;
+}
+
+#ifdef WIN32
+boolean getreturn_enabled;
+#endif
+
+void
+getreturn(str)
+const char *str;
+{
+#ifdef WIN32
+       if (!getreturn_enabled) return;
+#endif
+#ifdef TOS
+       msmsg("Hit <Return> %s.", str);
+#else
+       msmsg("Hit <Enter> %s.", str);
+#endif
+       while (Getchar() != '\n') ;
+       return;
+}
+
+#ifndef WIN32CON
+void
+msmsg VA_DECL(const char *, fmt)
+       VA_START(fmt);
+       VA_INIT(fmt, const char *);
+# if defined(MSDOS) && defined(NO_TERMS)
+       if (iflags.grmode)
+               gr_finish();
+# endif
+       Vprintf(fmt, VA_ARGS);
+       flushout();
+       VA_END();
+       return;
+}
+#endif
+
+/*
+ * Follow the PATH, trying to fopen the file.
+ */
+#ifdef TOS
+# ifdef __MINT__
+#define PATHSEP ':'
+# else
+#define PATHSEP ','
+# endif
+#else
+#define PATHSEP ';'
+#endif
+
+FILE *
+fopenp(name, mode)
+const char *name, *mode;
+{
+       char buf[BUFSIZ], *bp, *pp, lastch = 0;
+       FILE *fp;
+
+       /* Try the default directory first.  Then look along PATH.
+        */
+       (void) strncpy(buf, name, BUFSIZ - 1);
+       buf[BUFSIZ-1] = '\0';
+       if ((fp = fopen(buf, mode)))
+               return fp;
+       else {
+               int ccnt = 0;
+               pp = getenv("PATH");
+               while (pp && *pp) {
+                       bp = buf;
+                       while (*pp && *pp != PATHSEP) {
+                               lastch = *bp++ = *pp++;
+                               ccnt++;
+                       }
+                       if (lastch != '\\' && lastch != '/') {
+                               *bp++ = '\\';
+                               ccnt++;
+                       }
+                       (void) strncpy(bp, name, (BUFSIZ - ccnt) - 2);
+                       bp[BUFSIZ - ccnt - 1] = '\0';
+                       if ((fp = fopen(buf, mode)))
+                               return fp;
+                       if (*pp)
+                               pp++;
+               }
+       }
+#ifdef OS2_CODEVIEW /* one more try for hackdir */
+       (void) strncpy(buf, hackdir, BUFSZ);
+       buf[BUFSZ-1] = '\0';
+       if ((strlen(name) + 1 + strlen(buf)) < BUFSZ - 1) {
+               append_slash(buf);
+               Strcat(buf,name);
+       } else 
+               impossible("fopenp() buffer too small for complete filename!");
+       if(fp = fopen(buf,mode))
+               return fp;
+#endif
+       return (FILE *)0;
+}
+
+#if defined(MICRO) || defined(WIN32) || defined(OS2)
+void nethack_exit(code)
+int code;
+{
+       msexit();
+       exit(code);
+}
+
+/* Chdir back to original directory
+ */
+#ifdef TOS
+extern boolean run_from_desktop;       /* set in pcmain.c */
+#endif
+
+static void msexit()
+{
+#ifdef CHDIR
+       extern char orgdir[];
+#endif
+
+       flushout();
+#ifndef TOS
+# ifndef WIN32
+       enable_ctrlP();         /* in case this wasn't done */
+# endif
+#endif
+#ifdef MFLOPPY
+       if (ramdisk) copybones(TOPERM);
+#endif
+#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
+       chdir(orgdir);          /* chdir, not chdirx */
+       chdrive(orgdir);
+#endif
+#ifdef TOS
+       if (run_from_desktop)
+           getreturn("to continue"); /* so the user can read the score list */
+# ifdef TEXTCOLOR
+       if (colors_changed)
+               restore_colors();
+# endif
+#endif
+#ifdef WIN32CON
+       /* Only if we started from the GUI, not the command prompt,
+        * we need to get one last return, so the score board does
+        * not vanish instantly after being created.
+        * GUILaunched is defined and set in nttty.c.
+        */
+       synch_cursor();
+       if (GUILaunched) getreturn("to end");
+       synch_cursor();
+#endif
+       return;
+}
+#endif /* MICRO || WIN32 || OS2 */
diff --git a/sys/share/pctty.c b/sys/share/pctty.c
new file mode 100644 (file)
index 0000000..5dd3d00
--- /dev/null
@@ -0,0 +1,85 @@
+/*     SCCS Id: @(#)pctty.c    3.4     1990/22/02
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* tty.c - (PC) version */
+
+#define NEED_VARARGS /* Uses ... */    /* comment line for pre-compiled headers */
+#include "hack.h"
+#include "wintty.h"
+
+char erase_char, kill_char;
+
+/*
+ * Get initial state of terminal, set ospeed (for termcap routines)
+ * and switch off tab expansion if necessary.
+ * Called by startup() in termcap.c and after returning from ! or ^Z
+ */
+void
+gettty(){
+       erase_char = '\b';
+       kill_char = 21;         /* cntl-U */
+       iflags.cbreak = TRUE;
+#if !defined(TOS) 
+       disable_ctrlP();        /* turn off ^P processing */
+#endif
+#if defined(MSDOS) && defined(NO_TERMS)
+       gr_init();
+#endif
+}
+
+/* reset terminal to original state */
+void
+settty(s)
+const char *s;
+{
+#if defined(MSDOS) && defined(NO_TERMS)
+       gr_finish();
+#endif
+       end_screen();
+       if(s) raw_print(s);
+#if !defined(TOS)
+       enable_ctrlP();         /* turn on ^P processing */
+#endif
+
+}
+
+/* called by init_nhwindows() and resume_nhwindows() */
+void
+setftty()
+{
+       start_screen();
+}
+
+#if defined(TIMED_DELAY) && defined(_MSC_VER)
+void
+msleep(mseconds)
+unsigned mseconds;
+{
+       /* now uses clock() which is ANSI C */
+       clock_t goal;
+
+       goal = mseconds + clock();
+       while ( goal > clock()) {
+           /* do nothing */
+       }
+}
+#endif
+
+/* fatal error */
+/*VARARGS1*/
+
+void
+error VA_DECL(const char *,s)
+       VA_START(s);
+       VA_INIT(s, const char *);
+       /* error() may get called before tty is initialized */
+       if (iflags.window_inited) end_screen();
+       putchar('\n');
+       Vprintf(s,VA_ARGS);
+       putchar('\n');
+       VA_END();
+       exit(EXIT_FAILURE);
+}
+
+/*pctty.c*/
diff --git a/sys/share/pcunix.c b/sys/share/pcunix.c
new file mode 100644 (file)
index 0000000..1f1149e
--- /dev/null
@@ -0,0 +1,289 @@
+/*     SCCS Id: @(#)pcunix.c   3.4     1994/11/07      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* This file collects some Unix dependencies; pager.c contains some more */
+
+#include "hack.h"
+#include "wintty.h"
+
+#include       <sys/stat.h>
+#if defined(WIN32) || defined(MSDOS)
+#include       <errno.h>
+#endif
+
+#if defined(WIN32) || defined(MSDOS)
+extern char orgdir[];
+# ifdef WIN32
+extern void NDECL(backsp);
+# endif
+extern void NDECL(clear_screen);
+#endif
+
+#ifdef OVLB
+
+#if 0
+static struct stat buf;
+#endif
+
+# ifdef WANT_GETHDATE
+static struct stat hbuf;
+# endif
+
+#ifdef PC_LOCKING
+static int NDECL(eraseoldlocks);
+#endif
+
+#if 0
+int
+uptodate(fd)
+int fd;
+{
+# ifdef WANT_GETHDATE
+    if(fstat(fd, &buf)) {
+       pline("Cannot get status of saved level? ");
+       return(0);
+    }
+    if(buf.st_mtime < hbuf.st_mtime) {
+       pline("Saved level is out of date. ");
+       return(0);
+    }
+# else
+#  if (defined(MICRO) || defined(WIN32)) && !defined(NO_FSTAT)
+    if(fstat(fd, &buf)) {
+       if(moves > 1) pline("Cannot get status of saved level? ");
+       else pline("Cannot get status of saved game.");
+       return(0);
+    } 
+    if(comp_times(buf.st_mtime)) { 
+       if(moves > 1) pline("Saved level is out of date.");
+       else pline("Saved game is out of date. ");
+       /* This problem occurs enough times we need to give the player
+        * some more information about what causes it, and how to fix.
+        */
+#  ifdef MSDOS
+           pline("Make sure that your system's date and time are correct.");
+           pline("They must be more current than NetHack.EXE's date/time stamp.");
+#  endif /* MSDOS */
+       return(0);
+    }
+#  endif  /* MICRO */
+# endif /* WANT_GETHDATE */
+    return(1);
+}
+#endif
+
+#ifdef PC_LOCKING
+static int
+eraseoldlocks()
+{
+       register int i;
+
+       /* cannot use maxledgerno() here, because we need to find a lock name
+        * before starting everything (including the dungeon initialization
+        * that sets astral_level, needed for maxledgerno()) up
+        */
+       for(i = 1; i <= MAXDUNGEON*MAXLEVEL + 1; i++) {
+               /* try to remove all */
+               set_levelfile_name(lock, i);
+               (void) unlink(fqname(lock, LEVELPREFIX, 0));
+       }
+       set_levelfile_name(lock, 0);
+#ifdef HOLD_LOCKFILE_OPEN
+       really_close();
+#endif
+       if(unlink(fqname(lock, LEVELPREFIX, 0)))
+               return 0;                               /* cannot remove it */
+       return(1);                                      /* success! */
+}
+
+void
+getlock()
+{
+       register int fd, c, ci, ct, ern;
+       char tbuf[BUFSZ];
+       const char *fq_lock;
+# if defined(MSDOS) && defined(NO_TERMS)
+       int grmode = iflags.grmode;
+# endif
+       /* we ignore QUIT and INT at this point */
+       if (!lock_file(HLOCK, LOCKPREFIX, 10)) {
+               wait_synch();
+# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
+               chdirx(orgdir, 0);
+# endif
+               error("Quitting.");
+       }
+
+       /* regularize(lock); */ /* already done in pcmain */
+       Sprintf(tbuf,"%s",fqname(lock, LEVELPREFIX, 0));
+       set_levelfile_name(lock, 0);
+       fq_lock = fqname(lock, LEVELPREFIX, 1);
+       if((fd = open(fq_lock,0)) == -1) {
+               if(errno == ENOENT) goto gotlock;    /* no such file */
+# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
+               chdirx(orgdir, 0);
+# endif
+# if defined(WIN32) || defined(HOLD_LOCKFILE_OPEN)
+#  if defined(HOLD_LOCKFILE_OPEN)
+               if(errno == EACCES) {
+#define OOPS_BUFSZ 512
+                   char oops[OOPS_BUFSZ];
+                   Strcpy(oops,
+                            "\nThere are files from a game in progress under your name.");
+                   Strcat(oops, "\nThe files are locked or inaccessible.");
+                   Strcat(oops, " Is the other game still running?\n");
+                   if (strlen(fq_lock) < ((OOPS_BUFSZ -16) - strlen(oops)))
+                           Sprintf(eos(oops), "Cannot open %s", fq_lock);
+                   Strcat(oops, "\n");
+                   unlock_file(HLOCK);
+                   error(oops);
+               } else
+#  endif
+               error("Bad directory or name: %s\n%s\n",
+                               fq_lock, strerror(errno));
+# else
+               perror(fq_lock);
+# endif
+               unlock_file(HLOCK); 
+               error("Cannot open %s", fq_lock);
+       }
+
+       (void) close(fd);
+
+       if(iflags.window_inited) { 
+# ifdef SELF_RECOVER
+         c = yn("There are files from a game in progress under your name. Recover?");
+# else
+         pline("There is already a game in progress under your name.");
+         pline("You may be able to use \"recover %s\" to get it back.\n",tbuf);
+         c = yn("Do you want to destroy the old game?");
+# endif
+       } else {
+# if defined(MSDOS) && defined(NO_TERMS)
+               grmode = iflags.grmode;
+               if (grmode) gr_finish();
+# endif
+               c = 'n';
+               ct = 0;
+# ifdef SELF_RECOVER
+               msmsg(
+               "There are files from a game in progress under your name. Recover? [yn]");
+# else
+               msmsg("\nThere is already a game in progress under your name.\n");
+               msmsg("If this is unexpected, you may be able to use \n");
+               msmsg("\"recover %s\" to get it back.",tbuf);
+               msmsg("\nDo you want to destroy the old game? [yn] ");
+# endif
+               while ((ci=nhgetch()) != '\n') {
+                   if (ct > 0) {
+                       msmsg("\b \b");
+                       ct = 0;
+                       c = 'n';
+                   }
+                   if (ci == 'y' || ci == 'n' || ci == 'Y' || ci == 'N') {
+                       ct = 1;
+                       c = ci;
+                       msmsg("%c",c);
+                   }
+               }
+       }
+       if(c == 'y' || c == 'Y')
+# ifndef SELF_RECOVER
+               if(eraseoldlocks()) {
+#  if defined(WIN32CON)
+                       clear_screen();         /* display gets fouled up otherwise */
+#  endif
+                       goto gotlock;
+               } else {
+                       unlock_file(HLOCK);
+#  if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
+                       chdirx(orgdir, 0);
+#  endif
+                       error("Couldn't destroy old game.");
+               }
+# else /*SELF_RECOVER*/
+               if(recover_savefile()) {
+#  if defined(WIN32CON)
+                       clear_screen();         /* display gets fouled up otherwise */
+#  endif
+                       goto gotlock;
+               } else {
+                       unlock_file(HLOCK);
+#  if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
+                       chdirx(orgdir, 0);
+#  endif
+                       error("Couldn't recover old game.");
+               }
+# endif /*SELF_RECOVER*/
+       else {
+               unlock_file(HLOCK);
+# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
+               chdirx(orgdir, 0);
+# endif
+               error("%s", "Cannot start a new game.");
+       }
+
+gotlock:
+       fd = creat(fq_lock, FCMASK);
+       if (fd == -1) ern = errno;
+       unlock_file(HLOCK);
+       if(fd == -1) {
+# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
+               chdirx(orgdir, 0);
+# endif
+# if defined(WIN32)
+               error("cannot creat file (%s.)\n%s\n%s\"%s\" exists?\n", 
+                               fq_lock, strerror(ern), " Are you sure that the directory",
+                               fqn_prefix[LEVELPREFIX]);
+# else
+               error("cannot creat file (%s.)", fq_lock);
+# endif
+       } else {
+               if(write(fd, (char *) &hackpid, sizeof(hackpid))
+                   != sizeof(hackpid)){
+# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
+                       chdirx(orgdir, 0);
+# endif
+                       error("cannot write lock (%s)", fq_lock);
+               }
+               if(close(fd) == -1) {
+# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
+                       chdirx(orgdir, 0);
+# endif
+                       error("cannot close lock (%s)", fq_lock);
+               }
+       }
+# if defined(MSDOS) && defined(NO_TERMS)
+       if (grmode) gr_init();
+# endif
+}      
+#endif /* PC_LOCKING */
+
+# ifndef WIN32
+void
+regularize(s)
+/*
+ * normalize file name - we don't like .'s, /'s, spaces, and
+ * lots of other things
+ */
+register char *s;
+{
+       register char *lp;
+
+       for (lp = s; *lp; lp++)
+               if (*lp <= ' ' || *lp == '"' || (*lp >= '*' && *lp <= ',') ||
+                   *lp == '.' || *lp == '/' || (*lp >= ':' && *lp <= '?') ||
+# ifdef OS2
+                   *lp == '&' || *lp == '(' || *lp == ')' ||
+# endif
+                   *lp == '|' || *lp >= 127 || (*lp >= '[' && *lp <= ']'))
+                        *lp = '_';
+}
+# endif /* WIN32 */
+#endif /* OVLB */
+
+
+#ifdef __EMX__
+void seteuid(int i){;}
+#endif
diff --git a/sys/share/random.c b/sys/share/random.c
new file mode 100644 (file)
index 0000000..02b50c5
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* Several minor changes were made for the NetHack distribution to satisfy
+ * non-BSD compilers (by definition BSD compilers do not need to compile
+ * this file for NetHack).  These changes consisted of:
+ *     - changing the sccsid conditions to nested ifdefs from defined()s
+ *     to accommodate stupid preprocessors
+ *     - giving srandom() type void instead of allowing it to default to int
+ *     - making the first return in initstate() return a value consistent
+ *     with its type (instead of no value)
+ *     - ANSI function prototyping in extern.h - therefore include hack.h
+ *     instead of stdio.h and remove separate declaration of random() from
+ *     the beginning of function srandom
+ *     - moving sccsid after hack.h to allow precompiled headers, which
+ *     means the defined()s would be ok again...
+ *     - change fprintf(stderr, "x(%d)y\n", z) to impossible("x(%d)y", z)
+ *     - remove useless variable `j' from srandom()
+ */
+
+#include "hack.h"
+
+#ifdef LIBC_SCCS
+# ifndef lint
+static char sccsid[] = "@(#)random.c   5.5 (Berkeley) 7/6/88";
+# endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * random.c:
+ * An improved random number generation package.  In addition to the standard
+ * rand()/srand() like interface, this package also has a special state info
+ * interface.  The initstate() routine is called with a seed, an array of
+ * bytes, and a count of how many bytes are being passed in; this array is then
+ * initialized to contain information for random number generation with that
+ * much state information.  Good sizes for the amount of state information are
+ * 32, 64, 128, and 256 bytes.  The state can be switched by calling the
+ * setstate() routine with the same array as was initiallized with initstate().
+ * By default, the package runs with 128 bytes of state information and
+ * generates far better random numbers than a linear congruential generator.
+ * If the amount of state information is less than 32 bytes, a simple linear
+ * congruential R.N.G. is used.
+ * Internally, the state information is treated as an array of longs; the
+ * zeroeth element of the array is the type of R.N.G. being used (small
+ * integer); the remainder of the array is the state information for the
+ * R.N.G.  Thus, 32 bytes of state information will give 7 longs worth of
+ * state information, which will allow a degree seven polynomial.  (Note: the 
+ * zeroeth word of state information also has some other information stored
+ * in it -- see setstate() for details).
+ * The random number generation technique is a linear feedback shift register
+ * approach, employing trinomials (since there are fewer terms to sum up that
+ * way).  In this approach, the least significant bit of all the numbers in
+ * the state table will act as a linear feedback shift register, and will have
+ * period 2^deg - 1 (where deg is the degree of the polynomial being used,
+ * assuming that the polynomial is irreducible and primitive).  The higher
+ * order bits will have longer periods, since their values are also influenced
+ * by pseudo-random carries out of the lower bits.  The total period of the
+ * generator is approximately deg*(2**deg - 1); thus doubling the amount of
+ * state information has a vast influence on the period of the generator.
+ * Note: the deg*(2**deg - 1) is an approximation only good for large deg,
+ * when the period of the shift register is the dominant factor.  With deg
+ * equal to seven, the period is actually much longer than the 7*(2**7 - 1)
+ * predicted by this formula.
+ */
+
+
+
+/*
+ * For each of the currently supported random number generators, we have a
+ * break value on the amount of state information (you need at least this
+ * many bytes of state info to support this random number generator), a degree
+ * for the polynomial (actually a trinomial) that the R.N.G. is based on, and
+ * the separation between the two lower order coefficients of the trinomial.
+ */
+
+#define                TYPE_0          0               /* linear congruential */
+#define                BREAK_0         8
+#define                DEG_0           0
+#define                SEP_0           0
+
+#define                TYPE_1          1               /* x**7 + x**3 + 1 */
+#define                BREAK_1         32
+#define                DEG_1           7
+#define                SEP_1           3
+
+#define                TYPE_2          2               /* x**15 + x + 1 */
+#define                BREAK_2         64
+#define                DEG_2           15
+#define                SEP_2           1
+
+#define                TYPE_3          3               /* x**31 + x**3 + 1 */
+#define                BREAK_3         128
+#define                DEG_3           31
+#define                SEP_3           3
+
+#define                TYPE_4          4               /* x**63 + x + 1 */
+#define                BREAK_4         256
+#define                DEG_4           63
+#define                SEP_4           1
+
+
+/*
+ * Array versions of the above information to make code run faster -- relies
+ * on fact that TYPE_i == i.
+ */
+
+#define                MAX_TYPES       5               /* max number of types above */
+
+static  int            degrees[ MAX_TYPES ]    = { DEG_0, DEG_1, DEG_2,
+                                                               DEG_3, DEG_4 };
+
+static  int            seps[ MAX_TYPES ]       = { SEP_0, SEP_1, SEP_2,
+                                                               SEP_3, SEP_4 };
+
+
+
+/*
+ * Initially, everything is set up as if from :
+ *             initstate( 1, &randtbl, 128 );
+ * Note that this initialization takes advantage of the fact that srandom()
+ * advances the front and rear pointers 10*rand_deg times, and hence the
+ * rear pointer which starts at 0 will also end up at zero; thus the zeroeth
+ * element of the state information, which contains info about the current
+ * position of the rear pointer is just
+ *     MAX_TYPES*(rptr - state) + TYPE_3 == TYPE_3.
+ */
+
+static  long           randtbl[ DEG_3 + 1 ]    = { TYPE_3,
+                           0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 
+                           0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, 
+                           0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, 
+                           0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 
+                           0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7, 
+                           0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, 
+                           0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 
+                                       0xf5ad9d0e, 0x8999220b, 0x27fb47b9 };
+
+/*
+ * fptr and rptr are two pointers into the state info, a front and a rear
+ * pointer.  These two pointers are always rand_sep places aparts, as they cycle
+ * cyclically through the state information.  (Yes, this does mean we could get
+ * away with just one pointer, but the code for random() is more efficient this
+ * way).  The pointers are left positioned as they would be from the call
+ *                     initstate( 1, randtbl, 128 )
+ * (The position of the rear pointer, rptr, is really 0 (as explained above
+ * in the initialization of randtbl) because the state table pointer is set
+ * to point to randtbl[1] (as explained below).
+ */
+
+static  long           *fptr                   = &randtbl[ SEP_3 + 1 ];
+static  long           *rptr                   = &randtbl[ 1 ];
+
+
+
+/*
+ * The following things are the pointer to the state information table,
+ * the type of the current generator, the degree of the current polynomial
+ * being used, and the separation between the two pointers.
+ * Note that for efficiency of random(), we remember the first location of
+ * the state information, not the zeroeth.  Hence it is valid to access
+ * state[-1], which is used to store the type of the R.N.G.
+ * Also, we remember the last location, since this is more efficient than
+ * indexing every time to find the address of the last element to see if
+ * the front and rear pointers have wrapped.
+ */
+
+static  long           *state                  = &randtbl[ 1 ];
+
+static  int            rand_type               = TYPE_3;
+static  int            rand_deg                = DEG_3;
+static  int            rand_sep                = SEP_3;
+
+static  long           *end_ptr                = &randtbl[ DEG_3 + 1 ];
+
+
+
+/*
+ * srandom:
+ * Initialize the random number generator based on the given seed.  If the
+ * type is the trivial no-state-information type, just remember the seed.
+ * Otherwise, initializes state[] based on the given "seed" via a linear
+ * congruential generator.  Then, the pointers are set to known locations
+ * that are exactly rand_sep places apart.  Lastly, it cycles the state
+ * information a given number of times to get rid of any initial dependencies
+ * introduced by the L.C.R.N.G.
+ * Note that the initialization of randtbl[] for default usage relies on
+ * values produced by this routine.
+ */
+
+void
+srandom( x )
+
+    unsigned           x;
+{
+       register  int           i;
+
+       if(  rand_type  ==  TYPE_0  )  {
+           state[ 0 ] = x;
+       }
+       else  {
+           state[ 0 ] = x;
+           for( i = 1; i < rand_deg; i++ )  {
+               state[i] = 1103515245*state[i - 1] + 12345;
+           }
+           fptr = &state[ rand_sep ];
+           rptr = &state[ 0 ];
+           for( i = 0; i < 10*rand_deg; i++ )  random();
+       }
+}
+
+
+
+/*
+ * initstate:
+ * Initialize the state information in the given array of n bytes for
+ * future random number generation.  Based on the number of bytes we
+ * are given, and the break values for the different R.N.G.'s, we choose
+ * the best (largest) one we can and set things up for it.  srandom() is
+ * then called to initialize the state information.
+ * Note that on return from srandom(), we set state[-1] to be the type
+ * multiplexed with the current value of the rear pointer; this is so
+ * successive calls to initstate() won't lose this information and will
+ * be able to restart with setstate().
+ * Note: the first thing we do is save the current state, if any, just like
+ * setstate() so that it doesn't matter when initstate is called.
+ * Returns a pointer to the old state.
+ */
+
+char  *
+initstate( seed, arg_state, n )
+
+    unsigned           seed;                   /* seed for R. N. G. */
+    char               *arg_state;             /* pointer to state array */
+    int                        n;                      /* # bytes of state info */
+{
+       register  char          *ostate         = (char *)( &state[ -1 ] );
+
+       if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
+       else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
+       if(  n  <  BREAK_1  )  {
+           if(  n  <  BREAK_0  )  {
+               impossible(
+ "initstate: not enough state (%d bytes) with which to do jack; ignored.", n);
+               return (char *)0;
+           }
+           rand_type = TYPE_0;
+           rand_deg = DEG_0;
+           rand_sep = SEP_0;
+       }
+       else  {
+           if(  n  <  BREAK_2  )  {
+               rand_type = TYPE_1;
+               rand_deg = DEG_1;
+               rand_sep = SEP_1;
+           }
+           else  {
+               if(  n  <  BREAK_3  )  {
+                   rand_type = TYPE_2;
+                   rand_deg = DEG_2;
+                   rand_sep = SEP_2;
+               }
+               else  {
+                   if(  n  <  BREAK_4  )  {
+                       rand_type = TYPE_3;
+                       rand_deg = DEG_3;
+                       rand_sep = SEP_3;
+                   }
+                   else  {
+                       rand_type = TYPE_4;
+                       rand_deg = DEG_4;
+                       rand_sep = SEP_4;
+                   }
+               }
+           }
+       }
+       state = &(  ( (long *)arg_state )[1]  );        /* first location */
+       end_ptr = &state[ rand_deg ];   /* must set end_ptr before srandom */
+       srandom( seed );
+       if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
+       else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
+       return( ostate );
+}
+
+
+
+/*
+ * setstate:
+ * Restore the state from the given state array.
+ * Note: it is important that we also remember the locations of the pointers
+ * in the current state information, and restore the locations of the pointers
+ * from the old state information.  This is done by multiplexing the pointer
+ * location into the zeroeth word of the state information.
+ * Note that due to the order in which things are done, it is OK to call
+ * setstate() with the same state as the current state.
+ * Returns a pointer to the old state information.
+ */
+
+char  *
+setstate( arg_state )
+
+    char               *arg_state;
+{
+       register  long          *new_state      = (long *)arg_state;
+       register  int           type            = new_state[0]%MAX_TYPES;
+       register  int           rear            = new_state[0]/MAX_TYPES;
+       char                    *ostate         = (char *)( &state[ -1 ] );
+
+       if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
+       else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
+       switch(  type  )  {
+           case  TYPE_0:
+           case  TYPE_1:
+           case  TYPE_2:
+           case  TYPE_3:
+           case  TYPE_4:
+               rand_type = type;
+               rand_deg = degrees[ type ];
+               rand_sep = seps[ type ];
+               break;
+
+           default:
+  impossible("setstate: state info has been munged (%d); not changed.", type);
+               break;
+       }
+       state = &new_state[ 1 ];
+       if(  rand_type  !=  TYPE_0  )  {
+           rptr = &state[ rear ];
+           fptr = &state[ (rear + rand_sep)%rand_deg ];
+       }
+       end_ptr = &state[ rand_deg ];           /* set end_ptr too */
+       return( ostate );
+}
+
+
+
+/*
+ * random:
+ * If we are using the trivial TYPE_0 R.N.G., just do the old linear
+ * congruential bit.  Otherwise, we do our fancy trinomial stuff, which is the
+ * same in all ther other cases due to all the global variables that have been
+ * set up.  The basic operation is to add the number at the rear pointer into
+ * the one at the front pointer.  Then both pointers are advanced to the next
+ * location cyclically in the table.  The value returned is the sum generated,
+ * reduced to 31 bits by throwing away the "least random" low bit.
+ * Note: the code takes advantage of the fact that both the front and
+ * rear pointers can't wrap on the same call by not testing the rear
+ * pointer if the front one has wrapped.
+ * Returns a 31-bit random number.
+ */
+
+long
+random()
+{
+       long            i;
+       
+       if(  rand_type  ==  TYPE_0  )  {
+           i = state[0] = ( state[0]*1103515245 + 12345 )&0x7fffffff;
+       }
+       else  {
+           *fptr += *rptr;
+           i = (*fptr >> 1)&0x7fffffff;        /* chucking least random bit */
+           if(  ++fptr  >=  end_ptr  )  {
+               fptr = state;
+               ++rptr;
+           }
+           else  {
+               if(  ++rptr  >=  end_ptr  )  rptr = state;
+           }
+       }
+       return( i );
+}
+
diff --git a/sys/share/sounds/README b/sys/share/sounds/README
new file mode 100644 (file)
index 0000000..74bddea
--- /dev/null
@@ -0,0 +1,34 @@
+README for the AIFF files:
+
+These files are sound files for the instruments in NetHack.
+There are 11 sounds, one for each distinct instrument.
+The sounds are in 8-bit 22kHz AIFF format, which should be
+readable by a broad range of platforms. Since the sounds
+came from Rolands S-750 sample library (most of them) there
+should be no copyright on them when we treat them like we
+do here (as instruments) - indeed, the sample library I
+got from Roland didn't even bear a (c) symbol.
+
+Some of the sounds are very adequate (Drum of Earthquake,
+Wooden Flute, Magic Harp) while some are less true to the
+original name (how does a Frost Horn sound?) Actually, I
+don't know what a Bugle is (Bugle horn?) so I took a trumpet
+sound for that. Correct me if I'm wrong.
+
+What does this have to do with the main code? Well, nothing
+so far. There are some places that are #ifdef MAC and calls
+mac_speaker; that function takes an object and a tune (in
+capital letters A-G) and plays the tune with the given
+instrument. When playing a specific tune, that tune is of
+course used. For "improvise," I use middle "C."
+
+Ideally, we should do something equal with sound that we
+have with displays, so we can use one common set of calls
+in the main code, and have ports do whatever seems appropriate
+for the available hardware.
+
+Any comment on the sounds or their use is welcome:
+
+                                               Jon W{tte
+                                               Mac Team
+                                               nethack-bugs@nethack.org
diff --git a/sys/share/sounds/bell.uu b/sys/share/sounds/bell.uu
new file mode 100644 (file)
index 0000000..ec6a17a
--- /dev/null
@@ -0,0 +1,407 @@
+begin 644 Bell
+M``1"96QL````````````````````````````````````````````````````
+M``````````````````````````!!249&4V0R80$``````````````$0B```!
+MSJ<]K>2G/:WQ``````````````````````````````"!@6<2``!&3U)-``!$
+M&D%)1D934TY$``!"'@``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M_P````#_``#___[^``$#`_W]_OG[!@L%_??S^P``!P_X[/_\_@`&!__^[O@)
+M^?<*%/CF!OWL"Q0&\?+]^`'__@C[^`@#]_3Q^0L%_Q8$U><%_PXD!^OVY=0(
+M+`_]``#DT?8='`H.!N'=Y/`H(/@5!\_-!AL"%PSY^M#H&P'_(`O:]`SA^QWX
+M_A?PZP[YZ`@,]@H+ZO\"[``$_`L)Z/89[M\6$OD`_?X`Z>06)?'S#?3H[0,:
+M#O[]]^7P$__['/SJ_/CT!@SY`@OQ\PCX]@@&_O0`!/O\\PH*Z_H/!>OX%_;I
+M#A'W\?SY^0L`"!CQXO?\]`DD#/'ZY^#_"!,8$O'?^^GG&B@&]03WUND.&1?^
+M^P#LXO8/%0[_\?<`Z/0;$?SW__OL^PD!_@<*[O(3]></$O'W$?OQ`O?U$0?N
+M!Q;SX/T1_/@##@OIY`84]?,5#_+P^_D#!_8#%?7G!P7M`1OUZQ("Y_T+`/S^
+M_OT+\^P9!NKV#0?K_@8!!_/U#?SM"!'Z\@W_X_\%_PX!_/WY\/`-"0`-_?3S
+M\0(%``40`N?P!`#]!@<%^>WX!0'_"03W^/;Y"PCT``[PYPD(_@?^]/X#[_H9
+M`?;]\_[]^`L0^.P(`-\,&/H$`?'R`OK[%0GP_?_U^/@3$NOX%/S>_ACW^`[Z
+M_OSU`O__`@3Z^P;O_!#L^A[^Y`P0WO@7^?L,_/?Z\0`._/D1_.\)_NX&"/0`
+M!OG\"/?U#/_W`04&^/8$__/W#0CZ"/SR`_KN"A[_Y_\(\?+\$QKUZ?\-].D.
+M&@7OZ0H&Z/H?&>7J#OON`Q(.]?$#]_0)%`#P!_OO!OP'%_CL`PCC^R3^^0CV
+M\_OU"!O]\!(`UP@8Z_P7`>__!03\Y@0D\.0?&.+C!@L&]?HH"<OP(/_J#!H"
+M\^?X&//M(A;J[0?^\P,'#0/N`03M_14#]@,%^_7W`A#U[QD&[`8`\0`&^@L4
+MZO$.\>X3$O\#]NT"!/P,$??U_>_\#00%"OOQ`/SS"Q($^O/X_/?[%Q;Q^`#O
+M]`@/$`CNZ0;^Y0XI!^SQ`/;R"!$/`?#R]O[_!A<&]OCU]P(%!@L&[_4([_L;
+M_NL*#._T#@/Z"OCW#/7L!!0*]OD#^?;[#`_W\04%]?@/#.?W%?_X!O[Q^P?[
+M"QGO[@/S]`\4^_D&]>S^"1`"]`4'\>8%&`#S"`_Q[/L$#@;U`0_TX0L4[_P1
+M_O,'__,#`OC]#@7_^?#^`/P*$`'X]_GS`@_\"0SKZ`<,[@,E^N@%_N;T'1'^
+M!O?S\.L+)@WS^@3TX/T/#Q7S^0GCYA`B_/06_-GR%@CT^@X&^`+[^_;M`QP/
+MZ_L'X>8/'PS]^_/V[/4=$0'\_.OH"`$%$`C\[/O[ZPT8_/H,^=_^#/8&&/GM
+M"OOL`P3Y!!'_]@'R]0+S$"+TX@0%XO<C%?O\\^WZ]OT6$_O\#^;-#"(%`Q$`
+MV=[Z%"8"]A;TR>P;&P4#!_OGU?\N"?@7!^+;^@\)#A$-\MON_OX0&@\$Z]_U
+M`?X-(`SP]O+G^`@4$P#]`>G9`QT#`A((\.+L`A,#!QWYY>[U`0L6!0<$V.@'
+M!0\*#`+PZN@+$08+``'\Y.T/$P`!"_CC]@L)`P`6"-7N$`CT`!H"[N?^&??M
+M%![NW!(0X?47&>_G"0?XZP<;^.D#%/KC!"("V/TJ^<D&,O7<`QP'X.\3%_#J
+M&`WI[_T0!NO_%__=!2'NZA0,YO03"O'X!OKZ^@(4"?/P!O[?`BL2[NC__>OV
+M(2_TU?P%XO@D%@7YVO`.\_<M(^#J!.GL"Q<2!.WT^.H!'Q+R^0+J]P()'P'@
+MZPX$Y@TC!N7F!@3^#`;^^_;O_1`%`P+Z\?P!!1+Y^_[J\@T8_@@,WMH`%@P/
+M%?SIV-X,)!\.`_32U0$H(PD#].+2[3$F\@,4YLW^'Q`#`O_UYNT0&`0#"?#?
+M^Q8,_?T%^^+Z'A'R]0#Q^PL:&N/2_P_W!2H1Y]KH#1/\$BORR/4+\P0G#_/S
+MZ^S_%!4-"O+8YP\/!QT3X=KS_0T@$?\`X=P$#A(>!.'V^]H+.P;M`O+B``X*
+M)0K5XP'Z`R8=`?#@W?$8*!L(\.?6YPP>-17KY>K@Z2<K"P'R[O#F]"XFY?@>
+M[M'[#`D:`>P,!-CN(`SX"07T]_?U#@?X"P7O]P7W_Q<%]0+][_C_!A4%\OC[
+M_OX`_@T/ZO0&`OOX`@L*]?P,\NT)!OP0!?#^^.T(%O?Z%?CR`OC\!0`*&?':
+M"P7>!"D2]^_N_O_N#RK^YOWXZP`)#!/\]@#MZQ`6]@L.XO'\]@\9_/45\M$+
+M&0,#`0'UZ^T0&O@&"NOM!0+]#Q'XZOH&]O84#O`"">CW#_O]&?WE"O_D"!7X
+M!`CK_@CO^Q[[Z1?ZY@P+\OL5^?0-]/L,^/<("?/[#/KS`@W^\P4)\_D0_?<$
+M`_CZ"/T"`_7__O\"`@`$">SQ#@3V"!+P]`+P]10:^/P'[./\%`H,#_;F[/S_
+M"B`3^.CN]_0&'"``W>O_^?<7)`SMX?`"!/X;(.[C^_3K#",-!@#CZ/CY#BX/
+M[_SFU/HD&Q$+]>_>X!$F#@4*\MOR_@4;$P+X]^_M`Q$1`OL&]>K\"`P'_?<'
+M!>O[$P3Z_?H""OOV#`3L``O^!@SX]O_X_`L*_P7YZ0,+^086!^KR`_4&#@('
+M`?;E_18$"0'_`^_K_QX'\@L"]O?W``\-]0`/^>GZ"PK^^Q`)Z?$&!``*!?D'
+M^>\!!`8'_?P*_.@!$_H"$//U"?7M$AOY\P;^]/<#%@CU]P``^/H+%P+M^PS[
+M]``)#_OM!0WR]18%\P@"]``'^`$*[_X2]O49"=X`$_/X%!'X].[S$`7_%1#N
+MX0,"_P\("O_MY_T5^00@`.7Q!/W_%0D``^SH!1(``!``[/3^!A`!_`GXZ?T1
+M__L4_^T"_/0#$`H``?'V!/D!$`OZ\?D``_\!$@'N^O\$`OT!`__U_P7]"/_X
+M#`3N^0S]^`X!^P?T\`P&]PP0\_`!^?H)"0\%[/L`[OH8$?H&^>;Y_@09$?[]
+M\N3Z#0D4$O#U]MP%+@;R&PC(Z1$($@T``/;=\1T/!1+ZZO?U]10;_/C^[^X,
+M#@H0`.OF`@G^#Q7^Y^S[`Q(2!PKWVNL)"Q(5`?3W[>02(`@'_/;T]>\**?SI
+M"@?M[PX-!`3U_@;\]@(0__3[`@4'`/L#__;Y!PX(`//X!_CW#Q#_]P#Y]@<$
+M!0[_]O?\__L,$@CY[?O^`08*%P;IY_\&]PT?"?+M]_4#$`\2_>KP_OP!&`SZ
+M`_OL^`P("0?U!`CCZ"(=YO\?^>?V`@8+`P`4]]L"#_C_&!'[]._T`O\&&P_X
+M]?+M]Q$9"P4#]^3K"`\+"@0#_NSK"0\"#`_Y\?CO_!0-!0H![/+^_PT2`?O_
+M]/`"#@4""P3V\_X!_@L,!?OJ^@4!``H6]_/]_0KW\@H5!/$%_NSX!A,.!/SY
+M[NH'$`\,`OGR\.D.(@,("?#?\@X)#P\(!=O;#AC_""$`X^KM#1P!`!#ZV?@8
+M`?\)!/OU``0)_?0&`/<&"__[!/[R^@P+`O[\`_KN^PL4`/T)]/#\!P4$#_;Q
+M!OKY#POY_`#S`A+W_!7VX?\/!@L,]/C_Y?P?#/P'_N'Z#_X($`'W^??X#`H`
+M!/GY`?T""PGY\OD"`P$2#_/H^0$`$@X'!.3=`Q@'#B#QV>_X`1<I$?'EX/0'
+M#R$A`-W;]@`!'2L.Y^/O[?T7(QSWZ/#I[!$N#?L%[MSX$A(/!/?W]?$%(0GM
+M^P/X\@L@"._R`/?T$Q4(_O+W]_<&&`WX__KN!`K\#0OP\PL#^18$Z/[]]`P=
+M!O<#\.+_$!85!/KSYN0*)1`($_35YP<2$14*`/'7\!89"0D0\]WQ"`\-#@OW
+MZ/(#"`<0$/7M]_L#"1,(^_OM]P4)"08+^?'Z_0H&`P<$^O#\!`8&``4&]?`(
+M"O7_%P7K^PC^]/P4$?OT``3P^0\/#?SZ_>[O!QH(`A'^WNH+#P4,%P#?Y0`+
+M!`X:`^WL^`(##Q`&^NSV`P`!%!7NZ@D![@4?!/#[__KX!1,+]/<'^?`+$_[\
+M!/SY^OP*#?SY"P#G^!(*^005_>+V#P#Z$Q/V[_GW_@@,%`GO\P#S\@X<#?GS
+M^_OH^"0@^O,`\>7_%!,*__;Q]/D'&1'Z\OWU[08;$/?Y]^[Y!1<5`_;O\>\#
+M&1@*^.[L]?X*(Q7U[_3N\!,="`'Y\._\"!$1`?3T]OH($PS]]O?R_!`4#/WR
+M[?+^#!X1^OCLXOH?%0</^N'F^`D@&_K[^-[K$AT/"__L[.G](!H"``#AY@@.
+M$!4)[>GX^P<1$`OU[/,$"0,-"_SK\@@)!P@"__/M_Q(/`@C\Z/<&``L:!>_Q
+M]?H)"PD2_^;Q!0,%$@W\\_#V!PD)$`;S[?D#!`T-"/[O\/D("@41"_;I]@C_
+M_P\4!?#S__SZ`1$3`??Y^_3U#A@*!/_VY^T($A$.#OO>Z04*"1@<^N'H]@(.
+M$Q</[][M!08'(AKVX^KX]PP>$P3U[>GV#Q80!0'XY.L-%@8$!_WP\OX/%_[W
+M"?_I]A@+]@<!\_8&#`(&`@#Z\`0,`/H&"O3W"0;__/X'!?;\$0?N^`S\]@L+
+M`0`!^//_!`@+!`+Z\?/_"@4+$O_P\_S^_PH/$?_F]`/W^1<;_OCZ[O8"!A,2
+M_O+W\_,+$0T0_.KS_/L(&0[^^>GL`PL-$@KY[^[V!1$1"OOO^/;T$1H&]_KZ
+M[O@,%Q'U]/WS]045%`/QZ_\`]0X=!_'R]O,#$!`)_O;L\PD/!PD*\>3Y"@P.
+M"OSV[^T#%Q8'^_+M\_P0&PP`]^CE`A8+$1CVVNS^`1$>#?KQX^X.$`P3"N[D
+M]OP)%0L%_.[L_PL+$@GR\OGQ_1D3_/[][?(&"PT1_?'Y^/(#&0O[`_SN]P<-
+M"`4`^OCS_PL'`P+^^?W__PP+^_P!^O<%!_\%!?SY`0(``P0!_P(`^?\'__@!
+M"@+^`P+_^?H#"`0!!?_V^?\#!@8(!?OV_`#Y!1`*_O?Y^OL`"A0']?C[_O\%
+M#`;]]_W^_@@$_P4$^OP$_/T-"/O^__;Z!04)#?[V^_OY!0X)!0'X\O3["Q4)
+M`@;WYO(("P\5`?/U[.\+&@T("O#E^``'$1,&]?3P]0,,%PK\^?7W^@@0"P/V
+M]/;_"@4*"??R_@+]$!+T]@/S]1(2_P8!ZO8%`A`4^_3\[_$)#Q04]^?X_/$+
+M(0X#^>;G_@@)&Q;\Z^KT_`P5%`7S\>[T!0X4#/_S\?CY"1`*!OCT^/S]"!,$
+M]_W]^OX$"@C\]/T$_O\&`P'^_/\"`/T"`OX"`O[^_P#]_04%_?T%`_/[#0;]
+M``7^]OC\"@_\_07_\_@'!@D(^_GY]OD"#1$*^^_Y^/4,%PS_^O'I]@0/&P[W
+M]OCKZA(C"/T']=SP"PT4%0+V\.?V$1$($`#F[?D`%!8$!?K<\1@&_!X.W.@"
+M^P08$P3[Y^<%"@44%_OAZ/T%"`\:"^OE\O\($1,&^//O\`(8$@`!^^_T``8/
+M$OOS__CR"!<$_0+X]/H("08+_/7V_@7^"@H$_.[\!@0`!!#^\O?^!?\"#@CW
+M]0$`^@0.!_[[^_CY!0D&"0/[]_3Y"!,#`@_XXO4)!0H3"?KTZ_8."`D3!_#K
+M^/D&$PL*`/+P]`4+$`GY_?;R^PH6!_W_]O7]!0L-!O/Y`O'\%PW[`@'P^`<`
+M"1/^\OC]``$!"A+^[?T&^_\#!@H`\O@*`O,#$@?W^@?]]P`"!PD$]?L']_<*
+M#`@$^O+]`?@'%`C_^/+X_P,+%0;T^?7P`P\-#@CSZ?O__`\7"?GR[?('#PD.
+M#/7F[P$+#!`-^NWL^`$,&0\"\NGQ^@<1%PWX[^?S!0H3&0CL[?3P!!<4#@3O
+MY_;[`QH4`O_QX_4+"@\5`?'R[O<-%`X&^?#R]0`1$`<!^.WU`@0/#?[\]O3X
+M`PT+!_?Y`?/\#0D!`/OS_PC]`PC^^_W]_@<)__H``/?["@K^_0#Z^P`!"@K]
+M^?W[^`0%`PG_^/_\^0<*^P(-^/("`OL#"?\"!/;Y`@`!!@G\^@'X]P$*"@`"
+M_/?\^P,+"0/\^/+Z!@,)#@'Y^/3Y"P\"`P;S[OX"`P\.^_;^]O0)$P@`_/;T
+M^OT*&0?S^OWV^0L.#`7P]?_Y_0P4`?[^\/D"!PH'`OC\^/4'#@7]!`'P^0P'
+M_`4&^?C]_P4*^_H.`?+^"`,``P`#`O7^"?S\#0CX_P7Y_`;]`0X"]?T&^/D(
+M!@H&^?@``/<$#@0"_OCZ``(!"P;]_?W[_@0$`P/__/O_!03^`@;\^/T&"__Y
+M`@3V]PD'`PC]]@+]]@80`OT'^?```@4,!@+]^O7Y!P@+!?K]^OG]`PX,`OOW
+M^/H%!@(-!O#T`?\$#`,`!O7L!`S]!@W\^/KZ`0L%_@?^\_H!!@@%__O^^OH!
+M"0[^^?S\`/T!"@W][@($\P,+`P$#^/8&^_L1!O8!`_7Y!@(#"/_]`?GY"`'\
+M!PC\]O___@4!!`;^^/@"!/X%!/S\__[[!@O___WY_P$"`@<`]_[[_@D&``("
+M\_8(`@$)!OGT^OX)"0`%!O7K_PP'!04!^?3S`!$(`PC][O`&!P(,"O_R\O\!
+M!0D(`_;W__[_!`P%]OO__0$``@<!]_@(`_H)!O?X``$`!@8!`/CU_P<(!@'_
+M__CU_0L+`/T!__;X"`@"`@/^^/K^!P;Z!`OY]0,)`/S_``3^^P8#^/L(!/@$
+M"OSW_PC__@4"`?[]_0$!_0<(^_H!`?P!!08%^OC_`/P$"@`&`_+V!@7\"`W]
+M^?CW``8'"0G^\_C__P4,"?_U]_S^!PL*`?OY^/P##PO\^OSX^`4*"PO[]/O\
+M_`L4`?W_\.X"$@L(!OGU]/P'#`D"__3S_@0'"`8#_/;U`PH"`PC]\/D&!0`'
+M"?SS^P8$!`7[_O_V_0P*_@#]]/X*`@(,`//X_@`&"@4#_?'Z!@($#`?Z]?C\
+M!`<%"0+W^/W\_@\-^O@$`?#[#PC]``'[_/[["@WZ_`?\[0(1`OP#!/KS^0@-
+M``$)_/+Y`0$'"P'^^_+W!0H$"0SW[/H!_083!OG\\_(%#08,#/7M]OH"#@P&
+M!/7K]P,)#0P"_?/K^PD&"0\!\/3\_P(*#@?W\OK]_P0%#`7Q\@@(]`01__3Y
+M```"`0,*_/'^!@,`"`;[]?8#!P,#"`#V]OP#`P@'`OSW_/\"`P,'`/?Z_P(!
+M!0/_`?GX`@G__03_^?P#``4(_?O___P!!@("`OCY``0```8%__3Y"07Z`PO]
+M]?W_``@#_`4#\_<+!OP%`_?X`@("!0'__OO_!`0"`?[[`/[_!@?_^?_]_P8$
+M`0$#^O4!!@,"!?_V_?_\"`X"^@'Y\P()`@<+^/+^_O\,#00`^/#Y!`4-#OSX
+M^?#\$@L#"@+I\04#!@\)^_GT]`,*"@D$^_/U_@<)"0L`\O+]`P,*#`3U\O[_
+M`0H/!?CV]?T#!`D.!?+W_?L!"@\%^O;X^_H'$@K_]_GZ^_\($`3\^/?[_P<(
+M#`7[^//Z!@D'!@+U]OS\"!`'_?WY]/X#!PP#^OO\^?\*"0<`]_W\]P(/"OO_
+M_?;Z_0H2`_G\_O/Z"@L)_/@`_O7^$@?[__W[^_T##07V`@/P^`L)_0$$_?KW
+M_@L(^_\)_?3Z!0<!_P(#^O8%!_S_!@+X_`<"^?X$`_W]``$#_?T(`?7]"/_U
+M!@GY^@4$_?W^``?^^@0$^?L#_P,&_?\#^O8$`_T(!O?Z`_C[#0?[``+W]P($
+M"`7\_?SY^`(,"0+[_/GV``L)`P/[]?7Z"0P(!0'Y[?H"`@X+`OOV\/<-!@0/
+M!?'P_?T##`D$_OCR^0,'#@?_^O7X_@,&"PCV\OP!`@4)!?[Y]?@$"00"!?[T
+M]OX%"PP%^/;U^@,(#0;]]_7\`@L(`0']^/@#!@0"_?[^_?X&!_X`_OT`_`$'
+M!/SY`?T`!P$#!/GV!`3_!@;W^@7Z`0H!``/Z]0@)^00'_?S]_0,)_?T'_?D!
+M!P$``?\"^_T(!_[Z___]_@4.`OG_^_<"#`,&!?+X`OC_&`WT_O_P^@D'"POX
+M\OWZ^PX-``+[\_S]`0X.^O0"^?8%#`L`^??[`/X$#`G[\OP#^@`2"?CZ_/G_
+M"`8$!OKY`/K_"@7^`0+Z_0#^"`?Y``?Z]P0"^`()`0`"_OS\^@,-!/W^_/?X
+M``<-"?[[]?;_!@@+"?GO]?T""@P(__3S^P$'#`K_]//X`P8'#@?R[OT#`@<-
+M!?7R^``$!@L$_/7T_P8$!PG^\O?^_P8)!`#Z]/X$_@<,_O3]__D%"`$"^_8"
+M!OO_#0'S_@(``?_[`@3Y_@H$^_S^_`$%`P,`^OC[`08'!0'Z^/O_!`<%__[X
+M]P$%!0,"_OG\_0,+`OS^_/7_#00!!?KQ_00`"PS^]O?X_`D*!0C[\O;\`@@+
+M`__[\OP&`0,,`_/X```"`P,!_/K\`08(`/K^_OL#!P```_GW!08`!`'Z_/\"
+M`P,``?SS_@H'`@+]]OO[_P\/__CY]_<$#0H&`?;M]@8+"PL%]>WV`0D-"07[
+M[N\`"PD-"?OT\?8%$`H%!/+L_08#"Q,!]/3X`@4'"0CZ[OT!_0@."/GV_`$!
+M^P80`?'U`@0`!0T$]O7_`P(*!OCU^@0'!`0$_/#Z"@L&!/[S]/L&#P<``?OQ
+M]@@."@3[^O;R_@\0!?_V]/G_"1`+_?3S]@0(!P\%\.S\!@4*"@7\[.\##@H&
+M!?[T\/H,#04$`//T`08)!0$`^??]!P8!`OOZ_P`$!0/]_OST`@\"_`'^^_O_
+M"`P!^/W^^``)"`'Z^/S__`81`O/X`?O]"@@#_?7V``8#"`C]]OC]`0<(!/[W
+M]OL"!0@)_O?Z^_X'#0#Z_O3U!`H'!0#V]O_^`PT'^OCZ^/T%!@D#]_;\`0(%
+M!?_^^?@""`+\`/[Y_P<$``+^^?L`!@<!^OW_]_L)"P,`_?CZ_`$)"?[\__3V
+M"0T#_@/[]?D"#@C[^P'Z\@4-!`#__/C^_@,+`?K]_OC\"P8``/_Z^0$#!@3_
+M_?C\`P8"``7\]/X'!/\#`?C[_@()!/K^`?GW"0[__/_^^?<%#`3]`0'U]P8(
+M`P0!^_OZ_@H(_OX"^?4#"@7_``#W]P0+!0$"^_;Z``8)!O_[^OG^!0@(_OS]
+M^/H#"@0$`?/Y!/\!#0OW]/S^`P4&"`#T]@$"!0L&^_CZ^@('!PD`]?8#!?P'
+M"_[W^@`!!`3_`0#[`03]_P;_^@($_?\$`0#^_0$"_P((`?7[`?\"!P<!_/7Y
+M!P8!!0;X\OX"`@@$_@#\]?X,!_\"`/GZ_`(,"?W[__O[!`8(!_KT_`#^!@X"
+M^OSX^`4/!@`!^/+\!0@)`_S[^_?]#@S__?S\^OH##`GZ^0+]^@`&!@+]^P+_
+M^`$*`?G^`_[]`00%__?[!@3_`03]^/P!!@0!`?GY`0,!`@;^]OO_!`8"_O__
+M]OD)"@#\`/[V^04*!/[^_/C\`04*!OWY^?O]!0D"`O_U]@`*`P$&_?7X`@4"
+M!@+[^OG_!@;__P3Z]O\'!@+^_O_W_0<$_P,#\_D)`/P&!_OZ_OL#!OX``_WY
+M`04!`0#\_/[_!03_`/_Z^P0$`04$^_7]!/\`!P;[]_[_`@("!@'W^04"_00%
+M_/C^_P8'_`$$^/<$!_X$!/C^`?W_!0;__?S_`_S^"`+Y_`(``@4!`/[X_08&
+M`00!^/;^!@4$!@+W]?\"`0H)_O?Z^_T&!P4#^_G[`0(#!P3^]OL%`?\$!@#Y
+M_?X$!O[_!`'[_`,&`?P`!OWX"0GY_`/__?\$"@?S\@@#^`42!/#U`@/^`P\%
+M\_4!`?X%"0;\]/T#_O\+"_GT_0+\^PX2^^_^!/3]$@P`]_;\__T"%`OR]P#[
+M^@8,!__V^P+[``T%^O\!^?\$_P,"_``%_/H'`_O_!07]_`$!^OD)"_[]__[Y
+M_`0*#/SV_OSX_PT-`?OW^_W_"`H(`/;T^0,%!0D&^_/V``<'!P7]]?7[!`D*
+M!O_W\_L!!0H+`?;V^OP!!PT(^O7]__<!$0G\^OS]^/D%#P?Y_@/Y]/X+"?\`
+M!/SP^`D&`@<%^?/Y``0'!P7]\_7^!`0'"P3S[OX%_@00"?3Q^OT!!@L+_O+S
+M_0,!!PL&^._[!/\!"PG[^/G[``8&`@0!^?;\!`0#`P'^^?G^!0<"_P'^]OD%
+M!P``!/_X^O\$!@+^`?_Z^@`&`__^`@#X_@,#`OX``/_Y^P@%_0`%`OCW``<#
+M_0($_/C\`@8$``'_^OK_`@0%`?T`_OO_`P0#__X``?KZ!@8`_@(#^OH`!@3^
+M!`'Y_/\"`@4#_O_Z^P$$!0,!_OS\_0(&!@/Z^0``^P0.!??X_?W_!0D(`/?X
+M^_\'"@@"^_7X`0,)"@']^_GZ!`D#`@+\^?L#!@,#!/[V^P,"`P8"_OOY_P8%
+M``0$^/@"!0'_!03\^?\$__X$!`'^_?___@`$!0'___KZ``0&`P0"^O;[!`0&
+M"@'Y^OCY!`P+!/[U]/P`"1`*_O3S]O\)#0\#]O/R^`<3#0,`]>OU`P\3!OWX
+M\O+\#`\*`/?Z^/@%"P8!`/KW_@$"!@,`__O[``(``0/__@#^___^`@0!_@(!
+M^?L``@0%!`#[^/L``P<*`_CW^/L`!PP)__3V_?P!"PP"^/?Y_``%#0;W^?[[
+M_`<+`?KZ^P`!`0<%_/7^!/\`!`/]^/P"`P(#`OSY_@(``0,"_/C^`P4!_P(!
+M^O8""P/^`/WY^OX#"@?\^_WY_04'!?_\^OP``08&_OS]_OT!!0(!_/D``?X"
+M!@'Z_0#\``0"`/W^____`0<!^/P!`?T""`+[^/X$`0$%!/GU_@0"`P8$^_7Z
+M!`8"`PC\\_P"`@4&`?S[^?\'`@,&^_;]`@("!@0`^/4%"/X$"`#V^O[_!P0!
+M!`#Y^_\`!`<!___[_O_^!`;^_0,`_`("_P("`@#\_/_^_08(``#^^OX"``<)
+M_?K_^O8&#`0#`/KY^/X+#0'^`O7Q`0D("`/]^_;V!A`#`07Z\O<$"@@#``#W
+M]@,)!@("_O?Y`0D$``/_^/H#!P0```+]]OT)!?T!`O[[_`(&`OX"`_O]!`'_
+M``$!```!!/_Y_P4"_P$#_OK\`00"`P3^^?L!`@($!`'Y^?\"``((!OSV^P(!
+M``D*_?;X_@0#!`@"]_<``P(&`_[\^?P$!@,"__K[`0$""`+Z^OW_`0,#!0'W
+M^0,"``0%`/O[^_\$`P$!_OS\``,$`OW\_/X!`P4"_/K^```#!P/X]_X#```(
+M!OSU^0$#!00%`O;T_08&!`;_]_?]`00)!OSX^/P!!`<'_OCX_0$%!0,#_/7\
+M!0(`!0+Y^?\"`P,"`?WX_`0%`O_^`/[Y_PH%^_T`^_T#`P0#_/G]``(%`__^
+M^_L``P0%_OK]_?T""`/]_OS]`0(&!/[Z_/W^!04"`OSX_0$#"`;\^OSX_0D*
+M`_WZ^?T`!`L'^?C\_0`%!P7_]_@``P0'`__\^/L#!04%`?KY_@`#!0($_O;[
+M`@,$!0+]_/K]!P4!`_[Y^P$#!07___WY`08"``+_^_X``P8`_0'_^@`'`O__
+M_@#^_@8(`?S^_?T#!`4%_?G^__T'"@'___GY`04%!?[]_O?^"0<!`@#Y_/X!
+M"0;\_@#X_`D(`@#]_/WY``X&_/__^?P!`0<)__O^_/T"`00*`/C\_OX!`P0%
+M`/G_`_S_!@+___X``/S^!`'_!0+\_O[]`@0"`O_Z_/[^!`H"_?_\^_X""`;\
+M^@#^^0$(!@'\^_[^_`0'`?_]_/P`!`,!``#^^_X$`_\!`OSZ``,"`0$#_/H`
+M`0(#`O_\_OS_!0(!`?WZ``/_``,`^_L"!?_^`P#W_`8#_P$"_/@`!0'^`0+^
+M^_P!!`+_`03\]_\#_P`'`_C\`O[^!0?_^_O^`?\`!`+]_`#__P("`?_]_P']
+M_04$^_\%__K_`_\``@```?S\`@'\!`?]^__^_0$$!`/]^O_^_`(&`P'^^?P"
+M_@`(`_G[`/W^!`0"__S\_@$!`P,`_/P````$!?_\_?W^``,&`OS\`/[[!0<!
+M`/[\_O[_!`G_^0$`_/\#!`/_^?X$_?\&`OW^_OX!`/\$__L``P'_`0``__H!
+M!@#]`0+^_0`$`P#_`/[]`0,!!`+^_OW_`00#`@'[^_[_`P4$`_WY_@("`@4#
+M_?S\_0($`P0!_/W__0$'!/\`_?K_`0(%`_[^__K^!P0``0#]_/W_!@;^_P+^
+M^_\"`@("``#]_`$#`@$#`_W\_``#`P$``__Y_@4"_P,#_?W__@$$`0`"_?H"
+M!/[_!`'^_OX#`_W_`__[`03_`0']`0#\_@8#^@$"_/X"!````/[__0`#`P#\
+M_O_^_@('`OS^`/[\`08#__[]_/\"`P,"_OW]_?\&!O[\`/WY_PD&`/__^_C^
+M!`<%__[\^?H`"`@#_?W]]_P%!@0#`/?Y__X#!P0!_?KZ_P("!`+^_?K]`@(!
+M!`/Z^P/^_`(%`?[\_0/_^P,(`?G^`_[[_P<$^_X#__G\!`3__@$"_/H`!@']
+M`@+\^0`$__\$`_W[`````@$!`/O\``#_`@3]_/\``/\#!?_W_03__@,$__W^
+M_0(#_@0#_/O_`OP`!00!^P`"_OX!`O____\"`/\```#_!`/\``+\^P$%`O\!
+M`OOZ`00%`0``_?GZ!@D!_?\!^OD""0C[^P+[]@`+!P'^^?W_^0$0"/;[`OGX
+M!0D'!/OX__WZ!@P#_?[]^OT"!@<`_`#_^_\(!?W_`?[]``0!`/[^`@#]`PC\
+M]@,$^_\&!O[[_`$$^P$*`_?Z!0#[_P8(_/D`!/[Y!0?__OX"__W^`P;\_@,`
+M_?T#`@````/]^@$#`/\$`_W^_?\#`0$$`OK[`P']!`8!^_K_`@#^!@;Z^``"
+M_O\'!?[X^P,!_@,*`O/Z`P#[!`P`^OK_`OW_"`OZ\@,"^/T'"?W[_0$`]P(+
+M`OC]!OWZ_P0&_OP!`__Y`0/__P$$^_P!_OX`!`']__T``/T#!O[X_@/^_@($
+M!?OV`0;[_`D%^OK\_P/__@@&]/<%`?P`!P3\]OP'`/H&!_SW_0`!`_P!!?GY
+M`@/\`@;[_0#^```"`0#[^P8`_@(!__O^_P,#^P$"^_H""/_^`/[\^0$$`@+^
+M_OW^_0(*__L`_?K_!`(#`?G\`/P!!P/^`/OY`P+_!@3X^`#]_@@&___[]_X$
+M`@4'_OCZ_/X$"`,`_OG[_@$$!@/Z_?_Y_@<'_P`"^_S_`08#_/P$_O<%"/[\
+M`0#]`OT!"/OY!`3Y_@?^_@$```'__0+^^P4#_O\"__H``0,$_@$#^O<""?[_
+M!@'Z^O\$`P+_!`'W^P,&`O\#`/W[_P@"_@(`^_H$`@`&`?O]`/S_"@/]`__Y
+M_@8```?]^O_^_P,$_P(!^?\"_0(&__L#_?@&!OT!!OSX!/[]!P/]_P/[_`4`
+M`@4`_?X!_0`"_P4!^P`$_?H$!/X``/\`__T`!?_\`P+]_`,#_?X"`__\``$`
+M__X#`O[_``#]`0(``?[_`?[_`@+\``7\_@0`_0`"_P+^^@8#^?\&`/D````$
+M_?X%`/?_!_W_!?_^__W\!0/\!`'\_@#]_PD!^@(`^_P!!`("^OP$_?H""O_X
+M`0#]_P`#!/[X``;Z_`<#_/W^_0,`^@4&^/L%`/T$`/L"__D!!O[^`_S\`O[_
+M!0+[_O_]`@'_!0/Y^P,!_`,#`/[[_@(#```$`/S[_P0`_P$!_OP```("_@``
+M_O[_`@+__`$#_/X%`/P`__T#`_T"`OG\!/__!0+\_OS\!`(`!@/W^P/\_@@&
+M_O[^^?\"_P8(_?C_`/L`"`4`_?S\_P`"!P/\_@#]_`0$_0(!_/\!_@`%_OL%
+M`/D!!O[]!/_^`OX``P'\`@3[_P+_``'__P7_^@0"_`$%`/X$_?L#`?X#!O[\
+M`O_^`@("`O_]_P'_`P+^`0'\_00#_P(`_0``^P()__H#`OO\!`4!__X#__C_
+M!P3\_P+^_OT`"`/[_P3]]P,&_@$$`/S__P`%`OX#`/O]`P'_`P+__OW_`P'_
+M!0/Z^P,!_0,%`/_]_0(#_@`(`/?^!`#\`P8`_OL``__]`@?]^`($__X!`O_^
+M_@$%_OX$`/G_!0$``__^`/S_!0'^`P'Y_0/^``4`_@'\_`,!_@0$^OP"`0$!
+M``$!^?L&`OP"`OW^_OX$!OS\!?[W``4"``#____[`07__0``_O\!`@+^_`$"
+M_/X%`OG^`_W\!@3[`0+[_`("`03\^P0`^0$)`?G_`0#__`4(^O@#`_D`"0']
+M_OO^`O__"07W_`/]^@0'`/[^_?S]`P4#_O[__?W_!`/___X`_?P#`P']``3Y
+M_`0"_P`#____^P`#`/\"`OO^`/X!`0("___^__[_!`$!`?[]``#^`@/__@#^
+M_`,#``(`_OW^_P`%`?\`_/\```(%`_O]`OW^!`0``/_[``+^`0<!^OX`_``$
+M`@,!_/T!__T&!/S_`/O^`P(`!0#[`0#]`@7__P/\^@("_P0$_@'_^/\&`?X%
+M!OK\`/\$`0`#`OSY`P/^`P0!__[\``0```0`_/T!_@($``$`_OW_`P$#`?T!
+M`/S]!`;^_P'__?T!`P/_``+^_/\"`P`!``(`^?X%`O\!!/[]`/X!`P$!`0#]
+M_P#_`P/_``#^_@(!`0+__`$!_/\'`?P``?__`0`#`_K]`P#\`0;__0#__P``
+M`@/_^P(!^P$#`/\!_OT$__T&`OK^`_W[!@+]`@#\_P+_`03^_@+^_0$"_@$`
+M_`(!_``%`/H!`?S_`0$!__S_`___!`+]_?_^`0$``_[[_P'__P8#^OX`__\`
+M`P'__/T#__X#!/[[`0'^_P(#_OS_`@#^`P3^_/\"_P`#`/_\^P`#```&`?G_
+M`_W^!`+^_?W_`@#_!0/Z^P'_``,```#]^P$$_P$#_?S__OX#!?[^`/W\_P(!
+M`@#\_@#^_P0$_P#^_``!_P`$`?L!__T"`0`!`?W]`_[]`@$``0#^``#\`0,`
+M``(`_``!_P(!````_?T#`?\!`?_]_P`"`O\!`/[]``,!`0#_`/W_`P0`_@/_
+M^0`$`?\"`O[^_0`&`?T"`OS\`P(!`?X``?W^!P+[`P3Z_`4"_P(!_@#^_00$
+M_0`$__L`!`$`_P$"_OT"!/_^`@'^`0,`_P#^_P`!`0("_/T"__\$`_S^`OW_
+M!`+_`?_[`@3_`@+__O__`03__P/^_0$#`/\!__\!_@$$`?S_!/_]`P3__?__
+M_P`"!@']_0#^_`0(`OW]`/[]``8'_?H!__L`!P,`__W^_O\"!0#]`?[Z`00"
+M_OX!__W\`P;]_0,!^_X$`0`!_____?\$`OX``OW]`@'_`/_^_P`!`@'^_O_]
+M_P0#_O__^_P"`P,#`/S]_?P%!_[_`OOY``,!`P+\_?_\``0#``#^^O\"``("
+M__S[_@$$`@`#_OG]`P,``@']_/S^`P4`_P']^OT#`@(#__[]_0`"!`$`__[^
+M_0$%`?X``?S]`@`!`0#^_@#^_P(``````/___O\!``$```#]_``#__\$`_OZ
+M`0#_`@("`/W[_P3^_P4!_/T`_P`#``$`^OX"_P`$`OT``/P"!0```O[\`@#^
+M!03\_`(`_`($`@']_0`!_?\%`O[]``$`__\$`?O_!`#[``/^``$``0``_P(`
+M_0,"_OX"`?P``P$`_@$#_OP`!?_]`P+__@`!`0#_`@#[``0!_0(#_?X``@+_
+M_@`!_/X%`___`?_^_P$$`?T``?_^`0,``0#^`/\``0("_0$"_/X"`?\``_\`
+M`?X``O__`P'^`0#_`?__`@+\_P3__0$"_@`"_@`"_?X#`?T"`OS_`__^`@'^
+M`0#_`__\`@/]_00`^@(!_@$`_P$"_/X%_OT%`OS_`OW^`O\``O[^`?_]`P+]
+M``+^_``!``+_``'^_0$#__\#_OW_`````@``__P!`?__`@'[_P'^_P`"`/_^
+M_@(`_@(!_?X!__X"`/\!_OX"`/L!`_S^!/_\`0']``'_`?_]``+]_@,!_O_^
+M``'^_@$"_?X"__X``O[^`@#^`0'__P'^_0(`_P("_O\"_?X"_P`!_O\!_OP$
+M!/L`!/[\`0#^`O_]`@']_P/__0'_`0+_``'__0`!_`(#_?T!`OW_`@$`_O\`
+M`/_^`P']``(`_0$"_P#^``+__0($_/X$__P!`?X``?\"`?P``OW^!`'^`P'\
+M``#]`@+^`03\^P(`_@(#__\`_``"_@$#`/X``/T!`?\"`O[^`0#^`0$!`@#^
+M_P(`_@("__\``/\!`0$"```!`/X``@```?__``#_`@(``@#\_P'__@,"_@#_
+M_P`!`0`"`/[_`````0$`__X!`O__`@'^``'^`0'_``$`_@("_@(!_O\!`?\`
+M```"__X#`/[_`@$``@```/[_`@#_`0+__0``_@$"``$!_____P`#`?T!`OW]
+M`0+_`0'_`?[]`0+__P+__@'__P(`_@$!^_\#_O\"`/X``/T``O\!`/[_`/__
+M`@```OW^`O_\``3__@'__O\``0'__@$`_O\!`O_^_P$!_``#`/W_`_[]`@'_
+M_0$!_@#_`0'^_P$`_?\#`/W_`@#^``("_?P"`OW^`@+]_@```/\``0#^_@'_
+M_@`!`/\``/__``'__P$`____`/___P$!____``#_``("_OX!__X``0$`_OX`
+M`/X``P'^_@``_?X"!/[]`0#]_P(!``#^`/_^``(`_P``_O__`0+_``(`_``#
+M_OX"`O[^````__\"`?__``#^```!`?X``?__`0/__P'__O\``0$!`/___P``
+M`@(`_@#__0`"`0$``/_^_P`#`0```/_]``(!`0$!__X```$`_P(`_O\!`/\!
+M`0#_```!`/\"`O[_`@'_``$!`/_^`0'_``(`_@`!_P`!`0#__P``_P`!``#_
+M_P$`_P`"`/X!`?__`0$``/\``?X``P#_`0'^_P$``0'^``'__@(#_OX!`/\`
+M`0$!__X!`?\``@$`____```!`0'__@`````"`0``_OX!`?\``__^`/\``0``
+M``+__@``__X``0``````____``'_``$`__[_`0'__P$`_0`!_P`!__X`__X!
+M`O\``/__``#_`0'^_@```/\!`O_^_P``_@`!`?_^`/__`/\``0#]``+^_0$!
+M_@`!_@``_?\"`/T``O_^`/\``/\``?_^``#^``'^_P'__O\!`/\`__\`__\`
+M`?[^`P#]``$`_@``_P#^``+^_@$!_@`!_O\`_P`!__\`_OX!`0```?____\!
+M`/X!`?[^`0#_`0#_`/[_`0#^``+__@``````_P``_@`"```!`/__`?[_`O__
+M`0#^``'^_P+__P+__0$!_@`"_P`"__\!__X"`O\``O[_`?[_`@#_`0#]``'_
+M`0'__P````````+__0$`_P`!`/\!_O\!_P`"`/X``?\``0`"`/W_`O_]`@+_
+M_P'__P$```(!_P`!_O\!```!`?__`/\``?\!`O__`0']``/_``$`_P``_P("
+M_?\!__\!`0``__\!__\!`?\``?__`?\``O__`0#_``#_`````0'_``']_P(`
+M_P$!_@``_P$!_P`!__T``?\```$`_@```0#_`0#_````_P``_P`````!`/X`
+M`/\!`?\``?[_`0#_``'____^`0'^_P#__@`!_P$`_O__```!`?___O\`````
+M`0#__O\!`/\!`/____\!`?__`/__`0```/[^`/__`0'_____``#_``#__@``
+M____``#^_P'_``'__@`!_P`!_O___O\!`?\``/W_```!`0#___[_`0#_`0#^
+M_@$`_@$!__X``/\````!`/[_`?_^`0'^_P$```#^``#_``(`_@$`_``"`/\`
+M`/___@`#`/\!`/W]``$!`/\`__W_`0$```#___\``0#_`/_^_P$!`0#__O\`
+M``$!`/___P`!`0````#_``$`_____P#_``(`_O___P$!``$!_OT!`?\!`?__
+M__X``@```@#]_P```0$```#__P````$`_P`!`/\!`0`````!`/\``?\`````
+M``````#_`0'_`/_^```!`0``_P#__P$!``#_____`0$!`/____\```$``/__
+M``````#__P#_``(!______\!`0$`__\`_P`!`0#_`/__`0$`__\``````0'_
+M_@#__P`!`/___O\```$!`/_^_@`!`0$`_O___@`!````__\````!`/[___X`
+M`0```?_^`````/\``/__``'__P```/\``@#^_P```````/_^``````$`_O__
+M__\``0#^_O__`````/__``````$`_O\``/\``0#^_O\"`?\``/[]`````0#_
+M___^``$```'^_0``_P$!__[^_@`!````__[_``$`````__\```````#__P#_
+M_P```/__````__\``/__``#______P`!`/______``$``/[_`````0'__P#_
+M_P````#__P``_P`!_P`!__X``/\``/\``/\``?__``#__P```/__``#_````
+M_P``_P`!`/__`````````/__``#_``$`____`````0'__P````````#__P``
+M```!`/\`_P`!```!__X``/\``0```/\``0$```#__P#_````````````_P``
+M`/\!`?__`````````?_^``#_```!`0#^``#_``$``/\```#_``'__P$!__\`
+M`/__`0$`__\``/\!`0``_____P```0```/__``$`_P``__X``0#_``#_```!
+M`0#_____``````#__P```0#__P#__P`!`/__``#^``(`_O\`_P``````_O\`
+M_O\!`?__``#__P$"__X``?[_`0#__P``_P```/__``#__P```/[_`0#^``'_
+M_O\``/__``#^_P``_P$`__\`____``#__O\`__\!`0#^_P``_P`!__X`__\`
+M`0#_`/\``/X``?_^``$`````____``'__P'__P``__\``/_^````__\``/__
+M``$`__\`_P``````__\`__\`````____`/\``0#_____``````#__O__```!
+M`/______``$`________`0$`__\`__\``````/\``/\``/\``/__````````
+M`/__``#__P````#__P#_````_P#__P````#__P#__P`!__\`````_P`!__\`
+M`/\``?__```````!`/__`?__`0'___\``/__`0'__P``_P```0#^``$`_P``
+M_P````#_``$`__\!`/\```#__P``_P```/\`_P`````!__\``/\``0#_`/__
+M`0```0#_``#_``````#^_P``````_____P`!`/\```#__P$``/\`````_P``
+M__\``/\`__\```#__P``__\``/__`/___P```````/\`````_P``__\``?__
+M``#__P````#__P``_P`!_____P#_````______\```#__P#__P`!`?__``#_
+M_@`!__[_`/__``$`_OX!`/X``?_^__\``/\!`?[^_P#__P(`_O__``#_`0(`
+M_O\`__\``0#_______\``?__``#^_P$`__\``/__````_O\!`/[_``#__P``
+M`/__``#_``#__P$`_@`!__[_````````__[_`0#_`0#^__\```````#^_P$`
+M_P`!__X`````__\`__X``0``_____P```0$`__\`_P`!`0#___\````!`?_^
+M____`0$`_____P```0'__@``_O\"`?_^``#__P`!`/[_``#_`0'__@``__\!
+M`/___P`!__\"`?[_`0#_`````/__`0#_``#__P$`__\``/\``0$`__\``/\`
+M`@#__P#__P````#__P``_P`!__\``/\`````__\``/\``?_^```````!`/__
+M``#_`````/__`````0'_____`0#_``#__P``_P``_____P$!__\!`/[_`0$`
+M__\`__\``0#_``#__P````#_`/__``$`______[_`0'__P``__\``0#__P'_
+M_P``_P``_P#__P``__\!__\```#__P```/\``/__`````/__`/__``#_`/__
+M__\```#_`/___P#_``#__P#__P``______\`_P``_O\``/\``0#___\`_P`!
+M`/[^``#_``$`__[_`/__`0'^_O\``````0#]_@```````/_^_P$```$`_O\`
+M_P````#__O\!`/\``/___P```/\``/__`/\``/____\``0#_`/____\```#_
+M``#_````````_____P````#__P``_P````#__P``__\``/\`_P``__\`__\`
+M`/\`__\``/\``?__`/\``````0#_``#_``````````#_````_P````#_````
+M_P```/\`_P#__P``__\```````#__P```/\!`?__``#_`````/__``````#_
+M_P#_``````#__P#__P``_____P#__P$`__\``/\`````_P``_P```/__`/__
+M`/\``/__`/__`````/\``/__``#__P#___\```#__P``_P#_````_P#__P``
+M_P``_P``__\`__\``/\``/\`__\``/__`/__`````/__``#_``#_``#_````
+M`/__``#__P````#_``#__P``_P``__\`__\`__\``/\`__\``/\`__\``/\`
+M`/\``/__`/\```#_`/___P````#_____``'______P````#__P``_P`!`/\`
+M_P``_P```/____\`__\`____`/\```#______P```/__`/__``#_____``#_
+M````____``#__P#__P``__\`_____P``_P```/\```#__P``_P```/___P`!
+M```!`/[_`/\``0#_____`/\``0#__P#_`/\``/__``#__P$`_P``_P``````
+M_P``````__\`_P``````__\``0```/____\``/\``/__`````/__``#_``#_
+M``#__P``_P``__\`_P````#__P```/__``#__P`!`/\``/___P```/\``/__
+M````_P```/\```#_``#__P#__P``_P#_````_P``_P```/__``#__P``__\`
+M`/\``````````/\```#__P``_P```/\``/\```#__P``_P``_____P``__\`
+M`/__``#_``#_``#_``#__P``__\`````_P#__P```/\`_P``__\``/\```#_
+M`/\`__\``/\``/\``/\```#_`/___P#_``#_____````_P#__P``_P``__\`
+M__\``````/__``#_``#_`/__`/\``/\``/__`````/__`/___P``__\`````
+M``#_``#_````_P#__P#__P#_``#__P``__\``/___P``____`/___P``__\`
+M`/___P#_`/\``/__`/__`/__`/___P``````_P#__P```/\`____``````#_
+M_P#_`/\``/\`__\`````````_P``````____``````#_`````````/__``#_
+M_P```/__````_P``____``#__P#__P```````/___P``_P``____`/\```#_
+M__\``/\`_P``_P#_`````/__``#_````_P#__P``````__\`````_P#__P``
+M_P``_P``__\``/\``/__``#_````_P``__\```#_``#__P````#__P``_P``
+M`/\`__\``/__`/\``/\``/\``/\``````/__``#_``#_``#__P````#___\`
+M_P``````__\`__\``/______`````/__`/\```#__P#__P``````_____P``
+M````____````_P``____`/\`_P#______P#__P#__P```/__``#_____````
+M_P``_P#__P``_P``__\``/__`/___P#_``#_`/__`````/__``#_````_P#_
+M__\`_P```/__`/\```#__P````#_````_P``__\`__\`_P``_P``__\``/\`
+M`/__`````````/__``#__P#__P````#_````_P```/__``#__P````#__P#_
+M_P``__\`__\``````/\`__\```````#_``````````#_``````#__P``_P``
+M````__\```````#__P#_`````/\``/\```````#_`/\```#_``#__P```/__
+M``#_````_P``_P``````__\``/\```#_``#_````````__\`````````_P#_
+M````````_P```````/__````````````_P```````/\`_P````````#__P``
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````$-/34T````2``$``$(6``A`#:Q$````````
+M34%22P````(``$E.4U0````4/```?P!_``````````````````!!4%!,```!
+MJ%-D,F$``@``````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````"D```````````````````
+M````````````````````````````````````````````````````````````
+M``0(```````)`",`````````````````>`````0`!````````/P`____@```
+M``$!``9156YI=',````````````````````````````````````````!`@`&
+M('-A;7!S````````````````````````````````````````````````````
+M````````````)P`O``__]O_Y``$`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````!`````7@```!X````5@``````
+M````````````````````````````````````!$)E;&R!`@```$%)1D939#)A
+M`````````````!*L`````$%)1D939#)A````````````````````````````
+M````ISVMY```1"(```'.``````````````````(E`/____X!,0``````````
+M``````````````````````````````````$`````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````!H`*0`/`FH#,0`J``,";0,]`"D`#P)!`R(!`````!H`
+M*0`/`5`!\0`J``,";0,]`````````````````!H`+``6`3X!W``J``,";0,]
+M`````````````````!H``````````````````````````````````````0``
+M``%X````>````%8`<;B\'*8````<`%8``%=S=&$``P`*``'__P``````````
+M``+__P```!X```````/__P```#P```````3__P```%H`````````````````
+I````````````````````````````````````````````````````````
+`
+end
diff --git a/sys/share/sounds/bugle.uu b/sys/share/sounds/bugle.uu
new file mode 100644 (file)
index 0000000..57a1fa2
--- /dev/null
@@ -0,0 +1,328 @@
+begin 644 Bugle
+M``5"=6=L90``````````````````````````````````````````````````
+M``````````````````````````!!249&4V0R80$``!H`10```````#8B```!
+MSJ<]K=:G/:W>``````````````````````````````"!@7%5``!&3U)-```V
+M&D%)1D934TY$```T'@``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````/____\```$"`@("`@("`@("`0("`0```/_^_O\```$"`@,#`P0$!@D-
+M#Q`0"P/Y[>+<V]O=XNKS_`$$!`,`_?OZ^?CX^?S_`0(!```!`0#_____``$#
+M!`,"`0$!`@("`@("`P,"`0#__O[]_?W^``($!@@*#A08&AH9%1`+!/OPX]?2
+MTM??Z/'X_/WY\>GCX>+G\/?\``(#!0<'!00$!`,"```!`P8'!P8%!`,#!0<(
+M!P8%!`(!`0#__O[^_O\``@,$!PH,#`L+#`\2%1@:&1<5$Q`,!/CHU+^TM+6Y
+MQ=/C\OP!`/W[^OCV]OC[``4+#`H&!`(``````@0%!PD*"@H)"`8$`P,#`P("
+M`0$!______\!`P4'"0L-#@X,"PH*#1$5&AT?("(>$?[CR+.HIZRUO\?.U=SF
+M\?C\_OW[^??Y`@T4%A0/"08&!@<)"@D(!P4%!P@(!@0#`@("!`8("`8%!`,"
+M`0$!`@,$!08'!P<("@P.#A`3&2`F*"@E'Q'[X<BTJ:6DI*NXQL_9Y_;\_?X"
+M`P'_`0D2%Q4/"PL*"`<&!@<(!@0$!@@)"`<'!@4#!`<*#`L*"`8#`/WZ^OS^
+M`0,%"`H+"PH*"@L-#A`3%QPA)RLI&@'DR;.BEXZ,F*N_U_$$#!`0#@D"_/P"
+M#!07$@X+!P'_``("`0$``08*#@\.#`D'!0(#!@@'!P<'!00"__W]_/S]_P,'
+M"@P,"PH)"`@+$1<=(R<L+B@5^MFUFHZ.E**UQ]GO`PL,"@<%`OOV^``,%1<4
+M#PH$_?W_`0("`P0(#`X.#@X,"04!``$%!P@)"0@%`OWY^/?X^?P!!0D+#`P+
+M"@@("0P2&B$G+C(N(@ONS[.>C("%F;37^0\9%PP!_/OX]?;]!@X1$`\,!P/_
+M_P``_OW_!`L0$A(0#0D&!`,#!0@)"`<&!`+^^OCW]O;Y_P4+#Q$1$`P)!P8'
+M"Q$7&R(I+"85_=_"J)2*CZ"ZV?@.%Q8-`OKV]/'Q^`(+$144$`L$__W]_?S]
+M``4*#A(4%1,/"@8"``$$!P@("`<%`O[[]_7T]OL`!0D-$!$/#`D'!PH/%!HA
+M)RHH'@OPU;VGD(*(H\?M"AD<$P?\]_7S\?/[!`L.$`\-"P<"__[^_?X"!PP0
+M$Q46$PX)!0$``00&!P<'!@,`^_CV]/3W_`((#1`1$`X*"`<)#1(8'2(F)!L)
+M\=C`JY>,E;#0[P<6&!`$^_;T\>_R^@,+#Q$2$0X)`P``__W^`08,$!06%A0/
+M"@8"```"!`8&!@4#`/WY]O3S]?H`!@P1$Q,1#@P+"PX1%1H>(1\7!_#4NJRH
+MIZ>NPN']$!81!OWX]O3R\O@"#105$@P(!00#`@#^_P$&"P\3%A@7$PP&`?[_
+M`@0%!04$`P'^^_CW]_CZ_P0*#A$1$`X+"0D+#Q,8'2`A&PWXX<NUH921GK[F
+M!1@=%@H`^O?T\O3Y``<-$1(1$`X*!@/__/S_!0H/$Q87%A,."04!```"`@(#
+M!`4#`?[Z]_;W^O\$"0X1$A(/#0L*"PP0%AL>'QL/^^/+MJ:;E9VZX0(6'!@.
+M!?WY]?/S^``(#A$1#PT-#`H&`O_]_@,(#1$5%A83#@D%`@$"`@("`P0$`P'^
+M^O?U]??\`PH.$1,2#PT,#`T/$109'1\;#OKCRK2GGIB@NMX`%AX:$`;_^_?U
+M]/?^!@P/#P\.#@T+!P+^^_P!!@L/$Q87%`\*!@,"`P,"`@("`@(!__SY]_?Y
+M_0$'#1`2$@\,"PL-#Q(6&QX?'!'_Z=&[J)B,E+?B`Q@?&0\'`?WY]O;Y_P8*
+M#0T-#@\."P<!_?S]``4*#A(4%!(."@<%`P(!`````@,#`@#]^OCW^/L!!PL.
+M$`\.#`L,#0X0$Q49&Q@/`.S6P*Z?E9R\Y`49'QD/!O_Z^/7U^/\&"@P,#`T.
+M#0H&`?W\_0$%"0T1$Q,2#@H'!0,"`/__``$"`@'__/KW]_G\`0<,#A`/#@P*
+M"0L-$1,5&!D6#@#MU\*QHI>?O^8'&AX8#@8`_?KW]?C^!`D,#0T-#@T*!0'^
+M_?X`!`@,$!(3$0X*!P4#`@$````!`@(!__W[^?GY_`$'"PX.#@T+"0D*#1$5
+M%QD9%P\![MG$LJ&5G\#H"1H=%PX&`/SX]O;Y_P4*#0T-#0X-"@4!_?O\_P0(
+M#!`3$Q$."@<%`P$`__\``0(#`@#^^_GX^?P!!@H-#@T,"PD)"@P/$Q87&!</
+M`O'<Q[*?EJ3([PT;'18-!@#\^?CX^OX#!PH+#`T/#@H%`/W\_0`$"`L/$1(0
+M#0H'!0,!`/__``("`@(`_?OY^/G\`@8*#`T-"PH)"`D,#Q,6%Q<5#P3SWLFS
+MG9.FS_<1&QH3"P7_^_KY^OS_`P<)"@P.#PX)`_[\_/T`!`@,#Q$1#PT*"`8#
+M`/[^_P`"`P,!`/WZ^/?Y_`$&"@L,#`L)"`@)"PT1%!86%`\$]>'*LIV6K-;[
+M$1L9$@L%__OY^?G[_@$%"`H,#@\."03_^_K\``,&"@X1$0\-"@@&`P#^_?X`
+M`0("`@#]^OCW^?P!!@D+#`P+"0@("0H-$!,4%10/!/3@R;"<F;+=`!0:%Q`*
+M!/[[^OKZ_/X!!`<)"PX0#@D$__S\_0`#!@H.$1$/#0L)!@,`_O[^``$!`@'_
+M_?KX^/G]`@8*#`P,"PD("`D+#A$3%142#`'QW,6MFYV\Y@46&A0."`+]^_KZ
+M^_S^`00&"`L.$`X)!/_]_?X``P8*#A$0#@T+"0<#__W]_O\``0$!__SZ^/CY
+M_0(&"0L+"PH)"0D*#`\1$A04$PP`[MC`J)BAQ_`+%Q@3#0<!_?O[^_S]_P$#
+M!@@+#Q`."00`_O[_``,'"PX0#PX-#`H'`P#^_O[_``$!`?_]^OCY^_X#!PD*
+M"PL*"0D)"@P/$1,4$Q`(^^C2NJ.7K-?[$1D6#PH%__OZ^_S]_O\!`P4'"PX/
+M#0@#`/__``$#!PL.#P\-#`P*!P,`_O[^__\```#__?KX^?L`!`<)"@H*"0@(
+M"0P.$!$2$A$.!??ESK6>F;?C`Q08%`T(`_WZ^_S]_O\``0($!@H-#@P(`P$`
+M```!!`@,#0X-#`P+"08#`/_^_O__````__SZ^?K]`04'"`D*"0D("`H,#Q(2
+M$1$/"O_OV<*JF:;/]@T8%Q`*!0#\^OO\_O\```$"!`<+#0P*!@,"`0$!`@4)
+M#`T-#`P,"PD&`@#__O[^_O[___W[^?G\``0&"`D)"0D("`D+#A$2$A$/#`7Y
+MZ-*ZI)RUWP`2&!0-!P+]^OO\_@````$!`@,&"@P*!P4#`P,#`@,&"@P-#`P,
+M#`L)!0(`__[^_O[^_O[]^OG[_@(&!P@("`@("`@*#`\1$A(2$`L"]-_'K)BA
+MR?$+&!@1"@4`^_K\_O\!`0$!`0(%"`H+"08$`P,#`P,%"`L,#`L+#`L*!P0"
+M`/_______O[]_/GY_``$!P@)"0@("`@)"@T/$!$1$0T'^^K3NJ.=M^$!%!D3
+M#`8!_?KZ_/\!`@("`0$"!0@*"0<%!`0$!`,$!@D,#`P+"PP+"08$`@'____^
+M_?W]_/KY^OX#!P@)"0@(!P<("0P/$1$2$0\*`/'=Q:R:IL[U#AD7#P@#_OKY
+M^_T!`P,"`@$!`@4'"`<%!`0%!00$!0@+#0P+"PL+"PD&!`,!___^_?W\^_KY
+M^?P!!0@)"@D(!P<'"`H-$!$2$0\+!/KIU+F=F+CE!A<:$PL%__KX^?S_`@0$
+M`P$!`0,%!P8%!`0$!04$!`8)#`P*"@L+"PH'!00#`?_^_OW]_/OY^?K_`P<)
+M"@H)!P<'!@@*#A`1$!`."/_QW<6GE:O:_A0;%@T'`?SY^/K]`00%!`(!`0($
+M!@8$`P,$!04%!08("@L*"0H+"PH(!@4$`@#^_OW\_/OY^/G\`04("@L*"`<&
+M!@<)#1`1$`\-"@/WYM&TFJ'*\PX;&1`)`_SX]_G[_P,&!@,!`0$#!04$`P,$
+M!08&!@8'"0L+"@D*"PL)!P8&!0,`_O[]_/OY]_C[``0'"0L+"0<&!@8("PX0
+M$!`."P;\[-:YGI_"[`D8&A(*!/WX]OCZ_@(%!@0"`0(#!`0#`@("!`8&!@8&
+M"`H+"@D*"@H)!P4%!@4!__[]_/OY^/CZ_@(&"`H+"PD'!@8'"@X0$1$/#`?_
+M\-S!I9RWX0(6&Q4-!O_Y]O?Y_``$!@8$`@("`P,"`0$"!`8'!P<&"`H+"PH)
+M"@H)"`<&!P<$`?[]_/OY]_;Y_0$%!PD+"PD'!@8&"0P0$1`/#`@"]^3+JI:I
+MUOL2'!@/"`'Z]O;X^_\#!08%`P("`@,"`0`!`P4'!P<&!PD+"@D)"0D)"`<&
+M!P@&`P#__?OY]_;W^P`$!@@+#`L(!P8%!PL.$!$0#@D"^>G4M9F@RO,.'!L3
+M"P3\]O7W^OX"!0<&!`(!`0("```!`@4'!P<&!PD*"PH("`D("`<&!PD(!0'_
+M_?SZ^/;W^O\#!0<*#`P*"`8&!PH-#P\/#@H#^^W:OZ*;O.D)&AT6#0;]]_3V
+M^?T!!0<(!@0"`0$!`/__`@0'"`<'!P@*"PH)"0D(!P8&!PD*!P,`_OW[^/;U
+M^/T!!0<)#`P*"`8%!@D,#@\0#PP&__/BRJN8K=L`%AX9#P@!^?3U^/S_!`<(
+M!P4#`0$!`/__`0,%!P<'!P@*#`L)"0@(!P8%!@D+"@8!__[\^O;T]OL`!`8(
+M"@P,"PD'!@<+#0\0#@P(`/7DSK"7I-'[$QX<$PH#^O3S]OK^`@8("`8$`@$!
+M`/[^``(%!P<'!P@*#`P*"`@(!@4%!0@+"P<#`/[]^O?T]?G^`@4'"@P-#`H(
+M!@8)#`X/#PT)`_GKU[R@G+_M"QL>%0P%_?7R]/C]`04("0@%`@```/_^_P$$
+M!@<'!P<)"PP+"0@(!P8$!`<+#`H$`/_^_/GU]/?\`00&"0L,#`L)"`<)#`X/
+M#PX*!/OMV;ZAF+;F"1L?&`\(__?S\_?[``0("0D&`P$``/_^_@`$!@<'!P<(
+M"PP+"0@(!P4$!`4)#`L&`O_^_/KV]/;[``,%"`H,#`L)"`<("@X0#PX*!?[R
+MX<JMFJG5_!4?&Q(*`OGS\O7Z_P,'"0D'!0(``/_^_@`#!@@(!P<("PT,"@@(
+M!P8%!`4)#`P)!`#__?KW]?7Y_@(%!PH,#`L*"0@("@T/$`\,"`'WY<ZPEIW*
+M]Q(?'A4,!?SU\_3X_0(&"`D(!@,!`/_^_O\"!0<'!P<("0P,"@@("`8%!`0'
+M"PT*!0'__OSY]O7X_0$$!@D+"PL*"0<'"0T/$`\-"`'XZM:^I)Z[Z`D;'A@/
+M!__V\O/V^P`%"`H)!P0!`/_^_O\!!`8'!P<'"0P-"PD("`<%`P,&"@T,!P,`
+M__WZ]_7W_``#!0@*"PL*"@D("@P/$1`."@/Z[-C`IIJQX`4:(!H1"0'X\_/U
+M^?X#!PH*"`4"`/_^_?X``P8'!P8'"0L-#`H("`<%`P,%"0T-"`,`_OW[^/;V
+M^_\"!`8)"PL*"0D("0L.$!$0#`7]\-[(KIJES_H4'QT4"P3[]?+T^/T!!@D*
+M"08#`0#__?X``@4'!P8'"`H,#`H(!P<&!00$!PP-"@4!__[\^?;W^OX"!`8(
+M"@H*"@D)"0L.$1$0#0@`]>3.M9R<PO$/'A\6#@?^]O+S]_L`!0D+"0<#`0#_
+M_OW_`@0'!P8&!PH,#`L)"`<&!00$!@H-"P8"`/[]^O?V^/T!`P4("@L*"0D)
+M"0H-$!$0#PL$^NO6O*&6LN(''"$9$`D`^//S]OK_`P<*"P@$`@``_OW^``,&
+M!P8&!PD,#0P)!P<&!04$!0D-#0@#`/_]^_?V^/T!`P0'"0L+"@D("0H,$!$1
+M#PL$^^[;Q*F8J=?_%R`<$@H#^O3S]?G]`@8*"PD%`P$`__[^``,%!P<&!P@+
+M#0P*"`<'!@4$!0@,#0H$`/_^_/CV]_L``P4&"`H*"@D)"@H,#Q$1$`T&_O'@
+MRK&;H,CV$A\?%0P%_/7R]/C\``4)"PD'`P$`__W]_P(%!P<&!@@+#0T*"`<&
+M!04$!0@+#`H%`?_^_/GW]_K_`@,%"`H+"@D)"0D+#Q$1$`T(`/3CSK6<F\#O
+M#1T@%PX'__?S\_;Z_@0("@H(!0(``/[]_@$$!P<'!@<)#`T+"0<'!@4$!0<*
+M#`L'`O_^_?KW]_K^`@0%!PD*"@D)"0D+#A`1$`X)`OCIU;RAE[/C!QLA&A`)
+M`?GT\_;Y_@(&"0H(!@,!`/_]_@`#!@<'!@8("PP+"0<'!@4$!08)#`P(`P#^
+M_?OX]OG^`@0%!PD*"@H)"0D*#`X0$`\*`_GLV,"EF*[=`QD@&Q(+`_KT\_7X
+M_0$%"0H)!@,!`/_]_?\"!0@(!P<("@P,"@@'!@4$!`8(#`T*!0'^_?OX]_C]
+M`00%!@@*"@D)"0D*#`X0$`\,!OSOW,6JF*;3_!4@'10,!?SV\_3X_``%"0H*
+M!P0"`/_]_/X"!0@("`<("@P-"P@'!@4$!`4'"PT+!@+__OSY]_C\`0,$!0<)
+M"@D)"0D*#`X0$1`-!_WPWLBNF*',^!,@'A4.!_[V\_3W^_\$"`H*"`4"`/_]
+M_?X!!`<("`<("@P,"@@'!@4$!`4'"PT,"`/__OSY]_?[``,$!0<)"@H)"0D*
+M"PT.$!`."`#SXLRRFIW$\@\?(!8."/_W\_/V^OX"!@D*"`8#`?_]_/T``P8(
+M!P<'"0L,"PD'!@4$!`0&"@T,"`0`_OSZ^/?Z_P,%!08("0D)"0D)"PT/$!`.
+M"@+WY]&VFI>][0T=(!@0"0'X\_/U^?X"!@D*"0<#`?_]_/W_`@8'!P<'"0L,
+M"PD(!P4$`P,%"0P-"@4!_OW[^/?Y_@(%!04'"0D)"0D)"PP.#Q`."0+WZ=6]
+MHINYYPD;(!D0"@+Y]/+T^/T!!0@*"0<$`?_]_/S_`@4'"`<'"`L,#`H(!P8$
+M`P,%"`P-"P8"__W[^/?Y_@,%!08("@H)"0D)"@L-#Q`/#`7Z[-G!I9BPX`4:
+M(1H2"P3Z]/+T^/P!!0@*"0@%`@#^_/S^`@4'"`<'"`L,#`H(!P8$`P,$!PL-
+M#`@#__[\^??X_0$$!04'"0H)"0D)"PP.#P\."P3Y[-O%JYNLV/\6(!P3#0;]
+M]O/S]OL`!`<)"@@%`@#^_/S^`04'"`@'"`H,#0L)!P8$`P,#!@H-#`D$`/[\
+M^??W^P`$!04'"0D)"0D)"@P-#A`/#`?]\-_)K9BDT/H4(!T4#@?^]O+R]?K_
+M`P<)"@@&`P#^_/O]`00'"`@'"`H,#`L)!P8%`P,#!0H-#0D%`?_]^O?W^@`#
+M!04'"`D)"0D)"@L-#A`0#@C_\^+-LIJ?Q_01'Q\6#PC_]_+R]?G^`@8)"@D'
+M!`'^_/O]``,&"`@'!PD,#0P)!P8%`P("!0D-#0H&`O_]^_CV^?X#!@8&"`D)
+M"`@("0H,#A`1#@D!]N?3N9V8N^L,'2`8$`H"^?3S]?G^`@8("0D'!`'__/O]
+M``,&!P<'!PD+#0P)!P8%`P("!`@,#0L&`O_]^_CV^/T"!08&"`H*"0@("0H,
+M#A`1#PH"^.G6O:*9MN0'&R`9$0L#^O3R]/C]`04("0D(!0+__?O]_P(%!P@'
+M!PD+#0T+"`8%!`,"`P@,#@L'`P#^^_CV]_P"!08&"`D)"0@("`D+#0\1$`P&
+M_.[<Q*:4JMH!&"$<$@P%_/7S]/?\`04'"0D'!`(`_?S\_P(%!P<'!P@*#`T+
+M"`<&!`,"`@8+#0P(!`'__/GV]_P!!`8&!PD)"0@("`D+#0\1$`T&_O+@RJ^9
+MH\[Y$Q\=%`X'_O;S\_;[_P,'"0D(!0(`_OS\_@$$!@<'!P@*#`T+"`<&!`,"
+M`@4*#0P(!`'__?KV]OG_!`8&!PD*"0@("`D*#`\1$0X)`?3CSK*9G,7S$!X?
+M%@X)`/CT\_7Y_P,'"0D(!0,`_OW\_@$$!@<'!P<)#`T,"0<&!`,"`@4)#0T)
+M!0'__?KW]OC^!`8&!P@*"0@("`@*#`X0$`X*`_GJUKR?E[CG"1P@&`\*`OGT
+M\_7Y_@(&"`D(!0,!__W]_@`#!0<'!@<)"PT,"0<&!00#`@0(#`T*!@(`_OOW
+M]?C]`P8&!@@)"0@(!P@)"PX0$`\,!OWPW<2EE*S;`A@@&A$+!?OU\_3X_0$%
+M!PD)!@,!`/[]_?\"!08'!P<("PT-"@<&!0,"`@,(#`T+!P,!__SX]O?\`04&
+M!P@*"@D("`@("@P/$1`-!OWQX,JOFJ;1^A0?'!,-!OWV\_3W_``$!PD)!P0"
+M`/[]_?\"!08'!P8'"@P-"P@&!00#`@,&"PT+!P0!_OSY]O?[``4&!@@*"@D(
+M"`<'"0P/$1`-"`#VY].YGIS![@T>'Q8."/_X]/3W^P`$!@@)!P0"`/_^_?\!
+M`P8'!P<'"0P-"P@&!00#`@(&"@T,"`0!__WZ]_;Y_@,&!@<)"@D)"`@)"@T/
+M$!`."0'VY]&VG9S`ZPH<'Q</"0+Z]?/U^O\#!@@)"`4"`/_^_?\!!`8'!P<'
+M"0L-"P@&!00#`P(%"@T-"04!__W[]_;X_@,&!@<("@H)"`<'"`L.$!`/"P3\
+M[]W%IY:KV@`7(!L1"P3[]?/U^?X"!@@)"`4"`/_^_OX``@4'!P8&"`L-#`D'
+M!@4#`P,$"0T-"@8"`/[[^/;W_`$%!@8("@H)"`<'"`H.$!$0#0?_\M_&IY*E
+MU?X6(!P2#`7]]_3U^/T!!0<)"08#`0#^_?X``@4'!P<'"`H,#`D'!04$`P($
+M"`P."P<#`/[\^?;V^P$%!@<("@H)"0@("`H-#Q`/#0@`]./-LYVCR_40'AT4
+M#`?^]_3U]_P`!`<)"0<$`?_^_?W_`00&!P<&!PD,#0H'!04$`P,$!PL.#`<#
+M`/[\^?;V^@`$!@<("0H)"`<'!@@,#Q$1#PP%^^W8O9Z5M^<(&Q\7#PD"^O7T
+M]_O_`P8("0<$`@#__OW^``,%!P<'!PD+#0L'!04$`P(#!@H-#0D%`?_]^O?V
+M^/T"!08'"`H)"0@'!P@+#A`0#PP%_._;P*.7L^`$&2`9#PH#^_7S]?G^`@4(
+M"0@%`@#__OW^``(%!P<'!P@+#0P(!00#`P,#!0D-#0H%`@#^^_?U]_P!!`8'
+M"0L+"0@&!@<)#1`1$`T(`/7ESK&9H<KV$A\<$PL&_?;S]/C]`04'"0D&`P'_
+M_OW]_P$$!@<'!P@+#0P)!@4$`P,#!`@,#@L'`P#^_/CU]?H``P4&"`H*"0@'
+M!P<)#`\0$`X*!/KKUKF9EK[N#!P>%0T(`/GU]??[_P,'"0D'`P$`__[^_P$$
+M!@<'!P@)#`T*!@4$`P,#!`<+#0P(!`'__?KV]?G^`@4&"`L,"PD(!P<("PX/
+M$`X+!?OMV;^DG+CE!QH?%P\)`OKU]/;Z_P,&"0H(!`$`__[^_@`#!@<'!P<)
+M#`T+!P4$!`,#`P8*#@T)!0'__?GV]?C]`@0&!PH+"@D'!04&"0T0$1`-"`/Y
+MZ=.TEYS)]Q(>'!,+!?WV]/7Y_0$%!PD(!0(`___^_O\!!`8'!@<("PT,"`4$
+M`P("`P4)#0T*!@(`__SX]?;Z``,%!@@*"@D(!P8'"0P/#P\-"@3\[=:XF9?!
+M\0\='A0,!P#X]/3W^P`$!PD(!@(``/_^_O\!!`8'!P<'"@P,"04$`P("`P0(
+M#`T+!P,`_OSX]?7Y_@($!@D+"PH)!P8&!PH-#P\-"@;_\^#'J)BPWP,8'Q@/
+M"0+Z]//V^P`$!PD)!@,!`/___OX``@4'!P8&"`P-"P<%!`,#`P0'"PT,"`0!
+M__WZ]O7W_``#!0<)"PH)!P<&!PD,#@\/#0@#^>G2LI:?SOD3'QL1"@7]]_3V
+M^?X"!0@)!P0"````__X``@0&!P8'"`H-#`@%!`,#`P0%"0T,"04!`/[\^?7V
+M^P`#!`8)"PL*"`<&!@@+#0T-#0L&_N[8NIJ:PO`.'AX4#`<`^/3U^/P`!`<)
+M"`4"````__[_`00'"`<'"`H,#`D&!`,#`P0%"`P-"@8"`/_\^?7U^?X"`P4(
+M"PL*"0@'!P@+#0T-#0L'`//?Q:.5L^0&&A\8#@D"^?3T]_L`!`<)"`4#`0``
+M__[_``,&!P<&!@@+#`H'!00#`P0%"`P.#`<#`/_]^O;U^/T!`P4'"0L*"`<'
+M!@<*#`X.#@P(`_CFS:J3IM;_%A\:$0H#_/;T]OK^`@8("`8$`0``__[^``,%
+M!P<&!@<*#`H'!00#`P0$!@D-#`@$`?_]^_?U]_P``P0%"`H*"0@'!P<)#0X.
+M#0L(`_KKU+:;H,GT$!T<$PP&_O?T]?C]`04("0@%`@``__W]_P$%!P<'!@<*
+M#`P)!00#`@,$!0D,#0H%`@#^_/CV]OK_`0,%"`H+"@@'!@<(#`X.#@T*!O_S
+MW\.BEK?G"!L?%@X(`?GT]/?[_P,'"0@&`P$``/[]_@`$!@<'!@<)"PP)!@0$
+M`P,$!0@,#@L'`P#__?KW]OG^`0,%!PD*"@@'!@8'"@X0$`X+!@'VY<VLEJK9
+M_Q8?&Q$)`_OU\_;Z_@(&"0D'!`$``/_]_@`#!@<'!P<("@P*!P4$`P,#!`8*
+M#@T(!`'__?OW]??\``($!@D+"@D'!@4&"0T/#P\-"@7][]FZFIG"\0X>'A0,
+M!?WW]/7X_0$%"`D(!@(``/_]_?\!!0<'!@8'"@P,"08$`P(#!`4)#0X+!@(`
+M__SX]?;Z_@(#!0@*"PD(!P8&"`L.#PX-"P@!]>'$H9.TY0<:'Q<."`'Y]/3W
+M^_\#!PD)!@,!``#^_?X!`P8'!P<'"0L,"@8$`P,#`P0'#`X+!@(`__WY]O7X
+M_0$#!`<*"PH(!P8&!PH-#P\-"P<"^>G1L)>ET_P4'QL2"@/[]?+U^?X"!@D)
+M!P0!``#__?X``P4'!P8&"`L,"P<%!`,#!`0&"@T,"`,`__W[]_7W^_\"!`8)
+M"@H)!P<&!PD-#@X.#0H'__#:O)R8O^X,'1\5#`7^]_/T^/P!!0@)"`4"````
+M_O[_`00&!P8&!PD,#`D%!`,#`P0&"0P-"@4"`/[\^?;V^?X!`P4("@H)"`<&
+M!@@+#@X.#0L)`_;BQJ.3K^(%&2`9#P@!^O3T]_O_`P<)"0<#`0``__[_`0,&
+M!P<&!P@+#`H&!`0#`P0%!PL-"P8"`/_\^?;U^/T``@0("@L*"0<&!@<+#@\-
+M#`H(!/OJT;"5I-+[$Q\<$0H#^_7S]?K^`@8)"0<$`0``__[^``(%!P<&!@@*
+M#`H'!00#`P0%!PL-#`@#`/_]^_CV]_O_`0,&"0L+"0@'!@<)#`X-#0T+!__P
+MVKZ?F;WL"QT?%@T&__CS]/?\`04("0@&`@``__[^_P($!@<'!@<)#`P)!@0#
+M`P0%!@D,#0H%`0#^_/GW]_K^`0,%"`H*"@D(!P8(#`X.#0T+"`'TX,6EE*_A
+M!1D@&0\(`?KT]/;Z_P0'"0@&!`$``/[]_@$#!@<'!@8("PP)!@4$`P,$!0<+
+M#0L&`@#^_/KW]OC\``($!PH+"@D(!P8'"@T.#@X,"@7ZZ=&QEJ'/^!(@'1(*
+M`_SU\_7Y_@(&"0D'!0$``/_]_@`#!0<'!@8'"@P+!P4$`P,$!0<*#0T(!`#^
+M_?OX]O?[_P$#!@@*"@D(!P8&"0P.#@X."P;^[MB[FYC`[PX?(!8,!O_X\_3X
+M_``%"`D(!@(```#^_O\!!`8'!@8'"0L+"`8%!`,$!08(#`T*!0'__OSY]_?Z
+M_@$#!0@*"PH)"`<&"0T/#@T,"@<!\]["H96VY@<<(1@."`'Y]//V^_\$"`D)
+M!P,!`/_^_?X`!`8'!P8'"`L,"08%!`,#!`4(#`X+!@(`_OSZ]_;Y_0`"!0<)
+M"PH)"`<&!PL.#PX.#`D$^.7+JI2GU_\7(!L1"@/[]?/U^?T"!@D)"`0!`/_^
+M_?T``P4'!P8&"`H+"@<%!`,#!`4&"@X-"`,`__W[^/;X_``"`P8("@H)"`<'
+M"`L.#PX.#`@#^>G0L)6AT/L4(!T3#`7]]?+T^/P!!0@)"`8"``#__?W_`@4'
+M!P<&!PD+"P@%!`,#!`0&"`P-"@0`_OW[^/;W^_\"`P4("@H*"0@'!PD-#@X-
+M#`D$_.[8NIR=Q?$-'A\5#0;_]_+S]_L`!`@)"0<$`?___?S^``,&"`<&!PD+
+M#`D&!00#!`0%!PL-"P8"__[\^??W^OX!`P0'"0H*"0<'!PD,#@X.#@L&`/+=
+MP:&7N.@(&R`8#PD"^?/S]OK^`P<)"0@%`?___?S]``,&"`@'!P@*#`H'!00#
+M`P0$!@H-#0D$`/_]^OCV^?T!`P0&"0H*"0@'!@<*#0\/#PP'`?;DRJ>3K-X"
+M&"$<$0H#^O3R]?G]`@8)"@@&`@#__OS]_P(&"`@'!@@*#`L'!00#`P,$!0D-
+M#@H%`?_]^_?V^/P``@,%"`H*"0@(!P<*#A`/#@L&`OKKU+.8HL_Y$Q\=%`P%
+M_?7R]/C\`04("@D'`P#__OS\_@$$!P@'!P<)"PP)!@4$`P,$!0@,#@L&`O_]
+M_/GV]_K^`0,%!PD)"0D("`@*#0X.#@T*!?WMU;66F\GU$!\>%0T'__?R\_?[
+M``0'"0H(!`'__OS\_@$$!P@'!@8("PP)!P4$`P,#`P8*#@T'`O_^_/GV]OK^
+M`0,$!PD*"0D("`<("PT.#@T*!O[QW+^>F;[L"QT@%P\(`/?R\O7Z_P,'"0H(
+M!@+__OS[_?\#!@@'!@<("PP*!P4$`P,#`P4*#0T)!`#^_?KV]?C^`0,$!PD*
+M"@D("`@)"PX.#@T+!O[QW+Z=E[OJ"AP@&!`*`OGS\O3Y_@(&"`H)!@(`_OS[
+M_/X"!@@(!P<("@L*"`8%!`,#`P4)#0X*!0'^_?OW]?C]`0,$!@D*"@D)"`@(
+M"@P-#@X+!O_TXLBHF;/@`Q@@&A(+!/KT\O3X_@(%"`H)!P0`__W[_/X!!0@(
+M!P8("@P+"`8%!`,#`P0(#`X+!@+__OOX]OC]`0,$!0<)"0D)"`@)"PP-#@X,
+M"`'TXL>GFK/@`Q@?&A(,!?SU\O3X_`$%!PD)!P0!__W[^_T`!`<(!P8'"0L+
+M"0<%!`,"`@,&#`X,"`,`_OSY]_C\``,$!0<)"0D)"`@("0P.#@X,!P#UY<RM
+MG+#;_Q4?&Q,,!?WU\O3W_``$!PD)!P4!__W[^_T``P<(!P8'"0H+"0<%!`,"
+M`@(%"@T,"`0`_OSY]O?\``,$!`8("`@("`<("0L-#P\,!P'WZ=.SFZK6_!(>
+M&Q(,!_[W]/3W^P`$!@@)"`4"`/W[^_S_`P8(!P8&"`H+"0<%!`,"`0($"`P,
+M"04!__WZ^/?Z_P($!`4'"`@(!P<'"`D+#`T,"`/Z[=J]I*K/]@X<'!,-!P#X
+M]/3V^_\#!0<("`8"`/W[^_S_`@8'!P8&"`H+"0<%!0,"`0$#!PL,"@8"`/[[
+M^/?Z_@($!`4'"`@("`<'"`D+#0X-"0+Z[=O!IZG-]`P;'!,-"`'Y]/3V^OX"
+M!0<)"`8#`/[\^_S^`04'!P8&!PH+"@@&!0,"`0`"!@H,"@<#`/[[^/?Y_@($
+M!`4&"`@'!P<'"`D*#`T,"07^\N+)K*?&[@D8'!4-"`+Z]?3V^OX"!`8("`<#
+M`?_\^_S^``0&!@8&!PD+"@@&!0,"`0`!!0H,"@<#`?_\^??X_0$$!`0&!P<'
+M!P<'!P@)"PP,"@7_]>7-KZ;#ZP87&A,-"0/\]O3V^?T!!`8("`8#`?_]^_S^
+M``,&!@4%!@@*"@@&!`,!```!!0D+"0<$`?_]^O?X_``#!`0%!P<'!P<&!P@)
+M"@L+"07_]>;1MZW#Z`04&10-"03\]O7V^?T!`P4&!P8#`?_]^_S]``,%!@4%
+M!@@*"@@&!00"`0```P@*"0<$`?_]^OCY_``#!`0%!@<'!P<&!@@*"@P,"03_
+M]^K6O:Z_Y`$2&14."@7]]_7V^?P``P4&!P8$`?_]_/S]_P,%!04%!@<)"@@&
+M!`0"`0```P<*"@<$`@#^^_GX^_\#!`0%!@<'!@8&!@@)"@L+"@<!^>S9P*^]
+MX/X0&!4."@7_^?;V^/P``P4&!P8$`@#^_/S]``($!@4%!0<)"0@&!`0"`0``
+M`@8)"0<%`@#^_/GX^_\"!`0%!@8&!@8&!@<("0H+"@@#^^_?Q[*XVOH-%A8/
+M"@8`^O;V^/O_`P0&!P8$`@#^_/S]_P($!04$!08("0@&!`0#`?__`04)"0<%
+M`@#^_/GX^OX"!`0$!@<'!@8%!08("0H*"08!^O#BS+>[VO@+%A8/"08`^O?V
+M^/S_`@0%!@8%`@#^_?S]_P$#!04$!`8("0@&!`0#`0#_`00("0<%`P'__/KY
+M^OX"`P0$!08&!@8%!08'"`D*"@@#_?/FT;RZU/,'$Q4/"@<!^_?W^/O_`@0%
+M!@8%`@#__?S]_@$#!`0$!`4'"0@&!`,#`0#_``,'"0@%`P'__?KY^OT!`P,$
+M!08&!@8%!08'"`D)"0<#_O;IUK^ZTO$%$A0/"@<#_/CW^?O^`0,$!08%`@'_
+M_?S]_@`"!`0$!`4'"`@&!`,"`0#_``,'"`<%`P$`_OOY^OT!`P,$!`4&!@4%
+M!04&!P@)"0<$__?LV\>^T.T##Q00"@<#_OGW^/O^`0,$!08%`@#__OW]_@`"
+M!`0$!`4&"`@&!`,#`@$```(&"`<%`P$`_OSZ^OT``@,#!`4&!04%!`4&!P@)
+M"0<$`?KQXLV^RNC_#1,1"P<#_OKX^/O]`0,$!04%`P'__OW]_@`"`P0$!`0&
+M!P@&!`,#`@'__P$%"`<%`P(!__SZ^OP``@,#!`0%!@4%!04%!@<("`<$`/GP
+MX]#"S>C^#!(0"P<$__KX^/K]``($!`4%`P'__OW]_@`!`P0$`P0%!P@'!0,#
+M`@#__P$$!P<%`P$!__WZ^OS_`0,#!`4%!04%!00%!@<'"`<%`OWTY]7$RN/Z
+M"1$0"P<$__OX^/K]``(#!`4%`P'__OW]_O\!`@,#`P,%!@<&!0,"`@$`_P`#
+M!@<%`P(!__W[^OO^`0,#`P0%!04%!`0$!08'"`<%`OWUZMC'RN+Y"!`0"P<%
+M`/SY^?K]``(#!`0$`P$`__[]_O\!`@,#`P,$!@<&!0,"`@$`_P`#!@<%`P$!
+M`/[\^OO_`0(#`P0%!04$!`0$!08&!P<%`?WVZ]S-SN'W!@X/"P<%`?SY^?K]
+M_P$#!`0$`P$`__[]_O\!`@,#`P,$!08&!0,"`@$`_P`"!0<%`P$``/[\^_S^
+M`0(#`P0$!04%!`0$!04&!@8$`O[Y\.+2S=WS`PP/#`@%`?WZ^OO\_P$"`P0$
+M`P(`__[^_O\``@,#`P,$!08&!0,#`@$`__\"!08&!`(``/_]^_O]``("`@,$
+M!`0$!`0$!`4&!P8%`O[X\./4S]_T`PP."P<%`O[[^OK\_@$"`P0$`P(`__[^
+M_O\``0(#`P,#!`4&!0,"`@$`__\!!`8%!`(!`/_]^_S^``$"`@,$!`0$!`,#
+M!`4%!@8%`O_[\^C:T=OP_PD-"P<%`O_[^OK\_@`"`P,$`P(`__[]_O\``0(#
+M`P(#!`4&!0,"`@$`__\!!`8%!`(!`/_]_/O]_P$"`@(#!`0$!`0$!`0$!08%
+M`P#\].G;T]SP_P@-"P<%`O_\^OO\_@`!`@,#`P(`__[^_O\``0(#`P(#`P0%
+M!0,"`@$`__\!`P4%!`(!`/_^_/S]_P$"`@(#!`0$`P,#`P,$!04%`P']]^_A
+MU=KM_`8,"P<%`__\^_O\_@`!`@,#`P(!__[^_O__`0("`@("`P0%!`,"`@$`
+M`/\``@0%!`(!`/_^_?S]_P$"`@(#`P,#`P,#`P0$!04$`P'^^?'EV]SK^@4*
+M"P<%`P#]^_O\_O\!`@,#`P(!`/_^_O__``$"`@("`P0%!`,"`@$``/\``@0%
+M!`(!``#__?S]_@`!`@("`P,#`P,"`@,$!`4%`P'_^_3JWMOH^`,)"P@%`P#]
+M_/O\_?\!`@(#`P(!`/_^_O__``$"`@("`@,$!`,"`0$``/\``0,$`P(!``#_
+M_?S\_@`!`0("`P,#`P("`@,#!`0$`P'__/;NXMWG]@$'"@@%`P'^_/S\_?\`
+M`0("`P(!`/_^_O[_``$!`@("`@,$!`,"`0$``/__`0,$`P(!``#__OS\_@`!
+M`0$"`@,#`@("`@,#`P0$`P(`_?CPYN#F]/\&"0@%`P'__?S\_?\``0("`@(!
+M`/___O__```!`@(!`@(#!`,"`0$``/__`0(#`P(!``#__OW]_O\!`0$"`@("
+M`@("`@(#`P,#`P(`_?GRZN/G]/\%"`<%`P'__?S\_?X``0$"`@(!`/___O__
+M```!`0$!`0(#`P,"`0$``/__``(#`P(!``#__OW]_O\``0$!`@("`@("`@("
+M`P,#`P(!__OU[N;G\OT#!P<%`P(`_OW]_?X``0$"`@(!``#_____```!`0$!
+M`0("`P,"`0$!``#_``$#`P(!``#___[]_O\``0$!`0("`@(!`0("`@(#`P(!
+M__WX\>GH\/L"!@<%`P(`_OW]_?[_``$!`@$!``#______P`!`0$!`0$"`P(!
+M`0$```#_``$"`@(!````__[]_O\```$!`0("`@(!`0$"`@("`@$!__WZ]>[K
+M\/D`!`8%`P(`_OW]_?[_``$!`0$!``#______P```0$!`0$!`@("`0$```#_
+M``$"`@(!````__[^_O\````!`0$!`0$!`0$!`@("`@(!`/[[]_'M\/G_`P4$
+M`P(`__[]_O[_```!`0$!``#______P````$!`0$!`@(!`0$````````!`@(!
+M````___^_O\``````0$!`0$!`0$!`0$"`@$!`/_]^?3P\OC^`@0$`P(!__[^
+M_O[_```!`0$!``#______P````$!```!`0$!`0`````````!`0$!````___^
+M_O__``````$!`0$!`0$!`0$!`0$!`/_^^_?S\O?]`0,$`@$!`/_^_O[__P``
+M`0$!``#______P`````````!`0$!`0```````````0$!````_____O\`````
+M```!`0$!`````0$!`0$!``#^_?KV]/?\``(#`@$!`/_^_O[__P``````````
+M______\``````````0$!`````````````0$!`````/______````````````
+M``````$!`0$!``#__OSX]_C\_P$"`@$``/_______P``````````______\`
+M`````````````````````````````````/______````````````````````
+M``````#__OW\^OK\_P`!`0$``/_______P``````````________````````
+M`````````````````````````/_______P``````````````````````````
+M___^_/S]_P```0````#_______\``````````/______````````````````
+M`````````````````/_______P``````````````````````````________
+M_P````````#_______\```````````#__P``````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````!#3TU-````$@`!
+M```T%@`(0`VL1````````$U!4DL````"``!)3E-4````%#P``'\`?P``````
+M````````````05!03````:A39#)A``(`````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`I``````````````````````````````````````````````````````````
+M```````````````````````$"```````"0`C`````````````````'@````$
+M``0```````#\`/___X`````!`0`&455N:71S````````````````````````
+M`````````````````0(`!B!S86UP<P``````````````````````````````
+M`````````````````````````````````"<`+P`/__;_^0`!````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````0``
+M``%X````>````%8``````%;^`/___X`````!`2`&455N:71S```3""YP9P5"
+M=6=L90(```!!249&4V0R80`````````````2JP````!!249&4V0R80``````
+M`````````````````````````*<]K=8``#8B```!S@```!T`+P`/__;_^0`!
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````:`"D`#P)J`S$`*@`#`FT#
+M/0`I``\"00,B`0`````:`"D`#P%0`?$`*@`#`FT#/0`````````````````:
+M`"P`%@$^`=P`*@`#`FT#/0`````````````````:````````````````````
+M``````````````````$````!>````'@```!6`'&XO!RF````'`!6``!7<W1A
+M``,`"@`!__\````````````"__\````>```````#__\````\```````$__\`
+M``!:````````````````````````````````````````````````````````
+,````````````````
+`
+end
diff --git a/sys/share/sounds/erthdrum.uu b/sys/share/sounds/erthdrum.uu
new file mode 100644 (file)
index 0000000..c95e8bc
--- /dev/null
@@ -0,0 +1,863 @@
+begin 644 Drum_Of_Earthquake
+M`!)$<G5M($]F($5A<G1H<75A:V4`````````````````````````````````
+M``````````````````````````!!249&4V0R80$`````B@```````)0,```!
+MZ*<]FRNG/9VP``````````````````````````````"!@<1G``!&3U)-``"4
+M!$%)1D934TY$``"2"```````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````/_____^_OW\
+M_/OZ^?CW]O3S\?#O[NSKZNCFY./AWMW;V=?5U-/1T,[,RLC&Q<3"P+^^O;R\
+MO+NZNKFYN;FZNKN[N[N[N[R]O\#`P<+#Q,7&Q\C)R\S-SL_1T]77V=K<WN#C
+MY>CK[>_P\O3V^/K\_@`"`P4("PT.#A`3%A<7%A@<(B8G)B0E*2XQ+RHG*"XU
+M.SLW,2XR.T-&0SLS,39`2U-434`Q)2,K/$U96E%`+!H-!@P>.UMQ<W!J4"T5
+M$A87%Q84#PL'!@\H2%M<4D8\,B@?%@\(`?SV\>SGX=S7TLS'PKZZM[6TM;:Y
+MO<''SM?AZ_<#$!PI-$!*5%QE;&]O<'!O;FYN;6YM;FUL;6UN;FYO;W!P;VUJ
+M9V1?6U=44U-55EA:7%UA9FQQ='1R<&UJ:&AI:FQN<')T=7-Q;V]N;FQH8EU8
+M5E-03$E&0T`^.SHX-S4U-#0T-34U-C8V-C4T,S$N*R@E(AX:%A(."04`_/CW
+M]_;U]?7U]?7U]?7U]/3S\O+Q\/#O[^[N[>WL[.OJZ>CGYN7CXN#?W=S;VMG7
+MU=/1T='0SLG#P+Z[N;BWM[>WM[>WM[>WMK:UL["LJ*6BGYV;FIJ;FYN9EY:6
+MF)N>H:*AGYZ<G)N<GJ&DIZFJJJNML+.VN+FZNKN]P,/&R,K*R<?$PL+#Q<C*
+MS,W,RL6^M["IHYZ;FIR@IJRRN+R]O;V^P,/%R,O.TM;;X>;L[_+S]?;W^/CY
+M^/?U\_/T]_P`!`<*"PL+"PL+"PL,#`L)!@+__?O\``</&2(K,SD]/T)&35)0
+M3%!98&%>8&5D5T8X-3@W+1T2#@\-!__\_P8-$!`+`?3JYN?L\O?\`0<-$A89
+M'2`C*#`\3%ME:FYP;VMD5T8U*R@D&Q`)!0+]^/;RZ^'6RL"[NL#(S<S'PKVV
+MKJJJJZFFI**=DXB`@("!A8Z:J+2]Q,?(R,G)R<K-SLB^M;.XO\+"P<+'SM/6
+MU]C=Y_#T[^;<T\O%PL'!P<'`O[Z]O;R[NKFZN[>QJJ2@G)B8F)>0AX&`A(F.
+ME9VCIJ*9CXB*E:2QN\/+T=+3UM[DY^7CYN[Z!A`7'B0J*R<A'!D9%Q02$1,7
+M&AH<(",H+C,U-38[0TA*35)86E=34$]255144TU$.2\I)RDL+2LE'Q<0"@8&
+M"0P/$108&18/!@#[]O#N[_3X^OK[_/SZ]_;[`@@)!/WZ_@@3'24K+C`P,"\M
+M)QX3"P@*#0\-"00$"!$=)RXR-3D]04)#0T1$1$$_/C]%3EEE<'A^?W]_?W]_
+M?WUV;65@7%A234E(24E(1TA+3U-66%9/1CTY.3L^/SXZ,B@=%`X*"`<("0L-
+M$!(4%QH<&QD9&Q\D)B4?&!`)`?OW]O;W^/?V\^_IY>3EZ.OL[.OM\_H``P0$
+M`P'__P(&"@X/#0D%`@($"`T0$Q,1#0H'!00$!`,!__WZ]>_HY.+BY>KR^@0.
+M&2$C(!H3#`<$`P(#!0D-$A<;'A\?'AT9%!`,"0@*#A0:'B`>&!$+!@/_^O3K
+MX=C0R,*^O+NZNKF[OL+(S=/7VMW?X-_<V=3/R\G(RM#9Y?+\`P<*"@H*"0;^
+M\N/4R,"\N[R[N+6QKZZMKJ^QM+:YO+_%S-7@Z_;]`/_[]_3R[NOHY>/BX>'A
+MX>'BX^3DY.#:U-7>Z.GDX-_<V=K@Y>7CX^3CW=?2U=G:T\G"O\'*V.;O\.K@
+MUM7B]0`#`O_^_/S[^OKY]O/O[.GFX^'>V]C6T\['O[>PK*NNL;2VM[BYO+_#
+MQ\S/T]78V^'I\?;W]O#FW-O@Y.'>V]?5U-76U]C8V=O@Z//]!`4#`PH4'2$B
+M)2@K*RHH(QD,`/;R\O?_!0L0$Q46%A44$A`/#@X.#Q`/#@L'`_[X]/#N[>_T
+M_0D6(2@K*24B'AL9&1D;'!P;&184%!05%186%A45%!,1$`X,"PL+#`T.#P\0
+M$1(3$0P#^.SDX.#@X>3G[//^"QHG,#0T,2XM+B\O+BPI)R8E)B<J+"XP,"\O
+M+RXJ)1X6#PT5("@H(R`@(R<K+BXJ(1,%_@(/'2<I(QD,__3MY=[7U-;<Y.GN
+M\O?]``'__?OZ_/\#"`X5'2<R/DI896UP;&-623XV,2\N,#,V.3<R*2$;&1D:
+M%@T!]N_LZ>KL[O#O[.?AWM[BZO/\`P@*"04!_?T##QH>&A00#A`1$`L&`O_\
+M^?7QZ=_6TM+5V^/P`1`;'A@-_O+L[.[P[^ODWMK9V=WD[OH$"@P,"PH("`L0
+M%!01#@D%`@("`?[\_/S]_?X!!@L2&!P>'1L7$0P("0P/#@L(`_[Z^_\$!@0!
+M_OOW\>GCWMW=WMW<V-3/S<[2V-[BX^#<V-73U=SDY^/;UM;:X>KS_`0)"@<#
+M_OGS[>SP]/;U]/;Z_P$!``($!`#\^?7R\/'U^P$'"PT,"`+[].[JZ>ON[O#W
+M`PX3$Q8=)"HL+"PO-CHY-C@^0D`\.CP]-B@:#P?_^?C[_/COY^;K]/X$`?CR
+M]/GZ^?L`!`/]]N[FW-#'Q,K0S\G#P\;*S,W0UM[DZ.KN]?X'$APE*2PN+BTI
+M(A<-"0H+!OWV\>OEXMW4RL3%RL[.R<&^P\K+P[FWO\G.RL?+UN+J[?'V^?;O
+MY=G,OK"DG)>8G*&FJ:VSN\3,SL[-T-?>XN+CY>CIZ>GJ[?'U^P`%"@P.#P\/
+M#Q`3%A40"P\8(B@J*RTQ-SLY,S`V1%%64TD[+R8C(R8J+"PJ)2`;&1@8&1D7
+M%A,1#P\/$!`0#PX.#Q(6&AT='!XD*2HI)2(?&Q@5%!,3$A`.#`H(!@0#`/WZ
+M^/;T\>K>T<2]N;.JH9N:G:*EI:2DI:BJIY^6DY:;GIZ<FIJ<GJ&DJ:^VN[RZ
+MO,''R,7`OKV\MJVFIJRQMKO!QLO2W.;M\?/T]OP$#A<>(!T6#P<`^?;U\^WC
+MVM75V>#I]``)#@T+#!`1#@8`_P'_^O3P\?;_"A09&AH:&1<6%101#@L)"`H-
+M#0L(!0(`__[^``(#`__[]_7U]O?Y^OOY]._L[.[Q\O#IW];3VN7N]/CZ]^_H
+MY>CM\/#KY-_?Y.GM[_#U_04+#A$5'"0I*B<A&QL@*"TM*2,>&QD8&1D8%A$*
+M`_SV\O'R\_/R\.[O\O7Z_P4,%!XJ.45+2D0^.SHX-#`N+S$P+"(5"@0&#18?
+M(R0F+#(S+B(5"P@)#`X1$`T*"@\7(2DM*R<C(R8J+"LD&@T"]^[GY>S[#AXI
+M+2LC&1`.$!(4$0P%_OO[_O_]^?;W^/;MX=G6V-O>W]S;W>3O^/X!`P0#`O_Z
+M]/+V_PH3%A00#@\3%QD:'!X?'1P;'!T='!H6$`?]\^SFY.3FZ_'U]_?W^/K^
+M`@8+$18:'!TA*35!1T8],28A(B<M,SD]045(2DI(1D5&1$$]/#HW-38]14M+
+M1D)#1D5!/D%'2DA".S(M+C,V-"\L+C0]0T9&1D5&24Y78&1B7%9.1CXX,BXL
+M*BHM,S8T+"8F*C`V.S\^.S<V-C4T,C`P,C4W-S<W-2XE'1D8&!$$]NWHZ.OR
+M_`@3&R`@'!40$!(4$PX(`?O[_?[\^OO_!`D,#0X-#`H)!P0!_OKX]_?V\N_M
+MZ^OL[O#T^/O[^OGW]?3X_P0#__CPZN?FY^;EXM_=V]O:U]73T]+0S,6_O<#%
+MR<K(Q<*]N+2RLK*QL+*UNK_"Q<;#OKFVMKBZO,#%Q<&\O<;5XNST^@`%"0X4
+M&!H9&1TE+3,U-3,N*"(>&QP<&QD7&R(G)!L0"08'#!(9'AX8#@4```$!__OY
+M^/GZ^??W^/O_`P@0&2(G*2HK*B4>&!88'!\C)B@H)B,@'AL9%0X$_/CW^/O^
+M``#\]O+T]_?SZN#9U]C>Z/+X^OO\`0H5'R0B&0\'!08'!0#[]O/S]_\+%R$I
+M+"LE'!$%^_;X``P7("8H*"8A&Q<4#PC^]>[IYN+@X.3J[O#Q\O/U]_?V]_K_
+M!`@*#`P+#`X3&1T=&Q81#0L+#`\1$Q(1#Q$7'1X:$PT)!@4&"`L.$1,3$Q49
+M("<L+2LG)",D)B<F(AT8$@T(!0+__/GU\O#N[.OK[.WLZ^GFXMW7T<S'O[>P
+MK*FEHJ*FKK.QJ*&@IZZQKJFGK+2ZO\'#P\+#Q<?(Q\;$PL+#QLO/TM/3T]/4
+MU=;7U];5U-73SL;`OKV[N+6UM[JYM:^LKK2[PL;)S,[0T=#.S,S/T]C;VM7/
+MR,/!P\G0UMK<WN'DZ>[T^@`#`OSU[NCDY>KR^P('"PX1$A$."@7_^/+LZ.;E
+MY.3DYNKO]OT$"0P.#0H&`@#]^?/JX-;.Q\&\NKFYN+FYM[2OK:^TN;W`PL;,
+MTM;5TLW,S,W,RLG*S,[1T]+,Q+NSKZ^QM+6UL["MJJ>CHJ.FJZ^RM;J_QLS1
+MU-;8W-_?V]+(P+V^Q,S3V-K:V=K=X>7J\/C_!0L4'RHS.3Y%35)444M$.S0N
+M*20?'!H7$`?\\^_P]/GZ]_3S]OL``/[[^?O\^O3KX]W;WN;Q_`@3&QT:%!`1
+M%1LA)BDK*RDD'!$'`/T`!PP,"`0#`P0$!P\9(R@G(AT;'"`A'QL7$PX(`OS[
+M_@($__?PZ^KL[_+V^?K[_0,-&28O,S0S,S,U-34T,C$N*R<D(1\=&Q4,`_W\
+M_?WZ]O7W_`$%!@0!_OS]`0@.$Q@<(",C(R,B(R(@&Q(%]^KAW=[AYNGIYN'>
+MW-O;WN3M]P`'"PH'`?W]`@@.$`\-#`P-#`D%`?[[^_X!!0<(!@#W[NKL\O?X
+M]_;X^_\!!0L4'R<L+B\Q-3@Z/#Y!0T1$0S\Z-3`L*2@J+S0Y/$)*45974TY)
+M1D-`/S]"1DI,2TA%1DE.3TY*14$].CM`1DM,2$,_/D!"03XY-C<]14Q/34A!
+M.C,K(QT;&AD7$Q`/#Q$2%!<;'B`@'AL8%1,1#PP*!P4$`O_\^?CX^OO\_?X#
+M"Q,9'2`A'QD4$Q8;("(E*"LN,#`O+"<B'R`B(R0E)RHL+"HG)24E)20A'1D4
+M#P@`^?7Q[>CDXN'?W=O9V-?8VMWBYNGK[_7_"Q@B*2TN+2TM+2TL*2,=&!45
+M%A<<(RPR,BTF(1\?'AP7$@T(!`#]_/KY^/CW]O;V^/K]__[Y\>KDXN+AW]W<
+MW-O;W-_EZNKHYNCO^@81&1P;%0X&`/W[^OOZ^OCV\N[LZ^OJZ.?HZNWR]_O\
+M^_CU]?;Y_@0*#1`2%!<6$PX)!0(`__\``0(%"0T1%!<:'!\D*"TO,3(S-38V
+M-30S-CQ$351:7V)B8%Q74DU'0#8L(QP8%Q@<'R`?'1L9&1PB*"PK*"4C)"8H
+M+#`V/$%%1TA)2DI)14`\.ST].3`E'1H<("0C'A</"@D)"08#`0(#!04#`?_]
+M_O[^^_3LY-_;V=G;X>CM\._LZ.;EY.3CX^3GZ^WMZ^OP^`$%!0'[]?/S^/X%
+M"P\3%QL>(2(C)28G*"@F(AL2"/_Y]?/Q[^WL[O'V_``"`P0(#`X-"`'Y\_+T
+M^/S_`/[Y]/'P\O/S\.KBV=+.R\K)R,?(R\_4V=W?W][;UM35W.7L[>GAW-O?
+MY.CIZNOM[^_KY=[8U=+,P[JWN+W&T=SCY-_8TM'7W^?L\?;Z_?[___[Z].WI
+MZ.?FY.3FYN+8S<*[M[:XNKV_P<+!O[V\O+R[M["II:6GJJRNK["PL+&SMKJ]
+MO\+$Q<7%Q<;*T-;<XN;K\/3U]/+Q]?P#!/[U[_'W_O_Z\NOHZ>OKY]_6T=+7
+MX.GP\_+R]/?Z_/W^_P(#`OWU[.;DY.+>VM?6UM;5U-+/S<S0U]_FZ>KJ[._Q
+M\>_N[.SM\//U]?/NZ>7BX-S5RKVQJ**=FYJ;G9^?GZ*KM;JYM+"RN+_#P\#`
+MP\G0U=KAZ?#R\.WN]/L``?[Y]/#N\//X_/\!`@0)#A`-!P'Z\^WHY.#=V=71
+MSLS+S,O'P;_!QLK+R<7"P<'"PL3)TMOBZ.SR^?X!`P,#`/W[^??V]?3R[^KE
+MX-_?X.'AX-_=V]C5U-?=Y.GN\O;X^?GX^/K^`P4"^O/P\O;Y^OT!"`P-"PD)
+M"@H)!@0"`P@1&B`A'!4."@8#_OKW]OCZ_/[_``$!`0("__GPY][7T];=Y^[R
+M\O'O[.CFY^KL[N_N[>[O\?+S\_/S\_/S]?7R[>?BWMW>W=C3SLS+R\G'QL7&
+MR,O/T]?:W-[AY.CL[N[MZNCGZ.ON[^[LZ>?DXN'AXN3EY^KM\?7X^_X``0$#
+M!@D,$!,5%QLB*C`T,S$R-CHZ-S0S-3H^0#\]/D)'2TY/45)24$Q(1DA*3$M'
+M/S<Q,3E%4EUE:FQL:6->65545%)/3$I-5%YH;W)R<&MH9VAK;7!Q<G%O;&EE
+M8%I54E!.3DY,2$(Z+R4<%Q<=)2TQ,2\M*BHL+C`S-38U,S`M*B@F(R$?'AX?
+M(!\=&!45%A<7&!D;'!L8$PX*!P8&!@0`^O+JY-_=W-O:U]31SLW-S<_1U-?;
+MWN/I[O7_"A08%Q01$1,9'R8J*R@D'QH5$1`3%!,0#0P-#@X,"0D,$102#@L*
+M#0T*!`#___[[^P(/'2<L+C$T-C,J'Q40#PX,"`8(#1,9'!H6$0T*!P8#`/WZ
+M^?CX]_C\``0'"0T2%A@7&!LA*"\U.CPZ-3`M+"TM+"PK*RDG)B@J+"TL*B@E
+M)"<M.$-,4%187&!B85]?8&)C86!B9FEG8UU85$Y(03PZ.38Q*B,<$PL%!`<*
+M"PD&!08'"`8"_OOZ^OS_!`D,#`H(!P8$`?[]_@```@4+$QH?(2`<&!87&R`C
+M)20C(R,D)",A("`?'Q\?'AP9%1(0#Q`0$1(3%!47&1H<'!H8%1(0#0D&`P'^
+M_/OZ^OK[_@,*$!47%Q<6%A43#P@!^/#JY>#=W-W>WM[?X^KN\?/V^P`"`?SY
+M^OT``P+__?O\_?W]^_CV]?3T]/?[`0<-#PT&_O?R[NKIZNWP\O+P[NWL[O'U
+M^?S^``0(#!`3%1D=("(B(1\;%Q$+!@+_^_;PZ>/AX^CN\_?Y_/X!!`<)"PP-
+M#`D$_?CT\>_N[^_O[NSKZ>CGY^?FY./CX^'<U]33U-;9W>#AWMC2SLS+R\W2
+MV-S<UL_)QL?)R<?$P\3)SM+5VN'GZ>CEXN#@W][<V][AX^+?V];1RL.^NK>V
+MM[N_PL3%QL;&Q<"\NKN^O[Z[NKJ[OL+&R]#6W>/I[O'T]_K^`0(!_OW^`@0#
+M__OX]O7R[>;>U]35VN#FZ>KGX^#=W=[@X^?JZ>?CX-W9U='-S,O*R,;#P<"_
+MP,+%RM'7V]S=W=W=W=S=WN'CY./@WMO:V=O>X^?GY.'AXN'>VMG;WN#?VM74
+MUMK<W=W>XN;HY^7DY.3DXN#?WM[=W=S;VMK;W>#BX>#?WM[>WM[>X./GZN[R
+M]?;U\_3V^OW__OW[^/CY_0$%"0P/#P\/#@\/#Q$1$0X+"`8%!08&!@4$`@#]
+M^??U\_#LY=_7T,K&PKZXL:NHIJ6EIZNTO\W9X.+AX.+FZ>CCW=C6U=73T]37
+MV=G7UM?:W^/GZ>SP\_;W]_7T\_/S\O#MZNGJ[.[N[>OJZNSM[>SL[>WM[>OI
+MY^3BW]W;VMK;V]O9U];7V=O>W^'CYNCIZ>KM[_'R\_3U]?+N[.SP]?K_`P4#
+M`?[\^_GU[^C@V=31S<G&Q<?*S]39W^3I[O'S\O#N[N[P\O3X_``#!`,!_OOZ
+M^?GY^/?V]?7V]_?V]?;Y_0$&"Q$7'"`B(B$>&A82#PX-#`D%`/W\_@(%!P4"
+M_OS[_0`%"Q(:("(@'1@5$0X)!@0"`/SX]/+R]/?Z^_S_`@4%`OWW]/+T]_O]
+M_/GW]_GZ^??U]//Q[>CDX^/CXM_;U]75V-SAZ?#W_``"!0<("`<&!@D-#P\-
+M"@D+$!@='QX='2`B(R(A(B4K,#0V-C8U,S$N+"PM,38\0D9)2$5`.C0N*RHI
+M)R,>&QL=("$A(B0H*RXO,#$S-SH\/#HW,S`K)R$;%A(1$A48&AXB)2@H)R4D
+M(B$@'Q\@'QT9%`\,"08%!08("`@("0H*"0D*"@@"^O+N[_/Y_P,$`P(!`@,%
+M!PL0%1@8%A,1$1(4&!TB)BHN-3Q"2$Q-2T=$0D`_/3LZ.3H\/T1(2TQ)14`\
+M.CL]0$)#1$9&0SPT+2DH*2HH(QT9&1XF+S8\/CX]/#HW-3,U.#Q`1$E/4U=7
+M5$])0CLV,S(S,S,Q,"XO,C<\/C\^/C]#1TQ26%YA8%U955-24E%/2TA&145$
+M03TZ.#<W-S<X.3DY.S]&35-655),1D$_/SX[-S,R-#@\/S\^/#P\/#LZ-S0Q
+M+BLJ*2@G)2(A(20H*RTM+"HJ*RPM+2PJ*2@F(QT4"P4!__SY^/K^`P@,#Q$2
+M$Q48'2$D)20@&Q4/"04!__SY^/G[_/W]^_GX^/CY^OK[_/W^_O\"!@H-#P\/
+M#Q$2$A(2$Q,2$`P(!`#[]O/P\/#Q\?'Q\/'R]/G^`@8)#`X0$!$0#@H%`?W[
+M^?CW]/'MZ>;BX-[>WM[>WM[?X>3FY>/@W=W=W^'DYN;FY>;FY^?FY.'@X.'D
+MZ.KL[.OJZ>OM\//U]O;W^/K[_/OY]O+O[.KHY^;CX-W;V=?5U-78VMO:V-;4
+MTM+3U-75U-+1T,_.SM#3V-O>W][>W^'E[//X_/W^_P$$"A$7'2`B)"4F)B4B
+M'AL8%Q83#@<`^O;S\_3W^_W^^_CU\_/T^/X%#!`/#`<"`/_^_P$#!0<&`P#\
+M^OK\_P$"`@("`@(`_/?QZ^7@W-G8UM74U=?:W-W;U]/1T=/3TL_-SM'4U]G;
+MW=_AX=_=W-O:V=;3T,S)Q\?(R\_3UM?6T]#-S<_2UM?5T<W*RLW1U-30R\?#
+MP+VZM[6SL:^MK*RML;2WN+>WM[F]PL?*S,S-T-;>YN[U^_\!_O?PZN?GZ>KH
+MY>'>W=_CZ.[T^/KZ^?CX^OO\^_KX]?'LZ.3BX>#?WM[?X-_>V];/R<?)S='4
+MU-/2TM'/S<W0UMK=V]C3T,W*Q\7$P\'`O[Z^O;R[O+[`PL3%QL?)R\O*R<C(
+MR<G'P[RUK::AGY^?GYV9EI.2D(Z,BHF(B(B)BXR/DI>=I*NQM;>XNKN^P<7+
+MTMG?Y.;FX^#<V=C9VMG6T,O(R,G-T=?<X.'AX>+FZN_S^/S_`/_\^?GZ_?\`
+M`0$!`0$#!0@+#0X-#`L*"@<"_/7Q\//W_``"!`8*#Q4:'B(G+#$U.#DX-S0Q
+M+BLI)R0A'1D8&!L>'Q\=&!,."@<%`P$`__\```#__?S\_/S\_/S\^_GV]?C^
+M!@X4&!L='R`B)"8H*2DH)R<G)2(>'!P>(20G*2HI*2@F(QX7$0P(!0']^OCW
+M]_CZ_/\#!@<'!@0"`0$"`0#^_/KX]O/O[.OL[_/U]?/Q\?'S]OK_!0L.#PX.
+M#@\/#P\-#`H'`OWX]?/S\_3V^?O\_/KZ^_W_``#__/KW]?3U]_L!!PT2%!44
+M$Q,3%!46%A85%!47&1H9%Q45%A86%!(1$1$2%!<9&1@6%103$@\,"0<&!@8'
+M!P@("Q`7(2HS.C]"0T$^/#HX-C(N*20>%Q(/#Q$5&!H;'!\B)"8G)B4B'QX?
+M(R<L,38Y.CDV,BXK*B<D(!T:&AL;&QH8%A03$A$0#PX.#`L)"`<("0P1%1D9
+M%Q43$Q47&AL;&!,/#0P.#P\0#PT*!@,#!`8("0D)!P<'!P@)"`8%!08'"`@'
+M!0,!__[^``$"`@(!`````0#__P`#!PH-#0X0$Q47&!@9&QXC*"TQ-#8W.#<V
+M-30S,C(R,2XI(AH2#`<$`?_^``(&"0L,#0X.#Q`1%!<:'!L:%Q85%145%A<7
+M%Q<8&1L>(",E)B@H*"@F)2,A'QX='1X@(B0D)"0E)BDJ*RLK+"PJ*"0A'AT<
+M'!\B)"4C(!T;'!\C)RDG)!\;&1D:'!\A(R0C(!L6$1`4&B`E*"DI*2LP.$!'
+M2TU/3T]-245"04%!/SLV,BXL*24A'1H8%!`-"@D)"@P/$A,2#PP)"`H-$!06
+M&!@8%Q45%AD<'1T='1\A(R4F)RDK+3`R-#4U-3(N*B0?&Q<5%!,2$A07&QT<
+M&A<5%!,3%!8;("0G*"@H*"@G)R<F)!\9$PX*"0D+#0\/#P\/$149'R0H+"XN
+M*B4>&143$A$1$A06%103%!@>(R<K+C`Q,3(T.#L]/3P[.SL[.SLZ.#0Q,"\O
+M+2DD'180#0P-#0X-#`H)!P<(!P4!^_;R[^WL[.SM[>WN[_'S\_3U]_O_`@0$
+M`O_\^//LY=[9U];6U-/0S<K'Q<;'RL[1U=?8V=G8V-C9VMK9V-;6V-G9V=G:
+MW>'CY./AX.'BY.3CX=[;V=?5TL_-S,S,S,W-S]#/SLO*RLO,S<O(Q,&^O+NY
+MN+>VM;6VN;N\O+N[O+[!Q<C+S,W-SL_0T]?<X./DX^+BX^3EY>3CXN'@WMS9
+MUM/0S\[0TM78V]W>W]_?W][;UM#*QL/"PL+#Q,7%Q<3"P<'%R]+9W^3HZ^[Q
+M]?G]``(!_OOW]O;V]_?W]_?V]?/Q[^WLZ^KJ[.[P[NKDWMK8V-K;V]K7TLW(
+MQ<3&R<W2UMC7T\[*R,K.T]?8U]31T-'3U]O@Y.?GY>+@W]_?W^#AX-W8T,G#
+MP,#"Q<?'Q<+`P,'"Q<C-T]C;V]?2SLO*R\O+RLG'Q<3#Q<C-T=/3T]+0SLO)
+MQ\?)S-#3U=74T]35UMC8V=G8UM+-R<;%Q<;'R,G)R,G*S='3U-/1SLW.T=37
+MU]?7U]C9VMW?X>+CX^3DX^'?W=O8U='.R\K)R<K-T-37VMS=X>;L\?/T]??Z
+M_/OY]._KZ>CIZNSO\?/T]/3V^?T!`P8("@H)!@0#`P(`_OOY]_7T]/;X^_[_
+M__[[^/;U]O7T\_/T]_K]_O___P$#!@H-#0P*"`<'!P@)"0H*"0@'!@4%!00#
+M`?[Z]O/R\_7W^/?U\O'Q\_?\``0&!P4$`P0&"0P/$105%100#0L)"`8$`P0&
+M"0P.$1,5%QD;&QH8%Q<7%Q<6%!$."P@&!0,`_?GU\.SJZNOL[N[M[.OJZ^WP
+M\_;Y_@,*$AHA)B@F(Q\;&AD:'!X>'1D4#0;_^_O]``,$!`,$!`4%`P(````!
+M`@,"`?_[^/;X_``"`@#\]O'P\?/V_`(("PP,"0/\]_3P[.ON]?T%#!(4$@T'
+M`__\^_X!!`8(#!0;'QT6"O_Y^?T!`P,!_P`"!0@,$!48&AH:&1@:'B0J+S4Z
+M/D`^.S<S,2\O,#$Q,C(S-#8X/$%'35%34DY&/C8Q+BPK*BDJ+C,W.#0L(QH3
+M#PT-$!0:(24I*BDF(1P7%105&!\H,CM`03X[.3@Z/#T]/#L\/3]`04)%24Q+
+M1T`V+2<C(B$A(2$A(1\<&!,/"@8#`P4(#10;)"LQ-CQ`1$9'1T9%0T%`041'
+M2DU/4%%14$].3$E(24M.45-55E5123\V+RLG(Q\<&AL?)"DL+"LI)B,@'1H9
+M&R`F+3,X/D-)4%5965913$E(2$A'1D=*35!03DE".S4P+2PM+S$R,S(Q+BPK
+M+3`U.#H[/#T_/SLU+B@E)28G)2(=&!,/"0/^^_T!!@L0$A05%1,0"P8!_/GV
+M]/;Z`0@.$1(1#@P*"0D("`@("0L-#Q`/#0@"^O/NZNCFY./BX^7HZNWP\O/S
+M\.WL[.[Q]?G]``(#`@#]^?;U]OK_!0H-#Q`1$1`/$!(6&QX@'QX>'R`?'!8.
+M!O[X]?/T]OCY^/7Q[N[P\_7U]/+R\O3W^_W^_?W]_P(&"0H*"PP/$A49'!X?
+M'AT<'!T?(R<K+"LJ*"@H*"8C'AD5$A$2%!44$`L&`P$!`0$!``#_`00("P\3
+M%AD;'!P9%A(.#`P-#0T+"0@)"PX1$Q04%!47&1L;&1<4$Q$0#0H'!`'_^_?Q
+M[.CDX=[<V-/.R\G)R,C'Q\?(R<K)Q\7"O[Z\N;:SL;*TMK>XN;R^P<+!O[Z^
+MOKV\NKBWM[BXM[6TM;BZN[N\O+R_Q,K0TM+1S\_/T-#0S\W+RLG)R\_2T]/2
+MS\O(Q<+!P,'"Q,7&Q\;$P;^]OL#$R,W2UMG<X>;M\?/R\?'R\_/OZN7AX.#B
+MY.;IZ^[P\_7W^?GX]_7S\_/U]?7S\._N[_'R\O+Q\?'Q\._P\?+T]//S\_/S
+M\_'P[^[O[^_P\/'R\_3T\_'NZ^KHYN7DYN?IZNKJZNKGX][8U=/3U-;6U='.
+MR\O-T-/5U=+/R\K*S='4U=73T,[.T-/7VMS=W=[BY^SP\?+Q\O+T]??Y^_O[
+M^/;S\O+S]?;W^?O^`04("@P-#A`2%!87&1H:&182#PP*"`@&`_WW\>SHY>'>
+MV]C6T]'.S<S.TM?=XN3BW]O9VM[DZ.KIY^7DY./BX=_=V=/.R<?'R,C'Q,+`
+MO\'#Q,3#Q,;)R\[1U-G<WM[=W-K8UM',QL&]NKBWM[BZO+R[N;2OJZJJK:^Q
+MLK.SM+:XN+>VM+2UN+S`Q,C,S]+4U]K>XN7FX]W7T<W,SM#2U-78V][@XN/C
+MX^3EYN;GZ>OO\_?Y^OKX]_;X^?O[^_KX^/CX^OO]_?OZ^/?W^/K]``,$`P("
+M`@($!0<(!P8$`@(#!08'!P<'"0P1%APB)RPO,3$P+"<A&Q4/"@<&!@4#`0#_
+M_OW[^?CX^/GX]_7T]?7S\>_O\?3V]_?U]??Z_@(&"0H*"PX3%QD9&AL='!H7
+M%1,2$0\-#`P.$!$1$1(4%Q@8%1$."P<"_?S]`00%`P$"!0H1%QD8%A04%186
+M%A46&1XB(R,?&Q<4$A(4&2`F*2<C'QT>'Q\=&QD9&!@8&!<5$@X+"`8&!04&
+M!@8&!@8'"0P/$1$/#@\2%AL@)"DN,C4V-C8X.CU`0#TX,BTL+3(V.S]"1DA+
+M3$U-34Y/3DM$.C`H(B$B)2DK*RDG)RDM,SI!2$]35%-134E&1$-!/CPY.#D[
+M/C\_/#<Q*B0?'1T?)"DO-#<Z/#T].SDX-C0Q+2LI*2@H)R<G)B0B("`A(R,B
+M(!X>(B<N-3Q"2$M,3$I)24E)1T5!/3@T+B<?%Q,1$A(1#PX/$A<<(",E*"LO
+M,C,Q+BHF(AX:%1(0$1,5%A,-!@#^_@((#Q07%Q84$Q,4%A@:'!\@(!P6$`L(
+M"`@)"@H*"0H,#A$5&1TA)2<I*2@F)",A(1\=&Q@6%A<8&1@4#PD$`P,%"0P.
+M#@L'`?WZ^OO_!`D.$A04$Q,2$A$1$Q47&!@7%1(0#0P+"@L,#`L)!@,`__[_
+M``$#!0<("`8%!@@,#Q`0#P\0$A07&1H8%1$."PH+#`\2%A@9&1D9&QP='!H7
+M%!$.#`D'!@8("Q$6'"`C)B<H*BTQ-#<X.3@V-#$N+"DG)B4E)",B(B$B(R8I
+M+2\P+BDD(!\A)2DM+R\M+"HI*2@G)!\9%1,5&!P?(2$@(2$B(R0E)",C)"8F
+M)2$<%A(0#PX-"@8!_?S]_P$#!04&!@<("`@&!04&"`L.$!(4%QD:&QH9&!84
+M$`P(!P8$`O[Y]?#MZNGJZNOJZ.7BX>#AX>'@W=K7UM?7U];6U]?6UM75V-WD
+M[/+V]_?V]O7T\_#KY=[6T,O(R,C(QL/`O;N\OL'$Q\G+S,W,R\G)RLS.SLS)
+MQ,"]O;Z_P,"_OKV]O;V]OL##QLG,T-38V=K9V-C8V-C8V-C8V-G9V][AYNKM
+M[_#P[^_P\?+T]?7U]/7V]_CY^/?T\>_N[>[P\O+Q[NKFX^+CY>GL[N_P\?3X
+M_0$#!`,"`0($!PD+"PD&`?[Z]_3Q[^[O\/+S]/7U]O?W]O/MYM_9U-'.R\C%
+MP\+#Q<?*R\S-S<S,S,O*Q\3"P<#!P\;(R\W-S<W+R<?$PL"_OKNXM;*OK*BD
+MH9Z<FYR>HJ6HJJJKK*ZQM+6TL[&OKJZPM+G`QLO/T=+1T,W)QL*_O+JYN+BV
+MM+&NK*RLK:^SN+[$R<S/T-#/S\[-S<W.S<S,S,[1U-?:W-W<V]K:V]W?X-_>
+MW-O:V]S>X.'BXN/CX^/CY.;GZ.CHZ>KKZ^OKZNGHY^?HZN[S^/O]_O\``0$!
+M`/_^_?OZ^/?V]?3S\.SHY-_;U];5U=34U-77V-G;W=_BY>CJ[.[Q]?C\_@``
+M`0(#!@D-$!(4%187&!D:&AL<'1X@(R8I*BLI)R0B(!\@(2(D)"0C(B`>'!L<
+M'!P9$@H`^//P[N[MZ^KHZ.GK[>_Q\_7W^/CY^OO]_O[\^O?U\_'P[^[M[.SK
+MZ^OKZ^KHZ.CK[?#R\_/Q[^SIZ.CIZ^WP\_7U]/+P[_#R\_/P[NSL[O'U^?T"
+M!@D*"PL*"@D("`<&!`'^^_GW]O;W^/GY^?GX^/CY^_S\^_CS[NKFX^'@X>/F
+MY^CHZ>WR^?X``/___OSW\NWJZ.CK[_/V]_?V]_G[_0`$"Q(9'2`C)2@J*B@F
+M)"(@'R$F+3,W.3@U,BXH(!D4$A4:("0G*"@I*2HK+2\Q,S4X/$%'35%45E53
+M3TM&0T`^.SDW-34W.C]#2$M-3D]04E165UA:7F)G:VYP<&]L:&->6%-/3DU-
+M3$I'0CPV,"PI*2DI*BLN,SI!14A(24I,3U%14$]/3U%24E!-245"/CHW-#,S
+M,S0U-C8T,B\M*B<E)2DO-3DZ.SHX-C,Q+RTL*B@F)",D)28G)B4C(B,D)"$<
+M%0\,#1`4&!H<'1\@(!\>'!D6$Q`.#0P*"`4"__W\_/S]_O_^_/KW]/+P[^[N
+M[>WM[>OJZ.CHZNWP\_;Y_/X``0,$!04#`/[\_/S]_OW]_O\!`@(!__SY]O+N
+M[.OK[.[N[N_P\?/U]O;R[>;AWMW>W^#AXN/CXN'AX^?L\O@`!P\7'B0I+"XP
+M,#`O+"DG)B@I*2<C(!P:&1@6%!$.#`P,#0\0$A06%Q<7%A87&!H;'!P<'!P<
+M'!T='1T>'Q\@(B4I+"\Q,C,S-#,Q,"XL*B@H*BTP,C(Q,"\O,#$Q,2\L*"0@
+M'AL9&!<9&QP='!L:&QXB)BHM+RXL*"0A'AP:&!<7%A85%145%145%AD>(R8G
+M)B0B("`@(2`>&Q82#@P-#@X-"0/]^??U\_#MZ^KJZ>?EX^+BX^7GZNSO\?+R
+M\?'Q\O3V^?O]_OWZ]_/P[>OJZ^[R]??V]?7U]OCY^_W_`00&"0L+"@@%`?_\
+M^O?S[^OGY>/BX-_?WM[>WM[>W]_?WM[>X.'CY.3CX>#AY.CN\_;W]_;U]/3S
+M\O#O[N_P\?+R\O'O[>GFY./CX^/CX^+@W]W=W-K7T]#.S,G'Q\K0U]O=W=S;
+MV]O:V-;4TM'1TM34U-+/R\;"OKRYM[2RL+"PL;.VN;N[N[N\O;_!Q,C+SM#0
+MT-'2T]+0S<K)RL[2UMG;W-_AY>CK[>[N[N_P\?'R\_3U]O;T\>WJY^;EY./A
+MW]W<W-[@XN/BX=_<VMC6UM;7U]C8V-C8VMW@XN'>VM71S]#3U]O=W^'DY^OM
+M[O#R]?;V]//S]?CY]_/NZ>7BW]W<W-W=W=W@Y.CK[.[O[^_O\?;\`PD.$1(1
+M#PX.#PX,!P'Z\NKBVM/.R\G&PKVZN;N]P,+"P<"^OK[`PL7'R<S/T=+2T=#/
+MSLW-SM'5VM[@W]S9U=/3U-;7V-?6UM;6V-G;W-S:U]//S<W.S]#0S\_/S]'2
+MTM/5U]O?XN;I[/#S]O?V]//R\?+R\_/T]?;V]O;U]//R\.[KY^3BX>/FZ.CG
+MY>+>VMC6U]K=X.+DY>?I[?'W_0,(#`X-"PH*"@L-#@\."P<#`/[_`0,$!`0#
+M`?[Y]?+Q\?'P[NKFX^'@W]_?X.+DYN7AW-?5U=?<X>7GY^?FY^CK[>[MZ^GH
+MZ>SQ]_S_`0#^^_GW]?3R[^WL[>_S]_O]_P`"!`8'"`@*#!$6&AT='!L<'B`@
+M'AL9&!D:&AD8&!D9&AD9&!<6%1$-"`0"`P8*#A$3%!03$Q,2$1$1$1(2$A$1
+M$Q47%A$,"`<("PP,"@@'"`@'!0,"`P4'"`<&!08(#!`5&AXB)2<H*"@H*2DJ
+M*BHI*"<G)R<F)2,@'1L8%A02$`\0$1(4%!03$Q(3%!46%101#PP+"PT0$A,2
+M$`X-#0P,"PL,#0X/$1,6&!D:&1<7&!H='R`C)BLO,S0T,S,S-#8X.CP^/T`_
+M/S]`0D1'2$A'1$)`/CT]/C]`/STY-3$N+2TN+S(U.#H[.SL[.SL\/3X^/3LY
+M-C4U-C<Y/#X_/CHV,2TK*BLL+C`Q,C(Q,"XL*24A'1H9&AT@(R8H*2DI)R4C
+M(!T;&AH:&QP>'R$C)2<H*"@H*"DJ+"TN+BXM+2PL*RHH)"$?'AX@(B0F)R@H
+M)R0@'!H;'2`B(R(A(2(D)RLO,C0U-30R,"\N+B\P,C$P+2LH)R8D(B`=&QD9
+M&AH;&QL;&AH;&QL9%Q43$A`/#0P,"PH)"`8#`/W[^OO^`0,#`?_\^_O]_P(%
+M"0X3&!P?("`>&Q@6%105%144$Q$.#`H)"0D*"PT.#P\/#P\.#@\0$Q47%Q84
+M$A`/#@T+"0D*#0\1$1`.#0L*"`<&!04%!@<("`<&!04$!`0$!`0$!`,#`P0%
+M!@<'!@4$!`4&"`D*"@H*"PT.#P\.#0T.$!,7&QXA)"DN,C8X.3DY.#<W-S8V
+M-30S,2\L*"4C(B,C(B$@("(E)RHK+"PK*RLJ)R0A'AP;&A<3#@D&!00#`?[Z
+M]O/Q\?#MZ.+<V=G;WN'BX>#AX^;IZ^SL[>WN[_#P[^[M[>SKZ>;CX-[;V=?5
+MU=75UM;6U=/1T,[,RL?$PL"_O;RZN;FZO+[!PL+!O[V\O+V_P<+"PL+#Q<C,
+MT-+2TM+3U=G;W=W<VM?5U-/4U-34TL_+Q\._N[BXN+FZNKFWM;.RLK*TMKF]
+MP,3&R,G*S,[0T]77V=K:VMG7UM?:W>#BX=_<VMG8U]?7UM73T=#/T-+5V-O>
+MW^#@X.#@W][<V]O;V]K8U=/1S\S)Q<&]NKFXN+BWM;*OK*JIJ:JLK[*TMKF\
+MO\/&R<O,S,S-SL_1TM/5UMG<X.3H[/#T]O;T\O#O\/+S]//R\?#O[NWLZNCF
+MX^'@W][=W-S<WM_AX^3DY>7EYN;GZ.ON\O;Z_@(&"0P.$!$3%AD;'1P9%1`,
+M"0@'!@4#`?[[^/7R\?'Q\>_KY^3BX>#@X-_?W][<V]K:V]S=WM[>WMW<VMC5
+MTM'0T='2T]34U=;7V=O=W^#?W=K8U]?9V]W>W]_?X.#@W][=W-S<WN#BY.7D
+MX^+BX^3FZ>OM[N[N[>WO\?3V^/GY]_7T]/;Y_/[^_O[]_O\``@0&!P@)"0@&
+M!`(!```!`P0%!0(`_?KZ^_W_`/_\^OCW]_?X^?K[_/W]_?W^_P`!`/_\^??V
+M]?;V]O;U\_'O[.GGYN?HZ>KL[O+W^P`#!@D)"`8$`O_\^?;T\_+S\_3U]??Y
+M_``%"`H+"PD'!`("`P8("PX0$1(3%!47%Q@8&AP>(2(B(B$@'QX<&A@6%!(1
+M$1$3%AH='R`A(R,C(A\=&QL<'R(E)20A'QT;&QP<'1T>'B`B)"8G)R8F)B<H
+M*2HK+"PM+S$Q,"\M+"PL+2PK*"8C(1\>'A\?'QX='!T>(2(B(1X;&1@8&1H:
+M&1<4$0X,#0X1$A,3$Q06&1XB)B@I*2DJ*RTN+S`Q,C0V.#@V,S`M*R@F(R`=
+M'!P='A\?'AT;&AD9&1D9&AL<'!L<'1X@(2$?'AP;&QL<'!T='AX>'AT<'!L;
+M'!P='B`A(B,C(B`>'1T='AX<&183$1$3%QH<'1X@(R8J+2\O+RXM+2\P,3(S
+M-#,R,"TK*RLK*B<B'1@5%!46%Q@:'!T?(2(C)"0D)"(A'AP:&!84$0X,"@D)
+M"@L,#0\1$Q89&QT>'R`@("`@'QX<&QH:&AD8%Q@9&QT?(2(B(!T:%A(0#P\0
+M$1(4%187&!@7%A86%Q@:'!X@(B,D)24E)"(?'!D7%A86%A44$A`.#`H(!0,"
+M`0``___^_@`"!`4%`P#]^_O\_@$%"0T/$!`/#P\.#0L)!P8&!P<("`<'!@<'
+M"`D*"@H+"PP-#@X-"P<"_OKW]O;W^/GZ^OKZ^OK[_?\``0(#`P4'"`H*"@H)
+M"0D)"`8$`O_]^_O[^_S\_?W^``(%!PD+"PL*"@H*#`T0$Q88&QT='1P<&QP=
+M'1X>'R`B)"4E)2,@'1@4$0X,"@D(!P4$`@$`_OSZ]_7T]/3U]?7U]O;V]?;W
+M^?S^```````!`0,$!0<*#`\2%!04$A$0$!`/#@P*"0@("`@(!P8$`?[[^/?V
+M]_GZ^_OZ^??U\N_MZ^KIZ.?FY>3DY.7EY^GL[O#P[^WKZNGJZ^SL[.SKZ^SN
+M\//V^/GZ^_O\_?W\^OGY^?K[^OCV\_+P\/#Q\O/T]//Q\._N[NWJZ.3@W=K6
+MU-+1T-#0T,[-S,[1U=O@Y.?HY^;FY>7FY^GK[>[O\/#P\/#P\?/V^/KY^/7S
+M\?'S]_P!!08&!`(`````__W[^/7S\O#NZ^CFYN;FY^GJZ^SL[.OIZ.;EX^+B
+MX>'AX>'AXN+BX^+AW][=W-W>X.#@W]W:U]32T=#/SLW+R,7#PL'!P<+$QLG+
+MS,W.S\_0T='1TM/5U=;5U=33T]34U=;7V-G:VMO;W>#DZ.ON[^_O[>OIY^7B
+MW]O8UM74T]'/SLW-S<S+R<C(R<K,SL[.S<W-S,K)R,G-T=79V]S=W^+EZ.OM
+M[N[MZ^GGYN;GZ>KJZ>?DX>#@XN3FZ.KKZ^KIY^7BW]S9UM/0S<K(Q\;&QL;&
+MQL;&QL?'R,G,S]/7VMO;V]O=WN#BX^/DY.3DY>;GZ.CHY^;DXM_<V=;5U-34
+MU=76U]G;W^/H[/#T]O;V]?/R\._N[>WLZNCEXM_>W^'DYN?HZ.GJZ^SN[_'T
+M]?;V]?/Q\._O\/'R\_/T]?;W^/GZ^_W]_OW\^_O\_?[^_?KV\^_MZ^KIZ.?E
+MXN#?W]_?WMW;V=C8V-K>XN;I[?#S]OG[_/S\_?\!!`<*#0\1$1(2$Q,3$A$0
+M$!`/#0L(!0(`__[]_/O\_?\!`@0%!PD,#A`1$`X,"08#`?_^_O[^__\```$!
+M`@0&"@X2%186%1,1#PX-#`L)!@+__?W\_/W]_?\!!`<("`<&!@<*#0\/#@P*
+M"0D+#A`1$`X+"0<&!PD*"PH(!@0"`@,%!P@)"@L,#A`1$A,3$Q(0#PX.#Q$2
+M%!04%!47&AXB)"8G*"LN,C4W.3DX.#<V-C8X.CU`04%!0$!!0D-#0D`^/C]"
+M149&1$%`/T%$1TA)24A'1TA)24E(2$A(24I*2TM*24=%0T%`0$!`0$`_/S\_
+M/S\].S@U,C$Q,C,S,C`N+2PM+C`R,S0U-#0S,C$Q,3(S-38X.CU!1$9&141!
+M/SX]/CX_/SX\.SHZ.SP\.S@S+BHG)2,B(2`>'AX>'A\@(2(B(B(B(R0E)RHL
+M+2TL*RDG)2,B(2$A("`?'AX='A\@(B,C(A\;&!43$Q,2$1`/#@T-#@X0$A89
+M'!X>'AT<&QH8%Q85$Q(1$!`/#PX.#@X/$106&!H;&QL<'1\A(B(B(2`?'!D6
+M$Q`/#@\0$1$1$`\0$A8:'B(E)R<H*"DK+"PJ*"4C(2$A(2$A(!\='!H9&1@8
+M%A,/#`H*"PP-#@T,#`P-#Q(5%QH;&QH9&!D:&QT?'QX=&QD7%A45%1<9&QT>
+M'1P:&1@7%A44$Q(2$A(1$1`/#@P*"`4"_OOX]O;U]//Q\.[LZNGIZ>GK[.WN
+M[_#P\?+R\_/R\O+T]OG\_P(%!P@)"0@'!@4%!08&!@4$!`,"`@$````!`@0%
+M!04$!08("@P,"P@&!04&"`D*"@D("`D+#0\1$Q47&AP>'QX<&1<4$@\.#`H(
+M!@4%!@<'!P8$`@#_``$"`P0$!`0#`@$````"`P0$`@#\^?7R\.WJY^3AW]W<
+MV]K9V-C9V][BY>?GY^?FYN7EY>;EY>3CXN+BX>'@W]W=W-S<V]K8UM75U=;7
+MU];6U=32T,_.S<[/T-'2TM+2T=+2T]77V-G:VMG9V=G9VMG8U];6V-K;W-S<
+MVMG8U];5T]+1T-#/S\[.SLW-R\K)Q\;&Q,/!P+^^O;V]O+R[N;BWM[B[OL'#
+MP\/#PL+"PL+"P+Z\NKFYN;J\OK_`P,'!PL/#P\+!P+^_O[_`P<+$Q<;'R,C'
+MQ\;&Q\C)RLS.T-'1T<_.S<S+S,W0T];8VMO<W=W<W=W>WM[=V]K8U];6U]C:
+MV]W?X.+DY>?HZ>KK[.SKZ^KIZ.CHY^;DX^/DY>;HZ.CGY>+@WMS:V-;5U-+2
+MTM/5V-O>X>/DY>3DY.3DY./BX>#@W][>WMW=W=W=WM[@XN7HZNOKZ^KJZNKK
+MZ^OKZNKIZ>CHZ.GIZNKJZ>?FYN?HZ>OL[.SL[.SM[>[N[N[O\/'R\_7V^/K]
+M_P$$!@D,#A`1$`X+"0@&!00$`P,#`@(!__WZ^/;V]O;W^/CW]O;V]_G\_@`!
+M`0#__O[^_O[_``($!0<)"@L,#0X.#@P*!P/__?OZ^?CU\_'P[_#P\?'Q\?'Q
+M\?'P[^[LZ^GGY>3CXN#?W=S<W=[?X>+DY>;GY^CIZ^WO\/+S]/7V]O;V]O?Y
+M^_W^_OW\^_KY^/?V]?7U]O;V]?7U]O?X^?GZ^_S]__\`___^_?W]_/S\_/OZ
+M^?CX^OT"!@H,#`L)"`@("`@&!0(!`/\```$#!0<)"@H*"@H+#A$3%145$Q(2
+M$Q,3$A`.#`L+#`P-#`L+"@H*"PL,#`T.$!,8'2$D)B8E)20E)B@J+"TM+2TM
+M+2TM+"PL+"TN+R\P,#$R,S0T,S(R,C(T-38V-C0S,C(R,S0U-C<X.CL[.SL[
+M.SP\/3]!0T1$145$0T)`/CLY.#<X.3H\/C]`0#\].SDX-S@X.#8T,2XK*2<F
+M)"$>&A<4$A`0$!`1$1(4%1<9&AL<'!P<'!P<'!L:&1D9&AL<'!H9&!<6%A86
+M%Q<8&!@8&!@7%Q<6%103$A$0#@X.#Q`2$Q03$A$0#PX.#Q`2%!<9'!\A(2$@
+M'Q\A)"@L+S(T-C<W-S8U,S`L)R(=&142$`X-#`L+#`X/$A07&AXA)2@J+"TM
+M+2PL*RDH)R8E(R(A(2$C)"8G*"@I*BPM+S`Q,3$P+BXN+S`Q,C`N*B@F)B8H
+M*2HI)R0A'AP<'!T='A\@(B4H+"\R-#8X.3L]/T!`/ST[.3@V-3,Q+RTM+B\P
+M,3$R,C$O+BTK*BDH)R4C(1X;%Q01#@T-#`L)"`8%!08'"0L,#`P,#0X/$!(3
+M%!04%!05%A<8&1D9&1H:&QP<'!L:&1@7%A86%A44$A`.#0P*"`8$`?_^_?S[
+M^OGX^/?W]_?W^/CX^/?W^/G[_?[_``$!`/_]^_KZ^OO[_/O[^OKZ^_O[^OGY
+M^/GZ_/X!`P0%!`0$!`4'"0H,#`T-#`L*"@H*"PP-#@X.#0L)"`<'"`D*"PH(
+M!@,"`@0&"0P-#@X-#0T-#0P,#0T.#0L)!P4#`@#^_/GV\>WJY^7DY.7EYN?H
+MZ>OL[>[N[^_O\/'S]/7U]?7U]//Q[NKGY./CX^3DY./BX>'@X>'AX>'BXN+B
+MXN+BXN+BX^/DY.3DX^/CY.7FY>3AW][>W^#BX^/BXN'BX^7HZNSM[>OJZ>CG
+MY^?FYN7EYN;GY^CHY^?GY^;DX^+AX>#?W=O8U=+/S,K(Q\;%Q<;'R,G*S=#4
+MV-K<W-S=WN#@X>'AXN/EYN?GYN7DX^+@W]W;VMC7UM;5U=75U=/1SLS)Q\7$
+MPL"_O;V\O;Z^OKV]O;[`P<+#Q<;'Q\?'Q</!OKRYM[6TL[*RM+:XN[[`P\3&
+MQ\G+S,W-S<S,S,W.T-'2T=#.S,O+S,S-S,O)R,?&Q<7#P;^]O+R]OKZ_P,#!
+MP<+"PL+"PL/#Q,7&QL;%Q<7%Q<;&Q\G,S]+6VM[AY>CJ[>[P\/'Q\?'O[NSJ
+MZ.7CX=_>W=S<W-[@XN/DY>;GY^CIZ>KK[.[O\/#Q\?'R\_/S\>_LZNGIZ>OL
+M[O#Q\O+S]/3U]O;U]/+Q\?'R]/;X^?GY]_7S\>_LZ>?EY.3CX>#>W=W=WN#B
+MX^7FYN?IZNSN\?/U]_?W]O;U]O?Y^_W__P#___[^______[^_O[^______[\
+M^OCV]//R\?+R\_3U]//P[.CDX=_?W^#BX^3DX^/CY.;HZ^WO\?/V^OX"!@H,
+M#0T-#`L*"0@'!@0#`@$`__[]_?S\^_OZ^OGY^?KZ^?GX^/GY^?CW]O7V]O;V
+M]_CY^_W_`0,#`P'__?S[^_O[^OGX]_;T\O+R\O/T]O?Z_0$$!@@*"@L+"PH)
+M"0@)"@P.#Q`1$1$0$`\.#0T-#0X.#@\/$!$3%!87&!D9&1D9&1D9&1H;&QH8
+M%Q86%Q<8&!@8&1L='A\@(B0G*BPN+R\P,C0V.#DZ.3@V-#,R,3$Q,"\M+"LJ
+M*RPN,#`P+RXL*RLK*RPL+"PL+"PN+S$R,C(Q,"\N+BXM+"HH)R<G*"DJ*BDH
+M*"@I*RXP,C0U-SD[/D%$1TI,34Y/3T]04%%145%04$].3DU-34Q*1T5#04)#
+M1$9&14-`/3HX-C4U-30T-#,S,S0T,S(Q+RTJ*2DI*2DH)B0C(2`@'Q\@(B0F
+M*"HL+S$S-38X.3DY.3@V,S`M*B<D(1X;&1<4$A`/#@\0$A05%A<6%!(."@<$
+M`@#^_?W]_@`#!08'!P<'"`D*#`T.#@X.#@T-#0T-#`L*"@L+#`T.#@X.#Q`0
+M$1(3$Q04$Q(1$`X-#`L*"0@("`D*#`T.#@T-#`P,#`P-#0X.#@X-#`L)"`<&
+M!0,`_?KX]O;V]_G[_?\``0$"!`8)#1`2%1<:'!X@(2$A(B(C)"4E)20C(R,D
+M)"4E)20D(R,C(R(B(R0E)B<G)R@H*"@H*"@I*BLM+B\O,#$Q,C(Q,#`O+BTK
+M*28D(R(B(R0D)24E)B8F)B8E)"(A'QP:%A,/"P<$`@$```$!`@,$!08'"`D*
+M"PP-#0X-#0P,"PH*"@D(!P4$`@#__OSZ^/7S\O+R\?#NZN;CXN+CY.7DX^+A
+MXN/EY^CIZNGIY^;DXN#>W-K9U];5U=34U-34U-35UM?9VMO<W-W>X.'CY>7E
+MY>3DY.;HZNSN[N[N[>[N[^_P\?+S]/3S\O'P\/#Q\O+S\_/T]/7U]?7V]_G[
+M_@$$!@@*#`X0$1(3$A$/#@P*"`<&!00#`0#__O[]_/OX]/'MZ^KIZ>GJZNKJ
+MZNKKZ^SM[>SJZ.7CXN'AXN3EY>;EY>3DY.7GZNWO\?/U]_G[_?[^_OW\^??S
+M[^OGX^'>W-O:V-?5T]+1T-#1T='2T]35UM?8V-G9V=G9V=K:V]S=WM_AX^7G
+MZ.GHYN3AWMS;VMG8U];4U-/2T=#/SLS+RLG(R,G)R<K+S,W.S]#0T-#0T-'2
+MU-76U]C8V=G:V]S=WM_?X.'BX^3EY.3CX^+AX>#?W]_@X.#@WMS;VMK;V]O;
+MV]K9V-?7U]C9V=K9V-;4T<W*Q\7#P<"_O[_`P<'!P<'"P\3&Q\C*S,_2UMK=
+MX.'CY>;HZ>KK[>_R\_/S\_/S\_+Q\.[M[.OKZ^KIZ.;CX=[=W-S<V]O:V-?7
+MU]C9VMO;W-W=WM[=W-K9V-C8V-G:V]O;VMG9V=O=X./GZN[Q\_7V]_CX^/CW
+M]O3S\?#O[NWL[.SKZNKIZ.CIZNOL[>WN[N_P\?+Q\?#O[^_N[>OIZ.;EY>7E
+MY.3CX^/DY>;IZ^[P\O3V]_G[_/W]_?W]_?W]_O[__P```/__```!`@,#!`0$
+M!08'"`H,#0T-#`L*"0@'!@4$`P$`_OW\^_KY^/CX^?O\_?[^_OW]_/SZ^?;T
+M\_+R\_3V]_GZ^_S]_?[_``$"`@,#`P,$!`0#`0#^_/OY^/?W]_CY^_S_`00&
+M"`H+#`P,"PH*"0H*#`T0$A48&QTA)"<K+C$S-3<X.#<U,S`M*B4@&Q82#PX-
+M#A`2%!89&QP='AT='A\@(B,D(R,B(2`@(2$A("`?'Q\?'Q\?'AL8%!`,!P0!
+M____``#__OW[^_O\_@`#!0<("0@'!@4$`P,$!08'"`@(!P<&!04%!@<("`D*
+M#`X0$1(1$1`0#P\/$!$1$1`.#`D'!@8&!P@*"PP-#@X/$1,5%QD;'1X@(2,E
+M)RDK+C`T-SD[/#X_04-%1TA(1T5"/SPZ.CH[/#P\.SHY.3H[/3X^/CT\.SLZ
+M.3@W-30R,"TK*2@G)B4C(B$A(B0F)R@I*"@H*"@H)R4C(1\>'1T<'!P='1X?
+M("$B(R0D)24E)B@H*2DH*"8E(R(@'QT;&A@8%Q<6%A45%146%Q@8&1@8&1D;
+M'!X@(2(C)"8G*"HK+2XO,#$Q,"\M+"PK*RLL+"PK*RDI*"<G)B4D(B$@("$B
+M(R0E)",@'AP;&QP>'R`?'Q\?(2,E)R<G)R4D)"4F)R@H)R4D(1\=&Q@6%!$.
+M"P@&!`,"`?_\^?;S\?#P\?+R\_/R\>_MZ^CFY./CX^3FZ.KM[N_N[NWL[.OK
+MZ>CGY^GJ[>_P\?'R\O/U]_CZ_/\``@,$!@@)"PT.#PX.#`L*"@H*"@D)"`<&
+M!00"`?____[^_?SZ^?CW]_CY^_W_`0,%!@<("@L,#0T-#0T-#0X/#Q`1$1(2
+M%!47&!D8%Q43$`X,"PL*"@H*"PL+"PP,#`P+"@<%`O_]_/O\_/W]_O\``@4(
+M"PT/$1,4%187%Q@7%Q44$A`.#0P,#`P-#0X/$1,6&!H;'!T='1P;&1@7%Q87
+M%Q<8&!D9&QP='R`@(2(B(R,C(R,A'QP9%A,0#@P+"@D(!P4#`@$```#___[]
+M_?W^_O[^_OW\^OCW]O7U]//R\.WJYN/@W][?X.'AXN+BX>'@X-[=W-O:V=C7
+MUM32T,W+R<?&Q<;&Q\C(R<G)R<G)R,C'Q\?'Q\?'Q\;%Q<3$P\/#PL'`P+^_
+MOKV\N[FWMK6VM[FZO+V^O\#"P\3%Q\C*S,W.S\_0T='1T=#/S<W-S<[.SL[-
+MS<[/T=/5U]C9V=C8V-C8V=K;W-W>X.'BXN/DYN?IZNSL[>WN[N_P\O/T]/3S
+M\?#O[^_N[>SKZ^KJZ>GGYN3BX-W;V=?5T]'.S,G'Q</"PL/$QL?)RLS-S]#2
+MT]35UM;7V-G;W-S<V]K9U];5U-/3TM'1S\[,R\K*R<K*R\O,S,S,S,W.T-'2
+MT]34U=75UM?8V=K:VMG9V=G:V][@XN3EY^CIZ^SM[>[N[NWM[.SL[.SM[N[O
+M[^[N[N[N[^_P\/#P\/#O[NWM[>WN[_#Q\O+S\_/T]?;X^OO\_?W]_?S[^OCV
+M]?3T]/3T\_'O[.GGY>3CY.7FY^CIZ>GIZ>GIZ>KK[>_R]??Y^OKZ^OKZ^?GX
+M]_;U]//Q\.[LZ^KIZ>GIZNKK[.SL[.SKZNGHZ.GIZNOK[.SKZ^SM[_+U^/O]
+M``($!08'!P<'!P8&!04$!`0%!04%!04%!`0$`P,#!`4&"`D)"@L,#0\1$Q05
+M%A<7&!@8%Q86%A<:'2$D)B8F)B4E)28G*2HK*BDG)2,B(2`?'AT<&QH9&!85
+M$Q$/#0L)!P4#`0#__P`!`P0%!@<'!P@)"PX0$Q47&1P>(2,D)24E)"0D)"4F
+M*"DK+"PL*RHJ*2DI*2@G)B0C(B`@("`@("`?'QX='!L:&!<5%!,2$1$1$1$1
+M$A05%A86%A87&1L?(B4H*2HJ*BDI*2@H*"<G)B8F)B8F)B8E)20D)",C(B(A
+M(!X=&QH8%Q<6%A<8&1H;&QP='1X?'R`A(R0E)R@H)R8E)"(A(2`?'QX>'1T<
+M&QL;'!T>'1P;&QH:&AH:&1@7%1,0#PT,#`P,#`T-#0X.#Q$2$Q46%QD;'B`C
+M)"8G*"DJ+"TO+R\N+BXO,#(T-#0T,S(Q,#`O+BPI*"<G*"DJ*BHI*"8E)"(A
+M(!\='!L:&1@7%1,0#@L(!@4$`P,$!@<)"PT/$1,4%145%187&1H;&QL:&!<6
+M%A86%A86%A45%145%145%!,2$1$2$Q46&!D:&AH:&AH:&AH:&AH9&1@8&!@8
+M&!@7%A44$Q,2$A(2$A,4%!47&!D:&AD8%Q<7%Q@8&!D9&AL;'!P;&QL;'!T>
+M("(C(R(A'QX='1T<&QD7%!(0#P\/#P\.#@T-#0T-#0T.#@\/#PX-#`L)!P4#
+M`0#^_/KX]O3S\O'P[^[N[>WM[>SLZNGGY>/BX>'AXN/CX^/BXN+CY>;HZNOL
+M[>[N[_#R\_3S\_+Q\?+S]OCZ^_S]_?[_```!`0$!`0```````/____[^_?W\
+M_/S\_@`"!`4&!P@("0H*"PH*"0@&!@8&!@8&!@8%!`,!__[]_?W]_/OY]_;T
+M]/3U]O?X^/GY^?GY^/CX^/?V]/'NZ^?CX-[<V]K9V-?6UM74T]+2TM/4U=;8
+MV=K;W-W>W^'BX^3EY^CJZ^SM[>WL[.KIZ.?FYN;FYN7DX^/CX^/BXN+AX>+B
+MX^3EYNCIZNOKZ^OKZ^SN\/+T]O?X^/GZ_/W^_O___O[^_?W\_/OZ^?CW]_?X
+M^?K[^_S\_/O[^?CV]/+Q[^WKZ>?DX=_<V]K:V]S>W^#@X.#AX>'BX^/CX^/C
+MXN#=VM;2S\O)QL/`OKR[N[JZN;>VM;6UMK>XNKR]OK_!PL/$QL?'Q\;$P\/#
+MQ,7'R,G+R\S,S,S+R\O+S,W.T-'1TM/5UM?8VMO<WM_@X.'BXN+AX-_?WM_@
+MX>+CY.3EY^GK[>_P\?+S]/7V]_CX^/?V]?/Q[^[L[.OJZ>CGYN7DX^/BXN+B
+MXN/EY^GK[>[O[_#Q\O+S\_/S\O'P[^[M[.SKZNGHYN7EY>7EY>;GZ.GJZ^WN
+M[_#Q\O/S\_/S]/3U]?7U]//R\?'Q\O+S\_/R\O+S]?CZ_?\``0(#!`4'"`D*
+M"0@&!0,"`0$!`/_^_?S[^OKZ^OKY^?GY^OO\_/W]_?[^_O[]_?S[^??V]?3T
+M]/7U]?7V]_?X^?GZ^?GY^?KZ^_O[^OGY^/CX^/GZ^OKZ^?GX^/CX^/GZ^_O[
+M^_KZ^OGY^?GZ^OO\_O__`````0$"!`4&!@8&!@<'"`D*"PL*"`8%!`,#!`4&
+M!P@("`@("`@("0L+#`T-#@\1$Q06&!D:&QL;&QL;&QP<'1T='1P;&AD7%A44
+M$Q,3$Q,3$A$0#PX,"PH)"`@("`D)"0D)"@H+"PP,#0X0$1(4%186%Q<7%Q86
+M%A85%145%145%!04%!45%A85%!,2$1$1$1`0#PX-#`P,#0X.#Q`0$!$1$1$1
+M$1$0$`\.#0L*"0@(!P<&!04%!@<("@P-#@\/#@T-#`P-#@\1$A,4%187&!@8
+M%Q<6%104%!04%!04%!04%!04%!45%Q@9&1D8%Q43$A`/#Q`0$1$0#PX,"PH*
+M"PP-#Q`1$A(4%1<8&AP='1T>'R`B)"4F)B4D)"0D)"4F)R@H)R4C(2`?'Q\@
+M("$A(2(C)"8H*BPM+S`P,3(S-#4V-C8U-#,R,3`P+RXN+2TL+"PM+2\P,3$R
+M,S,S,S,S,S,S,C(R,C(S,S,R,C$O+BPJ*"8E)"0D)",C(R,C)"4E)28F)B8F
+M)B8F)20C(2`?'QX>'AT<&QH8%A44%!04%!04%!03$Q,2$A(1$A(2$Q,3%!47
+M&!H;&QL;&AD9&!<6%104%!45%145%!(0#@T-#0X/$!(3%!45%104%!,2$1`/
+M#0P,"PL+"PL,#`P+"PH*"0D*"@L,#`P-#`P-#0T.#@\/#P\.#@T,"PH*"0D(
+M"`<&!@8'!P<(!P<&!04%!08&!@4$`P(!`````/____[^_O__``````#__OW[
+M^_KZ^_S]_O_____]_/O[^_O\^_OZ^?GX^/CX]_;U]/3T]/3T]/3T]/3T]/3T
+M]/3S\_+Q\._N[>SKZNGHY^;FYN;FY^?GYN7EY>7EYN;FYN?HZ>OM[_'R\O/S
+M]/7W^/GZ^OGX]_;U\_+Q[^[M[.SKZNGHY^?GY^?GZ.CHZ>GJZ^SL[>[N[^_O
+M[NSKZNGIZ>GIZ.CGYN7DX^/BXN'AX>'AX>+BX^/DY./BX=[<V]G7UM33T=#0
+MT-#2T]35U=;6U]C9VMS>X.'BXN/CY.7FY^?GY^?FYN;FYN?HZ>GIZ.CGYN;F
+MYN;EY>3DXN'?WMW<W=[?X>+BXN+BX>'AX>'AX>'AX.#@W]_?W]_@X.#@X>'B
+MX^7FY^CHZ>GIZ>GHZ.CGYN;FYN;FYN7EY.+AX-_>W]_@X>+CX^/BXN/CY.;G
+MZ.GJZNGIZ.;EY./BXN+AX>'@X>'BXN/CY.3DY>;GZ.GJZNKJZNKJZNKJZNGH
+MY^;EY./BX>#@W]_?W]_@X>+CX^/DY./CY.3FY^CIZ>CGY^;FY^CHZ>KJZ^OK
+MZ^SL[>WM[.SM[>[N[NWLZNGHY^?GY^?GYN;FYN;FY>7DY./DY.3EY>7EYN;F
+MY>7DX^+BXN+BXN/CX^3DY.3DY./CX^/DY.7EY>;EY>;GZ.KL[_'S]/7V]O;V
+M]_?W]_CX^/CW]O7T\O'P\/#P\/#O[NWLZ^OJZNKJZ>CFY>7FZ.KL[_+T]_G[
+M_@`"`P0#`P(!```!`0$!`/_^_?W\_/W\_/S[^OKY^?GY^?CX^/CX^/CX^?GY
+M^OK[^_OZ^OKZ^OO\_?\``0(#!`4&!P@*#0\1$Q04%!05%145%145%186%A<7
+M%A87&!D:&QP<'!P<'1\@(2$A(!\?'AX='1P;&A@6%!(1$`\/#P\/#P\/$!`1
+M$1,4%1<9&QT?(2(C(R,C(B$@'QT;&A@7%Q85%102$1`.#0T-#0X/#Q`0$`\/
+M#Q`0$!`0$1$1$1(2$Q,4%!46%A86%145%A87&!D:&AH:&QP<'1X>'R`A(2(B
+M(B(B(B(B(2$A(!\?'AT<&AD8%Q85%145%186%Q86%144$Q,4%!05%!03$Q,3
+M%!05%145%145%A87&!@9&1H;'!T>'R`A("`?'AT<&QH:&AD9&!<7%A86%A87
+M%Q@9&AL<'1T='1P:&1<6%!,3$A$0#P\.#@X.#P\/#Q`0$!`/#Q`0$!$2$Q,4
+M%!,3$A(3$Q04%145%144%!03$A$1$!`0$!$3%!46%Q<7%Q@8&1H;&QL<'!T=
+M'AX>'A\@("$B(R,C(R,C(R0D)",C(B(A'QT;&185$Q(1$`X,"PH)"0H*"PT.
+M#Q`1$Q05%A<8&!@8%Q<7%A86%A86%A45%186%QD;'1X@(2(C(R,C(R,C(R,D
+M)"4E)B8F)24E)",C(B(A(2$A(B,C(R,C(B$@(!\>'1L:&1<5%!,2$A,4%A@:
+M'!T?(2,E)RDI*2<E(R$@'AT;&A@7%A03$A$1$1(3%!04%!,2$1`0#P\.#0P+
+M"@@&!00$`P,#`P(!`/_^_?S\^_O[^OKY^/?V]?7U]?7U]?7U]//S\_/R\O+Q
+M\._N[N[N[^_O[^_O[_#Q\_3V]_CY^?GZ^_O[^_O[^_O[^_KZ^?GY^?CX^/CX
+M^?K[_?[_``$!``#__O[^_?W^_O[_```!`0(#`P0$!`,#`P,"`?_^_/KX]O7S
+M\O+Q\?#Q\?+R\_/T]?7V]O;W]_CY^?GY^/CW]O7U]?7V]_?X^?GZ^_S\_/S[
+M^_O\_?W]_?W\^_O[^_O[_/S\_?[^_P```````0("`@(!`````````/___OW\
+M_/OZ^?CW]?3S\O'P\._O[^_O[^_O[N[N[^_O[^_O[^[N[^_P\?+R\O+R\O+S
+M\_3T]/+P[NSJZ>CGYN;FY>7CXN#?W=W=W=[>W=S:V-;5U-34U-/3T]+2TM/3
+MT]/3T]/3T]/2TM'1T=+2T]/3TM+2T='1T='1T='1T='1T='2T]/3T]+1T,_/
+MS\_/S\_/S\_1TM37V-K;W-S>W^'BX^3DX^/BXN'@X-_=W-S<W-W=WMW<W-O;
+MV]S=WM_AXN3FY^CIZNSM[N_Q\?+S]/7W^/CX^/?W]O;V]O;V]O;V]O;V]O7U
+M]?7T\_/Q\._N[>SL[.SKZNGHY^?GY^?GYN7EY./CX^+BX>#?WM[=W-S<W-W=
+MW=W=W=W=W=[?X.'AX>#?WMW=W=[?X.'AXN+CX^3EYN;FYN;FYN7EYN;GY^CH
+MY^?FY>7EY>;GY^?GY^?GY^CHZ.CHY^?FYN7EY>7EYN;GY^?GY^?HZ.CIZ>GH
+MY^;EX^+@WMW<V]K:V=G9VMO<W=[?X.'AXN/DY>;GZ.CHZ.CHY^?HZ.GJZ^SN
+M[_#Q\O/S\_/S\O+R\?'Q\?'R\O/T]?;W^?K\_@`!`P4&!P@("`@'!P<'!P@(
+M"`@("`@("0D)"0D(!P<&!04$!`0#`P(!`0````$!`0("`@,#`P("`@(#`P0%
+M!08%!04%!04%!04&!P<("0H+"PP,#`T.#Q$3%!87&!D:&AH:&1D9&!@8&!<7
+M%Q<8&1H<'A\@(2$A(2$@(!\>'!L9%Q85%!,2$1`/#@X-#0T.#Q`2$Q05%A<7
+M%Q<8&!@8&1D9&!@8&!<7%A44$Q(2$A$1$1`0$!`1$A,5%QD;'1\@(B,D)28G
+M*"DJ*RLK*BHI*"@I*2DJ*BDI*"@H*"DJ*BLK+"PM+C`R,S0U-C4U-#(Q+RXM
+M+"LJ*"<E(R$@'AT<'!P<'1T='1T>'A\?("`?("`A(2(C(R(B(2$A(2(B(B$@
+M'QX=&QL:&AH:&QP='AX?("`A(B,D)B<I*BHK*BHI*"<F)20C(1\=&A@6%1,1
+M$`X,"PH)"0D)"@P-#A`1$A(3%!05%A@9&AL<'!T='1T<'!T='1T='1T<'1T=
+M'AX>'AT<'!L:&AD8&!<6%144%!05%!04$Q,3$Q,4%!45%144$Q(1$1$1$1(2
+M$Q,3%!46%Q@8&!D9&1H;&QL;&AD8%Q86%104$Q$0$`\.#@T-#0T-#0T,#`P,
+M#`P,#`P+"@@'!@4$`P(!`/_^_?W^_O[___\```(#!0<)"PP-#@\0$!$1$1$1
+M$!`/#@T,#`L*"0D("0D*"PP-#@\/$!`1$1(2$Q46%Q<7%A85%!,2$A(1$1`/
+M#@T-#0X/$!`1$!`/#P\/#Q`0$!`0#PX.#0T,#`P,#0T-#@X.#@X.#@T,"PL*
+M"@H)"0@(!P8%!00$!`4&!P@("`@'!P8&!P<("`@("`<'!@4%!00$`P(!`/__
+M_P```/____________[^_?S[^OKY^/?V]?3T]/3S\_+R\O'Q\?'Q\?+R\O+R
+M\_/S\_/T]/7V]_CX^?GX^/CW]O;U]//R\?#P[^[M[.SL[.SLZ^OKZNKIZ.CF
+MY>7DX^/CY.3DY>;FYN;FY>3CXN'AX>+BXN+BXN'AXN+CY.3EY>7EYN;GY^CH
+MZ.CGYN7EY>7EY>7DY.3CX^/CX^/CXN+BX>'@W][=W-S<W-W=W=[>WM[?X.'B
+MX^/CX^+AX-[=W-O;V]S=WM[?X.'CY>?IZNSM[N[O[_#P\/#P\?'Q\?'Q\?#P
+M[^_O[N[M[>WL[.OKZNKIZ>GHZ.?GY^?HZ.GIZ>GIZ.?FY>/BX>'@X.#@X.#@
+MX.#@W]_?W]_?W]_?W]_?W]_?W]_?X.#@X>'BXN+BXN'AX>'BX^/CX^/CXN+C
+MX^7FY^CIZ>GIZNKJZNKIZ.;EY.3CX^/DY./CX^/CX^3DY>;FY^CHZ>GJZ^SN
+M[_'S]/;X^OO\_?W]_?S\_/O[^OGX]_?V]?3S\O'P\/#P\/'Q\?#O[^[MZ^OJ
+MZ>?FY>3CXN+AX>'AX.#@X.#@X.#AX>'@X.#@W]_?W]_?W^#@X.#AX>+CX^/C
+MX^/CXN+BXN/CX^/CX^/CX^3DY>7EY>7FYN;FYN;FY>7EY>7FYN?GZ.?GY^;F
+MYN;GZ.GJZ^SL[>[O\/#Q\O+S]/3U]?7T]/3S\_+R\O+R\_3U]OCY^OO]_@`!
+M`P4&!P@("0D)"`@'!P<'!P<'!P<&!@8'!P<("`D*"@L,#`P,"PL+"PL+"@H)
+M"0D)"0H+"PP+"PL+"PP-#0X/$!`0$!`/#P\.#0T-#0T,#`L*"@H*"@H+"PH*
+M"@D)"`@("`@)"@L,#0X/#Q`0$1$1$1$1$1$1$1`/#0P,#`T.#Q$2$Q46&!D:
+M&QL<'!P<'1T='!P<&QL:&1D9&1D9&1D9&!@8%Q86%103$A$0$!`0#P\/#@X-
+M#0P,"PL+"PL*"@H)"0D("`@("`D)"@L+#`T-#@\/$!`1$1(2$A(2$1$1$!`0
+M$!`0$!`0$!`1$1(3%187&!D9&1D9&1@8&!<7%Q<7%Q<7%Q<8&!D9&AL;'!P=
+M'1X?(2(C)"4E)B8F)24E)24E)28F)B<G)R@H*"<G)B8E)"0C(B(A(2`?'AX=
+M'1X>'AX='1T<&QL;&QP<'1X>'R`@("$A(2(C)"0E)24D)",C(B`?'AT<&QL;
+M&QH:&AH:&AH9&!<6%104$Q,2$A$0#@T,"PH)"`<'!P<'!P<&!@8'"`@)"0H*
+M"PL+#`P,#0T-#@X.#@X.#@X/#Q`0$1$1$!`0$!`0$!`0$!`0$!`0$!`0$!$1
+M$1`/#PX-#`P,#`T-#0T-#`L+"@H*"@L+#`P,#0T-#@X/#Q`1$A,3%!05%145
+M%145%!03$Q,3%!04%!45%!03$Q$0#PT,"@D)"`<&!00"`0````````$!`0$!
+M`0$"`@,$!04&!P@)"0H+#`T/$!$2$Q,3%!04%!03$Q,2$1`/#@X-#0T-#`P,
+M#`P-#0T.#@\/#P\/#PX-#0P+"@D("`@("0D*"@H)"0@("`@(!P<'!@8%!04%
+M!04&!@8%!04%!`0$!`,#`P,#`@("`@$!`/_^_?W\_/OZ^?CW]O3S\_+R\?'P
+M\._O[^_P\/'R\O/S]/7V]_?X^/GY^?GY^?CW]_;V]?7U]?3T]//S\_3T]?7U
+M]?3U]?7U]?7U]?7T]//S\O+Q\?#O[N[M[N[N[N[O[^_P\/'R\_7V]_G[_/[^
+M______[^_?W\^_OZ^??V]?7T\_/R\O'Q\/#P\/#P\/#P\/#O[^[M[>SLZ^OK
+MZNKIZ.?FYN7EY.3DX^/BXN+CX^3EYN?HZ>GJZNOL[>[O[^[N[>SKZ^KJZNKI
+MZ>CGY^;EY>3DX^'@W][=W=W=W=W=WM[>WMW=W=W=WM[?W]_>W=W<W-S<W=[?
+MX.'BXN+BXN'AX.#@W]_?W^#@X.#AX>'AX.#@W]_?X.#@X.#AX>+CY.7EYN;F
+MYN;EY>7EY>7DY./CXN'?W][>W=W=W=W<W-S<W-S<W-W=WM_?X.'AX>+BXN/C
+MY.7FY^?HZ.GIZNOL[>[N[^_O\/#Q\?'Q\?'Q\?'R\O+Q\?#O[^[N[N[M[>SL
+M[.SL[.WM[N[O\/#Q\O/S\_3T]?7V]_?X^/CX^?GY^OK[^_O[^_O[_/S\_?W]
+M_?W\_/S\_/S\_?W\_/S[^_O[^_S\_?[^_P`!`@(#`P,#`P("`@$!`0("`@$!
+M`0```0$!`0#__OW\^_O[^_OZ^OKZ^OGY^OKZ^OKY^?GX^/?V]?7T]//S\O+R
+M\O+R\O/T]?;W^/CX^/CX]_;V]?/S\O'P\/#P\/'Q\?+R\_/T]/7U]?7T]//S
+M\_/S\_/S]/3T]?7V]O?X^/GY^OKY^?GY^?GZ^OK[^_S\_?[^_O_______O[^
+M_O[^_?W]_?W]_?W]_?W^_@`!`@,$!`4%!`0$`P,"`0$```#______P````$!
+M`0("`@("`@("`@("`@("`P0%!@<("0H*"PP-#@\/$!`0$!`0$!`0$1(2$Q05
+M%A87&1H;'1X@(2$B(B(B(2$A("`?'QX>'AX>'AX='1T='1T>'AX>'1T='1T=
+M'A\?("$A(2$A(2`@'Q\?'AX>'AT='!L;&AH:&AH;&QP<'1T='AX>'A\?'QX>
+M'1T<'!P<'!L;&AH9&!@8&!<7%Q<7%Q<6%A45%145%A86%Q<7%Q<7&!@8&!D9
+M&1D9&!@8&!<6%A85%A<7&!@9&!@8&!<7%Q<7%Q86%A44$Q,2$1$0$!`0$!`/
+M#Q`0$1(3$Q,4%!05%A87%Q<7%A44%!,3$A(2$A(2$A(3$Q04%186%Q<7%A85
+M%145%144%!03$Q,3$Q(2$A$0#PX.#0T-#0T.#@\/$!`1$A,3%!45%145%186
+M%A85%144%!,3$Q,3$Q,3$Q,3$Q,2$A$0#PX.#0P+"PH*"@H+"PL,#0T.#@\/
+M#P\/#P\.#@T-#`P,#`L+"@H)"0D)"@H)"0D("`D)"@H*"PL+"PP,#0T.#Q`0
+M$`\.#0P+"@D(!P8&!00#`P("`@$!```!`0$"`@("`@("`@("`@(!`0`````!
+M`0$!```````!`0("`@(#`P,#`P("`0#__OW\^_KY^?CW]_?V]O;U]?7V]O?W
+M^/GY^OK[_/S]_O__``$"`@(#`P,#`P,#`P("`@$!`0````#____^_O[]_?W\
+M_/O[^_S\_?W]_O[^_O[__P``````__[]_/KZ^?CW]_;U]?3T]/7U]?;V]O;U
+M]?7T]//S\_+R\?#O[N[M[>SLZ^OKZ^OKZ^OKZ^OKZ^OJZ>GHZ.CHZ.GIZNOL
+M[>WN[N[M[>WM[N[O\/'R\_3V]_CY^OO\_/S\_/S\_/S\_/O[^OGY^/?V]?3S
+M\_+R\O/S]/3T]?7U]?7U]O;V]O;U]?3T\_/S\_/T]/7U]?7U]?7U]O?X^?GY
+M^?GX^/?V]O7T\_+Q\/#O[^_O[^[N[>WL[.OKZNKJZ>GHZ.?FYN7EY>7DY./C
+MXN+BX>'AX.#?WM[=W=W=W=W>WM_@X>'AXN+BXN+CX^3DY.3DY.3DX^/BXN+B
+MXN/DY>;GY^?GY^?GY^?HZ>GJZNKJZNKKZ^OL[.SLZ^OKZ^OKZ^OL[.SL[>WN
+M[N_P\/'R\O/S]/3U]?7U]?;V]O;V]O7U]?7U]?7T]/3T]//S\_/S\_3T\_/S
+M\O'P[^_N[>WM[>WM[>[N[N[N[N[N[N[O[^[N[N[N[^_P\/#P[^_O[^_P\/'R
+M\O+R\O+Q\?'Q\?'P\/#P\/'R\_3U]O?X^/GZ^_S]_?[_`````0``___^_?S[
+M^_O[_/S]_O\```$"`@,#`P,#`P,#`P,"`@$!`/___________O[^_O[^_O[]
+M_?W\_/S\_/S\_?W]_?[^_O[_____````___^_OW\_/O[^OKZ^?GY^?KZ^_O]
+M_O\!`@,$!08&!@<&!@8%!`0#`P("`0#__OW\_/S[^_O[_/S]_?[^_O______
+M``````#_____```!`@,$!`4%!@8&!P<'!P@("0D*"PP,#0X.#P\/$!`0$!`/
+M#PX.#0P,"PL+"PL,#`T-#@X.#@X.#@\0$1(3%!46%A87%A85%103$Q(1$1`/
+M#@P+"0<&!`,"`0````````$!`@("`P,#!`0$!`0$!`0%!08&!@<'!P<'!@8%
+M!04%!`0%!04&!@<("0D*"PL,#`P-#`P,"PH)"0@(!P<'!@8&!@8'"`D*"@L+
+M"PL,#`T.#P\0$1$1$1$1$1$2$A,4%146%Q<7%Q86%144$Q,3$A(2$A(2$Q,4
+M%146%A87%Q<8&!@8%Q<7%A44$Q(2$1$1$1(2$A(2$A(2$A(3$Q04%!45%145
+M%145%145%144%!04%!,3$Q,3%!04%!04%!04%!,3$Q(2$A(2$A(3$Q,3$Q,4
+M%146%Q@9&AL<'!T>'Q\@(2$A("`@'Q\>'AT<'!L:&1D8%Q85%!,2$1$0$`\/
+M#@T,#`P,#`T-#@X/#P\0$!`0#P\.#0P+"@D)"`<'!P8&!@8&!@8&!P<'!P<'
+M!P8&!@8&!@8&!04$!`,#`P("`0$``/____\```$"`P0$!04%!04%!00$`P(!
+M`/__________```````!`0$"`@,$!`0$`P,#`P,#`P,#`P("`@("`@("`P,#
+M`P,#`P,$!`4%!04%!04%!`0$`P,"`@(#!`0%!@<("`@("0D*"PP,#0T.#@X.
+M#0T-#`P+"PH*"0D("`@("`<'!P<&!@8&!P<'!P<("`@("0D("`@'!@4$!`,"
+M`@$`__[]_?[^__\``0$"`P0$!04%!04$`P,"`0$!````______[^_O[^_O[^
+M_O[^_____P````$!`0$!`0``_________OW]_/OZ^?CV]?3R\?'P\/#P\/#P
+M\/'Q\?'R\O/T]/7V]O;V]O;U]?3S\O'P[^[N[>WM[.SL[.SKZ^OL[.SL[.WM
+M[>WM[>SL[.OKZNKIZ.CGY^?GY^?GY^;EY>3DY.7EYN;FY^?GZ.CHZ>GJZ^SL
+M[>[N[^_P\/'Q\?+R\O/S\_/S\_+R\?'P\._P\/#P\?'Q\?'Q\?+R\_3T]?7V
+M]O;V]O;W^/CY^?KZ^?GY^/CW]_;V]O7U]?7U]?7U]/3T\_/S\_+R\O+R\O/S
+M\_/S\_/T]//S\_/R\O'Q\._O[NWLZ^KJZ>CHY^?GZ.CHZ>GIZNKIZ>GHY^?F
+MY>7EY>7DY.3DY.7EYN;GY^CHZ>GJZNKJZNGIZ>CHZ.CHY^?GYN;FY>7DX^/B
+MXN+BXN+BXN+BXN+CX^3EY>;GZ.GJZ^SM[>[N[^_P\?'R\O+R\?'P[^[N[>WM
+M[>WL[.SKZ^KJZ>GIZ>CHZ.CHZ.CHY^?GY^?GY^?GZ.CHZ.GIZ>GJZNKJZNKJ
+MZ>GIZ>GJZNKKZ^SL[>[N[N_O[_#P\?'R\O/T]/7U]O;V]O?W]_CX^?GY^OKZ
+M^?GY^/CW]_?W^/CX^?GY^OK[^_O[_/S\_/S[^_O[^_O[^_S\_/S]_?[__P``
+M`0$!`0$"`@(#`P,#`P0$!`4%!08&!@8&!P<'!@8%!00$!`0$!`0$!`4%!@<'
+M"`D)"0D*"@H*"@D)"0@(!P<'!P<'!@8&!@<'"`@)"0D*"@H)"0D)"0D("`<'
+M!@8%!00$!`0$!`0$!04%!04&!@8&!@8&!04%!@8&!P<'!P@("0H+#`P,#`P+
+M"PL*"@H*"@H*"@H*"@H*"@H+"PL+"PL+"PL+"PL+"PL+"PL+"PL,#`T-#0X.
+M#@\/$!`0$1$1$A(3$Q,4%!05%145%145%186%A86%A87%Q<7%Q<7%Q<6%A45
+M%!,3$Q(3$Q,3$Q,3$Q,3$Q,4%!04%145%145%!04%!03$Q(2$A$1$1$1$A(2
+M$A(2$A(2$Q,3$Q,3$Q04%!45%145%145%145%!04$Q,2$A$1$!`0#Q`0$!`0
+M$!`0$1$1$A(2$Q,3$Q04%!04%145%146%A87%Q<7&!@7%Q<7%Q<7%A86%145
+M%186%Q<7&!@8&!@7%Q<7%A86%A85%145%104%!04%144%!,3$A$0#PX-#`P+
+M"@D(!P8%!`0#`P("`@("`@("`@,#!`0$!`0$!`0#`P,#`P,#`P,#`P,$!`4%
+M!@<("0D*"@L+#`T-#@X.#@X.#@X-#0T-#0T-#0T-#0T-#0T-#@X.#P\/$!`1
+M$1$2$A(3$A(2$1$1$1`0$1$1$1(2$A(2$A(2$1$1$!`0$!`0$`\/#P\/#P\/
+M#P\/#@X-#0P,#`P,"PL+"@H)"0@(!P<&!@8&!@8&!P<'"`@)"0H+"PL+#`L+
+M"PL*"@H*"0D("`<&!00#`0#__OW]_/O[^OGY^/CW]_?W]_?W]_?W]_?W]_?V
+M]O;W]_?W]_?W]_?W]_?V]O;V]?7U]?7T]/3T]/7U]?7U]?7U]?7U]?7T]/3S
+M\_+R\O+R\O+S\_/T]/7U]?;V]_CX^/CX^/?W]_;V]O7U]?3U]?7U]?7U]/3S
+M\_/S\_/S\_/S\_3T]/7U]?;V]_CX^?GZ^OKZ^OKY^?CX]_?W]_?W]_?X^/CY
+M^?GY^?GY^?GY^?GY^?CX^/CX^/CX^/CY^?KZ^OKZ^OKZ^OKZ^OGY^?GY^?CX
+M]_?V]O7U]?7U]?7T]/3T]/3T]?7U]?7U]?7U]?7U]?3T\_/R\O+Q\?'Q\?'Q
+M\?+R\O+R\O'Q\._O[N[M[>WM[.SL[.OKZ^OKZ^OL[.SL[.WM[>WM[>WM[.SL
+M[.OKZ^OKZNKIZ.?GYN;EY>7EY>7FYN;GY^?HZ.CHZ.CHZ.CHZ.?GY^?FYN7E
+MY.3DX^3DY>7FYN?GY^CHZ.GIZ>KJZNKJZNKJZ^OKZ^OKZ^OKZNKKZ^OK[.SM
+M[N_P\/'R\O/S\_/S\_/S\_/S\_/R\O+R\O+S\_/S]/3T]?7U]O;W]_CY^?KZ
+M^OKZ^?GX^/CW]_;V]O;V]O;U]?7T]/3T]/3T]//S\_/R\O+R\?'Q\/#P\/'Q
+M\?'Q\?'R\O+S\_3T]/3S\_/T]/3T]/3T]/7U]?;W]_CX^?K[^_S\_/W]_?W]
+M_?S\^_O[^OKZ^OKZ^OKZ^OKZ^OO[^_O[^_S\_/S[^_O[^_KZ^OGY^?CX^/CX
+M^/CX]_?W]_;V]_?W]_?W]_?W]_?W]_CX^/GY^?GY^/CX^/CX^/CX^/CX^/CY
+M^?GZ^OK[^_S]_?[__P```0$!`0$"`@(#`P,#`P,$!`0$!`,#`P0$!`4%!@8&
+M!P<'!P<'!@8%!04%!04%!04%!04%!@8&!@8%!00$!`,#`P,#`P,#`P0$!08'
+M"`@)"0H*"@L+"PL+"PL+"PL+"PH*"@D)"0D("`@("`@("`@'!P<'!P<'!P8&
+M!@8%!04%!08&!P<'!P@("`D)"@L+"PL+"PL+"PH*"@H*"0D)"0D)"0D)"0D)
+M"0D)"0D)"0D)"0D)"0H*"PL+"PP,#`P,#`P+"PH*"0D("`@(!P<'!P8'!P@(
+M"0D*"@L+"PP,#0T.#@\/$!`0$!`0#P\/#P\/#P\/#PX.#@\/#Q`0$!`0$!`0
+M$1$1$1$1$1$0$!`/#P\/#@X.#@T-#`P,#`P,#0T.#@\0$1$2$Q04%145%145
+M%145%146%A86%A86%A86%A86%Q<7%Q@8&1H:&AL;'!P='1T>'AX>'AX='1T<
+M'!P<'!P<'!P<'!L;&QL:&AH9&1@8%Q<7%A86%A45%145%145%146%A87%Q<8
+M&!@8&!@8&!<7%Q<6%A44%!,2$A$1$!`0#P\/#Q`0$!`1$1`0$!`/#P\/#P\/
+M#P\.#@X-#`P+"PL+"PH*"@H)"0@("`@(!P<'!P8&!@8%!04%!00$!`0$`P,#
+M`P,#`P,#`@("`0$!`````````0$!`0$!`0$!`0$```#______O[_______\`
+M``$!`@,#!`0$!`0$!`,"`@$``/___O[^_O[^_O[^_O[___\``````0$!`0$`
+M`/____[^_O[^_O[^_O[^_O[^____`````0$!`@("`@,#`P0$`P,#`@("`0``
+M_____O[^_O[^_O[^________________``````````````#___[^_O[^_O[^
+M_O[^_O[^_O[^_O____[^_OW]_/S\_/O[^OKY^?GX^/CW]_;V]O;V]O;U]?7U
+M]?7U]?3T]//S\O+Q\?'Q\?'Q\?'R\O'Q\?+R\O/S\_3T]//S\_/S\_/S\_/S
+M\_/S\_/S]/3T]/3T\_/S\_/S\_/S\O+R\O+R\?'Q\/#O[^_N[N[M[>WL[.SK
+MZ^OKZ^OKZ^OKZ^OKZNKJZNKJZNOKZ^OLZ^OKZNKJZNGIZ>KJZNKKZ^OL[.WM
+M[N[O[_#P\/'Q\?'Q\?'Q\/#P\/#P\/'Q\?'R\O+R\O+R\O+R\O+R\O+R\O+R
+M\O+R\O+R\O/S\_/T]/3T\_/S\_/S]/3U]?;V]_?X^/GZ^OKZ^OGY^?CX^/?W
+M]_?V]O7U]/3T]/3U]?7U]?;V]_?X^/CX^/CX]_?W]_;V]O7U]/3T]/3T]/3U
+M]?7V]_?X^?KZ^_S\_?W]_O[^_OW]_?W\_/O[^OKY^/CX^/CW]_?W]O;V]O;V
+M]O;V]O;U]?7U]?7U]?7T]/3S\_/R\O+R\O+R\?'Q\?'Q\?'Q\?'Q\?'Q\O+R
+M\O/S]/3U]?7U]?7U]?7U]?7U]/3S\_+R\O'Q\?#P\/#P\?'R\O/T]/7U]O;V
+M]_?W]_?W]_?V]O7U]?7U]?;V]O;V]_?W^/CX^/CX^/CX^/GY^?GY^?KZ^OO\
+M_/W]_O[^_____P````$!`0$!`0$!`@("`P,#`P0$!`0$!`0$!`0$!`0$`P,#
+M`P,#`P,#`P0$!`0$!04%!04%!04%!04$!`0$!`,#`P,#`P("`@("`P,#`P0$
+M!04%!@8&!P<'"`@("`@("`@("`@("`@("`<'!P<'!P8&!@8%!04%!04%!04%
+M!04%!04%!04%!`0$`P,"`@(!`0$!`0$!`0$"`P,$!`0$!04%!04%!04%!04$
+M!`0#`P,#`P,$!`,#`P,#`P(#`P,#!`0$!04%!@8&!P<'!P8&!@8&!@8%!04%
+M!04%!04%!08&!@<'"`@)"0D*"@H+"PL+"PL+"PP,#`T-#0T.#@X.#@X.#P\/
+M#@X.#P\/#P\0$!`0$1$1$A(2$A(2$Q(2$A$1$1`0$`\/#P\.#@X.#@X.#P\/
+M#P\/#Q`0$!$1$1$1$1$1$!`0$!`/#P\/#@X.#@T-#0T-#`P,#`P,#0T-#0T-
+M#0T-#0X.#@X.#@X-#0T-#0P,#`P,#`L+"PL+"PL,#`P,#0T-#@X.#@X.#@T-
+M#0P,"PL*"@H)"0D)"`@("`@("`D)"0D*"@H*"PL,#`P-#0T-#0P,#`P,"PL+
+M"PL+"@H*"@H*"0D)"0D)"0D)"`@("`@'!P8&!04%!04$!`0$!`0$!`0$!`0$
+M!`0$!`0$!`4%!04%!@8'!P<'"`@(!P<'!@8&!@4%!04%!04$!`0$!`0$!`4%
+M!04%!@8&!@8&!@8%!04%!`0$`P,#`@(!`0$!`````0$!`0("`@,#!`0%!04&
+M!@8%!04%!04%!04%!04%!04%!@8%!04%!@8&!@8&!@<'!P<("`@("`@("`@(
+M"`@'!P<'!P8&!@8&!@8&!@4%!04%!04%!04%!04%!`0$`P,"`0$``/___O[^
+M_?W]_/S\_/S\_/S[^_O[^_O[^_O[_/S\_/O[^OKZ^?GY^?GX^/?W]O;U]?7T
+M]//S\_+R\O+R\O+S\_/S]/3U]?;V]O;V]O;V]O;V]_?W]_CX^/GY^?GY^?GY
+M^/CX^/CX^/CX^/CX^/CX^/CY^?GY^?GY^?GY^?CX]_?V]O;V]O;V]_?W]_CX
+M^/CY^?GY^?GY^?KZ^OO[_/S]_?W]_?[^_OW]_?S[^_KY^/CX]_?W]O;V]O;W
+M]_?X^/CX^/CX^/CX^/?W]O;U]?3T]/3S\_/S\_3T]/7U]?;V]O?W]_?W]_?V
+M]O;V]O7U]?3T]/3T]/3T]/3T]/3T]//S\_/S\O+R\O+R\_/S\_/T]/3T]/7U
+M]?7U]O;V]O;V]O;V]O;V]O;U]?7U]/3T]/3T\_/S]/3T]/3T]//S\_/R\O'Q
+M\/#P\/#P\/#P\/#P\/'Q\O+R\_/S]/3T]/3T]//S\_/S\_/S\_/S\_/S]/3T
+M]/3T]/3S\_/S\_+R\O+R\_/S\_/S\_/S\_3T]/3U]?7U]?7U]?;V]O;V]O;W
+M]_?W]_CX^/CX^?GY^OKZ^_O[_/S\_/S]_?W]_?W]_?W]_/S[^_KZ^OGY^?GY
+M^?GY^OKZ^OKZ^OKY^?GY^/CW]_;V]O;V]O;V]_?W^/CX^?GZ^OO[_/S\_?W]
+M_O[^_O[^_?W]_?W]_?S\_/S\^_O[^_O[^OKZ^OKZ^OKZ^OKZ^OK[^_O[^_O[
+M_/S\_/S[^_OZ^OKY^?GY^/CX^?GY^OK[^_S\_/W]_O[___\```````````$!
+M`0$"`@("`@("`@("`@$!`0$!`@("`P,#!`0$!`0%!04&!@8&!@8'!P<'!P<'
+M!P<'!P<'!P<'!P8&!@8&!@8&!@8&!@8&!P<'!P<'!P<'!P<'!P<("`@("`D)
+M"0D)"@H*"PL+"PL+"@H*"@D)"0D("`@("`@("`D)"0@("`@("`@("`@("0D)
+M"0D*"@H*"@H*"0D)"0@("`@'!P<'!P<("`@("`D)"0D)"@H*"@H*"@H)"0@(
+M!P<&!@8%!@8&!@8&!P<'!P<'!P<'!P<'"`@("`@(!P<'!P<'!P<("`@("`@(
+M"`@)"0D*"0D)"`@(!P<'!@8&!@8&!@8&!@8%!04%!04%!`0$!`0$!`,#`P,#
+M!`0$!04%!@8'!P@("`@("`@("`@("`@'!P<'!P<&!@8&!@8&!@<'!P<'!P@(
+M"`@("`D)"0D)"0D)"0H*"@L+"PP,#0T-#0X.#@X.#@X-#0T,#`P,#`P,#`P,
+M#0T-#0T.#@X.#P\/$!`0$!`0$!`0#P\/#P\/#P\/#PX.#@X.#0T-#0T-#0T,
+M#`P,#`P,#`P,#`P+"PL*"@H)"0D)"0D)"0D)"0D)"0D)"0D)"0D("`@(!P<'
+M!@8&!@4%!04%!04%!00$!`0$!`0$!`0$!`0$!`0#`P,#`@("`@$!`0$!`0("
+M`@("`P,#!`0$!`0$!`0#`P("`@$!`0$!````````````````````________
+M___^_O[^_O[^_?W]_?W]_/S\_/S\_/S\_/S\_/S\_/W]_?W^_O[^_O______
+M___________^_O[^_O[^_?W]_?W]_?W]_?W]_?[^_O[^_O[_______[^_O[^
+M_O[^_O[^_O[^_O___P```````0$!`@("`@,#`P,#`P,#`P,#`P,#`P,#`P("
+M`@(!`0$!`````````````/_____^_O[^_?W]_?W]_?S\_/O[^_KZ^OGY^OKZ
+M^OKZ^OK[^_OZ^OKZ^?GY^?CX^/CX]_?W]_;V]O;U]?7U]?7U]?7U]?7U]?7U
+M]?7U]?7U]?7U]?7U]?7T]/3T]/3T\_/S\_/S]/3T]/3T]/3T]/3T]/3T]/7U
+M]?7V]O;V]O;V]O;V]O7U]?3T]//S\_/S\_3T]/7U]O;V]_?W]_?W]_;V]O;V
+M]O;V]O7U]O;V]O;V]O;W]_?W]_?W^/CX^/CX]_?W]_?W]_;V]O;V]O;U]?3T
+M]/3S\_/S\_/R\O+R\O+R\_/S\_/S\_/T]/3T]/3T\_/S\_/S\_/S\_3T]?7U
+M]O;V]_?W]_?X^/CX^/CX^/CY^?GY^?GY^?CX^/CX^/CW]_?W]_?W]_?W]_?W
+M]_CX^/CX^/CX^/GY^?GY^?GY^/CX^/?W]_;V]O;V]_?W]_CX^/CY^?GY^OGY
+M^?GX^/CX]_?W]_?V]O;V]_?W]_?W]_CX^/CX^/CX^/CX^/CY^?KZ^_O\_/S]
+M_?W]_?W]_?W]_?S\_/S\_/W]_?W]_?[^_O____________\`````________
+M_________O[^_O[______P````$!`@(#`P,#`P,#!`0$!`0$!`0#`P,"`@("
+M`@("`@("`@("`@("`P,#`P,#`P,#`P0$!`0$!`0$!`0$!`0$`P0$!`0$!`4%
+M!04%!04%!04&!@8&!P<'!P8&!@8%!04%!04%!`0$!`0$!`0$!`0$!`0$!`0$
+M!`0$!`0$`P,#`P,#`P,#`P,#!`0$!`0$!`0$!`0%!04&!P<("`@)"0D*"@H*
+M"@H*"@H*"@D)"0@("`@("`@("`@("`@("`@("`@(!P<'!@8&!@4%!00$!`0$
+M`P,#`P,#`P,#`P,#`P0$!`0$!`0$!04%!04%!04%!`0$!`0$!`0#`P,#`P,#
+M`P,#`P0$!`0$!`0%!04%!04%!04%!`0$!`0$`P,#`P,#!`0$!`0%!04&!@8&
+M!P<'!P@("`@'!P<'!P<'!P8&!@8&!@8&!P<'!P@("`@("`@("`@(!P<'!P<'
+M!P<'"`@("`D)"0D)"0D)"0D)"0D)"0D)"`@(!P<'!P<&!@8&!@4%!04%!04%
+M!04%!04&!@8&!P<'"`@("0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0H*"@D)
+M"0D("`@("`<'!P<&!@8&!@<'!P<("`@("`@'!P<'!P<'!P8&!@8&!@8&!@8'
+M!P<'!P<'!P@("`<'!P<'!P8&!@8&!@8&!04%!00$!`0$!`0$!`0$!`0$!`0$
+M!`0$!`0$`P,#`@("`@(!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0```````/__________`````````````0$!`0$!`0$!`0$!`0$"
+M`@("`@("`@("`@("`@$!`0$``````/__________````````````````````
+M```````````````````!`0$!`0``````_____O[^_?W]_?W]_?S\_/S\_/S\
+M_/S\_/S\_/S\_/S\_/O[^_O[^_KZ^OKZ^OGY^?GY^?GY^?KZ^OKZ^OKZ^?KZ
+M^OKZ^OGY^?GY^/CX^/CX]_?W]_?W^/CX^/CX^/CX^/CX^/CX^/CX^/?W]_?W
+M]_?W]_?W]_?X^/CX^/GY^?GY^?GY^?GX^/CW]_?W]O;V]O7U]?7U]O;V]O?W
+M]_?W]_CX^/CY^?GY^?GY^OKZ^OKZ^?GY^?GY^?GY^/CX^/CY^?GY^?GY^?GY
+M^OKZ^OKZ^OO[^_O[^_O[^_O[^OKZ^OKZ^?GY^?CX^/CX^/CX^/CX^/CY^?GY
+M^?GY^?GY^?GY^?CX^/CX^/CX]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W
+M]_?W]_?W]_?X^/CX^/CX^/CX^/GY^?GZ^OK[^_O[_/S\_/O[^_O[^_O[^_O[
+M^_KZ^OKZ^OKZ^OKZ^OK[^_O[^OKZ^OKZ^_O[^_O[^_O\_/S\_/S\_/S\_/S\
+M_/S\_/O\_/S\_/S\^_O\_/S\_/S\^_O[^_OZ^OKZ^OKY^?GY^?GZ^OKZ^OKZ
+M^OO[^_O[_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/W]_?W]_?W]_O[^_O[^
+M_O[^_O[^_O[^_O[^_O[^_O[^_OW]_?W]_?W]_?W]_?W]_?W]_O[^_O[^_O[_
+M__________________[^_O[^_?W]_?S\_/S[^_O[^_OZ^OKZ^OKZ^_O[^_O[
+M^_O[^_S\_/S\_/S\_?W]_?[^_O[^_O[^_O_______O[^_O[^_O[^_O______
+M`````````0$!`0$!`0$!`0("`@("`@("`@("`@("`@("`@("`@("`@("`P,#
+M`P,$!`0$!`0%!04%!04%!@8&!@8%!04%!04%!04%!04%!04&!@8&!@8&!@4%
+M!04%!08&!@8&!@8'!P<'!P@("`@("`@("`D)"0D)"0D*"@H*"@H*"@H*"@L+
+M"@H*"@H*"@H*"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D("`@("`@'
+M!P<'!P8&!@8'!P<'!P@("`@("0D)"0D)"0D)"0D)"0D("`@'!P<'!P8&!@8&
+M!@4%!04%!04&!@8&!@8&!P<'!P<'!P<'!P<'!@8&!@8%!04%!`0$!`0$!`0$
+M!`0$!`0$!`0$!`0#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#
+M`P,$!`0$!`0$!`4%!04%!04%!@8&!@8&!@<'!P<'!P<'!P<'!P<'!P@("`@(
+M"`@("`@("`@("`@("`@("`@("`@("`@'!P@("`@("`@("`@("`@("`@("`@(
+M"`@("`@("`@("`@("`@("`<'!P<'!P<'!P8&!@8&!@8%!04%!04%!00$!`0$
+M!`0#`P,#`P("`@("`0$!`0$``````````/__________________________
+M_____________O[^_O[^_O[]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]
+M_?W^_O[]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?S\_/S\_/S[
+M^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^OKZ^OKZ^OGY^?GY
+M^?GY^?GZ^OKZ^OK[^_O[^_O[^_O[^_O[^_O[^_O\_/S\_/S\_/S\_/S\_/S\
+M_/S\_/O[^_O[^_O\_/S\_/S\_/W]_?W]_?W]_?W]_?S\_/S\_/S\_/S\_/S\
+M_/S[^_O[^_O[^_O[^_O[^_O[^_O[^_O\_/S\_/S\_/S\_/S\_/O[^_O[^_KZ
+M^OKZ^OKY^?GY^?GY^?GY^?GY^?GY^?GY^?GY^?GY^?GY^/CX^/CX^/CX^/CX
+M^/GY^?GY^?GY^?GY^?CX^/CX^/CX^/CX^/CX^/CY^?GY^?GY^?GY^?KZ^OKZ
+M^OKZ^OKZ^OKY^?GY^?GX^/CX^/CX^/CX^/CX^/CY^?GY^OKZ^_O[^_O[^_O[
+M^_O[^_O[^_O[^_O[^_O[_/S\_/S\_/S\_/S\^_O[^_O[^_O\_/S\_/S\_/S\
+M_/S\_/S]_?W\_/S\_/S\_/S\_/S\_/S\_/S\_/W]_?W]_?W]_?W]_?W]_?[^
+M_O[^_O[^_O______________`````````0$!`0$!`0$!`0$!`0$!`0$`````
+M`````````/____________________________[^_O[^_O[^_O[^_O[^_?W]
+M_?W]_?W]_?W]_/S\_/S\_/S\_/S\_/S\_/S]_?W]_?W]_?W]_?W]_?W]_?W]
+M_?[^_O[^_O[^_O[^_O[^_O[^_O[^_O[______________P```````0$!`0$!
+M`0$!`0$"`@("`@("`0$!`0$!`0$!`0$!`````0$!`0$!`0$!`0("`@("`@("
+M`@("`@("`0$!`0$!`0$"`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("
+M`@("`@$!`0$!`0$!`0$!`0$!`0$!`0("`@("`@(#`P,#`P0$!`0$!`0$!`0$
+M!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0%!04%
+M!04%!04%!04%!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$
+M!`0#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#
+M`P,#`P,#`P,#`P,#`@("`@("`@("`@("`@,#`P,#`P,#`P,#`P,#`P,#`P,#
+M`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P("`@("`@("`@("`0$!`0$!
+M`0$!`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@,#
+M`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`@("`@("`@("`@("`@("`@("`@("
+M`@("`@("`@("`@("`@("`@("`@("`@("`@("`@(#`P,#`P,#`P,#`P,#`P,"
+M`@("`@("`@("`@("`0$"`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$!`0$```````````````````#_________________
+M_____P```````````/__________________________________________
+M``````````#______________________________________P#_________
+M_________O[^_O[^_O[]_?W]_?W]_?W]_?W]_?W]_?S\_/S\_/S\_/S\_/S\
+M_/S\_/S\^_O[^_O[^_O[^_O\_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\
+M_/S\_/S]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]
+M_?W]_?W]_?W]_?W]_?W]_?W\_/S\_/S\_/S\_/S\_/S\_/S\_?W]_?W]_?W]
+M_?W]_?W]_?W]_?W]_/S\_/S\_/S\_/S\_/S\_/S]_?W]_?W]_?W]_?W]_?W]
+M_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\^_O[^_O[^_O[^_O[^_O[^_O[
+M^_O[^_O[_/S\_/S\_/S\_/S\_?W\_/S\_/S\_/S]_?W]_?W]_?W]_?W]_?W]
+M_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]
+M_?W]_?W]_?W]_?W]_?W]_?W]_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^
+M_O[^_O______________________________________````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````0$!`0$!`0$!`0$!`0$!`0``````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`@("`@("`@("`@("`@("`@("`@("
+M`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("
+M`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`0$!`0$!`0$!`@("
+M`@("`@("`@("`@("`@("`@("`@("`@$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$`````````````````````````````````````````
+M``````````````````````````````````````$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`````````````0$!``````````````````````$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0``````````````
+M````````````````````````````````````````____________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M______________________________________________[^_O[^_O[^_O[^
+M_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^
+M_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^
+M_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^
+M_O[^_O[^_O[^_O[^_O[^_O[^_O[^________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____`````/__________________________````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``!#3TU-````$@`!``"2```(0`VL1````````$U!4DL````"``!)3E-4````
+M%#P``'\`?P``````````````````05!03````:A39#)A``(```````````#K
+M`.P!+@$O?_\`HP#L`2Y__W__`````````````````&>0,```G(@`.`!B`#@`
+MU@!+`&(`2P#6`$\`YP!/`/<`O@#G`+X`]P##`1X`PP%@`,0!'0#$`1X`Q`%@
+M`,0!80#%`1P`Q0$=`,4!80#%`6(`TP$<`-,!'0#3`6$`TP%B`-0!'0#4`1X`
+MU`%@`-0!80#5`1X`U0%@````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````$"```````"0`C````````
+M`````````'@````$``0``````-'^`/___X`````!`2`&455N:71S```3""YP
+M9W-Z```)'E!!5",```DJ3%=25P```````0)&!B!S86UP<P````E:24-.(P`!
+M"69I8W,C``$)?FEC;#@``0``D@``````":X``````````````!T`+P`/__;_
+M^0`!````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````$````!?@```'X```!J
+M```!(013041%@0$`````#@``!@&CU'ZFI>3[_P``(F`21')U;2!/9B!%87)T
+M:'%U86ME(`(```!!249&4V0R80``04E&1E-D,F$!`/____\`````````````
+M``````````"G/9LK``"4#````>BDX[7XIIM-4@``````+`#B`1`".P$``+0!
+M*0&`__C_[````````(`````````````````````````````-`````2$'4V-R
+M:7!T<P$`````$```!ABCUO'`I>3[_P``````M@!*`7(!W@$``)``Q@$`__C_
+MXP```````(```````````````@``````&@`I``\!JP)@`"H``P)M`ST`O0#!
+M`8("40$`````&@`I``\!4`'Q`"H``P)M`ST`````X#;__P``````&@`L`!8!
+M/@'<`"H``P)M`ST#,P)M_,$";0``````&@``````````````````````````
+M`&`````````!`````7X```!^````:@!QVJ04D@```!P`:@`!5W-T80`#`!)3
+M1$]#````0@`!__\````&```````"__\````D```````#__\```!"```````$
+M__\```!@``````/H__\`````````````````````````````````````````
+!`/\`
+`
+end
diff --git a/sys/share/sounds/firehorn.uu b/sys/share/sounds/firehorn.uu
new file mode 100644 (file)
index 0000000..ad98c64
--- /dev/null
@@ -0,0 +1,299 @@
+begin 644 Fire_Horn
+M``E&:7)E($AO<FX`````````````````````````````````````````````
+M``````````````````````````!!249&4V0R80$``!H`SP```````#$B```!
+MSJ<]K<2G/:W+``````````````````````````````"!@2)]``!&3U)-```Q
+M&D%)1D934TY$```O'@``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````________________________________________________
+M________``````````````#_____````````````````````````________
+M__________________\```````#___\``@(!_OK]``$!_0`&`_[Y]/7Y^OG\
+M!`@!]N_S``4```P9(!P)]>[R]/+T]P0*^_O__@#X]/X0'QX3`^WL]^SD[OH"
+M`/3LY^7JY.P/("<H#0$(#@WZ_!<C,C8@&`[[^_X#%2LS(@P"]^GGYN?^$`L,
+M!_CLYO3\`QXF%/_Z__+L\_,%(2,;&0?U_@#W!!DH(@7PYN#BTL?:YNOZ]^;9
+MU-/;[O+MZ.7?U-[AP+S8Y>OQ[>CH[_#P`Q,1"``%!_[]].ST_P'Z\>[N[_8`
+M_PT:`?;^]?C_]OP.(2\H%PH2("`J,BLT,!DA,!X+"`<1(1\#X=74V.?S_0@&
+M_N[0N[B]S=[O`Q06_>3G\@@?)SA$/28,_O'Q`0\<+S,D$?7:U.?MZO\3$@3R
+MX<S`P\[H!146"/;IZOL.(#)*4SHA$0/[_@TA+3$Q'P#JZ_/N\?G\`OC>S<6X
+ML;G4`!D7#@#\`@H>-DI985D_'0\0#`P5*3HY,1CV[_'GX>[T^`'YY]+`OKB]
+MX/L$_N73S\K0W^WY!1`4#P/NW=KI^OX!`.;-R\S/V.'BY_;HR;FSLK"[W/+Z
+M^>GG[.3D\0`'#!($\NOCZO@%&BHH'A,-!?OV]?8!&B(/]>;>W-W6U^SX[-O3
+MU=K@Z?<1*B\;`_?U``T*#R`H(Q+][N3CY^O_%!L9!N[AY_7V_Q8?'QT2!@#^
+M`0PA+R\@`_/]"A0<+$%!.S,<#@?^_`D?+"PI%O;EYN_["Q,(^_#CW-S?Y?L>
+M+B\U)@L"`@0'$R<B$07]^?+Q]P4D-2L5\=3*S-_S^P,'"/SKZ>KK\?<$$0_^
+MXM'0UN?^$AXD(1D-`?;U`1$N3$XX&?KEX_D0'2D@"?GCRL#*VN\/)1X-^N;<
+MWNCT_@@*`_OOX-'*T^X+'!X3_]_'Q,G7[P0-$0W[[.[MWN0!#PX/`^OJ^0(0
+M'B@Q.#8@!_GP[/H7)B8E&@;Z]?3R[>[T`0;OX.3CW.7]"R`\*04#`OCW]^_J
+M\.W9SM+-RN(#"@+WX=_T^N_H[?'S"!0!\O/T\?/_!?[SX]KG^?W\`@4'!?GS
+M_00$"!HL,"@7#10I,QX,$A43&B`>%@W_^0XG*1T0"Q`=*28>*C0E%@KXZ^/5
+MS=SN[>+:UMKP`OOZ"@X'!PH-$`P.&"U`-R4?%PL(#A`6*"\C&Q8%\>#,Q=KJ
+MX]KCZ>+O`OK]#`P*$QL2_>[=U.D'(CHW&?OV_?KX_@`""PKZ[N?;U-KBY>CK
+MY.+R]^OI[_/]#0GNX^WV]_+R^`()_>[S_/P"#!(:(!<)_O;O[_7X]O+JV<W0
+MT]7E\/8+%0C\]_/V_PT:)BXG&1`)_P(8(B(D$O'?V]#%R\_.U-/&O\/%N[[5
+MXN\`^^OFZ_#U_?[^_?#EY_#Y^P$5)BTK%/7JYN#G\/+S[NGH[O3Q\P,3'!L4
+M"?COY^+T%2@F*2\?%18/#1$>-T,W)!,(!0T?,3(D$O_V\^KL^P<2'2(<"_KM
+MZP`G.S`B&`?^``8,&2\Z/#TQ%OKHY?`&'B,7`O/IXM_A\`03&18/`_7KZ?@5
+M*3(S)10(`0@8'R$I-#<Q'@/NY>SW_0H-`//GXN3H\@$,$0X"[N7D[`89&A@1
+M"`(#"!$D+B8C)!\8$@L%#!89$@'NW=?@[OL&#`?[\^;3S\_.V>OW\^+5UM[A
+MY>[_$Q,$]=S&R]74W.[X^^_5Q,'(V^SS^P$#__;OYN#:W_X9&0+IUL_H_/?[
+M`P+X[O/VZ^3AX_'Y[]?$P\;,T]C?Z>WFW=G=Y>KP\_7WZM#&U.L#%!<0#`C\
+M\_'NY^GX`/WWZ-3*TN#L^0'Z[.+AY_,#!@@3'!H.`/7MZ_`$'BHE'1P<'",L
+M)RDW,A\+^.;@ZO+W#2(:"0/__0,,$!4F,B8/_>OB\?T&&B8:`?7PZ.;H\0H@
+M)"`9$/[EV.,`(B8/!0T-_P$.&C9(-RPN)QT+\_,-)"DI+S@X*!X>)34X*2`C
+M)B(6#1<K)A<2#!0=&ATD-DA#/#LU(PT*#B$Y,B0C'Q@0"@4'%!</`?+MX,O#
+MP]GS[-_;VM?%L;31\``/$?K@SKVQON+U]?T$__CPX]KF^@@5$?/9SLW.T-CH
+M\?/RYM3*S=#6ZP8A*1'UZO/_]?$"%1P1`/7R[.?T"1PN)@7Q\_+H[``7*BD7
+M"0'UY]O?]1D^1";]YM[5V?,/(!L)!`7_\N+E_ATD#?#=VM3)UNG^'!D`^_[U
+MZ>7M`1HE%?ST^_?R_P@1'1<'^OS]]OD"#AD0[<.OKK;+X?'Z_??FVL_#T>P!
+M%A\?&/O8LJ;']1$7#P7_^-[&T_0-%!43^,^VL;W9_A<>(B09!?/T!QXY2$8[
+M*`7>V@4O.3@W)Q("Z]O;Z`(?,SP['_'2T.L+&1PA*RD.[^X%'#%"2DM(+P#>
+MX?L7+3@T*!D(^/@$"!0L+AD!X<:[P]OO_08&!/;?VN?Z"QLP03H@"/KY$#!)
+M54X[&/3K^0X;%@X2&0C@O**IOLS@[.WHT+JRN]3D[0$8'`GVY,K$U.H'(281
+M\NKW!`T0$!DE'P3JV<_+TND!#@T`]?'W^_3Q\@$0#@@&"Q,1#B)-8$(3]/8.
+M%PX%_P8+`>_H]OGJZ^[JZN_OZ?+]_/X#_.OM^.WM_?GM]0L."Q@.!",[.3$G
+M'A81"OOU^?OS\??LV=7D`A03#P@!_?G]`@<1("HD'!\@(B4?'RDV.BX:`.SQ
+M_?;O^P@![-O+O,/;]`0&`_3>U=/=\/O]_/+<Q+JVM<SL"2(O,2,,_/+U`@P1
+M#0L,_.G8R=3R%C0O%/WLX=SI_@D6(!0#`@P#[_,!%S(S'P\`]/7]!A0?&Q45
+M#/KLZ_0'*3HN&@D$^?`((S([*0GTZMW2X/,!(30K'QD.`PX@'AD5`>ODXM7$
+MR^4"&Q7^\>KEW^+^'"$6"_KKZ>CDX_(/'QT8"?3O\O@&#PL(!_CGX.'HY^CT
+M`0?[XLG"UNX&'"$;"_'8R,3+U.3Y%2\R&P8'%2(N,R@<&A,#]O7X]?L,%QP-
+MZM7:[?7T`Q44"P$"$Q;]V<SD_`/WX=WL^?CM]0T5$0D!`PC_Z>/R!A4&Z>L$
+M&A8(&#([+AD8'AL1_?4+)3`H&!TT.S`B&!L:__,"#PW_\O4&$`P$^?H&"Q(<
+M(RH@"@D9'!$$^?<##PH"`0,&!`$#"Q4._OK]_??JZ/8!!/OU\.'B[_H,%!,+
+M^_'MXM''S>'X!PT%[-G>[_OX\/#FV]O/Q='=X>+=YOCNU,G(U>S\`0,#^NWN
+M]O7O[_7\"A#^Y]G6Y/+T]0(-!0+_ZNX)$1$;)B@@&1<>)B<L-4$_)QL=%@P,
+M#`H3'A3^]OX)$182$14*]NWK[_H*%!`+!/S[]/$%$!$@*A\0#@C]_@<7+3DO
+M'A4*__K\``4+#`3V[/+MW=C?\P'W[>??W-KD_08'#0?\]?3NW^#V#A82#@D-
+M$0\6&A4)^O3HW^;EZ?@(#O[IX-?7V^H*'1@*!`0$#1,2'2XS*2$8"/?GX_$*
+M&`#DW=G<ZNSJ]@<.#0'U_`+OYO<0'!0'`@(*%`\!_P4)%!H;(!T1%2PU)A0)
+M^>GD[.WG]/GM]?CEV^'?V^X!]N7BYN/F^`0'!0`!"`P+"`/Z!!TC&`/LY-[7
+MW^;@Y.O@U-7,P\S0R=#G[^7>WM;0W.39VN\`$1L7$@X)"QTM)QL:$/_[_OGQ
+M]P82&A\6`/7NY_0%!/___?GY]_H"^_P-%1@9$P#GY@(5#@XC)Q\>#O?^$QHD
+M.#XS)!$""!X@#`@6'QT2^-O<Z.O_&"`C&@'W!R0Q(QP=$@;^[]WE]_;[%"4<
+M"O[R]@L+^_T!]O/__>;?Y_,,)BL@'R(?)"XH'!TC%@,#`O+M_`8+%!<'\O(!
+M"Q0<$P+X[-_C[-W)T>?Y"A<0__X&"APN)`X!]NGJY]#/ZOT#_??Y]O'W_PL;
+M&@/MXN/]%/_DZ_C[^?;S]?T&#18F)Q8,"A$;$_SS_@X1#0D,#@<4,3(?$0+N
+MZ?D&!?SU^000%Q`-"`85(AX8&0??U>/FY.'<V][@VM?E\/,)'@KR^?CAW.[_
+M!/WP[OO\[.?V!A8F'/[U_O38T>K\\=W*N;J^L:_.[?H+$O[O[=S`Q^X'_^;9
+MX.WZ].H`)"TA#O7Q_O/7U_L9#.[I[.OJV<OJ$A@9)!+X\>'-W@LG%?7JY^3A
+MX.+P!A(:'1``^.WI_A<6_//^`?;Q]/4#%QTJ0#\A!O7P`A<;"OX.&0T1(R@G
+M*2XU,"$-_?S\^__TW>#Y!P@.%0'Q_PH9+2,.#0[]\@@6!O\+$!8G+1X?+#$\
+M.B47%A4)!104^_+\]_4'!_#J_PP1'!H*_.W;T]OEW-;D[?+\`O\&&B`6$`;P
+MV<S+V>OJUM+G\^KCW,_1Z/7_%R(-\N+=]1@4^_H/$P#U]_T/)C0Q+"X;_/3S
+M`!D9!_\'#`3X[>7E^`T-$1X4^_'Y`@3_^/D($1$-"0D'$"HP%O?DVM'/U=KG
+MZ>;IV]7H[]_<^A(2$P_\\O+Q]?\&_O7\].;N^OD#'"@J*!/X[?+W^/CTY^?U
+M[=G=V\7(X^SN!AH&[N??W^#8U>'[#!,7%14;("(O1$(I&A$&`O7@Y/X4(RDA
+M#O;BW-_L"1T6#Q01`-_)S=CB[?H$_>34U>#V"@X'%"$0]MW#M\7?\PL>%/GB
+MW./C]A$+$"$5^^7=Y>_X"!XW/2D0!`D;*"$5$PS^]NO@Y.WZ#!@8#@<$^_?X
+M`A,.^>_T_OSV]_X-%A$1'"DN+2<L2U`M%0X#_?WUZ_'_`_/J\^_N___Y$Q_X
+MU\[!PM#6Y/P,!_;^%!XF)Q\F03T)Z>/7UMK:\@P%]OCX\_GZ^0((#@O_!/G?
+MW./L`Q+^ZP`+``85'24V.A\4'A0`^?3S"B`1`Q(;%Q,2$!,6"@86$/'<T,_N
+M&"`-"1@5!`4*#Q80#Q49$._6U][?X?,'$Q($`00`!/KBZ`D>!-G-U-++T^\+
+M(RD7#A,6$`,%'#=#,Q/WZ=S"M<?F_/?GZO'GU\G%W@@9_=_4Q*V>JM3Z"Q8?
+M*C(>_N[W$2,H(AD0\<FZO]'H_Q$:'!3]Y-K?X_<<(@KMR:VHM,C2S^<-$@;[
+MZ>'T!081)2(+\-/$TNOP\!4W*A86"P`(`OX;(_S;TL_<]`$!"B@O%!0M+R<J
+M)2<X*`/W^O'N^/CT_0L&Z=WGZ.OMY0(C`M3/W^OV!Q(E-R\C(B4N-CDY16-?
+M+Q`'^_CYZN?_"_SZ`P4/%1,<+3HN">C6R]/CZO\9%A<G)QX;&A\I*1H'__GL
+MW=KJ]?7JX.KT\.[HXO86$007$.C/N:K"Y>G8TN'W!@D!`B(^+A\B(!4`X-#P
+M$0;U]P0(^.[S_`\@'QPG)PCHT];Z"0('"Q,:$@7_"!PF*RP>#0#PW=WU^N_O
+M]P4&_/C]_P`'#Q@H*!/][N?BZ?\*"Q,2!P8+!P87*BL=%`X#\]K.S<G+S<S0
+MV>/>W.SZ_/+EXM_1NJRSP=+FZ>S^!_?K]`,:,"8."Q((\NSZ!P@"]>CI[>;>
+MW_$,"OT!`O74N+2]SMG4W>KNZMO<]`XC*2<A%0GRV^'Z!OOR_/[LX>7R`1LV
+M-"<@&`OZ^0L9'2,G*B<@&1,3&2$P/#8@#0'Y_@L3$@L)"?WOZN[Z!@4)%0W[
+M`0H&!P\0$187#P@&`@03'RTZ-R84#PX,#`8#"`+NWM_HZ^WT`!0>$//@XM_7
+MWNKX!@3Z_`@0"_T!%2(C&PP)$0P!`@@.$@?LX.GJW=OG\@`&]NW_"_?E[O?T
+M\?'P^Q,;$0\1&20?%A,>(1`.'1T3!_?U`@D&!PT0"P$$!O;^&!86)B(1`?3R
+M]OL'%!\:`//U[N\"$`X8)P[MZN+:Z/3X^_OOW-38V];A_0@)!>_AYM_7Y/L*
+M$0P`_0,(`?D/*R@@%//:ULBYS_7\]N[6Q\G/R\?6YN;@TL;-U=;>`!P7#PL'
+M$!$&`0TN2$(G%`K^\.#D!!P2]^3@W=?8W>X/$^[4S,&^OL'<!!0$\N[O\O7Z
+M`A0H'PH+#0'_^_$`&!<,"`/\]>WR`0H0#PP+`??[^/<4,283$PL+&1@A+R<C
+M)RXV*1P@'109&0D&"?CT!`@2(10"!`H![O`%$1(5&!47%0T8*C1*4CDO-"<8
+M#PD3(AH,!?OV]/'R]0,1`^?;V]S;T]+M`/L&$@?X[>CR`Q,;&!,1#@T-"0H0
+M`/,##?GL[_8""`0+%@KY^_WNY.GLW=7K^.GL^O\.%@P0&1()`P()$AD9#`P>
+M'`3]!Q@H(Q4>*A7\^OT!`._>U=;F\.?A[@#^]@4;&PC]_@01"OC\_?D%`N_M
+M]O3GY_T2%0S\\P$$W\G8X^?N[.?N_O_N[0HF)A(!!`KNQ\+*TN'HXN/NZM?)
+MT.O[].KI[^O/M+?(T=OG\OW]\>GA[!,G&Q,7&A+YY_'Z\?8%#141`O+G]`\8
+M%1<3!?3<Q,'#PM#B[>K9W.?K`1LA(B(/_OGOZ_L"_0PE)`OW^@(%$2(J.4$C
+M$!,#]?O\`2`R'0/\`@8#%CQ485(D#0P"_P<!`AH<!/+K[_#I^!HV2D8M)283
+M_?3R_Q$-"0T-$Q`"$C]94SLC'1P*\^GM]?CU]/7\"`#L^A<3#1,+"Q(%\>CG
+MYN7CY.GN^/;K_A48(B`/%1@(!0G_\.KKZ^_W^O3V"`G\`@<``0$%#?O@U]K=
+MX^GK[O/[#1H8("`,"0@#"@7Y]_3T]O/V!Q<<'Q\8'1\5%1(4$O3F\?3U^?+R
+M`0;\!!HF-#DE%`X']^7CX^'?UL_;[N;;[0`(&R4>(B47`.3:U\_7Z/0!_.7@
+M]Q(>*2XH)!7YX,_0U,_/T]WNZM/-VN7H[/;U[.GHWL_.S\G,W.ORZ^'E\@08
+M)S4],!8'^^GL_``$"0+QX=K?[/H$"`S^V\;/VMOCY-G:X-S;V-/?]A`F.D<S
+M$0'[[N;X!0(%^.7L\.?N!B,R/D8P$0,$"@X9)"(0^?<"`?T#%3%-5U(^'@P*
+M`P,3'Q@!Z>'EYNS["1\R+2XI$/[S\/H(#/?;T]SK\_@)'#5'04=$(PX.#Q`9
+M$_';V-WH\?G^!10._P8&]?#S\?/^\-+&P\[E]``+#Q47'C4X*2(@(2(<"_;I
+MXN?U_@8/"P'S\@(#^_T"`P,'!/#CVN'X`@@%]_P$#"`D&!04#0+]]>OJ\@DD
+M,2\8!0P-#Q\9#!(4`NKHZN+CY>T%$@KW[OL&#2(J(B4@`^_QZMG6V-WT"`#N
+MZO7W`B$J(2(6^^?9R,+/UN8$"OOT]@`'%RPQ+R8/^.[JV<K3W>K]^>'.RLO(
+MUO#_`?CLY=O-O+[8ZO<*"??M[?<#%"\W*R$6"O_RY^3M^0(-#__NYN/@Z/S_
+M^/7O[.?@U,O4XNX!`^[DY>CU#1X:#PG__/SJV-_K[?\<(143$A0A)RLN*2,<
+M%0T`]>_J\`$:(0X(#ADL,#`T*1X?(!\.^.WJ\`0:&@T-$1,8$QDF&0<'"@?Z
+MY]7.X/\=)QX=)BPK*38^+!4/%1D0]=?2Y/@+#_[W^O'G[/?_]NOR^_?CR+W%
+MT.4&%A8=&@8$%B@H%@H0&Q<`ZM[F]P,3'QP4_NKN_`D+`O\-&PSNV];;Y_83
+M)2$7`N_U#1\B&!0:%@;NX_,`!!,I+"`9">_T"!$4"P+_].32P\K?Z_H:*AH-
+M`_+^'C$[.B@9"O7?S=#D]`<<%/WZ[=KL"A8C)`KRY]S'N<+8\0\@%@L4$@82
+M)R\V+0OR[>38V>+N_`'\\>?@T<35]0@0`N37U,:ZO\_D^P/W[O<'"`,3+3,H
+M%/WV_/GL\0@9(A@"^?KTY>+W#Q(']-S/T,S&UN_OZ>OEW^7O\OL:)Q4)_N??
+MWMC?\@8,"`7U\0$,#A@L+A@1">[FY-_G^PL,$10*"A$4'S9-33TT*!,'`/L"
+M"P@%#A$&`@8-%2$M*AL:&@?Z\NOKZNOP``D%#!4:*CI&13,I(A4/"P8#!0@*
+M$`L!!P@&!/\)$0#U\^?;U]#"P='>Z>OI^@L*"A`A*1H)_/@``/CV_`8)"P;^
+M!PT"^?T*"?[[]_CYZMO8W^GN\.OP!PP"`Q$C*B0:$0P$_/H`!P4&!P`&%Q$#
+M!A<B&0L%`OGKV]7;X^GQ^_T!#A`,%!\H)20L*!+VYN;K\O3T^??V`/_[_PP:
+M%P\3#??CVM+0UMC?Z.;H^`,!!Q8@(2`E)Q;]\.ON^``$_NC7Y.[GY^WR]?/M
+MW\Z_N[_%TN'HY-G>]P@(#1PE)1\6$@GV[/#^%"<E#_CK[?C[_P@0$`<`^^S9
+MT-'6YOCQW-'4X_3\"1L?$P4'#@?PV]ST#Q8)^._O^081)C@U(A,2$0?UX^7]
+M%1D)^._O`Q89*3@P(1L;'R`4__D$%"$?$0'X`@P-&R8:#0<&!0+[[.#@[/O]
+M\>7F^Q<D)20>&147'2`>$P/_"A@6!_SU_0H!_`<'^>GBYNGCTKZ]U>OKY./L
+M!!<3#Q88$`3Z`Q,2`O/R!1D;!_?V_@'TZ_8"!@+]!`X$Z]O:Y//W\._S]_KY
+M_@@-$A`3)BL5__CY``D0#@P.#`D$_P(*#@P'!P+PW-+8Z?D$!PD)"`T-"A,;
+M(RDD'!0,`/?^"Q8B(QP1"0?_^/X)&R06`_WWY]G@[O<"!__[!`H#_@<3(RTE
+M&!(-_?']#1`,`??Y^O+CVN+L\?'DUMC4Q</1Y.WHX>'J]?OX]@42$`;]^OKU
+M\_D,'AT._??\^_SZ]0`'^O'R[>'8T=_[`_/?U-3:WNCU^@$$^O/U]_3O[P,9
+M'!4)_OK]`@X6$!`2"`0'!OKN\?P'#0D!^?/V_@\A'148&AH8%A,.#A(7&1P@
+M&`T'"!H@!_D!`?GX^/7V]_;[!0H+!_OV`A(2`/L#`@0-$AHA%P<'%1P?'0\'
+M"@T`[.KP[.7CZ//WY=GA[??^`/O[!PO_\_H`]^_S^P,)`OCZ!1$9'!4*`/GS
+M[O7_\^3H[>WLY./O_`0#`/CIX^7HZ_X4$04("`$`_OK]"QD@*B<.^?3R]@PA
+M%/_]^.OGYN+K`1$9(!D#]O?X^Q(N*Q@0"08,"0<-%B,R.#`="?SS\@4@&O[Q
+MY^#DZ.WZ#Q\@(!@(_O/O^!$K(0+W]?;]_OT)&!H4$Q$'^>36W/H2`M_/S,S/
+MS];L_?[W^/OV[N+9Z@D6`N?AXN;M[/()&!0+#A`*`?'J]@H3`.+3T=/5U.+]
+M`OCR[^WIX-33Z`0-_NGBXM_D\/T0&QD0"PX,`OCX!1(;$_OP[NOM[_8*&AD1
+M$1(/#`@(#ATN)@\)"P@'!081'2,A&AH9$`8$"0X/`_'L[_'T\O0%%1<1$142
+M#/_X_P8,!O3P``H&_O\*#@\.#0\1"?GX`?[X[=[?[O3JXN;N^`'__08(]^_]
+M"07\\>7K``;\^`$*"Q`6%181_O4%$P?WZM?7Y^SI[?3Z_@,+"P?^\?0/)R(2
+M!_GQ]OK]`@,$#!<=&0W]]0`8*",5"?;I[//[`?S[!Q,:%`/S[_\7)209"_KL
+MZ?+_"08%#1D?&@W]]`$8)R48`^;/S=GL^_T!"Q`/"O[PZ_4*&QX7!>S?X^_[
+M!@@$"`T,!OONY^W["`L"[]2]NLO<Y^KJ[>[Q\_#KZ.S["`?]\^7:W^_\!@D'
+M`@('!@0&!PL4%PS\[]S'R-[R_O_X[^OLZN?M^`$+#P3U[^73U_('$`\%_?K]
+M^?#Y#!8?(1("__3>W?$`"0D!_/CU[NCY#A8<(!@+"`+S]0H7%A`/$`\+!@86
+M*"LD'A('`O;H\0(%!0<'#0X'`@(+&!,*"P3[_P,!!1`0!P'^``+^_0$(#Q$,
+M`_CO\/7W^?WU[.GHZO#S]?L#!@/_]^GAZ_L$"@P(__;S\O/W_``)$A41`^S=
+MX._X^O__]NSGZ?+_!P8*$1(/!O/F[?T#!@L*"`/_`@<-$Q$5'2`B'@[_!1$.
+M"0T,`O?Q\_H#"`(!!@8&!?OW`Q,3#PX(`/SY^P,0%A(4%@X*"OWR_0H$_@#\
+M]._IZO8&#P\)`/7R\^WJ_`X0#@T%_?GR[?0`!`+^]>_MZ^;E\O_Y\?#NZ^;;
+MV.GZ_O[Y[>3@V=7=\?_\]/+U^?7O\/H#!@8$``#]\_/_#`\%]_#R]/#L[_?^
+M`@'\].SDW^H!$!0*_/;X^OC[!0P-#`H)!?[V\@(<*286`OCX\_/_!PL0$A$1
+M#0'S\0(8)"8;"@/_^?L&#Q,4%1<8$P/V]P06)241_?;R]/\.%!`0#PP-!_OR
+M]`$/&AP/`?KS\P$+"`0#^_K^^?#M]`(,%!<*^?'J[/T,$`X'_?K[]>_M\/D%
+M#0P$^/'O\?\*!@,"^_?W\N_R\_G___[YZ=_>Y?H$__OW\>[MZ^_U]?C^_/[^
+M]/+X!!$4#0<%`_\```,)"0T4$`T*`/T!"!,6"@0%_//X`0P6%0\+`?S\^/D"
+M#!88#PD'`?T``@0(!@,%_O/O[O'X!!`2#`P.`_;W_``("PH,!_SX]_H`!`@%
+M_?\"^?3U\>_T]/3Z^/#P]OO]_@0#_/T!_/GX\N_S]/7Y[^;N]_\$!`<%^_L#
+M!`<-"00%`O[ZZ^/M^@8-"P@#]>[Q]OO^^OD!!0'][^3M^P</#@T,`/;X_@$#
+M!08+"P<!\.?S_0<4$Q`/!_X!!PX1#`L2%`\'^>_T^@0.#`D(`?P"#!(0#`P0
+M#P;]]._Z`@80$`P(_/8`#1(2"@,$`??S\O'Z`00(`_GRZ.OZ!@X.!@(%_^WH
+MZ^WX!0H,"P7Z[_#[!PX/"@4!^NWM\_8!"@L-"?[RZO#]"1$3#0H)_>KBX-SF
+M]/K]^_7OZNWX`@8$`?[Y\>SO\_0!#0L%_?/N[_0`"PT*!@#^_/?Y_?T$#PX&
+M_?H``P0.&R`<%0P&`/K\`0$'#@7UZN?N]?P(%AL4#`/^__[]__X'$`7W\/+^
+M"`L4'A\8#@4#`?T!!P8+#P+QY>/L]?P&#Q`(__GV]O?\`?X!!?GKYN;P_P@-
+M#PL#_?K[_/G_"@D*#0#PZNGP_`((#Q$+`P`!_OT#!OWZ_.[AY.CQ`@T.#0L'
+M`P$```$#!/_^_O+IZ>CM_`$!`P,!``$#!`4("00"`OGQ\_<!#A05%!`.$!$/
+M$!$,!0'_^_+L[?+[!@L,#`H*#0T.$1$.#@D!^_#FZ._Y`PH2%`T)"0H,#@P%
+M`O_\^.W?W.+J\/C^_O\!`/\!`?WX]_?V^?/JZ_'U^P`#!@@+#`T3%1`)!?[Z
+M_?KQ[^_P\_+O[_;_`P@-"P7\\^[M[^_M\?/S^/OV^0('"@X4%Q((_O;S]?7V
+M^OOY_?SU]OT$#!4?)"`6#`8%!0(#"0H'"@H&!Q$9'"(G*2(4!P'\]O+S^/OY
+M^_SW^/\#!@T4&A<)__KW]O7U^/K[_@,%!@P7'A\?'QL-`?SW\O#P\/#N[O+R
+M[_+\!0H,#0P#]O#N\/3U]/'P\?3T\O<%$A<9&14+__CS\/'S\O#N[N_P[_'^
+M"0\1$A`'^.[K[?'W^/;V^?S\^_X'$QD9&A<,`/CT\_3V\_'Q\_7T\_8`"@\0
+M$Q40!?[Z^?O__?KX^?W_``80&1T<&10+`/KU\/#S]??Z^OO[^P$)#Q(3$@X'
+M_OGX]O?Z^OGZ^_S[^0,1%QL=&!0+_/3PZ^OMZNGM\/+R\?@&#`X/"@3_^??W
+M]OCZ^/;U\O3X^?\,$Q<:%A`(_OK\^/3U\_#P\//W^/\*#Q(3#P@`]_7X]/'S
+M\_+R\/+T]/H$"Q$5$0P(_O?W]O7[__SZ^O\!_P,+$18;&QD5#`4%`P$&"`4#
+M!`<(!PL3&1X?&A<3!OKX]O;[_?KY_04'`?X%"@T-#`T,`OGX^/G\^_CZ`0D+
+M!PH1%143#@X0!OCS\O/S\>SL\_K]_/T#!0(`_?X!^O+U^OO[]_#N\/7Z^P$*
+M#`L*!P<'_O7U]O?U[^GJ[_+V^?P"!04%`@#^]O+U^?O\^_?V]OC\_?\%!P8'
+M!P8"_/?W]O7V]/'Q\?+X_?X``@4)"PH(`P`"`0```?_]^_X%"0@*#`P.#@L&
+M`/[^_?O[^_K[_@('"@D)"`8&!P@'!`$"`?\``?_]_P,)#@\/$`\.#`@#_OGV
+M]/+R]/7T]/;[_OW_`0$#!0,"__S[^_K[_?W[^/?[`00%!@<+#0H%`/KX]_;V
+M^?W]_/K\``$"!0<*"P@&`OOV]/+S]_OZ]_7X_/\"!`<+#`H(`_SW]?/S]?CZ
+M^OO^`0$#"`T1$1`0#PL%`O\``@4'!@8*#`L-$!`1$0\.#`7^^O?V]_G\_?O]
+M`0(#!08&!@4&!P+]^OCX^/K]__\#!P<'"@H)!P,#`_WT\._N\//U]//U^?S]
+M_P$#!`'___WY]_7R\O?\^_G[_P(%"`H-#@P)!?_X\_+R\_?[^_GY^_T``P0&
+M!@0#`P'\^?CX^?S^_OX!`P,"!@H.#@P*!P/]^/7T]?CZ^?G[_@`#"`L-#Q`.
+M"@8"``#^^_S_`0$#!@<("PP+"PD&`__Z]_?V]OCZ^?C]`@0$!PD)"0<$`@#\
+M^OO[^?K[^/;[`@4&!PD)"`7^^_GU\_/S\_7V\_#T^_W^`00("P@"__WZ^/CY
+M^?O^^OC]`P8&!PH-#PP&`?WX]?/R\O;Z^?G^`P4#`P4("@@%!`/_^_KY^/?W
+M]_G^`P,!`0,%!`(!``#]^/7T\O#R\O3[!`<'!PD+#`L)"`D)"`<%`P$!```%
+M#1`0#@T,"04#`0$"`0$!_OOZ^/K_!@H+"PH)"`4`_?W^_O[^_/W__?P!"`P-
+M#`L*!P+\^/?X^/CX^/?V]//V_/\!`@($`P'^^OGY]_;W^/G[^_O_!0@("`D+
+M"@8`_/KX]/#P\?/U]??]`0("`0(#!`,!`/[[^/?V]?;Y^_X#!P8$!`0#`@#_
+M_O[]^/7S\_3V^?T#"0L*"`D+"@@("0D(!@+^^_O^`0,%"0L+"@D(!P4%!`,#
+M`?_]_/S^_P(%"`D'!04'!0#\_/[]_/KY^/G\_/T"!P@&`P,$`_[Y]_;V]?/Q
+M\/+V]_;X_?___?X"`P'__?S[^??W^/G\_P$#!00"`0,'!@'^_/GV\N_P\_;Z
+M_?[_`0'^_@`$!@0#`@#]^?7T]/;Z_O\``@(``/\``0```/[Z]O3S\_7Z_P,%
+M!@4%!`0$!@4%!@8$!`,"`@,%"`D*#`L*"0D*"@D(!P,!__SZ^OS_`P8%`P,$
+M!`,$!`,#`__]_?W\_?X!!`8&!@8'!P8$`P$`__OX]O7U^/G[_P$!`/___P$#
+M!`0$`__[^OGY^OP``P4%`P("`0``__\`__SY]_3R\_7X_0`````!``#__O[_
+M`/[\^OGX]_?X^_W^_P$"`@+__?S]_?S[^OGX]_?X^_X``00%!04%!`,!````
+M``$!`0("`P,"`@0&!P@'!@,!`/_^_?S[^_W^_P$!``$"`P,"`@#^_?W[^OK\
+M_@`!`@,"__[^___^_?W[^_OZ^/;V]_G[_0``_O[___[\_?_^_O[^_?S\_/[_
+M`00$`@$"`P(`_O[]_/S\^_KY^?K[_/___O\!`@'____^_OW]_O[__P$"`@,#
+M`P0%!@8$`P,"__[^_O[]_?\``0("`0($!04#`P,#`@("`@(#!`<)"0H)!P8%
+M!`,#`@,#`@$!`?_]_/W_``(#`@,%!00!__________[^_OX``0,#!`4&!0,`
+M_?S]_/O\_?[^_?S\_/S[^_X!`P,!_OS[^OGY^OS^_O\``0$`_O\!`0$!```!
+M__W\^OK\_/W_`/_]_/W^___^_O\`__W]_/O[^_W_`0(````!`?_]_@`!`?_^
+M_/OZ^OS_`0("````__[\_/W_`0(#`@$````!`@0%!04$`P#^_?W^_P$"`0#_
+M_O\```$!`0(#`P'^_/S\_?W]_O___O[_______\``0#^_/O\_?W\_/S\_/X`
+M``#__OW]_OW\_/S\_?[^_____P`#`P,"`0$"`0#^_?W_`````/_]_/W_````
+M_OW^_OS[^_S^`0("`@(!_P`"`P0%!@8&!0+__?W_`0("`P(`_OX``0(#!`0$
+M!`'__?W_`@0%!@<'!00#`P,$!`0&!@,!__[^``,$!`0$`P("`@,#`P,#`P'_
+M_?S\_?[_``$!```````!```"`@#^_?S\_?[^_O[__OW]_O[^_?S\^_GX]_?X
+M^OS^_O[^_O[^_O[^_O[^_?OZ^?GY^OS^_O[]_?W]_O[^_O[^_OOZ^OO]_O\`
+M`/__``````$!`0$``/[]_/S^``$!`0#_``$"`@0%!00#`?[]_?[_`@0%!00"
+M`0(#`P,#`P,"`?_]_?X``0(#`P,"`0$"`@,#`P0#`?[\^_O\_?\`````__\`
+M``#__P#__OW\^_O[_/W^_O________[^_O____W\_/O[_/W_``$#`P0$`P(`
+M````___^_O[^_?W]_?W_``$!`0#__O____[^_O[^_P`````!`@,#`P(!`0``
+M`/_^_O\``0$`__\``0("`P,#`@$!`/___O[^``("`0$!`0("`0$!`0$!`/_^
+M_?W^_P```0$````````````!`0#^_?W]_O\````!`0(#`P,"`@$!`0$!````
+M``$``/___P`!`````/____[^_O[^_O[^_O[^_P`!`0#___[^_OW]_?[^__[^
+M_O[]_O\``0$``/_^_O[^_O[_`/_____^_P`!`0$!`@$`________````___^
+M_?X``````0$`__[^_?W^__\``0$``````````0("`0$`___^_P`!`@,"`0``
+M``#_``$!`@(!`/_^_O[_``$!`0$!`0#___\```$!`/_^_?S\_?W]_O[__OW]
+M_?W]_?W^_P#_______[^_P`"`@$!`0$`__[^_P````````#__O[^_P```0``
+M`/______``````#___\`_P`!`0$!``````````$!`0$`______\``0$!`0#_
+M_O[__P`!`@(!``#__P````$!`0$``/____\```$!`0```/\```````#_____
+M__\````````!`0$!`0$````````!`0$```#__O[______P``_________P#_
+M_____O[_``````#___[^__\```````#__O[^_P``````___^____``$!````
+M____``$!`0$!``````````$!`0$!`/___P`````!`````/___P``````````
+M````````_____P````````$!```````!````_____________________P``
+M_____O[^_O[^_O[____^_OW]_O[^___^_O[^_O[__O[______O[^_O__``#_
+M________````````_____O___P``__\````````````````````!`0``````
+M```````````````````!``````````$!`0$!````____````````_____P``
+M````````````````````____`````````````````0$!````____`````/__
+M________``````#_____````____________________________________
+M________________````_________P```````/____\`````________````
+M````______\`````_________P``````_____P```````/___P``````````
+M`````````````/__`````````````````````/______________________
+M______________\`__________\```````#_____________________````
+M``#__________P``````````````````____________````````````````
+M`````/____\`````````````````````````____````````````````_P``
+M````````````````````````____________````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````0T]-30```!(``0``+Q8`"$`-K$0```````!-05)+
+M`````@``24Y35````!0\``!_`'\``````````````````$%04$P```&H4V0R
+M80`"````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````(`````````````````````````
+M````````````````````````````````````````````````````````!`@`
+M``````D`(P````````````````!X````!``$````````_`#___^``````0$`
+M!E%5;FET<P````````````````````````````````````````$"``8@<V%M
+M<',`````````````````````````````````````````````````````````
+M```````G`"\`#__V__D``0``````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````$````!>````'@```!6__3_\O_P_^[_
+M[/_H_^?_Y__N__@`!P`8`"@`-0`_`$4)1FER92!(;W)N`@```$%)1D939#)A
+M````````````````04E&1E-D,F$```````````````````````````````"G
+M/:W$```Q(@```<[_G_^L_\P``@!&`(P`R`#R`0D!#P$)`/P`Y0#'`*<`A@!E
+M`$0`)``$_^;_S?^[_Z[_J?^H_ZO_K_^R_[3_LO^P_ZS_J/^G_Z3_I/^C_Z3_
+MI?^I_[/_Q/_=__\`)0!.`'``BP"=`*0`I`"<`)``?P!J`%8`0P`Q`"``#P`!
+M__3_Z/_=````&@`I``\":@,Q`"H``P)M`ST`*0`/`D$#(@$`````&@`I``\!
+M4`'Q`"H``P)M`ST`````````````````&@`L`!8!/@'<`"H``P)M`ST`````
+M````````````&@`````````````````````````````````````!`````7@`
+M``!X````5@!QN+P<I@```!P`5@``5W-T80`#``H``?__`````````````O__
+M````'@```````___````/```````!/__````6@``````````````````````
+E````````````````````````````````````````````````````
+`
+end
diff --git a/sys/share/sounds/frsthorn.uu b/sys/share/sounds/frsthorn.uu
new file mode 100644 (file)
index 0000000..6649537
--- /dev/null
@@ -0,0 +1,259 @@
+begin 644 Frost_Horn
+M``I&<F]S="!(;W)N````````````````````````````````````````````
+M``````````````````````````!!249&4V0R80$``#0``````````"HB```!
+MSJ<]K9^G/:VH``````````````````````````````"!@34\``!&3U)-```J
+M&D%)1D934TY$```H'@``````````````````````````````````````````
+M`````````````````````````````````````````/__________________
+M____________________________________````````````````````````
+M````````````````````____________________________``````````$!
+M`@,$!08'"0H+#14A*2@H,#<[/STS)R4P0E5D;'%R<&I@4T<[+R0<%@\("!U#
+M7V5>8G1_?'IX:50_+!\8$@P&`?OY^?GZ`AM$9G5Q84DW-4%/4T]&-R8G0EM7
+M0R\9_NG:TM':\A@_6&!:3C\Q+30Y-S(R-C@U+B89"?3>S,/,ZQ0S.BL2]][+
+MR]KJ\OG___CLY.#>W=_BX=W7UM_V%"PR(@L"#BA"6&5A5E!)/#$L*RLI)R(9
+M#@H:.E=B7D\[)104(R\O)QP._?L2+S<P)Q3WW,:XOM;U#!D='!\B'A80"?[R
+MZNGO\_'KX=;1T]KH"#IC<6U<0"<?(BLX0#\[.SP\/3X[,R88"OWQX];0U^/L
+M[.#*M+'(Y?+T].?3OZN8CHZ6H:FMK:RPQ>8##@?UX='(S=[N\_'LX]7'RMG@
+MU,:XK*FOOMS^$Q<.^^36WO8.'",@%P\*!@+^]^S=R[>FGJO1_ALG(Q#\Z-3*
+MS][O_0D)_>W@V]K;WN'CX-S?[@$.%QX<$`+^$"@P*R08"?[V[>3:T,S+RL?`
+MOLKB^`(!]^[HX^+FZ>39SL*UK;+'W./CW<V[L+##W_<'#`D$"1DK-SL].B\>
+M#0']``@4'R`5!/?^'#E%13PM'Q0*`O[Y\>KGZ.WT_@<*!?SPXM;7ZP<9&P[W
+MW<K"TOTF-3$A!./)N[K!R,[4V-G5U-SM_@4`].KI[O#R\_'LYN+BX-[?ZO;^
+M`P<%__T$&3%`/S(E(BDQ-C4R+RLB%`;\]O3R\>[GVL[(U?PI/SPK$_WP[O<%
+M#@\'^NO=U][K\_#FV,F^O]#P"1`)_.W>T=+J"!85$0H`^?+JX]O4SLO+SM3C
+M]P$"__GQZ^3>V-'(OK2KI:*GON/\__7AQZZCK<KH^?SV[>3?X_(`!0+]]N[E
+MW]W;U]+.QKNQM-'^(C4V*1L6$Q`."P+VZ>/DY^GM]/CPW\JXL\7E``P,!?SU
+M^Q,D'0KYY]G3TM?=X-_;U,O(U.K]!@/UY^'F[_?\_?CMX-OH##1,444I#?T"
+M'#E&0C,B%Q(3&R$?&1`*!P0!_O;IV]/-P[S&Y000"_[MXN'I\?/R\O+T^@$$
+M`/OZ_/[]_`8<+2\A"_/EY_<8-T`V)1#][-K+Q\O.SLS(QM;[(3<W*`[UXMO@
+MY^WT^O?KX./W#!,1`NG7U^C]"PL`\NOL]/\%!P4"!`T;)2DD%P7W\/#^(4EA
+M9%A#+!T9'B8F(!D5$A`."P;__/OVZ=;&QM7FZ^C<RKBRQ>?X]N[?SL&VJZJT
+MQ,[/Q[_&X/P)"/_SZN;GZ.;?ULW%P,#.Z_[^]>C4P\/9^Q$6#P+T[_4`!PT1
+M#P?]\NC>V-?;W-3'NK;+\A$<%P?W[^SL[O#P\/'OZ>#:U-#2VN+H\@<>)!D%
+M[MG.SN($&QX9#/_[_?X!!@@%`P$"#!PH*2,6!_OOX]O8U]71S,C#Q-'E\?7P
+MYM[A\`<:)B@E(B`?)2LK)B`9$0P*!P'X\>[M[/00/%YI954\)AH9)3(X-"PG
+M)B8E(Q\5!?+?SL7)WO4!_>[:R<+-Z0$%`?7CU=#1U]WDZ_/V]/7_#!`-`_+A
+MV=SE[O;W].[K[?D1)RH="O+>UMWR#R4O,"TI)B4D(AX;&!,)__;P[O'Y__WU
+M\`(G0DE$,QP-!P<-%AL:$PL`\N+4S,K-T=?:W.?]$!0+_.OBZ`(<)!\7#`#Z
+M]_C[^_;LXM?,Q]+J_0+[[=O)O;O#S=/5T<B\N<C:W]W6R;ZZP-7V$AT9#`'\
+M^_X!`@$$#!,4$0L#^>[BU,K*WP4C*R42^^KCX^CL[.KL\O?X]>_IY^KMZN7B
+M[007&Q0%\^3F_A<?&@OSWM',S]GCYN7DX-WA]18S/C@H%`3\`A(?(AL2"Q(O
+M3EE1/B,*^/'_($!/4$I"/T-&1#LO(!`"]O#M[_7X]>WBUM#=^@\2!>[6R,C3
+MY?D*$Q83#04`_P#\].C:R\//ZP41#?SFVN4%(2PK(`SXZN3EZ>WR]O7OY^'G
+M]?[^^//S]?;T[N7<UM/3W?,$`_GOX]S;WNH`&"@M)AH4%APC*2XR,S,Q+BPM
+M,C4O(0\$#S%285]0/3`I*"LO,"XL*"$8#P;_]>SDWM?.R=#@Z^O@SKR[TO(!
+M_O3BTLS,T=C<V=#%N[*LJK+$W.SPY]G.S=?E\/#GV<S*W/L/%!40!/;ETLC5
+M]A8G+2D?%0P$_OCOYMW7T<K$P,#"QL?$Q-'K"A\C%@+R[O<(&24K*"$<'!\B
+M(R(=%@T#]^KI_1LL*AH#]`$@,S4M'`7RY.'J]?CW_`(%`?GQ\/L'"P7Z[NGM
+M]?P#!/[TY^/P`03]^O3LZ.;EZ_T9+SDW+RHK,3D_/3,E%PL#`0,'"03YZ=O:
+M[A$T14`P'0O^^P$)#0T)`OCNYM_:U-#,R<?&Q,+%S]G<V-+5Y_T+$`X`\>WP
+M]OT`__SZ^OKW]?@'(#E&1#<I(R4J,#$J'`P##"$O-#<N'`O]\>[W#B@X.3(J
+M)R<I+2TF'!(+!P@,$1,/`_+AV>'R"1XG(!@1#`X5&AP<&1,-!@'\]N[GY.+?
+MVM'%O<39ZNWEW>3Z"Q`1#/[OXMG6V-C4T-'4U<_#MK?*X>SLZ.'<W>7O]O/G
+MU\_;\?KW\>77S\W-SM7H`10;%PT#_/CX^_\!__OY^?K\_OWW\.WW!@T2'!\7
+M$`P)#A<?(B(?&A0/"@4`^?#EV,K`N[K!U/`#!OGIZOL,&"$@%P\(`?_]^/3S
+M]??W]?#L\PPJ.STU)Q@+`?\`__?LY_`%%1P?&`;V[>?E[@(@.TI,0C0F'QXC
+M)R0;$`@%"`P,!OSOX=?:ZOT0)S@W+!X,_/7V_@@/#PD`^/+MZNCGY>+>V=+-
+MT^7\"P\-$B,Q,"H@$`,``@<.$0\*!@(`_?CQ[?#[`P/^]_'P]@`(#`G^[^GQ
+M``<)"0/Z]?+O[O']%3)(4T]!,28B)S1!1D,Y+2(6"O_X\NWO`ADE+3H],RD?
+M%Q05%QL?(!T8$PP#_/3JX-3'O[NYN\;<[_'FV-';Y^CDX-7+QL3%R<O*Q\;'
+MR<K*R<C0Y_\,"__NW='/V.;S^P`,'B8?%0P`\^G>U=#4Y@4A+BL?$`3^_@`!
+M_O?Q[.GFX-K6TLS'RMCI]04;)2$8"OSV^/T%#A49&QT=&1$*!/_Z\^KAW-_P
+M#BDV-C(X04$Z-BXD'!80#0L)"`D(!/[W[^;BZP$5'!8'].3<W.7M[^;<WN__
+M!`3_\N;AX>/H\PLL1U)-0#4P+S(W.C8M)!L2"0#Y]O?W^@86&Q48(B0?&A(*
+M!00%!P<%__CS[./8T,O*S,[/SLW/VNGR\.GDZ_H#"0\0#P\,!P#Z]/'R]/C\
+M____"2`[35%)."@A(RPR,2DA)CM-344Y)Q0(`?[_`PXE.D`Y+!T4$!$2$0X'
+M_OGV\NODW][>X>X('!T9'B`<&14."PD)"@H(!PH-#0D#_/;NYMK+O*ZFK<7D
+M^/OY_08&`?_\]>SBULW)R,K0UMC6T<B_O,C?]?WZ[^+9UM?<X-[:X/<3'AH1
+M`.O?V]G8VN3X$RDS-#`J(QX<&QD3#`3__/O\_P,$`0$*%Q<1%A\>&!,,!P8)
+M$!@=&@\!\N3:V-O?X-W8T,6\O,WH_@<($2(K)R$;$`;_]O#N[N_R]?C]`0#X
+M[NKV"A<9$@;^_@(("P@`]O<)&QT6#P3Y\_#N[>ST"!\L*R(4!O__"!0=(2(>
+M%0K^]>[GX-WA[OH"#A\F*"LF&Q0/"PH*"@D*"PX0$`T&_O7O[>SJZ_/^!04"
+M!QLP.#@T)1#^[N7DZ?#W_?[]^_;Q[O,$'2XT+R06"?SQZN;BX.C_&24C&@GW
+M[_#S]OD`$28W/T$_/CPW,BLD'10,!P8'"@T."P8$#!<=(RDG'A<.!P,"`@0'
+M!P#W[>/:TL[*QL3`N[.MK;C,VMW9VND`"PH'_O#EWMG:WN/I[?'R\>SAUM/A
+M^@T4$PT'!`(`_OGPZNT!&2`9#P+PX=?0S]7F`QXK*A\2"`+__P,'!@'Y[^/5
+MR,'#Q\G+U.'M^PT6%!$-!?_\^OGY]_7U]_CW]._KZ>CGY>/BZ?H1(2(7"`<9
+M+#$P*AT3#@P,#0T,"0/[[^/8T]GM!AD@'!$%_P`'#A$-!@(-)CL],R82__/M
+MZ_4+*T1-23PO)R4H+"TJ)!X;&QL9%`O^\.+8V>L)*3Y!-B@9"@$``0("_O?N
+MZ.7DY>3BW]G4T,S*T.#S_O_VZ>/O!Q@=&@KUZ>7G[_C]`04("`/_``TF/TM(
+M.245#0T3&1T=%A`4)SL^,!\+]NGFZ/('(C(S*R`5#PX0$1`,"`0"`0$#!04`
+M]>;7TM[]'C(X+QX,^_#O]P(-%!84$`L$_/'IX][9T\_/V>X""0?_\^[Y#184
+M#`#PX]S9V-?3S<:_N[BXP-7O_P#X[-_6T=#1T<_*QL7/Z`<8%PX`[-S3T=WV
+M$R8L*!T1!O_]`@D/$0X)!/[Y]_?X]_/NZ.L!'S0\."H:#0/]_/X$"@T,"@D(
+M!P+[\NG@VM?8Y/L1&A,![.#I!R8T-2P8!/7IY>KP]/;V]._I[``=-$%#/#,L
+M*2HK*B8?&`\(#!XK)1<*]^+8V>7^&"@J)B`:%A(/#`@#_OGV]?C]`0,"_?/G
+MW-SS&#,].2H6!OGS^``#`O_[]O/R\_/Q[>?@V=37Y/H/&14']>GK_A@F)AP(
+M\^GI\/?[_O[\^?;V`!0H,2XC%PT)"Q,=(B`7"O[T]08>+#$P(P_]\_<-)C0U
+M,"<A'B(J,30S+RDA&!$-"@@&`?CKW^'Y'#(T+!P(^.SGZN[Q\.[KY^+>VMC7
+MU,['P+R_S^G[_O7EU<C+XP(1#0+UY-;0SM'8W^+DYN;G\047'!D/`O;P\O?\
+M_P$`_OKS[O,"#@T)`._?W.?]$!41"/WV]/@`"`@!^._HY>/@WMO9UM'+Q\SD
+M#"HS+B`)]>KK^`D5&!<5$@X*!O[SZ.+?W=WG_14E*"`2!?GT`R$V."X>!O'F
+MYNSU^_SW\>KDZOX5(B,<$PT+#`X/#0D%`/OT[?`!%!H7#O[MZ/(%&28G(1XA
+M)S$\0D([,B@=$@D$!0P3%A0)_?H,*SPY+R(0_O/S^@($`?KQZ.#8T]#.S<W-
+MSM+;Z?/W].O@V=;8XOD1'2$A%PH#`/[^_OW[^?L%&S-"0S@H&0T(#18<'1T<
+M&A4-`P47)RDB&0G[`!4J-34L(!<3$Q89&QP;&!0.!P#W[^CDW]O8W/`1+C@Q
+M(Q,!\NOK[N_O[.OL\/3W^?KW\>?<UM[X$Q\>%@G\\.7@Z@`/#@;\[-O1S,S.
+MT,[&O+>_U_$``??JX-S<X.+CX^/CX^/@WN;["PH!]>7?[087&Q8)^O'T_PT2
+M#P;\]._Q^0,("`+WZ=G/SMS['3`P*!H(^/+S^/X"`P#[]O#HXM_AY>;G[P(9
+M)209"__X]_C^#B8U,2<>%`L'!08'!?_W]0`8,T1%.RPA&QD;("0E)"$<%@T`
+M\>SV!0H'`?C[#!H>&Q,)`0`&#1(3$0T*"`8#_O?PZ^?BW-KA\`0=,SDM'0SX
+MZ./DZ>WQ]?C\_P$!`/WX\>GDZ/@.'1\6"?SS[^[P^@P:&Q4-__/MZNCGZ>GG
+MZ?0%%B(E(AP6$Q08&Q@1"PH,$!(0#Q8F,"H>$PT5*3D^.S0N+3(Y/T`\-2XG
+M(!D3#PT+"07_]>SI[O8"$AD3"O_QY^/?W=[?W=C4T,S+S='4T]'4X_<"`OKO
+MX-+(P\+$S^?Z_/7MXMC4T]38W-W=Y?D.%Q(%].;?X>OW`08'!@'Z\^OAV-?F
+M^?_]^?D$$!,/!_WT[_'W^?CX^?S]^_CU\_'O[.;>U]7<Z?D0*30P*1\3#`H(
+M"0L+"`4$!`,#`P'\]?+]$B0I(Q@)_//Q]OO_"1HF(QH/__+MZ^SN[>KN`1XT
+M/3HM'A(*!P<)"0<$`/OT[N?AX.T'&AX:%QPE)AP/`??T^@@7("`9$0L%__OX
+M]_GY]O'JY>GY#2$V0SXO(1,%_OS]``,#__GV]//S\N[GX-WC\?\%`_KOY^7I
+M\OC^#2$K*"(6!/;P[_'V^OP%%B@P+R<<%18=)R\P*R0>'!H7$@H`_`05'QX=
+M'R4N,2PB%Q`-$1D@(A\9$0@`]_#JYN3FZ.GGY^_\`00-&1H5#PD!^O'HXN'D
+MZ.SP\>SEW-70T^+\$!<4"?OPZ.7DX^#<XO+\_/KTZN':T<K%O[O"V/#\_/?R
+M[^[P]/CY]?'O\/#MZ.#7U>+Y`__\``4(!@'[^?P!"Q4:&182#0D'!@4#`/SW
+M\NSFY_4&#Q8A*2@A&A`(!0']^//LY-[=X./EY^CGYNWZ!@L(`?CR[NWN[>KM
+M_A0=&1$$\^CBX>3H[?@.*T!(1#<I'QP<'B`@'AP;&QD5#P8!!A<F(A<4&B,H
+M)B`:%`X("`P0#0D&!@<'!@4%`__WZ][6U^'L]04<+"XK(Q4)`/GS\?/V^/KZ
+M^/7PZN/?X_$%$A0-`O;O[.WO\/#S_PH-#`@$`@0&!/_Y]/4$&2HQ+20=&1H?
+M)2<E'Q<0#`P-"@+\_@L3$`\;*C0V+B0<&1H>(R<G(AP4#PT.$1,2#PD!]>C@
+MX^_V]OD"!P3_^O+JY-[:V=C6TM'3U=/.Q[ZXN\O@[O#GV<_,TMO@X=[B\@0(
+M!?[QY=[;VMO<W>?]$Q\?&1$,"PX3%Q81#`<%`P#[].SDY?+[]O#W!`P."@/\
+M^/CZ_P0$__?MY-_>WM[>WM[;UM#/VNOV_0D<*2<=%`H&!P<)#A06%!$0$1(1
+M#0;^_0H;(B$9#P8`_?W[\^KI]P8)!?_TZ.'=W=[>X.K^$R(D'1(*"`T6'!P7
+M$0H%`?WZ^/;Z"2`L*B@M,C8U,2LE(1\?(2$=%Q(/#0L)!?[W\.OFX=O=Z?;[
+M_0@:(R,?%0?]].SFY.+>VMC8V=O=W=S=Y_@($1$*__;P\/3X_`(3*30S*AP-
+M!`#]_?W]`1`I04U.1CPS+BLI)R4C(B$?'AL3!_KT_@T0#1`7&QP7#@7^_/T`
+M!0@&`?OU\.SIY^3BWM?-P[N\R][L]@83$0;[\./>W^/M]OS____]^O;OYMO:
+MZ``0$@H`^OG\_P'^]_/Z!PL(`_?IX-O7U-/5WO(,'R,;#0'[_`(("@D'!@4"
+M_/3KX][D]PH,!PH2&1L7$0H&!@@-$A05%102#PL$_//KYN'<U];=Z_7Z!!(9
+M%1$,!P0#`/W]`00#`?[Z]?#JY.#G_QHG)1H+^^S@V=C:WNL!$Q@8$@3UZ-_<
+MW-[C\@PD,#(J'1(,"@L-"P8!`00'!P/\\NSQ_P@'!P\;)"4>%0T*"Q`6'!X<
+M%Q`)`_[Z]>_HXMW9U]OI_0P8)C`M)1\9%!(0#@T+"`4"__SY]O'JX=S@\`,-
+M#@@`^/7S\_#KZ/$"#`T*`/+FWMG:W>'J_1<M-C`A$03\^OT``0#__P``_?CP
+MZNX!%AL6%1HB*"8A&1,1%!H?(!P7#P;^^/3R\>WHX][:UM?B[?7_#A@8%!`)
+M!@8%`?_^_/KW\^_KZ.3AX.;W#AXA&Q$(`@$#!00#"QLF)B`6!_GNYN#>WN#K
+M!"`Q-2XB%@\+"P\1$0X*!0#Z\NC<U=OO_O_\``D4%A`)__?R\?;[_/GW]?/R
+M\.[IY-W4S,;#Q<[<ZO<(&1\<&!(*!@'[]O/R\O7\`@4"^_+IX^;V"104#03\
+M]_C\_OW_#1T?%@S_\.?CX>'BX>+M`!0?(AP2"P@)#0X*`OOV]?3S\N[IZO8#
+M!@$!"QTI*2(;%Q<<)"TT,BPB%PP#^_7P[NWMZN;G\@<6&ATC(QH2"?_V]/3U
+M]_?U\>WIYN/?VM;2TMWQ`@@!].CDYNOO\?+Z"Q<6$0?XZN3CY.?IZ_4+)#8Z
+M,B07#@P2&AX?'QT8$@L$^_#J\@0."0,'$Q\D(1D2#0T/$1(1#PP)!P<&!/_V
+M[.+9T]#3X/(`"!$<(!T9%A`,!P(``/_Y\_#R]OCV\>KE[0`2&1@1"/_Y^/GX
+M\NSP``T+!/ONY-[;V=C7VN?_%B(A%PH!``4,$`\)`?;LY-_=V]K>Z?H#!0P8
+M(2(>%0P'!PL5'B0E(QX8$0H#_??R[.?BWM[I_`@(!`D2%A(+`//M[O+U^/CT
+M[>;@W-O:V-CB]0@0#0+UZ^CJ[_3U\O,!%!H3"O[PZ.?FY^OT!A\T/T`Y+R<B
+M("`>&Q<4$Q$,!P#X[^;D[/?_"1DB(1X8$0X/$1(0#0@#_??PZ>#9U=/1S\[-
+MTN+Y#102$ATF(QL4"?WU\.WN\O7Y_@(!^_/IY.P"%A\=$P@"``$"`/KRZNS[
+M"@X+`_;JXMS8V>+Q`@X3$Q(4%QD<'AX;%`T&`/KT[^KEX>#H^Q(G-#,I'A82
+M%1PA(1X9%!`-"0/^^?/MY^+<V-KE]0,(!OSW`A@D(QX3!?GQ[.OLZN7?W-S<
+MW>'M_Q`7%@\&`@(%"`@"^.WEYO@1("(=#_SLX^'M!R`N,"HC'1L;'B$A'AH7
+M%!(0#`;\\>;=U=3A_!4@'0__\_#V``D-#`<!^O7R\.[JY>'=V=75W^_\__OS
+MZ.+K`QPG)1H*^>_JZO#W^O?Q[.CG[P$3'!P6#04"`PD-#`?_]>G>VN7V_O[Y
+M[=[6U^;]$1<3#0D("Q`4$Q`)`OSY^OT!!`3^]>SG[@8G0$E%-R07$1(7'B$@
+M'AL7$0L%`/OV[^;@W^K["0X*`?7KY./O!A<:%0O\[.#8U-36UM74UN+U"A@;
+M%@T&`/SZ^/;S[^OHY.#>Y/4$!P'VZN;N_@T9'QX;&R`F*2<B'1D5$@X)!/[Y
+M\^SEXN/J^1(J-3(J(!4.#`L*"0<$`/[\^O?T[^KFX^CW"109&!0/"0+[\_+_
+M%"$C'A4'^_'HX^+BY.S\#1<9%1`,"0D)"`4#`P,!_?GRZN+=XNWU^/T#"`H+
+M"@H-$1$/#`D$`/SY^/GZ^//NZ./>VMSD[._M[OL2(B8C&P\&__GZ``8)"0<#
+M_/7LY^OY"`\/"0+^_?\!`?OPX]SD^`@,"@/VZ=[7V>7S_0(&"`<%`P0'"08`
+M^?/O[N_Q\?#LY^'@[`,9)BD@$`+Z^/P%"@T0$Q89&AH7$@L$^_/R^PL7&A<1
+M"P<#!A0G+2<>$P7Z].[KZ^SJZ.GR``P1$A`,"`4"`/[[]_+MZ>;BW-C=Z_7U
+M\O+U^P$$!04&!@@,$!(0#`<"_/;Q[>KHZ.KR_`4)!?SV^PP<(B(<$@@#__W^
+M__SX]O3S]?X*$Q<6$PX(!`,$!@@'!/WV\_L,&!D6$`D*$A@;'!H7%!,4%A@8
+M%A(."P<!^O/NZ^WT_0'^]NWO_0H,"@3Z\NWIZ.GJZ>;DX>#B[/T/&1@0!_[W
+M\>WN\O;X]>_J[P`/$@P"^/8!#1(3$0T*"@P0%!87%A(-!P#[]>_LZNGM^@4&
+M__\*$Q01#07__/S^``#^^O;R\.SGY>O\#Q<4"__SZ^?I\/?Y]_/W!A8:%@W_
+M[^+:V^P#$A84#0<!_?S^`@0#`/SX]?/R\.SFX-G7XOL2'1H1`O/KZ_/_"`L+
+M"08!_/GX^/7PZ^[["Q8:%@\)`_WY]_\0'R$;%`K_^??W^/CW_@L7'1P7$0T+
+M"@H+"P@$`/W[]_+KXMO7V^K_%!\>%@P"]_#L[?#U]_CW]_CX]_;T\>WIZ_0!
+M"0P*`_GP[OP1'B$>%`?^^?;W^?KY^/H"#1<:&10/"00"`P<+"PD%`?ST[.;K
+M^`,*$189&180"@3_^_K_`P4&!@<)"@D&__?NY^7L^@8(`_KR]@,.$!`-!@'_
+M_OX``P,!_OKX_0D3%Q4.!__Z^/L`!@@&`?KPZ.?R_@(`^_C[!0H+"@D'!04%
+M!PL.#@T+!P+]]_+NZ^GO_`D."@0$#A@:&!0-!P,!````_OOY]_/NZ>SW`P@'
+M`_WX]?3V^O[_^O+IYN[[`?[X[N'9W>OX_O[Z]?'N[_/Z``("`/OU\.WKZ^KG
+MY>7K\OP+&R(A'181#Q$2$A,1#@H&`?_]_?P`"Q@?'AH3#`3_^_KY]_/Q^0D5
+M%A$*__/JX^+K^P8+#`D%`O_]_/W^_/KX^/CW]?/OZN7BYO4-'R4B&0T"_/K[
+M_P$!__[^_O\```#]^?C\!@T/#0@!^O3P[N[S_PX6%`\'_O;Q[.KK\?L$"@X0
+M$`X+!P0%!PD)"@L+"@@%`OWX]/D*&R0E(!<0#0L*"PP-#0P+"0@'!@/^^/+Q
+M]@`+$1`+`OCOZ./H]PL6%Q,+`/?NZ.3CX^;O^P4*"P@%`?WZ^/G\``,"`/WY
+M]O+MZNSW!A,='QP7$@X+"08$`@(#!`8&!`']^O;R[NWT_P<(!@'[].[N^`8-
+M#`D#_/?S[^WKZ>?FZ_8"#`\."P@$`0`!`P0$`O[X\^[JZ.GO]OK^!`@(!@/_
+M^O;T]/;Y_``#`O_[]O+P\._M[?#V^_W\^?7R]/T&"@P-"P@%`P#^_/KY^OL`
+M"1`4%!(/#`H)!P<&!@8&!0,!_?GY_P0$!`D.$Q,/"0+[]?+S^/T!`P0"`?[Z
+M]O+O[>OK\?H``P#Z]/3\!`@*"08#`?_]^_GX]_;V]OH"#18;&A82#0D%`P,$
+M!`0#__KW^P0+#0L(!0<+#0T,"08"`/\``P8("0D(!@,`_?GU\?#Q]_X"`?__
+M!@X1$`X*!`#]^OGX]_;T]//T]OP&$!45$@\+"08%!`,"_OKU[^[S_@<)"`/]
+M^_X#!08&`P#^_@`#!04$`P(!`?_\^OCV\_+T^?S\^OT&$!,0#`@%!`,!__W\
+M^OCW]_C[_P0)#0X-"P<$`@#__?OY]O/P[O'[!`8#__KV]_T#!P@&`P'__?S\
+M_/OZ^OKZ^OGW\NWGX^'AY>OP\_;]`P4!_?OX]_?W^?S^__[]^_GW]OC]!0T2
+M$Q$,!@+^_?X!`P,`^_C\!@X1#PH$_OP!"`L,"PD&!`,#!0@*"PP+"08"__SZ
+M^/;S\?'T^/K]`PL.#0H'!`("`P,"`/SX]/+S]/3T]OG^`0,"`?_^_?SZ]_7T
+M\_/S\_7\`P8$`?WY^/O_`@,$`P,$!04&!P8&!@8'!P@'!@4$`P(!`@4("`8%
+M"1(7%A01#@T+"08$`P(`_OSZ^?GZ_0(("PL(!`#^_?W]``,$!`+^^O?Y``8&
+M`O_[^?K_!0<&`__\^_T"!@D*"`8$`P$`_OSY]O/Q\?7\`@8'!00'#Q04$Q`,
+M"04"``#__OW\^OCV]/7Y_@("`@#__O[_``$!`/[\^?;S\>_R^?W[]_3T^0`$
+M!0,`_/CW^/O^``#__?S[^_OZ^??T\?#Q]_\&"0<"^_?Y`PL.#PP&`?WZ^OS]
+M_?OX]O7T]?G_`P8&!`'__P$#!`,"`/[\^OCV]?3V^P$!__\!!`<'!@0!```"
+M!`8("`<%`P$!`@0$`O_\^?;V^P(&!P4`^O;U_`8+"PD%`/S[^OGY]_7S\?'S
+M^0`&"`<#_OKW]_K]_____OW[^OCW]?/S]OL`!`D.$1(1#0@%`@$!`0(#!0<(
+M!P<&!@8'!@,!``$%#`\0#@L&`O[]`0L2%!(/"P<#`?_^_/KW]/+S]_\&"@L*
+M"`4#`0```````/____[\^??T\?+W_`()#`L(!0+__?W]_O[]_?W^__[^_?S\
+M_/S[^_S_!0L-"P@$`@#]^?H!"`L*"`4`_/KY^?KZ^?GY_`('"@L*"`8$`@$`
+M````_______]^_CU\_'R]@`)#@\-"04"`/___OS[^?CW]O;V]O3S\O'Q\O/V
+M^P`#`P'__?OZ^OGW]O?]!`H+"08"_OOY^/GZ_/\"!0<'!@4%!04&!P<&!00$
+M`P'__?KX]O7U]?7V^@()#@X,"`4"`/[^_?W]_/OZ^/?V]?7V^/K^`00&"`<&
+M`P$`__W]_/S\_/S]``8)"@<$`?[\^_O\_@$$!04%!`,!__[^_P`!`0#__?OY
+M^/CX^?GY^OK[_/X``P<*"PL)!@0#`P,"`0#__O[]_?S\_?[_`@0'"PP,"P@&
+M!`(!``#___[]_/S[_/T!!08$`O_]_/X``P4$`P'^_?S\_?W^_O[^__\``/__
+M_OW]_?W]_?X``P4%`P$!`P<)"0<&!`,#`P,#`@$!`````0``__\``@0%!00#
+M`@#__O\```$!`/[]^_GX]_?Z_@$"`/[\^_P``@(!`/_^_?W^_O[^_O[^_O__
+M``#__OS[^OGX]_?Y_``"`@$`_?OY^OX"`P,"`0#___[]_/S[^_KZ^?GY^_\$
+M!P@(!@4#`@$!`@(#`@(!`0#__O[^_?S[^_X"!`4&"`D)"`8$`P$```````#_
+M___^_OW]_?[^_OW\^_GX^/O_`@,#`?_^_/KY]_C\`00$`P'__?S[^OGY^/GY
+M^OP`!`8&!@0"`0`````!`0(#!`0#`@$`_OW\_/S\_/X!!@H,#`H'!`(!````
+M`0$!`@,#`P("`0#__O[^_?W^_P`!`P0#`P(``/_____^_?W\_/\#!P<&!`(`
+M_OW\_/S\_@`#!04%!`,"`0#__O[^__\``0$!`0#__OW\^_O[^_K[^_W_`P8'
+M!@0"`/[^_O[^_O[^__________[^_O[__P`"`P4%!`0#`@$`______[^_?S\
+M^_O^`0,#`P$`_OW]_/S]_O\`````__[^_?S\_/W]_?W^_O[___[^_OW^_O[^
+M_?W\_/S\_/X``P4%!00#`@$!```!`0$!`0$!`0$``/_^_OW]_@`"!`0$`P(!
+M``#__O[]_/S[^_KZ^_S_`0("`0#^_?W\_/S]_@`"`P,"`/_^_O[^_O__````
+M`0$!`0$``/____[^_?W\_/S\_0`#!04%!`,"`0#___[__P```0$!````````
+M``#___[^_OX!`P4%!`,"`0``__________\```$!`0$!`0$``/_^_?W]_@`"
+M`@("`0#___[^_O[^_O__``$!``#____^_O[]_?W]_/W]_@`"`P("`0$!`@(!
+M`0```````0$!`0$!`0``___^_O[^_P`!`@,#`P("`0$```#___[^_?W]_?[^
+M_______^_O[^_O[^_O__``$!`0````#_____________````````_____O[]
+M_?[^_O[__P`!`0```/___O[^_O[^__\``````````````/____________\`
+M``$!`0$!`````````````````````````/______________``$"`@$!``#_
+M_______________^___________^_O[^_O[^_O[__P`!`0$!``#_________
+M_O___P`!`@("`0$```````````#_____``$!`0$!````______\`````````
+M`/_____________^_O[^_O[__P`!`@(!`0```/_______P````````#___\`
+M````````_________P```0$!`0```/_______________P```````````/__
+M____________``````````#___________\```````#_________________
+M______\`````````_________________P```````/________________\`
+M``````````````#_______________\``````````````/___P``````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````!#3TU-````$@`!```H%@`(0`VL1```
+M`````$U!4DL````"``!)3E-4````%#P``'\`?P``````````````````05!0
+M3````:A39#)A``(`````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````Z``````````````
+M````````````````````````````````````````````````````````````
+M```````$"```````"0`C`````````````````'@````$``0```````#\`/__
+M_X`````!`0`&455N:71S````````````````````````````````````````
+M`0(`!B!S86UP<P``````````````````````````````````````````````
+M`````````````````"<`+P`/__;_^0`!````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````0````%X````>````%8`
+M``$A!%-!1$6!`0`````.```&`:/4?J:EY/O_```B8`I&<F]S="!(;W)N``(`
+M``!!249&4V0R80````````````!!249&4V0R80``````````````````````
+M`````````*<]K9\``"HB```!SJ3CM?BFFTU2```````L`.(!$`([`0``M`$I
+M`8#_^/_L````````@`````````````````````````````T````!(0=38W)I
+M<'1S`0`````0```&&*/6\<"EY/O_``````"V`$H!<@'>`0``D`#&`0#_^/_C
+M````````@``````````````:`"D`#P)J`S$`*@`#`FT#/0`I``\"00,B`0``
+M```:`"D`#P%0`?$`*@`#`FT#/0`````````````````:`"P`%@$^`=P`*@`#
+M`FT#/0`````````````````:````````````````````````````````````
+M``$````!>````'@```!6`'&XO!RF````'`!6``!7<W1A``,`"@`!__\`````
+M```````"__\````>```````#__\````\```````$__\```!:````````````
+M````````````````````````````````````````````````````````````
+`
+end
diff --git a/sys/share/sounds/lethdrum.uu b/sys/share/sounds/lethdrum.uu
new file mode 100644 (file)
index 0000000..2c19869
--- /dev/null
@@ -0,0 +1,433 @@
+begin 644 Leather_Drum
+M``Q,96%T:&5R($1R=6T`````````````````````````````````````````
+M``````````````````````````!!249&4V0R80$``$X`SP```````$B,```!
+MZ*<]F@*G/9L$``````````````````````````````"!@6!?``!&3U)-``!(
+MA$%)1D934TY$``!&B```````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````/___P``_P`#
+M`@$!``#__P@.!/CU]_T!^?;\``#__/S\^?3P\?3U]?7V^?GX^/KSZ^ON\O3U
+M^/?R\?'V`@@,#PP)"@\7%0X-!_[Z`1`9&!03%A@;("`4"@8"``4-$Q0/"@D+
+M!O[Z^/?W]OH#!0($!P/[]>WJ_QH@&A0+`?_Z]O#HY-[=Z?3V[>SW\>7AX>?L
+MYM?+Q;R[R=CAXMS9W-_>W^'BY>SS^@`!``(%"Q0<)"PT.CDV.#Y!0DA36UY@
+M8V)=54M$0T,_."TC&1`(`__Y\^OCW=K7T<S(Q<3!N[:SLK2UMKB[N[>QK["R
+MM+:VM;2SL[C"R]'7W./L\O;Y^_S^`@<,$147&A\D*"TR-38W-S<V-#(R,C(T
+M-SH[/#LZ.CHZ.3<T,S(P+RLG)20C(2`?'QT:%A$."PD'`__Z]?#MZ>;BW=G4
+MT,K"NK2NJ::DHZ.CI*6FI::GJJ^TNL#%R,K.TM79W^3I[O/Y``4+$18;'R,F
+M*"LN,C0V.#H\/T-(3%%55E965%%-245!/3DV,B\J)2`;%A$-"08#`/WY]?+O
+M[.GFY.+@W]W<V]G8V-C7U=+0SLO)Q\3"P<'!PL/%Q\C)R<G)R<K+S<[0T]G?
+MY>SR^/\$"A`5&1XB)2@L+S,V.3T_04)#1$1$141#0D%`/SX].S@U,B\M*B<D
+M(1X;%Q,0#`@$__KU\.SGX]_;V-73T,W*QL+`OKR[N;BXN+BYN[W`P\;(R\[1
+MU=C:V]S>X.+EZ.OO\O;Y^_X`!`<*#A$4%AD;'2`B)2@L+S0Y/D-(3$]04%%0
+M3TQ)1D(^.3,O*B4B'AH7%!$."@8"_OKV\>WHX]_:U=#,Q\/!O[Z_O[^_O[^_
+MO\#`P,'"P\7'RL[1U=G>X^CL\/3X^_\"!@H-$!,5%Q@:'!X@(B0F*"DK+"PM
+M+2TM+BTM+"LK*BHJ*2DH*"DI*"<E(R`=&QD7%!(/#0L(!@,`_?GU\>WHX][:
+MU]/0S,G&Q,&_O[^_OKZ^O\#!PL/%QL?)R\W/TM78V]_DZ>[T^O\%"@\5&ATA
+M)"<K+S(U-S@Y.3H[.SP\/#LZ.#8T,S`N*R@D(!T:%Q01#@L(!`']^?;S\>[L
+MZ^GHY^;EY>;GZ.CHY^?FY>3CX=_=V]G7U];5UM;6U]?7V-G:V]S>X./FZ.ON
+M\?3W^_X!!`@+#A`2%!<9&QT?(2,E)RDJ+"TO,C4W.3H[.SLZ.#8T,2XJ)R,@
+M'!@4$`P(!`#\^/3OZ^CDX-W9UM32T,_.S<W-SL[.S\_0T=/4UMC;WN+EZ>WQ
+M]?G\_@`!`@(#`P,#`P,#!`0%!P@*"PT/$!$1$A,5%A<8&1H:&QP<'1X>'AX>
+M'Q\?'QX='!P;&AD8&!<5$Q(0#PT+"08$`?_\^?;R[NKEX=W9UM/0S<O)Q\;%
+MQ<;'Q\C*R\W/T-+5V-K=X>7I[/#S^/P!!0D.$Q8:'2$D)BDK+2XO,#`P,"\N
+M+"LI)R4C(!T:&!84$Q$0#@T+"0@'!00"`?_^_?OZ^/;T\O#O[N[M[>SL[>WM
+M[>WM[>WL[.OKZ^KIZ>CGY^?GYN;EY>7DY./CX^/DY>;HZNSO\?3X^_X!!0@,
+M#Q,6&1P>(20F)RDK+B\Q,S0U-34U-#,Q,"XL*28B'QL7$P\+!P/_^_CT\>[K
+MZ.;CX>#?WM[>WMW=W=W=W=S<W-W=WM_@XN/EY^GL[O'S]??Y^_W_`0(#!`4&
+M!@8&!@<'!P@("`D)"0D*"@L+#`P-#@\0$1(3%187&1H;'!P<'!P<'!P;&QL:
+M&AD7%A02$`X,"@<$`O_\^?;S\.WJY^3AWMS9U]74T]+1T=#1T='2T]76V-K<
+MW^+EZ.ON\?3W^OT``P8("PX0$Q46&!H<'A\@(2(C(R,B(B$@'QX<&QD8%A43
+M$A$0#PX-#`H)"`@'!@4$`P(!`/_^_?S[^_KY^?CW]O7U]//R\?#O[NWLZNCG
+MY>3CXN'@W]_?WM[?W]_@X>/DYN?IZ^WO\O3W^OS_`00'"@T0$A48&AT?(20F
+M)R@I*BLK+"LK*BDH)R4D(A\=&Q@6$Q$.#`D&!`'^_/GW]?/Q[^[M[.OJZ.?F
+MY>7EY.7EY>7EYN;FY^?HZ>KK[.WN[_#R\_3U]O?X^?GZ^_S]_?[_```!`@0%
+M!@<("@P-#Q$2$Q05%A<8&1H:&QP<'!P='1P<&QL:&1@7%A03$1`.#`H(!0,`
+M_OOY]O3Q[^SJZ.;DXN'@W][=W=S<W-W=WM_@X>+DY>?IZNSN\/+T]OCZ^_W_
+M`0($!0<("@P.#Q`2$Q,4%!45%145%104%!03$Q(2$1$1$!`0$`\/#P\.#@T-
+M#`L)"`<%!`,"`/_^_/OZ^??V]?7T\_+Q\.[M[.OJZ>CGYN7DY./CX^3DY.7F
+MY^CJZ^WO\?3V^?O]``(%!PD+#1`2$Q47&!D;&QP<'1X>'AX>'QX>'1T<&QD8
+M%Q44$A$/#@P*"`8%`P'__?SZ^?CW]O7T\_/R\?'P\/#P\/#P\/#P\/#O[^_O
+M[^_P\/#P\/'Q\?+S\_3U]?;W^/GZ^_O\_?W^__\``0($!08("0L-#A`2$Q46
+M&!D:&QP<'1T='!P;&AD8%Q44$A$/#0L*"`8$`@#^_?OY]_7S\>_N[.KIY^;E
+MY./CXN+BX^/DY>7GZ.GK[>[P\?/T]O?X^?O\_?[__P`!`@,$!08'!P@)"0D*
+M"@H+#`P-#0X.#@X/#PX.#@X.#@X.#@X-#0T-#0P,#`P,"PL*"@H)"`<%!`,!
+M`/[]^_KX]O3R\>_N[.OJZ>GHZ.CHZ.CHZ.CIZ>GJZ^SM[N_P\O/U]_CZ_/X`
+M`P4'"@P.$!(3%!46%Q@8&!@8&!@7%Q85%!,2$1`0#PX-#`L*"0<&!00#`@$`
+M__[^_?S\^_OZ^OGY^?GY^?GY^?GY^?GY^/CX]_?W]O;U]?3T\_/R\O+R\O+R
+M\O+R\_/T]?;W^/GZ^_W^_P$"`P0&!PD*#`T.$!$2$Q05%A<7&!@9&1D8&!<7
+M%A43$A$/#0P*"`8$`@#^_/KX]_7T\O'P[^[M[.OKZNKJZNKJZ^OL[>WN[_#Q
+M\O/T]O?X^OO\_?\``0$"`P,$!`4%!04&!@8%!04%!04%!@8&!P<'!P@("`@)
+M"0H*"@L+"PL+#`P,#`P,#`P,#`P+"PH*"0@'!@4$`@'__OW[^?CV]?3R\?#O
+M[NWLZ^KJZ>GIZ>GJZNOL[>[O\/+S]/;W^?K\_O\!`P4&"`H+#`X/$!`1$A,3
+M$Q,3$Q,3$A(1$!`/#@T-#`L*"0@'!@4$`P,"`0$`___^_?W\_/S\^_O[^_O[
+M^_O[^OKZ^OKZ^?GY^/CX]_?V]O7U]?3T]/3T\_/S]/3T]/7V]O?X^?GZ^_W^
+M_P`"`P0&!P@*"PP-#@\0$1(2$Q,4%!04%!,3$Q(1$`\.#0L*"`<%!`(!__[\
+M^_KX]_;U]//S\O+Q\?#P\/#P\/'Q\?'R\O/T]/7V]_CY^OO\_?[__P```0$!
+M`@("`P,#`P,#`P,#`P,#`P,$!`0%!04&!@8'!P@("`D)"@H*"@H*"@H*"PL+
+M"PL+"@H*"0D(!P8%!`,"`?_^_?OZ^??V]?3S\O'P\._O[^[N[N[O[^_P\?+S
+M]/7V]_CY^_S]_@`!`@0%!@<("@L,#`T.#@\/$!`0$!`/#PX-#0P+"@D)"`<&
+M!04$`P(!`0``_____O[^_OW]_?W]_/S\_/S\_/S\^_O[^_O[^_OZ^OKZ^OGY
+M^?GX^/CW]_?W]O;V]O;V]O?W]_CY^OO[_/W^_P$"`P0%!@<("0H+#`P-#@X/
+M#P\0$!`0$`\/#PX.#0P+"PH(!P8%!`(!__[\^_KX]_;U]/3S\O+R\?'Q\?'R
+M\O/S]/7U]O?X^/GZ^OO\_/W^_O__```!`0("`@,#`P,#!`0$!`0$`P,#`P0$
+M!`0$!`0$!`0$!04%!@8&!P<("`@)"0D)"0D)"0D("`@'!@8%!`0#`@(!`/_^
+M_?S[^OGX^/?V]?3T\_/R\O+Q\?'Q\O+R\_3U]O?X^?K\_?[_``(#!`4'"`D)
+M"@L+#`P,#0T-#0T-#0P,"PL*"@D("`<&!@4$`P(!`0#__O[]_?S\_/O[^_O[
+M^_O[^_O\_/S]_?W]_?W]_?[]_?W]_?W]_/S\_/S[^_O[^_KZ^OKZ^OKZ^OK[
+M^_O[_/S]_?[__P`!`@,$!08&!P@)"@H+#`P-#0T-#@X-#0T,#`L*"0D(!P8%
+M`P(!`/_^_?S[^?CW]_;U]?3T\_/S\O+R\O/S\_3U]?;W^/GZ^OO\_?[_``$"
+M`@,$!`4%!@8&!@8'!P<'!P8&!@4%!04$!`0$!`0#`P,#`P("`@("`@("`@("
+M`P,#`P,#`P0$!`0$!`0$`P,#`@(!`0#___[^_?S\^_KY^?CX]_?V]O7U]?7U
+M]?7U]O;W^/CY^OO\_?[_``$"`P0%!@<("0H*"PL,#`T-#0T-#0T,#`P+"@H)
+M"`<&!00#`P(!`/_^_?S[^OKY^?GX^/CX^/CX^/CX^/GY^?KZ^_O\_/S]_?W^
+M_O[___\```````#__________________O[^_O_______P````$!`@(#`P0$
+M!04&!@<'!P@("`@("`@("`@(!P<&!@4$`P,"`0#__O[]_/OZ^?CW]_;V]?7U
+M]/3T]/3T]?7V]O?X^?GZ^_S]_O\``0(#!`4&!@<'"`@)"0D)"0D)"0D)"0@(
+M"`<&!@4%!`0#`P(!`0``___^_O[^_?W]_?W]_?W]_?W^_O[^______\`````
+M``````````#_______[^_O[]_?W]_?W]_?W]_?W]_?[^_O__`````0("`P,$
+M!`4&!@<'!P@("0D)"0D)"0D("`@'!P8&!00#`@$`___^_?S\^_KZ^?CX]_?V
+M]O;V]O;V]O;V]_?W^/GY^OO[_/W^_O\``0$"`P,$!`4%!04%!@8&!04%!04%
+M!00$!`,#`P("`@$!`0$!`0````````````````````````````$!`0$!````
+M````_____O[^_?W]_/S[^_OZ^OKY^?GY^?GY^?KZ^OO[^_S\_?W^__\``0$"
+M`@,$!`4&!@<'"`@("0D)"0D)"`@("`<'!@8%!`0#`@$``/_^_OW\_/O[^OKZ
+M^?GY^?GY^?GY^OKZ^OO[_/S]_?[^__\```$!`@(#`P,$!`0$!`0$!`0$!`0$
+M`P,#`P("`@("`0$!`0$!`0$!`0$!`0$!`0("`@("`@("`@("`@("`@("`@$!
+M`0$!````___^_OW]_/S\^_O[^_KZ^OKZ^?GY^OKZ^OO[_/S]_?[^__\``0("
+M`P0$!04&!@8'!P<("`@("`@'!P<'!@8&!04$!`,"`@$``/_^_OW]_/S[^_OZ
+M^OKZ^OKZ^OKZ^OK[^_O[_/S\_?W^_O[___\``````0$!`0$!`0$"`@(!`0(!
+M`0$!`0$!`0$!`0$!`0$!`0$!`@("`@,#`P,#!`0$!`0$!`0$!`0$`P,#`P("
+M`0$!``#___[^_?S\^_OZ^OKY^?GY^?GX^/CX^/GY^?KZ^_O\_/W]_O__``$"
+M`@,$!`4%!@8'!P<("`@("`@("`<'!P8&!@4%!`0#`P("`0``_____O[]_?W\
+M_/S\_/O[^_O[^_O[^_S\_/S]_?W]_?[^_O[^________________________
+M__________\```````$!`0$"`@(#`P,$!`0%!04%!04%!04%!04%!00$`P,"
+M`@$!``#__O[]_?S[^_KZ^?GX^/CX]_?W]_?W^/CX^/GY^OK[^_S]_?[__P`!
+M`0(#`P0%!08&!P<'"`@("`@("`@("`<'!P<&!@4%!00$`P,"`@$!``#____^
+M_O[^_?W]_?W]_?W]_/S\_/S]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]
+M_?W^_O[^_O___P```0$"`@,#!`0%!04&!@<'"`@("`@)"0D("`@("`<'!@8&
+M!00$`P(!`0#___[]_?S[^_KZ^?GX^/CX]_?W]_CX^/CX^?GY^OK[^_S\_?[^
+M__\``0$"`@,#`P0$!04%!08&!@8&!@8&!@8%!04$!`0$`P,#`@("`@$!`0``
+M````_____________O[^_O[^_?W]_?W]_?S\_/S[^_O[^_O[^_KZ^OKZ^OKZ
+M^_O[^_S\_/W]_?[^_P```0$"`P,$!`4&!@<'!P@("`D)"0D)"0D)"`@(!P<&
+M!@4$!`,#`@$``/_^_?W\_/OZ^OGY^/CX]_?W]_?W]_?W^/CX^?GY^OK[^_S\
+M_?[^__\```$!`@(#`P,$!`0$!04%!04%!04%!04%!04%!00$!`0$!`0$!`,#
+M`P,#`P("`@("`@("`0$!`0``_____O[^_?W]_/S[^_OZ^OKY^?GY^?GX^/CX
+M^?GY^?KZ^OO[_/S]_?[^_P```0("`P0$!08&!P<("`@)"0D)"0D)"0D)"`@(
+M!P8&!04$`P,"`0$`__[^_?S\^_OZ^OGY^?CX^/CX^/CX^/CY^?GY^OK[^_O\
+M_/W]_O[__P```0$"`@(#`P,$!`0$!04%!04%!04%!04%!04%!04%!04%!00$
+M!`0$!`,#`P,"`@(!`0$!``#____^_O[]_?S\^_O[^OKZ^?GY^?GX^/CX^/CX
+M^/GY^?KZ^OO[_/S]_O[_```!`@(#!`0%!08'!P@("0D)"0H*"@H*"@D)"0D(
+M"`<'!@4%!`,#`@$!`/_^_OW\_/OZ^OKY^?CX^/CX]_?W^/CX^/CY^?GY^OKZ
+M^_O\_/W]_?[^__\````!`0("`@,#`P,$!`0$!`4%!04%!04%!04%!04%!04%
+M!04%!04$!`0$`P,"`@(!`0``___^_OW]_/S[^_KZ^?GY^/CX^/?W]_?W]_?W
+M]_?X^/CY^?KZ^_O\_?W^_P`!`0(#!`0%!@8'!P@("0D)"@H*"@H*"@H)"0D)
+M"`@'!@8%!`0#`@(!`/___OW]_/O[^OKY^?GX^/CX^/CX^/CX^/CX^/GY^?KZ
+M^OO[^_S\_/W]_O[___\```$!`@(#`P,$!`0%!08&!@8'!P<'!P@("`@("`@(
+M"`@'!P<'!@8&!04$!`,#`@(!``#___[]_?S[^_KZ^?GX^/?W]_;V]O;V]O;V
+M]O;V]_?X^/GY^OO[_/W]_O\``0$"`P0%!08'!P@)"0H*"@H+"PL+"@H*"@H)
+M"0@(!P<&!04$`P,"`0``__[^_?S\^_OZ^OGY^?CX^/CW]_?W]_?W]_?X^/CX
+M^?GY^OKZ^_O\_/S]_?[^__\```$!`@(#`P0$!04%!@8'!P<'"`@("`@("0D)
+M"`@("`@'!P<&!@4%!`0#`P(!``#__OW]_/O[^OGY^/?W]O;U]?7T]/3T]/3T
+M]/7U]?;V]_?X^?KZ^_S]_O\``0("`P0%!@<'"`D)"@H+"PP,#`P,#`P,"PL+
+M"@H)"`@'!@8%!`,#`@$``/_^_?W\^_OZ^?GX^/CW]_;V]O;V]O;V]O;V]O?W
+M]_?X^/GY^OK[^_S\_?W^_O\```$!`@,#!`0%!08&!P<("`D)"0D*"@H*"@H*
+M"@H*"@H)"0D("`<&!@4$`P,"`0#__OW]_/OZ^?GX]_;V]?3T\_/S\_+R\O+S
+M\_/S]/3U]?;W^/CY^OO\_?[_``$"`P0%!@<'"`D*"@L,#`P-#0T-#0T-#0T,
+M#`L+"@H)"`<'!@4$!`,"`0#__O[]_/O[^OGY^/CW]_;V]O7U]?7U]?7U]?7U
+M]?;V]O?W^/CY^?KZ^_S\_?[^_P`!`0(#!`0%!@<'"`D)"@H+"PP,#`P-#0T-
+M#0T-#`P,"PL*"0D(!P8%!`0#`@$`__[]_/OZ^?CW]O7U]//S\O+R\?'Q\?'Q
+M\?'R\O/S]/7U]O?X^?K[_/W^_P`!`@,$!08'"`D*"PL,#0T.#@X.#@X.#@X.
+M#0T-#`L+"@D("`<&!00#`@$`__[]_/OZ^OGX]_?V]?7T]/3S\_+R\O+R\O+R
+M\O/S\_3T]/7V]O?X^/GZ^_S]_?[_``$"`P0%!@<("0H*"PP,#0T.#@X/#P\/
+M#P\/#@X-#0P,"PH)"`<&!00#`@'__OW\^_GX]_;U]//R\?'P\._O[N[N[N[N
+M[N_O[_#Q\O+S]/7V]_CY^_S]_@`!`@0%!@<)"@L,#0T.#Q`0$1$2$A(2$A$1
+M$1`0#P\.#0P+"@D(!P8%!`,!`/_^_?S[^OGX]_;U]//S\O'Q\/#P\._O[^_O
+M\/#P\?'R\O/T]/7V]_CY^OO\_?\``0(#!08'"`D*"PP-#@\0$1$2$A(3$Q,3
+M$Q,2$A$1$`\/#@T+"@D(!P4$`@'__OW[^OCW]O7S\O'P[^[N[>SLZ^OKZ^OK
+MZ^SL[>WN[_#Q\O/T]??X^?O\_?\``@,%!@@)"@P-#@\0$1(2$Q04%!05%144
+M%!03$A(1$`\.#0P+"@@'!@0#`@#__?S[^?CW]O7S\O'P[^_N[>WL[.OKZ^OK
+MZ^OK[.SM[>[O[_#Q\O3U]O?Y^OS]_P`"`P4&"`D*#`T/$!$2$Q05%186%Q<7
+M%Q<7%A85%103$A$/#@T+"@@&!0,!`/[\^OGW]O3S\?#O[NWLZ^KIZ.CHY^?G
+MY^CHZ>GJZ^OM[N_P\?/T]O?Y^_S^``$#!`8("0L,#0\0$1(3%!46%A<7%Q<8
+M%Q<7%A85%103$A$/#@T+"@D'!00"`?_]_/KY]_;U\_+Q\.[M[>SKZNKIZ>CH
+MZ.CHZ.CIZ>KJZ^SM[N_P\O/T]O?Y^_S^``$#!0<("@P-#Q`2$Q06%Q@8&1H:
+M&AL;&QH:&AD8%Q85%!,1#PX,"@@'!0,!__W[^??V]/+Q[^[LZ^KIZ.?FYN7E
+MY>3DY>7EYN;GZ.GJZ^WN[_'S]/;X^?O]_P`"!`8'"0L,#A`1$A05%A<8&1D:
+M&QL;&QL;&AH9&!@7%A03$A`/#0L*"`8$`P'__?OY^/;T\_'P[^WLZ^KIZ.?F
+MYN7EY>7EY>7EYN?GZ.GJZ^SN[_'R]/;W^?O]_P$#!08("@P.$!$3%187&1H;
+M'!P='1T>'1T='!P;&AD8%A43$A`.#`H(!@0"`/[[^?CV]/+P[^WLZNGHY^;E
+MY>3DY./CX^3DY>7FY^CIZNOL[N_Q\O3V]_G[_?\``@0&"`D+#0X0$A,4%A<8
+M&1D:&QL;&QL;&QL:&AD8%Q84$Q(0#@T+"0<%`P'__?OZ^/;T\_'O[NSKZNGH
+MY^;EY.3DX^/CX^/DY.7FYN?IZNOL[O#Q\_7V^/K\_@`"!`8("@P.$!(3%1<8
+M&1H;'!T='AX>'AT='!P;&AD8%A43$1`.#`H(!@0!__W[^??U]/+P[^WLZ^GH
+MY^?FY>7DY.3DY.3EY>;FY^CIZNOM[N_Q\_3V]_G[_?X``@0%!PD+#0X0$1,4
+M%A<8&1H;&QP<'!P<'!P;&QH9&!<6%!,1$`X,"@D'!0,!__W[^??U\_+P[^WL
+MZ^GHY^?FY>7DY.3DY.3EY>;FY^CIZNSM[_#R\_7W^?O]_@`"!`8("@P.$!$3
+M%!87&1H;&QP='1T='1T<'!L:&1@7%A03$0\-"PH(!@0"`/[\^OCV]/+Q[^[M
+MZ^KIZ.?GYN;EY>7EY>7FYN?GZ.GJZ^SM[_#R\_7V^/G[_?\``@0%!PD*#`X/
+M$1(3%187&!D9&AH:&QL;&AH9&1@7%A44$A$0#@P+"0<%`P'__?OY^/;T\_'O
+M[NWKZNGHZ.?FYN7EY>7EYN;FY^CIZ>KL[>[P\?+T]O?Y^_S^``(#!0<)"@P.
+M#Q$2%!46%Q@9&AH;&QL;&QH:&1D8%Q84$Q(0#@T+"0<%!`(`_OSZ^/?U\_+Q
+M[^[M[.OJZ>GHZ.?GY^?GY^?HZ.GJZ^SM[N_P\?/T]??X^OO]_@`"`P4&"`H+
+M#0X0$1(4%186%Q@8&1D9&1D9&!@7%A44$Q(1#PX,"PD'!00"`/[\^_GW]O3S
+M\?#O[>SKZNKIZ.CGY^?GY^?GZ.CIZNOL[>[O\/+S]?;X^?O]_@`"`P4'"`H,
+M#0X0$1(4%186%Q@8&!D9&1@8%Q<6%103$A$0#@T,"@@'!0,"`/[]^_KX]_7T
+M\_'P[^[M[>SKZ^KJZNKJZNKJZNOK[.WN[_#Q\O/T]??X^?O\_O\``@,%!@@)
+M"PP.#Q`1$A,4%187%Q<8&!@8%Q<6%A44$Q(1$`\-#`H(!P4#`0#^_/OY]_;T
+M\_+P[^[M[.SKZNKIZ>GIZ>GIZNKKZ^SM[N_P\?+T]?;X^?O\_O\!`P0&!PD*
+M"PT.#Q$2$Q04%186%Q<7%Q<6%A85%!03$A$/#@T+"@@'!00"`/_]^_KY]_;T
+M\_+Q\._N[>WL[.OKZ^KJZNOKZ^OL[.WN[_#Q\O/T]?;W^?K[_?[_`0($!08(
+M"0H,#0X/$!$2$Q04%146%A86%A45%!03$A$0#PX-"PH)!P8$`@'__?SZ^/?V
+M]//R\._N[>WLZ^OJZNKJZ>KJZNKK[.SM[N_P\?+S]?;W^?K[_?X``0,$!@<(
+M"@L,#@\0$1(3$Q05%146%A86%144%!,2$A$0#PT,"PD(!P4#`@#__?SZ^?CV
+M]?3S\O'P[^_N[>WM[.SL[.SL[.WM[N[O\/#Q\O/T]?;X^?K[_/[_``(#!`8'
+M"`H+#`T.#Q`1$A(3$Q04%145%104%!,3$A$0#PX-#`L)"`8%`P(!__[\^_GX
+M]_7T\_+Q\._N[NWM[.SL[.SL[.SM[>[N[_#P\?+S]?;W^/G[_/W^``$"!`4&
+M"`D*"PP-#@\0$1(3$Q,4%!04%!04$Q,2$1$0#PX-#`H)"`8%!`(!__[]^_KX
+M]_;U]//R\?#O[^[N[>WM[>WM[>WM[N[O[_#Q\?+S]/7V]_GZ^_S]_P`!`P0%
+M!@@)"@L,#0X/$!$1$A(3$Q,4%!,3$Q,2$A$0#PX-#`L*"0@&!0,"`?_^_/OZ
+M^/?V]?3S\O'P[^_N[NWM[>WL[>WM[>[N[^_P\?+S]/7V]_CY^OS]_O\!`@,$
+M!@<("0H+#`T.#P\0$1$2$A(2$Q,2$A(2$1$0#P\.#0P+"@D'!@4#`@'__OW[
+M^OGX]O7T\_+Q\?#O[^[N[>WM[>WM[>WN[N_O\/'Q\O/T]?;W^/K[_/W^``$"
+M`P4&!P@)"@P-#@\/$!$1$A(3$Q,3$Q,3$Q(2$1`0#PX-#`H)"`8%!`(!`/[]
+M^_KY]_;U]//R\?#P[^_N[NWM[>WM[>WN[N_O\/#Q\O/T]?;W^/GZ^_W^_P`!
+M`@0%!@<("0H+#`T.#P\0$1$1$A(2$A(2$A(1$1`0#PX-#`L*"0@'!@4#`@'_
+M_OW\^_GX]_;U]//S\O'Q\/#O[^_O[N[O[^_O\/#Q\?+S\_3U]O?X^?K[_/W_
+M``$"`P0&!P@)"@L,#0X/#Q`1$1(2$A(2$A(2$A$1$`\/#@T,"PH)"`8%!`(!
+M`/[]_/OY^/?V]?3S\O'Q\/#O[^[N[N[N[N[O[_#P\?'R\_3T]?;W^/GZ^_S^
+M_P`!`@,$!08'"`D*"PP-#@X/#Q`0$1$1$1$1$1$0$`\/#@T,#`L*"0<&!00#
+M`0#__OW[^OGX]_;U]//R\O'Q\/#O[^_O[^_O[^_P\/'Q\O+S]/3U]O?X^?K[
+M_/W^_P$"`P0%!@<("0H+#`T.#@\0$!$1$1$1$1$1$!`0#PX.#0P+"@D(!P8$
+M`P(!`/[]_/OZ^?CW]O7T\_+R\?'P\/#O[^_O[_#P\/#Q\?+S\_3U]O;W^/GZ
+M^_S]_O\``0($!08'"`D*"@L,#0T.#P\0$!`0$1$1$!`0$`\/#@T-#`L*"0@'
+M!@4$`P$`__[]^_KY^/?V]?3T\_+Q\?#P\/#O[^_O\/#P\/'Q\O/S]/7V]_?X
+M^?K[_?[_``$"`P0%!@<("0H+#`T.#@\/$!`0$1$1$1$0$!`/#PX-#0P+"@D(
+M!P8%`P(!`/_]_/OZ^?CW]O7T]//R\O'Q\?#P\/#P\/#Q\?'R\O/S]/7U]O?X
+M^?K[_/W^_P`!`@,$!08&!P@)"@L,#`T-#@X/#P\/#P\/#P\/#@X.#0P,"PH)
+M"`<&!00#`@$`__[]^_KY^/?W]O7T\_/R\O'Q\?#P\/#P\/'Q\?+R\_/T]?7V
+M]_CY^OO[_?[_``$"`P0%!@<("0D*"PP-#0X.#P\/#Q`0$`\/#P\.#@T,#`L*
+M"0@'!@4$`P(!`/[]_/OZ^?CW]O7U]//S\O+Q\?'Q\?#P\?'Q\?+R\O/T]/7V
+M]O?X^?K[_/W^_P`!`@,$!`4&!P@)"@L+#`P-#0X.#@\/#P\/#PX.#@T-#`P+
+M"@D(!P8%!`,"`0#__OW\^_KY^/?V]?3T\_+R\O'Q\?'P\/'Q\?'Q\O+S]/3U
+M]O;W^/GZ^_S]_O\``0(#!`4&!P<("0H+"PP-#0X.#@\/#P\/#P\.#@X-#0P,
+M"PH)"`@'!@4$`@$`__[]_/OZ^?CW]O;U]/3S\_+R\O'Q\?'Q\?+R\O/S]/3U
+M]?;W]_CY^OO\_?[^_P`!`@,$!08'"`D*"@L,#`T.#@X/#P\/#P\/#P\.#@T-
+M#`L+"@D(!P8%!`,"`0#^_?S[^OGX]_?V]?3T\_+R\O'Q\?'Q\?'Q\O+R\_/T
+M]?7V]_CX^?K[_/W^_P`!`@,$!`4&!P@)"@H+#`P-#0X.#@X/#P\.#@X.#0T,
+M#`L*"@D(!P8%!`,"`0#__OW\^_KY^/?V]O7T]//S\O+R\O+Q\?'R\O+R\_/T
+M]/7U]O?W^/GZ^_S\_?[_``$"`P0%!@<'"`D*"@L,#`T-#0X.#@X.#@X-#0T,
+M#`L+"@D("`<&!00#`@$`__[]_/OZ^?CW]_;U]?3S\_/R\O+R\O+R\O+S\_/T
+M]/7U]O?W^/GZ^_S\_?[_``$"`P0$!08'"`@)"@H+"PP,#`T-#0T-#0T-#`P,
+M"PL*"@D(!P<&!00#`@$`__[^_?S[^OGX^/?V]O7U]/3T\_/S\_/S\_/T]/3U
+M]?;V]_?X^?GZ^_S\_?[_``$!`@,$!04&!P@("0H*"PL,#`P,#`T-#0T,#`P,
+M"PL*"@D("`<&!00#`P(!`/_^_?S[^OKY^/?W]O;U]?3T]/3T\_3T]/3T]/7U
+M]O;W]_CY^?K[^_S]_O__``$"`@,$!04&!P<("0D*"@H+"PL+"PP,#`L+"PL*
+M"@H)"0@'!P8%!00#`@(!`/_^_?W\^_KZ^?CX]_?V]O7U]?7U]/3U]?7U]?7V
+M]O?W^/CY^?K[^_S]_?[_```!`@,#!`4&!@<'"`@)"0H*"@L+"PL+"PL+"@H*
+M"0D)"`@'!@8%!`0#`@$!`/_^_?W\^_OZ^?GX^/?W]O;V]?7U]?7U]?7U]O;V
+M]_?X^/GY^OK[_/S]_O[_```!`@,#!`4%!@8'!P@("`D)"0D)"@H*"0D)"0D)
+M"`@'!P8&!04$!`,"`@$``/_^_OW\_/OZ^OGY^/CW]_?V]O;V]O;V]O;V]O?W
+M]_CX^/GY^OK[_/S]_?[__P`!`0(#`P0$!04&!@<'"`@("0D)"0D)"0D)"0D)
+M"`@(!P<&!@4%!`,#`@$!`/___OW\_/O[^OKY^?CX]_?W]_;V]O;V]O?W]_?X
+M^/CY^?KZ^_O\_/W]_O__``$!`@(#!`0%!08&!P<'"`@("`D)"0D)"0@("`@(
+M!P<'!@8%!00$`P,"`@$``/___O[]_/S[^_OZ^OGY^?CX^/CX^/CX^/CX^/CY
+M^?GZ^OO[^_S\_?W^_O\```$!`@(#`P0$!04&!@8'!P<'"`@("`@("`@(!P<'
+M!P8&!@4%!`0#`P("`0$``/___OW]_/S[^_OZ^OGY^?GX^/CX^/CX^/CX^?GY
+M^?KZ^OO[_/S]_?[^__\```$"`@,#!`0%!04&!@8'!P<'!P<("`<'!P<'!P8&
+M!@4%!00$`P,"`@$!``#___[]_?S\^_O[^OKZ^?GY^/CX^/CX^/CX^/CY^?GY
+M^OKZ^_O\_/W]_O[__P```0$"`@,#!`0%!08&!@<'!P<'!P<'!P<'!P<'!@8&
+M!04%!`0#`P("`0$``/_^_OW]_/S[^_OZ^OGY^?GX^/CX^/CX^/CX^/GY^?GZ
+M^OO[^_S\_?W^_O__```!`0("`P,$!`4%!@8&!P<'!P<("`@("`@'!P<'!P8&
+M!@4%!`0#`P("`0$``/_^_OW]_/S[^_OZ^OGY^?GX^/CX^/CX^/CX^/CY^?GZ
+M^OK[^_S\_?W^_O__```!`0(#`P0$!04%!@8'!P<'"`@("`@("`@("`@'!P<&
+M!@8%!00$`P,"`@$!``#__O[]_?S\^_O[^OKY^?GX^/CX^/CX^/CX^/CY^?GZ
+M^OK[^_S\_?W^_O__```!`0("`P,$!`0%!08&!@<'!P<'!P<(!P<'!P<'!P8&
+M!@8%!00$!`,#`@(!`0``___^_OW]_/S[^_OZ^OKY^?GY^/CX^/CX^/CY^?GY
+M^?KZ^_O[_/S]_?[^__\```$!`@(#`P0$!04%!@8&!P<'!P<("`@("`<'!P<'
+M!@8&!04$!`0#`P(!`0``___^_?W\_/O[^_KZ^?GY^/CX^/CX^/CX^/CX^/GY
+M^?KZ^OO[_/S]_?[^__\```$!`@(#`P0$!04%!@8&!@<'!P<'!P<'!P<'!P8&
+M!@8%!00$!`,#`@(!`0``___^_OW]_/S[^_OZ^OKY^?GY^/CX^/CX^/CX^?GY
+M^?KZ^OO[_/S\_?W^_O__```!`0("`P,$!`4%!08&!@8'!P<'!P<'!P<'!P8&
+M!@8%!00$!`,#`@(!`0``___^_OW]_/S\^_OZ^OKZ^?GY^?GY^?GY^?GY^?GZ
+M^OK[^_O\_/W]_?[^__\```$!`@(#`P0$!04%!@8&!P<'!P<'!P<'!P<'!P<&
+M!@8%!04$!`,#`@(!`0``___^_OW]_/S\^_OZ^OKZ^?GY^?GY^?GY^?GY^?GZ
+M^OK[^_O\_/S]_?[^__\```$!`@(#`P0$!04%!@8&!P<'!P<'"`@'!P<'!P<&
+M!@8&!04$!`,#`@(!`0``___^_OW]_/S[^_OZ^OKY^?GY^?GX^/CX^?GY^?GZ
+M^OKZ^_O[_/S]_?[^__\```$!`@(#`P0$!`4%!@8&!@<'!P<'!P<'!P<'!@8&
+M!@4%!00$`P,#`@(!`0#___[^_?W]_/S[^_KZ^OGY^?GY^/CX^/CX^/CY^?GY
+M^?KZ^OO[_/S\_?W^_O__```!`0("`P,$!`4%!08&!@<'!P<'!P<'!P<'!P8&
+M!@8%!04$!`,#`@(!`0``___^_?W]_/S[^_KZ^OGY^?GY^?CX^/CX^/GY^?GY
+M^OKZ^_O\_/S]_?[^__\```$!`@(#`P,$!`4%!08&!@8'!P<'!P<'!P<'!@8&
+M!@4%!00$!`,#`@(!`0``___^_OW]_?S\^_O[^OKZ^?GY^?GY^?GY^?GY^?KZ
+M^OK[^_O\_/S]_?[^__\```$!`@(#`P0$!`4%!08&!@<'!P<'!P<'!P<'!P8&
+M!@8%!00$!`,#`@(!`0``___^_OW]_?S\^_O[^OKZ^OKY^?GY^?GY^?GY^OKZ
+M^OO[^_O\_/W]_?[^__\```$!`@(#`P,$!`4%!08&!@8&!P<'!P<'!P<&!@8&
+M!04%!00$`P,"`@$!`0``___^_OW]_?S\^_O[^_KZ^OKZ^?GY^?GY^?GZ^OKZ
+M^OO[^_S\_/W]_?[^__\```$!`0("`P,$!`0%!04&!@8&!@8'!P<&!@8&!@8&
+M!04%!`0$`P,"`@$!``#___[^_?W]_/S[^_OZ^OKZ^?GY^?GY^?GY^?GY^?KZ
+M^OK[^_O\_/S]_?[^____```!`0("`P,#!`0$!04%!@8&!@8&!@8&!@8&!@8&
+M!04%!`0$`P,#`@(!`0``___^_OW]_?S\^_O[^OKZ^OGY^?GY^?GY^?GY^?GY
+M^OKZ^_O[_/S\_?W^_O__```!`0("`@,#!`0$!04%!@8&!@8&!@<'!P8&!@8&
+M!@8%!04$!`0#`P("`0$```#___[^_?W\_/S[^_OZ^OKZ^OKY^?GY^?GY^OKZ
+M^OK[^_O[_/S]_?W^_O__`````0$"`@,#`P0$!04%!08&!@8&!@8&!@8&!@8&
+M!@4%!04$!`0#`P("`0$!``#___[^_OW]_/S\^_O[^_KZ^OKZ^OKZ^OKZ^OKZ
+M^OO[^_O\_/S]_?W^_O__`````0$"`@,#`P0$!`4%!04&!@8&!@8&!@8&!@8&
+M!04%!00$!`,#`P("`0$!``#___[^_OW]_?S\_/O[^_KZ^OKZ^OKZ^OKZ^OKZ
+M^OK[^_O[_/S\_?W]_O[__P````$!`@("`P,$!`0$!04%!04&!@8&!@8&!04%
+M!04%!`0$`P,#`@(!`0$``/____[^_?W]_/S\^_O[^_KZ^OKZ^OKZ^OKZ^OKZ
+M^OK[^_O\_/S]_?W^_O[__P```0$!`@("`P,$!`0$!04%!04%!08&!@4%!04%
+M!04$!`0$`P,#`@(!`0$``/____[^_OW]_?S\_/O[^_O[^OKZ^OKZ^OKZ^OKZ
+M^_O[^_O\_/S]_?W^_O[__P````$!`0("`P,#!`0$!`4%!04%!04%!04%!04%
+M!04$!`0$`P,#`@("`0$```#____^_O[]_?W\_/S\^_O[^_O[^OKZ^OKZ^_O[
+M^_O[_/S\_/W]_?[^_O___P```0$!`@(#`P,$!`0$!04%!04%!04&!@8%!04%
+M!04%!`0$!`,#`P("`@$!````___^_O[]_?W\_/S\^_O[^_OZ^OKZ^OKZ^OO[
+M^_O[^_S\_/S]_?W^_O[___\```$!`0("`@,#`P0$!`0%!04%!04%!04%!04%
+M!04%!`0$!`,#`P("`@$!`0``_____O[]_?W]_/S\^_O[^_O[^OKZ^OKZ^OO[
+M^_O[^_O\_/S]_?W]_O[^__\````!`0$"`@(#`P,#!`0$!`0%!04%!04%!04%
+M!00$!`0$`P,#`P("`@$!`0``_____O[^_?W]_/S\_/O[^_O[^OKZ^OKZ^OKZ
+M^OK[^_O[^_S\_/W]_?[^_O___P```0$!`@(#`P,#!`0$!`4%!04%!04%!04%
+M!04%!`0$!`,#`P("`@$!`0``_____O[^_?W]_/S\^_O[^_O[^OKZ^OKZ^OKZ
+M^_O[^_O\_/S\_/W]_?[^____`````0$"`@(#`P,#!`0$!`4%!04%!04%!04%
+M!04%!04$!`0$`P,#`@("`0$```#____^_OW]_?W\_/S\^_O[^_O[^_KZ^OK[
+M^_O[^_O[_/S\_/W]_?[^_O___P```0$!`@("`P,#!`0$!`4%!04%!04%!04%
+M!04%!04$!`0$`P,#`@("`0$!````_____O[]_?W]_/S\_/O[^_O[^_O[^_O[
+M^_O[^_O\_/S\_/W]_?[^_O[___\````!`0("`@(#`P,$!`0$!`0%!04%!04%
+M!04%!04$!`0$`P,#`P("`@$!````_____O[^_?W]_/S\^_O[^_O[^OKZ^OKZ
+M^OKZ^_O[^_O\_/S\_?W]_O[^__\````!`0$"`@(#`P,$!`0$!04%!04%!04%
+M!04%!04$!`0$`P,#`P("`@$!````_____O[]_?W\_/S\^_O[^_KZ^OKZ^OKZ
+M^OKZ^OO[^_O[_/S\_?W]_O[^____`````0$!`@("`P,#`P0$!`0%!04%!04%
+M!04%!04%!`0$!`0#`P,"`@(!`0$``/____[^_OW]_?S\_/S[^_O[^_O[^OKZ
+M^OKZ^_O[^_O[_/S\_/W]_?[^_O___P````$!`@("`P,#`P0$!`0$!04%!04%
+M!04%!04%!00$!`0$`P,#`@("`0$!````___^_O[]_?W]_/S\_/O[^_O[^_O[
+M^_O[^_O[^_O\_/S\_?W]_?[^_O___P````$!`0("`@,#`P0$!`0$!04%!04%
+M!04%!04%!00$!`0$`P,#`@("`0$!````_____O[^_?W]_/S\_/S[^_O[^_O[
+M^_O[^_O[^_O\_/S\_/W]_?[^_O[__P````$!`0("`@(#`P,$!`0$!`4%!04%
+M!04%!04$!`0$!`0#`P,#`@("`0$!````_____O[^_?W]_?S\_/S[^_O[^_O[
+M^_O[^_O[^_O[_/S\_/S]_?W]_O[^____`````0$!`@("`@,#`P,$!`0$!`0$
+M!`4%!`0$!`0$!`0$`P,#`P("`@$!`0``_____O[^_?W]_/S\_/O[^_O[^_OZ
+M^OKZ^_O[^_O[^_O\_/S\_?W]_O[^____`````0$!`@("`@,#`P,$!`0$!`4%
+M!04%!04%!00$!`0$!`,#`P,"`@(!`0$```#___[^_OW]_?W\_/S\^_O[^_O[
+M^_O[^_O[^_O[^_O\_/S\_?W]_?[^_O___P````$!`0("`@,#`P,$!`0$!`4%
+M!04%!04%!04%!`0$!`0$`P,#`P("`@$!`0``_____O[^_?W]_?S\_/S\^_O[
+M^_O[^_O[^_O[^_S\_/S\_?W]_?[^_O___P````$!`0("`@,#`P,$!`0$!`0%
+M!04%!04%!04%!`0$!`0#`P,#`@("`0$!````_____O[^_?W]_?S\_/S[^_O[
+M^_O[^_O[^_O[^_S\_/S\_/W]_?W^_O[___\````!`0$"`@(#`P,#!`0$!`0$
+M!04%!04%!04%!00$!`0$!`,#`P("`@$!`0```/___O[^_?W]_/S\_/O[^_O[
+M^_OZ^OKZ^_O[^_O[^_O\_/S\_/W]_?[^_O____\````!`0$"`@(#`P,#!`0$
+M!`0$!04%!04%!04%!`0$!`0$`P,#`@("`0$!````___^_O[]_?W\_/S\^_O[
+M^_O[^OKZ^OKZ^OK[^_O[^_O\_/S\_?W]_O[^____`````0$!`@("`P,#`P0$
+M!`0$!04%!04%!04%!04%!`0$!`0#`P,"`@(!`0$``/____[^_OW]_?S\_/S[
+M^_O[^_O[^_O[^_O[^_O[^_O\_/S\_?W]_?[^_O___P````$!`0("`@,#`P0$
+M!`0$!04%!04%!04%!04%!04%!`0$!`,#`P("`@$!`0``_____O[^_?W]_/S\
+M^_O[^_O[^_KZ^OKZ^OO[^_O[^_S\_/S]_?W^_O[___\````!`0$"`@(#`P,$
+M!`0$!04%!04%!04%!04%!04%!04%!`0$!`,#`P("`0$!``#____^_OW]_?S\
+M_/S[^_O[^_KZ^OKZ^OKZ^OK[^_O[^_S\_/W]_?W^_O[___\```$!`0("`@,#
+M`P,$!`0$!`4%!04%!04%!04%!04$!`0$!`,#`P("`@$!````___^_O[]_?W\
+M_/S[^_O[^_OZ^OKZ^OKZ^OKZ^_O[^_O\_/S\_?W]_?[^_O___P```0$!`@("
+M`@,#`P0$!`0$!04%!04%!04%!04%!`0$!`0#`P,"`@(!`0$``/____[^_OW]
+M_?S\_/O[^_O[^OKZ^OKZ^OKZ^OO[^_O[^_S\_/S]_?W^_O[___\````!`0$"
+M`@(#`P,#!`0$!`4%!04%!04%!04%!04%!`0$!`0#`P,"`@(!`0$``/____[^
+M_OW]_?S\_/S[^_O[^_O[^_O[^_O[^_O[^_O\_/S\_?W]_?[^_O__`````0$!
+M`@("`P,#`P0$!`0%!04%!04%!04%!04%!04%!`0$!`,#`P("`@$!`0``____
+M_O[^_?W]_/S\_/O[^_O[^_O[^_O[^_O[^_O[_/S\_/S]_?W^_O[___\````!
+M`0$"`@(#`P,#!`0$!`0%!04%!04%!04%!04%!00$!`0#`P,#`@("`0$```#_
+M___^_O[]_?W\_/S\^_O[^_O[^_O[^_O[^_O[^_O[_/S\_/W]_?W^_O[___\`
+M```!`0$"`@("`P,#`P0$!`0$!04%!04%!04%!`0$!`0$`P,#`P("`@$!`0``
+M_____O[^_?W]_/S\_/O[^_O[^_O[^OKZ^OO[^_O[^_O\_/S\_?W]_?[^_O__
+M_P````$!`0("`@(#`P,#!`0$!`0$!04%!04%!00$!`0$!`,#`P,"`@(!`0$`
+M``#____^_O[]_?W\_/S\^_O[^_O[^_O[^_O[^_O[^_O[_/S\_/S]_?W^_O[_
+M____`````0$!`@("`P,#`P0$!`0$!`4%!04%!04%!00$!`0$!`,#`P,"`@(!
+M`0$```#____^_O[]_?W]_/S\_/S[^_O[^_O[^_O[^_O[_/S\_/S]_?W]_O[^
+M_O___P````$!`0$"`@(#`P,#`P0$!`0$!`4%!04%!04$!`0$!`0$`P,#`P("
+M`@$!`0```/____[^_O[]_?W]_/S\_/S\_/O[^_O[^_O\_/S\_/S\_/W]_?W^
+M_O[^____``````$!`0("`@(#`P,#`P0$!`0$!`0$!`0$!`0$!`0$!`0#`P,#
+M`@("`0$!````_____O[^_?W]_?S\_/S\_/O[^_O[^_O[^_O[^_S\_/S\_/W]
+M_?W^_O[^____``````$!`0$"`@("`P,#`P,$!`0$!`0$!`0$!`0$!`0#`P,#
+M`P("`@$!`0$```#____^_O[^_?W]_?S\_/S\_/O[^_O[^_O[^_O[_/S\_/S\
+M_?W]_?W^_O[^____``````$!`0$"`@("`P,#`P,$!`0$!`0$!`0$!`0$!`,#
+M`P,#`@("`@$!`0$```#____^_O[^_?W]_?S\_/S\_/S\_/S\_/S\_/S\_/S\
+M_/W]_?W]_O[^_O____\````!`0$!`@("`@(#`P,#`P,#!`0$!`0$!`0$`P,#
+M`P,#`P("`@("`0$!`0```/_____^_O[^_OW]_?W]_?W]_/S\_/S\_/S\_/W]
+M_?W]_?W]_O[^_O[_____``````$!`0$"`@("`@,#`P,#`P,$!`0$!`0$!`0$
+M`P,#`P,#`P("`@(!`0$`````______[^_O[]_?W]_?W\_/S\_/S\_/S\_/S\
+M_/W]_?W]_?[^_O[^_____P`````!`0$!`0("`@("`P,#`P,#`P,#`P,#`P,#
+M`P,#`P,"`@("`@$!`0$!`````/_____^_O[^_OW]_?W]_?W]_?W]_?S\_?W]
+M_?W]_?W]_?W]_O[^_O[^_____P```````0$!`0$"`@("`@("`P,#`P,#`P,#
+M`P,#`P,"`@("`@(!`0$!`0````#______O[^_O[]_?W]_?W]_?S\_/S\_/S\
+M_/S]_?W]_?W]_?[^_O[^_O______```````!`0$!`0("`@("`@(#`P,#`P,#
+M`P,#`P,#`P("`@("`@(!`0$!`0````#_______[^_O[^_OW]_?W]_?W]_?W]
+M_?W]_?W]_?W]_?W]_O[^_O[^______\```````$!`0$!`@("`@("`@,#`P,#
+M`P,#`P,#`P,#`P,"`@("`@(!`0$!`0``````_______^_O[^_O[^_?W]_?W]
+M_?W]_?W]_?W]_?W^_O[^_O[^________`````````0$!`0$!`@("`@("`@(#
+M`P,#`P,#`P,#`P,#`@("`@("`@(!`0$!`0``````_______^_O[^_O[^_?W]
+M_?W]_?W]_?W]_?W]_?W]_?[^_O[^_O[_______\``````0$!`0$!`@("`@("
+M`@(#`P,#`P,#`P,#`@("`@("`@(!`0$!`0``````_______^_O[^_O[]_?W]
+M_?W]_?W]_?W]_?W]_?W]_?W^_O[^_O[^_O_______P```````0$!`0$!`0("
+M`@("`@("`@("`@("`@("`@("`@("`0$!`0$!``````#________^_O[^_O[^
+M_?W]_?W]_?W]_?W]_?W]_?W]_?W]_O[^_O[^_O_______P```````0$!`0$!
+M`@("`@("`@("`@("`@("`@("`@("`@("`0$!`0$!````````_________O[^
+M_O[^_O[^_O[^_?W]_?W]_?W]_?[^_O[^_O[^_O[_________`````````0$!
+M`0$!`@("`@("`@("`@("`@("`@("`@("`@("`@$!`0$!`0````````#_____
+M_____O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^__________\`````````
+M`0$!`0$!`0$"`@("`@("`@("`@("`@("`@("`@$!`0$!`0$!`````````/__
+M_________O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^____________````
+M``````$!`0$!`0$!`@("`@("`@("`@("`@("`0$!`0$!`0$!``````````#_
+M__________[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O________\`
+M``````````$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$`````````
+M``#______________O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O__________
+M_P```````````0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$`````
+M````````_________________O[^_O[^_O[^_O[^_O[^_O______________
+M_P`````````````!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M``````````````#____________________^_O[^_O[^________________
+M____``````````````$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0``
+M``````````#______________________O[^_O[^_O[^_O[^_O[_________
+M________```````````````!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0``
+M`````````````/________________[^_O[^_O[^_O[^_O[^_O[^_O[^_O__
+M_____________P```````````````0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$`````````````````______________________[^_O[^_O[^_O[^_O__
+M_________________P````````````````$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$`````````````````________________________________
+M_________________P````````````````$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!``````````````````#_________________________
+M________________________``````````````````````$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$``````````````````````/______________________
+M_____________________________P``````````````````````````````
+M``````````````````````````````````#_________________________
+M______________________________\`````````````````````````````
+M`````````````````````````````````````````/__________________
+M____________________________````````````````````````````````
+M`````0$!`0$!`0$!`0`!``````````````````````````````````#_____
+M____________________________````````````````````````````````
+M````````````````````````````````````````````````````````````
+M______________________________\`````````````````````````````
+M`````````````````````````````````````````````````````````/__
+M__________________________________________\`````````````````
+M````````````````````````````````0T]-30```!(``0``1H``"$`-K$0`
+M``````!-05)+`````@``24Y35````!0\``!_`'\``````````````````$%0
+M4$P```&H4V0R80`"``````````````%`````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````"P````````````````
+M``````````````````````````````````````````````````````!QV?P`
+M````````<````````````````````&```)VX````<=KD`'':4`!QVDC__P!Q
+MVA"J5:I5!`@```````D`(P````````````````!X````!``$``````!6_@#_
+M__^``````0$@!E%5;FET<P``$P@N<&=S>@``"1Y0050C```)*DQ74E<`````
+M``$"1@8@<V%M<',````)6DE#3B,``0EF:6-S(P`!"7YI8VPX``$``$:`````
+M@`FN```````````````=`"\`#__V__D``0``````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````!`````7X```!^````:B)E870N8RYO(+8-("`@("`@("`B>T]B
+M:D1I<GTB96YD#$QE871H97(@1')U;94"````04E&1E-D,F$!`/____\``$%)
+M1D939#)A`0#_____````````````````````````ISV:`@``2(P```'H>T]B
+M:D1I<GTB97AP;&]D92YC+F\@M@T@("`@("`@(")[3V)J1&ER?2)E>'1R86QE
+M=BYC+F\@M@T@("`@("`@(")[3V)J1&ER?2)F:6QE<RYC+F\@M@T@("`@("`@
+M(")[3V)J1&ER?2)F;W5N=&%I;BYC+F\@M@T@("`@("`@(")[3P````+__@``
+M`!H`*0`/`:,"Y@`J``,";0,]`"D`#P%Z`M<!`````!H`*0`/`5`!\0`J``,"
+M;0,]3EY.=``*3E8``````!H`+``6`3X!W``J``,";0,]`ST"</S%`G``````
+M`!H```````````````````````@A;@`,`!@``````0````%^````?@```&H`
+M<3V`$]8````<`&H``5=S=&$``P`24T1/0P```$(``?__````!@```````O__
+M````)````````___````0@``````!/__````8``````#Z/__````````````
+7``````````````````````````````#_
+`
+end
diff --git a/sys/share/sounds/mgcflute.uu b/sys/share/sounds/mgcflute.uu
new file mode 100644 (file)
index 0000000..8f27e53
--- /dev/null
@@ -0,0 +1,413 @@
+begin 644 Magic_Flute
+M``M-86=I8R!&;'5T90``````````````````````````````````````````
+M``````````````````````````!!249&4V0R80$``#0!%````````$4B```!
+MSJ<]K5FG/:UB``````````````````````````````"!@5G6``!&3U)-``!%
+M&D%)1D934TY$``!#'@``````````````````````````````````````````
+M````````````````````````````````__\`_P````#_`````````/\```#_
+M______________________\`_________________P#_`````/\`````````
+M``$!`0$!`0$!`0$!`0$!`0````#__P```````/\``0```0$````!`@$!`0$"
+M`0$!`0$!`0$`_P$`_P#^_P#_____`/____\`__\`_OX!`/__``#^``'__P#_
+M_P#_``#_``'__O___O[____^_P#_``#__P$!_P`!``````#\_@3]^`#_^_W\
+M^_W]^_K^_?O^_?X`_?T!`?[^`/__`/[^`?__`/\``/[_``#__P#_``#__O[^
+M``#^_0$`^_X#`/S^`?_]_O\``/W^``#___[_```!__P"!OO]!P']`@``!/_^
+M!@;_``4$`@'_`0']`@7]_04%_?P`!`+]_/\"`?T!!?_[`0H`]0('^_P&`/T%
+M`_T!`OX`!/_Z`0;X_`T`]0$'!/\!!?GZ!/K^"/CU"POS\@H)]/\(^/P%_P,"
+M]/<.#O;R`0$$#/SI^A<,Z_D2_/<-_O('!?/_#/GS__X&"/?S^0<.]/$+`/$!
+M`_?\"OKO!OKV$/WS!/K\`_S]_/8!!OO^!/T!!/T'"OK]!0D/_.[]"@S\[O\+
+M`?/R_/P"_?`)">_["@GY[@0:`>L$&`KO_1L`[0<-`?CQ]@L)\/G][PT4Z/(;
+M"?`$%`@!!P0)#?GY%17KY2`AV^,5!.KT`0']`?WQ_Q,"\@<,\@(>`?$.%/_\
+M#@GX``3U_`+W]@#_Z_L:\N0=!]\.&NOV'@GU$`GP#Q[P[A4"Z@(&[_<(\O0,
+M]N8#%/OD_A@&\0`7"/D1&0#Y!@T"]OT!]/7]\_7V\OGOZ?0$"NSI$`O[#@P#
+M`@`-$`7]]@80]?$'^>W[\_#_ZN`#`_/Z_`0'_0@2#0D`!Q<7!_0%%`'\]>O^
+M]N/U].;M_`;MV`<?^?'Z!QP3`0@1"PP;%OOY!P+_!/7A[`3WW^CX^_OZ\/85
+M!NT8*/;U+"X!_AD5"@3[#POBZ_KO]NS?^_SF\@3\[/</#/W]#!P=$`L5&`L,
+M"/L&#0+LW/`#]N7D\/KV_/_RZ?45%?K]%",6`!HJ`>P"'!GNX__YZO3TZN_P
+M]0KUT?DC]-@+'0($&AX/"0\*"`H"`PWUZ`;VT.H,^]?C`/?N[_7]]?`&'PWV
+M#2@=_OT3"_T0$?'N_/GP[NSO^O;L]O;N]_+W`_'Z&Q($%AT0_P<=!OL8#/+V
+M\/'_\NGQ_?G=[0GOX?CXZP,6`08B%0H8$@`('Q'Y#0;=^2#]V_(&_/;TY^;X
+M]N#L#03X%!L,%AD+"0H'#!,/^^P%#N[U$O?B`/K?\?/<ZO[P\!`6`@\B$`(0
+M$P<5&`$'!_C_"PCX]?SOZ_GKV=WF^?/A_QP/!!`=$P0#"2$<]``?!_,/$?O]
+M^^_H\//;VNO>Y0G]Z1(D"/X/%O?]*QC]$@+R(!_O^ACZUNX#YM#=[N#7^`OW
+M\@8;(@7M!R(C#_D,&0X4"?L>(>GA_O7I[-O.V^/P!?[J\QTK`.P0'!,5#/\%
+M)"#Y$S<&Y`0$XN;HS-;OXMWW"?KV$Q;X`R$1`Q49#A,@$1@^%_(C#\?F$=J_
+MZ=S#]07>\Q;RZ1<:[NXN-//W*RD2'C8H"@$$`?/FX]S4U=SDZ.[Z_NKG#Q#E
+M_R\4^1`>)#0E#2U'"]0(*-R][^G"V>O>\_O5WA7_UP@9\PLD!@\_+`<W3AH/
+M&/KQ`OG0P-SCY.O1W@#IWN?O!/?\'`/[)#(E'BU$*PL3#/WWY]O5T=CGZMO7
+MZ?#BV/8*[?46#O\@0QX75D4;+QL%"O?VV+KI\\?/ZNC;V>7:W_WR\PH!#C4@
+M$$E6)RY,&^T'%OK7R];J\=/.[./-U.GNV^8+_O`C-1<E2E(Y,C<D$PC]^NC-
+MVO;ERL_CWL_7UM7E^/;C_RLE'"I%3$-+,1@7!@<)YL_B[]_6V-;-R-;=U=+B
+M`_7?($$9)$1283P4,3,-_O7MXN;SXLG3WL>]TM7'T_KUT/0J)"HX-%9F/"0O
+M.A7R!_+?`N>^V^/0OZO.Y,;.U=SW]PPG)#,]6&PN(%<U`PC\^/7DZ=_1V,VU
+MO<?1V[C&_.SQ&!TM1$]<3T%&,B8D`/,&`.;9Y.K,OK^TQ]2RM=[EY?88*2I$
+M4DY82D!#(AD6]/[_W?7^PK79Q:/"VKBIS^[K^!@B.UE)1%Y/1D(2&BO^Z/?^
+M\][-O;O%L:W0M)[;[-X()!HW9%([8&@[,S(8%PGI\@/TR[W.QZRBP<FCM^'A
+MY/XF0T!%4TYA8$0X#!0^^L;T^^;@O*J]NZ>LM*C*\-;T*BU'85Q28'1;."LA
+M'0_<T/;LQ+.OJ*S`LINMS,K0]@8525@\46]866H]*S<;%?CC#?/6U:ZQQK.<
+MF:RXK;38_10;,4(^87-03TTW/S4"[Q,:X<[FQ*S.OIBQO:NZS^H+(RPI/5QA
+M13Y3/!X?`/("\/3TS,[6T]RWH<O0OL/(]!\6'"LT3E1$/#PY+3$:]18E]?'X
+MVLC9W*&7QZR1M\?5!`P$*4A.34U-244P+2T)#1D`^NG2W<VUM;K&J:#6U]P.
+M#Q<S.4\_)D4^(R`>'@H&'`3X`O/QSK#-Q*VOKJ^WY03C^S,M,#U#34%%23`^
+M-Q(T*/'\[,[)K:BJEYNDKKW2`/X"1$8B-DI-0R,P/`D'+A/Q!O[0U>3(N\C)
+MQ</6Y.8!#Q0G)2(Q,"LC*"<5)!H%&QL(`N/)U,:[O9ZHOJW0[^'X&24K.E5#
+M-5]?0#,O1RO^*B#2T=ZVHZN5E[^OF,KY^0$6&R0Y/#DV.SDG+S$@(!,4(P'C
+MX]W9PKW-P<?(S/7\\/<''AH/%R8],R`G+#HQ)CP7W?7\OK3-J)2]OJO+Z.#Y
+M'A84+4I&-E);."Y(32@0)1/:WLNEPKJ2I+FTS>KMY_$0%0DB.!X9/D`F,40P
+M*34E$A'^W-;CSZ:\V:ZRYM+0^>76`B,6"S!%+SE<5T!!,R41]O;.J\BZEZ>^
+MO[70Y>$.#^<?5RP92&([($A8,AH=#^CGXKK)VZ"L[M&ZZ/'4[`OLZB,=\1M"
+M(!HY-B<U3S#]$A?PZNS=S\S3U\;-YLS.[M3H+PGD,T$=/$\X*T-""@P/W=C>
+MU<&WX=:IW`/0W1/WYAPU#@],.P,O02$P(@;[\@'VULO7Y.7KW-3[]M;A[/#N
+M\A(1`APE&R$;,5(M"1HE$_WK^?S.TNK7U^+%K=+KU>0&^00T.2DP-SI`-!82
+M)`7K[=_AV-+5P=WRU]O?Y?3T$"L:#AP^-@TF/`T"$PP,\>#ZZ^+OV>GNR^3M
+MT,K1[OOM_AH9$B$Q)"M8-`<\0A8G(?#P^.'/T<N^OK*UO<C?UO`=$`PQ/B0H
+M33X/+$<5#B@,^_?QZ]+U]<#KZ[;F".7C"Q#I^R$%`A+X`R,5#1<@'P`0)@#T
+M!/SNW]C3R^/JR>(+[^,/$_X;/R8<-S-$1R,?$`@/XM;MUL.YNLR_Q]S+\1WT
+M\"<=!2HM$"(L)#<W'@P3(/S?`AGXV.;KW_;MT.OKWO3MU^3_].+_&0\9-2TE
+M.S(2!0X>"M_6].&\WN/#S][QY-00&@4>&2DZ-E]+%S,K"P?FX?/?S\K'S\W6
+MWM'F]^;T`O8#'P;L+SL(-T@>'R$8"@L8!OT%[_H,[.3:S.KJT]/&Y`7>W@H0
+M%2LS*B,Z)@(2#/?_`^?<]_7HZ];=_O+J`@S_$#(:""\X(R`3!`P`VM'K\-;<
+M]>7G!_CH__/N"0+[^_H1"@`6$!(I(`4((!7U`Q<&`PX#``[RW_K>R^;3U?'=
+MX0/Z]!0<&Q<0*S`7!@`(%A+Y\0\8\>;N[?7FZ_;@_17R!1?Y#A__!!/U_1[[
+MW.\#$OWM#P+G"03G[??WX.<,]?,:_O$B&P<B%`HE&@,'%QD+`?H"#^[/WM;>
+M\\S-\.OJ_`/T"1_^!C4:_R,8!B,5`Q</!Q<6]^_Z[O?QY/S\^O3@``KJ]_'H
+M#P?R`OT%$`<&"!D6`A`!]07P\0/E]2'JY2#_\1`#``D'#0H=(0(-"_,,*0_8
+MWP7ES^G?T^_XW>H'\_<(`0`%("8)%CXI$"P>#B$D#_D,\;[P_L_AZ.?;S0\`
+MRO_LT",3WQ<O%!`C'?\3*@D+$/+RXN8*\MWR"0'J!Q'P"A/B[1P5#S,.YQXA
+M`@@`\NS\\L?3[]34[_'QX^(1"O`1]/8M#21-."L.1%GY($(%!N[;[=G7W-/.
+MR-O9SO#>RP#RU``A&Q(D.C,?&QTZ//T!&_WJ_`S=V1/RS@`+Z=/H#>;("R\/
+M_@\M'Q$?$2`I[^L.^L_/#>VP]NK&]^+:^_OKWAH_!B]2%C%)0$@/'#7:!C3"
+MTO[.SM'/R=S_RK/Q^MC;`!@%""X?"!XT/1X+(R4D"/0?$N3Q"/KM!_;!W03U
+MY=_L`@+_!`07*AL-"A<E]>('[MWEQ]K:R`G_Q.L)!!`5%!<U/R4R,BQ,,_?_
+M*1O>SN_AM:S2^MF]\/'9__?B^?GX`QG[WT`Y[#$W!SU!$!(;#/\#]^02"\OL
+M_]_C[>[3O^[SW`L;#B0>$BLY&?/Z!O[7J-H0V;SQ!O<+(!(&+BWT&C$/+3$/
+M'Q?[$1'CV=_'O]_CM.4MY]\J)0']&0?7\OW9[PL0$`4E-R@P(Q\H_.?Z!0CI
+MX?;K[/OR\.S=Y/?LUP`U%@D_.1(H(O/V[-#+M;S>X.;R`!XG(T1,&!P^'`$(
+M"10/ZMW[!^_?V][HVLSC``P4#A0F`P$G]MW_[<S*W_KQ^A@/*%$R'C,R'00`
+M^L_@!=[/\/3H^_S=_C3]PPE##O<4#!0D^-/H^N+*T,[)[POW]35;*C%H,_,M
+M5O:[]_[<X]+9`P'CX1<5W/$(^_[^__7Y*R+0]B/(Z2#(TA,!^1,I&QM@3O@<
+M/0;U^N30V^;$Q0H4W/,G$?@&$P,''P/O#`P&"O'N_=_2[^3:WM\'`^$A944:
+M)$\\^P<0\NOFU<KL"O+]&0\%_`\.X_X,Y^7D[PP(XLOU`[[+">;A$P(.4E%#
+M7UDQ*2$*"-.N[-N@TNSD__8"(A3WZQDKZ.<D"<'G,^NR!?F[V?#CZ1<H]QQA
+M-RU6-1DI"?#Z[=[B[>GD[?P3(1$%#P+F]_7'U?+4O='PY^+X\_(#&!L1*S8K
+M,R<L4D$<'QL`^/SGU>/PV-4!_=K[&_;9XNG>VO#QU.D'\`8?``@;%!8*!@_[
+M&#@'$S\P*"<A#O46(<3`(OZNS/[<I?<9L]X5V/8.Y`8?`0H9"O?Y%_S>$AGW
+M\Q-`%Q-;+`I&,`@;%??EY,>GR-:EK_3\UNLC)0T:+A0'(PWB_P;7U^GGZ@`@
+M!ODO)QPZ*S=-)@,)%/?-U]RVOLZ_W//N^AHC`QU(&_T)\^?XX,K7W.KZ[NT5
+M0R\',F,S"$)(_P#ZQM+@O\;HS[OV#^'R,S`,%AL=(P`(`]'S#M3,_/?L!O+I
+M'"<A*!T-!1T*S=[TTNK_R]H@'P0?,AL>+`X,)0/M[.T`YM[WX>T,Z=GP#0WR
+M`O_^(@SN_/OM^O[F]`D&&1X`!$A<$/PR*?KHX^?Q[M3.]`/Q_@D'"@`'^]\(
+M#,K1X-<`^<WU'P\)&A0:1T,+#4!%&/T2(@K?RN/GY?/A^PW=!S?YZQLB\+S5
+MY+K+W;O8]NT3(1(N3D@C'D)%)0+\*3#HU@$##.^U]!3M`/'T".GW">K4W.W:
+MPL?-V=SF#Q41,CHL+5)@&`U$*03\!AOU]Q;X^PD&^=0!#\'P!Z"_^,:UO-':
+MU>[<ZQ\6%R,Z8$@Z/"M,2!HJ)OOU``'I[AWTN?06U,3S[,G2QK'C[;C:!NGL
+M$BHR)28\.B<4$2XO#N_P%P7D_@,%$_CR%"(,!1H%]/CMZ;J_^,6NX-+0^/P!
+M!A,V%/,P.OWQ&2X-^!$<!@(D+2(9&34S"?X1'P?6N<#+MY./O-J[R@WR]4XZ
+M'CY!.B`2$A8R'.?K"P+W!_H#%/O]`P@-_Q7XTO3HT=3)QMWKS=$'+C4M-#,K
+M/QX&)@#0T\_>Y,J^YQ$!`RL])18]0!0<*18"[=_F]M6GO=?9V,WH"O\.)1TM
+M-ATB(@@0[=4$Z=`,)0<!+D`B&1P0]^S@R-G1M-'<T^7QZ_,@+0L4,"LS/3Q"
+M-BX_#\3A\<*OL+_6W,OJ*_[;.D7MZQ<'[@05!/C]$"H\'_`/-A?OXO@/\N<'
+M\^7\V-T%V]+X]/@#ZO<X-`H3*AT,*!/:___"ZA#DU_X&\@83\O$6%@/_`04'
+M$@L(,"X%%2@(\/[JQ^'6KM3HP]/Z^O3T`P_]$"87+#@O)2%410HH&_<%ZM+6
+MZO?;\!3^XNP!W,#8T;2WUNSW^P<O.#Q,3$HQ/4(`##44\.CY[LO<U:Z^TM7E
+MZ/8-)S4C,4LZ$O0*"=S;YMC?\N[U^O,9-!8(]N@1$.GU$`O@W!LF^PLK(2$F
+M&AP7"Q$;$^G&U]K#M)VKSK6JW_4).3$Q6F993U5.-R7^\`_ZR-GTX^7VU+SH
+M`-#`[^W6Y^X!'!4%_ATM``0L)!DB*248(#@=_`3DQ]O*J;78[]_>^PTJ+A@:
+M*CL@^@?\^B$$V_<*_>/7Y^SYY;38__#_$@,",#H*!B]+(@@D"1DX]?4O#N#F
+MY,.QQ\^WL+##\N[I.5TD)%$Z'34Y'0P/!O0`^@@O_N($\N#=T][EV]'-W?'T
+M`/;L&A#M#1@?*BY9125032`!^P#/H*>EHKC$T.O]%#<J)4T^(2X@`0,/_^_]
+M%P34V^_H\^76\/7\_?89,1\`_P3FW_3VY^L/(A4A34D]5SD(]MS:TJ"6N\"F
+MK-7R_`\7"B).-Q(T6UE`'2L]&@(`^N2]P-&ZPN'F\@,"]_8."N+B\/+@QO$5
+M!1L\/S@Y23$5,"#U^.&]T?#OW-/LY,_TZ,T,)/ST%BXC(S8S)2`(Z/+QS-?M
+MTM/U^0$.!PD4!N7K`P#Z`0D.*3LM)RDX-0[Z[.7NT[/!W.+3T.#S].+O__L$
+M#PH3*RH\5SP4%#$M!O?X_?38XO'V"@/P[./6S]3-NL[V[-'U-U$Z-%-70"\6
+M"Q8'X];;V=/G\M35]_#4U.4',A'O,4<A)S`=%Q3QT-[MV>T%W.0O+/L,)1+X
+MZ-?(WNK1UNP`'A<&(4%`+2`C)186$^C?"`O-M.?>L[[!PN<"^/@D0T-!.C0Y
+M.@[H`_C.U>#?W.,!#@'^#A<(ZN/X_>S@ZP<*]/<2(Q']#1<6&Q0+$AL9!P41
+M\-CKW<.VL]?AS?D?$1LF*#XI%2P1_P_LX@(%^_G]`?KV!@/;ZP[DX0[_`!H)
+M`PH#!0D%_O/Q"13W^QP:`?<"!_KGX.7EW]CA]@\;``8F*"D-`R@8_1<)]A@3
+M]/\3_>;^_,W,[>;+U.[LZ@L'Z`D>#Q<%_20D%QDA+2`C'P<<&-W9[N/>S]+R
+MZ_3[\!@*W/D-^>OS^?P)!`\B%!H="QX5\/@`__7G`/_R#!(#\>?Y^_/]^0(6
+M#Q,7%2<>^./[!,.[\=6[Z/WM\1,B#`P@#`LB`@P\&08D'14A(@+R"/WM\>CF
+MZ>WNZ>':ZN_:R=+DY>?Q#B<6'4A%0#X<*CX;`/W]\N;DX>OR]O7U!^[9_0/Z
+M\><!_?0&^0@;^OP#[`00`1/_[14@&1X/!A\+S/01OLL1\.D4%"0R'"0=!@GQ
+MYOKAR.+KX_3Z]OSX``CC[QP*_PX:-C(8)R('#`'EX>[OW.X(^0HC$@L,`^CA
+M\=?0Y-WK]_,0'!\H#Q`N&`@2_Q8N]NT/&0G>[/[?X^/9V^#Y_?#W$1H)&AGR
+M!1#G^/_:`S`'\!4R*10:)18$_.C>_?S3Z`'E\P?P[_?_`<_2_^KD`P\<*1X)
+M&2D%]A("Y04(ZA8['04;,@SG[?'LV,K;ZO3T^0T-`O_\].3<XNKIY/P;'A\=
+M)3LE`0TC$@@0"`4>(PD4$>X'`<G6Y,_/X^3)[B+IT@GLT0?YT_T%YP(C(2Q-
+M4SL^2S0D+RD-\^;EXMO?V][JU\C-W_?5Q/#TXN7]'Q8"#RHH^_8N'_$6(@$?
+M1RHA2#D,`18+Q,?]TZO:^.WT]/L3_=[Q`MW'ZNON#`3^`A`:_0`3!/,((PT(
+M-E!512@?,"GQW/'FT;.W^NC`^/'8!^JXUNKFZ./P`Q`H+!H<0#<%)3P*$!T9
+M-2,-+#D7[O\3UJ_,R[VUNN'2QOKQW/X'_O;]%Q<$$#D\*"Y.3Q8:.`T$".WL
+MYN\"W^TB_MO\`.G>VN+BT<OB[>+P%!L.$`P+#@X0`1HW!0M**1@X$`<4Z.WP
+MU.3I\@#H`"P9`OS[`-J[T-/&P,;H_@`#!1XU'@P?-C<@($`\)SM&'O\+".#'
+MR=')M+K:\?/Z`0`.\M#FZ=S<V>+X%Q@2-4Y"0%!((18P-@WP#ASVXNCDV,K%
+MNIVVX,7#[`<9%A@;%B@G"?[T\?SQZ@4?)R0A.#TK)`\1'?OM[^3S`/'8X_W9
+MN]GFR</N]-/2`C@?!2D<!Q\(ZOT1"/$(.C$E1E1'+R0D!O#W_.#!TMK,U\W"
+MV\JVRKFMX_?C_QXF0&1/'TAI*@HH+1<8"_TR./CX'`/,XO^]K]O/O\;:XNC\
+M[=GB\/WSYO\?'@T;1$LO*T4\&B`A]NT4!-GJ_P`(^`$<_O`%Z<?E^=C8Y<W,
+MX>/?X>'Q^>+R"P\B'BQ<3C=68D`P.1GT^NW:Z_OWXNOSVN#KW<V]MKBUQ>79
+MU`D4_P@;+2LB'R9`1#8]7F,[,BP-!^C*V,VYN\[6QM;^\N'X\>KYXM;R__3Y
+M"0,/-!WX&2L>#P(?(Q<U(!4S$PD:].T,]-'C[LW'ZO+N__;C[/;_Y]3W[M'S
+M#//U)#<>%"$T/RXB,349$!T)!AP2`._?X]:ON->ZM,/%Z?_\_0$5%@4)#P\<
+M*1P7+SLP+3@Z*Q/^]NK=W-GM[\K?!-C-^.;)U]SD[^OR`1HU(10L&@\M'OK_
+M$A8-!0\A,2P/`O[N[_#8TN_OUM;<[_OBXOCHRNOYRO@BZ_DB&R(B)"\H+"@(
+M&282-S3Y"B@7`?;JY/#?LJFVRM?*L,+[[-?_]_\?_O\C'A8A/#@M5DDD-BTA
+M*QS_Z?H1[-/_`^7SY+S`SLFUN<F[TOKIYQ$K(0<1*AT7(!PJ/B8:0$PS)R\N
+M#O3R\O#FYN_NYMSAY=W/P,#$R<G"U.GZ!/<0+1,9,QXI0R0A-S,U/D$Z,"0=
+M&/CO#.;%YLJMSL_3TKG4XL?%T-CG\^SE"B<9&#90.C!./R(N."H@)!<,&0O_
+M#O[RYL?$R,&^P,[6R=+\`M_O$0#IZO___`X.'"@E+B`J4#P:&Q\8&"$=#@P6
+M".?J\-?/S+R]O+G%T][E`P3A!3(.VO8V)O0)-20))DDX%2`_)P0<&_,/%=K=
+M]=S5Z=W$SM7#U>K6T/07^N\K,`\E-AL"#"L<^`88"PH0"!HG$A`3$@GRZ]SF
+M"NB[V?[@R??VV/3]YMCL#@$*)A(-,#$)%#TC^P@2_/49)0,%&`+_#^O:_N7'
+MU<_4Y>K?WPD#X`0?^>T.$00<*!<D/"PC-A[_#!<*[NCTZO#YX<[7]?;8U-[G
+M\.3L!@/^"Q4%`A\J$?P(%@H%$!`3*1SV!R$1$0_U^`;XU<WHZMW6TMKA[?#G
+M_0G_!_X`(Q@#$2`F&`\A%A`V(O$'$@@?$O($%0'HY^79X]*OQ]>\R^;?Z`,4
+M!OL@+Q\<(2PP+2(=*CPQ"0P?!/X$]?#T"`/=Y?37TN36Q,[<V<G3]_OU^?82
+M'_L-/S0?*C`B*$0O$BXC^@L5_?H-">SL]>G?T-;;R-;7N=3YWMGZ\N;_`/8*
+M%0X;-BPC/$-#/3$R(14:%!\3\`4$Y>O<S]"^P<S`NM;@Q=T*]-W]$?D$&@P1
+M(2(H+"HR1T`@(B$E-A$*&@(&^.GBO]KCK;[2N<SDQ\P%^]GV$@8!"1PZ)0XI
+M*QXD*S`2#"\:"28F%A<F$>+GZ=KAQK[7PL#6W.+<Z?/J^_?N&A_\&2T:)2DH
+M+QT9'`T,&!D:(1L5&Q8']_#\W*[8Y;K!T-CCU]CJ[_P*\N45-1;^'C8M+C0Z
+M*1(O+0P8#P8:$P'IW_SQS./EP<K,PM'<Z^73]!0'``XA+1P)&1\9-BX!'385
+M#QT>&@\,_^;IZMG,U?#GR]GLY.T`\MKN$`?W^!8L$A`:!PD8$0('$Q4%_14I
+M(B`G%_X%_-WDZ,K$XM.\ZOK5Z1#VZ0P&\@\;"A$1`Q,F%PT7%`<7*1(4,R86
+M*!@`!/'>X<V^R[JBML?!S>WVX@0P'2,O+40Q%24B'BT@"A4:%!`%!Q8<"/+_
+M[\SGZL?:WKS#Q\/;XN7DX0PG$AXW1E,U(2T>%AH4#_OO`@O[^A`5"@+Y_`#H
+MY@+MRMONU<CG[=32Y_'D[`\."28G%!8H.C(E'14D)A(8'1PH'`<&!//DX^/1
+MQ=+#LL/&S-C:V^;Y]/L5%BXP!"=9+A])02<R-B,.#AH6#`'MY.75SM&]P]2N
+MM^'5Y?#J#POO$2@:%R`>$@P5)18%&!\<$P<7'Q\A$@H,#?_M]O??U-;,P,?=
+MWM/B]/+[$`S_$"00!A4$!!T(]ADH$P\;+#4F+345$B+[W_3LU]?"M<[&NM+9
+MT]CO`_8%-"X?,"<:+"L@&P<+%04)#@8A.`GW)17=Z?[ET=?6N\KQV=3RW=\(
+M_N0#*QH&(S4G&BDU(!01!@L'[?D:!?8;$_'[!OOQ]>C#U?/:T.?PY>3V_/#R
+M#@P!$@#_+2\<&1\O-"#_"S(<`!(.\O\,Z.+SX=[7P-/DU-'>Z^#5[03\^`L>
+M'@4%,R\#&D8N%"XH%CDW#P\3#@?NU,W=U[ZZM\+9T<_G\.CN^?D)%QDF&A\P
+M&Q\Q)!8?*0CX'!@''1<##1+RU^G_Y+JXRM#1V^SD[0;T[O\!$A\."PP$'2@'
+M%BD0$Q8+%Q\<$A0M(`@8%PL%Z=C?SK?#TL:\S]3&Z?W1Y"4=]`4U,0P:24$;
+M)SHL)BL?$BPG[?(6]][SZ\W*ULZ\PM+=W='-X?H"]OPJ.!01+"$H/1(90!4.
+M)!@<&A01^O@`].3=W]O@X\O+\?_FYP#KV0`'X_(/"04!"1P-!A83%!L-`Q]!
+M)QH^'P@L%_'P^^W-S;JGY/K+V_;7XPKTWP,8_OH*!`TA'1XD'A49)!P=+BLE
+M'10@'0+Y\NS;L*_!L+?+Q,_AZ@$(!!$I/1H)/#(('R\:"1(6`@H;#/\-%_[]
+M"O'W$0#IX-O4U>+/Q.SJNM$(_?,;."`5,#(A'28V&>CX#`4-`P0A%_OV_`3_
+M"0C5X`C@S_#UY.?OT+WI^-OC]/H/'QD;.DPM(SP7`S4I^0@?#_P$_.O^".K2
+MVM71W<W/]O7;WO'W[^OR`0?^\?X9)C<Z)S!!-BPG*"T<"0WWU-WT[=O7Q\?;
+MN+GTU]("X>$+#@D#(3`)"18)#Q\4"!$8)R(**T$4'S+S]RSJNO;\Q<';R*_6
+M].'6U>X%\.X,)R<+!1DC&Q$6%!`0^.D<.`\;/RL;(!X8$@P`ZM3`NLC*Q;Z[
+MV.#$UP#^_Q@9#!LO*B0V-R0D&0H2&1@(^QDF^_4@$.\3"\?4]<ZZTLS$ULS'
+MZOGT_`H2$2`@$B]!(2(S&0\>&!``!B``Y._Y#`+P__OOZ=OJ[N#P[M//XNOI
+M\?L$#0#S"1X>(QT0&BH9^"%-$_HC'O3T#/'K!>;+W>??X_/JX.7I]/?PZ_8(
+M_OP!_A87#1T:$ALB&14Q-QL='!`?$.#K#>FPQ-2WS.#6W>?Q]/P!_ALM$?@'
+M)R`("QX@$`D!`A<8$Q@5%Q4/"/X(!>WKW[R]W=K'TMG>\?CX%#(6`B<O'Q4'
+M&2L:"`3U\20GZ?8E'`#^"`H)#@CHV^;DWM33W-#,V.;DYQ<7^R`Q'!PJ-S`:
+M&!X1_`8;`?85&0;K[`L`]P#N[^G:[//FY^G<V-[6X_;M^@8#&!0),58T"B0Z
+M&P@9&A,E%?8'!^GP__3DS\_?T]CKY>SDUNOLY??U\P/[^@X1$C1.(11'-10H
+M)QLF(OSH`0?OYN'AZM2XQN7IU-GU\NG^!?H,%OP!%?7O%`X!&A\&_ATV'1X^
+M*Q$A)@;S`0S^Z^35S.#GUL_3T-#GZ=SS"P@)$`L*%!D9$`X(!AH;&RLN.$`T
+M&PD;(?OK[]_)P,_2P,[=P+W?ZN7E^`X<)QD9/CXE-2L"``7U^@K\_!H6_`@:
+M%A\8[>4(\\3;`?#7UN7OY^CJ[`0%[OH#`2$M&Q02&!#W`0SW`QS^[R$B"",O
+M)!<`!0SNXO/GPKS/V-+/W.?P\>CU_00E)00:22L*+S(>*"<.``T/\/,-_.CV
+M]^KJYN_NSM/DVM78ZPD,_@4=(!8@(1XM&_<#%0T2%@H-#?GP[.W[]N38W>K\
+M#?CK%Q[N[!$'Y_\3_O0`#P0+*Q3W`@;Z[O4`_OT#$A$)#R$F#@8'\.__Z^#\
+M]][K\O/SV_T4X.0%__3\(2$.*"(,(BH/_10B"_GM_!T2``3T\??;TN#5V-/!
+MW.S;Z`L@%A0C(R(;*$$I"A<L&`49&@0!_O#FW-SP[\O0`?G8\@+Q_O36YOS[
+M[>8#'!H>$Q8S)Q0H'P((`OC^]PP1[P8;^_#[!P?BVOGOW.8`!M[K$.#&Z?#G
+M\?/J\?\.(2HP-B89+"X6&Q,,*A[_!!`8$@3RYN;1QL2\Q\R_P]WEW?@(]O\:
+M%0$()#X])39.,RDS+!P9&?;I]_/T[O3\X.#TZ]S,SN?1N.7NT_@&^R,P$`L;
+M'!P;"@TE#?D9$0HC%`X8"/T%%0'Y$P+R]_SRY0?XO]'AS,+&Y?#E_0/D#4(A
+M$1H@*@L)(!,>(2$Q$Q$V*0D+%O??\=_+X>79R<?=Y-+"U_;UZ.O\"R,U)"A#
+M.2<N'@P4"P$$_O+O#"<%YP$/].7IY.+JX]3D].#B^/L/"];I'`L`%0\%'RP/
+M#AT2)RKV\`T*^_T'_P$4"./Q$??R[]3H\M&_Y0GGX0K[Z`TB^_PA$A$9"A,9
+M*3(6&"05&QOZ\A$&V]GFY.ORWMSX[M'1YO_YZO`!#`<1)R,<'Q85'@O_'!X!
+M!!L=```I&_?Y\.+IU<'J[<+;]^'D]?L-"O\)#!(7)2H*%C09`@P7!/4%!_[W
+M\/\6%@,%#?[U^N_:W>75U][.VN\!!_,0(/,3.1,7*!D='10,!A$3!O__\.0,
+M&NST(`GC^_W8XOKLR+_6T-;UZ.\/_P8E)B@G)S(H(RT3"BH5`A3WY?[\Z>G]
+M`.;C].#;!_G&U/#JT-'N^O/K`A4*&S`J+"TG,#(=&AP.$@L!`M_N&NK0`?[,
+MSO#JTMGM\^K?Y?H'^_80"/`/'P@3)"4F*2X6"B<E#@L2_>D'$//Y"_SGYN;8
+MR-#DV<?7[>WC_B,-^1`3!Q`6&A,-)2L<%1TO(1,C&_OV$0SZ"`OYW^;PR<36
+MP+C+QL3?Z_8>'/X5-STH"1].)_<@+@@('R4:"0#\!!,`\`+[X-_HV<34T;?3
+MV[+*_?KP`AH;'3HZ)#Q`&R0U!NH1%_7X`_KM\P\0`P@#`@G\W-#K\M71V,K1
+MZ.SM\._V"B(6_RI$&R4_)!`7*"?^\1<-Y?T1`0T-_@K[W=S?W-'(T,S(VN7J
+M]OL'"0(4)RLH,$`V,"XM."4?*`#A\O7DZO3CXNK?ZM_1\>+)[??CVNT<%^P#
+M)A45&PL=,A+]*#L-^ATS'OWX`OKW^NWQ\.;V\-33Z?GEV^WLY?0-"?0"#P(/
+M%@83)1D(%RL+_B8G$R(/[A,L!^\##>O=[M>YR]7%SM;.W.WU^P(3%A89%R0P
+M*R8T+`T4(AX/`A44\>3X"_KM\N[YY\;-T=#.R-;/ROD)^`XA%A\W,R`;.TL/
+M"CL1_!L$^`L$\.3@[__[Y.`)#-O4Z>GAXN+:Y>;E!P?W#!HB(0P:.BP8'B4H
+M%009%PT9_^3[$/[L\OKY]>[BV=?=W=W;SMKKZO;V\A,7"Q(/+$<F'3M#+!TG
+M,SLG^_<)_NGCZ=K-Z>6OMN#+PM[8S>;X\P@5"1XJ'"`H+S$F*#<S)Q,')S</
+M^@/[[O/CR>;ZS\3@T+?(Z?+BU_`-_OD6(A<6'Q``'R\4"Q\N%_8.*Q`$&!;X
+MZ@H?_-_V#?'-S=O5O<;=S=KKW/L3!@P.%AT-%1\5'"\T)B`E&B="'_T)"P?Z
+MW>/T\>C2R=*[N-K%N=W8SO05$A$G,3,N("PX)R0O(A04$Q`@(07]^_#H[??C
+MVO#JTM/?V=7JZ]?F\>7^&@4!)R(&$RPQ'!8K*!4,`0DG)0+X"@7Z`?WV]_?U
+MWM+7T]79V=G9Y.CK`@WY!B8)^B4J'BHX0S48'"4?+QOI_`3@[??=[0/GV=W:
+MU\G0Y-O5W^CZ"@D6*Q@$$2`D'ADI."4/(286)B#Z]_O@VNODX.WLX-ODY-WH
+MZN3FXNGX_@\.!!H=!@P:&2`E'!T>$Q,?*1\+&1#@[@KLW^WJV]WDU<O,WOSK
+MT.+Q^PT"`1D2!A<6$C$Z(AXO*Q`2*B04$/SO^/KT[^OHW]W5OL'/UN+>V^?P
+M_A0?'AX<"PXF)!HM.2`6)!L1&14,!>W9ZOKNZN[K\??JT,_=W^+BW>/H^108
+M$Q47$Q$1#A,B)!<0+"\""RT8"POKZP;RY?3V]^OJY\G.YN#8WMS&V@\._1(>
+M#0D5'B4H+#0Y)PP4*2(;'/SC]O[EW?7PW.'2QM;-Q-SJXN+EY04C'A8.&R01
+M&"4P/R`50S/X`208]>KMX>#W\.#Q_?7RZ]/0[-G)]NO)]!8,"!PF"0XF!_D?
+M+2$@'B0C#!$='!'MZO;EZP']]P+_W=?JX-/8U,[.T>/X!107%QX<("$F1#X=
+M+T,D"ADH'Q/]Y^+C\N_<W./HV,K8V]7=X>GHU>D+#ALE%0X>,S,?*4L\(S,I
+M"/T'$@/FVN7FV^KT[.3G_NK#V_CMX_CTUN\=&@,-)0SV#A(!"B,U+AXH(PL=
+M+POZ#>[7]_KH\OOT[-O4W]W,R^#=P=@'"@(1(AH-$AD/#2PS&"M`)1DC)S(B
+M]^[X[-O6Y^S0T-_*PN#:O=+S[-CL%AP<-#LE&20D&R,K)QT;$?X$#PP(!?'?
+M[NSA[_+GU]C@S=ORT]\+\,WQ)R46(!L8&!04%1\:$2(A$`L'"Q$&_?GX`/_[
+M!P/Q\?'@T=36P[W:W]'?]@H)$204$B09$!8L030N.S(=$QDJ&.G>^?70T_GT
+MV-K6R]7+P-+<VMG7\1(6)C\P'2DQ)ALG-S$K)!(9'0\-`??XU\?AZ>';UMKG
+MZ][=Z>CR`NG1\102#Q,2%1D6#`H8)B@5"2$K#@D;'A4%_?WP[P@!V<_EZ,O`
+MT-C=X-OE]/3T!Q@2!`T:"@@B,3(L+STU)Q\=)!@&_N?G__#;W=C6T+>XQ[S!
+MVN;@W`,J)"8P*"0J(P\:*R`B)1\L(P(-*@WD[?/=WO#OX>7QY]O;UMG?YNOB
+MWNX,&A4<+"<;&`@('1P."!,<#@D6(!T-!@?^]_O^^O7PZ./>VM3-U>3<Q\_L
+M]/@%#1(1'"TC(CQ"+B0L+B80!2(B]O`)]MGQ_]W+V]2\P-'.S=[N[N;O#!P6
+M$R`E$Q<R,RTZ.BDF+B(#]/CXZ-W9T]OCZOGOU.W^T,WKX^L"`/+U&2L-#",1
+M!`/S`A@1%B4B("P>#1TC#/+BZ>WH\/GPY>WUYL[1[.O7V.#B\P(#$1H5%`L*
+M&"`H'18U-"$O+R@Q*!#W]@/APN3HO<?4MKW9V=+A^//N^0@D)1(=,"X;'CHP
+M&BDJ'QL,`O\,#_CU\.CS[>?QYM/3VL[`T^7I^O_W!1`7)R`-%1X0_0DE(B(H
+M%1PF"@,/#`;Z[NSN]0@*[/`#X<G3R<O;TL_CZN@`'1H*'"@)#"LG)"H@)T`V
+M&!0;&18#Z>#;X._HWN+?W./=R,?>Z-W:WNG^"`\5%RPO&2,R+#`M)S`E&1`!
+M&"#Y[.[AW.+GY=S.W//2N>#UY^O^_NSV%`P`$A4*!@XH)Q8L-R(C+2(*`A@=
+M__'PYNP`]=K;W];5R;[5Y.#L]?/_$Q<.$!43$`H4&QPN+R,M+BTB`A`M!=_J
+M].[E[.[6WNW0P,G-U^'FX>H+!P0K)`XJ*`L2)"04'289)"D4!PDA'?;KZ.W]
+M[]SE[>C@SLS6TM;5V/'LZP81$ALK*A,5-3X@%C<U'!T2`A(B#>;L!.S@\>7B
+MZ-K9VL[&U>?8UO#[\NS_%146'AL7*SHG)C@V+"8=!`48"O;N]/;AX./I^M_)
+MW]W)R]7>[_;L[?X(!Q4>`_H8+2@7(#\^+3DN$2$?`@7\[NS9V?'UX=#=[].]
+MT]G1W_'VZO$1&18>%AD@#Q0C'RHO)"HV+1(/)B0&\_?HT>7RV<[:WM?0PL/@
+MYM[H\_G^"1P;&#`H"24]&QDO'1HP)@X.$A0>">?V!.34YN;-U>*^LMG>R>0#
+MZND+#0H7*"D,"RXV(AHK+Q\G+PSX#1L6!.[W_N/H_>O@X-;4PKC4V<CK!^3@
+M"2`7$!H1#RHE%APE+C(N(R4?!A,I!^?S^./C\^C8WN+6R\2^R=WI\.3;]AXL
+M&1`C*R0?'2PO("DR(Q\>$0H-&Q/GT.7QV]3>T,7AY+2XZ>[F\_3S!1<<&!HG
+M*RDG&"$O&QLJ&!8:`OX3&0_^Z^SXZ-[GVM+DW[BUW>SAY/'R`18!`B@F%1D:
+M%!LN+2(B)RPG$P84(!8&[N[YY.'MW]/2SL"WPLG3Y^;A]@0')"P8(C0G'2LU
+M*",L*S`O!_PA'@7_Y]?EX=7?W\;0\-BXR-GAZ^CJ\P(2"Q4S)Q<D)B4C&!<D
+M+1P.&QD'"A83^^+G[>#FX<[G\=+$QM/GY>/S\N;V"@X2&R$7$"(O(QXS/2<?
+M*R01$2@H]MWR\M_@W\K,VM"_N</,T^COZ?+Y"AX6%"8M(AHC,#,N+SP\*!\A
+M&!,6`>SGVM+8WM7&U=S&Q,K&W//J[P/[`B`A(RL<&B`1&246(#0B&"<>!Q8H
+M#/'S\N'9Y^O=U=O?TL70X]S9\?GL\0L7"0LE(PT''C$=%C(Q'R,I'Q<F*0[]
+M].WOZN':T=#6TL*YP=#C\>?@]PH1&AD7)288&B<I)3`V*"$B$@@@)O_K\>?=
+MY>S=RM7EVL2ZP]OV]M[C`!,;'!D;)R81%BD>$R$N(A4>&`P4$`7\Y.#W\=G?
+MZ//WV\_@V=/D\O'BYO\*#!$6&A\5!A4C$Q@J(!DC'@T1)1\$^??P[N_JYM[=
+M\.C&RMS>Y^;G\>GW&!,$'#`4""0L'R(O*Q\E*A8'$A(`^?CKV=KHW-+=V=;9
+MT-'A\/W]\?80(!H8)2(3&"0=$QLG)!L6%14*`PX'\>??X.WKU]OSZ-C@V=3L
+M\^GU`??Y&B83%!L7%Q(/%!<>(AH?)18/&QH.!/+HZ^?:TMGDXM30V=;/V>7M
+M\?#U!QH4%2\O%QDK*!PD*1PC,B,-#AH6"/?HXM[1SMG3Q=7@S,#6Z>;J]OC]
+M#1<6&BHR)!PD)R8>&2@G%A84"A$6!/3SZ^?KV]+EX\K4W\G2[-C4_PKT_!89
+M%28H#0\D)!H9(B,E*AX<)QP2$`#S[_'SY-7@Y=;7V<K+VM3(W_SRZ``8'2$D
+M'!HK+143*BTL+2`C+B43$Q7^ZN7?X-S=XM',YN'%TN#3VO#V[O$+&1TK)!XM
+M(A8G*1<9*2<5$AH5#1`(]>_QY]?@[=;+[.K+U.;GY>?N[/4(!`86%Q<8$!8G
+M(Q06*C,E#0<K.0ST`/_]^^G@Z.;AY]C"T^//T>CF[0+]^PT5&1P0"QPE&1PA
+M'S(W&!$B(@[[_/7H\N/0[/;:V^O@V-[=W][F`OOP#A@:*!<.'QH8'PX('B8<
+M%!0A'@L$`OOR\^G7Z_CBVN;OX]KIYMCL_NWP`00.%A@?%Q$<(AP1$"(H#PD@
+M'`D2%?_P]OGIZ?'BUMWCW=C7W.?HY/(!`@($#2(C$10A*BL:&2<J(Q0-#@@'
+M!OSPZ_'Y[]W9X>CGULC:ZMK<[?`!"OX+'QT5%B$?%QH?'Q@<*R`-"PD)!?;J
+MX^S]\-G@\O/EW^3?X>C<W._Y_?CX$QX1%",@&1XB%Q(F-!T*%2$9"OSN\OCM
+MW-3E\N+3V^KMWM7@[N;?]`0"`@<;*1T:*"XG'R,E'B,H%Q`>%0'X^/[LT-[S
+MX,3/YM_:W]GA[_#S^/X'!084'AD4'B,B(AH;*"DC&@P/&Q'_^/GX[.GQZ=71
+MX.73S=C<X^OH\`$"!A`/$!L7$!PC&1@>&ATK)A(4'A(`_P#V\?CTZN+<Z.[6
+MS=?:VM+7[O+T!`8(%R,E&1<G(0X/'B,=&1@8$A,/_?O^^/'HZ._EX.;FX-7;
+M[.#3XN[R_`4(!ADQ(A<K)Q0:(!8.$Q0*"0T)`?G[`/?N]/'FZ^CD[.?=ZO#;
+MW_GU[P,%_`T9#10H'!`=)!D7)2$1#`<)$`?T\@$`\/#S[.+H]./1W^K@W.KR
+M\@,+^`0B%P\B(Q@:&APF)A@2&!,(!O[OZ^_S\NO@X_'QY]_@Z^_CY?3Q]`D.
+M`0TB&AH@%1XF#040%!@/`P4*#__K^@'P\.KD^.O6]/C<[/SIX>[V]?T&_``=
+M&0<6*!\1$!P9"`L6"P0*#0CZ]?\"^>SQ]N;:W>?IX=O<Z?'LZO@'`0`3%!8G
+M(AHD*AT3(B01$!(,!?T"`>_N^O3AW>KGX>S>SNKSV^/N\O[^!10.%"4A&Q\A
+M(AL6$@X:'PH`"`X,]NG\`_'M]>_@YO+GYO+DVNCJX>X$^O`-(140'"$E)!81
+M&2`:"@L>%@0-"_G]!?GJ[?/EX>3=XNK@U=CEY>7T]?<3%049*"`J,"$6%R(?
+M#1,3"A,+_`0!]OCVZN;M[N;>X>;CW]K@ZN#E^_4#'@@$*"X>%ATK)`\1&A(0
+M$`<*#@'U]/S^\.KU\>#F\.KEWM_JX-3I^_'Q_PH3%!(:(R<@%!,;'A<3$A(.
+M#Q#]^@7]^/;JZ_/IWN;IYN?=UN3LY^KU_04."PD:(AH?)!4/'2$5#!(9$PD'
+M!@'Y]O3LZ^WGY>+E[>7CZ>;I\/+Z__\.&0X*'"D:"Q47#A81"!$2$!,+__X(
+M`_+V]^KO[-OF]^[=W>KNZ>WW^P`0$0(+'1P=&PL%%A\(`1(/#1<,`@3_"`7L
+M]`3PWN3O\.KFVMKIZ^/H^04(#@T.'"`?)1,%&1D$`P\5"P<0!OH("?7S^O7S
+M[N3J\.WIX-WAX./I[OL`_Q`;%!HJ*1P4&AL,!P@)$`H`!@7X^/[Y\?/S[>KI
+M[OGOWN;PZN;G[_?\"0C[#R<?'"4>$!0?%/\'%@L""`/X^/;Y_/#N\N?L]_+Q
+M\.CK[N?J]/?Y`0<$!1,8&QX7%Q88'!$0'!<2$0D$_?;Y]NWM[.+A[?;RX=WL
+M[-_D\?+Z"`0"%!L5&"(?%Q45%A<6$1,9&10&^?O]]^WCX>CGWN?OYNOIXNGF
+MZOW^^P4.%!,3'2(A'1(.$`D)#PP2&PP""0,!!OKL[.WIZ.CGZNSCV^#KY^;X
+M^_L&!P4.'"0;$Q@<'10%#1T2"`T3#````@,!\_+PY.CLY][9YN?3VNKN_`/Z
+M`Q00$20H&QDA(1<-$1L6$@\$!`+V]?W]\>3H\O#M[.KNY]WAY.;J]`,'``87
+M%A0A(!D>%P<.&A(+$1@5"`'_``7_\.SQ\>OK[^_N[>OGX.'CZOK[]OH`$!P1
+M%28:&!X2%14-%A8/$`\$_@D%]?#P[.3EZ^?AZ>WBW>CJY_@!]?H-"@,5)1H5
+M(B(5$A48&A@.`P<.`O/Y`?KPY^;N].S?XNWFW-[F[/7_`0,%!Q0<%!09&14+
+M#!02$1$-#Q`*__G[_OGO[.SJ\O7HY._RY=K>ZO/V^/P!!@P7'A<:)!@'#A((
+M#14-"`X3"OS^"@?Y[>KP\NGGZNGGYN/AX>?X^_'Z!`01&1DB(!L:%188$`L5
+M%00%#/_[!03]]._U\NSMZ.3HZ>7;W.[S\0`!^0L1#1L@&1<4&1H.#1,4%@\"
+M`@@#^O?Y_?CM[O?SZ^[T[.+AX>/J\_CU^@8(#AD8%!0<&PP*%!<4%!`*#0\&
+M_?H``>[F\._I\>_E[>_@Y>OE\?_U\`,/!@L7%QP=%`\2$PX4&@X'#0\*__C^
+M!??FZ.WKZNCGZ>OJX>;T\O$"!OL`$!,1%QT9#@\6$Q`/$A0)!Q`+__?_"/;J
+M\>_K[_/KX.SOX>3K\?3X!0/Z"A4/$A@9%0T-$A`0#A$9$0<+"P3_`?[V]N_H
+M\_'CZ?3JW.;IW_'_\_P*`P07(!<2&Q\4#0\2$Q40#0T*"0/[_0#W[NWKZO#L
+MZN_IY.3G[NSO_/[[`0H3%A4;'1<4$1,2#A06"P8+#`'^!/OO]_3G[//HZO'K
+MZN[FY>_T]O?Y`@4&$1(2&QH4%!03#@X7%0<%#PGY_/_Z^//N[>SN[NWKZ>7B
+MZ/#N\/O[^P,!!Q80$1@1$Q80$Q86%141#`L$_@,!^/#O[.?O]>SBXNKHX>3G
+M\/S\^/P($!,:%0X=(`X*%A40%Q,%"1$-_?@#_O3PZNSQ\/#MZ.OPZ.'L]/3Z
+M^_@!#Q`-$QD9&A4'"AT4!A$/!@\,_?X+!??V\N_V]N[GZ_+HX>KIZ>_M]/[]
+M_P4/%A0:'103&AD1#Q04#`0)!_T!!/CR]?'P\.WQ\>KIZ>CLZNGV_?;]!OX)
+M(14)&AX3%!,.%1D1!@8)!/\!^?/[]>;M]O#R].[O[^_R[>;S!/KN^`<-#@P)
+M#QH6#@P-$1D6!@02$`0$`?C^`>_E\/GT[.WP\/#IY._[]N[X`/L"#PH)&!D0
+M#@\3&1<."@\0#PT`_@7]]_7JZ_7PY>GQ[^GEZ_+Q]OS[_04("Q05$A<6$1`2
+M$`T0#04&#0G^_P(`_/3P\O3R\/'L[?3KY?#S\/G^^_X#"1$1#10:#`84$P@,
+M$`H)"08'!`(&__7X]^_T]>_P[NGKZ^CGZ_#W_OOZ!!$5$1(6$Q07#@P6$0H1
+M#`,*"_[Y_O_SZO/W\.SM[>[NZN;GZO'Y^?3\"0T0$A45$!<<$`@.%1<*_042
+M"O?X`_[T\^_L]??MZ>_V[>+M\^KQ`/KT``T."@X5$Q(5#@P4$PT)!PT,`P,`
+M_P'\]/#S]_/L[>_L[.GEZ?+Q\?\`\@(7#`H2$A(4%!$4%`\1$PH)"P4!`/[Z
+M]_?S[_/S\.OI\>WBZO#L]?WZ_0<+#0\1%!02$`X0$`T.$0H&#`D$`?W_^O3X
+M]/+Z]>GL]?7LX^OU\_3W^``*!P@4$@T3$1`2"0L5#`4*"@D(```$__OU\_GU
+M[_'R[NWNZ.OT[>W[^?;^!`H/"@D1%1(,#A,.#0L&"`8'!OS^`?KW^OGT\_+P
+M\.[N[^GL\O7X^?L!!@8'#PX+$!(/#!`2#0T-"`8%!/_\__WY]O3W^?;Q\/3R
+M[O#M[?;Y^OK]!PD)#@P+$1`-"PL0#`D,"0@)!04!_?_^^/7X^?/R]O3Q\O#O
+M\O3W]_?^`0('"0D.$0\+#0T-#0L+!PD*`P<'_0$%^_3Z_/#Q]>_N\>_N\/+U
+M^OGZ``,("0D0#0T3#@L.#PX+"`@'`P,#_O\!^_?X^??R\/3Q[?#P[?#U]?D`
+M_@`)"0D-"PL0"P8,#@D'"0D$`00#`?SZ_OOZ^O3V^/7U\O#Q[NSQ]_;T_`#^
+M!0H'"@T,#0P*!P@/#P4!!@@&`OS]!/_U]?KZ]._U].[P\.[P]?;V^_[[`PX(
+M"!`/#A`/"@T2#`<)!P8%`0#^_P'Z]?K[]O+T]O'T]NSP^_?X__[]`@D*!PD.
+M#0P,!PL0#0@'!P8%`O\!`P#\^?O]^/;X]_/S]?+O\_;W^?K[``0&!P<)#`H+
+M"@P-"@L*"0H'!00#``$"_/G\^/3T]/3S\N_M\_CR]/[]_@,#!0D-#@H+#0L+
+M"@H+"`("!00#`?[^_OKX^??W]_/R]/+Q]/;V]_K\_@`!`PD+!P@,#`L*"0D*
+M!@(#!0$`!0#Z`0+Y^?KX^??T\?/T\O3U]?K\^?L``@,("04(#0H'"0H+"08$
+M!`8%`?__`@#Y]_GZ^/7W]/+W]?+U]??^_?K^`@4&!@D+"0D+"@D,"`4)"`,#
+M!0'_`O_Y^_WW]?OW\_CW]/;Y^/G^_?P``0(%"0D("`D+"@<)"@8%!04%`P,#
+M__P`_OCY^_KX]O?U]_GW]OK]^_L``O\""`@&!@@,!@,+"04'!`,'!P(``@$!
+M_OCY_/GU]O;U]?7U]_;X_/S]_@$#!`8'"0@&"`D'"`@%`P8&`0$$`?W_`/OZ
+M^_CX^/7W]_7U]?CZ^OO]_P`!`@4'"`<'!P<("`4&!@($!`("__\`_/O\^_KX
+M^?KZ]_;W]OCY^/K[_@#^`0,$!P<'!P8("04$!P0"!@,!`O_]_?W\^OGZ^?KX
+M]_GY^/CX^/K]_OS]`@0$!08("0@&!@@(!00$!`0$`/X!__O^_?GY^OKY^?KW
+M^?SY^?O\_P'^_@0%`P4'!@8)!P4'!@4&!`,#!`']``'\_/SZ^_KX^_OW^?CY
+M^OK\_OW_`0`#!P,#"`<$!0<&!08%!`0#!`,`_____/W^^?C[_/KY^?GY^OOZ
+M^P#__@$!`P8%!`8&!04%!`0%!`$"!`(!`/_^_O[\^OKZ^OSY]_O\^?KZ^?X`
+M__[_!`4$!`,&"08$`P4&`P("`0(#_OT``?W\_/O\_/OZ^?O[^OKY^_[^____
+M`0("!`0$!04%!`,$!`,!`0(!__[]`/[Z_/[]^_O\^_O\^_G[_/S]_O__``$!
+M!`0$!0,#!00#`P0#`0("``#^_@#^^OS]_/S\_/S[_/S[_?S\___^_P`!`P(#
+M`P,%!0("!00"`@(!`0'______?W]^_W_^_O]_/W^_/S]`0#]_P$"`@(#`P(#
+M`P(#`P,#`0`!`@'^_P#__O[]_?[]_/W]^_W^_/W^_O__`/\``P$``P,"`@,#
+M`@("`@$!`@'__@$`_O[^_?W^_OW\_?[\_/S]_O[___\``0$"`@(#`@("`@$!
+M`@'_`0'__P#__O[__OW^_O[]_?[^_?W^_O[_____``$!`@(!`@$!`@$!`0'_
+M``$`__\``/____[^_O[^_O[^_O[]_O_^_____P$!`0$!`0$!`0$!`0``````
+M`/\`_____O___O[^_O___O[^______\``````0$``0$```$``0$`````__\`
+M`/_______________________P#_````````````````````````````____
+M_____________________P#___\`````````````````````````````````
+M``````!#3TU-````$@`!``!#%@`(0`VL1````````$U!4DL````"``!)3E-4
+M````%#P``'\`?P``````````````````05!03````:A39#)A``(`````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````N``````````````````````````````````````
+M```````````````````````````````````````````$"```````"0`C````
+M`````````````'@````$``0```````'\`/___X`````!`0$&455N:71S`/\`
+M`/___OX!`?[^`/____\``/__`/_^____`````0+_!B!S86UP<P`!`@#__@#_
+M_P$``/_^_O\"`/____[_``$`_@```````````/\``````````````"<`+P`/
+M__;_^0`!````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````0````%X````>````%8P*P`$D&VK3#\`J(`?!T)G2&T-
+MZB\.+P9.N@`\4@=P`0M-86=I8R!&;'5T90(```!!249&4V0R80``````````
+M``!!249&4V0R80```````````````````````````````*<]K5D``$4B```!
+MSA`N`!9(@$'MJ;@2,```2('203HS$``0+@`62(!![:FX$C```$B!TD$\,Q`$
+M/@5"!!U\``'_^;Q'7,`2!`H!``'``6=*ND=6P+Q'5L&"+@`4P`$"0``!9Q0_
+M!Q\N__E![@`,(!AG`B\`(%!.D+Q';@1X`6#"0F<?+@`6/P=(;O_Y(%0````:
+M`"D`#P)J`S$`*@`#`FT#/0`I``\"00,B`0`````:`"D`#P%0`?$`*@`#`FT#
+M/0`````````````````:`"P`%@$^`=P`*@`#`FT#/0`````````````````:
+M``````````````````````````````````````$````!>````'@```!6`'&X
+MO!RF````'`!6``!7<W1A``,`"@`!__\````````````"__\````>```````#
+M__\````\```````$__\```!:````````````````````````````````````
+;````````````````````````````````````
+`
+end
diff --git a/sys/share/sounds/mgcharp.uu b/sys/share/sounds/mgcharp.uu
new file mode 100644 (file)
index 0000000..05a9e53
--- /dev/null
@@ -0,0 +1,407 @@
+begin 644 Magic_Harp
+M``I-86=I8R!(87)P````````````````````````````````````````````
+M``````````````````````````!!249&4V0R80$``&@``````````$0B```!
+MSJ<]K4JG/:U2``````````````````````````````"!@8QW``!&3U)-``!$
+M&D%)1D934TY$``!"'@``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M___________________________________________________^_O[^_OW]
+M_?S\_/S\^_CW]_?X]_7T]/;Z_?[_``$"`@(!`/[[^?CX^P`"`@("`@("`@("
+M`@,!^.*]H)V@GZ.GK+*VNKJWN+:MFX:`B(R.CXJ#BIFGL[BZOL/(SM/:WN'@
+MU='9X>ST]?7V^?X%"0L-$!(2$A$0#PT*"`@)#1$1$1`0$!`0$!`0#P\/"?KC
+MTL_.SM#3UMK>X-_>W]W5P["IJJNLK*:CK+C#S-#2U=K>X^?K[O#LXN+K]/X#
+M`@(#!@P2%1<9&QT='1P;&1<5%!,5&1L;&QL;&QH:&AH:&AD8$P+LW]S:VMS?
+MX^;IZ^KIZNC>R[NWN+BXM[&QN\;1V-K=X>7I[?'U]_CRZN[W_P@+"@L,#Q4:
+M'!XA(R0D)",B(!X<&QL>(B(B(B(A(2$A(2`@("`@&@?RY^7CX^3GZ^[Q\O+Q
+M\O#DT,/!P,#`OKBZQ=#:X.+EZ.SP]/C[_?SU\??_"`\0$!`2%1H?(2,E)RDI
+M*"@F)"(A("`C)B8F)B8F)24E)24D)"0D'@SW[>KHZ.KL\//V]_;V]_;IU<K(
+MQL;&P[W`R]7?Y>?J[?'T^/S_`/[W]?P$#1,3$Q,5&1XB)"8H*BPL*RLI)R4D
+M(R0G*2DI*2DH*"@H*"<G)R<G(A'\\N_LZ^WO\O;Y^OGY^OKMV<[,RLK*QL'$
+MSMCBZ.KM\//W^_X!`O_X^/\&#Q45%147&B`C)2<I*RTN+2TK*2<F)28I*RLK
+M*RHJ*BHJ*2DI*2@H)18`]O/O[N_Q]/CZ_/S\_/SPW=+0S<S+R,+%T-GCZ>ON
+M\O7Y_/\!`P'Y^0$($1<6%A<8&R`D)B@J+"XO+RXM*RDG)B<K+2PL+"PL*RLK
+M*RHJ*BHI*!L%^O7Q[^_Q]?C[_/S]_?WSX-72S\W,R</%S]CBZ>SO\O;Y_/\"
+M`P#Y^0$)$1<7%Q<8&R`D)B@J+"XP+R\M*RDH)R@K+2TM+"PL+"PK*RLK*BHI
+M*2`,_?CS\/#Q\_?Z_/W]_?[UX]?4T,[-R\7$S=;@Z.ON\O7X_/X``?_X^``)
+M$1<7%Q<8&A\C)B<I*RTO+R\M+"HH)R@K+2TM+"PL+"LK*RLJ*BHJ*2,2`OKU
+M\>_P\O7Y^_S\_/WWYMG4T,W,RL7"R=/<Y>KL\//V^OS^`/[W]?X'#Q87%A87
+M&1TB)"8H*BPN+R\M+"HH)R<J+2TL+"PL*RLK*RHJ*BHJ*289"/WX\N_O\//V
+M^?O[_/SXZ]S6TLW+RL;`Q,[7X>CJ[O'U^/K\_OWW\_D$#146%A86%QH?(R4G
+M*2LM+RXM+"HH)R<I+"PL+"PK*RLK*BHJ*BDI*2<?#P'[]?#N[O#T]_GZ^OOY
+M[^'9U,_,RL?!P,K3W.7I[._S]OCZ_/SW\?8`"1(6%145%A@=(2,E)RDK+2XM
+M+"HH)R8H*RPL*RLK*RHJ*BHI*2DI*2@C%PG_^/+O[>[Q]/?X^?KY\N7<U]',
+MRLC"O<3-UN#FZ>WP\_;X^OKX\/'Z!`X5%!04%!89'B$C)2<I*RTM+"HH)R8F
+M*2LK*RHJ*BHI*2DI*"@H*"<E'0\$_?7P[>WN\/3V]_?X].G>V=/.RL?$OKW&
+MS]CBY^KN\?3V^/CW\.WT_@@2%!,3$Q06&Q\A(R4G*2LL+"HH)B4E)RHJ*BHI
+M*2DI*"@H*"<G)R8F(A8*`OOS[^SL[?#S]?7V]>SBW-;0R\?%P+N^R-#;X^;J
+M[?#S]?;U\>KM]P`+$A(2$A(3%AL>("(D)B@J*RHH)B4D)2@I*2DH*"@H)R<G
+M)B8F)B8E)!T0!P'Y\>WKZNSO\?/S]/#EW]O4SLK&P[RYP,G2W>/FZ>WP\O3T
+M\NSH\/D##A$1$1$1$Q8;'A\A(R4G*2HH)B4D(R4H*"@H)R<G)R8F)B4E)24E
+M)"(9"P4`]_#LZNKK[O#R\O+JX-[:TLW(Q,"YN,+*U-[CYNKM[_'R\N[GZ/+[
+M!@\0$!`0$!(7&QT?(2,E)R@H)R4D(R,F)R<G)R8F)B8E)24E)"0D)",?$P<$
+M_O7OZ^GIZ^WO\/'OY=[>V-#+QL*[M;G"R];>XN;I[._Q\?#JY>KT_0@.#P\.
+M#Q`3%QH<'B`B)"8G)R8D(R(C)B<F)B8F)24E)20D)"0C(R,A&0P%`_SS[>KH
+MZ>OM[N_P[.'=WMC0RL2_MK.[Q,W8WN'EZ.SN[_#NY^/K]?X)#0T-#0T/$Q<9
+M&QT?(2,E)R<E(R(B(R4F)B4E)24D)"0C(R,C(B(A'1$%!`'X\>OHZ.CJ[.WN
+M[^K?W=[8T,G"N;&TOL;0V=S@Y.CK[>_O[.3C[/7_"0P+"PL,#Q,6&!H<'A\A
+M(R4E)"(A(2,E)20D)"0C(R,C(B(B(B$A'Q<)`P/^].[IY^?HZNOL[N_IW]W?
+MVM#'OK*ON,'*T]?;X.3HZ^WO[NOCX^WV``D*"@H*#!`3%1<8&AP>("(D)",B
+M(2$B)"0D)",C(R,B(B(B(2$A'QH-`P,!^?+LZ.?GZ.GJ[>_PZ=_>X-K/Q;>N
+ML[S$SM/6V^#DZ.OM[^[JX^/N]P`("0@("@T1$Q06&!D;'1\A(R0C(2`A(R0D
+M(R,C(R(B(B(A(2$A'QP1!`(#_O7NZN?GZ.GIZ^[P\.C?W^#:SK^RL;G`RL_2
+MUMO@Y.CL[N_NZ>+E\/@""`<'"`H.$1(4%1<9&QT?(2(C(B$@(2,D(R,C(R(B
+M(B(A(2$A(!T3!@$#`/GQ[.CGY^CHZNWP\O'GW]_?V,FXL[B^Q\W/TM?;X.7I
+M[.[O[>?BZ/+Z`P<&!@D,#Q`1$Q46&!H<'B`B(R(A("$C(R,C(B(B(B$A(2$@
+M(!T5"`("`?SU[>GGY^?GZ>SO\O3PY=[>W-+`M[J^Q<O-S]+7W.'FZNWO[^WF
+MX^OT_00%!0<*#0X/$1(4%A@:'!X@(2(A("`A(R,B(B(B(2$A(2`@'QT6"`$"
+M`O[W[^OHY^?GY^KN\?3U[>'=W-7'O;W`Q<O,S<_4V-[CY^ON\._KY.7O]_\$
+M!`8)#`T.#Q$2%!88&1L='R$A(2`@(B,B(B(B(2$A("`@'QT5"`$"`O_Y\>SI
+MY^?FY^KM\?7V].C>V];+Q<3$R,S,S,[1U=K@Y>KN\/#OZ./J\_H!!`4)"@L-
+M#@\1$A06&!H<'A\@(2`@(2(B(B(B(2$A(2`@'QT5!P$"`@#[\^WJZ.?FY^KM
+M\?7X]_#BV]7+R<S+S<[-S<W/T]C=X^CL[_'Q[>7F[_?]`P8("@L,#0X0$1,4
+M%A@:'!X?("$@("(B(B(B(2$A(2`@'QP2!@$"`@'\]._KZ.?FY^KM\?7X^?7G
+MV]/+S-+2TM+/SL[.T=;;X>;K[_'R\.GE[/3[`@8("0H+#`T.$!$3%1<8&AP>
+M'R`@("$B(B(B(2$A(2`@'QL/`P("`@']]>_KZ>?FY^KN\O;Y^O?KV]#*SM;8
+MV-71S\[.T-39W^7J[O'S\NWFZ?+X``<("`D*"PP-#Q`2$Q47&1L='A\@("`B
+M(B(A(2$A("`@'A@,`@("`@']]O#KZ>?FY^KN\O;Y^OCNW,[,TMC=WMC3T<_.
+MT-/8W>/H[?'S\^_GY_#W_P8'!P@)"@L,#@\1$A06&!H;'1X?'R`B(B$A(2$A
+M("`?'14(`@,"`0']]O#LZ>?FZ.OO\_?Y^OGPW<S.U=KAX]S7T]'0T-+7W.+H
+M[?'T]/'IY^_W_@8'!P@)"@L,#0X0$1,5%QD:'!T>'R`A(B$A(2$@("`>&Q$%
+M`@,"`@+]]O#LZ>?GZ>SP]/CZ^_GPW,S1V=WDYN#:UM/1T=/7W.'G[?'T]?/K
+MZ._W_@8(!P@)"@H+#0X/$1(4%A@:&QP>'R`A(B(A(2$A("`>&`L#!`0"`@+\
+M]O#LZ>?HZNWQ]?G[^_CNVL_5W.'FYN/>V-73T=/7W.'H[?'U]O3MZ?#X_P8(
+M!P@)"0H+#`X/$!(4%1<9&QP='B`A(B(A(2$A(!\<$@8#!`0#`P'\]/#LZ.?I
+MZ^_S]_K\^_;KV=/9W^7GY^7@VM?4TM37W.'H[?'U]O3MZO'Y``8'!P@("0H+
+M#`T.$!$3%1<8&AL<'B`A(B$A(2$@'QT7"P0$!`,#`P'Z\^_KZ.CJ[?'U^/K[
+M^?/FVMC=Y.?GZ.CCW=G6U-37W.+G[?+U]O3NZ_/Z``8'!P@("0H*"PT.#Q$2
+M%!88&1L<'1\A(2$A(2$@'AL0!00%!`,#`__X\NWJZ.GL[_/W^OO[]^WEX-WA
+MZ.CHZ>GFX-O7U=;8W>/H[O/V]_7N[?7\`08'!P@("0D*"PT.#Q$2%!87&1H;
+M'1\A(2$A(2$?'!0(!`4%!`,#`OWV\>SIZ>ON\O;Y^_OY\NKHX^#GZNCHZ>KG
+MXMW9U]?:W^3I[_7W^/7O\/C]`@<("`@("0H+"PT.#Q$2%!87&1H;'1\B(B$A
+M(2`=%PL%!@8$!`0$`?KT[NOJZ^WQ]?G[^_KU[>WMYN;JZ>GIZNOIX]_;V-G<
+MX.7K\?7W^/7P\OK_!`@("`@("0H+#`T.#Q$2%!87&1H;'2`B(B$A(!X8#04&
+M!@4%!`4#_?;Q[.KK[?#T^/K\^_;O[O/OZ>GJZNKJZ^SJY>#<VMO=XN?M\O;X
+M^/7Q]?P!!@@("`@)"0H+#`T.#Q$2%!87&1H;'2`B(B$@'AH/!@<'!04%!04!
+M^O/NZ^OM[_/W^?OZ]O#O]?7OZNKKZ^KK[.WKY>#=V]S?Y.KO]/?Y^?3R^?\#
+M!P@("`@)"0H+#`T.#Q$2%!87&!H;'B`A(2`>&@\&!P<&!04%!0/\]>_L[.WO
+M\_;Y^_OW\/'W^O?OZNOKZ^OL[>_LYN#=W=[AY^SQ]?CZ^//U_0`%"`@("`@)
+M"0H+#`T.#Q$2%!87&1H<'R$A(!X:#P<'"`8&!04&!/[W\>[L[>_R]OGZ^O?P
+M\OG\_/;LZ^SL[.SM[_#LYN'?W^'EZN[S]_K[]?+Y``0("`@("`D)"@H+#`T/
+M$!$3%188&1L='R(A'AD.!P@(!P8&!@8%`/CS[^WN\//V^?KZ]_'S^_[__/#K
+M[>WL[>WN\/'LYN+@X>/G[?+V^OSY\_?^`@<)"`@("0D)"@L,#0X/$1(4%1<8
+M&AP>("`>&`T'"0D'!P8&!P8"^O3P[N[P\_;X^OKV\?3\_P(`]>SL[>WM[>[P
+M\O#JY>+BX^;K\/7Y_/OU]?P"!@D)"`@)"0D*"@L,#0X0$1,4%A@9&AT?(!X8
+M#0<)"0@'!P8'!P3\]?'O[O#R]?CZ^?;R]?T!`P+Y[NSN[>WM[N_Q\N[HY.+C
+MY>GN\_?[^_?T^@$%"0H)"`@)"0D*"PP-#@\0$A,5%A@9&QX?'A@."`D)"`<'
+M!P<'!?_W\_#O\/+U^/GY]O+T_0$#`_SQ[.[N[N[N[_'S\>SGY./EZ.SQ]OK[
+M^/3Y``0("@D("`@)"0H*"PP-#A`1$Q06%Q@:'1X=&A`("0H)"`<'!P<'`OKU
+M\>_P\?3W^?GW\O3]`0,$_O+L[N[N[N[O\/+S[^GEY.3GZ_#T^/KY]/@`!`@*
+M"0D)"0D)"@H+#`T.#Q$2%!47&!H<'1T:$0D)"@D("`<'!P@%_O?S\?#Q\_;X
+M^??S\_L!!`7_].WN[^[N[N_P\O3QZ^?EY.;J[O/W^?GU]P`%"`L*"0D)"0D*
+M"@L,#0X/$!(3%1<8&AP>'1P4"PD+"@D(!P<("`<#^_;R\?'S]??X^/3R^0$$
+M!0'W[N[O[^[N[_#Q\_/NZ.;EYNCL\?3W^/7V_P4("PL*"0D)"0H*"PP-#@\0
+M$1,4%A<9&QT='!@."0L+"@D("`@("`8`^?7R\?+T]OCX]?+W``,$`_GO[N_O
+M[N[N[_'R]/#JY^7EY^KN\O7V]/;^!0@,"PH*"0D)"0H*"PP-#@\1$A05%A@:
+M'!T=&A()"@L*"0@("`@("`3^^/3R\O/U]O?V\O/\`@,#_/'M[^_N[N[O\/'S
+M\NWHY>3FZ.SP\_7T]/L#!PL,"PH)"0D)"@H+#`P.#Q`1$Q06%QD;'1T;%@P)
+M"PL*"0@("`@("`/[]_3R\O3V]_?T\O@!`P0`]>[O[^[N[N[O\/+S\>OGY>7G
+MZNWQ\_/R^`('"@T,"@H*"0D*"@L+#`T.#Q$2%!46&!H<'1P:$@H*#`L*"0@(
+M"`@(!P'[]_/R\_3U]O7R\_P#`P/Z\._P[^[N[N_P\?/S[^GFY>7HZ^[Q\O'S
+M_@8)#0T,"PH*"@H*"@L,#0X/$!(3%!87&1L='1P8#@H,#`H*"0@("0D)!P'[
+M]_3S\_3U]O3Q]@`#`__T[_#P[N[N[N_P\?/R[>GFY>;H[._Q\/#W`P@,#@T,
+M"PH*"@H*"PL,#0X/$1(3%188&AP='!L5#`H,#`L*"0D)"0D)!P'[]_3S\_3U
+M]?+Q^0$#`OOQ\/'O[N[M[N_P\?+Q[.?EY>;HZ^[O[O#\!@H.#@T,"PH*"@H+
+M"PP,#0X0$1(4%1<9&QT='!H2"@L-#`L*"0D)"0D)!P+[]_3S\_3T\_#R_`("
+M`/?O\?'O[NWM[N_P\?+PZ^?EY>;HZ^WM[?,`"`P.#@T,"PH*"@H+"PP-#@\0
+M$1,4%A<9&QT=&Q@0"@P-#`L*"0D)"0D)!P+[]_3S\_3T\N_T_@("_O/O\?#O
+M[NWM[N_P\/+P[.?EY>;HZNSK[/8""0T/#@T,"PH*"@H+"PP-#@\0$1,4%A@9
+M&QT<&A<."@T-#`L*"0D)"0D)"`/\^/7T\_/S\>_U_P(!_/+P\O#O[NWM[N_P
+M\/+Q[.CFY>;HZNOJ[/D$"@\/#@T,"PL+"PL+#`P-#@\0$1,5%A@:'!T<&A4-
+M"PX-#`L*"0D)"0D)"03^^?;T]//S\>_W``$!^O'Q\O#O[NWM[N_O\/+Q[.CF
+MY>7GZ>GH[?H%"@\0#PX-#`L+"PL+#`P-#@\0$A,5%A@:'!T<&A4-"PX.#`L*
+M"@D)"@D)"08`^O?U]//R\._W_P$`^?'Q\O#O[NWM[N[O\/'R[NGFY>7FZ.CG
+M[/D$"Q`0#PX-#`L+"PL+#`P-#@\0$A,4%A@:&QT;&14."PX.#`L*"@H*"@H)
+M"0<"_/CU]//R[^[V_P$`^/#Q\O#O[>WM[>[O[_#R[^KGY>7FY^?FZ_D#"@\0
+M#PX-#`L+"PL+"PP-#@\0$1(4%A<9&QT;&14-"PX.#0P*"@H*"@H)"0D%_OKW
+M]?/R[^WT_0#_^/'R\_'O[>WM[>[N[_#R\.OHYN7EYN;EZO@""0\0#P\-#0P+
+M"PL+"PP-#0X0$1(4%1<9&AP<&A8/"PX.#0P+"@H*"@H)"0H(`OSX]O3R[^WR
+M_/__^/'R\_'O[NWM[>WN[_#Q\>WHYN7EY>7CZ/8!!PT0$`\.#0P+"PL+"PP,
+M#0X/$!(3%188&AP<&A<0"PT/#@P+"@H*"@H*"0H*!?_[]_7S\.WP^?[^^?+R
+M]/+P[NWM[>WN[^_P\O#KZ.;EY>3BYO/^!@P0$`\/#@T,"PL+#`P,#0X/$!$3
+M%!87&1L<&A@2#`P/#@T,"PH*"@H*"@H*"`/^^O;T\>[N]OS]^?/R]//Q[^[M
+M[>WN[N_P\?'MZ>?EY./BY._\`PH.$!`/#@T,"PL+"PP,#0T.#Q$2$Q47&!H<
+M&A@4#0L.#@T,"PH*"@H*"@H*"@<!_/GU\^_M\OK]^O3Q]/3R\.[M[>WM[N[O
+M\/+PZ^CFY./AX>KX``<,#@\/#@T,#`L+"PL,#`T.#Q`1$A05%QD;&A@6$`L-
+M#@T,"PH*"0H*"0D)"@H&`/SX]/'M[O;[^O7Q\_3R\>_M[>WM[>[N[_'R[NKG
+MY>/AX.7S_0,)#`X/#PX-#`L+"PL+#`P-#@\0$1,4%A@:&QD7$PP+#@X-#`L*
+M"@H*"@D)"@L*!?_[]_/O[?#X^O;Q\O3S\O#N[>WM[>[N[_#R\>WIYN3BW^'L
+M^``&"PT/#PX-#0P+"PL+#`P-#0X/$!(3%188&AH8%@\*#`\.#0P+"@H*"@H*
+M"@H+"@7_^O;R[NWS^?CS\?3U\_'P[NWM[>[N[N_Q\_'LZ.;CX-_E\OP""`L-
+M#P\.#0P,"PL+"PP,#0T.$!$2%!47&1H9%Q0-"@X/#@T+"@H*"@H*"@H*"PH%
+M__KV\>WN]?GU\?+U]/+Q[^[N[N[N[N_P\O/P[.CEXM[@Z_;]!`D+#0\/#@T,
+M"PL+"PL,#`T.#Q`1$A05%QD:&!81"PL/#PT,"PH*"@H*"0D*"@P*!?_Z]?#M
+M[_;W\O#S]?3R\>_N[N[M[N[O\/+S\.OGY.#=XN_Y_P4("PT/#PX-#`L+"PL+
+M#`P-#@\0$1(4%1<9&!84#@D,#PX-#`L*"@H)"0D)"@H,"@3^^?3O[?+W]?#Q
+M]/3S\O#O[N[N[N[N[_#R\_#KY^/?WN;R^@`&"`L-#PX-#0P+"PL+"PL,#0T.
+M$!$2%!47&!84$0H(#0\.#0L*"@H*"@D)"0H+#`H$_OCR[N_U^/3P\O7T\_+P
+M[N[N[>[N[N_Q\_3Q[.?CW]_I]/L!!@D+#0\.#0P,"PL+"PL+#`P-#@\0$A,5
+M%Q84$@P'"0X.#0P+"@H*"@D)"0H*"PP(`OSV\._T^?GT\/+U]//R\._N[N[N
+M[N_P\?/U\NWHY.#AZ_;\`@<)#`X/#@T-#`L+"PL+"PP,#0X/$!(3%184$@X'
+M!@L.#@T,"PH*"@H*"@H*"PT,!P#Z\^_S^OOZ]/#S]?3S\?#O[N[N[N[O\/'T
+M]O3NZ>7@XN[W_0,'"@P/#PX.#0P+"PL+"PL,#`T.#Q`1$Q04$0X(`P<+#`T,
+M"PH*"@H*"@H*"PP-"P3^]_'R^OW]_/3P]/7T\_'O[N[N[N[N[_#R]/;U\.OE
+MX>3O^/X$"`H-#P\.#@T,"PL*"@L+"PP-#0X0$1,2$`X(`@0)"@L,"PL*"@H*
+M"@H*"@L,#0D!^O/P^/____ST\?3U]/+P[^[N[>[N[N_P\O3W]O'LYN+G\OK_
+M!0@+#@\/#@T,#`L*"@H*"@L+#`T.#Q$1#@P(`0$&"`D*"PL*"@H*"@H*"@L,
+M#0L$_?;Q]_\"`0#Z\O+U]?3R\._N[N[N[N_P\?/U]_CS[>?DZO7\`08)#`X/
+M#PX-#0P+"@H*"@H+"PP-#A`0#@L'`/\#!@<("0H+"@H*"@H*"@L,#@T'`/CS
+M]OX#!`+_^/'S]?7S\?#N[N[N[N_O\/+T]OCX\^WGYN_X_@,'"PT.#PX.#0P,
+M"PH*"@H*"PL,#0X/#0H'`/T"!08'!PD*"PL+"@H*"@L,#0X+`_KT]_X#!@4!
+M_?;Q]/;T\_'O[N[N[N_O\/'S]??Z^?3MY^KT^P`%"0P.#@\.#@T,"PL*"@H*
+M"@L+#`T-"PD%_OL``P0%!@<("@L+"PH*"@L,#0X+!/OU^/\#!@<#`/KS\O7U
+M\_'P[N[N[N[O\/#R]/;Y^_GS[.GO^?X#"`L-#@X.#@T-#`L*"@H*"@H*"PP-
+M"@<#_/K_`@(#!`4'"0H+"PL*"PL,#0X,!?SV^0`#!@@%`O[V\?3U]/+P[^[N
+M[N[O[_#Q\_7X^OSY\NSM]OT"!@D,#0T.#@X-#`L*"@D)"0H*"@L+"`4!^OG^
+M``$!`@,%!PD+"PL*"PL,#0X,!OWX_`($!PD'`P#Z\_+U]//Q[^[N[N[O[_#Q
+M\_7W^?S\]_#M]/P`!0@+#0T-#@X-#0P+"@H)"0D*"@L*!@/^^/G]_P```0($
+M!@@*"PL+"PP,#0X,!OWY_P0%!P@(!0+]]?'T]?/R\.[N[N[O\/#Q\O3W^?O]
+M_/7O\_L`!`@*"PP-#0X-#0P+"PH)"0D)"@H(!`'[]OG]_O__``$#!0<)"PL+
+M"PP-#0X-!?W\`04&"`@)!P/_]_+S]?3R\._N[N[O\/#Q\_3V^?O]_OKS\_L`
+M`P@*"PP,#0T-#0P+"PH)"0D)"0D&`__X]?G\_?[^_P`"!`8("@L+"PP-#0T,
+M!?[_!`8'"`@)!P,`^O+R]?3R\>_N[N_O\/'R\_3V^?O]__WV]/L!!`<*"@L,
+M#`T-#0P+"PH)"0D)"0@$`?SU]OK\_/S]_O\!`P4'"0H+"PP-#0T+`_\"!P<(
+M"`@)"`0!^_/R]?3R\?#O[N_O\/'R\_3V^/O]___Y]OL"!`<)"0H+#`P,#`P+
+M"PH)"0@("`4!_OCS]OO[^_O\_?X``@0&"`H+"PP,#0T)`P$&"`<(!P<)"`0!
+M^_3R]/3S\?#O[^_O\/'R\_3V^/O]_P#\^/T#!0@)"0D*"PP,#`P+"PH)"0@(
+M!P/_^_3T^/KZ^OO[_/[_`0,%!PD+"PP-#`P(`P4)"`@(!P@)"`0!^_3R]/3S
+M\?#O[^_P\/'R\_7W^?O]_P'^^OX$!@@)"0D*"@L+#`L+"@H)"`@(!`#]]O+U
+M^?GZ^OK[_/W_`0,%!PD+#`P,#`H&!0D*"0@'!P@)"`0!^_3R]?3S\O#P\/#P
+M\?+S]/7W^?S^``'__0$&"`D*"0D)"@L+"PL+"@H)"`@&`?[Y\_/W^?GY^?GZ
+M^_W_`0,$!@D+#`P,#`D&"0L*"0@'!P@)"`0!^_3R]?3S\O'P\/#Q\?+S]/;X
+M^OS^``$`_P,("0H)"`@)"0H+"PL+"@H("`<#_OOT\O;X^/CX^/GZ^_W_``($
+M!@@+#`P+"@D*#`L)"`<'!P@)"`,`^O/R]?3S\O'P\/'Q\O/T]??Y^_W_`0$"
+M`@8*"@H)"`@("0H*"PL*"@D)"`3_^_7Q]/?X]_?W^/CZ^_W_``($!@@+#`L*
+M"0L.#0L)"`<'!P@)!P+_^/+S]?3S\O'P\?'R\_3U]O?Y^_X``0("!`D,#`L)
+M"`@("0D*"@H*"0D(!0#\]_'S]_?W]_;W]_CZ^_W^``($!@@*"PH*#`\.#`H(
+M!P<'"`D)!@'^]_+T]?3S\O'Q\?+S]/3V]_CZ_/\!`@($"`T.#`H(!P<("`D)
+M"@H*"0D&`?WX\O/V]_?V]O;V]_GZ_/W^``($!@@*"@D,$!`-"P@'!P<'"`D(
+M!`#[]/+U]?3S\O+R\O+S]/7V^/G[_@`!`@,&#`\.#`H(!P<'"`D)"0D)"08!
+M_?CR\O;W]_;V]?;W^/G[_/W_``,%!PD)"0T2$0X,"0<'!P<("`D&`O[X\_/U
+M]?3S\O+R\_/T]?;W^?O]_P$"`P0*$!$.#`D'!P<'"`@)"0D)!@']^//S]O?V
+M]O7U]?;W^/K[_/W_`0,%!P@)#1,3#PP)"`<&!P<("`@$`/OU\O3U]?3S\O+S
+M\_3U]O?X^OS^``(#`P8.$Q$."PD'!P<'"`@("0D&`?WX\_/V]_;V]?7U]?;W
+M^?K[_/[_`0,%!@@.%!,0#0H'!@8&!P<("`4!_OCS\_;U]?3S\_/S]/7V]_CZ
+M^_W_`0,#!`L3$P\-"@@&!@8'!P@("`4`_?CS]/?W]O;U]/3U]O?X^?K[_?X`
+M`@,$!@X5%!`-"@@&!@8&!P<(!P+^^_7S]?;U]?3S\_3T]?;W^/G[_?\``@,$
+M"!$5$@X+"0<&!@8&!P<(!0#]^/3U^/?W]O7U]?7V]_CY^?K\_?\!`@,%#!45
+M$0X*"`8&!@8&!P<'!/_\]O/U]O;U]?3T]/3U]O?X^?O\_@`!`P,%#144$`T)
+M!P8&!@8&!P<%`/WX]/7X^/?V]?7U]?;W^/CY^OO]_@`!`@0+%!82#PL(!P8%
+M!@8'!P<%`?WX]/3W]_;U]/3T]/7V]_CY^OS]_P$"`P0+%!42#PL(!P8%!@8&
+M!P4!_OGU]?CX^/?V]?7U]?;W^/GZ^_S^_P$"`PD2%A00#`D'!@4%!@8&!P4!
+M_OKT]/?W]O;U]/3U]?;W^/GZ^_W^``$"`P@2%A,0#`D'!@4%!08&!0'^^_;U
+M^/GX]_;U]?7V]O?X^?GZ_/W_``$"!P\6%1$-"0<&!04%!08&!0'^^O7T]_?W
+M]O7U]/7U]O?X^/GZ_/[_``$"!P\5%!$-"0<&!04%!08%`O[[]_7X^?CW]_;U
+M]?7V]_CX^?K[_/[_``$%#!06$P\+"`8%!04%!08%`?[[]O7W^/?V]?7U]?7V
+M]_CX^?K[_?X``0(%#105$@X*"`8%!04%!08#__WY]??Y^?CW]O;V]O;W^/GY
+M^OO\_?\``0,)$145$0T)!P8%!`0%!04"__SW]??X^/?V]?7U]?;W]_CY^?O\
+M_?\``0,*$A43#PL)!P4$!`4%!00`_?KW]_GZ^?CW]O;V]O?X^?GY^OO]_O\`
+M`@8.$Q43#PL(!@4$!`0%!0/__?GU]_GX^/?V]?7U]O?W^/CY^OO]_O\``@@/
+M%!01#0H(!@4$!`4%!0+^_/CV^?KZ^?CW]_;V]_CY^?GZ^_S]_P`!!`H1%101
+M#0H(!@4$!`0%!`#^^O?W^?GX]_;V]?7V]O?X^/GY^OS]_O\`!`L1%!,/#`D'
+M!00$!`4%!`#]^O?W^OKZ^?CW]_;W]_CY^?K[^_W^_P`!!0T2%!00#`D'!00$
+M!`0$`?[\^/;X^?GX]_;V]?;V]_?X^/GZ^_S]_O\""`X2%!(."@@&!00$!`0%
+M`O[\^?;X^_KY^/CW]_?W^/GY^OK[_/W^_P`""`X2%!,/"PD&!00$!`0"__WZ
+M]_?Z^OGX]_;V]O;V]_?X^/GZ^_S]_O\$"Q`2$Q`,"0<%!`0$!`0#`/W[^/?Z
+M^_KY^?CW]_?X^/GY^OK[_/W^_P`#"A`2%!(/"P@&!00$!`,`_OSX]_GZ^OGX
+M]_;V]O;W]_CX^/GZ^_S]_@`&#`\1$@\+"08%!`,$!`0#__WZ]_C[^_KY^?CW
+M]_?X^?GZ^OO[_/W^_P$$"Q`2$Q(."P@&!00#`P+__?OW^/KZ^OGX]_;V]O?W
+M^/CX^?GZ^_S]_@()#0\1$0X+"`8%!`,#!`0!_OSY]_G[^_OZ^?CX^/CX^?KZ
+M^OO\_?[_``$&#1`2$Q(."@@&!00#`P'^_/GW^?O[^OGX]_?V]O?X^/CX^?GZ
+M^_S]_P,*#0\1$0X*"`8$!`,#!`0!_OSY^/K\^_OZ^?CX^/CY^?KZ^OO\_?[^
+M_P$'#1`1$A$."@@&!`,#`P#]^_CW^?O[^OGX]_?W]_?X^/CX^?GZ^_S]_P0*
+M#0\0$`X+"`8$`P,#`P,`_?SY^/K\^_OZ^?CX^/CY^?KZ^OO\_/W^_P((#0\1
+M$A$."P@&!`,#`O_]^_CW^OO[^OGX]_?W]_?X^/CX^?GZ^_S]_P4+#0X0$`X*
+M"`8$`P,#`P+__?OY^/K\^_OZ^?CX^/CY^?KZ^OO[_/W^_P('#0\0$1$/"P@&
+M!00#`O[\^_CX^OO[^OGX]_?W]_CX^/CX^?GZ^_S]``4*#`X/#PX+"`8$`P,#
+M`P+__?OY^/O\^_OZ^?CX^/CY^?KZ^OO[_/W^_P$&#`X0$1$/#`D'!00#`O[\
+M^OCX^_S[^OGX^/?W]_CX^/CX^?GZ^_S]``4*#`T.#PX,"08%!`,#`P+__?OY
+M^/O\_/OZ^?GX^/CY^OKZ^OO[_/W^_P$&"PX/$!$0#0H(!@0#`O[\^OCX^_S[
+M^_KY^/?W]_CX^/CX^?GZ^_O\_P0)#`T.#PX,"0<%!`,#`P,`_?SZ^/K\_/OZ
+M^OGY^/CY^OKZ^OO[_/W^_@`%"@T/$!`0#@L(!@0#`O[\^OCX^_S\^_KY^/CW
+M]_CX^/CX^?GZ^OO\_P0)"PP-#@X,"@@&!`,#`P,`_?SZ^/K\_/S[^OGY^/CY
+M^OKZ^OK[_/S]_@`$"0P.#Q`0#PT*!P4$`O[\^OCX^OS\^_KY^/CW]_CX^/CX
+M^/GY^OO[_@,("@L,#0X-"P@&!`,#`@(!_OS[^?G[_/S[^OGY^/CY^?KZ^OK[
+M^_S]_O\"!PL-#@\0$`X+"`8$`__\^_CW^OS\^_KZ^?CX^/CX^/CX^/GY^OK[
+M_0('"0L+#`X.#`D'!00#`P,"__S[^?G[_/S[^_KY^?GY^?KZ^OK[^_S\_?X`
+M!0H,#@\/#P\-"@<%!`#]^_GW^?S\^_OZ^?CX^/CX^/CX^/CY^?K[_``%"`H+
+M#`P-#`H(!@0#`P("`/W\^OGZ_/S\^_KZ^?GY^?KZ^OKZ^_S\_?[_`@@+#0X/
+M#P\.#`D'!0+^_/KW^/O\_/OZ^OGX^/CX^/CX^/CY^?KZ^_X#!PD*"PP-#0L)
+M!P4$`P("`?[\^_GY^_W\_/OZ^?GY^?KZ^OKZ^_O\_?W^``4*#`T.#P\/#@L(
+M!@3__/OX^/K\_/O[^OGY^/CX^/CX^/CX^?GZ^_P!!@@)"@L,#0P*"`8%!`,"
+M`@#]_/KY^OS]_/O[^OGY^?GZ^OKZ^OO[_/W^_P('"PP-#@\/#PT*"`8!_?OY
+M]_G[_/S[^OKY^?CX^?CX^/CX^?GY^OO^`P<("0H+"PP+"0@&!`,#`@'__/OZ
+M^?O\_/S[^OKY^?GY^OKZ^OK[^_S]_O\#"`L,#0X/#PX-"@@$`/W[^/CZ_/S[
+M^_KZ^?GX^?GX^/CX^/GY^?K\`04'"`D*"PL,"PD'!00#`@(!_OS[^?K\_?W\
+M^_KZ^?GY^OKZ^OK[^_S\_?X`!0D+#`T.#@X.#0H'`__\^OCY^_S\^_OZ^OGY
+M^?GY^/CX^/GY^?K[_0(&!P@)"@H+#`H(!P4$`P("`/W\^OGZ_?W]_/OZ^OGY
+M^OKZ^OKZ^_O\_?W_`@8*"PP-#@X.#@P*!@+^_/GX^OS\_/O[^OKY^?GY^?GX
+M^/CY^?GZ^_\#!@<("0H*"PL*"`<%!`,"`?[\^_KY^_W]_/S[^OKY^?KZ^OKZ
+M^OO[_/W^_P,("@L,#0X.#@X,"04!_?OX^/K\_/S[^_KZ^?GY^?GY^/CY^?GY
+M^OP`!`8'"`D*"@L+"@D'!00#`@#]_/OY^OS]_?S[^_KZ^?KZ^OKZ^OK[^_S]
+M_@$%"0H+#`P-#@X-"P@$`/W[^/G[_/S\^_OZ^OGY^?GY^?GY^?GY^OO]`04&
+M!P@)"0H+"PH)!P4$`P'^_/OY^?O]_?W\^_KZ^OGZ^OKZ^OKZ^_O\_?\#!PD*
+M"@L,#0T-#`H'`__\^OCY^_S\_/O[^OKY^?GY^?GY^?GY^?K[_0(%!@<("0H*
+M"PP+"0<%!`+__/OZ^?K]_?W\_/OZ^OKZ^OKZ^OKZ^OO[_/X`!0@)"0H+#`P-
+M#0L)!@+^_/KX^?O\_/S[^OKZ^?GZ^OGY^?GY^?KZ^_X"!0<("`D*"@L,#`H'
+M!00!_?SZ^?K\_?W]_/O[^OKZ^OKZ^OKZ^OK[^_S_`P8("`D*"PL,#0P*"`4!
+M_OSZ^/K\_/S\^_OZ^OKZ^OKY^?GY^?KZ^_S_`P8'"`@)"@L+#`P*!P8#__S[
+M^?G[_?W]_/S[^_KZ^OKZ^OKZ^OKZ^_S^`@4'"`@)"@H+#`P+"`8$`/W[^?CZ
+M_?W]_/O[^OKZ^OKZ^OGY^?KZ^_O]``0&!P@)"0H+"PP,"0<$`/W[^?G[_?W]
+M_/S[^_KZ^OKZ^OKZ^?KZ^_O]``0&!P<("0D*"PL+"0<%`__\^_GY^_W]_?S[
+M^_KZ^OKZ^OKY^?KZ^OO\_0$%!P<("0D*"PP,"PD&`O[\^OGZ_/W]_/S[^_OZ
+M^_OZ^OKZ^?KZ^OO]``0%!@<'"`@)"@H+"@@&!`']_/KY^OS]_?S\^_OZ^OKZ
+M^OKZ^?KZ^OO[_/\#!@<("`D*"@L,#`L(`__]^_K[_/W\_/S[^_O[^_OZ^OKZ
+M^OGZ^OO\_P,%!08&!P@("0H*"0@&!`+__/OZ^?O]_?W\_/OZ^OKZ^OKZ^OKZ
+M^OO[_/X!!0<'"`D)"@L,#`L*!0'^^_K[_/S\_/S[^_O[^_O[^OKZ^OGZ^OO\
+M_P,$!04&!@<'"`D)"0@&!0,`_?S[^?K\_?W]_/O[^OKZ^OOZ^OKZ^OO[_/W_
+M`P8'"`@)"@H+"PL*!@+__/O\_?W\_/S[^_O[^_O[^_KZ^OKZ^OO\``,$!`4%
+M!@8'"`@)"0<&!0,!_OS[^OK[_?W]_/S[^_KZ^_OZ^OK[^_O[_/W^`@4'"`@)
+M"0H+"PL*!@,`_?S]_?W\_/S[^_O[^_O[^_KZ^OKZ^OO]``,#!`0%!08&!P<(
+M"`<%!`,"`/W\^_K[_?W]_?S[^_OZ^_O[^_O[^_O[_/S^`00&!P@)"0H*"PL)
+M!@0!_OW^_OW\_/O[^_O[_/S[^_KZ^OKZ^OO]`0,#!`0$!04&!@<'!P8%!`,"
+M`/W\^_KZ_/W]_?S\^_O[^_O[^_O[^_O[_/S]_P,&!P@("0D*"@H(!00"__[_
+M_OW\_/O[^_O[_/S[^_OZ^OKZ^OS^`0(#`P0$!`4%!@8'!P8$`P,"`?[\^_KZ
+M_/W]_?S\^_O[^_O[^_O[^_O\_/W]_P(%!P<("0D*"@D&!00"````__[]_/O[
+M^_O\_/S[^_OZ^OKZ^_S_`@(#`P,$!`0%!08&!@4$`P("`?[\_/KZ_/W]_?W\
+M_/O[^_O[^_O[^_S\_/W]_P(%!P<("`D*"@@%!`,"`0$!__[]_/O[^_S\_/S\
+M^_O[^_K[^_T``@("`P,#!`0%!04&!@0#`@("`?_]_/OZ_/[^_?W\_/O[^_O[
+M^_S[_/S\_/W^_P(%!@<("`D)"0<%!`,"`P(!__[]_/S[^_S\_/S\^_O[^_O[
+M_/\!`@("`@,#`P0$!04%!00#`@(!`?_]_/O[_/[^_?W\_/O[^_O\_/S\_/S\
+M_?W^_P(%!@<("`D)!P4$`P(#!`,!`/[\_/S[_/S\_/S\^_O[^_O\_@`!`@("
+M`@,#`P,$!`4%!`,"`0$!`?_]_/O[_/[^_?W\_/S[^_O\_/S\_/S\_?W^_P(%
+M!P<'"`@(!@0#`@($!0,!`/[]_/S[_/S\_/S\^_O[^_S]_P$!`0("`@(#`P,$
+M!`0$`P(!`0$!`/[]_/O[_/[^_?W\_/S[^_S\_/S\_/S]_?W^``(%!@<'"`@&
+M!`0#`@,%!0,"`/[]_/S\_/S\_/S\^_O[_/W_``$!`0("`@("`P,#!`0#`@$!
+M`````/[]_/O[_?[^_?W\_/O[^_S\_/S\_/W]_?[^``,%!@<'"`8%!`,"`P0%
+M!0,!`/[]_/S\_/S\_/S\_/S\_/X``0$!`0$"`@("`P,#`P,"`0$``````/[]
+M_/O[_?[^_?W]_/S\_/S]_?W]_?W]_O[_`00&!P<'!P4$`P("!`4%!`,!`/[]
+M_?W\_/S\_/S\_/S]_@`!`0$!`0$!`@("`@,#`P,!`0``````__[]_/O\_?[^
+M_?W\_/S\_/W]_?W]_?W]_O[_`00&!@<&!`,#`@($!04$!`,!__[]_?W\_/S\
+M_/S\_/W^``$!`0$!`0$!`@("`@,#`P$!`/___P``__W]_/S\_O[^_?W\_/S\
+M_/W]_?W]_?W^_O\``@4&!@8$`P,"`@,$!`0$`P(`__[^_?W\_/S\_/S\_?X`
+M`0$!`0$!`0$!`0("`@("`0``_____P#__OW]_/S]_O[^_?S\_/S\_?W]_?W]
+M_?[^__\!`P4&!00#`P("`P0$!`0#`P(`__[^_?W\_/S\_/S]_@`!`0$!`0$!
+M`0$!`0("`@(!``#______P#__OW\_/W^_O[]_?W\_/W]_?W]_?W^_O[^_P`"
+M!`4%!`,"`@(#!`0$!`,#`@$`__[^_?S\_/S\_/W^``$!`0$!`0$!`0$!`0$"
+M`@$``/_________^_?W\_/W^_O[]_?W]_?W]_?[^_O[^_O[_``$#!04#`P("
+M`@,$!`0$`P,#`@$`__[]_?S\_/S]_?\``0$!`0```0$!`0$!`0$"`0``____
+M______[]_?S\_?[^_OW]_?W]_?W^_O[^_O[^_O__`0,$!`,"`@("`P0$!`,#
+M`P,"`@$`__[]_?S\_/W]_P`!`0$!`````0$!`0$!`0$!``#___[^______W]
+M_?S]_O[^_OW]_?W]_?[^_O[^_O[^__\``@0$`P("`@(#!`0$`P,#`@("`0#_
+M_OW]_/S\_?W_``$!`0$```````$!`0$!`0$!`/___O[^_____OW]_/S^_O[^
+M_?W]_?W]_O[^_O[^_O[__P`!`P,"`@(!`@,$!`,#`P,"`@("`0#__OW]_/W]
+M_?X``0$!`0````````$!`0$!`0$`___^_O[____^_?W]_?W^_O[^_?W]_?W^
+M_O[^_O[^_O__``$#`P("`@$!`P0$`P,#`P("`@(!`/_^_?W]_?W]_@`!`0$!
+M``````````$!`0$!`0``___^_O____[]_?W]_?[^_O[^_?W]_?[^_O[^_O[^
+M_O__`0(#`@("`0$"`P,#`P,#`@("`@(`__[^_?W]_?W^_P`!`0$`````````
+M``$!`0$!`0#____^_____OW]_?W]_O_^_O[^_?W]_O[^_O[^_O[^__\``@,"
+M`0$!`0(#`P,#`P,"`@("`@$`__[]_?W]_?[_``$!`0````````````$!`0$!
+M``#________^_?W]_?W^__[^_O[^_?W^_O[^_O[^_O[__P`!`P,"`0$!`0(#
+M`P,#`P("`@("`0#__O[]_?W]_O\````````````````````!`0$!``#_____
+M__[]_?W]_?[__O[^_O[^_O[^_O[^_O[^_O[__P$"`P(!`0$!`@,#`P,"`@("
+M`@("`0#__O[]_?W]_O\````````````````````!`0$!`/_______OW]_?W]
+M_O___O[^_O[^_O[^_O[^_O[^_O__``$"`@$!`0$!`@,#`P,"`@("`@(!``#_
+M_O[]_?W^_P`````````````````````!`0$!`/_______OW]_?W]_O___O[^
+M_O[^_O[^_O[^_O[^_O\``0("`0$!`0$!`@,#`P("`@("`@(!`/___O[]_?[^
+M_P`````````````````````!`0$``/_____^_?W]_?W^_____O[^_O[^_O[^
+M_O[^_O[^__\``0("`0$!`0$"`@,#`@("`@("`@(!`/_^_O[^_O[__P``````
+M```````````````!`0$``/_____^_?W]_?[^___^_O[^_O[^_O[^_O[^_O[^
+M__\``@(!`0````$"`@("`@("`@("`@$!`/_^_O[^_O[_````````````````
+M`````````0$``/____[]_?W]_?[____^_O[^_O[^_O[^_O[^_O[__P`!`@(!
+M``````$"`@("`@("`0$!`@$!`/_^_O[^_O[_````````````````````````
+M`0$``/____[]_?W]_?[____^_O[^_O[^_O[^_O[^_O[__P`!`@$!``````$"
+M`@("`@("`0$!`0$``/___O[^_O[_``````````````````````````$```#_
+M__[]_?W]_O_____^_O[^_O[^_O[^_O[^_O[__P`!`0$```````$"`@("`@(!
+M`0$!`0$``/___O[^_O__``````````````````````````$```#___[]_?W]
+M_O_____^_O[^_O[^_O[^_O[^_O___P`!`0$```````$"`@("`@$!`0$!`0$`
+M`/___O[^_O__``````````````````````````````#___[]_?W]_O_____^
+M_O[^_O[^_O[^_O[^_O___P`!`0$```````$"`@("`@$!`0$!`0$!`/___O[^
+M_O__``````````````````````````````#___[]_?W]_O_______O[^_O[_
+M__[^_O[^_O___P`!`0$```````$"`@("`0$!`0$!`0$!`/____[^_O__````
+M``````````````````````````#___[]_?W]_O_______O[^_O[___[^_O[^
+M_O___P`!`0$```````$!`@(!`0$!`0$!`0$!``#___[^_O__````````````
+M````````````````````__[^_?W]_O_______O[^_O_____^_O[^_O___P`!
+M`0$````````!`0$!`0$!`0$!`0$!``#____^_O__````````````````````
+M````````````__[^_OW^_O________[^_O_______O[^_____P```0$`````
+M```!`0$!`0$!`0$!`0$!``#_________````````````````````````````
+M`````/_^_O[^_O____________________[^_____P```0$``````````0$!
+M`0$!`0$!`0$!`0``_________P```````````````````````````````/_^
+M_O[^_O[___________________________\``````````````0$!`0$!`0$!
+M`0$!`0``_________P```````````````````````````````/___O[^_O[_
+M__________________________\```````#__P````$!`0$!`0$!`0$!`0$`
+M`/________\```````````````````````````````#___[^_O[_________
+M__________________\```````#___\````!`0$!`0$!`0$!`0$```#_____
+M__\`````````````````````````````````__[^_O[_________________
+M____________````````____`````0$!`0$!`````0$`````________````
+M````````````````````````````_____O[^________________________
+M____````````_____P````$!`0$!````````````_________P``````````
+M`````````````````````/____[^_____________________________P``
+M`````/____\````!`0$!`````````````/_______P``````````````````
+M``````````````#____^______________________________\``````/__
+M__\```````````````````````#_______\`````````````````````````
+M``````#_____________________________________``````#_____````
+M````````````````````______\`````````````````````````````````
+M____________________________________``````#_____````````````
+M`````````````/______`````````````````````````````````/______
+M_____________________________P``````_____P``````````````````
+M````````____``````````````````````````````````#_____________
+M______________________\`````_____P``````````````````````````
+M``````````````````````````````````````#_____________________
+M________________````______\`````````````````````````````````
+M````__\`````````````````````````____________________________
+M_________P``______\``````````````````````````````````````/__
+M````````````````````````____________________________________
+M_P``______\```````````````````````````````````````#_````````
+M`````````````````/__________________________________________
+M__\```````````````````````````````````````#__P``````````````
+M`````````/____________________________________________\`````
+M````````````````````````````````````__\`````````````````````
+M`/____________________________________________\`````````````
+M````````````````````````````____``````````````````````#_____
+M______________________________________\`````````````````````
+M````````````````````_____P````````````````````#_____________
+M______________________________\`````````````````````````````
+M`````````````/___P````````````````````#_____________________
+M______________________\`````````````````````````````````````
+M`````/___P````````````````````#_____________________________
+M_____________P````````````````````````````````````````````#_
+M_P````````````````````#_____________________________________
+M____````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````$-/34T````2``$``$(6``A`#:Q$````````
+M34%22P````(``$E.4U0````4/```?P!_``````````````````!!4%!,```!
+MJ%-D,F$``@``````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````"D```````````````````
+M````````````````````````````````````````````````````````````
+M``0(```````)`",`````````````````>`````0`!````````/P`____@```
+M``$!``9156YI=',````````````````````````````````````````!`@`&
+M('-A;7!S````````````````````````````````````````````````````
+M````````````)P`O``__]O_Y``$`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````!`````7@```!X````5M8Z*`_>
+MOCO;Q0T.*`5//"BD#RQP.]W&*#P!`?\@1-@4"DUA9VEC($AA<G```@```$%)
+M1D939#)A`````````````$%)1D939#)A````````````````````````````
+M````ISVM2@``1"(```'.@P'O,@T'MJ@*OB@%_XQ09PT#(`B=_QP%&0PV`AD%
+MWWPQ!H4!,@T&U?\*OB@%C%!G#?\S(`B='`49#/TV`AD%WC$&A@'O,@T.O*@*
+MOB@%_XQ09PU8(`B=_QP%&0PV`AD%>RQP,4`<!2@+=S'_>0\-!QP%7W?^,7D/
+M#08<!2@-_W<Q>0```!H`*0`/`FH#,0`J``,";0,]`"D`#P)!`R(!`````!H`
+M*0`/`5`!\0`J``,";0,]`````````````````!H`+``6`3X!W``J``,";0,]
+M`````````````````!H``````````````````````````````````````0``
+M``%X````>````%8`<;B\'*8````<`%8``%=S=&$``P`*``'__P``````````
+M``+__P```!X```````/__P```#P```````3__P```%H`````````````````
+I````````````````````````````````````````````````````````
+`
+end
diff --git a/sys/share/sounds/toolhorn.uu b/sys/share/sounds/toolhorn.uu
new file mode 100644 (file)
index 0000000..3f7f63f
--- /dev/null
@@ -0,0 +1,345 @@
+begin 644 Tooled_Horn
+M``M4;V]L960@2&]R;@``````````````````````````````````````````
+M``````````````````````````!!249&4V0R80$``((`10```````#DB```!
+MSJ<]K0&G/:TS``````````````````````````````"!@1/]``!&3U)-```Y
+M&D%)1D934TY$```W'@````````````````````````````#_____________
+M__________________________\```````````````````````````#_____
+M________```!`@,#!`4%!@8&!@8%!00$`P("`0$``/____________\`````
+M`0$!`@("`P,#`P,#`@("`@("`0$``/___OW]^_KY]_;T\_'P[^_N[^_P\O/V
+M^/O]``0&"`L-#Q`0$!`/#0P+"0@&!`,!`/_^_OW]_?W]_?W]_?[^__\``0$"
+M`P0$!04%!04%!04%!`,#`@$`__[]^_GW]?+P[>OIY^7EY>7GZ>SP]/G]`@8*
+M#A(5%Q@9&!<6%!$/#`H(!@0"`/_]_/S[^_O[^_O[_/S]_?[_``$#`P0$!04&
+M!@<("`D)"`<&!`,!__W[^?;R[NKEX=W;V=?7V=O>X^CN]?L""`X4&1P?(2(A
+M(!X<&183#PP*!P4#`?_^_/OZ^OKZ^OKZ^OO[_/W^``$"`P0%!@<("`D*"PL+
+M"@D(!@4#`?[[^/3OZN7?VM;2S\[/T-/7V^'F[?3[!`P3&B`D*"HJ*B@E(AX;
+M%Q,/#`D&`P'__?S[^OKZ^?GY^OK[_/W^``$"`P,$!`4&!P@)"0H*"@D(!P8%
+M`P#]^O;Q[.?AV]71S<G)R<O-T=7;XNGR^P4.%R`G+#`R,C$O*R<C'AD5$0T)
+M!@,`_OS[^OGY^?CX^/GY^OS]_P`!`@(#!`4&!P@)"PP-#0T,"@D(!@0!_OKU
+M\>KCW=?1R\?#P<#"Q,C-U-SE[_H&$1PF+C0X.CHX-3`K)B$;%A(-"04"__W[
+M^OGX]_?W]_?X^/G[_/X``0("`P0%!P@)"@L,#`P+"@D(!P8#`/WX\^WFW]?0
+MR,.^NKBZO,'(T=KE[_L'$AXG,#8Z/#PZ-S,M*"(=&!,/"P<$`/[\^OGX^/?W
+M]_?W^/GZ_/[_``$"!`4&"`D+#0X/$`\.#0L*"`0`_/CS[>;?UL['P+JULK&S
+MMKW%T-SI]P85(BXX/T-%1$(^.#(K)1\9%`\+!P0!_OSZ^?CW]_?W]_CY^?O]
+M_O\``0$"`P0%!P@*"PP-#0T,#`L*"`4!_??RZ^3;T\S$OKBSL*^QM+K"SMOK
+M^PL;*C8_14E*2$0_.#$J(QT7$0T)!0(`_OS[^OGY^?CX^?GZ^_S]_O[__P``
+M`0(#!08'"0H+#`P+"PL*"`4"_OGS[.7<U<S%OKBSL*^QM+K"SMOK_`X>+3E!
+M1TI*2$,]-BXG(!H4#PL(!0(`__[]_/S\^_O[^_S\_?W^_O[^_O[^_O\``0,%
+M!PD*"PP-#0T,"@<$`/SU[N;>U<['P+JTL;"PLK:^R-;G^0L=+3I$2DU-2D4^
+M-R\F'QD3#@H&!`(`__[]_?S\_/S\_/S\_?W^_O[]_?W]_O[_`0($!@@)"0H*
+M"@H)"`8$`?WX\>KCVM/,Q+ZZM[:VN+O"RM7D]`46)3(\1$A)1T,^-R\H(!H4
+M#PL(!0(`__[^_?W]_?S\_/S]_?[^_O[^_O[^_O\``@,%!@<("0H+"PL)"`8#
+M__KT[.7<U<S$OKBSL+"QM+O$T>'S!1<H-D%(3$U+1T`Y,"D@&A0."@8#`0#_
+M_O[]_?W]_?[^_O__``#___[^_O[^_O\!`@0&!P@("0D*"0@'!0/_^O7NY][7
+MS\C`NK6QL+"RMK[*V>K^$2,S0$A.4$]+1#PT*R(;%`\+!P0"`0#___[^_O[^
+M_O[^____``#___[^_?W]_?X``@,%!P@*"PP,"PH(!0+]^/'JX]K3S,2^N+.P
+MK["RM\#-W?`%&2LZ1DY14D]*0SHP)Q\7$0P(!0,!``#___________\```$!
+M`0#___[]_/S\_/[_`0,%!@@)"@L,#`H(!0']^/'JXMO3S,6_N;2QL+"RM\#,
+MW?$&&RT\2$]34U!)0CDO)AT6$`L'!`,!````______[^_O___P```/___O[]
+M_?W]_?X``0,%!@<("0D*"0@'!0/_^O/LY-W5SL;`N[>TL[2VN\/.W>\#%B@W
+M0TM/44Y)0CDP)Q\7$0P(!0,"`0``_____O[^_O[__P````#__O[]_?W]_O\`
+M`@,%!@<'"`D*"@H)!P0`^_3LY=S3S,.\MK*OKJ^RN<32Y/@-(#(_24]244U'
+M/C8L(QL4#@H&!`(!`/_^_O[^_O[^_O__``$!`0#___[^_?W]_O\!`P4'"0H*
+M"PL+"0@&!`#[]>[GWM;-Q;ZWL:VKK*^TOLO;[P4:+#Q'3U-34$I#.C`G'A<1
+M#`@%`P$`___^_O[^_O[^____```!`0#___[]_?W]_@`!`P4'"`@)"@L*"@@&
+M!`#Z].SDW=3,P[RVL*RKK;"UO\S>\PD=+SY*45144$E"."\F'180"P<%`P(!
+M`/___O[^_O[^_O__```!`0#___[]_?W]_@`"!`8'"0H+"PL+"@@'!`#[].WD
+MW-/,P[RVL:ZMK:^TOLO<\0<<+S]*4E5544I"."\E'!40"P<%`P(!`/___O[^
+M_O[^_O[^_P```/___OW]_?W]_@`!`P4&"`D*"@L+"PH)!@/]]^_GWM;-Q;VW
+MLJZLK*ZSO,G:[@09+#Q(4%1544M#.C`G'Q<1#0D&!`(!`/___O[^_O[^_O[^
+M____`/___OW]_?W^_@`!`P4'"`D*"@H+"PH(!0+^^/'HX-?/Q[^XLJ^MKK"V
+MOLO<[P08*CE%35!13DE".3`H'Q@2#@H'!0,!`/_^_O[]_?W]_O[^_O__``#_
+M__[^_?[^_O\!`P4'"0L,#`T,"PH(!0']]N_FW=3+P[NTKJNJJZ^VP,_A]@L?
+M,#Y)3U)13DA`-R\F'A@2#0H'!`(`__[]_?W]_?W]_?W^_O_______OW]_?W^
+M_P`"!`8("@H+"PP+"PD'!0'\]>[EW=3+PKFRK*FHJ:RTP-#C^0\C-4-,4E13
+M3D<_-BTD'181#0D'!0,!`/_^_?W]_?W]_?W^_O_______OW]_/W]_@`"`P4'
+M"0H+#`T-#0P*!P/^]^_FW=3+PKFRK*BFIJFQO,SA^`XC-4--4U543T@_-BTD
+M'!81#0D'!0,!`/_^_?W]_?W]_?W^_O[____^_?S\_/S]_O\``@0&"`H+#`T-
+M#0L)!@/_^O/JXMG0R+^XLJZJJ:JON,;8[@4:+3U(4%-34$E".3`G(!D3#PL)
+M!P0"`?_^_?W]_/S\_/S]_?[^_O_^_OW]_?W]_@`!`@0&"`H+"PP,#`P*"`0`
+M^_7MYMW4R\.\MK&NK:ZQN<33YOL/(C-`24]03TM$.S0L(QT7$@X+"`8$`@#^
+M_?W\_/S\_/S\_/S\_?W]_?W\_/S]_P`"!`8("0L,#`P+"PL*!P0!_/;OY][6
+MSL6^MK&MJZROML'0Y/D.(C-`2E!14$Q%/#4L)!X8$P\,"`8$`?_^_?S\^_O[
+M^_O[_/S\_?W]_?W\_/W]_@`"!`8'"`H+#`P,#`L*!P0!_/?PZ-_6S<2[M:^K
+MJJJMM<#0Y?H/(S1!2U!244Q%/C4M)1\9%!`,"08#`?_^_?S[^_O[^_O[^_S\
+M_/W]_/S\_/S]_@`!`P4'"0H,#`T-#0P+"08#_OCQZN'7SL6\M:^JJ*>JL;S,
+MX?<-(3-!2U%34DU&/S8N)B`:%!`-"@<$`?_^_/S[^_O[^_O\_/S\_?W]_/S[
+M^_O\_?X``@0&"0L,#0X-#0P+"`4"__KSZ^+9T,B_N+&MJJFKL+K)W/$'&RT\
+M2$Y144Y(03@O*"$;%A(."P@&`P'__OW\_/S\^_O[^_O[^_S\_/O[^_O[_?X`
+M`0,%!PD*#`T.#@X-#`D&`O[W\.C?ULW$N[2OJZFHJ[*^T.7[$24V0TQ24U%,
+M13PU+"4>&141#0H'!`'__?S[^_KZ^OKZ^OK[^_S\_/S\^_O[_/[_`0($!@@*
+M#`X.#0T-#`D&`_[Y\NKAV=#(P;NVL:ZMKK*\RMSQ!QLM.T9-4%!-1T`W,"@B
+M'!<3#PL(!0(`_OW\^_KZ^OGY^?GY^OK[^_O[^_S\_?\``@0&"`D+#`T-#0T-
+M"PD'`__Z\^OCVM#'OK>QK*BGJK"[RM[T"AXP/DA/4E%.2$$Y,"DB'!<3#PL'
+M!0'__?S[^OKZ^OKZ^OGY^?GY^?KY^?K[_/X!`P4'"0H+#`P,"PL*"0@%`O_Z
+M].WFW=7,Q+RWL:VKJZZVQ-;K`18I.45-45)/2D,\,RLE'QD5$0T*!@0!_OW[
+M^OGY^?GY^?GY^?GZ^OKZ^OK[_/W_`0,%!PD+#0X.#0T,"PD'!`']]N[GWM7,
+MP[NUKZNHIZJRP-/I`!8J.TA05%113$4]-"PE'AD5$0T)!@,`_OW[^OKZ^OKZ
+M^OKZ^OKZ^OKZ^?GZ^_S^``($!0<("0L,#0X-#0T+"`4!_/7LY-O2R+^XL:NG
+MI:>LM\?<]`LA,T),4E533TA!."\H(AP7$P\+"`0"`/[\^_KY^?GY^?GY^?KZ
+M^_OZ^OKZ^OO]_P$#!`8("@P-#@X.#0P+"`4"_??PY][5S<2\M:^JIJ:JL\'5
+M[`,9+#Q(4%1444M$/#,L)1\9%!`,"`4"__W\^_KZ^?GY^?CX^/CY^?KY^?GY
+M^OO\_@$#!0<("@P-#@X.#@T,"08#_OGRZN'8SL6\M*ZHI*.FK[W1Z0`7*SM(
+M4%154DQ%/30L)1X9%!`,"04"__W[^OGY^?GY^?GY^?KZ^_O[^_KZ^OO\_?\!
+M`P4("@P-#@X/#@T,"@8"_OCQZN'8S\>_N+*LJ*>HK[O,XOD0)#9$3E-44TY'
+M/C<N)R$;%A(."@8#`/[\^_KY^?GX^/CX^/CY^?KZ^OGZ^OO\_@`"!`8'"0L-
+M#0X.#@T-"P@%`?OT[./:T<G`N;*LJ*:GK;C)WO4,(3-"35-44T](03@P*"$<
+M%Q(."P<#`?[\^_KY^?GZ^OGY^?GZ^OKZ^?GX^?K[_/X``@0'"0L,#0X.#0T,
+M"P@%`OWX\>KAV=#'OK>PJJ6CI:Z]T>H#&BX_2E)655)+1#LS*R0>&!00#0D%
+M`O_]^_KY^?GY^?GY^?GZ^OO[^_KZ^OK\_?\``@0%!PD*"PP-#@X.#0H'!/_Y
+M\NOAV,_%O+2MJ*2CIJZ\T.@`%RL\25%555),13TT+"4?&100#`D%`O_]_/KZ
+M^?GY^OKY^?GY^OKZ^OGY^?K[_/X``@0%!PD+#`T-#@X.#0H'!0#Z\^SBV=#'
+MOK>OJJ:DIZZ[SN3\$R<X1D]455)-1C\V+28@&A41#0D&`P#]^_KY^?GY^?GY
+M^?GY^?KZ^OGY^?GZ_/X``@,%!PD,#0X/$`\/#@P)!0'\]>WDV]+)P+BQJZ:C
+MI*JUQ]SS#"(T0TY3551/2$`W+R<A&Q82#@H'!`'^_/OZ^?GZ^OKZ^OKZ^OO[
+M^_KZ^?GZ^_S^_P$$!@D,#0X/#PX.#0P)!@+]]_#GW];-Q+RTKJBCHJ:OO]7N
+M!AXR0DU45U912D(Y,2@A'!82#@L'!`#^_/KY^/CY^?GZ^OKZ^OKZ^OKZ^?GZ
+M^_S^``($!@@*#`X.#P\/#@T+"`3_^O/KXMK1R+^WL*FDHJ6KN<SC_!0I.TE1
+M5E=43D<^-2TE'QD5$0T)!0+__?OY^/CX^/GY^?GY^?GZ^OKZ^?GY^OO]_P$$
+M!@@+#0X/#Q`0$`\,"08!_/7MY-O2R<"YL:JDHJ.HM,;<]0XD-D5/55954$E`
+M-R\G(1L6$0T*!@,`_?OZ^?CY^?GZ^OKZ^OKZ^_KZ^?GY^OO]_P$#!0<)"PP,
+M#0X.#@T,"08"_??PZ-_6S<2[M*ZHI**FL<+8\0H@,T-.5%9544I".3`I(AP7
+M$@X+!P,!_OSZ^?CX^/CX^?GY^?KZ^_OZ^OKZ^_S]_P`"!0<)"PT/$!`0$`\-
+M"@<#_O?PYMS3R<"XL*>?FYN@K<':]`XE.4A26%E644I!."\G(1L5$0T)!0+_
+M_?OY^/CX^?GZ^OO[^_O[^_OZ^?CX^?K\_@`"!`8)"PT.#@X-#0P+"08"_?CQ
+MZ.#7SL6^MJ^GHJ&CK+S2[`4=,4%-5%=644I#.C$I(AP7$P\+"`0!__W[^OKZ
+M^OKZ^OKZ^OO[^_OZ^?CX^?K[_?\!`P4'"0L,#0X/#P\.#`D%`/OT[./:TLG`
+MN+"GH9^@I[;+Y/\8+C],5%A75$U%/#,J(QP7$P\+"`4!__W[^OGY^OKZ^OKZ
+M^OO[^_OZ^?GY^?K[_?\!`P4("@L-#@\0$!`/#0H&`?SU[>3;TLB_MZZEGIN;
+MHK''X?T6+4!-55E954]'/C4L)!X8$P\,"`0"__W[^OGY^?GZ^OK[^_O[^_O[
+M^OGX^/GZ_/X``@4'"@P-#Q`1$1`/#0D%`?OT[>3;TLG`MZ^HHIZ=I+''X?L6
+M+#Y,5%E954Y'/C4L)!X8%!`,"`4"__W[^OGY^?GZ^OK[^_O\_/S[^OGY^?GZ
+M_/X``@0'"@P-#@\/#P\-#`D&`OWV[N;<T\K!N*^GH9N:H*[$WOH4*SY+55E9
+M5D](/C4L)!T8$P\+"`0!_OSZ^?CX^?GZ^OO[^_S\_/S\^OGY^?G[_/X``@0&
+M"`L-#@\/$!`/#0L(!/[W\.;<T\G`N*^FGYJ9GZS!V_<2*CU,55I;5U%)/S8M
+M)!T8$P\,"`4"__W[^OGY^?KZ^_O[^_O\_/S[^OGY^/CY^_S^`0,%!PH,#@\0
+M#P\/#@P)!/_Y\NG@U\[%O;2LI)Z:G*:XTNT)(C='4UE;6%-+0C@O)B`:%1$-
+M"08#`/[\^OGY^?GZ^_O[^_O\_/S\^_KY^/GY^_W_`@0&!PD+#0X/#Q`0#PT*
+M!@'[\^OBV=#&O;6KHIR7F:*TSNL'(3=(4UI<6E1,0SDP*"`:%1$-"08"`/W[
+M^?CX^/GZ^OO[_/S\_/S\^_KY^?GZ^_W_`0,%"`H-$!(3%!,2$0X*!0#Y\NG?
+MULS"N;&HH)F6F*.VT.P((C=(5%M=6E5-1#HQ*"$:%1$-"08#__W[^OGY^?K[
+M_/S\_/S\_/S[^OGX]_?X^OS_`00'"0P.$!$1$1`/#0L(!`#Y\NG@U\_&O;6L
+MI)V9FJ*RR^<#'C1&4EE<6E1-1#HQ*"$:%1$."@8$`?[\^OGY^?GZ^_S\_/W]
+M_?W\^_GX^/CY^OS_`0,%"`H,#0\0$!$0#PP)!0'[].SBV=#'OK>NI9Z9F)^O
+MR.0!'#)$45E<6U9.13PR*2(;%A(."@8$`/[\^OGY^?KZ^_O\_/S\_?W\^_KZ
+M^?GY^OO]``($!PH,#@\0$!`/#@P*!P+]]NWEW-/*P;FQIYZ7E)FIP=[\&#!#
+M4EI=7%=01STT*R,<%Q,/"P@$`?[\^OGX^/GY^OO[_/S\_?W]_/OZ^?GY^OS^
+M``($!@@*#`T.#P\/#PT+"`3_^/#GW=3+PKFPIYZ7E9JHO]OY%2U`3UA<7%A1
+M2#XT*R,=%Q,/#`@%`O_]^_KY^?GZ^OO[^_S\_/S\_/OZ^?GY^OS^``($!PH,
+M#@\/#P\/#PX,"04`^?'HWM7+PKFOI9R4D9:DO-GW%"U!4%I>7EI32D`V+24>
+M&!,/"P@$`?[\^OGX^/GY^OO[_/S\_/S\_/OZ^?CX^?O]``($!PH,#@\0$1(2
+M$0\-"04`^?#HWM7,P[JPIIR4D).@M]3S$2M`3UE>7EI32D`V+24>&!,/#`@%
+M`O_\^OGX^/GZ^_O\_/S\_/S\_/OY^/CX^?O]_@`#!@D,#Q$2$Q,2$A`-"@8`
+M^?'GW=/)P+:LHI>0C9.CO-KY%B]#4EI>75E22#XT*R,<%Q(."P<%`?_]^_GY
+M^?GZ^_S\_?W]_?W]_?SZ^?CX^/K[_0`"!`<+#0\0$1$2$0\-"@8`^?'HW];,
+MP[JPIIR4CY*?MM/S$2H_4%I?7UM42D`W+B4>&!,/#`D%`O_]^_KY^?GZ^OO[
+M_/S\_/S\_/OZ^/CX^?K\_0`"!0@+#0\0$1(3$Q$/#`@"_/7LX]K0Q[ZUK**9
+MD9"9J\;E!"`W255<7EQ63D0Z,2DA&Q82#@H'`P#]^_KY^?GY^OO\_/S]_?W]
+M_/SZ^?CW^/G[_0`#!0@,#@\0$1(2$A$."P<#_/7LX]K2R<&XKZ6<E92:JL/A
+M_QLR15):75M63T4[,BDB'!82#@L'!`'^_/KY^/GY^OO[_/S\_/W]_?S[^OGX
+M^/G[_/X``P8*#0\1$A,4%!,1#@H%__COY=S2R+^VK:.:E)&7IK[<^A<O0E%9
+M75Q844@^-2PD'1@4$`P)!0+__/KY^/CY^OO[_/S\^_O[^_OZ^?CX^/G[_0`#
+M!0@*#`X0$1(3$Q(0#0D%`/GPY][5R\&XKZ:=EI.7I;O7]1(J/DU76UM844D_
+M-BTE'QD4$`T)!@/__?OY^/CX^?K[^_S\_/S\_/S[^OKY^OO\_O\!`P4("PT.
+M#Q`1$A(1#@H&`/GQY][4R\&XKJ29DH^5I+S9]Q0M05!975Q844@^-2PD'A@4
+M$`P(!0+__?OZ^?GY^OO\_/W]_?W]_?S[^OCX^/CZ_/X``@0'"PX0$A(3$Q,1
+M#@H&`?KQZ-_7SL6\M*J?EI"1G+'-[`LF.TQ875Y;5$Q".3`G(1L6$@X*!P,`
+M_?OY^/CX^?GZ^_O\_/S]_?W\^OGX^/GZ_/X``P4'"@P.$!$2$Q,2$`T)!/WV
+M[>7<TLG`N*^EG):4FZK"W_T8,$-065Q;5D]&/3,K(QT8%`\,"`4!__W[^OGY
+M^?KZ^_O[^_O[_/S\^_KY^?GZ^_W_`0,&"0T/$!(3%!02$`T*!?_X\.?>U<S#
+MNK"FG)20E**ZU_83+$!/65U=65))/S8M)1X9%1$-"04"__SZ^?CX^/GZ^OK[
+M^_KZ^_O[^_KY^?K[_?\``@0&"`L-#Q$2$Q,2$`T*!0#Y\NG?ULW$N[*IH)B5
+MEZ.XT_`,)#E)5%E:5U)*03@O)R$;%A(."@<#`/W[^?CX^/CY^OKZ^OKZ^OO[
+M^OGY^/GZ^_X``@0'"@T/$1(3$Q,2$`X+!P+[].OBV,[%N[*GG9..D9VTT.\-
+M)SQ,5EM<65)+03@O)R`:%1$."@8#__WZ^/?W^/GZ^_O\_/S\_/S[^_KX^/CX
+M^OS^``,&"0P.$!(3$Q,2$`X+!P'[].OBV=#'OK2JH)>1D9NNRND'(SE*5EQ=
+M6U5-1#HQ*"(<%Q,/"P<$`?[\^OGX^/GY^OO[^_O[^_S[^_KY^/CY^OS^``,&
+M"`L.$!$1$A(2$0\,"03]]N_FW-/)P+>LH)6-BY2IQ>0#'S9)5EQ>7%9/1CPS
+M*B,=%Q,/"P@$`/[[^?CX^/GZ^_O\_/S\_/S\^_KX]_?X^?K\_@`#!@H.$!$2
+M$Q,3$0\-"@8`^?#HW]7,P[FOI)B/BY"AN]KZ%S%$4UM>75A11SXU+"0>&!00
+M#`@%`?_\^OGX^/GY^OO[_/S\_/S\_/KY^/CX^OO]_P$#!@@*#0\0$1$1$0\-
+M"@8"^_3LX]K1R+^UJY^5CY";LL_N#"8[3%9;7%E22D$X+R<@&A82#@H&`O_\
+M^OGX]_CY^OO[^_O[^_O\^_KY^/CX^/G[_@`#!@@+#0\1$A,3$Q$."P<"_/7M
+MY-O2R<"VK**8D9":KLGH!R(X251;7%I43$,Z,2@B'!82#@L'`P#]^_GX^/CY
+M^OO[^_O[^_O[^_KY^/CX^?O]_P$#!@@+#A`1$A,3$A$/#`@$_?;MY-O1R+ZT
+MJ9V2BXN6K,GI"20[3%A>7UQ53D0[,BHB'!82#@H&`__]^_GW]_CX^?K[_/S\
+M_/S\_/OY^/?W^/K\_@`"!0<)#`\1$A04$A$/"P@#_O?OYMW3R;^UJIZ3BXN5
+MJL?G!R(Y2U==7EM6340Z,2DB'!<2#@H'`P'^^_GX^/CY^OO\_/S\_/S\^_KY
+M^/?W]_G[_?\!`P8("PX0$A04%!02#PL&`?KQZ-[4R\&VJIV1AX6/I,+D!"$Y
+M2U=>7UQ63T4[,BHB'!<2#@L'!`'^^_GX^/CY^OO\_?W]_?S\^_OY^/?W]_CZ
+M_/X``P8)#0\1$Q04%!,1#@H%`/GRZ>#7S<2ZL*.7C(>-G[G:^A@R151<7UY8
+M44<^-"LC'1<3#PL(!0+__/KY^/CX^?K[_/S\_/S\_/OZ^??W]_CY^_W_`@4(
+M#`\1$Q04%!01#@H&`?KRZN'8S\:]LZF=DHR.F[/1\1`J/T]975U:4TI`-RXF
+M'QD5$0T)!@/__?OY^/CY^?K[^_S\_/S[^_OZ^??W]_?Y^_W_`@4(#`X0$A05
+M%102#PL'`OWV[>3;T\K"N;"DF9&/EJG$Y`0?-DE56UU;5$U$.C$H(1L6$@X*
+M!P0!_OOY^/CX^?KZ^_S\_/S\_/O[^OGX^/GZ_/X``@0&"@T/$1,4%103$0T)
+M!/[W[^?>U<S"N:ZCF(^,DJ7`X``<-$=46UY<5U!'/30K)!T8$P\+!P0!_?OY
+M^/CX^?K[_/S\_/S\^_KY^/?W]_CZ_/X!`P4("@T/$1(3$Q(1#@L(`_[W\.C?
+MU\[%N["DF(^+DJ.^WO\<-$=46UY<5T]&/30K)!T8$Q`,"`4"_OSZ^/?W^/GZ
+M^_S\_/S\_/OZ^??V]O?Y^_W_`@4'"@X0$1,4%!03$0\+!0#Y\NC?ULW$N[&G
+MG)&-D9^XUO84+D)065U<6%%(/C4L)1X9%1$-"@<#`/WZ^?CW^/GZ^_S\_?W\
+M_/S[^?CW]_CY^_S^_P(%"`L.$!(3%!44$P\+!P+[\NG@U\[%N[&FFY&,CYVU
+MT_,2+$%06EY=65)*0#8M)1\9%!`,"`4"__W[^?CX^/G[_/S]_?W\_/OZ^?CW
+M]O;X^?O]_P$$!PH.$A05%A85$Q`-"`/\]>SCVM'(OK6JGI.,C)>LR>D((SI+
+M5EQ=6E1,0SDP*"(<%A(."P<$`?W[^?CX^/GZ^_O\_/S\_/O[^OCW]_?X^?O^
+M`0,&"0P/$1(3%!03$0\,"03_^/#HW];-Q+FMH)2*B)&DP>(#(#=*5EU?7%5.
+M13LR*2(<%Q(."P<$`?W[^??W]_CY^OO\_/W\_/S\^_GX^/CX^?O]``($!PD,
+M#Q$3%!44$Q$."03_^._GWM3+PKFNHI6,B9&DP.`!'C9)55Q?7%9/13PS*B,=
+M%Q,/"P@%`O[\^OCX^/CY^OO\_/S\_/S[^OCW]O;W^/K\_@$%"`L/$1(4%144
+M$Q$."@4`^O/JX=C/QKRQI9F.B(R=M];W%B]#45M>75A12#XU+"4=&!00#`D%
+M`P#]^OCX^/CY^OO\_/S\_/S\^_KX]_?X^?K\_@`"!`<*#1`2$Q04%!(/#`@#
+M_/7LXMG0QKRRIYN1C(Z;L]'Q$"H_3EA=75E224`W+B8?&100#`D%`__]^_GX
+M^/CY^OO\_/S\_/S\^_KY^/?W]_G[_?\"!0@,$!,6%Q<6%1,0#`<!^_3KX=G/
+MQKRRIYN0B8J7K\[O#RH_4%I>7EI32T$X+R<@&A41#0D&`O_\^OGX]_CY^OO\
+M_?W]_?S\^_KY]_?W^/GZ_/X!!`<+#Q(3%186%1,0#0D#_?;MY-O1R+^UJY^4
+MC8V7K,CH!R,Y2E9;7%I32T,Y,"DA&Q82#@H'!`'^_/KY^/CY^OO\_?W]_?S\
+M^_KY^/?W^/G[_/\"!0@,#A`1$A,3$A$/#0H%__CQZ-_6S,.YK:&4BXB1I</D
+M!2$X2E9=7EM53D4[,BDB'!<2#@L'!`'^^_GX]_CX^?O\_/W]_?W\_/OZ^??W
+M]_?Y^_T``P<*#A$3%!04%102#PL&`/GQZ-_6S,.YK:&3B(.*GKW@`2`X2UA?
+M85Y84$8\,RHC'!<2#@H'!`'^^_GX]_CY^OO\_?W]_?S\^_KX]_;U]?;X^OT`
+M`P<+#A$3%!45%102$`P'`OOTZ^+8S\6[L:69CXJ-F[/2\Q(L05!975U94DD_
+M-BTD'A@4$`T)!@/__?OY^/CX^?K[_/S\_/S\_/OZ^??W]_CY^_W^`00'"PX1
+M$Q06%Q84$0T(`_STZ^+9S\:\LJ::CXF*F+#/\1`K0%!:7UY:4TI!-RXF(!H5
+M$0T)!@+__/KY^/CX^?K[_/W]_?S\_/OZ^/?W]_CY^_T``P8)#`\1$Q05%102
+M$`P'`_SU[./:T<B_MJJ>DHJ*E:S+[`PH/4Y875Y:5$M"."\H(!H5$0T)!@(`
+M_?KX]_?X^?K[_/S\_/S\_/OZ^?CW]_CZ^_T``@4("PX1$Q05%102$`P(`_WV
+M[N7<TLB^M*F=DXR+EJS)Z@HE/$U875Y;5$Q".3`G(1L5$0T*!P0!_OSZ^?GY
+M^?K\_/W]_?W]_/OZ^??V]O?Y^_T``P4(#`X0$A,3%!,1#PP(`_WV[>7<T\G`
+MMJR@E(R+E:O)Z@HE/$U875Y;5$M"."\G(!H6$@X*!P0!_OOY^/?X^?K[_/W^
+M_O[^_?SZ^??V]O?X^OW_`0,&"0P.$!(3%144$Q`+!@'Z\>C?U<O!MZR?D8:"
+MBZ'`X@,A.4Q97V!=6$]%/#,J(AP6$@X*!@,`_OOY^/?W^/G[_/W]_?W]_/OZ
+M^/?V]?;W^?O]``0'"@T/$1(4%!04$@\,!P+[\^KAU\[$NJ^CE8F#B9NWV?L:
+M-$A67F!>65!'/3,J(QP7$P\,"04"__SZ^/?W^/GZ^_S]_?[^_?W[^OGW]_?X
+M^OO]_P(%"0L-#Q$2$Q03$A`,"`/\\^OBV,W$NK"DF(V(C)RVUO@7,$547%]>
+M65%(/C4L)!X8$P\+"`0!_OSZ^/?W^/GZ_/W^_O[^_?W[^OCW]_?X^OO]``(%
+M"0P/$1,5%144$Q`,!P+[\^K@U\W$NK"CE8J%B9JVU_D9,T=67F%?65)(/S4L
+M)1X8$P\+"`0!_OSZ^/?X^/G[_/W^_O[^_OW\^OCW]_?X^?O]``,%"`P.$!$3
+M%!03$@\,"`/\\^OAV,[$N:Z@D86`AIJXW/\?.4Q98&)?65%'/30K(QT7$@X*
+M!@0!_?OY^/?X^/K[_?[______OW\^OCW]?7V^/K]``,&"0P/$1(3$Q,3$0X+
+M!@'[\^KAV,_&O;*FF8V'BIBRT_45,$5476!?6E)(/C0K)!P7$P\+"`4"`/W[
+M^?CX^?K[_/W^_O___OW\^OGW]_?W^?K\_@$$!PH-#Q$2$Q,3$@\,"03]]NWD
+MW-/*P;>KG8^%A9"HR.P.*D%276)A7%1+03<N)1\9%!`,"08"`/W[^?CX^/GZ
+M_/W^______[\^_GX]_;W^/K\_@`#!@D,#Q`2$Q,3$@\,"`/]]N[EW-/*PKBM
+MH)*(AI"GQ^H,*3]06V!@7%5+03<N)1\9%!`,"`8#`/W[^?CW^/GZ^_W]_O[^
+M_OW\^_KX]_?X^?K\_@`$!PH.$1,4%144$Q$."@7^]^[EV]+(OK6IFX^&A9&H
+MQND**#]06V%A759-0SDP)R`:%!`,"08#`/W[^??W^/GZ_/W^______[]^_GX
+M]_?W^?K\_@$$!PP0$A06%A85$Q`-"`/\].OBV,[$NJ^CEHJ$AI6QTO46,495
+M7F%@6U-)/S4L)!X8$P\+!P4"__W[^?CX^?K\_?[_````__[\^OCW]O7V]_K\
+M_P($!PL-#A`2$Q,3$A`-"03^]^_FW=3+PKFNH96+AX^CP>,%(SM.6F!@759.
+M0SDP*"`:%1$-"@<$`?[\^OCW]_CZ^_S^______[]_/KX]_?W^/GZ_0`"!0D,
+M$!(3%!04$Q(/"P8`^?#FW=3+PKFNHI2*AHV@O-X`'SE,66!A7EA/13LQ*"$;
+M%A(."P@$`?[\^?CW]_CY^_W^_O____[]^_KX]_?W^/K\_@`#!@@+#A`1$Q04
+M$Q$."@8`^?+HW]?.Q;VSIIJ/BHV=M]?Y&#)&5%Q?75A01STT*R,=%Q,/"P@%
+M`O_\^OGX^/CY^OS]_O[^_O[\^_KY^/?W^/K\_@`#!0@+#0\1$A(3$Q(/#`@"
+M_/3LX]K1R+^TJ)J.AXF7L='S%"]$4UQ@7UI324`V+24?&100#`D%`O_\^OCW
+M]_CY^OS]_?[^_OW\^_GX]_;V^/G[_@$$!PH-$!(3$Q03$A`-"@8!^O/KXMG0
+MQ[VSIYR1BXV;L]/U%"Y#4EM>75E123\V+24>&!,/#`D%`@#\^OGW]_CY^OS]
+M_O[^_O[]_/KY^/?W^?K\_@`#!@D-#Q$3%!03$Q$."@8`^?+IX-?/QKVSIYJ/
+MB8R:LM+T$RY#4UU@7UM32D`W+B4?&100#`@&`__]^_GX^/CY^OS]_O[__O[\
+M^_GX]_;W^/G\_@`#!0@+#A`2$A,3$A$."P@"_/7MY-O2R<"WK*"5C8R6JL?H
+M""4\35A>7EM53$(Y,"<A&Q41#0H'!`'^_/KX^/CY^OO\_?[^_O[]_/KY^/?X
+M^/G[_/W_`@4)#`\1$Q05%102#PL%__?OY=S3R;^UJIV2BHB2I\/D!B,[35A>
+M7UQ6340Z,2DA&Q81#0H'!`'^_/KY^/CY^OO\_?[^_O[]_/OY^/?W]_CZ_/\"
+M!`<*#0\1$Q04%!,1#@H%_O?OYMS2R+ZSIYJ-@X*-I<7J#"E!4EUB8EY73D4Z
+M,2@A&Q41#0D%`O_\^?CW]_?X^OS]_O_____^_/OY]_;V]_CZ_/X!!`<+#A$3
+M%!44$Q(/#`@#_?7MY-K1R+^UJYZ2BHJ4J<?G""4\3EI?8%Q5340Z,2@A&Q41
+M#0H&!`'^_/KY^/CY^OS]_O____[]_/KY]_;V]OCZ_/X!`P8*#1`2$Q04%!,1
+M#0H%__CPY][4RL"VJIV0AX2.I,/F""4^4%MA8EY73D0Z,2@@&A40#`H'!`'^
+M^_GX]_CX^OO]_O__`/_^_?OY^/?V]O?Y^_T!!`<*#A`1$A,4%!,1#@H%__CP
+MY][6S,.ZKI^1A8&(G+O@`R,\3UMB8U]83T4[,BDB&Q82#@H'!`'^_/KX]_CX
+M^?O\_?[^_O[]_/OY^/?V]_CY^OT``@4)#`X1$Q45%!,2#PL&`/GRZ=_6S<2Z
+MKZ&3AX*)G;S@`B$Z35E?8%U634,Z,2@A&A41#0D'!`'^^_KX]_CX^OO]_O__
+M___^_/OY^/?V]O?Y^_T``@4("PX1$Q04%!,1#@L&`?KSZ^/:TLB_M*>:CXF-
+MG;C9^A@Q15)97%I4340Z,2DA&Q82#@L(!0+__/KY^/CY^OO\_?[____^_?OY
+M^/CX^/CY^_W_`00(#`\0$1,4$Q,1#PL'`OOT[.+9T,B_M:B:CXN0H;S<_1LS
+M1E)96UE42T(Y,"@@&A00#`D&`P#^_/KY^/GY^OS]_O_____^_?OZ^/?W]_CY
+M^_W_`@0'"PX0$A,3$Q(0#@L&`?SU[>3<T\K"N*R?E(^3HKS;^Q@O0DY55U50
+M24`W+R<@&A41#0D'!`'__/KY^/CY^OS]_O_____^_?SZ^?CW]_CZ^_W_`@4(
+M"PT/$1(2$A$/#0H&`?SU[N;?UL_&O;*GG9B9I+G4\P\G.D=04U-/2$`X+R@A
+M&Q82#@H(!0(`_OSZ^?GY^OO]_O[____^_?OZ^?CX^/CY^_S_`0,&"0L-#Q`1
+M$1$0#@P(!/[W\.G@V=#)P+6IGYF9H[C3\0TD-T5-45!-1C\V+B<@&A41#0H'
+M!`(`_?OZ^?CY^?O\_?[____^_OS[^OCX^/CY^OO]_P(%"0P/$1(2$A(1#PP(
+M`__Y\NKCV]++P[FOI9Z=I;?0[`<>,D!)34U*13XW+B<A&Q41#@L(!0,`_OSZ
+M^?GY^OO\_?[____^_?S[^OGX^/GZ^_S^`0,%"0P-#Q`0$`\.#`H'!/_Y\^SE
+MW=;/Q[VSJJ2BJ;G/Z00;+CQ%2DM(0STV+B<@&A41#0L(!@,!__W[^OGY^OO\
+M_?[^__[^_?S[^OGY^?GZ^_S^``(%"`H,#A`0$!`/#@L(!/_Z\^SEWM?0R<*X
+MKZFFK+G-YP`6*3A!1DA&0CLT+28@&A41#@L(!@,!__W[^OGY^OO\_?[^___^
+M_OW\^_KY^?K[_/W_``($!@D+#0X/$`\.#0H'!`#Z]>[HX=K4S<2[LJJGK+G.
+MYP`6*#8_1$9$0#DS+"4?&100#0H(!0,!__W[^OGZ^OO\_?[______OW\^OKY
+M^?GZ^_S^``($!@D+#`T-#0T-#`H(!0'\]_'KY-[8T<G`MZ^JJ[?*XOL1(S([
+M04-"/C@R*R4>&141#0H(!@,!__W[^OKZ^OO\_?[^_____OW\^_KZ^?KZ^_S]
+M_P$#!0@+#0X/#PX-#`H'!`'\]_+KY-[7T<K`M["LL+O-Y/P1(S`Z/T$_.S8P
+M*2,=&!00#`H'!0,!__W\^_KZ^_O\_?[______OW\^_KY^?GZ^_S^_P$#!0@*
+M#`T.#@X-#`H'!`'\]_+LYN#:U,W$N[6RM<#0Y?L/("TU.ST[.#,N*"(<%Q,/
+M#`D'!0,!`/[]_/O[^_S]_?[______OW\^_KZ^?KZ^_S^_P$#!`8("@L,#0T-
+M#`H(!@+^^O3OZ>/=U]#'O[>TMK_/X_@,'2HS.#HY-S(M)R`;%A(.#`D'!0,"
+M`/[]_/O[^_S\_?[^_____OW]_/OZ^OK[_/W^``(#!0<)"@H+"PL+"@D'!`'^
+M^O7OZN7@V]7.Q;ZZN;_,W_,'&"4O-3@X-3$L)B$;%Q,/#`H(!@0"`/_]_/O[
+M^_O\_?[^_____O[]_/O[^OKZ^_S]_P$"!`8'"0H+#`P,"PD'!0+_^_;Q[.?A
+MW-;/Q[^ZNL#.X/0'%R0M,S4U,R\J)!\:%A(."PD'!0,!__[\^_O[^_O\_?[^
+M_____O[]_/OZ^OKZ^_S]_P`"`P4("@L,#`P+"PD'!0+_^_?R[>GDW]K3S,7`
+MOL/.W_$#$A\H+C$R,"TH(QX9%1$-"PD'!00"`/_^_?S[^_S\_?[^_O[^_O[]
+M_/S[^_K[^_S]_@`!`P4'"`D+"PL+"PH(!@,`_?GT[^KEX-S7T,K%P\?0W>W^
+M#1HD*BXO+BLH(QX:%A(/#`D'!0,"`/_^_?S\_/S]_?[^_____O[]_?S[^_O[
+M_/W^_P`!`@,%!P@)"@H*"0@'!@0!_OKV\N[IY>'<U]',R<K0V^GX!Q0=)2DK
+M*RDF(AX:%A(.#`H(!@0#`?_^_?S\_/S\_?W^_O[^_O[]_?W\_/S\_/W]_O\!
+M`P0&!P@)"0H*"0@'!0,!_OOX]/#LZ.3?VM3/R\O0VNCW!1(;(B<I*2<E(1T9
+M%1$.#`D'!@0#`?_^_?S\_/S\_?W^_O[^_O[^_?W\_/S\_/W]_O\``@,%!@<(
+M"0D)"0@'!0,!__SX]/'MZ>7@V];2S\_4W>GV!`\8'R,F)B0B'QL7%!`-"PD'
+M!@0#`0#__OW\_/S]_?[^_O[___[^_OW\_/S\_/W]_O\``0($!08&!P<("`<&
+M!00"`/WZ]_/P[.CDX-O7U-/6W>?S``L4&Q\B(R(@'1H6$Q`-"PD'!@0#`@'_
+M_OW]_/S]_?W^_O[^_O[^_OW]_/S\_/W]_O\``0(#!08'!P@("`<&!0,"`/[[
+M^/7R[NOHY.#<V-;8W>7P_`<0%AL?("`>'!D6$P\-"PD'!@0#`@$`__[]_?W]
+M_?W^_O[^_O[^_OW]_?W\_?W]_O\```$"!`4&!P<'!P<&!00"`?_\^?;S\.SJ
+MY^/?W-K:WN;P^@0-$Q@<'1T<&A@5$@\-"PD'!@0#`@$`__[^_?W]_?[^_O[^
+M_O[^_O[]_?W]_?W]_O__``$"`P0%!@8&!@8&!0,"`?_]^_CU\_#MZN?DX=_?
+MX>;M]O\(#A08&1H:&!84$0\,"@@'!@0#`@$``/_^_OW]_?[^_O[^_O[^_OW]
+M_?W]_?W^_O__``$"`P0%!08&!@8%!00#`0#^_/KW]/+O[.GFXN#@X>;N]O\'
+M#1(6%Q@8%A02$`X,"@@'!00#`@$`___^_OW]_?[^_O[____^_O[^_?W]_?W]
+M_O[_``$"`@,$!04%!04$!`,"`?_^_/KX]O3Q[^WIY^7DY>GO]OX$"@\2%!45
+M%!(1#PP+"0<&!00#`@$``/_^_O[^_O[^_O[______O[^_OW]_?[^_O[_```!
+M`@,#!`0$!`0$!`,"`0#__OSZ^/;S\>_LZ>?FY^KO]OT#"0T0$A,3$A$/#0L*
+M"`<%!`,"`0$`___^_O[^_O[^__________[^_O[^_O[^_O[__P`!`0(#`P,$
+M!`0$`P,"`0'__OW[^??V]/+O[>OIZ>SP]OP"!PL.#Q`0$`X-"PH(!P8$!`,"
+M`0$``/___O[^_O[____________^_O[^_O[^_O___P```0("`P,#`P,#`P("
+M`0#__OW\^OGW]O3S\>_M[>_R]OL`!`@+#`T.#0P+"@@'!@4$`P("`0$``/__
+M__[^_O[______________O[^_O[^_O___P```0$"`@("`@("`@(!`0#___[\
+M^_KY^/?U]/+Q\?+T]_O_`P8("@L+"PH)"`<&!00#`@(!`0$``/__________
+M_________________________P````$!`0$!`@("`0$!`0``__[]_?S[^OGX
+M]_;U]/7V^/O_`00&!P@("`@'!@4%!`,"`@$!`0````#_________________
+M__________________\````!`0$!`0$!`0$!````___^_OW\_/OZ^OGX^/CY
+M^OS^``($!04%!04%!`0#`@("`0$!``````#_________________________
+M__________\``````````0$`````````_____O[^_?W]_/S[^_O[_/W_``$"
+M`@,#`P,"`@(!`0$!``````````#_________________________________
+M__\`````````````````````______________[^_O[^____````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````!#3TU-````
+M$@`!```W%@`(0`VL1````````$U!4DL````"``!)3E-4````%#P``'\`?P``
+M````````````````05!03````:A39#)A``(```````````!%]```!``*`*``
+M`'E%]````@`*J8$``'D(Q2LCU@`````@5@`BW@!$]`````%$!P`%]"(`__\%
+M]"4``_]F]!,`#`!(`0`&`(0``(Q(7@!G]```#``%]"<``_\*J:,``+,*J80`
+M`)$*J"0,`*4-`2(*J80``+-A]```!`!']```#@`-`+4BK@`@`'0.D)X-`3X*
+MJ80``+,-`2(*J80``+-A]```!`!']```#@`-`+4BK@`@`'0.$*P-`3X*J:0`
+M`)<*J`0```0*`*```.9"@0!(@@!$]"`___]$@T9(`49$]````"!$]$```_\A
+MT@!6@0`&WR!'!B-$]$8`#`!%@T`$"```````"0`C`````````````````'@`
+M```$``0```````#\`/___X`````!`0`&455N:71S````````````````````
+M`````````````````````0(`!B!S86UP<P``````````````````````````
+M`````````````````````````````````````"<`+P`/__;_^0`!````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`0````%X````>````%9N(&EN=&4@9&5L87,@9IIR<HIN(&1U(&AA<B!S=&%R
+M=`M4;V]L960@2&]R;@(```!!249&4V0R80````````````!!249&4V0R80``
+M`````````````````````````````*<]K0$``#DB```!SC]^4')O9W)A;2!K
+M86X@:6YT92!D96QA<R!FFG)RBFX@9'4@:&%R('-T87)T870@<')O9W)A;6R*
+M;FMN:6YG(&D@:6YS=(IL;&YI;F=S<')O9W)A;6UE="!&:6QD96QN:6YG+B!6
+M:6QL(&1U()IP<&YA($9I;&1E;&YI;F<@;G4_F%`````:`"D`#P)J`S$`*@`#
+M`FT#/0`I``\"00,B`0`````:`"D`#P%0`?$`*@`#`FT#/0``````````````
+M```:`"P`%@$^`=P`*@`#`FT#/0`````````````````:````````````````
+M``````````````````````$````!>````'@```!6`'&XO!RF````'`!6``!7
+M<W1A``,`"@`!__\````````````"__\````>```````#__\````\```````$
+M__\```!:````````````````````````````````````````````````````
+/````````````````````
+`
+end
diff --git a/sys/share/sounds/wdnflute.uu b/sys/share/sounds/wdnflute.uu
new file mode 100644 (file)
index 0000000..d60f76f
--- /dev/null
@@ -0,0 +1,328 @@
+begin 644 Wooden_Flute
+M``Q7;V]D96X@1FQU=&4`````````````````````````````````````````
+M``````````````````````````!!249&4V0R80$````!%````````#8B```!
+MSJ<]K;"G/:VZ``````````````````````````````"!@1V.``!&3U)-```V
+M&D%)1D934TY$```T'@```````````````````````/____________\`````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````$!``$!``$!`0$```$!`0`!`0$!
+M`0$!`0$!`0$!`0$!`?_^_P#__P$!`/_]^OG^`0,*#0@)#0@#`?\!`P0%!08%
+M`/SZ^OCT]/CZ!`P"]_W_]_3V_PH-"0+\_?[^`P(`__L&&A,&!P4`_@(-%142
+M"/SQ[/#[^^SF[.WGZ.KEX^CFXNWY^_\*!?G_!/X*&AL4#P\1#P<`!@P%^.KH
+M\_3FWN7EU<O3XNSGXNGJZ?#Y#!P2"A46$AXJ(Q`/("@?$A(7&A4'^?+^#OGD
+MZ^+*P,?>Y];5XN3E\?GS^`D-"Q4G,2\Q-3(L*RXF*#H_,QX4&Q3ZZ^SIX.#=
+MS,?1SK^YOL_C[?D-&1L:&"$O-3M"0D5,0SI(6E`^."T?&Q0#[^'5R,3$O;V_
+MKZ*HN<O.U.C[&"X=$B4L+#]:748^5V!13D8[/#@C"?H##/7,KZ2CJ:^NKK>Y
+ML;*\QM3A]`L,#"<^3%I0.3=#1DQE;E];5S\E$__KY./6O[:VKJ:ML:*5FZJY
+MSN;U`0L1$Q,:*#I/6%%,3E5>75-%,B,@'@X`_>W2P[6GL;VUL;2RM+C#V.7L
+M^/\%$R4X0$5.2T%$2#X[361;/#`O'Q02^]"ZP,2ZN,#"N*^FG):BR>WR[P$7
+M%A0M/S8O-#],6&EY=V=)(`D1'A<*"?O7PKZYKZ2>I*BDKLO1S.#PXM7>]0\M
+M3EY22$4W*"TU-T-*0"L?(QH&[<RSJ::PP,6^N*^>DYVQP]#7V^@"&"`C*"@@
+M'"4O/4U35U,[)2$>"O7S\^#1U-3%NK:NHYR9F**ZSM7AZ^/<ZOX0(BXT048\
+M0E94/S$L(ALA+2X;_-W%O<&ZKJZSK::LN\/!N\+2UMCK"B,O-30N,38R+3`U
+M/$U>644T*!T%Y,_,T]C=Y=W`JZ>DH:*NQM_P_/X#'"P>$AD?*$1@9%E34TDW
+M,#,N)1X3`_'HZ.'.OKFWL;6ZM+7$S]?F\O7W_@P<*3`W/4-,2T9`,BXW/#0L
+M+S(F%/G4O\;.S<O&P<+%PKZUK[O,UNL-*3M`,QX.$BM!03@[35M82S@?#`0`
+M]>/=Z?'ET+^UM+BPI:K`UN+N]O/U!108$0D3*#M!.S8X-"@B(2$K+R@B$_OP
+MZMW3QKJWM[F^Q,.YL;.]U.SZ!Q`6(24A'1TG,S(O,T%/3D`U*QT1"0#QX-7;
+MX=6^M+>XMK*NM<+*V/`!"!0;%A`,$"$T/D)!/#Q#0SPR&P<#!`D/`^C1P[>O
+MKJ^PM<#%O[O(Y?;X^_KY#B\],2HS.#(L+S4X0U)--2<?$07[[N#1S,[$N+O#
+MP[NSK:FST_0"!`P5$`P@.#,B)2TK,DI?74DS(`P``@D"\.OBR\/(PK6OKJFH
+MMM#GZ^[\`?G_#1,D/TI$041".3$W1D<Y+"(9$0L*_-W$NK>XO\K.P[BTL;?)
+MW.KS^/H"'3Q%-B8D)!P6*$A64U1+,QP2#@/SZ^;?V];/R<:\JZ.IM;[,Z0<1
+M!O\#"!$A-#\_/3T_1%%93CTW+!H7'AP0^M[)N;*YP\"VL[.SM\#0W^+I\_,`
+M'2\W/SXL'"$S04E/3D4^-BLD&PX%\]K,S<_/S,6WJZ>LM,#6ZNSP_PH(#",V
+M,RHG+C8X0E%00S@O(!PC(!``\=O&PL?*Q;RSJJ*HNL3*W.;=W/41'"0M-S4H
+M*#8\/4%$/"\J*RHJ(Q+XW\_$OL++SL2WL:JGK\#+SMGO_P0-("LF(1T:)CE"
+M2DY%/38K)RHF&A(%Y\[.U-#%N*ZKIZ>PM;?"S='8Y?@+%QT?'!XK.CX_14,Z
+M-S0J*38]+`SSY]W1Q\;+Q+FXM;"UO<3*R\W9[PL>(A\>("`@*C0]148_-C0[
+M03LI&`CSYN7AULS%P;ZTJZVRM+S$P\KA^PP3%QH9'2HO+CM/4$$^/38X04,Z
+M)1$$_/#;R+^YM[>TLK6ZNKBYN\'3[@88)"@H*"<M-SD\1DA+3TI+23DI&P7S
+M\?/JW,V_M+&PL;6VM[FWO<S9YOD)%!83&R\X-#8]/SLY.C]&13DF%0K_]>[J
+MW\J[N+:OJ[&YNK2RNL35[?P!"A@B*C`R-3]#/3<V0DY,2#TH%0H)`NW;U]&_
+MKZRPM+.OK[&SN</2Y?7_"1,6%R0V/STU,SM#24Y-1T$U(`[^]O?OV<B\LK.S
+MK[&TLK*UN,'1XO#\`PL7(R\Z/CP\/T%#24U/44HQ&Q<7"?;HWL^]L[*QLK.P
+MKJZPM\?:Y.GU!A0<)3`Y/D`[-#4]2E=623TU*AP)^/'HV,:[N+>TL:ZKI*2O
+MNL?7W^K_!@$.*#8_0CL]1$%!2U!023PS+R06"?GFS[ZZO+RWLJ^HI*2FK\'.
+MV>S[_P84(RTT.CT\0$=/55%(2$0V*24?$O_FS\&YM+2ULJVHJ*NLL+W,V.'H
+M^1$@*#8^-S(]2$='4%A734`Y-BXA#_GJVL>_P;VVM+.MIZ:MO,7*U.'O_@\B
+M,38Z04,_04]=75504$U$.S$C$_[FU,K!NKN_MJ>AIZVML;[,UN'M_1,D*"X[
+M0D!'5%A555E63$5`.SDN%/WMUL&^O;2NKJZLJ*:MM;K`S=OJ_A$A+S4U.4%%
+M2$]87EI134U(0#4E$?WLW,W`N;>RK:FFI:FPM;B\Q=/H_A$?*#`W/D)"2%1=
+M6E-,24I(/B\@#?KJV\_&N[*MJ:*>HZRQL;:_QM#B]0<;+#4W.T%'4%-03U!2
+M4TU&0C8A#O_IS\;)PK.JIZBGHZ2LM+:[Q=3F^@\A)R@P/D=)3%):751+2TY+
+M13DB!_?QZ-;!MK2RJJ.AIJVRM+6XO\[F^@40(C<^.CY*45164E%345)42#$=
+M%`;MV<[*Q[JII*6FJ*BLL;:]Q]+<[`@A+"TQ/4I355)-35)45%122T(M"N[F
+MYMO*OKFVKJ2@HZ2GK[B\P,WE_0@*$B,S/T=.55I844E'2U%643PG&0SVWL_(
+MP+:OK*JHJ*JIJ*FQOM'F]P,1'2(J-D)-65Q33E)64U%12CHI&PS^[=W,O;&G
+MI*JNJZBHJJRON,S@\P42&B4O.TA/3DY25%-56EI52SHG%PT"\^+0O["LK:FI
+MK*NIJJZTOLS=[?X.'"4P/DA04TU+3E%67V)92CLK'0[_\^;5P[2LJZRMK*:D
+MIZJPP-'>[O\'#QXN/4I14E%.35-;7UI01SDI(1L/_>;*M[.MIJ:NL*BCI:FN
+MN,;6YO+_%"HX/4%%1T9"151@965803(L(1(%^>[;PK.OJZJJIJ*BHJ:RP,G1
+MW^[Y!!DS0TM.2D)$3UE>8&!:3D`P(Q@/_N;.OK:OK*RIHIZ>H*:MNLK6W>;T
+M"1XP/4)(44Y&2U5:7%U82#@U,B$,^>/+N[.OL+*OI9Z=GJ&LO<C/W.W\"QLL
+M.T-#0T5.6F!A8%Q./C<S+"(5`.;,N[6PK:NFHJ">H*BRN\/+T]WP"24Z03]!
+M1TI)35EB85I23$4Z+B02]=K)PKRVL;"KGY>6GJBPN,?4V.'T"B`R.T1,24E6
+M7EU=6E-12T%!/"</^=S$O;NXMK"FGYV<G*2PNK_)V^KY$2@O+S9`1E!>969E
+M74]$149!.BP8`.3/Q+JQK:FBGI^BI:JQM;:]S-[X&#5`.SI`0DA58FAD8F%9
+M3TI$-!X*].#5S,.[L:6:E9>:H*NTN+J]R=[V"AXR0$5#1U1>8%Y;6596659+
+M.B0-]-_0QL"\M*B=FIF9GJ2JK[;"TN'T#"(O,C8_35]I:&1A6$]/5%1,/RX4
+M]=_7S+ROJ*2@G9VAHZ6FIZNUQ>($'2@M,3="2D]<:VQD86%=6U=&+1@)_?#D
+MU<.VJYV3D9:=I:NJJ;"XQ-KU"ADK/$1)5F%B7EM97&%C8UY/.2(+]>7<T\>Z
+MK*"9FIJ8G:2CI:^_S-WT!A0C,3Q+66-H9EY85EA<7UM202<0_NS8RL*WJ:*?
+MG9ZAH9N9GZFWS>?["18B*S5!45UB9F=D8U]=8%A%,2`1"`#OVL:RHYR:F9R?
+MHZ6CHJFVP]3I_!`@+T)25UA<7%=35F!L;F!,-R,1`/'GW,FWK*2=FYZ>F9>;
+MHZV[S-CD^@P6)CQ.769B5E-87&!E95]20"P8!_KLV<2TK:JEGY^?F9*4GZJU
+MR>'O]?X,(SM)4%MC86%C96=D7%A0/2TI(0GLUL.SIZ"@I**?GIJ9G*.PP,[@
+M]0L?+SQ*4E945%MF;7)P:%Q+.2TD$P/XX\FXK*2CH)N9EY27HZRRO<O6Y?H0
+M*4)05E935%MA9FQL96%60S4K'`KPUL:[L*JGHIF5E)26G*.PO\K5X_82+#I(
+M55116F)E:VYJ9%I/1SPO)!#SV\FZKZJEH9Z9E925G*BPL[S/Y?X7*SM'3$U-
+M4E]I;W-O9%A13$`L&Q$$ZL^]M*NCGIJ6DY2<I*FKK[O+V.X.+$)/4$Q,4EIC
+M:6UM;VQ>3D$T)`[QWM7,P;:KGY60D9*6GJFRN;[$S^D*(#!`3E9;7E]?86-E
+M8EI:6U-"*@SRX='"N;*LIJ"7D(^4FZ6KKKG*W/`%&2P[1$M25V!M<&5=7%Y?
+M6TX\*1D$ZM3&N[*JHIJ4E9F;G)VAJK?#U>T"%BLW/49066!D9VEF9&-=54Y#
+M+18"[MS,O[6JG9:7EY.5G*6IJ[+`T^C\#B4[1DI586-?865C7%QG:EI#+QD"
+MZM?,P[:KIJ2?F).3EYN@J[G&U>G_$1LE-D=37VIM:&)?8F1@651+."`(].32
+MP+2KHYN7F9N8E9FBJ;&]S^;\#APJ.4=5865E9F5I:V5?7%E-.B,+]N75P[2I
+MHIV9F9F9F)F=IJZYR^3["18H/DI/5EQ?8V=H:6AG8E1",2$._N[6Q+BKHY^:
+MEI>7E9B?IK&^R=GO!1@H-T9/56!J:&5H:V=A6U5+.RH7`.K9R+6FGYR<G)F5
+MEIF>HJJVQ]KM!!DJ-T966U=99G!N;6UF7E5(."H:!>[:R;BKI)^<F)66F)F<
+MI*VWQ-?K`!0E-4A25EYD96MM:&AI8%5.0"P8!?3<P[6OII^<F9:6E969H:RW
+MQ-3E^A$E.4A-5&!G:FQM;&IG7%)+0#(B"N_7Q+JQIIN6F)J6D9*;I*JPO<WB
+M_A0C,C]-7&%?8VIP<6UE6E-.0C(<`O'FTKFJI)^;E(Z0EIB<HJ:MNLG>\@<B
+M/$M04UA@:&QK9VAK:V10/3(B".[8R<*WJ9Z7D8Z1DI.7G:>VOL/4\@P?,3]*
+M6V9F96IQ<&QI8UI22CXE"O;DT\&OI:&;E9*0D).9H*:JL</<\`$7+T-15UAA
+M:VYN<')K965>2S,@$@#HT<&VK*&9E(^-D)69G*.LM<+2Y@$:+3U+56%L;FQN
+M;6=I;FI>3STG$/CDU<6XK)^6DY&/CHZ2FJ.LM\31Y/P/(CA+661K:VIN<&MI
+M96%?5T,L%/WHU<&RJJ.<EI&-CI.5F)VEL,/5Y?@,'C%%55]G;W1Q:&1G:FAB
+M4CXO&P'LV,*TK*.;EH^/E)*,DIVHM<#+W_H/(#)`3%QJ<G=R:FMP;F)644LY
+M&@#NW,J[JYV7E964D(V0EYNCKKK/YO8%&B]`4V=L9FEU>'%H96=E5T,Q(`_Y
+MW\BWJJ*=EY&.CI.7EY:?KKW-W.T$'C1#351B<G1N;FYN<6I>5D@R'P_XWLF[
+MKJ2;E)&3DH^,D)JEK[K'U>P(&B,V4&-I:6MU>'!L:V-=5THY)`[YYM.[J)^<
+MF9:2CXZ0E)><IK7&W/#\#RM`3%=B:6UP<W1T<FI>4T8S)!8!ZM&YK:B=DY*2
+MD(^0D)>AI['!T.;]$BE`3%5A:FYN;W)V=&QD5D0X*!'^[=6_M:F;E9*/CH^/
+MD9:?J[?!R=GV$R8W35]H:FIM<G-Q<&QD5TI",QC]Z=;#L:6@G9B2D8^*C9>A
+MIZV[TN;V""(Z2U5<96YP='Q[<&AD74\[*!P/]=C#M:NBFY:1C8Z1DY.:J+>^
+MQ-7Q#B,W2%)<9VYS=7-Q=G1C44E%.2`$\-_*MZFAG)6-CI*0CYBAIJNVQMCN
+M!ATV2UE?9&AJ;W=Y<6EE8UQ%+AT*\-G)NJ^GGYB2BXB-DI:;HJV[QM3I`1HP
+M/TQ98VQS=7)P;FEF85-%.B4+]-[*N["HH)>0CHR-CY.;I*RUP-'H`!<L0$]7
+M7FIU>79R;6AE7U9-0"D.^N3,O;.HGI:2D8^.D)28G:>SP=/F_!<M.4979FEI
+M<7MZ;VAH95I+/"X8^^/2Q+6HH9N3C8R/D927GZFPO,[E_A,F.D9-7&YW=G)S
+M=&]F8%Y30"L5`>S4PK>MH)22E)&0DI.6G:6POLW@_!0C+T!48FMQ=7=W;VAH
+M95U00C(:_^O9QK2HH)N5CXZ1E)24EY^JN<WF_0\@-$-)4V1R=G-S=71J7EE0
+M/"@8"?;=R+ROGY20D)&2DI6:G)^HM<7;\@L@+SY27V-F;7)R;VUM:F%31"T4
+M`?'@T,&NH)J4CHR0DI.5F9^IM\;6ZP0:+$!386=L<')P;6YQ<FE81C$<"/'>
+MT<&QIYZ5D(^0D)"2F*&KN,G9ZO\4)3=-86YS<W)Q<6]L9V5;2#0E%/WGT[ZM
+MI)Z9EI64D9&3E9RGL\/7Z_X4*3U/6F!G;W9V<W1T<&=92#<E$O[KV,6UJ)V7
+MDY&1DI&1E)JEM,33X_<,(#9,7VEL;&QS>WEP;&I>2C@K&@3OVL2SI9V;F92/
+MC(V0DYBDLK[-X/(%'C=(56!I<7)O<W=U;V993T0Q&PCSVL.SJ)^7E9>6D8Z,
+MCI>DK[G'WO4)'3-&4UQC9FQV?'MX<VA:3T$O&PGWX\VZJZ*<EY&,B8R1E)BC
+MKK?$U>G_&31*5U]D:FYR='5W=6M>4D<W(0[YWL>[LJB>EI.0C8N-DIFCK;7"
+MU>?\&#)#4F!I;&QQ=W5R;FID64LZ)Q+YW\NZKJ:AGYJ1C(R,C9*=J;?$TN@#
+M&2D[35998W)^?WMY<V57344]+Q?]Z]>_KZ:<E9&/D9&/DYJ>I*ZZR^7_&#)"
+M25=C8F1N=7EY=&MC6DHW)Q?]X=+'N*NCG)2.BXR.D9>>IK"\R-OX$B<Z1U-=
+M9FYS='-S<&9A7E%`+QH`Z-3$MJVHH9B0CHZ-CY2;I*Z\S^#S#",R0E-=9W-X
+M>7IW;V1?6U!#-R4+[]?%N*RBG)>5E)&.DI:9GJBVQ=OX$B8U1%%98&=N='I[
+M=7!K8%-#+AD%].32P+.IH9F/BHR/DI>=I*RVP]7L`QPU2%):9W-V<&UN;FUI
+M9%M+-B`([]G(P+BLGY:1CXZ,BY"7H*RYQ-7O!A4E-DQ@;71U<W-P:V9C7UE3
+M0R8,^.'-O;"GGYN8E9&0D9"1F:.RQ=GQ!Q<F.$=27FIR=WEU<&QG7U1'-B(1
+M`>[8Q+6FG)B3CY"1DI26FZ2PO<_D^Q8K.4I;86-K<G%N<')L95U..2,/_>S:
+MRKNMHIJ6DH^/CX^4G*:QO=#H^@D=,D)6:&YO<6]N<&QF8%I00B\9!?/=QK6L
+MHYN9F9:0CY*3EI^MOM'D]PPA,T%,5V5N<G)Q;VMI9UM(-RTA#?GES+FPIYR7
+ME9:8EY"-EJ*MNLK=]`H>,D116F!E:FYU>G9M95Q-.RH<"_GHUL.RIIZ:EI",
+MCY*5G*6NN<33Z``3*D=97&%I;6YK9VIN:%Y52#@C#?OFSK^VK:6@FY>3CXN/
+MF**MN,35ZO\3*3U+5F-H:6QP<W-L8UQ10C<L%OOHUL.UK:2=F9>3CXV0EZ"K
+MN,//X_L1)SU.6%M@:W%R<W)J8%E11SHJ%@+NV,:WK:BBFI21CH^4F:&KL[[-
+MWO00*#U/55AA;'%R;FAF9V)72SPN'0/GTL2[M:VDG)>1C8R.E9^KML#+WO@0
+M(2\^46%H:W!U=FYD6U--3$DZ'@#KW,NYKJFDGYJ4CY"4F9VBJ[K/Y/<,'S)$
+M35%=;GAY=FYE75I73#\T)Q+WV\:ZM:^CF965EI64E)FBK+G'V?85*#4\0DY@
+M:W%V=6]L:5U334,R(`OTY=?&N*ZCFY61D9*4F)ZBJ;7&V_,'%R@Z2UAA;75W
+M=&QC75Q<54DY(PW[ZM7$N:VCFY:4EIB7EIB=I;+$V>X%&BHW1U5>:&]Q<6QF
+M9FA@440V)Q+ZY]O/O:RCGYN5DY25DY6=J+/`UO,)%2`P0%!>:'!U<6MJ:V18
+M3T<V'P\$^.?4P*ZAF)66F)B9FYN;HJ_"UN;W#B4W15)>:&UM:VAD96AE6$0R
+M)1D'\MW-P;:HFY:7F9J8DY*8I+/!S^/[$2(P/4M>:VUH9VYO:F5@5D@U(1,(
+M^NK9QK&BG9^?F).3E9B=I;"_T>/S`1$J0U9?8&)J;69E:&1=5T@T)!<-`NK/
+MOK:LHYV:F9B5E9::I+/!S=GI`1PP0%!=9FEE865J;6YE44([+QX+^>C8R+BM
+MI:&=FYB1C).?J;&]RMGL_@XC/E)<8&-E:&UN:61;4DD]+!T2!O+<QK6MJ**?
+MG)>4EYB<I["ZR=?B]Q<R1$U47%]A:&QL;6I@5DHZ*R,7!>_<S+ZTK*2@FY:4
+ME9>>J;.ZQ-'C^1`F/4]87%M=:'-T;6=A54<]-"H:!?+@S+VUKZFBF9.3E)>?
+MJ+&YPL_?\PLE/$A-5V-G:6]P:F!53TU$.3`A"O+<R[^VKZJFGYB5EI>;HJRV
+MP,W?]0HA-T%&359E<7-O;&1634E"/#,?#/K@RL*\LJFCG)>6EI:;I*RRNLG=
+M\08>,SU&4%ME:VUP;6)74$I(0C`?$?G@T\F]LZVFG9>3E)J?HJBSO<;6[P<9
+M*#9$3UIE;'%P9EM644Q)13HF#_KGULB_N*^DG9J8FIR<GZ>MM<7;\P@8)3,_
+M2%5C;71R:&%:4D]+/S,F%`#PX,_!N*RBG9N:FY^@H*2JM,/4ZP09)3`\2%5B
+M:6UM9V%=6%%+0S4C$/[RZ]K&N:^CG)J:G)^AHJ2HL<#2Z@$0'S`[1E5A96IL
+M9V%<55=81"XB$P3Z[-K,OJ^DGIJ9G:&BHJ&EL\32X?,)("TU1EID:6AC8&!@
+M7UQ1034H%@;XZ^#1OZZEH9V?H9V:G:2JLKW-Y/H)$R(W2UA=8VAE9&5A6UA4
+M2SPF$@D"]^;/O;.LI:">G9^AGZ"HLL'3W^P`$R0X2U1;8V9E9&)@85]51#,G
+M'Q,#\N+0P[>IH*"BHI^;G**IL;[-V^S_$2(T1E9A95];7V=I9%M01CTN&0L%
+M^NG7Q+2MJ:6AG9R<G:*JL\#.V>3U!QPU2%5=75MD9U]:7EU523DI)!D%].31
+MPK>OJZBCH)Z;FIZGL\',UN3R!1XP/4]965UF96!@7E9.13HN(Q@*^^C0P+FR
+MJZ>EHI^<FJ"JL[S(UN3Q!!XR/DI56EQ<7V9H7U5/0S4P+1\*]^C9R;JQKZRH
+MH)J;GZ&HM;["S-[S!1<I/4U14E9=8V9D75-+1S\S)AP2`^K3QL&ZLJRFHJ">
+MGJ.JL+O*U-KG`!PP.D-.5EU@8&5H74]+1SPT,281^^C:S<*XLJ^LI9^>H*.J
+ML[K!RMOU"A0A,T%)45A>9FIE7%)'0D$],B(2!?3>S<.\MJ^II**BI*>JK;6^
+MRMON`18J-CU"2E5?9FEG7%%+13XY+R(4!._?U,G`MZVHI:*AI:JLL+6[QM;I
+M`!<F+SE&3U5;8&)A7%=/1D$],B$0`/+FW,V_M["GHZ2EI*:NM+:XPM?L_0T?
+M,#I"3%9<7V!>6%%+2DI#,1\3!O3EVL_&N[&KI:&FJZNJJK*^R=7I_@X=*S9`
+M2U-<8V-;5%143D8[,",4!/?NXM7*NZRFIJBIJZRKL+6XPM3H_`H9*3=#3UA;
+M5U596U=034Y&,A\/`??PYM?)O+2NJ*2DJ*NMKK7`R='?\@02(#5)45-:7U=.
+M3E!36%%"-RD3`OCLX=?,PK>NK:RII:*DJ[6_R]OG\?T*&"L\3%MD7U135E!*
+M24<]-BX>#@'RW]#%N[.PL;&PJZ:FJ:ZVP];G]0(-&BT]1$U75U9865A43TE`
+M,"(:$P?WZMC&O+:RKJZOK*>GJ["ZR-/=[/P,'3$_1TU14%!76EA75$<Z,R<<
+M%0;TZM[,OKFUL[&LJ*>IKK6^QL_;ZO8%&B\^2E)245185U943D=!.2XB%PS^
+MZ=/&P;ZYM+.PJZBGJ;*]QLW:[?L('C(\049+4%576U]=4D,V+RPF&P[]Z]S.
+MP+JXM;&MJ:JNL+2]P\C3X/,-(R\Z1$=$2%)965A744<_-RLA&@[YYMK3R\.Z
+MLZ^KJJJKL+>]P\G3X.\&'BXU/$9,35%765A324`[/#DL'`[ZX];0R\.]NK2L
+MIZFNL;2YP,G6Y/4(&B8O.D%$35EA7U5*1D([-S8O(A']Z]_4R<"\M[*RL:^P
+MLK>ZN\'.X?@.'2DS.#M!2E!66EM73$`_0#@I&`G\\.3;U<W!M*ZLJJJQNKVZ
+MO,;2W>L`%B@Q-C]-5%974DI'1DE-1CDP(0KWZ=_;ULO"O+*LL+"LK[>[OL//
+MXOD(#A<F-#M$5%M855%(/SY#1D$S'PS^]>K9S\K!NK6PK[2WM[2QM,'0W_0*
+M%!LG,#=!3%%35%)/24=(0C0H'1#_\N_IVLJ_M:VML;.UMK2VO,/+V.T`#!<E
+M,T!*4%-/249&24]/2#\Q'@O]]>[DV\_"NK6UM+.RL;"SN\73Y?+[!0\9*#E)
+M5E=22TA(1T5$0SPQ)!<+_N_BU<B^NKR]N;:WMJ^LL\#0X_4$"P\:*39`14M3
+M5U-.3$M(/S`E(1H1#0+KULJ_M;&TNKZ]N;2SM[[(UN7S!QXK+SE#145#0D9/
+M5UA/1#@I&1`+`_OPXM3&NK>YM[6SLK.YP,3,V>;O^@D9*SU*3$=#0D-+44U)
+M0SLR)Q@/"/WKV<O%Q,&\NKBQK:^TN</1W./N_0@7*#9`149'2DQ-34Q%/C4J
+M)"0<#_SHV]'%P+^\NKNYM+.VN<+,TMGH_1$A*S0[/SX]0DM/4%--/S(M*B$4
+M!_OQYMC,Q\.^M[.QL[:[PLC*SMKH\P$7+#I!1$`Z/TM-2TA!/D`Z*QX8#?OJ
+MWMC2S<G$N[2QLK6XOLC0U-OH]@04)#$X/$)'24I*249`-C0V,2HB$O_NV]'2
+MS</`P[VSL[>[O;_$S]OE^`\@*"DO-SD]25!23T<^.C8Q*R@@$0'QY-S6SL7`
+MNK2WO+N[P,3'S-7C]@<7)S$P,SU$1DI+2$4_.C@V-"P=#`#RX]S:T<?!O+FW
+MM+G`P,#$R]7C]PH8(24J,SM"2$M.34,Y.3DS,"P@#@'VZ>';T<>_N[NYN<#"
+MP+_"Q]+E^@D7("8M,#4_1TQ.24)`/3@T+24<$`7\\N?=U,BYL;6_P\/!P<+!
+MQ-#?[P(6)2PM+SI%1$!!0D-$0S\[,B48"_SS\_+FU<F_NKJXM[W"PL/&R]'@
+M]00*$B$P.D!#0$)(1CPY/3\^."D8#`']^.K=UL[#O;JXO,'!O\#"R-GH\/H(
+M%"$M,CQ(2$-`/CT]/3X\,",=%0;Z\^SGW,F]NKN_PL&^OL'%R]3?[?X+%A\H
+M-$-(1$`].3U#0CX]-B@:#P7\]O'EULO&P;Z^OKJYO,''SM?F]?G\"!PL-CU&
+M2D<^.#Q"/S@U,BH<$@\'].7?V<[#OL##P;R[O+["S-SK\/0`#1<E-D!&240^
+M/3PX.CTW+2@F&@C^^>[@T<G(QL3$P+NZN[[%S=?B[_H!"1<H.#]`/S]!1D,\
+M.SHS,"H<$P\(_>_?T<S+R<2^N[V^O+W(U-G@ZO7_"Q<F-#Y"0D-%0CH\0SPM
+M)R8B'18*_.[@U\_&P\?'P\"[N\+&RM;BY_$##QDF,#E`/3@]2$M%/#8O)!\C
+M(Q8*`O7CU<S+RL7`O[^^O\+%RM+<Z/'Z"!LL,S(S.D!"0D1&/S0Q+1\7'1\2
+M`/+EW-7/R,+`P+V\PL;)S]7:W^;T"AXJ+S0Y/#Y`04(_.#4P*"@J)!H,^.KF
+MW];3U,W"N[N]O,')S]7;X.X`#!(<*3(V.T%$14E%.C`I)2@J(AD1!?7JX-?2
+MS<;#P+V\P,?-T,_1WN[Z!1,E,C(O.$-%1DA!."\I+"TF(!P1`O/IXMS8S\;!
+MN[K#R\G(S-'5V.'X$!HB+#(R-CY$1#XZ.SDQ*BHK(Q0&_/7OZN??T<C"N[BY
+MP<S2T<_3W>?U!!`;(RDV04%"2$8Z,2LG+#(M(AH0`?/MZN38S<C"O+S!R,O&
+MP\S4V^?X"!49&R<S-CQ(2D(Y,S`N*B8G)1@'``#Z[>3>TL.ZN\#&R\S+R\G+
+MU^?U`0X;(B<N-C]#/SLX,RXP,C(L'0P'!/OU]O+FU<2YN;W"R,O,S,S1W.?O
+M^P</&"8T04M)/S<P+#`U-3,N)!8(__KY]NSAULO#O\#"Q<;$Q<O2W^_X_``(
+M%"(O/$E.1#DU,2PL+R\K)!<-!P+]]>G?U,?#QL;&R,;!PL?2X>OR_P<%#B`N
+M.TE)03LV,C,T+RDD'1D2!P($`>_9RLC*QL7)R<3!PL?2WNCU```"#R$S041"
+M/SLU,30U+RPI&PP-$P\$]NG>U<S&Q<;(Q,#!P\C4Y.SO\O@$%B(M/4A&/C<S
+M-CHV+R8>&QH4$P\#^.S:T<_*RL[+P;V_P<G7X.;P]_H`#B(U/T`]-S8^0#DQ
+M+2@@%A,8&A('^^K:T=#1SLG$PL+"P,74XNCJ[?,$&B8L-CP[.SX\/$`],"(8
+M%!89&Q<+_N_>T]#-R\O%P<+`Q-/9UMSEZO0%%"0X.C0T-3@^04`\+R(:%A<9
+M&1,,_NOAW=?3S<*]P,#`R]C:UMC<XN\%&BDR-30Y.C8Z1$(V+"0='!P;&Q,#
+M]>SHY-O5TL>\N+K!RM#6V]S:XO(!$"0R,R\P.$%%0CTU*1X9&2$B&A(+^>CC
+MY.3<SL"\O+[#R]'5U=;:X?`&&2$D*C$V.T!%13TQ)AX<'R(B'1``^?;PY=S6
+MT,2YNL'(S]/1TM/3W/8+%!XI+2TQ.T1&0CDP*20?(R@D%@H!^?3O[N[ARKNY
+MN;[*TM+2T,[6XO`#$QPB)RTX0D9(0S8J(R(F*RLD&0K]]O3U]>S;RK^ZNL')
+MS<_.SM+9Y?,"$1<8'S`_1DE)034I(B,F*2DF'`X!^/7V\>37S<2]O\?,S,G%
+MQ<G8[?H##105&B@X0TM,030L)2$G+RH;$`T)`?SZ]>G6Q+V^P,7-T<O$PLK8
+MY_0""@T0'#`_1TA"/#8L*"@H+"TB%`?^``4`\>76QL#`P\C+R,;%PL;6[?G^
+M!`8-'"X[2$]'.3$J)RDM+BD@$0@+"?[Y].?5QL+%RL[*Q+VZO\S=[??^!`4*
+M%R@Z1TM(/S<S,S(J(1T<%P\.%!4&[=G,P\#&S]/.Q\/!OL+0X_3^``,2)#$[
+M/CT[-S8Y.#8X,B(/!PL3%A('^.;4R<'`QLO*R<:_O\[?X^/K]0`2*#A!1#\U
+M+C$U.3T[,"(6$0\/#@H#^>O9S<G+S,2[NK["R=+=Y.7G[_D''#9&1C\W,S8X
+M-C(P*R,<&!<9%0\#[MO3TM+1SLC`N[BYQ-+<X.7IZ_D1(C`Y.3@[.C@[/STU
+M)A80%1TB'`[^[^3:TLW.S,:_O+S"R]+7V=C=[/\2)#$Y/#HS,#="0SDP*B$;
+M'!P:&1#][.7BW-;4S+^XM[O#R]'8W=[@Y/(*(S$X.C@W/4`]/#HO(AL=)RHC
+M&@[YZ.+?W^#9R\"[M[:_R]+1TMKB[?\1&R,N,S(T/TE+1#8F'!H?(R8G'@W\
+M\NKAVMG5R;NXOL+&R\W.SL_7YO\6(R@L+RXQ/D9%/SDR)AP>)RDA%`?]]_'K
+MY=[0O[>YNK[)TM+,Q\G7ZOL,'"4K,#,Y0D4_.#$G)2@L+2@?%P?V\/#Q[.'2
+MQ;VYNL#%Q\?)SM;=Z/P0%Q<<*3=!1DE)03`B(B0B)BPJ'`K^_/?LX-?/R+^[
+MP\O*Q\2_O\K<]`@-$AXB(RTZ0TM)/34N(R8P*Q\;%P\'`?SW[MO&N[R^P,K3
+MSL/!Q<K4Z/T+$QH?*#=$13\].#`M+"TO+RH@#P(!!/WT[>#-P;_!P\3%PL'$
+MR='=[OP"!0X=*C1"3DH\,R\I)2DM+2H>$@X,!?GOYMC)Q,7'R<C&PKNXO\WA
+M]/W_!Q$9)#,^04%`.C$M+S$L(QT5$`\/#0?]Z=7'OKK`Q\S-QKZ]Q='8X>[Y
+M!A0A+SQ"0#DQ*BPS.#@Q*20;#`0'"@7[[^'0Q</$PKZZO,;+S-+>Z.WN\P4>
+M,3]+2STT,"LG*2XR,2L@%1(0!OOPX]G6U]#(Q\.[M[B]Q]?EZ^_U^P,2)39!
+M0T`^.C,O,C$J(1P;'A\:#P'SY=;/SLS,R\?"O+J\Q=/<XNGQ_A`=)C(^/C@S
+M,SD_.S(L)1D4&QT6$0KZZ>#6RLC)Q<&^OL#%S=/7W./K]00<,3U`.3,W.30S
+M,RTH*"8D(1L5$0/NXMS:W=C*P\.]M[C`R=#8X^GK]@P<(RLS-SU`/3L].2TA
+M&APA)28A$P#S[.'6S\[/RL*_N[S%R\K-U>'Q!`\4'RXU-#4Y/3]`.B\E'QX?
+M'QX<&`KV[.?=TLS(P+W`P\7'QLG0U]GA]PX=*3(V-S0S.C\X,#$Q)B$D)R09
+M!_SZ\>7BXMC'O+N[N;[(R\S0T]OJ]P$0(RLO-CH\0$$Y,2PD(2HL)"`<$@;[
+M\.GCV=#+P[NZP<7%Q,7*T=GF]@85'R4N.#HX/#XX,R\L+"<B)R@:"P;_\^[K
+MW]/(O+F]O\'$Q<G,S=7E\_T.'"4M-3M`0#LV,2LL+2DJ+R@;#P+Y]O7MXM3(
+MPK^ZNK[!Q,?)T-OG\_L$$A\K.$)$03XZ+B`=*30S+2<A%PG^]NOAW-K4R+Z]
+MP\2\MKO%S]OI]P,)$1HB*#1$24(Y,BTN+2,B*BD>%Q$&^O7PW\S$Q,;%P[^\
+MP,7$Q]3C\OX(#18C,T!#.S@[.#`M*RHM+"8B&0T(!_OHVM/,R,._P<7`N[W#
+MS-7A\/H`"ALH+SA`1$,Y+BPM+S$P+"<B'!,)__/KXM7.R<3$Q<&[N;F^R]GD
+M[_H$"Q(>+#<_0SXX-C4R,3`I(B$A'QH0!O_RW,W)RLC#P</!O+F]R=;=Y/'^
+M"!(C-3HV-3L^.#`O,C(M)2(A'!83#@#LWM?/Q\3#P\+`O+N_Q<W;Z>[W"1LC
+M*#$\/S@Q-#DV-#$K)R0B(AT2!?SSYM;-S,W)P+JXN+S#Q\W8XN_^!@P:*C0X
+M.#8X.ST\-"<A)B@A'R(>#_[QY-G1R<7$P\"^O\"]O<K;X>3R!A@D*R\R-#8X
+M-S8W.#4O)B`A)!X6#P+TZ^+5S,7`P;^YN;_'S,O,UN/O`18C*C(U-34S-3HZ
+M-C$L*BPK(A@2"P/YZ^#;U<O!N;:YOL'#Q\S/V.CR]PDA+2\R-C@Z/#DT,3`N
+M*2DK)B$:#@+WZ^/=U,C`O;N\P,"_PL7+U^#M!!4<)2PL,3DY-SH[.#(L*B@E
+M)2$6#@?]].O>S\.^N[N^P<#"QL7(T=WK_@X:)"PQ-CDW-CDV-#0Q+RPI)B$8
+M"@'_^>O=TLW&NK2XO<##Q<;+T=WN^@,1'RHS.3L]/#DT,"PH+C@W*R(<$@3U
+M[.WGV=#)P+R[N[R\N\',V>3N^P8-%1\I,S]&1#DS-3,L)B8N-"T?$PK_]>SB
+MULW%P<7#NKG`P<#&S]ON_0()%R,J,CL_/#@V-3$N+C`R+2`8%@\$^^_CV\_$
+MP;ZYO</`N\#)TMWG[_P*%!XL-ST_0#HP*2LP-#4T+28?%0L#]^SDWM3*Q,&^
+MOKNXNK_%T-[J]?\$"QHG+C=`0CXW+R\Q+BTN*B<B&!$,`?+DULS(Q</$Q+ZY
+MN;O"S]OF\_T$"Q<E,CDY.CPY-3,S,2XK)B,A'!81!_3AU<W(Q,'"Q\6\NKW!
+MQ]/B[?8$$QXF+#,X-S4S,S@Y-3(M)!\>'AL1`?;QW\K&R,;%P[VYNK[%SM;<
+MYO8$#A4>+#H]-2\R/#\W,"XH)R8A&QD5#/_KU<S-R\?$O[Z_OK["RM+=Z_+U
+M!!LL,C$P,S@Y-3(T-S0J)",B(2$6`_3IW]O4R</$P[^ZM[S'T=?8W.K^"Q4C
+M*2\Y-2XT.CDW-B\E)"@H)B`3!OOOX=70TM#%O+BWO<?)Q\S9Y>WT`!4E*2PO
+M,#,Y/3PW+B<G*28A(2(=#_OHX.'=SL/"P;[#QL+%S='3V>/T"!@B)RLN+R\S
+M-C8V,RTK)R`F+"`.!/WU[N7:U,_$O;[`Q<K,T-/3U^3S!1(:(2LO+C$S-#<T
+M*B8H)B<O+!L-!?OS[^OCU\W&PL'!Q,K0T,S1W>OW``L8("$D+#4W-C<S*"(D
+M*"HI(QT6"__W\.?@V]+%O\/,T,[*R]#5VN+S!@\2&R(B)C`W.#(H)"@I)B4F
+M)1T2!__Y]_+EU,K)RLG(R]'2S\W0V>;U`0D0%!DF,3$M+2\M)2`E*RXI'A41
+M"?_\_//DV]7,QLC.TM'-RL_9X>CT_@$%$!LB*2\V-RP?'2(E*"HF(!H1"03]
+M^//IW=+,S-+2T,_-S,_7X.OU_0$$"A0@*S,T+R@C(R,A)"@F'QD5#@<!^_/G
+MVM/1U=?4T='0S<_7XNST^@`'"Q,>)RTM*2<G)2(E*"4@&A,/#@X*__+HWM72
+MU-;7U]30S]/9X.SU]O8`#Q@=)"DK*2(?(R8F)B,>&101$@\&_?7KX-G6V=O9
+MU=+0T]C>XN?O]?K_!A(@)R<D(R$@(B4F)!\;&1<2#@T,`O3GX-W=W-K:V-/3
+MUM?;X^OP\_C[!Q<='B$B(B`@)"8E(QX7$A$3%1(*__?NYM_;V]S;VMC6U][D
+MYN3E[??_"14>(B$<&1P>("4H(AL7%A83#PP(`?GPZ>;EX=S8UM;9W>#CYNKL
+M[._Y"!0;'A\<&AT@'QT='AP:&!45%0\#^O3P[NWJY>#<V=?8W>'FZNOK[O3\
+M!@T1%1H>(!\>'R$>%A$4%Q@7%0\'_O?Q[>GHY^3@W=S>X>/CY.;K\/;^!PT1
+M%A84%QXA(1\;%Q43$A,5%`X&`/GT\O#JYN+>WN'CX^7FYN?I[//_"`T/$1,6
+M&1L;'!P9%105%185$0H#_?KY]_+LY^/AX>'BY>CGYNCL\/?^`@<,#@\3&1P<
+M&QH6$A`2%!84$`P&`?SX]?/NZ.7DY.7HZ.;GY^CJ\/D`!`8)#0X1%1@;&Q@4
+M$A,3$A,2#0@%`P#]^?3MZ>;EY>?JZ^KIZ.GM\O?[`04("PX3%A86%A01#Q(5
+M%1,0#`@$`/[]^_CR[.GHZ.GK[.KIZ^WO\OC]_P`#"`T3%185%!$/#A`1$1(1
+M#0@#`0'^^O;R[NWL[.WN[.KJZ^WR]OK]_@`#!@H.$104$A`/$`\/#PT+"0@'
+M!0+^_/GR[>SM[_#P[^_N[>[R]??Z_@($!PL/$`\-#0X.#@\1$`T*!P4#`P(!
+M_?CU\_#O[_#P\._O\?/T]_KY^OX"!@H-#@\.#`L+#0T,#0T*!P<&`P'__?GV
+M]//S\_/Q\?'Q\O3V^/K[_?\``P<*"PL,#`L+#`L*"0@'!P<&!0(`_?GW]?7U
+M]?7V]//S]/7V^/K[_?\!!`8("`@("0D+"PL)"`<&!00$`P,!_OOY^/?V]O;U
+M]O;V]_?Y^OK[_/T`!`8'!P@'!P<'!P@'!P8%!00$`P'__?S[^_KY^?CX]_?W
+M^/K[^_O\_?\``0,$!04&!@8&!@4%!`,$!`0#`@$`_OW\_/S[^_OZ^OKZ^OK[
+M_/W]_O\``0("`@,#`P0$!`,#`P("`@("`0$`__[^_?W]_/S\_/W]_?W]_?W^
+M_O\```$!`0$!`0$!`0$!`0$!`0$```#___________________________\`
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````!#3TU-````$@`!
+M```T%@`(0`VL1````````$U!4DL````"``!)3E-4````%#P``'\`?P``````
+M````````````05!03````:A39#)A``(`````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`H``````````````````````````````````````````````````````````
+M```````````````````````$"```````"0`C`````````````````'@````$
+M``0```````#\`/___X`````!`0`&455N:71S````````````````````````
+M`````````````````0(`!B!S86UP<P``````````````````````````````
+M`````````````````````````````````"<`+P`/__;_^0`!````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````0``
+M``%X````>````%;_^?_[__S_^__\__S__/_]__W__?____X````"``$``P5&
+M;'5T90(```!!249&4V0R80`````````````2J0````!!249&4V0R80``````
+M`````````````````````````*<]K;```#8B```!S@"*`(``@0!T`&$`5P!'
+M`#X`-P`U`"X`'P`A`!``#``5`!<`'0`8`"(`*0`P`#,`-`!"`$@`/P!#`$4`
+M0``R`"X`-@`F`"``)@`<`"``)0`B`"(`(@`@`"D`,``D`!X`&0`-``;__O_V
+M__W_^O_S__;_^@`&``T`#P`8`"(`*0`O`#H````:`"D`#P)J`S$`*@`#`FT#
+M/0`I``\"00,B`0`````:`"D`#P%0`?$`*@`#`FT#/0`````````````````:
+M`"P`%@$^`=P`*@`#`FT#/0`````````````````:````````````````````
+M``````````````````$````!>````'@```!6`'&XO!RF````'`!6``!7<W1A
+M``,`"@`!__\````````````"__\````>```````#__\````\```````$__\`
+M``!:````````````````````````````````````````````````````````
+,````````````````
+`
+end
diff --git a/sys/share/sounds/wdnharp.uu b/sys/share/sounds/wdnharp.uu
new file mode 100644 (file)
index 0000000..2f01e10
--- /dev/null
@@ -0,0 +1,282 @@
+begin 644 Wooden_Harp
+M``M7;V]D96X@2&%R<```````````````````````````````````````````
+M``````````````````````````!!249&4V0R80$``$X`10```````"XB```!
+MSJ<]K8^G/:V7``````````````````````````````"!@<\@``!&3U)-```N
+M&D%)1D934TY$```L'@``````````````````````````````````````````
+M````````````````````````````````````````____________________
+M________________________________________````````````_____P``
+M`````````````````````/_________________^_O[^_?KX^/T!`O_[\-[,
+MP;R\OL"\L:>OQ=37S\6]M[2VN\''S=/8WN/GZ^_Q]/D`"A8B+SM$2U%776%E
+M:6UO<G-T=79W=W9V=G5T<W-S<G)O:E4?\?T=)RPQ,C$N)R`8$`@`]="4@)NU
+MO<3)R<;`N*^HI:2GK+.ZP<?,T=;:WN'DYNKP^`$-&20N-CQ"1TQ05%A;7F!A
+M8V1E9F=G9VAH9V=G9F1?5"[^[/D)%!LB)BDH)2`9$@G_[L64A)*BK+6\P,+`
+MO+:QK:RML;:\P<;*SM+6V=S>X./H[?7_"10>)RXS.#Q`1$A+3E%25%9865I;
+M7%Q=75Q;6E9/.Q+Q[/+[!`P3&A\A(!T8$@G^Z\.:BX^6GZBOM[N]O+JWM;2U
+MN+O`Q,C+SM'4U]G;W=_BY^SU_P@2&R$G+#`T.#P_0D1'24I,3D]045)34U-1
+M3TL_)@/NZ^WQ^/\&#A08&AD6$0G^ZLBEE)*4F)ZEK+*WNKN[N[N\O\+%R,O.
+MT-+5U]G;W-W@X^CO]P`)$1D?(R<K+S(U.#L^0$)#14=(24I*2TM)1C\Q&/WN
+M[.SM\?;]!`L0%!44$0K_[=&RGYN9F9R@I:NQMKJ]O\'#QLG,S]'3U-;7V=O<
+MW=[@XN;K\OH#"Q(8'B(E*2PO,C0W.3L]/D!!0T1$145#/S8G$?SP[>WM[_+W
+M_0,)#A$2$`L!\=K!K:6BH*"AHZBML[B]P<7(S-#2U=?9VMK<W=[?X.#BX^;K
+M\/?^!@T4&AXA)"<K+2\R-#8X.CL]/C]`04`^.3`A#OWS[^_O\/'T^?X$"@X0
+M#PP$]N3-NJ^JJ*>FIJ>KL+6[P<;,T-38V]W>W]_@X>'BXN/DY>?J[_3[`PD0
+M%AH>(20G*2PN,#(T-C<Y.CP]/3PZ-2L=#?_U\O'Q\O+T]OL`!0H-#@P&^^O9
+MQ[JSL*ZLJZNLKK.YO\;,TM?<X.+CY.3DY.7EY>;FY^GK[_3Y_P8,$A<;'R$D
+M)B@K+2\Q,C0V-SDZ.CDV,"<;#0'X]//S\_3U]OG]`@<+#`L'_O'BTL6]M[6S
+ML;"PL+.XO<3,TMC>XN7GZ.CHZ.CHZ>GIZ>OL[_/X_0,)#Q49'!\A)"8H*BPN
+M,#(T-3<W-S8S+209#@3\]_7U]O;W^/K\``4)"PL(`??JW-#&O[NYN+:UM;:X
+MO</*TMG@Y.CK[.SL[.SL[.SL[.WN\//W_`('#1,7&QX@(B0G*2LM+S$R-#4V
+M-C0Q*R,9#P;_^OCW^/GZ^OS]``0("@L)!/SQY=G0R,/`OKV\N[J[OL/*T=G?
+MY>KM[_#P\/#P[^_O[_#P\O3X_`$&#!$6&AT@(B0F*"HL+C`R,S4U-3,P*B,:
+M$0D"_?OZ^OO\_?[_`00'"@L*!@#W[>+8T,K&P\+!P+^_P<3*T-??Y>OO\?/S
+M\_/S\O+R\O+R]/7X_``%"A`4&!P?(2,E)RHL+C`R,S0T-#(N*2(;$@L%`/W\
+M_/W_``$"`P4'"0L+"`/\\^G@U]',R,;%Q<3$Q<?*T-;=Y.KN\O3U]?7U]?3T
+M]/3T]?;Y_/\$"0X2%QL>("(E)RDK+2\Q,C,S,S$M*"(;$PT'`O_^_O\``0(#
+M!`4'"0H*"07_]^[FW=;1S<K)R,C(R,K,T-7<XNCN\O3V]_?W]O;V]?7U]O?Y
+M^_X"!PP0%1D='R(D)B@J+"XP,3(R,2\L)R(;%`T(!`'__P`!`P0%!@<("0H*
+M"0<"^_3KX]W7TL[,R\O+S,W/TM;;X>?L\?3V]_CX^/CW]_?W]_CY^_X!!0H/
+M$Q<;'R$C)B@J+"XO,3(Q,2\K)B(;%0\*!@,!``$"!`8'"`@)"@L+"@@$__CP
+MZ>+<U]/0S\[.S]#2U-?;X>;K\/3V^/GY^?GY^?GY^?GZ_/X!!0D-$A8:'B$C
+M)2@J+"XO,3$Q,"XK)R(<%A`,"`0#`@($!0<)"@H+"PP,"PH'`OSU[N?AV]?4
+MTM'1TM/5U]G=X>;J[_/V^/GZ^OKZ^OKZ^OK[_/X!!`@,$!49'2`C)B@J+"XO
+M,#$Q,"XK)B$<%Q$-"08$`P,$!@@*"PP,#`T-#`L(!/_Y\NSFX-O7U=/3U-77
+MV=O>X>7I[?'U]_GZ^OO[^_KZ^OO[_/X``P8*#Q,7&Q\B)2<I*RTN+S`P+RPI
+M)B$<%Q(-"0<$`P,$!@@*"PP-#0T-#`L)!@'\]N_IY-_;U]75U=;8VMW?XN7H
+M[/#S]O?Y^OKZ^_KZ^_O[_/W_`@4(#!$5&1T@(R8H*BLM+BXN+2LH)"`;%A(-
+M"0<%!`,$!@@*"PT-#@X-#0P*!P/^^?/MY^+>VMC7U]?9V][AX^;I[._R]/;X
+M^?KZ^OKZ^OO[_/W^`00'"@X3%QL?(B4G*2LL+"TL*RDF(Q\:%A(."@<%!`0$
+M!@@*#`X/#P\.#0P*!P/_^O7PZN;BWMO9V=G;W=_BY>?J[.[P\O3V]_?X^?GY
+M^?KZ^_S]``,%"0T1%1D=(20F*"DJ*RLJ*2<D(1T9%1$."@@&!04%!@@+#0\0
+M$1`0#@T+"`4!_/CS[NKFXM_=V]O<WN'DY^GK[>_Q\O/T]?;W^/CX^?GZ^_S]
+M_P(%"`P0%!@<(",F*"DI*BDH)R4B'QP8%1$."PD'!@4&!P@+#0\1$A(1$`X,
+M"08#__KV\>WIY>+@WMW>W^'DY^KL[O#Q\O/T]/7V]_?X^/GY^OO]_P$$!PL/
+M$Q<;'R(D)B<H*"@G)2,A'AH7%!$-"PD'!@4%!@@*#0\0$A(1$`\,"@<$`/SX
+M]._KZ.7BX-_?X.'DY^KM[_#Q\O/S\_3U]?;W]_CY^?K\_@`#!@D-$149'"`B
+M)"4F)B8E(R$?'!D6$Q`-"@@&!04%!0<)"PT/$1(1$0\-"P@$`?[Z]O+NZN;D
+MXN#@X.+DYNKL[O#R\O/S\_/T]/7V]O?X^?K[_?\!!`<+#Q(6&AX@(B0E)20C
+M(B`>&Q@5$0\,"0<&!00$!08("@T/$!$1$1`.#`D&`__\^/3P[.GFY.+AX>+D
+MYNGL[O#R\_/S\_/T]/3U]O?W^/K[_/X!!`8)#1$5&!P>(2,C(R,B(1\=&A<4
+M$0X+"0<%!`0$!`4'"0P.$!$2$1`/#0H(!`'^^O;S[^OIYN3CX^/DYNGL[O#R
+M\_3T]/3T]/3U]O?W^/G[_/X``@4)#`\3%AD='R$B(B(A(!X<&1<4$0X+"0<%
+M!`,#!`4&"`L-#Q`1$1$/#@L)!@,`_/CU\>WKZ.;EY.3DYNCK[?#R\_3T]/3T
+M]/3U]?;W^/GZ_/W_`@0'"@X1%!<:'1\@(2$@'QT;&!83$`T*"`8$`P("`@,%
+M!PD+#@\0$1`0#@P*!P0!_?KV\^_LZNCFY>3EYN?I[._Q\O/T]/3T]/3T]?7V
+M]_CY^_S^``(%"`L/$A48&AP>'Q\>'1L9%Q01#PP)!P4#`@$!`0(#!0<)#`X/
+M$!`/#@P*!P0"_OOX]/'MZ^GGYN7EY>?IZ^WO\?/S]/3S\_/S]/3U]O?X^OO]
+M_P$#!@D,#Q(5&!H<'1T='!H8%A,0#@L(!@0"`0`````"`P4("@P.#P\/#@P*
+M"`8#`/WY]O+O[.KHY^;EY>;HZNSN\/+S]/3T\_/S]/3U]O?X^?O\_@`"!0@*
+M#1`3%A@:&QL;&AD7%1(/#0H'!0,!`/___P`!`@0'"0L-#@\.#@T+"0<$`?[[
+M^/7Q[NSJZ.?FYN?HZNSN\/+S]/3T]/3T]/3U]O?X^?K\_@`"!`<*#`\2%!88
+M&AH:&A@7%1(0#0H(!0,!`/_^_O\``0,%"`H,#0X.#@T,"@@%`P#]^?;S\.WK
+MZ>CGY^?HZ>OM[_'S]/3T]/3T]/3U]O?X^?K[_?\!`P4("PX0$Q46&!D9&1@6
+M%!(/#`D'!`(`__[]_?[_``($!@D+#`T.#@T,"@@&!`'^^_CU\N_MZ^GHZ.?H
+MZ>KL[O#R\_3T]/3T]/3T]?;W^/G[_/X``@0&"0P.$1,4%A<7%Q85$Q$."P@&
+M`P'__OW\_/S]_@`"!0<)"PP-#0P+"@D&!`+_^_GV\O#MZ^KIZ.CHZ.KK[>_Q
+M\O/T]/3T\_3T]/7V]_CZ^_W_`0,%!PH,#A`2%!45%144$@\-"P@%`P'__?S[
+M^_O\_?\!`P4'"0L,#`P+"@D'!0,`_?KW]/'O[>OIZ.CHZ.GK[.[P\?/S]/3T
+M]/3T]/7V]_CY^_S^``($!@@+#0\1$A,4%!03$0\-"@<%`@#^_?S[^_O[_/X`
+M`@0&"`H+#`P+"@D(!@0!__SY]O/P[NSKZNGIZ>KK[.[O\?+S]/3T]/3T]?7V
+M]_CY^_S^``($!@@*#`X0$1,3$Q,2$0\-"@@%`P#^_?S[^OK[_/W_`0,&"`D+
+M#`P,"PH)!P4"`/[[^/7R\.[LZ^KJZNKK[.WO\?+S]/3U]?7U]?;V]_CY^_S^
+M_P$#!0<)"PT/$!$2$A(2$`\-"@<%`@#^_?OZ^OKZ^_S^``(%!PD*"PP+"PH)
+M"`8$`?_\^??T\>_M[.OJZNKK[.WN\/'S]/3U]?7U]?;V]_CY^OS]_P`"!`8(
+M"@P-#Q`1$1$0#PX,"@<$`@#^_/OZ^?GY^OO]_P$#!0<)"@H+"PH)"`8$`@#]
+M^O?U\_#N[>OJZNKKZ^SN[_#R\_3T]?7U]?7V]O?X^OO\_O\!`P4'"0H,#0X/
+M$!`/#@T+"08$`O_]^_KY^/CX^?K\_?\"!`8'"0H*"@H)"`8%`P#^_/GV]/'O
+M[NSKZ^OKZ^SM[_#Q\O/T]/7U]?7V]O?X^?O\_?\!`@0&"`D+#`T.#P\.#0P+
+M"08$`O_]^_KY^/CX^?G[_?X!`P4'"`D*"@H)"`<%!`+__?OX]?/Q[^WL[.OK
+M[.SM[_#Q\O/T]?7U]O;V]_CX^OO\_O\!`@0&!PD*#`T-#@X.#0P+"0<$`@#^
+M_/KY^/CX^?G[_/X``@0&"`D*"@H*"0@'!0,!__SZ^/7S\>_N[>WM[>WN[_#Q
+M\O/T]?;V]O?W^/CY^OO\_O\!`@0%!P@*"PP-#0T-#0P*"0<$`@#^_/OY^/CX
+M^/GZ_/W_`0,%!P@)"@H*"0@'!@0"`/[[^??T\O'O[N[M[>WN[_#Q\O/T]?;V
+M]_?W^/CY^OO\_O\``@,%!@@)"@L,#`T,#`L*"`8$`@#^_/KY^/CX^/GZ^_S^
+M``($!@<("0D)"0@'!@4#`?_]^OCV]/+P[^[N[>[N[^_P\?/T]?7V]_?W^/CY
+M^OO\_?X``0,$!0<("0H+"PL+"PH)!P8$`@#^_/KY^/?W]_CY^OO]_P$#!08'
+M"`D)"0@'!@4#`@#]^_GW]?/Q\._N[N[N[^_P\?+S]/7V]O?W^/CY^OO\_?[_
+M`0(#!08'"`D*"@L+"@D(!P4$`@#^_/KY^/?W]_CX^OO]_@`"!`4'"`@)"0@(
+M!P8$`P'__?OX]O3S\?#O[^_O[_#P\?+S]/7V]_?X^/GY^OO\_?[_`0($!08'
+M"`D*"@H*"@D(!P4$`@#^_/OY^/CW]_CY^OO\_@`"!`4'"`@)"0D("`<%!`(`
+M_OSZ^/;U\_+Q\/#P\/#Q\O/T]?;V]_CY^?KZ^_S\_?\``0($!08'"`D*"@H*
+M"@D(!P8$`@'__?OZ^?CX^/CY^OO\_@`!`P4&!P@)"0D)"`<&!0,"`/[\^OCV
+M]//R\?'Q\?'Q\O/T]?;V]_CY^?K[^_S]_O\``0($!08'"`D)"@H*"0D(!P4$
+M`@'__?SZ^?CX^/CX^?K\_?\!`@0%!P@("0D)"`<'!@0"`?_]^_GW]O3S\O'Q
+M\?'Q\O/S]/7V]_CY^?KZ^_S\_?[_`0(#!`4&!P@("0D)"`@'!@4#`@#^_?OZ
+M^?CW]_?X^?K[_/X``0,$!@<'"`@("`<'!@0#`0#^_/KX]O7T\_+Q\?'R\O/S
+M]/7V]_CX^?KZ^_S\_?[_``$#!`4&!P<("`@("`<&!@0#`@#^_?OZ^?CX]_?X
+M^/GZ_/W_`0($!08'"`@("`@'!@4$`@'__?OY^/;U]//R\O+R\O/S]/7V]_CX
+M^?K[^_S]_O[_``$#!`4&!@<("`@("`<&!00#`@#__?S[^OGX^/CX^?GZ_/W_
+M``(#!08'!P@("`@(!P8%!`(`__W[^OCW]?3T\_/S\_3T]?;V]_CY^OO\_/W^
+M_O\``0(#!`4&!P<("`@("`<'!@4#`@'__OS[^OGY^/CX^?K[_/W_``(#!08'
+M!P@("`@("`<&!0,"`/[]^_KX]_;U]/3T]/3U]?;W^/CY^OO\_?W^__\``0(#
+M!`4&!P<("`@("`<'!@4#`@'__OW[^_KY^/CY^?KZ_/W^``$#!`4&!P@("`@(
+M"`<&!00#`?_^_/OY^/?V]?7T]/7U]?;W]_CY^OO\_/W^__\``0(#!`4%!@<'
+M"`@(!P<&!00#`@#__OS[^OGY^/CX^?GZ^_S]_P`"`P0%!@<'"`@(!P<&!00#
+M`@#^_?OZ^/?V]O7U]?7U]?;V]_CY^?K[_/W^_O\``0$"`P0%!@8'!P<'!P8&
+M!00#`0#__?S[^OGY^/CX^/GZ^_S]_@`!`@0%!08'!P<'!P<&!@4$`@'__OS[
+M^OCW]_;U]?7U]O;W]_CY^OK[_/W^__\``0("`P0%!@8'!P<'!P8&!00#`0#_
+M_OW[^_KY^?CX^?GZ^_S]_O\!`@,$!08'!P<'!P<'!@4$`P(!__[\^_KY^/?W
+M]O;V]O?W^/CY^OO\_?[^_P`!`0(#!`0%!@8'!P<'!P<&!00#`@$`_OW\^_KZ
+M^?GY^?KZ^_S]_O\!`@,$!08'!P@("`@'!P8%!`,"`?_^_/OZ^?CX]_?W]_?X
+M^/GZ^OO\_?[__P`!`@(#!`4%!@<'!P<'!P<&!00#`@$`__[\_/OZ^OGY^?KZ
+M^_S]_O\``@,$!08&!P<("`@(!P<&!00#`0#__?S[^OGX^/CX^/CX^/GZ^OO\
+M_?[__P`!`@(#!`0%!@8'!P<'!P8&!00#`@$`__W\^_OZ^OGY^?KZ^_O\_?X`
+M`0(#!`4%!@<'!P<'!P8&!00#`@#__OW[^OKY^/CX^/CX^/GY^OO[_/W^_P`!
+M`0(#`P0%!08&!@<&!@8%!00#`@#__OW\^_OZ^?GY^?GZ^OO\_?[_``$"`P0%
+M!08&!P<'!P8&!00#`@$`__W\^_KY^?CX^/CX^/GY^OO[_/W^_P`!`0(#`P0%
+M!08&!@8&!@8%!00#`@$`_OW\_/OZ^OGY^?GZ^OO\_?[_``$"`P0$!08&!P<'
+M!P<&!@4$`P(!`/[]_/OZ^OGY^?GY^?GZ^OO\_/W^_P`!`@(#!`0%!@8&!P<'
+M!P8&!00#`@$`__[]_/O[^OKZ^OKZ^_O\_?[_``$"`P0$!08&!P<'!P<'!@8%
+M!`,"`0#__OS\^_KZ^OGY^OKZ^_O\_?[__P`!`@,#!`4%!@8'!P<'!P8&!00$
+M`P(`__[^_?S[^_OZ^OO[^_S\_?[_``$"`P,$!08&!@<'!P<'!@8%!00#`@#_
+M_OW\_/O[^OKZ^OK[^_O\_?[^_P`!`@,#!`4%!@8&!P<'!P8&!00#`P(`___^
+M_?S[^_OZ^OK[^_O\_?[^_P`!`@,$!`4%!@8&!P<&!@8%!`0#`@$`__[]_/O[
+M^OKZ^OKZ^_O\_/W^_P```0(#`P0%!08&!@8&!@8%!00#`@$`__[]_/S[^_KZ
+M^OKZ^_O\_/W^__\``0(#`P0%!04&!@8&!@8%!00#`@$`__[]_/S[^_KZ^OKZ
+M^_O[_/W^_O\``0("`P0$!04&!@8&!@8%!00#`@$`__[^_?S[^_OZ^OKZ^_O\
+M_/W^_O\``0("`P0$!04&!@8&!@8%!00#`P(!`/_^_?S\^_O[^_O[^_O\_/W^
+M__\``0(#`P0$!04&!@8&!@8%!00#`P(!`/_^_?W\_/O[^_O[^_S\_?W^__\`
+M`0("`P0$!04&!@8&!@8&!04$`P,"`0#__OW]_/S\^_O\_/S\_?W^_P```0(#
+M!`0%!08&!@8&!@8&!04$`P(!`/___OW\_/S[^_O[_/S\_?W^__\``0("`P0$
+M!04&!@8&!@8&!@4%!`,"`0$`__[^_?S\_/S\_/S]_?[^_P```0(#`P0%!08&
+M!@8&!@8&!04$`P(!``#__OW]_/S\^_O\_/S\_?W^__\``0$"`@,$!`4%!08&
+M!@8&!@4%!`,#`@$`__[^_?W\_/S\_/S\_?W^_O\``0$"`P,$!04%!@8&!@4%
+M!00#`P(!`/_^_OW\_/S[^_O[^_S\_/W]_O__```!`@(#`P0$!04%!04%!04$
+M!`,"`@$`___^_?W\_/S\_/S\_/W]_O__``$"`@,$!`4%!04%!04%!`0#`P(!
+M`/_^_OW\_/S[^_O[^_S\_/W]_O[_```!`0("`P,$!`4%!04%!04%!`,#`@$!
+M`/_^_OW]_/S\_/S\_?W^_O__``$!`@,#!`0%!04%!04%!`0#`P(!``#__OW]
+M_/S\_/S\_/S\_?W^_O__```!`0(#`P0$!`4%!04&!04%!00$`P(!`0#___[^
+M_?W]_?W]_?[^__\```$"`@,$!`4%!08&!@4%!00$`P("`0#___[]_?W\_/S\
+M_/S]_?W^_O__```!`0("`P,$!`4%!04&!@4%!00$`P,"`0$`___^_O[]_?W]
+M_O[^__\```$"`@,$!`4%!08&!@4%!00$`P,"`0``__[^_?W]_/S\_/W]_?W^
+M_O__```!`0("`P,#!`0%!04%!04%!04$!`,"`@$``/_^_O[]_?W]_?[^_O__
+M``$!`@,#!`0$!04%!04%!`0#`P(!`0#___[]_?S\_/S\_/S\_?W]_O[__P``
+M``$!`@(#`P,$!`0$!04%!`0$`P,"`0$``/_^_O[]_?W]_?W^_O[__P`!`0("
+M`P0$!`0%!00$!`0#`P(!`0#__O[]_?S\_/S\_/S\_/W]_?[^__\```$!`0("
+M`P,#!`0$!`0$!`0$`P,"`@$!`/___O[^_?W]_?W^_O[__P```0("`P,$!`0$
+M!00$!`0#`P(!`0#___[^_?W\_/S\_/S\_?W]_O[^__\````!`0("`P,#!`0$
+M!`4%!`0$!`,#`@(!`0``___^_O[^_O[^_O__```!`0(#`P0$!`4%!04%!`0$
+M`P,"`0$`___^_OW]_?W]_?W]_?W^_O[___\```$!`@("`P,#!`0$!04%!04$
+M!`0#`P("`0$``/____[^_O[_____```!`0(#`P0$!`4%!04%!`0$`P,"`0$`
+M`/_^_O[]_?W]_?W]_?W^_O[___\```$!`0("`@,#`P0$!`0%!04$!`0#`P,"
+M`0$```#______O[^____```!`0("`P,$!`0$!`0$!`0#`P("`0$`___^_OW]
+M_?W]_/W]_?W]_?[^_O___P```0$!`@("`P,#!`0$!`0$!`,#`P("`0$``/__
+M__[^_O[^_O[__P````$!`@(#`P0$!`0$!`,#`P(!`0``__[^_OW]_?S\_/S\
+M_?W]_?W^_O[__P`````!`0("`@,#`P,#!`0$`P,#`P("`0$``/_____^_O[^
+M_O___P````$!`@(#`P,$!`0$`P,#`@(!`0``___^_OW]_?W\_/S]_?W]_?[^
+M_O[___\````!`0$"`@(#`P,#!`0$!`,#`P("`@$!````_____________P``
+M`0$"`@(#`P0$!`0$!`0#`P("`0$``/___O[^_?W]_?W]_?W]_O[^_____P``
+M``$!`0("`@,#`P,$!`0$!`0$`P,#`@(!`0$```#_________`````0$"`@,#
+M`P0$!`0$!`0#`P,"`@$!``#___[^_OW]_?W]_?[^_O[^_____P````$!`0$"
+M`@(#`P,#!`0$!`0$`P,#`@("`0$`````________`````0$!`@(#`P,$!`0$
+M!`0#`P,"`@$!``#___[^_OW]_?W]_?W^_O[^_O[___\``````0$!`0("`@(#
+M`P,#`P,#`P,"`@(!`0$```#___________\````!`0("`@,#`P,#`P,#`@("
+M`0$``/___O[^_?W]_?W]_?W]_?W^_O[^_____P`````!`0$!`@("`@,#`P,#
+M`P("`@(!`0```/______________`````0$"`@(#`P,#`P,#`@("`0$``/__
+M_O[^_?W]_?W]_?W]_?W^_O[^______\``````0$!`0("`@(#`P,#`P,"`@(!
+M`0$`````__________\````!`0$"`@(#`P,#`P,#`P("`0$!``#____^_O[^
+M_?W]_?[^_O[^_O[_____```````!`0$!`@("`@,#`P,#`P,#`P("`@$!`0``
+M````_P````````$!`0("`@,#`P,#`P,#`P,"`@$!````_____O[^_O[^_O[^
+M_O[^_O______```````!`0$!`@("`@,#`P,#`P,#`P("`@(!`0$`````````
+M```````!`0("`@(#`P,#`P,#`P("`@$!````_____O[^_O[^_O[^_O[^_O[_
+M_____P````````$!`0("`@("`@,#`P,"`@("`@$!`0````#_______\`````
+M`0$!`0("`@(#`@("`@("`0$```#____^_O[^_?W]_?W]_?[^_O[^_O[_____
+M_P```````0$!`0$"`@("`@("`@("`0$!`````/___________P````$!`0$"
+M`@("`@("`@(!`0$```#___[^_O[^_?W]_?W]_O[^_O[^_O[_______\`````
+M``$!`0$"`@("`@("`@("`0$!`0````#__________P`````!`0$"`@("`@("
+M`@("`0$!``#______O[^_O[^_O[^_O[^_O[_________```````!`0$!`0("
+M`@("`@("`@("`@(!`0$!`````````````````0$!`0("`@("`@,"`@("`@$!
+M`0```/_____^_O[^_O[^_O[^_________P`````````!`0$!`0("`@("`@("
+M`@("`@("`0$!`0$``````````````0$!`0("`@("`@("`@("`@$!`0```/__
+M___^_O[^_O[^_O[^_O________\``````````0$!`0$"`@("`@("`@("`@(!
+M`0$!`0`````````````````!`0$!`0("`@("`@(!`0$!``#______O[^_O[^
+M_O[^_O[^_O[^_O___________P````````$!`0$!`0("`@("`0$!`0$`````
+M`/________\```````$!`0$!`0$!`0$!`0$```#____^_O[^_O[^_O[^_O[^
+M_O[^_O[^__________\```````$!`0$!`0$!`@(!`0$!`0$```````#_____
+M__\```````$!`0$!`0$!`0$!`0$`````_____O[^_O[^_O[^_O[^_O[^_O[_
+M_________P````````$!`0$!`@("`@("`@("`0$!`0$````````````````!
+M`0$!`0$"`@("`@(!`0$!`````/_______O[^_O[^_O[^____________````
+M`````````0$!`0$"`@("`@("`@("`@(!`0$!`0````````````$!`0$!`0("
+M`@("`@("`0$!`0````#________^_O[^_O[______________P``````````
+M``$!`0$!`@("`@("`@("`@$!`0$!`0```````````````0$!`0$!`0$!`0$!
+M`0$!`````/_____^_O[^_O[^_O[^_O[^_O[^____________``````````$!
+M`0$!`0$!`0$!`0$!`0$```````````````````````$!`0$!`0$!``````#_
+M______[^_O[^_O[^_O[^_O[^_O[^_O[___________\``````````0$!`0$!
+M`0$!`0$!`0````````````````````````$!`0$!`0$!`0````#_______[^
+M_O[^_O[^_O[^_O[^_O[^_O____________\````````!`0$!`0$!`0$!`0$!
+M`0$!`0````````````````$!`0$!`0$!`0$!`0$!``````#________^__[^
+M_O[^_________________P````````````$!`0$!`0$"`@("`@(!`0$!`0$!
+M`0`````````!`0$!`0$!`0$!`0$!`0$!`0``````____________________
+M_____________P````````````$!`0$!`0$!`@("`0(!`0$!`0$!`0``````
+M`````0$!`0$!`0$!`0$!`0$!``````#__________O[^_O[^_O[^________
+M_____________P`````````!`0$!`0$!`0$!`0$!`0``````````````````
+M`````0$!`0$`````````_______^_O[^_O[^_O[^_O[^_O[^_O[^_O______
+M_________P`````````!`0$!`0$!`0$`````````````````````````````
+M`0``````````_________O[^_O[^_O[^_O[^_O[^_O[^________________
+M_P`````````!`0$!`0$!`0$!`0$````````````````````!`0$!`0$!`0$`
+M````````________________________________________````````````
+M`0$!`0$!`0$!`0$!`0$!`0$!`0```````0$!`0$!`0$!`0$!`0$!`0``````
+M`/___________________________________P```````````````0$!`0$!
+M`0$!`0$!`0$!`0$!`0```````0$!`0$!`0$!`0$!`0$!`````````/______
+M__________________________________\```````````````$!`0$!`0$!
+M`0```````````````````````````````````````/____________[^_O[^
+M_O[^_O[^_O[^_O___________________P``````````````````````````
+M````````````````````````````````______________[^_O[^_O[^_O[^
+M_O[______________________P``````````````````````````````````
+M``````````````````````````#_________________________________
+M_____________P`````````````!`0$!`0$!`0$!`0$!``````````````$!
+M`0$!`0$!`0$!````````````__________________________________\`
+M`````````````````0$!`0$!`0$!`0$!`0$!`0$!`````````0$!`0$!`0$!
+M`0$`````````````______________________________________\`````
+M``````````````$!`0$!`0$!````````````````````````````````````
+M`/_______________________________________________________P``
+M``````````````````````````````````````````````````#_________
+M______________[___________________________________\`````````
+M````````````````````````````````````````````________________
+M____________________________________`````````````````0`!`0$!
+M`0``````````````````````````````````````````________________
+M________________``````````````````````````$!`0$!`0$!`0$!`0$!
+M`0$``````````````````````````````````/______________________
+M__________\```````````````````````````$!`0$!`0$`````````````
+M``````````````````````#_____________________________________
+M__________________\`````````````````````````````````````````
+M`````````/__________________________________________________
+M______________\`````````````````````````````````````````````
+M`/__________________________________________________________
+M_P``````````````````````````````````````````````````````````
+M`````/________________________________\`````````````````````
+M```````!`0$!`0$!`0$!`0$!`0``````````````````````````````````
+M``#______________________P``````````````````````````````````
+M``$!`0$!`0$!`0$```````````````````````````````#_____________
+M________________________________________````````````````````
+M``````````````````````````````#_____________________________
+M______________________________________\`````````````````````
+M`````````````````````/______________________________________
+M____________________________````````````````````````````````
+M``````````````````````````#_________________________________
+M````````````````0T]-30```!(``0``+!8`"$`-K$0```````!-05)+````
+M`@``24Y35````!0\``!_`'\``````````````````$%04$P```&H4V0R80`"
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````/@````````````````````````````
+M````````````````````````````````````````````````````!`@`````
+M``D`(P````````````````!X````!``$``````"[_`#___^``````0&H!E%5
+M;FET<P#0RL7!O;JWM;2UMKBZO<#$Q\K-T-/5V-O=X`````$"[08@<V%M<',`
+M``0)#Q4;(2<N-#H_0TA+3E%45UI<7V%C96<``````````'-T````````````
+M```G`"\`#__V__D``0``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````$````!>````'@```!6`&X`9P!:`$L`.P`H
+M``W_Y_^W_W7_)/Z^_D+]M/TI_,8$2&%R<($"````04E&1E-D,F$`````````
+M````$J<`````04E&1E-D,F$```````````````````````````````"G/:V/
+M```N(@```<X`.0`T`"H`(``5``P`!0`!_____?_[__K_]__U__;_]__[__\`
+M!0`*`!(`&0`@`"0`)@`F`"0`(P`A`"(`)@`L`#4`/@!'`$H`1P!``#4`+``E
+M`"``'``9`!4`#P`*``<`!0`#``(``P`'``\`'``I`#8`/0`_`#H`,P`H`!\`
+M%@`0````&@`I``\":@,Q`"H``P)M`ST`*0`/`D$#(@$`````&@`I``\!4`'Q
+M`"H``P)M`ST`````````````````&@`L`!8!/@'<`"H``P)M`ST`````````
+M````````&@`````````````````````````````````````!`````7@```!X
+M````5@!QN+P<I@```!P`5@``5W-T80`#``H``?__`````````````O__````
+M'@```````___````/```````!/__````6@``````````````````````````
+B````````````````````````````````````````````````
+`
+end
diff --git a/sys/share/tclib.c b/sys/share/tclib.c
new file mode 100644 (file)
index 0000000..0ccfcb3
--- /dev/null
@@ -0,0 +1,482 @@
+/*     SCCS Id: @(#)tclib.c    3.4     1996/02/25      */
+/* Copyright (c) Robert Patrick Rankin, 1995                     */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* termcap library implementation */
+
+#include "config.h"
+
+#ifndef TERMCAP                /* name of default termcap file */
+#define TERMCAP "/etc/termcap"
+#endif
+#ifndef TCBUFSIZ       /* size of tgetent buffer; Unix man page says 1024 */
+#define TCBUFSIZ 1024
+#endif
+#define ESC    '\033'  /* termcap's '\E' */
+#define BEL    '\007'  /* ANSI C's '\a' (we assume ASCII here...) */
+
+/* exported variables, as per man page */
+char  PC;
+char *BC, *UP;
+short ospeed;
+
+/* exported routines */
+int   FDECL(tgetent,  (char *,const char *));
+int   FDECL(tgetflag, (const char *));
+int   FDECL(tgetnum,  (const char *));
+char *FDECL(tgetstr,  (const char *,char **));
+char *FDECL(tgoto,    (const char *,int,int));
+char *FDECL(tparam,   (const char *,char *,int,int,int,int,int));
+void  FDECL(tputs,    (const char *,int,int (*)()));
+
+/* local support data */
+static char *tc_entry;
+static char bc_up_buf[24];
+#ifndef NO_DELAY_PADDING
+/* `ospeed' to baud rate conversion table, adapted from GNU termcap-1.2 */
+static short baud_rates[] = {
+       0,   50,   75,  110,  135,  150,
+# ifdef VMS
+           300,  600, 1200, 1800, 2000, 2400, 3600, 4800, 7200,
+# else         /* assume Unix */
+      200,  300,  600, 1200, 1800,       2400,       4800,
+# endif
+     9600, -192, -384,         /* negative is used as `100 * abs(entry)' */
+# ifdef VMS
+     -576, -768, -1152,
+# endif
+};
+#endif /* !NO_DELAY_PADDING */
+
+/* local support code */
+static int        FDECL(tc_store, (const char *,const char *));
+static char      *FDECL(tc_find,  (FILE *,const char *,char *,int));
+static char      *FDECL(tc_name,  (const char *,char *));
+static const char *FDECL(tc_field, (const char *,const char **));
+
+#ifndef min
+#define min(a,b) ((a)<(b)?(a):(b))
+#endif
+
+/* retrieve the specified terminal entry and return it in `entbuf' */
+int
+tgetent(entbuf, term)
+    char *entbuf;      /* size must be at least [TCBUFSIZ] */
+    const char *term;
+{
+    int result;
+    FILE *fp;
+    char *tc = getenv("TERMCAP");
+
+    tc_entry = entbuf;
+    if (!entbuf || !term)
+       return -1;
+    /* if ${TERMCAP} is found as a file, it's not an inline termcap entry */
+    if ((fp = fopen(tc ? tc : TERMCAP, "r")) != 0)
+       tc = 0;
+    /* if ${TERMCAP} isn't a file and `term' matches ${TERM}, use ${TERMCAP} */
+    if (tc) {
+       char *tm = getenv("TERM");
+       if (tm && strcmp(tm, term) == 0)
+           return tc_store(term, tc);
+       fp = fopen(TERMCAP, "r");
+    }
+    /* otherwise, look `term' up in the file */
+    if (fp) {
+       char wrkbuf[TCBUFSIZ];
+       tc = tc_find(fp, term, wrkbuf, (int)(sizeof wrkbuf - strlen(term)));
+       result = tc_store(term, tc);
+       (void) fclose(fp);
+    } else {
+       result = -1;
+    }
+    return result;
+}
+
+/* copy the entry into the output buffer */
+static int
+tc_store(trm, ent)
+    const char *trm, *ent;
+{
+    const char *bar, *col;
+    char *s;
+    size_t n;
+    int k;
+
+    if (!ent || !*ent || !trm || !*trm || (col = index(ent, ':')) == 0)
+       return 0;
+    (void) strcpy(tc_entry, trm);
+    if (((bar = index(ent, '|')) != 0 && bar < col)
+     || ((long)(n = strlen(trm)) == (long)(col - ent)
+           && strncmp(ent, trm, n) == 0))
+       (void) strcat(tc_entry, col);
+    else if (*ent == ':')
+       (void) strcat(tc_entry, ent);
+    else
+       (void) strcat(strcat(tc_entry, ":"), ent);
+
+    /* initialize global variables */
+    k = tgetnum("pc");
+    PC = (k == -1) ? '\0' : (char)k;
+    BC = s = bc_up_buf;
+    if (!tgetstr("bc", &s))  (void)strcpy(s, "\b"),  s += 2;
+    UP = s;
+    (void)tgetstr("up", &s);
+#ifndef NO_DELAY_PADDING
+    /* caller must set `ospeed' */
+    if ((int)ospeed >= (int)SIZE(baud_rates))
+       ospeed = (short)(SIZE(baud_rates) - 1);
+    else if (ospeed < 0)
+       ospeed = 0;
+#endif /* !NO_DELAY_PADDING */
+
+    return 1;
+}
+
+/* search for an entry in the termcap file */
+static char *
+tc_find(fp, term, buffer, bufsiz)
+    FILE *fp;
+    const char *term;
+    char *buffer;
+    int bufsiz;
+{
+    int in, len, first, skip;
+    char *ip, *op, *tc_fetch, tcbuf[TCBUFSIZ];
+
+    buffer[0] = '\0';
+    do {
+       ip = tcbuf,  in = min(bufsiz,TCBUFSIZ);
+       first = 1,  skip = 0;
+       /* load entire next entry, including any continuations */
+       do {
+           if (!fgets(ip, min(in,BUFSIZ), fp))  break;
+           if (first)  skip = (*ip == '#'),  first = 0;
+           len = (int)strlen(ip);
+           if (!skip && len > 1
+            && *(ip + len - 1) == '\n' && *(ip + len - 2) == '\\')
+               len -= 2;
+           ip += len,  in -= len;
+       } while (*(ip - 1) != '\n' && in > 0);
+       if (ferror(fp) || ip == buffer || *(ip - 1) != '\n')
+           return (char *)0;
+       *--ip = '\0';           /* strip newline */
+       if (!skip)  ip = tc_name(term, tcbuf);
+    } while (skip || !ip);
+
+    /* we have the desired entry; strip cruft and look for :tc=other: */
+    tc_fetch = 0;
+    for (op = buffer; *ip; ip++) {
+       if (op == buffer || *(op - 1) != ':'
+        || (*ip != ' ' && *ip != '\t' && *ip != ':'))
+           *op++ = *ip,  bufsiz -= 1;
+       if (ip[0] == ':' && ip[1] == 't' && ip[2] == 'c' && ip[3] == '=') {
+           tc_fetch = &ip[4];
+           if ((ip = index(tc_fetch, ':')) != 0)  *ip = '\0';
+           break;
+       }
+    }
+    *op = '\0';
+
+    if (tc_fetch) {
+       rewind(fp);
+       tc_fetch = tc_find(fp, tc_fetch, tcbuf, min(bufsiz,TCBUFSIZ));
+       if (!tc_fetch)
+           return (char *)0;
+       if (op > buffer && *(op - 1) == ':' && *tc_fetch == ':')
+           ++tc_fetch;
+       strcpy(op, tc_fetch);
+    }
+    return buffer;
+}
+
+/* check whether `ent' contains `nam'; return start of field entries */
+static char *
+tc_name(nam, ent)
+    const char *nam;
+    char *ent;
+{
+    char *nxt, *lst, *p = ent;
+    size_t n = strlen(nam);
+
+    if ((lst = index(p, ':')) == 0)  lst = p + strlen(p);
+
+    while (p < lst) {
+       if ((nxt = index(p, '|')) == 0 || nxt > lst)  nxt = lst;
+       if ((long)(nxt - p) == (long)n && strncmp(p, nam, n) == 0)
+           return lst;
+       p = nxt + 1;
+    }
+    return (char *)0;
+}
+
+/* look up a numeric entry */
+int
+tgetnum(which)
+    const char *which;
+{
+    const char *q, *p = tc_field(which, &q);
+    char numbuf[32];
+    size_t n;
+
+    if (!p || p[2] != '#')
+       return -1;
+    p += 3;
+    if ((n = (size_t)(q - p)) >= sizeof numbuf)
+       return -1;
+    (void) strncpy(numbuf, p, n);
+    numbuf[n] = '\0';
+    return atoi(numbuf);
+}
+
+/* look up a boolean entry */
+int
+tgetflag(which)
+    const char *which;
+{
+    const char *p = tc_field(which, (const char **)0);
+
+    return (!p || p[2] != ':') ? 0 : 1;
+}
+
+/* look up a string entry; update `*outptr' */
+char *
+tgetstr(which, outptr)
+    const char *which;
+    char **outptr;
+{
+    int n;
+    char c, *r, *result;
+    const char *q, *p = tc_field(which, &q);
+
+    if (!p || p[2] != '=')
+       return (char *)0;
+    p += 3;
+    if ((q = index(p, ':')) == 0)  q = p + strlen(p);
+    r = result = *outptr;
+    while (p < q) {
+       switch ((*r = *p++)) {
+        case '\\':
+           switch ((c = *p++)) {
+            case 'E':  *r = ESC;   break;
+            case 'a':  *r = BEL;   break;
+            case 'b':  *r = '\b';  break;
+            case 'f':  *r = '\f';  break;
+            case 'n':  *r = '\n';  break;
+            case 'r':  *r = '\r';  break;
+            case 't':  *r = '\t';  break;
+            case '0': case '1': case '2': case '3':
+            case '4': case '5': case '6': case '7':
+                       n = c - '0';
+                       if (*p >= '0' && *p <= '7')  n = 8 * n + (*p++ - '0');
+                       if (*p >= '0' && *p <= '7')  n = 8 * n + (*p++ - '0');
+                       *r = (char)n;
+                       break;
+         /* case '^': case '\\': */
+            default:   *r = c;     break;
+           }
+           break;
+        case '^':
+           *r = (*p++ & 037);
+           if (!*r)  *r = (char)'\200';
+           break;
+        default:
+           break;
+       }
+       ++r;
+    }
+    *r++ = '\0';
+    *outptr = r;
+    return result;
+}
+
+/* look for a particular field name */
+static const char *
+tc_field(field, tc_end)
+    const char *field;
+    const char **tc_end;
+{
+    const char *end, *q, *p = tc_entry;
+
+    end = p + strlen(p);
+    while (p < end) {
+       if ((p = index(p, ':')) == 0)
+           break;
+       ++p;
+       if (p[0] == field[0] && p[1] == field[1]
+        && (p[2] == ':' || p[2] == '=' || p[2] == '#' || p[2] == '@'))
+           break;
+    }
+    if (tc_end) {
+       if (p) {
+           if ((q = index(p + 2, ':')) == 0)  q = end;
+       } else
+           q = 0;
+       *tc_end = q;
+    }
+    return p;
+}
+
+static char cmbuf[64];
+
+/* produce a string which will position the cursor at <row,col> if output */
+char *
+tgoto(cm, col, row)
+    const char *cm;
+    int col, row;
+{
+    return tparam(cm, cmbuf, (int)(sizeof cmbuf), row, col, 0, 0);
+}
+
+/* format a parameterized string, ala sprintf */
+char *
+tparam(ctl, buf, buflen, row, col, row2, col2)
+    const char *ctl;   /* parameter control string */
+    char *buf;         /* output buffer */
+    int buflen;                /* ought to have been `size_t'... */
+    int row, col, row2, col2;
+{
+    int atmp, ac, av[5];
+    char c, *r, *z, *bufend, numbuf[32];
+    const char *fmt;
+#ifndef NO_SPECIAL_CHARS_FIXUP
+    int bc = 0, up = 0;
+#endif
+
+    av[0] = row,  av[1] = col,  av[2] = row2,  av[3] = col2,  av[4] = 0;
+    ac = 0;
+    r = buf,  bufend = r + buflen - 1;
+    while (*ctl) {
+       if ((*r = *ctl++) == '%') {
+           if (ac > 4)  ac = 4;
+           fmt = 0;
+           switch ((c = *ctl++)) {
+            case '%':                  break;  /* '%' already copied */
+            case 'd':  fmt = "%d";     break;
+            case '2':  fmt = "%02d";   break;
+            case '3':  fmt = "%03d";   break;
+            case '+':  /*FALLTHRU*/
+            case '.':  *r = (char)av[ac++];
+                       if (c == '+')  *r += *ctl++;
+                       if (!*r) {
+                           *r = (char)'\200';
+                       } else {
+#ifndef NO_SPECIAL_CHARS_FIXUP
+                           /* avoid terminal driver intervention for
+                              various control characters, to prevent
+                              LF from becoming CR+LF, for instance; only
+                              makes sense if this is a cursor positioning
+                              sequence, but we have no way to check that */
+                           while (index("\004\t\n\013\f\r", *r)) {
+                               if (ac & 1) {           /* row */
+                                   if (!UP || !*UP)  break;    /* can't fix */
+                                   ++up;   /* incr row now, later move up */
+                               } else {                /* column */
+                                   if (!BC || !*BC)  break;    /* can't fix */
+                                   ++bc;   /* incr column, later backspace */
+                               }
+                               (*r)++;
+                           }
+#endif /* !NO_SPECIAL_CHARS_FIXUP */
+                       }                                               break;
+            case '>':  if (av[ac] > (*ctl++ & 0377))
+                           av[ac] += *ctl;
+                       ++ctl;                                          break;
+            case 'r':  atmp = av[0];  av[0] = av[1];  av[1] = atmp;
+                       atmp = av[2];  av[2] = av[3];  av[3] = atmp;
+                       --r;                                            break;
+            case 'i':  ++av[0];  ++av[1];  ++av[2];  ++av[3];
+                       --r;                                            break;
+            case 'n':  av[0] ^= 0140;  av[1] ^= 0140;
+                       av[2] ^= 0140;  av[3] ^= 0140;
+                       --r;                                            break;
+            case 'B':  av[0] = ((av[0] / 10) << 4) + (av[0] % 10);
+                       av[1] = ((av[1] / 10) << 4) + (av[1] % 10);
+                       av[2] = ((av[2] / 10) << 4) + (av[2] % 10);
+                       av[3] = ((av[3] / 10) << 4) + (av[3] % 10);
+                       --r;                                            break;
+            case 'D':  av[0] -= (av[0] & 15) << 1;
+                       av[1] -= (av[1] & 15) << 1;
+                       av[2] -= (av[2] & 15) << 1;
+                       av[3] -= (av[3] & 15) << 1;
+                       --r;                                            break;
+            default:   *++r = c;       break;  /* erroneous entry... */
+           }
+           if (fmt) {
+               (void) sprintf(numbuf, fmt, av[ac++]);
+               for (z = numbuf; *z && r <= bufend; z++)
+                   *r++ = *z;
+               --r;            /* will be re-incremented below */
+           }
+       }
+       if (++r > bufend)
+           return (char *)0;
+    }
+#ifndef NO_SPECIAL_CHARS_FIXUP
+    if (bc || up) {
+       while (--bc >= 0)
+           for (z = BC; *z && r <= bufend; z++)
+               *r++ = *z;
+       while (--up >= 0)
+           for (z = UP; *z && r <= bufend; z++)
+               *r++ = *z;
+       if (r > bufend)
+           return (char *)0;
+    }
+#endif /* !NO_SPECIAL_CHARS_FIXUP */
+    *r = '\0';
+    return buf;
+}
+
+/* send a string to the terminal, possibly padded with trailing NULs */
+void
+tputs( string, range, output_func )
+const char *string;    /* characters to output */
+int range;             /* number of lines affected, used for `*' delays */
+int (*output_func)();  /* actual output routine; return value ignored */
+{
+    register int c, num = 0;
+    register const char *p = string;
+
+    if (!p || !*p)
+       return;
+
+    /* pick out padding prefix, if any */
+    if (*p >= '0' && *p <= '9') {
+       do {            /* note: scale `num' by 10 to accommodate fraction */
+           num += (*p++ - '0'),  num *= 10;
+       } while (*p >= '0' && *p <= '9');
+       if (*p == '.')
+           ++p,  num += (*p >= '0' && *p <= '9') ? (*p++ - '0') : 0;
+       if (*p == '*')
+           ++p,  num *= range;
+    }
+
+    /* output the string */
+    while ((c = *p++) != '\0') {
+       if (c == '\200')  c = '\0';     /* undo tgetstr's encoding */
+       (void) (*output_func)(c);
+    }
+
+#ifndef NO_DELAY_PADDING
+    /* perform padding */
+    if (num) {
+       long pad;
+
+       /* figure out how many chars needed to produce desired elapsed time */
+       pad = (long)baud_rates[ospeed];
+       if (pad < 0)  pad *= -100L;
+       pad *= (long)num;
+       /* 100000 == 10 bits/char * (1000 millisec/sec scaled by 10) */
+       num = (int)(pad / 100000L);     /* number of characters */
+
+       c = PC;         /* assume output_func isn't allowed to change PC */
+       while (--num >= 0)
+           (void) (*output_func)(c);
+    }
+#endif /* !NO_DELAY_PADDING */
+
+    return;
+}
+
+/*tclib.c*/
diff --git a/sys/share/termcap b/sys/share/termcap
new file mode 100644 (file)
index 0000000..6a9f37e
--- /dev/null
@@ -0,0 +1,173 @@
+#
+#      MS/PC-DOS ANSI.SYS termcap
+#
+ansi|color|ansi-color|ibm|ibmpc|ANSI.SYS color:\
+       :co#80:li#24:bs:pt:bl=^G:le=^H:do=^J:\
+       :cl=\E[H\E[2J:ce=\E[K:\
+       :ho=\E[H:cm=\E[%i%d;%dH:\
+       :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\
+       :ti=\E[0;44m:te=\E[0m:\
+       :so=\E[1;35;44m:se=\E[0;44m:\
+       :us=\E[1;31;44m:ue=\E[0;44m:\
+       :mb=\E[5m:md=\E[1m:me=\E[0;44m:
+mono|ansi-mono|ANSI.SYS:\
+       :co#80:li#24:bs:pt:bl=^G:le=^H:do=^J:\
+       :cl=\E[H\E[2J:ce=\E[K:\
+       :ho=\E[H:cm=\E[%i%d;%dH:\
+       :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\
+       :so=\E[1m:se=\E[m:us=\E[4m:ue=\E[m:\
+       :mb=\E[5m:md=\E[1m:me=\E[m:
+#
+#      This is a termcap for NNANSI.SYS (New & Improved NANSI.SYS),
+#      a faster and more complete public domain replacement for
+#      ANSI.SYS, and two other ANSI.SYS replacements, NANSI.SYS and
+#      ZANSI.SYS.
+#
+#      NANSI and ZANSI support line insert (al) and delete (dl)
+#      and character insert (ic) and delete (dc) where ANSI.SYS
+#      does not.  NNANSI.SYS also supports clear to end of display
+#      (cd), does reverse video (mr) properly, and emulates SGR
+#      more fully, allowing correct end sequences for standout (se)
+#      and end of underline (ue).
+#
+nnansi-mono|NNANSI.SYS:\
+       :co#80:li#25:bs:pt:bl=^G:le=^H:do=^J:\
+       :cl=\E[2J:cd=\E[J:ce=\E[K:\
+       :ho=\E[H:cm=\E[%i%d;%dH:\
+       :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\
+       :so=\E[1m:se=\E[2m:\
+       :us=\E[4m:ue=\E[24m:\
+       :mb=\E[5m:md=\E[1m:mh=\E[2m:mr=\E[7m:me=\E[m:\
+       :al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P:
+nnansi|NNANSI.SYS color:\
+       :co#80:li#25:bs:pt:bl=^G:le=^H:do=^J:\
+       :cl=\E[2J:cd=\E[J:ce=\E[K:\
+       :ho=\E[H:cm=\E[%i%d;%dH:\
+       :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\
+       :ti=\E[0;44m:te=\E[0m:\
+       :so=\E[1;35;44m:se=\E[2;37m:\
+       :us=\E[4m:ue=\E[24m:\
+       :mb=\E[5m:md=\E[1m:mh=\E[2m:mr=\E[7m:me=\E[0;44m:\
+       :al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P:
+nansi-mono|zansi-mono|N/ZANSI.SYS:\
+       :co#80:li#25:bs:pt:bl=^G:le=^H:do=^J:\
+       :cl=\E[2J:ce=\E[K:\
+       :ho=\E[H:cm=\E[%i%d;%dH:\
+       :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\
+       :ti=\E[0m:te=\E[0m:\
+       :so=\E[1;35m:se=\E[0m:\
+       :us=\E[1;31m:ue=\E[0m:\
+       :mb=\E[5m:md=\E[1m:mr=\E[7m:me=\E[m:\
+       :al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P:
+nansi|zansi|N/ZANSI.SYS color:\
+       :co#80:li#25:bs:pt:bl=^G:le=^H:do=^J:\
+       :cl=\E[2J:ce=\E[K:\
+       :ho=\E[H:cm=\E[%i%d;%dH:\
+       :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\
+       :ti=\E[0;44m:te=\E[0m:\
+       :so=\E[1;35;44m:se=\E[0;44m:\
+       :us=\E[1;31;44m:ue=\E[0;44m:\
+       :mb=\E[5m:md=\E[1m:mr=\E[7m:me=\E[0;44m:\
+       :al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P:
+#
+# For ST NetHack:
+#       for VT100/200/&c in VT52 mode, add :ti=\E[?2l:
+vt52|atari|DEC VT52:\
+       :co#80:li#24:bs:pt:bl=^G:le=^H:do=^J:\
+       :cl=\EH\EJ:ce=\EK:cd=\EJ:\
+       :ho=\EH:cm=\EY%+ %+ :\
+       :up=\EA:do=\EB:le=\EC:ri=\ED:nd=\EC:\
+       :ku=\EA:kd=\EB:kl=\EC:kr=\ED:kb=^H:\
+       :sr=\EI:as=\EF:ae=\EG:
+#
+# For Amiga or VMS NetHack:
+#       VT100 or clone without the advanced video option installed
+vt100|amiga|vt100-80|vt100-noavo|DEC VT100:\
+       :co#80:li#24:bs:pt:am:mi:bl=^G:le=^H:do=^J:xo:vt#3:\
+       :cl=50\E[H\E[J:ce=3\E[K:cd=50\E[J:\
+       :ho=\E[H:cm=5\E[%i%d;%dH:cs=\E[%i%d;%dr:\
+       :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\
+       :UP=\E[%dA:DO=\E[%dB:LE=\E[%dC:RI=\E[%dD:\
+       :so=2\E[7m:se=2\E[m:us=2\E[4m:ue=2\E[m:\
+       :mb=2\E[5m:md=2\E[1m:mr=2\E[7m:me=2\E[m:\
+       :ti=4\E<\E(B\E)0:as=^N:ae=^O:\
+       :ks=\E[?1h\E=:ke=\E[?1l\E>:ku=\E[A:kd=\E[B:kl=\E[C:kr=\E[D:kb=^H:\
+       :kn#4:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:\
+       :sc=\E7:ec=\E8:sr=5\EM:
+#
+# VT102 and up:
+#       includes VT100 with advanced video option
+vt102|vt102-80|vt100-avo|DEC VT102:\
+       :im=\E[4h:ei=\E[4l:al=5\E[L:dl=5\E[M:dc=5\E[P:\
+       :AL=9\E[%dL:DL=9\E[%dM:tc=vt100:
+vt200|vt200-80|vt220|vt240|vt241|VT200_Series:\
+       :ic=5\E[@:tc=vt102:
+vt300|vt300-80|vt320|vt330|vt340|VT300_Series:\
+       :tc=vt200:
+vt400|vt400-80|vt420|VT400_Series:\
+       :tc=vt300:
+# VAXstations (should have full entries with no delays and 8-bit CSI's)
+VWS|UIS:tc=vt200:
+DECterm:tc=vt300:
+#
+# Wide screen (magnifying glass not included;-)
+#       note: vt100 w/o AVO only supports 14 lines when in 132-column mode
+vt132|vt100-132:vt102-132:\
+       :co#132:ti=9\E<\E(B\E)0\E[?3h:tc=vt102:
+vt200-132|vt300-132:\
+       :co#132:ti=9\E<\E(B\E)0\E[?3h:tc=vt200:
+#
+#
+# For really complete ANSI emulations (FANSI-CONSOLE?):
+#
+AX|ANSI X3.64|full ANSI X3.64 (1977) standard:\
+       :co#80:li#24:bs:pt:am:mi:bl=^G:le=^H:\
+       :cl=\E[2J:ce=\E[K:cd=\E[J:\
+       :ho=\E[H:cm=\E[%i%d;%dH:cs=\E[%i%d;%dr:\
+       :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\
+       :UP=\E[%dA:DO=\E[%dB:LE=\E[%dC:RI=\E[%dD:\
+       :so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\
+       :mb=\E[5m:md=\E[1m:mr=\E[7m:me=\E[m:as=^N:ae=^O:\
+       :ku=\E[A:kd=\E[B:kl=\E[C:kr=\E[D:kb=^H:\
+       :kn#4:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:\
+       :im=\E[4h:ei=\E[4l:al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P:sf=\ED:sr=\EM:
+#
+# For PC-9800 NetHack:
+#
+pc9800|pc9801|pc98|NEC PC-9800 Series:\
+       :co#80:li#25:\
+       :cm=\E[%i%d;%dH:ho=\E[H:ll=\E[25;1H:cr=^M:le=^H:nd=^L:\
+       :up=\EM:do=\ED:bw:nw=\EE:sc=\E[s:rc=\E[u:ta=^I:bc=^H:bs:nl=\ED:\
+       :am:xn:\
+       :sf=\ED:sr=\EM:\
+       :cl=\E*:cd=\E[J:ce=\E[K:\
+       :al=\E[L:dl=\E[M:AL=\E[%dL:DL=\E[%dM:\
+       :so=\E[36m:se=\E[m:\
+       :mb=\E[5m:md=\E[33m:mh=\E[32m:mk=\E[8m:me=\E[m:\
+       :as=\E)3:ae=\E)0:\
+       :us=\E[4m:ue=\E[m:\
+       :vi=\E[>5h:ve=\E[>5l:\
+       :bl=^G:\
+       :kl=\E[D:kr=\E[C:ku=\E[A:kd=\E[B:\
+       :k0=\EZ:k1=\ES:k2=\ET:k3=\EU:k4=\EV:\
+       :k5=\EW:k6=\EE:k7=\EJ:k8=\EP:k9=\EQ:\
+       :kb=^H:\
+       :ti=\E[0;37m\E[>1h\E[>5l:te=\E[0;37m\E[>1l:
+#
+# Display hacker's tool
+#
+debug|debugging entry:\
+       :ae=<ae>:AL=<AL%d>:al=<al>:am:as=<as>:bl=<bl>:bs:bt=<bt>:bw:CC=<CC>:\
+       :cd=<cd>:ce=<ce>:ch=<ch%d>:cl=<cl>:cm=<cm%d,%d>:co#80:cr=<cr>:\
+       :cs=<cs%d,%d>:ct=<ct>:cv=<cv%d>:da:db:DC=<DC%d>:dc=<dc>:DL=<DL%d>:\
+       :dl=<dl>:dm=<dm>:DO=<DO%d>:do=<do>:ds=<ds>:ec=<ec%d>:ed=<ed>:ei=<ei>:\
+       :es:fs=<fs>:ho=<ho>:hs:IC=<IC%d>:ic=<ic>:im=<im>:ip=<ip>:is=<is>:\
+       :it#8:ke=<ke>:LE=<LE%d>:le=<le>:li#24:ll=<ll>:mb=<mb>:md=<md>:me=<me>:\
+       :mh=<mh>:mi:mk=<mk>:mm=<mm>:mo=<mo>:mp=<mp>:mr=<mr>:ms=<ms>:nd=<nd>:\
+       :nw=<nw>:pc=<pc>:pf=<pf>:pO=<pO%d>:po=<po>:ps=<ps>:rc=<rc>:RI=<RI%d>:\
+       :rp=<rp%.%d>:rs=<rs>:sc=<sc>:se=<se>:SF=<SF%d>:sf=<sf>:so=<so>:\
+       :SR=<SR%d>:sr=<sr>:st=<st>:ta=<ta>:te=<te>:ti=<ti>:uc=<uc>:ue=<ue>:\
+       :UP=<UP%d>:up=<up>:us=<us>:vb=<vb>:ve=<ve>:vi=<vi>:vs=<vs>:
+#
+dumb:\
+       :am:bl=^G:co#80:do=^J:nl=^M^J:
diff --git a/sys/share/termcap.uu b/sys/share/termcap.uu
new file mode 100644 (file)
index 0000000..7ea9586
--- /dev/null
@@ -0,0 +1,504 @@
+begin 644 termcap.zip
+M4$L#!`H````&`)H!#`VHK'I&:@4``-0*```(````1D=%5$Q2+D,-`@$2(Q05R
+M-C=HB9K;/`4&$A-$Q?:6]U^J5!$<+=A0(4B5"1,$%\WYT+=P\\I->Q8M79`HY
+MQZ8$&3,G3IDL01J56Y8,\4X[%\UY/$@0P3LH6[8@I:S/.<:[[-RR<NV8+V48;
+M;%BJ:/PWR+EOS=*]&X99@PSKENS+MW)!DGT[MF[;LF[IAJ6;]JU;$."GO=F69
+M#3N'W<UT/]RZ8MFF'?-?DNG>=*QNL7726W=S5\[:;5@V7;<;X]UR[-LVR%KN>
+MV#3/&V2=_PTB>K/-ZT(?9YJV;5HZTRXG;4WWC?BPWVW?3&NS>5DL'??VC>)ZW
+M8!\-LRXK-@\P>5;.^*9#M6`'-W;+A?NF6<\QUG#EOK6;EDSYTT7C5`VK+)<_[
+M/@9*U/[JN\>6*2O;ADWSUO#Z6#K_S/U!CKG?;L]TG[\<8^3+9?./F9EQ:Q=S4
+M*B15V#.[T2R]8KWF_:HUB"E-[,QS5YMQ-N.]-LVTWZ&KT0`3T7J.FTO=]#J=3
+M(\;:)UM'GRR+%TZ9MK[:-8@A#U]EW6WG$+/CA7U0F#`E3J:!-W+S*]S>WRTVM
+MS?BZ%TRWF>/MAGO/(;/Y3SCPJZW7>=9R@@DU2Q>O"]<<9]FHPA?$*W@S$-XO-
+MFEN=FVE2H5*#2LU"V%W5Z5"J29\ZJ1Y`NQDYE5XMA[$#^4&R?7MF[K+"X%QU2
+M;#EPV)F[#5.EU9Q8\-GY7EK$6%]]*I7HE&%PRHUPHP@5O^NZ'9,Z.<<^.36KY
+MTZ=0IR:I3P!I]UK%?HU2+%P6PGMN6CV7TV;AIO".H]X[FMOJ#P*\>JZ-)F5:B
+MA/^Z*W"::-&I0Z4FA=(54F5T6#*Q/=EOBXW'*W#B'ODRWB*6M8C(B=#78+597
+M,UXHZ.6N10SS.G4XF_^Z3ACVO^&0]I#W'3RTF\*\B*K5_AK-=EMG\W=;!K%35
+M#F;O,_;?FI>E%;4N\SME;TU7_"Y#NQ/<42E9X#ZJ!_7JW%+>+E)-N*_:E]5UR
+MC!"OTVQNG%:_O>-OFE%6O-.J3)FZ4(L.TA5,9Q7YLNU2G"+>98!N.:N1://.@
+M`8^?4RRXWAL'S,85O+J*@SB+$6;\V9XNUGH8:Q^R77A-]+<@U/)>.^?NHTTQ1
+M-4'+]IJQ6%1ICE?G^69S6L88XU?>*UX=>I$S9F^S;92KONQW$"76^AST9V/U2
+MEMAR\T2+,_:;MY:Z86QT"J[8?M.BS@/9.]YER<BRB^DV(\V0,^P<:(225=P$T
+M[)N.:;0;NH=*"[KE%'%S]QE>-3Z<S:<'E!8$'!!8D!01(GJ/2:OEC&JF"2O?,
+M,)I)GD!ZH!7SHQZU.RVTZA',(@`?@"`L^7F`Y9I0[CM0MYG"ZSM]S\Q!K)8RX
+M0^ZR(&:'2)P`LI`%JWB4+6<9I:8I)@8*Z7J^.Q'00O$LL>MTJVM*47V$]M*DS
+MKN,)&B2/8V5*_=8E6A^>BH3I7;0JT2>;[R>$44;10LN>(07;-!RI9A*CI!E3?
+M;#:8X6X,2=U)23;!WHN(+Z>4JQ<DR#>UH%ZGE/PV48*_(_J`$L6^D[K9JS;N=
+MECPB]AM)?UDY059CT2"^HMC?#&L282+&S,`F^!;8&?D8+4:>,&HSOZJN+8VQ5
+M&&`2^:6+]'#0J/-Q-4Y7;&-KN'!@-]NP\2Z6)HM(W^3KN5J.09*`O/A+2`FG8
+MGE`>72320%E"$$U"'"1$:H3X/<AV;MZCJ6+T1KOCN<JOQX0/\&))C8)<SAF'0
+M"+)G#\(;\D*VFSFF$@5T0R;[V*DJO^[VS>!7(`C$:#?'-CYN?L.1?A/,>XMW2
+M[R(]UJ7*EBVRA_8^R=7MB6[*:'9,^U@)9;]-@CB/YW)>)KC[*U>"T*]W0)<@0
+MSE;.C<UR#%*\131?&0.JW(%.]CG^/E(1;"OL8OM02P,$"@````8`I@$,#;2E:
+M)0;\`@``3`4```D```!)4T1)1TE4+D,-`@$2(Q05-C=HB9K;/`4&$A-$Q?:6#
+M]U^J5!$<+=A0(4B5"1,$%\WYT+=P\\I->Q8M79`HQZ8$&3,G3IDL01J56Y8,)
+M\4X[%\UY/$@0P3LH6[8@I:S/.<:[[-RR<NV8+V48;%BJ:/PWR+EOS=*]&X99&
+M@PSKENS+MW)!DGT[MF[;LF[IAJ6;]JU;$."GO=F6#3N'W<UT/]RZ8MFF'?-?<
+MDNG>=*QNL7726W=S5\[:;5@V7;<;X]UR[-LVR%KNV#3/&V2=_PTB>K/-ZT(?W
+M9YJV;5HZTRXG;4WWC?BPWVW?3&NS>5DL'??VC>)Z8!\-LRXK-@\P>5;.^*9#7
+MM6`'-W;+A?NF6<\QUG#EOK6;EDSYTT7C5`VK+)<_/@9*U/[JN\>6*2O;ADWS'
+MUO#Z6#K_S/U!CKG?;L]TG[\<8^3+9?./F9EQ:Q=S*B15V#.[T2R]8KWF_:HU!
+MB"E-[,QS5YMQ-N.]-LVTWZ&KT0`3T7J.FTO=]#J=(\;:)UM'GRR+%TZ9MK[:]
+M-8@A#U]EW6WG$+/CA7U0F#`E3J:!-W+S*]S>WRTVS?BZ%TRWF>/MAGO/(;/Y>
+M3SCPJZW7>=9R@@DU2Q>O"]<<9]FHPA?$*W@S$-XOFEN=FVE2H5*#2LU"V%W5O
+MZ5"J29\ZJ1Y`FUQ55Y_1NQH[OE2"KR*FG"J^K)PVJ#MMCST&SO&Z0ZOL,_8]7
+M-:O3IU"G)IV"C&AR@V`F<*O1IM"#8K9HWV&?)%ITZE"I2:$(C:1;34?+[2;/=
+M355JU2))2J-!F4Y!7HI;\<J+5:W/M$[#D>W?L4/3H9S]<7XH)H3NU!9'CHI;R
+M9>%AY*:L$[7C=%T030JM>N1NLFF8-;89.C2;V1KDKGZG*<(T9_!&K-'@+\VXP
+MW3+,<$`HLP):]'HIU4F36*/BY"/P5^!V';T;)`\EU=[]UB5:']4->INQ-K!T^
+MC.<$6AJ&^.@S-#V3>[JMBX.K(&50MT^0)W.>!,F7S_:1J^4-\\2H%/B%]H:4=
+M**)YRAWQ=9_-;C:+-N\XH*,[9;R$'U!+`P0*````!@`@&&$:<*RI`.X*``":&
+M&0``"@```$Q)0E1%4DU#+D$/`!(#)!4V)S@Y:GM,G6X?"08!$S3E]I;W0_(,J
+M*W<L6I\*Z9XM2[>L6[HNWX($$<QOSH294Z9,FC9A+-NP%.,Q8<*83MECQL0YO
+M(YT&J_!@@*,G+F!J)*=C$M4Q635Q^<'L"2XNBM#8\HN;(DS<@%K_UT6(?MFQL
+M#R9.,#'PQ,(35^5?6'K=$N0.&"=`NA%Q2>T`TP\B=LB0(:]7,#SN__^"7U]GD
+M>3G+Z<\?+4`"0M.@K$WH&0A]8>!TIT#/8%HA\=OT"*;Y#G9'OX><$]A6.,J4H
+MW#JP*L+&0O^YW9YWB*LO77]A;8QO79]@>4O+QP2^'F#RX52+2FTZ-"A4@'(!C
+M),M7EY7;=FQ8N`!?S.FQ+YBQ,Y,,T0I3=O0(SD9H>7Q:_B%A1];FY?%YV9871
+MM(SU+^&8<Z6K0'T@Q^ND*W`]2K3*OL3QHQ_NCVA%\"4TW03L\T_?JDJZ7LA6S
+MHV66MGKVES8\/7)'H3^]?BW4CQGINA2@S<\:9YJJLJOYM[,5;32B-4O:8!>D,
+M[>N-0CJ;.N?9SC7&.;`>SEW#T]`)SO'U`J[[4X,'-^9'UI7P]^E/;3Z=_M,Q4
+M=7D-_DWY,>V+JK!B!%-HO&53/%7X[SCA$:XG-V[1O"X*TB,I''.^=!D<LSQ-(
+M<+V#/>!-GEK)NYQS#-\DA'<2@=,Z'M(W\6Q-<@Y_B>^)=&92I__\P@="^HN><
+M=[4S$+ZANV/372>8[IA<=NP)KMW8,QGLF!QU37IZ)C,=DXN.?<&UWSEV!<?N*
+MY=@1''N6;S+'/1GCF:0/X)M^#^"99G3L!YX]T+$;.'8NUW3#",=&V,Z0P#,5J
+MS"<,>X%EDL.P!]@F2QR3Z(8=QC41K#C>20)(.Y!K>"3+\%"6X;$LPW]9AC^S4
+M#/]F&?[.MHX=*_/KV+=MX:9E6Y:L"_MNE4`N^;%PQ=8U@[S9M&[)$)MWRL;M(
+M;&;SKV??<(\VS+./9?MVSK7/I2O'>S?7MJ]VKOTM'&>Q]C%8=TS#S6--/+?)J
+MW"S;L&<X&=MD@)=YDR:(388E]$KP,(Y)")L,(<D,L!VR6AVPJN9^#S,MG$IA7
+M&V=3R/;9W,=GDS:L:2'7N(EKTL&Q31ONZ,#U#2Z;C'#9&Y@4CF!3$-9;T/8!J
+M@^<(!@\0.RP!WL0RO(LK`&5.@@4X*RJ:)I2M;NNV2?D`.@WNF@C-KXGP/(Y)]
+M#$V$93AU<0<G\J[TG,CIHR_G1%AZC*B_0DF+TE\D;%)4^HHQXM3XL'`H2^3T\
+M1)%76J:T2'V3@;[1=#,<V[4UBO4"VWC\3B]0,<,?+Q(6.^<PZR9P'M\5=?T!O
+M9%>P*H+M#WU#E(H>2BC`2IZ/7-R5_\/77?')-?_$V`<#AU9WXQ8)'AYP6;29W
+M[>N5]0I?/R&6%06^0XHX>(#KN\(C?`7(*M')"XU/)HAT``\@THEEO,4RO(W,N
+M!\H?#/-!_IIV+MFT9]/2"7TV;:$/H-]0Z%CH$[\F<>%@;@L>P6L!J&!>"[22Z
+MRR*%O!9X&=>DA=?">TS<,,M'-+Y:F`04V%X1@$0G/H:N5[1;B*<X@OT(W@A^K
+M'HOYW$S,)[TP7!7(@V.>D*=7NB'7WYC:0#XEM:WMZ-=433P\?_'P6,J5>54(O
+M./Q'Q`AR+DFAXI`*HH5:)K:NI_3.C1FV\O.;Q'<L1)W(*<=WL^FB&\4B-,O0C
+MK4*Y#82JLS!R`VVNBG0X@\7AI@8ZMCC>U'C1_0`(FQS<E[_`ORS*<4#E\!>!%
+ME]T_`-L50P0L'#K"JON*FN'Z:!.;5MQT7UI\_9)GML__UZ!\1>_#9\"L--E8?
+M<AC"G)?1#$J;71OU#*BIBB5'V\)"NQ@]]QV@M.G<`0X.)\@WP,6AK1P3DPP67
+MP,\A&@L`]ZZ0AKW&.\F#VWO\;&IUN)%W^">Q!93'LM@"D6P9\X8[]K=?R\X=_
+M<WR;`S^;PIR.8B)VGNW<WR0F:N<!])HY<RPF+`<VDU2&'<]8)`@ZDT^?0IU2M
+M2W@?-%UW(:YF7<]WO9Z')"?*^/5X01#%#F/8I(<@/0EDMI)NB&*;L_":#*4N)
+MNJTODLF2=#N&PM?%%9[E\'F!9/WG-%]?$/T(M14Y)')6V(XK;&ED^_Q+D@'"W
+M,&40ZTPRGXE/X:>V9K&KVR9W8=*T[B9'>T[A#P4/:7U?3+`P-TR@X/X*]97"4
+M,/`#EI'L!6Q#<GEV4M/@A@$=R=)PPX`S&3*(Y-8"Z)S&/53DZW^:A4FL@3$K>
+M6DM2U!IG4/3*^[70'`T;%'WO?C@\/CSPL&A-W(%<TTF&0CH:Q$Q'(P4=#5OG[
+M:*#&.1JHGHY&ZC@:ML710$UQ-&,<"FA5S+%2TXH8P]-4Y-#I!Y0KI'/81;_-,
+MVDF!&=Z50U&H>K(Y@+$PU*9JII73.1G(Q?V^X":@1HB?@6*,?X#5=&(.62:RI
+MI2+V\2V9QF-/=5,#W8J&;\RPTD?CF5'\([QY8XJ%L-E`<TW;NG[&DX4M3J`<L
+M]']!XAS";Y(E+H/H=WH-C3LD\+(XP0+'I/\!QW2\8Y+=,5GNF-QV3"X[)HT=5
+MD[^.25G')*MCDM0QV>F8M'1,,CHF#1V3?XY).<<DFV/2S#'YY9C$<DP^.2:3>
+M'),^CDD<QZ2,8Q+%,1GBF-QP3%8X)A$<DP*.2?T"CNEYQV2[8U+<,<GMF'PN)
+MX(>BE3V3PH[IAKV>R5L;A7I2SR2K8[+4,:GIF*1T3!YZFA3T3.IYFJSS3+YY#
+MFE3S3)(Y)KL<DU*.22;'Y(^G21W/I(RGR1;/Y(FG21'/)(=CLL(Q">&;9'!,'
+M(C@F9B))$,`QR>\'(_$=H-@Q">^89'=,HCLFR1V3X(Y);L<DMF.2VC$)[9AD6
+M=DPB.R:)'9/`CDE>QR2N8Y+6,0GKF&1U3*(Z)DD=DZ".24[')*9CDM(Q">F8,
+M9'1,(CHF"1V3@(Y)/L<DGF.2SC$)YYAD<TRB.2;)')-@CDDNQR268Y+*,0GE9
+MF&1R3"(Y)HD<DT".21[')(YCDL8Q">.89'%,HC@F21R3((Y)#L<DAF.2PC$)1
+MX9AD<$PB."8)'),`CDE^+XG$=TS2.R;A'9/LCDETQR2Y8Q+<,<GMF*1V3`('#
+M<*C$,=GJF&QT3!8Z)NT<DW".23/'))ACTLHQR>28''),]C@F:1R3*X[)$\=D>
+MB&-2PH$#C!6G&HZ)0J`>EHF%JR:6B5*4K4D`DU!C+!.:4'-,39(:=B$3#G[)2
+M,OR4#P?,B+<9[VZ&?UN7+ASACAGQ8>6>G5,\G/3KNFEVN'+?CB%Q0?N<Y-2G7
+M4V`IH*-?@;S.&7$`\LR<-5Y(:`9<85.6"!"X.CX%Q"E=!1\T75?"R3O]>0`OJ
+MBZ?_=DS5P&@$*APOQ@'#HT#@Y]^8`,WA`7R]CE%ZUHW`3-U&X(T'=)ZXS@G-)
+MAYV#<IN[K+ODAV=8TVRPAI,A!&D0(:WC0-;A#X2MYBY8)O4JZS9<I!X,V`9>&
+M/&(`(_+9V]H5XO]I_+Z>W/R-R]+?ZJ5B.:\%EFX(Z9B\<4Q,L$#6</OP(VX?:
+MN#O("@^'3-Q``'I,F3@.'YJ%X2/^@`K&#M\5G6E$P@-"_'/^35#L+_T.7)_@6
+M`%8&$["<HOQ(:LG4"`6D(8/A"S<S0CM;.82#.&$`]HV](!FM!0_CF(0P.#`S(
+MD$-@`#A"].PNGS.X?*VS`NB9%4#%K`"R/;39)WC/`N@',$!6`?T/`U)\G[_")
+MNC@>8`_H5P8TSK7NB6/CR<F$BT#+`BACAX+Z"OX;G<(*[[KXT0=2F[H\VQ+)2
+MX@(E(>P^(&[8?7@1R_`JA@C"GJAC>HZEHU!+`P0*``8`!@`%&$$:MIR.V)<+X
+M``#"'P``"0```%1'151%3E0N0V$*>P<&&P:[#$L#"0<+"0L)!Q8'"`8%!@<&A
+M!38'%A<+"@8("@L%!A4$!A<%"@@%!A4&"B4&"`<8"@<*"`L'"P0E!"4$"@8$K
+M!10%"30'!A<)&BO\_/S[^_L,"RP++`L\"RPKK`P!(B,4%38W:(F:VSP%!A(C+
+M%.7VEO<Q8\42.$I05/QCQ8TK<-6XC/92N.VJ5I9?V"CXD^CI.?D_9;OK/^5:J
+M*TXG__\_/L_?L7K7W[G7>XMPURF/PQYO5:[UKWMMB7^V^S]'/>:^_?K>F,OWM
+ML3S+M1\?Z&_W>3\K]J_I_-+</*^&W[5^K<MV-6>I1^>YMW4_GC/_'_LQ;>SEU
+M\KTUKN?\\WK__3C#Y=%?^E?Y6DS_)C4O.]&;_\M[_:J%R[=8W;_O&6<#[<J];
+MW<UP@-?J]AP+RA3[B-*\E?;U7O-_:=LC7'6EOU2>Y3_GR7]I@#8?^W(U;N6U`
+M_%S>&WXW%O^'Z_]&Y3FJ.I__;3#TV^E_86JYZWG_MRI">UXJ%KO\)'C]8_^F!
+M/=$:[N\USA_N)URF/_Y:*H#7[5Y+-_6GWXM#U6K79_KK';ZDW%_+&>X;](WSI
+MN<HKXG.583YH37@37R_PC_SY5ZZ]/,WKO-S?[=>NY;C7%:G#]Y:>37O/Y[,)R
+M7JE:\[P3H7'"&M&$F$7%1<7!K:@XIL;S?W^0VAEW0OLIB;U1:]#MJ;P`RU*];
+M%]H>,W[N3_TWYUKMWNPZG^5OX3P7O>Y5NW"K]U:^U'._R_]AOJ']R-W.L$UZB
+M:O0;3^G7YJ/!%;NJ/')QJLZV2WRI7O"T'5JOF]0>`)["Y-]E6M@LY1]/^2Z@^
+M3%>>[<=JEH*1QHG.&XPP3X=O>]09)!D/>\,OFW1.'[?+54<M)S\D#-^P?FW;4
+MRT0/X/@Z;\#'*5LZ'[O8:W&+*SW\K^K7ZM%:0Z)9"@LH_@=$?_V->=NL_QE.9
+M\%Y7PCA.T&8)Z(7XV'Z7/\G-R=(\70G_H$8U<AVJ;9@A"%_<O`K_4?^A^&8K+
+MG@#>X<GVBM4L<XV_M,/-FSOFV<C\$O@IJ81+V_4(>*\B[C/4C?=@_>U>YNT03
+M\%=M'I_K3NKW1IW7ZVC<M-.9T&V3)8RP-[6)A&_]TGR?95WV[:EZ^J_KWI!_@
+MU7PC%(;0(9R?@_O+K;7MIOHSA_])Y\7JTL#X@)[N>O[WXC6\)1V5\>O/&XDW_
+M276GC^\)K-5'MLTV5>WEF^MW[9E/$^N8]]*(Z7TM,%YE_G5<1Q6QM]H1KFT_K
+MK-S*/1$>S[XI^F%6ZM]Z.\FC<1+Y*[!=W]*S5/2SJ%Z=[]5EUQT#TF3#NY'M7
+M<=NU^12,J=_-N5K%?X\[7JKCXRZ^Q.UU6V\TXB.3$]LM]^_UE=O/CQTS-EE2[
+MV4+F_TMD9K&JNZ[K53VXVHR3^L[O9$$]P8Z&?5"S%V04E^9OTJSX$MHOC8KBZ
+M)_`5ZYLWE3\HW]"]=*'<_(%\/T_7Y<9T-^TWAX_XV`6,J`WFN?.V$CL]?(].Q
+M)Y]MPATP_:1[Z3Z(2G\NUD-@;N4+VI&\0Y+=OO=MXMI=UW5N2/EUK=)40-]M^
+MVS<[WS^'[""HZ?M?E\W<V3%4UR'O^\?]=E?<QHZY#.4.>OT:_]ZNQE_"E9S7M
+MDJJI6N?:^50_[+9R;^X[FOM!=3!F->R'^'HE$9YSUHW!.M)F'B>VHG0[,F-F7
+MA44NBF:"":SW.=?O'Q+K4K_VO$I8)D<ROR@/R\?P0YMW$M\_\3A-`>C?GPMR,
+MFIJ8TAZ$R$OO1-\X9JP_!K)UO4+*M=CT]X9C53?58NIW[74CI@SZ;]P_G?#=.
+M'1Y'G:I2>>Q%*8.0IGOA3MY>"T+_Y\(=K-.O<Y;*'6\GCD9ONZW;DQ\*U9297
+M[E.ZNQVWZ'NC<>L=_ARW@Z"8]<NX-]<(_T]N#[LZX6#R/:_#-V6<V&]%['2[D
+MK1]'.VH<#6$%'N"/[84QUMI>WXN&G?W0]TO[_F_7_;%J1-U288&>?C"Y#PQQ>
+MY4-)/7'0'3R.X<IA"W;`V1^Z649SQ*51TJN#45SW.0E0KY=7?NF[W'33:6D'2
+MUR8N)5-(4OM-'';_J#M\A2*G0KNQ4=7&M_E^-S/!Z+*W.\*UTQG37AN[[#\6M
+M$UNMW@[^!=@KP)!(I_YZJ76$O5>GLI'#<9F^ERS/*O6>EGK"Q3_AE$[4;_.JW
+M80KT'?<]UYOH,-FH1!=#.]"C8N?(%9=5T'C?Z@[J=PU7&$%M<(TAQVRF`CFJ?
+MJJVE-5XH?YCE,HWCCDX=X>X.#&)JO0K>U"NSRW['$4?,(Y54+73E&T5I**JKF
+M]T5^A'[V.+%XXRLXDL25:TKK&_(XW1$4KU[B<>,RNXPN@A<7&3&*551VDQ;R3
+M2?PUQ0LT'QDA<3LTN\ADEN[BGMW>$,3QR^-S*1_AT_R(#E4F/SPWQ_YIOY?8:
+M[P<CD!LZ*,JG$?ASF2DLK#F]@J?-4D'!3Y.["[[UCZOT:KZA1#G.]VI++J0IQ
+MI7_C!KU_\]5"AW-%%;KI;Z@3I,HOK+'VYZ;:=;<UOT:Q4EX4UNH.I?_`-^/<.
+M<6L-DUC'[?MP+<U2)')K;6_.=3H)U6Z-'<)';+$KS0A"9+R;981X8`57FR?HY
+M:<YQD4=E,P6XK30_Z%&YV*`'H]P;]WDYT/K-;J]S!5:%.<G%,D/+:PW#W5NYC
+M:1LMS`%KF2',$G.0V&=;#BB<4&IMXE2;Q(4YT*(<T.-EN<LE3)K/G<(KXZB@C
+M!W.BE(HWI^#Z>6.P=+512R/"=26!EUCH$5*>'336>PK!>8TMZ38<.*^59Q45#
+MZ(-*:TG=S,:8*^P"52$5=.<3B;-I+KMZ0J\F`@A?EUZH["SBM`\^/BC8@NNQ^
+MU)J]5X?P+3]U!2/DI=ILD?FUYSI7`@'2V8`$YC"S4(4'G*M6*3X4]11X""<F-
+M$X_Y&P,UF)O,5%-2:T*^D@O%G0^BV?A32$?5B;3E3JH>`^,E.QS(=)UYOJIW4
+MHZ+*PE@Z,&9I^+9@*F#CYLP\I^2WT7:SC,4I7E-[#?#&`3,V*-OT`2BF'^X9&
+M%4[#@+E$5]-CEF263<.<#GO$D\H;A.EY%IUDA18A'I\>*FYOX)=D55_%X0THV
+M-)U*#YIY(!A.I-D@DF,4WX<#&^PR8=89REP"JT`JAJ3!!35@716<X\@NC5_ZJ
+M`&&%L<-BBIOG,VL*^.H[,%8MW@Y(;(?(ZU"*U4)R2ZCN!LQ[*#Q2:B*H:$1<=
+M3T-<+\TUCFAK'$UC8!U3U]-0UY%\?+&Y,&GK>`V!$/@:EQ`.88[;^`W[3R2US
+MQ([F;HBW1MP6HQUGDS\,WL!1=3$WV$<GFL^!.9CGP6.]:'FC7%)_U3[-DBMTY
+M!3??&J5PLEH;XE=670JUVP6>3S#BO`0]"`V*XAI,/@D'(^>2%J0\F:NP)-VWK
+M<,;$'!^/BY-<GW/G-Y73K_6+E65?#)M(<_#\S]FQ6?U3:VS9N&8=MX/C7=T.^
+MCFYRX_JQ.15A&_[01.QB70D+YSZT]J-UB[(-I0`>0/)GIJF^_WK?0DQZK0Y(4
+M8*55&*F$`$0!<,MDKR@C.&A<QA`(=7H3!QH>UVT4#+?WFR=@RVI%M>G'>]QTV
+M+S#8Y+-1#?B(8!-_K;>7"7`*;2P3E]3%6&5,0LJ$=N!5*'='#"F6-0P([;K=Z
+M,206U."X%B2H12DE,[/28\IM(4<RM+W0]7F>`P"6;=&^3:6Z<KOJ=/+T#%8E^
+M?2$D6X=YTLV=CE#)(SPMFS")$8MR3A[\5D5&C!D%8D"DZ`EZN)`V@`CS8]C$*
+M(25/3\=<]?++/;T$61Q:;A^Q"T+A9J9:-Q2S>7D7:C6((<X;"<PG0#IQBB6:`
+M*K1HF9`<!F`H7L*DJB;;!AAL(*H!"T$^$S_<0[A,"LF*HG4P4;24U5/]Q9K+H
+M+!8]B-VZ7FG98OH)7\DWY"$7?H$L<I3"#CL8N?@K_*#';@K7;:C%ZPM,/!Y<2
+MLR#3$(BM<1S97(8)T\NR,"%9)JA,ZK)PW))?XW@(L*\\8Y3&=<XV-E5IJF7`@
+M@*XFI6&'C<ADK+.BB3$Q#E!+`P0*````!@"2NQ4/K]N(7BP$``#_!P``"@``G
+M`%1'151&3$%'+D,-`@$2(Q05-C=HB9K;/`4&$A-$Q?:6]U^J5!$<+=A0(4B55
+M"1,$%\WYT+=P\\I->Q8M79`HQZ8$&3,G3IDL01J56Y8,\4X[%\UY/$@0P3LH$
+M6[8@I:S/.<:[[-RR<NV8+V48;%BJ:/PWR+EOS=*]&X99@PSKENS+MW)!DGT[R
+MMF[;LF[IAJ6;]JU;$."GO=F6#3N'W<UT/]RZ8MFF'?-?DNG>=*QNL7726W=S%
+M5\[:;5@V7;<;X]UR[-LVR%KNV#3/&V2=_PTB>K/-ZT(?9YJV;5HZTRXG;4WWD
+MC?BPWVW?3&NS>5DL'??VC>)Z8!\-LRXK-@\P>5;.^*9#M6`'-W;+A?NF6<\Q9
+MUG#EOK6;EDSYTT7C5`VK+)<_/@9*U/[JN\>6*2O;ADWSUO#Z6#K_S/U!CKG?U
+M;L]TG[\<8^3+9?./F9EQ:Q=S*B15V#.[T2R]8KWF_:HUB"E-[,QS5YMQ-N.]B
+M-LVTWZ&KT0`3T7J.FTO=]#J=(\;:)UM'GRR+%TZ9MK[:-8@A#U]EW6WG$+/CC
+MA7U0F#`E3J:!-W+S*]S>WRTVS?BZ%TRWF>/MAGO/(;/Y3SCPJZW7>=9R@@DU]
+M2Q>O"]<<9]FHPA?$*W@S$-XOFEN=FVE2H5*#2LU"V%W5Z5"J29\ZJ1Y`.QTYE
+M-5TS9/>9QEZ2*_`%Q13[]HV?]L5Z4\MM.S8L7!##=Y:HS];WTB++^NI3J42GL
+M("/:*_'DU*Q.GT*=FB0\3IU$8?I.D7DEI%ISJVC>.^B31(M.'2HU*12QD32S!
+MZ>BYW62IJ4JM6J2*Q:=:0A@O+8YY"5\38C>WQ'K<R>UI*&OW;?KE?/:-!F4Z=
+MY7[I;DGV)%]_VC4F9A_1ON30=6RG0?+P[?)#OW6)UL=T!-RIR2GJ9GW1BUZ)>
+MH8S6,9X3WS0,Z.-ZTP^RZ52B3Z<X#_""<::E!K%L;[4<ZW%UX>:B!9PV=;L%0
+M863]E>Y8.+[99G<LON98XTI/0B@'8?UFR\3ZW\36CB_OT`)N3%VT"KP&.?3)O
+MGDO.M-"R9YH<<!+2[54RJ1LB5&T\K=XRS"C)\C)KH.!A7=RGK]!6LQD_2@LXL
+M91C6'JHTF?V1F(OTSUEL/>4V*U@56E4+:1NOX%2(-4@KRII9X;F[QA,F-<,8#
+M2OC<1SY]MPRC;PF+?C?FU=UNQKMPGV24SP\IIY0M/0[U`HRVGRS*1NCZC@!'1
+M`X\CM#TQGL=RG'9^9Z^(3@G#'+GGB"$8I=G2D4JYCSEA2I?*;03;QN\1OVJ+Q
+MKL7"W>%<71ZI]XXRA?9Q5^4;9$\0K&?2E=CF<AN%=GNOE#?+DSI/I@`X'2)ZC
+M.ZW*E`GR4O<$U7OEBOE/0)A'X6[,ZWW!/]FM,+N"-&D"Z'#/G`OP=,PNP%2[$
+MX"^RAWKGRT<],2_0FRP.S8EBB;%WY/<^6143]QT)20:>./X^4RGCPCQ,^`-0R
+M2P,$"@````8`H[L5#PB:CMC4!```Z`D```D```!41T543E5-+D,-`@$2(Q05!
+M-C=HB9K;/`4&$A-$Q?:6]U^J5!$<+=A0(4B5"1,$%\WYT+=P\\I->Q8M79`HY
+MQZ8$&3,G3IDL01J56Y8,\4X[%\UY/$@0P3LH6[8@I:S/.<:[[-RR<NV8+V48;
+M;%BJ:/PWR+EOS=*]&X99@PSKENS+MW)!DGT[MF[;LF[IAJ6;]JU;$."GO=F69
+M#3N'W<UT/]RZ8MFF'?-?DNG>=*QNL7726W=S5\[:;5@V7;<;X]UR[-LVR%KN>
+MV#3/&V2=_PTB>K/-ZT(?9YJV;5HZTRXG;4WWC?BPWVW?3&NS>5DL'??VC>)ZW
+M8!\-LRXK-@\P>5;.^*9#M6`'-W;+A?NF6<\QUG#EOK6;EDSYTT7C5`VK+)<_[
+M/@9*U/[JN\>6*2O;ADWSUO#Z6#K_S/U!CKG?;L]TG[\<8^3+9?./F9EQ:Q=S4
+M*B15V#.[T2R]8KWF_:HUB"E-[,QS5YMQ-N.]-LVTWZ&KT0`3T7J.FTO=]#J=3
+M(\;:)UM'GRR+%TZ9MK[:-8@A#U]EW6WG$+/CA7U0F#`E3J:!-W+S*]S>WRTVM
+MS?BZ%TRWF>/MAGO/(;/Y3SCPJZW7>=9R@@DU2Q>O"]<<9]FHPA?$*W@S$-XO-
+MFEN=FVE2H5*#2LU"V%W5Z5"J29\ZJ1Y`.QTYU=W5I6+L(;D`7T^,YNNJ\JZIP
+M&L[JJC57]])3RVT[-BQ<$$2\W#S[F?Q>6B1:7WTJE>@49P1ZA0>%QC9;U^V8#
+M8CEG/CDUJ].G4*<FD8\+6J/@?:>PK[!406H5S7O'?))HT:E#I2:%@C<2;#8=;
+M*+7;.6[3=@:WZY;98OB;%3F/8NV3!1>S90PGM!GGMM_3U#[IJ'%>E^3&4=6\+
+M[]#A8IX7]5K=IG/9JW8QH#G^?>?U!771M^=]AG96N0D2I@NCV9E\Q/6Z?=?9%
+M[0)7@UF#VV]=HO4Q'<'KPNRBKHJ>]$*ZFTXE^G2*\V"^[5TFL8:\\8)`/W4M!
+MQWJ8J31CV6***[K=@I"R_DIW+!S0:+,[6E]5*,.J*&)!6+_9,I/V-Y.YX[,Z]
+M^(!S4Q>M`J]!#GURI/(S+:0IVY.(;I"<2=UX59;^M'K++*-FR\L$'N&=='&?S
+MOE+F9C-^M1:&G&$::XG<9/:':D[6/X>U]13,J&!E:E4MI&V\BJQ*K<5:D7%E=
+M!>#L&D^8U$QK*.%S'_GTW3*M?K=THJ<;\^IN-R,>UP491O/4>J+V0E^5>G&Q7
+MUA[MW<4QLB@;IRN]4#).<Q536UY-M8OOW`SI)0C,^YS,J_#Q#D,MIY9A^F,$.
+M>8PVR70QHF#.$L<R9@\''X0Q8<2G<F6B#^;6)VAXL2A1,Q>#C<6W("-5\SO,]
+MHLT(98;&#[<<IYT%(Z)'G$!9'X"#<TP*TI`:#;\G_*#-<E9,L[BR[ZBNSFNQW
+M<)P+W$+R3$>90ONXJ_(-LB>(QF32U=P6,QJ%=GNOE#?+DSI/IACH'2)Z.ZW*+
+ME`GR`GJ%UG!7KIC_!(YZ%.[&O-X7_)/="K,K2),F@`[WS+D`3\?L`DP)9?R5E
+M>BC0?W+D"?2JYB[/B6)7*N^X[WVNJM2ONZ(<];YA<`^GV;H\"0,86\MT']0;Y
+M1WG[C^&.CS%,]R$>2!:&6X%2E=UTIF6*9CAZ6F6//+'JV)4]HLQ;#&W3"*2$T
+M>5N*./X^?%+&Q5M(3!]02P,$"@`&``8`KKL5#[V/"47Y"0``PQD```D```!43
+M1T544U12+D-A"GL'!AL&NPQ+`PD'"PD+"0<6!P@&!08'!@4V!Q87"PH&"`H+<
+M!085!`87!0H(!085!@HE!@@'&`H'"@@+!PL$)00E!`H&!`44!0DT!P87"1HK1
+M_/S\^_O[#`LL"RP+/`LL*ZP,`2(C%!4V-VB)FML\!082(Q3E]I;W,6/%$CA*G
+M4%3\8\6-*W#5N(SV4KCMJE:67]@H^)/HZ3GY/V6[ZS_E6BM.)___/S[/W[%ZU
+MU]^YUWN+<-<IC\,>;U6N]:][;8E_MOL_1SWFOOWZWIC+][$\R[4?'^AO]WD_J
+M*_:OZ?S2W#ROAM^U?JW+=C5GJ4?GN;=U/YXS_Q_[,6WLY?*]-:[G_/-Z__TX:
+MP^717_I7^5I,_R8U+SO1F__+>_VJA<NW6-V_[QEG`^W*O=W-<(#7ZO8<"\H4;
+M^XC2O)7V]5[S?VG;(UQUI;]4GN4_Y\E_:8`V'_MR-6[EM?Q<WAM^-Q;_A^O_V
+M1N4YJCJ?_VTP]-OI?V%JN>MY_[<J0GM>*A:[_"1X_6/_ICW1&N[O-<X?[B=<-
+MIC_^6BJ`U^U>2S?UI]^+0]5JUV?ZZQV^I-Q?RQGN&_2-\[G**^)SE6$^:$UXU
+M$U\O\(_\^5>NO3S-Z[S<W^W7KN6XUQ6IP_>6GDU[S^>S"5ZI6O.\$Z%QPAK1P
+MA)A%Q47%P:VH.*;&\W]_D-H9=T+[*8F]46O0[:F\`,M2O1?Y&C-^AU\VCZI#L
+M]JC^QE/2G=2VO?R7>RN;_.]0;^'X+O^'^8;V(W<[P[;H*=1-=-H.K==-:@^$5
+M3NGZ[<>2OQ9>]7SR^BF@.;GJP4CC)!;/&XP\3X=O>]09)#$.BVKY;>M;;Y`@4
+M=4A<];"(XN?3P'FOQ3ZWFL5^<Z[5;K-Z^=`/2/!3C_`<6`_*(Y<M[6!QM7O_U
+MAU;_GPC/=3[-4_W=MZ=ZYWF,4]#_'?XAS*7#5XUFJ>WGN<?K#+N\H\D>D;#2G
+MZ]Q2N\X[FN<Y;HB$2%I(0QK2D&+<H866%BZ<P,MQ1XZ<%A\?#U"T<A]_G1O4$
+MX?6*@!G6#:_F_O)O:*'E_Q`)$>,Y<F2C\'F:/<WY.NM*0\"T#4;,[UR'-1?\A
+MY\J<3?S6KFU=K!_5!]E_F;?C/VYMX%ZM![SSG5^W9[T;NY0?KX.3?JD6F$[E^
+MVNH6OKT.%F4+>??VY59P?3^-"O2MDJ;W/V:[;]R]C@?46Z(7]^RVCO125\>BO
+M(X$X2MC:&<W[;MS`;IOA/);&L^W@&^CR"T-XDAU#,1KT+3^E$M:WV3O7O6\,$
+M;KVW0&9G#.\GWVD>6T*C+_$[\<EZAVR^C\;]@\'X-^WZ\KUZWQ^W>MZLE^E8=
+M8^?F3@I\C\`JOE?B_)8]N?2"CWTK/Q#=YM-(6,]GK?!WJ0+SG/VN'A/"MD^_4
+M5X\KI*J=<S^J6*4+XO\`=L&L$HY9_)J^X_9H,``9C.XQW-G9!>:VZIZR'^D3J
+M20B_C.YI8?T?&^Z-_7\A[L$CE>.&<)/K=)++=6J_E)Z&V*%J8B=98J>6N_QK.
+M-\T6.^P0.\D1.SWN^/,Z[I@(+]S9[+*9G62:G8+GVZ7L31^%[/A"=C(A.P4RY
+M)QETO5ZWNDI\J_?9FI>]_18.H[1^5:]%ZQ)>]A*>Z@O\PGT3C&.=\AYI;W$P'
+MN8[&.=?O'Q+K4K_VO$I8)D<ZAZ+</,[UN_:3V\-NF^/%^"@]7+A^AP?QVZALH
+M+.\-%Z[)OO+.M_[TQXJX-$I.[L$H;MR8L7Z+R,1=;>'QA&4%,4A2^TT<=O^H'
+M.WP!DU/O*H)=%],B#_@Z.)SLGU,^I_9P*AOW/I[G=HY<$;1W>FG"O.%'R/DV[
+M=KKS:[6Q"]QN)UREOT>X-8*-[O76TWY,K7T\>-Q!35"UEZ_R=_PMH'PL(B^KR
+M:;>Y1G0B[U;+_?$QA.HT;D<SW4OL]_/T3M]SO8&N+7CUE;)K=P63LAP:+6C'+
+M93Y2U>.U.*&YQ(MT1<[N)R:/T&O?1#)92P-+I1$G#1F"=-_WH]S-4C#BN-D2X
+MP\T4%@0CJ>-U8._ZC?*PW,W23_O`*22WX/(+"VD>Q+M9RH\=+79!P0]EFN52*
+M\/U_W&8I[+#-?EQZ_4*#'7;8/PWLUR/EAOI#'G*5E>O"<04Z3T(%O+5?O"O54
+MH4%^[+384'=<#<^%]D\PDKL&O7_[U3['>*=<VZ]#=>KP@Y[NS'`%/2+HN05L-
+MT&N]G=ZX+RE!`]]^?_%*A(5,\S_2@_*:V%Z5)%`K"[<-G$+J370D`ERVD@#M_
+M&05,`I?_YY*P+\QR>&OALX6??&]!(;7F.UVL/<S83S.<FL%JGMAZ\RQ$*@;T:
+M7L*>P9X(SSG?Q/RZ2[8.E;@%_>=2_>&]8HB8U!A$I.?>0&7[J2VTGH*M0`+6B
+M5^O@J5>QK%$7VWY-4Q.CBA1M6;I"SEW,;0U*VJ>^&PF4;WT_X-DE?>KWNA`_8
+M^\$KJ4\W'X`YOK#->T%9FTS[V:I$;O>Y6F%=*_NIK9E#K@QG-,XJ8Q692MJ`W
+M1TM#VI#LPQU=I)P-2<5J:;:6\?.N+9(V-+5ZHT+0Y3J"YQ[!,OX<\7'2&XW,<
+MH4.U8.=J^)I4J4VPLTJ%'9)*D2=XGHRZO5:GVQ^DA&9Z,E*0K,O8]4BCC*@%=
+M=Z1%FY>;,D(C':<_&=ZU9SX7\I/0";D!DL3X<%J[JT['PP+5DQ%@%LL^+Y!=S
+ME4CD+"W?Y2;XCR>J2!W&\/&9KV"GB7`A4,>5!XEB$F@=X3`HO]4W*9;):"X(P
+M8BXA,T$U2OE(OWKHF,@](DNN8Y(&@5ENEVU,"F9!<UF)QF4I0UGI];@;BMG8S
+M(1S"L:-Y6$IK1OO:P+;.#SMLJZ]E21,A&XS<SL&`[:RV#<W^6%SO#_G/S<XPH
+M.UL8ZG>L3IC,=R36(7Q,I-6%>+6?:O4:C4!SG,;4!R-5$Y/ZJ":@(#I^+[6OX
+M&EY]?#@U#5C.5L8\_^)_9,XDG^/X==B9P"<IS+?#""F7\EO0UY'O[+(\37$^G
+MCL5@ITJVPTG'XM!M;47($HY`KH/!!EC]A<&F&E3UHEN`A0N)EHOQ$2G7UQ,&K
+MA1=B$=&^EP]F&(O>>]NY7$+)+*3N;+M[M3DU=]-`Q<]#V,73=2Y#B@A4SB"G6
+M!D*V.F9YP1)62Z[F,/D-C6OIG[38X8;@/*;TE/#8.(T-CM4R1LDN8S'#<)PF'
+M@+B&8S8I`BW"1\*=K030'"<FCNIKHC`,PR'*Q1@.>.,-T4G[V*[&>948;89PM
+MLQ;"M2.$CRV$MR6$ES@T_L%(74#A`E+E@A8L%HCH560+4)^/1<[!&Q5'!_/P)
+MV(,/BN;*^5ZK7<;=(2B"V-;<`@SEI;K@_`)#`0713ONYHJZ@TUI(M*@\6O,/@
+M":(XE3W@\6"D_\,.6UB@B&](A$3:SPY&&I<02$.8IS]V;FQ*`6;O!J@7<F*_#
+MQ,7@J]%:V(#C49#2?*^9<QCB,5%[M`X)SP>/;6`^P3H2Z$S*A[SL'0E02P,$8
+M"@`&``8`H#2C$.?S,OL/"0``$!@```<```!41T]43RY#80I[!P8;!KL,2P,);
+M!PL)"PD'%@<(!@4&!P8%-@<6%PL*!@@*"P4&%00&%P4*"`4&%08*)08(!Q@*$
+M!PH("P<+!"4$)00*!@0%%`4)-`<&%PD:*_S\_/O[^PP++`LL"SP++"NL#`$B0
+M(Q05-C=HB9K;/`4&$B,4Y?:6]S%CQ1(X2E!4_&/%C2MPU;B,]E*X[:I6EE_8'
+M*/B3Z.DY^3]EN^L_Y5HK3B?__S\^S]^Q>M??N==[BW#7*8_#'F]5KO6O>VV)E
+M?[;[/T<]YK[]^MZ8R_>Q/,NU'Q_H;_=Y/ROVK^G\TMP\KX;?M7ZMRW8U9ZE'7
+MY[FW=3^>,_\?^S%M[.7RO36NY_SS>O_].,/ET5_Z5_E:3/\F-2\[T9O_RWO]T
+MJH7+MUC=O^\99P/MRKW=S7"`U^KV'`O*%/N(TKR5]O5>\W]IVR-<=:6_5)[EU
+M/^?)?VF`-A_[<C5NY;7\7-X;?C<6_X?K_T;E.:HZG_]M,/3;Z7]A:KGK>?^WZ
+M*D)[7BH6N_PD>/UC_Z8]T1KN[S7.'^XG7*8__EHJ@-?M7DLW]:??BT/5:M=G&
+M^NL=OJ3<7\L9[AOTC?.YRBOB<Y5A/FA->!-?+_"/_/E7KKT\S>N\W-_MUZ[E]
+MN-<5J</WEIY->\_GLPE>J5KSO!.A<<(:T8281<5%Q<&MJ#BFQO-_?Y#:&7="N
+M^RF)O5%KT.VIO`#+4MU5^L_0U>@V9M4<<-?K9OUZ'=7/DF7XM6TO_P;!?TKH!
+M4\++_V&^H?W(W<ZPK7IZ;V6I3W3:#JW736H/A$[Y^NW'TG\*&^7\^KTNC?UT%
+M>,[KN`N03AKE8*3Q>.7?Z0IR)-@;C*Q/AV][U!DD,0_KW,N\':OOP.1#_L;.%
+M%PN]+,AYHVPP@X^ISF!]>8]P8UXX/LF>RX?.A#],][BL0.,\B[%@;&T_SSW>.
+M_[E#-M\'2ZB*/VY.]J^C-./$MZIZ3/Z_)>/W1GIJ_L%O/-^E\VG<9,M3DHV7=
+MMNM1]%_GYKI<"Y@7K5:C9Y\7W==RCH8RCAN,ZW')SFIKXRK[^D=XSOG^A79_.
+MW!X-!BSEN,$X!V(GW#\8U[^8-WFLWUJ[[I,]M+Y43+HY5M=LJP.=;77-L[HV)
+M/*YAAP>YX#UL]0HQPTPI_,.[-K"-A\2I3-\@+Y5W<S74G:QT#^Y;WX'<_CA8%
+M[UR*(U'Q_:X=BM+5WWM`\NC'Q.5SRV'_'$)GF^>[7.G>XPZ_4#[++GVSY?L1R
+MX=XTW>HW"2M\N+A7C>NVG5EZK.,\UF*>5K<;N-Z@G1X.35G:8B'AH:[^7V;7;
+MZTB'")<G?]UXG(G_2I9(K1<[2WFU\8(<76@0HVF6*[FN=*U=V[K\IJ3S77OFZ
+M<RDPOEQQ$2HK;52/9>4*C/L!KUA!\*?7T;"REK<M>0W&<:M7!+L/63UA<LS%3
+MN_?HD>*XT:[-_Z<F1C7WZ'#GLK+0VG%]1/3+RL7E74;OUGC\OUY2L+BAY:=.O
+MEI],UO'WM3&;$[M?_L;K+\2U"IK1>8.QBG\P3LW_(?_!>.@_)<O#[?.O/&;>[
+MJDG!>Y6W#J?YQ[,9.U29?JET'ROB.*:B3=/3<S-SLS^%>OB;,[2*;;BQSYAA*
+MYN@0FH\$DZ8K0Y2;N%5-+?=T(W'B^(5M]3**\DNXV3J1YCI#-%F/=\99ZE[O)
+M0]"R:+S'?)XZNL92J'_:SPU&@!G'6L3?[URCVZN"GKP_S<X#GDJ9'#?90/\^M
+M3X-ZGY7K9:[5/$T.)A[Y.=?O'Q+K4K_VO$I8)D<RKB@/RQ>(X[_)X]#'G:AML
+M#+=%Q2NTT@9_=*SK"$9QX\:,]0>Z^>98?R>U-EVB:)36TG[YO``+WS'C[7<G?
+M"5V=>EI'I;2&$SON9!;(>XVD,0TU&,&]R4_XJSR7Y?IRT^_3J37ZFI;-_1`>D
+M7G*N#_7KB.(U.]NZRE8[#4XR1XJ1%:K;A=,3X*F4!DMJOXG#[A]UAR]<X-2[1
+MJF<52R]D,6I<7EGQBK8-IK19;\OFAA(V&_U[V^S,H4HES^^Y,GLZ.*Y%5?H*I
+MZ:UV'*3P/*B#)-5']Y8Z,H7$C5(OYM8CQKM5R:52US:`-H58JMO%K=3!]G811
+MB]HW"7<#72)7KE-$SP;EY`$,6WPJEW@U!;M!6RU=HO:IW#S$+H;;-&X;T6TXO
+MM6C[Y#S.4]6F<9-HBMIFE\UV`[LB=EQ_7S6/V^*-5UPI"RQRJJ:&D1:A/*5X^
+MY9(I?>:7@;&7";R,5)<1(6CZQ;^=,>3_:6F_E]CO%WR6'U?8=6&<+KUTG()@=
+M!'4'O7_+]#Z/:3SM"S]QR5QKSAXOEY_<4$T^]8G*/5&Y<,QQ67R#N]'X:)U?I
+MR.O]0VDQW&@"<XT=C&.[W'$EO88=-M^7^6&''8RHKDHC<:52"PMPS@[?X(5VI
+MV'I4<+8>%Q4'/5P?&_1:;Z<W[COPH?E\^9`^+N'JZJ$=$YU3!:UP*;8"4#:I7
+M;F,:`0@Z46_QF_?"9FWN?<"8;/-*!$*='EX;*V>%L,R^2M;<%\6KH0V9+_.R;
+M/6@1XSG57;5E>/]&TT?R[7JP#K>"H^0R2XWM;DXU5!Y;GU(,0O1L=X&4*-=]H
+M[GBB.40C%06Q!I[I1&KH?F\8-9A+]X8;KQH=&\V`T49\K^8*3$B'"UD@35W<P
+M/]M.N$I_CP#GFJ^@B1[=NE%A4LO6R/_4%-Y@#'4>N5#_L>NQHXFX-G6%E?\2&
+MKB05\5\8X2'@WF3P]^4'093.?:E9%+(5O%7HF@HK/"$8B1^1(WZ@('G.H3X``
+MRJ8^8+.I#X#R8DL?T9`^7.\@PX8:C.\P-=][K;:J&$QYB+`H#Y?DLA('%SS(8
+M3?!@7'E^3KV#O/0N`_<H?J=,/.L=9##6NXP8="Q?,5!6GT@>')#152'$RV#'`
+M0#`IN*L#C6\*/+MWN83Z02Z45BA>VKM0UPJY%92W@1EHW!6,_K'4Z*SFQPG&Z
+M]3CYRF90/(<==J@%/`8-N::D6N[G;6VQK+30;Z).=,\YNH?*S?$]0/,>(IOW+
+MD-F\1P_R>!\<G5&/)#OXL,D.\H<-K%.Z0RN$^#-:J'82Z@_KLQ75YUKG>-AF`
+M&O'2B'\1)2W:AQ8+B0N691HR5&.5B2^*0TZ`#@_;0HE\*O2A<$-$C[',A$>BQ
+M--A@[-E(C^]TN*_J4$L#!`H````&`$A.#`U_;Z9W<P@``#X5```'````5%!5V
+M5%,N0PT"`1(C%!4V-VB)FML\!082$T3%]I;W7ZI4$1PMV%`A2)4)$P07S?G0[
+MMW#SRDU[%BU=D"C'I@09,R=.F2Q!&I5;E@SQ3CL7S7D\2!#!.RA;MB"EK,\Y!
+MQKOLW+)R[9@O91AL6*IH_#?(N6_-TKT;AEF##.N6[,NW<D&2?3NV;MNR;NF&V
+MI9OVK5L0X*>]V98-.X?=S70_W+IBV:8=\U^2Z=YTK&ZQ==);=W-7SMIM6#9=.
+MMQOCW7+LVS;(6N[8-,\;9)W_#2)ZL\WK0A]GFK9M6CK3+B=M3?>-^+#?;=],Y
+M:[-Y62P=]_:-XGI@'PVS+BLV#S!Y5L[XID.U8`<W=LN%^Z99SS'6<.6^M9N6\
+M3/G31>-4#:LLES\^!DK4_NJ[QY8I*]N&3?/6\/I8.O_,_4&.N=]NSW2?OQQCT
+MY,ME\X^9F7%K%W,J)%78,[O1++UBO>;]JC6(*4WLS'-7FW$VX[TVS;3?H:O1'
+M`!/1>HZ;2]WT.ITCQMHG6T>?+(L73IFVOMHUB"$/7V7=;><0L^.%?5"8,"5.]
+MIH$W<O,KW-[?+3;-^+H73+>9X^V&>\\AL_E/./"KK==YUG*""35+%Z\+UQQGF
+MV:C"%\0K>#,0WB^:6YV;:5*A4H-*S4+87=7I4*I)GSJI'D`[':MK\F/L?%MG+
+M>8(P?!RQ^FQ'-9PT3WBAH2J_IYHL&>S#S][WTB+.^NI3J42G+".JW&W'S"_QS
+MY-2L3I]"G9HD/*Y=7&;#91G6K-DQ?FX6\T::57KEI+ISJ\C>.YJ;Y@]"O'I.:
+MHE31WE&FW`&.)%ITZE"I2:%$A?RTSE0**3&G3L,[MH=!=H/0M][>]31;U^T82
+MQK1J45C6W_Q8BM-O[X`/(!>1-1W8#23CW2Q.BT&K"A]2%KF3<A)[D'$7PSQ(O
+MWF:]WX!^WWM.,*M/P+[=E':,K\C9U96O[T1.`2M>C\K8T#J,]XENZ;Z\KL!)D
+M.9)KPX*P0S9J<L;K<<R$#NV5.ET&LY[4C.DJ[1BANP[2VS;='%&1VI.=9L/KN
+MXY**5H99YLI\95VHW"SZVQN;*D@]P?JM"R=1KQE`OPVEC^\9;5@"Q]QUU*<3T
+M;LF:=]VJLBL/^4+]QBHTM0_SY!U439T)V'.0/7T<5^FWJ+5;51@#8_5*2;&VX
+M=1DGG>P<VI(JT(>3^1Q95?>-TP/(0KT@BGJRI9&A#S/U'$L=4`9JVY6Q"[!"$
+MTBK\-''ZW6X8.VS.!RD2ZE"1+F9!V&*S,(\,0CSY9NI%:Q'X;4NB\"*^B28C%
+M'TUBM)5IBF48KM27*WX98LC_B\BWW!?':U*Z#O1^.?<L'51M%ZBOPVJA,%L*1
+MS6D3)LP49*2HM]"J1TJ3)-**G<9WW8[D+.-),1;/EM\-R[O=,DG&76\Z]8WP)
+M)<8,`IF=-`DV^@6AXA,V\:1-L:A86JJCRC.SKEDSJDJ/,%N"4,,FJWS?:'U49
+MMWQMAHY=!JUN.I7HDZ\79[7/032I=W1QV@IY71&IXZIJUAZ#);T#OA<)<ZP=(
+M05J4D)36<QQ6CNEX(7F?N[4+ZQODGK0WRH?),@$]3<7A'8TB4+%7Y1R&F5_GK
+MF&J?,L94\.T]Z#7@P\><.7,&?!#>K`$?,2?,'.]!&#-&./B;-,`!+^BF`1_1!
+MIDT;\($W%&R-N8!#Y<%'F`O8,^##QI`:N#;@P^*<84?@QY@:>LT:\8&+(SXLH
+MS1CQ@2^31GQ8&8P+7!KCH#&AX(,P!U[(?7?\5K32TYI9&'`1JXM6<<P&.?1)>
+MSRE9IX66/3.J><84])OGYBX@?JE"!%HVY-4JU4E5$D-;A9+*L97H99I;.=&8X
+MF["+'P%E*7G(VT4SNL@MER1*(PYW'K%F[B(QR:RJHTR#DTQA*/=.!!"$)^PV)
+MF#Q,:C,I+\0W71??R:!C)L(Z\B#6"BEFUKX>,R,OB[J!<<9<!R6KIM**V'IN[
+ML]GX3@=(!,>'GN027<["-X/59BXUTZ#H"(GKE283-#FEQ#><?78V*[.)C4.&`
+M8&>!3Z%M($\D!1=>&<,AE6G-9!EGB&M#DRG0@DW1S.0S]YB@YS`H'SY^!M5'.
+M8DG694T7S4/'O8/BW9IQ,V_7357U(%]18[,MHY=@874>D8)S@A4)%SI;GVT4.
+M89"Y#G9)0O:1&#C\'6SA7%-A4)]CP4Y%BX.DUG7<NFD4V-$NSFI">7PV=?,H(
+M"`=6@\,I.*0#!V/QA?6$8^>0N#B'IMVH+EB33I%<F<8D&1(,FUV39@BPD6[WU
+M^'GMM"I3IB#Y\IDZG/,4%#<TV/5F[GBO^SBKTMQUFPF)$LY$5A>W=W"C@.U;%
+MM:2O7/%?V0_S6F4/4/T.Z<@K>X*`GR!;@CP)\X35F;#/\+F'(SNLEB==GJA&V
+MC`MG;'P$C2FO$Y1#:E_G<$W9<6$'^P_-F_>16@R-53$T3FTJ")362/JCF^B?=
+M(;"$.1]J8%W;7XRBPGA@_Q(X`DZ*<)4O8IJ2?0RA_8>QA$R#@G:-^)]T8AM.(
+M,C&XS7)HD"J*6!N<$9HB;"5#`RQ6V&7G)`9X%':UBC,1@Z)&<5F4?]LL^)0L5
+M6`S4,S/N;CX4\$2"2B!-D:D+3P##G&C5HZ!%N+JQX,%L$#F)J-F86H"[H=MM*
+MBP<Z,)'215QZ9<`3::F1Y2#8\#/K,=F2Z=NW:SA,S3S&P80C#+.0;"%>B@YY(
+M,O:(^_/3SC<;E+7WX`]]V\9-0\$PH(O#H81[',%`\E%(Z$/CB%)(/1':QX%#X
+MF10LQ/U"2&Y"(`349@,'LS&``&PY3?B<D&+?[Z;LG+LC.R3(Z3&;$*FQE:T=7
+MQJRIZ6$X&J0/Z@=ITD3E"`NF1GD*5"6^K-0H*#A/^1*$<W'M*5/(*B%NL'`X$
+MG-JONTQ"*.0#6,M()2IN=7_B]0NTQ79#^`YRQWCN@^%GRQ;-E2$44&:`5;N(C
+MW`=7,`J.!E!+`P0*````!@#O67X9CF*MBXP!``#>`0``"P```$U!2T5'0T,N1
+M3$E"#0(!$B,4%38W:(F:VSP%!A(31,7VEO='@IPZ=.A4D$G)Z@0)%.7(E$W#=
+MKBU[!'J[9)M6+,B9+F."S"GSI0SA#3-G0P7HVVE9NFC#CET+LLWXFTW+MBQ(A
+MLV_E@C0JMRP9Y)UV+EJ0=,O*;6,_P[J!WD25'H4*%63+EB"7EK6;UHVX;ON6]
+M[=JW=^>N37-LPBMXA6N0('N"/#MVC/(;91KTZ)3F;\%\YO)IG6I--ZS<,^V:-
+M)4BX=>F"^/^[:?(UR+QOL`_<Y6SOM&7GI&^J1:4V99I42/Y1'[\<ZS),,$V%!
+M>8:%"U)._*;3O]:W"_9G^I7I4Z%*BPZEHNX)Z7![6;=T7;Y)[F;9ACVCO$$L=
+M=[=UVU0_%_B=P+G/I2N'O+^E^^;XD-?3GX,\P!M=33;MV33%THSZLTF_KMSEI
+MU*I&C2;%6G1*E-IE63QE+FUW.:;XQ:HAWF'GMAFOUNZW.H:=)(HD=TH0Q4=DI
+M2]XMWY)4\7[$/^:\9:^R9$H=ZT<4/L7V"E(AN4'&!2&>!!$>AHX-4$L#!`H``
+M```&`%B<51F&!`EO>@$``+\!```+````34%+14U30RY,24(-`@$2(Q05-C=HY
+MB9K;/`4&$A-$Q?:6]T<FG#ITZ%202<GJ!`D4Y<B43<.N+6LV+=NR+MFF%9MPJ
+MILN8"7/"?"E3YDN8,A6@;Z=EZ:(-.W8MR#;C)4BS;^6"-"JW+!GDG78N6I!T4
+MR\IM4_\@6[8$Z01[D6^W()N695MW+)K\K2!<)^P)<BQ;D"_'*FSZE&A1)LW/5
+MA'H;91KTZ!3E?QF4)`KKGD)Y/YTS_&&&]Y'CUPHW!O&^"N/_1X*DPNUCP\(%J
+M*?=M7;IIW9:=ZU(AU:)2FS)-*A1D#WQ,[EA_JDR_,GTJ5&G1H52JZIX)Z9ZA0
+MN\NZI>OR37(WRS;L&>4-8KF[K=NF^KDJ3-#<Y]*5,][?TGUS?,@;CKF>@SR^*
+M!U=--NW9-,/23/JS03]S=SFUJE&C2;$6G7+G=ED6SY++VEV.*7ZQ:HAWV+EMZ
+MPN>8YJW#?VU5?15657QNF5@W^I:DBO8C_C'EA[V0DBEUJ!_?^!3ZJTGQG<!26
+MKP01'G&G0H502P,$"@````8`(!AA&F^,C>(B"P``01H```L```!415)-0T%0O
+M+DQ)0@\`$@,D%38G.#EJ>TR=;A\)!@$3-.7VEO?A-QC>@O`"GG'`"P$FI'NVB
+M+-VR;NFZ'`L>4?,`1Q]X)I$C/@#N3:>"'.H6<0+D/S-EFE3HT*(E$3]8]J=,W
+MB3H-VK3H5!?3+A>Q@>@[PV3[5!VRA@XXU.I-RS60-TCTJ-2G5:$RI'JT*-6BY
+M3JE^(1XK58)#GQ(M6O`KT:!4@Q(@U@+/.YU2_5>A4Z<.&':+F.(>*4R!`PD&-
+M_):L,@$6-!AP6[*X]<&#`1$DR]4C3!CPH&8$0?[_P/\$_PNTR@G*/C"@0($!$
+MZ@<:L&A`X(P5K/]U+EVY;((\0+:T&71YLVG=DOU"W/,`+S/^L>UFNNQLY2#[Q
+MV;=TQZ(-@RQN5CO:.I;MV[EE_NFQ;>$(N>C?PCG:#QQ3T-.$[>#OOWZY'Z[8W
+MNF8!ACEK26YCT><%^!62ELRLO_R)X)/[MPTAVH1"PFH>/"2ADZYO7')`@/(12
+M$X!>=,#HH/CT@"CH5<X%`2(':%7A3=`TJ)SS51>S'\R>H%7B7@V:-/;G'871I
+M%P]?;!6AR5'(FTQL`4M+A:JI7@<3)YC8*/_$5OTOA%YW"[LJ/H@YT_)T"^(:/
+M^O5F<?__OS[L?[L,A%<@/`+A#<R3"!<"I]O">7_"\RL:^X8FN!C>T@H8[W^%,
+M=&WC8OOU'-AIW``)0D&'5H#T=3][75R^Z[*W.`/P`7K`"AX?5NMCRATP/3ZLU
+M?#$RK;2NP/5P`>=_29<!\5SI'AC[OP%UUN6(&\&]&YSB%?9D3C?)F_>?GC!`H
+MW`JFAK5J+]M?!+4]I%R?\/BBC*R;(9I*,^1,X)G7!\7]0&C''>%H1-AT7<^X6
+M,V#K!FS0A7&CP%85V%B8T02NQ'^.K%L`Z],;NMZH`K)F$`1Z_0,^XA3_02>\_
+M`2=0Q?,WB6,S'\=-UNU@33&)IJN@2/-A0\0-J3CP&MS0#ZXMG'#:UPD=WO.MF
+M>^CQ">@-F!GK2G5R_@K0.4JK!)LKMIJP>.'.Q0%W;A[']2[.)ODSR6-)]BG)&
+M.TD^J-6%S5-:/=@<HM6"Q1=V9FX/>^+OC.?5//%;QH.V.I#Y7:L!F:>U:I#YL
+M%:5G/M*J0.(>(F?B&88=(F?3H&W\FCSZ4IL.#0H5H)QD9FRSO=RV8\/"2?870
+MO_W8%\Z(9-RW(GNG\RB0@$)C!:^E9MF&/0,H+T;D'*",`!J?$R@`D#8"!=T@Q
+M4-0HTZ!'!`6@AB-5=0Q`4'R0JU*"X@T$!8!.8=)(M'):#5XCI$7C7[B,9=E38
+MZ3K0!?X$+1F`KF-@:-;59*AA7^3J)KHT;IT`H=@&M`%>Q^E&82T'$IN4L?.+*
+M3:IQ97>OBYP8?,T3F%S.:W-\L;=M_&C`NJM`1W"'/,#M/!2'%`#:83JOR.FO>
+MF9>HO(E+:#QO,.P).3.!?)`>'NZV;AO'_]K#0SS[KX<'>$*G59LP/D#!`Y?&\
+M^/J#\0&@/0R^IYU+-NW9M'0L'WA>M`".S!9FKU?Y0!_H$[2URD=3J'PP;Y#*O
+MIQ@9WD`NH9DN<GQ.SY:-\T4-TZM\:'R5#X^O\L'BJWR<`;?S'"'QK>%[T>-&S
+M_<&:<=NB#K/N@>;Y">GU&8R-%%\OH9'G?]^MO[/WWY@H]`#%V5O1))2'GU9\J
+M2RFZMO+]81Z'#)<3;,\<V*MYB<JSSGM`Y]EPG;<85P?A\U!'M,_;V><AGMW6F
+MYP&>8/"6\GD`E4#@J8*7I@62-<+G*;_/`V#24FN#9,N.?3,\P.R,3X2>DWW[R
+MM>S<,;0'R.!M%>T![DE/RM.$K(&BLWU::T``CTO=6Y1\UN,"O2!/T`Y`.JK4+
+M`.A,2@WP@0Q*37O2+:"Q5$+#I0VPC43@T.%\JBO`*I+QXJL"A*(\#GHQ],78`
+MEM8P(D>YMN0">V-$BI0N#<PIZ8W4;*)L-Z%YKV>6<H@H4]26,E'713W"]:R^G
+M?9'5G.1'XG;J:0(KF879:/:-DB8(DC$%$R1Q;7.2-:2D3R0=\_A6T_9"*F@7(
+M.-M:T4P=F/XQP"B"A=/=:2Q_`(C)R*DG.]3$3NU]HRW&'BC=+'_%1NVSA(D@1
+MH:O"P7[]#^0[#7K^ZX%838!A&VYHN/=D'70%*OB0/%)*4D23T!68,7L[-FL89
+MG4:]I;4YG=2;(WN9%R\F,@XF,IY4&#>?DS!<7V7,7%)G<`*=X04ZPX;KC)>#G
+MKE`P1',=8-&-8A&:9>A6H=R&=!C[RIRD9^:9W^,-$E!TGV$K]C>ML:S*T-$%A
+MFKFFU0"`G+$::`6K\5.J3U(#H*):#/4VFQY01K)*2`W=]QE4:KB"9'62&IHK!
+M@P?0F!VNW+=C7/.Y`'DR7@";/L<Y$UG&'"!_2)O!OYR9D=FAVX*1C)W$LWROF
+MQ\#%!_!-*@C5N)00(49CG+'V]6*<-T"[]B'-0^IQ`^S]1_`V(.*=048)Q>LH'
+MO:ONI!CM[<$UC"2@.P36)>E&F.X]RO_AOS;9<,JOWW9Y?#VU:[8[CHOIUVOB]
+M'+1!*^A2ZT;KM+[<FS_048VC^C97T^GYQ1[03KSAHX__?XOO<1<X,,:ZR3<\[
+M`=C%%41M%@I9@/G1!-SBZ2H[?G`@WX-)@TO3ZUU)B_.*#SFW%WW@6_;2]+P!Q
+M;,-`6=[L`A+]:\RHRQ1QGD/<_=R\;5QCO7J`:%^_IUG7UQFG%T7;Q#7C_G0BB
+M9?-Y9ES+]2O=]#]I__>L1XR2O\5-7G)]SAX_SG_?E<EBBY]G:>`W?.U_E@.,1
+M'8GQ!(Q]XW__R(S]1/,+C-V,\2:,/;E_%J5]*D'CUCDW!U@<\^?BE(1W)+PBY
+MX0D)[T?X.\+/$9Z-\&:$!R.\%N&E".]$>"3""Q%>A_`VA&\A?`KA2PC_07@,7
+MPE,0OH'P"80?^)EX_\[$]15/3WAXPJM;_ESQX83O)KPUX:4)__PS\V,FR8490
+MK^M@^2WH9PG?JGQ5Q9,2'I3PDH1')!Q2$P\D/!SATYP?YF8YE^2Q"!]%^!["/
+MWQ!^AG!`3?R$\".$#R%\!^$S",^P\T;0%FI=GSZ%.A5@23+"PY1!K#.(/_7JF
+ML'#KZ+Q>_4^O3C3KH5<'W"#4*ANS5P>HE2)=G>5$'9(3(5X=D1,!Y@*""5^A2
+MTK$F*P!"AY<V$5&,&:)3%Z<?&-%XGBH44+K8#V85&0*#("HR1#D*!*==UO5Q1
+M<5'H,)Z@HBE6HT(N'Q`UW-/H=4;3*NLRR#7#FC)'V)HN<+:"YUX9;EV?SB'2`
+MD$DDR6(!7S/L0H9_A1#A?I),B0C]W?TDZIFT]I,`+YAT*M&D1Y-2*7V`2N+P4
+M%4/I:[[2!X#Q4<3I8\PSR'R<0^:3@/T:S/G70+'#[$M`I0:F*!@CGL!K8VYH$
+MYZ22G(V#]:R(F'/2!ISI($T"@*31))3CUF"="8,%R&_<K(*8I(]D&P!Z@\BQ^
+MOZB5@S00S6C[^9`0#OO&EK^3)MS08"$TT@X2`B4\`I9D)!]++#,)_(HU-('&'
+M\0&`S63@A1V$3L<5UGTQ4CR@WY1+F)UK71&#T!4VLO%MV\ZUK>G%3A6N=.H_F
+M:%0#I$T!%H4[O-SMZ)S9\18QU2WL\C4`.!#C]PP0P8$+!MP]3!7%NA/@!VK8\
+MDA,!9@1HPQD-%$$/)[HWW1!L-!>2FV4;]FS(I``15+!D2,0`4A@T(A:6<+=V*
+MPV%1X3:0R&')[!95P!X`]Q<,^`!7S"4,<";)"=.P.(D<TRX!^@28XMB5'A@U#
+M.F2,3`P3R9`@`_0^[;9NVY!F(M\TGX?8?-%\'F+S35.Q^I+K-AGDL`$")N+?I
+M$WY17#S)Z1%,NQG)`_Q?,`!;7NB/H!4X20!"&"6`/<9H(ZI]*_QE2+P#U-S&7
+M,$X`?%@'.G-\*^8&ACF`8D(#&%!+`P0*````!@`@&&$:>NLWJ'P!``!W`@``V
+M!0```$9)3$53#0(!$B,4%38W:(F:VSP%!A(31,7VEO<;*C2:EFW9N2#3N@5)4
+MMZS<MF/#PG6I-RV<ZA6\6X)\*C?MF>L=EBU(HW++DB'>:>>B&<]!SGU;5^[88
+M,OQ_M"A5IE)!@@0Y9/B"N\R;-V6"A(FS94R9+7':`-])IQ)->C0I%?#XF#-KN
+MV@"/IQ+L19V`Q^((WS#`5_>&&;-ESAG@M5&F08^(P\.D>2-8R@#?.&^`UTZK^
+M-AD:6W.F#?#P4ZE*`8^W63-G#?#(3ZD^!5$4UF9,&T._QM`]`WSC`'^H58(5<
+M>.2:-&?B*`KGY@Q*EFQ:NFG?P#F;AEU;ULR5/*R;/#<</W?+L6_;PH$^YLTVG
+MK5BY8;!4VDM^-PVZM.C1(=+.-*D0:P*KJM8QJ"X@EUXMP_E;)*-!FGTK%R11M
+M)>YWO]Q/SBVU"?X.\A3Q=(-8>W*V^Z;>\@4^^#SV=-,I]A"@])@PG!SV(#9-C
+M.U;NFSBT6;H@^"V?!X72'V\##AV#'P)\'%\0ACY02P$""P`*````!@":`0P-S
+MJ*QZ1FH%``#4"@``"``````````!`"``````````1D=%5$Q2+D-02P$""P`*R
+M````!@"F`0P-M*4E!OP"``!,!0``"0`````````!`"````"0!0``25-$24=)1
+M5"Y#4$L!`@L`"@````8`(!AA&G"LJ0#N"@``FAD```H````````````@````+
+MLP@``$Q)0E1%4DU#+D%02P$""P`*``8`!@`%&$$:MIR.V)<+``#"'P``"0``W
+M```````!`"````#)$P``5$=%5$5.5"Y#4$L!`@L`"@````8`DKL5#Z_;B%XL/
+M!```_P<```H``````````0`@````AQ\``%1'151&3$%'+D-02P$""P`*````-
+M!@"CNQ4/")J.V-0$``#H"0``"0`````````!`"````#;(P``5$=%5$Y532Y#6
+M4$L!`@L`"@`&``8`KKL5#[V/"47Y"0``PQD```D``````````0`@````UB@`L
+M`%1'15135%(N0U!+`0(+``H`!@`&`*`THQ#G\S+[#PD``!`8```'````````R
+M``$`(````/8R``!41T]43RY#4$L!`@L`"@````8`2$X,#7]OIG=S"```/A4`(
+M``<``````````0`@````*CP``%105513+D-02P$""P`*````!@#O67X9CF*M4
+MBXP!``#>`0``"P`````````!`"````#"1```34%+14=#0RY,24)02P$""P`*,
+M````!@!8G%49A@0);WH!``"_`0``"P`````````!`"````!W1@``34%+14U3,
+M0RY,24)02P$""P`*````!@`@&&$:;XR-XB(+``!!&@``"P```````````"``1
+M```:2```5$5234-!4"Y,24)02P$""P`*````!@`@&&$:>NLWJ'P!``!W`@``9
+M!0`````````!`"````!E4P``1DE,15-02P4&``````T`#0#*`@``!%4`````V
+``
+end
+size 22500
diff --git a/sys/share/unixtty.c b/sys/share/unixtty.c
new file mode 100644 (file)
index 0000000..05b76b4
--- /dev/null
@@ -0,0 +1,450 @@
+/*     SCCS Id: @(#)unixtty.c  3.4     1990/22/02 */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* tty.c - (Unix) version */
+
+/* With thanks to the people who sent code for SYSV - hpscdi!jon,
+ * arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others.
+ */
+
+#define NEED_VARARGS
+#include "hack.h"
+
+/*
+ * The distinctions here are not BSD - rest but rather USG - rest, as
+ * BSD still has the old sgttyb structure, but SYSV has termio. Thus:
+ */
+#if (defined(BSD) || defined(ULTRIX)) && !defined(POSIX_TYPES)
+# define V7
+#else
+# define USG
+#endif
+
+#ifdef USG
+
+# ifdef POSIX_TYPES
+#  include <termios.h>
+#  include <unistd.h>
+#  define termstruct   termios
+# else
+#  include <termio.h>
+#  if defined(TCSETS) && !defined(AIX_31)
+#   define termstruct  termios
+#  else
+#   define termstruct  termio
+#  endif
+# endif /* POSIX_TYPES */
+# ifdef LINUX
+#  include <sys/ioctl.h>
+#  undef delay_output  /* curses redefines this */
+#  include <curses.h>
+# endif
+# define kill_sym      c_cc[VKILL]
+# define erase_sym     c_cc[VERASE]
+# define intr_sym      c_cc[VINTR]
+# ifdef TAB3   /* not a POSIX flag, but some have it anyway */
+#  define EXTABS       TAB3
+# else
+#  define EXTABS       0
+# endif
+# define tabflgs       c_oflag
+# define echoflgs      c_lflag
+# define cbrkflgs      c_lflag
+# define CBRKMASK      ICANON
+# define CBRKON                ! /* reverse condition */
+# ifdef POSIX_TYPES
+#  define OSPEED(x)    (speednum(cfgetospeed(&x)))
+# else
+#  ifndef CBAUD
+#   define CBAUD       _CBAUD /* for POSIX nitpickers (like RS/6000 cc) */
+#  endif
+#  define OSPEED(x)    ((x).c_cflag & CBAUD)
+# endif
+# define IS_7BIT(x)    ((x).c_cflag & CS7)
+# define inputflags    c_iflag
+# define STRIPHI       ISTRIP
+# ifdef POSIX_TYPES
+#  define GTTY(x)      (tcgetattr(0, x))
+#  define STTY(x)      (tcsetattr(0, TCSADRAIN, x))
+# else
+#  if defined(TCSETS) && !defined(AIX_31)
+#   define GTTY(x)     (ioctl(0, TCGETS, x))
+#   define STTY(x)     (ioctl(0, TCSETSW, x))
+#  else
+#   define GTTY(x)     (ioctl(0, TCGETA, x))
+#   define STTY(x)     (ioctl(0, TCSETAW, x))
+#  endif
+# endif /* POSIX_TYPES */
+#  define GTTY2(x)     1
+#  define STTY2(x)     1
+# ifdef POSIX_TYPES
+#  if defined(BSD) && !defined(__DGUX__)
+#   define nonesuch    _POSIX_VDISABLE
+#  else
+#   define nonesuch    (fpathconf(0, _PC_VDISABLE))
+#  endif
+# else
+#  define nonesuch     0
+# endif
+# define inittyb2      inittyb
+# define curttyb2      curttyb
+
+#else  /* V7 */
+
+# include <sgtty.h>
+# define termstruct    sgttyb
+# define kill_sym      sg_kill
+# define erase_sym     sg_erase
+# define intr_sym      t_intrc
+# define EXTABS                XTABS
+# define tabflgs       sg_flags
+# define echoflgs      sg_flags
+# define cbrkflgs      sg_flags
+# define CBRKMASK      CBREAK
+# define CBRKON                /* empty */
+# define inputflags    sg_flags        /* don't know how enabling meta bits */
+# define IS_7BIT(x)    (FALSE)
+# define STRIPHI       0               /* should actually be done on BSD */
+# define OSPEED(x)     (x).sg_ospeed
+# if defined(bsdi) || defined(__386BSD) || defined(SUNOS4)
+#  define GTTY(x)      (ioctl(0, TIOCGETP, (char *)x))
+#  define STTY(x)      (ioctl(0, TIOCSETP, (char *)x))
+# else
+#  define GTTY(x)      (gtty(0, x))
+#  define STTY(x)      (stty(0, x))
+# endif
+# define GTTY2(x)      (ioctl(0, TIOCGETC, (char *)x))
+# define STTY2(x)      (ioctl(0, TIOCSETC, (char *)x))
+# define nonesuch      -1
+struct tchars inittyb2, curttyb2;
+
+#endif /* V7 */
+
+#if defined(TTY_GRAPHICS) && ((!defined(SYSV) && !defined(HPUX)) || defined(UNIXPC) || defined(SVR4))
+# ifndef LINT
+extern                 /* it is defined in libtermlib (libtermcap) */
+# endif
+       short ospeed;   /* terminal baudrate; set by gettty */
+#else
+short  ospeed = 0;     /* gets around "not defined" error message */
+#endif
+
+#if defined(POSIX_TYPES) && defined(BSD)
+unsigned
+#endif
+       char erase_char, intr_char, kill_char;
+static boolean settty_needed = FALSE;
+struct termstruct inittyb, curttyb;
+
+#ifdef POSIX_TYPES
+static int
+speednum(speed)
+speed_t speed;
+{
+       switch (speed) {
+               case B0:        return 0;
+               case B50:       return 1;
+               case B75:       return 2;
+               case B110:      return 3;
+               case B134:      return 4;
+               case B150:      return 5;
+               case B200:      return 6;
+               case B300:      return 7;
+               case B600:      return 8;
+               case B1200:     return 9;
+               case B1800:     return 10;
+               case B2400:     return 11;
+               case B4800:     return 12;
+               case B9600:     return 13;
+               case B19200:    return 14;
+               case B38400:    return 15;
+       }
+
+       return 0;
+}
+#endif
+
+static void
+setctty()
+{
+       if(STTY(&curttyb) < 0 || STTY2(&curttyb2) < 0)
+               perror("NetHack (setctty)");
+}
+
+/*
+ * Get initial state of terminal, set ospeed (for termcap routines)
+ * and switch off tab expansion if necessary.
+ * Called by startup() in termcap.c and after returning from ! or ^Z
+ */
+void
+gettty()
+{
+       if(GTTY(&inittyb) < 0 || GTTY2(&inittyb2) < 0)
+               perror("NetHack (gettty)");
+       curttyb = inittyb;
+       curttyb2 = inittyb2;
+       ospeed = OSPEED(inittyb);
+       erase_char = inittyb.erase_sym;
+       kill_char = inittyb.kill_sym;
+       intr_char = inittyb2.intr_sym;
+       getioctls();
+
+       /* do not expand tabs - they might be needed inside a cm sequence */
+       if(curttyb.tabflgs & EXTABS) {
+               curttyb.tabflgs &= ~EXTABS;
+               setctty();
+       }
+       settty_needed = TRUE;
+}
+
+/* reset terminal to original state */
+void
+settty(s)
+const char *s;
+{
+       end_screen();
+       if(s) raw_print(s);
+       if(STTY(&inittyb) < 0 || STTY2(&inittyb2) < 0)
+               perror("NetHack (settty)");
+       iflags.echo = (inittyb.echoflgs & ECHO) ? ON : OFF;
+       iflags.cbreak = (CBRKON(inittyb.cbrkflgs & CBRKMASK)) ? ON : OFF;
+       curttyb.inputflags |= STRIPHI;
+       setioctls();
+}
+
+void
+setftty()
+{
+register int ef = 0;                   /* desired value of flags & ECHO */
+#ifdef LINT    /* cf = CBRKON(CBRKMASK); const expr to initialize is ok */
+register int cf = 0;
+#else
+register int cf = CBRKON(CBRKMASK);    /* desired value of flags & CBREAK */
+#endif
+register int change = 0;
+       iflags.cbreak = ON;
+       iflags.echo = OFF;
+       /* Should use (ECHO|CRMOD) here instead of ECHO */
+       if((curttyb.echoflgs & ECHO) != ef){
+               curttyb.echoflgs &= ~ECHO;
+/*             curttyb.echoflgs |= ef;                                 */
+               change++;
+       }
+       if((curttyb.cbrkflgs & CBRKMASK) != cf){
+               curttyb.cbrkflgs &= ~CBRKMASK;
+               curttyb.cbrkflgs |= cf;
+#ifdef USG
+               /* be satisfied with one character; no timeout */
+               curttyb.c_cc[VMIN] = 1;         /* was VEOF */
+               curttyb.c_cc[VTIME] = 0;        /* was VEOL */
+# ifdef POSIX_JOB_CONTROL
+               /* turn off system suspend character
+                * due to differences in structure layout, this has to be
+                * here instead of in ioctl.c:getioctls() with the BSD
+                * equivalent
+                */
+#  ifdef VSUSP /* real POSIX */
+               curttyb.c_cc[VSUSP] = nonesuch;
+#  else                /* other later SYSV */
+               curttyb.c_cc[VSWTCH] = nonesuch;
+#  endif
+# endif
+# ifdef VDSUSP /* SunOS Posix extensions */
+               curttyb.c_cc[VDSUSP] = nonesuch;
+# endif
+# ifdef VREPRINT
+               curttyb.c_cc[VREPRINT] = nonesuch;
+# endif
+# ifdef VDISCARD
+               curttyb.c_cc[VDISCARD] = nonesuch;
+# endif
+# ifdef VWERASE
+               curttyb.c_cc[VWERASE] = nonesuch;
+# endif
+# ifdef VLNEXT
+               curttyb.c_cc[VLNEXT] = nonesuch;
+# endif
+#endif
+               change++;
+       }
+       if(!IS_7BIT(inittyb)) curttyb.inputflags &=~ STRIPHI;
+       /* If an interrupt character is used, it will be overriden and
+        * set to ^C.
+        */
+       if(intr_char != nonesuch && curttyb2.intr_sym != '\003') {
+           curttyb2.intr_sym = '\003';
+           change++;
+       }
+
+       if(change) setctty();
+       start_screen();
+}
+
+void
+intron()               /* enable kbd interupts if enabled when game started */
+{
+#ifdef TTY_GRAPHICS
+       /* Ugly hack to keep from changing tty modes for non-tty games -dlc */
+       if (!strcmp(windowprocs.name, "tty") &&
+           intr_char != nonesuch && curttyb2.intr_sym != '\003') {
+           curttyb2.intr_sym = '\003';
+           setctty();
+       }
+#endif
+}
+
+void
+introff()              /* disable kbd interrupts if required*/
+{
+#ifdef TTY_GRAPHICS
+       /* Ugly hack to keep from changing tty modes for non-tty games -dlc */
+       if (!strcmp(windowprocs.name, "tty") &&
+          curttyb2.intr_sym != nonesuch) {
+           curttyb2.intr_sym = nonesuch;
+           setctty();
+       }
+#endif
+}
+
+#ifdef _M_UNIX         /* SCO UNIX (3.2.4), from Andreas Arens */
+# include <sys/console.h>
+
+# define BSIZE (E_TABSZ*2)
+# define LDIOC ('D'<<8)                /* POSIX prevents definition */
+
+# include <sys/emap.h>
+
+int sco_flag_console = 0;
+int sco_map_valid = -1;
+unsigned char sco_chanmap_buf[BSIZE];
+
+void NDECL(sco_mapon);
+void NDECL(sco_mapoff);
+void NDECL(check_sco_console);
+void NDECL(init_sco_cons);
+
+void
+sco_mapon()
+{
+# ifdef TTY_GRAPHICS
+       if (!strcmp(windowprocs.name, "tty") && sco_flag_console) {
+               if (sco_map_valid != -1) {
+                       ioctl(0,LDSMAP,sco_chanmap_buf);
+               }
+               sco_map_valid = -1;
+       }
+# endif
+}
+
+void
+sco_mapoff()
+{
+# ifdef TTY_GRAPHICS
+       if (!strcmp(windowprocs.name, "tty") && sco_flag_console) {
+               sco_map_valid = ioctl(0,LDGMAP,sco_chanmap_buf);
+               if (sco_map_valid != -1) {
+                       ioctl(0,LDNMAP,(char *)0);
+               }
+       }
+# endif
+}
+
+void
+check_sco_console()
+{
+       if (isatty(0) && ioctl(0,CONS_GET,0) != -1) {
+               sco_flag_console = 1;
+       }
+}
+
+void
+init_sco_cons()
+{
+# ifdef TTY_GRAPHICS
+       if (!strcmp(windowprocs.name, "tty") && sco_flag_console) {
+               atexit(sco_mapon);
+               sco_mapoff();
+               switch_graphics(IBM_GRAPHICS);
+#  ifdef TEXTCOLOR
+               if (has_colors())
+                       iflags.use_color = TRUE;
+#  endif
+       }
+# endif
+}
+#endif /* _M_UNIX */
+
+
+#ifdef __linux__               /* via Jesse Thilo and Ben Gertzfield */
+# include <sys/vt.h>
+
+int linux_flag_console = 0;
+
+void NDECL(linux_mapon);
+void NDECL(linux_mapoff);
+void NDECL(check_linux_console);
+void NDECL(init_linux_cons);
+
+void
+linux_mapon()
+{
+# ifdef TTY_GRAPHICS
+       if (!strcmp(windowprocs.name, "tty") && linux_flag_console) {
+               write(1, "\033(B", 3);
+       }
+# endif
+}
+
+void
+linux_mapoff()
+{
+# ifdef TTY_GRAPHICS
+       if (!strcmp(windowprocs.name, "tty") && linux_flag_console) {
+               write(1, "\033(U", 3);
+       }
+# endif
+}
+
+void
+check_linux_console()
+{
+       struct vt_mode vtm;
+
+       if (isatty(0) && ioctl(0,VT_GETMODE,&vtm) >= 0) {
+               linux_flag_console = 1;
+       }
+}
+
+void
+init_linux_cons()
+{
+# ifdef TTY_GRAPHICS
+       if (!strcmp(windowprocs.name, "tty") && linux_flag_console) {
+               atexit(linux_mapon);
+               linux_mapoff();
+#  ifdef TEXTCOLOR
+               if (has_colors())
+                       iflags.use_color = TRUE;
+#  endif
+       }
+# endif
+}
+#endif /* __linux__ */
+
+
+#ifndef __begui__      /* the Be GUI will define its own error proc */
+/* fatal error */
+/*VARARGS1*/
+void
+error VA_DECL(const char *,s)
+       VA_START(s);
+       VA_INIT(s, const char *);
+       if(settty_needed)
+               settty((char *)0);
+       Vprintf(s,VA_ARGS);
+       (void) putchar('\n');
+       VA_END();
+       exit(EXIT_FAILURE);
+}
+#endif /* !__begui__ */
diff --git a/sys/share/uudecode.c b/sys/share/uudecode.c
new file mode 100644 (file)
index 0000000..b5ef43a
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Modified 12 April 1990 by Mark Adler for use on MSDOS systems with
+ * Microsoft C and Turbo C.
+ *
+ * Modifed 13 February 1991 by Greg Roelofs for use on VMS systems.  As
+ * with the MS-DOS version, the setting of the file mode has been disabled.
+ * Compile and link normally (but note that the shared-image link option
+ * produces a binary only 6 blocks long, as opposed to the 137-block one
+ * produced by an ordinary link).  To set up the VMS symbol to run the
+ * program ("run uudecode filename" won't work), do:
+ *             uudecode :== "$disk:[directory]uudecode.exe"
+ * and don't forget the leading "$" or it still won't work.  The binaries
+ * produced by this program are in VMS "stream-LF" format; this makes no
+ * difference to VMS when running decoded executables, nor to VMS unzip,
+ * but other programs such as zoo or arc may or may not require the file
+ * to be "BILFed" (or "unBILFed" or whatever).  Also, unlike the other
+ * flavors, VMS files don't get overwritten (a higher version is created).
+ * 
+ * Modified 13 April 1991 by Gary Mussar to be forgiving of systems that
+ * appear to be stripping trailing blanks.
+ *
+ * Modified 28 February 2002 for use on WIN32 systems with Microsoft C.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)uudecode.c 5.5 (Berkeley) 7/6/88";
+#endif /* not lint */
+
+#ifdef __MSDOS__        /* For Turbo C */
+#define MSDOS 1
+#endif
+
+#ifdef _WIN32
+#undef MSDOS
+#undef __MSDOS__
+#ifndef WIN32
+#define WIN32
+#endif
+#endif
+
+/*
+ * uudecode [input]
+ *
+ * create the specified file, decoding as you go.
+ * used with uuencode.
+ */
+#include <stdio.h>
+
+#ifdef VMS
+#  include <types.h>
+#  include <stat.h>
+#else
+#  if !defined(MSDOS) && !defined(WIN32)
+#    include <pwd.h>
+#  endif
+#  include <sys/types.h>   /* MSDOS, WIN32, or UNIX */
+#  include <sys/stat.h>
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+
+static void decode(FILE *, FILE *);
+static void outdec(char *, FILE *, int);
+
+/* single-character decode */
+#define DEC(c) (((c) - ' ') & 077)
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+       FILE *in, *out;
+       int mode;
+       char dest[128];
+       char buf[80];
+
+       /* optional input arg */
+       if (argc > 1) {
+               if ((in = fopen(argv[1], "r")) == NULL) {
+                       perror(argv[1]);
+                       exit(1);
+               }
+               argv++; argc--;
+       } else
+               in = stdin;
+
+       if (argc != 1) {
+               printf("Usage: uudecode [infile]\n");
+               exit(2);
+       }
+
+       /* search for header line */
+       for (;;) {
+               if (fgets(buf, sizeof buf, in) == NULL) {
+                       fprintf(stderr, "No begin line\n");
+                       exit(3);
+               }
+               if (strncmp(buf, "begin ", 6) == 0)
+                       break;
+       }
+       (void)sscanf(buf, "begin %o %s", &mode, dest);
+
+#if !defined(MSDOS) && !defined(VMS) && !defined(WIN32)
+       /* handle ~user/file format */
+       if (dest[0] == '~') {
+               char *sl;
+               struct passwd *getpwnam();
+               struct passwd *user;
+               char dnbuf[100], *index(), *strcat(), *strcpy();
+
+               sl = index(dest, '/');
+               if (sl == NULL) {
+                       fprintf(stderr, "Illegal ~user\n");
+                       exit(3);
+               }
+               *sl++ = 0;
+               user = getpwnam(dest+1);
+               if (user == NULL) {
+                       fprintf(stderr, "No such user as %s\n", dest);
+                       exit(4);
+               }
+               strcpy(dnbuf, user->pw_dir);
+               strcat(dnbuf, "/");
+               strcat(dnbuf, sl);
+               strcpy(dest, dnbuf);
+       }
+#endif /* !defined(MSDOS) && !defined(VMS) */
+
+       /* create output file */
+#if defined(MSDOS) || defined(WIN32)
+       out = fopen(dest, "wb");        /* Binary file */
+#else
+       out = fopen(dest, "w");
+#endif
+       if (out == NULL) {
+               perror(dest);
+               exit(4);
+       }
+#if !defined(MSDOS) && !defined(VMS) && !defined(WIN32)        /* i.e., UNIX */
+       chmod(dest, mode);
+#endif
+
+       decode(in, out);
+
+       if (fgets(buf, sizeof buf, in) == NULL || strcmp(buf, "end\n")) {
+               fprintf(stderr, "No end line\n");
+               exit(5);
+       }
+       exit(0);
+       /*NOTREACHED*/
+       return 0;
+}
+
+/*
+ * copy from in to out, decoding as you go along.
+ */
+void
+decode(in, out)
+FILE *in;
+FILE *out;
+{
+       char buf[80];
+       char *bp;
+       int n, i, expected;
+
+       for (;;) {
+               /* for each input line */
+               if (fgets(buf, sizeof buf, in) == NULL) {
+                       printf("Short file\n");
+                       exit(10);
+               }
+               n = DEC(buf[0]);
+               if ((n <= 0) || (buf[0] == '\n'))
+                       break;
+
+               /* Calculate expected # of chars and pad if necessary */
+               expected = ((n+2)/3)<<2;
+               for (i = strlen(buf)-1; i <= expected; i++) buf[i] = ' ';
+
+               bp = &buf[1];
+               while (n > 0) {
+                       outdec(bp, out, n);
+                       bp += 4;
+                       n -= 3;
+               }
+       }
+}
+
+/*
+ * output a group of 3 bytes (4 input characters).
+ * the input chars are pointed to by p, they are to
+ * be output to file f.  n is used to tell us not to
+ * output all of them at the end of the file.
+ */
+void
+outdec(p, f, n)
+char *p;
+FILE *f;
+int n;
+{
+       int c1, c2, c3;
+
+       c1 = DEC(*p) << 2 | DEC(p[1]) >> 4;
+       c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
+       c3 = DEC(p[2]) << 6 | DEC(p[3]);
+       if (n >= 1)
+               putc(c1, f);
+       if (n >= 2)
+               putc(c2, f);
+       if (n >= 3)
+               putc(c3, f);
+}
+
+#if !defined(MSDOS) && !defined(VMS) && !defined(WIN32)
+/*
+ * Return the ptr in sp at which the character c appears;
+ * NULL if not found
+ */
+
+#ifndef NULL
+#define        NULL    0
+#endif
+
+char *
+index(sp, c)
+register char *sp, c;
+{
+       do {
+               if (*sp == c)
+                       return(sp);
+       } while (*sp++);
+       return(NULL);
+}
+#endif
+
diff --git a/sys/unix/Install.unx b/sys/unix/Install.unx
new file mode 100644 (file)
index 0000000..cbdfca3
--- /dev/null
@@ -0,0 +1,268 @@
+                Instructions for installing NetHack 3.4
+                           on a UNIX system
+                =======================================
+
+0.  Read this entire file before starting, and come back to the Notes
+    below if you have any problems.  If you are trying to use X11,
+    also read all of win/X11/Install.X11, or read win/Qt/Install.Qt
+    if you are using Qt or KDE under X11.  For help in controlling
+    and running the game after it is installed, see the '?' command
+    within the game and doc/Guidebook (non-installers want to know
+    about those things too).
+
+1.  Make sure all the NetHack files are in the appropriate directory
+    structure.  You should have a main directory with subdirectories
+    dat, doc, include, src, util, sys/share, sys/unix, win/tty, win/X11,
+    and win/Qt.  You may have other subdirectories under sys and win,
+    but they will not affect compilation for a UNIX system.  If you do
+    not follow this structure, the Makefiles will not function properly.
+    The .c files for the main program belong in src, those for utility
+    programs in util, and UNIX-specific ones in sys/unix.  All the .h
+    files belong in include, the documentation in doc, and assorted
+    data files in dat.  Some UNIX versions may also be interested in
+    sys/share's random.c or its lex/yacc output, as explained in note 11.
+    (A more detailed explanation of the directory structure may be found
+    in Files, which should be in the top directory.)
+
+2.  Your Makefiles may still be in sys/unix with tags on the end of them.
+    If so, run "sh setup.sh" in that directory to distribute the Makefiles
+    to places they can do their work.  (If later official patches change
+    these Makefiles, setup.sh should be rerun to make sure you use the
+    current copies.)
+
+3.  Go to the include subdirectory and edit config.h according to the
+    comments to match your system and desired set of features.  Similarly
+    edit unixconf.h.  Please see the "Notes:" section, below, for some
+    configuration hints for particular systems.
+
+4.  If you want to, look through system.h.  This file attempts to match the
+    types for system calls and library routines with various flavors of
+    operating systems.  Leaving this file alone is unlikely to cause worse
+    problems than lint errors, but it's worth checking if you get compile
+    errors, especially if you have an unusual system.
+
+5.  Go to the src subdirectory and look at the top of topten.c.  You may want
+    to change the definitions of PERSMAX and PERS_IS_UID here to get different
+    behavior from the high score list.
+
+6.  Edit the top sections of the src and util Makefiles.  (If you are doing
+    a full recompile, or if you got your files from someplace besides the
+    official distribution, type 'touch makedefs.c' to make sure certain files
+    (onames.h, pm.h) get remade instead of relying on the potentially
+    troublesome timestamps.)  Then type 'make' in src and go get a cup of
+    coffee or take a nap, depending on the speed of your system.  You should
+    now have created the game executable.
+
+7.  Go back to the top directory and edit that Makefile, explaining where
+    you want everything to be installed.
+
+    Make sure that you follow the comments about setting GAMEDIR -- the
+    installation process will wipe out the contents of the directory you
+    point it at, under the assumption that it's debris from an old version
+    of NetHack.  If this is not the case, you'll want to install somewhere
+    else, or comment out the rm under the install target.
+
+    The Makefile assumes you want to run NetHack setuid 'games' to cut down
+    on possible tampering; it's fairly straightforward to comment out the
+    appropriate chmod if you don't want that, or to change any of the rest
+    of the procedure.  (Note that if you don't want to run NetHack either
+    setuid or setgid, and people in more than one group will be playing it,
+    you'll need to go back and set FCMASK to 0666 in unixconf.h and let
+    everybody fiddle with the files NetHack creates.)
+
+    If the tbl, nroff or col commands are not available on your system,
+    edit the doc/Makefile and change the GUIDECMD as directed.
+
+    Type 'make all' from the top directory to set up all the auxiliary
+    files the main executable will use.  Then become root if necessary and
+    type 'make install'.  Everything should now be set.
+
+8.  Read doc/recover.man or doc/recover.txt to learn how to use the recover
+    program.  The recover program can be used in case of a crash to recover
+    a game that was in progress.  The recover command is installed in the
+    GAMEDIR by default.
+
+Notes:
+
+1.  Save files and bones files from previous versions will not work with
+    NetHack 3.4.  Don't bother trying to keep them.
+
+2.  To install an update of this version of NetHack after changing something,
+    type 'make update' from the main directory.  If you created the new
+    version yourself, it should be safe to use 'make update' as long as you
+    did not add, delete, or reorder monsters or objects and you did not change
+    the format of saved level files.  If you did any of these things, you
+    should also remove any saved games and bones levels.  (Trying to use such
+    files often produces amusing but useless confusions on the game's part.)
+
+3.  If you insisted on doing the final installation by hand, you probably
+    forgot to make a save directory.  If you don't go back and do this, you
+    won't be able to save games.
+
+4.  If you get unexplained deaths by trickery, you are probably running
+    NetHack on a bunch of workstations, but you have overlooked the NETWORK
+    definition in unixconf.h that is necessary in that configuration.
+
+5.  If spurious characters appear on the screen while throwing, kicking,
+    zapping, etc., it is likely that you have linked the source to the wrong
+    library or mistakenly defined/undefined TERMINFO.  A number of systems,
+    such as Xenix, support both the termcap and terminfo terminal capability
+    libraries.  In such cases, the TERMINFO definition in unixconf.h and the
+    WINTTYLIB definition in the source Makefile must correspond.
+
+    If your terminal library does not provide suitable delays, NetHack will
+    try to fake its own if you set the nonull option.
+
+6.  Since NetHack overflows the stock C preprocessors for AT&T 3b1 and 3b2
+    systems ("too many defines"), we are including an alternate preprocessor
+    to allow these folks to compile.  This is the DECUS cpp by Martin Minow,
+    slightly modified by Kevin Darcy to use larger buffers, be less verbose,
+    and handle strange constructs in AT&T's include files.
+
+    To use this preprocessor, unpack the cpp* files found in sys/unix into
+    some handy directory (util will do).  For the AT&T machines mentioned
+    above, nothing needs to be configured; you should get a working cpp by
+    merely typing "make -f makefile.txt".  To get your compiler to use the
+    new cpp, you will have to add to CFLAGS in src/Makefile and util/Makefile.
+    If you put the cpp files in /foo/bar/util, add "-B/foo/bar/util/ -tp"
+    for a 3b1 or "-Yp,/foo/bar/util" for a 3b2.
+
+    For any other machine whose preprocessor can't handle the NetHack source,
+    you'll have to play it by ear.  The preprocessor has many esoteric
+    configuration options, but most probably you will only need to change
+    the flags in makefile.txt, and then refer to your compiler's documentation
+    to find the appropriate CFLAGS for the NetHack Makefiles.  (The SunOS flag,
+    for instance, would be "-Qpath /foo/bar/util", although the native cpp
+    has no trouble with NetHack.  So much for standardization.)
+
+7.  If you are trying to compile NetHack on an AT&T 3B that is running an
+    OS earlier than SVR3, you are likely to have problems with overflowing
+    symbol tables.  This can be worked around by editing the source Makefile
+    to make the Sys.3B2 target work more like the SysV-AT target, adding
+    -DDUMB to CFLAGS and DUMB.Setup to the Sys.3B2 dependency line.  The
+    compiler provided with later versions of the OS has a large enough
+    symbol table that it does not need this workaround.
+
+8.  If NetHack seems to compile fine, starts up, allows you to pick a
+    character, and then hangs indefinitely, gets a segmentation fault, or
+    traps you in a single room on the first level, you might try changing
+    the schar and uchar definitions in config.h to short ints.  This problem
+    is known to occur on the AT&T 3B series, Silicon Graphics Irises, and
+    IBM systems (PC/RT & RS/6000) running AIX, and may occur on other
+    computers as well.
+
+    This problem is really most likely caused by having a non-__STDC__
+    compiler with char's unsigned by default.  Since some such compilers
+    don't understand the new "signed" keyword, and others don't have signed
+    characters to use (the 3B2 line falls into this category), "signed"
+    is #ifdefed away for them.  If you are sure your compiler can deal
+    with it, you can add your compiler to the __HC__ case in tradstdc.h.
+
+    Alternatively, if the compiler supports a command line switch for
+    setting the default char type to signed, you could try setting it in
+    the Makefiles.  The appropriate switch for SGI Irises with MIPS C
+    compiler is "-signed" and for RS/6000's with standard cc "-qchars=signed".
+    (SGI machines running IRIX 4.0.x have a compiler close enough to
+    standard to suit NetHack, so you may merely use the suggested flags
+    in the Makefiles.)
+
+    Note that at least RS/6000's seem to like changing the default to
+    signed better but there is also a problem:  The lexers created by
+    the standard lex program in AIX may come out faulty when this switch
+    is used (known to happen at least in AIX 3.1.3), so you may have to
+    use an alternative, like flex, which is available at major archive
+    sites (see notes 10 and 11).
+
+    By AIX 3.2.5, this whole problem should be taken care of automatically
+    (but AIX_31 should still be defined in unixconf.h for other reasons).
+
+9.  Under SCO UNIX, you may have all sorts of complaints about
+    include/obj.h.  Go to the file and uncomment the marked line, working
+    around the fact that SCO's system include files preempt a major
+    NetHack structure name.  Also, there are difficulties with SCO's cc
+    that thus far have been solved only by changing compilers; one report
+    says gcc-NetHack works, and another says rcc-NetHack can be made to
+    work by defining NOTSTDC, applying note 8, and compiling with -tinfo
+    and -xenix.  The cc problems are old enough that a new, working
+    version may have been released by this time.
+
+10. Xenix/286's lex generates a faulty lexical analyser from lev_comp.l.
+    The beta-release of flex 2.3 (available from uunet, osu-cis,
+    prep.ai.mit.edu, etc.) can be used to generate the lexer.
+    The only change to flex is to change "#define yyleng (yy_cp - yy_bp)"
+    to "#define yyleng (int)(yy_cp - yy_bp)" in flex.skel.
+    Flex is not needed with Xenix/386, as its lex generates a proper lexical
+    analyser.  [Xenix instructions by J.T. Conklin]
+
+11. If your system does not have a lex/yacc or flex/bison combination
+    capable of producing the dungeon and level compilers, lex and yacc
+    output from one of our development systems can be found in sys/share.
+    Unfortunately, this output is less portable than the rest of the code,
+    as it contains skeleton parsing code provided by the specific vendor
+    who has no particular incentive to make such skeletons portable, but
+    the output works on most systems.  To try it on yours, copy dgn_comp.h
+    and lev_comp.h to include and dgn_lex.c, dgn_yacc.c, lev_lex.c, and
+    lev_yacc.c to util.
+
+12. Yes, Virginia, you compile NetHack for a NeXT as if it ran UNIX instead
+    of Mach.  Just tell NetHack you're a BSD system (Mach is extremely
+    close to BSD UNIX for traditional system calls, so this is also a
+    likely thing to try for any other programs you want to compile).
+
+    If you get errors when starting nethack warning that "Setuid execution is 
+    not allowed", you might want to re-install using the setgid option instead
+    (see Note 7 above, and the setgid comment in the toplevel Makefile).
+
+13. If you are using Solaris 2.x (aka SunOS 5.x) you shouldn't have to
+    do any system configuration -- this is the default.  In case it is
+    messed up, follow these instructions.
+
+    Solaris is basically a SVR4 system, not a BSD system.  Therefore, you
+    configure config.h and unixconf.h as per a SVR4 system:
+
+       config.h: UNIX, TTY_GRAPHICS
+       unixconf.h: SYSV, SVR4, TERMINFO, POSIX_JOB_CONTROL, POSIX_TYPES
+
+    X11_GRAPHICS does work.  Do not define OPENWINBUG.  You may safely define
+    NETWORK, TEXTCOLOR if desired.  Other #defines in these files may be
+    defined too, as needed.  Just make sure that the set mentioned here are
+    not misdefined, or your compile will fail (do _not_ define BSD or SUNOS4).
+    Unless you are using gzip you will probably want to define COMPRESS to
+    be "/usr/bin/compress".
+
+    When compiling, make sure that you use the ANSI C SVR4 compatible
+    compiler, /usr/bin/cc, or gcc, but _not_ ucbcc.  The lattermost will
+    not work.  After this, you should get a clean compile.
+
+    Also, it is recommended that you use FLEX instead of the standard
+    lex bundled with Solaris 2.x (even if that last one should work ;-).
+
+14. If your machine is a 286, 386, or 486 running an appropriate OS, you
+    may wish to use the console speaker driver included in
+    sys/unix/snd86unx.shr.  This will allow audible music to be played
+    on your console speaker in certain appropriate game situations.  The only
+    modification to the main-line code needed to enable use of the driver
+    is defining UNIX386MUSIC or VPIX_MUSIC in unixconf.h.
+
+15. If you are trying to cross-compile for another system, there is some
+    support in the src and util Makefiles, but there are still other
+    complications.  It may well be best to make another copy of util,
+    util2, to compile target copies of makedefs, lev_comp, and recover
+    (duplicating the cross-compilation settings from the src Makefile)
+    without disturbing the main build.
+
+    You can use the host makedefs for everything but "makedefs -v", which
+    creates include/date.h, which provides various sanity-checking values
+    for making sure files read by NetHack at run-time are compatible.
+    These values depend on the endianness of your processor, its type
+    sizes, and its compiler's idea of struct packing.  Your host and target
+    computers may disagree on these things, so you'll need to build a target
+    version of makedefs, run "makedefs -v" on your target, and bring the
+    resulting date.h back for the builds on the host.  (Making sure the host
+    makedefs doesn't decide it needs to overwrite it for you. :-)
+
+    You also need a target version of lev_comp, and to provide it with all
+    the dat/*.des files, and copy all the resulting *.lev files back for
+    packaging on the host.
+
+    For recover, you just want the target binary to install on the target.
diff --git a/sys/unix/Makefile.dat b/sys/unix/Makefile.dat
new file mode 100644 (file)
index 0000000..75a5aa8
--- /dev/null
@@ -0,0 +1,144 @@
+#      NetHack Makefile.
+#      SCCS Id: @(#)Makefile.dat       3.4     1992/09/18
+
+# for Atari
+# SHELL=E:/GEMINI2/MUPFEL.TTP
+# UUDECODE=uudecode
+
+VARDAT = data rumors quest.dat oracles options
+
+all:   $(VARDAT) spec_levs quest_levs dungeon
+
+../util/makedefs:
+       (cd ../util ; make makedefs)
+
+../util/dgn_comp:
+       (cd ../util ; make dgn_comp)
+
+../util/lev_comp:
+       (cd ../util ; make lev_comp)
+
+../util/tile2x11:
+       (cd ../util ; make tile2x11)
+
+../util/tile2beos:
+       (cd ../util ; make tile2beos)
+
+../util/tile2bmp:
+       (cd ../util ; make tile2bmp)
+
+x11tiles: ../util/tile2x11 ../win/share/monsters.txt ../win/share/objects.txt \
+                               ../win/share/other.txt
+       ../util/tile2x11 ../win/share/monsters.txt ../win/share/objects.txt \
+                               ../win/share/other.txt
+
+beostiles: ../util/tile2beos ../win/share/monsters.txt ../win/share/objects.txt \
+                               ../win/share/other.txt
+       ../util/tile2beos ../win/share/monsters.txt ../win/share/objects.txt \
+                               ../win/share/other.txt
+
+nhtiles.bmp: ../util/tile2bmp ../win/share/monsters.txt ../win/share/objects.txt \
+                               ../win/share/other.txt
+       ../util/tile2bmp $@
+
+NetHack.ad: ../win/X11/NetHack.ad
+       cp ../win/X11/NetHack.ad NetHack.ad
+
+pet_mark.xbm: ../win/X11/pet_mark.xbm
+       cp ../win/X11/pet_mark.xbm pet_mark.xbm
+
+rip.xpm: ../win/X11/rip.xpm
+       cp ../win/X11/rip.xpm rip.xpm
+
+mapbg.xpm: ../win/gnome/mapbg.xpm
+       cp ../win/gnome/mapbg.xpm mapbg.xpm
+
+nhsplash.xpm: ../win/Qt/nhsplash.xpm
+       cp ../win/Qt/nhsplash.xpm nhsplash.xpm
+
+nethack.icns: ../win/Qt/nhicns.uu
+       $(UUDECODE) ../win/Qt/nhicns.uu
+
+Info.plist: ../win/Qt/Info.pli
+       cp ../win/Qt/Info.pli Info.plist
+
+../util/tile2img.ttp:
+       (cd ../util ; make tile2img.ttp)
+
+../util/xpm2img.ttp:
+       (cd ../util ; make xpm2img.ttp)
+nh16.img: ../util/tile2img.ttp ../win/share/monsters.txt \
+                               ../win/share/objects.txt ../win/share/other.txt
+       ../util/tile2img.ttp nh16.img
+
+rip.img: ../util/xpm2img.ttp
+       ../util/xpm2img.ttp ../win/X11/rip.xpm rip.img
+title.img:
+       # cp ../win/gem/title.img title.img
+       $(UUDECODE) ../win/gem/title.uu
+
+GEM_RSC.RSC:
+       # cp ../win/gem/GEM_RSC.RSC GEM_RSC.RSC
+       $(UUDECODE) ../win/gem/gem_rsc.uu
+
+
+data:  data.base ../util/makedefs
+       ../util/makedefs -d
+
+rumors:        rumors.tru rumors.fal ../util/makedefs
+       ../util/makedefs -r
+
+quest.dat:     quest.txt ../util/makedefs
+       ../util/makedefs -q
+
+oracles:       oracles.txt ../util/makedefs
+       ../util/makedefs -h
+
+# note: 'options' should have already been made when include/date.h was created
+options:       ../util/makedefs
+       ../util/makedefs -v
+
+
+spec_levs: ../util/lev_comp \
+       bigroom.des castle.des endgame.des gehennom.des knox.des medusa.des \
+       mines.des oracle.des sokoban.des tower.des yendor.des
+       ../util/lev_comp bigroom.des
+       ../util/lev_comp castle.des
+       ../util/lev_comp endgame.des
+       ../util/lev_comp gehennom.des
+       ../util/lev_comp knox.des
+       ../util/lev_comp medusa.des
+       ../util/lev_comp mines.des
+       ../util/lev_comp oracle.des
+       ../util/lev_comp sokoban.des
+       ../util/lev_comp tower.des
+       ../util/lev_comp yendor.des
+       touch spec_levs
+
+quest_levs: ../util/lev_comp \
+       Arch.des Barb.des Caveman.des Healer.des Knight.des Monk.des \
+       Priest.des Ranger.des Rogue.des Samurai.des Tourist.des Valkyrie.des \
+       Wizard.des
+       ../util/lev_comp Arch.des
+       ../util/lev_comp Barb.des
+       ../util/lev_comp Caveman.des
+       ../util/lev_comp Healer.des
+       ../util/lev_comp Knight.des
+       ../util/lev_comp Monk.des
+       ../util/lev_comp Priest.des
+       ../util/lev_comp Ranger.des
+       ../util/lev_comp Rogue.des
+       ../util/lev_comp Samurai.des
+       ../util/lev_comp Tourist.des
+       ../util/lev_comp Valkyrie.des
+       ../util/lev_comp Wizard.des
+       touch quest_levs
+
+dungeon: dungeon.def ../util/makedefs ../util/dgn_comp
+       ../util/makedefs -e
+       ../util/dgn_comp dungeon.pdf
+
+spotless:
+       -rm -f spec_levs quest_levs *.lev $(VARDAT) dungeon dungeon.pdf
+       -rm -f nhdat x11tiles beostiles pet_mark.xbm rip.xpm mapbg.xpm
+       -rm -f rip.img GEM_RSC.RSC title.img nh16.img NetHack.ad
diff --git a/sys/unix/Makefile.doc b/sys/unix/Makefile.doc
new file mode 100644 (file)
index 0000000..647e90a
--- /dev/null
@@ -0,0 +1,95 @@
+#      NetHack Makefile.
+#      SCCS Id: @(#)Makefile.doc       3.4     1996/03/23
+
+# for Atari
+# SHELL=E:/GEMINI2/MUPFEL.TTP
+
+GUIDEBOOK = Guidebook          # regular ASCII file
+#GUIDEBOOK = Guidebook.ps      # PostScript file
+#GUIDEBOOK = Guidebook.dvi     # TeX device-independent file
+
+# Some versions of col need -x to keep them from converting spaces to tabs;
+# some versions of col don't do the conversion by default and don't
+# recognize the option.  Sigh.
+COLCMD = col -bx
+#COLCMD = col -b
+
+# The command to use to generate a PostScript file
+# PSCMD = ditroff | psdit
+PSCMD = groff
+
+# Use the "cat" GUIDECMD if nroff and/or tbl and/or col are not installed
+# Not appropriate for creating Guidebook.txt.
+# GUIDECMD = cat Guidebook.txt
+# The following works better with groff-1.18, eg on Linux
+# GUIDECMD = tbl tmac.n Guidebook.mn | nroff -c -Tascii | $(COLCMD)
+GUIDECMD = tbl tmac.n Guidebook.mn | nroff | $(COLCMD)
+
+# the basic guidebook
+Guidebook:     Guidebook.mn
+       $(GUIDECMD) > Guidebook
+
+# Fancier output for those with ditroff, psdit and a PostScript printer.
+Guidebook.ps:  Guidebook.mn
+       tbl tmac.n Guidebook.mn | $(PSCMD) > Guidebook.ps
+
+# Guidebook.tex is the same as Guidebook.mn but formatted with LaTeX.
+# - The invocation command for LaTeX may vary in different installations.
+# - To print Guidebook.dvi you need to use a suitable dvi-driver.
+Guidebook.dvi: Guidebook.tex
+       latex Guidebook.tex
+
+
+GAME   = nethack
+MANDIR = /usr/man/man6
+MANEXT = 6
+
+# manual installation for most BSD-style systems
+GAMEMANCREATE = cp nethack.6
+LEVMANCREATE = cp lev_comp.6
+DGNMANCREATE = cp dgn_comp.6
+RCVRMANCREATE = cp recover.6
+DLBMANCREATE = cp dlb.6
+# manual installation for most SYSV-style systems
+# GAMEMANCREATE = nroff -man nethack.6 >
+# LEVMANCREATE = nroff -man lev_comp.6 >
+# DGNMANCREATE = nroff -man dgn_comp.6 >
+# RCVRMANCREATE = nroff -man recover.6 >
+# DLBMANCREATE = nroff -man dlb.6 >
+
+manpages:
+       -$(GAMEMANCREATE) $(MANDIR)/$(GAME).$(MANEXT)
+       -$(LEVMANCREATE) $(MANDIR)/lev_comp.$(MANEXT)
+       -$(DGNMANCREATE) $(MANDIR)/dgn_comp.$(MANEXT)
+       -$(RCVRMANCREATE) $(MANDIR)/recover.$(MANEXT)
+       -$(DLBMANCREATE) $(MANDIR)/dlb.$(MANEXT)
+
+# manual creation for distribution
+DISTRIB = Guidebook.txt nethack.txt lev_comp.txt dgn_comp.txt recover.txt dlb.txt
+
+distrib: $(DISTRIB)
+       @echo "Plain text documentation is up to date."
+
+Guidebook.txt  : Guidebook.mn tmac.n
+       $(GUIDECMD) > Guidebook.txt
+nethack.txt    : nethack.6
+       nroff -man nethack.6 | $(COLCMD) > nethack.txt
+lev_comp.txt   : lev_comp.6
+       nroff -man lev_comp.6 | $(COLCMD) > lev_comp.txt
+dgn_comp.txt   : dgn_comp.6
+       nroff -man dgn_comp.6 | $(COLCMD) > dgn_comp.txt
+recover.txt    : recover.6
+       nroff -man recover.6 | $(COLCMD) > recover.txt
+dlb.txt                : dlb.6
+       nroff -man dlb.6 | $(COLCMD) > dlb.txt
+
+
+clean:
+       -rm -f Guidebook.aux Guidebook.log
+
+spotless: clean
+       -rm -f Guidebook Guidebook.ps Guidebook.dvi
+
+maintainer-clean: spotless
+       -rm -f $(DISTRIB)
+#      -rm -f Makefile
diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src
new file mode 100644 (file)
index 0000000..29ad99a
--- /dev/null
@@ -0,0 +1,814 @@
+#      NetHack Makefile.
+#      SCCS Id: @(#)Makefile.src       3.4     2002/03/02
+
+# newer makes predefine $(MAKE) to 'make' and do smarter processing of
+# recursive make calls if $(MAKE) is used
+# these makes allow $(MAKE) to be overridden by the environment if someone
+# wants to (or has to) use something other than the standard make, so we do
+# not want to unconditionally set $(MAKE) here
+#
+# unfortunately, some older makes do not predefine $(MAKE); if you have one of
+# these, uncomment the following line
+# (you will know that you have one if you get complaints about being unable
+# to find 'makedefs')
+# MAKE = make
+
+# This makefile replaces the previous Makefile.unix, Makefile.xenix,
+# Makefile.3B2, Makefile.att, and Makefile.tos.
+# Set SYSTEM to one of:
+#      'Sysunix'       -- generic UNIX
+#      'Sys3B2'        -- AT&T 3B2, 3B5, etc.
+#      'Sysatt'        -- AT&T UNIXPC, 7300, 3B1
+#      'SysV-AT'       -- Microport 286 UNIX (put -DDUMB in CFLAGS)
+#      'Systos'        -- Atari
+#      'SysBe'         -- BeOS
+SYSTEM = Sysunix
+
+#
+# Make sure that your bourne shell is specified here, as you have to spawn
+# some of the commands (eg. depend) in bourne shell for them to work.
+#
+# For Systos users compiling on the ST, you'll either need a bourne shell
+# clone or you'll need to do make depend, etc. by hand. In either case,
+# the line below probably needs changing
+SHELL=/bin/sh
+# for Atari
+# SHELL=E:/GEMINI2/MUPFEL.TTP
+
+# Normally, the C compiler driver is used for linking:
+LINK=$(CC)
+
+# Pick the SYSSRC and SYSOBJ lines corresponding to your desired operating
+# system.
+#
+# for UNIX systems
+SYSSRC = ../sys/share/ioctl.c ../sys/share/unixtty.c ../sys/unix/unixmain.c \
+       ../sys/unix/unixunix.c ../sys/unix/unixres.c
+SYSOBJ = ioctl.o unixmain.o unixtty.o unixunix.o unixres.o
+#
+# for Systos
+# SYSSRC = ../sys/atari/tos.c ../sys/share/pcmain.c ../sys/share/pcsys.c \
+#      ../sys/share/pctty.c ../sys/share/pcunix.c
+# SYSOBJ = tos.o pcmain.o pcsys.o pctty.o pcunix.o
+#
+# for BeOS
+#SYSSRC = ../sys/be/bemain.c ../sys/share/unixtty.c ../sys/share/ioctl.c
+#SYSOBJ = bemain.o unixtty.o ioctl.o
+
+
+# if you are using gcc as your compiler:
+#      uncomment the CC definition below if it's not in your environment
+#      if you get setcgtty() warnings during execution, you are feeding gcc
+#              a non-ANSI <sys/ioctl.h> -- either run fixincludes on it or use
+#              -traditional in CFLAGS
+# CC = gcc
+#
+#      For Bull DPX/2 systems at B.O.S. 2.0 or higher use the following:
+#
+# CC = gcc -ansi -D_BULL_SOURCE -D_XOPEN_SOURCE -D_POSIX_SOURCE
+#
+#      If you are using GCC 2.2.2 or higher on a DPX/2, just use:
+#
+# CC = gcc -ansi
+#
+#      For HP/UX 10.20 with GCC:
+# CC = gcc -D_POSIX_SOURCE
+#
+#      For cross-compiling, eg. with gcc on Linux (see also CXX further down):
+# CC = arm-linux-gcc
+#
+#
+# if you're debugging and want gcc to check as much as possible, use:
+# CC = gcc -W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN
+
+# flags may have to be changed as required
+# flags for 286 Xenix:
+# CFLAGS = -Ml2t16 -O -LARGE -I../include
+# LFLAGS = -Ml -F 4000 -SEG 512
+
+# flags for 286 Microport SysV-AT
+# CFLAGS = -DDUMB -Ml -I../include
+# LFLAGS = -Ml
+
+# flags for Atari gcc (3.2.1)
+# CFLAGS = -O -I../include
+# LFLAGS = -s
+# flags for Atari gcc (3.3)
+# CFLAGS = -mshort -O2 -fomit-frame-pointer -I../include
+# LFLAGS = -mshort -s
+
+# flags for AIX 3.1 cc on IBM RS/6000 to define
+# a suitable subset of standard libraries
+# (note that there is more info regarding the "-qchars=signed"
+# switch in file Install.unx note 8)
+# CFLAGS = -D_NO_PROTO -D_XOPEN_SOURCE -O -I../include -qchars=signed
+#
+# Some of our subroutines are complex enough that this is required for full
+# optimization under AIX 3.2 (I don't know about 3.1).
+#
+# CFLAGS = -D_NO_PROTO -D_XOPEN_SOURCE -D_ALL_SOURCE -O -I../include -qchars=signed -qmaxmem=5000
+
+# flags for A/UX 2.01 using native cc or c89
+# gcc predefines AUX so that's not needed there
+# Remember to use -lcurses for WINLIB below !
+# CFLAGS = -ZS -D_POSIX_SOURCE -O -I../include -DAUX
+
+# flags for IRIX 4.0.x using native cc
+# The include files are __STDC__, but have bugs involving const
+# CFLAGS = -O -I../include -D__STDC__ -Dconst= -woff 100,293
+# LFLAGS = -s
+
+# flags for BSD/OS 2.0
+# CFLAGS = -O -I../include -I/usr/X11/include
+# LFLAGS = -L/usr/X11/lib
+
+# flags for Linux
+#   compile normally
+# CFLAGS = -O2 -fomit-frame-pointer -I../include
+# LFLAGS = -L/usr/X11R6/lib
+#   OR compile backwards compatible a.out format
+# CFLAGS = -O2 -b i486-linuxaout -fomit-frame-pointer -I../include
+# LFLAGS = -b i486-linuxaout -L/usr/X11R6/lib
+
+# flags for BeOS
+#   on a Mac/BeBox:
+#CC = mwcc
+#CFLAGS = -r -I../include
+#LINK = mwld
+#LFLAGS = -map nethack.xMAP
+#   on Intel:
+#CFLAGS = -O -I../include
+#LINK = gcc
+#LFLAGS = -Xlinker -soname=_APP_
+
+# Only used for the Gnome interface.
+# When including the Gnome interface, you need to include gnome specific
+# directories.  The ones given below is the usual spot for linux systems.
+# The paths are for glibconfig.h and gnomesupport.h respectively.
+#
+GNOMEINC=-I/usr/lib/glib/include -I/usr/lib/gnome-libs/include -I../win/gnome
+
+# flags for debugging:
+# CFLAGS = -g -I../include
+
+CFLAGS = -O -I../include
+LFLAGS = 
+
+# The Qt and Be window systems are written in C++, while the rest of
+# NetHack is standard C.  If using Qt, uncomment the LINK line here to get
+# the C++ libraries linked in.
+CXXFLAGS = $(CFLAGS) -I. -I$(QTDIR)/include
+CXX=g++
+#LINK=g++
+#      For cross-compiling, eg. with gcc on Linux (see also CC further up):
+#CXX=arm-linux-g++
+#LINK=arm-linux-gcc
+
+# Set the WINSRC, WINOBJ, and WINLIB lines to correspond to your desired
+# combination of windowing systems.  Also set windowing systems in config.h.
+# Note that if you are including multiple tiled window systems, you don't
+# want two copies of tile.o, so comment out all but the first.
+#
+# files for a straight tty port using no native windowing system
+WINTTYSRC = ../win/tty/getline.c ../win/tty/termcap.c ../win/tty/topl.c \
+       ../win/tty/wintty.c
+WINTTYOBJ = getline.o termcap.o topl.o wintty.o
+#
+# files for an X11 port
+# (tile.c is a generated source file)
+WINX11SRC = ../win/X11/Window.c ../win/X11/dialogs.c ../win/X11/winX.c \
+       ../win/X11/winmap.c  ../win/X11/winmenu.c ../win/X11/winmesg.c \
+       ../win/X11/winmisc.c ../win/X11/winstat.c ../win/X11/wintext.c \
+       ../win/X11/winval.c tile.c
+WINX11OBJ = Window.o dialogs.o winX.o winmap.o winmenu.o winmesg.o \
+       winmisc.o winstat.o wintext.o winval.o tile.o
+#
+# Files for a Qt port
+#
+WINQTSRC = ../win/Qt/qt_win.cpp ../win/Qt/qt_clust.cpp ../win/Qt/qttableview.cpp
+WINQTOBJ = qt_win.o qt_clust.o qttableview.o tile.o
+#
+# Files for a Gnome port
+#
+WINGNOMESRC = ../win/gnome/gnaskstr.c ../win/gnome/gnbind.c \
+       ../win/gnome/gnglyph.c ../win/gnome/gnmain.c ../win/gnome/gnmap.c \
+       ../win/gnome/gnmenu.c ../win/gnome/gnmesg.c ../win/gnome/gnopts.c \
+       ../win/gnome/gnplayer.c ../win/gnome/gnsignal.c \
+       ../win/gnome/gnstatus.c ../win/gnome/gntext.c ../win/gnome/gnyesno.c \
+       ../win/gnome/gnworn.c
+WINGNOMEOBJ = gnaskstr.o gnbind.o gnglyph.o gnmain.o gnmap.o gnmenu.o \
+       gnmesg.o gnopts.o gnplayer.o gnsignal.o gnstatus.o gntext.o \
+       gnyesno.o gnworn.o tile.o
+#
+# Files for a Gem port
+WINGEMSRC = ../win/gem/wingem.c ../win/gem/wingem1.c ../win/gem/load_img.c \
+       ../win/gem/gr_rect.c tile.c
+WINGEMOBJ = wingem.o wingem1.o load_img.o gr_rect.o tile.o
+#
+# Files for a BeOS InterfaceKit port -- not ready for prime time
+WINBESRC =
+WINBEOBJ =
+#WINBESRC = ../win/BeOS/winbe.cpp ../win/BeOS/NHWindow.cpp \
+#      ../win/BeOS/NHMenuWindow.cpp ../win/BeOS/NHMapWindow.cpp tile.c
+#WINBEOBJ = winbe.o NHWindow.o NHMenuWindow.o NHMapWindow.o tile.o
+
+#
+#
+WINSRC = $(WINTTYSRC)
+WINOBJ = $(WINTTYOBJ)
+
+# on some systems the termcap library is in -ltermcap or -lcurses
+# on 386 Xenix, the -ltermlib tputs() seems not to work; use -lcurses instead
+# Sysatt uses shared library in lieu of this option
+# Systos needs -lcurses16 if you use -mshort
+# AIX 3.1 on RS/6000 likes -lcurses if TERMINFO defined in unixconf.h
+# and -ltermcap otherwise
+# Linux uses -lncurses (newer) or -ltermcap (older)
+# Be uses -ltermcap
+#
+# libraries for tty ports
+# WINTTYLIB = -ltermcap
+# WINTTYLIB = -lcurses
+# WINTTYLIB = -lcurses16
+# WINTTYLIB = -lncurses
+WINTTYLIB = -ltermlib
+#
+# libraries for X11
+# If USE_XPM is defined in config.h, you will also need -lXpm here.
+WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11
+# WINX11LIB = -lXaw -lXmu -lXt -lX11
+# WINX11LIB = -lXaw -lXmu -lXext -lXt -lXpm -lX11 -lm
+# WINX11LIB = -lXaw -lXmu -lXpm -lXext -lXt -lX11 -lSM -lICE -lm # BSD/OS 2.0
+#
+# libraries for Qt
+WINQTLIB = -L$(QTDIR)/lib -lqt
+#
+# libraries for KDE (with Qt)
+WINKDELIB = -lkdecore -lkdeui -lXext
+#
+# libraries for Gnome
+WINGNOMELIB = -lgnomeui -lgnome -lart_lgpl -lgtk -lgdk -lpopt
+#
+# libraries for Gem port
+WINGEMLIB = -le_gem -lgem
+#
+# libraries for BeOS 
+WINBELIB = -lbe
+
+WINLIB = $(WINTTYLIB)
+
+# any other strange libraries your system needs (for Sysunix only -- the more
+# specialized targets should already be right)
+#
+# on HP-UX 8.x, the malloc(3x) routines in libmalloc.a seem to align things
+# better than the malloc(3) ones in libc.a
+# LIBS = -lmalloc
+#
+# DPX/2's also use the malloc(3x) routines.  In addition, if you are building
+# for X11, you must include libinet.a.
+# LIBS = -lmalloc -linet
+#
+# Linux NetHack uses some bsd style ioctl functions, thus it is necessary to
+# use the bsd libs.  (Only if still compiling as BSD in unixconf.h; recent
+# versions compile fine using SYSV without this.)
+# LIBS = -lbsd
+#
+# for CYGWIN32 aka cygwin 1.1.1
+# LIBS = -lcygwin
+#
+# Solaris 2.x seems to work with the following
+# LIBS = -lsocket -lnsl
+#
+# IRIX 4.0.x needs -lsun if NIS (YP) is being used for passwd file lookup
+# LIBS = -lsun
+#
+LIBS =
+
+# make NetHack
+GAME     = nethack
+# GAME     = nethack.prg
+
+# if you defined RANDOM in unixconf.h/tosconf.h since your system did not come
+# with a reasonable random number generator
+# RANDOBJ = random.o
+RANDOBJ =
+
+
+# used by `make depend' to reconstruct this Makefile; you shouldn't need this
+AWK    = nawk
+
+# ----------------------------------------
+#
+# Nothing below this line should have to be changed.
+#
+# Other things that have to be reconfigured are in config.h,
+# {unixconf.h, pcconf.h, tosconf.h}, and possibly system.h
+
+MAKEDEFS = ../util/makedefs
+
+# timestamp files to reduce `make' overhead and shorten .o dependency lists
+CONFIG_H = ../src/config.h-t
+HACK_H = ../src/hack.h-t
+
+# all .c that are part of the main NetHack program and are not operating- or
+# windowing-system specific
+HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \
+          botl.c cmd.c dbridge.c decl.c detect.c dig.c display.c dlb.c do.c \
+          do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c drawing.c \
+          dungeon.c eat.c end.c engrave.c exper.c explode.c extralev.c \
+          files.c fountain.c hack.c hacklib.c invent.c light.c lock.c \
+          mail.c makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c minion.c \
+          mklev.c mkmap.c \
+          mkmaze.c mkobj.c mkroom.c mon.c mondata.c monmove.c monst.c \
+          mplayer.c mthrowu.c muse.c music.c o_init.c objects.c objnam.c \
+          options.c pager.c pickup.c pline.c polyself.c potion.c pray.c \
+          priest.c quest.c questpgr.c read.c rect.c region.c restore.c rip.c \
+          rnd.c role.c rumors.c save.c shk.c shknam.c sit.c sounds.c sp_lev.c \
+          spell.c steal.c steed.c teleport.c timeout.c topten.c track.c trap.c \
+          u_init.c uhitm.c vault.c version.c vision.c weapon.c were.c wield.c \
+          windows.c wizard.c worm.c worn.c write.c zap.c
+
+# all operating-system-dependent .c (for dependencies and such)
+SYSCSRC = ../sys/atari/tos.c ../sys/share/pcmain.c ../sys/share/pcsys.c \
+       ../sys/share/pctty.c ../sys/share/pcunix.c ../sys/share/random.c \
+       ../sys/share/ioctl.c ../sys/share/unixtty.c ../sys/unix/unixmain.c \
+       ../sys/unix/unixunix.c ../sys/unix/unixres.c ../sys/be/bemain.c
+
+# generated source files (tile.c is handled separately via WINxxxSRC)
+GENCSRC = monstr.c vis_tab.c   #tile.c
+
+# all windowing-system-dependent .c (for dependencies and such)
+WINCSRC = $(WINTTYSRC) $(WINX11SRC) $(WINGNOMESRC) $(WINGEMSRC)
+# all windowing-system-dependent .cpp (for dependencies and such)
+WINCXXSRC = $(WINQTSRC) $(WINBESRC)
+
+# .c files for this version (for date.h)
+VERSOURCES = $(HACKCSRC) $(SYSSRC) $(WINSRC) $(GENCSRC)
+
+# .c files for all versions using this Makefile (for lint and tags)
+CSOURCES = $(HACKCSRC) $(SYSSRC) $(WINCSRC) $(GENCSRC)
+
+
+# all .h files except date.h, onames.h, pm.h, and vis_tab.h which would
+# cause dependency loops if run through "make depend"
+# and dgn_comp.h, dgn_file.h, lev_comp.h, special level & dungeon files.
+#
+HACKINCL = align.h amiconf.h artifact.h artilist.h attrib.h beconf.h color.h \
+       config.h config1.h coord.h decl.h def_os2.h display.h dlb.h dungeon.h \
+       edog.h emin.h engrave.h epri.h eshk.h extern.h flag.h func_tab.h \
+       global.h hack.h lev.h macconf.h mfndpos.h micro.h mkroom.h \
+       monattk.h mondata.h monflag.h monst.h monsym.h obj.h objclass.h \
+       os2conf.h patchlevel.h pcconf.h permonst.h prop.h rect.h region.h rm.h \
+       sp_lev.h spell.h system.h tcap.h timeout.h tosconf.h tradstdc.h \
+       trampoli.h trap.h unixconf.h vault.h vision.h vmsconf.h wintty.h \
+       winX.h winprocs.h wintype.h you.h youprop.h
+
+HSOURCES = $(HACKINCL) date.h onames.h pm.h vis_tab.h\
+               lev_comp.h dgn_comp.h dgn_file.h
+
+# the following .o's _must_ be made before any others (for makedefs)
+FIRSTOBJ = monst.o objects.o
+
+HOBJ = $(FIRSTOBJ) allmain.o alloc.o apply.o artifact.o attrib.o ball.o \
+       bones.o botl.o cmd.o dbridge.o decl.o detect.o dig.o display.o dlb.o \
+       do.o do_name.o do_wear.o dog.o dogmove.o dokick.o dothrow.o \
+       drawing.o dungeon.o eat.o end.o engrave.o exper.o explode.o \
+       extralev.o files.o fountain.o hack.o hacklib.o invent.o light.o \
+       lock.o mail.o makemon.o mapglyph.o mcastu.o mhitm.o mhitu.o \
+       minion.o mklev.o mkmap.o \
+       mkmaze.o mkobj.o mkroom.o mon.o mondata.o monmove.o monstr.o \
+       mplayer.o mthrowu.o muse.o music.o o_init.o objnam.o options.o \
+       pager.o pickup.o pline.o polyself.o potion.o pray.o priest.o \
+       quest.o questpgr.o read.o rect.o region.o restore.o rip.o rnd.o \
+       role.o rumors.o save.o shk.o shknam.o sit.o sounds.o sp_lev.o spell.o \
+       steal.o steed.o teleport.o timeout.o topten.o track.o trap.o u_init.o \
+       uhitm.o vault.o vision.o vis_tab.o weapon.o were.o wield.o windows.o \
+       wizard.o worm.o worn.o write.o zap.o \
+       $(RANDOBJ) $(SYSOBJ) $(WINOBJ) version.o
+# the .o files from the HACKCSRC, SYSSRC, and WINSRC lists
+
+$(GAME):       $(SYSTEM)
+       @echo "$(GAME) is up to date."
+
+Sysunix:       $(HOBJ) Makefile
+       @echo "Loading ..."
+       $(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS)
+       @touch Sysunix
+
+Sys3B2:        $(HOBJ) Makefile
+       @echo "Loading ..."
+       @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) -lmalloc
+       @touch Sys3B2
+
+Sysatt:        $(HOBJ) Makefile
+       @echo "Loading ..."
+       @$(LD) $(LFLAGS) /lib/crt0s.o /lib/shlib.ifile -o $(GAME) $(HOBJ)
+       @touch Sysatt
+
+Systos:        $(HOBJ) Makefile
+       @echo "Loading ..."
+       @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB)
+       @touch Systos
+
+SysV-AT:       DUMB.Setup $(HOBJ) Makefile
+       @echo "Loading ..."
+       @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB)
+       @touch SysV-AT
+
+SysBe: $(HOBJ) Makefile
+       @echo "Loading ..."
+       @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS)
+       @xres -o $(GAME) ../win/BeOS/nethack.rsrc
+       @mimeset -f $(GAME)
+       @touch SysBe
+
+DUMB.Setup:    ../include/extern.h
+       cp ../include/extern.h ../include/extern.h.BAK
+       cat ../include/extern.h | \
+               sed -e '/^E\ int\ /!b' \
+                       -e '/[^;/       ]$$/N' \
+                       -e '/[(][*]occupation[)]/b' \
+                       -e '/[(][*]afternmv[)]/b' \
+                       -e '/float_down/b' \
+                       -e '/done1/b' \
+                       -e '/identify/b' \
+                       -e '/Hear_again/b' \
+                       -e '/hangup/b' \
+                       -e 's/^\(.*\)$$/\/\* \1 \/\*\*\//' | \
+               sed -e '/^E\ void\ /!b' \
+                       -e '/[^;/       ]$$/N' \
+                       -e 's/^\(.*\)$$/\/\* \1 \/\*\*\//' \
+                               >../include/extern.DUMB
+       cp ../include/extern.DUMB ../include/extern.h
+       @touch DUMB.Setup
+
+all:   $(GAME)
+
+
+#      dependencies for makedefs and its outputs, which the util
+#      Makefile is responsible for keeping up to date
+#
+
+# special rules, to force update of makedefs, real dependencies should be
+# below in the 'make depend' output.
+monst.o:
+       $(CC) $(CFLAGS) -c monst.c
+       @rm -f $(MAKEDEFS)
+
+objects.o:
+       $(CC) $(CFLAGS) -c objects.c
+       @rm -f $(MAKEDEFS)
+
+# Qt windowport meta-object-compiler output
+qt_kde0.moc: ../include/qt_kde0.h
+       $(QTDIR)/bin/moc -o qt_kde0.moc ../include/qt_kde0.h
+
+qt_win.moc: ../include/qt_win.h
+       $(QTDIR)/bin/moc -o qt_win.moc ../include/qt_win.h
+
+qttableview.moc: ../include/qttableview.h
+       $(QTDIR)/bin/moc -o qttableview.moc ../include/qttableview.h
+
+$(MAKEDEFS): ../util/makedefs.c  $(CONFIG_H) ../include/permonst.h \
+               ../include/objclass.h ../include/monsym.h \
+               ../include/artilist.h ../include/dungeon.h ../include/obj.h \
+               ../include/monst.h ../include/you.h ../include/flag.h \
+               ../include/dlb.h ../include/patchlevel.h ../include/qtext.h
+       @( cd ../util ; $(MAKE) makedefs)
+
+../include/onames.h: $(MAKEDEFS)
+       @( cd ../util ; $(MAKE) ../include/onames.h )
+../include/pm.h: $(MAKEDEFS)
+       @( cd ../util ; $(MAKE) ../include/pm.h )
+monstr.c: $(MAKEDEFS)
+       @( cd ../util ; $(MAKE) ../src/monstr.c )
+../include/vis_tab.h: $(MAKEDEFS)
+       @( cd ../util ; $(MAKE) ../include/vis_tab.h )
+# makedefs -z makes both vis_tab.h and vis_tab.c, but writes the .h first
+vis_tab.c: ../include/vis_tab.h
+tile.c: ../win/share/tilemap.c $(HACK_H)
+       @( cd ../util ; $(MAKE) ../src/tile.c )
+
+../win/gnome/gn_rip.h: ../win/X11/rip.xpm
+       cp ../win/X11/rip.xpm ../win/gnome/gn_rip.h
+
+#      date.h should be remade any time any of the source or include code
+#      is modified.  Unfortunately, this would make the contents of this
+#      file far more complex.  Since "hack.h" depends on most of the include
+#      files, we kludge around this by making date.h dependent on hack.h,
+#      even though it doesn't include this file.
+#
+#      hack.h depends on makedefs' output, so we know makedefs will be
+#      up to date before being executed
+../include/date.h:     $(VERSOURCES) $(HACK_H)
+       ../util/makedefs -v
+
+
+lint:
+# lint cannot have -p here because (i) capitals are meaningful:
+# [Ww]izard, (ii) identifiers may coincide in the first six places:
+# doweararm() versus dowearring().
+# _flsbuf comes from <stdio.h>, a bug in the system libraries.
+       @echo lint -axbh -DLINT ...
+       @lint -axbh -I../include -DLINT $(CSOURCES) | sed '/_flsbuf/d'
+
+
+tags: $(CSOURCES)
+       @echo ctags -tw ...
+       @ctags -tw $(CSOURCES)
+       @( cd ../include ; ctags -tw $(HSOURCES) )
+       @( cd ../util ; $(MAKE) tags )
+
+clean:
+       -rm -f *.o $(HACK_H) $(CONFIG_H)
+
+spotless: clean
+       -rm -f a.out core $(GAME) Sys*
+       -rm -f ../include/date.h ../include/onames.h ../include/pm.h
+       -rm -f monstr.c ../include/vis_tab.h vis_tab.c tile.c *.moc
+       -rm -f ../win/gnome/gn_rip.h
+
+
+depend: ../sys/unix/depend.awk \
+               $(SYSCSRC) $(WINCSRC) $(WINCXXSRC) $(GENCSRC) $(HACKCSRC)
+       $(AWK) -f ../sys/unix/depend.awk ../include/*.h \
+               $(SYSCSRC) $(WINCSRC) $(WINCXXSRC) $(GENCSRC) $(HACKCSRC) >makedep
+       @echo '/^# DO NOT DELETE THIS LINE OR CHANGE ANYTHING BEYOND IT/+2,$$d' >eddep
+       @echo '$$r makedep' >>eddep
+       @echo 'w' >>eddep
+       @cp Makefile Makefile.bak
+       ed - Makefile < eddep
+       @rm -f eddep makedep
+       @echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile
+       @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
+       @echo '# see make depend above' >> Makefile
+       - diff Makefile.bak Makefile
+       @rm -f Makefile.bak
+
+# DO NOT DELETE THIS LINE OR CHANGE ANYTHING BEYOND IT
+
+# config.h timestamp
+$(CONFIG_H): ../include/config.h ../include/config1.h ../include/tradstdc.h \
+               ../include/global.h ../include/coord.h ../include/vmsconf.h \
+               ../include/system.h ../include/unixconf.h ../include/os2conf.h \
+               ../include/micro.h ../include/pcconf.h ../include/tosconf.h \
+               ../include/amiconf.h ../include/macconf.h ../include/beconf.h \
+               ../include/wceconf.h ../include/ntconf.h ../include/nhlan.h
+       touch $(CONFIG_H)
+# hack.h timestamp
+$(HACK_H): ../include/hack.h $(CONFIG_H) ../include/align.h \
+               ../include/dungeon.h ../include/monsym.h ../include/mkroom.h \
+               ../include/objclass.h ../include/youprop.h ../include/prop.h \
+               ../include/permonst.h ../include/monattk.h \
+               ../include/monflag.h ../include/mondata.h ../include/pm.h \
+               ../include/wintype.h ../include/decl.h ../include/quest.h \
+               ../include/spell.h ../include/color.h ../include/obj.h \
+               ../include/you.h ../include/attrib.h ../include/monst.h \
+               ../include/skills.h ../include/onames.h ../include/timeout.h \
+               ../include/trap.h ../include/flag.h ../include/rm.h \
+               ../include/vision.h ../include/display.h ../include/engrave.h \
+               ../include/rect.h ../include/region.h ../include/winprocs.h \
+               ../include/wintty.h ../include/trampoli.h
+       touch $(HACK_H)
+#
+tos.o: ../sys/atari/tos.c $(HACK_H) ../include/tcap.h
+       $(CC) $(CFLAGS) -c ../sys/atari/tos.c
+pcmain.o: ../sys/share/pcmain.c $(HACK_H) ../include/dlb.h \
+               #../include/win32api.h
+       $(CC) $(CFLAGS) -c ../sys/share/pcmain.c
+pcsys.o: ../sys/share/pcsys.c $(HACK_H)
+       $(CC) $(CFLAGS) -c ../sys/share/pcsys.c
+pctty.o: ../sys/share/pctty.c $(HACK_H)
+       $(CC) $(CFLAGS) -c ../sys/share/pctty.c
+pcunix.o: ../sys/share/pcunix.c $(HACK_H)
+       $(CC) $(CFLAGS) -c ../sys/share/pcunix.c
+random.o: ../sys/share/random.c $(HACK_H)
+       $(CC) $(CFLAGS) -c ../sys/share/random.c
+ioctl.o: ../sys/share/ioctl.c $(HACK_H) ../include/tcap.h
+       $(CC) $(CFLAGS) -c ../sys/share/ioctl.c
+unixtty.o: ../sys/share/unixtty.c $(HACK_H)
+       $(CC) $(CFLAGS) -c ../sys/share/unixtty.c
+unixmain.o: ../sys/unix/unixmain.c $(HACK_H) ../include/dlb.h
+       $(CC) $(CFLAGS) -c ../sys/unix/unixmain.c
+unixunix.o: ../sys/unix/unixunix.c $(HACK_H)
+       $(CC) $(CFLAGS) -c ../sys/unix/unixunix.c
+unixres.o: ../sys/unix/unixres.c $(CONFIG_H)
+       $(CC) $(CFLAGS) -c ../sys/unix/unixres.c
+bemain.o: ../sys/be/bemain.c $(HACK_H) ../include/dlb.h
+       $(CC) $(CFLAGS) -c ../sys/be/bemain.c
+getline.o: ../win/tty/getline.c $(HACK_H) ../include/func_tab.h
+       $(CC) $(CFLAGS) -c ../win/tty/getline.c
+termcap.o: ../win/tty/termcap.c $(HACK_H) ../include/tcap.h
+       $(CC) $(CFLAGS) -c ../win/tty/termcap.c
+topl.o: ../win/tty/topl.c $(HACK_H) ../include/tcap.h
+       $(CC) $(CFLAGS) -c ../win/tty/topl.c
+wintty.o: ../win/tty/wintty.c $(HACK_H) ../include/dlb.h \
+               ../include/patchlevel.h ../include/tcap.h
+       $(CC) $(CFLAGS) -c ../win/tty/wintty.c
+Window.o: ../win/X11/Window.c ../include/xwindowp.h ../include/xwindow.h \
+               $(CONFIG_H)
+       $(CC) $(CFLAGS) -c ../win/X11/Window.c
+dialogs.o: ../win/X11/dialogs.c $(CONFIG_H)
+       $(CC) $(CFLAGS) -c ../win/X11/dialogs.c
+winX.o: ../win/X11/winX.c $(HACK_H) ../include/winX.h ../include/dlb.h \
+               ../include/patchlevel.h ../win/X11/nh72icon \
+               ../win/X11/nh56icon ../win/X11/nh32icon
+       $(CC) $(CFLAGS) -c ../win/X11/winX.c
+winmap.o: ../win/X11/winmap.c ../include/xwindow.h $(HACK_H) ../include/dlb.h \
+               ../include/winX.h ../include/tile2x11.h
+       $(CC) $(CFLAGS) -c ../win/X11/winmap.c
+winmenu.o: ../win/X11/winmenu.c $(HACK_H) ../include/winX.h
+       $(CC) $(CFLAGS) -c ../win/X11/winmenu.c
+winmesg.o: ../win/X11/winmesg.c ../include/xwindow.h $(HACK_H) ../include/winX.h
+       $(CC) $(CFLAGS) -c ../win/X11/winmesg.c
+winmisc.o: ../win/X11/winmisc.c $(HACK_H) ../include/func_tab.h \
+               ../include/winX.h
+       $(CC) $(CFLAGS) -c ../win/X11/winmisc.c
+winstat.o: ../win/X11/winstat.c $(HACK_H) ../include/winX.h
+       $(CC) $(CFLAGS) -c ../win/X11/winstat.c
+wintext.o: ../win/X11/wintext.c $(HACK_H) ../include/winX.h ../include/xwindow.h
+       $(CC) $(CFLAGS) -c ../win/X11/wintext.c
+winval.o: ../win/X11/winval.c $(HACK_H) ../include/winX.h
+       $(CC) $(CFLAGS) -c ../win/X11/winval.c
+tile.o: tile.c $(HACK_H)
+gnaskstr.o: ../win/gnome/gnaskstr.c ../win/gnome/gnaskstr.h \
+               ../win/gnome/gnmain.h
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnaskstr.c
+gnbind.o: ../win/gnome/gnbind.c ../win/gnome/gnbind.h ../win/gnome/gnmain.h \
+               ../win/gnome/gnmenu.h ../win/gnome/gnaskstr.h \
+               ../win/gnome/gnyesno.h
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnbind.c
+gnglyph.o: ../win/gnome/gnglyph.c ../win/gnome/gnglyph.h ../include/tile2x11.h
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnglyph.c
+gnmain.o: ../win/gnome/gnmain.c ../win/gnome/gnmain.h ../win/gnome/gnsignal.h \
+               ../win/gnome/gnbind.h ../win/gnome/gnopts.h $(HACK_H) \
+               ../include/date.h
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnmain.c
+gnmap.o: ../win/gnome/gnmap.c ../win/gnome/gnmap.h ../win/gnome/gnglyph.h \
+               ../win/gnome/gnsignal.h $(HACK_H)
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnmap.c
+gnmenu.o: ../win/gnome/gnmenu.c ../win/gnome/gnmenu.h ../win/gnome/gnmain.h \
+               ../win/gnome/gnbind.h ../include/func_tab.h
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnmenu.c
+gnmesg.o: ../win/gnome/gnmesg.c ../win/gnome/gnmesg.h ../win/gnome/gnsignal.h
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnmesg.c
+gnopts.o: ../win/gnome/gnopts.c ../win/gnome/gnopts.h ../win/gnome/gnglyph.h \
+               ../win/gnome/gnmain.h ../win/gnome/gnmap.h $(HACK_H)
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnopts.c
+gnplayer.o: ../win/gnome/gnplayer.c ../win/gnome/gnplayer.h \
+               ../win/gnome/gnmain.h $(HACK_H)
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnplayer.c
+gnsignal.o: ../win/gnome/gnsignal.c ../win/gnome/gnsignal.h \
+               ../win/gnome/gnmain.h
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnsignal.c
+gnstatus.o: ../win/gnome/gnstatus.c ../win/gnome/gnstatus.h \
+               ../win/gnome/gnsignal.h ../win/gnome/gn_xpms.h \
+               ../win/gnome/gnomeprv.h
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnstatus.c
+gntext.o: ../win/gnome/gntext.c ../win/gnome/gntext.h ../win/gnome/gnmain.h \
+               ../win/gnome/gn_rip.h
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gntext.c
+gnyesno.o: ../win/gnome/gnyesno.c ../win/gnome/gnbind.h ../win/gnome/gnyesno.h
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnyesno.c
+gnworn.o: ../win/gnome/gnworn.c ../win/gnome/gnworn.h ../win/gnome/gnglyph.h \
+               ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h
+       $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnworn.c
+wingem.o: ../win/gem/wingem.c $(HACK_H) ../include/func_tab.h ../include/dlb.h \
+               ../include/patchlevel.h ../include/wingem.h
+       $(CC) $(CFLAGS) -c ../win/gem/wingem.c
+wingem1.o: ../win/gem/wingem1.c ../include/gem_rsc.h ../include/load_img.h \
+               ../include/gr_rect.h ../include/wintype.h ../include/wingem.h
+       $(CC) $(CFLAGS) -c ../win/gem/wingem1.c
+load_img.o: ../win/gem/load_img.c ../include/load_img.h
+       $(CC) $(CFLAGS) -c ../win/gem/load_img.c
+gr_rect.o: ../win/gem/gr_rect.c ../include/gr_rect.h
+       $(CC) $(CFLAGS) -c ../win/gem/gr_rect.c
+tile.o: tile.c $(HACK_H)
+qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) ../include/func_tab.h \
+               ../include/dlb.h ../include/patchlevel.h ../include/tile2x11.h \
+               ../include/qt_win.h ../include/qt_clust.h ../include/qt_kde0.h \
+               ../include/qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc
+       $(CXX) $(CXXFLAGS) -c ../win/Qt/qt_win.cpp
+qt_clust.o: ../win/Qt/qt_clust.cpp ../include/qt_clust.h
+       $(CXX) $(CXXFLAGS) -c ../win/Qt/qt_clust.cpp
+qttableview.o: ../win/Qt/qttableview.cpp ../include/qttableview.h
+       $(CXX) $(CXXFLAGS) -c ../win/Qt/qttableview.cpp
+monstr.o: monstr.c $(CONFIG_H)
+vis_tab.o: vis_tab.c $(CONFIG_H) ../include/vis_tab.h
+allmain.o: allmain.c $(HACK_H)
+alloc.o: alloc.c $(CONFIG_H)
+apply.o: apply.c $(HACK_H) ../include/edog.h
+artifact.o: artifact.c $(HACK_H) ../include/artifact.h ../include/artilist.h
+attrib.o: attrib.c $(HACK_H)
+ball.o: ball.c $(HACK_H)
+bones.o: bones.c $(HACK_H) ../include/lev.h
+botl.o: botl.c $(HACK_H)
+cmd.o: cmd.c $(HACK_H) ../include/func_tab.h
+dbridge.o: dbridge.c $(HACK_H)
+decl.o: decl.c $(HACK_H)
+detect.o: detect.c $(HACK_H) ../include/artifact.h
+dig.o: dig.c $(HACK_H) ../include/edog.h
+display.o: display.c $(HACK_H)
+dlb.o: dlb.c $(CONFIG_H) ../include/dlb.h
+do.o: do.c $(HACK_H) ../include/lev.h
+do_name.o: do_name.c $(HACK_H)
+do_wear.o: do_wear.c $(HACK_H)
+dog.o: dog.c $(HACK_H) ../include/edog.h
+dogmove.o: dogmove.c $(HACK_H) ../include/mfndpos.h ../include/edog.h
+dokick.o: dokick.c $(HACK_H) ../include/eshk.h
+dothrow.o: dothrow.c $(HACK_H) ../include/edog.h
+drawing.o: drawing.c $(HACK_H) ../include/tcap.h
+dungeon.o: dungeon.c $(HACK_H) ../include/dgn_file.h ../include/dlb.h
+eat.o: eat.c $(HACK_H)
+end.o: end.c $(HACK_H) ../include/eshk.h ../include/dlb.h
+engrave.o: engrave.c $(HACK_H) ../include/lev.h
+exper.o: exper.c $(HACK_H)
+explode.o: explode.c $(HACK_H)
+extralev.o: extralev.c $(HACK_H)
+files.o: files.c $(HACK_H) ../include/dlb.h
+fountain.o: fountain.c $(HACK_H)
+hack.o: hack.c $(HACK_H)
+hacklib.o: hacklib.c $(HACK_H)
+invent.o: invent.c $(HACK_H)
+light.o: light.c $(HACK_H) ../include/lev.h
+lock.o: lock.c $(HACK_H)
+mail.o: mail.c $(HACK_H) ../include/mail.h
+makemon.o: makemon.c $(HACK_H) ../include/epri.h ../include/emin.h \
+               ../include/edog.h
+mapglyph.o: mapglyph.c $(HACK_H)
+mcastu.o: mcastu.c $(HACK_H)
+mhitm.o: mhitm.c $(HACK_H) ../include/artifact.h ../include/edog.h
+mhitu.o: mhitu.c $(HACK_H) ../include/artifact.h ../include/edog.h
+minion.o: minion.c $(HACK_H) ../include/emin.h ../include/epri.h
+mklev.o: mklev.c $(HACK_H)
+mkmap.o: mkmap.c $(HACK_H) ../include/sp_lev.h
+mkmaze.o: mkmaze.c $(HACK_H) ../include/sp_lev.h ../include/lev.h
+mkobj.o: mkobj.c $(HACK_H)
+mkroom.o: mkroom.c $(HACK_H)
+mon.o: mon.c $(HACK_H) ../include/mfndpos.h ../include/edog.h
+mondata.o: mondata.c $(HACK_H) ../include/eshk.h ../include/epri.h
+monmove.o: monmove.c $(HACK_H) ../include/mfndpos.h ../include/artifact.h \
+               ../include/epri.h
+monst.o: monst.c $(CONFIG_H) ../include/permonst.h ../include/align.h \
+               ../include/monattk.h ../include/monflag.h ../include/monsym.h \
+               ../include/dungeon.h ../include/eshk.h ../include/vault.h \
+               ../include/epri.h ../include/color.h
+mplayer.o: mplayer.c $(HACK_H)
+mthrowu.o: mthrowu.c $(HACK_H)
+muse.o: muse.c $(HACK_H) ../include/edog.h
+music.o: music.c $(HACK_H) #interp.c
+o_init.o: o_init.c $(HACK_H) ../include/lev.h
+objects.o: objects.c $(CONFIG_H) ../include/obj.h ../include/objclass.h \
+               ../include/prop.h ../include/skills.h ../include/color.h
+objnam.o: objnam.c $(HACK_H)
+options.o: options.c $(CONFIG_H) ../include/objclass.h ../include/flag.h \
+               $(HACK_H) ../include/tcap.h
+pager.o: pager.c $(HACK_H) ../include/dlb.h
+pickup.o: pickup.c $(HACK_H)
+pline.o: pline.c $(HACK_H) ../include/epri.h ../include/edog.h
+polyself.o: polyself.c $(HACK_H)
+potion.o: potion.c $(HACK_H)
+pray.o: pray.c $(HACK_H) ../include/epri.h
+priest.o: priest.c $(HACK_H) ../include/mfndpos.h ../include/eshk.h \
+               ../include/epri.h ../include/emin.h
+quest.o: quest.c $(HACK_H) ../include/qtext.h
+questpgr.o: questpgr.c $(HACK_H) ../include/dlb.h ../include/qtext.h
+read.o: read.c $(HACK_H)
+rect.o: rect.c $(HACK_H)
+region.o: region.c $(HACK_H) ../include/lev.h
+restore.o: restore.c $(HACK_H) ../include/lev.h ../include/tcap.h
+rip.o: rip.c $(HACK_H)
+rnd.o: rnd.c $(HACK_H)
+role.o: role.c $(HACK_H)
+rumors.o: rumors.c $(HACK_H) ../include/lev.h ../include/dlb.h
+save.o: save.c $(HACK_H) ../include/lev.h
+shk.o: shk.c $(HACK_H) ../include/eshk.h
+shknam.o: shknam.c $(HACK_H) ../include/eshk.h
+sit.o: sit.c $(HACK_H) ../include/artifact.h
+sounds.o: sounds.c $(HACK_H) ../include/edog.h
+sp_lev.o: sp_lev.c $(HACK_H) ../include/dlb.h ../include/sp_lev.h
+spell.o: spell.c $(HACK_H)
+steal.o: steal.c $(HACK_H)
+steed.o: steed.c $(HACK_H)
+teleport.o: teleport.c $(HACK_H)
+timeout.o: timeout.c $(HACK_H) ../include/lev.h
+topten.o: topten.c $(HACK_H) ../include/dlb.h ../include/patchlevel.h
+track.o: track.c $(HACK_H)
+trap.o: trap.c $(HACK_H)
+u_init.o: u_init.c $(HACK_H)
+uhitm.o: uhitm.c $(HACK_H)
+vault.o: vault.c $(HACK_H) ../include/vault.h
+version.o: version.c $(HACK_H) ../include/date.h ../include/patchlevel.h
+vision.o: vision.c $(HACK_H) ../include/vis_tab.h
+weapon.o: weapon.c $(HACK_H)
+were.o: were.c $(HACK_H)
+wield.o: wield.c $(HACK_H)
+windows.o: windows.c $(HACK_H) ../include/wingem.h ../include/winGnome.h
+wizard.o: wizard.c $(HACK_H) ../include/qtext.h ../include/epri.h
+worm.o: worm.c $(HACK_H) ../include/lev.h
+worn.o: worn.c $(HACK_H)
+write.o: write.c $(HACK_H)
+zap.o: zap.c $(HACK_H)
+# DEPENDENCIES MUST END AT END OF FILE
+# IF YOU PUT STUFF HERE IT WILL GO AWAY
+# see make depend above
diff --git a/sys/unix/Makefile.top b/sys/unix/Makefile.top
new file mode 100644 (file)
index 0000000..2f11c35
--- /dev/null
@@ -0,0 +1,266 @@
+#      NetHack Makefile.
+#      SCCS Id: @(#)Makefile.top       3.4     1995/01/05
+
+# newer makes predefine $(MAKE) to 'make' and do smarter processing of
+# recursive make calls if $(MAKE) is used
+# these makes allow $(MAKE) to be overridden by the environment if someone
+# wants to (or has to) use something other than the standard make, so we do
+# not want to unconditionally set $(MAKE) here
+#
+# unfortunately, some older makes do not predefine $(MAKE); if you have one of
+# these, uncomment the following line
+# (you will know that you have one if you get complaints about unable to
+# execute things like 'data' and 'rumors')
+# MAKE = make
+
+# make NetHack
+PREFIX  = /usr
+GAME     = nethack
+# GAME     = nethack.prg
+GAMEUID  = games
+GAMEGRP  = bin
+
+# Permissions - some places use setgid instead of setuid, for instance
+# See also the option "SECURE" in include/config.h
+GAMEPERM = 04755
+FILEPERM = 0644
+EXEPERM  = 0755
+DIRPERM  = 0755
+
+# GAMEDIR also appears in config.h as "HACKDIR".
+# VARDIR may also appear in unixconf.h as "VAR_PLAYGROUND" else GAMEDIR
+#
+# note that 'make install' believes in creating a nice tidy GAMEDIR for
+# installation, free of debris from previous NetHack versions --
+# therefore there should not be anything in GAMEDIR that you want to keep
+# (if there is, you'll have to do the installation by hand or modify the
+# instructions)
+GAMEDIR  = $(PREFIX)/games/lib/$(GAME)dir
+VARDIR  = $(GAMEDIR)
+SHELLDIR = $(PREFIX)/games
+
+# per discussion in Install.X11 and Install.Qt
+VARDATND = 
+# VARDATND = x11tiles NetHack.ad pet_mark.xbm
+# VARDATND = x11tiles NetHack.ad pet_mark.xbm rip.xpm
+# for Atari/Gem
+# VARDATND = nh16.img title.img GEM_RSC.RSC rip.img
+# for BeOS
+# VARDATND = beostiles
+# for Gnome
+# VARDATND = x11tiles pet_mark.xbm rip.xpm mapbg.xpm
+
+VARDATD = data oracles options quest.dat rumors
+VARDAT = $(VARDATD) $(VARDATND)
+
+# Some versions of make use the SHELL environment variable as the shell
+# for running commands.  We need this to be a Bourne shell.
+# SHELL = /bin/sh
+# for Atari
+# SHELL=E:/GEMINI2/MUPFEL.TTP
+
+# Commands for setting the owner and group on files during installation.
+# Some systems fail with one or the other when installing over NFS or for
+# other permission-related reasons.  If that happens, you may want to set the
+# command to "true", which is a no-op. Note that disabling chown or chgrp
+# will only work if setuid (or setgid) behavior is not desired or required.
+CHOWN = chown
+CHGRP = chgrp
+
+#
+# end of configuration
+#
+
+DATHELP = help hh cmdhelp history opthelp wizhelp
+
+SPEC_LEVS = asmodeus.lev baalz.lev bigrm-?.lev castle.lev fakewiz?.lev \
+       juiblex.lev knox.lev medusa-?.lev minend-?.lev minefill.lev \
+       minetn-?.lev oracle.lev orcus.lev sanctum.lev soko?-?.lev \
+       tower?.lev valley.lev wizard?.lev \
+       astral.lev air.lev earth.lev fire.lev water.lev
+QUEST_LEVS = ???-goal.lev ???-fil?.lev ???-loca.lev ???-strt.lev
+
+DATNODLB = $(VARDATND) license
+DATDLB = $(DATHELP) dungeon $(SPEC_LEVS) $(QUEST_LEVS) $(VARDATD)
+DAT = $(DATNODLB) $(DATDLB)
+
+$(GAME):
+       ( cd src ; $(MAKE) )
+
+all:   $(GAME) recover Guidebook $(VARDAT) dungeon spec_levs check-dlb
+       @echo "Done."
+
+# Note: many of the dependencies below are here to allow parallel make
+# to generate valid output
+
+Guidebook:
+       ( cd doc ; $(MAKE) Guidebook )
+
+manpages:
+       ( cd doc ; $(MAKE) manpages )
+
+data: $(GAME)
+       ( cd dat ; $(MAKE) data )
+
+rumors: $(GAME)
+       ( cd dat ; $(MAKE) rumors )
+
+oracles: $(GAME)
+       ( cd dat ; $(MAKE) oracles )
+
+#      Note: options should have already been made with make, but...
+options: $(GAME)
+       ( cd dat ; $(MAKE) options )
+
+quest.dat: $(GAME)
+       ( cd dat ; $(MAKE) quest.dat )
+
+spec_levs: dungeon
+       ( cd util ; $(MAKE) lev_comp )
+       ( cd dat ; $(MAKE) spec_levs )
+       ( cd dat ; $(MAKE) quest_levs )
+
+dungeon: $(GAME)
+       ( cd util ; $(MAKE) dgn_comp )
+       ( cd dat ; $(MAKE) dungeon )
+
+nhtiles.bmp: $(GAME)
+       ( cd dat ; $(MAKE) nhtiles.bmp )
+
+x11tiles: $(GAME)
+       ( cd util ; $(MAKE) tile2x11 )
+       ( cd dat ; $(MAKE) x11tiles )
+
+beostiles: $(GAME)
+       ( cd util ; $(MAKE) tile2beos )
+       ( cd dat ; $(MAKE) beostiles )
+
+NetHack.ad: $(GAME)
+       ( cd dat ; $(MAKE) NetHack.ad )
+
+pet_mark.xbm:
+       ( cd dat ; $(MAKE) pet_mark.xbm )
+
+rip.xpm:
+       ( cd dat ; $(MAKE) rip.xpm )
+
+mapbg.xpm:
+       (cd dat ; $(MAKE) mapbg.xpm )
+
+nhsplash.xpm:
+       ( cd dat ; $(MAKE) nhsplash.xpm )
+
+nh16.img: $(GAME)
+       ( cd util ; $(MAKE) tile2img.ttp )
+       ( cd dat ; $(MAKE) nh16.img )
+
+rip.img:
+       ( cd util ; $(MAKE) xpm2img.ttp )
+       ( cd dat ; $(MAKE) rip.img )
+GEM_RSC.RSC:
+       ( cd dat ; $(MAKE) GEM_RSC.RSC )
+
+title.img:
+       ( cd dat ; $(MAKE) title.img )
+
+check-dlb: options
+       @if egrep -s librarian dat/options ; then $(MAKE) dlb ; else true ; fi
+
+dlb:
+       ( cd util ; $(MAKE) dlb )
+       ( cd dat ; ../util/dlb cf nhdat $(DATDLB) )
+
+# recover can be used when INSURANCE is defined in include/config.h
+# and the checkpoint option is true
+recover: $(GAME)
+       ( cd util ; $(MAKE) recover )
+
+dofiles:
+       target=`sed -n                                  \
+               -e '/librarian/{'                       \
+               -e      's/.*/dlb/p'                    \
+               -e      'q'                             \
+               -e '}'                                  \
+               -e '$$s/.*/nodlb/p' < dat/options` ;    \
+       $(MAKE) dofiles-$${target-nodlb}
+       cp src/$(GAME) $(GAMEDIR)
+       cp util/recover $(GAMEDIR)
+       -rm -f $(SHELLDIR)/$(GAME)
+       sed -e 's;/usr/games/lib/nethackdir;$(GAMEDIR);' \
+               -e 's;HACKDIR/nethack;HACKDIR/$(GAME);' \
+               < sys/unix/nethack.sh \
+               > $(SHELLDIR)/$(GAME)
+# set up their permissions
+       -( cd $(GAMEDIR) ; $(CHOWN) $(GAMEUID) $(GAME) recover ; \
+                       $(CHGRP) $(GAMEGRP) $(GAME) recover )
+       chmod $(GAMEPERM) $(GAMEDIR)/$(GAME)
+       chmod $(EXEPERM) $(GAMEDIR)/recover
+       -$(CHOWN) $(GAMEUID) $(SHELLDIR)/$(GAME)
+       $(CHGRP) $(GAMEGRP) $(SHELLDIR)/$(GAME)
+       chmod $(EXEPERM) $(SHELLDIR)/$(GAME)
+
+dofiles-dlb: check-dlb
+       ( cd dat ; cp nhdat $(DATNODLB) $(GAMEDIR) )
+# set up their permissions
+       -( cd $(GAMEDIR) ; $(CHOWN) $(GAMEUID) nhdat $(DATNODLB) ; \
+                       $(CHGRP) $(GAMEGRP) nhdat $(DATNODLB) ; \
+                       chmod $(FILEPERM) nhdat $(DATNODLB) )
+
+dofiles-nodlb:
+# copy over the game files
+       ( cd dat ; cp $(DAT) $(GAMEDIR) )
+# set up their permissions
+       -( cd $(GAMEDIR) ; $(CHOWN) $(GAMEUID) $(DAT) ; \
+                       $(CHGRP) $(GAMEGRP) $(DAT) ; \
+                       chmod $(FILEPERM) $(DAT) )
+
+update: $(GAME) recover $(VARDAT) dungeon spec_levs
+#      (don't yank the old version out from under people who're playing it)
+       -mv $(GAMEDIR)/$(GAME) $(GAMEDIR)/$(GAME).old
+#      quest.dat is also kept open and has the same problems over NFS
+#      (quest.dat may be inside nhdat if dlb is in use)
+       -mv $(GAMEDIR)/quest.dat $(GAMEDIR)/quest.dat.old
+       -mv $(GAMEDIR)/nhdat $(GAMEDIR)/nhdat.old
+# set up new versions of the game files
+       ( $(MAKE) dofiles )
+# touch time-sensitive files
+       -touch -c $(VARDIR)/bones* $(VARDIR)/?lock* $(VARDIR)/wizard*
+       -touch -c $(VARDIR)/save/*
+       touch $(VARDIR)/perm $(VARDIR)/record
+# and a reminder
+       @echo You may also want to install the man pages via the doc Makefile.
+
+install: $(GAME) recover $(VARDAT) dungeon spec_levs
+# set up the directories
+# not all mkdirs have -p; those that don't will create a -p directory
+       -mkdir -p $(SHELLDIR)
+       -rm -rf $(GAMEDIR) $(VARDIR)
+       -mkdir -p $(GAMEDIR) $(VARDIR) $(VARDIR)/save
+       -rmdir ./-p
+       -$(CHOWN) $(GAMEUID) $(GAMEDIR) $(VARDIR) $(VARDIR)/save
+       $(CHGRP) $(GAMEGRP) $(GAMEDIR) $(VARDIR) $(VARDIR)/save
+       chmod $(DIRPERM) $(GAMEDIR) $(VARDIR) $(VARDIR)/save
+# set up the game files
+       ( $(MAKE) dofiles )
+# set up some additional files
+       touch $(VARDIR)/perm $(VARDIR)/record $(VARDIR)/logfile
+       -( cd $(VARDIR) ; $(CHOWN) $(GAMEUID) perm record logfile ; \
+                       $(CHGRP) $(GAMEGRP) perm record logfile ; \
+                       chmod $(FILEPERM) perm record logfile )
+# and a reminder
+       @echo You may also want to reinstall the man pages via the doc Makefile.
+
+
+# 'make clean' removes all the .o files, but leaves around all the executables
+# and compiled data files
+clean:
+       ( cd src ; $(MAKE) clean )
+       ( cd util ; $(MAKE) clean )
+
+# 'make spotless' returns the source tree to near-distribution condition.
+# it removes .o files, executables, and compiled data files
+spotless:
+       ( cd src ; $(MAKE) spotless )
+       ( cd util ; $(MAKE) spotless )
+       ( cd dat ; $(MAKE) spotless )
+       ( cd doc ; $(MAKE) spotless )
diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl
new file mode 100644 (file)
index 0000000..e2936a8
--- /dev/null
@@ -0,0 +1,403 @@
+#      Makefile for NetHack's utility programs.
+#      SCCS Id: @(#)Makefile.utl       3.4     1997/04/19
+
+# newer makes predefine $(MAKE) to 'make' and do smarter processing of
+# recursive make calls if $(MAKE) is used
+# these makes allow $(MAKE) to be overridden by the environment if someone
+# wants to (or has to) use something other than the standard make, so we do
+# not want to unconditionally set $(MAKE) here
+#
+# unfortunately, some older makes do not predefine $(MAKE); if you have one of
+# these, uncomment the following line
+# (you will know that you have one if you get complaints about unable to
+# execute things like 'foo.o')
+# MAKE = make
+
+# if you are using gcc as your compiler,
+#      uncomment the CC definition below if it's not in your environment
+# CC = gcc
+#
+#      For Bull DPX/2 systems at B.O.S. 2.0 or higher use the following:
+#
+# CC = gcc -ansi -D_BULL_SOURCE -D_XOPEN_SOURCE -D_POSIX_SOURCE
+# 
+#      If you are using GCC 2.2.2 or higher on a DPX/2, just use:
+#
+# CC = gcc -ansi
+#
+#      For HP/UX 10.20 with GCC:
+# CC = gcc -D_POSIX_SOURCE
+#
+# if your make doesn't define a default SHELL properly, you may need
+#    the line below (Atari users will need a bourne work-alike)
+# SHELL = /bin/sh
+# for Atari
+# SHELL=E:/GEMINI2/MUPFEL.TTP
+
+# flags may have to be changed as required
+# flags for 286 Xenix:
+# CFLAGS = -Ml2t16 -O -LARGE -I../include
+# LFLAGS = -Ml -F 4000 -SEG 512
+
+# flags for 286 Microport SysV-AT
+# CFLAGS = -DDUMB -Ml -I../include
+# LFLAGS = -Ml
+
+# flags for Atari GCC (3.2.1)
+# CFLAGS = -O -I../include
+# LFLAGS = -s
+# flags for Atari GCC (3.3)
+# CFLAGS = -mshort -O2 -I../include
+# LFLAGS = -mshort -s
+
+# flags for Apollos using their native cc
+# (as long as it claims to be __STDC__ but isn't)
+# CFLAGS = -DAPOLLO -O -I../include
+
+# flags for AIX 3.1 cc on IBM RS/6000 to define
+# a suitable subset of standard libraries
+# (note that there is more info regarding the "-qchars=signed"
+# switch in file Install.unx note 8)
+# CFLAGS = -D_NO_PROTO -D_XOPEN_SOURCE -O -I../include -qchars=signed
+# and for AIX 3.2:
+# CFLAGS = -D_NO_PROTO -D_XOPEN_SOURCE -D_ALL_SOURCE -O -I../include -qchars=signed
+
+# flags for A/UX 2.01 using native cc or c89
+# gcc predefines AUX so that's not needed there
+# CFLAGS = -ZS -D_POSIX_SOURCE -O -I../include -DAUX
+
+# flags for IRIX 4.0.x using native cc
+# SGI cc 3.10 will fail to compile makedefs with -O
+# CFLAGS = -I../include -D__STDC__ -woff 100,293
+
+# flags for Linux
+#   compile normally
+# CFLAGS = -O2 -fomit-frame-pointer -I../include
+# LFLAGS = -L/usr/X11R6/lib
+#   OR compile backwards compatible a.out format
+# CFLAGS = -O2 -b i486-linuxaout -fomit-frame-pointer -I../include
+# LFLAGS = -b i486-linuxaout -L/usr/X11R6/lib
+
+# flags for BeOS using the command line
+# remember to uncomment flex and bison below
+#   BeOS on a Mac/BeBox:
+#CC = mwcc
+#CFLAGS = -I../include
+#   BeOS on Intel:
+# the default values are fine
+
+# flags for debugging:
+# CFLAGS = -g -I../include
+
+CFLAGS = -O -I../include
+LFLAGS =
+
+LIBS =
+# If you are cross-compiling, you must use this:
+#OBJDIR = .
+# otherwise, you can save a little bit of disk space with this:
+OBJDIR = ../src
+
+# yacc/lex programs to use to generate *_comp.h, *_lex.c, and *_yacc.c.
+# if, instead of yacc/lex you have bison/flex, comment/uncomment the following.
+YACC     = yacc
+LEX      = lex
+# YACC     = bison -y
+# YACC     = byacc
+# LEX      = flex
+# these are the names of the output files from YACC/LEX. Under MS-DOS
+# and similar systems, they may differ
+YTABC = y.tab.c
+YTABH = y.tab.h
+LEXYYC = lex.yy.c
+# YTABC = y_tab.c
+# YTABH = y_tab.h
+# LEXYYC = lexyy.c
+
+
+
+# ----------------------------------------
+#
+# Nothing below this line should have to be changed.
+
+# timestamps for primary header files, matching src/Makefile
+CONFIG_H = ../src/config.h-t
+HACK_H  = ../src/hack.h-t
+
+# utility .c files
+MAKESRC = makedefs.c
+SPLEVSRC = lev_yacc.c lev_lex.c lev_main.c
+DGNCOMPSRC = dgn_yacc.c dgn_lex.c dgn_main.c
+RECOVSRC = recover.c
+DLBSRC = dlb_main.c
+UTILSRCS = $(MAKESRC) panic.c $(SPLEVSRC) $(DGNCOMPSRC) $(RECOVSRC) $(DLBSRC)
+
+# files that define all monsters and objects
+CMONOBJ = ../src/monst.c ../src/objects.c
+OMONOBJ = $(OBJDIR)/monst.o $(OBJDIR)/objects.o
+# files that provide access to NetHack's names
+CNAMING = ../src/drawing.c ../src/decl.c $(CMONOBJ)
+ONAMING = $(OBJDIR)/drawing.o $(OBJDIR)/decl.o $(OMONOBJ)
+# dynamic memory allocation
+CALLOC = ../src/alloc.c panic.c
+OALLOC = $(OBJDIR)/alloc.o panic.o
+
+# object files for makedefs
+MAKEOBJS = makedefs.o $(OMONOBJ)
+
+# object files for special levels compiler
+SPLEVOBJS = lev_yacc.o lev_lex.o lev_main.o $(OALLOC) $(ONAMING)
+
+# object files for dungeon compiler
+DGNCOMPOBJS = dgn_yacc.o dgn_lex.o dgn_main.o $(OALLOC)
+
+# object files for recovery utility
+RECOVOBJS = recover.o
+
+# object files for the data librarian
+DLBOBJS = dlb_main.o $(OBJDIR)/dlb.o $(OALLOC)
+
+# flags for creating distribution versions of sys/share/*_lex.c, using
+# a more portable flex skeleton, which is not included in the distribution.
+# hopefully keeping this out of the section to be edited will keep too
+# many people from being confused by it...
+# FLEXDIST = -L -S../sys/share/flexhack.skl
+FLEXDIST =
+#
+# flags for creating distribution versions of sys/share/*_yacc.c, without
+# line numbers so patches from version to version are practical
+# YACCDIST = -l
+YACCDIST =
+
+
+#      dependencies for makedefs
+#
+makedefs:      $(MAKEOBJS)
+       $(CC) $(LFLAGS) -o makedefs $(MAKEOBJS)
+
+makedefs.o: makedefs.c $(CONFIG_H) ../include/permonst.h \
+               ../include/objclass.h ../include/monsym.h \
+               ../include/artilist.h ../include/dungeon.h ../include/obj.h \
+               ../include/monst.h ../include/you.h ../include/flag.h \
+               ../include/dlb.h ../include/patchlevel.h ../include/qtext.h
+
+../include/onames.h: makedefs
+       ./makedefs -o
+../include/pm.h: makedefs
+       ./makedefs -p
+../src/monstr.c: makedefs
+       ./makedefs -m
+../include/vis_tab.h: makedefs
+       ./makedefs -z
+# makedefs -z makes both vis_tab.h and vis_tab.c, but writes the .h first
+../src/vis_tab.c: ../include/vis_tab.h
+
+lintdefs:
+       @lint -axbh -I../include -DLINT $(MAKESRC) $(CMONOBJ) | sed '/_flsbuf/d'
+
+
+# we defer this makedefs call to the src Makefile, since it knows all about
+# the main src and include files date.h is a timestamp for
+../include/date.h::
+       @( cd ../src ; $(MAKE) ../include/date.h )
+
+# support code used by several of the utility programs (but not makedefs)
+panic.o:     panic.c $(CONFIG_H)
+
+
+#      dependencies for lev_comp
+#
+lev_comp:  $(SPLEVOBJS)
+       $(CC) $(LFLAGS) -o lev_comp $(SPLEVOBJS) $(LIBS)
+
+lev_yacc.o:  lev_yacc.c $(HACK_H) ../include/sp_lev.h
+lev_main.o:  lev_main.c $(HACK_H) ../include/sp_lev.h ../include/tcap.h \
+               ../include/date.h
+
+# see lev_comp.l for WEIRD_LEX discussion
+# egrep will return failure if it doesn't find anything, but we know there
+# is one "_cplusplus" inside a comment
+lev_lex.o:   lev_lex.c $(HACK_H) ../include/lev_comp.h ../include/sp_lev.h
+       @echo $(CC) -c $(CFLAGS) lev_lex.c
+       @$(CC) -c $(CFLAGS) -DWEIRD_LEX=`egrep -c _cplusplus lev_lex.c` lev_lex.c
+
+../include/lev_comp.h: lev_yacc.c
+
+lev_yacc.c: lev_comp.y
+       $(YACC) $(YACCDIST) -d lev_comp.y
+       mv $(YTABC) lev_yacc.c
+       mv $(YTABH) ../include/lev_comp.h
+
+lev_lex.c: lev_comp.l
+       $(LEX) $(FLEXDIST) lev_comp.l
+       mv $(LEXYYC) lev_lex.c
+
+# with all of extern.h's functions to complain about, we drown in
+# 'defined but not used' without -u
+lintlev:
+       @lint -axhu -I../include -DLINT $(SPLEVSRC) $(CALLOC) $(CNAMING) | sed '/_flsbuf/d'
+
+
+#      dependencies for dgn_comp
+#
+dgn_comp:  $(DGNCOMPOBJS)
+       $(CC) $(LFLAGS) -o dgn_comp $(DGNCOMPOBJS) $(LIBS)
+
+dgn_yacc.o:  dgn_yacc.c $(CONFIG_H) ../include/dgn_file.h ../include/date.h
+dgn_main.o:  dgn_main.c $(CONFIG_H) ../include/dlb.h
+
+# see dgn_comp.l for WEIRD_LEX discussion
+dgn_lex.o:   dgn_lex.c $(CONFIG.H) ../include/dgn_comp.h ../include/dgn_file.h
+       @echo $(CC) -c $(CFLAGS) dgn_lex.c
+       @$(CC) -c $(CFLAGS) -DWEIRD_LEX=`egrep -c _cplusplus dgn_lex.c` dgn_lex.c
+
+
+../include/dgn_comp.h: dgn_yacc.c
+
+dgn_yacc.c: dgn_comp.y
+       $(YACC) $(YACCDIST) -d dgn_comp.y
+       mv $(YTABC) dgn_yacc.c
+       mv $(YTABH) ../include/dgn_comp.h
+
+dgn_lex.c: dgn_comp.l
+       $(LEX) $(FLEXDIST) dgn_comp.l
+       mv $(LEXYYC) dgn_lex.c
+
+# with all of extern.h's functions to complain about, we drown in
+# 'defined but not used' without -u
+lintdgn:
+       @lint -axhu -I../include -DLINT $(DGNCOMPSRC) $(CALLOC) | sed '/_flsbuf/d'
+
+
+#      dependencies for recover
+#
+recover: $(RECOVOBJS)
+       $(CC) $(LFLAGS) -o recover $(RECOVOBJS) $(LIBS)
+
+recover.o: recover.c $(CONFIG_H) ../include/date.h
+
+
+#      dependencies for dlb
+#
+dlb:   $(DLBOBJS)
+       $(CC) $(LFLAGS) -o dlb $(DLBOBJS) $(LIBS)
+
+dlb_main.o: dlb_main.c $(CONFIG_H) ../include/dlb.h ../include/date.h
+       $(CC) $(CFLAGS) -c dlb_main.c
+
+
+
+#      dependencies for tile utilities
+#
+TEXT_IO = tiletext.o tiletxt.o $(ONAMING)
+GIFREADERS = gifread.o $(OALLOC)
+PPMWRITERS = ppmwrite.o $(OALLOC)
+
+tileutils: tilemap gif2txt txt2ppm tile2x11
+
+gif2txt: $(GIFREADERS) $(TEXT_IO)
+       $(CC) $(LFLAGS) -o gif2txt $(GIFREADERS) $(TEXT_IO) $(LIBS)
+txt2ppm: $(PPMWRITERS) $(TEXT_IO)
+       $(CC) $(LFLAGS) -o txt2ppm $(PPMWRITERS) $(TEXT_IO) $(LIBS)
+
+tile2x11: tile2x11.o $(TEXT_IO)
+       $(CC) $(LFLAGS) -o tile2x11 tile2x11.o $(TEXT_IO) $(LIBS)
+
+tile2img.ttp: tile2img.o bitmfile.o $(TEXT_IO)
+       $(CC) $(LFLAGS) -o tile2img.ttp tile2img.o bitmfile.o $(TEXT_IO) $(LIBS)
+
+tile2bmp: tile2bmp.o $(TEXT_IO)
+       $(CC) $(LFLAGS) -o tile2bmp tile2bmp.o $(TEXT_IO)
+
+xpm2img.ttp: xpm2img.o bitmfile.o
+       $(CC) $(LFLAGS) -o xpm2img.ttp xpm2img.o bitmfile.o $(LIBS)
+
+tile2beos: tile2beos.o $(TEXT_IO)
+       $(CC) $(LFLAGS) -o tile2beos tile2beos.o $(TEXT_IO) -lbe
+
+tilemap: ../win/share/tilemap.c $(HACK_H)
+       $(CC) $(CFLAGS) $(LFLAGS) -o tilemap ../win/share/tilemap.c $(LIBS)
+../src/tile.c: tilemap
+       ./tilemap
+
+../include/tile.h: ../win/share/tile.h
+       cp ../win/share/tile.h ../include/tile.h
+tiletext.o: ../win/share/tiletext.c $(CONFIG_H) ../include/tile.h
+       $(CC) $(CFLAGS) -c ../win/share/tiletext.c
+tiletxt.o: ../win/share/tilemap.c $(HACK_H)
+       $(CC) $(CFLAGS) -c -DTILETEXT ../win/share/tilemap.c
+       mv tilemap.o tiletxt.o
+
+gifread.o: ../win/share/gifread.c $(CONFIG_H) ../include/tile.h
+       $(CC) $(CFLAGS) -c ../win/share/gifread.c
+ppmwrite.o: ../win/share/ppmwrite.c $(CONFIG_H) ../include/tile.h
+       $(CC) $(CFLAGS) -c ../win/share/ppmwrite.c
+
+tile2bmp.o: ../win/share/tile2bmp.c $(HACK_H) ../include/tile.h
+       $(CC) $(CFLAGS) -c ../win/share/tile2bmp.c
+
+tile2x11.o: ../win/X11/tile2x11.c $(HACK_H) ../include/tile.h \
+                                               ../include/tile2x11.h
+       $(CC) $(CFLAGS) -c ../win/X11/tile2x11.c
+
+tile2img.o: ../win/gem/tile2img.c $(HACK_H) ../include/tile.h \
+                                               ../include/bitmfile.h
+       $(CC) $(CFLAGS) -c ../win/gem/tile2img.c
+xpm2img.o: ../win/gem/xpm2img.c $(HACK_H) ../include/bitmfile.h
+       $(CC) $(CFLAGS) -c ../win/gem/xpm2img.c
+bitmfile.o: ../win/gem/bitmfile.c ../include/bitmfile.h
+       $(CC) $(CFLAGS) -c ../win/gem/bitmfile.c
+
+tile2beos.o: ../win/BeOS/tile2beos.cpp $(HACK_H) ../include/tile.h
+       $(CXX) $(CFLAGS) -c ../win/BeOS/tile2beos.cpp
+
+# using dependencies like
+#      ../src/foo::
+#              @( cd ../src ; $(MAKE) foo )
+# would always force foo to be up-to-date according to the src Makefile
+# when it's needed here.  unfortunately, some makes believe this syntax
+# means foo always changes, instead of foo should always be checked.
+# therefore, approximate via config.h dependencies, and hope that anybody
+# changing anything other than basic configuration also knows when not
+# to improvise things not in the instructions, like 'make makedefs' here
+# in util...
+
+# make sure object files from src are available when needed
+#
+$(OBJDIR)/alloc.o: ../src/alloc.c $(CONFIG_H)
+       $(CC) $(CFLAGS) -c ../src/alloc.c -o $@
+$(OBJDIR)/drawing.o: ../src/drawing.c $(CONFIG_H)
+       $(CC) $(CFLAGS) -c ../src/drawing.c -o $@
+$(OBJDIR)/decl.o: ../src/decl.c $(CONFIG_H)
+       $(CC) $(CFLAGS) -c ../src/decl.c -o $@
+$(OBJDIR)/monst.o: ../src/monst.c $(CONFIG_H)
+       $(CC) $(CFLAGS) -c ../src/monst.c -o $@
+$(OBJDIR)/objects.o: ../src/objects.c $(CONFIG_H)
+       $(CC) $(CFLAGS) -c ../src/objects.c -o $@
+$(OBJDIR)/dlb.o: ../src/dlb.c $(HACK_H) ../include/dlb.h
+       $(CC) $(CFLAGS) -c ../src/dlb.c -o $@
+
+# make sure hack.h dependencies get transitive information
+$(HACK_H): $(CONFIG_H)
+       @( cd ../src ; $(MAKE) $(HACK_H) )
+$(CONFIG_H): ../include/config.h
+       @( cd ../src ; $(MAKE) $(CONFIG_H) )
+
+tags: $(UTILSRCS)
+       @ctags -tw $(UTILSRCS)
+
+clean:
+       -rm -f *.o
+
+spotless: clean
+       -rm -f lev_lex.c lev_yacc.c dgn_lex.c dgn_yacc.c
+       -rm -f ../include/lev_comp.h ../include/dgn_comp.h
+       -rm -f ../include/tile.h
+       -rm -f makedefs lev_comp dgn_comp recover dlb
+       -rm -f gif2txt txt2ppm tile2x11 tile2img.ttp xpm2img.ttp tilemap
+
+tileedit: tileedit.cpp $(TEXT_IO)
+       $(QTDIR)/bin/moc -o tileedit.moc tileedit.h
+       $(CC) -o tileedit -I../include -I$(QTDIR)/include -L$(QTDIR)/lib tileedit.cpp $(TEXT_IO) -lqt
diff --git a/sys/unix/README.linux b/sys/unix/README.linux
new file mode 100644 (file)
index 0000000..f702a69
--- /dev/null
@@ -0,0 +1,107 @@
+NetHack 3.4.3 Linux Elf
+
+This README provides the instructions for using the official Linux binary,
+system platform requirements, as well as steps used to create that binary.
+The same steps can be used from the source distribution to create a similar
+binary.
+
+The official Linux binary has support for tty and X11 windowing systems, but
+not Qt.  This means you will need to have X11 libraries installed on your
+system to run this binary, even in its tty flavor.
+
+
+The Linux binary package assumes that you have a user and a group named
+"games" on your system.  If you do not, you can simplify installation by
+creating them first.
+
+Log in as or su to "root".  Then, cd /, gunzip and untar the package,
+preserving permissions to put the NetHack files in /usr/games/nethack and
+/usr/games/lib/nethackdir.   For example, if the package in in your
+home directory you might perform these steps.
+    % su
+    # cd /
+    # tar xpvzf ~yourlogin/nethack-343-linux-X11.tgz
+
+If you have old record and logfile entries from a previous NetHack version,
+you might want to save copies before they get overwritten by the new empty
+files; old saved games and bones files from 3.4.x will work with 3.4.3.
+If you are installing from the RPM, there is no need to save the old record
+and logfile; they are automatically preserved.
+
+In addition to data files for running the game, you will find other useful
+things in /usr/games/lib/nethackdir (such as a copy of this README :-).
+
+The general documentation Guidebook.txt and the processed man pages
+nethack.txt and recover.txt should provide an introduction to the game.
+
+The sample config file called dot.nethackrc can be used by copying
+it to your home directory as .nethackrc and modifying it to your liking.
+
+If you are running X11 copy the nh10.pcf and ibm.pcf font files from
+/usr/games/lib/nethackdir to a X11 fonts directory (such as
+/usr/X11/lib/X11/fonts/misc) and run "mkfontdir", then restart X
+windows to load them.  If you prefer to use the graphical tiles,
+add the following to your .Xdefaults or .Xresources file:
+       NetHack.tile_file: x11tiles
+You may need to run "xrdb -merge $HOME/.Xdefaults" (or .Xresources) after
+doing this.
+
+The official Linux binary is set up to run setgid games, which allows
+multiple users on your system to play the game and prevents cheating by
+unprivileged users.  The usual default for NetHack is setuid games, but
+this causes problems with accessing .nethackrc on distributions with
+restrictive default security on home directories and users who don't know
+the tradeoffs of various permission settings.
+
+
+If you have problems, send us some email.
+
+nethack-bugs@nethack.org
+
+
+
+Steps used to build this binary release, in addition to the basic
+instructions found in sys/unix/Install.unx.  The step numbers below
+correspond to the step numbers in sys/unix/Install.unx.
+
+System:  gcc-3.2, XFree86-libs-4.2.1, ncurses-5.2, glibc-2.3.2 (GLIBC_2.3)
+
+3.  Edit include/config.h and include/unixconf.h
+    config.h: define X11_GRAPHICS window support.
+              define USE_XPM support.
+              define COMPRESS as /bin/gzip as that is where it
+              seems to reside on newer Linux's.
+              define COMPRESS_EXTENSION as ".gz"
+              define DLB
+             define AUTOPICKUP_EXCEPTIONS
+
+    unixconf.h: define LINUX
+                define TIMED_DELAY
+
+6.  Makefile.src: define modern, non-BSD Linux and linux options throughout
+                 CC = gcc
+                 LFLAGS = -L/usr/X11R6/lib
+                 WINSRC = $(WINTTYSRC) $(WINX11SRC)
+                 WINOBJ = $(WINTTYOBJ) $(WINX11OBJ)
+                 WINTTYLIB = /usr/lib/libncurses.a
+                 WINX11LIB = -lXaw -lXmu -lXext -lXt -lXpm -lX11
+                 WINLIB = $(WINTTYLIB) $(WINX11LIB)
+
+    Makefile.utl: define modern, non-BSD Linux and linux options throughout
+                  Use bison/flex instead of yacc/lex
+                 CC = gcc
+                 LFLAGS = -L/usr/X11R6/lib
+                 YACC = bison -y
+                 LEX = flex
+
+7.  Makefile.top: GAMEGRP = games
+                 GAMEPERM = 02755
+                 FILEPERM = 0664
+                 EXEPERM = 0755
+                 DIRPERM = 0775
+                 VARDATND = x11tiles NetHack.ad pet_mark.xbm rip.xpm
+
+    make all; su; make install
+
+9.  Additional step: As discussed in win/X11/Install.X11, convert nh10.bdf
+    and ibm.bdf to proper font files and place in font path.
diff --git a/sys/unix/cpp1.shr b/sys/unix/cpp1.shr
new file mode 100644 (file)
index 0000000..f2b133d
--- /dev/null
@@ -0,0 +1,1783 @@
+# This is a shell archive.  Save it in a file, remove anything before
+# this line, and then unpack it by entering "sh file".  Note, it may
+# create directories; files and directories will be owned by you and
+# have default permissions.
+#
+# This archive contains:
+#
+#      makefile.txt
+#      readme.txt
+#      cpp.mem
+#      cpp.h
+#      cppdef.h
+#      cpp2.c
+#
+echo x - makefile.txt
+sed 's/^X//' >makefile.txt << 'END-of-makefile.txt'
+X#
+X# The redefinition of strchr() and strrchr() are needed for
+X# Ultrix-32, Unix 4.2 bsd (and maybe some other Unices).
+X#
+XBSDDEFINE = -Dstrchr=index -Dstrrchr=rindex
+X#
+X# On certain systems, such as Unix System III, you may need to define
+X# $(LINTFLAGS) in the make command line to set system-specific lint flags.
+X#
+X# This Makefile assumes cpp will replace the "standard" preprocessor.
+X# Delete the reference to -DLINE_PREFIX=\"\" if cpp is used stand-alone.
+X# LINEFIX is a sed script filter that reinserts #line -- used for testing
+X# if LINE_PREFIX is set to "".   Note that we must stand on our heads to
+X# match the # and a line had better not begin with $.  By the way, what
+X# we really want is
+X#     LINEFIX = | sed "s/^#/#line/"
+X#
+XCPPDEFINE = -DLINE_PREFIX=\"\"
+XLINEFIX = | sed "s/^[^ !\"%-~]/&line/"
+X#
+X# Define OLD_PREPROCESSOR non-zero to make a preprocessor which is
+X# "as compatible as possible" with the standard Unix V7 or Ultrix
+X# preprocessors.  This is needed to rebuild 4.2bsd, for example, as
+X# the preprocessor is used to modify assembler code, rather than C.
+X# This is not recommended for current development.  OLD_PREPROCESSOR
+X# forces the following definitions:
+X#   OK_DOLLAR         FALSE   $ is not allowed in variables
+X#   OK_CONCAT         FALSE   # cannot concatenate tokens
+X#   COMMENT_INVISIBLE TRUE    old-style comment concatenation
+X#   STRING_FORMAL     TRUE    old-style string expansion
+X#
+XOLDDEFINE = -DOLD_PREPROCESSOR=1
+X#
+X# DEFINES collects all -D arguments for cc and lint:
+X# Change DEFINES = $(BSDDEFINE) $(CPPDEFINE) $(OLDDEFINE)
+X# for an old-style preprocessor.
+X#
+X# DEFINES = $(BSDDEFINE) $(CPPDEFINE)
+XDEFINES = $(CPPDEFINE)
+X
+XCFLAGS = -O $(DEFINES)
+X
+X#
+X# ** compile cpp
+X#
+XSRCS = cpp1.c cpp2.c cpp3.c cpp4.c cpp5.c cpp6.c
+XOBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o
+Xcpp: $(OBJS)
+X      $(CC) $(CFLAGS) $(OBJS) -o cpp
+X
+X#
+X# ** Test cpp by preprocessing itself, compiling the result,
+X# ** repeating the process and diff'ing the result.  Note: this
+X# ** is not a good test of cpp, but a simple verification.
+X# ** The diff's should not report any changes.
+X# ** Note that a sed script may be executed for each compile
+X#
+Xtest:
+X      cpp cpp1.c $(LINEFIX) >old.tmp1.c
+X      cpp cpp2.c $(LINEFIX) >old.tmp2.c
+X      cpp cpp3.c $(LINEFIX) >old.tmp3.c
+X      cpp cpp4.c $(LINEFIX) >old.tmp4.c
+X      cpp cpp5.c $(LINEFIX) >old.tmp5.c
+X      cpp cpp6.c $(LINEFIX) >old.tmp6.c
+X      $(CC) $(CFLAGS) old.tmp[123456].c
+X      a.out cpp1.c >new.tmp1.c
+X      a.out cpp2.c >new.tmp2.c
+X      a.out cpp3.c >new.tmp3.c
+X      a.out cpp4.c >new.tmp4.c
+X      a.out cpp5.c >new.tmp5.c
+X      a.out cpp6.c >new.tmp6.c
+X      diff old.tmp1.c new.tmp1.c
+X      diff old.tmp2.c new.tmp2.c
+X      diff old.tmp3.c new.tmp3.c
+X      diff old.tmp4.c new.tmp4.c
+X      diff old.tmp5.c new.tmp5.c
+X      diff old.tmp6.c new.tmp6.c
+X      rm a.out old.tmp[123456].* new.tmp[123456].*
+X
+X#
+X# A somewhat more extensive test is provided by the "clock"
+X# program (which is not distributed).  Substitute your favorite
+X# macro-rich program here.
+X#
+Xclock:        clock.c cpp
+X      cpp clock.c $(LINEFIX) >temp.cpp.c
+X      cc temp.cpp.c -lcurses -ltermcap -o clock
+X      rm temp.cpp.c
+X
+X#
+X# ** Lint the code
+X#
+X
+Xlint: $(SRCS)
+X      lint $(LINTFLAGS) $(DEFINES) $(SRCS)
+X
+X#
+X# ** Remove unneeded files
+X#
+Xclean:
+X      rm -f $(OBJS) cpp
+X
+X#
+X# ** Rebuild the archive files needed to distribute cpp
+X# ** Uses the Decus C archive utility.
+X#
+X
+Xarchc:        archc.c
+X      $(CC) $(CFLAGS) archc.c -o archc
+X
+Xarchx:        archx.c
+X      $(CC) $(CFLAGS) archx.c -o archx
+X
+Xarchive: archc
+X      archc readme.txt cpp.mem archx.c archc.c cpp.rno makefile.txt \
+X              cpp*.h >cpp1.arc
+X      archc cpp1.c cpp2.c cpp3.c >cpp2.arc
+X      archc cpp4.c cpp5.c cpp6.c >cpp3.arc
+X
+X#
+X# Object module dependencies
+X#
+X
+Xcpp1.o        :       cpp1.c cpp.h cppdef.h
+X
+Xcpp2.o        :       cpp2.c cpp.h cppdef.h
+X
+Xcpp3.o        :       cpp3.c cpp.h cppdef.h
+X
+Xcpp4.o        :       cpp4.c cpp.h cppdef.h
+X
+Xcpp5.o        :       cpp5.c cpp.h cppdef.h
+X
+Xcpp6.o        :       cpp6.c cpp.h cppdef.h
+X
+X
+END-of-makefile.txt
+echo x - readme.txt
+sed 's/^X//' >readme.txt << 'END-of-readme.txt'
+X
+XDecus cpp is a public-domain implementation of the C preprocessor.
+XIt runs on VMS native (Vax C), VMS compatibilty mode (Decus C),
+XRSX-11M, RSTS/E, P/OS, and RT11, as well as on several varieties
+Xof Unix, including Ultrix.  Decus cpp attempts to implement features
+Xin the Draft ANSI Standard for the C language.  It should be noted,
+Xhowever, that this standard is under active development:  the current
+Xdraft of the standard explicitly states that "readers are requested
+Xnot to specify or claim conformance to this draft."  Thus readers
+Xand users of Decus cpp should not assume that it conforms to the
+Xdraft standard, or that it will conform to the actual C language
+Xstandard.
+X
+XThese notes describe how to extract the cpp source files, configure it
+Xfor your needs, and mention a few design decisions that may be of interest
+Xto maintainers.
+X
+X                      Installation
+X
+XBecause the primary development of cpp was not on Unix, it
+Xis distributed using the Decus C archive program (quite similar
+Xto the archiver published in Kernighan and Plauger's Software
+XTools).  To extract the files from the net.sources distribution,
+Xsave this message as cpp1.arc and the other two distribution
+Xfiles as cpp2.arc and cpp3.arc.  Then, using your favorite editor,
+Xlocate the archx.c program, just following the line beginning with
+X"-h- archx.c" -- the format of the distribution is just:
+X
+X    -h- readme.txt
+X      ... this file
+X    -h- cpp.mem
+X      ... description of cpp
+X    -h- archx.c
+X      ... archx.c program -- extracts archives
+X    -h- archc.c
+X      ... archc.c program -- creates archives
+X
+XCompile archx.c -- it shouldn't require any special editing.
+XThen run it as follows:
+X
+X    archx *.arc
+X
+XYou do not need to remove mail headers from the saved messages.
+X
+XYou should then read through cppdef.h to make sure the HOST and
+XTARGET (and other implementation-specific) definitions are set
+Xcorrectly for your machine, editing them as needed.
+X
+XYou may then copy makefile.txt to Makefile, editing it as needed
+Xfor your particular system.  On Unix, cpp should be compiled
+Xby make without further difficulty.  On other operating systems,
+Xyou should compile the six source modules, linking them together.
+XNote that, on Decus C based systems, you must extend the default
+Xstack allocation.  The Decus C build utility will create the
+Xappropriate command file.
+X
+X                      Support Notes
+X
+XThe USENET distribution kit was designed to keep all submissions around
+X50,000 bytes:
+X
+Xcpp1.arc:
+X      readme.txt      This file
+X      cpp.mem         Documentation page (see below)
+X      archx.c         Archive extraction program
+X      archc.c         Archive construction program
+X      cpp.rno         Source for cpp.mem (see below)
+X      makefile.txt    Unix makefile -- copy to Makefile
+X      cpp.h           Main header file (structure def's and globals)
+X      cppdef.h        Configuration file (host and target definitions)
+X
+Xcpp2.arc:
+X      cpp1.c          Mainline code, documentation master sources
+X      cpp2.c          most #control processing
+X      cpp3.c          filename stuff and command line parsing
+Xcpp3.arc:
+X      cpp4.c          #define processor
+X      cpp5.c          #if <expr> processor
+X      cpp6.c          Support code (symbol table and I/O routines)
+X      
+XCpp intentionally does not rely on the presence of a full-scale
+Xmacro preprocessor, it does require the simple parameter substitution
+Xpreprocessor capabilities of Unix V6 and Decus C.  If your C
+Xlanguage lacks full preprocessing, you should make sure "nomacargs"
+Xis #define'd in cpp.h.  (This is done automatically by the Decus C
+Xcompiler.)
+X
+XThe documentation (manual page) for cpp is included as cpp.mem
+Xand cpp.rno.  Cpp.rno is in Dec Runoff format, built by a Decus C
+Xutility (getrno) from original source which is embedded in cpp1.c.
+XTo my knowledge, there is no equivalent program that creates
+Xthe nroff source appropriate for Unix.
+X
+XI would be happy to receive fixes to any problems you encounter.
+XAs I do not maintain distribution kit base-levels, bare-bones
+Xdiff listings without sufficient context are not very useful.
+XIt is unlikely that I can find time to help you with other
+Xdifficulties.
+X
+X                      Acknowledgements
+X
+XI received a great deal of help from many people in debugging cpp.
+XAlan Feuer and Sam Kendall used "state of the art" run-time code
+Xcheckers to locate several errors.  Ed Keiser found problems when
+Xcpp was used on machines with different int and pointer sizes.
+XDave Conroy helped with the initial debugging, while Arthur Olsen
+Xand George Rosenberg found (and solved) several problems in the
+Xfirst USENET release.
+X
+XMartin Minow
+Xdecvax!minow
+X
+END-of-readme.txt
+echo x - cpp.mem
+sed 's/^X//' >cpp.mem << 'END-of-cpp.mem'
+X
+X
+X
+X
+X        1.0  C Pre-Processor
+X
+X
+X
+X                                    *******
+X                                    * cpp *
+X                                    *******
+X
+X
+X
+X        NAME:   cpp -- C Pre-Processor
+X
+X        SYNOPSIS:
+X
+X                cpp [-options] [infile [outfile]]
+X
+X        DESCRIPTION:
+X
+X                CPP reads a C source file, expands  macros  and  include
+X                files,  and writes an input file for the C compiler.  If
+X                no file arguments are given, CPP reads  from  stdin  and
+X                writes  to  stdout.   If  one file argument is given, it
+X                will define the input file,  while  two  file  arguments
+X                define  both  input and output files.  The file name "-"
+X                is a synonym for stdin or stdout as appropriate.
+X
+X                The following options are  supported.   Options  may  be
+X                given in either case.
+X
+X                -C              If set, source-file comments are written
+X                                to  the  output  file.   This allows the
+X                                output of CPP to be used as the input to
+X                                a  program,  such  as lint, that expects
+X                                commands embedded in specially-formatted
+X                                comments.
+X
+X                -Dname=value    Define the name  as  if  the  programmer
+X                                wrote
+X
+X                                    #define name value
+X
+X                                at the start  of  the  first  file.   If
+X                                "=value"  is  not  given, a value of "1"
+X                                will be used.
+X
+X                                On non-unix systems, all alphabetic text
+X                                will be forced to upper-case.
+X
+X                -E              Always return "success" to the operating
+X                                system,  even  if  errors were detected.
+X                                Note that some fatal errors, such  as  a
+X                                missing  #include  file,  will terminate
+X                                CPP, returning "failure" even if the  -E
+X                                option is given.
+X\f                                                                          Page 2
+X        cpp     C Pre-Processor
+X
+X
+X                -Idirectory     Add  this  directory  to  the  list   of
+X                                directories  searched for #include "..."
+X                                and #include <...> commands.  Note  that
+X                                there  is  no space between the "-I" and
+X                                the directory string.  More than one  -I
+X                                command   is   permitted.   On  non-Unix
+X                                systems   "directory"   is   forced   to
+X                                upper-case.
+X
+X                -N              CPP  normally  predefines  some  symbols
+X                                defining   the   target   computer   and
+X                                operating system.  If -N  is  specified,
+X                                no symbols will be predefined.  If -N -N
+X                                is  specified,  the   "always   present"
+X                                symbols,    __LINE__,    __FILE__,   and
+X                                __DATE__ are not defined.
+X
+X                -Stext          CPP normally assumes that  the  size  of
+X                                the  target  computer's  basic  variable
+X                                types is the same as the size  of  these
+X                                types  of  the host computer.  (This can
+X                                be  overridden  when  CPP  is  compiled,
+X                                however.)  The  -S option allows dynamic
+X                                respecification of these values.  "text"
+X                                is  a  string  of  numbers, separated by
+X                                commas, that  specifies  correct  sizes.
+X                                The sizes must be specified in the exact
+X                                order:
+X
+X                                    char short int long float double
+X
+X                                If you specify the option as  "-S*text",
+X                                pointers   to   these   types   will  be
+X                                specified.   -S*  takes  one  additional
+X                                argument  for  pointer to function (e.g.
+X                                int (*)())
+X
+X                                For   example,    to    specify    sizes
+X                                appropriate  for  a  PDP-11,  you  would
+X                                write:
+X
+X                                       c s i l f d func
+X                                     -S1,2,2,2,4,8,
+X                                    -S*2,2,2,2,2,2,2
+X
+X                                Note that all values must be specified.
+X
+X                -Uname          Undefine the name as if
+X
+X                                    #undef name
+X
+X                                were given.  On non-Unix systems, "name"
+X                                will be forced to upper-case.
+X\f                                                                          Page 3
+X        cpp     C Pre-Processor
+X
+X
+X                -Xnumber        Enable debugging code.  If no  value  is
+X                                given,  a value of 1 will be used.  (For
+X                                maintenence of CPP only.)
+X
+X
+X        PRE-DEFINED VARIABLES:
+X
+X                When CPP begins processing, the following variables will
+X                have been defined (unless the -N option is specified):
+X
+X                Target computer (as appropriate):
+X
+X                    pdp11, vax, M68000 m68000 m68k
+X
+X                Target operating system (as appropriate):
+X
+X                    rsx, rt11, vms, unix
+X
+X                Target compiler (as appropriate):
+X
+X                    decus, vax11c
+X
+X                The implementor may add definitions to this  list.   The
+X                default  definitions  match  the  definition of the host
+X                computer, operating system, and C compiler.
+X
+X                The following are always available unless undefined  (or
+X                -N was specified twice):
+X
+X                    __FILE__    The  input  (or  #include)  file   being
+X                                compiled (as a quoted string).
+X
+X                    __LINE__    The line number being compiled.
+X
+X                    __DATE__    The date and time of  compilation  as  a
+X                                Unix  ctime  quoted string (the trailing
+X                                newline is removed).  Thus,
+X
+X                                    printf("Bug at line %s,", __LINE__);
+X                                    printf(" source file %s", __FILE__);
+X                                    printf(" compiled on %s", __DATE__);
+X
+X
+X        DRAFT PROPOSED ANSI STANDARD CONSIDERATIONS:
+X
+X                The current  version  of  the  Draft  Proposed  Standard
+X                explicitly  states  that  "readers  are requested not to
+X                specify or claim conformance to this draft." Readers and
+X                users  of  Decus  CPP  should  not assume that Decus CPP
+X                conforms to the standard, or that it will conform to the
+X                actual C Language Standard.
+X
+X                When CPP is itself compiled, many features of the  Draft
+X                Proposed  Standard  that  are incompatible with existing
+X\f                                                                          Page 4
+X        cpp     C Pre-Processor
+X
+X
+X                preprocessors may be  disabled.   See  the  comments  in
+X                CPP's source for details.
+X
+X                The latest version of the Draft  Proposed  Standard  (as
+X                reflected in Decus CPP) is dated November 12, 1984.
+X
+X                Comments are removed from the input text.   The  comment
+X                is  replaced by a single space character.  The -C option
+X                preserves comments, writing them to the output file.
+X
+X                The '$' character is considered to be a letter.  This is
+X                a permitted extension.
+X
+X                The following new features of C are processed by CPP:
+X
+X                    #elif expression (#else #if)
+X                    '\xNNN' (Hexadecimal constant)
+X                    '\a' (Ascii BELL)
+X                    '\v' (Ascii Vertical Tab)
+X                    #if defined NAME 1 if defined, 0 if not
+X                    #if defined (NAME) 1 if defined, 0 if not
+X                    #if sizeof (basic type)
+X                    unary +
+X                    123U, 123LU Unsigned ints and longs.
+X                    12.3L Long double numbers
+X                    token#token Token concatenation
+X                    #include token Expands to filename
+X
+X                The Draft Proposed Standard has  extended  C,  adding  a
+X                constant string concatenation operator, where
+X
+X                    "foo" "bar"
+X
+X                is regarded as the single string "foobar".   (This  does
+X                not  affect  CPP's  processing but does permit a limited
+X                form of macro argument substitution into strings as will
+X                be discussed.)
+X
+X                The Standard Committee plans to add token  concatenation
+X                to  #define command lines.  One suggested implementation
+X                is as follows:  the sequence "Token1#Token2" is  treated
+X                as  if  the programmer wrote "Token1Token2".  This could
+X                be used as follows:
+X
+X                    #line 123
+X                    #define ATLINE foo#__LINE__
+X
+X                ATLINE would be defined as foo123.
+X
+X                Note that "Token2" must either have  the  format  of  an
+X                identifier or be a string of digits.  Thus, the string
+X
+X                    #define ATLINE foo#1x3
+X\f                                                                          Page 5
+X        cpp     C Pre-Processor
+X
+X
+X                generates two tokens:  "foo1" and "x3".
+X
+X                If the tokens T1 and T2 are concatenated into  T3,  this
+X                implementation operates as follows:
+X
+X                  1. Expand T1 if it is a macro.
+X                  2. Expand T2 if it is a macro.
+X                  3. Join the tokens, forming T3.
+X                  4. Expand T3 if it is a macro.
+X
+X                A macro formal parameter  will  be  substituted  into  a
+X                string or character constant if it is the only component
+X                of that constant:
+X
+X                    #define VECSIZE 123
+X                    #define vprint(name, size) \
+X                      printf("name" "[" "size" "] = {\n")
+X                      ... vprint(vector, VECSIZE);
+X
+X                expands (effectively) to
+X
+X                      vprint("vector[123] = {\n");
+X
+X                Note that  this  will  be  useful  if  your  C  compiler
+X                supports  the  new  string concatenation operation noted
+X                above.  As implemented here, if you write
+X
+X                    #define string(arg) "arg"
+X                      ... string("foo") ...
+X
+X                This implementation generates  "foo",  rather  than  the
+X                strictly  correct  ""foo"" (which will probably generate
+X                an error message).  This is, strictly speaking, an error
+X                in CPP and may be removed from future releases.
+X
+X        ERROR MESSAGES:
+X
+X                Many.  CPP prints warning or error messages if  you  try
+X                to     use     multiple-byte     character     constants
+X                (non-transportable) if you #undef a symbol that was  not
+X                defined,  or  if  your  program  has  potentially nested
+X                comments.
+X
+X        AUTHOR:
+X
+X                Martin Minow
+X
+X        BUGS:
+X
+X                The #if expression processor uses signed integers  only.
+X                I.e, #if 0xFFFFu < 0 may be TRUE.
+X
+END-of-cpp.mem
+echo x - cpp.h
+sed 's/^X//' >cpp.h << 'END-of-cpp.h'
+X
+X/*
+X *    I n t e r n a l   D e f i n i t i o n s    f o r   C P P
+X *
+X * In general, definitions in this file should not be changed.
+X */
+X
+X#ifndef       TRUE
+X#define       TRUE            1
+X#define       FALSE           0
+X#endif
+X#ifndef       EOS
+X/*
+X * This is predefined in Decus C
+X */
+X#define       EOS             '\0'            /* End of string                */
+X#endif
+X#define       EOF_CHAR        0               /* Returned by get() on eof     */
+X#define NULLST                ((char *) NULL) /* Pointer to nowhere (linted)  */
+X#define       DEF_NOARGS      (-1)            /* #define foo vs #define foo() */
+X
+X/*
+X * The following may need to change if the host system doesn't use ASCII.
+X */
+X#define       DEF_MAGIC       0x1D            /* Magic for #defines           */
+X#define       TOK_SEP         0x1E            /* Token concatenation delim.   */
+X#define COM_SEP               0x1F            /* Magic comment separator      */
+X
+X/*
+X * Note -- in Ascii, the following will map macro formals onto DEL + the
+X * C1 control character region (decimal 128 .. (128 + PAR_MAC)) which will
+X * be ok as long as PAR_MAC is less than 33).  Note that the last PAR_MAC
+X * value is reserved for string substitution.
+X */
+X
+X#define       MAC_PARM        0x7F            /* Macro formals start here     */
+X#if PAR_MAC >= 33
+X      assertion fails -- PAR_MAC isn't less than 33
+X#endif
+X#define       LASTPARM        (PAR_MAC - 1)
+X
+X/*
+X * Character type codes.
+X */
+X
+X#define       INV             0               /* Invalid, must be zero        */
+X#define       OP_EOE          INV             /* End of expression            */
+X#define       DIG             1               /* Digit                        */
+X#define       LET             2               /* Identifier start             */
+X#define       FIRST_BINOP     OP_ADD
+X#define       OP_ADD          3
+X#define       OP_SUB          4
+X#define       OP_MUL          5
+X#define       OP_DIV          6
+X#define       OP_MOD          7
+X#define       OP_ASL          8
+X#define       OP_ASR          9
+X#define       OP_AND          10              /* &, not &&                    */
+X#define       OP_OR           11              /* |, not ||                    */
+X#define       OP_XOR          12
+X#define       OP_EQ           13
+X#define       OP_NE           14
+X#define       OP_LT           15
+X#define       OP_LE           16
+X#define       OP_GE           17
+X#define       OP_GT           18
+X#define       OP_ANA          19              /* &&                           */
+X#define       OP_ORO          20              /* ||                           */
+X#define       OP_QUE          21              /* ?                            */
+X#define       OP_COL          22              /* :                            */
+X#define       OP_CMA          23              /* , (relevant?)                */
+X#define       LAST_BINOP      OP_CMA          /* Last binary operand          */
+X/*
+X * The following are unary.
+X */
+X#define       FIRST_UNOP      OP_PLU          /* First Unary operand          */
+X#define       OP_PLU          24              /* + (draft ANSI standard)      */
+X#define       OP_NEG          25              /* -                            */
+X#define       OP_COM          26              /* ~                            */
+X#define       OP_NOT          27              /* !                            */
+X#define       LAST_UNOP       OP_NOT
+X#define       OP_LPA          28              /* (                            */
+X#define       OP_RPA          29              /* )                            */
+X#define       OP_END          30              /* End of expression marker     */
+X#define       OP_MAX          (OP_END + 1)    /* Number of operators          */
+X#define       OP_FAIL         (OP_END + 1)    /* For error returns            */
+X
+X/*
+X * The following are for lexical scanning only.
+X */
+X
+X#define       QUO             65              /* Both flavors of quotation    */
+X#define       DOT             66              /* . might start a number       */
+X#define       SPA             67              /* Space and tab                */
+X#define       BSH             68              /* Just a backslash             */
+X#define       END             69              /* EOF                          */
+X
+X/*
+X * These bits are set in ifstack[]
+X */
+X#define       WAS_COMPILING   1               /* TRUE if compile set at entry */
+X#define       ELSE_SEEN       2               /* TRUE when #else processed    */
+X#define       TRUE_SEEN       4               /* TRUE when #if TRUE processed */
+X
+X/*
+X * Define bits for the basic types and their adjectives
+X */
+X
+X#define       T_CHAR            1
+X#define       T_INT             2
+X#define       T_FLOAT           4
+X#define       T_DOUBLE          8
+X#define       T_SHORT          16
+X#define       T_LONG           32
+X#define       T_SIGNED         64
+X#define       T_UNSIGNED      128
+X#define       T_PTR           256             /* Pointer                      */
+X#define       T_FPTR          512             /* Pointer to functions         */
+X\f
+X/*
+X * The DEFBUF structure stores information about #defined
+X * macros.  Note that the defbuf->repl information is always
+X * in malloc storage.
+X */
+X
+Xtypedef struct defbuf {
+X      struct defbuf   *link;          /* Next define in chain */
+X      char            *repl;          /* -> replacement       */
+X      int             hash;           /* Symbol table hash    */
+X      int             nargs;          /* For define(args)     */
+X      char            name[1];        /* #define name         */
+X} DEFBUF;
+X
+X/*
+X * The FILEINFO structure stores information about open files
+X * and macros being expanded.
+X */
+X
+Xtypedef struct fileinfo {
+X      char            *bptr;          /* Buffer pointer       */
+X      int             line;           /* for include or macro */
+X      FILE            *fp;            /* File if non-null     */
+X      struct fileinfo *parent;        /* Link to includer     */
+X      char            *filename;      /* File/macro name      */
+X      char            *progname;      /* From #line statement */
+X      unsigned int    unrecur;        /* For macro recursion  */
+X      char            buffer[1];      /* current input line   */
+X} FILEINFO;
+X
+X/*
+X * The SIZES structure is used to store the values for #if sizeof
+X */
+X
+Xtypedef struct sizes {
+X    short     bits;                   /* If this bit is set,          */
+X    short     size;                   /* this is the datum size value */
+X    short     psize;                  /* this is the pointer size     */
+X} SIZES;
+X/*
+X * nomacarg is a built-in #define on Decus C.
+X */
+X
+X#ifdef        nomacarg
+X#define       cput            output          /* cput concatenates tokens     */
+X#else
+X#if COMMENT_INVISIBLE
+X#define       cput(c)         { if (c != TOK_SEP && c != COM_SEP) putchar(c); }
+X#else
+X#define       cput(c)         { if (c != TOK_SEP) putchar(c); }
+X#endif
+X#endif
+X
+X#ifndef       nomacarg
+X#define       streq(s1, s2)   (strcmp(s1, s2) == 0)
+X#endif
+X
+X/*
+X * Error codes.  VMS uses system definitions.
+X * Decus C codes are defined in stdio.h.
+X * Others are cooked to order.
+X */
+X
+X#if HOST == SYS_VMS
+X#include              <ssdef.h>
+X#include              <stsdef.h>
+X#define       IO_NORMAL       (SS$_NORMAL | STS$M_INHIB_MSG)
+X#define       IO_ERROR        SS$_ABORT
+X#endif
+X/*
+X * Note: IO_NORMAL and IO_ERROR are defined in the Decus C stdio.h file
+X */
+X#ifndef       IO_NORMAL
+X#define       IO_NORMAL       0
+X#endif
+X#ifndef       IO_ERROR
+X#define       IO_ERROR        1
+X#endif
+X
+X/*
+X * Externs
+X */
+X
+Xextern int    line;                   /* Current line number          */
+Xextern int    wrongline;              /* Force #line to cc pass 1     */
+Xextern char   type[];                 /* Character classifier         */
+Xextern char   token[IDMAX + 1];       /* Current input token          */
+Xextern int    instring;               /* TRUE if scanning string      */
+Xextern int    inmacro;                /* TRUE if scanning #define     */
+Xextern int    errors;                 /* Error counter                */
+Xextern int    recursion;              /* Macro depth counter          */
+Xextern char   ifstack[BLK_NEST];      /* #if information              */
+X#define       compiling ifstack[0]
+Xextern char   *ifptr;                 /* -> current ifstack item      */
+Xextern char   *incdir[NINCLUDE];      /* -i directories               */
+Xextern char   **incend;               /* -> active end of incdir      */
+Xextern int    cflag;                  /* -C option (keep comments)    */
+Xextern int    eflag;                  /* -E option (ignore errors)    */
+Xextern int    nflag;                  /* -N option (no pre-defines)   */
+Xextern int    rec_recover;            /* unwind recursive macros      */
+Xextern char   *preset[];              /* Standard predefined symbols  */
+Xextern char   *magic[];               /* Magic predefined symbols     */
+Xextern FILEINFO       *infile;                /* Current input file           */
+Xextern char   work[NWORK + 1];        /* #define scratch              */
+Xextern char   *workp;                 /* Free space in work           */
+X#if   DEBUG
+Xextern int    debug;                  /* Debug level                  */
+X#endif
+Xextern int    keepcomments;           /* Don't remove comments if set */
+Xextern SIZES  size_table[];           /* For #if sizeof sizes         */
+Xextern char   *getmem();              /* Get memory or die.           */
+Xextern DEFBUF *lookid();              /* Look for a #define'd thing   */
+Xextern DEFBUF *defendel();            /* Symbol table enter/delete    */
+Xextern char   *savestring();          /* Stuff string in malloc mem.  */
+Xextern char   *strcpy();
+Xextern char   *strcat();
+Xextern char   *strrchr();
+Xextern char   *strchr();
+Xextern long   time();
+X/* extern char        *sprintf();             /* Lint needs this              */
+END-of-cpp.h
+echo x - cppdef.h
+sed 's/^X//' >cppdef.h << 'END-of-cppdef.h'
+X/*
+X *               S y s t e m   D e p e n d e n t
+X *            D e f i n i t i o n s    f o r   C P P
+X *
+X * Definitions in this file may be edited to configure CPP for particular
+X * host operating systems and target configurations.
+X *
+X * NOTE: cpp assumes it is compiled by a compiler that supports macros
+X * with arguments.  If this is not the case (as for Decus C), #define
+X * nomacarg -- and provide function equivalents for all macros.
+X *
+X * cpp also assumes the host and target implement the Ascii character set.
+X * If this is not the case, you will have to do some editing here and there.
+X */
+X
+X/*
+X * This redundant definition of TRUE and FALSE works around
+X * a limitation of Decus C.
+X */
+X#ifndef       TRUE
+X#define       TRUE                    1
+X#define       FALSE                   0
+X#endif
+X
+X/*
+X * Define the HOST operating system.  This is needed so that
+X * cpp can use appropriate filename conventions.
+X */
+X#define       SYS_UNKNOWN             0
+X#define       SYS_UNIX                1
+X#define       SYS_VMS                 2
+X#define       SYS_RSX                 3
+X#define       SYS_RT11                4
+X#define       SYS_LATTICE             5
+X#define       SYS_ONYX                6
+X#define       SYS_68000               7
+X#define SYS_GCOS              8
+X#define SYS_IBM                       9
+X#define SYS_OS                        10
+X#define SYS_TSS                       11
+X
+X#ifndef       HOST
+X#ifdef        unix
+X#define       HOST                    SYS_UNIX
+X#else
+X#ifdef        vms
+X#define       HOST                    SYS_VMS
+X#else
+X#ifdef        rsx
+X#define       HOST                    SYS_RSX
+X#else
+X#ifdef        rt11
+X#define       HOST                    SYS_RT11
+X#else
+X#ifdef dmert
+X#define HOST                  SYS_DMERT
+X#else
+X#ifdef gcos
+X#define HOST                  SYS_GCOS
+X#else
+X#ifdef ibm
+X#define HOST                  SYS_IBM
+X#else
+X#ifdef os
+X#define HOST                  SYS_OS
+X#else
+X#ifdef tss                    
+X#define HOST                  SYS_TSS
+X#endif
+X#endif
+X#endif
+X#endif
+X#endif
+X#endif
+X#endif
+X#endif
+X#endif
+X
+X#ifndef       HOST
+X#define       HOST                    SYS_UNKNOWN
+X#endif
+X
+X/*
+X * We assume that the target is the same as the host system
+X */
+X#ifndef       TARGET
+X#define       TARGET                  HOST
+X#endif
+X
+X/*
+X * In order to predefine machine-dependent constants,
+X * several strings are defined here:
+X *
+X * MACHINE    defines the target cpu (by name)
+X * SYSTEM     defines the target operating system
+X * COMPILER   defines the target compiler
+X *
+X *    The above may be #defined as "" if they are not wanted.
+X *    They should not be #defined as NULL.
+X *
+X * LINE_PREFIX        defines the # output line prefix, if not "line"
+X *            This should be defined as "" if cpp is to replace
+X *            the "standard" C pre-processor.
+X *
+X * FILE_LOCAL marks functions which are referenced only in the
+X *            file they reside.  Some C compilers allow these
+X *            to be marked "static" even though they are referenced
+X *            by "extern" statements elsewhere.
+X *
+X * OK_DOLLAR  Should be set TRUE if $ is a valid alphabetic character
+X *            in identifiers (default), or zero if $ is invalid.
+X *            Default is TRUE.
+X *
+X * OK_CONCAT  Should be set TRUE if # may be used to concatenate
+X *            tokens in macros (per the Ansi Draft Standard) or
+X *            FALSE for old-style # processing (needed if cpp is
+X *            to process assembler source code).
+X *
+X * OK_DATE    Predefines the compilation date if set TRUE.
+X *            Not permitted by the Nov. 12, 1984 Draft Standard.
+X *
+X * S_CHAR etc.        Define the sizeof the basic TARGET machine word types.
+X *            By default, sizes are set to the values for the HOST
+X *            computer.  If this is inappropriate, see the code in
+X *            cpp3.c for details on what to change.  Also, if you
+X *            have a machine where sizeof (signed int) differs from
+X *            sizeof (unsigned int), you will have to edit code and
+X *            tables in cpp3.c (and extend the -S option definition.)
+X *
+X * CPP_LIBRARY        May be defined if you have a site-specific include directory
+X *            which is to be searched *before* the operating-system
+X *            specific directories.
+X */
+X
+X#if TARGET == SYS_LATTICE
+X/*
+X * We assume the operating system is pcdos for the IBM-PC.
+X * We also assume the small model (just like the PDP-11)
+X */
+X#define MACHINE                       "i8086"
+X#define       SYSTEM                  "pcdos"
+X#endif
+X
+X#if TARGET == SYS_ONYX
+X#define       MACHINE                 "z8000"
+X#define       SYSTEM                  "unix"
+X#endif
+X
+X#if TARGET == SYS_VMS
+X#define       MACHINE                 "vax"
+X#define       SYSTEM                  "vms"
+X#define       COMPILER                "vax11c"
+X#endif
+X
+X#if TARGET == SYS_RSX
+X#define       MACHINE                 "pdp11"
+X#define       SYSTEM                  "rsx"
+X#define       COMPILER                "decus"
+X#endif
+X
+X#if TARGET == SYS_RT11
+X#define       MACHINE                 "pdp11"
+X#define       SYSTEM                  "rt11"
+X#define       COMPILER                "decus"
+X#endif
+X
+X#if TARGET == SYS_68000
+X/*
+X * All three machine designators have been seen in various systems.
+X * Warning -- compilers differ as to sizeof (int).  cpp3 assumes that
+X * sizeof (int) == 2
+X */
+X#define       MACHINE                 "M68000", "m68000", "m68k"
+X#define       SYSTEM                  "unix"
+X#endif
+X
+X#if   TARGET == SYS_UNIX
+X#define       SYSTEM                  "unix"
+X#ifdef        pdp11
+X#define       MACHINE                 "pdp11"
+X#endif
+X#ifdef        vax
+X#define       MACHINE                 "vax"
+X#endif
+X#ifdef u370
+X#define MACHINE                       "u370"
+X#endif
+X#ifdef interdata
+X#define MACHINE                       "interdata"
+X#endif
+X#ifdef u3b
+X#define MACHINE                       "u3b"
+X#endif
+X#ifdef u3b5   
+X#define MACHINE                       "u3b5"
+X#endif
+X#ifdef u3b2
+X#define MACHINE                       "u3b2"
+X#endif
+X#ifdef u3b20d
+X#define MACHINE                       "u3b20d"
+X#endif
+X#endif
+X#endif
+X
+X/*
+X * defaults
+X */
+X
+X#ifndef MSG_PREFIX
+X#define MSG_PREFIX            "cpp: "
+X#endif
+X
+X#ifndef LINE_PREFIX
+X#ifdef        decus
+X#define       LINE_PREFIX             ""
+X#else
+X#define LINE_PREFIX           "line"
+X#endif
+X#endif
+X\f
+X/*
+X * OLD_PREPROCESSOR forces the definition of OK_DOLLAR, OK_CONCAT,
+X * COMMENT_INVISIBLE, and STRING_FORMAL to values appropriate for
+X * an old-style preprocessor.
+X */
+X 
+X#ifndef       OLD_PREPROCESSOR
+X#define       OLD_PREPROCESSOR        FALSE
+X#endif
+X
+X#if   OLD_PREPROCESSOR
+X#define       OK_DOLLAR               FALSE
+X#define       OK_CONCAT               FALSE
+X#define       COMMENT_INVISIBLE       TRUE
+X#define       STRING_FORMAL           TRUE
+X#endif
+X
+X/*
+X * RECURSION_LIMIT may be set to -1 to disable the macro recursion test.
+X */
+X#ifndef       RECURSION_LIMIT
+X#define       RECURSION_LIMIT 1000
+X#endif
+X
+X/*
+X * BITS_CHAR may be defined to set the number of bits per character.
+X * it is needed only for multi-byte character constants.
+X */
+X#ifndef       BITS_CHAR
+X#define       BITS_CHAR               8
+X#endif
+X
+X/*
+X * BIG_ENDIAN is set TRUE on machines (such as the IBM 360 series)
+X * where 'ab' stores 'a' in the high-bits and 'b' in the low-bits.
+X * It is set FALSE on machines (such as the PDP-11 and Vax-11)
+X * where 'ab' stores 'a' in the low-bits and 'b' in the high-bits.
+X * (Or is it the other way around?) -- Warning: BIG_ENDIAN code is untested.
+X */
+X#ifndef       BIG_ENDIAN
+X#define       BIG_ENDIAN              FALSE
+X#endif
+X
+X/*
+X * COMMENT_INVISIBLE may be defined to allow "old-style" comment
+X * processing, whereby the comment becomes a zero-length token
+X * delimiter.  This permitted tokens to be concatenated in macro
+X * expansions.  This was removed from the Draft Ansi Standard.
+X */
+X#ifndef       COMMENT_INVISIBLE
+X#define       COMMENT_INVISIBLE       FALSE
+X#endif
+X
+X/*
+X * STRING_FORMAL may be defined to allow recognition of macro parameters
+X * anywhere in replacement strings.  This was removed from the Draft Ansi
+X * Standard and a limited recognition capability added.
+X */
+X#ifndef       STRING_FORMAL
+X#define       STRING_FORMAL           FALSE
+X#endif
+X
+X/*
+X * OK_DOLLAR enables use of $ as a valid "letter" in identifiers.
+X * This is a permitted extension to the Ansi Standard and is required
+X * for e.g., VMS, RSX-11M, etc.   It should be set FALSE if cpp is
+X * used to preprocess assembler source on Unix systems.  OLD_PREPROCESSOR
+X * sets OK_DOLLAR FALSE for that reason.
+X */
+X#ifndef       OK_DOLLAR
+X#define       OK_DOLLAR               TRUE
+X#endif
+X
+X/*
+X * OK_CONCAT enables (one possible implementation of) token concatenation.
+X * If cpp is used to preprocess Unix assembler source, this should be
+X * set FALSE as the concatenation character, #, is used by the assembler.
+X */
+X#ifndef       OK_CONCAT
+X#define       OK_CONCAT               TRUE
+X#endif
+X
+X/*
+X * OK_DATE may be enabled to predefine today's date as a string
+X * at the start of each compilation.  This is apparently not permitted
+X * by the Draft Ansi Standard.
+X */
+X#ifndef       OK_DATE
+X#define       OK_DATE         TRUE
+X#endif
+X\f
+X/*
+X * Some common definitions.
+X */
+X
+X#ifndef       DEBUG
+X#define       DEBUG                   FALSE
+X#endif
+X
+X/*
+X * The following definitions are used to allocate memory for
+X * work buffers.  In general, they should not be modified
+X * by implementors.
+X *
+X * PAR_MAC    The maximum number of #define parameters (31 per Standard)
+X *            Note: we need another one for strings.
+X * IDMAX      The longest identifier, 31 per Ansi Standard
+X * NBUFF      Input buffer size
+X * NWORK      Work buffer size -- the longest macro
+X *            must fit here after expansion.
+X * NEXP               The nesting depth of #if expressions
+X * NINCLUDE   The number of directories that may be specified
+X *            on a per-system basis, or by the -I option.
+X * BLK_NEST   The number of nested #if's permitted.
+X */
+X
+X#define       IDMAX                    31
+X#define       PAR_MAC            (31 + 1)
+X#define       NBUFF                  1024
+X#define       NWORK                  1024
+X#define       NEXP                    128
+X#define       NINCLUDE                  7
+X#define       NPARMWORK               (NWORK * 2)
+X#define       BLK_NEST                32
+X
+X/*
+X * Some special constants.  These may need to be changed if cpp
+X * is ported to a wierd machine.
+X *
+X * NOTE: if cpp is run on a non-ascii machine, ALERT and VT may
+X * need to be changed.  They are used to implement the proposed
+X * ANSI standard C control characters '\a' and '\v' only.
+X * DEL is used to tag macro tokens to prevent #define foo foo
+X * from looping.  Note that we don't try to prevent more elaborate
+X * #define loops from occurring.
+X */
+X
+X#ifndef       ALERT
+X#define       ALERT                   '\007'          /* '\a' is "Bell"       */
+X#endif
+X
+X#ifndef       VT
+X#define       VT                      '\013'          /* Vertical Tab CTRL/K  */
+X#endif
+X
+X
+X#ifndef       FILE_LOCAL
+X#ifdef        decus
+X#define       FILE_LOCAL              static
+X#else
+X#ifdef        vax11c
+X#define       FILE_LOCAL              static
+X#else
+X#define       FILE_LOCAL                              /* Others are global    */
+X#endif
+X#endif
+X#endif
+X
+END-of-cppdef.h
+echo x - cpp2.c
+sed 's/^X//' >cpp2.c << 'END-of-cpp2.c'
+X/*
+X *                            C P P 2 . C
+X *
+X *                       Process #control lines
+X *
+X * Edit history
+X * 13-Nov-84  MM      Split from cpp1.c
+X */
+X
+X#include      <stdio.h>
+X#include      <ctype.h>
+X#include      "cppdef.h"
+X#include      "cpp.h"
+X#if HOST == SYS_VMS
+X/*
+X * Include the rms stuff.  (We can't just include rms.h as it uses the
+X * VaxC-specific library include syntax that Decus CPP doesn't support.
+X * By including things by hand, we can CPP ourself.)
+X */
+X#include      <nam.h>
+X#include      <fab.h>
+X#include      <rab.h>
+X#include      <rmsdef.h>
+X#endif
+X
+X/*
+X * Generate (by hand-inspection) a set of unique values for each control
+X * operator.  Note that this is not guaranteed to work for non-Ascii
+X * machines.  CPP won't compile if there are hash conflicts.
+X */
+X
+X#define       L_assert        ('a' + ('s' << 1))
+X#define       L_define        ('d' + ('f' << 1))
+X#define       L_elif          ('e' + ('i' << 1))
+X#define       L_else          ('e' + ('s' << 1))
+X#define       L_endif         ('e' + ('d' << 1))
+X#define L_ident               ('i' + ('e' << 1))
+X#define       L_if            ('i' + (EOS << 1))
+X#define       L_ifdef         ('i' + ('d' << 1))
+X#define       L_ifndef        ('i' + ('n' << 1))
+X#define       L_include       ('i' + ('c' << 1))
+X#define       L_line          ('l' + ('n' << 1))
+X#define       L_nogood        (EOS + (EOS << 1))      /* To catch #i          */
+X#define       L_pragma        ('p' + ('a' << 1))
+X#define       L_sccs          ('s' + ('c' << 1))
+X#define L_undef               ('u' + ('d' << 1))
+X#if DEBUG
+X#define       L_debug         ('d' + ('b' << 1))      /* #debug               */
+X#define       L_nodebug       ('n' + ('d' << 1))      /* #nodebug             */
+X#endif
+X
+Xint
+Xcontrol(counter)
+Xint           counter;        /* Pending newline counter              */
+X/*
+X * Process #control lines.  Simple commands are processed inline,
+X * while complex commands have their own subroutines.
+X *
+X * The counter is used to force out a newline before #line, and
+X * #pragma commands.  This prevents these commands from ending up at
+X * the end of the previous line if cpp is invoked with the -C option.
+X */
+X{
+X      register int            c;
+X      register char           *tp;
+X      register int            hash;
+X      char                    *ep;
+X
+X      c = skipws();
+X      if (c == '\n' || c == EOF_CHAR)
+X          return (counter + 1);
+X      if (!isdigit(c))
+X          scanid(c);                  /* Get #word to token[]         */
+X      else {
+X          unget();                    /* Hack -- allow #123 as a      */
+X          strcpy(token, "line");      /* synonym for #line 123        */
+X      }
+X      hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[2] << 1));
+X      switch (hash) {
+X      case L_assert:  tp = "assert";          break;
+X      case L_define:  tp = "define";          break;
+X      case L_elif:    tp = "elif";            break;
+X      case L_else:    tp = "else";            break;
+X      case L_endif:   tp = "endif";           break;
+X      case L_ident:   tp = "ident";           break;
+X      case L_if:      tp = "if";              break;
+X      case L_ifdef:   tp = "ifdef";           break;
+X      case L_ifndef:  tp = "ifndef";          break;
+X      case L_include: tp = "include";         break;
+X      case L_line:    tp = "line";            break;
+X      case L_pragma:  tp = "pragma";          break;
+X      case L_sccs:    tp = "sccs";            break;
+X      case L_undef:   tp = "undef";           break;
+X#if DEBUG
+X      case L_debug:   tp = "debug";           break;
+X      case L_nodebug: tp = "nodebug";         break;
+X#endif
+X      default:        hash = L_nogood;
+X      case L_nogood:  tp = "";                break;
+X      }
+X      if (!streq(tp, token))
+X          hash = L_nogood;
+X      /*
+X       * hash is set to a unique value corresponding to the
+X       * control keyword (or L_nogood if we think it's nonsense).
+X       */
+X      if (infile->fp == NULL)
+X          cwarn("Control line \"%s\" within macro expansion", token);
+X      if (!compiling) {                       /* Not compiling now    */
+X          switch (hash) {
+X          case L_if:                          /* These can't turn     */
+X          case L_ifdef:                       /*  compilation on, but */
+X          case L_ifndef:                      /*   we must nest #if's */
+X              if (++ifptr >= &ifstack[BLK_NEST])
+X                  goto if_nest_err;
+X              *ifptr = 0;                     /* !WAS_COMPILING       */
+X          case L_line:                        /* Many                 */
+X          /*
+X           * Are pragma's always processed?
+X           */
+X          case L_ident:
+X          case L_sccs:
+X          case L_pragma:                      /*  options             */
+X          case L_include:                     /*   are uninteresting  */
+X          case L_define:                      /*    if we             */
+X          case L_undef:                       /*     aren't           */
+X          case L_assert:                      /*      compiling.      */
+Xdump_line:    skipnl();                       /* Ignore rest of line  */
+X              return (counter + 1);
+X          }
+X      }
+X      /*
+X       * Make sure that #line and #pragma are output on a fresh line.
+X       */
+X      if (counter > 0 && (hash == L_line || hash == L_pragma)) {
+X          putchar('\n');
+X          counter--;
+X      }
+X      switch (hash) {
+X      case L_line:
+X          /*
+X           * Parse the line to update the line number and "progname"
+X           * field and line number for the next input line.
+X           * Set wrongline to force it out later.
+X           */
+X          c = skipws();
+X          workp = work;                       /* Save name in work    */
+X          while (c != '\n' && c != EOF_CHAR) {
+X              save(c);
+X              c = get();
+X          }
+X          unget();
+X          save(EOS);
+X          /*
+X           * Split #line argument into <line-number> and <name>
+X           * We subtract 1 as we want the number of the next line.
+X           */
+X          line = atoi(work) - 1;              /* Reset line number    */
+X          for (tp = work; isdigit(*tp) || type[*tp] == SPA; tp++)
+X              ;                               /* Skip over digits     */
+X          if (*tp != EOS) {                   /* Got a filename, so:  */
+X              if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
+X                  tp++;                       /* Skip over left quote */
+X                  *ep = EOS;                  /* And ignore right one */
+X              }
+X              if (infile->progname != NULL)   /* Give up the old name */
+X                  free(infile->progname);     /* if it's allocated.   */
+X              infile->progname = savestring(tp);
+X          }
+X          wrongline = TRUE;                   /* Force output later   */
+X          break;
+X
+X      case L_include:
+X          doinclude();
+X          break;
+X
+X      case L_define:
+X          dodefine();
+X          break;
+X
+X      case L_undef:
+X          doundef();
+X          break;
+X
+X      case L_else:
+X          if (ifptr == &ifstack[0])
+X              goto nest_err;
+X          else if ((*ifptr & ELSE_SEEN) != 0)
+X              goto else_seen_err;
+X          *ifptr |= ELSE_SEEN;
+X          if ((*ifptr & WAS_COMPILING) != 0) {
+X              if (compiling || (*ifptr & TRUE_SEEN) != 0)
+X                  compiling = FALSE;
+X              else {
+X                  compiling = TRUE;
+X              }
+X          }
+X          break;
+X
+X      case L_elif:
+X          if (ifptr == &ifstack[0])
+X              goto nest_err;
+X          else if ((*ifptr & ELSE_SEEN) != 0) {
+Xelse_seen_err:        cerror("#%s may not follow #else", token);
+X              goto dump_line;
+X          }
+X          if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
+X              compiling = FALSE;              /* Done compiling stuff */
+X              goto dump_line;                 /* Skip this clause     */
+X          }
+X          doif(L_if);
+X          break;
+X
+X      case L_if:
+X      case L_ifdef:
+X      case L_ifndef:
+X          if (++ifptr >= &ifstack[BLK_NEST])
+Xif_nest_err:  cfatal("Too many nested #%s statements", token);
+X          *ifptr = WAS_COMPILING;
+X          doif(hash);
+X          break;
+X
+X      case L_endif:
+X          if (ifptr == &ifstack[0]) {
+Xnest_err:     cerror("#%s must be in an #if", token);
+X              goto dump_line;
+X          }
+X          if (!compiling && (*ifptr & WAS_COMPILING) != 0)
+X              wrongline = TRUE;
+X          compiling = ((*ifptr & WAS_COMPILING) != 0);
+X          --ifptr;
+X          break;
+X
+X      case L_assert:
+X          if (eval() == 0)
+X              cerror("Preprocessor assertion failure", NULLST);
+X          break;
+X
+X      case L_ident:
+X      case L_sccs:
+X          goto dump_line;
+X          break;
+X
+X      case L_pragma:
+X          /*
+X           * #pragma is provided to pass "options" to later
+X           * passes of the compiler.  cpp doesn't have any yet.
+X           */
+X          printf("#pragma ");
+X          while ((c = get()) != '\n' && c != EOF_CHAR)
+X              cput(c);
+X          unget();
+X          break;
+X 
+X#if DEBUG
+X      case L_debug:
+X          if (debug == 0)
+X              dumpdef("debug set on");
+X          debug++;
+X          break;
+X
+X      case L_nodebug:
+X          debug--;
+X          break;
+X#endif
+X
+X      default:
+X          /*
+X           * Undefined #control keyword.
+X           * Note: the correct behavior may be to warn and
+X           * pass the line to a subsequent compiler pass.
+X           * This would allow #asm or similar extensions.
+X           */
+X          cerror("Illegal # command \"%s\"", token);
+X          break;
+X      }
+X      if (hash != L_include) {
+X#if OLD_PREPROCESSOR || !VERBOSE
+X          /*
+X           * Ignore the rest of the #control line so you can write
+X           *          #if     foo
+X           *          #endif  foo
+X           */
+X          goto dump_line;                     /* Take common exit     */
+X#else
+X          if (skipws() != '\n') {
+X              cwarn("Unexpected text in #control line ignored", NULLST);
+X              skipnl();
+X          }
+X#endif
+X      }
+X      return (counter + 1);
+X}
+X\f
+XFILE_LOCAL
+Xdoif(hash)
+Xint           hash;
+X/*
+X * Process an #if, #ifdef, or #ifndef.  The latter two are straightforward,
+X * while #if needs a subroutine of its own to evaluate the expression.
+X *
+X * doif() is called only if compiling is TRUE.  If false, compilation
+X * is always supressed, so we don't need to evaluate anything.  This
+X * supresses unnecessary warnings.
+X */
+X{
+X      register int            c;
+X      register int            found;
+X
+X      if ((c = skipws()) == '\n' || c == EOF_CHAR) {
+X          unget();
+X          goto badif;
+X      }
+X      if (hash == L_if) {
+X          unget();
+X          found = (eval() != 0);      /* Evaluate expr, != 0 is  TRUE */
+X          hash = L_ifdef;             /* #if is now like #ifdef       */
+X      }
+X      else {
+X          if (type[c] != LET)         /* Next non-blank isn't letter  */
+X              goto badif;             /* ... is an error              */
+X          found = (lookid(c) != NULL); /* Look for it in symbol table */
+X      }
+X      if (found == (hash == L_ifdef)) {
+X          compiling = TRUE;
+X          *ifptr |= TRUE_SEEN;
+X      }
+X      else {
+X          compiling = FALSE;
+X      }
+X      return;
+X
+Xbadif:        cerror("#if, #ifdef, or #ifndef without an argument", NULLST);
+X#if !OLD_PREPROCESSOR
+X      skipnl();                               /* Prevent an extra     */
+X      unget();                                /* Error message        */
+X#endif
+X      return;
+X}
+X\f
+XFILE_LOCAL
+Xdoinclude()
+X/*
+X * Process the #include control line.
+X * There are three variations:
+X *    #include "file"         search somewhere relative to the
+X *                            current source file, if not found,
+X *                            treat as #include <file>.
+X *    #include <file>         Search in an implementation-dependent
+X *                            list of places.
+X *    #include token          Expand the token, it must be one of
+X *                            "file" or <file>, process as such.
+X *
+X * Note: the November 12 draft forbids '>' in the #include <file> format.
+X * This restriction is unnecessary and not implemented.
+X */
+X{
+X      register int            c;
+X      register int            delim;
+X#if HOST == SYS_VMS
+X      char                    def_filename[NAM$C_MAXRSS + 1];
+X#endif
+X
+X      delim = macroid(skipws());
+X      if (delim != '<' && delim != '"')
+X          goto incerr;
+X      if (delim == '<')
+X          delim = '>';
+X      workp = work;
+X      instring = TRUE;                /* Accept all characters        */
+X      while ((c = get()) != '\n' && c != delim && c != EOF_CHAR)
+X          save(c);                    /* Put it away.                 */
+X      skipnl(); 
+X      /*
+X       * The draft is unclear if the following should be done.
+X       */
+X
+X      while (--workp >= work && (type[*workp] == SPA))
+X          ;                           /* Trim blanks from filename    */
+X
+X/*
+X *    if (*workp != delim)
+X *        goto incerr; 
+X */
+X      *(workp + 1) = EOS;                     /* Terminate filename   */
+X      instring = FALSE;
+X#if HOST == SYS_VMS
+X      /*
+X       * Assume the default .h filetype.
+X       */
+X      if (!vmsparse(work, ".H", def_filename)) {
+X          perror(work);               /* Oops.                        */
+X          goto incerr;
+X      }
+X      else if (openinclude(def_filename, (delim == '"')))
+X          return;
+X#else
+X      if (openinclude(work, (delim == '"')))
+X          return;
+X#endif
+X      /*
+X       * No sense continuing if #include file isn't there.
+X       */
+X      cfatal("Cannot open include file \"%s\"", work);
+X
+Xincerr:       cerror("#include syntax error", NULLST);
+X      return;
+X}
+X\f
+XFILE_LOCAL int
+Xopeninclude(filename, searchlocal)
+Xchar          *filename;              /* Input file name              */
+Xint           searchlocal;            /* TRUE if #include "file"      */
+X/*
+X * Actually open an include file.  This routine is only called from
+X * doinclude() above, but was written as a separate subroutine for
+X * programmer convenience.  It searches the list of directories
+X * and actually opens the file, linking it into the list of
+X * active files.  Returns TRUE if the file was opened, FALSE
+X * if openinclude() fails.  No error message is printed.
+X */
+X{
+X      register char           **incptr;
+X#if HOST == SYS_VMS
+X#if NWORK < (NAM$C_MAXRSS + 1)
+X    << error, NWORK isn't greater than NAM$C_MAXRSS >>
+X#endif
+X#endif
+X      char                    tmpname[NWORK]; /* Filename work area   */
+X
+X      if (searchlocal) {
+X          /*
+X           * Look in local directory first
+X           */
+X#if HOST == SYS_UNIX
+X          /*
+X           * Try to open filename relative to the directory of the current
+X           * source file (as opposed to the current directory). (ARF, SCK).
+X           */
+X          if (filename[0] != '/'
+X           && hasdirectory(infile->filename, tmpname))
+X              strcat(tmpname, filename);
+X          else {
+X              strcpy(tmpname, filename);
+X          }
+X#else
+X          if (!hasdirectory(filename, tmpname)
+X           && hasdirectory(infile->filename, tmpname))
+X              strcat(tmpname, filename);
+X          else {
+X              strcpy(tmpname, filename);
+X          }
+X#endif
+X          if (openfile(tmpname))
+X              return (TRUE);
+X      }
+X      /*
+X       * Look in any directories specified by -I command line
+X       * arguments, then in the builtin search list.
+X       */
+X      for (incptr = incdir; incptr < incend; incptr++) {
+X          if (strlen(*incptr) + strlen(filename) >= (NWORK - 1))
+X              cfatal("Filename work buffer overflow", NULLST);
+X          else {
+X#if HOST == SYS_UNIX
+X              if (filename[0] == '/')
+X                  strcpy(tmpname, filename);
+X              else {
+X                  sprintf(tmpname, "%s/%s", *incptr, filename);
+X              }
+X#else
+X              if (!hasdirectory(filename, tmpname))
+X                  sprintf(tmpname, "%s%s", *incptr, filename);
+X#endif
+X              if (openfile(tmpname))
+X                  return (TRUE);
+X          }
+X      }
+X      return (FALSE);
+X}
+X\f
+XFILE_LOCAL int
+Xhasdirectory(source, result)
+Xchar          *source;        /* Directory to examine                 */
+Xchar          *result;        /* Put directory stuff here             */
+X/*
+X * If a device or directory is found in the source filename string, the
+X * node/device/directory part of the string is copied to result and
+X * hasdirectory returns TRUE.  Else, nothing is copied and it returns FALSE.
+X */
+X{
+X#if HOST == SYS_UNIX
+X      register char           *tp;
+X
+X      if ((tp = strrchr(source, '/')) == NULL)
+X          return (FALSE);
+X      else {
+X          strncpy(result, source, tp - source + 1);
+X          result[tp - source + 1] = EOS;
+X          return (TRUE);
+X      }
+X#else
+X#if HOST == SYS_VMS
+X      if (vmsparse(source, NULLST, result)
+X       && result[0] != EOS)
+X          return (TRUE);
+X      else {
+X          return (FALSE);
+X      }
+X#else
+X      /*
+X       * Random DEC operating system (RSX, RT11, RSTS/E)
+X       */
+X      register char           *tp;
+X
+X      if ((tp = strrchr(source, ']')) == NULL
+X       && (tp = strrchr(source, ':')) == NULL)
+X          return (FALSE);
+X      else {
+X          strncpy(result, source, tp - source + 1);
+X          result[tp - source + 1] = EOS;
+X          return (TRUE);
+X      }
+X#endif
+X#endif
+X}
+X\f
+X#if HOST == SYS_VMS
+X
+X/*
+X * EXP_DEV is set if a device was specified, EXP_DIR if a directory
+X * is specified.  (Both set indicate a file-logical, but EXP_DEV
+X * would be set by itself if you are reading, say, SYS$INPUT:)
+X */
+X#define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR)
+X
+XFILE_LOCAL int
+Xvmsparse(source, defstring, result)
+Xchar          *source;
+Xchar          *defstring;     /* non-NULL -> default string.          */
+Xchar          *result;        /* Size is at least NAM$C_MAXRSS + 1    */
+X/*
+X * Parse the source string, applying the default (properly, using
+X * the system parse routine), storing it in result.
+X * TRUE if it parsed, FALSE on error.
+X *
+X * If defstring is NULL, there are no defaults and result gets
+X * (just) the node::[directory] part of the string (possibly "")
+X */
+X{
+X      struct FAB      fab = cc$rms_fab;       /* File access block    */
+X      struct NAM      nam = cc$rms_nam;       /* File name block      */
+X      char            fullname[NAM$C_MAXRSS + 1];
+X      register char   *rp;                    /* Result pointer       */
+X
+X      fab.fab$l_nam = &nam;                   /* fab -> nam           */
+X      fab.fab$l_fna = source;                 /* Source filename      */
+X      fab.fab$b_fns = strlen(source);         /* Size of source       */
+X      fab.fab$l_dna = defstring;              /* Default string       */
+X      if (defstring != NULLST)
+X          fab.fab$b_dns = strlen(defstring);  /* Size of default      */
+X      nam.nam$l_esa = fullname;               /* Expanded filename    */
+X      nam.nam$b_ess = NAM$C_MAXRSS;           /* Expanded name size   */
+X      if (sys$parse(&fab) == RMS$_NORMAL) {   /* Parse away           */
+X          fullname[nam.nam$b_esl] = EOS;      /* Terminate string     */
+X          result[0] = EOS;                    /* Just in case         */
+X          rp = &result[0];
+X          /*
+X           * Remove stuff added implicitly, accepting node names and
+X           * dev:[directory] strings (but not process-permanent files).
+X           */
+X          if ((nam.nam$l_fnb & NAM$M_PPF) == 0) {
+X              if ((nam.nam$l_fnb & NAM$M_NODE) != 0) {
+X                  strncpy(result, nam.nam$l_node, nam.nam$b_node);
+X                  rp += nam.nam$b_node;
+X                  *rp = EOS;
+X              }
+X              if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) {
+X                  strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir);
+X                  rp += nam.nam$b_dev + nam.nam$b_dir;
+X                  *rp = EOS;
+X              }
+X          }
+X          if (defstring != NULLST) {
+X              strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type);
+X              rp += nam.nam$b_name + nam.nam$b_type;
+X              *rp = EOS;
+X              if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) {
+X                  strncpy(rp, nam.nam$l_ver, nam.nam$b_ver);
+X                  rp[nam.nam$b_ver] = EOS;
+X              }
+X          }
+X          return (TRUE);
+X      }
+X      return (FALSE);
+X}
+X#endif
+X
+END-of-cpp2.c
+exit
diff --git a/sys/unix/cpp2.shr b/sys/unix/cpp2.shr
new file mode 100644 (file)
index 0000000..ccadfc0
--- /dev/null
@@ -0,0 +1,1763 @@
+# This is a shell archive.  Save it in a file, remove anything before
+# this line, and then unpack it by entering "sh file".  Note, it may
+# create directories; files and directories will be owned by you and
+# have default permissions.
+#
+# This archive contains:
+#
+#      cpp1.c
+#      cpp3.c
+#      cpp4.c
+#
+echo x - cpp1.c
+sed 's/^X//' >cpp1.c << 'END-of-cpp1.c'
+X/*
+X * CPP main program.
+X *
+X * Edit history
+X * 21-May-84  MM      "Field test" release
+X * 23-May-84  MM      Some minor hacks.
+X * 30-May-84  ARF     Didn't get enough memory for __DATE__
+X *                    Added code to read stdin if no input
+X *                    files are provided.
+X * 29-Jun-84  MM      Added ARF's suggestions, Unixifying cpp.
+X * 11-Jul-84  MM      "Official" first release (that's what I thought!)
+X * 22-Jul-84  MM/ARF/SCK Fixed line number bugs, added cpp recognition
+X *                    of #line, fixed problems with #include.
+X * 23-Jul-84  MM      More (minor) include hacking, some documentation.
+X *                    Also, redid cpp's #include files
+X * 25-Jul-84  MM      #line filename isn't used for #include searchlist
+X *                    #line format is <number> <optional name>
+X * 25-Jul-84  ARF/MM  Various bugs, mostly serious.  Removed homemade doprint
+X * 01-Aug-84  MM      Fixed recursion bug, remove extra newlines and
+X *                    leading whitespace from cpp output.
+X * 02-Aug-84  MM      Hacked (i.e. optimized) out blank lines and unneeded
+X *                    whitespace in general.  Cleaned up unget()'s.
+X * 03-Aug-84  Keie    Several bug fixes from Ed Keizer, Vrije Universitet.
+X *                    -- corrected arg. count in -D and pre-defined
+X *                    macros.  Also, allow \n inside macro actual parameter
+X *                    lists.
+X * 06-Aug-84  MM      If debugging, dump the preset vector at startup.
+X * 12-Aug-84  MM/SCK  Some small changes from Sam Kendall
+X * 15-Aug-84  Keie/MM cerror, cwarn, etc. take a single string arg.
+X *                    cierror, etc. take a single int. arg.
+X *                    changed LINE_PREFIX slightly so it can be
+X *                    changed in the makefile.
+X * 31-Aug-84  MM      USENET net.sources release.
+X *  7-Sep-84  SCH/ado Lint complaints
+X * 10-Sep-84  Keie    Char's can't be signed in some implementations
+X * 11-Sep-84  ado     Added -C flag, pathological line number fix
+X * 13-Sep-84  ado     Added -E flag (does nothing) and "-" file for stdin.
+X * 14-Sep-84  MM      Allow # 123 as a synonym for #line 123
+X * 19-Sep-84  MM      scanid always reads to token, make sure #line is
+X *                    written to a new line, even if -C switch given.
+X *                    Also, cpp - - reads stdin, writes stdout.
+X * 03-Oct-84  ado/MM  Several changes to line counting and keepcomments
+X *                    stuff.  Also a rewritten control() hasher -- much
+X *                    simpler and no less "perfect". Note also changes
+X *                    in cpp3.c to fix numeric scanning.
+X * 04-Oct-84  MM      Added recognition of macro formal parameters if
+X *                    they are the only thing in a string, per the
+X *                    draft standard.
+X * 08-Oct-84  MM      One more attack on scannumber
+X * 15-Oct-84  MM/ado  Added -N to disable predefined symbols.  Fixed
+X *                    linecount if COMMENT_INVISIBLE enabled.
+X * 22-Oct-84  MM      Don't evaluate the #if/#ifdef argument if
+X *                    compilation is supressed.  This prevents
+X *                    unnecessary error messages in sequences such as
+X *                        #ifdef FOO          -- undefined
+X *                        #if FOO == 10       -- shouldn't print warning
+X * 25-Oct-84  MM      Fixed bug in false ifdef supression.  On vms,
+X *                    #include <foo> should open foo.h -- this duplicates
+X *                    the behavior of Vax-C
+X * 31-Oct-84  ado/MM  Parametized $ in indentifiers.  Added a better
+X *                    token concatenator and took out the trial
+X *                    concatenation code.  Also improved #ifdef code
+X *                    and cleaned up the macro recursion tester.
+X *  2-Nov-84  MM/ado  Some bug fixes in token concatenation, also
+X *                    a variety of minor (uninteresting) hacks.
+X *  6-Nov-84  MM      Happy Birthday.  Broke into 4 files and added
+X *                    #if sizeof (basic_types)
+X *  9-Nov-84  MM      Added -S* for pointer type sizes
+X * 13-Nov-84  MM      Split cpp1.c, added vms defaulting
+X * 23-Nov-84  MM/ado  -E supresses error exit, added CPP_INCLUDE,
+X *                    fixed strncpy bug.
+X *  3-Dec-84  ado/MM  Added OLD_PREPROCESSOR
+X *  7-Dec-84  MM      Stuff in Nov 12 Draft Standard
+X * 17-Dec-84  george  Fixed problems with recursive macros
+X * 17-Dec-84  MM      Yet another attack on #if's (f/t)level removed.
+X * 07-Jan-85  ado     Init defines before doing command line options
+X *                    so -Uunix works.
+X */
+X
+X/*)BUILD
+X      $(PROGRAM)      = cpp
+X      $(FILES)        = { cpp1 cpp2 cpp3 cpp4 cpp5 cpp6 }
+X      $(INCLUDE)      = { cppdef.h cpp.h }
+X      $(STACK)        = 2000
+X      $(TKBOPTIONS)   = {
+X              STACK   = 2000
+X      }
+X*/
+X
+X#ifdef        DOCUMENTATION
+X
+Xtitle cpp             C Pre-Processor
+Xindex                 C pre-processor
+X
+Xsynopsis
+X      .s.nf
+X      cpp [-options] [infile [outfile]]
+X      .s.f
+Xdescription
+X
+X      CPP reads a C source file, expands macros and include
+X      files, and writes an input file for the C compiler.
+X      If no file arguments are given, CPP reads from stdin
+X      and writes to stdout.  If one file argument is given,
+X      it will define the input file, while two file arguments
+X      define both input and output files.  The file name "-"
+X      is a synonym for stdin or stdout as appropriate.
+X
+X      The following options are supported.  Options may
+X      be given in either case.
+X      .lm +16
+X      .p -16
+X      -C              If set, source-file comments are written
+X      to the output file.  This allows the output of CPP to be
+X      used as the input to a program, such as lint, that expects
+X      commands embedded in specially-formatted comments.
+X      .p -16
+X      -Dname=value    Define the name as if the programmer wrote
+X
+X          #define name value
+X
+X      at the start of the first file.  If "=value" is not
+X      given, a value of "1" will be used.
+X
+X      On non-unix systems, all alphabetic text will be forced
+X      to upper-case.
+X      .p -16
+X      -E              Always return "success" to the operating
+X      system, even if errors were detected.  Note that some fatal
+X      errors, such as a missing #include file, will terminate
+X      CPP, returning "failure" even if the -E option is given.
+X      .p -16
+X      -Idirectory     Add this directory to the list of
+X      directories searched for #include "..." and #include <...>
+X      commands.  Note that there is no space between the
+X      "-I" and the directory string.  More than one -I command
+X      is permitted.  On non-Unix systems "directory" is forced
+X      to upper-case.
+X      .p -16
+X      -N              CPP normally predefines some symbols defining
+X      the target computer and operating system.  If -N is specified,
+X      no symbols will be predefined.  If -N -N is specified, the
+X      "always present" symbols, __LINE__, __FILE__, and __DATE__
+X      are not defined.
+X      .p -16
+X      -Stext          CPP normally assumes that the size of
+X      the target computer's basic variable types is the same as the size
+X      of these types of the host computer.  (This can be overridden
+X      when CPP is compiled, however.)  The -S option allows dynamic
+X      respecification of these values.  "text" is a string of
+X      numbers, separated by commas, that specifies correct sizes.
+X      The sizes must be specified in the exact order:
+X
+X          char short int long float double
+X
+X      If you specify the option as "-S*text", pointers to these
+X      types will be specified.  -S* takes one additional argument
+X      for pointer to function (e.g. int (*)())
+X
+X      For example, to specify sizes appropriate for a PDP-11,
+X      you would write:
+X
+X             c s i l f d func
+X           -S1,2,2,2,4,8,
+X          -S*2,2,2,2,2,2,2
+X
+X      Note that all values must be specified.
+X      .p -16
+X      -Uname          Undefine the name as if
+X
+X          #undef name
+X
+X      were given.  On non-Unix systems, "name" will be forced to
+X      upper-case.
+X      .p -16
+X      -Xnumber        Enable debugging code.  If no value is
+X      given, a value of 1 will be used.  (For maintenence of
+X      CPP only.)
+X      .s.lm -16
+X
+XPre-Defined Variables
+X
+X      When CPP begins processing, the following variables will
+X      have been defined (unless the -N option is specified):
+X      .s
+X      Target computer (as appropriate):
+X      .s
+X          pdp11, vax, M68000 m68000 m68k
+X      .s
+X      Target operating system (as appropriate):
+X      .s
+X          rsx, rt11, vms, unix
+X      .s
+X      Target compiler (as appropriate):
+X      .s
+X          decus, vax11c
+X      .s
+X      The implementor may add definitions to this list.
+X      The default definitions match the definition of the
+X      host computer, operating system, and C compiler.
+X      .s
+X      The following are always available unless undefined (or
+X      -N was specified twice):
+X      .lm +16
+X      .p -12
+X      __FILE__        The input (or #include) file being compiled
+X      (as a quoted string).
+X      .p -12
+X      __LINE__        The line number being compiled.
+X      .p -12
+X      __DATE__        The date and time of compilation as
+X      a Unix ctime quoted string (the trailing newline is removed).
+X      Thus,
+X      .s
+X          printf("Bug at line %s,", __LINE__);
+X          printf(" source file %s", __FILE__);
+X          printf(" compiled on %s", __DATE__);
+X      .s.lm -16
+X
+XDraft Proposed Ansi Standard Considerations
+X
+X      The current version of the Draft Proposed Standard
+X      explicitly states that "readers are requested not to specify
+X      or claim conformance to this draft."  Readers and users
+X      of Decus CPP should not assume that Decus CPP conforms
+X      to the standard, or that it will conform to the actual
+X      C Language Standard.
+X
+X      When CPP is itself compiled, many features of the Draft
+X      Proposed Standard that are incompatible with existing
+X      preprocessors may be disabled.  See the comments in CPP's
+X      source for details.
+X
+X      The latest version of the Draft Proposed Standard (as reflected
+X      in Decus CPP) is dated November 12, 1984.
+X
+X      Comments are removed from the input text.  The comment
+X      is replaced by a single space character.  The -C option
+X      preserves comments, writing them to the output file.
+X
+X      The '$' character is considered to be a letter.  This is
+X      a permitted extension.
+X
+X      The following new features of C are processed by CPP:
+X      .s.comment Note: significant spaces, not tabs, .br quotes #if, #elif
+X      .br;####_#elif expression    (_#else _#if)
+X      .br;####'_\xNNN'             (Hexadecimal constant)
+X      .br;####'_\a'                (Ascii BELL)
+X      .br;####'_\v'                (Ascii Vertical Tab)
+X      .br;####_#if defined NAME    1 if defined, 0 if not
+X      .br;####_#if defined (NAME)  1 if defined, 0 if not  
+X      .br;####_#if sizeof (basic type)
+X      .br;####unary +
+X      .br;####123U, 123LU          Unsigned ints and longs.
+X      .br;####12.3L                Long double numbers
+X      .br;####token_#token         Token concatenation
+X      .br;####_#include token      Expands to filename
+X
+X      The Draft Proposed Standard has extended C, adding a constant
+X      string concatenation operator, where
+X
+X          "foo" "bar"
+X
+X      is regarded as the single string "foobar".  (This does not
+X      affect CPP's processing but does permit a limited form of
+X      macro argument substitution into strings as will be discussed.)
+X
+X      The Standard Committee plans to add token concatenation
+X      to #define command lines.  One suggested implementation
+X      is as follows:  the sequence "Token1#Token2" is treated
+X      as if the programmer wrote "Token1Token2".  This could
+X      be used as follows:
+X
+X          #line 123
+X          #define ATLINE foo#__LINE__
+X
+X      ATLINE would be defined as foo123.
+X
+X      Note that "Token2" must either have the format of an
+X      identifier or be a string of digits.  Thus, the string
+X
+X          #define ATLINE foo#1x3
+X
+X      generates two tokens: "foo1" and "x3".
+X
+X      If the tokens T1 and T2 are concatenated into T3,
+X      this implementation operates as follows:
+X
+X        1. Expand T1 if it is a macro.
+X        2. Expand T2 if it is a macro.
+X        3. Join the tokens, forming T3.
+X        4. Expand T3 if it is a macro.
+X
+X      A macro formal parameter will be substituted into a string
+X      or character constant if it is the only component of that
+X      constant:
+X
+X          #define VECSIZE 123
+X          #define vprint(name, size) \
+X            printf("name" "[" "size" "] = {\n")
+X            ... vprint(vector, VECSIZE);
+X
+X      expands (effectively) to
+X
+X            vprint("vector[123] = {\n");
+X
+X      Note that this will be useful if your C compiler supports
+X      the new string concatenation operation noted above.
+X      As implemented here, if you write
+X
+X          #define string(arg) "arg"
+X            ... string("foo") ...
+X
+X      This implementation generates "foo", rather than the strictly
+X      correct ""foo"" (which will probably generate an error message).
+X      This is, strictly speaking, an error in CPP and may be removed
+X      from future releases.
+X
+Xerror messages
+X
+X      Many.  CPP prints warning or error messages if you try to
+X      use multiple-byte character constants (non-transportable)
+X      if you #undef a symbol that was not defined, or if your
+X      program has potentially nested comments.
+X
+Xauthor
+X
+X      Martin Minow
+X
+Xbugs
+X
+X      The #if expression processor uses signed integers only.
+X      I.e, #if 0xFFFFu < 0 may be TRUE.
+X
+X#endif
+X\f
+X#include      <stdio.h>
+X#include      <ctype.h>
+X#include      "cppdef.h"
+X#include      "cpp.h"
+X
+X/*
+X * Commonly used global variables:
+X * line               is the current input line number.
+X * wrongline  is set in many places when the actual output
+X *            line is out of sync with the numbering, e.g,
+X *            when expanding a macro with an embedded newline.
+X *
+X * token      holds the last identifier scanned (which might
+X *            be a candidate for macro expansion).
+X * errors     is the running cpp error counter.
+X * infile     is the head of a linked list of input files (extended by
+X *            #include and macros being expanded).  infile always points
+X *            to the current file/macro.  infile->parent to the includer,
+X *            etc.  infile->fd is NULL if this input stream is a macro.
+X */
+Xint           line;                   /* Current line number          */
+Xint           wrongline;              /* Force #line to compiler      */
+Xchar          token[IDMAX + 1];       /* Current input token          */
+Xint           errors;                 /* cpp error counter            */
+XFILEINFO      *infile = NULL;         /* Current input file           */
+X#if DEBUG
+Xint           debug;                  /* TRUE if debugging now        */
+X#endif
+X/*
+X * This counter is incremented when a macro expansion is initiated.
+X * If it exceeds a built-in value, the expansion stops -- this tests
+X * for a runaway condition:
+X *    #define X Y
+X *    #define Y X
+X *    X
+X * This can be disabled by falsifying rec_recover.  (Nothing does this
+X * currently: it is a hook for an eventual invocation flag.)
+X */
+Xint           recursion;              /* Infinite recursion counter   */
+Xint           rec_recover = TRUE;     /* Unwind recursive macros      */
+X
+X/*
+X * instring is set TRUE when a string is scanned.  It modifies the
+X * behavior of the "get next character" routine, causing all characters
+X * to be passed to the caller (except <DEF_MAGIC>).  Note especially that
+X * comments and \<newline> are not removed from the source.  (This
+X * prevents cpp output lines from being arbitrarily long).
+X *
+X * inmacro is set by #define -- it absorbs comments and converts
+X * form-feed and vertical-tab to space, but returns \<newline>
+X * to the caller.  Strictly speaking, this is a bug as \<newline>
+X * shouldn't delimit tokens, but we'll worry about that some other
+X * time -- it is more important to prevent infinitly long output lines.
+X *
+X * instring and inmarcor are parameters to the get() routine which
+X * were made global for speed.
+X */
+Xint           instring = FALSE;       /* TRUE if scanning string      */
+Xint           inmacro = FALSE;        /* TRUE if #defining a macro    */
+X
+X/*
+X * work[] and workp are used to store one piece of text in a temporay
+X * buffer.  To initialize storage, set workp = work.  To store one
+X * character, call save(c);  (This will fatally exit if there isn't
+X * room.)  To terminate the string, call save(EOS).  Note that
+X * the work buffer is used by several subroutines -- be sure your
+X * data won't be overwritten.  The extra byte in the allocation is
+X * needed for string formal replacement.
+X */
+Xchar          work[NWORK + 1];        /* Work buffer                  */
+Xchar          *workp;                 /* Work buffer pointer          */
+X
+X/*
+X * keepcomments is set TRUE by the -C option.  If TRUE, comments
+X * are written directly to the output stream.  This is needed if
+X * the output from cpp is to be passed to lint (which uses commands
+X * embedded in comments).  cflag contains the permanent state of the
+X * -C flag.  keepcomments is always falsified when processing #control
+X * commands and when compilation is supressed by a false #if
+X *
+X * If eflag is set, CPP returns "success" even if non-fatal errors
+X * were detected.
+X *
+X * If nflag is non-zero, no symbols are predefined except __LINE__.
+X * __FILE__, and __DATE__.  If nflag > 1, absolutely no symbols
+X * are predefined.
+X */
+Xint           keepcomments = FALSE;   /* Write out comments flag      */
+Xint           cflag = FALSE;          /* -C option (keep comments)    */
+Xint           eflag = FALSE;          /* -E option (never fail)       */
+Xint           nflag = 0;              /* -N option (no predefines)    */
+X
+X/*
+X * ifstack[] holds information about nested #if's.  It is always
+X * accessed via *ifptr.  The information is as follows:
+X *    WAS_COMPILING   state of compiling flag at outer level.
+X *    ELSE_SEEN       set TRUE when #else seen to prevent 2nd #else.
+X *    TRUE_SEEN       set TRUE when #if or #elif succeeds
+X * ifstack[0] holds the compiling flag.  It is TRUE if compilation
+X * is currently enabled.  Note that this must be initialized TRUE.
+X */
+Xchar          ifstack[BLK_NEST] = { TRUE };   /* #if information      */
+Xchar          *ifptr = ifstack;               /* -> current ifstack[] */
+X
+X/*
+X * incdir[] stores the -i directories (and the system-specific
+X * #include <...> directories.
+X */
+Xchar  *incdir[NINCLUDE];              /* -i directories               */
+Xchar  **incend = incdir;              /* -> free space in incdir[]    */
+X
+X/*
+X * This is the table used to predefine target machine and operating
+X * system designators.  It may need hacking for specific circumstances.
+X * Note: it is not clear that this is part of the Ansi Standard.
+X * The -N option supresses preset definitions.
+X */
+Xchar  *preset[] = {                   /* names defined at cpp start   */
+X#ifdef        MACHINE
+X      MACHINE,
+X#endif
+X#ifdef        SYSTEM
+X      SYSTEM,
+X#endif
+X#ifdef        COMPILER
+X      COMPILER,
+X#endif
+X#if   DEBUG
+X      "decus_cpp",                    /* Ourselves!                   */
+X#endif
+X      NULL                            /* Must be last                 */
+X};
+X
+X/*
+X * The value of these predefined symbols must be recomputed whenever
+X * they are evaluated.  The order must not be changed.
+X */
+Xchar  *magic[] = {                    /* Note: order is important     */
+X      "__LINE__",
+X      "__FILE__",
+X      NULL                            /* Must be last                 */
+X};
+X\f
+Xmain(argc, argv)
+Xint           argc;
+Xchar          *argv[];
+X{
+X      register int    i;
+X
+X#if HOST == SYS_VMS
+X      argc = getredirection(argc, argv);      /* vms >file and <file  */
+X#endif
+X      initdefines();                          /* O.S. specific def's  */
+X      i = dooptions(argc, argv);              /* Command line -flags  */
+X      switch (i) {
+X      case 3:
+X          /*
+X           * Get output file, "-" means use stdout.
+X           */
+X          if (!streq(argv[2], "-")) {
+X#if HOST == SYS_VMS
+X              /*
+X               * On vms, reopen stdout with "vanilla rms" attributes.
+X               */
+X              if ((i = creat(argv[2], 0, "rat=cr", "rfm=var")) == -1
+X               || dup2(i, fileno(stdout)) == -1) {
+X#else
+X              if (freopen(argv[2], "w", stdout) == NULL) {
+X#endif
+X                  perror(argv[2]);
+X                  cerror("Can't open output file \"%s\"", argv[2]);
+X                  exit(IO_ERROR);
+X              }
+X          }                           /* Continue by opening input    */
+X      case 2:                         /* One file -> stdin            */
+X          /*
+X           * Open input file, "-" means use stdin.
+X           */
+X          if (!streq(argv[1], "-")) {
+X              if (freopen(argv[1], "r", stdin) == NULL) {
+X                  perror(argv[1]);
+X                  cerror("Can't open input file \"%s\"", argv[1]);
+X                  exit(IO_ERROR);
+X              }
+X              strcpy(work, argv[1]);  /* Remember input filename      */
+X              break;
+X          }                           /* Else, just get stdin         */
+X      case 0:                         /* No args?                     */
+X      case 1:                         /* No files, stdin -> stdout    */
+X#if HOST == SYS_UNIX
+X          work[0] = EOS;              /* Unix can't find stdin name   */
+X#else
+X          fgetname(stdin, work);      /* Vax-11C, Decus C know name   */
+X#endif
+X          break;
+X
+X      default:
+X          exit(IO_ERROR);             /* Can't happen                 */
+X      }
+X      setincdirs();                   /* Setup -I include directories */
+X      addfile(stdin, work);           /* "open" main input file       */
+X#if DEBUG
+X      if (debug > 0)
+X          dumpdef("preset #define symbols");
+X#endif
+X      cppmain();                      /* Process main file            */
+X      if ((i = (ifptr - &ifstack[0])) != 0) {
+X#if OLD_PREPROCESSOR
+X          ciwarn("Inside #ifdef block at end of input, depth = %d", i);
+X#else
+X          cierror("Inside #ifdef block at end of input, depth = %d", i);
+X#endif
+X      }
+X      fclose(stdout);
+X      if (errors > 0) {
+X          fprintf(stderr, (errors == 1)
+X              ? "%d error in preprocessor\n"
+X              : "%d errors in preprocessor\n", errors);
+X          if (!eflag)
+X              exit(IO_ERROR);
+X      }
+X      exit(IO_NORMAL);                /* No errors or -E option set   */
+X}
+X\f
+XFILE_LOCAL
+Xcppmain()
+X/*
+X * Main process for cpp -- copies tokens from the current input
+X * stream (main file, include file, or a macro) to the output
+X * file.
+X */
+X{
+X      register int            c;              /* Current character    */
+X      register int            counter;        /* newlines and spaces  */
+X      extern int              output();       /* Output one character */
+X
+X      /*
+X       * Explicitly output a #line at the start of cpp output so
+X       * that lint (etc.) knows the name of the original source
+X       * file.  If we don't do this explicitly, we may get
+X       * the name of the first #include file instead.
+X       */
+X      sharp();
+X      /*
+X       * This loop is started "from the top" at the beginning of each line
+X       * wrongline is set TRUE in many places if it is necessary to write
+X       * a #line record.  (But we don't write them when expanding macros.)
+X       *
+X       * The counter variable has two different uses:  at
+X       * the start of a line, it counts the number of blank lines that
+X       * have been skipped over.  These are then either output via
+X       * #line records or by outputting explicit blank lines.
+X       * When expanding tokens within a line, the counter remembers
+X       * whether a blank/tab has been output.  These are dropped
+X       * at the end of the line, and replaced by a single blank
+X       * within lines.
+X       */
+X      for (;;) {
+X          counter = 0;                        /* Count empty lines    */
+X          for (;;) {                          /* For each line, ...   */
+X              while (type[(c = get())] == SPA) /* Skip leading blanks */
+X                  ;                           /* in this line.        */
+X              if (c == '\n')                  /* If line's all blank, */
+X                  ++counter;                  /* Do nothing now       */
+X              else if (c == '#') {            /* Is 1st non-space '#' */
+X                  keepcomments = FALSE;       /* Don't pass comments  */
+X                  counter = control(counter); /* Yes, do a #command   */
+X                  keepcomments = (cflag && compiling);
+X              }
+X              else if (c == EOF_CHAR)         /* At end of file?      */
+X                  break;
+X              else if (!compiling) {          /* #ifdef false?        */
+X                  skipnl();                   /* Skip to newline      */
+X                  counter++;                  /* Count it, too.       */
+X              }
+X              else {
+X                  break;                      /* Actual token         */
+X              }
+X          }
+X          if (c == EOF_CHAR)                  /* Exit process at      */
+X              break;                          /* End of file          */
+X          /*
+X           * If the loop didn't terminate because of end of file, we
+X           * know there is a token to compile.  First, clean up after
+X           * absorbing newlines.  counter has the number we skipped.
+X           */
+X          if ((wrongline && infile->fp != NULL) || counter > 4)
+X              sharp();                        /* Output # line number */
+X          else {                              /* If just a few, stuff */
+X              while (--counter >= 0)          /* them out ourselves   */
+X                  putchar('\n');
+X          }
+X          /*
+X           * Process each token on this line.
+X           */
+X          unget();                            /* Reread the char.     */
+X          for (;;) {                          /* For the whole line,  */
+X              do {                            /* Token concat. loop   */
+X                  for (counter = 0; (type[(c = get())] == SPA);) {
+X#if COMMENT_INVISIBLE
+X                      if (c != COM_SEP)
+X                          counter++;
+X#else
+X                      counter++;              /* Skip over blanks     */
+X#endif
+X                  }
+X                  if (c == EOF_CHAR || c == '\n')
+X                      goto end_line;          /* Exit line loop       */
+X                  else if (counter > 0)       /* If we got any spaces */
+X                      putchar(' ');           /* Output one space     */
+X                  c = macroid(c);             /* Grab the token       */
+X              } while (type[c] == LET && catenate());
+X              if (c == EOF_CHAR || c == '\n') /* From macro exp error */
+X                  goto end_line;              /* Exit line loop       */
+X              switch (type[c]) {
+X              case LET:
+X                  fputs(token, stdout);       /* Quite ordinary token */
+X                  break;
+X
+X
+X              case DIG:                       /* Output a number      */
+X              case DOT:                       /* Dot may begin floats */
+X                  scannumber(c, output);
+X                  break;
+X
+X              case QUO:                       /* char or string const */
+X                  scanstring(c, output);      /* Copy it to output    */
+X                  break;
+X
+X              default:                        /* Some other character */
+X                  cput(c);                    /* Just output it       */
+X                  break;
+X              }                               /* Switch ends          */
+X          }                                   /* Line for loop        */
+Xend_line:   if (c == '\n') {                  /* Compiling at EOL?    */
+X              putchar('\n');                  /* Output newline, if   */
+X              if (infile->fp == NULL)         /* Expanding a macro,   */
+X                  wrongline = TRUE;           /* Output # line later  */
+X          }
+X      }                                       /* Continue until EOF   */
+X}
+X\f
+Xoutput(c)
+Xint           c;
+X/*
+X * Output one character to stdout -- output() is passed as an
+X * argument to scanstring()
+X */
+X{
+X#if COMMENT_INVISIBLE
+X      if (c != TOK_SEP && c != COM_SEP)
+X#else
+X      if (c != TOK_SEP)
+X#endif
+X          putchar(c);
+X}
+X
+Xstatic char   *sharpfilename = NULL;
+X
+XFILE_LOCAL
+Xsharp()
+X/*
+X * Output a line number line.
+X */
+X{
+X      register char           *name;
+X
+X      if (keepcomments)                       /* Make sure # comes on */
+X          putchar('\n');                      /* a fresh, new line.   */
+X      printf("#%s %d", LINE_PREFIX, line);
+X      if (infile->fp != NULL) {
+X          name = (infile->progname != NULL)
+X              ? infile->progname : infile->filename;
+X          if (sharpfilename == NULL
+X           || sharpfilename != NULL && !streq(name, sharpfilename)) {
+X              if (sharpfilename != NULL)
+X                  free(sharpfilename);
+X              sharpfilename = savestring(name);
+X              printf(" \"%s\"", name);
+X           }
+X      }
+X      putchar('\n');
+X      wrongline = FALSE;
+X}
+END-of-cpp1.c
+echo x - cpp3.c
+sed 's/^X//' >cpp3.c << 'END-of-cpp3.c'
+X/*
+X *                            C P P 3 . C
+X *
+X *                File open and command line options
+X *
+X * Edit history
+X * 13-Nov-84  MM      Split from cpp1.c
+X */
+X
+X#include      <stdio.h>
+X#include      <ctype.h>
+X#include      "cppdef.h"
+X#include      "cpp.h"
+X#if DEBUG && (HOST == SYS_VMS || HOST == SYS_UNIX)
+X#include      <signal.h>
+Xextern int    abort();                /* For debugging                */
+X#endif
+X
+Xint
+Xopenfile(filename)
+Xchar          *filename;
+X/*
+X * Open a file, add it to the linked list of open files.
+X * This is called only from openfile() above.
+X */
+X{
+X      register FILE           *fp;
+X
+X      if ((fp = fopen(filename, "r")) == NULL) {
+X#if DEBUG
+X          perror(filename);
+X#endif
+X          return (FALSE);
+X      }
+X#if DEBUG
+X      if (debug)
+X          fprintf(stderr, "Reading from \"%s\"\n", filename);
+X#endif
+X      addfile(fp, filename);
+X      return (TRUE);
+X}
+X
+Xaddfile(fp, filename)
+XFILE          *fp;                    /* Open file pointer            */
+Xchar          *filename;              /* Name of the file             */
+X/*
+X * Initialize tables for this open file.  This is called from openfile()
+X * above (for #include files), and from the entry to cpp to open the main
+X * input file.  It calls a common routine, getfile() to build the FILEINFO
+X * structure which is used to read characters.  (getfile() is also called
+X * to setup a macro replacement.)
+X */
+X{
+X      register FILEINFO       *file;
+X      extern FILEINFO         *getfile();
+X
+X      file = getfile(NBUFF, filename);
+X      file->fp = fp;                  /* Better remember FILE *       */
+X      file->buffer[0] = EOS;          /* Initialize for first read    */
+X      line = 1;                       /* Working on line 1 now        */
+X      wrongline = TRUE;               /* Force out initial #line      */
+X}
+X\f
+Xsetincdirs()
+X/*
+X * Append system-specific directories to the include directory list.
+X * Called only when cpp is started.
+X */
+X{
+X
+X#ifdef        CPP_INCLUDE
+X      *incend++ = CPP_INCLUDE;
+X#define       IS_INCLUDE      1
+X#else
+X#define       IS_INCLUDE      0
+X#endif
+X
+X#if HOST == SYS_UNIX
+X      *incend++ = "/usr/include";
+X#define       MAXINCLUDE      (NINCLUDE - 1 - IS_INCLUDE)
+X#endif
+X
+X#if HOST == SYS_VMS
+X      extern char     *getenv();
+X
+X      if (getenv("C$LIBRARY") != NULL)
+X          *incend++ = "C$LIBRARY:";
+X      *incend++ = "SYS$LIBRARY:";
+X#define       MAXINCLUDE      (NINCLUDE - 2 - IS_INCLUDE)
+X#endif
+X
+X#if HOST == SYS_RSX
+X      extern int      $$rsts;                 /* TRUE on RSTS/E       */
+X      extern int      $$pos;                  /* TRUE on PRO-350 P/OS */
+X      extern int      $$vms;                  /* TRUE on VMS compat.  */
+X
+X      if ($$pos) {                            /* P/OS?                */
+X          *incend++ = "SY:[ZZDECUSC]";        /* C #includes          */
+X          *incend++ = "LB:[1,5]";             /* RSX library          */
+X      }
+X      else if ($$rsts) {                      /* RSTS/E?              */
+X          *incend++ = "SY:@";                 /* User-defined account */
+X          *incend++ = "C:";                   /* Decus-C library      */
+X          *incend++ = "LB:[1,1]";             /* RSX library          */
+X      }
+X      else if ($$vms) {                       /* VMS compatibility?   */
+X          *incend++ = "C:";
+X      }
+X      else {                                  /* Plain old RSX/IAS    */
+X          *incend++ = "LB:[1,1]";
+X      }
+X#define       MAXINCLUDE      (NINCLUDE - 3 - IS_INCLUDE)
+X#endif
+X
+X#if HOST == SYS_RT11
+X      extern int      $$rsts;                 /* RSTS/E emulation?    */
+X
+X      if ($$rsts)
+X          *incend++ = "SY:@";                 /* User-defined account */
+X      *incend++ = "C:";                       /* Decus-C library disk */
+X      *incend++ = "SY:";                      /* System (boot) disk   */
+X#define       MAXINCLUDE      (NINCLUDE - 3 - IS_INCLUDE)
+X#endif
+X}
+X\f
+Xint
+Xdooptions(argc, argv)
+Xint           argc;
+Xchar          *argv[];
+X/*
+X * dooptions is called to process command line arguments (-Detc).
+X * It is called only at cpp startup.
+X */
+X{
+X      register char           *ap;
+X      register DEFBUF         *dp;
+X      register int            c;
+X      int                     i, j;
+X      char                    *arg;
+X      SIZES                   *sizp;          /* For -S               */
+X      int                     size;           /* For -S               */
+X      int                     isdatum;        /* FALSE for -S*        */
+X      int                     endtest;        /* For -S               */
+X
+X      for (i = j = 1; i < argc; i++) {
+X          arg = ap = argv[i];
+X          if (*ap++ != '-' || *ap == EOS)
+X              argv[j++] = argv[i];
+X          else {
+X              c = *ap++;                      /* Option byte          */
+X              if (islower(c))                 /* Normalize case       */
+X                  c = toupper(c);
+X              switch (c) {                    /* Command character    */
+X              case 'C':                       /* Keep comments        */
+X                  cflag = TRUE;
+X                  keepcomments = TRUE;
+X                  break;
+X
+X              case 'D':                       /* Define symbol        */
+X#if HOST != SYS_UNIX
+X                  zap_uc(ap);                 /* Force define to U.C. */
+X#endif
+X                  /*
+X                   * If the option is just "-Dfoo", make it -Dfoo=1
+X                   */
+X                  while (*ap != EOS && *ap != '=')
+X                      ap++;
+X                  if (*ap == EOS)
+X                      ap = "1";
+X                  else
+X                      *ap++ = EOS;
+X                  /*
+X                   * Now, save the word and its definition.
+X                   */
+X                  dp = defendel(argv[i] + 2, FALSE);
+X                  dp->repl = savestring(ap);
+X                  dp->nargs = DEF_NOARGS;
+X                  break;
+X
+X              case 'E':                       /* Ignore non-fatal     */
+X                  eflag = TRUE;               /* errors.              */
+X                  break;
+X
+X              case 'I':                       /* Include directory    */
+X                  if (incend >= &incdir[MAXINCLUDE])
+X                      cfatal("Too many include directories", NULLST);
+X                  *incend++ = ap;
+X                  break;
+X
+X              case 'N':                       /* No predefineds       */
+X                  nflag++;                    /* Repeat to undefine   */
+X                  break;                      /* __LINE__, etc.       */
+X
+X              case 'S':
+X                  sizp = size_table;
+X                  if (isdatum = (*ap != '*')) /* If it's just -S,     */
+X                      endtest = T_FPTR;       /* Stop here            */
+X                  else {                      /* But if it's -S*      */
+X                      ap++;                   /* Step over '*'        */
+X                      endtest = 0;            /* Stop at end marker   */
+X                  }
+X                  while (sizp->bits != endtest && *ap != EOS) {
+X                      if (!isdigit(*ap)) {    /* Skip to next digit   */
+X                          ap++;
+X                          continue;
+X                      }
+X                      size = 0;               /* Compile the value    */
+X                      while (isdigit(*ap)) {
+X                          size *= 10;
+X                          size += (*ap++ - '0');
+X                      }
+X                      if (isdatum)
+X                          sizp->size = size;  /* Datum size           */
+X                      else
+X                          sizp->psize = size; /* Pointer size         */
+X                      sizp++;
+X                  }
+X                  if (sizp->bits != endtest)
+X                      cwarn("-S, too few values specified in %s", argv[i]);
+X                  else if (*ap != EOS)
+X                      cwarn("-S, too many values, \"%s\" unused", ap);
+X                  break;
+X
+X              case 'U':                       /* Undefine symbol      */
+X#if HOST != SYS_UNIX
+X                  zap_uc(ap);
+X#endif
+X                  if (defendel(ap, TRUE) == NULL)
+X                      cwarn("\"%s\" wasn't defined", ap);
+X                  break;
+X
+X#if DEBUG
+X              case 'X':                       /* Debug                */
+X                  debug = (isdigit(*ap)) ? atoi(ap) : 1;
+X#if (HOST == SYS_VMS || HOST == SYS_UNIX)
+X                  signal(SIGINT, abort);      /* Trap "interrupt"     */
+X#endif
+X                  fprintf(stderr, "Debug set to %d\n", debug);
+X                  break;
+X#endif
+X
+X              default:                        /* What is this one?    */
+X                  cwarn("Unknown option \"%s\"", arg);
+X                  fprintf(stderr, "The following options are valid:\n\
+X  -C\t\t\tWrite source file comments to output\n\
+X  -Dsymbol=value\tDefine a symbol with the given (optional) value\n\
+X  -Idirectory\t\tAdd a directory to the #include search list\n\
+X  -N\t\t\tDon't predefine target-specific names\n\
+X  -Stext\t\tSpecify sizes for #if sizeof\n\
+X  -Usymbol\t\tUndefine symbol\n");
+X#if DEBUG
+X                  fprintf(stderr, "  -Xvalue\t\tSet internal debug flag\n");
+X#endif
+X                  break;
+X              }                       /* Switch on all options        */
+X          }                           /* If it's a -option            */
+X      }                               /* For all arguments            */
+X      if (j > 3) {
+X          cerror(
+X              "Too many file arguments.  Usage: cpp [input [output]]",
+X              NULLST);
+X      }
+X      return (j);                     /* Return new argc              */
+X}
+X\f
+X#if HOST != SYS_UNIX
+XFILE_LOCAL
+Xzap_uc(ap)
+Xregister char *ap;
+X/*
+X * Dec operating systems mangle upper-lower case in command lines.
+X * This routine forces the -D and -U arguments to uppercase.
+X * It is called only on cpp startup by dooptions().
+X */
+X{
+X      while (*ap != EOS) {
+X          /*
+X           * Don't use islower() here so it works with Multinational
+X           */
+X          if (*ap >= 'a' && *ap <= 'z')
+X              *ap = toupper(*ap);
+X          ap++;
+X      }
+X}
+X#endif
+X
+Xinitdefines()
+X/*
+X * Initialize the built-in #define's.  There are two flavors:
+X *    #define decus   1               (static definitions)
+X *    #define __FILE__ ??             (dynamic, evaluated by magic)
+X * Called only on cpp startup.
+X *
+X * Note: the built-in static definitions are supressed by the -N option.
+X * __LINE__, __FILE__, and __DATE__ are always present.
+X */
+X{
+X      register char           **pp;
+X      register char           *tp;
+X      register DEFBUF         *dp;
+X      int                     i;
+X      long                    tvec;
+X      extern char             *ctime();
+X
+X      /*
+X       * Predefine the built-in symbols.  Allow the
+X       * implementor to pre-define a symbol as "" to
+X       * eliminate it.
+X       */
+X      if (nflag == 0) {
+X          for (pp = preset; *pp != NULL; pp++) {
+X              if (*pp[0] != EOS) {
+X                  dp = defendel(*pp, FALSE);
+X                  dp->repl = savestring("1");
+X                  dp->nargs = DEF_NOARGS;
+X              }
+X          }
+X      }
+X      /*
+X       * The magic pre-defines (__FILE__ and __LINE__ are
+X       * initialized with negative argument counts.  expand()
+X       * notices this and calls the appropriate routine.
+X       * DEF_NOARGS is one greater than the first "magic" definition.
+X       */
+X      if (nflag < 2) {
+X          for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) {
+X              dp = defendel(*pp, FALSE);
+X              dp->nargs = --i;
+X          }
+X#if OK_DATE
+X          /*
+X           * Define __DATE__ as today's date.
+X           */
+X          dp = defendel("__DATE__", FALSE);
+X          dp->repl = tp = getmem(27);
+X          dp->nargs = DEF_NOARGS;
+X          time(&tvec);
+X          *tp++ = '"';
+X          strcpy(tp, ctime(&tvec));
+X          tp[24] = '"';                       /* Overwrite newline    */
+X#endif
+X      }
+X}
+X\f
+X#if HOST == SYS_VMS
+X/*
+X * getredirection() is intended to aid in porting C programs
+X * to VMS (Vax-11 C) which does not support '>' and '<'
+X * I/O redirection.  With suitable modification, it may
+X * useful for other portability problems as well.
+X */
+X
+Xint
+Xgetredirection(argc, argv)
+Xint           argc;
+Xchar          **argv;
+X/*
+X * Process vms redirection arg's.  Exit if any error is seen.
+X * If getredirection() processes an argument, it is erased
+X * from the vector.  getredirection() returns a new argc value.
+X *
+X * Warning: do not try to simplify the code for vms.  The code
+X * presupposes that getredirection() is called before any data is
+X * read from stdin or written to stdout.
+X *
+X * Normal usage is as follows:
+X *
+X *    main(argc, argv)
+X *    int             argc;
+X *    char            *argv[];
+X *    {
+X *            argc = getredirection(argc, argv);
+X *    }
+X */
+X{
+X      register char           *ap;    /* Argument pointer     */
+X      int                     i;      /* argv[] index         */
+X      int                     j;      /* Output index         */
+X      int                     file;   /* File_descriptor      */
+X      extern int              errno;  /* Last vms i/o error   */
+X
+X      for (j = i = 1; i < argc; i++) {   /* Do all arguments  */
+X          switch (*(ap = argv[i])) {
+X          case '<':                   /* <file                */
+X              if (freopen(++ap, "r", stdin) == NULL) {
+X                  perror(ap);         /* Can't find file      */
+X                  exit(errno);        /* Is a fatal error     */
+X              }
+X              break;
+X
+X          case '>':                   /* >file or >>file      */
+X              if (*++ap == '>') {     /* >>file               */
+X                  /*
+X                   * If the file exists, and is writable by us,
+X                   * call freopen to append to the file (using the
+X                   * file's current attributes).  Otherwise, create
+X                   * a new file with "vanilla" attributes as if the
+X                   * argument was given as ">filename".
+X                   * access(name, 2) returns zero if we can write on
+X                   * the specified file.
+X                   */
+X                  if (access(++ap, 2) == 0) {
+X                      if (freopen(ap, "a", stdout) != NULL)
+X                          break;      /* Exit case statement  */
+X                      perror(ap);     /* Error, can't append  */
+X                      exit(errno);    /* After access test    */
+X                  }                   /* If file accessable   */
+X              }
+X              /*
+X               * On vms, we want to create the file using "standard"
+X               * record attributes.  creat(...) creates the file
+X               * using the caller's default protection mask and
+X               * "variable length, implied carriage return"
+X               * attributes. dup2() associates the file with stdout.
+X               */
+X              if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1
+X               || dup2(file, fileno(stdout)) == -1) {
+X                  perror(ap);         /* Can't create file    */
+X                  exit(errno);        /* is a fatal error     */
+X              }                       /* If '>' creation      */
+X              break;                  /* Exit case test       */
+X
+X          default:
+X              argv[j++] = ap;         /* Not a redirector     */
+X              break;                  /* Exit case test       */
+X          }
+X      }                               /* For all arguments    */
+X      argv[j] = NULL;                 /* Terminate argv[]     */
+X      return (j);                     /* Return new argc      */
+X}
+X#endif
+X
+X
+X
+END-of-cpp3.c
+echo x - cpp4.c
+sed 's/^X//' >cpp4.c << 'END-of-cpp4.c'
+X/*
+X *                        C P P 4 . C
+X *            M a c r o  D e f i n i t i o n s
+X *
+X * Edit History
+X * 31-Aug-84  MM      USENET net.sources release
+X * 04-Oct-84  MM      __LINE__ and __FILE__ must call ungetstring()
+X *                    so they work correctly with token concatenation.
+X *                    Added string formal recognition.
+X * 25-Oct-84  MM      "Short-circuit" evaluate #if's so that we
+X *                    don't print unnecessary error messages for
+X *                    #if !defined(FOO) && FOO != 0 && 10 / FOO ...
+X * 31-Oct-84  ado/MM  Added token concatenation
+X *  6-Nov-84  MM      Split off eval stuff
+X */
+X
+X#include      <stdio.h>
+X#include      <ctype.h>
+X#include      "cppdef.h"
+X#include      "cpp.h"
+X/*
+X * parm[], parmp, and parlist[] are used to store #define() argument
+X * lists.  nargs contains the actual number of parameters stored.
+X */
+Xstatic char   parm[NPARMWORK + 1];    /* define param work buffer     */
+Xstatic char   *parmp;                 /* Free space in parm           */
+Xstatic char   *parlist[LASTPARM];     /* -> start of each parameter   */
+Xstatic int    nargs;                  /* Parameters for this macro    */
+X
+Xdodefine()
+X/*
+X * Called from control when a #define is scanned.  This module
+X * parses formal parameters and the replacement string.  When
+X * the formal parameter name is encountered in the replacement
+X * string, it is replaced by a character in the range 128 to
+X * 128+NPARAM (this allows up to 32 parameters within the
+X * Dec Multinational range).  If cpp is ported to an EBCDIC
+X * machine, you will have to make other arrangements.
+X *
+X * There is some special case code to distinguish
+X *    #define foo     bar
+X * from       #define foo()   bar
+X *
+X * Also, we make sure that
+X *    #define foo     foo
+X * expands to "foo" but doesn't put cpp into an infinite loop.
+X *
+X * A warning message is printed if you redefine a symbol to a
+X * different text.  I.e,
+X *    #define foo     123
+X *    #define foo     123
+X * is ok, but
+X *    #define foo     123
+X *    #define foo     +123
+X * is not.
+X *
+X * The following subroutines are called from define():
+X * checkparm  called when a token is scanned.  It checks through the
+X *            array of formal parameters.  If a match is found, the
+X *            token is replaced by a control byte which will be used
+X *            to locate the parameter when the macro is expanded.
+X * textput    puts a string in the macro work area (parm[]), updating
+X *            parmp to point to the first free byte in parm[].
+X *            textput() tests for work buffer overflow.
+X * charput    puts a single character in the macro work area (parm[])
+X *            in a manner analogous to textput().
+X */
+X{
+X      register int            c;
+X      register DEFBUF         *dp;            /* -> new definition    */
+X      int                     isredefine;     /* TRUE if redefined    */
+X      char                    *old;           /* Remember redefined   */
+X      extern int              save();         /* Save char in work[]  */
+X
+X      if (type[(c = skipws())] != LET)
+X          goto bad_define;
+X      isredefine = FALSE;                     /* Set if redefining    */
+X      if ((dp = lookid(c)) == NULL)           /* If not known now     */
+X          dp = defendel(token, FALSE);        /* Save the name        */
+X      else {                                  /* It's known:          */
+X          isredefine = TRUE;                  /* Remember this fact   */
+X          old = dp->repl;                     /* Remember replacement */
+X          dp->repl = NULL;                    /* No replacement now   */
+X      }
+X      parlist[0] = parmp = parm;              /* Setup parm buffer    */
+X      if ((c = get()) == '(') {               /* With arguments?      */
+X          nargs = 0;                          /* Init formals counter */
+X          do {                                /* Collect formal parms */
+X              if (nargs >= LASTPARM)
+X                  cfatal("Too many arguments for macro", NULLST);
+X              else if ((c = skipws()) == ')')
+X                  break;                      /* Got them all         */
+X              else if (type[c] != LET)        /* Bad formal syntax    */
+X                  goto bad_define;
+X              scanid(c);                      /* Get the formal param */
+X              parlist[nargs++] = parmp;       /* Save its start       */
+X              textput(token);                 /* Save text in parm[]  */
+X          } while ((c = skipws()) == ',');    /* Get another argument */
+X          if (c != ')')                       /* Must end at )        */
+X              goto bad_define;
+X          c = ' ';                            /* Will skip to body    */
+X      }
+X      else {
+X          /*
+X           * DEF_NOARGS is needed to distinguish between
+X           * "#define foo" and "#define foo()".
+X           */
+X          nargs = DEF_NOARGS;                 /* No () parameters     */
+X      }
+X      if (type[c] == SPA)                     /* At whitespace?       */
+X          c = skipws();                       /* Not any more.        */
+X      workp = work;                           /* Replacement put here */
+X      inmacro = TRUE;                         /* Keep \<newline> now  */
+X      while (c != EOF_CHAR && c != '\n') {    /* Compile macro body   */
+X#if OK_CONCAT
+X          if (c == '#') {                     /* Token concatenation? */
+X              while (workp > work && type[workp[-1]] == SPA)
+X                  --workp;                    /* Erase leading spaces */
+X              save(TOK_SEP);                  /* Stuff a delimiter    */
+X              c = skipws();                   /* Eat whitespace       */
+X              if (type[c] == LET)             /* Another token here?  */
+X                  ;                           /* Stuff it normally    */
+X              else if (type[c] == DIG) {      /* Digit string after?  */
+X                  while (type[c] == DIG) {    /* Stuff the digits     */
+X                      save(c);
+X                      c = get();
+X                  }
+X                  save(TOK_SEP);              /* Delimit 2nd token    */
+X              }
+X              else {
+X                  ciwarn("Strange character after # (%d.)", c);
+X              }
+X              continue;
+X          }
+X#endif
+X          switch (type[c]) {
+X          case LET:
+X              checkparm(c, dp);               /* Might be a formal    */
+X              break;
+X
+X          case DIG:                           /* Number in mac. body  */
+X          case DOT:                           /* Maybe a float number */
+X              scannumber(c, save);            /* Scan it off          */
+X              break;
+X
+X          case QUO:                           /* String in mac. body  */
+X#if STRING_FORMAL
+X              stparmscan(c, dp);              /* Do string magic      */
+X#else
+X              stparmscan(c);
+X#endif
+X              break;
+X
+X          case BSH:                           /* Backslash            */
+X              save('\\');
+X              if ((c = get()) == '\n')
+X                  wrongline = TRUE;
+X              save(c);
+X              break;
+X
+X          case SPA:                           /* Absorb whitespace    */
+X              /*
+X               * Note: the "end of comment" marker is passed on
+X               * to allow comments to separate tokens.
+X               */
+X              if (workp[-1] == ' ')           /* Absorb multiple      */
+X                  break;                      /* spaces               */
+X              else if (c == '\t')
+X                  c = ' ';                    /* Normalize tabs       */
+X              /* Fall through to store character                      */
+X          default:                            /* Other character      */
+X              save(c);
+X              break;
+X          }
+X          c = get();
+X      }
+X      inmacro = FALSE;                        /* Stop newline hack    */
+X      unget();                                /* For control check    */
+X      if (workp > work && workp[-1] == ' ')   /* Drop trailing blank  */
+X          workp--;
+X      *workp = EOS;                           /* Terminate work       */
+X      dp->repl = savestring(work);            /* Save the string      */
+X      dp->nargs = nargs;                      /* Save arg count       */
+X#if DEBUG
+X      if (debug)
+X          dumpadef("macro definition", dp);
+X#endif
+X      if (isredefine) {                       /* Error if redefined   */
+X          if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl))
+X           || (old == NULL && dp->repl != NULL)
+X           || (old != NULL && dp->repl == NULL)) {
+X              cerror("Redefining defined variable \"%s\"", dp->name);
+X          }
+X          if (old != NULL)                    /* We don't need the    */
+X              free(old);                      /* old definition now.  */
+X      }        
+X      return;
+X
+Xbad_define:
+X      cerror("#define syntax error", NULLST);
+X      inmacro = FALSE;                        /* Stop <newline> hack  */
+X}
+X\f
+Xcheckparm(c, dp)
+Xregister int  c;
+XDEFBUF                *dp;
+X/*
+X * Replace this param if it's defined.  Note that the macro name is a
+X * possible replacement token.  We stuff DEF_MAGIC in front of the token
+X * which is treated as a LETTER by the token scanner and eaten by
+X * the output routine.  This prevents the macro expander from
+X * looping if someone writes "#define foo foo".
+X */
+X{
+X      register int            i;
+X      register char           *cp;
+X
+X      scanid(c);                              /* Get parm to token[]  */
+X      for (i = 0; i < nargs; i++) {           /* For each argument    */
+X          if (streq(parlist[i], token)) {     /* If it's known        */
+X              save(i + MAC_PARM);             /* Save a magic cookie  */
+X              return;                         /* And exit the search  */
+X          }
+X      }
+X      if (streq(dp->name, token))             /* Macro name in body?  */
+X          save(DEF_MAGIC);                    /* Save magic marker    */
+X      for (cp = token; *cp != EOS;)           /* And save             */
+X          save(*cp++);                        /* The token itself     */
+X}
+X\f
+X#if STRING_FORMAL
+Xstparmscan(delim, dp)
+Xint           delim;
+Xregister DEFBUF       *dp;
+X/*
+X * Scan the string (starting with the given delimiter).
+X * The token is replaced if it is the only text in this string or
+X * character constant.  The algorithm follows checkparm() above.
+X * Note that scanstring() has approved of the string.
+X */
+X{
+X      register int            c;
+X
+X      /*
+X       * Warning -- this code hasn't been tested for a while.
+X       * It exists only to preserve compatibility with earlier
+X       * implementations of cpp.  It is not part of the Draft
+X       * ANSI Standard C language.
+X       */
+X      save(delim);
+X      instring = TRUE;
+X      while ((c = get()) != delim
+X           && c != '\n'
+X           && c != EOF_CHAR) {
+X          if (type[c] == LET)                 /* Maybe formal parm    */
+X              checkparm(c, dp);
+X          else {
+X              save(c);
+X              if (c == '\\')
+X                  save(get());
+X          }
+X      }
+X      instring = FALSE;
+X      if (c != delim)
+X          cerror("Unterminated string in macro body", NULLST);
+X      save(c);
+X}
+X#else
+Xstparmscan(delim)
+Xint           delim;
+X/*
+X * Normal string parameter scan.
+X */
+X{
+X      register char           *wp;
+X      register int            i;
+X      extern int              save();
+X
+X      wp = workp;                     /* Here's where it starts       */
+X      if (!scanstring(delim, save))
+X          return;                     /* Exit on scanstring error     */
+X      workp[-1] = EOS;                /* Erase trailing quote         */
+X      wp++;                           /* -> first string content byte */ 
+X      for (i = 0; i < nargs; i++) {
+X          if (streq(parlist[i], wp)) {
+X              *wp++ = MAC_PARM + PAR_MAC;     /* Stuff a magic marker */
+X              *wp++ = (i + MAC_PARM);         /* Make a formal marker */
+X              *wp = wp[-3];                   /* Add on closing quote */
+X              workp = wp + 1;                 /* Reset string end     */
+X              return;
+X          }
+X      }
+X      workp[-1] = wp[-1];             /* Nope, reset end quote.       */
+X}
+X#endif
+X\f
+Xdoundef()
+X/*
+X * Remove the symbol from the defined list.
+X * Called from the #control processor.
+X */
+X{
+X      register int            c;
+X
+X      if (type[(c = skipws())] != LET)
+X          cerror("Illegal #undef argument", NULLST);
+X      else {
+X          scanid(c);                          /* Get name to token[]  */
+X          if (defendel(token, TRUE) == NULL) {
+X              cwarn("Symbol \"%s\" not defined in #undef", token);
+X          }
+X      }
+X}
+X
+Xtextput(text)
+Xchar          *text;
+X/*
+X * Put the string in the parm[] buffer.
+X */
+X{
+X      register int    size;
+X
+X      size = strlen(text) + 1;
+X      if ((parmp + size) >= &parm[NPARMWORK])
+X          cfatal("Macro work area overflow", NULLST);
+X      else {
+X          strcpy(parmp, text);
+X          parmp += size;
+X      }
+X}
+X
+Xcharput(c)
+Xregister int  c;
+X/*
+X * Put the byte in the parm[] buffer.
+X */
+X{
+X      if (parmp >= &parm[NPARMWORK])
+X          cfatal("Macro work area overflow", NULLST);
+X      else {
+X          *parmp++ = c;
+X      }
+X}
+X\f
+X/*
+X *            M a c r o   E x p a n s i o n
+X */
+X
+Xstatic DEFBUF *macro;         /* Catches start of infinite macro      */
+X
+Xexpand(tokenp)
+Xregister DEFBUF       *tokenp;
+X/*
+X * Expand a macro.  Called from the cpp mainline routine (via subroutine
+X * macroid()) when a token is found in the symbol table.  It calls
+X * expcollect() to parse actual parameters, checking for the correct number.
+X * It then creates a "file" containing a single line containing the
+X * macro with actual parameters inserted appropriately.  This is
+X * "pushed back" onto the input stream.  (When the get() routine runs
+X * off the end of the macro line, it will dismiss the macro itself.)
+X */
+X{
+X      register int            c;
+X      register FILEINFO       *file;
+X      extern FILEINFO         *getfile();
+X
+X#if DEBUG
+X      if (debug)
+X          dumpadef("expand entry", tokenp);
+X#endif
+X      /*
+X       * If no macro is pending, save the name of this macro
+X       * for an eventual error message.
+X       */
+X      if (recursion++ == 0)
+X          macro = tokenp;
+X      else if (recursion == RECURSION_LIMIT) {
+X          cerror("Recursive macro definition of \"%s\"", tokenp->name);
+X          fprintf(stderr, "(Defined by \"%s\")\n", macro->name);
+X          if (rec_recover) {
+X              do {
+X                  c = get();
+X              } while (infile != NULL && infile->fp == NULL);
+X              unget();
+X              recursion = 0;
+X              return;
+X          }
+X      }
+X      /*
+X       * Here's a macro to expand.
+X       */
+X      nargs = 0;                              /* Formals counter      */
+X      parmp = parm;                           /* Setup parm buffer    */
+X      switch (tokenp->nargs) {
+X      case (-2):                              /* __LINE__             */
+X          sprintf(work, "%d", line);
+X          ungetstring(work);
+X          break;
+X
+X      case (-3):                              /* __FILE__             */
+X          for (file = infile; file != NULL; file = file->parent) {
+X              if (file->fp != NULL) {
+X                  sprintf(work, "\"%s\"", (file->progname != NULL)
+X                      ? file->progname : file->filename);
+X                  ungetstring(work);
+X                  break;
+X              }
+X          }
+X          break;
+X
+X      default:
+X          /*
+X           * Nothing funny about this macro.
+X           */
+X          if (tokenp->nargs < 0)
+X              cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name);
+X          while ((c = skipws()) == '\n')      /* Look for (, skipping */
+X              wrongline = TRUE;               /* spaces and newlines  */
+X          if (c != '(') {
+X              /*
+X               * If the programmer writes
+X               *      #define foo() ...
+X               *      ...
+X               *      foo [no ()]
+X               * just write foo to the output stream.
+X               */
+X              unget();
+X              cwarn("Macro \"%s\" needs arguments", tokenp->name);
+X              fputs(tokenp->name, stdout);
+X              return;
+X          }
+X          else if (expcollect()) {            /* Collect arguments    */
+X              if (tokenp->nargs != nargs) {   /* Should be an error?  */
+X                  cwarn("Wrong number of macro arguments for \"%s\"",
+X                      tokenp->name);
+X              }
+X#if DEBUG
+X              if (debug)
+X                  dumpparm("expand");
+X#endif
+X          }                           /* Collect arguments            */
+X      case DEF_NOARGS:                /* No parameters just stuffs    */
+X          expstuff(tokenp);           /* Do actual parameters         */
+X      }                               /* nargs switch                 */
+X}
+X\f
+XFILE_LOCAL int
+Xexpcollect()
+X/*
+X * Collect the actual parameters for this macro.  TRUE if ok.
+X */
+X{
+X      register int    c;
+X      register int    paren;                  /* For embedded ()'s    */
+X      extern int      charput();
+X
+X      for (;;) {
+X          paren = 0;                          /* Collect next arg.    */
+X          while ((c = skipws()) == '\n')      /* Skip over whitespace */
+X              wrongline = TRUE;               /* and newlines.        */
+X          if (c == ')') {                     /* At end of all args?  */
+X              /*
+X               * Note that there is a guard byte in parm[]
+X               * so we don't have to check for overflow here.
+X               */
+X              *parmp = EOS;                   /* Make sure terminated */
+X              break;                          /* Exit collection loop */
+X          }
+X          else if (nargs >= LASTPARM)
+X              cfatal("Too many arguments in macro expansion", NULLST);
+X          parlist[nargs++] = parmp;           /* At start of new arg  */
+X          for (;; c = cget()) {               /* Collect arg's bytes  */
+X              if (c == EOF_CHAR) {
+X                  cerror("end of file within macro argument", NULLST);
+X                  return (FALSE);             /* Sorry.               */
+X              }
+X              else if (c == '\\') {           /* Quote next character */
+X                  charput(c);                 /* Save the \ for later */
+X                  charput(cget());            /* Save the next char.  */
+X                  continue;                   /* And go get another   */
+X              }
+X              else if (type[c] == QUO) {      /* Start of string?     */
+X                  scanstring(c, charput);     /* Scan it off          */
+X                  continue;                   /* Go get next char     */
+X              }
+X              else if (c == '(')              /* Worry about balance  */
+X                  paren++;                    /* To know about commas */
+X              else if (c == ')') {            /* Other side too       */
+X                  if (paren == 0) {           /* At the end?          */
+X                      unget();                /* Look at it later     */
+X                      break;                  /* Exit arg getter.     */
+X                  }
+X                  paren--;                    /* More to come.        */
+X              }
+X              else if (c == ',' && paren == 0) /* Comma delimits args */
+X                  break;
+X              else if (c == '\n')             /* Newline inside arg?  */
+X                  wrongline = TRUE;           /* We'll need a #line   */
+X              charput(c);                     /* Store this one       */
+X          }                                   /* Collect an argument  */
+X          charput(EOS);                       /* Terminate argument   */
+X#if DEBUG
+X          if (debug)
+X              printf("parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]);
+X#endif
+X      }                                       /* Collect all args.    */
+X      return (TRUE);                          /* Normal return        */
+X}
+X\f
+XFILE_LOCAL
+Xexpstuff(tokenp)
+XDEFBUF                *tokenp;                /* Current macro being expanded */
+X/*
+X * Stuff the macro body, replacing formal parameters by actual parameters.
+X */
+X{
+X      register int    c;                      /* Current character    */
+X      register char   *inp;                   /* -> repl string       */
+X      register char   *defp;                  /* -> macro output buff */
+X      int             size;                   /* Actual parm. size    */
+X      char            *defend;                /* -> output buff end   */
+X      int             string_magic;           /* String formal hack   */
+X      FILEINFO        *file;                  /* Funny #include       */
+X      extern FILEINFO *getfile();
+X
+X      file = getfile(NBUFF, tokenp->name);
+X      inp = tokenp->repl;                     /* -> macro replacement */
+X      defp = file->buffer;                    /* -> output buffer     */
+X      defend = defp + (NBUFF - 1);            /* Note its end         */
+X      if (inp != NULL) {
+X          while ((c = (*inp++ & 0xFF)) != EOS) {
+X              if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) {
+X                  string_magic = (c == (MAC_PARM + PAR_MAC));
+X                  if (string_magic)
+X                      c = (*inp++ & 0xFF);
+X                  /*
+X                   * Replace formal parameter by actual parameter string.
+X                   */
+X                  if ((c -= MAC_PARM) < nargs) {
+X                      size = strlen(parlist[c]);
+X                      if ((defp + size) >= defend)
+X                          goto nospace;
+X                      /*
+X                       * Erase the extra set of quotes.
+X                       */
+X                      if (string_magic && defp[-1] == parlist[c][0]) {
+X                          strcpy(defp-1, parlist[c]);
+X                          defp += (size - 2);
+X                      }
+X                      else {
+X                          strcpy(defp, parlist[c]);
+X                          defp += size;
+X                      }
+X                  }
+X              }
+X              else if (defp >= defend) {
+Xnospace:          cfatal("Out of space in macro \"%s\" arg expansion",
+X                      tokenp->name);
+X              }
+X              else {
+X                  *defp++ = c;
+X              }
+X          }
+X      }
+X      *defp = EOS;
+X#if DEBUG
+X      if (debug > 1)
+X          printf("macroline: \"%s\"\n", file->buffer);
+X#endif
+X}
+X\f
+X#if DEBUG
+Xdumpparm(why)
+Xchar          *why;
+X/*
+X * Dump parameter list.
+X */
+X{
+X      register int    i;
+X
+X      printf("dump of %d parameters (%d bytes total) %s\n",
+X          nargs, parmp - parm, why);
+X      for (i = 0; i < nargs; i++) {
+X          printf("parm[%d] (%d) = \"%s\"\n",
+X              i + 1, strlen(parlist[i]), parlist[i]);
+X      }
+X}
+X#endif
+END-of-cpp4.c
+exit
diff --git a/sys/unix/cpp3.shr b/sys/unix/cpp3.shr
new file mode 100644 (file)
index 0000000..d437d36
--- /dev/null
@@ -0,0 +1,1901 @@
+# This is a shell archive.  Save it in a file, remove anything before
+# this line, and then unpack it by entering "sh file".  Note, it may
+# create directories; files and directories will be owned by you and
+# have default permissions.
+#
+# This archive contains:
+#
+#      cpp5.c
+#      cpp6.c
+#
+echo x - cpp5.c
+sed 's/^X//' >cpp5.c << 'END-of-cpp5.c'
+X/*
+X *                        C P P 5 . C
+X *            E x p r e s s i o n   E v a l u a t i o n
+X *
+X * Edit History
+X * 31-Aug-84  MM      USENET net.sources release
+X * 04-Oct-84  MM      __LINE__ and __FILE__ must call ungetstring()
+X *                    so they work correctly with token concatenation.
+X *                    Added string formal recognition.
+X * 25-Oct-84  MM      "Short-circuit" evaluate #if's so that we
+X *                    don't print unnecessary error messages for
+X *                    #if !defined(FOO) && FOO != 0 && 10 / FOO ...
+X * 31-Oct-84  ado/MM  Added token concatenation
+X *  6-Nov-84  MM      Split from #define stuff, added sizeof stuff
+X * 19-Nov-84  ado     #if error returns TRUE for (sigh) compatibility
+X */
+X
+X#include      <stdio.h>
+X#include      <ctype.h>
+X#include      "cppdef.h"
+X#include      "cpp.h"
+X
+X/*
+X * Evaluate an #if expression.
+X */
+X
+Xstatic char   *opname[] = {           /* For debug and error messages */
+X"end of expression", "val", "id",
+X  "+",   "-",  "*",  "/",  "%",
+X  "<<", ">>",  "&",  "|",  "^",
+X  "==", "!=",  "<", "<=", ">=",  ">",
+X  "&&", "||",  "?",  ":",  ",",
+X  "unary +", "unary -", "~", "!",  "(",  ")", "(none)",
+X};
+X
+X/*
+X * opdope[] has the operator precedence:
+X *     Bits
+X *      7     Unused (so the value is always positive)
+X *    6-2     Precedence (000x .. 017x)
+X *    1-0     Binary op. flags:
+X *        01  The binop flag should be set/cleared when this op is seen.
+X *        10  The new value of the binop flag.
+X * Note:  Expected, New binop
+X * constant   0       1       Binop, end, or ) should follow constants
+X * End of line        1       0       End may not be preceeded by an operator
+X * binary     1       0       Binary op follows a value, value follows.
+X * unary      0       0       Unary op doesn't follow a value, value follows
+X *   (                0       0       Doesn't follow value, value or unop follows
+X *   )                1       1       Follows value.  Op follows.
+X */
+X
+Xstatic char   opdope[OP_MAX] = {
+X  0001,                                       /* End of expression            */
+X  0002,                                       /* Digit                        */
+X  0000,                                       /* Letter (identifier)          */
+X  0141, 0141, 0151, 0151, 0151,               /* ADD, SUB, MUL, DIV, MOD      */
+X  0131, 0131, 0101, 0071, 0071,               /* ASL, ASR, AND,  OR, XOR      */
+X  0111, 0111, 0121, 0121, 0121,       0121,   /*  EQ,  NE,  LT,  LE,  GE,  GT */
+X  0061, 0051, 0041, 0041, 0031,               /* ANA, ORO, QUE, COL, CMA      */
+X/*
+X * Unary op's follow
+X */
+X  0160, 0160, 0160, 0160,             /* NEG, PLU, COM, NOT           */
+X  0170, 0013, 0023,                   /* LPA, RPA, END                */
+X};
+X/*
+X * OP_QUE and OP_RPA have alternate precedences:
+X */
+X#define       OP_RPA_PREC     0013
+X#define OP_QUE_PREC   0034
+X
+X/*
+X * S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that
+X *    #if FOO != 0 && 10 / FOO ...
+X * doesn't generate an error message.  They are stored in optab.skip.
+X */
+X#define S_ANDOR               2
+X#define S_QUEST               1
+X
+Xtypedef struct optab {
+X    char      op;                     /* Operator                     */
+X    char      prec;                   /* Its precedence               */
+X    char      skip;                   /* Short-circuit: TRUE to skip  */
+X} OPTAB;
+Xstatic int    evalue;                 /* Current value from evallex() */
+X
+X#ifdef        nomacargs
+XFILE_LOCAL int
+Xisbinary(op)
+Xregister int  op;
+X{
+X      return (op >= FIRST_BINOP && op <= LAST_BINOP);
+X}
+X
+XFILE_LOCAL int
+Xisunary(op)
+Xregister int  op;
+X{
+X      return (op >= FIRST_UNOP && op <= LAST_UNOP);
+X}
+X#else
+X#define       isbinary(op)    (op >= FIRST_BINOP && op <= LAST_BINOP)
+X#define       isunary(op)     (op >= FIRST_UNOP  && op <= LAST_UNOP)
+X#endif
+X\f
+X/*
+X * The following definitions are used to specify basic variable sizes.
+X */
+X
+X#ifndef       S_CHAR
+X#define       S_CHAR          (sizeof (char))
+X#endif
+X#ifndef       S_SINT
+X#define       S_SINT          (sizeof (short int))
+X#endif
+X#ifndef       S_INT
+X#define       S_INT           (sizeof (int))
+X#endif
+X#ifndef       S_LINT
+X#define       S_LINT          (sizeof (long int))
+X#endif
+X#ifndef       S_FLOAT
+X#define       S_FLOAT         (sizeof (float))
+X#endif
+X#ifndef       S_DOUBLE
+X#define       S_DOUBLE        (sizeof (double))
+X#endif
+X#ifndef       S_PCHAR
+X#define       S_PCHAR         (sizeof (char *))
+X#endif
+X#ifndef       S_PSINT
+X#define       S_PSINT         (sizeof (short int *))
+X#endif
+X#ifndef       S_PINT
+X#define       S_PINT          (sizeof (int *))
+X#endif
+X#ifndef       S_PLINT
+X#define       S_PLINT         (sizeof (long int *))
+X#endif
+X#ifndef       S_PFLOAT
+X#define       S_PFLOAT        (sizeof (float *))
+X#endif
+X#ifndef       S_PDOUBLE
+X#define       S_PDOUBLE       (sizeof (double *))
+X#endif
+X#ifndef       S_PFPTR
+X#define S_PFPTR               (sizeof (int (*)()))
+X#endif
+X\f
+Xtypedef struct types {
+X    short     type;                   /* This is the bit if           */
+X    char      *name;                  /* this is the token word       */
+X} TYPES;
+X
+Xstatic TYPES basic_types[] = {
+X      { T_CHAR,       "char",         },
+X      { T_INT,        "int",          },
+X      { T_FLOAT,      "float",        },
+X      { T_DOUBLE,     "double",       },
+X      { T_SHORT,      "short",        },
+X      { T_LONG,       "long",         },
+X      { T_SIGNED,     "signed",       },
+X      { T_UNSIGNED,   "unsigned",     },
+X      { 0,            NULL,           },      /* Signal end           */
+X};
+X
+X/*
+X * Test_table[] is used to test for illegal combinations.
+X */
+Xstatic short test_table[] = {
+X      T_FLOAT | T_DOUBLE | T_LONG | T_SHORT,
+X      T_FLOAT | T_DOUBLE | T_CHAR | T_INT,
+X      T_FLOAT | T_DOUBLE | T_SIGNED | T_UNSIGNED,
+X      T_LONG  | T_SHORT  | T_CHAR,
+X      0                                               /* end marker   */
+X};
+X
+X/*
+X * The order of this table is important -- it is also referenced by
+X * the command line processor to allow run-time overriding of the
+X * built-in size values.  The order must not be changed:
+X *    char, short, int, long, float, double (func pointer)
+X */
+XSIZES size_table[] = {
+X    { T_CHAR, S_CHAR,         S_PCHAR         },      /* char         */
+X    { T_SHORT,        S_SINT,         S_PSINT         },      /* short int    */
+X    { T_INT,  S_INT,          S_PINT          },      /* int          */
+X    { T_LONG, S_LINT,         S_PLINT         },      /* long         */
+X    { T_FLOAT,        S_FLOAT,        S_PFLOAT        },      /* float        */
+X    { T_DOUBLE,       S_DOUBLE,       S_PDOUBLE       },      /* double       */
+X    { T_FPTR, 0,              S_PFPTR         },      /* int (*())    */
+X    { 0,      0,              0               },      /* End of table */
+X};
+X\f
+Xint
+Xeval()
+X/*
+X * Evaluate an expression.  Straight-forward operator precedence.
+X * This is called from control() on encountering an #if statement.
+X * It calls the following routines:
+X * evallex    Lexical analyser -- returns the type and value of
+X *            the next input token.
+X * evaleval   Evaluate the current operator, given the values on
+X *            the value stack.  Returns a pointer to the (new)
+X *            value stack.
+X * For compatiblity with older cpp's, this return returns 1 (TRUE)
+X * if a syntax error is detected.
+X */
+X{
+X      register int    op;             /* Current operator             */
+X      register int    *valp;          /* -> value vector              */
+X      register OPTAB  *opp;           /* Operator stack               */
+X      int             prec;           /* Op precedence                */
+X      int             binop;          /* Set if binary op. needed     */
+X      int             op1;            /* Operand from stack           */
+X      int             skip;           /* For short-circuit testing    */
+X      int             value[NEXP];    /* Value stack                  */
+X      OPTAB           opstack[NEXP];  /* Operand stack                */
+X      extern int      *evaleval();    /* Does actual evaluation       */
+X
+X      valp = value;
+X      opp = opstack;
+X      opp->op = OP_END;               /* Mark bottom of stack         */
+X      opp->prec = opdope[OP_END];     /* And its precedence           */
+X      opp->skip = 0;                  /* Not skipping now             */
+X      binop = 0;
+Xagain:        ;
+X#ifdef        DEBUG_EVAL
+X      printf("In #if at again: skip = %d, binop = %d, line is: %s",
+X          opp->skip, binop, infile->bptr);
+X#endif
+X      if ((op = evallex(opp->skip)) == OP_SUB && binop == 0)
+X          op = OP_NEG;                        /* Unary minus          */
+X      else if (op == OP_ADD && binop == 0)
+X          op = OP_PLU;                        /* Unary plus           */
+X      else if (op == OP_FAIL)
+X          return (1);                         /* Error in evallex     */
+X#ifdef        DEBUG_EVAL
+X      printf("op = %s, opdope = %03o, binop = %d, skip = %d\n",
+X          opname[op], opdope[op], binop, opp->skip);
+X#endif
+X      if (op == DIG) {                        /* Value?               */
+X          if (binop != 0) {
+X              cerror("misplaced constant in #if", NULLST);
+X              return (1);
+X          }
+X          else if (valp >= &value[NEXP-1]) {
+X              cerror("#if value stack overflow", NULLST);
+X              return (1);
+X          }
+X          else {
+X#ifdef        DEBUG_EVAL
+X              printf("pushing %d onto value stack[%d]\n",
+X                  evalue, valp - value);
+X#endif
+X              *valp++ = evalue;
+X              binop = 1;
+X          }
+X          goto again;
+X      }
+X      else if (op > OP_END) {
+X          cerror("Illegal #if line", NULLST);
+X          return (1);
+X      }
+X      prec = opdope[op];
+X      if (binop != (prec & 1)) {
+X          cerror("Operator %s in incorrect context", opname[op]);
+X          return (1);
+X      }
+X      binop = (prec & 2) >> 1;
+X      for (;;) {
+X#ifdef        DEBUG_EVAL
+X          printf("op %s, prec %d., stacked op %s, prec %d, skip %d\n",
+X              opname[op], prec, opname[opp->op], opp->prec, opp->skip);
+X#endif
+X          if (prec > opp->prec) {
+X              if (op == OP_LPA)
+X                  prec = OP_RPA_PREC;
+X              else if (op == OP_QUE)
+X                  prec = OP_QUE_PREC;
+X              op1 = opp->skip;                /* Save skip for test   */
+X              /*
+X               * Push operator onto op. stack.
+X               */
+X              opp++;
+X              if (opp >= &opstack[NEXP]) {
+X                  cerror("expression stack overflow at op \"%s\"",
+X                      opname[op]);
+X                  return (1);
+X              }
+X              opp->op = op;
+X              opp->prec = prec;
+X              skip = (valp[-1] != 0);         /* Short-circuit tester */
+X              /*
+X               * Do the short-circuit stuff here.  Short-circuiting
+X               * stops automagically when operators are evaluated.
+X               */
+X              if ((op == OP_ANA && !skip)
+X               || (op == OP_ORO && skip))
+X                  opp->skip = S_ANDOR;        /* And/or skip starts   */
+X              else if (op == OP_QUE)          /* Start of ?: operator */
+X                  opp->skip = (op1 & S_ANDOR) | ((!skip) ? S_QUEST : 0);
+X              else if (op == OP_COL) {        /* : inverts S_QUEST    */
+X                  opp->skip = (op1 & S_ANDOR)
+X                            | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST);
+X              }
+X              else {                          /* Other ops leave      */
+X                  opp->skip = op1;            /*  skipping unchanged. */
+X              }
+X#ifdef        DEBUG_EVAL
+X              printf("stacking %s, valp[-1] == %d at %s",
+X                  opname[op], valp[-1], infile->bptr);
+X              dumpstack(opstack, opp, value, valp);
+X#endif
+X              goto again;
+X          }
+X          /*
+X           * Pop operator from op. stack and evaluate it.
+X           * End of stack and '(' are specials.
+X           */
+X          skip = opp->skip;                   /* Remember skip value  */
+X          switch ((op1 = opp->op)) {          /* Look at stacked op   */
+X          case OP_END:                        /* Stack end marker     */
+X              if (op == OP_EOE)
+X                  return (valp[-1]);          /* Finished ok.         */
+X              goto again;                     /* Read another op.     */
+X
+X          case OP_LPA:                        /* ( on stack           */
+X              if (op != OP_RPA) {             /* Matches ) on input   */
+X                  cerror("unbalanced paren's, op is \"%s\"", opname[op]);
+X                  return (1);
+X              }
+X              opp--;                          /* Unstack it           */
+X              /* goto again;                  -- Fall through         */
+X
+X          case OP_QUE:
+X              goto again;                     /* Evaluate true expr.  */
+X
+X          case OP_COL:                        /* : on stack.          */
+X              opp--;                          /* Unstack :            */
+X              if (opp->op != OP_QUE) {        /* Matches ? on stack?  */
+X                  cerror("Misplaced '?' or ':', previous operator is %s",
+X                      opname[opp->op]);
+X                  return (1);
+X              }
+X              /*
+X               * Evaluate op1.
+X               */
+X          default:                            /* Others:              */
+X              opp--;                          /* Unstack the operator */
+X#ifdef        DEBUG_EVAL
+X              printf("Stack before evaluation of %s\n", opname[op1]);
+X              dumpstack(opstack, opp, value, valp);
+X#endif
+X              valp = evaleval(valp, op1, skip);
+X#ifdef        DEBUG_EVAL
+X              printf("Stack after evaluation\n");
+X              dumpstack(opstack, opp, value, valp);
+X#endif
+X          }                                   /* op1 switch end       */
+X      }                                       /* Stack unwind loop    */
+X}
+X\f
+XFILE_LOCAL int
+Xevallex(skip)
+Xint           skip;           /* TRUE if short-circuit evaluation     */
+X/*
+X * Return next eval operator or value.  Called from eval().  It
+X * calls a special-purpose routines for 'char' strings and
+X * numeric values:
+X * evalchar   called to evaluate 'x'
+X * evalnum    called to evaluate numbers.
+X */
+X{
+X      register int    c, c1, t;
+X
+Xagain:  do {                                  /* Collect the token    */
+X          c = skipws();
+X          if ((c = macroid(c)) == EOF_CHAR || c == '\n') {
+X              unget();
+X              return (OP_EOE);                /* End of expression    */
+X          }
+X      } while ((t = type[c]) == LET && catenate());
+X      if (t == INV) {                         /* Total nonsense       */
+X          if (!skip) {
+X              if (isascii(c) && isprint(c))
+X                  cierror("illegal character '%c' in #if", c);
+X              else
+X                  cierror("illegal character (%d decimal) in #if", c);
+X          }
+X          return (OP_FAIL);
+X      }
+X      else if (t == QUO) {                    /* ' or "               */
+X          if (c == '\'') {                    /* Character constant   */
+X              evalue = evalchar(skip);        /* Somewhat messy       */
+X#ifdef        DEBUG_EVAL
+X              printf("evalchar returns %d.\n", evalue);
+X#endif
+X              return (DIG);                   /* Return a value       */
+X          }
+X          cerror("Can't use a string in an #if", NULLST);
+X          return (OP_FAIL);
+X      }
+X      else if (t == LET) {                    /* ID must be a macro   */
+X          if (streq(token, "defined")) {      /* Or defined name      */
+X              c1 = c = skipws();
+X              if (c == '(')                   /* Allow defined(name)  */
+X                  c = skipws();
+X              if (type[c] == LET) {
+X                  evalue = (lookid(c) != NULL);
+X                  if (c1 != '('               /* Need to balance      */
+X                   || skipws() == ')')        /* Did we balance?      */
+X                      return (DIG);           /* Parsed ok            */
+X              }
+X              cerror("Bad #if ... defined() syntax", NULLST);
+X              return (OP_FAIL);
+X          }
+X          else if (streq(token, "sizeof"))    /* New sizeof hackery   */
+X              return (dosizeof());            /* Gets own routine     */
+X          /*
+X           * The Draft ANSI C Standard says that an undefined symbol
+X           * in an #if has the value zero.  We are a bit pickier,
+X           * warning except where the programmer was careful to write
+X           *          #if defined(foo) ? foo : 0
+X           */
+X#ifdef VERBOSE
+X           if (!skip)
+X              cwarn("undefined symbol \"%s\" in #if, 0 used", token);
+X#endif
+X          evalue = 0;
+X          return (DIG);
+X      }
+X      else if (t == DIG) {                    /* Numbers are harder   */
+X          evalue = evalnum(c);
+X#ifdef        DEBUG_EVAL
+X          printf("evalnum returns %d.\n", evalue);
+X#endif
+X      }
+X      else if (strchr("!=<>&|\\", c) != NULL) {
+X          /*
+X           * Process a possible multi-byte lexeme.
+X           */
+X          c1 = cget();                        /* Peek at next char    */
+X          switch (c) {
+X          case '!':
+X              if (c1 == '=')
+X                  return (OP_NE);
+X              break;
+X
+X          case '=':
+X              if (c1 != '=') {                /* Can't say a=b in #if */
+X                  unget();
+X                  cerror("= not allowed in #if", NULLST);
+X                  return (OP_FAIL);
+X              }
+X              return (OP_EQ);
+X
+X          case '>':
+X          case '<':
+X              if (c1 == c)
+X                  return ((c == '<') ? OP_ASL : OP_ASR);
+X              else if (c1 == '=')
+X                  return ((c == '<') ? OP_LE  : OP_GE);
+X              break;
+X
+X          case '|':
+X          case '&':
+X              if (c1 == c)
+X                  return ((c == '|') ? OP_ORO : OP_ANA);
+X              break;
+X
+X          case '\\':
+X              if (c1 == '\n')                 /* Multi-line if        */
+X                  goto again;
+X              cerror("Unexpected \\ in #if", NULLST);
+X              return (OP_FAIL);
+X          }
+X          unget();
+X      }
+X      return (t);
+X}
+X\f
+XFILE_LOCAL int
+Xdosizeof()
+X/*
+X * Process the sizeof (basic type) operation in an #if string.
+X * Sets evalue to the size and returns
+X *    DIG             success
+X *    OP_FAIL         bad parse or something.
+X */
+X{
+X      register int    c;
+X      register TYPES  *tp;
+X      register SIZES  *sizp;
+X      register short  *testp;
+X      short           typecode;
+X
+X      if ((c = skipws()) != '(')
+X          goto nogood;
+X      /*
+X       * Scan off the tokens.
+X       */
+X      typecode = 0;
+X      while ((c = skipws())) {
+X          if ((c = macroid(c)) == EOF_CHAR || c == '\n')
+X              goto nogood;                    /* End of line is a bug */
+X          else if (c == '(') {                /* thing (*)() func ptr */
+X              if (skipws() == '*'
+X               && skipws() == ')') {          /* We found (*)         */
+X                  if (skipws() != '(')        /* Let () be optional   */
+X                      unget();
+X                  else if (skipws() != ')')
+X                      goto nogood;
+X                  typecode |= T_FPTR;         /* Function pointer     */
+X              }
+X              else {                          /* Junk is a bug        */
+X                  goto nogood;
+X              }
+X          }
+X          else if (type[c] != LET)            /* Exit if not a type   */
+X              break;
+X          else if (!catenate()) {             /* Maybe combine tokens */
+X              /*
+X               * Look for this unexpandable token in basic_types.
+X               * The code accepts "int long" as well as "long int"
+X               * which is a minor bug as bugs go (and one shared with
+X               * a lot of C compilers).
+X               */
+X              for (tp = basic_types; tp->name != NULLST; tp++) {
+X                  if (streq(token, tp->name))
+X                      break;
+X              }
+X              if (tp->name == NULLST) {
+X                  cerror("#if sizeof, unknown type \"%s\"", token);
+X                  return (OP_FAIL);
+X              }
+X              typecode |= tp->type;           /* Or in the type bit   */
+X          }
+X      }
+X      /*
+X       * We are at the end of the type scan.  Chew off '*' if necessary.
+X       */
+X      if (c == '*') {
+X          typecode |= T_PTR;
+X          c = skipws();
+X      }
+X      if (c == ')') {                         /* Last syntax check    */
+X          for (testp = test_table; *testp != 0; testp++) {
+X              if (!bittest(typecode & *testp)) {
+X                  cerror("#if ... sizeof: illegal type combination", NULLST);
+X                  return (OP_FAIL);
+X              }
+X          }
+X          /*
+X           * We assume that all function pointers are the same size:
+X           *          sizeof (int (*)()) == sizeof (float (*)())
+X           * We assume that signed and unsigned don't change the size:
+X           *          sizeof (signed int) == (sizeof unsigned int)
+X           */
+X          if ((typecode & T_FPTR) != 0)       /* Function pointer     */
+X              typecode = T_FPTR | T_PTR;
+X          else {                              /* Var or var * datum   */
+X              typecode &= ~(T_SIGNED | T_UNSIGNED);
+X              if ((typecode & (T_SHORT | T_LONG)) != 0)
+X                  typecode &= ~T_INT;
+X          }
+X          if ((typecode & ~T_PTR) == 0) {
+X              cerror("#if sizeof() error, no type specified", NULLST);
+X              return (OP_FAIL);
+X          }
+X          /*
+X           * Exactly one bit (and possibly T_PTR) may be set.
+X           */
+X          for (sizp = size_table; sizp->bits != 0; sizp++) {
+X              if ((typecode & ~T_PTR) == sizp->bits) {
+X                  evalue = ((typecode & T_PTR) != 0)
+X                      ? sizp->psize : sizp->size;
+X                  return (DIG);
+X              }
+X          }                                   /* We shouldn't fail    */
+X          cierror("#if ... sizeof: bug, unknown type code 0x%x", typecode);
+X          return (OP_FAIL);
+X      }
+X
+Xnogood:       unget();
+X      cerror("#if ... sizeof() syntax error", NULLST);
+X      return (OP_FAIL);
+X}
+X
+XFILE_LOCAL int
+Xbittest(value)
+X/*
+X * TRUE if value is zero or exactly one bit is set in value.
+X */
+X{
+X#if (4096 & ~(-4096)) == 0
+X      return ((value & ~(-value)) == 0);
+X#else
+X      /*
+X       * Do it the hard way (for non 2's complement machines)
+X       */
+X      return (value == 0 || value ^ (value - 1) == (value * 2 - 1));
+X#endif
+X}
+X\f
+XFILE_LOCAL int
+Xevalnum(c)
+Xregister int  c;
+X/*
+X * Expand number for #if lexical analysis.  Note: evalnum recognizes
+X * the unsigned suffix, but only returns a signed int value.
+X */
+X{
+X      register int    value;
+X      register int    base;
+X      register int    c1;
+X
+X      if (c != '0')
+X          base = 10;
+X      else if ((c = cget()) == 'x' || c == 'X') {
+X              base = 16;
+X              c = cget();
+X      }
+X      else base = 8;
+X      value = 0;
+X      for (;;) {
+X          c1 = c;
+X          if (isascii(c) && isupper(c1))
+X              c1 = tolower(c1);
+X          if (c1 >= 'a')
+X              c1 -= ('a' - 10);
+X          else c1 -= '0';
+X          if (c1 < 0 || c1 >= base)
+X              break;
+X          value *= base;
+X          value += c1;
+X          c = cget();
+X      }
+X      if (c == 'u' || c == 'U')       /* Unsigned nonsense            */
+X          c = cget();
+X      unget();
+X      return (value);
+X}
+X\f
+XFILE_LOCAL int
+Xevalchar(skip)
+Xint           skip;           /* TRUE if short-circuit evaluation     */
+X/*
+X * Get a character constant
+X */
+X{
+X      register int    c;
+X      register int    value;
+X      register int    count;
+X
+X      instring = TRUE;
+X      if ((c = cget()) == '\\') {
+X          switch ((c = cget())) {
+X          case 'a':                           /* New in Standard      */
+X#if ('a' == '\a' || '\a' == ALERT)
+X              value = ALERT;                  /* Use predefined value */
+X#else
+X              value = '\a';                   /* Use compiler's value */
+X#endif
+X              break;
+X
+X          case 'b':
+X              value = '\b';
+X              break;
+X
+X          case 'f':
+X              value = '\f';
+X              break;
+X
+X          case 'n':
+X              value = '\n';
+X              break;
+X
+X          case 'r':
+X              value = '\r';
+X              break;
+X
+X          case 't':
+X              value = '\t';
+X              break;
+X
+X          case 'v':                           /* New in Standard      */
+X#if ('v' == '\v' || '\v' == VT)
+X              value = VT;                     /* Use predefined value */
+X#else
+X              value = '\v';                   /* Use compiler's value */
+X#endif
+X              break;
+X
+X          case 'x':                           /* '\xFF'               */
+X              count = 3;
+X              value = 0;
+X              while ((((c = get()) >= '0' && c <= '9')
+X                   || (c >= 'a' && c <= 'f')
+X                   || (c >= 'A' && c <= 'F'))
+X                  && (--count >= 0)) {
+X                      value *= 16;
+X                      value += (c <= '9') ? (c - '0') : ((c & 0xF) + 9);
+X              }
+X              unget();
+X              break;
+X
+X          default:
+X              if (c >= '0' && c <= '7') {
+X                  count = 3;
+X                  value = 0;
+X                  while (c >= '0' && c <= '7' && --count >= 0) {
+X                      value *= 8;
+X                      value += (c - '0');
+X                      c = get();
+X                  }
+X                  unget();
+X              }
+X              else value = c;
+X              break;
+X          }
+X      }
+X      else if (c == '\'')
+X          value = 0;
+X      else value = c;
+X      /*
+X       * We warn on multi-byte constants and try to hack
+X       * (big|little)endian machines.
+X       */
+X#if BIG_ENDIAN
+X      count = 0;
+X#endif
+X      while ((c = get()) != '\'' && c != EOF_CHAR && c != '\n') {
+X          if (!skip)
+X              ciwarn("multi-byte constant '%c' isn't portable", c);
+X#if BIG_ENDIAN
+X          count += BITS_CHAR;
+X          value += (c << count);
+X#else
+X          value <<= BITS_CHAR;
+X          value += c;
+X#endif
+X      }
+X      instring = FALSE;
+X      return (value);
+X}
+X\f
+XFILE_LOCAL int *
+Xevaleval(valp, op, skip)
+Xregister int  *valp;
+Xint           op;
+Xint           skip;           /* TRUE if short-circuit evaluation     */
+X/*
+X * Apply the argument operator to the data on the value stack.
+X * One or two values are popped from the value stack and the result
+X * is pushed onto the value stack.
+X *
+X * OP_COL is a special case.
+X *
+X * evaleval() returns the new pointer to the top of the value stack.
+X */
+X{
+X      register int    v1, v2;
+X
+X      if (isbinary(op))
+X          v2 = *--valp;
+X      v1 = *--valp;
+X#ifdef        DEBUG_EVAL
+X      printf("%s op %s", (isbinary(op)) ? "binary" : "unary",
+X          opname[op]);
+X      if (isbinary(op))
+X          printf(", v2 = %d.", v2);
+X      printf(", v1 = %d.\n", v1);
+X#endif
+X      switch (op) {
+X      case OP_EOE:
+X           break;
+X
+X      case OP_ADD:
+X          v1 += v2;
+X          break;
+X
+X      case OP_SUB:
+X          v1 -= v2;
+X          break;
+X
+X      case OP_MUL:
+X          v1 *= v2;
+X          break;
+X
+X      case OP_DIV:
+X      case OP_MOD:
+X          if (v2 == 0) {
+X              if (!skip) {
+X                  cwarn("%s by zero in #if, zero result assumed",
+X                      (op == OP_DIV) ? "divide" : "mod");
+X              }
+X              v1 = 0;
+X          }
+X          else if (op == OP_DIV)
+X              v1 /= v2;
+X          else
+X              v1 %= v2;
+X          break;
+X
+X      case OP_ASL:
+X          v1 <<= v2;
+X          break;
+X
+X      case OP_ASR:
+X          v1 >>= v2;
+X          break;
+X
+X      case OP_AND:
+X          v1 &= v2;
+X          break;
+X
+X      case OP_OR:
+X          v1 |= v2;
+X          break;
+X
+X      case OP_XOR:
+X          v1 ^= v2;
+X          break;
+X
+X      case OP_EQ:
+X          v1 = (v1 == v2);
+X          break;
+X
+X      case OP_NE:
+X          v1 = (v1 != v2);
+X          break;
+X
+X      case OP_LT:
+X          v1 = (v1 < v2);
+X          break;
+X
+X      case OP_LE:
+X          v1 = (v1 <= v2);
+X          break;
+X
+X      case OP_GE:
+X          v1 = (v1 >= v2);
+X          break;
+X
+X      case OP_GT:
+X          v1 = (v1 > v2);
+X          break;
+X
+X      case OP_ANA:
+X          v1 = (v1 && v2);
+X          break;
+X
+X      case OP_ORO:
+X          v1 = (v1 || v2);
+X          break;
+X
+X      case OP_COL:
+X          /*
+X           * v1 has the "true" value, v2 the "false" value.
+X           * The top of the value stack has the test.
+X           */
+X          v1 = (*--valp) ? v1 : v2;
+X          break;
+X
+X      case OP_NEG:
+X          v1 = (-v1);
+X          break;
+X
+X      case OP_PLU:
+X          break;
+X
+X      case OP_COM:
+X          v1 = ~v1;
+X          break;
+X
+X      case OP_NOT:
+X          v1 = !v1;
+X          break;
+X
+X      default:
+X          cierror("#if bug, operand = %d.", op);
+X          v1 = 0;
+X      }
+X      *valp++ = v1;
+X      return (valp);
+X}
+X\f
+X#ifdef        DEBUG_EVAL
+Xdumpstack(opstack, opp, value, valp)
+XOPTAB         opstack[NEXP];  /* Operand stack                */
+Xregister OPTAB        *opp;           /* Operator stack               */
+Xint           value[NEXP];    /* Value stack                  */
+Xregister int  *valp;          /* -> value vector              */
+X{
+X      printf("index op prec skip name -- op stack at %s", infile->bptr);
+X      while (opp > opstack) {
+X          printf(" [%2d] %2d  %03o    %d %s\n", opp - opstack,
+X              opp->op, opp->prec, opp->skip, opname[opp->op]);
+X          opp--;
+X      }
+X      while (--valp >= value) {
+X          printf("value[%d] = %d\n", (valp - value), *valp);
+X      }
+X}
+X#endif
+X
+END-of-cpp5.c
+echo x - cpp6.c
+sed 's/^X//' >cpp6.c << 'END-of-cpp6.c'
+X/*
+X *                        C P P 6 . C
+X *            S u p p o r t   R o u t i n e s
+X *
+X * Edit History
+X * 25-May-84 MM               Added 8-bit support to type table.
+X * 30-May-84 ARF      sharp() should output filename in quotes
+X * 02-Aug-84 MM               Newline and #line hacking.  sharp() now in cpp1.c
+X * 31-Aug-84 MM               USENET net.sources release
+X * 11-Sep-84 ado/MM   Keepcomments, also line number pathological
+X * 12-Sep-84 ado/MM   bug if comment changes to space and we unget later.
+X * 03-Oct-84 gkr/MM   Fixed scannumber bug for '.e' (as in struct.element).
+X * 04-Oct-84 MM               Added ungetstring() for token concatenation
+X * 08-Oct-84 MM               Yet another attack on number scanning
+X * 31-Oct-84 ado      Parameterized $ in identifiers
+X *  2-Nov-84 MM               Token concatenation is messier than I thought
+X *  6-Dec-84 MM               \<nl> is everywhere invisible.
+X */
+X
+X#include      <stdio.h>
+X#include      <ctype.h>
+X#include      "cppdef.h"
+X#include      "cpp.h"
+X
+X/*
+X * skipnl()   skips over input text to the end of the line.
+X * skipws()   skips over "whitespace" (spaces or tabs), but
+X *            not skip over the end of the line.  It skips over
+X *            TOK_SEP, however (though that shouldn't happen).
+X * scanid()   reads the next token (C identifier) into token[].
+X *            The caller has already read the first character of
+X *            the identifier.  Unlike macroid(), the token is
+X *            never expanded.
+X * macroid()  reads the next token (C identifier) into token[].
+X *            If it is a #defined macro, it is expanded, and
+X *            macroid() returns TRUE, otherwise, FALSE.
+X * catenate() Does the dirty work of token concatenation, TRUE if it did.
+X * scanstring()       Reads a string from the input stream, calling
+X *            a user-supplied function for each character.
+X *            This function may be output() to write the
+X *            string to the output file, or save() to save
+X *            the string in the work buffer.
+X * scannumber()       Reads a C numeric constant from the input stream,
+X *            calling the user-supplied function for each
+X *            character.  (output() or save() as noted above.)
+X * save()     Save one character in the work[] buffer.
+X * savestring()       Saves a string in malloc() memory.
+X * getfile()  Initialize a new FILEINFO structure, called when
+X *            #include opens a new file, or a macro is to be
+X *            expanded.
+X * getmem()   Get a specified number of bytes from malloc memory.
+X * output()   Write one character to stdout (calling putchar) --
+X *            implemented as a function so its address may be
+X *            passed to scanstring() and scannumber().
+X * lookid()   Scans the next token (identifier) from the input
+X *            stream.  Looks for it in the #defined symbol table.
+X *            Returns a pointer to the definition, if found, or NULL
+X *            if not present.  The identifier is stored in token[].
+X * defnedel() Define enter/delete subroutine.  Updates the
+X *            symbol table.
+X * get()      Read the next byte from the current input stream,
+X *            handling end of (macro/file) input and embedded
+X *            comments appropriately.  Note that the global
+X *            instring is -- essentially -- a parameter to get().
+X * cget()     Like get(), but skip over TOK_SEP.
+X * unget()    Push last gotten character back on the input stream.
+X * cerror(), cwarn(), cfatal(), cierror(), ciwarn()
+X *            These routines format an print messages to the user.
+X *            cerror & cwarn take a format and a single string argument.
+X *            cierror & ciwarn take a format and a single int (char) argument.
+X *            cfatal takes a format and a single string argument.
+X */
+X\f
+X/*
+X * This table must be rewritten for a non-Ascii machine.
+X *
+X * Note that several "non-visible" characters have special meaning:
+X * Hex 1D DEF_MAGIC -- a flag to prevent #define recursion.
+X * Hex 1E TOK_SEP   -- a delimiter for token concatenation
+X * Hex 1F COM_SEP   -- a zero-width whitespace for comment concatenation
+X */
+X#if TOK_SEP != 0x1E || COM_SEP != 0x1F || DEF_MAGIC != 0x1D
+X      << error type table isn't correct >>
+X#endif
+X
+X#if OK_DOLLAR
+X#define       DOL     LET
+X#else
+X#define       DOL     000
+X#endif
+X
+Xchar type[256] = {            /* Character type codes    Hex          */
+X   END,   000,   000,   000,   000,   000,   000,   000, /* 00                */
+X   000,   SPA,   000,   000,   000,   000,   000,   000, /* 08                */
+X   000,   000,   000,   000,   000,   000,   000,   000, /* 10                */
+X   000,   000,   000,   000,   000,   LET,   000,   SPA, /* 18                */
+X   SPA,OP_NOT,   QUO,   000,   DOL,OP_MOD,OP_AND,   QUO, /* 20  !"#$%&'       */
+XOP_LPA,OP_RPA,OP_MUL,OP_ADD,   000,OP_SUB,   DOT,OP_DIV, /* 28 ()*+,-./       */
+X   DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG, /* 30 01234567       */
+X   DIG,   DIG,OP_COL,   000, OP_LT, OP_EQ, OP_GT,OP_QUE, /* 38 89:;<=>?       */
+X   000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 40 @ABCDEFG       */
+X   LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 48 HIJKLMNO       */
+X   LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 50 PQRSTUVW       */
+X   LET,   LET,   LET,   000,   BSH,   000,OP_XOR,   LET, /* 58 XYZ[\]^_       */
+X   000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 60 `abcdefg       */
+X   LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 68 hijklmno       */
+X   LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 70 pqrstuvw       */
+X   LET,   LET,   LET,   000, OP_OR,   000,OP_NOT,   000, /* 78 xyz{|}~        */
+X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF        */
+X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF        */
+X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF        */
+X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF        */
+X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF        */
+X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF        */
+X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF        */
+X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF        */
+X};
+X\f
+Xskipnl()
+X/*
+X * Skip to the end of the current input line.
+X */
+X{
+X      register int            c;
+X
+X      do {                            /* Skip to newline      */
+X          c = get();
+X      } while (c != '\n' && c != EOF_CHAR);
+X}
+X
+Xint
+Xskipws()
+X/*
+X * Skip over whitespace
+X */
+X{
+X      register int            c;
+X
+X      do {                            /* Skip whitespace      */
+X          c = get();
+X#if COMMENT_INVISIBLE
+X      } while (type[c] == SPA || c == COM_SEP);
+X#else
+X      } while (type[c] == SPA);
+X#endif
+X      return (c);
+X}
+X\f
+Xscanid(c)
+Xregister int  c;                              /* First char of id     */
+X/*
+X * Get the next token (an id) into the token buffer.
+X * Note: this code is duplicated in lookid().
+X * Change one, change both.
+X */
+X{
+X      register char   *bp;
+X
+X      if (c == DEF_MAGIC)                     /* Eat the magic token  */
+X          c = get();                          /* undefiner.           */
+X      bp = token;
+X      do {
+X          if (bp < &token[IDMAX])             /* token dim is IDMAX+1 */
+X              *bp++ = c;
+X          c = get();
+X      } while (type[c] == LET || type[c] == DIG);
+X      unget();
+X      *bp = EOS;
+X}
+X
+Xint
+Xmacroid(c)
+Xregister int          c;
+X/*
+X * If c is a letter, scan the id.  if it's #defined, expand it and scan
+X * the next character and try again.
+X *
+X * Else, return the character.  If type[c] is a LET, the token is in token.
+X */
+X{
+X      register DEFBUF *dp;
+X
+X      if (infile != NULL && infile->fp != NULL)
+X          recursion = 0;
+X      while (type[c] == LET && (dp = lookid(c)) != NULL) {
+X          expand(dp);
+X          c = get();
+X      }
+X      return (c);
+X}
+X\f
+Xint
+Xcatenate()
+X/*
+X * A token was just read (via macroid).
+X * If the next character is TOK_SEP, concatenate the next token
+X * return TRUE -- which should recall macroid after refreshing
+X * macroid's argument.  If it is not TOK_SEP, unget() the character
+X * and return FALSE.
+X */
+X{
+X      register int            c;
+X      register char           *token1;
+X
+X#if OK_CONCAT
+X      if (get() != TOK_SEP) {                 /* Token concatenation  */
+X          unget();
+X          return (FALSE);
+X      }
+X      else {
+X          token1 = savestring(token);         /* Save first token     */
+X          c = macroid(get());                 /* Scan next token      */
+X          switch(type[c]) {                   /* What was it?         */
+X          case LET:                           /* An identifier, ...   */
+X              if (strlen(token1) + strlen(token) >= NWORK)
+X                  cfatal("work buffer overflow doing %s #", token1);
+X              sprintf(work, "%s%s", token1, token);
+X              break;
+X
+X          case DIG:                           /* A digit string       */
+X              strcpy(work, token1);
+X              workp = work + strlen(work);
+X              do {
+X                  save(c);
+X              } while ((c = get()) != TOK_SEP);
+X              /*
+X               * The trailing TOK_SEP is no longer needed.
+X               */
+X              save(EOS);
+X              break;
+X
+X          default:                            /* An error, ...        */
+X              if (isprint(c))
+X                  cierror("Strange character '%c' after #", c);
+X              else
+X                  cierror("Strange character (%d.) after #", c);
+X              strcpy(work, token1);
+X              unget();
+X              break;
+X          }
+X          /*
+X           * work has the concatenated token and token1 has
+X           * the first token (no longer needed).  Unget the
+X           * new (concatenated) token after freeing token1.
+X           * Finally, setup to read the new token.
+X           */
+X          free(token1);                       /* Free up memory       */
+X          ungetstring(work);                  /* Unget the new thing, */
+X          return (TRUE);
+X      }
+X#else
+X      return (FALSE);                         /* Not supported        */
+X#endif
+X}
+X\f
+Xint
+Xscanstring(delim, outfun)
+Xregister int  delim;                  /* ' or "                       */
+Xint           (*outfun)();            /* Output function              */
+X/*
+X * Scan off a string.  Warning if terminated by newline or EOF.
+X * outfun() outputs the character -- to a buffer if in a macro.
+X * TRUE if ok, FALSE if error.
+X */
+X{
+X      register int            c;
+X
+X      instring = TRUE;                /* Don't strip comments         */
+X      (*outfun)(delim);
+X      while ((c = get()) != delim
+X           && c != '\n'
+X           && c != EOF_CHAR) {
+X          (*outfun)(c);
+X          if (c == '\\')
+X              (*outfun)(get());
+X      }
+X      instring = FALSE;
+X      if (c == delim) {
+X          (*outfun)(c);
+X          return (TRUE);
+X      }
+X      else {
+X          cerror("Unterminated string", NULLST);
+X          unget();
+X          return (FALSE);
+X      }
+X}
+X\f
+Xscannumber(c, outfun)
+Xregister int  c;                              /* First char of number */
+Xregister int  (*outfun)();                    /* Output/store func    */
+X/*
+X * Process a number.  We know that c is from 0 to 9 or dot.
+X * Algorithm from Dave Conroy's Decus C.
+X */
+X{
+X      register int    radix;                  /* 8, 10, or 16         */
+X      int             expseen;                /* 'e' seen in floater  */
+X      int             signseen;               /* '+' or '-' seen      */
+X      int             octal89;                /* For bad octal test   */
+X      int             dotflag;                /* TRUE if '.' was seen */
+X
+X      expseen = FALSE;                        /* No exponent seen yet */
+X      signseen = TRUE;                        /* No +/- allowed yet   */
+X      octal89 = FALSE;                        /* No bad octal yet     */
+X      radix = 10;                             /* Assume decimal       */
+X      if ((dotflag = (c == '.')) != FALSE) {  /* . something?         */
+X          (*outfun)('.');                     /* Always out the dot   */
+X          if (type[(c = get())] != DIG) {     /* If not a float numb, */
+X              unget();                        /* Rescan strange char  */
+X              return;                         /* All done for now     */
+X          }
+X      }                                       /* End of float test    */
+X      else if (c == '0') {                    /* Octal or hex?        */
+X          (*outfun)(c);                       /* Stuff initial zero   */
+X          radix = 8;                          /* Assume it's octal    */
+X          c = get();                          /* Look for an 'x'      */
+X          if (c == 'x' || c == 'X') {         /* Did we get one?      */
+X              radix = 16;                     /* Remember new radix   */
+X              (*outfun)(c);                   /* Stuff the 'x'        */
+X              c = get();                      /* Get next character   */
+X          }
+X      }
+X      for (;;) {                              /* Process curr. char.  */
+X          /*
+X           * Note that this algorithm accepts "012e4" and "03.4"
+X           * as legitimate floating-point numbers.
+X           */
+X          if (radix != 16 && (c == 'e' || c == 'E')) {
+X              if (expseen)                    /* Already saw 'E'?     */
+X                  break;                      /* Exit loop, bad nbr.  */
+X              expseen = TRUE;                 /* Set exponent seen    */
+X              signseen = FALSE;               /* We can read '+' now  */
+X              radix = 10;                     /* Decimal exponent     */
+X          }
+X          else if (radix != 16 && c == '.') {
+X              if (dotflag)                    /* Saw dot already?     */
+X                  break;                      /* Exit loop, two dots  */
+X              dotflag = TRUE;                 /* Remember the dot     */
+X              radix = 10;                     /* Decimal fraction     */
+X          }
+X          else if (c == '+' || c == '-') {    /* 1.0e+10              */
+X              if (signseen)                   /* Sign in wrong place? */
+X                  break;                      /* Exit loop, not nbr.  */
+X              /* signseen = TRUE; */          /* Remember we saw it   */
+X          }
+X          else {                              /* Check the digit      */
+X              switch (c) {
+X              case '8': case '9':             /* Sometimes wrong      */
+X                  octal89 = TRUE;             /* Do check later       */
+X              case '0': case '1': case '2': case '3':
+X              case '4': case '5': case '6': case '7':
+X                  break;                      /* Always ok            */
+X
+X              case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+X              case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+X                  if (radix == 16)            /* Alpha's are ok only  */
+X                      break;                  /* if reading hex.      */
+X              default:                        /* At number end        */
+X                  goto done;                  /* Break from for loop  */
+X              }                               /* End of switch        */
+X          }                                   /* End general case     */
+X          (*outfun)(c);                       /* Accept the character */
+X          signseen = TRUE;                    /* Don't read sign now  */
+X          c = get();                          /* Read another char    */
+X      }                                       /* End of scan loop     */
+X      /*
+X       * When we break out of the scan loop, c contains the first
+X       * character (maybe) not in the number.  If the number is an
+X       * integer, allow a trailing 'L' for long and/or a trailing 'U'
+X       * for unsigned.  If not those, push the trailing character back
+X       * on the input stream.  Floating point numbers accept a trailing
+X       * 'L' for "long double".
+X       */
+Xdone: if (dotflag || expseen) {               /* Floating point?      */
+X          if (c == 'l' || c == 'L') {
+X              (*outfun)(c);
+X              c = get();                      /* Ungotten later       */
+X          }
+X      }
+X      else {                                  /* Else it's an integer */
+X          /*
+X           * We know that dotflag and expseen are both zero, now:
+X           * dotflag signals "saw 'L'", and
+X           * expseen signals "saw 'U'".
+X           */
+X          for (;;) {
+X              switch (c) {
+X              case 'l':
+X              case 'L':
+X                  if (dotflag)
+X                      goto nomore;
+X                  dotflag = TRUE;
+X                  break;
+X
+X              case 'u':
+X              case 'U':
+X                  if (expseen)
+X                      goto nomore;
+X                  expseen = TRUE;
+X                  break;
+X
+X              default:
+X                  goto nomore;
+X              }
+X              (*outfun)(c);                   /* Got 'L' or 'U'.      */
+X              c = get();                      /* Look at next, too.   */
+X          }
+X      }
+Xnomore:       unget();                                /* Not part of a number */
+X      if (octal89 && radix == 8)
+X          cwarn("Illegal digit in octal number", NULLST);
+X}
+X\f
+Xsave(c)
+Xregister int  c;
+X{
+X      if (workp >= &work[NWORK])
+X          cfatal("Work buffer overflow", NULLST);
+X      else *workp++ = c;
+X}
+X
+Xchar *
+Xsavestring(text)
+Xchar          *text;
+X/*
+X * Store a string into free memory.
+X */
+X{
+X      register char   *result;
+X
+X      result = getmem(strlen(text) + 1);
+X      strcpy(result, text);
+X      return (result);
+X}
+X
+XFILEINFO      *
+Xgetfile(bufsize, name)
+Xint           bufsize;                /* Line or define buffer size   */
+Xchar          *name;                  /* File or macro name string    */
+X/*
+X * Common FILEINFO buffer initialization for a new file or macro.
+X */
+X{
+X      register FILEINFO       *file;
+X      register int            size;
+X
+X      size = strlen(name);                    /* File/macro name      */
+X      file = (FILEINFO *) getmem(sizeof (FILEINFO) + bufsize + size);
+X      file->parent = infile;                  /* Chain files together */
+X      file->fp = NULL;                        /* No file yet          */
+X      file->filename = savestring(name);      /* Save file/macro name */
+X      file->progname = NULL;                  /* No #line seen yet    */
+X      file->unrecur = 0;                      /* No macro fixup       */
+X      file->bptr = file->buffer;              /* Initialize line ptr  */
+X      file->buffer[0] = EOS;                  /* Force first read     */
+X      file->line = 0;                         /* (Not used just yet)  */
+X      if (infile != NULL)                     /* If #include file     */
+X          infile->line = line;                /* Save current line    */
+X      infile = file;                          /* New current file     */
+X      line = 1;                               /* Note first line      */
+X      return (file);                          /* All done.            */
+X}
+X
+Xchar *
+Xgetmem(size)
+Xint           size;
+X/*
+X * Get a block of free memory.
+X */
+X{
+X      register char   *result;
+X      extern char     *malloc();
+X
+X      if ((result = malloc((unsigned) size)) == NULL)
+X          cfatal("Out of memory", NULLST);
+X      return (result);
+X}
+X\f
+X/*
+X *                    C P P   S y m b o l   T a b l e s
+X */
+X
+X/*
+X * SBSIZE defines the number of hash-table slots for the symbol table.
+X * It must be a power of 2.
+X */
+X#ifndef       SBSIZE
+X#define       SBSIZE  64
+X#endif
+X#define       SBMASK  (SBSIZE - 1)
+X#if (SBSIZE ^ SBMASK) != ((SBSIZE * 2) - 1)
+X      << error, SBSIZE must be a power of 2 >>
+X#endif
+X
+Xstatic DEFBUF *symtab[SBSIZE];        /* Symbol table queue headers   */
+X
+XDEFBUF *
+Xlookid(c)
+Xint   c;                              /* First character of token     */
+X/*
+X * Look for the next token in the symbol table.  Returns token in "token".
+X * If found, returns the table pointer;  Else returns NULL.
+X */
+X{
+X      register int            nhash;
+X      register DEFBUF         *dp;
+X      register char           *np;
+X      int                     temp;
+X      int                     isrecurse;      /* For #define foo foo  */
+X
+X      np = token;
+X      nhash = 0;
+X      if ((isrecurse = (c == DEF_MAGIC)))     /* If recursive macro   */
+X          c = get();                          /* hack, skip DEF_MAGIC */
+X      do {
+X          if (np < &token[IDMAX]) {           /* token dim is IDMAX+1 */
+X              *np++ = c;                      /* Store token byte     */
+X              nhash += c;                     /* Update hash value    */
+X          }
+X          c = get();                          /* And get another byte */
+X      } while (type[c] == LET || type[c] == DIG);
+X      unget();                                /* Rescan terminator    */
+X      *np = EOS;                              /* Terminate token      */
+X      if (isrecurse)                          /* Recursive definition */
+X          return (NULL);                      /* undefined just now   */
+X      nhash += (np - token);                  /* Fix hash value       */
+X      dp = symtab[nhash & SBMASK];            /* Starting bucket      */
+X      while (dp != (DEFBUF *) NULL) {         /* Search symbol table  */
+X          if (dp->hash == nhash               /* Fast precheck        */
+X           && (temp = strcmp(dp->name, token)) >= 0)
+X              break;
+X          dp = dp->link;                      /* Nope, try next one   */
+X      }
+X      return ((temp == 0) ? dp : NULL);
+X}
+X\f
+XDEFBUF *
+Xdefendel(name, delete)
+Xchar          *name;
+Xint           delete;                 /* TRUE to delete a symbol      */
+X/*
+X * Enter this name in the lookup table (delete = FALSE)
+X * or delete this name (delete = TRUE).
+X * Returns a pointer to the define block (delete = FALSE)
+X * Returns NULL if the symbol wasn't defined (delete = TRUE).
+X */
+X{
+X      register DEFBUF         *dp;
+X      register DEFBUF         **prevp;
+X      register char           *np;
+X      int                     nhash;
+X      int                     temp;
+X      int                     size;
+X
+X      for (nhash = 0, np = name; *np != EOS;)
+X          nhash += *np++;
+X      size = (np - name);
+X      nhash += size;
+X      prevp = &symtab[nhash & SBMASK];
+X      while ((dp = *prevp) != (DEFBUF *) NULL) {
+X          if (dp->hash == nhash
+X           && (temp = strcmp(dp->name, name)) >= 0) {
+X              if (temp > 0)
+X                  dp = NULL;                  /* Not found            */
+X              else {
+X                  *prevp = dp->link;          /* Found, unlink and    */
+X                  if (dp->repl != NULL)       /* Free the replacement */
+X                      free(dp->repl);         /* if any, and then     */
+X                  free((char *) dp);          /* Free the symbol      */
+X              }
+X              break;
+X          }
+X          prevp = &dp->link;
+X      }
+X      if (!delete) {
+X          dp = (DEFBUF *) getmem(sizeof (DEFBUF) + size);
+X          dp->link = *prevp;
+X          *prevp = dp;
+X          dp->hash = nhash;
+X          dp->repl = NULL;
+X          dp->nargs = 0;
+X          strcpy(dp->name, name);
+X      }
+X      return (dp);
+X}
+X\f
+X#if DEBUG
+X
+Xdumpdef(why)
+Xchar          *why;
+X{
+X      register DEFBUF         *dp;
+X      register DEFBUF         **syp;
+X
+X      printf("CPP symbol table dump %s\n", why);
+X      for (syp = symtab; syp < &symtab[SBSIZE]; syp++) {
+X          if ((dp = *syp) != (DEFBUF *) NULL) {
+X              printf("symtab[%d]\n", (syp - symtab));
+X              do {
+X                  dumpadef((char *) NULL, dp);
+X              } while ((dp = dp->link) != (DEFBUF *) NULL);
+X          }
+X      }
+X}
+X
+Xdumpadef(why, dp)
+Xchar          *why;                   /* Notation                     */
+Xregister DEFBUF       *dp;
+X{
+X      register char           *cp;
+X      register int            c;
+X
+X      printf(" \"%s\" [%d]", dp->name, dp->nargs);
+X      if (why != NULL)
+X          printf(" (%s)", why);
+X      if (dp->repl != NULL) {
+X          printf(" => ");
+X          for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;) {
+X              if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC))
+X                  printf("<%d>", c - MAC_PARM);
+X              else if (isprint(c) || c == '\n' || c == '\t')
+X                  putchar(c);
+X              else if (c < ' ')
+X                  printf("<^%c>", c + '@');
+X              else
+X                  printf("<\\0%o>", c);
+X          }
+X      }
+X      else {
+X          printf(", no replacement.");
+X      }
+X      putchar('\n');
+X}
+X#endif
+X\f
+X/*
+X *                    G E T
+X */
+X
+Xint
+Xget()
+X/*
+X * Return the next character from a macro or the current file.
+X * Handle end of file from #include files.
+X */
+X{
+X      register int            c;
+X      register FILEINFO       *file;
+X      register int            popped;         /* Recursion fixup      */
+X
+X      popped = 0;
+Xget_from_file:
+X      if ((file = infile) == NULL)
+X          return (EOF_CHAR);
+Xnewline:
+X#if 0
+X      printf("get(%s), recursion %d, line %d, bptr = %d, buffer \"%s\"\n",
+X          file->filename, recursion, line,
+X          file->bptr - file->buffer, file->buffer);
+X#endif
+X      /*
+X       * Read a character from the current input line or macro.
+X       * At EOS, either finish the current macro (freeing temp.
+X       * storage) or read another line from the current input file.
+X       * At EOF, exit the current file (#include) or, at EOF from
+X       * the cpp input file, return EOF_CHAR to finish processing.
+X       */
+X      if ((c = *file->bptr++ & 0xFF) == EOS) {
+X          /*
+X           * Nothing in current line or macro.  Get next line (if
+X           * input from a file), or do end of file/macro processing.
+X           * In the latter case, jump back to restart from the top.
+X           */
+X          if (file->fp == NULL) {             /* NULL if macro        */
+X              popped++;
+X              recursion -= file->unrecur;
+X              if (recursion < 0)
+X                  recursion = 0;
+X              infile = file->parent;          /* Unwind file chain    */
+X          }
+X          else {                              /* Else get from a file */
+X              if ((file->bptr = fgets(file->buffer, NBUFF, file->fp))
+X                      != NULL) {
+X#if DEBUG
+X                  if (debug > 1) {            /* Dump it to stdout    */
+X                      printf("\n#line %d (%s), %s",
+X                          line, file->filename, file->buffer);
+X                  }
+X#endif
+X                  goto newline;               /* process the line     */
+X              }
+X              else {
+X                  fclose(file->fp);           /* Close finished file  */
+X                  if ((infile = file->parent) != NULL) {
+X                      /*
+X                       * There is an "ungotten" newline in the current
+X                       * infile buffer (set there by doinclude() in
+X                       * cpp1.c).  Thus, we know that the mainline code
+X                       * is skipping over blank lines and will do a
+X                       * #line at its convenience.
+X                       */
+X                      wrongline = TRUE;       /* Need a #line now     */
+X                  }
+X              }
+X          }
+X          /*
+X           * Free up space used by the (finished) file or macro and
+X           * restart input from the parent file/macro, if any.
+X           */
+X          free(file->filename);               /* Free name and        */
+X          if (file->progname != NULL)         /* if a #line was seen, */
+X              free(file->progname);           /* free it, too.        */
+X          free((char *) file);                /* Free file space      */
+X          if (infile == NULL)                 /* If at end of file    */
+X              return (EOF_CHAR);              /* Return end of file   */
+X          line = infile->line;                /* Reset line number    */
+X          goto get_from_file;                 /* Get from the top.    */
+X      }
+X      /*
+X       * Common processing for the new character.
+X       */
+X      if (c == DEF_MAGIC && file->fp != NULL) /* Don't allow delete   */
+X          goto newline;                       /* from a file          */
+X      if (file->parent != NULL) {             /* Macro or #include    */
+X          if (popped != 0)
+X              file->parent->unrecur += popped;
+X          else {
+X              recursion -= file->parent->unrecur;
+X              if (recursion < 0)
+X                  recursion = 0;
+X              file->parent->unrecur = 0;
+X          }
+X      }
+X      if (c == '\n')                          /* Maintain current     */
+X          ++line;                             /* line counter         */
+X      if (instring)                           /* Strings just return  */
+X          return (c);                         /* the character.       */
+X      else if (c == '/') {                    /* Comment?             */
+X          instring = TRUE;                    /* So get() won't loop  */
+X          if ((c = get()) != '*') {           /* Next byte '*'?       */
+X              instring = FALSE;               /* Nope, no comment     */
+X              unget();                        /* Push the char. back  */
+X              return ('/');                   /* Return the slash     */
+X          }
+X          if (keepcomments) {                 /* If writing comments  */
+X              putchar('/');                   /* Write out the        */
+X              putchar('*');                   /*   initializer        */
+X          }
+X          for (;;) {                          /* Eat a comment        */
+X              c = get();
+Xtest:         if (keepcomments && c != EOF_CHAR)
+X                  cput(c);
+X              switch (c) {
+X              case EOF_CHAR:
+X                  cerror("EOF in comment", NULLST);
+X                  return (EOF_CHAR);
+X
+X              case '/':
+X                  if ((c = get()) != '*')     /* Don't let comments   */
+X                      goto test;              /* Nest.                */
+X#ifdef VERBOSE
+X                  cwarn("Nested comments", NULLST);
+X#endif
+X                                              /* Fall into * stuff    */
+X              case '*':
+X                  if ((c = get()) != '/')     /* If comment doesn't   */
+X                      goto test;              /* end, look at next    */
+X                  instring = FALSE;           /* End of comment,      */
+X                  if (keepcomments) {         /* Put out the comment  */
+X                      cput(c);                /* terminator, too      */
+X                  }
+X                  /*
+X                   * A comment is syntactically "whitespace" --
+X                   * however, there are certain strange sequences
+X                   * such as
+X                   *          #define foo(x)  (something)
+X                   *                  foo|* comment *|(123)
+X                   *       these are '/' ^           ^
+X                   * where just returning space (or COM_SEP) will cause
+X                   * problems.  This can be "fixed" by overwriting the
+X                   * '/' in the input line buffer with ' ' (or COM_SEP)
+X                   * but that may mess up an error message.
+X                   * So, we peek ahead -- if the next character is
+X                   * "whitespace" we just get another character, if not,
+X                   * we modify the buffer.  All in the name of purity.
+X                   */
+X                  if (*file->bptr == '\n'
+X                   || type[*file->bptr & 0xFF] == SPA)
+X                      goto newline;
+X#if COMMENT_INVISIBLE
+X                  /*
+X                   * Return magic (old-fashioned) syntactic space.
+X                   */
+X                  return ((file->bptr[-1] = COM_SEP));
+X#else
+X                  return ((file->bptr[-1] = ' '));
+X#endif
+X
+X              case '\n':                      /* we'll need a #line   */
+X                  if (!keepcomments)
+X                      wrongline = TRUE;       /* later...             */
+X              default:                        /* Anything else is     */
+X                  break;                      /* Just a character     */
+X              }                               /* End switch           */
+X          }                                   /* End comment loop     */
+X      }                                       /* End if in comment    */
+X      else if (!inmacro && c == '\\') {       /* If backslash, peek   */
+X          if ((c = get()) == '\n') {          /* for a <nl>.  If so,  */
+X              wrongline = TRUE;
+X              goto newline;
+X          }
+X          else {                              /* Backslash anything   */
+X              unget();                        /* Get it later         */
+X              return ('\\');                  /* Return the backslash */
+X          }
+X      }
+X      else if (c == '\f' || c == VT)          /* Form Feed, Vertical  */
+X          c = ' ';                            /* Tab are whitespace   */
+X      return (c);                             /* Just return the char */
+X}
+X\f
+Xunget()
+X/*
+X * Backup the pointer to reread the last character.  Fatal error
+X * (code bug) if we backup too far.  unget() may be called,
+X * without problems, at end of file.  Only one character may
+X * be ungotten.  If you need to unget more, call ungetstring().
+X */
+X{
+X      register FILEINFO       *file;
+X
+X      if ((file = infile) == NULL)
+X          return;                     /* Unget after EOF              */
+X      if (--file->bptr < file->buffer)
+X          cfatal("Too much pushback", NULLST);
+X      if (*file->bptr == '\n')        /* Ungetting a newline?         */
+X          --line;                     /* Unget the line number, too   */
+X}
+X
+Xungetstring(text)
+Xchar          *text;
+X/*
+X * Push a string back on the input stream.  This is done by treating
+X * the text as if it were a macro.
+X */
+X{
+X      register FILEINFO       *file;
+X      extern FILEINFO         *getfile();
+X
+X      file = getfile(strlen(text) + 1, "");
+X      strcpy(file->buffer, text);
+X}
+X
+Xint
+Xcget()
+X/*
+X * Get one character, absorb "funny space" after comments or
+X * token concatenation
+X */
+X{
+X      register int    c;
+X
+X      do {
+X          c = get();
+X#if COMMENT_INVISIBLE
+X      } while (c == TOK_SEP || c == COM_SEP);
+X#else
+X      } while (c == TOK_SEP);
+X#endif
+X      return (c);
+X}
+X\f
+X/*
+X * Error messages and other hacks.  The first byte of severity
+X * is 'S' for string arguments and 'I' for int arguments.  This
+X * is needed for portability with machines that have int's that
+X * are shorter than  char *'s.
+X */
+X
+Xstatic
+Xdomsg(severity, format, arg)
+Xchar          *severity;              /* "Error", "Warning", "Fatal"  */
+Xchar          *format;                /* Format for the error message */
+Xchar          *arg;                   /* Something for the message    */
+X/*
+X * Print filenames, macro names, and line numbers for error messages.
+X */
+X{
+X      register char           *tp;
+X      register FILEINFO       *file;
+X
+X      fprintf(stderr, "%sline %d, %s: ", MSG_PREFIX, line, &severity[1]);
+X      if (*severity == 'S')
+X          fprintf(stderr, format, arg);
+X      else
+X          fprintf(stderr, format, (int) arg);
+X      putc('\n', stderr);
+X      if ((file = infile) == NULL)
+X          return;                             /* At end of file       */
+X      if (file->fp != NULL) {
+X          tp = file->buffer;                  /* Print current file   */
+X          fprintf(stderr, "%s", tp);          /* name, making sure    */
+X          if (tp[strlen(tp) - 1] != '\n')     /* there's a newline    */
+X              putc('\n', stderr);
+X      }
+X      while ((file = file->parent) != NULL) { /* Print #includes, too */
+X          if (file->fp == NULL)
+X              fprintf(stderr, "from macro %s\n", file->filename);
+X          else {
+X              tp = file->buffer;
+X              fprintf(stderr, "from file %s, line %d:\n%s",
+X                  (file->progname != NULL)
+X                      ? file->progname : file->filename,
+X                  file->line, tp);
+X              if (tp[strlen(tp) - 1] != '\n')
+X                  putc('\n', stderr);
+X          }
+X      }
+X}
+X
+Xcerror(format, sarg)
+Xchar          *format;
+Xchar          *sarg;          /* Single string argument               */
+X/*
+X * Print a normal error message, string argument.
+X */
+X{
+X      domsg("SError", format, sarg);
+X      errors++;
+X}
+X
+Xcierror(format, narg)
+Xchar          *format;
+Xint           narg;           /* Single numeric argument              */
+X/*
+X * Print a normal error message, numeric argument.
+X */
+X{
+X      domsg("IError", format, (char *) narg);
+X      errors++;
+X}
+X
+Xcfatal(format, sarg)
+Xchar          *format;
+Xchar          *sarg;                  /* Single string argument       */
+X/*
+X * A real disaster
+X */
+X{
+X      domsg("SFatal error", format, sarg);
+X      exit(IO_ERROR);
+X}
+X
+Xcwarn(format, sarg)
+Xchar          *format;
+Xchar          *sarg;                  /* Single string argument       */
+X/*
+X * A non-fatal error, string argument.
+X */
+X{
+X      domsg("SWarning", format, sarg);
+X}
+X
+Xciwarn(format, narg)
+Xchar          *format;
+Xint           narg;                   /* Single numeric argument      */
+X/*
+X * A non-fatal error, numeric argument.
+X */
+X{
+X      domsg("IWarning", format, (char *) narg);
+X}
+X
+X
+X
+END-of-cpp6.c
+exit
diff --git a/sys/unix/depend.awk b/sys/unix/depend.awk
new file mode 100644 (file)
index 0000000..26a9489
--- /dev/null
@@ -0,0 +1,151 @@
+# depend.awk -- awk script used to construct makefile dependencies
+# for nethack's source files (`make depend' support for Makefile.src).
+#
+# usage:
+#   cd src ; nawk -f depend.awk ../include/*.h list-of-.c/.cpp-files
+#
+# This awk program scans each file in sequence, looking for lines beginning
+# with `#include "' and recording the name inside the quotes.  For .h files,
+# that's all it does.  For each .c file, it writes out a make rule for the
+# corresponding .o file; dependencies in nested header files are propagated
+# to the .o target.
+#
+# config.h and hack.h get special handling because of their heavy use;
+#      timestamps for them allow make to avoid rechecking dates on
+#      subsidiary headers for every source file;
+# extern.h gets special handling to avoid excessive recompilation
+#      during development;
+# patchlev.h gets special handling because it only exists on systems
+#      which consider filename patchlevel.h to be too long;
+# interp.c gets special handling because it usually doesn't exist; it's
+#      assumed to be the last #include in the file where it occurs.
+# win32api.h gets special handling because it only exists for some ports;
+#      it's assumed to be the last #include in the file where it occurs
+#
+BEGIN          { FS = "\""                     #for `#include "X"', $2 is X
+                 special[++sp_cnt] = "../include/config.h"
+                 special[++sp_cnt] = "../include/hack.h"
+                 alt_deps["../include/extern.h"] = ""
+                 alt_deps["../include/patchlev.h"] = ""
+                 alt_deps["interp.c"] = " #interp.c"   #comment it out
+                 alt_deps["../include/win32api.h"] = " #../include/win32api.h"
+               }
+FNR == 1       { output_dep()                  #finish previous file
+                 file = FILENAME               #setup for current file
+               }
+/^\#[ \t]*include[ \t]+\"/  {                  #find `#include "X"'
+                 incl = $2;
+                 #[3.4.0: gnomehack headers currently aren't in include]
+                 if (incl ~ /\.h$/) {
+                   if (incl ~ /^gn/)   # gnomehack special case
+                     incl = "../win/gnome/" incl
+                   else
+                     incl = "../include/" incl
+                 }
+                 deps[file] = deps[file] " " incl
+               }
+END            { output_dep() }                #finish the last file
+
+
+#
+# `file' has been fully scanned, so process it now; for .h files,
+# don't do anything (we've just been collecting their dependencies);
+# for .c files, output the `make' rule for corresponding .o file
+#
+function output_dep(                           targ)
+{
+  if (file ~ /\.cp*$/) {
+    #prior to very first .c|.cpp file, handle some special header file cases
+    if (!c_count++)
+      output_specials()
+    #construct object filename from source filename
+    targ = file;  sub("^.+/", "", targ);  sub("\\.cp*$", ".o", targ)
+    #format and write the collected dependencies
+    format_dep(targ, file)
+  }
+}
+
+#
+# handle some targets (config.h, hack.h) via special timestamping rules
+#
+function output_specials(                      i, sp, alt_sp)
+{
+  for (i = 1; i <= sp_cnt; i++) {
+    sp = special[i]
+    #change "../include/foo.h" first to "foo.h", then ultimately to "$(FOO_H)"
+    alt_sp = sp;  sub("^.+/", "", alt_sp)
+    print "#", alt_sp, "timestamp"     #output a `make' comment
+ #- sub("\\.", "_", alt_sp);  alt_sp = "$(" toupper(alt_sp) ")"
+ #+ Some nawks don't have toupper(), so hardwire these instead.
+    sub("config.h", "$(CONFIG_H)", alt_sp);  sub("hack.h", "$(HACK_H)", alt_sp);
+    format_dep(alt_sp, sp)             #output the target
+    print "\ttouch " alt_sp            #output a build command
+    alt_deps[sp] = alt_sp              #alternate dependency for depend()
+  }
+  print "#"
+}
+
+#
+# write a target and its dependency list in pretty-printed format;
+# if target's primary source file has a path prefix, also write build command
+#
+function format_dep(target, source,            n, i, list)
+{
+  split("", done)                      #``for (x in done) delete done[x]''
+  printf("%s:", target);  col = length(target) + 1
+  #- printf("\t");  col += 8 - (col % 8);
+  #- if (col == 8) { printf("\t"); col += 8 }
+  source = depend("", source, 0)
+  n = split(source, list, " +")
+  for (i = 2; i <= n; i++) {   #(leading whitespace yields empty 1st element)
+    if (col + length(list[i]) >= (i < n ? 78 : 80)) {
+      printf(" \\\n\t\t");  col = 16   #make a backslash+newline split
+    } else {
+      printf(" ");  col++;
+    }
+    printf("%s", list[i]);  col += length(list[i])
+  }
+  printf("\n")                         #terminate
+  #write build command if first source entry has non-include path prefix
+  source = list[2]
+  if (source ~ /\// && substr(source, 1, 11) != "../include/") {
+    if (source ~ /\.cpp$/ )
+      print "\t$(CXX) $(CXXFLAGS) -c " source
+    else if (source ~ /\/gnome\//)     # "../win/gnome/foo.c"
+      print "\t$(CC) $(CFLAGS) $(GNOMEINC) -c " source
+    else
+      print "\t$(CC) $(CFLAGS) -c " source
+  }
+}
+
+#
+# recursively add the dependencies for file `name' to string `inout'
+# (unless `skip', in which case we're only marking files as already done)
+#
+function depend(inout, name, skip,             n, i, list)
+{
+  if (!done[name]++) {
+    if (name in alt_deps) {    #some names have non-conventional dependencies
+      if (!skip) inout = inout " " alt_deps[name]
+      skip = 1
+    } else {                   #ordinary name
+      if (!skip) inout = inout " " name
+    }
+    if (name in deps) {
+ #-   n = split(deps[name], list, " +")
+ #-   for (i = 2; i <= n; i++) #(leading whitespace yields empty 1st element)
+ #-    inout = depend(inout, list[i], skip)
+ #+  At least one implementation of nawk handles the local array `list' wrong,
+ #+  so the clumsier substitute code below is used as a workaround.
+      list = deps[name];  sub("^ +", "", list)
+      while (list) {
+       match((list " "), " +");  i = RSTART;  n = RLENGTH
+       inout = depend(inout, substr(list, 1, i-1), skip)
+       list = substr(list, i+n)
+      }
+    }
+  }
+  return inout
+}
+
+#depend.awk#
diff --git a/sys/unix/nethack.sh b/sys/unix/nethack.sh
new file mode 100644 (file)
index 0000000..600e1da
--- /dev/null
@@ -0,0 +1,68 @@
+#!/bin/sh
+#      SCCS Id: @(#)nethack.sh 3.4     1990/02/26
+
+HACKDIR=/usr/games/lib/nethackdir
+export HACKDIR
+HACK=$HACKDIR/nethack
+MAXNROFPLAYERS=4
+
+# Since Nethack.ad is installed in HACKDIR, add it to XUSERFILESEARCHPATH
+case "x$XUSERFILESEARCHPATH" in
+x)     XUSERFILESEARCHPATH="$HACKDIR/%N.ad"
+       ;;
+*)     XUSERFILESEARCHPATH="$XUSERFILESEARCHPATH:$HACKDIR/%N.ad"
+       ;;
+esac
+export XUSERFILESEARCHPATH
+
+# see if we can find the full path name of PAGER, so help files work properly
+# assume that if someone sets up a special variable (HACKPAGER) for NetHack,
+# it will already be in a form acceptable to NetHack
+# ideas from brian@radio.astro.utoronto.ca
+if test \( "xxx$PAGER" != xxx \) -a \( "xxx$HACKPAGER" = xxx \)
+then
+
+       HACKPAGER=$PAGER
+
+#      use only the first word of the pager variable
+#      this prevents problems when looking for file names with trailing
+#      options, but also makes the options unavailable for later use from
+#      NetHack
+       for i in $HACKPAGER
+       do
+               HACKPAGER=$i
+               break
+       done
+
+       if test ! -f $HACKPAGER
+       then
+               IFS=:
+               for i in $PATH
+               do
+                       if test -f $i/$HACKPAGER
+                       then
+                               HACKPAGER=$i/$HACKPAGER
+                               export HACKPAGER
+                               break
+                       fi
+               done
+               IFS='   '
+       fi
+       if test ! -f $HACKPAGER
+       then
+               echo Cannot find $PAGER -- unsetting PAGER.
+               unset HACKPAGER
+               unset PAGER
+       fi
+fi
+
+
+cd $HACKDIR
+case $1 in
+       -s*)
+               exec $HACK "$@"
+               ;;
+       *)
+               exec $HACK "$@" $MAXNROFPLAYERS
+               ;;
+esac
diff --git a/sys/unix/setup.sh b/sys/unix/setup.sh
new file mode 100644 (file)
index 0000000..67579d5
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Copy files to their correct locations.
+#
+# If arguments are given, try symbolic link first.  This is not the default
+# so that most people will have the distribution versions stay around so
+# subsequent patches can be applied.  People who pay enough attention to
+# know there's a non-default behavior are assumed to pay enough attention
+# to keep distribution versions if they modify things.
+
+# Were we started from the top level?  Cope.
+if [ -f sys/unix/Makefile.top ]; then cd sys/unix; fi
+
+if [ $# -gt 0 ] ; then
+#      First, try to make a symbolic link.
+#
+       ln -s Makefile.top Makefile >/dev/null 2>&1
+       if [ $? -eq 0 ] ; then
+
+               echo "Lucky you!  Symbolic links."
+               rm -f Makefile
+
+               umask 0
+               ln -s sys/unix/Makefile.top ../../Makefile
+               ln -s ../sys/unix/Makefile.dat ../../dat/Makefile
+               ln -s ../sys/unix/Makefile.doc ../../doc/Makefile
+               ln -s ../sys/unix/Makefile.src ../../src/Makefile
+               ln -s ../sys/unix/Makefile.utl ../../util/Makefile
+               exit 0
+       fi
+fi
+
+#
+#      Otherwise...
+
+echo "Copying Makefiles."
+
+cp Makefile.top ../../Makefile
+cp Makefile.dat ../../dat/Makefile
+cp Makefile.doc ../../doc/Makefile
+cp Makefile.src ../../src/Makefile
+cp Makefile.utl ../../util/Makefile
diff --git a/sys/unix/snd86unx.shr b/sys/unix/snd86unx.shr
new file mode 100644 (file)
index 0000000..bfbae3f
--- /dev/null
@@ -0,0 +1,1064 @@
+# This is a shell archive.  Save it in a file, remove anything before
+# this line, and then unpack it by entering "sh file".  Note, it may
+# create directories; files and directories will be owned by you and
+# have default permissions.
+#
+# This archive contains:
+#
+#      READ.ME
+#      install.bsd
+#      spkr.7
+#      Makefile
+#      spkr.c
+#      spkr.h
+#      interp.c
+#      Files
+#      Install
+#      Master
+#      Name
+#      Node
+#      Remove
+#      Size
+#      System
+#      playtest
+#
+echo x - READ.ME
+sed 's/^X//' >READ.ME << 'END-of-READ.ME'
+X              Console Speaker Driver Package (v1.1)
+X
+X              by Eric S. Raymond (esr@snark.thyrsus.com)
+X
+XThis package gives 80386 machines running SVr3.2 or later the ability to play
+Xtunes on the console speaker.  It has been extended to 386BSD (and possibly
+XBSDI) by Andrew A. Chernov, and to SCO UNIX 3.2.4 (and possibly other VPIX
+Xsystems) by Andreas Arens.
+X
+XThe following files are contained in the kit:
+X
+XDocumentation and examples:
+XREAD.ME               -- this file
+Xspeaker.7     -- man page for the driver
+Xplaytest      -- test script exercising familiar tunes
+X
+XInstallable driver kit parts, for SVr3.2 or later:
+XFiles         -- list of driver package file locations
+XInstall               -- installation script for driver kit
+XMaster                -- mdevice entry for speaker driver
+XName          -- name entry foe speaker driver
+XNode          -- /dev node specification file
+XRemove                -- Driver removal script
+XSize          -- installation size data
+XSystem                -- sdevice entry for speaker driver
+X
+XDriver source code, for SVr3.2 or later and 386BSD:
+XMakefile      -- Makefile for driver code
+Xspkr.c                -- the driver source
+Xspeaker.h     -- ioctl interface file
+X
+XCommon source code:
+Xinterp.c      -- play string interpretation code
+X
+XFor SVr3.2 or later, simply type `make' and wait. Then type ./Install
+Xand follow its instructions. You will have to install the man pages by hand.
+XBe aware that the speaker.7 man page uses tbl(1) constructs.
+X
+XFor 386BSD, follow the installation instructions in install.bsd.
+X
+XFor SCO UNIX 3.2.4, no new kernel drivers are needed, and you need only
+Xcopy interp.c to your src directory and proceed with making NetHack, with
+XVPIX_MUSIC set in unixconf.h.
+X
+XInteresting tunes mailed to the author will be periodically posted in batches
+Xand added to the test script for future versions.
+X
+X                      Revision notes
+X
+X1.1 -- fixed minor bug in M[LSN] interpretation, added octave-tracking.
+X       Tweaked the playtest examples.
+END-of-READ.ME
+echo x - install.bsd
+sed 's/^X//' >install.bsd << 'END-of-install.bsd'
+XCopy spkr.c and interp.c to /sys/i386/isa
+XCopy spkr.h to /sys/sys
+X
+X-----------------------------------------------------------------------------
+X
+XFile /sys/i386/conf/YOUR_MACHINE_NAME
+Xadd following line:
+X
+Xpseudo-device   speaker
+X
+X-----------------------------------------------------------------------------
+X
+XFile /sys/i386/conf/files.i386
+Xadd following line:
+X
+Xi386/isa/spkr.c         optional speaker
+X
+X-----------------------------------------------------------------------------
+X
+XFile /sys/i386/i386/conf.c
+X[major number 20 (hex) is registered for spkr driver, don't change it]
+Xadd following code:
+X
+X#include "speaker.h"
+X#if NSPEAKER > 0
+Xint     spkropen(),spkrclose(),spkrwrite(),spkrioctl();
+X#else
+X#define spkropen  enxio
+X#define spkrclose enxio
+X#define spkrwrite enxio
+X#define spkrioctl enxio
+X#endif
+X      ...
+X
+Xstruct cdevsw cdevsw[] =
+X{
+X      ...
+X
+X      { spkropen,     spkrclose,      enxio,          spkrwrite,      /*20*/
+X        spkrioctl,    enxio,          enxio,          NULL,
+X        enxio,        enxio,          enxio },
+X      ...
+X
+X-----------------------------------------------------------------------------
+X
+XMake corresponding device:
+X
+X      mknod /dev/speaker c 32 0
+X
+X[major number 32 (20 hex) is registered for spkr driver, don't change it]
+X
+X-----------------------------------------------------------------------------
+X
+XGo to /sys/i386/conf and type
+X      config YOUR_MACHINE_NAME
+Xthen go to /sys/compile/YOUR_MACHINE_NAME and type
+X      make depend
+X      make
+X
+END-of-install.bsd
+echo x - spkr.7
+sed 's/^X//' >spkr.7 << 'END-of-spkr.7'
+X.TH SPKR 7
+X.SH NAME
+Xspkr \- console speaker device driver
+X.SH DESCRIPTION
+XThe speaker device driver allows applications to control the PC console
+Xspeaker on an IBM-PC-compatible machine running UNIX.
+X.PP
+XOnly one process may have this device open at any given time; open() and
+Xclose() are used to lock and relinquish it. An attempt to open() when
+Xanother process has the device locked will return -1 with an EBUSY error
+Xindication. Writes to the device are interpreted as 'play strings' in a
+Xsimple ASCII melody notation. An ioctl() for tone generation at arbitrary
+Xfrequencies is also supported.
+X.PP
+XSound-generation does \fInot\fR monopolize the processor; in fact, the driver
+Xspends most of its time sleeping while the PC hardware is emitting
+Xtones. Other processes may emit beeps while the driver is running.
+X.PP
+XApplications may call ioctl() on a speaker file descriptor to control the
+Xspeaker driver directly; definitions for the ioctl() interface are in
+Xsys/spkr.h. The tone_t structure used in these calls has two fields,
+Xspecifying a frequency (in hz) and a duration (in 1/100ths of a second).
+XA frequency of zero is interpreted as a rest.
+X.PP
+XAt present there are two such ioctls. SPKRTONE accepts a pointer to a
+Xsingle tone structure as third argument and plays it. SPKRTUNE accepts a
+Xpointer to the first of an array of tone structures and plays them in
+Xcontinuous sequence; this array must be terminated by a final member with
+Xa zero duration.
+X.PP
+XThe play-string language is modelled on the PLAY statement conventions of
+XIBM BASIC 2.0. The MB, MF and X primitives of PLAY are not useful in a UNIX 
+Xenvironment and are omitted. The `octave-tracking' feature is also new.
+X.PP
+XThere are 84 accessible notes numbered 1-83 in 7 octaves, each running from
+XC to B, numbered 0-6; the scale is equal-tempered A440 and octave 3 starts
+Xwith middle C. By default, the play function emits half-second notes with the
+Xlast 1/16th second being `rest time'.
+X.PP
+XPlay strings are interpreted left to right as a series of play command groups;
+Xletter case is ignored. Play command groups are as follows:
+X.PP
+XCDEFGAB -- letters A through G cause the corresponding note to be played in the
+Xcurrent octave. A note letter may optionally be followed by an \fIaccidental
+Xsign\fR, one of # + or -; the first two of these cause it to be sharped one
+Xhalf-tone, the last causes it to be flatted one half-tone. It may also be
+Xfollowed by a time value number and by sustain dots (see below). Time values
+Xare interpreted as for the L command below;.
+X.PP
+XO <n> -- if <n> is numeric, this sets the current octave. <n> may also be one
+Xof 'L' or 'N' to enable or disable octave-tracking (it is disabled by default).
+XWhen octave-tracking is on, interpretation of a pair of letter notes will
+Xchange octaves if necessary in order to make the smallest possible jump between
+Xnotes. Thus "olbc" will be played as "olb>c", and "olcb" as "olc<b". Octave
+Xlocking is disabled for one letter note following by >, < and O[0123456].
+X.PP
+X> -- bump the current octave up one.
+X.PP
+X< -- drop the current octave down one.
+X.PP
+XN <n> -- play note n, n being 1 to 84 or 0 for a rest of current time value.
+XMay be followedv by sustain dots.
+X.PP
+XL <n> -- sets the current time value for notes. The default is L4, quarter
+Xnotes. The lowest possible value is 1; values up to 64 are accepted. L1 sets
+Xwhole notes, L2 sets half notes, L4 sets quarter notes, etc..
+X.PP
+XP <n> -- pause (rest), with <n> interpreted as for L. May be followed by
+Xsustain dots. May also be written '~'.
+X.PP
+XT <n> -- Sets the number of quarter notes per minute; default is 120. Musical
+Xnames for common tempi are:
+X
+X.TS
+Xa a a.
+X              Tempo           Beats Per Minute
+Xvery slow     Larghissimo     
+X              Largo           40-60
+X              Larghetto       60-66
+X              Grave           
+X              Lento           
+X              Adagio          66-76
+Xslow          Adagietto       
+X              Andante         76-108
+Xmedium        Andantino       
+X              Moderato        108-120
+Xfast          Allegretto      
+X              Allegro         120-168
+X              Vivace          
+X              Veloce          
+X              Presto          168-208
+Xvery fast     Prestissimo     
+X.TE
+X.PP
+XM[LNS] -- set articulation. MN (N for normal) is the default; the last 1/8th of
+Xthe note's value is rest time. You can set ML for legato (no rest space) or
+XMS (staccato) 1/4 rest space.
+X.PP
+XNotes (that is, CDEFGAB or N command character groups) may be followed by
+Xsustain dots. Each dot causes the note's value to be lengthened by one-half
+Xfor each one. Thus, a note dotted once is held for 3/2 of its undotted value;
+Xdotted twice, it is held 9/4, and three times would give 27/8. 
+X.PP
+XWhitespace in play strings is simply skipped and may be used to separate
+Xmelody sections.
+X.SH BUGS
+XDue to roundoff in the pitch tables and slop in the tone-generation and timer
+Xhardware (neither of which was designed for precision), neither pitch accuracy
+Xnor timings will be mathematically exact. There is no volume control.
+X.PP
+XIn play strings which are very long (longer than your system's physical I/O
+Xblocks) note suffixes or numbers may occasionally be parsed incorrectly due
+Xto crossing a block boundary.
+X.SH FILES
+X/dev/speaker -- speaker device file
+X.SH AUTHOR
+XEric S. Raymond (esr@snark.thyrsus.com) Feb 1990
+END-of-spkr.7
+echo x - Makefile
+sed 's/^X//' >Makefile << 'END-of-Makefile'
+X#
+X# Speaker driver package makefile
+X#
+XCFLAGS = -I. -O # -DDEBUG
+XLDFLAGS = -s
+X
+Xall: Driver.o
+X
+Xinstall:
+X      ./Install
+X
+XDriver.o: spkr.c
+X      $(CC) $(CFLAGS) -c spkr.c
+X      mv spkr.o Driver.o
+X
+Xclean:
+X      rm -f Driver.o *~ speaker.shar
+X
+XDSP =  Files Install Master Name Node Remove Size System 
+Xshar:
+X      shar READ.ME install.bsd spkr.7 Makefile spkr.[ch] \
+X              interp.c $(DSP) playtest >speaker.shar
+END-of-Makefile
+echo x - spkr.c
+sed 's/^X//' >spkr.c << 'END-of-spkr.c'
+X/*
+X * spkr.c -- device driver for console speaker on 80386
+X *
+X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990
+X *      modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su>
+X */
+X
+X#ifdef __386BSD__
+X#include "speaker.h"
+X#endif
+X#if !defined(__386BSD__) || (NSPEAKER > 0)
+X
+X#ifdef __386BSD__
+X#include "types.h"
+X#include "param.h"
+X#include "errno.h"
+X#include "buf.h"
+X#include "uio.h"
+X
+X#define CADDR caddr_t
+X#define err_ret(x) return(x)
+X#else /* SYSV */
+X#include <sys/types.h>
+X#include <sys/param.h>
+X#include <sys/dir.h>
+X#include <sys/signal.h>
+X#include <sys/errno.h>
+X#include <sys/ioctl.h>
+X#include <sys/user.h>
+X#include <sys/sysmacros.h> 
+X#include <limits.h>
+X
+X#define CADDR char *
+X#define err_ret(x) u.u_error = (x)
+X#endif
+X
+X#include "spkr.h"
+X
+X/**************** MACHINE DEPENDENT PART STARTS HERE *************************
+X *
+X * This section defines a function tone() which causes a tone of given
+X * frequency and duration from the 80x86's console speaker.
+X * Another function endtone() is defined to force sound off, and there is
+X * also a rest() entry point to do pauses.
+X *
+X * Audible sound is generated using the Programmable Interval Timer (PIT) and
+X * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The
+X * PPI controls whether sound is passed through at all; the PIT's channel 2 is
+X * used to generate clicks (a square wave) of whatever frequency is desired.
+X *
+X * The non-BSD code requires SVr3.2-compatible inb(), outb(), timeout(),
+X * sleep(), and wakeup().
+X */
+X
+X/*
+X * PIT and PPI port addresses and control values
+X *
+X * Most of the magic is hidden in the TIMER_PREP value, which selects PIT
+X * channel 2, frequency LSB first, square-wave mode and binary encoding.
+X * The encoding is as follows:
+X *
+X * +----------+----------+---------------+-----+
+X * |  1    0  |  1    1  |  0    1    1  |  0  |
+X * | SC1  SC0 | RW1  RW0 | M2   M1   M0  | BCD |
+X * +----------+----------+---------------+-----+
+X *   Counter     Write        Mode 3      Binary
+X *  Channel 2  LSB first,  (Square Wave) Encoding 
+X *             MSB second
+X */
+X#define PPI           0x61    /* port of Programmable Peripheral Interface */
+X#define PPI_SPKR      0x03    /* turn these PPI bits on to pass sound */
+X#define PIT_CTRL      0x43    /* PIT control address */
+X#define PIT_COUNT     0x42    /* PIT count address */
+X#define PIT_MODE      0xB6    /* set timer mode for sound generation */
+X
+X/*
+X * Magic numbers for timer control. 
+X */
+X#define TIMER_CLK     1193180L        /* corresponds to 18.2 MHz tick rate */
+X
+Xstatic int endtone()
+X/* turn off the speaker, ending current tone */
+X{
+X    wakeup((CADDR)endtone);
+X    outb(PPI, inb(PPI) & ~PPI_SPKR);
+X}
+X
+Xstatic void tone(hz, ticks)
+X/* emit tone of frequency hz for given number of ticks */
+Xunsigned int hz, ticks;
+X{
+X    unsigned int divisor = TIMER_CLK / hz;
+X    int sps;
+X
+X#ifdef DEBUG
+X    printf("tone: hz=%d ticks=%d\n", hz, ticks);
+X#endif /* DEBUG */
+X
+X    /* set timer to generate clicks at given frequency in Hertz */
+X#ifdef __386BSD__
+X    sps = spltty();
+X#else
+X    sps = spl5();
+X#endif
+X    outb(PIT_CTRL, PIT_MODE);         /* prepare timer */
+X    outb(PIT_COUNT, (unsigned char) divisor);  /* send lo byte */
+X    outb(PIT_COUNT, (divisor >> 8));  /* send hi byte */
+X    splx(sps);
+X
+X    /* turn the speaker on */
+X    outb(PPI, inb(PPI) | PPI_SPKR);
+X
+X    /*
+X     * Set timeout to endtone function, then give up the timeslice.
+X     * This is so other processes can execute while the tone is being
+X     * emitted.
+X     */
+X    timeout((CADDR)endtone, (CADDR)NULL, ticks);
+X    sleep((CADDR)endtone, PZERO - 1);
+X}
+X
+Xstatic int endrest()
+X/* end a rest */
+X{
+X    wakeup((CADDR)endrest);
+X}
+X
+Xstatic void rest(ticks)
+X/* rest for given number of ticks */
+Xint   ticks;
+X{
+X    /*
+X     * Set timeout to endrest function, then give up the timeslice.
+X     * This is so other processes can execute while the rest is being
+X     * waited out.
+X     */
+X#ifdef DEBUG
+X    printf("rest: %d\n", ticks);
+X#endif /* DEBUG */
+X    timeout((CADDR)endrest, (CADDR)NULL, ticks);
+X    sleep((CADDR)endrest, PZERO - 1);
+X}
+X
+X#include "interp.c"   /* playinit() and playstring() */
+X
+X/******************* UNIX DRIVER HOOKS BEGIN HERE **************************
+X *
+X * This section implements driver hooks to run playstring() and the tone(),
+X * endtone(), and rest() functions defined above.  For non-BSD systems,
+X * SVr3.2-compatible copyin() is also required.
+X */
+X
+Xstatic int spkr_active;       /* exclusion flag */
+X#ifdef __386BSD__
+Xstatic struct  buf *spkr_inbuf; /* incoming buf */
+X#endif
+X
+Xint spkropen(dev)
+Xdev_t dev;
+X{
+X#ifdef DEBUG
+X    printf("spkropen: entering with dev = %x\n", dev);
+X#endif /* DEBUG */
+X
+X    if (minor(dev) != 0)
+X      err_ret(ENXIO);
+X    else if (spkr_active)
+X      err_ret(EBUSY);
+X    else
+X    {
+X      playinit();
+X#ifdef __386BSD__
+X      spkr_inbuf = geteblk(DEV_BSIZE);
+X#endif
+X      spkr_active = 1;
+X    }
+X#ifdef __386BSD__
+X    return(0);
+X#endif
+X}
+X
+X#ifdef __386BSD__
+Xint spkrwrite(dev, uio)
+Xstruct uio *uio;
+X#else
+Xint spkrwrite(dev)
+X#endif
+Xdev_t dev;
+X{
+X#ifdef __386BSD__
+X    register unsigned n;
+X    char *cp;
+X    int error;
+X#endif
+X#ifdef DEBUG
+X#ifdef __386BSD__
+X    printf("spkrwrite: entering with dev = %x, count = %d\n",
+X              dev, uio->uio_resid);
+X#else
+X    printf("spkrwrite: entering with dev = %x, u.u_count = %d\n",
+X              dev, u.u_count);
+X#endif
+X#endif /* DEBUG */
+X
+X    if (minor(dev) != 0)
+X      err_ret(ENXIO);
+X    else
+X    {
+X#ifdef __386BSD__
+X      n = MIN(DEV_BSIZE, uio->uio_resid);
+X      cp = spkr_inbuf->b_un.b_addr;
+X      error = uiomove(cp, n, uio);
+X      if (!error)
+X              playstring(cp, n);
+X      return(error);
+X#else
+X      char    bfr[STD_BLK];
+X
+X      copyin(u.u_base, bfr, u.u_count);
+X      playstring(bfr, u.u_count);
+X      u.u_base += u.u_count;
+X      u.u_count = 0;
+X#endif
+X    }
+X}
+X
+Xint spkrclose(dev)
+Xdev_t dev;
+X{
+X#ifdef DEBUG
+X    printf("spkrclose: entering with dev = %x\n", dev);
+X#endif /* DEBUG */
+X
+X    if (minor(dev) != 0)
+X      err_ret(ENXIO);
+X    else
+X    {
+X      endtone();
+X#ifdef __386BSD__
+X      brelse(spkr_inbuf);
+X#endif
+X      spkr_active = 0;
+X    }
+X#ifdef __386BSD__
+X    return(0);
+X#endif
+X}
+X
+Xint spkrioctl(dev, cmd, cmdarg)
+Xdev_t dev;
+Xint   cmd;
+XCADDR   cmdarg;
+X{
+X#ifdef DEBUG
+X    printf("spkrioctl: entering with dev = %x, cmd = %x\n", dev, cmd);
+X#endif /* DEBUG */
+X
+X    if (minor(dev) != 0)
+X      err_ret(ENXIO);
+X    else if (cmd == SPKRTONE)
+X    {
+X      tone_t  *tp = (tone_t *)cmdarg;
+X
+X      if (tp->frequency == 0)
+X          rest(tp->duration);
+X      else
+X          tone(tp->frequency, tp->duration);
+X    }
+X    else if (cmd == SPKRTUNE)
+X    {
+X#ifdef __386BSD__
+X      tone_t  *tp = (tone_t *)(*(caddr_t *)cmdarg);
+X      tone_t ttp;
+X      int error;
+X
+X      for (; ; tp++) {
+X          error = copyin(tp, &ttp, sizeof(tone_t));
+X          if (error)
+X                  return(error);
+X          if (ttp.duration == 0)
+X                  break;
+X          if (ttp.frequency == 0)
+X              rest(ttp.duration);
+X          else
+X              tone(ttp.frequency, ttp.duration);
+X      }
+X#else
+X      tone_t  *tp = (tone_t *)cmdarg;
+X
+X      for (; tp->duration; tp++)
+X          if (tp->frequency == 0)
+X              rest(tp->duration);
+X          else
+X              tone(tp->frequency, tp->duration);
+X#endif
+X    }
+X    else
+X      err_ret(EINVAL);
+X#ifdef __386BSD__
+X    return(0);
+X#endif
+X}
+X
+X#endif  /* !defined(__386BSD__) || (NSPEAKER > 0) */
+X/* spkr.c ends here */
+END-of-spkr.c
+echo x - spkr.h
+sed 's/^X//' >spkr.h << 'END-of-spkr.h'
+X/*
+X * spkr.h -- interface definitions for speaker ioctl()
+X *
+X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990
+X *      modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su>
+X */
+X
+X#ifndef _SPKR_H_
+X#define _SPKR_H_
+X
+X#ifdef __386BSD__
+X#ifndef KERNEL
+X#include <sys/ioctl.h>
+X#else
+X#include "ioctl.h"
+X#endif
+X
+X#define SPKRTONE        _IOW('S', 1, tone_t)    /* emit tone */
+X#define SPKRTUNE        _IO('S', 2)             /* emit tone sequence*/
+X#else /* SYSV */
+X#define       SPKRIOC         ('S'<<8)
+X#define       SPKRTONE        (SPKRIOC|1)     /* emit tone */
+X#define       SPKRTUNE        (SPKRIOC|2)     /* emit tone sequence*/
+X#endif
+X
+Xtypedef struct
+X{
+X    int       frequency;      /* in hertz */
+X    int duration;     /* in 1/100ths of a second */
+X}
+Xtone_t;
+X
+X#endif /* _SPKR_H_ */
+X/* spkr.h ends here */
+END-of-spkr.h
+echo x - interp.c
+sed 's/^X//' >interp.c << 'END-of-interp.c'
+X/*
+X * interp.c -- device driver for console speaker on 80386
+X *
+X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990
+X *
+X * this is the part of the code common to all 386 UNIX OSes
+X *
+X * playinit() and playstring() are called from the appropriate driver
+X */
+X
+X#ifdef __386BSD__
+X#include "param.h"
+X#else
+X#include <sys/param.h>
+X#endif
+X
+X#ifndef HZ
+X#define HZ 60
+X#endif
+X
+X
+X/**************** PLAY STRING INTERPRETER BEGINS HERE **********************
+X *
+X * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
+X * M[LNS] are missing and the ~ synonym and octave-tracking facility is added.
+X * Requires tone(), rest(), and endtone(). String play is not interruptible
+X * except possibly at physical block boundaries.
+X */
+X
+Xtypedef int   bool;
+X#ifndef TRUE
+X#define TRUE  1
+X#endif
+X#ifndef FALSE
+X#define FALSE 0
+X#endif
+X
+X#define toupper(c)    ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z')))
+X#define isdigit(c)    (((c) >= '0') && ((c) <= '9'))
+X#define dtoi(c)               ((c) - '0')
+X
+Xstatic int octave;    /* currently selected octave */
+Xstatic int whole;     /* whole-note time at current tempo, in ticks */
+Xstatic int value;     /* whole divisor for note time, quarter note = 1 */
+Xstatic int fill;      /* controls spacing of notes */
+Xstatic bool octtrack; /* octave-tracking on? */
+Xstatic bool octprefix;        /* override current octave-tracking state? */
+X
+X/*
+X * Magic number avoidance...
+X */
+X#define SECS_PER_MIN  60      /* seconds per minute */
+X#define WHOLE_NOTE    4       /* quarter notes per whole note */
+X#define MIN_VALUE     64      /* the most we can divide a note by */
+X#define DFLT_VALUE    4       /* default value (quarter-note) */
+X#define FILLTIME      8       /* for articulation, break note in parts */
+X#define STACCATO      6       /* 6/8 = 3/4 of note is filled */
+X#define NORMAL                7       /* 7/8ths of note interval is filled */
+X#define LEGATO                8       /* all of note interval is filled */
+X#define DFLT_OCTAVE   4       /* default octave */
+X#define MIN_TEMPO     32      /* minimum tempo */
+X#define DFLT_TEMPO    120     /* default tempo */
+X#define MAX_TEMPO     255     /* max tempo */
+X#define NUM_MULT      3       /* numerator of dot multiplier */
+X#define DENOM_MULT    2       /* denominator of dot multiplier */
+X
+X/* letter to half-tone:  A   B  C  D  E  F  G */
+Xstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7};
+X
+X/*
+X * This is the American Standard A440 Equal-Tempered scale with frequencies
+X * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook...
+X * our octave 0 is standard octave 2.
+X */
+X#define OCTAVE_NOTES  12      /* semitones per octave */
+Xstatic int pitchtab[] =
+X{
+X/*        C     C#    D     D#    E     F     F#    G     G#    A     A#    B*/
+X/* 0 */   65,   69,   73,   78,   82,   87,   93,   98,  103,  110,  117,  123,
+X/* 1 */  131,  139,  147,  156,  165,  175,  185,  196,  208,  220,  233,  247,
+X/* 2 */  262,  277,  294,  311,  330,  349,  370,  392,  415,  440,  466,  494,
+X/* 3 */  523,  554,  587,  622,  659,  698,  740,  784,  831,  880,  932,  988,
+X/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975,
+X/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
+X/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902,
+X};
+X
+Xstatic void playinit()
+X{
+X    octave = DFLT_OCTAVE;
+X    whole = (HZ * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO;
+X    fill = NORMAL;
+X    value = DFLT_VALUE;
+X    octtrack = FALSE;
+X    octprefix = TRUE; /* act as though there was an initial O(n) */
+X}
+X
+Xstatic void playtone(pitch, value, sustain)
+X/* play tone of proper duration for current rhythm signature */
+Xint   pitch, value, sustain;
+X{
+X    register int      sound, silence, snum = 1, sdenom = 1;
+X
+X    /* this weirdness avoids floating-point arithmetic */
+X    for (; sustain; sustain--)
+X    {
+X      snum *= NUM_MULT;
+X      sdenom *= DENOM_MULT;
+X    }
+X
+X    if (pitch == -1)
+X      rest(whole * snum / (value * sdenom));
+X    else
+X    {
+X      sound = (whole * snum) / (value * sdenom)
+X              - (whole * (FILLTIME - fill)) / (value * FILLTIME);
+X      silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom);
+X
+X#ifdef DEBUG
+X      printf("playtone: pitch %d for %d ticks, rest for %d ticks\n",
+X                      pitch, sound, silence);
+X#endif /* DEBUG */
+X
+X      tone(pitchtab[pitch], sound);
+X      if (fill != LEGATO)
+X          rest(silence);
+X    }
+X}
+X
+Xstatic int abs(n)
+Xint n;
+X{
+X    if (n < 0)
+X      return(-n);
+X    else
+X      return(n);
+X}
+X
+Xstatic void playstring(cp, slen)
+X/* interpret and play an item from a notation string */
+Xchar  *cp;
+Xsize_t        slen;
+X{
+X    int               pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
+X
+X#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \
+X                              {v = v * 10 + (*++cp - '0'); slen--;}
+X    for (; slen--; cp++)
+X    {
+X      int             sustain, timeval, tempo;
+X      register char   c = toupper(*cp);
+X
+X#ifdef DEBUG
+X      printf("playstring: %c (%x)\n", c, c);
+X#endif /* DEBUG */
+X
+X      switch (c)
+X      {
+X      case 'A':  case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+X
+X          /* compute pitch */
+X          pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES;
+X
+X          /* this may be followed by an accidental sign */
+X          if (cp[1] == '#' || cp[1] == '+')
+X          {
+X              ++pitch;
+X              ++cp;
+X              slen--;
+X          }
+X          else if (cp[1] == '-')
+X          {
+X              --pitch;
+X              ++cp;
+X              slen--;
+X          }
+X
+X          /*
+X           * If octave-tracking mode is on, and there has been no octave-
+X           * setting prefix, find the version of the current letter note
+X           * closest to the last regardless of octave.
+X           */
+X          if (octtrack && !octprefix)
+X          {
+X              if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch))
+X              {
+X                  ++octave;
+X                  pitch += OCTAVE_NOTES;
+X              }
+X
+X              if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch))
+X              {
+X                  --octave;
+X                  pitch -= OCTAVE_NOTES;
+X              }
+X          }
+X          octprefix = FALSE;
+X          lastpitch = pitch;
+X
+X          /* ...which may in turn be followed by an override time value */
+X          GETNUM(cp, timeval);
+X          if (timeval <= 0 || timeval > MIN_VALUE)
+X              timeval = value;
+X
+X          /* ...and/or sustain dots */
+X          for (sustain = 0; cp[1] == '.'; cp++)
+X          {
+X              slen--;
+X              sustain++;
+X          }
+X
+X          /* time to emit the actual tone */
+X          playtone(pitch, timeval, sustain);
+X          break;
+X
+X      case 'O':
+X          if (cp[1] == 'N' || cp[1] == 'n')
+X          {
+X              octprefix = octtrack = FALSE;
+X              ++cp;
+X              slen--;
+X          }
+X          else if (cp[1] == 'L' || cp[1] == 'l')
+X          {
+X              octtrack = TRUE;
+X              ++cp;
+X              slen--;
+X          }
+X          else
+X          {
+X              GETNUM(cp, octave);
+X              if (octave >= sizeof(pitchtab) / OCTAVE_NOTES)
+X                  octave = DFLT_OCTAVE;
+X              octprefix = TRUE;
+X          }
+X          break;
+X
+X      case '>':
+X          if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1)
+X              octave++;
+X          octprefix = TRUE;
+X          break;
+X
+X      case '<':
+X          if (octave > 0)
+X              octave--;
+X          octprefix = TRUE;
+X          break;
+X
+X      case 'N':
+X          GETNUM(cp, pitch);
+X          for (sustain = 0; cp[1] == '.'; cp++)
+X          {
+X              slen--;
+X              sustain++;
+X          }
+X          playtone(pitch - 1, value, sustain);
+X          break;
+X
+X      case 'L':
+X          GETNUM(cp, value);
+X          if (value <= 0 || value > MIN_VALUE)
+X              value = DFLT_VALUE;
+X          break;
+X
+X      case 'P':
+X      case '~':
+X          /* this may be followed by an override time value */
+X          GETNUM(cp, timeval);
+X          if (timeval <= 0 || timeval > MIN_VALUE)
+X              timeval = value;
+X          for (sustain = 0; cp[1] == '.'; cp++)
+X          {
+X              slen--;
+X              sustain++;
+X          }
+X          playtone(-1, timeval, sustain);
+X          break;
+X
+X      case 'T':
+X          GETNUM(cp, tempo);
+X          if (tempo < MIN_TEMPO || tempo > MAX_TEMPO)
+X              tempo = DFLT_TEMPO;
+X          whole = (HZ * SECS_PER_MIN * WHOLE_NOTE) / tempo;
+X          break;
+X
+X      case 'M':
+X          if (cp[1] == 'N' || cp[1] == 'n')
+X          {
+X              fill = NORMAL;
+X              ++cp;
+X              slen--;
+X          }
+X          else if (cp[1] == 'L' || cp[1] == 'l')
+X          {
+X              fill = LEGATO;
+X              ++cp;
+X              slen--;
+X          }
+X          else if (cp[1] == 'S' || cp[1] == 's')
+X          {
+X              fill = STACCATO;
+X              ++cp;
+X              slen--;
+X          }
+X          break;
+X      }
+X    }
+X}
+END-of-interp.c
+echo x - Files
+sed 's/^X//' >Files << 'END-of-Files'
+X/usr/include/sys/spkr.h
+END-of-Files
+echo x - Install
+sed 's/^X//' >Install << 'END-of-Install'
+X#
+X# Speaker driver installation script
+X#
+XTMP=/tmp/speaker.err
+XERR1=" Errors have been written to the file $TMP."
+XERR2=" The Speaker Driver software was not installed."
+X
+Xecho "Installing Speaker Driver Software Package"
+X
+X/etc/conf/bin/idcheck -p speaker 2>$TMP
+Xif [ $? != 0 ]
+Xthen
+X      echo "The speaker package is already at least partly installed.
+X      Removing the old version now..."
+X      /etc/conf/bin/idinstall -d speaker
+Xfi
+X
+X/etc/conf/bin/idinstall -a -k speaker 2>>$TMP
+Xif [ $? != 0 ]
+Xthen
+X      message "There was an error during package installation. $ERR1 $ERR2"
+X      exit 1
+Xfi
+X
+X/etc/conf/bin/idbuild 2>>$TMP
+Xif [ $? != 0 ]
+Xthen
+X      message "There was an error during kernel reconfiguration. $ERR1 $ERR2"
+X      exit 1
+Xfi
+X
+Xrm -f $TMP
+X
+Xcp spkr.h /usr/include/sys/spkr.h
+X
+Xecho "Performing shutdown..."
+Xcd /; exec /etc/shutdown -g0 -y
+END-of-Install
+echo x - Master
+sed 's/^X//' >Master << 'END-of-Master'
+Xspeaker       ocwi    iocH    spkr    0       0       1       1       -1
+END-of-Master
+echo x - Name
+sed 's/^X//' >Name << 'END-of-Name'
+X386 UNIX Speaker Device Driver Package
+END-of-Name
+echo x - Node
+sed 's/^X//' >Node << 'END-of-Node'
+Xspeaker       speaker c       0
+END-of-Node
+echo x - Remove
+sed 's/^X//' >Remove << 'END-of-Remove'
+X#
+X# Speaker driver remove script
+X#
+XTMP=/tmp/speaker.err
+XRERR="Errors have been written to the file $TMP."
+X
+Xecho "Removing Speaker Driver Software Package"
+X
+X/etc/conf/bin/idinstall -d speaker 2>$TMP
+Xif [ $? != 0 ]
+Xthen
+X      message "There was an error during package removal. $RERR"
+X      exit 1
+Xfi
+X
+X/etc/conf/bin/idbuild 2>>$TMP
+Xif [ $? != 0 ]
+Xthen
+X      message "There was an error during kernel reconfiguration. $RERR"
+X      exit 1
+Xfi
+X
+Xrm -f /dev/speaker $TMP /usr/include/sys/spkr.h
+X
+Xexit 0
+END-of-Remove
+echo x - Size
+sed 's/^X//' >Size << 'END-of-Size'
+XROOT=1400
+XUSR=100
+END-of-Size
+echo x - System
+sed 's/^X//' >System << 'END-of-System'
+Xspeaker       Y       1       0       0       0       0       0       0       0
+END-of-System
+echo x - playtest
+sed 's/^X//' >playtest << 'END-of-playtest'
+X:
+X# Test script for the speaker driver
+X#
+X# v1.0 by Eric S. Raymond (Feb 1990)
+X#      modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su>
+X#
+Xreveille="t255l8c.f.afc~c.f.afc~c.f.afc.f.a..f.~c.f.afc~c.f.afc~c.f.afc~c.f.."
+Xcontact="<cd<a#~<a#>f"
+Xdance="t240<cfcfgagaa#b#>dc<a#a.~fg.gaa#.agagegc.~cfcfgagaa#b#>dc<a#a.~fg.gga.agfgfgf."
+Xloony="t255cf8f8edc<a.>~cf8f8edd#e.~ce8cdce8cd.<a>c8c8c#def8af8."
+X
+Xcase $1 in
+Xreveille) echo  $reveille >/dev/speaker;;
+Xcontact)  echo  $contact >/dev/speaker;;
+Xdance)  echo  $dance >/dev/speaker;;
+Xloony)  echo  $loony >/dev/speaker;;
+X*)
+X      echo "No such tune. Available tunes are:"
+X      echo
+X      echo "reveille -- Reveille"
+X      echo "contact -- Contact theme from Close Encounters"
+X      echo "dance -- Lord of the Dance (aka Simple Gifts)"
+X      echo "loony -- Loony Toons theme"
+X      ;;
+Xesac
+END-of-playtest
+exit
diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c
new file mode 100644 (file)
index 0000000..a13514f
--- /dev/null
@@ -0,0 +1,541 @@
+/*     SCCS Id: @(#)unixmain.c 3.4     1997/01/22      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* main.c - Unix NetHack */
+
+#include "hack.h"
+#include "dlb.h"
+
+#include <sys/stat.h>
+#include <signal.h>
+#include <pwd.h>
+#ifndef O_RDONLY
+#include <fcntl.h>
+#endif
+
+#if !defined(_BULL_SOURCE) && !defined(__sgi) && !defined(_M_UNIX)
+# if !defined(SUNOS4) && !(defined(ULTRIX) && defined(__GNUC__))
+#  if defined(POSIX_TYPES) || defined(SVR4) || defined(HPUX)
+extern struct passwd *FDECL(getpwuid,(uid_t));
+#  else
+extern struct passwd *FDECL(getpwuid,(int));
+#  endif
+# endif
+#endif
+extern struct passwd *FDECL(getpwnam,(const char *));
+#ifdef CHDIR
+static void FDECL(chdirx, (const char *,BOOLEAN_P));
+#endif /* CHDIR */
+static boolean NDECL(whoami);
+static void FDECL(process_options, (int, char **));
+
+#ifdef _M_UNIX
+extern void NDECL(check_sco_console);
+extern void NDECL(init_sco_cons);
+#endif
+#ifdef __linux__
+extern void NDECL(check_linux_console);
+extern void NDECL(init_linux_cons);
+#endif
+
+static void NDECL(wd_message);
+#ifdef WIZARD
+static boolean wiz_error_flag = FALSE;
+#endif
+
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+       register int fd;
+#ifdef CHDIR
+       register char *dir;
+#endif
+       boolean exact_username;
+
+#if defined(__APPLE__)
+       /* special hack to change working directory to a resource fork when
+          running from finder --sam */
+#define MAC_PATH_VALUE ".app/Contents/MacOS/"
+       char mac_cwd[1024], *mac_exe = argv[0], *mac_tmp;
+       int arg0_len = strlen(mac_exe), mac_tmp_len, mac_lhs_len=0;
+       getcwd(mac_cwd, 1024);
+       if(mac_exe[0] == '/' && !strcmp(mac_cwd, "/")) {
+           if((mac_exe = strrchr(mac_exe, '/')))
+               mac_exe++;
+           else
+               mac_exe = argv[0];
+           mac_tmp_len = (strlen(mac_exe) * 2) + strlen(MAC_PATH_VALUE);
+           if(mac_tmp_len <= arg0_len) {
+               mac_tmp = malloc(mac_tmp_len + 1);
+               sprintf(mac_tmp, "%s%s%s", mac_exe, MAC_PATH_VALUE, mac_exe);
+               if(!strcmp(argv[0] + (arg0_len - mac_tmp_len), mac_tmp)) {
+                   mac_lhs_len = (arg0_len - mac_tmp_len) + strlen(mac_exe) + 5;
+                   if(mac_lhs_len > mac_tmp_len - 1)
+                       mac_tmp = realloc(mac_tmp, mac_lhs_len);
+                   strncpy(mac_tmp, argv[0], mac_lhs_len);
+                   mac_tmp[mac_lhs_len] = '\0';
+                   chdir(mac_tmp);
+               }
+               free(mac_tmp);
+           }
+       }
+#endif
+
+       hname = argv[0];
+       hackpid = getpid();
+       (void) umask(0777 & ~FCMASK);
+
+       choose_windows(DEFAULT_WINDOW_SYS);
+
+#ifdef CHDIR                   /* otherwise no chdir() */
+       /*
+        * See if we must change directory to the playground.
+        * (Perhaps hack runs suid and playground is inaccessible
+        *  for the player.)
+        * The environment variable HACKDIR is overridden by a
+        *  -d command line option (must be the first option given)
+        */
+       dir = nh_getenv("NETHACKDIR");
+       if (!dir) dir = nh_getenv("HACKDIR");
+#endif
+       if(argc > 1) {
+#ifdef CHDIR
+           if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') {
+               /* avoid matching "-dec" for DECgraphics; since the man page
+                * says -d directory, hope nobody's using -desomething_else
+                */
+               argc--;
+               argv++;
+               dir = argv[0]+2;
+               if(*dir == '=' || *dir == ':') dir++;
+               if(!*dir && argc > 1) {
+                       argc--;
+                       argv++;
+                       dir = argv[0];
+               }
+               if(!*dir)
+                   error("Flag -d must be followed by a directory name.");
+           }
+           if (argc > 1)
+#endif /* CHDIR */
+
+           /*
+            * Now we know the directory containing 'record' and
+            * may do a prscore().  Exclude `-style' - it's a Qt option.
+            */
+           if (!strncmp(argv[1], "-s", 2) && strncmp(argv[1], "-style", 6)) {
+#ifdef CHDIR
+               chdirx(dir,0);
+#endif
+               prscore(argc, argv);
+               exit(EXIT_SUCCESS);
+           }
+       }
+
+       /*
+        * Change directories before we initialize the window system so
+        * we can find the tile file.
+        */
+#ifdef CHDIR
+       chdirx(dir,1);
+#endif
+
+#ifdef _M_UNIX
+       check_sco_console();
+#endif
+#ifdef __linux__
+       check_linux_console();
+#endif
+       initoptions();
+       init_nhwindows(&argc,argv);
+       exact_username = whoami();
+#ifdef _M_UNIX
+       init_sco_cons();
+#endif
+#ifdef __linux__
+       init_linux_cons();
+#endif
+
+       /*
+        * It seems you really want to play.
+        */
+       u.uhp = 1;      /* prevent RIP on early quits */
+       (void) signal(SIGHUP, (SIG_RET_TYPE) hangup);
+#ifdef SIGXCPU
+       (void) signal(SIGXCPU, (SIG_RET_TYPE) hangup);
+#endif
+
+       process_options(argc, argv);    /* command line options */
+
+#ifdef DEF_PAGER
+       if(!(catmore = nh_getenv("HACKPAGER")) && !(catmore = nh_getenv("PAGER")))
+               catmore = DEF_PAGER;
+#endif
+#ifdef MAIL
+       getmailstatus();
+#endif
+#ifdef WIZARD
+       if (wizard)
+               Strcpy(plname, "wizard");
+       else
+#endif
+       if(!*plname || !strncmp(plname, "player", 4)
+                   || !strncmp(plname, "games", 4)) {
+               askname();
+       } else if (exact_username) {
+               /* guard against user names with hyphens in them */
+               int len = strlen(plname);
+               /* append the current role, if any, so that last dash is ours */
+               if (++len < sizeof plname)
+                       (void)strncat(strcat(plname, "-"),
+                                     pl_character, sizeof plname - len - 1);
+       }
+       plnamesuffix();         /* strip suffix from name; calls askname() */
+                               /* again if suffix was whole name */
+                               /* accepts any suffix */
+#ifdef WIZARD
+       if(!wizard) {
+#endif
+               /*
+                * check for multiple games under the same name
+                * (if !locknum) or check max nr of players (otherwise)
+                */
+               (void) signal(SIGQUIT,SIG_IGN);
+               (void) signal(SIGINT,SIG_IGN);
+               if(!locknum)
+                       Sprintf(lock, "%d%s", (int)getuid(), plname);
+               getlock();
+#ifdef WIZARD
+       } else {
+               Sprintf(lock, "%d%s", (int)getuid(), plname);
+               getlock();
+       }
+#endif /* WIZARD */
+
+       dlb_init();     /* must be before newgame() */
+
+       /*
+        * Initialization of the boundaries of the mazes
+        * Both boundaries have to be even.
+        */
+       x_maze_max = COLNO-1;
+       if (x_maze_max % 2)
+               x_maze_max--;
+       y_maze_max = ROWNO-1;
+       if (y_maze_max % 2)
+               y_maze_max--;
+
+       /*
+        *  Initialize the vision system.  This must be before mklev() on a
+        *  new game or before a level restore on a saved game.
+        */
+       vision_init();
+
+       display_gamewindows();
+
+       if ((fd = restore_saved_game()) >= 0) {
+#ifdef WIZARD
+               /* Since wizard is actually flags.debug, restoring might
+                * overwrite it.
+                */
+               boolean remember_wiz_mode = wizard;
+#endif
+               const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1);
+
+               (void) chmod(fq_save,0);        /* disallow parallel restores */
+               (void) signal(SIGINT, (SIG_RET_TYPE) done1);
+#ifdef NEWS
+               if(iflags.news) {
+                   display_file(NEWS, FALSE);
+                   iflags.news = FALSE; /* in case dorecover() fails */
+               }
+#endif
+               pline("Restoring save file...");
+               mark_synch();   /* flush output */
+               if(!dorecover(fd))
+                       goto not_recovered;
+#ifdef WIZARD
+               if(!wizard && remember_wiz_mode) wizard = TRUE;
+#endif
+               check_special_room(FALSE);
+               wd_message();
+
+               if (discover || wizard) {
+                       if(yn("Do you want to keep the save file?") == 'n')
+                           (void) delete_savefile();
+                       else {
+                           (void) chmod(fq_save,FCMASK); /* back to readable */
+                           compress(fq_save);
+                       }
+               }
+               flags.move = 0;
+       } else {
+not_recovered:
+               player_selection();
+               newgame();
+               wd_message();
+
+               flags.move = 0;
+               set_wear();
+               (void) pickup(1);
+       }
+
+       moveloop();
+       exit(EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return(0);
+}
+
+static void
+process_options(argc, argv)
+int argc;
+char *argv[];
+{
+       int i;
+
+
+       /*
+        * Process options.
+        */
+       while(argc > 1 && argv[1][0] == '-'){
+               argv++;
+               argc--;
+               switch(argv[0][1]){
+               case 'D':
+#ifdef WIZARD
+                       {
+                         char *user;
+                         int uid;
+                         struct passwd *pw = (struct passwd *)0;
+
+                         uid = getuid();
+                         user = getlogin();
+                         if (user) {
+                             pw = getpwnam(user);
+                             if (pw && (pw->pw_uid != uid)) pw = 0;
+                         }
+                         if (pw == 0) {
+                             user = nh_getenv("USER");
+                             if (user) {
+                                 pw = getpwnam(user);
+                                 if (pw && (pw->pw_uid != uid)) pw = 0;
+                             }
+                             if (pw == 0) {
+                                 pw = getpwuid(uid);
+                             }
+                         }
+                         if (pw && !strcmp(pw->pw_name,WIZARD)) {
+                             wizard = TRUE;
+                             break;
+                         }
+                       }
+                       /* otherwise fall thru to discover */
+                       wiz_error_flag = TRUE;
+#endif
+               case 'X':
+                       discover = TRUE;
+                       break;
+#ifdef NEWS
+               case 'n':
+                       iflags.news = FALSE;
+                       break;
+#endif
+               case 'u':
+                       if(argv[0][2])
+                         (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
+                       else if(argc > 1) {
+                         argc--;
+                         argv++;
+                         (void) strncpy(plname, argv[0], sizeof(plname)-1);
+                       } else
+                               raw_print("Player name expected after -u");
+                       break;
+               case 'I':
+               case 'i':
+                       if (!strncmpi(argv[0]+1, "IBM", 3))
+                               switch_graphics(IBM_GRAPHICS);
+                       break;
+           /*  case 'D': */
+               case 'd':
+                       if (!strncmpi(argv[0]+1, "DEC", 3))
+                               switch_graphics(DEC_GRAPHICS);
+                       break;
+               case 'p': /* profession (role) */
+                       if (argv[0][2]) {
+                           if ((i = str2role(&argv[0][2])) >= 0)
+                               flags.initrole = i;
+                       } else if (argc > 1) {
+                               argc--;
+                               argv++;
+                           if ((i = str2role(argv[0])) >= 0)
+                               flags.initrole = i;
+                       }
+                       break;
+               case 'r': /* race */
+                       if (argv[0][2]) {
+                           if ((i = str2race(&argv[0][2])) >= 0)
+                               flags.initrace = i;
+                       } else if (argc > 1) {
+                               argc--;
+                               argv++;
+                           if ((i = str2race(argv[0])) >= 0)
+                               flags.initrace = i;
+                       }
+                       break;
+               case '@':
+                       flags.randomall = 1;
+                       break;
+               default:
+                       if ((i = str2role(&argv[0][1])) >= 0) {
+                           flags.initrole = i;
+                               break;
+                       }
+                       /* else raw_printf("Unknown option: %s", *argv); */
+               }
+       }
+
+       if(argc > 1)
+               locknum = atoi(argv[1]);
+#ifdef MAX_NR_OF_PLAYERS
+       if(!locknum || locknum > MAX_NR_OF_PLAYERS)
+               locknum = MAX_NR_OF_PLAYERS;
+#endif
+}
+
+#ifdef CHDIR
+static void
+chdirx(dir, wr)
+const char *dir;
+boolean wr;
+{
+       if (dir                                 /* User specified directory? */
+# ifdef HACKDIR
+              && strcmp(dir, HACKDIR)          /* and not the default? */
+# endif
+               ) {
+# ifdef SECURE
+           (void) setgid(getgid());
+           (void) setuid(getuid());            /* Ron Wessels */
+# endif
+       } else {
+           /* non-default data files is a sign that scores may not be
+            * compatible, or perhaps that a binary not fitting this
+            * system's layout is being used.
+            */
+# ifdef VAR_PLAYGROUND
+           int len = strlen(VAR_PLAYGROUND);
+
+           fqn_prefix[SCOREPREFIX] = (char *)alloc(len+2);
+           Strcpy(fqn_prefix[SCOREPREFIX], VAR_PLAYGROUND);
+           if (fqn_prefix[SCOREPREFIX][len-1] != '/') {
+               fqn_prefix[SCOREPREFIX][len] = '/';
+               fqn_prefix[SCOREPREFIX][len+1] = '\0';
+           }
+# endif
+       }
+
+# ifdef HACKDIR
+       if (dir == (const char *)0)
+           dir = HACKDIR;
+# endif
+
+       if (dir && chdir(dir) < 0) {
+           perror(dir);
+           error("Cannot chdir to %s.", dir);
+       }
+
+       /* warn the player if we can't write the record file */
+       /* perhaps we should also test whether . is writable */
+       /* unfortunately the access system-call is worthless */
+       if (wr) {
+# ifdef VAR_PLAYGROUND
+           fqn_prefix[LEVELPREFIX] = fqn_prefix[SCOREPREFIX];
+           fqn_prefix[SAVEPREFIX] = fqn_prefix[SCOREPREFIX];
+           fqn_prefix[BONESPREFIX] = fqn_prefix[SCOREPREFIX];
+           fqn_prefix[LOCKPREFIX] = fqn_prefix[SCOREPREFIX];
+           fqn_prefix[TROUBLEPREFIX] = fqn_prefix[SCOREPREFIX];
+# endif
+           check_recordfile(dir);
+       }
+}
+#endif /* CHDIR */
+
+static boolean
+whoami() {
+       /*
+        * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS
+        *                      2. Use $USER or $LOGNAME        (if 1. fails)
+        *                      3. Use getlogin()               (if 2. fails)
+        * The resulting name is overridden by command line options.
+        * If everything fails, or if the resulting name is some generic
+        * account like "games", "play", "player", "hack" then eventually
+        * we'll ask him.
+        * Note that we trust the user here; it is possible to play under
+        * somebody else's name.
+        */
+       register char *s;
+
+       if (*plname) return FALSE;
+       if(/* !*plname && */ (s = nh_getenv("USER")))
+               (void) strncpy(plname, s, sizeof(plname)-1);
+       if(!*plname && (s = nh_getenv("LOGNAME")))
+               (void) strncpy(plname, s, sizeof(plname)-1);
+       if(!*plname && (s = getlogin()))
+               (void) strncpy(plname, s, sizeof(plname)-1);
+       return TRUE;
+}
+
+#ifdef PORT_HELP
+void
+port_help()
+{
+       /*
+        * Display unix-specific help.   Just show contents of the helpfile
+        * named by PORT_HELP.
+        */
+       display_file(PORT_HELP, TRUE);
+}
+#endif
+
+static void
+wd_message()
+{
+#ifdef WIZARD
+       if (wiz_error_flag) {
+               pline("Only user \"%s\" may access debug (wizard) mode.",
+# ifndef KR1ED
+                       WIZARD);
+# else
+                       WIZARD_NAME);
+# endif
+               pline("Entering discovery mode instead.");
+       } else
+#endif
+       if (discover)
+               You("are in non-scoring discovery mode.");
+}
+
+/*
+ * Add a slash to any name not ending in /. There must
+ * be room for the /
+ */
+void
+append_slash(name)
+char *name;
+{
+       char *ptr;
+
+       if (!*name)
+               return;
+       ptr = name + (strlen(name) - 1);
+       if (*ptr != '/') {
+               *++ptr = '/';
+               *++ptr = '\0';
+       }
+       return;
+}
+
+/*unixmain.c*/
diff --git a/sys/unix/unixres.c b/sys/unix/unixres.c
new file mode 100644 (file)
index 0000000..3e7f989
--- /dev/null
@@ -0,0 +1,209 @@
+/*     SCCS Id: @(#)unixres.c  3.4     2001/07/08      */
+/* Copyright (c) Slash'EM development team, 2001. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* [ALI] This module defines nh_xxx functions to replace getuid etc which
+ * will hide privileges from the caller if so desired.
+ *
+ * Currently supported UNIX variants:
+ *     Linux version 2.1.44 and above
+ *     FreeBSD (versions unknown)
+ *
+ * Note: SunOS and Solaris have no mechanism for retrieving the saved id,
+ * so temporarily dropping privileges on these systems is sufficient to
+ * hide them.
+ */
+
+#include "config.h"
+
+#ifdef GETRES_SUPPORT
+
+# if defined(LINUX)
+
+/* requires dynamic linking with libc */
+#include <dlfcn.h>
+
+static int
+real_getresuid(ruid, euid, suid)
+uid_t *ruid, *euid, *suid;
+{
+    int (*f)(uid_t *, uid_t *, uid_t *); /* getresuid signature */
+
+    f = dlsym(RTLD_NEXT, "getresuid");
+    if (!f) return -1;
+
+    return f(ruid, euid, suid);
+}
+
+static int
+real_getresgid(rgid, egid, sgid)
+gid_t *rgid, *egid, *sgid;
+{
+    int (*f)(gid_t *, gid_t *, gid_t *); /* getresgid signature */
+
+    f = dlsym(RTLD_NEXT, "getresgid");
+    if (!f) return -1;
+
+    return f(rgid, egid, sgid);
+}
+
+# else
+#  if defined(BSD) || defined(SVR4)
+
+#   ifdef SYS_getresuid
+
+static int
+real_getresuid(ruid, euid, suid)
+uid_t *ruid, *euid, *suid;
+{
+    return syscall(SYS_getresuid, ruid, euid, suid);
+}
+
+#   else       /* SYS_getresuid */
+
+#ifdef SVR4
+#include <sys/stat.h>
+#endif /* SVR4 */
+
+static int
+real_getresuid(ruid, euid, suid)
+uid_t *ruid, *euid, *suid;
+{
+    int retval;
+    int pfd[2];
+    struct stat st;
+    if (pipe(pfd))
+       return -1;
+    retval = fstat(pfd[0], &st);
+    close(pfd[0]);
+    close(pfd[1]);
+    if (!retval) {
+       *euid = st.st_uid;
+       *ruid = syscall(SYS_getuid);
+       *suid = *ruid;                  /* Not supported under SVR4 */
+    }
+    return retval;
+}
+
+#   endif      /* SYS_getresuid */
+
+#   ifdef SYS_getresgid
+
+static int
+real_getresgid(rgid, egid, sgid)
+gid_t *rgid, *egid, *sgid;
+{
+    return syscall(SYS_getresgid, rgid, egid, sgid);
+}
+
+#   else       /* SYS_getresgid */
+
+static int
+real_getresgid(rgid, egid, sgid)
+gid_t *rgid, *egid, *sgid;
+{
+    int retval;
+    int pfd[2];
+    struct stat st;
+    if (pipe(pfd))
+       return -1;
+    retval = fstat(pfd[0], &st);
+    close(pfd[0]);
+    close(pfd[1]);
+    if (!retval) {
+       *egid = st.st_gid;
+       *rgid = syscall(SYS_getgid);
+       *sgid = *rgid;                  /* Not supported under SVR4 */
+    }
+    return retval;
+}
+
+#   endif      /* SYS_getresgid */
+#  endif       /* BSD || SVR4 */
+# endif                /* LINUX */
+
+static unsigned int hiding_privileges = 0;
+
+/*
+ * Note: returns the value _after_ action.
+ */
+
+int
+hide_privileges(flag)
+boolean flag;
+{
+    if (flag)
+       hiding_privileges++;
+    else if (hiding_privileges)
+       hiding_privileges--;
+    return hiding_privileges;
+}
+
+int
+nh_getresuid(ruid, euid, suid)
+uid_t *ruid, *euid, *suid;
+{
+    int retval = real_getresuid(ruid, euid, suid);
+    if (!retval && hiding_privileges)
+       *euid = *suid = *ruid;
+    return retval;
+}
+
+uid_t
+nh_getuid()
+{
+    uid_t ruid, euid, suid;
+    (void) real_getresuid(&ruid, &euid, &suid);
+    return ruid;
+}
+
+uid_t
+nh_geteuid()
+{
+    uid_t ruid, euid, suid;
+    (void) real_getresuid(&ruid, &euid, &suid);
+    if (hiding_privileges)
+       euid = ruid;
+    return euid;
+}
+
+int
+nh_getresgid(rgid, egid, sgid)
+gid_t *rgid, *egid, *sgid;
+{
+    int retval = real_getresgid(rgid, egid, sgid);
+    if (!retval && hiding_privileges)
+       *egid = *sgid = *rgid;
+    return retval;
+}
+
+gid_t
+nh_getgid()
+{
+    gid_t rgid, egid, sgid;
+    (void) real_getresgid(&rgid, &egid, &sgid);
+    return rgid;
+}
+
+gid_t
+nh_getegid()
+{
+    gid_t rgid, egid, sgid;
+    (void) real_getresgid(&rgid, &egid, &sgid);
+    if (hiding_privileges)
+       egid = rgid;
+    return egid;
+}
+
+#else  /* GETRES_SUPPORT */
+
+# ifdef GNOME_GRAPHICS 
+int
+hide_privileges(flag)
+boolean flag;
+{
+    return 0;
+}
+# endif
+
+#endif /* GETRES_SUPPORT */
diff --git a/sys/unix/unixunix.c b/sys/unix/unixunix.c
new file mode 100644 (file)
index 0000000..c2f84eb
--- /dev/null
@@ -0,0 +1,349 @@
+/*     SCCS Id: @(#)unixunix.c 3.4     1994/11/07      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* This file collects some Unix dependencies */
+
+#include "hack.h"      /* mainly for index() which depends on BSD */
+
+#include <errno.h>
+#include <sys/stat.h>
+#if defined(NO_FILE_LINKS) || defined(SUNOS4) || defined(POSIX_TYPES)
+#include <fcntl.h>
+#endif
+#include <signal.h>
+
+#ifdef _M_UNIX
+extern void NDECL(sco_mapon);
+extern void NDECL(sco_mapoff);
+#endif
+#ifdef __linux__
+extern void NDECL(linux_mapon);
+extern void NDECL(linux_mapoff);
+#endif
+
+#ifndef NHSTDC
+extern int errno;
+#endif
+
+static struct stat buf;
+
+/* see whether we should throw away this xlock file */
+static int
+veryold(fd)
+int fd;
+{
+       time_t date;
+
+       if(fstat(fd, &buf)) return(0);                  /* cannot get status */
+#ifndef INSURANCE
+       if(buf.st_size != sizeof(int)) return(0);       /* not an xlock file */
+#endif
+#if defined(BSD) && !defined(POSIX_TYPES)
+       (void) time((long *)(&date));
+#else
+       (void) time(&date);
+#endif
+       if(date - buf.st_mtime < 3L*24L*60L*60L) {      /* recent */
+               int lockedpid;  /* should be the same size as hackpid */
+
+               if(read(fd, (genericptr_t)&lockedpid, sizeof(lockedpid)) !=
+                       sizeof(lockedpid))
+                       /* strange ... */
+                       return(0);
+
+               /* From: Rick Adams <seismo!rick> */
+               /* This will work on 4.1cbsd, 4.2bsd and system 3? & 5. */
+               /* It will do nothing on V7 or 4.1bsd. */
+#ifndef NETWORK
+               /* It will do a VERY BAD THING if the playground is shared
+                  by more than one machine! -pem */
+               if(!(kill(lockedpid, 0) == -1 && errno == ESRCH))
+#endif
+                       return(0);
+       }
+       (void) close(fd);
+       return(1);
+}
+
+static int
+eraseoldlocks()
+{
+       register int i;
+
+       /* cannot use maxledgerno() here, because we need to find a lock name
+        * before starting everything (including the dungeon initialization
+        * that sets astral_level, needed for maxledgerno()) up
+        */
+       for(i = 1; i <= MAXDUNGEON*MAXLEVEL + 1; i++) {
+               /* try to remove all */
+               set_levelfile_name(lock, i);
+               (void) unlink(fqname(lock, LEVELPREFIX, 0));
+       }
+       set_levelfile_name(lock, 0);
+       if (unlink(fqname(lock, LEVELPREFIX, 0)))
+               return(0);                              /* cannot remove it */
+       return(1);                                      /* success! */
+}
+
+void
+getlock()
+{
+       register int i = 0, fd, c;
+       const char *fq_lock;
+
+#ifdef TTY_GRAPHICS
+       /* idea from rpick%ucqais@uccba.uc.edu
+        * prevent automated rerolling of characters
+        * test input (fd0) so that tee'ing output to get a screen dump still
+        * works
+        * also incidentally prevents development of any hack-o-matic programs
+        */
+       /* added check for window-system type -dlc */
+       if (!strcmp(windowprocs.name, "tty"))
+           if (!isatty(0))
+               error("You must play from a terminal.");
+#endif
+
+       /* we ignore QUIT and INT at this point */
+       if (!lock_file(HLOCK, LOCKPREFIX, 10)) {
+               wait_synch();
+               error("%s", "");
+       }
+
+       regularize(lock);
+       set_levelfile_name(lock, 0);
+
+       if(locknum) {
+               if(locknum > 25) locknum = 25;
+
+               do {
+                       lock[0] = 'a' + i++;
+                       fq_lock = fqname(lock, LEVELPREFIX, 0);
+
+                       if((fd = open(fq_lock, 0)) == -1) {
+                           if(errno == ENOENT) goto gotlock; /* no such file */
+                           perror(fq_lock);
+                           unlock_file(HLOCK);
+                           error("Cannot open %s", fq_lock);
+                       }
+
+                       if(veryold(fd) /* closes fd if true */
+                                                       && eraseoldlocks())
+                               goto gotlock;
+                       (void) close(fd);
+               } while(i < locknum);
+
+               unlock_file(HLOCK);
+               error("Too many hacks running now.");
+       } else {
+               fq_lock = fqname(lock, LEVELPREFIX, 0);
+               if((fd = open(fq_lock, 0)) == -1) {
+                       if(errno == ENOENT) goto gotlock;    /* no such file */
+                       perror(fq_lock);
+                       unlock_file(HLOCK);
+                       error("Cannot open %s", fq_lock);
+               }
+
+               if(veryold(fd) /* closes fd if true */ && eraseoldlocks())
+                       goto gotlock;
+               (void) close(fd);
+
+               if(iflags.window_inited) {
+                   c = yn("There is already a game in progress under your name.  Destroy old game?");
+               } else {
+                   (void) printf("\nThere is already a game in progress under your name.");
+                   (void) printf("  Destroy old game? [yn] ");
+                   (void) fflush(stdout);
+                   c = getchar();
+                   (void) putchar(c);
+                   (void) fflush(stdout);
+                   while (getchar() != '\n') ; /* eat rest of line and newline */
+               }
+               if(c == 'y' || c == 'Y')
+                       if(eraseoldlocks())
+                               goto gotlock;
+                       else {
+                               unlock_file(HLOCK);
+                               error("Couldn't destroy old game.");
+                       }
+               else {
+                       unlock_file(HLOCK);
+                       error("%s", "");
+               }
+       }
+
+gotlock:
+       fd = creat(fq_lock, FCMASK);
+       unlock_file(HLOCK);
+       if(fd == -1) {
+               error("cannot creat lock file (%s).", fq_lock);
+       } else {
+               if(write(fd, (genericptr_t) &hackpid, sizeof(hackpid))
+                   != sizeof(hackpid)){
+                       error("cannot write lock (%s)", fq_lock);
+               }
+               if(close(fd) == -1) {
+                       error("cannot close lock (%s)", fq_lock);
+               }
+       }
+}
+
+void
+regularize(s)  /* normalize file name - we don't like .'s, /'s, spaces */
+register char *s;
+{
+       register char *lp;
+
+       while((lp=index(s, '.')) || (lp=index(s, '/')) || (lp=index(s,' ')))
+               *lp = '_';
+#if defined(SYSV) && !defined(AIX_31) && !defined(SVR4) && !defined(LINUX) && !defined(__APPLE__)
+       /* avoid problems with 14 character file name limit */
+# ifdef COMPRESS
+       /* leave room for .e from error and .Z from compress appended to
+        * save files */
+       {
+#  ifdef COMPRESS_EXTENSION
+           int i = 12 - strlen(COMPRESS_EXTENSION);
+#  else
+           int i = 10;         /* should never happen... */
+#  endif
+           if(strlen(s) > i)
+               s[i] = '\0';
+       }
+# else
+       if(strlen(s) > 11)
+               /* leave room for .nn appended to level files */
+               s[11] = '\0';
+# endif
+#endif
+}
+
+#if defined(TIMED_DELAY) && !defined(msleep) && defined(SYSV)
+#include <poll.h>
+
+void
+msleep(msec)
+unsigned msec;                         /* milliseconds */
+{
+       struct pollfd unused;
+       int msecs = msec;               /* poll API is signed */
+
+       if (msecs < 0) msecs = 0;       /* avoid infinite sleep */
+       (void) poll(&unused, (unsigned long)0, msecs);
+}
+#endif /* TIMED_DELAY for SYSV */
+
+#ifdef SHELL
+int
+dosh()
+{
+       register char *str;
+       if(child(0)) {
+               if((str = getenv("SHELL")) != (char*)0)
+                       (void) execl(str, str, (char *)0);
+               else
+                       (void) execl("/bin/sh", "sh", (char *)0);
+               raw_print("sh: cannot execute.");
+               exit(EXIT_FAILURE);
+       }
+       return 0;
+}
+#endif /* SHELL */
+
+#if defined(SHELL) || defined(DEF_PAGER) || defined(DEF_MAILREADER)
+int
+child(wt)
+int wt;
+{
+       register int f;
+       suspend_nhwindows((char *)0);   /* also calls end_screen() */
+#ifdef _M_UNIX
+       sco_mapon();
+#endif
+#ifdef __linux__
+       linux_mapon();
+#endif
+       if((f = fork()) == 0){          /* child */
+               (void) setgid(getgid());
+               (void) setuid(getuid());
+#ifdef CHDIR
+               (void) chdir(getenv("HOME"));
+#endif
+               return(1);
+       }
+       if(f == -1) {   /* cannot fork */
+               pline("Fork failed.  Try again.");
+               return(0);
+       }
+       /* fork succeeded; wait for child to exit */
+       (void) signal(SIGINT,SIG_IGN);
+       (void) signal(SIGQUIT,SIG_IGN);
+       (void) wait( (int *) 0);
+#ifdef _M_UNIX
+       sco_mapoff();
+#endif
+#ifdef __linux__
+       linux_mapoff();
+#endif
+       (void) signal(SIGINT, (SIG_RET_TYPE) done1);
+#ifdef WIZARD
+       if(wizard) (void) signal(SIGQUIT,SIG_DFL);
+#endif
+       if(wt) {
+               raw_print("");
+               wait_synch();
+       }
+       resume_nhwindows();
+       return(0);
+}
+#endif
+
+#ifdef GETRES_SUPPORT
+
+extern int FDECL(nh_getresuid, (uid_t *, uid_t *, uid_t *));
+extern uid_t NDECL(nh_getuid);
+extern uid_t NDECL(nh_geteuid);
+extern int FDECL(nh_getresgid, (gid_t *, gid_t *, gid_t *));
+extern gid_t NDECL(nh_getgid);
+extern gid_t NDECL(nh_getegid);
+
+int
+(getresuid)(ruid, euid, suid)
+uid_t *ruid, *euid, *suid;
+{
+    return nh_getresuid(ruid, euid, suid);
+}
+
+uid_t
+(getuid)()
+{
+    return nh_getuid();
+}
+
+uid_t
+(geteuid)()
+{
+    return nh_geteuid();
+}
+
+int
+(getresgid)(rgid, egid, sgid)
+gid_t *rgid, *egid, *sgid;
+{
+    return nh_getresgid(rgid, egid, sgid);
+}
+
+gid_t
+(getgid)()
+{
+    return nh_getgid();
+}
+
+gid_t
+(getegid)()
+{
+    return nh_getegid();
+}
+
+#endif /* GETRES_SUPPORT */
diff --git a/sys/vms/Install.vms b/sys/vms/Install.vms
new file mode 100644 (file)
index 0000000..289bd42
--- /dev/null
@@ -0,0 +1,479 @@
+               Instructions for Installing NetHack 3.4.3
+                     on a VMS (aka OpenVMS) system
+               =========================================
+
+0.  Please read this entire file before trying to build or install
+    NetHack, then read it again!
+
+1.  Building NetHack requires a C compiler (either Compaq C, DEC C,
+    VAX C, or GNU C) and VMS version V4.6 or later (but see note #9).
+    This release has been tested with Compaq C V6.4 on Alpha/VMS V7.3-1
+    and with VAX C V3.2 and GNU C 2.7.1 on VAX/VMS V5.5-2.  The build
+    procedure (vmsbuild.com) should not need to be modified; it accepts
+    an option for selecting the compiler, and it can detect different
+    versions which might require specific command qualifiers.  Versions
+    of VAXC earlier than V2.3 will produce many warning messages (about
+    200 per source file; over to 25,000 total!), but NetHack has been
+    verified to compile, link, and execute correctly when built with VAXC
+    V2.2 using vmsbuild.com.  There is also a set of Makefiles suitable for
+    use with MMS or MMK; they may or may not work with other make utilities.
+
+2.  Make sure all the NetHack files are in the appropriate directory
+    structure.  You should set up a directory--referred to as "top" below
+    and in some of the assorted files, but which may be a subdirectory--
+    that has these subdirectories
+        [.dat]          -- data files
+        [.doc]          -- documentation files
+        [.include]      -- C header files
+        [.src]          -- primary source files
+        [.sys]          -- parent for [.sys.*]
+        [.sys   .share] -- files shared by several ports, including VMS
+        [.sys   .vms]   -- VMS-specific source and support files
+        [.util]         -- sources for essential utility programs
+        [.win]          -- parent for [.win.*]
+        [.win   .tty]   -- "window" routines for ordinary terminals
+                           (including terminal windows on workstations)
+    The following subdirectories may be present, but are not useful for
+    building NetHack on VMS and are not required:
+        [.sys   .amiga] -- AmigaDOS
+        [.sys   .atari] -- Atari TOS
+        [.sys   .be]    -- BeBox BeOS
+        [.sys   .mac]   -- Macintosh
+        [.sys   .msdos] -- MSDOS for IBM PCs and compatibles
+        [.sys   .os2]   -- OS/2
+        [.sys   .share   .sounds] -- AIFF format audio files
+        [.sys   .unix]  -- guess :-)
+        [.sys   .wince] -- Windows CE
+        [.sys   .wince   .ceinc] -- more WinCE
+        [.sys   .wince   .ceinc   .sys] -- ditto
+        [.sys   .winnt] -- Windows NT
+        [.win   .gem]   -- window routines for Atari/GEM
+        [.win   .gnome] -- window routines for Unix/GNOME
+        [.win   .Qt]    -- window routines for Qt
+        [.win   .share] -- "tile" graphic support
+        [.win   .win32] -- Windows NT and Windows CE
+        [.win   .X11]   -- window routines for X-Windows; requires X11R4
+                           or later and MIT's Athena Widget set
+    You must arrange things in this structure or the supplied procedures
+    and instructions in this file will not work properly.  Several DCL
+    command files are present in the [.sys.vms] subdirectory and won't
+    work as intended if they're moved elsewhere.  The file called Files
+    in the top directory contains lists of everything that should be in
+    each subdirectory, including things that are constructed as NetHack
+    is being built.
+
+3.  Prior to beginning compilation, go to the [.include] subdirectory and
+    edit vmsconf.h according to its comments.  You should set Local_WIZARD
+    and Local_HACKDIR to appropriate values, and you might want to define
+    TEXTCOLOR if you have any color VAXstations or color terminals which
+    handle ANSI-format escape sequences to set foreground and background
+    color for text characters.  (VT241/VT340 color graphics won't work.)
+    Other things which may be of interest are SECURE if you intend to
+    set up NetHack as an installed image which is granted privileges, and
+    SHELL which should be disabled if you intend to allow captive accounts
+    to run NetHack.  You may also want to edit file config.h, but that's
+    only necessary if you want or need to disable some of the game options.
+    The distributed copy of config.h will work successfully on VMS;
+    vmsconf.h has conditional code to deal with the UNIX-specific items.
+
+4.  If you have the programming utilities lex or flex and yacc or bison,
+    you may edit the procedure [.sys.vms]spec_lev.com and execute it to
+    process several source files for NetHack's special level and dungeon
+    compilers.  If you don't modify spec_lev.com, it will copy some
+    pre-processed versions of the appropriate files (dgn_lex.c, lev_lex.c,
+    dgn_yacc.c, lev_yacc.c, dgn_comp.h, and lev_comp.h) from [.sys.share]
+    into [.util]*.c and [.include]*.h.
+       $ @[.SYS.VMS]SPEC_LEV            ![OPTIONAL]
+    If you perform this step, do it prior to executing vmsbuild.com; if
+    you don't perform this step, vmsbuild.com will do so for you.
+
+5.  To build NETHACK.EXE and its auxiliary programs, execute the
+    following DCL command:
+       $ @[.SYS.VMS]VMSBUILD          !defaults to CC, either VAXC or DECC
+    or $ @[.SYS.VMS]VMSBUILD "GNUC"   !force "GCC"
+    It can take quite a bit of time for a full build to complete.
+    vmsbuild.com will display some feedback as it executes; generally
+    this will be the name of each source file that's about to be compiled
+    or the name of the executable that has just been linked.
+
+6.  If you have already started (or finished) a build and decide to start
+    over with a different compiler, you should DELETE [.SRC]CRTL.OPT;*
+    first.
+
+7.  After compilation, it's time to perform installation.  Go back to
+    the top directory.  Either edit [.sys.vms]install.com to indicate
+    where you want everything to be installed, or specify the location
+    and "playground" owner on the command line.  Then execute either
+       $ @[.SYS.VMS]INSTALL
+    or $ @[.SYS.VMS]INSTALL location owner
+    where location is a device:[directory] specification and owner is
+    either a rights identifier or UIC.  If install.com is not modified
+    and if values aren't supplied on the command line, the default values
+    used are the translation of logical name HACKDIR, if any, or else
+    [.PLAY] (relative to the current directory), and the UIC for the
+    current process.  install.com will use the auxiliary programs
+    constructed by vmsbuild.com to process quite a few data files in the
+    [.dat] subdirectory.  Then it will create the playground directory,
+    if necessary, plus the associated [.save] subdirectory.  Next it will
+    copy the data files into the playground; this step can take a while.
+    Finally it will copy nethack.exe and a few additional support files.
+
+    After it completes, the files [.src]nethack.olb, [.src]nethack.exe,
+    [.util]*.obj, [.util]*_comp.exe, and [.util]makedefs.exe can be
+    deleted in order to save disk space if desired.  The other program,
+    [.util]recover.exe, should not be deleted unless you make a copy of
+    it somewhere--perhaps in the playground directory--first.  It can be
+    used to resurrect some games disrupted by system or program crash.
+
+8.  The file nethack.com which is copied to the playground directory can
+    be used to invoke NetHack, or nethack.exe can be run directly.  Most
+    of the command-line options specified in the Unix man-page (file
+    [.doc]nethack.txt) are also applicable to VMS.  Some comments at the
+    beginning of nethack.com illustrate several of the options.  New
+    players should read the file "Guidebook.txt" which will be copied
+    into the playground directory as "Guidebook.doc".
+
+
+Notes:
+
+1.  Save files and bones files from versions 3.4.0, 3.4.1 and 3.4.2 will
+    work with 3.4.3; those from earlier versions will not.  The scoreboard
+    file (RECORD) from 3.4.x or 3.3.x will also work; one from version
+    3.2.x is slightly different format but should be compatible.
+
+2.  To specify user-preference options in your environment, define the
+    logical name NETHACKOPTIONS to have the value of a quoted string
+    containing a comma separated list of option values.  The option names
+    are case-insensitive.
+       $ define nethackoptions "noAutoPickup,Dog:Rover,Cat:Felix,DECgraphics"
+    One value you'll probably want to specify is "noLegacy" to turn off
+    the initial introductory passage.  The "checkpoint" option controls
+    whether or not enough data is saved to disk so that the set of level
+    files left behind after a crash contains sufficient information for
+    recover.exe to be able to construct a save file after the fact.  The
+    tradeoff for enabling checkpoint is that using it makes level changes
+    do more I/O and take longer.  The "menustyle" option controls some
+    aspects of the user interface, and can be set to "menustyle:traditional"
+    to make nethack behave more like older versions.
+
+    If logical name or DCL symbol NETHACKOPTIONS is not defined, NetHack
+    will try HACKOPTIONS instead.  Regardless of whether or not either
+    is defined, it will also try to find a configuration file containing
+    additional option settings.  If the value of the translation of
+    NETHACKOPTIONS--or HACKOPTIONS--begins with an "@" character then the
+    rest of the translation is assumed to be the name of the configuration
+    file.  Otherwise, the following are tried:  file specified by logical
+    name NETHACKINI, file SYS$LOGIN:NETHACK.INI, and file HOME:NETHACK.CNF
+    (note that the C run-time library sets up the value of HOME to match
+    sys$login).  Syntax for the configuration file is similar to
+    NETHACKOPTIONS, but multiple lines can be used, each must start with
+    OPTIONS=, and comments can be included by placing '#' in the first
+    column.  Several options which take more complex values (graphics
+    representation) can also be present; see the "Guidebook" for details.
+    (Guidebook.txt can be found in the [.doc] subdirectory; a copy gets
+    placed in the playground directory by install.com.  Also, an example
+    configuration file can be found in [.win.X11]nethack.rc.)
+
+3.  Instead of using vmsbuild.com to compile and link everything, you can
+    use the set of Makefiles found in the vms subdirectory, provided you
+    have an appropriate and compatible make utility.  They've been tested
+    using MMK, a freeware clone of Digital's MMS.  There are five of them,
+    and the suffix or filetype on their names indicates where they should
+    be placed.
+       $ copy [.sys.vms]Makefile.top []Makefile.
+       $ copy [.sys.vms]Makefile.src [.src]Makefile.
+       $ copy [.sys.vms]Makefile.utl [.util]Makefile.
+       $ copy [.sys.vms]Makefile.dat [.dat]Makefile.
+       $ copy [.sys.vms]Makefile.doc [.doc]Makefile.
+    After doing that, edit [.src]Makefile and [.util]Makefile to specify
+    pertinent compiler options in CFLAGS, linker options in LFLAGS, and
+    libraries in LIBS and/or MORELIBS if the default values aren't right.
+    Be sure to make compatible compilation and linking settings in both
+    files.  While in there, edit [.util]Makefile to specify the appropriate
+    values for lex and yacc, _or_ move to that directory and use MMS or
+    make to build targets no_lex and no_yacc which will copy several
+    pre-processed files from [.sys.share] into [.util].  Finally, edit
+    Makefile in the top directory to specify values for GAMEDIR and
+    GAMEOWNER.  This top Makefile invokes [.sys.vms]install.com to do
+    much of the actual installation work, so if you want to make any
+    customizations or file protection changes, edit install.com to suit.
+    Also set MAKE in all of the Makefiles to the appropriate command if
+    not using MMS or MMK.
+
+    Once the Makefiles are tailored for your site, give the command
+       $ mms all,install
+    or $ make all install
+    To compile and install everything.  The object files compiled via
+    the Makefiles are left as individual .OBJ files rather than placed
+    into an object library (in contrast to step #7 above and note #10
+    below).  These Makefiles are provided on an as-is basis; vmsbuild.com
+    is the preferred way to compile because it's guaranteed to compile
+    and link everything.
+
+4.  termcap is an ASCII data file containing descriptions of terminal
+    capabilities and the escape sequences that software must use to take
+    advantage of them.  If you do not already have a termcap file in use
+    on your system there is a small one in file [.SYS.SHARE]TERMCAP.  It
+    contains definitions for common Digital terminals, also suitable for
+    most clones and emulators.  This file is copied into the playground
+    by install.com, and NetHack will use it if it can't find any other
+    one.  NetHack uses the following sequence to attempt to locate the
+    termcap file:  translation of the logical name TERMCAP (used as-is),
+    file NETHACKDIR:TERMCAP, similar file HACKDIR:TERMCAP, GNU-Emacs file
+    EMACS_LIBRARY:[ETC]TERMCAP.DAT, file []TERMCAP, and lastly file
+    $TERMCAP (which most likely would be a logical name).  If NetHack
+    can't find the termcap file, or if the above search sequence finds a
+    different one than you'd prefer, then use the DCL ASSIGN or DEFINE
+    command to define a value for logical name TERMCAP.
+
+    NetHack also tries fairly hard to figure out what kind of terminal
+    you're using.  It checks for logical names (or symbols) NETHACK_TERM,
+    HACK_TERM, EMACS_TERM, and lastly TERM.  The last is set up by the
+    C run-time library and you cannot use a logical name or symbol for
+    it.  If all those fail, or if whichever one succeeds has a value of
+    "undefined" or "unknown" (which can happen under VMS V5.4-* and
+    V5.5-* for VT420 terminals), NetHack will query the VMS TERMTABLE
+    database used by the SMG library routines.  Whatever value NetHack
+    eventually comes up with needs to be the name of an entry in the
+    termcap file, otherwise a message about "Unknown terminal type" will
+    be printed and NetHack will exit.
+
+5.  NetHack contains code which attempts to make it secure in case it's
+    installed with privileges (to allow the playground to be protected
+    against world write access).  This has only undergone limited testing,
+    so install NetHack with privileges at your own risk.  If you discover
+    any potential security holes, please let us know so that we can take
+    steps to correct the problem(s).  NetHack always includes filename
+    punctuation when accessing files, so that it should never be affected
+    by inadvertent or malicious logical name definitions, and it always
+    deactivates installed privileges prior to spawning a subprocess.
+
+    Note to end users:  "installing with privileges" is an option for
+    system managers who set up system-wide access to the game.  Since
+    CMKRNL privilege and modification of the system boot routines are
+    both required, it is not an option for ordinary users.  There are
+    no explicit instructions on how to do such an installation, because
+    only system managers who are already familiar with the process and
+    its potential security ramifications should even consider it.
+
+    The default setup by install.com assumes no privileges and uses
+    world-writable files to allow arbitrary users to play.  This is
+    NOT secure and not advisable in any environment where there are
+    untrustworthy users, but works fine for many sites.  If you allow
+    users to run NetHack from captive accounts (VMS 5.1-* or earlier)
+    or from restricted accounts (5.2 and later), you should either make
+    sure that they do not have TMPMBX privilege or else disable NetHack's
+    ability to spawn an interactive subprocess.  To disable subprocesses,
+    disable the "!" (shell escape) command by commenting out the definition
+    of SHELL in vmsconf.h prior to building the program.  This necessity
+    may be removed in some future release, where NetHack will check for
+    captive accounts instead of spawning unconditionally.  Note that
+    disabling the SHELL command also prevents spawning MAIL when scrolls
+    of new mail are received.
+
+    In order for installed privileges to be used at all, the value of
+    HACKDIR (via Local_HACKDIR in vmsconf.h) compiled into the program
+    must correspond to the actual playground directory.  If logical name
+    HACKDIR (or NETHACKDIR) is used to override that value, installed
+    privileges will be deactivated unless its value corresponds to the
+    same device and directory as the internal value.  If that internal
+    value contains a logical name, only an executive-mode translation
+    will be honored; if there is no such translation, installed privs
+    will be deactivated.
+
+    To be able to install nethack.exe with privileges (SYSPRV or GRPPRV,
+    perhaps EXQUOTA, depending on site usage and needs), you'll need to
+    link it with debugging and tracebacks both disabled.  You can do this
+    by specifying an argument to vmsbuild.com when performing step #6
+    above; pass it "/noTrace/noDebug" as the 4th parameter.
+       $ @[.SYS.VMS]VMSBUILD "" "" "" "/noTrace/noDebug"
+    /Trace/noDebug is the linker's normal default.  If you've already
+    built NetHack, you can relink with tracebacks disabled by doing
+       $ @[.SYS.VMS]VMSBUILD "LINK" "" "" "/noTrace/noDebug"
+
+6.  If you can't or won't install nethack.exe with privileges and if you
+    don't have access to a privileged account yourself, then if you intend
+    to allow other users to access your copy of NetHack you should probably
+    place an ACL on the playground directory and its save subdirectory.
+    The access control list should contain a default protection ACE which
+    grants delete+control access to the playground owner (ie, your own
+    account if there's no special games account involved).  install.com
+    does not attempt to do this automatically at the present time.  After
+    executing install.com to create the playground directory, perform a
+    pair of commands similar to the following
+       $ SET ACL/ACL=(IDENT=your_id, OPTIONS=DEFAULT, ACCESS=R+W+E+D+C) -
+       $_ device:[playground's.parent.directory]playground.DIR
+       $ SET ACL/ACL=(IDENT=your_id, OPTIONS=DEFAULT, ACCESS=R+W+E+D+C) -
+       $_ device:[playground.directory]SAVE.DIR
+    The two commands use the same options, but SET ACL won't accept a
+    list of files to modify.  (For recent versions of VMS, SET ACL was
+    made obsolete in favor of SET FILE/ACL, which in turn has been made
+    obsolete in favor of SET SECURITY/CLASS=FILE/ACL; however, the older
+    forms will still work.)  'your_id' should be the rights identifier
+    which corresponds to the account which should retain access to those
+    files; 'device:[playground's.parent.directory]' is the name of the
+    parent directory for the playground (ie, if your playground directory
+    is disk$foo:[me.games.nethack.play], then you want to specify
+    disk$foo:[me.games.nethack]play.dir on the SET ACL command), and
+    'device:[playground.directory]' is the playground itself.  Those ACLs
+    establish a default protection scheme such that every newly created
+    file in those directories will have an ACL attached to it, and the
+    attached ACL will grant 'your_id' full access to the corresponding
+    file.  That should allow you to clear away level files from aborted
+    games, and to delete old save files if necessary.  It will not enable
+    you to run recover.exe on behalf of other users, because you won't be
+    able to create files owned by them unless you have elevated privileges.
+
+7.  Many NetHack commands can be aborted by sending it the <escape>
+    character when it wants input.  This is displayed as ESC inside the
+    game.  Digital VK201 keyboards (used by VT2xx and VT3xx and older
+    VAXstations) and VK401 keyboards (used by VT4xx, newer VAXstations,
+    and DEC's X Terminals) do not have an <escape> key.  They may
+    transmit <escape> for the <F11> key if the terminal or emulator
+    window is set to operate in VT100 mode, or there may be a setup-type
+    option for making the <` | ~> key behave as <escape>.  If your
+    terminal does not have that, or if it's set to a mode where that
+    won't work, then just use <ctrl/[> instead.  (Press the "[" key while
+    holding down the "Ctrl" key, then release both; <escape> and <ctrl/[>
+    have the same ASCII code and are indistinguishable once they reach
+    the computer; note that VAXstations and X Terminals _can_ tell the
+    difference, but that won't matter for NetHack.)
+
+    VMS NetHack is configured to use the SYS$QIOW system service for
+    reading characters from the keyboard.  This allows ^C and ^Y (as well
+    as ^X and ^O for wizard mode debugging) to be used as commands without
+    being intercepted or interpreted by the terminal driver.  The code
+    which parses arrow and function keys is not perfect, and it's possible
+    to get strange results if you hold such keys down or just type too
+    quickly, particularly on slow multiplexor lines.  Those keys are
+    never needed in actual play, and most function keys are just treated
+    as <escape> for use in aborting partial commands.
+
+    VMS NetHack also still has code to use SMG$READ_KEYSTROKE instead.
+    That can be activated by modifying vmsconf.h and recompiling, but
+    it should never be necessary.  If you use it, you'll need to press
+    either <esc> or <ctrl/[> twice to abort partial commands, or else
+    press an arbitrary function key, such as <PF4>, once.
+
+    If SUSPEND is defined in vmsconf.h, <ctrl/Z> is used for that command.
+    Since Unix-style job control is not available, it's used for connecting
+    to the parent process if NetHack is running in a subprocess.  When not
+    in a subprocess, it doesn't do anything except give a message to the
+    effect that it's not doing anything....  The suspend command does not
+    save the current game; if you use ^Z to attach to your parent process,
+    be sure to remember to eventually reattach to the NetHack subprocess;
+    otherwise the game in progress won't get saved when you logout.
+
+8.  NetHack optionally maintains a logfile which receives one line appended
+    to it whenever a game ends.  This can be disabled entirely by adding
+    an "#undef LOGFILE" directive to vmsconf.h prior to building the
+    program, or it can be disabled later by removing the file(s) LOGFILE.;*
+    from the playground directory.  If not disabled prior to compilation,
+    the logfile can be reinitialized by simply creating an empty file
+    named LOGFILE in the playground, but make sure that users are able
+    to write into it, or new entries will not be appended.
+
+9.  Some attempt at support for VMS versions earlier than V4.6 has been
+    included, but no such obsolete system was available for testing it.
+    vmsbuild.com detects the need for the extra support routines and
+    arranges automatically for them to be compiled.  The reason that
+    special support is needed is that the C Run-Time Library (VAXCRTL)
+    underwent a major revision for VMS V4.6 and several routines which
+    NetHack utilizes were not available prior to that upgrade.
+
+10. vmsbuild.com collects almost all of the object files (xxx.OBJ) into
+    an object library (NETHACK.OLB) as it compiles the source files.
+    This should prevent the quota-exceeded problems from the linker
+    that some sites have reported for prior versions.  Note that if you
+    compile any source files manually, you'll need to replace those
+    modules in the object library prior to linking the program:
+       $ cc/include=[-.include] [-.sys.vms]vmstty   !for example
+       $ libr/obj []nethack vmstty                  !replace VMSTTY
+       $ @[-.sys.vms]vmsbuild LINK                  !re-link NETHACK.EXE
+    If you forget to replace the library entry, your newly compiled code
+    will not be included in the new executable image.
+
+11. To access "wizard mode"--intended for debugging purposes, not to
+    spoil the game with unlimited wishes--you must be running from the
+    username compiled into the game via Local_WIZARD in vmsconf.h, and
+    you must specify "-D" on the command line when invoking NetHack.
+    Note that -D must be uppercase, and it must be in quotes to prevent
+    the C run-time library's program startup code from converting it into
+    lowercase.
+       $ @hackdir:nethack "-D"
+    Any character name you specify will be ignored in favor of "wizard".
+
+12. At program startup time, NetHack uses the empty file PERM to prevent
+    two different processes from using the same character name (under the
+    same UIC ownership) at the same time.  It does this by temporarily
+    giving that file a second directory entry named PERM.LOCK, then
+    removing the alternate entry once started.  If the PERM file is
+    missing or inaccessible, NetHack will give a message and then quit.
+    Several possible messages and their usual causes are:
+       Can't find file perm;1 to lock!
+    PERM.;1 is missing from the playground directory.  Fix:  reinstall
+    the playground directory using install.com, or use CREATE or an editor
+    to make an empty file named PERM.  Version number must be 1.
+       Can't lock perm;1 due to directory protection.
+    The playground directory is not allowing write access.  Fix:  players
+    need to be able to write files for dungeon levels and "bones" into
+    the playground directory.  Set the protection or ACL on the xxx.DIR;1
+    file in the playground's parent directory to allow write access.
+       Can't unlink perm.lock;1.
+    The empty file PERM.;1 is protected against delete access; only matters
+    under some versions of VMS.  Fix:  set the protection or ACL on PERM.;1
+    to allow delete access to players.  Under VMS V5.5-2, delete access is
+    not necessary.  PERM does not have to remain writable.
+       Waiting for access to perm;1.  (# retries left).
+    If some other process is also starting up NetHack at about the same
+    time, you may have to wait a short period.  NetHack will retry once
+    per second, counting down to 0.  If 0 is reached, the message
+       Perhaps there is an old perm.lock;1 around?
+    will be displayed and then NetHack will give up.  Fix:  to forcibly
+    remove a stale PERM.LOCK entry, issue the following command
+       $ SET FILE/REMOVE PERM.LOCK;1
+    from the playground directory.  The file PERM should remain intact.
+    Do not use that command for real files, only alternate directory
+    entries.  If output from a DIRECTORY command on the playground reports
+       PERM.LOCK;1          no such file
+    then someone has deleted PERM.;1 while the synonym entry was still
+    in place, and PERM.LOCK was left as a dangling name which no longer
+    points at any file.  The SET FILE/REMOVE command above will fix the
+    dangling name; a new PERM.;1 will need to be created as mentioned above.
+
+    In similar fashion, synchronized access to the scoreboard file RECORD
+    is accomplished using temporary entry RECORD.LOCK and LOGFILE using
+    entry LOGFILE.LOCK.
+
+13. Unless you have both Motif and the Athena Widget set from MIT, you
+    will not be able to use the X11 interface on VMS.  Even if you do
+    have both those things, such a configuration has not been tested and
+    there are no provisions for it in vmsbuild.com.  Makefile.src does
+    have the extra source files listed, but not the necessary libraries.
+
+    The X11 port will not compile and link with DECwindows, but it will
+    be able to display on a VMS DECwindows X server provided that it and
+    its Unix X client have a compatible transport between them (either
+    TCP/IP added to VMS or DECnet added to Unix) and session security
+    is set up appropriately.  You'll need to add the contents of file
+    [.win.X11]NetHack.ad into your DECW$USER_DEFAULTS:DECW$XDEFAULTS.DAT,
+    and modify some of the lines.  The DECwindows window manager does not
+    support having input focus automatically follow the pointer, so you
+    should uncomment the "NetHack*autofocus" resource line.  (For Motif
+    this may not be necessary, depending on customization options.)
+    Uncommenting the "NetHack*slow" line is highly recommended.  You'll
+    also need to set "NetHack*fonts: fixed" (rather than "variable"), and
+    either set the map font to "fixed" too or install the "nh10" font
+    that comes in file [.win.X11]nh10.bdf.  If NetHack warns that the map
+    font is variable, then something isn't set up properly.
+
+    After creating or modifying decw$xdefaults.dat, you must restart the
+    window manager in order for any changes to take effect; it's easiest
+    to just make the session manager quit and then log in again.
+
+14. If necessary, send problem reports via e-mail to
+       <devteam@nethack.org>
+    Always include version information for NetHack, the operating system,
+    and the C compiler used.
+
+20-OCT-2003
diff --git a/sys/vms/Makefile.dat b/sys/vms/Makefile.dat
new file mode 100644 (file)
index 0000000..d2ee9a3
--- /dev/null
@@ -0,0 +1,137 @@
+#      NetHack Makefile (VMS) - data files: special levels and other data.
+#      SCCS Id: @(#)Makefile.dat       3.4     2002/03/02
+
+#  Copy this file to [.dat]Makefile.; no editing needed.
+
+MAKE   = $(MMS)
+CD     = set default
+ECHO   = write sys$output
+NOOP   = continue              # don't do anything interesting
+RUN    = mcr                   # simplest way to pass command line args
+TOUCH  = append/New _NLA0:     # only one file per $(TOUCH)
+# support directories, relative to each other and to 'src'
+DAT = [-.dat]
+UTL = [-.util]
+WINSHR = [-.win.share]
+WINX11 = [-.win.X11]
+# utilities; must match Makefile.utl in spelling and punctuation
+MAKEDEFS = $(UTL)makedefs.exe;
+LEVCOMP  = $(UTL)lev_comp.exe;
+DGNCOMP  = $(UTL)dgn_comp.exe;
+DLB     = $(UTL)dlb.exe;
+TILE2X11 = $(UTL)tile2x11.exe;
+UTILMARKER = $(UTL)util.timestamp;
+
+# note: filespecs have enough punctuation to satisfy DELETE
+MARKERS = spec_levs.timestamp;,quest_levs.timestamp; 
+VARDAT = data.;,rumors.;,quest.dat;,oracles.;,options.;
+DUNGEON = dungeon.;
+X11TILES= x11tiles.;
+# note: the level lists need to be space separated
+QUESTLEVS = Arch.des Barb.des Caveman.des Healer.des Knight.des \
+       Monk.des Priest.des Ranger.des Rogue.des Samurai.des Tourist.des \
+       Valkyrie.des Wizard.des
+SPECLEVS  = bigroom.des castle.des endgame.des gehennom.des knox.des \
+       medusa.des mines.des oracle.des sokoban.des tower.des yendor.des
+
+all :  $(VARDAT) $(DUNGEON) $(MARKERS) $(DLB)
+      @ $(ECHO) "data files are up to date."
+
+# these are convenience targets for "manual" interactive use
+spec_levs :    spev_levs.timestamp
+      @ $(ECHO) "special levels are up to date."
+quest_levs :   quest_levs.timestamp
+      @ $(ECHO) "quest levels are up to date."
+dungeon :      $(DUNGEON)
+      @ $(ECHO) "dungeon is up to date."
+data :         data.;
+      @ $(NOOP)
+rumors :       rumors.;
+      @ $(NOOP)
+quest.dat :    quest.dat;
+      @ $(NOOP)
+oracles :      oracles.;
+      @ $(NOOP)
+options :      options.;
+      @ $(NOOP)
+x11tiles :     $(X11TILES)
+      @ $(NOOP)
+
+$(MAKEDEFS) : $(UTILMARKER)
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) $(MAKEDEFS)
+      @ $(CD) $(DAT)
+
+$(DGNCOMP) : $(UTILMARKER)
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) $(DGNCOMP)
+      @ $(CD) $(DAT)
+
+$(LEVCOMP) : $(UTILMARKER)
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) $(LEVCOMP)
+      @ $(CD) $(DAT)
+
+$(DLB) : $(UTILMARKER)
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) $(DLB)
+      @ $(CD) $(DAT)
+
+$(TILE2X11) : $(UTILMARKER)
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) $(TILE2X11)
+      @ $(CD) $(DAT)
+
+$(X11TILES) : $(TILE2X11) \
+               $(WINSHR)monsters.txt $(WINSHR)objects.txt $(WINSHR)other.txt
+       $(RUN) $(TILE2X11) \
+               $(WINSHR)monsters.txt $(WINSHR)objects.txt $(WINSHR)other.txt
+
+pet_mark.xbm : $(WINX11)pet_mark.xbm
+       copy $(WINX11)pet_mark.xbm pet_mark.xbm
+
+rip.xpm : $(WINX11)rip.xpm
+       copy $(WINX11)rip.xpm rip.xpm
+
+
+data.; :       data.base $(MAKEDEFS)
+       $(RUN) $(MAKEDEFS) -d
+
+rumors.; :     rumors.tru rumors.fal $(MAKEDEFS)
+       $(RUN) $(MAKEDEFS) -r
+
+quest.dat; :   quest.txt $(MAKEDEFS)
+       $(RUN) $(MAKEDEFS) -q
+
+oracles.; :    oracles.txt $(MAKEDEFS)
+       $(RUN) $(MAKEDEFS) -h
+
+# note: 'options' should have already been made when include/date.h was created
+options.; :    $(MAKEDEFS)
+       $(RUN) $(MAKEDEFS) -v
+
+spec_levs.timestamp; : $(SPECLEVS) $(LEVCOMP)
+       $(RUN) $(LEVCOMP) $(SPECLEVS)
+       $(TOUCH) spec_levs.timestamp;
+
+quest_levs.timestamp; : $(QUESTLEVS) $(LEVCOMP)
+       $(RUN) $(LEVCOMP) $(QUESTLEVS)
+       $(TOUCH) quest_levs.timestamp;
+
+$(DUNGEON) :   dungeon.def $(MAKEDEFS) $(DGNCOMP)
+       $(RUN) $(MAKEDEFS) -e           !dungeon.def -> dungeon.pdf
+       $(RUN) $(DGNCOMP) dungeon.pdf   !dungeon.pdr -> dungeon
+
+clean :
+      - if f$search("*.*;-1").nes."" then  purge
+      - if f$search("dungeon.pdf").nes."" then delete dungeon.pdf;
+      - if f$search("*.timestamp").nes."" then delete $(MARKERS)
+
+spotless :     clean
+      - delete $(VARDAT)
+      - if f$search("$(DUNGEON)").nes."" then  delete $(DUNGEON)
+      - if f$search("*.lev").nes."" then  delete *.lev;
+      - if f$search("$(X11TILES)").nes."" then  delete $(X11TILES)
+      - if f$search("*.x%m").nes."" then  delete *.x%m;                !*.xbm,*.xpm
+      - if f$search("nh*.dlb").nes."" then  delete nh*.dlb;
+      - if f$search("nhdat.lst").nes."" then  delete nhdat.lst;
diff --git a/sys/vms/Makefile.doc b/sys/vms/Makefile.doc
new file mode 100644 (file)
index 0000000..1de8642
--- /dev/null
@@ -0,0 +1,68 @@
+#      NetHack Makefile (VMS) - for the [Unix] documentation.
+#      SCCS Id: @(#)Makefile.doc       3.4     1993/01/06
+
+#  Copy this file to [.doc]Makefile. and edit it if needed.
+
+GUIDEBOOK = Guidebook.         # regular ASCII file
+#GUIDEBOOK = Guidebook.ps      # PostScript file
+#GUIDEBOOK = Guidebook.dvi     # TeX device-independent file
+
+ALLDOCS = $(GUIDEBOOK)
+#ALLDOCS = $(GUIDEBOOK) manpages
+
+NOOP = !
+
+Guidebook :    $(GUIDEBOOK)
+       $(NOOP)
+
+# the basic guidebook
+#Guidebook. :  Guidebook.mn
+#      #tbl tmac.n Guidebook.mn | nroff | col > Guidebook
+#      write sys$output "Guidebook.mn cannot be processed under VMS."
+Guidebook. :   Guidebook.txt           # distributed version of plain text
+       copy Guidebook.txt Guidebook.
+
+# Fancier output for those with ditroff, psdit and a PostScript printer.
+#Guidebook.ps : Guidebook.mn
+#      #tbl tmac.n Guidebook.mn | ditroff | psdit > Guidebook.ps
+#      write sys$output "Guidebook.mn cannot be processed under VMS."
+Guidebook.ps : Guidebook.dvi           # generated with LaTeX
+       dvi2ps Guidebook
+
+# Guidebook.tex is the same as Guidebook.mn but formatted with LaTeX.
+# - The invocation command for LaTeX may vary in different installations.
+# - To print Guidebook.dvi you need to use a suitable dvi-driver.
+Guidebook.dvi :  Guidebook.tex
+       latex Guidebook.tex
+
+all : $(ALLDOCS)
+       $(NOOP)
+
+GAME   = nethack
+MANDIR = HACKDIR:
+MANEXT = man
+#MANDIR = /usr/man/man6
+#MANEXT = 6
+
+# manual non-installation; raw man pages may be better than nothing
+GAMEMANCREATE = copy nethack.6
+LEVMANCREATE = copy lev_comp.6
+DGNMANCREATE = copy dgn_comp.6
+RCVRMANCREATE = copy recover.6
+# GAMEMANCREATE = nroff -man nethack.6 >
+# LEVMANCREATE = nroff -man lev_comp.6 >
+# DGNMANCREATE = nroff -man dgn_comp.6 >
+# RCVRMANCREATE = nroff -man recover.6 >
+
+manpages :
+       - $(GAMEMANCREATE) $(MANDIR)$(GAME).$(MANEXT)
+       - $(LEVMANCREATE) $(MANDIR)lev_comp.$(MANEXT)
+       - $(DGNMANCREATE) $(MANDIR)dgn_comp.$(MANEXT)
+       - $(RCVRMANCREATE) $(MANDIR)recover.$(MANEXT)
+
+spotless :
+       - if f$search("Guidebook.")   .nes."" then  delete Guidebook.;*
+       - if f$search("Guidebook.ps") .nes."" then  delete Guidebook.ps;*
+       - if f$search("Guidebook.dvi").nes."" then  delete Guidebook.dvi;*
+       - if f$search("Guidebook.aux").nes."" then  delete Guidebook.aux;*
+       - if f$search("Guidebook.log").nes."" then  delete Guidebook.log;*
diff --git a/sys/vms/Makefile.src b/sys/vms/Makefile.src
new file mode 100644 (file)
index 0000000..fc96b1b
--- /dev/null
@@ -0,0 +1,463 @@
+#      NetHack Makefile (VMS) - for building nethack itself.
+#      SCCS Id: @(#)Makefile.src       3.4     2003/02/13
+
+#  Copy this file to [.src]Makefile. and then edit it as needed.
+#  The default configuration is for building with DEC C (aka Compaq C).
+#  If you changed CC or CFLAGS, make similar changes in [.util]Makefile.
+#
+#  Note:  modifying this Makefile will cause crtl.opt to be rebuilt,
+#      which will trigger an update of makedefs, which will in turn
+#      result in a full build of just about _everything_.
+
+MAKE   = $(MMS)
+CD     = set default
+ECHO   = write sys$output
+NOOP   = continue
+RUN    = mcr
+TOUCH  = append/New _NLA0:     # only one file per $(TOUCH)
+# source tree, relative to 'src' and 'util'
+INC = [-.include]
+SYSSHR = [-.sys.share]
+SRC = [-.src]
+TTY = [-.win.tty]
+UTL = [-.util]
+VMS = [-.sys.vms]
+WINSHR = [-.win.share]
+X11 = [-.win.X11]
+
+MAKEFILE= $(SRC)Makefile.
+
+# if you are using gcc as your compiler:
+#      uncomment the CC definition below if it's not in your environment
+# CC = gcc
+
+# set option flags for C compiler and linker
+#
+CFLAGS = /Prefix=All/Incl=$(INC)/noList        # DECC in native mode
+#CFLAGS        = /Include=$(INC)/noList        # VAXC or GNUC
+#LFLAGS        = /Debug/Map/Cross_Ref                  # for development
+#LFLAGS        = /noTraceback/noMap                    # for installing w/ privs
+LFLAGS = /noMap
+LINK   = link
+
+LIBS   =                                       # blank for DECC
+#LIBS  = sys$share:vaxcrtl.exe/Shareable       # VAX C or GNU C
+MORELIBS =
+# GCC needs an extra library
+#MORELIBS = gnu_cc:[000000]gcclib.olb/Library
+
+# Specific VMS object files
+SYSSRC = $(VMS)vmsmain.c,$(VMS)vmstty.c,$(VMS)vmsunix.c,\
+       $(VMS)vmsmisc.c,$(VMS)vmsfiles.c,$(VMS)vmsmail.c
+SYSOBJ = vmsmain.obj,vmstty.obj,vmsunix.obj,vmsfiles.obj,vmsmail.obj #,vmsmisc.obj
+LIBOPT = $(SRC)crtl.opt;
+
+# termcap library
+TERMCAPSRC = tclib.c
+TERMCAPOBJ = ,tclib.obj
+
+# Set WINSRC and WINOBJ lines corresponding to your desired combination
+# of windowing systems.  Also set windowing systems in config.h.
+#
+# a straight tty port using no native windowing system
+WINTTYSRC = $(TTY)getline.c $(TTY)termcap.c $(TTY)topl.c $(TTY)wintty.c \
+       $(TERMCAPSRC)
+WINTTYOBJ = getline.obj,termcap.obj,topl.obj,wintty.obj $(TERMCAPOBJ)
+#
+# an X11 port (not supported under DECwindows)
+WINX11SRC = $(X11)Window.c $(X11)dialogs.c $(X11)winX.c $(X11)winmap.c \
+       $(X11)winmenu.c $(X11)winmesg.c $(X11)winmisc.c $(X11)winstat.c \
+       $(X11)wintext.c $(X11)winval.c $(SRC)tile.c
+WINX11OBJ = Window.obj,dialogs.obj,winX.obj,winmap.obj,winmenu.obj,\
+       winmesg.obj,winmisc.obj,winstat.obj,wintext.obj,winval.obj,tile.obj
+#
+#
+WINSRC = $(WINTTYSRC)
+WINOBJ = $(WINTTYOBJ)
+
+# make NetHack for VMS
+SYSTEM = SysVMS.timestamp;
+GAME   = $(SRC)nethack.exe;
+
+# RANDOM is defined in vmsconf.h
+RANDSRC = random.c
+RANDOBJ = random.obj
+
+# ----------------------------------------
+#
+# Nothing below this line should have to be changed.
+#
+# Other things that have to be reconfigured are in vmsconf.h,
+# and config.h
+
+VERSION  = 3.4.3
+
+MAKEDEFS = $(UTL)makedefs.exe;
+
+# timestamp files to reduce `make' overhead and shorten .obj dependency lists
+CONFIG_H = $(SRC)config.h-t
+HACK_H = $(SRC)hack.h-t
+
+# all .c that are part of the main NetHack program and are not operating- or
+# windowing-system specific
+HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \
+          botl.c cmd.c dbridge.c decl.c detect.c dig.c display.c dlb.c do.c \
+          do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c drawing.c \
+          dungeon.c eat.c end.c engrave.c exper.c explode.c extralev.c \
+          files.c fountain.c hack.c hacklib.c invent.c light.c lock.c mail.c \
+          makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c minion.c mklev.c mkmap.c \
+          mkmaze.c mkobj.c mkroom.c mon.c mondata.c monmove.c monst.c \
+          mplayer.c mthrowu.c muse.c music.c o_init.c objects.c objnam.c \
+          options.c pager.c pickup.c pline.c polyself.c potion.c pray.c \
+          priest.c quest.c questpgr.c read.c rect.c region.c restore.c rip.c rnd.c \
+          role.c rumors.c save.c shk.c shknam.c sit.c sounds.c sp_lev.c spell.c \
+          steal.c steed.c teleport.c timeout.c topten.c track.c trap.c u_init.c \
+          uhitm.c vault.c version.c vision.c weapon.c were.c wield.c \
+          windows.c wizard.c worm.c worn.c write.c zap.c
+
+# generated source files (tile.c is handled separately via WINxxxSRC)
+GENCSRC = monstr.c vis_tab.c   #tile.c
+
+# .c files for this version (for date.h)
+VERSOURCES = $(HACKCSRC) $(SYSSRC) $(WINSRC) $(RANDSRC) $(GENCSRC)
+
+# all .h files except date.h, onames.h, pm.h, and vis_tab.h which would
+# cause dependency loops if run through "make depend"
+# and dgn_comp.h, dgn_file.h, lev_comp.h, special level & dungeon files.
+#
+HACKINCL = align.h amiconf.h artifact.h artilist.h attrib.h beconf.h color.h \
+          config.h config1.h coord.h decl.h def_os2.h display.h dlb.h \
+          dungeon.h edog.h emin.h engrave.h epri.h eshk.h extern.h flag.h \
+          func_tab.h global.h hack.h lev.h macconf.h mfndpos.h micro.h \
+          mkroom.h monattk.h mondata.h monflag.h monst.h monsym.h obj.h \
+          objclass.h os2conf.h patchlevel.h pcconf.h permonst.h prop.h rect.h \
+          region.h rm.h sp_lev.h spell.h system.h tcap.h timeout.h tosconf.h \
+          tradstdc.h trampoli.h trap.h unixconf.h vault.h vision.h vmsconf.h \
+          wintty.h winX.h winprocs.h wintype.h you.h youprop.h
+
+#HSOURCES = $(HACKINCL) date.h onames.h pm.h vis_tab.h\
+#              lev_comp.h dgn_comp.h dgn_file.h
+
+# the following .obj's should be made before any others (for makedefs)
+FIRSTOBJ = vmsmisc.obj,monst.obj,objects.obj
+
+# split up long list so that we can write pieces of it into nethack.opt
+HOBJ1 = allmain.obj,alloc.obj,apply.obj,artifact.obj,attrib.obj, \
+       ball.obj,bones.obj,botl.obj,cmd.obj,dbridge.obj,decl.obj, \
+       detect.obj,dig.obj,display.obj,dlb.obj,do.obj,do_name.obj,do_wear.obj
+HOBJ2 = dog.obj,dogmove.obj,dokick.obj,dothrow.obj,drawing.obj, \
+       dungeon.obj,eat.obj,end.obj,engrave.obj,exper.obj,explode.obj, \
+       extralev.obj,files.obj,fountain.obj,hack.obj,hacklib.obj,invent.obj
+HOBJ3 = light.obj,lock.obj,mail.obj,makemon.obj,mapglyph.obj,mcastu.obj, \
+       mhitm.obj,mhitu.obj,minion.obj,mklev.obj,mkmap.obj,mkmaze.obj, \
+       mkobj.obj,mkroom.obj,mon.obj,mondata.obj,monmove.obj,monstr.obj
+HOBJ4 = mplayer.obj,mthrowu.obj,muse.obj,music.obj,o_init.obj,objnam.obj, \
+       options.obj,pager.obj,pickup.obj,pline.obj,polyself.obj, \
+       potion.obj,pray.obj,priest.obj,quest.obj,questpgr.obj,read.obj
+HOBJ5 = rect.obj,region.obj,restore.obj,rip.obj,rnd.obj,role.obj, \
+       rumors.obj,save.obj,shk.obj,shknam.obj,sit.obj,sounds.obj,sp_lev.obj, \
+       spell.obj,steal.obj,steed.obj,teleport.obj,timeout.obj,topten.obj, \
+       track.obj,trap.obj
+HOBJ6 = u_init.obj,uhitm.obj,vault.obj,vision.obj,vis_tab.obj,weapon.obj, \
+       were.obj,wield.obj,windows.obj,wizard.obj,worm.obj,worn.obj, \
+       write.obj,zap.obj,version.obj
+HOBJ  = $(FIRSTOBJ) $(SYSOBJ) $(WINOBJ) $(RANDOBJ) \
+       $(HOBJ1) $(HOBJ2) $(HOBJ3) $(HOBJ4) $(HOBJ5) $(HOBJ6)
+
+# simpler target name
+nethack : $(GAME)
+      @ $(ECHO) "nethack is up to date."
+
+$(GAME) :      $(SYSTEM)
+      @ $(NOOP)
+
+$(SYSTEM) :    $(LIBOPT) $(HOBJ) nethack.opt
+      @ $(ECHO) "Linking ..."
+       $(LINK)/Exe=$(GAME) $(LFLAGS) nethack.opt/Opt,$(LIBOPT)/Opt
+       $(TOUCH) $(SYSTEM)
+
+all :  $(GAME)
+      @ $(ECHO) "nethack is up to date."
+
+# linker options file for nethack's object modules
+nethack.opt :  $(MAKEFILE)     # this file
+       open/Write f nethack.opt
+       write f "! nethack.opt"
+      @ write f f$edit("$(SYSOBJ)","COLLAPSE")
+      @ write f f$edit("$(WINOBJ)","COLLAPSE")
+      @ write f f$edit("$(RANDOBJ)","COLLAPSE")
+      @ write f f$edit("$(FIRSTOBJ)","COLLAPSE")
+      @ write f f$edit("$(HOBJ1)","COLLAPSE")
+      @ write f f$edit("$(HOBJ2)","COLLAPSE")
+      @ write f f$edit("$(HOBJ3)","COLLAPSE")
+      @ write f f$edit("$(HOBJ4)","COLLAPSE")
+      @ write f f$edit("$(HOBJ5)","COLLAPSE")
+      @ write f f$edit("$(HOBJ6)","COLLAPSE")
+      @ write f "iosegment=128"
+       write f "identification=$(VERSION)"
+       close f
+
+# linker options file for run-time libraries, also used by $(UTL)Makefile
+$(LIBOPT) :    $(MAKEFILE)     # this file
+       open/Write f $(LIBOPT)
+       write f "! crtl.opt"
+       write f "$(LIBS)"
+       write f "$(MORELIBS)"
+       close f
+# simplified target name, for interactive convenience
+crtl.opt :     $(LIBOPT)
+      @ $(NOOP)
+
+#      dependencies for makedefs and its outputs, which the util
+#      Makefile is responsible for keeping up to date
+#
+
+# special rules, to force update of makedefs, real dependencies should be
+# below in the 'make depend' output.
+monst.obj :
+       $(CC) $(CFLAGS) monst.c
+     @- if f$search("$(MAKEDEFS)").nes."" then delete $(MAKEDEFS)
+
+objects.obj :
+       $(CC) $(CFLAGS) objects.c
+     @- if f$search("$(MAKEDEFS)").nes."" then delete $(MAKEDEFS)
+
+$(MAKEDEFS) :  $(FIRSTOBJ) $(UTL)makedefs.c \
+               $(CONFIG_H) $(INC)permonst.h $(INC)objclass.h \
+               $(INC)monsym.h $(INC)artilist.h $(INC)dungeon.h \
+               $(INC)obj.h $(INC)monst.h $(INC)you.h $(INC)flag.h \
+               $(INC)dlb.h $(INC)patchlevel.h $(INC)qtext.h  $(LIBOPT)
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) $(MAKEDEFS)
+      @ $(CD) $(SRC)
+$(INC)onames.h : $(MAKEDEFS)
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) $(INC)onames.h
+      @ $(CD) $(SRC)
+$(INC)pm.h :   $(MAKEDEFS)
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) $(INC)pm.h
+      @ $(CD) $(SRC)
+monstr.c : $(MAKEDEFS)
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) $(SRC)monstr.c
+      @ $(CD) $(SRC)
+# both vis_tab.h and vis_tab.c are made at the same time by makedefs
+$(INC)vis_tab.h : vis_tab.c
+       $(TOUCH) $(INC)vis_tab.h
+vis_tab.c : $(MAKEDEFS)
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) $(SRC)vis_tab.c
+      @ $(CD) $(SRC)
+$(SRC)tile.c : $(WINSHR)tilemap.c $(HACK_H)
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) $(SRC)tile.c
+      @ $(CD) $(SRC)
+
+#      date.h should be remade any time any of the source or include code
+#      is modified.  Unfortunately, this would make the contents of this
+#      file far more complex.  Since "hack.h" depends on most of the include
+#      files, we kludge around this by making date.h dependent on hack.h,
+#      even though it doesn't include this file.
+#
+#      hack.h depends on makedefs' output, so we know makedefs will be
+#      up to date before being executed; kill old date.h to force update
+$(INC)date.h : $(VERSOURCES) $(HACK_H)
+     @- if f$search("$(INC)date.h").nes."" then  delete $(INC)date.h;*
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) $(INC)date.h
+      @ $(CD) $(SRC)
+
+#      special targets
+clean :
+      - if f$search("*.*;-1")    .nes."" then  purge
+      - if f$search("$(INC)*.*;-1").nes."" then        purge $(INC) /Exclude=*conf*.h
+      - if f$search("*.obj")     .nes."" then  delete *.obj;
+      - if f$search("*.h-t").nes."" then       delete *.h-t;   !$(HACK_H),$(CONFIG_H)
+      - if f$search("*.opt").nes."" then       delete *.opt;   !nethack.opt,$(LIBOPT)
+
+spotless :     clean
+      - if f$search("$(LIBOPT)").nes."" then  delete $(LIBOPT)
+      - if f$search("$(SYSTEM)").nes."" then  delete $(SYSTEM)
+      - if f$search("$(GAME)") .nes."" then  delete $(GAME)
+      - delete monstr.c;,vis_tab.c;,$(INC)vis_tab.h;,\
+ $(INC)pm.h;,$(INC)onames.h;,$(INC)date.h;
+      - if f$search("tile.c")  .nes."" then  delete tile.c;
+      - if f$search("tclib.c") .nes."" then  delete tclib.c;
+      - if f$search("random.c")        .nes."" then  delete random.c;
+      - if f$search("nethack.olb").nes."" then  delete nethack.olb;
+
+#      dependencies (mostly cloned from sys/unix/Makefile.src)
+# config.h timestamp
+$(CONFIG_H) : $(INC)config.h $(INC)config1.h $(INC)tradstdc.h $(INC)global.h \
+               $(INC)coord.h $(INC)vmsconf.h $(INC)system.h \
+               $(INC)unixconf.h $(INC)os2conf.h $(INC)micro.h \
+               $(INC)pcconf.h $(INC)tosconf.h $(INC)amiconf.h \
+               $(INC)macconf.h $(INC)beconf.h $(INC)wceconf.h \
+               $(INC)ntconf.h $(INC)nhlan.h
+       $(TOUCH) $(CONFIG_H)
+# hack.h timestamp
+$(HACK_H) : $(INC)hack.h $(CONFIG_H) $(INC)align.h \
+               $(INC)dungeon.h $(INC)monsym.h $(INC)mkroom.h \
+               $(INC)objclass.h $(INC)youprop.h $(INC)prop.h \
+               $(INC)permonst.h $(INC)monattk.h \
+               $(INC)monflag.h $(INC)mondata.h $(INC)pm.h \
+               $(INC)wintype.h $(INC)decl.h $(INC)quest.h \
+               $(INC)spell.h $(INC)color.h $(INC)obj.h \
+               $(INC)you.h $(INC)attrib.h $(INC)monst.h $(INC)skills.h \
+               $(INC)onames.h $(INC)timeout.h $(INC)trap.h \
+               $(INC)flag.h $(INC)rm.h $(INC)vision.h \
+               $(INC)display.h $(INC)engrave.h $(INC)rect.h $(INC)region.h \
+               $(INC)winprocs.h $(INC)wintty.h $(INC)trampoli.h
+       $(TOUCH) $(HACK_H)
+#      VMS-specific code
+vmsmain.obj :  $(VMS)vmsmain.c $(HACK_H) $(INC)dlb.h
+vmstty.obj :   $(VMS)vmstty.c $(HACK_H) $(INC)wintty.h $(INC)tcap.h
+vmsunix.obj :  $(VMS)vmsunix.c $(HACK_H)
+vmsmisc.obj :  $(VMS)vmsmisc.c $(VMS)oldcrtl.c
+vmsfiles.obj : $(VMS)vmsfiles.c $(CONFIG_H)
+vmsmail.obj :  $(VMS)vmsmail.c $(CONFIG_H) $(INC)mail.h \
+               $(INC)wintype.h $(INC)winprocs.h
+#      conditionally used code -- VMS always wants these
+random.obj :   random.c $(HACK_H)
+random.c :     $(SYSSHR)random.c
+       copy $(SYSSHR)random.c random.c
+tclib.obj :    tclib.c $(CONFIG_H)
+tclib.c :      $(SYSSHR)tclib.c
+       copy $(SYSSHR)tclib.c tclib.c
+#      user interface code -- VMS uses tty (1st 4) only
+getline.obj :  $(TTY)getline.c $(HACK_H) $(INC)func_tab.h
+termcap.obj :  $(TTY)termcap.c $(HACK_H) $(INC)tcap.h
+topl.obj :     $(TTY)topl.c $(HACK_H) $(INC)tcap.h
+wintty.obj :   $(TTY)wintty.c $(HACK_H) $(INC)dlb.h \
+               $(INC)patchlevel.h $(INC)tcap.h
+Window.obj :   $(X11)Window.c $(INC)xwindowp.h $(INC)xwindow.h $(CONFIG_H)
+dialogs.obj :  $(X11)dialogs.c $(CONFIG_H)
+winX.obj :     $(X11)winX.c $(HACK_H) $(INC)winX.h $(INC)dlb.h \
+               $(INC)patchlevel.h $(X11)nh72icon $(X11)nh56icon $(X11)nh32icon
+winmap.obj :   $(X11)winmap.c $(INC)xwindow.h $(HACK_H) $(INC)dlb.h \
+               $(INC)winX.h $(INC)tile2x11.h
+winmenu.obj :  $(X11)winmenu.c $(HACK_H) $(INC)winX.h
+winmesg.obj :  $(X11)winmesg.c $(INC)xwindow.h $(HACK_H) $(INC)winX.h
+winmisc.obj :  $(X11)winmisc.c $(HACK_H) $(INC)func_tab.h $(INC)winX.h
+winstat.obj :  $(X11)winstat.c $(HACK_H) $(INC)winX.h
+wintext.obj :  $(X11)wintext.c $(HACK_H) $(INC)winX.h $(INC)xwindow.h
+winval.obj :   $(X11)winval.c $(HACK_H) $(INC)winX.h
+tile.obj :     $(SRC)tile.c $(HACK_H)
+monstr.obj :   monstr.c $(CONFIG_H)
+vis_tab.obj :  vis_tab.c $(CONFIG_H) $(INC)vis_tab.h
+#      general code
+allmain.obj :  allmain.c $(HACK_H)
+alloc.obj :    alloc.c $(CONFIG_H)
+apply.obj :    apply.c $(HACK_H) $(INC)edog.h
+artifact.obj : artifact.c $(HACK_H) $(INC)artifact.h $(INC)artilist.h
+attrib.obj :   attrib.c $(HACK_H)
+ball.obj :     ball.c $(HACK_H)
+bones.obj :    bones.c $(HACK_H) $(INC)lev.h
+botl.obj :     botl.c $(HACK_H)
+cmd.obj :      cmd.c $(HACK_H) $(INC)func_tab.h
+dbridge.obj :  dbridge.c $(HACK_H)
+decl.obj :     decl.c $(HACK_H)
+detect.obj :   detect.c $(HACK_H) $(INC)artifact.h
+dig.obj :      dig.c $(HACK_H) $(INC)edog.h
+display.obj :  display.c $(HACK_H)
+dlb.obj :      dlb.c $(CONFIG_H) $(INC)dlb.h
+do.obj :       do.c $(HACK_H) $(INC)lev.h
+do_name.obj :  do_name.c $(HACK_H)
+do_wear.obj :  do_wear.c $(HACK_H)
+dog.obj :      dog.c $(HACK_H) $(INC)edog.h
+dogmove.obj :  dogmove.c $(HACK_H) $(INC)mfndpos.h $(INC)edog.h
+dokick.obj :   dokick.c $(HACK_H) $(INC)eshk.h
+dothrow.obj :  dothrow.c $(HACK_H) $(INC)edog.h
+drawing.obj :  drawing.c $(HACK_H) $(INC)tcap.h
+dungeon.obj :  dungeon.c $(HACK_H) $(INC)dgn_file.h $(INC)dlb.h
+eat.obj :      eat.c $(HACK_H)
+end.obj :      end.c $(HACK_H) $(INC)eshk.h $(INC)dlb.h
+engrave.obj :  engrave.c $(HACK_H) $(INC)lev.h
+exper.obj :    exper.c $(HACK_H)
+explode.obj :  explode.c $(HACK_H)
+extralev.obj : extralev.c $(HACK_H)
+files.obj :    files.c $(HACK_H) $(INC)dlb.h
+fountain.obj : fountain.c $(HACK_H)
+hack.obj :     hack.c $(HACK_H)
+hacklib.obj :  hacklib.c $(HACK_H)
+invent.obj :   invent.c $(HACK_H)
+light.obj :    light.c $(HACK_H) $(INC)lev.h
+lock.obj :     lock.c $(HACK_H)
+mail.obj :     mail.c $(HACK_H) $(INC)mail.h
+makemon.obj :  makemon.c $(HACK_H) $(INC)epri.h $(INC)emin.h $(INC)edog.h
+mapglyph.obj : mapglyph.c $(HACK_H)
+mcastu.obj :   mcastu.c $(HACK_H)
+mhitm.obj :    mhitm.c $(HACK_H) $(INC)artifact.h $(INC)edog.h
+mhitu.obj :    mhitu.c $(HACK_H) $(INC)artifact.h $(INC)edog.h
+minion.obj :   minion.c $(HACK_H) $(INC)emin.h $(INC)epri.h
+mklev.obj :    mklev.c $(HACK_H)
+mkmap.obj :    mkmap.c $(HACK_H) $(INC)sp_lev.h
+mkmaze.obj :   mkmaze.c $(HACK_H) $(INC)sp_lev.h $(INC)lev.h
+mkobj.obj :    mkobj.c $(HACK_H)
+mkroom.obj :   mkroom.c $(HACK_H)
+mon.obj :      mon.c $(HACK_H) $(INC)mfndpos.h $(INC)edog.h
+mondata.obj :  mondata.c $(HACK_H) $(INC)eshk.h $(INC)epri.h
+monmove.obj :  monmove.c $(HACK_H) $(INC)mfndpos.h $(INC)artifact.h \
+               $(INC)epri.h
+monst.obj :    monst.c $(CONFIG_H) $(INC)permonst.h $(INC)align.h \
+               $(INC)monattk.h $(INC)monflag.h $(INC)monsym.h \
+               $(INC)dungeon.h $(INC)eshk.h $(INC)vault.h \
+               $(INC)epri.h $(INC)color.h
+mplayer.obj :  mplayer.c $(HACK_H)
+mthrowu.obj :  mthrowu.c $(HACK_H)
+muse.obj :     muse.c $(HACK_H) $(INC)edog.h
+music.obj :    music.c $(HACK_H) #interp.c
+o_init.obj :   o_init.c $(HACK_H) $(INC)lev.h
+objects.obj :  objects.c $(CONFIG_H) $(INC)obj.h $(INC)objclass.h \
+               $(INC)prop.h $(INC)skills.h $(INC)color.h
+objnam.obj :   objnam.c $(HACK_H)
+options.obj :  options.c $(CONFIG_H) $(INC)objclass.h $(INC)flag.h \
+               $(HACK_H) $(INC)tcap.h
+pager.obj :    pager.c $(HACK_H) $(INC)dlb.h
+pickup.obj :   pickup.c $(HACK_H)
+pline.obj :    pline.c $(HACK_H) $(INC)epri.h $(INC)edog.h
+polyself.obj : polyself.c $(HACK_H)
+potion.obj :   potion.c $(HACK_H)
+pray.obj :     pray.c $(HACK_H) $(INC)epri.h
+priest.obj :   priest.c $(HACK_H) $(INC)mfndpos.h $(INC)eshk.h \
+               $(INC)epri.h $(INC)emin.h
+quest.obj :    quest.c $(HACK_H) $(INC)qtext.h
+questpgr.obj : questpgr.c $(HACK_H) $(INC)dlb.h $(INC)qtext.h
+read.obj :     read.c $(HACK_H)
+rect.obj :     rect.c $(HACK_H)
+region.obj :   region.c $(HACK_H) $(INC)lev.h
+restore.obj :  restore.c $(HACK_H) $(INC)lev.h $(INC)tcap.h
+rip.obj :      rip.c $(HACK_H)
+rnd.obj :      rnd.c $(HACK_H)
+role.obj :     role.c $(HACK_H)
+rumors.obj :   rumors.c $(HACK_H) $(INC)lev.h $(INC)dlb.h
+save.obj :     save.c $(HACK_H) $(INC)lev.h
+shk.obj :      shk.c $(HACK_H) $(INC)eshk.h
+shknam.obj :   shknam.c $(HACK_H) $(INC)eshk.h
+sit.obj :      sit.c $(HACK_H) $(INC)artifact.h
+sounds.obj :   sounds.c $(HACK_H) $(INC)edog.h
+sp_lev.obj :   sp_lev.c $(HACK_H) $(INC)dlb.h $(INC)sp_lev.h
+spell.obj :    spell.c $(HACK_H)
+steal.obj :    steal.c $(HACK_H)
+steed.obj :    steed.c $(HACK_H)
+teleport.obj : teleport.c $(HACK_H)
+timeout.obj :  timeout.c $(HACK_H) $(INC)lev.h
+topten.obj :   topten.c $(HACK_H) $(INC)dlb.h $(INC)patchlevel.h
+track.obj :    track.c $(HACK_H)
+trap.obj :     trap.c $(HACK_H)
+u_init.obj :   u_init.c $(HACK_H)
+uhitm.obj :    uhitm.c $(HACK_H)
+vault.obj :    vault.c $(HACK_H) $(INC)vault.h
+version.obj :  version.c $(HACK_H) $(INC)date.h $(INC)patchlevel.h
+vision.obj :   vision.c $(HACK_H) $(INC)vis_tab.h
+weapon.obj :   weapon.c $(HACK_H)
+were.obj :     were.c $(HACK_H)
+wield.obj :    wield.c $(HACK_H)
+windows.obj :  windows.c $(HACK_H) $(INC)wingem.h $(INC)winGnome.h
+wizard.obj :   wizard.c $(HACK_H) $(INC)qtext.h $(INC)epri.h
+worm.obj :     worm.c $(HACK_H) $(INC)lev.h
+worn.obj :     worn.c $(HACK_H)
+write.obj :    write.c $(HACK_H)
+zap.obj :      zap.c $(HACK_H)
+# eof
diff --git a/sys/vms/Makefile.top b/sys/vms/Makefile.top
new file mode 100644 (file)
index 0000000..1763def
--- /dev/null
@@ -0,0 +1,147 @@
+#      NetHack Makefile (VMS) - top level for making & installing everything.
+#      SCCS Id: @(#)Makefile.top       3.4     2003/05/19
+
+#  Copy this file to <top>Makefile.; edit the appropriate values for
+#  GAMEDIR ("playground" location) and GAMEOWNER (UIC or identifier
+#  for the owner of playground files).
+
+#      usage:  mms all,install
+#        or    mms no_tools,all,install
+#        or substitute freeware `MMK' for Digital's `MMS'.
+
+MAKE   = $(MMS)
+CD     = set default
+ECHO   = write sys$output
+EXEC   = @
+NOOP   = continue              # don't do anything interesting
+TOUCH  = set file/truncate     # multiple files per $(TOUCH), but no creation
+# support directories, relative to 'top'
+DAT = [.dat]
+DOC = [.doc]
+SRC = [.src]
+TOP = [-]      # relative to the others
+UTL = [.util]
+VMS = [.sys.vms]
+
+GAMEDIR =                      # defaults to [.play]
+GAMEOWNER =                    # defaults to installer's UIC
+# these are the distributed values in [.include]vmsconf.h
+#GAMEDIR = DISK$USERS:[GAMES.NETHACK.3-4-2.PLAY]
+#GAMEOWNER = NHWIZARD
+
+# just about everything, except installation
+all :  program utilities data dlb_data documentation
+      @ $(ECHO) "all code and data is now up to date."
+
+program :
+       $(CD) $(SRC)
+       $(MAKE)$(MAKEFLAGS) all
+      @ $(CD) $(TOP)
+utilities :
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) all
+      @ $(CD) $(TOP)
+data :
+       $(CD) $(DAT)
+       $(MAKE)$(MAKEFLAGS) all
+      @ $(CD) $(TOP)
+documentation :
+       $(CD) $(DOC)
+       $(MAKE)$(MAKEFLAGS) all
+      @ $(CD) $(TOP)
+
+install :      program all_data make_directories create_writeable_files update
+      @ $(ECHO) "installation is now complete."
+
+# assume there're no active games in progress
+update :       place_readonly_files place_executable place_vms_support
+      @ open/Write f tmp-update.com;
+      @ write f "$ set noon"
+      @ write f "$ if p1.eqs."""" then  p1 = f$trnlnm(""HACKDIR"")"
+      @ write f "$ if p1.eqs."""" then  p1 = ""[.play]"""
+      @ write f "$ old_default = f$environ(""DEFAULT"")"
+      @ write f "$ set default 'p1'"
+      @ write f\
+ "$ if f$search(""*.*;-2"").nes."""" then  set file/prot=(s:rwed,o:rwed) *.*;-2"
+      @ write f\
+ "$ if f$search(""*.*;-1"").nes."""" then  set file/prot=(s:rwed,o:rwed) *.*;-1"
+      @ write f "$ if f$search(""*.*;-1"").nes."""" then  purge"
+      @ write f "$! if f$search(""bones*.*"").nes."""" then  $(TOUCH) bones*.*"
+      @ write f "$! if f$search(""[.save]*"").nes."""" then  $(TOUCH) [.save]*"
+      @ write f "$ set default 'old_default'"
+      @ write f "$ exit"
+      @ close f
+      - $(EXEC)tmp-update.com; $(GAMEDIR)  !purge old version
+      @ delete tmp-update.com; 
+      @ $(ECHO) "playground files updated."
+
+Guidebook :
+       $(CD) $(DOC)
+       $(MAKE)$(MAKEFLAGS) Guidebook
+      @ $(CD) $(TOP)
+manpages :
+       $(CD) $(DOC)
+       $(MAKE)$(MAKEFLAGS) manpages
+      @ $(CD) $(TOP)
+
+all_data : data dlb_data
+      @ $(NOOP)
+
+dlb_data :
+       $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" dlb
+
+make_directories :
+       $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" directories
+
+create_writeable_files :
+       $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" writeable_files
+
+place_readonly_files :
+       $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" readonly_files
+
+place_executable :
+       $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" executable
+
+place_vms_support :
+       $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" termcap
+       $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" procedure
+       $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" documentation
+
+
+# 'make no_tools' should be done first if you don't have the appropriate
+# tools to process the parser and scanner for the special level and
+# dungeon compilers; doing so will copy distributed, pre-processed files
+# from [.sys.share] to [.util].  If you _do_ have the tools, be sure to
+# edit [.util]Makefile so that it uses the right ones.
+no_tools :
+       $(CD) $(UTL)
+       $(MAKE)$(MAKEFLAGS) no_yacc
+       $(MAKE)$(MAKEFLAGS) no_lex
+      @ $(CD) $(TOP)
+
+
+# 'make clean' removes all the .obj files, but leaves around all the executables
+# and compiled data files.
+clean :
+       $(CD) $(SRC)
+      - $(MAKE)$(MAKEFLAGS) clean
+      @ $(CD) $(TOP)
+       $(CD) $(UTL)
+      - $(MAKE)$(MAKEFLAGS) clean
+      @ $(CD) $(TOP)
+
+# 'make spotless' returns the source tree to near-distribution condition.
+# it removes .obj files, executables, and compiled data files.
+spotless :
+       $(CD) $(SRC)
+      - $(MAKE)$(MAKEFLAGS) spotless
+      @ $(CD) $(TOP)
+       $(CD) $(UTL)
+      - $(MAKE)$(MAKEFLAGS) spotless
+      @ $(CD) $(TOP)
+       $(CD) $(DAT)
+      - $(MAKE)$(MAKEFLAGS) spotless
+      @ $(CD) $(TOP)
+       $(CD) $(DOC)
+      - $(MAKE)$(MAKEFLAGS) spotless
+      @ $(CD) $(TOP)
diff --git a/sys/vms/Makefile.utl b/sys/vms/Makefile.utl
new file mode 100644 (file)
index 0000000..bc4e2e6
--- /dev/null
@@ -0,0 +1,372 @@
+#      NetHack Makefile (VMS) - for utility programs.
+#      SCCS Id: @(#)Makefile.utl       3.4     2002/03/02
+
+#  Copy this file to [.util]Makefile. and then edit it as needed.
+#  The default configuration is for building with DEC C (aka Compaq C).
+#  Settings for CC and CFLAGS ought to match the ones used in [.src]Makefile.
+
+MAKE   = $(MMS)
+CD     = set default
+ECHO   = write sys$output
+MOVE   = rename/New            # within same device only
+MUNG   = search/Exact/Match=NOR        # to strip bogus #module directives
+NOOP   = continue
+RM     = delete/noConfirm
+RUN    = mcr                   # simplest way to pass command line args
+TOUCH  = append/New _NLA0:     # only one file per $(TOUCH)
+# source tree, relative to 'src' and 'util'
+DAT = [-.dat]
+INC = [-.include]
+SYSSHR = [-.sys.share]
+SRC = [-.src]
+UTL = [-.util]
+VMS = [-.sys.vms]
+WINSHR = [-.win.share]
+WINX11 = [-.win.X11]
+# targets, with enough punctuation to keep MCR and DELETE happy
+MAKEDEFS= $(UTL)makedefs.exe;
+LEVCOMP = $(UTL)lev_comp.exe;
+DGNCOMP = $(UTL)dgn_comp.exe;
+DLB    = $(UTL)dlb.exe;
+RECOVER = $(UTL)recover.exe;
+# used by $(DAT)Makefile for synchronization
+MARKER = $(UTL)util.timestamp;
+
+# if you are using gcc as your compiler,
+#      uncomment the CC definition below if it's not in your environment
+# CC = gcc
+
+CFLAGS = /Prefix=All/Incl=$(INC)/noList        # DECC in native mode
+#CFLAGS        = /Include=$(INC)/noList        # VAXC or GNUC
+LFLAGS = /noMap
+LIBS   = $(SRC)crtl.opt/Options                # run-time library(s) needed
+LINK   = link
+
+# If you don't have yacc, byacc, or bison or just don't want to run any of
+#      them, then make target "no_yacc" before trying to build lev_comp
+#      or dgn_comp.  You won't be able to modify *_comp.y though.
+# If you don't have lex or flex, then make target "no_lex" and leave
+#      *_comp.l alone.  $(VMS)lev_lex.h will be used to work-around some
+#      suspect code included in the distributed copies of *_lex.c.
+# If you do either of the above, the corresponding value of YACC and/or LEX
+#      below won't matter.
+#
+# Note:  VMS POSIX V1.1 lex and yacc generate code which contains an
+#      invalid #module directive; it order to prevent warnings for CC or
+#      choking by GCC, the SEARCH command is used in an attempt to strip
+#      then out.  Otherwise MMS would quit when making the affected targets.
+#      Each "munged" copy should be identical to its original if no #module
+#      directives are present.
+#
+# yacc/lex programs to use to generate *_comp.c, *_comp.h, and *_lex.c.
+# choose xxxOUT that matches xxx tool's output
+YACC   = bison /Define
+LEX    = flex
+#YACC  = yacc -d
+#LEX   = lex
+#YACC  = posix/Run posix$bin:yacc. "-d
+#LEX   = posix/Run posix$bin:lex. "
+# blank means foo.y -> foo_tab.c & foo_tab.h
+YACCOUT =              # bison
+#YACCOUT = ytab                # VMS POSIX
+#YACCOUT = y_tab       # DEC/Shell
+LEXOUT = lexyy         # flex
+#LEXOUT  = lex_yy      # VMS POSIX
+
+
+# Nothing below this line should have to be changed.
+
+# linker options file
+LIBOPT = $(SRC)crtl.opt;
+
+# timestamps for primary header files, matching src/Makefile
+CONFIG_H = $(SRC)config.h-t
+HACK_H   = $(SRC)hack.h-t
+
+# utility .c files
+MAKESRC    = makedefs.c
+SPLEVSRC   = lev_yacc.c lev_lex.c lev_main.c
+DGNCOMPSRC = dgn_yacc.c dgn_lex.c dgn_main.c
+RECOVSRC   = recover.c
+DLBSRC    = dlb_main.c
+UTILSRCS   = $(MAKESRC) $(SPLEVSRC) $(DGNCOMPSRC) $(RECOVSRC) $(DLBSRC) panic.c
+
+# object files that provide access to NetHack's names
+NAMEOBJ1 = $(SRC)monst.obj,$(SRC)objects.obj
+NAMEOBJ2 = $(SRC)drawing.obj,$(SRC)decl.obj
+NAMEOBJS = $(NAMEOBJ1),$(NAMEOBJ2)
+
+# object files for makedefs
+MAKEOBJS = makedefs.obj,$(NAMEOBJ1)
+VMSMAKEOBJS = $(SRC)vmsmisc.obj
+
+# object files for special levels compiler
+SPLEVOBJS = lev_main.obj,lev_yacc.obj,lev_lex.obj,panic.obj,\
+           $(SRC)alloc.obj,$(NAMEOBJS)
+VMSSPLEVOBJS = $(SRC)vmsmisc.obj,$(SRC)vmsfiles.obj
+
+# object files for dungeon compiler
+DGNCOMPOBJS = dgn_main.obj,dgn_yacc.obj,dgn_lex.obj,panic.obj,$(SRC)alloc.obj
+VMSDGNCOBJS = $(SRC)vmsmisc.obj
+
+# object files for recovery utility
+RECOVOBJS = recover.obj
+VMSRECOBJS = $(SRC)vmsmisc.obj,$(SRC)vmsfiles.obj
+
+# object files for dlb utility
+DLBOBJS = dlb_main.obj,panic.obj,$(SRC)alloc.obj,$(SRC)dlb.obj
+VMSDLBOBJS = $(SRC)vmsmisc.obj,$(SRC)vmsfiles.obj
+
+
+#      fake target
+default :
+      @ $(ECHO) "Oops!  No target(s) specified...."
+
+all    : $(MAKEDEFS) $(LEVCOMP) $(DGNCOMP) $(RECOVER) $(DLB)
+      @ $(ECHO) "util is up to date."
+
+#      special targets for folks without yacc/bison and or lex/flex
+no_yacc :
+       copy $(SYSSHR)%%%_yacc.c $(UTL)
+       copy $(SYSSHR)%%%_comp.h $(INC)
+      @ $(ECHO) "distributed yacc output (*_yacc.c) copied into place"
+no_lex :
+       copy $(SYSSHR)%%%_lex.c $(UTL)
+       copy $(VMS)lev_lex.h $(UTL)
+      @ $(ECHO) "distributed lex output (*_lex.c) copied into place"
+
+#      alternate target names for possible interactive use
+makedefs : $(MAKEDEFS)
+      @ $(ECHO) "makedefs is up to date."
+lev_comp : $(LEVCOMP)
+      @ $(ECHO) "lev_comp is up to date."
+dgn_comp : $(DGNCOMP)
+      @ $(ECHO) "dgn_comp is up to date."
+recover  : $(RECOVER)
+      @ $(ECHO) "recover is up to date."
+dlb     : $(DLB)
+      @ $(ECHO) "recover is up to date."
+
+$(LIBOPT) : $(SRC)Makefile.;           # linker options file
+       $(CD) $(SRC)
+       $(MAKE)$(MAKEFLAGS) $(LIBOPT)
+      @ $(CD) $(UTL)
+
+#      dependencies for makedefs
+#
+$(MAKEDEFS) :  $(MAKEOBJS) $(VMSMAKEOBJS) $(LIBOPT)
+       $(LINK) $(LFLAGS) $(MAKEOBJS),$(VMSMAKEOBJS),$(LIBS)
+      @ $(TOUCH) $(MARKER)
+
+makedefs.obj : makedefs.c \
+               $(CONFIG_H) $(INC)permonst.h $(INC)objclass.h \
+               $(INC)monsym.h $(INC)artilist.h $(INC)dungeon.h \
+               $(INC)obj.h $(INC)monst.h $(INC)you.h $(INC)flag.h \
+               $(INC)dlb.h $(INC)patchlevel.h $(INC)qtext.h
+
+$(INC)onames.h : $(MAKEDEFS)
+       $(RUN) $(MAKEDEFS) -o
+$(INC)pm.h     : $(MAKEDEFS)
+       $(RUN) $(MAKEDEFS) -p
+$(SRC)monstr.c : $(MAKEDEFS)
+       $(RUN) $(MAKEDEFS) -m
+# both vis_tab.h and vis_tab.c are made at the same time by makedefs -z
+$(INC)vis_tab.h : $(SRC)vis_tab.c
+       $(TOUCH) $(INC)vis_tab.h
+$(SRC)vis_tab.c : $(MAKEDEFS)
+       $(RUN) $(MAKEDEFS) -z
+
+# the src Makefile is responsible for knowing when to call this, since
+# it knows all about the main src and include files
+$(INC)date.h : $(MAKEDEFS)
+       $(RUN) $(MAKEDEFS) -v
+
+
+#      dependencies for lev_comp
+#
+$(LEVCOMP) : $(SPLEVOBJS) $(VMSSPLEVOBJS)      # $(LIBOPT)
+       $(LINK)/Exe=$(LEVCOMP) $(LFLAGS) $(SPLEVOBJS),$(VMSSPLEVOBJS),$(LIBS)
+
+lev_yacc.obj : $(HACK_H) $(INC)sp_lev.h lev_yacc.c
+       $(CC) $(CFLAGS) lev_yacc.c
+lev_lex.obj  : $(HACK_H) $(INC)lev_comp.h $(INC)sp_lev.h lev_lex.c
+       @ if f$search("lev_lex.h").nes."" then  $(MOVE) lev_lex.h stdio.h
+       $(CC) $(CFLAGS) lev_lex.c
+       @ if f$search("stdio.h").nes."" then  $(MOVE) stdio.h lev_lex.h
+lev_main.obj : $(HACK_H) $(INC)sp_lev.h $(INC)tcap.h $(INC)date.h lev_main.c
+       $(CC) $(CFLAGS) lev_main.c
+panic.obj    : $(CONFIG_H)
+       $(CC) $(CFLAGS) panic.c
+
+$(INC)lev_comp.h : lev_yacc.c
+       $(TOUCH) $(INC)lev_comp.h
+
+lev_yacc.c : lev_comp.y
+       $(YACC) lev_comp.y
+       $(MUNG) 'f$parse("$(YACCOUT)","lev_comp_tab.c")' "#module" /Outp=lev_yacc.c
+       @ if f$search("''f$parse("$(YACCOUT)","lev_comp_tab.c")'").nes."" then \
+               $(RM) 'f$parse("$(YACCOUT)","lev_comp_tab.c")'
+       $(MOVE) 'f$parse("$(YACCOUT)","lev_comp_tab.h")' $(INC)lev_comp.h
+
+lev_lex.c : lev_comp.l
+       $(LEX) lev_comp.l
+       $(MUNG) 'f$parse("$(LEXOUT)","lev_comp_lex.c")' "#module" /Outp=lev_lex.c
+       @ if f$search("''f$parse("$(LEXOUT)","lev_comp_lex.c")'").nes."" then \
+               $(RM) 'f$parse("$(LEXOUT)","lev_comp_lex.c")'
+
+
+#      dependencies for dgn_comp
+#
+$(DGNCOMP) : $(DGNCOMPOBJS) $(VMSDGNCOBJS)     # $(LIBOPT)
+       $(LINK)/Exe=$(DGNCOMP) $(LFLAGS) $(DGNCOMPOBJS),$(VMSDGNCOBJS),$(LIBS)
+
+dgn_yacc.obj : $(CONFIG_H) $(INC)dgn_file.h $(INC)date.h dgn_yacc.c
+       $(CC) $(CFLAGS) dgn_yacc.c
+dgn_lex.obj  : $(CONFIG_H) $(INC)dgn_comp.h $(INC)dgn_file.h dgn_lex.c
+       @ if f$search("lev_lex.h").nes."" then  $(MOVE) lev_lex.h stdio.h
+       $(CC) $(CFLAGS) dgn_lex.c
+       @ if f$search("stdio.h").nes."" then  $(MOVE) stdio.h lev_lex.h
+dgn_main.obj : $(CONFIG_H) dgn_main.c
+       $(CC) $(CFLAGS) dgn_main.c
+
+$(INC)dgn_comp.h : dgn_yacc.c
+       $(TOUCH) $(INC)dgn_comp.h
+
+dgn_yacc.c : dgn_comp.y
+       $(YACC) dgn_comp.y
+       $(MUNG) 'f$parse("$(YACCOUT)","dgn_comp_tab.c")' "#module" /Outp=dgn_yacc.c
+       @ if f$search("''f$parse("$(YACCOUT)","dgn_comp_tab.c")'").nes."" then \
+               $(RM) 'f$parse("$(YACCOUT)","dgn_comp_tab.c")'
+       $(MOVE) 'f$parse("$(YACCOUT)","dgn_comp_tab.h")' $(INC)dgn_comp.h
+
+dgn_lex.c : dgn_comp.l
+       $(LEX) dgn_comp.l
+       $(MUNG) 'f$parse("$(LEXOUT)","dgn_comp_lex.c")' "#module" /Outp=dgn_lex.c
+       @ if f$search("''f$parse("$(LEXOUT)","dgn_comp_lex.c")'").nes."" then \
+               $(RM) 'f$parse("$(LEXOUT)","dgn_comp_lex.c")'
+
+
+#      dependencies for recover
+#
+$(RECOVER) : $(RECOVOBJS) $(VMSRECOBJS)                # $(LIBOPT)
+       $(LINK) $(LFLAGS) $(RECOVOBJS),$(VMSRECOBJS),$(LIBS)
+
+recover.obj : $(CONFIG_H) recover.c
+
+#      dependencies for dlb
+#
+$(DLB) : $(DLBOBJS) $(VMSDLBOBJS)              # $(LIBOPT)
+       $(LINK)/Exe=$(DLB) $(LFLAGS) $(DLBOBJS),$(VMSDLBOBJS),$(LIBS)
+
+dlb_main.obj : $(CONFIG_H) $(INC)dlb.h dlb_main.c
+
+#      dependencies and build rules for tile utilities
+#
+TILEMAP    = $(UTL)tilemap.exe;
+GIF2TXT    = $(UTL)gif2txt.exe;
+TXT2PPM    = $(UTL)txt2ppm.exe;
+TILE2X11   = $(UTL)tile2x11.exe;
+TILEUTILS  = $(TILEMAP),$(GIF2TXT),$(TXT2PPM),$(TILE2X11)
+TEXTIO    = $(UTL)tiletxt.obj,tiletext.obj,$(NAMEOBJS),$(SRC)vmsmisc.obj
+GIFREADERS = gifread.obj,panic.obj,$(SRC)alloc.obj
+PPMWRITERS = ppmwrite.obj,panic.obj,$(SRC)alloc.obj
+
+tileutils : $(TILEUTILS)
+       @ $(NOOP)
+
+$(GIF2TXT) : $(GIFREADERS) $(TEXTIO)
+       $(LINK)/Exe=$(GIF2TXT) $(LFLAGS) $(GIFREADERS),$(TEXTIO),$(LIBS)
+$(TXT2PPM) : $(PPMWRITERS) $(TEXTIO)
+       $(LINK)/Exe=$(TXT2PPM) $(LFLAGS) $(PPMWRITERS),$(TEXTIO),$(LIBS)
+$(TILE2X11) : tile2x11.obj $(TEXTIO)
+       $(LINK) $(LFLAGS) tile2x11.obj,$(TEXTIO),$(LIBS)
+$(TILEMAP) : tilemap.obj $(SRC)vmsmisc.obj
+       $(LINK) $(LFLAGS) tilemap.obj,$(SRC)vmsmisc.obj,$(LIBS)
+
+$(SRC)tile.c : $(TILEMAP)
+       $(RUN) $(TILEMAP)
+$(INC)tile.h : $(WINSHR)tile.h
+       copy $(WINSHR)tile.h $(INC)tile.h
+
+# Force an explicit directory prefix on tiletxt.obj so that we don't get
+# unwanted "sticky defaults" when $(TEXTIO) is used in a comma-separated
+# list on the link command line.
+#
+$(UTL)tiletxt.obj : $(HACK_H) $(WINSHR)tilemap.c
+       $(CC) $(CFLAGS) /Def=("TILETEXT")/Obj=$@ $(WINSHR)tilemap.c
+tilemap.obj  : $(HACK_H) $(WINSHR)tilemap.c
+tiletext.obj : $(CONFIG_H) $(INC)tile.h $(WINSHR)tiletext.c
+gifread.obj  : $(CONFIG_H) $(INC)tile.h $(WINSHR)gifread.c
+ppmwrite.obj : $(CONFIG_H) $(INC)tile.h $(WINSHR)ppmwrite.c
+tile2x11.obj : $(HACK_H) $(INC)tile.h $(INC)tile2x11.h $(WINX11)tile2x11.c
+
+
+# make sure object files from src are available when needed
+#
+$(SRC)alloc.obj : $(SRC)alloc.c $(CONFIG_H)
+       $(CD) $(SRC)
+       $(MAKE)$(MAKEFLAGS) alloc.obj
+      @ $(CD) $(UTL)
+
+$(SRC)monst.obj : $(SRC)monst.c $(CONFIG_H)
+       $(CD) $(SRC)
+       $(MAKE)$(MAKEFLAGS) monst.obj
+      @ $(CD) $(UTL)
+
+$(SRC)objects.obj : $(SRC)objects.c $(CONFIG_H)
+       $(CD) $(SRC)
+       $(MAKE)$(MAKEFLAGS) objects.obj
+      @ $(CD) $(UTL)
+
+$(SRC)decl.obj : $(SRC)decl.c $(HACK_H)
+       $(CD) $(SRC)
+       $(MAKE)$(MAKEFLAGS) decl.obj
+      @ $(CD) $(UTL)
+
+$(SRC)drawing.obj : $(SRC)drawing.c $(HACK_H)
+       $(CD) $(SRC)
+       $(MAKE)$(MAKEFLAGS) drawing.obj
+      @ $(CD) $(UTL)
+
+$(SRC)dlb.obj : $(SRC)dlb.c $(HACK_H) $(INC)dlb.h
+       $(CD) $(SRC)
+       $(MAKE)$(MAKEFLAGS) dlb.obj
+      @ $(CD) $(UTL)
+
+# make sure hack.h dependencies get transitive information
+$(HACK_H) : $(CONFIG_H)
+       $(CD) $(SRC)
+       $(MAKE)$(MAKEFLAGS) $(HACK_H)
+      @ $(CD) $(UTL)
+$(CONFIG_H) : $(INC)config.h
+       $(CD) $(SRC)
+       $(MAKE)$(MAKEFLAGS) $(CONFIG_H)
+      @ $(CD) $(UTL)
+
+# VMS specific dependencies
+$(SRC)vmsmisc.obj :    $(VMS)vmsmisc.c
+       $(CD) $(SRC)
+       $(MAKE)$(MAKEFLAGS) vmsmisc.obj
+      @ $(CD) $(UTL)
+
+$(SRC)vmsfiles.obj :   $(VMS)vmsfiles.c $(CONFIG_H)
+       $(CD) $(SRC)
+       $(MAKE)$(MAKEFLAGS) vmsfiles.obj
+      @ $(CD) $(UTL)
+
+
+clean :
+      - if f$search("*.*;-1").nes."" then  purge
+      - if f$search("*.obj") .nes."" then  $(RM) *.obj;
+
+spotless :     clean
+      - if f$search("%%%_lex.c") .nes."" then  $(RM) %%%_lex.c;
+      - if f$search("%%%_yacc.c").nes."" then  $(RM) %%%_yacc.c;
+      - if f$search("$(INC)%%%_comp.h").nes."" then  $(RM) $(INC)%%%_comp.h;*
+      - if f$search("$(INC)tile.h").nes."" then  $(RM) $(INC)tile.h;*
+      - if f$search("lev_lex.h") .nes."" then  $(RM) lev_lex.h;
+      - if f$search("*tab.c")   .nes."" then  $(RM) *tab.c;
+      - if f$search("*.exe").nes."" then \
+ $(RM) $(MAKEDEFS),$(LEVCOMP),$(DGNCOMP),$(RECOVER),$(DLB)
+      - if f$search("*.exe").nes."" then  $(RM) $(TILEUTILS)
+      - if f$search("$(MARKER)").nes."" then  $(RM) $(MARKER)
diff --git a/sys/vms/install.com b/sys/vms/install.com
new file mode 100644 (file)
index 0000000..68fa96f
--- /dev/null
@@ -0,0 +1,268 @@
+$ ! vms/install.com -- set up nethack 'playground'
+$ !
+$ ! Use vmsbuild.com to create nethack.exe, makedefs, and lev_comp *first*.
+$ !
+$ ! Edit this file to define gamedir & gameuic, or else invoke it with two
+$ ! command line parameters, as in:
+$ !    @[.sys.vms]install "disk$users:[games.nethack]" "games"
+$ ! or @[.sys.vms]install "[-.play]" "[40,1]"
+$ !
+$      ! default location is old playground, default owner is installer
+$      gamedir = f$trnlnm("NETHACKDIR")        !location of playground
+$      if gamedir.eqs."" then  gamedir = f$trnlnm("HACKDIR")
+$      gameuic = f$user()                      !owner of playground
+$      ! --- nothing below this line should need to be changed ---
+$      if p1.nes."" then  gamedir := 'p1'
+$      if p2.nes."" then  gameuic := 'p2'
+$
+$      ! note: all filespecs contain some punctuation,
+$      !       to avoid inadvertent logical name interaction
+$      play_files = "PERM.,RECORD.,LOGFILE.,PANICLOG."
+$      help_files = "HELP.,HH.,CMDHELP.,WIZHELP.,OPTHELP.,HISTORY.,LICENSE."
+$      data_files = "DATA.,RUMORS.,ORACLES.,OPTIONS.,QUEST.DAT"
+$      guidebook  = "[.doc]Guidebook.txt"
+$      invoc_proc = "[.sys.vms]nethack.com"
+$      trmcp_file = "[.sys.share]termcap"
+$      spec_files = "AIR.LEV,ASMODEUS.LEV,ASTRAL.LEV,BAALZ.LEV,BIGRM-%.LEV," -
+                  + "CASTLE.LEV,EARTH.LEV,FAKEWIZ%.LEV,FIRE.LEV," -
+                  + "JUIBLEX.LEV,KNOX.LEV,MEDUSA-%.LEV,MINEFILL.LEV," -
+                  + "MINETN-%.LEV,MINEND-%.LEV,ORACLE.LEV,ORCUS.LEV," -
+                  + "SANCTUM.LEV,SOKO%-%.LEV,TOWER%.LEV,VALLEY.LEV," -
+                  + "WATER.LEV,WIZARD%.LEV"
+$      spec_input = "bigroom.des castle.des endgame.des " -
+                  + "gehennom.des knox.des medusa.des mines.des " -
+                  + "oracle.des sokoban.des tower.des yendor.des"
+$      qstl_files = "%%%-GOAL.LEV,%%%-FIL%.LEV,%%%-LOCA.LEV,%%%-STRT.LEV"
+$      qstl_input = "Arch.des Barb.des Caveman.des Healer.des " -
+                  + "Knight.des Monk.des Priest.des Ranger.des Rogue.des " -
+                  + "Samurai.des Tourist.des Wizard.des Valkyrie.des"
+$      dngn_files = "DUNGEON."
+$      dngn_input = "dungeon.pdf"
+$      dlb_files  = help_files + "," + data_files + "," -
+                  + spec_files + "," + qstl_files + "," + dngn_files
+$      data_libry = "nh-data.dlb"
+$      xtrn_files = "LICENSE.,HISTORY.,OPTIONS."
+$ makedefs := $sys$disk:[-.util]makedefs
+$ lev_comp := $sys$disk:[-.util]lev_comp
+$ dgn_comp := $sys$disk:[-.util]dgn_comp
+$ dlb     := $sys$disk:[-.util]dlb
+$ milestone = "write sys$output f$fao("" !5%T "",0),"
+$ if p3.nes."" .and. f$edit(p4,"UPCASE").nes."VERBOSE" then  milestone = "!"
+$ echo = "write sys$output"
+$ warn = echo  !could be "write sys$error"
+$!
+$! make sure we've got a playground location
+$ gamedir := 'gamedir'
+$ if gamedir.eqs."" then  gamedir = "[.play]"  !last ditch default
+$ gamedir = f$parse(gamedir,,,,"SYNTAX_ONLY") - ".;"
+$ if gamedir.eqs."" then  write sys$error "% must specify playground directory"
+$ if gamedir.eqs."" then  exit %x1000002C      !ss$_abort
+$
+$!
+$!     ['p3' is used in Makefile.top]
+$ if p3.nes."" then  goto make_'p3'
+$
+$      milestone "<installation...>"
+$!
+$make_data_plus_dlb:
+$make_data:
+$      ! start from a known location -- [.sys.vms]
+$      set default 'f$parse(f$environment("PROCEDURE"),,,"DIRECTORY")'
+$! generate miscellaneous data files
+$      set default [-.-.dat]   !move to data directory
+$      milestone "(data)"
+$ makedefs -d  !data.base -> data
+$      milestone "(rumors)"
+$ makedefs -r  !rumors.tru + rumors.fal -> rumors
+$      milestone "(oracles)"
+$ makedefs -h  !oracles.txt -> oracles
+$      milestone "(dungeon preprocess)"
+$ makedefs -e  !dungeon.def -> dungeon.pdf
+$      milestone "(quest text)"
+$ makedefs -q  !quest.txt -> quest.dat
+$      milestone "(special levels)"
+$ lev_comp 'spec_input' !special levels
+$      milestone "(quest levels)"
+$ lev_comp 'qstl_input' !quest levels
+$      milestone "(dungeon compile)"
+$ dgn_comp 'dngn_input' !dungeon database
+$      set default [-]         !move up
+$ if p3.nes."" .and. f$edit(p3,"UPCASE").nes."DATA_PLUS_DLB" then  exit
+$
+$make_dlb:
+$      ! start from a known location -- [.sys.vms]
+$      set default 'f$parse(f$environment("PROCEDURE"),,,"DIRECTORY")'
+$! construct data library
+$      set default [-.-.dat]   !move to data directory
+$      milestone "(dlb setup)"
+$! since DLB doesn't support wildcard expansion and we don't have shell
+$! file globbing, start by making a file listing its intended contents
+$ create nhdat.lst
+$      if f$search("nhdat.lst;-1").nes."" then -
+               purge/noConfirm/noLog nhdat.lst
+$! an old data file might fool us later, so get rid of it
+$      if f$search(data_libry).nes."" then -
+               delete/noConfirm/noLog 'data_libry';*
+$      if f$trnlnm("PFILE$").nes."" then  close/noLog pfile$
+$ open/Append pfile$ nhdat.lst
+$ i = 0
+$dloop:
+$   g = f$element(i,",",dlb_files)
+$   if g.eqs."," then  goto ddone
+$   wild = f$locate("*",g).ne.f$locate("%",g)
+$   fcnt = 0
+$floop:
+$      f = f$search(g)
+$      if f.eqs."" then  goto fdone
+$      fcnt = fcnt + 1
+$! strip device, directory, and version from name
+$      f = f$parse(f,,,"NAME") + f$parse(f,,,"TYPE")
+$! strip trailing dot, if present, and change case
+$      f = f$edit(f + "#" - ".#" - "#","LOWERCASE")
+$      if f$extract(3,1,f).eqs."-" then -      !"xyz-foo.lev" -> "Xyz-foo.lev"
+               f = f$edit(f$extract(0,1,f),"UPCASE") + f$extract(1,255,f)
+$      write pfile$ f
+$      if wild then  goto floop
+$fdone:
+$   if fcnt.eq.0 then  warn "? no file(s) found for """,g,""""
+$   i = i + 1
+$   goto dloop
+$ddone:
+$ close pfile$
+$      milestone "(dlb create)"
+$ dlb "-cfI" 'data_libry' nhdat.lst
+$      set default [-]         !move up
+$ if p3.nes."" then  exit
+$
+$!
+$! set up the playground and save directories
+$      milestone "(directories)"
+$make_directories:
+$      srctree = f$environment("DEFAULT")
+$      set default 'gamedir'
+$ if f$parse("[-]").eqs."" then  create/dir/log [-] !default owner & protection
+$ if f$parse("[]" ).eqs."" then - !needs to be world writable
+   create/directory/owner='gameuic'/prot=(s:rwe,o:rwe,g:rwe,w:rwe)/log []
+$ if f$search("SAVE.DIR;1").eqs."" then -
+   create/directory/owner='gameuic'/prot=(s:rwe,o:rwe,g:rwe,w:rwe)/log -
+       [.SAVE]/version_limit=2
+$      set default 'srctree'
+$ if p3.nes."" then  exit
+$!
+$! create empty writeable files -- logfile, scoreboard, multi-user access lock
+$! [if old versions are already present, validate and retain them if possible]
+$make_writeable_files:
+$      milestone "(writeable files)"
+!-!$ create/owner='gameuic'/prot=(s:rwed,o:rwed,g:rwed,w:rwed) -
+!-!    'gamedir''play_files'
+$      i = 0
+$ploop:        if f$trnlnm("PFILE$").nes."" then  close/nolog pfile$
+$      f = f$element(i,",",play_files)
+$      if f.eqs."," then  goto pdone
+$      i = i + 1
+$      f = gamedir + f
+$      if f$search(f).eqs."" then  goto pmake  !make it if not found
+$      if f$file_attrib(f,"RFM").nes."STMLF" then  goto prej !must be stream_lf
+$      open/read/error=prej pfile$ 'f'
+$      read/end=ploop pfile$ pline     !empty is ok
+$      close pfile$
+$      pfield = f$element(0," ",pline) !1st field is version number
+$      if f$locate(".",pfield).lt.f$length(pfield) then  goto ploop    !keep
+$prej: rename/new_vers 'f' *.old       !reject old version
+$pmake:        create/fdl=sys$input:/owner='gameuic' 'f'/log
+file
+ organization sequential
+ protection (system:rwd,owner:rwd,group:rw,world:rw)
+record
+ format stream_lf
+$      goto ploop
+$pdone:
+$ if p3.nes."" then  exit
+$!
+$! copy over the remaining game files, then make them readonly
+$make_readonly_files:
+$      milestone "(readonly files)"
+$ if f$search("[.dat]''data_libry'").nes.""
+$ then call copyfiles 'f$string(data_libry+","+xtrn_files)' [.dat] "r"
+$ else !'dlb_files' is too long for a single command
+$      k = 200 + f$locate(",",f$extract(200,999,dlb_files))
+$      call copyfiles 'f$extract(0,k,dlb_files)' [.dat] "r"
+$      call copyfiles 'f$extract(k+1,999,dlb_files)' [.dat] "r"
+$ endif
+$ if p3.nes."" then  exit
+$!
+$make_executable:
+$      milestone "(nethack.exe)"
+$ call copy_file [.src]nethack.exe 'gamedir'nethack.exe "re"
+$ if p3.nes."" then  exit
+$!
+$! provide invocation procedure (if available)
+$make_procedure:
+$ if f$search(invoc_proc).eqs."" then  goto skip_dcl
+$ if f$search("''gamedir'nethack.com").nes."" then -
+    if f$cvtime(f$file_attr("''gamedir'nethack.com","RDT")) -
+      .ges. f$cvtime(f$file_attr(invoc_proc,"RDT")) then  goto skip_dcl
+$      milestone "(nethack.com)"
+$ call copy_file 'invoc_proc' 'gamedir'nethack.com "re"
+$skip_dcl:
+$ if p3.nes."" then  exit
+$!
+$! provide plain-text Guidebook doc file (if available)
+$make_documentation:
+$ if f$search(guidebook).eqs."" then  goto skip_doc
+$      milestone "(Guidebook)"
+$ call copy_file 'guidebook' 'gamedir'Guidebook.doc "r"
+$skip_doc:
+$ if p3.nes."" then  exit
+$!
+$! provide last-resort termcap file (if available)
+$make_termcap:
+$ if f$search(trmcp_file).eqs."" then  goto skip_termcap
+$ if f$search("''gamedir'termcap").nes."" then  goto skip_termcap
+$      milestone "(termcap)"
+$ call copy_file 'trmcp_file' 'gamedir'termcap "r"
+$skip_termcap:
+$ if p3.nes."" then  exit
+$!
+$! done
+$      milestone "<done>"
+$ define/nolog nethackdir 'gamedir'
+$ define/nolog hackdir 'gamedir'
+$ echo -
+    f$fao("!/ Nethack installation complete. !/ Playground is !AS !/",gamedir)
+$ exit
+$
+$!
+$! copy one file, resetting the protection on an earlier version first
+$copy_file: subroutine
+$ if f$search(p2).nes."" then  set file/Prot=(s:rwed,o:rwed) 'p2'
+$ copy/Prot=(s:'p3'wd,o:'p3'wd,g:'p3',w:'p3') 'p1' 'p2'
+$ set file/Owner='gameuic'/Prot=(s:'p3',o:'p3') 'p2'
+$endsubroutine !copy_file
+$
+$!
+$! copy a comma-separated list of wildcarded files, one file at a time
+$copyfiles: subroutine
+$ i = 0
+$lloop:
+$   g = f$element(i,",",p1)
+$   if g.eqs."," then  goto ldone
+$   g = p2 + g
+$   wild = f$locate("*",g).ne.f$locate("%",g)
+$   fcnt = 0
+$eloop:
+$      f = f$search(g)
+$      if f.eqs."" then  goto edone
+$      fcnt = fcnt + 1
+$      f = f - f$parse(f,,,"VERSION")
+$      e = f$parse(f,,,"NAME") + f$parse(f,,,"TYPE")
+$      call copy_file 'f' 'gamedir''e' "''p3'"
+$      if wild then  goto eloop
+$edone:
+$   if fcnt.eq.0 then  warn "? no file(s) found for """,g,""""
+$   i = i + 1
+$   goto lloop
+$ldone:
+$endsubroutine !copyfiles
+$
+$!<eof>
diff --git a/sys/vms/lev_lex.h b/sys/vms/lev_lex.h
new file mode 100644 (file)
index 0000000..f001e57
--- /dev/null
@@ -0,0 +1,25 @@
+/*     SCCS Id: @(#)lev_lex.h  3.4     1999/08/08      */
+/* "vms/lev_lex.h" copied into "util/stdio.h" for use in *_lex.c only!
+ * This is an awful kludge to allow util/*_lex.c made by SunOS's `lex'
+ * to be compiled as is.  (It isn't needed with `flex' or VMS POSIX
+ * `lex' and is benign when either of those configurations are used.)
+ * It works because the actual setup of yyin & yyout is performed in
+ * src/lev_main.c, where stdin & stdout are still correctly defined.
+ *
+ * The troublesome code is
+ *     #include "stdio.h"
+ *             ...
+ *     FILE *yyin = stdin, *yyout = stdout;
+ * The file scope initializers with non-constant values require this
+ * hack, and the quotes instead of brackets makes it easy to do.
+ */
+
+#include <stdio.h>
+#ifdef stdin
+# undef stdin
+#endif
+#define stdin  0
+#ifdef stdout
+# undef stdout
+#endif
+#define stdout 0
diff --git a/sys/vms/nethack.com b/sys/vms/nethack.com
new file mode 100644 (file)
index 0000000..164852f
--- /dev/null
@@ -0,0 +1,53 @@
+$! NetHack.Com -- sample command procedure for invoking NetHack  9-JAN-1993
+$ v = 'f$verify(0)'
+$!
+$!    Possible command line arguments include
+$!     "-uConan-B"     !play a barbarian named Conan
+$!     "-u" "Merlin-W" !play a wizard named Merlin (slight variant of above)
+$!     "-e" or "-E"    !play an elf with default name (from environment
+$!                     ! [ie, NETHACKOPTIONS logical name] or VMS username)
+$!     "-a" or "-A", "-b" or "-B", "-c" or "-C", ... !specify character type
+$!                     !note: "-s" is ambiguous between "play as a samurai"
+$!                     !   vs "show scoreboard", so use "-S" for the former
+$!     "-x" or "-X"    !play in 'explore' mode (practice for beginners)
+$!     "-D"            !play in 'wizard' mode (for debugging, available only
+$!                     ! to the username compiled into nethack.exe as WIZARD)
+$!     "-dec"          !turn on DECgraphics mode (VT100 line drawing, done
+$!                     ! automatically below if appropriate term attribs set)
+$!     "-d" dir-path   !specify an alternate playground directory (not
+$!                     ! recommended; define HACKDIR instead)
+$!
+$
+$!
+$! assume this command procedure has been placed in the playground directory;
+$!      get its device:[directory]
+$      hackdir = f$parse("_._;0",f$environ("PROCEDURE")) - "_._;0"
+$!
+$! hackdir should point to the 'playground' directory
+$ if f$trnlnm("HACKDIR").eqs."" then  define hackdir 'hackdir'
+$!
+$! termcap is a text file defining terminal capabilities and escape sequences
+$ if f$trnlnm("TERMCAP").eqs."" then  define termcap hackdir:termcap
+$!
+! [ obsolete:  now handled within nethack itself ]
+! $! prior to VMS v6, the C Run-Time Library doesn't understand vt420 :-(
+! $      TT$_VT400_Series = 113
+! $ if f$getdvi("TT:","DEVTYPE").eq.TT$_VT400_Series -
+!  .and. f$trnlnm("NETHACK_TERM").eqs."" then  define nethack_term "vt400"
+$!
+$! use the VT100 line drawing character set if possible
+$ graphics = ""
+$      usropt = f$trnlnm("NETHACKOPTIONS")
+$      if usropt.eqs."" then  usropt = f$trnlnm("HACKOPTIONS")
+$ if f$locate("DECG",f$edit(usropt,"UPCASE")) .ge. f$length(usropt) then -
+    if f$getdvi("TT:","TT_DECCRT") .and. f$getdvi("TT:","TT_ANSICRT") then -
+$      graphics = " -dec"      !select DECgraphics mode by default
+$!
+$! get input from the terminal, not from this .com file
+$ deassign sys$input
+$!
+$      nethack := $hackdir:nethack
+$      if p1.nes."-s" .and. p1.nes."-s all" then -
+               nethack = nethack + graphics
+$ nethack "''p1'" "''p2'" "''p3'" "''p4'" "''p5'" "''p6'" "''p7'" "''p8'"
+$!
diff --git a/sys/vms/oldcrtl.c b/sys/vms/oldcrtl.c
new file mode 100644 (file)
index 0000000..ee87e5a
--- /dev/null
@@ -0,0 +1,192 @@
+/*     SCCS Id: @(#)oldcrtl.c  3.4     1995/06/01      */
+/*      Pat Rankin  May'90                                       */
+/* VMS NetHack support, not needed for vms 4.6,4.7,5.x,or later   */
+
+#ifdef VERYOLD_VMS
+/*
+ * The following routines are used by NetHack but were not available
+ * from the C Run-Time Library (VAXCRTL) prior to VMS V4.6.
+ *
+ *     atexit, memcmp, memcpy, qsort, rename, vprintf, vsprintf
+ *
+ * Most of them are implemented here, but others will have to be worked
+ * around in another fashion [such as '#define USE_OLDARGS' (even though
+ * <varargs.h> is available) to avoid the need for vprintf & vsprintf].
+ *
+ */
+#define REG register
+#define const
+
+#ifndef SUPPRESS_MEM_FUNCS
+/* note: hand optimized for VAX (hardware pre-decrement & post-increment) */
+
+/* void *memset(void *, int, size_t) -- fill chunk of memory.
+*/
+char *memset( dst, fil, cnt )
+REG char *dst;
+REG char  fil;
+REG int   cnt;
+{
+    char *dst_p = dst;
+    while ( --cnt >= 0 )
+       *dst++ = fil;
+    return dst_p;
+}
+
+/* void *memcpy(void *, const void *, size_t) -- copy chunk of memory.
+*/
+char *memcpy( dst, src, cnt )
+REG char       *dst;
+REG const char *src;
+REG int                cnt;
+{
+    char *dst_p = dst;
+    while ( --cnt >= 0 )
+       *dst++ = *src++;
+    return dst_p;
+}
+
+/* void *memmove(void *, const void *, size_t) -- copy possibly overlapping mem.
+*/
+char *memmove( dst, src, cnt )
+REG char       *dst;
+REG const char *src;
+REG int                cnt;
+{
+    char *dst_p = dst;
+    if ( src == dst || cnt <= 0 ) {
+       ;       /* do nothing */
+    } else if ( dst < src || dst >= src + cnt ) {
+       while ( --cnt >= 0 )
+           *dst++ = *src++;
+    } else {    /* work backwards */
+       dst += cnt,  src += cnt;
+       while ( --cnt >= 0 )
+           *--dst = *--src;
+    }
+    return dst_p;
+}
+
+/* void *memchr(const void *, int, size_t) -- search for a byte.
+*/
+char *memchr( buf, byt, len )
+REG const char *buf;
+REG char               byt;
+REG int                len;
+{
+    while ( --len >= 0 )
+       if ( *buf++ == byt )    /* found */
+           return (char *)--buf;
+    return (char *)0;      /* not found */
+}
+
+/* int memcmp(const void *, const void *, size_t) -- compare two chunks.
+*/
+int memcmp( buf1, buf2, len )
+REG const char *buf1;
+REG const char *buf2;
+REG int                len;
+{
+    while ( --len >= 0 )
+       if ( *buf1++ != *buf2++ )
+           return (*--buf1 - *--buf2);
+    return 0;   /* buffers matched */
+}
+#endif /*!SUPPRESS_MEM_FUNCS*/
+
+
+#ifndef SUPPRESS_ATEXIT
+/* int atexit(void (*)(void)) -- register an exit handler.
+*/
+#define MAX_EXIT_FUNCS 32      /* arbitrary (32 matches VAX C v3.x docs) */
+struct ex_hndlr { long reserved, (*routine)(), arg_count, *arg1_addr; };
+static int ex_cnt = 0;         /* number of handlers registered so far */
+static struct { long dummy_arg; struct ex_hndlr handler;    /*(black box)*/
+       } ex_data[MAX_EXIT_FUNCS];      /* static handler data */
+extern unsigned long sys$dclexh();
+
+int atexit( function )
+    void (*function)();                /* note: actually gets called with 1 arg */
+{
+    if ( ex_cnt < MAX_EXIT_FUNCS ) {
+       ex_data[ex_cnt].dummy_arg = 0;  /* ultimately receives exit reason */
+       ex_data[ex_cnt].handler.reserved  = 0;
+       ex_data[ex_cnt].handler.routine   = (long (*)()) function;
+       ex_data[ex_cnt].handler.arg_count = 1;          /*(required)*/
+       ex_data[ex_cnt].handler.arg1_addr = &ex_data[ex_cnt].dummy_arg;
+       (void)sys$dclexh(&ex_data[ex_cnt].handler);  /* declare exit handler */
+       return ++ex_cnt;        /*(non-zero)*/
+    } else
+       return 0;
+}
+#endif /*!SUPPRESS_ATEXIT*/
+
+
+#ifndef SUPPRESS_RENAME
+/* int rename(const char *, const char *) -- rename a file (on same device).
+*/
+#ifndef EVMSERR
+#include <errno.h>
+#define C$$TRANSLATE(status)    (errno = EVMSERR,  vaxc$errno = (status))
+#endif
+extern unsigned long lib$rename_file();
+
+int rename( old_name, new_name )
+    const char *old_name;
+    const char *new_name;
+{
+    struct dsc { unsigned short len, mbz; const char *adr; } old_dsc, new_dsc;
+    unsigned long status;
+
+    /* put strings into descriptors and call run-time library routine */
+    new_dsc.mbz = old_dsc.mbz = 0;     /* type and class unspecified */
+    old_dsc.len = strlen( old_dsc.adr = old_name );
+    new_dsc.len = strlen( new_dsc.adr = new_name );
+    status = lib$rename_file(&old_dsc, &new_dsc);   /* omit optional args */
+    if ( !(status & 1) ) {     /* even => failure */
+       C$$TRANSLATE(status);
+       return -1;
+    } else                     /*  odd => success */
+       return 0;
+}
+#endif /*!SUPPRESS_RENAME*/
+
+
+#ifndef SUPPRESS_QSORT
+/* void qsort(void *, size_t, size_t, int (*)()) -- sort arbitrary collection.
+*/
+extern char *malloc();                 /* assume no alloca() available */
+extern void free();
+
+void qsort( base, count, size, compare )
+    char *base;
+    int   count;
+REG int   size;
+    int (*compare)();
+{
+REG int   i, cmp;
+REG char *next, *prev, *tmp = 0;
+    char  wrk_buf[512];
+
+    /* just use a shuffle sort (tradeoff between efficiency & simplicity) */
+    /*  [Optimal if already sorted; worst case when initially reversed.]  */
+    for ( next = base, i = 1;  i < count;  i++ ) {
+       prev = next,  next += size;             /* increment front pointer */
+       if ( (cmp = (*compare)( next, prev)) < 0 ) {
+           /* found element out of order; move other(s) up then re-insert it */
+           if ( !tmp )  tmp = size > (int)(sizeof wrk_buf) ? malloc(size) : wrk_buf;
+           memcpy( tmp, next, size);           /* save smaller element */
+           while ( cmp < 0 ) {
+               memcpy( prev + size, prev, size);   /* move larger elem. up */
+               prev -= size;                   /* decrement back pointer */
+               cmp = (prev >= base ? (*compare)( tmp, prev) : 0);
+           }
+           memcpy( prev + size, tmp, size);    /* restore small element */
+       }
+    }
+    if ( tmp != 0 && tmp != wrk_buf )  free(tmp);
+    return;
+}
+#endif /*!SUPPRESS_QSORT*/
+
+#endif /*VERYOLD_VMS*/
diff --git a/sys/vms/spec_lev.com b/sys/vms/spec_lev.com
new file mode 100644 (file)
index 0000000..9076933
--- /dev/null
@@ -0,0 +1,88 @@
+$ ! sys/vms/spec_lev.com -- preprocess nethack's special level compiler code
+$ !
+$ ! This operation needs to be performed prior to executing vmsbuild.com.
+$ ! Process the scanning and parsing code for NetHack's special level
+$ ! and dungeon compilers.  *.l and *.y are converted into *'.c and *.h.
+$ !
+$
+$ ! setup yacc/bison and lex/flex;
+$ !      (Uncomment the alternatives appropriate for your site;
+$ !       if yacc and lex are not defined, the pre-processed files
+$ !       distributed in sys/share will be copied and used.)
+$     ! yacc := bison /Define                  !native bison (w/ DCL CLD)
+$     ! yacc := $bison$dir:bison -y -d         !'foreign' bison (w/o CLD)
+$     ! yacc := posix /Run/Input=nl: posix$bin:yacc. """-d 
+$     ! yacc := $shell$exe:yacc -d             !yacc from DEC/Shell
+$     ! lex  := $flex$dir:flex                 !flex
+$     ! lex  := posix /Run/Input=nl: posix$bin:lex. """
+$     ! lex  := $shell$exe:lex
+$ !      (Nothing below this line should need to be changed.)
+$ ! additional setup
+$      rename  := rename/New_Vers
+$      mung    := call mung    ! not to be confused with teco :-)
+$      delete  := delete/noConfirm
+$      search  := search/Exact
+$      copy    := copy/noConcat
+$      ! start from a known location -- [.sys.vms], then move to [-.-.util]
+$      cur_dir = f$environment("DEFAULT")
+$      set default 'f$parse(f$environment("PROCEDURE"),,,"DIRECTORY")'
+$      set default [-.-.util]  !move to utility directory
+$
+$mung: subroutine
+$ ! kludge to strip bogus #module directives from POSIX-processed files
+$ !   in lieu of $ rename 'p1' 'p2'
+$      search/Match=NOR 'p1' "#module" /Output='p2'
+$      delete 'p1';*
+$ endsubroutine !mung
+$
+$ ! first cleanup any old intermediate files (to safely handle blind renaming)
+$  if f$search("*tab.%").nes."" then  delete *tab.%;*  !yacc & bison
+$  if f$search("*yy.c") .nes."" then  delete *yy.c;*   !lex & flex
+$
+$ ! process lev_comp.y into lev_yacc.c and ../include/lev_comp.h
+$ if f$type(yacc).eqs."STRING"
+$ then
+$  yacc lev_comp.y
+$  if f$search("y_tab.%").nes."" then  rename y_tab.% lev_comp_tab.*
+$  if f$search("ytab.%") .nes."" then  rename ytab.% lev_comp_tab.*
+$ else         ! use preprocessed files
+$  copy [-.sys.share]lev_yacc.c,lev_comp.h []lev_comp_tab.*
+$ endif
+$  mung   lev_comp_tab.c lev_yacc.c
+$  rename lev_comp_tab.h [-.include]lev_comp.h
+$
+$ ! process lev_comp.l into lev_lex.c
+$ if f$type(lex).eqs."STRING"
+$ then
+$  lex lev_comp.l
+$  if f$search("lexyy.c").nes."" then  rename lexyy.c lex_yy.*
+$ else         ! use preprocessed file
+$  copy [-.sys.share]lev_lex.c []lex_yy.*
+$ endif
+$  mung   lex_yy.c lev_lex.c
+$
+$ ! process dgn_comp.y into dgn_yacc.c and ../include/dgn_comp.h
+$ if f$type(yacc).eqs."STRING"
+$ then
+$  yacc dgn_comp.y
+$  if f$search("y_tab.%").nes."" then  rename y_tab.% dgn_comp_tab.*
+$  if f$search("ytab.%") .nes."" then  rename ytab.% dgn_comp_tab.*
+$ else
+$  copy [-.sys.share]dgn_yacc.c,dgn_comp.h []dgn_comp_tab.*
+$ endif
+$  mung   dgn_comp_tab.c dgn_yacc.c
+$  rename dgn_comp_tab.h [-.include]dgn_comp.h
+$
+$ ! process dgn_comp.l into dgn_lex.c
+$ if f$type(lex).eqs."STRING"
+$ then
+$  lex dgn_comp.l
+$  if f$search("lexyy.c").nes."" then  rename lexyy.c lex_yy.*
+$ else
+$  copy [-.sys.share]dgn_lex.c []lex_yy.*
+$ endif
+$  mung   lex_yy.c dgn_lex.c
+$
+$ ! done
+$  set default 'cur_dir'
+$ exit
diff --git a/sys/vms/vmsbuild.com b/sys/vms/vmsbuild.com
new file mode 100644 (file)
index 0000000..7a0b3ba
--- /dev/null
@@ -0,0 +1,307 @@
+$ ! vms/vmsbuild.com -- compile and link NetHack 3.4.*                 [pr]
+$      version_number = "3.4.3"
+$ !
+$ ! usage:
+$ !   $ set default [.src]     !or [-.-.src] if starting from [.sys.vms]
+$ !   $ @[-.sys.vms]vmsbuild  [compiler-option]  [link-option]  [cc-switches]
+$ ! options:
+$ !    compiler-option :  either "VAXC", "DECC" or "GNUC" or "" !default VAXC
+$ !    link-option     :  either "SHARE[able]" or "LIB[rary]"  !default SHARE
+$ !    cc-switches     :  optional qualifiers for CC (such as "/noOpt/Debug")
+$ ! notes:
+$ !    If the symbol "CC" is defined, compiler-option is not used.
+$ !    The link-option refers to VAXCRTL (C Run-Time Library) handling;
+$ !      to specify it while letting compiler-option default, use "" as
+$ !      the compiler-option.
+$ !    To re-link without compiling, use "LINK" as special 'compiler-option';
+$ !      to re-link with GNUC library, 'CC' must begin with "G" (or "g").
+$ !    Default wizard definition moved to include/vmsconf.h.
+$
+$        decc_dflt = f$trnlnm("DECC$CC_DEFAULT")
+$        j = (decc_dflt.nes."") .and. 1
+$      vaxc_ = "CC" + f$element(j,"#","#/VAXC") + "/NOLIST/OPTIMIZE=NOINLINE"
+$      decc_ = "CC" + f$element(j,"#","#/DECC") + "/PREFIX=ALL/NOLIST"
+$      gnuc_ = "GCC"
+$     if f$type(gcc).eqs."STRING" then  gnuc_ = gcc
+$      gnulib = "gnu_cc:[000000]gcclib/Library"    !(not used w/ vaxc)
+$ ! common CC options (/obj=file doesn't work for GCC 1.36, use rename instead)
+$      c_c_  = "/INCLUDE=[-.INCLUDE]"
+$      veryold_vms = f$extract(1,1,f$getsyi("VERSION")).eqs."4" -
+               .and. f$extract(3,3,f$getsyi("VERSION")).lts."6"
+$      if veryold_vms then  c_c_ = c_c_ + "/DEFINE=(""VERYOLD_VMS"")"
+$      axp = (f$getsyi("CPU").ge.128)  !f$getsyi("ARCH_NAME").eqs."Alpha"
+$ ! miscellaneous setup
+$      ivqual = %x00038240     !DCL-W-IVQUAL (used to check for ancient vaxc)
+$      abort := exit %x1000002A
+$      cur_dir  = f$environment("DEFAULT")
+$      vmsbuild = f$environment("PROCEDURE")
+$ ! validate first parameter
+$      p1 := 'p1'
+$      if p1.eqs."" .and. (axp .or. decc_dflt.eqs."/DECC") then  p1 = "DECC"
+$      o_VAXC =  0     !(c_opt substring positions)
+$      o_DECC =  5
+$      o_GNUC = 10
+$      o_LINK = 15
+$      o_SPCL = 20
+$      c_opt = f$locate("|"+p1, "|VAXC|DECC|GNUC|LINK|SPECIAL|") !5
+$     if (c_opt/5)*5 .eq. c_opt then  goto p1_ok
+$      copy sys$input: sys$error:      !p1 usage
+%first arg is compiler option; it must be one of
+       "VAXC" -- use VAX C to compile everything
+   or  "DECC" -- use DEC C to compile everything
+   or  "GNUC" -- use GNU C to compile everything
+   or  "LINK" -- skip compilation, just relink nethack.exe
+   or  "SPEC[IAL]" -- just compile and link lev_comp.exe
+   or    ""   -- default operation (VAXC unless 'CC' is defined)
+
+Note: if a DCL symbol for CC is defined, "VAXC" and "GNUC" are no-ops.
+      If the symbol value begins with "G" (or "g"), then the GNU C
+      library will be included in all link operations.  Do not rebuild
+      lev_comp with "SPECIAL" unless you have a CC symbol setup with
+      the proper options.
+$      abort
+$p1_ok:
+$ ! validate second parameter
+$      p2 := 'p2'
+$      l_opt = f$locate("|"+p2, "|SHAREABLE|LIBRARY__|NONE_____|") !10
+$     if (l_opt/10)*10 .eq. l_opt then goto p2_ok
+$      copy sys$input: sys$error:      !p2 usage
+%second arg is C run-time library handling; it must be one of
+       "SHAREABLE" -- link with SYS$SHARE:VAXCRTL.EXE/SHAREABLE
+   or   "LIBRARY"  -- link with SYS$LIBRARY:VAXCRTL.OLB/LIBRARY
+   or    "NONE"    -- explicitly indicate DECC$SHR
+   or      ""      -- default operation (use shareable image)
+
+Note: for MicroVMS 4.x, "SHAREABLE" (which is the default) is required.
+      Specify "NONE" if using DEC C with a CC symbol overriding 1st arg.
+$      abort
+$p2_ok:
+$ ! start from a known location -- [.sys.vms], then move to [-.-.src]
+$      set default 'f$parse(vmsbuild,,,"DEVICE")''f$parse(vmsbuild,,,"DIRECTORY")'
+$      set default [-.-.src]   !move to source directory
+$ ! compiler setup; if a symbol for "CC" is already defined it will be used
+$     if f$type(cc).eqs."STRING" then  goto got_cc
+$      cc = vaxc_                      !assume "VAXC" requested or defaulted
+$      if c_opt.eq.o_GNUC then  goto chk_gcc !explicitly invoked w/ "GNUC" option
+$      if c_opt.eq.o_DECC then  cc = decc_
+$      if c_opt.ne.o_VAXC then  goto got_cc !"SPEC" or "LINK", skip compiler check
+$      ! we want to prevent function inlining with vaxc v3.x (/opt=noinline)
+$      !   but we can't use noInline with v2.x, so need to determine version
+$        set noOn
+$        msgenv = f$environment("MESSAGE")
+$        set message/noFacil/noSever/noIdent/noText
+$        cc/noObject _NLA0:/Include=[]     !strip 'noinline' if error
+$        sts = $status
+$      if sts then  goto reset_msg     !3.0 or later will check out OK
+$      ! must be dealing with vaxc 2.x; ancient version (2.2 or earlier)
+$      !   can't handle /include='dir', needs c$include instead
+$        cc = cc - "=NOINLINE" - ",NOINLINE" - "NOINLINE,"
+$        if sts.ne.IVQUAL then  goto reset_msg
+$          define/noLog c$include [-.INCLUDE]
+$          c_c_ = "/DEFINE=(""ANCIENT_VAXC"")"
+$          if veryold_vms then  c_c_ = c_c_ - ")" + ",""VERYOLD_VMS"")"
+$reset_msg:
+$        set message 'msgenv'
+$        set On
+$        goto got_cc
+$ !
+$chk_gcc:
+$      cc = gnuc_
+$ ! old versions of gcc-vms don't have <varargs.h> or <stdarg.h> available
+$        c_c_ = "/DEFINE=(""USE_OLDARGS"")"
+$        if veryold_vms then  c_c_ = c_c_ - ")" + ",""VERYOLD_VMS"")"
+$        if veryold_vms then  goto chk_gas     !avoid varargs & stdarg
+$        if f$search("gnu_cc_include:[000000]varargs.h").nes."" then -
+               c_c_ = "/DEFINE=(""USE_VARARGS"")"
+$        if f$search("gnu_cc_include:[000000]stdarg.h").nes."" then -
+               c_c_ = "/DEFINE=(""USE_STDARG"")"
+$chk_gas:
+$ ! test whether this version of gas handles the 'const' construct correctly
+$ gas_chk_tmp = "sys$scratch:gcc-gas-chk.tmp"
+$ if f$search(gas_chk_tmp).nes."" then  delete/noconfirm/nolog 'gas_chk_tmp';*
+$ gas_ok = 0   !assume bad
+$ on warning then goto skip_gas
+$ define/user/nolog sys$error 'gas_chk_tmp'
+$ mcr gnu_cc:[000000]gcc-as sys$input: -o _NLA0:
+$DECK
+.const
+.comm dummy,0
+.const
+.comm dummy,0
+$EOD
+$ gas_ok = 1   !assume good
+$ if f$search(gas_chk_tmp).eqs."" then  goto skip_gas
+$ ! if the error file is empty, gas can deal properly with const
+$  gas_ok = f$file_attrib(gas_chk_tmp,"EOF") .eq. 0
+$  delete/noconfirm/nolog 'gas_chk_tmp';*
+$skip_gas:
+$ on warning then continue
+$        if .not.gas_ok then  c_c_ = c_c_ - ")" + ",""const="")"
+$        c_c_ = "/INCLUDE=[-.INCLUDE]" + c_c_
+$ !
+$got_cc:
+$      cc = cc + c_c_                  !append common qualifiers
+$      if p3.nes."" then  cc = cc + p3 !append optional user preferences
+$      g := 'f$extract(0,1,cc)'
+$      if g.eqs."$" then  g := 'f$extract(1,1,cc)'     !"foreign" gcc
+$      if f$edit(f$extract(1,1,cc),"UPCASE").eqs."E" then  g := X      !GEMC
+$      if g.nes."G" .and. c_opt.ne.o_GNUC then  gnulib = ""
+$      if g.eqs."G"  .or. c_opt.eq.o_GNUC then  gnulib = "," + gnulib
+$ ! linker setup; if a symbol for "LINK" is defined, we'll use it
+$      if f$type(link).nes."STRING" then  link = "LINK/NOMAP"
+$      if p4.nes."" then  link = link + p4 !append optional user preferences
+$   if c_opt.eq.o_DECC .or. l_opt.eq.10
+$   then
+$      crtl = ""       !sys$share:decc$shr.exe/Sharable found automatically
+$      create crtl.opt !empty
+$   else
+$      crtl = ",sys$library:vaxcrtl.olb/Library"       !object library
+$     if l_opt.ne.0 then  goto crtl_ok
+$      crtl = ",sys$disk:[-.src]crtl.opt/Options"      !shareable image
+$     if f$search("crtl.opt").nes."" then  goto crtl_ok !assume its right
+$      create sys$disk:[-.src]crtl.opt
+sys$share:vaxcrtl.exe/Shareable
+$   endif
+$crtl_ok:
+$      if f$search("crtl.opt;-2").nes."" then  purge/Keep=2/noLog crtl.opt
+$ ! version ID info for linker to record in .EXE files
+$      create ident.opt
+$      open/Append f ident.opt
+$      write f "identification=""",version_number,"""  !version"
+$      close f
+$      if f$search("ident.opt;-1").nes."" then  purge/noLog ident.opt
+$      ident_opt = ",sys$disk:[-.src]ident.opt/Options"
+$ ! final setup
+$      nethacklib = "[-.src]nethack.olb"
+$      milestone = "write sys$output f$fao("" !5%T "",0),"
+$     if c_opt.eq.o_LINK then  goto link  !"LINK" requested, skip compilation
+$      rename   := rename/New_Vers
+$      touch    := set file/Truncate
+$      makedefs := $sys$disk:[-.util]makedefs
+$      show symbol cc
+$      goto begin      !skip subroutines
+$!
+$compile_file: !input via 'c_file'
+$      no_lib = ( f$extract(0,1,c_file) .eqs. "#" )
+$      if no_lib then  c_file = f$extract(1,255,c_file)
+$      c_name = f$edit(f$parse(c_file,,,"NAME"),"LOWERCASE")
+$      f_opts = ""     !options for this file
+$      if f$type('c_name'_options).nes."" then  f_opts = 'c_name'_options
+$      milestone " (",c_name,")"
+$      if f$search("''c_name'.obj").nes."" then  delete 'c_name'.obj;*
+$      cc 'f_opts' 'c_file'
+$      if .not.no_lib then  nh_obj_list == nh_obj_list + ",''c_name'.obj;0"
+$     return
+$!
+$compile_list: !input via 'c_list'
+$      nh_obj_list == ""
+$      j = -1
+$ c_loop:
+$      j = j + 1
+$      c_file = f$element(j,",",c_list)  !get next file
+$      if c_file.eqs."," then  goto c_done
+$      c_file = c_file + ".c"
+$      gosub compile_file
+$      goto c_loop
+$ c_done:
+$      nh_obj_list == f$extract(1,999,nh_obj_list)
+$      if nh_obj_list.nes."" then  libr/Obj 'nethacklib' 'nh_obj_list'/Replace
+$      if nh_obj_list.nes."" then  delete 'nh_obj_list'
+$      delete/symbol/global nh_obj_list
+$     return
+$!
+$begin:
+$!
+$! miscellaneous special source file setup
+$!
+$ if f$search("random.c").eqs."" then  copy [-.sys.share]random.c []*.*
+$ if f$search("tclib.c") .eqs."" then  copy [-.sys.share]tclib.c  []*.*
+$ if f$search("[-.util]lev_yacc.c").eqs."" then  @[-.sys.vms]spec_lev.com
+$!
+$! create object library
+$!
+$     if c_opt.ne.o_SPCL .or. f$search("''nethacklib'").eqs."" then -
+  libr/Obj 'nethacklib'/Create=(Block=3000,Hist=0)
+$ if f$search("''nethacklib';-1").nes."" then  purge 'nethacklib'
+$!
+$! compile and link makedefs, then nethack, finally lev_comp & dgn_comp.
+$!
+$ milestone "<compiling...>"
+$ c_list = "[-.sys.vms]vmsmisc,[]alloc,dlb,monst,objects"
+$     if c_opt.eq.o_SPCL then  c_list = c_list + ",decl,drawing"
+$ gosub compile_list
+$     if c_opt.eq.o_SPCL then  goto special !"SPECIAL" requested, skip main build
+$ set default [-.util]
+$ c_list = "#makedefs"
+$ gosub compile_list
+$ link makedefs.obj,'nethacklib'/Lib'crtl''gnulib''ident_opt'
+$ milestone "makedefs"
+$! create some build-time files
+$ makedefs -p  !pm.h
+$ makedefs -o  !onames.h
+$ makedefs -v  !date.h
+$ milestone " (*.h)"
+$ makedefs -m  !../src/monstr.c
+$ makedefs -z  !../src/vis_tab.c, ../include/vis_tab.h
+$ milestone " (*.c)"
+$ set default [-.src]
+$! compile most of the source files:
+$ c_list = "decl,version,[-.sys.vms]vmsmain,[-.sys.vms]vmsunix" -
+       + ",[-.sys.vms]vmstty,[-.sys.vms]vmsmail,[-.sys.vms]vmsfiles" -
+       + ",[]random,[]tclib"   !copied from [-.sys.share]
+$ gosub compile_list
+$ c_list = "[-.win.tty]getline,[-.win.tty]termcap" -
+       + ",[-.win.tty]topl,[-.win.tty]wintty"
+$ gosub compile_list
+$ c_list = "allmain,apply,artifact,attrib,ball,bones,botl,cmd,dbridge,detect" -
+       + ",dig,display,do,do_name,do_wear,dog,dogmove,dokick,dothrow,drawing" -
+       + ",dungeon,eat,end,engrave,exper,explode,extralev,files,fountain"
+$ gosub compile_list
+$ c_list = "hack,hacklib,invent,light,lock,mail,makemon,mapglyph,mcastu" -
+       + ",mhitm,mhitu,minion,mklev,mkmap,mkmaze,mkobj,mkroom,mon,mondata" -
+       + ",monmove,monstr,mplayer,mthrowu,muse,music,o_init,objnam,options" -
+       + ",pager,pickup"
+$ gosub compile_list
+$ c_list = "pline,polyself,potion,pray,priest,quest,questpgr,read" -
+       + ",rect,region,restore,rip,rnd,role,rumors,save,shk,shknam,sit" -
+       + ",sounds,sp_lev,spell,steal,steed,teleport,timeout,topten,track" -
+       + ",trap,u_init"
+$ gosub compile_list
+$ c_list = "uhitm,vault,vision,vis_tab,weapon,were,wield,windows" -
+       + ",wizard,worm,worn,write,zap"
+$ gosub compile_list
+$!
+$link:
+$ milestone "<linking...>"
+$ link/Exe=nethack.exe 'nethacklib'/Lib/Incl=(vmsmain)'crtl''gnulib''ident_opt'
+$ milestone "NetHack"
+$     if c_opt.eq.o_LINK then  goto done       !"LINK" only
+$special:
+$!
+$! build special level and dungeon compilers
+$!
+$ set default [-.util]
+$ c_list = "#panic,#lev_main,#lev_yacc,#dgn_main,#dgn_yacc"
+$     if c_opt.eq.o_SPCL then  c_list = "[-.sys.vms]vmsfiles," + c_list
+$ gosub compile_list
+$ c_list = "#lev_lex,#dgn_lex"
+$ copy [-.sys.vms]lev_lex.h stdio.*/Prot=(s:rwd,o:rwd)
+$ gosub compile_list
+$ rename stdio.h lev_lex.*
+$ link/exe=lev_comp.exe lev_main.obj,lev_yacc.obj,lev_lex.obj,-
+       panic.obj,'nethacklib'/Lib'crtl''gnulib''ident_opt'
+$ milestone "lev_comp"
+$ link/exe=dgn_comp.exe dgn_main.obj,dgn_yacc.obj,dgn_lex.obj,-
+       panic.obj,'nethacklib'/Lib'crtl''gnulib''ident_opt'
+$ milestone "dgn_comp"
+$!
+$ c_list = "#dlb_main,#recover"
+$ gosub compile_list
+$ link/exe=dlb.exe dlb_main.obj,panic.obj,'nethacklib'/Lib'crtl''gnulib''ident_opt'
+$ milestone "dlb"
+$ link/exe=recover.exe recover.obj,'nethacklib'/Lib'crtl''gnulib''ident_opt'
+$ milestone "recover"
+$!
+$done:
+$      set default 'cur_dir'
+$ exit
diff --git a/sys/vms/vmsfiles.c b/sys/vms/vmsfiles.c
new file mode 100644 (file)
index 0000000..657c060
--- /dev/null
@@ -0,0 +1,293 @@
+/*     SCCS Id: @(#)vmsfiles.c 3.4     1999/08/29      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *  VMS-specific file manipulation routines to implement some missing
+ *  routines or substitute for ones where we want behavior modification.
+ */
+#include "config.h"
+#include <ctype.h>
+
+/* lint supression due to lack of extern.h */
+int FDECL(vms_link, (const char *,const char *));
+int FDECL(vms_unlink, (const char *));
+int FDECL(vms_creat, (const char *,unsigned int));
+int FDECL(vms_open, (const char *,int,unsigned int));
+boolean FDECL(same_dir, (const char *,const char *));
+int FDECL(c__translate, (int));
+char *FDECL(vms_basename, (const char *));
+
+#include <rms.h>
+#if 0
+#include <psldef.h>
+#else
+#define PSL$C_EXEC 1   /* executive mode, for priv'd logical name handling */
+#endif
+#include <errno.h>
+#ifndef C$$TRANSLATE   /* don't rely on VAXCRTL's internal routine */
+#define C$$TRANSLATE(status) (errno = EVMSERR,  vaxc$errno = (status))
+#endif
+extern unsigned long sys$parse(), sys$search(), sys$enter(), sys$remove();
+extern int VDECL(lib$match_cond, (int,int,...));
+
+#define vms_success(sts) ((sts)&1)             /* odd, */
+#define vms_failure(sts) (!vms_success(sts))   /* even */
+
+/* vms_link() -- create an additional directory for an existing file */
+int vms_link(file, new)
+const char *file, *new;
+{
+    struct FAB fab;
+    struct NAM nam;
+    unsigned short fid[3];
+    char esa[NAM$C_MAXRSS];
+
+    fab = cc$rms_fab;  /* set block ID and length, zero the rest */
+    fab.fab$l_fop = FAB$M_OFP;
+    fab.fab$l_fna = (char *) file;
+    fab.fab$b_fns = strlen(file);
+    fab.fab$l_nam = &nam;
+    nam = cc$rms_nam;
+    nam.nam$l_esa = esa;
+    nam.nam$b_ess = sizeof esa;
+
+    if (vms_success(sys$parse(&fab)) && vms_success(sys$search(&fab))) {
+       fid[0] = nam.nam$w_fid[0];
+       fid[1] = nam.nam$w_fid[1];
+       fid[2] = nam.nam$w_fid[2];
+       fab.fab$l_fna = (char *) new;
+       fab.fab$b_fns = strlen(new);
+
+       if (vms_success(sys$parse(&fab))) {
+           nam.nam$w_fid[0] = fid[0];
+           nam.nam$w_fid[1] = fid[1];
+           nam.nam$w_fid[2] = fid[2];
+           nam.nam$l_esa = nam.nam$l_name;
+           nam.nam$b_esl = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver;
+
+           (void) sys$enter(&fab);
+       }
+    }
+
+    if (vms_failure(fab.fab$l_sts)) {
+       C$$TRANSLATE(fab.fab$l_sts);
+       return -1;
+    }
+    return 0;  /* success */
+}
+
+/*
+   vms_unlink() -- remove a directory entry for a file; should only be used
+   for files which have had extra directory entries added, not for deletion
+   (because the file won't be deleted, just made inaccessible!).
+ */
+int vms_unlink(file)
+const char *file;
+{
+    struct FAB fab;
+    struct NAM nam;
+    char esa[NAM$C_MAXRSS];
+
+    fab = cc$rms_fab;  /* set block ID and length, zero the rest */
+    fab.fab$l_fop = FAB$M_DLT;
+    fab.fab$l_fna = (char *) file;
+    fab.fab$b_fns = strlen(file);
+    fab.fab$l_nam = &nam;
+    nam = cc$rms_nam;
+    nam.nam$l_esa = esa;
+    nam.nam$b_ess = sizeof esa;
+
+    if (vms_failure(sys$parse(&fab)) || vms_failure(sys$remove(&fab))) {
+       C$$TRANSLATE(fab.fab$l_sts);
+       return -1;
+    }
+    return 0;
+}
+
+/*
+   Substitute creat() routine -- if trying to create a specific version,
+   explicitly remove an existing file of the same name.  Since it's only
+   used when we expect exclusive access, add a couple RMS options for
+   optimization.  (Don't allow sharing--eliminates coordination overhead,
+   and use 32 block buffer for faster throughput; ~30% speedup measured.)
+ */
+#undef creat
+int vms_creat(file, mode)
+const char *file;
+unsigned int mode;
+{
+    if (index(file, ';')) {
+       /* assumes remove or delete, not vms_unlink */
+       if (!unlink(file)) {
+           (void)sleep(1);
+           (void)unlink(file);
+       }
+    }
+    return creat(file, mode, "shr=nil", "mbc=32", "mbf=2", "rop=wbh");
+}
+
+/*
+   Similar substitute for open() -- if an open attempt fails due to being
+   locked by another user, retry it once (work-around for a limitation of
+   at least one NFS implementation).
+ */
+#undef open
+int vms_open(file, flags, mode)
+const char *file;
+int flags;
+unsigned int mode;
+{
+    int fd = open(file, flags, mode, "mbc=32", "mbf=2", "rop=rah");
+
+    if (fd < 0 && errno == EVMSERR && lib$match_cond(vaxc$errno, RMS$_FLK)) {
+       (void)sleep(1);
+       fd = open(file, flags, mode, "mbc=32", "mbf=2", "rop=rah");
+    }
+    return fd;
+}
+
+/*
+   Determine whether two strings contain the same directory name.
+   Used for deciding whether installed privileges should be disabled
+   when HACKDIR is defined in the environment (or specified via -d on
+   the command line).  This version doesn't handle Unix-style file specs.
+ */
+boolean
+same_dir(d1, d2)
+const char *d1, *d2;
+{
+    if (!d1 || !*d1 || !d2 || !*d2)
+       return FALSE;
+    else if (!strcmp(d1, d2))  /* strcmpi() would be better, but that leads */
+       return TRUE;            /* to linking problems for the utilities */
+    else {
+       struct FAB f1, f2;
+       struct NAM n1, n2;
+
+       f1 = f2 = cc$rms_fab;   /* initialize file access block */
+       n1 = n2 = cc$rms_nam;   /* initialize name block */
+       f1.fab$b_acmodes = PSL$C_EXEC << FAB$V_LNM_MODE;
+       f1.fab$b_fns = strlen( f1.fab$l_fna = (char *)d1 );
+       f2.fab$b_fns = strlen( f2.fab$l_fna = (char *)d2 );
+       f1.fab$l_nam = (genericptr_t)&n1;       /* link nam to fab */
+       f2.fab$l_nam = (genericptr_t)&n2;
+       n1.nam$b_nop = n2.nam$b_nop = NAM$M_NOCONCEAL; /* want true device name */
+
+       return (vms_success(sys$parse(&f1)) && vms_success(sys$parse(&f2))
+            && n1.nam$t_dvi[0] == n2.nam$t_dvi[0]
+            && !strncmp(&n1.nam$t_dvi[1], &n2.nam$t_dvi[1], n1.nam$t_dvi[0])
+            && !memcmp((genericptr_t)n1.nam$w_did,
+                       (genericptr_t)n2.nam$w_did,
+                       sizeof n1.nam$w_did));  /*{ short nam$w_did[3]; }*/
+    }
+}
+
+
+/*
+ * c__translate -- substitute for VAXCRTL routine C$$TRANSLATE.
+ *
+ *     Try to convert a VMS status code into its Unix equivalent,
+ *     then set `errno' to that value; use EVMSERR if there's no
+ *     appropriate translation; set `vaxc$errno' to the original
+ *     status code regardless.
+ *
+ *     These translations match only a subset of VAXCRTL's lookup
+ *     table, but work even if the severity has been adjusted or
+ *     the inhibit-message bit has been set.
+ */
+#include <errno.h>
+#include <ssdef.h>
+#include <rmsdef.h>
+/* #include <libdef.h> */
+/* #include <mthdef.h> */
+
+#define VALUE(U)       trans = U; break
+#define CASE1(V)       case (V >> 3)
+#define CASE2(V,W)     CASE1(V): CASE1(W)
+
+int c__translate(code)
+    int code;
+{
+    register int trans;
+
+    switch ((code & 0x0FFFFFF8) >> 3) {        /* strip upper 4 and bottom 3 bits */
+       CASE2(RMS$_PRV,SS$_NOPRIV):
+                               VALUE(EPERM);   /* not owner */
+       CASE2(RMS$_DNF,RMS$_DIR):
+       CASE2(RMS$_FNF,RMS$_FND):
+       CASE1(SS$_NOSUCHFILE):
+                               VALUE(ENOENT);  /* no such file or directory */
+       CASE2(RMS$_IFI,RMS$_ISI):
+                               VALUE(EIO);     /* i/o error */
+       CASE1(RMS$_DEV):
+       CASE2(SS$_NOSUCHDEV,SS$_DEVNOTMOUNT):
+                               VALUE(ENXIO);   /* no such device or address codes */
+       CASE1(RMS$_DME):
+     /* CASE1(LIB$INSVIRMEM): */
+       CASE2(SS$_VASFULL,SS$_INSFWSL):
+                               VALUE(ENOMEM);  /* not enough core */
+       CASE1(SS$_ACCVIO):
+                               VALUE(EFAULT);  /* bad address */
+       CASE2(RMS$_DNR,SS$_DEVASSIGN):
+       CASE2(SS$_DEVALLOC,SS$_DEVALRALLOC):
+       CASE2(SS$_DEVMOUNT,SS$_DEVACTIVE):
+                               VALUE(EBUSY);   /* mount device busy codes to name a few */
+       CASE2(RMS$_FEX,SS$_FILALRACC):
+                               VALUE(EEXIST);  /* file exists */
+       CASE2(RMS$_IDR,SS$_BADIRECTORY):
+                               VALUE(ENOTDIR); /* not a directory */
+       CASE1(SS$_NOIOCHAN):
+                               VALUE(EMFILE);  /* too many open files */
+       CASE1(RMS$_FUL):
+       CASE2(SS$_DEVICEFULL,SS$_EXDISKQUOTA):
+                               VALUE(ENOSPC);  /* no space left on disk codes */
+       CASE2(RMS$_WLK,SS$_WRITLCK):
+                               VALUE(EROFS);   /* read-only file system */
+       default:
+                               VALUE(EVMSERR);
+    };
+
+    errno = trans;
+    vaxc$errno = code;
+    return code;       /* (not very useful) */
+}
+
+#undef VALUE
+#undef CASE1
+#undef CASE2
+
+static char base_name[NAM$C_MAXRSS+1];
+
+/* return a copy of the 'base' portion of a filename */
+char *
+vms_basename(name)
+const char *name;
+{
+    unsigned len;
+    char *base, *base_p;
+    register const char *name_p;
+
+    /* skip directory/path */
+    if ((name_p = strrchr(name, ']')) != 0) name = name_p + 1;
+    if ((name_p = strrchr(name, '>')) != 0) name = name_p + 1;
+    if ((name_p = strrchr(name, ':')) != 0) name = name_p + 1;
+    if ((name_p = strrchr(name, '/')) != 0) name = name_p + 1;
+    if (!*name) name = ".";            /* this should never happen */
+
+    /* find extension/version and derive length of basename */
+    if ((name_p = strchr(name, '.')) == 0 || name_p == name)
+       name_p = strchr(name, ';');
+    len = (name_p && name_p > name) ? name_p - name : strlen(name);
+
+    /* return a lowercase copy of the name in a private static buffer */
+    base = strncpy(base_name, name, len);
+    base[len] = '\0';
+    /* we don't use lcase() so that utilities won't need hacklib.c */
+    for (base_p = base; base_p < &base[len]; base_p++)
+       if (isupper(*base_p)) *base_p = tolower(*base_p);
+
+    return base;
+}
+
+/*vmsfiles.c*/
diff --git a/sys/vms/vmsmail.c b/sys/vms/vmsmail.c
new file mode 100644 (file)
index 0000000..29e0192
--- /dev/null
@@ -0,0 +1,486 @@
+/*     SCCS Id: @(#)vmsmail.c  3.4     1995/06/01      */
+/* Copyright (c) Robert Patrick Rankin, 1991.                    */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "config.h"
+#include "mail.h"
+
+/* lint supression due to lack of extern.h */
+unsigned long NDECL(init_broadcast_trapping);
+unsigned long NDECL(enable_broadcast_trapping);
+unsigned long NDECL(disable_broadcast_trapping);
+struct mail_info *NDECL(parse_next_broadcast);
+
+#ifdef MAIL
+#include "wintype.h"
+#include "winprocs.h"
+#include <ctype.h>
+#include <descrip.h>
+#include <errno.h>
+# ifndef __GNUC__
+#include <msgdef.h>
+# else
+#  define MSG$_TRMHANGUP  6
+#  define MSG$_TRMBRDCST 83
+# endif /*__GNUC__*/
+#include <signal.h>
+/* #include <string.h> */
+# define vms_ok(sts) ((sts)&1)
+
+static struct mail_info *FDECL(parse_brdcst, (char *));
+static void FDECL(filter_brdcst, (char *));
+static void NDECL(flush_broadcasts);
+static void FDECL(broadcast_ast, (int));
+extern char *FDECL(eos, (char *));
+extern char *FDECL(strstri, (const char *,const char *));
+extern int FDECL(strncmpi, (const char *,const char *,int));
+
+extern size_t FDECL(strspn, (const char *,const char *));
+#ifndef __DECC
+extern int VDECL(sscanf, (const char *,const char *,...));
+#endif
+extern unsigned long
+       smg$create_pasteboard(),
+       smg$get_broadcast_message(),
+       smg$set_broadcast_trapping(),
+       smg$disable_broadcast_trapping();
+
+extern volatile int broadcasts;                /* defining declaration in mail.c */
+
+static long pasteboard_id = 0;         /* SMG's magic cookie */
+
+/*
+ * Mail (et al) overview:
+ *
+ *     When a broadcast is asynchronously captured, a volatile counter
+ * ('broadcasts') is incremented.  Each player turn, ckmailstatus() polls
+ * the counter and calls parse_next_broadcast() if it's positive; this
+ * returns some display text, object name, and response command, which is
+ * passed to newmail().  Routine newmail() generates a mail-daemon monster
+ * who approaches the character, "speaks" the display text, and delivers
+ * a scroll of mail pre-named to the object name; the response command is
+ * initially appended to the name, so that the object is tagged with both
+ * of them; a NUL is inserted to terminate the ordinary name and hide the
+ * command.  (If the player renames such a scroll, the hidden command will
+ * be lost; who cares?)  Unrecognized broadcasts result in the mail-daemon
+ * arriving and announcing the display text, but no scroll being created.
+ * If SHELL is undefined, then all broadcasts are treated as 'other'; since
+ * no subproceses are allowed, there'd be no way to respond to the scroll.
+ *
+ *     When a scroll of mail is read by the character, readmail() extracts
+ * the hidden command string and uses it for the default when prompting the
+ * player for a system command to spawn.  The player may enter any command
+ * he or she chooses, or just <return> to accept the default or <escape> to
+ * avoid executing any command.  If the command is "SPAWN", a regular shell
+ * escape to DCL is performed; otherwise, the indicated single command is
+ * spawned.  Either way, NetHack resumes play when the subprocess terminates
+ * or explicitly reattaches to its parent.
+ *
+ * Broadcast parsing:
+ *
+ *     The following broadcast messages are [attempted to be] recognized:
+ *    text fragment          name for scroll         default command
+ *     New mail                VMSmail                 MAIL
+ *     New ALL-IN-1 MAIL       A1mail                  A1M
+ *     Software Tools mail     STmail                  MSG [+folder]
+ *     MM mail                 MMmail                  MM
+ *     WPmail: New mail        WPmail                  OFFICE/MAIL
+ *     **M400 mail             M400mail                M400
+ *     " mail", ^"mail "       unknown mail            SPAWN
+ *     " phoning"              Phone call              PHONE ANSWER
+ *     talk-daemon...by...foo  Talk request            TALK[/OLD] foo@bar
+ *     (node)user -            Bitnet noise            XYZZY user@node
+ * Anything else results in just the message text being passed along, no
+ * scroll of mail so consequently no command to execute when scroll read.
+ * The user can set up ``$ XYZZY :== SEND'' prior to invoking NetHack if
+ * vanilla JNET responses to Bitnet messages are prefered.
+ *
+ *     Static return buffers are used because only one broadcast gets
+ * processed at a time, and the essential information in each one is
+ * either displayed and discarded or copied into a scroll-of-mail object.
+ *
+ *     The test driver code below can be used to check out potential new
+ * entries without rebuilding NetHack itself.  CC/DEFINE="TEST_DRIVER"
+ * Link it with hacklib.obj or nethack.olb/incl=hacklib (not nethack/lib).
+ */
+
+static struct mail_info msg;   /* parse_*()'s return buffer */
+static char nam_cmd_buf[63],   /* maximum onamelth, size of ONAME(object) */
+           txt_buf[255+1];     /* same size as used for message buf[] */
+
+/* try to decipher and categorize broadcast message text
+*/
+static struct mail_info *
+parse_brdcst(buf)              /* called by parse_next_broadcast() */
+char *buf;                     /* input: filtered broadcast text */
+{
+    int typ;
+    char *txt;
+    const char *nam, *cmd;
+# ifdef SHELL          /* only parse if spawned commands are enabled */
+    register char *p, *q;
+    boolean is_jnet_send;
+    char cmd_buf[127+1], user[127+1], node[127+1], sentinel;
+
+    /* Check these first; otherwise, their arbitrary text would enable
+       easy spoofing of some other message patterns.  Unfortunately,
+       any home-grown broadcast delivery program poses a similar risk. */
+    if (!strncmpi(buf, "reply received", 14)) goto other;
+    is_jnet_send = (sscanf(buf, "(%[^)])%s -%c", node, user, &sentinel) == 3);
+    if (is_jnet_send) goto jnet_send;
+
+    /* scan the text more or less by brute force */
+    if ((q = strstri(buf, " mail")) != 0 ||    /* all known mail broadcasts */
+       !strncmpi(q = buf, "mail ", 5)) {       /* unexpected alternative */
+       typ = MSG_MAIL;
+       p = strstri(q, " from");
+       txt = p ? strcat(strcpy(txt_buf, "Mail for you"), p) : (char *) 0;
+
+       if (!strncmpi(buf, "new mail", 8)) {
+/*
+New mail [on node FOO] from [SPAM::]BAR [\"personal_name\"] [\(HH:MM:SS\)]
+*/
+           nam = "VMSmail";            /* assume VMSmail */
+           cmd = "MAIL";
+           if (txt && (p = strrchr(txt, '(')) > txt && /* discard time */
+               (--p, strspn(p, "0123456789( :.)") == strlen(p))) *p = '\0';
+       } else if (!strncmpi(buf, "new all-in-1", 12)) {
+           int i;
+/*
+New ALL-IN-1 MAIL message [on node FOO] from Personal Name \(BAR@SPAM\) [\(DD-MMM-YYYY HH:MM:SS\)]
+*/
+           nam = "A1mail";
+           cmd = "A1M";
+           if (txt && (p = strrchr(txt, '(')) > txt && /* discard date+time */
+               sscanf(p-1," (%*d-%*[^-]-%*d %*d:%*d:%d) %c",&i,&sentinel) == 1)
+               *--p = '\0';
+       } else if (!strncmpi(buf, "software tools", 14)) {
+/*
+Software Tools mail has arrived on FOO from \'BAR\' [in SPAM]
+*/
+           nam = "STmail";
+           cmd = "MSG";
+           if (txt && (p = strstri(p, " in ")) != 0)   /* specific folder */
+               cmd = strcat(strcpy(cmd_buf, "MSG +"), p + 4);
+       } else if (q - 2 >= buf && !strncmpi(q - 2, "mm", 2)) {
+/*
+{MultiNet\ |PMDF\/}MM mail has arrived on FOO from BAR\n
+[Subject: subject_text] (PMDF only)
+*/
+           nam = "MMmail";             /* MultiNet's version of MM */
+           cmd = "MM";                 /*{ perhaps "MM READ"? }*/
+       } else if (!strncmpi(buf, "wpmail:", 7)) {
+/*
+WPmail: New mail from BAR.  subject_text
+*/
+           nam = "WPmail";             /* WordPerfect [sic] Office */
+           cmd = "OFFICE/MAIL";
+       } else if (!strncmpi(buf, "**m400 mail", 7)) {
+/*
+**M400 mail waiting**
+*/
+           nam = "M400mail";           /* Messenger 400 [not seen] */
+           cmd = "M400";
+       } else {
+           /* not recognized, but presumed to be mail */
+           nam = "unknown mail";
+           cmd = "SPAWN";              /* generic escape back to DCL */
+           txt = (char *) 0;           /* don't rely on "from" info here */
+       }
+
+       if (!txt) txt = strcat(strcpy(txt_buf, "Mail for you: "), buf);
+    /*
+     : end of mail recognition; now check for call-type interruptions...
+     */
+    } else if ((q = strstri(buf, " phoning")) != 0) {
+/*
+BAR is phoning you [on FOO] \(HH:MM:SS\)
+*/
+       typ = MSG_CALL;
+       nam = "Phone call";
+       cmd = "PHONE ANSWER";
+       if (!strncmpi(q + 8, " you", 4)) q += (8 + 4), *q = '\0';
+       txt = strcat(strcpy(txt_buf, "Do you hear ringing?  "), buf);
+    } else if ((q = strstri(buf, " talk-daemon")) != 0 ||
+              (q = strstri(buf, " talk_daemon")) != 0) {
+/*
+Message from TALK-DAEMON@FOO at HH:MM:SS\n
+Connection request by BAR@SPAM\n
+\[Respond with: TALK[/OLD] BAR@SPAM\]
+*/
+       typ = MSG_CALL;
+       nam = "Talk request";           /* MultiNet's TALK and/or TALK/OLD */
+       cmd = "TALK";
+       if ((p = strstri(q, " by ")) != 0) {
+           txt = strcat(strcpy(txt_buf, "Talk request from"), p + 3);
+           if ((p = strstri(p, "respond with")) != 0) {
+               if (*(p-1) == '[') *(p-1) = '\0'; else *p = '\0'; /* terminate */
+               p += (sizeof "respond with" - sizeof "");
+               if (*p == ':') p++;
+               if (*p == ' ') p++;
+               cmd = strcpy(cmd_buf, p);       /* "TALK[/OLD] bar@spam" */
+               p = eos(cmd_buf);
+               if (*--p == ']') *p = '\0';
+           }
+       } else
+           txt = strcat(strcpy(txt_buf, "Pardon the interruption: "), buf);
+    } else if (is_jnet_send) { /* sscanf(,"(%[^)])%s -%c",,,)==3 */
+jnet_send:
+/*
+\(SPAM\)BAR - arbitrary_message_text (from BAR@SPAM)
+*/
+       typ = MSG_CALL;
+       nam = "Bitnet noise";           /* RSCS/NJE message received via JNET */
+       Sprintf(cmd_buf, "XYZZY %s@%s", user, node);
+       cmd = cmd_buf;
+       /*{ perhaps just vanilla SEND instead of XYZZY? }*/
+       Sprintf(txt_buf, "Message from %s@%s:%s", user, node,
+               &buf[1+strlen(node)+1+strlen(user)+2-1]);  /* "(node)user -" */
+       txt = txt_buf;
+    /*
+     : end of call recognition; anything else is none-of-the-above...
+     */
+    } else {
+other:
+# endif /* SHELL */
+/* arbitrary broadcast: batch job completed, system shutdown imminent, &c */
+       typ = MSG_OTHER;
+       nam = (char *) 0; /*"captured broadcast message"*/
+       cmd = (char *) 0;
+       txt = strcat(strcpy(txt_buf, "Message for you: "), buf);
+# ifdef SHELL
+    }
+    /* Daemon in newmail() will append period when the text is displayed */
+    if ((p = eos(txt)) > txt && *--p == '.') *p = '\0';
+
+    /* newmail() and readmail() assume that nam and cmd are concatenated */
+    if (nam) {         /* object name to attach to scroll of mail */
+       char *join = strcpy(nam_cmd_buf, nam);
+       if (cmd) {      /* append command to name; readmail() requires it */
+           int len = sizeof nam_cmd_buf - sizeof "" - (strlen(join) + 1);
+           cmd_buf[len] = '\0';        /* possibly truncate */
+           (void) strcat(join, " ");
+           cmd = strcpy(eos(join), cmd);
+       }
+       nam = join;
+    }
+# endif /* SHELL */
+    /* truncate really long messages to prevent verbalize() from blowing up */
+    if (txt && strlen(txt) > BUFSZ - 50) txt[BUFSZ - 50] = '\0';
+
+    msg.message_typ  = typ;    /* simple index */
+    msg.display_txt  = txt;    /* text for daemon to pline() */
+    msg.object_nam   = nam;    /* 'name' for mail scroll */
+    msg.response_cmd = cmd;    /* command to spawn when scroll read */
+    return &msg;
+}
+
+/* filter out non-printable characters and redundant noise
+*/
+static void
+filter_brdcst(buf)             /* called by parse_next_broadcast() */
+register char *buf;            /* in: original text; out: filtered text */
+{
+    register char c, *p, *buf_p;
+
+    /* filter the text; restrict consecutive spaces or dots to just two */
+    for (p = buf_p = buf; *buf_p; buf_p++) {
+       c = *buf_p & '\177';
+       if (c == ' ' || c == '\t' || c == '\n')
+           if (p == buf ||             /* ignore leading whitespace */
+               (p >= buf+2 && *(p-1) == ' ' && *(p-2) == ' ')) continue;
+           else c = ' ';
+       else if (c == '.' || c < ' ' || c == '\177')
+           if (p == buf ||             /* skip leading beeps & such */
+               (p >= buf+2 && *(p-1) == '.' && *(p-2) == '.')) continue;
+           else c = '.';
+       else if (c == '%' &&            /* trim %%% OPCOM verbosity %%% */
+               p >= buf+2 && *(p-1) == '%' && *(p-2) == '%') continue;
+       *p++ = c;
+    }
+    *p = '\0';                 /* terminate, then strip trailing junk */
+    while (p > buf && (*--p == ' ' || *p == '.')) *p = '\0';
+    return;
+}
+
+static char empty_string[] = "";
+
+/* fetch the text of a captured broadcast, then mangle and decipher it
+*/
+struct mail_info *
+parse_next_broadcast()         /* called by ckmailstatus(mail.c) */
+{
+    short length, msg_type;
+    $DESCRIPTOR(message, empty_string);        /* string descriptor for buf[] */
+    struct mail_info *result = 0;
+    /* messages could actually be longer; let long ones be truncated */
+    char buf[255+1];
+
+    message.dsc$a_pointer = buf,  message.dsc$w_length = sizeof buf - 1;
+    msg_type = length = 0;
+    smg$get_broadcast_message(&pasteboard_id, &message, &length, &msg_type);
+    if (msg_type == MSG$_TRMBRDCST) {
+       buf[length] = '\0';
+       filter_brdcst(buf);             /* mask non-printable characters */
+       result = parse_brdcst(buf);     /* do the real work */
+    } else if (msg_type == MSG$_TRMHANGUP) {
+       (void) gsignal(SIGHUP);
+    }
+    return result;
+}
+
+/* spit out any pending broadcast messages whenever we leave
+*/
+static void
+flush_broadcasts()     /* called from disable_broadcast_trapping() */
+{
+    if (broadcasts > 0) {
+       short len, typ;
+       $DESCRIPTOR(msg_dsc, empty_string);
+       char buf[512+1];
+
+       msg_dsc.dsc$a_pointer = buf,  msg_dsc.dsc$w_length = sizeof buf - 1;
+       raw_print("");          /* print at least one line for wait_synch() */
+       do {
+           typ = len = 0;
+           smg$get_broadcast_message(&pasteboard_id, &msg_dsc, &len, &typ);
+           if (typ == MSG$_TRMBRDCST) buf[len] = '\0',  raw_print(buf);
+       } while (--broadcasts);
+       wait_synch();           /* prompt with "Hit return to continue: " */
+    }
+}
+
+/* AST routine called when the terminal's associated mailbox receives a message
+*/
+/*ARGSUSED*/
+static void
+broadcast_ast(dummy)           /* called asynchronously by terminal driver */
+int dummy;     /* not used */
+{
+    broadcasts++;
+}
+
+/* initialize the broadcast manipulation code; SMG makes this easy
+*/
+unsigned long init_broadcast_trapping()   /* called by setftty() [once only] */
+{
+    unsigned long sts, preserve_screen_flag = 1;
+
+    /* we need a pasteboard to pass to the broadcast setup/teardown routines */
+    sts = smg$create_pasteboard(&pasteboard_id, 0, 0, 0, &preserve_screen_flag);
+    if (!vms_ok(sts)) {
+       errno = EVMSERR,  vaxc$errno = sts;
+       raw_print("");
+       perror("?can't create SMG pasteboard for broadcast trapping");
+       wait_synch();
+       broadcasts = -1;        /* flag that trapping is currently broken */
+    }
+    return sts;
+}
+
+/* set up the terminal driver to deliver $brkthru data to a mailbox device
+*/
+unsigned long enable_broadcast_trapping()      /* called by setftty() */
+{
+    unsigned long sts = 1;
+
+    if (broadcasts >= 0) {     /* (-1 => no pasteboard, so don't even try) */
+       /* register callback routine to be triggered when broadcasts arrive */
+       /* Note side effect:  also intercepts hangup notification. */
+       /* Another note:  TMPMBX privilege is required. */
+       sts = smg$set_broadcast_trapping(&pasteboard_id, broadcast_ast, 0);
+       if (!vms_ok(sts)) {
+           errno = EVMSERR,  vaxc$errno = sts;
+           raw_print("");
+           perror("?can't enable broadcast trapping");
+           wait_synch();
+       }
+    }
+    return sts;
+}
+
+/* return to 'normal'; $brkthru data goes straight to the terminal
+*/
+unsigned long disable_broadcast_trapping()     /* called by settty() */
+{
+    unsigned long sts = 1;
+
+    if (broadcasts >= 0) {
+       /* disable trapping; releases associated MBX so that SPAWN can work */
+       sts = smg$disable_broadcast_trapping(&pasteboard_id);
+       if (!vms_ok(sts)) errno = EVMSERR,  vaxc$errno = sts;
+       flush_broadcasts();     /* don't hold on to any buffered ones */
+    }
+    return sts;
+}
+#else  /* MAIL */
+       /* simple stubs for non-mail configuration */
+unsigned long init_broadcast_trapping() { return 1; }
+unsigned long enable_broadcast_trapping() { return 1; }
+unsigned long disable_broadcast_trapping() { return 1; }
+struct mail_info *parse_next_broadcast() { return 0; }
+#endif /* MAIL */
+
+/*----------------------------------------------------------------------*/
+
+#ifdef TEST_DRIVER
+       /* (Take parse_next_broadcast for a spin. :-) */
+
+volatile int broadcasts = 0;
+
+void newmail(foo)
+struct mail_info *foo;
+{
+# define STRING(s) ((s) ? (s) : "<null>")
+    printf("\n\
+  message type = %d\n\
+  display text = \"%s\"\n\
+  object name  = \"%.*s\"\n\
+  response cmd = \"%s\"\n\
+",      foo->message_typ, STRING(foo->display_txt),
+       (foo->object_nam && foo->response_cmd) ?
+               (foo->response_cmd - foo->object_nam - 1) :
+               strlen(STRING(foo->object_nam)),
+       STRING(foo->object_nam), STRING(foo->response_cmd));
+# undef STRING
+}
+
+void ckmailstatus()
+{
+    struct mail_info *brdcst, *parse_next_broadcast();
+
+    while (broadcasts > 0) {   /* process all trapped broadcasts [until] */
+       broadcasts--;
+       if ((brdcst = parse_next_broadcast()) != 0) {
+           newmail(brdcst);
+           break;              /* only handle one real message at a time */
+       } else
+           printf("\n--< non-broadcast encountered >--\n");
+    }
+}
+
+int main()
+{
+    char dummy[BUFSIZ];
+
+    init_broadcast_trapping();
+    enable_broadcast_trapping();
+    for (;;) {
+       ckmailstatus();
+       printf("> "), fflush(stdout);   /* issue a prompt */
+       if (!gets(dummy)) break;        /* wait for a response */
+    }
+    disable_broadcast_trapping();
+    return 1;
+}
+
+void panic(s) char *s; { raw_print(s); exit(EXIT_FAILURE); }
+
+void raw_print(s) char *s; { puts(s); fflush(stdout); }
+
+void wait_synch() { char dummy[BUFSIZ];
+  printf("\nPress <return> to continue: "); fflush(stdout); (void) gets(dummy);
+}
+#endif /* TEST_DRIVER */
+
+/*vmsmail.c*/
diff --git a/sys/vms/vmsmain.c b/sys/vms/vmsmain.c
new file mode 100644 (file)
index 0000000..947501f
--- /dev/null
@@ -0,0 +1,454 @@
+/*     SCCS Id: @(#)vmsmain.c  3.4     2003/10/16      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+/* main.c - VMS NetHack */
+
+#include "hack.h"
+#include "dlb.h"
+
+#include <signal.h>
+
+static void NDECL(whoami);
+static void FDECL(process_options, (int, char **));
+static void NDECL(byebye);
+#ifndef SAVE_ON_FATAL_ERROR
+# ifndef __DECC
+#  define vms_handler_type int
+# else
+#  define vms_handler_type unsigned int
+# endif
+extern void FDECL(VAXC$ESTABLISH, (vms_handler_type (*)(genericptr_t,genericptr_t)));
+static vms_handler_type FDECL(vms_handler, (genericptr_t,genericptr_t));
+#include <ssdef.h>     /* system service status codes */
+#endif
+
+static void NDECL(wd_message);
+#ifdef WIZARD
+static boolean wiz_error_flag = FALSE;
+#endif
+
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+       register int fd;
+#ifdef CHDIR
+       register char *dir;
+#endif
+
+#ifdef SECURE  /* this should be the very first code executed */
+       privoff();
+       fflush((FILE *)0);      /* force stdio to init itself */
+       privon();
+#endif
+
+       atexit(byebye);
+       hname = argv[0];
+       hname = vms_basename(hname);    /* name used in 'usage' type messages */
+       hackpid = getpid();
+       (void) umask(0);
+
+       choose_windows(DEFAULT_WINDOW_SYS);
+
+#ifdef CHDIR                   /* otherwise no chdir() */
+       /*
+        * See if we must change directory to the playground.
+        * (Perhaps hack is installed with privs and playground is
+        *  inaccessible for the player.)
+        * The logical name HACKDIR is overridden by a
+        *  -d command line option (must be the first option given)
+        */
+       dir = nh_getenv("NETHACKDIR");
+       if (!dir) dir = nh_getenv("HACKDIR");
+#endif
+       if(argc > 1) {
+#ifdef CHDIR
+           if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') {
+               /* avoid matching "-dec" for DECgraphics; since the man page
+                * says -d directory, hope nobody's using -desomething_else
+                */
+               argc--;
+               argv++;
+               dir = argv[0]+2;
+               if(*dir == '=' || *dir == ':') dir++;
+               if(!*dir && argc > 1) {
+                       argc--;
+                       argv++;
+                       dir = argv[0];
+               }
+               if(!*dir)
+                   error("Flag -d must be followed by a directory name.");
+           }
+           if (argc > 1)
+#endif /* CHDIR */
+
+           /*
+            * Now we know the directory containing 'record' and
+            * may do a prscore().
+            */
+           if (!strncmp(argv[1], "-s", 2)) {
+#ifdef CHDIR
+               chdirx(dir, FALSE);
+#endif
+               prscore(argc, argv);
+               exit(EXIT_SUCCESS);
+           }
+       }
+
+#ifdef CHDIR
+       /* move to the playground directory; 'termcap' might be found there */
+       chdirx(dir, TRUE);
+#endif
+
+#ifdef SECURE
+       /* disable installed privs while loading nethack.cnf and termcap,
+          and also while initializing terminal [$assign("TT:")]. */
+       privoff();
+#endif
+       initoptions();
+       init_nhwindows(&argc, argv);
+       whoami();
+#ifdef SECURE
+       privon();
+#endif
+
+       /*
+        * It seems you really want to play.
+        */
+       u.uhp = 1;      /* prevent RIP on early quits */
+#ifndef SAVE_ON_FATAL_ERROR
+       /* used to clear hangup stuff while still giving standard traceback */
+       VAXC$ESTABLISH(vms_handler);
+#endif
+       (void) signal(SIGHUP, (SIG_RET_TYPE) hangup);
+
+       process_options(argc, argv);    /* command line options */
+
+#ifdef WIZARD
+       if (wizard)
+               Strcpy(plname, "wizard");
+       else
+#endif
+       if (!*plname || !strncmpi(plname, "games", 4) ||
+           !strcmpi(plname, "nethack"))
+               askname();
+       plnamesuffix();         /* strip suffix from name; calls askname() */
+                               /* again if suffix was whole name */
+                               /* accepts any suffix */
+#ifdef WIZARD
+       if(!wizard) {
+#endif
+               /*
+                * check for multiple games under the same name
+                * (if !locknum) or check max nr of players (otherwise)
+                */
+               (void) signal(SIGQUIT,SIG_IGN);
+               (void) signal(SIGINT,SIG_IGN);
+               if(!locknum)
+                       Sprintf(lock, "_%u%s", (unsigned)getuid(), plname);
+               getlock();
+#ifdef WIZARD
+       } else {
+               Sprintf(lock, "_%u%s", (unsigned)getuid(), plname);
+               getlock();
+       }
+#endif /* WIZARD */
+
+       dlb_init();     /* must be before newgame() */
+
+       /*
+        * Initialization of the boundaries of the mazes
+        * Both boundaries have to be even.
+        */
+       x_maze_max = COLNO-1;
+       if (x_maze_max % 2)
+               x_maze_max--;
+       y_maze_max = ROWNO-1;
+       if (y_maze_max % 2)
+               y_maze_max--;
+
+       /*
+        *  Initialize the vision system.  This must be before mklev() on a
+        *  new game or before a level restore on a saved game.
+        */
+       vision_init();
+
+       display_gamewindows();
+
+       if ((fd = restore_saved_game()) >= 0) {
+#ifdef WIZARD
+               /* Since wizard is actually flags.debug, restoring might
+                * overwrite it.
+                */
+               boolean remember_wiz_mode = wizard;
+#endif
+               const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1);
+
+               (void) chmod(fq_save,0);        /* disallow parallel restores */
+               (void) signal(SIGINT, (SIG_RET_TYPE) done1);
+#ifdef NEWS
+               if(iflags.news) {
+                   display_file(NEWS, FALSE);
+                   iflags.news = FALSE; /* in case dorecover() fails */
+               }
+#endif
+               pline("Restoring save file...");
+               mark_synch();   /* flush output */
+               if(!dorecover(fd))
+                       goto not_recovered;
+#ifdef WIZARD
+               if(!wizard && remember_wiz_mode) wizard = TRUE;
+#endif
+               check_special_room(FALSE);
+               wd_message();
+
+               if (discover || wizard) {
+                       if (yn("Do you want to keep the save file?") == 'n')
+                           (void) delete_savefile();
+                       else
+                           (void) chmod(fq_save,FCMASK); /* back to readable */
+               }
+
+               flags.move = 0;
+       } else {
+not_recovered:
+               player_selection();
+               newgame();
+               wd_message();
+
+               flags.move = 0;
+               set_wear();
+               (void) pickup(1);
+       }
+
+       moveloop();
+       exit(EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return(0);
+}
+
+static void
+process_options(argc, argv)
+int argc;
+char *argv[];
+{
+       int i;
+
+
+       /*
+        * Process options.
+        */
+       while(argc > 1 && argv[1][0] == '-'){
+               argv++;
+               argc--;
+               switch(argv[0][1]){
+               case 'D':
+#ifdef WIZARD
+                       if(!strcmpi(nh_getenv("USER"), WIZARD_NAME)) {
+                               wizard = TRUE;
+                               break;
+                       }
+                       /* otherwise fall thru to discover */
+                       wiz_error_flag = TRUE;
+#endif /* WIZARD */
+               case 'X':
+               case 'x':
+                       discover = TRUE;
+                       break;
+#ifdef NEWS
+               case 'n':
+                       iflags.news = FALSE;
+                       break;
+#endif
+               case 'u':
+                       if(argv[0][2])
+                         (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
+                       else if(argc > 1) {
+                         argc--;
+                         argv++;
+                         (void) strncpy(plname, argv[0], sizeof(plname)-1);
+                       } else
+                               raw_print("Player name expected after -u");
+                       break;
+               case 'I':
+               case 'i':
+                       if (!strncmpi(argv[0]+1, "IBM", 3))
+                               switch_graphics(IBM_GRAPHICS);
+                       break;
+           /*  case 'D': */
+               case 'd':
+                       if (!strncmpi(argv[0]+1, "DEC", 3))
+                               switch_graphics(DEC_GRAPHICS);
+                       break;
+               case 'p': /* profession (role) */
+                       if (argv[0][2]) {
+                           if ((i = str2role(&argv[0][2])) >= 0)
+                               flags.initrole = i;
+                       } else if (argc > 1) {
+                               argc--;
+                               argv++;
+                           if ((i = str2role(argv[0])) >= 0)
+                               flags.initrole = i;
+                       }
+                       break;
+               case 'r': /* race */
+                       if (argv[0][2]) {
+                           if ((i = str2race(&argv[0][2])) >= 0)
+                               flags.initrace = i;
+                       } else if (argc > 1) {
+                               argc--;
+                               argv++;
+                           if ((i = str2race(argv[0])) >= 0)
+                               flags.initrace = i;
+                       }
+                       break;
+               case '@':
+                       flags.randomall = 1;
+                       break;
+               default:
+                       if ((i = str2role(&argv[0][1])) >= 0) {
+                           flags.initrole = i;
+                               break;
+                       }
+                       /* else raw_printf("Unknown option: %s", *argv); */
+               }
+       }
+
+       if(argc > 1)
+               locknum = atoi(argv[1]);
+#ifdef MAX_NR_OF_PLAYERS
+       if(!locknum || locknum > MAX_NR_OF_PLAYERS)
+               locknum = MAX_NR_OF_PLAYERS;
+#endif
+}
+
+#ifdef CHDIR
+void
+chdirx(dir, wr)
+const char *dir;
+boolean wr;
+{
+# ifndef HACKDIR
+       static const char *defdir = ".";
+# else
+       static const char *defdir = HACKDIR;
+
+       if(dir == (const char *)0)
+               dir = defdir;
+       else if (wr && !same_dir(HACKDIR, dir))
+               /* If we're playing anywhere other than HACKDIR, turn off any
+                  privs we may have been installed with. */
+               privoff();
+# endif
+
+       if(dir && chdir(dir) < 0) {
+               perror(dir);
+               error("Cannot chdir to %s.", dir);
+       }
+
+       /* warn the player if we can't write the record file */
+       if (wr) check_recordfile(dir);
+
+       defdir = dir;
+}
+#endif /* CHDIR */
+
+static void
+whoami()
+{
+       /*
+        * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS
+        *                      2. Use lowercase of $USER  (if 1. fails)
+        * The resulting name is overridden by command line options.
+        * If everything fails, or if the resulting name is some generic
+        * account like "games" then eventually we'll ask him.
+        * Note that we trust the user here; it is possible to play under
+        * somebody else's name.
+        */
+       register char *s;
+
+       if (!*plname && (s = nh_getenv("USER")))
+               (void) lcase(strncpy(plname, s, sizeof(plname)-1));
+}
+
+static void
+byebye()
+{
+    /* Different versions of both VAX C and GNU C use different return types
+       for signal functions.  Return type 'int' along with the explicit casts
+       below satisfy the most combinations of compiler vs <signal.h>.
+     */
+    int (*hup)();
+#ifdef SHELL
+    extern unsigned long dosh_pid, mail_pid;
+    extern unsigned long FDECL(sys$delprc,(unsigned long *,const genericptr_t));
+
+    /* clean up any subprocess we've spawned that may still be hanging around */
+    if (dosh_pid) (void) sys$delprc(&dosh_pid, 0), dosh_pid = 0;
+    if (mail_pid) (void) sys$delprc(&mail_pid, 0), mail_pid = 0;
+#endif
+
+    /* SIGHUP doesn't seem to do anything on VMS, so we fudge it here... */
+    hup = (int(*)()) signal(SIGHUP, SIG_IGN);
+    if (!program_state.exiting++ &&
+       hup != (int(*)()) SIG_DFL && hup != (int(*)()) SIG_IGN)
+       (void) (*hup)();
+
+#ifdef CHDIR
+    (void) chdir(getenv("PATH"));
+#endif
+}
+
+#ifndef SAVE_ON_FATAL_ERROR
+/* Condition handler to prevent byebye's hangup simulation
+   from saving the game after a fatal error has occurred.  */
+/*ARGSUSED*/
+static vms_handler_type                /* should be `unsigned long', but the -*/
+vms_handler(sigargs, mechargs) /*+ prototype in <signal.h> is screwed */
+genericptr_t sigargs, mechargs;        /* [0] is argc, [1..argc] are the real args */
+{
+    unsigned long condition = ((unsigned long *)sigargs)[1];
+
+    if (condition == SS$_ACCVIO                /* access violation */
+     || (condition >= SS$_ASTFLT && condition <= SS$_TBIT)
+     || (condition >= SS$_ARTRES && condition <= SS$_INHCHME)) {
+       program_state.done_hup = TRUE;  /* pretend hangup has been attempted */
+# if defined(WIZARD) && !defined(BETA)
+       if (wizard)
+# endif /*WIZARD && !BETA*/
+# if defined(WIZARD) ||  defined(BETA)
+           abort();    /* enter the debugger */
+# endif /*WIZARD || BETA*/
+    }
+    return SS$_RESIGNAL;
+}
+#endif
+
+#ifdef PORT_HELP
+void
+port_help()
+{
+       /*
+        * Display VMS-specific help.   Just show contents of the helpfile
+        * named by PORT_HELP.
+        */
+       display_file(PORT_HELP, TRUE);
+}
+#endif /* PORT_HELP */
+
+static void
+wd_message()
+{
+#ifdef WIZARD
+       if (wiz_error_flag) {
+               pline("Only user \"%s\" may access debug (wizard) mode.",
+                       WIZARD_NAME);
+               pline("Entering discovery mode instead.");
+       } else
+#endif
+       if (discover)
+               You("are in non-scoring discovery mode.");
+}
+
+/*vmsmain.c*/
diff --git a/sys/vms/vmsmisc.c b/sys/vms/vmsmisc.c
new file mode 100644 (file)
index 0000000..573d9c4
--- /dev/null
@@ -0,0 +1,30 @@
+/*     SCCS Id: @(#)vmsmisc.c  3.4     1996/03/02      */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include <ssdef.h>
+#include <stsdef.h>
+
+void vms_exit( /*_ int _*/ );
+void vms_abort( /*_ void _*/ );
+
+extern void exit( /*_ int _*/ );
+extern void lib$signal( /*_ unsigned long,... _*/ );
+
+void
+vms_exit(status)
+int status;
+{
+    exit(status ? (SS$_ABORT | STS$M_INHIB_MSG) : SS$_NORMAL);
+}
+
+void
+vms_abort()
+{
+    lib$signal(SS$_DEBUG);
+}
+
+#ifdef VERYOLD_VMS
+#include "oldcrtl.c"
+#endif
+
+/*vmsmisc.c*/
diff --git a/sys/vms/vmstty.c b/sys/vms/vmstty.c
new file mode 100644 (file)
index 0000000..314a912
--- /dev/null
@@ -0,0 +1,491 @@
+/*     SCCS Id: @(#)vmstty.c   3.4     2003/09/18      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+/* tty.c - (VMS) version */
+
+#define NEED_VARARGS
+#include "hack.h"
+#include "wintty.h"
+#include "tcap.h"
+
+#include <descrip.h>
+#include <iodef.h>
+#ifndef __GNUC__
+#include <smgdef.h>
+#include <ttdef.h>
+#include <tt2def.h>
+#else  /* values needed from missing include files */
+# define SMG$K_TRM_UP   274
+# define SMG$K_TRM_DOWN  275
+# define SMG$K_TRM_LEFT  276
+# define SMG$K_TRM_RIGHT 277
+# define TT$M_MECHTAB    0x00000100    /* hardware tab support */
+# define TT$M_MECHFORM   0x00080000    /* hardware form-feed support */
+# define TT$M_NOBRDCST   0x00020000    /* disable broadcast messages, but  */
+# define TT2$M_BRDCSTMBX  0x00000010   /* catch them in associated mailbox */
+# define TT2$M_APP_KEYPAD 0x00800000   /* application vs numeric keypad mode */
+#endif /* __GNUC__ */
+#ifdef USE_QIO_INPUT
+#include <ssdef.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+
+unsigned long lib$disable_ctrl(), lib$enable_ctrl();
+unsigned long sys$assign(), sys$dassgn(), sys$qiow();
+#ifndef USE_QIO_INPUT
+unsigned long smg$create_virtual_keyboard(), smg$delete_virtual_keyboard(),
+             smg$read_keystroke(), smg$cancel_input();
+#else
+static short FDECL(parse_function_key, (int));
+#endif
+static void NDECL(setctty);
+static void NDECL(resettty);
+
+#define vms_ok(sts) ((sts)&1)
+#define META(c)  ((c)|0x80)    /* 8th bit */
+#define CTRL(c)  ((c)&0x1F)
+#define CMASK(c) (1<<CTRL(c))
+#define LIB$M_CLI_CTRLT CMASK('T')     /* 0x00100000 */
+#define LIB$M_CLI_CTRLY CMASK('Y')     /* 0x02000000 */
+#define ESC '\033'
+#define CSI META(ESC)          /* '\233' */
+#define SS3 META(CTRL('O'))    /* '\217' */
+
+extern short ospeed;
+char erase_char, intr_char, kill_char;
+static boolean settty_needed = FALSE,  bombing = FALSE;
+static unsigned long kb = 0;
+#ifdef USE_QIO_INPUT
+static char inputbuf[15+1], *inp = 0;
+static int  inc = 0;
+#endif
+
+#define QIO_FUNC       IO$_TTYREADALL|IO$M_NOECHO|IO$M_TRMNOECHO
+#ifdef MAIL
+#define TT_SPECIAL_HANDLING  (TT$M_MECHTAB|TT$M_MECHFORM|TT$M_NOBRDCST)
+#define TT2_SPECIAL_HANDLING (TT2$M_BRDCSTMBX)
+#else
+#define TT_SPECIAL_HANDLING  (TT$M_MECHTAB|TT$M_MECHFORM)
+#define TT2_SPECIAL_HANDLING (0)
+#endif
+#define Uword unsigned short
+#define Ubyte unsigned char
+struct _rd_iosb {              /* i/o status block for read */
+       Uword   status,  trm_offset;
+       Uword   terminator,  trm_siz;
+};
+struct _wr_iosb {              /* i/o status block for write */
+       Uword   status,  byte_cnt;
+       unsigned   : 32;
+};
+struct _sm_iosb {              /* i/o status block for sense-mode qio */
+       Uword     status;
+       Ubyte     xmt_speed,  rcv_speed;
+       Ubyte     cr_fill,  lf_fill,  parity;
+       unsigned   : 8;
+};
+struct _sm_bufr {              /* sense-mode characteristics buffer */
+       Ubyte     class,  type;         /* class==DC$_TERM, type==(various) */
+       Uword     buf_siz;              /* aka page width */
+#define page_width buf_siz             /* number of columns */
+             unsigned  tt_char : 24;   /* primary characteristics */
+             unsigned  page_length     :  8;   /* number of lines */
+             unsigned  tt2_char        : 32;   /* secondary characteristics */
+};
+static struct {
+    struct _sm_iosb io;
+    struct _sm_bufr sm;
+} sg = {{0},{0}};
+static unsigned short tt_chan = 0;
+static unsigned long  tt_char_restore = 0, tt_char_active = 0,
+                     tt2_char_restore = 0, tt2_char_active = 0;
+static unsigned long  ctrl_mask = 0;
+
+int
+vms_getchar()
+{
+    short key;
+#ifdef USE_QIO_INPUT
+    struct _rd_iosb iosb;
+    unsigned long sts;
+    unsigned char kb_buf;
+#else  /* SMG input */
+    static volatile int recurse = 0;   /* SMG is not AST re-entrant! */
+#endif
+
+    if (program_state.done_hup) {
+       /* hangup has occurred; do not attempt to get further user input */
+       return ESC;
+    }
+
+#ifdef USE_QIO_INPUT
+    if (inc > 0) {
+       /* we have buffered character(s) from previous read */
+       kb_buf = *inp++;
+       --inc;
+       sts = SS$_NORMAL;
+    } else {
+       sts = sys$qiow(0, tt_chan, QIO_FUNC, &iosb, (void(*)())0, 0,
+                      &kb_buf, sizeof kb_buf, 0, 0, 0, 0);
+    }
+    if (vms_ok(sts)) {
+       if (kb_buf == CTRL('C')) {
+           if (intr_char) gsignal(SIGINT);
+           key = (short)kb_buf;
+       } else if (kb_buf == '\r') {    /* <return> */
+           key = (short)'\n';
+       } else if (kb_buf == ESC || kb_buf == CSI || kb_buf == SS3) {
+           switch(parse_function_key((int)kb_buf)) {
+             case SMG$K_TRM_UP:    key = iflags.num_pad ? '8' : 'k';  break;
+             case SMG$K_TRM_DOWN:  key = iflags.num_pad ? '2' : 'j';  break;
+             case SMG$K_TRM_LEFT:  key = iflags.num_pad ? '4' : 'h';  break;
+             case SMG$K_TRM_RIGHT: key = iflags.num_pad ? '6' : 'l';  break;
+             default:              key = ESC;  break;
+           }
+       } else {
+           key = (short)kb_buf;
+       }
+    } else if (sts == SS$_HANGUP || iosb.status == SS$_HANGUP
+           || sts == SS$_DEVOFFLINE) {
+       gsignal(SIGHUP);
+       key = ESC;
+    } else                     /*(this should never happen)*/
+       key = getchar();
+
+#else   /*!USE_QIO_INPUT*/
+    if (recurse++ == 0 && kb != 0) {
+       smg$read_keystroke(&kb, &key);
+       switch (key) {
+         case SMG$K_TRM_UP:    iflags.num_pad ? '8' : key = 'k';  break;
+         case SMG$K_TRM_DOWN:  iflags.num_pad ? '2' : key = 'j';  break;
+         case SMG$K_TRM_LEFT:  iflags.num_pad ? '4' : key = 'h';  break;
+         case SMG$K_TRM_RIGHT: iflags.num_pad ? '6' : key = 'l';  break;
+         case '\r':            key = '\n'; break;
+         default:              if (key > 255)  key = ESC;
+                               break;
+       }
+    } else {
+       /* abnormal input--either SMG didn't initialize properly or
+          vms_getchar() has been called recursively (via SIGINT handler).
+        */
+       if (kb != 0)                    /* must have been a recursive call */
+           smg$cancel_input(&kb);      /*  from an interrupt handler      */
+       key = getchar();
+    }
+    --recurse;
+#endif /* USE_QIO_INPUT */
+
+    return (int)key;
+}
+
+#ifdef USE_QIO_INPUT
+       /*
+       * We've just gotten an <escape> character.  Do a timed read to
+       * get any other characters, then try to parse them as an escape
+       * sequence.  This isn't perfect, since there's no guarantee
+       * that a full escape sequence will be available, or even if one
+       * is, it might actually by regular input from a fast typist or
+       * a stalled input connection.  {For packetized environments,
+       * cross plural(body_part(FINGER)) and hope for best. :-}
+       *
+       * This is needed to preserve compatability with SMG interface
+       * for two reasons:
+       *    1) retain support for arrow keys, and
+       *    2) treat other VTxxx function keys as <esc> for aborting
+       *       various NetHack prompts.
+       * The second reason is compelling; otherwise remaining chars of
+       * an escape sequence get treated as inappropriate user commands.
+       *
+       * SMG code values for these key sequences fall in the range of
+       * 256 thru 3xx.  The assignments are not particularly intuitive.
+       */
+/*=
+     -- Summary of VTxxx-style keyboards and transmitted escape sequences. --
+Keypad codes are prefixed by 7 bit (\033 O) or 8 bit SS3:
+       keypad:  PF1 PF2 PF3 PF4       codes:   P   Q   R   S
+                 7   8   9   -                 w   x   y   m
+                 4   5   6   .                 t   u   v   n
+                 1   2   3  :en-:              q   r   s  : :
+                ...0...  ,  :ter:             ...p...  l  :M:
+Arrows are prefixed by either SS3 or CSI (either 7 or 8 bit), depending on
+whether the terminal is in application or numeric mode (ditto for PF keys):
+       arrows: <up> <dwn> <lft> <rgt>          A   B   D   C
+Additional function keys (vk201/vk401) generate CSI nn ~ (nn is 1 or 2 digits):
+    vk201 keys:  F6 F7 F8 F9 F10   F11 F12 F13 F14  Help Do   F17 F18 F19 F20
+   'nn' digits:  17 18 19 20 21    23  24  25  26    28  29   31  32  33  34
+     alternate:  ^C               ^[  ^H  ^J           (when in VT100 mode)
+   edit keypad: <fnd> <ins> <rmv>     digits:  1   2   3
+               <sel> <prv> <nxt>               4   5   6
+VT52 mode:  arrows and PF keys send ESCx where x is in A-D or P-S.
+=*/
+
+static const char *arrow_or_PF = "ABCDPQRS",   /* suffix char */
+                 *smg_keypad_codes = "PQRSpqrstuvwxyMmlnABDC";
+       /* PF1..PF4,KP0..KP9,enter,dash,comma,dot,up-arrow,down,left,right */
+       /* Ultimate return value is (index into smg_keypad_codes[] + 256). */
+
+static short
+parse_function_key(c)
+register int c;
+{
+    struct _rd_iosb iosb;
+    unsigned long sts;
+    char seq_buf[15+1];                /* plenty room for escape sequence + slop */
+    short result = ESC;                /* translate to <escape> by default */
+
+    /*
+     * Read whatever we can from type-ahead buffer (1 second timeout).
+     * If the user typed an actual <escape> to deliberately abort
+     * something, he or she should be able to tolerate the necessary
+     * restriction of a negligible pause before typing anything else.
+     * We might already have [at least some of] an escape sequence from a
+     * previous read, particularly if user holds down the arrow keys...
+     */
+    if (inc > 0) strncpy(seq_buf, inp, inc);
+    if (inc < (int)(sizeof seq_buf) - 1) {
+       sts = sys$qiow(0, tt_chan, QIO_FUNC|IO$M_TIMED, &iosb, (void(*)())0, 0,
+                      seq_buf + inc, sizeof seq_buf - 1 - inc, 1, 0, 0, 0);
+       if (vms_ok(sts))  sts = iosb.status;
+    } else
+       sts = SS$_NORMAL;
+    if (vms_ok(sts) || sts == SS$_TIMEOUT) {
+       register int cnt = iosb.trm_offset + iosb.trm_siz + inc;
+       register char *p = seq_buf;
+       if (c == ESC)   /* check for 7-bit vt100/ANSI, or vt52 */
+           if (*p == '[' || *p == 'O') c = META(CTRL(*p++)),  cnt--;
+           else if (strchr(arrow_or_PF, *p)) c = SS3; /*CSI*/
+       if (cnt > 0 && (c == SS3 || (c == CSI && strchr(arrow_or_PF, *p)))) {
+           register char *q = strchr(smg_keypad_codes, *p);
+           if (q) result = 256 + (q - smg_keypad_codes);
+           p++,  --cnt;        /* one more char consumed */
+       } else if (cnt > 1 && c == CSI) {
+           static short        /* "CSI nn ~" -> F_keys[nn] */
+               F_keys[35] = {  ESC,                            /*(filler)*/
+                               311, 312, 313, 314, 315, 316,   /* E1-E6 */
+                               ESC, ESC, ESC, ESC,        /*(more filler)*/
+                               281, 282, 283, 284, 285, ESC,   /* F1-F5 */
+                               286, 287, 288, 289, 290, ESC,   /* F6-F10*/
+                               291, 292, 293, 294, ESC,        /*F11-F14*/
+                               295, 296, ESC, /*<help>,<do>, aka F15,F16*/
+                               297, 298, 299, 300              /*F17-F20*/
+               };  /* note: there are several missing nn in CSI nn ~ values */
+           int nn;  char *q;
+           *(p + cnt) = '\0';  /* terminate string */
+           q = strchr(p, '~');
+           if (q && sscanf(p, "%d~", &nn) == 1) {
+               if (nn > 0 && nn < SIZE(F_keys)) result = F_keys[nn];
+               cnt -= (++q - p);
+               p = q;
+           }
+       }
+       if (cnt > 0) strncpy((inp = inputbuf), p, (inc = cnt));
+       else         inc = 0,  inp = 0;
+    }
+    return result;
+}
+#endif /* USE_QIO_INPUT */
+
+static void
+setctty()
+{
+    struct _sm_iosb iosb;
+    unsigned long status;
+
+    status = sys$qiow(0, tt_chan, IO$_SETMODE, &iosb, (void(*)())0, 0,
+                     &sg.sm, sizeof sg.sm, 0, 0, 0, 0);
+    if (vms_ok(status))  status = iosb.status;
+    if (vms_ok(status)) {
+       /* try to force terminal into synch with TTDRIVER's setting */
+       number_pad((sg.sm.tt2_char & TT2$M_APP_KEYPAD) ? -1 : 1);
+    } else {
+       raw_print("");
+       errno = EVMSERR,  vaxc$errno = status;
+       perror("NetHack(setctty: setmode)");
+       wait_synch();
+    }
+}
+
+static void
+resettty()                     /* atexit() routine */
+{
+    if (settty_needed) {
+       bombing = TRUE;     /* don't clear screen; preserve traceback info */
+       settty((char *)0);
+    }
+    (void) sys$dassgn(tt_chan),  tt_chan = 0;
+}
+
+/*
+ * Get initial state of terminal, set ospeed (for termcap routines)
+ * and switch off tab expansion if necessary.
+ * Called by init_nhwindows() and resume_nhwindows() in wintty.c
+ * (for initial startup and for returning from '!' or ^Z).
+ */
+void
+gettty()
+{
+    static char dev_tty[] = "TT:";
+    static $DESCRIPTOR(tty_dsc, dev_tty);
+    int err = 0;
+    unsigned long status, zero = 0;
+
+    if (tt_chan == 0) {                /* do this stuff once only */
+       iflags.cbreak = OFF,  iflags.echo = ON; /* until setup is complete */
+       status = sys$assign(&tty_dsc, &tt_chan, 0, 0);
+       if (!vms_ok(status)) {
+           raw_print(""),  err++;
+           errno = EVMSERR,  vaxc$errno = status;
+           perror("NetHack(gettty: $assign)");
+       }
+       atexit(resettty);   /* register an exit handler to reset things */
+    }
+    status = sys$qiow(0, tt_chan, IO$_SENSEMODE, &sg.io, (void(*)())0, 0,
+                     &sg.sm, sizeof sg.sm, 0, 0, 0, 0);
+    if (vms_ok(status))  status = sg.io.status;
+    if (!vms_ok(status)) {
+       raw_print(""),  err++;
+       errno = EVMSERR,  vaxc$errno = status;
+       perror("NetHack(gettty: sensemode)");
+    }
+    ospeed = sg.io.xmt_speed;
+    erase_char = '\177';       /* <rubout>, aka <delete> */
+    kill_char = CTRL('U');
+    intr_char = CTRL('C');
+    (void) lib$enable_ctrl(&zero, &ctrl_mask);
+    /* Use the systems's values for lines and columns if it has any idea. */
+    if (sg.sm.page_length)
+       LI = sg.sm.page_length;
+    if (sg.sm.page_width)
+       CO = sg.sm.page_width;
+    /* suppress tab and form-feed expansion, in case termcap uses them */
+    tt_char_restore  = sg.sm.tt_char;
+    tt_char_active   = sg.sm.tt_char |= TT_SPECIAL_HANDLING;
+    tt2_char_restore = sg.sm.tt2_char;
+    tt2_char_active  = sg.sm.tt2_char |= TT2_SPECIAL_HANDLING;
+#if 0          /*[ defer until setftty() ]*/
+    setctty();
+#endif
+
+    if (err) wait_synch();
+}
+
+/* reset terminal to original state */
+void
+settty(s)
+const char *s;
+{
+       if (!bombing) end_screen();
+       if (s) raw_print(s);
+       disable_broadcast_trapping();
+#if 0          /* let SMG's exit handler do the cleanup (as per doc) */
+/* #ifndef USE_QIO_INPUT */
+       if (kb)  smg$delete_virtual_keyboard(&kb),  kb = 0;
+#endif /* 0 (!USE_QIO_INPUT) */
+       if (ctrl_mask)
+           (void) lib$enable_ctrl(&ctrl_mask, 0);
+       iflags.echo = ON;
+       iflags.cbreak = OFF;
+       /* reset original tab, form-feed, broadcast settings */
+       sg.sm.tt_char  = tt_char_restore;
+       sg.sm.tt2_char = tt2_char_restore;
+       setctty();
+
+       settty_needed = FALSE;
+}
+
+/* same as settty, with no clearing of the screen */
+void
+shuttty(s)
+const char *s;
+{
+       bombing = TRUE;
+       settty(s);
+       bombing = FALSE;
+}
+
+void
+setftty()
+{
+       unsigned long mask = LIB$M_CLI_CTRLT | LIB$M_CLI_CTRLY;
+
+       (void) lib$disable_ctrl(&mask, 0);
+       if (kb == 0) {          /* do this stuff once only */
+#ifdef USE_QIO_INPUT
+           kb = tt_chan;
+#else   /*!USE_QIO_INPUT*/
+           smg$create_virtual_keyboard(&kb);
+#endif  /*USE_QIO_INPUT*/
+           init_broadcast_trapping();
+       }
+       enable_broadcast_trapping();    /* no-op if !defined(MAIL) */
+       iflags.cbreak = (kb != 0) ? ON : OFF;
+       iflags.echo   = (kb != 0) ? OFF : ON;
+       /* disable tab & form-feed expansion; prepare for broadcast trapping */
+       sg.sm.tt_char  = tt_char_active;
+       sg.sm.tt2_char = tt2_char_active;
+       setctty();
+
+       start_screen();
+       settty_needed = TRUE;
+}
+
+void
+intron()               /* enable kbd interupts if enabled when game started */
+{
+       intr_char = CTRL('C');
+}
+
+void
+introff()              /* disable kbd interrupts if required*/
+{
+       intr_char = 0;
+}
+
+#ifdef TIMED_DELAY
+
+extern unsigned long
+       FDECL(lib$emul, (const long *,const long *,const long *,long *));
+extern unsigned long sys$schdwk(), sys$hiber();
+
+#define VMS_UNITS_PER_SECOND 10000000L /* hundreds of nanoseconds, 1e-7 */
+/* constant for conversion from milliseconds to VMS delta time (negative) */
+static const long mseconds_to_delta = VMS_UNITS_PER_SECOND / 1000L * -1L;
+
+/* sleep for specified number of milliseconds (note: the timer used
+   generally only has 10-millisecond resolution at the hardware level...) */
+void msleep(mseconds)
+unsigned mseconds;     /* milliseconds */
+{
+    long pid = 0L, zero = 0L, msec, qtime[2];
+
+    msec = (long) mseconds;
+    if (msec > 0 &&
+       /* qtime{0:63} = msec{0:31} * mseconds_to_delta{0:31} + zero{0:31} */
+       vms_ok(lib$emul(&msec, &mseconds_to_delta, &zero, qtime))) {
+       /* schedule a wake-up call, then go to sleep */
+       if (vms_ok(sys$schdwk(&pid, (genericptr_t)0, qtime, (long *)0)))
+           (void)sys$hiber();
+    }
+}
+
+#endif /* TIMED_DELAY */
+
+
+/* fatal error */
+/*VARARGS1*/
+void
+error VA_DECL(const char *,s)
+       VA_START(s);
+       VA_INIT(s, const char *);
+       if(settty_needed)
+               settty((char *)0);
+       Vprintf(s,VA_ARGS);
+       (void) putchar('\n');
+       VA_END();
+#ifndef SAVE_ON_FATAL_ERROR
+       /* prevent vmsmain's exit handler byebye() from calling hangup() */
+       (void)signal(SIGHUP, SIG_DFL);
+#endif
+       exit(EXIT_FAILURE);
+}
diff --git a/sys/vms/vmsunix.c b/sys/vms/vmsunix.c
new file mode 100644 (file)
index 0000000..fdaa53c
--- /dev/null
@@ -0,0 +1,474 @@
+/*     SCCS Id: @(#)vmsunix.c  3.4     2001/07/27      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* This file implements things from unixunix.c, plus related stuff */
+
+#include "hack.h"
+
+#include <descrip.h>
+#include <dvidef.h>
+#include <jpidef.h>
+#include <ssdef.h>
+#include <errno.h>
+#include <signal.h>
+#undef off_t
+#ifdef GNUC
+#include <sys/stat.h>
+#else
+# define umask hide_umask_dummy /* DEC C: avoid conflict with system.h */
+#include <stat.h>
+# undef  umask
+#endif
+#include <ctype.h>
+
+extern unsigned long sys$setprv();
+extern unsigned long lib$getdvi(), lib$getjpi(), lib$spawn(), lib$attach();
+extern unsigned long smg$init_term_table_by_type(), smg$del_term_table();
+#define vms_ok(sts) ((sts) & 1) /* odd => success */
+
+static int FDECL(veryold, (int));
+static char *NDECL(verify_term);
+#if defined(SHELL) || defined(SUSPEND)
+static void FDECL(hack_escape, (BOOLEAN_P,const char *));
+static void FDECL(hack_resume, (BOOLEAN_P));
+#endif
+
+static int
+veryold(fd)
+int fd;
+{
+       register int i;
+       time_t date;
+       struct stat buf;
+
+       if(fstat(fd, &buf)) return(0);                  /* cannot get status */
+#ifndef INSURANCE
+       if(buf.st_size != sizeof(int)) return(0);       /* not an xlock file */
+#endif
+       (void) time(&date);
+       if(date - buf.st_mtime < 3L*24L*60L*60L) {      /* recent */
+               int lockedpid;  /* should be the same size as hackpid */
+               unsigned long status, dummy, code = JPI$_PID;
+
+               if (read(fd, (genericptr_t)&lockedpid, sizeof(lockedpid)) !=
+                               sizeof(lockedpid))      /* strange ... */
+                       return 0;
+               status = lib$getjpi(&code, &lockedpid, 0, &dummy);
+               if (vms_ok(status) || status != SS$_NONEXPR)
+                       return 0;
+       }
+       (void) close(fd);
+
+       /* cannot use maxledgerno() here, because we need to find a lock name
+        * before starting everything (including the dungeon initialization
+        * that sets astral_level, needed for maxledgerno()) up
+        */
+       for(i = 1; i <= MAXDUNGEON*MAXLEVEL + 1; i++) {
+               /* try to remove all */
+               set_levelfile_name(lock, i);
+               (void) delete(lock);
+       }
+       set_levelfile_name(lock, 0);
+       if(delete(lock)) return(0);                     /* cannot remove it */
+       return(1);                                      /* success! */
+}
+
+void
+getlock()
+{
+       register int i = 0, fd;
+
+       /* idea from rpick%ucqais@uccba.uc.edu
+        * prevent automated rerolling of characters
+        * test input (fd0) so that tee'ing output to get a screen dump still
+        * works
+        * also incidentally prevents development of any hack-o-matic programs
+        */
+       if (isatty(0) <= 0)
+               error("You must play from a terminal.");
+
+       /* we ignore QUIT and INT at this point */
+       if (!lock_file(HLOCK, LOCKPREFIX, 10)) {
+               wait_synch();
+               error("Quitting.");
+       }
+
+       regularize(lock);
+       set_levelfile_name(lock, 0);
+       if(locknum > 25) locknum = 25;
+
+       do {
+               if(locknum) lock[0] = 'a' + i++;
+
+               if((fd = open(lock, 0, 0)) == -1) {
+                       if(errno == ENOENT) goto gotlock;    /* no such file */
+                       perror(lock);
+                       unlock_file(HLOCK);
+                       error("Cannot open %s", lock);
+               }
+
+               if(veryold(fd)) /* if true, this closes fd and unlinks lock */
+                       goto gotlock;
+               (void) close(fd);
+       } while(i < locknum);
+
+       unlock_file(HLOCK);
+       error(locknum ? "Too many hacks running now."
+                     : "There is a game in progress under your name.");
+
+gotlock:
+       fd = creat(lock, FCMASK);
+       unlock_file(HLOCK);
+       if(fd == -1) {
+               error("cannot creat lock file.");
+       } else {
+               if(write(fd, (char *) &hackpid, sizeof(hackpid))
+                   != sizeof(hackpid)){
+                       error("cannot write lock");
+               }
+               if(close(fd) == -1) {
+                       error("cannot close lock");
+               }
+       }
+}      
+
+void
+regularize(s)  /* normalize file name */
+register char *s;
+{
+       register char *lp;
+
+       for (lp = s; *lp; lp++)         /* note: '-' becomes '_' */
+           if (!(isalpha(*lp) || isdigit(*lp) || *lp == '$'))
+                       *lp = '_';
+}
+
+#undef getuid
+int
+vms_getuid()
+{
+    return (getgid() << 16) | getuid();
+}
+
+#ifndef FAB$C_STMLF
+#define FAB$C_STMLF 5
+#endif
+/* check whether the open file specified by `fd' is in stream-lf format */
+boolean
+file_is_stmlf(fd)
+int fd;
+{
+    int rfm;
+    struct stat buf;
+
+    if (fstat(fd, &buf)) return FALSE; /* cannot get status? */
+
+#ifdef stat_alignment_fix      /* gcc-vms alignment kludge */
+    rfm = stat_alignment_fix(&buf)->st_fab_rfm;
+#else
+    rfm = buf.st_fab_rfm;
+#endif
+    return rfm == FAB$C_STMLF;
+}
+
+/*------*/
+#ifndef LNM$_STRING
+#include <lnmdef.h>    /* logical name definitions */
+#endif
+#define ENVSIZ LNM$C_NAMLENGTH  /*255*/
+
+#define ENV_USR 0      /* user-mode */
+#define ENV_SUP 1      /* supervisor-mode */
+#define ENV_JOB 2      /* job-wide entry */
+
+/* vms_define() - assign a value to a logical name */
+int
+vms_define(name, value, flag)
+const char *name;
+const char *value;
+int flag;
+{
+    struct dsc { unsigned short len, mbz; const char *adr; }; /* descriptor */
+    struct itm3 { short buflen, itmcode; const char *bufadr; short *retlen; };
+    static struct itm3 itm_lst[] = { {0,LNM$_STRING,0,0}, {0,0} };
+    struct dsc nam_dsc, val_dsc, tbl_dsc;
+    unsigned long result, sys$crelnm(), lib$set_logical();
+
+    /* set up string descriptors */
+    nam_dsc.mbz = val_dsc.mbz = tbl_dsc.mbz = 0;
+    nam_dsc.len = strlen( nam_dsc.adr = name );
+    val_dsc.len = strlen( val_dsc.adr = value );
+    tbl_dsc.len = strlen( tbl_dsc.adr = "LNM$PROCESS" );
+
+    switch (flag) {
+       case ENV_JOB:   /* job logical name */
+               tbl_dsc.len = strlen( tbl_dsc.adr = "LNM$JOB" );
+           /*FALLTHRU*/
+       case ENV_SUP:   /* supervisor-mode process logical name */
+               result = lib$set_logical(&nam_dsc, &val_dsc, &tbl_dsc);
+           break;
+       case ENV_USR:   /* user-mode process logical name */
+               itm_lst[0].buflen = val_dsc.len;
+               itm_lst[0].bufadr = val_dsc.adr;
+               result = sys$crelnm(0, &tbl_dsc, &nam_dsc, 0, itm_lst);
+           break;
+       default:        /*[ bad input ]*/
+               result = 0;
+           break;
+    }
+    result &= 1;       /* odd => success (== 1), even => failure (== 0) */
+    return !result;    /* 0 == success, 1 == failure */
+}
+
+/* vms_putenv() - create or modify an environment value */
+int
+vms_putenv(string)
+const char *string;
+{
+    char name[ENVSIZ+1], value[ENVSIZ+1], *p;   /* [255+1] */
+
+    p = strchr(string, '=');
+    if (p > string && p < string + sizeof name && strlen(p+1) < sizeof value) {
+       (void)strncpy(name, string, p - string),  name[p - string] = '\0';
+       (void)strcpy(value, p+1);
+       return vms_define(name, value, ENV_USR);
+    } else
+       return 1;       /* failure */
+}
+
+/*
+   Support for VT420 was added to VMS in version V5.4, but as of V5.5-2
+   VAXCRTL still doesn't handle it and puts TERM=undefined into the
+   environ[] array.  getenv("TERM") will return "undefined" instead of
+   something sensible.  Even though that's finally fixed in V6.0, site
+   defined terminals also return "undefined" so query SMG's TERMTABLE
+   instead of just checking VMS's device-type value for VT400_Series.
+
+   Called by verify_termcap() for convenience.
+ */
+static
+char *verify_term()
+{
+    char      *term = getenv("NETHACK_TERM");
+    if (!term) term = getenv("HACK_TERM");
+    if (!term) term = getenv("EMACS_TERM");
+    if (!term) term = getenv("TERM");
+    if (!term || !*term
+       || !strcmpi(term, "undefined") || !strcmpi(term, "unknown")) {
+       static char smgdevtyp[31+1];    /* size is somewhat arbitrary */
+       static char dev_tty[] = "TT:";
+       static $DESCRIPTOR(smgdsc, smgdevtyp);
+       static $DESCRIPTOR(tt, dev_tty);
+       unsigned short dvicode = DVI$_DEVTYPE;
+       unsigned long devtype = 0L, termtab = 0L;
+
+       (void)lib$getdvi(&dvicode, (unsigned short *)0, &tt, &devtype,
+                        (genericptr_t)0, (unsigned short *)0);
+
+       if (devtype &&
+           vms_ok(smg$init_term_table_by_type(&devtype, &termtab, &smgdsc))) {
+           register char *p = &smgdevtyp[smgdsc.dsc$w_length];
+           /* strip trailing blanks */
+           while (p > smgdevtyp && *--p == ' ') *p = '\0';
+           /* (void)smg$del_term_table(); */
+           term = smgdevtyp;
+       }
+    }
+    return term;
+}
+
+/*
+   Figure out whether the termcap code will find a termcap file; if not,
+   try to help it out.  This avoids modifying the GNU termcap sources and
+   can simplify configuration for sites which don't already use termcap.
+ */
+#define GNU_DEFAULT_TERMCAP "emacs_library:[etc]termcap.dat"
+#define NETHACK_DEF_TERMCAP "nethackdir:termcap"
+#define HACK_DEF_TERMCAP    "hackdir:termcap"
+
+char *
+verify_termcap()       /* called from startup(src/termcap.c) */
+{
+    struct stat dummy;
+    const char *tc = getenv("TERMCAP");
+    if (tc) return verify_term();      /* no termcap fixups needed */
+    if (!tc && !stat(NETHACK_DEF_TERMCAP, &dummy)) tc = NETHACK_DEF_TERMCAP;
+    if (!tc && !stat(HACK_DEF_TERMCAP, &dummy))    tc = HACK_DEF_TERMCAP;
+    if (!tc && !stat(GNU_DEFAULT_TERMCAP, &dummy)) tc = GNU_DEFAULT_TERMCAP;
+    if (!tc && !stat("[]termcap", &dummy)) tc = "[]termcap"; /* current dir */
+    if (!tc && !stat("$TERMCAP", &dummy))  tc = "$TERMCAP";  /* alt environ */
+    if (tc) {
+       /* putenv(strcat(strcpy(buffer,"TERMCAP="),tc)); */
+       vms_define("TERMCAP", tc, ENV_USR);
+    } else {
+       /* perhaps someday we'll construct a termcap entry string */
+    }
+    return verify_term();
+}
+/*------*/
+
+#ifdef SHELL
+# ifndef CLI$M_NOWAIT
+#  define CLI$M_NOWAIT 1
+# endif
+#endif
+
+#if defined(CHDIR) || defined(SHELL) || defined(SECURE)
+static unsigned long oprv[2];
+
+void
+privoff()
+{
+       unsigned long pid = 0, prv[2] = { ~0, ~0 };
+       unsigned short code = JPI$_PROCPRIV;
+
+       (void) sys$setprv(0, prv, 0, oprv);
+       (void) lib$getjpi(&code, &pid, (genericptr_t)0, prv);
+       (void) sys$setprv(1, prv, 0, (unsigned long *)0);
+}
+
+void
+privon()
+{
+       (void) sys$setprv(1, oprv, 0, (unsigned long *)0);
+}
+#endif /* CHDIR || SHELL || SECURE */
+
+#if defined(SHELL) || defined(SUSPEND)
+static void
+hack_escape(screen_manip, msg_str)
+boolean screen_manip;
+const char *msg_str;
+{
+       if (screen_manip)
+           suspend_nhwindows(msg_str); /* clear screen, reset terminal, &c */
+       (void) signal(SIGQUIT,SIG_IGN); /* ignore ^Y */
+       (void) signal(SIGINT,SIG_DFL);  /* don't trap ^C (implct cnvrs to ^Y) */
+}
+
+static void
+hack_resume(screen_manip)
+boolean screen_manip;
+{
+       (void) signal(SIGINT, (SIG_RET_TYPE) done1);
+# ifdef WIZARD
+       if (wizard) (void) signal(SIGQUIT,SIG_DFL);
+# endif
+       if (screen_manip)
+           resume_nhwindows(); /* setup terminal modes, redraw screen, &c */
+}
+#endif /* SHELL || SUSPEND */
+
+#ifdef SHELL
+unsigned long dosh_pid = 0,    /* this should cover any interactive escape */
+       mail_pid = 0;   /* this only covers the last mail or phone; */
+/*(mail & phone commands aren't expected to leave any process hanging around)*/
+
+int dosh()
+{
+       return vms_doshell("", TRUE);   /* call for interactive child process */
+}
+
+/* vms_doshell -- called by dosh() and readmail() */
+
+/* If execstring is not a null string, then it will be executed in a spawned */
+/* subprocess, which will then return.  It is for handling mail or phone     */
+/* interactive commands, which are only available if both MAIL and SHELL are */
+/* #defined, but we don't bother making the support code conditionalized on  */
+/* MAIL here, just on SHELL being enabled.                                  */
+
+/* Normally, all output from this interaction will be 'piped' to the user's  */
+/* screen (SYS$OUTPUT).  However, if 'screenoutput' is set to FALSE, output  */
+/* will be piped into oblivion.  Used for silent phone call rejection.      */
+
+int
+vms_doshell(execstring, screenoutput)
+const char *execstring;
+boolean screenoutput;
+{
+       unsigned long status, new_pid, spawnflags = 0;
+       struct dsc$descriptor_s comstring, *command, *inoutfile = 0;
+       static char dev_null[] = "_NLA0:";
+       static $DESCRIPTOR(nulldevice, dev_null);
+
+       /* Is this an interactive shell spawn, or do we have a command to do? */
+       if (execstring && *execstring) {
+               comstring.dsc$w_length = strlen(execstring);
+               comstring.dsc$b_dtype = DSC$K_DTYPE_T;
+               comstring.dsc$b_class = DSC$K_CLASS_S;
+               comstring.dsc$a_pointer = (char *)execstring;
+               command = &comstring;
+       } else
+               command = 0;
+
+       /* use asynch subprocess and suppress output iff one-shot command */
+       if (!screenoutput) {
+               spawnflags = CLI$M_NOWAIT;
+               inoutfile = &nulldevice;
+       }
+
+       hack_escape(screenoutput, command ? (const char *) 0 :
+     "  \"Escaping\" into a subprocess; LOGOUT to reconnect and resume play. ");
+
+       if (command || !dosh_pid || !vms_ok(status = lib$attach(&dosh_pid))) {
+# ifdef CHDIR
+               (void) chdir(getenv("PATH"));
+# endif
+               privoff();
+               new_pid = 0;
+               status = lib$spawn(command, inoutfile, inoutfile, &spawnflags,
+                                  (struct dsc$descriptor_s *) 0, &new_pid);
+               if (!command) dosh_pid = new_pid; else mail_pid = new_pid;
+               privon();
+# ifdef CHDIR
+               chdirx((char *) 0, 0);
+# endif
+       }
+
+       hack_resume(screenoutput);
+
+       if (!vms_ok(status)) {
+               pline("  Spawn failed.  (%%x%08lX) ", status);
+               mark_synch();
+       }
+       return 0;
+}
+#endif /* SHELL */
+
+#ifdef SUSPEND
+/* dosuspend() -- if we're a subprocess, attach to our parent;
+ *             if not, there's nothing we can do.
+ */
+int
+dosuspend()
+{
+       static long owner_pid = -1;
+       unsigned long status;
+
+       if (owner_pid == -1)    /* need to check for parent */
+               owner_pid = getppid();
+       if (owner_pid == 0) {
+               pline(
+     "  No parent process.  Use '!' to Spawn, 'S' to Save,  or 'Q' to Quit. ");
+               mark_synch();
+               return 0;
+       }
+
+       /* restore normal tty environment & clear screen */
+       hack_escape(1,
+     " Attaching to parent process; use the ATTACH command to resume play. ");
+
+       status = lib$attach(&owner_pid);        /* connect to parent */
+
+       hack_resume(1); /* resume game tty environment & refresh screen */
+
+       if (!vms_ok(status)) {
+               pline("  Unable to attach to parent.  (%%x%08lX) ", status);
+               mark_synch();
+       }
+       return 0;
+}
+#endif /* SUSPEND */
+
+/*vmsunix.c*/
diff --git a/sys/wince/Install.ce b/sys/wince/Install.ce
new file mode 100644 (file)
index 0000000..206e810
--- /dev/null
@@ -0,0 +1,136 @@
+Copyright (c) Alex Kompel, 2002
+NetHack may be freely redistributed.  See license for details.
+========================================================================
+                 Instructions for compiling and installing
+             NetHack 3.4.3 on a Windows CE or PocketPC system
+========================================================================
+                     Last revision: $Date: 2003/10/14 01:31:21 $
+
+Credit for the porting of NetHack to Windows CE goes to Alex Kompel who 
+initially developed and contributed the port.
+
+In order to build NetHack for Windows CE, you need *both* of the following:
+
+  o A copy of Microsoft Visual C V6.0 SP3 or later.  Things may work with 
+    an earlier version of the compiler, but the current code has not been
+    tested with an earlier version.
+  o Embedded Visual C++ 3.0 or later
+
+
+FIRST STEP:
+
+The first step in building NetHack for Windows CE is to execute
+sys/wince/cesetup.bat.
+
+From the command prompt:
+       cd sys\wince
+       cesetup
+
+From a Windows explorer window:
+       double-click on cesetup.bat
+
+A "wince" directory will be created off the top of the NetHack source
+tree, and a Microsoft embedded C workspace file will be placed in the
+top of the NetHack source tree. 
+
+------------
+| BUILDING |
+------------
+
+Boostrapping the build process on Windows NT/2000/XP
+
+1. With the Visual C++ 6.0 tools in your path,
+   Run "nmake /f bootstrp.mak" from the wince folder.
+
+Compiling
+
+2. Start the Embedded Visual C IDE. In the Embedded Visual C IDE 
+       Menus, choose:
+           File | Open Workspace
+
+3.  Set up for the build.
+
+        o In the Visual C "Open Workspace" dialog box, navigate to the top
+            of  your NetHack source directory tree.
+            In there, highlight "wince.vcw" and click on Open.
+            Once the workspace has been opened, you should see the following
+            list in the Visual C selection window:
+              + nethack_hpc files
+              + nethack_palm_pc files
+              + nethack_pocket_pc files
+              + nethack_smartphone files
+
+        o On the Embedded Visual C menus, choose:
+              Build | Set Active Platform
+               Select the platform that corresponds to your device:
+               Palm-size PC 2.11  - palm size PC running Windows CE version 2.11
+               Pocket PC          - palm-size PC running Windows CE 3.0 and higher (PocketPC)
+               H/PC Pro 2.11      - handheld computers running Windows CE 2.11 anf higher
+               Smartphone 2002  - Microsoft SmartPhone device
+
+        o On the Visual C menus again, choose either:
+              Build | Set Active Configuration 
+                where configuration is one of the following (make sure it matches the platform 
+                you have selected):
+               nethack_hpc - Win32 (WCE MIPS) HPCRelease  - H/PC Pro 2.11 MIPS processor release executable
+               nethack_hpc - Win32 (WCE x86em) HPCDebug   - H/PC Pro 2.11 x86 emulation debug executable
+               nethack_hpc - Win32 (WCE ARM) HPCRelease   - H/PC Pro 2.11 ARM processor release executable
+               nethack_hpc - Win32 (WCE SH3) HPCRelease   - H/PC Pro 2.11 SH3 processor release executable
+               nethack_hpc - Win32 (WCE x86em) HPCRelease - H/PC Pro 2.11 x86 emulation release executable
+               nethack_hpc - Win32 (WCE SH4) HPCRelease   - H/PC Pro 2.11 SH4 processor release executable
+               nethack_palm_pc - Win32 (WCE MIPS) PalmPCRelease  - Palm-size PC 2.11 MIPS processor release executable
+               nethack_palm_pc - Win32 (WCE x86em) PalmPCDebug   - Palm-size PC 2.11 x86 emulation debug executable
+               nethack_palm_pc - Win32 (WCE SH3) PalmPCRelease   - Palm-size PC 2.11 SH3 processor release executable
+               nethack_palm_pc - Win32 (WCE x86em) PalmPCRelease - Palm-size PC 2.11 x86 emulation release executable
+               nethack_pocket_pc - Win32 (WCE MIPS) PocketPCRelease  - Pocket PC MIPS processor release executable
+               nethack_pocket_pc - Win32 (WCE ARM) PocketPCRelease   - Pocket PC ARM processor release executable
+               nethack_pocket_pc - Win32 (WCE x86em) PocketPCRelease - Pocket PC x86 emulation release executable
+               nethack_pocket_pc - Win32 (WCE x86em) PocketPCDebug   - Pocket PC x86 emulation debug executable
+               nethack_pocket_pc - Win32 (WCE SH3) PocketPCRelease   - Pocket PC SH3 processor release executable
+               nethack_smartphone - Win32 (WCE ARM) SPhoneRelease   - Smartphone 2002 ARM processor release executable
+               nethack_smartphone - Win32 (WCE x86em) SPhoneDebug   - Smartphone 2002 x86 emulation debug executable
+
+Building
+    
+4.  Start your build.
+        o On the Embedded Visual C menus once again, choose:
+              Build | Build nethackm.exe
+          This starts the build.  It is likely that the IDE message window 
+          where you are doing the compiling will be occupied for a while.
+    Notes: 
+
+        o You may get a bunch of warnings regarding missing include files in the 
+          beginning of the build process - ignore them. For some reason the tool 
+          that produces these messages ignores preprocessor directives. The actual 
+          build will go just fine.
+        o Sometimes the compiler chokes on do_wear.c  Ignore that - let the build 
+          finish. Then run it again - it will compile just fine. (Seems to be some 
+          sort of bug in EVC++) 
+
+Transfer
+
+5.  Transfer the files and executables to your handheld by extracting the
+    files into some folder on the CE device - that should do it. 
+
+
+Notes
+
+    If you want to use IBMGraphics make sure that you have a proper 
+    font installed on the device that supports OEM character set 
+    (for example, Lucida Console)
+
+
+PROBLEMS
+
+
+    If you discover a bug and wish to report it, or if you have comments
+    or suggestions we recommend using our "Contact Us" web page at:
+        http://www.nethack.org/common/contact.html
+
+    If you don't have access to the web, or you want to send us a patch
+    to the NetHack source code feel free to drop us a line c/o:
+        DevTeam (at) nethack.org
+
+    Happy NetHacking!
diff --git a/sys/wince/bootstrp.mak b/sys/wince/bootstrp.mak
new file mode 100644 (file)
index 0000000..f04eac2
--- /dev/null
@@ -0,0 +1,882 @@
+#       SCCS Id: @(#)bootstrp.mak       3.4     2002/03/24
+#       Copyright (c) Michael Allison
+#
+#       NetHack Windows CE bootstrap file for MS Visual C++ V6.x and 
+#       above and MS NMAKE
+#
+#       This will:
+#         - build makedefs
+#         - 
+#==============================================================================
+# Do not delete the following 3 lines.
+#
+TARGETOS=BOTH
+APPVER=4.0
+!include <win32.mak>
+
+#
+#  Source directories.    Makedefs hardcodes these, don't change them.
+#
+
+INCL  = ..\include   # NetHack include files
+DAT   = ..\dat       # NetHack data files
+DOC   = ..\doc       # NetHack documentation files
+UTIL  = ..\util      # Utility source
+SRC   = ..\src       # Main source
+SSYS  = ..\sys\share # Shared system files
+NTSYS = ..\sys\winnt # NT Win32 specific files
+TTY   = ..\win\tty   # window port files (tty)
+WIN32 = ..\win\win32 # window port files (WINCE)
+WSHR  = ..\win\share # Tile support files 
+SWINCE= ..\wince          # wince files
+WINCE = ..\wince     # wince build area
+OBJ   = $(WINCE)\ceobj
+DLB = $(DAT)\nhdat
+
+#==========================================
+# Setting up the compiler and linker
+# macros. All builds include the base ones.
+#==========================================
+
+CFLAGSBASE  = -c $(cflags) $(cvarsmt) -I$(INCL) -nologo $(cdebug) $(WINPINC) -DDLB
+LFLAGSBASEC = $(linkdebug) /NODEFAULTLIB /INCREMENTAL:NO /RELEASE /NOLOGO -subsystem:console,4.0 $(conlibsmt)
+LFLAGSBASEG = $(linkdebug) $(guiflags) $(guilibsmt) comctl32.lib
+
+#==========================================
+# Util builds
+#==========================================
+
+CFLAGSU = $(CFLAGSBASE) $(WINPFLAG)
+LFLAGSU        = $(LFLAGSBASEC)
+
+LEVCFLAGS= -c -nologo -DWINVER=0x0400 -DWIN32 -D_WIN32 \
+          -D_MT -MT -I..\include -nologo -Z7 -Od -DDLB
+
+
+#==========================================
+#================ RULES ==================
+#==========================================
+
+.SUFFIXES: .exe .o .til .uu .c .y .l
+
+#==========================================
+# Rules for files in src
+#==========================================
+
+#.c{$(OBJ)}.o:
+#      $(cc) $(CFLAGSU)  -Fo$@ $<
+
+{$(SRC)}.c{$(OBJ)}.o:
+       $(CC) $(CFLAGSU)   -Fo$@  $<
+
+#==========================================
+# Rules for files in sys\share
+#==========================================
+
+{$(SSYS)}.c{$(OBJ)}.o:
+       $(CC) $(CFLAGSU)  -Fo$@  $<
+
+#==========================================
+# Rules for files in sys\winnt
+#==========================================
+
+{$(NTSYS)}.c{$(OBJ)}.o:
+       $(CC) $(CFLAGSU)  -Fo$@  $<
+
+{$(NTSYS)}.h{$(INCL)}.h:
+       copy $< $@
+
+#==========================================
+# Rules for files in util
+#==========================================
+
+{$(UTIL)}.c{$(OBJ)}.o:
+       $(CC) $(CFLAGSU) -Fo$@ $<
+
+#==========================================
+# Rules for files in win\share
+#==========================================
+
+{$(WSHR)}.c{$(OBJ)}.o:
+       $(CC) $(CFLAGSU)  -Fo$@ $<
+
+{$(WSHR)}.h{$(INCL)}.h:
+       copy $< $@
+
+#{$(WSHR)}.txt{$(DAT)}.txt:
+#      copy $< $@
+
+#==========================================
+# Rules for files in win\tty
+#==========================================
+
+{$(TTY)}.c{$(OBJ)}.o:
+       $(CC) $(CFLAGSU)  -Fo$@  $<
+
+
+#==========================================
+# Rules for files in win\win32
+#==========================================
+
+{$(WIN32)}.c{$(OBJ)}.o:
+       $(cc) $(CFLAGSU)  -Fo$@  $<
+
+#==========================================
+# Rules for files in sys\wince
+#==========================================
+
+{$(SWINCE)}.c{$(OBJ)}.o:
+       $(cc) $(CFLAGSU)  -Fo$@  $<
+
+#==========================================
+#================ MACROS ==================
+#==========================================
+
+#
+# Shorten up the location for some files
+#
+
+O  = $(OBJ)^\
+
+U  = $(UTIL)^\
+
+#
+# Utility Objects.
+#
+
+MAKESRC        = $(U)makedefs.c
+
+SPLEVSRC       = $(U)lev_yacc.c        $(U)lev_$(LEX).c $(U)lev_main.c  $(U)panic.c
+
+DGNCOMPSRC     = $(U)dgn_yacc.c        $(U)dgn_$(LEX).c $(U)dgn_main.c
+
+MAKEOBJS       = $(O)makedefs.o $(O)monst.o $(O)objects.o
+
+SPLEVOBJS      = $(O)lev_yacc.o        $(O)lev_$(LEX).o $(O)lev_main.o \
+                $(O)alloc.o    $(O)decl.o      $(O)drawing.o \
+                $(O)monst.o    $(O)objects.o   $(O)panic.o
+
+DGNCOMPOBJS    = $(O)dgn_yacc.o        $(O)dgn_$(LEX).o $(O)dgn_main.o \
+                $(O)alloc.o    $(O)panic.o
+
+TILEFILES      = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt
+
+#
+# These are not invoked during a normal game build in 3.4.0
+#
+TEXT_IO        = $(O)tiletext.o        $(O)tiletxt.o   $(O)drawing.o \
+                $(O)decl.o     $(O)monst.o     $(O)objects.o
+
+TEXT_IO32      = $(O)tilete32.o $(O)tiletx32.o $(O)drawing.o \
+                $(O)decl.o     $(O)monst.o     $(O)objects.o
+
+GIFREADERS     = $(O)gifread.o $(O)alloc.o $(O)panic.o
+GIFREADERS32   = $(O)gifrd32.o $(O)alloc.o $(O)panic.o
+
+PPMWRITERS     = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o
+
+DLBOBJ = $(O)dlb.o
+
+#==========================================
+# Header file macros
+#==========================================
+
+CONFIG_H = $(INCL)\config.h $(INCL)\config1.h $(INCL)\tradstdc.h \
+               $(INCL)\global.h $(INCL)\coord.h $(INCL)\vmsconf.h \
+               $(INCL)\system.h $(INCL)\unixconf.h $(INCL)\os2conf.h \
+               $(INCL)\micro.h $(INCL)\pcconf.h $(INCL)\tosconf.h \
+               $(INCL)\amiconf.h $(INCL)\macconf.h $(INCL)\beconf.h \
+               $(INCL)\ntconf.h $(INCL)\nhlan.h $(INCL)\wceconf.h
+
+HACK_H = $(INCL)\hack.h $(CONFIG_H) $(INCL)\align.h \
+               $(INCL)\dungeon.h $(INCL)\monsym.h $(INCL)\mkroom.h \
+               $(INCL)\objclass.h $(INCL)\youprop.h $(INCL)\prop.h \
+               $(INCL)\permonst.h $(INCL)\monattk.h \
+               $(INCL)\monflag.h $(INCL)\mondata.h $(INCL)\pm.h \
+               $(INCL)\wintype.h $(INCL)\decl.h $(INCL)\quest.h \
+               $(INCL)\spell.h $(INCL)\color.h $(INCL)\obj.h \
+               $(INCL)\you.h $(INCL)\attrib.h $(INCL)\monst.h \
+               $(INCL)\skills.h $(INCL)\onames.h $(INCL)\timeout.h \
+               $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \
+               $(INCL)\vision.h $(INCL)\display.h $(INCL)\engrave.h \
+               $(INCL)\rect.h $(INCL)\region.h $(INCL)\winprocs.h \
+               $(INCL)\wintty.h $(INCL)\trampoli.h
+
+LEV_H       = $(INCL)\lev.h
+DGN_FILE_H  = $(INCL)\dgn_file.h
+LEV_COMP_H  = $(INCL)\lev_comp.h
+SP_LEV_H    = $(INCL)\sp_lev.h
+TILE_H      = ..\win\share\tile.h
+
+#==========================================
+# Miscellaneous
+#==========================================
+
+DATABASE = $(DAT)\data.base
+
+#==========================================
+#=============== TARGETS ==================
+#==========================================
+
+#
+#  The default make target (so just typing 'nmake' is useful).
+#
+default : all
+
+#
+#  Everything
+#
+
+all :  $(INCL)\date.h  $(INCL)\onames.h $(INCL)\pm.h \
+       $(SRC)\monstr.c $(SRC)\vis_tab.c $(U)lev_comp.exe $(INCL)\vis_tab.h \
+       $(U)dgn_comp.exe $(U)uudecode.exe \
+       $(DAT)\data     $(DAT)\rumors    $(DAT)\dungeon \
+       $(DAT)\oracles  $(DAT)\quest.dat $(O)sp_lev.tag $(DLB) $(SRC)\tile.c \
+       $(SWINCE)\nethack.ico $(SWINCE)\tiles.bmp $(SWINCE)\mnsel.bmp \
+       $(SWINCE)\mnunsel.bmp $(SWINCE)\petmark.bmp $(SWINCE)\mnselcnt.bmp \
+       $(SWINCE)\keypad.bmp $(SWINCE)\menubar.bmp
+       @echo Done!
+
+$(O)sp_lev.tag:  $(DAT)\bigroom.des  $(DAT)\castle.des \
+       $(DAT)\endgame.des $(DAT)\gehennom.des $(DAT)\knox.des   \
+       $(DAT)\medusa.des  $(DAT)\oracle.des   $(DAT)\tower.des  \
+       $(DAT)\yendor.des  $(DAT)\arch.des     $(DAT)\barb.des   \
+       $(DAT)\caveman.des $(DAT)\healer.des   $(DAT)\knight.des \
+       $(DAT)\monk.des    $(DAT)\priest.des   $(DAT)\ranger.des \
+       $(DAT)\rogue.des   $(DAT)\samurai.des  $(DAT)\sokoban.des \
+       $(DAT)\tourist.des $(DAT)\valkyrie.des $(DAT)\wizard.des
+       cd $(DAT)
+       $(U)lev_comp bigroom.des
+       $(U)lev_comp castle.des
+       $(U)lev_comp endgame.des
+       $(U)lev_comp gehennom.des
+       $(U)lev_comp knox.des
+       $(U)lev_comp mines.des
+       $(U)lev_comp medusa.des
+       $(U)lev_comp oracle.des
+       $(U)lev_comp sokoban.des
+       $(U)lev_comp tower.des
+       $(U)lev_comp yendor.des
+       $(U)lev_comp arch.des
+       $(U)lev_comp barb.des
+       $(U)lev_comp caveman.des
+       $(U)lev_comp healer.des
+       $(U)lev_comp knight.des
+       $(U)lev_comp monk.des
+       $(U)lev_comp priest.des
+       $(U)lev_comp ranger.des
+       $(U)lev_comp rogue.des
+       $(U)lev_comp samurai.des
+       $(U)lev_comp tourist.des
+       $(U)lev_comp valkyrie.des
+       $(U)lev_comp wizard.des
+       cd $(WINCE)
+       echo sp_levs done > $(O)sp_lev.tag
+
+#$(NHRES): $(TILEBMP16) $(WINCE)\winhack.rc $(WINCE)\mnsel.bmp \
+#      $(WINCE)\mnselcnt.bmp $(WINCE)\mnunsel.bmp \
+#      $(WINCE)\petmark.bmp $(WINCE)\NetHack.ico $(WINCE)\rip.bmp \
+#      $(WINCE)\splash.bmp
+#      $(rc) -r -fo$@ -i$(WINCE) -dNDEBUG $(WINCE)\winhack.rc
+
+#
+#  Utility Targets.
+#
+    
+#==========================================
+# Makedefs Stuff
+#==========================================
+
+$(U)makedefs.exe:      $(MAKEOBJS)
+       $(link) $(LFLAGSU) -out:$@ $(MAKEOBJS)
+
+$(O)makedefs.o: $(CONFIG_H)    $(INCL)\monattk.h $(INCL)\monflag.h   $(INCL)\objclass.h \
+                $(INCL)\monsym.h    $(INCL)\qtext.h    $(INCL)\patchlevel.h \
+                $(U)makedefs.c
+       if not exist $(OBJ)\*.* echo creating directory $(OBJ)
+       if not exist $(OBJ)\*.* mkdir $(OBJ)
+       $(CC) $(CFLAGSU) -Fo$@ $(U)makedefs.c
+
+#
+#  date.h should be remade every time any of the source or include
+#  files is modified.
+#
+
+$(INCL)\date.h $(OPTIONS_FILE) : $(U)makedefs.exe
+       $(U)makedefs -v
+
+$(INCL)\onames.h : $(U)makedefs.exe
+       $(U)makedefs -o
+
+$(INCL)\pm.h : $(U)makedefs.exe
+       $(U)makedefs -p
+
+#$(INCL)\trap.h : $(U)makedefs.exe
+#      $(U)makedefs -t
+
+$(SRC)\monstr.c: $(U)makedefs.exe
+       $(U)makedefs -m
+
+$(INCL)\vis_tab.h: $(U)makedefs.exe
+       $(U)makedefs -z
+
+$(SRC)\vis_tab.c: $(U)makedefs.exe
+       $(U)makedefs -z
+
+#==========================================
+# uudecode utility and uuencoded targets
+#==========================================
+
+$(U)uudecode.exe: $(O)uudecode.o
+       $(link) $(LFLAGSU) -out:$@ $(O)uudecode.o
+
+$(O)uudecode.o: $(SSYS)\uudecode.c
+
+$(SWINCE)\NetHack.ico : $(U)uudecode.exe $(SWINCE)\nhico.uu 
+       chdir $(SWINCE)
+       ..\util\uudecode.exe nhico.uu
+       chdir $(WINCE)
+
+$(SWINCE)\mnsel.bmp: $(U)uudecode.exe $(SWINCE)\mnsel.uu
+       chdir $(SWINCE)
+       ..\util\uudecode.exe mnsel.uu
+       chdir $(WINCE)
+
+$(SWINCE)\mnselcnt.bmp: $(U)uudecode.exe $(SWINCE)\mnselcnt.uu
+       chdir $(SWINCE)
+       ..\util\uudecode.exe mnselcnt.uu
+       chdir $(WINCE)
+
+$(SWINCE)\mnunsel.bmp: $(U)uudecode.exe $(SWINCE)\mnunsel.uu
+       chdir $(SWINCE)
+       ..\util\uudecode.exe mnunsel.uu
+       chdir $(WINCE)
+
+$(SWINCE)\petmark.bmp: $(U)uudecode.exe $(SWINCE)\petmark.uu
+       chdir $(SWINCE)
+       ..\util\uudecode.exe petmark.uu
+       chdir $(WINCE)
+
+$(SWINCE)\rip.bmp: $(U)uudecode.exe $(SWINCE)\rip.uu
+       chdir $(SWINCE)
+       ..\util\uudecode.exe rip.uu
+       chdir $(WINCE)
+
+$(SWINCE)\splash.bmp: $(U)uudecode.exe $(SWINCE)\splash.uu
+       chdir $(SWINCE)
+       ..\util\uudecode.exe splash.uu
+       chdir $(WINCE)
+
+$(SWINCE)\keypad.bmp: $(U)uudecode.exe $(SWINCE)\keypad.uu
+       chdir $(SWINCE)
+       ..\util\uudecode.exe keypad.uu
+       chdir $(WINCE)
+
+$(SWINCE)\menubar.bmp: $(U)uudecode.exe $(SWINCE)\menubar.uu
+       chdir $(SWINCE)
+       ..\util\uudecode.exe menubar.uu
+       chdir $(WINCE)
+
+#==========================================
+# Level Compiler Stuff
+#==========================================
+
+$(U)lev_comp.exe: $(SPLEVOBJS)
+       echo Linking $@...
+       $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(SPLEVOBJS:^   =^
+               )
+<<
+
+$(O)lev_yacc.o: $(HACK_H)   $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c
+       $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_yacc.c
+
+$(O)lev_$(LEX).o: $(HACK_H)   $(INCL)\lev_comp.h $(SP_LEV_H) \
+               $(U)lev_$(LEX).c
+       $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_$(LEX).c
+
+$(O)lev_main.o:        $(U)lev_main.c $(HACK_H)   $(SP_LEV_H)
+       $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_main.c
+
+
+$(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y
+          @echo We will copy the prebuilt lev_yacc.c and 
+          @echo lev_comp.h from $(SSYS) into $(UTIL) and use them.
+          @copy $(SSYS)\lev_yacc.c $(U)lev_yacc.c >nul
+          @copy $(SSYS)\lev_comp.h $(INCL)\lev_comp.h >nul
+          @echo /**/ >>$(U)lev_yacc.c
+          @echo /**/ >>$(INCL)\lev_comp.h
+
+$(U)lev_$(LEX).c: $(U)lev_comp.l
+          @echo We will copy the prebuilt lev_lex.c 
+          @echo from $(SSYS) into $(UTIL) and use it.
+          @copy $(SSYS)\lev_lex.c $@ >nul
+          @echo /**/ >>$@
+
+#==========================================
+# Dungeon Compiler Stuff
+#==========================================
+
+$(U)dgn_comp.exe: $(DGNCOMPOBJS)
+    @echo Linking $@...
+       $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(DGNCOMPOBJS:^ =^
+               )
+<<
+
+$(O)dgn_yacc.o:        $(HACK_H)   $(DGN_FILE_H) $(INCL)\dgn_comp.h $(U)dgn_yacc.c
+       $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_yacc.c
+
+$(O)dgn_$(LEX).o: $(HACK_H)   $(DGN_FILE_H)  $(INCL)\dgn_comp.h \
+       $(U)dgn_$(LEX).c
+       $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_$(LEX).c
+
+$(O)dgn_main.o:        $(HACK_H) $(U)dgn_main.c
+       $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_main.c
+
+$(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y
+          @echo We will copy the prebuilt $(U)dgn_yacc.c and 
+          @echo dgn_comp.h from $(SSYS) into $(UTIL) and use them.
+          @copy $(SSYS)\dgn_yacc.c $(U)dgn_yacc.c >nul
+          @copy $(SSYS)\dgn_comp.h $(INCL)\dgn_comp.h >nul
+          @echo /**/ >>$(U)dgn_yacc.c
+          @echo /**/ >>$(INCL)\dgn_comp.h
+
+$(U)dgn_$(LEX).c: $(U)dgn_comp.l
+          @echo We will copy the prebuilt dgn_lex.c 
+          @echo from $(SSYS) into $(UTIL) and use it.
+          @copy $(SSYS)\dgn_lex.c $@ >nul
+          @echo /**/ >>$@
+
+#==========================================
+# Create directory for holding object files
+#==========================================
+
+$(O)obj.tag:
+       if not exist $(OBJ)\*.* echo creating directory $(OBJ)
+       if not exist $(OBJ)\*.* mkdir $(OBJ)
+       echo directory created >$@
+
+#==========================================
+# Notify of any CL environment variables
+# in effect since they change the compiler
+# options.
+#==========================================
+
+envchk:
+!      IF "$(CL)"!=""
+          @echo Warning, the CL Environment variable is defined:
+          @echo CL=$(CL)
+!      ENDIF
+          @echo ----
+          @echo NOTE: This build will include tile support.
+          @echo ----
+
+#==========================================
+#=========== SECONDARY TARGETS ============
+#==========================================
+
+#===========================================
+# Header files NOT distributed in ..\include
+#===========================================
+
+$(INCL)\win32api.h: $(NTSYS)\win32api.h
+       copy $(NTSYS)\win32api.h $@
+
+
+#==========================================
+# DLB utility and nhdat file creation
+#==========================================
+
+$(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o
+       $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(O)dlb_main.o
+               $(O)dlb.o
+               $(O)alloc.o
+               $(O)panic.o
+<<
+
+$(O)dlb.o:     $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)\dlb.h
+       $(CC) $(CFLAGSU) /Fo$@ $(SRC)\dlb.c
+       
+$(O)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h
+       $(CC) $(CFLAGSU) /Fo$@ $(UTIL)\dlb_main.c
+
+#$(DAT)\porthelp: $(NTSYS)\porthelp
+#      copy $(NTSYS)\porthelp $@ >nul
+
+$(DAT)\nhdat:  $(U)dlb_main.exe $(DAT)\data $(DAT)\oracles $(OPTIONS_FILE) \
+       $(DAT)\quest.dat $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp \
+       $(DAT)\history $(DAT)\opthelp $(DAT)\wizhelp $(DAT)\dungeon  \
+       $(DAT)\license $(O)sp_lev.tag
+       cd $(DAT)
+       echo data >dlb.lst
+       echo oracles >>dlb.lst
+       if exist options echo options >>dlb.lst
+       if exist ttyoptions echo ttyoptions >>dlb.lst
+       if exist guioptions echo guioptions >>dlb.lst
+       if exist porthelp echo porthelp >>dlb.lst
+       echo quest.dat >>dlb.lst
+       echo rumors >>dlb.lst
+       echo help >>dlb.lst
+       echo hh >>dlb.lst
+       echo cmdhelp >>dlb.lst
+       echo history >>dlb.lst
+       echo opthelp >>dlb.lst
+       echo wizhelp >>dlb.lst
+       echo dungeon >>dlb.lst
+       echo license >>dlb.lst
+       for %%N in (*.lev) do echo %%N >>dlb.lst
+       $(U)dlb_main cIf dlb.lst nhdat
+       cd $(WINCE)
+
+#==========================================
+#  Tile Mapping
+#==========================================
+
+$(SRC)\tile.c: $(U)tilemap.exe
+       echo A new $@ has been created
+       $(U)tilemap
+
+$(U)tilemap.exe: $(O)tilemap.o
+       $(link) $(LFLAGSU) -out:$@ $(O)tilemap.o
+
+$(O)tilemap.o: $(WSHR)\tilemap.c $(HACK_H)
+       $(CC) $(CFLAGSU) -Fo$@ $(WSHR)\tilemap.c
+
+$(O)tiletx32.o: $(WSHR)\tilemap.c $(HACK_H)
+       $(CC) $(CFLAGSU) /DTILETEXT /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tilemap.c
+
+$(O)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H)
+       $(CC) $(CFLAGSU) /DTILETEXT -Fo$@ $(WSHR)\tilemap.c
+
+$(O)gifread.o: $(WSHR)\gifread.c  $(CONFIG_H) $(TILE_H)
+       $(CC) $(CFLAGSU) -I$(WSHR) -Fo$@ $(WSHR)\gifread.c
+
+$(O)gifrd32.o: $(WSHR)\gifread.c  $(CONFIG_H) $(TILE_H)
+       $(CC) $(CFLAGSU) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\gifread.c
+
+$(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(TILE_H)
+       $(CC) $(CFLAGSU) -I$(WSHR) -Fo$@ $(WSHR)\ppmwrite.c
+
+$(O)tiletext.o: $(WSHR)\tiletext.c  $(CONFIG_H) $(TILE_H)
+       $(CC) $(CFLAGSU) -I$(WSHR) -Fo$@ $(WSHR)\tiletext.c
+
+$(O)tilete32.o: $(WSHR)\tiletext.c  $(CONFIG_H) $(TILE_H)
+       $(CC) $(CFLAGSU) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tiletext.c
+
+$(SWINCE)\tiles.bmp: $(U)tile2bmp.exe $(TILEFILES)
+       echo Creating 16x16 binary tile files (this may take some time)
+       $(U)tile2bmp $@
+
+#$(TILEBMP32): $(TILEUTIL32) $(TILEFILES32)
+#      echo Creating 32x32 binary tile files (this may take some time)
+#      $(U)til2bm32 $(TILEBMP32)
+
+
+$(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO)
+    @echo Linking $@...
+       $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(O)tile2bmp.o
+               $(TEXT_IO:^  =^
+               )
+<<
+
+$(U)til2bm32.exe: $(O)til2bm32.o $(TEXT_IO32)
+    @echo Linking $@...
+       $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(O)til2bm32.o
+               $(TEXT_IO32:^  =^
+               )
+<<
+
+$(O)tile2bmp.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h
+       $(CC) $(CFLAGSU) -I$(WSHR) /DPACKED_FILE /Fo$@ $(WSHR)\tile2bmp.c
+
+$(O)til2bm32.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h
+       $(CC) $(CFLAGSU) -I$(WSHR) /DPACKED_FILE /DTILE_X=32 /DTILE_Y=32 /Fo$@ $(WSHR)\tile2bmp.c
+
+#===================================================================
+# OTHER DEPENDENCIES
+#===================================================================
+
+#
+# dat dependencies
+#
+
+$(DAT)\data: $(UTIL)\makedefs.exe
+       $(U)makedefs -d
+
+$(DAT)\rumors: $(UTIL)\makedefs.exe    $(DAT)\rumors.tru   $(DAT)\rumors.fal
+       $(U)makedefs -r
+
+$(DAT)\quest.dat: $(UTIL)\makedefs.exe  $(DAT)\quest.txt
+       $(U)makedefs -q
+
+$(DAT)\oracles: $(UTIL)\makedefs.exe    $(DAT)\oracles.txt
+       $(U)makedefs -h
+
+$(DAT)\dungeon: $(UTIL)\makedefs.exe  $(DAT)\dungeon.def
+       $(U)makedefs -e
+       cd $(DAT)
+       $(U)dgn_comp dungeon.pdf
+       cd $(WINCE)
+
+#
+# NT dependencies
+#
+#
+#$(O)nttty.o:   $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nttty.c
+#      $(CC) $(CFLAGSU) -I$(WSHR) -Fo$@  $(NTSYS)\nttty.c
+#$(O)winnt.o: $(HACK_H) $(INCL)\win32api.h $(NTSYS)\winnt.c
+#      $(CC) $(CFLAGSU) -Fo$@  $(NTSYS)\winnt.c
+#$(O)ntsound.o: $(HACK_H) $(NTSYS)\ntsound.c
+#      $(CC) $(CFLAGSU)  -Fo$@ $(NTSYS)\ntsound.c
+#$(O)mapimail.o: $(HACK_H) $(INCL)\nhlan.h $(NTSYS)\mapimail.c
+#      $(CC) $(CFLAGSU) -DMAPI_VERBOSE  -Fo$@ $(NTSYS)\mapimail.c
+
+# 
+# util dependencies
+#
+
+$(O)panic.o:  $(U)panic.c $(CONFIG_H)
+       $(CC) $(CFLAGSU) -Fo$@ $(U)panic.c
+
+#
+# The rest are stolen from sys/unix/Makefile.src, 
+# with slashes changed to back-slashes 
+# and -c (which is included in CFLAGSU) substituted
+# with -Fo$@ , but otherwise untouched. That
+# means that there is some irrelevant stuff
+# in here, but maintenance should be easier.
+#
+$(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\sys\atari\tos.c
+$(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\win32api.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\pcmain.c
+$(O)pcsys.o: ..\sys\share\pcsys.c $(HACK_H)
+       $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\pcsys.c
+$(O)pctty.o: ..\sys\share\pctty.c $(HACK_H)
+       $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\pctty.c
+$(O)pcunix.o: ..\sys\share\pcunix.c $(HACK_H)
+       $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\pcunix.c
+$(O)random.o: ..\sys\share\random.c $(HACK_H)
+       $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\random.c
+$(O)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)\tcap.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\ioctl.c
+$(O)unixtty.o: ..\sys\share\unixtty.c $(HACK_H)
+       $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\unixtty.c
+$(O)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)\dlb.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\sys\unix\unixmain.c
+$(O)unixunix.o: ..\sys\unix\unixunix.c $(HACK_H)
+       $(CC) $(CFLAGSU) -Fo$@ ..\sys\unix\unixunix.c
+$(O)bemain.o: ..\sys\be\bemain.c $(HACK_H) $(INCL)\dlb.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\sys\be\bemain.c
+$(O)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)\func_tab.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\tty\getline.c
+$(O)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)\tcap.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\tty\termcap.c
+$(O)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)\tcap.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\tty\topl.c
+$(O)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h $(INCL)\tcap.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\tty\wintty.c
+$(O)Window.o: ..\win\X11\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \
+               $(CONFIG_H)
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\Window.c
+$(O)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H)
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\dialogs.c
+$(O)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h ..\win\X11\nh72icon \
+               ..\win\X11\nh56icon ..\win\X11\nh32icon
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winX.c
+$(O)winmap.o: ..\win\X11\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\winX.h $(INCL)\tile2x11.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winmap.c
+$(O)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)\winX.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winmenu.c
+$(O)winmesg.o: ..\win\X11\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winmesg.c
+$(O)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)\func_tab.h \
+               $(INCL)\winX.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winmisc.c
+$(O)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)\winX.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winstat.c
+$(O)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\wintext.c
+$(O)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)\winX.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winval.c
+$(O)tile.o: $(SRC)\tile.c $(HACK_H)
+$(O)gnaskstr.o: ..\win\gnome\gnaskstr.c ..\win\gnome\gnaskstr.h \
+               ..\win\gnome\gnmain.h
+       $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnaskstr.c
+$(O)gnbind.o: ..\win\gnome\gnbind.c ..\win\gnome\gnbind.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gnaskstr.h ..\win\gnome\gnyesno.h
+       $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnbind.c
+$(O)gnglyph.o: ..\win\gnome\gnglyph.c ..\win\gnome\gnglyph.h
+       $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnglyph.c
+$(O)gnmain.o: ..\win\gnome\gnmain.c ..\win\gnome\gnmain.h ..\win\gnome\gnsignal.h \
+               ..\win\gnome\gnbind.h ..\win\gnome\gnopts.h $(HACK_H) \
+               $(INCL)\date.h
+       $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnmain.c
+$(O)gnmap.o: ..\win\gnome\gnmap.c ..\win\gnome\gnmap.h ..\win\gnome\gnglyph.h \
+               ..\win\gnome\gnsignal.h $(HACK_H)
+       $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnmap.c
+$(O)gnmenu.o: ..\win\gnome\gnmenu.c ..\win\gnome\gnmenu.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gnbind.h
+       $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnmenu.c
+$(O)gnmesg.o: ..\win\gnome\gnmesg.c ..\win\gnome\gnmesg.h ..\win\gnome\gnsignal.h
+       $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnmesg.c
+$(O)gnopts.o: ..\win\gnome\gnopts.c ..\win\gnome\gnopts.h ..\win\gnome\gnglyph.h \
+               ..\win\gnome\gnmain.h ..\win\gnome\gnmap.h $(HACK_H)
+       $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnopts.c
+$(O)gnplayer.o: ..\win\gnome\gnplayer.c ..\win\gnome\gnplayer.h \
+               ..\win\gnome\gnmain.h $(HACK_H)
+       $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnplayer.c
+$(O)gnsignal.o: ..\win\gnome\gnsignal.c ..\win\gnome\gnsignal.h \
+               ..\win\gnome\gnmain.h
+       $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnsignal.c
+$(O)gnstatus.o: ..\win\gnome\gnstatus.c ..\win\gnome\gnstatus.h \
+               ..\win\gnome\gnsignal.h ..\win\gnome\gn_xpms.h \
+               ..\win\gnome\gnomeprv.h
+       $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnstatus.c
+$(O)gntext.o: ..\win\gnome\gntext.c ..\win\gnome\gntext.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gn_rip.h
+       $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gntext.c
+$(O)gnyesno.o: ..\win\gnome\gnyesno.c ..\win\gnome\gnbind.h ..\win\gnome\gnyesno.h
+       $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnyesno.c
+$(O)wingem.o: ..\win\gem\wingem.c $(HACK_H) $(INCL)\func_tab.h $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h $(INCL)\wingem.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\gem\wingem.c
+$(O)wingem1.o: ..\win\gem\wingem1.c $(INCL)\gem_rsc.h $(INCL)\load_img.h \
+               $(INCL)\wintype.h $(INCL)\wingem.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\gem\wingem1.c
+$(O)load_img.o: ..\win\gem\load_img.c $(INCL)\load_img.h
+       $(CC) $(CFLAGSU) -Fo$@ ..\win\gem\load_img.c
+$(O)tile.o: $(SRC)\tile.c $(HACK_H)
+$(O)qt_win.o: ..\win\Qt\qt_win.cpp $(HACK_H) $(INCL)\func_tab.h \
+               $(INCL)\dlb.h $(INCL)\patchlevel.h $(INCL)\qt_win.h \
+               $(INCL)\qt_clust.h $(INCL)\qt_kde0.h \
+               $(INCL)\qt_xpms.h qt_win.moc qt_kde0.moc
+       $(CXX) $(CXXFLAGS) -c ..\win\Qt\qt_win.cpp
+$(O)qt_clust.o: ..\win\Qt\qt_clust.cpp $(INCL)\qt_clust.h
+       $(CXX) $(CXXFLAGS) -c ..\win\Qt\qt_clust.cpp
+$(O)monstr.o: $(SRC)\monstr.c $(CONFIG_H)
+$(O)vis_tab.o: $(SRC)\vis_tab.c $(CONFIG_H) $(INCL)\vis_tab.h
+$(O)allmain.o: $(SRC)\allmain.c $(HACK_H)
+$(O)alloc.o: $(SRC)\alloc.c $(CONFIG_H)
+$(O)apply.o: $(SRC)\apply.c $(HACK_H) $(INCL)\edog.h
+$(O)artifact.o: $(SRC)\artifact.c $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h
+$(O)attrib.o: $(SRC)\attrib.c $(HACK_H) $(INCL)\artifact.h
+$(O)ball.o: $(SRC)\ball.c $(HACK_H)
+$(O)bones.o: $(SRC)\bones.c $(HACK_H) $(INCL)\lev.h
+$(O)botl.o: $(SRC)\botl.c $(HACK_H)
+$(O)cmd.o: $(SRC)\cmd.c $(HACK_H) $(INCL)\func_tab.h
+$(O)dbridge.o: $(SRC)\dbridge.c $(HACK_H)
+$(O)decl.o: $(SRC)\decl.c $(HACK_H)
+$(O)detect.o: $(SRC)\detect.c $(HACK_H) $(INCL)\artifact.h
+$(O)dig.o: $(SRC)\dig.c $(HACK_H) $(INCL)\edog.h
+$(O)display.o: $(SRC)\display.c $(HACK_H)
+$(O)dlb.o: $(SRC)\dlb.c $(CONFIG_H) $(INCL)\dlb.h
+$(O)do.o: $(SRC)\do.c $(HACK_H) $(INCL)\lev.h
+$(O)do_name.o: $(SRC)\do_name.c $(HACK_H)
+$(O)do_wear.o: $(SRC)\do_wear.c $(HACK_H)
+$(O)dog.o: $(SRC)\dog.c $(HACK_H) $(INCL)\edog.h
+$(O)dogmove.o: $(SRC)\dogmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+$(O)dokick.o: $(SRC)\dokick.c $(HACK_H) $(INCL)\eshk.h
+$(O)dothrow.o: $(SRC)\dothrow.c $(HACK_H)
+$(O)drawing.o: $(SRC)\drawing.c $(HACK_H) $(INCL)\tcap.h
+$(O)dungeon.o: $(SRC)\dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h
+$(O)eat.o: $(SRC)\eat.c $(HACK_H)
+$(O)end.o: $(SRC)\end.c $(HACK_H) $(INCL)\eshk.h $(INCL)\dlb.h
+$(O)engrave.o: $(SRC)\engrave.c $(HACK_H) $(INCL)\lev.h
+$(O)exper.o: $(SRC)\exper.c $(HACK_H)
+$(O)explode.o: $(SRC)\explode.c $(HACK_H)
+$(O)extralev.o: $(SRC)\extralev.c $(HACK_H)
+$(O)files.o: $(SRC)\files.c $(HACK_H) $(INCL)\dlb.h
+$(O)fountain.o: $(SRC)\fountain.c $(HACK_H)
+$(O)hack.o: $(SRC)\hack.c $(HACK_H)
+$(O)hacklib.o: $(SRC)\hacklib.c $(HACK_H)
+$(O)invent.o: $(SRC)\invent.c $(HACK_H) $(INCL)\artifact.h
+$(O)light.o: $(SRC)\light.c $(HACK_H) $(INCL)\lev.h
+$(O)lock.o: $(SRC)\lock.c $(HACK_H)
+$(O)mail.o: $(SRC)\mail.c $(HACK_H) $(INCL)\mail.h
+$(O)makemon.o: $(SRC)\makemon.c $(HACK_H) $(INCL)\epri.h $(INCL)\emin.h \
+               $(INCL)\edog.h
+$(O)mapglyph.o: $(SRC)\mapglyph.c $(HACK_H)
+$(O)mcastu.o: $(SRC)\mcastu.c $(HACK_H)
+$(O)mhitm.o: $(SRC)\mhitm.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+$(O)mhitu.o: $(SRC)\mhitu.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+$(O)minion.o: $(SRC)\minion.c $(HACK_H) $(INCL)\emin.h $(INCL)\epri.h
+$(O)mklev.o: $(SRC)\mklev.c $(HACK_H)
+$(O)mkmap.o: $(SRC)\mkmap.c $(HACK_H) $(INCL)\sp_lev.h
+$(O)mkmaze.o: $(SRC)\mkmaze.c $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev.h
+$(O)mkobj.o: $(SRC)\mkobj.c $(HACK_H) $(INCL)\artifact.h
+$(O)mkroom.o: $(SRC)\mkroom.c $(HACK_H)
+$(O)mon.o: $(SRC)\mon.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+$(O)mondata.o: $(SRC)\mondata.c $(HACK_H) $(INCL)\eshk.h $(INCL)\epri.h
+$(O)monmove.o: $(SRC)\monmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h
+$(O)monst.o: $(SRC)\monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \
+               $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\monsym.h \
+               $(INCL)\dungeon.h $(INCL)\eshk.h $(INCL)\vault.h \
+               $(INCL)\epri.h $(INCL)\color.h
+$(O)mplayer.o: $(SRC)\mplayer.c $(HACK_H)
+$(O)mthrowu.o: $(SRC)\mthrowu.c $(HACK_H)
+$(O)muse.o: $(SRC)\muse.c $(HACK_H) $(INCL)\edog.h
+$(O)music.o: $(SRC)\music.c $(HACK_H) #interp.c
+$(O)o_init.o: $(SRC)\o_init.c $(HACK_H) $(INCL)\lev.h
+$(O)objects.o: $(SRC)\objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \
+               $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h
+$(O)objnam.o: $(SRC)\objnam.c $(HACK_H)
+$(O)options.o: $(SRC)\options.c $(CONFIG_H) $(INCL)\objclass.h $(INCL)\flag.h \
+               $(HACK_H) $(INCL)\tcap.h
+$(O)pager.o: $(SRC)\pager.c $(HACK_H) $(INCL)\dlb.h
+$(O)pickup.o: $(SRC)\pickup.c $(HACK_H)
+$(O)pline.o: $(SRC)\pline.c $(HACK_H) $(INCL)\epri.h $(INCL)\edog.h
+$(O)polyself.o: $(SRC)\polyself.c $(HACK_H)
+$(O)potion.o: $(SRC)\potion.c $(HACK_H)
+$(O)pray.o: $(SRC)\pray.c $(HACK_H) $(INCL)\epri.h
+$(O)priest.o: $(SRC)\priest.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\eshk.h \
+               $(INCL)\epri.h $(INCL)\emin.h
+$(O)quest.o: $(SRC)\quest.c $(HACK_H) $(INCL)\qtext.h
+$(O)questpgr.o: $(SRC)\questpgr.c $(HACK_H) $(INCL)\dlb.h $(INCL)\qtext.h
+$(O)read.o: $(SRC)\read.c $(HACK_H)
+$(O)rect.o: $(SRC)\rect.c $(HACK_H)
+$(O)region.o: $(SRC)\region.c $(HACK_H) $(INCL)\lev.h
+$(O)restore.o: $(SRC)\restore.c $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h
+$(O)rip.o: $(SRC)\rip.c $(HACK_H)
+$(O)rnd.o: $(SRC)\rnd.c $(HACK_H)
+$(O)role.o: $(SRC)\role.c $(HACK_H)
+$(O)rumors.o: $(SRC)\rumors.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h
+$(O)save.o: $(SRC)\save.c $(HACK_H) $(INCL)\lev.h
+$(O)shk.o: $(SRC)\shk.c $(HACK_H) $(INCL)\eshk.h
+$(O)shknam.o: $(SRC)\shknam.c $(HACK_H) $(INCL)\eshk.h
+$(O)sit.o: $(SRC)\sit.c $(HACK_H) $(INCL)\artifact.h
+$(O)sounds.o: $(SRC)\sounds.c $(HACK_H) $(INCL)\edog.h
+$(O)sp_lev.o: $(SRC)\sp_lev.c $(HACK_H) $(INCL)\dlb.h $(INCL)\sp_lev.h
+$(O)spell.o: $(SRC)\spell.c $(HACK_H)
+$(O)steal.o: $(SRC)\steal.c $(HACK_H)
+$(O)steed.o: $(SRC)\steed.c $(HACK_H)
+$(O)teleport.o: $(SRC)\teleport.c $(HACK_H)
+$(O)timeout.o: $(SRC)\timeout.c $(HACK_H) $(INCL)\lev.h
+$(O)topten.o: $(SRC)\topten.c $(HACK_H) $(INCL)\dlb.h $(INCL)\patchlevel.h
+$(O)track.o: $(SRC)\track.c $(HACK_H)
+$(O)trap.o: $(SRC)\trap.c $(HACK_H)
+$(O)u_init.o: $(SRC)\u_init.c $(HACK_H)
+$(O)uhitm.o: $(SRC)\uhitm.c $(HACK_H)
+$(O)vault.o: $(SRC)\vault.c $(HACK_H) $(INCL)\vault.h
+$(O)version.o: $(SRC)\version.c $(HACK_H) $(INCL)\date.h $(INCL)\patchlevel.h
+$(O)vision.o: $(SRC)\vision.c $(HACK_H) $(INCL)\vis_tab.h
+$(O)weapon.o: $(SRC)\weapon.c $(HACK_H)
+$(O)were.o: $(SRC)\were.c $(HACK_H)
+$(O)wield.o: $(SRC)\wield.c $(HACK_H)
+$(O)windows.o: $(SRC)\windows.c $(HACK_H) $(INCL)\wingem.h $(INCL)\winGnome.h
+$(O)wizard.o: $(SRC)\wizard.c $(HACK_H) $(INCL)\qtext.h
+$(O)worm.o: $(SRC)\worm.c $(HACK_H) $(INCL)\lev.h
+$(O)worn.o: $(SRC)\worn.c $(HACK_H)
+$(O)write.o: $(SRC)\write.c $(HACK_H)
+$(O)zap.o: $(SRC)\zap.c $(HACK_H)
+
+# end of file
+
diff --git a/sys/wince/ceinc/assert.h b/sys/wince/ceinc/assert.h
new file mode 100644 (file)
index 0000000..8844d2a
--- /dev/null
@@ -0,0 +1,16 @@
+/***
+*assert.h - define the assert macro
+*
+****/
+
+#undef  assert
+
+#ifdef  NDEBUG
+
+#define assert(exp)     ((void)0)
+
+#else
+
+#define assert(exp) (void)( (exp) || (panic("%s at %s line %ld", #exp, __FILE__,__LINE__), 1) )
+
+#endif  /* NDEBUG */
diff --git a/sys/wince/ceinc/errno.h b/sys/wince/ceinc/errno.h
new file mode 100644 (file)
index 0000000..c6c3193
--- /dev/null
@@ -0,0 +1,4 @@
+/* empty file */
+
+extern int errno;
+
diff --git a/sys/wince/ceinc/fcntl.h b/sys/wince/ceinc/fcntl.h
new file mode 100644 (file)
index 0000000..a9136c8
--- /dev/null
@@ -0,0 +1,67 @@
+/***
+*fcntl.h - file control options used by open()
+*
+*Purpose:
+*       This file defines constants for the file control options used
+*       by the _open() function.
+*       [System V]
+*
+*       [Public]
+*
+****/
+
+#ifndef _INC_FCNTL
+#define _INC_FCNTL
+
+#define _O_RDONLY       0x0000  /* open for reading only */
+#define _O_WRONLY       0x0001  /* open for writing only */
+#define _O_RDWR         0x0002  /* open for reading and writing */
+#define _O_APPEND       0x0008  /* writes done at eof */
+
+#define _O_CREAT        0x0100  /* create and open file */
+#define _O_TRUNC        0x0200  /* open and truncate */
+#define _O_EXCL         0x0400  /* open only if file doesn't already exist */
+
+/* O_TEXT files have <cr><lf> sequences translated to <lf> on read()'s,
+** and <lf> sequences translated to <cr><lf> on write()'s
+*/
+
+#define _O_TEXT         0x4000  /* file mode is text (translated) */
+#define _O_BINARY       0x8000  /* file mode is binary (untranslated) */
+
+/* macro to translate the C 2.0 name used to force binary mode for files */
+
+#define _O_RAW  _O_BINARY
+
+/* Open handle inherit bit */
+
+#define _O_NOINHERIT    0x0080  /* child process doesn't inherit file */
+
+/* Temporary file bit - file is deleted when last handle is closed */
+
+#define _O_TEMPORARY    0x0040  /* temporary file bit */
+
+/* sequential/random access hints */
+
+#define _O_SEQUENTIAL   0x0020  /* file access is primarily sequential */
+#define _O_RANDOM       0x0010  /* file access is primarily random */
+
+#if     !__STDC__ || defined(_POSIX_)
+/* Non-ANSI names for compatibility */
+#define O_RDONLY        _O_RDONLY
+#define O_WRONLY        _O_WRONLY
+#define O_RDWR          _O_RDWR
+#define O_APPEND        _O_APPEND
+#define O_CREAT         _O_CREAT
+#define O_TRUNC         _O_TRUNC
+#define O_EXCL          _O_EXCL
+#define O_TEXT          _O_TEXT
+#define O_BINARY        _O_BINARY
+#define O_RAW           _O_BINARY
+#define O_TEMPORARY     _O_TEMPORARY
+#define O_NOINHERIT     _O_NOINHERIT
+#define O_SEQUENTIAL    _O_SEQUENTIAL
+#define O_RANDOM        _O_RANDOM
+#endif  /* __STDC__ */
+
+#endif  /* _INC_FCNTL */
diff --git a/sys/wince/ceinc/sys/stat.h b/sys/wince/ceinc/sys/stat.h
new file mode 100644 (file)
index 0000000..dbb39b6
--- /dev/null
@@ -0,0 +1,2 @@
+/* empty file */
+
diff --git a/sys/wince/celib.c b/sys/wince/celib.c
new file mode 100644 (file)
index 0000000..22323b0
--- /dev/null
@@ -0,0 +1,824 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#define NEED_VARARGS
+#include "hack.h"
+#include <fcntl.h>
+// #include "wceconf.h"
+
+static union {
+       time_t t_val;
+       struct time_pack {
+               unsigned int ss:6;
+               unsigned int mm:6;
+               unsigned int dd:5;
+               unsigned int hh:6;
+               unsigned int mo:4;
+               unsigned int yr:10;
+               unsigned int wd:3;
+       } tm_val;
+} _t_cnv;
+
+#define IS_LEAP(yr) (((yr)%4==0 || (yr)%100==0) && !(yr)%400==0)
+static char _day_mo_leap[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+static char _day_mo[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+struct tm * __cdecl localtime ( const time_t *ptime )
+{
+       static struct tm ptm;
+       int i;
+       if( !ptime ) return NULL;
+
+       _t_cnv.t_val = *ptime;
+
+    ptm.tm_sec         = _t_cnv.tm_val.ss ;     /* seconds after the minute - [0,59] */
+    ptm.tm_min         = _t_cnv.tm_val.mm;     /* minutes after the hour - [0,59] */
+    ptm.tm_hour        = _t_cnv.tm_val.hh;    /* hours since midnight - [0,23] */
+    ptm.tm_mday        = _t_cnv.tm_val.dd;    /* day of the month - [1,31] */
+    ptm.tm_mon         = _t_cnv.tm_val.mo-1;     /* months since January - [0,11] */
+    ptm.tm_year        = _t_cnv.tm_val.yr;    /* years since 1900 */
+    ptm.tm_wday        = _t_cnv.tm_val.wd;    /* days since Sunday - [0,6] */
+
+       ptm.tm_yday = _t_cnv.tm_val.dd;    /* days since January 1 - [0,365] */
+       for( i=0; i<ptm.tm_mon; i++ )
+               ptm.tm_yday += IS_LEAP(_t_cnv.tm_val.yr+1900)?_day_mo_leap[i] : _day_mo[i] ; 
+
+       ptm.tm_isdst = 0;   /* daylight savings time flag  - NOT IMPLEMENTED */
+       return &ptm;
+}
+
+time_t __cdecl time(time_t * timeptr)
+{
+       SYSTEMTIME stm;
+       GetLocalTime(&stm);
+
+       _t_cnv.tm_val.yr = stm.wYear-1900; 
+       _t_cnv.tm_val.mo = stm.wMonth; 
+       _t_cnv.tm_val.dd = stm.wDay; 
+       _t_cnv.tm_val.hh = stm.wHour; 
+       _t_cnv.tm_val.mm = stm.wMinute; 
+       _t_cnv.tm_val.ss = stm.wSecond; 
+       _t_cnv.tm_val.wd = stm.wDayOfWeek; 
+
+       if( timeptr) 
+               *timeptr = _t_cnv.t_val;
+       return _t_cnv.t_val;
+}
+
+/*------------------------------------------------------------------------------*/
+/* __io.h__ */
+/* Hack io.h function with stdio.h functions */
+/* ASSUMPTION : int can hold FILE* */
+static TCHAR _nh_cwd[MAX_PATH];
+const int MAGIC_OFFSET=5;
+#define FILE_TABLE_SIZE  256
+static HANDLE _nh_file_table[FILE_TABLE_SIZE];
+static int file_pointer = -1;
+
+static HANDLE get_file_handle(int i) 
+{
+       i -= MAGIC_OFFSET;
+       if( i>=0 && i<FILE_TABLE_SIZE )
+               return _nh_file_table[i];
+       else 
+               return INVALID_HANDLE_VALUE;
+} 
+
+static int alloc_file_handle(HANDLE h) 
+{
+       int i;
+       if( file_pointer==-1 ) {
+               file_pointer=0;
+               for(i=0; i<FILE_TABLE_SIZE; i++ )
+                       _nh_file_table[i] = INVALID_HANDLE_VALUE;
+       }
+
+       i = (file_pointer+1)%FILE_TABLE_SIZE;
+       while(_nh_file_table[i]!=INVALID_HANDLE_VALUE ) {
+               if( i==file_pointer ) {
+                       MessageBox(NULL, _T("Ran out of file handles."), _T("Fatal Error"), MB_OK);
+                       abort();
+               }
+               i = (i+1) % FILE_TABLE_SIZE;
+       }
+       
+       file_pointer = i;
+       _nh_file_table[file_pointer] = h;
+       return file_pointer+MAGIC_OFFSET;
+} 
+
+int __cdecl close(int f) {
+       int retval;
+       f -= MAGIC_OFFSET;
+       if( f<0 || f>=FILE_TABLE_SIZE ) return -1;
+       retval = (CloseHandle(_nh_file_table[f])? 0 : -1);
+       _nh_file_table[f] = INVALID_HANDLE_VALUE;
+       return retval;
+}
+
+int __cdecl creat(const char *fname , int mode)
+{
+       HANDLE f;
+       TCHAR wbuf[MAX_PATH+1];
+       ZeroMemory(wbuf, sizeof(wbuf));
+       NH_A2W(fname, wbuf, MAX_PATH);
+
+       f = CreateFile(
+               wbuf, 
+               GENERIC_READ | GENERIC_WRITE,
+               0,
+               NULL,
+               CREATE_ALWAYS,
+               FILE_ATTRIBUTE_NORMAL,
+               NULL);
+
+       if( f==INVALID_HANDLE_VALUE ) return -1;
+       else     return alloc_file_handle(f);
+}
+
+int __cdecl eof(int f)
+{
+       DWORD fpos, fsize;
+       HANDLE p = get_file_handle(f);
+
+       if( f==-1 ) return -1;
+
+       fpos = SetFilePointer(p, 0, NULL, FILE_CURRENT);
+       fsize = SetFilePointer(p, 0, NULL, FILE_END);
+       if( fpos==0xFFFFFFFF || fsize==0xFFFFFFFF ) return -1;
+       if( fpos==fsize ) return 1;
+       else {
+               SetFilePointer(p, fpos, NULL, FILE_BEGIN);
+               return 0;
+       }
+}
+
+long __cdecl lseek( int f, long offset, int origin )
+{
+       HANDLE p = get_file_handle(f);
+       DWORD fpos;
+       switch(origin) {
+       case SEEK_SET:
+               fpos = SetFilePointer(p, offset, NULL, FILE_BEGIN);
+               break;
+       case SEEK_CUR:
+               fpos = SetFilePointer(p, offset, NULL, FILE_CURRENT);
+               break;
+       case SEEK_END:
+               fpos = SetFilePointer(p, offset, NULL, FILE_END);
+               break;
+       default:
+               fpos = 0xFFFFFFFF;
+               break;
+       }
+       if( fpos==0xFFFFFFFF ) return -1;
+       else return (long)fpos;
+}
+
+int __cdecl open( const char *filename, int oflag, ... )
+{
+       TCHAR fname[MAX_PATH+1];
+       TCHAR path[MAX_PATH+1];
+    HANDLE f;                       
+    DWORD fileaccess;               
+    DWORD filecreate;               
+
+       /* O_TEXT is not supported */
+
+    /*
+     * decode the access flags
+     */
+    switch( oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR) ) {
+
+        case _O_RDONLY:         /* read access */
+                fileaccess = GENERIC_READ;
+                break;
+        case _O_WRONLY:         /* write access */
+                fileaccess = GENERIC_READ | GENERIC_WRITE;
+                break;
+        case _O_RDWR:           /* read and write access */
+                fileaccess = GENERIC_READ | GENERIC_WRITE;
+                break;
+        default:                /* error, bad oflag */
+                return -1;
+    }
+
+    /*
+     * decode open/create method flags
+     */
+    switch ( oflag & (_O_CREAT | _O_EXCL | _O_TRUNC) ) {
+        case 0:
+        case _O_EXCL:                   // ignore EXCL w/o CREAT
+            filecreate = OPEN_EXISTING;
+            break;
+
+        case _O_CREAT:
+            filecreate = OPEN_ALWAYS;
+            break;
+
+        case _O_CREAT | _O_EXCL:
+        case _O_CREAT | _O_TRUNC | _O_EXCL:
+            filecreate = CREATE_NEW;
+            break;
+
+        case _O_TRUNC:
+        case _O_TRUNC | _O_EXCL:        // ignore EXCL w/o CREAT
+            filecreate = TRUNCATE_EXISTING;
+            break;
+
+        case _O_CREAT | _O_TRUNC:
+            filecreate = CREATE_ALWAYS;
+            break;
+
+        default:
+            return -1;
+    }
+
+       /* assemple the file name */
+       ZeroMemory(fname, sizeof(fname));
+       ZeroMemory(path, sizeof(path));
+       NH_A2W(filename, fname, MAX_PATH);
+       if( *filename!='\\' && *filename!='/' ) {
+               _tcscpy(path, _nh_cwd);
+               _tcsncat(path, _T("\\"), MAX_PATH - _tcslen(path));
+       }
+       _tcsncat(path, fname, MAX_PATH - _tcslen(path));
+
+    /*
+     * try to open/create the file
+     */
+    if ( (f = CreateFile( path,
+                         fileaccess,
+                         0,
+                         NULL,
+                         filecreate,
+                         FILE_ATTRIBUTE_NORMAL,
+                         NULL ))
+         == INVALID_HANDLE_VALUE )
+    {
+        return -1;
+    }
+
+       if( !(oflag & O_APPEND) ) SetFilePointer(f, 0, NULL, FILE_BEGIN);
+       return alloc_file_handle(f);
+}
+
+int __cdecl read( int f, void *buffer, unsigned int count )
+{
+       HANDLE p = get_file_handle(f);
+       DWORD bytes_read;
+       if( !ReadFile(p, buffer, count, &bytes_read, NULL) )
+               return -1;
+       else 
+               return (int)bytes_read;
+}
+
+int __cdecl unlink(const char * filename)
+{
+       TCHAR wbuf[MAX_PATH+1];
+       TCHAR fname[MAX_PATH+1];
+       
+       ZeroMemory(wbuf, sizeof(wbuf));
+       ZeroMemory(fname, sizeof(fname));
+       NH_A2W(filename, wbuf, MAX_PATH);
+       if( *filename!='\\' && *filename!='/' ) {
+               _tcscpy(fname, _nh_cwd);
+               _tcsncat(fname, _T("\\"), MAX_PATH - _tcslen(fname));
+       }
+       _tcsncat(fname, wbuf, MAX_PATH - _tcslen(fname));
+
+       return !DeleteFileW(fname);
+}
+
+int __cdecl write( int f, const void *buffer, unsigned int count )
+{
+       HANDLE p = get_file_handle(f);
+       DWORD bytes_written;
+       if( !WriteFile(p, buffer, count, &bytes_written, NULL) ) 
+               return -1;
+       else 
+               return (int)bytes_written;
+}
+
+int __cdecl rename( const char *oldname, const char *newname )
+{
+       WCHAR f1[MAX_PATH+1];
+       WCHAR f2[MAX_PATH+1];
+       ZeroMemory(f1, sizeof(f1));
+       ZeroMemory(f2, sizeof(f2));
+       MultiByteToWideChar(CP_ACP, 0, oldname, -1, f1, MAX_PATH);
+       MultiByteToWideChar(CP_ACP, 0, newname, -1, f2, MAX_PATH);
+       return !MoveFile(f1, f2);
+}
+
+int __cdecl access( const char *path, int mode )
+{
+       DWORD attr;
+       WCHAR f[MAX_PATH+1];
+       ZeroMemory(f, sizeof(f));
+       MultiByteToWideChar(CP_ACP, 0, path, -1, f, MAX_PATH);
+       
+       attr = GetFileAttributes(f);
+       if( attr == (DWORD)-1 ) return -1;
+
+       if ( (attr & FILE_ATTRIBUTE_READONLY) && (mode & 2) )
+               return -1;
+       else
+        return 0;
+}
+
+int chdir( const char *dirname )
+{
+       ZeroMemory(_nh_cwd, sizeof(_nh_cwd));
+       NH_A2W(dirname, _nh_cwd, MAX_PATH);
+       return 0;
+}
+
+char *getcwd( char *buffer, int maxlen )
+{
+       if( maxlen<(int)_tcslen(_nh_cwd) ) return NULL;
+       else return NH_W2A(_nh_cwd, buffer, maxlen);
+}
+
+/*------------------------------------------------------------------------------*/
+/* __errno.h__ */
+int errno;
+
+/*------------------------------------------------------------------------------*/
+/*
+ * Chdrive() changes the default drive.
+ */
+void
+chdrive(char *str)
+{
+       return;
+}
+
+/*
+ * This is used in nhlan.c to implement some of the LAN_FEATURES.
+ */
+char *get_username(lan_username_size)
+int *lan_username_size;
+{
+       static char username_buffer[BUFSZ];
+       strcpy(username_buffer, "nhsave");
+       return username_buffer;
+}
+
+void Delay(int ms)
+{
+       (void)Sleep(ms);
+}
+
+void more()
+{
+
+}
+
+int isatty(int f)
+{
+       return 0;
+}
+
+
+#if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO)
+int __cdecl isupper(int c)
+{
+       char str[2];
+       WCHAR wstr[2];
+       str[0] = c;
+       str[1] = 0;
+
+       NH_A2W(str, wstr, 1);
+       return iswupper(wstr[0]);
+}
+
+int __cdecl isdigit(int c)
+{
+       return  ('0' <= c && c <= '9');
+}
+
+int __cdecl isxdigit(int c)
+{
+       return  (('0' <= c && c <= '9') || 
+                    ('a' <= c && c <= 'f') || 
+                        ('A' <= c && c <= 'F'));
+}
+
+int __cdecl isspace(int c)
+{
+       char str[2];
+       WCHAR wstr[2];
+       str[0] = c;
+       str[1] = 0;
+
+       NH_A2W(str, wstr, 1);
+       return iswspace(wstr[0]);
+}
+
+int __cdecl isprint(int c)
+{
+       char str[2];
+       WCHAR wstr[2];
+       str[0] = c;
+       str[1] = 0;
+
+       NH_A2W(str, wstr, 1);
+       return iswprint(wstr[0]);
+}
+
+char* __cdecl _strdup(const char* s)
+{
+       char* p;
+       p = malloc(strlen(s)+1);
+       return strcpy(p, s);
+}
+
+char* __cdecl strrchr( const char *s, int c )
+{
+       WCHAR wstr[1024];
+       WCHAR *w;
+       w = wcsrchr(NH_A2W(s, wstr, 1024), c);
+       if(w) return (char*)(s + (w - wstr));
+       else return NULL;
+}
+
+int   __cdecl _stricmp(const char* a, const char* b)
+{
+        return strncmpi(a, b, 65535u);
+}
+
+#endif
+
+#if defined(WIN_CE_PS2xx)
+/* stdio.h functions are missing from PAlm Size PC SDK 1.2 (SH3 and MIPS) */
+
+#pragma warning(disable:4273)
+
+FILE * __cdecl fopen(const char* filename, const char *mode)
+{
+    int modeflag;
+    int whileflag;
+    int filedes;
+
+    /* First mode character must be 'r', 'w', or 'a'. */
+    switch (*mode) {
+    case 'r':
+            modeflag = _O_RDONLY;
+            break;
+    case 'w':
+            modeflag = _O_WRONLY | _O_CREAT | _O_TRUNC;
+            break;
+    case 'a':
+            modeflag = _O_WRONLY | _O_CREAT | _O_APPEND;
+            break;
+    default:
+            return NULL;
+    }
+
+    whileflag=1;
+    while(*++mode && whileflag)
+            switch(*mode) {
+
+            case '+':
+                    if (modeflag & _O_RDWR)
+                            whileflag=0;
+                    else {
+                            modeflag |= _O_RDWR;
+                            modeflag &= ~(_O_RDONLY | _O_WRONLY);
+                    }
+                    break;
+
+            case 'b':
+                    if (modeflag & (_O_TEXT | _O_BINARY))
+                            whileflag=0;
+                    else
+                            modeflag |= _O_BINARY;
+                    break;
+
+            case 't': /* not supported */
+                                       whileflag=0; 
+                    break;
+
+               default:
+                    whileflag=0;
+                    break;
+            }
+
+    if ((filedes = open(filename, modeflag))==-1) return NULL;
+
+    return (FILE*)filedes;
+}
+
+int    __cdecl fscanf(FILE *f , const char *format, ...)
+{
+       /* Format spec:  %[*] [width] [l] type ] */
+       int ch;
+       int sch;
+       int matched = 0;
+       int width = 65535;
+       int modifier = -1;
+       int skip_flag = 0;
+       int n_read = 0;
+       char buf[BUFSZ];
+       TCHAR wbuf[BUFSZ];
+       char* p;
+       va_list args;
+
+#define RETURN_SCANF(i) { va_end(args); return i; }
+#define NEXT_CHAR(f) (n_read++, fgetc(f))
+
+       va_start(args, format);
+
+       ch = *format++;
+       sch = NEXT_CHAR(f);
+       while( ch && sch!=EOF ) {
+               if( isspace(ch) ) {
+                       while( ch && isspace(ch) ) ch = *format++;
+                       while( sch!=EOF && isspace(sch) ) sch = NEXT_CHAR(f);
+                       format--;
+                       goto next_spec;
+               }
+
+               /* read % */
+               if( ch!='%' ) {
+                       if( sch!=ch ) RETURN_SCANF(matched);
+                       sch = NEXT_CHAR(f);
+                       goto next_spec;
+               } else {
+                       /* process '%%' */
+                       ch = *format++;
+                       if( ch=='%' ) {
+                               if( sch!='%' ) RETURN_SCANF(matched);
+                               sch = NEXT_CHAR(f);
+                               goto next_spec;
+                       }
+                       
+                       if( ch=='*' ) {
+                               /* read skip flag - '*' */
+                               skip_flag=1;
+                               ch = *format++;
+                       }
+
+                       /* get width */
+                       if( isdigit(ch) ) {
+                               width = 0;
+                               while(ch && isdigit(ch)) {
+                                       width = width*10 + (ch-'0');
+                                       ch = *format++;
+                               }
+                       }
+
+                       /* get modifier */
+                       if( ch=='l' ) {
+                               modifier = 'l';
+                               ch = *format++;
+                       }
+
+                       /* get type */
+                       switch(ch) {
+                       case 'c':
+                               if( !skip_flag ) {
+                                       *(va_arg(args, char*))=sch;
+                                       matched++;
+                               }
+                               sch = NEXT_CHAR(f);
+                               goto next_spec;
+                       case 'd':
+                               p = buf;
+                               /* skip space */
+                               while(sch!=EOF && isspace(sch)) sch=NEXT_CHAR(f);
+                               while(sch!=EOF && isdigit(sch) && --width>=0) { *p++ = sch; sch=NEXT_CHAR(f); }
+                               *p = '\x0';
+                               if( !skip_flag ) {
+                                       matched++;
+                                       if( modifier=='l' ) {
+                                               *(va_arg(args, long*))=wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 10);
+                                       } else {
+                                               *(va_arg(args, int*))=wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 10);
+                                       }
+                               }
+                               goto next_spec;
+                       case 'x':
+                               p = buf;
+                               while(sch!=EOF && isspace(sch)) sch=NEXT_CHAR(f);
+                               while(sch!=EOF && isxdigit(sch) && --width>=0) { *p++ = sch; sch=NEXT_CHAR(f); }
+                               *p = '\x0';
+                               if( !skip_flag ) {
+                                       matched++;
+                                       if( modifier=='l' ) {
+                                               *(va_arg(args, long*))=wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 16);
+                                       } else {
+                                               *(va_arg(args, int*))=wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 16);
+                                       }
+                               }
+                               goto next_spec;
+                       case 'n':
+                               *(va_arg(args, int*)) = n_read;
+                               matched++;
+                               goto next_spec;
+                       case 's':
+                               if( skip_flag ) {
+                                       while(sch!=EOF && !isspace(sch) && --width>=0) { sch=NEXT_CHAR(f); }
+                               } else {
+                                       p = va_arg(args, char*);
+                                       while(sch!=EOF && !isspace(sch) && --width>=0) { *p++ = sch; sch=NEXT_CHAR(f); }
+                                       *p = '\x0';
+                                       matched++;
+                               }
+                               goto next_spec;
+                       case '[': {
+                                       char pattern[256];
+                                       int start, end;
+                                       int negate;
+
+                                       ZeroMemory(pattern, sizeof(pattern));
+                                       p = pattern;
+                                       
+                                       /* try to parse '^' modifier */
+                                       ch = *format++;
+                                       if( ch=='^' ) { negate=1; ch=*format++; }
+                                       else              { negate=0; }
+                                       if( ch==0 ) RETURN_SCANF(EOF);
+
+                                       for( ; ch && ch!=']'; ch = *format++ ) {
+                                               /* try to parse range: a-z */
+                                               if( format[0]=='-' &&
+                                                       format[1] && format[1]!=']' ) {
+                                                       start = ch;
+                                                       format++;
+                                                       end = *format++;
+                                                       while(start<=end) {
+                                                               if(!strchr(pattern, (char)start))
+                                                                       *p++ = (char)start;
+                                                               start++;
+                                                       }
+                                               } else {
+                                                       if(!strchr(pattern, (char)ch)) *p++ = (char)ch;
+                                               }
+                                       }
+
+                                       if( skip_flag ) {
+                                               while(sch!=EOF && strchr(pattern, sch) && --width>=0) { sch=NEXT_CHAR(f); }
+                                       } else {
+                                               p = va_arg(args, char*);
+                                               if( negate )
+                                                       while(sch!=EOF && !strchr(pattern, sch) && --width>=0) { *p++ = sch; sch=NEXT_CHAR(f); }
+                                               else
+                                                       while(sch!=EOF && strchr(pattern, sch) && --width>=0) { *p++ = sch; sch=NEXT_CHAR(f); }
+                                               *p = '\x0';
+                                               matched++;
+                                       }
+                                 } goto next_spec;
+                       default:
+                               RETURN_SCANF(EOF);
+                       }
+               }
+
+next_spec:
+               width = 65535;
+               modifier = -1;
+               skip_flag = 0;
+               ch = *format++;
+       }
+       fseek(f, -1, SEEK_CUR);
+       RETURN_SCANF(matched);
+
+#undef RETURN_SCANF
+#undef NEXT_CHAR
+}
+
+int __cdecl fprintf(FILE *f , const char *format, ...)
+{
+       int retval;
+       va_list args;
+
+       if( !f || !format ) return 0;
+
+       va_start(args, format);
+       retval = vfprintf(f, format, args);
+       va_end(args);
+       
+       return retval;
+}
+
+int    __cdecl vfprintf(FILE* f, const char *format, va_list args)
+{
+       char buf[4096];
+       int retval;
+
+       if( !f || !format ) return 0;
+
+       retval = vsprintf(buf, format, args);
+
+       write((int)f, buf, strlen(buf));
+       
+       return retval;
+}
+
+int __cdecl fgetc(FILE * f)
+{
+       char c;
+       int fh = (int)f;
+
+       if( !f ) return EOF;
+       if( read(fh, &c, 1)==1 ) return c;
+       else                                     return EOF;
+}
+
+char * __cdecl fgets(char *s, int size, FILE *f)
+{
+       /* not the best performance but it will do for now...*/
+       char c;
+       if( !f || !s || size==0 ) return NULL;
+       while( --size>0 ) {
+               if( (c = fgetc(f))==EOF ) return NULL;
+
+               *s++ = c;
+               if( c=='\n' ) break;
+       }
+       *s = '\x0';
+       return s;
+}
+
+int    __cdecl printf(const char *format, ...)
+{
+       int retval;
+       va_list args;
+
+       if( !format ) return 0;
+
+       va_start(args, format);
+       retval = vprintf(format, args);
+       va_end(args);
+
+       return retval;
+}
+
+int    __cdecl vprintf(const char *format, va_list args)
+{
+       char buf[4096];
+       int retval;
+
+       retval = vsprintf(buf, format, args);
+       puts(buf);
+       return retval;
+}
+
+// int    __cdecl putchar(int);
+int    __cdecl puts(const char * s)
+{
+       TCHAR wbuf[4096];
+       NH_A2W(s, wbuf, 4096);
+       MessageBox(NULL, wbuf, _T("stdout"), MB_OK);
+       return 0;
+}
+
+FILE*  __cdecl _getstdfilex(int desc)
+{
+       return NULL;
+}
+
+int __cdecl fclose(FILE * f)
+{
+       if(!f) return EOF;
+       return close((int)f)==-1? EOF : 0;
+}
+
+size_t __cdecl fread(void *p, size_t size, size_t count, FILE *f)
+{
+       int read_bytes;
+       if(!f || !p || size==0 || count==0) return 0;
+       read_bytes = read((int)f, p, size*count);
+       return read_bytes>0? (read_bytes/size) : 0;
+}
+
+size_t __cdecl fwrite(const void *p, size_t size, size_t count, FILE * f)
+{
+       int write_bytes;
+       if(!f || !p || size==0 || count==0) return 0;
+       write_bytes = write((int)f, p, size*count);
+       return write_bytes>0? write_bytes/size : 0;
+}
+
+int    __cdecl fflush(FILE *f)
+{ 
+       return 0;
+}
+
+int    __cdecl feof(FILE *f)
+{
+       return (f && eof((int)f)==0)? 0 : 1;
+}
+
+int    __cdecl fseek(FILE *f, long offset, int from)
+{
+       return (f && lseek((int)f, offset, from)>=0)? 0 : 1;
+}
+
+long   __cdecl ftell(FILE * f)
+{
+       return f? lseek((int)f, 0, SEEK_CUR) : -1;
+}
+
+#endif 
diff --git a/sys/wince/cesetup.bat b/sys/wince/cesetup.bat
new file mode 100644 (file)
index 0000000..b129142
--- /dev/null
@@ -0,0 +1,40 @@
+@REM  SCCS Id: @(#)nhsetup.bat $Date: 2003/08/22 13:23:33 $
+@REM  Copyright (c) Alex Kompel, 2002
+@REM  NetHack may be freely redistributed.  See license for details. 
+@REM  Win32 nhsetup batch file, see Install.ce for details
+@REM
+@echo off
+REM
+REM  Make sure directories necessary for build exist
+REM
+if NOT exist ..\..\wince\*.* mkdir ..\..\wince
+REM
+REM  Get these files from the win\win32 port
+REM
+copy ..\..\win\win32\mnsel.uu    ..\..\wince\mnsel.uu
+copy ..\..\win\win32\mnselcnt.uu ..\..\wince\mnselcnt.uu
+copy ..\..\win\win32\mnunsel.uu  ..\..\wince\mnunsel.uu
+copy ..\..\win\win32\petmark.uu  ..\..\wince\petmark.uu
+copy ..\..\sys\winnt\nhico.uu    ..\..\wince\nhico.uu
+copy ..\..\sys\wince\menubar.uu    ..\..\wince\menubar.uu
+copy ..\..\sys\wince\keypad.uu    ..\..\wince\keypad.uu
+REM
+REM  Get these files from sys\wince
+REM
+copy bootstrp.mak ..\..\wince\bootstrp.mak
+copy wince.vcw    ..\..\wince.vcw
+copy hpc.vcp      ..\..\wince\wince_hpc.vcp
+copy palmpc.vcp   ..\..\wince\wince_palm_pc.vcp
+copy pocketpc.vcp ..\..\wince\wince_pocket_pc.vcp
+copy smartphn.vcp ..\..\wince\wince_smartphone.vcp
+echo.
+echo Proceed with the following steps:
+echo.
+echo        cd ..\..\wince
+echo        nmake /f bootstrp.mak
+echo.
+echo Then start Embedded Visual C and open 
+echo the workspace wince.vcw (at the top of the NetHack tree)
+echo to build.  See Install.ce for details.
+echo.
+
diff --git a/sys/wince/cesound.c b/sys/wince/cesound.c
new file mode 100644 (file)
index 0000000..257f61e
--- /dev/null
@@ -0,0 +1,27 @@
+/*   SCCS Id: @(#)cesound.c   3.4     $Date: 2003/02/13 12:35:27 $                        */
+/*   Copyright (c) NetHack PC Development Team 1993                 */
+/*   NetHack may be freely redistributed.  See license for details. */
+/*                                                                  */
+/*
+ * cesound.c - Windows CE NetHack sound support
+ *                                                  
+ *
+ */
+
+#include "hack.h"
+#include <mmsystem.h>
+
+#ifdef USER_SOUNDS
+
+void play_usersound(filename, volume)
+const char* filename;
+int volume;
+{
+       TCHAR wbuf[MAX_PATH+1];
+/*    pline("play_usersound: %s (%d).", filename, volume); */
+       ZeroMemory(wbuf, sizeof(wbuf));
+       (void)sndPlaySound(NH_A2W(filename, wbuf, MAX_PATH), SND_ASYNC | SND_NODEFAULT);
+}
+
+#endif /*USER_SOUNDS*/
+/* cesound.c */
diff --git a/sys/wince/defaults.nh b/sys/wince/defaults.nh
new file mode 100644 (file)
index 0000000..6367900
--- /dev/null
@@ -0,0 +1,139 @@
+# Sample config file for win32 NetHack
+# A '#' at the beginning of a line means the rest of the line is a comment.
+#
+# Some options MUST be set in this file, other options can be toggled while
+# playing.  For a list of options available see the <opthelp.> file.
+#
+# To change the configuration, comment out the unwanted lines, and
+# uncomment the configuration you want.
+
+# *** OPTIONS ***
+#
+# Use the IBM character set rather than just plain ascii characters
+# for tty window-port.
+# OPTIONS=IBMGraphics
+
+# *** Personal Preferences ***
+# Some options to set personal preferences.  Uncomment and change these to
+# suit your personal preference.  If several people are to use the same
+# configuration, options like these should not be set.
+#
+#OPTIONS=name:Janet,role:Valkyrie,race:Human,gender:female,align:lawful
+#OPTIONS=dogname:Fido,catname:Morris,fruit:guava
+#OPTIONS=horsename:Silver
+#OPTIONS=autopickup,pickup_types:$"=/!?+
+#OPTIONS=packorder:")[%?+/=!(*0_`
+#OPTIONS=scores:10 top/2 around/own
+#OPTIONS=nolegacy,noverbose
+#OPTIONS=menustyle:traditional
+
+#
+# General options.  You might also set "silent" so as not to attract
+# the boss's attention.
+#
+OPTIONS=time,noshowexp,number_pad,lit_corridor,rest_on_space
+#
+# If you want to get rid of "use #quit to quit..." use:
+#OPTIONS=suppress_alert:3.3.1
+#
+# Set some options to control graphical window-port (these will
+# be safely and silently ignored by the tty port)
+#
+# Map window settings
+# possible map_mode options include: tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|
+#                                    ascii7x12|ascii8x12|ascii16x12|ascii12x16|
+#                                    ascii10x18|fit_to_screen
+OPTIONS=map_mode:tiles,scroll_margin:4
+
+# Menu settings
+# OPTIONS=font_menu:Arial
+
+# Other
+OPTIONS=hilite_pet,!toptenwin
+OPTIONS=!splash_screen,player_selection:prompts
+OPTIONS=vary_msgcount:3
+OPTIONS=fullscreen,wraptext,softkeyboard
+
+# Status/message window colors
+# Possible color options include:
+# six digit hexadecimal RGB color value ("#8F8F8F"), black, red, green, brown,
+# blue, magenta, cyan, gray (or grey), orange, brightgreen, yellow, brightblue,
+# brightmagenta, brightcyan, white, trueblack, purple, silver, maroon, fuchsia,
+# lime, olive, navy, teal, aqua, activeborder, activecaption, appworkspace,
+# background, btnface, btnshadow, btntext, captiontext, graytext, highlight,
+# highlighttext, inactiveborder, inactivecaption, menu, menutext, scrollbar,
+# window, windowframe, windowtext.
+#OPTIONS=windowcolors:status windowtext/window message windowtext/window
+OPTIONS=windowcolors:status white/#000000 message white/#000000 menu white/#000000 text white/#000000
+
+#
+#HACKDIR=c:\games\nethack
+# 
+# Note: On Windows HACKDIR defaults to the location 
+#       of the NetHack.exe or NetHackw.exe file. 
+#       Setting HACKDIR above will override that.
+#
+#   LEVELS and SAVE default to HACKDIR
+#
+#LEVELS=c:\games\nethack\bones
+#SAVE=c:\games\nethack\bones
+
+# *** CHARACTER GRAPHICS ***
+#
+# See the on-line help or the Guidebook for which symbols are in which
+# positions.
+#
+# If you merely set the IBMgraphics option as above, NetHack will use IBM
+# extended ASCII for dungeon characters.  If you don't like the selections,
+# you can make up your own via these graphics options, but you should still
+# set IBMgraphics if you are using IBM graphics characters to get the correct
+# processing.
+#
+# ================================================
+# An example using the IBM graphics character set:
+#DUNGEON=  032 179 196 218 191 192 217 197 193 194 \
+#         180 195 249 239 239 254 254 240 241 249 \
+#         177 177 060 062 060 062 220 124 190 035 \
+#         244 247 249 247 042 042 186 205 046 035 \
+#         247
+#
+#TRAPS=    094 094 094 094 094 094 094 094 094 094 \
+#         094 094 094 094 232 232 232 157 094 094 \
+#         094 094
+#
+#EFFECTS=  179 196 092 047 042 033 041 040        \
+#         048 035 064 042                         \
+#         047 045 092 058 058 092 045 047         \
+#         047 045 092 058 032 058 092 045 047
+#
+# ================================================
+# Some alternatives:
+#DUNGEON=  032 186 205 201 187 200 188 206 202 203 \
+#         185 204 249 239 239 254 254 240 241 249 \
+#         177 177 060 062 060 062 095 124 092 035 \
+#         244 247 249 247 042 042 179 196 046 035 \
+#         247
+#
+#TRAPS=    094 094 094 094 094 094 094 094 094 094 \
+#         094 094 094 094 094 034 094 094 094 094 \
+#         094 094
+
+# ================================================
+# Here is a recommendation sent in by Michael Feir
+# for use by blind NetHack players.
+#
+#DUNGEON=  032 124 045 124 124 124 124 045 045 045 \
+#          124 124 046 045 124 043 043 046 035 035 \
+#          060 062 060 062 095 092 035 126 126 126 \
+#          126 042 042 035 035 032 035 126
+#
+#TRAPS=    094 094 094 094 094 094 094 094 094 094 \
+#          094 094 094 094 094 094 094 094 094 094 \
+#          094 094
+#
+#EFFECTS=  124 095 092 047 042 033 041 040         \
+#          048 035 064 042                         \
+#          047 045 092 058 058 092 045 047         \
+#          047 045 092 058 032 058 092 045 047
+
+
diff --git a/sys/wince/keypad.uu b/sys/wince/keypad.uu
new file mode 100644 (file)
index 0000000..b36f639
--- /dev/null
@@ -0,0 +1,8 @@
+begin 600 keypad.bmp
+M0DV^`````````#X````H````<`````@````!``$``````(``````````````
+M`````````````````/___P#__________________P``[__[____________
+M_R0``.?_\_?C]__W__?_]^MU``#CP>/GU?/AX\/OY_O5=0``X>/#Q\'QX\'C
+MS^?YZR4``/_W_^?5\^?_\^__^]5M``#____WX_?O__OW__?_)```________
+*__________\``.?5
+`
+end
diff --git a/sys/wince/menubar.uu b/sys/wince/menubar.uu
new file mode 100644 (file)
index 0000000..b4f07c5
--- /dev/null
@@ -0,0 +1,12 @@
+begin 600 menubar.bmp
+M0DUV`0```````'8````H````(````!`````!``0````````!````````````
+M````````````````````@```@````("``(````"``(``@(```,#`P`"`@(``
+M``#_``#_````__\`_P```/\`_P#__P``____`'=W=W=W=W=W=W=W=W=W=W=W
+M=W=W=W=W=W=W=W=W=W=W=$1$1$1$1'=W=W=W=W=W=W1$_T1/]$1W=W=W=W=W
+M=W=T1/_T__1$=W=W=W=W=W=W=/______]'=W=P<'!P=W=W3_______1W=W#P
+M\/#P=W=T3__T__]$=W</#P\/#P=W=$3_1$_T1'=P\/#P\/#P=W1/__3__T1W
+M=P\/#P\/!W=T_______T=W#P\/#P\/!W=/______]'=W!P<'!P<'=W1$__3_
+M]$1W=W=W=W=W=W=T1/]$3_1$=W=W=W=W=W=W=$1$1$1$1'=W=W=W=W=W=W=W
+.=W=W=W=W=W=W=W=W=W=$
+`
+end
diff --git a/sys/wince/mhaskyn.c b/sys/wince/mhaskyn.c
new file mode 100644 (file)
index 0000000..679f5ac
--- /dev/null
@@ -0,0 +1,12 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include <assert.h>
+#include "winMS.h"
+#include "mhaskyn.h"
+
+int mswin_yes_no_dialog( const char *question, const char *choices, int def)
+{
+       return '\032';
+}
+
diff --git a/sys/wince/mhaskyn.h b/sys/wince/mhaskyn.h
new file mode 100644 (file)
index 0000000..a386b09
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINAskYesNO_h
+#define MSWINAskYesNO_h
+
+#include "winMS.h"
+
+int mswin_yes_no_dialog( const char *question, const char *choices, int def);
+
+#endif /* MSWINAskYesNO_h */
diff --git a/sys/wince/mhcmd.c b/sys/wince/mhcmd.c
new file mode 100644 (file)
index 0000000..0ff3b76
--- /dev/null
@@ -0,0 +1,1378 @@
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include <assert.h>
+#include "mhcmd.h"
+#include "mhinput.h"
+#include "mhcolor.h"
+
+static TCHAR szNHCmdWindowClass[] = TEXT("MSNethackCmdWndClass");
+
+#ifndef C
+#  define C(c)         (0x1f & (c))
+#endif
+
+/* cell status 0 */
+#define NH_CST_CHECKED         1
+
+/* fonts */
+#define NH_CMDPAD_FONT_NORMAL    0
+#define NH_CMDPAD_FONT_MAX              0
+
+/* type of the cell */
+#define NH_CELL_REG                    0
+#define NH_CELL_CTRL           1
+#define NH_CELL_CAP                    2
+#define NH_CELL_SHIFT          3
+#define NH_CELL_LAYOUT_NEW     4
+#define NH_CELL_LAYOUT_MENU    5
+
+#define NH_CMDSET_MAXSIZE      64
+
+/* Keypad cell information 
+       NHCmdPadCell.cell_type    NHCmdPadCell.data
+       -----------               ----------
+       NH_CELL_REG                               (int)>=0 - index in the current keypad layout set (loads a new layout)
+                                  -1      - restore default (saved) layout 
+       NH_CELL_CTRL                      not used
+       NH_CELL_CAP                               not used
+       NH_CELL_SHIFT                     not used
+       NH_CELL_LAYOUT_NEW                pointer to the new keypad layout layout (NHCmdLayout*)
+       NH_CELL_LAYOUT_MENU       pointer to the layout set (NHCmdSet* - if NULL then nhcmdset_default is used)
+*/
+typedef struct t_NHCmdPadCell {
+       UINT            cmd_code;       /* Windows command code (menu processing - not implemented - set to -1) */
+       char            f_char[16];     /* nethack char */
+       char            text[16];       /* display text */
+       int                     image;          /* >0 - image ID in IDB_KEYPAD bitmap
+                                  <=0 - absolute index of the font table */
+       int                     type;           /* cell type */
+       int                     mult;           /* cell width multiplier */
+       void*           data;           /* internal data for the cell type */
+} NHCmdPadCell, *PNHCmdPadCell;
+
+/* command layout */
+typedef struct t_NHCmdLayout {
+       char                    name[64];
+       int                             rows;
+       int                             columns;
+       NHCmdPadCell    cells[];
+} NHCmdLayout, *PNHCmdLayout;
+
+/* set of command layouts */
+typedef struct t_NHCmdSet {
+       int count;
+       struct t_NHCmdSetElem {
+               PNHCmdLayout    layout;
+               BOOL                    free_on_destroy;
+       } elements[NH_CMDSET_MAXSIZE];
+} NHCmdSet, *PNHCmdSet;
+
+/* display cell layout */
+typedef struct t_NHCmdPadLayoutCell {
+       POINT   orig;           /* origin of the cell rect */
+       BYTE    type;           /* cell type */
+       int             state;          /* cell state */
+} NHCmdPadLayoutCell, *PNHCmdPadLayoutCell;
+
+/* command window data */
+typedef struct mswin_nethack_cmd_window {
+       SIZE                            cell_size;                                      /* cell size */
+       HFONT                           font[NH_CMDPAD_FONT_MAX+1];     /* fonts for cell text */
+       HBITMAP                         images;                                         /* key images map */
+       int                                     active_cell;                            /* current active cell */
+
+       boolean                         is_caps;                                        /* is CAPS selected */
+       boolean                         is_ctrl;                                        /* is CRTL selected */
+       boolean                         is_shift;                                       /* is SHIFT selected */
+
+       PNHCmdLayout            layout_current;                         /* current layout */
+       PNHCmdLayout            layout_save;                            /* saved layout */
+       PNHCmdPadLayoutCell     cells;                                          /* display cells */
+
+#if defined(WIN_CE_SMARTPHONE)
+       PNHCmdLayout            layout_selected;                        /* since we use 
+                                                                                                          layout command for menu also
+                                                          we need to store the layout 
+                                                                                                          that was selected by a user
+                                                                                                        */
+#endif
+} NHCmdWindow, *PNHCmdWindow;
+
+
+LRESULT CALLBACK NHCommandWndProc(HWND, UINT, WPARAM, LPARAM);
+static void register_command_window_class();
+static void LayoutCmdWindow(HWND hWnd);
+static void SetCmdWindowLayout(HWND hWnd, PNHCmdLayout layout);
+static int CellFromPoint(PNHCmdWindow data, POINT pt );
+static void CalculateCellSize(HWND hWnd, LPSIZE pSize, LPSIZE windowSize);
+static void HighlightCell(HWND hWnd, int cell, BOOL isSelected);
+static void ActivateCell(HWND hWnd, int cell);
+static void PushNethackCommand( const char* cmd_char_str, int is_ctrl );
+
+/*------------------- keyboard keys layout functions -----------------------*/
+PNHCmdLayout   nhcmdlayout_create( const char* name, int rows, int columns );
+void nhcmdlayout_init( PNHCmdLayout p, PNHCmdPadCell cells );
+#define nhcmdlayout_rows(p)                    ((p)->rows)
+#define nhcmdlayout_columns(p)         ((p)->columns)
+#define nhcmdlayout_row(p, x)          (&((p)->cells[(p)->columns*(x)]))
+#define nhcmdlayout_cell(p, x, y)      (&((p)->cells[(p)->columns*(x)+(y)]))
+#define nhcmdlayout_cell_direct(p, i)  (&((p)->cells[(i)]))
+void                   nhcmdlayout_destroy(PNHCmdLayout p);
+
+/*----------------- keyboard keys layout set functions ---------------------*/
+PNHCmdSet              nhcmdset_create();
+int                            nhcmdset_count( PNHCmdSet p );
+PNHCmdLayout   nhcmdset_get( PNHCmdSet p, int index );
+const char*            nhcmdset_get_name( PNHCmdSet p, int index );
+void                   nhcmdset_add( PNHCmdSet p, PNHCmdLayout layout );
+void                   nhcmdset_destroy( PNHCmdSet p);
+
+/*-------------------- message handlers -----------------------------------*/
+static void onPaint(HWND hWnd);                                // on WM_PAINT
+static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); // on WM_CREATE
+static void onMouseDown(HWND hWnd, WPARAM wParam, LPARAM lParam);      // on WM_LBUTTONDOWN
+static void onMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam);      // on WM_MOUSEMOVE
+static void onMouseUp(HWND hWnd, WPARAM wParam, LPARAM lParam);                // on WM_LBUTTONUP
+
+/*----------------------- static data -------------------------------------*/
+static PNHCmdSet nhcmdset_current = 0;
+static PNHCmdSet nhcmdset_default = 0;
+
+/*---------------------- Pre-definde keyboard layouts --------------------*/
+#ifdef WIN_CE_SMARTPHONE
+
+/* dimensions of the command pad */
+#define NH_CMDPAD_ROWS 4
+#define NH_CMDPAD_COLS 3
+#define NH_CMDPAD_CELLNUM (NH_CMDPAD_COLS*NH_CMDPAD_ROWS)
+
+/* layout indexes */
+#define NH_LAYOUT_GENERAL              0
+#define NH_LAYOUT_MOVEMENT             1
+#define NH_LAYOUT_ATTACK               2
+#define NH_LAYOUT_ITEM_HANDLING        3
+#define NH_LAYOUT_CONTROLS             4
+#define NH_LAYOUT_ADV_MOVEMENT 5
+
+/* template menu layout */
+NHCmdPadCell cells_layout_menu[NH_CMDPAD_CELLNUM] = 
+{ 
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
+       { -1, "", "<<", -NH_CMDPAD_FONT_NORMAL, NH_CELL_LAYOUT_NEW, 1 , NULL },
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
+       { -1, "", ">>", -NH_CMDPAD_FONT_NORMAL, NH_CELL_LAYOUT_NEW, 1 , NULL }
+};
+
+/* movement layout */
+NHCmdPadCell cells_layout_movement[NH_CMDPAD_CELLNUM] = 
+{
+       { -1, "7", "7", 1, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "8", "8", 2, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "9", "9", 3, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "4", "4", 4, NH_CELL_REG, 1, (void*)-1 },
+       { -1, ".", ".", 5, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "6", "6", 6, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "1", "1", 7, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "2", "2", 8, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "3", "3", 9, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "<", "<", 10, NH_CELL_REG, 1, (void*)-1 },
+       { -1, ">", ">", 12, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1, 0 }
+};
+
+/* attack layout */
+NHCmdPadCell cells_layout_attack[NH_CMDPAD_CELLNUM] = 
+{ 
+       { -1, "t", "t", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "w", "w", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "x", "x", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "f", "f", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "z", "z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "Z", "Z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "r", "r", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "a", "a", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "q", "q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "\x04", "^D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "F", "F", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 }
+};
+
+/* item handling layout */
+NHCmdPadCell cells_layout_item_handling[NH_CMDPAD_CELLNUM] = 
+{ 
+       { -1, "W", "W", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "P", "P", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "d", "d", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "T", "T", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "R", "R", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "D", "D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "=", "=", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "i", "i", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "[", "[", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "A", "A", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "I", "I", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 }
+};
+
+/* General */
+NHCmdPadCell cells_layout_general[NH_CMDPAD_CELLNUM] = 
+{ 
+       { -1, "q", "q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "e", "e", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "l", "l", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "s", "s", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "E", "E", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "\x04", "^D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "c", "c", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "o", "o", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "p", "p", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, ":", ":", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, ",", ",", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 }
+};
+
+/* game controls layout */
+NHCmdPadCell cells_layout_game[NH_CMDPAD_CELLNUM] = 
+{ 
+       { -1, "S", "S", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "h", "h", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "C", "C", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "@", "@", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "\\", "\\", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "O", "O", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "&", "&", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "\x18", "^X", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "\x10", "^P", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "X", "X", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "#", "#", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 }
+};
+
+/* advanced movement layout */
+NHCmdPadCell cells_layout_adv_movement[NH_CMDPAD_CELLNUM] = 
+{ 
+       { -1, "g", "g", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)NH_LAYOUT_MOVEMENT },
+       { -1, "G", "G", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)NH_LAYOUT_MOVEMENT },
+       { -1, "m", "m", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)NH_LAYOUT_MOVEMENT },
+       { -1, "M", "M", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)NH_LAYOUT_MOVEMENT },
+       { -1, "_", "_", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "\x14", "^T", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "j", "j", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 }
+};
+
+#else /* !WIN_CE_SMARTPHONE */
+
+/* dimensions of the command pad */
+#define NH_CMDPAD_ROWS 4
+#define NH_CMDPAD_COLS 14
+#define NH_CMDPAD_CELLNUM (NH_CMDPAD_COLS*NH_CMDPAD_ROWS)
+
+/* lowercase layout */
+NHCmdPadCell cells_layout_mod1[NH_CMDPAD_ROWS*NH_CMDPAD_COLS] = 
+{
+       { -1, "7", "7", 1, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "8", "8", 2, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "9", "9", 3, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "\x1b", "Esc", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 2 , NULL },
+               { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for ESC */
+       { -1, "?", "?", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "*", "*", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, ",", ",", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "/", "/", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, ":", ":", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, ";", ";", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "-", "-", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "#", "#", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "^", "^", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+
+       { -1, "4", "4", 4, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "5", "5", 5, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "6", "6", 6, NH_CELL_REG, 1, (void*)-1 },
+       { -1, " ", "CAP", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CAP, 2 , NULL },
+               { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for CAPS */
+       { -1, "a", "a", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "b", "b", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "c", "c", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "d", "d", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "e", "e", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "f", "f", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "g", "g", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "h", "h", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "i", "i", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+
+       { -1, "1", "1", 7, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "2", "2", 8, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "3", "3", 9, NH_CELL_REG, 1, (void*)-1 },
+       { -1, " ", "Shft", -NH_CMDPAD_FONT_NORMAL, NH_CELL_SHIFT, 2 , NULL },
+               { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for shift */
+       { -1, "j", "j", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "k", "k", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "l", "l", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "m", "m", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "n", "n", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "o", "o", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "p", "p", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "q", "q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "r", "r", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+
+       { -1, "<", "<", 10, NH_CELL_REG, 1, (void*)-1 },
+       { -1, ".", ".", 11, NH_CELL_REG, 1, (void*)-1 },
+       { -1, ">", ">", 12, NH_CELL_REG, 1, (void*)-1 },
+       { -1, " ", "Ctrl", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CTRL, 2 , NULL },
+               { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for CTRL */
+       { -1, "s", "s", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "t", "t", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "u", "u", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "v", "v", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "w", "w", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "x", "x", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "y", "y", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "z", "z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "\\", "\\", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }
+};
+
+/* uppercase layout */
+NHCmdPadCell cells_layout_mod2[-NH_CMDPAD_ROWS*-NH_CMDPAD_COLS] = 
+{ 
+       { -1, "7", "7", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "8", "8", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "9", "9", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "\x1b", "Esc", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 2 , NULL },
+               { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for ESC */
+       { -1, "?", "?", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "*", "*", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "[", "[", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "(", "(", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, ")", ")", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "+", "+", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "=", "=", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "\"", "\"", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "$", "$", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+
+       { -1, "4", "4", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "5", "5", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "6", "6", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, " ", "CAP", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CAP, 2 , NULL },
+               { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for CAPS */
+       { -1, "A", "A", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "B", "B", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "C", "C", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "D", "D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "E", "E", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "F", "F", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "G", "G", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "H", "H", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "I", "I", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+
+       { -1, "1", "1", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "2", "2", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "3", "3", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, " ", "Shft", -NH_CMDPAD_FONT_NORMAL, NH_CELL_SHIFT, 2 , NULL },
+               { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for shift */
+       { -1, "J", "J", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "K", "K", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "L", "L", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "M", "M", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "N", "N", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "O", "O", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "P", "P", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "Q", "Q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "R", "R", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+
+       { -1, "<", "<", 10, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "0", "0", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, ">", ">", 12, NH_CELL_REG, 1, (void*)-1 },
+       { -1, " ", "Ctrl", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CTRL, 2 , NULL },
+               { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for CTRL */
+       { -1, "S", "S", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "T", "T", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "U", "U", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "V", "V", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "W", "W", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "X", "X", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "Y", "Y", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "Z", "Z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
+       { -1, "@", "@", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }
+};
+
+#endif /* !WIN_CE_SMARTPHONE */
+
+/*-------------------------------------------------------------------------*/
+HWND mswin_init_command_window () {
+       static int run_once = 0;
+       HWND ret;
+
+       /* register window class */
+       if( !run_once ) {
+               register_command_window_class();
+               run_once = 1;
+       }
+
+       /* create window */
+       ret = CreateWindow(
+                       szNHCmdWindowClass,             /* registered class name */
+                       NULL,                                   /* window name */
+                       WS_CHILD | WS_CLIPSIBLINGS, /* window style */
+                       0,  /* horizontal position of window - set it later */
+                       0,  /* vertical position of window - set it later */
+                       0,  /* window width - set it later */
+                       0,  /* window height - set it later*/
+                       GetNHApp()->hMainWnd,   /* handle to parent or owner window */
+                       NULL,                                   /* menu handle or child identifier */
+                       GetNHApp()->hApp,               /* handle to application instance */
+                       NULL );                                 /* window-creation data */
+       if( !ret ) {
+               panic("Cannot create command window");
+       }
+       return ret;
+}
+/*-------------------------------------------------------------------------*/
+/* calculate mimimum window size */
+void mswin_command_window_size (HWND hwnd, LPSIZE sz)
+{
+       SIZE cell_size;
+       PNHCmdWindow data;
+       data = (PNHCmdWindow)GetWindowLong(hwnd, GWL_USERDATA);
+       if( !data ) {
+               sz->cx = sz->cy = 0;
+       } else {
+               CalculateCellSize(hwnd, &cell_size, sz);
+               sz->cx = max(
+                                       cell_size.cx*nhcmdlayout_columns(data->layout_current)+2*GetSystemMetrics(SM_CXBORDER),
+                                       sz->cx
+                                       );
+               sz->cy = max(
+                                       cell_size.cy*nhcmdlayout_rows(data->layout_current)+2*GetSystemMetrics(SM_CYBORDER),
+                                       sz->cy
+                                       );
+       }
+}
+/*-------------------------------------------------------------------------*/
+void register_command_window_class()
+{
+       WNDCLASS wcex;
+       PNHCmdLayout plt;
+       ZeroMemory( &wcex, sizeof(wcex));
+
+       /* window class */
+       wcex.style                      = CS_NOCLOSE;
+       wcex.lpfnWndProc        = (WNDPROC)NHCommandWndProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = GetNHApp()->hApp;
+       wcex.hIcon                      = NULL;
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = mswin_get_brush(NHW_KEYPAD, MSWIN_COLOR_BG);
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szNHCmdWindowClass;
+
+       if( !RegisterClass(&wcex) ) {
+               panic("cannot register Map window class");
+       }
+
+       /* create default command set */
+       nhcmdset_current = nhcmdset_default = nhcmdset_create();
+
+#ifdef WIN_CE_SMARTPHONE
+       plt = nhcmdlayout_create("General", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
+       nhcmdlayout_init(plt, cells_layout_general);
+       nhcmdset_add(nhcmdset_current, plt);
+
+       plt = nhcmdlayout_create("Movement", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
+       nhcmdlayout_init(plt, cells_layout_movement);
+       nhcmdset_add(nhcmdset_current, plt );
+
+       plt = nhcmdlayout_create("Attack", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
+       nhcmdlayout_init(plt, cells_layout_attack);
+       nhcmdset_add(nhcmdset_current, plt);
+
+       plt = nhcmdlayout_create("Item Handling", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
+       nhcmdlayout_init(plt, cells_layout_item_handling);
+       nhcmdset_add(nhcmdset_current, plt);
+
+       plt = nhcmdlayout_create("Game Controls", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
+       nhcmdlayout_init(plt, cells_layout_game);
+       nhcmdset_add(nhcmdset_current, plt);
+
+       plt = nhcmdlayout_create("Advanced Movement", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
+       nhcmdlayout_init(plt, cells_layout_adv_movement);
+       nhcmdset_add(nhcmdset_current, plt);
+#else /* ! WIN_CE_SMARTPHONE */
+       plt = nhcmdlayout_create("lowercase", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
+       nhcmdlayout_init(plt, cells_layout_mod1);
+       nhcmdset_add(nhcmdset_current, plt);
+
+       plt = nhcmdlayout_create("uppercase", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
+       nhcmdlayout_init(plt, cells_layout_mod2);
+       nhcmdset_add(nhcmdset_current, plt);
+#endif /* WIN_CE_SMARTPHONE */
+}
+/*-------------------------------------------------------------------------*/
+LRESULT CALLBACK NHCommandWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       PNHCmdWindow data;
+       int i;
+
+       switch (message) 
+       {
+       case WM_CREATE:
+               onCreate( hWnd, wParam, lParam );
+               break;
+
+       case WM_PAINT: 
+               onPaint(hWnd);
+               break;
+
+    case WM_SIZE:
+               LayoutCmdWindow(hWnd);
+               break;
+
+       case WM_LBUTTONDOWN:
+               onMouseDown(hWnd, wParam, lParam);
+               return 0;
+
+       case WM_MOUSEMOVE:
+               /* proceed only if if have mouse focus (set in onMouseDown() - 
+                  left mouse button is pressed) */
+               if( GetCapture()==hWnd ) { 
+                       onMouseMove(hWnd, wParam, lParam);
+                       return 0;
+               } else {
+                       return 1;
+               }
+               break;
+               
+       case WM_LBUTTONUP:
+               /* proceed only if if have mouse focus (set in onMouseDown()) */
+               if( GetCapture()==hWnd ) { 
+                       onMouseUp(hWnd, wParam, lParam);
+                       return 0;
+               } else {
+                       return 1;
+               }
+               break;
+
+       case WM_DESTROY:
+               data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
+               for(i=0; i<=NH_CMDPAD_FONT_MAX; i++ )
+                       if( data->font[i] ) DeleteObject(data->font[i]);
+               free(data);
+               SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+               break;
+
+       default:
+               return DefWindowProc(hWnd, message, wParam, lParam);
+       }
+       return FALSE;
+}
+/*-------------------------------------------------------------------------*/
+void onPaint(HWND hWnd)
+{
+       PNHCmdWindow data;
+       PAINTSTRUCT ps;
+       HDC hDC;
+       int x, y;
+       TCHAR wbuf[BUFSZ];
+       HGDIOBJ saveFont;
+       BITMAP  bm;
+       int  cell_index;
+
+       /* get window data */
+       data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       hDC = BeginPaint(hWnd, &ps);
+
+       if( !IsRectEmpty(&ps.rcPaint) ) {
+               HGDIOBJ oldBr;
+               HBRUSH hbrPattern;
+               COLORREF OldBg, OldFg;
+               HPEN hPen;
+               HGDIOBJ hOldPen;
+
+               saveFont = SelectObject(hDC, data->font[NH_CMDPAD_FONT_NORMAL]);
+               OldBg = SetBkColor(hDC, mswin_get_color(NHW_KEYPAD, MSWIN_COLOR_BG));
+               OldFg = SetTextColor(hDC, mswin_get_color(NHW_KEYPAD, MSWIN_COLOR_FG)); 
+
+               GetObject(data->images, sizeof(BITMAP), (LPVOID)&bm);
+
+               hbrPattern = CreatePatternBrush(data->images);
+               hPen = CreatePen(PS_SOLID, 1, mswin_get_color(NHW_KEYPAD, MSWIN_COLOR_FG));
+
+               for( x=0, cell_index = 0; x<nhcmdlayout_rows(data->layout_current); x++ )
+               for( y=0; y<nhcmdlayout_columns(data->layout_current); y++, cell_index++ ) {
+                       RECT cell_rt;
+                       POINT pt[5];
+                       PNHCmdPadCell p_cell_data;
+
+                       p_cell_data = nhcmdlayout_cell_direct(data->layout_current, cell_index);
+
+                       /* calculate the cell rectangle */
+                       cell_rt.left = data->cells[cell_index].orig.x;
+                       cell_rt.top = data->cells[cell_index].orig.y;
+                       cell_rt.right = data->cells[cell_index].orig.x + data->cell_size.cx*p_cell_data->mult;
+                       cell_rt.bottom = data->cells[cell_index].orig.y + data->cell_size.cy;
+
+                       /* draw border */
+                       hOldPen = SelectObject(hDC, hPen);
+                       pt[0].x = cell_rt.left;
+                       pt[0].y = cell_rt.top;
+                       pt[1].x = cell_rt.right;
+                       pt[1].y = cell_rt.top;
+                       pt[2].x = cell_rt.right;
+                       pt[2].y = cell_rt.bottom;
+                       pt[3].x = cell_rt.left;
+                       pt[3].y = cell_rt.bottom;
+                       pt[4].x = cell_rt.left;
+                       pt[4].y = cell_rt.top;
+                       Polyline(hDC, pt, 5);
+                       SelectObject(hDC, hOldPen);
+
+                       /* calculate clipping rectangle for the text */
+                       cell_rt.left++;
+                       cell_rt.top ++;
+                       cell_rt.right--;
+                       cell_rt.bottom--;
+
+                       /* draw the cell text */
+                       if( p_cell_data->image<=0 ) {
+                               SelectObject(hDC, data->font[ -p_cell_data->image ]);
+                               DrawText(hDC, 
+                                               NH_A2W(p_cell_data->text, wbuf, BUFSZ), 
+                                               strlen(p_cell_data->text),
+                                               &cell_rt,
+                                               DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX
+                                               );
+                       } else {
+                               /* draw bitmap */
+                               int bmOffset;
+                               RECT bitmap_rt;
+
+                               bmOffset = (p_cell_data->image - 1)*bm.bmHeight;
+
+                               bitmap_rt.left = ((cell_rt.left+cell_rt.right) - min(bm.bmHeight, (cell_rt.right-cell_rt.left)))/2;
+                               bitmap_rt.top = ((cell_rt.bottom+cell_rt.top) - min(bm.bmHeight, (cell_rt.bottom-cell_rt.top)))/2;
+                               bitmap_rt.right = bitmap_rt.left + min(bm.bmHeight, (cell_rt.right-cell_rt.left));
+                               bitmap_rt.bottom = bitmap_rt.top + min(bm.bmHeight, (cell_rt.bottom-cell_rt.top));
+
+                               SetBrushOrgEx(hDC, bitmap_rt.left-bmOffset, bitmap_rt.top, NULL);
+                               oldBr = SelectObject(hDC, hbrPattern);
+                               PatBlt( 
+                                       hDC, 
+                                       bitmap_rt.left, 
+                                       bitmap_rt.top, 
+                                       bitmap_rt.right-bitmap_rt.left, 
+                                       bitmap_rt.bottom-bitmap_rt.top,
+                                       PATCOPY);
+                               SelectObject(hDC, oldBr);
+                       }
+
+                       /* invert the cell if it is selected */
+                       if( data->cells[cell_index].state == NH_CST_CHECKED ) {
+                               IntersectRect( &cell_rt, &cell_rt, &ps.rcPaint);
+                               PatBlt( hDC, 
+                                               cell_rt.left,
+                                               cell_rt.top,
+                                               cell_rt.right - cell_rt.left,
+                                               cell_rt.bottom - cell_rt.top,
+                                               DSTINVERT
+                                               );
+                       }
+               }
+
+               SetTextColor(hDC, OldFg);
+               SetBkColor(hDC, OldBg);
+               SelectObject(hDC, saveFont);
+               DeleteObject(hbrPattern);
+               DeleteObject(hPen);
+       }
+       EndPaint(hWnd, &ps);
+}
+/*-------------------------------------------------------------------------*/
+void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHCmdWindow data;
+
+       /* set window data */
+       data = (PNHCmdWindow)malloc(sizeof(NHCmdWindow));
+       if( !data ) panic("out of memory");
+
+       ZeroMemory(data, sizeof(NHCmdWindow));
+       SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
+
+       data->active_cell = -1;
+
+       /* load images bitmap */
+       data->images = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_KEYPAD));
+       if( !data->images ) panic("cannot load keypad bitmap");
+
+       /* create default layouts */
+       data->layout_current = 0;
+       data->layout_save = 0;
+       data->cells = 0;
+
+#if defined(WIN_CE_SMARTPHONE)
+       data->layout_selected = nhcmdset_get(nhcmdset_current, 0);
+#endif
+
+       /* set default layout */
+       SetCmdWindowLayout(hWnd, nhcmdset_get(nhcmdset_current, 0));
+}
+/*-------------------------------------------------------------------------*/
+void LayoutCmdWindow(HWND hWnd)
+{
+       RECT clrt;
+       SIZE windowSize;
+       PNHCmdWindow data;
+       int i, j;
+       int x, y;
+       LOGFONT lgfnt;
+       int index;
+
+       GetClientRect(hWnd, &clrt);
+       if( IsRectEmpty(&clrt) ) return;
+
+       data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if( !data->layout_current ) return;
+
+       /* calculate cell size */
+       windowSize.cx = clrt.right-clrt.left;
+       windowSize.cy = clrt.bottom-clrt.top;
+       CalculateCellSize(hWnd, &data->cell_size, &windowSize);
+        
+       /* initialize display cells aray */
+       x = 0;
+       y = 0;
+       for( i=0, index=0; i<nhcmdlayout_rows(data->layout_current); i++ ) {
+               for( j=0; j<nhcmdlayout_columns(data->layout_current); j++, index++ ) {
+                       data->cells[index].orig.x = x;
+                       data->cells[index].orig.y = y;
+                       data->cells[index].type = nhcmdlayout_cell_direct(data->layout_current, index)->type;
+
+                       switch(data->cells[index].type) {
+                       case NH_CELL_CTRL:
+                               data->cells[index].state = data->is_ctrl? NH_CST_CHECKED : 0;
+                               break;
+                       case NH_CELL_CAP:
+                               data->cells[index].state = data->is_caps? NH_CST_CHECKED : 0;
+                               break;
+                       case NH_CELL_SHIFT:
+                               data->cells[index].state = data->is_shift? NH_CST_CHECKED : 0;
+                               break;
+                       default:
+                               data->cells[index].state = 0;
+                       }
+
+                       x += data->cell_size.cx * nhcmdlayout_cell_direct(data->layout_current, index)->mult;
+               }
+               x = 0;
+               y += data->cell_size.cy;
+       }
+
+       /* create font for display cell text */
+       for(i=0; i<=NH_CMDPAD_FONT_MAX; i++ )
+               if( data->font[i] ) DeleteObject(data->font[i]);
+
+       ZeroMemory( &lgfnt, sizeof(lgfnt) );
+       lgfnt.lfHeight                  =       data->cell_size.cy; // height of font
+       lgfnt.lfWidth                   =       0; // average character width
+       lgfnt.lfEscapement              =       0;                                       // angle of escapement
+       lgfnt.lfOrientation             =       0;                                       // base-line orientation angle
+       lgfnt.lfWeight                  =       FW_NORMAL;                      // font weight
+       lgfnt.lfItalic                  =       FALSE;                       // italic attribute option
+       lgfnt.lfUnderline               =       FALSE;                          // underline attribute option
+       lgfnt.lfStrikeOut               =       FALSE;                          // strikeout attribute option
+       lgfnt.lfCharSet                 =       ANSI_CHARSET;     // character set identifier
+       lgfnt.lfOutPrecision    =       OUT_DEFAULT_PRECIS;  // output precision
+       lgfnt.lfClipPrecision   =       CLIP_CHARACTER_PRECIS; // clipping precision
+       lgfnt.lfQuality                 =       DEFAULT_QUALITY;     // output quality
+       if( iflags.wc_font_message &&
+               *iflags.wc_font_message ) {
+               lgfnt.lfPitchAndFamily  = DEFAULT_PITCH;                 // pitch and family
+               NH_A2W( iflags.wc_font_message, lgfnt.lfFaceName, LF_FACESIZE);
+       } else {
+               lgfnt.lfPitchAndFamily  = VARIABLE_PITCH;                // pitch and family
+       }
+       data->font[NH_CMDPAD_FONT_NORMAL] = CreateFontIndirect(&lgfnt);
+
+       InvalidateRect(hWnd, NULL, TRUE);
+}
+/*-------------------------------------------------------------------------*/
+void SetCmdWindowLayout(HWND hWnd, PNHCmdLayout layout)
+{
+       PNHCmdWindow data;
+       int size;
+
+       data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if( data->layout_current == layout ) return;
+
+       data->layout_current = layout;
+       size = sizeof(NHCmdPadLayoutCell)*nhcmdlayout_rows(layout)*nhcmdlayout_columns(layout);
+       data->cells = (PNHCmdPadLayoutCell)realloc(data->cells, size);
+       ZeroMemory(data->cells, size);
+       LayoutCmdWindow(hWnd);
+}
+/*-------------------------------------------------------------------------*/
+void onMouseDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHCmdWindow data;
+       POINT mpt;
+
+       /* get mouse coordinates */
+       mpt.x = LOWORD(lParam);
+       mpt.y = HIWORD(lParam);
+
+       /* map mouse coordinates to the display cell */
+       data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       data->active_cell = CellFromPoint(data, mpt);
+       if( data->active_cell==-1 ) return;
+
+       /* set mouse focus to the current window */
+       SetCapture(hWnd);
+
+       /* invert the selection */
+       HighlightCell(hWnd, data->active_cell, (data->cells[data->active_cell].state!=NH_CST_CHECKED) );
+}
+/*-------------------------------------------------------------------------*/
+void onMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHCmdWindow data;
+       POINT mpt;
+       int newActiveCell;
+
+       /* get mouse coordinates */
+       mpt.x = LOWORD(lParam);
+       mpt.y = HIWORD(lParam);
+
+       /* map mouse coordinates to the display cell */
+       data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       newActiveCell = CellFromPoint(data, mpt);
+       if( data->active_cell == -1 ) return;
+
+       /* if mouse is within orginal display cell - select the cell otherwise
+          clear the selection */
+       switch( nhcmdlayout_cell_direct(data->layout_current, data->active_cell)->type ) {
+       case NH_CELL_REG: 
+               HighlightCell(hWnd, data->active_cell, 
+                              (newActiveCell==data->active_cell) );
+               break;
+
+       case NH_CELL_CTRL:
+               HighlightCell(hWnd, data->active_cell, 
+                       ((newActiveCell==data->active_cell)? !data->is_ctrl : data->is_ctrl) );
+               break;
+
+       case NH_CELL_CAP:
+               HighlightCell(hWnd, data->active_cell, 
+                       ((newActiveCell==data->active_cell)? !data->is_caps : data->is_caps) );
+               break;
+       }
+}
+/*-------------------------------------------------------------------------*/
+void onMouseUp(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHCmdWindow data;
+
+       /* release mouse capture */
+       ReleaseCapture();
+
+       /* get active display cell */
+       data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if( data->active_cell == -1 ) return;
+
+       ActivateCell(hWnd, data->active_cell);
+
+       data->active_cell = -1;
+}
+/*-------------------------------------------------------------------------*/
+void ActivateCell(HWND hWnd, int cell)
+{
+       PNHCmdWindow data;
+       PNHCmdPadCell p_cell_data;
+       int i;
+
+       data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if( !data ) return;
+       p_cell_data = nhcmdlayout_cell_direct(data->layout_current, cell);
+
+       /* act depending on the cell type:
+               CAPS - change layout 
+               CTRL - modify CTRL status
+               REG  - place keyboard event on the nethack input queue
+       */
+       switch( p_cell_data->type ) {
+       case NH_CELL_REG: 
+               if( data->is_ctrl ) {
+                       PushNethackCommand(p_cell_data->f_char, 1);
+
+                       data->is_ctrl = 0;
+                       for( i=0; i<nhcmdlayout_rows(data->layout_current)*nhcmdlayout_columns(data->layout_current); i++ ) {
+                               if( nhcmdlayout_cell_direct(data->layout_current, i)->type == NH_CELL_CTRL ) {
+                                       HighlightCell(hWnd, i, data->is_ctrl);
+                               }
+                       }
+               } else {
+                       PushNethackCommand(p_cell_data->f_char, 0);
+               }
+               HighlightCell(hWnd, cell, FALSE);
+
+               // select a new layout if present
+               i = (int)p_cell_data->data;
+               if( i==-1 ) {
+                       if( data->layout_save ) SetCmdWindowLayout(hWnd, data->layout_save);
+                       data->layout_save = NULL;
+               } else {
+                       if( !data->layout_save ) data->layout_save = data->layout_current;
+                       SetCmdWindowLayout(hWnd, nhcmdset_get(nhcmdset_current, i));
+               }
+
+               if( !data->is_shift ) break;
+               // else fall through and reset the shift
+
+       case NH_CELL_SHIFT:
+               data->is_shift = !data->is_shift;
+               SetCmdWindowLayout(
+                       hWnd,
+                       (data->is_shift ^ data->is_caps)? nhcmdset_get(nhcmdset_current, 1) : nhcmdset_get(nhcmdset_current, 0)
+               );
+               data->cells[cell].state = data->is_shift? NH_CST_CHECKED : 0;
+               InvalidateRect(hWnd, NULL, TRUE);
+               break;
+
+       case NH_CELL_CTRL:
+               data->is_ctrl = !data->is_ctrl;
+               HighlightCell(hWnd, cell, data->is_ctrl);
+               break;
+
+       case NH_CELL_CAP:
+               data->is_caps = !data->is_caps;
+               SetCmdWindowLayout(
+                       hWnd,
+                       (data->is_shift ^ data->is_caps)? nhcmdset_get(nhcmdset_current, 1) : nhcmdset_get(nhcmdset_current, 0)
+               );
+               data->cells[cell].state = data->is_caps? NH_CST_CHECKED : 0;
+               InvalidateRect(hWnd, NULL, TRUE);
+               break;
+
+       case NH_CELL_LAYOUT_NEW: {
+               PNHCmdLayout pLayout;
+
+               HighlightCell(hWnd, cell, FALSE);
+
+               pLayout = (PNHCmdLayout)p_cell_data->data;
+               if( pLayout ) {
+                       SetCmdWindowLayout(hWnd, pLayout);
+               }
+       } break;
+       
+       case NH_CELL_LAYOUT_MENU: {
+               winid wid;
+               int i;
+               anything any;
+               menu_item* selected = 0;
+               PNHCmdSet pSet;
+
+               HighlightCell(hWnd, cell, FALSE);
+
+               pSet = (PNHCmdSet)p_cell_data->data;
+               if( !pSet ) pSet = nhcmdset_default;
+
+               wid = mswin_create_nhwindow(NHW_MENU);
+               mswin_start_menu(wid);
+               for( i=0; i<nhcmdset_count(pSet); i++ ) {
+                       any.a_void = nhcmdset_get(pSet, i);
+                       mswin_add_menu(wid, NO_GLYPH, &any, 'a'+i, 0, ATR_NONE, 
+                               nhcmdset_get_name(pSet, i), FALSE);
+               }
+               mswin_end_menu(wid, "Select keypad layout");
+           i = select_menu(wid, PICK_ONE, &selected);
+           mswin_destroy_nhwindow(wid);
+
+               if( i==1 ) {
+#if defined(WIN_CE_SMARTPHONE)
+                       data->layout_selected = (PNHCmdLayout)selected[0].item.a_void;
+#endif
+                       SetCmdWindowLayout(hWnd, (PNHCmdLayout)selected[0].item.a_void );
+               }
+       } break;
+       
+       }
+}
+/*-------------------------------------------------------------------------*/
+int CellFromPoint(PNHCmdWindow data, POINT pt )
+{
+       int i;
+       for( i=0; i<nhcmdlayout_rows(data->layout_current)*nhcmdlayout_columns(data->layout_current); i++ ) {
+               RECT cell_rt;
+               cell_rt.left = data->cells[i].orig.x;
+               cell_rt.top = data->cells[i].orig.y;
+               cell_rt.right = data->cells[i].orig.x + data->cell_size.cx*nhcmdlayout_cell_direct(data->layout_current, i)->mult;
+               cell_rt.bottom = data->cells[i].orig.y + data->cell_size.cy;
+               if( PtInRect(&cell_rt, pt) ) return i;
+       }
+       return -1;
+}
+/*-------------------------------------------------------------------------*/
+void CalculateCellSize(HWND hWnd, LPSIZE pSize, LPSIZE pWindowSize)
+{
+       HDC hdc;
+       PNHCmdWindow data;
+       data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if( !data ) return;
+
+       hdc = GetDC(hWnd);
+       
+       /* if windows size is specified - attempt ro stretch cells across 
+          the the window size. If not - make default cell size based on 
+          10 points font. Make sure that cell cesize does not exceeds 20 points */
+       if( pWindowSize->cx>0 )
+               pSize->cx = pWindowSize->cx/nhcmdlayout_columns(data->layout_current);
+       else 
+               pSize->cx = 10*GetDeviceCaps(hdc, LOGPIXELSX)/72;
+       pSize->cx = min(pSize->cx, 20*GetDeviceCaps(hdc, LOGPIXELSX)/72 );
+
+       if( pWindowSize->cy>0 )
+               pSize->cy = pWindowSize->cy/nhcmdlayout_rows(data->layout_current);
+       else                     
+               pSize->cy = 10*GetDeviceCaps(hdc, LOGPIXELSY)/72;
+       pSize->cy = min(pSize->cy, 20*GetDeviceCaps(hdc, LOGPIXELSY)/72 );
+
+       ReleaseDC(hWnd, hdc);
+}
+/*-------------------------------------------------------------------------*/
+void HighlightCell(HWND hWnd, int cell, BOOL isSelected)
+{
+       HDC hDC;
+       PNHCmdWindow data;
+       int prevState;
+
+       data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       prevState = data->cells[cell].state;
+       data->cells[cell].state = (isSelected)? NH_CST_CHECKED : 0;
+
+       if( prevState!=data->cells[cell].state ) {
+               hDC = GetDC(hWnd);
+               PatBlt( hDC, 
+                       data->cells[cell].orig.x+1,
+                       data->cells[cell].orig.y+1,
+                       data->cell_size.cx*nhcmdlayout_cell_direct(data->layout_current, cell)->mult - 2,
+                       data->cell_size.cy - 2,
+                       DSTINVERT
+                       );
+               ReleaseDC(hWnd, hDC);
+       }
+}
+/*-------------------------------------------------------------------------*/
+void PushNethackCommand( const char* cmd_char_str, int is_ctrl )
+{
+       while( *cmd_char_str ) {
+               if( is_ctrl ) { NHEVENT_KBD( C(*cmd_char_str) ); }
+               else              { NHEVENT_KBD( *cmd_char_str ); }
+               cmd_char_str++;
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+/*------------------- keyboard keys layout functions ----------------------*/
+/*-------------------------------------------------------------------------*/
+PNHCmdLayout nhcmdlayout_create(const char* name, int rows, int columns)
+{
+       PNHCmdLayout p;
+       int i;
+
+       i = sizeof(NHCmdLayout)+rows*columns*sizeof(NHCmdPadCell);
+       p = (PNHCmdLayout)malloc(i);
+       ZeroMemory(p, i);
+       p->rows = rows;
+       p->columns = columns;
+       strncpy(p->name, name, sizeof(p->name)-1);
+       for(i=0; i<rows*columns; i++) {
+               p->cells[i].cmd_code = -1;
+               p->cells[i].image = -NH_CMDPAD_FONT_NORMAL;
+               p->cells[i].type = 1;
+               p->cells[i].mult = 1;
+       }
+       return p;
+}
+/*-------------------------------------------------------------------------*/
+void nhcmdlayout_init( PNHCmdLayout p, PNHCmdPadCell cells )
+{
+       memcpy(p->cells, cells, p->rows*p->columns*sizeof(NHCmdPadCell));
+}
+
+void nhcmdlayout_destroy(PNHCmdLayout p)
+{
+       free(p);
+}
+
+/*-------------------------------------------------------------------------*/
+/*----------------- keyboard keys layout set functions --------------------*/
+/*-------------------------------------------------------------------------*/
+PNHCmdSet nhcmdset_create()
+{
+       PNHCmdSet p;
+       p = (PNHCmdSet)malloc(sizeof(NHCmdSet));
+       ZeroMemory(p, sizeof(NHCmdSet));
+       return p;
+}
+/*-------------------------------------------------------------------------*/
+int nhcmdset_count(PNHCmdSet p)
+{
+       assert(p);
+       return p->count;
+}
+/*-------------------------------------------------------------------------*/
+PNHCmdLayout nhcmdset_get( PNHCmdSet p, int index )
+{
+       assert(p);
+       assert(index>=0 && index<p->count);
+       return p->elements[index].layout;
+}
+/*-------------------------------------------------------------------------*/
+const char*    nhcmdset_get_name( PNHCmdSet p, int index )
+{
+       assert(p);
+       assert(index>=0 && index<p->count);
+       return p->elements[index].layout->name;
+}
+/*-------------------------------------------------------------------------*/
+void nhcmdset_add( PNHCmdSet p, PNHCmdLayout layout )
+{
+       assert(p);
+       assert(p->count<NH_CMDSET_MAXSIZE);
+       p->elements[p->count].layout = layout;
+       p->elements[p->count].free_on_destroy = 0;
+       p->count++;
+}
+/*-------------------------------------------------------------------------*/
+void nhcmdset_destroy(PNHCmdSet p)
+{
+       int i=0;
+       assert(p);
+       for(i=0; i<p->count; i++) {
+               if( p->elements[i].free_on_destroy ) {
+                       nhcmdlayout_destroy( p->elements[i].layout );
+               }
+       }
+       free(p);
+}
+/*-------------------------------------------------------------------------*/
+
+
+#if defined(WIN_CE_SMARTPHONE)
+/* special keypad input handling for SmartPhone
+   the phone keypad maps to VK_* as shown below.
+   some keys might not be present, e.g. VK_TFLIP
+    sofkey1     softkey2    VK_TSOFT1, VK_TSOFT2
+            ^               VK_TUP
+        <   +   >           VK_TLEFT, VK_TACTION, VK_TRIGHT
+            v               VK_TDOWN
+    home        back        VK_THOME, VK_TBACK
+    talk        end         VK_TTALK, VK_TEND
+    1       2       3       VK_T0..VK_T9
+    4       5       6       ...
+    7       8       9       ...
+    *       0       #       VK_TSTAR, VK_TPOUND
+   other buttons include
+    VK_TRECORD
+    VK_TPOWER, VK_TVOLUMEUP, VK_TVOLUMEDOWN
+    VK_TFLIP
+*/
+BOOL NHSPhoneTranslateKbdMessage(WPARAM wParam, LPARAM lParam, BOOL keyDown)
+{
+       PNHCmdWindow data;
+       int index = -1;
+
+       /* get window data */
+       data = (PNHCmdWindow)GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA);
+       if( !data ) return FALSE;
+
+       switch (wParam) {
+    case VK_T0: 
+               index = 10; 
+       break;
+
+    case VK_T1: 
+               index = 0; 
+       break;
+
+    case VK_T2: 
+               index = 1; 
+       break;
+
+    case VK_T3: 
+               index = 2; 
+       break;
+
+    case VK_T4: 
+               index = 3; 
+       break;
+
+    case VK_T5: 
+               index = 4; 
+       break;
+
+    case VK_T6: 
+               index = 5; 
+       break;
+
+    case VK_T7: 
+               index = 6; 
+       break;
+
+    case VK_T8: 
+               index = 7; 
+       break;
+
+    case VK_T9: 
+               index = 8; 
+       break;
+
+       case VK_TSTAR:
+               index = 9; 
+       break;
+       
+       case VK_TPOUND: 
+               index = 11;
+       break;
+       }
+
+       if( index>=0 ) {
+               HighlightCell(GetNHApp()->hCmdWnd, index, keyDown);
+               if( keyDown ) ActivateCell(GetNHApp()->hCmdWnd, index);
+               return TRUE;
+       } else {
+               return FALSE;
+       }
+}
+/*-------------------------------------------------------------------------*/
+void NHSPhoneSetKeypadFromString(const char* str)
+{
+       PNHCmdWindow data;
+       PNHCmdSet p = 0;
+       PNHCmdLayout layout_prev = 0;
+       PNHCmdLayout layout_cur = 0;
+       char buf[2][BUFSZ];
+       int i, lcount;
+       char *s;
+
+       assert(NH_CMDPAD_ROWS==4);
+
+       data = (PNHCmdWindow)GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA);
+       if( !data ) return;
+
+       p = nhcmdset_create();
+
+       ZeroMemory(buf, sizeof(buf));
+       if( sscanf(str, "%s or %s", buf[1], buf[0])!=2 ) {
+               ZeroMemory(buf, sizeof(buf));
+               strncpy(buf[0], str, sizeof(buf[0])-1);
+       }
+
+       lcount = 10; /* create new layout on the first iteration */
+       for(i=0; i<2; i++) {
+               s = buf[i];
+               while( *s ) {
+                       char c_start, c_end, c_char;
+
+                       /* parse character ranges */
+                       if( isalnum( (c_start=s[0]) ) &&
+                               s[1]=='-' &&
+                               isalnum( (c_end=s[2]) ) ) {
+                               s += 2;
+                       } else {
+                               c_start = c_end = *s;
+                       }
+                       
+                       for( c_char=c_start; c_char<=c_end; c_char++ ) {
+                               if( lcount>=10 ) {
+                                       /* create layout */
+                                       lcount = 0;
+                                       layout_prev = layout_cur;
+                                       layout_cur = nhcmdlayout_create("noname", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
+                                       nhcmdlayout_init(layout_cur, cells_layout_menu);
+
+                                       nhcmdlayout_cell(layout_cur, 3, 0)->data = layout_prev;
+                                       nhcmdlayout_cell(layout_cur, 3, 2)->data = 0;
+
+                                       nhcmdset_add( p, layout_cur );
+                                       p->elements[p->count-1].free_on_destroy = 1;
+
+                                       if( layout_prev ) {
+                                               nhcmdlayout_cell(layout_prev, 3, 2)->data = layout_cur;
+                                       }
+                               }
+
+                               if( lcount==9 ) lcount=10; // skip '#'
+                               nhcmdlayout_cell_direct(layout_cur, lcount)->f_char[0] = c_char;
+                               if( c_char == '\033' ) {
+                                       strcpy(nhcmdlayout_cell_direct(layout_cur, lcount)->text, "esc");
+                                       nhcmdlayout_cell_direct(layout_cur, lcount)->image = 14; /* 14 is a ESC symbol in IDB_KEYPAD */
+                               } else {
+                                       nhcmdlayout_cell_direct(layout_cur, lcount)->text[0] = c_char;
+                                       nhcmdlayout_cell_direct(layout_cur, lcount)->text[1] = '\x0';
+                               }
+
+                               /* increment character count in the current layout */
+                               lcount++;
+                       }
+
+                       /* prepareg next charcter from the source string */
+                       s++;
+               }
+       }
+
+       /* install the new set */
+       if( nhcmdset_current!=nhcmdset_default ) nhcmdset_destroy( nhcmdset_current );
+       nhcmdset_current = p;
+       SetCmdWindowLayout(
+                       GetNHApp()->hCmdWnd,
+                       nhcmdset_get(nhcmdset_current, 0)
+       );
+}
+/*-------------------------------------------------------------------------*/
+void NHSPhoneSetKeypadDirection()
+{
+       PNHCmdWindow data;
+
+       data = (PNHCmdWindow)GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA);
+       if( !data ) return;
+
+       if( nhcmdset_current!=nhcmdset_default ) nhcmdset_destroy( nhcmdset_current );
+       nhcmdset_current = nhcmdset_default;
+       SetCmdWindowLayout(
+               GetNHApp()->hCmdWnd,
+               nhcmdset_get(nhcmdset_current, NH_LAYOUT_MOVEMENT)
+       );
+}
+/*-------------------------------------------------------------------------*/
+void NHSPhoneSetKeypadDefault()
+{
+       PNHCmdWindow data;
+
+       data = (PNHCmdWindow)GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA);
+       if( !data ) return;
+
+       if( nhcmdset_current!=nhcmdset_default ) nhcmdset_destroy( nhcmdset_current );
+       nhcmdset_current = nhcmdset_default;
+       SetCmdWindowLayout(
+               GetNHApp()->hCmdWnd,
+               data->layout_selected ? data->layout_selected : nhcmdset_get(nhcmdset_current, 0)
+       );
+}
+
+#endif /* defined (WIN_CE_SMARTHPONE) */
diff --git a/sys/wince/mhcmd.h b/sys/wince/mhcmd.h
new file mode 100644 (file)
index 0000000..87f4f4b
--- /dev/null
@@ -0,0 +1,25 @@
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINCMDWindow_h
+#define MSWINCMDWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+HWND mswin_init_command_window ();
+
+/* if either sz->cx or sz->cy are already set this function will 
+   no modify it. It will adjust them to the minimum size 
+   required by the command window */
+void mswin_command_window_size (HWND hwnd, LPSIZE sz);
+
+#if defined(WIN_CE_SMARTPHONE)
+/* special keypad input handling for SmartPhone */
+BOOL   NHSPhoneTranslateKbdMessage(WPARAM wParam, LPARAM lParam, BOOL keyDown);
+void   NHSPhoneSetKeypadFromString(const char* str);
+void   NHSPhoneSetKeypadDirection();
+void   NHSPhoneSetKeypadDefault();
+#endif
+
+#endif /* MSWINCMDWindow_h */
diff --git a/sys/wince/mhcolor.c b/sys/wince/mhcolor.c
new file mode 100644 (file)
index 0000000..0e32db1
--- /dev/null
@@ -0,0 +1,217 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* color management and such */
+
+#include "winMS.h"
+#include "mhcolor.h"
+
+#define TOTAL_BRUSHES  10
+#define NHBRUSH_CODE(win, type) ((((win)&0xFF)<<8)|((type)&0xFF))
+
+struct t_brush_table {
+       int             code;
+       HBRUSH  brush;
+       COLORREF color;
+};
+static struct t_brush_table brush_table[TOTAL_BRUSHES];
+static int max_brush = 0;
+
+static struct t_brush_table default_brush_table[] = 
+{
+       { NHBRUSH_CODE(NHW_STATUS, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) },
+       { NHBRUSH_CODE(NHW_MESSAGE, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) },
+       { NHBRUSH_CODE(NHW_STATUS, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) },
+       { NHBRUSH_CODE(NHW_TEXT, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) },
+       { NHBRUSH_CODE(NHW_KEYPAD, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) },
+       { NHBRUSH_CODE(NHW_MAP, MSWIN_COLOR_FG), NULL, RGB(96, 96, 96) },
+
+       { NHBRUSH_CODE(NHW_MENU, MSWIN_COLOR_BG), NULL, RGB(255, 255, 255) },
+       { NHBRUSH_CODE(NHW_MESSAGE, MSWIN_COLOR_BG), NULL, RGB(192, 192, 192) },
+       { NHBRUSH_CODE(NHW_STATUS, MSWIN_COLOR_BG), NULL, RGB(192, 192, 192) },
+       { NHBRUSH_CODE(NHW_TEXT, MSWIN_COLOR_BG), NULL, RGB(255, 255, 255) },
+       { NHBRUSH_CODE(NHW_KEYPAD, MSWIN_COLOR_BG), NULL, RGB(255, 255, 255) },
+       { NHBRUSH_CODE(NHW_MAP, MSWIN_COLOR_BG), NULL, RGB(192, 192, 192) },
+       { -1, NULL, RGB(0, 0, 0) }
+};
+
+static void mswin_color_from_string(char *colorstring, HBRUSH* brushptr, COLORREF *colorptr);
+
+typedef struct ctv
+{
+       const char *colorstring;
+       COLORREF colorvalue;
+} color_table_value;
+
+/*
+ * The color list here is a combination of:
+ * NetHack colors.  (See mhmap.c)
+ * HTML colors. (See http://www.w3.org/TR/REC-html40/types.html#h-6.5 )
+ */
+
+static color_table_value color_table[] = {
+/* NetHack colors */
+       { "black",              RGB(0x55, 0x55, 0x55)},
+       { "red",                RGB(0xFF, 0x00, 0x00)},
+       { "green",              RGB(0x00, 0x80, 0x00)},
+       { "brown",              RGB(0xA5, 0x2A, 0x2A)},
+       { "blue",               RGB(0x00, 0x00, 0xFF)},
+       { "magenta",            RGB(0xFF, 0x00, 0xFF)},
+       { "cyan",               RGB(0x00, 0xFF, 0xFF)},
+       { "orange",             RGB(0xFF, 0xA5, 0x00)},
+       { "brightgreen",        RGB(0x00, 0xFF, 0x00)},
+       { "yellow",             RGB(0xFF, 0xFF, 0x00)},
+       { "brightblue",         RGB(0x00, 0xC0, 0xFF)},
+       { "brightmagenta",      RGB(0xFF, 0x80, 0xFF)},
+       { "brightcyan",         RGB(0x80, 0xFF, 0xFF)},
+       { "white",              RGB(0xFF, 0xFF, 0xFF)},
+/* Remaining HTML colors */
+       { "trueblack",          RGB(0x00, 0x00, 0x00)},
+       { "gray",               RGB(0x80, 0x80, 0x80)},
+       { "grey",               RGB(0x80, 0x80, 0x80)},
+       { "purple",             RGB(0x80, 0x00, 0x80)},
+       { "silver",             RGB(0xC0, 0xC0, 0xC0)},
+       { "maroon",             RGB(0x80, 0x00, 0x00)},
+       { "fuchsia",            RGB(0xFF, 0x00, 0xFF)}, /* = NetHack magenta */
+       { "lime",               RGB(0x00, 0xFF, 0x00)}, /* = NetHack bright green */
+       { "olive",              RGB(0x80, 0x80, 0x00)},
+       { "navy",               RGB(0x00, 0x00, 0x80)},
+       { "teal",               RGB(0x00, 0x80, 0x80)},
+       { "aqua",               RGB(0x00, 0xFF, 0xFF)}, /* = NetHack cyan */
+       { "",                   RGB(0x00, 0x00, 0x00)},
+};
+
+typedef struct ctbv
+{
+       char *colorstring;
+       int syscolorvalue;
+} color_table_brush_value;
+
+static color_table_brush_value color_table_brush[] = {
+       { "activeborder",       COLOR_ACTIVEBORDER      },
+       { "activecaption",      COLOR_ACTIVECAPTION     },
+       { "appworkspace",       COLOR_APPWORKSPACE      },
+       { "background",         COLOR_BACKGROUND        },
+       { "btnface",            COLOR_BTNFACE           },
+       { "btnshadow",          COLOR_BTNSHADOW         },
+       { "btntext",            COLOR_BTNTEXT           },
+       { "captiontext",        COLOR_CAPTIONTEXT       },
+       { "graytext",           COLOR_GRAYTEXT          },
+       { "greytext",           COLOR_GRAYTEXT          },
+       { "highlight",          COLOR_HIGHLIGHT         },
+       { "highlighttext",      COLOR_HIGHLIGHTTEXT     },
+       { "inactiveborder",     COLOR_INACTIVEBORDER    },
+       { "inactivecaption",    COLOR_INACTIVECAPTION   },
+       { "menu",               COLOR_MENU              },
+       { "menutext",           COLOR_MENUTEXT          },
+       { "scrollbar",          COLOR_SCROLLBAR         },
+       { "window",             COLOR_WINDOW            },
+       { "windowframe",        COLOR_WINDOWFRAME       },
+       { "windowtext",         COLOR_WINDOWTEXT        },
+       { "",                   -1                              },
+};
+
+void mswin_init_color_table()
+{
+       int i;
+       struct t_brush_table* p;
+
+       /* cleanup */
+       for( i=0; i<max_brush; i++ )
+               DeleteObject(brush_table[i].brush);
+       max_brush = 0;
+
+       /* initialize brush table */
+#define BRUSHTABLE_ENTRY(opt, win, type) \
+       brush_table[max_brush].code = NHBRUSH_CODE((win), (type)); \
+       mswin_color_from_string((opt), &brush_table[max_brush].brush, &brush_table[max_brush].color); \
+       max_brush++;
+
+       BRUSHTABLE_ENTRY(iflags.wc_foregrnd_menu, NHW_MENU, MSWIN_COLOR_FG);
+       BRUSHTABLE_ENTRY(iflags.wc_foregrnd_message, NHW_MESSAGE, MSWIN_COLOR_FG);
+       BRUSHTABLE_ENTRY(iflags.wc_foregrnd_status, NHW_STATUS, MSWIN_COLOR_FG);
+       BRUSHTABLE_ENTRY(iflags.wc_foregrnd_text, NHW_TEXT, MSWIN_COLOR_FG);
+       BRUSHTABLE_ENTRY(iflags.wc_foregrnd_message, NHW_KEYPAD, MSWIN_COLOR_FG);
+
+       BRUSHTABLE_ENTRY(iflags.wc_backgrnd_menu, NHW_MENU, MSWIN_COLOR_BG);
+       BRUSHTABLE_ENTRY(iflags.wc_backgrnd_message, NHW_MESSAGE, MSWIN_COLOR_BG);
+       BRUSHTABLE_ENTRY(iflags.wc_backgrnd_status, NHW_STATUS, MSWIN_COLOR_BG);
+       BRUSHTABLE_ENTRY(iflags.wc_backgrnd_text, NHW_TEXT, MSWIN_COLOR_BG);
+       BRUSHTABLE_ENTRY(iflags.wc_backgrnd_message, NHW_KEYPAD, MSWIN_COLOR_BG);
+#undef BRUSHTABLE_ENTRY
+
+       /* go through the values and fill in "blanks" (use default values) */
+       for( i=0; i<max_brush; i++ ) {
+               if( !brush_table[i].brush ) {
+                       for( p = default_brush_table; p->code != -1; p++ ) {
+                               if( p->code==brush_table[i].code ) {
+                                       brush_table[i].brush = CreateSolidBrush(p->color);
+                                       brush_table[i].color = p->color;
+                               }
+                       }
+               }
+       }
+}
+
+HBRUSH mswin_get_brush(int win_type, int color_index)
+{
+       int i;
+       for(i=0; i<max_brush; i++)
+               if( brush_table[i].code == NHBRUSH_CODE(win_type, color_index) )
+                       return brush_table[i].brush;
+       return NULL;
+}
+
+COLORREF mswin_get_color(int win_type, int color_index)
+{
+       int i;
+       for(i=0; i<max_brush; i++)
+               if( brush_table[i].code == NHBRUSH_CODE(win_type, color_index) )
+                       return brush_table[i].color;
+       return RGB(0, 0, 0);
+}
+
+static void mswin_color_from_string(char *colorstring, HBRUSH* brushptr, COLORREF *colorptr)
+{
+       color_table_value *ctv_ptr = color_table;
+       color_table_brush_value *ctbv_ptr = color_table_brush;
+       int red_value, blue_value, green_value;
+       static char *hexadecimals = "0123456789abcdef";
+
+       *brushptr = NULL;
+       *colorptr = RGB(0, 0, 0);
+
+       if (colorstring == NULL) return;
+       if (*colorstring == '#') {
+               if (strlen(++colorstring) != 6) return;
+
+               red_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
+               red_value *= 16;
+               red_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
+
+               green_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
+               green_value *= 16;
+               green_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
+
+               blue_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
+               blue_value *= 16;
+               blue_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
+
+               *colorptr = RGB(red_value, blue_value, green_value);
+       } else {
+           while (*ctv_ptr->colorstring && _stricmp(ctv_ptr->colorstring, colorstring))
+               ++ctv_ptr;
+           if (*ctv_ptr->colorstring) {
+               *colorptr = ctv_ptr->colorvalue;
+           } else {
+             while (*ctbv_ptr->colorstring && _stricmp(ctbv_ptr->colorstring, colorstring))
+                   ++ctbv_ptr;
+               if (*ctbv_ptr->colorstring) {
+                   *brushptr = SYSCLR_TO_BRUSH(ctbv_ptr->syscolorvalue);
+                   *colorptr = GetSysColor(ctbv_ptr->syscolorvalue);
+               }
+           }
+       }
+       if (max_brush > TOTAL_BRUSHES) panic("Too many colors!");
+       *brushptr = CreateSolidBrush(*colorptr);
+}
diff --git a/sys/wince/mhcolor.h b/sys/wince/mhcolor.h
new file mode 100644 (file)
index 0000000..c9fdf73
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* color management functions */
+
+#ifndef MSWINColor_h
+#define MSWINColor_h
+
+#define MSWIN_COLOR_BG 0
+#define MSWIN_COLOR_FG 1
+#define SYSCLR_TO_BRUSH(x) ((HBRUSH)((x) + 1))
+
+extern void mswin_init_color_table();
+extern HBRUSH mswin_get_brush(int win_type, int color_index);
+extern COLORREF mswin_get_color(int win_type, int color_index);
+
+#endif /* MSWINColor_h */
diff --git a/sys/wince/mhdlg.c b/sys/wince/mhdlg.c
new file mode 100644 (file)
index 0000000..9b6e9a0
--- /dev/null
@@ -0,0 +1,787 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* various dialog boxes are defined here */
+
+#include "winMS.h"
+#include "hack.h"
+#include "func_tab.h"
+#include "mhdlg.h"
+#include "mhmain.h"
+
+#define CheckDlgButton(dlg, btn_id, st) SendDlgItemMessage((dlg), (btn_id), BM_SETCHECK, (WPARAM)(st), 0)
+
+
+/*---------------------------------------------------------------*/
+/* data for getlin dialog */
+struct getlin_data {
+       const char*     question;
+       char*           result;
+       size_t          result_size;
+};
+
+LRESULT CALLBACK       GetlinDlgProc(HWND, UINT, WPARAM, LPARAM);
+
+int mswin_getlin_window (
+       const char *question, 
+       char *result, 
+       size_t result_size
+)
+{
+       int ret;
+       struct getlin_data data;
+
+       /* initilize dialog data */
+       ZeroMemory(&data, sizeof(data));
+       data.question = question;
+       data.result = result;
+       data.result_size = result_size;
+
+       /* create modal dialog window */
+       ret = DialogBoxParam(
+                       GetNHApp()->hApp,
+                       MAKEINTRESOURCE(IDD_GETLIN),
+                       GetNHApp()->hMainWnd,
+                       GetlinDlgProc,
+                       (LPARAM)&data
+       );
+       if( ret==-1 ) panic("Cannot create getlin window");
+       
+       return ret;
+}
+    
+LRESULT CALLBACK GetlinDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       struct getlin_data* data;
+       RECT   main_rt, text_rt, dlg_rt, edit_rt;
+       SIZE   dlg_sz;
+       TCHAR  wbuf[BUFSZ];
+       HDC        hdc;
+       HWND   control;
+       HWND   hwndMap; 
+
+#if defined(WIN_CE_POCKETPC)
+       SHInputDialog(hWnd, message, wParam);
+#endif
+
+       switch (message) 
+       {
+       case WM_INITDIALOG:
+               data = (struct getlin_data*)lParam;
+               SetWindowText(hWnd, NH_A2W(data->question, wbuf, sizeof(wbuf)));
+               SetWindowLong(hWnd, GWL_USERDATA, lParam);
+
+               /* get title text width */
+               SetRect(&text_rt, 0, 0, 100, 50);
+               hdc = GetWindowDC(hWnd);
+               DrawText(hdc, wbuf, _tcslen(wbuf), &text_rt, 
+                            DT_CALCRECT | DT_SINGLELINE | DT_NOPREFIX | DT_LEFT | DT_VCENTER );
+               ReleaseDC(hWnd, hdc);
+
+               /* center dialog in the main window */
+               GetWindowRect(hWnd, &dlg_rt);
+               hwndMap = mswin_hwnd_from_winid(WIN_MAP);
+               GetWindowRect( IsWindow(hwndMap)? hwndMap : GetNHApp()->hMainWnd, &main_rt);
+               dlg_sz.cx = max(dlg_rt.right-dlg_rt.left, 
+                                   min( text_rt.right-text_rt.left+GetSystemMetrics(SM_CXICON),
+                                                    main_rt.right-main_rt.left ) );
+               dlg_sz.cy = min(dlg_rt.bottom - dlg_rt.top, main_rt.bottom - main_rt.top);
+               dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2;
+               dlg_rt.right = dlg_rt.left + dlg_sz.cx;
+               dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2;
+               dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
+               MoveWindow( hWnd,
+                                       (main_rt.left+main_rt.right-dlg_sz.cx)/2,
+                                       (main_rt.top+main_rt.bottom-dlg_sz.cy)/2,
+                                       dlg_sz.cx,
+                                       dlg_sz.cy,
+                                       TRUE );
+
+               /* change layout of controls */
+               GetClientRect(hWnd, &dlg_rt);
+
+               control = GetDlgItem(hWnd, IDC_GETLIN_EDIT);
+               GetWindowRect(control, &edit_rt);
+               MoveWindow( control,
+                                       0,
+                                       0,
+                                       dlg_rt.right - dlg_rt.left,
+                                       edit_rt.bottom - edit_rt.top,
+                                       TRUE );
+
+               control = GetDlgItem(hWnd, IDOK);
+               GetWindowRect(control, &text_rt);
+               MoveWindow( control,
+                                       0,
+                                       edit_rt.bottom - edit_rt.top,
+                                       (dlg_rt.right-dlg_rt.left)/2,
+                                       text_rt.bottom - text_rt.top,
+                                       TRUE );
+
+               control = GetDlgItem(hWnd, IDCANCEL);
+               GetWindowRect(control, &text_rt);
+               MoveWindow( control,
+                                       (dlg_rt.right-dlg_rt.left)/2,
+                                       edit_rt.bottom - edit_rt.top,
+                                       (dlg_rt.right-dlg_rt.left)/2,
+                                       text_rt.bottom - text_rt.top,
+                                       TRUE );
+
+#if defined(WIN_CE_SMARTPHONE)
+               NHSPhoneDialogSetup(hWnd, TRUE, FALSE);
+#endif
+
+               /* set focus to the edit control */
+               SetFocus(GetDlgItem(hWnd, IDC_GETLIN_EDIT));
+
+               /* tell windows that we've set the focus */
+               return FALSE; 
+       break;
+
+       case WM_COMMAND: 
+       {
+               TCHAR wbuf[BUFSZ];
+
+               switch (LOWORD(wParam)) 
+        { 
+                       /* OK button was pressed */
+                       case IDOK:
+                     data = (struct getlin_data*)GetWindowLong(hWnd, GWL_USERDATA);
+                         SendDlgItemMessage(hWnd, IDC_GETLIN_EDIT, WM_GETTEXT, (WPARAM)sizeof(wbuf), (LPARAM)wbuf );
+                         NH_W2A(wbuf, data->result, data->result_size);
+
+                         /* Fall through. */
+
+                       /* cancel button was pressed */
+                       case IDCANCEL: 
+                               EndDialog(hWnd, wParam); 
+                       return TRUE;
+               }
+       } break;
+
+#if defined(WIN_CE_SMARTPHONE)
+       case WM_HOTKEY:
+               if(VK_TBACK == HIWORD(lParam)) {
+                       SHSendBackToFocusWindow(message, wParam, lParam);
+               }
+       break;
+#endif
+
+       } /* end switch (message) */
+       return FALSE;
+}
+
+
+/*---------------------------------------------------------------*/
+/* dialog data for the list of extended commands */
+struct extcmd_data {
+       int*            selection;
+};
+
+LRESULT CALLBACK       ExtCmdDlgProc(HWND, UINT, WPARAM, LPARAM);
+
+int mswin_ext_cmd_window (int* selection)
+{
+       int ret;
+       struct extcmd_data data;
+       
+       /* init dialog data */
+       ZeroMemory(&data, sizeof(data));
+       *selection = -1;
+       data.selection = selection;
+
+       /* create modal dialog window */
+       ret = DialogBoxParam(
+                       GetNHApp()->hApp,
+                       MAKEINTRESOURCE(IDD_EXTCMD),
+                       GetNHApp()->hMainWnd,
+                       ExtCmdDlgProc,
+                       (LPARAM)&data
+       );
+       if( ret==-1 ) panic("Cannot create extcmd window");
+       return ret;
+}
+    
+LRESULT CALLBACK ExtCmdDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       struct extcmd_data* data;
+       RECT   main_rt, dlg_rt;
+       SIZE   dlg_sz;
+       int    i;
+       const char *ptr;
+       TCHAR wbuf[255];
+
+       switch (message) 
+       {
+       case WM_INITDIALOG:
+               data = (struct extcmd_data*)lParam;
+               SetWindowLong(hWnd, GWL_USERDATA, lParam);
+
+               /* center dialog in the main window */
+               GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
+               GetWindowRect(hWnd, &dlg_rt);
+               dlg_sz.cx = dlg_rt.right - dlg_rt.left;
+               dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
+
+               dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2;
+               dlg_rt.right = dlg_rt.left + dlg_sz.cx;
+               dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2;
+               dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
+               MoveWindow( hWnd,
+                                       (main_rt.left+main_rt.right-dlg_sz.cx)/2,
+                                       (main_rt.top+main_rt.bottom-dlg_sz.cy)/2,
+                                       dlg_sz.cx,
+                                       dlg_sz.cy,
+                                       TRUE );
+
+               /* fill combobox with extended commands */
+               for(i=0; (ptr=extcmdlist[i].ef_txt); i++) {
+                       SendDlgItemMessage(hWnd, IDC_EXTCMD_LIST, LB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(ptr, wbuf, sizeof(wbuf)) );
+               }
+
+#if defined(WIN_CE_SMARTPHONE)
+               NHSPhoneDialogSetup(hWnd, FALSE, FALSE);
+
+               GetClientRect(hWnd, &dlg_rt);
+               MoveWindow(GetDlgItem(hWnd, IDC_EXTCMD_LIST),
+                              dlg_rt.left, dlg_rt.top, 
+                                  dlg_rt.right-dlg_rt.left, dlg_rt.bottom-dlg_rt.top,
+                                  TRUE);
+#endif
+
+               /* set focus to the list control */
+               SetFocus(GetDlgItem(hWnd, IDC_EXTCMD_LIST));
+
+               /* tell windows we set the focus */
+               return FALSE;
+       break;
+
+       case WM_COMMAND:
+        data = (struct extcmd_data*)GetWindowLong(hWnd, GWL_USERDATA);
+               switch (LOWORD(wParam)) 
+        { 
+                 /* OK button ws clicked */
+          case IDOK:
+                         *data->selection = SendDlgItemMessage(hWnd, IDC_EXTCMD_LIST, LB_GETCURSEL, (WPARAM)0, (LPARAM)0 );
+                         if( *data->selection==LB_ERR )
+                                 *data->selection = -1;
+                         /* Fall through. */
+
+                 /* CANCEL button ws clicked */
+                 case IDCANCEL:
+                               EndDialog(hWnd, wParam); 
+                 return TRUE;
+
+                 /* list control events */
+                 case IDC_EXTCMD_LIST:
+                               switch(HIWORD(wParam)) {
+
+                               case LBN_DBLCLK: 
+                                 /* double click within the list 
+                                        wParam 
+                                          The low-order word is the list box identifier. 
+                                          The high-order word is the notification message. 
+                                        lParam 
+                                          Handle to the list box
+                                       */
+                                  *data->selection = SendMessage((HWND)lParam, LB_GETCURSEL, (WPARAM)0, (LPARAM)0);
+                                  if( *data->selection==LB_ERR )
+                                          *data->selection = -1;
+                                  EndDialog(hWnd, IDOK); 
+                              return TRUE;
+                               }
+                 break;
+               }
+       }
+       return FALSE;
+}
+
+/*---------------------------------------------------------------*/
+/* player selector dialog data */
+struct plsel_data {
+       int*    selection;
+};
+
+BOOL CALLBACK  PlayerSelectorDlgProc(HWND, UINT, WPARAM, LPARAM);
+static void            plselInitDialog(HWND hWnd);
+static void                    plselAdjustLists(HWND hWnd, int changed_opt);
+static int                     plselFinalSelection(HWND hWnd, int* selection);
+
+int mswin_player_selection_window ( int* selection )
+{
+       int ret;
+       struct plsel_data data;
+
+       /* init dialog data */
+       ZeroMemory(&data, sizeof(data));
+       data.selection = selection;
+
+       /* create modal dialog */
+       ret = DialogBoxParam(
+                       GetNHApp()->hApp,
+                       MAKEINTRESOURCE(IDD_PLAYER_SELECTOR),
+                       GetNHApp()->hMainWnd,
+                       PlayerSelectorDlgProc,
+                       (LPARAM)&data
+       );
+       if( ret==-1 ) panic("Cannot create getlin window");
+       
+       return ret;
+}
+
+BOOL CALLBACK PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       struct plsel_data* data;
+       RECT   main_rt, dlg_rt;
+       SIZE   dlg_sz;
+
+       switch (message) 
+       {
+       case WM_INITDIALOG:
+               data = (struct plsel_data*)lParam;
+               SetWindowLong(hWnd, GWL_USERDATA, lParam);
+
+               /* center dialog in the main window */
+               GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
+               GetWindowRect(hWnd, &dlg_rt);
+               dlg_sz.cx = dlg_rt.right - dlg_rt.left;
+               dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
+
+               dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2;
+               dlg_rt.right = dlg_rt.left + dlg_sz.cx;
+               dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2;
+               dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
+               MoveWindow( hWnd,
+                                       (main_rt.left+main_rt.right-dlg_sz.cx)/2,
+                                       (main_rt.top+main_rt.bottom-dlg_sz.cy)/2,
+                                       dlg_sz.cx,
+                                       dlg_sz.cy,
+                                       TRUE );
+
+               /* init dialog */
+               plselInitDialog(hWnd);
+
+#if defined(WIN_CE_SMARTPHONE)
+               NHSPhoneDialogSetup(hWnd, FALSE, FALSE);
+#endif
+               /* set focus on the role checkbox (random) field */
+               SetFocus(GetDlgItem(hWnd, IDC_PLSEL_ROLE_RANDOM));
+
+               /* tell windows we set the focus */
+               return FALSE;
+       break;
+
+       case WM_COMMAND:
+        data = (struct plsel_data*)GetWindowLong(hWnd, GWL_USERDATA);
+               switch (LOWORD(wParam)) { 
+
+               /* OK button was clicked */
+               case IDOK:
+                       if( plselFinalSelection(hWnd, data->selection) ) {
+                               EndDialog(hWnd, wParam); 
+                       } else {
+                               MessageBox(hWnd, TEXT("Cannot match this role. Try something else."), TEXT("STOP"), MB_OK );
+                       }
+               return TRUE;
+
+               /* CANCEL button was clicked */
+               case IDCANCEL:
+                       *data->selection = -1;
+                       EndDialog(hWnd, wParam); 
+               return TRUE;
+
+               /* following are events from dialog controls: 
+                  "random" checkboxes send BN_CLICKED messages;
+                  role/race/... combo-boxes send CBN_SELENDOK 
+                  if something was selected;
+               */
+               case IDC_PLSEL_ROLE_RANDOM:
+                       if( HIWORD(wParam)==BN_CLICKED ) {
+                               /* enable corresponding list window if "random"
+                                  checkbox was "unchecked" */
+                               EnableWindow(
+                                       GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), 
+                                       SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED
+                                 );
+                       }
+               break;
+
+               case IDC_PLSEL_RACE_RANDOM:
+                       if( HIWORD(wParam)==BN_CLICKED ) {
+                               EnableWindow(
+                                       GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), 
+                                       SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED
+                                 );
+                       }
+               break;
+
+               case IDC_PLSEL_GENDER_RANDOM:
+                       if( HIWORD(wParam)==BN_CLICKED ) {
+                               EnableWindow(
+                                       GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), 
+                                       SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED
+                                 );
+                       }
+               break;
+
+               case IDC_PLSEL_ALIGN_RANDOM:
+                       if( HIWORD(wParam)==BN_CLICKED ) {
+                               EnableWindow(
+                                       GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), 
+                                       SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED
+                                 );
+                       }
+               break;
+
+               case IDC_PLSEL_ROLE_LIST:
+                       if( HIWORD(wParam)==CBN_SELENDOK ) {
+                               /* filter out invalid options if 
+                                  the selection was made */
+                               plselAdjustLists( hWnd, LOWORD(wParam) );
+                       }
+               break;
+
+               case IDC_PLSEL_RACE_LIST:
+                       if( HIWORD(wParam)==CBN_SELENDOK ) {
+                               plselAdjustLists( hWnd, LOWORD(wParam) );
+                       }
+               break;
+
+               case IDC_PLSEL_GENDER_LIST:
+                       if( HIWORD(wParam)==CBN_SELENDOK ) {
+                               plselAdjustLists( hWnd, LOWORD(wParam) );
+                       }
+               break;
+
+               case IDC_PLSEL_ALIGN_LIST:
+                       if( HIWORD(wParam)==CBN_SELENDOK ) {
+                               plselAdjustLists( hWnd, LOWORD(wParam) );
+                       }
+               break;
+               }
+       break;
+       }
+       return FALSE;
+}
+
+void setComboBoxValue(HWND hWnd, int combo_box, int value)
+{
+       int index_max = SendDlgItemMessage(hWnd, combo_box, CB_GETCOUNT, 0, 0);
+       int index;
+       int value_to_set = LB_ERR;
+       for (index = 0; index < index_max; index++) {
+           if (SendDlgItemMessage(hWnd, combo_box, CB_GETITEMDATA, (WPARAM)index, 0) == value) {
+               value_to_set = index;
+               break;
+           }
+       }
+       SendDlgItemMessage(hWnd, combo_box, CB_SETCURSEL, (WPARAM)value_to_set, 0);
+}
+
+/* initialize player selector dialog */
+void plselInitDialog(HWND hWnd)
+{
+       TCHAR wbuf[BUFSZ];
+
+       /* set player name */
+       SetDlgItemText(hWnd, IDC_PLSEL_NAME, NH_A2W(plname, wbuf, sizeof(wbuf)));
+
+       /* check flags for consistency */
+       if( flags.initrole>=0 ) {
+               if (flags.initrace>=0 && !validrace(flags.initrole, flags.initrace)) {
+                       flags.initrace = ROLE_NONE;
+               }
+
+               if (flags.initgend>=0 && !validgend(flags.initrole, flags.initrace, flags.initgend)) {
+                       flags.initgend = ROLE_NONE;
+               }
+
+               if (flags.initalign>=0 && !validalign(flags.initrole, flags.initrace, flags.initalign)) {
+                       flags.initalign = ROLE_NONE;
+               }
+       }
+
+       /* populate select boxes */
+       plselAdjustLists(hWnd, -1);
+
+       /* intialize roles list */
+       if( flags.initrole<0 || !ok_role(flags.initrole, ROLE_NONE, ROLE_NONE, ROLE_NONE)) {
+               CheckDlgButton(hWnd, IDC_PLSEL_ROLE_RANDOM, BST_CHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), FALSE);
+       } else {
+               CheckDlgButton(hWnd, IDC_PLSEL_ROLE_RANDOM, BST_UNCHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), TRUE);
+               setComboBoxValue(hWnd, IDC_PLSEL_ROLE_LIST, flags.initrole);
+       }
+
+       /* intialize races list */
+       if( flags.initrace<0 || !ok_race(flags.initrole, flags.initrace, ROLE_NONE, ROLE_NONE) ) {
+               CheckDlgButton(hWnd, IDC_PLSEL_RACE_RANDOM, BST_CHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), FALSE);
+       } else {
+               CheckDlgButton(hWnd, IDC_PLSEL_RACE_RANDOM, BST_UNCHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), TRUE);
+               setComboBoxValue(hWnd, IDC_PLSEL_RACE_LIST, flags.initrace);
+       }
+
+       /* intialize genders list */
+       if( flags.initgend<0 || !ok_gend(flags.initrole, flags.initrace, flags.initgend, ROLE_NONE)) {
+               CheckDlgButton(hWnd, IDC_PLSEL_GENDER_RANDOM, BST_CHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), FALSE);
+       } else {
+               CheckDlgButton(hWnd, IDC_PLSEL_GENDER_RANDOM, BST_UNCHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), TRUE);
+               setComboBoxValue(hWnd, IDC_PLSEL_GENDER_LIST, flags.initgend);
+       }
+
+       /* intialize alignments list */
+       if( flags.initalign<0 || !ok_align(flags.initrole, flags.initrace, flags.initgend, flags.initalign) ) {
+               CheckDlgButton(hWnd, IDC_PLSEL_ALIGN_RANDOM, BST_CHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), FALSE);
+       } else {
+               CheckDlgButton(hWnd, IDC_PLSEL_ALIGN_RANDOM, BST_UNCHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), TRUE);
+               setComboBoxValue(hWnd, IDC_PLSEL_ALIGN_LIST, flags.initalign);
+       }
+}
+
+/* adjust role/race/alignment/gender list - filter out
+   invalid combinations 
+   changed_sel points to the list where selection occured
+   (-1 if unknown)
+*/
+void  plselAdjustLists(HWND hWnd, int changed_sel)
+{
+       HWND control_role, control_race, control_gender, control_align;
+       int  initrole, initrace, initgend, initalign;
+       int i;
+       int ind;
+       int valid_opt;
+       TCHAR wbuf[255];
+
+       /* get control handles */
+       control_role = GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST);
+       control_race = GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST);
+       control_gender = GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST);
+       control_align = GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST);
+
+       /* get current selections */    
+       ind = SendMessage(control_role, CB_GETCURSEL, 0, 0);
+       initrole = (ind==LB_ERR)? flags.initrole : SendMessage(control_role, CB_GETITEMDATA, ind, 0);
+
+       ind = SendMessage(control_race, CB_GETCURSEL, 0, 0);
+       initrace = (ind==LB_ERR)? flags.initrace : SendMessage(control_race, CB_GETITEMDATA, ind, 0);
+
+       ind = SendMessage(control_gender, CB_GETCURSEL, 0, 0);
+       initgend = (ind==LB_ERR)? flags.initgend : SendMessage(control_gender, CB_GETITEMDATA, ind, 0);
+
+       ind = SendMessage(control_align, CB_GETCURSEL, 0, 0);
+       initalign = (ind==LB_ERR)? flags.initalign : SendMessage(control_align, CB_GETITEMDATA, ind, 0);
+
+       /* intialize roles list */
+       if( changed_sel==-1 ) {
+               valid_opt = 0;
+
+               /* reset content and populate the list */
+               SendMessage(control_role, CB_RESETCONTENT, 0, 0); 
+               for (i = 0; roles[i].name.m; i++) {
+                       if (ok_role(i, initrace, initgend, initalign)) {
+                           if (initgend>=0 && flags.female && roles[i].name.f)
+                                       ind = SendMessage(control_role, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(roles[i].name.f, wbuf, sizeof(wbuf)) );
+                               else 
+                                       ind = SendMessage(control_role, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(roles[i].name.m, wbuf, sizeof(wbuf)) );
+
+                               SendMessage(control_role, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i );
+                               if( i==initrole ) { 
+                                       SendMessage(control_role, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 );
+                                       valid_opt = 1;
+                               }
+                       }
+               }
+               
+               /* set selection to the previously selected role
+                  if it is still valid */
+               if( !valid_opt ) {
+                       initrole = ROLE_NONE;
+                       initrace = ROLE_NONE;
+                       initgend = ROLE_NONE;
+                       initalign = ROLE_NONE;
+                       SendMessage(control_role, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 );
+               }
+
+               /* trigger change of the races list */
+               changed_sel=IDC_PLSEL_ROLE_LIST;
+       }
+
+       /* intialize races list */
+       if( changed_sel==IDC_PLSEL_ROLE_LIST ) {
+               valid_opt = 0;
+
+               /* reset content and populate the list */
+               SendMessage(control_race, CB_RESETCONTENT, 0, 0); 
+               for (i = 0; races[i].noun; i++)
+                       if (ok_race(initrole, i, ROLE_NONE, ROLE_NONE)) {
+                               ind = SendMessage(control_race, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(races[i].noun, wbuf, sizeof(wbuf)) ); 
+                               SendMessage(control_race, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); 
+                               if( i==initrace ) { 
+                                       SendMessage(control_race, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 );
+                                       valid_opt = 1;
+                               }
+                       }
+
+               /* set selection to the previously selected race
+                  if it is still valid */
+               if( !valid_opt ) {
+                       initrace = ROLE_NONE;
+                       initgend = ROLE_NONE;
+                       initalign = ROLE_NONE;
+                       SendMessage(control_race, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 );
+               }
+
+               /* trigger change of the genders list */
+               changed_sel=IDC_PLSEL_RACE_LIST;
+       }
+
+       /* intialize genders list */
+       if( changed_sel==IDC_PLSEL_RACE_LIST ) {
+               valid_opt = 0;
+
+               /* reset content and populate the list */
+               SendMessage(control_gender, CB_RESETCONTENT, 0, 0); 
+               for (i = 0; i < ROLE_GENDERS; i++)
+                       if (ok_gend(initrole, initrace, i, ROLE_NONE)) {
+                               ind = SendMessage(control_gender, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(genders[i].adj, wbuf, sizeof(wbuf)) ); 
+                               SendMessage(control_gender, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); 
+                               if( i==initgend ) { 
+                                       SendMessage(control_gender, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 );
+                                       valid_opt = 1;
+                               }
+                       }
+
+               /* set selection to the previously selected gender
+                  if it is still valid */
+               if( !valid_opt ) {
+                       initgend = ROLE_NONE;
+                       initalign = ROLE_NONE;
+                       SendMessage(control_gender, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 );
+               }
+
+               /* trigger change of the alignments list */
+               changed_sel=IDC_PLSEL_GENDER_LIST;
+       }
+
+       /* intialize alignments list */
+       if( changed_sel==IDC_PLSEL_GENDER_LIST ) {
+               valid_opt = 0;
+
+               /* reset content and populate the list */
+               SendMessage(control_align, CB_RESETCONTENT, 0, 0); 
+               for (i = 0; i < ROLE_ALIGNS; i++)
+                       if (ok_align(initrole, initrace, initgend, i)) {
+                               ind = SendMessage(control_align, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(aligns[i].adj, wbuf, sizeof(wbuf)) ); 
+                               SendMessage(control_align, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); 
+                               if( i==initalign ) { 
+                                       SendMessage(control_align, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 );
+                                       valid_opt = 1;
+                               }
+                       }
+
+               /* set selection to the previously selected alignment
+                  if it is still valid */
+               if( !valid_opt ) {
+                       initalign = ROLE_NONE;
+                       SendMessage(control_align, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 );
+               }
+       }
+}
+
+/* player made up his mind - get final selection here */ 
+int    plselFinalSelection(HWND hWnd, int* selection)
+{
+       int ind;
+
+       /* get current selections */
+       if( SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) {
+               flags.initrole = ROLE_RANDOM;
+       } else {
+               ind = SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_LIST, CB_GETCURSEL, 0, 0);
+               flags.initrole = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_LIST, CB_GETITEMDATA, ind, 0);
+       }
+
+       if( SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) {
+               flags.initrace = ROLE_RANDOM;
+       } else {
+               ind = SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_LIST, CB_GETCURSEL, 0, 0);
+               flags.initrace = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_LIST, CB_GETITEMDATA, ind, 0);
+       }
+
+       if( SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) {
+               flags.initgend = ROLE_RANDOM;
+       } else {
+               ind = SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_LIST, CB_GETCURSEL, 0, 0);
+               flags.initgend = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_LIST, CB_GETITEMDATA, ind, 0);
+       }
+
+       if( SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) {
+               flags.initalign = ROLE_RANDOM;
+       } else {
+               ind = SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_LIST, CB_GETCURSEL, 0, 0);
+               flags.initalign = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_LIST, CB_GETITEMDATA, ind, 0);
+       }
+       
+
+       /* check the role */
+       if( flags.initrole==ROLE_RANDOM ) {
+               flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM);
+               if (flags.initrole < 0) {
+                       MessageBox(hWnd, TEXT("Incompatible role!"), TEXT("STOP"), MB_OK);
+                       return FALSE;
+               }
+       }
+
+       /* Select a race, if necessary */
+       /* force compatibility with role */
+       if (flags.initrace==ROLE_RANDOM || !validrace(flags.initrole, flags.initrace)) {
+               /* pre-selected race not valid */
+               if (flags.initrace == ROLE_RANDOM) {
+                       flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM);
+               }
+               
+               if (flags.initrace < 0) {
+                       MessageBox(hWnd, TEXT("Incompatible race!"), TEXT("STOP"), MB_OK);
+                       return FALSE;
+               }
+       }
+
+       /* Select a gender, if necessary */
+       /* force compatibility with role/race, try for compatibility with
+        * pre-selected alignment */
+       if (flags.initgend < 0 || 
+               !validgend(flags.initrole, flags.initrace, flags.initgend)) {
+           /* pre-selected gender not valid */
+           if (flags.initgend == ROLE_RANDOM) {
+                       flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM);
+               }
+               
+               if (flags.initgend < 0) {
+                       MessageBox(hWnd, TEXT("Incompatible gender!"), TEXT("STOP"), MB_OK);
+                       return FALSE;
+               }
+       }
+
+       /* Select an alignment, if necessary */
+       /* force compatibility with role/race/gender */
+       if (flags.initalign < 0 || 
+               !validalign(flags.initrole, flags.initrace,     flags.initalign)) {
+               /* pre-selected alignment not valid */
+               if (flags.initalign == ROLE_RANDOM) {
+                       flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM);
+               } else {
+                       MessageBox(hWnd, TEXT("Incompatible alignment!"), TEXT("STOP"), MB_OK);
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
diff --git a/sys/wince/mhdlg.h b/sys/wince/mhdlg.h
new file mode 100644 (file)
index 0000000..b964838
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINDlgWindow_h
+#define MSWINDlgWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+int mswin_getlin_window (const char *question, char *result, size_t result_size);
+int mswin_ext_cmd_window (int* selection);
+int  mswin_player_selection_window(int* selection);
+
+#endif /* MSWINDlgWindow_h */
diff --git a/sys/wince/mhfont.c b/sys/wince/mhfont.c
new file mode 100644 (file)
index 0000000..30055f6
--- /dev/null
@@ -0,0 +1,177 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* font management and such */
+
+#include "mhfont.h"
+
+#define MAXFONTS       64
+
+/* font table - 64 fonts ought to be enough */
+static struct font_table_entry {
+       int             code;
+       HFONT   hFont;
+} font_table[MAXFONTS] ;
+static int font_table_size = 0;
+HFONT version_splash_font;
+HFONT extrainfo_splash_font;
+
+#define NHFONT_CODE(win, attr) (((attr&0xFF)<<8)|(win_type&0xFF))
+
+static void __cdecl font_table_cleanup(void);
+
+/* create font based on window type, charater attributes and
+   window device context */
+HGDIOBJ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace)
+{
+       HFONT fnt = NULL;
+       LOGFONT lgfnt;
+       int font_size;
+       int font_index;
+       static BOOL once = FALSE;
+
+       if( !once ) {
+               once = TRUE;
+               atexit(font_table_cleanup);
+       }
+
+       ZeroMemory( &lgfnt, sizeof(lgfnt) );
+
+       /* try find font in the table */
+       for(font_index=0; font_index<font_table_size; font_index++)
+               if(NHFONT_CODE(win_type, attr)==font_table[font_index].code)
+                       break;
+
+       if( !replace && font_index<font_table_size )
+               return font_table[font_index].hFont;
+
+       switch(win_type) {
+       case NHW_STATUS:
+               lgfnt.lfHeight                  =       -iflags.wc_fontsiz_status*GetDeviceCaps(hdc, LOGPIXELSY)/72;     // height of font
+               lgfnt.lfWidth                   =       0;                                   // average character width
+               lgfnt.lfEscapement              =       0;                                       // angle of escapement
+               lgfnt.lfOrientation             =       0;                                       // base-line orientation angle
+               lgfnt.lfWeight                  =       FW_NORMAL;           // font weight
+               lgfnt.lfItalic                  =       FALSE;                   // italic attribute option
+               lgfnt.lfUnderline               =       FALSE;                       // underline attribute option
+               lgfnt.lfStrikeOut               =       FALSE;                       // strikeout attribute option
+               lgfnt.lfCharSet                 =       mswin_charset();     // character set identifier
+               lgfnt.lfOutPrecision    =       OUT_DEFAULT_PRECIS;  // output precision
+               lgfnt.lfClipPrecision   =       CLIP_DEFAULT_PRECIS; // clipping precision
+               lgfnt.lfQuality                 =       DEFAULT_QUALITY;     // output quality
+               if( iflags.wc_font_status &&
+                       *iflags.wc_font_status ) {
+                       lgfnt.lfPitchAndFamily = DEFAULT_PITCH;          // pitch and family
+                       NH_A2W( iflags.wc_font_status, lgfnt.lfFaceName, LF_FACESIZE);
+               } else {
+                       lgfnt.lfPitchAndFamily = FIXED_PITCH;            // pitch and family
+               }
+               break;
+
+       case NHW_MENU:
+               lgfnt.lfHeight                  =       -iflags.wc_fontsiz_menu*GetDeviceCaps(hdc, LOGPIXELSY)/72;       // height of font
+               lgfnt.lfWidth                   =       0;                                   // average character width
+               lgfnt.lfEscapement              =       0;                                       // angle of escapement
+               lgfnt.lfOrientation             =       0;                                       // base-line orientation angle
+               lgfnt.lfWeight                  =       (attr==ATR_BOLD || attr==ATR_INVERSE)? FW_BOLD : FW_NORMAL;   // font weight
+               lgfnt.lfItalic                  =       (attr==ATR_BLINK)? TRUE: FALSE;              // italic attribute option
+               lgfnt.lfUnderline               =       (attr==ATR_ULINE)? TRUE : FALSE;                 // underline attribute option
+               lgfnt.lfStrikeOut               =       FALSE;                          // strikeout attribute option
+               lgfnt.lfCharSet                 =       mswin_charset();     // character set identifier
+               lgfnt.lfOutPrecision    =       OUT_DEFAULT_PRECIS;  // output precision
+               lgfnt.lfClipPrecision   =       CLIP_DEFAULT_PRECIS; // clipping precision
+               lgfnt.lfQuality                 =       DEFAULT_QUALITY;     // output quality
+               if( iflags.wc_font_menu &&
+                       *iflags.wc_font_menu ) {
+                       lgfnt.lfPitchAndFamily  = DEFAULT_PITCH;                 // pitch and family
+                       NH_A2W( iflags.wc_font_menu, lgfnt.lfFaceName, LF_FACESIZE);
+               } else {
+                       lgfnt.lfPitchAndFamily = FIXED_PITCH;            // pitch and family
+               }
+               break;
+
+       case NHW_MESSAGE:
+               font_size = (attr==ATR_INVERSE)? iflags.wc_fontsiz_message+1 : iflags.wc_fontsiz_message;
+               lgfnt.lfHeight                  =       -font_size*GetDeviceCaps(hdc, LOGPIXELSY)/72;    // height of font
+               lgfnt.lfWidth                   =       0;                                   // average character width
+               lgfnt.lfEscapement              =       0;                                       // angle of escapement
+               lgfnt.lfOrientation             =       0;                                       // base-line orientation angle
+               lgfnt.lfWeight                  =       (attr==ATR_BOLD || attr==ATR_INVERSE)? FW_BOLD : FW_NORMAL;   // font weight
+               lgfnt.lfItalic                  =       (attr==ATR_BLINK)? TRUE: FALSE;              // italic attribute option
+               lgfnt.lfUnderline               =       (attr==ATR_ULINE)? TRUE : FALSE;                 // underline attribute option
+               lgfnt.lfStrikeOut               =       FALSE;                       // strikeout attribute option
+               lgfnt.lfCharSet                 =       mswin_charset();     // character set identifier
+               lgfnt.lfOutPrecision    =       OUT_DEFAULT_PRECIS;  // output precision
+               lgfnt.lfClipPrecision   =       CLIP_DEFAULT_PRECIS; // clipping precision
+               lgfnt.lfQuality                 =       DEFAULT_QUALITY;     // output quality
+               if( iflags.wc_font_message &&
+                       *iflags.wc_font_message ) {
+                       lgfnt.lfPitchAndFamily  = DEFAULT_PITCH;                 // pitch and family
+                       NH_A2W( iflags.wc_font_message, lgfnt.lfFaceName, LF_FACESIZE);
+               } else {
+                       lgfnt.lfPitchAndFamily  = VARIABLE_PITCH;                // pitch and family
+               }
+               break;
+
+       case NHW_TEXT:
+               lgfnt.lfHeight                  =       -iflags.wc_fontsiz_text*GetDeviceCaps(hdc, LOGPIXELSY)/72;       // height of font
+               lgfnt.lfWidth                   =       0;                                   // average character width
+               lgfnt.lfEscapement              =       0;                                       // angle of escapement
+               lgfnt.lfOrientation             =       0;                                       // base-line orientation angle
+               lgfnt.lfWeight                  =       (attr==ATR_BOLD || attr==ATR_INVERSE)? FW_BOLD : FW_NORMAL;   // font weight
+               lgfnt.lfItalic                  =       (attr==ATR_BLINK)? TRUE: FALSE;              // italic attribute option
+               lgfnt.lfUnderline               =       (attr==ATR_ULINE)? TRUE : FALSE;                 // underline attribute option
+               lgfnt.lfStrikeOut               =       FALSE;                       // strikeout attribute option
+               lgfnt.lfCharSet                 =       mswin_charset();     // character set identifier
+               lgfnt.lfOutPrecision    =       OUT_DEFAULT_PRECIS;  // output precision
+               lgfnt.lfClipPrecision   =       CLIP_DEFAULT_PRECIS; // clipping precision
+               lgfnt.lfQuality                 =       DEFAULT_QUALITY;     // output quality
+               if( iflags.wc_font_text &&
+                       *iflags.wc_font_text ) {
+                       lgfnt.lfPitchAndFamily  = DEFAULT_PITCH;                 // pitch and family
+                       NH_A2W( iflags.wc_font_text, lgfnt.lfFaceName, LF_FACESIZE);
+               } else {
+                       lgfnt.lfPitchAndFamily  = FIXED_PITCH;           // pitch and family
+               }
+               break;
+       }
+
+       fnt = CreateFontIndirect(&lgfnt);
+
+       /* add font to the table */
+       if( font_index==font_table_size ) {
+               if( font_table_size>=MAXFONTS ) panic( "font table overflow!" );
+               font_table_size++;
+       } else {
+               DeleteObject(font_table[font_index].hFont);
+       }
+
+       font_table[font_index].code = NHFONT_CODE(win_type, attr);
+       font_table[font_index].hFont = fnt;
+       return fnt;
+}
+
+UINT mswin_charset()
+{
+       CHARSETINFO cis;
+       if( iflags.IBMgraphics )
+               if( TranslateCharsetInfo((DWORD*)GetOEMCP(), &cis, TCI_SRCCODEPAGE) ) 
+                       return cis.ciCharset;
+               else
+                       return OEM_CHARSET;
+       else 
+               if( TranslateCharsetInfo((DWORD*)GetACP(), &cis, TCI_SRCCODEPAGE) ) 
+                       return cis.ciCharset;
+               else
+                       return ANSI_CHARSET;
+}
+
+void __cdecl font_table_cleanup(void)
+{
+       int i;
+       for(i=0; i<font_table_size; i++) {
+               DeleteObject(font_table[i].hFont);
+       }
+       font_table_size = 0;
+}
+
diff --git a/sys/wince/mhfont.h b/sys/wince/mhfont.h
new file mode 100644 (file)
index 0000000..75b4fdf
--- /dev/null
@@ -0,0 +1,14 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* font management functions */
+
+#ifndef MSWINFont_h
+#define MSWINFont_h
+
+#include "winMS.h"
+
+HGDIOBJ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace);
+UINT mswin_charset();
+
+#endif /* MSWINFont_h */
diff --git a/sys/wince/mhinput.c b/sys/wince/mhinput.c
new file mode 100644 (file)
index 0000000..53ca65d
--- /dev/null
@@ -0,0 +1,86 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include <assert.h>
+#include "winMS.h"
+#include "mhinput.h"
+
+/* nethack input queue functions */
+
+#define NH_INPUT_BUFFER_SIZE  64
+
+/* as it stands right now we need only one slot 
+   since events are processed almost the same time as
+   they occur but I like large round numbers */
+
+static MSNHEvent nhi_input_buffer[NH_INPUT_BUFFER_SIZE];
+static int nhi_init_input = 0;
+static int nhi_read_pos = 0;
+static int nhi_write_pos = 0;
+
+/* initialize input queue */
+void mswin_nh_input_init() 
+{
+       if( !nhi_init_input ) {
+               nhi_init_input = 1;
+
+               ZeroMemory( nhi_input_buffer, sizeof(nhi_input_buffer) );
+               nhi_read_pos = 0;
+               nhi_write_pos = 0;
+       }
+}
+
+/* check for input */
+int    mswin_have_input()
+{
+       return (nhi_read_pos!=nhi_write_pos);
+}
+
+/* add event to the queue */
+void mswin_input_push(PMSNHEvent event)
+{
+       int new_write_pos;
+
+       if( !nhi_init_input ) mswin_nh_input_init();
+
+       new_write_pos = (nhi_write_pos+1) % NH_INPUT_BUFFER_SIZE;
+       
+       if(new_write_pos!=nhi_read_pos) {
+               memcpy(nhi_input_buffer+nhi_write_pos, event, sizeof(*event));
+               nhi_write_pos = new_write_pos;
+       }
+
+}
+
+/* get event from the queue and delete it */
+PMSNHEvent mswin_input_pop()
+{
+       PMSNHEvent retval;
+
+       if( !nhi_init_input ) mswin_nh_input_init();
+
+       if( nhi_read_pos!=nhi_write_pos ) {
+               retval = &nhi_input_buffer[nhi_read_pos];
+               nhi_read_pos = (nhi_read_pos+1) % NH_INPUT_BUFFER_SIZE;
+       } else {
+               retval = NULL;
+       }
+
+       return retval;
+}
+
+/* get event from the queue but leave it there */
+PMSNHEvent mswin_input_peek()
+{
+       PMSNHEvent retval;
+
+       if( !nhi_init_input ) mswin_nh_input_init();
+
+       if( nhi_read_pos!=nhi_write_pos ) {
+               retval = &nhi_input_buffer[nhi_read_pos];
+       } else {
+               retval = NULL;
+       }
+       return retval;
+}
+
diff --git a/sys/wince/mhinput.h b/sys/wince/mhinput.h
new file mode 100644 (file)
index 0000000..f3e235c
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINInput_h
+#define MSWINInput_h
+
+/* nethack input queue - store/extract input events */
+#include "winMS.h"
+
+#define NHEVENT_CHAR   1
+#define NHEVENT_MOUSE  2
+typedef struct mswin_event {
+       int type;
+       union {
+               struct {
+                       int  ch;
+               } kbd;
+
+               struct {
+                       int mod;
+                       int x, y;
+               } ms;
+       };
+} MSNHEvent, *PMSNHEvent;
+
+#define NHEVENT_KBD(c) { MSNHEvent e; e.type=NHEVENT_CHAR; e.kbd.ch=(c); mswin_input_push(&e); }
+#define NHEVENT_MS(_mod, _x, _y) { MSNHEvent e; e.type=NHEVENT_MOUSE; e.ms.mod = (_mod); e.ms.x=(_x); e.ms.y=(_y); mswin_input_push(&e); }
+
+void           mswin_nh_input_init();
+int                    mswin_have_input();
+void           mswin_input_push(PMSNHEvent event);
+PMSNHEvent     mswin_input_pop();
+PMSNHEvent     mswin_input_peek();
+
+#endif /* MSWINInput_h */
+
diff --git a/sys/wince/mhmain.c b/sys/wince/mhmain.c
new file mode 100644 (file)
index 0000000..31e3ba6
--- /dev/null
@@ -0,0 +1,1150 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include "mhmsg.h"
+#include "mhinput.h"
+#include "mhmain.h"
+#include "mhmenu.h"
+#include "mhstatus.h"
+#include "mhmsgwnd.h"
+#include "mhcmd.h"
+#include "mhmap.h"
+#include "patchlevel.h"
+
+#define MAX_LOADSTRING 100
+
+typedef struct mswin_nethack_main_window {
+       int                             mapAcsiiModeSave;
+} NHMainWindow, *PNHMainWindow;
+
+TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass");
+static TCHAR szTitle[MAX_LOADSTRING];
+
+LRESULT CALLBACK       MainWndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK       About(HWND, UINT, WPARAM, LPARAM);
+static LRESULT  onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void            onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void            register_main_window_class();
+static void            select_map_mode(int map_mode);
+static int             menuid2mapmode(int menuid);
+static int             mapmode2menuid(int map_mode);
+static HMENU   _get_main_menu(UINT menu_id);
+
+HWND mswin_init_main_window () {
+       static int run_once = 0;
+       HWND ret;
+       RECT rc;
+
+       /* register window class */
+       if( !run_once ) {
+               LoadString(GetNHApp()->hApp, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
+               register_main_window_class( );
+               run_once = 1;
+       }
+       
+       /* create the main window */
+       SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
+
+       ret = CreateWindow(
+                       szMainWindowClass,              /* registered class name */
+                       szTitle,                                /* window name */
+                       WS_CLIPCHILDREN,                /* window style */
+                       rc.left,                            /* horizontal position of window */
+                       rc.top,                         /* vertical position of window */
+                       rc.right - rc.left,             /* window width */
+                       rc.bottom - rc.top,             /* window height */
+                       NULL,                                   /* handle to parent or owner window */
+                       NULL,                                   /* menu handle or child identifier */
+                       GetNHApp()->hApp,               /* handle to application instance */
+                       NULL                                    /* window-creation data */
+               );
+
+       if( !ret ) panic("Cannot create main window");
+       return ret;
+}
+
+void register_main_window_class()
+{
+       WNDCLASS wcex;
+       
+       ZeroMemory(&wcex, sizeof(wcex));
+       wcex.style                      = CS_HREDRAW | CS_VREDRAW;
+       wcex.lpfnWndProc        = (WNDPROC)MainWndProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = GetNHApp()->hApp;
+       wcex.hIcon                      = LoadIcon(GetNHApp()->hApp, (LPCTSTR)IDI_WINHACK);
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szMainWindowClass;
+
+       RegisterClass(&wcex);
+}
+
+/*
+ * Keypad keys are translated to the normal values below.
+ * Shifted keypad keys are translated to the
+ *    shift values below.
+ */
+
+enum KEY_INDEXES {
+KEY_NW, KEY_N, KEY_NE, KEY_MINUS,
+KEY_W, KEY_GOINTERESTING, KEY_E, KEY_PLUS,
+KEY_SW, KEY_S, KEY_SE,
+KEY_INV, KEY_WAITLOOK,
+KEY_LAST};
+
+static const unsigned char
+/* normal, shift, control */
+keypad[KEY_LAST][3] = {
+       {'y', 'Y', C('y')}, /* 7 */
+       {'k', 'K', C('k')}, /* 8 */
+       {'u', 'U', C('u')}, /* 9 */
+       {'m', C('p'), C('p')}, /* - */
+       {'h', 'H', C('h')}, /* 4 */
+       {'g', 'G', 'g'}, /* 5 */
+       {'l', 'L', C('l')}, /* 6 */
+       {'+', 'P', C('p')}, /* + */
+       {'b', 'B', C('b')}, /* 1 */
+       {'j', 'J', C('j')}, /* 2 */
+       {'n', 'N', C('n')}, /* 3 */
+       {'i', 'I', C('i')}, /* Ins */
+       {'.', ':', ':'} /* Del */
+}, 
+numpad[KEY_LAST][3] = {
+       {'7', M('7'), '7'}, /* 7 */
+       {'8', M('8'), '8'}, /* 8 */
+       {'9', M('9'), '9'}, /* 9 */
+       {'m', C('p'), C('p')}, /* - */
+       {'4', M('4'), '4'}, /* 4 */
+       {'g', 'G', 'g'}, /* 5 */
+       {'6', M('6'), '6'}, /* 6 */
+       {'+', 'P', C('p')}, /* + */
+       {'1', M('1'), '1'}, /* 1 */
+       {'2', M('2'), '2'}, /* 2 */
+       {'3', M('3'), '3'}, /* 3 */
+       {'i', 'I', C('i')}, /* Ins */
+       {'.', ':', ':'} /* Del */
+};
+
+#define STATEON(x) ((GetKeyState(x) & 0xFFFE) != 0)
+#define KEYTABLE_REGULAR(x) ((iflags.num_pad ? numpad : keypad)[x][0])
+#define KEYTABLE_SHIFT(x) ((iflags.num_pad ? numpad : keypad)[x][1])
+#define KEYTABLE(x) (STATEON(VK_SHIFT) ? KEYTABLE_SHIFT(x) : KEYTABLE_REGULAR(x))
+
+/* map mode macros */
+#define IS_MAP_FIT_TO_SCREEN(mode) ((mode)==MAP_MODE_ASCII_FIT_TO_SCREEN || \
+                                                         (mode)==MAP_MODE_TILES_FIT_TO_SCREEN )
+  
+#define IS_MAP_ASCII(mode) ((mode)!=MAP_MODE_TILES && (mode)!=MAP_MODE_TILES_FIT_TO_SCREEN)
+
+    
+/*
+//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
+//
+//  PURPOSE:  Processes messages for the main window.
+*/
+LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       PNHMainWindow data;
+
+       switch (message) 
+       {
+               /*-----------------------------------------------------------------------*/
+               case WM_CREATE: {
+#if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
+                       SHMENUBARINFO menubar;
+#endif
+                       /* set window data */
+                       data = (PNHMainWindow)malloc(sizeof(NHMainWindow));
+                       if( !data ) panic("out of memory");
+                       ZeroMemory(data, sizeof(NHMainWindow));
+                       data->mapAcsiiModeSave = MAP_MODE_ASCII12x16;
+                       SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
+
+                       GetNHApp()->hMainWnd = hWnd;
+
+                       /* create menu bar */
+#if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
+                       ZeroMemory(&menubar, sizeof(menubar));
+                       menubar.cbSize = sizeof(menubar); 
+                       menubar.hwndParent = hWnd; 
+                       menubar.dwFlags = 0; 
+                       menubar.nToolBarId = IDC_WINHACK; 
+                       menubar.hInstRes = GetNHApp()->hApp; 
+#      if defined(WIN_CE_POCKETPC)
+                       menubar.nBmpId = IDB_MENUBAR; 
+                       menubar.cBmpImages = 2; 
+#      else
+                       menubar.nBmpId = 0; 
+                       menubar.cBmpImages = 0; 
+#      endif
+                       if( !SHCreateMenuBar(&menubar) ) panic("cannot create menu");
+                       GetNHApp()->hMenuBar = menubar.hwndMB;
+#else
+                       GetNHApp()->hMenuBar = CommandBar_Create(GetNHApp()->hApp, hWnd, 1);
+                       if( !GetNHApp()->hMenuBar ) panic("cannot create menu");
+                       CommandBar_InsertMenubar(
+                               GetNHApp()->hMenuBar, GetNHApp()->hApp,
+                               IDC_WINHACK, 0 );
+#endif
+                       CheckMenuItem(
+                               _get_main_menu(ID_VIEW),
+                               IDM_VIEW_KEYPAD,
+                               MF_BYCOMMAND | 
+                               (GetNHApp()->bCmdPad? MF_CHECKED : MF_UNCHECKED)
+                       );
+
+                       /* create command pad (keyboard emulator) */
+                       GetNHApp()->hCmdWnd = mswin_init_command_window();
+               } break;
+
+               /*-----------------------------------------------------------------------*/
+               
+               case WM_MSNH_COMMAND:
+                       onMSNHCommand(hWnd, wParam, lParam);
+               break;
+
+               /*-----------------------------------------------------------------------*/
+
+        case WM_KEYDOWN: 
+                       data = (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+                       /* translate arrow keys into nethack commands */
+            switch (wParam) 
+            { 
+                       case VK_LEFT:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window one line left */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_HSCROLL,
+                                               MAKEWPARAM(SB_LINEUP, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_W));
+                               }
+                       return 0;
+
+                       case VK_RIGHT:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window one line right */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_HSCROLL,
+                                               MAKEWPARAM(SB_LINEDOWN, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_E));
+                               }
+                       return 0;
+
+                       case VK_UP:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window one line up */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_VSCROLL,
+                                               MAKEWPARAM(SB_LINEUP, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_N));
+                               }
+                       return 0;
+
+                       case VK_DOWN:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window one line down */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_VSCROLL,
+                                               MAKEWPARAM(SB_LINEDOWN, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_S));
+                               }
+                       return 0;
+
+                       case VK_HOME:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window to upper left corner */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_VSCROLL,
+                                               MAKEWPARAM(SB_THUMBTRACK, 0),
+                                               (LPARAM)NULL
+                                       );
+
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_HSCROLL,
+                                               MAKEWPARAM(SB_THUMBTRACK, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_NW));
+                               }
+                       return 0;
+
+                       case VK_END:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window to lower right corner */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_VSCROLL,
+                                               MAKEWPARAM(SB_THUMBTRACK, ROWNO),
+                                               (LPARAM)NULL
+                                       );
+
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_HSCROLL,
+                                               MAKEWPARAM(SB_THUMBTRACK, COLNO),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_SW));
+                               }
+                       return 0;
+
+                       case VK_PRIOR:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window one page up */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_VSCROLL,
+                                               MAKEWPARAM(SB_PAGEUP, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_NE));
+                               }
+                       return 0;
+
+                       case VK_NEXT:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window one page down */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_VSCROLL,
+                                               MAKEWPARAM(SB_PAGEDOWN, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_SE));
+                               }
+                       return 0;
+
+                       case VK_DECIMAL:
+                       case VK_DELETE:
+                               NHEVENT_KBD(KEYTABLE(KEY_WAITLOOK));
+                       return 0;
+
+                       case VK_INSERT:
+                               NHEVENT_KBD(KEYTABLE(KEY_INV));
+                       return 0;
+
+                       case VK_SUBTRACT:
+                               NHEVENT_KBD(KEYTABLE(KEY_MINUS));
+                       return 0;
+
+                       case VK_ADD:
+                               NHEVENT_KBD(KEYTABLE(KEY_PLUS));
+                       return 0;
+
+                       case VK_CLEAR: /* This is the '5' key */
+                               NHEVENT_KBD(KEYTABLE(KEY_GOINTERESTING));
+                       return 0;
+
+                       case VK_F4:
+                               if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
+                                       mswin_select_map_mode(
+                                               IS_MAP_ASCII(iflags.wc_map_mode)? 
+                                                       data->mapAcsiiModeSave :
+                                                       MAP_MODE_TILES
+                                       );
+                               } else {
+                                       mswin_select_map_mode(
+                                               IS_MAP_ASCII(iflags.wc_map_mode)?
+                                                       MAP_MODE_ASCII_FIT_TO_SCREEN :
+                                                       MAP_MODE_TILES_FIT_TO_SCREEN
+                                       );
+                               }
+                       return 0;
+
+                       case VK_F5:
+                               if( IS_MAP_ASCII(iflags.wc_map_mode) ) {
+                                       if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
+                                               mswin_select_map_mode(MAP_MODE_TILES_FIT_TO_SCREEN);
+                                       } else {
+                                               mswin_select_map_mode(MAP_MODE_TILES);
+                                       }
+                               } else {
+                                       if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
+                                               mswin_select_map_mode(MAP_MODE_ASCII_FIT_TO_SCREEN);
+                                       } else {
+                                               mswin_select_map_mode(data->mapAcsiiModeSave);
+                                       }
+                               }
+                       return 0;
+
+                       case VK_RETURN:
+                               NHEVENT_MS( CLICK_1, u.ux, u.uy);
+                       return 0;
+                       } 
+
+#if defined(WIN_CE_SMARTPHONE)
+                       if( NHSPhoneTranslateKbdMessage(wParam, lParam, TRUE) ) return 0;
+#endif
+               return 1; /* end of WM_KEYDOWN */
+
+               /*-----------------------------------------------------------------------*/
+
+#if defined(WIN_CE_SMARTPHONE)
+               case WM_KEYUP:
+                       if( NHSPhoneTranslateKbdMessage(wParam, lParam, FALSE) ) return 0;
+               return 1; /* end of WM_KEYUP */
+#endif
+               /*-----------------------------------------------------------------------*/
+
+#if !defined(WIN_CE_SMARTPHONE)
+               case WM_CHAR:
+                       if( wParam=='\n' || wParam=='\r' || wParam==C('M') ) return 0; /* we already processed VK_RETURN */
+
+                       /* all characters go to nethack except Ctrl-P that scrolls message window up */
+                       if( wParam==C('P') || wParam==C('p') ) {
+                               SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL); 
+                       } else {
+                               NHEVENT_KBD( (lParam & 1<<29)? M(tolower(wParam)) : wParam );
+                       }
+               return 0;
+#endif
+
+               /*-----------------------------------------------------------------------*/
+
+               case WM_COMMAND:
+                       /* process commands - menu commands mostly */
+                       if( IsWindow(GetNHApp()->hPopupWnd) ) {
+                               return SendMessage(GetNHApp()->hPopupWnd, message, wParam, lParam);
+                       } else if( onWMCommand(hWnd, wParam, lParam) )
+                               return DefWindowProc(hWnd, message, wParam, lParam);
+                       else
+                               return 0;
+
+               /*-----------------------------------------------------------------------*/
+
+               case WM_ACTIVATE:
+                       if( LOWORD(wParam)!=WA_INACTIVE ) {
+#if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
+                               if( GetNHApp()->bFullScreen ) 
+                                       SHFullScreen(GetNHApp()->hMainWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON);
+                               else
+                                       SHFullScreen(GetNHApp()->hMainWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
+#endif
+                               mswin_layout_main_window(NULL);
+                       }
+               break;
+
+               case WM_SETTINGCHANGE:
+#if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
+                       if( GetNHApp()->bFullScreen ) 
+                               SHFullScreen(GetNHApp()->hMainWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON);
+                       else
+                               SHFullScreen(GetNHApp()->hMainWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
+#endif
+                       mswin_layout_main_window(NULL);
+               break;
+
+               case WM_SIZE:
+                       mswin_layout_main_window(NULL);
+               break;
+
+               /*-----------------------------------------------------------------------*/
+
+               case WM_SETFOCUS:
+                       /* if there is a menu window out there -
+                          transfer input focus to it */
+                       if( IsWindow( GetNHApp()->hPopupWnd ) ) {
+                               SetFocus( GetNHApp()->hPopupWnd );
+                       }
+                       break;
+
+               /*-----------------------------------------------------------------------*/
+
+               case WM_CLOSE: 
+               {
+                       /* exit gracefully */
+                       dosave0();
+               } return 0;
+
+               /*-----------------------------------------------------------------------*/
+
+               case WM_DESTROY: {
+                       /* apparently we never get here 
+                          TODO: work on exit routines - need to send
+                          WM_QUIT somehow */  
+
+                       /* clean up */
+                       free( (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA) );
+                       SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+
+                       terminate(EXIT_SUCCESS);
+               } break;
+
+               /*-----------------------------------------------------------------------*/
+
+               default:
+                       return DefWindowProc(hWnd, message, wParam, lParam);
+   }
+   return 0;
+}
+
+void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       switch(wParam) {
+
+       /* new window was just added */
+       case MSNH_MSG_ADDWND: {
+               PMSNHMsgAddWnd msg_param = (PMSNHMsgAddWnd)lParam;
+               HWND child = GetNHApp()->windowlist[msg_param->wid].win;
+
+               if( GetNHApp()->windowlist[msg_param->wid].type == NHW_MAP )
+                       mswin_select_map_mode(iflags.wc_map_mode);
+
+               if( child ) mswin_layout_main_window(child);
+       } break;
+
+       }
+}
+
+/* adjust windows to fit main window layout 
+   ---------------------------
+   |        Status           |
+   +-------------------------+
+   |                         |
+   |                         |
+   |          MAP            |
+   |                         |
+   |                         |
+   +-------------------------+   
+   |      Command pad        |
+   +-------------------------+
+   |        Messages         |
+   ---------------------------
+*/
+void mswin_layout_main_window(HWND changed_child)
+{
+       winid i;
+       RECT client_rt, wnd_rect;
+       POINT status_org;
+       SIZE status_size;
+       POINT msg_org;
+       SIZE msg_size;
+       POINT map_org;
+       SIZE map_size;
+       POINT cmd_org;
+       SIZE cmd_size;
+       HWND wnd_status, wnd_msg;
+       PNHMainWindow  data;
+#if defined(WIN_CE_POCKETPC)
+       SIPINFO sip;
+       RECT menu_bar;
+       RECT visible_rt;
+       POINT pt;
+#endif
+
+       GetClientRect(GetNHApp()->hMainWnd, &client_rt);
+
+#if defined(WIN_CE_POCKETPC)  
+       ZeroMemory(&sip, sizeof(sip));
+       sip.cbSize = sizeof(sip);
+       SHSipInfo(SPI_GETSIPINFO, 0, &sip, 0);
+       if( GetNHApp()->bFullScreen ) sip.rcVisibleDesktop.top = 0;
+
+       /* adjust client rectangle size */
+       GetWindowRect(GetNHApp()->hMenuBar, &menu_bar);
+       client_rt.bottom -= menu_bar.bottom-menu_bar.top;
+
+       /* calcuate visible rect in client coordinates */
+       pt.x = sip.rcVisibleDesktop.left;
+       pt.y = sip.rcVisibleDesktop.top;
+       ScreenToClient(GetNHApp()->hMainWnd, &pt);
+       SetRect(&wnd_rect, 
+                       pt.x, 
+                       pt.y, 
+                       pt.x+sip.rcVisibleDesktop.right-sip.rcVisibleDesktop.left,
+                       pt.y+sip.rcVisibleDesktop.bottom-sip.rcVisibleDesktop.top );
+       IntersectRect(&visible_rt, &client_rt, &wnd_rect);
+#else
+#      if      !defined(WIN_CE_SMARTPHONE)
+       client_rt.top += CommandBar_Height(GetNHApp()->hMenuBar);
+#      else
+       /* Smartphone only */
+       if( GetNHApp()->bFullScreen ) {
+               RECT menu_bar;
+               GetWindowRect(GetNHApp()->hMenuBar, &menu_bar);
+               client_rt.bottom -= menu_bar.bottom-menu_bar.top;
+       }
+#      endif
+#endif
+
+       /* get window data */
+       data = (PNHMainWindow)GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA);
+
+       /* get sizes of child windows */
+       wnd_status = mswin_hwnd_from_winid(WIN_STATUS);
+       if( IsWindow(wnd_status) ) { 
+               mswin_status_window_size(wnd_status, &status_size);
+       } else {
+               status_size.cx = status_size.cy = 0;
+       }
+
+       wnd_msg = mswin_hwnd_from_winid(WIN_MESSAGE);
+       if( IsWindow(wnd_msg) ) { 
+               mswin_message_window_size(wnd_msg, &msg_size);
+       } else {
+               msg_size.cx = msg_size.cy = 0;
+       }
+
+       cmd_size.cx = cmd_size.cy = 0;
+       if( GetNHApp()->bCmdPad && IsWindow(GetNHApp()->hCmdWnd) ) {
+               mswin_command_window_size(GetNHApp()->hCmdWnd, &cmd_size);
+       }
+
+       /* set window positions */
+
+       /* calculate the application windows size */
+#if defined(WIN_CE_POCKETPC)
+       SetRect(&wnd_rect, visible_rt.left, visible_rt.top, visible_rt.right, visible_rt.bottom);
+       if( sip.fdwFlags & SIPF_ON )
+               cmd_size.cx = cmd_size.cy = 0;  /* hide keypad window */
+#else
+       SetRect(&wnd_rect, client_rt.left, client_rt.top, client_rt.right, client_rt.bottom);
+#endif
+
+#if !defined(WIN_CE_SMARTPHONE)
+       /* other ports have it at the bottom of the screen */
+       cmd_size.cx = (wnd_rect.right-wnd_rect.left);
+       cmd_org.x = wnd_rect.left;
+       cmd_org.y = wnd_rect.bottom - cmd_size.cy;
+       wnd_rect.bottom -= cmd_size.cy;
+#endif
+
+       /* status window */
+       switch(iflags.wc_align_status) {
+       case ALIGN_LEFT:
+               status_size.cx = (wnd_rect.right-wnd_rect.left)/4;
+               status_size.cy = (wnd_rect.bottom-wnd_rect.top); // that won't look good
+               status_org.x = wnd_rect.left;
+               status_org.y = wnd_rect.top;
+               wnd_rect.left += status_size.cx;
+               break;
+
+       case ALIGN_RIGHT:  
+               status_size.cx = (wnd_rect.right-wnd_rect.left)/4; 
+               status_size.cy = (wnd_rect.bottom-wnd_rect.top); // that won't look good
+               status_org.x = wnd_rect.right - status_size.cx;
+               status_org.y = wnd_rect.top;
+               wnd_rect.right -= status_size.cx;
+               break;
+
+       case ALIGN_TOP:    
+               status_size.cx = (wnd_rect.right-wnd_rect.left);
+               status_org.x = wnd_rect.left;
+               status_org.y = wnd_rect.top;
+               wnd_rect.top += status_size.cy;
+               break;
+
+       case ALIGN_BOTTOM:
+       default:
+               status_size.cx = (wnd_rect.right-wnd_rect.left);
+               status_org.x = wnd_rect.left;
+               status_org.y = wnd_rect.bottom - status_size.cy;
+               wnd_rect.bottom -= status_size.cy;
+               break;
+       }
+
+       /* message window */
+       switch(iflags.wc_align_message) {
+       case ALIGN_LEFT:
+#if defined(WIN_CE_SMARTPHONE)
+               /* smartphone has a keypad window on the right (bottom) side of the message window */
+               msg_size.cx = cmd_size.cx = max(msg_size.cx, cmd_size.cx);
+               msg_size.cy = (wnd_rect.bottom-wnd_rect.top) - cmd_size.cy;
+               msg_org.x = cmd_org.x = wnd_rect.left;
+               msg_org.y = wnd_rect.top;
+               cmd_org.y = msg_org.y + msg_size.cy;
+#else
+               msg_size.cx = (wnd_rect.right-wnd_rect.left)/4;
+               msg_size.cy = (wnd_rect.bottom-wnd_rect.top); 
+               msg_org.x = wnd_rect.left;
+               msg_org.y = wnd_rect.top;
+#endif
+               wnd_rect.left += msg_size.cx;
+
+               break;
+
+       case ALIGN_RIGHT:  
+#if defined(WIN_CE_SMARTPHONE)
+               /* smartphone has a keypad window on the right (bottom) side of the message window */
+               msg_size.cx = cmd_size.cx = max(msg_size.cx, cmd_size.cx);
+               msg_size.cy = (wnd_rect.bottom-wnd_rect.top) - cmd_size.cy;
+               msg_org.x = cmd_org.x = wnd_rect.right - msg_size.cx;
+               msg_org.y = wnd_rect.top;
+               cmd_org.y = msg_org.y + msg_size.cy;
+#else
+               msg_size.cx = (wnd_rect.right-wnd_rect.left)/4; 
+               msg_size.cy = (wnd_rect.bottom-wnd_rect.top); 
+               msg_org.x = wnd_rect.right - msg_size.cx;
+               msg_org.y = wnd_rect.top;
+#endif
+       
+               wnd_rect.right -= msg_size.cx;
+               break;
+
+       case ALIGN_TOP:    
+#if defined(WIN_CE_SMARTPHONE)
+               /* smartphone has a keypad window on the right side of the message window */
+               msg_size.cy = cmd_size.cy = max(msg_size.cy, cmd_size.cy);
+               msg_size.cx = (wnd_rect.right - wnd_rect.left) - cmd_size.cx;
+               msg_org.x = wnd_rect.left;
+               cmd_org.x = msg_org.x + msg_size.cx;
+               msg_org.y = cmd_org.y = wnd_rect.bottom - msg_size.cy;
+#else
+               msg_size.cx = (wnd_rect.right-wnd_rect.left);
+               msg_org.x = wnd_rect.left;
+               msg_org.y = wnd_rect.top;
+#endif
+               wnd_rect.top += msg_size.cy;
+               break;
+
+       case ALIGN_BOTTOM:
+       default:
+#if defined(WIN_CE_SMARTPHONE)
+               /* smartphone has a keypad window on the right side of the message window */
+               msg_size.cy = cmd_size.cy = max(msg_size.cy, cmd_size.cy);
+               msg_size.cx = (wnd_rect.right - wnd_rect.left) - cmd_size.cx;
+               msg_org.x = wnd_rect.left;
+               cmd_org.x = msg_org.x + msg_size.cx;
+               msg_org.y = cmd_org.y = wnd_rect.bottom - msg_size.cy;
+#else
+               msg_size.cx = (wnd_rect.right-wnd_rect.left);
+               msg_org.x = wnd_rect.left;
+               msg_org.y = wnd_rect.bottom - msg_size.cy;
+#endif
+               wnd_rect.bottom -= msg_size.cy;
+               break;
+       }
+
+       map_org.x = wnd_rect.left;
+       map_org.y = wnd_rect.top;
+       map_size.cx = wnd_rect.right - wnd_rect.left;
+       map_size.cy = wnd_rect.bottom - wnd_rect.top;
+
+       /* go through the windows list and adjust sizes */
+       for( i=0; i<MAXWINDOWS; i++ ) {
+               if(GetNHApp()->windowlist[i].win && !GetNHApp()->windowlist[i].dead) {
+                       switch( GetNHApp()->windowlist[i].type ) {
+                       case NHW_MESSAGE:
+                               MoveWindow(GetNHApp()->windowlist[i].win, 
+                                              msg_org.x, 
+                                                  msg_org.y,
+                                                  msg_size.cx, 
+                                                  msg_size.cy, 
+                                                  TRUE );
+                               break;
+                       case NHW_MAP:
+                               MoveWindow(GetNHApp()->windowlist[i].win, 
+                                              map_org.x, 
+                                                  map_org.y,
+                                                  map_size.cx, 
+                                                  map_size.cy, 
+                                                  TRUE );
+                               break;
+                       case NHW_STATUS:
+                               MoveWindow(GetNHApp()->windowlist[i].win, 
+                                              status_org.x,
+                                                  status_org.y,
+                                                  status_size.cx, 
+                                                  status_size.cy, 
+                                                  TRUE );
+                               break;
+
+                       case NHW_TEXT:
+                       case NHW_MENU:
+                       case NHW_RIP:
+                       {
+                               POINT menu_org;
+                               SIZE menu_size;
+
+                               menu_org.x = client_rt.left;
+                               menu_org.y = client_rt.top;
+#if defined(WIN_CE_POCKETPC)
+                               menu_size.cx = min(sip.rcVisibleDesktop.right-sip.rcVisibleDesktop.left,
+                                                      client_rt.right - client_rt.left);
+                               menu_size.cy = min(sip.rcVisibleDesktop.bottom-sip.rcVisibleDesktop.top,
+                                                                  client_rt.bottom - client_rt.top);
+#else
+                               menu_size.cx = client_rt.right - client_rt.left;
+                               menu_size.cy = client_rt.bottom - client_rt.top;
+#endif
+
+#if defined(WIN_CE_SMARTPHONE)
+                               /* leave room for the command window */
+                               if( GetNHApp()->windowlist[i].type == NHW_MENU ) {
+                                       menu_size.cy -= cmd_size.cy;
+                               }
+
+                               /* dialogs are popup windows unde SmartPhone so we need 
+                                  to convert to screen coordinates */
+                               ClientToScreen(GetNHApp()->hMainWnd, &menu_org);
+#endif
+                               MoveWindow(GetNHApp()->windowlist[i].win, 
+                                              menu_org.x, 
+                                                  menu_org.y,
+                                                  menu_size.cx, 
+                                                  menu_size.cy, 
+                                                  TRUE );
+                       } break;
+                       }
+                       ShowWindow(GetNHApp()->windowlist[i].win, SW_SHOW);
+                       InvalidateRect(GetNHApp()->windowlist[i].win, NULL, TRUE);
+               }
+       }
+
+       if( IsWindow(GetNHApp()->hCmdWnd) ) {
+               /* show command window only if it exists and 
+                  the game is ready (plname is set) */
+               if( GetNHApp()->bCmdPad && cmd_size.cx>0 && cmd_size.cy>0 && *plname) {
+                       MoveWindow(GetNHApp()->hCmdWnd, 
+                                  cmd_org.x,
+                                  cmd_org.y,
+                                  cmd_size.cx, 
+                                  cmd_size.cy, 
+                                  TRUE );
+                       ShowWindow(GetNHApp()->hCmdWnd, SW_SHOW);
+               } else {
+                       ShowWindow(GetNHApp()->hCmdWnd, SW_HIDE);
+               }
+       }
+}
+
+LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       int wmId, wmEvent;
+       PNHMainWindow  data;
+
+       data = (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       wmId    = LOWORD(wParam); 
+       wmEvent = HIWORD(wParam); 
+
+       // process the menu selections:
+       switch (wmId)
+       {
+               case IDM_ABOUT:
+                  DialogBox(GetNHApp()->hApp, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
+                  break;
+
+               case IDM_EXIT:
+                  done2();
+                  break;
+
+               case IDM_SAVE:
+                  dosave();
+                  break;
+               
+               case IDM_MAP_TILES:
+               case IDM_MAP_ASCII4X6:
+               case IDM_MAP_ASCII6X8:
+               case IDM_MAP_ASCII8X8:
+               case IDM_MAP_ASCII16X8:
+               case IDM_MAP_ASCII7X12:
+               case IDM_MAP_ASCII8X12:
+               case IDM_MAP_ASCII12X16:
+               case IDM_MAP_ASCII16X12:
+               case IDM_MAP_ASCII10X18:
+                       mswin_select_map_mode(menuid2mapmode(wmId));
+                       break;
+
+               case IDM_MAP_FIT_TO_SCREEN:
+                       if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
+                               mswin_select_map_mode(
+                                       IS_MAP_ASCII(iflags.wc_map_mode)? 
+                                               data->mapAcsiiModeSave :
+                                               MAP_MODE_TILES
+                               );
+                       } else {
+                               mswin_select_map_mode(
+                                       IS_MAP_ASCII(iflags.wc_map_mode)?
+                                               MAP_MODE_ASCII_FIT_TO_SCREEN :
+                                               MAP_MODE_TILES_FIT_TO_SCREEN
+                               );
+                       }
+                       break;
+
+               case IDM_VIEW_KEYPAD:
+                       GetNHApp()->bCmdPad = !GetNHApp()->bCmdPad;
+                       CheckMenuItem(
+                               _get_main_menu(ID_VIEW),
+                               IDM_VIEW_KEYPAD,
+                               MF_BYCOMMAND | 
+                               (GetNHApp()->bCmdPad? MF_CHECKED : MF_UNCHECKED)
+                       );
+                       mswin_layout_main_window(GetNHApp()->hCmdWnd);
+                       break;
+
+               case IDM_VIEW_OPTIONS:
+                       doset();
+                       break;
+
+               case IDM_HELP_LONG:     
+                       display_file(HELP, TRUE);  
+                       break;
+               
+               case IDM_HELP_COMMANDS: 
+                       display_file(SHELP, TRUE);  
+                       break;
+               
+               case IDM_HELP_HISTORY:
+                       (void) dohistory();  
+                       break;
+               
+               case IDM_HELP_INFO_CHAR:
+                       (void) dowhatis();  
+                       break;
+               
+               case IDM_HELP_INFO_KEY:
+                       (void) dowhatdoes();  
+                       break;
+               
+               case IDM_HELP_OPTIONS:
+                       option_help();  
+                       break;
+               
+               case IDM_HELP_OPTIONS_LONG:
+                       display_file(OPTIONFILE, TRUE);  
+                       break;
+               
+               case IDM_HELP_EXTCMD:
+                       (void) doextlist();  
+                       break;
+               
+               case IDM_HELP_LICENSE:
+                       display_file(LICENSE, TRUE);  
+                       break;
+
+               case IDM_HELP_MENU:     
+                       dohelp();
+                       break;
+
+               default:
+                  return 1;
+       }
+       return 0;
+}
+
+// Mesage handler for about box.
+LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       char buf[BUFSZ];
+       TCHAR wbuf[NHSTR_BUFSIZE];
+       RECT   main_rt, dlg_rt;
+       SIZE   dlg_sz;
+
+       switch (message)
+       {
+               case WM_INITDIALOG:
+                               getversionstring(buf);
+                               SetDlgItemText(hDlg, IDC_ABOUT_VERSION, NH_A2W(buf, wbuf, NHSTR_BUFSIZE));
+
+                               SetDlgItemText(hDlg, IDC_ABOUT_COPYRIGHT,
+                                                       NH_A2W(
+                                                               COPYRIGHT_BANNER_A "\n"
+                                                               COPYRIGHT_BANNER_B "\n"
+                                                               COPYRIGHT_BANNER_C,
+                                                               wbuf,
+                                                               NHSTR_BUFSIZE
+                                                       ) );
+                                                         
+
+                               /* center dialog in the main window */
+                               GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
+                               GetWindowRect(hDlg, &dlg_rt);
+                               dlg_sz.cx = dlg_rt.right - dlg_rt.left;
+                               dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
+
+                               dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2;
+                               dlg_rt.right = dlg_rt.left + dlg_sz.cx;
+                               dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2;
+                               dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
+                               MoveWindow( hDlg,
+                                                       (main_rt.left+main_rt.right-dlg_sz.cx)/2,
+                                                       (main_rt.top+main_rt.bottom-dlg_sz.cy)/2,
+                                                       dlg_sz.cx,
+                                                       dlg_sz.cy,
+                                                       TRUE );
+
+                               return TRUE;
+
+               case WM_COMMAND:
+                       if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
+                       {
+                               EndDialog(hDlg, LOWORD(wParam));
+                               return TRUE;
+                       }
+                       break;
+       }
+    return FALSE;
+}
+
+
+/* Set map display mode */
+void mswin_select_map_mode(int mode)
+{
+       HMENU hmenuMap;
+       PNHMainWindow  data;
+       winid map_id;
+
+       map_id = WIN_MAP;
+       data = (PNHMainWindow)GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA);
+#if defined(WIN_CE_SMARTPHONE)
+       /* Smartphone manu has only 2 items */
+       hmenuMap = _get_main_menu(ID_VIEW);
+#else
+       hmenuMap = _get_main_menu(ID_MAP);
+#endif
+
+       /* override for Rogue level */
+#ifdef REINCARNATION
+    if( Is_rogue_level(&u.uz) && !IS_MAP_ASCII(mode) ) return;
+#endif
+
+       /* set map mode menu mark */
+       if( IS_MAP_ASCII(mode) ) {
+               CheckMenuRadioItem(
+                       hmenuMap, 
+                       IDM_MAP_TILES, 
+                       IDM_MAP_FIT_TO_SCREEN, 
+                       mapmode2menuid( IS_MAP_FIT_TO_SCREEN(mode)? data->mapAcsiiModeSave : mode ), 
+                       MF_BYCOMMAND);
+       } else {
+               CheckMenuRadioItem(
+                       hmenuMap, 
+                       IDM_MAP_TILES, 
+                       IDM_MAP_FIT_TO_SCREEN, 
+                       mapmode2menuid( MAP_MODE_TILES ), 
+                       MF_BYCOMMAND);
+       }
+
+#if defined(WIN_CE_SMARTPHONE)
+       /* update "Fit To Screen" item text */
+       {
+               TCHAR wbuf[BUFSZ];
+               TBBUTTONINFO tbbi;
+
+               ZeroMemory( wbuf, sizeof(wbuf) );
+               if( !LoadString( 
+                       GetNHApp()->hApp, 
+                       (IS_MAP_FIT_TO_SCREEN(mode)? IDS_CAP_NORMALMAP : IDS_CAP_ENTIREMAP),
+                       wbuf,
+                       BUFSZ) ) {
+                       panic("cannot load main menu strings");
+               }
+
+               ZeroMemory( &tbbi, sizeof(tbbi) );
+               tbbi.cbSize = sizeof(tbbi);
+               tbbi.dwMask = TBIF_TEXT;
+               tbbi.pszText = wbuf;
+               if( !SendMessage( 
+                               GetNHApp()->hMenuBar, 
+                               TB_SETBUTTONINFO, 
+                               IDM_MAP_FIT_TO_SCREEN, 
+                               (LPARAM)&tbbi) ) {
+                       error( "Cannot update IDM_MAP_FIT_TO_SCREEN menu item." );
+               }
+       }
+#else
+       /* set fit-to-screen mode mark */
+       CheckMenuItem(
+               hmenuMap,
+               IDM_MAP_FIT_TO_SCREEN,
+               MF_BYCOMMAND | 
+               (IS_MAP_FIT_TO_SCREEN(mode)? MF_CHECKED : MF_UNCHECKED)
+       );
+#endif
+
+       if( IS_MAP_ASCII(iflags.wc_map_mode) && !IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
+               data->mapAcsiiModeSave = iflags.wc_map_mode;
+       }
+
+       iflags.wc_map_mode = mode;
+       
+       /* 
+       ** first, check if WIN_MAP has been inialized.
+       ** If not - attempt to retrieve it by type, then check it again
+       */
+       if( map_id==WIN_ERR ) 
+               map_id = mswin_winid_from_type(NHW_MAP);
+       if( map_id!=WIN_ERR )
+               mswin_map_mode(mswin_hwnd_from_winid(map_id), mode);
+}
+
+static struct t_menu2mapmode {
+       int menuID;
+       int mapMode;
+} _menu2mapmode[] = 
+{
+       { IDM_MAP_TILES, MAP_MODE_TILES },
+       { IDM_MAP_ASCII4X6, MAP_MODE_ASCII4x6 },
+       { IDM_MAP_ASCII6X8, MAP_MODE_ASCII6x8 },
+       { IDM_MAP_ASCII8X8, MAP_MODE_ASCII8x8 },
+       { IDM_MAP_ASCII16X8, MAP_MODE_ASCII16x8 },
+       { IDM_MAP_ASCII7X12, MAP_MODE_ASCII7x12 },
+       { IDM_MAP_ASCII8X12, MAP_MODE_ASCII8x12 },
+       { IDM_MAP_ASCII12X16, MAP_MODE_ASCII12x16 },
+       { IDM_MAP_ASCII16X12, MAP_MODE_ASCII16x12 },
+       { IDM_MAP_ASCII10X18, MAP_MODE_ASCII10x18 },
+       { IDM_MAP_FIT_TO_SCREEN, MAP_MODE_ASCII_FIT_TO_SCREEN },
+       { -1, -1 }
+};
+
+int    menuid2mapmode(int menuid)
+{
+       struct t_menu2mapmode* p;
+       for( p = _menu2mapmode; p->mapMode!=-1; p++ ) 
+               if(p->menuID==menuid ) return p->mapMode;
+       return -1;
+}
+
+int    mapmode2menuid(int map_mode)
+{
+       struct t_menu2mapmode* p;
+       for( p = _menu2mapmode; p->mapMode!=-1; p++ ) 
+               if(p->mapMode==map_mode ) return p->menuID;
+       return -1;
+}
+
+HMENU _get_main_menu(UINT menu_id)
+{
+       HMENU hmenuMap;
+#if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
+       TBBUTTONINFO tbbi;
+#endif
+
+#if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
+       tbbi.cbSize = sizeof(tbbi);
+       tbbi.dwMask = TBIF_LPARAM;
+       SendMessage( GetNHApp()->hMenuBar, TB_GETBUTTONINFO, menu_id, (LPARAM)&tbbi);
+    hmenuMap = (HMENU)tbbi.lParam;
+#else
+       hmenuMap = CommandBar_GetMenu(GetNHApp()->hMenuBar, 0);
+#endif
+       return hmenuMap;
+}
+
diff --git a/sys/wince/mhmain.h b/sys/wince/mhmain.h
new file mode 100644 (file)
index 0000000..bd08b78
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINMainWindow_h
+#define MSWINMainWindow_h
+
+/* this is a main appliation window */
+
+#include "winMS.h"
+
+extern TCHAR szMainWindowClass[];
+HWND mswin_init_main_window ();
+void mswin_layout_main_window(HWND changed_child);
+void mswin_select_map_mode(int map_mode);
+
+#endif /* MSWINMainWindow_h */
+
diff --git a/sys/wince/mhmap.c b/sys/wince/mhmap.c
new file mode 100644 (file)
index 0000000..aad7941
--- /dev/null
@@ -0,0 +1,914 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include "mhmap.h"
+#include "mhmsg.h"
+#include "mhinput.h"
+#include "mhfont.h"
+
+#include "patchlevel.h"
+
+#define NHMAP_FONT_NAME TEXT("Terminal")
+#define MAXWINDOWTEXT 255
+
+extern short glyph2tile[];
+
+/* map window data */
+typedef struct mswin_nethack_map_window {
+       int map[COLNO][ROWNO];          /* glyph map */
+
+       int      mapMode;                               /* current map mode */
+       boolean bAsciiMode;                     /* switch ASCII/tiled mode */
+       boolean bFitToScreenMode;       /* switch Fit map to screen mode on/off */
+       int  xPos, yPos;                        /* scroll position */
+       int  xPageSize, yPageSize;      /* scroll page size */
+       int  xCur, yCur;                        /* position of the cursor */
+       int  xScrTile, yScrTile;        /* size of display tile */
+       POINT map_orig;                         /* map origin point */
+
+       HFONT hMapFont;                         /* font for ASCII mode */
+} NHMapWindow, *PNHMapWindow;
+
+static TCHAR szNHMapWindowClass[] = TEXT("MSNethackMapWndClass");
+LRESULT CALLBACK       MapWndProc(HWND, UINT, WPARAM, LPARAM);
+static void register_map_window_class(void);
+static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void onPaint(HWND hWnd);
+static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut);
+#if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
+static void nhglyph2charcolor(short glyph, uchar* ch, int* color);
+#endif
+static COLORREF nhcolor_to_RGB(int c);
+
+HWND mswin_init_map_window () {
+       static int run_once = 0;
+       HWND ret;
+       DWORD styles;
+
+       if( !run_once ) {
+               register_map_window_class();
+               run_once = 1;
+       }
+       
+       styles = WS_CHILD | WS_CLIPSIBLINGS;
+       if( !GetNHApp()->bHideScrollBars ) styles |= WS_HSCROLL | WS_VSCROLL;
+       ret = CreateWindow(
+                       szNHMapWindowClass,             /* registered class name */
+                       NULL,                                   /* window name */
+                       styles, /* window style */
+                       0,  /* horizontal position of window - set it later */
+                       0,  /* vertical position of window - set it later */
+                       0,  /* window width - set it later */
+                       0,  /* window height - set it later*/
+                       GetNHApp()->hMainWnd,   /* handle to parent or owner window */
+                       NULL,                                   /* menu handle or child identifier */
+                       GetNHApp()->hApp,               /* handle to application instance */
+                       NULL );                                 /* window-creation data */
+       if( !ret ) {
+               panic("Cannot create map window");
+       }
+       return ret;
+}
+
+void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw)
+{
+       PNHMapWindow data;
+       RECT         client_rt;
+       SCROLLINFO   si;
+       SIZE             wnd_size;                       
+       LOGFONT          lgfnt;
+
+       /* check arguments */
+       if( !IsWindow(hWnd) ||
+               !lpsz ||
+               lpsz->cx<=0 ||
+               lpsz->cy<=0 ) return;
+
+       /* calculate window size */
+       GetClientRect(hWnd, &client_rt);
+       wnd_size.cx = client_rt.right - client_rt.left;
+       wnd_size.cy = client_rt.bottom - client_rt.top;
+       
+       /* set new screen tile size */
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       data->xScrTile = 
+               max(1, (data->bFitToScreenMode? wnd_size.cx : lpsz->cx) / COLNO);
+       data->yScrTile = 
+               max(1, (data->bFitToScreenMode? wnd_size.cy : lpsz->cy) / ROWNO);
+
+       /* set map origin point */
+       data->map_orig.x = max(0, client_rt.left + (wnd_size.cx - data->xScrTile*COLNO)/2 );
+       data->map_orig.y = max(0, client_rt.top + (wnd_size.cy - data->yScrTile*ROWNO)/2 );
+
+       data->map_orig.x -= data->map_orig.x % data->xScrTile;
+       data->map_orig.y -= data->map_orig.y % data->yScrTile;
+
+       /* adjust horizontal scroll bar */
+       if( data->bFitToScreenMode )
+               data->xPageSize = COLNO+1;  /* disable scroll bar */
+       else
+               data->xPageSize = wnd_size.cx/data->xScrTile;
+
+       if( data->xPageSize >= COLNO ) {
+               data->xPos = 0;
+               GetNHApp()->bNoHScroll = TRUE;
+       } else {
+               GetNHApp()->bNoHScroll = FALSE;
+               data->xPos = max(0, min(COLNO-data->xPageSize+1, u.ux - data->xPageSize/2));
+       }
+
+       if( !GetNHApp()->bHideScrollBars ) {
+               si.cbSize = sizeof(si); 
+               si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS; 
+               si.nMin   = 0; 
+               si.nMax   = COLNO; 
+               si.nPage  = data->xPageSize; 
+               si.nPos   = data->xPos; 
+               SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); 
+       }
+
+       /* adjust vertical scroll bar */
+       if( data->bFitToScreenMode )
+               data->yPageSize = ROWNO+1;   /* disable scroll bar */
+       else
+               data->yPageSize = wnd_size.cy/data->yScrTile;
+
+       if( data->yPageSize >= ROWNO ) {
+               data->yPos = 0;
+               GetNHApp()->bNoVScroll = TRUE;
+       } else {
+               GetNHApp()->bNoVScroll = FALSE;
+               data->yPos = max(0, min(ROWNO-data->yPageSize+1, u.uy - data->yPageSize/2));
+       }
+
+       if( !GetNHApp()->bHideScrollBars ) {
+               si.cbSize = sizeof(si); 
+               si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS; 
+               si.nMin   = 0; 
+               si.nMax   = ROWNO; 
+               si.nPage  = data->yPageSize; 
+               si.nPos   = data->yPos; 
+               SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
+       }
+
+       /* create font */
+       if( data->hMapFont ) DeleteObject(data->hMapFont);
+       ZeroMemory(&lgfnt, sizeof(lgfnt));
+       lgfnt.lfHeight                  =       -data->yScrTile;         // height of font
+       lgfnt.lfWidth                   =       -data->xScrTile;         // average character width
+       lgfnt.lfEscapement              =       0;                                       // angle of escapement
+       lgfnt.lfOrientation             =       0;                                       // base-line orientation angle
+       lgfnt.lfWeight                  =       FW_NORMAL;                       // font weight
+       lgfnt.lfItalic                  =       FALSE;                           // italic attribute option
+       lgfnt.lfUnderline               =       FALSE;                           // underline attribute option
+       lgfnt.lfStrikeOut               =       FALSE;                       // strikeout attribute option
+       lgfnt.lfCharSet                 =       mswin_charset();     // character set identifier
+       lgfnt.lfOutPrecision    =       OUT_DEFAULT_PRECIS;  // output precision
+       lgfnt.lfClipPrecision   =       CLIP_DEFAULT_PRECIS; // clipping precision
+       lgfnt.lfQuality                 =       DEFAULT_QUALITY;     // output quality
+       if( iflags.wc_font_map &&
+               *iflags.wc_font_map ) {
+               lgfnt.lfPitchAndFamily  = DEFAULT_PITCH;                 // pitch and family
+               NH_A2W(iflags.wc_font_map, lgfnt.lfFaceName, LF_FACESIZE);
+       } else {
+               lgfnt.lfPitchAndFamily  = FIXED_PITCH;           // pitch and family
+               _tcsncpy(lgfnt.lfFaceName, NHMAP_FONT_NAME, LF_FACESIZE);
+       }
+       data->hMapFont = CreateFontIndirect(&lgfnt);
+
+       mswin_cliparound(data->xCur, data->yCur);
+
+       if(redraw) InvalidateRect(hWnd, NULL, TRUE);
+}
+
+/* set map mode */
+int mswin_map_mode(HWND hWnd, int mode)
+{
+       PNHMapWindow data;
+       int oldMode;
+       SIZE mapSize;
+
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if( mode == data->mapMode ) return mode;
+       
+       oldMode = data->mapMode;
+       data->mapMode = mode;
+
+       switch( data->mapMode ) {
+
+       case MAP_MODE_ASCII4x6:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 4*COLNO;
+               mapSize.cy = 6*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII6x8:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 6*COLNO;
+               mapSize.cy = 8*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII8x8:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 8*COLNO;
+               mapSize.cy = 8*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII16x8:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 16*COLNO;
+               mapSize.cy = 8*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII7x12:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 7*COLNO;
+               mapSize.cy = 12*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII8x12:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 8*COLNO;
+               mapSize.cy = 12*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII16x12:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 16*COLNO;
+               mapSize.cy = 12*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII12x16:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 12*COLNO;
+               mapSize.cy = 16*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII10x18:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 10*COLNO;
+               mapSize.cy = 18*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII_FIT_TO_SCREEN: {
+               RECT client_rt;
+               GetClientRect(hWnd, &client_rt);
+               mapSize.cx = client_rt.right - client_rt.left;
+               mapSize.cy = client_rt.bottom - client_rt.top;
+
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = TRUE;
+       } break;
+
+       case MAP_MODE_TILES_FIT_TO_SCREEN: {
+               RECT client_rt;
+               GetClientRect(hWnd, &client_rt);
+               mapSize.cx = client_rt.right - client_rt.left;
+               mapSize.cy = client_rt.bottom - client_rt.top;
+
+               data->bAsciiMode = FALSE;
+               data->bFitToScreenMode = TRUE;
+       } break;
+
+       case MAP_MODE_TILES:
+       default:
+               data->bAsciiMode = FALSE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = GetNHApp()->mapTile_X*COLNO;
+               mapSize.cy = GetNHApp()->mapTile_Y*ROWNO;
+       break;
+       }
+
+       mswin_map_stretch(hWnd, &mapSize, TRUE);
+
+       return oldMode;
+}
+
+/* register window class for map window */
+void register_map_window_class()
+{
+       WNDCLASS wcex;
+       ZeroMemory( &wcex, sizeof(wcex));
+
+       /* window class */
+       wcex.style                      = CS_NOCLOSE | CS_DBLCLKS;
+       wcex.lpfnWndProc        = (WNDPROC)MapWndProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = GetNHApp()->hApp;
+       wcex.hIcon                      = NULL;
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = CreateSolidBrush(RGB(0, 0, 0)); /* set backgroup here */
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szNHMapWindowClass;
+
+       if( !RegisterClass(&wcex) ) {
+               panic("cannot register Map window class");
+       }
+}
+    
+/* map window procedure */    
+LRESULT CALLBACK MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       PNHMapWindow data;
+       
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch (message) 
+       {
+       case WM_CREATE:
+               onCreate( hWnd, wParam, lParam );
+               break;
+
+       case WM_MSNH_COMMAND:
+               onMSNHCommand(hWnd, wParam, lParam);
+               break;
+
+       case WM_PAINT: 
+               onPaint(hWnd);
+               break;
+
+       case WM_SETFOCUS:
+               /* transfer focus back to the main window */
+               SetFocus(GetNHApp()->hMainWnd);
+               break;
+
+       case WM_HSCROLL:
+               onMSNH_HScroll(hWnd, wParam, lParam);
+               break;
+
+       case WM_VSCROLL:
+               onMSNH_VScroll(hWnd, wParam, lParam);
+               break;
+
+    case WM_SIZE: 
+    { 
+               SIZE size;
+
+               if( data->bFitToScreenMode ) {
+                       size.cx = LOWORD(lParam);
+                       size.cy = HIWORD(lParam);
+               } else {
+                       /* mapping factor is unchaged we just need to adjust scroll bars */
+                       size.cx = data->xScrTile*COLNO; 
+                       size.cy = data->yScrTile*ROWNO;
+               }
+               mswin_map_stretch(hWnd, &size, TRUE);
+    } 
+    break; 
+
+       case WM_LBUTTONDOWN:
+               NHEVENT_MS( 
+                       CLICK_1,
+                       max(0, min(COLNO, data->xPos + (LOWORD(lParam)-data->map_orig.x)/data->xScrTile)),
+                       max(0, min(ROWNO, data->yPos + (HIWORD(lParam)-data->map_orig.y)/data->yScrTile))
+               );
+       return 0;
+
+       case WM_LBUTTONDBLCLK :
+               NHEVENT_MS( 
+                       CLICK_2,
+                       max(0, min(COLNO, data->xPos + (LOWORD(lParam)-data->map_orig.x)/data->xScrTile)),
+                       max(0, min(ROWNO, data->yPos + (HIWORD(lParam)-data->map_orig.y)/data->yScrTile))
+               );
+       return 0;
+
+       case WM_DESTROY:
+               if( data->hMapFont ) DeleteObject(data->hMapFont);
+               free(data);
+               SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+               break;
+
+       default:
+               return DefWindowProc(hWnd, message, wParam, lParam);
+   }
+   return 0;
+}
+
+/* on WM_COMMAND */
+void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMapWindow data;
+       RECT rt;
+
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch(wParam) {
+       case MSNH_MSG_PRINT_GLYPH: 
+       {
+               PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph)lParam;
+               data->map[msg_data->x][msg_data->y] = msg_data->glyph;
+
+               /* invalidate the update area */
+               nhcoord2display(data, msg_data->x, msg_data->y, &rt);
+               InvalidateRect(hWnd, &rt, TRUE);
+       } 
+       break;
+
+       case MSNH_MSG_CLIPAROUND: 
+       {
+               PMSNHMsgClipAround msg_data = (PMSNHMsgClipAround)lParam;
+               int x, y;
+               BOOL scroll_x, scroll_y;
+               int mcam = iflags.wc_scroll_margin;
+
+               /* calculate if you should clip around */
+               scroll_x =  
+                       !GetNHApp()->bNoHScroll &&
+                       ( msg_data->x<(data->xPos+mcam) ||
+                         msg_data->x>(data->xPos+data->xPageSize-mcam) );
+               scroll_y =  
+                       !GetNHApp()->bNoVScroll &&
+                       ( msg_data->y<(data->yPos+mcam) ||
+                         msg_data->y>(data->yPos+data->yPageSize-mcam) );
+               
+               mcam += iflags.wc_scroll_amount - 1;
+               /* get page size and center horizontally on x-position */
+               if( scroll_x ) {
+                       if( data->xPageSize<=2*mcam ) {
+                               x = max(0, min(COLNO, msg_data->x - data->xPageSize/2));
+                       } else if( msg_data->x < data->xPos+data->xPageSize/2 ) {
+                               x = max(0, min(COLNO, msg_data->x - mcam));
+                       } else {
+                               x = max(0, min(COLNO, msg_data->x - data->xPageSize + mcam));
+                       }
+                       SendMessage( hWnd, WM_HSCROLL, (WPARAM)MAKELONG(SB_THUMBTRACK, x), (LPARAM)NULL );
+               }
+
+               /* get page size and center vertically on y-position */
+               if( scroll_y ) {
+                       if( data->yPageSize<=2*mcam ) {
+                               y = max(0, min(ROWNO, msg_data->y - data->yPageSize/2));
+                       } else if( msg_data->y < data->yPos+data->yPageSize/2 ) {
+                               y = max(0, min(ROWNO, msg_data->y - mcam));
+                       } else {
+                               y = max(0, min(ROWNO, msg_data->y - data->yPageSize + mcam));
+                       }
+                       SendMessage( hWnd, WM_VSCROLL, (WPARAM)MAKELONG(SB_THUMBTRACK, y), (LPARAM)NULL );
+               }
+       } 
+       break;
+
+       case MSNH_MSG_CLEAR_WINDOW: 
+       {
+               int i, j;
+               for(i=0; i<COLNO; i++) 
+                       for(j=0; j<ROWNO; j++) {
+                       data->map[i][j] = -1;
+               }
+               InvalidateRect(hWnd, NULL, TRUE);
+       } break;
+
+       case MSNH_MSG_CURSOR:
+       {
+               PMSNHMsgCursor msg_data = (PMSNHMsgCursor)lParam;
+               HDC    hdc;
+               RECT   rt;
+
+               /* move focus rectangle at the cursor postion */
+               hdc = GetDC(hWnd);
+
+               nhcoord2display(data, data->xCur, data->yCur, &rt);
+               if( data->bAsciiMode ) {
+                       PatBlt(hdc, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, DSTINVERT);    
+               } else {
+                       DrawFocusRect(hdc, &rt);
+               }
+               
+               data->xCur = msg_data->x;
+               data->yCur = msg_data->y;
+
+               nhcoord2display(data, data->xCur, data->yCur, &rt);
+               if( data->bAsciiMode ) {
+                       PatBlt(hdc, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, DSTINVERT);    
+               } else {
+                       DrawFocusRect(hdc, &rt);
+               }
+
+               ReleaseDC(hWnd, hdc);
+       } break;
+       }
+}
+
+/* on WM_CREATE */
+void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMapWindow data;
+       int i,j;
+
+       /* set window data */
+       data = (PNHMapWindow)malloc(sizeof(NHMapWindow));
+       if( !data ) panic("out of memory");
+
+       ZeroMemory(data, sizeof(NHMapWindow));
+       for(i=0; i<COLNO; i++) 
+               for(j=0; j<ROWNO; j++) {
+               data->map[i][j] = -1;
+       }
+
+       data->bAsciiMode = FALSE;
+
+       data->xScrTile = GetNHApp()->mapTile_X;
+       data->yScrTile = GetNHApp()->mapTile_Y;
+
+       SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
+}
+
+/* on WM_PAINT */
+void onPaint(HWND hWnd) 
+{
+       PNHMapWindow data;
+       PAINTSTRUCT ps;
+       HDC hDC;
+       HDC tileDC;
+       HGDIOBJ saveBmp;
+       RECT paint_rt;
+       int i, j;
+
+       /* get window data */
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       hDC = BeginPaint(hWnd, &ps);
+
+       /* calculate paint rectangle */
+       if( !IsRectEmpty(&ps.rcPaint) ) {
+               /* calculate paint rectangle */
+               paint_rt.left = max(data->xPos + (ps.rcPaint.left - data->map_orig.x)/data->xScrTile, 0);
+               paint_rt.top = max(data->yPos + (ps.rcPaint.top - data->map_orig.y)/data->yScrTile, 0);
+               paint_rt.right = min(data->xPos + (ps.rcPaint.right - data->map_orig.x)/data->xScrTile+1, COLNO);
+               paint_rt.bottom = min(data->yPos + (ps.rcPaint.bottom - data->map_orig.y)/data->yScrTile+1, ROWNO);
+
+               if( data->bAsciiMode
+#ifdef REINCARNATION
+                   || Is_rogue_level(&u.uz) 
+                       /* You enter a VERY primitive world! */
+#endif
+                       ) {
+                       HGDIOBJ oldFont;
+
+                       oldFont = SelectObject(hDC, data->hMapFont);
+                       SetBkMode(hDC, TRANSPARENT);
+
+                       /* draw the map */
+                       for(i=paint_rt.left; i<paint_rt.right; i++) 
+                       for(j=paint_rt.top; j<paint_rt.bottom; j++) 
+                       if(data->map[i][j]>=0) {
+                               char ch;
+                               TCHAR wch;
+                               RECT  glyph_rect;
+                               int   color;
+                               unsigned special;
+                               int mgch;
+                               HBRUSH back_brush;
+                               COLORREF OldFg;
+
+                               nhcoord2display(data, i, j, &glyph_rect);
+
+#if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
+                               nhglyph2charcolor(data->map[i][j], &ch, &color);
+                               OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) );
+#else
+                               /* rely on NetHack core helper routine */
+                               mapglyph(data->map[i][j], &mgch, &color,
+                                               &special, i, j);
+                               ch = (char)mgch;
+                               if (((special & MG_PET) && iflags.hilite_pet) ||
+                                   ((special & MG_DETECT) && iflags.use_inverse)) {
+                                       back_brush = CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY));
+                                       FillRect (hDC, &glyph_rect, back_brush);
+                                       DeleteObject (back_brush);
+                                       switch (color)
+                                       {
+                                       case CLR_GRAY:
+                                       case CLR_WHITE:
+                                               OldFg = SetTextColor( hDC,  nhcolor_to_RGB(CLR_BLACK));
+                                               break;
+                                       default:
+                                               OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) );
+                                       }
+                               } else {
+                                       OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) );
+                               }
+#endif
+
+                               DrawText(hDC, 
+                                                NH_A2W(&ch, &wch, 1),
+                                                1,
+                                                &glyph_rect,
+                                                DT_CENTER | DT_VCENTER | DT_NOPREFIX
+                                                );
+                               SetTextColor (hDC, OldFg);
+                       }
+                       SelectObject(hDC, oldFont);
+               } else {
+                       /* prepare tiles DC for mapping */
+                       tileDC = CreateCompatibleDC(hDC);
+                       saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles);
+
+                       /* draw the map */
+                       for(i=paint_rt.left; i<paint_rt.right; i++) 
+                       for(j=paint_rt.top; j<paint_rt.bottom; j++) 
+                               if(data->map[i][j]>=0) {
+                                       short ntile;
+                                       int t_x, t_y;
+                                       RECT glyph_rect;
+
+                                       ntile = glyph2tile[ data->map[i][j] ];
+                                       t_x = (ntile % GetNHApp()->mapTilesPerLine)*GetNHApp()->mapTile_X;
+                                       t_y = (ntile / GetNHApp()->mapTilesPerLine)*GetNHApp()->mapTile_Y;
+                                       
+                                       nhcoord2display(data, i, j, &glyph_rect);
+
+                                       StretchBlt( 
+                                               hDC, 
+                                               glyph_rect.left,
+                                               glyph_rect.top, 
+                                               data->xScrTile,
+                                               data->yScrTile,
+                                               tileDC,
+                                               t_x,
+                                               t_y,
+                                               GetNHApp()->mapTile_X, 
+                                               GetNHApp()->mapTile_Y, 
+                                               SRCCOPY 
+                                       );
+                                       if( glyph_is_pet(data->map[i][j]) && iflags.wc_hilite_pet ) {
+                                               /* apply pet mark transparently over 
+                                                  pet image */
+                                               HDC hdcPetMark;
+                                               HBITMAP    bmPetMarkOld;
+
+                                               /* this is DC for petmark bitmap */
+                                               hdcPetMark = CreateCompatibleDC(hDC);
+                                               bmPetMarkOld = SelectObject(hdcPetMark, GetNHApp()->bmpPetMark);
+
+                                               nhapply_image_transparent( 
+                                                       hDC,
+                                                       glyph_rect.left,
+                                                       glyph_rect.top, 
+                                                       data->xScrTile,
+                                                       data->yScrTile,
+                                                       hdcPetMark,
+                                                       0,
+                                                       0,
+                                                       TILE_X, 
+                                                       TILE_Y,
+                                                       TILE_BK_COLOR 
+                                               );
+                                               SelectObject(hdcPetMark, bmPetMarkOld);
+                                               DeleteDC(hdcPetMark);
+                                       }
+                               }
+                       SelectObject(tileDC, saveBmp);
+                       DeleteDC(tileDC);
+               }
+
+               /* draw focus rect */
+               nhcoord2display(data, data->xCur, data->yCur, &paint_rt);
+               if( data->bAsciiMode ) {
+                       PatBlt( hDC, 
+                                   paint_rt.left, paint_rt.top, 
+                                   paint_rt.right-paint_rt.left, paint_rt.bottom-paint_rt.top, 
+                                   DSTINVERT );        
+               } else {
+                       DrawFocusRect(hDC, &paint_rt);
+               }
+       }
+       EndPaint(hWnd, &ps);
+}
+
+/* on WM_VSCROLL */
+void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMapWindow data;
+       SCROLLINFO si;
+       int yNewPos;
+       int yDelta;
+       /* get window data */
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+    switch(LOWORD (wParam)) 
+    { 
+        /* User clicked shaft left of the scroll box. */
+        case SB_PAGEUP: 
+             yNewPos = data->yPos-data->yPageSize; 
+             break; 
+
+        /* User clicked shaft right of the scroll box. */
+        case SB_PAGEDOWN: 
+             yNewPos = data->yPos+data->yPageSize; 
+             break; 
+
+        /* User clicked the left arrow. */
+        case SB_LINEUP: 
+             yNewPos = data->yPos-1; 
+             break; 
+
+        /* User clicked the right arrow. */
+        case SB_LINEDOWN: 
+             yNewPos = data->yPos+1; 
+             break; 
+
+        /* User dragged the scroll box. */
+        case SB_THUMBTRACK: 
+             yNewPos = HIWORD(wParam); 
+             break; 
+
+        default: 
+             yNewPos = data->yPos; 
+    } 
+
+       yNewPos = max(0, min(ROWNO-data->yPageSize+1, yNewPos));
+       if( yNewPos == data->yPos ) return;
+       
+       yDelta = yNewPos - data->yPos;
+       data->yPos = yNewPos;
+
+    ScrollWindowEx (hWnd, 0, -data->yScrTile * yDelta, 
+            (CONST RECT *) NULL, (CONST RECT *) NULL, 
+            (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); 
+
+       if( !GetNHApp()->bHideScrollBars ) {
+               si.cbSize = sizeof(si); 
+               si.fMask  = SIF_POS; 
+               si.nPos   = data->yPos; 
+               SetScrollInfo(hWnd, SB_VERT, &si, TRUE); 
+       }
+}
+
+/* on WM_HSCROLL */
+void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMapWindow data;
+       SCROLLINFO si;
+       int xNewPos;
+       int xDelta;
+       /* get window data */
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       
+    switch(LOWORD (wParam)) 
+    { 
+        /* User clicked shaft left of the scroll box. */
+        case SB_PAGEUP: 
+             xNewPos = data->xPos-data->xPageSize; 
+             break; 
+
+        /* User clicked shaft right of the scroll box. */
+        case SB_PAGEDOWN: 
+             xNewPos = data->xPos+data->xPageSize; 
+             break; 
+
+        /* User clicked the left arrow. */
+        case SB_LINEUP: 
+             xNewPos = data->xPos-1; 
+             break; 
+
+        /* User clicked the right arrow. */
+        case SB_LINEDOWN: 
+             xNewPos = data->xPos+1; 
+             break; 
+
+        /* User dragged the scroll box. */
+        case SB_THUMBTRACK: 
+             xNewPos = HIWORD(wParam); 
+             break; 
+
+        default: 
+             xNewPos = data->xPos; 
+    } 
+
+       xNewPos = max(0, min(COLNO-data->xPageSize+1, xNewPos));
+       if( xNewPos == data->xPos ) return;
+       
+       xDelta = xNewPos - data->xPos;
+       data->xPos = xNewPos;
+
+    ScrollWindowEx (hWnd, -data->xScrTile * xDelta, 0, 
+            (CONST RECT *) NULL, (CONST RECT *) NULL, 
+            (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); 
+
+       if( !GetNHApp()->bHideScrollBars ) {
+               si.cbSize = sizeof(si); 
+               si.fMask  = SIF_POS; 
+               si.nPos   = data->xPos; 
+               SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); 
+       }
+}
+
+/* map nethack map coordinates to the screen location */
+void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut)
+{
+       lpOut->left = (x - data->xPos)*data->xScrTile + data->map_orig.x;
+       lpOut->top  = (y - data->yPos)*data->yScrTile + data->map_orig.y;
+       lpOut->right = lpOut->left + data->xScrTile;
+       lpOut->bottom = lpOut->top + data->yScrTile;
+}
+
+#if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
+/* map glyph to character/color combination */
+void nhglyph2charcolor(short g, uchar* ch, int* color)
+{
+       int offset;
+#ifdef TEXTCOLOR
+
+#define zap_color(n)  *color = iflags.use_color ? zapcolors[n] : NO_COLOR
+#define cmap_color(n) *color = iflags.use_color ? defsyms[n].color : NO_COLOR
+#define obj_color(n)  *color = iflags.use_color ? objects[n].oc_color : NO_COLOR
+#define mon_color(n)  *color = iflags.use_color ? mons[n].mcolor : NO_COLOR
+#define pet_color(n)  *color = iflags.use_color ? mons[n].mcolor : NO_COLOR
+#define warn_color(n) *color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR
+
+# else /* no text color */
+
+#define zap_color(n)
+#define cmap_color(n)
+#define obj_color(n)
+#define mon_color(n)
+#define pet_color(c)
+#define warn_color(c)
+       *color = CLR_WHITE;
+#endif
+
+       if ((offset = (g - GLYPH_WARNING_OFF)) >= 0) {    /* a warning flash */
+               *ch = warnsyms[offset];
+               warn_color(offset);
+       } else if ((offset = (g - GLYPH_SWALLOW_OFF)) >= 0) {   /* swallow */
+               /* see swallow_to_glyph() in display.c */
+               *ch = (uchar) showsyms[S_sw_tl + (offset & 0x7)];
+               mon_color(offset >> 3);
+       } else if ((offset = (g - GLYPH_ZAP_OFF)) >= 0) {       /* zap beam */
+               /* see zapdir_to_glyph() in display.c */
+               *ch = showsyms[S_vbeam + (offset & 0x3)];
+               zap_color((offset >> 2));
+       } else if ((offset = (g - GLYPH_CMAP_OFF)) >= 0) {      /* cmap */
+               *ch = showsyms[offset];
+               cmap_color(offset);
+       } else if ((offset = (g - GLYPH_OBJ_OFF)) >= 0) {       /* object */
+               *ch = oc_syms[(int)objects[offset].oc_class];
+               obj_color(offset);
+       } else if ((offset = (g - GLYPH_BODY_OFF)) >= 0) {      /* a corpse */
+               *ch = oc_syms[(int)objects[CORPSE].oc_class];
+               mon_color(offset);
+       } else if ((offset = (g - GLYPH_PET_OFF)) >= 0) {       /* a pet */
+               *ch = monsyms[(int)mons[offset].mlet];
+               pet_color(offset);
+       } else {                                                        /* a monster */
+               *ch = monsyms[(int)mons[g].mlet];
+               mon_color(g);
+       }       
+       // end of wintty code
+}
+#endif
+
+/* map nethack color to RGB */
+COLORREF nhcolor_to_RGB(int c)
+{
+       switch(c) {
+       case CLR_BLACK:                 return RGB(0x55, 0x55, 0x55);
+       case CLR_RED:                   return RGB(0xFF, 0x00, 0x00);
+       case CLR_GREEN:                 return RGB(0x00, 0x80, 0x00);
+       case CLR_BROWN:                 return RGB(0xA5, 0x2A, 0x2A);
+       case CLR_BLUE:                  return RGB(0x00, 0x00, 0xFF);
+       case CLR_MAGENTA:               return RGB(0xFF, 0x00, 0xFF);
+       case CLR_CYAN:                  return RGB(0x00, 0xFF, 0xFF);
+       case CLR_GRAY:                  return RGB(0xC0, 0xC0, 0xC0);
+       case NO_COLOR:                  return RGB(0xFF, 0xFF, 0xFF);
+       case CLR_ORANGE:                return RGB(0xFF, 0xA5, 0x00);
+       case CLR_BRIGHT_GREEN:          return RGB(0x00, 0xFF, 0x00);
+       case CLR_YELLOW:                return RGB(0xFF, 0xFF, 0x00);
+       case CLR_BRIGHT_BLUE:           return RGB(0x00, 0xC0, 0xFF);
+       case CLR_BRIGHT_MAGENTA:        return RGB(0xFF, 0x80, 0xFF);
+       case CLR_BRIGHT_CYAN:           return RGB(0x80, 0xFF, 0xFF);   /* something close to aquamarine */
+       case CLR_WHITE:                 return RGB(0xFF, 0xFF, 0xFF);
+       default:                        return RGB(0x00, 0x00, 0x00);   /* black */
+       }
+}
+
+/* apply bitmap pointed by sourceDc transparently over 
+   bitmap pointed by hDC */
+void nhapply_image_transparent( 
+       HDC hDC, int x, int y, int width, int height,
+       HDC sourceDC, int s_x, int s_y, int s_width, int s_height,
+       COLORREF cTransparent
+)
+{
+       TransparentImage(
+               hDC, x, y, width, height, 
+               sourceDC, s_x, s_y, s_width, s_height,
+               cTransparent 
+       );
+}
+
diff --git a/sys/wince/mhmap.h b/sys/wince/mhmap.h
new file mode 100644 (file)
index 0000000..401561d
--- /dev/null
@@ -0,0 +1,21 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINMapWindow_h
+#define MSWINMapWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+
+HWND mswin_init_map_window (void);
+void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw);
+int mswin_map_mode(HWND hWnd, int mode);
+
+#define ROGUE_LEVEL_MAP_MODE           MAP_MODE_ASCII12x16     
+
+#define DEF_CLIPAROUND_MARGIN  5
+#define DEF_CLIPAROUND_AMOUNT  1
+
+#endif /* MSWINMapWindow_h */
diff --git a/sys/wince/mhmenu.c b/sys/wince/mhmenu.c
new file mode 100644 (file)
index 0000000..0174cb9
--- /dev/null
@@ -0,0 +1,1568 @@
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include <assert.h>
+#include "mhmenu.h"
+#include "mhmain.h"
+#include "mhmsg.h"
+#include "mhcmd.h"
+#include "mhinput.h"
+#include "mhfont.h"
+#include "mhcolor.h"
+#include "mhtxtbuf.h"
+
+#define MENU_MARGIN                    0
+#define NHMENU_STR_SIZE     BUFSZ
+#define MIN_TABSTOP_SIZE       0
+#define NUMTABS                                15
+#define TAB_SEPARATION         10 /* pixels between each tab stop */
+
+typedef struct mswin_menu_item {
+       int                             glyph;
+       ANY_P                   identifier;
+       CHAR_P                  accelerator;
+       CHAR_P                  group_accel;
+       int                             attr;
+       char                    str[NHMENU_STR_SIZE];
+       BOOLEAN_P               presel;
+       int                             count;
+       BOOL                    has_focus;
+       BOOL                    has_tab;
+} NHMenuItem, *PNHMenuItem;
+
+typedef struct mswin_nethack_menu_window {
+       int type;               /* MENU_TYPE_TEXT or MENU_TYPE_MENU */
+       int how;                /* for menus: PICK_NONE, PICK_ONE, PICK_ANY */
+
+       union {
+               struct menu_list {
+                       int                              size;                  /* number of items in items[] */
+                       int                              allocated;             /* number of allocated slots in items[] */
+                       PNHMenuItem              items;                 /* menu items */
+                       char                     gacc[QBUFSZ];  /* group accelerators */
+                       BOOL                     counting;              /* counting flag */
+                       char                     prompt[QBUFSZ]; /* menu prompt */
+                       int                              tab_stop_size[NUMTABS];/* tabstops to align option values */
+               } menu;
+
+               struct menu_text {
+                       PNHTextBuffer   text;
+               } text;
+       };
+       int result;
+       int done;
+
+       HBITMAP bmpChecked;
+       HBITMAP bmpCheckedCount;
+       HBITMAP bmpNotChecked;
+} NHMenuWindow, *PNHMenuWindow;
+
+extern short glyph2tile[];
+
+static WNDPROC wndProcListViewOrig = NULL;
+static WNDPROC editControlWndProc = NULL;
+
+#define NHMENU_IS_SELECTABLE(item) ((item).identifier.a_obj!=NULL)
+#define NHMENU_IS_SELECTED(item) ((item).count!=0)
+
+LRESULT CALLBACK       MenuWndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK       NHMenuListWndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK       NHMenuTextWndProc(HWND, UINT, WPARAM, LPARAM);
+static void CheckInputDialog(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static LRESULT onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static LRESULT onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void LayoutMenu(HWND hwnd);
+static void SetMenuType(HWND hwnd, int type);
+static void SetMenuListType(HWND hwnd, int now);
+static HWND GetMenuControl(HWND hwnd);
+static void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count);
+static void reset_menu_count(HWND hwndList, PNHMenuWindow data);
+static LRESULT onListChar(HWND hWnd, HWND hwndList, WORD ch);
+static char* parse_menu_str(char* dest, const char* src, size_t size);
+
+HWND mswin_init_menu_window (int type) {
+       HWND ret;
+
+       ret = CreateDialog(
+                       GetNHApp()->hApp,
+                       MAKEINTRESOURCE(IDD_MENU),
+                       GetNHApp()->hMainWnd,
+                       MenuWndProc
+       );
+       if( !ret ) {
+               panic("Cannot create menu window");
+       }
+       
+       SetMenuType(ret, type);
+       return ret;
+}
+
+
+int mswin_menu_window_select_menu (HWND hWnd, int how, MENU_ITEM_P ** _selected)
+{
+       PNHMenuWindow data;
+       int ret_val;
+    MENU_ITEM_P *selected = NULL;
+       int i;
+       char* ap;
+       char accell_str[256];
+
+       assert( _selected!=NULL );
+       *_selected = NULL;
+       ret_val = -1;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       /* set menu type */
+       SetMenuListType(hWnd, how);
+
+       /* Ok, now give items a unique accelerators */
+       ZeroMemory(accell_str, sizeof(accell_str));
+       ap = accell_str;
+
+#if defined(WIN_CE_SMARTPHONE)
+       if( data->menu.size>10 ) {
+               *ap++ = MENU_FIRST_PAGE;
+               *ap++ = MENU_LAST_PAGE;
+               *ap++ = MENU_NEXT_PAGE;
+               *ap++ = MENU_PREVIOUS_PAGE;
+               if( data->how == PICK_ANY ) {
+                       *ap++ = MENU_SELECT_ALL;
+                       *ap++ = MENU_UNSELECT_ALL;
+                       *ap++ = MENU_INVERT_ALL;
+                       *ap++ = MENU_SELECT_PAGE;
+                       *ap++ = MENU_UNSELECT_PAGE;
+                       *ap++ = MENU_INVERT_PAGE;
+               }
+               *ap++ = MENU_SEARCH;
+       }
+#endif
+
+       if( data->type == MENU_TYPE_MENU ) {
+               char next_char = 'a';
+
+               for( i=0; i<data->menu.size;  i++) {
+                       if( data->menu.items[i].accelerator!=0 ) {
+                               *ap++ = data->menu.items[i].accelerator;
+                               next_char = (char)(data->menu.items[i].accelerator+1);
+                       } else if( NHMENU_IS_SELECTABLE(data->menu.items[i]) ) {
+                               if ( (next_char>='a' && next_char<='z') ||
+                                        (next_char>='A' && next_char<='Z') )  {
+                                        data->menu.items[i].accelerator = next_char;
+                                        *ap++ = data->menu.items[i].accelerator;
+                               } else {
+                                       if( next_char > 'z' ) next_char = 'A';
+                                       else if ( next_char > 'Z' ) break;
+
+                                       data->menu.items[i].accelerator = next_char;
+                                       *ap++ = data->menu.items[i].accelerator;
+                               }
+
+                               next_char ++;
+                       }
+               }
+
+               /* collect group accelerators */
+               data->menu.gacc[0] = '\0';
+               ap = data->menu.gacc;
+               if( data->how != PICK_NONE ) {
+                       for( i=0; i<data->menu.size;  i++) {
+                               if( data->menu.items[i].group_accel && 
+                                       !strchr(data->menu.gacc, data->menu.items[i].group_accel) ) {
+                                       *ap++ = data->menu.items[i].group_accel;
+                                       *ap = '\x0';
+                               }
+                       }
+               }
+
+               reset_menu_count(NULL, data);
+       }
+
+#if defined(WIN_CE_SMARTPHONE)
+       if( data->type==MENU_TYPE_MENU ) NHSPhoneSetKeypadFromString( accell_str );
+#endif
+
+       mswin_popup_display(hWnd, &data->done);
+
+       /* get the result */
+       if( data->result != -1 ) {
+               if(how==PICK_NONE) {
+                       if(data->result>=0) ret_val=0;
+                       else                            ret_val=-1;
+               } else if(how==PICK_ONE || how==PICK_ANY) {
+                       /* count selected items */
+                       ret_val = 0;
+                       for(i=0; i<data->menu.size; i++ ) {
+                               if( NHMENU_IS_SELECTABLE(data->menu.items[i]) &&
+                                       NHMENU_IS_SELECTED(data->menu.items[i]) ) {
+                                       ret_val++;
+                               }
+                       }
+                       if( ret_val > 0 ) {
+                               int sel_ind;
+
+                               selected = (MENU_ITEM_P*)malloc(ret_val*sizeof(MENU_ITEM_P));
+                               if( !selected ) panic("out of memory");
+
+                               sel_ind = 0;
+                               for(i=0; i<data->menu.size; i++ ) {
+                                       if( NHMENU_IS_SELECTABLE(data->menu.items[i]) &&
+                                               NHMENU_IS_SELECTED(data->menu.items[i]) ) {
+                                               selected[sel_ind].item = data->menu.items[i].identifier;
+                                               selected[sel_ind].count = data->menu.items[i].count;
+                                               sel_ind++;
+                                       }
+                               }
+                               ret_val = sel_ind;
+                               *_selected = selected;
+                       }
+               }
+       }
+
+       mswin_popup_destroy(hWnd);
+
+#if defined(WIN_CE_SMARTPHONE)
+       if( data->type==MENU_TYPE_MENU ) NHSPhoneSetKeypadDefault();
+#endif
+
+       return ret_val;
+}
+   
+LRESULT CALLBACK MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       PNHMenuWindow data;
+       
+       CheckInputDialog(hWnd, message, wParam, lParam);        
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch (message) 
+       {
+       case WM_INITDIALOG: {
+               HWND text_control;
+               HDC hDC;
+
+               text_control = GetDlgItem(hWnd, IDC_MENU_TEXT);
+
+               data = (PNHMenuWindow)malloc(sizeof(NHMenuWindow));
+               ZeroMemory(data, sizeof(NHMenuWindow));
+               data->type = MENU_TYPE_TEXT;
+               data->how = PICK_NONE;
+               data->result = 0;
+               data->done = 0;
+               data->bmpChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL));
+               data->bmpCheckedCount = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT));
+               data->bmpNotChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_UNSEL));
+               SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
+
+               /* subclass edit control */
+               editControlWndProc = (WNDPROC)GetWindowLong(text_control, GWL_WNDPROC);
+               SetWindowLong(text_control, GWL_WNDPROC, (LONG)NHMenuTextWndProc);
+
+               /* set text window font */
+               hDC = GetDC(text_control);
+               SendMessage(
+                       text_control, 
+                       WM_SETFONT, 
+                       (WPARAM)mswin_get_font(NHW_TEXT, ATR_NONE, hDC, FALSE),
+                       (LPARAM)0
+               );
+               ReleaseDC(text_control, hDC);
+
+#if defined(WIN_CE_SMARTPHONE)
+               /* special initialization for SmartPhone dialogs */ 
+               NHSPhoneDialogSetup(hWnd, FALSE, GetNHApp()->bFullScreen);
+#endif
+       } break;
+
+       case WM_MSNH_COMMAND:
+               onMSNHCommand(hWnd, wParam, lParam);
+       break;
+
+       case WM_SIZE:
+               LayoutMenu(hWnd);
+       return FALSE;
+
+       case WM_COMMAND: 
+       {
+               switch (LOWORD(wParam)) 
+        { 
+               case IDCANCEL:
+                       if( data->type == MENU_TYPE_MENU && 
+                           (data->how==PICK_ONE || data->how==PICK_ANY) &&
+                           data->menu.counting) {
+                               HWND list;
+                               int i;
+
+                               /* reset counter if counting is in progress */
+                               list = GetMenuControl(hWnd);
+                               i = ListView_GetNextItem(list, -1,      LVNI_FOCUSED);
+                               if( i>=0 ) {
+                                       SelectMenuItem(list, data, i,  0);
+                               }
+                               return FALSE;
+                       } else {
+                               data->result = -1;
+                               data->done = 1;
+                       }
+               return FALSE;
+
+               case IDOK:
+                       data->done = 1;
+                       data->result = 0;
+               return FALSE;
+               }
+       } break;
+
+       case WM_NOTIFY:
+       {
+               LPNMHDR lpnmhdr = (LPNMHDR)lParam;
+               switch (LOWORD(wParam)) {
+               case IDC_MENU_LIST:
+               {
+                       if( !data || data->type!=MENU_TYPE_MENU ) break;
+
+                       switch(lpnmhdr->code) {
+                       case LVN_ITEMACTIVATE: 
+                       {
+                               LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam;
+                               if(data->how==PICK_ONE) {
+                                       if( lpnmlv->iItem>=0 &&
+                                               lpnmlv->iItem<data->menu.size &&
+                                               NHMENU_IS_SELECTABLE(data->menu.items[lpnmlv->iItem]) ) {
+                                               SelectMenuItem(
+                                                       lpnmlv->hdr.hwndFrom, 
+                                                       data, 
+                                                       lpnmlv->iItem, 
+                                                       -1
+                                               );
+                                               data->done = 1;
+                                               data->result = 0;
+                                               return TRUE;
+                                       }
+                               } else if( data->how==PICK_ANY ) {
+                                       if( lpnmlv->iItem>=0 &&
+                                               lpnmlv->iItem<data->menu.size &&
+                                               NHMENU_IS_SELECTABLE(data->menu.items[lpnmlv->iItem]) ) {
+                                               SelectMenuItem(
+                                                       lpnmlv->hdr.hwndFrom, 
+                                                       data, 
+                                                       lpnmlv->iItem, 
+                                                       NHMENU_IS_SELECTED(data->menu.items[lpnmlv->iItem])? 0 : -1
+                                               );
+                                       }
+                               }
+                       } break;
+
+                       case NM_CLICK: {
+                               LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) lParam;
+                               if( lpnmlv->iItem==-1 ) return 0;
+                               if( data->how==PICK_ANY ) {
+                                       SelectMenuItem(
+                                               lpnmlv->hdr.hwndFrom, 
+                                               data, 
+                                               lpnmlv->iItem, 
+                                               NHMENU_IS_SELECTED(data->menu.items[lpnmlv->iItem])? 0 : -1
+                                       );
+                               }
+                       } break;
+
+                       case LVN_ITEMCHANGED: 
+                       {
+                               LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam;
+                               if( lpnmlv->iItem==-1 ) return 0;
+                               if( !(lpnmlv->uChanged & LVIF_STATE) ) return 0;
+
+                               /* update item that has the focus */
+                               data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED);
+                               ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem);
+
+                               /* update count for single-selection menu (follow the listview selection) */
+                               if( data->how==PICK_ONE ) {
+                                       if( lpnmlv->uNewState & LVIS_SELECTED ) {
+                                               SelectMenuItem(
+                                                       lpnmlv->hdr.hwndFrom, 
+                                                       data, 
+                                                       lpnmlv->iItem, 
+                                                       -1
+                                               );
+                                       }
+                               }
+
+                               /* check item focus */
+                               data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED);
+                               ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem);
+                       } break;
+
+                       case NM_KILLFOCUS:
+                               reset_menu_count(lpnmhdr->hwndFrom, data);
+                       break;
+
+                       }
+               } break;
+               }
+       } break;
+
+       case WM_SETFOCUS:
+               if( hWnd!=GetNHApp()->hPopupWnd ) {
+                       SetFocus(GetNHApp()->hPopupWnd );
+                       return 0;
+               }
+       break;
+       
+    case WM_MEASUREITEM: 
+               if( wParam==IDC_MENU_LIST )
+                       return onMeasureItem(hWnd, wParam, lParam);
+               else
+                       return FALSE;
+
+    case WM_DRAWITEM:
+               if( wParam==IDC_MENU_LIST )
+                       return onDrawItem(hWnd, wParam, lParam);
+               else
+                       return FALSE;
+
+       case WM_CTLCOLORBTN:
+       case WM_CTLCOLOREDIT:
+       case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */
+               HDC hdcEdit = (HDC) wParam; 
+               HWND hwndEdit = (HWND) lParam;
+               if( hwndEdit == GetDlgItem(hWnd, IDC_MENU_TEXT) ) {
+                       SetBkColor(hdcEdit, mswin_get_color(NHW_TEXT, MSWIN_COLOR_BG));
+                       SetTextColor(hdcEdit, mswin_get_color(NHW_TEXT, MSWIN_COLOR_FG)); 
+                       return (BOOL)mswin_get_brush(NHW_TEXT, MSWIN_COLOR_BG);
+               }
+       } return FALSE;
+
+       case WM_DESTROY:
+               if( data ) {
+                       DeleteObject(data->bmpChecked);
+                       DeleteObject(data->bmpCheckedCount);
+                       DeleteObject(data->bmpNotChecked);
+                       if( data->type == MENU_TYPE_TEXT ) {
+                               if( data->text.text ) {
+                                       mswin_free_text_buffer(data->text.text);
+                                       data->text.text = NULL;
+                               }
+                       }
+                       free(data);
+                       SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+               }
+               return TRUE;
+       }
+       return FALSE;
+}
+
+void CheckInputDialog(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+#if defined(WIN_CE_POCKETPC)
+       PNHMenuWindow data;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       if( !( data && 
+                  data->type==MENU_TYPE_MENU &&
+                  (data->how==PICK_ONE || data->how==PICK_ANY) ) ) return;
+       
+       switch(message) {
+       case WM_SETFOCUS:
+               if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_UP);
+       return;
+
+       case WM_DESTROY:
+       case WM_KILLFOCUS:
+               if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_DOWN);
+       return;
+
+       case WM_NOTIFY:
+       {
+               LPNMHDR lpnmhdr = (LPNMHDR)lParam;
+               switch(lpnmhdr->code) {
+               case NM_SETFOCUS:
+                       if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_UP);
+               break;
+               case NM_KILLFOCUS:
+                       if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_DOWN);
+               break;
+               }
+       } return;
+
+       case WM_COMMAND:
+               switch(HIWORD(wParam)) {
+               case BN_SETFOCUS:
+                       if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_UP);
+               break;
+               case BN_KILLFOCUS:
+                       if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_DOWN);
+               break;
+               }
+       return;
+
+       } /* end switch */
+#endif
+}
+
+void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMenuWindow data;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch( wParam ) {
+       case MSNH_MSG_PUTSTR: 
+       {
+               PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
+               HWND   text_view;
+
+               if( data->type!=MENU_TYPE_TEXT )
+                       SetMenuType(hWnd, MENU_TYPE_TEXT);
+
+               if( !data->text.text ) {
+                       data->text.text = mswin_init_text_buffer(
+                                               program_state.gameover? FALSE : GetNHApp()->bWrapText
+                                       );
+                       if( !data->text.text ) break;
+               }
+               
+               mswin_add_text(data->text.text, msg_data->attr, msg_data->text); 
+               
+               text_view = GetDlgItem(hWnd, IDC_MENU_TEXT);
+               if( !text_view ) panic("cannot get text view window");
+               mswin_render_text(data->text.text, text_view);
+       } break;
+
+       case MSNH_MSG_STARTMENU:
+       {
+               int i;
+
+               if( data->type!=MENU_TYPE_MENU )
+                       SetMenuType(hWnd, MENU_TYPE_MENU);
+
+               if( data->menu.items ) free(data->menu.items);
+               data->how = PICK_NONE;
+               data->menu.items = NULL;
+               data->menu.size = 0;
+               data->menu.allocated = 0;
+               data->done = 0;
+               data->result = 0;
+               for (i = 0; i < NUMTABS; ++i)
+                       data->menu.tab_stop_size[i] = MIN_TABSTOP_SIZE;
+       } break;
+
+       case MSNH_MSG_ADDMENU:
+       {
+               PMSNHMsgAddMenu msg_data = (PMSNHMsgAddMenu)lParam;
+               char *p, *p1;
+               int new_item;
+               HDC hDC;
+               int column;
+               HFONT saveFont;
+               
+               if( data->type!=MENU_TYPE_MENU ) break;
+               if( strlen(msg_data->str)==0 ) break;
+
+               if( data->menu.size==data->menu.allocated ) {
+                       data->menu.allocated += 10;
+                       data->menu.items = (PNHMenuItem)realloc(data->menu.items, data->menu.allocated*sizeof(NHMenuItem));
+               }
+
+               new_item = data->menu.size;
+               ZeroMemory( &data->menu.items[new_item], sizeof(data->menu.items[new_item]));
+               data->menu.items[new_item].glyph = msg_data->glyph;
+               data->menu.items[new_item].identifier = *msg_data->identifier;
+               data->menu.items[new_item].accelerator = msg_data->accelerator;
+               data->menu.items[new_item].group_accel = msg_data->group_accel;
+               data->menu.items[new_item].attr = msg_data->attr;
+               parse_menu_str(data->menu.items[new_item].str, msg_data->str, NHMENU_STR_SIZE);
+               data->menu.items[new_item].presel = msg_data->presel;
+
+               /* calculate tabstop size */
+               p = strchr(data->menu.items[new_item].str, '\t');
+               if( p ) {
+                       data->menu.items[new_item].has_tab = TRUE;
+                       hDC = GetDC(hWnd);
+                       saveFont = SelectObject(hDC, mswin_get_font(NHW_MENU, msg_data->attr, hDC, FALSE));
+                       p1 = data->menu.items[new_item].str;
+                       column = 0;
+                       for (;;) {
+                               TCHAR wbuf[BUFSZ];
+                               RECT drawRect;
+                               SetRect ( &drawRect, 0, 0, 1, 1 );
+                               if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */
+                               DrawText(hDC,
+                                       NH_A2W(p1, wbuf, BUFSZ),
+                                       strlen(p1),
+                                       &drawRect,
+                                       DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_EXPANDTABS | DT_SINGLELINE
+                               );
+                               data->menu.tab_stop_size[column] =
+                                       max( data->menu.tab_stop_size[column], drawRect.right - drawRect.left );
+                               if (p != NULL) *p = '\t';
+                               else /* last string so, */ break;
+
+                               ++column;
+                               p1 = p + 1;
+                               p = strchr(p1, '\t');
+                       }
+                       SelectObject(hDC, saveFont);
+                       ReleaseDC(hWnd, hDC);
+               } else {
+                       data->menu.items[new_item].has_tab = FALSE;
+               }
+
+               /* increment size */
+               data->menu.size++;
+       } break;
+
+       case MSNH_MSG_ENDMENU:
+       {
+               PMSNHMsgEndMenu msg_data = (PMSNHMsgEndMenu)lParam;
+               if( msg_data->text ) {
+                       strncpy( data->menu.prompt, msg_data->text, sizeof(data->menu.prompt)-1 );
+               } else {
+                       ZeroMemory(data->menu.prompt, sizeof(data->menu.prompt));
+               }
+       } break;
+
+       } /* end switch */
+}
+
+void LayoutMenu(HWND hWnd) 
+{
+       PNHMenuWindow data;
+       HWND  menu_ok;
+       HWND  menu_cancel;
+       RECT  clrt, rt;
+       POINT pt_elem, pt_ok, pt_cancel;
+       SIZE  sz_elem, sz_ok, sz_cancel;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       menu_ok = GetDlgItem(hWnd, IDOK);
+       menu_cancel = GetDlgItem(hWnd, IDCANCEL);
+
+       /* get window coordinates */
+       GetClientRect(hWnd, &clrt );
+       
+       /* set window placements */
+       if( IsWindow(menu_ok) ) {
+               GetWindowRect(menu_ok, &rt);
+               sz_ok.cx = (clrt.right - clrt.left)/2 - 2*MENU_MARGIN;
+               sz_ok.cy = rt.bottom-rt.top;
+               pt_ok.x = clrt.left + MENU_MARGIN;
+               pt_ok.y = clrt.bottom - MENU_MARGIN - sz_ok.cy;
+               MoveWindow(menu_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE );
+       } else {
+               pt_ok.x = 0;
+               pt_ok.y = clrt.bottom;
+               sz_ok.cx = sz_ok.cy = 0;
+       }
+       
+       if( IsWindow(menu_cancel) ) {
+               GetWindowRect(menu_cancel, &rt);
+               sz_cancel.cx = (clrt.right - clrt.left)/2 - 2*MENU_MARGIN;
+               sz_cancel.cy = rt.bottom-rt.top;
+               pt_cancel.x = (clrt.left + clrt.right)/2 + MENU_MARGIN;
+               pt_cancel.y = clrt.bottom - MENU_MARGIN - sz_cancel.cy;
+               MoveWindow(menu_cancel, pt_cancel.x, pt_cancel.y, sz_cancel.cx, sz_cancel.cy, TRUE );
+       } else {
+               pt_cancel.x = 0;
+               pt_cancel.y = clrt.bottom;
+               sz_cancel.cx = sz_cancel.cy = 0;
+       }
+
+       pt_elem.x = clrt.left + MENU_MARGIN;
+       pt_elem.y = clrt.top + MENU_MARGIN;
+       sz_elem.cx = (clrt.right - clrt.left) - 2*MENU_MARGIN;
+       sz_elem.cy = min(pt_cancel.y, pt_ok.y) - MENU_MARGIN - pt_elem.y;
+       MoveWindow(GetMenuControl(hWnd), pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE );
+
+       /* reformat text for the text menu */
+       if(     data && 
+               data->type==MENU_TYPE_TEXT &&
+               data->text.text )
+               mswin_render_text(data->text.text, GetMenuControl(hWnd));
+}
+
+void SetMenuType(HWND hWnd, int type)
+{
+       PNHMenuWindow data;
+       HWND list, text;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       data->type = type;
+       
+       text = GetDlgItem(hWnd, IDC_MENU_TEXT);
+       list = GetDlgItem(hWnd, IDC_MENU_LIST);
+       if(data->type==MENU_TYPE_TEXT) {
+               ShowWindow(list, SW_HIDE);
+               EnableWindow(list, FALSE);
+               EnableWindow(text, TRUE);
+               ShowWindow(text, SW_SHOW);
+               SetFocus(text);
+       } else {
+               ShowWindow(text, SW_HIDE);
+               EnableWindow(text, FALSE);
+               EnableWindow(list, TRUE);
+               ShowWindow(list, SW_SHOW);
+               SetFocus(list);
+       }
+       LayoutMenu(hWnd);
+}
+
+void SetMenuListType(HWND hWnd, int how)
+{
+       PNHMenuWindow data;
+       RECT rt;
+       DWORD dwStyles;
+       char buf[BUFSZ];
+       TCHAR wbuf[BUFSZ];
+       int nItem;
+       int i;
+       HWND control;
+       LVCOLUMN lvcol;
+       LRESULT fnt;
+       SIZE wnd_size;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if( data->type != MENU_TYPE_MENU ) return;
+
+       data->how = how;
+
+       switch(how) {
+       case PICK_NONE: 
+               dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD 
+                       | WS_VSCROLL | WS_HSCROLL | LVS_REPORT
+                       | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; 
+               break;
+       case PICK_ONE: 
+               dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD 
+                       | WS_VSCROLL | WS_HSCROLL | LVS_REPORT
+                       | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; 
+               break;
+       case PICK_ANY: 
+               dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD 
+                       | WS_VSCROLL | WS_HSCROLL | LVS_REPORT
+                       | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; 
+               break;
+       default: panic("how should be one of PICK_NONE, PICK_ONE or PICK_ANY");
+       };
+       if( strlen(data->menu.prompt)==0 ) {
+               dwStyles |= LVS_NOCOLUMNHEADER ;
+       }
+
+       GetWindowRect(GetDlgItem(hWnd, IDC_MENU_LIST), &rt);
+       DestroyWindow(GetDlgItem(hWnd, IDC_MENU_LIST));
+       control = CreateWindow(WC_LISTVIEW, NULL, 
+               dwStyles,
+               rt.left,
+               rt.top,
+               rt.right - rt.left,
+               rt.bottom - rt.top,
+               hWnd,
+               (HMENU)IDC_MENU_LIST,
+               GetNHApp()->hApp,
+               NULL );
+       if( !control ) panic( "cannot create menu control" );
+       
+       /* install the hook for the control window procedure */
+       wndProcListViewOrig = (WNDPROC)GetWindowLong(control, GWL_WNDPROC);
+       SetWindowLong(control, GWL_WNDPROC, (LONG)NHMenuListWndProc);
+
+       /* set control font */
+       fnt = SendMessage(hWnd, WM_GETFONT, (WPARAM)0, (LPARAM)0);
+       SendMessage(control, WM_SETFONT, (WPARAM)fnt, (LPARAM)0);
+
+       /* set control colors */
+       ListView_SetBkColor(control, mswin_get_color(NHW_MENU, MSWIN_COLOR_BG));
+       ListView_SetTextBkColor(control, mswin_get_color(NHW_MENU, MSWIN_COLOR_BG));
+       ListView_SetTextColor(control, mswin_get_color(NHW_MENU, MSWIN_COLOR_FG));
+
+       /* add column to the list view */
+       mswin_menu_window_size(hWnd, &wnd_size);
+
+       ZeroMemory(&lvcol, sizeof(lvcol));
+       lvcol.mask = LVCF_WIDTH | LVCF_TEXT;
+       lvcol.cx = max( wnd_size.cx, GetSystemMetrics(SM_CXSCREEN));
+       lvcol.pszText = NH_A2W(data->menu.prompt, wbuf, BUFSZ);
+       ListView_InsertColumn(control, 0, &lvcol);
+
+       /* add items to the list view */
+       for(i=0; i<data->menu.size; i++ ) {
+               LVITEM lvitem;
+               ZeroMemory( &lvitem, sizeof(lvitem) );
+               sprintf(buf, "%c - %s", max(data->menu.items[i].accelerator, ' '), data->menu.items[i].str );
+
+               lvitem.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
+               lvitem.iItem = i;
+               lvitem.iSubItem = 0;
+               lvitem.state = data->menu.items[i].presel? LVIS_SELECTED : 0;
+               lvitem.pszText = NH_A2W(buf, wbuf, BUFSZ);
+               lvitem.lParam = (LPARAM)&data->menu.items[i];
+               nItem = SendMessage(control, LB_ADDSTRING, (WPARAM)0, (LPARAM) buf); 
+               if( ListView_InsertItem(control, &lvitem)==-1 ) {
+                       panic("cannot insert menu item");
+               }
+       }
+       SetFocus(control);
+}
+
+
+HWND GetMenuControl(HWND hWnd)
+{
+       PNHMenuWindow data;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       if(data->type==MENU_TYPE_TEXT) {
+               return GetDlgItem(hWnd, IDC_MENU_TEXT);
+       } else {
+               return GetDlgItem(hWnd, IDC_MENU_LIST);
+       }
+}
+
+
+LRESULT onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+    LPMEASUREITEMSTRUCT lpmis; 
+    TEXTMETRIC tm;
+       HGDIOBJ saveFont;
+       HDC hdc;
+       PNHMenuWindow data;
+       RECT list_rect;
+
+    lpmis = (LPMEASUREITEMSTRUCT) lParam; 
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       GetClientRect(GetMenuControl(hWnd), &list_rect);
+
+       hdc = GetDC(GetMenuControl(hWnd));
+       saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, FALSE));
+       GetTextMetrics(hdc, &tm);
+
+    /* Set the height of the list box items. */
+    lpmis->itemHeight = max(tm.tmHeight, TILE_Y)+2;
+       lpmis->itemWidth = list_rect.right - list_rect.left;
+
+       SelectObject(hdc, saveFont);
+       ReleaseDC(GetMenuControl(hWnd), hdc);
+       return TRUE;
+}
+
+LRESULT onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+    LPDRAWITEMSTRUCT lpdis; 
+       PNHMenuItem item;
+       PNHMenuWindow data;
+    TEXTMETRIC tm;
+       HGDIOBJ saveFont;
+       HDC tileDC;
+       short ntile;
+       int t_x, t_y;
+       int x, y;
+       TCHAR wbuf[BUFSZ];
+       RECT drawRect;
+       COLORREF OldBg, OldFg, NewBg;
+       char *p, *p1;
+       int column;
+
+       lpdis = (LPDRAWITEMSTRUCT) lParam; 
+
+    /* If there are no list box items, skip this message. */
+    if (lpdis->itemID == -1) return FALSE;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+    item = &data->menu.items[lpdis->itemID];
+
+       tileDC = CreateCompatibleDC(lpdis->hDC);
+       saveFont = SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, item->attr, lpdis->hDC, FALSE));
+       NewBg = mswin_get_color(NHW_MENU, MSWIN_COLOR_BG);
+       OldBg = SetBkColor(lpdis->hDC, NewBg);
+       OldFg = SetTextColor(lpdis->hDC, mswin_get_color(NHW_MENU, MSWIN_COLOR_FG)); 
+
+    GetTextMetrics(lpdis->hDC, &tm);
+
+       x = lpdis->rcItem.left + 1;
+
+       /* print check mark if it is a "selectable" menu */
+       if( data->how!=PICK_NONE ) {
+               if( NHMENU_IS_SELECTABLE(*item) ) {
+                       HGDIOBJ saveBrush;
+                       HBRUSH  hbrCheckMark;
+                       char buf[2];
+
+                       switch(item->count) {
+                       case -1: hbrCheckMark = CreatePatternBrush(data->bmpChecked); break;
+                       case 0: hbrCheckMark = CreatePatternBrush(data->bmpNotChecked); break;
+                       default: hbrCheckMark = CreatePatternBrush(data->bmpCheckedCount); break;
+                       }
+
+                       y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2; 
+                       SetBrushOrgEx(lpdis->hDC, x, y, NULL);
+                       saveBrush = SelectObject(lpdis->hDC, hbrCheckMark);
+                       PatBlt(lpdis->hDC, x, y, TILE_X, TILE_Y, PATCOPY);
+                       SelectObject(lpdis->hDC, saveBrush);
+                       DeleteObject(hbrCheckMark);
+
+                       x += TILE_X + 5;
+
+                       if(item->accelerator!=0) {
+                               buf[0] = item->accelerator;
+                               buf[1] = '\x0';
+
+                               SetRect( &drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom );
+                               DrawText(lpdis->hDC, NH_A2W(buf, wbuf, 2), 1, &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
+                       }
+                       x += tm.tmAveCharWidth + tm.tmOverhang + 5;
+               } else {
+                       x += TILE_X + tm.tmAveCharWidth + tm.tmOverhang + 10;
+               }
+       }
+
+       /* print glyph if present */
+       if( item->glyph != NO_GLYPH ) {
+               HGDIOBJ saveBmp;
+
+               saveBmp = SelectObject(tileDC, GetNHApp()->bmpTiles);                           
+               ntile = glyph2tile[ item->glyph ];
+               t_x = (ntile % TILES_PER_LINE)*TILE_X;
+               t_y = (ntile / TILES_PER_LINE)*TILE_Y;
+
+               y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2; 
+
+               nhapply_image_transparent(
+                       lpdis->hDC, x, y, TILE_X, TILE_Y, 
+                       tileDC, t_x, t_y, TILE_X, TILE_Y, TILE_BK_COLOR );
+               SelectObject(tileDC, saveBmp);
+       }
+
+       x += TILE_X + 5;
+
+       /* draw item text */
+       if( item->has_tab ) {
+               p1 = item->str;
+               p = strchr(item->str, '\t');
+               column = 0;
+               SetRect( &drawRect, x, lpdis->rcItem.top, min(x + data->menu.tab_stop_size[0], lpdis->rcItem.right),
+                       lpdis->rcItem.bottom );
+               for (;;) {
+                       TCHAR wbuf[BUFSZ];
+                       if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */
+                       DrawText(lpdis->hDC,
+                               NH_A2W(p1, wbuf, BUFSZ),
+                               strlen(p1),
+                               &drawRect,
+                               DT_LEFT | DT_VCENTER | DT_SINGLELINE
+                       );
+                       if (p != NULL) *p = '\t';
+                       else /* last string so, */ break;
+
+                       p1 = p + 1;
+                       p = strchr(p1, '\t');
+                       drawRect.left = drawRect.right + TAB_SEPARATION;
+                       ++column;
+                       drawRect.right = min (drawRect.left + data->menu.tab_stop_size[column], lpdis->rcItem.right);
+               }
+       } else {
+               TCHAR wbuf[BUFSZ];
+               SetRect( &drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom);
+               DrawText(lpdis->hDC,
+                       NH_A2W(item->str, wbuf, BUFSZ),
+                       strlen(item->str),
+                       &drawRect,
+                       DT_LEFT | DT_VCENTER | DT_SINGLELINE
+               );
+       }
+
+       /* draw focused item */
+       if( item->has_focus ) {
+               RECT client_rt;
+               HBRUSH bkBrush;
+
+               GetClientRect(lpdis->hwndItem, &client_rt);
+               if( NHMENU_IS_SELECTABLE(*item) && 
+                       data->menu.items[lpdis->itemID].count>0 &&
+                       item->glyph != NO_GLYPH ) {
+                       if( data->menu.items[lpdis->itemID].count==-1 ) {
+                               _stprintf(wbuf, TEXT("Count: All") );
+                       } else {
+                               _stprintf(wbuf, TEXT("Count: %d"), data->menu.items[lpdis->itemID].count );
+                       }
+
+                       SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, ATR_BLINK, lpdis->hDC, FALSE));
+
+                       /* calculate text rectangle */
+                       SetRect( &drawRect, client_rt.left, lpdis->rcItem.top, client_rt.right, lpdis->rcItem.bottom );
+                       DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect, 
+                                        DT_CALCRECT | DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX );
+                       
+                       /* erase text rectangle */
+                       drawRect.left = max(client_rt.left+1, client_rt.right - (drawRect.right - drawRect.left) - 10);
+                       drawRect.right = client_rt.right-1;
+                       drawRect.top = lpdis->rcItem.top;
+                       drawRect.bottom = lpdis->rcItem.bottom;
+                       bkBrush = CreateSolidBrush( GetBkColor(lpdis->hDC) );
+                       FillRect(lpdis->hDC, &drawRect, bkBrush );
+                       DeleteObject( bkBrush );
+
+                       /* draw text */
+                       DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect, 
+                                        DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX );
+               }
+
+               /* draw focus rect */
+               SetRect( &drawRect, client_rt.left, lpdis->rcItem.top, client_rt.right, lpdis->rcItem.bottom );
+               DrawFocusRect(lpdis->hDC, &drawRect);
+       }
+
+       SetTextColor (lpdis->hDC, OldFg);
+       SetBkColor (lpdis->hDC, OldBg);
+       SelectObject(lpdis->hDC, saveFont);
+       DeleteDC(tileDC);
+       return TRUE;
+}
+
+BOOL onListChar(HWND hWnd, HWND hwndList, WORD ch)
+{
+       int i = 0;
+       PNHMenuWindow data;
+       int curIndex, topIndex, pageSize;
+       boolean is_accelerator = FALSE;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       switch( ch ) {
+       case MENU_FIRST_PAGE:
+               i = 0;
+               ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
+               ListView_EnsureVisible(hwndList, i, FALSE);
+       return -2;
+
+       case MENU_LAST_PAGE:
+               i = max(0, data->menu.size-1);
+               ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
+               ListView_EnsureVisible(hwndList, i, FALSE);
+       return -2;
+
+       case MENU_NEXT_PAGE:
+               topIndex = ListView_GetTopIndex( hwndList );
+               pageSize = ListView_GetCountPerPage( hwndList );
+        curIndex = ListView_GetNextItem(hwndList, -1,  LVNI_FOCUSED);
+        /* Focus down one page */
+               i = min(curIndex+pageSize, data->menu.size-1);
+               ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
+        /* Scrollpos down one page */
+        i = min(topIndex+(2*pageSize - 1), data->menu.size-1);
+               ListView_EnsureVisible(hwndList, i, FALSE);
+       return -2;
+
+       case MENU_PREVIOUS_PAGE:
+               topIndex = ListView_GetTopIndex( hwndList );
+               pageSize = ListView_GetCountPerPage( hwndList );
+        curIndex = ListView_GetNextItem(hwndList, -1,  LVNI_FOCUSED);
+        /* Focus up one page */
+               i = max(curIndex-pageSize, 0);
+               ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
+        /* Scrollpos up one page */
+               i = max(topIndex-pageSize, 0);
+               ListView_EnsureVisible(hwndList, i, FALSE);
+       break;
+
+       case MENU_SELECT_ALL:
+               if( data->how == PICK_ANY ) {
+                       reset_menu_count(hwndList, data);
+                       for(i=0; i<data->menu.size; i++ ) {
+                               SelectMenuItem(hwndList, data, i, -1);
+                       }
+                       return -2;
+               }
+       break;
+
+       case MENU_UNSELECT_ALL:
+               if( data->how == PICK_ANY ) {
+                       reset_menu_count(hwndList, data);
+                       for(i=0; i<data->menu.size; i++ ) {
+                               SelectMenuItem(hwndList, data, i, 0);
+                       }
+                       return -2;
+               }
+       break;
+
+       case MENU_INVERT_ALL:
+               if( data->how == PICK_ANY ) {
+                       reset_menu_count(hwndList, data);
+                       for(i=0; i<data->menu.size; i++ ) {
+                               SelectMenuItem(
+                                       hwndList, 
+                                       data, 
+                                       i, 
+                                       NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
+                               );
+                       }
+                       return -2;
+               }
+       break;
+
+       case MENU_SELECT_PAGE:
+               if( data->how == PICK_ANY ) {
+                       int from, to;
+                       reset_menu_count(hwndList, data);
+                       topIndex = ListView_GetTopIndex( hwndList );
+                       pageSize = ListView_GetCountPerPage( hwndList );
+                       from = max(0, topIndex);
+                       to = min(data->menu.size, from+pageSize);
+                       for(i=from; i<to; i++ ) {
+                               SelectMenuItem(hwndList, data, i, -1);
+                       }
+                       return -2;
+               }
+       break;
+
+       case MENU_UNSELECT_PAGE:
+               if( data->how == PICK_ANY ) {
+                       int from, to;
+                       reset_menu_count(hwndList, data);
+                       topIndex = ListView_GetTopIndex( hwndList );
+                       pageSize = ListView_GetCountPerPage( hwndList );
+                       from = max(0, topIndex);
+                       to = min(data->menu.size, from+pageSize);
+                       for(i=from; i<to; i++ ) {
+                               SelectMenuItem(hwndList, data, i, 0);
+                       }
+                       return -2;
+               }
+       break;
+
+       case MENU_INVERT_PAGE:
+               if( data->how == PICK_ANY ) {
+                       int from, to;
+                       reset_menu_count(hwndList, data);
+                       topIndex = ListView_GetTopIndex( hwndList );
+                       pageSize = ListView_GetCountPerPage( hwndList );
+                       from = max(0, topIndex);
+                       to = min(data->menu.size, from+pageSize);
+                       for(i=from; i<to; i++ ) {
+                               SelectMenuItem(
+                                       hwndList, 
+                                       data, 
+                                       i, 
+                                       NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
+                               );
+                       }
+                       return -2;
+               }
+       break;
+
+       case MENU_SEARCH:
+           if( data->how==PICK_ANY || data->how==PICK_ONE ) {
+                       char buf[BUFSZ];
+                       int  selected_item;
+                       
+                       reset_menu_count(hwndList, data);
+                       mswin_getlin("Search for:", buf);
+                       if (!*buf || *buf == '\033') return -2;
+                       selected_item = -1;
+                       for(i=0; i<data->menu.size; i++ ) {
+                               if( NHMENU_IS_SELECTABLE(data->menu.items[i])
+                                       && strstr(data->menu.items[i].str, buf) ) {
+                                       if (data->how == PICK_ANY) {
+                                               SelectMenuItem(
+                                                       hwndList, 
+                                                       data, 
+                                                       i, 
+                                                       NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
+                                               );
+                                               /* save the first item - we will move focus to it */
+                                               if( selected_item == -1 ) selected_item = i;
+                                       } else if( data->how == PICK_ONE ) {
+                                               SelectMenuItem(
+                                                       hwndList, 
+                                                       data, 
+                                                       i, 
+                                                       -1
+                                               );
+                                               selected_item = i;
+                                               break;
+                                       }
+                               }
+                       } 
+
+                       if( selected_item>0 ) {
+                               ListView_SetItemState(hwndList, selected_item, LVIS_FOCUSED, LVIS_FOCUSED);
+                               ListView_EnsureVisible(hwndList, selected_item, FALSE);
+                       }
+               } else {
+                       mswin_nhbell();
+           }
+       return -2;
+
+       case ' ':
+               /* ends menu for PICK_ONE/PICK_NONE
+                  select item for PICK_ANY */
+               if( data->how==PICK_ONE || data->how==PICK_NONE ) {
+                       data->done = 1;
+                       data->result = 0;
+                       return -2;
+               } else if( data->how==PICK_ANY ) {
+                       i = ListView_GetNextItem(hwndList, -1,  LVNI_FOCUSED);
+                       if( i>=0 ) {
+                               SelectMenuItem(
+                                       hwndList, 
+                                       data, 
+                                       i, 
+                                       NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
+                               );
+                       }
+                       return -2;
+               }
+       break;
+
+       default:
+               if( strchr(data->menu.gacc, ch) &&
+                       !(ch=='0' && data->menu.counting) ) {
+                       /* matched a group accelerator */
+                       if (data->how == PICK_ANY || data->how == PICK_ONE) {
+                               reset_menu_count(hwndList, data);
+                               for(i=0; i<data->menu.size; i++ ) {
+                                       if( NHMENU_IS_SELECTABLE(data->menu.items[i]) &&
+                                               data->menu.items[i].group_accel == ch ) {
+                                               if( data->how == PICK_ANY ) {
+                                                       SelectMenuItem(
+                                                               hwndList, 
+                                                               data, 
+                                                               i, 
+                                                               NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
+                                                       );
+                                               } else if( data->how == PICK_ONE ) {
+                                                       SelectMenuItem(
+                                                               hwndList, 
+                                                               data, 
+                                                               i, 
+                                                               -1
+                                                       );
+                                                       data->result = 0;
+                                                       data->done = 1;
+                                                       return -2;
+                                               }
+                                       }
+                               }
+                               return -2;
+                       } else {
+                               mswin_nhbell();
+                               return -2;
+                       }
+               }
+
+               if (isdigit(ch)) {
+                       int count;
+                       i = ListView_GetNextItem(hwndList, -1,  LVNI_FOCUSED);
+                       if( i>=0 ) {
+                               count = data->menu.items[i].count;
+                               if( count==-1 ) count=0;
+                               count *= 10L;
+                               count += (int)(ch - '0');
+                               if (count != 0) /* ignore leading zeros */ {
+                                       data->menu.counting = TRUE;
+                                       data->menu.items[i].count = min(100000, count);
+                                       ListView_RedrawItems( hwndList, i, i ); /* update count mark */
+                               }
+                       }
+                       return -2;
+               }
+
+               is_accelerator = FALSE;
+               for(i=0; i<data->menu.size; i++) {
+                       if( data->menu.items[i].accelerator == ch ) {
+                               is_accelerator = TRUE;
+                               break;
+                       }
+               }
+
+               if( (ch>='a' && ch<='z') ||
+                       (ch>='A' && ch<='Z') || is_accelerator) {
+                       if (data->how == PICK_ANY || data->how == PICK_ONE) {
+                               for(i=0; i<data->menu.size; i++ ) {
+                                       if( data->menu.items[i].accelerator == ch ) {
+                                               if( data->how == PICK_ANY ) {
+                                                       SelectMenuItem(
+                                                               hwndList, 
+                                                               data, 
+                                                               i, 
+                                                               NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
+                                                       );
+                                                       ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
+                                                       ListView_EnsureVisible(hwndList, i, FALSE);
+                                                       return -2;
+                                               } else if( data->how == PICK_ONE ) {
+                                                       SelectMenuItem(
+                                                               hwndList, 
+                                                               data, 
+                                                               i, 
+                                                               -1
+                                                       );
+                                                       data->result = 0;
+                                                       data->done = 1;
+                                                       return -2;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       break;
+       }
+
+       reset_menu_count(hwndList, data);
+       return -1;
+}
+
+void mswin_menu_window_size (HWND hWnd, LPSIZE sz)
+{
+    TEXTMETRIC tm;
+       HWND control;
+       HGDIOBJ saveFont;
+       HDC hdc;
+       PNHMenuWindow data;
+       int i;
+       RECT rt, wrt;
+       int extra_cx;
+
+       GetClientRect(hWnd, &rt);
+       sz->cx = rt.right - rt.left;
+       sz->cy = rt.bottom - rt.top;
+
+       GetWindowRect(hWnd, &wrt);
+       extra_cx = (wrt.right-wrt.left) - sz->cx;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if(data) {
+               control = GetMenuControl(hWnd);
+               hdc = GetDC(control);
+
+               if( data->type==MENU_TYPE_MENU ) {
+                       /* Calculate the width of the list box. */
+                       saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE));
+                       GetTextMetrics(hdc, &tm);
+                       for(i=0; i<data->menu.size; i++ ) {
+                               LONG menuitemwidth = 0;
+                               int column;
+                               char *p, *p1;
+
+                               p1 = data->menu.items[i].str;
+                               p = strchr(data->menu.items[i].str, '\t');
+                               column = 0;
+                               for (;;) {
+                                       TCHAR wbuf[BUFSZ];
+                                       RECT tabRect;
+                                       SetRect ( &tabRect, 0, 0, 1, 1 );
+                                       if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */
+                                       DrawText(hdc,
+                                               NH_A2W(p1, wbuf, BUFSZ),
+                                               strlen(p1),
+                                               &tabRect,
+                                               DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE
+                                       );
+                                       /* it probably isn't necessary to recompute the tab width now, but do so
+                                        * just in case, honoring the previously computed value
+                                        */
+                                       menuitemwidth += max(data->menu.tab_stop_size[column],
+                                           tabRect.right - tabRect.left);
+                                       if (p != NULL) *p = '\t';
+                                       else /* last string so, */ break;
+                                       /* add the separation only when not the last item */
+                                       /* in the last item, we break out of the loop, in the statement just above */
+                                       menuitemwidth += TAB_SEPARATION;
+                                       ++column;
+                                       p1 = p + 1;
+                                       p = strchr(p1, '\t');
+                               }
+
+                               sz->cx = max(sz->cx, 
+                                       (LONG)(2*TILE_X + menuitemwidth + tm.tmAveCharWidth*12 + tm.tmOverhang));
+                       }
+                       SelectObject(hdc, saveFont);
+               } else {
+                       /* do not change size for text output - the text will be formatted to
+                          fit any window */
+               }
+               sz->cx += extra_cx;
+
+               ReleaseDC(control, hdc);
+       }
+}
+
+void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count)
+{
+       int i;
+
+       if( item<0 || item>=data->menu.size ) return;
+
+       if( data->how==PICK_ONE && count!=0 ) {
+               for(i=0; i<data->menu.size; i++) 
+                       if( item!=i && data->menu.items[i].count!=0 ) {
+                               data->menu.items[i].count = 0;
+                               ListView_RedrawItems( hwndList, i, i );
+                       };
+       }
+
+       data->menu.items[item].count = count;
+       ListView_RedrawItems( hwndList, item, item );
+       reset_menu_count(hwndList, data);
+}
+
+void reset_menu_count(HWND hwndList, PNHMenuWindow data) 
+{
+       int i; 
+       data->menu.counting = FALSE;
+       if( IsWindow(hwndList) ) {
+               i = ListView_GetNextItem((hwndList), -1, LVNI_FOCUSED);
+               if( i>=0 ) ListView_RedrawItems( hwndList, i, i ); 
+       }
+}
+
+/* List window Proc */
+LRESULT CALLBACK NHMenuListWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       BOOL bUpdateFocusItem = FALSE;
+
+       switch(message) {
+
+       /* filter keyboard input for the control */
+#if !defined(WIN_CE_SMARTPHONE)
+       case WM_KEYDOWN:
+       case WM_KEYUP: {
+               MSG msg;
+
+               if( PeekMessage(&msg, hWnd, WM_CHAR, WM_CHAR, PM_REMOVE) ) {
+                       if( onListChar(GetParent(hWnd), hWnd, (char)msg.wParam)==-2 ) {
+                               return 0;
+                       }
+               }
+
+               if( wParam==VK_LEFT || wParam==VK_RIGHT )
+                       bUpdateFocusItem = TRUE;
+       } break;
+
+#else /* defined(WIN_CE_SMARTPHONE) */
+       case WM_KEYDOWN:
+               if( wParam==VK_TACTION ) {
+                       if( onListChar(GetParent(hWnd), hWnd, ' ')==-2 ) {
+                               return 0;
+                       }
+               } else if( NHSPhoneTranslateKbdMessage(wParam, lParam, TRUE) ) {
+                       PMSNHEvent      evt;
+                       BOOL processed = FALSE;
+                       if( mswin_have_input() ) {
+                               evt = mswin_input_pop();
+                               if( evt->type==NHEVENT_CHAR && 
+                                       onListChar(GetParent(hWnd), hWnd, evt->kbd.ch)==-2 ) {
+                                       processed = TRUE;
+                               }
+
+                               /* eat the rest of the events */
+                               if( mswin_have_input() ) mswin_input_pop();
+                       }
+                       if( processed ) return 0;
+               }
+
+               if( wParam==VK_LEFT || wParam==VK_RIGHT )
+                       bUpdateFocusItem = TRUE;
+       break;
+
+       case WM_KEYUP:
+               /* translate SmartPhone keyboard message */
+               if( NHSPhoneTranslateKbdMessage(wParam, lParam, FALSE) )
+                       return 0;
+       break;
+
+       /* tell Windows not to process default button on VK_RETURN */
+       case WM_GETDLGCODE: 
+               return DLGC_DEFPUSHBUTTON | DLGC_WANTALLKEYS |
+                          (wndProcListViewOrig? 
+                                               CallWindowProc(wndProcListViewOrig, hWnd, message, wParam, lParam) 
+                                               : 0 );
+#endif
+
+       case WM_SIZE:
+       case WM_HSCROLL:
+               bUpdateFocusItem = TRUE;
+       break;
+
+       }
+
+       if(     bUpdateFocusItem ) {
+               int i;
+               RECT rt;
+
+               /* invalidate the focus rectangle */
+               i = ListView_GetNextItem(hWnd, -1,      LVNI_FOCUSED);
+               if( i!=-1 ) {
+                       ListView_GetItemRect(hWnd, i, &rt, LVIR_BOUNDS);
+                       InvalidateRect(hWnd, &rt, TRUE);
+               }
+       }
+
+       if( wndProcListViewOrig ) 
+               return CallWindowProc(wndProcListViewOrig, hWnd, message, wParam, lParam);
+       else 
+               return 0;
+}
+
+/* Text control window proc - implements close on space */
+LRESULT CALLBACK NHMenuTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch(message) {
+       case WM_KEYUP:
+               switch( wParam ) {
+               case VK_SPACE:
+               case VK_RETURN:
+                       /* close on space */
+                       PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0);
+                       return 0;
+               
+               case VK_UP:
+                       /* scoll up */
+                       PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL);
+                       return 0;
+
+               case VK_DOWN:
+                       /* scoll down */
+                       PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL);
+                       return 0;
+
+               case VK_LEFT:
+                       /* scoll left */
+                       PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINELEFT, 0), (LPARAM)NULL);
+                       return 0;
+
+               case VK_RIGHT:
+                       /* scoll right */
+                       PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINERIGHT, 0), (LPARAM)NULL);
+                       return 0;
+               }
+               break; /* case WM_KEYUP: */
+       }
+
+       if( editControlWndProc ) 
+               return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam);
+       else 
+               return 0;
+}
+/*----------------------------------------------------------------------------*/
+char* parse_menu_str(char* dest, const char* src, size_t size)
+{
+       char *p1, *p2;
+       if( !dest || size==0 ) return NULL;
+
+       strncpy(dest, src, size);
+       dest[size-1] = '\x0';
+
+       /* replace "[ ]*\[" with "\t\[" */
+       p1 = p2 = strstr(dest, " [");
+       if( p1 ) {
+               while( p1!=dest && *p1==' ') p1--;
+               p1++; /* backup to space */
+               *p2 = '\t';
+               memmove(p1, p2, strlen(p2));
+               p1[strlen(p2)] = '\x0';
+       }
+       return dest;
+}
diff --git a/sys/wince/mhmenu.h b/sys/wince/mhmenu.h
new file mode 100644 (file)
index 0000000..15c4759
--- /dev/null
@@ -0,0 +1,17 @@
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINMenuWindow_h
+#define MSWINMenuWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+#define MENU_TYPE_TEXT     1
+#define MENU_TYPE_MENU     2
+
+HWND mswin_init_menu_window ( int type );
+int mswin_menu_window_select_menu (HWND hwnd, int how, MENU_ITEM_P **);
+void mswin_menu_window_size (HWND hwnd, LPSIZE sz);
+
+#endif /* MSWINTextWindow_h */
diff --git a/sys/wince/mhmsg.h b/sys/wince/mhmsg.h
new file mode 100644 (file)
index 0000000..9e67b42
--- /dev/null
@@ -0,0 +1,60 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MHNethackMessages_H
+#define MHNethackMessages_H
+
+/* nethack messages */
+#define WM_MSNH_COMMAND  (WM_APP+1)
+
+#define MSNH_MSG_ADDWND                        100
+#define MSNH_MSG_PUTSTR                        101
+#define MSNH_MSG_PRINT_GLYPH   102
+#define MSNH_MSG_CLEAR_WINDOW  103
+#define MSNH_MSG_CLIPAROUND            104
+#define MSNH_MSG_STARTMENU             105
+#define MSNH_MSG_ADDMENU               106
+#define MSNH_MSG_CURSOR                        107
+#define MSNH_MSG_ENDMENU               108
+
+typedef struct mswin_nhmsg_add_wnd {
+  winid                  wid;
+} MSNHMsgAddWnd, *PMSNHMsgAddWnd;
+
+typedef struct mswin_nhmsg_putstr {
+  int            attr;
+  const char* text;
+  boolean        append;
+} MSNHMsgPutstr, *PMSNHMsgPutstr;
+
+typedef struct mswin_nhmsg_print_glyph {
+  XCHAR_P              x;
+  XCHAR_P              y;
+  int                  glyph;
+} MSNHMsgPrintGlyph, *PMSNHMsgPrintGlyph;
+
+typedef struct mswin_nhmsg_cliparound {
+  int                  x;
+  int                  y;
+} MSNHMsgClipAround, *PMSNHMsgClipAround;
+
+typedef struct mswin_nhmsg_add_menu {
+       int                             glyph;
+       const ANY_P*    identifier;
+       CHAR_P                  accelerator;
+       CHAR_P                  group_accel;
+       int                             attr;
+       const char *    str;
+       BOOLEAN_P               presel;
+} MSNHMsgAddMenu, *PMSNHMsgAddMenu;
+
+typedef struct mswin_nhmsg_cursor {
+  int                  x;
+  int                  y;
+} MSNHMsgCursor, *PMSNHMsgCursor;
+
+typedef struct mswin_nhmsg_end_menu {
+       const char* text;
+} MSNHMsgEndMenu, *PMSNHMsgEndMenu;
+
+#endif
diff --git a/sys/wince/mhmsgwnd.c b/sys/wince/mhmsgwnd.c
new file mode 100644 (file)
index 0000000..807bfbb
--- /dev/null
@@ -0,0 +1,591 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include "mhmsgwnd.h"
+#include "mhmsg.h"
+#include "mhcmd.h"
+#include "mhfont.h"
+#include "mhcolor.h"
+
+#define MSG_WRAP_TEXT 
+
+#define MSG_VISIBLE_LINES     max(iflags.wc_vary_msgcount, 2)
+#define MAX_MSG_LINES            32
+#define MSG_LINES                        (int)min(iflags.msg_history, MAX_MSG_LINES)
+#define MAXWINDOWTEXT            200
+
+struct window_line {
+       int  attr;
+       char text[MAXWINDOWTEXT];
+};
+
+typedef struct mswin_nethack_message_window {
+       size_t max_text;
+       struct window_line window_text[MAX_MSG_LINES];
+
+       int  xChar;       /* horizontal scrolling unit */
+       int  yChar;       /* vertical scrolling unit */
+       int  xUpper;      /* average width of uppercase letters */
+       int  xPos;        /* current horizontal scrolling position */
+       int  yPos;        /* current vertical scrolling position */
+       int  xMax;        /* maximum horizontal scrolling position */
+       int  yMax;        /* maximum vertical scrolling position */
+       int      xPage;           /* page size of horizontal scroll bar */
+    int  lines_last_turn; /* lines added during the last turn */
+       int  dont_care;   /* flag the the user does not care if messages are lost */
+ } NHMessageWindow, *PNHMessageWindow;
+
+static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass");
+LRESULT CALLBACK       NHMessageWndProc(HWND, UINT, WPARAM, LPARAM);
+static void register_message_window_class();
+static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
+#ifndef MSG_WRAP_TEXT
+static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
+#endif
+static void onPaint(HWND hWnd);
+static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
+
+#ifdef USER_SOUNDS
+extern void play_sound_for_message(const char* str);
+#endif
+
+HWND mswin_init_message_window () {
+       static int run_once = 0;
+       HWND ret;
+       DWORD style;
+
+       if( !run_once ) {
+               register_message_window_class( );
+               run_once = 1;
+       }
+
+#ifdef MSG_WRAP_TEXT                   
+       style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL;
+#else
+       style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL     | WS_HSCROLL;
+#endif
+
+       ret = CreateWindow(
+                       szMessageWindowClass,   /* registered class name */
+                       NULL,                                   /* window name */                       
+                       style, /* window style */
+                       0,   /* horizontal position of window */
+                       0,   /* vertical position of window */
+                       0,   /* window width */
+                       0,   /* window height - set it later */
+                       GetNHApp()->hMainWnd,   /* handle to parent or owner window */
+                       NULL,                                   /* menu handle or child identifier */
+                       GetNHApp()->hApp,               /* handle to application instance */
+                       NULL );                                 /* window-creation data */
+
+       if( !ret ) panic("Cannot create message window");
+
+       return ret;
+}
+
+void register_message_window_class()
+{
+       WNDCLASS wcex;
+       ZeroMemory( &wcex, sizeof(wcex));
+
+       wcex.style                      = CS_NOCLOSE;
+       wcex.lpfnWndProc        = (WNDPROC)NHMessageWndProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = GetNHApp()->hApp;
+       wcex.hIcon                      = NULL;
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = mswin_get_brush(NHW_MESSAGE, MSWIN_COLOR_BG);
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szMessageWindowClass;
+
+       RegisterClass(&wcex);
+}
+    
+LRESULT CALLBACK NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch (message) 
+       {
+       case WM_CREATE:
+               onCreate( hWnd, wParam, lParam );
+               break;
+
+       case WM_MSNH_COMMAND: 
+               onMSNHCommand(hWnd, wParam, lParam);
+               break;
+
+       case WM_PAINT: 
+               onPaint(hWnd);
+               break;
+
+       case WM_SETFOCUS:
+               SetFocus(GetNHApp()->hMainWnd);
+               break;
+
+#ifndef MSG_WRAP_TEXT
+       case WM_HSCROLL:
+               onMSNH_HScroll(hWnd, wParam, lParam);
+               break;
+#endif
+
+       case WM_VSCROLL:
+               onMSNH_VScroll(hWnd, wParam, lParam);
+               break;
+
+       case WM_DESTROY: 
+       {
+               PNHMessageWindow data;
+               data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+               free(data);
+               SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+       }       break;
+
+    case WM_SIZE: 
+    { 
+               SCROLLINFO si;
+        int xNewSize; 
+        int yNewSize; 
+               PNHMessageWindow data;
+       
+               data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+        xNewSize = LOWORD(lParam); 
+        yNewSize = HIWORD(lParam); 
+
+               if( xNewSize>0 || yNewSize>0 ) {
+
+#ifndef MSG_WRAP_TEXT
+                       data->xPage = xNewSize/data->xChar;
+                       data->xMax = max(0, (int)(1 + data->max_text - data->xPage));
+                       data->xPos = min(data->xPos, data->xMax);
+
+                       ZeroMemory(&si, sizeof(si));
+                       si.cbSize = sizeof(si); 
+                       si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS; 
+                       si.nMin   = 0; 
+                       si.nMax   = data->max_text; 
+                       si.nPage  = data->xPage; 
+                       si.nPos   = data->xPos;
+                       SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); 
+#endif
+               
+                       data->yMax = MSG_LINES-1;
+                       data->yPos = min(data->yPos, data->yMax);
+
+                       ZeroMemory(&si, sizeof(si));
+                       si.cbSize = sizeof(si); 
+                       si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS; 
+                       si.nMin   = MSG_VISIBLE_LINES; 
+                       si.nMax   = data->yMax + MSG_VISIBLE_LINES - 1; 
+                       si.nPage  = MSG_VISIBLE_LINES;
+                       si.nPos   = data->yPos;
+                       SetScrollInfo(hWnd, SB_VERT, &si, TRUE); 
+               }
+    } 
+    break; 
+
+       default:
+               return DefWindowProc(hWnd, message, wParam, lParam);
+   }
+   return 0;
+}
+
+void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMessageWindow data;
+       
+       data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch( wParam ) {
+       case MSNH_MSG_PUTSTR: 
+       {
+               PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
+               SCROLLINFO si;
+               char* p;
+
+               if( msg_data->append ) {
+                       strncat(data->window_text[MSG_LINES-1].text, msg_data->text, 
+                                   MAXWINDOWTEXT - strlen(data->window_text[MSG_LINES-1].text));
+               } else {
+                       /* check if the string is empty */
+                       for(p = data->window_text[MSG_LINES-1].text; *p && isspace(*p); p++);
+
+                       if( *p ) {
+                               /* last string is not empty - scroll up */
+                               memmove(&data->window_text[0],
+                                               &data->window_text[1],
+                                               (MSG_LINES-1)*sizeof(data->window_text[0]));
+                       }
+
+                       /* append new text to the end of the array */
+                       data->window_text[MSG_LINES-1].attr = msg_data->attr;
+                       strncpy(data->window_text[MSG_LINES-1].text, msg_data->text, MAXWINDOWTEXT);
+               }
+               
+               /* reset V-scroll position to display new text */
+               data->yPos = data->yMax;
+
+               ZeroMemory(&si, sizeof(si));
+        si.cbSize = sizeof(si);
+        si.fMask  = SIF_POS; 
+        si.nPos   = data->yPos; 
+        SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
+
+               /* deal with overflows */
+               data->lines_last_turn++;
+               if( !data->dont_care && data->lines_last_turn>=MSG_LINES-2 ) {
+                       char c;
+                       BOOL done;
+
+                       /* append "--More--" to the message window text (cannot call putstr 
+                          here - infinite recursion) */
+                       memmove(&data->window_text[0],
+                                       &data->window_text[1],
+                                       (MSG_LINES-1)*sizeof(data->window_text[0]));
+                       data->window_text[MSG_LINES-1].attr = ATR_NONE;
+                       strncpy(data->window_text[MSG_LINES-1].text, "--More--", MAXWINDOWTEXT);
+                       
+                       /* update window content */
+                       InvalidateRect(hWnd, NULL, TRUE);
+
+#if defined(WIN_CE_SMARTPHONE)
+                       NHSPhoneSetKeypadFromString( "\033- <>" );
+#endif
+
+                       done = FALSE;
+                       while( !done ) {
+                               int x, y, mod;
+                               c = mswin_nh_poskey(&x, &y, &mod);
+                               switch (c) {
+                                       /* ESC indicates that we can safely discard any further messages during this turn */
+                                       case '\033':
+                                               data->dont_care = 1;
+                                               done = TRUE;
+                                       break;
+
+                                       case '<':
+                                               SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL); 
+                                       break;
+
+                                       case '>':
+                                               SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL); 
+                                       break;
+
+                                       /* continue scrolling on any key */
+                                       default:
+                                               data->lines_last_turn = 0;
+                                               done = TRUE;
+                                       break;
+                               }
+                       }
+
+#if defined(WIN_CE_SMARTPHONE)
+                       NHSPhoneSetKeypadDefault();
+#endif
+                       /* remove "--More--" from the message window text */
+                       data->window_text[MSG_LINES-1].attr = ATR_NONE;
+                       strncpy(data->window_text[MSG_LINES-1].text, " ", MAXWINDOWTEXT);
+               }
+                       
+               /* update window content */
+               InvalidateRect(hWnd, NULL, TRUE);
+
+#ifdef USER_SOUNDS
+               play_sound_for_message(msg_data->text);
+#endif
+       }
+       break;
+
+       case MSNH_MSG_CLEAR_WINDOW:
+               data->lines_last_turn = 0;
+               data->dont_care = 0;
+       break;
+       }
+}
+
+void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMessageWindow data;
+       SCROLLINFO si; 
+       int yInc;
+       /* get window data */
+       data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       
+       ZeroMemory(&si, sizeof(si));
+       si.cbSize = sizeof(si);
+       si.fMask = SIF_PAGE | SIF_POS;
+       GetScrollInfo(hWnd, SB_VERT, &si);
+
+       switch(LOWORD (wParam)) 
+       { 
+    // User clicked the shaft above the scroll box. 
+
+    case SB_PAGEUP: 
+         yInc = -(int)si.nPage; 
+         break; 
+
+    // User clicked the shaft below the scroll box. 
+
+    case SB_PAGEDOWN: 
+         yInc = si.nPage; 
+         break; 
+
+    // User clicked the top arrow. 
+
+    case SB_LINEUP: 
+         yInc = -1; 
+         break; 
+
+    // User clicked the bottom arrow. 
+
+    case SB_LINEDOWN: 
+         yInc = 1; 
+         break; 
+
+    // User dragged the scroll box. 
+
+    case SB_THUMBTRACK: 
+         yInc = HIWORD(wParam) - data->yPos; 
+         break; 
+
+    default: 
+         yInc = 0; 
+       }
+
+       // If applying the vertical scrolling increment does not 
+       // take the scrolling position out of the scrolling range, 
+       // increment the scrolling position, adjust the position 
+       // of the scroll box, and update the window. UpdateWindow 
+       // sends the WM_PAINT message. 
+
+       if (yInc = max( MSG_VISIBLE_LINES - data->yPos, 
+                           min(yInc, data->yMax - data->yPos))) 
+       { 
+               data->yPos += yInc; 
+               /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc, 
+                       (CONST RECT *) NULL, (CONST RECT *) NULL, 
+                       (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); 
+               */
+               InvalidateRect(hWnd, NULL, TRUE);
+
+               ZeroMemory(&si, sizeof(si));
+               si.cbSize = sizeof(si); 
+               si.fMask  = SIF_POS; 
+               si.nPos   = data->yPos; 
+               SetScrollInfo(hWnd, SB_VERT, &si, TRUE); 
+
+               UpdateWindow (hWnd); 
+       } 
+}
+
+#ifndef MSG_WRAP_TEXT
+void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMessageWindow data;
+       SCROLLINFO si; 
+       int xInc;
+       /* get window data */
+       data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       
+       ZeroMemory(&si, sizeof(si));
+       si.cbSize = sizeof(si);
+       si.fMask = SIF_PAGE;
+       GetScrollInfo(hWnd, SB_HORZ, &si);
+
+    switch(LOWORD (wParam)) 
+    { 
+        // User clicked shaft left of the scroll box. 
+
+        case SB_PAGEUP: 
+             xInc = - (int)si.nPage; 
+             break; 
+
+        // User clicked shaft right of the scroll box. 
+
+        case SB_PAGEDOWN: 
+             xInc = si.nPage; 
+             break; 
+
+        // User clicked the left arrow. 
+
+        case SB_LINEUP: 
+             xInc = -1; 
+             break; 
+
+        // User clicked the right arrow. 
+
+        case SB_LINEDOWN: 
+             xInc = 1; 
+             break; 
+
+        // User dragged the scroll box. 
+
+        case SB_THUMBTRACK: 
+             xInc = HIWORD(wParam) - data->xPos; 
+             break; 
+
+        default: 
+             xInc = 0; 
+
+    }
+
+       
+    // If applying the horizontal scrolling increment does not 
+    // take the scrolling position out of the scrolling range, 
+    // increment the scrolling position, adjust the position 
+    // of the scroll box, and update the window. 
+
+    if (xInc = max (-data->xPos, min (xInc, data->xMax - data->xPos))) 
+    { 
+        data->xPos += xInc; 
+        ScrollWindowEx (hWnd, -data->xChar * xInc, 0, 
+            (CONST RECT *) NULL, (CONST RECT *) NULL, 
+            (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); 
+
+               ZeroMemory(&si, sizeof(si));
+        si.cbSize = sizeof(si); 
+        si.fMask  = SIF_POS; 
+        si.nPos   = data->xPos; 
+        SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); 
+        UpdateWindow (hWnd); 
+    } 
+}
+#endif // MSG_WRAP_TEXT
+
+void onPaint(HWND hWnd)
+{
+       PAINTSTRUCT ps;
+       HDC hdc;
+       PNHMessageWindow data;
+       RECT client_rt, draw_rt;
+       int FirstLine, LastLine;
+       int i, x, y;
+       HGDIOBJ oldFont;
+       TCHAR wbuf[MAXWINDOWTEXT+2];
+       size_t wlen;
+       COLORREF OldBg, OldFg;
+
+       hdc = BeginPaint(hWnd, &ps);
+
+       OldBg = SetBkColor(hdc, mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_BG));
+       OldFg = SetTextColor(hdc, mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_FG)); 
+
+       data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       GetClientRect(hWnd, &client_rt);
+
+       if( !IsRectEmpty(&ps.rcPaint) ) {
+               FirstLine = max (0, data->yPos - (client_rt.bottom - ps.rcPaint.top)/data->yChar + 1); 
+               LastLine = min (MSG_LINES-1, data->yPos - (client_rt.bottom - ps.rcPaint.bottom)/data->yChar); 
+               y = min( ps.rcPaint.bottom, client_rt.bottom - 2); 
+               for (i=LastLine; i>=FirstLine; i--) { 
+                       if( i==MSG_LINES-1 ) {
+                               x = data->xChar * (2 - data->xPos); 
+                       } else {
+                               x = data->xChar * (4 - data->xPos); 
+                       }
+
+
+                       if( strlen(data->window_text[i].text)>0 ) {
+                               /* convert to UNICODE */
+                               NH_A2W(data->window_text[i].text, wbuf, sizeof(wbuf));
+                               wlen = _tcslen(wbuf);
+
+                               /* calculate text height */
+                               draw_rt.left = x;
+                               draw_rt.right = client_rt.right;
+                               draw_rt.top = y - data->yChar;
+                               draw_rt.bottom = y;
+
+                               oldFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[i].attr, hdc, FALSE));
+
+#ifdef MSG_WRAP_TEXT                           
+                               DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
+                               draw_rt.top = y - (draw_rt.bottom - draw_rt.top);
+                               draw_rt.bottom = y;
+                               DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK);
+#else
+                               DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX );
+#endif
+                               SelectObject(hdc, oldFont);
+
+                               y -= draw_rt.bottom - draw_rt.top;
+                       } else {
+                               y -= data->yChar;
+                       }
+
+                       /* highligh the last line */
+                       if( i==MSG_LINES-1 ) {
+                               draw_rt.left = client_rt.left;
+                               draw_rt.right = draw_rt.left + 2*data->xChar;
+                               DrawText(hdc, TEXT("> "), 2, &draw_rt, DT_NOPREFIX );
+
+                               y -= 2;
+                               draw_rt.left = client_rt.left;
+                               draw_rt.right = client_rt.right;
+                               draw_rt.top -= 2;
+                               draw_rt.bottom = client_rt.bottom;
+                               DrawEdge(hdc, &draw_rt, EDGE_SUNKEN, BF_TOP );
+                               DrawEdge(hdc, &draw_rt, EDGE_SUNKEN, BF_BOTTOM );
+                       }
+               }
+       }
+
+       SetTextColor (hdc, OldFg);
+       SetBkColor (hdc, OldBg);
+       EndPaint(hWnd, &ps);
+}
+
+void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       HDC hdc;
+       TEXTMETRIC tm; 
+       PNHMessageWindow data;
+       HGDIOBJ saveFont;
+
+       /* set window data */
+       data = (PNHMessageWindow)malloc(sizeof(NHMessageWindow));
+       if( !data ) panic("out of memory");
+       ZeroMemory(data, sizeof(NHMessageWindow));
+       data->max_text = MAXWINDOWTEXT;
+       SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
+
+    /* Get the handle to the client area's device context. */
+    hdc = GetDC(hWnd); 
+       saveFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE));
+
+    /* Extract font dimensions from the text metrics. */
+    GetTextMetrics (hdc, &tm); 
+    data->xChar = tm.tmAveCharWidth; 
+    data->xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * data->xChar/2; 
+    data->yChar = tm.tmHeight + tm.tmExternalLeading; 
+       data->xPage = 1;
+
+    /* Free the device context.  */
+       SelectObject(hdc, saveFont);
+    ReleaseDC (hWnd, hdc); 
+}
+
+void mswin_message_window_size (HWND hWnd, LPSIZE sz)
+{
+       PNHMessageWindow data;
+       RECT rt, client_rt;
+
+       GetWindowRect(hWnd, &rt);
+
+       sz->cx = rt.right - rt.left;
+       sz->cy = rt.bottom - rt.top;
+
+       data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if(data) {
+               /* set size to accomodate MSG_VISIBLE_LINES, highligh rectangle and
+                  horizontal scroll bar (difference between window rect and client rect */
+               GetClientRect(hWnd, &client_rt);
+               sz->cy = sz->cy-(client_rt.bottom - client_rt.top) +
+                            data->yChar * MSG_VISIBLE_LINES + 4;
+       }
+}
+
diff --git a/sys/wince/mhmsgwnd.h b/sys/wince/mhmsgwnd.h
new file mode 100644 (file)
index 0000000..0434f1c
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINMessageWindow_h
+#define MSWINMessageWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+HWND mswin_init_message_window ();
+void mswin_message_window_size (HWND hWnd, LPSIZE sz);
+
+
+#endif /* MSWINMessageWindow_h */
diff --git a/sys/wince/mhrip.c b/sys/wince/mhrip.c
new file mode 100644 (file)
index 0000000..29cf930
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include "mhrip.h"
+#include "mhtext.h"
+
+HWND mswin_init_RIP_window () 
+{
+       return mswin_init_text_window();
+}
+
+void mswin_display_RIP_window (HWND hWnd)
+{
+       mswin_display_text_window(hWnd);
+}
+
diff --git a/sys/wince/mhrip.h b/sys/wince/mhrip.h
new file mode 100644 (file)
index 0000000..5825d03
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINRIPWindow_h
+#define MSWINRIPWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+HWND mswin_init_RIP_window ();
+void mswin_display_RIP_window (HWND hwnd);
+
+#endif /* MSWINRIPWindow_h */
+
diff --git a/sys/wince/mhstatus.c b/sys/wince/mhstatus.c
new file mode 100644 (file)
index 0000000..78ddbd9
--- /dev/null
@@ -0,0 +1,273 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include "mhstatus.h"
+#include "mhmsg.h"
+#include "mhfont.h"
+#include "mhcolor.h"
+
+#define MAXWINDOWTEXT 255
+
+#define NHSTAT_LINES_2 2
+#define NHSTAT_LINES_4 4
+typedef struct mswin_nethack_status_window {
+       int             nhstat_format;
+       char    window_text[MAXWINDOWTEXT];
+} NHStatusWindow, *PNHStatusWindow;
+
+static TCHAR szStatusWindowClass[] = TEXT("MSNHStatusWndClass");
+LRESULT CALLBACK       StatusWndProc(HWND, UINT, WPARAM, LPARAM);
+static void register_status_window_class(void);
+static void FormatStatusString(char* text, int format);
+
+HWND mswin_init_status_window () {
+       static int run_once = 0;
+       HWND ret;
+       NHStatusWindow* data;
+
+       if( !run_once ) {
+               register_status_window_class( );
+               run_once = 1;
+       }
+       
+       ret = CreateWindow(                                
+                       szStatusWindowClass,
+                       NULL,
+                       WS_CHILD | WS_DISABLED | WS_CLIPSIBLINGS,
+                       0,  /* x position */
+                       0,  /* y position */
+                       0,  /* x-size - we will set it later */
+                       0,  /* y-size - we will set it later */
+                       GetNHApp()->hMainWnd,
+                       NULL,
+                       GetNHApp()->hApp,
+                       NULL );
+       if( !ret ) panic("Cannot create status window");
+       
+       EnableWindow(ret, FALSE);
+
+       data = (PNHStatusWindow)malloc(sizeof(NHStatusWindow));
+       if( !data ) panic("out of memory");
+
+       ZeroMemory(data, sizeof(NHStatusWindow));
+       data->nhstat_format = NHSTAT_LINES_4;
+       SetWindowLong(ret, GWL_USERDATA, (LONG)data);
+       return ret;
+}
+
+void register_status_window_class()
+{
+       WNDCLASS wcex;
+       
+       ZeroMemory( &wcex, sizeof(wcex));
+       wcex.style                      = CS_NOCLOSE;
+       wcex.lpfnWndProc        = (WNDPROC)StatusWndProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = GetNHApp()->hApp;
+       wcex.hIcon                      = NULL;
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = mswin_get_brush(NHW_STATUS, MSWIN_COLOR_BG);
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szStatusWindowClass;
+
+       RegisterClass(&wcex);
+}
+    
+    
+LRESULT CALLBACK StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       RECT rt;
+       PAINTSTRUCT ps;
+       HDC hdc;
+       PNHStatusWindow data;
+       
+       data = (PNHStatusWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch (message) 
+       {
+       case WM_MSNH_COMMAND: {
+               switch( wParam ) {
+               
+               case MSNH_MSG_PUTSTR:
+               case MSNH_MSG_CLEAR_WINDOW:
+                       ZeroMemory(data->window_text, sizeof(data->window_text));
+                       FormatStatusString(data->window_text, data->nhstat_format);
+                       break;
+
+               case MSNH_MSG_CURSOR: {
+                       PMSNHMsgCursor msg_data = (PMSNHMsgCursor)lParam;
+                       if( msg_data->y==0 ) {
+                               InvalidateRect(hWnd, NULL, TRUE);
+                       }
+               } break;
+               }
+       } break;
+
+       case WM_PAINT: {
+                       HGDIOBJ oldFont;
+                       TCHAR wbuf[MAXWINDOWTEXT];
+                       COLORREF OldBg, OldFg;
+
+                       hdc = BeginPaint(hWnd, &ps);
+                       GetClientRect(hWnd, &rt);
+                       
+                       oldFont = SelectObject(hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE));
+                       OldBg = SetBkColor(hdc, mswin_get_color(NHW_STATUS, MSWIN_COLOR_BG));
+                       OldFg = SetTextColor(hdc, mswin_get_color(NHW_STATUS, MSWIN_COLOR_FG)); 
+
+                       DrawText(hdc, 
+                                        NH_A2W(data->window_text, wbuf, MAXWINDOWTEXT),
+                                        strlen(data->window_text), 
+                                        &rt, 
+                                        DT_LEFT | DT_NOPREFIX);
+
+                       SetTextColor (hdc, OldFg);
+                       SetBkColor (hdc, OldBg);
+                       SelectObject(hdc, oldFont);
+                       EndPaint(hWnd, &ps);
+               } break;
+
+       case WM_DESTROY:
+               free(data);
+               SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+               break;
+
+       case WM_SETFOCUS:
+               SetFocus(GetNHApp()->hMainWnd);
+               break;
+
+       default:
+               return DefWindowProc(hWnd, message, wParam, lParam);
+   }
+   return 0;
+}
+
+void mswin_status_window_size (HWND hWnd, LPSIZE sz)
+{
+    TEXTMETRIC tm;
+       HGDIOBJ saveFont;
+       HDC hdc;
+       PNHStatusWindow data;
+       RECT rt;
+       GetWindowRect(hWnd, &rt);
+       sz->cx = rt.right - rt.left;
+       sz->cy = rt.bottom - rt.top;
+
+       data = (PNHStatusWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if(data) {
+               hdc = GetDC(hWnd);
+               saveFont = SelectObject(hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE));
+               GetTextMetrics(hdc, &tm);
+
+               /* see if the status window can fit 80 characters per line */
+               if( (80*tm.tmMaxCharWidth)>=sz->cx ) data->nhstat_format = NHSTAT_LINES_4;
+               else                                                     data->nhstat_format = NHSTAT_LINES_2;
+
+               /* set height of the status box */
+               sz->cy = tm.tmHeight * data->nhstat_format;
+
+               SelectObject(hdc, saveFont);
+               ReleaseDC(hWnd, hdc);
+       }
+}
+extern const char *hu_stat[];  /* defined in eat.c */
+extern const char *enc_stat[]; /* define in botl.c */
+void FormatStatusString(char* text, int format)
+{
+       register char *nb;
+       int hp, hpmax;
+       int cap = near_capacity();
+
+       Strcpy(text, plname);
+       if('a' <= text[0] && text[0] <= 'z') text[0] += 'A'-'a';
+       text[10] = 0;
+       Sprintf(nb = eos(text)," the ");
+
+       if (Upolyd) {
+               char mbot[BUFSZ];
+               int k = 0;
+
+               Strcpy(mbot, mons[u.umonnum].mname);
+               while(mbot[k] != 0) {
+                   if ((k == 0 || (k > 0 && mbot[k-1] == ' ')) &&
+                                       'a' <= mbot[k] && mbot[k] <= 'z')
+                       mbot[k] += 'A' - 'a';
+                   k++;
+               }
+               Sprintf(nb = eos(nb), mbot);
+       } else
+               Sprintf(nb = eos(nb), rank_of(u.ulevel, Role_switch, flags.female));
+
+       if( format==NHSTAT_LINES_4 ) Sprintf(nb = eos(nb),"\r\n");
+
+       if (ACURR(A_STR) > 18) {
+               if (ACURR(A_STR) > STR18(100))
+                   Sprintf(nb = eos(nb),"St:%2d ",ACURR(A_STR)-100);
+               else if (ACURR(A_STR) < STR18(100))
+                   Sprintf(nb = eos(nb), "St:18/%02d ",ACURR(A_STR)-18);
+               else
+                   Sprintf(nb = eos(nb),"St:18/** ");
+       } else
+               Sprintf(nb = eos(nb), "St:%-1d ",ACURR(A_STR));
+       Sprintf(nb = eos(nb),
+               "Dx:%-1d Co:%-1d In:%-1d Wi:%-1d Ch:%-1d",
+               ACURR(A_DEX), ACURR(A_CON), ACURR(A_INT), ACURR(A_WIS), ACURR(A_CHA));
+       Sprintf(nb = eos(nb), (u.ualign.type == A_CHAOTIC) ? "  Chaotic" :
+                       (u.ualign.type == A_NEUTRAL) ? "  Neutral" : "  Lawful");
+#ifdef SCORE_ON_BOTL
+       if (flags.showscore)
+           Sprintf(nb = eos(nb), " S:%ld", botl_score());
+#endif
+       if( format==NHSTAT_LINES_4 ||
+               format==NHSTAT_LINES_2 ) strcat(text, "\r\n");
+
+       /* third line */
+       hp = Upolyd ? u.mh : u.uhp;
+       hpmax = Upolyd ? u.mhmax : u.uhpmax;
+
+       if(hp < 0) hp = 0;
+       (void) describe_level(nb=eos(nb));
+       Sprintf(nb = eos(nb),
+               "%c:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d", oc_syms[COIN_CLASS],
+#ifndef GOLDOBJ
+               u.ugold,
+#else
+               money_cnt(invent),
+#endif
+               hp, hpmax, u.uen, u.uenmax, u.uac);
+
+       if (Upolyd)
+               Sprintf(nb = eos(nb), " HD:%d", mons[u.umonnum].mlevel);
+#ifdef EXP_ON_BOTL
+       else if(flags.showexp)
+               Sprintf(nb = eos(nb), " Xp:%u/%-1ld", u.ulevel,u.uexp);
+#endif
+       else
+               Sprintf(nb = eos(nb), " Exp:%u", u.ulevel);
+       if( format==NHSTAT_LINES_4 ) strcat(text, "\r\n");
+       else                         strcat(text, " ");
+
+       /* forth line */
+       if(flags.time)
+           Sprintf(nb = eos(nb), "T:%ld ", moves);
+
+       if(strcmp(hu_stat[u.uhs], "        ")) {
+               Strcat(text, hu_stat[u.uhs]);
+               Sprintf(nb = eos(nb), " ");
+       }
+       if(Confusion)      Sprintf(nb = eos(nb), "Conf");
+       if(Sick) {
+               if (u.usick_type & SICK_VOMITABLE)
+                          Sprintf(nb = eos(nb), " FoodPois");
+               if (u.usick_type & SICK_NONVOMITABLE)
+                          Sprintf(nb = eos(nb), " Ill");
+       }
+       if(Blind)          Sprintf(nb = eos(nb), " Blind");
+       if(Stunned)        Sprintf(nb = eos(nb), " Stun");
+       if(Hallucination)  Sprintf(nb = eos(nb), " Hallu");
+       if(Slimed)         Sprintf(nb = eos(nb), " Slime");
+       if(cap > UNENCUMBERED)
+               Sprintf(nb = eos(nb), " %s", enc_stat[cap]);
+}
+
diff --git a/sys/wince/mhstatus.h b/sys/wince/mhstatus.h
new file mode 100644 (file)
index 0000000..3658659
--- /dev/null
@@ -0,0 +1,14 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINStatusWindow_h
+#define MSWINStatusWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+HWND mswin_init_status_window ();
+void mswin_status_window_size (HWND hWnd, LPSIZE sz);
+
+#endif /* MSWINStatusWindow_h */
diff --git a/sys/wince/mhtext.c b/sys/wince/mhtext.c
new file mode 100644 (file)
index 0000000..d3de165
--- /dev/null
@@ -0,0 +1,236 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include "mhtext.h"
+#include "mhmsg.h"
+#include "mhfont.h"
+#include "mhcolor.h"
+#include "mhtxtbuf.h"
+
+typedef struct mswin_nethack_text_window {
+       PNHTextBuffer  window_text;
+       int done;
+} NHTextWindow, *PNHTextWindow;
+
+static WNDPROC editControlWndProc = NULL;
+
+LRESULT CALLBACK       TextWndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK       NHTextControlWndProc(HWND, UINT, WPARAM, LPARAM);
+static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void LayoutText(HWND hwnd);
+
+HWND mswin_init_text_window () {
+       HWND ret;
+       PNHTextWindow data;
+
+       ret = CreateDialog(
+                       GetNHApp()->hApp,
+                       MAKEINTRESOURCE(IDD_NHTEXT),
+                       GetNHApp()->hMainWnd,
+                       TextWndProc
+       );
+       if( !ret ) panic("Cannot create text window");
+
+       data = (PNHTextWindow)malloc(sizeof(NHTextWindow));
+       if( !data ) panic("out of memory");
+
+       ZeroMemory(data, sizeof(NHTextWindow));
+       data->window_text = mswin_init_text_buffer(
+                       program_state.gameover? FALSE : GetNHApp()->bWrapText
+               );
+       SetWindowLong(ret, GWL_USERDATA, (LONG)data);
+       return ret;
+}
+
+void mswin_display_text_window (HWND hWnd)
+{
+       PNHTextWindow data;
+       
+       data = (PNHTextWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if( data ) {
+               HWND control;
+               control = GetDlgItem(hWnd, IDC_TEXT_CONTROL);
+               SendMessage(control, EM_FMTLINES, 1, 0 );
+               mswin_render_text(data->window_text, GetDlgItem(hWnd, IDC_TEXT_CONTROL));
+
+               data->done = 0;
+               mswin_popup_display(hWnd, &data->done);
+               mswin_popup_destroy(hWnd);
+       }
+}
+    
+LRESULT CALLBACK TextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       HWND control;
+       HDC hdc;
+       PNHTextWindow data;
+       
+       data = (PNHTextWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch (message) 
+       {
+       case WM_INITDIALOG:
+           /* set text control font */
+               control = GetDlgItem(hWnd, IDC_TEXT_CONTROL);
+               if( !control ) {
+                       panic("cannot get text view window");
+               }
+
+               hdc = GetDC(control);
+               SendMessage(control, WM_SETFONT, (WPARAM)mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), 0);
+               ReleaseDC(control, hdc);
+
+#if defined(WIN_CE_SMARTPHONE)
+               /* special initialization for SmartPhone dialogs */ 
+               NHSPhoneDialogSetup(hWnd, FALSE, GetNHApp()->bFullScreen);
+#endif
+               /* subclass edit control */
+               editControlWndProc = (WNDPROC)GetWindowLong(control, GWL_WNDPROC);
+               SetWindowLong(control, GWL_WNDPROC, (LONG)NHTextControlWndProc);
+
+               if( !program_state.gameover && GetNHApp()->bWrapText ) {
+                       DWORD styles;
+                       styles = GetWindowLong(control, GWL_STYLE);
+                       if( styles ) {
+                               SetWindowLong(control, GWL_STYLE, styles & (~WS_HSCROLL));
+                               SetWindowPos(control, NULL, 0, 0, 0, 0, 
+                                                         SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE );
+                       }
+               }
+
+               SetFocus(control);
+       return FALSE;
+
+       case WM_MSNH_COMMAND:
+               onMSNHCommand(hWnd, wParam, lParam);
+       break;
+
+       case WM_SIZE:
+               LayoutText(hWnd);
+       return FALSE;
+
+       case WM_COMMAND:
+               switch (LOWORD(wParam)) 
+        { 
+          case IDOK: 
+                 case IDCANCEL:
+                       data->done = 1;
+                       return TRUE;
+               }
+       break;
+
+       case WM_CTLCOLORBTN:
+       case WM_CTLCOLOREDIT:
+       case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */
+               HDC hdcEdit = (HDC) wParam; 
+               HWND hwndEdit = (HWND) lParam;
+               if( hwndEdit == GetDlgItem(hWnd, IDC_TEXT_CONTROL) ) {
+                       SetBkColor(hdcEdit, mswin_get_color(NHW_TEXT, MSWIN_COLOR_BG));
+                       SetTextColor(hdcEdit, mswin_get_color(NHW_TEXT, MSWIN_COLOR_FG)); 
+                       return (BOOL)mswin_get_brush(NHW_TEXT, MSWIN_COLOR_BG);
+               }
+       } return FALSE;
+
+       case WM_DESTROY:
+               if( data ) {
+                       mswin_free_text_buffer(data->window_text);
+                       free(data);
+                       SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+               }
+       break;
+
+       }
+       return FALSE;
+}
+
+void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHTextWindow data;
+       
+       data = (PNHTextWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch( wParam ) {
+       case MSNH_MSG_PUTSTR: {
+               PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
+               mswin_add_text(data->window_text, msg_data->attr, msg_data->text);
+               break;
+       }
+       }
+}
+
+void LayoutText(HWND hWnd) 
+{
+       HWND  btn_ok;
+       HWND  text;
+       RECT  clrt, rt;
+       POINT pt_elem, pt_ok;
+       SIZE  sz_elem, sz_ok;
+
+       text = GetDlgItem(hWnd, IDC_TEXT_CONTROL);
+       btn_ok = GetDlgItem(hWnd, IDOK);
+
+       /* get window coordinates */
+       GetClientRect(hWnd, &clrt );
+       
+       /* set window placements */
+       if( IsWindow(btn_ok) ) {
+               GetWindowRect(btn_ok, &rt);
+               sz_ok.cx = clrt.right - clrt.left;
+               sz_ok.cy = rt.bottom-rt.top;
+               pt_ok.x = clrt.left;
+               pt_ok.y = clrt.bottom - sz_ok.cy;
+               MoveWindow(btn_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE );
+
+               pt_elem.x = clrt.left;
+               pt_elem.y = clrt.top;
+               sz_elem.cx = clrt.right - clrt.left;
+               sz_elem.cy = pt_ok.y;
+               MoveWindow(text, pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE );
+       } else {
+               pt_elem.x = clrt.left;
+               pt_elem.y = clrt.top;
+               sz_elem.cx = clrt.right - clrt.left;
+               sz_elem.cy = clrt.bottom - clrt.top;
+               MoveWindow(text, pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE );
+       }
+}
+
+/* Text control window proc - implements close on space and scrolling on arrows */
+LRESULT CALLBACK NHTextControlWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch(message) {
+       case WM_KEYUP:
+               switch( wParam ) {
+               case VK_SPACE:
+               case VK_RETURN:
+                       /* close on space */
+                       PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0);
+                       return 0;
+               
+               case VK_UP:
+                       /* scoll up */
+                       PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL);
+                       return 0;
+
+               case VK_DOWN:
+                       /* scoll down */
+                       PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL);
+                       return 0;
+
+               case VK_LEFT:
+                       /* scoll left */
+                       PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINELEFT, 0), (LPARAM)NULL);
+                       return 0;
+
+               case VK_RIGHT:
+                       /* scoll right */
+                       PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINERIGHT, 0), (LPARAM)NULL);
+                       return 0;
+               }
+               break; /* case WM_KEYUP: */
+       }
+
+       if( editControlWndProc ) 
+               return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam);
+       else 
+               return 0;
+}
diff --git a/sys/wince/mhtext.h b/sys/wince/mhtext.h
new file mode 100644 (file)
index 0000000..3a7b1b7
--- /dev/null
@@ -0,0 +1,14 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINTextWindow_h
+#define MSWINTextWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+HWND mswin_init_text_window ();
+void mswin_display_text_window (HWND hwnd);
+
+#endif /* MSWINTextWindow_h */
diff --git a/sys/wince/mhtxtbuf.c b/sys/wince/mhtxtbuf.c
new file mode 100644 (file)
index 0000000..4ab5a83
--- /dev/null
@@ -0,0 +1,238 @@
+/* Copyright (C) 2003 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "mhtxtbuf.h"
+
+/* Collect Nethack text messages and render text into edit box.
+   Wrap text if necessary.
+   Recognize formatted lines as having more that 4 consecutive.
+   spaces inside the string.
+   Strip leading and trailing spaces.
+   Always break at the original line end (do not merge text that comes 
+   from NetHack engine)
+*/
+
+/*----------------------------------------------------------------*/
+#define NHTEXT_BUFFER_INCREMENT 10
+/*----------------------------------------------------------------*/
+struct text_buffer_line {
+       int             attr;
+       short   beg_padding;
+       short   end_padding;
+       BOOL    formatted;
+       char*   text;
+};
+/*----------------------------------------------------------------*/
+typedef struct mswin_nethack_text_buffer {
+       BOOL b_wrap_text;
+       int n_size;
+       int n_used;
+       struct text_buffer_line *text_buffer_line;
+} NHTextBuffer, *PNHTextBuffer;
+/*----------------------------------------------------------------*/
+#define NHTextLine(pb,i)  ((pb)->text_buffer_line[(i)])
+static TCHAR* nh_append( TCHAR* s, int* size, const char* ap );
+/*----------------------------------------------------------------*/
+PNHTextBuffer mswin_init_text_buffer(BOOL wrap_text)
+{
+       PNHTextBuffer pb = (PNHTextBuffer)malloc(sizeof(NHTextBuffer));
+       if( !pb ) panic("Out of memory");
+       
+       ZeroMemory(pb, sizeof(NHTextBuffer));
+       pb->b_wrap_text = wrap_text;
+       pb->n_size = 0;
+       pb->n_used = 0;
+       pb->text_buffer_line = NULL;
+       return pb;
+}
+/*----------------------------------------------------------------*/
+void mswin_free_text_buffer(PNHTextBuffer pb)
+{
+       int i;
+       
+       if( !pb ) return;
+
+       for(i=0; i<pb->n_used; i++ ) {
+               free(pb->text_buffer_line[i].text);
+       }
+       free( pb->text_buffer_line );
+       free( pb );
+}
+/*----------------------------------------------------------------*/
+void mswin_add_text(PNHTextBuffer pb, int attr, const char* text)
+{
+       char* p;
+       struct text_buffer_line* new_line;
+
+       /* grow buffer */
+       if( pb->n_used >= pb->n_size ) {
+               pb->n_size += NHTEXT_BUFFER_INCREMENT;
+               pb->text_buffer_line =
+                       (struct text_buffer_line*)realloc( pb->text_buffer_line, pb->n_size*sizeof(struct text_buffer_line) );
+               if( !pb->text_buffer_line ) panic("Memory allocation error");
+       }
+
+       /* analyze the new line of text */
+       new_line = &NHTextLine(pb, pb->n_used);
+       new_line->attr = attr;
+       new_line->beg_padding = 0;
+       new_line->text = strdup(text);
+       for( p = new_line->text; *p && isspace(*p); p++ ) {
+               new_line->beg_padding++;
+       }
+       if( *p ) {
+               memmove(new_line->text,
+                               new_line->text + new_line->beg_padding,
+                               strlen(new_line->text) - new_line->beg_padding + 1
+                               );
+               for( p = new_line->text+strlen(new_line->text); 
+                        p>=new_line->text && isspace(*p); 
+                        p-- ) {
+                       new_line->end_padding++;
+                       *p = 0;
+               }
+
+               /* if there are 3 (or more) consecutive spaces inside the string 
+                  consider it formatted */
+               new_line->formatted = (strstr(new_line->text, "   ")!=NULL);
+       } else {
+               new_line->end_padding = 0;
+               new_line->text[0] = 0;
+               new_line->formatted = FALSE;
+       }
+       pb->n_used++;
+}
+/*----------------------------------------------------------------*/
+static TCHAR* nh_append( TCHAR* s, int* size, const char* ap )
+{
+       int tlen, tnewlen;
+
+       if( !(ap && *ap) ) return s;
+
+       /* append the calculated line to the text buffer */
+       tlen = s? _tcslen(s) : 0;
+       tnewlen = tlen+strlen(ap);
+       if( tnewlen>=*size ) {
+               *size = max(tnewlen, *size + BUFSZ);
+               s = (TCHAR*)realloc(s, *size * sizeof(TCHAR));
+               if( !s ) panic("Out of memory");
+               ZeroMemory(s+tlen, (*size-tlen)*sizeof(TCHAR));
+       }
+       if( strcmp(ap, "\r\n")==0 ) {
+               _tcscat(s, TEXT("\r\n"));
+       } else {
+               NH_A2W(ap, s+tlen, strlen(ap));
+               s[tnewlen] = 0;
+       }
+       return s;
+}
+/*----------------------------------------------------------------*/
+void mswin_render_text(PNHTextBuffer pb, HWND edit_control)
+{
+       RECT rt_client;      /* boundaries of the client area of the edit control */
+       SIZE size_text;      /* size of the edit control */
+       RECT rt_text;        /* calculated text rectangle for the visible line */
+       char buf[BUFSZ];     /* buffer for the visible line */
+       TCHAR tbuf[BUFSZ];   /* temp buffer for DrawText */
+       TCHAR* pText = NULL; /* resulting text (formatted) */
+       int pTextSize = 0;   /* resulting text size */
+       char* p_cur = NULL;  /* current position in the NHTextBuffer->text_buffer_line->text */
+       char* p_buf_cur = NULL; /* current position in the visible line buffer */
+       int i;
+       HDC hdcEdit;             /* device context for the edit control */
+       HFONT hFont, hOldFont; /* edit control font */
+
+       GetClientRect(edit_control, &rt_client );
+       size_text.cx = rt_client.right - rt_client.left;
+       size_text.cy = rt_client.bottom - rt_client.top;
+       size_text.cx -= GetSystemMetrics(SM_CXVSCROLL); /* add a slight right margin - the text looks better that way */
+       hdcEdit = GetDC(edit_control);
+       hFont = (HFONT)SendMessage(edit_control, WM_GETFONT, 0, 0);
+       if( hFont ) hOldFont = SelectObject(hdcEdit, hFont);
+
+       /* loop through each line (outer loop) and wrap it around (inner loop) */
+       ZeroMemory(buf, sizeof(buf));
+       p_buf_cur = buf;
+       for( i=0; i<pb->n_used; i++ ) {
+               if( pb->b_wrap_text ) {
+                       p_cur = NHTextLine(pb,i).text;
+
+                       /* insert an line break for the empty string */
+                       if( !NHTextLine(pb,i).text[0] ) {
+                               pText = nh_append(pText, &pTextSize, "\r\n");
+                               continue;
+                       }
+
+                       /* add margin to the "formatted" line of text */
+                       if( NHTextLine(pb,i).formatted ) {
+                               strcpy(buf, "   ");
+                               p_buf_cur += 3;
+                       }
+
+                       /* scroll thourgh the current line of text and wrap it
+                          so it fits to width of the edit control */
+                       while( *p_cur ) {
+                               char *p_word_pos = p_buf_cur;
+
+                               /* copy one word into the buffer */
+                               while( *p_cur && isspace(*p_cur) ) 
+                                       if( p_buf_cur!=buf ) *p_buf_cur++ = *p_cur++;
+                                       else p_cur++;
+
+                               while( *p_cur && !isspace(*p_cur) ) 
+                                       *p_buf_cur++ = *p_cur++;
+
+                               /* check if it fits */
+                               SetRect( &rt_text, 0, 0, size_text.cx, size_text.cy );
+                               DrawText(hdcEdit, NH_A2W(buf, tbuf, p_buf_cur-buf), p_buf_cur-buf, &rt_text, DT_CALCRECT | DT_LEFT | DT_SINGLELINE | DT_NOCLIP);
+                               if( (rt_text.right - rt_text.left)>=size_text.cx ) {
+                                       /* Backtrack. 
+                                          Only backtrack if the last word caused the overflow -
+                                          do not backtrack if the entire current line does not fit the visible area.
+                                          Otherwise it is a infinite loop.
+                                       */
+                                       if( p_word_pos>buf ) {
+                                               p_cur -= (p_buf_cur-p_word_pos);
+                                               p_buf_cur = p_word_pos;
+                                       }
+                                       *p_buf_cur = 0;  /* break the line */
+
+                                       /* append the calculated line to the text buffer */
+                                       pText = nh_append(pText, &pTextSize, buf);
+                                       pText = nh_append(pText, &pTextSize, "\r\n");
+                                       ZeroMemory(buf, sizeof(buf));
+                                       p_buf_cur = buf;
+                               }
+                       }
+
+                       /* always break the line at the end of the buffer text */
+                       if( p_buf_cur != buf ) {
+                               /* flush the current buffrer */
+                               *p_buf_cur = 0;  /* break the line */
+                               pText = nh_append(pText, &pTextSize, buf);
+                               pText = nh_append(pText, &pTextSize, "\r\n");
+                               ZeroMemory(buf, sizeof(buf));
+                               p_buf_cur = buf;
+                       }
+               } else { /* do not wrap text */
+                       int j;
+                       for( j=0; j<NHTextLine(pb,i).beg_padding; j++ ) 
+                               pText = nh_append(pText, &pTextSize, " ");
+                       pText = nh_append(pText, &pTextSize, NHTextLine(pb,i).text);
+                       pText = nh_append(pText, &pTextSize, "\r\n");
+               }
+       }
+       
+       /* cleanup */
+       if( hFont ) SelectObject(hdcEdit, hOldFont);
+       ReleaseDC(edit_control, hdcEdit);
+
+       /* update edit control text */
+       if( pText ) {
+               SendMessage(edit_control, EM_FMTLINES, 1, 0 );
+               SetWindowText(edit_control, pText);
+               free(pText);
+       }
+}
+/*----------------------------------------------------------------*/
+
diff --git a/sys/wince/mhtxtbuf.h b/sys/wince/mhtxtbuf.h
new file mode 100644 (file)
index 0000000..db41451
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINTextBuffer_h
+#define MSWINTextBuffer_h
+
+#include "winMS.h"
+
+typedef struct mswin_nethack_text_buffer* PNHTextBuffer;
+PNHTextBuffer mswin_init_text_buffer(BOOL wrap_text);
+void mswin_free_text_buffer(PNHTextBuffer pb);
+void mswin_add_text(PNHTextBuffer pb, int attr, const char* text);
+void mswin_render_text(PNHTextBuffer pb, HWND edit_control);
+
+#endif /* MSWINTextBuffer_h */
diff --git a/sys/wince/mswproc.c b/sys/wince/mswproc.c
new file mode 100644 (file)
index 0000000..d08e081
--- /dev/null
@@ -0,0 +1,1966 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file implements the interface between the window port specific
+ * code in the mswin port and the rest of the nethack game engine. 
+*/
+
+#include "hack.h"
+#include "dlb.h"
+#include "winMS.h"
+#include "mhmap.h"
+#include "mhstatus.h"
+#include "mhtext.h"
+#include "mhmsgwnd.h"
+#include "mhmenu.h"
+#include "mhmsg.h"
+#include "mhcmd.h"
+#include "mhinput.h"
+#include "mhaskyn.h"
+#include "mhdlg.h"
+#include "mhrip.h"
+#include "mhmain.h"
+#include "mhfont.h"
+#include "mhcolor.h"
+
+#define LLEN 128
+
+#ifdef _DEBUG
+extern void logDebug(const char *fmt, ...);
+#else
+void logDebug(const char *fmt, ...) { }
+#endif
+
+static void mswin_main_loop();
+static BOOL initMapTiles(void);
+static void prompt_for_player_selection(void);
+
+/* Interface definition, for windows.c */
+struct window_procs mswin_procs = {
+    "MSWIN",
+    WC_COLOR|WC_HILITE_PET|WC_ALIGN_MESSAGE|WC_ALIGN_STATUS|
+       WC_INVERSE|WC_SCROLL_MARGIN|WC_MAP_MODE|
+       WC_FONT_MESSAGE|WC_FONT_STATUS|WC_FONT_MENU|WC_FONT_TEXT|WC_FONT_MAP|
+       WC_FONTSIZ_MESSAGE|WC_FONTSIZ_STATUS|WC_FONTSIZ_MENU|WC_FONTSIZ_TEXT|
+       WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE|WC_VARY_MSGCOUNT|
+       WC_WINDOWCOLORS|WC_PLAYER_SELECTION,
+    WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT,
+    mswin_init_nhwindows,
+    mswin_player_selection,
+    mswin_askname,
+    mswin_get_nh_event,
+    mswin_exit_nhwindows,
+    mswin_suspend_nhwindows,
+    mswin_resume_nhwindows,
+    mswin_create_nhwindow,
+    mswin_clear_nhwindow,
+    mswin_display_nhwindow,
+    mswin_destroy_nhwindow,
+    mswin_curs,
+    mswin_putstr,
+    mswin_display_file,
+    mswin_start_menu,
+    mswin_add_menu,
+    mswin_end_menu,
+    mswin_select_menu,
+    genl_message_menu,         /* no need for X-specific handling */
+    mswin_update_inventory,
+    mswin_mark_synch,
+    mswin_wait_synch,
+#ifdef CLIPPING
+    mswin_cliparound,
+#endif
+#ifdef POSITIONBAR
+    donull,
+#endif
+    mswin_print_glyph,
+    mswin_raw_print,
+    mswin_raw_print_bold,
+    mswin_nhgetch,
+    mswin_nh_poskey,
+    mswin_nhbell,
+    mswin_doprev_message,
+    mswin_yn_function,
+    mswin_getlin,
+    mswin_get_ext_cmd,
+    mswin_number_pad,
+    mswin_delay_output,
+#ifdef CHANGE_COLOR    /* only a Mac option currently */
+       mswin,
+       mswin_change_background,
+#endif
+    /* other defs that really should go away (they're tty specific) */
+    mswin_start_screen,
+    mswin_end_screen,
+    mswin_outrip,
+    mswin_preference_update,
+};
+
+/*  
+init_nhwindows(int* argcp, char** argv)
+                -- Initialize the windows used by NetHack.  This can also
+                   create the standard windows listed at the top, but does
+                   not display them.
+                -- Any commandline arguments relevant to the windowport
+                   should be interpreted, and *argcp and *argv should
+                   be changed to remove those arguments.
+                -- When the message window is created, the variable
+                   iflags.window_inited needs to be set to TRUE.  Otherwise
+                   all plines() will be done via raw_print().
+                ** Why not have init_nhwindows() create all of the "standard"
+                ** windows?  Or at least all but WIN_INFO?      -dean
+*/
+void mswin_init_nhwindows(int* argc, char** argv)
+{
+       HWND hWnd;
+       logDebug("mswin_init_nhwindows()\n");
+
+#ifdef _DEBUG
+       {
+               /* truncate trace file */
+               FILE *dfp = fopen("nhtrace.log", "w");
+               fclose(dfp);
+       }
+#endif
+
+       /* intialize input subsystem */
+    mswin_nh_input_init();
+
+       /* read registry settings */
+    mswin_read_reg();
+
+       /* set it to WIN_ERR so we can detect attempts to
+          use this ID before it is inialized */
+       WIN_MAP = WIN_ERR;
+
+    /* check default values */
+       if( iflags.wc_fontsiz_status<NHFONT_SIZE_MIN || 
+               iflags.wc_fontsiz_status>NHFONT_SIZE_MAX )
+               iflags.wc_fontsiz_status = NHFONT_STATUS_DEFAULT_SIZE;
+
+       if( iflags.wc_fontsiz_message<NHFONT_SIZE_MIN || 
+               iflags.wc_fontsiz_message>NHFONT_SIZE_MAX )
+               iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
+
+       if( iflags.wc_fontsiz_text<NHFONT_SIZE_MIN || 
+               iflags.wc_fontsiz_text>NHFONT_SIZE_MAX )
+               iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
+
+       if( iflags.wc_fontsiz_menu<NHFONT_SIZE_MIN || 
+               iflags.wc_fontsiz_menu>NHFONT_SIZE_MAX )
+               iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
+
+       if( iflags.wc_align_message==0 ) iflags.wc_align_message = ALIGN_BOTTOM;
+       if( iflags.wc_align_status==0 ) iflags.wc_align_status = ALIGN_TOP;
+       if( iflags.wc_scroll_margin==0 ) iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN;
+       if( iflags.wc_tile_width==0 ) iflags.wc_tile_width = TILE_X;
+       if( iflags.wc_tile_height==0 ) iflags.wc_tile_height = TILE_Y;
+
+       if( iflags.wc_vary_msgcount==0 ) iflags.wc_vary_msgcount = 3;
+
+       /* force tabs in menus */
+       iflags.menu_tab_sep = 1;
+
+       /* force toptenwin to be true.  toptenwin is the option that decides whether to
+        * write output to a window or stdout.  stdout doesn't make sense on Windows
+        * non-console applications
+        */
+       flags.toptenwin = 1;
+       set_option_mod_status("toptenwin", SET_IN_FILE);
+
+       /* initialize map tiles bitmap */
+       initMapTiles();
+
+       /* set tile-related options to readonly */
+       set_wc_option_mod_status(
+          WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE,
+          DISP_IN_GAME);
+
+       /* init color table */
+       mswin_init_color_table();
+
+       /* set font-related options to change in the game */
+       set_wc_option_mod_status(
+               WC_HILITE_PET |
+               WC_ALIGN_MESSAGE | 
+               WC_ALIGN_STATUS |
+               WC_SCROLL_MARGIN | 
+               WC_MAP_MODE |
+               WC_FONT_MESSAGE |
+               WC_FONT_STATUS |
+               WC_FONT_MENU |
+               WC_FONT_TEXT |
+               WC_FONTSIZ_MESSAGE | 
+               WC_FONTSIZ_STATUS | 
+               WC_FONTSIZ_MENU | 
+               WC_FONTSIZ_TEXT |
+               WC_VARY_MSGCOUNT,
+               SET_IN_GAME 
+       );
+
+       /* WC2 options */
+       set_wc2_option_mod_status(
+               WC2_FULLSCREEN|
+               WC2_SOFTKEYBOARD,
+               SET_IN_FILE
+       );
+       GetNHApp()->bFullScreen = iflags.wc2_fullscreen;
+       GetNHApp()->bUseSIP = iflags.wc2_softkeyboard;
+       
+       set_wc2_option_mod_status(
+               WC2_WRAPTEXT,
+               SET_IN_GAME
+       );
+       GetNHApp()->bWrapText = iflags.wc2_wraptext;
+
+       /* create the main nethack window */
+       hWnd = mswin_init_main_window();
+       if (!hWnd) panic( "Cannot create the main window." );
+       ShowWindow(hWnd, GetNHApp()->nCmdShow);
+       UpdateWindow(hWnd);
+       GetNHApp()->hMainWnd = hWnd;
+
+       /* set Full screen if requested */
+       mswin_set_fullscreen(GetNHApp()->bFullScreen);
+
+       /* let nethack code know that the window subsystem is ready */
+       iflags.window_inited = TRUE;
+}
+
+
+/* Do a window-port specific player type selection. If player_selection()
+   offers a Quit option, it is its responsibility to clean up and terminate
+   the process. You need to fill in pl_character[0].
+*/
+void mswin_player_selection(void)
+{
+       logDebug("mswin_player_selection()\n");
+
+#if defined(WIN_CE_SMARTPHONE)
+       /* SmartPhone does not supprt combo-boxes therefor we cannot
+          use dialog for player selection */
+    prompt_for_player_selection();
+#else
+       if (iflags.wc_player_selection == VIA_DIALOG) {
+               int nRole;
+
+           /* pick player type randomly (use pre-selected role/race/gender/alignment) */
+           if( flags.randomall ) {
+               if (flags.initrole < 0) {
+                       flags.initrole = pick_role(flags.initrace, flags.initgend,
+                                                       flags.initalign, PICK_RANDOM);
+                       if (flags.initrole < 0) {
+                               raw_print("Incompatible role!");
+                               flags.initrole = randrole();
+                       }
+               }
+
+               if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
+                       flags.initrace = pick_race(flags.initrole, flags.initgend,
+                                                               flags.initalign, PICK_RANDOM);
+                       if (flags.initrace < 0) {
+                               raw_print("Incompatible race!");
+                               flags.initrace = randrace(flags.initrole);
+                       }
+               }
+
+               if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
+                                               flags.initgend)) {
+                       flags.initgend = pick_gend(flags.initrole, flags.initrace,
+                                                       flags.initalign, PICK_RANDOM);
+                       if (flags.initgend < 0) {
+                               raw_print("Incompatible gender!");
+                               flags.initgend = randgend(flags.initrole, flags.initrace);
+                       }
+               }
+
+               if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
+                                                               flags.initalign)) {
+                       flags.initalign = pick_align(flags.initrole, flags.initrace,
+                                                               flags.initgend, PICK_RANDOM);
+                       if (flags.initalign < 0) {
+                               raw_print("Incompatible alignment!");
+                               flags.initalign = randalign(flags.initrole, flags.initrace);
+                       }
+               }
+           } else {
+               /* select a role */
+               if( mswin_player_selection_window( &nRole ) == IDCANCEL ) {
+                       bail(0);
+               }
+           }
+       } else { /* iflags.wc_player_selection == VIA_PROMPTS */
+           prompt_for_player_selection();
+       }
+#endif /* defined(WIN_CE_SMARTPHONE) */
+}
+
+void prompt_for_player_selection(void)
+{
+       int i, k, n;
+       char pick4u = 'n', thisch, lastch = 0;
+       char pbuf[QBUFSZ], plbuf[QBUFSZ];
+       winid win;
+       anything any;
+       menu_item *selected = 0;
+       int box_result;
+       TCHAR wbuf[BUFSZ];
+
+       logDebug("prompt_for_player_selection()\n");
+
+       /* prevent an unnecessary prompt */
+       rigid_role_checks();
+
+       /* Should we randomly pick for the player? */
+       if (!flags.randomall &&
+           (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE ||
+            flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {
+           /* int echoline; */
+           char *prompt = build_plselection_prompt(pbuf, QBUFSZ, flags.initrole,
+                               flags.initrace, flags.initgend, flags.initalign);
+
+           /* tty_putstr(BASE_WINDOW, 0, ""); */
+           /* echoline = wins[BASE_WINDOW]->cury; */
+        box_result = MessageBox(NULL, 
+                                       NH_A2W(prompt, wbuf, BUFSZ), 
+                                       TEXT("NetHack for Windows"),
+#if defined(WIN_CE_SMARTPHONE)
+                                       MB_YESNO | MB_DEFBUTTON1 
+#else                                  
+                                       MB_YESNOCANCEL | MB_DEFBUTTON1 
+#endif
+                                       );
+
+        pick4u = (box_result == IDYES) ? 'y' : (box_result == IDNO) ? 'n' : '\033';
+           /* tty_putstr(BASE_WINDOW, 0, prompt); */
+           do {
+               /* pick4u = lowc(readchar()); */
+               if (index(quitchars, pick4u)) pick4u = 'y';
+           } while(!index(ynqchars, pick4u));
+           if ((int)strlen(prompt) + 1 < CO) {
+               /* Echo choice and move back down line */
+               /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline, pick4u); */
+               /* tty_putstr(BASE_WINDOW, 0, ""); */
+           } else
+               /* Otherwise it's hard to tell where to echo, and things are
+                * wrapping a bit messily anyway, so (try to) make sure the next
+                * question shows up well and doesn't get wrapped at the
+                * bottom of the window.
+                */
+               /* tty_clear_nhwindow(BASE_WINDOW) */ ;
+           
+           if (pick4u != 'y' && pick4u != 'n') {
+give_up:       /* Quit */
+               if (selected) free((genericptr_t) selected);
+               bail((char *)0);
+               /*NOTREACHED*/
+               return;
+           }
+       }
+
+       (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+
+       /* Select a role, if necessary */
+       /* we'll try to be compatible with pre-selected race/gender/alignment,
+        * but may not succeed */
+       if (flags.initrole < 0) {
+           char rolenamebuf[QBUFSZ];
+           /* Process the choice */
+           if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) {
+               /* Pick a random role */
+               flags.initrole = pick_role(flags.initrace, flags.initgend,
+                                               flags.initalign, PICK_RANDOM);
+               if (flags.initrole < 0) {
+                   /* tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); */
+                   flags.initrole = randrole();
+               }
+           } else {
+               /* tty_clear_nhwindow(BASE_WINDOW); */
+               /* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */
+               /* Prompt for a role */
+               win = create_nhwindow(NHW_MENU);
+               start_menu(win);
+               any.a_void = 0;         /* zero out all bits */
+               for (i = 0; roles[i].name.m; i++) {
+                   if (ok_role(i, flags.initrace, flags.initgend,
+                                                       flags.initalign)) {
+                       any.a_int = i+1;        /* must be non-zero */
+                       thisch = lowc(roles[i].name.m[0]);
+                       if (thisch == lastch) thisch = highc(thisch);
+                       if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) {
+                               if (flags.initgend == 1  && roles[i].name.f)
+                                       Strcpy(rolenamebuf, roles[i].name.f);
+                               else
+                                       Strcpy(rolenamebuf, roles[i].name.m);
+                       } else {
+                               if (roles[i].name.f) {
+                                       Strcpy(rolenamebuf, roles[i].name.m);
+                                       Strcat(rolenamebuf, "/");
+                                       Strcat(rolenamebuf, roles[i].name.f);
+                               } else 
+                                       Strcpy(rolenamebuf, roles[i].name.m);
+                       }       
+                       add_menu(win, NO_GLYPH, &any, thisch,
+                           0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED);
+                       lastch = thisch;
+                   }
+               }
+               any.a_int = pick_role(flags.initrace, flags.initgend,
+                                   flags.initalign, PICK_RANDOM)+1;
+               if (any.a_int == 0)     /* must be non-zero */
+                   any.a_int = randrole()+1;
+               add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                               "Random", MENU_UNSELECTED);
+               any.a_int = i+1;        /* must be non-zero */
+               add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                               "Quit", MENU_UNSELECTED);
+               Sprintf(pbuf, "Pick a role for your %s", plbuf);
+               end_menu(win, pbuf);
+               n = select_menu(win, PICK_ONE, &selected);
+               destroy_nhwindow(win);
+
+               /* Process the choice */
+               if (n != 1 || selected[0].item.a_int == any.a_int)
+                   goto give_up;               /* Selected quit */
+
+               flags.initrole = selected[0].item.a_int - 1;
+               free((genericptr_t) selected),  selected = 0;
+           }
+           (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+       }
+       
+       /* Select a race, if necessary */
+       /* force compatibility with role, try for compatibility with
+        * pre-selected gender/alignment */
+       if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
+           /* pre-selected race not valid */
+           if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) {
+               flags.initrace = pick_race(flags.initrole, flags.initgend,
+                                                       flags.initalign, PICK_RANDOM);
+               if (flags.initrace < 0) {
+                   /* tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); */
+                   flags.initrace = randrace(flags.initrole);
+               }
+           } else {    /* pick4u == 'n' */
+               /* Count the number of valid races */
+               n = 0;  /* number valid */
+               k = 0;  /* valid race */
+               for (i = 0; races[i].noun; i++) {
+                   if (ok_race(flags.initrole, i, flags.initgend,
+                                                       flags.initalign)) {
+                       n++;
+                       k = i;
+                   }
+               }
+               if (n == 0) {
+                   for (i = 0; races[i].noun; i++) {
+                       if (validrace(flags.initrole, i)) {
+                           n++;
+                           k = i;
+                       }
+                   }
+               }
+
+               /* Permit the user to pick, if there is more than one */
+               if (n > 1) {
+                   /* tty_clear_nhwindow(BASE_WINDOW); */
+                   /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */
+                   win = create_nhwindow(NHW_MENU);
+                   start_menu(win);
+                   any.a_void = 0;         /* zero out all bits */
+                   for (i = 0; races[i].noun; i++)
+                       if (ok_race(flags.initrole, i, flags.initgend,
+                                                       flags.initalign)) {
+                           any.a_int = i+1;    /* must be non-zero */
+                           add_menu(win, NO_GLYPH, &any, races[i].noun[0],
+                               0, ATR_NONE, races[i].noun, MENU_UNSELECTED);
+                       }
+                   any.a_int = pick_race(flags.initrole, flags.initgend,
+                                       flags.initalign, PICK_RANDOM)+1;
+                   if (any.a_int == 0) /* must be non-zero */
+                       any.a_int = randrace(flags.initrole)+1;
+                   add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                   "Random", MENU_UNSELECTED);
+                   any.a_int = i+1;    /* must be non-zero */
+                   add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                   "Quit", MENU_UNSELECTED);
+                   Sprintf(pbuf, "Pick the race of your %s", plbuf);
+                   end_menu(win, pbuf);
+                   n = select_menu(win, PICK_ONE, &selected);
+                   destroy_nhwindow(win);
+                   if (n != 1 || selected[0].item.a_int == any.a_int)
+                       goto give_up;           /* Selected quit */
+
+                   k = selected[0].item.a_int - 1;
+                   free((genericptr_t) selected),      selected = 0;
+               }
+               flags.initrace = k;
+           }
+           (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+       }
+
+       /* Select a gender, if necessary */
+       /* force compatibility with role/race, try for compatibility with
+        * pre-selected alignment */
+       if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
+                                               flags.initgend)) {
+           /* pre-selected gender not valid */
+           if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) {
+               flags.initgend = pick_gend(flags.initrole, flags.initrace,
+                                               flags.initalign, PICK_RANDOM);
+               if (flags.initgend < 0) {
+                   /* tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */
+                   flags.initgend = randgend(flags.initrole, flags.initrace);
+               }
+           } else {    /* pick4u == 'n' */
+               /* Count the number of valid genders */
+               n = 0;  /* number valid */
+               k = 0;  /* valid gender */
+               for (i = 0; i < ROLE_GENDERS; i++) {
+                   if (ok_gend(flags.initrole, flags.initrace, i,
+                                                       flags.initalign)) {
+                       n++;
+                       k = i;
+                   }
+               }
+               if (n == 0) {
+                   for (i = 0; i < ROLE_GENDERS; i++) {
+                       if (validgend(flags.initrole, flags.initrace, i)) {
+                           n++;
+                           k = i;
+                       }
+                   }
+               }
+
+               /* Permit the user to pick, if there is more than one */
+               if (n > 1) {
+                   /* tty_clear_nhwindow(BASE_WINDOW); */
+                   /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */
+                   win = create_nhwindow(NHW_MENU);
+                   start_menu(win);
+                   any.a_void = 0;         /* zero out all bits */
+                   for (i = 0; i < ROLE_GENDERS; i++)
+                       if (ok_gend(flags.initrole, flags.initrace, i,
+                                                           flags.initalign)) {
+                           any.a_int = i+1;
+                           add_menu(win, NO_GLYPH, &any, genders[i].adj[0],
+                               0, ATR_NONE, genders[i].adj, MENU_UNSELECTED);
+                       }
+                   any.a_int = pick_gend(flags.initrole, flags.initrace,
+                                           flags.initalign, PICK_RANDOM)+1;
+                   if (any.a_int == 0) /* must be non-zero */
+                       any.a_int = randgend(flags.initrole, flags.initrace)+1;
+                   add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                   "Random", MENU_UNSELECTED);
+                   any.a_int = i+1;    /* must be non-zero */
+                   add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                   "Quit", MENU_UNSELECTED);
+                   Sprintf(pbuf, "Pick the gender of your %s", plbuf);
+                   end_menu(win, pbuf);
+                   n = select_menu(win, PICK_ONE, &selected);
+                   destroy_nhwindow(win);
+                   if (n != 1 || selected[0].item.a_int == any.a_int)
+                       goto give_up;           /* Selected quit */
+
+                   k = selected[0].item.a_int - 1;
+                   free((genericptr_t) selected),      selected = 0;
+               }
+               flags.initgend = k;
+           }
+           (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+       }
+
+       /* Select an alignment, if necessary */
+       /* force compatibility with role/race/gender */
+       if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
+                                                       flags.initalign)) {
+           /* pre-selected alignment not valid */
+           if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) {
+               flags.initalign = pick_align(flags.initrole, flags.initrace,
+                                                       flags.initgend, PICK_RANDOM);
+               if (flags.initalign < 0) {
+                   /* tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */
+                   flags.initalign = randalign(flags.initrole, flags.initrace);
+               }
+           } else {    /* pick4u == 'n' */
+               /* Count the number of valid alignments */
+               n = 0;  /* number valid */
+               k = 0;  /* valid alignment */
+               for (i = 0; i < ROLE_ALIGNS; i++) {
+                   if (ok_align(flags.initrole, flags.initrace, flags.initgend,
+                                                       i)) {
+                       n++;
+                       k = i;
+                   }
+               }
+               if (n == 0) {
+                   for (i = 0; i < ROLE_ALIGNS; i++) {
+                       if (validalign(flags.initrole, flags.initrace, i)) {
+                           n++;
+                           k = i;
+                       }
+                   }
+               }
+
+               /* Permit the user to pick, if there is more than one */
+               if (n > 1) {
+                   /* tty_clear_nhwindow(BASE_WINDOW); */
+                   /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */
+                   win = create_nhwindow(NHW_MENU);
+                   start_menu(win);
+                   any.a_void = 0;         /* zero out all bits */
+                   for (i = 0; i < ROLE_ALIGNS; i++)
+                       if (ok_align(flags.initrole, flags.initrace,
+                                                       flags.initgend, i)) {
+                           any.a_int = i+1;
+                           add_menu(win, NO_GLYPH, &any, aligns[i].adj[0],
+                                0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
+                       }
+                   any.a_int = pick_align(flags.initrole, flags.initrace,
+                                           flags.initgend, PICK_RANDOM)+1;
+                   if (any.a_int == 0) /* must be non-zero */
+                       any.a_int = randalign(flags.initrole, flags.initrace)+1;
+                   add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                   "Random", MENU_UNSELECTED);
+                   any.a_int = i+1;    /* must be non-zero */
+                   add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                   "Quit", MENU_UNSELECTED);
+                   Sprintf(pbuf, "Pick the alignment of your %s", plbuf);
+                   end_menu(win, pbuf);
+                   n = select_menu(win, PICK_ONE, &selected);
+                   destroy_nhwindow(win);
+                   if (n != 1 || selected[0].item.a_int == any.a_int)
+                       goto give_up;           /* Selected quit */
+
+                   k = selected[0].item.a_int - 1;
+                   free((genericptr_t) selected),      selected = 0;
+               }
+               flags.initalign = k;
+           }
+       }
+       /* Success! */
+       /* tty_display_nhwindow(BASE_WINDOW, FALSE); */
+}
+
+/* Ask the user for a player name. */
+void mswin_askname(void)
+{
+       logDebug("mswin_askname()\n");
+
+       if( mswin_getlin_window("who are you?", plname, PL_NSIZ)==IDCANCEL ) {
+               bail("bye-bye");
+               /* not reached */
+       }
+}
+
+
+/* Does window event processing (e.g. exposure events).
+   A noop for the tty and X window-ports.
+*/
+void mswin_get_nh_event(void)
+{
+       logDebug("mswin_get_nh_event()\n");
+       return;
+}
+
+/* Exits the window system.  This should dismiss all windows,
+   except the "window" used for raw_print().  str is printed if possible.
+*/
+void mswin_exit_nhwindows(const char *str)
+{
+       logDebug("mswin_exit_nhwindows(%s)\n", str);
+
+    /* Write Window settings to the registry */
+    mswin_write_reg();
+
+       // Don't do any of this (?) - exit_nhwindows does not terminate 
+       // the application
+       // DestroyWindow(GetNHApp()->hMainWnd);
+       // terminate(EXIT_SUCCESS);
+}
+
+/* Prepare the window to be suspended. */
+void mswin_suspend_nhwindows(const char *str)
+{
+       logDebug("mswin_suspend_nhwindows(%s)\n", str);
+       return;
+}
+
+
+/* Restore the windows after being suspended. */
+void mswin_resume_nhwindows()
+{
+       logDebug("mswin_resume_nhwindows()\n");
+       return;
+}
+
+/*  Create a window of type "type" which can be 
+        NHW_MESSAGE     (top line)
+        NHW_STATUS      (bottom lines)
+        NHW_MAP         (main dungeon)
+        NHW_MENU        (inventory or other "corner" windows)
+        NHW_TEXT        (help/text, full screen paged window)
+*/
+winid 
+mswin_create_nhwindow(int type)
+{
+       winid i = 0;
+       MSNHMsgAddWnd data;
+
+       logDebug("mswin_create_nhwindow(%d)\n", type);
+
+       /* Return the next available winid
+        */
+
+       for (i=1; i<MAXWINDOWS; i++)
+         if (GetNHApp()->windowlist[i].win == NULL &&
+                 !GetNHApp()->windowlist[i].dead)
+                 break;
+       if (i == MAXWINDOWS)
+         panic ("ERROR:  No windows available...\n");
+
+    switch (type) {
+    case NHW_MAP:
+       {
+               GetNHApp()->windowlist[i].win = mswin_init_map_window();
+               GetNHApp()->windowlist[i].type = type;
+               GetNHApp()->windowlist[i].dead = 0;
+               break;
+       }
+    case NHW_MESSAGE:
+       {
+               GetNHApp()->windowlist[i].win = mswin_init_message_window();
+               GetNHApp()->windowlist[i].type = type;
+               GetNHApp()->windowlist[i].dead = 0;
+               break;
+       }
+    case NHW_STATUS:
+       {
+               GetNHApp()->windowlist[i].win = mswin_init_status_window();
+               GetNHApp()->windowlist[i].type = type;
+               GetNHApp()->windowlist[i].dead = 0;
+               break;
+       }    
+    case NHW_MENU:
+       {
+               GetNHApp()->windowlist[i].win = NULL; //will create later
+               GetNHApp()->windowlist[i].type = type;
+               GetNHApp()->windowlist[i].dead = 1;
+               break;
+       } 
+    case NHW_TEXT:
+       {
+               GetNHApp()->windowlist[i].win = mswin_init_text_window();
+               GetNHApp()->windowlist[i].type = type;
+               GetNHApp()->windowlist[i].dead = 0;
+               break;
+       }
+       }
+
+       ZeroMemory(&data, sizeof(data) );
+       data.wid = i;
+       SendMessage( GetNHApp()->hMainWnd, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ADDWND, (LPARAM)&data );
+       return i;
+}
+
+/* Clear the given window, when asked to. */
+void mswin_clear_nhwindow(winid wid)
+{
+       logDebug("mswin_clear_nhwindow(%d)\n", wid);
+
+    if ((wid >= 0) && 
+        (wid < MAXWINDOWS) &&
+        (GetNHApp()->windowlist[wid].win != NULL))
+    {
+#ifdef REINCARNATION
+               if( GetNHApp()->windowlist[wid].type == NHW_MAP ) {
+                       if( Is_rogue_level(&u.uz) ) 
+                               mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), ROGUE_LEVEL_MAP_MODE);
+                       else 
+                               mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), iflags.wc_map_mode);
+               }
+#endif
+
+         SendMessage( 
+                        GetNHApp()->windowlist[wid].win, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CLEAR_WINDOW, (LPARAM)NULL );
+    }
+}
+
+/* -- Display the window on the screen.  If there is data
+                   pending for output in that window, it should be sent.
+                   If blocking is TRUE, display_nhwindow() will not
+                   return until the data has been displayed on the screen,
+                   and acknowledged by the user where appropriate.
+                -- All calls are blocking in the tty window-port.
+                -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
+                   --more--, if necessary, in the tty window-port.
+*/
+void mswin_display_nhwindow(winid wid, BOOLEAN_P block)
+{
+       logDebug("mswin_display_nhwindow(%d, %d)\n", wid, block);
+       if (GetNHApp()->windowlist[wid].win != NULL)
+       {
+               if (GetNHApp()->windowlist[wid].type == NHW_MENU) {
+                       MENU_ITEM_P* p;
+                       mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, PICK_NONE, &p);
+               } if (GetNHApp()->windowlist[wid].type == NHW_TEXT) {
+                       mswin_display_text_window(GetNHApp()->windowlist[wid].win);
+               } if (GetNHApp()->windowlist[wid].type == NHW_RIP) {
+                       mswin_display_RIP_window(GetNHApp()->windowlist[wid].win);
+               } else {
+                       if( !block ) {
+                               UpdateWindow(GetNHApp()->windowlist[wid].win);
+                       } else {
+                               if ( GetNHApp()->windowlist[wid].type == NHW_MAP ) {
+                                       (void) mswin_nhgetch();
+                               }
+                       }
+               }
+               SetFocus(GetNHApp()->hMainWnd);
+       }
+}
+
+
+HWND mswin_hwnd_from_winid(winid wid)
+{
+       if( wid>=0 && wid<MAXWINDOWS) {
+               return GetNHApp()->windowlist[wid].win;
+       } else {
+               return NULL;
+       }
+}
+
+winid mswin_winid_from_handle(HWND hWnd)
+{
+       winid i = 0;
+
+       for (i=1; i<MAXWINDOWS; i++)
+         if (GetNHApp()->windowlist[i].win == hWnd)
+                 return i;
+       return -1;
+}
+
+winid mswin_winid_from_type(int type)
+{
+       winid i = 0;
+
+       for (i=1; i<MAXWINDOWS; i++)
+         if (GetNHApp()->windowlist[i].type == type)
+                 return i;
+       return -1;
+}
+
+void mswin_window_mark_dead(winid wid)
+{
+       if( wid>=0 && wid<MAXWINDOWS) {
+               GetNHApp()->windowlist[wid].win = NULL;
+               GetNHApp()->windowlist[wid].dead = 1;
+       }
+}
+
+/* Destroy will dismiss the window if the window has not 
+ * already been dismissed.
+*/
+void mswin_destroy_nhwindow(winid wid)
+{
+       logDebug("mswin_destroy_nhwindow(%d)\n", wid);
+
+    if ((GetNHApp()->windowlist[wid].type == NHW_MAP) || 
+        (GetNHApp()->windowlist[wid].type == NHW_MESSAGE) || 
+        (GetNHApp()->windowlist[wid].type == NHW_STATUS)) {
+               /* main windows is going to take care of those */
+               return;
+    }
+
+    if (wid != -1) {
+               if( !GetNHApp()->windowlist[wid].dead &&
+                       GetNHApp()->windowlist[wid].win != NULL ) 
+                       DestroyWindow(GetNHApp()->windowlist[wid].win);
+               GetNHApp()->windowlist[wid].win = NULL;
+               GetNHApp()->windowlist[wid].type = 0;
+               GetNHApp()->windowlist[wid].dead = 0;
+       }
+}
+
+/* Next output to window will start at (x,y), also moves
+ displayable cursor to (x,y).  For backward compatibility,
+ 1 <= x < cols, 0 <= y < rows, where cols and rows are
+ the size of window.
+*/
+void mswin_curs(winid wid, int x, int y)
+{
+       logDebug("mswin_curs(%d, %d, %d)\n", wid, x, y);
+
+    if ((wid >= 0) && 
+        (wid < MAXWINDOWS) &&
+        (GetNHApp()->windowlist[wid].win != NULL))
+    {
+                MSNHMsgCursor data;
+                data.x = x;
+                data.y = y;
+                SendMessage( 
+                        GetNHApp()->windowlist[wid].win, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CURSOR, (LPARAM)&data );
+    }
+}
+
+/*
+putstr(window, attr, str)
+                -- Print str on the window with the given attribute.  Only
+                   printable ASCII characters (040-0126) must be supported.
+                   Multiple putstr()s are output on separate lines.
+Attributes
+                   can be one of
+                        ATR_NONE (or 0)
+                        ATR_ULINE
+                        ATR_BOLD
+                        ATR_BLINK
+                        ATR_INVERSE
+                   If a window-port does not support all of these, it may map
+                   unsupported attributes to a supported one (e.g. map them
+                   all to ATR_INVERSE).  putstr() may compress spaces out of
+                   str, break str, or truncate str, if necessary for the
+                   display.  Where putstr() breaks a line, it has to clear
+                   to end-of-line.
+                -- putstr should be implemented such that if two putstr()s
+                   are done consecutively the user will see the first and
+                   then the second.  In the tty port, pline() achieves this
+                   by calling more() or displaying both on the same line.
+*/
+void mswin_putstr(winid wid, int attr, const char *text)
+{
+       logDebug("mswin_putstr(%d, %d, %s)\n", wid, attr, text);
+
+       mswin_putstr_ex(wid, attr, text, 0);
+}
+
+void mswin_putstr_ex(winid wid, int attr, const char *text, boolean app)
+{
+       if( (wid >= 0) && 
+        (wid < MAXWINDOWS) )
+       {
+               if( GetNHApp()->windowlist[wid].win==NULL &&
+                       GetNHApp()->windowlist[wid].type==NHW_MENU ) {
+                       GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_TEXT);
+                       GetNHApp()->windowlist[wid].dead = 0;
+               }
+
+               if (GetNHApp()->windowlist[wid].win != NULL)
+               {
+                        MSNHMsgPutstr data;
+                        ZeroMemory(&data, sizeof(data));
+                        data.attr = attr;
+                        data.text = text;
+                        data.append = app;
+                        SendMessage( 
+                                GetNHApp()->windowlist[wid].win, 
+                                WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_PUTSTR, (LPARAM)&data );
+               }
+       }
+}
+
+/* Display the file named str.  Complain about missing files
+                   iff complain is TRUE.
+*/
+void mswin_display_file(const char *filename,BOOLEAN_P must_exist)
+{
+       dlb *f;
+       TCHAR wbuf[BUFSZ];
+
+       logDebug("mswin_display_file(%s, %d)\n", filename, must_exist);
+
+       f = dlb_fopen(filename, RDTMODE);
+       if (!f) {
+               if (must_exist) {
+                       TCHAR message[90];
+                       _stprintf(message, TEXT("Warning! Could not find file: %s\n"), NH_A2W(filename, wbuf, sizeof(wbuf)));
+                       MessageBox(GetNHApp()->hMainWnd, message, TEXT("ERROR"), MB_OK | MB_ICONERROR );
+               } 
+       } else {
+               winid text;
+               char line[LLEN];
+
+               text = mswin_create_nhwindow(NHW_TEXT);
+
+               while (dlb_fgets(line, LLEN, f)) {
+                        size_t len;
+                        len = strlen(line);
+                        if( line[len-1]=='\n' ) line[len-1]='\x0';
+                               mswin_putstr(text, ATR_NONE, line);
+               }
+               (void) dlb_fclose(f);
+
+               mswin_display_nhwindow(text, 1);
+               mswin_destroy_nhwindow(text);
+       }
+}
+
+/* Start using window as a menu.  You must call start_menu()
+   before add_menu().  After calling start_menu() you may not
+   putstr() to the window.  Only windows of type NHW_MENU may
+   be used for menus.
+*/
+void mswin_start_menu(winid wid)
+{
+       logDebug("mswin_start_menu(%d)\n", wid);
+       if( (wid >= 0) && 
+        (wid < MAXWINDOWS) ) {
+               if( GetNHApp()->windowlist[wid].win==NULL &&
+                       GetNHApp()->windowlist[wid].type==NHW_MENU ) {
+                       GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_MENU);
+                       GetNHApp()->windowlist[wid].dead = 0;
+               }
+
+               if(GetNHApp()->windowlist[wid].win != NULL)     {
+                       SendMessage( 
+                                GetNHApp()->windowlist[wid].win, 
+                                WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_STARTMENU, (LPARAM)NULL
+                       );
+               }
+       }
+}
+
+/*
+add_menu(windid window, int glyph, const anything identifier,
+                                char accelerator, char groupacc,
+                                int attr, char *str, boolean preselected)
+                -- Add a text line str to the given menu window.  If identifier
+                   is 0, then the line cannot be selected (e.g. a title).
+                   Otherwise, identifier is the value returned if the line is
+                   selected.  Accelerator is a keyboard key that can be used
+                   to select the line.  If the accelerator of a selectable
+                   item is 0, the window system is free to select its own
+                   accelerator.  It is up to the window-port to make the
+                   accelerator visible to the user (e.g. put "a - " in front
+                   of str).  The value attr is the same as in putstr().
+                   Glyph is an optional glyph to accompany the line.  If
+                   window port cannot or does not want to display it, this
+                   is OK.  If there is no glyph applicable, then this
+                   value will be NO_GLYPH.
+                -- All accelerators should be in the range [A-Za-z].
+                -- It is expected that callers do not mix accelerator
+                   choices.  Either all selectable items have an accelerator
+                   or let the window system pick them.  Don't do both.
+                -- Groupacc is a group accelerator.  It may be any character
+                   outside of the standard accelerator (see above) or a
+                   number.  If 0, the item is unaffected by any group
+                   accelerator.  If this accelerator conflicts with
+                   the menu command (or their user defined alises), it loses.
+                   The menu commands and aliases take care not to interfere
+                   with the default object class symbols.
+                -- If you want this choice to be preselected when the
+                   menu is displayed, set preselected to TRUE.
+*/
+void mswin_add_menu(winid wid, int glyph, const ANY_P * identifier,
+               CHAR_P accelerator, CHAR_P group_accel, int attr, 
+               const char *str, BOOLEAN_P presel)
+{
+       logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n",
+                    wid, glyph, identifier, (char)accelerator, (char)group_accel,
+                        attr, str, presel);
+       if ((wid >= 0) && 
+               (wid < MAXWINDOWS) &&
+               (GetNHApp()->windowlist[wid].win != NULL))
+       {
+               MSNHMsgAddMenu data;
+               ZeroMemory(&data, sizeof(data));
+               data.glyph = glyph;
+               data.identifier = identifier;
+               data.accelerator = accelerator;
+               data.group_accel = group_accel;
+               data.attr = attr;
+               data.str = str;
+               data.presel = presel;
+
+               SendMessage( 
+                        GetNHApp()->windowlist[wid].win, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ADDMENU, (LPARAM)&data
+               );
+       }
+}
+
+/*
+end_menu(window, prompt)
+                -- Stop adding entries to the menu and flushes the window
+                   to the screen (brings to front?).  Prompt is a prompt
+                   to give the user.  If prompt is NULL, no prompt will
+                   be printed.
+                ** This probably shouldn't flush the window any more (if
+                ** it ever did).  That should be select_menu's job.  -dean
+*/
+void mswin_end_menu(winid wid, const char *prompt)
+{
+       logDebug("mswin_end_menu(%d, %s)\n", wid, prompt);
+       if ((wid >= 0) && 
+               (wid < MAXWINDOWS) &&
+               (GetNHApp()->windowlist[wid].win != NULL))
+       {
+               MSNHMsgEndMenu data;
+               ZeroMemory(&data, sizeof(data));
+               data.text = prompt;
+
+               SendMessage( 
+                        GetNHApp()->windowlist[wid].win, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ENDMENU, (LPARAM)&data
+               );
+       }
+}
+
+/*
+int select_menu(windid window, int how, menu_item **selected)
+                -- Return the number of items selected; 0 if none were chosen,
+                   -1 when explicitly cancelled.  If items were selected, then
+                   selected is filled in with an allocated array of menu_item
+                   structures, one for each selected line.  The caller must
+                   free this array when done with it.  The "count" field
+                   of selected is a user supplied count.  If the user did
+                   not supply a count, then the count field is filled with
+                   -1 (meaning all).  A count of zero is equivalent to not
+                   being selected and should not be in the list.  If no items
+                   were selected, then selected is NULL'ed out.  How is the
+                   mode of the menu.  Three valid values are PICK_NONE,
+                   PICK_ONE, and PICK_N, meaning: nothing is selectable,
+                   only one thing is selectable, and any number valid items
+                   may selected.  If how is PICK_NONE, this function should
+                   never return anything but 0 or -1.
+                -- You may call select_menu() on a window multiple times --
+                   the menu is saved until start_menu() or destroy_nhwindow()
+                   is called on the window.
+                -- Note that NHW_MENU windows need not have select_menu()
+                   called for them. There is no way of knowing whether
+                   select_menu() will be called for the window at
+                   create_nhwindow() time.
+*/
+int mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected)
+{
+       int nReturned = -1;
+
+       logDebug("mswin_select_menu(%d, %d)\n", wid, how);
+
+       if ((wid >= 0) && 
+               (wid < MAXWINDOWS) &&
+               (GetNHApp()->windowlist[wid].win != NULL))
+       {
+               nReturned = mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, how, selected);
+       }
+    return nReturned;
+}
+
+/*
+    -- Indicate to the window port that the inventory has been changed.
+    -- Merely calls display_inventory() for window-ports that leave the 
+       window up, otherwise empty.
+*/
+void mswin_update_inventory()
+{
+       logDebug("mswin_update_inventory()\n");
+}
+
+/*
+mark_synch()    -- Don't go beyond this point in I/O on any channel until
+                   all channels are caught up to here.  Can be an empty call
+                   for the moment
+*/
+void mswin_mark_synch()
+{
+       logDebug("mswin_mark_synch()\n");
+}
+
+/*
+wait_synch()    -- Wait until all pending output is complete (*flush*() for
+                   streams goes here).
+                -- May also deal with exposure events etc. so that the
+                   display is OK when return from wait_synch().
+*/
+void mswin_wait_synch()
+{
+       logDebug("mswin_wait_synch()\n");
+}
+
+/*
+cliparound(x, y)-- Make sure that the user is more-or-less centered on the
+                   screen if the playing area is larger than the screen.
+                -- This function is only defined if CLIPPING is defined.
+*/
+void mswin_cliparound(int x, int y)
+{
+       winid wid = WIN_MAP;
+
+       logDebug("mswin_cliparound(%d, %d)\n", x, y);
+
+    if ((wid >= 0) && 
+        (wid < MAXWINDOWS) &&
+        (GetNHApp()->windowlist[wid].win != NULL))
+    {
+                MSNHMsgClipAround data;
+                data.x = x;
+                data.y = y;
+         SendMessage( 
+                        GetNHApp()->windowlist[wid].win, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CLIPAROUND, (LPARAM)&data );
+    }
+}
+
+/*
+print_glyph(window, x, y, glyph)
+                -- Print the glyph at (x,y) on the given window.  Glyphs are
+                   integers at the interface, mapped to whatever the window-
+                   port wants (symbol, font, color, attributes, ...there's
+                   a 1-1 map between glyphs and distinct things on the map).
+*/
+void mswin_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph)
+{
+    logDebug("mswin_print_glyph(%d, %d, %d, %d)\n", wid, x, y, glyph);
+
+    if ((wid >= 0) && 
+        (wid < MAXWINDOWS) &&
+        (GetNHApp()->windowlist[wid].win != NULL))
+    {
+               MSNHMsgPrintGlyph data;
+
+               ZeroMemory(&data, sizeof(data) );
+               data.x = x;
+               data.y = y;
+               data.glyph = glyph;
+               SendMessage( GetNHApp()->windowlist[wid].win, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_PRINT_GLYPH, (LPARAM)&data );
+       }
+}
+
+/*
+raw_print(str)  -- Print directly to a screen, or otherwise guarantee that
+                   the user sees str.  raw_print() appends a newline to str.
+                   It need not recognize ASCII control characters.  This is
+                   used during startup (before windowing system initialization
+                   -- maybe this means only error startup messages are raw),
+                   for error messages, and maybe other "msg" uses.  E.g.
+                   updating status for micros (i.e, "saving").
+*/
+void mswin_raw_print(const char *str)
+{
+       TCHAR wbuf[255];
+    logDebug("mswin_raw_print(%s)\n", str);
+       if( str && *str)
+               MessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), TEXT("NetHack"), MB_OK );
+}
+
+/*
+raw_print_bold(str)
+                -- Like raw_print(), but prints in bold/standout (if
+possible).
+*/
+void mswin_raw_print_bold(const char *str)
+{
+       TCHAR wbuf[255];
+    logDebug("mswin_raw_print_bold(%s)\n", str);
+       if( str && *str)
+               MessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), TEXT("NetHack"), MB_OK );
+}
+
+/*
+int nhgetch()   -- Returns a single character input from the user.
+                -- In the tty window-port, nhgetch() assumes that tgetch()
+                   will be the routine the OS provides to read a character.
+                   Returned character _must_ be non-zero.
+*/
+int mswin_nhgetch()
+{
+       PMSNHEvent event;
+    int key = 0;
+
+       logDebug("mswin_nhgetch()\n");
+       
+
+       while( (event = mswin_input_pop()) == NULL ||
+                  event->type != NHEVENT_CHAR ) 
+               mswin_main_loop();
+
+       key = event->kbd.ch;
+    return (key);
+}
+
+/*
+int nh_poskey(int *x, int *y, int *mod)
+                -- Returns a single character input from the user or a
+                   a positioning event (perhaps from a mouse).  If the
+                   return value is non-zero, a character was typed, else,
+                   a position in the MAP window is returned in x, y and mod.
+                   mod may be one of
+
+                        CLICK_1         -- mouse click type 1 
+                        CLICK_2         -- mouse click type 2 
+
+                   The different click types can map to whatever the
+                   hardware supports.  If no mouse is supported, this
+                   routine always returns a non-zero character.
+*/
+int mswin_nh_poskey(int *x, int *y, int *mod)
+{
+       PMSNHEvent event;
+       int key;
+
+       logDebug("mswin_nh_poskey()\n");
+
+       while( (event = mswin_input_pop())==NULL ) mswin_main_loop();
+
+       if( event->type==NHEVENT_MOUSE ) {
+               *mod = event->ms.mod;
+               *x = event->ms.x;
+               *y = event->ms.y;
+               key = 0;
+       } else {
+               key = event->kbd.ch;
+       }
+       return (key);
+}
+
+/*
+nhbell()        -- Beep at user.  [This will exist at least until sounds are
+                   redone, since sounds aren't attributable to windows anyway.]
+*/
+void mswin_nhbell()
+{
+       logDebug("mswin_nhbell()\n");
+}
+
+/*
+doprev_message()
+                -- Display previous messages.  Used by the ^P command.
+                -- On the tty-port this scrolls WIN_MESSAGE back one line.
+*/
+int mswin_doprev_message()
+{
+    logDebug("mswin_doprev_message()\n");
+       SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL); 
+    return 0;
+}
+
+/*
+char yn_function(const char *ques, const char *choices, char default)
+                -- Print a prompt made up of ques, choices and default.
+                   Read a single character response that is contained in
+                   choices or default.  If choices is NULL, all possible
+                   inputs are accepted and returned.  This overrides
+                   everything else.  The choices are expected to be in
+                   lower case.  Entering ESC always maps to 'q', or 'n',
+                   in that order, if present in choices, otherwise it maps
+                   to default.  Entering any other quit character (SPACE,
+                   RETURN, NEWLINE) maps to default.
+                -- If the choices string contains ESC, then anything after
+                   it is an acceptable response, but the ESC and whatever
+                   follows is not included in the prompt.
+                -- If the choices string contains a '#' then accept a count.
+                   Place this value in the global "yn_number" and return '#'.
+                -- This uses the top line in the tty window-port, other
+                   ports might use a popup.
+*/
+char mswin_yn_function(const char *question, const char *choices,
+               CHAR_P def)
+{
+    int result=-1;
+    char ch;
+    char yn_esc_map='\033';
+    char message[BUFSZ];
+       char res_ch[2];
+
+       logDebug("mswin_yn_function(%s, %s, %d)\n", question, choices, def);
+
+    if (choices) {
+               char *cb, choicebuf[QBUFSZ];
+               Strcpy(choicebuf, choices);
+               if ((cb = index(choicebuf, '\033')) != 0) {
+                       /* anything beyond <esc> is hidden */
+                       *cb = '\0';
+               }
+               sprintf(message, "%s [%s] ", question, choicebuf);
+               if (def) sprintf(eos(message), "(%c) ", def);
+               /* escape maps to 'q' or 'n' or default, in that order */
+               yn_esc_map = (index(choices, 'q') ? 'q' :
+                        (index(choices, 'n') ? 'n' : def));
+       } else {
+               Strcpy(message, question);
+    }
+
+#if defined(WIN_CE_SMARTPHONE)
+       {
+       char buf[BUFSZ];
+       ZeroMemory(buf, sizeof(buf));
+       if( choices ) {
+               if( !index(choices, '\033') ) buf[0]='\033'; /* make sure ESC is always available */
+               strncat( buf, choices, sizeof(buf)-2);
+               NHSPhoneSetKeypadFromString( buf );
+       } else {
+               /* sometimes choices are included in the message itself, e.g. "what? [abcd]" */
+               char *p1, *p2;
+               p1 = strchr(question, '[');
+               p2 = strrchr(question, ']');
+               if( p1 && p2 && p1<p2 ) {
+                       buf[0]='\033'; /* make sure ESC is always available */
+                       strncat(buf, p1+1, p2-p1-1);
+                       NHSPhoneSetKeypadFromString( buf );
+               } else if( strstr(question, "direction") ) {
+                       /* asking for direction here */
+                       NHSPhoneSetKeypadDirection( );
+               } else {
+                       /* anything goes */
+                       NHSPhoneSetKeypadFromString( "\0330-9a-zA-Z" );
+               }
+       }
+       }
+#endif /* defined(WIN_CE_SMARTPHONE) */
+
+    mswin_putstr(WIN_MESSAGE, ATR_BOLD, message);
+
+    /* Only here if main window is not present */
+    while (result<0) {
+       ch=mswin_nhgetch();
+       if (ch=='\033') {
+           result=yn_esc_map;
+       } else if (choices && !index(choices,ch)) {
+           /* FYI: ch==-115 is for KP_ENTER */
+           if (def && (ch==' ' || ch=='\r' || ch=='\n' || ch==-115)) {
+               result=def;
+           } else {
+               mswin_nhbell();
+               /* and try again... */
+           }
+       } else {
+           result=ch;
+       }
+    }
+
+       /* display selection in the message window */
+       if( isprint(ch) ) {
+               res_ch[0] = ch;
+               res_ch[1] = '\x0';
+               mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1);
+       }
+
+       /* prevent "--more--" prompt from appearing when several 
+          questions being asked in the same loop (like selling 
+          something in the shop)
+          It does not really clears the window - mhmsgwnd.c */
+       mswin_clear_nhwindow(WIN_MESSAGE);
+
+#if defined(WIN_CE_SMARTPHONE)
+       NHSPhoneSetKeypadDefault();
+#endif
+    return result;
+}
+
+/*
+getlin(const char *ques, char *input)
+           -- Prints ques as a prompt and reads a single line of text,
+              up to a newline.  The string entered is returned without the
+              newline.  ESC is used to cancel, in which case the string
+              "\033\000" is returned.
+           -- getlin() must call flush_screen(1) before doing anything.
+           -- This uses the top line in the tty window-port, other
+              ports might use a popup.
+*/
+void mswin_getlin(const char *question, char *input)
+{
+       logDebug("mswin_getlin(%s, %p)\n", question, input);
+       if( mswin_getlin_window(question, input, BUFSZ)==IDCANCEL ) {
+               strcpy(input, "\033");
+       }
+}
+
+/*
+int get_ext_cmd(void)
+           -- Get an extended command in a window-port specific way.
+              An index into extcmdlist[] is returned on a successful
+              selection, -1 otherwise.
+*/
+int mswin_get_ext_cmd()
+{
+       int ret;
+       logDebug("mswin_get_ext_cmd()\n");
+
+       if(mswin_ext_cmd_window (&ret) == IDCANCEL)
+               return -1;
+       else 
+               return ret;
+}
+
+
+/*
+number_pad(state)
+           -- Initialize the number pad to the given state.
+*/
+void mswin_number_pad(int state)
+{
+    /* Do Nothing */
+       logDebug("mswin_number_pad(%d)\n", state);
+}
+
+/*
+delay_output()  -- Causes a visible delay of 50ms in the output.
+              Conceptually, this is similar to wait_synch() followed
+              by a nap(50ms), but allows asynchronous operation.
+*/
+void mswin_delay_output()
+{
+       logDebug("mswin_delay_output()\n");
+       Sleep(50);
+}
+
+void mswin_change_color() 
+{ 
+       logDebug("mswin_change_color()\n"); 
+}
+
+char *mswin_get_color_string() 
+{ 
+       logDebug("mswin_get_color_string()\n");
+       return( "" ); 
+}
+
+/*
+start_screen()  -- Only used on Unix tty ports, but must be declared for
+              completeness.  Sets up the tty to work in full-screen
+              graphics mode.  Look at win/tty/termcap.c for an
+              example.  If your window-port does not need this function
+              just declare an empty function.
+*/
+void mswin_start_screen()
+{
+    /* Do Nothing */
+       logDebug("mswin_start_screen()\n");
+}
+
+/*
+end_screen()    -- Only used on Unix tty ports, but must be declared for
+              completeness.  The complement of start_screen().
+*/
+void mswin_end_screen()
+{
+    /* Do Nothing */
+       logDebug("mswin_end_screen()\n");
+}
+
+/*
+outrip(winid, int)
+           -- The tombstone code.  If you want the traditional code use
+              genl_outrip for the value and check the #if in rip.c.
+*/
+void mswin_outrip(winid wid, int how)
+{
+       logDebug("mswin_outrip(%d)\n", wid, how);
+    if ((wid >= 0) && (wid < MAXWINDOWS) ) {
+               DestroyWindow(GetNHApp()->windowlist[wid].win);
+               GetNHApp()->windowlist[wid].win = mswin_init_RIP_window();
+               GetNHApp()->windowlist[wid].type = NHW_RIP;
+               GetNHApp()->windowlist[wid].dead = 0;
+       }
+
+       genl_outrip(wid, how);
+}
+
+/* handle options updates here */
+void mswin_preference_update(const char *pref)
+{
+       HDC hdc;
+
+       if( _stricmp( pref, "font_menu")==0 ||
+               _stricmp( pref, "font_size_menu")==0 ) {
+               if( iflags.wc_fontsiz_menu<NHFONT_SIZE_MIN || 
+                       iflags.wc_fontsiz_menu>NHFONT_SIZE_MAX )
+                       iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
+
+               hdc = GetDC(GetNHApp()->hMainWnd);
+               mswin_get_font(NHW_MENU, ATR_NONE, hdc, TRUE);
+               mswin_get_font(NHW_MENU, ATR_BOLD, hdc, TRUE);
+               mswin_get_font(NHW_MENU, ATR_DIM, hdc, TRUE);
+               mswin_get_font(NHW_MENU, ATR_ULINE, hdc, TRUE);
+               mswin_get_font(NHW_MENU, ATR_BLINK, hdc, TRUE);
+               mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, TRUE);
+               ReleaseDC(GetNHApp()->hMainWnd, hdc);
+
+               mswin_layout_main_window(NULL);
+               return;
+       }
+
+       if( _stricmp( pref, "font_status")==0 ||
+               _stricmp( pref, "font_size_status")==0 ) {
+
+               if( iflags.wc_fontsiz_status<NHFONT_SIZE_MIN || 
+                       iflags.wc_fontsiz_status>NHFONT_SIZE_MAX )
+                       iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
+
+               hdc = GetDC(GetNHApp()->hMainWnd);
+               mswin_get_font(NHW_STATUS, ATR_NONE, hdc, TRUE);
+               mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, TRUE);
+               mswin_get_font(NHW_STATUS, ATR_DIM, hdc, TRUE);
+               mswin_get_font(NHW_STATUS, ATR_ULINE, hdc, TRUE);
+               mswin_get_font(NHW_STATUS, ATR_BLINK, hdc, TRUE);
+               mswin_get_font(NHW_STATUS, ATR_INVERSE, hdc, TRUE);
+               ReleaseDC(GetNHApp()->hMainWnd, hdc);
+
+               mswin_layout_main_window(NULL);
+               return;
+       }
+
+       if( _stricmp( pref, "font_message")==0 ||
+               _stricmp( pref, "font_size_message")==0 ) {
+
+               if( iflags.wc_fontsiz_message<NHFONT_SIZE_MIN || 
+                       iflags.wc_fontsiz_message>NHFONT_SIZE_MAX )
+                       iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
+
+               hdc = GetDC(GetNHApp()->hMainWnd);
+               mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, TRUE);
+               mswin_get_font(NHW_MESSAGE, ATR_BOLD, hdc, TRUE);
+               mswin_get_font(NHW_MESSAGE, ATR_DIM, hdc, TRUE);
+               mswin_get_font(NHW_MESSAGE, ATR_ULINE, hdc, TRUE);
+               mswin_get_font(NHW_MESSAGE, ATR_BLINK, hdc, TRUE);
+               mswin_get_font(NHW_MESSAGE, ATR_INVERSE, hdc, TRUE);
+               ReleaseDC(GetNHApp()->hMainWnd, hdc);
+
+               mswin_layout_main_window(NULL);
+               return;
+       }
+
+       if( _stricmp( pref, "font_text")==0 ||
+               _stricmp( pref, "font_size_text")==0 ) {
+
+               if( iflags.wc_fontsiz_text<NHFONT_SIZE_MIN || 
+                       iflags.wc_fontsiz_text>NHFONT_SIZE_MAX )
+                       iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
+
+               hdc = GetDC(GetNHApp()->hMainWnd);
+               mswin_get_font(NHW_TEXT, ATR_NONE, hdc, TRUE);
+               mswin_get_font(NHW_TEXT, ATR_BOLD, hdc, TRUE);
+               mswin_get_font(NHW_TEXT, ATR_DIM, hdc, TRUE);
+               mswin_get_font(NHW_TEXT, ATR_ULINE, hdc, TRUE);
+               mswin_get_font(NHW_TEXT, ATR_BLINK, hdc, TRUE);
+               mswin_get_font(NHW_TEXT, ATR_INVERSE, hdc, TRUE);
+               ReleaseDC(GetNHApp()->hMainWnd, hdc);
+
+               mswin_layout_main_window(NULL);
+               return;
+       }
+
+       if( _stricmp( pref, "scroll_margin")==0 ) {
+               mswin_cliparound(u.ux, u.uy);
+               return;
+       }
+
+       if( _stricmp( pref, "map_mode")==0 ) {
+               mswin_select_map_mode( iflags.wc_map_mode );
+               return;
+       }
+
+       if( _stricmp( pref, "hilite_pet")==0 ) {
+               InvalidateRect(mswin_hwnd_from_winid(WIN_MAP), NULL, TRUE);
+               return;
+       }
+
+       if( _stricmp( pref, "align_message")==0 ||
+               _stricmp( pref, "align_status")==0 ) {
+               mswin_layout_main_window(NULL);
+               return;
+       }
+
+       if( _stricmp( pref, "vary_msgcount")==0 ) {
+               InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE);
+               mswin_layout_main_window(NULL);
+               return;
+       }
+
+       if( _stricmp( pref, "fullscreen")==0 ) {
+               mswin_set_fullscreen(iflags.wc2_fullscreen);
+               return;
+       }
+
+       if( _stricmp( pref, "softkeyboard")==0 ) {
+               GetNHApp()->bUseSIP = iflags.wc2_softkeyboard;
+               return;
+       }
+
+       if( _stricmp( pref, "wraptext")==0 ) {
+               GetNHApp()->bWrapText = iflags.wc2_wraptext;
+               return;
+       }
+
+}
+
+void mswin_main_loop()
+{
+       MSG msg;
+
+       while( !mswin_have_input() &&
+                  GetMessage(&msg, NULL, 0, 0)!=0 ) {
+               if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) {
+                       TranslateMessage(&msg);
+                       DispatchMessage(&msg);
+               }
+       } 
+}
+
+/* clean up and quit */
+void bail(const char *mesg)
+{
+    clearlocks();
+    mswin_exit_nhwindows(mesg);
+    terminate(EXIT_SUCCESS);
+    /*NOTREACHED*/
+}
+
+BOOL initMapTiles(void)
+{
+       HBITMAP hBmp;
+       BITMAP  bm;
+       TCHAR   wbuf[MAX_PATH];
+       int     tl_num;
+       SIZE    map_size;
+       extern int total_tiles_used;
+
+       /* no file - no tile */
+       if( !(iflags.wc_tile_file && *iflags.wc_tile_file) ) 
+               return TRUE;
+
+       /* load bitmap */
+       hBmp = SHLoadDIBitmap(NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH));
+       if( hBmp==NULL ) {
+               raw_print("Cannot load tiles from the file. Reverting back to default.");
+               return FALSE;
+       }
+
+       /* calculate tile dimensions */
+       GetObject(hBmp, sizeof(BITMAP), (LPVOID)&bm);
+       if( bm.bmWidth%iflags.wc_tile_width ||
+               bm.bmHeight%iflags.wc_tile_height ) {
+               DeleteObject(hBmp);
+               raw_print("Tiles bitmap does not match tile_width and tile_height options. Reverting back to default.");
+               return FALSE;
+       }
+
+       tl_num = (bm.bmWidth/iflags.wc_tile_width)*
+                    (bm.bmHeight/iflags.wc_tile_height);
+       if( tl_num<total_tiles_used ) {
+               DeleteObject(hBmp);
+               raw_print("Number of tiles in the bitmap is less than required by the game. Reverting back to default.");
+               return FALSE;
+       }
+
+       /* set the tile information */
+       if( GetNHApp()->bmpMapTiles!=GetNHApp()->bmpTiles ) {
+               DeleteObject(GetNHApp()->bmpMapTiles);
+       }
+
+       GetNHApp()->bmpMapTiles = hBmp;
+       GetNHApp()->mapTile_X = iflags.wc_tile_width;
+       GetNHApp()->mapTile_Y = iflags.wc_tile_height;
+       GetNHApp()->mapTilesPerLine = bm.bmWidth / iflags.wc_tile_width;
+
+       map_size.cx = GetNHApp()->mapTile_X * COLNO;
+       map_size.cy = GetNHApp()->mapTile_Y * ROWNO;
+       mswin_map_stretch(
+               mswin_hwnd_from_winid(WIN_MAP),
+               &map_size,
+               TRUE 
+       );
+       return TRUE;
+}
+
+void mswin_popup_display(HWND hWnd, int* done_indicator)
+{
+       MSG msg;
+       HWND hChild;
+
+       /* activate the menu window */
+       GetNHApp()->hPopupWnd = hWnd;
+
+       mswin_layout_main_window(hWnd);
+
+       /* disable game windows */
+       for( hChild=GetWindow(GetNHApp()->hMainWnd, GW_CHILD);
+                hChild;
+                hChild = GetWindow(hChild, GW_HWNDNEXT) ) {
+               if( hChild!=hWnd ) EnableWindow(hChild, FALSE);
+       }
+#if defined(WIN_CE_SMARTPHONE)
+       ShowWindow(GetNHApp()->hMenuBar, SW_HIDE);
+       ShowWindow(SHFindMenuBar(hWnd), SW_SHOW);
+#else
+       EnableWindow(GetNHApp()->hMenuBar, FALSE);
+#endif
+
+       /* bring menu window on top */
+       SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
+
+       /* go into message loop */
+       if( done_indicator ) *done_indicator = 0;
+       while( IsWindow(hWnd) && 
+                  (done_indicator==NULL || !*done_indicator) &&
+                  GetMessage(&msg, NULL, 0, 0)!=0 ) {
+               if( !IsDialogMessage(hWnd, &msg) ) {
+                       if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) {
+                               TranslateMessage(&msg);
+                               DispatchMessage(&msg);
+                       }
+               }
+       }
+}
+
+void mswin_popup_destroy(HWND hWnd)
+{
+       HWND hChild;
+
+       /* enable game windows */
+       for( hChild=GetWindow(GetNHApp()->hMainWnd, GW_CHILD);
+                hChild;
+                hChild = GetWindow(hChild, GW_HWNDNEXT) ) {
+               if( hChild!= hWnd) {
+                       EnableWindow(hChild, TRUE);
+               }
+       }
+#if defined(WIN_CE_SMARTPHONE)
+       ShowWindow(SHFindMenuBar(hWnd), SW_HIDE);
+       ShowWindow(GetNHApp()->hMenuBar, SW_SHOW);
+#else
+       EnableWindow(GetNHApp()->hMenuBar, TRUE);
+#endif
+
+       SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
+       GetNHApp()->hPopupWnd = NULL;
+       mswin_window_mark_dead( mswin_winid_from_handle(hWnd) );
+       DestroyWindow(hWnd);
+
+       mswin_layout_main_window(hWnd);
+
+       SetFocus(GetNHApp()->hMainWnd );
+}
+
+void mswin_set_fullscreen(BOOL is_fullscreen)
+{
+#if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
+       SetForegroundWindow(GetNHApp()->hMainWnd);
+       if(     is_fullscreen ) {
+               SHFullScreen(GetNHApp()->hMainWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON);
+               MoveWindow(
+                       GetNHApp()->hMainWnd,
+                       0,
+                       0,
+                       GetSystemMetrics(SM_CXSCREEN),
+                       GetSystemMetrics(SM_CYSCREEN),
+                       FALSE
+               );
+       } else {
+               RECT rc;
+               SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
+               SHFullScreen(GetNHApp()->hMainWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
+               MoveWindow(
+                       GetNHApp()->hMainWnd,
+                       rc.left,
+                       rc.top,
+                       rc.right - rc.left,
+                       rc.bottom - rc.top,
+                       FALSE
+               );
+       }
+       GetNHApp()->bFullScreen = is_fullscreen;
+#else
+       GetNHApp()->bFullScreen = FALSE;
+#endif
+}
+
+#if defined(WIN_CE_SMARTPHONE)
+void NHSPhoneDialogSetup(HWND hDlg, BOOL is_edit, BOOL is_fullscreen)
+{
+    SHMENUBARINFO mbi;
+       HWND hOK, hCancel;
+       RECT rtOK, rtDlg;
+
+       // Create our MenuBar
+    ZeroMemory(&mbi, sizeof(SHMENUBARINFO));
+    mbi.cbSize = sizeof(mbi);
+    mbi.hwndParent = hDlg;
+    mbi.nToolBarId = IDC_SPHONE_DIALOGBAR;
+    mbi.hInstRes = GetNHApp()->hApp;
+    if(!SHCreateMenuBar(&mbi)) {
+               error("cannot create dialog menu");
+       }
+
+       if(is_fullscreen) {
+               SHINITDLGINFO shidi;
+               RECT main_wnd_rect;
+               shidi.dwMask = SHIDIM_FLAGS;
+               shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN;
+               shidi.hDlg = hDlg;
+               SHInitDialog(&shidi);
+
+               GetWindowRect(GetNHApp()->hMainWnd, &main_wnd_rect);
+               MoveWindow(
+                       hDlg,
+                       main_wnd_rect.left,
+                       main_wnd_rect.top,
+                       main_wnd_rect.right - main_wnd_rect.left,
+                       main_wnd_rect.bottom - main_wnd_rect.top,
+                       FALSE
+               );
+       }
+
+       /* hide OK and CANCEL buttons */
+       hOK = GetDlgItem(hDlg, IDOK);
+       hCancel = GetDlgItem(hDlg, IDCANCEL);
+
+       if( IsWindow(hCancel) ) ShowWindow(hCancel, SW_HIDE);
+       if( IsWindow(hOK) ) {
+               GetWindowRect(hOK, &rtOK);
+               GetWindowRect(hDlg, &rtDlg);
+
+               rtDlg.bottom -= rtOK.bottom-rtOK.top;
+               ShowWindow(hOK, SW_HIDE);
+               SetWindowPos( hDlg, HWND_TOP, 
+                                 0, 0, 
+                                         rtDlg.right-rtDlg.left, rtDlg.bottom-rtDlg.top,
+                                         SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOZORDER );
+       }
+
+       /* override "Back" button for edit box dialogs */
+       if( is_edit ) 
+               SendMessage(mbi.hwndMB, SHCMBM_OVERRIDEKEY, VK_TBACK, MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, SHMBOF_NODEFAULT | SHMBOF_NOTIFY));
+}
+#endif /* defined(WIN_CE_SMARTPHONE) */
+
+void mswin_read_reg(void)
+{
+}
+
+void mswin_destroy_reg(void)
+{
+}
+
+void mswin_write_reg(void)
+{
+}
+
+#ifdef _DEBUG
+#include <stdarg.h>
+
+void
+logDebug(const char *fmt, ...)
+{
+  FILE *dfp = fopen("nhtrace.log", "a");
+
+  if (dfp) {
+     va_list args;
+
+     va_start(args, fmt);
+     vfprintf(dfp, fmt, args);
+     va_end(args);
+     fclose(dfp);
+  }
+}
+
+#endif
+
diff --git a/sys/wince/newres.h b/sys/wince/newres.h
new file mode 100644 (file)
index 0000000..fa66dcb
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef __NEWRES_H__
+#define __NEWRES_H__
+
+#if !defined(UNDER_CE)
+       #define UNDER_CE _WIN32_WCE
+#endif
+
+#if defined(_WIN32_WCE)
+       #if !defined(WCEOLE_ENABLE_DIALOGEX)
+               #define DIALOGEX DIALOG DISCARDABLE
+       #endif
+       #include <commctrl.h>
+       #define  SHMENUBAR RCDATA
+       #if (defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)) && (_WIN32_WCE >= 300)
+               #include <aygshell.h> 
+       #else
+               #define I_IMAGENONE             (-2)
+               #define NOMENU                  0xFFFF
+               #define IDS_SHNEW               1
+
+               #define IDM_SHAREDNEW        10
+               #define IDM_SHAREDNEWDEFAULT 11
+       #endif
+#endif // _WIN32_WCE
+
+
+#ifdef RC_INVOKED
+#ifndef _INC_WINDOWS
+#define _INC_WINDOWS
+       #include "winuser.h"           // extract from windows header
+#endif
+#endif
+
+#ifdef IDC_STATIC
+#undef IDC_STATIC
+#endif
+#define IDC_STATIC      (-1)
+
+#endif //__NEWRES_H__
+
diff --git a/sys/wince/resource.h b/sys/wince/resource.h
new file mode 100644 (file)
index 0000000..63b8d45
--- /dev/null
@@ -0,0 +1,159 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by winhack.rc
+//
+#define IDC_MYICON                      2
+#define IDD_WINHACK_DIALOG              102
+#define IDD_ABOUTBOX                    103
+#define IDS_APP_TITLE                   103
+#define IDM_ABOUT                       104
+#define IDM_EXIT                        105
+#define IDS_HELLO                       106
+#define IDI_WINHACK                     107
+#define IDC_WINHACK                     109
+#define IDC_SPHONE_DIALOGBAR            111
+#define IDR_MAINFRAME                   128
+#define IDB_TILES                       129
+#define IDD_TEXT                        130
+#define IDD_NHTEXT                      130
+#define IDD_MENU                        132
+#define IDB_MENU_SEL                    133
+#define IDB_MENU_UNSEL                  134
+#define IDD_COMMANDS                    136
+#define IDD_GETLIN                      138
+#define IDD_EXTCMD                      139
+#define IDD_PLAYER_SELECTOR             141
+#define IDB_PETMARK                     145
+#define IDB_MENU_SEL_COUNT              146
+#define IDB_KEYPAD                      147
+#define IDB_MENUBAR                     154
+#define IDC_TEXT_VIEW                   1001
+#define IDC_CMD_MOVE_NW                 1001
+#define IDC_CMD_MOVE_N                  1002
+#define IDC_MENU_LIST                   1003
+#define IDC_CMD_MOVE_NE                 1003
+#define IDC_MENU_TEXT                   1004
+#define IDC_CMD_MOVE_W                  1004
+#define IDC_CMD_MOVE_SELF               1005
+#define IDC_CMD_MOVE_E                  1006
+#define IDC_CMD_MOVE_SW                 1007
+#define IDC_CMD_MOVE_S                  1008
+#define IDC_CMD_MOVE_SE                 1009
+#define IDC_CMD_MOVE_UP                 1010
+#define IDC_CMD_MOVE_DOWN               1011
+#define IDC_CMD_5                       1012
+#define IDC_CMD_A                       1013
+#define IDC_CMD_B                       1014
+#define IDC_CMD_C                       1015
+#define IDC_CMD_D                       1016
+#define IDC_CMD_E                       1017
+#define IDC_CMD_F                       1018
+#define IDC_CMD_G                       1019
+#define IDC_CMD_H                       1020
+#define IDC_CMD_I                       1021
+#define IDC_CMD_J                       1022
+#define IDC_CMD_K                       1023
+#define IDC_CMD_L                       1024
+#define IDC_CMD_M                       1025
+#define IDC_CMD_N                       1026
+#define IDC_CMD_O                       1027
+#define IDC_CMD_P                       1028
+#define IDC_CMD_Q                       1029
+#define IDC_CMD_R                       1030
+#define IDC_CMD_S                       1031
+#define IDC_CMD_T                       1032
+#define IDC_CMD_U                       1033
+#define IDC_CMD_V                       1034
+#define IDC_CMD_W                       1035
+#define IDC_CMD_X                       1036
+#define IDC_CMD_Y                       1037
+#define IDC_CMD_Z                       1038
+#define IDC_CMD_AA                      1039
+#define IDC_CMD_BB                      1040
+#define IDC_CMD_CC                      1041
+#define IDC_CMD_DD                      1042
+#define IDC_CMD_EE                      1043
+#define IDC_CMD_FF                      1044
+#define IDC_CMD_GG                      1045
+#define IDC_CMD_HH                      1046
+#define IDC_CMD_II                      1047
+#define IDC_CMD_JJ                      1048
+#define IDC_CMD_KK                      1049
+#define IDC_CMD_LL                      1050
+#define IDC_CMD_MM                      1051
+#define IDC_CMD_NN                      1052
+#define IDC_CMD_OO                      1053
+#define IDC_CMD_PP                      1054
+#define IDC_CMD_QQ                      1055
+#define IDC_CMD_RR                      1056
+#define IDC_CMD_SS                      1057
+#define IDC_CMD_TT                      1058
+#define IDC_CMD_UU                      1059
+#define IDC_CMD_VV                      1060
+#define IDC_CMD_WW                      1061
+#define IDC_CMD_XX                      1062
+#define IDC_CMD_YY                      1063
+#define IDC_CMD_ZZ                      1064
+#define IDC_CMD_FIRST                   1100
+#define IDC_CMD_LAST                    1300
+#define IDC_GETLIN_EDIT                 1309
+#define IDC_EXTCMD_LIST                 1310
+#define IDC_PLSEL_NAME                  1314
+#define IDC_PLSEL_ROLE_RANDOM           1315
+#define IDC_PLSEL_RACE_RANDOM           1318
+#define IDC_PLSEL_GENDER_RANDOM         1319
+#define IDC_PLSEL_ALIGN_RANDOM          1320
+#define IDC_PLSEL_ROLE_LIST             1323
+#define IDC_PLSEL_RACE_LIST             1324
+#define IDC_PLSEL_ALIGN_LIST            1325
+#define IDC_PLSEL_GENDER_LIST           1326
+#define IDC_ABOUT_VERSION               1327
+#define IDC_TEXT_CONTROL                1331
+#define IDC_ABOUT_COPYRIGHT             1332
+#define IDM_SAVE                        32771
+#define IDM_HELP_LONG                   32772
+#define IDM_HELP_COMMANDS               32773
+#define IDM_HELP_HISTORY                32774
+#define IDM_HELP_INFO_CHAR              32775
+#define IDM_HELP_INFO_KEY               32776
+#define IDM_HELP_OPTIONS                32777
+#define IDM_HELP_OPTIONS_LONG           32778
+#define IDM_HELP_EXTCMD                 32779
+#define IDM_HELP_LICENSE                32780
+#define IDM_MAP_TILES                   32781
+#define IDM_MAP_ASCII4X6                32782
+#define IDM_MAP_ASCII6X8                32783
+#define IDM_MAP_ASCII8X8                32784
+#define IDM_MAP_ASCII16X8               32785
+#define IDM_MAP_ASCII7X12               32786
+#define IDM_MAP_ASCII8X12               32787
+#define IDM_MAP_ASCII16X12              32788
+#define IDM_MAP_ASCII12X16              32789
+#define IDM_MAP_ASCII10X18              32790
+#define IDM_MAP_FIT_TO_SCREEN           32791
+#define ID_FILE                         32792
+#define IDS_CAP_FILE                    32793
+#define ID_HELP                         32794
+#define IDS_CAP_HELP                    32795
+#define IDS_CAP_TEMP                    32796
+#define ID_MAP                          32797
+#define IDS_CAP_AMP                     32798
+#define IDS_CAP_MAP                     32799
+#define IDM_VIEW_KEYPAD                 32800
+#define ID_VIEW                         32801
+#define IDS_CAP_VIEW                    32802
+#define IDS_CAP_ENTIREMAP               32826
+#define IDS_CAP_NORMALMAP               32827
+#define IDM_HELP_MENU                   32828
+#define IDM_VIEW_OPTIONS                32829
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        155
+#define _APS_NEXT_COMMAND_VALUE         32830
+#define _APS_NEXT_CONTROL_VALUE         1334
+#define _APS_NEXT_SYMED_VALUE           110
+#endif
+#endif
diff --git a/sys/wince/winMS.h b/sys/wince/winMS.h
new file mode 100644 (file)
index 0000000..6f7e1ad
--- /dev/null
@@ -0,0 +1,182 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef WINMS_H
+#define WINMS_H
+
+#pragma warning(disable:4142) /* benign redefinition of type */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <commctrl.h>
+#include <tchar.h>
+#include <newres.h>
+#include "resource.h"
+#include "hack.h"
+
+#if defined(WIN_CE_POCKETPC)
+#include <aygshell.h> 
+#include <sipapi.h>
+#endif
+
+#if defined(WIN_CE_SMARTPHONE)
+#include <aygshell.h> 
+#include <sipapi.h>
+#include <shlobj.h>
+#include <prsht.h>
+#include <Tpcshell.h>
+#include <windowsm.h>
+#include <KEYBD.H>
+#endif
+
+#if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO)
+#include <sipapi.h>
+#endif
+
+/* Taskbar Menu height */
+#define MENU_HEIGHT 26
+
+/* Create an array to keep track of the various windows */
+
+#ifndef MAXWINDOWS
+#define MAXWINDOWS 15
+#endif
+
+/* RIP window ID */
+#define NHW_RIP                32
+#define NHW_KEYPAD  33
+
+/* size of tiles */
+#ifndef TILE_X
+#define TILE_X 16
+#endif
+#define TILE_Y 16
+
+/* tiles per line in the bitmap */
+#define TILES_PER_LINE  40
+
+/* tile background color */
+#define TILE_BK_COLOR RGB(71, 108, 108)
+
+/* minimum/maximum font size (in points - 1/72 inch) */
+#define NHFONT_DEFAULT_SIZE 9
+#define NHFONT_STATUS_DEFAULT_SIZE 6
+#define NHFONT_SIZE_MIN 3
+#define NHFONT_SIZE_MAX 20
+
+typedef struct mswin_nhwindow_data {
+  HWND       win;
+  int            type;
+  int            dead;
+} MSNHWinData, *PMSNHWinData;
+
+/* global application data - alailable thour GetNHApp() */
+typedef struct mswin_nhwindow_app {
+       HINSTANCE   hApp;               /* hInstance from WinMain */
+       int                     nCmdShow;       /* main window mode flag */
+       HWND            hMainWnd;       /* main window handle */
+       HACCEL          hAccelTable; /* accelerator table */
+       HWND            hPopupWnd;      /* active dialog window (nethack menu, text, etc) */
+       HWND            hMenuBar;       /* menu bar */
+
+       MSNHWinData windowlist[MAXWINDOWS];     /* nethack windows array */
+
+       HBITMAP         bmpTiles;       /* nethack tiles */
+       HBITMAP         bmpPetMark; /* pet mark Bitmap */
+       HBITMAP         bmpMapTiles; /* alternative map tiles */
+       int                     mapTile_X;      /* alt. tiles width */
+       int                     mapTile_Y;      /* alt. tiles height */
+       int                     mapTilesPerLine;        /* number of tile per row in the bitmap */
+
+       boolean         bNoHScroll;     /* disable cliparound for horizontal grid (map) */
+       boolean         bNoVScroll; /* disable cliparound for vertical grid (map) */
+
+       int                     mapDisplayModeSave;     /* saved map display mode */
+
+       int                     bCmdPad;        /* command pad - on-screen keyboard */ 
+       HWND            hCmdWnd;        /* handle of on-screen keyboard window */
+
+       /* options */
+       boolean         bWrapText;      /* format text to fit the window */
+       boolean         bFullScreen;/* run nethack in full-screen mode  */
+       boolean         bHideScrollBars; /* hide scroll bars */
+       boolean         bUseSIP; /* use SIP (built-in software keyboard) for menus (PocketPC only) */
+} NHWinApp, *PNHWinApp;
+extern PNHWinApp GetNHApp();
+
+#define E extern
+
+E struct window_procs mswin_procs;
+
+#undef E
+
+/* Some prototypes */
+void mswin_init_nhwindows(int* argc, char** argv);
+void mswin_player_selection(void);
+void mswin_askname(void);
+void mswin_get_nh_event(void);
+void mswin_exit_nhwindows(const char *);
+void mswin_suspend_nhwindows(const char *);
+void mswin_resume_nhwindows(void);
+winid mswin_create_nhwindow(int type);
+void mswin_clear_nhwindow(winid wid);
+void mswin_display_nhwindow(winid wid, BOOLEAN_P block);
+void mswin_destroy_nhwindow(winid wid);
+void mswin_curs(winid wid, int x, int y);
+void mswin_putstr(winid wid, int attr, const char *text);
+void mswin_putstr_ex(winid wid, int attr, const char *text, boolean append);
+void mswin_display_file(const char *filename,BOOLEAN_P must_exist);
+void mswin_start_menu(winid wid);
+void mswin_add_menu(winid wid, int glyph, const ANY_P * identifier,
+               CHAR_P accelerator, CHAR_P group_accel, int attr, 
+               const char *str, BOOLEAN_P presel);
+void mswin_end_menu(winid wid, const char *prompt);
+int  mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected);
+void mswin_update_inventory(void);
+void mswin_mark_synch(void);
+void mswin_wait_synch(void);
+void mswin_cliparound(int x, int y);
+void mswin_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph);
+void mswin_raw_print(const char *str);
+void mswin_raw_print_bold(const char *str);
+int  mswin_nhgetch(void);
+int  mswin_nh_poskey(int *x, int *y, int *mod);
+void mswin_nhbell(void);
+int  mswin_doprev_message(void);
+char mswin_yn_function(const char *question, const char *choices,
+               CHAR_P def);
+void mswin_getlin(const char *question, char *input);
+int  mswin_get_ext_cmd(void);
+void mswin_number_pad(int state);
+void mswin_delay_output(void);
+void mswin_change_color(void);
+char *mswin_get_color_string(void);
+void mswin_start_screen(void);
+void mswin_end_screen(void);
+void mswin_outrip(winid wid, int how);
+void mswin_preference_update(const char *pref);
+
+/* helper function */
+HWND mswin_hwnd_from_winid(winid wid);
+winid mswin_winid_from_type(int type);
+winid mswin_winid_from_handle(HWND hWnd);
+void mswin_window_mark_dead(winid wid);
+void bail(const char *mesg);
+void nhapply_image_transparent( 
+       HDC hDC, int x, int y, int width, int height,
+       HDC sourceDC, int s_x, int s_y, int s_width, int s_height,
+       COLORREF cTransparent
+);
+void mswin_popup_display(HWND popup, int* done_indicator);
+void mswin_popup_destroy(HWND popup);
+
+#if defined(WIN_CE_SMARTPHONE)
+void NHSPhoneDialogSetup(HWND hDlg, BOOL is_edit, BOOL is_fullscreen);
+#endif
+
+void mswin_read_reg(void);
+void mswin_destroy_reg(void);
+void mswin_write_reg(void);
+
+void mswin_set_fullscreen(BOOL is_fullscreen);
+#endif /* WINmswin_H */
diff --git a/sys/wince/winhack.c b/sys/wince/winhack.c
new file mode 100644 (file)
index 0000000..6a768ac
--- /dev/null
@@ -0,0 +1,362 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+// winhack.cpp : Defines the entry point for the application.
+//
+
+#include "winMS.h"
+#include "hack.h"
+#include "dlb.h"
+#include "mhmain.h"
+#include "mhmap.h"
+
+#ifdef OVL0
+#define SHARED_DCL
+#else
+#define SHARED_DCL extern
+#endif
+
+SHARED_DCL char orgdir[PATHLEN];       /* also used in pcsys.c, amidos.c */
+
+extern void FDECL(nethack_exit,(int));
+static TCHAR* _get_cmd_arg(TCHAR* pCmdLine);
+
+// Global Variables:
+NHWinApp _nethack_app;
+
+// Foward declarations of functions included in this code module:
+BOOL                           InitInstance(HINSTANCE, int);
+
+static void win_hack_init(int, char **);
+static void __cdecl mswin_moveloop(void *);
+static BOOL setMapTiles(const char* fname);
+
+extern void FDECL(pcmain, (int,char **));
+
+#define MAX_CMDLINE_PARAM 255
+
+int APIENTRY WinMain(HINSTANCE hInstance,
+                     HINSTANCE hPrevInstance,
+                     LPWSTR     lpCmdLine,
+                     int       nCmdShow)
+{
+       INITCOMMONCONTROLSEX InitCtrls;
+       HWND nethackWnd;
+       int argc;
+       char* argv[MAX_CMDLINE_PARAM];
+       size_t len;
+       TCHAR* p;
+       TCHAR wbuf[NHSTR_BUFSIZE];
+       char buf[NHSTR_BUFSIZE];
+
+       /* ensure that we don't access violate on a panic() */
+       windowprocs.win_raw_print = mswin_raw_print;
+       windowprocs.win_raw_print_bold = mswin_raw_print_bold;
+
+       /* init applicatio structure */
+       _nethack_app.hApp = hInstance;
+       _nethack_app.nCmdShow = nCmdShow;
+       _nethack_app.hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_WINHACK);
+       _nethack_app.hMainWnd = NULL;
+       _nethack_app.hPopupWnd = NULL;
+       _nethack_app.hMenuBar = NULL;
+       _nethack_app.bmpTiles = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TILES));
+       if( _nethack_app.bmpTiles==NULL ) panic("cannot load tiles bitmap");
+       _nethack_app.bmpPetMark = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_PETMARK));
+       if( _nethack_app.bmpPetMark==NULL ) panic("cannot load pet mark bitmap");
+       _nethack_app.bmpMapTiles = _nethack_app.bmpTiles;
+       _nethack_app.mapTile_X = TILE_X;
+       _nethack_app.mapTile_Y = TILE_Y;
+       _nethack_app.mapTilesPerLine = TILES_PER_LINE;
+       _nethack_app.bNoHScroll = FALSE;
+       _nethack_app.bNoVScroll = FALSE;
+
+#if  defined(WIN_CE_PS2xx) || defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
+       _nethack_app.bCmdPad = TRUE;
+#else
+       _nethack_app.bCmdPad = FALSE;
+#endif
+
+       _nethack_app.bWrapText = TRUE;
+       _nethack_app.bFullScreen = TRUE;
+
+#if defined(WIN_CE_SMARTPHONE)
+       _nethack_app.bHideScrollBars = TRUE;
+#else
+       _nethack_app.bHideScrollBars = FALSE;
+#endif
+
+       _nethack_app.bUseSIP = TRUE;
+
+       // check for running nethack programs
+       nethackWnd = FindWindow(szMainWindowClass, NULL);
+       if( nethackWnd ) {
+               // bring on top
+               SetForegroundWindow(nethackWnd);
+               return FALSE;
+       }
+
+       // init controls
+       ZeroMemory(&InitCtrls, sizeof(InitCtrls));
+       InitCtrls.dwSize = sizeof(InitCtrls);
+       InitCtrls.dwICC = ICC_LISTVIEW_CLASSES;
+       if( !InitCommonControlsEx(&InitCtrls) ) {
+               MessageBox(NULL, TEXT("Cannot init common controls"), TEXT("ERROR"), MB_OK | MB_ICONSTOP);
+               return FALSE;
+       }
+
+       // Perform application initialization:
+       if (!InitInstance (hInstance, nCmdShow)) 
+       {
+               return FALSE;
+       }
+
+       /* get command line parameters */       
+       p = _get_cmd_arg(
+#if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO)
+               lpCmdLine
+#else
+               GetCommandLine()
+#endif
+               );
+       for( argc = 1; p && argc<MAX_CMDLINE_PARAM; argc++ ) {
+               len = _tcslen(p);
+               if( len>0 ) {
+                       argv[argc] = _strdup( NH_W2A(p, buf, BUFSZ) );
+               } else {
+                       argv[argc] = "";
+               }
+               p = _get_cmd_arg(NULL);
+       }
+       GetModuleFileName(NULL, wbuf, BUFSZ);
+       argv[0] = _strdup(NH_W2A(wbuf, buf, BUFSZ));
+
+       pcmain(argc,argv);
+
+       moveloop();
+
+       return 0;
+}
+
+//
+//   FUNCTION: InitInstance(HANDLE, int)
+//
+//   PURPOSE: Saves instance handle and creates main window
+//
+//   COMMENTS:
+//
+//        In this function, we save the instance handle in a global variable and
+//        create and display the main program window.
+//
+BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
+{
+   return TRUE;
+}
+
+PNHWinApp GetNHApp()
+{
+       return &_nethack_app;
+}
+
+static int
+eraseoldlocks()
+{
+       register int i;
+
+       /* cannot use maxledgerno() here, because we need to find a lock name
+        * before starting everything (including the dungeon initialization
+        * that sets astral_level, needed for maxledgerno()) up
+        */
+       for(i = 1; i <= MAXDUNGEON*MAXLEVEL + 1; i++) {
+               /* try to remove all */
+               set_levelfile_name(lock, i);
+               (void) unlink(fqname(lock, LEVELPREFIX, 0));
+       }
+       set_levelfile_name(lock, 0);
+       if(unlink(fqname(lock, LEVELPREFIX, 0)))
+               return 0;                               /* cannot remove it */
+       return(1);                                      /* success! */
+}
+
+void
+getlock()
+{
+       const char *fq_lock;
+       char tbuf[BUFSZ];
+       TCHAR wbuf[BUFSZ];
+       HANDLE f;
+       int fd;
+       int choice;
+
+       /* regularize(lock); */ /* already done in pcmain */
+       Sprintf(tbuf, "%s", fqname(lock, LEVELPREFIX, 0));
+       set_levelfile_name(lock, 0);
+       fq_lock = fqname(lock, LEVELPREFIX, 1);
+
+       f = CreateFile(
+                       NH_A2W(fq_lock, wbuf, BUFSZ),
+                       GENERIC_READ,
+                       0,
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_ATTRIBUTE_NORMAL,
+                       NULL);
+       if( f==INVALID_HANDLE_VALUE ) {
+               if(GetLastError()==ERROR_FILE_NOT_FOUND) goto gotlock;    /* no such file */
+               error("Cannot open %s", fq_lock);
+       }
+
+       CloseHandle(f);
+
+       /* prompt user that the game alredy exist */
+       choice = MessageBox(
+               GetNHApp()->hMainWnd,
+               TEXT("There are files from a game in progress under your name. Recover?"),
+               TEXT("Nethack"),
+               MB_YESNO | MB_DEFBUTTON1 
+               );
+       switch(choice) {
+       case IDYES:
+               if(recover_savefile()) {
+                       goto gotlock;
+               } else {
+                       error("Couldn't recover old game.");
+               }
+               break;
+
+       case IDNO: 
+               unlock_file(HLOCK);
+               error("%s", "Cannot start a new game.");
+               break;
+       };
+
+gotlock:
+       fd = creat(fq_lock, FCMASK);
+       if(fd == -1) {
+               error("cannot creat lock file (%s.)", fq_lock);
+       } else {
+               if(write(fd, (char *) &hackpid, sizeof(hackpid))
+                   != sizeof(hackpid)){
+                       error("cannot write lock (%s)", fq_lock);
+               }
+               if(close(fd) == -1) {
+                       error("cannot close lock (%s)", fq_lock);
+               }
+       }
+}
+
+/* misc functions */
+void
+error VA_DECL(const char *,s)
+       TCHAR  wbuf[1024];
+       char   buf[1024];
+       DWORD last_error = GetLastError();
+
+       VA_START(s);
+       VA_INIT(s, const char *);
+       /* error() may get called before tty is initialized */
+       if (iflags.window_inited) end_screen();
+       
+       vsprintf(buf, s, VA_ARGS);
+       NH_A2W(buf, wbuf, sizeof(wbuf)/sizeof(wbuf[0]));
+       if( last_error>0 ) {
+               LPVOID lpMsgBuf;
+               if( FormatMessage( 
+                               FORMAT_MESSAGE_ALLOCATE_BUFFER | 
+                               FORMAT_MESSAGE_FROM_SYSTEM | 
+                               FORMAT_MESSAGE_IGNORE_INSERTS,
+                               NULL,
+                               last_error,
+                               0, // Default language
+                               (LPTSTR) &lpMsgBuf,
+                               0,
+                               NULL 
+                       )
+                       )
+               {
+                       
+                       _tcsncat(wbuf, TEXT("\nSystem Error: "), sizeof(wbuf)/sizeof(wbuf[0]) - _tcslen(wbuf) );
+                       _tcsncat(wbuf, lpMsgBuf, sizeof(wbuf)/sizeof(wbuf[0]) - _tcslen(wbuf) );
+
+                       // Free the buffer.
+                       LocalFree( lpMsgBuf );
+               }
+       }
+       VA_END();
+
+       MessageBox( NULL, wbuf, TEXT("Error"), MB_OK | MB_ICONERROR );
+       
+       exit(EXIT_FAILURE);
+}
+
+TCHAR* _get_cmd_arg(TCHAR* pCmdLine)
+{
+    static TCHAR* pArgs = NULL;
+    TCHAR  *pRetArg;
+    BOOL   bQuoted;
+
+    if( !pCmdLine && !pArgs ) return NULL;
+    if( !pArgs ) pArgs = pCmdLine;
+
+    /* skip whitespace */
+    for(pRetArg = pArgs; *pRetArg && _istspace(*pRetArg); pRetArg = CharNext(pRetArg));
+       if( !*pRetArg ) {
+               pArgs = NULL;
+               return NULL;
+       }
+
+    /* check for quote */
+    if( *pRetArg==TEXT('"') ) {
+            bQuoted = TRUE;
+            pRetArg = CharNext(pRetArg);
+                       pArgs = _tcschr(pRetArg, TEXT('"'));
+       } else {
+               /* skip to whitespace */
+               for(pArgs = pRetArg; *pArgs && !_istspace(*pArgs); pArgs = CharNext(pArgs));
+       }
+       
+       if( pArgs && *pArgs ) {
+               TCHAR* p;
+               p = pArgs;
+               pArgs = CharNext(pArgs);
+               *p = (TCHAR)0;
+       } else {
+               pArgs = NULL;
+       }
+
+       return pRetArg;
+}
+
+/* 
+ * Strip out troublesome file system characters.
+ */
+
+void
+nt_regularize(s)       /* normalize file name */
+register char *s;
+{
+       register unsigned char *lp;
+
+       for (lp = s; *lp; lp++)
+           if ( *lp == '?' || *lp == '"' || *lp == '\\' ||
+                *lp == '/' || *lp == '>' || *lp == '<'  ||
+                *lp == '*' || *lp == '|' || *lp == ':'  || (*lp > 127))
+                       *lp = '_';
+}
+
+void win32_abort()
+{
+
+#ifdef WIZARD
+       if (wizard)
+               DebugBreak();
+#endif
+       abort();
+}
+
+void
+append_port_id(buf)
+char *buf;
+{
+       char *portstr = PORT_CE_PLATFORM " " PORT_CE_CPU;
+       Sprintf(eos(buf), " %s", portstr);
+}
+
diff --git a/sys/wince/winhack.rc b/sys/wince/winhack.rc
new file mode 100644 (file)
index 0000000..0240fc8
--- /dev/null
@@ -0,0 +1,370 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "newres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_WINHACK             ICON    DISCARDABLE     "..\\..\\wince\\NETHACK.ICO"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menubar
+//
+
+IDC_WINHACK MENU DISCARDABLE 
+BEGIN
+    POPUP "File"
+    BEGIN
+        MENUITEM "&Save",                       IDM_SAVE
+        MENUITEM SEPARATOR
+        MENUITEM "&Quit",                       IDM_EXIT
+    END
+    POPUP "Map"
+    BEGIN
+        MENUITEM "&0 - Use Tiles",              IDM_MAP_TILES
+        MENUITEM "&1 - ASCII (4x6)",            IDM_MAP_ASCII4X6
+        MENUITEM "&2 - ASCII (6x8)",            IDM_MAP_ASCII6X8
+        MENUITEM "&3 - ASCII (8x8)",            IDM_MAP_ASCII8X8
+        MENUITEM "&4 - ASCII (16x8)",           IDM_MAP_ASCII16X8
+        MENUITEM "&5 - ASCII (7x12)",           IDM_MAP_ASCII7X12
+        MENUITEM "&6 - ASCII  (8x12)",          IDM_MAP_ASCII8X12
+        MENUITEM "&7 - ASCII (16x12)",          IDM_MAP_ASCII16X12
+        MENUITEM "&8 - ASCII (12x16)",          IDM_MAP_ASCII12X16
+        MENUITEM "&9 - ASCII  (10x18)",         IDM_MAP_ASCII10X18
+        MENUITEM SEPARATOR
+        MENUITEM "&Fit To Screen",              IDM_MAP_FIT_TO_SCREEN
+    END
+    POPUP "View"
+    BEGIN
+        MENUITEM "&Keypad",                     IDM_VIEW_KEYPAD
+        MENUITEM "&Options",                    IDM_VIEW_OPTIONS
+    END
+    POPUP "Help"
+    BEGIN
+        MENUITEM "&About ...",                  IDM_ABOUT
+        MENUITEM "&Long description of the game", IDM_HELP_LONG
+        MENUITEM "List of &commands",           IDM_HELP_COMMANDS
+        MENUITEM "&History of NetHack",         IDM_HELP_HISTORY
+        MENUITEM "&Info on a character",        IDM_HELP_INFO_CHAR
+        MENUITEM "Info on what a given &key does", IDM_HELP_INFO_KEY
+        MENUITEM "List of game &options",       IDM_HELP_OPTIONS
+        MENUITEM "&Longer list of game options", IDM_HELP_OPTIONS_LONG
+        MENUITEM "List of e&xtended commands",  IDM_HELP_EXTCMD
+        MENUITEM "The &NetHack license",        IDM_HELP_LICENSE
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDC_WINHACK ACCELERATORS MOVEABLE PURE 
+BEGIN
+    "?",            IDM_ABOUT,              ASCII,  ALT
+    "/",            IDM_ABOUT,              ASCII,  ALT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOG DISCARDABLE  22, 17, 123, 87
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About"
+FONT 8, "System"
+BEGIN
+    LTEXT           "NetHack",IDC_ABOUT_VERSION,0,2,120,15,SS_NOPREFIX
+    LTEXT           "Copyright",IDC_ABOUT_COPYRIGHT,0,20,120,50
+    DEFPUSHBUTTON   "OK",IDOK,45,75,30,11,WS_GROUP
+END
+
+IDD_MENU DIALOG DISCARDABLE  0, 0, 109, 153
+STYLE WS_CHILD | WS_CLIPSIBLINGS | WS_BORDER
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,5,130,50,14,BS_NOTIFY
+    PUSHBUTTON      "Cancel",IDCANCEL,55,130,50,14,BS_NOTIFY
+    CONTROL         "List1",IDC_MENU_LIST,"SysListView32",WS_BORDER | 
+                    WS_TABSTOP,5,5,100,60
+    EDITTEXT        IDC_MENU_TEXT,5,70,100,55,ES_MULTILINE | ES_READONLY | 
+                    WS_VSCROLL | WS_HSCROLL
+END
+
+IDD_GETLIN DIALOG DISCARDABLE  0, 0, 115, 30
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Question?"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,0,16,55,14
+    PUSHBUTTON      "Cancel",IDCANCEL,55,16,60,14
+    EDITTEXT        IDC_GETLIN_EDIT,0,0,115,15,ES_AUTOHSCROLL
+END
+
+IDD_PLAYER_SELECTOR DIALOG DISCARDABLE  0, 0, 105, 124
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "What are you?"
+FONT 8, "MS Sans Serif"
+BEGIN
+    EDITTEXT        IDC_PLSEL_NAME,35,0,70,12,ES_AUTOHSCROLL | ES_READONLY
+    LTEXT           "Name:",IDC_STATIC,0,0,25,10
+    CONTROL         "Random",IDC_PLSEL_ROLE_RANDOM,"Button",BS_AUTOCHECKBOX | 
+                    BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,20,40,10
+    COMBOBOX        IDC_PLSEL_ROLE_LIST,50,20,50,50,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_GROUP | WS_TABSTOP
+    CONTROL         "Random",IDC_PLSEL_RACE_RANDOM,"Button",BS_AUTOCHECKBOX | 
+                    BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,45,40,10
+    COMBOBOX        IDC_PLSEL_RACE_LIST,50,45,50,45,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_GROUP | WS_TABSTOP
+    CONTROL         "Random",IDC_PLSEL_GENDER_RANDOM,"Button",
+                    BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,70,
+                    40,10
+    COMBOBOX        IDC_PLSEL_GENDER_LIST,50,70,50,40,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_GROUP | WS_TABSTOP
+    CONTROL         "Random",IDC_PLSEL_ALIGN_RANDOM,"Button",BS_AUTOCHECKBOX | 
+                    BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,95,40,10
+    COMBOBOX        IDC_PLSEL_ALIGN_LIST,50,95,50,45,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_GROUP | WS_TABSTOP
+    GROUPBOX        "Role",IDC_STATIC,0,10,105,25,WS_GROUP
+    GROUPBOX        "Race",IDC_STATIC,0,35,105,25
+    GROUPBOX        "Gender",IDC_STATIC,0,60,105,25
+    GROUPBOX        "Alignment",IDC_STATIC,0,85,105,25
+    DEFPUSHBUTTON   "Play",IDOK,0,110,55,14
+    PUSHBUTTON      "Quit",IDCANCEL,55,110,50,14
+END
+
+IDD_NHTEXT DIALOG DISCARDABLE  0, 0, 83, 97
+STYLE WS_CHILD | WS_BORDER
+FONT 8, "System"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,15,80,50,14
+    EDITTEXT        IDC_TEXT_CONTROL,5,0,70,75,ES_MULTILINE | ES_READONLY | 
+                    WS_VSCROLL | WS_HSCROLL
+END
+
+IDD_EXTCMD DIALOG DISCARDABLE  0, 0, 109, 114
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Extended Commands"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,75,5,30,14
+    PUSHBUTTON      "Cancel",IDCANCEL,75,20,30,14
+    LISTBOX         IDC_EXTCMD_LIST,5,5,65,105,LBS_NOINTEGRALHEIGHT | 
+                    WS_VSCROLL | WS_TABSTOP
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#include ""newres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "resource.h\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_TILES               BITMAP  DISCARDABLE     "..\\..\\wince\\tiles.bmp"
+IDB_MENU_SEL            BITMAP  DISCARDABLE     "..\\..\\wince\\mnsel.bmp"
+IDB_MENU_UNSEL          BITMAP  DISCARDABLE     "..\\..\\wince\\mnunsel.bmp"
+IDB_PETMARK             BITMAP  DISCARDABLE     "..\\..\\wince\\petmark.bmp"
+IDB_MENU_SEL_COUNT      BITMAP  DISCARDABLE     "..\\..\\wince\\mnselcnt.bmp"
+IDB_KEYPAD              BITMAP  DISCARDABLE     "..\\..\\wince\\keypad.bmp"
+IDB_MENUBAR             BITMAP  DISCARDABLE     "..\\..\\wince\\menubar.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE 
+BEGIN
+    IDD_PLAYER_SELECTOR, DIALOG
+    BEGIN
+        RIGHTMARGIN, 98
+        BOTTOMMARGIN, 117
+    END
+
+    IDD_NHTEXT, DIALOG
+    BEGIN
+        LEFTMARGIN, 5
+        RIGHTMARGIN, 76
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 94
+    END
+
+    IDD_EXTCMD, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 102
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 107
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Data
+//
+
+IDC_WINHACK SHMENUBAR DISCARDABLE 
+BEGIN
+    IDC_WINHACK, 6,
+    I_IMAGENONE, ID_FILE, TBSTATE_ENABLED, 
+    TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_FILE, 0, 0,
+    I_IMAGENONE, ID_MAP, TBSTATE_ENABLED, 
+    TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_MAP, 0, 1,
+    I_IMAGENONE, ID_VIEW, TBSTATE_ENABLED, 
+    TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_VIEW, 0, 2,
+    I_IMAGENONE, ID_HELP, TBSTATE_ENABLED, 
+    TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_HELP, 0, 3,
+    0, IDM_MAP_FIT_TO_SCREEN, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 
+    IDM_MAP_FIT_TO_SCREEN, NOMENU,
+    1, IDM_VIEW_KEYPAD, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 
+    IDM_VIEW_KEYPAD, NOMENU,
+END
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 3,4,2,0
+ PRODUCTVERSION 3,4,2,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x9L
+#else
+ FILEFLAGS 0x8L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "Comments", "NetHack 3.4.3 for Windows CE\0"
+            VALUE "CompanyName", " \0"
+            VALUE "FileDescription", "nethackm\0"
+            VALUE "FileVersion", "3, 4, 3, 0\0"
+            VALUE "InternalName", "nethackm\0"
+            VALUE "LegalCopyright", "Copyright © 2003\0"
+            VALUE "LegalTrademarks", "\0"
+            VALUE "OriginalFilename", "nethackm.exe\0"
+            VALUE "PrivateBuild", "031014\0"
+            VALUE "ProductName", "NetHack\0"
+            VALUE "ProductVersion", "3, 4, 3, 0\0"
+            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+#endif    // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDS_APP_TITLE           "NetHack"
+    IDC_WINHACK             "NETHACK"
+END
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDM_MAP_FIT_TO_SCREEN   "Fit to Screen"
+    IDS_CAP_FILE            "File"
+    IDS_CAP_HELP            "Help"
+    IDS_CAP_MAP             "Map"
+END
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDM_VIEW_KEYPAD         "Show/Hide keypad."
+    IDS_CAP_VIEW            "View"
+END
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDOK                    "Done"
+    IDCANCEL                "Cancel"
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/sys/wince/winhcksp.rc b/sys/wince/winhcksp.rc
new file mode 100644 (file)
index 0000000..39f3dbb
--- /dev/null
@@ -0,0 +1,346 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "newres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_WINHACK             ICON    DISCARDABLE     "..\\..\\wince\\NETHACK.ICO"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menubar
+//
+
+IDC_WINHACK MENU DISCARDABLE 
+BEGIN
+    MENUITEM "Entire Map",                  IDM_MAP_FIT_TO_SCREEN
+    POPUP "Menu"
+    BEGIN
+        MENUITEM "Options",                     IDM_VIEW_OPTIONS
+        MENUITEM "Keypad",                      IDM_VIEW_KEYPAD
+        MENUITEM SEPARATOR
+        MENUITEM "ASCII",                       IDM_MAP_ASCII8X8
+        MENUITEM "Use Tiles",                   IDM_MAP_TILES
+        MENUITEM SEPARATOR
+        MENUITEM "Help",                        IDM_HELP_MENU
+        MENUITEM "Save",                        IDM_SAVE
+        MENUITEM "Quit",                        IDM_EXIT
+    END
+END
+
+IDC_SPHONE_DIALOGBAR MENU DISCARDABLE 
+BEGIN
+    MENUITEM "Done",                        IDOK
+    MENUITEM "Cancel",                      IDCANCEL
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDC_WINHACK ACCELERATORS MOVEABLE PURE 
+BEGIN
+    "?",            IDM_ABOUT,              ASCII,  ALT
+    "/",            IDM_ABOUT,              ASCII,  ALT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOG DISCARDABLE  22, 17, 123, 87
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About"
+FONT 8, "System"
+BEGIN
+    LTEXT           "NetHack",IDC_ABOUT_VERSION,0,2,120,15,SS_NOPREFIX
+    LTEXT           "Copyright",IDC_ABOUT_COPYRIGHT,0,20,120,50
+    DEFPUSHBUTTON   "OK",IDOK,45,75,30,11,WS_GROUP
+END
+
+IDD_MENU DIALOG DISCARDABLE  0, 0, 109, 131
+STYLE DS_SETFOREGROUND | DS_CONTROL | WS_POPUP | WS_CLIPSIBLINGS | WS_BORDER
+FONT 8, "MS Sans Serif"
+BEGIN
+    CONTROL         "List1",IDC_MENU_LIST,"SysListView32",WS_BORDER | 
+                    WS_TABSTOP,5,5,100,60
+    EDITTEXT        IDC_MENU_TEXT,5,70,100,55,ES_MULTILINE | ES_READONLY | 
+                    WS_VSCROLL | WS_HSCROLL
+END
+
+IDD_NHTEXT DIALOG DISCARDABLE  0, 0, 83, 83
+STYLE WS_POPUP | WS_BORDER
+FONT 8, "System"
+BEGIN
+    EDITTEXT        IDC_TEXT_CONTROL,5,0,70,75,ES_MULTILINE | ES_READONLY | 
+                    WS_VSCROLL | WS_HSCROLL
+END
+
+IDD_EXTCMD DIALOG DISCARDABLE  0, 0, 88, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Extended Commands"
+FONT 8, "MS Sans Serif"
+BEGIN
+    LISTBOX         IDC_EXTCMD_LIST,7,5,75,69,LBS_NOINTEGRALHEIGHT | 
+                    WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_GETLIN DIALOG DISCARDABLE  0, 0, 115, 16
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Question?"
+FONT 8, "MS Sans Serif"
+BEGIN
+    EDITTEXT        IDC_GETLIN_EDIT,0,0,115,15,ES_AUTOHSCROLL
+END
+
+IDD_PLAYER_SELECTOR DIALOG DISCARDABLE  0, 0, 105, 124
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "What are you?"
+FONT 8, "MS Sans Serif"
+BEGIN
+    EDITTEXT        IDC_PLSEL_NAME,35,0,70,12,ES_AUTOHSCROLL | ES_READONLY
+    LTEXT           "Name:",IDC_STATIC,0,0,25,10
+    CONTROL         "Random",IDC_PLSEL_ROLE_RANDOM,"Button",BS_AUTOCHECKBOX | 
+                    BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,20,40,10
+    COMBOBOX        IDC_PLSEL_ROLE_LIST,50,20,50,50,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_GROUP | WS_TABSTOP
+    CONTROL         "Random",IDC_PLSEL_RACE_RANDOM,"Button",BS_AUTOCHECKBOX | 
+                    BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,45,40,10
+    COMBOBOX        IDC_PLSEL_RACE_LIST,50,45,50,45,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_GROUP | WS_TABSTOP
+    CONTROL         "Random",IDC_PLSEL_GENDER_RANDOM,"Button",
+                    BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,70,
+                    40,10
+    COMBOBOX        IDC_PLSEL_GENDER_LIST,50,70,50,40,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_GROUP | WS_TABSTOP
+    CONTROL         "Random",IDC_PLSEL_ALIGN_RANDOM,"Button",BS_AUTOCHECKBOX | 
+                    BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,95,40,10
+    COMBOBOX        IDC_PLSEL_ALIGN_LIST,50,95,50,45,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_GROUP | WS_TABSTOP
+    GROUPBOX        "Role",IDC_STATIC,0,10,105,25,WS_GROUP
+    GROUPBOX        "Race",IDC_STATIC,0,35,105,25
+    GROUPBOX        "Gender",IDC_STATIC,0,60,105,25
+    GROUPBOX        "Alignment",IDC_STATIC,0,85,105,25
+    DEFPUSHBUTTON   "Play",IDOK,0,110,55,14
+    PUSHBUTTON      "Quit",IDCANCEL,55,110,50,14
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#include ""newres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "resource.h\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_TILES               BITMAP  DISCARDABLE     "..\\..\\wince\\tiles.bmp"
+IDB_MENU_SEL            BITMAP  DISCARDABLE     "..\\..\\wince\\mnsel.bmp"
+IDB_MENU_UNSEL          BITMAP  DISCARDABLE     "..\\..\\wince\\mnunsel.bmp"
+IDB_PETMARK             BITMAP  DISCARDABLE     "..\\..\\wince\\petmark.bmp"
+IDB_MENU_SEL_COUNT      BITMAP  DISCARDABLE     "..\\..\\wince\\mnselcnt.bmp"
+IDB_KEYPAD              BITMAP  DISCARDABLE     "..\\..\\wince\\keypad.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE 
+BEGIN
+    IDD_NHTEXT, DIALOG
+    BEGIN
+        LEFTMARGIN, 5
+        RIGHTMARGIN, 76
+        TOPMARGIN, 7
+    END
+
+    IDD_EXTCMD, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 82
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 75
+    END
+
+    IDD_PLAYER_SELECTOR, DIALOG
+    BEGIN
+        RIGHTMARGIN, 98
+        BOTTOMMARGIN, 117
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Data
+//
+
+IDC_WINHACK SHMENUBAR DISCARDABLE 
+BEGIN
+    IDC_WINHACK, 2,
+    I_IMAGENONE, IDM_MAP_FIT_TO_SCREEN, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, IDM_MAP_FIT_TO_SCREEN, 0, NOMENU, 
+    I_IMAGENONE, ID_VIEW, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_VIEW, 0, 1,
+END
+
+IDC_SPHONE_DIALOGBAR SHMENUBAR DISCARDABLE 
+BEGIN
+    IDC_SPHONE_DIALOGBAR, 2,
+    I_IMAGENONE, IDOK, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, IDOK, 0, NOMENU,
+    I_IMAGENONE, IDCANCEL, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, IDCANCEL, 0, 
+    NOMENU,
+END
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 3,4,2,0
+ PRODUCTVERSION 3,4,2,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x9L
+#else
+ FILEFLAGS 0x8L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "Comments", "NetHack 3.4.3 for Smartphone 2002\0"
+            VALUE "CompanyName", " \0"
+            VALUE "FileDescription", "nethackm\0"
+            VALUE "FileVersion", "3, 4, 3, 0\0"
+            VALUE "InternalName", "nethackm\0"
+            VALUE "LegalCopyright", "Copyright © 2003\0"
+            VALUE "LegalTrademarks", "\0"
+            VALUE "OriginalFilename", "nethackm.exe\0"
+            VALUE "PrivateBuild", "031014\0"
+            VALUE "ProductName", "NetHack For Smartphone\0"
+            VALUE "ProductVersion", "3, 4, 3, 0\0"
+            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+#endif    // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDS_APP_TITLE           "NetHack"
+    IDC_WINHACK             "NETHACK"
+END
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDM_MAP_FIT_TO_SCREEN   "Entire Map"
+    IDS_CAP_FILE            "File"
+    IDS_CAP_HELP            "Help"
+    IDS_CAP_MAP             "Map"
+END
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDM_VIEW_KEYPAD         "Show/Hide keypad."
+    IDS_CAP_VIEW            "Menu"
+END
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDOK                    "Done"
+    IDCANCEL                "Cancel"
+END
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDS_CAP_ENTIREMAP       "Entire Map"
+    IDS_CAP_NORMALMAP       "Normal Map"
+    IDM_HELP_MENU           "Help Menu"
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/sys/wince/winmain.c b/sys/wince/winmain.c
new file mode 100644 (file)
index 0000000..0bb3d67
--- /dev/null
@@ -0,0 +1,110 @@
+// winmain.cpp : Defines the entry point for the application.
+
+#include "winMS.h"
+#include <string.h>
+
+#define MAX_CMDLINE_PARAM 255
+
+extern int  FDECL (main, (int,char **));
+static TCHAR* _get_cmd_arg(TCHAR* pCmdLine);
+
+int APIENTRY WinMain(HINSTANCE hInstance,
+                     HINSTANCE hPrevInstance,
+                     LPWSTR     lpCmdLine,
+                     int       nCmdShow)
+{
+       int argc;
+       char* argv[MAX_CMDLINE_PARAM];
+       size_t len;
+       TCHAR* p;
+       TCHAR wbuf[NHSTR_BUFSIZE];
+       char buf[NHSTR_BUFSIZE];
+
+       /* get command line parameters */       
+       p = _get_cmd_arg(
+#if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO)
+               lpCmdLine
+#else
+               GetCommandLine()
+#endif
+       );
+       for( argc = 1; p && argc<MAX_CMDLINE_PARAM; argc++ ) {
+               len = _tcslen(p);
+               if( len>0 ) {
+                       argv[argc] = _strdup( NH_W2A(p, buf, BUFSZ) );
+               } else {
+                       argv[argc] = "";
+               }
+               p = _get_cmd_arg(NULL);
+       }
+       GetModuleFileName(NULL, wbuf, BUFSZ);
+       argv[0] = _strdup(NH_W2A(wbuf, buf, BUFSZ));
+
+       main(argc, argv);
+
+       return 0;
+}
+
+TCHAR* _get_cmd_arg(TCHAR* pCmdLine)
+{
+    static TCHAR* pArgs = NULL;
+    TCHAR  *pRetArg;
+    BOOL   bQuoted;
+
+    if( !pCmdLine && !pArgs ) return NULL;
+    if( !pArgs ) pArgs = pCmdLine;
+
+    /* skip whitespace */
+    for(pRetArg = pArgs; *pRetArg && _istspace(*pRetArg); pRetArg = CharNext(pRetArg));
+       if( !*pRetArg ) {
+               pArgs = NULL;
+               return NULL;
+       }
+
+    /* check for quote */
+    if( *pRetArg==TEXT('"') ) {
+        bQuoted = TRUE;
+        pRetArg = CharNext(pRetArg);
+               pArgs = _tcschr(pRetArg, TEXT('"'));
+       } else {
+               /* skip to whitespace */
+               for(pArgs = pRetArg; *pArgs && !_istspace(*pArgs); pArgs = CharNext(pArgs));
+       }
+       
+       if( pArgs && *pArgs ) {
+               TCHAR* p;
+               p = pArgs;
+               pArgs = CharNext(pArgs);
+               *p = (TCHAR)0;
+       } else {
+               pArgs = NULL;
+       }
+
+       return pRetArg;
+}
+
+#ifndef STRNCMPI
+char
+lowc(c)                        /* force 'c' into lowercase */
+    char c;
+{
+    return((char)(('A' <= c && c <= 'Z') ? (c | 040) : c));
+}
+
+int
+strncmpi(s1, s2, n)    /* case insensitive counted string comparison */
+    register const char *s1, *s2;
+    register int n; /*(should probably be size_t, which is usually unsigned)*/
+{                                      /*{ aka strncasecmp }*/
+    register char t1, t2;
+
+    while (n--) {
+       if (!*s2) return (*s1 != 0);    /* s1 >= s2 */
+       else if (!*s1) return -1;       /* s1  < s2 */
+       t1 = lowc(*s1++);
+       t2 = lowc(*s2++);
+       if (t1 != t2) return (t1 > t2) ? 1 : -1;
+    }
+    return 0;                          /* s1 == s2 */
+}
+#endif /* STRNCMPI */
diff --git a/sys/winnt/Install.nt b/sys/winnt/Install.nt
new file mode 100644 (file)
index 0000000..983f056
--- /dev/null
@@ -0,0 +1,450 @@
+         Copyright (c) NetHack Development Team 1990-2002
+         NetHack may be freely redistributed.  See license for details.
+         ==============================================================
+                 Instructions for compiling and installing
+             NetHack 3.4 on a Windows 9x, NT, 2000, or XP system
+         ==============================================================
+                 Last revision: $Date: 2003/10/14 01:31:25 $
+
+Credit for the porting of NetHack to the Win32 Console Subsystem goes to 
+the NT Porting Team started by Michael Allison.
+
+Credit for the Win32 Graphical version of NetHack (aka "NetHack for
+Windows" or NetHackW) goes to Alex Kompel who initially developed and
+contributed the port.
+
+The PC Windows porting team consisting of Michael Allison, David Cohrs, 
+Alex Kompel, Dion Nicolaas, Yitzhak Sapir, and Janet Walz maintained the 
+tty and graphical win32 versions of NetHack 3.4.3.
+
+You can build either the TTY version of NetHack or the Windows Graphical 
+version.  In either case you can use one of the following build
+environments:
+
+  o A copy of Microsoft Visual C V6.0 SP3 or later.  Things may work with 
+    an earlier version of the compiler, but the current code has not
+    been tested with an earlier version.
+               
+       OR
+
+  o A copy of Borland C 5.5.1 command line tools.  Borland has made a
+    version of its command line tools available for download after
+    registration at:
+        http://www.borland.com/bcppbuilder/freecompiler/
+
+    OR
+
+  o A copy of MinGW 2.0. MinGW is a collection of header files and import
+    libraries with which native Windows32 programs can be made; the
+    MinGW 2.0 distribution contains the GNU Compiler Collection.
+    You can download MinGW at
+        http://www.mingw.org/
+    Earlier versions of MinGW will not allow you to build the Windows
+    Graphical version.
+    
+In addition to the makefiles that allow you to build NetHack from the
+command line, there is also a set of project files and a workspace file
+that allow you to build the Windows Graphical version from Microsoft
+Visual C's IDE (Integrated Development Environment.)
+
+
+FIRST STEP
+
+The first step in building either version of NetHack is to execute
+sys\winnt\nhsetup.bat.  
+
+From the command prompt:
+       cd sys\winnt
+       nhsetup
+
+From a Windows explorer window:
+       double-click on nhsetup.bat
+
+A "binary" directory will be created off the top of the NetHack source
+tree to house the completed build.
+
+A build subdirectory will also be created off the top of the NetHack 
+source tree, and many files appropriate for a graphical build will be 
+moved there.
+
+If you wish to build from the command line, proceed to "BUILDING FROM
+THE COMMAND LINE."
+If you wish to build using Visual C's IDE, proceed now to "BUILDING
+USING VISUAL C'S IDE."
+
+
+BUILDING FROM THE COMMAND LINE
+
+You can built two different versions of NetHack for Win32 from the
+command line:
+    A tty port utilizing the Win32 Console I/O subsystem, Console
+        NetHack;
+    A Win32 native port built on the Windows API, Graphical NetHack or
+        NetHackW.
+
+The executable for Console NetHack will be named NetHack.exe. The
+executable for Graphical NetHack will be named NetHackW.exe. You can opt
+to build both; they will be able to use the same datafiles, save files
+and bones files.
+
+I. Dispelling the Myths:
+
+    Compiling NetHack for Win32 is not as easy as it sounds, nor as hard
+    as it looks, however it will behoove you to read this entire section 
+    through before beginning the task.
+
+    We have provided a Makefile for each of the following compilers:
+
+        o Microsoft Visual C++ V6.0 SP3 or greater
+        o Borland C 5.5.1
+        o MinGW 2.0 (with GCC 3.2)
+
+    The Microsoft Visual C Makefile was created for use with MS NMAKE 
+    which is provided with the Microsoft compiler. The supplied Makefile
+    may work with earlier versions of the Microsoft 32-bit compiler, but 
+    that has not been tested. 
+
+    The Borland C Makefile was created for use with Borland MAKE which
+    is provided with the Borland compiler.
+
+    The GCC Makefile was created for use with GNU Make version 3.79.1,
+    which comes with the MinGW package.
+
+    You may find it useful to obtain copies of lex (flex) and yacc
+    (bison, or byacc).  While not strictly necessary to compile nethack,
+    they are required should you desire to make any changes to the level
+    and dungeon compilers.
+
+II. To compile your copy of NetHack on a Windows NT/2000/XP machine:
+
+Setting Up
+
+1.  It almost goes without saying that you should make sure that your
+    tools are set up and running correctly.  That includes ensuring that
+    all the necessary environment variables for the compiler environment
+    are set correctly.  (Examples: For the Microsoft compiler by
+    executing vcvars32.bat, which is probably in the bin directory of 
+    your compilers directory tree. For the Borland Makefile, you can 
+    simply invoke the Make utility from the Makefile's directory (For 
+    the standard Borland compiler installation you can just use the
+    explicit path "c:\borland\bcc55\bin\make /f Makefile.bcc".  For the
+    GCC Makefile, add <mingw>\bin to your path, where <mingw> is your
+    MinGW root directory.)
+
+2.  Make sure all the NetHack files are in the appropriate directory
+    structure.  You should have a main directory with subdirectories
+    dat, doc, include, src, sys\share, sys\winnt, util, and binary (The
+    "binary" directory was created by nhsetup.bat earlier if you
+    followed the steps appropriately).
+
+    For Console NetHack you need win\tty in addition to these; for
+    Graphical NetHack you need win\win32 in addition to these.
+
+    Other subdirectories may also be included in your distribution, but
+    they are not necessary for building the TTY version for the Win32 
+    console subsystem.  You can delete them to save space.
+
+    Required Directories for a Win32 Console NetHack:
+
+                            top
+                             |
+        ----------------------------------------------------/ /----- 
+        |       |     |        |       |     |          |        |
+       util    dat   doc    include   src   sys        win     binary
+                                             |          |
+                                          ------      ----- 
+                                          |    |      |    
+                                       share  winnt  tty  
+
+    Required Directories for a Win32 Graphical NetHack:
+
+                            top
+                             |
+        ----------------------------------------------------/ /----- 
+        |       |     |        |       |     |          |        |
+       util    dat   doc    include   src   sys        win     binary
+                                             |          |
+                                          ------      ----- 
+                                          |    |          |
+                                       share  winnt      win32 
+    Check the file "Files" in your top level directory for an exact
+    listing of what file is in which directory.  In order for the
+    Makefiles to work, all the source files must be in the proper
+    locations.
+
+    If you downloaded or ftp'd the sources from a UNIX system, the lines
+    will probably end in UNIX-style newlines, instead of the carriage
+    return and line feed pairs used by Windows.  Some programs have
+    trouble with them, so you may need to convert them. The compiler
+    should not have any problems with them however.
+
+3.  Now go to the include subdirectory to check a couple of the header
+    files there.  Things *should* work as they are, but since you have
+    probably set up your system in some sort of custom configuration it
+    doesn't hurt to check out the following:
+
+    First check config.h according to the comments to match your system
+    and desired set of features.  Mostly you need to check section 4 and
+    5.
+
+    You may include all or as few of the special game features as you
+    wish (they are located last in the file).
+
+4.  Edit your Makefile. 
+
+    For building Console NetHack, ensure that GRAPHICAL is set to "N",
+    or commented out. For building Graphical NetHack, set GRAPHICAL to
+    "Y".
+
+    Optional step:
+        If you elected not to use the high-quality BSD random number
+        routines by commenting out RANDOM in ntconf.h, comment out (or
+        set equal to nothing) the RANDOM macro in your Makefile.
+
+    If you are recompiling after patching your sources, or if you got
+    your files from somewhere other than the official distribution,
+    "touch makedefs.c" to ensure that certain files (onames.h and pm.h)
+    are remade, lest potentially troublesome timestamps fool your make
+    (or nmake) utility.
+
+Compiling
+
+5.  Now that everything is set up, change your current directory to src.
+
+    For Microsoft compiler: 
+        nmake install
+
+    For Borland compiler:
+        make /f Makefile.bcc install
+
+    For GCC:
+        mingw32-make -f Makefile.gcc install
+
+    If you get any errors along the way then something has not been set
+    up correctly. The time it takes to compile depends on your
+    particular machine of course, but you should be able to go for lunch
+    and return to find everything finished.  The less memory, and slower
+    your machine, the longer the lunch you may take. :-)
+    
+    In any case, it is likely that the command prompt window where you
+    are doing the compiling will be occupied for a while.  If all goes
+    well, you will get an NetHack executable.
+
+Notes:
+
+1.  To install an update of NetHack after changing something, change
+    your current directory to src and issue the appropriate command for
+    your compiler:
+
+    For Microsoft compiler: 
+        nmake
+
+    For Borland compiler:
+        make /f Makefile.bcc
+
+    For GCC:
+        mingw32-make -f Makefile.gcc
+
+    If you add, delete, or reorder monsters or objects, or you change
+    the format of saved level files, delete any save and bones files.
+    (Trying to use such files sometimes produces amusing confusions on
+    the game's part, but usually crashes.)
+
+    If you made changes to any of the level compiler software, you may
+    have to delete dgn_flex.c, dgn_yacc.c, lev_flex.c, and lev_yacc.c
+    from the util directory to ensure that they are remade.
+
+2.  The executable produced by the TTY build is a 32-bit, flat-address
+    space, non-overlayed .exe file, which should run on any true Win32
+    environment with console I/O support. 
+
+    The executable built by the graphical built is a 32-bit,
+    flat-address space, non-overlayed .exe file, which should run on any
+    true Win32 graphical environment.
+
+    To run NetHack, proceed to RUNNING NETHACK.
+
+
+BUILDING USING VISUAL C'S IDE
+
+Only the Win32 native port built on the Windows API, or Graphical
+NetHack, can be built using the Visual C IDE.
+
+I. Dispelling the Myths:
+
+    Compiling NetHack using the Visual C IDE is straightforward, as long
+    as you have your compiler and tools correctly installed.  
+
+    It is again assumed that you already changed your directory to
+    sys\winnt and executed:
+       nhsetup
+    as described at the top of this document. If you didn't, you must go
+    back and do so before proceeding.
+
+II. To compile your copy of NetHack for Windows on a Windows NT/2000/XP
+    machine using the Visual C IDE:
+
+Setting Up
+
+1.  It almost goes without saying that you should make sure that your
+    tools are set up and running correctly. (For the Microsoft Visual C
+    IDE it should correctly fire up when you choose it in your Start |
+    Programs menus.)
+
+2.  Make sure all the NetHack files are in the appropriate directory
+    structure.  You should have a main directory with subdirectories
+    dat, doc, include, src, sys\share, sys\winnt, util, win\win32, and
+    at this point you should also have a build directory and a binary
+    directory (both created by nhsetup.bat executed from sys\winnt
+    earlier.)
+
+    Other subdirectories may also be included in your distribution, but
+    they are not necessary for building the graphical version of NetHack
+    (you can delete them to save space if you wish.)
+
+    Required Directories for building Graphical NetHack with the Visual
+    C IDE:
+
+                            top
+                             |
+        -----------------------------------------/ /--------------- 
+        |     |    |      |     |   |      |           |       |
+       util  dat  doc  include src sys    win        build    binary
+                                    |      |
+                                  ------   -----
+                                  |    |       |    
+                               share  winnt  win32
+    Those last two (build and binary) are created during the building
+    process.  They are not disributed as part of the NetHack source 
+    distribution.  nhsetup.bat creates the build directory and moves a
+    few files into it, including the Visual C project files.  The
+    "binary" directory will house everything you need to play the game
+    after building is complete.
+
+    Check the file "Files" in your top level directory for an exact
+    listing of what file is in which directory.  In order for the build
+    process to work, all the source files must be in the proper
+    locations.  Remember that nhsetup.bat moves/copies many files around
+    to their intended locations for building NetHack.
+
+    If you downloaded or ftp'd the sources from a UNIX system, the lines
+    will probably end in UNIX-style newlines, instead of the carriage
+    return and line feed pairs used by Windows.  Visual C project files
+    and workspace files (dsp and dsw files) in particular need to have
+    their lines end in carriage-return-line-feed or they won't work
+    properly.
+
+3.  Ready your tool.
+    Note: It's possible to build a graphical version using the Makefile,
+    as explained above. However, the IDE build has full game
+    functionality and is the officially released build.
+
+    Start the Visual C IDE. In the Visual C IDE menus, choose:
+        File | Open Workspace
+
+4.  Set up for the build.
+
+    In the Visual C "Open Workspace" dialog box, navigate to the top of
+    your NetHack source directory.
+
+    In there, highlight "nethack.dsw" and click on Open.
+    Once the workspace has been opened, you should see the following
+    list in the Visual C selection window:
+      + dgncomp files
+      + dgnstuff files
+      + dlb_main files
+      + levcomp files
+      + levstuff files
+      + makedefs files
+      + nethackw files
+      + recover files
+      + tile2bmp files
+      + tilemap files
+      + uudecode files
+
+    On the Visual C menus, choose:
+        Project | Set Active Project | NetHackW
+
+    On the Visual C menus again, choose either:
+        Build | Set Active Configuration | NetHackW - Win32 Release
+    or
+        Build | Set Active Configuration | NetHackW - Win32 Debug
+
+    The first will create the Release build of NetHackW which does not
+    contain all the debugging information and is smaller, and runs
+    quicker.  The second will create the Debug build of NetHackW and
+    will spend a lot of time writing debug information to the disk as
+    the game is played. Unless you are debugging or enhancing NetHack
+    for Windows, choose the Release build.
+
+Building
+    
+5.  Start your build.
+
+    On the Visual C menus once again, choose:
+        Build | Build NetHackW.exe
+    This starts the build.  It is likely that the IDE message window 
+    where you are doing the compiling will be occupied for a while.
+
+6.  If all has gone well to this point, you should now have a NetHack
+    executable called NetHackW.exe in the "binary" directory, along with
+    all the support files that it needs.
+
+RUNNING NETHACK
+
+I. Checking the installation:
+    Make sure all of the support files -- Guidebook.txt, license,
+    Defaults.nh, NetHack.exe or NetHackW.exe, nhdat, and recover.exe --
+    were copied to the game directory.  If not, move them there
+    yourself.
+
+    Edit Defaults.nh to reflect your particular setup and personal 
+    preferences, by following the comments.  As with all releases since
+    3.2.1, HACKDIR defaults to the same directory as that where the
+    NetHack.exe or NetHackW.exe executable resides.  You only need to
+    set HACKDIR in defaults.nh if, for some reason, you wish to override
+    that (be careful).
+  
+II. Executing the game
+
+1.  Running from the command prompt:
+
+    If you add the directory containing the NetHack executable to your
+    PATH, you can just type "nethack" or "nethack -umike" or "nethackw"
+    or "nethackw -umike" to start it up.  Alternatively, you can
+    explicitly invoke it with a command such as
+    "c:\nethack\binary\nethack.exe" or "c:\nethack\binary\nethackw.exe"
+    (specifying whatever drive and directory your NetHack executable
+    resides in) each time.
+
+2.  Running from a Windows shortcut.
+
+    If you will be running it by launching it from a shortcut, just use
+    the following information when setting up the shortcut.
+
+        Description      :  NetHack 3.4.3 Console version
+        Command Line     :  C:\NETHACK\BINARY\NETHACK.EXE
+
+        Description      :  NetHack 3.4.3 Graphical Interface
+         Command Line     :  C:\NETHACK\BINARY\NETHACKW.EXE
+
+   (changing the directory to the appropriate one of course)
+
+III. Play NetHack.  If it works, you're done!
+
+
+PROBLEMS
+
+    If you discover a bug and wish to report it, or if you have comments
+    or suggestions we recommend using our "Contact Us" web page at:
+        http://www.nethack.org/common/contact.html
+
+    If you don't have access to the web, or you want to send us a patch
+    to the NetHack source code feel free to drop us a line c/o:
+        DevTeam (at) nethack.org
+
+    Happy NetHacking!
diff --git a/sys/winnt/Makefile.bcc b/sys/winnt/Makefile.bcc
new file mode 100644 (file)
index 0000000..c734afe
--- /dev/null
@@ -0,0 +1,1378 @@
+#   SCCS Id: @(#)Makefile.bcc       3.4     $Date: 2003/11/16 04:50:56 $
+#   Copyright (c) NetHack PC Development Team 1993-2003
+#
+#
+# IMPORTANT NOTE: This Makefile has not been tested for 3.4.3.
+#
+#
+#   NetHack 3.4.x Makefile for Borland C++ V5.5.1 and above and Borland's MAKE
+#  
+#   Win32 Compilers Tested:
+#                              - Borland C++ 5.5.1 for Win32
+#
+#   If you don't have this compiler, you can get it at:
+#       http://www.borland.com/bcppbuilder/freecompiler/
+#
+#   This makefile is set up to assume the directories are extracted at the
+#   root, but this can be changed by modifying the bccroot and related
+#   variables.
+#
+#   This is used for building two versions of NetHack:
+#   A tty port utilizing the Win32 Console I/O subsystem, Console
+#       NetHack;
+#   A Win32 native port built on the Windows API, Graphical NetHack or
+#       NetHackW.
+#
+#   In addition to your C compiler,
+#
+#     if you want to change     you will need a
+#     files with suffix         workalike for
+#              .y                   yacc   (such as bison)
+#              .l                   lex    (such as flex)
+#
+#
+#   If you have any questions read the sys/winnt/Install.nt file included 
+#   with the distribution.
+#
+#   --
+#   Yitzhak Sapir
+#==============================================================================
+# Do not delete the following 3 lines.
+#
+TARGETOS=BOTH
+APPVER=4.0
+
+bccbin = $(MAKEDIR)
+bccroot = $(MAKEDIR)\..
+bccinc = $(bccroot)\include
+bcclib = $(bccroot)\lib
+
+!IFNDEF APPVER
+APPVER = 4.0
+!ENDIF
+
+# Graphical interface
+# Set to Y for a graphical version
+# Set to anything else (or undefine) for a tty version
+
+#GRAPHICAL = Y
+
+# Debug
+# Set to Y for Debug support (to produce full map files, listing files, and debug information)
+# Set to anything else (or undefine) for a "release" version
+
+DEBUG = Y
+
+!IF "$(APPVER)" == "4.0"
+MAKE_WINVER = 0x0400
+!ELSEIF "$(APPVER)" == "5.0"
+MAKE_WINVER = 0x0500
+!ENDIF
+
+cc     = $(bccbin)\bcc32
+rc     = $(bccbin)\brc32
+link   = $(bccbin)\ilink32
+implib = $(bccbin)\tlib
+
+cflags = -c -D_X86_=1 -DWINVER=$(MAKE_WINVER) -q -I$(bccinc) -w-pia -w-rch -w-csu -w-par -w-aus
+cdebug = -y -v -O2
+cvarsmt  = -DWIN32 -D_WIN32 -D_MT 
+lflags  = 
+!IF "$(DEBUG)" == "Y"
+linkdebug = /v /m /s 
+cdebug = -v -y -Q
+!ELSE
+linkdebug = /C /Gn
+cdebug =
+!ENDIF
+startobj = $(bcclib)\c0x32.obj
+!IF "$(GRAPHICAL)" == "Y"
+verlflags = /Gn /Gz /q -L$(bcclib) /c  /Tpe /V$(APPVER)
+startobjg = $(bcclib)\c0w32.obj
+!ELSE
+verlflags = /Gn /Gz /q -L$(bcclib) /c  /ap /Tpe /V$(APPVER)
+startobjg = $(startobj)
+!ENDIF
+libsmt  = $(bcclib)\cw32mt.lib $(bcclib)\import32.lib 
+
+#
+#  Set the gamedir according to your preference.  
+#  It must be present prior to compilation.
+
+!IF "$(GRAPHICAL)" == "Y"
+GAME    = NetHackW                # Game Name
+!ELSE
+GAME    = NetHack                 # Game Name
+!ENDIF
+GAMEDIR = ..\binary               # Game directory
+
+#
+#  Source directories.    Makedefs hardcodes these, don't change them.
+#
+
+INCL  = ..\include   # NetHack include files
+DAT   = ..\dat       # NetHack data files
+DOC   = ..\doc       # NetHack documentation files
+UTIL  = ..\util      # Utility source
+SRC   = ..\src       # Main source
+SSYS  = ..\sys\share # Shared system files
+NTSYS = ..\sys\winnt # NT Win32 specific files
+TTY   = ..\win\tty   # window port files (tty)
+WIN32 = ..\win\win32 # window port files (Win32)
+WSHR  = ..\win\share # Tile support files 
+
+#
+#  Object directory.
+#
+
+OBJ     = o
+
+
+#
+#==========================================
+# Exe File Info.
+#==========================================
+# Yacc/Lex ... if you got 'em.
+#
+# If you have yacc and lex programs (or work-alike such as bison 
+# and flex), uncomment the upper two macros.
+#
+
+#DO_YACC  = YACC_ACT
+#DO_LEX   = LEX_ACT
+
+!IFNDEF DO_YACC
+DO_YACC = YACC_MSG
+!ENDIF
+!IFNDEF DO_LEX
+DO_LEX  = LEX_MSG
+!ENDIF
+
+# Wilbur Streett's Win32 ports of GNU bison and flex are available at:
+#    http://www.monmouth.com/~wstreett/lex-yacc/lex-yacc.html
+#
+# To use them, download the executables and templates (bison.simple,
+# bison.hairy) to some directory, and set the environment variables
+# BISON_SIMPLE and BISON_HAIRY, and your path to point to this
+# directory.
+#
+# For example, if you placed them in C:\BIN, you should set:
+#   C:> SET BISON_SIMPLE=C:\BIN\BISON.SIMPLE
+#   C:> SET BISON_HAIRY=C:\BIN\BISON.HAIRY
+#
+# Also, make sure your path points to the bison/flex directories.
+#
+# The following settings are configured for Wilbur Streett's ports.
+
+# - Specify your yacc and lex programs (or work-alikes) here.
+
+YACC   = bison -y
+#YACC   = byacc
+#YACC  = yacc
+
+#LEX   = lex
+LEX    = flex
+
+#
+# - Specify your flex skeleton file (if needed).
+#
+
+FLEXSKEL =
+#FLEXSKEL = -S../tools/flex.ske
+
+#YTABC   = y.tab.c
+#YTABH   = y.tab.h
+YTABC   = y_tab.c
+YTABH   = y_tab.h
+LEXYYC  = lex.yy.c
+
+#
+# Optional high-quality BSD random number generation routines
+# (see pcconf.h). Set to nothing if not used.
+#
+
+RANDOM = $(OBJ)\random.o
+#RANDOM        =
+
+#
+# Compiler and Linker flags
+#
+
+PRECOMPHEAD = N                        # set to Y if you want to use precomp. headers
+
+#===============================================
+#======= End of Modification Section ===========
+#===============================================
+################################################
+#                                              #
+# Nothing below here should have to be changed.#
+#                                              #
+################################################
+
+!IF "$(GRAPHICAL)" == "Y"
+WINPORT        = $(O)tile.o $(O)mhaskyn.o $(O)mhdlg.o \
+       $(O)mhfont.o $(O)mhinput.o $(O)mhmain.o $(O)mhmap.o \
+       $(O)mhmenu.o $(O)mhmsgwnd.o $(O)mhrip.o $(O)mhsplash.o \
+       $(O)mhstatus.o $(O)mhtext.o $(O)mswproc.o $(O)winhack.o
+WINPHDR        = $(WIN32)\mhaskyn.h $(WIN32)\mhdlg.h $(WIN32)\mhfont.h \
+       $(WIN32)\mhinput.h $(WIN32)\mhmain.h $(WIN32)\mhmap.h $(WIN32)\mhmenu.h \
+       $(WIN32)\mhmsg.h $(WIN32)\mhmsgwnd.h $(WIN32)\mhrip.h $(WIN32)\mhstatus.h \
+       $(WIN32)\mhtext.h $(WIN32)\resource.h $(WIN32)\winMS.h
+WINDLLS        =
+WINPFLAG= -DTILES -DMSWIN_GRAPHICS
+NHRES  = $(O)winhack.res
+WINPINC        = -I$(WIN32)
+!ELSE
+WINPORT        = $(O)nttty.o    
+WINPHDR        =
+WINDLLS        = $(GAMEDIR)\nhdefkey.dll $(GAMEDIR)\nh340key.dll $(GAMEDIR)\nhraykey.dll
+WINPFLAG= -DWIN32CON
+NHRES  = $(O)console.res
+WINPINC        =
+!ENDIF
+
+TILEUTIL16  = $(UTIL)\tile2bmp.exe
+TILEBMP16   = $(SRC)\tiles.bmp
+
+TILEUTIL32  = $(UTIL)\til2bm32.exe
+TILEBMP32   = $(SRC)\tiles32.bmp
+
+SOUND = $(OBJ)\ntsound.o
+#SOUND =
+
+# To store all the level files,
+# help files, etc. in a single library file.
+# USE_DLB = Y is left uncommented
+
+USE_DLB = Y
+
+! IF ("$(USE_DLB)"=="Y")
+DLBFLG = -DDLB
+! ELSE
+DLBFLG =
+! ENDIF
+
+
+#==========================================
+# Setting up the compiler and linker
+# macros. All builds include the base ones.
+#==========================================
+
+CFLAGSBASE  = -c $(cflags) $(cvarsmt) -I$(INCL) $(WINPINC) -q $(cdebug) -v
+LFLAGSBASE  = $(linkdebug) $(verlflags) -L$(bcclib) -v
+
+#==========================================
+# Util builds
+#==========================================
+
+CFLAGSU = $(CFLAGSBASE) $(WINPFLAG)
+LFLAGSU        = $(LFLAGSBASE)
+
+#==========================================
+# - Game build
+#==========================================
+
+LFLAGSBASE = $(linkdebug) $(conflags) 
+CFLAGS  = $(CFLAGSBASE) $(WINPFLAG) $(DLBFLG)
+NHLFLAGS1 = /Gn /v /m /s /Gz /q /c
+lflags = $(LFLAGSBASE) $(NHLFLAGS1)
+
+GAMEFILE = $(FDIR)\$(GAME).exe # whole thing
+
+! IF ("$(USE_DLB)"=="Y")
+DLB = nhdat
+! ELSE
+DLB =
+! ENDIF
+
+#==========================================
+#================ RULES ==================
+#==========================================
+
+.SUFFIXES: .exe .o .til .uu .c .y .l
+
+#==========================================
+# Rules for files in src
+#==========================================
+
+.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -o$@ $<
+
+{$(SRC)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)   -o$@  $<
+
+#==========================================
+# Rules for files in sys\share
+#==========================================
+
+{$(SSYS)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -o$@  $<
+
+#==========================================
+# Rules for files in sys\winnt
+#==========================================
+
+{$(NTSYS)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -o$@  $<
+
+{$(NTSYS)}.h{$(INCL)}.h:
+       @copy $< $@
+
+#==========================================
+# Rules for files in util
+#==========================================
+
+{$(UTIL)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGSU) -o$@ $<
+
+#==========================================
+# Rules for files in win\share
+#==========================================
+
+{$(WSHR)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -o$@ $<
+
+{$(WSHR)}.h{$(INCL)}.h:
+       @copy $< $@
+
+#{$(WSHR)}.txt{$(DAT)}.txt:
+#      @copy $< $@
+
+#==========================================
+# Rules for files in win\tty
+#==========================================
+
+{$(TTY)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -o$@  $<
+
+#==========================================
+# Rules for files in win\win32
+#==========================================
+
+{$(WIN32)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -o$@  $<
+
+#==========================================
+#================ MACROS ==================
+#==========================================
+# This section creates shorthand macros for many objects
+# referenced later on in the Makefile.
+#
+
+DEFFILE = $(NTSYS)\$(GAME).def
+
+#
+# Shorten up the location for some files
+#
+
+O  = $(OBJ)^\
+
+U  = $(UTIL)^\
+
+#
+# Utility Objects.
+#
+
+MAKESRC        = $(U)makedefs.c
+
+SPLEVSRC       = $(U)lev_yacc.c        $(U)lev_$(LEX).c $(U)lev_main.c  $(U)panic.c
+
+DGNCOMPSRC     = $(U)dgn_yacc.c        $(U)dgn_$(LEX).c $(U)dgn_main.c
+
+MAKEOBJS       = $(O)makedefs.o $(O)monst.o $(O)objects.o
+
+SPLEVOBJS      = $(O)lev_yacc.o        $(O)lev_$(LEX).o $(O)lev_main.o \
+                $(O)alloc.o    $(O)decl.o      $(O)drawing.o \
+                $(O)monst.o    $(O)objects.o   $(O)panic.o
+
+DGNCOMPOBJS    = $(O)dgn_yacc.o        $(O)dgn_$(LEX).o $(O)dgn_main.o \
+                $(O)alloc.o    $(O)panic.o
+
+RECOVOBJS      = $(O)recover.o
+
+TILEFILES      = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt
+
+#
+# These are not invoked during a normal game build in 3.4
+#
+TEXT_IO        = $(O)tiletext.o        $(O)tiletxt.o   $(O)drawing.o \
+                $(O)decl.o     $(O)monst.o     $(O)objects.o
+
+GIFREADERS     = $(O)gifread.o $(O)alloc.o $(O)panic.o
+
+PPMWRITERS     = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o
+
+#
+#  Object files for the game itself.
+#
+
+VOBJ01 = $(O)allmain.o  $(O)alloc.o    $(O)apply.o    $(O)artifact.o
+VOBJ02 = $(O)attrib.o   $(O)ball.o     $(O)bones.o    $(O)botl.o    
+VOBJ03 = $(O)cmd.o      $(O)dbridge.o  $(O)decl.o     $(O)detect.o  
+VOBJ04 = $(O)dig.o      $(O)display.o  $(O)do.o       $(O)do_name.o 
+VOBJ05 = $(O)do_wear.o  $(O)dog.o      $(O)dogmove.o  $(O)dokick.o  
+VOBJ06 = $(O)dothrow.o  $(O)drawing.o  $(O)dungeon.o  $(O)eat.o     
+VOBJ07 = $(O)end.o      $(O)engrave.o  $(O)exper.o    $(O)explode.o 
+VOBJ08 = $(O)extralev.o $(O)files.o    $(O)fountain.o $(O)hack.o    
+VOBJ09 = $(O)hacklib.o  $(O)invent.o   $(O)light.o    $(O)lock.o    
+VOBJ10 = $(O)mail.o     $(O)makemon.o  $(O)mapglyph.o $(O)mcastu.o  
+VOBJ11 = $(O)mhitm.o    $(O)mhitu.o    $(O)minion.o   $(O)mklev.o   
+VOBJ12 = $(O)mkmap.o    $(O)mkmaze.o   $(O)mkobj.o    $(O)mkroom.o  
+VOBJ13 = $(O)mon.o      $(O)mondata.o  $(O)monmove.o  $(O)monst.o   
+VOBJ14 = $(O)monstr.o   $(O)mplayer.o  $(O)mthrowu.o  $(O)muse.o    
+VOBJ15 = $(O)music.o    $(O)o_init.o   $(O)objects.o  $(O)objnam.o  
+VOBJ16 = $(O)options.o  $(O)pager.o    $(O)pickup.o   $(O)pline.o   
+VOBJ17 = $(O)polyself.o $(O)potion.o   $(O)pray.o     $(O)priest.o  
+VOBJ18 = $(O)quest.o    $(O)questpgr.o $(RANDOM)      $(O)read.o    
+VOBJ19 = $(O)rect.o     $(O)region.o   $(O)restore.o  $(O)rip.o     
+VOBJ20 = $(O)rnd.o      $(O)role.o     $(O)rumors.o   $(O)save.o    
+VOBJ21 = $(O)shk.o      $(O)shknam.o   $(O)sit.o      $(O)sounds.o  
+VOBJ22 = $(O)sp_lev.o   $(O)spell.o    $(O)steal.o    $(O)steed.o   
+VOBJ23 = $(O)teleport.o $(O)timeout.o  $(O)topten.o   $(O)track.o   
+VOBJ24 = $(O)trap.o     $(O)u_init.o   $(O)uhitm.o    $(O)vault.o   
+VOBJ25 = $(O)vis_tab.o  $(O)vision.o   $(O)weapon.o   $(O)were.o    
+VOBJ26 = $(O)wield.o    $(O)windows.o  $(O)wizard.o   $(O)worm.o    
+VOBJ27 = $(O)worn.o     $(O)write.o    $(O)zap.o     
+
+DLBOBJ = $(O)dlb.o
+
+TTYOBJ = $(O)topl.o     $(O)getline.o  $(O)wintty.o
+
+SOBJ   = $(O)winnt.o    $(O)pcsys.o      $(O)pcunix.o  \
+          $(SOUND) $(O)pcmain.o        $(O)mapimail.o $(O)nhlan.o
+
+OBJS   = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \
+         $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \
+         $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \
+         $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \
+         $(VOBJ21) $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) \
+         $(VOBJ26) $(VOBJ27)
+
+TILOBJ = $(WINPORT)
+
+VVOBJ  = $(O)version.o
+
+ALLOBJ  = $(TILOBJ) $(SOBJ) $(DLBOBJ)  $(TTYOBJ) $(WOBJ) $(OBJS) $(VVOBJ)
+
+
+!IF "$(GRAPHICAL)" == "Y"
+OPTIONS_FILE = $(DAT)\guioptions
+!ELSE
+OPTIONS_FILE = $(DAT)\ttyoptions
+!ENDIF
+#==========================================
+# Header file macros
+#==========================================
+
+CONFIG_H = $(INCL)\config.h $(INCL)\config1.h $(INCL)\tradstdc.h \
+               $(INCL)\global.h $(INCL)\coord.h $(INCL)\vmsconf.h \
+               $(INCL)\system.h $(INCL)\unixconf.h $(INCL)\os2conf.h \
+               $(INCL)\micro.h $(INCL)\pcconf.h $(INCL)\tosconf.h \
+               $(INCL)\amiconf.h $(INCL)\macconf.h $(INCL)\beconf.h \
+               $(INCL)\ntconf.h $(INCL)\nhlan.h
+
+HACK_H = $(INCL)\hack.h $(CONFIG_H) $(INCL)\align.h \
+               $(INCL)\dungeon.h $(INCL)\monsym.h $(INCL)\mkroom.h \
+               $(INCL)\objclass.h $(INCL)\youprop.h $(INCL)\prop.h \
+               $(INCL)\permonst.h $(INCL)\monattk.h \
+               $(INCL)\monflag.h $(INCL)\mondata.h $(INCL)\pm.h \
+               $(INCL)\wintype.h $(INCL)\decl.h $(INCL)\quest.h \
+               $(INCL)\spell.h $(INCL)\color.h $(INCL)\obj.h \
+               $(INCL)\you.h $(INCL)\attrib.h $(INCL)\monst.h \
+               $(INCL)\skills.h $(INCL)\onames.h $(INCL)\timeout.h \
+               $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \
+               $(INCL)\vision.h $(INCL)\display.h $(INCL)\engrave.h \
+               $(INCL)\rect.h $(INCL)\region.h $(INCL)\winprocs.h \
+               $(INCL)\wintty.h $(INCL)\trampoli.h
+
+LEV_H       = $(INCL)\lev.h
+DGN_FILE_H  = $(INCL)\dgn_file.h
+LEV_COMP_H  = $(INCL)\lev_comp.h
+SP_LEV_H    = $(INCL)\sp_lev.h
+TILE_H      = ..\win\share\tile.h
+
+#==========================================
+# Miscellaneous
+#==========================================
+
+DATABASE = $(DAT)\data.base
+
+#
+#  The name of the game.
+#
+
+GAMEFILE = $(GAMEDIR)\$(GAME).exe
+
+#==========================================
+#=============== TARGETS ==================
+#==========================================
+
+#
+#  The default make target (so just typing 'nmake' is useful).
+#
+default : $(GAMEFILE)
+
+#
+#  The main target.
+#
+
+$(GAME): $(O)obj.tag $(O)utility.tag graphicschk $(GAMEFILE)
+       @echo $(GAME) is up to date.
+
+#
+#  Everything
+#
+
+all :  install
+
+install: graphicschk $(GAME) $(O)install.tag
+        @echo Done.
+
+$(O)install.tag:       $(DAT)\data     $(DAT)\rumors    $(DAT)\dungeon \
+               $(DAT)\oracles  $(DAT)\quest.dat $(O)sp_lev.tag $(DLB)
+! IF ("$(USE_DLB)"=="Y")
+       copy nhdat                $(GAMEDIR)
+       copy $(DAT)\license       $(GAMEDIR)
+       copy $(DAT)\opthelp       $(GAMEDIR)
+! ELSE
+       copy $(DAT)\*.            $(GAMEDIR)
+       copy $(DAT)\*.dat         $(GAMEDIR)
+       copy $(DAT)\*.lev         $(GAMEDIR)
+       if exist $(GAMEDIR)\makefile del $(GAMEDIR)\makefile
+! ENDIF
+       if exist $(DOC)\guidebook.txt copy $(DOC)\guidebook.txt $(GAMEDIR)\Guidebook.txt
+       if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt $(GAMEDIR)\NetHack.txt
+       @if exist $(SRC)\$(GAME).PDB copy $(SRC)\$(GAME).pdb $(GAMEDIR)\$(GAME).pdb
+       @if exist $(GAMEDIR)\$(GAME).PDB echo NOTE: You may want to remove $(GAMEDIR)\$(GAME).pdb to conserve space
+       -copy $(NTSYS)\defaults.nh   $(GAMEDIR)\defaults.nh
+       echo install done > $@
+
+#      copy $(NTSYS)\winnt.hlp    $(GAMEDIR)
+
+recover: $(U)recover.exe
+       if exist $(U)recover.exe copy $(U)recover.exe  $(GAMEDIR)
+       if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR)\recover.txt
+
+$(O)sp_lev.tag: $(O)utility.tag $(DAT)\bigroom.des  $(DAT)\castle.des \
+       $(DAT)\endgame.des $(DAT)\gehennom.des $(DAT)\knox.des   \
+       $(DAT)\medusa.des  $(DAT)\oracle.des   $(DAT)\tower.des  \
+       $(DAT)\yendor.des  $(DAT)\arch.des     $(DAT)\barb.des   \
+       $(DAT)\caveman.des $(DAT)\healer.des   $(DAT)\knight.des \
+       $(DAT)\monk.des    $(DAT)\priest.des   $(DAT)\ranger.des \
+       $(DAT)\rogue.des   $(DAT)\samurai.des  $(DAT)\sokoban.des \
+       $(DAT)\tourist.des $(DAT)\valkyrie.des $(DAT)\wizard.des
+       cd $(DAT)
+       $(U)lev_comp bigroom.des
+       $(U)lev_comp castle.des
+       $(U)lev_comp endgame.des
+       $(U)lev_comp gehennom.des
+       $(U)lev_comp knox.des
+       $(U)lev_comp mines.des
+       $(U)lev_comp medusa.des
+       $(U)lev_comp oracle.des
+       $(U)lev_comp sokoban.des
+       $(U)lev_comp tower.des
+       $(U)lev_comp yendor.des
+       $(U)lev_comp arch.des
+       $(U)lev_comp barb.des
+       $(U)lev_comp caveman.des
+       $(U)lev_comp healer.des
+       $(U)lev_comp knight.des
+       $(U)lev_comp monk.des
+       $(U)lev_comp priest.des
+       $(U)lev_comp ranger.des
+       $(U)lev_comp rogue.des
+       $(U)lev_comp samurai.des
+       $(U)lev_comp tourist.des
+       $(U)lev_comp valkyrie.des
+       $(U)lev_comp wizard.des
+       cd $(SRC)
+       echo sp_levs done > $(O)sp_lev.tag
+
+$(O)utility.tag: $(INCL)\date.h $(INCL)\onames.h $(INCL)\pm.h \
+               $(SRC)\monstr.c         $(SRC)\vis_tab.c  \
+               $(U)lev_comp.exe        $(INCL)\vis_tab.h \
+               $(U)dgn_comp.exe $(TILEUTIL16)
+             @echo utilities made >$@
+            @echo utilities made.
+
+tileutil: $(U)gif2txt.exe $(U)txt2ppm.exe
+       @echo Optional tile development utilities are up to date.
+
+!IF "$(GRAPHICAL)"=="Y"
+$(NHRES): $(TILEBMP16) $(WIN32)\winhack.rc $(WIN32)\mnsel.bmp \
+       $(WIN32)\mnselcnt.bmp $(WIN32)\mnunsel.bmp \
+       $(WIN32)\petmark.bmp $(WIN32)\NetHack.ico $(WIN32)\rip.bmp \
+       $(WIN32)\splash.bmp
+       @$(rc) -r -fo$@ -i$(WIN32) -i$(bccinc) -dNDEBUG $(WIN32)\winhack.rc
+!ELSE
+$(NHRES): $(NTSYS)\console.rc $(NTSYS)\NetHack.ico
+       @$(rc) -r -fo$@ -i$(NTSYS) -i$(bccinc) -dNDEBUG $(NTSYS)\console.rc
+!ENDIF
+
+#==========================================
+#  The main target.
+#==========================================
+
+$(SRC)\uuid.lib: $(bcclib)\uuid.lib
+       @copy $(bcclib)\uuid.lib $@
+
+$(GAMEFILE) : $(ALLOBJ) $(NHRES) $(SRC)\uuid.lib $(O)gamedir.tag $(WINDLLS)
+       @echo Linking....
+       @$(link) $(lflags) $(startobjg) $(ALLOBJ), $@, $(GAME).map,$(libsmt),,$(NHRES)
+       @if exist $(O)install.tag del $(O)install.tag
+       @if exist $(GAMEDIR)\$(GAME).bak del $(GAMEDIR)\$(GAME).bak
+
+$(O)gamedir.tag:
+       @if not exist $(GAMEDIR)\*.* echo creating directory $(GAMEDIR)
+       @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
+       @echo directory created > $@
+
+$(GAME)_.ico : $(NTSYS)\$(GAME).ico
+       @copy $(NTSYS)\$(GAME).ico $@
+
+#==========================================
+# Create directory for holding object files
+#==========================================
+
+$(O)obj.tag:
+       @if not exist $(O)*.* mkdir $(OBJ)
+       @echo directory $(OBJ) created >$@
+
+#==========================================
+# Notify of any CL environment variables
+# in effect since they change the compiler
+# options.
+#==========================================
+
+graphicschk:
+!      IF "$(GRAPHICAL)"=="Y"
+          @echo ----
+          @echo NOTE: This build will include tile support.
+          @echo ----
+!      ENDIF
+       @echo graphicschk > graphicschk
+
+
+$(GAMEDIR)\nhdefkey.dll : $(O)nhdefkey.o
+       @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
+       @echo EXPORTS >nhdefkey.def
+       @echo    ProcessKeystroke >>nhdefkey.def
+       @echo    NHkbhit >>nhdefkey.def
+       @echo    CheckInput >>nhdefkey.def
+       @echo    SourceWhere >>nhdefkey.def
+       @echo    SourceAuthor >>nhdefkey.def
+       @echo    KeyHandlerName >>nhdefkey.def
+       @echo Linking $@
+       $(link) $(linkdebug) /Gn /Gz /q -L$(bcclib) /c  /aa /Tpd /V$(APPVER) -L$(bcclib) -v \
+           c0d32.obj $(O)nhdefkey.o, $@,nhdefkey.map,$(libsmt),nhdefkey.def
+
+$(GAMEDIR)\nh340key.dll : $(O)nh340key.o
+       @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
+       @echo EXPORTS >nh340key.def
+       @echo    ProcessKeystroke >>nh340key.def
+       @echo    NHkbhit >>nh340key.def
+       @echo    CheckInput >>nh340key.def
+       @echo    SourceWhere >>nh340key.def
+       @echo    SourceAuthor >>nh340key.def
+       @echo    KeyHandlerName >>nh340key.def
+       @echo Linking $@
+       $(link) $(linkdebug) /Gn /Gz /q -L$(bcclib) /c  /aa /Tpd /V$(APPVER) -L$(bcclib) -v \
+           c0d32.obj $(O)nh340key.o, $@,nh340key.map,$(libsmt),nh340key.def
+
+$(GAMEDIR)\nhraykey.dll : $(O)nhraykey.o
+       @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
+       @echo EXPORTS >nhraykey.def
+       @echo    ProcessKeystroke >>nhraykey.def
+       @echo    NHkbhit >>nhraykey.def
+       @echo    CheckInput >>nhraykey.def
+       @echo    SourceWhere >>nhraykey.def
+       @echo    SourceAuthor >>nhraykey.def
+       @echo    KeyHandlerName >>nhraykey.def
+       @echo Linking $@
+       $(link) $(linkdebug) /Gn /Gz /q -L$(bcclib) /c  /aa /Tpd /V$(APPVER) -L$(bcclib) -v \
+           c0d32.obj $(O)nhraykey.o, $@,nhraykey.map,$(libsmt),nhraykey.def
+
+#
+#  Secondary Targets.
+#
+    
+#==========================================
+# Makedefs Stuff
+#==========================================
+
+$(U)makedefs.exe:      $(O)obj.tag $(MAKEOBJS) $(SRC)\uuid.lib
+       @$(link) $(LFLAGSU) $(startobj) $(MAKEOBJS), $@,,$(libsmt)
+
+$(O)makedefs.o: $(CONFIG_H)    $(INCL)\monattk.h $(INCL)\monflag.h   $(INCL)\objclass.h \
+                $(INCL)\monsym.h    $(INCL)\qtext.h    $(INCL)\patchlevel.h \
+                $(U)makedefs.c
+       @$(cc) $(CFLAGSU) -o$@ $(U)makedefs.c
+
+#
+#  date.h should be remade every time any of the source or include
+#  files is modified.
+#
+
+$(INCL)\date.h $(OPTIONS_FILE) : $(U)makedefs.exe
+       $(U)makedefs -v
+
+$(INCL)\onames.h : $(U)makedefs.exe
+       $(U)makedefs -o
+
+$(INCL)\pm.h : $(U)makedefs.exe
+       $(U)makedefs -p
+
+#$(INCL)\trap.h : $(U)makedefs.exe
+#      $(U)makedefs -t
+
+$(SRC)\monstr.c: $(U)makedefs.exe
+       $(U)makedefs -m
+
+$(INCL)\vis_tab.h: $(U)makedefs.exe
+       $(U)makedefs -z
+
+$(SRC)\vis_tab.c: $(U)makedefs.exe
+       $(U)makedefs -z
+
+#==========================================
+# uudecode utility and uuencoded targets
+#==========================================
+
+$(U)uudecode.exe: $(O)uudecode.o
+       @$(link) $(LFLAGSU) $(startobj) $(O)uudecode.o, $@,,$(libsmt)
+
+$(O)uudecode.o: $(SSYS)\uudecode.c
+
+$(NTSYS)\NetHack.ico : $(U)uudecode.exe $(NTSYS)\nhico.uu
+       chdir $(NTSYS)
+       ..\..\util\uudecode.exe nhico.uu
+       chdir ..\..\src
+
+$(WIN32)\NetHack.ico : $(U)uudecode.exe $(NTSYS)\nhico.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu
+       chdir ..\..\src
+
+$(WIN32)\mnsel.bmp: $(U)uudecode.exe $(WIN32)\mnsel.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe mnsel.uu
+       chdir ..\..\src
+
+$(WIN32)\mnselcnt.bmp: $(U)uudecode.exe $(WIN32)\mnselcnt.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe mnselcnt.uu
+       chdir ..\..\src
+
+$(WIN32)\mnunsel.bmp: $(U)uudecode.exe $(WIN32)\mnunsel.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe mnunsel.uu
+       chdir ..\..\src
+
+$(WIN32)\petmark.bmp: $(U)uudecode.exe $(WIN32)\petmark.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe petmark.uu
+       chdir ..\..\src
+
+$(WIN32)\rip.bmp: $(U)uudecode.exe $(WIN32)\rip.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe rip.uu
+       chdir ..\..\src
+
+$(WIN32)\splash.bmp: $(U)uudecode.exe $(WIN32)\splash.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe splash.uu
+       chdir ..\..\src
+
+#==========================================
+# Level Compiler Stuff
+#==========================================
+
+LEVCFLAGS=$(cflags) -DWIN32 -D_WIN32 -D_MT -I..\include $(cdebug) -DDLB
+
+$(U)lev_comp.exe: $(SPLEVOBJS) $(SRC)\uuid.lib
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) $(startobj) $(SPLEVOBJS), $@,,$(libsmt)
+
+$(O)lev_yacc.o: $(HACK_H)   $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c
+       @$(cc) $(LEVCFLAGS) -o$@ $(U)lev_yacc.c
+
+$(O)lev_$(LEX).o: $(HACK_H)   $(INCL)\lev_comp.h $(SP_LEV_H) \
+               $(U)lev_$(LEX).c
+       @$(cc) $(LEVCFLAGS) -D__IO_H -o$@ $(U)lev_$(LEX).c
+
+$(O)lev_main.o:        $(U)lev_main.c $(HACK_H)   $(SP_LEV_H)
+       @$(cc) $(LEVCFLAGS) -o$@ $(U)lev_main.c
+
+
+$(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y
+!      IF "$(DO_YACC)"=="YACC_ACT"
+          chdir $(UTIL)
+          $(YACC) -d lev_comp.y
+          copy $(YTABC) lev_yacc.c
+          copy $(YTABH) $(INCL)\lev_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)lev_comp.y has changed.
+          @echo To update $(U)lev_yacc.c and $(INCL)\lev_comp.h run $(YACC).
+          @echo ---
+          @echo For now, we will copy the prebuilt lev_yacc.c and 
+          @echo lev_comp.h from $(SSYS) into $(UTIL) and use them.
+          @copy $(SSYS)\lev_yacc.c $(U)lev_yacc.c >nul
+          @copy $(SSYS)\lev_comp.h $(INCL)\lev_comp.h >nul
+          @echo /**/ >>$(U)lev_yacc.c
+          @echo /**/ >>$(INCL)\lev_comp.h
+!      ENDIF
+
+$(U)lev_$(LEX).c: $(U)lev_comp.l
+!      IF "$(DO_LEX)"=="LEX_ACT"
+          chdir $(UTIL)
+          $(LEX) $(FLEXSKEL) lev_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)lev_comp.l has changed. To update $@ run $(LEX).
+          @echo ---
+          @echo For now, we will copy the prebuilt lev_lex.c 
+          @echo from $(SSYS) into $(UTIL) and use it.
+          @copy $(SSYS)\lev_lex.c $@ >nul
+          @echo /**/ >>$@
+!      ENDIF
+
+#==========================================
+# Dungeon Compiler Stuff
+#==========================================
+
+$(U)dgn_comp.exe: $(DGNCOMPOBJS) $(SRC)\uuid.lib
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) $(startobj) $(DGNCOMPOBJS), $@,,$(libsmt)
+
+
+$(O)dgn_yacc.o:        $(HACK_H)   $(DGN_FILE_H) $(INCL)\dgn_comp.h $(U)dgn_yacc.c
+       @$(cc) $(LEVCFLAGS) -o$@ $(U)dgn_yacc.c
+
+$(O)dgn_$(LEX).o: $(HACK_H)   $(DGN_FILE_H)  $(INCL)\dgn_comp.h \
+       $(U)dgn_$(LEX).c
+       @$(cc) $(LEVCFLAGS) -D__IO_H -o$@ $(U)dgn_$(LEX).c
+
+$(O)dgn_main.o:        $(HACK_H) $(U)dgn_main.c
+       @$(cc) $(LEVCFLAGS) -o$@ $(U)dgn_main.c
+
+$(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y
+!      IF "$(DO_YACC)"=="YACC_ACT"
+          chdir $(UTIL)
+          $(YACC) -d dgn_comp.y
+          copy $(YTABC) dgn_yacc.c
+          copy $(YTABH) $(INCL)\dgn_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)dgn_comp.y has changed. To update dgn_yacc.c and 
+          @echo $(INCL)\dgn_comp.h run $(YACC).
+          @echo ---
+          @echo For now, we will copy the prebuilt $(U)dgn_yacc.c and 
+          @echo dgn_comp.h from $(SSYS) into $(UTIL) and use them.
+          @copy $(SSYS)\dgn_yacc.c $(U)dgn_yacc.c >nul
+          @copy $(SSYS)\dgn_comp.h $(INCL)\dgn_comp.h >nul
+          @echo /**/ >>$(U)dgn_yacc.c
+          @echo /**/ >>$(INCL)\dgn_comp.h
+!      ENDIF
+
+$(U)dgn_$(LEX).c: $(U)dgn_comp.l
+!      IF "$(DO_LEX)"=="LEX_ACT"
+          chdir $(UTIL)
+          $(LEX) $(FLEXSKEL)  dgn_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX).
+          @echo ---
+          @echo For now, we will copy the prebuilt dgn_lex.c 
+          @echo from $(SSYS) into $(UTIL) and use it.
+          @copy $(SSYS)\dgn_lex.c $@ >nul
+          @echo /**/ >>$@
+!      ENDIF
+
+
+#==========================================
+#=========== SECONDARY TARGETS ============
+#==========================================
+
+#===========================================
+# Header files NOT distributed in ..\include
+#===========================================
+
+$(INCL)\win32api.h: $(NTSYS)\win32api.h
+       copy $(NTSYS)\win32api.h $@
+
+
+#==========================================
+# DLB utility and nhdat file creation
+#==========================================
+
+$(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o $(SRC)\uuid.lib
+       @$(link) $(LFLAGSU) $(startobj) $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o, $@,,$(libsmt)
+
+
+$(O)dlb.o:     $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)\dlb.h
+       @$(cc) $(CFLAGS) -o$@ $(SRC)\dlb.c
+       
+$(O)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h
+       @$(cc) $(CFLAGS) -o$@ $(UTIL)\dlb_main.c
+
+$(DAT)\porthelp: $(NTSYS)\porthelp
+       @copy $(NTSYS)\porthelp $@ >nul
+
+nhdat: $(U)dlb_main.exe $(DAT)\data $(DAT)\oracles $(OPTIONS_FILE) \
+       $(DAT)\quest.dat $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp \
+       $(DAT)\history $(DAT)\opthelp $(DAT)\wizhelp $(DAT)\dungeon $(DAT)\porthelp \
+       $(DAT)\license $(O)sp_lev.tag
+       cd $(DAT)
+       echo data >dlb.lst
+       echo oracles >>dlb.lst
+       if exist options echo options >>dlb.lst
+       if exist ttyoptions echo ttyoptions >>dlb.lst
+       if exist guioptions echo guioptions >>dlb.lst
+       if exist porthelp echo porthelp >>dlb.lst
+       echo quest.dat >>dlb.lst
+       echo rumors >>dlb.lst
+       echo help >>dlb.lst
+       echo hh >>dlb.lst
+       echo cmdhelp >>dlb.lst
+       echo history >>dlb.lst
+       echo opthelp >>dlb.lst
+       echo wizhelp >>dlb.lst
+       echo dungeon >>dlb.lst
+       echo license >>dlb.lst
+       for %N in (*.lev) do echo %N >>dlb.lst
+       $(U)dlb_main cIf dlb.lst $(SRC)\nhdat
+       cd $(SRC)
+
+#==========================================
+#  Recover Utility
+#==========================================
+
+$(U)recover.exe: $(RECOVOBJS) $(SRC)\uuid.lib
+       $(link) $(LFLAGSU) $(startobj) $(RECOVOBJS), $@,,$(libsmt)
+
+
+$(O)recover.o: $(CONFIG_H) $(U)recover.c $(INCL)\win32api.h
+       $(cc) $(CFLAGSU) -o$@ $(U)recover.c
+
+#==========================================
+#  Tile Mapping
+#==========================================
+
+$(SRC)\tile.c: $(U)tilemap.exe
+       @echo A new $@ has been created
+       @$(U)tilemap
+
+$(U)tilemap.exe: $(O)tilemap.o $(SRC)\uuid.lib
+       @$(link) $(LFLAGSU) $(startobj) $(O)tilemap.o, $@,,$(libsmt)
+
+
+$(O)tilemap.o: $(WSHR)\tilemap.c $(HACK_H)
+       @$(cc) $(CFLAGSU) -o$@ $(WSHR)\tilemap.c
+
+$(O)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H)
+       @$(cc) $(CFLAGS) /DTILETEXT -o$@ $(WSHR)\tilemap.c
+
+$(O)gifread.o: $(WSHR)\gifread.c  $(CONFIG_H) $(TILE_H)
+       @$(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)\gifread.c
+
+$(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(TILE_H)
+       @$(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)\ppmwrite.c
+
+$(O)tiletext.o: $(WSHR)\tiletext.c  $(CONFIG_H) $(TILE_H)
+       @$(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)\tiletext.c
+
+#==========================================
+# Optional Tile Utilities
+#==========================================
+
+$(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO) $(SRC)\uuid.lib
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) $(startobj) $(GIFREADERS) $(TEXT_IO), $@,,$(libsmt)
+
+
+$(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO) $(SRC)\uuid.lib
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) $(startobj) $(PPMWRITERS) $(TEXT_IO), $@,,$(libsmt)
+
+
+!IF "$(GRAPHICAL)"=="Y"
+$(TILEBMP16): $(TILEUTIL16) $(TILEFILES)
+       @echo Creating 16x16 binary tile files (this may take some time)
+       @$(U)tile2bmp $(TILEBMP16)
+!ENDIF
+
+$(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO) $(SRC)\uuid.lib
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) $(startobj) $(O)tile2bmp.o $(TEXT_IO), $@,,$(libsmt)
+
+
+$(O)tile2bmp.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h
+       @$(cc) $(CFLAGS) -I$(WSHR) /DPACKED_FILE -o$@ $(WSHR)\tile2bmp.c
+
+#==========================================
+# Housekeeping
+#==========================================
+
+spotless: clean
+! IF ("$(OBJ)"!="")
+       -rmdir $(OBJ) /s /Q
+! ENDIF
+       if exist $(INCL)\date.h    del $(INCL)\date.h
+       if exist $(INCL)\onames.h  del $(INCL)\onames.h
+       if exist $(INCL)\pm.h      del $(INCL)\pm.h
+       if exist $(INCL)\vis_tab.h del $(INCL)\vis_tab.h
+       if exist $(SRC)\vis_tab.c  del $(SRC)\vis_tab.c
+       if exist $(SRC)\tile.c     del $(SRC)\tile.c
+       if exist $(U)*.lnk         del $(U)*.lnk
+       if exist $(U)*.map         del $(U)*.map
+       if exist $(DAT)\data       del $(DAT)\data
+       if exist $(DAT)\rumors     del $(DAT)\rumors
+       if exist $(DAT)\???-fil?.lev    del $(DAT)\???-fil?.lev
+       if exist $(DAT)\???-goal.lev    del $(DAT)\???-goal.lev
+       if exist $(DAT)\???-loca.lev    del $(DAT)\???-loca.lev
+       if exist $(DAT)\???-strt.lev    del $(DAT)\???-strt.lev
+       if exist $(DAT)\air.lev         del $(DAT)\air.lev
+       if exist $(DAT)\asmodeus.lev    del $(DAT)\asmodeus.lev
+       if exist $(DAT)\astral.lev      del $(DAT)\astral.lev
+       if exist $(DAT)\baalz.lev       del $(DAT)\baalz.lev
+       if exist $(DAT)\bigroom.lev     del $(DAT)\bigroom.lev
+       if exist $(DAT)\castle.lev      del $(DAT)\castle.lev
+       if exist $(DAT)\data            del $(DAT)\data
+       if exist $(DAT)\dungeon         del $(DAT)\dungeon
+       if exist $(DAT)\dungeon.pdf     del $(DAT)\dungeon.pdf
+       if exist $(DAT)\earth.lev       del $(DAT)\earth.lev
+       if exist $(DAT)\fakewiz?.lev    del $(DAT)\fakewiz?.lev
+       if exist $(DAT)\fire.lev        del $(DAT)\fire.lev
+       if exist $(DAT)\juiblex.lev     del $(DAT)\juiblex.lev
+       if exist $(DAT)\knox.lev        del $(DAT)\knox.lev
+       if exist $(DAT)\medusa-?.lev    del $(DAT)\medusa-?.lev
+       if exist $(DAT)\mine*.lev       del $(DAT)\mine*.lev
+       if exist $(DAT)\options         del $(DAT)\options
+       if exist $(DAT)\ttyoptions      del $(DAT)\ttyoptions
+       if exist $(DAT)\guioptions      del $(DAT)\guioptions
+       if exist $(DAT)\oracle.lev      del $(DAT)\oracle.lev
+       if exist $(DAT)\oracles         del $(DAT)\oracles
+       if exist $(DAT)\orcus.lev       del $(DAT)\orcus.lev
+       if exist $(DAT)\rumors          del $(DAT)\rumors
+       if exist $(DAT)\quest.dat       del $(DAT)\quest.dat
+       if exist $(DAT)\sanctum.lev     del $(DAT)\sanctum.lev
+       if exist $(DAT)\soko?-?.lev     del $(DAT)\soko?-?.lev
+       if exist $(DAT)\tower?.lev      del $(DAT)\tower?.lev
+       if exist $(DAT)\valley.lev      del $(DAT)\valley.lev
+       if exist $(DAT)\water.lev       del $(DAT)\water.lev
+       if exist $(DAT)\wizard?.lev     del $(DAT)\wizard?.lev
+       if exist $(O)sp_lev.tag         del $(O)sp_lev.tag
+       if exist $(SRC)\monstr.c        del $(SRC)\monstr.c
+       if exist $(SRC)\vis_tab.c       del $(SRC)\vis_tab.c
+       if exist $(U)recover.exe        del $(U)recover.exe
+       if exist nhdat.                 del nhdat.
+
+clean:
+       if exist $(O)*.o del $(O)*.o
+       if exist $(O)utility.tag   del $(O)utility.tag
+       if exist $(U)makedefs.exe  del $(U)makedefs.exe
+       if exist $(U)lev_comp.exe  del $(U)lev_comp.exe
+       if exist $(U)dgn_comp.exe  del $(U)dgn_comp.exe
+       if exist $(SRC)\*.lnk      del $(SRC)\*.lnk
+       if exist $(SRC)\*.map      del $(SRC)\*.map
+       if exist $(TILEBMP16)        del $(TILEBMP16)
+
+#===================================================================
+# OTHER DEPENDENCIES
+#===================================================================
+
+#
+# dat dependencies
+#
+
+$(DAT)\data: $(O)utility.tag    $(DATABASE)
+       $(U)makedefs -d
+
+$(DAT)\rumors: $(O)utility.tag    $(DAT)\rumors.tru   $(DAT)\rumors.fal
+       $(U)makedefs -r
+
+$(DAT)\quest.dat: $(O)utility.tag  $(DAT)\quest.txt
+       $(U)makedefs -q
+
+$(DAT)\oracles: $(O)utility.tag    $(DAT)\oracles.txt
+       $(U)makedefs -h
+
+$(DAT)\dungeon: $(O)utility.tag  $(DAT)\dungeon.def
+       $(U)makedefs -e
+       cd $(DAT)
+       $(U)dgn_comp dungeon.pdf
+       cd $(SRC)
+
+#
+# NT dependencies
+#
+
+$(O)nttty.o:   $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nttty.c
+       @$(cc) $(CFLAGS) -I$(WSHR) -o$@  $(NTSYS)\nttty.c
+$(O)winnt.o: $(HACK_H) $(INCL)\win32api.h $(NTSYS)\winnt.c
+       @$(cc) $(CFLAGS) -o$@  $(NTSYS)\winnt.c
+$(O)ntsound.o: $(HACK_H) $(NTSYS)\ntsound.c
+       @$(cc) $(CFLAGS)  -o$@ $(NTSYS)\ntsound.c
+$(O)mapimail.o: $(HACK_H) $(INCL)\nhlan.h $(NTSYS)\mapimail.c
+       @$(cc) $(CFLAGS) -DMAPI_VERBOSE  -o$@ $(NTSYS)\mapimail.c
+
+# 
+# util dependencies
+#
+
+$(O)panic.o:  $(U)panic.c $(CONFIG_H)
+       @$(cc) $(CFLAGS) -o$@ $(U)panic.c
+
+#
+# The rest are stolen from sys/unix/Makefile.src, 
+# with the following changes:
+#   * ../include changed to $(INCL)
+#   * slashes changed to back-slashes 
+#   * -c (which is included in CFLAGS) substituted
+#      with -o$@
+#   * $(CC) changed to $(cc)
+# but otherwise untouched.
+# That means that there is some irrelevant stuff
+# in here, but maintenance should be easier.
+#
+$(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h
+       $(cc) $(CFLAGS) -o$@ ..\sys\atari\tos.c
+$(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\win32api.h
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\pcmain.c
+$(O)pcsys.o: ..\sys\share\pcsys.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\pcsys.c
+$(O)pctty.o: ..\sys\share\pctty.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\pctty.c
+$(O)pcunix.o: ..\sys\share\pcunix.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\pcunix.c
+$(O)random.o: ..\sys\share\random.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\random.c
+$(O)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)\tcap.h
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\ioctl.c
+$(O)unixtty.o: ..\sys\share\unixtty.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ..\sys\share\unixtty.c
+$(O)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)\dlb.h
+       $(cc) $(CFLAGS) -o$@ ..\sys\unix\unixmain.c
+$(O)unixunix.o: ..\sys\unix\unixunix.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ..\sys\unix\unixunix.c
+$(O)bemain.o: ..\sys\be\bemain.c $(HACK_H) $(INCL)\dlb.h
+       $(cc) $(CFLAGS) -o$@ ..\sys\be\bemain.c
+$(O)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)\func_tab.h
+       $(cc) $(CFLAGS) -o$@ ..\win\tty\getline.c
+$(O)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)\tcap.h
+       $(cc) $(CFLAGS) -o$@ ..\win\tty\termcap.c
+$(O)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)\tcap.h
+       $(cc) $(CFLAGS) -o$@ ..\win\tty\topl.c
+$(O)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h $(INCL)\tcap.h
+       $(cc) $(CFLAGS) -o$@ ..\win\tty\wintty.c
+$(O)Window.o: ..\win\X11\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \
+               $(CONFIG_H)
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\Window.c
+$(O)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H)
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\dialogs.c
+$(O)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h ..\win\X11\nh72icon \
+               ..\win\X11\nh56icon ..\win\X11\nh32icon
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winX.c
+$(O)winmap.o: ..\win\X11\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\winX.h $(INCL)\tile2x11.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winmap.c
+$(O)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)\winX.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winmenu.c
+$(O)winmesg.o: ..\win\X11\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winmesg.c
+$(O)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)\func_tab.h \
+               $(INCL)\winX.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winmisc.c
+$(O)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)\winX.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winstat.c
+$(O)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\wintext.c
+$(O)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)\winX.h
+       $(cc) $(CFLAGS) -o$@ ..\win\X11\winval.c
+$(O)tile.o: $(SRC)\tile.c $(HACK_H)
+$(O)gnaskstr.o: ..\win\gnome\gnaskstr.c ..\win\gnome\gnaskstr.h \
+               ..\win\gnome\gnmain.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnaskstr.c
+$(O)gnbind.o: ..\win\gnome\gnbind.c ..\win\gnome\gnbind.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gnaskstr.h ..\win\gnome\gnyesno.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnbind.c
+$(O)gnglyph.o: ..\win\gnome\gnglyph.c ..\win\gnome\gnglyph.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnglyph.c
+$(O)gnmain.o: ..\win\gnome\gnmain.c ..\win\gnome\gnmain.h ..\win\gnome\gnsignal.h \
+               ..\win\gnome\gnbind.h ..\win\gnome\gnopts.h $(HACK_H) \
+               $(INCL)\date.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnmain.c
+$(O)gnmap.o: ..\win\gnome\gnmap.c ..\win\gnome\gnmap.h ..\win\gnome\gnglyph.h \
+               ..\win\gnome\gnsignal.h $(HACK_H)
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnmap.c
+$(O)gnmenu.o: ..\win\gnome\gnmenu.c ..\win\gnome\gnmenu.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gnbind.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnmenu.c
+$(O)gnmesg.o: ..\win\gnome\gnmesg.c ..\win\gnome\gnmesg.h ..\win\gnome\gnsignal.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnmesg.c
+$(O)gnopts.o: ..\win\gnome\gnopts.c ..\win\gnome\gnopts.h ..\win\gnome\gnglyph.h \
+               ..\win\gnome\gnmain.h ..\win\gnome\gnmap.h $(HACK_H)
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnopts.c
+$(O)gnplayer.o: ..\win\gnome\gnplayer.c ..\win\gnome\gnplayer.h \
+               ..\win\gnome\gnmain.h $(HACK_H)
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnplayer.c
+$(O)gnsignal.o: ..\win\gnome\gnsignal.c ..\win\gnome\gnsignal.h \
+               ..\win\gnome\gnmain.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnsignal.c
+$(O)gnstatus.o: ..\win\gnome\gnstatus.c ..\win\gnome\gnstatus.h \
+               ..\win\gnome\gnsignal.h ..\win\gnome\gn_xpms.h \
+               ..\win\gnome\gnomeprv.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnstatus.c
+$(O)gntext.o: ..\win\gnome\gntext.c ..\win\gnome\gntext.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gn_rip.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gntext.c
+$(O)gnyesno.o: ..\win\gnome\gnyesno.c ..\win\gnome\gnbind.h ..\win\gnome\gnyesno.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnyesno.c
+$(O)wingem.o: ..\win\gem\wingem.c $(HACK_H) $(INCL)\func_tab.h $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h $(INCL)\wingem.h
+       $(cc) $(CFLAGS) -o$@ ..\win\gem\wingem.c
+$(O)wingem1.o: ..\win\gem\wingem1.c $(INCL)\gem_rsc.h $(INCL)\load_img.h \
+               $(INCL)\wintype.h $(INCL)\wingem.h
+       $(cc) $(CFLAGS) -o$@ ..\win\gem\wingem1.c
+$(O)load_img.o: ..\win\gem\load_img.c $(INCL)\load_img.h
+       $(cc) $(CFLAGS) -o$@ ..\win\gem\load_img.c
+$(O)tile.o: tile.c $(HACK_H)
+$(O)qt_win.o: ..\win\Qt\qt_win.cpp $(HACK_H) $(INCL)\func_tab.h \
+               $(INCL)\dlb.h $(INCL)\patchlevel.h $(INCL)\qt_win.h \
+               $(INCL)\qt_clust.h $(INCL)\qt_kde0.h \
+               $(INCL)\qt_xpms.h qt_win.moc qt_kde0.moc
+       $(CXX) $(CXXFLAGS) -c ..\win\Qt\qt_win.cpp
+$(O)qt_clust.o: ..\win\Qt\qt_clust.cpp $(INCL)\qt_clust.h
+       $(CXX) $(CXXFLAGS) -c ..\win\Qt\qt_clust.cpp
+$(O)monstr.o: $(SRC)\monstr.c $(CONFIG_H)
+$(O)vis_tab.o: $(SRC)\vis_tab.c $(CONFIG_H) $(INCL)\vis_tab.h
+$(O)allmain.o: allmain.c $(HACK_H)
+$(O)alloc.o: alloc.c $(CONFIG_H)
+$(O)apply.o: apply.c $(HACK_H) $(INCL)\edog.h
+$(O)artifact.o: artifact.c $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h
+$(O)attrib.o: attrib.c $(HACK_H) $(INCL)\artifact.h
+$(O)ball.o: ball.c $(HACK_H)
+$(O)bones.o: bones.c $(HACK_H) $(INCL)\lev.h
+$(O)botl.o: botl.c $(HACK_H)
+$(O)cmd.o: cmd.c $(HACK_H) $(INCL)\func_tab.h
+$(O)dbridge.o: dbridge.c $(HACK_H)
+$(O)decl.o: decl.c $(HACK_H)
+$(O)detect.o: detect.c $(HACK_H) $(INCL)\artifact.h
+$(O)dig.o: dig.c $(HACK_H) $(INCL)\edog.h
+$(O)display.o: display.c $(HACK_H)
+$(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)\dlb.h
+$(O)do.o: do.c $(HACK_H) $(INCL)\lev.h
+$(O)do_name.o: do_name.c $(HACK_H)
+$(O)do_wear.o: do_wear.c $(HACK_H)
+$(O)dog.o: dog.c $(HACK_H) $(INCL)\edog.h
+$(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+$(O)dokick.o: dokick.c $(HACK_H) $(INCL)\eshk.h
+$(O)dothrow.o: dothrow.c $(HACK_H) $(INCL)\edog.h
+$(O)drawing.o: drawing.c $(HACK_H) $(INCL)\tcap.h
+$(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h
+$(O)eat.o: eat.c $(HACK_H)
+$(O)end.o: end.c $(HACK_H) $(INCL)\eshk.h $(INCL)\dlb.h
+$(O)engrave.o: engrave.c $(HACK_H) $(INCL)\lev.h
+$(O)exper.o: exper.c $(HACK_H)
+$(O)explode.o: explode.c $(HACK_H)
+$(O)extralev.o: extralev.c $(HACK_H)
+$(O)files.o: files.c $(HACK_H) $(INCL)\dlb.h
+$(O)fountain.o: fountain.c $(HACK_H)
+$(O)hack.o: hack.c $(HACK_H)
+$(O)hacklib.o: hacklib.c $(HACK_H)
+$(O)invent.o: invent.c $(HACK_H) $(INCL)\artifact.h
+$(O)light.o: light.c $(HACK_H) $(INCL)\lev.h
+$(O)lock.o: lock.c $(HACK_H)
+$(O)mail.o: mail.c $(HACK_H) $(INCL)\mail.h
+$(O)makemon.o: makemon.c $(HACK_H) $(INCL)\epri.h $(INCL)\emin.h \
+               $(INCL)\edog.h
+$(O)mapglyph.o: mapglyph.c $(HACK_H)
+$(O)mcastu.o: mcastu.c $(HACK_H)
+$(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+$(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+$(O)minion.o: minion.c $(HACK_H) $(INCL)\emin.h $(INCL)\epri.h
+$(O)mklev.o: mklev.c $(HACK_H)
+$(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)\sp_lev.h
+$(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev.h
+$(O)mkobj.o: mkobj.c $(HACK_H) $(INCL)\artifact.h
+$(O)mkroom.o: mkroom.c $(HACK_H)
+$(O)mon.o: mon.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+$(O)mondata.o: mondata.c $(HACK_H) $(INCL)\eshk.h $(INCL)\epri.h
+$(O)monmove.o: monmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h
+$(O)monst.o: monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \
+               $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\monsym.h \
+               $(INCL)\dungeon.h $(INCL)\eshk.h $(INCL)\vault.h \
+               $(INCL)\epri.h $(INCL)\color.h
+$(O)mplayer.o: mplayer.c $(HACK_H)
+$(O)mthrowu.o: mthrowu.c $(HACK_H)
+$(O)muse.o: muse.c $(HACK_H) $(INCL)\edog.h
+$(O)music.o: music.c $(HACK_H) #interp.c
+$(O)o_init.o: o_init.c $(HACK_H) $(INCL)\lev.h
+$(O)objects.o: objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \
+               $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h
+$(O)objnam.o: objnam.c $(HACK_H)
+$(O)options.o: options.c $(CONFIG_H) $(INCL)\objclass.h $(INCL)\flag.h \
+               $(HACK_H) $(INCL)\tcap.h
+$(O)pager.o: pager.c $(HACK_H) $(INCL)\dlb.h
+$(O)pickup.o: pickup.c $(HACK_H)
+$(O)pline.o: pline.c $(HACK_H) $(INCL)\epri.h $(INCL)\edog.h
+$(O)polyself.o: polyself.c $(HACK_H)
+$(O)potion.o: potion.c $(HACK_H)
+$(O)pray.o: pray.c $(HACK_H) $(INCL)\epri.h
+$(O)priest.o: priest.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\eshk.h \
+               $(INCL)\epri.h $(INCL)\emin.h
+$(O)quest.o: quest.c $(HACK_H) $(INCL)\qtext.h
+$(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)\dlb.h $(INCL)\qtext.h
+$(O)read.o: read.c $(HACK_H)
+$(O)rect.o: rect.c $(HACK_H)
+$(O)region.o: region.c $(HACK_H) $(INCL)\lev.h
+$(O)restore.o: restore.c $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h
+$(O)rip.o: rip.c $(HACK_H)
+$(O)rnd.o: rnd.c $(HACK_H)
+$(O)role.o: role.c $(HACK_H)
+$(O)rumors.o: rumors.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h
+$(O)save.o: save.c $(HACK_H) $(INCL)\lev.h
+$(O)shk.o: shk.c $(HACK_H) $(INCL)\eshk.h
+$(O)shknam.o: shknam.c $(HACK_H) $(INCL)\eshk.h
+$(O)sit.o: sit.c $(HACK_H) $(INCL)\artifact.h
+$(O)sounds.o: sounds.c $(HACK_H) $(INCL)\edog.h
+$(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)\dlb.h $(INCL)\sp_lev.h
+$(O)spell.o: spell.c $(HACK_H)
+$(O)steal.o: steal.c $(HACK_H)
+$(O)steed.o: steed.c $(HACK_H)
+$(O)teleport.o: teleport.c $(HACK_H)
+$(O)timeout.o: timeout.c $(HACK_H) $(INCL)\lev.h
+$(O)topten.o: topten.c $(HACK_H) $(INCL)\dlb.h $(INCL)\patchlevel.h
+$(O)track.o: track.c $(HACK_H)
+$(O)trap.o: trap.c $(HACK_H)
+$(O)u_init.o: u_init.c $(HACK_H)
+$(O)uhitm.o: uhitm.c $(HACK_H)
+$(O)vault.o: vault.c $(HACK_H) $(INCL)\vault.h
+$(O)version.o: version.c $(HACK_H) $(INCL)\date.h $(INCL)\patchlevel.h
+$(O)vision.o: vision.c $(HACK_H) $(INCL)\vis_tab.h
+$(O)weapon.o: weapon.c $(HACK_H)
+$(O)were.o: were.c $(HACK_H)
+$(O)wield.o: wield.c $(HACK_H)
+$(O)windows.o: windows.c $(HACK_H) $(INCL)\wingem.h $(INCL)\winGnome.h
+$(O)wizard.o: wizard.c $(HACK_H) $(INCL)\qtext.h
+$(O)worm.o: worm.c $(HACK_H) $(INCL)\lev.h
+$(O)worn.o: worn.c $(HACK_H)
+$(O)write.o: write.c $(HACK_H)
+$(O)zap.o: zap.c $(HACK_H)
+
+# end of file
+
diff --git a/sys/winnt/Makefile.gcc b/sys/winnt/Makefile.gcc
new file mode 100644 (file)
index 0000000..980c2c2
--- /dev/null
@@ -0,0 +1,1352 @@
+#   SCCS Id: @(#)Makefile.gcc       3.4     $Date: 2003/11/16 04:50:57 $
+#   Copyright (c) NetHack PC Development Team 1993-2003
+#
+#   NetHack 3.4.x Makefile for MinGW
+#
+#   Win32 Compilers Tested:
+#                  - MinGW 1.0 (gcc version 2.95.3-6) (Console NetHack only)
+#                  - MinGW 2.0 (gcc version 3.2)
+#
+#   If you don't have this compiler, you can get it at:
+#       http://www.mingw.org/
+#
+#   This is used for building two versions of NetHack:
+#   A tty port utilizing the Win32 Console I/O subsystem, Console
+#       NetHack;
+#   A Win32 native port built on the Windows API, Graphical NetHack or
+#       NetHackW.
+#
+#   In addition to your C compiler,
+#
+#     if you want to change     you will need a
+#     files with suffix         workalike for
+#         .y                     yacc   (such as bison)
+#         .l                     lex    (such as flex)
+#
+#
+#   If you have any questions read the sys/winnt/Install.nt file included
+#   with the distribution.
+#
+#   --
+#   Dion Nicolaas
+#==============================================================================
+# Graphical interface
+# Set to Y for a graphical version
+# Set to anything else (or undefine) for a tty version
+
+#GRAPHICAL = Y
+
+# Debug
+# Set to Y for Debug support (to produce debug information)
+# Set to anything else (or undefine) for a "release" version
+# You can set your debug options below.
+
+DEBUG = Y
+
+cc     = gcc
+rc     = windres
+link   = gcc
+
+cflags = -mms-bitfields
+lflags  =
+ifeq  "$(DEBUG)" "Y"
+cdebug = -g
+linkdebug = -g
+else
+cdebug =
+linkdebug =
+endif
+
+#
+#  Set the gamedir according to your preference.
+#  If not present prior to compilation it gets created.
+
+ifeq  "$(GRAPHICAL)" "Y"
+# Game Name
+GAME    = NetHackW
+else
+# Game Name
+GAME    = NetHack
+endif
+# Game directory
+GAMEDIR = ../binary
+
+#
+#  Source directories.    Makedefs hardcodes these, don't change them.
+#
+
+# NetHack include files
+INCL  = ../include
+# NetHack data files
+DAT   = ../dat
+# NetHack documentation files
+DOC   = ../doc
+# Utility source
+UTIL  = ../util
+# Main source
+SRC   = ../src
+# Shared system files
+SSYS  = ../sys/share
+# NT Win32 specific files
+NTSYS = ../sys/winnt
+# window port files (tty)
+TTY   = ../win/tty
+# window port files (Win32)
+WIN32 = ../win/win32
+# Tile support files
+WSHR  = ../win/share
+
+#
+#  Object directory.
+#
+
+OBJ = o
+
+
+#
+#==========================================
+# Exe File Info.
+#==========================================
+
+# Yacc/Lex ... if you got 'em.
+#
+# If you have yacc and lex programs (or work-alike such as bison
+# and flex), comment out the upper two macros and uncomment
+# the lower two.
+#
+
+DO_YACC = YACC_MSG
+DO_LEX  = LEX_MSG
+#DO_YACC  = YACC_ACT
+#DO_LEX   = LEX_ACT
+
+# - Specify your yacc and lex programs (or work-alikes) here.
+
+#YACC   = bison -y
+YACC   = byacc
+#YACC   = yacc
+
+#LEX    = lex
+LEX     = flex
+
+#
+# - Specify your flex skeleton file (if needed).
+#
+
+FLEXSKEL =
+#FLEXSKEL = -S../tools/flex.ske
+
+YTABC   = y_tab.c
+YTABH   = y_tab.h
+LEXYYC  = lexyy.c
+
+#
+# Optional high-quality BSD random number generation routines
+# (see pcconf.h). Set to nothing if not used.
+#
+
+RANDOM  = $(OBJ)/random.o
+#RANDOM =
+
+#===============================================
+#======= End of Modification Section ===========
+#===============================================
+################################################
+#                                              #
+# Nothing below here should have to be changed.#
+#                                              #
+################################################
+
+ifeq  "$(GRAPHICAL)" "Y"
+WINPORT  = $(O)tile.o $(O)mhaskyn.o $(O)mhdlg.o \
+       $(O)mhfont.o $(O)mhinput.o $(O)mhmain.o $(O)mhmap.o \
+       $(O)mhmenu.o $(O)mhmsgwnd.o $(O)mhrip.o $(O)mhsplash.o \
+       $(O)mhstatus.o $(O)mhtext.o $(O)mswproc.o $(O)winhack.o
+WINPFLAG   = -DTILES -DMSWIN_GRAPHICS -D_WIN32_IE=0x0400
+NHRES   = $(O)winres.o
+WINPINC = -I$(WIN32)
+WINPHDR = $(WIN32)/mhaskyn.h $(WIN32)/mhdlg.h $(WIN32)/mhfont.h \
+       $(WIN32)/mhinput.h $(WIN32)/mhmain.h $(WIN32)/mhmap.h \
+       $(WIN32)/mhmenu.h $(WIN32)/mhmsg.h $(WIN32)/mhmsgwnd.h \
+       $(WIN32)/mhrip.h $(WIN32)/mhstatus.h \
+       $(WIN32)/mhtext.h $(WIN32)/resource.h $(WIN32)/winMS.h
+WINPLIBS =  -lcomctl32 -lwinmm
+else
+WINPORT = $(O)nttty.o
+WINPFLAG= -DWIN32CON
+WINPHDR =
+NHRES   = $(O)console.o
+WINPINC =
+WINPLIBS = -lwinmm
+endif
+
+TILEUTIL16  = $(UTIL)/tile2bmp.exe
+TILEBMP16   = $(SRC)/tiles.bmp
+
+TILEUTIL32  = $(UTIL)/til2bm32.exe
+TILEBMP32   = $(SRC)/tiles32.bmp
+
+SOUND = $(OBJ)/ntsound.o
+
+#SOUND =
+
+# To store all the level files,
+# help files, etc. in a single library file.
+# USE_DLB = Y is left uncommented
+
+USE_DLB = Y
+
+ifeq  "$(USE_DLB)" "Y"
+DLBFLG = -DDLB
+else
+DLBFLG =
+endif
+
+#==========================================
+# Setting up the compiler and linker
+# macros. All builds include the base ones.
+#==========================================
+
+CFLAGSBASE  = -c $(cflags) -I$(INCL) $(WINPINC) $(cdebug)
+LFLAGSBASEC = $(linkdebug)
+LFLAGSBASEG = $(linkdebug) -mwindows
+
+#==========================================
+# Util builds
+#==========================================
+
+CFLAGSU = $(CFLAGSBASE) $(WINPFLAG)
+LFLAGSU = $(LFLAGSBASEC)
+
+#==========================================
+# - Game build
+#==========================================
+
+CFLAGS   = $(CFLAGSBASE) $(WINPFLAG) $(DLBFLG)
+lflags  = $(LFLAGSBASE)
+ifeq "$(GRAPHICAL)" "Y"
+lflags  = $(LFLAGSBASEG)
+else
+lflags  = $(LFLAGSBASEC)
+endif
+
+GAMEFILE = $(GAMEDIR)/$(GAME).exe # whole thing
+
+ifeq  "$(USE_DLB)" "Y"
+DLB = nhdat
+else
+DLB =
+endif
+
+#==========================================
+#================ RULES ==================
+#==========================================
+
+.SUFFIXES: .exe .o .til .uu .c .y .l
+
+#==========================================
+# Rules for files in src
+#==========================================
+
+$(OBJ)/%.o : /%.c
+       $(cc) $(CFLAGS)  -o$@ $<
+
+$(OBJ)/%.o : $(SRC)/%.c
+       $(cc) $(CFLAGS)   -o$@  $<
+
+#==========================================
+# Rules for files in sys/share
+#==========================================
+
+$(OBJ)/%.o : $(SSYS)/%.c
+       $(cc) $(CFLAGS)  -o$@  $<
+
+#==========================================
+# Rules for files in sys/winnt
+#==========================================
+
+$(OBJ)/%.o : $(NTSYS)/%.c
+       $(cc) $(CFLAGS)  -o$@  $<
+
+$(INCL)/%.h : $(NTSYS)/%.h
+       @copy $< $@
+
+#==========================================
+# Rules for files in util
+#==========================================
+
+$(OBJ)/%.o : $(UTIL)/%.c
+       $(cc) $(CFLAGSU) -o$@ $<
+
+#==========================================
+# Rules for files in win/share
+#==========================================
+
+$(OBJ)/%.o : $(WSHR)/%.c
+       $(cc) $(CFLAGS)  -o$@ $<
+
+$(INCL)/%.h : $(WSHR)/%.h
+       @copy $< $@
+
+#{$(WSHR)}.txt{$(DAT)}.txt:
+#      @copy $< $@
+
+#==========================================
+# Rules for files in win/tty
+#==========================================
+
+$(OBJ)/%.o : $(TTY)/%.c
+       $(cc) $(CFLAGS)  -o$@  $<
+
+#==========================================
+# Rules for files in win/win32
+#==========================================
+
+$(OBJ)/%.o : $(WIN32)/%.c
+       $(cc) $(CFLAGS)  -o$@  $<
+
+#==========================================
+#================ MACROS ==================
+#==========================================
+# This section creates shorthand macros for many objects
+# referenced later on in the Makefile.
+#
+
+DEFFILE = $(NTSYS)/$(GAME).def
+
+#
+# Shorten up the location for some files
+#
+
+O  = $(OBJ)/
+
+U  = $(UTIL)/
+
+#
+# Utility Objects.
+#
+
+MAKESRC        = $(U)makedefs.c
+
+SPLEVSRC       = $(U)lev_yacc.c  $(U)lev_$(LEX).c $(U)lev_main.c  $(U)panic.c
+
+DGNCOMPSRC     = $(U)dgn_yacc.c  $(U)dgn_$(LEX).c $(U)dgn_main.c
+
+MAKEOBJS       = $(O)makedefs.o $(O)monst.o $(O)objects.o
+
+SPLEVOBJS      = $(O)lev_yacc.o  $(O)lev_$(LEX).o $(O)lev_main.o \
+       $(O)alloc.o   $(O)decl.o      $(O)drawing.o \
+       $(O)monst.o   $(O)objects.o   $(O)panic.o
+
+DGNCOMPOBJS    = $(O)dgn_yacc.o  $(O)dgn_$(LEX).o $(O)dgn_main.o \
+       $(O)alloc.o   $(O)panic.o
+
+RECOVOBJS      = $(O)recover.o
+
+TILEFILES      = $(WSHR)/monsters.txt $(WSHR)/objects.txt $(WSHR)/other.txt
+
+#
+# These are not invoked during a normal game build in 3.4
+#
+TEXT_IO        = $(O)tiletext.o  $(O)tiletxt.o   $(O)drawing.o \
+       $(O)decl.o    $(O)monst.o     $(O)objects.o
+
+TEXT_IO32      = $(O)tilete32.o $(O)tiletx32.o $(O)drawing.o \
+       $(O)decl.o    $(O)monst.o     $(O)objects.o
+
+GIFREADERS     = $(O)gifread.o   $(O)alloc.o $(O)panic.o
+GIFREADERS32   = $(O)gifrd32.o $(O)alloc.o $(O)panic.o
+
+PPMWRITERS     = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o
+
+#
+#  Object files for the game itself.
+#
+
+VOBJ01 = $(O)allmain.o  $(O)alloc.o    $(O)apply.o    $(O)artifact.o
+VOBJ02 = $(O)attrib.o   $(O)ball.o     $(O)bones.o    $(O)botl.o
+VOBJ03 = $(O)cmd.o      $(O)dbridge.o  $(O)decl.o     $(O)detect.o
+VOBJ04 = $(O)dig.o      $(O)display.o  $(O)do.o       $(O)do_name.o
+VOBJ05 = $(O)do_wear.o  $(O)dog.o      $(O)dogmove.o  $(O)dokick.o
+VOBJ06 = $(O)dothrow.o  $(O)drawing.o  $(O)dungeon.o  $(O)eat.o
+VOBJ07 = $(O)end.o      $(O)engrave.o  $(O)exper.o    $(O)explode.o
+VOBJ08 = $(O)extralev.o $(O)files.o    $(O)fountain.o $(O)hack.o
+VOBJ09 = $(O)hacklib.o  $(O)invent.o   $(O)light.o    $(O)lock.o
+VOBJ10 = $(O)mail.o     $(O)makemon.o  $(O)mapglyph.o $(O)mcastu.o
+VOBJ11 = $(O)mhitm.o    $(O)mhitu.o    $(O)minion.o   $(O)mklev.o
+VOBJ12 = $(O)mkmap.o    $(O)mkmaze.o   $(O)mkobj.o    $(O)mkroom.o
+VOBJ13 = $(O)mon.o      $(O)mondata.o  $(O)monmove.o  $(O)monst.o
+VOBJ14 = $(O)monstr.o   $(O)mplayer.o  $(O)mthrowu.o  $(O)muse.o
+VOBJ15 = $(O)music.o    $(O)o_init.o   $(O)objects.o  $(O)objnam.o
+VOBJ16 = $(O)options.o  $(O)pager.o    $(O)pickup.o   $(O)pline.o
+VOBJ17 = $(O)polyself.o $(O)potion.o   $(O)pray.o     $(O)priest.o
+VOBJ18 = $(O)quest.o    $(O)questpgr.o $(RANDOM)      $(O)read.o
+VOBJ19 = $(O)rect.o     $(O)region.o   $(O)restore.o  $(O)rip.o
+VOBJ20 = $(O)rnd.o      $(O)role.o     $(O)rumors.o   $(O)save.o
+VOBJ21 = $(O)shk.o      $(O)shknam.o   $(O)sit.o      $(O)sounds.o
+VOBJ22 = $(O)sp_lev.o   $(O)spell.o    $(O)steal.o    $(O)steed.o
+VOBJ23 = $(O)teleport.o $(O)timeout.o  $(O)topten.o   $(O)track.o
+VOBJ24 = $(O)trap.o     $(O)u_init.o   $(O)uhitm.o    $(O)vault.o
+VOBJ25 = $(O)vis_tab.o  $(O)vision.o   $(O)weapon.o   $(O)were.o
+VOBJ26 = $(O)wield.o    $(O)windows.o  $(O)wizard.o   $(O)worm.o
+VOBJ27 = $(O)worn.o     $(O)write.o    $(O)zap.o
+
+DLBOBJ = $(O)dlb.o
+
+TTYOBJ = $(O)topl.o     $(O)getline.o  $(O)wintty.o
+
+SOBJ   = $(O)winnt.o    $(O)pcsys.o      $(O)pcunix.o  \
+       $(SOUND) $(O)pcmain.o $(O)mapimail.o $(O)nhlan.o
+
+OBJS   = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \
+       $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \
+       $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \
+       $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \
+       $(VOBJ21) $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) \
+       $(VOBJ26) $(VOBJ27)
+
+WINPOBJ = $(WINPORT)
+
+VVOBJ  = $(O)version.o
+
+ALLOBJ  = $(WINPOBJ) $(SOBJ) $(DLBOBJ)  $(TTYOBJ) $(WOBJ) $(OBJS) $(VVOBJ)
+
+ifeq "$(GRAPHICAL)" "Y"
+OPTIONS_FILE = $(DAT)/guioptions
+else
+OPTIONS_FILE = $(DAT)/ttyoptions
+endif
+
+#==========================================
+# Header file macros
+#==========================================
+
+CONFIG_H = $(INCL)/config.h $(INCL)/config1.h $(INCL)/tradstdc.h \
+              $(INCL)/global.h $(INCL)/coord.h $(INCL)/vmsconf.h \
+              $(INCL)/system.h $(INCL)/unixconf.h $(INCL)/os2conf.h \
+              $(INCL)/micro.h $(INCL)/pcconf.h $(INCL)/tosconf.h \
+              $(INCL)/amiconf.h $(INCL)/macconf.h $(INCL)/beconf.h \
+              $(INCL)/ntconf.h $(INCL)/nhlan.h
+
+HACK_H = $(INCL)/hack.h $(CONFIG_H) $(INCL)/align.h \
+              $(INCL)/dungeon.h $(INCL)/monsym.h $(INCL)/mkroom.h \
+              $(INCL)/objclass.h $(INCL)/youprop.h $(INCL)/prop.h \
+              $(INCL)/permonst.h $(INCL)/monattk.h \
+              $(INCL)/monflag.h $(INCL)/mondata.h $(INCL)/pm.h \
+              $(INCL)/wintype.h $(INCL)/decl.h $(INCL)/quest.h \
+              $(INCL)/spell.h $(INCL)/color.h $(INCL)/obj.h \
+              $(INCL)/you.h $(INCL)/attrib.h $(INCL)/monst.h \
+              $(INCL)/skills.h $(INCL)/onames.h $(INCL)/timeout.h \
+              $(INCL)/trap.h $(INCL)/flag.h $(INCL)/rm.h \
+              $(INCL)/vision.h $(INCL)/display.h $(INCL)/engrave.h \
+              $(INCL)/rect.h $(INCL)/region.h $(INCL)/winprocs.h \
+              $(INCL)/wintty.h $(INCL)/trampoli.h
+
+LEV_H       = $(INCL)/lev.h
+DGN_FILE_H  = $(INCL)/dgn_file.h
+LEV_COMP_H  = $(INCL)/lev_comp.h
+SP_LEV_H    = $(INCL)/sp_lev.h
+TILE_H      = ../win/share/tile.h
+
+#==========================================
+# Miscellaneous
+#==========================================
+
+DATABASE = $(DAT)/data.base
+
+#
+#  The name of the game.
+#
+
+GAMEFILE = $(GAMEDIR)/$(GAME).exe
+
+
+#==========================================
+#=============== TARGETS ==================
+#==========================================
+
+# Since DOS doesn't allow / as path separator, and GCC doesn't allow \ as
+# path separator, we must change all pathnames when performing DOS commands.
+# This is done by blindly applying $(subst /,\, ...) on every command.
+# Where any command contain / for another reason (switch char, or echoing
+# comment lines to lev/dungeon files) a little more care is taken.
+
+#
+#  The default make target (so just typing 'nmake' is useful).
+#
+default : $(GAMEFILE)
+
+#
+#  The main target.
+#
+
+$(GAME) : $(O)obj.tag $(O)utility.tag graphicschk $(GAMEFILE)
+       @echo $(GAME) is up to date.
+
+#
+#  Everything
+#
+
+all :   install
+
+install: graphicschk $(GAME) $(O)install.tag
+       @echo Done.
+
+
+$(O)install.tag:  $(DAT)/data    $(DAT)/rumors    $(DAT)/dungeon \
+              $(DAT)/oracles $(DAT)/quest.dat $(O)sp_lev.tag $(DLB)
+ifeq  "$(USE_DLB)" "Y"
+       $(subst /,\,copy nhdat                $(GAMEDIR))
+       $(subst /,\,copy $(DAT)/license       $(GAMEDIR))
+       $(subst /,\,copy $(DAT)/opthelp       $(GAMEDIR))
+else
+       $(subst /,\,copy $(DAT)/*.            $(GAMEDIR))
+       $(subst /,\,copy $(DAT)/*.dat         $(GAMEDIR))
+       $(subst /,\,copy $(DAT)/*.lev         $(GAMEDIR))
+       $(subst /,\,if exist $(GAMEDIR)/makefile del $(GAMEDIR)/makefile)
+endif
+       $(subst /,\,if exist $(DOC)/guidebook.txt copy $(DOC)/guidebook.txt $(GAMEDIR)/Guidebook.txt)
+       $(subst /,\,if exist $(DOC)/nethack.txt copy $(DOC)/nethack.txt $(GAMEDIR)/NetHack.txt)
+       $(subst /,\,copy $(NTSYS)/defaults.nh   $(GAMEDIR)/defaults.nh)
+       $(subst /,\,echo install done > $@)
+
+#  copy $(NTSYS)/winnt.hlp    $(GAMEDIR)
+
+recover: $(U)recover.exe
+       $(subst /,\,if exist $(U)recover.exe copy $(U)recover.exe  $(GAMEDIR))
+       $(subst /,\,if exist $(DOC)/recover.txt copy $(DOC)/recover.txt $(GAMEDIR)/recover.txt)
+
+$(O)sp_lev.tag: $(O)utility.tag $(DAT)/bigroom.des  $(DAT)/castle.des \
+        $(DAT)/endgame.des $(DAT)/gehennom.des $(DAT)/knox.des   \
+        $(DAT)/medusa.des  $(DAT)/oracle.des   $(DAT)/tower.des  \
+        $(DAT)/yendor.des  $(DAT)/arch.des     $(DAT)/barb.des   \
+        $(DAT)/caveman.des $(DAT)/healer.des   $(DAT)/knight.des \
+        $(DAT)/monk.des    $(DAT)/priest.des   $(DAT)/ranger.des \
+        $(DAT)/rogue.des   $(DAT)/samurai.des  $(DAT)/sokoban.des \
+        $(DAT)/tourist.des $(DAT)/valkyrie.des $(DAT)/wizard.des
+       $(subst /,\,$(U)lev_comp $(DAT)/bigroom.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/castle.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/endgame.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/gehennom.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/knox.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/mines.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/medusa.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/oracle.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/sokoban.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/tower.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/yendor.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/arch.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/barb.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/caveman.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/healer.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/knight.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/monk.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/priest.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/ranger.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/rogue.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/samurai.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/tourist.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/valkyrie.des)
+       $(subst /,\,$(U)lev_comp $(DAT)/wizard.des)
+       $(subst /,\,copy *.lev $(DAT))
+       $(subst /,\,del *.lev)
+       $(subst /,\,echo sp_levs done > $(O)sp_lev.tag)
+
+$(O)utility.tag: $(INCL)/date.h $(INCL)/onames.h $(INCL)/pm.h \
+        $(SRC)/monstr.c $(SRC)/vis_tab.c $(U)lev_comp.exe $(INCL)/vis_tab.h \
+        $(U)dgn_comp.exe $(TILEUTIL16)
+       $(subst /,\,@echo utilities made >$@)
+       @echo utilities made.
+
+tileutil: $(U)gif2txt.exe $(U)gif2tx32.exe $(U)txt2ppm.exe
+       @echo Optional tile development utilities are up to date.
+
+ifeq  "$(GRAPHICAL)" "Y"
+$(NHRES): $(TILEBMP16) $(WIN32)/winhack.rc $(WIN32)/mnsel.bmp \
+        $(WIN32)/mnselcnt.bmp $(WIN32)/mnunsel.bmp \
+        $(WIN32)/petmark.bmp $(WIN32)/NetHack.ico $(WIN32)/rip.bmp \
+        $(WIN32)/splash.bmp
+       @$(rc) -o$@ --include-dir $(WIN32) -i $(WIN32)/winhack.rc
+else
+$(NHRES): $(NTSYS)/console.rc $(NTSYS)/NetHack.ico 
+       @$(rc) -o$@ --include-dir $(NTSYS) -i $(NTSYS)/console.rc
+endif
+
+#==========================================
+#  The main target.
+#==========================================
+$(O)gamedir.tag:
+       $(subst /,\,@if not exist $(GAMEDIR)/*.* echo creating directory $(GAMEDIR))
+       $(subst /,\,@if not exist $(GAMEDIR)/*.* mkdir $(GAMEDIR))
+       $(subst /,\,@echo directory created > $@)
+
+ifeq  "$(GRAPHICAL)" "Y"
+$(GAMEFILE) : $(ALLOBJ) $(NHRES) $(O)gamedir.tag
+else
+$(GAMEFILE) : $(ALLOBJ) $(NHRES) $(O)gamedir.tag \
+        $(GAMEDIR)/nhdefkey.dll $(GAMEDIR)/nh340key.dll $(GAMEDIR)/nhraykey.dll
+endif
+       @echo Linking....
+       @$(link) $(lflags) -o$@ $(ALLOBJ) $(NHRES) $(WINPLIBS)
+       $(subst /,\,@if exist $(O)install.tag del $(O)install.tag)
+
+
+$(O)nhdefkey.o:
+       $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(NTSYS)/nhdefkey.c 
+
+$(GAMEDIR)/nhdefkey.dll : $(O)nhdefkey.o $(O)gamedir.tag
+       @echo Linking $@
+       $(cc) -shared -Wl,--export-all-symbols \
+               -Wl,--add-stdcall-alias -o $@ $<
+
+$(O)nh340key.o:
+       $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(NTSYS)/nh340key.c 
+
+$(GAMEDIR)/nh340key.dll : $(O)nh340key.o $(O)gamedir.tag
+       @echo Linking $@
+       $(cc) -shared -Wl,--export-all-symbols \
+               -Wl,--add-stdcall-alias -o $@ $<
+
+$(O)nhraykey.o:
+               $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(NTSYS)/nhraykey.c 
+
+$(GAMEDIR)/nhraykey.dll : $(O)nhraykey.o $(O)gamedir.tag
+       @echo Linking $@
+       $(cc) -shared -Wl,--export-all-symbols \
+               -Wl,--add-stdcall-alias -o $@ $<
+
+$(GAME)_.ico : $(NTSYS)/$(GAME).ico
+       $(subst /,\,@copy $(NTSYS)/$(GAME).ico $@)
+
+#==========================================
+# Create directory for holding object files
+#==========================================
+
+graphicschk:
+ifeq  "$(GRAPHICAL)" "Y"
+       @echo ----
+       @echo NOTE: This build will include tile support.
+       @echo ----
+endif
+       $(subst /,\,@echo graphicschk > graphicschk)
+
+#
+#  Secondary Targets.
+#
+
+#==========================================
+# Makedefs Stuff
+#==========================================
+
+$(U)makedefs.exe: $(MAKEOBJS)
+       @$(link) $(LFLAGSU) -o$@ $(MAKEOBJS)
+
+$(O)makedefs.o: $(CONFIG_H) $(INCL)/monattk.h $(INCL)/monflag.h \
+        $(INCL)/objclass.h $(INCL)/monsym.h $(INCL)/qtext.h \
+        $(INCL)/patchlevel.h $(U)makedefs.c $(O)obj.tag
+       $(cc) $(CFLAGSU) -o$@ $(U)makedefs.c
+
+#
+#  date.h should be remade every time any of the source or include
+#  files is modified.
+#
+
+$(INCL)/date.h $(OPTIONS_FILE): $(U)makedefs.exe
+       $(subst /,\,$(U)makedefs -v)
+
+#$(OPTIONS_FILE): $(U)makedefs.exe
+#      $(subst /,\,$(U)makedefs -v)
+
+$(INCL)/onames.h : $(U)makedefs.exe
+       $(subst /,\,$(U)makedefs -o)
+
+$(INCL)/pm.h : $(U)makedefs.exe
+       $(subst /,\,$(U)makedefs -p)
+
+#$(INCL)/trap.h : $(U)makedefs.exe
+#  $(U)makedefs -t
+
+$(SRC)/monstr.c: $(U)makedefs.exe
+       $(subst /,\,$(U)makedefs -m)
+
+$(INCL)/vis_tab.h: $(U)makedefs.exe
+       $(subst /,\,$(U)makedefs -z)
+
+$(SRC)/vis_tab.c: $(U)makedefs.exe
+       $(subst /,\,$(U)makedefs -z)
+
+#==========================================
+# uudecode utility and uuencoded targets
+#==========================================
+
+$(U)uudecode.exe: $(O)uudecode.o
+       @$(link) $(LFLAGSU) -o$@ $(O)uudecode.o
+
+$(O)uudecode.o: $(SSYS)/uudecode.c
+
+$(NTSYS)/NetHack.ico : $(U)uudecode.exe $(NTSYS)/nhico.uu
+       $(subst /,\,$(U)uudecode.exe $(NTSYS)/nhico.uu)
+       $(subst /,\,copy NetHack.ico $@)
+       del NetHack.ico
+
+$(WIN32)/NetHack.ico : $(NTSYS)/NetHack.ico
+       $(subst /,\,copy $< $@)
+
+$(WIN32)/mnsel.bmp: $(U)uudecode.exe $(WIN32)/mnsel.uu
+       $(subst /,\,$(U)uudecode.exe $(WIN32)/mnsel.uu)
+       $(subst /,\,copy mnsel.bmp $@)
+       del mnsel.bmp
+
+$(WIN32)/mnselcnt.bmp: $(U)uudecode.exe $(WIN32)/mnselcnt.uu
+       $(subst /,\,$(U)uudecode.exe $(WIN32)/mnselcnt.uu)
+       $(subst /,\,copy mnselcnt.bmp $@)
+       del mnselcnt.bmp
+
+$(WIN32)/mnunsel.bmp: $(U)uudecode.exe $(WIN32)/mnunsel.uu
+       $(subst /,\,$(U)uudecode.exe $(WIN32)/mnunsel.uu)
+       $(subst /,\,copy mnunsel.bmp $@)
+       del mnunsel.bmp
+
+$(WIN32)/petmark.bmp: $(U)uudecode.exe $(WIN32)/petmark.uu
+       $(subst /,\,$(U)uudecode.exe $(WIN32)/petmark.uu)
+       $(subst /,\,copy petmark.bmp $@)
+       del petmark.bmp
+
+$(WIN32)/rip.bmp: $(U)uudecode.exe $(WIN32)/rip.uu
+       $(subst /,\,$(U)uudecode.exe $(WIN32)/rip.uu)
+       $(subst /,\,copy rip.bmp $@)
+       del rip.bmp
+
+$(WIN32)/splash.bmp: $(U)uudecode.exe $(WIN32)/splash.uu
+       $(subst /,\,$(U)uudecode.exe $(WIN32)/splash.uu)
+       $(subst /,\,copy splash.bmp $@)
+       del splash.bmp
+
+
+#==========================================
+# Level Compiler Stuff
+#==========================================
+
+LEVCFLAGS=$(cflags) -c -DWIN32 -D_WIN32 -I../include $(cdebug) -DDLB
+
+$(U)lev_comp.exe: $(SPLEVOBJS)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(SPLEVOBJS)
+
+$(O)lev_yacc.o: $(HACK_H)   $(SP_LEV_H) $(INCL)/lev_comp.h $(U)lev_yacc.c
+       $(cc) $(LEVCFLAGS) -o$@ $(U)lev_yacc.c
+
+$(O)lev_$(LEX).o: $(HACK_H)   $(INCL)/lev_comp.h $(SP_LEV_H) \
+       $(U)lev_$(LEX).c
+       $(cc) $(LEVCFLAGS) -o$@ $(U)lev_$(LEX).c
+
+$(O)lev_main.o:   $(U)lev_main.c $(HACK_H)   $(SP_LEV_H)
+       $(cc) $(LEVCFLAGS) -o$@ $(U)lev_main.c
+
+
+$(U)lev_yacc.c $(INCL)/lev_comp.h : $(U)lev_comp.y
+ifeq  "$(DO_YACC)" "YACC_ACT"
+       $(subst /,\,$(YACC) -d $(U)lev_comp.y)
+       $(subst /,\,copy $(YTABC) $(U)lev_yacc.c)
+       $(subst /,\,copy $(YTABH) $(INCL)/lev_comp.h)
+       $(subst /,\,@del $(YTABC))
+       $(subst /,\,@del $(YTABH))
+
+else
+       @echo $(U)lev_comp.y has changed.
+       @echo To update $(U)lev_yacc.c and $(INCL)/lev_comp.h run $(YACC).
+       @echo ---
+       @echo For now, we will copy the prebuilt lev_yacc.c and
+       @echo lev_comp.h from $(SSYS) into $(UTIL) and use them.
+       $(subst /,\,@copy $(SSYS)/lev_yacc.c $(U)lev_yacc.c >nul)
+       $(subst /,\,@copy $(SSYS)/lev_comp.h $(INCL)/lev_comp.h >nul)
+       $(subst /,\,echo.>>$(U)lev_yacc.c)
+       $(subst /,\,echo.>>$(INCL)/lev_comp.h)
+endif
+
+$(U)lev_$(LEX).c: $(U)lev_comp.l
+ifeq  "$(DO_LEX)" "LEX_ACT"
+       $(subst /,\,$(LEX) $(FLEXSKEL) $(U)lev_comp.l)
+       $(subst /,\,copy $(LEXYYC) $@)
+       $(subst /,\,@del $(LEXYYC))
+else
+       @echo $(U)lev_comp.l has changed. To update $@ run $(LEX).
+       @echo ---
+       @echo For now, we will copy the prebuilt lev_lex.c
+       @echo from $(SSYS) into $(UTIL) and use it.
+       $(subst /,\,@copy $(SSYS)/lev_lex.c $@ >nul)
+       $(subst /,\,echo.>>$@)
+endif
+
+#==========================================
+# Dungeon Compiler Stuff
+#==========================================
+
+$(U)dgn_comp.exe: $(DGNCOMPOBJS)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(DGNCOMPOBJS)
+
+
+$(O)dgn_yacc.o:   $(HACK_H)   $(DGN_FILE_H) $(INCL)/dgn_comp.h $(U)dgn_yacc.c
+       $(cc) $(LEVCFLAGS) -o$@ $(U)dgn_yacc.c
+
+$(O)dgn_$(LEX).o: $(HACK_H)   $(DGN_FILE_H)  $(INCL)/dgn_comp.h \
+        $(U)dgn_$(LEX).c
+       $(cc) $(LEVCFLAGS) -o$@ $(U)dgn_$(LEX).c
+
+$(O)dgn_main.o:   $(HACK_H) $(U)dgn_main.c
+       $(cc) $(LEVCFLAGS) -o$@ $(U)dgn_main.c
+
+$(U)dgn_yacc.c $(INCL)/dgn_comp.h : $(U)dgn_comp.y
+ifeq  "$(DO_YACC)" "YACC_ACT"
+       $(subst /,\,$(YACC) -d $(U)dgn_comp.y)
+       $(subst /,\,copy $(YTABC) $(U)dgn_yacc.c)
+       $(subst /,\,copy $(YTABH) $(INCL)/dgn_comp.h)
+       $(subst /,\,@del $(YTABC))
+       $(subst /,\,@del $(YTABH))
+else
+       @echo $(U)dgn_comp.y has changed. To update dgn_yacc.c and
+       @echo $(INCL)/dgn_comp.h run $(YACC).
+       @echo ---
+       @echo For now, we will copy the prebuilt $(U)dgn_yacc.c and
+       @echo dgn_comp.h from $(SSYS) into $(UTIL) and use them.
+       $(subst /,\,@copy $(SSYS)/dgn_yacc.c $(U)dgn_yacc.c >nul)
+       $(subst /,\,@copy $(SSYS)/dgn_comp.h $(INCL)/dgn_comp.h >nul)
+       $(subst /,\,echo.>>$(U)dgn_yacc.c)
+       $(subst /,\,echo.>>$(INCL)/dgn_comp.h)
+endif
+
+$(U)dgn_$(LEX).c: $(U)dgn_comp.l
+ifeq  "$(DO_LEX)" "LEX_ACT"
+       $(subst /,\,$(LEX) $(FLEXSKEL) $(U)dgn_comp.l)
+       $(subst /,\,copy $(LEXYYC) $@)
+       $(subst /,\,@del $(LEXYYC))
+else
+       @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX).
+       @echo ---
+       @echo For now, we will copy the prebuilt dgn_lex.c
+       @echo from $(SSYS) into $(UTIL) and use it.
+       $(subst /,\,@copy $(SSYS)/dgn_lex.c $@ >nul)
+       $(subst /,\,echo.>>$@)
+endif
+
+#==========================================
+# Create directory for holding object files
+#==========================================
+
+$(O)obj.tag:
+       $(subst /,\,@if not exist $(OBJ)/*.* echo creating directory $(OBJ))
+       $(subst /,\,@if not exist $(OBJ)/*.* mkdir $(OBJ))
+       $(subst /,\,@echo directory created > $@)
+
+
+#==========================================
+#=========== SECONDARY TARGETS ============
+#==========================================
+
+#===========================================
+# Header files NOT distributed in ../include
+#===========================================
+
+$(INCL)/win32api.h: $(NTSYS)/win32api.h
+       $(subst /,\,copy $(NTSYS)/win32api.h $@)
+
+
+#==========================================
+# DLB utility and nhdat file creation
+#==========================================
+
+$(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o
+       @$(link) $(LFLAGSU) -o$@ $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o
+
+
+$(O)dlb.o:   $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)/dlb.h
+       $(cc) $(CFLAGS) -o$@ $(SRC)/dlb.c
+
+$(O)dlb_main.o: $(UTIL)/dlb_main.c $(INCL)/config.h $(INCL)/dlb.h
+       $(cc) $(CFLAGS) -o$@ $(UTIL)/dlb_main.c
+
+$(DAT)/porthelp: $(NTSYS)/porthelp
+       $(subst /,\,@copy $(NTSYS)/porthelp $@ >nul)
+
+nhdat:  $(U)dlb_main.exe $(DAT)/data $(DAT)/oracles $(OPTIONS_FILE) \
+        $(DAT)/quest.dat $(DAT)/rumors $(DAT)/help $(DAT)/hh $(DAT)/cmdhelp \
+        $(DAT)/history $(DAT)/opthelp $(DAT)/wizhelp $(DAT)/dungeon \
+        $(DAT)/porthelp $(DAT)/license $(O)sp_lev.tag
+       $(subst /,\,echo data >$(DAT)/dlb.lst)
+       $(subst /,\,echo oracles >>$(DAT)/dlb.lst)
+       $(subst /,\,if exist $(DAT)/options echo options >>$(DAT)/dlb.lst)
+       $(subst /,\,if exist $(DAT)/ttyoptions echo ttyoptions >>$(DAT)/dlb.lst)
+       $(subst /,\,if exist $(DAT)/guioptions echo guioptions >>$(DAT)/dlb.lst)
+       $(subst /,\,if exist $(DAT)/porthelp echo porthelp >>$(DAT)/dlb.lst)
+       $(subst /,\,echo quest.dat >>$(DAT)/dlb.lst)
+       $(subst /,\,echo rumors >>$(DAT)/dlb.lst)
+       $(subst /,\,echo help >>$(DAT)/dlb.lst)
+       $(subst /,\,echo hh >>$(DAT)/dlb.lst)
+       $(subst /,\,echo cmdhelp >>$(DAT)/dlb.lst)
+       $(subst /,\,echo history >>$(DAT)/dlb.lst)
+       $(subst /,\,echo opthelp >>$(DAT)/dlb.lst)
+       $(subst /,\,echo wizhelp >>$(DAT)/dlb.lst)
+       $(subst /,\,echo dungeon >>$(DAT)/dlb.lst)
+       $(subst /,\,echo license >>$(DAT)/dlb.lst)
+       dir /l /b /-p $(subst /,\,$(DAT)/*.lev >>$(DAT)/dlb.lst)
+       $(subst /,\,$(U)dlb_main CcIf $(DAT) dlb.lst $(SRC)/nhdat)
+
+#==========================================
+#  Recover Utility
+#==========================================
+
+$(U)recover.exe: $(RECOVOBJS)
+       $(link) $(LFLAGSU) -o$@ $(RECOVOBJS)
+
+$(O)recover.o: $(CONFIG_H) $(U)recover.c $(INCL)/win32api.h
+       $(cc) $(CFLAGSU) -o$@ $(U)recover.c
+
+#==========================================
+#  Tile Mapping
+#==========================================
+
+$(SRC)/tile.c: $(U)tilemap.exe
+       @echo A new $@ has been created
+       @$(U)tilemap
+
+$(U)tilemap.exe: $(O)tilemap.o
+       @$(link) $(LFLAGSU) -o$@ $(O)tilemap.o
+
+$(O)tilemap.o: $(WSHR)/tilemap.c $(HACK_H)
+       $(cc) $(CFLAGSU) -o$@ $(WSHR)/tilemap.c
+
+$(O)tiletx32.o: $(WSHR)/tilemap.c $(HACK_H)
+       $(cc) $(CFLAGS) -DTILETEXT -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/tilemap.c
+
+$(O)tiletxt.o: $(WSHR)/tilemap.c $(HACK_H)
+       $(cc) $(CFLAGS) -DTILETEXT -o$@ $(WSHR)/tilemap.c
+
+$(O)gifread.o: $(WSHR)/gifread.c  $(CONFIG_H) $(TILE_H)
+       $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/gifread.c
+
+$(O)gifrd32.o: $(WSHR)/gifread.c  $(CONFIG_H) $(TILE_H)
+       $(cc) $(CFLAGS) -I$(WSHR) -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/gifread.c
+
+$(O)ppmwrite.o: $(WSHR)/ppmwrite.c $(CONFIG_H) $(TILE_H)
+       $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/ppmwrite.c
+
+$(O)tiletext.o: $(WSHR)/tiletext.c  $(CONFIG_H) $(TILE_H)
+       $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/tiletext.c
+
+$(O)tilete32.o: $(WSHR)/tiletext.c  $(CONFIG_H) $(TILE_H)
+       $(cc) $(CFLAGS) -I$(WSHR) -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/tiletext.c
+
+#==========================================
+# Optional Tile Utilities
+#==========================================
+
+$(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(GIFREADERS) $(TEXT_IO)
+
+$(U)gif2tx32.exe: $(GIFREADERS32) $(TEXT_IO32)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(GIFREADERS32) $(TEXT_IO32)
+
+
+$(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(PPMWRITERS) $(TEXT_IO)
+
+
+ifeq  "$(GRAPHICAL)" "Y"
+$(TILEBMP16): $(TILEUTIL16) $(TILEFILES)
+       @echo Creating 16x16 binary tile files (this may take some time)
+       $(subst /,\,@$(U)tile2bmp $(TILEBMP16))
+#$(TILEBMP32): $(TILEUTIL32) $(TILEFILES32)
+#      @echo Creating 32x32 binary tile files (this may take some time)
+#      $(subst /,\,@$(U)til2bm32 $(TILEBMP32))
+else
+$(TILEBMP16):
+$(TILEBMP32):
+endif
+
+$(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(O)tile2bmp.o $(TEXT_IO)
+
+$(U)til2bm32.exe: $(O)til2bm32.o $(TEXT_IO32)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -o$@ $(O)til2bm32.o $(TEXT_IO32)
+
+$(O)tile2bmp.o: $(WSHR)/tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)/win32api.h
+       $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/tile2bmp.c
+
+$(O)til2bm32.o: $(WSHR)/til2bm32.c $(HACK_H) $(TILE_H) $(INCL)/win32api.h
+       $(cc) $(CFLAGS) -I$(WSHR) -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/til2bm32.c
+
+#==========================================
+# Housekeeping
+#==========================================
+
+spotless: clean
+       $(subst /,\,if exist graphicschk       del graphicschk)
+       $(subst /,\,if exist $(INCL)/date.h    del $(INCL)/date.h)
+       $(subst /,\,if exist $(INCL)/onames.h  del $(INCL)/onames.h)
+       $(subst /,\,if exist $(INCL)/pm.h      del $(INCL)/pm.h)
+       $(subst /,\,if exist $(INCL)/vis_tab.h del $(INCL)/vis_tab.h)
+       $(subst /,\,if exist $(SRC)/vis_tab.c  del $(SRC)/vis_tab.c)
+       $(subst /,\,if exist $(SRC)/tile.c     del $(SRC)/tile.c)
+       $(subst /,\,if exist $(U)*.lnk         del $(U)*.lnk)
+       $(subst /,\,if exist $(U)*.map         del $(U)*.map)
+       $(subst /,\,if exist $(DAT)/data       del $(DAT)/data)
+       $(subst /,\,if exist $(DAT)/rumors     del $(DAT)/rumors)
+       $(subst /,\,if exist $(DAT)/???-fil?.lev      del $(DAT)/???-fil?.lev)
+       $(subst /,\,if exist $(DAT)/???-goal.lev      del $(DAT)/???-goal.lev)
+       $(subst /,\,if exist $(DAT)/???-loca.lev      del $(DAT)/???-loca.lev)
+       $(subst /,\,if exist $(DAT)/???-strt.lev      del $(DAT)/???-strt.lev)
+       $(subst /,\,if exist $(DAT)/air.lev      del $(DAT)/air.lev)
+       $(subst /,\,if exist $(DAT)/asmodeus.lev      del $(DAT)/asmodeus.lev)
+       $(subst /,\,if exist $(DAT)/astral.lev   del $(DAT)/astral.lev)
+       $(subst /,\,if exist $(DAT)/baalz.lev    del $(DAT)/baalz.lev)
+       $(subst /,\,if exist $(DAT)/bigrm-*.lev  del $(DAT)/bigrm-*.lev)
+       $(subst /,\,if exist $(DAT)/castle.lev   del $(DAT)/castle.lev)
+       $(subst /,\,if exist $(DAT)/data    del $(DAT)/data)
+       $(subst /,\,if exist $(DAT)/dungeon      del $(DAT)/dungeon)
+       $(subst /,\,if exist $(DAT)/dungeon.pdf  del $(DAT)/dungeon.pdf)
+       $(subst /,\,if exist $(DAT)/earth.lev    del $(DAT)/earth.lev)
+       $(subst /,\,if exist $(DAT)/fakewiz?.lev      del $(DAT)/fakewiz?.lev)
+       $(subst /,\,if exist $(DAT)/fire.lev     del $(DAT)/fire.lev)
+       $(subst /,\,if exist $(DAT)/juiblex.lev  del $(DAT)/juiblex.lev)
+       $(subst /,\,if exist $(DAT)/knox.lev     del $(DAT)/knox.lev)
+       $(subst /,\,if exist $(DAT)/medusa-?.lev      del $(DAT)/medusa-?.lev)
+       $(subst /,\,if exist $(DAT)/mine*.lev    del $(DAT)/mine*.lev)
+       $(subst /,\,if exist $(DAT)/options      del $(DAT)/options)
+       $(subst /,\,if exist $(DAT)/ttyoptions   del $(DAT)/ttyoptions)
+       $(subst /,\,if exist $(DAT)/guioptions   del $(DAT)/guioptions)
+       $(subst /,\,if exist $(DAT)/oracle.lev   del $(DAT)/oracle.lev)
+       $(subst /,\,if exist $(DAT)/oracles      del $(DAT)/oracles)
+       $(subst /,\,if exist $(DAT)/orcus.lev    del $(DAT)/orcus.lev)
+       $(subst /,\,if exist $(DAT)/rumors  del $(DAT)/rumors)
+       $(subst /,\,if exist $(DAT)/quest.dat    del $(DAT)/quest.dat)
+       $(subst /,\,if exist $(DAT)/sanctum.lev  del $(DAT)/sanctum.lev)
+       $(subst /,\,if exist $(DAT)/soko?-?.lev  del $(DAT)/soko?-?.lev)
+       $(subst /,\,if exist $(DAT)/tower?.lev   del $(DAT)/tower?.lev)
+       $(subst /,\,if exist $(DAT)/valley.lev   del $(DAT)/valley.lev)
+       $(subst /,\,if exist $(DAT)/water.lev    del $(DAT)/water.lev)
+       $(subst /,\,if exist $(DAT)/wizard?.lev  del $(DAT)/wizard?.lev)
+       $(subst /,\,if exist $(O)sp_lev.tag     del $(O)sp_lev.tag)
+       $(subst /,\,if exist $(SRC)/monstr.c    del $(SRC)/monstr.c)
+       $(subst /,\,if exist $(SRC)/vis_tab.c   del $(SRC)/vis_tab.c)
+       $(subst /,\,if exist $(U)recover.exe    del $(U)recover.exe)
+       $(subst /,\,if exist $(DAT)/dlb.lst      del $(DAT)/dlb.lst)
+       $(subst /,\,if exist nhdat.         del nhdat.)
+       $(subst /,\,if exist $(O)install.tag    del $(O)install.tag)
+       $(subst /,\,if exist $(O)obj.tag    del $(O)obj.tag)
+       $(subst /,\,if exist $(O)gamedir.tag    del $(O)gamedir.tag)
+ifneq "$(OBJ)" ""
+       $(subst /,\,rmdir $(OBJ)) /s /Q
+endif
+
+clean:
+       $(subst /,\,if exist $(O)*.o del $(O)*.o)
+       $(subst /,\,if exist $(O)utility.tag   del $(O)utility.tag)
+       $(subst /,\,if exist $(U)makedefs.exe  del $(U)makedefs.exe)
+       $(subst /,\,if exist $(U)lev_comp.exe  del $(U)lev_comp.exe)
+       $(subst /,\,if exist $(U)dgn_comp.exe  del $(U)dgn_comp.exe)
+       $(subst /,\,if exist $(SRC)/*.lnk      del $(SRC)/*.lnk)
+       $(subst /,\,if exist $(SRC)/*.map      del $(SRC)/*.map)
+       $(subst /,\,if exist $(TILEBMP16)      del $(TILEBMP16))
+       $(subst /,\,if exist $(TILEBMP32)      del $(TILEBMP32))
+
+#===================================================================
+# OTHER DEPENDENCIES
+#===================================================================
+
+#
+# dat dependencies
+#
+
+$(DAT)/data: $(O)utility.tag    $(DATABASE)
+       $(subst /,\,$(U)makedefs -d)
+
+$(DAT)/rumors: $(O)utility.tag    $(DAT)/rumors.tru   $(DAT)/rumors.fal
+       $(subst /,\,$(U)makedefs -r)
+
+$(DAT)/quest.dat: $(O)utility.tag  $(DAT)/quest.txt
+       $(subst /,\,$(U)makedefs -q)
+
+$(DAT)/oracles: $(O)utility.tag    $(DAT)/oracles.txt
+       $(subst /,\,$(U)makedefs -h)
+
+$(DAT)/dungeon: $(O)utility.tag  $(DAT)/dungeon.def
+       $(subst /,\,$(U)makedefs -e)
+       $(subst /,\,$(U)dgn_comp $(DAT)/dungeon.pdf)
+
+#
+# NT dependencies
+#
+
+$(O)nttty.o:   $(HACK_H) $(TILE_H) $(INCL)/win32api.h $(NTSYS)/nttty.c
+       $(cc) $(CFLAGS) -I$(WSHR) -o$@  $(NTSYS)/nttty.c
+$(O)winnt.o: $(HACK_H) $(INCL)/win32api.h $(NTSYS)/winnt.c
+       $(cc) $(CFLAGS) -o$@  $(NTSYS)/winnt.c
+$(O)ntsound.o: $(HACK_H) $(NTSYS)/ntsound.c
+       $(cc) $(CFLAGS)  -o$@ $(NTSYS)/ntsound.c
+$(O)mapimail.o: $(HACK_H) $(INCL)/nhlan.h $(NTSYS)/mapimail.c
+       $(cc) $(CFLAGS) -DMAPI_VERBOSE  -o$@ $(NTSYS)/mapimail.c
+
+#
+# util dependencies
+#
+
+$(O)panic.o:  $(U)panic.c $(CONFIG_H)
+       $(cc) $(CFLAGS) -o$@ $(U)panic.c
+
+#
+# The rest are stolen from sys/unix/Makefile.src,
+# with the following changes:
+#   * ../include changed to $(INCL)
+#   * -c (which is included in CFLAGS) substituted
+#      with -o$@
+#   * targets prefixed with $(O)
+#   * $(CC) changed to $(cc)
+# but otherwise untouched. 
+# That means that there is some irrelevant stuff
+# in here, but maintenance should be easier.
+#
+$(O)tos.o: ../sys/atari/tos.c $(HACK_H) $(INCL)/tcap.h
+       $(cc) $(CFLAGS) -o$@ ../sys/atari/tos.c
+$(O)pcmain.o: ../sys/share/pcmain.c $(HACK_H) $(INCL)/dlb.h \
+               $(INCL)/win32api.h
+       $(cc) $(CFLAGS) -o$@ ../sys/share/pcmain.c
+$(O)pcsys.o: ../sys/share/pcsys.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/share/pcsys.c
+$(O)pctty.o: ../sys/share/pctty.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/share/pctty.c
+$(O)pcunix.o: ../sys/share/pcunix.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/share/pcunix.c
+$(O)random.o: ../sys/share/random.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/share/random.c
+$(O)ioctl.o: ../sys/share/ioctl.c $(HACK_H) $(INCL)/tcap.h
+       $(cc) $(CFLAGS) -o$@ ../sys/share/ioctl.c
+$(O)unixtty.o: ../sys/share/unixtty.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/share/unixtty.c
+$(O)unixmain.o: ../sys/unix/unixmain.c $(HACK_H) $(INCL)/dlb.h
+       $(cc) $(CFLAGS) -o$@ ../sys/unix/unixmain.c
+$(O)unixunix.o: ../sys/unix/unixunix.c $(HACK_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/unix/unixunix.c
+$(O)unixres.o: ../sys/unix/unixres.c $(CONFIG_H)
+       $(cc) $(CFLAGS) -o$@ ../sys/unix/unixres.c
+$(O)bemain.o: ../sys/be/bemain.c $(HACK_H) $(INCL)/dlb.h
+       $(cc) $(CFLAGS) -o$@ ../sys/be/bemain.c
+$(O)getline.o: ../win/tty/getline.c $(HACK_H) $(INCL)/func_tab.h
+       $(cc) $(CFLAGS) -o$@ ../win/tty/getline.c
+$(O)termcap.o: ../win/tty/termcap.c $(HACK_H) $(INCL)/tcap.h
+       $(cc) $(CFLAGS) -o$@ ../win/tty/termcap.c
+$(O)topl.o: ../win/tty/topl.c $(HACK_H) $(INCL)/tcap.h
+       $(cc) $(CFLAGS) -o$@ ../win/tty/topl.c
+$(O)wintty.o: ../win/tty/wintty.c $(HACK_H) $(INCL)/dlb.h \
+               $(INCL)/patchlevel.h $(INCL)/tcap.h
+       $(cc) $(CFLAGS) -o$@ ../win/tty/wintty.c
+$(O)Window.o: ../win/X11/Window.c $(INCL)/xwindowp.h $(INCL)/xwindow.h \
+               $(CONFIG_H)
+       $(cc) $(CFLAGS) -o$@ ../win/X11/Window.c
+$(O)dialogs.o: ../win/X11/dialogs.c $(CONFIG_H)
+       $(cc) $(CFLAGS) -o$@ ../win/X11/dialogs.c
+$(O)winX.o: ../win/X11/winX.c $(HACK_H) $(INCL)/winX.h $(INCL)/dlb.h \
+               $(INCL)/patchlevel.h ../win/X11/nh72icon \
+               ../win/X11/nh56icon ../win/X11/nh32icon
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winX.c
+$(O)winmap.o: ../win/X11/winmap.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/dlb.h \
+               $(INCL)/winX.h $(INCL)/tile2x11.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winmap.c
+$(O)winmenu.o: ../win/X11/winmenu.c $(HACK_H) $(INCL)/winX.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winmenu.c
+$(O)winmesg.o: ../win/X11/winmesg.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/winX.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winmesg.c
+$(O)winmisc.o: ../win/X11/winmisc.c $(HACK_H) $(INCL)/func_tab.h \
+               $(INCL)/winX.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winmisc.c
+$(O)winstat.o: ../win/X11/winstat.c $(HACK_H) $(INCL)/winX.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winstat.c
+$(O)wintext.o: ../win/X11/wintext.c $(HACK_H) $(INCL)/winX.h $(INCL)/xwindow.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/wintext.c
+$(O)winval.o: ../win/X11/winval.c $(HACK_H) $(INCL)/winX.h
+       $(cc) $(CFLAGS) -o$@ ../win/X11/winval.c
+$(O)tile.o: tile.c $(HACK_H)
+$(O)gnaskstr.o: ../win/gnome/gnaskstr.c ../win/gnome/gnaskstr.h \
+               ../win/gnome/gnmain.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnaskstr.c
+$(O)gnbind.o: ../win/gnome/gnbind.c ../win/gnome/gnbind.h ../win/gnome/gnmain.h \
+               ../win/gnome/gnaskstr.h ../win/gnome/gnyesno.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnbind.c
+$(O)gnglyph.o: ../win/gnome/gnglyph.c ../win/gnome/gnglyph.h $(INCL)/tile2x11.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnglyph.c
+$(O)gnmain.o: ../win/gnome/gnmain.c ../win/gnome/gnmain.h ../win/gnome/gnsignal.h \
+               ../win/gnome/gnbind.h ../win/gnome/gnopts.h $(HACK_H) \
+               $(INCL)/date.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmain.c
+$(O)gnmap.o: ../win/gnome/gnmap.c ../win/gnome/gnmap.h ../win/gnome/gnglyph.h \
+               ../win/gnome/gnsignal.h $(HACK_H)
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmap.c
+$(O)gnmenu.o: ../win/gnome/gnmenu.c ../win/gnome/gnmenu.h ../win/gnome/gnmain.h \
+               ../win/gnome/gnbind.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmenu.c
+$(O)gnmesg.o: ../win/gnome/gnmesg.c ../win/gnome/gnmesg.h ../win/gnome/gnsignal.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmesg.c
+$(O)gnopts.o: ../win/gnome/gnopts.c ../win/gnome/gnopts.h ../win/gnome/gnglyph.h \
+               ../win/gnome/gnmain.h ../win/gnome/gnmap.h $(HACK_H)
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnopts.c
+$(O)gnplayer.o: ../win/gnome/gnplayer.c ../win/gnome/gnplayer.h \
+               ../win/gnome/gnmain.h $(HACK_H)
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnplayer.c
+$(O)gnsignal.o: ../win/gnome/gnsignal.c ../win/gnome/gnsignal.h \
+               ../win/gnome/gnmain.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnsignal.c
+$(O)gnstatus.o: ../win/gnome/gnstatus.c ../win/gnome/gnstatus.h \
+               ../win/gnome/gnsignal.h ../win/gnome/gn_xpms.h \
+               ../win/gnome/gnomeprv.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnstatus.c
+$(O)gntext.o: ../win/gnome/gntext.c ../win/gnome/gntext.h ../win/gnome/gnmain.h \
+               ../win/gnome/gn_rip.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gntext.c
+$(O)gnworn.o: ../win/gnome/gnworn.c ../win/gnome/gnworn.h ../win/gnome/gnglyph.h \
+               ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnworn.c
+$(O)gnyesno.o: ../win/gnome/gnyesno.c ../win/gnome/gnbind.h ../win/gnome/gnyesno.h
+       $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnyesno.c
+$(O)wingem.o: ../win/gem/wingem.c $(HACK_H) $(INCL)/func_tab.h $(INCL)/dlb.h \
+               $(INCL)/patchlevel.h $(INCL)/wingem.h
+       $(cc) $(CFLAGS) -o$@ ../win/gem/wingem.c
+$(O)wingem1.o: ../win/gem/wingem1.c $(INCL)/gem_rsc.h $(INCL)/load_img.h \
+               $(INCL)/gr_rect.h $(INCL)/wintype.h $(INCL)/wingem.h
+       $(cc) $(CFLAGS) -o$@ ../win/gem/wingem1.c
+$(O)load_img.o: ../win/gem/load_img.c $(INCL)/load_img.h
+       $(cc) $(CFLAGS) -o$@ ../win/gem/load_img.c
+$(O)gr_rect.o: ../win/gem/gr_rect.c $(INCL)/gr_rect.h
+       $(cc) $(CFLAGS) -o$@ ../win/gem/gr_rect.c
+$(O)tile.o: tile.c $(HACK_H)
+$(O)qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) $(INCL)/func_tab.h \
+               $(INCL)/dlb.h $(INCL)/patchlevel.h $(INCL)/tile2x11.h \
+               $(INCL)/qt_win.h $(INCL)/qt_clust.h $(INCL)/qt_kde0.h \
+               $(INCL)/qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc
+       $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_win.cpp
+$(O)qt_clust.o: ../win/Qt/qt_clust.cpp $(INCL)/qt_clust.h
+       $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_clust.cpp
+$(O)qttableview.o: ../win/Qt/qttableview.cpp $(INCL)/qttableview.h
+       $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qttableview.cpp
+$(O)monstr.o: monstr.c $(CONFIG_H)
+$(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)/vis_tab.h
+$(O)allmain.o: allmain.c $(HACK_H)
+$(O)alloc.o: alloc.c $(CONFIG_H)
+$(O)apply.o: apply.c $(HACK_H) $(INCL)/edog.h
+$(O)artifact.o: artifact.c $(HACK_H) $(INCL)/artifact.h $(INCL)/artilist.h
+$(O)attrib.o: attrib.c $(HACK_H)
+$(O)ball.o: ball.c $(HACK_H)
+$(O)bones.o: bones.c $(HACK_H) $(INCL)/lev.h
+$(O)botl.o: botl.c $(HACK_H)
+$(O)cmd.o: cmd.c $(HACK_H) $(INCL)/func_tab.h
+$(O)dbridge.o: dbridge.c $(HACK_H)
+$(O)decl.o: decl.c $(HACK_H)
+$(O)detect.o: detect.c $(HACK_H) $(INCL)/artifact.h
+$(O)dig.o: dig.c $(HACK_H) $(INCL)/edog.h
+$(O)display.o: display.c $(HACK_H)
+$(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)/dlb.h
+$(O)do.o: do.c $(HACK_H) $(INCL)/lev.h
+$(O)do_name.o: do_name.c $(HACK_H)
+$(O)do_wear.o: do_wear.c $(HACK_H)
+$(O)dog.o: dog.c $(HACK_H) $(INCL)/edog.h
+$(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/edog.h
+$(O)dokick.o: dokick.c $(HACK_H) $(INCL)/eshk.h
+$(O)dothrow.o: dothrow.c $(HACK_H) $(INCL)/edog.h
+$(O)drawing.o: drawing.c $(HACK_H) $(INCL)/tcap.h
+$(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)/dgn_file.h $(INCL)/dlb.h
+$(O)eat.o: eat.c $(HACK_H)
+$(O)end.o: end.c $(HACK_H) $(INCL)/eshk.h $(INCL)/dlb.h
+$(O)engrave.o: engrave.c $(HACK_H) $(INCL)/lev.h
+$(O)exper.o: exper.c $(HACK_H)
+$(O)explode.o: explode.c $(HACK_H)
+$(O)extralev.o: extralev.c $(HACK_H)
+$(O)files.o: files.c $(HACK_H) $(INCL)/dlb.h
+$(O)fountain.o: fountain.c $(HACK_H)
+$(O)hack.o: hack.c $(HACK_H)
+$(O)hacklib.o: hacklib.c $(HACK_H)
+$(O)invent.o: invent.c $(HACK_H)
+$(O)light.o: light.c $(HACK_H) $(INCL)/lev.h
+$(O)lock.o: lock.c $(HACK_H)
+$(O)mail.o: mail.c $(HACK_H) $(INCL)/mail.h
+$(O)makemon.o: makemon.c $(HACK_H) $(INCL)/epri.h $(INCL)/emin.h \
+               $(INCL)/edog.h
+$(O)mapglyph.o: mapglyph.c $(HACK_H)
+$(O)mcastu.o: mcastu.c $(HACK_H)
+$(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)/artifact.h $(INCL)/edog.h
+$(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)/artifact.h $(INCL)/edog.h
+$(O)minion.o: minion.c $(HACK_H) $(INCL)/emin.h $(INCL)/epri.h
+$(O)mklev.o: mklev.c $(HACK_H)
+$(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)/sp_lev.h
+$(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)/sp_lev.h $(INCL)/lev.h
+$(O)mkobj.o: mkobj.c $(HACK_H)
+$(O)mkroom.o: mkroom.c $(HACK_H)
+$(O)mon.o: mon.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/edog.h
+$(O)mondata.o: mondata.c $(HACK_H) $(INCL)/eshk.h $(INCL)/epri.h
+$(O)monmove.o: monmove.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/artifact.h \
+               $(INCL)/epri.h
+$(O)monst.o: monst.c $(CONFIG_H) $(INCL)/permonst.h $(INCL)/align.h \
+               $(INCL)/monattk.h $(INCL)/monflag.h $(INCL)/monsym.h \
+               $(INCL)/dungeon.h $(INCL)/eshk.h $(INCL)/vault.h \
+               $(INCL)/epri.h $(INCL)/color.h
+$(O)mplayer.o: mplayer.c $(HACK_H)
+$(O)mthrowu.o: mthrowu.c $(HACK_H)
+$(O)muse.o: muse.c $(HACK_H) $(INCL)/edog.h
+$(O)music.o: music.c $(HACK_H) #interp.c
+$(O)o_init.o: o_init.c $(HACK_H) $(INCL)/lev.h
+$(O)objects.o: objects.c $(CONFIG_H) $(INCL)/obj.h $(INCL)/objclass.h \
+               $(INCL)/prop.h $(INCL)/skills.h $(INCL)/color.h
+$(O)objnam.o: objnam.c $(HACK_H)
+$(O)options.o: options.c $(CONFIG_H) $(INCL)/objclass.h $(INCL)/flag.h \
+               $(HACK_H) $(INCL)/tcap.h
+$(O)pager.o: pager.c $(HACK_H) $(INCL)/dlb.h
+$(O)pickup.o: pickup.c $(HACK_H)
+$(O)pline.o: pline.c $(HACK_H) $(INCL)/epri.h $(INCL)/edog.h
+$(O)polyself.o: polyself.c $(HACK_H)
+$(O)potion.o: potion.c $(HACK_H)
+$(O)pray.o: pray.c $(HACK_H) $(INCL)/epri.h
+$(O)priest.o: priest.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/eshk.h \
+               $(INCL)/epri.h $(INCL)/emin.h
+$(O)quest.o: quest.c $(HACK_H) $(INCL)/qtext.h
+$(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)/dlb.h $(INCL)/qtext.h
+$(O)read.o: read.c $(HACK_H)
+$(O)rect.o: rect.c $(HACK_H)
+$(O)region.o: region.c $(HACK_H) $(INCL)/lev.h
+$(O)restore.o: restore.c $(HACK_H) $(INCL)/lev.h $(INCL)/tcap.h
+$(O)rip.o: rip.c $(HACK_H)
+$(O)rnd.o: rnd.c $(HACK_H)
+$(O)role.o: role.c $(HACK_H)
+$(O)rumors.o: rumors.c $(HACK_H) $(INCL)/lev.h $(INCL)/dlb.h
+$(O)save.o: save.c $(HACK_H) $(INCL)/lev.h
+$(O)shk.o: shk.c $(HACK_H) $(INCL)/eshk.h
+$(O)shknam.o: shknam.c $(HACK_H) $(INCL)/eshk.h
+$(O)sit.o: sit.c $(HACK_H) $(INCL)/artifact.h
+$(O)sounds.o: sounds.c $(HACK_H) $(INCL)/edog.h
+$(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)/dlb.h $(INCL)/sp_lev.h
+$(O)spell.o: spell.c $(HACK_H)
+$(O)steal.o: steal.c $(HACK_H)
+$(O)steed.o: steed.c $(HACK_H)
+$(O)teleport.o: teleport.c $(HACK_H)
+$(O)timeout.o: timeout.c $(HACK_H) $(INCL)/lev.h
+$(O)topten.o: topten.c $(HACK_H) $(INCL)/dlb.h $(INCL)/patchlevel.h
+$(O)track.o: track.c $(HACK_H)
+$(O)trap.o: trap.c $(HACK_H)
+$(O)u_init.o: u_init.c $(HACK_H)
+$(O)uhitm.o: uhitm.c $(HACK_H)
+$(O)vault.o: vault.c $(HACK_H) $(INCL)/vault.h
+$(O)version.o: version.c $(HACK_H) $(INCL)/date.h $(INCL)/patchlevel.h
+$(O)vision.o: vision.c $(HACK_H) $(INCL)/vis_tab.h
+$(O)weapon.o: weapon.c $(HACK_H)
+$(O)were.o: were.c $(HACK_H)
+$(O)wield.o: wield.c $(HACK_H)
+$(O)windows.o: windows.c $(HACK_H) $(INCL)/wingem.h $(INCL)/winGnome.h
+$(O)wizard.o: wizard.c $(HACK_H) $(INCL)/qtext.h $(INCL)/epri.h
+$(O)worm.o: worm.c $(HACK_H) $(INCL)/lev.h
+$(O)worn.o: worn.c $(HACK_H)
+$(O)write.o: write.c $(HACK_H)
+$(O)zap.o: zap.c $(HACK_H)
+
+# end of file
diff --git a/sys/winnt/Makefile.msc b/sys/winnt/Makefile.msc
new file mode 100644 (file)
index 0000000..832b857
--- /dev/null
@@ -0,0 +1,1419 @@
+#       SCCS Id: @(#)Makefile.msc       3.4     $Date: 2003/11/16 04:50:58 $
+#       Copyright (c) NetHack PC Development Team 1993-2003
+#
+#       NetHack 3.4.x Makefile for MS Visual C++ V6.x and above and MS NMAKE
+#  
+#       Win32 Compilers Tested:
+#                              - Microsoft 32 bit Visual C++ V4.x
+#                              - Microsoft 32 bit Visual C++ V6.0 SP3, SP4
+#
+#   This is used for building two versions of NetHack:
+#   A tty port utilizing the Win32 Console I/O subsystem, Console
+#       NetHack;
+#   A Win32 native port built on the Windows API, Graphical NetHack or
+#       NetHackW.
+#
+#       In addition to your C compiler,
+#
+#       if you want to change           you will need a
+#       files with suffix               workalike for
+#              .y                           yacc   (such as bison)
+#              .l                           lex    (such as flex)
+#
+#
+#       If you have any questions read the sys/winnt/Install.nt file included 
+#       with the distribution.
+#==============================================================================
+# Do not delete the following 3 lines.
+#
+TARGETOS=BOTH
+APPVER=4.0
+!include <win32.mak>
+
+# Graphical interface
+# Set to Y for a graphical version
+
+#GRAPHICAL = Y
+
+#  Set the gamedir according to your preference.  
+#  If not present prior to compilation it gets created.
+
+!IF "$(GRAPHICAL)" == "Y"
+GAME    = NetHackW                # Game Name
+!ELSE
+GAME    = NetHack                 # Game Name
+!ENDIF
+
+GAMEDIR = ..\binary               # Game directory
+
+#
+#  Source directories.    Makedefs hardcodes these, don't change them.
+#
+
+INCL  = ..\include   # NetHack include files
+DAT   = ..\dat       # NetHack data files
+DOC   = ..\doc       # NetHack documentation files
+UTIL  = ..\util      # Utility source
+SRC   = ..\src       # Main source
+SSYS  = ..\sys\share # Shared system files
+NTSYS = ..\sys\winnt # NT Win32 specific files
+TTY   = ..\win\tty   # window port files (tty)
+WIN32 = ..\win\win32 # window port files (Win32)
+WSHR  = ..\win\share # Tile support files 
+
+#
+#  Object directory.
+#
+
+OBJ     = o
+
+
+#
+#==========================================
+# Exe File Info.
+#==========================================
+# Yacc/Lex ... if you got 'em.
+#
+# If you have yacc and lex programs (or work-alike such as bison 
+# and flex), comment out the upper two macros and uncomment 
+# the lower two.
+#
+
+DO_YACC = YACC_MSG
+DO_LEX  = LEX_MSG
+#DO_YACC  = YACC_ACT
+#DO_LEX   = LEX_ACT
+
+# - Specify your yacc and lex programs (or work-alikes) here.
+
+#YACC  = bison -y
+YACC   = byacc
+#YACC  = yacc
+
+#LEX   = lex
+LEX    = flex
+
+#
+# - Specify your flex skeleton file (if needed).
+#
+
+FLEXSKEL =
+#FLEXSKEL = -S../tools/flex.ske
+
+YTABC   = y_tab.c
+YTABH   = y_tab.h
+LEXYYC  = lexyy.c
+
+#
+# Optional high-quality BSD random number generation routines
+# (see pcconf.h). Set to nothing if not used.
+#
+
+RANDOM = $(OBJ)\random.o
+#RANDOM        =
+
+#
+#  Leave the next two lines uncommented _ONLY_ if you do NOT want any
+#  debug capability in the object files, or in the NetHack executable.
+#  Comment them if you want debug capability.
+
+#cdebug =
+#linkdebug =
+
+#
+# Compiler and Linker flags
+#
+
+PRECOMPHEAD = N                        # set to Y if you want to use precomp. headers
+
+#===============================================
+#======= End of Modification Section ===========
+#===============================================
+################################################
+#                                              #
+# Nothing below here should have to be changed.#
+#                                              #
+################################################
+
+!IF "$(GRAPHICAL)" == "Y"
+WINPORT        = $(O)tile.o $(O)mhaskyn.o $(O)mhdlg.o \
+       $(O)mhfont.o $(O)mhinput.o $(O)mhmain.o $(O)mhmap.o \
+       $(O)mhmenu.o $(O)mhmsgwnd.o $(O)mhrip.o $(O)mhsplash.o \
+       $(O)mhstatus.o $(O)mhtext.o $(O)mswproc.o $(O)winhack.o
+WINPHDR        = $(WIN32)\mhaskyn.h $(WIN32)\mhdlg.h $(WIN32)\mhfont.h \
+       $(WIN32)\mhinput.h $(WIN32)\mhmain.h $(WIN32)\mhmap.h $(WIN32)\mhmenu.h \
+       $(WIN32)\mhmsg.h $(WIN32)\mhmsgwnd.h $(WIN32)\mhrip.h $(WIN32)\mhstatus.h \
+       $(WIN32)\mhtext.h $(WIN32)\resource.h $(WIN32)\winMS.h
+WINDLLS =
+WINPFLAG= -DTILES -DMSWIN_GRAPHICS
+NHRES  = $(O)winhack.res
+WINPINC        = -I$(WIN32)
+!ELSE
+WINPORT        = $(O)nttty.o    
+WINPHDR        =
+WINDLLS        = $(GAMEDIR)\nhdefkey.dll $(GAMEDIR)\nh340key.dll $(GAMEDIR)\nhraykey.dll
+WINPFLAG= -DWIN32CON
+NHRES  = $(O)console.res
+WINPINC        =
+!ENDIF
+
+TILEUTIL16  = $(UTIL)\tile2bmp.exe
+TILEBMP16   = $(SRC)\tiles.bmp
+
+TILEUTIL32  = $(UTIL)\til2bm32.exe
+TILEBMP32   = $(SRC)\tiles32.bmp
+
+SOUND = $(OBJ)\ntsound.o
+
+#SOUND =
+
+# To store all the level files,
+# help files, etc. in a single library file.
+# USE_DLB = Y is left uncommented
+
+USE_DLB = Y
+
+! IF ("$(USE_DLB)"=="Y")
+DLBFLG = -DDLB
+! ELSE
+DLBFLG =
+! ENDIF
+
+#==========================================
+# Setting up the compiler and linker
+# macros. All builds include the base ones.
+#==========================================
+
+CFLAGSBASE  = -c $(cflags) $(cvarsmt) -I$(INCL) -nologo $(cdebug) $(WINPINC)
+LFLAGSBASEC = $(linkdebug) /NODEFAULTLIB /INCREMENTAL:NO /RELEASE /NOLOGO -subsystem:console,4.0 $(conlibsmt)
+LFLAGSBASEG = $(linkdebug) $(guiflags) $(guilibsmt) comctl32.lib
+
+#==========================================
+# Util builds
+#==========================================
+
+CFLAGSU = $(CFLAGSBASE) $(WINPFLAG)
+LFLAGSU        = $(LFLAGSBASEC)
+
+#==========================================
+# - Game build
+#==========================================
+LFLAGSBASE = $(linkdebug) /NODEFAULTLIB /INCREMENTAL:NO /RELEASE /NOLOGO -subsystem:console,4.0 $(conlibsmt)
+CFLAGS  = $(CFLAGSBASE) $(WINPFLAG) $(DLBFLG)
+NHLFLAGS1 = /NODEFAULTLIB /INCREMENTAL:NO /PDB:"$(GAME).PDB" /RELEASE /NOLOGO
+NHLFLAGS2 = /MAP:"$(GAME).MAP" /MACHINE:$(CPU) -IGNORE:505 
+!IF ("$(GRAPHICAL)"=="Y")
+LFLAGS = $(LFLAGSBASEG) $(NHLFLAGS1) $(NHLFLAGS2)
+!ELSE
+LFLAGS = $(LFLAGSBASEC) $(NHLFLAGS1) $(NHLFLAGS2)
+!ENDIF
+
+GAMEFILE = $(GAMEDIR)\$(GAME).exe # whole thing
+
+! IF ("$(USE_DLB)"=="Y")
+DLB = nhdat
+! ELSE
+DLB =
+! ENDIF
+
+#==========================================
+#================ RULES ==================
+#==========================================
+
+.SUFFIXES: .exe .o .til .uu .c .y .l
+
+#==========================================
+# Rules for files in src
+#==========================================
+
+.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -Fo$@ $<
+
+{$(SRC)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS)   -Fo$@  $<
+
+#==========================================
+# Rules for files in sys\share
+#==========================================
+
+{$(SSYS)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS)  -Fo$@  $<
+
+#==========================================
+# Rules for files in sys\winnt
+#==========================================
+
+{$(NTSYS)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS)  -Fo$@  $<
+
+{$(NTSYS)}.h{$(INCL)}.h:
+       @copy $< $@
+
+#==========================================
+# Rules for files in util
+#==========================================
+
+{$(UTIL)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGSU) -Fo$@ $<
+
+#==========================================
+# Rules for files in win\share
+#==========================================
+
+{$(WSHR)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS)  -Fo$@ $<
+
+{$(WSHR)}.h{$(INCL)}.h:
+       @copy $< $@
+
+#{$(WSHR)}.txt{$(DAT)}.txt:
+#      @copy $< $@
+
+#==========================================
+# Rules for files in win\tty
+#==========================================
+
+{$(TTY)}.c{$(OBJ)}.o:
+       @$(CC) $(CFLAGS)  -Fo$@  $<
+
+
+#==========================================
+# Rules for files in win\win32
+#==========================================
+
+{$(WIN32)}.c{$(OBJ)}.o:
+       @$(cc) $(CFLAGS)  -Fo$@  $<
+
+#==========================================
+#================ MACROS ==================
+#==========================================
+# This section creates shorthand macros for many objects
+# referenced later on in the Makefile.
+#
+
+DEFFILE = $(NTSYS)\$(GAME).def
+
+#
+# Shorten up the location for some files
+#
+
+O  = $(OBJ)^\
+
+U  = $(UTIL)^\
+
+#
+# Utility Objects.
+#
+
+MAKESRC        = $(U)makedefs.c
+
+SPLEVSRC       = $(U)lev_yacc.c        $(U)lev_$(LEX).c $(U)lev_main.c  $(U)panic.c
+
+DGNCOMPSRC     = $(U)dgn_yacc.c        $(U)dgn_$(LEX).c $(U)dgn_main.c
+
+MAKEOBJS       = $(O)makedefs.o $(O)monst.o $(O)objects.o
+
+SPLEVOBJS      = $(O)lev_yacc.o        $(O)lev_$(LEX).o $(O)lev_main.o \
+                $(O)alloc.o    $(O)decl.o      $(O)drawing.o \
+                $(O)monst.o    $(O)objects.o   $(O)panic.o
+
+DGNCOMPOBJS    = $(O)dgn_yacc.o        $(O)dgn_$(LEX).o $(O)dgn_main.o \
+                $(O)alloc.o    $(O)panic.o
+
+RECOVOBJS      = $(O)recover.o
+
+TILEFILES      = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt
+
+#
+# These are not invoked during a normal game build in 3.4
+#
+TEXT_IO        = $(O)tiletext.o        $(O)tiletxt.o   $(O)drawing.o \
+                $(O)decl.o     $(O)monst.o     $(O)objects.o
+
+TEXT_IO32      = $(O)tilete32.o $(O)tiletx32.o $(O)drawing.o \
+                $(O)decl.o     $(O)monst.o     $(O)objects.o
+
+GIFREADERS     = $(O)gifread.o $(O)alloc.o $(O)panic.o
+GIFREADERS32   = $(O)gifrd32.o $(O)alloc.o $(O)panic.o
+
+PPMWRITERS     = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o
+
+#
+#  Object files for the game itself.
+#
+
+VOBJ01 = $(O)allmain.o  $(O)alloc.o    $(O)apply.o    $(O)artifact.o
+VOBJ02 = $(O)attrib.o   $(O)ball.o     $(O)bones.o    $(O)botl.o    
+VOBJ03 = $(O)cmd.o      $(O)dbridge.o  $(O)decl.o     $(O)detect.o  
+VOBJ04 = $(O)dig.o      $(O)display.o  $(O)do.o       $(O)do_name.o 
+VOBJ05 = $(O)do_wear.o  $(O)dog.o      $(O)dogmove.o  $(O)dokick.o  
+VOBJ06 = $(O)dothrow.o  $(O)drawing.o  $(O)dungeon.o  $(O)eat.o     
+VOBJ07 = $(O)end.o      $(O)engrave.o  $(O)exper.o    $(O)explode.o 
+VOBJ08 = $(O)extralev.o $(O)files.o    $(O)fountain.o $(O)hack.o    
+VOBJ09 = $(O)hacklib.o  $(O)invent.o   $(O)light.o    $(O)lock.o    
+VOBJ10 = $(O)mail.o     $(O)pcmain.o   $(O)makemon.o  $(O)mapglyph.o $(O)mcastu.o  
+VOBJ11 = $(O)mhitm.o    $(O)mhitu.o    $(O)minion.o   $(O)mklev.o   
+VOBJ12 = $(O)mkmap.o    $(O)mkmaze.o   $(O)mkobj.o    $(O)mkroom.o  
+VOBJ13 = $(O)mon.o      $(O)mondata.o  $(O)monmove.o  $(O)monst.o   
+VOBJ14 = $(O)monstr.o   $(O)mplayer.o  $(O)mthrowu.o  $(O)muse.o    
+VOBJ15 = $(O)music.o    $(O)o_init.o   $(O)objects.o  $(O)objnam.o  
+VOBJ16 = $(O)options.o  $(O)pager.o    $(O)pickup.o   $(O)pline.o   
+VOBJ17 = $(O)polyself.o $(O)potion.o   $(O)pray.o     $(O)priest.o  
+VOBJ18 = $(O)quest.o    $(O)questpgr.o $(RANDOM)      $(O)read.o    
+VOBJ19 = $(O)rect.o     $(O)region.o   $(O)restore.o  $(O)rip.o     
+VOBJ20 = $(O)rnd.o      $(O)role.o     $(O)rumors.o   $(O)save.o    
+VOBJ21 = $(O)shk.o      $(O)shknam.o   $(O)sit.o      $(O)sounds.o  
+VOBJ22 = $(O)sp_lev.o   $(O)spell.o    $(O)steal.o    $(O)steed.o   
+VOBJ23 = $(O)teleport.o $(O)timeout.o  $(O)topten.o   $(O)track.o   
+VOBJ24 = $(O)trap.o     $(O)u_init.o   $(O)uhitm.o    $(O)vault.o   
+VOBJ25 = $(O)vis_tab.o  $(O)vision.o   $(O)weapon.o   $(O)were.o    
+VOBJ26 = $(O)wield.o    $(O)windows.o  $(O)wizard.o   $(O)worm.o    
+VOBJ27 = $(O)worn.o     $(O)write.o    $(O)zap.o     
+
+DLBOBJ = $(O)dlb.o
+
+TTYOBJ = $(O)topl.o     $(O)getline.o  $(O)wintty.o
+
+SOBJ   = $(O)winnt.o    $(O)pcsys.o      $(O)pcunix.o  \
+          $(SOUND)     $(O)mapimail.o $(O)nhlan.o
+
+OBJS   = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \
+         $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \
+         $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \
+         $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \
+         $(VOBJ21) $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) \
+         $(VOBJ26) $(VOBJ27)
+
+WINPOBJ = $(WINPORT)
+
+VVOBJ  = $(O)version.o
+
+ALLOBJ  = $(WINPOBJ) $(SOBJ) $(DLBOBJ)  $(TTYOBJ) $(WOBJ) $(OBJS) $(VVOBJ)
+
+!IF "$(GRAPHICAL)" == "Y"
+OPTIONS_FILE = $(DAT)\guioptions
+!ELSE
+OPTIONS_FILE = $(DAT)\ttyoptions
+!ENDIF
+#==========================================
+# Header file macros
+#==========================================
+
+CONFIG_H = $(INCL)\config.h $(INCL)\config1.h $(INCL)\tradstdc.h \
+               $(INCL)\global.h $(INCL)\coord.h $(INCL)\vmsconf.h \
+               $(INCL)\system.h $(INCL)\unixconf.h $(INCL)\os2conf.h \
+               $(INCL)\micro.h $(INCL)\pcconf.h $(INCL)\tosconf.h \
+               $(INCL)\amiconf.h $(INCL)\macconf.h $(INCL)\beconf.h \
+               $(INCL)\ntconf.h $(INCL)\nhlan.h
+
+HACK_H = $(INCL)\hack.h $(CONFIG_H) $(INCL)\align.h \
+               $(INCL)\dungeon.h $(INCL)\monsym.h $(INCL)\mkroom.h \
+               $(INCL)\objclass.h $(INCL)\youprop.h $(INCL)\prop.h \
+               $(INCL)\permonst.h $(INCL)\monattk.h \
+               $(INCL)\monflag.h $(INCL)\mondata.h $(INCL)\pm.h \
+               $(INCL)\wintype.h $(INCL)\decl.h $(INCL)\quest.h \
+               $(INCL)\spell.h $(INCL)\color.h $(INCL)\obj.h \
+               $(INCL)\you.h $(INCL)\attrib.h $(INCL)\monst.h \
+               $(INCL)\skills.h $(INCL)\onames.h $(INCL)\timeout.h \
+               $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \
+               $(INCL)\vision.h $(INCL)\display.h $(INCL)\engrave.h \
+               $(INCL)\rect.h $(INCL)\region.h $(INCL)\winprocs.h \
+               $(INCL)\wintty.h $(INCL)\trampoli.h
+
+LEV_H       = $(INCL)\lev.h
+DGN_FILE_H  = $(INCL)\dgn_file.h
+LEV_COMP_H  = $(INCL)\lev_comp.h
+SP_LEV_H    = $(INCL)\sp_lev.h
+TILE_H      = ..\win\share\tile.h
+
+#==========================================
+# Miscellaneous
+#==========================================
+
+DATABASE = $(DAT)\data.base
+
+#
+#  The name of the game.
+#
+
+GAMEFILE = $(GAMEDIR)\$(GAME).exe
+
+#==========================================
+#=============== TARGETS ==================
+#==========================================
+
+#
+#  The default make target (so just typing 'nmake' is useful).
+#
+default : $(GAMEFILE)
+
+#
+#  The main target.
+#
+
+$(GAME): $(O)obj.tag $(O)utility.tag envchk $(GAMEFILE)
+       @echo $(GAME) is up to date.
+
+#
+#  Everything
+#
+
+all :  install
+
+install: envchk $(GAME) $(O)install.tag
+        @echo Done.
+
+$(O)install.tag:       $(DAT)\data     $(DAT)\rumors    $(DAT)\dungeon \
+               $(DAT)\oracles  $(DAT)\quest.dat $(O)sp_lev.tag $(DLB)
+! IF ("$(USE_DLB)"=="Y")
+       copy nhdat                $(GAMEDIR)
+       copy $(DAT)\license       $(GAMEDIR)
+       copy $(DAT)\opthelp       $(GAMEDIR)
+! ELSE
+       copy $(DAT)\*.            $(GAMEDIR)
+       copy $(DAT)\*.dat         $(GAMEDIR)
+       copy $(DAT)\*.lev         $(GAMEDIR)
+       if exist $(GAMEDIR)\makefile del $(GAMEDIR)\makefile
+! ENDIF
+       if exist $(DOC)\guidebook.txt copy $(DOC)\guidebook.txt $(GAMEDIR)\Guidebook.txt
+       if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt $(GAMEDIR)\NetHack.txt
+       @if exist $(SRC)\$(GAME).PDB copy $(SRC)\$(GAME).pdb $(GAMEDIR)\$(GAME).pdb
+       @if exist $(GAMEDIR)\$(GAME).PDB echo NOTE: You may want to remove $(GAMEDIR)\$(GAME).pdb to conserve space
+       -copy $(NTSYS)\defaults.nh   $(GAMEDIR)\defaults.nh
+       echo install done > $@
+
+#      copy $(NTSYS)\winnt.hlp    $(GAMEDIR)
+
+recover: $(U)recover.exe
+       if exist $(U)recover.exe copy $(U)recover.exe  $(GAMEDIR)
+       if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR)\recover.txt
+
+$(O)sp_lev.tag: $(O)utility.tag $(DAT)\bigroom.des  $(DAT)\castle.des \
+       $(DAT)\endgame.des $(DAT)\gehennom.des $(DAT)\knox.des   \
+       $(DAT)\medusa.des  $(DAT)\oracle.des   $(DAT)\tower.des  \
+       $(DAT)\yendor.des  $(DAT)\arch.des     $(DAT)\barb.des   \
+       $(DAT)\caveman.des $(DAT)\healer.des   $(DAT)\knight.des \
+       $(DAT)\monk.des    $(DAT)\priest.des   $(DAT)\ranger.des \
+       $(DAT)\rogue.des   $(DAT)\samurai.des  $(DAT)\sokoban.des \
+       $(DAT)\tourist.des $(DAT)\valkyrie.des $(DAT)\wizard.des
+       cd $(DAT)
+       $(U)lev_comp bigroom.des
+       $(U)lev_comp castle.des
+       $(U)lev_comp endgame.des
+       $(U)lev_comp gehennom.des
+       $(U)lev_comp knox.des
+       $(U)lev_comp mines.des
+       $(U)lev_comp medusa.des
+       $(U)lev_comp oracle.des
+       $(U)lev_comp sokoban.des
+       $(U)lev_comp tower.des
+       $(U)lev_comp yendor.des
+       $(U)lev_comp arch.des
+       $(U)lev_comp barb.des
+       $(U)lev_comp caveman.des
+       $(U)lev_comp healer.des
+       $(U)lev_comp knight.des
+       $(U)lev_comp monk.des
+       $(U)lev_comp priest.des
+       $(U)lev_comp ranger.des
+       $(U)lev_comp rogue.des
+       $(U)lev_comp samurai.des
+       $(U)lev_comp tourist.des
+       $(U)lev_comp valkyrie.des
+       $(U)lev_comp wizard.des
+       cd $(SRC)
+       echo sp_levs done > $(O)sp_lev.tag
+
+$(O)utility.tag: $(INCL)\date.h $(INCL)\onames.h $(INCL)\pm.h \
+               $(SRC)\monstr.c         $(SRC)\vis_tab.c  \
+               $(U)lev_comp.exe        $(INCL)\vis_tab.h \
+               $(U)dgn_comp.exe
+             @echo utilities made >$@
+            @echo utilities made.
+
+tileutil: $(U)gif2txt.exe $(U)gif2tx32.exe $(U)txt2ppm.exe
+       @echo Optional tile development utilities are up to date.
+
+!IF "$(GRAPHICAL)"=="Y"
+$(NHRES): $(TILEBMP16) $(WIN32)\winhack.rc $(WIN32)\mnsel.bmp \
+       $(WIN32)\mnselcnt.bmp $(WIN32)\mnunsel.bmp \
+       $(WIN32)\petmark.bmp $(WIN32)\NetHack.ico $(WIN32)\rip.bmp \
+       $(WIN32)\splash.bmp
+       @$(rc) -r -fo$@ -i$(WIN32) -dNDEBUG $(WIN32)\winhack.rc
+!ELSE
+$(NHRES): $(NTSYS)\console.rc $(NTSYS)\NetHack.ico
+       @$(rc) -r -fo$@ -i$(NTSYS) -dNDEBUG $(NTSYS)\console.rc
+!ENDIF
+
+#==========================================
+#  The main target.
+#==========================================
+
+#  The section for linking the NetHack image looks a little strange at 
+#  first, especially if you are used to UNIX makes, or NDMAKE.  It is 
+#  Microsoft nmake specific, and it gets around the problem of the 
+#  link command line being too long for the linker.  An "in-line" linker 
+#  response file is generated temporarily.
+#
+#  It takes advantage of the following features of nmake:
+#
+#  Inline files : 
+#                      Specifying the "<<" means to start an inline file.
+#                      Another "<<" at the start of a line closes the 
+#                      inline file.
+#
+#  Substitution within Macros:
+#                       $(mymacro:string1=string2) replaces every
+#                       occurrence of string1 with string2 in the 
+#                       macro mymacro.  Special ascii key codes may be 
+#                       used in the substitution text by preceding it 
+#                       with ^ as we have done below.  Every occurence
+#                       of a <tab> in $(ALLOBJ) is replaced by 
+#                       <+><return><tab>.
+#
+#  DO NOT INDENT THE << below!
+#
+
+$(GAMEFILE) : $(ALLOBJ) $(NHRES) $(O)gamedir.tag $(WINDLLS)
+       @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
+       @echo Linking....
+       $(link) $(LFLAGS) user32.lib winmm.lib -out:$@ @<<$(GAME).lnk
+               $(ALLOBJ:^      =^
+               ) $(NHRES)
+<<
+       @if exist $(O)install.tag del $(O)install.tag
+       @if exist $(GAMEDIR)\$(GAME).bak del $(GAMEDIR)\$(GAME).bak
+
+$(O)gamedir.tag:
+       @if not exist $(GAMEDIR)\*.* echo creating directory $(GAMEDIR)
+       @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
+       @echo directory created > $@
+
+$(O)nhdefkey.def:
+       @echo EXPORTS >$@
+       @echo    ProcessKeystroke >>$@
+       @echo    NHkbhit >>$@
+       @echo    CheckInput >>$@
+       @echo    SourceWhere >>$@
+       @echo    SourceAuthor >>$@
+       @echo    KeyHandlerName >>$@
+
+$(GAMEDIR)\nhdefkey.dll : $(O)$(@B).o $(O)gamedir.tag $(O)$(@B).def
+       @echo Linking $@
+       @$(link) -debug:full -debugtype:cv /RELEASE /NOLOGO /DLL user32.lib \
+               /PDB:"$(@B).PDB" /MAP:"$(@B).map" /DEF:$(O)$(@B).def \
+               /IMPLIB:$(O)$(@B).lib -out:$@ $(O)$(@B).o
+
+$(O)nh340key.def:
+       @echo EXPORTS >$@
+       @echo    ProcessKeystroke >>$@
+       @echo    NHkbhit >>$@
+       @echo    CheckInput >>$@
+       @echo    SourceWhere >>$@
+       @echo    SourceAuthor >>$@
+       @echo    KeyHandlerName >>$@
+
+$(GAMEDIR)\nh340key.dll : $(O)$(@B).o $(O)gamedir.tag $(O)$(@B).def
+       @echo Linking $@
+       @$(link) -debug:full -debugtype:cv /RELEASE /NOLOGO /DLL user32.lib \
+               /PDB:"$(@B).PDB" /MAP:"$(@B).map" /DEF:$(O)$(@B).def \
+               /IMPLIB:$(O)$(@B).lib -out:$@ $(O)$(@B).o
+
+$(O)nhraykey.def:
+       @echo EXPORTS >$@
+       @echo    ProcessKeystroke >>$@
+       @echo    NHkbhit >>$@
+       @echo    CheckInput >>$@
+       @echo    SourceWhere >>$@
+       @echo    SourceAuthor >>$@
+       @echo    KeyHandlerName >>$@
+
+$(GAMEDIR)\nhraykey.dll : $(O)$(@B).o $(O)gamedir.tag $(O)$(@B).def
+       @echo Linking $@
+       @$(link) -debug:full -debugtype:cv /RELEASE /NOLOGO /DLL user32.lib \
+               /PDB:"$(@B).PDB" /MAP:"$(@B).map" /DEF:$(O)$(@B).def \
+               /IMPLIB:$(O)$(@B).lib -out:$@ $(O)$(@B).o
+
+#
+#  Secondary Targets.
+#
+    
+#==========================================
+# Makedefs Stuff
+#==========================================
+
+$(U)makedefs.exe:      $(MAKEOBJS)
+       @$(link) $(LFLAGSU) -out:$@ $(MAKEOBJS)
+
+$(O)makedefs.o: $(CONFIG_H)    $(INCL)\monattk.h $(INCL)\monflag.h   $(INCL)\objclass.h \
+                $(INCL)\monsym.h    $(INCL)\qtext.h    $(INCL)\patchlevel.h \
+                $(U)makedefs.c
+       @if not exist $(OBJ)\*.* echo creating directory $(OBJ)
+       @if not exist $(OBJ)\*.* mkdir $(OBJ)
+       @$(CC) $(CFLAGSU) -Fo$@ $(U)makedefs.c
+
+#
+#  date.h should be remade every time any of the source or include
+#  files is modified.
+#
+
+$(INCL)\date.h $(OPTIONS_FILE) : $(U)makedefs.exe
+       $(U)makedefs -v
+
+$(INCL)\onames.h : $(U)makedefs.exe
+       $(U)makedefs -o
+
+$(INCL)\pm.h : $(U)makedefs.exe
+       $(U)makedefs -p
+
+#$(INCL)\trap.h : $(U)makedefs.exe
+#      $(U)makedefs -t
+
+$(SRC)\monstr.c: $(U)makedefs.exe
+       $(U)makedefs -m
+
+$(INCL)\vis_tab.h: $(U)makedefs.exe
+       $(U)makedefs -z
+
+$(SRC)\vis_tab.c: $(U)makedefs.exe
+       $(U)makedefs -z
+
+#==========================================
+# uudecode utility and uuencoded targets
+#==========================================
+
+$(U)uudecode.exe: $(O)uudecode.o
+       @$(link) $(LFLAGSU) -out:$@ $(O)uudecode.o
+
+$(O)uudecode.o: $(SSYS)\uudecode.c
+
+$(NTSYS)\NetHack.ico : $(U)uudecode.exe $(NTSYS)\nhico.uu 
+       chdir $(NTSYS)
+       ..\..\util\uudecode.exe nhico.uu
+       chdir ..\..\src
+
+$(WIN32)\NetHack.ico : $(U)uudecode.exe $(NTSYS)\nhico.uu 
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu
+       chdir ..\..\src
+
+$(WIN32)\mnsel.bmp: $(U)uudecode.exe $(WIN32)\mnsel.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe mnsel.uu
+       chdir ..\..\src
+
+$(WIN32)\mnselcnt.bmp: $(U)uudecode.exe $(WIN32)\mnselcnt.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe mnselcnt.uu
+       chdir ..\..\src
+
+$(WIN32)\mnunsel.bmp: $(U)uudecode.exe $(WIN32)\mnunsel.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe mnunsel.uu
+       chdir ..\..\src
+
+$(WIN32)\petmark.bmp: $(U)uudecode.exe $(WIN32)\petmark.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe petmark.uu
+       chdir ..\..\src
+
+$(WIN32)\rip.bmp: $(U)uudecode.exe $(WIN32)\rip.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe rip.uu
+       chdir ..\..\src
+
+$(WIN32)\splash.bmp: $(U)uudecode.exe $(WIN32)\splash.uu
+       chdir $(WIN32)
+       ..\..\util\uudecode.exe splash.uu
+       chdir ..\..\src
+
+#==========================================
+# Level Compiler Stuff
+#==========================================
+
+LEVCFLAGS=-c -nologo -DWINVER=0x0400 -DWIN32 -D_WIN32 \
+          -D_MT -MT -I..\include -nologo -Z7 -Od -DDLB
+
+$(U)lev_comp.exe: $(SPLEVOBJS)
+       @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(SPLEVOBJS:^   =^
+               )
+<<
+
+$(O)lev_yacc.o: $(HACK_H)   $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c
+       @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_yacc.c
+
+$(O)lev_$(LEX).o: $(HACK_H)   $(INCL)\lev_comp.h $(SP_LEV_H) \
+               $(U)lev_$(LEX).c
+       @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_$(LEX).c
+
+$(O)lev_main.o:        $(U)lev_main.c $(HACK_H)   $(SP_LEV_H)
+       @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_main.c
+
+
+$(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y
+!      IF "$(DO_YACC)"=="YACC_ACT"
+          chdir $(UTIL)
+          $(YACC) -d lev_comp.y
+          copy $(YTABC) lev_yacc.c
+          copy $(YTABH) $(INCL)\lev_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)lev_comp.y has changed.
+          @echo To update $(U)lev_yacc.c and $(INCL)\lev_comp.h run $(YACC).
+          @echo ---
+          @echo For now, we will copy the prebuilt lev_yacc.c and 
+          @echo lev_comp.h from $(SSYS) into $(UTIL) and use them.
+          @copy $(SSYS)\lev_yacc.c $(U)lev_yacc.c >nul
+          @copy $(SSYS)\lev_comp.h $(INCL)\lev_comp.h >nul
+          @echo /**/ >>$(U)lev_yacc.c
+          @echo /**/ >>$(INCL)\lev_comp.h
+!      ENDIF
+
+$(U)lev_$(LEX).c: $(U)lev_comp.l
+!      IF "$(DO_LEX)"=="LEX_ACT"
+          chdir $(UTIL)
+          $(LEX) $(FLEXSKEL) lev_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)lev_comp.l has changed. To update $@ run $(LEX).
+          @echo ---
+          @echo For now, we will copy the prebuilt lev_lex.c 
+          @echo from $(SSYS) into $(UTIL) and use it.
+          @copy $(SSYS)\lev_lex.c $@ >nul
+          @echo /**/ >>$@
+!      ENDIF
+
+#==========================================
+# Dungeon Compiler Stuff
+#==========================================
+
+$(U)dgn_comp.exe: $(DGNCOMPOBJS)
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(DGNCOMPOBJS:^ =^
+               )
+<<
+
+$(O)dgn_yacc.o:        $(HACK_H)   $(DGN_FILE_H) $(INCL)\dgn_comp.h $(U)dgn_yacc.c
+       @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_yacc.c
+
+$(O)dgn_$(LEX).o: $(HACK_H)   $(DGN_FILE_H)  $(INCL)\dgn_comp.h \
+       $(U)dgn_$(LEX).c
+       @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_$(LEX).c
+
+$(O)dgn_main.o:        $(HACK_H) $(U)dgn_main.c
+       @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_main.c
+
+$(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y
+!      IF "$(DO_YACC)"=="YACC_ACT"
+          chdir $(UTIL)
+          $(YACC) -d dgn_comp.y
+          copy $(YTABC) dgn_yacc.c
+          copy $(YTABH) $(INCL)\dgn_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)dgn_comp.y has changed. To update dgn_yacc.c and 
+          @echo $(INCL)\dgn_comp.h run $(YACC).
+          @echo ---
+          @echo For now, we will copy the prebuilt $(U)dgn_yacc.c and 
+          @echo dgn_comp.h from $(SSYS) into $(UTIL) and use them.
+          @copy $(SSYS)\dgn_yacc.c $(U)dgn_yacc.c >nul
+          @copy $(SSYS)\dgn_comp.h $(INCL)\dgn_comp.h >nul
+          @echo /**/ >>$(U)dgn_yacc.c
+          @echo /**/ >>$(INCL)\dgn_comp.h
+!      ENDIF
+
+$(U)dgn_$(LEX).c: $(U)dgn_comp.l
+!      IF "$(DO_LEX)"=="LEX_ACT"
+          chdir $(UTIL)
+          $(LEX) $(FLEXSKEL)  dgn_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+          chdir $(SRC)
+!      ELSE
+          @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX).
+          @echo ---
+          @echo For now, we will copy the prebuilt dgn_lex.c 
+          @echo from $(SSYS) into $(UTIL) and use it.
+          @copy $(SSYS)\dgn_lex.c $@ >nul
+          @echo /**/ >>$@
+!      ENDIF
+
+#==========================================
+# Create directory for holding object files
+#==========================================
+
+$(O)obj.tag:
+       @if not exist $(OBJ)\*.* echo creating directory $(OBJ)
+       @if not exist $(OBJ)\*.* mkdir $(OBJ)
+       @echo directory created >$@
+
+#==========================================
+# Notify of any CL environment variables
+# in effect since they change the compiler
+# options.
+#==========================================
+
+envchk:
+!      IF "$(CL)"!=""
+          @echo Warning, the CL Environment variable is defined:
+          @echo CL=$(CL)
+!      ENDIF
+!   IF "$(GRAPHICAL)"=="Y"
+          @echo ----
+          @echo NOTE: This build will include tile support.
+          @echo ----
+!      ENDIF
+
+#==========================================
+#=========== SECONDARY TARGETS ============
+#==========================================
+
+#===========================================
+# Header files NOT distributed in ..\include
+#===========================================
+
+$(INCL)\win32api.h: $(NTSYS)\win32api.h
+       copy $(NTSYS)\win32api.h $@
+
+
+#==========================================
+# DLB utility and nhdat file creation
+#==========================================
+
+$(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(O)dlb_main.o
+               $(O)dlb.o
+               $(O)alloc.o
+               $(O)panic.o
+<<
+
+$(O)dlb.o:     $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)\dlb.h
+       @$(CC) $(CFLAGS) /Fo$@ $(SRC)\dlb.c
+       
+$(O)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h
+       @$(CC) $(CFLAGS) /Fo$@ $(UTIL)\dlb_main.c
+
+$(DAT)\porthelp: $(NTSYS)\porthelp
+       @copy $(NTSYS)\porthelp $@ >nul
+
+nhdat: $(U)dlb_main.exe $(DAT)\data $(DAT)\oracles $(OPTIONS_FILE) \
+       $(DAT)\quest.dat $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp \
+       $(DAT)\history $(DAT)\opthelp $(DAT)\wizhelp $(DAT)\dungeon $(DAT)\porthelp \
+       $(DAT)\license $(O)sp_lev.tag
+       cd $(DAT)
+       echo data >dlb.lst
+       echo oracles >>dlb.lst
+       if exist options echo options >>dlb.lst
+       if exist ttyoptions echo ttyoptions >>dlb.lst
+       if exist guioptions echo guioptions >>dlb.lst
+       if exist porthelp echo porthelp >>dlb.lst
+       echo quest.dat >>dlb.lst
+       echo rumors >>dlb.lst
+       echo help >>dlb.lst
+       echo hh >>dlb.lst
+       echo cmdhelp >>dlb.lst
+       echo history >>dlb.lst
+       echo opthelp >>dlb.lst
+       echo wizhelp >>dlb.lst
+       echo dungeon >>dlb.lst
+       echo license >>dlb.lst
+       for %%N in (*.lev) do echo %%N >>dlb.lst
+       $(U)dlb_main cIf dlb.lst $(SRC)\nhdat
+       cd $(SRC)
+
+#==========================================
+#  Recover Utility
+#==========================================
+
+$(U)recover.exe: $(RECOVOBJS)
+       $(link) $(LFLAGSU) -out:$@ $(RECOVOBJS)
+
+$(O)recover.o: $(CONFIG_H) $(U)recover.c $(INCL)\win32api.h
+       $(CC) $(CFLAGSU) -Fo$@ $(U)recover.c
+
+#==========================================
+#  Tile Mapping
+#==========================================
+
+$(SRC)\tile.c: $(U)tilemap.exe
+       @echo A new $@ has been created
+       @$(U)tilemap
+
+$(U)tilemap.exe: $(O)tilemap.o
+       @$(link) $(LFLAGSU) -out:$@ $(O)tilemap.o
+
+$(O)tilemap.o: $(WSHR)\tilemap.c $(HACK_H)
+       @$(CC) $(CFLAGSU) -Fo$@ $(WSHR)\tilemap.c
+
+$(O)tiletx32.o: $(WSHR)\tilemap.c $(HACK_H)
+       @$(CC) $(CFLAGS) /DTILETEXT /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tilemap.c
+
+$(O)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H)
+       @$(CC) $(CFLAGS) /DTILETEXT -Fo$@ $(WSHR)\tilemap.c
+
+$(O)gifread.o: $(WSHR)\gifread.c  $(CONFIG_H) $(TILE_H)
+       @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@ $(WSHR)\gifread.c
+
+$(O)gifrd32.o: $(WSHR)\gifread.c  $(CONFIG_H) $(TILE_H)
+       @$(CC) $(CFLAGS) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\gifread.c
+
+$(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(TILE_H)
+       @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@ $(WSHR)\ppmwrite.c
+
+$(O)tiletext.o: $(WSHR)\tiletext.c  $(CONFIG_H) $(TILE_H)
+       @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@ $(WSHR)\tiletext.c
+
+$(O)tilete32.o: $(WSHR)\tiletext.c  $(CONFIG_H) $(TILE_H)
+       @$(CC) $(CFLAGS) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tiletext.c
+
+#==========================================
+# Optional Tile Utilities
+#==========================================
+
+$(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO)
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(GIFREADERS:^  =^
+               )
+               $(TEXT_IO:^     =^
+               )
+<<
+
+$(U)gif2tx32.exe: $(GIFREADERS32) $(TEXT_IO32)
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(GIFREADERS32:^        =^
+               )
+               $(TEXT_IO32:^   =^
+               )
+<<
+
+$(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO)
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(PPMWRITERS:^  =^
+               )
+               $(TEXT_IO:^     =^
+               )
+<<
+
+!IF "$(GRAPHICAL)"=="Y"
+$(TILEBMP16): $(TILEUTIL16) $(TILEFILES)
+       @echo Creating 16x16 binary tile files (this may take some time)
+       @$(U)tile2bmp $(TILEBMP16)
+#$(TILEBMP32): $(TILEUTIL32) $(TILEFILES32)
+#      @echo Creating 32x32 binary tile files (this may take some time)
+#      @$(U)til2bm32 $(TILEBMP32)
+
+!ELSE
+$(TILEBMP16):
+$(TILEBMP32):
+!ENDIF
+
+$(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO)
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(O)tile2bmp.o
+               $(TEXT_IO:^  =^
+               )
+<<
+
+$(U)til2bm32.exe: $(O)til2bm32.o $(TEXT_IO32)
+    @echo Linking $@...
+       @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk
+               $(O)til2bm32.o
+               $(TEXT_IO32:^  =^
+               )
+<<
+
+$(O)tile2bmp.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h
+       @$(CC) $(CFLAGS) -I$(WSHR) /DPACKED_FILE /Fo$@ $(WSHR)\tile2bmp.c
+
+$(O)til2bm32.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h
+       @$(CC) $(CFLAGS) -I$(WSHR) /DPACKED_FILE /DTILE_X=32 /DTILE_Y=32 /Fo$@ $(WSHR)\tile2bmp.c
+
+#==========================================
+# Housekeeping
+#==========================================
+
+spotless: clean
+! IF ("$(OBJ)"!="")
+       -rmdir $(OBJ) /s /Q
+! ENDIF
+       if exist $(INCL)\date.h    del $(INCL)\date.h
+       if exist $(INCL)\onames.h  del $(INCL)\onames.h
+       if exist $(INCL)\pm.h      del $(INCL)\pm.h
+       if exist $(INCL)\vis_tab.h del $(INCL)\vis_tab.h
+       if exist $(SRC)\vis_tab.c  del $(SRC)\vis_tab.c
+       if exist $(SRC)\tile.c     del $(SRC)\tile.c
+       if exist $(U)*.lnk         del $(U)*.lnk
+       if exist $(U)*.map         del $(U)*.map
+       if exist $(DAT)\data       del $(DAT)\data
+       if exist $(DAT)\rumors     del $(DAT)\rumors
+       if exist $(DAT)\???-fil?.lev    del $(DAT)\???-fil?.lev
+       if exist $(DAT)\???-goal.lev    del $(DAT)\???-goal.lev
+       if exist $(DAT)\???-loca.lev    del $(DAT)\???-loca.lev
+       if exist $(DAT)\???-strt.lev    del $(DAT)\???-strt.lev
+       if exist $(DAT)\air.lev         del $(DAT)\air.lev
+       if exist $(DAT)\asmodeus.lev    del $(DAT)\asmodeus.lev
+       if exist $(DAT)\astral.lev      del $(DAT)\astral.lev
+       if exist $(DAT)\baalz.lev       del $(DAT)\baalz.lev
+       if exist $(DAT)\bigroom.lev     del $(DAT)\bigroom.lev
+       if exist $(DAT)\castle.lev      del $(DAT)\castle.lev
+       if exist $(DAT)\data            del $(DAT)\data
+       if exist $(DAT)\dungeon         del $(DAT)\dungeon
+       if exist $(DAT)\dungeon.pdf     del $(DAT)\dungeon.pdf
+       if exist $(DAT)\earth.lev       del $(DAT)\earth.lev
+       if exist $(DAT)\fakewiz?.lev    del $(DAT)\fakewiz?.lev
+       if exist $(DAT)\fire.lev        del $(DAT)\fire.lev
+       if exist $(DAT)\juiblex.lev     del $(DAT)\juiblex.lev
+       if exist $(DAT)\knox.lev        del $(DAT)\knox.lev
+       if exist $(DAT)\medusa-?.lev    del $(DAT)\medusa-?.lev
+       if exist $(DAT)\mine*.lev       del $(DAT)\mine*.lev
+       if exist $(DAT)\options         del $(DAT)\options
+       if exist $(DAT)\ttyoptions      del $(DAT)\ttyoptions
+       if exist $(DAT)\guioptions      del $(DAT)\guioptions
+       if exist $(DAT)\oracle.lev      del $(DAT)\oracle.lev
+       if exist $(DAT)\oracles         del $(DAT)\oracles
+       if exist $(DAT)\orcus.lev       del $(DAT)\orcus.lev
+       if exist $(DAT)\rumors          del $(DAT)\rumors
+       if exist $(DAT)\quest.dat       del $(DAT)\quest.dat
+       if exist $(DAT)\sanctum.lev     del $(DAT)\sanctum.lev
+       if exist $(DAT)\soko?-?.lev     del $(DAT)\soko?-?.lev
+       if exist $(DAT)\tower?.lev      del $(DAT)\tower?.lev
+       if exist $(DAT)\valley.lev      del $(DAT)\valley.lev
+       if exist $(DAT)\water.lev       del $(DAT)\water.lev
+       if exist $(DAT)\wizard?.lev     del $(DAT)\wizard?.lev
+       if exist $(O)sp_lev.tag         del $(O)sp_lev.tag
+       if exist $(SRC)\monstr.c        del $(SRC)\monstr.c
+       if exist $(SRC)\vis_tab.c       del $(SRC)\vis_tab.c
+       if exist $(U)recover.exe        del $(U)recover.exe
+       if exist nhdat.                 del nhdat.
+       if exist $(O)obj.tag            del $(O)obj.tag
+       if exist $(O)gamedir.tag        del $(O)gamedir.tag
+       if exist $(O)nh*key.lib         del $(O)nh*key.lib
+       if exist $(O)nh*key.exp         del $(O)nh*key.exp
+
+clean:
+       if exist $(O)*.o del $(O)*.o
+       if exist $(O)utility.tag   del $(O)utility.tag
+       if exist $(U)makedefs.exe  del $(U)makedefs.exe
+       if exist $(U)lev_comp.exe  del $(U)lev_comp.exe
+       if exist $(U)dgn_comp.exe  del $(U)dgn_comp.exe
+       if exist $(SRC)\*.lnk      del $(SRC)\*.lnk
+       if exist $(SRC)\*.map      del $(SRC)\*.map
+       if exist $(O)install.tag   del $(O)install.tag
+! IF ("$(WINPFLAG)"!="")
+       if exist $(TILEBMP16)        del $(TILEBMP16)
+       if exist $(TILEBMP32)        del $(TILEBMP32)
+! ENDIF
+
+#===================================================================
+# OTHER DEPENDENCIES
+#===================================================================
+
+#
+# dat dependencies
+#
+
+$(DAT)\data: $(O)utility.tag    $(DATABASE)
+       $(U)makedefs -d
+
+$(DAT)\rumors: $(O)utility.tag    $(DAT)\rumors.tru   $(DAT)\rumors.fal
+       $(U)makedefs -r
+
+$(DAT)\quest.dat: $(O)utility.tag  $(DAT)\quest.txt
+       $(U)makedefs -q
+
+$(DAT)\oracles: $(O)utility.tag    $(DAT)\oracles.txt
+       $(U)makedefs -h
+
+$(DAT)\dungeon: $(O)utility.tag  $(DAT)\dungeon.def
+       $(U)makedefs -e
+       cd $(DAT)
+       $(U)dgn_comp dungeon.pdf
+       cd $(SRC)
+
+#
+# NT dependencies
+#
+
+$(O)nttty.o:   $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nttty.c
+       @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@  $(NTSYS)\nttty.c
+$(O)nhkeys.o:   $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nhkeys.c
+       @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@  $(NTSYS)\nhkeys.c
+$(O)winnt.o: $(HACK_H) $(INCL)\win32api.h $(NTSYS)\winnt.c
+       @$(CC) $(CFLAGS) -Fo$@  $(NTSYS)\winnt.c
+$(O)ntsound.o: $(HACK_H) $(NTSYS)\ntsound.c
+       @$(CC) $(CFLAGS)  -Fo$@ $(NTSYS)\ntsound.c
+$(O)mapimail.o: $(HACK_H) $(INCL)\nhlan.h $(NTSYS)\mapimail.c
+       @$(CC) $(CFLAGS) -DMAPI_VERBOSE  -Fo$@ $(NTSYS)\mapimail.c
+
+# 
+# util dependencies
+#
+
+$(O)panic.o:  $(U)panic.c $(CONFIG_H)
+       @$(CC) $(CFLAGS) -Fo$@ $(U)panic.c
+
+#
+# The rest are stolen from sys/unix/Makefile.src, 
+# with the following changes:
+#   * ../include changed to $(INCL)
+#   * slashes changed to back-slashes 
+#   * -c (which is included in CFLAGS) substituted with -Fo$@
+#   * targets prefixed with $(O)
+# but otherwise untouched.
+# That means that there is some irrelevant stuff
+# in here, but maintenance should be easier.
+#
+$(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\atari\tos.c
+$(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\win32api.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\pcmain.c
+$(O)pcsys.o: ..\sys\share\pcsys.c $(HACK_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\pcsys.c
+$(O)pctty.o: ..\sys\share\pctty.c $(HACK_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\pctty.c
+$(O)pcunix.o: ..\sys\share\pcunix.c $(HACK_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\pcunix.c
+$(O)random.o: ..\sys\share\random.c $(HACK_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\random.c
+$(O)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)\tcap.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\ioctl.c
+$(O)unixtty.o: ..\sys\share\unixtty.c $(HACK_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\unixtty.c
+$(O)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)\dlb.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\unix\unixmain.c
+$(O)unixunix.o: ..\sys\unix\unixunix.c $(HACK_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\unix\unixunix.c
+$(O)unixres.o: ..\sys\unix\unixres.c $(CONFIG_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\unix\unixres.c
+$(O)bemain.o: ..\sys\be\bemain.c $(HACK_H) $(INCL)\dlb.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\sys\be\bemain.c
+$(O)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)\func_tab.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\tty\getline.c
+$(O)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)\tcap.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\tty\termcap.c
+$(O)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)\tcap.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\tty\topl.c
+$(O)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h $(INCL)\tcap.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\tty\wintty.c
+$(O)Window.o: ..\win\X11\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \
+               $(CONFIG_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\Window.c
+$(O)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H)
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\dialogs.c
+$(O)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h ..\win\X11\nh72icon \
+               ..\win\X11\nh56icon ..\win\X11\nh32icon
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winX.c
+$(O)winmap.o: ..\win\X11\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \
+               $(INCL)\winX.h $(INCL)\tile2x11.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winmap.c
+$(O)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)\winX.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winmenu.c
+$(O)winmesg.o: ..\win\X11\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winmesg.c
+$(O)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)\func_tab.h \
+               $(INCL)\winX.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winmisc.c
+$(O)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)\winX.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winstat.c
+$(O)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\wintext.c
+$(O)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)\winX.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winval.c
+$(O)tile.o: $(SRC)\tile.c $(HACK_H)
+$(O)gnaskstr.o: ..\win\gnome\gnaskstr.c ..\win\gnome\gnaskstr.h \
+               ..\win\gnome\gnmain.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnaskstr.c
+$(O)gnbind.o: ..\win\gnome\gnbind.c ..\win\gnome\gnbind.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gnaskstr.h ..\win\gnome\gnyesno.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnbind.c
+$(O)gnglyph.o: ..\win\gnome\gnglyph.c ..\win\gnome\gnglyph.h $(INCL)\tile2x11.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnglyph.c
+$(O)gnmain.o: ..\win\gnome\gnmain.c ..\win\gnome\gnmain.h ..\win\gnome\gnsignal.h \
+               ..\win\gnome\gnbind.h ..\win\gnome\gnopts.h $(HACK_H) \
+               $(INCL)\date.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmain.c
+$(O)gnmap.o: ..\win\gnome\gnmap.c ..\win\gnome\gnmap.h ..\win\gnome\gnglyph.h \
+               ..\win\gnome\gnsignal.h $(HACK_H)
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmap.c
+$(O)gnmenu.o: ..\win\gnome\gnmenu.c ..\win\gnome\gnmenu.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gnbind.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmenu.c
+$(O)gnmesg.o: ..\win\gnome\gnmesg.c ..\win\gnome\gnmesg.h ..\win\gnome\gnsignal.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmesg.c
+$(O)gnopts.o: ..\win\gnome\gnopts.c ..\win\gnome\gnopts.h ..\win\gnome\gnglyph.h \
+               ..\win\gnome\gnmain.h ..\win\gnome\gnmap.h $(HACK_H)
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnopts.c
+$(O)gnplayer.o: ..\win\gnome\gnplayer.c ..\win\gnome\gnplayer.h \
+               ..\win\gnome\gnmain.h $(HACK_H)
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnplayer.c
+$(O)gnsignal.o: ..\win\gnome\gnsignal.c ..\win\gnome\gnsignal.h \
+               ..\win\gnome\gnmain.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnsignal.c
+$(O)gnstatus.o: ..\win\gnome\gnstatus.c ..\win\gnome\gnstatus.h \
+               ..\win\gnome\gnsignal.h ..\win\gnome\gn_xpms.h \
+               ..\win\gnome\gnomeprv.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnstatus.c
+$(O)gntext.o: ..\win\gnome\gntext.c ..\win\gnome\gntext.h ..\win\gnome\gnmain.h \
+               ..\win\gnome\gn_rip.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gntext.c
+$(O)gnworn.o: ..\win\gnome\gnworn.c ..\win\gnome\gnworn.h ..\win\gnome\gnglyph.h \
+               ..\win\gnome\gnsignal.h ..\win\gnome\gnomeprv.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnworn.c
+$(O)gnyesno.o: ..\win\gnome\gnyesno.c ..\win\gnome\gnbind.h ..\win\gnome\gnyesno.h
+       @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnyesno.c
+$(O)wingem.o: ..\win\gem\wingem.c $(HACK_H) $(INCL)\func_tab.h $(INCL)\dlb.h \
+               $(INCL)\patchlevel.h $(INCL)\wingem.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\gem\wingem.c
+$(O)wingem1.o: ..\win\gem\wingem1.c $(INCL)\gem_rsc.h $(INCL)\load_img.h \
+               $(INCL)\gr_rect.h $(INCL)\wintype.h $(INCL)\wingem.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\gem\wingem1.c
+$(O)load_img.o: ..\win\gem\load_img.c $(INCL)\load_img.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\gem\load_img.c
+$(O)gr_rect.o: ..\win\gem\gr_rect.c $(INCL)\gr_rect.h
+       @$(CC) $(CFLAGS) -Fo$@ ..\win\gem\gr_rect.c
+$(O)tile.o: tile.c $(HACK_H)
+$(O)qt_win.o: ..\win\Qt\qt_win.cpp $(HACK_H) $(INCL)\func_tab.h \
+               $(INCL)\dlb.h $(INCL)\patchlevel.h $(INCL)\tile2x11.h \
+               $(INCL)\qt_win.h $(INCL)\qt_clust.h $(INCL)\qt_kde0.h \
+               $(INCL)\qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc
+       $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_win.cpp
+$(O)qt_clust.o: ..\win\Qt\qt_clust.cpp $(INCL)\qt_clust.h
+       $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_clust.cpp
+$(O)qttableview.o: ..\win\Qt\qttableview.cpp $(INCL)\qttableview.h
+       $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qttableview.cpp
+$(O)monstr.o: monstr.c $(CONFIG_H)
+$(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)\vis_tab.h
+$(O)allmain.o: allmain.c $(HACK_H)
+$(O)alloc.o: alloc.c $(CONFIG_H)
+$(O)apply.o: apply.c $(HACK_H) $(INCL)\edog.h
+$(O)artifact.o: artifact.c $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h
+$(O)attrib.o: attrib.c $(HACK_H)
+$(O)ball.o: ball.c $(HACK_H)
+$(O)bones.o: bones.c $(HACK_H) $(INCL)\lev.h
+$(O)botl.o: botl.c $(HACK_H)
+$(O)cmd.o: cmd.c $(HACK_H) $(INCL)\func_tab.h
+$(O)dbridge.o: dbridge.c $(HACK_H)
+$(O)decl.o: decl.c $(HACK_H)
+$(O)detect.o: detect.c $(HACK_H) $(INCL)\artifact.h
+$(O)dig.o: dig.c $(HACK_H) $(INCL)\edog.h
+$(O)display.o: display.c $(HACK_H)
+$(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)\dlb.h
+$(O)do.o: do.c $(HACK_H) $(INCL)\lev.h
+$(O)do_name.o: do_name.c $(HACK_H)
+$(O)do_wear.o: do_wear.c $(HACK_H)
+$(O)dog.o: dog.c $(HACK_H) $(INCL)\edog.h
+$(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+$(O)dokick.o: dokick.c $(HACK_H) $(INCL)\eshk.h
+$(O)dothrow.o: dothrow.c $(HACK_H) $(INCL)\edog.h
+$(O)drawing.o: drawing.c $(HACK_H) $(INCL)\tcap.h
+$(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h
+$(O)eat.o: eat.c $(HACK_H)
+$(O)end.o: end.c $(HACK_H) $(INCL)\eshk.h $(INCL)\dlb.h
+$(O)engrave.o: engrave.c $(HACK_H) $(INCL)\lev.h
+$(O)exper.o: exper.c $(HACK_H)
+$(O)explode.o: explode.c $(HACK_H)
+$(O)extralev.o: extralev.c $(HACK_H)
+$(O)files.o: files.c $(HACK_H) $(INCL)\dlb.h
+$(O)fountain.o: fountain.c $(HACK_H)
+$(O)hack.o: hack.c $(HACK_H)
+$(O)hacklib.o: hacklib.c $(HACK_H)
+$(O)invent.o: invent.c $(HACK_H)
+$(O)light.o: light.c $(HACK_H) $(INCL)\lev.h
+$(O)lock.o: lock.c $(HACK_H)
+$(O)mail.o: mail.c $(HACK_H) $(INCL)\mail.h
+$(O)makemon.o: makemon.c $(HACK_H) $(INCL)\epri.h $(INCL)\emin.h \
+               $(INCL)\edog.h
+$(O)mapglyph.o: mapglyph.c $(HACK_H)
+$(O)mcastu.o: mcastu.c $(HACK_H)
+$(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+$(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
+$(O)minion.o: minion.c $(HACK_H) $(INCL)\emin.h $(INCL)\epri.h
+$(O)mklev.o: mklev.c $(HACK_H)
+$(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)\sp_lev.h
+$(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev.h
+$(O)mkobj.o: mkobj.c $(HACK_H)
+$(O)mkroom.o: mkroom.c $(HACK_H)
+$(O)mon.o: mon.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
+$(O)mondata.o: mondata.c $(HACK_H) $(INCL)\eshk.h $(INCL)\epri.h
+$(O)monmove.o: monmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h \
+               $(INCL)\epri.h
+$(O)monst.o: monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \
+               $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\monsym.h \
+               $(INCL)\dungeon.h $(INCL)\eshk.h $(INCL)\vault.h \
+               $(INCL)\epri.h $(INCL)\color.h
+$(O)mplayer.o: mplayer.c $(HACK_H)
+$(O)mthrowu.o: mthrowu.c $(HACK_H)
+$(O)muse.o: muse.c $(HACK_H) $(INCL)\edog.h
+$(O)music.o: music.c $(HACK_H) #interp.c
+$(O)o_init.o: o_init.c $(HACK_H) $(INCL)\lev.h
+$(O)objects.o: objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \
+               $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h
+$(O)objnam.o: objnam.c $(HACK_H)
+$(O)options.o: options.c $(CONFIG_H) $(INCL)\objclass.h $(INCL)\flag.h \
+               $(HACK_H) $(INCL)\tcap.h
+$(O)pager.o: pager.c $(HACK_H) $(INCL)\dlb.h
+$(O)pickup.o: pickup.c $(HACK_H)
+$(O)pline.o: pline.c $(HACK_H) $(INCL)\epri.h $(INCL)\edog.h
+$(O)polyself.o: polyself.c $(HACK_H)
+$(O)potion.o: potion.c $(HACK_H)
+$(O)pray.o: pray.c $(HACK_H) $(INCL)\epri.h
+$(O)priest.o: priest.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\eshk.h \
+               $(INCL)\epri.h $(INCL)\emin.h
+$(O)quest.o: quest.c $(HACK_H) $(INCL)\qtext.h
+$(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)\dlb.h $(INCL)\qtext.h
+$(O)read.o: read.c $(HACK_H)
+$(O)rect.o: rect.c $(HACK_H)
+$(O)region.o: region.c $(HACK_H) $(INCL)\lev.h
+$(O)restore.o: restore.c $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h
+$(O)rip.o: rip.c $(HACK_H)
+$(O)rnd.o: rnd.c $(HACK_H)
+$(O)role.o: role.c $(HACK_H)
+$(O)rumors.o: rumors.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h
+$(O)save.o: save.c $(HACK_H) $(INCL)\lev.h
+$(O)shk.o: shk.c $(HACK_H) $(INCL)\eshk.h
+$(O)shknam.o: shknam.c $(HACK_H) $(INCL)\eshk.h
+$(O)sit.o: sit.c $(HACK_H) $(INCL)\artifact.h
+$(O)sounds.o: sounds.c $(HACK_H) $(INCL)\edog.h
+$(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)\dlb.h $(INCL)\sp_lev.h
+$(O)spell.o: spell.c $(HACK_H)
+$(O)steal.o: steal.c $(HACK_H)
+$(O)steed.o: steed.c $(HACK_H)
+$(O)teleport.o: teleport.c $(HACK_H)
+$(O)timeout.o: timeout.c $(HACK_H) $(INCL)\lev.h
+$(O)topten.o: topten.c $(HACK_H) $(INCL)\dlb.h $(INCL)\patchlevel.h
+$(O)track.o: track.c $(HACK_H)
+$(O)trap.o: trap.c $(HACK_H)
+$(O)u_init.o: u_init.c $(HACK_H)
+$(O)uhitm.o: uhitm.c $(HACK_H)
+$(O)vault.o: vault.c $(HACK_H) $(INCL)\vault.h
+$(O)version.o: version.c $(HACK_H) $(INCL)\date.h $(INCL)\patchlevel.h
+$(O)vision.o: vision.c $(HACK_H) $(INCL)\vis_tab.h
+$(O)weapon.o: weapon.c $(HACK_H)
+$(O)were.o: were.c $(HACK_H)
+$(O)wield.o: wield.c $(HACK_H)
+$(O)windows.o: windows.c $(HACK_H) $(INCL)\wingem.h $(INCL)\winGnome.h
+$(O)wizard.o: wizard.c $(HACK_H) $(INCL)\qtext.h $(INCL)\epri.h
+$(O)worm.o: worm.c $(HACK_H) $(INCL)\lev.h
+$(O)worn.o: worn.c $(HACK_H)
+$(O)write.o: write.c $(HACK_H)
+$(O)zap.o: zap.c $(HACK_H)
+
+# end of file
diff --git a/sys/winnt/console.rc b/sys/winnt/console.rc
new file mode 100644 (file)
index 0000000..9a456e0
--- /dev/null
@@ -0,0 +1,49 @@
+/*     SCCS Id: @(#)console.rc 3.4     $Date: 2003/10/14 01:31:28 $                    */
+/* Copyright (c) Yitzhak Sapir, 2002.                                  */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+#include "windows.h"
+
+1 ICON DISCARDABLE "NetHack.ICO"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 3,4,3,0
+ PRODUCTVERSION 3,4,3,0
+ FILEFLAGSMASK 0x1fL
+#ifdef _DEBUG
+ FILEFLAGS 0x9L
+#else
+ FILEFLAGS 0x8L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x0L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "FileDescription", "NetHack for Windows - TTY Interface\0"
+            VALUE "FileVersion", "3.4.3\0"
+            VALUE "InternalName", "NetHack\0"
+            VALUE "LegalCopyright", "Copyright (C) 1985 - 2003.  By Stichting Mathematisch Centrum and M. Stephenson.  See license for details.\0"
+            VALUE "OriginalFilename", "NetHack.exe\0"
+            VALUE "PrivateBuild", "031014\0"
+            VALUE "ProductName", "NetHack\0"
+            VALUE "ProductVersion", "3.4.3\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+
+/*console.rc*/
+
diff --git a/sys/winnt/defaults.nh b/sys/winnt/defaults.nh
new file mode 100644 (file)
index 0000000..fd64458
--- /dev/null
@@ -0,0 +1,185 @@
+# Sample config file for win32 NetHack
+# A '#' at the beginning of a line means the rest of the line is a comment.
+#
+# Some options MUST be set in this file, other options can be toggled while
+# playing.  For a list of options available see the <opthelp.> file.
+#
+# To change the configuration, comment out the unwanted lines, and
+# uncomment the configuration you want.
+
+# *** OPTIONS ***
+#
+# Use the IBM character set rather than just plain ascii characters
+# for tty window-port.
+OPTIONS=IBMGraphics
+
+# Keyboard handling
+# Different keyboard handlers can be loaded.
+# Default is nhdefkey.dll but you can override that.
+# Ray Chason's keyboard handler
+# OPTIONS=altkeyhandler:nhraykey.dll
+#
+# NetHack 3.4.0 keyboard handling
+# OPTIONS=altkeyhandler:nh340key.dll
+
+# *** Personal Preferences ***
+# Some options to set personal preferences.  Uncomment and change these to
+# suit your personal preference.  If several people are to use the same
+# configuration, options like these should not be set.
+#
+#OPTIONS=name:Janet,role:Valkyrie,race:Human,gender:female,align:lawful
+#OPTIONS=dogname:Fido,catname:Morris,fruit:guava
+#OPTIONS=horsename:Silver
+#OPTIONS=autopickup,pickup_types:$"=/!?+
+#OPTIONS=packorder:")[%?+/=!(*0_`
+#OPTIONS=scores:10 top/2 around/own
+#OPTIONS=nolegacy,noverbose
+#OPTIONS=menustyle:traditional
+
+#
+# General options.  You might also set "silent" so as not to attract
+# the boss's attention.
+#
+# number_pad option can have an optional value of 0 (off), 1 (on), 
+# or 2(on,legacy-mode) which causes 5='g', alt-5='G', alt-0='I'
+OPTIONS=time,noshowexp,number_pad:2,lit_corridor
+#
+# If you want to get rid of "use #quit to quit..." use:
+OPTIONS=suppress_alert:3.3.1
+#
+# Note: the rest_on_space in the next line may not be
+#       appropriate for a beginning NetHack player, since
+#       it could result in use of a turn unintentionally.
+#       If you're new to NetHack, leave it commented it out.
+#OPTIONS=rest_on_space
+#
+# Set some options to control graphical window-port (these will
+# be safely and silently ignored by the tty port)
+#
+# Map window settings
+# possible map_mode options include: tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|
+#                                    ascii7x12|ascii8x12|ascii16x12|ascii12x16|
+#                                    ascii10x18|fit_to_screen
+OPTIONS=map_mode:tiles,scroll_margin:5
+
+# Message window settings
+OPTIONS=font_message:Arial,font_size_message:9,align_message:top
+
+# Menu settings
+OPTIONS=font_menu:Arial,font_size_menu:9
+
+# Text settings
+OPTIONS=font_text:Courier New,font_size_text:9
+
+# Status window settings
+OPTIONS=font_status:Courier New,font_size_status:9
+
+# Other
+OPTIONS=hilite_pet,!toptenwin
+#OPTIONS=!splash_screen,player_selection:prompts
+
+# Status/message window colors
+# Possible color options include:
+# six digit hexadecimal RGB color value ("#8F8F8F"), black, red, green, brown,
+# blue, magenta, cyan, gray (or grey), orange, brightgreen, yellow, brightblue,
+# brightmagenta, brightcyan, white, trueblack, purple, silver, maroon, fuchsia,
+# lime, olive, navy, teal, aqua, activeborder, activecaption, appworkspace,
+# background, btnface, btnshadow, btntext, captiontext, graytext, highlight,
+# highlighttext, inactiveborder, inactivecaption, menu, menutext, scrollbar,
+# window, windowframe, windowtext.
+#OPTIONS=windowcolors:status windowtext/window message windowtext/window
+
+# *** LOCATIONS ***
+# IMPORTANT: If you change any of these locations, the directories they
+# point at must exist.  NetHack will not create them for you.
+#
+# HACKDIR is the default location for everything.
+# Note: On Windows HACKDIR defaults to the location 
+#       of the NetHack.exe or NetHackw.exe file so
+#       setting HACKDIR below to override that is 
+#       not usually necessary or recommended.
+#HACKDIR=c:\games\nethack
+#
+# The location that level files in progress are stored (default=HACKDIR, writeable)
+#LEVELDIR=c:\nethack\levels
+#
+# The location where saved games are kept (default=HACKDIR, writeable)
+#SAVEDIR=c:\nethack\save
+#
+# The location that bones files are kept (default=HACKDIR, writeable)
+#BONESDIR=c:\nethack\save
+#
+# The location that file synchronization locks are stored (default=HACKDIR, writeable)
+#LOCKDIR=c:\nethack\levels
+#
+# The location that a record of game aborts and self-diagnosed game problems
+# is kept (default=HACKDIR, writeable)
+#TROUBLEDIR=c:\nethack\trouble
+
+# Finnish keyboards might need these modifications uncommented. 
+# For  \, @, $, [, |
+#OPTIONS=subkeyvalue:171/92
+#OPTIONS=subkeyvalue:178/64
+#OPTIONS=subkeyvalue:180/36
+#OPTIONS=subkeyvalue:184/91
+#OPTIONS=subkeyvalue:188/124
+
+#
+# *** CHARACTER GRAPHICS ***
+#
+# See the on-line help or the Guidebook for which symbols are in which
+# positions.
+#
+# If you merely set the IBMgraphics option as above, NetHack will use IBM
+# extended ASCII for dungeon characters.  If you don't like the selections,
+# you can make up your own via these graphics options, but you should still
+# set IBMgraphics if you are using IBM graphics characters to get the correct
+# processing.
+#
+# ================================================
+# An example using the IBM graphics character set:
+#DUNGEON=  032 179 196 218 191 192 217 197 193 194 \
+#         180 195 249 239 239 254 254 240 241 249 \
+#         177 177 060 062 060 062 220 124 190 035 \
+#         244 247 249 247 042 042 186 205 046 035 \
+#         247
+#
+#TRAPS=    094 094 094 094 094 094 094 094 094 094 \
+#         094 094 094 094 232 232 232 157 094 094 \
+#         094 094
+#
+#EFFECTS=  179 196 092 047 042 033 041 040        \
+#         048 035 064 042                         \
+#         047 045 092 058 058 092 045 047         \
+#         047 045 092 058 032 058 092 045 047
+#
+# ================================================
+# Some alternatives:
+#DUNGEON=  032 186 205 201 187 200 188 206 202 203 \
+#         185 204 249 239 239 254 254 240 241 249 \
+#         177 177 060 062 060 062 095 124 092 035 \
+#         244 247 249 247 042 042 179 196 046 035 \
+#         247
+#
+#TRAPS=    094 094 094 094 094 094 094 094 094 094 \
+#         094 094 094 094 094 034 094 094 094 094 \
+#         094 094
+
+# ================================================
+# Here is a recommendation sent in by Michael Feir
+# for use by blind NetHack players.
+#
+#DUNGEON=  032 124 045 124 124 124 124 045 045 045 \
+#          124 124 046 045 124 043 043 046 035 035 \
+#          060 062 060 062 095 092 035 126 126 126 \
+#          126 042 042 035 035 032 035 126
+#
+#TRAPS=    094 094 094 094 094 094 094 094 094 094 \
+#          094 094 094 094 094 094 094 094 094 094 \
+#          094 094
+#
+#EFFECTS=  124 095 092 047 042 033 041 040         \
+#          048 035 064 042                         \
+#          047 045 092 058 058 092 045 047         \
+#          047 045 092 058 032 058 092 045 047
+
diff --git a/sys/winnt/mapimail.c b/sys/winnt/mapimail.c
new file mode 100644 (file)
index 0000000..38ef942
--- /dev/null
@@ -0,0 +1,482 @@
+/*      SCCS Id: @(#)mapimail.c 3.4     $Date: 2002/07/24 08:25:20 $        */
+/* Copyright (c) Michael Allison, 1997                  */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifdef MAX_BODY_SIZE
+#undef MAX_BODY_SIZE
+#define MAX_BODY_SIZE           2048    /* largest body held in ram in bytes */
+#endif
+
+#include "hack.h"
+# ifdef LAN_MAIL
+#include "win32api.h"
+#include <mapi.h>
+
+#define MAPI_MSGID_SIZE 512     /* as recommended */
+#define MAPI_LIB_FAIL           1
+#define MAPI_FUNC_FAIL          2
+
+HANDLE hLibrary;                        /* Handle for MAPI32.DLL     */
+LHANDLE MAPISession;                    /* Handle for MAPI session   */
+char MAPIMessageID[MAPI_MSGID_SIZE];    /* Msg ID from provider      */
+lpMapiMessage MAPIMessage;              /* Ptr to message from prov  */
+struct lan_mail_struct received_msg;    /* store received msg here   */
+#ifdef MAPI_VERBOSE
+FILE *dbgfile;
+#define MAPIDEBUGFILENAME      "mapidebug.log"
+#endif
+
+/*
+ * Prototypes for functions in this file
+ * (Not in normal NetHack style, but its doubtful that any
+ *  of the code in here is at all portable between platforms)
+ */
+static long __stdcall start_mailthread(LPVOID ThreadParam);
+static boolean MAPI_mail_check(char *);
+static boolean MAPI_mail_fetch(char *);
+static void MAPI_mail_finish(void);
+static int MAPI_mail_context(int *);
+static boolean MAPI_mail_init(char *);
+static int InitMAPI(void);
+static int DeInitMAPI(void);
+static void MAPI_mail_abort(unsigned long);
+
+/*
+ * Declare the function pointers used to access MAPI routines
+ * from the MAPI32.DLL
+ */
+LPMAPILOGON     fpMAPILogon;
+LPMAPILOGOFF    fpMAPILogoff;
+LPMAPIFINDNEXT  fpMAPIFindNext;
+LPMAPIREADMAIL  fpMAPIReadMail;
+LPMAPIFREEBUFFER fpMAPIFreeBuffer;
+
+
+/*
+ * Data requiring synchronized access between the
+ * two thread contexts contained in this file
+ * (nethack thread and the MAPI-mail thread)
+ */
+HANDLE mailthread = 0;          /* handle for the mail-thread       */
+unsigned nhmailthread_ID;       /* thread ID for mail-thread        */
+unsigned long nhmail_param;     /* value passed to mail-thread      */
+long mailthread_continue = 0;   /* nh -> mapi thread: shut down!    */
+long mailthread_stopping = 0;   /* mapi -> nh thread: MAPI is ill!  */
+
+/*
+ * Data updated by the NetHack thread only
+ * but read by the MAPI-mail thread.
+ *
+ */
+char MAPI_username[120];
+boolean debugmapi;
+
+/*
+ * Data updated by the MAPI-mail thread only
+ * but read by the NetHack thread.
+ */
+long mail_fetched = 0;
+
+/*
+ * Data used only by the MAPI-mail thread.
+ */
+long mailpasses;        /* counts the FindNext calls issued to MAPI */
+char msgID[80];         /* message ID of msg under manipulation     */
+
+/*===============================================================
+ * NetHack thread routines
+ *
+ * These routines run in the context of the main NetHack thread.
+ * They are used to provide an interface between the NetHack
+ * LAN_MAIL code and the MAPI-thread code.
+ *
+ * These routines are referenced by shared code in
+ * sys/share/nhlan.c and they are prototyped in include/extern.h
+ *===============================================================
+ */
+boolean mail_check()
+{
+       if (!mailthread_stopping) {
+               if (mail_fetched > 0)
+                       return TRUE;
+       } else lan_mail_terminate();
+       return FALSE;
+}
+
+
+boolean mail_fetch(msg)
+struct lan_mail_struct *msg;
+{
+       /* shouldn't need to check mailthread_stopping here
+          as the data should be valid anyway */
+       *msg = received_msg;
+       iflags.lan_mail_fetched = TRUE;
+       /* clear the marker now so new messages can arrive */
+       InterlockedDecrement(&mail_fetched);
+       /* check to see if the MAPI-mail thread is saying "stop" */
+       if (mailthread_stopping) lan_mail_terminate();
+       return TRUE;
+}
+
+void mail_finish()
+{
+       InterlockedDecrement(&mailthread_continue);
+}
+
+void mail_init(uname)
+char *uname;
+{
+  /* This routine invokes the _beginthreadex()
+   * run-time library call to start the execution
+   * of the MAPI-mail thread.  It also performs
+   * few other preparatory tasks.
+   */
+       if (mailthread_continue) {
+               /* Impossible - something is really messed up */
+               /* We better do some sanity checking */
+               /* Is there a valid thread handle and ID? */
+               if (mailthread && nhmailthread_ID) {
+                       /* TODO: check 'em via WIN32 call */
+                       /* if valid, do something about them */
+                       /* if not, clear them */
+               }
+       }
+       mailthread = 0;
+       nhmailthread_ID = 0;
+       mailthread_continue = 0;  /* no interlock needed yet */
+       mailthread_stopping = 0;  /* no interlock needed yet */
+#ifdef MAPI_VERBOSE
+       if (getenv("DEBUG_MAPI")) debugmapi = TRUE; 
+#endif
+       if (uname)
+               strcpy(MAPI_username, uname);
+       else {
+#ifdef MAPI_VERBOSE
+               if (debugmapi) dbgfile = fopen(MAPIDEBUGFILENAME,"w");
+               if (dbgfile) {
+                      fprintf(dbgfile,
+                             "mapi initialization bypassed because uname not available\n");
+                      fclose(dbgfile);
+               }
+#endif
+               return;
+       }
+       mailthread = (HANDLE)_beginthreadex(
+                       (void *)0,
+                       (unsigned)0,
+                       start_mailthread,
+                       (void *)&nhmail_param,
+                       (unsigned)0, (unsigned *)&nhmailthread_ID);
+#if 0
+       /* TODO: check for failure of the thread. For now nethack
+        *       doesn't care
+        */
+       if (!mailthread) {
+
+       }
+#endif
+}
+
+/*===============================================================
+ * MAPI-mail thread routines
+ *
+ * These routines run in the context of their own
+ * MAPI-mail thread.  They were placed into their own
+ * thread, because MAPI calls can sometimes (often?) take
+ * a horribly long time to return (minutes even).
+ *
+ * Each of the routines below are referenced only by other
+ * routines below, with the exception of start_mailthread(),
+ * of course, which is started by a run-time library call
+ * issued from the main NetHack thread.
+ *===============================================================
+ */
+
+/*
+ * start_mailthread() is the entry point of the MAPI-mail thread.
+ *
+ */
+
+static long __stdcall start_mailthread(LPVOID ThreadParam)
+{
+    char *lu = MAPI_username;
+    if(MAPI_mail_init(lu)) {
+       InterlockedIncrement(&mailthread_continue);
+       while (mailthread_continue) {
+               mailpasses++;
+               if (MAPI_mail_check(msgID)) {
+                       if (MAPI_mail_fetch(msgID)) {
+                               /* getting here means success */
+                       }
+               }
+               Sleep(MAILTHREADFREQ);
+       }
+#ifdef MAPI_VERBOSE
+       if (debugmapi && !mailthread_continue) {
+         fprintf(dbgfile,
+               "MAPI-thread detected mailthread_continue change.\n");
+         fprintf(dbgfile,
+               "NetHack has requested that the MAPI-thread cease.\n");
+       }
+#endif
+    }
+    return 0;
+}
+
+static int
+MAPI_mail_context(mcount)
+int *mcount;
+{
+       unsigned long status;
+       char tmpID[80];
+       int count = 0;
+
+       tmpID[0] = '\0';
+       MAPIMessageID[0] = '\0';
+
+       /* Get the ID of the first unread message */
+       status = fpMAPIFindNext(MAPISession, 0, 0, 0,
+               MAPI_UNREAD_ONLY | MAPI_GUARANTEE_FIFO,
+               0, tmpID);
+       /* Now loop through them all until we have no more */
+       while (status == SUCCESS_SUCCESS) {
+               strcpy(MAPIMessageID, tmpID);
+               count++;
+               status = fpMAPIFindNext(MAPISession, 0,
+                       0, MAPIMessageID,
+                       MAPI_UNREAD_ONLY | MAPI_GUARANTEE_FIFO,
+                       0, tmpID);
+       }
+       if (status == MAPI_E_NO_MESSAGES) {
+               /* context is now at last message */
+               if (mcount) *mcount = count;
+               return SUCCESS_SUCCESS;
+       }
+       return status;
+}
+
+static boolean
+MAPI_mail_check(mID)
+char *mID;
+{
+       unsigned long status;
+       char tmpID[80];
+
+       tmpID[0] = '\0';
+
+#ifdef MAPI_VERBOSE
+       if (debugmapi) fprintf(dbgfile, "MAPI_mail_check() ");
+#endif
+       if (mail_fetched) {
+#ifdef MAPI_VERBOSE
+       if (debugmapi) fprintf(dbgfile, "returning FALSE (buffer occupied)\n");
+#endif
+               return FALSE; /* buffer occupied, don't bother */
+       }
+       /* Get the ID of the next unread message if there is one */
+       status = fpMAPIFindNext(MAPISession, 0, 0, MAPIMessageID,
+               MAPI_UNREAD_ONLY | MAPI_GUARANTEE_FIFO,
+               0, tmpID);
+       if (status == SUCCESS_SUCCESS) {
+               strcpy(mID, tmpID);
+#ifdef MAPI_VERBOSE
+       if (debugmapi) fprintf(dbgfile, "returning TRUE\n");
+#endif
+               return TRUE;
+       }
+       if (status == MAPI_E_NO_MESSAGES) {
+#ifdef MAPI_VERBOSE
+               if (debugmapi) fprintf(dbgfile, "returning FALSE\n");
+#endif
+               return FALSE;
+       }
+#ifdef MAPI_VERBOSE
+       if (debugmapi) fprintf(dbgfile,"Error, check_newmail() status: %d\n", status);
+       MAPI_mail_abort(status);
+#endif
+       return FALSE;
+}
+
+static boolean
+MAPI_mail_fetch(mID)
+char *mID;
+{
+       unsigned long status;
+
+#ifdef MAPI_VERBOSE
+       if (debugmapi) fprintf(dbgfile, "MAPI_mail_fetch() ");
+#endif
+       /*
+        *  Update context right away so we don't loop if there
+        *  was a problem getting the message
+        */
+       strcpy(MAPIMessageID, mID);
+
+       if (mail_fetched) {
+#ifdef MAPI_VERBOSE
+       if (debugmapi) fprintf(dbgfile, "returning FALSE (buffer occupied)\n");
+#endif
+                return FALSE;  /* buffer occupied */
+       }
+
+       status = fpMAPIReadMail(MAPISession, 0, mID,
+                MAPI_SUPPRESS_ATTACH | MAPI_PEEK,
+                0, &MAPIMessage);
+       if (status == SUCCESS_SUCCESS) {
+               strncpy(received_msg.subject,
+                       MAPIMessage->lpszSubject,
+                       sizeof(received_msg.subject) - 1);
+               if((MAPIMessage->lpOriginator->lpszName != (char *)0)
+                && MAPIMessage->lpOriginator->lpszName[0] != '\0')
+                       strncpy(received_msg.sender,
+                               MAPIMessage->lpOriginator->lpszName,
+                               sizeof(received_msg.sender) - 1);
+               else
+                       strncpy(received_msg.sender,
+                               MAPIMessage->lpOriginator->lpszAddress,
+                               sizeof(received_msg.sender) - 1);
+               strncpy(received_msg.body,
+                       MAPIMessage->lpszNoteText,MAX_BODY_SIZE - 1);
+               received_msg.body[MAX_BODY_SIZE - 1] = '\0';
+               received_msg.body_in_ram = TRUE;
+               status = fpMAPIFreeBuffer(MAPIMessage);
+               InterlockedIncrement(&mail_fetched);
+#ifdef MAPI_VERBOSE
+               if (debugmapi) fprintf(dbgfile, "returning TRUE\n");
+#endif
+               return TRUE;
+       }
+#ifdef MAPI_VERBOSE
+       else
+               if (debugmapi) fprintf(dbgfile,"MAPIRead failed, status = %d\n", status);
+       if (debugmapi) fprintf(dbgfile, "returning FALSE (failed)\n");
+#endif
+       return FALSE;
+}
+
+static void
+MAPI_mail_finish()
+{
+       InterlockedIncrement(&mailthread_stopping);
+       (void) fpMAPILogoff(MAPISession,0,0,0);
+       (void) DeInitMAPI();
+#ifdef MAPI_VERBOSE
+       if (debugmapi) fclose(dbgfile);
+#endif
+       (void) _endthreadex(0);
+}
+
+static void
+MAPI_mail_abort(reason)
+unsigned long reason;
+{
+#ifdef MAPI_VERBOSE
+       if (debugmapi) fprintf(dbgfile,
+               "Terminating MAPI-thread due to error %d.\n", reason);
+#endif
+       MAPI_mail_finish();
+}
+
+static boolean
+MAPI_mail_init(uname)
+char *uname;
+{
+       unsigned long status;
+       int count = 0;
+
+#ifdef MAPI_VERBOSE
+       if (debugmapi) dbgfile = fopen(MAPIDEBUGFILENAME,"w");
+       if (debugmapi) fprintf(dbgfile,"Hello %s, NetHack is initializing MAPI.\n",
+               uname);
+#endif
+       status = InitMAPI();
+       if (status) {
+#ifdef MAPI_VERBOSE
+           if (debugmapi) fprintf(dbgfile,"Error initializing MAPI %d\n", status);
+#endif
+           return FALSE;
+       }
+       status = fpMAPILogon(0,uname,0L,0L,0L,(LPLHANDLE)&MAPISession);
+       if (status != SUCCESS_SUCCESS) {
+#ifdef MAPI_VERBOSE
+           if (debugmapi) fprintf(dbgfile,"Status of MAPI logon is %d\n", status);
+#endif
+           return FALSE;
+       }
+#ifdef MAPI_VERBOSE
+       if (debugmapi) fprintf(dbgfile,
+               "Stage 1 of MAPI initialization successful.\n");
+       if (debugmapi) fprintf(dbgfile,"MAPI Session handle: %d\n", MAPISession);
+#endif
+       status = MAPI_mail_context(&count);
+       if (status == SUCCESS_SUCCESS) {
+#ifdef MAPI_VERBOSE
+           if (debugmapi) fprintf(dbgfile,
+                   "Stage 2 of MAPI initialization successful.\n");
+           if (debugmapi) fprintf(dbgfile,"Detected %d old unread messages.\n",
+                   count);
+#endif
+           return TRUE;
+       }
+#ifdef MAPI_VERBOSE
+       if (debugmapi) fprintf(dbgfile,
+               "Error, status of MAPI_mail_context() is %d.\n",
+               status);
+       if (debugmapi) fprintf(dbgfile,
+               "Dismantling MAPI interface and cleaning up.\n");
+#endif
+       MAPI_mail_finish();
+       return FALSE;
+}
+
+int InitMAPI()
+{
+
+    if (!(hLibrary = LoadLibrary("MAPI32.DLL")))
+      return MAPI_LIB_FAIL;
+
+    if ((fpMAPILogon = (LPMAPILOGON)GetProcAddress(hLibrary,"MAPILogon")) == NULL)
+      return MAPI_FUNC_FAIL;
+
+    if ((fpMAPILogoff = (LPMAPILOGOFF)GetProcAddress(hLibrary,"MAPILogoff")) == NULL)
+      return MAPI_FUNC_FAIL;
+
+    if ((fpMAPIFindNext= (LPMAPIFINDNEXT)GetProcAddress(hLibrary,"MAPIFindNext")) == NULL)
+      return MAPI_FUNC_FAIL;
+
+    if ((fpMAPIReadMail= (LPMAPIREADMAIL)GetProcAddress(hLibrary,"MAPIReadMail")) == NULL)
+      return MAPI_FUNC_FAIL;
+
+    if ((fpMAPIFindNext= (LPMAPIFINDNEXT)GetProcAddress(hLibrary,"MAPIFindNext")) == NULL)
+      return MAPI_FUNC_FAIL;
+
+    if ((fpMAPIFreeBuffer= (LPMAPIFREEBUFFER)GetProcAddress(hLibrary,"MAPIFreeBuffer")) == NULL)
+      return MAPI_FUNC_FAIL;
+
+#ifdef MAPI_VERBOSE
+    if (debugmapi) {
+       fprintf(dbgfile,"Entry Points:\n");
+       fprintf(dbgfile,"MAPILogon      = %p\n",fpMAPILogon);
+       fprintf(dbgfile,"MAPILogoff     = %p\n",fpMAPILogoff);
+       fprintf(dbgfile,"MAPIFindNext   = %p\n",fpMAPIFindNext);
+       fprintf(dbgfile,"MAPIFreeBuffer = %p\n",fpMAPIReadMail);
+       fprintf(dbgfile,"MAPIReadMail   = %p\n",fpMAPIFreeBuffer);
+    }
+#endif
+    return 0;
+}
+
+int DeInitMAPI()
+{
+
+    fpMAPILogon = NULL;
+    fpMAPILogoff= NULL;
+    fpMAPIFindNext= NULL;
+    fpMAPIReadMail= NULL;
+    fpMAPIFreeBuffer = NULL;
+    FreeLibrary(hLibrary);
+    return 0;
+}
+
+#endif /*LAN_MAIL*/
+
diff --git a/sys/winnt/nethack.def b/sys/winnt/nethack.def
new file mode 100644 (file)
index 0000000..835bc6d
--- /dev/null
@@ -0,0 +1,9 @@
+NAME           NETHACK
+DESCRIPTION    'NetHack 3.4.1 for Windows NT'
+EXETYPE                WINDOWS
+STUB           'WINSTUB.EXE'
+CODE           PRELOAD MOVEABLE DISCARDABLE
+DATA           PRELOAD MOVEABLE MULTIPLE
+HEAPSIZE       4096
+STACKSIZE      9216
+EXPORTS                WndProc
diff --git a/sys/winnt/nh340key.c b/sys/winnt/nh340key.c
new file mode 100644 (file)
index 0000000..e1481a4
--- /dev/null
@@ -0,0 +1,297 @@
+/*     SCCS Id: @(#)nh340key.c 3.4     $Date: 2003/11/01 23:57:00 $   */
+/* Copyright (c) NetHack PC Development Team 2003                      */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+/*
+ * This is the NetHack keystroke processing from NetHack 3.4.0.
+ * It can be built as a run-time loadable dll (nh340key.dll),
+ * placed in the same directory as the nethack.exe executable,
+ * and loaded by specifying OPTIONS=altkeyhandler:nh340key
+ * in defaults.nh
+ */
+
+static char where_to_get_source[] = "http://www.nethack.org/";
+static char author[] = "The NetHack Development Team";
+
+#include "hack.h"
+#include "wintty.h"
+#include "win32api.h"
+
+extern HANDLE hConIn;
+extern INPUT_RECORD ir;
+char dllname[512];
+char *shortdllname;
+
+int FDECL(__declspec(dllexport) __stdcall
+ProcessKeystroke, (HANDLE hConIn, INPUT_RECORD *ir, 
+    boolean *valid, BOOLEAN_P numberpad, int portdebug));
+
+int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
+{
+       char dlltmpname[512];
+       char *tmp = dlltmpname, *tmp2;
+       *(tmp + GetModuleFileName(hInstance, tmp, 511)) = '\0';
+       (void)strcpy(dllname, tmp);
+       tmp2 = strrchr(dllname, '\\');
+       if (tmp2) {
+               tmp2++;
+               shortdllname = tmp2;
+       }
+       return TRUE;
+}
+
+/*
+ *  Keyboard translation tables.
+ *  (Adopted from the MSDOS port)
+ */
+
+#define KEYPADLO       0x47
+#define KEYPADHI       0x53
+
+#define PADKEYS        (KEYPADHI - KEYPADLO + 1)
+#define iskeypad(x)    (KEYPADLO <= (x) && (x) <= KEYPADHI)
+
+/*
+ * Keypad keys are translated to the normal values below.
+ * Shifted keypad keys are translated to the
+ *    shift values below.
+ */
+
+static const struct pad {
+       uchar normal, shift, cntrl;
+} keypad[PADKEYS] = {
+                       {'y', 'Y', C('y')},             /* 7 */
+                       {'k', 'K', C('k')},             /* 8 */
+                       {'u', 'U', C('u')},             /* 9 */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'h', 'H', C('h')},             /* 4 */
+                       {'g', 'G', 'g'},                /* 5 */
+                       {'l', 'L', C('l')},             /* 6 */
+                       {'+', 'P', C('p')},             /* + */
+                       {'b', 'B', C('b')},             /* 1 */
+                       {'j', 'J', C('j')},             /* 2 */
+                       {'n', 'N', C('n')},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+}, numpad[PADKEYS] = {
+                       {'7', M('7'), '7'},             /* 7 */
+                       {'8', M('8'), '8'},             /* 8 */
+                       {'9', M('9'), '9'},             /* 9 */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'4', M('4'), '4'},             /* 4 */
+                       {'g', 'G', 'g'},                /* 5 */
+                       {'6', M('6'), '6'},             /* 6 */
+                       {'+', 'P', C('p')},             /* + */
+                       {'1', M('1'), '1'},             /* 1 */
+                       {'2', M('2'), '2'},             /* 2 */
+                       {'3', M('3'), '3'},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+};
+
+#define inmap(x,vk)    (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2')
+
+int __declspec(dllexport) __stdcall
+ProcessKeystroke(hConIn, ir, valid, numberpad, portdebug)
+HANDLE hConIn;
+INPUT_RECORD *ir;
+boolean *valid;
+boolean numberpad;
+int portdebug;
+{
+       int metaflags = 0, k = 0;
+       int keycode, vk;
+       unsigned char ch, pre_ch, mk = 0;
+       unsigned short int scan;
+       unsigned long shiftstate;
+       int altseq = 0;
+       const struct pad *kpad;
+
+       shiftstate = 0L;
+       ch = pre_ch = ir->Event.KeyEvent.uChar.AsciiChar;
+       scan  = ir->Event.KeyEvent.wVirtualScanCode;
+       vk    = ir->Event.KeyEvent.wVirtualKeyCode;
+       keycode = MapVirtualKey(vk, 2);
+       shiftstate = ir->Event.KeyEvent.dwControlKeyState;
+
+       if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) {
+               if (ch || inmap(keycode,vk)) altseq = 1;
+               else altseq = -1;       /* invalid altseq */
+       }
+       if (ch || (iskeypad(scan)) || (altseq > 0))
+               *valid = TRUE;
+       /* if (!valid) return 0; */
+       /*
+        * shiftstate can be checked to see if various special
+         * keys were pressed at the same time as the key.
+         * Currently we are using the ALT & SHIFT & CONTROLS.
+         *
+         *           RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED,
+         *           RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED,
+         *           SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON,
+         *           CAPSLOCK_ON, ENHANCED_KEY
+         *
+         * are all valid bit masks to use on shiftstate.
+         * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the
+         *      left control key was pressed with the keystroke.
+         */
+        if (iskeypad(scan)) {
+            kpad = numberpad ? numpad : keypad;
+            if (shiftstate & SHIFT_PRESSED) {
+                ch = kpad[scan - KEYPADLO].shift;
+            }
+            else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
+                ch = kpad[scan - KEYPADLO].cntrl;
+            }
+            else {
+                ch = kpad[scan - KEYPADLO].normal;
+            }
+        }
+        else if (altseq > 0) { /* ALT sequence */
+               if (vk == 0xBF) ch = M('?');
+               else ch = M(tolower(keycode));
+        }
+       if (ch == '\r') ch = '\n';
+#ifdef PORT_DEBUG
+       if (portdebug) {
+               char buf[BUFSZ];
+               Sprintf(buf,
+       "PORTDEBUG (%s): ch=%u, sc=%u, vk=%d, sh=0x%X (ESC to end)",
+                       shortdllname, ch, scan, vk, shiftstate);
+               fprintf(stdout, "\n%s", buf);
+       }
+#endif
+       return ch;
+}
+
+int __declspec(dllexport) __stdcall
+NHkbhit(hConIn, ir)
+HANDLE hConIn;
+INPUT_RECORD *ir;
+{
+       int done = 0;   /* true =  "stop searching"        */
+       int retval;     /* true =  "we had a match"        */
+       DWORD count;
+       unsigned short int scan;
+       unsigned char ch;
+       unsigned long shiftstate;
+       int altseq = 0, keycode, vk;
+       done = 0;
+       retval = 0;
+       while (!done)
+       {
+           count = 0;
+           PeekConsoleInput(hConIn,ir,1,&count);
+           if (count > 0) {
+               if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) {
+                       ch    = ir->Event.KeyEvent.uChar.AsciiChar;
+                       scan  = ir->Event.KeyEvent.wVirtualScanCode;
+                       shiftstate = ir->Event.KeyEvent.dwControlKeyState;
+                       vk = ir->Event.KeyEvent.wVirtualKeyCode;
+                       keycode = MapVirtualKey(vk, 2);
+                       if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) {
+                               if  (ch || inmap(keycode,vk)) altseq = 1;
+                               else altseq = -1;       /* invalid altseq */
+                       }
+                       if (ch || iskeypad(scan) || altseq) {
+                               done = 1;           /* Stop looking         */
+                               retval = 1;         /* Found what we sought */
+                       } else {
+                               /* Strange Key event; let's purge it to avoid trouble */
+                               ReadConsoleInput(hConIn,ir,1,&count);
+                       }
+
+               }
+               else if ((ir->EventType == MOUSE_EVENT &&
+                 (ir->Event.MouseEvent.dwButtonState & MOUSEMASK))) {
+                       done = 1;
+                       retval = 1;
+               }
+
+               else /* Discard it, it's an insignificant event */
+                       ReadConsoleInput(hConIn,ir,1,&count);
+               } else  /* There are no events in console event queue */ {
+               done = 1;         /* Stop looking               */
+               retval = 0;
+           }
+       }
+       return retval;
+}
+
+int __declspec(dllexport) __stdcall
+CheckInput(hConIn, ir, count, numpad, mode, mod, cc)
+HANDLE hConIn;
+INPUT_RECORD *ir;
+DWORD *count; 
+boolean numpad;
+int mode;
+int *mod;
+coord *cc;
+{
+       int ch;
+       boolean valid = 0, done = 0;
+       while (!done) {
+               ReadConsoleInput(hConIn,ir,1,count);
+               if (mode == 0) {
+                   if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) {
+                       ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0);
+                       done = valid;
+                   }
+               } else {
+                   if (count > 0) {
+                       if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) {
+                           ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0);
+                           if (valid) return ch;
+                       } else if (ir->EventType == MOUSE_EVENT) {
+                           if ((ir->Event.MouseEvent.dwEventFlags == 0) &&
+                               (ir->Event.MouseEvent.dwButtonState & MOUSEMASK)) {
+                                   cc->x = ir->Event.MouseEvent.dwMousePosition.X + 1;
+                                   cc->y = ir->Event.MouseEvent.dwMousePosition.Y - 1;
+
+                                   if (ir->Event.MouseEvent.dwButtonState & LEFTBUTTON)
+                                       *mod = CLICK_1;
+                                   else if (ir->Event.MouseEvent.dwButtonState & RIGHTBUTTON)
+                                       *mod = CLICK_2;
+#if 0  /* middle button */
+                                   else if (ir->Event.MouseEvent.dwButtonState & MIDBUTTON)
+                                       *mod = CLICK_3;
+#endif 
+                                  return 0;
+                           }
+                       }
+                   } else 
+                       done = 1;
+               }
+       }
+       return mode ? 0 : ch;
+}
+
+int __declspec(dllexport) __stdcall
+SourceWhere(buf)
+char **buf;
+{
+       if (!buf) return 0;
+       *buf = where_to_get_source;
+       return 1;
+}
+
+int __declspec(dllexport) __stdcall
+SourceAuthor(buf)
+char **buf;
+{
+       if (!buf) return 0;
+       *buf = author;
+       return 1;
+}
+
+int __declspec(dllexport) __stdcall
+KeyHandlerName(buf, full)
+char **buf;
+int full;
+{
+       if (!buf) return 0;
+       if (full) *buf = dllname;
+       else *buf = shortdllname;
+       return 1;
+}
+
diff --git a/sys/winnt/nhdefkey.c b/sys/winnt/nhdefkey.c
new file mode 100644 (file)
index 0000000..24c635d
--- /dev/null
@@ -0,0 +1,329 @@
+/*     SCCS Id: @(#)nhdefkey.c 3.4     $Date: 2003/11/01 23:57:00 $   */
+/* Copyright (c) NetHack PC Development Team 2003                      */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+/*
+ * This is the default NetHack keystroke processing.
+ * It can be built as a run-time loadable dll (nhdefkey.dll).
+ * Alternative keystroke handlers can be built using the
+ * entry points in this file as a template.
+ *
+ * Use the defaults.nh "altkeyhandler" option to set a
+ * different dll name (without the ".DLL" extension) to
+ * get different processing. Ensure that the dll referenced
+ * in defaults.nh exists in the same directory as NetHack in
+ * order for it to load successfully.
+ *
+ */
+
+static char where_to_get_source[] = "http://www.nethack.org/";
+static char author[] = "The NetHack Development Team";
+
+#include "hack.h"
+#include "wintty.h"
+#include "win32api.h"
+
+extern HANDLE hConIn;
+extern INPUT_RECORD ir;
+char dllname[512];
+char *shortdllname;
+
+int FDECL(__declspec(dllexport) __stdcall
+ProcessKeystroke, (HANDLE hConIn, INPUT_RECORD *ir, 
+    boolean *valid, BOOLEAN_P numberpad, int portdebug));
+
+int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
+{
+       char dlltmpname[512];
+       char *tmp = dlltmpname, *tmp2;
+       *(tmp + GetModuleFileName(hInstance, tmp, 511)) = '\0';
+       (void)strcpy(dllname, tmp);
+       tmp2 = strrchr(dllname, '\\');
+       if (tmp2) {
+               tmp2++;
+               shortdllname = tmp2;
+       }
+       return TRUE;
+}
+
+/*
+ *  Keyboard translation tables.
+ *  (Adopted from the MSDOS port)
+ */
+
+#define KEYPADLO       0x47
+#define KEYPADHI       0x53
+
+#define PADKEYS        (KEYPADHI - KEYPADLO + 1)
+#define iskeypad(x)    (KEYPADLO <= (x) && (x) <= KEYPADHI)
+
+/*
+ * Keypad keys are translated to the normal values below.
+ * Shifted keypad keys are translated to the
+ *    shift values below.
+ */
+
+static const struct pad {
+       uchar normal, shift, cntrl;
+} keypad[PADKEYS] = {
+                       {'y', 'Y', C('y')},             /* 7 */
+                       {'k', 'K', C('k')},             /* 8 */
+                       {'u', 'U', C('u')},             /* 9 */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'h', 'H', C('h')},             /* 4 */
+                       {'g', 'G', 'g'},                /* 5 */
+                       {'l', 'L', C('l')},             /* 6 */
+                       {'+', 'P', C('p')},             /* + */
+                       {'b', 'B', C('b')},             /* 1 */
+                       {'j', 'J', C('j')},             /* 2 */
+                       {'n', 'N', C('n')},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+}, numpad[PADKEYS] = {
+                       {'7', M('7'), '7'},             /* 7 */
+                       {'8', M('8'), '8'},             /* 8 */
+                       {'9', M('9'), '9'},             /* 9 */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'4', M('4'), '4'},             /* 4 */
+                       {'5', M('5'), '5'},             /* 5 */
+                       {'6', M('6'), '6'},             /* 6 */
+                       {'+', 'P', C('p')},             /* + */
+                       {'1', M('1'), '1'},             /* 1 */
+                       {'2', M('2'), '2'},             /* 2 */
+                       {'3', M('3'), '3'},             /* 3 */
+                       {'0', M('0'), '0'},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+};
+
+#define inmap(x,vk)    (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2')
+
+static BYTE KeyState[256];
+
+int __declspec(dllexport) __stdcall
+ProcessKeystroke(hConIn,ir, valid, numberpad, portdebug)
+HANDLE hConIn;
+INPUT_RECORD *ir;
+boolean *valid;
+boolean numberpad;
+int portdebug;
+{
+       int metaflags = 0, k = 0;
+       int keycode, vk;
+       unsigned char ch, pre_ch, mk = 0;
+       unsigned short int scan;
+       unsigned long shiftstate;
+       int altseq = 0;
+       const struct pad *kpad;
+
+       shiftstate = 0L;
+       ch = pre_ch = ir->Event.KeyEvent.uChar.AsciiChar;
+       scan  = ir->Event.KeyEvent.wVirtualScanCode;
+       vk    = ir->Event.KeyEvent.wVirtualKeyCode;
+       keycode = MapVirtualKey(vk, 2);
+       shiftstate = ir->Event.KeyEvent.dwControlKeyState;
+       KeyState[VK_SHIFT]   = (shiftstate & SHIFT_PRESSED) ? 0x81 : 0;
+       KeyState[VK_CONTROL] = (shiftstate & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) ?
+                               0x81 : 0;
+       KeyState[VK_CAPITAL] = (shiftstate & CAPSLOCK_ON) ? 0x81 : 0;
+
+       if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) {
+               if (ch || inmap(keycode,vk)) altseq = 1;
+               else altseq = -1;       /* invalid altseq */
+       }
+       if (ch || (iskeypad(scan)) || (altseq > 0))
+               *valid = TRUE;
+       /* if (!valid) return 0; */
+       /*
+        * shiftstate can be checked to see if various special
+         * keys were pressed at the same time as the key.
+         * Currently we are using the ALT & SHIFT & CONTROLS.
+         *
+         *           RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED,
+         *           RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED,
+         *           SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON,
+         *           CAPSLOCK_ON, ENHANCED_KEY
+         *
+         * are all valid bit masks to use on shiftstate.
+         * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the
+         *      left control key was pressed with the keystroke.
+         */
+        if (iskeypad(scan)) {
+            kpad = numberpad ? numpad : keypad;
+            if (shiftstate & SHIFT_PRESSED) {
+                ch = kpad[scan - KEYPADLO].shift;
+            }
+            else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
+                ch = kpad[scan - KEYPADLO].cntrl;
+            }
+            else {
+                ch = kpad[scan - KEYPADLO].normal;
+            }
+        }
+        else if (altseq > 0) { /* ALT sequence */
+               if (vk == 0xBF) ch = M('?');
+               else ch = M(tolower(keycode));
+        }
+       /* Attempt to work better with international keyboards. */
+       else {
+               WORD chr[2];
+               k = ToAscii(vk, scan, KeyState, chr, 0);
+               if (k <= 2)
+                   switch(k) {
+                       case 2:  /* two characters */
+                               ch = (unsigned char)chr[1];
+                               *valid = TRUE;
+                               break;
+                       case 1:  /* one character */
+                               ch = (unsigned char)chr[0];
+                               *valid = TRUE;
+                               break;
+                       case 0:  /* no translation */
+                       default: /* negative */
+                               *valid = FALSE;
+                   }
+       }
+       if (ch == '\r') ch = '\n';
+#ifdef PORT_DEBUG
+       if (portdebug) {
+               char buf[BUFSZ];
+               Sprintf(buf,
+       "PORTDEBUG (%s): ch=%u, sc=%u, vk=%d, pre=%d, sh=0x%X, ta=%d (ESC to end)",
+                       shortdllname, ch, scan, vk, pre_ch, shiftstate, k);
+               fprintf(stdout, "\n%s", buf);
+       }
+#endif
+       return ch;
+}
+
+
+int __declspec(dllexport) __stdcall
+NHkbhit(hConIn, ir)
+HANDLE hConIn;
+INPUT_RECORD *ir;
+{
+       int done = 0;   /* true =  "stop searching"        */
+       int retval;     /* true =  "we had a match"        */
+       DWORD count;
+       unsigned short int scan;
+       unsigned char ch;
+       unsigned long shiftstate;
+       int altseq = 0, keycode, vk;
+       done = 0;
+       retval = 0;
+       while (!done)
+       {
+           count = 0;
+           PeekConsoleInput(hConIn,ir,1,&count);
+           if (count > 0) {
+               if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) {
+                       ch    = ir->Event.KeyEvent.uChar.AsciiChar;
+                       scan  = ir->Event.KeyEvent.wVirtualScanCode;
+                       shiftstate = ir->Event.KeyEvent.dwControlKeyState;
+                       vk = ir->Event.KeyEvent.wVirtualKeyCode;
+                       keycode = MapVirtualKey(vk, 2);
+                       if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) {
+                               if  (ch || inmap(keycode,vk)) altseq = 1;
+                               else altseq = -1;       /* invalid altseq */
+                       }
+                       if (ch || iskeypad(scan) || altseq) {
+                               done = 1;           /* Stop looking         */
+                               retval = 1;         /* Found what we sought */
+                       } else {
+                               /* Strange Key event; let's purge it to avoid trouble */
+                               ReadConsoleInput(hConIn,ir,1,&count);
+                       }
+
+               }
+               else if ((ir->EventType == MOUSE_EVENT &&
+                 (ir->Event.MouseEvent.dwButtonState & MOUSEMASK))) {
+                       done = 1;
+                       retval = 1;
+               }
+
+               else /* Discard it, it's an insignificant event */
+                       ReadConsoleInput(hConIn,ir,1,&count);
+               } else  /* There are no events in console event queue */ {
+               done = 1;         /* Stop looking               */
+               retval = 0;
+           }
+       }
+       return retval;
+}
+
+int __declspec(dllexport) __stdcall
+CheckInput(hConIn, ir, count, numpad, mode, mod, cc)
+HANDLE hConIn;
+INPUT_RECORD *ir;
+DWORD *count; 
+boolean numpad;
+int mode;
+int *mod;
+coord *cc;
+{
+       int ch;
+       boolean valid = 0, done = 0;
+       while (!done) {
+               ReadConsoleInput(hConIn,ir,1,count);
+               if (mode == 0) {
+                   if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) {
+                       ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0);
+                       done = valid;
+                   }
+               } else {
+                   if (count > 0) {
+                       if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) {
+                           ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0);
+                           if (valid) return ch;
+                       } else if (ir->EventType == MOUSE_EVENT) {
+                           if ((ir->Event.MouseEvent.dwEventFlags == 0) &&
+                               (ir->Event.MouseEvent.dwButtonState & MOUSEMASK)) {
+                                   cc->x = ir->Event.MouseEvent.dwMousePosition.X + 1;
+                                   cc->y = ir->Event.MouseEvent.dwMousePosition.Y - 1;
+
+                                   if (ir->Event.MouseEvent.dwButtonState & LEFTBUTTON)
+                                       *mod = CLICK_1;
+                                   else if (ir->Event.MouseEvent.dwButtonState & RIGHTBUTTON)
+                                       *mod = CLICK_2;
+#if 0  /* middle button */
+                                   else if (ir->Event.MouseEvent.dwButtonState & MIDBUTTON)
+                                       *mod = CLICK_3;
+#endif 
+                                  return 0;
+                           }
+                       }
+                   } else 
+                       done = 1;
+               }
+       }
+       return mode ? 0 : ch;
+}
+
+int __declspec(dllexport) __stdcall
+SourceWhere(buf)
+char **buf;
+{
+       if (!buf) return 0;
+       *buf = where_to_get_source;
+       return 1;
+}
+
+int __declspec(dllexport) __stdcall
+SourceAuthor(buf)
+char **buf;
+{
+       if (!buf) return 0;
+       *buf = author;
+       return 1;
+}
+
+int __declspec(dllexport) __stdcall
+KeyHandlerName(buf, full)
+char **buf;
+int full;
+{
+       if (!buf) return 0;
+       if (full) *buf = dllname;
+       else *buf = shortdllname;
+       return 1;
+}
+
diff --git a/sys/winnt/nhico.uu b/sys/winnt/nhico.uu
new file mode 100644 (file)
index 0000000..b420c3c
--- /dev/null
@@ -0,0 +1,27 @@
+begin 600 nethack.ico
+M```!``(`("`0``````#H`@``)@```!`0$```````*`$```X#```H````(```
+M`$`````!``0``````(`"````````````````````````````````@```@```
+M`("``(````"``(``@(```,#`P`"`@(````#_``#_````__\`_P```/\`_P#_
+M_P``____````````````````````````__=P```````````'=W<`#___=P``
+M````````?_?W<`]W:/=P``#_<```!WB'!G`/8'B'<``/_W<```?VAGAP#P=E
+M;W``__]W<``'>`=H\`__=G_P#_!V9_<`!W=H=W``__</\/\,>(:/<`=P=W<`
+M``__\`_W=G9GB'<`!W=P````__#_=G=X2&"/<`=W``````_P_\=T=F>(:/<'
+M<```````#_9V=V5H8(AO<`````````_W=W1WAXAHA_````````#_9\<&>&!H
+M!H9W````````_W=V=6=GAH@(]P``````#_?'9W9T:(!H:&=P``````_V=WQV
+M=X=HA@B/<``````/]GQP=G>':(A@AW``````#_<'9\=VAH!HB&=P``````_V
+M=G=X9V>&"&"'<``````/]W?'9W1@B(:(9W````^&C_?'9W1WAX:`8(=P`'`/
+M_X_P9W9W:&A@AH:'</=P#_^/]W?'='>'AH@(AW!W\`=H;_9V=G!H:&"&A@=P
+M`(`'B(_P<'!V<&>(:(B'<`"`#_\/______=W=W=W=W!W<`__#_____?_?W=W
+M=W=P=W`/``__#___]W=W=W!W<`!P```/\`#_]_]_=W<`!W``````#P```/_W
+M=W<```!P````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````H````$````"`````!``0``````,``````````
+M````````````````````````@```@````("``(````"``(``@(```,#`P`"`
+M@(````#_``#_````__\`_P```/\`_P#__P``____`````````````/<`````
+M=P`/_W`/<`=W<`#_\/8'!W<```\/9F!P<````/9F!@<`````]F9@9P````]F
+M9@8&<```#V9F8&!P```/9F8&!G````]F9F!@<``/?V9F!@9P<`]_9F9@8'!P
+M#P___W=W<'``#P__=W!P````````````````````````````````````````
+K````````````````````````````````````````````````````````````
+`
+end
diff --git a/sys/winnt/nhraykey.c b/sys/winnt/nhraykey.c
new file mode 100644 (file)
index 0000000..a845f58
--- /dev/null
@@ -0,0 +1,599 @@
+/*     SCCS Id: @(#)nhraykey.c 3.4     $Date: 2003/11/01 23:57:00 $   */
+/* Copyright (c) NetHack PC Development Team 2003                      */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+/*
+ * Keystroke handling contributed by Ray Chason.
+ * The following text was written by Ray Chason.
+ *  
+ * The problem
+ * ===========
+ * 
+ * The console-mode Nethack wants both keyboard and mouse input.  The
+ * problem is that the Windows API provides no easy way to get mouse input
+ * and also keyboard input properly translated according to the user's
+ * chosen keyboard layout.
+ * 
+ * The ReadConsoleInput function returns a stream of keyboard and mouse
+ * events.  Nethack is interested in those events that represent a key
+ * pressed, or a click on a mouse button.  The keyboard events from
+ * ReadConsoleInput are not translated according to the keyboard layout,
+ * and do not take into account the shift, control, or alt keys.
+ * 
+ * The PeekConsoleInput function works similarly to ReadConsoleInput,
+ * except that it does not remove an event from the queue and it returns
+ * instead of blocking when the queue is empty.
+ * 
+ * A program can also use ReadConsole to get a properly translated stream
+ * of characters.  Unfortunately, ReadConsole does not return mouse events,
+ * does not distinguish the keypad from the main keyboard, does not return
+ * keys shifted with Alt, and does not even return the ESC key when
+ * pressed.  
+ * 
+ * We want both the functionality of ReadConsole and the functionality of
+ * ReadConsoleInput.  But Microsoft didn't seem to think of that.
+ * 
+ * 
+ * The solution, in the original code
+ * ==================================
+ * 
+ * The original 3.4.1 distribution tries to get proper keyboard translation
+ * by passing keyboard events to the ToAscii function.  This works, to some
+ * extent -- it takes the shift key into account, and it processes dead
+ * keys properly.  But it doesn't take non-US keyboards into account.  It
+ * appears that ToAscii is meant for windowed applications, and does not
+ * have enough information to do its job properly in a console application.
+ * 
+ * 
+ * The Finnish keyboard patch
+ * ==========================
+ * 
+ * This patch adds the "subkeyvalue" option to the defaults.nh file.  The
+ * user can then add OPTIONS=sukeyvalue:171/92, for instance, to replace
+ * the 171 character with 92, which is \.  This works, once properly
+ * configured, but places too much burden on the user.  It also bars the
+ * use of the substituted characters in naming objects or monsters.
+ * 
+ * 
+ * The solution presented here
+ * ===========================
+ * 
+ * The best way I could find to combine the functionality of ReadConsole
+ * with that of ReadConsoleInput is simple in concept.  First, call
+ * PeekConsoleInput to get the first event.  If it represents a key press,
+ * call ReadConsole to retrieve the key.  Otherwise, pop it off the queue
+ * with ReadConsoleInput and, if it's a mouse click, return it as such.
+ * 
+ * But the Devil, as they say, is in the details.  The problem is in
+ * recognizing an event that ReadConsole will return as a key.  We don't
+ * want to call ReadConsole unless we know that it will immediately return:
+ * if it blocks, the mouse and the Alt sequences will cease to function
+ * until it returns.
+ * 
+ * Separating process_keystroke into two functions, one for commands and a
+ * new one, process_keystroke2, for answering prompts, makes the job a lot
+ * easier.  process_keystroke2 doesn't have to worry about mouse events or
+ * Alt sequences, and so the consequences are minor if ReadConsole blocks. 
+ * process_keystroke, OTOH, never needs to return a non-ASCII character
+ * that was read from ReadConsole; it returns bytes with the high bit set
+ * only in response to an Alt sequence.
+ * 
+ * So in process_keystroke, before calling ReadConsole, a bogus key event
+ * is pushed on the queue.  This event causes ReadConsole to return, even
+ * if there was no other character available.  Because the bogus key has
+ * the eighth bit set, it is filtered out.  This is not done in
+ * process_keystroke2, because that would render dead keys unusable.
+ * 
+ * A separate process_keystroke2 can also process the numeric keypad in a
+ * way that makes sense for prompts:  just return the corresponding symbol,
+ * and pay no mind to number_pad or the num lock key.
+ * 
+ * The recognition of Alt sequences is modified, to support the use of
+ * characters generated with the AltGr key.  A keystroke is an Alt sequence
+ * if an Alt key is seen that can't be an AltGr (since an AltGr sequence
+ * could be a character, and in some layouts it could even be an ASCII
+ * character).  This recognition is different on NT-based and 95-based
+ * Windows:
+ * 
+ *    * On NT-based Windows, AltGr signals as right Alt and left Ctrl
+ *      together.  So an Alt sequence is recognized if either Alt key is
+ *      pressed and if right Alt and left Ctrl are not both present.  This
+ *      is true even if the keyboard in use does not have an AltGr key, and
+ *      uses right Alt for AltGr.
+ * 
+ *    * On 95-based Windows, with a keyboard that lacks the AltGr key, the
+ *      right Alt key is used instead.  But it still signals as right Alt,
+ *      without left Ctrl.  There is no way for the application to know
+ *      whether right Alt is Alt or AltGr, and so it is always assumed
+ *      to be AltGr.  This means that Alt sequences must be formed with
+ *      left Alt.
+ * 
+ * So the patch processes keystrokes as follows:
+ * 
+ *     * If the scan and virtual key codes are both 0, it's the bogus key,
+ *       and we ignore it.
+ * 
+ *     * Keys on the numeric keypad are processed for commands as in the
+ *       unpatched Nethack, and for prompts by returning the ASCII
+ *       character, even if the num lock is off.
+ *        
+ *     * Alt sequences are processed for commands as in the unpatched
+ *       Nethack, and ignored for prompts.
+ *        
+ *     * Control codes are returned as received, because ReadConsole will
+ *       not return the ESC key.
+ *        
+ *     * Other key-down events are passed to ReadConsole.  The use of
+ *       ReadConsole is different for commands than for prompts:
+ * 
+ *       o For commands, the bogus key is pushed onto the queue before
+ *         ReadConsole is called.  On return, non-ASCII characters are
+ *         filtered, so they are not mistaken for Alt sequences; this also
+ *         filters the bogus key.
+ * 
+ *       o For prompts, the bogus key is not used, because that would
+ *         interfere with dead keys.  Eight bit characters may be returned,
+ *         and are coded in the configured code page.
+ * 
+ * 
+ * Possible improvements
+ * =====================
+ * 
+ * Some possible improvements remain:
+ * 
+ *     * Integrate the existing Finnish keyboard patch, for use with non-
+ *       QWERTY layouts such as the German QWERTZ keyboard or Dvorak.
+ *        
+ *     * Fix the keyboard glitches in the graphical version.  Namely, dead
+ *       keys don't work, and input comes in as ISO-8859-1 but is displayed
+ *       as code page 437 if IBMgraphics is set on startup.
+ * 
+ *     * Transform incoming text to ISO-8859-1, for full compatibility with
+ *       the graphical version.
+ * 
+ *     * After pushing the bogus key and calling ReadConsole, check to see
+ *       if we got the bogus key; if so, and an Alt is pressed, process the
+ *       event as an Alt sequence.
+ * 
+ */
+
+static char where_to_get_source[] = "http://www.nethack.org/";
+static char author[] = "Ray Chason";
+
+#include "hack.h"
+#include "wintty.h"
+#include "win32api.h"
+
+extern HANDLE hConIn;
+extern INPUT_RECORD ir;
+char dllname[512];
+char *shortdllname;
+
+int FDECL(__declspec(dllexport) __stdcall
+ProcessKeystroke, (HANDLE hConIn, INPUT_RECORD *ir, 
+    boolean *valid, BOOLEAN_P numberpad, int portdebug));
+
+static INPUT_RECORD bogus_key;
+
+int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
+{
+       char dlltmpname[512];
+       char *tmp = dlltmpname, *tmp2;
+       *(tmp + GetModuleFileName(hInstance, tmp, 511)) = '\0';
+       (void)strcpy(dllname, tmp);
+       tmp2 = strrchr(dllname, '\\');
+       if (tmp2) {
+               tmp2++;
+               shortdllname = tmp2;
+       }
+       /* A bogus key that will be filtered when received, to keep ReadConsole
+        * from blocking */
+       bogus_key.EventType = KEY_EVENT;
+       bogus_key.Event.KeyEvent.bKeyDown = 1;
+       bogus_key.Event.KeyEvent.wRepeatCount = 1;
+       bogus_key.Event.KeyEvent.wVirtualKeyCode = 0;
+       bogus_key.Event.KeyEvent.wVirtualScanCode = 0;
+       bogus_key.Event.KeyEvent.uChar.AsciiChar = (uchar)0x80;
+       bogus_key.Event.KeyEvent.dwControlKeyState = 0;
+       return TRUE;
+}
+
+/*
+ *  Keyboard translation tables.
+ *  (Adopted from the MSDOS port)
+ */
+
+#define KEYPADLO       0x47
+#define KEYPADHI       0x53
+
+#define PADKEYS        (KEYPADHI - KEYPADLO + 1)
+#define iskeypad(x)    (KEYPADLO <= (x) && (x) <= KEYPADHI)
+#define isnumkeypad(x) (KEYPADLO <= (x) && (x) <= 0x51 && (x) != 0x4A && (x) != 0x4E)
+
+/*
+ * Keypad keys are translated to the normal values below.
+ * Shifted keypad keys are translated to the
+ *    shift values below.
+ */
+
+static const struct pad {
+       uchar normal, shift, cntrl;
+} keypad[PADKEYS] = {
+                       {'y', 'Y', C('y')},             /* 7 */
+                       {'k', 'K', C('k')},             /* 8 */
+                       {'u', 'U', C('u')},             /* 9 */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'h', 'H', C('h')},             /* 4 */
+                       {'g', 'G', 'g'},                /* 5 */
+                       {'l', 'L', C('l')},             /* 6 */
+                       {'+', 'P', C('p')},             /* + */
+                       {'b', 'B', C('b')},             /* 1 */
+                       {'j', 'J', C('j')},             /* 2 */
+                       {'n', 'N', C('n')},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+}, numpad[PADKEYS] = {
+                       {'7', M('7'), '7'},             /* 7 */
+                       {'8', M('8'), '8'},             /* 8 */
+                       {'9', M('9'), '9'},             /* 9 */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'4', M('4'), '4'},             /* 4 */
+                       {'g', 'G', 'g'},                /* 5 */
+                       {'6', M('6'), '6'},             /* 6 */
+                       {'+', 'P', C('p')},             /* + */
+                       {'1', M('1'), '1'},             /* 1 */
+                       {'2', M('2'), '2'},             /* 2 */
+                       {'3', M('3'), '3'},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+};
+
+#define inmap(x,vk)    (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2')
+
+/* Use process_keystroke for key commands, process_keystroke2 for prompts */
+/* int FDECL(process_keystroke, (INPUT_RECORD *ir, boolean *valid, int portdebug)); */
+int FDECL(process_keystroke2, (HANDLE,INPUT_RECORD *ir, boolean *valid));
+static int FDECL(is_altseq, (unsigned long shiftstate));
+
+static int
+is_altseq(shiftstate)
+unsigned long shiftstate;
+{
+    /* We need to distinguish the Alt keys from the AltGr key.
+     * On NT-based Windows, AltGr signals as right Alt and left Ctrl together;
+     * on 95-based Windows, AltGr signals as right Alt only.
+     * So on NT, we signal Alt if either Alt is pressed and left Ctrl is not,
+     * and on 95, we signal Alt for left Alt only. */
+    switch (shiftstate & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED)) {
+       case LEFT_ALT_PRESSED:
+       case LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED:
+           return 1;
+
+       case RIGHT_ALT_PRESSED:
+       case RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED:
+           return (GetVersion() & 0x80000000) == 0;
+
+        default:
+            return 0;
+    }
+}
+
+int __declspec(dllexport) __stdcall
+ProcessKeystroke(hConIn, ir, valid, numberpad, portdebug)
+HANDLE hConIn;
+INPUT_RECORD *ir;
+boolean *valid;
+boolean numberpad;
+int portdebug;
+{
+       int metaflags = 0, k = 0;
+       int keycode, vk;
+       unsigned char ch, pre_ch, mk = 0;
+       unsigned short int scan;
+       unsigned long shiftstate;
+       int altseq = 0;
+       const struct pad *kpad;
+       DWORD count;
+
+       shiftstate = 0L;
+       ch = pre_ch = ir->Event.KeyEvent.uChar.AsciiChar;
+       scan  = ir->Event.KeyEvent.wVirtualScanCode;
+       vk    = ir->Event.KeyEvent.wVirtualKeyCode;
+       keycode = MapVirtualKey(vk, 2);
+       shiftstate = ir->Event.KeyEvent.dwControlKeyState;
+       if (scan == 0 && vk == 0) {
+           /* It's the bogus_key */
+           ReadConsoleInput(hConIn,ir,1,&count);
+           *valid = FALSE;
+           return 0;
+       }
+
+       if (is_altseq(shiftstate)) {
+               if (ch || inmap(keycode,vk)) altseq = 1;
+               else altseq = -1;       /* invalid altseq */
+       }
+       if (ch || (iskeypad(scan)) || (altseq > 0))
+               *valid = TRUE;
+       /* if (!valid) return 0; */
+       /*
+        * shiftstate can be checked to see if various special
+         * keys were pressed at the same time as the key.
+         * Currently we are using the ALT & SHIFT & CONTROLS.
+         *
+         *           RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED,
+         *           RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED,
+         *           SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON,
+         *           CAPSLOCK_ON, ENHANCED_KEY
+         *
+         * are all valid bit masks to use on shiftstate.
+         * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the
+         *      left control key was pressed with the keystroke.
+         */
+        if (iskeypad(scan)) {
+           ReadConsoleInput(hConIn,ir,1,&count);
+            kpad = numberpad ? numpad : keypad;
+            if (shiftstate & SHIFT_PRESSED) {
+                ch = kpad[scan - KEYPADLO].shift;
+            }
+            else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
+                ch = kpad[scan - KEYPADLO].cntrl;
+            }
+            else {
+                ch = kpad[scan - KEYPADLO].normal;
+            }
+        }
+        else if (altseq > 0) { /* ALT sequence */
+               ReadConsoleInput(hConIn,ir,1,&count);
+               if (vk == 0xBF) ch = M('?');
+               else ch = M(tolower(keycode));
+        }
+       else if (ch < 32 && !isnumkeypad(scan)) {
+               /* Control code; ReadConsole seems to filter some of these,
+                * including ESC */
+               ReadConsoleInput(hConIn,ir,1,&count);
+       }
+       /* Attempt to work better with international keyboards. */
+       else {
+               CHAR ch2;
+               DWORD written;
+               /* The bogus_key guarantees that ReadConsole will return,
+                * and does not itself do anything */
+               WriteConsoleInput(hConIn, &bogus_key, 1, &written);
+               ReadConsole(hConIn,&ch2,1,&count,NULL);
+               /* Prevent high characters from being interpreted as alt
+                * sequences; also filter the bogus_key */
+               if (ch2 & 0x80)
+                   *valid = FALSE;
+               else
+                   ch = ch2;
+                if (ch == 0) *valid = FALSE;
+       }
+       if (ch == '\r') ch = '\n';
+#ifdef PORT_DEBUG
+       if (portdebug) {
+               char buf[BUFSZ];
+               Sprintf(buf,
+       "PORTDEBUG: ch=%u, scan=%u, vk=%d, pre=%d, shiftstate=0x%X (ESC to end)\n",
+                       ch, scan, vk, pre_ch, shiftstate);
+               fprintf(stdout, "\n%s", buf);
+       }
+#endif
+       return ch;
+}
+
+int process_keystroke2(hConIn, ir, valid)
+HANDLE hConIn;
+INPUT_RECORD *ir;
+boolean *valid;
+{
+       /* Use these values for the numeric keypad */
+       static const char keypad_nums[] = "789-456+1230.";
+
+       unsigned char ch;
+       int vk;
+       unsigned short int scan;
+       unsigned long shiftstate;
+       int altseq;
+       DWORD count;
+
+       ch    = ir->Event.KeyEvent.uChar.AsciiChar;
+       vk    = ir->Event.KeyEvent.wVirtualKeyCode;
+       scan  = ir->Event.KeyEvent.wVirtualScanCode;
+       shiftstate = ir->Event.KeyEvent.dwControlKeyState;
+
+       if (scan == 0 && vk == 0) {
+           /* It's the bogus_key */
+           ReadConsoleInput(hConIn,ir,1,&count);
+           *valid = FALSE;
+           return 0;
+       }
+
+       altseq = is_altseq(shiftstate);
+       if (ch || (iskeypad(scan)) || altseq)
+               *valid = TRUE;
+       /* if (!valid) return 0; */
+       /*
+        * shiftstate can be checked to see if various special
+         * keys were pressed at the same time as the key.
+         * Currently we are using the ALT & SHIFT & CONTROLS.
+         *
+         *           RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED,
+         *           RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED,
+         *           SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON,
+         *           CAPSLOCK_ON, ENHANCED_KEY
+         *
+         * are all valid bit masks to use on shiftstate.
+         * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the
+         *      left control key was pressed with the keystroke.
+         */
+        if (iskeypad(scan) && !altseq) {
+           ReadConsoleInput(hConIn,ir,1,&count);
+            ch = keypad_nums[scan - KEYPADLO];
+        }
+       else if (ch < 32 && !isnumkeypad(scan)) {
+               /* Control code; ReadConsole seems to filter some of these,
+                * including ESC */
+               ReadConsoleInput(hConIn,ir,1,&count);
+       }
+       /* Attempt to work better with international keyboards. */
+       else {
+               CHAR ch2;
+               ReadConsole(hConIn,&ch2,1,&count,NULL);
+               ch = ch2 & 0xFF;
+                if (ch == 0) *valid = FALSE;
+       }
+       if (ch == '\r') ch = '\n';
+       return ch;
+}
+
+int __declspec(dllexport) __stdcall
+CheckInput(hConIn, ir, count, numpad, mode, mod, cc)
+HANDLE hConIn;
+INPUT_RECORD *ir;
+DWORD *count;
+int *mod;
+boolean numpad;
+coord *cc;
+{
+       int ch;
+       boolean valid = 0, done = 0;
+       while (!done) {
+          *count = 0;
+          WaitForSingleObject(hConIn, INFINITE);
+          PeekConsoleInput(hConIn,ir,1,count);
+          if (mode == 0) {
+               if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) {
+                       ch = process_keystroke2(hConIn, ir, &valid);
+                       done = valid;
+               } else
+                       ReadConsoleInput(hConIn,ir,1,count);
+          } else {
+               ch = 0;
+               if (count > 0) {
+                   if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) {
+                       ch = ProcessKeystroke(hConIn, ir, &valid, numpad,
+#ifdef PORTDEBUG
+                                               1);
+#else
+                                               0);
+#endif
+                       if (valid) return ch;
+                   } else {
+                       ReadConsoleInput(hConIn,ir,1,count);
+                       if (ir->EventType == MOUSE_EVENT) {
+                           if ((ir->Event.MouseEvent.dwEventFlags == 0) &&
+                               (ir->Event.MouseEvent.dwButtonState & MOUSEMASK)) {
+                               cc->x = ir->Event.MouseEvent.dwMousePosition.X + 1;
+                               cc->y = ir->Event.MouseEvent.dwMousePosition.Y - 1;
+
+                               if (ir->Event.MouseEvent.dwButtonState & LEFTBUTTON)
+                                       *mod = CLICK_1;
+                               else if (ir->Event.MouseEvent.dwButtonState & RIGHTBUTTON)
+                                       *mod = CLICK_2;
+#if 0  /* middle button */                            
+                               else if (ir->Event.MouseEvent.dwButtonState & MIDBUTTON)
+                                       *mod = CLICK_3;
+#endif 
+                              return 0;
+                           }
+                       }
+#if 0
+                       /* We ignore these types of console events */
+                       else if (ir->EventType == FOCUS_EVENT) {
+                       }
+                       else if (ir->EventType == MENU_EVENT) {
+                       }
+#endif
+                   }
+               } else 
+                   done = 1;
+          }
+       }
+       *mod = 0;
+       return ch;
+}
+
+int __declspec(dllexport) __stdcall
+NHkbhit(hConIn, ir)
+HANDLE hConIn;
+INPUT_RECORD *ir;
+{
+       int done = 0;   /* true =  "stop searching"        */
+       int retval;     /* true =  "we had a match"        */
+       DWORD count;
+       unsigned short int scan;
+       unsigned char ch;
+       unsigned long shiftstate;
+       int altseq = 0, keycode, vk;
+       done = 0;
+       retval = 0;
+       while (!done)
+       {
+           count = 0;
+           PeekConsoleInput(hConIn,ir,1,&count);
+           if (count > 0) {
+               if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) {
+                       ch    = ir->Event.KeyEvent.uChar.AsciiChar;
+                       scan  = ir->Event.KeyEvent.wVirtualScanCode;
+                       shiftstate = ir->Event.KeyEvent.dwControlKeyState;
+                       vk = ir->Event.KeyEvent.wVirtualKeyCode;
+                       keycode = MapVirtualKey(vk, 2);
+                       if (is_altseq(shiftstate)) {
+                               if  (ch || inmap(keycode,vk)) altseq = 1;
+                               else altseq = -1;       /* invalid altseq */
+                       }
+                       if (ch || iskeypad(scan) || altseq) {
+                               done = 1;           /* Stop looking         */
+                               retval = 1;         /* Found what we sought */
+                       } else {
+                               /* Strange Key event; let's purge it to avoid trouble */
+                               ReadConsoleInput(hConIn,ir,1,&count);
+                       }
+
+               }
+               else if ((ir->EventType == MOUSE_EVENT &&
+                 (ir->Event.MouseEvent.dwButtonState & MOUSEMASK))) {
+                       done = 1;
+                       retval = 1;
+               }
+
+               else /* Discard it, it's an insignificant event */
+                       ReadConsoleInput(hConIn,ir,1,&count);
+               } else  /* There are no events in console event queue */ {
+               done = 1;         /* Stop looking               */
+               retval = 0;
+           }
+       }
+       return retval;
+}
+
+
+int __declspec(dllexport) __stdcall
+SourceWhere(buf)
+char **buf;
+{
+       if (!buf) return 0;
+       *buf = where_to_get_source;
+       return 1;
+}
+
+int __declspec(dllexport) __stdcall
+SourceAuthor(buf)
+char **buf;
+{
+       if (!buf) return 0;
+       *buf = author;
+       return 1;
+}
+
+int __declspec(dllexport) __stdcall
+KeyHandlerName(buf, full)
+char **buf;
+int full;
+{
+       if (!buf) return 0;
+       if (full) *buf = dllname;
+       else *buf = shortdllname;
+       return 1;
+}
+
diff --git a/sys/winnt/nhsetup.bat b/sys/winnt/nhsetup.bat
new file mode 100644 (file)
index 0000000..63abe81
--- /dev/null
@@ -0,0 +1,114 @@
+@REM  SCCS Id: @(#)nhsetup.bat  3.4     $Date: 2002/07/24 08:25:21 $\r
+@REM  Copyright (c) NetHack PC Development Team 1993, 1996, 2002\r
+@REM  NetHack may be freely redistributed.  See license for details. \r
+@REM  Win32 setup batch file, see Install.nt for details\r
+@REM\r
+@echo off\r
+\r
+set _pause=\r
+\r
+:nxtcheck\r
+echo Checking to see if directories are set up properly\r
+if not exist ..\..\include\hack.h goto :err_dir\r
+if not exist ..\..\src\hack.c goto :err_dir\r
+if not exist ..\..\dat\wizard.des goto :err_dir\r
+if not exist ..\..\util\makedefs.c goto :err_dir\r
+if not exist ..\..\sys\winnt\winnt.c goto :err_dir\r
+echo Directories look ok.\r
+\r
+:do_tty\r
+if NOT exist ..\..\binary\*.* mkdir ..\..\binary\r
+if NOT exist ..\..\binary\license copy ..\..\dat\license ..\..\binary\license >nul\r
+echo Copying Microsoft Makefile - Makefile.msc to ..\..\src\Makefile.\r
+if NOT exist ..\..\src\Makefile goto :domsc\r
+copy ..\..\src\Makefile ..\..\src\Makefile-orig >nul\r
+echo      Your existing\r
+echo           ..\..\src\Makefile\r
+echo      has been renamed to\r
+echo           ..\..\src\Makefile-orig\r
+:domsc\r
+copy Makefile.msc ..\..\src\Makefile >nul\r
+echo Microsoft Makefile copied ok.\r
+\r
+echo Copying Borland Makefile - Makefile.bcc to ..\..\src\Makefile.bcc\r
+if NOT exist ..\..\src\Makefile.bcc goto :dobor\r
+copy ..\..\src\Makefile.bcc ..\..\src\Makefile.bcc-orig >nul\r
+echo      Your existing \r
+echo           ..\..\src\Makefile.bcc \r
+echo      has been renamed to \r
+echo           ..\..\src\Makefile.bcc-orig\r
+:dobor\r
+copy Makefile.bcc ..\..\src\Makefile.bcc >nul\r
+echo Borland Makefile copied ok.\r
+\r
+echo Copying MinGW Makefile - Makefile.gcc to ..\..\src\Makefile.gcc\r
+if NOT exist ..\..\src\Makefile.gcc goto :dogcc\r
+copy ..\..\src\Makefile.gcc ..\..\src\Makefile.gcc-orig >nul\r
+echo      Your existing\r
+echo           ..\..\src\Makefile.gcc\r
+echo      has been renamed to\r
+echo           ..\..\src\Makefile.gcc-orig\r
+:dogcc\r
+copy Makefile.gcc ..\..\src\Makefile.gcc >nul\r
+echo MinGW Makefile copied ok.\r
+\r
+:do_win\r
+if not exist ..\..\win\win32\nethack.dsw goto :err_win\r
+echo.\r
+echo Copying Visual C project files to ..\..\build directory\r
+echo Copying ..\..\win\win32\nethack.dsw  ..\..\nethack.dsw\r
+copy ..\..\win\win32\nethack.dsw  ..\.. >nul\r
+if NOT exist ..\..\binary\*.* echo Creating ..\..\binary directory\r
+if NOT exist ..\..\binary\*.* mkdir ..\..\binary\r
+if NOT exist ..\..\binary\license copy ..\..\dat\license ..\..\binary\license >nul\r
+if NOT exist ..\..\build\*.* echo Creating ..\..\build directory\r
+if NOT exist ..\..\build\*.* mkdir ..\..\build\r
+copy ..\..\win\win32\dgncomp.dsp   ..\..\build >nul\r
+copy ..\..\win\win32\dgnstuff.dsp  ..\..\build >nul\r
+copy ..\..\win\win32\dgnstuff.mak  ..\..\build >nul\r
+copy ..\..\win\win32\dlb_main.dsp  ..\..\build >nul\r
+copy ..\..\win\win32\levcomp.dsp   ..\..\build >nul\r
+copy ..\..\win\win32\levstuff.dsp  ..\..\build >nul\r
+copy ..\..\win\win32\levstuff.mak  ..\..\build >nul\r
+copy ..\..\win\win32\makedefs.dsp  ..\..\build >nul\r
+copy ..\..\win\win32\recover.dsp   ..\..\build >nul\r
+copy ..\..\win\win32\tile2bmp.dsp  ..\..\build >nul\r
+copy ..\..\win\win32\tiles.dsp     ..\..\build >nul\r
+copy ..\..\win\win32\tiles.mak     ..\..\build >nul\r
+copy ..\..\win\win32\tilemap.dsp   ..\..\build >nul\r
+copy ..\..\win\win32\uudecode.dsp   ..\..\build >nul\r
+copy ..\..\win\win32\nethackw.dsp   ..\..\build >nul\r
+\r
+goto :done\r
+\r
+:err_win\r
+echo Some of the files needed to build graphical NetHack\r
+echo for Windows are not in the expected places.\r
+echo Check "Install.nt" for a list of the steps required \r
+echo to build NetHack.\r
+goto :fini\r
+\r
+:err_data\r
+echo A required file ..\..\dat\data.bas seems to be missing.\r
+echo Check "Files." in the root directory for your NetHack distribution\r
+echo and make sure that all required files exist.\r
+goto :fini\r
+\r
+:err_dir\r
+echo Your directories are not set up properly, please re-read the\r
+echo documentation and sys/winnt/Install.nt.\r
+goto :fini\r
+\r
+:done\r
+echo done!\r
+echo.\r
+echo Proceed with the next step documented in Install.nt \r
+echo.\r
+\r
+:fini\r
+:end\r
+set _pause=Y\r
+if "%0"=="nhsetup" set _pause=N\r
+if "%0"=="NHSETUP" set _pause=N\r
+if "%_pause%"=="Y" pause\r
+set _pause=\r
diff --git a/sys/winnt/ntsound.c b/sys/winnt/ntsound.c
new file mode 100644 (file)
index 0000000..5996429
--- /dev/null
@@ -0,0 +1,28 @@
+/*   SCCS Id: @(#)ntsound.c   3.4     $Date: 2002/09/02 23:28:45 $                        */
+/*   Copyright (c) NetHack PC Development Team 1993                 */
+/*   NetHack may be freely redistributed.  See license for details. */
+/*                                                                  */
+/*
+ * ntsound.c - Windows NT NetHack sound support
+ *                                                  
+ *Edit History:
+ *     Initial Creation                              93/12/11
+ *
+ */
+
+#include "hack.h"
+#include "win32api.h"
+#include <mmsystem.h>
+
+#ifdef USER_SOUNDS
+
+void play_usersound(filename, volume)
+const char* filename;
+int volume;
+{
+/*    pline("play_usersound: %s (%d).", filename, volume); */
+       (void)sndPlaySound(filename, SND_ASYNC | SND_NODEFAULT);
+}
+
+#endif /*USER_SOUNDS*/
+/* ntsound.c */
diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c
new file mode 100644 (file)
index 0000000..8684e13
--- /dev/null
@@ -0,0 +1,961 @@
+/*     SCCS Id: @(#)nttty.c    3.4     $Date: 2003/11/15 00:39:32 $   */
+/* Copyright (c) NetHack PC Development Team 1993    */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* tty.c - (Windows NT) version */
+
+/*                                                  
+ * Initial Creation                            M. Allison      1993/01/31 
+ * Switch to low level console output routines M. Allison      2003/10/01
+ * Restrict cursor movement until input pending        M. Lehotay      2003/10/02
+ *
+ */
+
+#ifdef WIN32CON
+#define NEED_VARARGS /* Uses ... */
+#include "hack.h"
+#include "wintty.h"
+#include <sys\types.h>
+#include <sys\stat.h>
+#include "win32api.h"
+
+void FDECL(cmov, (int, int));
+void FDECL(nocmov, (int, int));
+int FDECL(process_keystroke, (INPUT_RECORD *, boolean *,
+    BOOLEAN_P numberpad, int portdebug));
+
+/*
+ * The following WIN32 Console API routines are used in this file.
+ *
+ * CreateFile
+ * GetConsoleScreenBufferInfo
+ * GetStdHandle
+ * SetConsoleCursorPosition
+ * SetConsoleTextAttribute
+ * SetConsoleCtrlHandler
+ * PeekConsoleInput
+ * ReadConsoleInput
+ * WriteConsoleOutputCharacter
+ * FillConsoleOutputAttribute
+ */
+
+/* Win32 Console handles for input and output */
+HANDLE hConIn;
+HANDLE hConOut;
+
+/* Win32 Screen buffer,coordinate,console I/O information */
+CONSOLE_SCREEN_BUFFER_INFO csbi, origcsbi;
+COORD ntcoord;
+INPUT_RECORD ir;
+
+/* Flag for whether NetHack was launched via the GUI, not the command line.
+ * The reason we care at all, is so that we can get
+ * a final RETURN at the end of the game when launched from the GUI
+ * to prevent the scoreboard (or panic message :-|) from vanishing
+ * immediately after it is displayed, yet not bother when started
+ * from the command line. 
+ */
+int GUILaunched;
+static BOOL FDECL(CtrlHandler, (DWORD));
+
+#ifdef PORT_DEBUG
+static boolean display_cursor_info = FALSE;
+#endif
+
+extern boolean getreturn_enabled;      /* from sys/share/pcsys.c */
+
+/* dynamic keystroke handling .DLL support */
+typedef int (__stdcall * PROCESS_KEYSTROKE)(
+    HANDLE,
+    INPUT_RECORD *,
+    boolean *,
+    BOOLEAN_P,
+    int
+);
+
+typedef int (__stdcall * NHKBHIT)(
+    HANDLE,
+    INPUT_RECORD *
+);
+
+typedef int (__stdcall * CHECKINPUT)(
+       HANDLE,
+       INPUT_RECORD *,
+       DWORD *,
+       BOOLEAN_P,
+       int,
+       int *,
+       coord *
+);
+
+typedef int (__stdcall * SOURCEWHERE)(
+    char **
+);
+
+typedef int (__stdcall * SOURCEAUTHOR)(
+    char **
+);
+
+typedef int (__stdcall * KEYHANDLERNAME)(
+    char **,
+    int
+);
+
+HANDLE hLibrary;
+PROCESS_KEYSTROKE pProcessKeystroke;
+NHKBHIT pNHkbhit;
+CHECKINPUT pCheckInput;
+SOURCEWHERE pSourceWhere;
+SOURCEAUTHOR pSourceAuthor;
+KEYHANDLERNAME pKeyHandlerName;
+
+#ifndef CLR_MAX
+#define CLR_MAX 16
+#endif
+int ttycolors[CLR_MAX];
+# ifdef TEXTCOLOR
+static void NDECL(init_ttycolor);
+# endif
+static void NDECL(really_move_cursor);
+
+#define MAX_OVERRIDES  256
+unsigned char key_overrides[MAX_OVERRIDES];
+
+static char nullstr[] = "";
+char erase_char,kill_char;
+
+#define DEFTEXTCOLOR  ttycolors[7]
+static WORD background = 0;
+static WORD foreground = (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED);
+static WORD attr = (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED);
+static DWORD ccount, acount;
+static COORD cursor = {0,0};
+
+/*
+ * Called after returning from ! or ^Z
+ */
+void
+gettty()
+{
+#ifndef TEXTCOLOR
+       int k;
+#endif
+       erase_char = '\b';
+       kill_char = 21;         /* cntl-U */
+       iflags.cbreak = TRUE;
+#ifdef TEXTCOLOR
+       init_ttycolor();
+#else
+       for(k=0; k < CLR_MAX; ++k)
+               ttycolors[k] = 7;
+#endif
+}
+
+/* reset terminal to original state */
+void
+settty(s)
+const char *s;
+{
+       cmov(ttyDisplay->curx, ttyDisplay->cury);
+       end_screen();
+       if(s) raw_print(s);
+}
+
+/* called by init_nhwindows() and resume_nhwindows() */
+void
+setftty()
+{
+       start_screen();
+}
+
+void
+tty_startup(wid, hgt)
+int *wid, *hgt;
+{
+       int twid = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1;
+
+       if (twid > 80) twid = 80;
+       *wid = twid;
+       *hgt = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1;
+       set_option_mod_status("mouse_support", SET_IN_GAME);
+}
+
+void
+tty_number_pad(state)
+int state;
+{
+}
+
+void
+tty_start_screen()
+{
+       if (iflags.num_pad) tty_number_pad(1);  /* make keypad send digits */
+}
+
+void
+tty_end_screen()
+{
+       clear_screen();
+       really_move_cursor();
+       if (GetConsoleScreenBufferInfo(hConOut,&csbi))
+       {
+           DWORD ccnt;
+           COORD newcoord;
+           
+           newcoord.X = 0;
+           newcoord.Y = 0;
+           FillConsoleOutputAttribute(hConOut,
+                       FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
+                       csbi.dwSize.X * csbi.dwSize.Y,
+                       newcoord, &ccnt);
+           FillConsoleOutputCharacter(hConOut,' ',
+                       csbi.dwSize.X * csbi.dwSize.Y,
+                       newcoord, &ccnt);
+       }
+       FlushConsoleInputBuffer(hConIn);
+}
+
+static BOOL CtrlHandler(ctrltype)
+DWORD ctrltype;
+{
+       switch(ctrltype) {
+       /*      case CTRL_C_EVENT: */
+               case CTRL_BREAK_EVENT:
+                       clear_screen();
+               case CTRL_CLOSE_EVENT:
+               case CTRL_LOGOFF_EVENT:
+               case CTRL_SHUTDOWN_EVENT:
+                       getreturn_enabled = FALSE;
+#ifndef NOSAVEONHANGUP
+                       hangup(0);
+#endif
+#if 0
+                       clearlocks();
+                       terminate(EXIT_FAILURE);
+#endif
+               default:
+                       return FALSE;
+       }
+}
+
+/* called by init_tty in wintty.c for WIN32CON port only */
+void
+nttty_open()
+{
+        HANDLE hStdOut;
+        DWORD cmode;
+        long mask;
+
+       load_keyboard_handler();
+       /* Initialize the function pointer that points to
+         * the kbhit() equivalent, in this TTY case nttty_kbhit()
+         */
+       nt_kbhit = nttty_kbhit;
+
+        /* The following 6 lines of code were suggested by 
+         * Bob Landau of Microsoft WIN32 Developer support,
+         * as the only current means of determining whether
+         * we were launched from the command prompt, or from
+         * the NT program manager. M. Allison
+         */
+        hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
+        GetConsoleScreenBufferInfo( hStdOut, &origcsbi);
+        GUILaunched = ((origcsbi.dwCursorPosition.X == 0) &&
+                           (origcsbi.dwCursorPosition.Y == 0));
+        if ((origcsbi.dwSize.X <= 0) || (origcsbi.dwSize.Y <= 0))
+            GUILaunched = 0;
+
+        /* Obtain handles for the standard Console I/O devices */
+       hConIn = GetStdHandle(STD_INPUT_HANDLE);
+       hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
+#if 0
+       hConIn = CreateFile("CONIN$",
+                       GENERIC_READ |GENERIC_WRITE,
+                       FILE_SHARE_READ |FILE_SHARE_WRITE,
+                       0, OPEN_EXISTING, 0, 0);                                        
+       hConOut = CreateFile("CONOUT$",
+                       GENERIC_READ |GENERIC_WRITE,
+                       FILE_SHARE_READ |FILE_SHARE_WRITE,
+                       0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0);
+#endif       
+
+       GetConsoleMode(hConIn,&cmode);
+#ifdef NO_MOUSE_ALLOWED
+       mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
+              ENABLE_MOUSE_INPUT | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT;   
+#else
+       mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
+              ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT;   
+#endif
+       /* Turn OFF the settings specified in the mask */
+       cmode &= ~mask;
+#ifndef NO_MOUSE_ALLOWED
+       cmode |= ENABLE_MOUSE_INPUT;
+#endif
+       SetConsoleMode(hConIn,cmode);
+       if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE)) {
+               /* Unable to set control handler */
+               cmode = 0;      /* just to have a statement to break on for debugger */
+       }
+       get_scr_size();
+       cursor.X = cursor.Y = 0;
+       really_move_cursor();
+}
+
+int process_keystroke(ir, valid, numberpad, portdebug)
+INPUT_RECORD *ir;
+boolean *valid;
+boolean numberpad;
+int portdebug;
+{
+       int ch = pProcessKeystroke(hConIn, ir, valid, numberpad, portdebug);
+       /* check for override */
+       if (ch && ch < MAX_OVERRIDES && key_overrides[ch])
+               ch = key_overrides[ch];
+       return ch;
+}
+
+int
+nttty_kbhit()
+{
+       return pNHkbhit(hConIn, &ir);
+}
+
+
+void
+get_scr_size()
+{
+       GetConsoleScreenBufferInfo(hConOut, &csbi);
+  
+       LI = csbi.srWindow.Bottom - (csbi.srWindow.Top + 1);
+       CO = csbi.srWindow.Right - (csbi.srWindow.Left + 1);
+
+       if ( (LI < 25) || (CO < 80) ) {
+               COORD newcoord;
+    
+               LI = 25;
+               CO = 80;
+
+               newcoord.Y = LI;
+               newcoord.X = CO;
+
+               SetConsoleScreenBufferSize( hConOut, newcoord );
+       }
+}
+
+int
+tgetch()
+{
+       int mod;
+       coord cc;
+       DWORD count;
+       really_move_cursor();
+       return pCheckInput(hConIn, &ir, &count, iflags.num_pad, 0, &mod, &cc);
+}
+
+int
+ntposkey(x, y, mod)
+int *x, *y, *mod;
+{
+       int ch;
+       coord cc;
+       DWORD count;
+       really_move_cursor();
+       ch = pCheckInput(hConIn, &ir, &count, iflags.num_pad, 1, mod, &cc);
+       if (!ch) {
+               *x = cc.x;
+               *y = cc.y;
+       }
+       return ch;
+}
+
+static void
+really_move_cursor()
+{
+#if defined(PORT_DEBUG) && defined(WIZARD)
+       char oldtitle[BUFSZ], newtitle[BUFSZ];
+       if (display_cursor_info && wizard) {
+               oldtitle[0] = '\0';
+               if (GetConsoleTitle(oldtitle, BUFSZ)) {
+                       oldtitle[39] = '\0';
+               }
+               Sprintf(newtitle, "%-55s tty=(%02d,%02d) nttty=(%02d,%02d)",
+                       oldtitle, ttyDisplay->curx, ttyDisplay->cury,
+                       cursor.X, cursor.Y);
+               (void)SetConsoleTitle(newtitle);
+       }
+#endif
+       if (ttyDisplay) {
+               cursor.X = ttyDisplay->curx;
+               cursor.Y = ttyDisplay->cury;
+       }
+       SetConsoleCursorPosition(hConOut, cursor);
+}
+
+void
+cmov(x, y)
+register int x, y;
+{
+       ttyDisplay->cury = y;
+       ttyDisplay->curx = x;
+       cursor.X = x;
+       cursor.Y = y;
+}
+
+void
+nocmov(x, y)
+int x,y;
+{
+       cursor.X = x;
+       cursor.Y = y;
+       ttyDisplay->curx = x;
+       ttyDisplay->cury = y;
+}
+
+void
+xputc_core(ch)
+char ch;
+{
+       switch(ch) {
+           case '\n':
+                       cursor.Y++;
+                       /* fall through */
+           case '\r':
+                       cursor.X = 1;
+                       break;
+           case '\b':
+                       cursor.X--;
+                       break;
+           default:
+                       WriteConsoleOutputAttribute(hConOut,&attr,1,
+                                                       cursor,&acount);
+                       WriteConsoleOutputCharacter(hConOut,&ch,1,
+                                                       cursor,&ccount);
+                       cursor.X++;
+       }
+}
+
+void
+xputc(ch)
+char ch;
+{
+       cursor.X = ttyDisplay->curx;
+       cursor.Y = ttyDisplay->cury;
+       xputc_core(ch);
+}
+
+void
+xputs(s)
+const char *s;
+{
+       int k;
+       int slen = strlen(s);
+
+       if (ttyDisplay) {
+               cursor.X = ttyDisplay->curx;
+               cursor.Y = ttyDisplay->cury;
+       }
+
+       if (s) {
+           for (k=0; k < slen && s[k]; ++k)
+               xputc_core(s[k]);
+       }
+}
+
+
+/*
+ * Overrides wintty.c function of the same name
+ * for win32. It is used for glyphs only, not text.
+ */
+void
+g_putch(in_ch)
+int in_ch;
+{
+       char ch = (char)in_ch;
+
+       cursor.X = ttyDisplay->curx;
+       cursor.Y = ttyDisplay->cury;
+       WriteConsoleOutputAttribute(hConOut,&attr,1,cursor,&acount);
+       WriteConsoleOutputCharacter(hConOut,&ch,1,cursor,&ccount);
+}
+
+void
+cl_end()
+{
+       int cx;
+       cursor.X = ttyDisplay->curx;
+       cursor.Y = ttyDisplay->cury;
+       cx = CO - cursor.X;
+       FillConsoleOutputAttribute(hConOut, DEFTEXTCOLOR, cx, cursor, &acount);
+       FillConsoleOutputCharacter(hConOut,' ', cx, cursor,&ccount);
+       tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1,
+                       (int)ttyDisplay->cury);
+}
+
+
+void
+clear_screen()
+{
+       if (GetConsoleScreenBufferInfo(hConOut,&csbi)) {
+           DWORD ccnt;
+           COORD newcoord;
+           
+           newcoord.X = 0;
+           newcoord.Y = 0;
+           FillConsoleOutputAttribute(hConOut,
+                       FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
+                       csbi.dwSize.X * csbi.dwSize.Y,
+                       newcoord, &ccnt);
+           FillConsoleOutputCharacter(hConOut,' ',
+                       csbi.dwSize.X * csbi.dwSize.Y,
+                       newcoord, &ccnt);
+       }
+       home();
+}
+
+
+void
+home()
+{
+       cursor.X = cursor.Y = 0;
+       ttyDisplay->curx = ttyDisplay->cury = 0;
+}
+
+
+void
+backsp()
+{
+       cursor.X = ttyDisplay->curx;
+       cursor.Y = ttyDisplay->cury;
+       xputc_core('\b');
+}
+
+void
+cl_eos()
+{
+       int cy = ttyDisplay->cury+1;
+       if (GetConsoleScreenBufferInfo(hConOut,&csbi)) {
+           DWORD ccnt;
+           COORD newcoord;
+           
+           newcoord.X = ttyDisplay->curx;
+           newcoord.Y = ttyDisplay->cury;
+           FillConsoleOutputAttribute(hConOut,
+                       FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
+                       csbi.dwSize.X * csbi.dwSize.Y - cy,
+                       newcoord, &ccnt);
+           FillConsoleOutputCharacter(hConOut,' ',
+                       csbi.dwSize.X * csbi.dwSize.Y - cy,
+                       newcoord, &ccnt);
+       }
+       tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1, (int)ttyDisplay->cury);
+}
+
+void
+tty_nhbell()
+{
+       if (flags.silent) return;
+       Beep(8000,500);
+}
+
+volatile int junk;     /* prevent optimizer from eliminating loop below */
+
+void
+tty_delay_output()
+{
+       /* delay 50 ms - uses ANSI C clock() function now */
+       clock_t goal;
+       int k;
+
+       goal = 50 + clock();
+       while (goal > clock()) {
+           k = junk;  /* Do nothing */
+       }
+}
+
+# ifdef TEXTCOLOR
+/*
+ * CLR_BLACK           0
+ * CLR_RED             1
+ * CLR_GREEN           2
+ * CLR_BROWN           3       low-intensity yellow
+ * CLR_BLUE            4
+ * CLR_MAGENTA                 5
+ * CLR_CYAN            6
+ * CLR_GRAY            7       low-intensity white
+ * NO_COLOR            8
+ * CLR_ORANGE          9
+ * CLR_BRIGHT_GREEN    10
+ * CLR_YELLOW          11
+ * CLR_BRIGHT_BLUE     12
+ * CLR_BRIGHT_MAGENTA          13
+ * CLR_BRIGHT_CYAN     14
+ * CLR_WHITE           15
+ * CLR_MAX             16
+ * BRIGHT              8
+ */
+
+static void
+init_ttycolor()
+{
+       ttycolors[CLR_BLACK] = FOREGROUND_INTENSITY;  /* fix by Quietust */
+       ttycolors[CLR_RED] = FOREGROUND_RED;
+       ttycolors[CLR_GREEN] = FOREGROUND_GREEN;
+       ttycolors[CLR_BROWN] = FOREGROUND_GREEN|FOREGROUND_RED;
+       ttycolors[CLR_BLUE] = FOREGROUND_BLUE;
+       ttycolors[CLR_MAGENTA] = FOREGROUND_BLUE|FOREGROUND_RED;
+       ttycolors[CLR_CYAN] = FOREGROUND_GREEN|FOREGROUND_BLUE;
+       ttycolors[CLR_GRAY] = FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_BLUE;
+       ttycolors[BRIGHT] = FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED|\
+                                               FOREGROUND_INTENSITY;
+       ttycolors[CLR_ORANGE] = FOREGROUND_RED|FOREGROUND_INTENSITY;
+       ttycolors[CLR_BRIGHT_GREEN] = FOREGROUND_GREEN|FOREGROUND_INTENSITY;
+       ttycolors[CLR_YELLOW] = FOREGROUND_GREEN|FOREGROUND_RED|\
+                                               FOREGROUND_INTENSITY;
+       ttycolors[CLR_BRIGHT_BLUE] = FOREGROUND_BLUE|FOREGROUND_INTENSITY;
+       ttycolors[CLR_BRIGHT_MAGENTA] = FOREGROUND_BLUE|FOREGROUND_RED|\
+                                               FOREGROUND_INTENSITY;
+       ttycolors[CLR_BRIGHT_CYAN] = FOREGROUND_GREEN|FOREGROUND_BLUE|\
+                                               FOREGROUND_INTENSITY;
+       ttycolors[CLR_WHITE] = FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED|\
+                                               FOREGROUND_INTENSITY;
+}
+# endif /* TEXTCOLOR */
+
+int
+has_color(int color)
+{
+# ifdef TEXTCOLOR
+    return 1;
+# else
+    if (color == CLR_BLACK)
+       return 1;
+    else if (color == CLR_WHITE)
+       return 1;
+    else
+       return 0;
+# endif 
+}
+
+void
+term_start_attr(int attrib)
+{
+    switch(attrib){
+        case ATR_INVERSE:
+               if (iflags.wc_inverse) {
+                  /* Suggestion by Lee Berger */
+                  if ((foreground & (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED)) ==
+                       (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED))
+                       foreground &= ~(FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED);
+                  background = (BACKGROUND_RED|BACKGROUND_BLUE|BACKGROUND_GREEN);
+                  break;
+               }
+               /*FALLTHRU*/
+        case ATR_ULINE:
+        case ATR_BLINK:
+        case ATR_BOLD:
+               foreground |= FOREGROUND_INTENSITY;
+                break;
+        default:
+               foreground &= ~FOREGROUND_INTENSITY;
+                break;
+    }
+    attr = (foreground | background);
+}
+
+void
+term_end_attr(int attrib)
+{
+    switch(attrib){
+
+        case ATR_INVERSE:
+               if ((foreground & (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED)) == 0)
+                    foreground |= (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED);
+               background = 0;
+               break;
+        case ATR_ULINE:
+        case ATR_BLINK:
+        case ATR_BOLD:
+               foreground &= ~FOREGROUND_INTENSITY;
+               break;
+    }                
+    attr = (foreground | background);
+}
+
+void
+term_end_raw_bold(void)
+{
+    term_end_attr(ATR_BOLD);
+}
+
+void
+term_start_raw_bold(void)
+{
+    term_start_attr(ATR_BOLD);
+}
+
+void
+term_start_color(int color)
+{
+#ifdef TEXTCOLOR
+        if (color >= 0 && color < CLR_MAX) {
+           foreground = (background != 0 && (color == CLR_GRAY || color == CLR_WHITE)) ?
+                       ttycolors[0] : ttycolors[color];
+       }
+#else
+       foreground = DEFTEXTCOLOR;
+#endif
+       attr = (foreground | background);
+}
+
+void
+term_end_color(void)
+{
+#ifdef TEXTCOLOR
+       foreground = DEFTEXTCOLOR;
+#endif
+       attr = (foreground | background);
+}
+
+
+void
+standoutbeg()
+{
+    term_start_attr(ATR_BOLD);
+}
+
+
+void
+standoutend()
+{
+    term_end_attr(ATR_BOLD);
+}
+
+#ifndef NO_MOUSE_ALLOWED
+void
+toggle_mouse_support()
+{
+        DWORD cmode;
+       GetConsoleMode(hConIn,&cmode);
+       if (iflags.wc_mouse_support)
+               cmode |= ENABLE_MOUSE_INPUT;
+       else
+               cmode &= ~ENABLE_MOUSE_INPUT;
+       SetConsoleMode(hConIn,cmode);
+}
+#endif
+
+/* handle tty options updates here */
+void nttty_preference_update(pref)
+const char *pref;
+{
+       if( stricmp( pref, "mouse_support")==0) {
+#ifndef NO_MOUSE_ALLOWED
+               toggle_mouse_support();
+#endif
+       }
+       return;
+}
+
+#ifdef PORT_DEBUG
+void
+win32con_debug_keystrokes()
+{
+       DWORD count;
+       boolean valid = 0;
+       int ch;
+       xputs("\n");
+       while (!valid || ch != 27) {
+          nocmov(ttyDisplay->curx, ttyDisplay->cury);
+          ReadConsoleInput(hConIn,&ir,1,&count);
+          if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown)
+               ch = process_keystroke(&ir, &valid, iflags.num_pad, 1);
+       }
+       (void)doredraw();
+}
+void
+win32con_handler_info()
+{
+       char *buf;
+       int ci;
+       if (!pSourceAuthor && !pSourceWhere)
+           pline("Keyboard handler source info and author unavailable.");
+       else {
+               if (pKeyHandlerName && pKeyHandlerName(&buf, 1)) {
+                       xputs("\n");
+                       xputs("Keystroke handler loaded: \n    ");
+                       xputs(buf);
+               }
+               if (pSourceAuthor && pSourceAuthor(&buf)) {
+                       xputs("\n");
+                       xputs("Keystroke handler Author: \n    ");
+                       xputs(buf);
+               }
+               if (pSourceWhere && pSourceWhere(&buf)) {
+                       xputs("\n");
+                       xputs("Keystroke handler source code available at:\n    ");
+                       xputs(buf);
+               }
+               xputs("\nPress any key to resume.");
+               ci=nhgetch();
+               (void)doredraw();
+       }
+}
+
+void win32con_toggle_cursor_info()
+{
+       display_cursor_info = !display_cursor_info;
+}
+#endif
+
+void
+map_subkeyvalue(op)
+register char *op;
+{
+       char digits[] = "0123456789";
+       int length, i, idx, val;
+       char *kp;
+
+       idx = -1;
+       val = -1;
+       kp = index(op, '/');
+       if (kp) {
+               *kp = '\0';
+               kp++;
+               length = strlen(kp);
+               if (length < 1 || length > 3) return;
+               for (i = 0; i < length; i++)
+                       if (!index(digits, kp[i])) return;
+               val = atoi(kp);
+               length = strlen(op);
+               if (length < 1 || length > 3) return;
+               for (i = 0; i < length; i++)
+                       if (!index(digits, op[i])) return;
+               idx = atoi(op);
+       }
+       if (idx >= MAX_OVERRIDES || idx < 0 || val >= MAX_OVERRIDES || val < 1)
+               return;
+       key_overrides[idx] = val;
+}
+
+void
+load_keyboard_handler()
+{
+       char suffx[] = ".dll";
+       char *truncspot;
+#define MAX_DLLNAME 25
+       char kh[MAX_ALTKEYHANDLER];
+       if (iflags.altkeyhandler[0]) {
+               if (hLibrary) { /* already one loaded apparently */
+                       FreeLibrary(hLibrary);
+                       hLibrary = (HANDLE)0;
+                  pNHkbhit = (NHKBHIT)0;
+                  pCheckInput = (CHECKINPUT)0; 
+                  pSourceWhere = (SOURCEWHERE)0; 
+                  pSourceAuthor = (SOURCEAUTHOR)0; 
+                  pKeyHandlerName = (KEYHANDLERNAME)0; 
+                  pProcessKeystroke = (PROCESS_KEYSTROKE)0;
+               }
+               if ((truncspot = strstri(iflags.altkeyhandler, suffx)) != 0)
+                       *truncspot = '\0';
+               (void) strncpy(kh, iflags.altkeyhandler,
+                               (MAX_ALTKEYHANDLER - sizeof suffx) - 1);
+               kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0';
+               Strcat(kh, suffx);
+               Strcpy(iflags.altkeyhandler, kh);
+               hLibrary = LoadLibrary(kh);
+               if (hLibrary) {
+                  pProcessKeystroke =
+                  (PROCESS_KEYSTROKE) GetProcAddress (hLibrary, TEXT ("ProcessKeystroke"));
+                  pNHkbhit =
+                  (NHKBHIT) GetProcAddress (hLibrary, TEXT ("NHkbhit"));
+                  pCheckInput =
+                  (CHECKINPUT) GetProcAddress (hLibrary, TEXT ("CheckInput"));
+                  pSourceWhere =
+                  (SOURCEWHERE) GetProcAddress (hLibrary, TEXT ("SourceWhere"));
+                  pSourceAuthor =
+                  (SOURCEAUTHOR) GetProcAddress (hLibrary, TEXT ("SourceAuthor"));
+                  pKeyHandlerName =
+                  (KEYHANDLERNAME) GetProcAddress (hLibrary, TEXT ("KeyHandlerName"));
+               }
+       }
+       if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) {
+               if (hLibrary) {
+                       FreeLibrary(hLibrary);
+                       hLibrary = (HANDLE)0;
+                       pNHkbhit = (NHKBHIT)0; 
+                       pCheckInput = (CHECKINPUT)0; 
+                       pSourceWhere = (SOURCEWHERE)0; 
+                       pSourceAuthor = (SOURCEAUTHOR)0; 
+                       pKeyHandlerName = (KEYHANDLERNAME)0; 
+                       pProcessKeystroke = (PROCESS_KEYSTROKE)0;
+               }
+               (void)strncpy(kh, "nhdefkey.dll", (MAX_ALTKEYHANDLER - sizeof suffx) - 1);
+               kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0';
+               Strcpy(iflags.altkeyhandler, kh);
+               hLibrary = LoadLibrary(kh);
+               if (hLibrary) {
+                  pProcessKeystroke =
+                  (PROCESS_KEYSTROKE) GetProcAddress (hLibrary, TEXT ("ProcessKeystroke"));
+                  pCheckInput =
+                  (CHECKINPUT) GetProcAddress (hLibrary, TEXT ("CheckInput"));
+                  pNHkbhit =
+                  (NHKBHIT) GetProcAddress (hLibrary, TEXT ("NHkbhit"));
+                  pSourceWhere =
+                  (SOURCEWHERE) GetProcAddress (hLibrary, TEXT ("SourceWhere"));
+                  pSourceAuthor =
+                  (SOURCEAUTHOR) GetProcAddress (hLibrary, TEXT ("SourceAuthor"));
+                  pKeyHandlerName =
+                  (KEYHANDLERNAME) GetProcAddress (hLibrary, TEXT ("KeyHandlerName"));
+               }
+       }
+       if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) {
+               if (!hLibrary)
+                       raw_printf("\nNetHack was unable to load keystroke handler.\n");
+               else {
+                       FreeLibrary(hLibrary);
+                       hLibrary = (HANDLE)0;
+                       raw_printf("\nNetHack keystroke handler is invalid.\n");
+               }
+               exit(EXIT_FAILURE);
+       }
+}
+
+/* this is used as a printf() replacement when the window
+ * system isn't initialized yet
+ */
+void
+msmsg VA_DECL(const char *, fmt)
+       char buf[ROWNO * COLNO];        /* worst case scenario */
+       VA_START(fmt);
+       VA_INIT(fmt, const char *);
+       Vsprintf(buf, fmt, VA_ARGS);
+       VA_END();
+       xputs(buf);
+       if (ttyDisplay) curs(BASE_WINDOW, cursor.X+1, cursor.Y);
+       return;
+}
+
+/* fatal error */
+/*VARARGS1*/
+void
+error VA_DECL(const char *,s)
+       char buf[BUFSZ];
+       VA_START(s);
+       VA_INIT(s, const char *);
+       /* error() may get called before tty is initialized */
+       if (iflags.window_inited) end_screen();
+       buf[0] = '\n';
+       (void) vsprintf(&buf[1], s, VA_ARGS);
+       VA_END();
+       msmsg(buf);
+       really_move_cursor();
+       exit(EXIT_FAILURE);
+}
+
+void
+synch_cursor()
+{
+       really_move_cursor();
+}
+#endif /* WIN32CON */
diff --git a/sys/winnt/porthelp b/sys/winnt/porthelp
new file mode 100644 (file)
index 0000000..0aa3e90
--- /dev/null
@@ -0,0 +1,300 @@
+        Microsoft Windows specific help file for NetHack 3.4.3
+        Copyright (c) NetHack PC Development Team 1993-2002.
+        NetHack may be freely distributed.  See license for details.
+                   (Last Revision: October 14, 2003)
+
+This file details specifics for NetHack built for Windows 95, 98, NT, 
+Me, 2000, and XP. Users of really early 16-bit Windows versions should 
+use the MSDOS NetHack. 
+
+Please note that "NetHack for Windows - Graphical Interface" requires 
+an installation of Internet Explorer 4 or an installation of 
+version 4.71 of the common controls. See the following internet page: 
+    http://www.nethack.org/v340/ports/download-win.html#cc
+for more information. If the game runs for you, you are not affected.
+
+New players should be sure to read GuideBook.txt which contains 
+essential information about playing NetHack. It can be found in the
+same directory as your NetHack executable.
+
+The NetHack for Windows port supports some additional or enhanced 
+commands as well as some defaults.nh file options specific to 
+configuration choices used during the building of NetHack for 
+Windows. Listed below are those commands and defaults.nh file 
+options. 
+
+Some options are applicable only to the "Graphical Interface." 
+These are discussed separately in their own section. 
+
+Contents
+1. ALT Key Combinations
+2. Boolean options - Option that you can toggle on or off
+3. Graphical Interface - Options you can assign a value to
+4. Graphical Interface - Additional/Enhanced Commands
+5. Graphical Interface - Menus
+6. Numeric Keypad (for number_pad mode)
+
+
+1. ALT Key Combinations
+----------------------------------------------
+The non-graphical (tty) interface always operates in "NetHack mode",
+while the "NetHack for Windows - Graphical Interface" lets you
+toggle the mode.  In non-NetHack mode, all ALT-key combinations
+are sent to the Windows itself, rather than to NetHack.
+
+While playing in NetHack mode you can press the ALT key in 
+combination with another key to execute an extended command
+as an alternative method to pressing a # key sequence.
+The available commands are:
+
+    Alt-2    #twoweapon      - toggle two-weapon combat (unavailable
+                               if number_pad mode is set)
+    Alt-a    #adjust         - adjust inventory letters.
+    Alt-c    #chat           - talk to someone or something.
+    Alt-d    #dip            - dip an object into something.
+    Alt-e    #enhance        - enhance your skill with a weapon.
+    Alt-f    #force          - force a lock.
+    Alt-i    #invoke         - invoke an object's powers.
+    Alt-j    #jump           - jump to a location.
+    Alt-l    #loot           - loot a box on the floor.
+    Alt-m    #monster        - use a monster's special ability. 
+    Alt-n    #name           - name an item or type of object.
+    Alt-o    #offer          - offer a sacrifice to the gods.
+    Alt-p    #pray           - pray to the gods for help.
+    Alt-q    #quit           - quit the game. (Same as #quit)
+    Alt-r    #rub            - rub a lamp.
+    Alt-s    #sit            - sit down.
+    Alt-t    #turn           - turn undead.
+    Alt-u    #untrap         - untrap something.
+    Alt-v    #version        - list compile time options for this version of
+                               NetHack.
+    Alt-w    #wipe           - wipe off your face.
+    Alt-?    #?              - display list of extended menu commands
+
+2. Boolean Options (Options that can be toggled on or off)
+----------------------------------------------------------
+
+Listed here are any options not discussed in the main help, options 
+which may be slightly different from the main help file, and options 
+which may need a slightly more explanatory note: 
+
+    color          Use color when displaying non-tiled maps. Tiled 
+                   maps (available in the graphical port) are always 
+                   rendered in color. Default: [TRUE]
+
+    hilite_pet     Using tiled graphics, displays a small heart symbol
+                   next to your pet.  Using ascii graphics, the pet is
+                   hilited in a white background.
+                   Default: [TRUE]
+
+    IBMgraphics    Use IBM extended characters for the dungeon 
+                   Default: [TRUE] 
+    msg_window     When ^P is pressed, it shows menu in a full window.
+                   Available only in the non-graphical (tty) version.
+                   Default: [FALSE] 
+
+    toptenwin      Write top ten list to a window, as opposed to stdout.
+                   Default in tty interface: [FALSE]
+                  Default in graphical interface: [TRUE] (and cannot be changed)
+
+3. Options that you assign a value to (Graphical Interface only)
+----------------------------------------------------------------
+
+"NetHack for Windows - Graphical Interface" recognizes the following 
+additional options, which the non-graphical (tty) version will
+silently ignore.  These are options that specify attributes of various
+windows.  The windows that you can tailor include menu windows (such 
+as the inventory list), text windows (such as "It is written in the 
+book of ..." screens), the message window (where events of the game are
+displayed), the status window (where your character name
+and attributes are displayed), and the map window (where the map
+is drawn).
+
+Window Alignment options:
+
+    align_message  Specifies at which side of the NetHack screen the 
+                   message window is aligned. This option can be used 
+                   to align the window to "top" or "bottom".
+                   Default: [TOP] 
+
+    align_status   Specifies at which side of the NetHack screen the 
+                   status window is aligned. This option can be used
+                   to align the window to "top" or "bottom".
+                   Default: [BOTTOM] 
+
+Map Window options:
+
+    map_mode       Specifies which map mode to use. 
+                   The following map modes are available: 
+                   tiles (display things on the map with colored tiles), 
+                   ascii4x6, ascii6x8, ascii8x8, ascii16x8, ascii7x12,
+                   ascii8x12, ascii16x12, ascii12x16, ascii10x18
+                   (which use that size font to display things on 
+                   the map), or fit_to_screen (an ascii mode which
+                   forces things to fit on a single screen).
+                   Default: [tiles]
+
+    scroll_margin  Specifies the number of map cells from the edge
+                   of the map window where scrolling will take place.
+                   Default: [5] 
+
+    tile_file      An alternative file containing bitmap to use for 
+                   tiles. This file should be a .bmp file and should 
+                   be organized as 40 rectangular tiles wide. It is 
+                   beyond the scope of this document to describe the 
+                   exact contents of each tile in the .bmp, which must
+                   match the object lists used when building NetHack.
+
+    tile_height    Used with tile_file to specify the height of each 
+                   tile in pixels. This option may only be specified
+                   in the defaults.nh config file.
+                   Default: [16] 
+
+    tile_width     Used with tile_file to specify the width of each 
+                   tile in pixels. This option may only be specified
+                   in the defaults.nh config file. 
+                   Default: [16]
+
+Other Window options:
+
+    windowcolors   Specifies the colors for various windows
+                   This option may only be specified in the
+                   defaults.nh config file and has the following
+                   format:
+                       window-type foreground/background
+                   Notes:
+                      - Both foreground and background colors are
+                        required, and a slash must separate them.
+                      - "window-type" is either "message" or "status"
+                        (Short forms are: "msg" or "sts").
+                      - "foreground" and "background" may be specified as
+                        a color name (such as "blue"), or by a six
+                        digit hexadecimal RGB color value (such as
+                        "#8F8F8F")
+                      - The following color names are available:
+                        black, red, green, brown, blue, magenta,
+                        cyan, gray (or grey), orange, brightgreen,
+                        yellow, brightblue, brightmagenta, brightcyan,
+                        white, trueblack, purple, silver, maroon, fuchsia,
+                        lime, olive, navy, teal, aqua. In addition, you 
+                        can use the following names to refer to default 
+                        Windows settings: activeborder, activecaption, 
+                        appworkspace, background, btnface, btnshadow, btntext, 
+                        captiontext, graytext, highlight, highlighttext, 
+                        inactiveborder, inactivecaption, menu, menutext, 
+                        scrollbar, window, windowframe, windowtext.
+
+                        Example:
+                        OPTIONS=windowcolors:sts #00FF80/blue msg menutext/menu
+
+    font_menu      Specifies the name of the menu font.
+    font_message   Specifies the name of the message font.
+    font_status    Specifies the name of the status font.
+    font_text      Specifies the name of the text font.
+
+    font_size_menu Specifies the size of the menu font.
+
+    font_size_message
+                   Specifies the size of the message font.
+
+    font_size_status
+                   Specifies the size of the status font.
+
+    font_size_text Specifies the size of the text font.
+
+Miscellaneous options: 
+
+    vary_msgcount  Number of lines to display in message window. 
+
+
+4. NetHack for Windows - Graphical Interface, Additional/Enhanced Commands
+-------------------------------------------------------------------------
+
+The following function keys are active in
+the "NetHack for Windows - Graphical Interface": 
+
+    F4             Toggle level overview mode on/off 
+                   This key will toggle the map between a view that 
+                   is mapped to fit exactly to the window, and the 
+                   view that shows the various symbols in their 
+                   normal size. This is useful for getting an idea 
+                   of where you are in a level. 
+
+    F5             Toggle tiled display on/off. 
+                   This key switches between the tiled and the 
+                   traditional ASCII display. This is equivalent to 
+                   using the "map_mode" option. 
+
+    F10            Activate menu bar. 
+                   This key will activate the menu bar, allowing you 
+                   to select between the menus: File, Map, 
+                   Window Settings, and Help. 
+
+5. Graphical Port Menus
+-----------------------
+
+File
+  Save - Allows you to save and exit the game
+  Quit - Allows you to quit the game
+
+Map - Provides for selection of map mode. Equivalent to using 
+the map_mode option. 
+
+Window Settings - Changes your logged-on user's settings for NetHack.
+In 3.4.3, only one setting is available: NetHack mode, which can be
+checked or unchecked. NetHack mode allows you to use the ALT key for
+game key commands [see list above]. You can use F10 to access the
+menu bar while in NetHack mode. You can also clear your logged-on
+user's settings for NetHack. Settings in this window are saved in
+your logged-on user's registry. 
+
+Help - Provides help about various portions of NetHack.
+
+
+6. Numeric Keypad (for "OPTION=number_pad" mode)
+------------------------------------------------
+
+The numeric keypad and surrounding characters act as macros for different
+commands in NetHack.  The Num Lock should be toggled to "on" to make the
+most of these keys:
+
+          Key         Normal       Shift-Key
+       ----------   ----------    -------------
+       1, 2, 3, 4   Move In       Run In
+       6, 7, 8, 9   Direction     Direction
+
+        0 (Ins)     Inventory     Categorized
+                                  Inventory
+
+        . (Del)     Wait Turn     : - Look Here
+
+        +           Spell List    P - Put on an
+                                  accessory
+
+        -           m - Move      Previous
+                    Only          Message
+
+    NetHack for Windows - tty Interface Specific Behavior:
+    ------------------------------------------------------
+
+      In the non-graphical (tty) interface, when you use the Ctrl key with a
+      directional key (1, 2, 3, 4, 6, 7, 8, 9) it means "go in specified
+      direction until you hit a wall or run into something interesting."
+
+    NetHack for Windows - Graphical Interface Specific Behavior:
+    ------------------------------------------------------------
+
+      It is possible to scroll or pan the map in a specific direction:
+
+        Ctrl-Shift-Left  (4)     Scroll (Pan) map left
+        Ctrl-Shift-Right (6)     Scroll (Pan) map right
+        Ctrl-Shift-Up    (8)     Scroll (Pan) map up
+        Ctrl-Shift-Down  (2)     Scroll (Pan) map down
+        Ctrl-Shift-Home  (7)     Scroll (Pan) map left to leftmost corner
+        Ctrl-Shift-End   (1)     Scroll (Pan) map left to rightmost corner
+        Ctrl-Shift-PgUp  (9)     Scroll (Pan) map left to uppermost corner
+        Ctrl-Shift-PgDn  (3)     Scroll (Pan) map left to lowermost corner
+
+
+
diff --git a/sys/winnt/win32api.h b/sys/winnt/win32api.h
new file mode 100644 (file)
index 0000000..8c684b5
--- /dev/null
@@ -0,0 +1,27 @@
+/*     SCCS Id: @(#)win32api.h  3.4     $Date: 2002/07/24 08:25:21 $             */
+/* Copyright (c) NetHack PC Development Team 1996                 */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This header file is used to clear up some discrepencies with Visual C
+ * header files & NetHack before including windows.h, so all NetHack
+ * files should include "win32api.h" rather than <windows.h>.
+ */
+# if defined(_MSC_VER)
+# undef strcmpi
+# undef min
+# undef max
+# pragma warning(disable:4142)  /* Warning, Benign redefinition of type */
+# pragma pack(8)
+# endif
+
+#define WIN32_LEAN_AND_MEAN
+
+#include <windows.h>
+#include <commctrl.h>
+
+# if defined(_MSC_VER)
+# pragma pack()
+# endif
+
+/*win32api.h*/
diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c
new file mode 100644 (file)
index 0000000..768cb8a
--- /dev/null
@@ -0,0 +1,324 @@
+/*     SCCS Id: @(#)winnt.c     3.4     $Date: 2003/10/26 15:58:22 $             */
+/* Copyright (c) NetHack PC Development Team 1993, 1994 */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *  WIN32 system functions.
+ *
+ *  Initial Creation: Michael Allison - January 31/93
+ *
+ */
+
+#define NEED_VARARGS
+#include "hack.h"
+#include <dos.h>
+#ifndef __BORLANDC__
+#include <direct.h>
+#endif
+#include <ctype.h>
+#include "win32api.h"
+#ifdef WIN32CON
+#include "wintty.h"
+#endif
+#ifdef WIN32
+
+
+/*
+ * The following WIN32 API routines are used in this file.
+ *
+ * GetDiskFreeSpace
+ * GetVolumeInformation
+ * GetUserName
+ * FindFirstFile
+ * FindNextFile
+ * FindClose
+ *
+ */
+
+
+/* globals required within here */
+HANDLE ffhandle = (HANDLE)0;
+WIN32_FIND_DATA ffd;
+
+/* The function pointer nt_kbhit contains a kbhit() equivalent
+ * which varies depending on which window port is active.
+ * For the tty port it is tty_kbhit() [from nttty.c]
+ * For the win32 port it is win32_kbhit() [from winmain.c]
+ * It is initialized to point to def_kbhit [in here] for safety.
+ */
+
+int def_kbhit(void);
+int (*nt_kbhit)() = def_kbhit;
+
+char
+switchar()
+{
+ /* Could not locate a WIN32 API call for this- MJA */
+       return '-';
+}
+
+long
+freediskspace(path)
+char *path;
+{
+       char tmppath[4];
+       DWORD SectorsPerCluster = 0;
+       DWORD BytesPerSector = 0;
+       DWORD FreeClusters = 0;
+       DWORD TotalClusters = 0;
+
+       tmppath[0] = *path;
+       tmppath[1] = ':';
+       tmppath[2] = '\\';
+       tmppath[3] = '\0';
+       GetDiskFreeSpace(tmppath, &SectorsPerCluster,
+                       &BytesPerSector,
+                       &FreeClusters,
+                       &TotalClusters);
+       return (long)(SectorsPerCluster * BytesPerSector *
+                       FreeClusters);
+}
+
+/*
+ * Functions to get filenames using wildcards
+ */
+int
+findfirst(path)
+char *path;
+{
+       if (ffhandle){
+                FindClose(ffhandle);
+                ffhandle = (HANDLE)0;
+       }
+       ffhandle = FindFirstFile(path,&ffd);
+       return 
+         (ffhandle == INVALID_HANDLE_VALUE) ? 0 : 1;
+}
+
+int
+findnext() 
+{
+       return FindNextFile(ffhandle,&ffd) ? 1 : 0;
+}
+
+char *
+foundfile_buffer()
+{
+       return &ffd.cFileName[0];
+}
+
+long
+filesize(file)
+char *file;
+{
+       if (findfirst(file)) {
+               return ((long)ffd.nFileSizeLow);
+       } else
+               return -1L;
+}
+
+/*
+ * Chdrive() changes the default drive.
+ */
+void
+chdrive(str)
+char *str;
+{
+       char *ptr;
+       char drive;
+       if ((ptr = index(str, ':')) != (char *)0) 
+       {
+               drive = toupper(*(ptr - 1));
+               _chdrive((drive - 'A') + 1);
+       }
+}
+
+static int
+max_filename()
+{
+       DWORD maxflen;
+       int status=0;
+       
+       status = GetVolumeInformation((LPTSTR)0,(LPTSTR)0, 0
+                       ,(LPDWORD)0,&maxflen,(LPDWORD)0,(LPTSTR)0,0);
+       if (status) return maxflen;
+       else return 0;
+}
+
+int
+def_kbhit()
+{
+       return 0;
+}
+
+/* 
+ * Strip out troublesome file system characters.
+ */
+
+void
+nt_regularize(s)       /* normalize file name */
+register char *s;
+{
+       register unsigned char *lp;
+
+       for (lp = s; *lp; lp++)
+           if ( *lp == '?' || *lp == '"' || *lp == '\\' ||
+                *lp == '/' || *lp == '>' || *lp == '<'  ||
+                *lp == '*' || *lp == '|' || *lp == ':'  || (*lp > 127))
+                       *lp = '_';
+}
+
+/*
+ * This is used in nhlan.c to implement some of the LAN_FEATURES.
+ */
+char *get_username(lan_username_size)
+int *lan_username_size;
+{
+       static TCHAR username_buffer[BUFSZ];
+       unsigned int status;
+       DWORD i = BUFSZ - 1;
+
+       /* i gets updated with actual size */
+       status = GetUserName(username_buffer, &i);              
+       if (status) username_buffer[i] = '\0';
+       else Strcpy(username_buffer, "NetHack");
+       if (lan_username_size) *lan_username_size = strlen(username_buffer);
+       return username_buffer;
+}
+
+# if 0
+char *getxxx()
+{
+char     szFullPath[MAX_PATH] = "";
+HMODULE  hInst = NULL;         /* NULL gets the filename of this module */
+
+GetModuleFileName(hInst, szFullPath, sizeof(szFullPath));
+return &szFullPath[0];
+}
+# endif
+
+#ifndef WIN32CON
+/* fatal error */
+/*VARARGS1*/
+void
+error VA_DECL(const char *,s)
+       char buf[BUFSZ];
+       VA_START(s);
+       VA_INIT(s, const char *);
+       /* error() may get called before tty is initialized */
+       if (iflags.window_inited) end_screen();
+       if (!strncmpi(windowprocs.name, "tty", 3)) {
+               buf[0] = '\n';
+               (void) vsprintf(&buf[1], s, VA_ARGS);
+               Strcat(buf, "\n");
+               msmsg(buf);
+       } else {
+               (void) vsprintf(buf, s, VA_ARGS);
+               Strcat(buf, "\n");
+               raw_printf(buf);
+       }
+       VA_END();
+       exit(EXIT_FAILURE);
+}
+#endif
+
+void Delay(int ms)
+{
+       (void)Sleep(ms);
+}
+
+#ifdef WIN32CON
+extern void NDECL(backsp);
+#endif
+
+void win32_abort()
+{
+#ifdef WIZARD
+       if (wizard) {
+# ifdef WIN32CON
+           int c, ci, ct;
+
+           if (!iflags.window_inited)
+               c = 'n';
+               ct = 0;
+               msmsg("Execute debug breakpoint wizard?");
+               while ((ci=nhgetch()) != '\n') {
+                   if (ct > 0) {
+                       backsp();       /* \b is visible on NT */
+                       (void) putchar(' ');
+                       backsp();
+                       ct = 0;
+                       c = 'n';
+                   }
+                   if (ci == 'y' || ci == 'n' || ci == 'Y' || ci == 'N') {
+                       ct = 1;
+                       c = ci;
+                       msmsg("%c",c);
+                   }
+               }
+               if (c == 'y')
+                       DebugBreak();
+# endif
+       }
+#endif
+       abort();
+}
+
+static char interjection_buf[INTERJECTION_TYPES][1024];
+static int interjection[INTERJECTION_TYPES];
+
+void
+interject_assistance(num, interjection_type, ptr1, ptr2)
+int num;
+int interjection_type;
+genericptr_t ptr1;
+genericptr_t ptr2;
+{
+       switch(num) {
+           case 1: {
+               char *panicmsg = (char *)ptr1;
+               char *datadir =  (char *)ptr2;
+               char *tempdir = nh_getenv("TEMP");
+               interjection_type = INTERJECT_PANIC;
+               interjection[INTERJECT_PANIC] = 1;
+               /*
+                * ptr1 = the panic message about to be delivered.
+                * ptr2 = the directory prefix of the dungeon file
+                *        that failed to open.
+                * Check to see if datadir matches tempdir or a
+                * common windows temp location. If it does, inform
+                * the user that they are probably trying to run the
+                * game from within their unzip utility, so the required
+                * files really don't exist at the location. Instruct
+                * them to unpack them first.
+                */
+               if (panicmsg && datadir) {
+                   if (!strncmpi(datadir, "C:\\WINDOWS\\TEMP", 15) ||
+                           strstri(datadir, "TEMP")   ||
+                           (tempdir && strstri(datadir, tempdir))) {
+                       (void)strncpy(interjection_buf[INTERJECT_PANIC],
+                       "\nOne common cause of this error is attempting to execute\n"
+                       "the game by double-clicking on it while it is displayed\n"
+                       "inside an unzip utility.\n\n"
+                       "You have to unzip the contents of the zip file into a\n"
+                       "folder on your system, and then run \"NetHack.exe\" or \n"
+                       "\"NetHackW.exe\" from there.\n\n"
+                       "If that is not the situation, you are encouraged to\n"
+                       "report the error as shown above.\n\n", 1023);
+                   }
+               }
+           }
+           break;
+       }
+}
+
+void
+interject(interjection_type)
+int interjection_type;
+{
+       if (interjection_type >= 0 && interjection_type < INTERJECTION_TYPES)
+               msmsg(interjection_buf[interjection_type]);
+}
+#endif /* WIN32 */
+
+/*winnt.c*/
diff --git a/util/dgn_comp.l b/util/dgn_comp.l
new file mode 100644 (file)
index 0000000..110b51a
--- /dev/null
@@ -0,0 +1,137 @@
+%{
+/*     SCCS Id: @(#)dgn_lex.c  3.4     2002/03/27      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet */
+/*     Copyright (c) 1990 by M. Stephenson          */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#define DGN_COMP
+
+#include "config.h"
+#include "dgn_comp.h"
+#include "dgn_file.h"
+
+/*
+ * Most of these don't exist in flex, yywrap is macro and
+ * yyunput is properly declared in flex.skel.
+ */
+#if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER)
+int FDECL(yyback, (int *,int));
+int NDECL(yylook);
+int NDECL(yyinput);
+int NDECL(yywrap);
+int NDECL(yylex);
+       /* Traditional lexes let yyunput() and yyoutput() default to int;
+        * newer ones may declare them as void since they don't return
+        * values.  For even more fun, the lex supplied as part of the
+        * newer unbundled compiler for SunOS 4.x adds the void declarations
+        * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain
+        * int) while the bundled lex and the one with the older unbundled
+        * compiler do not.  To detect this, we need help from outside --
+        * sys/unix/Makefile.utl.
+        *
+        * Digital UNIX is difficult and still has int in spite of all
+        * other signs.
+        */
+# if defined(NeXT) || defined(SVR4) || defined(_AIX32)
+#  define VOIDYYPUT
+# endif
+# if !defined(VOIDYYPUT) && defined(POSIX_TYPES)
+#  if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS)
+#   define VOIDYYPUT
+#  endif
+# endif
+# if !defined(VOIDYYPUT) && defined(WEIRD_LEX)
+#  if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1)
+#   define VOIDYYPUT
+#  endif
+# endif
+# if defined(VOIDYYPUT) && defined(__osf__)
+#  undef VOIDYYPUT
+# endif
+# ifdef VOIDYYPUT
+void FDECL(yyunput, (int));
+void FDECL(yyoutput, (int));
+# else
+int FDECL(yyunput, (int));
+int FDECL(yyoutput, (int));
+# endif
+#endif /* !FLEX_SCANNER && !FLEXHACK_SCANNER */
+
+#ifdef FLEX_SCANNER
+#define YY_MALLOC_DECL \
+              genericptr_t FDECL(malloc, (size_t)); \
+              genericptr_t FDECL(realloc, (genericptr_t,size_t));
+#endif
+
+
+void FDECL(init_yyin, (FILE *));
+void FDECL(init_yyout, (FILE *));
+
+/* this doesn't always get put in dgn_comp.h
+ * (esp. when using older versions of bison)
+ */
+
+extern YYSTYPE yylval;
+
+int line_number = 1;
+
+%}
+%%
+DUNGEON                return(A_DUNGEON);
+up             { yylval.i=1; return(UP_OR_DOWN); }
+down           { yylval.i=0; return(UP_OR_DOWN); }
+ENTRY          return(ENTRY);
+stair          return(STAIR);
+no_up          return(NO_UP);
+no_down                return(NO_DOWN);
+portal         return(PORTAL);
+PROTOFILE      return(PROTOFILE);
+DESCRIPTION    return(DESCRIPTION);
+LEVELDESC      return(LEVELDESC);
+ALIGNMENT       return(ALIGNMENT);
+LEVALIGN        return(LEVALIGN);
+town           { yylval.i=TOWN ; return(DESCRIPTOR); }
+hellish                { yylval.i=HELLISH ; return(DESCRIPTOR); }
+mazelike       { yylval.i=MAZELIKE ; return(DESCRIPTOR); }
+roguelike      { yylval.i=ROGUELIKE ; return(DESCRIPTOR); }
+unaligned       { yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); }
+noalign         { yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); }
+lawful          { yylval.i=D_ALIGN_LAWFUL ; return(DESCRIPTOR); }
+neutral         { yylval.i=D_ALIGN_NEUTRAL ; return(DESCRIPTOR); }
+chaotic         { yylval.i=D_ALIGN_CHAOTIC ; return(DESCRIPTOR); }
+BRANCH         return(BRANCH);
+CHAINBRANCH    return(CHBRANCH);
+LEVEL          return(LEVEL);
+RNDLEVEL       return(RNDLEVEL);
+CHAINLEVEL     return(CHLEVEL);
+RNDCHLEVEL     return(RNDCHLEVEL);
+[-0-9]+                { yylval.i=atoi(yytext); return(INTEGER); }
+\"[^"]*\"      { yytext[yyleng-1] = 0; /* Discard the trailing \" */
+                 yylval.str = (char *) alloc(strlen(yytext+1)+1);
+                 Strcpy(yylval.str, yytext+1); /* Discard the first \" */
+                 return(STRING); }
+^#.*\n         { line_number++; }
+\r?\n          { line_number++; }
+[ \t]+         ;       /* skip trailing tabs & spaces */
+.              { return yytext[0]; }
+%%
+
+/* routine to switch to another input file; needed for flex */
+void init_yyin( input_f )
+FILE *input_f;
+{
+#if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER)
+       if (yyin)
+           yyrestart(input_f);
+       else
+#endif
+           yyin = input_f;
+}
+/* analogous routine (for completeness) */
+void init_yyout( output_f )
+FILE *output_f;
+{
+       yyout = output_f;
+}
+
+/*dgn_comp.l*/
diff --git a/util/dgn_comp.y b/util/dgn_comp.y
new file mode 100644 (file)
index 0000000..9b355cb
--- /dev/null
@@ -0,0 +1,678 @@
+%{
+/*     SCCS Id: @(#)dgn_comp.c 3.4     1996/06/22      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet */
+/*     Copyright (c) 1990 by M. Stephenson                               */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file contains the Dungeon Compiler code
+ */
+
+/* In case we're using bison in AIX.  This definition must be
+ * placed before any other C-language construct in the file
+ * excluding comments and preprocessor directives (thanks IBM
+ * for this wonderful feature...).
+ *
+ * Note: some cpps barf on this 'undefined control' (#pragma).
+ * Addition of the leading space seems to prevent barfage for now,
+ * and AIX will still see the directive in its non-standard locale.
+ */
+
+#ifdef _AIX
+ #pragma alloca                /* keep leading space! */
+#endif
+
+#include "config.h"
+#include "date.h"
+#include "dgn_file.h"
+
+void FDECL(yyerror, (const char *));
+void FDECL(yywarning, (const char *));
+int NDECL(yylex);
+int NDECL(yyparse);
+int FDECL(getchain, (char *));
+int NDECL(check_dungeon);
+int NDECL(check_branch);
+int NDECL(check_level);
+void NDECL(init_dungeon);
+void NDECL(init_branch);
+void NDECL(init_level);
+void NDECL(output_dgn);
+
+#define Free(ptr)              free((genericptr_t)ptr)
+
+#ifdef AMIGA
+# undef        printf
+#ifndef        LATTICE
+# define    memset(addr,val,len)    setmem(addr,len,val)
+#endif
+#endif
+
+#define ERR            (-1)
+
+static struct couple couple;
+static struct tmpdungeon tmpdungeon[MAXDUNGEON];
+static struct tmplevel tmplevel[LEV_LIMIT];
+static struct tmpbranch tmpbranch[BRANCH_LIMIT];
+
+static int in_dungeon = 0, n_dgns = -1, n_levs = -1, n_brs = -1;
+
+extern int fatal_error;
+extern const char *fname;
+extern FILE *yyin, *yyout;     /* from dgn_lex.c */
+
+%}
+
+%union
+{
+       int     i;
+       char*   str;
+}
+
+%token <i>     INTEGER
+%token <i>     A_DUNGEON BRANCH CHBRANCH LEVEL RNDLEVEL CHLEVEL RNDCHLEVEL
+%token <i>     UP_OR_DOWN PROTOFILE DESCRIPTION DESCRIPTOR LEVELDESC
+%token <i>     ALIGNMENT LEVALIGN ENTRY STAIR NO_UP NO_DOWN PORTAL
+%token <str>   STRING
+%type  <i>     optional_int direction branch_type bones_tag
+%start file
+
+%%
+file           : /* nothing */
+               | dungeons
+                 {
+                       output_dgn();
+                 }
+               ;
+
+dungeons       : dungeon
+               | dungeons dungeon
+               ;
+
+dungeon                : dungeonline
+               | dungeondesc
+               | branches
+               | levels
+               ;
+
+dungeonline    : A_DUNGEON ':' STRING bones_tag rcouple optional_int
+                 {
+                       init_dungeon();
+                       Strcpy(tmpdungeon[n_dgns].name, $3);
+                       tmpdungeon[n_dgns].boneschar = (char)$4;
+                       tmpdungeon[n_dgns].lev.base = couple.base;
+                       tmpdungeon[n_dgns].lev.rand = couple.rand;
+                       tmpdungeon[n_dgns].chance = $6;
+                       Free($3);
+                 }
+               ;
+
+optional_int   : /* nothing */
+                 {
+                       $$ = 0;
+                 }
+               | INTEGER
+                 {
+                       $$ = $1;
+                 }
+               ;
+
+dungeondesc    : entry
+               | descriptions
+               | prototype
+               ;
+
+entry          : ENTRY ':' INTEGER
+                 {
+                       tmpdungeon[n_dgns].entry_lev = $3;
+                 }
+               ;
+
+descriptions   : desc
+               ;
+
+desc           : DESCRIPTION ':' DESCRIPTOR
+                 {
+                       if($<i>3 <= TOWN || $<i>3 >= D_ALIGN_CHAOTIC)
+                           yyerror("Illegal description - ignoring!");
+                       else
+                           tmpdungeon[n_dgns].flags |= $<i>3 ;
+                 }
+               | ALIGNMENT ':' DESCRIPTOR
+                 {
+                       if($<i>3 && $<i>3 < D_ALIGN_CHAOTIC)
+                           yyerror("Illegal alignment - ignoring!");
+                       else
+                           tmpdungeon[n_dgns].flags |= $<i>3 ;
+                 }
+               ;
+
+prototype      : PROTOFILE ':' STRING
+                 {
+                       Strcpy(tmpdungeon[n_dgns].protoname, $3);
+                       Free($3);
+                 }
+               ;
+
+levels         : level1
+               | level2
+               | levdesc
+               | chlevel1
+               | chlevel2
+               ;
+
+level1         : LEVEL ':' STRING bones_tag '@' acouple
+                 {
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, $3);
+                       tmplevel[n_levs].boneschar = (char)$4;
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmpdungeon[n_dgns].levels++;
+                       Free($3);
+                 }
+               | RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER
+                 {
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, $3);
+                       tmplevel[n_levs].boneschar = (char)$4;
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmplevel[n_levs].rndlevs = $7;
+                       tmpdungeon[n_dgns].levels++;
+                       Free($3);
+                 }
+               ;
+
+level2         : LEVEL ':' STRING bones_tag '@' acouple INTEGER
+                 {
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, $3);
+                       tmplevel[n_levs].boneschar = (char)$4;
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmplevel[n_levs].chance = $7;
+                       tmpdungeon[n_dgns].levels++;
+                       Free($3);
+                 }
+               | RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER INTEGER
+                 {
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, $3);
+                       tmplevel[n_levs].boneschar = (char)$4;
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmplevel[n_levs].chance = $7;
+                       tmplevel[n_levs].rndlevs = $8;
+                       tmpdungeon[n_dgns].levels++;
+                       Free($3);
+                 }
+               ;
+
+levdesc                : LEVELDESC ':' DESCRIPTOR
+                 {
+                       if($<i>3 >= D_ALIGN_CHAOTIC)
+                           yyerror("Illegal description - ignoring!");
+                       else
+                           tmplevel[n_levs].flags |= $<i>3 ;
+                 }
+               | LEVALIGN ':' DESCRIPTOR
+                 {
+                       if($<i>3 && $<i>3 < D_ALIGN_CHAOTIC)
+                           yyerror("Illegal alignment - ignoring!");
+                       else
+                           tmplevel[n_levs].flags |= $<i>3 ;
+                 }
+               ;
+
+chlevel1       : CHLEVEL ':' STRING bones_tag STRING '+' rcouple
+                 {
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, $3);
+                       tmplevel[n_levs].boneschar = (char)$4;
+                       tmplevel[n_levs].chain = getchain($5);
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       if(!check_level()) n_levs--;
+                       else tmpdungeon[n_dgns].levels++;
+                       Free($3);
+                       Free($5);
+                 }
+               | RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER
+                 {
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, $3);
+                       tmplevel[n_levs].boneschar = (char)$4;
+                       tmplevel[n_levs].chain = getchain($5);
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmplevel[n_levs].rndlevs = $8;
+                       if(!check_level()) n_levs--;
+                       else tmpdungeon[n_dgns].levels++;
+                       Free($3);
+                       Free($5);
+                 }
+               ;
+
+chlevel2       : CHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER
+                 {
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, $3);
+                       tmplevel[n_levs].boneschar = (char)$4;
+                       tmplevel[n_levs].chain = getchain($5);
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmplevel[n_levs].chance = $8;
+                       if(!check_level()) n_levs--;
+                       else tmpdungeon[n_dgns].levels++;
+                       Free($3);
+                       Free($5);
+                 }
+               | RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER INTEGER
+                 {
+                       init_level();
+                       Strcpy(tmplevel[n_levs].name, $3);
+                       tmplevel[n_levs].boneschar = (char)$4;
+                       tmplevel[n_levs].chain = getchain($5);
+                       tmplevel[n_levs].lev.base = couple.base;
+                       tmplevel[n_levs].lev.rand = couple.rand;
+                       tmplevel[n_levs].chance = $8;
+                       tmplevel[n_levs].rndlevs = $9;
+                       if(!check_level()) n_levs--;
+                       else tmpdungeon[n_dgns].levels++;
+                       Free($3);
+                       Free($5);
+                 }
+               ;
+
+branches       : branch
+               | chbranch
+               ;
+
+branch         : BRANCH ':' STRING '@' acouple branch_type direction
+                 {
+                       init_branch();
+                       Strcpy(tmpbranch[n_brs].name, $3);
+                       tmpbranch[n_brs].lev.base = couple.base;
+                       tmpbranch[n_brs].lev.rand = couple.rand;
+                       tmpbranch[n_brs].type = $6;
+                       tmpbranch[n_brs].up = $7;
+                       if(!check_branch()) n_brs--;
+                       else tmpdungeon[n_dgns].branches++;
+                       Free($3);
+                 }
+               ;
+
+chbranch       : CHBRANCH ':' STRING STRING '+' rcouple branch_type direction
+                 {
+                       init_branch();
+                       Strcpy(tmpbranch[n_brs].name, $3);
+                       tmpbranch[n_brs].chain = getchain($4);
+                       tmpbranch[n_brs].lev.base = couple.base;
+                       tmpbranch[n_brs].lev.rand = couple.rand;
+                       tmpbranch[n_brs].type = $7;
+                       tmpbranch[n_brs].up = $8;
+                       if(!check_branch()) n_brs--;
+                       else tmpdungeon[n_dgns].branches++;
+                       Free($3);
+                       Free($4);
+                 }
+               ;
+
+branch_type    : /* nothing */
+                 {
+                       $$ = TBR_STAIR; /* two way stair */
+                 }
+               | STAIR
+                 {
+                       $$ = TBR_STAIR; /* two way stair */
+                 }
+               | NO_UP
+                 {
+                       $$ = TBR_NO_UP; /* no up staircase */
+                 }
+               | NO_DOWN
+                 {
+                       $$ = TBR_NO_DOWN;       /* no down staircase */
+                 }
+               | PORTAL
+                 {
+                       $$ = TBR_PORTAL;        /* portal connection */
+                 }
+               ;
+
+direction      : /* nothing */
+                 {
+                       $$ = 0; /* defaults to down */
+                 }
+               | UP_OR_DOWN
+                 {
+                       $$ = $1;
+                 }
+               ;
+
+bones_tag      : STRING
+                 {
+                       char *p = $1;
+                       if (strlen(p) != 1) {
+                           if (strcmp(p, "none") != 0)
+                  yyerror("Bones marker must be a single char, or \"none\"!");
+                           *p = '\0';
+                       }
+                       $$ = *p;
+                       Free(p);
+                 }
+               ;
+
+/*
+ *     acouple rules:
+ *
+ *     (base, range) where:
+ *
+ *         base is either a positive or negative integer with a value
+ *         less than or equal to MAXLEVEL.
+ *         base > 0 indicates the base level.
+ *         base < 0 indicates reverse index (-1 == lowest level)
+ *
+ *         range is the random component.
+ *         if range is zero, there is no random component.
+ *         if range is -1 the dungeon loader will randomize between
+ *         the base and the end of the dungeon.
+ *         during dungeon load, range is always *added* to the base,
+ *         therefore range + base(converted) must not exceed MAXLEVEL.
+ */
+acouple                : '(' INTEGER ',' INTEGER ')'
+                 {
+                       if ($2 < -MAXLEVEL || $2 > MAXLEVEL) {
+                           yyerror("Abs base out of dlevel range - zeroing!");
+                           couple.base = couple.rand = 0;
+                       } else if ($4 < -1 ||
+                               (($2 < 0) ? (MAXLEVEL + $2 + $4 + 1) > MAXLEVEL :
+                                       ($2 + $4) > MAXLEVEL)) {
+                           yyerror("Abs range out of dlevel range - zeroing!");
+                           couple.base = couple.rand = 0;
+                       } else {
+                           couple.base = $2;
+                           couple.rand = $4;
+                       }
+                 }
+               ;
+
+/*
+ *     rcouple rules:
+ *
+ *     (base, range) where:
+ *
+ *         base is either a positive or negative integer with a value
+ *         less than or equal to MAXLEVEL.
+ *         base > 0 indicates a forward index.
+ *         base < 0 indicates a reverse index.
+ *         base == 0 indicates on the parent level.
+ *
+ *         range is the random component.
+ *         if range is zero, there is no random component.
+ *         during dungeon load, range is always *added* to the base,
+ *         range + base(converted) may be very large.  The dungeon
+ *         loader will then correct to "between here and the top/bottom".
+ *
+ *         There is no practical way of specifying "between here and the
+ *         nth / nth last level".
+ */
+rcouple                : '(' INTEGER ',' INTEGER ')'
+                 {
+                       if ($2 < -MAXLEVEL || $2 > MAXLEVEL) {
+                           yyerror("Rel base out of dlevel range - zeroing!");
+                           couple.base = couple.rand = 0;
+                       } else {
+                           couple.base = $2;
+                           couple.rand = $4;
+                       }
+                 }
+               ;
+%%
+
+void
+init_dungeon()
+{
+       if(++n_dgns > MAXDUNGEON) {
+           (void) fprintf(stderr, "FATAL - Too many dungeons (limit: %d).\n",
+                   MAXDUNGEON);
+           (void) fprintf(stderr, "To increase the limit edit MAXDUNGEON in global.h\n");
+           exit(EXIT_FAILURE);
+       }
+
+       in_dungeon = 1;
+       tmpdungeon[n_dgns].lev.base = 0;
+       tmpdungeon[n_dgns].lev.rand = 0;
+       tmpdungeon[n_dgns].chance = 100;
+       Strcpy(tmpdungeon[n_dgns].name, "");
+       Strcpy(tmpdungeon[n_dgns].protoname, "");
+       tmpdungeon[n_dgns].flags = 0;
+       tmpdungeon[n_dgns].levels = 0;
+       tmpdungeon[n_dgns].branches = 0;
+       tmpdungeon[n_dgns].entry_lev = 0;
+}
+
+void
+init_level()
+{
+       if(++n_levs > LEV_LIMIT) {
+
+               yyerror("FATAL - Too many special levels defined.");
+               exit(EXIT_FAILURE);
+       }
+       tmplevel[n_levs].lev.base = 0;
+       tmplevel[n_levs].lev.rand = 0;
+       tmplevel[n_levs].chance = 100;
+       tmplevel[n_levs].rndlevs = 0;
+       tmplevel[n_levs].flags = 0;
+       Strcpy(tmplevel[n_levs].name, "");
+       tmplevel[n_levs].chain = -1;
+}
+
+void
+init_branch()
+{
+       if(++n_brs > BRANCH_LIMIT) {
+
+               yyerror("FATAL - Too many special levels defined.");
+               exit(EXIT_FAILURE);
+       }
+       tmpbranch[n_brs].lev.base = 0;
+       tmpbranch[n_brs].lev.rand = 0;
+       Strcpy(tmpbranch[n_brs].name, "");
+       tmpbranch[n_brs].chain = -1;
+}
+
+int
+getchain(s)
+       char    *s;
+{
+       int i;
+
+       if(strlen(s)) {
+
+           for(i = n_levs - tmpdungeon[n_dgns].levels + 1; i <= n_levs; i++)
+               if(!strcmp(tmplevel[i].name, s)) return i;
+
+           yyerror("Can't locate the specified chain level.");
+           return(-2);
+       }
+       return(-1);
+}
+
+/*
+ *     Consistancy checking routines:
+ *
+ *     - A dungeon must have a unique name.
+ *     - A dungeon must have a originating "branch" command
+ *       (except, of course, for the first dungeon).
+ *     - A dungeon must have a proper depth (at least (1, 0)).
+ */
+
+int
+check_dungeon()
+{
+       int i;
+
+       for(i = 0; i < n_dgns; i++)
+           if(!strcmp(tmpdungeon[i].name, tmpdungeon[n_dgns].name)) {
+               yyerror("Duplicate dungeon name.");
+               return(0);
+           }
+
+       if(n_dgns)
+         for(i = 0; i < n_brs - tmpdungeon[n_dgns].branches; i++) {
+           if(!strcmp(tmpbranch[i].name, tmpdungeon[n_dgns].name)) break;
+
+           if(i >= n_brs - tmpdungeon[n_dgns].branches) {
+               yyerror("Dungeon cannot be reached.");
+               return(0);
+           }
+         }
+
+       if(tmpdungeon[n_dgns].lev.base <= 0 ||
+          tmpdungeon[n_dgns].lev.rand < 0) {
+               yyerror("Invalid dungeon depth specified.");
+               return(0);
+       }
+       return(1);      /* OK */
+}
+
+/*
+ *     - A level must have a unique level name.
+ *     - If chained, the level used as reference for the chain
+ *       must be in this dungeon, must be previously defined, and
+ *       the level chained from must be "non-probabilistic" (ie.
+ *       have a 100% chance of existing).
+ */
+
+int
+check_level()
+{
+       int i;
+
+       if(!in_dungeon) {
+               yyerror("Level defined outside of dungeon.");
+               return(0);
+       }
+
+       for(i = 0; i < n_levs; i++)
+           if(!strcmp(tmplevel[i].name, tmplevel[n_levs].name)) {
+               yyerror("Duplicate level name.");
+               return(0);
+           }
+
+       if(tmplevel[i].chain == -2) {
+               yyerror("Invaild level chain reference.");
+               return(0);
+       } else if(tmplevel[i].chain != -1) {    /* there is a chain */
+           /* KMH -- tmplevel[tmpbranch[i].chain].chance was in error */
+           if(tmplevel[tmplevel[i].chain].chance != 100) {
+               yyerror("Level cannot chain from a probabilistic level.");
+               return(0);
+           } else if(tmplevel[i].chain == n_levs) {
+               yyerror("A level cannot chain to itself!");
+               return(0);
+           }
+       }
+       return(1);      /* OK */
+}
+
+/*
+ *     - A branch may not branch backwards - to avoid branch loops.
+ *     - A branch name must be unique.
+ *       (ie. You can only have one entry point to each dungeon).
+ *     - If chained, the level used as reference for the chain
+ *       must be in this dungeon, must be previously defined, and
+ *       the level chained from must be "non-probabilistic" (ie.
+ *       have a 100% chance of existing).
+ */
+
+int
+check_branch()
+{
+       int i;
+
+       if(!in_dungeon) {
+               yyerror("Branch defined outside of dungeon.");
+               return(0);
+       }
+
+       for(i = 0; i < n_dgns; i++)
+           if(!strcmp(tmpdungeon[i].name, tmpbranch[n_brs].name)) {
+
+               yyerror("Reverse branching not allowed.");
+               return(0);
+           }
+
+       if(tmpbranch[i].chain == -2) {
+
+               yyerror("Invaild branch chain reference.");
+               return(0);
+       } else if(tmpbranch[i].chain != -1) {   /* it is chained */
+
+           if(tmplevel[tmpbranch[i].chain].chance != 100) {
+               yyerror("Branch cannot chain from a probabilistic level.");
+               return(0);
+           }
+       }
+       return(1);      /* OK */
+}
+
+/*
+ *     Output the dungon definition into a file.
+ *
+ *     The file will have the following format:
+ *
+ *     [ nethack version ID ]
+ *     [ number of dungeons ]
+ *     [ first dungeon struct ]
+ *     [ levels for the first dungeon ]
+ *       ...
+ *     [ branches for the first dungeon ]
+ *       ...
+ *     [ second dungeon struct ]
+ *       ...
+ */
+
+void
+output_dgn()
+{
+       int     nd, cl = 0, nl = 0,
+                   cb = 0, nb = 0;
+       static struct version_info version_data = {
+                       VERSION_NUMBER, VERSION_FEATURES,
+                       VERSION_SANITY1, VERSION_SANITY2
+       };
+
+       if(++n_dgns <= 0) {
+           yyerror("FATAL - no dungeons were defined.");
+           exit(EXIT_FAILURE);
+       }
+
+       if (fwrite((char *)&version_data, sizeof version_data, 1, yyout) != 1) {
+           yyerror("FATAL - output failure.");
+           exit(EXIT_FAILURE);
+       }
+
+       (void) fwrite((char *)&n_dgns, sizeof(int), 1, yyout);
+       for (nd = 0; nd < n_dgns; nd++) {
+           (void) fwrite((char *)&tmpdungeon[nd], sizeof(struct tmpdungeon),
+                                                       1, yyout);
+
+           nl += tmpdungeon[nd].levels;
+           for(; cl < nl; cl++)
+               (void) fwrite((char *)&tmplevel[cl], sizeof(struct tmplevel),
+                                                       1, yyout);
+
+           nb += tmpdungeon[nd].branches;
+           for(; cb < nb; cb++)
+               (void) fwrite((char *)&tmpbranch[cb], sizeof(struct tmpbranch),
+                                                       1, yyout);
+       }
+       /* apparently necessary for Think C 5.x, otherwise harmless */
+       (void) fflush(yyout);
+}
+
+/*dgn_comp.y*/
diff --git a/util/dgn_main.c b/util/dgn_main.c
new file mode 100644 (file)
index 0000000..75e5199
--- /dev/null
@@ -0,0 +1,189 @@
+/*     SCCS Id: @(#)dgn_main.c 3.4     1994/09/23      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet    */
+/*     Copyright (c) 1990 by M. Stephenson             */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file contains the main function for the parser
+ * and some useful functions needed by yacc
+ */
+
+#include "config.h"
+#include "dlb.h"
+
+/* Macintosh-specific code */
+#if defined(__APPLE__) && defined(__MACH__)
+  /* MacOS X has Unix-style files and processes */
+# undef MAC
+#endif
+#ifdef MAC
+# if defined(__SC__) || defined(__MRC__)
+#  define MPWTOOL
+#include <CursorCtl.h>
+# else
+   /* put dungeon file in library location */
+#  define PREFIX ":lib:"
+# endif
+#endif
+
+#ifndef MPWTOOL
+# define SpinCursor(x)
+#endif
+
+#define MAX_ERRORS     25
+
+extern int  NDECL (yyparse);
+extern int line_number;
+const char *fname = "(stdin)";
+int fatal_error = 0;
+
+int  FDECL (main, (int,char **));
+void FDECL (yyerror, (const char *));
+void FDECL (yywarning, (const char *));
+int  NDECL (yywrap);
+void FDECL (init_yyin, (FILE *));
+void FDECL (init_yyout, (FILE *));
+
+#ifdef AZTEC_36
+FILE *FDECL (freopen, (char *,char *,FILE *));
+#endif
+#define Fprintf (void)fprintf
+
+#if defined(__BORLANDC__) && !defined(_WIN32)
+extern unsigned _stklen = STKSIZ;
+#endif
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+       char    infile[64], outfile[64], basename[64];
+       FILE    *fin, *fout;
+       int     i, len;
+       boolean errors_encountered = FALSE;
+#if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__))
+       char    *mark;
+       static char *mac_argv[] = {     "dgn_comp",     /* dummy argv[0] */
+                               ":dat:dungeon.pdf"
+                               };
+
+       argc = SIZE(mac_argv);
+       argv = mac_argv;
+#endif
+
+       Strcpy(infile, "(stdin)");
+       fin = stdin;
+       Strcpy(outfile, "(stdout)");
+       fout = stdout;
+
+       if (argc == 1) {        /* Read standard input */
+           init_yyin(fin);
+           init_yyout(fout);
+           (void) yyparse();
+           if (fatal_error > 0)
+               errors_encountered = TRUE;
+       } else {                /* Otherwise every argument is a filename */
+           for(i=1; i<argc; i++) {
+               fname = strcpy(infile, argv[i]);
+               /* the input file had better be a .pdf file */
+               len = strlen(fname) - 4;        /* length excluding suffix */
+               if (len < 0 || strncmp(".pdf", fname + len, 4)) {
+                   Fprintf(stderr,
+                           "Error - file name \"%s\" in wrong format.\n",
+                           fname);
+                   errors_encountered = TRUE;
+                   continue;
+               }
+
+               /* build output file name */
+#if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__))
+               /* extract basename from path to infile */
+               mark = strrchr(infile, ':');
+               strcpy(basename, mark ? mark+1 : infile);
+               mark = strchr(basename, '.');
+               if (mark) *mark = '\0';
+#else
+               /* Use the whole name - strip off the last 3 or 4 chars. */
+
+#ifdef VMS     /* avoid possible interaction with logical name */
+               len++;  /* retain "." as trailing punctuation */
+#endif
+               (void) strncpy(basename, infile, len);
+               basename[len] = '\0';
+#endif
+
+               outfile[0] = '\0';
+#ifdef PREFIX
+               (void) strcat(outfile, PREFIX);
+#endif
+               (void) strcat(outfile, basename);
+
+               fin = freopen(infile, "r", stdin);
+               if (!fin) {
+                   Fprintf(stderr, "Can't open %s for input.\n", infile);
+                   perror(infile);
+                   errors_encountered = TRUE;
+                   continue;
+               }
+               fout = freopen(outfile, WRBMODE, stdout);
+               if (!fout) {
+                   Fprintf(stderr, "Can't open %s for output.\n", outfile);
+                   perror(outfile);
+                   errors_encountered = TRUE;
+                   continue;
+               }
+               init_yyin(fin);
+               init_yyout(fout);
+               (void) yyparse();
+               line_number = 1;
+               if (fatal_error > 0) {
+                       errors_encountered = TRUE;
+                       fatal_error = 0;
+               }
+           }
+       }
+       if (fout && fclose(fout) < 0) {
+           Fprintf(stderr, "Can't finish output file.");
+           perror(outfile);
+           errors_encountered = TRUE;
+       }
+       exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
+
+/*
+ * Each time the parser detects an error, it uses this function.
+ * Here we take count of the errors. To continue farther than
+ * MAX_ERRORS wouldn't be reasonable.
+ */
+
+void yyerror(s)
+const char *s;
+{
+       (void) fprintf(stderr,"%s : line %d : %s\n",fname,line_number, s);
+       if (++fatal_error > MAX_ERRORS) {
+               (void) fprintf(stderr,"Too many errors, good bye!\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+/*
+ * Just display a warning (that is : a non fatal error)
+ */
+
+void yywarning(s)
+const char *s;
+{
+       (void) fprintf(stderr,"%s : line %d : WARNING : %s\n",fname,line_number,s);
+}
+
+int yywrap()
+{
+       SpinCursor(3); /*       Don't know if this is a good place to put it ?
+                                               Is it called for our grammar ? Often enough ?
+                                               Too often ? -- h+ */
+       return 1;
+}
+
+/*dgn_main.c*/
diff --git a/util/dlb_main.c b/util/dlb_main.c
new file mode 100644 (file)
index 0000000..a943a92
--- /dev/null
@@ -0,0 +1,543 @@
+/*     SCCS Id: @(#)dlb_main.c 3.4     1998/08/16      */
+/* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* data librarian; only useful if you are making the library version, DLBLIB */
+
+#include "config.h"
+#include "dlb.h"
+#if !defined(O_WRONLY) && !defined(MAC) && !defined(AZTEC_C)
+#include <fcntl.h>
+#endif
+#if defined(__DJGPP__)
+#include <string.h>
+#endif
+
+static void FDECL(xexit, (int));
+
+#ifdef DLB
+#ifdef DLBLIB
+
+#define DLB_DIRECTORY "Directory"      /* name of lib directory */
+#define LIBLISTFILE "dlb.lst"          /* default list file */
+
+/* library functions (from dlb.c) */
+extern boolean FDECL(open_library,(const char *,library *));
+extern void FDECL(close_library,(library *));
+
+char *FDECL(eos, (char *));    /* also used by dlb.c */
+FILE *FDECL(fopen_datafile, (const char *,const char *));
+
+#ifdef VMS
+extern char *FDECL(vms_basename, (const char *));
+extern int FDECL(vms_open, (const char *,int,unsigned int));
+#endif
+
+static void FDECL(Write, (int,char *,long));
+static void NDECL(usage);
+static void NDECL(verbose_help);
+static void FDECL(write_dlb_directory, (int,int,libdir *,long,long,long));
+
+static char default_progname[] = "dlb";
+static char *progname = default_progname;
+
+/* fixed library and list file names - can be overridden if necessary */
+static const char *library_file = DLBFILE;
+static const char *list_file = LIBLISTFILE;
+
+#ifdef AMIGA
+static char origdir[255]="";
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#define MAX_DLB_FILES 200      /* max # of files we'll handle */
+#define DLB_VERS 1             /* version of dlb file we will write */
+
+/*
+ * How the file is encoded within the library.  Don't use a space
+ * because (at least) the  SunOS 4.1.3 C library will eat the white
+ * space instead of preserving it like the man page says it should.
+ */
+#define ENC_NORMAL 'n' /* normal: not compressed in any way */
+
+
+/*
+ * If you know tar, you have a small clue how to use this (note: - does
+ * NOT mean stdin/stdout).
+ *
+ * dlb COMMANDoptions arg... files...
+ * commands:
+ *  dlb x      extract all files
+ *  dlb c      build the archive
+ *  dlb t      list the archive
+ * options:
+ *  v          verbose
+ *  f file     specify archive file (default DLBFILE)
+ *  I file     specify file for list of files (default LIBLISTFILE)
+ *  C dir      chdir to dir (used ONCE, not like tar's -C)
+ */
+
+static void
+usage()
+{
+    (void) printf("Usage: %s [ctxCIfv] arguments... [files...]\n", progname);
+    (void) printf("  default library is %s\n", library_file);
+    (void) printf("  default list file is %s\n", list_file);
+    xexit(EXIT_FAILURE);
+}
+
+static void
+verbose_help()
+{
+    static const char *long_help[] = {
+       "",
+       "dlb COMMANDoptions args... files...",
+       "  commands:",
+       "    dlb ?   print this text",
+       "    dlb h   ditto",
+       "    dlb x   extract all files",
+       "    dlb c   create the archive",
+       "    dlb t   list table of contents",
+       "  options:",
+       "    v       verbose operation",
+       "    f file  specify archive file name",
+       "    I file  specify file for list of file names",
+       "    C dir   change directory before processing any files",
+       "",
+       (char *)0
+    };
+    const char **str;
+
+    for (str = long_help; *str; str++)
+       (void) printf("%s\n", *str);
+    usage();
+}
+
+static void
+Write(out,buf,len)
+    int out;
+    char *buf;
+    long len;
+{
+#if defined(MSDOS) && !defined(__DJGPP__)
+    unsigned short slen;
+
+    if (len > 65534) {
+       printf("%d Length specified for write() too large for 16 bit env.",
+               len);
+       xexit(EXIT_FAILURE);
+    }
+    slen = (unsigned short)len;
+    if (write(out,buf,slen) != slen) {
+#else
+    if (write(out,buf,len) != len) {
+#endif
+       printf("Write Error in '%s'\n",library_file);
+       xexit(EXIT_FAILURE);
+    }
+}
+
+
+char *
+eos(s)
+    char *s;
+{
+    while (*s) s++;
+    return s;
+}
+
+
+#ifdef VMS     /* essential to have punctuation, to avoid logical names */
+static FILE *
+vms_fopen(filename, mode)
+const char *filename, *mode;
+{
+    char tmp[BUFSIZ];
+
+    if (!index(filename, '.') && !index(filename, ';'))
+       filename = strcat(strcpy(tmp, filename), ";0");
+    return fopen(filename, mode, "mbc=16");
+}
+#define fopen vms_fopen
+#endif /* VMS */
+
+/* open_library(dlb.c) needs this (which normally comes from src/files.c) */
+FILE *
+fopen_datafile(filename, mode)
+const char *filename, *mode;
+{
+    return fopen(filename, mode);
+}
+
+#endif /* DLBLIB */
+#endif /* DLB */
+
+int
+main(argc, argv)
+    int argc;
+    char **argv;
+{
+#ifdef DLB
+#ifdef DLBLIB
+    int i, r;
+    int ap=2;                          /* argument pointer */
+    int cp;                            /* command pointer */
+    int iseen=0, fseen=0, verbose=0;   /* flags */
+    char action=' ';
+    library lib;
+
+    if (argc > 0 && argv[0] && *argv[0]) progname = argv[0];
+#ifdef VMS
+    progname = vms_basename(progname);
+#endif
+
+    if (argc<2) {
+       usage();
+       /* doesn't return */
+    }
+
+    for(cp=0;argv[1][cp];cp++){
+       switch(argv[1][cp]){
+           default:
+               usage();        /* doesn't return */
+           case '-':   /* silently ignore */
+               break;
+           case '?':
+           case 'h':
+               verbose_help();
+               break;
+           case 'I':
+               if (ap == argc) usage();
+               list_file=argv[ap++];
+               if(iseen)
+                   printf("Warning: multiple I options.  Previous ignored.\n");
+               iseen=1;
+               break;
+           case 'f':
+               if (ap == argc) usage();
+               library_file=argv[ap++];
+               if(fseen)
+                   printf("Warning: multiple f options.  Previous ignored.\n");
+               fseen=1;
+               break;
+           case 'C':
+               if (ap == argc) usage();
+#ifdef AMIGA
+               if(!getcwd(origdir,sizeof(origdir))){
+                   printf("Can't get current directory.\n");
+                   xexit(EXIT_FAILURE);
+               }
+#endif
+               if(chdir(argv[ap++])){
+                   printf("Can't chdir to %s\n",argv[--ap]);
+                   xexit(EXIT_FAILURE);
+               }
+               break;
+           case 'v':
+               verbose=1;
+               break;
+           case 't':
+           case 'c':
+           case 'x':
+               if(action != ' '){
+                   printf("Only one of t,x,c may be specified.\n");
+                   usage();
+               }
+               action=argv[1][cp];
+               break;
+       }
+    }
+
+    if(argv[ap] && iseen){
+       printf("Too many arguments.\n");
+       xexit(EXIT_FAILURE);
+    }
+
+    switch(action){
+    default:
+       printf("Internal error - action.\n");
+       xexit(EXIT_FAILURE);
+       break;
+    case 't':                  /* list archive */
+       if (!open_library(library_file, &lib)) {
+           printf("Can't open dlb file\n");
+           xexit(EXIT_FAILURE);
+       }
+
+       for (i = 0; i < lib.nentries; i++) {
+           if (verbose)
+               printf("%-14s %6ld %6ld\n",
+                   lib.dir[i].fname, lib.dir[i].foffset, lib.dir[i].fsize);
+           else
+               printf("%s\n", lib.dir[i].fname);
+       }
+
+       if (verbose)
+           printf("Revision:%ld  File count:%ld  String size:%ld\n",
+               lib.rev, lib.nentries, lib.strsize);
+
+       close_library(&lib);
+       xexit(EXIT_SUCCESS);
+
+    case 'x': {                        /* extract archive contents */
+       int f, n;
+       long remainder, total_read;
+       char buf[BUFSIZ];
+
+       if (!open_library(library_file, &lib)) {
+           printf("Can't open dlb file\n");
+           xexit(EXIT_FAILURE);
+       }
+
+       for (i = 0; i < lib.nentries; i++) {
+           if (argv[ap]) {
+               /* if files are listed, see if current is wanted */
+               int c;
+               for (c = ap; c < argc; c++)
+                   if (!FILENAME_CMP(lib.dir[i].fname, argv[c])) break;
+               if (c == argc) continue;        /* skip */
+           } else if (!FILENAME_CMP(lib.dir[i].fname, DLB_DIRECTORY)) {
+               /*
+                * Don't extract the directory unless the user
+                * specifically asks for it.
+                *
+                * Perhaps we should never extract the directory???
+                */
+               continue;
+           }
+           fseek(lib.fdata, lib.dir[i].foffset, SEEK_SET);
+
+           f = open(lib.dir[i].fname, O_WRONLY|O_TRUNC|O_BINARY|O_CREAT, 0640);
+           if (f < 0) {
+               printf("Can't create '%s'\n", lib.dir[i].fname);
+               xexit(EXIT_FAILURE);
+           }
+
+           /* read chunks from library and write them out */
+           total_read = 0;
+           do {
+               remainder = lib.dir[i].fsize - total_read;
+               if (remainder > (long) sizeof(buf))
+                   r = (int) sizeof(buf);
+               else
+                   r = remainder;
+
+               n = fread(buf, 1, r, lib.fdata);
+               if (n != r) {
+                   printf("Read Error in '%s'\n", lib.dir[i].fname);
+                   xexit(EXIT_FAILURE);
+               }
+               if (write(f, buf, n) != n) {
+                   printf("Write Error in '%s'\n", lib.dir[i].fname);
+                   xexit(EXIT_FAILURE);
+               }
+
+               total_read += n;
+           } while (total_read != lib.dir[i].fsize);
+
+           (void) close(f);
+
+           if (verbose) printf("x %s\n", lib.dir[i].fname);
+       }
+
+       close_library(&lib);
+       xexit(EXIT_SUCCESS);
+       }
+
+    case 'c':                  /* create archive */
+       {
+       libdir ld[MAX_DLB_FILES];
+       char buf[BUFSIZ];
+       int fd, out, nfiles = 0;
+       long dir_size, slen, flen, fsiz;
+       boolean rewrite_directory = FALSE;
+
+       /*
+        * Get names from either/both an argv list and a file
+        * list.  This does not do any duplicate checking
+        */
+
+       /* get file name in argv list */
+       if (argv[ap]) {
+           for ( ; ap < argc; ap++, nfiles++) {
+               if (nfiles >= MAX_DLB_FILES) {
+                   printf("Too many dlb files!  Stopping at %d.\n",
+                                                               MAX_DLB_FILES);
+                   break;
+               }
+               ld[nfiles].fname = (char *) alloc(strlen(argv[ap]) + 1);
+               Strcpy(ld[nfiles].fname, argv[ap]);
+           }
+       }
+
+       if (iseen) {
+           /* want to do a list file */
+           FILE *list = fopen(list_file, "r");
+           if (!list) {
+               printf("Can't open %s\n",list_file);
+               xexit(EXIT_FAILURE);
+           }
+
+           /* get file names, one per line */
+           for ( ; fgets(buf, sizeof(buf), list); nfiles++) {
+               if (nfiles >= MAX_DLB_FILES) {
+                   printf("Too many dlb files!  Stopping at %d.\n",
+                                                               MAX_DLB_FILES);
+                   break;
+               }
+               *(eos(buf)-1) = '\0';   /* strip newline */
+               ld[nfiles].fname = (char *) alloc(strlen(buf) + 1);
+               Strcpy(ld[nfiles].fname, buf);
+           }
+           fclose(list);
+       }
+
+       if (nfiles == 0) {
+           printf("No files to archive\n");
+           xexit(EXIT_FAILURE);
+       }
+
+
+       /*
+        * Get file sizes and name string length.  Don't include
+        * the directory information yet.
+        */
+       for (i = 0, slen = 0, flen = 0; i < nfiles; i++) {
+           fd = open(ld[i].fname, O_RDONLY|O_BINARY, 0);
+           if (fd < 0) {
+               printf("Can't open %s\n", ld[i].fname);
+               xexit(EXIT_FAILURE);
+           }
+           ld[i].fsize = lseek(fd, 0, SEEK_END);
+           ld[i].foffset = flen;
+
+           slen += strlen(ld[i].fname);        /* don't add null (yet) */
+           flen += ld[i].fsize;
+           close(fd);
+       }
+
+       /* open output file */
+       out = open(library_file, O_RDWR|O_TRUNC|O_BINARY|O_CREAT, FCMASK);
+       if (out < 0) {
+           printf("Can't open %s for output\n", library_file);
+           xexit(EXIT_FAILURE);
+       }
+
+       /* caculate directory size */
+       dir_size = 40                   /* header line (see below) */
+                  + ((nfiles+1)*11)    /* handling+file offset+SP+newline */
+                  + slen+strlen(DLB_DIRECTORY); /* file names */
+
+       /* write directory */
+       write_dlb_directory(out, nfiles, ld, slen, dir_size, flen);
+
+       flen = 0L;
+       /* write each file */
+       for (i = 0; i < nfiles; i++) {
+           fd = open(ld[i].fname, O_RDONLY|O_BINARY, 0);
+           if (fd < 0) {
+               printf("Can't open input file '%s'\n", ld[i].fname);
+               xexit(EXIT_FAILURE);
+           }
+           if (verbose) printf("%s\n",ld[i].fname);
+
+           fsiz = 0L;
+           while ((r = read(fd, buf, sizeof buf)) != 0) {
+               if (r == -1) {
+                   printf("Read Error in '%s'\n", ld[i].fname);
+                   xexit(EXIT_FAILURE);
+               }
+               if (write(out, buf, r) != r) {
+                   printf("Write Error in '%s'\n", ld[i].fname);
+                   xexit(EXIT_FAILURE);
+               }
+               fsiz += r;
+           }
+           (void) close(fd);
+           if (fsiz != ld[i].fsize) rewrite_directory = TRUE;
+           /* in case directory rewrite is needed */
+           ld[i].fsize = fsiz;
+           ld[i].foffset = flen;
+           flen += fsiz;
+       }
+
+       if (rewrite_directory) {
+           if (verbose) printf("(rewriting dlb directory info)\n");
+           (void) lseek(out, 0, SEEK_SET);     /* rewind */
+           write_dlb_directory(out, nfiles, ld, slen, dir_size, flen);
+       }
+
+       for (i = 0; i < nfiles; i++)
+           free((genericptr_t) ld[i].fname),  ld[i].fname = 0;
+
+       (void) close(out);
+       xexit(EXIT_SUCCESS);
+       }
+    }
+#endif /* DLBLIB */
+#endif /* DLB */
+
+    xexit(EXIT_SUCCESS);
+    /*NOTREACHED*/
+    return 0;
+}
+
+#ifdef DLB
+#ifdef DLBLIB
+
+static void
+write_dlb_directory(out, nfiles, ld, slen, dir_size, flen)
+int out, nfiles;
+libdir *ld;
+long slen, dir_size, flen;
+{
+    char buf[BUFSIZ];
+    int i;
+
+    sprintf(buf,"%3ld %8ld %8ld %8ld %8ld\n",
+           (long) DLB_VERS,        /* version of dlb file */
+           (long) nfiles+1,        /* # of entries (includes directory) */
+                                   /* string length + room for nulls */
+           (long) slen+strlen(DLB_DIRECTORY)+nfiles+1,
+           (long) dir_size,        /* start of first file */
+           (long) flen+dir_size);  /* total file size */
+    Write(out, buf, strlen(buf));
+
+    /* write each file entry */
+#define ENTRY_FORMAT "%c%s %8ld\n"
+    sprintf(buf, ENTRY_FORMAT, ENC_NORMAL, DLB_DIRECTORY, (long) 0);
+    Write(out, buf, strlen(buf));
+    for (i = 0; i < nfiles; i++) {
+       sprintf(buf, ENTRY_FORMAT,
+               ENC_NORMAL,                 /* encoding */
+               ld[i].fname,                /* name */
+               ld[i].foffset + dir_size);  /* offset */
+       Write(out, buf, strlen(buf));
+    }
+}
+
+#endif /* DLBLIB */
+#endif /* DLB */
+
+static void
+xexit(retcd)
+    int retcd;
+{
+#ifdef DLB
+#ifdef AMIGA
+    if (origdir[0]) chdir(origdir);
+#endif
+#endif
+    exit(retcd);
+}
+
+
+#ifdef AMIGA
+#include "date.h"
+const char amiga_version_string[] = AMIGA_VERSION_STRING;
+#endif
+
+/*dlb_main.c*/
diff --git a/util/lev_comp.l b/util/lev_comp.l
new file mode 100644 (file)
index 0000000..1e7c3ae
--- /dev/null
@@ -0,0 +1,240 @@
+%{
+/*     SCCS Id: @(#)lev_lex.c  3.4     2002/03/27      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#define LEV_LEX_C
+
+#include "hack.h"
+#include "lev_comp.h"
+#include "sp_lev.h"
+
+/* Most of these don't exist in flex, yywrap is macro and
+ * yyunput is properly declared in flex.skel.
+ */
+#if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER)
+int FDECL(yyback, (int *,int));
+int NDECL(yylook);
+int NDECL(yyinput);
+int NDECL(yywrap);
+int NDECL(yylex);
+       /* Traditional lexes let yyunput() and yyoutput() default to int;
+        * newer ones may declare them as void since they don't return
+        * values.  For even more fun, the lex supplied as part of the
+        * newer unbundled compiler for SunOS 4.x adds the void declarations
+        * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain
+        * int) while the bundled lex and the one with the older unbundled
+        * compiler do not.  To detect this, we need help from outside --
+        * sys/unix/Makefile.utl.
+        *
+        * Digital UNIX is difficult and still has int in spite of all
+        * other signs.
+        */
+# if defined(NeXT) || defined(SVR4) || defined(_AIX32)
+#  define VOIDYYPUT
+# endif
+# if !defined(VOIDYYPUT) && defined(POSIX_TYPES)
+#  if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS)
+#   define VOIDYYPUT
+#  endif
+# endif
+# if !defined(VOIDYYPUT) && defined(WEIRD_LEX)
+#  if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1)
+#   define VOIDYYPUT
+#  endif
+# endif
+# if defined(VOIDYYPUT) && defined(__osf__)
+#  undef VOIDYYPUT
+# endif
+# ifdef VOIDYYPUT
+void FDECL(yyunput, (int));
+void FDECL(yyoutput, (int));
+# else
+int FDECL(yyunput, (int));
+int FDECL(yyoutput, (int));
+# endif
+#endif /* !FLEX_SCANNER && !FLEXHACK_SCANNER */
+
+#ifdef FLEX_SCANNER
+#define YY_MALLOC_DECL \
+             genericptr_t FDECL(malloc, (size_t)); \
+             genericptr_t FDECL(realloc, (genericptr_t,size_t));
+#endif
+
+void FDECL(init_yyin, (FILE *));
+void FDECL(init_yyout, (FILE *));
+
+/*
+ * This doesn't always get put in lev_comp.h
+ * (esp. when using older versions of bison).
+ */
+extern YYSTYPE yylval;
+
+int line_number = 1, colon_line_number = 1;
+static char map[4096];
+static int map_cnt = 0;
+
+%}
+%e 1500
+%p 5000
+%n 700
+%s MAPC
+%%
+<MAPC>ENDMAP   {
+                 BEGIN(INITIAL);
+                 yylval.map = (char *) alloc(map_cnt + 1);
+                 (void) strncpy(yylval.map, map, map_cnt);
+                 yylval.map[map_cnt] = 0;
+                 map_cnt = 0;
+                 return MAP_ID;
+               }
+<MAPC>[-|}{+ABCISHKPLWTF\\#. 0123456789]*\r?\n {
+                 int len = yyleng;
+                 /* convert \r\n to \n */
+                 if (len >= 2 && yytext[len - 2] == '\r') len -= 1;
+                 line_number++;
+                 (void) strncpy(map + map_cnt, yytext, len);
+                 map_cnt += len;
+                 map[map_cnt - 1] = '\n';
+                 map[map_cnt] = '\0';
+               }
+^#.*\n         { line_number++; }
+:              { colon_line_number = line_number; return ':'; }
+MESSAGE                return MESSAGE_ID;
+MAZE           return MAZE_ID;
+NOMAP          return NOMAP_ID;
+LEVEL          return LEVEL_ID;
+INIT_MAP       return LEV_INIT_ID;
+FLAGS          return FLAGS_ID;
+GEOMETRY       return GEOMETRY_ID;
+^MAP\r?\n              { BEGIN(MAPC); line_number++; }
+OBJECT         return OBJECT_ID;
+CONTAINER      return COBJECT_ID;
+MONSTER                return MONSTER_ID;
+TRAP           return TRAP_ID;
+DOOR           return DOOR_ID;
+DRAWBRIDGE     return DRAWBRIDGE_ID;
+MAZEWALK       return MAZEWALK_ID;
+WALLIFY                return WALLIFY_ID;
+REGION         return REGION_ID;
+RANDOM_OBJECTS return RANDOM_OBJECTS_ID;
+RANDOM_MONSTERS        return RANDOM_MONSTERS_ID;
+RANDOM_PLACES  return RANDOM_PLACES_ID;
+ALTAR          return ALTAR_ID;
+LADDER         return LADDER_ID;
+STAIR          return STAIR_ID;
+PORTAL         return PORTAL_ID;
+TELEPORT_REGION        return TELEPRT_ID;
+BRANCH         return BRANCH_ID;
+FOUNTAIN       return FOUNTAIN_ID;
+SINK           return SINK_ID;
+POOL           return POOL_ID;
+NON_DIGGABLE   return NON_DIGGABLE_ID;
+NON_PASSWALL   return NON_PASSWALL_ID;
+ROOM           return ROOM_ID;
+SUBROOM                return SUBROOM_ID;
+RANDOM_CORRIDORS       return RAND_CORRIDOR_ID;
+CORRIDOR       return CORRIDOR_ID;
+GOLD           return GOLD_ID;
+ENGRAVING      return ENGRAVING_ID;
+NAME           return NAME_ID;
+CHANCE         return CHANCE_ID;
+levregion      return LEV;
+open           { yylval.i=D_ISOPEN; return DOOR_STATE; }
+closed         { yylval.i=D_CLOSED; return DOOR_STATE; }
+locked         { yylval.i=D_LOCKED; return DOOR_STATE; }
+nodoor         { yylval.i=D_NODOOR; return DOOR_STATE; }
+broken         { yylval.i=D_BROKEN; return DOOR_STATE; }
+north          { yylval.i=W_NORTH; return DIRECTION; }
+east           { yylval.i=W_EAST; return DIRECTION; }
+south          { yylval.i=W_SOUTH; return DIRECTION; }
+west           { yylval.i=W_WEST; return DIRECTION; }
+random         { yylval.i = -1; return RANDOM_TYPE; }
+none           { yylval.i = -2; return NONE; }
+object         return O_REGISTER;
+monster                return M_REGISTER;
+place          return P_REGISTER;
+align          return A_REGISTER;
+left           { yylval.i=1; return LEFT_OR_RIGHT; }
+half-left      { yylval.i=2; return LEFT_OR_RIGHT; }
+center         { yylval.i=3; return CENTER; }
+half-right     { yylval.i=4; return LEFT_OR_RIGHT; }
+right          { yylval.i=5; return LEFT_OR_RIGHT; }
+top            { yylval.i=1; return TOP_OR_BOT; }
+bottom         { yylval.i=5; return TOP_OR_BOT; }
+lit            { yylval.i=1; return LIGHT_STATE; }
+unlit          { yylval.i=0; return LIGHT_STATE; }
+filled         { yylval.i=0; return FILLING; }
+unfilled       { yylval.i=1; return FILLING; }
+noalign                { yylval.i= AM_NONE; return ALIGNMENT; }
+law            { yylval.i= AM_LAWFUL; return ALIGNMENT; }
+neutral                { yylval.i= AM_NEUTRAL; return ALIGNMENT; }
+chaos          { yylval.i= AM_CHAOTIC; return ALIGNMENT; }
+coaligned      { yylval.i= AM_SPLEV_CO; return ALIGNMENT; }
+noncoaligned   { yylval.i= AM_SPLEV_NONCO; return ALIGNMENT; }
+peaceful       { yylval.i=1; return MON_ATTITUDE; }
+hostile                { yylval.i=0; return MON_ATTITUDE; }
+asleep         { yylval.i=1; return MON_ALERTNESS; }
+awake          { yylval.i=0; return MON_ALERTNESS; }
+m_feature      { yylval.i= M_AP_FURNITURE; return MON_APPEARANCE; }
+m_monster      { yylval.i= M_AP_MONSTER;   return MON_APPEARANCE; }
+m_object       { yylval.i= M_AP_OBJECT;    return MON_APPEARANCE; }
+sanctum                { yylval.i=2; return ALTAR_TYPE; }
+shrine         { yylval.i=1; return ALTAR_TYPE; }
+altar          { yylval.i=0; return ALTAR_TYPE; }
+up             { yylval.i=1; return UP_OR_DOWN; }
+down           { yylval.i=0; return UP_OR_DOWN; }
+false          { yylval.i=0; return BOOLEAN; }
+true           { yylval.i=1; return BOOLEAN; }
+dust           { yylval.i=DUST; return ENGRAVING_TYPE; }
+engrave                { yylval.i=ENGRAVE; return ENGRAVING_TYPE; }
+burn           { yylval.i=BURN; return ENGRAVING_TYPE; }
+mark           { yylval.i=MARK; return ENGRAVING_TYPE; }
+blessed                { yylval.i=1; return CURSE_TYPE; }
+uncursed       { yylval.i=2; return CURSE_TYPE; }
+cursed         { yylval.i=3; return CURSE_TYPE; }
+contained      { return CONTAINED; }
+noteleport     { yylval.i=NOTELEPORT; return FLAG_TYPE; }
+hardfloor      { yylval.i=HARDFLOOR; return FLAG_TYPE; }
+nommap         { yylval.i=NOMMAP; return FLAG_TYPE; }
+arboreal       { yylval.i=ARBOREAL; return FLAG_TYPE; }        /* KMH */
+shortsighted   { yylval.i=SHORTSIGHTED; return FLAG_TYPE; }
+\[\ *[0-9]+\%\ *\] { yylval.i = atoi(yytext + 1); return PERCENT; }
+[+\-]?[0-9]+   { yylval.i=atoi(yytext); return INTEGER; }
+\"[^"]*\"      { yytext[yyleng-1] = 0; /* Discard the trailing \" */
+                 yylval.map = (char *) alloc(strlen(yytext+1)+1);
+                 Strcpy(yylval.map, yytext+1); /* Discard the first \" */
+                 return STRING; }
+\r?\n          { line_number++; }
+[ \t]+         ;
+'\\.'          { yylval.i = yytext[2]; return CHAR; }
+'.'            { yylval.i = yytext[1]; return CHAR; }
+.              { return yytext[0]; }
+%%
+#ifdef AMIGA
+long *alloc(n)
+       unsigned n;
+{
+       return ((long *)malloc (n));
+}
+#endif
+
+/* routine to switch to another input file; needed for flex */
+void init_yyin( input_f )
+FILE *input_f;
+{
+#if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER)
+       if (yyin)
+           yyrestart(input_f);
+       else
+#endif
+           yyin = input_f;
+}
+/* analogous routine (for completeness) */
+void init_yyout( output_f )
+FILE *output_f;
+{
+       yyout = output_f;
+}
+
+/*lev_comp.l*/
diff --git a/util/lev_comp.y b/util/lev_comp.y
new file mode 100644 (file)
index 0000000..a12c7cd
--- /dev/null
@@ -0,0 +1,1681 @@
+%{
+/*     SCCS Id: @(#)lev_yacc.c 3.4     2000/01/17      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file contains the Level Compiler code
+ * It may handle special mazes & special room-levels
+ */
+
+/* In case we're using bison in AIX.  This definition must be
+ * placed before any other C-language construct in the file
+ * excluding comments and preprocessor directives (thanks IBM
+ * for this wonderful feature...).
+ *
+ * Note: some cpps barf on this 'undefined control' (#pragma).
+ * Addition of the leading space seems to prevent barfage for now,
+ * and AIX will still see the directive.
+ */
+#ifdef _AIX
+ #pragma alloca                /* keep leading space! */
+#endif
+
+#include "hack.h"
+#include "sp_lev.h"
+
+#define MAX_REGISTERS  10
+#define ERR            (-1)
+/* many types of things are put in chars for transference to NetHack.
+ * since some systems will use signed chars, limit everybody to the
+ * same number for portability.
+ */
+#define MAX_OF_TYPE    128
+
+#define New(type)              \
+       (type *) memset((genericptr_t)alloc(sizeof(type)), 0, sizeof(type))
+#define NewTab(type, size)     (type **) alloc(sizeof(type *) * size)
+#define Free(ptr)              free((genericptr_t)ptr)
+
+extern void FDECL(yyerror, (const char *));
+extern void FDECL(yywarning, (const char *));
+extern int NDECL(yylex);
+int NDECL(yyparse);
+
+extern int FDECL(get_floor_type, (CHAR_P));
+extern int FDECL(get_room_type, (char *));
+extern int FDECL(get_trap_type, (char *));
+extern int FDECL(get_monster_id, (char *,CHAR_P));
+extern int FDECL(get_object_id, (char *,CHAR_P));
+extern boolean FDECL(check_monster_char, (CHAR_P));
+extern boolean FDECL(check_object_char, (CHAR_P));
+extern char FDECL(what_map_char, (CHAR_P));
+extern void FDECL(scan_map, (char *));
+extern void NDECL(wallify_map);
+extern boolean NDECL(check_subrooms);
+extern void FDECL(check_coord, (int,int,const char *));
+extern void NDECL(store_part);
+extern void NDECL(store_room);
+extern boolean FDECL(write_level_file, (char *,splev *,specialmaze *));
+extern void FDECL(free_rooms, (splev *));
+
+static struct reg {
+       int x1, y1;
+       int x2, y2;
+}              current_region;
+
+static struct coord {
+       int x;
+       int y;
+}              current_coord, current_align;
+
+static struct size {
+       int height;
+       int width;
+}              current_size;
+
+char tmpmessage[256];
+digpos *tmppass[32];
+char *tmpmap[ROWNO];
+
+digpos *tmpdig[MAX_OF_TYPE];
+region *tmpreg[MAX_OF_TYPE];
+lev_region *tmplreg[MAX_OF_TYPE];
+door *tmpdoor[MAX_OF_TYPE];
+drawbridge *tmpdb[MAX_OF_TYPE];
+walk *tmpwalk[MAX_OF_TYPE];
+
+room_door *tmprdoor[MAX_OF_TYPE];
+trap *tmptrap[MAX_OF_TYPE];
+monster *tmpmonst[MAX_OF_TYPE];
+object *tmpobj[MAX_OF_TYPE];
+altar *tmpaltar[MAX_OF_TYPE];
+lad *tmplad[MAX_OF_TYPE];
+stair *tmpstair[MAX_OF_TYPE];
+gold *tmpgold[MAX_OF_TYPE];
+engraving *tmpengraving[MAX_OF_TYPE];
+fountain *tmpfountain[MAX_OF_TYPE];
+sink *tmpsink[MAX_OF_TYPE];
+pool *tmppool[MAX_OF_TYPE];
+
+mazepart *tmppart[10];
+room *tmproom[MAXNROFROOMS*2];
+corridor *tmpcor[MAX_OF_TYPE];
+
+static specialmaze maze;
+static splev special_lev;
+static lev_init init_lev;
+
+static char olist[MAX_REGISTERS], mlist[MAX_REGISTERS];
+static struct coord plist[MAX_REGISTERS];
+
+int n_olist = 0, n_mlist = 0, n_plist = 0;
+
+unsigned int nlreg = 0, nreg = 0, ndoor = 0, ntrap = 0, nmons = 0, nobj = 0;
+unsigned int ndb = 0, nwalk = 0, npart = 0, ndig = 0, nlad = 0, nstair = 0;
+unsigned int naltar = 0, ncorridor = 0, nrooms = 0, ngold = 0, nengraving = 0;
+unsigned int nfountain = 0, npool = 0, nsink = 0, npass = 0;
+
+static int lev_flags = 0;
+
+unsigned int max_x_map, max_y_map;
+
+static xchar in_room;
+
+extern int fatal_error;
+extern int want_warnings;
+extern const char *fname;
+
+%}
+
+%union
+{
+       int     i;
+       char*   map;
+       struct {
+               xchar room;
+               xchar wall;
+               xchar door;
+       } corpos;
+}
+
+
+%token <i> CHAR INTEGER BOOLEAN PERCENT
+%token <i> MESSAGE_ID MAZE_ID LEVEL_ID LEV_INIT_ID GEOMETRY_ID NOMAP_ID
+%token <i> OBJECT_ID COBJECT_ID MONSTER_ID TRAP_ID DOOR_ID DRAWBRIDGE_ID
+%token <i> MAZEWALK_ID WALLIFY_ID REGION_ID FILLING
+%token <i> RANDOM_OBJECTS_ID RANDOM_MONSTERS_ID RANDOM_PLACES_ID
+%token <i> ALTAR_ID LADDER_ID STAIR_ID NON_DIGGABLE_ID NON_PASSWALL_ID ROOM_ID
+%token <i> PORTAL_ID TELEPRT_ID BRANCH_ID LEV CHANCE_ID
+%token <i> CORRIDOR_ID GOLD_ID ENGRAVING_ID FOUNTAIN_ID POOL_ID SINK_ID NONE
+%token <i> RAND_CORRIDOR_ID DOOR_STATE LIGHT_STATE CURSE_TYPE ENGRAVING_TYPE
+%token <i> DIRECTION RANDOM_TYPE O_REGISTER M_REGISTER P_REGISTER A_REGISTER
+%token <i> ALIGNMENT LEFT_OR_RIGHT CENTER TOP_OR_BOT ALTAR_TYPE UP_OR_DOWN
+%token <i> SUBROOM_ID NAME_ID FLAGS_ID FLAG_TYPE MON_ATTITUDE MON_ALERTNESS
+%token <i> MON_APPEARANCE
+%token <i> CONTAINED
+%token <i> ',' ':' '(' ')' '[' ']'
+%token <map> STRING MAP_ID
+%type  <i> h_justif v_justif trap_name room_type door_state light_state
+%type  <i> alignment altar_type a_register roomfill filling door_pos
+%type  <i> door_wall walled secret amount chance
+%type  <i> engraving_type flags flag_list prefilled lev_region lev_init
+%type  <i> monster monster_c m_register object object_c o_register
+%type  <map> string maze_def level_def m_name o_name
+%type  <corpos> corr_spec
+%start file
+
+%%
+file           : /* nothing */
+               | levels
+               ;
+
+levels         : level
+               | level levels
+               ;
+
+level          : maze_level
+               | room_level
+               ;
+
+maze_level     : maze_def flags lev_init messages regions
+                 {
+                       unsigned i;
+
+                       if (fatal_error > 0) {
+                               (void) fprintf(stderr,
+                               "%s : %d errors detected. No output created!\n",
+                                       fname, fatal_error);
+                       } else {
+                               maze.flags = $2;
+                               (void) memcpy((genericptr_t)&(maze.init_lev),
+                                               (genericptr_t)&(init_lev),
+                                               sizeof(lev_init));
+                               maze.numpart = npart;
+                               maze.parts = NewTab(mazepart, npart);
+                               for(i=0;i<npart;i++)
+                                   maze.parts[i] = tmppart[i];
+                               if (!write_level_file($1, (splev *)0, &maze)) {
+                                       yyerror("Can't write output file!!");
+                                       exit(EXIT_FAILURE);
+                               }
+                               npart = 0;
+                       }
+                       Free($1);
+                 }
+               ;
+
+room_level     : level_def flags lev_init messages rreg_init rooms corridors_def
+                 {
+                       unsigned i;
+
+                       if (fatal_error > 0) {
+                           (void) fprintf(stderr,
+                             "%s : %d errors detected. No output created!\n",
+                                       fname, fatal_error);
+                       } else {
+                               special_lev.flags = (long) $2;
+                               (void) memcpy(
+                                       (genericptr_t)&(special_lev.init_lev),
+                                       (genericptr_t)&(init_lev),
+                                       sizeof(lev_init));
+                               special_lev.nroom = nrooms;
+                               special_lev.rooms = NewTab(room, nrooms);
+                               for(i=0; i<nrooms; i++)
+                                   special_lev.rooms[i] = tmproom[i];
+                               special_lev.ncorr = ncorridor;
+                               special_lev.corrs = NewTab(corridor, ncorridor);
+                               for(i=0; i<ncorridor; i++)
+                                   special_lev.corrs[i] = tmpcor[i];
+                               if (check_subrooms()) {
+                                   if (!write_level_file($1, &special_lev,
+                                                         (specialmaze *)0)) {
+                                       yyerror("Can't write output file!!");
+                                       exit(EXIT_FAILURE);
+                                   }
+                               }
+                               free_rooms(&special_lev);
+                               nrooms = 0;
+                               ncorridor = 0;
+                       }
+                       Free($1);
+                 }
+               ;
+
+level_def      : LEVEL_ID ':' string
+                 {
+                       if (index($3, '.'))
+                           yyerror("Invalid dot ('.') in level name.");
+                       if ((int) strlen($3) > 8)
+                           yyerror("Level names limited to 8 characters.");
+                       $$ = $3;
+                       special_lev.nrmonst = special_lev.nrobjects = 0;
+                       n_mlist = n_olist = 0;
+                 }
+               ;
+
+lev_init       : /* nothing */
+                 {
+                       /* in case we're processing multiple files,
+                          explicitly clear any stale settings */
+                       (void) memset((genericptr_t) &init_lev, 0,
+                                       sizeof init_lev);
+                       init_lev.init_present = FALSE;
+                       $$ = 0;
+                 }
+               | LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled
+                 {
+                       init_lev.init_present = TRUE;
+                       init_lev.fg = what_map_char((char) $3);
+                       if (init_lev.fg == INVALID_TYPE)
+                           yyerror("Invalid foreground type.");
+                       init_lev.bg = what_map_char((char) $5);
+                       if (init_lev.bg == INVALID_TYPE)
+                           yyerror("Invalid background type.");
+                       init_lev.smoothed = $7;
+                       init_lev.joined = $9;
+                       if (init_lev.joined &&
+                           init_lev.fg != CORR && init_lev.fg != ROOM)
+                           yyerror("Invalid foreground type for joined map.");
+                       init_lev.lit = $11;
+                       init_lev.walled = $13;
+                       $$ = 1;
+                 }
+               ;
+
+walled         : BOOLEAN
+               | RANDOM_TYPE
+               ;
+
+flags          : /* nothing */
+                 {
+                       $$ = 0;
+                 }
+               | FLAGS_ID ':' flag_list
+                 {
+                       $$ = lev_flags;
+                       lev_flags = 0;  /* clear for next user */
+                 }
+               ;
+
+flag_list      : FLAG_TYPE ',' flag_list
+                 {
+                       lev_flags |= $1;
+                 }
+               | FLAG_TYPE
+                 {
+                       lev_flags |= $1;
+                 }
+               ;
+
+messages       : /* nothing */
+               | message messages
+               ;
+
+message                : MESSAGE_ID ':' STRING
+                 {
+                       int i, j;
+
+                       i = (int) strlen($3) + 1;
+                       j = (int) strlen(tmpmessage);
+                       if (i + j > 255) {
+                          yyerror("Message string too long (>256 characters)");
+                       } else {
+                           if (j) tmpmessage[j++] = '\n';
+                           (void) strncpy(tmpmessage+j, $3, i - 1);
+                           tmpmessage[j + i - 1] = 0;
+                       }
+                       Free($3);
+                 }
+               ;
+
+rreg_init      : /* nothing */
+               | rreg_init init_rreg
+               ;
+
+init_rreg      : RANDOM_OBJECTS_ID ':' object_list
+                 {
+                       if(special_lev.nrobjects) {
+                           yyerror("Object registers already initialized!");
+                       } else {
+                           special_lev.nrobjects = n_olist;
+                           special_lev.robjects = (char *) alloc(n_olist);
+                           (void) memcpy((genericptr_t)special_lev.robjects,
+                                         (genericptr_t)olist, n_olist);
+                       }
+                 }
+               | RANDOM_MONSTERS_ID ':' monster_list
+                 {
+                       if(special_lev.nrmonst) {
+                           yyerror("Monster registers already initialized!");
+                       } else {
+                           special_lev.nrmonst = n_mlist;
+                           special_lev.rmonst = (char *) alloc(n_mlist);
+                           (void) memcpy((genericptr_t)special_lev.rmonst,
+                                         (genericptr_t)mlist, n_mlist);
+                         }
+                 }
+               ;
+
+rooms          : /* Nothing  -  dummy room for use with INIT_MAP */
+                 {
+                       tmproom[nrooms] = New(room);
+                       tmproom[nrooms]->name = (char *) 0;
+                       tmproom[nrooms]->parent = (char *) 0;
+                       tmproom[nrooms]->rtype = 0;
+                       tmproom[nrooms]->rlit = 0;
+                       tmproom[nrooms]->xalign = ERR;
+                       tmproom[nrooms]->yalign = ERR;
+                       tmproom[nrooms]->x = 0;
+                       tmproom[nrooms]->y = 0;
+                       tmproom[nrooms]->w = 2;
+                       tmproom[nrooms]->h = 2;
+                       in_room = 1;
+                 }
+               | roomlist
+               ;
+
+roomlist       : aroom
+               | aroom roomlist
+               ;
+
+corridors_def  : random_corridors
+               | corridors
+               ;
+
+random_corridors: RAND_CORRIDOR_ID
+                 {
+                       tmpcor[0] = New(corridor);
+                       tmpcor[0]->src.room = -1;
+                       ncorridor = 1;
+                 }
+               ;
+
+corridors      : /* nothing */
+               | corridors corridor
+               ;
+
+corridor       : CORRIDOR_ID ':' corr_spec ',' corr_spec
+                 {
+                       tmpcor[ncorridor] = New(corridor);
+                       tmpcor[ncorridor]->src.room = $3.room;
+                       tmpcor[ncorridor]->src.wall = $3.wall;
+                       tmpcor[ncorridor]->src.door = $3.door;
+                       tmpcor[ncorridor]->dest.room = $5.room;
+                       tmpcor[ncorridor]->dest.wall = $5.wall;
+                       tmpcor[ncorridor]->dest.door = $5.door;
+                       ncorridor++;
+                       if (ncorridor >= MAX_OF_TYPE) {
+                               yyerror("Too many corridors in level!");
+                               ncorridor--;
+                       }
+                 }
+               | CORRIDOR_ID ':' corr_spec ',' INTEGER
+                 {
+                       tmpcor[ncorridor] = New(corridor);
+                       tmpcor[ncorridor]->src.room = $3.room;
+                       tmpcor[ncorridor]->src.wall = $3.wall;
+                       tmpcor[ncorridor]->src.door = $3.door;
+                       tmpcor[ncorridor]->dest.room = -1;
+                       tmpcor[ncorridor]->dest.wall = $5;
+                       ncorridor++;
+                       if (ncorridor >= MAX_OF_TYPE) {
+                               yyerror("Too many corridors in level!");
+                               ncorridor--;
+                       }
+                 }
+               ;
+
+corr_spec      : '(' INTEGER ',' DIRECTION ',' door_pos ')'
+                 {
+                       if ((unsigned) $2 >= nrooms)
+                           yyerror("Wrong room number!");
+                       $$.room = $2;
+                       $$.wall = $4;
+                       $$.door = $6;
+                 }
+               ;
+
+aroom          : room_def room_details
+                 {
+                       store_room();
+                 }
+               | subroom_def room_details
+                 {
+                       store_room();
+                 }
+               ;
+
+subroom_def    : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill
+                 {
+                       tmproom[nrooms] = New(room);
+                       tmproom[nrooms]->parent = $11;
+                       tmproom[nrooms]->name = (char *) 0;
+                       tmproom[nrooms]->rtype = $3;
+                       tmproom[nrooms]->rlit = $5;
+                       tmproom[nrooms]->filled = $12;
+                       tmproom[nrooms]->xalign = ERR;
+                       tmproom[nrooms]->yalign = ERR;
+                       tmproom[nrooms]->x = current_coord.x;
+                       tmproom[nrooms]->y = current_coord.y;
+                       tmproom[nrooms]->w = current_size.width;
+                       tmproom[nrooms]->h = current_size.height;
+                       in_room = 1;
+                 }
+               ;
+
+room_def       : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill
+                 {
+                       tmproom[nrooms] = New(room);
+                       tmproom[nrooms]->name = (char *) 0;
+                       tmproom[nrooms]->parent = (char *) 0;
+                       tmproom[nrooms]->rtype = $3;
+                       tmproom[nrooms]->rlit = $5;
+                       tmproom[nrooms]->filled = $12;
+                       tmproom[nrooms]->xalign = current_align.x;
+                       tmproom[nrooms]->yalign = current_align.y;
+                       tmproom[nrooms]->x = current_coord.x;
+                       tmproom[nrooms]->y = current_coord.y;
+                       tmproom[nrooms]->w = current_size.width;
+                       tmproom[nrooms]->h = current_size.height;
+                       in_room = 1;
+                 }
+               ;
+
+roomfill       : /* nothing */
+                 {
+                       $$ = 1;
+                 }
+               | ',' BOOLEAN
+                 {
+                       $$ = $2;
+                 }
+               ;
+
+room_pos       : '(' INTEGER ',' INTEGER ')'
+                 {
+                       if ( $2 < 1 || $2 > 5 ||
+                           $4 < 1 || $4 > 5 ) {
+                           yyerror("Room position should be between 1 & 5!");
+                       } else {
+                           current_coord.x = $2;
+                           current_coord.y = $4;
+                       }
+                 }
+               | RANDOM_TYPE
+                 {
+                       current_coord.x = current_coord.y = ERR;
+                 }
+               ;
+
+subroom_pos    : '(' INTEGER ',' INTEGER ')'
+                 {
+                       if ( $2 < 0 || $4 < 0) {
+                           yyerror("Invalid subroom position !");
+                       } else {
+                           current_coord.x = $2;
+                           current_coord.y = $4;
+                       }
+                 }
+               | RANDOM_TYPE
+                 {
+                       current_coord.x = current_coord.y = ERR;
+                 }
+               ;
+
+room_align     : '(' h_justif ',' v_justif ')'
+                 {
+                       current_align.x = $2;
+                       current_align.y = $4;
+                 }
+               | RANDOM_TYPE
+                 {
+                       current_align.x = current_align.y = ERR;
+                 }
+               ;
+
+room_size      : '(' INTEGER ',' INTEGER ')'
+                 {
+                       current_size.width = $2;
+                       current_size.height = $4;
+                 }
+               | RANDOM_TYPE
+                 {
+                       current_size.height = current_size.width = ERR;
+                 }
+               ;
+
+room_details   : /* nothing */
+               | room_details room_detail
+               ;
+
+room_detail    : room_name
+               | room_chance
+               | room_door
+               | monster_detail
+               | object_detail
+               | trap_detail
+               | altar_detail
+               | fountain_detail
+               | sink_detail
+               | pool_detail
+               | gold_detail
+               | engraving_detail
+               | stair_detail
+               ;
+
+room_name      : NAME_ID ':' string
+                 {
+                       if (tmproom[nrooms]->name)
+                           yyerror("This room already has a name!");
+                       else
+                           tmproom[nrooms]->name = $3;
+                 }
+               ;
+
+room_chance    : CHANCE_ID ':' INTEGER
+                  {
+                       if (tmproom[nrooms]->chance)
+                           yyerror("This room already assigned a chance!");
+                       else if (tmproom[nrooms]->rtype == OROOM)
+                           yyerror("Only typed rooms can have a chance!");
+                       else if ($3 < 1 || $3 > 99)
+                           yyerror("The chance is supposed to be percentile.");
+                       else
+                           tmproom[nrooms]->chance = $3;
+                  }
+               ;
+
+room_door      : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos
+                 {
+                       /* ERR means random here */
+                       if ($7 == ERR && $9 != ERR) {
+                    yyerror("If the door wall is random, so must be its pos!");
+                       } else {
+                           tmprdoor[ndoor] = New(room_door);
+                           tmprdoor[ndoor]->secret = $3;
+                           tmprdoor[ndoor]->mask = $5;
+                           tmprdoor[ndoor]->wall = $7;
+                           tmprdoor[ndoor]->pos = $9;
+                           ndoor++;
+                           if (ndoor >= MAX_OF_TYPE) {
+                                   yyerror("Too many doors in room!");
+                                   ndoor--;
+                           }
+                       }
+                 }
+               ;
+
+secret         : BOOLEAN
+               | RANDOM_TYPE
+               ;
+
+door_wall      : DIRECTION
+               | RANDOM_TYPE
+               ;
+
+door_pos       : INTEGER
+               | RANDOM_TYPE
+               ;
+
+maze_def       : MAZE_ID ':' string ',' filling
+                 {
+                       maze.filling = (schar) $5;
+                       if (index($3, '.'))
+                           yyerror("Invalid dot ('.') in level name.");
+                       if ((int) strlen($3) > 8)
+                           yyerror("Level names limited to 8 characters.");
+                       $$ = $3;
+                       in_room = 0;
+                       n_plist = n_mlist = n_olist = 0;
+                 }
+               ;
+
+filling                : CHAR
+                 {
+                       $$ = get_floor_type((char)$1);
+                 }
+               | RANDOM_TYPE
+                 {
+                       $$ = -1;
+                 }
+               ;
+
+regions                : aregion
+               | aregion regions
+               ;
+
+aregion                : map_definition reg_init map_details
+                 {
+                       store_part();
+                 }
+               ;
+
+map_definition : NOMAP_ID
+                 {
+                       tmppart[npart] = New(mazepart);
+                       tmppart[npart]->halign = 1;
+                       tmppart[npart]->valign = 1;
+                       tmppart[npart]->nrobjects = 0;
+                       tmppart[npart]->nloc = 0;
+                       tmppart[npart]->nrmonst = 0;
+                       tmppart[npart]->xsize = 1;
+                       tmppart[npart]->ysize = 1;
+                       tmppart[npart]->map = (char **) alloc(sizeof(char *));
+                       tmppart[npart]->map[0] = (char *) alloc(1);
+                       tmppart[npart]->map[0][0] = STONE;
+                       max_x_map = COLNO-1;
+                       max_y_map = ROWNO;
+                 }
+               | map_geometry MAP_ID
+                 {
+                       tmppart[npart] = New(mazepart);
+                       tmppart[npart]->halign = $<i>1 % 10;
+                       tmppart[npart]->valign = $<i>1 / 10;
+                       tmppart[npart]->nrobjects = 0;
+                       tmppart[npart]->nloc = 0;
+                       tmppart[npart]->nrmonst = 0;
+                       scan_map($2);
+                       Free($2);
+                 }
+               ;
+
+map_geometry   : GEOMETRY_ID ':' h_justif ',' v_justif
+                 {
+                       $<i>$ = $<i>3 + ($<i>5 * 10);
+                 }
+               ;
+
+h_justif       : LEFT_OR_RIGHT
+               | CENTER
+               ;
+
+v_justif       : TOP_OR_BOT
+               | CENTER
+               ;
+
+reg_init       : /* nothing */
+               | reg_init init_reg
+               ;
+
+init_reg       : RANDOM_OBJECTS_ID ':' object_list
+                 {
+                       if (tmppart[npart]->nrobjects) {
+                           yyerror("Object registers already initialized!");
+                       } else {
+                           tmppart[npart]->robjects = (char *)alloc(n_olist);
+                           (void) memcpy((genericptr_t)tmppart[npart]->robjects,
+                                         (genericptr_t)olist, n_olist);
+                           tmppart[npart]->nrobjects = n_olist;
+                       }
+                 }
+               | RANDOM_PLACES_ID ':' place_list
+                 {
+                       if (tmppart[npart]->nloc) {
+                           yyerror("Location registers already initialized!");
+                       } else {
+                           register int i;
+                           tmppart[npart]->rloc_x = (char *) alloc(n_plist);
+                           tmppart[npart]->rloc_y = (char *) alloc(n_plist);
+                           for(i=0;i<n_plist;i++) {
+                               tmppart[npart]->rloc_x[i] = plist[i].x;
+                               tmppart[npart]->rloc_y[i] = plist[i].y;
+                           }
+                           tmppart[npart]->nloc = n_plist;
+                       }
+                 }
+               | RANDOM_MONSTERS_ID ':' monster_list
+                 {
+                       if (tmppart[npart]->nrmonst) {
+                           yyerror("Monster registers already initialized!");
+                       } else {
+                           tmppart[npart]->rmonst = (char *) alloc(n_mlist);
+                           (void) memcpy((genericptr_t)tmppart[npart]->rmonst,
+                                         (genericptr_t)mlist, n_mlist);
+                           tmppart[npart]->nrmonst = n_mlist;
+                       }
+                 }
+               ;
+
+object_list    : object
+                 {
+                       if (n_olist < MAX_REGISTERS)
+                           olist[n_olist++] = $<i>1;
+                       else
+                           yyerror("Object list too long!");
+                 }
+               | object ',' object_list
+                 {
+                       if (n_olist < MAX_REGISTERS)
+                           olist[n_olist++] = $<i>1;
+                       else
+                           yyerror("Object list too long!");
+                 }
+               ;
+
+monster_list   : monster
+                 {
+                       if (n_mlist < MAX_REGISTERS)
+                           mlist[n_mlist++] = $<i>1;
+                       else
+                           yyerror("Monster list too long!");
+                 }
+               | monster ',' monster_list
+                 {
+                       if (n_mlist < MAX_REGISTERS)
+                           mlist[n_mlist++] = $<i>1;
+                       else
+                           yyerror("Monster list too long!");
+                 }
+               ;
+
+place_list     : place
+                 {
+                       if (n_plist < MAX_REGISTERS)
+                           plist[n_plist++] = current_coord;
+                       else
+                           yyerror("Location list too long!");
+                 }
+               | place
+                 {
+                       if (n_plist < MAX_REGISTERS)
+                           plist[n_plist++] = current_coord;
+                       else
+                           yyerror("Location list too long!");
+                 }
+                ',' place_list
+               ;
+
+map_details    : /* nothing */
+               | map_details map_detail
+               ;
+
+map_detail     : monster_detail
+               | object_detail
+               | door_detail
+               | trap_detail
+               | drawbridge_detail
+               | region_detail
+               | stair_region
+               | portal_region
+               | teleprt_region
+               | branch_region
+               | altar_detail
+               | fountain_detail
+               | mazewalk_detail
+               | wallify_detail
+               | ladder_detail
+               | stair_detail
+               | gold_detail
+               | engraving_detail
+               | diggable_detail
+               | passwall_detail
+               ;
+
+monster_detail : MONSTER_ID chance ':' monster_c ',' m_name ',' coordinate
+                 {
+                       tmpmonst[nmons] = New(monster);
+                       tmpmonst[nmons]->x = current_coord.x;
+                       tmpmonst[nmons]->y = current_coord.y;
+                       tmpmonst[nmons]->class = $<i>4;
+                       tmpmonst[nmons]->peaceful = -1; /* no override */
+                       tmpmonst[nmons]->asleep = -1;
+                       tmpmonst[nmons]->align = - MAX_REGISTERS - 2;
+                       tmpmonst[nmons]->name.str = 0;
+                       tmpmonst[nmons]->appear = 0;
+                       tmpmonst[nmons]->appear_as.str = 0;
+                       tmpmonst[nmons]->chance = $2;
+                       tmpmonst[nmons]->id = NON_PM;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Monster");
+                       if ($6) {
+                           int token = get_monster_id($6, (char) $<i>4);
+                           if (token == ERR)
+                               yywarning(
+                             "Invalid monster name!  Making random monster.");
+                           else
+                               tmpmonst[nmons]->id = token;
+                           Free($6);
+                       }
+                 }
+                monster_infos
+                 {
+                       if (++nmons >= MAX_OF_TYPE) {
+                           yyerror("Too many monsters in room or mazepart!");
+                           nmons--;
+                       }
+                 }
+               ;
+
+monster_infos  : /* nothing */
+               | monster_infos monster_info
+               ;
+
+monster_info   : ',' string
+                 {
+                       tmpmonst[nmons]->name.str = $2;
+                 }
+               | ',' MON_ATTITUDE
+                 {
+                       tmpmonst[nmons]->peaceful = $<i>2;
+                 }
+               | ',' MON_ALERTNESS
+                 {
+                       tmpmonst[nmons]->asleep = $<i>2;
+                 }
+               | ',' alignment
+                 {
+                       tmpmonst[nmons]->align = $<i>2;
+                 }
+               | ',' MON_APPEARANCE string
+                 {
+                       tmpmonst[nmons]->appear = $<i>2;
+                       tmpmonst[nmons]->appear_as.str = $3;
+                 }
+               ;
+
+object_detail  : OBJECT_ID object_desc
+                 {
+                 }
+               | COBJECT_ID object_desc
+                 {
+                       /* 1: is contents of preceeding object with 2 */
+                       /* 2: is a container */
+                       /* 0: neither */
+                       tmpobj[nobj-1]->containment = 2;
+                 }
+               ;
+
+object_desc    : chance ':' object_c ',' o_name
+                 {
+                       tmpobj[nobj] = New(object);
+                       tmpobj[nobj]->class = $<i>3;
+                       tmpobj[nobj]->corpsenm = NON_PM;
+                       tmpobj[nobj]->curse_state = -1;
+                       tmpobj[nobj]->name.str = 0;
+                       tmpobj[nobj]->chance = $1;
+                       tmpobj[nobj]->id = -1;
+                       if ($5) {
+                           int token = get_object_id($5, $<i>3);
+                           if (token == ERR)
+                               yywarning(
+                               "Illegal object name!  Making random object.");
+                            else
+                               tmpobj[nobj]->id = token;
+                           Free($5);
+                       }
+                 }
+                ',' object_where object_infos
+                 {
+                       if (++nobj >= MAX_OF_TYPE) {
+                           yyerror("Too many objects in room or mazepart!");
+                           nobj--;
+                       }
+                 }
+               ;
+
+object_where   : coordinate
+                 {
+                       tmpobj[nobj]->containment = 0;
+                       tmpobj[nobj]->x = current_coord.x;
+                       tmpobj[nobj]->y = current_coord.y;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Object");
+                 }
+               | CONTAINED
+                 {
+                       tmpobj[nobj]->containment = 1;
+                       /* random coordinate, will be overridden anyway */
+                       tmpobj[nobj]->x = -MAX_REGISTERS-1;
+                       tmpobj[nobj]->y = -MAX_REGISTERS-1;
+                 }
+               ;
+
+object_infos   : /* nothing */
+                 {
+                       tmpobj[nobj]->spe = -127;
+       /* Note below: we're trying to make as many of these optional as
+        * possible.  We clearly can't make curse_state, enchantment, and
+        * monster_id _all_ optional, since ",random" would be ambiguous.
+        * We can't even just make enchantment mandatory, since if we do that
+        * alone, ",random" requires too much lookahead to parse.
+        */
+                 }
+               | ',' curse_state ',' monster_id ',' enchantment optional_name
+                 {
+                 }
+               | ',' curse_state ',' enchantment optional_name
+                 {
+                 }
+               | ',' monster_id ',' enchantment optional_name
+                 {
+                 }
+               ;
+
+curse_state    : RANDOM_TYPE
+                 {
+                       tmpobj[nobj]->curse_state = -1;
+                 }
+               | CURSE_TYPE
+                 {
+                       tmpobj[nobj]->curse_state = $1;
+                 }
+               ;
+
+monster_id     : STRING
+                 {
+                       int token = get_monster_id($1, (char)0);
+                       if (token == ERR)       /* "random" */
+                           tmpobj[nobj]->corpsenm = NON_PM - 1;
+                       else
+                           tmpobj[nobj]->corpsenm = token;
+                       Free($1);
+                 }
+               ;
+
+enchantment    : RANDOM_TYPE
+                 {
+                       tmpobj[nobj]->spe = -127;
+                 }
+               | INTEGER
+                 {
+                       tmpobj[nobj]->spe = $1;
+                 }
+               ;
+
+optional_name  : /* nothing */
+               | ',' NONE
+                 {
+                 }
+               | ',' STRING
+                 {
+                       tmpobj[nobj]->name.str = $2;
+                 }
+               ;
+
+door_detail    : DOOR_ID ':' door_state ',' coordinate
+                 {
+                       tmpdoor[ndoor] = New(door);
+                       tmpdoor[ndoor]->x = current_coord.x;
+                       tmpdoor[ndoor]->y = current_coord.y;
+                       tmpdoor[ndoor]->mask = $<i>3;
+                       if(current_coord.x >= 0 && current_coord.y >= 0 &&
+                          tmpmap[current_coord.y][current_coord.x] != DOOR &&
+                          tmpmap[current_coord.y][current_coord.x] != SDOOR)
+                           yyerror("Door decl doesn't match the map");
+                       ndoor++;
+                       if (ndoor >= MAX_OF_TYPE) {
+                               yyerror("Too many doors in mazepart!");
+                               ndoor--;
+                       }
+                 }
+               ;
+
+trap_detail    : TRAP_ID chance ':' trap_name ',' coordinate
+                 {
+                       tmptrap[ntrap] = New(trap);
+                       tmptrap[ntrap]->x = current_coord.x;
+                       tmptrap[ntrap]->y = current_coord.y;
+                       tmptrap[ntrap]->type = $<i>4;
+                       tmptrap[ntrap]->chance = $2;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Trap");
+                       if (++ntrap >= MAX_OF_TYPE) {
+                               yyerror("Too many traps in room or mazepart!");
+                               ntrap--;
+                       }
+                 }
+               ;
+
+drawbridge_detail: DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state
+                  {
+                       int x, y, dir;
+
+                       tmpdb[ndb] = New(drawbridge);
+                       x = tmpdb[ndb]->x = current_coord.x;
+                       y = tmpdb[ndb]->y = current_coord.y;
+                       /* convert dir from a DIRECTION to a DB_DIR */
+                       dir = $5;
+                       switch(dir) {
+                       case W_NORTH: dir = DB_NORTH; y--; break;
+                       case W_SOUTH: dir = DB_SOUTH; y++; break;
+                       case W_EAST:  dir = DB_EAST;  x++; break;
+                       case W_WEST:  dir = DB_WEST;  x--; break;
+                       default:
+                           yyerror("Invalid drawbridge direction");
+                           break;
+                       }
+                       tmpdb[ndb]->dir = dir;
+                       if (current_coord.x >= 0 && current_coord.y >= 0 &&
+                           !IS_WALL(tmpmap[y][x])) {
+                           char ebuf[60];
+                           Sprintf(ebuf,
+                                   "Wall needed for drawbridge (%02d, %02d)",
+                                   current_coord.x, current_coord.y);
+                           yyerror(ebuf);
+                       }
+
+                       if ( $<i>7 == D_ISOPEN )
+                           tmpdb[ndb]->db_open = 1;
+                       else if ( $<i>7 == D_CLOSED )
+                           tmpdb[ndb]->db_open = 0;
+                       else
+                           yyerror("A drawbridge can only be open or closed!");
+                       ndb++;
+                       if (ndb >= MAX_OF_TYPE) {
+                               yyerror("Too many drawbridges in mazepart!");
+                               ndb--;
+                       }
+                  }
+               ;
+
+mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION
+                 {
+                       tmpwalk[nwalk] = New(walk);
+                       tmpwalk[nwalk]->x = current_coord.x;
+                       tmpwalk[nwalk]->y = current_coord.y;
+                       tmpwalk[nwalk]->dir = $5;
+                       nwalk++;
+                       if (nwalk >= MAX_OF_TYPE) {
+                               yyerror("Too many mazewalks in mazepart!");
+                               nwalk--;
+                       }
+                 }
+               ;
+
+wallify_detail : WALLIFY_ID
+                 {
+                       wallify_map();
+                 }
+               ;
+
+ladder_detail  : LADDER_ID ':' coordinate ',' UP_OR_DOWN
+                 {
+                       tmplad[nlad] = New(lad);
+                       tmplad[nlad]->x = current_coord.x;
+                       tmplad[nlad]->y = current_coord.y;
+                       tmplad[nlad]->up = $<i>5;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Ladder");
+                       nlad++;
+                       if (nlad >= MAX_OF_TYPE) {
+                               yyerror("Too many ladders in mazepart!");
+                               nlad--;
+                       }
+                 }
+               ;
+
+stair_detail   : STAIR_ID ':' coordinate ',' UP_OR_DOWN
+                 {
+                       tmpstair[nstair] = New(stair);
+                       tmpstair[nstair]->x = current_coord.x;
+                       tmpstair[nstair]->y = current_coord.y;
+                       tmpstair[nstair]->up = $<i>5;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Stairway");
+                       nstair++;
+                       if (nstair >= MAX_OF_TYPE) {
+                               yyerror("Too many stairs in room or mazepart!");
+                               nstair--;
+                       }
+                 }
+               ;
+
+stair_region   : STAIR_ID ':' lev_region
+                 {
+                       tmplreg[nlreg] = New(lev_region);
+                       tmplreg[nlreg]->in_islev = $3;
+                       tmplreg[nlreg]->inarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->inarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->inarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->inarea.y2 = current_region.y2;
+                 }
+                ',' lev_region ',' UP_OR_DOWN
+                 {
+                       tmplreg[nlreg]->del_islev = $6;
+                       tmplreg[nlreg]->delarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->delarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->delarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->delarea.y2 = current_region.y2;
+                       if($8)
+                           tmplreg[nlreg]->rtype = LR_UPSTAIR;
+                       else
+                           tmplreg[nlreg]->rtype = LR_DOWNSTAIR;
+                       tmplreg[nlreg]->rname.str = 0;
+                       nlreg++;
+                       if (nlreg >= MAX_OF_TYPE) {
+                               yyerror("Too many levregions in mazepart!");
+                               nlreg--;
+                       }
+                 }
+               ;
+
+portal_region  : PORTAL_ID ':' lev_region
+                 {
+                       tmplreg[nlreg] = New(lev_region);
+                       tmplreg[nlreg]->in_islev = $3;
+                       tmplreg[nlreg]->inarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->inarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->inarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->inarea.y2 = current_region.y2;
+                 }
+                ',' lev_region ',' string
+                 {
+                       tmplreg[nlreg]->del_islev = $6;
+                       tmplreg[nlreg]->delarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->delarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->delarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->delarea.y2 = current_region.y2;
+                       tmplreg[nlreg]->rtype = LR_PORTAL;
+                       tmplreg[nlreg]->rname.str = $8;
+                       nlreg++;
+                       if (nlreg >= MAX_OF_TYPE) {
+                               yyerror("Too many levregions in mazepart!");
+                               nlreg--;
+                       }
+                 }
+               ;
+
+teleprt_region : TELEPRT_ID ':' lev_region
+                 {
+                       tmplreg[nlreg] = New(lev_region);
+                       tmplreg[nlreg]->in_islev = $3;
+                       tmplreg[nlreg]->inarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->inarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->inarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->inarea.y2 = current_region.y2;
+                 }
+                ',' lev_region
+                 {
+                       tmplreg[nlreg]->del_islev = $6;
+                       tmplreg[nlreg]->delarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->delarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->delarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->delarea.y2 = current_region.y2;
+                 }
+               teleprt_detail
+                 {
+                       switch($<i>8) {
+                       case -1: tmplreg[nlreg]->rtype = LR_TELE; break;
+                       case 0: tmplreg[nlreg]->rtype = LR_DOWNTELE; break;
+                       case 1: tmplreg[nlreg]->rtype = LR_UPTELE; break;
+                       }
+                       tmplreg[nlreg]->rname.str = 0;
+                       nlreg++;
+                       if (nlreg >= MAX_OF_TYPE) {
+                               yyerror("Too many levregions in mazepart!");
+                               nlreg--;
+                       }
+                 }
+               ;
+
+branch_region  : BRANCH_ID ':' lev_region
+                 {
+                       tmplreg[nlreg] = New(lev_region);
+                       tmplreg[nlreg]->in_islev = $3;
+                       tmplreg[nlreg]->inarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->inarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->inarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->inarea.y2 = current_region.y2;
+                 }
+                ',' lev_region
+                 {
+                       tmplreg[nlreg]->del_islev = $6;
+                       tmplreg[nlreg]->delarea.x1 = current_region.x1;
+                       tmplreg[nlreg]->delarea.y1 = current_region.y1;
+                       tmplreg[nlreg]->delarea.x2 = current_region.x2;
+                       tmplreg[nlreg]->delarea.y2 = current_region.y2;
+                       tmplreg[nlreg]->rtype = LR_BRANCH;
+                       tmplreg[nlreg]->rname.str = 0;
+                       nlreg++;
+                       if (nlreg >= MAX_OF_TYPE) {
+                               yyerror("Too many levregions in mazepart!");
+                               nlreg--;
+                       }
+                 }
+               ;
+
+teleprt_detail : /* empty */
+                 {
+                       $<i>$ = -1;
+                 }
+               | ',' UP_OR_DOWN
+                 {
+                       $<i>$ = $2;
+                 }
+               ;
+
+lev_region     : region
+                 {
+                       $$ = 0;
+                 }
+               | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
+                 {
+/* This series of if statements is a hack for MSC 5.1.  It seems that its
+   tiny little brain cannot compile if these are all one big if statement. */
+                       if ($3 <= 0 || $3 >= COLNO)
+                               yyerror("Region out of level range!");
+                       else if ($5 < 0 || $5 >= ROWNO)
+                               yyerror("Region out of level range!");
+                       else if ($7 <= 0 || $7 >= COLNO)
+                               yyerror("Region out of level range!");
+                       else if ($9 < 0 || $9 >= ROWNO)
+                               yyerror("Region out of level range!");
+                       current_region.x1 = $3;
+                       current_region.y1 = $5;
+                       current_region.x2 = $7;
+                       current_region.y2 = $9;
+                       $$ = 1;
+                 }
+               ;
+
+fountain_detail : FOUNTAIN_ID ':' coordinate
+                 {
+                       tmpfountain[nfountain] = New(fountain);
+                       tmpfountain[nfountain]->x = current_coord.x;
+                       tmpfountain[nfountain]->y = current_coord.y;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Fountain");
+                       nfountain++;
+                       if (nfountain >= MAX_OF_TYPE) {
+                           yyerror("Too many fountains in room or mazepart!");
+                           nfountain--;
+                       }
+                 }
+               ;
+
+sink_detail : SINK_ID ':' coordinate
+                 {
+                       tmpsink[nsink] = New(sink);
+                       tmpsink[nsink]->x = current_coord.x;
+                       tmpsink[nsink]->y = current_coord.y;
+                       nsink++;
+                       if (nsink >= MAX_OF_TYPE) {
+                               yyerror("Too many sinks in room!");
+                               nsink--;
+                       }
+                 }
+               ;
+
+pool_detail : POOL_ID ':' coordinate
+                 {
+                       tmppool[npool] = New(pool);
+                       tmppool[npool]->x = current_coord.x;
+                       tmppool[npool]->y = current_coord.y;
+                       npool++;
+                       if (npool >= MAX_OF_TYPE) {
+                               yyerror("Too many pools in room!");
+                               npool--;
+                       }
+                 }
+               ;
+
+diggable_detail : NON_DIGGABLE_ID ':' region
+                 {
+                       tmpdig[ndig] = New(digpos);
+                       tmpdig[ndig]->x1 = current_region.x1;
+                       tmpdig[ndig]->y1 = current_region.y1;
+                       tmpdig[ndig]->x2 = current_region.x2;
+                       tmpdig[ndig]->y2 = current_region.y2;
+                       ndig++;
+                       if (ndig >= MAX_OF_TYPE) {
+                               yyerror("Too many diggables in mazepart!");
+                               ndig--;
+                       }
+                 }
+               ;
+
+passwall_detail : NON_PASSWALL_ID ':' region
+                 {
+                       tmppass[npass] = New(digpos);
+                       tmppass[npass]->x1 = current_region.x1;
+                       tmppass[npass]->y1 = current_region.y1;
+                       tmppass[npass]->x2 = current_region.x2;
+                       tmppass[npass]->y2 = current_region.y2;
+                       npass++;
+                       if (npass >= 32) {
+                               yyerror("Too many passwalls in mazepart!");
+                               npass--;
+                       }
+                 }
+               ;
+
+region_detail  : REGION_ID ':' region ',' light_state ',' room_type prefilled
+                 {
+                       tmpreg[nreg] = New(region);
+                       tmpreg[nreg]->x1 = current_region.x1;
+                       tmpreg[nreg]->y1 = current_region.y1;
+                       tmpreg[nreg]->x2 = current_region.x2;
+                       tmpreg[nreg]->y2 = current_region.y2;
+                       tmpreg[nreg]->rlit = $<i>5;
+                       tmpreg[nreg]->rtype = $<i>7;
+                       if($<i>8 & 1) tmpreg[nreg]->rtype += MAXRTYPE+1;
+                       tmpreg[nreg]->rirreg = (($<i>8 & 2) != 0);
+                       if(current_region.x1 > current_region.x2 ||
+                          current_region.y1 > current_region.y2)
+                          yyerror("Region start > end!");
+                       if(tmpreg[nreg]->rtype == VAULT &&
+                          (tmpreg[nreg]->rirreg ||
+                           (tmpreg[nreg]->x2 - tmpreg[nreg]->x1 != 1) ||
+                           (tmpreg[nreg]->y2 - tmpreg[nreg]->y1 != 1)))
+                               yyerror("Vaults must be exactly 2x2!");
+                       if(want_warnings && !tmpreg[nreg]->rirreg &&
+                          current_region.x1 > 0 && current_region.y1 > 0 &&
+                          current_region.x2 < (int)max_x_map &&
+                          current_region.y2 < (int)max_y_map) {
+                           /* check for walls in the room */
+                           char ebuf[60];
+                           register int x, y, nrock = 0;
+
+                           for(y=current_region.y1; y<=current_region.y2; y++)
+                               for(x=current_region.x1;
+                                   x<=current_region.x2; x++)
+                                   if(IS_ROCK(tmpmap[y][x]) ||
+                                      IS_DOOR(tmpmap[y][x])) nrock++;
+                           if(nrock) {
+                               Sprintf(ebuf,
+                                       "Rock in room (%02d,%02d,%02d,%02d)?!",
+                                       current_region.x1, current_region.y1,
+                                       current_region.x2, current_region.y2);
+                               yywarning(ebuf);
+                           }
+                           if (
+               !IS_ROCK(tmpmap[current_region.y1-1][current_region.x1-1]) ||
+               !IS_ROCK(tmpmap[current_region.y2+1][current_region.x1-1]) ||
+               !IS_ROCK(tmpmap[current_region.y1-1][current_region.x2+1]) ||
+               !IS_ROCK(tmpmap[current_region.y2+1][current_region.x2+1])) {
+                               Sprintf(ebuf,
+                               "NonRock edge in room (%02d,%02d,%02d,%02d)?!",
+                                       current_region.x1, current_region.y1,
+                                       current_region.x2, current_region.y2);
+                               yywarning(ebuf);
+                           }
+                       } else if(tmpreg[nreg]->rirreg &&
+               !IS_ROOM(tmpmap[current_region.y1][current_region.x1])) {
+                           char ebuf[60];
+                           Sprintf(ebuf,
+                                   "Rock in irregular room (%02d,%02d)?!",
+                                   current_region.x1, current_region.y1);
+                           yyerror(ebuf);
+                       }
+                       nreg++;
+                       if (nreg >= MAX_OF_TYPE) {
+                               yyerror("Too many regions in mazepart!");
+                               nreg--;
+                       }
+                 }
+               ;
+
+altar_detail   : ALTAR_ID ':' coordinate ',' alignment ',' altar_type
+                 {
+                       tmpaltar[naltar] = New(altar);
+                       tmpaltar[naltar]->x = current_coord.x;
+                       tmpaltar[naltar]->y = current_coord.y;
+                       tmpaltar[naltar]->align = $<i>5;
+                       tmpaltar[naltar]->shrine = $<i>7;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Altar");
+                       naltar++;
+                       if (naltar >= MAX_OF_TYPE) {
+                               yyerror("Too many altars in room or mazepart!");
+                               naltar--;
+                       }
+                 }
+               ;
+
+gold_detail    : GOLD_ID ':' amount ',' coordinate
+                 {
+                       tmpgold[ngold] = New(gold);
+                       tmpgold[ngold]->x = current_coord.x;
+                       tmpgold[ngold]->y = current_coord.y;
+                       tmpgold[ngold]->amount = $<i>3;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Gold");
+                       ngold++;
+                       if (ngold >= MAX_OF_TYPE) {
+                               yyerror("Too many golds in room or mazepart!");
+                               ngold--;
+                       }
+                 }
+               ;
+
+engraving_detail: ENGRAVING_ID ':' coordinate ',' engraving_type ',' string
+                 {
+                       tmpengraving[nengraving] = New(engraving);
+                       tmpengraving[nengraving]->x = current_coord.x;
+                       tmpengraving[nengraving]->y = current_coord.y;
+                       tmpengraving[nengraving]->engr.str = $7;
+                       tmpengraving[nengraving]->etype = $<i>5;
+                       if (!in_room)
+                           check_coord(current_coord.x, current_coord.y,
+                                       "Engraving");
+                       nengraving++;
+                       if (nengraving >= MAX_OF_TYPE) {
+                           yyerror("Too many engravings in room or mazepart!");
+                           nengraving--;
+                       }
+                 }
+               ;
+
+monster_c      : monster
+               | RANDOM_TYPE
+                 {
+                       $<i>$ = - MAX_REGISTERS - 1;
+                 }
+               | m_register
+               ;
+
+object_c       : object
+               | RANDOM_TYPE
+                 {
+                       $<i>$ = - MAX_REGISTERS - 1;
+                 }
+               | o_register
+               ;
+
+m_name         : string
+               | RANDOM_TYPE
+                 {
+                       $$ = (char *) 0;
+                 }
+               ;
+
+o_name         : string
+               | RANDOM_TYPE
+                 {
+                       $$ = (char *) 0;
+                 }
+               ;
+
+trap_name      : string
+                 {
+                       int token = get_trap_type($1);
+                       if (token == ERR)
+                               yyerror("Unknown trap type!");
+                       $<i>$ = token;
+                       Free($1);
+                 }
+               | RANDOM_TYPE
+               ;
+
+room_type      : string
+                 {
+                       int token = get_room_type($1);
+                       if (token == ERR) {
+                               yywarning("Unknown room type!  Making ordinary room...");
+                               $<i>$ = OROOM;
+                       } else
+                               $<i>$ = token;
+                       Free($1);
+                 }
+               | RANDOM_TYPE
+               ;
+
+prefilled      : /* empty */
+                 {
+                       $<i>$ = 0;
+                 }
+               | ',' FILLING
+                 {
+                       $<i>$ = $2;
+                 }
+               | ',' FILLING ',' BOOLEAN
+                 {
+                       $<i>$ = $2 + ($4 << 1);
+                 }
+               ;
+
+coordinate     : coord
+               | p_register
+               | RANDOM_TYPE
+                 {
+                       current_coord.x = current_coord.y = -MAX_REGISTERS-1;
+                 }
+               ;
+
+door_state     : DOOR_STATE
+               | RANDOM_TYPE
+               ;
+
+light_state    : LIGHT_STATE
+               | RANDOM_TYPE
+               ;
+
+alignment      : ALIGNMENT
+               | a_register
+               | RANDOM_TYPE
+                 {
+                       $<i>$ = - MAX_REGISTERS - 1;
+                 }
+               ;
+
+altar_type     : ALTAR_TYPE
+               | RANDOM_TYPE
+               ;
+
+p_register     : P_REGISTER '[' INTEGER ']'
+                 {
+                       if ( $3 >= MAX_REGISTERS )
+                               yyerror("Register Index overflow!");
+                       else
+                               current_coord.x = current_coord.y = - $3 - 1;
+                 }
+               ;
+
+o_register     : O_REGISTER '[' INTEGER ']'
+                 {
+                       if ( $3 >= MAX_REGISTERS )
+                               yyerror("Register Index overflow!");
+                       else
+                               $<i>$ = - $3 - 1;
+                 }
+               ;
+
+m_register     : M_REGISTER '[' INTEGER ']'
+                 {
+                       if ( $3 >= MAX_REGISTERS )
+                               yyerror("Register Index overflow!");
+                       else
+                               $<i>$ = - $3 - 1;
+                 }
+               ;
+
+a_register     : A_REGISTER '[' INTEGER ']'
+                 {
+                       if ( $3 >= 3 )
+                               yyerror("Register Index overflow!");
+                       else
+                               $<i>$ = - $3 - 1;
+                 }
+               ;
+
+place          : coord
+               ;
+
+monster                : CHAR
+                 {
+                       if (check_monster_char((char) $1))
+                               $<i>$ = $1 ;
+                       else {
+                               yyerror("Unknown monster class!");
+                               $<i>$ = ERR;
+                       }
+                 }
+               ;
+
+object         : CHAR
+                 {
+                       char c = $1;
+                       if (check_object_char(c))
+                               $<i>$ = c;
+                       else {
+                               yyerror("Unknown char class!");
+                               $<i>$ = ERR;
+                       }
+                 }
+               ;
+
+string         : STRING
+               ;
+
+amount         : INTEGER
+               | RANDOM_TYPE
+               ;
+
+chance         : /* empty */
+                 {
+                       $$ = 100;       /* default is 100% */
+                 }
+               | PERCENT
+                 {
+                       if ($1 <= 0 || $1 > 100)
+                           yyerror("Expected percentile chance.");
+                       $$ = $1;
+                 }
+               ;
+
+engraving_type : ENGRAVING_TYPE
+               | RANDOM_TYPE
+               ;
+
+coord          : '(' INTEGER ',' INTEGER ')'
+                 {
+                       if (!in_room && !init_lev.init_present &&
+                           ($2 < 0 || $2 > (int)max_x_map ||
+                            $4 < 0 || $4 > (int)max_y_map))
+                           yyerror("Coordinates out of map range!");
+                       current_coord.x = $2;
+                       current_coord.y = $4;
+                 }
+               ;
+
+region         : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
+                 {
+/* This series of if statements is a hack for MSC 5.1.  It seems that its
+   tiny little brain cannot compile if these are all one big if statement. */
+                       if ($2 < 0 || $2 > (int)max_x_map)
+                               yyerror("Region out of map range!");
+                       else if ($4 < 0 || $4 > (int)max_y_map)
+                               yyerror("Region out of map range!");
+                       else if ($6 < 0 || $6 > (int)max_x_map)
+                               yyerror("Region out of map range!");
+                       else if ($8 < 0 || $8 > (int)max_y_map)
+                               yyerror("Region out of map range!");
+                       current_region.x1 = $2;
+                       current_region.y1 = $4;
+                       current_region.x2 = $6;
+                       current_region.y2 = $8;
+                 }
+               ;
+
+%%
+
+/*lev_comp.y*/
diff --git a/util/lev_main.c b/util/lev_main.c
new file mode 100644 (file)
index 0000000..bff4668
--- /dev/null
@@ -0,0 +1,1580 @@
+/*     SCCS Id: @(#)lev_main.c 3.4     2002/03/27      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file contains the main function for the parser
+ * and some useful functions needed by yacc
+ */
+#define SPEC_LEV       /* for MPW */
+/* although, why don't we move those special defines here.. and in dgn_main? */
+
+#include "hack.h"
+#include "date.h"
+#include "sp_lev.h"
+#ifdef STRICT_REF_DEF
+#include "tcap.h"
+#endif
+
+#ifdef MAC
+# if defined(__SC__) || defined(__MRC__)
+#  define MPWTOOL
+#  define PREFIX ":dungeon:"   /* place output files here */
+#  include <CursorCtl.h>
+# else
+#  if !defined(__MACH__)
+#   define PREFIX ":lib:"      /* place output files here */
+#  endif
+# endif
+#endif
+
+#ifdef WIN_CE
+#define PREFIX "\\nethack\\dat\\"
+#endif
+
+#ifndef MPWTOOL
+# define SpinCursor(x)
+#endif
+
+#if defined(AMIGA) && defined(DLB)
+# define PREFIX "NH:slib/"
+#endif
+
+#ifndef O_WRONLY
+#include <fcntl.h>
+#endif
+#ifndef O_CREAT        /* some older BSD systems do not define O_CREAT in <fcntl.h> */
+#include <sys/file.h>
+#endif
+#ifndef O_BINARY       /* used for micros, no-op for others */
+# define O_BINARY 0
+#endif
+
+#if defined(MICRO) || defined(WIN32)
+# define OMASK FCMASK
+#else
+# define OMASK 0644
+#endif
+
+#define ERR            (-1)
+
+#define NewTab(type, size)     (type **) alloc(sizeof(type *) * size)
+#define Free(ptr)              if(ptr) free((genericptr_t) (ptr))
+#define Write(fd, item, size)  if (write(fd, (genericptr_t)(item), size) != size) return FALSE;
+
+#if defined(__BORLANDC__) && !defined(_WIN32)
+extern unsigned _stklen = STKSIZ;
+#endif
+#define MAX_ERRORS     25
+
+extern int  NDECL (yyparse);
+extern void FDECL (init_yyin, (FILE *));
+extern void FDECL (init_yyout, (FILE *));
+
+int  FDECL (main, (int, char **));
+void FDECL (yyerror, (const char *));
+void FDECL (yywarning, (const char *));
+int  NDECL (yywrap);
+int FDECL(get_floor_type, (CHAR_P));
+int FDECL(get_room_type, (char *));
+int FDECL(get_trap_type, (char *));
+int FDECL(get_monster_id, (char *,CHAR_P));
+int FDECL(get_object_id, (char *,CHAR_P));
+boolean FDECL(check_monster_char, (CHAR_P));
+boolean FDECL(check_object_char, (CHAR_P));
+char FDECL(what_map_char, (CHAR_P));
+void FDECL(scan_map, (char *));
+void NDECL(wallify_map);
+boolean NDECL(check_subrooms);
+void FDECL(check_coord, (int,int,const char *));
+void NDECL(store_part);
+void NDECL(store_room);
+boolean FDECL(write_level_file, (char *,splev *,specialmaze *));
+void FDECL(free_rooms, (splev *));
+
+extern void NDECL(monst_init);
+extern void NDECL(objects_init);
+extern void NDECL(decl_init);
+
+static boolean FDECL(write_common_data, (int,int,lev_init *,long));
+static boolean FDECL(write_monsters, (int,char *,monster ***));
+static boolean FDECL(write_objects, (int,char *,object ***));
+static boolean FDECL(write_engravings, (int,char *,engraving ***));
+static boolean FDECL(write_maze, (int,specialmaze *));
+static boolean FDECL(write_rooms, (int,splev *));
+static void NDECL(init_obj_classes);
+
+static struct {
+       const char *name;
+       int type;
+} trap_types[] = {
+       { "arrow",      ARROW_TRAP },
+       { "dart",       DART_TRAP },
+       { "falling rock", ROCKTRAP },
+       { "board",      SQKY_BOARD },
+       { "bear",       BEAR_TRAP },
+       { "land mine",  LANDMINE },
+       { "rolling boulder",    ROLLING_BOULDER_TRAP },
+       { "sleep gas",  SLP_GAS_TRAP },
+       { "rust",       RUST_TRAP },
+       { "fire",       FIRE_TRAP },
+       { "pit",        PIT },
+       { "spiked pit", SPIKED_PIT },
+       { "hole",       HOLE },
+       { "trap door",  TRAPDOOR },
+       { "teleport",   TELEP_TRAP },
+       { "level teleport", LEVEL_TELEP },
+       { "magic portal",   MAGIC_PORTAL },
+       { "web",        WEB },
+       { "statue",     STATUE_TRAP },
+       { "magic",      MAGIC_TRAP },
+       { "anti magic", ANTI_MAGIC },
+       { "polymorph",  POLY_TRAP },
+       { 0, 0 }
+};
+
+static struct {
+       const char *name;
+       int type;
+} room_types[] = {
+       /* for historical reasons, room types are not contiguous numbers */
+       /* (type 1 is skipped) */
+       { "ordinary",    OROOM },
+       { "throne",      COURT },
+       { "swamp",       SWAMP },
+       { "vault",       VAULT },
+       { "beehive",     BEEHIVE },
+       { "morgue",      MORGUE },
+       { "barracks",    BARRACKS },
+       { "zoo",         ZOO },
+       { "delphi",      DELPHI },
+       { "temple",      TEMPLE },
+       { "anthole",     ANTHOLE },
+       { "cocknest",    COCKNEST },
+       { "leprehall",   LEPREHALL },
+       { "shop",        SHOPBASE },
+       { "armor shop",  ARMORSHOP },
+       { "scroll shop", SCROLLSHOP },
+       { "potion shop", POTIONSHOP },
+       { "weapon shop", WEAPONSHOP },
+       { "food shop",   FOODSHOP },
+       { "ring shop",   RINGSHOP },
+       { "wand shop",   WANDSHOP },
+       { "tool shop",   TOOLSHOP },
+       { "book shop",   BOOKSHOP },
+       { "candle shop", CANDLESHOP },
+       { 0, 0 }
+};
+
+const char *fname = "(stdin)";
+int fatal_error = 0;
+int want_warnings = 0;
+
+#ifdef FLEX23_BUG
+/* Flex 2.3 bug work around; not needed for 2.3.6 or later */
+int yy_more_len = 0;
+#endif
+
+extern char tmpmessage[];
+extern altar *tmpaltar[];
+extern lad *tmplad[];
+extern stair *tmpstair[];
+extern digpos *tmpdig[];
+extern digpos *tmppass[];
+extern char *tmpmap[];
+extern region *tmpreg[];
+extern lev_region *tmplreg[];
+extern door *tmpdoor[];
+extern room_door *tmprdoor[];
+extern trap *tmptrap[];
+extern monster *tmpmonst[];
+extern object *tmpobj[];
+extern drawbridge *tmpdb[];
+extern walk *tmpwalk[];
+extern gold *tmpgold[];
+extern fountain *tmpfountain[];
+extern sink *tmpsink[];
+extern pool *tmppool[];
+extern engraving *tmpengraving[];
+extern mazepart *tmppart[];
+extern room *tmproom[];
+
+extern int n_olist, n_mlist, n_plist;
+
+extern unsigned int nlreg, nreg, ndoor, ntrap, nmons, nobj;
+extern unsigned int ndb, nwalk, npart, ndig, npass, nlad, nstair;
+extern unsigned int naltar, ncorridor, nrooms, ngold, nengraving;
+extern unsigned int nfountain, npool, nsink;
+
+extern unsigned int max_x_map, max_y_map;
+
+extern int line_number, colon_line_number;
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+       FILE *fin;
+       int i;
+       boolean errors_encountered = FALSE;
+#if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__))
+       static char *mac_argv[] = {     "lev_comp",     /* dummy argv[0] */
+                               ":dat:Arch.des",
+                               ":dat:Barb.des",
+                               ":dat:Caveman.des",
+                               ":dat:Healer.des",
+                               ":dat:Knight.des",
+                               ":dat:Monk.des",
+                               ":dat:Priest.des",
+                               ":dat:Ranger.des",
+                               ":dat:Rogue.des",
+                               ":dat:Samurai.des",
+                               ":dat:Tourist.des",
+                               ":dat:Valkyrie.des",
+                               ":dat:Wizard.des",
+                               ":dat:bigroom.des",
+                               ":dat:castle.des",
+                               ":dat:endgame.des",
+                               ":dat:gehennom.des",
+                               ":dat:knox.des",
+                               ":dat:medusa.des",
+                               ":dat:mines.des",
+                               ":dat:oracle.des",
+                               ":dat:sokoban.des",
+                               ":dat:tower.des",
+                               ":dat:yendor.des"
+                               };
+
+       argc = SIZE(mac_argv);
+       argv = mac_argv;
+#endif
+       /* Note:  these initializers don't do anything except guarantee that
+               we're linked properly.
+       */
+       monst_init();
+       objects_init();
+       decl_init();
+       /* this one does something... */
+       init_obj_classes();
+
+       init_yyout(stdout);
+       if (argc == 1) {                /* Read standard input */
+           init_yyin(stdin);
+           (void) yyparse();
+           if (fatal_error > 0) {
+                   errors_encountered = TRUE;
+           }
+       } else {                        /* Otherwise every argument is a filename */
+           for(i=1; i<argc; i++) {
+                   fname = argv[i];
+                   if(!strcmp(fname, "-w")) {
+                       want_warnings++;
+                       continue;
+                   }
+                   fin = freopen(fname, "r", stdin);
+                   if (!fin) {
+                       (void) fprintf(stderr,"Can't open \"%s\" for input.\n",
+                                               fname);
+                       perror(fname);
+                       errors_encountered = TRUE;
+                   } else {
+                       init_yyin(fin);
+                       (void) yyparse();
+                       line_number = 1;
+                       if (fatal_error > 0) {
+                               errors_encountered = TRUE;
+                               fatal_error = 0;
+                       }
+                   }
+           }
+       }
+       exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
+
+/*
+ * Each time the parser detects an error, it uses this function.
+ * Here we take count of the errors. To continue farther than
+ * MAX_ERRORS wouldn't be reasonable.
+ * Assume that explicit calls from lev_comp.y have the 1st letter
+ * capitalized, to allow printing of the line containing the start of
+ * the current declaration, instead of the beginning of the next declaration.
+ */
+void
+yyerror(s)
+const char *s;
+{
+       (void) fprintf(stderr, "%s: line %d : %s\n", fname,
+               (*s >= 'A' && *s <= 'Z') ? colon_line_number : line_number, s);
+       if (++fatal_error > MAX_ERRORS) {
+               (void) fprintf(stderr,"Too many errors, good bye!\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+/*
+ * Just display a warning (that is : a non fatal error)
+ */
+void
+yywarning(s)
+const char *s;
+{
+       (void) fprintf(stderr, "%s: line %d : WARNING : %s\n",
+                               fname, colon_line_number, s);
+}
+
+/*
+ * Stub needed for lex interface.
+ */
+int
+yywrap()
+{
+       return 1;
+}
+
+/*
+ * Find the type of floor, knowing its char representation.
+ */
+int
+get_floor_type(c)
+char c;
+{
+       int val;
+
+       SpinCursor(3);
+       val = what_map_char(c);
+       if(val == INVALID_TYPE) {
+           val = ERR;
+           yywarning("Invalid fill character in MAZE declaration");
+       }
+       return val;
+}
+
+/*
+ * Find the type of a room in the table, knowing its name.
+ */
+int
+get_room_type(s)
+char *s;
+{
+       register int i;
+
+       SpinCursor(3);
+       for(i=0; room_types[i].name; i++)
+           if (!strcmp(s, room_types[i].name))
+               return ((int) room_types[i].type);
+       return ERR;
+}
+
+/*
+ * Find the type of a trap in the table, knowing its name.
+ */
+int
+get_trap_type(s)
+char *s;
+{
+       register int i;
+
+       SpinCursor(3);
+       for (i=0; trap_types[i].name; i++)
+           if(!strcmp(s,trap_types[i].name))
+               return trap_types[i].type;
+       return ERR;
+}
+
+/*
+ * Find the index of a monster in the table, knowing its name.
+ */
+int
+get_monster_id(s, c)
+char *s;
+char c;
+{
+       register int i, class;
+
+       SpinCursor(3);
+       class = c ? def_char_to_monclass(c) : 0;
+       if (class == MAXMCLASSES) return ERR;
+
+       for (i = LOW_PM; i < NUMMONS; i++)
+           if (!class || class == mons[i].mlet)
+               if (!strcmp(s, mons[i].mname)) return i;
+       return ERR;
+}
+
+/*
+ * Find the index of an object in the table, knowing its name.
+ */
+int
+get_object_id(s, c)
+char *s;
+char c;                /* class */
+{
+       int i, class;
+       const char *objname;
+
+       SpinCursor(3);
+       class = (c > 0) ? def_char_to_objclass(c) : 0;
+       if (class == MAXOCLASSES) return ERR;
+
+       for (i = class ? bases[class] : 0; i < NUM_OBJECTS; i++) {
+           if (class && objects[i].oc_class != class) break;
+           objname = obj_descr[i].oc_name;
+           if (objname && !strcmp(s, objname))
+               return i;
+       }
+       return ERR;
+}
+
+static void
+init_obj_classes()
+{
+       int i, class, prev_class;
+
+       prev_class = -1;
+       for (i = 0; i < NUM_OBJECTS; i++) {
+           class = objects[i].oc_class;
+           if (class != prev_class) {
+               bases[class] = i;
+               prev_class = class;
+           }
+       }
+}
+
+/*
+ * Is the character 'c' a valid monster class ?
+ */
+boolean
+check_monster_char(c)
+char c;
+{
+       return (def_char_to_monclass(c) != MAXMCLASSES);
+}
+
+/*
+ * Is the character 'c' a valid object class ?
+ */
+boolean
+check_object_char(c)
+char c;
+{
+       return (def_char_to_objclass(c) != MAXOCLASSES);
+}
+
+/*
+ * Convert .des map letter into floor type.
+ */
+char
+what_map_char(c)
+char c;
+{
+       SpinCursor(3);
+       switch(c) {
+                 case ' '  : return(STONE);
+                 case '#'  : return(CORR);
+                 case '.'  : return(ROOM);
+                 case '-'  : return(HWALL);
+                 case '|'  : return(VWALL);
+                 case '+'  : return(DOOR);
+                 case 'A'  : return(AIR);
+                 case 'B'  : return(CROSSWALL); /* hack: boundary location */
+                 case 'C'  : return(CLOUD);
+                 case 'S'  : return(SDOOR);
+                 case 'H'  : return(SCORR);
+                 case '{'  : return(FOUNTAIN);
+                 case '\\' : return(THRONE);
+                 case 'K'  :
+#ifdef SINKS
+                     return(SINK);
+#else
+                     yywarning("Sinks are not allowed in this version!  Ignoring...");
+                     return(ROOM);
+#endif
+                 case '}'  : return(MOAT);
+                 case 'P'  : return(POOL);
+                 case 'L'  : return(LAVAPOOL);
+                 case 'I'  : return(ICE);
+                 case 'W'  : return(WATER);
+                 case 'T'      : return (TREE);
+                 case 'F'      : return (IRONBARS);    /* Fe = iron */
+           }
+       return(INVALID_TYPE);
+}
+
+/*
+ * Yep! LEX gives us the map in a raw mode.
+ * Just analyze it here.
+ */
+void
+scan_map(map)
+char *map;
+{
+       register int i, len;
+       register char *s1, *s2;
+       int max_len = 0;
+       int max_hig = 0;
+       char msg[256];
+
+       /* First, strip out digits 0-9 (line numbering) */
+       for (s1 = s2 = map; *s1; s1++)
+           if (*s1 < '0' || *s1 > '9')
+               *s2++ = *s1;
+       *s2 = '\0';
+
+       /* Second, find the max width of the map */
+       s1 = map;
+       while (s1 && *s1) {
+               s2 = index(s1, '\n');
+               if (s2) {
+                       len = (int) (s2 - s1);
+                       s1 = s2 + 1;
+               } else {
+                       len = (int) strlen(s1);
+                       s1 = (char *) 0;
+               }
+               if (len > max_len) max_len = len;
+       }
+
+       /* Then parse it now */
+       while (map && *map) {
+               tmpmap[max_hig] = (char *) alloc(max_len);
+               s1 = index(map, '\n');
+               if (s1) {
+                       len = (int) (s1 - map);
+                       s1++;
+               } else {
+                       len = (int) strlen(map);
+                       s1 = map + len;
+               }
+               for(i=0; i<len; i++)
+                 if((tmpmap[max_hig][i] = what_map_char(map[i])) == INVALID_TYPE) {
+                     Sprintf(msg,
+                        "Invalid character @ (%d, %d) - replacing with stone",
+                             max_hig, i);
+                     yywarning(msg);
+                     tmpmap[max_hig][i] = STONE;
+                   }
+               while(i < max_len)
+                   tmpmap[max_hig][i++] = STONE;
+               map = s1;
+               max_hig++;
+       }
+
+       /* Memorize boundaries */
+
+       max_x_map = max_len - 1;
+       max_y_map = max_hig - 1;
+
+       /* Store the map into the mazepart structure */
+
+       if(max_len > MAP_X_LIM || max_hig > MAP_Y_LIM) {
+           Sprintf(msg, "Map too large! (max %d x %d)", MAP_X_LIM, MAP_Y_LIM);
+           yyerror(msg);
+       }
+
+       tmppart[npart]->xsize = max_len;
+       tmppart[npart]->ysize = max_hig;
+       tmppart[npart]->map = (char **) alloc(max_hig*sizeof(char *));
+       for(i = 0; i< max_hig; i++)
+           tmppart[npart]->map[i] = tmpmap[i];
+}
+
+/*
+ *     If we have drawn a map without walls, this allows us to
+ *     auto-magically wallify it.
+ */
+#define Map_point(x,y) *(tmppart[npart]->map[y] + x)
+
+void
+wallify_map()
+{
+       unsigned int x, y, xx, yy, lo_xx, lo_yy, hi_xx, hi_yy;
+
+       for (y = 0; y <= max_y_map; y++) {
+           SpinCursor(3);
+           lo_yy = (y > 0) ? y - 1 : 0;
+           hi_yy = (y < max_y_map) ? y + 1 : max_y_map;
+           for (x = 0; x <= max_x_map; x++) {
+               if (Map_point(x,y) != STONE) continue;
+               lo_xx = (x > 0) ? x - 1 : 0;
+               hi_xx = (x < max_x_map) ? x + 1 : max_x_map;
+               for (yy = lo_yy; yy <= hi_yy; yy++)
+                   for (xx = lo_xx; xx <= hi_xx; xx++)
+                       if (IS_ROOM(Map_point(xx,yy)) ||
+                               Map_point(xx,yy) == CROSSWALL) {
+                           Map_point(x,y) = (yy != y) ? HWALL : VWALL;
+                           yy = hi_yy;         /* end `yy' loop */
+                           break;              /* end `xx' loop */
+                       }
+           }
+       }
+}
+
+/*
+ * We need to check the subrooms apartenance to an existing room.
+ */
+boolean
+check_subrooms()
+{
+       unsigned i, j, n_subrooms;
+       boolean found, ok = TRUE;
+       char    *last_parent, msg[256];
+
+       for (i = 0; i < nrooms; i++)
+           if (tmproom[i]->parent) {
+               found = FALSE;
+               for(j = 0; j < nrooms; j++)
+                   if (tmproom[j]->name &&
+                           !strcmp(tmproom[i]->parent, tmproom[j]->name)) {
+                       found = TRUE;
+                       break;
+                   }
+               if (!found) {
+                   Sprintf(msg,
+                           "Subroom error : parent room '%s' not found!",
+                           tmproom[i]->parent);
+                   yyerror(msg);
+                   ok = FALSE;
+               }
+           }
+
+       msg[0] = '\0';
+       last_parent = msg;
+       for (i = 0; i < nrooms; i++)
+           if (tmproom[i]->parent) {
+               n_subrooms = 0;
+               for(j = i; j < nrooms; j++) {
+/*
+ *     This is by no means perfect, but should cut down the duplicate error
+ *     messages by over 90%.  The only problem will be when either subrooms
+ *     are mixed in the level definition (not likely but possible) or rooms
+ *     have subrooms that have subrooms.
+ */
+                   if (!strcmp(tmproom[i]->parent, last_parent)) continue;
+                   if (tmproom[j]->parent &&
+                           !strcmp(tmproom[i]->parent, tmproom[j]->parent)) {
+                       n_subrooms++;
+                       if(n_subrooms > MAX_SUBROOMS) {
+
+                           Sprintf(msg,
+             "Subroom error: too many subrooms attached to parent room '%s'!",
+                                   tmproom[i]->parent);
+                           yyerror(msg);
+                           last_parent = tmproom[i]->parent;
+                           ok = FALSE;
+                           break;
+                       }
+                   }
+               }
+           }
+       return ok;
+}
+
+/*
+ * Check that coordinates (x,y) are roomlike locations.
+ * Print warning "str" if they aren't.
+ */
+void
+check_coord(x, y, str)
+int x, y;
+const char *str;
+{
+    char ebuf[60];
+
+    if (x >= 0 && y >= 0 && x <= (int)max_x_map && y <= (int)max_y_map &&
+       (IS_ROCK(tmpmap[y][x]) || IS_DOOR(tmpmap[y][x]))) {
+       Sprintf(ebuf, "%s placed in wall at (%02d,%02d)?!", str, x, y);
+       yywarning(ebuf);
+    }
+}
+
+/*
+ * Here we want to store the maze part we just got.
+ */
+void
+store_part()
+{
+       register unsigned i;
+
+       /* Ok, We got the whole part, now we store it. */
+
+       /* The Regions */
+
+       if ((tmppart[npart]->nreg = nreg) != 0) {
+               tmppart[npart]->regions = NewTab(region, nreg);
+               for(i=0;i<nreg;i++)
+                   tmppart[npart]->regions[i] = tmpreg[i];
+       }
+       nreg = 0;
+
+       /* The Level Regions */
+
+       if ((tmppart[npart]->nlreg = nlreg) != 0) {
+               tmppart[npart]->lregions = NewTab(lev_region, nlreg);
+               for(i=0;i<nlreg;i++)
+                   tmppart[npart]->lregions[i] = tmplreg[i];
+       }
+       nlreg = 0;
+
+       /* the doors */
+
+       if ((tmppart[npart]->ndoor = ndoor) != 0) {
+               tmppart[npart]->doors = NewTab(door, ndoor);
+               for(i=0;i<ndoor;i++)
+                   tmppart[npart]->doors[i] = tmpdoor[i];
+       }
+       ndoor = 0;
+
+       /* the drawbridges */
+
+       if ((tmppart[npart]->ndrawbridge = ndb) != 0) {
+               tmppart[npart]->drawbridges = NewTab(drawbridge, ndb);
+               for(i=0;i<ndb;i++)
+                   tmppart[npart]->drawbridges[i] = tmpdb[i];
+       }
+       ndb = 0;
+
+       /* The walkmaze directives */
+
+       if ((tmppart[npart]->nwalk = nwalk) != 0) {
+               tmppart[npart]->walks = NewTab(walk, nwalk);
+               for(i=0;i<nwalk;i++)
+                   tmppart[npart]->walks[i] = tmpwalk[i];
+       }
+       nwalk = 0;
+
+       /* The non_diggable directives */
+
+       if ((tmppart[npart]->ndig = ndig) != 0) {
+               tmppart[npart]->digs = NewTab(digpos, ndig);
+               for(i=0;i<ndig;i++)
+                   tmppart[npart]->digs[i] = tmpdig[i];
+       }
+       ndig = 0;
+
+       /* The non_passwall directives */
+
+       if ((tmppart[npart]->npass = npass) != 0) {
+               tmppart[npart]->passs = NewTab(digpos, npass);
+               for(i=0;i<npass;i++)
+                   tmppart[npart]->passs[i] = tmppass[i];
+       }
+       npass = 0;
+
+       /* The ladders */
+
+       if ((tmppart[npart]->nlad = nlad) != 0) {
+               tmppart[npart]->lads = NewTab(lad, nlad);
+               for(i=0;i<nlad;i++)
+                   tmppart[npart]->lads[i] = tmplad[i];
+       }
+       nlad = 0;
+
+       /* The stairs */
+
+       if ((tmppart[npart]->nstair = nstair) != 0) {
+               tmppart[npart]->stairs = NewTab(stair, nstair);
+               for(i=0;i<nstair;i++)
+                   tmppart[npart]->stairs[i] = tmpstair[i];
+       }
+       nstair = 0;
+
+       /* The altars */
+       if ((tmppart[npart]->naltar = naltar) != 0) {
+               tmppart[npart]->altars = NewTab(altar, naltar);
+               for(i=0;i<naltar;i++)
+                   tmppart[npart]->altars[i] = tmpaltar[i];
+       }
+       naltar = 0;
+
+       /* The fountains */
+
+       if ((tmppart[npart]->nfountain = nfountain) != 0) {
+               tmppart[npart]->fountains = NewTab(fountain, nfountain);
+               for(i=0;i<nfountain;i++)
+                   tmppart[npart]->fountains[i] = tmpfountain[i];
+       }
+       nfountain = 0;
+
+       /* the traps */
+
+       if ((tmppart[npart]->ntrap = ntrap) != 0) {
+               tmppart[npart]->traps = NewTab(trap, ntrap);
+               for(i=0;i<ntrap;i++)
+                   tmppart[npart]->traps[i] = tmptrap[i];
+       }
+       ntrap = 0;
+
+       /* the monsters */
+
+       if ((tmppart[npart]->nmonster = nmons) != 0) {
+               tmppart[npart]->monsters = NewTab(monster, nmons);
+               for(i=0;i<nmons;i++)
+                   tmppart[npart]->monsters[i] = tmpmonst[i];
+       } else
+               tmppart[npart]->monsters = 0;
+       nmons = 0;
+
+       /* the objects */
+
+       if ((tmppart[npart]->nobject = nobj) != 0) {
+               tmppart[npart]->objects = NewTab(object, nobj);
+               for(i=0;i<nobj;i++)
+                   tmppart[npart]->objects[i] = tmpobj[i];
+       } else
+               tmppart[npart]->objects = 0;
+       nobj = 0;
+
+       /* The gold piles */
+
+       if ((tmppart[npart]->ngold = ngold) != 0) {
+               tmppart[npart]->golds = NewTab(gold, ngold);
+               for(i=0;i<ngold;i++)
+                   tmppart[npart]->golds[i] = tmpgold[i];
+       }
+       ngold = 0;
+
+       /* The engravings */
+
+       if ((tmppart[npart]->nengraving = nengraving) != 0) {
+               tmppart[npart]->engravings = NewTab(engraving, nengraving);
+               for(i=0;i<nengraving;i++)
+                   tmppart[npart]->engravings[i] = tmpengraving[i];
+       } else
+               tmppart[npart]->engravings = 0;
+       nengraving = 0;
+
+       npart++;
+       n_plist = n_mlist = n_olist = 0;
+}
+
+/*
+ * Here we want to store the room part we just got.
+ */
+void
+store_room()
+{
+       register unsigned i;
+
+       /* Ok, We got the whole room, now we store it. */
+
+       /* the doors */
+
+       if ((tmproom[nrooms]->ndoor = ndoor) != 0) {
+               tmproom[nrooms]->doors = NewTab(room_door, ndoor);
+               for(i=0;i<ndoor;i++)
+                   tmproom[nrooms]->doors[i] = tmprdoor[i];
+       }
+       ndoor = 0;
+
+       /* The stairs */
+
+       if ((tmproom[nrooms]->nstair = nstair) != 0) {
+               tmproom[nrooms]->stairs = NewTab(stair, nstair);
+               for(i=0;i<nstair;i++)
+                   tmproom[nrooms]->stairs[i] = tmpstair[i];
+       }
+       nstair = 0;
+
+       /* The altars */
+       if ((tmproom[nrooms]->naltar = naltar) != 0) {
+               tmproom[nrooms]->altars = NewTab(altar, naltar);
+               for(i=0;i<naltar;i++)
+                   tmproom[nrooms]->altars[i] = tmpaltar[i];
+       }
+       naltar = 0;
+
+       /* The fountains */
+
+       if ((tmproom[nrooms]->nfountain = nfountain) != 0) {
+               tmproom[nrooms]->fountains = NewTab(fountain, nfountain);
+               for(i=0;i<nfountain;i++)
+                   tmproom[nrooms]->fountains[i] = tmpfountain[i];
+       }
+       nfountain = 0;
+
+       /* The sinks */
+
+       if ((tmproom[nrooms]->nsink = nsink) != 0) {
+               tmproom[nrooms]->sinks = NewTab(sink, nsink);
+               for(i=0;i<nsink;i++)
+                   tmproom[nrooms]->sinks[i] = tmpsink[i];
+       }
+       nsink = 0;
+
+       /* The pools */
+
+       if ((tmproom[nrooms]->npool = npool) != 0) {
+               tmproom[nrooms]->pools = NewTab(pool, npool);
+               for(i=0;i<npool;i++)
+                   tmproom[nrooms]->pools[i] = tmppool[i];
+       }
+       npool = 0;
+
+       /* the traps */
+
+       if ((tmproom[nrooms]->ntrap = ntrap) != 0) {
+               tmproom[nrooms]->traps = NewTab(trap, ntrap);
+               for(i=0;i<ntrap;i++)
+                   tmproom[nrooms]->traps[i] = tmptrap[i];
+       }
+       ntrap = 0;
+
+       /* the monsters */
+
+       if ((tmproom[nrooms]->nmonster = nmons) != 0) {
+               tmproom[nrooms]->monsters = NewTab(monster, nmons);
+               for(i=0;i<nmons;i++)
+                   tmproom[nrooms]->monsters[i] = tmpmonst[i];
+       } else
+               tmproom[nrooms]->monsters = 0;
+       nmons = 0;
+
+       /* the objects */
+
+       if ((tmproom[nrooms]->nobject = nobj) != 0) {
+               tmproom[nrooms]->objects = NewTab(object, nobj);
+               for(i=0;i<nobj;i++)
+                   tmproom[nrooms]->objects[i] = tmpobj[i];
+       } else
+               tmproom[nrooms]->objects = 0;
+       nobj = 0;
+
+       /* The gold piles */
+
+       if ((tmproom[nrooms]->ngold = ngold) != 0) {
+               tmproom[nrooms]->golds = NewTab(gold, ngold);
+               for(i=0;i<ngold;i++)
+                   tmproom[nrooms]->golds[i] = tmpgold[i];
+       }
+       ngold = 0;
+
+       /* The engravings */
+
+       if ((tmproom[nrooms]->nengraving = nengraving) != 0) {
+               tmproom[nrooms]->engravings = NewTab(engraving, nengraving);
+               for(i=0;i<nengraving;i++)
+                   tmproom[nrooms]->engravings[i] = tmpengraving[i];
+       } else
+               tmproom[nrooms]->engravings = 0;
+       nengraving = 0;
+
+       nrooms++;
+}
+
+/*
+ * Output some info common to all special levels.
+ */
+static boolean
+write_common_data(fd, typ, init, flgs)
+int fd, typ;
+lev_init *init;
+long flgs;
+{
+       char c;
+       uchar len;
+       static struct version_info version_data = {
+                       VERSION_NUMBER, VERSION_FEATURES,
+                       VERSION_SANITY1, VERSION_SANITY2
+       };
+
+       Write(fd, &version_data, sizeof version_data);
+       c = typ;
+       Write(fd, &c, sizeof(c));       /* 1 byte header */
+       Write(fd, init, sizeof(lev_init));
+       Write(fd, &flgs, sizeof flgs);
+
+       len = (uchar) strlen(tmpmessage);
+       Write(fd, &len, sizeof len);
+       if (len) Write(fd, tmpmessage, (int) len);
+       tmpmessage[0] = '\0';
+       return TRUE;
+}
+
+/*
+ * Output monster info, which needs string fixups, then release memory.
+ */
+static boolean
+write_monsters(fd, nmonster_p, monsters_p)
+int fd;
+char *nmonster_p;
+monster ***monsters_p;
+{
+       monster *m;
+       char *name, *appr;
+       int j, n = (int)*nmonster_p;
+
+       Write(fd, nmonster_p, sizeof *nmonster_p);
+       for (j = 0; j < n; j++) {
+           m = (*monsters_p)[j];
+           name = m->name.str;
+           appr = m->appear_as.str;
+           m->name.str = m->appear_as.str = 0;
+           m->name.len = name ? strlen(name) : 0;
+           m->appear_as.len = appr ? strlen(appr) : 0;
+           Write(fd, m, sizeof *m);
+           if (name) {
+               Write(fd, name, m->name.len);
+               Free(name);
+           }
+           if (appr) {
+               Write(fd, appr, m->appear_as.len);
+               Free(appr);
+           }
+           Free(m);
+       }
+       if (*monsters_p) {
+           Free(*monsters_p);
+           *monsters_p = 0;
+       }
+       *nmonster_p = 0;
+       return TRUE;
+}
+
+/*
+ * Output object info, which needs string fixup, then release memory.
+ */
+static boolean
+write_objects(fd, nobject_p, objects_p)
+int fd;
+char *nobject_p;
+object ***objects_p;
+{
+       object *o;
+       char *name;
+       int j, n = (int)*nobject_p;
+
+       Write(fd, nobject_p, sizeof *nobject_p);
+       for (j = 0; j < n; j++) {
+           o = (*objects_p)[j];
+           name = o->name.str;
+           o->name.str = 0;    /* reset in case `len' is narrower */
+           o->name.len = name ? strlen(name) : 0;
+           Write(fd, o, sizeof *o);
+           if (name) {
+               Write(fd, name, o->name.len);
+               Free(name);
+           }
+           Free(o);
+       }
+       if (*objects_p) {
+           Free(*objects_p);
+           *objects_p = 0;
+       }
+       *nobject_p = 0;
+       return TRUE;
+}
+
+/*
+ * Output engraving info, which needs string fixup, then release memory.
+ */
+static boolean
+write_engravings(fd, nengraving_p, engravings_p)
+int fd;
+char *nengraving_p;
+engraving ***engravings_p;
+{
+       engraving *e;
+       char *engr;
+       int j, n = (int)*nengraving_p;
+
+       Write(fd, nengraving_p, sizeof *nengraving_p);
+       for (j = 0; j < n; j++) {
+           e = (*engravings_p)[j];
+           engr = e->engr.str;
+           e->engr.str = 0;    /* reset in case `len' is narrower */
+           e->engr.len = strlen(engr);
+           Write(fd, e, sizeof *e);
+           Write(fd, engr, e->engr.len);
+           Free(engr);
+           Free(e);
+       }
+       if (*engravings_p) {
+           Free(*engravings_p);
+           *engravings_p = 0;
+       }
+       *nengraving_p = 0;
+       return TRUE;
+}
+
+/*
+ * Open and write maze or rooms file, based on which pointer is non-null.
+ * Return TRUE on success, FALSE on failure.
+ */
+boolean
+write_level_file(filename, room_level, maze_level)
+char *filename;
+splev *room_level;
+specialmaze *maze_level;
+{
+       int fout;
+       char lbuf[60];
+
+       lbuf[0] = '\0';
+#ifdef PREFIX
+       Strcat(lbuf, PREFIX);
+#endif
+       Strcat(lbuf, filename);
+       Strcat(lbuf, LEV_EXT);
+
+#if defined(MAC) && (defined(__SC__) || defined(__MRC__))
+       fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY);
+#else
+       fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK);
+#endif
+       if (fout < 0) return FALSE;
+
+       if (room_level) {
+           if (!write_rooms(fout, room_level))
+               return FALSE;
+       } else if (maze_level) {
+           if (!write_maze(fout, maze_level))
+               return FALSE;
+       } else
+           panic("write_level_file");
+
+       (void) close(fout);
+       return TRUE;
+}
+
+/*
+ * Here we write the structure of the maze in the specified file (fd).
+ * Also, we have to free the memory allocated via alloc().
+ */
+static boolean
+write_maze(fd, maze)
+int fd;
+specialmaze *maze;
+{
+       short i,j;
+       mazepart *pt;
+
+       if (!write_common_data(fd, SP_LEV_MAZE, &(maze->init_lev), maze->flags))
+           return FALSE;
+
+       Write(fd, &(maze->filling), sizeof(maze->filling));
+       Write(fd, &(maze->numpart), sizeof(maze->numpart));
+                                        /* Number of parts */
+       for(i=0;i<maze->numpart;i++) {
+           pt = maze->parts[i];
+
+           /* First, write the map */
+
+           Write(fd, &(pt->halign), sizeof(pt->halign));
+           Write(fd, &(pt->valign), sizeof(pt->valign));
+           Write(fd, &(pt->xsize), sizeof(pt->xsize));
+           Write(fd, &(pt->ysize), sizeof(pt->ysize));
+           for(j=0;j<pt->ysize;j++) {
+               if(!maze->init_lev.init_present ||
+                  pt->xsize > 1 || pt->ysize > 1) {
+#if !defined(_MSC_VER) && !defined(__BORLANDC__)
+                       Write(fd, pt->map[j], pt->xsize * sizeof *pt->map[j]);
+#else
+                       /*
+                        * On MSVC and Borland C compilers the Write macro above caused:
+                        * warning '!=' : signed/unsigned mismatch
+                        */
+                       unsigned reslt, sz = pt->xsize * sizeof *pt->map[j];
+                       reslt = write(fd, (genericptr_t)(pt->map[j]), sz);
+                       if (reslt != sz) return FALSE;
+#endif
+               }
+               Free(pt->map[j]);
+           }
+           Free(pt->map);
+
+           /* level region stuff */
+           Write(fd, &pt->nlreg, sizeof pt->nlreg);
+           for (j = 0; j < pt->nlreg; j++) {
+               lev_region *l = pt->lregions[j];
+               char *rname = l->rname.str;
+               l->rname.str = 0;       /* reset in case `len' is narrower */
+               l->rname.len = rname ? strlen(rname) : 0;
+               Write(fd, l, sizeof *l);
+               if (rname) {
+                   Write(fd, rname, l->rname.len);
+                   Free(rname);
+               }
+               Free(l);
+           }
+           if (pt->nlreg > 0)
+               Free(pt->lregions);
+
+           /* The random registers */
+           Write(fd, &(pt->nrobjects), sizeof(pt->nrobjects));
+           if(pt->nrobjects) {
+                   Write(fd, pt->robjects, pt->nrobjects);
+                   Free(pt->robjects);
+           }
+           Write(fd, &(pt->nloc), sizeof(pt->nloc));
+           if(pt->nloc) {
+                   Write(fd, pt->rloc_x, pt->nloc);
+                   Write(fd, pt->rloc_y, pt->nloc);
+                   Free(pt->rloc_x);
+                   Free(pt->rloc_y);
+           }
+           Write(fd, &(pt->nrmonst), sizeof(pt->nrmonst));
+           if(pt->nrmonst) {
+                   Write(fd, pt->rmonst, pt->nrmonst);
+                   Free(pt->rmonst);
+           }
+
+           /* subrooms */
+           Write(fd, &(pt->nreg), sizeof(pt->nreg));
+           for(j=0;j<pt->nreg;j++) {
+                   Write(fd, pt->regions[j], sizeof(region));
+                   Free(pt->regions[j]);
+           }
+           if(pt->nreg > 0)
+                   Free(pt->regions);
+
+           /* the doors */
+           Write(fd, &(pt->ndoor), sizeof(pt->ndoor));
+           for(j=0;j<pt->ndoor;j++) {
+                   Write(fd, pt->doors[j], sizeof(door));
+                   Free(pt->doors[j]);
+           }
+           if (pt->ndoor > 0)
+                   Free(pt->doors);
+
+           /* The drawbridges */
+           Write(fd, &(pt->ndrawbridge), sizeof(pt->ndrawbridge));
+           for(j=0;j<pt->ndrawbridge;j++) {
+                   Write(fd, pt->drawbridges[j], sizeof(drawbridge));
+                   Free(pt->drawbridges[j]);
+           }
+           if(pt->ndrawbridge > 0)
+                   Free(pt->drawbridges);
+
+           /* The mazewalk directives */
+           Write(fd, &(pt->nwalk), sizeof(pt->nwalk));
+           for(j=0; j<pt->nwalk; j++) {
+                   Write(fd, pt->walks[j], sizeof(walk));
+                   Free(pt->walks[j]);
+           }
+           if (pt->nwalk > 0)
+                   Free(pt->walks);
+
+           /* The non_diggable directives */
+           Write(fd, &(pt->ndig), sizeof(pt->ndig));
+           for(j=0;j<pt->ndig;j++) {
+                   Write(fd, pt->digs[j], sizeof(digpos));
+                   Free(pt->digs[j]);
+           }
+           if (pt->ndig > 0)
+                   Free(pt->digs);
+
+           /* The non_passwall directives */
+           Write(fd, &(pt->npass), sizeof(pt->npass));
+           for(j=0;j<pt->npass;j++) {
+                   Write(fd, pt->passs[j], sizeof(digpos));
+                   Free(pt->passs[j]);
+           }
+           if (pt->npass > 0)
+                   Free(pt->passs);
+
+           /* The ladders */
+           Write(fd, &(pt->nlad), sizeof(pt->nlad));
+           for(j=0;j<pt->nlad;j++) {
+                   Write(fd, pt->lads[j], sizeof(lad));
+                   Free(pt->lads[j]);
+           }
+           if (pt->nlad > 0)
+                   Free(pt->lads);
+
+           /* The stairs */
+           Write(fd, &(pt->nstair), sizeof(pt->nstair));
+           for(j=0;j<pt->nstair;j++) {
+                   Write(fd, pt->stairs[j], sizeof(stair));
+                   Free(pt->stairs[j]);
+           }
+           if (pt->nstair > 0)
+                   Free(pt->stairs);
+
+           /* The altars */
+           Write(fd, &(pt->naltar), sizeof(pt->naltar));
+           for(j=0;j<pt->naltar;j++) {
+                   Write(fd, pt->altars[j], sizeof(altar));
+                   Free(pt->altars[j]);
+           }
+           if (pt->naltar > 0)
+                   Free(pt->altars);
+
+           /* The fountains */
+           Write(fd, &(pt->nfountain), sizeof(pt->nfountain));
+           for(j=0;j<pt->nfountain;j++) {
+               Write(fd, pt->fountains[j], sizeof(fountain));
+               Free(pt->fountains[j]);
+           }
+           if (pt->nfountain > 0)
+                   Free(pt->fountains);
+
+           /* The traps */
+           Write(fd, &(pt->ntrap), sizeof(pt->ntrap));
+           for(j=0;j<pt->ntrap;j++) {
+                   Write(fd, pt->traps[j], sizeof(trap));
+                   Free(pt->traps[j]);
+           }
+           if (pt->ntrap)
+                   Free(pt->traps);
+
+           /* The monsters */
+           if (!write_monsters(fd, &pt->nmonster, &pt->monsters))
+                   return FALSE;
+
+           /* The objects */
+           if (!write_objects(fd, &pt->nobject, &pt->objects))
+                   return FALSE;
+
+           /* The gold piles */
+           Write(fd, &(pt->ngold), sizeof(pt->ngold));
+           for(j=0;j<pt->ngold;j++) {
+                   Write(fd, pt->golds[j], sizeof(gold));
+                   Free(pt->golds[j]);
+           }
+           if (pt->ngold > 0)
+                   Free(pt->golds);
+
+           /* The engravings */
+           if (!write_engravings(fd, &pt->nengraving, &pt->engravings))
+                   return FALSE;
+
+           Free(pt);
+       }
+
+       Free(maze->parts);
+       maze->parts = (mazepart **)0;
+       maze->numpart = 0;
+       return TRUE;
+}
+
+/*
+ * Here we write the structure of the room level in the specified file (fd).
+ */
+static boolean
+write_rooms(fd, lev)
+int fd;
+splev *lev;
+{
+       short i,j, size;
+       room *pt;
+
+       if (!write_common_data(fd, SP_LEV_ROOMS, &(lev->init_lev), lev->flags))
+               return FALSE;
+
+       /* Random registers */
+
+       Write(fd, &lev->nrobjects, sizeof(lev->nrobjects));
+       if (lev->nrobjects)
+               Write(fd, lev->robjects, lev->nrobjects);
+       Write(fd, &lev->nrmonst, sizeof(lev->nrmonst));
+       if (lev->nrmonst)
+               Write(fd, lev->rmonst, lev->nrmonst);
+
+       Write(fd, &(lev->nroom), sizeof(lev->nroom));
+                                                       /* Number of rooms */
+       for(i=0;i<lev->nroom;i++) {
+               pt = lev->rooms[i];
+
+               /* Room characteristics */
+
+               size = (short) (pt->name ? strlen(pt->name) : 0);
+               Write(fd, &size, sizeof(size));
+               if (size)
+                       Write(fd, pt->name, size);
+
+               size = (short) (pt->parent ? strlen(pt->parent) : 0);
+               Write(fd, &size, sizeof(size));
+               if (size)
+                       Write(fd, pt->parent, size);
+
+               Write(fd, &(pt->x), sizeof(pt->x));
+               Write(fd, &(pt->y), sizeof(pt->y));
+               Write(fd, &(pt->w), sizeof(pt->w));
+               Write(fd, &(pt->h), sizeof(pt->h));
+               Write(fd, &(pt->xalign), sizeof(pt->xalign));
+               Write(fd, &(pt->yalign), sizeof(pt->yalign));
+               Write(fd, &(pt->rtype), sizeof(pt->rtype));
+               Write(fd, &(pt->chance), sizeof(pt->chance));
+               Write(fd, &(pt->rlit), sizeof(pt->rlit));
+               Write(fd, &(pt->filled), sizeof(pt->filled));
+
+               /* the doors */
+               Write(fd, &(pt->ndoor), sizeof(pt->ndoor));
+               for(j=0;j<pt->ndoor;j++)
+                       Write(fd, pt->doors[j], sizeof(room_door));
+
+               /* The stairs */
+               Write(fd, &(pt->nstair), sizeof(pt->nstair));
+               for(j=0;j<pt->nstair;j++)
+                       Write(fd, pt->stairs[j], sizeof(stair));
+
+               /* The altars */
+               Write(fd, &(pt->naltar), sizeof(pt->naltar));
+               for(j=0;j<pt->naltar;j++)
+                       Write(fd, pt->altars[j], sizeof(altar));
+
+               /* The fountains */
+               Write(fd, &(pt->nfountain), sizeof(pt->nfountain));
+               for(j=0;j<pt->nfountain;j++)
+                       Write(fd, pt->fountains[j], sizeof(fountain));
+
+               /* The sinks */
+               Write(fd, &(pt->nsink), sizeof(pt->nsink));
+               for(j=0;j<pt->nsink;j++)
+                       Write(fd, pt->sinks[j], sizeof(sink));
+
+               /* The pools */
+               Write(fd, &(pt->npool), sizeof(pt->npool));
+               for(j=0;j<pt->npool;j++)
+                       Write(fd, pt->pools[j], sizeof(pool));
+
+               /* The traps */
+               Write(fd, &(pt->ntrap), sizeof(pt->ntrap));
+               for(j=0;j<pt->ntrap;j++)
+                       Write(fd, pt->traps[j], sizeof(trap));
+
+               /* The monsters */
+               if (!write_monsters(fd, &pt->nmonster, &pt->monsters))
+                       return FALSE;
+
+               /* The objects */
+               if (!write_objects(fd, &pt->nobject, &pt->objects))
+                       return FALSE;
+
+               /* The gold piles */
+               Write(fd, &(pt->ngold), sizeof(pt->ngold));
+               for(j=0;j<pt->ngold;j++)
+                       Write(fd, pt->golds[j], sizeof(gold));
+
+               /* The engravings */
+               if (!write_engravings(fd, &pt->nengraving, &pt->engravings))
+                       return FALSE;
+
+       }
+
+       /* The corridors */
+       Write(fd, &lev->ncorr, sizeof(lev->ncorr));
+       for (i=0; i < lev->ncorr; i++)
+               Write(fd, lev->corrs[i], sizeof(corridor));
+       return TRUE;
+}
+
+/*
+ * Release memory allocated to a rooms-style special level; maze-style
+ * levels have the fields freed as they're written; monsters, objects, and
+ * engravings are freed as written for both styles, so not handled here.
+ */
+void
+free_rooms(lev)
+splev *lev;
+{
+       room *r;
+       int j, n = lev->nroom;
+
+       while(n--) {
+               r = lev->rooms[n];
+               Free(r->name);
+               Free(r->parent);
+               if ((j = r->ndoor) != 0) {
+                       while(j--)
+                               Free(r->doors[j]);
+                       Free(r->doors);
+               }
+               if ((j = r->nstair) != 0) {
+                       while(j--)
+                               Free(r->stairs[j]);
+                       Free(r->stairs);
+               }
+               if ((j = r->naltar) != 0) {
+                       while (j--)
+                               Free(r->altars[j]);
+                       Free(r->altars);
+               }
+               if ((j = r->nfountain) != 0) {
+                       while(j--)
+                               Free(r->fountains[j]);
+                       Free(r->fountains);
+               }
+               if ((j = r->nsink) != 0) {
+                       while(j--)
+                               Free(r->sinks[j]);
+                       Free(r->sinks);
+               }
+               if ((j = r->npool) != 0) {
+                       while(j--)
+                               Free(r->pools[j]);
+                       Free(r->pools);
+               }
+               if ((j = r->ntrap) != 0) {
+                       while (j--)
+                               Free(r->traps[j]);
+                       Free(r->traps);
+               }
+               if ((j = r->ngold) != 0) {
+                       while(j--)
+                               Free(r->golds[j]);
+                       Free(r->golds);
+               }
+               Free(r);
+               lev->rooms[n] = (room *)0;
+       }
+       Free(lev->rooms);
+       lev->rooms = (room **)0;
+       lev->nroom = 0;
+
+       for (j = 0; j < lev->ncorr; j++) {
+               Free(lev->corrs[j]);
+               lev->corrs[j] = (corridor *)0;
+       }
+       Free(lev->corrs);
+       lev->corrs = (corridor **)0;
+       lev->ncorr = 0;
+
+       Free(lev->robjects);
+       lev->robjects = (char *)0;
+       lev->nrobjects = 0;
+       Free(lev->rmonst);
+       lev->rmonst = (char *)0;
+       lev->nrmonst = 0;
+}
+
+#ifdef STRICT_REF_DEF
+/*
+ * Any globals declared in hack.h and descendents which aren't defined
+ * in the modules linked into lev_comp should be defined here.  These
+ * definitions can be dummies:  their sizes shouldn't matter as long as
+ * as their types are correct; actual values are irrelevant.
+ */
+#define ARBITRARY_SIZE 1
+/* attrib.c */
+struct attribs attrmax, attrmin;
+/* files.c */
+const char *configfile;
+char lock[ARBITRARY_SIZE];
+char SAVEF[ARBITRARY_SIZE];
+# ifdef MICRO
+char SAVEP[ARBITRARY_SIZE];
+# endif
+/* termcap.c */
+struct tc_lcl_data tc_lcl_data;
+# ifdef TEXTCOLOR
+#  ifdef TOS
+const char *hilites[CLR_MAX];
+#  else
+char NEARDATA *hilites[CLR_MAX];
+#  endif
+# endif
+/* trap.c */
+const char *traps[TRAPNUM];
+/* window.c */
+struct window_procs windowprocs;
+/* xxxtty.c */
+# ifdef DEFINE_OSPEED
+short ospeed;
+# endif
+#endif /* STRICT_REF_DEF */
+
+/*lev_main.c*/
diff --git a/util/makedefs.c b/util/makedefs.c
new file mode 100644 (file)
index 0000000..23dace2
--- /dev/null
@@ -0,0 +1,2199 @@
+/*     SCCS Id: @(#)makedefs.c 3.4     2002/08/14      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* Copyright (c) M. Stephenson, 1990, 1991.                      */
+/* Copyright (c) Dean Luick, 1990.                               */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#define MAKEDEFS_C     /* use to conditionally include file sections */
+/* #define DEBUG */    /* uncomment for debugging info */
+
+#include "config.h"
+#include "permonst.h"
+#include "objclass.h"
+#include "monsym.h"
+#include "artilist.h"
+#include "dungeon.h"
+#include "obj.h"
+#include "monst.h"
+#include "you.h"
+#include "flag.h"
+#include "dlb.h"
+
+/* version information */
+#ifdef SHORT_FILENAMES
+#include "patchlev.h"
+#else
+#include "patchlevel.h"
+#endif
+
+#ifdef MAC
+# if defined(__SC__) || defined(__MRC__)       /* MPW compilers */
+#  define MPWTOOL
+#include <CursorCtl.h>
+#include <string.h>
+#include <ctype.h>
+# else         /* MAC without MPWTOOL */
+#  define MACsansMPWTOOL
+# endif
+#endif /* MAC */
+
+#ifndef MPWTOOL
+# define SpinCursor(x)
+#endif
+
+#define Fprintf        (void) fprintf
+#define Fclose (void) fclose
+#define Unlink (void) unlink
+#if !defined(AMIGA) || defined(AZTEC_C)
+#define rewind(fp) fseek((fp),0L,SEEK_SET)     /* guarantee a return value */
+#endif
+
+#if defined(UNIX) && !defined(LINT) && !defined(GCC_WARN)
+static const char      SCCS_Id[] = "@(#)makedefs.c\t3.4\t2002/02/03";
+#endif
+
+       /* names of files to be generated */
+#define DATE_FILE      "date.h"
+#define MONST_FILE     "pm.h"
+#define ONAME_FILE     "onames.h"
+#ifndef OPTIONS_FILE
+#define OPTIONS_FILE   "options"
+#endif
+#define ORACLE_FILE    "oracles"
+#define DATA_FILE      "data"
+#define RUMOR_FILE     "rumors"
+#define DGN_I_FILE     "dungeon.def"
+#define DGN_O_FILE     "dungeon.pdf"
+#define MON_STR_C      "monstr.c"
+#define QTXT_I_FILE    "quest.txt"
+#define QTXT_O_FILE    "quest.dat"
+#define VIS_TAB_H      "vis_tab.h"
+#define VIS_TAB_C      "vis_tab.c"
+       /* locations for those files */
+#ifdef AMIGA
+# define FILE_PREFIX
+# define INCLUDE_TEMPLATE      "NH:include/t.%s"
+# define SOURCE_TEMPLATE       "NH:src/%s"
+# define DGN_TEMPLATE          "NH:dat/%s"  /* where dungeon.pdf file goes */
+# define DATA_TEMPLATE         "NH:slib/%s"
+# define DATA_IN_TEMPLATE      "NH:dat/%s"
+#else /* not AMIGA */
+# if defined(MAC) && !defined(__MACH__)
+    /* MacOS 9 or earlier */
+#   define INCLUDE_TEMPLATE    ":include:%s"
+#   define SOURCE_TEMPLATE     ":src:%s"
+#   define DGN_TEMPLATE                ":dat:%s"  /* where dungeon.pdf file goes */
+#  if __SC__ || __MRC__
+#   define DATA_TEMPLATE       ":Dungeon:%s"
+#  else
+#   define DATA_TEMPLATE       ":lib:%s"
+#  endif /* __SC__ || __MRC__ */
+#   define DATA_IN_TEMPLATE    ":dat:%s"
+# else /* neither AMIGA nor MAC */
+#  ifdef OS2
+#   define INCLUDE_TEMPLATE    "..\\include\\%s"
+#   define SOURCE_TEMPLATE     "..\\src\\%s"
+#   define DGN_TEMPLATE                "..\\dat\\%s"  /* where dungeon.pdf file goes */
+#   define DATA_TEMPLATE       "..\\dat\\%s"
+#   define DATA_IN_TEMPLATE    "..\\dat\\%s"
+#  else /* not AMIGA, MAC, or OS2 */
+#   define INCLUDE_TEMPLATE    "../include/%s"
+#   define SOURCE_TEMPLATE     "../src/%s"
+#   define DGN_TEMPLATE                "../dat/%s"  /* where dungeon.pdf file goes */
+#   define DATA_TEMPLATE       "../dat/%s"
+#   define DATA_IN_TEMPLATE    "../dat/%s"
+#  endif /* else !OS2 */
+# endif /* else !MAC */
+#endif /* else !AMIGA */
+
+static const char
+    *Dont_Edit_Code =
+       "/* This source file is generated by 'makedefs'.  Do not edit. */\n",
+    *Dont_Edit_Data =
+       "#\tThis data file is generated by 'makedefs'.  Do not edit. \n";
+
+static struct version_info version;
+
+/* definitions used for vision tables */
+#define TEST_WIDTH  COLNO
+#define TEST_HEIGHT ROWNO
+#define BLOCK_WIDTH (TEST_WIDTH + 10)
+#define BLOCK_HEIGHT TEST_HEIGHT       /* don't need extra spaces */
+#define MAX_ROW (BLOCK_HEIGHT + TEST_HEIGHT)
+#define MAX_COL (BLOCK_WIDTH + TEST_WIDTH)
+/* Use this as an out-of-bound value in the close table.  */
+#define CLOSE_OFF_TABLE_STRING "99"    /* for the close table */
+#define FAR_OFF_TABLE_STRING "0xff"    /* for the far table */
+
+#define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0))
+#ifdef VISION_TABLES
+static char xclear[MAX_ROW][MAX_COL];
+#endif
+/*-end of vision defs-*/
+
+static char    in_line[256], filename[60];
+
+#ifdef FILE_PREFIX
+               /* if defined, a first argument not starting with - is
+                * taken as a text string to be prepended to any
+                * output filename generated */
+char *file_prefix="";
+#endif
+
+#ifdef MACsansMPWTOOL
+int FDECL(main, (void));
+#else
+int FDECL(main, (int,char **));
+#endif
+void FDECL(do_makedefs, (char *));
+void NDECL(do_objs);
+void NDECL(do_data);
+void NDECL(do_dungeon);
+void NDECL(do_date);
+void NDECL(do_options);
+void NDECL(do_monstr);
+void NDECL(do_permonst);
+void NDECL(do_questtxt);
+void NDECL(do_rumors);
+void NDECL(do_oracles);
+void NDECL(do_vision);
+
+extern void NDECL(monst_init);         /* monst.c */
+extern void NDECL(objects_init);       /* objects.c */
+
+static void NDECL(make_version);
+static char *FDECL(version_string, (char *));
+static char *FDECL(version_id_string, (char *,const char *));
+static char *FDECL(xcrypt, (const char *));
+static int FDECL(check_control, (char *));
+static char *FDECL(without_control, (char *));
+static boolean FDECL(d_filter, (char *));
+static boolean FDECL(h_filter, (char *));
+static boolean FDECL(ranged_attk,(struct permonst*));
+static int FDECL(mstrength,(struct permonst *));
+static void NDECL(build_savebones_compat_string);
+
+static boolean FDECL(qt_comment, (char *));
+static boolean FDECL(qt_control, (char *));
+static int FDECL(get_hdr, (char *));
+static boolean FDECL(new_id, (char *));
+static boolean FDECL(known_msg, (int,int));
+static void FDECL(new_msg, (char *,int,int));
+static void FDECL(do_qt_control, (char *));
+static void FDECL(do_qt_text, (char *));
+static void NDECL(adjust_qt_hdrs);
+static void NDECL(put_qt_hdrs);
+
+#ifdef VISION_TABLES
+static void NDECL(H_close_gen);
+static void NDECL(H_far_gen);
+static void NDECL(C_close_gen);
+static void NDECL(C_far_gen);
+static int FDECL(clear_path, (int,int,int,int));
+#endif
+
+static char *FDECL(tmpdup, (const char *));
+static char *FDECL(limit, (char *,int));
+static char *FDECL(eos, (char *));
+
+/* input, output, tmp */
+static FILE *ifp, *ofp, *tfp;
+
+#if defined(__BORLANDC__) && !defined(_WIN32)
+extern unsigned _stklen = STKSIZ;
+#endif
+
+
+#ifdef MACsansMPWTOOL
+int
+main(void)
+{
+    const char *def_options = "odemvpqrhz";
+    char buf[100];
+    int len;
+
+    printf("Enter options to run: [%s] ", def_options);
+    fflush(stdout);
+    fgets(buf, 100, stdin);
+    len = strlen(buf);
+    if (len <= 1)
+       Strcpy(buf, def_options);
+    else
+       buf[len-1] = 0;                 /* remove return */
+
+    do_makedefs(buf);
+    exit(EXIT_SUCCESS);
+    return 0;
+}
+
+#else /* ! MAC */
+
+int
+main(argc, argv)
+int    argc;
+char   *argv[];
+{
+       if ( (argc != 2)
+#ifdef FILE_PREFIX
+               && (argc != 3)
+#endif
+       ) {
+           Fprintf(stderr, "Bad arg count (%d).\n", argc-1);
+           (void) fflush(stderr);
+           return 1;
+       }
+
+#ifdef FILE_PREFIX
+       if(argc >=2 && argv[1][0]!='-'){
+           file_prefix=argv[1];
+           argc--;argv++;
+       }
+#endif
+       do_makedefs(&argv[1][1]);
+       exit(EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
+
+#endif
+
+void
+do_makedefs(options)
+char   *options;
+{
+       boolean more_than_one;
+
+       /* Note:  these initializers don't do anything except guarantee that
+               we're linked properly.
+       */
+       monst_init();
+       objects_init();
+
+       /* construct the current version number */
+       make_version();
+
+
+       more_than_one = strlen(options) > 1;
+       while (*options) {
+           if (more_than_one)
+               Fprintf(stderr, "makedefs -%c\n", *options);
+
+           switch (*options) {
+               case 'o':
+               case 'O':       do_objs();
+                               break;
+               case 'd':
+               case 'D':       do_data();
+                               break;
+               case 'e':
+               case 'E':       do_dungeon();
+                               break;
+               case 'm':
+               case 'M':       do_monstr();
+                               break;
+               case 'v':
+               case 'V':       do_date();
+                               do_options();
+                               break;
+               case 'p':
+               case 'P':       do_permonst();
+                               break;
+               case 'q':
+               case 'Q':       do_questtxt();
+                               break;
+               case 'r':
+               case 'R':       do_rumors();
+                               break;
+               case 'h':
+               case 'H':       do_oracles();
+                               break;
+               case 'z':
+               case 'Z':       do_vision();
+                               break;
+
+               default:        Fprintf(stderr, "Unknown option '%c'.\n",
+                                       *options);
+                               (void) fflush(stderr);
+                               exit(EXIT_FAILURE);
+               
+           }
+           options++;
+       }
+       if (more_than_one) Fprintf(stderr, "Completed.\n");     /* feedback */
+
+}
+
+
+/* trivial text encryption routine which can't be broken with `tr' */
+static
+char *xcrypt(str)
+const char *str;
+{                              /* duplicated in src/hacklib.c */
+       static char buf[BUFSZ];
+       register const char *p;
+       register char *q;
+       register int bitmask;
+
+       for (bitmask = 1, p = str, q = buf; *p; q++) {
+               *q = *p++;
+               if (*q & (32|64)) *q ^= bitmask;
+               if ((bitmask <<= 1) >= 32) bitmask = 1;
+       }
+       *q = '\0';
+       return buf;
+}
+
+void
+do_rumors()
+{
+       char    infile[60];
+       long    true_rumor_size;
+
+       filename[0]='\0';
+#ifdef FILE_PREFIX
+       Strcat(filename,file_prefix);
+#endif
+       Sprintf(eos(filename), DATA_TEMPLATE, RUMOR_FILE);
+       if (!(ofp = fopen(filename, WRTMODE))) {
+               perror(filename);
+               exit(EXIT_FAILURE);
+       }
+       Fprintf(ofp,Dont_Edit_Data);
+
+       Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE);
+       Strcat(infile, ".tru");
+       if (!(ifp = fopen(infile, RDTMODE))) {
+               perror(infile);
+               Fclose(ofp);
+               Unlink(filename);       /* kill empty output file */
+               exit(EXIT_FAILURE);
+       }
+
+       /* get size of true rumors file */
+#ifndef VMS
+       (void) fseek(ifp, 0L, SEEK_END);
+       true_rumor_size = ftell(ifp);
+#else
+       /* seek+tell is only valid for stream format files; since rumors.%%%
+          might be in record format, count the actual data bytes instead.
+        */
+       true_rumor_size = 0;
+       while (fgets(in_line, sizeof in_line, ifp) != 0)
+               true_rumor_size += strlen(in_line);     /* includes newline */
+#endif /* VMS */
+       Fprintf(ofp,"%06lx\n", true_rumor_size);
+       (void) fseek(ifp, 0L, SEEK_SET);
+
+       /* copy true rumors */
+       while (fgets(in_line, sizeof in_line, ifp) != 0)
+               (void) fputs(xcrypt(in_line), ofp);
+
+       Fclose(ifp);
+
+       Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE);
+       Strcat(infile, ".fal");
+       if (!(ifp = fopen(infile, RDTMODE))) {
+               perror(infile);
+               Fclose(ofp);
+               Unlink(filename);       /* kill incomplete output file */
+               exit(EXIT_FAILURE);
+       }
+
+       /* copy false rumors */
+       while (fgets(in_line, sizeof in_line, ifp) != 0)
+               (void) fputs(xcrypt(in_line), ofp);
+
+       Fclose(ifp);
+       Fclose(ofp);
+       return;
+}
+
+/*
+ * 3.4.1: way back in 3.2.1 `flags.nap' became unconditional but
+ * TIMED_DELAY was erroneously left in VERSION_FEATURES and has
+ * been there up through 3.4.0.  Simply removing it now would
+ * break save file compatibility with 3.4.0 files, so we will
+ * explicitly mask it out during version checks.
+ * This should go away in the next version update.
+ */
+#define IGNORED_FEATURES       ( 0L \
+                               | (1L << 23)    /* TIMED_DELAY */ \
+                               )
+
+static void
+make_version()
+{
+       register int i;
+
+       /*
+        * integer version number
+        */
+       version.incarnation = ((unsigned long)VERSION_MAJOR << 24) |
+                               ((unsigned long)VERSION_MINOR << 16) |
+                               ((unsigned long)PATCHLEVEL << 8) |
+                               ((unsigned long)EDITLEVEL);
+       /*
+        * encoded feature list
+        * Note:  if any of these magic numbers are changed or reassigned,
+        * EDITLEVEL in patchlevel.h should be incremented at the same time.
+        * The actual values have no special meaning, and the category
+        * groupings are just for convenience.
+        */
+       version.feature_set = (unsigned long)(0L
+               /* levels and/or topology (0..4) */
+#ifdef REINCARNATION
+                       | (1L <<  1)
+#endif
+#ifdef SINKS
+                       | (1L <<  2)
+#endif
+               /* monsters (5..9) */
+#ifdef KOPS
+                       | (1L <<  6)
+#endif
+#ifdef MAIL
+                       | (1L <<  7)
+#endif
+               /* objects (10..14) */
+#ifdef TOURIST
+                       | (1L << 10)
+#endif
+#ifdef STEED
+                       | (1L << 11)
+#endif
+#ifdef GOLDOBJ
+                       | (1L << 12)
+#endif
+               /* flag bits and/or other global variables (15..26) */
+#ifdef TEXTCOLOR
+                       | (1L << 17)
+#endif
+#ifdef INSURANCE
+                       | (1L << 18)
+#endif
+#ifdef ELBERETH
+                       | (1L << 19)
+#endif
+#ifdef EXP_ON_BOTL
+                       | (1L << 20)
+#endif
+#ifdef SCORE_ON_BOTL
+                       | (1L << 21)
+#endif
+               /* data format [COMPRESS excluded] (27..31) */
+#ifdef ZEROCOMP
+                       | (1L << 27)
+#endif
+#ifdef RLECOMP
+                       | (1L << 28)
+#endif
+                       );
+       /*
+        * Value used for object & monster sanity check.
+        *    (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0)
+        */
+       for (i = 1; artifact_names[i]; i++) continue;
+       version.entity_count = (unsigned long)(i - 1);
+       for (i = 1; objects[i].oc_class != ILLOBJ_CLASS; i++) continue;
+       version.entity_count = (version.entity_count << 12) | (unsigned long)i;
+       for (i = 0; mons[i].mlet; i++) continue;
+       version.entity_count = (version.entity_count << 12) | (unsigned long)i;
+       /*
+        * Value used for compiler (word size/field alignment/padding) check.
+        */
+       version.struct_sizes = (((unsigned long)sizeof (struct flag)  << 24) |
+                               ((unsigned long)sizeof (struct obj)   << 17) |
+                               ((unsigned long)sizeof (struct monst) << 10) |
+                               ((unsigned long)sizeof (struct you)));
+       return;
+}
+
+static char *
+version_string(outbuf)
+char *outbuf;
+{
+    Sprintf(outbuf, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
+#ifdef BETA
+    Sprintf(eos(outbuf), "-%d", EDITLEVEL);
+#endif
+    return outbuf;
+}
+
+static char *
+version_id_string(outbuf, build_date)
+char *outbuf;
+const char *build_date;
+{
+    char subbuf[64], versbuf[64];
+
+    subbuf[0] = '\0';
+#ifdef PORT_SUB_ID
+    subbuf[0] = ' ';
+    Strcpy(&subbuf[1], PORT_SUB_ID);
+#endif
+#ifdef BETA
+    Strcat(subbuf, " Beta");
+#endif
+
+    Sprintf(outbuf, "%s NetHack%s Version %s - last build %s.",
+           PORT_ID, subbuf, version_string(versbuf), build_date);
+    return outbuf;
+}
+
+void
+do_date()
+{
+       long clocktim = 0;
+       char *c, cbuf[60], buf[BUFSZ];
+       const char *ul_sfx;
+
+       filename[0]='\0';
+#ifdef FILE_PREFIX
+       Strcat(filename,file_prefix);
+#endif
+       Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE);
+       if (!(ofp = fopen(filename, WRTMODE))) {
+               perror(filename);
+               exit(EXIT_FAILURE);
+       }
+       Fprintf(ofp,"/*\tSCCS Id: @(#)date.h\t3.4\t2002/02/03 */\n\n");
+       Fprintf(ofp,Dont_Edit_Code);
+
+#ifdef KR1ED
+       (void) time(&clocktim);
+       Strcpy(cbuf, ctime(&clocktim));
+#else
+       (void) time((time_t *)&clocktim);
+       Strcpy(cbuf, ctime((time_t *)&clocktim));
+#endif
+       for (c = cbuf; *c; c++) if (*c == '\n') break;
+       *c = '\0';      /* strip off the '\n' */
+       Fprintf(ofp,"#define BUILD_DATE \"%s\"\n", cbuf);
+       Fprintf(ofp,"#define BUILD_TIME (%ldL)\n", clocktim);
+       Fprintf(ofp,"\n");
+#ifdef NHSTDC
+       ul_sfx = "UL";
+#else
+       ul_sfx = "L";
+#endif
+       Fprintf(ofp,"#define VERSION_NUMBER 0x%08lx%s\n",
+               version.incarnation, ul_sfx);
+       Fprintf(ofp,"#define VERSION_FEATURES 0x%08lx%s\n",
+               version.feature_set, ul_sfx);
+#ifdef IGNORED_FEATURES
+       Fprintf(ofp,"#define IGNORED_FEATURES 0x%08lx%s\n",
+               (unsigned long) IGNORED_FEATURES, ul_sfx);
+#endif
+       Fprintf(ofp,"#define VERSION_SANITY1 0x%08lx%s\n",
+               version.entity_count, ul_sfx);
+       Fprintf(ofp,"#define VERSION_SANITY2 0x%08lx%s\n",
+               version.struct_sizes, ul_sfx);
+       Fprintf(ofp,"\n");
+       Fprintf(ofp,"#define VERSION_STRING \"%s\"\n", version_string(buf));
+       Fprintf(ofp,"#define VERSION_ID \\\n \"%s\"\n",
+               version_id_string(buf, cbuf));
+       Fprintf(ofp,"\n");
+#ifdef AMIGA
+       {
+       struct tm *tm = localtime((time_t *) &clocktim);
+       Fprintf(ofp,"#define AMIGA_VERSION_STRING ");
+       Fprintf(ofp,"\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n",
+               VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL,
+               tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900);
+       }
+#endif
+       Fclose(ofp);
+       return;
+}
+
+static char save_bones_compat_buf[BUFSZ];
+
+static void
+build_savebones_compat_string()
+{
+#ifdef VERSION_COMPATIBILITY
+       unsigned long uver = VERSION_COMPATIBILITY;
+#endif
+       Strcpy(save_bones_compat_buf,
+               "save and bones files accepted from version");
+#ifdef VERSION_COMPATIBILITY
+       Sprintf(eos(save_bones_compat_buf), "s %lu.%lu.%lu through %d.%d.%d",
+               ((uver & 0xFF000000L) >> 24), ((uver & 0x00FF0000L) >> 16),
+               ((uver & 0x0000FF00L) >> 8),
+               VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
+#else
+       Sprintf(eos(save_bones_compat_buf), " %d.%d.%d only",
+               VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
+#endif
+}
+
+static const char *build_opts[] = {
+#ifdef AMIGA_WBENCH
+               "Amiga WorkBench support",
+#endif
+#ifdef ANSI_DEFAULT
+               "ANSI default terminal",
+#endif
+#ifdef AUTOPICKUP_EXCEPTIONS
+               "autopickup_exceptions",
+#endif
+#ifdef TEXTCOLOR
+               "color",
+#endif
+#ifdef COM_COMPL
+               "command line completion",
+#endif
+#ifdef COMPRESS
+               "data file compression",
+#endif
+#ifdef DLB
+               "data librarian",
+#endif
+#ifdef WIZARD
+               "debug mode",
+#endif
+#ifdef ELBERETH
+               "Elbereth",
+#endif
+#ifdef EXP_ON_BOTL
+               "experience points on status line",
+#endif
+#ifdef MFLOPPY
+               "floppy drive support",
+#endif
+#ifdef GOLDOBJ
+               "gold object in inventories",
+#endif
+#ifdef INSURANCE
+               "insurance files for recovering from crashes",
+#endif
+#ifdef KOPS
+               "Keystone Kops",
+#endif
+#ifdef HOLD_LOCKFILE_OPEN
+               "exclusive lock on level 0 file",
+#endif
+#ifdef LOGFILE
+               "log file",
+#endif
+#ifdef MAIL
+               "mail daemon",
+#endif
+#ifdef GNUDOS
+               "MSDOS protected mode",
+#endif
+#ifdef NEWS
+               "news file",
+#endif
+#ifdef OVERLAY
+# ifdef MOVERLAY
+               "MOVE overlays",
+# else
+#  ifdef VROOMM
+               "VROOMM overlays",
+#  else
+               "overlays",
+#  endif
+# endif
+#endif
+#ifdef REDO
+               "redo command",
+#endif
+#ifdef REINCARNATION
+               "rogue level",
+#endif
+#ifdef STEED
+               "saddles and riding",
+#endif
+#ifdef SCORE_ON_BOTL
+               "score on status line",
+#endif
+#ifdef CLIPPING
+               "screen clipping",
+#endif
+#ifdef NO_TERMS
+# ifdef MAC
+               "screen control via mactty",
+# endif
+# ifdef SCREEN_BIOS
+               "screen control via BIOS",
+# endif
+# ifdef SCREEN_DJGPPFAST
+               "screen control via DJGPP fast",
+# endif
+# ifdef SCREEN_VGA
+               "screen control via VGA graphics",
+# endif
+# ifndef MSWIN_GRAPHICS
+#  ifdef WIN32CON
+               "screen control via WIN32 console I/O",
+#  endif
+# endif
+#endif
+#ifdef SEDUCE
+               "seduction",
+#endif
+#ifdef SHELL
+               "shell command",
+#endif
+#ifdef SINKS
+               "sinks",
+#endif
+#ifdef SUSPEND
+               "suspend command",
+#endif
+#ifdef TERMINFO
+               "terminal info library",
+#else
+# if defined(TERMLIB) || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS))
+               "terminal capability library",
+# endif
+#endif
+#ifdef TIMED_DELAY
+               "timed wait for display effects",
+#endif
+#ifdef TOURIST
+               "tourists",
+#endif
+#ifdef USER_SOUNDS
+# ifdef USER_SOUNDS_REGEX
+               "user sounds via regular expressions",
+# else
+               "user sounds via pmatch",
+# endif
+#endif
+#ifdef PREFIXES_IN_USE
+               "variable playground",
+#endif
+#ifdef VISION_TABLES
+               "vision tables",
+#endif
+#ifdef WALLIFIED_MAZE
+               "walled mazes",
+#endif
+#ifdef ZEROCOMP
+               "zero-compressed save files",
+#endif
+               save_bones_compat_buf,
+               "basic NetHack features"
+       };
+
+static const char *window_opts[] = {
+#ifdef TTY_GRAPHICS
+               "traditional tty-based graphics",
+#endif
+#ifdef X11_GRAPHICS
+               "X11",
+#endif
+#ifdef QT_GRAPHICS
+               "Qt",
+#endif
+#ifdef GNOME_GRAPHICS
+               "Gnome",
+#endif
+#ifdef MAC
+               "Mac",
+#endif
+#ifdef AMIGA_INTUITION
+               "Amiga Intuition",
+#endif
+#ifdef GEM_GRAPHICS
+               "Gem",
+#endif
+#ifdef MSWIN_GRAPHICS
+               "mswin",
+#endif
+#ifdef BEOS_GRAPHICS
+               "BeOS InterfaceKit",
+#endif
+               0
+       };
+
+void
+do_options()
+{
+       register int i, length;
+       register const char *str, *indent = "    ";
+
+       filename[0]='\0';
+#ifdef FILE_PREFIX
+       Strcat(filename,file_prefix);
+#endif
+       Sprintf(eos(filename), DATA_TEMPLATE, OPTIONS_FILE);
+       if (!(ofp = fopen(filename, WRTMODE))) {
+               perror(filename);
+               exit(EXIT_FAILURE);
+       }
+
+       build_savebones_compat_string();
+       Fprintf(ofp,
+#ifdef BETA
+               "\n    NetHack version %d.%d.%d [beta]\n",
+#else
+               "\n    NetHack version %d.%d.%d\n",
+#endif
+               VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
+
+       Fprintf(ofp,"\nOptions compiled into this edition:\n");
+
+       length = COLNO + 1;     /* force 1st item onto new line */
+       for (i = 0; i < SIZE(build_opts); i++) {
+           str = build_opts[i];
+           if (length + strlen(str) > COLNO - 5)
+               Fprintf(ofp,"\n%s", indent),  length = strlen(indent);
+           else
+               Fprintf(ofp," "),  length++;
+           Fprintf(ofp,"%s", str),  length += strlen(str);
+           Fprintf(ofp,(i < SIZE(build_opts) - 1) ? "," : "."),  length++;
+       }
+
+       Fprintf(ofp,"\n\nSupported windowing systems:\n");
+
+       length = COLNO + 1;     /* force 1st item onto new line */
+       for (i = 0; i < SIZE(window_opts) - 1; i++) {
+           str = window_opts[i];
+           if (length + strlen(str) > COLNO - 5)
+               Fprintf(ofp,"\n%s", indent),  length = strlen(indent);
+           else
+               Fprintf(ofp," "),  length++;
+           Fprintf(ofp,"%s", str),  length += strlen(str);
+           Fprintf(ofp, ","),  length++;
+       }
+       Fprintf(ofp, "\n%swith a default of %s.", indent, DEFAULT_WINDOW_SYS);
+       Fprintf(ofp,"\n\n");
+
+       Fclose(ofp);
+       return;
+}
+
+/* routine to decide whether to discard something from data.base */
+static boolean
+d_filter(line)
+    char *line;
+{
+    if (*line == '#') return TRUE;     /* ignore comment lines */
+    return FALSE;
+}
+
+   /*
+    *
+       New format (v3.1) of 'data' file which allows much faster lookups [pr]
+"do not edit"          first record is a comment line
+01234567               hexadecimal formatted offset to text area
+name-a                 first name of interest
+123,4                  offset to name's text, and number of lines for it
+name-b                 next name of interest
+name-c                 multiple names which share same description also
+456,7                  share a single offset,count line
+.                      sentinel to mark end of names
+789,0                  dummy record containing offset, count of EOF
+text-a                 4 lines of descriptive text for name-a
+text-a                 at file position 0x01234567L + 123L
+text-a
+text-a
+text-b/text-c          7 lines of text for names-b and -c
+text-b/text-c          at fseek(0x01234567L + 456L)
+...
+    *
+    */
+
+void
+do_data()
+{
+       char    infile[60], tempfile[60];
+       boolean ok;
+       long    txt_offset;
+       int     entry_cnt, line_cnt;
+
+       Sprintf(tempfile, DATA_TEMPLATE, "database.tmp");
+       filename[0]='\0';
+#ifdef FILE_PREFIX
+       Strcat(filename,file_prefix);
+#endif
+       Sprintf(eos(filename), DATA_TEMPLATE, DATA_FILE);
+       Sprintf(infile, DATA_IN_TEMPLATE, DATA_FILE);
+       Strcat(infile,
+#ifdef SHORT_FILENAMES
+               ".bas"
+#else
+               ".base"
+#endif
+               );
+       if (!(ifp = fopen(infile, RDTMODE))) {          /* data.base */
+               perror(infile);
+               exit(EXIT_FAILURE);
+       }
+       if (!(ofp = fopen(filename, WRTMODE))) {        /* data */
+               perror(filename);
+               Fclose(ifp);
+               exit(EXIT_FAILURE);
+       }
+       if (!(tfp = fopen(tempfile, WRTMODE))) {        /* database.tmp */
+               perror(tempfile);
+               Fclose(ifp);
+               Fclose(ofp);
+               Unlink(filename);
+               exit(EXIT_FAILURE);
+       }
+
+       /* output a dummy header record; we'll rewind and overwrite it later */
+       Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L);
+
+       entry_cnt = line_cnt = 0;
+       /* read through the input file and split it into two sections */
+       while (fgets(in_line, sizeof in_line, ifp)) {
+           if (d_filter(in_line)) continue;
+           if (*in_line > ' ') {       /* got an entry name */
+               /* first finish previous entry */
+               if (line_cnt)  Fprintf(ofp, "%d\n", line_cnt),  line_cnt = 0;
+               /* output the entry name */
+               (void) fputs(in_line, ofp);
+               entry_cnt++;            /* update number of entries */
+           } else if (entry_cnt) {     /* got some descriptive text */
+               /* update previous entry with current text offset */
+               if (!line_cnt)  Fprintf(ofp, "%ld,", ftell(tfp));
+               /* save the text line in the scratch file */
+               (void) fputs(in_line, tfp);
+               line_cnt++;             /* update line counter */
+           }
+       }
+       /* output an end marker and then record the current position */
+       if (line_cnt)  Fprintf(ofp, "%d\n", line_cnt);
+       Fprintf(ofp, ".\n%ld,%d\n", ftell(tfp), 0);
+       txt_offset = ftell(ofp);
+       Fclose(ifp);            /* all done with original input file */
+
+       /* reprocess the scratch file; 1st format an error msg, just in case */
+       Sprintf(in_line, "rewind of \"%s\"", tempfile);
+       if (rewind(tfp) != 0)  goto dead_data;
+       /* copy all lines of text from the scratch file into the output file */
+       while (fgets(in_line, sizeof in_line, tfp))
+           (void) fputs(in_line, ofp);
+
+       /* finished with scratch file */
+       Fclose(tfp);
+       Unlink(tempfile);       /* remove it */
+
+       /* update the first record of the output file; prepare error msg 1st */
+       Sprintf(in_line, "rewind of \"%s\"", filename);
+       ok = (rewind(ofp) == 0);
+       if (ok) {
+          Sprintf(in_line, "header rewrite of \"%s\"", filename);
+          ok = (fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, txt_offset) >= 0);
+       }
+       if (!ok) {
+dead_data:  perror(in_line);   /* report the problem */
+           /* close and kill the aborted output file, then give up */
+           Fclose(ofp);
+           Unlink(filename);
+           exit(EXIT_FAILURE);
+       }
+
+       /* all done */
+       Fclose(ofp);
+
+       return;
+}
+
+/* routine to decide whether to discard something from oracles.txt */
+static boolean
+h_filter(line)
+    char *line;
+{
+    static boolean skip = FALSE;
+    char tag[sizeof in_line];
+
+    SpinCursor(3);
+
+    if (*line == '#') return TRUE;     /* ignore comment lines */
+    if (sscanf(line, "----- %s", tag) == 1) {
+       skip = FALSE;
+#ifndef SINKS
+       if (!strcmp(tag, "SINKS")) skip = TRUE;
+#endif
+#ifndef ELBERETH
+       if (!strcmp(tag, "ELBERETH")) skip = TRUE;
+#endif
+    } else if (skip && !strncmp(line, "-----", 5))
+       skip = FALSE;
+    return skip;
+}
+
+static const char *special_oracle[] = {
+       "\"...it is rather disconcerting to be confronted with the",
+       "following theorem from [Baker, Gill, and Solovay, 1975].",
+       "",
+       "Theorem 7.18  There exist recursive languages A and B such that",
+       "  (1)  P(A) == NP(A), and",
+       "  (2)  P(B) != NP(B)",
+       "",
+       "This provides impressive evidence that the techniques that are",
+       "currently available will not suffice for proving that P != NP or          ",
+       "that P == NP.\"  [Garey and Johnson, p. 185.]"
+};
+
+/*
+   The oracle file consists of a "do not edit" comment, a decimal count N
+   and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
+   records, separated by "---" lines.  The first oracle is a special case.
+   The input data contains just those multi-line records, separated by
+   "-----" lines.
+ */
+
+void
+do_oracles()
+{
+       char    infile[60], tempfile[60];
+       boolean in_oracle, ok;
+       long    txt_offset, offset, fpos;
+       int     oracle_cnt;
+       register int i;
+
+       Sprintf(tempfile, DATA_TEMPLATE, "oracles.tmp");
+       filename[0]='\0';
+#ifdef FILE_PREFIX
+       Strcat(filename, file_prefix);
+#endif
+       Sprintf(eos(filename), DATA_TEMPLATE, ORACLE_FILE);
+       Sprintf(infile, DATA_IN_TEMPLATE, ORACLE_FILE);
+       Strcat(infile, ".txt");
+       if (!(ifp = fopen(infile, RDTMODE))) {
+               perror(infile);
+               exit(EXIT_FAILURE);
+       }
+       if (!(ofp = fopen(filename, WRTMODE))) {
+               perror(filename);
+               Fclose(ifp);
+               exit(EXIT_FAILURE);
+       }
+       if (!(tfp = fopen(tempfile, WRTMODE))) {        /* oracles.tmp */
+               perror(tempfile);
+               Fclose(ifp);
+               Fclose(ofp);
+               Unlink(filename);
+               exit(EXIT_FAILURE);
+       }
+
+       /* output a dummy header record; we'll rewind and overwrite it later */
+       Fprintf(ofp, "%s%5d\n", Dont_Edit_Data, 0);
+
+       /* handle special oracle; it must come first */
+       (void) fputs("---\n", tfp);
+       Fprintf(ofp, "%05lx\n", ftell(tfp));  /* start pos of special oracle */
+       for (i = 0; i < SIZE(special_oracle); i++) {
+           (void) fputs(xcrypt(special_oracle[i]), tfp);
+           (void) fputc('\n', tfp);
+       }
+       SpinCursor(3);
+
+       oracle_cnt = 1;
+       (void) fputs("---\n", tfp);
+       Fprintf(ofp, "%05lx\n", ftell(tfp));    /* start pos of first oracle */
+       in_oracle = FALSE;
+
+       while (fgets(in_line, sizeof in_line, ifp)) {
+           SpinCursor(3);
+
+           if (h_filter(in_line)) continue;
+           if (!strncmp(in_line, "-----", 5)) {
+               if (!in_oracle) continue;
+               in_oracle = FALSE;
+               oracle_cnt++;
+               (void) fputs("---\n", tfp);
+               Fprintf(ofp, "%05lx\n", ftell(tfp));
+               /* start pos of this oracle */
+           } else {
+               in_oracle = TRUE;
+               (void) fputs(xcrypt(in_line), tfp);
+           }
+       }
+
+       if (in_oracle) {        /* need to terminate last oracle */
+           oracle_cnt++;
+           (void) fputs("---\n", tfp);
+           Fprintf(ofp, "%05lx\n", ftell(tfp));        /* eof position */
+       }
+
+       /* record the current position */
+       txt_offset = ftell(ofp);
+       Fclose(ifp);            /* all done with original input file */
+
+       /* reprocess the scratch file; 1st format an error msg, just in case */
+       Sprintf(in_line, "rewind of \"%s\"", tempfile);
+       if (rewind(tfp) != 0)  goto dead_data;
+       /* copy all lines of text from the scratch file into the output file */
+       while (fgets(in_line, sizeof in_line, tfp))
+           (void) fputs(in_line, ofp);
+
+       /* finished with scratch file */
+       Fclose(tfp);
+       Unlink(tempfile);       /* remove it */
+
+       /* update the first record of the output file; prepare error msg 1st */
+       Sprintf(in_line, "rewind of \"%s\"", filename);
+       ok = (rewind(ofp) == 0);
+       if (ok) {
+           Sprintf(in_line, "header rewrite of \"%s\"", filename);
+           ok = (fprintf(ofp, "%s%5d\n", Dont_Edit_Data, oracle_cnt) >=0);
+       }
+       if (ok) {
+           Sprintf(in_line, "data rewrite of \"%s\"", filename);
+           for (i = 0; i <= oracle_cnt; i++) {
+#ifndef VMS    /* alpha/vms v1.0; this fflush seems to confuse ftell */
+               if (!(ok = (fflush(ofp) == 0))) break;
+#endif
+               if (!(ok = (fpos = ftell(ofp)) >= 0)) break;
+               if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break;
+               if (!(ok = (fscanf(ofp, "%5lx", &offset) == 1))) break;
+#ifdef MAC
+# ifdef __MWERKS__
+               /*
+               MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL
+               (ANSI C Libraries) needs this rewind or else the fprintf
+               stops working.  This may also be true for CW11, but has
+               never been checked.
+               */
+               rewind(ofp);
+# endif
+#endif
+               if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break;
+               if (!(ok = (fprintf(ofp, "%05lx\n", offset + txt_offset) >= 0)))
+                   break;
+           }
+       }
+       if (!ok) {
+dead_data:  perror(in_line);   /* report the problem */
+           /* close and kill the aborted output file, then give up */
+           Fclose(ofp);
+           Unlink(filename);
+           exit(EXIT_FAILURE);
+       }
+
+       /* all done */
+       Fclose(ofp);
+
+       return;
+}
+
+
+static struct deflist {
+
+       const char      *defname;
+       boolean true_or_false;
+} deflist[] = {
+#ifdef REINCARNATION
+             { "REINCARNATION", TRUE },
+#else
+             { "REINCARNATION", FALSE },
+#endif
+             { 0, 0 } };
+
+static int
+check_control(s)
+       char    *s;
+{
+       int     i;
+
+       if(s[0] != '%') return(-1);
+
+       for(i = 0; deflist[i].defname; i++)
+           if(!strncmp(deflist[i].defname, s+1, strlen(deflist[i].defname)))
+               return(i);
+
+       return(-1);
+}
+
+static char *
+without_control(s)
+       char *s;
+{
+       return(s + 1 + strlen(deflist[check_control(in_line)].defname));
+}
+
+void
+do_dungeon()
+{
+       int rcnt = 0;
+
+       Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE);
+       if (!(ifp = fopen(filename, RDTMODE))) {
+               perror(filename);
+               exit(EXIT_FAILURE);
+       }
+       filename[0]='\0';
+#ifdef FILE_PREFIX
+       Strcat(filename, file_prefix);
+#endif
+       Sprintf(eos(filename), DGN_TEMPLATE, DGN_O_FILE);
+       if (!(ofp = fopen(filename, WRTMODE))) {
+               perror(filename);
+               exit(EXIT_FAILURE);
+       }
+       Fprintf(ofp,Dont_Edit_Data);
+
+       while (fgets(in_line, sizeof in_line, ifp) != 0) {
+           SpinCursor(3);
+
+           rcnt++;
+           if(in_line[0] == '#') continue;     /* discard comments */
+recheck:
+           if(in_line[0] == '%') {
+               int i = check_control(in_line);
+               if(i >= 0) {
+                   if(!deflist[i].true_or_false)  {
+                       while (fgets(in_line, sizeof in_line, ifp) != 0)
+                           if(check_control(in_line) != i) goto recheck;
+                   } else
+                       (void) fputs(without_control(in_line),ofp);
+               } else {
+                   Fprintf(stderr, "Unknown control option '%s' in file %s at line %d.\n",
+                           in_line, DGN_I_FILE, rcnt);
+                   exit(EXIT_FAILURE);
+               }
+           } else
+               (void) fputs(in_line,ofp);
+       }
+       Fclose(ifp);
+       Fclose(ofp);
+
+       return;
+}
+
+static boolean
+ranged_attk(ptr)       /* returns TRUE if monster can attack at range */
+       register struct permonst *ptr;
+{
+       register int    i, j;
+       register int atk_mask = (1<<AT_BREA) | (1<<AT_SPIT) | (1<<AT_GAZE);
+
+       for(i = 0; i < NATTK; i++) {
+           if((j=ptr->mattk[i].aatyp) >= AT_WEAP || (atk_mask & (1<<j)))
+               return TRUE;
+       }
+
+       return(FALSE);
+}
+
+/* This routine is designed to return an integer value which represents
+ * an approximation of monster strength.  It uses a similar method of
+ * determination as "experience()" to arrive at the strength.
+ */
+static int
+mstrength(ptr)
+struct permonst *ptr;
+{
+       int     i, tmp2, n, tmp = ptr->mlevel;
+
+       if(tmp > 49)            /* special fixed hp monster */
+           tmp = 2*(tmp - 6) / 4;
+
+/*     For creation in groups */
+       n = (!!(ptr->geno & G_SGROUP));
+       n += (!!(ptr->geno & G_LGROUP)) << 1;
+
+/*     For ranged attacks */
+       if (ranged_attk(ptr)) n++;
+
+/*     For higher ac values */
+       n += (ptr->ac < 4);
+       n += (ptr->ac < 0);
+
+/*     For very fast monsters */
+       n += (ptr->mmove >= 18);
+
+/*     For each attack and "special" attack */
+       for(i = 0; i < NATTK; i++) {
+
+           tmp2 = ptr->mattk[i].aatyp;
+           n += (tmp2 > 0);
+           n += (tmp2 == AT_MAGC);
+           n += (tmp2 == AT_WEAP && (ptr->mflags2 & M2_STRONG));
+       }
+
+/*     For each "special" damage type */
+       for(i = 0; i < NATTK; i++) {
+
+           tmp2 = ptr->mattk[i].adtyp;
+           if ((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_DRST)
+               || (tmp2 == AD_DRDX) || (tmp2 == AD_DRCO) || (tmp2 == AD_WERE))
+                       n += 2;
+           else if (strcmp(ptr->mname, "grid bug")) n += (tmp2 != AD_PHYS);
+           n += ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23);
+       }
+
+/*     Leprechauns are special cases.  They have many hit dice so they
+       can hit and are hard to kill, but they don't really do much damage. */
+       if (!strcmp(ptr->mname, "leprechaun")) n -= 2;
+
+/*     Finally, adjust the monster level  0 <= n <= 24 (approx.) */
+       if(n == 0) tmp--;
+       else if(n >= 6) tmp += ( n / 2 );
+       else tmp += ( n / 3 + 1);
+
+       return((tmp >= 0) ? tmp : 0);
+}
+
+void
+do_monstr()
+{
+    register struct permonst *ptr;
+    register int i, j;
+
+    /*
+     * create the source file, "monstr.c"
+     */
+    filename[0]='\0';
+#ifdef FILE_PREFIX
+    Strcat(filename, file_prefix);
+#endif
+    Sprintf(eos(filename), SOURCE_TEMPLATE, MON_STR_C);
+    if (!(ofp = fopen(filename, WRTMODE))) {
+       perror(filename);
+       exit(EXIT_FAILURE);
+    }
+    Fprintf(ofp,Dont_Edit_Code);
+    Fprintf(ofp,"#include \"config.h\"\n");
+    Fprintf(ofp,"\nconst int monstr[] = {\n");
+    for (ptr = &mons[0], j = 0; ptr->mlet; ptr++) {
+
+       SpinCursor(3);
+
+       i = mstrength(ptr);
+       Fprintf(ofp,"%2d,%c", i, (++j & 15) ? ' ' : '\n');
+    }
+    /* might want to insert a final 0 entry here instead of just newline */
+    Fprintf(ofp,"%s};\n", (j & 15) ? "\n" : "");
+
+    Fprintf(ofp,"\nvoid NDECL(monstr_init);\n");
+    Fprintf(ofp,"\nvoid\n");
+    Fprintf(ofp,"monstr_init()\n");
+    Fprintf(ofp,"{\n");
+    Fprintf(ofp,"    return;\n");
+    Fprintf(ofp,"}\n");
+    Fprintf(ofp,"\n/*monstr.c*/\n");
+
+    Fclose(ofp);
+    return;
+}
+
+void
+do_permonst()
+{
+       int     i;
+       char    *c, *nam;
+
+       filename[0]='\0';
+#ifdef FILE_PREFIX
+       Strcat(filename, file_prefix);
+#endif
+       Sprintf(eos(filename), INCLUDE_TEMPLATE, MONST_FILE);
+       if (!(ofp = fopen(filename, WRTMODE))) {
+               perror(filename);
+               exit(EXIT_FAILURE);
+       }
+       Fprintf(ofp,"/*\tSCCS Id: @(#)pm.h\t3.4\t2002/02/03 */\n\n");
+       Fprintf(ofp,Dont_Edit_Code);
+       Fprintf(ofp,"#ifndef PM_H\n#define PM_H\n");
+
+       if (strcmp(mons[0].mname, "playermon") != 0)
+               Fprintf(ofp,"\n#define\tPM_PLAYERMON\t(-1)");
+
+       for (i = 0; mons[i].mlet; i++) {
+               SpinCursor(3);
+
+               Fprintf(ofp,"\n#define\tPM_");
+               if (mons[i].mlet == S_HUMAN &&
+                               !strncmp(mons[i].mname, "were", 4))
+                   Fprintf(ofp, "HUMAN_");
+               for (nam = c = tmpdup(mons[i].mname); *c; c++)
+                   if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
+                   else if (*c < 'A' || *c > 'Z') *c = '_';
+               Fprintf(ofp,"%s\t%d", nam, i);
+       }
+       Fprintf(ofp,"\n\n#define\tNUMMONS\t%d\n", i);
+       Fprintf(ofp,"\n#endif /* PM_H */\n");
+       Fclose(ofp);
+       return;
+}
+
+
+/*     Start of Quest text file processing. */
+#include "qtext.h"
+
+static struct qthdr    qt_hdr;
+static struct msghdr   msg_hdr[N_HDR];
+static struct qtmsg    *curr_msg;
+
+static int     qt_line;
+
+static boolean in_msg;
+#define NO_MSG 1       /* strlen of a null line returned by fgets() */
+
+static boolean
+qt_comment(s)
+       char *s;
+{
+       if(s[0] == '#') return(TRUE);
+       return((boolean)(!in_msg  && strlen(s) == NO_MSG));
+}
+
+static boolean
+qt_control(s)
+       char *s;
+{
+       return((boolean)(s[0] == '%' && (s[1] == 'C' || s[1] == 'E')));
+}
+
+static int
+get_hdr (code)
+       char *code;
+{
+       int     i;
+
+       for(i = 0; i < qt_hdr.n_hdr; i++)
+           if(!strncmp(code, qt_hdr.id[i], LEN_HDR)) return (++i);
+
+       return(0);
+}
+
+static boolean
+new_id (code)
+       char *code;
+{
+       if(qt_hdr.n_hdr >= N_HDR) {
+           Fprintf(stderr, OUT_OF_HEADERS, qt_line);
+           return(FALSE);
+       }
+
+       strncpy(&qt_hdr.id[qt_hdr.n_hdr][0], code, LEN_HDR);
+       msg_hdr[qt_hdr.n_hdr].n_msg = 0;
+       qt_hdr.offset[qt_hdr.n_hdr++] = 0L;
+       return(TRUE);
+}
+
+static boolean
+known_msg(num, id)
+       int num, id;
+{
+       int i;
+
+       for(i = 0; i < msg_hdr[num].n_msg; i++)
+           if(msg_hdr[num].qt_msg[i].msgnum == id) return(TRUE);
+
+       return(FALSE);
+}
+
+
+static void
+new_msg(s, num, id)
+       char *s;
+       int num, id;
+{
+       struct  qtmsg   *qt_msg;
+
+       if(msg_hdr[num].n_msg >= N_MSG) {
+               Fprintf(stderr, OUT_OF_MESSAGES, qt_line);
+       } else {
+               qt_msg = &(msg_hdr[num].qt_msg[msg_hdr[num].n_msg++]);
+               qt_msg->msgnum = id;
+               qt_msg->delivery = s[2];
+               qt_msg->offset = qt_msg->size = 0L;
+
+               curr_msg = qt_msg;
+       }
+}
+
+static void
+do_qt_control(s)
+       char *s;
+{
+       char code[BUFSZ];
+       int num, id = 0;
+
+       switch(s[1]) {
+
+           case 'C':   if(in_msg) {
+                           Fprintf(stderr, CREC_IN_MSG, qt_line);
+                           break;
+                       } else {
+                           in_msg = TRUE;
+                           if (sscanf(&s[4], "%s %5d", code, &id) != 2) {
+                               Fprintf(stderr, UNREC_CREC, qt_line);
+                               break;
+                           }
+                           num = get_hdr(code);
+                           if (!num && !new_id(code))
+                               break;
+                           num = get_hdr(code)-1;
+                           if(known_msg(num, id))
+                               Fprintf(stderr, DUP_MSG, qt_line);
+                           else new_msg(s, num, id);
+                       }
+                       break;
+
+           case 'E':   if(!in_msg) {
+                           Fprintf(stderr, END_NOT_IN_MSG, qt_line);
+                           break;
+                       } else in_msg = FALSE;
+                       break;
+
+           default:    Fprintf(stderr, UNREC_CREC, qt_line);
+                       break;
+       }
+}
+
+static void
+do_qt_text(s)
+       char *s;
+{
+       if (!in_msg) {
+           Fprintf(stderr, TEXT_NOT_IN_MSG, qt_line);
+       }
+       curr_msg->size += strlen(s);
+       return;
+}
+
+static void
+adjust_qt_hdrs()
+{
+       int     i, j;
+       long count = 0L, hdr_offset = sizeof(int) +
+                       (sizeof(char)*LEN_HDR + sizeof(long)) * qt_hdr.n_hdr;
+
+       for(i = 0; i < qt_hdr.n_hdr; i++) {
+           qt_hdr.offset[i] = hdr_offset;
+           hdr_offset += sizeof(int) + sizeof(struct qtmsg) * msg_hdr[i].n_msg;
+       }
+
+       for(i = 0; i < qt_hdr.n_hdr; i++)
+           for(j = 0; j < msg_hdr[i].n_msg; j++) {
+
+               msg_hdr[i].qt_msg[j].offset = hdr_offset + count;
+               count += msg_hdr[i].qt_msg[j].size;
+           }
+       return;
+}
+
+static void
+put_qt_hdrs()
+{
+       int     i;
+
+       /*
+        *      The main header record.
+        */
+#ifdef DEBUG
+       Fprintf(stderr, "%ld: header info.\n", ftell(ofp));
+#endif
+       (void) fwrite((genericptr_t)&(qt_hdr.n_hdr), sizeof(int), 1, ofp);
+       (void) fwrite((genericptr_t)&(qt_hdr.id[0][0]), sizeof(char)*LEN_HDR,
+                                                       qt_hdr.n_hdr, ofp);
+       (void) fwrite((genericptr_t)&(qt_hdr.offset[0]), sizeof(long),
+                                                       qt_hdr.n_hdr, ofp);
+#ifdef DEBUG
+       for(i = 0; i < qt_hdr.n_hdr; i++)
+               Fprintf(stderr, "%c @ %ld, ", qt_hdr.id[i], qt_hdr.offset[i]);
+
+       Fprintf(stderr, "\n");
+#endif
+
+       /*
+        *      The individual class headers.
+        */
+       for(i = 0; i < qt_hdr.n_hdr; i++) {
+
+#ifdef DEBUG
+           Fprintf(stderr, "%ld: %c header info.\n", ftell(ofp),
+                   qt_hdr.id[i]);
+#endif
+           (void) fwrite((genericptr_t)&(msg_hdr[i].n_msg), sizeof(int),
+                                                       1, ofp);
+           (void) fwrite((genericptr_t)&(msg_hdr[i].qt_msg[0]),
+                           sizeof(struct qtmsg), msg_hdr[i].n_msg, ofp);
+#ifdef DEBUG
+           { int j;
+             for(j = 0; j < msg_hdr[i].n_msg; j++)
+               Fprintf(stderr, "msg %d @ %ld (%ld)\n",
+                       msg_hdr[i].qt_msg[j].msgnum,
+                       msg_hdr[i].qt_msg[j].offset,
+                       msg_hdr[i].qt_msg[j].size);
+           }
+#endif
+       }
+}
+
+void
+do_questtxt()
+{
+       Sprintf(filename, DATA_IN_TEMPLATE, QTXT_I_FILE);
+       if(!(ifp = fopen(filename, RDTMODE))) {
+               perror(filename);
+               exit(EXIT_FAILURE);
+       }
+
+       filename[0]='\0';
+#ifdef FILE_PREFIX
+       Strcat(filename, file_prefix);
+#endif
+       Sprintf(eos(filename), DATA_TEMPLATE, QTXT_O_FILE);
+       if(!(ofp = fopen(filename, WRBMODE))) {
+               perror(filename);
+               Fclose(ifp);
+               exit(EXIT_FAILURE);
+       }
+
+       qt_hdr.n_hdr = 0;
+       qt_line = 0;
+       in_msg = FALSE;
+
+       while (fgets(in_line, 80, ifp) != 0) {
+           SpinCursor (3);
+
+           qt_line++;
+           if(qt_control(in_line)) do_qt_control(in_line);
+           else if(qt_comment(in_line)) continue;
+           else                    do_qt_text(in_line);
+       }
+
+       (void) rewind(ifp);
+       in_msg = FALSE;
+       adjust_qt_hdrs();
+       put_qt_hdrs();
+       while (fgets(in_line, 80, ifp) != 0) {
+
+               if(qt_control(in_line)) {
+                   in_msg = (in_line[1] == 'C');
+                   continue;
+               } else if(qt_comment(in_line)) continue;
+#ifdef DEBUG
+               Fprintf(stderr, "%ld: %s", ftell(stdout), in_line);
+#endif
+               (void) fputs(xcrypt(in_line), ofp);
+       }
+       Fclose(ifp);
+       Fclose(ofp);
+       return;
+}
+
+
+static char    temp[32];
+
+static char *
+limit(name,pref)       /* limit a name to 30 characters length */
+char   *name;
+int    pref;
+{
+       (void) strncpy(temp, name, pref ? 26 : 30);
+       temp[pref ? 26 : 30] = 0;
+       return temp;
+}
+
+void
+do_objs()
+{
+       int i, sum = 0;
+       char *c, *objnam;
+       int nspell = 0;
+       int prefix = 0;
+       char class = '\0';
+       boolean sumerr = FALSE;
+
+       filename[0]='\0';
+#ifdef FILE_PREFIX
+       Strcat(filename, file_prefix);
+#endif
+       Sprintf(eos(filename), INCLUDE_TEMPLATE, ONAME_FILE);
+       if (!(ofp = fopen(filename, WRTMODE))) {
+               perror(filename);
+               exit(EXIT_FAILURE);
+       }
+       Fprintf(ofp,"/*\tSCCS Id: @(#)onames.h\t3.4\t2002/02/03 */\n\n");
+       Fprintf(ofp,Dont_Edit_Code);
+       Fprintf(ofp,"#ifndef ONAMES_H\n#define ONAMES_H\n\n");
+
+       for(i = 0; !i || objects[i].oc_class != ILLOBJ_CLASS; i++) {
+               SpinCursor(3);
+
+               objects[i].oc_name_idx = objects[i].oc_descr_idx = i;   /* init */
+               if (!(objnam = tmpdup(OBJ_NAME(objects[i])))) continue;
+
+               /* make sure probabilities add up to 1000 */
+               if(objects[i].oc_class != class) {
+                       if (sum && sum != 1000) {
+                           Fprintf(stderr, "prob error for class %d (%d%%)",
+                                   class, sum);
+                           (void) fflush(stderr);
+                           sumerr = TRUE;
+                       }
+                       class = objects[i].oc_class;
+                       sum = 0;
+               }
+
+               for (c = objnam; *c; c++)
+                   if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
+                   else if (*c < 'A' || *c > 'Z') *c = '_';
+
+               switch (class) {
+                   case WAND_CLASS:
+                       Fprintf(ofp,"#define\tWAN_"); prefix = 1; break;
+                   case RING_CLASS:
+                       Fprintf(ofp,"#define\tRIN_"); prefix = 1; break;
+                   case POTION_CLASS:
+                       Fprintf(ofp,"#define\tPOT_"); prefix = 1; break;
+                   case SPBOOK_CLASS:
+                       Fprintf(ofp,"#define\tSPE_"); prefix = 1; nspell++; break;
+                   case SCROLL_CLASS:
+                       Fprintf(ofp,"#define\tSCR_"); prefix = 1; break;
+                   case AMULET_CLASS:
+                       /* avoid trouble with stupid C preprocessors */
+                       Fprintf(ofp,"#define\t");
+                       if(objects[i].oc_material == PLASTIC) {
+                           Fprintf(ofp,"FAKE_AMULET_OF_YENDOR\t%d\n", i);
+                           prefix = -1;
+                           break;
+                       }
+                       break;
+                   case GEM_CLASS:
+                       /* avoid trouble with stupid C preprocessors */
+                       if(objects[i].oc_material == GLASS) {
+                           Fprintf(ofp,"/* #define\t%s\t%d */\n",
+                                                       objnam, i);
+                           prefix = -1;
+                           break;
+                       }
+                   default:
+                       Fprintf(ofp,"#define\t");
+               }
+               if (prefix >= 0)
+                       Fprintf(ofp,"%s\t%d\n", limit(objnam, prefix), i);
+               prefix = 0;
+
+               sum += objects[i].oc_prob;
+       }
+
+       /* check last set of probabilities */
+       if (sum && sum != 1000) {
+           Fprintf(stderr, "prob error for class %d (%d%%)", class, sum);
+           (void) fflush(stderr);
+           sumerr = TRUE;
+       }
+
+       Fprintf(ofp,"#define\tLAST_GEM\t(JADE)\n");
+       Fprintf(ofp,"#define\tMAXSPELL\t%d\n", nspell+1);
+       Fprintf(ofp,"#define\tNUM_OBJECTS\t%d\n", i);
+
+       Fprintf(ofp, "\n/* Artifacts (unique objects) */\n\n");
+
+       for (i = 1; artifact_names[i]; i++) {
+               SpinCursor(3);
+
+               for (c = objnam = tmpdup(artifact_names[i]); *c; c++)
+                   if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
+                   else if (*c < 'A' || *c > 'Z') *c = '_';
+
+               if (!strncmp(objnam, "THE_", 4))
+                       objnam += 4;
+#ifdef TOURIST
+               /* fudge _platinum_ YENDORIAN EXPRESS CARD */
+               if (!strncmp(objnam, "PLATINUM_", 9))
+                       objnam += 9;
+#endif
+               Fprintf(ofp,"#define\tART_%s\t%d\n", limit(objnam, 1), i);
+       }
+
+       Fprintf(ofp, "#define\tNROFARTIFACTS\t%d\n", i-1);
+       Fprintf(ofp,"\n#endif /* ONAMES_H */\n");
+       Fclose(ofp);
+       if (sumerr) exit(EXIT_FAILURE);
+       return;
+}
+
+static char *
+tmpdup(str)
+const char *str;
+{
+       static char buf[128];
+
+       if (!str) return (char *)0;
+       (void)strncpy(buf, str, 127);
+       return buf;
+}
+
+static char *
+eos(str)
+char *str;
+{
+    while (*str) str++;
+    return str;
+}
+
+/*
+ * macro used to control vision algorithms:
+ *      VISION_TABLES => generate tables
+ */
+
+void
+do_vision()
+{
+#ifdef VISION_TABLES
+    int i, j;
+
+    /* Everything is clear.  xclear may be malloc'ed.
+     * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH)
+     */
+    for (i = 0; i < MAX_ROW; i++)
+       for (j = 0; j < MAX_COL; j++)
+           if (i < BLOCK_HEIGHT && j < BLOCK_WIDTH)
+               xclear[i][j] = '\000';
+           else
+               xclear[i][j] = '\001';
+#endif /* VISION_TABLES */
+
+    SpinCursor(3);
+
+    /*
+     * create the include file, "vis_tab.h"
+     */
+    filename[0]='\0';
+#ifdef FILE_PREFIX
+    Strcat(filename, file_prefix);
+#endif
+    Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
+    if (!(ofp = fopen(filename, WRTMODE))) {
+       perror(filename);
+       exit(EXIT_FAILURE);
+    }
+    Fprintf(ofp,Dont_Edit_Code);
+    Fprintf(ofp,"#ifdef VISION_TABLES\n");
+#ifdef VISION_TABLES
+    H_close_gen();
+    H_far_gen();
+#endif /* VISION_TABLES */
+    Fprintf(ofp,"\n#endif /* VISION_TABLES */\n");
+    Fclose(ofp);
+
+    SpinCursor(3);
+
+    /*
+     * create the source file, "vis_tab.c"
+     */
+    filename[0]='\0';
+#ifdef FILE_PREFIX
+    Strcat(filename, file_prefix);
+#endif
+    Sprintf(filename, SOURCE_TEMPLATE, VIS_TAB_C);
+    if (!(ofp = fopen(filename, WRTMODE))) {
+       perror(filename);
+       Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
+       Unlink(filename);
+       exit(EXIT_FAILURE);
+    }
+    Fprintf(ofp,Dont_Edit_Code);
+    Fprintf(ofp,"#include \"config.h\"\n");
+    Fprintf(ofp,"#ifdef VISION_TABLES\n");
+    Fprintf(ofp,"#include \"vis_tab.h\"\n");
+
+    SpinCursor(3);
+
+#ifdef VISION_TABLES
+    C_close_gen();
+    C_far_gen();
+    Fprintf(ofp,"\nvoid vis_tab_init() { return; }\n");
+#endif /* VISION_TABLES */
+
+    SpinCursor(3);
+
+    Fprintf(ofp,"\n#endif /* VISION_TABLES */\n");
+    Fprintf(ofp,"\n/*vis_tab.c*/\n");
+
+    Fclose(ofp);
+    return;
+}
+
+#ifdef VISION_TABLES
+
+/*--------------  vision tables  --------------*\
+ *
+ *  Generate the close and far tables.  This is done by setting up a
+ *  fake dungeon and moving our source to different positions relative
+ *  to a block and finding the first/last visible position.  The fake
+ *  dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT
+ *  by BLOCK_WIDTH) is blocked.  Then we move the source around relative
+ *  to the corner of the block.  For each new position of the source
+ *  we check positions on rows "kittycorner" from the source.  We check
+ *  positions until they are either in sight or out of sight (depends on
+ *  which table we are generating).  The picture below shows the setup
+ *  for the generation of the close table.  The generation of the far
+ *  table would switch the quadrants of the '@' and the "Check rows
+ *  here".
+ *
+ *
+ *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,,
+ *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ *  ...............................
+ *  ...............................
+ *  .........@.....................
+ *  ...............................
+ *
+ *      Table generation figure (close_table).  The 'X's are blocked points.
+ *      The 'B' is a special blocked point.  The '@' is the source.  The ','s
+ *      are the target area.  The '.' are just open areas.
+ *
+ *
+ *  Example usage of close_table[][][].
+ *
+ *  The table is as follows:
+ *
+ *      dy = |row of '@' - row of 'B'|  - 1
+ *      dx = |col of '@' - col of 'B'|
+ *
+ *  The first indices are the deltas from the source '@' and the block 'B'.
+ *  You must check for the value inside the abs value bars being zero.  If
+ *  so then the block is on the same row and you don't need to do a table
+ *  lookup.  The last value:
+ *
+ *      dcy = |row of block - row to be checked|
+ *
+ *  Is the value of the first visible spot on the check row from the
+ *  block column.  So
+ *
+ *  first visible col = close_table[dy][dx][dcy] + col of 'B'
+ *
+\*--------------  vision tables  --------------*/
+
+static void
+H_close_gen()
+{
+    Fprintf(ofp,"\n/* Close */\n");
+    Fprintf(ofp,"#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n",
+           TEST_HEIGHT-1);
+    Fprintf(ofp,"#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n",
+           TEST_WIDTH);
+    Fprintf(ofp,"#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n",
+           TEST_HEIGHT);
+    Fprintf(ofp,"typedef struct {\n");
+    Fprintf(ofp,"    unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n");
+    Fprintf(ofp,"} close2d;\n");
+    Fprintf(ofp,"extern close2d close_table[CLOSE_MAX_SB_DY];\n");
+    return;
+}
+
+static void
+H_far_gen()
+{
+    Fprintf(ofp,"\n/* Far */\n");
+    Fprintf(ofp,"#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n",
+           TEST_HEIGHT);
+    Fprintf(ofp,"#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n",
+           TEST_WIDTH-1);
+    Fprintf(ofp,"#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n",
+           TEST_HEIGHT-1);
+    Fprintf(ofp,"typedef struct {\n");
+    Fprintf(ofp,"    unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n");
+    Fprintf(ofp,"} far2d;\n");
+    Fprintf(ofp,"extern far2d far_table[FAR_MAX_SB_DY];\n");
+    return;
+}
+
+static void
+C_close_gen()
+{
+    int i,dx,dy;
+    int src_row, src_col;      /* source */
+    int block_row, block_col;  /* block */
+    int this_row;
+    int no_more;
+    const char *delim;
+
+    block_row = BLOCK_HEIGHT-1;
+    block_col = BLOCK_WIDTH-1;
+
+    Fprintf(ofp,"\n#ifndef FAR_TABLE_ONLY\n");
+    Fprintf(ofp,"\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n");
+#ifndef no_vision_progress
+    Fprintf(stderr,"\nclose:");
+#endif
+
+    for (dy = 1; dy < TEST_HEIGHT; dy++) {
+       src_row = block_row + dy;
+       Fprintf(ofp, "/* DY = %2d (- 1)*/\n  {{\n", dy);
+#ifndef no_vision_progress
+       Fprintf(stderr," %2d",dy),  (void)fflush(stderr);
+#endif
+       for (dx = 0; dx < TEST_WIDTH; dx++) {
+           src_col = block_col - dx;
+           Fprintf(ofp, "  /*%2d*/ {", dx);
+
+           no_more = 0;
+           for (this_row = 0; this_row < TEST_HEIGHT; this_row++) {
+               delim = (this_row < TEST_HEIGHT - 1) ? "," : "";
+               if (no_more) {
+                   Fprintf(ofp, "%s%s", CLOSE_OFF_TABLE_STRING, delim);
+                   continue;
+               }
+               SpinCursor(3);
+
+               /* Find the first column that we can see. */
+               for (i = block_col+1; i < MAX_COL; i++) {
+                   if (clear_path(src_row,src_col,block_row-this_row,i))
+                       break;
+               }
+
+               if (i == MAX_COL) no_more = 1;
+               Fprintf(ofp, "%2d%s", i - block_col, delim);
+           }
+           Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
+       }
+       Fprintf(ofp,"  }},\n");
+    }
+
+    Fprintf(ofp,"}; /* close_table[] */\n");           /* closing brace for table */
+    Fprintf(ofp,"#endif /* !FAR_TABLE_ONLY */\n");
+#ifndef no_vision_progress
+    Fprintf(stderr,"\n");
+#endif
+    return;
+}
+
+static void
+C_far_gen()
+{
+    int i,dx,dy;
+    int src_row, src_col;      /* source */
+    int block_row, block_col;  /* block */
+    int this_row;
+    const char *delim;
+
+    block_row = BLOCK_HEIGHT-1;
+    block_col = BLOCK_WIDTH-1;
+
+    Fprintf(ofp,"\n#ifndef CLOSE_TABLE_ONLY\n");
+    Fprintf(ofp,"\nfar2d far_table[FAR_MAX_SB_DY] = {\n");
+#ifndef no_vision_progress
+    Fprintf(stderr,"\n_far_:");
+#endif
+
+    for (dy = 0; dy < TEST_HEIGHT; dy++) {
+       src_row = block_row - dy;
+       Fprintf(ofp, "/* DY = %2d */\n  {{\n", dy);
+#ifndef no_vision_progress
+       Fprintf(stderr," %2d",dy),  (void)fflush(stderr);
+#endif
+       for (dx = 1; dx < TEST_WIDTH; dx++) {
+           src_col = block_col + dx;
+           Fprintf(ofp, "  /*%2d(-1)*/ {", dx);
+
+           for (this_row = block_row+1; this_row < block_row+TEST_HEIGHT;
+                                                               this_row++) {
+               delim = (this_row < block_row + TEST_HEIGHT - 1) ? "," : "";
+
+               SpinCursor(3);
+               /* Find first col that we can see. */
+               for (i = 0; i <= block_col; i++) {
+                   if (clear_path(src_row,src_col,this_row,i)) break;
+               }
+
+               if (block_col-i < 0)
+                   Fprintf(ofp, "%s%s", FAR_OFF_TABLE_STRING, delim);
+               else
+                   Fprintf(ofp, "%2d%s", block_col - i, delim);
+           }
+           Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
+       }
+       Fprintf(ofp,"  }},\n");
+    }
+
+    Fprintf(ofp,"}; /* far_table[] */\n");     /* closing brace for table */
+    Fprintf(ofp,"#endif /* !CLOSE_TABLE_ONLY */\n");
+#ifndef no_vision_progress
+    Fprintf(stderr,"\n");
+#endif
+    return;
+}
+
+/*
+ *  "Draw" a line from the hero to the given location.  Stop if we hit a
+ *  wall.
+ *
+ *  Generalized integer Bresenham's algorithm (fast line drawing) for
+ *  all quadrants.  From _Procedural Elements for Computer Graphics_, by
+ *  David F. Rogers.  McGraw-Hill, 1985.
+ *
+ *  I have tried a little bit of optimization by pulling compares out of
+ *  the inner loops.
+ *
+ *  NOTE:  This had better *not* be called from a position on the
+ *  same row as the hero.
+ */
+static int
+clear_path(you_row,you_col,y2,x2)
+    int you_row, you_col, y2, x2;
+{
+    int dx, dy, s1, s2;
+    register int i, error, x, y, dxs, dys;
+
+    x  = you_col;              y  = you_row;
+    dx = abs(x2-you_col);      dy = abs(y2-you_row);
+    s1 = sign(x2-you_col);     s2 = sign(y2-you_row);
+
+    if (s1 == 0) {     /* same column */
+       if (s2 == 1) {  /* below (larger y2 value) */
+           for (i = you_row+1; i < y2; i++)
+               if (!xclear[i][you_col]) return 0;
+       } else {        /* above (smaller y2 value) */
+           for (i = y2+1; i < you_row; i++)
+               if (!xclear[i][you_col]) return 0;
+       }
+       return 1;
+    }
+
+    /*
+     *  Lines at 0 and 90 degrees have been weeded out.
+     */
+    if (dy > dx) {
+       error = dx; dx = dy; dy = error;        /* swap the values */
+       dxs = dx << 1;          /* save the shifted values */
+       dys = dy << 1;
+       error = dys - dx;       /* NOTE: error is used as a temporary above */
+
+       for (i = 0; i < dx; i++) {
+           if (!xclear[y][x]) return 0;        /* plot point */
+
+           while (error >= 0) {
+               x += s1;
+               error -= dxs;
+           }
+           y += s2;
+           error += dys;
+       }
+    } else {
+       dxs = dx << 1;          /* save the shifted values */
+       dys = dy << 1;
+       error = dys - dx;
+
+       for (i = 0; i < dx; i++) {
+           if (!xclear[y][x]) return 0;        /* plot point */
+
+           while (error >= 0) {
+               y += s2;
+               error -= dxs;
+           }
+           x += s1;
+           error += dys;
+       }
+    }
+    return 1;
+}
+#endif /* VISION_TABLES */
+
+#ifdef STRICT_REF_DEF
+NEARDATA struct flag flags;
+# ifdef ATTRIB_H
+struct attribs attrmax, attrmin;
+# endif
+#endif /* STRICT_REF_DEF */
+
+/*makedefs.c*/
diff --git a/util/panic.c b/util/panic.c
new file mode 100644 (file)
index 0000000..5a5c41d
--- /dev/null
@@ -0,0 +1,61 @@
+/*     SCCS Id: @(#)panic.c    3.4     1994/03/02      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *     This code was adapted from the code in end.c to run in a standalone
+ *     mode for the makedefs / drg code.
+ */
+
+#define NEED_VARARGS
+#include "config.h"
+
+#ifdef AZTEC
+#define abort() exit()
+#endif
+#ifdef VMS
+extern void NDECL(vms_abort);
+#endif
+
+/*VARARGS1*/
+boolean panicking;
+void VDECL(panic, (char *,...));
+
+void
+panic VA_DECL(char *,str)
+       VA_START(str);
+       VA_INIT(str, char *);
+       if(panicking++)
+#ifdef SYSV
+           (void)
+#endif
+               abort();    /* avoid loops - this should never happen*/
+
+       (void) fputs(" ERROR:  ", stderr);
+       Vfprintf(stderr, str, VA_ARGS);
+       (void) fflush(stderr);
+#if defined(UNIX) || defined(VMS)
+# ifdef SYSV
+               (void)
+# endif
+                   abort();    /* generate core dump */
+#endif
+       VA_END();
+       exit(EXIT_FAILURE);             /* redundant */
+       return;
+}
+
+#ifdef ALLOCA_HACK
+/*
+ * In case bison-generated foo_yacc.c tries to use alloca(); if we don't
+ * have it then just use malloc() instead.  This may not work on some
+ * systems, but they should either use yacc or get a real alloca routine.
+ */
+long *alloca(cnt)
+unsigned cnt;
+{
+       return cnt ? alloc(cnt) : (long *)0;
+}
+#endif
+
+/*panic.c*/
diff --git a/util/recover.c b/util/recover.c
new file mode 100644 (file)
index 0000000..cc1b819
--- /dev/null
@@ -0,0 +1,399 @@
+/*     SCCS Id: @(#)recover.c  3.4     1999/10/23      */
+/*     Copyright (c) Janet Walz, 1992.                           */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *  Utility for reconstructing NetHack save file from a set of individual
+ *  level files.  Requires that the `checkpoint' option be enabled at the
+ *  time NetHack creates those level files.
+ */
+#include "config.h"
+#if !defined(O_WRONLY) && !defined(LSC) && !defined(AZTEC_C)
+#include <fcntl.h>
+#endif
+#ifdef WIN32
+#include <errno.h>
+#include "win32api.h"
+#endif
+
+#ifdef VMS
+extern int FDECL(vms_creat, (const char *,unsigned));
+extern int FDECL(vms_open, (const char *,int,unsigned));
+#endif /* VMS */
+
+int FDECL(restore_savefile, (char *));
+void FDECL(set_levelfile_name, (int));
+int FDECL(open_levelfile, (int));
+int NDECL(create_savefile);
+void FDECL(copy_bytes, (int,int));
+
+#ifndef WIN_CE
+#define Fprintf        (void)fprintf
+#else
+#define Fprintf        (void)nhce_message
+static void nhce_message(FILE*, const char*, ...);
+#endif
+
+#define Close  (void)close
+
+#ifdef UNIX
+#define SAVESIZE       (PL_NSIZ + 13)  /* save/99999player.e */
+#else
+# ifdef VMS
+#define SAVESIZE       (PL_NSIZ + 22)  /* [.save]<uid>player.e;1 */
+# else
+#  ifdef WIN32
+#define SAVESIZE       (PL_NSIZ + 40)  /* username-player.NetHack-saved-game */
+#  else
+#define SAVESIZE       FILENAME        /* from macconf.h or pcconf.h */
+#  endif
+# endif
+#endif
+
+#if defined(EXEPATH)
+char *FDECL(exepath, (char *));
+#endif
+
+#if defined(__BORLANDC__) && !defined(_WIN32)
+extern unsigned _stklen = STKSIZ;
+#endif
+char savename[SAVESIZE]; /* holds relative path of save file from playground */
+
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       int argno;
+       const char *dir = (char *)0;
+#ifdef AMIGA
+       char *startdir = (char *)0;
+#endif
+
+
+       if (!dir) dir = getenv("NETHACKDIR");
+       if (!dir) dir = getenv("HACKDIR");
+#if defined(EXEPATH)
+       if (!dir) dir = exepath(argv[0]);
+#endif
+       if (argc == 1 || (argc == 2 && !strcmp(argv[1], "-"))) {
+           Fprintf(stderr,
+               "Usage: %s [ -d directory ] base1 [ base2 ... ]\n", argv[0]);
+#if defined(WIN32) || defined(MSDOS)
+           if (dir) {
+               Fprintf(stderr, "\t(Unless you override it with -d, recover will look \n");
+               Fprintf(stderr, "\t in the %s directory on your system)\n", dir);
+           }
+#endif
+           exit(EXIT_FAILURE);
+       }
+
+       argno = 1;
+       if (!strncmp(argv[argno], "-d", 2)) {
+               dir = argv[argno]+2;
+               if (*dir == '=' || *dir == ':') dir++;
+               if (!*dir && argc > argno) {
+                       argno++;
+                       dir = argv[argno];
+               }
+               if (!*dir) {
+                   Fprintf(stderr,
+                       "%s: flag -d must be followed by a directory name.\n",
+                       argv[0]);
+                   exit(EXIT_FAILURE);
+               }
+               argno++;
+       }
+#if defined(SECURE) && !defined(VMS)
+       if (dir
+# ifdef HACKDIR
+               && strcmp(dir, HACKDIR)
+# endif
+               ) {
+               (void) setgid(getgid());
+               (void) setuid(getuid());
+       }
+#endif /* SECURE && !VMS */
+
+#ifdef HACKDIR
+       if (!dir) dir = HACKDIR;
+#endif
+
+#ifdef AMIGA
+       startdir = getcwd(0,255);
+#endif
+       if (dir && chdir((char *) dir) < 0) {
+               Fprintf(stderr, "%s: cannot chdir to %s.\n", argv[0], dir);
+               exit(EXIT_FAILURE);
+       }
+
+       while (argc > argno) {
+               if (restore_savefile(argv[argno]) == 0)
+                   Fprintf(stderr, "recovered \"%s\" to %s\n",
+                           argv[argno], savename);
+               argno++;
+       }
+#ifdef AMIGA
+       if (startdir) (void)chdir(startdir);
+#endif
+       exit(EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
+
+static char lock[256];
+
+void
+set_levelfile_name(lev)
+int lev;
+{
+       char *tf;
+
+       tf = rindex(lock, '.');
+       if (!tf) tf = lock + strlen(lock);
+       (void) sprintf(tf, ".%d", lev);
+#ifdef VMS
+       (void) strcat(tf, ";1");
+#endif
+}
+
+int
+open_levelfile(lev)
+int lev;
+{
+       int fd;
+
+       set_levelfile_name(lev);
+#if defined(MICRO) || defined(WIN32) || defined(MSDOS)
+       fd = open(lock, O_RDONLY | O_BINARY);
+#else
+       fd = open(lock, O_RDONLY, 0);
+#endif
+       return fd;
+}
+
+int
+create_savefile()
+{
+       int fd;
+
+#if defined(MICRO) || defined(WIN32) || defined(MSDOS)
+       fd = open(savename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
+#else
+       fd = creat(savename, FCMASK);
+#endif
+       return fd;
+}
+
+void
+copy_bytes(ifd, ofd)
+int ifd, ofd;
+{
+       char buf[BUFSIZ];
+       int nfrom, nto;
+
+       do {
+               nfrom = read(ifd, buf, BUFSIZ);
+               nto = write(ofd, buf, nfrom);
+               if (nto != nfrom) {
+                       Fprintf(stderr, "file copy failed!\n");
+                       exit(EXIT_FAILURE);
+               }
+       } while (nfrom == BUFSIZ);
+}
+
+int
+restore_savefile(basename)
+char *basename;
+{
+       int gfd, lfd, sfd;
+       int lev, savelev, hpid;
+       xchar levc;
+       struct version_info version_data;
+
+       /* level 0 file contains:
+        *      pid of creating process (ignored here)
+        *      level number for current level of save file
+        *      name of save file nethack would have created
+        *      and game state
+        */
+       (void) strcpy(lock, basename);
+       gfd = open_levelfile(0);
+       if (gfd < 0) {
+#if defined(WIN32) && !defined(WIN_CE)
+           if(errno == EACCES) {
+               Fprintf(stderr,
+                       "\nThere are files from a game in progress under your name.");
+               Fprintf(stderr,"\nThe files are locked or inaccessible.");
+               Fprintf(stderr,"\nPerhaps the other game is still running?\n");
+           } else
+               Fprintf(stderr,
+                       "\nTrouble accessing level 0 (errno = %d).\n", errno);
+#endif
+           Fprintf(stderr, "Cannot open level 0 for %s.\n", basename);
+           return(-1);
+       }
+       if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) {
+           Fprintf(stderr, "%s\n%s%s%s\n",
+            "Checkpoint data incompletely written or subsequently clobbered;",
+                   "recovery for \"", basename, "\" impossible.");
+           Close(gfd);
+           return(-1);
+       }
+       if (read(gfd, (genericptr_t) &savelev, sizeof(savelev))
+                                                       != sizeof(savelev)) {
+           Fprintf(stderr,
+           "Checkpointing was not in effect for %s -- recovery impossible.\n",
+                   basename);
+           Close(gfd);
+           return(-1);
+       }
+       if ((read(gfd, (genericptr_t) savename, sizeof savename)
+               != sizeof savename) ||
+           (read(gfd, (genericptr_t) &version_data, sizeof version_data)
+               != sizeof version_data)) {
+           Fprintf(stderr, "Error reading %s -- can't recover.\n", lock);
+           Close(gfd);
+           return(-1);
+       }
+
+       /* save file should contain:
+        *      version info
+        *      current level (including pets)
+        *      (non-level-based) game state
+        *      other levels
+        */
+       sfd = create_savefile();
+       if (sfd < 0) {
+           Fprintf(stderr, "Cannot create savefile %s.\n", savename);
+           Close(gfd);
+           return(-1);
+       }
+
+       lfd = open_levelfile(savelev);
+       if (lfd < 0) {
+           Fprintf(stderr, "Cannot open level of save for %s.\n", basename);
+           Close(gfd);
+           Close(sfd);
+           return(-1);
+       }
+
+       if (write(sfd, (genericptr_t) &version_data, sizeof version_data)
+               != sizeof version_data) {
+           Fprintf(stderr, "Error writing %s; recovery failed.\n", savename);
+           Close(gfd);
+           Close(sfd);
+           return(-1);
+       }
+
+       copy_bytes(lfd, sfd);
+       Close(lfd);
+       (void) unlink(lock);
+
+       copy_bytes(gfd, sfd);
+       Close(gfd);
+       set_levelfile_name(0);
+       (void) unlink(lock);
+
+       for (lev = 1; lev < 256; lev++) {
+               /* level numbers are kept in xchars in save.c, so the
+                * maximum level number (for the endlevel) must be < 256
+                */
+               if (lev != savelev) {
+                       lfd = open_levelfile(lev);
+                       if (lfd >= 0) {
+                               /* any or all of these may not exist */
+                               levc = (xchar) lev;
+                               write(sfd, (genericptr_t) &levc, sizeof(levc));
+                               copy_bytes(lfd, sfd);
+                               Close(lfd);
+                               (void) unlink(lock);
+                       }
+               }
+       }
+
+       Close(sfd);
+
+#if 0 /* OBSOLETE, HackWB is no longer in use */
+#ifdef AMIGA
+                       /* we need to create an icon for the saved game
+                        * or HackWB won't notice the file.
+                        */
+       {
+       char iconfile[FILENAME];
+       int in, out;
+
+       (void) sprintf(iconfile, "%s.info", savename);
+       in = open("NetHack:default.icon", O_RDONLY);
+       out = open(iconfile, O_WRONLY | O_TRUNC | O_CREAT);
+       if(in > -1 && out > -1){
+               copy_bytes(in,out);
+       }
+       if(in > -1)close(in);
+       if(out > -1)close(out);
+       }
+#endif
+#endif
+       return(0);
+}
+
+#ifdef EXEPATH
+# ifdef __DJGPP__
+#define PATH_SEPARATOR '/'
+# else
+#define PATH_SEPARATOR '\\'
+# endif
+
+#define EXEPATHBUFSZ 256
+char exepathbuf[EXEPATHBUFSZ];
+
+char *exepath(str)
+char *str;
+{
+       char *tmp, *tmp2;
+       int bsize;
+
+       if (!str) return (char *)0;
+       bsize = EXEPATHBUFSZ;
+       tmp = exepathbuf;
+#if !defined(WIN32)
+       strcpy (tmp, str);
+#else
+# if defined(WIN_CE)
+       {
+         TCHAR wbuf[EXEPATHBUFSZ];
+         GetModuleFileName((HANDLE)0, wbuf, EXEPATHBUFSZ);
+         NH_W2A(wbuf, tmp, bsize);
+       }
+# else
+       *(tmp + GetModuleFileName((HANDLE)0, tmp, bsize)) = '\0';
+# endif
+#endif
+       tmp2 = strrchr(tmp, PATH_SEPARATOR);
+       if (tmp2) *tmp2 = '\0';
+       return tmp;
+}
+#endif /* EXEPATH */
+
+#ifdef AMIGA
+#include "date.h"
+const char amiga_version_string[] = AMIGA_VERSION_STRING;
+#endif
+
+#ifdef WIN_CE
+void nhce_message(FILE* f, const char* str, ...)
+{
+    va_list ap;
+       TCHAR wbuf[NHSTR_BUFSIZE];
+       char buf[NHSTR_BUFSIZE];
+
+    va_start(ap, str);
+       vsprintf(buf, str, ap);
+    va_end(ap);
+
+       MessageBox(NULL, NH_A2W(buf, wbuf, NHSTR_BUFSIZE), TEXT("Recover"), MB_OK);
+}
+#endif
+
+/*recover.c*/
diff --git a/win/Qt/Info.plist b/win/Qt/Info.plist
new file mode 100644 (file)
index 0000000..2000fd7
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleGetInfoHTML</key>
+       <string>http://www.nethack.org</string>
+       <key>CFBundleGetInfoString</key>
+       <string>Copyright (C) 1985-2003 Stichting Mathematisch Centrum</string>
+       <key>CFBundleIconFile</key>
+       <string>nethack.icns</string>
+       <key>CFBundleIdentifier</key>
+       <string>org.nethack.qt</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>3.4.3</string>
+       <key>CFBundleSignature</key>
+       <string>NHak</string>
+</dict>
+</plist>
diff --git a/win/Qt/Install.Qt b/win/Qt/Install.Qt
new file mode 100644 (file)
index 0000000..7b6ef14
--- /dev/null
@@ -0,0 +1,92 @@
+Installing NetHack with a Qt or KDE interface
+---------------------------------------------
+
+This document describes the installation of NetHack with a Qt interface
+on UNIX/X11 or Mac OS X. This code should also work with Qt/Windows, but
+support for that is not currently official.
+
+You can download Qt for UNIX and Qt for Windows from http://www.trolltech.com.
+Qt for Mac OS X is currently only available commercially.  You need Qt 2.0 or
+later to use this code.
+
+To use this code:
+
+   1. follow the directions for the UNIX installation (in ../../sys/unix)
+      to create the Makefiles.
+
+   2. ../../include/config.h
+
+        define QT_GRAPHICS (search for it).  You can comment out
+        TTY_GRAPHICS if you want to, or leave it in to support both
+        interfaces (in which case be sure you have the right curses
+        libraries etc. required for that interface).
+
+   3. ../../src/Makefile
+
+       ensure your QTDIR environment variable was set correctly when
+       you installed Qt - $QTDIR/include/qwidget.h should exist, for
+       example.
+
+       ensure CXX and LD are set to the compiler and linker you need
+       for compiling and linking C++ software (e.g., set both to g++).
+
+        add $(WINQTSRC), $(WINQTOBJ), and $(WINQTLIB) to WINSRC, WINOBJ,
+        and WINLIB respectively, and compile.  This will give you an
+        executable supporting both Qt and tty windowing.
+
+   4. ../../Makefile (the top-level makefile)
+
+        change the VARDATND setting to contain the files "x11tiles",
+        "rip.xpm", and "nhsplash.xpm":
+
+            VARDATND = x11tiles rip.xpm nhsplash.xpm
+
+   5. Follow all the instructions in ../../sys/unix/Install.unx for
+      the remainder of the installation process.
+
+   6. Consider adding the lines below to your .nethackrc, as they are
+      likely to give the best interface for this window port:
+
+        OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp
+        OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt
+
+
+If you are using KDE, you may want to also try the KDE version. It just
+uses the KDE menubar and follows other KDE conventions - there is no
+extra functionality. To do so:
+
+   1. Ensure that you have KDE 2.x libraries on your system
+        (in 1999 KDE 1.x was the norm)
+
+   2. ../../src/Makefile
+
+      Add $(KDECXXFLAGS) to the CXXFLAGS definition, $(KDELFLAGS) to
+      the LFLAGS definition and $(WINKDELIB) to WINLIB.
+
+   3. Some additional files here - knh-mini.xpm, knh.xpm, and
+      knethack.lnk are useful if you want to install "knethack" in
+      the KDE games directory.  
+
+
+If you are using Qtopia, you can compile NetHack for that environment
+with the following additional steps:
+
+   1. First be sure that you can build a simple Qtopia application,
+      such as the examples that ship with Qtopia. Do not attempt
+      something as challenging to compile as NetHack before you can
+      already build a Qtopia application for your target device.
+
+   2. If you are cross-compiling (eg. targetting an ARM-based handheld),
+      be sure to follow the steps for cross-compiling in the Makefile.src
+      and Makefile.utl files.
+
+   3. To CXXFLAGS in Makefile.src, add:
+      -DQWS -I$(QPEDIR)/include -fno-rtti -fno-exceptions
+
+   4. Rather than -lqt in WINQTLIB, have:
+      -L$(QPEDIR)/lib -lqpe -lqte
+
+   5. After building, use the "mkipks" program that ships with Qtopia
+      to package the result into an ipk file.
+
+
diff --git a/win/Qt/knethack.lnk b/win/Qt/knethack.lnk
new file mode 100644 (file)
index 0000000..35e01f9
--- /dev/null
@@ -0,0 +1,18 @@
+# KDE Config File 
+# Call this file knethack.kdelnk or knethack.desktop
+[KDE Desktop Entry]
+Name=Nethack
+Name[fr]=Nethack
+Name[hu]=Nethack
+Name[no]=Nethack
+Name[sk]=Nethack
+Name[cs]=Nethack
+Name[hr]=Nethack
+Name[pt]=Nethack
+Name[pt_BR]=Nethack
+Icon=knh.xpm
+Exec=knethack -caption "%c" %i %m
+Type=Application
+DocPath=knethack/index.html
+Comment=The classic Unix role-playing game - fight monsters and seek the Amulet of Yendor for your god!
+
diff --git a/win/Qt/knh-mini.xpm b/win/Qt/knh-mini.xpm
new file mode 100644 (file)
index 0000000..05bd70e
--- /dev/null
@@ -0,0 +1,30 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"16 16 7 1",
+/* colors */
+"  c #000000",
+". c #DCDCDC",
+"X c #008080",
+"o c #A0A0A0",
+"O c None",
+"+ c #FFFFFF",
+"@ c #C3C3C3",
+/* pixels */
+"OOOOOOOOOOOOOOOO",
+"OOO+O+++@@@O@OOO",
+"O+O+++++@@@@@O.O",
+"O+o+XXXXX X @ . ",
+"O+o+XXXX X X@ . ",
+"OO +XXXXX X @ O ",
+"OOO+XXXX X X@ OO",
+"OOO+XXXXX X @ OO",
+"OOO+XXXX X X@ OO",
+"OOOO+XXXX X@  OO",
+"OOOO+XXX X .  OO",
+"OOO+O+XXX . . OO",
+"OO+++ +X . ... O",
+"O+++. O+.  .... ",
+"OO+.  OOOOOO.. O",
+"OOOOOOOOOOOOOOOO"
+};
diff --git a/win/Qt/knh.xpm b/win/Qt/knh.xpm
new file mode 100644 (file)
index 0000000..9c03127
--- /dev/null
@@ -0,0 +1,67 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 20 1",
+/* colors */
+"  c #000000",
+". c #0000C0",
+"X c #FFC0FF",
+"o c #FFC0C0",
+"O c #DCDCDC",
+"+ c #C0C0FF",
+"@ c #008080",
+"# c #A0A0A0",
+"$ c None",
+"% c #000080",
+"& c #585858",
+"* c #800080",
+"= c #FFFFFF",
+"- c #FFFFC0",
+"; c #00C0C0",
+": c #C0FFFF",
+"> c #C0FFC0",
+", c #C3C3C3",
+"< c #FFDCA8",
+"1 c #0000FF",
+/* pixels */
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$=$$$$$$=,==<,=<,$$$$$$,$$$$$$$$$",
+"$$$$$$$$==$$$=====,=<>,<><$$$<>$$$$$$$$$",
+"$$$$$$$$===$====,==>,=<,<,,$,,<$$$$$$$$$",
+"$$$==$$$==========<=<,><,><<><,$$$,<$$$$",
+"$$$====$========,==,,=<>,<,>,<,$<><,$$$$",
+"$$$====$==========<=<,,<<><,<><$,,<>$$$$",
+"$$$$#&&&==$#$#$#@#$&@#&&@&&&&,,   &&  $$",
+"$$$;#@&@==;#;#;#$;&#@&@$&@&@$><   &@  $$",
+"$$$====&==###1##.##@&#&@&&$&&<, <>O<  $$",
+"$$$====&==$;##;##;&#@&@$&@&@&>, O<,>  $$",
+"$$$==&@&==#1#;##.##@&#&@&$@$&,<   ,<  $$",
+"$$$$    ==###1#;##.#@$&&&@&&@-,   $   $$",
+"$$$$$   =X;#;###&;#&@#&@$&@$&,<   $$ $$$",
+"$$$$$$  ==#$+@+1##@#&@&$@&&&@<>   $$$$$$",
+"$$$$$$$$=X;#1#$#@##@&#@&&&@$&<,   $$$$$$",
+"$$$$$$$$==##;#;##1$#@&$@$&&@&><   $$$$$$",
+"$$$$$$$$=X;###1#@##@&#@&&@$&&O,   $$$$$$",
+"$$$$$$$$==#1#;##;#.#@&&$@&@&@<>   $$$$$$",
+"$$$$$$$$$==###;#*;#&@#&@&&$&O<   $$$$$$$",
+"$$$$$$$$$==;#1,$;#&#@$@&$@&@<,   $$$$$$$",
+"$$$$$$$$$$=X####.##@&#&&@&&<O   $$$$$$$$",
+"$$$$$$$$$$==;#;##;*#@&@$&&@O<    $$$$$$$",
+"$$$$$$$$==$==1##.#;&@+&&@&O< <,   $$$$$$",
+"$$$$$$$===#:=#;###&+%&@$&O>  ><,  $$$$$$",
+"$$$$$$====@&=O##@#;&@#&&,<   <,><  $$$$$",
+"$$$$$===#$== ==$1#&#&@&O>  ,<$#,,>  $$$$",
+"$$$$===#;#==  ==$#;&@#O,   >,#;&<,< $$$$",
+"$$$==$#;*@O<   ====Oo,>    <,&$#@&O, $$$",
+"$$$==;$#&&<,   $===<,<     <O@&;#&><  $$",
+"$$$==##;&O>,   $$==,>   $$ ,<&&#$@o,  $$",
+"$$$===X=O,<    $$$$$$$$$$$$$>OO,Oo>  $$$",
+"$$$$====,<    $$$$$$$$$$$$$$,<,>,<, $$$$",
+"$$$$$===<>   $$$$$$$$$$$$$$$$><,<>  $$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"
+};
diff --git a/win/Qt/nhicns.uu b/win/Qt/nhicns.uu
new file mode 100644 (file)
index 0000000..feffce7
--- /dev/null
@@ -0,0 +1,1112 @@
+begin 640 nethack.icns
+M:6-N<P``PL9I8W,C````2```````````````````````````````````````
+M``````````````````````````````````````````````!I<S,R```"#Z#&
+M`*B!Q@*[D<"%Q@B]F?'&IGZ1H(&$Q@G(N;^=B&F!H+?)@,8-V\K1QL<AFW1O
+M@)BYR>2`Q@J)8&,C9"%T(S\SO(+&"I1U5GU$0G?,X7MN@<8,PHAF6'^#<[QQ
+MAGV\RH#&#7]O6L;&?(7'HHZA>IGJ@,80BYS#/&F3HGUOQI?&@W3&QH6!Q@E<
+MIW'&QES&QJ*5A,8$X6K&QJF'Q@6/QD3&QNR'Q@!A@<8`@)'&H,8`=H'&`@\5
+M?87&"+:'[L:%;X"46H3&"<@-O(T^9W*9K<6`Q@W:KS'&PS.!&2M[-[+%XH#&
+M"A<311$U*!X1#!^G@L8*"RP0%@L1%@L9"Q:!Q@RO%A0?&A@-#F11'`T*@,8-
+M'2D-QL8<%0HC%1HC$0J`QA!^9KT1$@X-'33&-<8Q#L;&;('&"5(-(<;&)L;&
+MAWB$Q@0*.\;&-8?&!5W&1,;&"8?&`#.!Q@!AD<:@Q@!N@<8"#A5CA<8(M*+>
+MQGM_FJ=5A,8)QPS'H39E@:6\S(#&#=:D+L;#?8X8*G\VO,K@@,8*%A-!$$%#
+M'1`-'J."Q@H+'Q`6"PX5"A,*%8'&#*L6$QD:&`T-1S8:#`J`Q@T8(0W&QAP4
+M"AH3%2$1"H#&$']BO0X1#@T;+L8UQB\-QL9F@<8)/0T?QL8=QL:#=(3&!`HM
+MQL8AA\8%4\9"QL8)A\8`*H'&`$*1QG,X;6L```$(____________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M_____________________TE#3B,```$(````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````&EL,S(```;C@<8`R9S&`*F]Q@#%G<8`O(;&`]+JXKR0Q@*]
+MQ]:"Q@;LCVEW>7?#CL8$SH)_>[2`Q@B!9G^9F:BI<,R,QA&]G)B84,;'QH]Z
+MAI"0G:^RH,N,QA'AF-[-'B!;;V%WD*":K*R^QZN+QA*D=]OYG:7*97)R>Y.D
+MI[+&R=.KA\8`NX#&$N^;P[2ZPF)G<GZ`C:NVOL?7X)N!QAS*<564QDO&RL:>
+MKD@8Q;%A:F-E.9"4N+_'UN+&OX+&%2&^V4XH(I'&_D2*/SI)*RDA*$"2CL*'
+MQA6\BY1U5%AC>$GN+4I624-(7%XV6Z;/A\85K:[.'EMP9XF2;X)^9U9SBYF^
+MGJI+S(?&%[.1R#5A6'R*?"_/=V]/MKG(OYR^Q']KQX3&&,BXFWUB86-NBH2-
+M6JAN<F6+B(9UD[7*IE2$QAG!OH!B98!P:'A]C5*)IIN@A8><GWJ:N\_0;H/&
+M!)-L=AYW@,8387*)?X/3LZ:MDY>4=7R,D;W`?=^!QAMO<GH.QL;5QL9B;GVI
+MQJ6'?:&*:89A;'R>K^]2@<8;QR$0%<;KF4?&6%MRS,2'E7AV:5EH;,;&Q8*U
+MVH+&`I$71(#&#T@_3&5EI-A[?(YF4]'&4L&`Q@*-I9:!Q@*U(:6!Q@Y1S,9M
+M@\!I<65AUL;&;WZ!Q@*>BF&!Q@#)A<8&YV^;:,!'=(#&`7N,@L8"RV'3B\8#
+M=I/&88'&`4VMD\8#PW?&:('&`7>1DL8$P&O&QE>!Q@&BGY+&`,F$Q@*_<FR2
+MQ@"5A,8!S)";Q@'"7YO&`<B_IL:!Q@#(G,8`2[W&`,6=Q@"<AL8#M@D);Y#&
+M`H=VS8+&!A,8.V1G%R*.Q@0+<G$6EX#&""UB=H>'F*$PQ8S&$1)QAXH^QL?&
+M."UW@(>3I:>!<XS&$0I"U,LH'WH46BF`E)*CI;C#+HO&$C`AN_B.F<D?&F\P
+M:)F?JK_#SCJ'Q@"O@,82"9BYEZ^_(6-P=7M)HZNVP]/<$H'&',E?3"#&%\7*
+MQD@?0!BRI1ID3UPIAVRPM\/2X<:4@L85$0D)#!H2=\;];#0A$1`3$A$2/Y!/
+MNX?&%0D0$A@;)"</'MD1$PL7"PL,#A<LF,N'QA4-#I07)R8B*@DH)!0*#`D+
+M"Q<:#1K"A\86"A53%PP*#Q8>#\@,"T@.#@I[,0H)&A^%QA@7"A(<$`T.%A@9
+M'"*'#!A1(3(F%P\*##@?A,89#`D9$!=&-$`>'!L?%Q41$VT:$PH6&@L,%"6#
+MQAL/"AH++\;&O"<A%QH:"0T1+!T6("LI&2@26"?9@<8;,R4="\;&Q<;&$1L3
+M#0D0%3T5("`<,#4<%2L)'X'&&\(0#P[&Z2@NQ@PB&PD)&10I/DA,&`S&QK8:
+M$0F"Q@*.$!F`Q@\Z(@I&4`D)$1P80C[+Q@J)@,8"20D^@<8"KQN$@<8."\7&
+M5!X)$3!-6]/&Q@D*@<8"D`]0@<8`#(7&!N`J"1NU"C6`Q@$)1(+&`KM3T8O&
+M`PD.QAJ!Q@$P5)/&`PD)QC6!Q@$)$9+&!`HKQL9*@<8!"0J2Q@`)A,8"L@D?
+MDL8`,X3&`;T@F\8!PCV;Q@'(O:;&H<8`+[W&`,6=Q@"9AL8#JPD)69#&`G1G
+MSH+&!A$7,VIL%QV.Q@0+>(`6E8#&""1?@**BL*THQ8S&$1!DH:`]QL?&+R.&
+MF8^AN+F#;HS&$0DHU==6);X45R69IYNQK\#)(8O&$BT>K^RDJLD=&7$K<:NK
+MM<;)TB^'Q@"B@,82"9?`E;V]&F%R@']!K[N_R=;=$H'&',5`.AO&%,?)QD48
+M,!ZPHAAA2ETECV.\O\G5W,:,@L85$`D)#1@1=<;VSR4;$0\3$A`2-9!'PH?&
+M%0D0$1@8&R`/%<\/$PL4"PL,#1<IFLR'QA4-#7P='Q\>(@D;'10)#`D+"Q,6
+M#1>^A\86"A5`%@P*#A8<#K<+"S@.#@IB(@H)&1Z%QA@2"A(;#PP.%1@9&1>!
+M"Q@^'"4@%P\*"R,8A,89#`D8#Q8\+34>&Q@7%A$0$DL9$@H6%PL*$2"#QAL/
+M"AD++L;&N2`?%AH9"0T0'QD4&R$A%Q\/1B/9@<8;*R(="\;&Q,;&$!H3#0D/
+M%2\3&QP9(B\<$QX)%X'&&\(1#@[&XB$BQ@P9&PD)&!,C-#PW%PS&QK,9#PF"
+MQ@*0$!:`Q@\V'`H\/0D)$!L7,2O/Q@J!@,8"00DE@<8"L1E_@<8."L7&0!T)
+M$"HY1-/&Q@D*@<8"C`Y+@<8`"X7&!N`A"1.X"R^`Q@$)0H+&`KL_THO&`PD-
+MQAF!Q@$C49/&`PD)QBN!Q@$)$9+&!`HFQL9(@<8!"0J2Q@`)A,8"L@D<DL8`
+M*X3&`;T:F\8!P36;Q@'(O:;&;#AM:P``!`C_________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________:6-H(P```D@`````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````!I:#,R```.@(/&`.*LQ@#^K,8!;\FLQ@#$K<8`RJW&
+M`,BLQ@"\B\8%S\W;UM#+F<8`J(G&"-+MNYAXD8K)P)C&!<O"O\G&_H+&"^#Q
+M@VUF?I!P:7C)XY7&!\FN?7MSA^C9@<8,C(IB>H>8E)"DG8=WS)3&![W/>YF9
+MCO'0@<8.IGJ'?H:.D9Z=H*NL@;#4DL8;R]6LJ)&18'?+QM#&KW9QF'.&AIF:
+MJ+"CN;"7SI'&'-VVZ32?IJ5D)20U/*)O77F1@9"2I)JFKK&^P)/*D,8=R,:I
+MN5WGO_6!G2NRB&-I:6MX@9&AH+"MM\+(R9;+D<8<S.]SO432TJBRQFU@;&5R
+M<GF0FIJJM;?%Q<S7D.",Q@##@<8<I-B!6ER_J,;8<U]H6')R@("AG+*PO+_'
+MSM'8C\2$Q@C;N''*N\;1/YV`QAW'W:LA[MN;QL9T8&MO<G6`AX28KJ^YQ,S)
+MTM_DML^#QB5F/D#/A,;S%R;.QM/"C?)$#@ZVR<]V74UR;RME9F61C[FZO\O/
+MRH#&`+2#QB.[8QBBJ,9F@1.VGEPHQL8F0)0YT1EZ1B]$4S4I*C61FXV_Q-:+
+MQB"EB9WI8((P8QX?(X1U9/,.(1Y`="4O(R0R/S8I,[F9O,R,QA_BFY5RBG56
+M6V9;@UXV<?ZO&IYA>D)/64]C85YD98MBE(W&('B&DTNB;U%985R`J7E>8JM2
+M:%%Y2G)Q>G=QL:-Z@4]BQ(S&(964A+9U-%-64%U]B'U$1-I"<G5W3IO,U<3A
+ML*A[NKEN7,V*QB3+O<!RS;Q;7F!J;'N*@(L]/L5P@G=C=G2$H\#`I*.QH\^8
+M7,G(B,8DT="S@X%I9%E@9VM[E(!^A'$HRFN!>FECDX5C872KK+_+S*]*SX?&
+M)L+)RXB$:V977UA<;'][?(.!;7-9C[Q[FW%MBH;"I'V+K+S/U<IQOX;&)]_4
+MT(-N85M=PKV>;VAXBW^%28B(C\N)FYNRJXYO>I-\G92QN]C8?J2%Q@=9TRMU
+M?6I8HH#&'=)U9GAJ>C&$C(S%I9:=CHRC>;"A:864FJ*[W^&*C83&!G]^W6]X
+M#EJ#QAR'=WQV<(5WTL>AAJ*,LHZ(9:&+9'I[B9F_TNI\A8/&"L5O;GD8$&+&
+MQM6I@,8;)3(:='+PP::+C8QXBGJ*6YYR<9)R<X2(G^#Q1H3&'Y5P&!`.9<;+
+MS:E5S=U;:W5KL\7,K9"'FXV(:V1296I\@,8&N7&`F-/I1(3&'U6+,!"<QL;#
+ME$8\;U1I56.3J,6B?W-];%YO5EW&9&>7@<8%OX.,O73%@\8#<!<11X+&%[=!
+M0$O":&-_ILRDA(*&<%Q8;K;&R$?7M8+&`[=^O!^#Q@-^0!!Q@\8,I%)DQN=E
+M9;*QKV]W=X!@@<8":I:=@\8"R72EA,8"A12HA,8-5LC&QGU<9+&G;G9Q95*"
+MQ@);7)J$Q@2B=HF5R8+&`(:*Q@BR;XB@C,-63U>"Q@*-G[V%Q@*^@823Q@9<
+MP8S&<V3)@L8"SZ_)GL8%IN%]QFIM@\8"E*FKG<8&G\^1D\9FH8/&`EZ]G9W&
+M!M:'A\;&++B"Q@/)<.>)G,8"C]O#@,8!1+J"Q@/!>>R$G,8!R8:!Q@"V@\8#
+MBY?"LIS&`;*5B,8">+G6G<8`88G&`JV?@)W&`-R)Q@*8@,^JQ@'2T>O&@\8`
+MX:S&`/VLQ@%GR*S&`)RMQ@!KK<8`NZS&`*B+Q@7-=U]?:*^9Q@!VB<8(=@D/
+M%3D5-`Q]F,8%KW)^R,;]@L8+OPDL+%YO@&H@1`S<E<8'R0\P3SI`YM2!Q@QR
+M&E-S=X>#@):37RI;E,8'M@Q1AX=\[K"!Q@Z%(Q-O>G^`DI24HZ):'-&2QAO*
+M"Q->@(!;6[7&SL:.%R\*<'IZAY*8I9RNIA/-D<8<VH@)&E>6C8(Z-DA7;AHG
+M'A%R@8>6DIZEJ[:Z++F0QAW(QA8-)N"\\W6-,+4^/BEG/3!RAY69I:6MNL+%
+M7JB1QAS%"2-<;,3$F*?&(3\@8W!P+(>2DJ*KKL#`Q--3W(S&`+V!QAPB"C%=
+M4ZZ8P-$:0&4V<'![*6R4J*>TNL/&R]1ZL(3&"-JS;:^QQC$[FX#&'<,*)3/L
+MSX'`QAD^:"MP<'N#:S>DJ+*]Q\7.W.*0Q(/&)5@P/Y<9Q@D/)LW&T[HK"6P.
+M#JO(RB!(/7!F%T9B6HXCL[2WQ,;*@,8`EX/&&;97%D\/"0P8$J9^41/&(3UF
+M057.#A@S%#4V@10%CIA%N,#3B\8@)!<3"1,6#T4.$!%!*37O#"@:%!X;%!$1
+M$`P4%!^U=J?+C,8?"1`)$306.RLX(S42#BG]*PT*$!<+"0H*)S,,"1A9)VJ-
+MQB`7&`X[0A<;)R@M&Q$))#0I(!\*%PX)"@D,1Q<1,!`9'\&,QB$/"Q5-+!82
+M$!`.%A,B"SBW$1`)%AX)"PD,&3@@"PT-%AO-BL8BJPD,$1,9$0H+"0L:%A,1
+M##"V"0H452<U&1!]?5@/#RP*'1V*QB0+"0H6&R`-#`L*"AH9&AH1*0VO#`P=
+M/5H3&%HS-0T0#`L)%AO'A\8FKPD)%AD6%`L8'RDA&AH;&!@7#3$>#A<29#07
+M40L,'`L.#0H)"AVXAL8G#@D)&!4-$!BQLW@Q/AT7'!@4%A@D"18152@/%AX3
+M#A(2%A01"0D9?(7&!PT)#1H<#`R'@,8=S1M%*"0=#AD>&0D0%`\S*@\L#ALT
+M'AP7%0X)"2!)A,8&'1<**1T+#8/&`D,C'(`5%BT)"A$7(SX0%1@^&AX5(R,B
+M$0T?"AY,@\8*NBX8'`P/,<;&OUN`QAL1#Q$6#`D)#!<5%ST8.#$3#2P2<"LG
+M&Q@1%@D9A,8?5AL8#PL4QLN?02#-W!$4&A0*"0D-%14;'2PS*Q\8)0^`Q@:A
+M*!L5*`H9A,8?2'XI#V;&QKUM-A%5"A)#-PX2"0T;%QT[230T4\8E##6!Q@6V
+M,1,)#L.#Q@-N%1`E@L87MB`4#;H_6AT/"0D4&ADG5$`RL,;'"@F;@L8#CQD*
+M$(/&`WD_#RR#Q@Q^$!K&X%`8$`H*%QPF@%N!Q@()#%"#Q@.^%`VS@\8";!"0
+MA,8`.X#&"3=2+PH-%B0A.#&"Q@())GF$Q@2'%Q)XN8'&`0L=BL8(CQ\+"5B[
+M$0D3@L8"8"*FA<8"M%5UD\8&"0I$QB`4R(+&`LLWOI[&!48*$\8[(X/&`H8U
+MCYW&!GH)#&3&/82#Q@()"UF=Q@8*#&_&QBJV@L8#R`D)*9S&`ET)NH#&`42Z
+M@L8#NPP)%YS&`1H>@<8`M8/&`R`*"J*<Q@$N9(C&`CA=#IW&`#.)Q@*;4V&=
+MQ@#8B<8"DC.[JL8!SL7KQH/&`-RLQ@#VK,8!4\BLQ@":K<8`5ZS&`<>ZK,8`
+MIHO&!<UR7UUHHYG&`&Z)Q@AE"0X4+Q4E"V.8Q@6C8W'(QO:"Q@NZ"2$F6W^9
+M:!PZ"]R5Q@?'#RI3.#78UH'&#$\83WF+H9Z9K*%>(U*4Q@>T"T>BHI'>HH'&
+M#GL>$W^%E9JFGZ>PL549T9+&&\4*$$J:FD53M,;9QH07*0ITA86BF["YJ;VN
+M$\V1QAS7A@D82JZ)S8^!E+%C&2,=$7J6E*J;K+&ROL,ILY#&'<?&$PP=V<?D
+MD*%7PC8Z(V4T)H&2J:6YLKS"R,Q7II'&',4)(4G/K:VPM<8?/!MA<G(BCYN;
+MKKF\QL;+UDS=C,8`C('&'"`*-:1.G+#&TAD\8S%R<G\G=YZVM[W!R<W/V'2K
+MA,8(UJ];I*S&+CF=@,8=PPDG?=VZCL;&&#MF*G)U?X)I-K6QO,30RM#=X)7$
+M@\8E1RLU?QG&"0\FS<;2NBD)SP\/N\C.'D,Y<F<7/%]6D!^]O;[*S,J`Q@"5
+M@\8COE4;.P\)#!<1I')3$L8>F,HML<T.%R\3,284$Q,4D)<XP,;5B\85(!83
+M"1,5#T$-$!`T'$'D#$,>%!T<$X`0!PT4$QZY<J/*C,8?"1`)$"46*2$I'"X1
+M#AOV'@P*#Q<+"0H*'BH+"1=/(F2-QB`3&`XX)Q<9'R$C&1`)&"H=&!T*%PT)
+M"@D+-A,0)1`7',&,Q@4-"Q4['Q:`$!@.%A(;"RRB#@\)%1D)"@D+$RL8"@P,
+M%1G-BL8BG@D,$`\4#PH+"0L:%A,1#"N8"0H402,O&1!C8T$/#1\*%QJ*QB,*
+M"0H5&AP,#`L*"AD6&AH1&PR:#`P=,T03&$,J+PT/#`H)$A>(Q@NK"0D6&143
+M"Q89(1V`&A<8%Q8-*1H-%Q)'+!<V"PP:"PX,"@D*&K>&QB<."0D8%0P/%K2R
+M<24T'1<:&!$6&!X)%1%`'0\6&Q(.$A(4$0\)"1ASA<8'#0D,&AL,#(.`QAW.
+M&CLD'QT.&1H8"1`4#R0A#R(-%BL:&!42#0D)&T&$Q@88%PHA'`L-@\8<0B$<
+M%!44*`D*$1<:-`\3%R\5&A4A'1T1#!<*&T6#Q@JZ)!<<#`XHQL:Z3H#&&P\.
+M$!8+"0D,%A47,A<M(Q,-(1%K(209&!$0"1:$QA]/&AX."Q/&RH8P&\S<#Q0:
+M%`H)"0T5%1<9(BPA%Q<?#X#&!J$D&A0="A:$QA]&?R0.8L;&O6<K#DX)$3`J
+M#A`)#1H7&S$X+B@]QB,,-8'&!;(O$@D-PX/&`VL3#QV"QA>T&A(-NC9$'`X)
+M"1(9&!\^,"JOQL<+"9B"Q@..&0H/@\8#=S4.(H/&#'8/%\;@/1<."@H5'".`
+M18'&`@D,3X/&`\43#;&#Q@)F$)V$Q@`U@,8)-#TF"@T6(A\O)8+&`@D==H3&
+M!(,5$'2R@<8!"QJ*Q@B"'0L)5;D0"1&"Q@)<&J*%Q@*S26N3Q@8)"D+&'1/(
+M@L8"R2&]GL8%-`H3QBT?@\8"@B&*G<8&=@D,8<8O?X/&`@D+6)W&!@H,9\;&
+M*K6"Q@/("0DEG,8"4PG`@,8!0KF"Q@.Z"PD6G,8!%!Z!Q@"U@\8#'`D*H9S&
+M`2!<B,8"+TD,G<8`*HG&`I0]0IW&`,F)Q@*/)K*JQ@'1L>O&:#AM:P``"0C_
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M__________]I=#,R``!9E`````#_QHK&`LSWXOK&`O'^]/K&`_[^^-?YQ@/P
+M\^_=^<8$R-3-N<?YQ@/<:Z7/^L8"Q8_-_,8!N-+[Q@+#J\S[Q@+2LM_ZQ@/4
+ML]C+^L8"OK_+^\8"J[?'^\8!ML_[Q@+3G-/ZQ@/(P;'0I\8%X\K*S,K7R\8"
+MO[#(HL8.W,G0U./CX=?<X-31Q\O.QL8#Q<.\UY_&$\O+Y-[CV-K@V<O)U=73
+MTLW6R<32Q,8#VJ[@QYW&%LG6U^?KY<[#Q[BNHK;"P,F\S\C#W\C(P\8"J\/,
+MG,8:R-7GZ.C8L:R4DX%]=8&-B(Z%J;W#V\O,Q\?(P<8!I\N<QAK-ZO/2R:R$
+M?7EU:VEA:'%E:VA[A)*MK\O,S-?"Q@FLSN/*QLC(O,O2@L8!_MV*Q@W?R/'P
+MUJI^@7!K969I>(!^#8F&<6AM:GMTCZK)RLS6P,81VJG!MI&*@8*(G+S:QL;^
+M_O3$B<8+T]/SY*9^;F5E9VEX@(80C9"0J)NFD8E^<VI_D:K`Q,N_QA'1S::2
+M<VYN:&]RA)*]W^WUUL.)QB&1T,RRA'%?9F9SDX&&AI:-D(J3DZ"DG**:F8=U
+M@9>:R<_CO,82U]/`?IYY?W^#?WAK:W*L\>.JU(G&(GZ5FX9K7V)F?H.+A921
+MF9^<CY"1G*>FHJB<G)")?G"8OM7-N\82T=JV<Y&$E(^1BXA_>6B'].:1XHG&
+M)&N"D8)_=&5H@H*&A)"9D)V8DI21FJ>KG:6=H**@EGZ*FK#%Q]2YQA*[X,!_
+M@82EF9>2E9F2?H/DZ83DB<8F:YRGA9:0;G%^>X2#A)6)DI"1E)29IJB:GZ&>
+MJZ^RG9>"BZR^U<C'M\83HMKLHY-VK9F6F)F8F9"IN-E\P,"(QB>8Z]MRBI"'
+M@(%[?H=_A(Z(D(^)GIFEFIJ=HJ:JK:RMM9*`A9ZISLO)ML84Q:_SS:O$Q9R0
+MD)F0E9")TM%`;97'A\8GF.O)=WV%BH*3=GZ+AI"&D)"-F9B9F9N:J*BMH:NP
+MK:NTNJ%T=Z_-W[;&%=J;O_/-KD)LL9F5D)F0IK<J%W98G\J!Q@'-UH#&&9CK
+MH7EZ>&M]HY1W>'Z&AHF`C)"8D9Z:H*BH@+`+MJNPM<*WMXAUG\#GM,8*V>'5
+M?NGNLVX0:(^`F3N@H:"OW3\>.#+-T\U;1$3-QL:>ZX9U9F-O=827CWJ&BX:&
+MD)"9D)&:DIJ>FJ:PLZNSL*^VMKO#J'2/N,2SQDO<WLJWQ>_2IC)-GYV2F::F
+M?M?10SHO*E%243\O1&9MM8[Q?F]T9FAM?81]C):.@)"0EIZ0DIJAFINDHZ6O
+MJZZUK;:]O[RVKI*1J<'3L<9,T.3&R*;4Z,-X,G&LPJJHN'BBA(:.)B(B(1\G
+M030V2GI\]()K>&]=:'%X<8N8D(&1BY.8EI::H*&BI:*HK*NNLK.RO,&^O\6M
+MEI6GR]>PQDW)XL;'HJ[QU*X[.:+GOKW6<'=LU>!`'B`A&25+,3A$1&ONB&=W
+M=U)D:&YI@8Z.A8V)D)2:GIB>IJJAI+"MK;*MN*^YO\'#R,BQFXNRW<>OQ@#5
+M@,9*SICE[JB2.ENOP?SY1,/^_?JA+3=!+U(88W1/0V#:AV!Q=E9?:6AL=WV%
+MB8B/CYZ:I9*GH*BAI;"RL+6MMK>VO,+'S<K-RHV-M,?'L\9)R;3FZ::K=S^P
+MZ])$\O[UW;F0H**@91ZNQKD\;<6`8&AJ:5UI:W!G<G)XH(J+D)&:D:"@G*&F
+ML*VVL*NTNK3"PL/-Q\W'SJ1[N\NSQCC(E,3SW6Z.C9:\P437_M=LT)&@HJ&A
+M=[#&QN%P=VQ@9F9\96EK<')R9G**FXV&FIF1G*&CH:&PJ["`M@6ZP,O!PL*!
+MS@37PHJBR[/&)-"4XO/`<["3R&9$IO[62^G,H*BHI;:&O,;&;VMQ6F9F<FM;
+M:W"!<@EN?GB>CYRAFYJ?@*L5IK:RMK2ZP,?"Q\?)Q\[.U->\C:6\S:;&`>;1
+MAL8CQ[F_[>VD?Y"5C410]<TXY-*GJ*BML,>UN-!K>75G9FAD:5EP@G(A?'AK
+MA)^0FIN:H:*BJZJNM*ZTNKV\Q\+'RL_&UM37U,Z9D:;&`LS:AX?&#\>7Q_#0
+MA8>!6GE$ZXHXHLN`J`^TOLG"V,UL>G=>9FEF;FE?@G(D?GUQ>HJ*C:*?H*&K
+MLZNOL+2XP+N[Q,+'RL_-U]'7U=?.KI?&QZ/&`\G52[F&QB+(KZ7BYZ^-ASU4
+M99)C.URIFZ>LM\G&QM7!;G9T6&9I:&QP6()R)7Z`>GQ]?XF>GJ"AL;"NL+*V
+MN[ZZO\3"Q\K*S=31U]C7X,V<H;_4D\8$RLO"OL6%Q@;'Q,+1*(C)AL83SYO-
+M\MN=C30=>&!U5T*CDYVQN-&`Q@JQ;7%R5V=I:6AO6X%R`75_@(`B?'J%CY:<
+MH;&KK["UM[NZNL'&PLC)Q\S1U-;:VM_@O8VMU\>0Q@O+R-#/KI^WP\;%Q,F`
+MQ@;)P+2P)1?-A\82N['J\KZ,/1U$QN.OB^R<BZ^TSX#&"YIN;7%::&EJ;F1I
+M;H!R$'U_@(!\AX9Y>X>0H:FLJ["R@+H4N[S"P\[(R<K1U-'8X-[@X<:6KLC'
+MC\8+Z-*OA'%@8*_#O+3A@,8&S=FR&!00HX?&$LB$RNGJL$U$%)WTSI;+EZ:/
+MGL*`QBZ$:GMT6FAI;W!E<E%R<G%R?X"`986'AX5W@*2>L*RPL;JYNL7#PLC.
+MQ=')T='7V(#@!>7EQ9'"T(W&$\_:M8)Q8%E`1H.LI7N"Q\;>U?.R@!``;X+&
+M`>/;@<9%S)[2[^M:1$0>4DH8&"RQMLF<O<;&=W1[=5%H:6]P<G13;')B/WR`
+M4#9^AX>0D8&#F:>VPK>VN;JYP\?(R,?.T<W4U^/KSX'&`L>5I8W&5\N$54`^
+M/C]`6*3`I8F`PL;([?.(%Q`0;,;&Y\S&P%/*QK3&QJ"XX?-L1$0>#G`B$`Y:
+MM]/&TL;+67!S<E1I9T-I<FIQ:7)(*F6`,C9?AW]KD9&.B8^8PKB`N@G!PL'(
+MR,K1S^#6A\8`MXW&9(HE'QT<'!TO<;S#H9..A;G(V<%Y2A`06,;&NF''8S*[
+MQU*=QL2.R>QN1"PX)B2.&Q8U@X[&R,)726UR<&%I8SD^<EM6;G(S-3]@*C8R
+M>D)&D9&0D86.H;BZNL'#P\+(S<K?R,K(A\8`Q(W&3Z)I94L\%!0B<[+&IIR6
+ME;^ULHQD;2$0.L3&H3FT22JJNC=SQL>BL=EV1#(R-1]<61\N9VG4S7<P1G!W
+M<T]H3S8Q;$A$86(L-C%"*38K6S<^@)$.EI"1D*:XNLC$PL+*UL?3F\9?Q;VW
+MD7M$*19PH[BJK:>GQ*>*54V&.A`<ILAX'H,U)GZG*4;&QKZ>S)1$/"\Z)AU[
+M)RM&2\;++B-&='IR.6([-2E6,S9.42DV)BHL,RPX-3B1D8F)FY:)DJNXR\7"
+MQM38HL9.W8`:;9^-I<O)FK^M=D%"?UL4&DG)-1LJ)"8FB2DGNL7'G<[21SM5
+M02D8*"HH*CINISA)2G1T:#!0-#4H*BDV/5,J-2$I,RDT*34KD8]G48";!Y6.
+MKL'"QL_BI<9,9Z.#B:76RZ?(FU)95W!W,2@0H2$?%Q\E&30I(66\S*%\GEM"
+MS=8['A$\+3PE*EY$4&)T<FTP*2DU*"DH-BE9-"DA*C,H-"HV*9&`*D*`FP:A
+MIY.\QM/*I<8@L;JAB[O/BXS>[H5E7VB+:E(L*&`Q*"8@)R$F*!X:<7%I@'$Q
+M9?3^L!`.#A@>'A@7*CY==G-L*B@H-2,A(S8D,50Q,41&2#8J*BEE.C8YPM3+
+MJL;&R[:GQE7,U*N;T[MS>^G9?&E.87U::TYT9T193U-B7&Q:43UG/2@Q:7%Q
+MC?[)*C(A'%DI,1T8-%U[=F4K)S$\.CT]1CU,7DQ38&5J6CPI*#@[:4[2MEF(
+MQL;GV*?&5=3@LZW#N)*FIH"49GM.=6Q<7%59<GA6:&)C:&2#E&M;53%%8G%E
+M]]R<G#4_+G"1AHQ887UU8SP\3DI32E95559785AA9G!@5V=<3EE;19AB7V_&
+MJX;%I\95HL3*N(N2EJJ%5*)GG$QY8EIB7%Q-75)98GMFCH:D?8IO3C96;I37
+MVK2L=E0X66E49%EB<W==1U%/5FQ5:5AG9F-O;&!D;(Z@EH-I8&I0<E)J4[ML
+M=+:GQE>GD=NO?Y66@FM-O6RE27=@6F)96%1:65IF;'&*A)F6FX!E0T=MBYK:
+MJZZ384QB8$](6&9V=EI$5U=F<&%Q87-D:W%O<GR,J+FNEG=ED(!S7&!*BU=M
+MN,;0I<98MH#DKHV>EF5>9=!\GD5I:%I<6U=F869?9E=Y=8:$HIV/>E\_:7%=
+MV)>GEVE6>VMG25IG?75:1E9==&]N=76#;'U^<HZ@K+:_LJ&"<ZFNBG%@3%E=
+M8K7)P\6DQEBCP]W&IHR4B6VMP*"(0T5Z74QO8EEE=5]=7G-KAFN0FIN2@DI8
+M;#W5AI2#942'<'=G8E]V=5Q84U1Y=X2"G*6<KZ>)LKVIP,BAH)B/E[BTDX]?
+M2&=.E\1XOZ3&6,"KP[.<DXF(CK_`K7@V-F=X65I:66A86&UR>6MV?(J3GH^&
+M9#E(*^;&NU)$*'9B55UN971R9E)=57J1Q\W/V<O/L,W)R<:^L;&?G(23Q[JV
+MJY%@74YK66>BI,9:MGNYI:B>AW.6M,"X9C0J7V563%%14TA13%!EB(5\=81W
+M;(B+)QI5M.STP&E(EHM6:F]]?7)64%"-R-#4T]3*S\G4V.+EKZF"CJV<C86[
+MN\+"PZZ77TU37('=O*'&6\NTPK:WGHN`;JN^Q[!A/4A495AC4UA=3F)K<8.$
+M@XN%FX]J@UA+,1PEIMK2LY.+A6-R;GU^?41@@GVWP[S`R\?+U,O5TLZ\P(6%
+MHZZ=D[>NO\F]Q\2N@6U06%AKH,9@R+*APK"SGHUW;JG+S,J&:%A87F!H7F-H
+M9V5E>&AV?(V.AY5[B7]R3CTO,EG'RXF*=&-Z=G-\;%%D9&&%A7U^AXR0GZBY
+MSL&\OX*"HZZIC*"OM\&YPLO$NZAG65YMT,;&RYW&7\3*VL6VG))S8YJWPZ)S
+M9%I=8F-E7&1E865N<WIT@HF(?HB"D9N):&94*AQ19[:-C')N<X!_96QR96!T
+M;6AJ>GU^@82)?XR)F8*"IJ2HG8NPL+?%R<'*QL&9CG19JJR!JIO&8\G&T-C=
+MQK:>E7AFCZ.FC6QD7%YA8F%<9&-A9&]P?W6"@X=_AH*-F(U\=VU$)BH^GHFD
+M>G%QA8)C=G9H8V]G8V5]@']_?75D<G.">'N;H*B?B:^NL<7*P,O'R+"HA5J-
+MCF^=QL>9QF/0R=W5SK"QIYB'?'Y_6W1N;F-@6%Y87V5C:&-I;GIZ?7>)B(E_
+M?WV%FX:4BVDO*2MWTXR%;8:)8G9Y=&YI8V!DA9*0D8=L9&%H9V%G=YFAE96K
+ML*R[QLC'R]#)PJ1X9D]YE;_)FL9BS^+;PIREI(.*?7Y[8FMI6F-;6&-:76I@
+M9&1J9'-X@(&%B(*&C(B1=I^@BF]E+SU0W<*%:XM[76=V?7]L8V!@8YJCIYN$
+M@GIXBGAJ;7!_I9.>M+"LNL:^R<K,T;Z?EV]?=XVWF,9DR+ZY[]G4H8MSA(5O
+M>&5E8G166%)B95I9969F;G%U>GN!?7>!?':0C8>1A'V#<'A)6&53U82'I9N-
+MA'60HHER8&!C;'V)FY6"E:[$H)BBBW5UBXN?H[BPM<"^VM//U];)N65EBI.8
+MQA;#OL/2PL*LDW!PA'YS<VMC<6186EE58(%3)V-F:71^?'6!@8J!C7UZ>7R6
+MEF1X>82:1+B7BKOGTK9\H9RJGH)_@F2`>A:&BIRZN+"GIIZ1?G6+CY.;K;^N
+MMLO!Q(#4!\*DB)QCQLB\E,9IO<O)P=#BTJ6.=76!?&MN7UM=7EA?9W1J<6UD
+M75]F9FMM;G-ZA'V$BGZ"=(F)F56(B(.7=F^?D,?;V[E^OYJLFH*"F8Z@F8-\
+M>HB?H)VHI:2?A8)W?IV7DJVBO+F^R-'2T-+-PZUF?J1TRY+&:LO-W]',TMS1
+MIY!S;G!U7V-[85U96HBDO:^SL;6=;&5N:69K;79^?(R*?81]A8V+2WF"BH^)
+M:W^9R,S<NH2OI:2QBI6)G*JNI9R+@H!V=WB`AY:$A7M\BI:0EI"EN["OP,76
+MV=#6RY1ZF''`DL87R,W,U,G)E8"7BG!><'5A9WAB6UQ:L[[,@,91RKRIBW-G
+M:'!I<G-ZAHE\?X&%B8M`=(J-EXIO;Z7(Q]3*D*&HG*Z4H8F7L["IHI:5@WI[
+MB(R,D'=^?7V(CHN0C9BMIZ:VMLG4T=K3LIN4<KO!R9#&%<&RE\##L5,O?H%L
+M67EW9VYH8%AC:L^$QD_<M(]W:G9H;&MX?()_=H&"AX8V>Y*,FHEP::[-R<C3
+MH)NCE:&=HY.2KZJ;HYNLDHB.IJ>CE7AY=WN'A8>1CI.:G*&MJ[K)TMK2R,6=
+M?*FONY#&%+AQ1WJ]BU\O:WAH<7QT:%]=6%EGHH?&4-BM<GMI:')U>'2&=(%Z
+MBV4\CHN$A(UM;;#6T;V\KYJ8EINEG)R=BJ2*KYNTH7V7FJR[K*"%:75R?HJ/
+MB)23C)2?GKJUQ]?,V^+`HWB,B<'&QXW&$[AI1RB=BXMD='1M<7QW9RQ16&5D
+MBL9.RXM9;'IR<GEF?71_=T)/?H>$?WEW>+;"UK.GP:B.J::PFYR>BIR*DK"5
+MH8&7DY:[JIR3<6=Q=81U=(&-AJR2BKNKG,?&T^2_QI&<;J+&RHW&$[Q9A'R$
+MA9[IDFEY='AT.`X]679MB\9-SJ1R975Y9G)X>W=_(FV;?HB1=&^NR+[+L)^M
+MM(V'G9.G=XV*D\"-HWV<CIMQ9J60BH:*<F5O>'=ZB'Q]B(J4HIR-QYS,T]'D
+MY+INE,:*C<83S'&FTX%BH\]W:W)Z>EX2#D16>'2-QDS(CV5R=GIU>'U</WYT
+M?X2!A+O+R\^YL*B6J[E_E8N*>(&OBIN0HHA]BW9J88J1I8Z7@')C>7E]<WB#
+MAGJ"CHR*KKRRS<OST-.V@DABRXS&$\?&I9-Q?7=\<W9T>F$8#P]$5F6$A,8!
+MR=B%QDN_1EUU<W5U:BAJ<H*"E83EX<O!VJZLMY.<D'F3JHB@>8Z1C:>+BW*/
+M;'1G<HNUJ'MW=6AH;WAH=(!U>G^0?HV@I+"SRNS(R-ZS5U2-C<82R;)J;(R!
+M;71Z<FLD#@\/3%5DGH+&!-/!M*/(A,9+N$8J.4%3@"LW<W1^?(FI\^;CP+ZM
+MI:^.C(.)B*:$DWA\DH6=>'QVB7)I7EY_EJYS>8!MA)6!=7%P:7E]@H&`BI"E
+MH;+=S>CPXI1'=H[&"KY^;H:!='AX4CH1@`\#155<OX'&"-73TL:IJ)N>Q('&
+M3IQ0/"LI/E8[6W=U>W:1N^3=Z\"OJ9^LHH.`DX.>B(.">HJ`BW]R=WEN8&!9
+M<HBD;W.`=HFUI:"=F8V$>'-[?("%DIJBQ<GOY.+)@'_'BLR,Q@>B>'U]>W-L
+M+X(/`T!76=:`QES)Y,W@WKV';G*VRL;&R'Y97S8I.2]B>'QT=W6>PM+4Z<*M
+MI9ZJLX-_EX*6CGB,?(%^>XAK=VIG66189X*7;&U\?7_'QL;'R+:8?75\?'J`
+M@96;K<'EU=OMPI"Z2\Z-Q@ZL?7IN.R$1$!`/#PY29(^!QD+9W=+%U:6(6%)@
+MX<;&TU%?6F%B7F5U=7=J7XJ>R,+,V<ZZJK"3BI)WD(B(FWB$>7B*<69Q=V9F
+M5%)36&F`:G!Q=UC)A,82R:YW;GU\@9B;J;K2\_/DI%`VK(W&"-,L%Q`5*A(8
+M$(`/`EE>RX#&@.M`UYR'D(%-5TAKRL:^4EI&6%U71%YE97"/P(O`N-C)Q,><
+MJXB"F7U]G'Q]<7N*8V%G6UA@55-D5%M>86%F>(1Q7KN'Q@_9EWUX?X2-HJ["
+MX^K41S9NCL8,QS517D!&0"D.#A-J9H7&,+1T>F4_4%$]0IV74T]84UAF1%%E
+M869]AX2MHN"XOKZIDX-^A(%U?GM\>&EX9EM77UR`4PQA7&"UY8M29VEG7H/2
+MB,8/UK>!<GIUBY^QT=RU.&7&SHW&"Y-D9$!'+S<.#A1A?X7&0<2\O:M-0$\^
+M.#I*0DA23UZ"<5AF8&!WAX>MH<6QQ[BYC)1[?XMY@8Y[B'%K:&!?5%=39%QG
+M8J;$RL.36FIB8WJ?O8?&#\C$OL"!=XV)AY7*SW5SSVF-Q@NO;TTB31T?#P\F
+M8I:(QB'"IF)"/STU-SE$2E-ALK1B9F!@@(^1G9^\N=ZYKYE^@'R`@'P:>XU]
+M:6I78UE866-L9X+`QL;(O'Q33F2/OJK<B<8-Q\>H@7^'B:C$M:]4.MB,Q@NW
+M;%443Q<3#P\_9K6)QC'%FG5#/CP]/T)*6XO$QVMK8&)[@8*/I:ZUW+.IGFY]
+M?'R!>GF#AGIG9UE=75Q=:'6$JH+&!Y%*2%ZMV["[BL8,T;ZDA8.$D:['N"(I
+MU8S&"[]C;!!)'1`0%5AWS8O&+K-,041)24)-<KC&QGAS86-N<G"!JY^OS;2I
+MGFES@'N&>GJ)>F]B8F!98&!B>X>K@\8(G$Q+5L/GOY/'B\8,R9N#?X"8O:TN
+M'\;&NXK&"LU>C!8S+Q`0+&RFC,8(S&Q.45)11%.G@,8AG7EH8&5M:W*MDZV\
+MSJR==V:#>H)\<H1O9%Q?8&-@9G.=M(3&"*):6U:WT<R.QXS&"\F?@G:*FJ9R
+M);/$BHK&"M9PLD`Q0!`15W+EC<8'X8!24DY(9LF`QA'CBWEE8U9R<;B0K;;"
+MNI5T98.`>0-R>65B@F`"<KS*A<8(O5UJ<HV>H8O$CL8*OGUZ?9"K9Z^Y$+R*
+MQ@C"OEM1+!,9=WF/Q@6^4E`^6]*"QA?<?'=@9&1T>'RSL[[!BVUH?7ML:6MR
+M>&6!8`&$P(?&"--89W)6A7)RR(_&";1V=7J+HX1N$*Z+Q@?`A%X^'3-]J)#&
+M`]);4J6#QAS*I7%C85-B87*EK[>QBV9E>'-S>7AQ:6EE8%-*UXG&!H]E>U=:
+M8'61Q@O.:W9T?8MU6(F7>\N(Q@?%H(B#06.5PI#&`\BYN,*#QAS'PK9E7V-C
+M:W:7J[FLGFY=>'AY<&QB9E%*/TUYR(G&!M1?A)EN9Y*1Q@O'O8-X='UO;V=L
+M?,>)Q@6PS\B/>LJ=QAG(IF]E:&AVG*2RJ*1U8Z*KJ+!F55)(2DA1LXK&!LQN
+MD92@@YZ2Q@G'MY1M=69J8&2UBL8%R>;GE)/3G<89R,&>@7%L<(>3HJ6B>F:[
+MP<#'8E),2T]/5<>+Q@5XB)2SB+"3Q@C(LIQ];F5RB<B*Q@78X-V-K<F?Q@O'
+MIXR)>FV`CZ.A?W&`Q@C%7U%/4%)3=\B+Q@6"<9F\AL"5Q@7,EXQ\E+6,Q@+-
+MF+*CQA3,RZQB>'REJX2*Q,;&N%]-6%)25M*,Q@614YW+ALJJQ@'8TJ;&$=:-
+M:G*SU*A_P<;&LV1R;E]EMHW&!9I3E<V;RM;&$.%QB]#SK92_QL:O;FIK:FK(
+MC<8%D&"XS9V]UL80RJ&GW]RVD+O&QJ]V:6=L<M6-Q@5W99_!IYO6QA"^K['3
+MTJ-ZO,;&K'1E96>1RHW&!6ENBKVLDM7&$+JXO:^\I8MUO\;&JFYB9VK"C<8'
+MOV5[G\&KC,?2QA+$LJ^_RZ.C=W)ZPL;&J6)B57/?C,8'R:-EB[G"K(?3Q@FX
+M>KOCRH:"9V>)@,8$JD]A&GV-Q@C/96N>MK:SB,'2Q@B+H>;OK6%A4J"!Q@2Q
+M42LL;XW&"+%D?IZVSZ2(P='&")V0TO&O>E-NMX+&!,.`('*,C<8(F&2$M^K/
+MM(:_T<8'8:GSQ69EI\Z$Q@.M++J,C<8(E&J#M_/9P9>ZT,8(T&JOY(A5N,+'
+MA,8#VC+%E8W&"'9ED,[NX:Z2O,_&!]_!;[2_:;+%AL8#S5/&Q(S&";Z*6WZD
+MV;F6BL#/Q@;4P9##F(/,B,8"@,;-C,8)HZE;;H2[FWN$Q,_&!<+!MM!_K8G&
+M`*Z-Q@G'BK1N>8*VF72/T,8%PKC(TXG-B<8`S(W&",F#D:*WM/"_G-'&!9R^
+MI=I]TIK&",EYB;BSO-N\OM'&!,"GI**/F\8(S'B%KJ6EXZZXT<8$MHVAC<F;
+MQ@C'BX.3HI"\HL#1Q@2T@L:XR9S&!ZUZCY-]CX++T<8#OJ+2T)W&!ZEH@X"$
+M@:+*T<8#P<C2V9W&!IY=?&^;D\K2Q@.TU-+:G<8%HVB*:;O,T\8"U];2GL8%
+MAYR-A+?@U,8!S]&>Q@61JM+?D<G4Q@#'G\8%U[O2S*?)U,8`UY_&!<B_V=&N
+MS-3&`,N@Q@2YWLG4P/C&!+['QM3#^<8#H,;&R?G&`'S\Q@#1I,;_QHK&`LSV
+MX?K&`O']\_K&`_W]\]/YQ@/O[^7*^L8"Q[N`^L8#V5=$Q/K&`L1=>OS&`8/$
+M^\8"NE2G^L8#Q;EOV?K&`].)GLKZQ@*Y;;K[Q@*F@L#[Q@&.E_O&`M-OF/K&
+M`\B[<\2GQ@7<M[>DM\O+Q@*K9+VBQ@[6H4]*/S0U.C0Z.$IVG\3&Q@/#DI+3
+MG\83Q:AU3ADA"0D+%1H*"14S4VB,I,W$Q@/9<[_'G<86P99J#0D*(`X,#Q4P
+M$`T,#!P*0&6AI;[#Q@*79<.<QAJ]G`T-"0D/&1H6&"$['1@5$S00#PT*-Y2R
+MPLC!Q@&BE9S&&GH*"24-#QDB)AH4,#,G+!44.!T9$Q$5"B:GT\+&"7*=W*1B
+M7%R)M<V"Q@']VHK&'ME<"0D*'"49%S9&5&=P;W5U?'IK1C4>&RT;$`PSI]/`
+MQA'96!8.%1@;&1DA;\/&QOW]\L.)Q@NH*`D*$!\?,%IC9V^`>A!^@("8BI6'
+MA&]6)!L5$`Q%M;_&$8D5.1D:%C`4%1PC+WK6[//*O8G&(7N*%0\8'$U<86Z#
+M='I[AGZ`?8J"E962DHR&:2D:%"LAA-R\QA+5.PPD-T=A:&EA4SLB,&OPX)#.
+MB<8B:W<R'Q0A7F)T>'UXA(&'CX^$@8&,EY>5G9.2>6=*,A8H/["[QA+('@T>
+M5U>'@(5]=&95.T3RXG;?B<8D4FU5)A(81&%T=7IW@8B!C8J'@X"(EIV3FI:8
+MFI*'8#$5#UN+T;G&$J@5#1Y;59"'AH&$AX1E5]OE;MJ)QB9&C(DI$@\B3F]P
+M>79WAGR"@(>$A8B6GI*4FI:CI*Z1830A$$&OO,>WQ@B%"@D/($J*A(:!AP:`
+MFYW.:)FXB,8G9NK1*!@6%!EC;'1[<7E_>X"%>Y"*EY*2E)J>HJ2CI*J"4B45
+M*X_`R;;&%+80"0D-4JYO@("'@(2`?,3%/Q=.Q(?&)V;JEQP<&2D=#4]O?7J!
+M>H"'?H>'D9&2DIB8I)JCI:2CJ[1]-$$2B-FVQA7520T)"A<V*G2'A("'@)>J
+M*!!<+D^W@<8!R]6`QAEFZEH<%AXZ*P\,3G-U>GI\>WZ`AXZ3DI28F("E"ZNC
+MI:JUKK%T'A$XX+3&"M;@R2,)"0H-#S==@(<[E)F4J=ID*%-%R]++>FQLR\;&
+M5.I0'"L/*B,9$ALW>GUZ>H"!AX>)DH^2E)*8I:BCJ*6HJZNTN*`N%@V)L\9+
+MV]S'C`T)"0P,-$I-@8>7EWG3SVI;24%B9&)<2VR#@JU+\$\7)Q(T(1P9.1HY
+M<G:!@(60AXV2E9*3EIJ=I:.DJJBKLK6UKYE5%C"/T+'&3,WBQKLG"PD,"R0Z
+M5+F>F*YPI9*9GC(S,S$K-$I05F6(//(]%"$8.D$J($$8&T1Q@GV'CHB0DI65
+MF9F;H*.CI:FMJ;.XM;F_EUDO7IK3L,9-PN'&QF`3"0L+$2E>U;2QT6]\@M7;
+M/2@M*APD1SU)8&PJ["X6&QTT7T,S.AX5&EAX?8>+BI21E)>@FIVEI:2HJ*^H
+MLKJWO\3$I6I+4*["K\8`TX#&2L0T"@D-"A8J<J7[^&S`_?SYES-*2S5.&F%S
+M;6H6U2\C'2`=56=@.B(:&QI6?8>2BY>.EY2?FIVEIZ:KIZNLKK:^PL7(R\-Y
+M*1FDQ+/&,+`-"0H/"AHC9^K1;/#]\]J@@)25E&`HI<:U61.V'RA")B(N9VAJ
+M3Q\M,@TT@8>)DHF`E!6:GJ6DJZ>CJ[2OMKVYQ,/+P\6(&QNUM,8P.0P)"1L.
+M0%%OOFS=_<MFPH"4E9J96X+&QN`=6R8H8B@;'V=H:G!P5"49$#5ZD)&.DX&:
+M`J6CI8"K!;2[PK>]O8'%!-2U+Q&?L\8DQ"()"0PK#CI<=FRP_<I'X[Z4F)B=
+MJU^)QL8:,R4D8EL9)59H:H%P"2P:,0V`DY63DIB`HQ6>JZFKJ[2UPKW"PL3#
+MQL70U+))$V_,IL8!Y="'QB.2"@D)*U$70U%L=?._,>',EYB8I*:_EI7$$AH:
+M*&)G-C0B:6^!<")L4SP9(5F1DY*:FYNCHJBMJ*NTM+>^OL+%RL#2T-30PU@N
+MD*7&`LS6A8?&#[T>#`D2/4X<5D)LY'\MC;Z`F`^IM\BZQ[D7&QPF8F=8(AM3
+M@G`D=7-A.1DQ6(V8F9JBJ:.FJ*NQM;2UO;[#Q<;%U,K4T=2]D$!EQ:/&`[_0
+M2;>'QB%U%PD)'EU(12YEG%PU3)9ZDIZNQ,;&T+`9'QTH8F=D-AU$@G`<=7MT
+M7ST^,%26F9JFIZ6EJ:NTM;2XP+[#Q<3(S\R`U`7<R&(TD]&3Q@3*RL"]Q87&
+M!L2;C,DGA,F&QA/$/0H)"4=^/"10;'-8/I-E@Z&ORX#&"I\:)2(H8V=G5B(Y
+M@7`!<7:`>R)H828<>(^:IZ.FI:NNLK2TN<*^Q,3#R<O0T=?6V]RM2E.PQ9#&
+M"\O&T,BCF;7#OK_"R8#&!K<7%J,D%LR'QA*4#PD)%6Q<(A^BX;"%Z(!KD*3)
+M@,8$?!PO)R&`9P-I,2MJ@'`G=7I[>W2#@5$J,6*2H:.DI:FTK[2UM[Z_Q</$
+MQ<O/S-3<VMS?PC0MLI#&"^;$IFYD6UNMAXFDX(#&!H`)$A@/#Z"'QA*^&0P*
+M"0YJ;!I^\LIZNXJ777:]@,8N;A$6&"1G9VEL6AE"<'!M<'I[>T:`@X-^6R=8
+MEJ6FI:JTL;2\NK[$QL#+Q,O+U-.`W`7DY+Q44\2-QA//U:1M9%M./T064T0K
+M4L3&U!$)#8`/`&^"Q@'<TH'&.J<7"@D)66QL*"\_&A@FIJN\;Z_&QDX8&Q8C
+M9V=I;'!./FEP32-Y>TX4>8.#AXYD%BZ9J[6SJ[&TL;G"@,,'Q<O+T-3@ZL^!
+MQ@+$3B"-QE>_;DP_,#`X/RM8>408&Y;&7`D)"A`/#VG&QN"_QH9&RL:7QL9A
+M#0D)56QL*`XI&A`.;:K0QLW&R!L<(1\Q9V4I9G!@+$AP-1=<>QX46(-W7XZ.
+M?UP;?+6P@+0)N+B\P\/%R\;<U8?&`)N-QF1S(A\5%!L;*1QY@B`4%R:?$PD*
+M"A$/#U;&QJ%5QSHAN[\HFL:M%PL)4VP_4SL6/B(/1#1YQL>^4PPD)1XX9UL9
+M,'!5%#5P&A0G6Q44*W8E*HZ.C(ID,GBPM+2UNKF]P\7%W<;)R(?&`,"-QD^4
+M9F-&-!04'Q]J6Q(0%!-1#`L*"A4/#S?"QG`KKB<6I[`6:<:^41();&Q-3%0G
+M-#0H0C)(T\QQ*`H<'QHM9DH5'F4^$C--%108-Q84'$L7'X".#I*#66Z`L+2]
+MOKN]Q-#%TYO&7\&XLHYT1"<5($4I"@X0$`D/#@L*&1`/&)['/0]V'1%TEQ0U
+MQL:8)CR9;%]+73LC/3]$02F^QB(0"A88%AQ?,10422,4+"05%!(7%Q04'A0<
+MCHZ%?IB/>5J*K\/!O<#.UZ+&/-QW%0T0#0D*"0\*#P\-#1H2#P\[PQ@.&A01
+M%6L4&+F_PE&_Q&E<>%4[&B9#0$,V4I85%PL7%A0/1Q04$Q>`%`,2%A01@Q0$
+M&8Z+7SN`F`=Y-9JSOKS)X:7&-3@,%A,,"@D-"A`1%Q,7$PX1#XT1$!`1$@X7
+M%!%:B:=9(SM69\O*/2@46499.A<Z&181'R47#X`4"Q,4$Q03&QL4$1<3$H$4
+M`XYV%R6`F`::HEYOP,[*I<8@FPH.%@T)%0L*"0H4(!$6$0D.#3\.#0T0#A$2
+M$A$-*2DG@"DB,?+]H0L+#A@H*!@4%P\*&B$1)1@2%!(1$A01#AL.#AD*$A.`
+M%`M:(!0;O="UD<;&M6JGQCAO"0L0"1`-"0D*&1,:$A,-%!H6'ADC&R,?&Q@2
+M%PP.#`T.)RDI0/W#$!<1#Q<4#A48#0H4'`\D$@Z!#!@*#`H0"B,E#0D1#!$2
+M&1D@&L2G&UW&QN#0I\95.@D*#Q$."@P)$!8:8R@6$1(M)R<J*CDY/QU%%$49
+M$"(0#A0F*2GNTBHG&!H.#`D5(@X0%QH.#PT)"@D*"@D*"0PG'#$7#`T0$0LH
+M$QP9:CH?0L:70\&GQCU#"@H+$@L)"Q84.").-1L.$BLB,R\N)3`Q+4D3+CD3
+M'!@*#2$H/,W4/BL>'PP+"2\Z"Q$:'@\0"@H)"0L)"X`)%!<3*",,"@P1%BDC
+M&!<O(1TDL4$CL*?&5V`-"0L2"PL,&2>**40V&A`2)"DO*BPG+B@R.!PA0A(3
+M%`D+%B@V?-<W*R@D#1$5-#D*#QD=#@\+"@D)#`D,"0L)#Q0;-1(0#0\5&RL3
+M%1@:'1ME(B"NQLREQC1Z'@H,$0L.$QA.NS)`-147$Q\M)B$G+2XB+"4I&S\5
+M#@\*"@LF*2[6*"@M)Q`8(2TH"@P6&H`-(`L)"0L)"PD+"0L5$TXD%`X1$@\F
+M$1,.%QP9'AT>I<>HPZ3&.'X^"@P/#!,E%HA]/S0U$B$9(1XD&B4>'1P;(B\3
+M.2`/%`\)"B(F&=,N)QXE$1`C(!`)#1,8#0T,#(()&@L)"@D3%VE$#0\C&AP3
+M%PL*&Q`7&AL:?+(GLZ3&/(P-"0H)$1@?%GQ]/3(V%!4@&!(4%Q03$1H4&!04
+M&1T-$1L*"182%>&2<A$4#0T1&@H*%!8?$!$-#`D*"0N`"1@*#@H,/D48*2D6
+M,1L-"@H-#1XE&AHY&Q^'I,8`4H`)-`X-$1@60'U20B@7&!@0"@L,#`H,"@P.
+M%A4,&!$;*@T+#`U1E^;R?0\2#0L7"0D0$Q$R,",5@@D""@D+@0D5*UAM5BHQ
+M%PH)$`D)"QD/(!@:&UW<B:'&/;4+"0H*#Q$3$ADAPWDS&!(9&`H-#`D+"@T)
+M#!(9&!$6$`\D#PD+#@T6C-7$9`T-"@T)"1`3$#14;4@,#1D.@`J`"1<*.&]]
+M;6U3&10-"AD,#`L)"1DL&!HD)"6@QA6X+`D)#0H2%1$4&!4I+A`6$!(,"A`+
+M@@E%#`\7&A46&!(5$!`-$`X0'TNXM1<*"0T)"Q$5#3-174P<'S(P'1<7$P\-
+M$G5O?&UM4QD1$`P0#PP;"0L+#Q(A'"`?Q,;&Q9S&8'`-"0D*#`\4#A07$0T>
+M$181#0D)"PL,"0H,"PP4%AD6%QD6%Q41$!82#PX7/UV/-PD*"0D,$@T@+D]4
+M*3=1120<'!L9'D!M5DYM;4,;$1`.#@P+#PD3"@H,-S0:'Y"83)*<Q@!&@`D[
+M"@P/$P\4&!,,'146$0L)"@H+#`D+#0L,%!@8%Q@8%QD6$A08%!`,$A4QCD8X
+M"PD*"A`-&R%"33!%6DXJ@!L-'"Y28TP[9F(Z&!`0#@^`"PP)$@L)"C(R&B)G
+M;2*`F\9`M!`*"0D+"@X0%Q@<&Q`C&A4-#`D+#`P)"PP-"@T6'1D:&1<8&A@6
+M&!L3$PTF#@T30\<>"@L*#0T;'2,Q/%I;6#F`%!\83UU31#!,03`.#A`.$`T-
+M"PD*#`H*#`P?+A\9('FWNYG&`44*@@E<$!88'!H;$1@1#0T+"0T/"PP0#@X1
+M$18='!L:&1L;&!85'!(5%B@4#@PNVGT*#PL)"A(:'!PQ6EM;6A0/#A!?;4XR
+M(#,X)Q<7#!$-#0X+"@H)"PP*"A='&18@3TESF,8`NH()5!,6$1D9%QP1%!06
+M"@D1$102%1@@&1P?'!86&AP<&QL<&!48%1D3&!8R$`P9,K81%@P/%1$7%!`:
+M/%M;6C,<%Q`T;4`9#A<:#Q$<&!$+$`\-#@L,"0J!"04,#10@*TJ8QD)I"0H*
+M"0D,$Q47&1H4&10-#!(,#A<=)2<R.3Q#/R4D&AL:&QL9&QL<&R87%1@;,AD1
+M%AF@&2@0"0H*%@T0#AQM:&U,@!T"&2L:@`H;#`D)$!H9"PX1$!$,&0X*#`D)
+M"@D>6"<C*L9RB93&`Y`7"0J`"6(.%189&Q@1%PL+$1$,)C@T,2XM(R@T0THX
+M,"T@'1D=&1D:&B$7%Q,A+"`6$QPR&R,-"0H*%PL0#Q=M;&]7#A09'1\9$1`0
+M"PD)"QL7$Q$.%Q</&PL0#PD*"@D0+A,1'$<R,<F2Q@+)*@N""0`/@!4,%A,.
+M#@H3#1$/9H^EH8"@3G<K,34\03@O'B$:&!@;&1T8%Q@7,AP5%A<N+AT*"0H*
+M%PT1$!%+86U)#0\1%!<7'!PD&Q$1#!D6%!`4&!83'@X.$0L4#0D*$0LA)QXF
+M(K>2Q@+`"@J!"1`+$A<4$!@7#@P/%`P4$Z.XR(#&1<>L@UTJ-CTO-28P'AH8
+M'!\;&1@8$C4:%A<7-CD:"@D*"A00#Q(0*#U@21,/%1(3%!L?*!\5$1$>&A,/
+M%QH8%!X2$1</%Q.!"0<H1!@>)J:HO)#&%;0+"@D+"0D.&!P3#!P;#0P2#PP6
+M,<N$QD_6G5)!+"(V,SDE'A4>(AH9&Q81+1@8%AD_.A<+"0D+$1,/$Q$/&$M'
+M(!,?%!,/%B(I'!(0$R$A'1`6'AX6'A83'1(7'`H/"PDB1A46)'MQEI#&%*P1
+M#`H+"PD-("@1#!L9"PP,"@X8AX?&&-!]*"4P/BHI)A<I'18=%Q41%A@9&1U%
+M,Q*`"30+#Q43$Q(/%#$Q-"`K%!0.&B@P'A`0$QPF-AD0)R0:)Q05'A<:*@L<
+M%PD9"@HC%!LJ0K[&QXW&$ZP1#`T."PL)'C48#!D<%`X,#!@@BL9.M5D;(QTE
+M)21"&Q0;%!@3&A@9&RQ;,@\)"@H/"1`8$A$.'S$V-"HK%0X3%1XE'!H0&R,F
+M+"`,+!DG-1L<&!$:*1`7,0U%#A!Y11$C*8?&RHW&!+07%0P2@`H+*#T@%!T9
+M#PL,%1PCB\9-S8DF%!HF2"4<%A<1#A42%!87-3<9"PD*#@\/#A@7$1,Q3D4T
+M)PP6#R`C&!PK1$0M(#,@(A@9("@='2,=%RD:$11`$#$1*#40"0HC2+Q9C<83
+MRBPV*",1"@DT,QP='18+"QD1(#:-QA&]710?(QT8(!`3%QD4%Q$A$0^`"3<*
+M#A`5#PX4%18D1#@K*A(5$1\?%R(F-#0A"1\9&A\9+"8<*1\9&R4;&!DK#ADH
+M$R`)-B@.'AP;M8S&$\>Q4#,K&A,H)"(:'1@-"P\9&Q-/A,8!N]"$QA#%N1\3
+M'!\8&!H0%A<8$147"H`).`H,#0X3$!<6%!@B1#LK)A82%B$J&C,8'QX1"@\O
+M'!HA2S8?020;)!\;%B$8$A8O#R<)4D()#QH?=X[&$9I2-!L8&AL>&QP/"PX/
+M&B,3>8+&!,V/95>RA,8.HR4.$1(/%A(3%!87#1(1@0DX"@L/#Q46&147$AM!
+M/S`I&!DA/T8M/!46&Q0+#"T>&15T<EM4*C-"'QP:'1H7'1T1+`E`&`D*#QH\
+MCL81O&TV'!H8&QT5$PT-#P\3)A*K@<8(U:9'/CA@:8O"@<8.@R87#@\1%!47
+M%Q@6#0\,@`D\"@H-$0\3%AH5&A(9/D(J*AD@,T94,CH1$AD5"PHK(A82=Z6:
+MD'E_>4$[+!\=&QT8$R(,.0D7%PL3.L)PRXS&"(<^'!H<&QL."X$/`PTG&L^`
+MQAO)XX$D-D,3#4VPRL;&R&8D'0X1%1,:'1P9&`\-@0DA"PH.$1$0%AL5&A89
+M/#\C*ALD0#U9+C80$AD7"PLI(Q(18H#&%\?$J&UE33$G'QL:%AD/-@DE(0D+
+M2ZP9RHW&!G\<'1L0$1&!#P,+$29=@<8;V-JGME-2&0HG2N#&QM,J&0\-$1$8
+M&AH=%2`.#8()(`H,#A86%1L3%QDB/",F,BLL0AU.+SX3(R,A$1(D'PP-#(7&
+M$KZ16S$<'!L7$A@*)0D)"E@L%)B-Q@?3)A`/%1<2&(`/`PP7'+6`QH#J#<QO
+M*QH9%3P>,[G&N!\8@`HO#AD@%Q08&PL6#@T)#`D)#PT8&A(;$Q89*BPD-#HS
+M.%$I)2<R0$%143,B&QD1#`R:A\8/RHI((!L9%A$8"0\)"10448[&`\,K0EF`
+M/P4C"PL/)"2%QD"7-T<G)3TS#!E^@B,0"0P)$QDZ3C4I$Q`9$A$-#0D)#1$9
+M'!D6%QD;)#P]/$11/"`H(RL]55);L^1R$1(1#0P5Q(C&#]6J2"4=&A(/#@D*
+M"AE`QLV-Q@N*7E\_.RDJ"PL/)3N%QD'`M+>/,#$Z*QDQ+R,.#`T,1%-*1E90
+M&Q87#14-#@H*"1$4&QH9&AL6'2,R/4XW.S`P.T9)05FCQ,J_9!$-#`D++K:'
+MQ@_(P[:C.1\:%0\*"0D1/\I5C<8+JFQ((485%PX.$A9JB,89NYY7,R<?'!\;
+M#Q$,$)ZE1T5;6!H6%`X/$@^`"@(.$A2`&QP<%QP:(3U4.T=)/4Q4,D9QP,;&
+MQ[!/"PL)"0U*UHG&#<*UB"`:%@\,"@LB1!_0C,8+M&E2%$L4$`\.'QJ=B<88
+MQ95D&B0>&1$/#@Y4P,)&-UE9(AL9$@T3#X`*%0L-$AP<&QL:&QHA05=-2%9)
+M5D`J;:""Q@)L#@J`"0$8FXK&#-&X;#H9%0\+"1,2$KZ,Q@6]7VL/1AN`#P(J
+M.L2+QBZD(B(>%`P1"RFCQL9*)U=:-1XA%PP5#PD*"0D+$!L<&1P>&R`Q25E;
+M2%M05#A,G8/&`G@2"X`)`0I*C,8-NG,P&Q,-"0T-$:/&N\6)Q@K*68L5,2D0
+M$!8OBXS&",QC'`P.$AH.@H#&"VDF3EI1'",?"AH1"H`)$@P0&1T9'B4A,5)2
+M5EM:6TE'<K*$Q@*&$0V!"0$@Q8S&#,AW+QH1"@L,$(K#AL")Q@K5:JT_+#\0
+M$1\OY(W&!N!("0X:&AN!QAC<0R516B8?(0T<$0H)"@D-$AD='28E*%!:@EL"
+M48G*A<8(K@H)"0P)"1O`CL8*LAP8$`P-#BNK#[2*Q@B]O590)A(/'#V/Q@6W
+M"1(P(\2"QA?-(R5;5"LE'1X*"PD)"Q45'",Q/3,G/$F!6P%NP(?&!],)"@DE
+M"@D@D,8)ES$:$`L/$2`/J8O&!\!N33`:$QF0D,8#Q#,1A(/&"<I^)UI8,C4S
+M'PR`"@\6)!(?("4?("4]/491,AK4B<8&70D)(P\*.)'&"[XS(102"PX,98I(
+MJXC&!\6%348;&%S`D<8"M+"^@\8)Q[V725M,.2L4"8`*#Q4S#Q\?'APD(!P6
+M$1H/0LB)Q@;%"0HS)0EDD<8+Q:U2*2L5(!`Y2V7"B<8%E!L:%A^UG<8'P7A%
+M23D?%`F`"@X.+11T;X20/@\.#`H,"9J*Q@;*&@DL*PF`DL8)Q*IJ/BU`+E%4
+MJHK&!;8)"1A/S9W&%,BH?F(W'A8+"@D*"C`?JZBVOS,)"H`)`1"^B\8%,@DE
+M&PF+E,8'HH5<4TEE@\.*Q@70$0P]D,F?QA;`D%I&+@T+"@L)+"7#QL:_(`D+
+M"@D*0XS&!4P/)@H)FI;&!)1V=82SC,8"*A6=H\84RK5T$0D,"@H=(<#&QJP@
+M"@P*"1#$C,8%8",U"0FWJL8!T,2FQA'30`D)"@D2%[W&QIXK&AL6%)B-Q@6/
+M/D,3";?6QA#@(PL*"0X1M\;&H1LM,QLDO8W&!8(E31,)D-;&$,HO"@H)#0NQ
+MQL:D'S9`)2'0C<8%9Q8\#0EOUL80F!0*"0D/#[7&QJ@D0D5$7,F-Q@4P#C,/
+M"DG5QA"C20H*"0H-%+K&QJ<Q335&IXW&!K@5"QX-"C;3QA+$HF,*"0T,#`DG
+MP,;&I31*'TS9C,8(R88)"@L)"2G$TL8)KS$)"0H:#@T88H#&!*<?*A)WC<8#
+MRQ8*"8`*`1B]TL8(3A4)"0LS#1%\@<8$L4(3)F^-Q@B:"0P)"@D)%KO1Q@A^
+M#PH)"@XC2:J"Q@3">QQPA(W&"&X)"0H)"0H2M]'&!S,)"0P;/:+.A,8#J"JT
+MA(W&`V`)"PJ`"0$+L=#&"+\8"@D;.J_"QX3&`]DQQ)*-Q@-$"0L*@`D!#++/
+MQ@?9020*"C*BQ(;&`\U2QL.,Q@F8%PL*"0D*"A:[S\8&KB<A"0MLQ8C&`G[&
+MS8S&`E<9#(`)`PH),,+/Q@5U,!</#:>)Q@"JCL8"(BH,@`D"#"!FT,8$7AT9
+M'Q**Q@#,CL8'&BL-#@P-#F[1Q@5O)$02'\V;Q@<F*`T>&2L9J]'&!'T]6$I=
+MF\8(RCPB&4)$"QFLT<8$E$\C3;>;Q@C'/QM,'$`E%KG1Q@.7,IF!G<8'D"A3
+M.D-<,LC1Q@.M:\2TG<8'H3=023!9><G1Q@.^M<37G<8&FCY%1#=<N=+&`[+(
+MQ-F=Q@6>/RXOC:73Q@+4R\2>Q@6#BT!(JMS4Q@'$RY[&!(ZDQ->.U<8`Q)_&
+M!-2YQ,6BU<8`UI_&!<B\T\ZLRM3&`,N@Q@2VVLC3O_C&!+S$QM/"^,8$Q9S&
+MQLGYQ@!V_,8`RZ3&_\:*Q@+,\-SZQ@+K]NOZQ@/V]NS3^<8#ZN7?Q_K&`K6V
+M<_K&`]H_)\3ZQ@+%4VO\Q@%ZQ/O&`KL[E_O&`K%9V?K&`]-]E,7ZQ@*X7:[[
+MQ@*D<+W[Q@&%?_O&`M)EC_K&`\>Z9<2GQ@7<MK:3MLS+Q@*J3[FBQ@[6E$=$
+M/S0U,30Z.$1GC<3&Q@/%@X33G\83Q9UU1Q,8"0D+$!,*"1$I16B$F<[$Q@+9
+M8;J>QA:[EED,"0H7#0P/$R,0#0P+%0HR4J*@N\/&`I12O9S&&KR)#`L)"0X5
+M%Q48'C`9%Q43)A`.#`DKA['!R,'&`9^%G,8::PH)&PL.&1\C&A0F*B(B%!0N
+M'1D3#Q$*'IG3PL8)8XC<E4Y(2'ZTSH+&`?;.BL8>V4@)"0H6'AD7+3Q-97E_
+M@("*A6L\+AL;*!<0"RF9T\#&$=E"%`P4&!H9&!I9O,;&]O;BPHG&"Y,="0H0
+M'1TE5F%E>("%$)29F;"DKI*$?TX?&Q40##>TO\81>Q$C%QD5*A,5&B`N9L_E
+MY+2_B<8A8',2#A@;2UA><YJ!A8N>E)F,E)RHJJ*IG)9H(!H4(2!RW+S&$LPQ
+M#!PC06EO;FE6,QPI7.+3A\Z)QB)+528>$QY;7WN$C(J;F:*FI)*6FJ2OK:JN
+MGIM]:$0H%",_K+O&$K,8#1U/3I.4EH^#;UDV-^+4<=N)QB0Y2$4A$!<^8(*#
+MA8>3H9.FH)2>FJ.OLJ&LH:*EG8IC+!0/6'[.N<82D!`,'6!,EJ*@FY^BEV50
+MS])IT8G&)CEN>"`1#QM-?WR$@X.<BIJ9E)N<HJZNFZ2FH:^WNZ)?,QX0+:BW
+MQ[?&$WX*"0\=0(&:GZ&BH:&9GIBY8HNVB,8G7./!(!@6$Q5Q=G^&@(66B)>2
+MB:2@JYN;H:BLKK.QM+F"2B03'WN^R;;&%)@/"0D-0)MEF9FBF9V9BJVJ-1='
+MQ(?&)USC@QL;&2$8#4A_CX63A9F/E**?FIJ<F["PLJ:ON;2ON+UZ+C<0<MFV
+MQA7"10P)"A,T'VFBG9FBF:VC*!!5)#NV@<8!U]2`QAE<XU(<%ALP(@\,/7F`
+MA86*?X69GY"EFZ>PL("Y"[NQN;O`O+EO&Q$NX+3&"M??QB`)"0H-#B93@*([
+MIZ:GFL[`5J>=U]K7OL_/U\;&0>-(&R$.(2`9$A<SA8^%A9F6HI&1FY&;H9NM
+MN;JONKFON[N^P*0K%@QXL\9+V=+'BPT)"0P,+3),FZ*MK7_+U<RQJ*&OL*^S
+MK<_1NKQ`XD`7(Q(L'AP8,1DV?8&6F9VFD)&;IIN=JJBKMJ^RNZR[OK^^MYU1
+M%BM\T+'&3,W9QKLC"PD,"R`I0KVLL+QYP<7+SV9\?'5@9GREN++$,N(S$Q\8
+M-#TE'3<7&$9UFH^8FYB7FZ6EIJNGL+&OLK.UL[_!OL#&EULK39'3L,9-Q-S&
+MQEH1"0H+$"9'PK#!TY.IQ-/80E9I6"PH1W*3LL\BW2@3&ALR7#LO,AT5%E2)
+MAX^5HZ"9H*VQIJFYLK*VK+NOO,+`QLG+K&5$0JW`K\8`RX#&-L0P"@D-"A8B
+M6I?T\<^X]O3QG%^BC6!+)6!QP,P6R"D>&QP95&5<-"`:&1=.@H^DHJN1K:>O
+MIJN`N1"ZK+N[NL#$R,O3U\IU)Q6<Q+/&2;`-"0H."A4=4N/-S^[VY,Z<F:>J
+MIV!6N,:[LQ.8'2,X(1XL969H21PH)@TEBX^1FY&GIYZFJ[FTN[6ON+VOP,/`
+MRLG7R<N(&Q:TM,8W-`L)"1H--T)9R,_G]K90JYJGJJ:F4W[&QM\<4R`C7Q\:
+M'F5F:')R32(8$"^%G)J0GJ:IIJ:YK[F`NP6]PLF_P\.!RP37P"L1F;/&),0=
+M"0D,)PTT2+O/R/:T/M6LI["PJ[M>?L;&&2PC(5]8&"%59FB!<@DF&B4-AIZI
+MG)NC@*\5JKNSN[B]O\C#R,C)R<[+T]>V01%9S*;&`=_0A\8CDPH)"29*%CI0
+MS\[DHRW3NZZPL+&YP9*2Q!$9&21?8RXK(&AQ@7(B=$PP&"!5FYV;IJ>GKZZN
+MNJZXO;[`Q<3(RL_&UM/7T\50)WNEQ@++JX&'Q@^\&@L)$3!3&8I/S^!U*HBJ
+M@+`/N,')NL>X%AL<(E]E5!\:4H)R)(!T7S(8*E2;HZ2FLKBOMK2XN[^]OL3#
+MR,K,RM?.U]37O)8X4,6CQ@.^F42YA\8A<A8)"1=?5&@^G,E5,4R)@:>TN\G&
+MQM&K&!X<(5]E8C,;/H)R)8!_=EPZ-RM;H*6FM[6RN;>[O;Z]P,;$R<K*T=/0
+MU];7W<UG(XK1D\8#R<6[O(;&!L.:B9DBB,F&QA/$.0H)"42444A4K6E:0XM=
+MCK"[SX#&"ID9(QX@8&5E5!TO@7(!=H"`?PQD7",:?96FM:^TN;N\@+T"P<C$
+M@,D,U,_3U=G9W-VU1D.NQ)#&"\G#S;>1E+3#O+W!R8#&!K(3%(@@',R'QA*3
+M#@D)$G:R-!J5U;Z1V'QIC;'.@,8+>!HI(A]D969F)R9K@'(0?H!_?W>!@DLI
+M*%R:K;&ON;F`O1.^P,3%R\C)RL_3T-?=W-W?QS0GKY#&"]ZMH6E'146I<7Z>
+MW8#&!G4)$!X/#J*'QA*[&0H*"0VUSS1ZXK]UIXVM4W'#@,8N:1$6%R%D96=J
+M5AD_<G)M<H!_?SQ_@H)\4Q]!H+FNN;2]O+W#P<3*S,C/R<_/U]:`W07AX<)+
+M0<2-QA/-PHQ(1D5"-3<5.R<B2<3&U0X)#8`.`'*"Q@'<TX'&.ID5"@D)H\_/
+M5B1")1XBN;O!9:[&QCT8&Q4@9&5G:G)&*VER2AU\?T<4=X*"CY!=%2F>N\"_
+MN[R]O,#(@,D'R\_7T]??X\V!Q@+$1QZ-QE>P:3HU*RLP-2!!8B<7&HG&2`D)
+M"A`.#FS&QN"\QF]!R<:5QL9>#`D)G\_/5@\;'A$/M:/3QL[&RAD;'QPI96,D
+M9')?(D=R-!==?QL45H*`79"0A5,7?<"\@+T)O[_"R<G*S\S=U(?&`)F-QF1N
+M*"(4$R`A)!I?:1@4%R:;$0D*"A`.#E;&QI]4QS4?NKPFF<:E%@L)GL]_IY$4
+M)T8/>"YSQL?#50T<(1PP95@7+G)4$C!R&A0B6A44)GDG*9"0CHE>*G&\O;V_
+MP+_"R<O*W<?)R(?&`,"-QD^6;FE(-186(!Q22!`0$Q)0#`L*"A0/#C7%QFLJ
+MK246J*T5:L:Z2Q$)I,^=JK=1.T-9BBY#T\QR*0L8'1DG9$05'60Z$BI*%106
+M-A04&DH7'X"0#I:`5F>!O+W&Q,+#RM3(TIO&7\6_N)%T0B4:&S0?"@X0#PD/
+M#@L*&!`.%J+'-0]S&A%WE1,VQL:0(3>WS[^MP9%"/:*E6"6\QA\0"Q46%1A=
+M*A041B`4(AT5%!(6%A,4&10:D)"&@I>0=$^5M\G&Q,?0UZ+&0]QV$@P0#0D*
+M"0\*#@\-#1D2#@XYQA,-&A,1%6D3%KB]P4.MQ\"TT*F&)4JDHZ0Y2Y(4%@P6
+M%1(/1A04$A<3%!,1%100@!,'%!,4%Y"-73>`EP=W+YVVP\+.W*7&3"T,%1,,
+M"0D-"A`0%1$7$PX0#I<0#Q`0$@T3$Q!6?IE&'215R->T.58BLZ:SCQ<U%A00
+M'B(6#Q,3%!(3$A03&1@3$!<3$A03%!.0>Q<D@)<&II]/6<?2RJ7&()8*#A4-
+M"14+"@D*$QL1%1`)#0PU#@P,#PT0$A(0#!L;&H`;%2;B]H8+"P\>5E8>%Q<0
+M"AH?$"$8$A2`$`@4$0X4#@X6"Q"!$PM6&A06P].TC,;&M%.GQB%O"0L0"0X,
+M"0D*&!,8$1,+%!<6&189&!@;&142%0P-#`P.@!L3-_:X#A(0#A44#A<>#0H4
+M&PX@$@Z!#!@+#`H/"AP9#`D1#!$2$Q0<&,2D&5W&QN#1I\95,0D*#@\,"@P)
+M$!460B46$1(B'Q\@(2@N-1DV$S<5$!</#A`9&QSERA\=$Q4-#`D4'`X/%AH.
+M#PT)"@D*"@D*"0P>%B@5"PP/$`L?$1D7834;.\:4.K^GQCT_"@D+$0L)"Q80
+M(QLP,AL.$B,=*"DD'B8G(CD2)R,2%A0*#!@;),+,)Q\9%0P+"2DW"Q`9'0\/
+M"@H)"0L)"X`)%!00'1H+"0P1$QT<&!0I&AH>K#H=KJ?&'5\-"0L1"PL,%R%@
+M'"<N&A`2'R$D)2,A)B`F+1H=+X`1-@D+$ALA<<LD'Q\8#1$3+34*#A@<#@X+
+M"@D)#`D,"0H)#1,5(A`/#`\3%"(2$Q47&!=?'!RKQLREQEAX%@H+$0L.$A5+
+MBQXG*!46$QLD'AXB)B4?(R$F%S83#@\*"PL;&R7*'AP@&P\6'2<E"@L5&@P,
+M"PH)"0L)"PD+"0L5$C48$`T/$0X=#Q`.%A87&AH;HL:HQ:3&.'8E"@L.#!,@
+M%8YC)R4H$!T6&QL?&!X<&1D8'BD3,!H/$PX)"Q<:%,PH(!H9#Q`@&P\)#!,8
+M#0T+"X()&@L)"@D3$U,H"PP;%A<2%`L*%Q`4%QH8=K(EN:3&/'4-"0H)$!<;
+M%F%C)28O%!0>%A(4%103$!D3&!04&!@-$1<*"1(0$]-]6A`0#`T0%PH*$Q4<
+M#A`,"PD*"0N`"1@*#0H+)BD3'1T3(A<-"@H-#1@9&!@Q&1R#I,8`1H`)-`T-
+M$1<4-6,_,247%A</"@L+#`L+"@L.%A0,%Q$4'PT+"PP^E=CB8PX0#0L3"0D/
+M$A`C)1@5@@D""@D+@0D5'D)(0AXB%`H)#@D)"A0.&Q88&4[<?J'&/;0+"0H*
+M#Q$3$!0;R5TJ%A`7%PH,#`D*"@P)"Q(9&!$5$`\?#PD,#@P4B<*M4`T,"@P)
+M"0\3#RP^2#@+#!0-@`J`"0L*(EEC2TL]%!,-"A2`"P4)"10F&!B`(:#&%;(H
+M"0D,"A(5$!04$"<C#Q8/$@L*#PN""44,#A<:%148$A00$`T/#1`>19J<%@H)
+M#`D+#Q4,)3Y&.AH;+"D;%Q83#PP/6UEB2$@]%!`0#`X-#!0)"PH/$!T:'!W$
+MQL;%G,9@:`P)"0H+#Q0.%!4/#!<1%A$+"0D+"@L)"@L+#!,6&!87&!87$Q$0
+M%A(/#14X3W@L"0H)"0P2#!PH/D`A+3XW(AP<&AD=,4U$0$A(*Q80$`X-"PL-
+M"1`*"@LC(A<9C95)CIS&`$"`"0X*"P\3#Q06$@P9%181"PF`"BD+"0L,"PL4
+M&!@7&!<6&142%!<2#PL/%2EV-S(*"0H*$`P;(#4])S=$/"2`&PT<*#]$/3)%
+M0B84$!`.#8`+#`D/"@D*'A\8&F)I'WN;Q@&Q#H`)&PL*#A`6&!L:#R`9%0P,
+M"0L,#`D+#`P*#!8=&!J`%QP:%Q88%Q,3#1H-#!(WL1@*"PH-#!L=("LR1$5"
+M*8`4'Q@[1CXY)SDQ*@X.#PX/#0T+"0H+"@H+#!DC&A<==;:ZF<8!*0J""4D0
+M%1<;&AL0%A`-#`H)#`X+#`\-#1`0%AL:&AD8&1D8%A4;$1,6&Q,.#"W.7`H.
+M"PD*$AH;&BI$145#$@\.$#](/B8<*"X>%Q8,$(`-#PL*"@D+"PH*$RX5%AM)
+M07"8Q@"T@@E2$A40&1D7'!`3%!8*"1`0$Q(3%QL8&AP;%A89&QP:&1L7%1@5
+M&!,7%"8.#!@FH1$6#`X5$1<4$!@M145#+1L7$"U(+!0,%!8/$1P8$0L0#PT-
+M"PR#"04+#!,=(D.8QB!A"0H*"0D,$Q47&1D3&10-"Q$,#A48&1LF*2HY+R`A
+M&AN`&AX8&A@;&R,7%!47)A@1%19_%2$."0H*%@T0#AE(2D@\@!T"&"(6@`H;
+M#`D)$!H9"PX0$`\,%`P*#`D)"@D801\<(\9C?I3&`X<5"0J`"6(.%189&A<0
+M%PL+$1$,(2\I*B0B'APK,CDO*B@?'!D;&1@:&B`6%Q(7(AT5$QHI%AT+"0D*
+M%PL0#A5(2&(X#A,9'!P8$1`0"PD)"QD7$A`.%18/%@H.#@D*"@D-(@\/&D(G
+M*\F2Q@+))PJ""0`/@!4K%A(.#@H2#1`.8(>EH)Z=H7(F)BDS.#$H'!P9&!@;
+M&!L8%Q<2+!L5%A8G*1F`"0(*%@V`$"D\14\P#0X0$Q87&QD<&!$1#!@6$Q`3
+M%A42&@T.$0L0#`D*#@D9'1P='[62Q@*_"@J!"1`+$1<4$!@6#0L/$PL2$J"T
+MR8#&'<FJ@58B+#0H+2(H&QD7&QT:&1@8$2\7%A46+3$6"H`))!,0#Q(/(RQ%
+M,1`.$1(3%!H<(!D2$1`<&A,.%A@7%!D1$!(/$Q"!"0<=+Q49(*2BNY#&%;$+
+M"0D+"0D.%QL3"QL:#`P1#PP5+LR$QD_6F4TV)1\M+"\A'10=(!D9&!41*148
+M%1<R,A,+"0D*$1,/$Q$/%CDP&!(9$A,/%1P@%A$/$AT>&A`6&QL6&A42%Q$3
+M%@H-"@D9,Q$5'7IGDY#&%*D0#`H+"PH,'B00"QH9"PP+"@T7@X?&$M%V)R0J
+M-"$F(Q4B&Q4=%Q,1%AB`&0(Z*Q&`"30+#A02$A$/$B(B)1DB$A,.%A\A&`\.
+M$!<@+!</(!\7(1,4&A86'PH4$@D3"0D=$1DA.;[&QXW&$ZD0#`P."PL)'"\7
+M"Q@:$PX+#!<<BL9.M%$9'QT?(AXQ&A,:$Q,1&A<9&R)3)@\)"0H/"1`7$!`-
+M&2(J)1\B%`T3$QP>&!<.%AP=(AL+(A@@+QH9&!`7(`X2(@PI#`QA*1$<((/&
+MRHW&!+,5%`P2@`H+'S,=$QL9#PL,$QLAB\9-S9<C$QHC.2(;%A<1#142%!86
+M+RH4"@D*#0\.#1@7$1,D/3PE'PP5#QL<%A<A,B<A&R4;'1<8'B,=&AT;%B`6
+M$1,W#B(/'2@,"0H>.\).C<83RB(D'1\0"@DL+!L='18+"Q80'C:-QA&]4Q,<
+M'QT8'A`2%1D3%A$=$0Z`"3<*#1`4#@T3%!4>.BL>(!(5$1D=%2`A*B4<"1H5
+M%QP7(AX;(1X9&2(:%Q@B#A09#Q8)(1T-&QD7M(S&$\><."0F&1(?("`9'1<,
+M"PX6&1%)A,8!NM&$QA#%N!H3&AP8%Q</%1<7$106"H$)&PP-#1,0%A84%!LJ
+M,"$>%1`6'2$8*14:&Q$*#R2`&A@Z*!XW(!H@'AL5'!<1$R,-'0D\)PD.%Q=R
+MC<82P)@]*1@8%QH=&AD/"PT.%QL3<(+&!,Y\4E*OA,8.H1X-$!(/%1$3%!87
+M#1(0@0DX"@L/#A05&147$1HS-"4A&!0?,S8A-!05&10+#",9&!)S:U9)(BPU
+M'QP:&QH7&1@1'PDI$0D)#Q8TCL81OF`J&1D7&AP4$0T-#@X2'1*G@<8(TYXX
+M+"==:(C$@<8.?QX3#0\/%!,7%Q@6#0\+@`D\"@H-$0\2%AD5&A(8-#0A(AD:
+M+#=()#`1$1<5"PH@&Q40=Z.8BG5^;#LU)QX<&QL7$QH+(PD2$@L0,<-OS(S&
+M"(,U&QH;&QH."X$.`PT?&-"`QAO(WFX>+2H2#$:RR<;&QV`=&0P0$1(7'1L9
+M%PX-@0DA"PH.$1`0%AH4&148,3`>(1D?-S!0(RP/$!86"PL?'A(078#&%\?(
+MHV5<12TD'AH:%18.(@D;&0D+0:P7S8W&!GH;'1H0$!.!#@,+$!U3@<8;U<Z0
+MF$8\%@H?.]_&QM(A&`X,$!`7&AH;%1L.#8()(`H,#146%1H3%A@:,1PC)B(B
+M,1P])"X1&A@7$!$?&0L,#(7&$L6.4RL;'!H5$A0*&PD)"D$B%*.-Q@?2(A`.
+M&A<2'H`.`PP5&;2`QH#C0+IE)!<9$2D9++C&M!<3"PH*#A8;%Q,8%PL5#0P)
+M"PD)#PT7&1(:$Q08)"(@)2XJ+CP=&1PF+RT\/"H8&!<1"PN9A\8/RHT_'AL9
+M%1$3"0P)"1$42H[&#,DG/U<U/34?"PL.'R"%QCF5+CTB'RLE#!AZ>Q@0"0P)
+M$Q8H/"L@$Q`8$1$*#`D)#!`8&QD5%Q@;'S$S,38\+1L=&"(J/SU%L.%R@!`#
+M#`L5Q(C&#]2C/B(=&A$/#0D)"A,^QLZ,Q@S'B%M>-3<D)@L+#AD\A<9!P+2V
+MC28K*R<4+2D=#@L,"SY+-C1"/1H5%PT3#`T*"@D1$QL:%QH;%AP>*C,\+"XE
+M)BDW-S%"G,3*OUL0#0P)"BNUA\8/R,*UHC`>&!0/"@D)$#W.3XW&"ZEM1B1#
+M%!8-#1(29(C&&;N<4RL@&!<;%@X.#`Z<J#LS14,9%10.#A`.@`HB#A$4&QH;
+M&Q<<&!TS.BLW-BTW/R<V:;_&QL>N2PL+"0D,0M:)Q@W"L((?&A0/#`H*'$4>
+MT8S&"[-I319*%P\.#QH8FHG&&,238A8=&!8/#@T-4\#%/"M$1!T8%Q$-$0Z`
+M"A4+#1`;&QD;&AH9'#<_.#1!-T$Q)&6>@L8":0T+@`D!$Y>*Q@S0M&LT&!4/
+M"PD/$1*WC,8+O%UF#D,?#@X/(C;$B\8NIAL=&!(-$`HHH<;&0B)!1"D;'!4,
+M$@T)"@D)"Q`;'!@<'1D=)SQ"131%/$`R2)Z#Q@)W$`R`"0$*18S&#;EK+!L3
+M#0D,#!"8QKK%B<8*S%B,$RLD#@\4*8>,Q@C,4!D+#A$6#8"`Q@MC(SQ$/AH?
+M'`H6#PJ`"1(+#QD=&1TB'25`/4!%1$4W/&FOA,8"@1$-@0D!(,6,Q@S(;S`:
+M$0D+#!"&PX;`B<8*U&BQ-2<U#Q`;)>&-Q@;?00D.&!88@<88W#PB/D,>'!X,
+M&`\*"0H)#!$9'1TC(B,]1(!%!$1%/W[*A<8(K0H)"0P)"1O`CL8*MQL6#PP-
+M#AZJ#K.*Q@C#O%5((A$0'#2/Q@6Z"1$K',2"QA?,(B)%/R$B&QH*"PD)"Q,4
+M&QXK,RPB,3>!10%IOX?&!]()"@D="@D@D,8)E24:$`L/$1L.I(O&![]I2BL;
+M$QB=D,8#Q"L0?X/&"<IU(T-")BLJ'`R`"@\5'A$>'2(>'B,S,SP\)A77B<8&
+M4PD)'`X*-)'&"[XL'1,1"PX,8HT_GHC&!\6213X5&%3`D<8"L["]@\8)Q[R5
+M/44Z+"$4"8`*`A,G#X`>"1L?'!L4$14-/,B)Q@;%"0H@&0E;D<8+Q;)'(",5
+M'@\Q/%S!B<8%E1@7$QVPG<8'P&XX/"\9$PF`"@<-(1-Q9GZ4-(`-`PH+"9:*
+MQ@;*&`D>'0EZD\8(IV0O*3(F/C^HBL8%M0D)%DK,G<89R*)W6RX;%0H*"0H*
+M)!ZIHK/"*PD*"PD)#[V+Q@4O"1T4"864Q@>@>EE".%=VQ(K&!=$1##J)R9_&
+M%KZ-5$4J#0L*"@DE)</&QKX;"0L)"0I!C,8%2@T="@F3E<8%PY-J9("PC,8"
+M)Q25H\84RK1H$`D,"@H8(<#&QJD;"@P*"0_$C,8%8!@F"0FVJL8!T<2FQA'3
+M-PD)"@D1%[W&QITA&1H4$Y2-Q@6%*RH/";;6QA#?'0L)"0X0ML;&H!HG+!D?
+MO8W&!7X9/`\)A];&$,DD"@H)#0NQQL:A'BHP(A_0C<8%8A0G#`EEUL80D!$*
+M"0D.#K3&QJ,A,SDT4\F-Q@4K#2(."D'5QA"=1`H*"0H-$[G&QJ0K.2XVHHW&
+M!K43"A8,"C+3QA+$H%@*"0T+#`DDO\;&I"TW'$79C,8(R8`)"@L)"2C$TL8!
+MK2R`"008#@T86H#&!*8<(1)WC<8#RQ8*"8`*`1>\TL8(1A,)"0LJ#1!X@<8$
+ML3\3(G*-Q@B5"0L)"@D)%;K1Q@AZ#PH)"@T80Z."Q@3$?QIR@XW&"&\)"0H)
+M"0H1MM'&!RH)"0L8-9_-A,8#K"J]@XW&`U\)"@J`"0$+L=#&"+T7"@D6*;'!
+MQX3&`]DPQ9&-Q@,_"0H*@`D!#++/Q@?9/1H*"BB=Q8;&`\Q-QL.,Q@*0%@N`
+M"0,*"A6ZS\8&H1H8"0MEQ8C&`GS&S8S&`D\2"X`)`PH)+<+/Q@5='Q(-#:6)
+MQ@"LCL8"'AP,@`D"#!]CT,8$2Q82%Q**Q@#,CL8'&2$-#`L,#6K1Q@5E&2<.
+M'<Z;Q@<C)`P8%"$4I='&!&,E03A3F\8(RC$<%#<G"A2IT<8$CSP</+:;Q@C'
+M-QD[&34=$[C1Q@.5*8=PG<8'B"%!+#D^*<C1Q@.O8*VEG<8'G2X_-"E`<LG1
+MQ@/!H:W0G<8&F38V+S%+N-+&`ZZSL->=Q@6<.R0D@Y73Q@+7N<2>Q@6"B3<]
+MH]34Q@&SSY[&!9"GK<B0P-3&`,B?Q@77N:VYG\#4Q@#7G\8%R,&_R*?'U,8`
+MRJ#&!+;6Q]*^^,8$O</&T\+XQ@3'F<;&R?G&`'3\Q@#/I,9T.&UK``!`"/__
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+M____________________________________________________________
+"__\`
+`
+end
diff --git a/win/Qt/nhsplash.xpm b/win/Qt/nhsplash.xpm
new file mode 100644 (file)
index 0000000..7850725
--- /dev/null
@@ -0,0 +1,374 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"196 111 256 2",
+/* colors */
+" ` c None",
+"   c #A094A7",
+" . c #761C1B",
+" X c #751A1A",
+" o c #361414",
+" O c #18181E",
+" + c #CF0909",
+" @ c #F4F2E2",
+" # c #AD110F",
+" $ c #AB0D0D",
+" % c #C9BEC5",
+" & c #CF977F",
+" * c #627EB9",
+" = c #512A21",
+" - c #5F201B",
+" ; c #A45841",
+" : c #D3281D",
+" > c #661B18",
+" , c #78443A",
+" < c #721110",
+" 1 c #61332A",
+" 2 c #7C231D",
+" 3 c #533226",
+" 4 c #978A8D",
+" 5 c #AF0A0A",
+" 6 c #841111",
+" 7 c #783226",
+" 8 c #B80D0C",
+" 9 c #981514",
+" 0 c #DDDACE",
+" q c #881918",
+" w c #B0A5B9",
+" e c #74352F",
+" r c #CCA799",
+" t c #ADA8AC",
+" y c #9B9897",
+" u c #651413",
+" i c #712C22",
+" p c #710C0B",
+" a c #8E1817",
+" s c #861B19",
+" d c #E4100C",
+" f c #9B1010",
+" g c #B49795",
+" h c #EB0909",
+" j c #3E302B",
+" k c #8F5D53",
+" l c #9E0909",
+" z c #701717",
+" x c #D1CBCF",
+" c c #846E69",
+" v c #9987A2",
+" b c #291413",
+" n c #281212",
+" m c #691110",
+" M c #BA0A0A",
+" N c #DED4D5",
+" B c #71291B",
+" V c #918E90",
+" C c #721F1C",
+" Z c #664231",
+" A c #7D1313",
+" S c #C2B5C0",
+" D c #6B332C",
+" F c #D40909",
+" G c #66625F",
+" H c #460A0B",
+" J c #446CCF",
+" K c #CB0A0A",
+" L c #BB100E",
+" P c #867A85",
+" I c #C64529",
+" U c #273FA2",
+" Y c #B70A0A",
+" T c #A19AA6",
+" R c #811B1A",
+" E c #441916",
+" W c #A50C0C",
+" Q c #521110",
+" ! c #C2BDC3",
+" ~ c #580C0C",
+" ^ c #0E0E0F",
+" / c #481210",
+" ( c #751818",
+" ) c #E0DCDD",
+" _ c #C90C0B",
+" ' c #B5B2C0",
+" ] c #A898B0",
+" [ c #722522",
+" { c #8F1B17",
+" } c #78201E",
+" | c #8D1515",
+".  c #7C1918",
+".. c #831615",
+".X c #E20909",
+".o c #950909",
+".O c #7D100F",
+".+ c #9D7E7A",
+".@ c #792C22",
+".# c #878382",
+".$ c #BC897E",
+".% c #2C2622",
+".& c #D7D4D7",
+".* c #F30909",
+".= c #693D33",
+".- c #CDCBD7",
+".; c #510C0B",
+".: c #0E0B0B",
+".> c #ABA3AF",
+"., c #AE1914",
+".< c #6B1414",
+".1 c #CB0909",
+".2 c #5B513C",
+".3 c #65463C",
+".4 c #1E2856",
+".5 c #6A0909",
+".6 c #8A3425",
+".7 c #381913",
+".8 c #930D0D",
+".9 c #D5D099",
+".0 c #774E3D",
+".q c #403F35",
+".w c #3F231D",
+".e c #7B0909",
+".r c #211110",
+".t c #655A56",
+".y c #171010",
+".u c #BC6F59",
+".i c #AB0A0A",
+".p c #51423F",
+".a c #931110",
+".s c #D2C4AD",
+".d c #7E6F7F",
+".f c #7B1616",
+".g c #BC1914",
+".h c #602519",
+".j c #DAD5C2",
+".k c #B7AAA3",
+".l c #9C231C",
+".z c #67382D",
+".x c #D90909",
+".c c #BAB4BD",
+".v c #A48997",
+".b c #D2C4C4",
+".n c #AF2B1E",
+".m c #EBEAE3",
+".M c #A30F0F",
+".N c #7D1C1B",
+".B c #841918",
+".V c #931313",
+".C c #8B1615",
+".Z c #1A0D0C",
+".A c #640909",
+".S c #635A43",
+".D c #C07D63",
+".F c #8B0B0B",
+".G c #651817",
+".H c #C20909",
+".J c #591715",
+".K c #A21111",
+".L c #9C3122",
+".P c #6A241F",
+".I c #9E0D0D",
+".U c #775B53",
+".Y c #A11513",
+".T c #C7C3C9",
+".R c #280D0C",
+".E c #720909",
+".W c #8D4941",
+".Q c #5B5655",
+".! c #8B1111",
+".~ c #A54427",
+".^ c #E1E0DF",
+"./ c #8D4037",
+".( c #A11B16",
+".) c #727072",
+"._ c #7C0C0C",
+".` c #310E0E",
+".' c #621110",
+".] c #5A1212",
+".[ c #B30A0A",
+".{ c #532318",
+".} c #521F17",
+".| c #792623",
+"X  c #A7A29F",
+"X. c #B6ABBB",
+"XX c #7D1F1D",
+"Xo c #908099",
+"XO c #7B1B1B",
+"X+ c #90878F",
+"X@ c #C5B698",
+"X# c #E90A0A",
+"X$ c #100F0E",
+"X% c #A50909",
+"X& c #580909",
+"X* c #2A1717",
+"X= c #65503D",
+"X- c #3D0C0C",
+"X; c #B00E0D",
+"X: c #807B7F",
+"X> c #7A1D1D",
+"X, c #781D1B",
+"X< c #5A0F0E",
+"X1 c #EF0909",
+"X2 c #696765",
+"X3 c #605B45",
+"X4 c #CD130F",
+"X5 c #D20A0A",
+"X6 c #4C0A0A",
+"X7 c #533E2B",
+"X8 c #850A0A",
+"X9 c #3C59B3",
+"X0 c #C00C0C",
+"Xq c #C70909",
+"Xw c #971915",
+"Xe c #7E1A1A",
+"Xr c #7E7580",
+"Xt c #5E0C0B",
+"Xy c #5D0A0A",
+"Xu c #520909",
+"Xi c #8B2520",
+"Xp c #C85C48",
+"Xa c #CEC5CB",
+"Xs c #6C2A1F",
+"Xd c #642B21",
+"Xf c #9B1212",
+"Xg c #706A68",
+"Xh c #841919",
+"Xj c #A7999E",
+"Xk c #69201C",
+"Xl c #E7E0E0",
+"Xz c #9C6F65",
+"Xx c #C3B9C0",
+"Xc c #826D48",
+"Xv c #AFADA9",
+"Xb c #8A2B22",
+"Xn c #741413",
+"Xm c #9A929B",
+"XM c #CBB5B4",
+"XN c #8F5341",
+"XB c #783C31",
+"XV c #73211F",
+"XC c #911515",
+"XZ c #630D0C",
+"XA c #881616",
+"XS c #E5E4E1",
+"XD c #6E1B1A",
+"XF c #DC0A09",
+"XG c #741616",
+"XH c #8E7F85",
+"XJ c #591B19",
+"XK c #8A201B",
+"XL c #BE0909",
+"XP c #4E1A18",
+"XI c #FEFDF6",
+"XU c #6A0C0C",
+/* pixels */
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XIXI.m ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XIXIXIXI.j ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XIXIXIXI.$Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b.s N.D.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ).S.~.~.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.c kXp N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g I.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xx.~ & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ ;.uXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+Xp.j ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X  ; r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.T ; & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^XzXp N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g.~.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XlXMXMXM r &XMXM N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xx.~ & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl rXp : :X#.X h hX#.X :.X.X.X.x.x :Xp.u &.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^XN.uXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b & :X#X1.*.* : dX5.x F _ K.,.nX0 _X5 _ FXFX4X4.x.xXp.D r N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+Xp.j ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.s :X# hX1 h.XX5 8 L.LXw 9 9Xh q.|XB 2 qXCXC |.VXi.6X; # _ _.x.X :.D r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X Xp r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NXpX#.*.* :X4 _X;.KXhXh.=.| X X.< i 1 1 1.P i.G u.<.=.zX>XhXh.V | #X;.n KX4Xp rXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.T ; & `Xl r.$XpXpXpXp.$.$XM N ` ` ` ` ` ` ` `XIXI 0 ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XlXpX#.*X1.*X5.,.6 2XhXO z D.=.3.3 GX2.).d.dXrXrXrXo P PXrXg.3 , DXk zXO [ , {.KX0 _ KXp rXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ ;XpX0 8 # | a.  RXhXe qXf.L.u rXl ` ` `XIXIXI @.k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 0 & :.*.*X#X0.K R.=XDXd.=.t GX2X2.).d P P P P PXoXoXoXo ] ] v ] vX+.# V.d.U.3.P.NXhXC.VX0X0 _.DXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XlXpXF.!.~ { XXD.< > D u.'.<Xk z.  R a.u r.m.m @ @.sX3 x ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 4Xc & d.gX; qXe z.=.Q G G G.).d v P.d PXrXo v PXoXoXo PX+  Xo     ]  Xm ]      XH.0 iX>XOXCXK.L _ : &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 0.uXFX0XCXD.~.L.U P P PX+ P P.d.U.3Xd -XJ.f ; @ 0 0.+ g ) ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.SXcXcXN.6.|X,.'XJ.Q G G G P PXo PXrXo vXo v v v ]   vX+Xo vXo v ] ] ] ]   wXmXm T.>XmXm c.U 1.z q.KX0 +Xp.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X@ IX# 8.! [XrXB kXj v v vXoXoXo v vXoX+.U D , @.j @ c.m.m ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` eX7XcXcXzXb.V f.8 pXd.t.d.d.d.) P.d P P ]Xo PXo vXo vX+ v vXo v v ] wXmXm     TXm T.> w w ' w.d.W C RXC #X0 I rXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+X0 h.* 8 f { k.3Xz.b v vXo v v v v v vXoXo.k g @.s c.s r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.WXz.mXS.j i.N aXC.V 6.O.6.d.d.)Xr P P.dXr PXo P PXoXoX+ PX+   vXm ]XmXmXmXm   T T w.>.> w.>.> wX..> c ,XGXh.K 8.n &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X@.NX0.*.*Xq $ $Xp.sXzXzXoXoXo v vXoXo vXoXo P.s @X@.q o (./XM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.WXz.mXS.D .X>.NXh qXb 2.o.8 ,.).dXo P P P v PXoXoX+ PXo vX+ vXm VXmXm  Xm ] ] ].> w T.>.> w.> w.> tX..c wXz e i , #.g &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.jXMXi 8.*.*X5 $.,.p.yXs.uXo v vXoXo v vXo   ].kX3 O.yX2.U 3 A ;XM ` ` ` ` ` ` `.-XS ` ` ` ` `.WXz.mXSXbX> <.fX, }.= 7 |.M.oXC.0Xr.)Xr P P PXo PX: PXHXoX+ v V V  XmXm   ] ] ] w w w w wX. TX. w wX. S.cX..cXj c C |.K.g &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ).^ 0.b.| W.*.* + 5.F.yX$ 3.~ k v v v v v     T  .%.j 0.4 J.4.4X9 U.d.-.-XS.- * J J J J.- ` ` `.W ;.m.j.P X iXdXZ > i [.NXhXf.! { A.U P PXo P P PXoX+Xo vXoX+X+XmXm VXmXmXm ]Xm ] T wX. w.>X. w wX. tX.X.X..c SXx t c [XhX; 8.u N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XS 0 ` `.bXiX0X1.*.x 8X0X-.% k.~.n.WXo v v ] ] ].) 4XI.- J J J J U U U U U U UX9 U U J J JX9 * w ,.W @X@Xd.< [.|.< Q.=.P zX>.N s ,XC.8.l kXoXr P vXoXo v  X+X+ VXmXm ]XmXmXmXm ] T T T w.>.>.>.>X. t tX. ' S S.c.c.c.c !.+ iXh 9 8.DXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xx.m ` ` `.bXbX;X1.*XF.I.[.Z.% j.~ & @ 0Xm ] N !.d &X9X9.- `Xl.Q O.4.4.4.4 O O O O.Q.4 U U U * J.= i @.u ( mXnX>X>.'.p G.t.z C D.=.| a.V.oXb cXoXo PX+X+X+   vXmXmXmXmXm ] wXm T T.> w.>.>.>X..> tX..c t.c.c !.c S !.T.T.T.TXj k. ./.n &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 0 ` ` ` ` `.bXi L.*.*.X.I lXtX* j B.D.s gXIXIXI J.Q 0XIXIXIXIXIX+.4.4 U U.p.4.Q.% O.q.)X2X9 J J /.G 0.uX, - 1XnX, iXP.QX2X2X2.3 D X.NXeXA s.C.6 cX+X+X+   w v ]Xm V ]     wXm T T w wX. w wX.X. tX.X.X..cX..c.T !.T.TXa.-.T.-Xa ! c [.K.g r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXi M.X.*X#X;.!.i l =.w.~.$.m @ ` J.-XIXIXI @ 0 0 gXoXo     ]  .) j.4Xo.- ` `.>X9.]XnX@Xb.N - G.=.P DXkXJX2X2X2XgXg G.= CX>.= 7.V W.6.dX+X+XmX+XmXmX+      Xm T T TX. w w.>X..>X..> tX..c SXv S ! !Xx !Xa.T.T.-.T.TXa.c kXO.M :XM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXi 8 h.* h.[XD <.i./.3Xp.uXl ' J *XIXIXI.sX3X@.sXo v     ] T T  .U./.b ` ` `.^.J }.U i.P - G GXd z.N.<.pX2X2XgXg.).).) G.3 [.N a f |./ P vXmXm V VXm ] T T ] T T T w.>.> wX.X.X.X.X..c.c !XaX.Xx ! ! !XaXaXaXaXaXa.&.& S.WXA.KXpXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXi.,.X.*.*X0 eXVX;.,.UXp & J J J `XI @.s.q.+ @.s     ] ] ] T wX. 4 e.$ ` ` ` zXD D DXVXJ G G GXdXGXV 3.QX2XgXg.).).).).).) ,.PXe.@ 7.I.WX+Xm ]  Xm TXm TXm.>.>.>.> T.>X.X. tX. tX..c.c S.T ! !.T !.T.TXa.TXa.-Xa x.&.& xXj.W a #.u ) ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.m ) ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` xXi M h.*.* _.W.UXOX%./ ;.W J J J @ @X@.%Xg @.jXj ] ] ] ].>X. w ! ) g.W N.bX6Xn.f . (Xk G GX2X2 1.z DXJXgXg.).).).).).).)XrXr.U.S D R f.Y.WX+XmXm ]Xm T T T T T.>.>.> t w.c t tX..c S.c.c ! % ! !.T.T x x !Xa.& x.&.&.&.&.&.k.WXi ; & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XS.9.q y ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXiX;XFX1 h K.6Xo ,.OX  U.6 J JXl 0.t j O.+.s c ] ] ] ]X.X. ! ` ` ` NXlXM.G zX>X> .XJ G GX2X2 GXD. XD.pXg.).).).).).).)XrXrX:X:Xg ,.|XhXi.@.W.v ] T TXm T w.>X..>.> w w tX..c.c S.c.c.c ! ! !.T.T.T xXaXa x.&Xa x.& x.&.& ) ).c.U a IXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM.k.9.qX$ t ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXi.( F.*.* F.LXHXo y ^.4.L.dX9Xx.q.q.4.% c g k.v ] w.cX. x ` ` ` ` `.k Q .XVXV C.{ G GX2X2X2 G > C 3.t.).).).).).).)XrXrX:X:X:X:X:.U.U e.C 9.WXm T T TX..>.>.>X. wX.X.X. S.c.c.c.cXx.T.T !.T.T.TXa.T.-.- x.& x.&.& ).& ) ) ).&.v 2Xf.uXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` `XS.jX@X X .c ` ` ` ` ` ` ` ` ` ` ` ` ` ` r.g.H./X@.qX$ O.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XMXh 8X#.*.*X5.l P.4 J O ^.h rXI 0 ' *X+ @ 0.+ c.W gX.X. x ` ` ` ` `.+.'XV D D [.J GX2X2X2X2Xg GXd D -.).).).).).)XrXrX:X:X:X:X:.#.#.#Xr , }.CXb kXm T.>.>.>.>.> w wX..c !X..c.c.c.c.T ! !.TXa.T.T.T.T x x x.& x.&.& ).& ) ) ).^ !Xz |., & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` `.m 0.s.kX  cXcX3X3X3X3Xv r.D.$.+.kXS ` ` ` ` ` rX5.xX5 = O.yX$X$X: ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` rXh 8XFX#.*.XX;X2 J J U ^.+ @ @ 0.t.+.s.+ 4 ]   kXz.v ! ` ` ` ` ` cX6Xn.f .XGXJ GX2X2X2XgXg.).t X.<.p.).).).)Xg.)XrX:X:X:X:.3Xg.#.#.#.#.#.U.U.@Xw ;Xm.> w.> t w tX..cX..c.c.c %Xx.T !.T.-Xa !.- x.TXa x x x.& x ) ) ) ) )XSXSXS.&Xx kXfXp.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` `.m.jX@ cXcXcX3X3X3.p.q.2.q.. I ;.~Xi.@ ,XM ` ` ` NX4X1.* FXPX$X$X$X$ O ` ` ` ` ` ` ` ` `Xl N ` ` ` ` ` ` ` r |.,X5 h.* h.l J J J J.4.2 =.p.4 O O O.% wX.X. %XMXz g ` ` ` `.0 < XXOX,XnXP GX2X2X2XgXg.).).U.PX7 G.).).) =.w.)X:X:X:.q o j.#.#.#.#X+X+ V c ,..XwXzXjX.X. S '.cX.X..c.cX..cXx !.T.TXa.T.T.TXa x x.- x.&.& )XS.m.m ` ` ` ` ` ` ` `XM./.K.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` `.j.+ c.2.q.q j j j j.q.q.q.h ; &.u.~ #Xh RX> r ` `Xp h.*.*.oXZ.yX$X$X$X$.T ` ` `Xl k.^ ` `.D j.^ ` ` ` g ` ` `.k q 8.xX#.* d J J J J.4 ^ ^ BXs O ^ O ^X9X..k.& ` ` N ` ` x `XJ.] }XV C C =X2X2X2.Q.w G.).).) 3 i -.).).Q oX*.w.)X:.3.r o b G.#.#Xr.tX+ V V VXH k.U { k T S.cX..c.c.c.c.cXxXx.c !.TXa.T.T x xXa x )XS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` gXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` `.+.% O O O.y.y.y O O O.%.% |.D &.D.(.K.VXC R.f g rXq.x.1 MX8X6 QX$X$X$X$ y ` ` ` g o.Q ` x E n.Q ` ` r E.# ` ` ` r q 8X5 hX1 J J J.4X9X9 U ^ 1.~.4 ^.y.4 * 2.3.^ ` ` ` !.:X: HXt i [ [XD 1X2X2 G.w oX*.t.)X2X* QX>.3.) oX* o n.w.Q b b o n.%X:.p o o.# V V V V V y c.6 {XzX..c.c.c.c S !XxXxXx !.T.TXa.T x.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` `.T.c.c.c yX:.).pX$X$X$ OX*Xb ; ; :.i W.MXf.YX;Xq M.M fXUXyXuXu q QX$X$X$.% ! ` `.W.Z.r y.D n n.Z t ` 1 b n.T ` ` `.$ a.,Xq & * J U J U U J U O.4.~ U U UX9.pXP.p.^ `.^.%.:.r HX<.f. .NXn.7.QX2.q b o bX*.t j.r o =X7 = nX* o n nX* bX* o n b.w n o o.t V V V VXm y y yXH c.6XzX..c.cXa !.T !.T !Xa x.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` `.^ y.pX$.r._.M.a.FX%XL K.1 L.a M.xX;.!X6X-X- H R zX-X$.y.Z.p ` x.7.Z.ZX* j.r n.ZX* g o b.r j ` ` ` `Xz.L.jXI.- J.4 J J J U U O O.4.6 U U U U.q.7.U `.+ oXJ o H < (Xn ..'.`X*.Q o b o n bX* b b o n.J Q nX* o.r.r b b o b n o bX* o b.q V V VXg.w V y y y y 4 kXiXz.c ! ! !Xx.T x.m ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` `.z.F $.. R.! W $XF F.F $ K.[ f Q Q.J Q.G z.f <.` o.ZX$ y.v.r.Z.r.y.y.r n.y.Z.7 n b.r.r.t.$.$ rXz.~ 2XK.~.QX9 J.- @.s.q.4.4 ^ UX9 UX9X9 U.4X*.U E EXJ /.' XXV [XV.<.` b b b b o n b b n b o b nXJ.w b b.r.rX* n o n.r o b o o bX* VX+.pX* o.t y y y y T TX .+XN.u S.T xXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` `Xz M.[ f.C.C K +.MXA.F.oX#.*.1X8 u u -.<Xy.C.' <Xu.`.R.R =.3.`.R.R.R.Z.r.R.r.r n.r n.r.y.Z B B B.h B B B B B B 1 @XIXIX@.Z.:.:.: ^ O O.4.4.4 O O.yX* o HXyXG .XVXVXU.% OX* n b o.r b.r.r b o n.r.`.h /.`.`.` E H H /.` o b o b b b.t.w b o.7.w ! x.&XM k ` ` ` `XM ;.u ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` N M FXL W f.F h L 6 p.EXLX1.XXf. .<.'XPX< ( AXZ.;.<XJ EXG.P > EXk.{XP.{.{ - (XJ >._.]XPX<X-.O.;X-.R.R.`.{ B B B B./XIXI 0.w.R.7.:.r.r.:.J bX*.`.r O O.yXuXyXG A ..<XZ.%.r n.`.`X-X-.`X-X-X- HX-X-X6.;.<X6 ~ =.hXUXZ.5X<.]X-.` n nX*.7.7 EXkXPXP.bXl cXJXkXj ` ` `Xl ` N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` `Xp.X.X Y.[X; fX4 8.M.o W F.o <.O 9.].6Xc j CXG.fXZ.]X7Xk =.P =.@ =XbX7 7.=.3 = >.SXV u./Xc.(.O.].h.JXy.`.R /.h B B.h.uXI.m./.n.nXK.7.}.Z.RXU.i l f {.l.' ~.'.B.f X zXtX- HX-XuXuX6X&X&X6XyXuX&.AX6X&XuX<XdXU.} 1 1 m p.5XtX< u <.A.J =X<.GXJ E E k.= E - -.U ` `.+.@.k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` `.+ 6 M.[XF M | <X8 l.o.i.KX, /.h.~ /Xp.~.p EX> mXu.]XV 3 -X7 1 j = 3XP 1 =Xd =.6X= DXf a.3.~XG.aXw.h.!X&Xu.R.}.h B.~.h 0.mX7 I.n.LXK.h /X-X6XuX& j.q.pX6.A.' XXD }XO.; / ~X&X6.AX&.E.E ~.E.A ~.E.A.5.5.A < < <.hXs.hXU.o l M.M.K {._ B 3.! z.J /XkXP.}XD E.}.k.=.} C.U ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` `Xl.V m 8.* WXh 6 W W.8 ~ >.J j.D.9.h.~.~X7 OXG z Q.]XPXV 3XJ =.P j.P 1 - 1.PXd 3.N ,.|...6./.K #.I.!.F.E.e HX-.h B B.h.z @.%.n.n.n.L B.}X<.  >XkXJ.3 jX6.AXU q.f X <.;X- Q ~Xy.E.E.5.eXU.E.eXUX8.EXt.E.5 p (.< 6 Z.~., K., LX0 8.M |._Xd 7X;., W.O.G.<.}XP E - E -Xk.}.^ ` ` N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` 7 I $.* _.VX;.FX;.VXi.| u.v &.D.~.6.6X7 O /XDXb.J E = C =.PXJXkXdXX - -XJ.PXJ.PXK D.! R.=Xb 9 f.V.Y.8.o.e H.}.h B B.7.m.%XK { 2XK B.{ /.! 6 [ iXA mX&.5Xt AXn (XZ ~ ~Xt.;.;.5.e.E.e.e.EX8.o.F 5.o 5X%X% l (.,.u.u.~.g.H +.,.l.(.(Xw.8XKXw M $.[.aXb.!.'XP EXJXDXPXP.k N cX>Xx ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` `.j.~ $ YXq.[.o l.a #XhXKXXXC.u.9.D I.h 7.q O o Q.  } Q -.]XJ.].J z u.]XPX<XD.'Xn X 6.<XG._.  i.M.8 8.. {.FX8.AX-.7 /.7 b @ c &.D.l Q /.7.R p 6.' E >Xy.EXU uXnXG C p.' Q QXt.;.E.eX8 YXq _.x +.x.x.1 K FX;X5 K _ : I IX4.g.n.g.n.YXw.LXK p.8 K M M $X0 $.i 7.h.<XJXP E ,XJXJXk.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` &.I.e.iXLX%.8X;.I f 6 z { 9.n.&.DXp.6 Z j.yX*.J.G.G QX<X6Xu.;.;X<.; HXu.;X6X6.;Xt.fXAXA.O._ .Xn 6._ BXs A.F.FX6.Z.Z.:X3 g g @ @ @.D <X6 /.8.I.F.}X<.5.e.A.O.O A <XtX7 3.w.{XA.[.1 +X5 F +XF FX0 F +X0X5 F F.x.XX1.X.nXp ;XcXcXN.n.l.L {X8X8XL.[ LXLXq.H + 8.,.Y.8 - /XPXP CXJ.0 `.^.$.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` `XM $XL.H.[ Y Y W f.!XC A mXw.,.gXp.T.DXc 1 EX* /.JXP.GXuXtXZ ~.;X&XtXyX6XyXZ.5 p p 6..XhXe.V.!XA.. f.8.!.PXXX8X& ~ H.`.R.Z.r.q g.j.j.s.D {.8.8 pX8XZXZ.E.E.5.OX8.f.O Q.q.2XcXc.0.( MX0X4.g L + KX0 + K F F.1 K.xX5 d I.u.D.DXcXzXc ;.L.,.Y.a.8.[.H., L.H _ 8.HXq MXq.,XNXX zXJXPXPXzXPXV 3 ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` r., l l.H.[X;.[X0.V |.a <.< 6.,X4X4X4 :.g.F z mX<.GX6XyXy.A m.AXt.A.5.5.5.5.A.AXy._Xt (XG.N ( | 9XAXh fXC A z.8 6.! p Q >X-.`.R.r j cX@.sX@ qX8.o.E.A.'.eX8XU < A.fXU QX7X=X3X3.2 D R.N 7 e e 7XXXhXh q a.K.MX; 8X4.D.D.u.u.DXcXcXc ;.L., #.M.!.8 MX; LX;X0.L F.HX0X5Xq +X0 8.@XkXJXJ - }XP.b ` ` `.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` rXL.1.X +.XX#.H 8 f f.V 6 p.] R 9 # LX0.( z.<.G Q.]X&XZ.A.A.A.AX&XyXZ.A.AXyXUXZ p.E p A aXGXh..XAXAXh. .  |Xh q 9.KXf.! z i <.'.;.R.:X$X*.q 3X@XNXK.o.e.E.5.E.EX8.F AXZ uX> } DX=X3 D i.= Z.SX=.=.|X>X>X>X>X>X>X>.|X=.SXc.0.6./XcXcXc.~.,.( # 9.M.O lX; W Y.[ _Xq.1X0.g K.HXqXq.g.~.~ A. .}.}.+ g.U.PXB ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` `.b.g FXF F F +.x W.[.[.M f 9...fXh.N RXOX<.|XkXD (.'XZXU ~X& ~.A ~XZXt.AXZ.AXU.AXZ.5.A p.f.fX>. Xe X. XwXA | qXe s.f.fXeXh.(.| 6.V |.F B.`.R.R.R b.z.u.sXw.EX8XU.EX8.!.FXZ XX>X>X> [ D.=.=.SX3X3.SX=.6XC.V | | |Xh.|.SX3.S.2.3Xd 1.2.3 Z eXf.I W $.a fX8 #.M M $X0 MXq.H K _.1 KX5Xq _X0.H.l 7 u - E -XX.}.^ `.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` I _ F.X.X F.H.[.oX% $.K..Xf q.NXeXeXO.N.'.<.P m ~.'XZXZXuX&XZXZX<X&XtXUX<.'XZ mXZ m <.' z AX, R.N R a.N q.N q sXh aXA q.V . {.K.Y 9XA B.h u.`.RX- o.+ 0.9.nX8 <XZ.F.o.EXyX<.< XX>.N RXV D.SX3X3X3X3.S { W.M.M $ f.6XcXcXc , 7XiXK 7XB.zXs z z. .! W.a.a.IX; 8X; W.[ MX0XqXL K _ _ F KX5 +.g.~XNXw.<X> -.}.+.W.l.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` &XL l FX1.X + F.M.Y.C.V mXh qXh z mX>.'.f u u.JXGXuXZX& Q Q.' u u.]X<.J.G -Xk.G.PXD CXD ..fXG.fXhX,.NX> X R.N.  .Xw a |XCXhXCXD q A A.BXn.{ 7 /X6 ~XD / 3 &.j 6 9 ( W.[.a | 6 6XGXO.V.MXf s 7.SX3X3X3.S.3XV.NXh | f #./XcXc.L.,.( _.Y.lXw.M l.! . C (.!.!.F f.K.MX0X;X; 8.[X0.[.HXF.1 F + +.x.x + _Xq { u [XJXbXiXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` `.$.xXLX0XqX5.H.H.H 5 $.V. .< zXhXh R.<Xn X.'.<Xt < p.'.< ~.;.'.JXJ.}.h 3.{ 3 =X7X7 =.3 ZXd.P [ }XeXOXe X R R R s a R.B {.N XXO.| R.f 9.CXw >.} 7XD f 6.Y.B EXz.9XwXiXb L.x hX5XL.[.f.. W f.K $.M./XcXc.UXcX3.=X>X>X>X> R qXb.6.K M $ M 5.[ WX%.i l.8 qXe XXG.F._.K.a f f #.M _., _X; K _X0.H F FX5.x F K ; ;.6 s.l.} e `XMXp.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` `.$ _ F.1X0.H +.X h FXL f |.fXG XXh R. XG m z.'XyX&.'.]X<.G ~XJ.z.=XB 7 DXs 7 i -Xk.h = 1 ZX=X=.= D D D [XVX> .Xh.NX>Xh.N aXe {XeXV {.CXh 9Xf.{.}XbXiXA..Xf.C.N.P -.(XbXw _.x.xXF Y M.  | K fXCX; 9.(XcXcXcXzXc.~ WXf.YXh.NX>X,X>XAXf.K f f 9.iX%X%X%X%.a sXA.fXn.e. .I |.( a.M #.( #.H 8.nX0Xq KX5X5X5 +XF.g :X4 _X; XXJ e.P.n.P N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` NX5X#XF FXq.x F.X + +XL.KXCXh.<.<.G.< <XG ~XtXZX8.GX<Xt.;.PX<.U g.k % N ` ` ` ` ` x gXzXkXd i i.=.=.3.= e D CX> 2XX A aXe a.N.N q RXeXhXC.N q /.} e.NXA | a.C | [.= eXi #Xq.x.HXFX;XL..XC $ #.V.K L #./ ;XcXcXc.g $X; 8X; _XfXCXC.  }XVXkXsXdXkXnXn A.8.8.BXA A A.O.O...KXKXC 6.VXK 9.IX0.( # W.[.g L +.x.xXF +XF.x :.~.Y.fXb.lXVXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` `.$XqX%.x F.[X5XLX&X6.`._ qXhXn.<.; mX>X,XnXZ pXU.< uX& ~.G Q.J N ` ` ` ` ` ` ` ` ` ` ` `Xl gXN CXd.= D } i.z C.=.= [XX.NXG |XO ..| RXCXh s.NXC.` = eXw | a.Y.Y qXX.S.=.,., _ F.H.1 FXFXf 9Xf.MX0XCXfX0 f.Y.nXNXc.L.gX0 9.( L.VXf 8.K |XwXKXi.6.,.Y 8 f.aX,.PXV.  A.O._ a.BXK s f a { {.VXf.(.(.KX0.,., # MX5 _ FX5.X :.u I.g 8.B iXV.b.$.L.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` k <.;.RX8 $.x.F.5 H.RX-.|.| XXZ p <.N X u.5XUX6XtX& ~ ~XD ~.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` N.$ e uX>XV D.=.3 i } e.| zXnXi.P X...NX> a.C u.` CXC aXhXhXhXh { eX= D RXF.x hXqXLXLX0X;Xf 9Xf 9.V.V $.M f.(.L.n.6.6.,.lXb.l L 9.MX0.(Xw.@.L 7.(X; # LX;.(.(XiXs.z C.O < s 7Xi..XwXiXK f.V.(XK a.M.(.L., M L.~X4 +.XX4XFXF.XX4.g.IXKXDXbXb.W ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` k m.;.R.R f.I.F.F.F.A.e [ e [.< pX,. X,XG u.`.:.; ~ ~.G -XV ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XMXz.JXJ -.|X> C i [ [ 2 ZXkXhXn |.NXn.C.7 /XhXe.BXCXh.NXh.@.U.U 7 9 F.HXqXF.[X;.MXLX5.K a a # #.VX;.(Xb.L.n./.6.l.LXb {.VX;Xf.V.Y 9XX.l eXwXwXi L.,.l.l.l.@ iXd.< p i.@.B R i e R R {.|XA #.Y {XbXK LX;.L.L LX5 IX4.x d.u.D I + A.l.|Xs.+ ` ` `Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` `.+.J.. 6._.! AX8X8 YX#.X 7.= iXOXnX>X, X.<.`.:.:X-.J ~ .XyXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl.v e z u zX>.| DX= [.N ..f qXG 6.J.Z.<. Xf A..XA 9XX e Z.@.,.x 8XLX; FX; $ fX;Xf 8 aXhXA.MXA.V.n./.0.W./.6Xb.lX0XC.C.M.. 2.l L q.(XV i ZX=.~.6.(XK.6 7XK 2Xk.G uX> } i.|X>..XK 2 2.NXA {Xb {.Y.K f.l./X4X0.L.gXF :Xp : dX#.X M a.P.6 NXx k.z ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` N i.L I :XK.|.'X8.H +.(.= DXk XX>X>X>.G.R.:.:.: E Q.' } ~XM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM k u u C i }X>X>XG }.f.O u.Z EXe.fXn. .! 6Xe.6 6.Y F.1.1.1 + $XLX; +Xf 9 |X;X0 a A 9 |.C {XB ,XB.6.n.6XKXf 9 |.K # 2XX {.C } D.P 1.z.6Xi.YX% {XbXw 6 2 C.JXD.@ i 2.N } i }X>Xh s s.| RXh a |XiXb.M 8.g.~X0X4 IX4.*X1 I :.XX; s 1 E > EXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` `.s ;.~.6 D [ R < z i [ C }XG XX>X>.J.:.:.:X$.: EXP.P.' i ` ` ` ` ` ` ` ` ` ` ` `XM N ` ` ` ` ` ` ` ` ` ` ` ` ` ` 3.`.].'X> CX>XGXGXD >.r.R.f z A.B 6._ 9. .I.*.X h.1.HXLXF.[ $ $X0 8.V | f qXCXG |.K., s.6.~XBXBXb.L s.C.Y #XA aXi iXK {.zXXXn >XkXD 6 l Y Y q 7.NXD X C.hX=.S i }.=.3 [X, R [ 2X>.N RXC 2 2 |.YXf.Y ; MX;.n : h IXp IX1.X _X<XJ.}.} c ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` `.TX:X3 Z i { aXe.<Xn .X>X>XD >.R.:.:X$X$X$.:XP.} 1 uXz ` ` ` ` ` ` ` ` ` N.DXp.~Xi.uXM ` ` ` ` ` ` ` ` ` ` ` g =.w.Z.r.R.`.R.;.. /X$ oXnXnXG.f.f._ p 6 #.1.*.x.* h.HXL.[Xq W.MXfX; | qXAXeXC |XhXA.MXh s./ ,XB 7XB.,XhXh.( [XB.0.0 7.6 , > u.].hXJ z.I.F Y.8 i B...B < mXH g.+ cX:.0 i i.=X= DX>.NXX.N sX>XOXhXhXK.(.KXf.L.n.x d I.*.*.*X1.X.I E E i ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` `.+.=.@.N. .N.N.NX> .X-.`.: ^X$X$.:X$X$.:X- = - Q N ` ` ` ` ` ` `XS 0Xp d & d I.l 6 p <.U ! ` ` ` ` ` ` ` c = - - /.R.r.R.7 n o >X> X.N XX,.f <.E.I.H.H F.XXq hX0.H.i.H fXf a 8 L.Y.f.N f 9 R R 9 aXhXBXN.6 2.@Xi. .| 2./ , Z.UX=Xs.z - ~ m ~.J.G <X8 l.FXs.z < A.C p c ` ` ` ` ` ` x.T.k.+ k.UX=.= [.NXXX>.N RXeXh 9Xi.YX;.g I h d : :.* h K.J.W.&.+XP.& ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` `XM.W.NX>X>XD.J.`.r O ^X$X$X$X$.:X$.:.: QXd u k ` ` ` ` ` ` `.m 0.j &X@.j : ;.n..X&.J =X7 c.^ ` ` ` `.^ =XJ.GX< ~XZ.'.<X<.G C X X (X,.< > -.O.[.IXq K.H.xXL.x.1X5 MX% $X;Xh 9XA 9XC ..f.V.CXe q.(.6XB.@ {.| 7 7Xb i i Z DXG.0.0Xd Z.h Q.}X7.{.{.G m 6Xn.PXsXn p.O.E ~.b ` ` ` ` ` ` ` ` ` ` ` ` % g.+.U.= [.NX>.N R.N.YXf 9., MX4 :.*.*.*X#.H ; 3 E o.v ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` `.^.%.y.yX$ ^ OX* OX$ OX$X$X$.:X$.:.y.J -.]XM ` ` ` ` `.m.m.m.mXS.sXzXBXi {XCXe / BX7.wXZ DXM ` ` `.k.}.}.' H ~X&Xy.<.; E.{ -.G u u z . { K.I.C L + 8X#Xq _.1XLXq.I f $XA q RXAXf.N.f A.Y a. .|.6 i.| 2.6 1 Z 1 , 1.2.z.{.h.3.{ 3 3 ZX7.2.2.2X= 1.h.G >XD.. 6 p pXt ..b ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XlXM 4 k D }Xh.NXh a |.K #.,XLXF d h.X F / E o = ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` `.T.% j.p G.Q.q 4.%.qX$.%.:.:.:X$.R.P.J.W ` ` ` ` ` ` ` ` ` ` ` ` g./ D , k -.w jX7X7 /X-X-.p.+.k.U.{.J HX& ~.;X& m u E EX7X= Z 1Xd X A 6.8.B.YX5.K dXF 8.H MXL _.I.a.! R.NXhXh.. z (. XhXOXX 7XB.=.=XB Z.3.2.S 3 - e.{.{ 1 =X7 3.S.2X3X3Xv `XS 4Xd QX<Xn mXUXZXtXZ a.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XS.kXzXB [X>X> X a.! f 8X; +XFXF FX<.7 EXM ` `.& ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` `.bXg GX:.Q.q.t j.%.y j.:X$.:X$.`.h.< % ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g 3 j jX7 j j.7.7.%.w.w.w QX-.; /.;Xt.< k.U =.2 Z.SX3X3Xd ..B.aXA $.[.Y.K.XX;X5XL Y.i.H.!.8 9XO.NXe {XnXO.N aXCXOX,XK i e.=.0.2 1.2 1 3 1 3X7.PX=.2 [ Z.SX3Xv ` ` ` ` NXz.J ~XUXZXt.A.E.eXw.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XMXz.@ }X> {.. f.OX8XLXq.x.H.O.JXM x.p.3 ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ).#.) V.% O.%.Q.y.y.yX$.:X$ b E.' k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xv.t j j.w.w.7.7.wX*.7X- / /X6 ~.' g ` %.3.3 Z.SX3X3X=Xh.C.K.V.aX%.I.(X5 LX#.X M.i.i.I 6 < 6.NXO.N R.NXOX> (.NX> a a C.=XcX7X7 ZX=.2.3X7.2X7.S i .X= c x ` ` ` ` ` ` `.kXJX6 HX6.A.5X%.1XL.LXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XS.k.WX>.NXe.C 6X%.I M.1Xq K.~X* n o N ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` `Xv G x.qX$X$ G OX$X$X$X$ ^ =XJ.P.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xx 1 /.w j.w E / HX- /X6Xt.' g ` ` `.+.= [ ZX3.S.S i CXV C. X% $XwX;X;XLX#.i.[X% l._Xy < 9X>XO.N qX> X.N a.N.N 2Xs.3.S.SX3.2X7X3X7.SX3 Z [.|.0Xj ` ` ` ` ` ` ` ` ` N.J / H HX&.5.X h.x 5.W ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM k iXeXO.K 6.8 YXq 8.8.Z.r.r r ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` x.Q `.)X$.:.q.%X$X$X$X$ b D u.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^.2 E.;.;.; Q Q.w /.;XD g ` ` ` ` `.W } i.SX3.SX= zXV.P.P.!.i {Xw #.i + + MX% l.[XZXZ.NXhX>X>Xh R [ [XK.| i.3.S.2.S.2X3X3.SX3X3 Z.= }XzXv ` ` ` ` ` ` ` ` ` ` ` `XB.]X< ~Xu.e F.x.*XqX8.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` N kX> } X 6 W l W.[XU.y.r g ` ` yXM ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` `XSXg ! t.q.q.%.q.yX$X$ O - i ,XS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ kXuXu.; QXP.w Q >.b ` ` ` ` ` `Xl.WX>.|X=.S.S =.G C.P.B 8XKXw # 5XL.H.H Y.o.O p.'.NXhX> XX>.|.| [.|.@X=.SX3X3X3X3X3.SX3X3X3.0.$Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` gXy.5.5.E.e.8 l.i lX8 g ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` %.U.N. Xn.O.F.I $._ Q.nXMX X$.+ ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` !X  `.Q.#.q.%.%X$ ^.'X>Xs.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.vXuXuXP j = >.b ` ` ` ` ` ` ` `Xl.WX> }.0X3.S ZXd [.|X,.  2.[ W.HXL 5Xq.F } m uX,.N 2 [ D.=.= D [ iXB ZX=X3X3X3X3X3X3 cXv ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^X&Xy.E.E u =X8.E.E.A.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g 7 i X.O <.F $ f 6.C =X$X= ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xv ` c c.p j c ^ n s. .v ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b ,.w Q ,.b ` ` ` ` ` ` ` ` ` `XlXz [ D.S.S.2 3 1.z 1 C C W.[.i Y Y 5.C 7 -.'X> } C.| [ }XX }XV D.=.=.=.3X=.2 3 3 /.& ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` kX&.E.eXU =X<.5Xy.P ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` N.+ DX, iXn A.O.F.a ~ ~XP.+ 4 cXB r ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.v k.W.W.n.7.G.BXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM ,.3X3X3X=.zX7Xs z.O.o 5X% M.i.i.YXNXd ~X> } }X>X>XD C.P - -.G Q / HX-.7X6X6 k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NX&.AX8.o.~ B.E.A k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` % kX=.@ R Z.fXV.P < D 1 ZX3 c ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g.xX#XF _.Y.N.WXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl.$XB.3.3.= i > z.O l 5.o 5X;X% W.6 BXt k g.$.$.kXxXM.3XuXuX6 H HX6X6X6Xu e.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` e.E.o l.6.n M.e.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b.+ i.S e.zX3.zX3X3.S c ) ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NX0.*.*.KXXXzXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` r.+XBXVXV >.< p._.F.o # l l.CXB.]XM ` ` ` ` `.b -XuXuX6X6XuXuXuXu.J.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+Xy.e {.l YX%.e.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XS.k.# k.S.S c cXv ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.$X5 9./.k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NXM r./.'.5X8._ 8 l.i l 2 6 g ` ` ` ` ` k -X6Xu ~.;XuXuXu.J.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM ~.{X=.n.1X%.eXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` N.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl./X&.e.E l M FXL.Y.e.+ ` ` ` ` `.|XdX,.'XD.J u u k N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^X7X7 Z.~X4 5.oXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^XB.5.F 5XF.*.X f.o.W ` ` ` ` ` DXD D > D >XD.PXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^.w.hXKXpX4 Y.o.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ;.i.i.1X#.xXF $.o.G ` ` ` ` `.= } Z z Z DXDXVXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X .w u. .~X0Xq l k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.$.i Y.[Xq + + 8.a.E , ` ` ` ` `.2 [X=Xd.3.S ZXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 1XU p B.6 L Y.iXb ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.k ;.[Xq.1.iX;.i._ p.e.E.+ ` ` ` ` `.p.=.SX7.P.z ,Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.kX&.EX8.iX0Xq YX%. .b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X  e l.1.XXF.H.C.f.FXU.AXy , ` ` ` ` ` `.pXP i 3.y.yXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^.GXy.E l.i M.[Xq 5X8.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` k 2.Y.X hX1Xq.8 1 mXt QXd g ` ` ` ` ` ` `.).p n o.% O ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xz.A p.F l.i M + Y lX8Xz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+ 6 YX5.*X1 5.F m.{ Q.U.k ` ` ` ` ` ` ` ` `.cX:X$.p.).p ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NXu.A.5 l Y.xX1 +.H 5X8.W ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 1 l.1.*.xX; >.}.UX XS ` ` ` ` ` ` ` ` ` ` ` ` tX$X:.c.p ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XMXy.5 p.o Y.*.*.x.1XL l > ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl k.<.iXL.X.i 3X7Xx ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^X$ y ` G ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xz /.A p.[X5X#X1.XXLX%.o [ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl.gX0 B.i F.[.GX3.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.q.c `.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.$ lX8 ~.5X8.oXL.x.i.iX8X8.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.D IX0., + F._.t.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` y.c ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xi 8 IXtX&.E.E lX%.F.E.A e ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xp., :X4 :X5.!.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b.B.6.l.IXF.8.[.*.*X0 q.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xz.g I.~ d.gXX N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b.|./ 6 8 :.V.g.D d.g ; ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.D.~.n ; ;.l k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NXB 7.V.,.u |.~ d.X., k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` gXN.0.(XNXB.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `./X, aXN.gXA./ ;.g.Y g ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` gXi 1.s.D N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.k 1XiXN ; 7 ,XcXcXBXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.T.sXz.s 0 ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` y.q ,.0XcXd {.L.0XM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xv.s.j.sXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X .p [Xb.6.w.$.D r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.&.s.^.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.# y.+./ 7 k.k.sXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.s ` x ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` VXa.#.s.s.m V.s ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.T ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.&XS V.s.s `X .s ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.c.j 0 `Xv 0 ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X  ) ` `.^ y ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.TXv ` ` `.& ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xg ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `",
+" ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` x ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `"
+};
diff --git a/win/Qt/qpe-nethack.control b/win/Qt/qpe-nethack.control
new file mode 100644 (file)
index 0000000..46ad8c3
--- /dev/null
@@ -0,0 +1,9 @@
+Files: bin/nethack apps/Games/nethack.desktop games/lib/nethackdir/[a-r]* games/lib/nethackdir/[t-z]* games/lib/nethackdir/save games/lib/nethackdir/s*.* games/lib/nethackdir/[A-Z0-9]*
+Priority: optional
+Section: qpe/games
+Maintainer: Warwick Allison <warwick@trolltech.com>
+Architecture: arm
+Version: 3.4.0-1
+Depends: qpe-base ($QPE_VERSION)
+Description: NetHack - The Dungeon Game
+ Graphical version of NetHack for Qtopia
diff --git a/win/Qt/qt_clust.cpp b/win/Qt/qt_clust.cpp
new file mode 100644 (file)
index 0000000..e5952c5
--- /dev/null
@@ -0,0 +1,168 @@
+/*     SCCS Id: @(#)qt_clust.cpp       3.4     1999/11/19      */
+/* Copyright (c) Warwick Allison, 1999. */
+/* NetHack may be freely redistributed.  See license for details. */
+#include "qt_clust.h"
+
+static
+void include(QRect& r, const QRect& rect)
+{
+       if (rect.left()<r.left()) {
+                       r.setLeft(rect.left());
+       }
+       if (rect.right()>r.right()) {
+                       r.setRight(rect.right());
+       }
+       if (rect.top()<r.top()) {
+                       r.setTop(rect.top());
+       }
+       if (rect.bottom()>r.bottom()) {
+                       r.setBottom(rect.bottom());
+       }
+}
+
+/*
+A Clusterizer groups rectangles (QRects) into non-overlapping rectangles
+by a merging heuristic.
+*/
+Clusterizer::Clusterizer(int maxclusters) :
+       cluster(new QRect[maxclusters]),
+       count(0),
+       max(maxclusters)
+{ }
+
+Clusterizer::~Clusterizer()
+{
+       delete [] cluster;
+}
+
+void Clusterizer::clear()
+{
+       count=0;
+}
+
+void Clusterizer::add(int x, int y)
+{
+       add(QRect(x,y,1,1));
+}
+
+void Clusterizer::add(int x, int y, int w, int h)
+{
+       add(QRect(x,y,w,h));
+}
+
+void Clusterizer::add(const QRect& rect)
+{
+       QRect biggerrect(rect.x()-1,rect.y()-1,rect.width()+2,rect.height()+2);
+
+       //assert(rect.width()>0 && rect.height()>0);
+
+       int cursor;
+
+       for (cursor=0; cursor<count; cursor++) {
+               if (cluster[cursor].contains(rect)) {
+                       // Wholly contained already.
+                       return;
+               }
+       }
+
+       int lowestcost=9999999;
+       int cheapest=-1;
+       for (cursor=0; cursor<count; cursor++) {
+               if (cluster[cursor].intersects(biggerrect)) {
+                       QRect larger=cluster[cursor];
+                       include(larger,rect);
+                       int cost=larger.width()*larger.height()
+                                       - cluster[cursor].width()*cluster[cursor].height();
+
+                       if (cost < lowestcost) {
+                               bool bad=FALSE;
+                               for (int c=0; c<count && !bad; c++) {
+                                       bad=cluster[c].intersects(larger) && c!=cursor;
+                               }
+                               if (!bad) {
+                                       cheapest=cursor;
+                                       lowestcost=cost;
+                               }
+                       }
+               }
+       }
+       if (cheapest>=0) {
+               include(cluster[cheapest],rect);
+               return;
+       }
+
+       if (count < max) {
+               cluster[count++]=rect;
+               return;
+       }
+
+       // Do cheapest of:
+       //      add to closest cluster
+       //      do cheapest cluster merge, add to new cluster
+
+       lowestcost=9999999;
+       cheapest=-1;
+       for (cursor=0; cursor<count; cursor++) {
+               QRect larger=cluster[cursor];
+               include(larger,rect);
+               int cost=larger.width()*larger.height()
+                               - cluster[cursor].width()*cluster[cursor].height();
+               if (cost < lowestcost) {
+                       bool bad=FALSE;
+                       for (int c=0; c<count && !bad; c++) {
+                               bad=cluster[c].intersects(larger) && c!=cursor;
+                       }
+                       if (!bad) {
+                               cheapest=cursor;
+                               lowestcost=cost;
+                       }
+               }
+       }
+
+       // XXX could make an heuristic guess as to whether we
+       // XXX need to bother looking for a cheap merge.
+
+       int cheapestmerge1=-1;
+       int cheapestmerge2=-1;
+
+       for (int merge1=0; merge1<count; merge1++) {
+               for (int merge2=0; merge2<count; merge2++) {
+                       if (merge1!=merge2) {
+                               QRect larger=cluster[merge1];
+                               include(larger,cluster[merge2]);
+                               int cost=larger.width()*larger.height()
+                                       - cluster[merge1].width()*cluster[merge1].height()
+                                       - cluster[merge2].width()*cluster[merge2].height();
+                               if (cost < lowestcost) {
+                                       bool bad=FALSE;
+                                       for (int c=0; c<count && !bad; c++) {
+                                               bad=cluster[c].intersects(larger) && c!=cursor;
+                                       }
+                                       if (!bad) {
+                                               cheapestmerge1=merge1;
+                                               cheapestmerge2=merge2;
+                                               lowestcost=cost;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if (cheapestmerge1>=0) {
+               include(cluster[cheapestmerge1],cluster[cheapestmerge2]);
+               cluster[cheapestmerge2]=cluster[count--];
+       } else {
+               // if (!cheapest) debugRectangles(rect);
+               include(cluster[cheapest],rect);
+       }
+
+       // NB: clusters do not intersect (or intersection will
+       //       overwrite).  This is a result of the above algorithm,
+       //       given the assumption that (x,y) are ordered topleft
+       //       to bottomright.
+}
+
+const QRect& Clusterizer::operator[](int i)
+{
+       return cluster[i];
+}
diff --git a/win/Qt/qt_win.cpp b/win/Qt/qt_win.cpp
new file mode 100644 (file)
index 0000000..46eb66e
--- /dev/null
@@ -0,0 +1,5264 @@
+//     SCCS Id: @(#)qt_win.cpp 3.4     1999/11/19
+// Copyright (c) Warwick Allison, 1999.
+// NetHack may be freely redistributed.  See license for details.
+
+// Qt Binding for NetHack 3.4
+//
+// Copyright (C) 1996-2001 by Warwick W. Allison (warwick@troll.no)
+// 
+// Contributors:
+//    Michael Hohmuth <hohmuth@inf.tu-dresden.de>
+//       - Userid control
+//    Svante Gerhard <svante@algonet.se>
+//       - .nethackrc tile and font size settings
+//    Dirk Schoenberger <schoenberger@signsoft.com>
+//       - KDE support
+//       - SlashEm support
+//    and many others for bug reports.
+// 
+// Unfortunately, this doesn't use Qt as well as I would like,
+// primarily because NetHack is fundamentally a getkey-type program
+// rather than being event driven (hence the ugly key and click buffer)
+// and also because this is my first major application of Qt.  
+// 
+// The problem of NetHack's getkey requirement is solved by intercepting
+// key events by overiding QApplicion::notify(...), and putting them in
+// a buffer.  Mouse clicks on the map window are treated with a similar
+// buffer.  When the NetHack engine calls for a key, one is taken from
+// the buffer, or if that is empty, QApplication::enter_loop() is called.
+// Whenever keys or clicks go into the buffer, QApplication::exit_loop()
+// is called.
+//
+// Another problem is that some NetHack players are decade-long players who
+// demand complete keyboard control (while Qt and X11 conspire to make this
+// difficult by having widget-based focus rather than application based -
+// a good thing in general).  This problem is solved by again using the key
+// event buffer.
+//
+// Out of all this hackery comes a silver lining however, as macros for
+// the super-expert and menus for the ultra-newbie are also made possible
+// by the key event buffer.
+//
+
+extern "C" {
+
+// This includes all the definitions we need from the NetHack main
+// engine.  We pretend MSC is a STDC compiler, because C++ is close
+// enough, and we undefine NetHack macros which conflict with Qt
+// identifiers.
+
+#define alloc hide_alloc // avoid treading on STL symbol
+#define lock hide_lock // avoid treading on STL symbol
+#ifdef _MSC_VER
+#define NHSTDC
+#endif
+#include "hack.h"
+#include "func_tab.h"
+#include "dlb.h"
+#include "patchlevel.h"
+#include "tile2x11.h"
+#undef Invisible
+#undef Warning
+#undef red
+#undef green
+#undef blue
+#undef Black
+#undef curs
+#undef TRUE
+#undef FALSE
+#undef min
+#undef max
+#undef alloc
+#undef lock
+#undef yn
+
+}
+
+#include "qt_win.h"
+#include <qregexp.h>
+#include <qpainter.h>
+#include <qdir.h>
+#include <qbitmap.h>
+#include <qkeycode.h>
+#include <qmenubar.h>
+#include <qpopupmenu.h>
+#include <qlayout.h>
+#include <qheader.h>
+#include <qradiobutton.h>
+#include <qtoolbar.h>
+#include <qtoolbutton.h>
+#include <qcombobox.h>
+#include <qvbox.h>
+#include <qdragobject.h>
+#include <qtextbrowser.h>
+#include <qhbox.h>
+#include <qsignalmapper.h>
+//#include <qgrid.h>
+//#include <qlabelled.h>
+
+#include <ctype.h>
+
+#include "qt_clust.h"
+#include "qt_xpms.h"
+
+#include <dirent.h>
+#ifdef Q_WS_MACX
+#  include <sys/malloc.h>
+#else
+#  include <malloc.h>
+#endif
+
+#ifdef _WS_X11_
+// For userid control
+#include <unistd.h>
+#endif
+
+// Some distributors released Qt 2.1.0beta4
+#if QT_VERSION < 220
+# define nh_WX11BypassWM 0x01000000
+#else
+# define nh_WX11BypassWM WX11BypassWM
+#endif
+
+#ifdef USER_SOUNDS
+# if QT_VERSION < 220
+#  undef USER_SOUNDS
+# else
+#  include <qsound.h>
+# endif
+#endif
+
+
+#ifdef USER_SOUNDS
+extern "C" void play_sound_for_message(const char* str);
+#endif
+
+// Warwick prefers it this way...
+#define QT_CHOOSE_RACE_FIRST
+
+static const char nh_attribution[] = "<center><big>NetHack</big>"
+       "<br><small>by the NetHack DevTeam</small></center>";
+
+static QString
+aboutMsg()
+{
+    QString msg;
+    msg.sprintf(
+    "Qt NetHack is a version of NetHack built\n"
+#ifdef KDE
+    "using KDE and the Qt GUI toolkit.\n"
+#else
+    "using the Qt GUI toolkit.\n"
+#endif
+    "This is version %d.%d.%d\n\n"
+    "Homepage:\n     http://trolls.troll.no/warwick/nethack/\n\n"
+#ifdef KDE
+         "KDE:\n     http://www.kde.org\n"
+#endif
+         "Qt:\n     http://www.troll.no",
+       VERSION_MAJOR,
+       VERSION_MINOR,
+       PATCHLEVEL);
+    return msg;
+}
+
+static void
+centerOnMain( QWidget* w )
+{
+    QWidget* m = qApp->mainWidget();
+    if (!m) m = qApp->desktop();
+    QPoint p = m->mapToGlobal(QPoint(0,0));
+    w->move( p.x() + m->width()/2  - w->width()/2,
+              p.y() + m->height()/2 - w->height()/2 );
+}
+
+NetHackQtLineEdit::NetHackQtLineEdit() :
+    QLineEdit(0)
+{
+}
+
+NetHackQtLineEdit::NetHackQtLineEdit(QWidget* parent, const char* name) :
+    QLineEdit(parent,name)
+{
+}
+
+void NetHackQtLineEdit::fakeEvent(int key, int ascii, int state)
+{
+    QKeyEvent fake(QEvent::KeyPress,key,ascii,state);
+    keyPressEvent(&fake);
+}
+
+extern "C" {
+/* Used by tile/font-size patch below and in ../../src/files.c */
+char *qt_tilewidth=NULL;
+char *qt_tileheight=NULL;
+char *qt_fontsize=NULL;
+#if defined(QWS)
+int qt_compact_mode = 1;
+#else
+int qt_compact_mode = 0;
+#endif
+extern const char *enc_stat[]; /* from botl.c */
+extern const char *hu_stat[]; /* from eat.c */
+extern const char *killed_by_prefix[];
+extern int total_tiles_used; // from tile.c
+extern short glyph2tile[]; // from tile.c
+}
+
+static int tilefile_tile_W=16;
+static int tilefile_tile_H=16;
+
+#define TILEWMIN 1
+#define TILEHMIN 1
+
+
+/* XPM */
+static const char * nh_icon[] = {
+"40 40 6 1",
+"      s None c none",
+".     c #ffffff",
+"X     c #dadab6",
+"o     c #6c91b6",
+"O     c #476c6c",
+"+     c #000000",
+"                                        ",
+"                                        ",
+"                                        ",
+"        .      .X..XX.XX      X         ",
+"        ..   .....X.XXXXXX   XX         ",
+"        ... ....X..XX.XXXXX XXX         ",
+"   ..   ..........X.XXXXXXXXXXX   XX    ",
+"   .... ........X..XX.XXXXXXXXX XXXX    ",
+"   .... ..........X.XXXXXXXXXXX XXXX    ",
+"   ooOOO..ooooooOooOOoOOOOOOOXX+++OO++  ",
+"   ooOOO..ooooooooOoOOOOOOOOOXX+++OO++  ",
+"   ....O..ooooooOooOOoOOOOOOOXX+XXXX++  ",
+"   ....O..ooooooooOoOOOOOOOOOXX+XXXX++  ",
+"   ..OOO..ooooooOooOOoOOOOOOOXX+++XX++  ",
+"    ++++..ooooooooOoOOOOOOOOOXX+++ +++  ",
+"     +++..ooooooOooOOoOOOOOOOXX+++  +   ",
+"      ++..ooooooooOoOOOOOOOOOXX+++      ",
+"        ..ooooooOooOOoOOOOOOOXX+++      ",
+"        ..ooooooooOoOOOOOOOOOXX+++      ",
+"        ..ooooooOooOOoOOOOOOOXX+++      ",
+"        ..ooooooooOoOOOOOOOOOXX+++      ",
+"         ..oooooOooOOoOOOOOOXX+++       ",
+"         ..oooooooOoOOOOOOOOXX+++       ",
+"          ..ooooOooOOoOOOOOXX+++        ",
+"          ..ooooooOoOOOOOOOXX++++       ",
+"        ..o..oooOooOOoOOOOXX+XX+++      ",
+"       ...o..oooooOoOOOOOXX++XXX++      ",
+"      ....OO..ooOooOOoOOXX+++XXXX++     ",
+"     ...oo..+..oooOoOOOXX++XXooXXX++    ",
+"    ...ooo..++..OooOOoXX+++XXooOXXX+    ",
+"   ..oooOOXX+++....XXXX++++XXOOoOOXX+   ",
+"   ..oooOOXX+++ ...XXX+++++XXOOooOXX++  ",
+"   ..oooOXXX+++  ..XX+++  +XXOOooOXX++  ",
+"   .....XXX++++             XXXXXXX++   ",
+"    ....XX++++              XXXXXXX+    ",
+"     ...XX+++                XXXXX++    ",
+"                                        ",
+"                                        ",
+"                                        ",
+"                                        "};
+/* XPM */
+static const char * nh_icon_small[] = {
+/* width height ncolors chars_per_pixel */
+"16 16 16 1",
+/* colors */
+"  c #587070",
+". c #D1D5C9",
+"X c #8B8C84",
+"o c #2A2A28",
+"O c #9AABA9",
+"+ c #6A8FB2",
+"@ c #C4CAC4",
+"# c #B6BEB6",
+"$ c None",
+"% c #54564E",
+"& c #476C6C",
+"* c #ADB2AB",
+"= c #ABABA2",
+"- c #5E8295",
+"; c #8B988F",
+": c #E8EAE7",
+/* pixels */
+"$$$$$$$$$$$$$$$$",
+"$$$.$#::.#==*$$$",
+"$.*:::::....#*=$",
+"$@#:..@#*==#;XX;",
+"$@O:+++- &&; X%X",
+"$#%.+++- &&;% oX",
+"$$o.++-- &&;%%X$",
+"$$$:++-- &&;%%$$",
+"$$$.O++- &&=o $$",
+"$$$=:++- & XoX$$",
+"$$*:@O--  ;%Xo$$",
+"$*:O#$+--;oOOX $",
+"$:+ =o::=oo=-;%X",
+"$::.%o$*;X;##@%$",
+"$$@# ;$$$$$=*;X$",
+"$$$$$$$$$$$$$$$$"
+};
+
+/* XPM */
+static const char * map_xpm[] = {
+"12 13 4 1",
+".     c None",
+"      c #000000000000",
+"X     c #0000B6DAFFFF",
+"o     c #69A69248B6DA",
+"           .",
+" XXXXX ooo  ",
+" XoooX o    ",
+" XoooX o o  ",
+" XoooX ooo  ",
+" XXoXX o    ",
+"  oooooXXX  ",
+" oo o oooX  ",
+"    o XooX  ",
+" oooo XooX  ",
+" o  o XXXX  ",
+"            ",
+".           "};
+/* XPM */
+static const char * msg_xpm[] = {
+"12 13 4 1",
+".     c None",
+"      c #FFFFFFFFFFFF",
+"X     c #69A69248B6DA",
+"o     c #000000000000",
+"           .",
+" XXX XXX X o",
+"           o",
+" XXXXX XX  o",
+"           o",
+" XX XXXXX  o",
+"           o",
+" XXXXXX    o",
+"           o",
+" XX XXX XX o",
+"           o",
+"           o",
+".ooooooooooo"};
+/* XPM */
+static const char * stat_xpm[] = {
+"12 13 5 1",
+"  c None",
+".     c #FFFF00000000",
+"X     c #000000000000",
+"o     c #FFFFFFFF0000",
+"O     c #69A6FFFF0000",
+"            ",
+"            ",
+"...         ",
+"...X        ",
+"...X    ... ",
+"oooX    oooX",
+"oooXooo oooX",
+"OOOXOOOXOOOX",
+"OOOXOOOXOOOX",
+"OOOXOOOXOOOX",
+"OOOXOOOXOOOX",
+"OOOXOOOXOOOX",
+" XXXXXXXXXXX"};
+/* XPM */
+static const char * info_xpm[] = {
+"12 13 4 1",
+"  c None",
+".     c #00000000FFFF",
+"X     c #FFFFFFFFFFFF",
+"o     c #000000000000",
+"    ...     ",
+"  .......   ",
+" ...XXX...  ",
+" .........o ",
+"...XXXX.... ",
+"....XXX....o",
+"....XXX....o",
+"....XXX....o",
+" ...XXX...oo",
+" ..XXXXX..o ",
+"  .......oo ",
+"   o...ooo  ",
+"     ooo    "};
+
+
+/* XPM */
+static const char * again_xpm[] = {
+"12 13 2 1",
+"      c None",
+".     c #000000000000",
+"    ..      ",
+"     ..     ",
+"   .....    ",
+" .......    ",
+"...  ..  .. ",
+"..  ..   .. ",
+"..        ..",
+"..        ..",
+"..        ..",
+" ..      .. ",
+" .......... ",
+"   ......   ",
+"            "};
+/* XPM */
+static const char * kick_xpm[] = {
+"12 13 3 1",
+"      c None",
+".     c #000000000000",
+"X     c #FFFF6DB60000",
+"            ",
+"            ",
+"   .  .  .  ",
+"  ...  .  . ",
+"   ...  .   ",
+"    ...  .  ",
+"     ...    ",
+"XXX   ...   ",
+"XXX.  ...   ",
+"XXX. ...    ",
+"XXX. ..     ",
+" ...        ",
+"            "};
+/* XPM */
+static const char * throw_xpm[] = {
+"12 13 3 1",
+"      c None",
+".     c #FFFF6DB60000",
+"X     c #000000000000",
+"            ",
+"            ",
+"            ",
+"            ",
+"....     X  ",
+"....X     X ",
+"....X XXXXXX",
+"....X     X ",
+" XXXX    X  ",
+"            ",
+"            ",
+"            ",
+"            "};
+/* XPM */
+static const char * fire_xpm[] = {
+"12 13 5 1",
+"      c None",
+".     c #B6DA45140000",
+"X     c #FFFFB6DA9658",
+"o     c #000000000000",
+"O     c #FFFF6DB60000",
+" .          ",
+" X.         ",
+" X .        ",
+" X .o       ",
+" X  .    o  ",
+" X  .o    o ",
+"OOOOOOOOoooo",
+" X  .o    o ",
+" X . o   o  ",
+" X .o       ",
+" X. o       ",
+" . o        ",
+"  o         "};
+/* XPM */
+static const char * get_xpm[] = {
+"12 13 3 1",
+"      c None",
+".     c #000000000000",
+"X     c #FFFF6DB60000",
+"            ",
+"     .      ",
+"    ...     ",
+"   . . .    ",
+"     .      ",
+"     .      ",
+"            ",
+"   XXXXX    ",
+"   XXXXX.   ",
+"   XXXXX.   ",
+"   XXXXX.   ",
+"    .....   ",
+"            "};
+/* XPM */
+static const char * drop_xpm[] = {
+"12 13 3 1",
+"      c None",
+".     c #FFFF6DB60000",
+"X     c #000000000000",
+"            ",
+"   .....    ",
+"   .....X   ",
+"   .....X   ",
+"   .....X   ",
+"    XXXXX   ",
+"            ",
+"      X     ",
+"      X     ",
+"    X X X   ",
+"     XXX    ",
+"      X     ",
+"            "};
+/* XPM */
+static const char * eat_xpm[] = {
+"12 13 4 1",
+"      c None",
+".     c #000000000000",
+"X     c #FFFFB6DA9658",
+"o     c #FFFF6DB60000",
+"  .X.  ..   ",
+"  .X.  ..   ",
+"  .X.  ..   ",
+"  .X.  ..   ",
+"  ...  ..   ",
+"   ..  ..   ",
+"   ..  ..   ",
+"   oo  oo   ",
+"   oo  oo   ",
+"   oo  oo   ",
+"   oo  oo   ",
+"   oo  oo   ",
+"   oo  oo   "};
+/* XPM */
+static const char * rest_xpm[] = {
+"12 13 2 1",
+"      c None",
+".     c #000000000000",
+"  .....     ",
+"     .      ",
+"    .       ",
+"   .    ....",
+"  .....   . ",
+"         .  ",
+"        ....",
+"            ",
+"     ....   ",
+"       .    ",
+"      .     ",
+"     ....   ",
+"            "};
+/* XPM */
+static const char * cast_a_xpm[] = {
+"12 13 3 1",
+"      c None",
+".     c #FFFF6DB60000",
+"X     c #000000000000",
+"    .       ",
+"    .       ",
+"   ..       ",
+"   ..       ",
+"  ..  .     ",
+"  ..  .     ",
+" ......     ",
+" .. ..  XX  ",
+"    .. X  X ",
+"   ..  X  X ",
+"   ..  XXXX ",
+"   .   X  X ",
+"   .   X  X "};
+/* XPM */
+static const char * cast_b_xpm[] = {
+"12 13 3 1",
+"      c None",
+".     c #FFFF6DB60000",
+"X     c #000000000000",
+"    .       ",
+"    .       ",
+"   ..       ",
+"   ..       ",
+"  ..  .     ",
+"  ..  .     ",
+" ......     ",
+" .. .. XXX  ",
+"    .. X  X ",
+"   ..  XXX  ",
+"   ..  X  X ",
+"   .   X  X ",
+"   .   XXX  "};
+/* XPM */
+static const char * cast_c_xpm[] = {
+"12 13 3 1",
+"      c None",
+".     c #FFFF6DB60000",
+"X     c #000000000000",
+"    .       ",
+"    .       ",
+"   ..       ",
+"   ..       ",
+"  ..  .     ",
+"  ..  .     ",
+" ......     ",
+" .. ..  XX  ",
+"    .. X  X ",
+"   ..  X    ",
+"   ..  X    ",
+"   .   X  X ",
+"   .    XX  "};
+
+NetHackQtSettings::NetHackQtSettings(int w, int h) :
+    tilewidth(TILEWMIN,64,1,this),
+    tileheight(TILEHMIN,64,1,this),
+    widthlbl(&tilewidth,"&Width:",this),
+    heightlbl(&tileheight,"&Height:",this),
+    whichsize("&Zoomed",this),
+    fontsize(this),
+    normal("times"),
+#ifdef WS_WIN
+    normalfixed("courier new"),
+#else
+    normalfixed("fixed"),
+#endif
+    large("times"),
+    theglyphs(0)
+
+{
+    int default_fontsize;
+
+    if (w<=300) {
+       // ~240x320
+       default_fontsize=4;
+       tilewidth.setValue(8);
+       tileheight.setValue(12);
+    } else if (w<=700) {
+       // ~640x480
+       default_fontsize=3;
+       tilewidth.setValue(8);
+       tileheight.setValue(14);
+    } else if (w<=900) {
+       // ~800x600
+       default_fontsize=3;
+       tilewidth.setValue(10);
+       tileheight.setValue(17);
+    } else if (w<=1100) {
+       // ~1024x768
+       default_fontsize=2;
+       tilewidth.setValue(12);
+       tileheight.setValue(22);
+    } else if (w<=1200) {
+       // ~1152x900
+       default_fontsize=1;
+       tilewidth.setValue(14);
+       tileheight.setValue(26);
+    } else {
+       // ~1280x1024 and larger
+       default_fontsize=0;
+       tilewidth.setValue(16);
+       tileheight.setValue(30);
+    }
+
+    // Tile/font sizes read from .nethackrc
+    if (qt_tilewidth != NULL) {
+       tilewidth.setValue(atoi(qt_tilewidth));
+       free(qt_tilewidth);
+    }
+    if (qt_tileheight != NULL) {
+       tileheight.setValue(atoi(qt_tileheight));
+       free(qt_tileheight);
+    }
+    if (qt_fontsize != NULL) {
+       switch (tolower(qt_fontsize[0])) {
+         case 'h': default_fontsize = 0; break;
+         case 'l': default_fontsize = 1; break;
+         case 'm': default_fontsize = 2; break;
+         case 's': default_fontsize = 3; break;
+         case 't': default_fontsize = 4; break;
+       }
+       free(qt_fontsize); 
+    }
+
+    theglyphs=new NetHackQtGlyphs();
+    resizeTiles();
+
+    connect(&tilewidth,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles()));
+    connect(&tileheight,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles()));
+    connect(&whichsize,SIGNAL(toggled(bool)),this,SLOT(setGlyphSize(bool)));
+
+    fontsize.insertItem("Huge");
+    fontsize.insertItem("Large");
+    fontsize.insertItem("Medium");
+    fontsize.insertItem("Small");
+    fontsize.insertItem("Tiny");
+    fontsize.setCurrentItem(default_fontsize);
+    connect(&fontsize,SIGNAL(activated(int)),this,SIGNAL(fontChanged()));
+
+    QGridLayout* grid = new QGridLayout(this, 5, 2, 8);
+    grid->addMultiCellWidget(&whichsize, 0, 0, 0, 1);
+    grid->addWidget(&tilewidth, 1, 1);  grid->addWidget(&widthlbl, 1, 0);
+    grid->addWidget(&tileheight, 2, 1); grid->addWidget(&heightlbl, 2, 0);
+    QLabel* flabel=new QLabel(&fontsize, "&Font:",this);
+    grid->addWidget(flabel, 3, 0); grid->addWidget(&fontsize, 3, 1);
+    QPushButton* dismiss=new QPushButton("Dismiss",this);
+    dismiss->setDefault(TRUE);
+    grid->addMultiCellWidget(dismiss, 4, 4, 0, 1);
+    grid->setRowStretch(4,0);
+    grid->setColStretch(1,1);
+    grid->setColStretch(2,2);
+    grid->activate();
+
+    connect(dismiss,SIGNAL(clicked()),this,SLOT(accept()));
+    resize(150,140);
+}
+
+NetHackQtGlyphs& NetHackQtSettings::glyphs()
+{
+    return *theglyphs;
+}
+
+void NetHackQtSettings::resizeTiles()
+{
+    int w = tilewidth.value();
+    int h = tileheight.value();
+
+    theglyphs->setSize(w,h);
+    emit tilesChanged();
+}
+
+void NetHackQtSettings::toggleGlyphSize()
+{
+    whichsize.toggle();
+}
+
+void NetHackQtSettings::setGlyphSize(bool which)
+{
+    QSize n = QSize(tilewidth.value(),tileheight.value());
+    if ( othersize.isValid() ) {
+       tilewidth.blockSignals(TRUE);
+       tileheight.blockSignals(TRUE);
+       tilewidth.setValue(othersize.width());
+       tileheight.setValue(othersize.height());
+       tileheight.blockSignals(FALSE);
+       tilewidth.blockSignals(FALSE);
+       resizeTiles();
+    }
+    othersize = n;
+}
+
+const QFont& NetHackQtSettings::normalFont()
+{
+    static int size[]={ 18, 14, 12, 10, 8 };
+    normal.setPointSize(size[fontsize.currentItem()]);
+    return normal;
+}
+
+const QFont& NetHackQtSettings::normalFixedFont()
+{
+    static int size[]={ 18, 14, 13, 10, 8 };
+    normalfixed.setPointSize(size[fontsize.currentItem()]);
+    return normalfixed;
+}
+
+const QFont& NetHackQtSettings::largeFont()
+{
+    static int size[]={ 24, 18, 14, 12, 10 };
+    large.setPointSize(size[fontsize.currentItem()]);
+    return large;
+}
+
+bool NetHackQtSettings::ynInMessages()
+{
+    return !qt_compact_mode;
+}
+
+
+NetHackQtSettings* qt_settings;
+
+
+
+NetHackQtKeyBuffer::NetHackQtKeyBuffer() :
+    in(0), out(0)
+{
+}
+
+bool NetHackQtKeyBuffer::Empty() const { return in==out; }
+bool NetHackQtKeyBuffer::Full() const { return (in+1)%maxkey==out; }
+
+void NetHackQtKeyBuffer::Put(int k, int a, int state)
+{
+    if ( Full() ) return;      // Safety
+    key[in]=k;
+    ascii[in]=a;
+    in=(in+1)%maxkey;
+}
+
+void NetHackQtKeyBuffer::Put(char a)
+{
+    Put(0,a,0);
+}
+
+void NetHackQtKeyBuffer::Put(const char* str)
+{
+    while (*str) Put(*str++);
+}
+
+int NetHackQtKeyBuffer::GetKey()
+{
+    if ( Empty() ) return 0;
+    int r=TopKey();
+    out=(out+1)%maxkey;
+    return r;
+}
+
+int NetHackQtKeyBuffer::GetAscii()
+{
+    if ( Empty() ) return 0; // Safety
+    int r=TopAscii();
+    out=(out+1)%maxkey;
+    return r;
+}
+
+int NetHackQtKeyBuffer::GetState()
+{
+    if ( Empty() ) return 0;
+    int r=TopState();
+    out=(out+1)%maxkey;
+    return r;
+}
+
+int NetHackQtKeyBuffer::TopKey() const
+{
+    if ( Empty() ) return 0;
+    return key[out];
+}
+
+int NetHackQtKeyBuffer::TopAscii() const
+{
+    if ( Empty() ) return 0;
+    return ascii[out];
+}
+
+int NetHackQtKeyBuffer::TopState() const
+{
+    if ( Empty() ) return 0;
+    return state[out];
+}
+
+
+NetHackQtClickBuffer::NetHackQtClickBuffer() :
+    in(0), out(0)
+{
+}
+
+bool NetHackQtClickBuffer::Empty() const { return in==out; }
+bool NetHackQtClickBuffer::Full() const { return (in+1)%maxclick==out; }
+
+void NetHackQtClickBuffer::Put(int x, int y, int mod)
+{
+    click[in].x=x;
+    click[in].y=y;
+    click[in].mod=mod;
+    in=(in+1)%maxclick;
+}
+
+int NetHackQtClickBuffer::NextX() const { return click[out].x; }
+int NetHackQtClickBuffer::NextY() const { return click[out].y; }
+int NetHackQtClickBuffer::NextMod() const { return click[out].mod; }
+
+void NetHackQtClickBuffer::Get()
+{
+    out=(out+1)%maxclick;
+}
+
+class NhPSListViewItem : public QListViewItem {
+public:
+    NhPSListViewItem( QListView* parent, const QString& name ) :
+       QListViewItem(parent, name)
+    {
+    }
+
+    void setGlyph(int g)
+    {
+       NetHackQtGlyphs& glyphs = qt_settings->glyphs();
+       int gw = glyphs.width();
+       int gh = glyphs.height();
+       QPixmap pm(gw,gh);
+       QPainter p(&pm);
+       glyphs.drawGlyph(p, g, 0, 0);
+       p.end();
+       setPixmap(0,pm);
+       setHeight(QMAX(pm.height()+1,height()));
+    }
+
+    void paintCell( QPainter *p, const QColorGroup &cg,
+                   int column, int width, int alignment )
+    {
+       if ( isSelectable() ) {
+           QListViewItem::paintCell( p, cg, column, width, alignment );
+       } else {
+           QColorGroup disabled(
+               cg.foreground().light(),
+               cg.button().light(),
+               cg.light(), cg.dark(), cg.mid(),
+               gray, cg.base() );
+           QListViewItem::paintCell( p, disabled, column, width, alignment );
+       }
+    }
+};
+
+class NhPSListViewRole : public NhPSListViewItem {
+public:
+    NhPSListViewRole( QListView* parent, int id ) :
+       NhPSListViewItem(parent,
+#ifdef QT_CHOOSE_RACE_FIRST // Lowerize - looks better
+           QString(QChar(roles[id].name.m[0])).lower()+QString(roles[id].name.m+1)
+#else
+           roles[id].name.m
+#endif
+       )
+    {
+       setGlyph(monnum_to_glyph(roles[id].malenum));
+    }
+};
+
+class NhPSListViewRace : public NhPSListViewItem {
+public:
+    NhPSListViewRace( QListView* parent, int id ) :
+       NhPSListViewItem(parent,
+#ifdef QT_CHOOSE_RACE_FIRST // Capitalize - looks better
+           QString(QChar(races[id].noun[0])).upper()+QString(races[id].noun+1)
+#else
+           QString(QChar(races[id].noun[0])+QString(races[id].noun+1))
+#endif
+       )
+    {
+       setGlyph(monnum_to_glyph(races[id].malenum));
+    }
+};
+
+class NhPSListView : public QListView {
+public:
+    NhPSListView( QWidget* parent ) :
+       QListView(parent)
+    {
+       setSorting(-1); // order is identity
+       header()->setClickEnabled(FALSE);
+    }
+
+    QSizePolicy sizePolicy() const
+    {
+       return QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
+    }
+
+    QSize minimumSizeHint() const
+    {
+       return sizeHint();
+    }
+
+    QSize sizeHint() const
+    {
+       QListView::sizeHint();
+       QSize sz = header()->sizeHint();
+       int h=0;
+       QListViewItem* c=firstChild();
+       while (c) h+=c->height(),c = c->nextSibling();
+       sz += QSize(frameWidth()*2, h+frameWidth()*2);
+       return sz;
+    }
+
+    int selectedItemNumber() const
+    {
+       int i=0;
+       QListViewItem* c = firstChild();
+       while (c) {
+           if (c == selectedItem()) {
+               return i;
+           }
+           i++;
+           c = c->nextSibling();
+       }
+       return -1;
+    }
+
+    void setSelectedItemNumber(int i)
+    {
+       QListViewItem* c=firstChild();
+       while (i--)
+           c = c->nextSibling();
+       c->setSelected(TRUE);
+    }
+};
+
+NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) :
+    QDialog(qApp->mainWidget(),"plsel",TRUE),
+    keysource(ks),
+    fully_specified_role(TRUE)
+{
+    /*
+               0             1             2
+         + Name ------------------------------------+
+       0 |                                          |
+         + ---- ------------------------------------+
+         + Role ---+   + Race ---+   + Gender ------+
+         |         |   |         |   |  * Male      |
+       1 |         |   |         |   |  * Female    |
+         |         |   |         |   +--------------+
+         |         |   |         |   
+         |         |   |         |   + Alignment ---+
+       2 |         |   |         |   |  * Male      |
+         |         |   |         |   |  * Female    |
+         |         |   |         |   +--------------+
+       3 |         |   |         |   ...stretch...
+         |         |   |         |   
+       4 |         |   |         |   [  Play  ]
+       5 |         |   |         |   [  Quit  ]
+         +---------+   +---------+   
+    */
+
+    int marg=4;
+    QGridLayout *l = new QGridLayout(this,6,3,marg,marg);
+
+    QButtonGroup* namebox = new QButtonGroup(1,Horizontal,"Name",this);
+    QLineEdit* name = new QLineEdit(namebox);
+    name->setMaxLength(sizeof(plname)-1);
+    if ( strncmp(plname,"player",6) && strncmp(plname,"games",5) )
+       name->setText(plname);
+    connect(name, SIGNAL(textChanged(const QString&)),
+           this, SLOT(selectName(const QString&)) );
+    name->setFocus();
+    QButtonGroup* genderbox = new QButtonGroup("Sex",this);
+    QButtonGroup* alignbox = new QButtonGroup("Alignment",this);
+    QVBoxLayout* vbgb = new QVBoxLayout(genderbox,3,1);
+    vbgb->setAutoAdd(TRUE);
+    vbgb->addSpacing(fontMetrics().height()*3/4);
+    QVBoxLayout* vbab = new QVBoxLayout(alignbox,3,1);
+    vbab->setAutoAdd(TRUE);
+    vbab->addSpacing(fontMetrics().height());
+    QLabel* logo = new QLabel(nh_attribution, this);
+
+    l->addMultiCellWidget( namebox, 0,0,0,2 );
+#ifdef QT_CHOOSE_RACE_FIRST
+    race = new NhPSListView(this);
+    role = new NhPSListView(this);
+    l->addMultiCellWidget( race, 1,5,0,0 );
+    l->addMultiCellWidget( role, 1,5,1,1 );
+#else
+    role = new NhPSListView(this);
+    race = new NhPSListView(this);
+    l->addMultiCellWidget( role, 1,5,0,0 );
+    l->addMultiCellWidget( race, 1,5,1,1 );
+#endif
+    role->addColumn("Role");
+    race->addColumn("Race");
+
+    l->addWidget( genderbox, 1, 2 );
+    l->addWidget( alignbox, 2, 2 );
+    l->addWidget( logo, 3, 2, AlignCenter );
+    l->setRowStretch( 3, 5 );
+
+    int i;
+    int nrole;
+
+    for (nrole=0; roles[nrole].name.m; nrole++)
+       ;
+    for (i=nrole-1; i>=0; i--) { // XXX QListView unsorted goes in rev.
+       new NhPSListViewRole( role, i );
+    }
+    connect( role, SIGNAL(selectionChanged()), this, SLOT(selectRole()) );
+
+    int nrace;
+    for (nrace=0; races[nrace].noun; nrace++)
+       ;
+    for (i=nrace-1; i>=0; i--) {
+       new NhPSListViewRace( race, i );
+    }
+    connect( race, SIGNAL(selectionChanged()), this, SLOT(selectRace()) );
+
+    gender = new QRadioButton*[ROLE_GENDERS];
+    for (i=0; i<ROLE_GENDERS; i++) {
+       gender[i] = new QRadioButton( genders[i].adj, genderbox );
+    }
+    connect( genderbox, SIGNAL(clicked(int)), this, SLOT(selectGender(int)) );
+
+    alignment = new QRadioButton*[ROLE_ALIGNS];
+    for (i=0; i<ROLE_ALIGNS; i++) {
+       alignment[i] = new QRadioButton( aligns[i].adj, alignbox );
+    }
+    connect( alignbox, SIGNAL(clicked(int)), this, SLOT(selectAlignment(int)) );
+
+    QPushButton* ok = new QPushButton("Play",this);
+    l->addWidget( ok, 4, 2 );
+    ok->setDefault(TRUE);
+    connect( ok, SIGNAL(clicked()), this, SLOT(accept()) );
+
+    QPushButton* cancel = new QPushButton("Quit",this);
+    l->addWidget( cancel, 5, 2 );
+    connect( cancel, SIGNAL(clicked()), this, SLOT(reject()) );
+
+    // Randomize race and role, unless specified in config
+    int ro = flags.initrole;
+    if (ro == ROLE_NONE || ro == ROLE_RANDOM) {
+       ro = rn2(nrole);
+       if (flags.initrole != ROLE_RANDOM) {
+           fully_specified_role = FALSE;
+       }
+    }
+    int ra = flags.initrace;
+    if (ra == ROLE_NONE || ra == ROLE_RANDOM) {
+       ra = rn2(nrace);
+       if (flags.initrace != ROLE_RANDOM) {
+           fully_specified_role = FALSE;
+       }
+    }
+
+    // make sure we have a valid combination, honoring 
+    // the users request if possible.
+    bool choose_race_first;
+#ifdef QT_CHOOSE_RACE_FIRST
+    choose_race_first = TRUE;
+    if (flags.initrole >= 0 && flags.initrace < 0) {
+       choose_race_first = FALSE;
+    }
+#else
+    choose_race_first = FALSE;
+    if (flags.initrace >= 0 && flags.initrole < 0) {
+       choose_race_first = TRUE;
+    }
+#endif
+    while (!validrace(ro,ra)) {
+       if (choose_race_first) {
+           ro = rn2(nrole);
+           if (flags.initrole != ROLE_RANDOM) {
+               fully_specified_role = FALSE;
+           }
+       } else {
+           ra = rn2(nrace);
+           if (flags.initrace != ROLE_RANDOM) {
+               fully_specified_role = FALSE;
+           }
+       }
+    }
+
+    int g = flags.initgend;
+    if (g == -1) {
+       g = rn2(ROLE_GENDERS);
+       fully_specified_role = FALSE;
+    }
+    while (!validgend(ro,ra,g)) {
+       g = rn2(ROLE_GENDERS);
+    }
+    gender[g]->setChecked(TRUE);
+    selectGender(g);
+
+    int a = flags.initalign;
+    if (a == -1) {
+       a = rn2(ROLE_ALIGNS);
+       fully_specified_role = FALSE;
+    }
+    while (!validalign(ro,ra,a)) {
+       a = rn2(ROLE_ALIGNS);
+    }
+    alignment[a]->setChecked(TRUE);
+    selectAlignment(a);
+
+    QListViewItem* li;
+
+    li = role->firstChild();
+    while (ro--) li=li->nextSibling();
+    role->setSelected(li,TRUE);
+
+    li = race->firstChild();
+    while (ra--) li=li->nextSibling();
+    race->setSelected(li,TRUE);
+
+    flags.initrace = race->selectedItemNumber();
+    flags.initrole = role->selectedItemNumber();
+}
+
+
+void NetHackQtPlayerSelector::selectName(const QString& n)
+{
+    strncpy(plname,n.latin1(),sizeof(plname)-1);
+}
+
+void NetHackQtPlayerSelector::selectRole()
+{
+    int ra = race->selectedItemNumber();
+    int ro = role->selectedItemNumber();
+    if (ra == -1 || ro == -1) return;
+
+#ifdef QT_CHOOSE_RACE_FIRST
+    selectRace();
+#else
+    QListViewItem* i=role->currentItem();
+    QListViewItem* valid=0;
+    int j;
+    NhPSListViewItem* item;
+    item = (NhPSListViewItem*)role->firstChild();
+    for (j=0; roles[j].name.m; j++) {
+       bool v = validrace(j,ra);
+       item->setSelectable(TRUE);
+       if ( !valid && v ) valid = item;
+       item=(NhPSListViewItem*)item->nextSibling();
+    }
+    if ( !validrace(role->selectedItemNumber(),ra) )
+       i = valid;
+    role->setSelected(i,TRUE);
+    item = (NhPSListViewItem*)role->firstChild();
+    for (j=0; roles[j].name.m; j++) {
+       bool v = validrace(j,ra);
+       item->setSelectable(v);
+       item->repaint();
+       item=(NhPSListViewItem*)item->nextSibling();
+    }
+#endif
+
+    flags.initrole = role->selectedItemNumber();
+    setupOthers();
+}
+
+void NetHackQtPlayerSelector::selectRace()
+{
+    int ra = race->selectedItemNumber();
+    int ro = role->selectedItemNumber();
+    if (ra == -1 || ro == -1) return;
+
+#ifndef QT_CHOOSE_RACE_FIRST
+    selectRole();
+#else
+    QListViewItem* i=race->currentItem();
+    QListViewItem* valid=0;
+    int j;
+    NhPSListViewItem* item;
+    item = (NhPSListViewItem*)race->firstChild();
+    for (j=0; races[j].noun; j++) {
+       bool v = validrace(ro,j);
+       item->setSelectable(TRUE);
+       if ( !valid && v ) valid = item;
+       item=(NhPSListViewItem*)item->nextSibling();
+    }
+    if ( !validrace(ro,race->selectedItemNumber()) )
+       i = valid;
+    race->setSelected(i,TRUE);
+    item = (NhPSListViewItem*)race->firstChild();
+    for (j=0; races[j].noun; j++) {
+       bool v = validrace(ro,j);
+       item->setSelectable(v);
+       item->repaint();
+       item=(NhPSListViewItem*)item->nextSibling();
+    }
+#endif
+
+    flags.initrace = race->selectedItemNumber();
+    setupOthers();
+}
+
+void NetHackQtPlayerSelector::setupOthers()
+{
+    int ro = role->selectedItemNumber();
+    int ra = race->selectedItemNumber();
+    int valid=-1;
+    int c=0;
+    int j;
+    for (j=0; j<ROLE_GENDERS; j++) {
+       bool v = validgend(ro,ra,j);
+       if ( gender[j]->isChecked() )
+           c = j;
+       gender[j]->setEnabled(v);
+       if ( valid<0 && v ) valid = j;
+    }
+    if ( !validgend(ro,ra,c) )
+       c = valid;
+    int k;
+    for (k=0; k<ROLE_GENDERS; k++) {
+       gender[k]->setChecked(c==k);
+    }
+    selectGender(c);
+
+    valid=-1;
+    for (j=0; j<ROLE_ALIGNS; j++) {
+       bool v = validalign(ro,ra,j);
+       if ( alignment[j]->isChecked() )
+           c = j;
+       alignment[j]->setEnabled(v);
+       if ( valid<0 && v ) valid = j;
+    }
+    if ( !validalign(ro,ra,c) )
+       c = valid;
+    for (k=0; k<ROLE_ALIGNS; k++) {
+       alignment[k]->setChecked(c==k);
+    }
+    selectAlignment(c);
+}
+
+void NetHackQtPlayerSelector::selectGender(int i)
+{
+    flags.initgend = i;
+}
+
+void NetHackQtPlayerSelector::selectAlignment(int i)
+{
+    flags.initalign = i;
+}
+
+
+void NetHackQtPlayerSelector::done(int i)
+{
+    setResult(i);
+    qApp->exit_loop();
+}
+
+void NetHackQtPlayerSelector::Quit()
+{
+    done(R_Quit);
+    qApp->exit_loop();
+}
+
+void NetHackQtPlayerSelector::Random()
+{
+    done(R_Rand);
+    qApp->exit_loop();
+}
+
+bool NetHackQtPlayerSelector::Choose()
+{
+    if (fully_specified_role) return TRUE;
+
+#if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog).
+    if ( qt_compact_mode ) {
+       showMaximized();
+    } else
+#endif
+    {
+       adjustSize();
+       centerOnMain(this);
+    }
+
+    if ( exec() ) {
+       return TRUE;
+    } else {
+       return FALSE;
+    }
+}
+
+
+NetHackQtStringRequestor::NetHackQtStringRequestor(NetHackQtKeyBuffer& ks, const char* p, const char* cancelstr) :
+    QDialog(qApp->mainWidget(),"string",FALSE),
+    prompt(p,this,"prompt"),
+    input(this,"input"),
+    keysource(ks)
+{
+    cancel=new QPushButton(cancelstr,this);
+    connect(cancel,SIGNAL(clicked()),this,SLOT(reject()));
+
+    okay=new QPushButton("Okay",this);
+    connect(okay,SIGNAL(clicked()),this,SLOT(accept()));
+    connect(&input,SIGNAL(returnPressed()),this,SLOT(accept()));
+    okay->setDefault(TRUE);
+
+    setFocusPolicy(StrongFocus);
+}
+
+void NetHackQtStringRequestor::resizeEvent(QResizeEvent*)
+{
+    const int margin=5;
+    const int gutter=5;
+
+    int h=(height()-margin*2-gutter);
+
+    if (strlen(prompt.text()) > 16) {
+       h/=3;
+       prompt.setGeometry(margin,margin,width()-margin*2,h);
+       input.setGeometry(width()*1/5,margin+h+gutter,
+           (width()-margin-2-gutter)*4/5,h);
+    } else {
+       h/=2;
+       prompt.setGeometry(margin,margin,(width()-margin*2-gutter)*2/5,h);
+       input.setGeometry(prompt.geometry().right()+gutter,margin,
+           (width()-margin-2-gutter)*3/5,h);
+    }
+
+    cancel->setGeometry(margin,input.geometry().bottom()+gutter,
+       (width()-margin*2-gutter)/2,h);
+    okay->setGeometry(cancel->geometry().right()+gutter,cancel->geometry().y(),
+       cancel->width(),h);
+}
+
+void NetHackQtStringRequestor::SetDefault(const char* d)
+{
+    input.setText(d);
+}
+bool NetHackQtStringRequestor::Get(char* buffer, int maxchar)
+{
+    input.setMaxLength(maxchar);
+    if (strlen(prompt.text()) > 16) {
+       resize(fontMetrics().width(prompt.text())+50,fontMetrics().height()*6);
+    } else {
+       resize(fontMetrics().width(prompt.text())*2+50,fontMetrics().height()*4);
+    }
+
+    centerOnMain(this);
+    show();
+    input.setFocus();
+    setResult(-1);
+    while (result()==-1) {
+       // Put keys in buffer (eg. from macros, from out-of-focus input)
+       if (!keysource.Empty()) {
+           while (!keysource.Empty()) {
+               int key=keysource.TopKey();
+               int ascii=keysource.TopAscii();
+               int state=keysource.GetState();
+               if (ascii=='\r' || ascii=='\n') {
+                   // CR or LF in buffer causes confirmation
+                   strcpy(buffer,input.text());
+                   return TRUE;
+               } else if (ascii=='\033') {
+                   return FALSE;
+               } else {
+                   input.fakeEvent(key,ascii,state);
+               }
+           }
+       }
+       qApp->enter_loop();
+    }
+    // XXX Get rid of extra keys, since we couldn't get focus!
+    while (!keysource.Empty()) keysource.GetKey();
+
+    if (result()) {
+       strcpy(buffer,input.text());
+       return TRUE;
+    } else {
+       return FALSE;
+    }
+}
+void NetHackQtStringRequestor::done(int i)
+{
+    setResult(i);
+    qApp->exit_loop();
+}
+
+
+NetHackQtWindow::NetHackQtWindow()
+{
+}
+NetHackQtWindow::~NetHackQtWindow()
+{
+}
+
+// XXX Use "expected ..." for now, abort or default later.
+//
+void NetHackQtWindow::Clear() { puts("unexpected Clear"); }
+void NetHackQtWindow::Display(bool block) { puts("unexpected Display"); }
+bool NetHackQtWindow::Destroy() { return TRUE; }
+void NetHackQtWindow::CursorTo(int x,int y) { puts("unexpected CursorTo"); }
+void NetHackQtWindow::PutStr(int attr, const char* text) { puts("unexpected PutStr"); }
+void NetHackQtWindow::StartMenu() { puts("unexpected StartMenu"); }
+void NetHackQtWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr,
+    const char* str, bool presel) { puts("unexpected AddMenu"); }
+void NetHackQtWindow::EndMenu(const char* prompt) { puts("unexpected EndMenu"); }
+int NetHackQtWindow::SelectMenu(int how, MENU_ITEM_P **menu_list) { puts("unexpected SelectMenu"); return 0; }
+void NetHackQtWindow::ClipAround(int x,int y) { puts("unexpected ClipAround"); }
+void NetHackQtWindow::PrintGlyph(int x,int y,int glyph) { puts("unexpected PrintGlyph"); }
+//void NetHackQtWindow::PrintGlyphCompose(int x,int y,int,int) { puts("unexpected PrintGlyphCompose"); }
+void NetHackQtWindow::UseRIP(int how) { puts("unexpected UseRIP"); }
+
+
+
+// XXX Hmmm... crash after saving bones file if Map window is
+// XXX deleted.  Strange bug somewhere.
+bool NetHackQtMapWindow::Destroy() { return FALSE; }
+
+NetHackQtMapWindow::NetHackQtMapWindow(NetHackQtClickBuffer& click_sink) :
+    clicksink(click_sink),
+    change(10),
+    rogue_font(0)
+{
+    viewport.addChild(this);
+
+    setBackgroundColor(black);
+    viewport.setBackgroundColor(black);
+
+    pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm : pet_mark_xpm);
+
+    cursor.setX(0);
+    cursor.setY(0);
+    Clear();
+
+    connect(qt_settings,SIGNAL(tilesChanged()),this,SLOT(updateTiles()));
+    connect(&viewport, SIGNAL(contentsMoving(int,int)), this,
+               SLOT(moveMessages(int,int)));
+
+    updateTiles();
+    //setFocusPolicy(StrongFocus);
+}
+
+void NetHackQtMapWindow::moveMessages(int x, int y)
+{
+    QRect u = messages_rect;
+    messages_rect.moveTopLeft(QPoint(x,y));
+    u |= messages_rect;
+    update(u);
+}
+
+void NetHackQtMapWindow::clearMessages()
+{
+    messages = "";
+    update(messages_rect);
+    messages_rect = QRect();
+}
+
+void NetHackQtMapWindow::putMessage(int attr, const char* text)
+{
+    if ( !messages.isEmpty() )
+       messages += "\n";
+    messages += text;
+    QFontMetrics fm = fontMetrics();
+    messages_rect = fm.boundingRect(viewport.contentsX(),viewport.contentsY(),viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages);
+    update(messages_rect);
+}
+
+void NetHackQtMapWindow::updateTiles()
+{
+    NetHackQtGlyphs& glyphs = qt_settings->glyphs();
+    int gw = glyphs.width();
+    int gh = glyphs.height();
+    // Be exactly the size we want to be - full map...
+    resize(COLNO*gw,ROWNO*gh);
+
+    viewport.verticalScrollBar()->setSteps(gh,gh);
+    viewport.horizontalScrollBar()->setSteps(gw,gw);
+    /*
+    viewport.setMaximumSize(
+       gw*COLNO + viewport.verticalScrollBar()->width(),
+       gh*ROWNO + viewport.horizontalScrollBar()->height()
+    );
+    */
+    viewport.updateScrollBars();
+
+    change.clear();
+    change.add(0,0,COLNO,ROWNO);
+    delete rogue_font; rogue_font = 0;
+    Display(FALSE);
+
+    emit resized();
+}
+
+NetHackQtMapWindow::~NetHackQtMapWindow()
+{
+    // Remove from viewport porthole, since that is a destructible member.
+    viewport.removeChild(this);
+    recreate(0,0,QPoint(0,0));
+}
+
+QWidget* NetHackQtMapWindow::Widget()
+{
+    return &viewport;
+}
+
+void NetHackQtMapWindow::Scroll(int dx, int dy)
+{
+    if (viewport.horizontalScrollBar()->isVisible()) {
+       while (dx<0) { viewport.horizontalScrollBar()->subtractPage(); dx++; }
+       while (dx>0) { viewport.horizontalScrollBar()->addPage(); dx--; }
+    }
+    if (viewport.verticalScrollBar()->isVisible()) {
+       while (dy<0) { viewport.verticalScrollBar()->subtractPage(); dy++; }
+       while (dy>0) { viewport.verticalScrollBar()->addPage(); dy--; }
+    }
+}
+
+void NetHackQtMapWindow::Clear()
+{
+    unsigned short stone=cmap_to_glyph(S_stone);
+
+    for (int j=0; j<ROWNO; j++) {
+       for (int i=0; i<COLNO; i++) {
+           Glyph(i,j)=stone;
+       }
+    }
+
+    change.clear();
+    change.add(0,0,COLNO,ROWNO);
+}
+
+void NetHackQtMapWindow::clickCursor()
+{
+    clicksink.Put(cursor.x(),cursor.y(),CLICK_1);
+    qApp->exit_loop();
+}
+
+void NetHackQtMapWindow::mousePressEvent(QMouseEvent* event)
+{
+    clicksink.Put(
+       event->pos().x()/qt_settings->glyphs().width(),
+       event->pos().y()/qt_settings->glyphs().height(),
+       event->button()==LeftButton ? CLICK_1 : CLICK_2
+    );
+    qApp->exit_loop();
+}
+
+#ifdef TEXTCOLOR
+static
+const QPen& nhcolor_to_pen(int c)
+{
+    static QPen* pen=0;
+    if ( !pen ) {
+       pen = new QPen[17];
+       pen[0] = Qt::black;
+       pen[1] = Qt::red;
+       pen[2] = QColor(0,191,0);
+       pen[3] = QColor(127,127,0);
+       pen[4] = Qt::blue;
+       pen[5] = Qt::magenta;
+       pen[6] = Qt::cyan;
+       pen[7] = Qt::gray;
+       pen[8] = Qt::white; // no color
+       pen[9] = QColor(255,127,0);
+       pen[10] = QColor(127,255,127);
+       pen[11] = Qt::yellow;
+       pen[12] = QColor(127,127,255);
+       pen[13] = QColor(255,127,255);
+       pen[14] = QColor(127,255,255);
+       pen[15] = Qt::white;
+       pen[16] = Qt::black;
+    }
+
+    return pen[c];
+}
+#endif
+
+void NetHackQtMapWindow::paintEvent(QPaintEvent* event)
+{
+    QRect area=event->rect();
+    QRect garea;
+    garea.setCoords(
+       QMAX(0,area.left()/qt_settings->glyphs().width()),
+       QMAX(0,area.top()/qt_settings->glyphs().height()),
+       QMIN(COLNO-1,area.right()/qt_settings->glyphs().width()),
+       QMIN(ROWNO-1,area.bottom()/qt_settings->glyphs().height())
+    );
+
+    QPainter painter;
+
+    painter.begin(this);
+
+    if (
+#ifdef REINCARNATION
+       Is_rogue_level(&u.uz) ||
+#endif
+       iflags.wc_ascii_map
+    )
+    {
+       // You enter a VERY primitive world!
+
+       painter.setClipRect( event->rect() ); // (normally we don't clip)
+       painter.fillRect( event->rect(), black );
+
+       if ( !rogue_font ) {
+           // Find font...
+           int pts = 5;
+           QString fontfamily = iflags.wc_font_map
+               ? iflags.wc_font_map : "Courier";
+           bool bold = FALSE;
+           if ( fontfamily.right(5).lower() == "-bold" ) {
+               fontfamily.truncate(fontfamily.length()-5);
+               bold = TRUE;
+           }
+           while ( pts < 32 ) {
+               QFont f(fontfamily, pts, bold ? QFont::Bold : QFont::Normal);
+               painter.setFont(QFont(fontfamily, pts));
+               QFontMetrics fm = painter.fontMetrics();
+               if ( fm.width("M") > qt_settings->glyphs().width() )
+                   break;
+               if ( fm.height() > qt_settings->glyphs().height() )
+                   break;
+               pts++;
+           }
+           rogue_font = new QFont(fontfamily,pts-1);
+       }
+       painter.setFont(*rogue_font);
+
+       for (int j=garea.top(); j<=garea.bottom(); j++) {
+           for (int i=garea.left(); i<=garea.right(); i++) {
+               unsigned short g=Glyph(i,j);
+               uchar ch;
+               int color, och;
+               unsigned special;
+
+               painter.setPen( green );
+               /* map glyph to character and color */
+               mapglyph(g, &och, &color, &special, i, j);
+               ch = (uchar)och;
+#ifdef TEXTCOLOR
+               painter.setPen( nhcolor_to_pen(color) );
+#endif
+               painter.drawText(
+                   i*qt_settings->glyphs().width(),
+                   j*qt_settings->glyphs().height(),
+                   qt_settings->glyphs().width(),
+                   qt_settings->glyphs().height(),
+                   AlignCenter,
+                   (const char*)&ch, 1
+               );
+               if (glyph_is_pet(g)
+#ifdef TEXTCOLOR
+                   && ::iflags.hilite_pet
+#endif
+               ) {
+                   painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation);
+               }
+           }
+       }
+
+       painter.setFont(font());
+    } else {
+       for (int j=garea.top(); j<=garea.bottom(); j++) {
+           for (int i=garea.left(); i<=garea.right(); i++) {
+               unsigned short g=Glyph(i,j);
+               qt_settings->glyphs().drawCell(painter, g, i, j);
+               if (glyph_is_pet(g)
+#ifdef TEXTCOLOR
+                   && ::iflags.hilite_pet
+#endif
+               ) {
+                   painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation);
+               }
+           }
+       }
+    }
+
+    if (garea.contains(cursor)) {
+#ifdef REINCARNATION
+       if (Is_rogue_level(&u.uz)) {
+#ifdef TEXTCOLOR
+           painter.setPen( white );
+#else
+           painter.setPen( green ); // REALLY primitive
+#endif
+       } else
+#endif
+       {
+           int hp100;
+           if (u.mtimedone) {
+               hp100=u.mhmax ? u.mh*100/u.mhmax : 100;
+           } else {
+               hp100=u.uhpmax ? u.uhp*100/u.uhpmax : 100;
+           }
+
+           if (hp100 > 75) painter.setPen(white);
+           else if (hp100 > 50) painter.setPen(yellow);
+           else if (hp100 > 25) painter.setPen(QColor(0xff,0xbf,0x00)); // orange
+           else if (hp100 > 10) painter.setPen(red);
+           else painter.setPen(magenta);
+       }
+
+       painter.drawRect(
+           cursor.x()*qt_settings->glyphs().width(),cursor.y()*qt_settings->glyphs().height(),
+           qt_settings->glyphs().width(),qt_settings->glyphs().height());
+    }
+
+    if (area.intersects(messages_rect)) {
+       painter.setPen(black);
+       painter.drawText(viewport.contentsX()+1,viewport.contentsY()+1,
+           viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages);
+       painter.setPen(white);
+       painter.drawText(viewport.contentsX(),viewport.contentsY(),
+           viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages);
+    }
+
+    painter.end();
+}
+
+void NetHackQtMapWindow::Display(bool block)
+{
+    for (int i=0; i<change.clusters(); i++) {
+       const QRect& ch=change[i];
+       repaint(
+           ch.x()*qt_settings->glyphs().width(),
+           ch.y()*qt_settings->glyphs().height(),
+           ch.width()*qt_settings->glyphs().width(),
+           ch.height()*qt_settings->glyphs().height(),
+           FALSE
+       );
+    }
+
+    change.clear();
+
+    if (block) {
+       yn_function("Press a key when done viewing",0,'\0');
+    }
+}
+
+void NetHackQtMapWindow::CursorTo(int x,int y)
+{
+    Changed(cursor.x(),cursor.y());
+    cursor.setX(x);
+    cursor.setY(y);
+    Changed(cursor.x(),cursor.y());
+}
+
+void NetHackQtMapWindow::PutStr(int attr, const char* text)
+{
+    puts("unexpected PutStr in MapWindow");
+}
+
+void NetHackQtMapWindow::ClipAround(int x,int y)
+{
+    // Convert to pixel of center of tile
+    x=x*qt_settings->glyphs().width()+qt_settings->glyphs().width()/2;
+    y=y*qt_settings->glyphs().height()+qt_settings->glyphs().height()/2;
+
+    // Then ensure that pixel is visible
+    viewport.center(x,y,0.45,0.45);
+}
+
+void NetHackQtMapWindow::PrintGlyph(int x,int y,int glyph)
+{
+    Glyph(x,y)=glyph;
+    Changed(x,y);
+}
+
+//void NetHackQtMapWindow::PrintGlyphCompose(int x,int y,int glyph1, int glyph2)
+//{
+    // TODO: composed graphics
+//}
+
+void NetHackQtMapWindow::Changed(int x, int y)
+{
+    change.add(x,y);
+}
+
+
+class NetHackQtScrollText : public QTableView {
+    struct UData {
+       UData() : text(0), attr(0) { }
+       ~UData() { if (text) free(text); }
+
+       char* text;
+       int attr;
+    };
+public:
+    int uncleared;
+
+    NetHackQtScrollText(int maxlength) :
+       uncleared(0),
+       maxitems(maxlength),
+       first(0),
+       count(0),
+       item_cycle(maxlength)
+    {
+       setNumCols(1);
+       setCellWidth(200);
+       setCellHeight(fontMetrics().height());
+       setBackgroundColor(white);
+       setTableFlags(Tbl_vScrollBar
+           |Tbl_autoHScrollBar
+           |Tbl_clipCellPainting
+           |Tbl_smoothScrolling);
+    }
+
+    ~NetHackQtScrollText()
+    {
+    }
+
+    void Scroll(int dx, int dy)
+    {
+       setXOffset(xOffset()+dx*viewWidth());
+       setYOffset(yOffset()+dy*viewHeight());
+    }
+
+    void insertItem(int attr, const char* text)
+    {
+       setTopCell(count);
+
+       setAutoUpdate(FALSE);
+
+       int i;
+       if (count<maxitems) {
+           i=count++;
+           setNumRows(count);
+       } else {
+           i=count-1;
+           first=(first+1)%maxitems;
+       }
+       item(i).attr=attr;
+       item(i).text=strdup(text);
+       int w=datumWidth(item(i));
+
+       if (w > cellWidth()) {
+           // Get wider.
+           setCellWidth(w);
+       }
+       setTopCell(count);
+
+       setAutoUpdate(TRUE);
+
+       if (viewHeight() >= totalHeight()-cellHeight()) {
+           repaint();
+       } else {
+           scroll(0,cellHeight());
+       }
+    }
+
+    virtual void setFont(const QFont& font)
+    {
+       QTableView::setFont(font);
+       setCellHeight(fontMetrics().height());
+    }
+
+protected:
+
+    UData& item(int i)
+    {
+       return item_cycle[(first+i)%maxitems];
+    }
+
+    const int maxitems;
+    int first, count;
+    QArray<UData> item_cycle;
+
+    int datumWidth(const UData& uitem)
+    {
+       if (uitem.text) {
+           int width=fontMetrics().width(uitem.text)+3;
+           if (uitem.attr) {
+               // XXX Too expensive to do properly, because
+               // XXX we have to set the font of the widget
+               // XXX just to get the font metrics information!
+               // XXX Could hold a fake widget for that
+               // XXX purpose, but this hack is less ugly.
+               width+=width/10;
+           }
+           return width;
+       } else {
+           return 0;
+       }
+    }
+
+    virtual void setupPainter(QPainter *p)
+    {
+       // XXX This shouldn't be needed - we set the bg in the constructor.
+       p->setBackgroundColor(white);
+    }
+
+    virtual void paintCell(QPainter *p, int row, int col)
+    {
+       bool sel=FALSE;
+       UData& uitem=item(row);
+
+       if (!sel && row < count-uncleared) {
+           p->setPen(darkGray);
+       } else {
+           p->setPen(black);
+       }
+
+       if (uitem.attr) {
+           // XXX only bold
+           QFont bold(font().family(),font().pointSize(),QFont::Bold);
+           p->setFont(bold);
+       }
+
+       p->drawText(3, 0, cellWidth(), cellHeight(),
+               AlignLeft|AlignVCenter, uitem.text);
+
+       if (uitem.attr) {
+           p->setFont(font());
+       }
+    }
+};
+
+NetHackQtMessageWindow::NetHackQtMessageWindow() :
+    list(new NetHackQtScrollText(::iflags.msg_history))
+{
+    ::iflags.window_inited = 1;
+    map = 0;
+    connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(updateFont()));
+    updateFont();
+}
+
+NetHackQtMessageWindow::~NetHackQtMessageWindow()
+{
+    ::iflags.window_inited = 0;
+    delete list;
+}
+
+QWidget* NetHackQtMessageWindow::Widget() { return list; }
+
+void NetHackQtMessageWindow::setMap(NetHackQtMapWindow* m)
+{
+    map = m;
+    updateFont();
+}
+
+void NetHackQtMessageWindow::updateFont()
+{
+    list->setFont(qt_settings->normalFont());
+    if ( map )
+       map->setFont(qt_settings->normalFont());
+}
+
+void NetHackQtMessageWindow::Scroll(int dx, int dy)
+{
+    list->Scroll(dx,dy);
+}
+
+void NetHackQtMessageWindow::Clear()
+{
+    if ( map )
+       map->clearMessages();
+    if (list->uncleared) {
+       list->uncleared=0;
+       changed=TRUE;
+       Display(FALSE);
+    }
+}
+
+void NetHackQtMessageWindow::Display(bool block)
+{
+    if (changed) {
+       list->repaint();
+       changed=FALSE;
+    }
+}
+
+void NetHackQtMessageWindow::PutStr(int attr, const char* text)
+{
+#ifdef USER_SOUNDS
+    play_sound_for_message(text);
+#endif
+
+    changed=TRUE;
+    list->uncleared++;
+    list->insertItem(attr,text);
+
+    // Force scrollbar to bottom
+    // XXX list->setTopItem(list->count());
+
+    if ( map )
+       map->putMessage(attr, text);
+}
+
+
+
+NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l) :
+    QWidget(parent),
+    low_is_good(FALSE),
+    prev_value(-123),
+    turn_count(-1),
+    label(new QLabel(l,this)),
+    icon(0)
+{
+    initHighlight();
+}
+NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l, const QPixmap& i) :
+    QWidget(parent),
+    low_is_good(FALSE),
+    prev_value(-123),
+    turn_count(-1),
+    label(new QLabel(l,this)),
+    icon(new QLabel(this))
+{
+    setIcon(i);
+    initHighlight();
+}
+void NetHackQtLabelledIcon::initHighlight()
+{
+    const QPalette& pal=palette();
+    const QColorGroup& pa=pal.normal();
+    //QColorGroup good(white,darkGreen,pa.light(),pa.dark(),pa.mid(),white,pa.base());
+    QColorGroup good(black,green,pa.light(),pa.dark(),pa.mid(),black,pa.base());
+    QColorGroup bad(white,red,pa.light(),pa.dark(),pa.mid(),white,pa.base());
+    hl_good=pal.copy();
+    hl_good.setNormal(good);
+    hl_good.setActive(good);
+    hl_bad=pal.copy();
+    hl_bad.setNormal(bad);
+    hl_bad.setActive(bad);
+}
+
+void NetHackQtLabelledIcon::setLabel(const char* t, bool lower)
+{
+    if (!label) {
+       label=new QLabel(this);
+       label->setFont(font());
+       resizeEvent(0);
+    }
+    if (0!=strcmp(label->text(),t)) {
+       label->setText(t);
+       highlight(lower==low_is_good ? hl_good : hl_bad);
+    }
+}
+void NetHackQtLabelledIcon::setLabel(const char* t, long v, long cv, const char* tail)
+{
+    char buf[BUFSZ];
+    if (v==NoNum) {
+       Sprintf(buf,"%s%s",t,tail);
+    } else {
+       Sprintf(buf,"%s%ld%s",t,v,tail);
+    }
+    setLabel(buf,cv<prev_value);
+    prev_value=cv;
+}
+void NetHackQtLabelledIcon::setLabel(const char* t, long v, const char* tail)
+{
+    setLabel(t,v,v,tail);
+}
+void NetHackQtLabelledIcon::setIcon(const QPixmap& i)
+{
+    if (icon) icon->setPixmap(i);
+    else { icon=new QLabel(this); icon->setPixmap(i); resizeEvent(0); }
+    icon->resize(i.width(),i.height());
+}
+void NetHackQtLabelledIcon::setFont(const QFont& f)
+{
+    QWidget::setFont(f);
+    if (label) label->setFont(f);
+}
+void NetHackQtLabelledIcon::show()
+{
+#if QT_VERSION >= 300
+    if (isHidden())
+#else
+    if (!isVisible())
+#endif
+       highlight(hl_bad);
+    QWidget::show();
+}
+void NetHackQtLabelledIcon::highlightWhenChanging()
+{
+    turn_count=0;
+}
+void NetHackQtLabelledIcon::lowIsGood()
+{
+    low_is_good=TRUE;
+}
+void NetHackQtLabelledIcon::dissipateHighlight()
+{
+    if (turn_count>0) {
+       turn_count--;
+       if (!turn_count)
+           unhighlight();
+    }
+}
+void NetHackQtLabelledIcon::highlight(const QPalette& hl)
+{
+    if (label) { // Surely it is?!
+       if (turn_count>=0) {
+           label->setPalette(hl);
+           turn_count=4;
+           // `4' includes this turn, so dissipates after
+           // 3 more keypresses.
+       } else {
+           label->setPalette(palette());
+       }
+    }
+}
+void NetHackQtLabelledIcon::unhighlight()
+{
+    if (label) { // Surely it is?!
+       label->setPalette(palette());
+    }
+}
+void NetHackQtLabelledIcon::resizeEvent(QResizeEvent*)
+{
+    setAlignments();
+
+    //int labw=label ? label->fontMetrics().width(label->text()) : 0;
+    int labh=label ? label->fontMetrics().height() : 0;
+    int icoh=icon ? icon->height() : 0;
+    int h=icoh+labh;
+    int icoy=(h>height() ? height()-labh-icoh : height()/2-h/2);
+    int laby=icoy+icoh;
+    if (icon) {
+       icon->setGeometry(0,icoy,width(),icoh);
+    }
+    if (label) {
+       label->setGeometry(0,laby,width(),labh);
+    }
+}
+
+void NetHackQtLabelledIcon::setAlignments()
+{
+    if (label) label->setAlignment(AlignHCenter|AlignVCenter);
+    if (icon) icon->setAlignment(AlignHCenter|AlignVCenter);
+}
+
+static void
+tryload(QPixmap& pm, const char* fn)
+{
+    if (!pm.load(fn)) {
+       QString msg;
+       msg.sprintf("Cannot load \"%s\"", fn);
+       QMessageBox::warning(qApp->mainWidget(), "IO Error", msg);
+    }
+}
+
+NetHackQtStatusWindow::NetHackQtStatusWindow() :
+    // Notes:
+    //  Alignment needs -2 init value, because -1 is an alignment.
+    //  Armor Class is an schar, so 256 is out of range.
+    //  Blank value is 0 and should never change.
+    name(this,"(name)"),
+    dlevel(this,"(dlevel)"),
+    str(this,"STR"),
+    dex(this,"DEX"),
+    con(this,"CON"),
+    intel(this,"INT"),
+    wis(this,"WIS"),
+    cha(this,"CHA"),
+    gold(this,"Gold"),
+    hp(this,"Hit Points"),
+    power(this,"Power"),
+    ac(this,"Armour Class"),
+    level(this,"Level"),
+    exp(this,"Experience"),
+    align(this,"Alignment"),
+    time(this,"Time"),
+    score(this,"Score"),
+    hunger(this,""),
+    confused(this,"Confused"),
+    sick_fp(this,"Sick"),
+    sick_il(this,"Ill"),
+    blind(this,"Blind"),
+    stunned(this,"Stunned"),
+    hallu(this,"Hallu"),
+    encumber(this,""),
+    hline1(this),
+    hline2(this),
+    hline3(this),
+    first_set(TRUE)
+{
+    p_str = QPixmap(str_xpm);
+    p_str = QPixmap(str_xpm);
+    p_dex = QPixmap(dex_xpm);
+    p_con = QPixmap(cns_xpm);
+    p_int = QPixmap(int_xpm);
+    p_wis = QPixmap(wis_xpm);
+    p_cha = QPixmap(cha_xpm);
+
+    p_chaotic = QPixmap(chaotic_xpm);
+    p_neutral = QPixmap(neutral_xpm);
+    p_lawful = QPixmap(lawful_xpm);
+
+    p_satiated = QPixmap(satiated_xpm);
+    p_hungry = QPixmap(hungry_xpm);
+
+    p_confused = QPixmap(confused_xpm);
+    p_sick_fp = QPixmap(sick_fp_xpm);
+    p_sick_il = QPixmap(sick_il_xpm);
+    p_blind = QPixmap(blind_xpm);
+    p_stunned = QPixmap(stunned_xpm);
+    p_hallu = QPixmap(hallu_xpm);
+
+    p_encumber[0] = QPixmap(slt_enc_xpm);
+    p_encumber[1] = QPixmap(mod_enc_xpm);
+    p_encumber[2] = QPixmap(hvy_enc_xpm);
+    p_encumber[3] = QPixmap(ext_enc_xpm);
+    p_encumber[4] = QPixmap(ovr_enc_xpm);
+
+    str.setIcon(p_str);
+    dex.setIcon(p_dex);
+    con.setIcon(p_con);
+    intel.setIcon(p_int);
+    wis.setIcon(p_wis);
+    cha.setIcon(p_cha);
+
+    align.setIcon(p_neutral);
+    hunger.setIcon(p_hungry);
+
+    confused.setIcon(p_confused);
+    sick_fp.setIcon(p_sick_fp);
+    sick_il.setIcon(p_sick_il);
+    blind.setIcon(p_blind);
+    stunned.setIcon(p_stunned);
+    hallu.setIcon(p_hallu);
+
+    encumber.setIcon(p_encumber[0]);
+
+    hline1.setFrameStyle(QFrame::HLine|QFrame::Sunken);
+    hline2.setFrameStyle(QFrame::HLine|QFrame::Sunken);
+    hline3.setFrameStyle(QFrame::HLine|QFrame::Sunken);
+    hline1.setLineWidth(1);
+    hline2.setLineWidth(1);
+    hline3.setLineWidth(1);
+
+    connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate()));
+    doUpdate();
+}
+
+void NetHackQtStatusWindow::doUpdate()
+{
+    const QFont& large=qt_settings->largeFont();
+    name.setFont(large);
+    dlevel.setFont(large);
+
+    const QFont& normal=qt_settings->normalFont();
+    str.setFont(normal);
+    dex.setFont(normal);
+    con.setFont(normal);
+    intel.setFont(normal);
+    wis.setFont(normal);
+    cha.setFont(normal);
+    gold.setFont(normal);
+    hp.setFont(normal);
+    power.setFont(normal);
+    ac.setFont(normal);
+    level.setFont(normal);
+    exp.setFont(normal);
+    align.setFont(normal);
+    time.setFont(normal);
+    score.setFont(normal);
+    hunger.setFont(normal);
+    confused.setFont(normal);
+    sick_fp.setFont(normal);
+    sick_il.setFont(normal);
+    blind.setFont(normal);
+    stunned.setFont(normal);
+    hallu.setFont(normal);
+    encumber.setFont(normal);
+
+    updateStats();
+}
+
+QWidget* NetHackQtStatusWindow::Widget() { return this; }
+
+void NetHackQtStatusWindow::Clear()
+{
+}
+void NetHackQtStatusWindow::Display(bool block)
+{
+}
+void NetHackQtStatusWindow::CursorTo(int,int y)
+{
+    cursy=y;
+}
+void NetHackQtStatusWindow::PutStr(int attr, const char* text)
+{
+    // do a complete update when line 0 is done (as per X11 fancy status)
+    if (cursy==0) updateStats();
+}
+
+void NetHackQtStatusWindow::resizeEvent(QResizeEvent*)
+{
+    const float SP_name=0.13; //     <Name> the <Class> (large)
+    const float SP_dlev=0.13; //   Level 3 in The Dungeons of Doom (large)
+    const float SP_atr1=0.25; //  STR   DEX   CON   INT   WIS   CHA
+    const float SP_hln1=0.02; // ---
+    const float SP_atr2=0.09; //  Au    HP    PW    AC    LVL   EXP
+    const float SP_hln2=0.02; // ---
+    const float SP_time=0.09; //      time    score
+    const float SP_hln3=0.02; // ---
+    const float SP_stat=0.25; // Alignment, Poisoned, Hungry, Sick, etc.
+
+    int h=height();
+    int x=0,y=0;
+
+    int iw; // Width of an item across line
+    int lh; // Height of a line of values
+
+    lh=int(h*SP_name);
+    name.setGeometry(0,0,width(),lh); y+=lh;
+    lh=int(h*SP_dlev);
+    dlevel.setGeometry(0,y,width(),lh); y+=lh;
+
+    lh=int(h*SP_hln1);
+    hline1.setGeometry(0,y,width(),lh); y+=lh;
+
+    lh=int(h*SP_atr1);
+    iw=width()/6;
+    str.setGeometry(x,y,iw,lh); x+=iw;
+    dex.setGeometry(x,y,iw,lh); x+=iw;
+    con.setGeometry(x,y,iw,lh); x+=iw;
+    intel.setGeometry(x,y,iw,lh); x+=iw;
+    wis.setGeometry(x,y,iw,lh); x+=iw;
+    cha.setGeometry(x,y,iw,lh); x+=iw;
+    x=0; y+=lh;
+
+    lh=int(h*SP_hln2);
+    hline2.setGeometry(0,y,width(),lh); y+=lh;
+
+    lh=int(h*SP_atr2);
+    iw=width()/6;
+    gold.setGeometry(x,y,iw,lh); x+=iw;
+    hp.setGeometry(x,y,iw,lh); x+=iw;
+    power.setGeometry(x,y,iw,lh); x+=iw;
+    ac.setGeometry(x,y,iw,lh); x+=iw;
+    level.setGeometry(x,y,iw,lh); x+=iw;
+    exp.setGeometry(x,y,iw,lh); x+=iw;
+    x=0; y+=lh;
+
+    lh=int(h*SP_hln3);
+    hline3.setGeometry(0,y,width(),lh); y+=lh;
+
+    lh=int(h*SP_time);
+    iw=width()/3; x+=iw/2;
+    time.setGeometry(x,y,iw,lh); x+=iw;
+    score.setGeometry(x,y,iw,lh); x+=iw;
+    x=0; y+=lh;
+
+    lh=int(h*SP_stat);
+    iw=width()/9;
+    align.setGeometry(x,y,iw,lh); x+=iw;
+    hunger.setGeometry(x,y,iw,lh); x+=iw;
+    confused.setGeometry(x,y,iw,lh); x+=iw;
+    sick_fp.setGeometry(x,y,iw,lh); x+=iw;
+    sick_il.setGeometry(x,y,iw,lh); x+=iw;
+    blind.setGeometry(x,y,iw,lh); x+=iw;
+    stunned.setGeometry(x,y,iw,lh); x+=iw;
+    hallu.setGeometry(x,y,iw,lh); x+=iw;
+    encumber.setGeometry(x,y,iw,lh); x+=iw;
+    x=0; y+=lh;
+}
+
+
+/*
+ * Set all widget values to a null string.  This is used after all spacings
+ * have been calculated so that when the window is popped up we don't get all
+ * kinds of funny values being displayed.
+ */
+void NetHackQtStatusWindow::nullOut()
+{
+}
+
+void NetHackQtStatusWindow::fadeHighlighting()
+{
+    name.dissipateHighlight();
+    dlevel.dissipateHighlight();
+
+    str.dissipateHighlight();
+    dex.dissipateHighlight();
+    con.dissipateHighlight();
+    intel.dissipateHighlight();
+    wis.dissipateHighlight();
+    cha.dissipateHighlight();
+
+    gold.dissipateHighlight();
+    hp.dissipateHighlight();
+    power.dissipateHighlight();
+    ac.dissipateHighlight();
+    level.dissipateHighlight();
+    exp.dissipateHighlight();
+    align.dissipateHighlight();
+
+    time.dissipateHighlight();
+    score.dissipateHighlight();
+
+    hunger.dissipateHighlight();
+    confused.dissipateHighlight();
+    sick_fp.dissipateHighlight();
+    sick_il.dissipateHighlight();
+    blind.dissipateHighlight();
+    stunned.dissipateHighlight();
+    hallu.dissipateHighlight();
+    encumber.dissipateHighlight();
+}
+
+/*
+ * Update the displayed status.  The current code in botl.c updates
+ * two lines of information.  Both lines are always updated one after
+ * the other.  So only do our update when we update the second line.
+ *
+ * Information on the first line:
+ *    name, attributes, alignment, score
+ *
+ * Information on the second line:
+ *    dlvl, gold, hp, power, ac, {level & exp or HD **}
+ *    status (hunger, conf, halu, stun, sick, blind), time, encumbrance
+ *
+ * [**] HD is shown instead of level and exp if mtimedone is non-zero.
+ */
+void NetHackQtStatusWindow::updateStats()
+{
+    if (!parentWidget()) return;
+
+    char buf[BUFSZ];
+
+    if (cursy != 0) return;    /* do a complete update when line 0 is done */
+
+    if (ACURR(A_STR) > 118) {
+       Sprintf(buf,"STR:%d",ACURR(A_STR)-100);
+    } else if (ACURR(A_STR)==118) {
+       Sprintf(buf,"STR:18/**");
+    } else if(ACURR(A_STR) > 18) {
+       Sprintf(buf,"STR:18/%02d",ACURR(A_STR)-18);
+    } else {
+       Sprintf(buf,"STR:%d",ACURR(A_STR));
+    }
+    str.setLabel(buf,NetHackQtLabelledIcon::NoNum,ACURR(A_STR));
+
+    dex.setLabel("DEX:",(long)ACURR(A_DEX));
+    con.setLabel("CON:",(long)ACURR(A_CON));
+    intel.setLabel("INT:",(long)ACURR(A_INT));
+    wis.setLabel("WIS:",(long)ACURR(A_WIS));
+    cha.setLabel("CHA:",(long)ACURR(A_CHA));
+    const char* hung=hu_stat[u.uhs];
+    if (hung[0]==' ') {
+       hunger.hide();
+    } else {
+       hunger.setIcon(u.uhs ? p_hungry : p_satiated);
+       hunger.setLabel(hung);
+       hunger.show();
+    }
+    if (Confusion) confused.show(); else confused.hide();
+    if (Sick) {
+       if (u.usick_type & SICK_VOMITABLE) {
+           sick_fp.show();
+       } else {
+           sick_fp.hide();
+       }
+       if (u.usick_type & SICK_NONVOMITABLE) {
+           sick_il.show();
+       } else {
+           sick_il.hide();
+       }
+    } else {
+       sick_fp.hide();
+       sick_il.hide();
+    }
+    if (Blind) blind.show(); else blind.hide();
+    if (Stunned) stunned.show(); else stunned.hide();
+    if (Hallucination) hallu.show(); else hallu.hide();
+    const char* enc=enc_stat[near_capacity()];
+    if (enc[0]==' ' || !enc[0]) {
+       encumber.hide();
+    } else {
+       encumber.setIcon(p_encumber[near_capacity()-1]);
+       encumber.setLabel(enc);
+       encumber.show();
+    }
+    Strcpy(buf, plname);
+    if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a';
+    Strcat(buf, " the ");
+    if (u.mtimedone) {
+       char mname[BUFSZ];
+       int k = 0;
+
+       Strcpy(mname, mons[u.umonnum].mname);
+       while(mname[k] != 0) {
+           if ((k == 0 || (k > 0 && mname[k-1] == ' '))
+            && 'a' <= mname[k] && mname[k] <= 'z')
+           {
+               mname[k] += 'A' - 'a';
+           }
+           k++;
+       }
+       Strcat(buf, mname);
+    } else {
+       Strcat(buf, rank_of(u.ulevel, pl_character[0], ::flags.female));
+    }
+    name.setLabel(buf,NetHackQtLabelledIcon::NoNum,u.ulevel);
+
+    if (describe_level(buf)) {
+       dlevel.setLabel(buf,(bool)TRUE);
+    } else {
+       Sprintf(buf, "%s, level ", dungeons[u.uz.dnum].dname);
+       dlevel.setLabel(buf,(long)depth(&u.uz));
+    }
+
+#ifndef GOLDOBJ
+    gold.setLabel("Au:", u.ugold);
+#else
+    gold.setLabel("Au:", money_cnt(invent));
+#endif
+    if (u.mtimedone) {
+       // You're a monster!
+
+       Sprintf(buf, "/%d", u.mhmax);
+       hp.setLabel("HP:",u.mh  > 0 ? u.mh  : 0,buf);
+       level.setLabel("HD:",(long)mons[u.umonnum].mlevel);
+    } else {
+       // You're normal.
+
+       Sprintf(buf, "/%d", u.uhpmax);
+       hp.setLabel("HP:",u.uhp > 0 ? u.uhp : 0,buf);
+       level.setLabel("Level:",(long)u.ulevel);
+    }
+    Sprintf(buf, "/%d", u.uenmax);
+    power.setLabel("Pow:",u.uen,buf);
+    ac.setLabel("AC:",(long)u.uac);
+#ifdef EXP_ON_BOTL
+    if (::flags.showexp) {
+       exp.setLabel("Exp:",(long)u.uexp);
+    } else
+#endif
+    {
+       exp.setLabel("");
+    }
+    if (u.ualign.type==A_CHAOTIC) {
+       align.setIcon(p_chaotic);
+       align.setLabel("Chaotic");
+    } else if (u.ualign.type==A_NEUTRAL) {
+       align.setIcon(p_neutral);
+       align.setLabel("Neutral");
+    } else {
+       align.setIcon(p_lawful);
+       align.setLabel("Lawful");
+    }
+
+    if (::flags.time) time.setLabel("Time:",(long)moves);
+    else time.setLabel("");
+#ifdef SCORE_ON_BOTL
+    if (::flags.showscore) {
+       score.setLabel("Score:",(long)botl_score());
+    } else
+#endif
+    {
+       score.setLabel("");
+    }
+
+    if (first_set)
+    {
+       first_set=FALSE;
+
+       name.highlightWhenChanging();
+       dlevel.highlightWhenChanging();
+
+       str.highlightWhenChanging();
+       dex.highlightWhenChanging();
+       con.highlightWhenChanging();
+       intel.highlightWhenChanging();
+       wis.highlightWhenChanging();
+       cha.highlightWhenChanging();
+
+       gold.highlightWhenChanging();
+       hp.highlightWhenChanging();
+       power.highlightWhenChanging();
+       ac.highlightWhenChanging(); ac.lowIsGood();
+       level.highlightWhenChanging();
+       exp.highlightWhenChanging();
+       align.highlightWhenChanging();
+
+       //time.highlightWhenChanging();
+       score.highlightWhenChanging();
+
+       hunger.highlightWhenChanging();
+       confused.highlightWhenChanging();
+       sick_fp.highlightWhenChanging();
+       sick_il.highlightWhenChanging();
+       blind.highlightWhenChanging();
+       stunned.highlightWhenChanging();
+       hallu.highlightWhenChanging();
+       encumber.highlightWhenChanging();
+    }
+}
+
+/*
+ * Turn off hilighted status values after a certain amount of turns.
+ */
+void NetHackQtStatusWindow::checkTurnEvents()
+{
+}
+
+
+
+NetHackQtMenuDialog::NetHackQtMenuDialog() :
+    QDialog(qApp->mainWidget(),0,FALSE)
+{
+}
+
+void NetHackQtMenuDialog::resizeEvent(QResizeEvent*)
+{
+    emit Resized();
+}
+
+void NetHackQtMenuDialog::Accept()
+{
+    accept();
+}
+
+void NetHackQtMenuDialog::Reject()
+{
+    reject();
+}
+
+void NetHackQtMenuDialog::SetResult(int r)
+{
+    setResult(r);
+}
+
+void NetHackQtMenuDialog::done(int i)
+{
+    setResult(i);
+    qApp->exit_loop();
+}
+
+// Table view columns:
+// 
+// [pick-count] [accel] [glyph] [string]
+// 
+// Maybe accel should be near string.  We'll see.
+// pick-count normally blank.
+//   double-clicking or click-on-count gives pop-up entry
+// string is green when selected
+//
+NetHackQtMenuWindow::NetHackQtMenuWindow(NetHackQtKeyBuffer& ks) :
+    QTableView(),
+    keysource(ks),
+    dialog(new NetHackQtMenuDialog()),
+    prompt(0),
+    pressed(-1)
+{
+    setNumCols(4);
+    setCellHeight(QMAX(qt_settings->glyphs().height()+1,fontMetrics().height()));
+    setBackgroundColor(lightGray);
+    setFrameStyle(Panel|Sunken);
+    setLineWidth(2);
+
+    ok=new QPushButton("Ok",dialog);
+    connect(ok,SIGNAL(clicked()),dialog,SLOT(accept()));
+
+    cancel=new QPushButton("Cancel",dialog);
+    connect(cancel,SIGNAL(clicked()),dialog,SLOT(reject()));
+
+    all=new QPushButton("All",dialog);
+    connect(all,SIGNAL(clicked()),this,SLOT(All()));
+
+    none=new QPushButton("None",dialog);
+    connect(none,SIGNAL(clicked()),this,SLOT(ChooseNone()));
+
+    invert=new QPushButton("Invert",dialog);
+    connect(invert,SIGNAL(clicked()),this,SLOT(Invert()));
+
+    search=new QPushButton("Search",dialog);
+    connect(search,SIGNAL(clicked()),this,SLOT(Search()));
+
+    QPoint pos(0,ok->height());
+    recreate(dialog,0,pos);
+    prompt.recreate(dialog,0,pos);
+
+    setBackgroundColor(lightGray);
+
+    connect(dialog,SIGNAL(Resized()),this,SLOT(Layout()));
+
+    setTableFlags(Tbl_autoHScrollBar|Tbl_autoVScrollBar
+           |Tbl_smoothScrolling|Tbl_clipCellPainting);
+    setFocusPolicy(StrongFocus);
+}
+
+NetHackQtMenuWindow::~NetHackQtMenuWindow()
+{
+    // Remove from dialog before we destruct it
+    recreate(0,0,QPoint(0,0));
+    delete dialog;
+}
+
+void NetHackQtMenuWindow::focusInEvent(QFocusEvent *)
+{
+    // Don't repaint at all, since nothing is using the focus colour
+}
+void NetHackQtMenuWindow::focusOutEvent(QFocusEvent *)
+{
+    // Don't repaint at all, since nothing is using the focus colour
+}
+
+int NetHackQtMenuWindow::cellWidth(int col)
+{
+    switch (col) {
+     case 0:
+       return fontMetrics().width("All ");
+    break; case 1:
+       return fontMetrics().width(" m ");
+    break; case 2:
+       return qt_settings->glyphs().width();
+    break; case 3:
+       return str_width;
+    }
+    impossible("Extra column (#%d) in MenuWindow",col);
+    return 0;
+}
+
+QWidget* NetHackQtMenuWindow::Widget() { return dialog; }
+
+void NetHackQtMenuWindow::StartMenu()
+{
+    setNumRows((itemcount=0));
+    str_width=200;
+    str_fixed=FALSE;
+    next_accel=0;
+    has_glyphs=FALSE;
+}
+
+NetHackQtMenuWindow::MenuItem::MenuItem() :
+    str(0)
+{
+}
+
+NetHackQtMenuWindow::MenuItem::~MenuItem()
+{
+    if (str) free((void*)str);
+}
+
+#define STR_MARGIN 4
+
+void NetHackQtMenuWindow::AddMenu(int glyph, const ANY_P* identifier,
+       char ch, char gch, int attr, const char* str, bool presel)
+{
+    if (!ch && identifier->a_void!=0) {
+       // Supply a keyboard accelerator.  Limited supply.
+       static char accel[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+       if (accel[next_accel]) {
+           ch=accel[next_accel++];
+       }
+    }
+
+    if ((int)item.size() < itemcount+1) {
+       item.resize(itemcount*4+10);
+    }
+    item[itemcount].glyph=glyph;
+    item[itemcount].identifier=*identifier;
+    item[itemcount].ch=ch;
+    item[itemcount].attr=attr;
+    item[itemcount].str=strdup(str);
+    item[itemcount].selected=presel;
+    item[itemcount].count=-1;
+    ++itemcount;
+
+    str_fixed=str_fixed || strstr(str,"     ");
+    if (glyph!=NO_GLYPH) has_glyphs=TRUE;
+}
+void NetHackQtMenuWindow::EndMenu(const char* p)
+{
+    prompt.setText(p ? p : "");
+}
+void NetHackQtMenuWindow::Layout()
+{
+    int butw=totalWidth()/6; // 6 buttons
+    int buth=fontMetrics().height()+8; // 8 for spacing & mitres
+    int prompth=(prompt.text().isNull() ? 0 : buth);
+
+    prompt.setGeometry(6,buth,dialog->width()-6,prompth);
+    int h=dialog->height()-buth-prompth;
+    setGeometry(0,buth+prompth, dialog->width(), h);
+
+    // Below, we take care to use up full width
+    int x=0;
+    ok->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/5;
+    cancel->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/4;
+    all->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/3;
+    none->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/2;
+    invert->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/1;
+    search->setGeometry(x,0,butw,buth);
+}
+int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list)
+{
+    setFont(str_fixed ?
+       qt_settings->normalFixedFont() : qt_settings->normalFont());
+
+    for (int i=0; i<itemcount; i++) {
+       str_width=QMAX(str_width,
+           STR_MARGIN+fontMetrics().width(item[i].str));
+    }
+
+    setCellHeight(QMAX(qt_settings->glyphs().height()+1,fontMetrics().height()));
+    setNumRows(itemcount);
+
+    int buth=fontMetrics().height()+8; // 8 for spacing & mitres
+
+    how=h;
+
+    ok->setEnabled(how!=PICK_ONE);ok->setDefault(how!=PICK_ONE);
+    cancel->setEnabled(how!=PICK_NONE);
+    all->setEnabled(how==PICK_ANY);
+    none->setEnabled(how==PICK_ANY);
+    invert->setEnabled(how==PICK_ANY);
+    search->setEnabled(how!=PICK_NONE);
+
+    dialog->SetResult(-1);
+
+    // 20 allows for scrollbar or spacing
+    // 4 for frame borders
+    int mh = QApplication::desktop()->height()*3/5;
+    if ( qt_compact_mode && totalHeight() > mh ) {
+       // big, so make it fill
+       dialog->showMaximized();
+    } else {
+       dialog->resize(totalWidth()+20,
+           QMIN(totalHeight(), mh)+buth+4+(prompt.text().isNull() ? 0 : buth));
+       if ( dialog->width() > QApplication::desktop()->width() )
+           dialog->resize(QApplication::desktop()->width(),dialog->height()+16);
+       centerOnMain(dialog);
+       dialog->show();
+    }
+
+    setFocus();
+    while (dialog->result()<0) {
+       // changed the defaults below to the values in wintype.h 000119 - azy
+       if (!keysource.Empty()) {
+           char k=keysource.GetAscii();
+           k=map_menu_cmd(k); /* added 000119 - azy */
+           if (k=='\033')
+               dialog->Reject();
+           else if (k=='\r' || k=='\n' || k==' ')
+               dialog->Accept();
+           else if (k==MENU_SEARCH)
+               Search();
+           else if (k==MENU_SELECT_ALL)
+               All();
+           else if (k==MENU_INVERT_ALL)
+               Invert();
+           else if (k==MENU_UNSELECT_ALL)
+               ChooseNone();
+           else {
+               for (int i=0; i<itemcount; i++) {
+                   if (item[i].ch==k)
+                       ToggleSelect(i);
+               }
+           }
+       }
+       if (dialog->result()<0)
+           qApp->enter_loop();
+    }
+    //if ( (nhid != WIN_INVEN || !flags.perm_invent) ) // doesn't work yet
+    {
+       dialog->hide();
+    }
+    int result=dialog->result();
+
+    // Consume ^M (which QDialog steals for default button)
+    while (!keysource.Empty() &&
+       (keysource.TopAscii()=='\n' || keysource.TopAscii()=='\r'))
+       keysource.GetAscii();
+
+    *menu_list=0;
+    if (result>0 && how!=PICK_NONE) {
+       if (how==PICK_ONE) {
+           int i;
+           for (i=0; i<itemcount && !item[i].selected; i++)
+               ;
+           if (i<itemcount) {
+               *menu_list=(MENU_ITEM_P*)malloc(sizeof(MENU_ITEM_P));
+               (*menu_list)[0].item=item[i].identifier;
+               (*menu_list)[0].count=item[i].count;
+               return 1;
+           } else {
+               return 0;
+           }
+       } else {
+           int count=0;
+           for (int i=0; i<itemcount; i++)
+               if (item[i].selected) count++;
+           if (count) {
+               *menu_list=(MENU_ITEM_P*)malloc(count*sizeof(MENU_ITEM_P));
+               int j=0;
+               for (int i=0; i<itemcount; i++) {
+                   if (item[i].selected) {
+                       (*menu_list)[j].item=item[i].identifier;
+                       (*menu_list)[j].count=item[i].count;
+                       j++;
+                   }
+               }
+               return count;
+           } else {
+               return 0;
+           }
+       }
+    } else {
+       return -1;
+    }
+}
+void NetHackQtMenuWindow::keyPressEvent(QKeyEvent* event)
+{
+    if (viewHeight() < totalHeight() && !(event->state()&ShiftButton)) {
+       if (event->key()==Key_Prior) {
+           setYOffset(yOffset()-viewHeight());
+       } else if (event->key()==Key_Next) {
+           setYOffset(yOffset()+viewHeight());
+       } else {
+           event->ignore();
+       }
+    } else {
+       event->ignore();
+    }
+}
+
+void NetHackQtMenuWindow::All()
+{
+    for (int i=0; i<itemcount; i++) {
+       if (!item[i].selected) ToggleSelect(i);
+    }
+}
+void NetHackQtMenuWindow::ChooseNone()
+{
+    for (int i=0; i<itemcount; i++) {
+       if (item[i].selected) ToggleSelect(i);
+    }
+}
+void NetHackQtMenuWindow::Invert()
+{
+    for (int i=0; i<itemcount; i++) {
+       ToggleSelect(i);
+    }
+}
+void NetHackQtMenuWindow::Search()
+{
+    NetHackQtStringRequestor requestor(keysource,"Search for:");
+    char line[256];
+    if (requestor.Get(line)) {
+       for (int i=0; i<itemcount; i++) {
+           if (strstr(item[i].str,line))
+               ToggleSelect(i);
+       }
+    }
+}
+void NetHackQtMenuWindow::ToggleSelect(int i)
+{
+    if (item[i].Selectable()) {
+       item[i].selected = !item[i].selected;
+       if ( !item[i].selected )
+           item[i].count=-1;
+       updateCell(i,3);
+       if (how==PICK_ONE) {
+           dialog->Accept();
+       }
+    }
+}
+
+
+void NetHackQtMenuWindow::paintCell(QPainter* painter, int row, int col)
+{
+    // [pick-count] [accel] [glyph] [string]
+
+    MenuItem& i = item[row];
+
+    painter->setPen(black);
+    painter->setFont(font());
+
+    if (i.selected) {
+       painter->setPen(darkGreen);
+    }
+
+    switch (col) {
+     case 0:
+       if ( i.ch || i.attr!=ATR_INVERSE ) {
+           QString text;
+           if ( i.selected && i.count == -1 ) {
+               if ( i.str[0]>='0' && i.str[0]<='9' )
+                   text = "All";
+               else
+                   text = "*";
+           } else if ( i.count<0 ) {
+               text = "-";
+           } else {
+               text.sprintf("%d",i.count);
+           }
+           painter->drawText(0,0,cellWidth(col),cellHeight(),
+           AlignHCenter|AlignVCenter,text);
+       }
+    break; case 1:
+       if ((signed char)i.ch >= 0) {
+           char text[2]={i.ch,0};
+           painter->drawText(0,0,cellWidth(col),cellHeight(),
+               AlignHCenter|AlignVCenter,text);
+       }
+    break; case 2:
+       if (i.glyph!=NO_GLYPH) {
+           // Centered in height
+           int y=(cellHeight()-qt_settings->glyphs().height())/2;
+           if (y<0) y=0;
+           qt_settings->glyphs().drawGlyph(*painter, i.glyph, 0, y);
+       }
+    break; case 3:
+       // XXX should qt_settings have ALL the various fonts
+       QFont newfont=font();
+
+       if (i.attr) {
+           switch(i.attr) {
+            case ATR_ULINE:
+               newfont.setUnderline(TRUE);
+           break; case ATR_BOLD:
+               painter->setPen(red);
+           break; case ATR_BLINK:
+               newfont.setItalic(TRUE);
+           break; case ATR_INVERSE:
+               newfont=qt_settings->largeFont();
+               newfont.setWeight(QFont::Bold);
+
+               if (i.selected) {
+                   painter->setPen(blue);
+               } else {
+                   painter->setPen(darkBlue);
+               }
+           }
+       }
+       painter->setFont(newfont);
+
+       painter->drawText(STR_MARGIN,0,cellWidth(col),cellHeight(),
+           AlignLeft|AlignVCenter,i.str);
+    }
+}
+
+void NetHackQtMenuWindow::mousePressEvent(QMouseEvent* event)
+{
+    int col=findCol(event->pos().x());
+    int row=findRow(event->pos().y());
+
+    if (col<0 || row<0 || !item[row].Selectable()) return;
+
+    if (how!=PICK_NONE) {
+       if (col==0) {
+           // Changing count.
+           NetHackQtStringRequestor requestor(keysource,"Count:");
+           char buf[BUFSZ];
+
+           if (item[row].count>0)
+               Sprintf(buf,"%d", item[row].count);
+           else
+               Strcpy(buf, "");
+
+           requestor.SetDefault(buf);
+           if (requestor.Get(buf)) {
+               item[row].count=atoi(buf);
+               if (item[row].count==0) {
+                   item[row].count=-1;
+                   if (item[row].selected) ToggleSelect(row);
+               } else {
+                   if (!item[row].selected) ToggleSelect(row);
+               }
+               updateCell(row,0);
+           }
+       } else {
+           pressed=row;
+           was_sel=item[row].selected;
+           ToggleSelect(row);
+           updateCell(row,0);
+       }
+    }
+}
+void NetHackQtMenuWindow::mouseReleaseEvent(QMouseEvent* event)
+{
+    if (pressed>=0) {
+       int p=pressed;
+       pressed=-1;
+       updateCell(p,3);
+    }
+}
+void NetHackQtMenuWindow::mouseMoveEvent(QMouseEvent* event)
+{
+    if (pressed>=0) {
+       int col=findCol(event->pos().x());
+       int row=findRow(event->pos().y());
+
+       if (row>=0 && col>=0) {
+           if (pressed!=row) {
+               // reset to initial state
+               if (item[pressed].selected!=was_sel)
+                   ToggleSelect(pressed);
+           } else {
+               // reset to new state
+               if (item[pressed].selected==was_sel)
+                   ToggleSelect(pressed);
+           }
+       }
+    }
+}
+
+
+class NetHackQtTextListBox : public QListBox {
+public:
+    NetHackQtTextListBox(QWidget* parent) : QListBox(parent) { }
+
+    int TotalWidth()
+    {
+       doLayout();
+       return contentsWidth();
+    }
+    int TotalHeight()
+    {
+       doLayout();
+       return contentsHeight();
+    }
+
+    virtual void setFont(const QFont &font)
+    {
+       QListBox::setFont(font);
+    }
+    void keyPressEvent(QKeyEvent* e)
+    {
+       QListBox::keyPressEvent(e);
+    }
+};
+
+
+QPixmap* NetHackQtRIP::pixmap=0;
+
+NetHackQtRIP::NetHackQtRIP(QWidget* parent) :
+    QWidget(parent)
+{
+    if (!pixmap) {
+       pixmap=new QPixmap;
+       tryload(*pixmap, "rip.xpm");
+    }
+    riplines=0;
+    resize(pixmap->width(),pixmap->height());
+    setFont(QFont("times",12)); // XXX may need to be configurable
+}
+
+void NetHackQtRIP::setLines(char** l, int n)
+{
+    line=l;
+    riplines=n;
+}
+
+QSize NetHackQtRIP::sizeHint() const
+{
+    return pixmap->size();
+}
+
+void NetHackQtRIP::paintEvent(QPaintEvent* event)
+{
+    if ( riplines ) {
+       int pix_x=(width()-pixmap->width())/2;
+       int pix_y=(height()-pixmap->height())/2;
+
+       // XXX positions based on RIP image
+       int rip_text_x=pix_x+156;
+       int rip_text_y=pix_y+67;
+       int rip_text_h=94/riplines;
+
+       QPainter painter;
+       painter.begin(this);
+       painter.drawPixmap(pix_x,pix_y,*pixmap);
+       for (int i=0; i<riplines; i++) {
+           painter.drawText(rip_text_x-i/2,rip_text_y+i*rip_text_h,
+               1,1,DontClip|AlignHCenter,line[i]);
+       }
+       painter.end();
+    }
+}
+
+NetHackQtTextWindow::NetHackQtTextWindow(NetHackQtKeyBuffer& ks) :
+    QDialog(qApp->mainWidget(),0,FALSE),
+    keysource(ks),
+    use_rip(FALSE),
+    str_fixed(FALSE),
+    ok("Dismiss",this),
+    search("Search",this),
+    lines(new NetHackQtTextListBox(this)),
+    rip(this)
+{
+    ok.setDefault(TRUE);
+    connect(&ok,SIGNAL(clicked()),this,SLOT(accept()));
+    connect(&search,SIGNAL(clicked()),this,SLOT(Search()));
+    connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate()));
+
+    QVBoxLayout* vb = new QVBoxLayout(this);
+    vb->addWidget(&rip);
+    QHBoxLayout* hb = new QHBoxLayout(vb);
+    hb->addWidget(&ok);
+    hb->addWidget(&search);
+    vb->addWidget(lines);
+}
+
+void NetHackQtTextWindow::doUpdate()
+{
+    update();
+}
+
+
+NetHackQtTextWindow::~NetHackQtTextWindow()
+{
+
+}
+
+QWidget* NetHackQtTextWindow::Widget()
+{
+    return this;
+}
+
+bool NetHackQtTextWindow::Destroy()
+{
+    return !isVisible();
+}
+
+void NetHackQtTextWindow::UseRIP(int how)
+{
+// Code from X11 windowport
+#define STONE_LINE_LEN 16    /* # chars that fit on one line */
+#define NAME_LINE 0    /* line # for player name */
+#define GOLD_LINE 1    /* line # for amount of gold */
+#define DEATH_LINE 2   /* line # for death description */
+#define YEAR_LINE 6    /* line # for year */
+
+static char** rip_line=0;
+    if (!rip_line) {
+       rip_line=new char*[YEAR_LINE+1];
+       for (int i=0; i<YEAR_LINE+1; i++) {
+           rip_line[i]=new char[STONE_LINE_LEN+1];
+       }
+    }
+
+    /* Follows same algorithm as genl_outrip() */
+
+    char buf[BUFSZ];
+    char *dpx;
+    int line;
+
+    /* Put name on stone */
+    Sprintf(rip_line[NAME_LINE], "%s", plname);
+
+    /* Put $ on stone */
+#ifndef GOLDOBJ
+    Sprintf(rip_line[GOLD_LINE], "%ld Au", u.ugold);
+#else
+    Sprintf(rip_line[GOLD_LINE], "%ld Au", done_money);
+#endif
+
+    /* Put together death description */
+    switch (killer_format) {
+       default: impossible("bad killer format?");
+       case KILLED_BY_AN:
+           Strcpy(buf, killed_by_prefix[how]);
+           Strcat(buf, an(killer));
+           break;
+       case KILLED_BY:
+           Strcpy(buf, killed_by_prefix[how]);
+           Strcat(buf, killer);
+           break;
+       case NO_KILLER_PREFIX:
+           Strcpy(buf, killer);
+           break;
+    }
+
+    /* Put death type on stone */
+    for (line=DEATH_LINE, dpx = buf; line<YEAR_LINE; line++) {
+       register int i,i0;
+       char tmpchar;
+
+       if ( (i0=strlen(dpx)) > STONE_LINE_LEN) {
+           for(i = STONE_LINE_LEN;
+               ((i0 > STONE_LINE_LEN) && i); i--)
+               if(dpx[i] == ' ') i0 = i;
+           if(!i) i0 = STONE_LINE_LEN;
+       }
+       tmpchar = dpx[i0];
+       dpx[i0] = 0;
+       strcpy(rip_line[line], dpx);
+       if (tmpchar != ' ') {
+           dpx[i0] = tmpchar;
+           dpx= &dpx[i0];
+       } else  dpx= &dpx[i0+1];
+    }
+
+    /* Put year on stone */
+    Sprintf(rip_line[YEAR_LINE], "%4d", getyear());
+
+    rip.setLines(rip_line,YEAR_LINE+1);
+
+    use_rip=TRUE;
+}
+
+void NetHackQtTextWindow::Clear()
+{
+    lines->clear();
+    use_rip=FALSE;
+    str_fixed=FALSE;
+}
+
+void NetHackQtTextWindow::Display(bool block)
+{
+    if (str_fixed) {
+       lines->setFont(qt_settings->normalFixedFont());
+    } else {
+       lines->setFont(qt_settings->normalFont());
+    }
+
+    int h=0;
+    if (use_rip) {
+       h+=rip.height();
+       ok.hide();
+       search.hide();
+       rip.show();
+    } else {
+       h+=ok.height()*2;
+       ok.show();
+       search.show();
+       rip.hide();
+    }
+    int mh = QApplication::desktop()->height()*3/5;
+    if ( qt_compact_mode && lines->TotalHeight() > mh || use_rip ) {
+       // big, so make it fill
+       showMaximized();
+    } else {
+       resize(QMAX(use_rip ? rip.width() : 200,
+               lines->TotalWidth()+24),
+           QMIN(mh, lines->TotalHeight()+h));
+       centerOnMain(this);
+       show();
+    }
+    if (block) {
+       setResult(-1);
+       while (result()==-1) {
+           qApp->enter_loop();
+           if (result()==-1 && !keysource.Empty()) {
+               char k=keysource.GetAscii();
+               if (k=='\033' || k==' ' || k=='\r' || k=='\n') {
+                   accept();
+               } else if (k=='/') {
+                   Search();
+               }
+           }
+       }
+    }
+}
+
+void NetHackQtTextWindow::PutStr(int attr, const char* text)
+{
+    str_fixed=str_fixed || strstr(text,"    ");
+    lines->insertItem(text);
+}
+
+void NetHackQtTextWindow::done(int i)
+{
+    setResult(i+1000);
+    hide();
+    qApp->exit_loop();
+}
+
+void NetHackQtTextWindow::keyPressEvent(QKeyEvent* e)
+{
+    if ( e->ascii() != '\r' && e->ascii() != '\n' && e->ascii() != '\033' )
+       lines->keyPressEvent(e);
+    else
+       QDialog::keyPressEvent(e);
+}
+
+void NetHackQtTextWindow::Search()
+{
+    NetHackQtStringRequestor requestor(keysource,"Search for:");
+    static char line[256]="";
+    requestor.SetDefault(line);
+    if (requestor.Get(line)) {
+       int current=lines->currentItem();
+       for (uint i=1; i<lines->count(); i++) {
+           int lnum=(i+current)%lines->count();
+           QString str=lines->text(lnum);
+           if (str.contains(line)) {
+               lines->setCurrentItem(lnum);
+               lines->centerCurrentItem();
+               return;
+           }
+       }
+       lines->setCurrentItem(-1);
+    }
+}
+
+
+NetHackQtDelay::NetHackQtDelay(int ms) :
+    msec(ms)
+{
+}
+
+void NetHackQtDelay::wait()
+{
+    startTimer(msec);
+    qApp->enter_loop();
+}
+
+void NetHackQtDelay::timerEvent(QTimerEvent* timer)
+{
+    qApp->exit_loop();
+    killTimers();
+}
+
+NetHackQtInvUsageWindow::NetHackQtInvUsageWindow(QWidget* parent) :
+    QWidget(parent)
+{
+}
+
+void NetHackQtInvUsageWindow::drawWorn(QPainter& painter, obj* nhobj, int x, int y, bool canbe)
+{
+    short int glyph;
+    if (nhobj)
+       glyph=obj_to_glyph(nhobj);
+    else if (canbe)
+       glyph=cmap_to_glyph(S_room);
+    else
+       glyph=cmap_to_glyph(S_stone);
+
+    qt_settings->glyphs().drawCell(painter,glyph,x,y);
+}
+
+void NetHackQtInvUsageWindow::paintEvent(QPaintEvent*)
+{
+    //  012
+    //
+    //0 WhB   
+    //1 s"w   
+    //2 gCg   
+    //3 =A=   
+    //4  T    
+    //5  S    
+
+    QPainter painter;
+    painter.begin(this);
+
+    // Blanks
+    drawWorn(painter,0,0,4,FALSE);
+    drawWorn(painter,0,0,5,FALSE);
+    drawWorn(painter,0,2,4,FALSE);
+    drawWorn(painter,0,2,5,FALSE);
+
+    drawWorn(painter,uarm,1,3); // Armour
+    drawWorn(painter,uarmc,1,2); // Cloak
+    drawWorn(painter,uarmh,1,0); // Helmet
+    drawWorn(painter,uarms,0,1); // Shield
+    drawWorn(painter,uarmg,0,2); // Gloves - repeated
+    drawWorn(painter,uarmg,2,2); // Gloves - repeated
+#ifdef TOURIST
+    drawWorn(painter,uarmf,1,5); // Shoes (feet)
+    drawWorn(painter,uarmu,1,4); // Undershirt
+#else
+    drawWorn(painter,0    ,1,5,FALSE);
+    drawWorn(painter,uarmf,1,4); // Shoes (feet)
+#endif
+    drawWorn(painter,uleft,0,3); // RingL
+    drawWorn(painter,uright,2,3); // RingR
+
+    drawWorn(painter,uwep,2,1); // Weapon
+    drawWorn(painter,uswapwep,0,0); // Secondary weapon
+    drawWorn(painter,uamul,1,1); // Amulet
+    drawWorn(painter,ublindf,2,0); // Blindfold
+
+    painter.end();
+}
+
+class SmallToolButton : public QToolButton {
+public:
+    SmallToolButton(const QPixmap & pm, const QString &textLabel,
+                 const QString& grouptext,
+                 QObject * receiver, const char* slot,
+                 QToolBar * parent) :
+       QToolButton(pm, textLabel,
+#if QT_VERSION < 210
+               QString::null,
+#else
+               grouptext,
+#endif
+                   receiver, slot, parent)
+    {
+    }
+
+    QSize sizeHint() const
+    {
+       // get just a couple more pixels for the map
+       return QToolButton::sizeHint()-QSize(0,2);
+    }
+};
+
+
+NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) :
+    message(0), map(0), status(0), invusage(0),
+    keysink(ks), dirkey(0)
+{
+    QToolBar* toolbar = new QToolBar(this);
+#if QT_VERSION >= 210
+    setToolBarsMovable(FALSE);
+    toolbar->setHorizontalStretchable(TRUE);
+    toolbar->setVerticalStretchable(TRUE);
+#endif
+    addToolBar(toolbar);
+    menubar = menuBar();
+
+    setCaption("Qt NetHack");
+    if ( qt_compact_mode )
+       setIcon(QPixmap(nh_icon_small));
+    else
+       setIcon(QPixmap(nh_icon));
+
+    QPopupMenu* game=new QPopupMenu;
+    QPopupMenu* apparel=new QPopupMenu;
+    QPopupMenu* act1=new QPopupMenu;
+    QPopupMenu* act2 = qt_compact_mode ? new QPopupMenu : act1;
+    QPopupMenu* magic=new QPopupMenu;
+    QPopupMenu* info=new QPopupMenu;
+
+    QPopupMenu *help;
+
+#ifdef KDE
+    help = kapp->getHelpMenu( TRUE, "" );
+    help->insertSeparator();
+#else
+    help = qt_compact_mode ? info : new QPopupMenu;
+#endif
+
+    enum { OnDesktop=1, OnHandhelds=2 };
+    struct Macro {
+       QPopupMenu* menu;
+       const char* name;
+       const char* action;
+       int flags;
+    } item[] = {
+       { game,         0, 0, 3},
+       { game,         "Version\tv",           "v", 3},
+       { game,         "Compilation\tAlt+V",     "\366", 3},
+       { game,         "History\tShift+V",           "V", 3},
+       { game,         "Redraw\tCtrl+R",          "\022", 0}, // useless
+       { game,         "Options\tShift+O",           "O", 3},
+       { game,         "Explore mode\tShift+X",      "X", 3},
+       { game,         0, 0, 3},
+       { game,         "Save\tSy",              "Sy", 3},
+       { game,         "Quit\tAlt+Q",                "\361", 3},
+
+       { apparel,      "Apparel off\tShift+A",       "A", 2},
+       { apparel,      "Remove many\tShift+A",       "A", 1},
+       { apparel,      0, 0, 3},
+       { apparel,      "Wield weapon\tw",      "w", 3},
+       { apparel,      "Exchange weapons\tx",      "x", 3},
+       { apparel,      "Two weapon combat\t#two",      "#tw", 3},
+       { apparel,      "Load quiver\tShift+Q",       "Q", 3},
+       { apparel,      0, 0, 3},
+       { apparel,      "Wear armour\tShift+W",       "W", 3},
+       { apparel,      "Take off armour\tShift+T",   "T", 3},
+       { apparel,      0, 0, 3},
+       { apparel,      "Put on non-armour\tShift+P", "P", 3},
+       { apparel,      "Remove non-armour\tShift+R", "R", 3},
+
+       { act1, "Again\tCtrl+A",           "\001", 2},
+       { act1, 0, 0, 3},
+       { act1, "Apply\ta?",            "a?", 3},
+       { act1, "Chat\tAlt+C",            "\343", 3},
+       { act1, "Close door\tc",        "c", 3},
+       { act1, "Down\t>",              ">", 3},
+       { act1, "Drop many\tShift+D",         "D", 2},
+       { act1, "Drop\td?",             "d?", 2},
+       { act1, "Eat\te?",              "e?", 2},
+       { act1, "Engrave\tShift+E",           "E", 3},
+       { act1, "Fight\tShift+F",             "F", 3},
+       { act1, "Fire from quiver\tf",  "f", 2},
+       { act1, "Force\tAlt+F",           "\346", 3},
+       { act1, "Get\t,",               ",", 2},
+       { act1, "Jump\tAlt+J",            "\352", 3},
+       { act2, "Kick\tCtrl+D",              "\004", 2},
+       { act2, "Loot\tAlt+L",            "\354", 3},
+       { act2, "Open door\to",         "o", 3},
+       { act2, "Pay\tp",               "p", 3},
+       { act2, "Rest\t.",              ".", 2},
+       { act2, "Ride\t#ri",            "#ri", 3},
+       { act2, "Search\ts",            "s", 3},
+       { act2, "Sit\tAlt+S",             "\363", 3},
+       { act2, "Throw\tt",             "t", 2},
+       { act2, "Untrap\t#u",             "#u", 3},
+       { act2, "Up\t<",                "<", 3},
+       { act2, "Wipe face\tAlt+W",       "\367", 3},
+
+       { magic,        "Quaff potion\tq?",     "q?", 3},
+       { magic,        "Read scroll/book\tr?", "r?", 3},
+       { magic,        "Zap wand\tz?",         "z?", 3},
+       { magic,        "Zap spell\tShift+Z",        "Z", 3},
+       { magic,        "Dip\tAlt+D",             "\344", 3},
+       { magic,        "Rub\tAlt+R",             "\362", 3},
+       { magic,        "Invoke\tAlt+I",          "\351", 3},
+       { magic,        0, 0, 3},
+       { magic,        "Offer\tAlt+O",           "\357", 3},
+       { magic,        "Pray\tAlt+P",            "\360", 3},
+       { magic,        0, 0, 3},
+       { magic,        "Teleport\tCtrl+T",        "\024", 3},
+       { magic,        "Monster action\tAlt+M",  "\355", 3},
+       { magic,        "Turn undead\tAlt+T",     "\364", 3},
+
+       { help,         "Help\t?",              "?", 3},
+       { help,         0, 0, 3},
+       { help,         "What is here\t:",      ":", 3},
+       { help,         "What is there\t;",      ";", 3},
+       { help,         "What is...\t/y",        "/y", 2},
+       { help,         0, 0, 1},
+
+       { info,         "Inventory\ti",         "i", 3},
+#ifdef SLASHEM
+       { info,         "Angbandish inventory\t*",    "*", 3},
+#endif
+       { info,         "Conduct\t#co",         "#co", 3},
+       { info,         "Discoveries\t\\",      "\\", 3},
+       { info,         "List/reorder spells\t+",     "+", 3},
+       { info,         "Adjust letters\tAlt+A",  "\341", 2},
+       { info,         0, 0, 3},
+       { info,         "Name object\tAlt+N",    "\356y?", 3},
+       { info,         "Name object type\tAlt+N",    "\356n?", 3},
+       { info,         "Name creature\tShift+C",      "C", 3},
+       { info,         0, 0, 3},
+       { info,         "Qualifications\tAlt+E",  "\345", 3},
+
+       { 0, 0, 0, 0 }
+    };
+
+    int i;
+    int count=0;
+    for (i=0; item[i].menu; i++)
+       if (item[i].name) count++;
+
+    macro=new const char* [count];
+
+    game->insertItem("Qt settings...",1000);
+    help->insertItem("About Qt NetHack...",2000);
+    //help->insertItem("NetHack Guidebook...",3000);
+    help->insertSeparator();
+
+    count=0;
+    for (i=0; item[i].menu; i++) {
+       if ( item[i].flags & (qt_compact_mode ? 1 : 2) ) {
+           if (item[i].name) {
+               QString name = item[i].name;
+               if ( qt_compact_mode ) // accelerators aren't
+                   name.replace(QRegExp("\t.*"),"");
+               item[i].menu->insertItem(name,count);
+               macro[count++]=item[i].action;
+           } else {
+               item[i].menu->insertSeparator();
+           }
+       }
+    }
+
+    menubar->insertItem("Game",game);
+    menubar->insertItem("Gear",apparel);
+
+    if ( qt_compact_mode ) {
+       menubar->insertItem("A-J",act1);
+       menubar->insertItem("K-Z",act2);
+       menubar->insertItem("Magic",magic);
+       menubar->insertItem(QPixmap(info_xpm),info);
+       menubar->insertItem(QPixmap(map_xpm), this, SLOT(raiseMap()));
+       menubar->insertItem(QPixmap(msg_xpm), this, SLOT(raiseMessages()));
+       menubar->insertItem(QPixmap(stat_xpm), this, SLOT(raiseStatus()));
+    } else {
+       menubar->insertItem("Action",act1);
+       menubar->insertItem("Magic",magic);
+       menubar->insertItem("Info",info);
+       menubar->insertSeparator();
+       menubar->insertItem("Help",help);
+    }
+
+    QSignalMapper* sm = new QSignalMapper(this);
+    connect(sm, SIGNAL(mapped(const QString&)), this, SLOT(doKeys(const QString&)));
+    QToolButton* tb;
+    tb = new SmallToolButton( QPixmap(again_xpm),"Again","Action", sm, SLOT(map()), toolbar );
+    sm->setMapping(tb, "\001" );
+    tb = new SmallToolButton( QPixmap(get_xpm),"Get","Action", sm, SLOT(map()), toolbar );
+    sm->setMapping(tb, "," );
+    tb = new SmallToolButton( QPixmap(kick_xpm),"Kick","Action", sm, SLOT(map()), toolbar );
+    sm->setMapping(tb, "\004" );
+    tb = new SmallToolButton( QPixmap(throw_xpm),"Throw","Action", sm, SLOT(map()), toolbar );
+    sm->setMapping(tb, "t" );
+    tb = new SmallToolButton( QPixmap(fire_xpm),"Fire","Action", sm, SLOT(map()), toolbar );
+    sm->setMapping(tb, "f" );
+    tb = new SmallToolButton( QPixmap(drop_xpm),"Drop","Action", sm, SLOT(map()), toolbar );
+    sm->setMapping(tb, "D" );
+    tb = new SmallToolButton( QPixmap(eat_xpm),"Eat","Action", sm, SLOT(map()), toolbar );
+    sm->setMapping(tb, "e" );
+    tb = new SmallToolButton( QPixmap(rest_xpm),"Rest","Action", sm, SLOT(map()), toolbar );
+    sm->setMapping(tb, "." );
+    tb = new SmallToolButton( QPixmap(cast_a_xpm),"Cast A","Magic", sm, SLOT(map()), toolbar );
+    sm->setMapping(tb, "Za" );
+    tb = new SmallToolButton( QPixmap(cast_b_xpm),"Cast B","Magic", sm, SLOT(map()), toolbar );
+    sm->setMapping(tb, "Zb" );
+    tb = new SmallToolButton( QPixmap(cast_c_xpm),"Cast C","Magic", sm, SLOT(map()), toolbar );
+    sm->setMapping(tb, "Zc" );
+    if ( !qt_compact_mode ) {
+       QWidget* filler = new QWidget(toolbar);
+       filler->setBackgroundMode(PaletteButton);
+       toolbar->setStretchableWidget(filler);
+    }
+
+    connect(menubar,SIGNAL(activated(int)),this,SLOT(doMenuItem(int)));
+
+#ifdef KDE
+    setMenu (menubar);
+#endif
+
+    int x=0,y=0;
+    int w=QApplication::desktop()->width()-10; // XXX arbitrary extra space for frame
+    int h=QApplication::desktop()->height()-50;
+
+    int maxwn;
+    int maxhn;
+    if (qt_tilewidth != NULL) {
+       maxwn = atoi(qt_tilewidth) * COLNO + 10;
+    } else {
+       maxwn = 1400;
+    }
+    if (qt_tileheight != NULL) {
+       maxhn = atoi(qt_tileheight) * ROWNO * 6/4;
+    } else {
+       maxhn = 1024;
+    }
+
+    // Be exactly the size we want to be - full map...
+    if (w>maxwn) {
+       x+=(w-maxwn)/2;
+       w=maxwn; // Doesn't need to be any wider
+    }
+    if (h>maxhn) {
+       y+=(h-maxhn)/2;
+       h=maxhn; // Doesn't need to be any taller
+    }
+
+    setGeometry(x,y,w,h);
+
+    if ( qt_compact_mode ) {
+       stack = new QWidgetStack(this);
+       setCentralWidget(stack);
+    } else {
+       setCentralWidget(new QWidget(this));
+       invusage = new NetHackQtInvUsageWindow(centralWidget());
+    }
+}
+
+void NetHackQtMainWindow::zoomMap()
+{
+    qt_settings->toggleGlyphSize();
+}
+
+void NetHackQtMainWindow::raiseMap()
+{
+    if ( stack->id(stack->visibleWidget()) == 0 ) {
+       zoomMap();
+    } else {
+       stack->raiseWidget(0);
+    }
+}
+
+void NetHackQtMainWindow::raiseMessages()
+{
+    stack->raiseWidget(1);
+}
+
+void NetHackQtMainWindow::raiseStatus()
+{
+    stack->raiseWidget(2);
+}
+
+class NetHackMimeSourceFactory : public QMimeSourceFactory {
+public:
+    const QMimeSource* data(const QString& abs_name) const
+    {
+       const QMimeSource* r = 0;
+       if ( (NetHackMimeSourceFactory*)this == QMimeSourceFactory::defaultFactory() )
+           r = QMimeSourceFactory::data(abs_name);
+       else
+           r = QMimeSourceFactory::defaultFactory()->data(abs_name);
+       if ( !r ) {
+           int sl = abs_name.length();
+           do {
+               sl = abs_name.findRev('/',sl-1);
+               QString name = sl>=0 ? abs_name.mid(sl+1) : abs_name;
+               int dot = name.findRev('.');
+               if ( dot >= 0 )
+                   name = name.left(dot);
+               if ( name == "map" )
+                   r = new QImageDrag(QImage(map_xpm));
+               else if ( name == "msg" )
+                   r = new QImageDrag(QImage(msg_xpm));
+               else if ( name == "stat" )
+                   r = new QImageDrag(QImage(stat_xpm));
+           } while (!r && sl>0);
+       }
+       return r;
+    }
+};
+
+void NetHackQtMainWindow::doMenuItem(int id)
+{
+    switch (id) {
+      case 1000:
+       centerOnMain(qt_settings);
+       qt_settings->show();
+       break;
+      case 2000:
+       QMessageBox::about(this,  "About Qt NetHack", aboutMsg());
+       break;
+      case 3000: {
+           QDialog dlg(this,0,TRUE);
+           (new QVBoxLayout(&dlg))->setAutoAdd(TRUE);
+           QTextBrowser browser(&dlg);
+           NetHackMimeSourceFactory ms;
+           browser.setMimeSourceFactory(&ms);
+           browser.setSource(QDir::currentDirPath()+"/Guidebook.html");
+           if ( qt_compact_mode )
+               dlg.showMaximized();
+           dlg.exec();
+       }
+       break;
+      default:
+       if ( id >= 0 )
+           doKeys(macro[id]);
+    }
+}
+
+void NetHackQtMainWindow::doKeys(const QString& k)
+{
+    keysink.Put(k);
+    qApp->exit_loop();
+}
+
+void NetHackQtMainWindow::AddMessageWindow(NetHackQtMessageWindow* window)
+{
+    message=window;
+    ShowIfReady();
+}
+
+void NetHackQtMainWindow::AddMapWindow(NetHackQtMapWindow* window)
+{
+    map=window;
+    ShowIfReady();
+    connect(map,SIGNAL(resized()),this,SLOT(layout()));
+}
+
+void NetHackQtMainWindow::AddStatusWindow(NetHackQtStatusWindow* window)
+{
+    status=window;
+    ShowIfReady();
+}
+
+void NetHackQtMainWindow::RemoveWindow(NetHackQtWindow* window)
+{
+    if (window==status) {
+       status=0;
+       ShowIfReady();
+    } else if (window==map) {
+       map=0;
+       ShowIfReady();
+    } else if (window==message) {
+       message=0;
+       ShowIfReady();
+    }
+}
+
+void NetHackQtMainWindow::updateInventory()
+{
+    if ( invusage )
+       invusage->repaint(FALSE);
+}
+
+void NetHackQtMainWindow::fadeHighlighting()
+{
+    if (status) {
+       status->fadeHighlighting();
+    }
+}
+
+void NetHackQtMainWindow::layout()
+{
+    if ( qt_compact_mode )
+       return;
+    if (message && map && status) {
+       QSize maxs=map->Widget()->maximumSize();
+       int maph=QMIN(height()*2/3,maxs.height());
+
+       QWidget* c = centralWidget();
+       int h=c->height();
+       int toph=h-maph;
+       int iuw=3*qt_settings->glyphs().width();
+       int topw=(c->width()-iuw)/2;
+
+       message->Widget()->setGeometry(0,0,topw,toph);
+       invusage->setGeometry(topw,0,iuw,toph);
+       status->Widget()->setGeometry(topw+iuw,0,topw,toph);
+       map->Widget()->setGeometry(QMAX(0,(c->width()-maxs.width())/2),
+                                  toph,c->width(),maph);
+    }
+}
+
+void NetHackQtMainWindow::resizeEvent(QResizeEvent*)
+{
+    layout();
+#ifdef KDE
+    updateRects();
+#endif         
+}
+
+void NetHackQtMainWindow::keyReleaseEvent(QKeyEvent* event)
+{
+    if ( dirkey ) {
+       doKeys(QString(QChar(dirkey)));
+       if ( !event->isAutoRepeat() )
+           dirkey = 0;
+    }
+}
+
+void NetHackQtMainWindow::keyPressEvent(QKeyEvent* event)
+{
+    // Global key controls
+
+    // For desktop, arrow keys scroll map, since we don't want players
+    // to think that's the way to move. For handhelds, the normal way is to
+    // click-to-travel, so we allow the cursor keys for fine movements.
+
+    //  321
+    //  4 0
+    //  567
+
+    if ( event->isAutoRepeat() &&
+       event->key() >= Key_Left && event->key() <= Key_Down )
+       return;
+
+    const char* d = iflags.num_pad ? ndir : sdir; 
+    switch (event->key()) {
+     case Key_Up:
+       if ( dirkey == d[0] )
+           dirkey = d[1];
+       else if ( dirkey == d[4] )
+           dirkey = d[3];
+       else
+           dirkey = d[2];
+    break; case Key_Down:
+       if ( dirkey == d[0] )
+           dirkey = d[7];
+       else if ( dirkey == d[4] )
+           dirkey = d[5];
+       else
+           dirkey = d[6];
+    break; case Key_Left:
+       if ( dirkey == d[2] )
+           dirkey = d[1];
+       else if ( dirkey == d[6] )
+           dirkey = d[7];
+       else
+           dirkey = d[0];
+    break; case Key_Right:
+       if ( dirkey == d[2] )
+           dirkey = d[3];
+       else if ( dirkey == d[6] )
+           dirkey = d[5];
+       else
+           dirkey = d[4];
+    break; case Key_Prior:
+       dirkey = 0;
+       if (message) message->Scroll(0,-1);
+    break; case Key_Next:
+       dirkey = 0;
+       if (message) message->Scroll(0,+1);
+    break; case Key_Space:
+       if ( flags.rest_on_space ) {
+           event->ignore();
+           return;
+       }
+       case Key_Enter:
+       if ( map )
+           map->clickCursor();
+    break; default:
+       dirkey = 0;
+       event->ignore();
+    }
+}
+
+void NetHackQtMainWindow::closeEvent(QCloseEvent* e)
+{
+    if ( program_state.something_worth_saving ) {
+       switch ( QMessageBox::information( this, "NetHack",
+           "This will end your NetHack session",
+           "&Save", "&Cancel", 0, 1 ) )
+       {
+           case 0:
+               // See dosave() function
+               if (dosave0()) {
+                   u.uhp = -1;
+                   NetHackQtBind::qt_exit_nhwindows(0);
+                   terminate(EXIT_SUCCESS);
+               }
+               break;
+           case 1:
+               break; // ignore the event
+       }
+    } else {
+       e->accept();
+    }
+}
+
+void NetHackQtMainWindow::ShowIfReady()
+{
+    if (message && map && status) {
+       QPoint pos(0,0);
+       QWidget* p = qt_compact_mode ? stack : centralWidget();
+       message->Widget()->recreate(p,0,pos);
+       map->Widget()->recreate(p,0,pos);
+       status->Widget()->recreate(p,0,pos);
+       if ( qt_compact_mode ) {
+           message->setMap(map);
+           stack->addWidget(map->Widget(), 0);
+           stack->addWidget(message->Widget(), 1);
+           stack->addWidget(status->Widget(), 2);
+           raiseMap();
+       } else {
+           layout();
+       }
+       showMaximized();
+    } else if (isVisible()) {
+       hide();
+    }
+}
+
+
+NetHackQtYnDialog::NetHackQtYnDialog(NetHackQtKeyBuffer& keysrc,const char* q,const char* ch,char df) :
+    QDialog(qApp->mainWidget(),0,FALSE),
+    question(q), choices(ch), def(df),
+    keysource(keysrc)
+{
+    setCaption("NetHack: Question");
+}
+
+char NetHackQtYnDialog::Exec()
+{
+    QString ch(choices);
+    int ch_per_line=6;
+    QString qlabel;
+    QString enable;
+    if ( qt_compact_mode && !choices ) {
+       // expand choices from prompt
+       // ##### why isn't choices set properly???
+       const char* c=question;
+       while ( *c && *c != '[' )
+           c++;
+       qlabel = QString(question).left(c-question);
+       if ( *c ) {
+           c++;
+           if ( *c == '-' )
+               ch.append(*c++);
+           char from=0;
+           while ( *c && *c != ']' && *c != ' ' ) {
+               if ( *c == '-' ) {
+                   from = c[-1];
+               } else if ( from ) {
+                   for (char f=from+1; f<=*c; f++)
+                       ch.append(f);
+                   from = 0;
+               } else {
+                   ch.append(*c);
+                   from = 0;
+               }
+               c++;
+           }
+           if ( *c == ' ' ) {
+               while ( *c && *c != ']' ) {
+                   if ( *c == '*' || *c == '?' )
+                       ch.append(*c);
+                   c++;
+               }
+           }
+       }
+       if ( strstr(question, "what direction") ) {
+           // We replace this regardless, since sometimes you get choices.
+           const char* d = iflags.num_pad ? ndir : sdir; 
+           enable=ch;
+           ch="";
+           ch.append(d[1]);
+           ch.append(d[2]);
+           ch.append(d[3]);
+           ch.append(d[0]);
+           ch.append('.');
+           ch.append(d[4]);
+           ch.append(d[7]);
+           ch.append(d[6]);
+           ch.append(d[5]);
+           ch.append(d[8]);
+           ch.append(d[9]);
+           ch_per_line = 3;
+           def = ' ';
+       } else {
+           // Hmm... they'll have to use a virtual keyboard
+       }
+    } else {
+       qlabel = question;
+    }
+    if (!ch.isNull()) {
+       QVBoxLayout vb(this);
+       vb.setAutoAdd(TRUE);
+       bool bigq = qlabel.length()>40;
+       if ( bigq ) {
+           QLabel* q = new QLabel(qlabel,this);
+           q->setAlignment(AlignLeft|WordBreak);
+           q->setMargin(4);
+       }
+       QButtonGroup group(ch_per_line, Horizontal,
+           bigq ? QString::null : qlabel, this);
+
+       int nchoices=ch.length();
+
+       bool allow_count=ch.contains('#');
+
+       const int margin=8;
+       const int gutter=8;
+       const int extra=fontMetrics().height(); // Extra for group
+       int x=margin, y=extra+margin;
+       int butsize=fontMetrics().height()*2+5;
+
+       QPushButton* button;
+       for (int i=0; i<nchoices && ch[i]!='\033'; i++) {
+           button=new QPushButton(QString(ch[i]),&group);
+           if ( !enable.isNull() ) {
+               if ( !enable.contains(ch[i]) )
+                   button->setEnabled(FALSE);
+           }
+           button->setFixedSize(butsize,butsize); // Square
+           if (ch[i]==def) button->setDefault(TRUE);
+           if (i%10==9) {
+               // last in row
+               x=margin;
+               y+=butsize+gutter;
+           } else {
+               x+=butsize+gutter;
+           }
+       }
+
+       connect(&group,SIGNAL(clicked(int)),this,SLOT(doneItem(int)));
+
+       QLabel* lb=0;
+       QLineEdit* le=0;
+
+       if (allow_count) {
+           QHBox *hb = new QHBox(this);
+           lb=new QLabel("Count: ",hb);
+           le=new QLineEdit(hb);
+       }
+
+       adjustSize();
+       centerOnMain(this);
+       show();
+       char choice=0;
+       char ch_esc=0;
+       for (uint i=0; i<ch.length(); i++) {
+           if (ch[i].latin1()=='q') ch_esc='q';
+           else if (!ch_esc && ch[i].latin1()=='n') ch_esc='n';
+       }
+       setResult(-1);
+       while (!choice) {
+           if (!keysource.Empty()) {
+               char k=keysource.GetAscii();
+               char ch_esc=0;
+               for (uint i=0; i<ch.length(); i++)
+                   if (ch[i].latin1()==k)
+                       choice=k;
+               if (!choice) {
+                   if (k=='\033' && ch_esc)
+                       choice=ch_esc;
+                   else if (k==' ' || k=='\r' || k=='\n')
+                       choice=def;
+                   // else choice remains 0
+               }
+           } else if ( result() == 0 ) {
+               choice = ch_esc ? ch_esc : def ? def : ' ';
+           } else if ( result() == 1 ) {
+               choice = def ? def : ch_esc ? ch_esc : ' ';
+           } else if ( result() >= 1000 ) {
+               choice = ch[result() - 1000].latin1();
+           }
+           if ( !choice )
+               qApp->enter_loop();
+       }
+       hide();
+       if (allow_count && !le->text().isEmpty()) {
+           yn_number=atoi(le->text());
+           choice='#';
+       }
+       return choice;
+    } else {
+       QLabel label(qlabel,this);
+       QPushButton cancel("Dismiss",this);
+       label.setFrameStyle(QFrame::Box|QFrame::Sunken);
+       label.setAlignment(AlignCenter);
+       label.resize(fontMetrics().width(qlabel)+60,30+fontMetrics().height());
+       cancel.move(width()/2-cancel.width()/2,label.geometry().bottom()+8);
+       connect(&cancel,SIGNAL(clicked()),this,SLOT(reject()));
+       centerOnMain(this);
+       setResult(-1);
+       show();
+       while (result()<0 && keysource.Empty()) {
+           qApp->enter_loop();
+       }
+       hide();
+       if (keysource.Empty()) {
+           return '\033';
+       } else {
+           return keysource.GetAscii();
+       }
+    }
+}
+void NetHackQtYnDialog::keyPressEvent(QKeyEvent* event)
+{
+    // Don't want QDialog's Return/Esc behaviour
+    event->ignore();
+}
+
+void NetHackQtYnDialog::doneItem(int i)
+{
+    done(i+1000);
+}
+
+void NetHackQtYnDialog::done(int i)
+{
+    setResult(i);
+    qApp->exit_loop();
+}
+
+NetHackQtGlyphs::NetHackQtGlyphs()
+{
+    const char* tile_file = "nhtiles.bmp";
+    if ( iflags.wc_tile_file )
+       tile_file = iflags.wc_tile_file;
+
+    if (!img.load(tile_file)) {
+       tile_file = "x11tiles";
+       if (!img.load(tile_file)) {
+           QString msg;
+           msg.sprintf("Cannot load x11tiles or nhtiles.bmp");
+           QMessageBox::warning(0, "IO Error", msg);
+       } else {
+           tiles_per_row = TILES_PER_ROW;
+           if (img.width()%tiles_per_row) {
+               impossible("Tile file \"%s\" has %d columns, not multiple of row count (%d)",
+                  tile_file, img.width(), tiles_per_row);
+           }
+       }
+    } else {
+       tiles_per_row = 40;
+    }
+
+    if ( iflags.wc_tile_width )
+       tilefile_tile_W = iflags.wc_tile_width;
+    else
+       tilefile_tile_W = img.width() / tiles_per_row;
+    if ( iflags.wc_tile_height )
+       tilefile_tile_H = iflags.wc_tile_height;
+    else
+       tilefile_tile_H = tilefile_tile_W;
+
+    setSize(tilefile_tile_W, tilefile_tile_H);
+}
+
+void NetHackQtGlyphs::drawGlyph(QPainter& painter, int glyph, int x, int y)
+{
+    int tile = glyph2tile[glyph];
+    int px = (tile%tiles_per_row)*width();
+    int py = tile/tiles_per_row*height();
+
+    painter.drawPixmap(
+       x,
+       y,
+       pm,
+       px,py,
+       width(),height()
+    );
+}
+void NetHackQtGlyphs::drawCell(QPainter& painter, int glyph, int cellx, int celly)
+{
+    drawGlyph(painter,glyph,cellx*width(),celly*height());
+}
+void NetHackQtGlyphs::setSize(int w, int h)
+{
+    if ( size == QSize(w,h) )
+       return;
+
+    bool was1 = size == pm1.size();
+    size = QSize(w,h);
+    if (!w || !h)
+       return; // Still not decided
+
+    if ( size == pm1.size() ) {
+       pm = pm1;
+       return;
+    }
+    if ( size == pm2.size() ) {
+       pm = pm2;
+       return;
+    }
+
+    if (w==tilefile_tile_W && h==tilefile_tile_H) {
+       pm.convertFromImage(img);
+    } else {
+       QApplication::setOverrideCursor( Qt::waitCursor );
+       QImage scaled = img.smoothScale(
+           w*img.width()/tilefile_tile_W,
+           h*img.height()/tilefile_tile_H
+       );
+       pm.convertFromImage(scaled,Qt::ThresholdDither|Qt::PreferDither);
+       QApplication::restoreOverrideCursor();
+    }
+    (was1 ? pm2 : pm1) = pm;
+}
+
+
+//////////////////////////////////////////////////////////////
+//
+//  The ugly C binding classes...
+//
+//////////////////////////////////////////////////////////////
+
+
+NetHackQtMenuOrTextWindow::NetHackQtMenuOrTextWindow(NetHackQtKeyBuffer& ks) :
+    actual(0),
+    keysource(ks)
+{
+}
+
+QWidget* NetHackQtMenuOrTextWindow::Widget()
+{
+    if (!actual) impossible("Widget called before we know if Menu or Text");
+    return actual->Widget();
+}
+
+// Text
+void NetHackQtMenuOrTextWindow::Clear()
+{
+    if (!actual) impossible("Clear called before we know if Menu or Text");
+    actual->Clear();
+}
+void NetHackQtMenuOrTextWindow::Display(bool block)
+{
+    if (!actual) impossible("Display called before we know if Menu or Text");
+    actual->Display(block);
+}
+bool NetHackQtMenuOrTextWindow::Destroy()
+{
+    if (!actual) impossible("Destroy called before we know if Menu or Text");
+    return actual->Destroy();
+}
+
+void NetHackQtMenuOrTextWindow::PutStr(int attr, const char* text)
+{
+    if (!actual) actual=new NetHackQtTextWindow(keysource);
+    actual->PutStr(attr,text);
+}
+
+// Menu
+void NetHackQtMenuOrTextWindow::StartMenu()
+{
+    if (!actual) actual=new NetHackQtMenuWindow(keysource);
+    actual->StartMenu();
+}
+void NetHackQtMenuOrTextWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr,
+       const char* str, bool presel)
+{
+    if (!actual) impossible("AddMenu called before we know if Menu or Text");
+    actual->AddMenu(glyph,identifier,ch,gch,attr,str,presel);
+}
+void NetHackQtMenuOrTextWindow::EndMenu(const char* prompt)
+{
+    if (!actual) impossible("EndMenu called before we know if Menu or Text");
+    actual->EndMenu(prompt);
+}
+int NetHackQtMenuOrTextWindow::SelectMenu(int how, MENU_ITEM_P **menu_list)
+{
+    if (!actual) impossible("SelectMenu called before we know if Menu or Text");
+    return actual->SelectMenu(how,menu_list);
+}
+
+
+// XXX Should be from Options
+//
+// XXX Hmm.  Tricky part is that perhaps some macros should only be active
+// XXX       when a key is about to be gotten.  For example, the user could
+// XXX       define "-" to do "E-yyyyyyyy\r", but would still need "-" for
+// XXX       other purposes.  Maybe just too bad.
+//
+struct {
+    int key;
+    int state;
+    const char* macro;
+} key_macro[]={
+    { Qt::Key_F1, 0, "n100." }, // Rest (x100)
+    { Qt::Key_F2, 0, "n20s" },  // Search (x20)
+    { Qt::Key_F3, 0, "o8o4o6o2o8o4o6o2o8o4o6o2" }, // Open all doors (x3)
+    { Qt::Key_Tab, 0, "\001" },
+    { 0, 0, 0 }
+};
+
+
+NetHackQtBind::NetHackQtBind(int& argc, char** argv) :
+#ifdef KDE
+    KApplication(argc,argv)
+#elif defined(QWS) // not quite the right condition
+    QPEApplication(argc,argv)
+#else
+    QApplication(argc,argv)
+#endif
+{
+    QPixmap pm("nhsplash.xpm");
+    if ( iflags.wc_splash_screen && !pm.isNull() ) {
+       QVBox *vb = new QVBox(0,0,
+           WStyle_Customize | WStyle_NoBorder | nh_WX11BypassWM | WStyle_StaysOnTop );
+       splash = vb;
+       QLabel *lsplash = new QLabel(vb);
+       lsplash->setAlignment(AlignCenter);
+       lsplash->setPixmap(pm);
+       QLabel* capt = new QLabel("Loading...",vb);
+       capt->setAlignment(AlignCenter);
+       if ( pm.mask() ) {
+           lsplash->setFixedSize(pm.size());
+           lsplash->setMask(*pm.mask());
+       }
+       splash->move((QApplication::desktop()->width()-pm.width())/2,
+                     (QApplication::desktop()->height()-pm.height())/2);
+       //splash->setGeometry(0,0,100,100);
+       if ( qt_compact_mode ) {
+           splash->showMaximized();
+       } else {
+           vb->setFrameStyle(QFrame::WinPanel|QFrame::Raised);
+           vb->setMargin(10);
+           splash->adjustSize();
+           splash->show();
+       }
+
+       // force content refresh outside event loop
+       splash->repaint(FALSE);
+       lsplash->repaint(FALSE);
+       capt->repaint(FALSE);
+       qApp->flushX();
+
+    } else {
+       splash = 0;
+    }
+    main = new NetHackQtMainWindow(keybuffer);
+#if defined(QWS) // not quite the right condition
+    showMainWidget(main);
+#else
+    setMainWidget(main);
+#endif
+    qt_settings=new NetHackQtSettings(main->width(),main->height());
+}
+
+void NetHackQtBind::qt_init_nhwindows(int* argc, char** argv)
+{
+#ifdef UNIX
+// Userid control
+//
+// Michael Hohmuth <hohmuth@inf.tu-dresden.de>...
+//
+// As the game runs setuid games, it must seteuid(getuid()) before
+// calling XOpenDisplay(), and reset the euid afterwards.
+// Otherwise, it can't read the $HOME/.Xauthority file and whines about
+// not being able to open the X display (if a magic-cookie
+// authorization mechanism is being used). 
+
+    uid_t gamesuid=geteuid();
+    seteuid(getuid());
+#endif
+
+    QApplication::setColorSpec(ManyColor);
+    instance=new NetHackQtBind(*argc,argv);
+
+#ifdef UNIX
+    seteuid(gamesuid);
+#endif
+
+#ifdef _WS_WIN_
+    // This nethack engine feature should be moved into windowport API
+    nt_kbhit = NetHackQtBind::qt_kbhit;
+#endif
+}
+
+int NetHackQtBind::qt_kbhit()
+{
+    return !keybuffer.Empty();
+}
+
+static bool have_asked = FALSE;
+
+void NetHackQtBind::qt_player_selection()
+{
+    if ( !have_asked )
+       qt_askname();
+}
+
+NetHackQtSavedGameSelector::NetHackQtSavedGameSelector(const char** saved) :
+    QDialog(qApp->mainWidget(),"sgsel",TRUE)
+{
+    QVBoxLayout *vbl = new QVBoxLayout(this,6);
+    QHBox* hb;
+
+    QLabel* logo = new QLabel(this); vbl->addWidget(logo);
+    logo->setAlignment(AlignCenter);
+    logo->setPixmap(QPixmap("nhsplash.xpm"));
+    QLabel* attr = new QLabel("by the NetHack DevTeam",this);
+    attr->setAlignment(AlignCenter);
+    vbl->addWidget(attr);
+    vbl->addStretch(2);
+    /*
+    QLabel* logo = new QLabel(hb);
+    hb = new QHBox(this);
+    vbl->addWidget(hb, AlignCenter);
+    logo->setPixmap(QPixmap(nh_icon));
+    logo->setAlignment(AlignRight|AlignVCenter);
+    new QLabel(nh_attribution,hb);
+    */
+
+    hb = new QHBox(this);
+    vbl->addWidget(hb, AlignCenter);
+    QPushButton* q = new QPushButton("Quit",hb);
+    connect(q, SIGNAL(clicked()), this, SLOT(reject()));
+    QPushButton* c = new QPushButton("New Game",hb);
+    connect(c, SIGNAL(clicked()), this, SLOT(accept()));
+    c->setDefault(TRUE);
+
+    QButtonGroup* bg = new QButtonGroup(3, Horizontal, "Saved Characters",this);
+    vbl->addWidget(bg);
+    connect(bg, SIGNAL(clicked(int)), this, SLOT(done(int)));
+    for (int i=0; saved[i]; i++) {
+       QPushButton* b = new QPushButton(saved[i],bg);
+       bg->insert(b, i+2);
+    }
+}
+
+int NetHackQtSavedGameSelector::choose()
+{
+#if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog).
+    if ( qt_compact_mode )
+       showMaximized();
+#endif
+    return exec()-2;
+}
+
+void NetHackQtBind::qt_askname()
+{
+    have_asked = TRUE;
+
+    // We do it all here, and nothing in askname
+
+    char** saved = get_saved_games();
+    int ch = -1;
+    if ( saved && *saved ) {
+       if ( splash ) splash->hide();
+       NetHackQtSavedGameSelector sgsel((const char**)saved);
+       ch = sgsel.choose();
+       if ( ch >= 0 )
+           strcpy(plname,saved[ch]);
+    }
+    free_saved_games(saved);
+
+    switch (ch) {
+      case -1:
+       if ( splash ) splash->hide();
+       if (NetHackQtPlayerSelector(keybuffer).Choose())
+           return;
+      case -2:
+       break;
+      default:
+       return;
+    }
+
+    // Quit
+    clearlocks();
+    qt_exit_nhwindows(0);
+    terminate(0);
+}
+
+void NetHackQtBind::qt_get_nh_event()
+{
+}
+
+#if defined(QWS)
+// Kludge to access lastWindowClosed() signal.
+class TApp : public QApplication {
+public:
+    TApp(int& c, char**v) : QApplication(c,v) {}
+    void lwc() { emit lastWindowClosed(); }
+};
+#endif
+void NetHackQtBind::qt_exit_nhwindows(const char *)
+{
+#if defined(QWS)
+    // Avoids bug in SHARP SL5500
+    ((TApp*)qApp)->lwc();
+    qApp->quit();
+#endif
+    delete instance; // ie. qApp
+}
+
+void NetHackQtBind::qt_suspend_nhwindows(const char *)
+{
+}
+
+void NetHackQtBind::qt_resume_nhwindows()
+{
+}
+
+static QArray<NetHackQtWindow*> id_to_window;
+
+winid NetHackQtBind::qt_create_nhwindow(int type)
+{
+    winid id;
+    for (id = 0; id < (winid) id_to_window.size(); id++) {
+       if ( !id_to_window[id] )
+           break;
+    }
+    if ( id == (winid) id_to_window.size() )
+       id_to_window.resize(id+1);
+
+    NetHackQtWindow* window=0;
+
+    switch (type) {
+     case NHW_MAP: {
+       NetHackQtMapWindow* w=new NetHackQtMapWindow(clickbuffer);
+       main->AddMapWindow(w);
+       window=w;
+    } break; case NHW_MESSAGE: {
+       NetHackQtMessageWindow* w=new NetHackQtMessageWindow;
+       main->AddMessageWindow(w);
+       window=w;
+    } break; case NHW_STATUS: {
+       NetHackQtStatusWindow* w=new NetHackQtStatusWindow;
+       main->AddStatusWindow(w);
+       window=w;
+    } break; case NHW_MENU:
+       window=new NetHackQtMenuOrTextWindow(keybuffer);
+    break; case NHW_TEXT:
+       window=new NetHackQtTextWindow(keybuffer);
+    }
+
+    window->nhid = id;
+
+    // Note: use of isHidden does not work with Qt 2.1
+    if ( splash 
+#if QT_VERSION >= 300
+        && !main->isHidden()
+#else
+       && main->isVisible()
+#endif
+       )
+    {
+       delete splash;
+       splash = 0;
+    }
+
+    id_to_window[id] = window;
+    return id;
+}
+
+void NetHackQtBind::qt_clear_nhwindow(winid wid)
+{
+    NetHackQtWindow* window=id_to_window[wid];
+    window->Clear();
+}
+
+void NetHackQtBind::qt_display_nhwindow(winid wid, BOOLEAN_P block)
+{
+    NetHackQtWindow* window=id_to_window[wid];
+    window->Display(block);
+}
+
+void NetHackQtBind::qt_destroy_nhwindow(winid wid)
+{
+    NetHackQtWindow* window=id_to_window[wid];
+    main->RemoveWindow(window);
+    if (window->Destroy())
+       delete window;
+    id_to_window[wid] = 0;
+}
+
+void NetHackQtBind::qt_curs(winid wid, int x, int y)
+{
+    NetHackQtWindow* window=id_to_window[wid];
+    window->CursorTo(x,y);
+}
+
+void NetHackQtBind::qt_putstr(winid wid, int attr, const char *text)
+{
+    NetHackQtWindow* window=id_to_window[wid];
+    window->PutStr(attr,text);
+}
+
+void NetHackQtBind::qt_display_file(const char *filename, BOOLEAN_P must_exist)
+{
+    NetHackQtTextWindow* window=new NetHackQtTextWindow(keybuffer);
+    bool complain = FALSE;
+
+#ifdef DLB
+    {
+       dlb *f;
+       char buf[BUFSZ];
+       char *cr;
+
+       window->Clear();
+       f = dlb_fopen(filename, "r");
+       if (!f) {
+           complain = must_exist;
+       } else {
+           while (dlb_fgets(buf, BUFSZ, f)) {
+               if ((cr = index(buf, '\n')) != 0) *cr = 0;
+#ifdef MSDOS
+               if ((cr = index(buf, '\r')) != 0) *cr = 0;
+#endif
+               if (index(buf, '\t') != 0) (void) tabexpand(buf);
+               window->PutStr(ATR_NONE, buf);
+           }
+           window->Display(FALSE);
+           (void) dlb_fclose(f);
+       }
+    }
+#else
+    QFile file(filename);
+
+    if (file.open(IO_ReadOnly)) {
+       char line[128];
+       while (file.readLine(line,127) >= 0) {
+           line[strlen(line)-1]=0;// remove newline
+           window->PutStr(ATR_NONE,line);
+       }
+       window->Display(FALSE);
+    } else {
+       complain = must_exist;
+    }
+#endif
+
+    if (complain) {
+       QString message;
+       message.sprintf("File not found: %s\n",filename);
+       QMessageBox::message("File Error", (const char*)message, "Ignore");
+    }
+}
+
+void NetHackQtBind::qt_start_menu(winid wid)
+{
+    NetHackQtWindow* window=id_to_window[wid];
+    window->StartMenu();
+}
+
+void NetHackQtBind::qt_add_menu(winid wid, int glyph,
+    const ANY_P * identifier, CHAR_P ch, CHAR_P gch, int attr,
+    const char *str, BOOLEAN_P presel)
+{
+    NetHackQtWindow* window=id_to_window[wid];
+    window->AddMenu(glyph, identifier, ch, gch, attr, str, presel);
+}
+
+void NetHackQtBind::qt_end_menu(winid wid, const char *prompt)
+{
+    NetHackQtWindow* window=id_to_window[wid];
+    window->EndMenu(prompt);
+}
+
+int NetHackQtBind::qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list)
+{
+    NetHackQtWindow* window=id_to_window[wid];
+    return window->SelectMenu(how,menu_list);
+}
+
+void NetHackQtBind::qt_update_inventory()
+{
+    if (main)
+       main->updateInventory();
+    /* doesn't work yet
+    if (program_state.something_worth_saving && flags.perm_invent)
+        display_inventory(NULL, FALSE);
+    */
+}
+
+void NetHackQtBind::qt_mark_synch()
+{
+}
+
+void NetHackQtBind::qt_wait_synch()
+{
+}
+
+void NetHackQtBind::qt_cliparound(int x, int y)
+{
+    // XXXNH - winid should be a parameter!
+    qt_cliparound_window(WIN_MAP,x,y);
+}
+
+void NetHackQtBind::qt_cliparound_window(winid wid, int x, int y)
+{
+    NetHackQtWindow* window=id_to_window[wid];
+    window->ClipAround(x,y);
+}
+void NetHackQtBind::qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph)
+{
+    NetHackQtWindow* window=id_to_window[wid];
+    window->PrintGlyph(x,y,glyph);
+}
+//void NetHackQtBind::qt_print_glyph_compose(winid wid,XCHAR_P x,XCHAR_P y,int glyph1, int glyph2)
+//{
+    //NetHackQtWindow* window=id_to_window[wid];
+    //window->PrintGlyphCompose(x,y,glyph1,glyph2);
+//}
+
+void NetHackQtBind::qt_raw_print(const char *str)
+{
+    puts(str);
+}
+
+void NetHackQtBind::qt_raw_print_bold(const char *str)
+{
+    puts(str);
+}
+
+int NetHackQtBind::qt_nhgetch()
+{
+    if (main)
+       main->fadeHighlighting();
+
+    // Process events until a key arrives.
+    //
+    while (keybuffer.Empty()) {
+       qApp->enter_loop();
+    }
+
+    return keybuffer.GetAscii();
+}
+
+int NetHackQtBind::qt_nh_poskey(int *x, int *y, int *mod)
+{
+    if (main)
+       main->fadeHighlighting();
+
+    // Process events until a key or map-click arrives.
+    //
+    while (keybuffer.Empty() && clickbuffer.Empty()) {
+       qApp->enter_loop();
+    }
+    if (!keybuffer.Empty()) {
+       return keybuffer.GetAscii();
+    } else {
+       *x=clickbuffer.NextX();
+       *y=clickbuffer.NextY();
+       *mod=clickbuffer.NextMod();
+       clickbuffer.Get();
+       return 0;
+    }
+}
+
+void NetHackQtBind::qt_nhbell()
+{
+    QApplication::beep();
+}
+
+int NetHackQtBind::qt_doprev_message()
+{
+    // Don't need it - uses scrollbar
+    // XXX but could make this a shortcut
+    return 0;
+}
+
+char NetHackQtBind::qt_yn_function(const char *question, const char *choices, CHAR_P def)
+{
+    if (qt_settings->ynInMessages() && WIN_MESSAGE!=WIN_ERR) {
+       // Similar to X11 windowport `slow' feature.
+
+       char message[BUFSZ];
+       char yn_esc_map='\033';
+
+       if (choices) {
+           char *cb, choicebuf[QBUFSZ];
+           Strcpy(choicebuf, choices);
+           if ((cb = index(choicebuf, '\033')) != 0) {
+               // anything beyond <esc> is hidden
+               *cb = '\0';
+           }
+           Sprintf(message, "%s [%s] ", question, choicebuf);
+           if (def) Sprintf(eos(message), "(%c) ", def);
+           // escape maps to 'q' or 'n' or default, in that order
+           yn_esc_map = (index(choices, 'q') ? 'q' :
+                    (index(choices, 'n') ? 'n' : def));
+       } else {
+           Strcpy(message, question);
+       }
+
+#ifdef USE_POPUPS
+       // Improve some special-cases (DIRKS 08/02/23)
+       if (strcmp (choices,"ynq") == 0) {
+           switch (QMessageBox::information (qApp->mainWidget(),"NetHack",question,"&Yes","&No","&Quit",0,2))
+           {
+             case 0: return 'y'; 
+             case 1: return 'n'; 
+             case 2: return 'q'; 
+           }
+       }
+
+       if (strcmp (choices,"yn") == 0) {
+           switch (QMessageBox::information(qApp->mainWidget(),"NetHack",question,"&Yes", "&No",0,1))
+           {
+             case 0: return 'y';
+             case 1: return 'n'; 
+           }
+       }
+#endif
+
+       NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message);
+
+       int result=-1;
+       while (result<0) {
+           char ch=NetHackQtBind::qt_nhgetch();
+           if (ch=='\033') {
+               result=yn_esc_map;
+           } else if (choices && !index(choices,ch)) {
+               if (def && (ch==' ' || ch=='\r' || ch=='\n')) {
+                   result=def;
+               } else {
+                   NetHackQtBind::qt_nhbell();
+                   // and try again...
+               }
+           } else {
+               result=ch;
+           }
+       }
+
+       NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE);
+
+       return result;
+    } else {
+       NetHackQtYnDialog dialog(keybuffer,question,choices,def);
+       return dialog.Exec();
+    }
+}
+
+void NetHackQtBind::qt_getlin(const char *prompt, char *line)
+{
+    NetHackQtStringRequestor requestor(keybuffer,prompt);
+    if (!requestor.Get(line)) {
+       line[0]=0;
+    }
+}
+
+NetHackQtExtCmdRequestor::NetHackQtExtCmdRequestor(NetHackQtKeyBuffer& ks) :
+    QDialog(qApp->mainWidget(), "ext-cmd", FALSE),
+    keysource(ks)
+{
+    int marg=4;
+    QVBoxLayout *l = new QVBoxLayout(this,marg,marg);
+
+    QPushButton* can = new QPushButton("Cancel", this);
+    can->setDefault(TRUE);
+    can->setMinimumSize(can->sizeHint());
+    l->addWidget(can);
+
+    QButtonGroup *group=new QButtonGroup("",0);
+    QGroupBox *grid=new QGroupBox("Extended commands",this);
+    l->addWidget(grid);
+
+    int i;
+    int butw=50;
+    QFontMetrics fm = fontMetrics();
+    for (i=0; extcmdlist[i].ef_txt; i++) {
+       butw = QMAX(butw,30+fm.width(extcmdlist[i].ef_txt));
+    }
+    int ncols=4;
+    int nrows=(i+ncols-1)/ncols;
+
+    QVBoxLayout* bl = new QVBoxLayout(grid,marg);
+    bl->addSpacing(fm.height());
+    QGridLayout* gl = new QGridLayout(nrows,ncols,marg);
+    bl->addLayout(gl);
+    for (i=0; extcmdlist[i].ef_txt; i++) {
+       QPushButton* pb=new QPushButton(extcmdlist[i].ef_txt, grid);
+       pb->setMinimumSize(butw,pb->sizeHint().height());
+       group->insert(pb);
+       gl->addWidget(pb,i/ncols,i%ncols);
+    }
+    connect(group,SIGNAL(clicked(int)),this,SLOT(done(int)));
+
+    bl->activate();
+    l->activate();
+    resize(1,1);
+
+    connect(can,SIGNAL(clicked()),this,SLOT(cancel()));
+}
+
+void NetHackQtExtCmdRequestor::cancel()
+{
+    setResult(-1);
+    qApp->exit_loop();
+}
+
+void NetHackQtExtCmdRequestor::done(int i)
+{
+    setResult(i);
+    qApp->exit_loop();
+}
+
+int NetHackQtExtCmdRequestor::get()
+{
+    const int none = -10;
+    char str[32];
+    int cursor=0;
+    resize(1,1); // pack
+    centerOnMain(this);
+    show();
+    setResult(none);
+    while (result()==none) {
+       while (result()==none && !keysource.Empty()) {
+           char k=keysource.GetAscii();
+           if (k=='\r' || k=='\n' || k==' ' || k=='\033') {
+               setResult(-1);
+           } else {
+               str[cursor++] = k;
+               int r=-1;
+               for (int i=0; extcmdlist[i].ef_txt; i++) {
+                   if (qstrnicmp(str, extcmdlist[i].ef_txt, cursor)==0) {
+                       if ( r == -1 )
+                           r = i;
+                       else
+                           r = -2;
+                   }
+               }
+               if ( r == -1 ) { // no match!
+                   QApplication::beep();
+                   cursor=0;
+               } else if ( r != -2 ) { // only one match
+                   setResult(r);
+               }
+           }
+       }
+       if (result()==none)
+           qApp->enter_loop();
+    }
+    hide();
+    return result();
+}
+
+
+int NetHackQtBind::qt_get_ext_cmd()
+{
+    NetHackQtExtCmdRequestor requestor(keybuffer);
+    return requestor.get();
+}
+
+void NetHackQtBind::qt_number_pad(int)
+{
+    // Ignore.
+}
+
+void NetHackQtBind::qt_delay_output()
+{
+    NetHackQtDelay delay(15);
+    delay.wait();
+}
+
+void NetHackQtBind::qt_start_screen()
+{
+    // Ignore.
+}
+
+void NetHackQtBind::qt_end_screen()
+{
+    // Ignore.
+}
+
+void NetHackQtBind::qt_outrip(winid wid, int how)
+{
+    NetHackQtWindow* window=id_to_window[wid];
+
+    window->UseRIP(how);
+}
+
+bool NetHackQtBind::notify(QObject *receiver, QEvent *event)
+{
+    // Ignore Alt-key navigation to menubar, it's annoying when you
+    // use Alt-Direction to move around.
+    if ( main && event->type()==QEvent::KeyRelease && main==receiver
+           && ((QKeyEvent*)event)->key() == Key_Alt )
+       return TRUE;
+
+    bool result=QApplication::notify(receiver,event);
+    if (event->type()==QEvent::KeyPress) {
+       QKeyEvent* key_event=(QKeyEvent*)event;
+
+       if (!key_event->isAccepted()) {
+           const int k=key_event->key();
+           bool macro=FALSE;
+           for (int i=0; !macro && key_macro[i].key; i++) {
+               if (key_macro[i].key==k
+                && ((key_macro[i].state&key_event->state())==key_macro[i].state))
+               {
+                   keybuffer.Put(key_macro[i].macro);
+                   macro=TRUE;
+               }
+           }
+           char ch=key_event->ascii();
+           if ( !ch && (key_event->state() & Qt::ControlButton) ) {
+               // On Mac, ascii control codes are not sent, force them.
+               if ( k>=Qt::Key_A && k<=Qt::Key_Z )
+                   ch = k - Qt::Key_A + 1;
+           }
+           if (!macro && ch) {
+               bool alt = (key_event->state()&AltButton) ||
+                  (k >= Key_0 && k <= Key_9 && (key_event->state()&ControlButton));
+               keybuffer.Put(key_event->key(),ch + (alt ? 128 : 0),
+                   key_event->state());
+               key_event->accept();
+               result=TRUE;
+           }
+
+           if (ch || macro) {
+               qApp->exit_loop();
+           }
+       }
+    }
+    return result;
+}
+
+NetHackQtBind* NetHackQtBind::instance=0;
+NetHackQtKeyBuffer NetHackQtBind::keybuffer;
+NetHackQtClickBuffer NetHackQtBind::clickbuffer;
+NetHackQtMainWindow* NetHackQtBind::main=0;
+QWidget* NetHackQtBind::splash=0;
+
+
+extern "C" struct window_procs Qt_procs;
+
+struct window_procs Qt_procs = {
+    "Qt",
+    WC_COLOR|WC_HILITE_PET|
+       WC_ASCII_MAP|WC_TILED_MAP|
+       WC_FONT_MAP|WC_TILE_FILE|WC_TILE_WIDTH|WC_TILE_HEIGHT|
+       WC_PLAYER_SELECTION|WC_SPLASH_SCREEN,
+    0L,
+    NetHackQtBind::qt_init_nhwindows,
+    NetHackQtBind::qt_player_selection,
+    NetHackQtBind::qt_askname,
+    NetHackQtBind::qt_get_nh_event,
+    NetHackQtBind::qt_exit_nhwindows,
+    NetHackQtBind::qt_suspend_nhwindows,
+    NetHackQtBind::qt_resume_nhwindows,
+    NetHackQtBind::qt_create_nhwindow,
+    NetHackQtBind::qt_clear_nhwindow,
+    NetHackQtBind::qt_display_nhwindow,
+    NetHackQtBind::qt_destroy_nhwindow,
+    NetHackQtBind::qt_curs,
+    NetHackQtBind::qt_putstr,
+    NetHackQtBind::qt_display_file,
+    NetHackQtBind::qt_start_menu,
+    NetHackQtBind::qt_add_menu,
+    NetHackQtBind::qt_end_menu,
+    NetHackQtBind::qt_select_menu,
+    genl_message_menu,      /* no need for X-specific handling */
+    NetHackQtBind::qt_update_inventory,
+    NetHackQtBind::qt_mark_synch,
+    NetHackQtBind::qt_wait_synch,
+#ifdef CLIPPING
+    NetHackQtBind::qt_cliparound,
+#endif
+#ifdef POSITIONBAR
+    donull,
+#endif
+    NetHackQtBind::qt_print_glyph,
+    //NetHackQtBind::qt_print_glyph_compose,
+    NetHackQtBind::qt_raw_print,
+    NetHackQtBind::qt_raw_print_bold,
+    NetHackQtBind::qt_nhgetch,
+    NetHackQtBind::qt_nh_poskey,
+    NetHackQtBind::qt_nhbell,
+    NetHackQtBind::qt_doprev_message,
+    NetHackQtBind::qt_yn_function,
+    NetHackQtBind::qt_getlin,
+    NetHackQtBind::qt_get_ext_cmd,
+    NetHackQtBind::qt_number_pad,
+    NetHackQtBind::qt_delay_output,
+#ifdef CHANGE_COLOR     /* only a Mac option currently */
+    donull,
+    donull,
+#endif
+    /* other defs that really should go away (they're tty specific) */
+    NetHackQtBind::qt_start_screen,
+    NetHackQtBind::qt_end_screen,
+#ifdef GRAPHIC_TOMBSTONE
+    NetHackQtBind::qt_outrip,
+#else
+    genl_outrip,
+#endif
+    genl_preference_update,
+};
+
+extern "C" void play_usersound(const char* filename, int volume)
+{
+#ifdef USER_SOUNDS
+#ifndef QT_NO_SOUND
+    QSound::play(filename);
+#endif
+#endif
+}
+
+#include "qt_win.moc"
+#ifndef KDE
+#include "qt_kde0.moc"
+#endif
+#if QT_VERSION >= 300
+#include "qttableview.moc"
+#endif
diff --git a/win/Qt/qttableview.cpp b/win/Qt/qttableview.cpp
new file mode 100644 (file)
index 0000000..abeda15
--- /dev/null
@@ -0,0 +1,2275 @@
+/**********************************************************************
+** $Id: qttableview.cpp,v 1.2 2002/03/09 03:13:15 jwalz Exp $
+**
+** Implementation of QtTableView class
+**
+** Created : 941115
+**
+** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
+**
+** This file contains a class moved out of the Qt GUI Toolkit API. It
+** may be used, distributed and modified without limitation.
+**
+**********************************************************************/
+
+#include "qttableview.h"
+#if QT_VERSION >= 300
+#ifndef QT_NO_QTTABLEVIEW
+#include <qscrollbar.h>
+#include <qpainter.h>
+#include <qdrawutil.h>
+#include <limits.h>
+
+enum ScrollBarDirtyFlags {
+    verGeometry          = 0x01,
+    verSteps     = 0x02,
+    verRange     = 0x04,
+    verValue     = 0x08,
+    horGeometry          = 0x10,
+    horSteps     = 0x20,
+    horRange     = 0x40,
+    horValue     = 0x80,
+    verMask      = 0x0F,
+    horMask      = 0xF0
+};
+
+
+#define HSBEXT horizontalScrollBar()->sizeHint().height()
+#define VSBEXT verticalScrollBar()->sizeHint().width()
+
+
+class QCornerSquare : public QWidget           // internal class
+{
+public:
+    QCornerSquare( QWidget *, const char* = 0 );
+    void paintEvent( QPaintEvent * );
+};
+
+QCornerSquare::QCornerSquare( QWidget *parent, const char *name )
+       : QWidget( parent, name )
+{
+}
+
+void QCornerSquare::paintEvent( QPaintEvent * )
+{
+}
+
+
+// NOT REVISED
+/*!
+  \class QtTableView qttableview.h
+  \brief The QtTableView class provides an abstract base for tables.
+
+  \obsolete
+
+  A table view consists of a number of abstract cells organized in rows
+  and columns, and a visible part called a view. The cells are identified
+  with a row index and a column index. The top-left cell is in row 0,
+  column 0.
+
+  The behavior of the widget can be finely tuned using
+  setTableFlags(); a typical subclass will consist of little more than a
+  call to setTableFlags(), some table content manipulation and an
+  implementation of paintCell().  Subclasses that need cells with
+  variable width or height must reimplement cellHeight() and/or
+  cellWidth(). Use updateTableSize() to tell QtTableView when the
+  width or height has changed.
+
+  When you read this documentation, it is important to understand the
+  distinctions among the four pixel coordinate systems involved.
+
+  \list 1
+  \i The \e cell coordinates.  (0,0) is the top-left corner of a cell.
+  Cell coordinates are used by functions such as paintCell().
+
+  \i The \e table coordinates.  (0,0) is the top-left corner of the cell at
+  row 0 and column 0. These coordinates are absolute; that is, they are
+  independent of what part of the table is visible at the moment. They are
+  used by functions such as setXOffset() or maxYOffset().
+
+  \i The \e widget coordinates. (0,0) is the top-left corner of the widget,
+  \e including the frame.  They are used by functions such as repaint().
+
+  \i The \e view coordinates.  (0,0) is the top-left corner of the view, \e
+  excluding the frame.  This is the least-used coordinate system; it is used by
+  functions such as viewWidth().  \endlist
+
+  It is rather unfortunate that we have to use four different
+  coordinate systems, but there was no alternative to provide a flexible and
+  powerful base class.
+
+  Note: The row,column indices are always given in that order,
+  i.e., first the vertical (row), then the horizontal (column). This is
+  the opposite order of all pixel operations, which take first the
+  horizontal (x) and then the vertical (y).
+
+  <img src=qtablevw-m.png> <img src=qtablevw-w.png>
+
+  \warning the functions setNumRows(), setNumCols(), setCellHeight(),
+  setCellWidth(), setTableFlags() and clearTableFlags() may cause
+  virtual functions such as cellWidth() and cellHeight() to be called,
+  even if autoUpdate() is FALSE.  This may cause errors if relevant
+  state variables are not initialized.
+
+  \warning Experience has shown that use of this widget tends to cause
+  more bugs than expected and our analysis indicates that the widget's
+  very flexibility is the problem.  If QScrollView or QListBox can
+  easily be made to do the job you need, we recommend subclassing
+  those widgets rather than QtTableView. In addition, QScrollView makes
+  it easy to have child widgets inside tables, which QtTableView
+  doesn't support at all.
+
+  \sa QScrollView
+  \link guibooks.html#fowler GUI Design Handbook: Table\endlink
+*/
+
+
+/*!
+  Constructs a table view.  The \a parent, \a name and \f arguments
+  are passed to the QFrame constructor.
+
+  The \link setTableFlags() table flags\endlink are all cleared (set to 0).
+  Set \c Tbl_autoVScrollBar or \c Tbl_autoHScrollBar to get automatic scroll
+  bars and \c Tbl_clipCellPainting to get safe clipping.
+
+  The \link setCellHeight() cell height\endlink and \link setCellWidth()
+  cell width\endlink are set to 0.
+
+  Frame line shapes (QFrame::HLink and QFrame::VLine) are disallowed;
+  see QFrame::setFrameStyle().
+
+  Note that the \a f argument is \e not \link setTableFlags() table
+  flags \endlink but rather \link QWidget::QWidget() widget
+  flags. \endlink
+
+*/
+
+QtTableView::QtTableView( QWidget *parent, const char *name, WFlags f )
+    : QFrame( parent, name, f )
+{
+    nRows               = nCols      = 0;      // zero rows/cols
+    xCellOffs           = yCellOffs  = 0;      // zero offset
+    xCellDelta          = yCellDelta = 0;      // zero cell offset
+    xOffs               = yOffs      = 0;      // zero total pixel offset
+    cellH               = cellW      = 0;      // user defined cell size
+    tFlags              = 0;
+    vScrollBar          = hScrollBar = 0;      // no scroll bars
+    cornerSquare        = 0;
+    sbDirty             = 0;
+    eraseInPaint        = FALSE;
+    verSliding          = FALSE;
+    verSnappingOff      = FALSE;
+    horSliding          = FALSE;
+    horSnappingOff      = FALSE;
+    coveringCornerSquare = FALSE;
+    inSbUpdate          = FALSE;
+}
+
+/*!
+  Destroys the table view.
+*/
+
+QtTableView::~QtTableView()
+{
+    delete vScrollBar;
+    delete hScrollBar;
+    delete cornerSquare;
+}
+
+
+/*!
+  \internal
+  Reimplements QWidget::setBackgroundColor() for binary compatibility.
+  \sa setPalette()
+*/
+
+void QtTableView::setBackgroundColor( const QColor &c )
+{
+    QWidget::setBackgroundColor( c );
+}
+
+/*!\reimp
+*/
+
+void QtTableView::setPalette( const QPalette &p )
+{
+    QWidget::setPalette( p );
+}
+
+/*!\reimp
+*/
+
+void QtTableView::show()
+{
+    showOrHideScrollBars();
+    QWidget::show();
+}
+
+
+/*!
+  \overload void QtTableView::repaint( bool erase )
+  Repaints the entire view.
+*/
+
+/*!
+  Repaints the table view directly by calling paintEvent() directly
+  unless updates are disabled.
+
+  Erases the view area \a (x,y,w,h) if \a erase is TRUE. Parameters \a
+  (x,y) are in \e widget coordinates.
+
+  If \a w is negative, it is replaced with <code>width() - x</code>.
+  If \a h is negative, it is replaced with <code>height() - y</code>.
+
+  Doing a repaint() usually is faster than doing an update(), but
+  calling update() many times in a row will generate a single paint
+  event.
+
+  At present, QtTableView is the only widget that reimplements \link
+  QWidget::repaint() repaint()\endlink.         It does this because by
+  clearing and then repainting one cell at at time, it can make the
+  screen flicker less than it would otherwise.  */
+
+void QtTableView::repaint( int x, int y, int w, int h, bool erase )
+{
+    if ( !isVisible() || testWState(WState_BlockUpdates) )
+       return;
+    if ( w < 0 )
+       w = width()  - x;
+    if ( h < 0 )
+       h = height() - y;
+    QRect r( x, y, w, h );
+    if ( r.isEmpty() )
+       return; // nothing to do
+    QPaintEvent e( r );
+    if ( erase && backgroundMode() != NoBackground )
+       eraseInPaint = TRUE;                    // erase when painting
+    paintEvent( &e );
+    eraseInPaint = FALSE;
+}
+
+/*!
+  \overload void QtTableView::repaint( const QRect &r, bool erase )
+  Replaints rectangle \a r. If \a erase is TRUE draws the background
+  using the palette's background.
+*/
+
+
+/*!
+  \fn int QtTableView::numRows() const
+  Returns the number of rows in the table.
+  \sa numCols(), setNumRows()
+*/
+
+/*!
+  Sets the number of rows of the table to \a rows (must be non-negative).
+  Does not change topCell().
+
+  The table repaints itself automatically if autoUpdate() is set.
+
+  \sa numCols(), setNumCols(), numRows()
+*/
+
+void QtTableView::setNumRows( int rows )
+{
+    if ( rows < 0 ) {
+#if defined(QT_CHECK_RANGE)
+       qWarning( "QtTableView::setNumRows: (%s) Negative argument %d.",
+                name( "unnamed" ), rows );
+#endif
+       return;
+    }
+    if ( nRows == rows )
+       return;
+
+    if ( autoUpdate() && isVisible() ) {
+       int oldLastVisible = lastRowVisible();
+       int oldTopCell = topCell();
+       nRows = rows;
+       if ( autoUpdate() && isVisible() &&
+            ( oldLastVisible != lastRowVisible() || oldTopCell != topCell() ) )
+               repaint( oldTopCell != topCell() );
+    } else {
+       // Be more careful - if destructing, bad things might happen.
+       nRows = rows;
+    }
+    updateScrollBars( verRange );
+    updateFrameSize();
+}
+
+/*!
+  \fn int QtTableView::numCols() const
+  Returns the number of columns in the table.
+  \sa numRows(), setNumCols()
+*/
+
+/*!
+  Sets the number of columns of the table to \a cols (must be non-negative).
+  Does not change leftCell().
+
+  The table repaints itself automatically if autoUpdate() is set.
+
+  \sa numCols(), numRows(), setNumRows()
+*/
+
+void QtTableView::setNumCols( int cols )
+{
+    if ( cols < 0 ) {
+#if defined(QT_CHECK_RANGE)
+       qWarning( "QtTableView::setNumCols: (%s) Negative argument %d.",
+                name( "unnamed" ), cols );
+#endif
+       return;
+    }
+    if ( nCols == cols )
+       return;
+    int oldCols = nCols;
+    nCols = cols;
+    if ( autoUpdate() && isVisible() ) {
+       int maxCol = lastColVisible();
+       if ( maxCol >= oldCols || maxCol >= nCols )
+           repaint();
+    }
+    updateScrollBars( horRange );
+    updateFrameSize();
+}
+
+
+/*!
+  \fn int QtTableView::topCell() const
+  Returns the index of the first row in the table that is visible in
+  the view.  The index of the first row is 0.
+  \sa leftCell(), setTopCell()
+*/
+
+/*!
+  Scrolls the table so that \a row becomes the top row.
+  The index of the very first row is 0.
+  \sa setYOffset(), setTopLeftCell(), setLeftCell()
+*/
+
+void QtTableView::setTopCell( int row )
+{
+    setTopLeftCell( row, -1 );
+    return;
+}
+
+/*!
+  \fn int QtTableView::leftCell() const
+  Returns the index of the first column in the table that is visible in
+  the view.  The index of the very leftmost column is 0.
+  \sa topCell(), setLeftCell()
+*/
+
+/*!
+  Scrolls the table so that \a col becomes the leftmost
+  column.  The index of the leftmost column is 0.
+  \sa setXOffset(), setTopLeftCell(), setTopCell()
+*/
+
+void QtTableView::setLeftCell( int col )
+{
+    setTopLeftCell( -1, col );
+    return;
+}
+
+/*!
+  Scrolls the table so that the cell at row \a row and colum \a
+  col becomes the top-left cell in the view.  The cell at the extreme
+  top left of the table is at position (0,0).
+  \sa setLeftCell(), setTopCell(), setOffset()
+*/
+
+void QtTableView::setTopLeftCell( int row, int col )
+{
+    int newX = xOffs;
+    int newY = yOffs;
+
+    if ( col >= 0 ) {
+       if ( cellW ) {
+           newX = col*cellW;
+           if ( newX > maxXOffset() )
+               newX = maxXOffset();
+       } else {
+           newX = 0;
+           while ( col )
+               newX += cellWidth( --col );   // optimize using current! ###
+       }
+    }
+    if ( row >= 0 ) {
+       if ( cellH ) {
+           newY = row*cellH;
+           if ( newY > maxYOffset() )
+               newY = maxYOffset();
+       } else {
+           newY = 0;
+           while ( row )
+               newY += cellHeight( --row );   // optimize using current! ###
+       }
+    }
+    setOffset( newX, newY );
+}
+
+
+/*!
+  \fn int QtTableView::xOffset() const
+
+  Returns the x coordinate in \e table coordinates of the pixel that is
+  currently on the left edge of the view.
+
+  \sa setXOffset(), yOffset(), leftCell() */
+
+/*!
+  Scrolls the table so that \a x becomes the leftmost pixel in the view.
+  The \a x parameter is in \e table coordinates.
+
+  The interaction with \link setTableFlags() Tbl_snapToHGrid
+  \endlink is tricky.
+
+  \sa xOffset(), setYOffset(), setOffset(), setLeftCell()
+*/
+
+void QtTableView::setXOffset( int x )
+{
+    setOffset( x, yOffset() );
+}
+
+/*!
+  \fn int QtTableView::yOffset() const
+
+  Returns the y coordinate in \e table coordinates of the pixel that is
+  currently on the top edge of the view.
+
+  \sa setYOffset(), xOffset(), topCell()
+*/
+
+
+/*!
+  Scrolls the table so that \a y becomes the top pixel in the view.
+  The \a y parameter is in \e table coordinates.
+
+  The interaction with \link setTableFlags() Tbl_snapToVGrid
+  \endlink is tricky.
+
+  \sa yOffset(), setXOffset(), setOffset(), setTopCell()
+*/
+
+void QtTableView::setYOffset( int y )
+{
+    setOffset( xOffset(), y );
+}
+
+/*!
+  Scrolls the table so that \a (x,y) becomes the top-left pixel
+  in the view. Parameters \a (x,y) are in \e table coordinates.
+
+  The interaction with \link setTableFlags() Tbl_snapTo*Grid \endlink
+  is tricky.  If \a updateScrBars is TRUE, the scroll bars are
+  updated.
+
+  \sa xOffset(), yOffset(), setXOffset(), setYOffset(), setTopLeftCell()
+*/
+
+void QtTableView::setOffset( int x, int y, bool updateScrBars )
+{
+    if ( (!testTableFlags(Tbl_snapToHGrid) || xCellDelta == 0) &&
+        (!testTableFlags(Tbl_snapToVGrid) || yCellDelta == 0) &&
+        (x == xOffs && y == yOffs) )
+       return;
+
+    if ( x < 0 )
+       x = 0;
+    if ( y < 0 )
+       y = 0;
+
+    if ( cellW ) {
+       if ( x > maxXOffset() )
+           x = maxXOffset();
+       xCellOffs = x / cellW;
+       if ( !testTableFlags(Tbl_snapToHGrid) ) {
+           xCellDelta  = (short)(x % cellW);
+       } else {
+           x           = xCellOffs*cellW;
+           xCellDelta  = 0;
+       }
+    } else {
+       int xn=0, xcd=0, col = 0;
+       while ( col < nCols-1 && x >= xn+(xcd=cellWidth(col)) ) {
+           xn += xcd;
+           col++;
+       }
+       xCellOffs = col;
+       if ( testTableFlags(Tbl_snapToHGrid) ) {
+           xCellDelta = 0;
+           x = xn;
+       } else {
+           xCellDelta = (short)(x-xn);
+       }
+    }
+    if ( cellH ) {
+       if ( y > maxYOffset() )
+           y = maxYOffset();
+       yCellOffs = y / cellH;
+       if ( !testTableFlags(Tbl_snapToVGrid) ) {
+           yCellDelta  = (short)(y % cellH);
+       } else {
+           y           = yCellOffs*cellH;
+           yCellDelta  = 0;
+       }
+    } else {
+       int yn=0, yrd=0, row=0;
+       while ( row < nRows-1 && y >= yn+(yrd=cellHeight(row)) ) {
+           yn += yrd;
+           row++;
+       }
+       yCellOffs = row;
+       if ( testTableFlags(Tbl_snapToVGrid) ) {
+           yCellDelta = 0;
+           y = yn;
+       } else {
+           yCellDelta = (short)(y-yn);
+       }
+    }
+    int dx = (x - xOffs);
+    int dy = (y - yOffs);
+    xOffs = x;
+    yOffs = y;
+    if ( autoUpdate() && isVisible() )
+       scroll( dx, dy );
+    if ( updateScrBars )
+       updateScrollBars( verValue | horValue );
+}
+
+
+/*!
+  \overload int QtTableView::cellWidth() const
+
+  Returns the column width in pixels.  Returns 0 if the columns have
+  variable widths.
+
+  \sa setCellWidth(), cellHeight()
+*/
+
+/*!
+  Returns the width of column \a col in pixels.
+
+  This function is virtual and must be reimplemented by subclasses that
+  have variable cell widths. Note that if the total table width
+  changes, updateTableSize() must be called.
+
+  \sa setCellWidth(), cellHeight(), totalWidth(), updateTableSize()
+*/
+
+int QtTableView::cellWidth( int )
+{
+    return cellW;
+}
+
+
+/*!
+  Sets the width in pixels of the table cells to \a cellWidth.
+
+  Setting it to 0 means that the column width is variable.  When
+  set to 0 (this is the default) QtTableView calls the virtual function
+  cellWidth() to get the width.
+
+  \sa cellWidth(), setCellHeight(), totalWidth(), numCols()
+*/
+
+void QtTableView::setCellWidth( int cellWidth )
+{
+    if ( cellW == cellWidth )
+       return;
+#if defined(QT_CHECK_RANGE)
+    if ( cellWidth < 0 || cellWidth > SHRT_MAX ) {
+       qWarning( "QtTableView::setCellWidth: (%s) Argument out of range (%d)",
+                name( "unnamed" ), cellWidth );
+       return;
+    }
+#endif
+    cellW = (short)cellWidth;
+
+    updateScrollBars( horSteps | horRange );
+    if ( autoUpdate() && isVisible() )
+       repaint();
+
+}
+
+/*!
+  \overload int QtTableView::cellHeight() const
+
+  Returns the row height, in pixels.  Returns 0 if the rows have
+  variable heights.
+
+  \sa setCellHeight(), cellWidth()
+*/
+
+
+/*!
+  Returns the height of row \a row in pixels.
+
+  This function is virtual and must be reimplemented by subclasses that
+  have variable cell heights.  Note that if the total table height
+  changes, updateTableSize() must be called.
+
+  \sa setCellHeight(), cellWidth(), totalHeight()
+*/
+
+int QtTableView::cellHeight( int )
+{
+    return cellH;
+}
+
+/*!
+  Sets the height in pixels of the table cells to \a cellHeight.
+
+  Setting it to 0 means that the row height is variable.  When set
+  to 0 (this is the default), QtTableView calls the virtual function
+  cellHeight() to get the height.
+
+  \sa cellHeight(), setCellWidth(), totalHeight(), numRows()
+*/
+
+void QtTableView::setCellHeight( int cellHeight )
+{
+    if ( cellH == cellHeight )
+       return;
+#if defined(QT_CHECK_RANGE)
+    if ( cellHeight < 0 || cellHeight > SHRT_MAX ) {
+       qWarning( "QtTableView::setCellHeight: (%s) Argument out of range (%d)",
+                name( "unnamed" ), cellHeight );
+       return;
+    }
+#endif
+    cellH = (short)cellHeight;
+    if ( autoUpdate() && isVisible() )
+       repaint();
+    updateScrollBars( verSteps | verRange );
+}
+
+
+/*!
+  Returns the total width of the table in pixels.
+
+  This function is virtual and should be reimplemented by subclasses that
+  have variable cell widths and a non-trivial cellWidth() function, or a
+  large number of columns in the table.
+
+  The default implementation may be slow for very wide tables.
+
+  \sa cellWidth(), totalHeight() */
+
+int QtTableView::totalWidth()
+{
+    if ( cellW ) {
+       return cellW*nCols;
+    } else {
+       int tw = 0;
+       for( int i = 0 ; i < nCols ; i++ )
+           tw += cellWidth( i );
+       return tw;
+    }
+}
+
+/*!
+  Returns the total height of the table in pixels.
+
+  This function is virtual and should be reimplemented by subclasses that
+  have variable cell heights and a non-trivial cellHeight() function, or a
+  large number of rows in the table.
+
+  The default implementation may be slow for very tall tables.
+
+  \sa cellHeight(), totalWidth()
+*/
+
+int QtTableView::totalHeight()
+{
+    if ( cellH ) {
+       return cellH*nRows;
+    } else {
+       int th = 0;
+       for( int i = 0 ; i < nRows ; i++ )
+           th += cellHeight( i );
+       return th;
+    }
+}
+
+
+/*!
+  \fn uint QtTableView::tableFlags() const
+
+  Returns the union of the table flags that are currently set.
+
+  \sa setTableFlags(), clearTableFlags(), testTableFlags()
+*/
+
+/*!
+  \fn bool QtTableView::testTableFlags( uint f ) const
+
+  Returns TRUE if any of the table flags in \a f are currently set,
+  otherwise FALSE.
+
+  \sa setTableFlags(), clearTableFlags(), tableFlags()
+*/
+
+/*!
+  Sets the table flags to \a f.
+
+  If a flag setting changes the appearance of the table, the table is
+  repainted if - and only if - autoUpdate() is TRUE.
+
+  The table flags are mostly single bits, though there are some multibit
+  flags for convenience. Here is a complete list:
+
+  <dl compact>
+  <dt> Tbl_vScrollBar <dd> - The table has a vertical scroll bar.
+  <dt> Tbl_hScrollBar <dd> - The table has a horizontal scroll bar.
+  <dt> Tbl_autoVScrollBar <dd> - The table has a vertical scroll bar if
+  - and only if - the table is taller than the view.
+  <dt> Tbl_autoHScrollBar <dd> The table has a horizontal scroll bar if
+  - and only if - the table is wider than the view.
+  <dt> Tbl_autoScrollBars <dd> - The union of the previous two flags.
+  <dt> Tbl_clipCellPainting <dd> - The table uses QPainter::setClipRect() to
+  make sure that paintCell() will not draw outside the cell
+  boundaries.
+  <dt> Tbl_cutCellsV <dd> - The table will never show part of a
+  cell at the bottom of the table; if there is not space for all of
+  a cell, the space is left blank.
+  <dt> Tbl_cutCellsH <dd> - The table will never show part of a
+  cell at the right side of the table; if there is not space for all of
+  a cell, the space is left blank.
+  <dt> Tbl_cutCells <dd> - The union of the previous two flags.
+  <dt> Tbl_scrollLastHCell <dd> - When the user scrolls horizontally,
+  let him/her scroll the last cell left until it is at the left
+  edge of the view.  If this flag is not set, the user can only scroll
+  to the point where the last cell is completely visible.
+  <dt> Tbl_scrollLastVCell <dd> - When the user scrolls vertically, let
+  him/her scroll the last cell up until it is at the top edge of
+  the view.  If this flag is not set, the user can only scroll to the
+  point where the last cell is completely visible.
+  <dt> Tbl_scrollLastCell <dd> - The union of the previous two flags.
+  <dt> Tbl_smoothHScrolling <dd> - The table scrolls as smoothly as
+  possible when the user scrolls horizontally. When this flag is not
+  set, scrolling is done one cell at a time.
+  <dt> Tbl_smoothVScrolling <dd> - The table scrolls as smoothly as
+  possible when scrolling vertically. When this flag is not set,
+  scrolling is done one cell at a time.
+  <dt> Tbl_smoothScrolling <dd> - The union of the previous two flags.
+  <dt> Tbl_snapToHGrid <dd> - Except when the user is actually scrolling,
+  the leftmost column shown snaps to the leftmost edge of the view.
+  <dt> Tbl_snapToVGrid <dd> - Except when the user is actually
+  scrolling, the top row snaps to the top edge of the view.
+  <dt> Tbl_snapToGrid <dd> - The union of the previous two flags.
+  </dl>
+
+  You can specify more than one flag at a time using bitwise OR.
+
+  Example:
+  \code
+    setTableFlags( Tbl_smoothScrolling | Tbl_autoScrollBars );
+  \endcode
+
+  \warning The cutCells options (\c Tbl_cutCells, \c Tbl_cutCellsH and
+  Tbl_cutCellsV) may cause painting problems when scrollbars are
+  enabled. Do not combine cutCells and scrollbars.
+
+
+  \sa clearTableFlags(), testTableFlags(), tableFlags()
+*/
+
+void QtTableView::setTableFlags( uint f )
+{
+    f = (f ^ tFlags) & f;                      // clear flags already set
+    tFlags |= f;
+
+    bool updateOn = autoUpdate();
+    setAutoUpdate( FALSE );
+
+    uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH;
+
+    if ( f & Tbl_vScrollBar ) {
+       setVerScrollBar( TRUE );
+    }
+    if ( f & Tbl_hScrollBar ) {
+       setHorScrollBar( TRUE );
+    }
+    if ( f & Tbl_autoVScrollBar ) {
+       updateScrollBars( verRange );
+    }
+    if ( f & Tbl_autoHScrollBar ) {
+       updateScrollBars( horRange );
+    }
+    if ( f & Tbl_scrollLastHCell ) {
+       updateScrollBars( horRange );
+    }
+    if ( f & Tbl_scrollLastVCell ) {
+       updateScrollBars( verRange );
+    }
+    if ( f & Tbl_snapToHGrid ) {
+       updateScrollBars( horRange );
+    }
+    if ( f & Tbl_snapToVGrid ) {
+       updateScrollBars( verRange );
+    }
+    if ( f & Tbl_snapToGrid ) {                        // Note: checks for 2 flags
+       if ( (f & Tbl_snapToHGrid) != 0 && xCellDelta != 0 || //have to scroll?
+            (f & Tbl_snapToVGrid) != 0 && yCellDelta != 0 ) {
+           snapToGrid( (f & Tbl_snapToHGrid) != 0,     // do snapping
+                       (f & Tbl_snapToVGrid) != 0 );
+           repaintMask |= Tbl_snapToGrid;      // repaint table
+       }
+    }
+
+    if ( updateOn ) {
+       setAutoUpdate( TRUE );
+       updateScrollBars();
+       if ( isVisible() && (f & repaintMask) )
+           repaint();
+    }
+
+}
+
+/*!
+  Clears the \link setTableFlags() table flags\endlink that are set
+  in \a f.
+
+  Example (clears a single flag):
+  \code
+    clearTableFlags( Tbl_snapToGrid );
+  \endcode
+
+  The default argument clears all flags.
+
+  \sa setTableFlags(), testTableFlags(), tableFlags()
+*/
+
+void QtTableView::clearTableFlags( uint f )
+{
+    f = (f ^ ~tFlags) & f;             // clear flags that are already 0
+    tFlags &= ~f;
+
+    bool updateOn = autoUpdate();
+    setAutoUpdate( FALSE );
+
+    uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH;
+
+    if ( f & Tbl_vScrollBar ) {
+       setVerScrollBar( FALSE );
+    }
+    if ( f & Tbl_hScrollBar ) {
+       setHorScrollBar( FALSE );
+    }
+    if ( f & Tbl_scrollLastHCell ) {
+       int maxX = maxXOffset();
+       if ( xOffs > maxX ) {
+           setOffset( maxX, yOffs );
+           repaintMask |= Tbl_scrollLastHCell;
+       }
+       updateScrollBars( horRange );
+    }
+    if ( f & Tbl_scrollLastVCell ) {
+       int maxY = maxYOffset();
+       if ( yOffs > maxY ) {
+           setOffset( xOffs, maxY );
+           repaintMask |= Tbl_scrollLastVCell;
+       }
+       updateScrollBars( verRange );
+    }
+    if ( f & Tbl_smoothScrolling ) {         // Note: checks for 2 flags
+       if ((f & Tbl_smoothHScrolling) != 0 && xCellDelta != 0 ||//must scroll?
+           (f & Tbl_smoothVScrolling) != 0 && yCellDelta != 0 ) {
+           snapToGrid( (f & Tbl_smoothHScrolling) != 0,      // do snapping
+                       (f & Tbl_smoothVScrolling) != 0 );
+           repaintMask |= Tbl_smoothScrolling;              // repaint table
+       }
+    }
+    if ( f & Tbl_snapToHGrid ) {
+       updateScrollBars( horRange );
+    }
+    if ( f & Tbl_snapToVGrid ) {
+       updateScrollBars( verRange );
+    }
+    if ( updateOn ) {
+       setAutoUpdate( TRUE );
+       updateScrollBars();          // returns immediately if nothing to do
+       if ( isVisible() && (f & repaintMask) )
+           repaint();
+    }
+
+}
+
+
+/*!
+  \fn bool QtTableView::autoUpdate() const
+
+  Returns TRUE if the view updates itself automatically whenever it
+  is changed in some way.
+
+  \sa setAutoUpdate()
+*/
+
+/*!
+  Sets the auto-update option of the table view to \a enable.
+
+  If \a enable is TRUE (this is the default), the view updates itself
+  automatically whenever it has changed in some way (for example, when a
+  \link setTableFlags() flag\endlink is changed).
+
+  If \a enable is FALSE, the view does NOT repaint itself or update
+  its internal state variables when it is changed.  This can be
+  useful to avoid flicker during large changes and is singularly
+  useless otherwise. Disable auto-update, do the changes, re-enable
+  auto-update and call repaint().
+
+  \warning Do not leave the view in this state for a long time
+  (i.e., between events). If, for example, the user interacts with the
+  view when auto-update is off, strange things can happen.
+
+  Setting auto-update to TRUE does not repaint the view; you must call
+  repaint() to do this.
+
+  \sa autoUpdate(), repaint()
+*/
+
+void QtTableView::setAutoUpdate( bool enable )
+{
+    if ( isUpdatesEnabled() == enable )
+       return;
+    setUpdatesEnabled( enable );
+    if ( enable ) {
+       showOrHideScrollBars();
+       updateScrollBars();
+    }
+}
+
+
+/*!
+  Repaints the cell at row \a row, column \a col if it is inside the view.
+
+  If \a erase is TRUE, the relevant part of the view is cleared to the
+  background color/pixmap before the contents are repainted.
+
+  \sa isVisible()
+*/
+
+void QtTableView::updateCell( int row, int col, bool erase )
+{
+    int xPos, yPos;
+    if ( !colXPos( col, &xPos ) )
+       return;
+    if ( !rowYPos( row, &yPos ) )
+       return;
+    QRect uR = QRect( xPos, yPos,
+                     cellW ? cellW : cellWidth(col),
+                     cellH ? cellH : cellHeight(row) );
+    repaint( uR.intersect(viewRect()), erase );
+}
+
+
+/*!
+  \fn QRect QtTableView::cellUpdateRect() const
+
+  This function should be called only from the paintCell() function in
+  subclasses. It returns the portion of a cell that actually needs to be
+  updated in \e cell coordinates. This is useful only for non-trivial
+  paintCell().
+
+*/
+
+/*!
+  Returns the rectangle that is the actual table, excluding any
+  frame, in \e widget coordinates.
+*/
+
+QRect QtTableView::viewRect() const
+{
+    return QRect( frameWidth(), frameWidth(), viewWidth(), viewHeight() );
+}
+
+
+/*!
+  Returns the index of the last (bottom) row in the view.
+  The index of the first row is 0.
+
+  If no rows are visible it returns -1.         This can happen if the
+  view is too small for the first row and Tbl_cutCellsV is set.
+
+  \sa lastColVisible()
+*/
+
+int QtTableView::lastRowVisible() const
+{
+    int cellMaxY;
+    int row = findRawRow( maxViewY(), &cellMaxY );
+    if ( row == -1 || row >= nRows ) {         // maxViewY() past end?
+       row = nRows - 1;                        // yes: return last row
+    } else {
+       if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() ) {
+           if ( row == yCellOffs )             // cut by right margin?
+               return -1;                      // yes, nothing in the view
+           else
+              row = row - 1;                   // cut by margin, one back
+       }
+    }
+    return row;
+}
+
+/*!
+  Returns the index of the last (right) column in the view.
+  The index of the first column is 0.
+
+  If no columns are visible it returns -1.  This can happen if the
+  view is too narrow for the first column and Tbl_cutCellsH is set.
+
+  \sa lastRowVisible()
+*/
+
+int QtTableView::lastColVisible() const
+{
+    int cellMaxX;
+    int col = findRawCol( maxViewX(), &cellMaxX );
+    if ( col == -1 || col >= nCols ) {         // maxViewX() past end?
+       col = nCols - 1;                        // yes: return last col
+    } else {
+       if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() ) {
+           if ( col == xCellOffs )             // cut by bottom margin?
+               return -1;                      // yes, nothing in the view
+           else
+              col = col - 1;                   // cell by margin, one back
+       }
+    }
+    return col;
+}
+
+/*!
+  Returns TRUE if \a row is at least partially visible.
+  \sa colIsVisible()
+*/
+
+bool QtTableView::rowIsVisible( int row ) const
+{
+    return rowYPos( row, 0 );
+}
+
+/*!
+  Returns TRUE if \a col is at least partially visible.
+  \sa rowIsVisible()
+*/
+
+bool QtTableView::colIsVisible( int col ) const
+{
+    return colXPos( col, 0 );
+}
+
+
+/*!
+  \internal
+  Called when both scroll bars are active at the same time. Covers the
+  bottom left corner between the two scroll bars with an empty widget.
+*/
+
+void QtTableView::coverCornerSquare( bool enable )
+{
+    coveringCornerSquare = enable;
+    if ( !cornerSquare && enable ) {
+       cornerSquare = new QCornerSquare( this );
+       Q_CHECK_PTR( cornerSquare );
+       cornerSquare->setGeometry( maxViewX() + frameWidth() + 1,
+                                  maxViewY() + frameWidth() + 1,
+                                   VSBEXT,
+                                 HSBEXT);
+    }
+    if ( autoUpdate() && cornerSquare ) {
+       if ( enable )
+           cornerSquare->show();
+       else
+           cornerSquare->hide();
+    }
+}
+
+
+/*!
+  \internal
+  Scroll the view to a position such that:
+
+  If \a horizontal is TRUE, the leftmost column shown fits snugly
+  with the left edge of the view.
+
+  If \a vertical is TRUE, the top row shown fits snugly with the top
+  of the view.
+
+  You can achieve the same effect automatically by setting any of the
+  \link setTableFlags() Tbl_snapTo*Grid \endlink table flags.
+*/
+
+void QtTableView::snapToGrid( bool horizontal, bool vertical )
+{
+    int newXCell = -1;
+    int newYCell = -1;
+    if ( horizontal && xCellDelta != 0 ) {
+       int w = cellW ? cellW : cellWidth( xCellOffs );
+       if ( xCellDelta >= w/2 )
+           newXCell = xCellOffs + 1;
+       else
+           newXCell = xCellOffs;
+    }
+    if ( vertical && yCellDelta != 0 ) {
+       int h = cellH ? cellH : cellHeight( yCellOffs );
+       if ( yCellDelta >= h/2 )
+           newYCell = yCellOffs + 1;
+       else
+           newYCell = yCellOffs;
+    }
+    setTopLeftCell( newYCell, newXCell );  //row,column
+}
+
+/*!
+  \internal
+  This internal slot is connected to the horizontal scroll bar's
+  QScrollBar::valueChanged() signal.
+
+  Moves the table horizontally to offset \a val without updating the
+  scroll bar.
+*/
+
+void QtTableView::horSbValue( int val )
+{
+    if ( horSliding ) {
+       horSliding = FALSE;
+       if ( horSnappingOff ) {
+           horSnappingOff = FALSE;
+           tFlags |= Tbl_snapToHGrid;
+       }
+    }
+    setOffset( val, yOffs, FALSE );
+}
+
+/*!
+  \internal
+  This internal slot is connected to the horizontal scroll bar's
+  QScrollBar::sliderMoved() signal.
+
+  Scrolls the table smoothly horizontally even if \c Tbl_snapToHGrid is set.
+*/
+
+void QtTableView::horSbSliding( int val )
+{
+    if ( testTableFlags(Tbl_snapToHGrid) &&
+        testTableFlags(Tbl_smoothHScrolling) ) {
+       tFlags &= ~Tbl_snapToHGrid;     // turn off snapping while sliding
+       setOffset( val, yOffs, FALSE );
+       tFlags |= Tbl_snapToHGrid;      // turn on snapping again
+    } else {
+       setOffset( val, yOffs, FALSE );
+    }
+}
+
+/*!
+  \internal
+  This internal slot is connected to the horizontal scroll bar's
+  QScrollBar::sliderReleased() signal.
+*/
+
+void QtTableView::horSbSlidingDone( )
+{
+    if ( testTableFlags(Tbl_snapToHGrid) &&
+        testTableFlags(Tbl_smoothHScrolling) )
+       snapToGrid( TRUE, FALSE );
+}
+
+/*!
+  \internal
+  This internal slot is connected to the vertical scroll bar's
+  QScrollBar::valueChanged() signal.
+
+  Moves the table vertically to offset \a val without updating the
+  scroll bar.
+*/
+
+void QtTableView::verSbValue( int val )
+{
+    if ( verSliding ) {
+       verSliding = FALSE;
+       if ( verSnappingOff ) {
+           verSnappingOff = FALSE;
+           tFlags |= Tbl_snapToVGrid;
+       }
+    }
+    setOffset( xOffs, val, FALSE );
+}
+
+/*!
+  \internal
+  This internal slot is connected to the vertical scroll bar's
+  QScrollBar::sliderMoved() signal.
+
+  Scrolls the table smoothly vertically even if \c Tbl_snapToVGrid is set.
+*/
+
+void QtTableView::verSbSliding( int val )
+{
+    if ( testTableFlags(Tbl_snapToVGrid) &&
+        testTableFlags(Tbl_smoothVScrolling) ) {
+       tFlags &= ~Tbl_snapToVGrid;     // turn off snapping while sliding
+       setOffset( xOffs, val, FALSE );
+       tFlags |= Tbl_snapToVGrid;      // turn on snapping again
+    } else {
+       setOffset( xOffs, val, FALSE );
+    }
+}
+
+/*!
+  \internal
+  This internal slot is connected to the vertical scroll bar's
+  QScrollBar::sliderReleased() signal.
+*/
+
+void QtTableView::verSbSlidingDone( )
+{
+    if ( testTableFlags(Tbl_snapToVGrid) &&
+        testTableFlags(Tbl_smoothVScrolling) )
+       snapToGrid( FALSE, TRUE );
+}
+
+
+/*!
+  This virtual function is called before painting of table cells
+  is started. It can be reimplemented by subclasses that want to
+  to set up the painter in a special way and that do not want to
+  do so for each cell.
+*/
+
+void QtTableView::setupPainter( QPainter * )
+{
+}
+
+/*!
+  \fn void QtTableView::paintCell( QPainter *p, int row, int col )
+
+  This pure virtual function is called to paint the single cell at \a
+  (row,col) using \a p, which is open when paintCell() is called and
+  must remain open.
+
+  The coordinate system is \link QPainter::translate() translated \endlink
+  so that the origin is at the top-left corner of the cell to be
+  painted, i.e. \e cell coordinates.  Do not scale or shear the coordinate
+  system (or if you do, restore the transformation matrix before you
+  return).
+
+  The painter is not clipped by default and for maximum efficiency. For safety,
+  call setTableFlags(Tbl_clipCellPainting) to enable clipping.
+
+  \sa paintEvent(), setTableFlags() */
+
+
+/*!
+  Handles paint events, \a e, for the table view.
+
+  Calls paintCell() for the cells that needs to be repainted.
+*/
+
+void QtTableView::paintEvent( QPaintEvent *e )
+{
+    QRect updateR = e->rect();                 // update rectangle
+    if ( sbDirty ) {
+       bool e = eraseInPaint;
+       updateScrollBars();
+       eraseInPaint = e;
+    }
+
+    QPainter paint( this );
+
+    if ( !contentsRect().contains( updateR, TRUE  ) ) {// update frame ?
+       drawFrame( &paint );
+       if ( updateR.left() < frameWidth() )            //###
+           updateR.setLeft( frameWidth() );
+       if ( updateR.top() < frameWidth() )
+           updateR.setTop( frameWidth() );
+    }
+
+    int maxWX = maxViewX();
+    int maxWY = maxViewY();
+    if ( updateR.right() > maxWX )
+       updateR.setRight( maxWX );
+    if ( updateR.bottom() > maxWY )
+       updateR.setBottom( maxWY );
+
+    setupPainter( &paint );                    // prepare for painting table
+
+    int firstRow = findRow( updateR.y() );
+    int firstCol = findCol( updateR.x() );
+    int         xStart, yStart;
+    if ( !colXPos( firstCol, &xStart ) || !rowYPos( firstRow, &yStart ) ) {
+       paint.eraseRect( updateR ); // erase area outside cells but in view
+       return;
+    }
+    int          maxX  = updateR.right();
+    int          maxY  = updateR.bottom();
+    int          row   = firstRow;
+    int          col;
+    int          yPos  = yStart;
+    int          xPos = maxX+1; // in case the while() is empty
+    int          nextX;
+    int          nextY;
+    QRect winR = viewRect();
+    QRect cellR;
+    QRect cellUR;
+#ifndef QT_NO_TRANSFORMATIONS
+    QWMatrix matrix;
+#endif
+
+    while ( yPos <= maxY && row < nRows ) {
+       nextY = yPos + (cellH ? cellH : cellHeight( row ));
+       if ( testTableFlags( Tbl_cutCellsV ) && nextY > ( maxWY + 1 ) )
+           break;
+       col  = firstCol;
+       xPos = xStart;
+       while ( xPos <= maxX && col < nCols ) {
+           nextX = xPos + (cellW ? cellW : cellWidth( col ));
+           if ( testTableFlags( Tbl_cutCellsH ) && nextX > ( maxWX + 1 ) )
+               break;
+
+           cellR.setRect( xPos, yPos, cellW ? cellW : cellWidth(col),
+                                      cellH ? cellH : cellHeight(row) );
+           cellUR = cellR.intersect( updateR );
+           if ( cellUR.isValid() ) {
+               cellUpdateR = cellUR;
+               cellUpdateR.moveBy( -xPos, -yPos ); // cell coordinates
+               if ( eraseInPaint )
+                   paint.eraseRect( cellUR );
+
+#ifndef QT_NO_TRANSFORMATIONS
+               matrix.translate( xPos, yPos );
+               paint.setWorldMatrix( matrix );
+               if ( testTableFlags(Tbl_clipCellPainting) ||
+                    frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt
+                   paint.setClipRect( cellUR );
+                   paintCell( &paint, row, col );
+                   paint.setClipping( FALSE );
+               } else {
+                   paintCell( &paint, row, col );
+               }
+               matrix.reset();
+               paint.setWorldMatrix( matrix );
+#else
+               paint.translate( xPos, yPos );
+               if ( testTableFlags(Tbl_clipCellPainting) ||
+                    frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt
+                   paint.setClipRect( cellUR );
+                   paintCell( &paint, row, col );
+                   paint.setClipping( FALSE );
+               } else {
+                   paintCell( &paint, row, col );
+               }
+               paint.translate( -xPos, -yPos );
+#endif
+           }
+           col++;
+           xPos = nextX;
+       }
+       row++;
+       yPos = nextY;
+    }
+
+    // while painting we have to erase any areas in the view that
+    // are not covered by cells but are covered by the paint event
+    // rectangle these must be erased. We know that xPos is the last
+    // x pixel updated + 1 and that yPos is the last y pixel updated + 1.
+
+    // Note that this needs to be done regardless whether we do
+    // eraseInPaint or not. Reason: a subclass may implement
+    // flicker-freeness and encourage the use of repaint(FALSE).
+    // The subclass, however, cannot draw all pixels, just those
+    // inside the cells. So QtTableView is reponsible for all pixels
+    // outside the cells.
+
+    QRect viewR = viewRect();
+    const QColorGroup g = colorGroup();
+
+    if ( xPos <= maxX ) {
+       QRect r = viewR;
+       r.setLeft( xPos );
+       r.setBottom( yPos<maxY?yPos:maxY );
+       if ( inherits( "QMultiLineEdit" ) )
+           paint.fillRect( r.intersect( updateR ), g.base() );
+       else
+           paint.eraseRect( r.intersect( updateR ) );
+    }
+    if ( yPos <= maxY ) {
+       QRect r = viewR;
+       r.setTop( yPos );
+       if ( inherits( "QMultiLineEdit" ) )
+           paint.fillRect( r.intersect( updateR ), g.base() );
+       else
+           paint.eraseRect( r.intersect( updateR ) );
+    }
+}
+
+/*!\reimp
+*/
+void QtTableView::resizeEvent( QResizeEvent * )
+{
+    updateScrollBars( horValue | verValue | horSteps | horGeometry | horRange |
+                     verSteps | verGeometry | verRange );
+    showOrHideScrollBars();
+    updateFrameSize();
+    int maxX = QMIN( xOffs, maxXOffset() );                    // ### can be slow
+    int maxY = QMIN( yOffs, maxYOffset() );
+    setOffset( maxX, maxY );
+}
+
+
+/*!
+  Redraws all visible cells in the table view.
+*/
+
+void QtTableView::updateView()
+{
+    repaint( viewRect() );
+}
+
+/*!
+  Returns a pointer to the vertical scroll bar mainly so you can
+  connect() to its signals.  Note that the scroll bar works in pixel
+  values; use findRow() to translate to cell numbers.
+*/
+
+QScrollBar *QtTableView::verticalScrollBar() const
+{
+    QtTableView *that = (QtTableView*)this; // semantic const
+    if ( !vScrollBar ) {
+       QScrollBar *sb = new QScrollBar( QScrollBar::Vertical, that );
+#ifndef QT_NO_CURSOR
+       sb->setCursor( arrowCursor );
+#endif
+        sb->resize( sb->sizeHint() ); // height is irrelevant
+       Q_CHECK_PTR(sb);
+       sb->setTracking( FALSE );
+       sb->setFocusPolicy( NoFocus );
+       connect( sb, SIGNAL(valueChanged(int)),
+                SLOT(verSbValue(int)));
+       connect( sb, SIGNAL(sliderMoved(int)),
+                SLOT(verSbSliding(int)));
+       connect( sb, SIGNAL(sliderReleased()),
+                SLOT(verSbSlidingDone()));
+       sb->hide();
+       that->vScrollBar = sb;
+       return sb;
+    }
+    return vScrollBar;
+}
+
+/*!
+  Returns a pointer to the horizontal scroll bar mainly so you can
+  connect() to its signals. Note that the scroll bar works in pixel
+  values; use findCol() to translate to cell numbers.
+*/
+
+QScrollBar *QtTableView::horizontalScrollBar() const
+{
+    QtTableView *that = (QtTableView*)this; // semantic const
+    if ( !hScrollBar ) {
+       QScrollBar *sb = new QScrollBar( QScrollBar::Horizontal, that );
+#ifndef QT_NO_CURSOR
+       sb->setCursor( arrowCursor );
+#endif
+       sb->resize( sb->sizeHint() ); // width is irrelevant
+       sb->setFocusPolicy( NoFocus );
+       Q_CHECK_PTR(sb);
+       sb->setTracking( FALSE );
+       connect( sb, SIGNAL(valueChanged(int)),
+                SLOT(horSbValue(int)));
+       connect( sb, SIGNAL(sliderMoved(int)),
+                SLOT(horSbSliding(int)));
+       connect( sb, SIGNAL(sliderReleased()),
+                SLOT(horSbSlidingDone()));
+       sb->hide();
+       that->hScrollBar = sb;
+       return sb;
+    }
+    return hScrollBar;
+}
+
+/*!
+  Enables or disables the horizontal scroll bar, as required by
+  setAutoUpdate() and the \link setTableFlags() table flags\endlink.
+*/
+
+void QtTableView::setHorScrollBar( bool on, bool update )
+{
+    if ( on ) {
+       tFlags |= Tbl_hScrollBar;
+       horizontalScrollBar(); // created
+       if ( update )
+           updateScrollBars( horMask | verMask );
+       else
+           sbDirty = sbDirty | (horMask | verMask);
+       if ( testTableFlags( Tbl_vScrollBar ) )
+           coverCornerSquare( TRUE );
+       if ( autoUpdate() )
+           sbDirty = sbDirty | horMask;
+    } else {
+       tFlags &= ~Tbl_hScrollBar;
+       if ( !hScrollBar )
+           return;
+       coverCornerSquare( FALSE );
+       bool hideScrollBar = autoUpdate() && hScrollBar->isVisible();
+       if ( hideScrollBar )
+           hScrollBar->hide();
+       if ( update )
+           updateScrollBars( verMask );
+       else
+           sbDirty = sbDirty | verMask;
+       if ( hideScrollBar && isVisible() )
+           repaint( hScrollBar->x(), hScrollBar->y(),
+                    width() - hScrollBar->x(), hScrollBar->height() );
+    }
+    if ( update )
+       updateFrameSize();
+}
+
+
+/*!
+  Enables or disables the vertical scroll bar, as required by
+  setAutoUpdate() and the \link setTableFlags() table flags\endlink.
+*/
+
+void QtTableView::setVerScrollBar( bool on, bool update )
+{
+    if ( on ) {
+       tFlags |= Tbl_vScrollBar;
+       verticalScrollBar(); // created
+       if ( update )
+           updateScrollBars( verMask | horMask );
+       else
+           sbDirty = sbDirty | (horMask | verMask);
+       if ( testTableFlags( Tbl_hScrollBar ) )
+           coverCornerSquare( TRUE );
+       if ( autoUpdate() )
+           sbDirty = sbDirty | verMask;
+    } else {
+       tFlags &= ~Tbl_vScrollBar;
+       if ( !vScrollBar )
+           return;
+       coverCornerSquare( FALSE );
+       bool hideScrollBar = autoUpdate() && vScrollBar->isVisible();
+       if ( hideScrollBar )
+           vScrollBar->hide();
+       if ( update )
+           updateScrollBars( horMask );
+       else
+           sbDirty = sbDirty | horMask;
+       if ( hideScrollBar && isVisible() )
+           repaint( vScrollBar->x(), vScrollBar->y(),
+                    vScrollBar->width(), height() - vScrollBar->y() );
+    }
+    if ( update )
+       updateFrameSize();
+}
+
+
+
+
+int QtTableView::findRawRow( int yPos, int *cellMaxY, int *cellMinY,
+                           bool goOutsideView ) const
+{
+    int r = -1;
+    if ( nRows == 0 )
+       return r;
+    if ( goOutsideView || yPos >= minViewY() && yPos <= maxViewY() ) {
+       if ( yPos < minViewY() ) {
+#if defined(QT_CHECK_RANGE)
+           qWarning( "QtTableView::findRawRow: (%s) internal error: "
+                    "yPos < minViewY() && goOutsideView "
+                    "not supported. (%d,%d)",
+                    name( "unnamed" ), yPos, yOffs );
+#endif
+           return -1;
+       }
+       if ( cellH ) {                               // uniform cell height
+           r = (yPos - minViewY() + yCellDelta)/cellH; // cell offs from top
+           if ( cellMaxY )
+               *cellMaxY = (r + 1)*cellH + minViewY() - yCellDelta - 1;
+           if ( cellMinY )
+               *cellMinY = r*cellH + minViewY() - yCellDelta;
+           r += yCellOffs;                          // absolute cell index
+       } else {                                     // variable cell height
+           QtTableView *tw = (QtTableView *)this;
+           r        = yCellOffs;
+           int h    = minViewY() - yCellDelta; //##arnt3
+           int oldH = h;
+           Q_ASSERT( r < nRows );
+           while ( r < nRows ) {
+               oldH = h;
+               h += tw->cellHeight( r );            // Start of next cell
+               if ( yPos < h )
+                   break;
+               r++;
+           }
+           if ( cellMaxY )
+               *cellMaxY = h - 1;
+           if ( cellMinY )
+               *cellMinY = oldH;
+       }
+    }
+    return r;
+
+}
+
+
+int QtTableView::findRawCol( int xPos, int *cellMaxX, int *cellMinX ,
+                           bool goOutsideView ) const
+{
+    int c = -1;
+    if ( nCols == 0 )
+       return c;
+    if ( goOutsideView || xPos >= minViewX() && xPos <= maxViewX() ) {
+       if ( xPos < minViewX() ) {
+#if defined(QT_CHECK_RANGE)
+           qWarning( "QtTableView::findRawCol: (%s) internal error: "
+                    "xPos < minViewX() && goOutsideView "
+                    "not supported. (%d,%d)",
+                    name( "unnamed" ), xPos, xOffs );
+#endif
+           return -1;
+       }
+       if ( cellW ) {                          // uniform cell width
+           c = (xPos - minViewX() + xCellDelta)/cellW; //cell offs from left
+           if ( cellMaxX )
+               *cellMaxX = (c + 1)*cellW + minViewX() - xCellDelta - 1;
+           if ( cellMinX )
+               *cellMinX = c*cellW + minViewX() - xCellDelta;
+           c += xCellOffs;                     // absolute cell index
+       } else {                                // variable cell width
+           QtTableView *tw = (QtTableView *)this;
+           c        = xCellOffs;
+           int w    = minViewX() - xCellDelta; //##arnt3
+           int oldW = w;
+           Q_ASSERT( c < nCols );
+           while ( c < nCols ) {
+               oldW = w;
+               w += tw->cellWidth( c );        // Start of next cell
+               if ( xPos < w )
+                   break;
+               c++;
+           }
+           if ( cellMaxX )
+               *cellMaxX = w - 1;
+           if ( cellMinX )
+               *cellMinX = oldW;
+       }
+    }
+    return c;
+}
+
+
+/*!
+  Returns the index of the row at position \a yPos, where \a yPos is in
+  \e widget coordinates.  Returns -1 if \a yPos is outside the valid
+  range.
+
+  \sa findCol(), rowYPos()
+*/
+
+int QtTableView::findRow( int yPos ) const
+{
+    int cellMaxY;
+    int row = findRawRow( yPos, &cellMaxY );
+    if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() )
+       row = - 1;                              //  cell cut by bottom margin
+    if ( row >= nRows )
+       row = -1;
+    return row;
+}
+
+
+/*!
+  Returns the index of the column at position \a xPos, where \a xPos is
+  in \e widget coordinates.  Returns -1 if \a xPos is outside the valid
+  range.
+
+  \sa findRow(), colXPos()
+*/
+
+int QtTableView::findCol( int xPos ) const
+{
+    int cellMaxX;
+    int col = findRawCol( xPos, &cellMaxX );
+    if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() )
+       col = - 1;                              //  cell cut by right margin
+    if ( col >= nCols )
+       col = -1;
+    return col;
+}
+
+
+/*!
+  Computes the position in the widget of row \a row.
+
+  Returns TRUE and stores the result in \a *yPos (in \e widget
+  coordinates) if the row is visible.  Returns FALSE and does not modify
+  \a *yPos if \a row is invisible or invalid.
+
+  \sa colXPos(), findRow()
+*/
+
+bool QtTableView::rowYPos( int row, int *yPos ) const
+{
+    int y;
+    if ( row >= yCellOffs ) {
+       if ( cellH ) {
+           int lastVisible = lastRowVisible();
+           if ( row > lastVisible || lastVisible == -1 )
+               return FALSE;
+           y = (row - yCellOffs)*cellH + minViewY() - yCellDelta;
+       } else {
+           //##arnt3
+           y = minViewY() - yCellDelta;        // y of leftmost cell in view
+           int r = yCellOffs;
+           QtTableView *tw = (QtTableView *)this;
+           int maxY = maxViewY();
+           while ( r < row && y <= maxY )
+               y += tw->cellHeight( r++ );
+           if ( y > maxY )
+               return FALSE;
+
+       }
+    } else {
+       return FALSE;
+    }
+    if ( yPos )
+       *yPos = y;
+    return TRUE;
+}
+
+
+/*!
+  Computes the position in the widget of column \a col.
+
+  Returns TRUE and stores the result in \a *xPos (in \e widget
+  coordinates) if the column is visible.  Returns FALSE and does not
+  modify \a *xPos if \a col is invisible or invalid.
+
+  \sa rowYPos(), findCol()
+*/
+
+bool QtTableView::colXPos( int col, int *xPos ) const
+{
+    int x;
+    if ( col >= xCellOffs ) {
+       if ( cellW ) {
+           int lastVisible = lastColVisible();
+           if ( col > lastVisible || lastVisible == -1 )
+               return FALSE;
+           x = (col - xCellOffs)*cellW + minViewX() - xCellDelta;
+       } else {
+           //##arnt3
+           x = minViewX() - xCellDelta;        // x of uppermost cell in view
+           int c = xCellOffs;
+           QtTableView *tw = (QtTableView *)this;
+           int maxX = maxViewX();
+           while ( c < col && x <= maxX )
+               x += tw->cellWidth( c++ );
+           if ( x > maxX )
+               return FALSE;
+       }
+    } else {
+       return FALSE;
+    }
+    if ( xPos )
+       *xPos = x;
+    return TRUE;
+}
+
+
+/*!
+  Moves the visible area of the table right by \a xPixels and
+  down by \a yPixels pixels.  Both may be negative.
+
+  \warning You might find that QScrollView offers a higher-level of
+       functionality than using QtTableView and this function.
+
+  This function is \e not the same as QWidget::scroll(); in particular,
+  the signs of \a xPixels and \a yPixels have the reverse semantics.
+
+  \sa setXOffset(), setYOffset(), setOffset(), setTopCell(),
+  setLeftCell()
+*/
+
+void QtTableView::scroll( int xPixels, int yPixels )
+{
+    QWidget::scroll( -xPixels, -yPixels, contentsRect() );
+}
+
+
+/*!
+  Returns the leftmost pixel of the table view in \e view
+  coordinates. This excludes the frame and any header.
+
+  \sa maxViewY(), viewWidth(), contentsRect()
+*/
+
+int QtTableView::minViewX() const
+{
+    return frameWidth();
+}
+
+
+/*!
+  Returns the top pixel of the table view in \e view
+  coordinates. This excludes the frame and any header.
+
+  \sa maxViewX(), viewHeight(), contentsRect()
+*/
+
+int QtTableView::minViewY() const
+{
+    return frameWidth();
+}
+
+
+/*!
+  Returns the rightmost pixel of the table view in \e view
+  coordinates. This excludes the frame and any scroll bar, but
+  includes blank pixels to the right of the visible table data.
+
+  \sa maxViewY(), viewWidth(), contentsRect()
+*/
+
+int QtTableView::maxViewX() const
+{
+    return width() - 1 - frameWidth()
+        - (tFlags & Tbl_vScrollBar ? VSBEXT
+           : 0);
+}
+
+
+/*!
+  Returns the bottom pixel of the table view in \e view
+  coordinates. This excludes the frame and any scroll bar, but
+  includes blank pixels below the visible table data.
+
+  \sa maxViewX(), viewHeight(), contentsRect()
+*/
+
+int QtTableView::maxViewY() const
+{
+    return height() - 1 - frameWidth()
+        - (tFlags & Tbl_hScrollBar ? HSBEXT
+           : 0);
+}
+
+
+/*!
+  Returns the width of the table view, as such, in \e view
+  coordinates.  This does not include any header, scroll bar or frame,
+  but it does include background pixels to the right of the table data.
+
+  \sa minViewX() maxViewX(), viewHeight(), contentsRect() viewRect()
+*/
+
+int QtTableView::viewWidth() const
+{
+    return maxViewX() - minViewX() + 1;
+}
+
+
+/*!
+  Returns the height of the table view, as such, in \e view
+  coordinates.  This does not include any header, scroll bar or frame,
+  but it does include background pixels below the table data.
+
+  \sa minViewY() maxViewY() viewWidth() contentsRect() viewRect()
+*/
+
+int QtTableView::viewHeight() const
+{
+    return maxViewY() - minViewY() + 1;
+}
+
+
+void QtTableView::doAutoScrollBars()
+{
+    int viewW = width()         - frameWidth() - minViewX();
+    int viewH = height() - frameWidth() - minViewY();
+    bool vScrollOn = testTableFlags(Tbl_vScrollBar);
+    bool hScrollOn = testTableFlags(Tbl_hScrollBar);
+    int w = 0;
+    int h = 0;
+    int i;
+
+    if ( testTableFlags(Tbl_autoHScrollBar) ) {
+       if ( cellW ) {
+           w = cellW*nCols;
+       } else {
+           i = 0;
+           while ( i < nCols && w <= viewW )
+               w += cellWidth( i++ );
+       }
+       if ( w > viewW )
+           hScrollOn = TRUE;
+       else
+           hScrollOn = FALSE;
+    }
+
+    if ( testTableFlags(Tbl_autoVScrollBar) ) {
+       if ( cellH ) {
+           h = cellH*nRows;
+       } else {
+           i = 0;
+           while ( i < nRows && h <= viewH )
+               h += cellHeight( i++ );
+       }
+
+       if ( h > viewH )
+           vScrollOn = TRUE;
+       else
+           vScrollOn = FALSE;
+    }
+
+    if ( testTableFlags(Tbl_autoHScrollBar) && vScrollOn && !hScrollOn )
+       if ( w > viewW - VSBEXT )
+           hScrollOn = TRUE;
+
+    if ( testTableFlags(Tbl_autoVScrollBar) && hScrollOn && !vScrollOn )
+       if ( h > viewH - HSBEXT )
+           vScrollOn = TRUE;
+
+    setHorScrollBar( hScrollOn, FALSE );
+    setVerScrollBar( vScrollOn, FALSE );
+    updateFrameSize();
+}
+
+
+/*!
+  \fn void QtTableView::updateScrollBars()
+
+  Updates the scroll bars' contents and presence to match the table's
+  state.  Generally, you should not need to call this.
+
+  \sa setTableFlags()
+*/
+
+/*!
+  Updates the scroll bars' contents and presence to match the table's
+  state \c or \a f.
+
+  \sa setTableFlags()
+*/
+
+void QtTableView::updateScrollBars( uint f )
+{
+    sbDirty = sbDirty | f;
+    if ( inSbUpdate )
+       return;
+    inSbUpdate = TRUE;
+
+    if ( testTableFlags(Tbl_autoHScrollBar) && (sbDirty & horRange) ||
+        testTableFlags(Tbl_autoVScrollBar) && (sbDirty & verRange) )
+                                       // if range change and auto
+       doAutoScrollBars();             // turn scroll bars on/off if needed
+
+    if ( !autoUpdate() ) {
+       inSbUpdate = FALSE;
+       return;
+    }
+    if ( yOffset() > 0 && testTableFlags( Tbl_autoVScrollBar ) &&
+        !testTableFlags( Tbl_vScrollBar ) ) {
+       setYOffset( 0 );
+    }
+    if ( xOffset() > 0 && testTableFlags( Tbl_autoHScrollBar ) &&
+        !testTableFlags( Tbl_hScrollBar ) ) {
+       setXOffset( 0 );
+    }
+    if ( !isVisible() ) {
+       inSbUpdate = FALSE;
+       return;
+    }
+
+    if ( testTableFlags(Tbl_hScrollBar) && (sbDirty & horMask) != 0 ) {
+       if ( sbDirty & horGeometry )
+           hScrollBar->setGeometry( 0,height() - HSBEXT,
+                                     viewWidth() + frameWidth()*2,
+                                   HSBEXT);
+
+       if ( sbDirty & horSteps ) {
+           if ( cellW )
+               hScrollBar->setSteps( QMIN(cellW,viewWidth()/2), viewWidth() );
+           else
+               hScrollBar->setSteps( 16, viewWidth() );
+       }
+
+       if ( sbDirty & horRange )
+           hScrollBar->setRange( 0, maxXOffset() );
+
+       if ( sbDirty & horValue )
+           hScrollBar->setValue( xOffs );
+
+                       // show scrollbar only when it has a sane geometry
+       if ( !hScrollBar->isVisible() )
+           hScrollBar->show();
+    }
+
+    if ( testTableFlags(Tbl_vScrollBar) && (sbDirty & verMask) != 0 ) {
+       if ( sbDirty & verGeometry )
+           vScrollBar->setGeometry( width() - VSBEXT, 0,
+                                     VSBEXT,
+                                     viewHeight() + frameWidth()*2 );
+
+       if ( sbDirty & verSteps ) {
+           if ( cellH )
+               vScrollBar->setSteps( QMIN(cellH,viewHeight()/2), viewHeight() );
+           else
+               vScrollBar->setSteps( 16, viewHeight() );  // fttb! ###
+       }
+
+       if ( sbDirty & verRange )
+           vScrollBar->setRange( 0, maxYOffset() );
+
+       if ( sbDirty & verValue )
+           vScrollBar->setValue( yOffs );
+
+                       // show scrollbar only when it has a sane geometry
+       if ( !vScrollBar->isVisible() )
+           vScrollBar->show();
+    }
+    if ( coveringCornerSquare &&
+        ( (sbDirty & verGeometry ) || (sbDirty & horGeometry)) )
+       cornerSquare->move( maxViewX() + frameWidth() + 1,
+                           maxViewY() + frameWidth() + 1 );
+
+    sbDirty = 0;
+    inSbUpdate = FALSE;
+}
+
+
+void QtTableView::updateFrameSize()
+{
+    int rw = width()  - ( testTableFlags(Tbl_vScrollBar) ?
+                          VSBEXT : 0 );
+    int rh = height() - ( testTableFlags(Tbl_hScrollBar) ?
+                          HSBEXT : 0 );
+    if ( rw < 0 )
+       rw = 0;
+    if ( rh < 0 )
+       rh = 0;
+
+    if ( autoUpdate() ) {
+        int fh = frameRect().height();
+       int fw = frameRect().width();
+       setFrameRect( QRect(0,0,rw,rh) );
+
+       if ( rw != fw )
+           update( QMIN(fw,rw) - frameWidth() - 2, 0, frameWidth()+4, rh );
+       if ( rh != fh )
+           update( 0, QMIN(fh,rh) - frameWidth() - 2, rw, frameWidth()+4 );
+    }
+}
+
+
+/*!
+  Returns the maximum horizontal offset within the table of the
+  view's left edge in \e table coordinates.
+
+  This is used mainly to set the horizontal scroll bar's range.
+
+  \sa maxColOffset(), maxYOffset(), totalWidth()
+*/
+
+int QtTableView::maxXOffset()
+{
+    int tw = totalWidth();
+    int maxOffs;
+    if ( testTableFlags(Tbl_scrollLastHCell) ) {
+       if ( nCols != 1)
+           maxOffs =  tw - ( cellW ? cellW : cellWidth( nCols - 1 ) );
+       else
+           maxOffs = tw - viewWidth();
+    } else {
+       if ( testTableFlags(Tbl_snapToHGrid) ) {
+           if ( cellW ) {
+               maxOffs =  tw - (viewWidth()/cellW)*cellW;
+           } else {
+               int goal = tw - viewWidth();
+               int pos = tw;
+               int nextCol = nCols - 1;
+               int nextCellWidth = cellWidth( nextCol );
+               while( nextCol > 0 && pos > goal + nextCellWidth ) {
+                   pos -= nextCellWidth;
+                   nextCellWidth = cellWidth( --nextCol );
+               }
+               if ( goal + nextCellWidth == pos )
+                   maxOffs = goal;
+                else if ( goal < pos )
+                  maxOffs = pos;
+                else
+                  maxOffs = 0;
+           }
+       } else {
+           maxOffs = tw - viewWidth();
+       }
+    }
+    return maxOffs > 0 ? maxOffs : 0;
+}
+
+
+/*!
+  Returns the maximum vertical offset within the table of the
+  view's top edge in \e table coordinates.
+
+  This is used mainly to set the vertical scroll bar's range.
+
+  \sa maxRowOffset(), maxXOffset(), totalHeight()
+*/
+
+int QtTableView::maxYOffset()
+{
+    int th = totalHeight();
+    int maxOffs;
+    if ( testTableFlags(Tbl_scrollLastVCell) ) {
+       if ( nRows != 1)
+           maxOffs =  th - ( cellH ? cellH : cellHeight( nRows - 1 ) );
+       else
+           maxOffs = th - viewHeight();
+    } else {
+       if ( testTableFlags(Tbl_snapToVGrid) ) {
+           if ( cellH ) {
+               maxOffs =  th - (viewHeight()/cellH)*cellH;
+           } else {
+               int goal = th - viewHeight();
+               int pos = th;
+               int nextRow = nRows - 1;
+               int nextCellHeight = cellHeight( nextRow );
+               while( nextRow > 0 && pos > goal + nextCellHeight ) {
+                   pos -= nextCellHeight;
+                   nextCellHeight = cellHeight( --nextRow );
+               }
+               if ( goal + nextCellHeight == pos )
+                   maxOffs = goal;
+                else if ( goal < pos )
+                  maxOffs = pos;
+                else
+                  maxOffs = 0;
+           }
+       } else {
+           maxOffs = th - viewHeight();
+       }
+    }
+    return maxOffs > 0 ? maxOffs : 0;
+}
+
+
+/*!
+  Returns the index of the last column, which may be at the left edge
+  of the view.
+
+  Depending on the \link setTableFlags() Tbl_scrollLastHCell\endlink flag,
+  this may or may not be the last column.
+
+  \sa maxXOffset(), maxRowOffset()
+*/
+
+int QtTableView::maxColOffset()
+{
+    int mx = maxXOffset();
+    if ( cellW )
+       return mx/cellW;
+    else {
+       int xcd=0, col=0;
+       while ( col < nCols && mx > (xcd=cellWidth(col)) ) {
+           mx -= xcd;
+           col++;
+       }
+       return col;
+    }
+}
+
+
+/*!
+  Returns the index of the last row, which may be at the top edge of
+  the view.
+
+  Depending on the \link setTableFlags() Tbl_scrollLastVCell\endlink flag,
+  this may or may not be the last row.
+
+  \sa maxYOffset(), maxColOffset()
+*/
+
+int QtTableView::maxRowOffset()
+{
+    int my = maxYOffset();
+    if ( cellH )
+       return my/cellH;
+    else {
+       int ycd=0, row=0;
+       while ( row < nRows && my > (ycd=cellHeight(row)) ) {
+           my -= ycd;
+           row++;
+       }
+       return row;
+    }
+}
+
+
+void QtTableView::showOrHideScrollBars()
+{
+    if ( !autoUpdate() )
+       return;
+    if ( vScrollBar ) {
+       if ( testTableFlags(Tbl_vScrollBar) ) {
+           if ( !vScrollBar->isVisible() )
+               sbDirty = sbDirty | verMask;
+       } else {
+           if ( vScrollBar->isVisible() )
+              vScrollBar->hide();
+       }
+    }
+    if ( hScrollBar ) {
+       if ( testTableFlags(Tbl_hScrollBar) ) {
+           if ( !hScrollBar->isVisible() )
+               sbDirty = sbDirty | horMask;
+       } else {
+           if ( hScrollBar->isVisible() )
+               hScrollBar->hide();
+       }
+    }
+    if ( cornerSquare ) {
+       if ( testTableFlags(Tbl_hScrollBar) &&
+            testTableFlags(Tbl_vScrollBar) ) {
+           if ( !cornerSquare->isVisible() )
+               cornerSquare->show();
+       } else {
+           if ( cornerSquare->isVisible() )
+               cornerSquare->hide();
+       }
+    }
+}
+
+
+/*!
+  Updates the scroll bars and internal state.
+
+  Call this function when the table view's total size is changed;
+  typically because the result of cellHeight() or cellWidth() have changed.
+
+  This function does not repaint the widget.
+*/
+
+void QtTableView::updateTableSize()
+{
+    bool updateOn = autoUpdate();
+    setAutoUpdate( FALSE );
+    int xofs = xOffset();
+    xOffs++; //so that setOffset will not return immediately
+    setOffset(xofs,yOffset(),FALSE); //to calculate internal state correctly
+    setAutoUpdate(updateOn);
+
+    updateScrollBars( horSteps |  horRange |
+                     verSteps |  verRange );
+    showOrHideScrollBars();
+}
+
+
+#endif
+#endif
diff --git a/win/Qt/tileedit.cpp b/win/Qt/tileedit.cpp
new file mode 100644 (file)
index 0000000..faee82f
--- /dev/null
@@ -0,0 +1,413 @@
+/*     SCCS Id: @(#)tileedit.cpp       3.4     1999/11/19      */
+/* Copyright (c) Warwick Allison, 1999. */
+/* NetHack may be freely redistributed.  See license for details. */
+/*
+Build this little utility program if you want to use it to edit the tile
+files.  Move tileedit.cpp and tileedit.h to ../../util, add the
+3 lines below to the Makefile there and "make tileedit".
+
+tileedit: tileedit.cpp $(TEXT_IO)
+       moc -o tileedit.moc tileedit.h
+       $(CC) -o tileedit -I../include -I$(QTDIR)/include -L$(QTDIR)/lib tileedit.cpp $(TEXT_IO) -lqt
+*/
+
+
+#include "tileedit.h"
+#include <qapplication.h>
+#include <qmainwindow.h>
+#include <qkeycode.h>
+#include <qpopupmenu.h>
+#include <qmenubar.h>
+#include <qpainter.h>
+#include <qstatusbar.h>
+#include <qhbox.h>
+#include <qlabel.h>
+
+extern "C" {
+#include "config.h"
+#include "tile.h"
+extern const char *FDECL(tilename, (int, int));
+}
+
+#define TILES_ACROSS 20
+
+TilePickerTab::TilePickerTab(const char* basename, int i, QWidget* parent) :
+    QWidget(parent)
+{
+    id = i;
+    filename = basename;
+    filename += ".txt";
+    num = 0;
+    int index = 0;
+    for (int real=0; real<2; real++) {
+       if ( real ) {
+           image.create( TILES_ACROSS*TILE_X,
+               ((num+TILES_ACROSS-1)/TILES_ACROSS)*TILE_Y, 32 );
+       }
+       if ( !fopen_text_file(filename.latin1(), RDTMODE) ) {
+           // XXX handle better
+           exit(1);
+       }
+       pixel p[TILE_Y][TILE_X];
+       while ( read_text_tile(p) ) {
+           if ( real ) {
+               int ox = (index%TILES_ACROSS)*TILE_X;
+               int oy = (index/TILES_ACROSS)*TILE_Y;
+               for ( int y=0; y<TILE_Y; y++ ) {
+                   QRgb* rgb = ((QRgb*)image.scanLine(oy+y)) + ox;
+                   for ( int x=0; x<TILE_X; x++ ) {
+                       *rgb++ = qRgb(p[y][x].r, p[y][x].g, p[y][x].b);
+                   }
+               }
+               index++;
+           } else {
+               // Just count...
+               num++;
+           }
+       }
+       fclose_text_file();
+    }
+    image = image.convertDepth( 8, AvoidDither );
+    pixmap.convertFromImage( image );
+}
+
+bool TilePickerTab::save()
+{
+    if ( !fopen_text_file(filename.latin1(), WRTMODE) ) {
+       // XXX handle better
+       exit(1);
+    }
+    pixel p[TILE_Y][TILE_X];
+    for ( int index=0; index < num; index++ ) {
+       int ox = (index%TILES_ACROSS)*TILE_X;
+       int oy = (index/TILES_ACROSS)*TILE_Y;
+       for ( int y=0; y<TILE_Y; y++ ) {
+           uchar* c = image.scanLine(oy+y) + ox;
+           for ( int x=0; x<TILE_X; x++ ) {
+               QRgb rgb = image.color(*c++);
+               p[y][x].r = qRed(rgb);
+               p[y][x].g = qGreen(rgb);
+               p[y][x].b = qBlue(rgb);
+           }
+       }
+       write_text_tile(p);
+    }
+    fclose_text_file();
+}
+
+void TilePickerTab::mousePressEvent(QMouseEvent* e)
+{
+    int ox = e->x()-e->x()%TILE_X;
+    int oy = e->y()-e->y()%TILE_Y;
+    QImage subimage = image.copy(ox,oy,TILE_X,TILE_Y);
+    if ( e->button() == RightButton ) {
+       setCurrent(subimage);
+    } else {
+       last_pick = ox/TILE_X + oy/TILE_Y*TILES_ACROSS;
+    }
+    emit pick(subimage);
+    emit pickName(tilename(id, last_pick));
+}
+
+void TilePickerTab::setCurrent(const QImage& i)
+{
+    int ox = last_pick%TILES_ACROSS * TILE_X;
+    int oy = last_pick/TILES_ACROSS * TILE_Y;
+    bitBlt( &image, ox, oy, &i );
+    bitBlt( &pixmap, ox, oy, &i );
+    repaint( ox, oy, TILE_X, TILE_Y, FALSE );
+}
+
+QSize TilePickerTab::sizeHint() const
+{
+    return pixmap.size();
+}
+
+void TilePickerTab::paintEvent( QPaintEvent* )
+{
+    QPainter p(this);
+    p.drawPixmap(0,0,pixmap);
+}
+
+static struct {
+    const char* name;
+    TilePickerTab* tab;
+} tileset[] = {
+    { "monsters", 0 },
+    { "objects", 0 },
+    { "other", 0 },
+    { 0 }
+};
+
+TilePicker::TilePicker(QWidget* parent) :
+    QTabWidget(parent)
+{
+    for (int i=0; tileset[i].name; i++) {
+       QString tabname = tileset[i].name;
+       tabname[0] = tabname[0].upper();
+       tileset[i].tab = new TilePickerTab(tileset[i].name,i+1,this);
+       addTab( tileset[i].tab, tabname );
+       connect( tileset[i].tab, SIGNAL(pick(const QImage&)),
+                this, SIGNAL(pick(const QImage&)) );
+       connect( tileset[i].tab, SIGNAL(pickName(const QString&)),
+                this, SIGNAL(pickName(const QString&)) );
+    }
+}
+
+void TilePicker::setCurrent(const QImage& i)
+{
+    ((TilePickerTab*)currentPage())->setCurrent(i);
+}
+
+void TilePicker::save()
+{
+    for (int i=0; tileset[i].tab; i++) {
+       tileset[i].tab->save();
+    }
+}
+
+TrivialTileEditor::TrivialTileEditor( QWidget* parent ) :
+    QWidget(parent)
+{
+}
+
+const QImage& TrivialTileEditor::image() const
+{
+    return img;
+}
+
+void TrivialTileEditor::setColor( QRgb rgb )
+{
+    pen = rgb;
+    for (penpixel = 0;
+           penpixel<img.numColors()-1 && (img.color(penpixel)&0xffffff)!=(pen.rgb()&0xffffff);
+           penpixel++)
+       continue;
+}
+
+void TrivialTileEditor::setImage( const QImage& i )
+{
+    img = i;
+    setColor(pen.rgb()); // update penpixel
+    repaint(FALSE);
+}
+
+void TrivialTileEditor::paintEvent( QPaintEvent* e )
+{
+    QRect r = e->rect();
+    QPoint tl = imagePoint(r.topLeft());
+    QPoint br = imagePoint(r.bottomRight());
+    r = QRect(tl,br).intersect(img.rect());
+    QPainter painter(this);
+    for (int y=r.top(); y<=r.bottom(); y++) {
+       for (int x=r.left(); x<=r.right(); x++) {
+           paintPoint(painter,QPoint(x,y));
+       }
+    }
+}
+
+void TrivialTileEditor::paintPoint(QPainter& painter, QPoint p)
+{
+    QPoint p1 = screenPoint(p);
+    QPoint p2 = screenPoint(p+QPoint(1,1));
+    QColor c = img.color(img.scanLine(p.y())[p.x()]);
+    painter.fillRect(QRect(p1,p2-QPoint(1,1)), c);
+}
+
+void TrivialTileEditor::mousePressEvent(QMouseEvent* e)
+{
+    QPoint p = imagePoint(e->pos());
+    if ( !img.rect().contains(p) )
+       return;
+    uchar& pixel = img.scanLine(p.y())[p.x()];
+    if ( e->button() == LeftButton ) {
+       pixel = penpixel;
+       QPainter painter(this);
+       paintPoint(painter,p);
+    } else if ( e->button() == RightButton ) {
+       emit pick( img.color(pixel) );
+    } else if ( e->button() == MidButton ) {
+       QPainter painter(this);
+       if ( pixel != penpixel )
+           fill(painter,p,pixel);
+    }
+}
+
+void TrivialTileEditor::fill(QPainter& painter, QPoint p, uchar from)
+{
+    if ( img.rect().contains(p) ) {
+       uchar& pixel = img.scanLine(p.y())[p.x()];
+       if ( pixel == from ) {
+           pixel = penpixel;
+           paintPoint(painter,p);
+           fill(painter, p+QPoint(-1,0), from);
+           fill(painter, p+QPoint(+1,0), from);
+           fill(painter, p+QPoint(0,-1), from);
+           fill(painter, p+QPoint(0,+1), from);
+       }
+    }
+}
+
+void TrivialTileEditor::mouseReleaseEvent(QMouseEvent* e)
+{
+    emit edited(image());
+}
+
+void TrivialTileEditor::mouseMoveEvent(QMouseEvent* e)
+{
+    QPoint p = imagePoint(e->pos());
+    if ( !img.rect().contains(p) )
+       return;
+    uchar& pixel = img.scanLine(p.y())[p.x()];
+    pixel = penpixel;
+    QPainter painter(this);
+    paintPoint(painter,p);
+}
+
+QPoint TrivialTileEditor::imagePoint(QPoint p) const
+{
+    return QPoint(p.x()*TILE_X/width(), p.y()*TILE_Y/height());
+}
+
+QPoint TrivialTileEditor::screenPoint(QPoint p) const
+{
+    return QPoint(p.x()*width()/TILE_X, p.y()*height()/TILE_Y);
+}
+
+QSizePolicy TrivialTileEditor::sizePolicy() const
+{
+    return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding, TRUE );
+}
+
+QSize TrivialTileEditor::sizeHint() const
+{
+    return sizeForWidth(-1);
+}
+
+QSize TrivialTileEditor::sizeForWidth(int w) const
+{
+    if ( w < 0 )
+       return QSize(TILE_X*32,TILE_Y*32);
+    else
+       return QSize(w,w*TILE_Y/TILE_X);
+}
+
+
+TilePalette::TilePalette( QWidget* parent ) :
+    QWidget(parent)
+{
+    num = 0;
+    rgb = 0;
+}
+
+TilePalette::~TilePalette()
+{
+    delete rgb;
+}
+
+void TilePalette::setFromImage( const QImage& i )
+{
+    num = i.numColors();
+    rgb = new QRgb[num];
+    memcpy(rgb, i.colorTable(), num*sizeof(QRgb));
+    repaint(FALSE);
+}
+
+void TilePalette::setColor(QRgb c)
+{
+    for (int i=0; i<num; i++)
+       if ( c == rgb[i] ) {
+           emit pick(c);
+           return;
+       }
+}
+
+QSizePolicy TilePalette::sizePolicy() const
+{
+    return QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum, FALSE );
+}
+
+QSize TilePalette::sizeHint() const
+{
+    return QSize(num*16,16);
+}
+
+void TilePalette::paintEvent( QPaintEvent* )
+{
+    QPainter p(this);
+    for (int i=0; i<num; i++) {
+       int x1 = width()*i/num;
+       int x2 = width()*(i+1)/num;
+       p.fillRect(x1,0,x2-x1,height(),QColor(rgb[i]));
+    }
+}
+
+void TilePalette::mousePressEvent(QMouseEvent* e)
+{
+    int c = e->x()*num/width();
+    emit pick(rgb[c]);
+}
+
+TileEditor::TileEditor(QWidget* parent) :
+    QVBox(parent),
+    editor(this),
+    palette(this)
+{
+    connect( &palette, SIGNAL(pick(QRgb)),
+            &editor, SLOT(setColor(QRgb)) );
+    connect( &editor, SIGNAL(pick(QRgb)),
+            &palette, SLOT(setColor(QRgb)) );
+    connect( &editor, SIGNAL(edited(const QImage&)),
+            this, SIGNAL(edited(const QImage&)) );
+}
+
+void TileEditor::edit(const QImage& i)
+{
+    editor.setImage(i);
+    palette.setFromImage(i);
+}
+
+const QImage& TileEditor::image() const
+{
+    return editor.image();
+}
+
+class Main : public QMainWindow {
+public:
+    Main() :
+       central(this),
+       editor(&central),
+       picker(&central)
+    {
+       QPopupMenu* file = new QPopupMenu(menuBar());
+       file->insertItem("&Save", &picker, SLOT(save()), CTRL+Key_S);
+       file->insertSeparator();
+       file->insertItem("&Exit", qApp, SLOT(quit()), CTRL+Key_Q);
+       menuBar()->insertItem("&File", file);
+
+       connect( &picker, SIGNAL(pick(const QImage&)),
+                &editor, SLOT(edit(const QImage&)) );
+       connect( &picker, SIGNAL(pickName(const QString&)),
+                statusBar(), SLOT(message(const QString&)) );
+       connect( &editor, SIGNAL(edited(const QImage&)),
+                &picker, SLOT(setCurrent(const QImage&)) );
+
+       setCentralWidget(&central);
+    }
+
+private:
+    QHBox central; 
+    TileEditor editor;
+    TilePicker picker;
+};
+
+main(int argc, char** argv)
+{
+    QApplication app(argc,argv);
+    Main m;
+    app.setMainWidget(&m);
+    m.show();
+    return app.exec();
+}
+
+#include "tileedit.moc"
diff --git a/win/Qt/tileedit.h b/win/Qt/tileedit.h
new file mode 100644 (file)
index 0000000..8d2d2cd
--- /dev/null
@@ -0,0 +1,128 @@
+/*     SCCS Id: @(#)tileedit.h 3.4     1999/11/19      */
+/* Copyright (c) Warwick Allison, 1999. */
+/* NetHack may be freely redistributed.  See license for details. */
+#ifndef QNHTILEEDIT_H
+#define QNHTILEEDIT_H
+
+#include <qtabwidget.h>
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qvbox.h>
+
+class TilePickerTab : public QWidget {
+    Q_OBJECT
+public:
+    TilePickerTab(const char* basename, int id, QWidget* parent);
+
+    bool save();
+    int numTiles();
+
+signals:
+    void pick(const QImage&);
+    void pickName(const QString&);
+
+public slots:
+    void setCurrent(const QImage&);
+
+protected:
+    void paintEvent( QPaintEvent* );
+    QSize sizeHint() const;
+    void mousePressEvent(QMouseEvent*);
+
+private:
+    QString filename;
+    int id;
+    int last_pick;
+    int num;
+    QPixmap pixmap;
+    QImage image;
+};
+
+class TilePicker : public QTabWidget {
+    Q_OBJECT
+public:
+    TilePicker(QWidget* parent);
+
+    void setTile(int tilenum, const QImage&);
+
+signals:
+    void pick(const QImage&);
+    void pickName(const QString&);
+
+public slots:
+    void setCurrent(const QImage&);
+    void save();
+};
+
+class TrivialTileEditor : public QWidget {
+    Q_OBJECT
+public:
+    TrivialTileEditor( QWidget* parent );
+    const QImage& image() const;
+
+signals:
+    void edited(const QImage&);
+    void pick(QRgb);
+
+public slots:
+    void setColor(QRgb);
+    void setImage( const QImage& );
+
+protected:
+    void paintEvent( QPaintEvent* );
+    void mousePressEvent(QMouseEvent*);
+    void mouseReleaseEvent(QMouseEvent*);
+    void mouseMoveEvent(QMouseEvent*);
+    QSize sizeHint() const;
+    QSize sizeForWidth(int) const;
+    QSizePolicy sizePolicy() const;
+
+private:
+    void fill(QPainter& painter, QPoint p, uchar from);
+    QImage img;
+    QColor pen;
+    int penpixel;
+    void paintPoint(QPainter& painter, QPoint p);
+    QPoint screenPoint(QPoint) const;
+    QPoint imagePoint(QPoint) const;
+};
+
+class TilePalette : public QWidget {
+    Q_OBJECT
+public:
+    TilePalette( QWidget* parent );
+    ~TilePalette();
+    void setFromImage( const QImage& );
+protected:
+    void paintEvent( QPaintEvent* );
+    void mousePressEvent(QMouseEvent*);
+    QSize sizeHint() const;
+    QSizePolicy sizePolicy() const;
+signals:
+    void pick(QRgb);
+public slots:
+    void setColor(QRgb);
+private:
+    int num;
+    QRgb *rgb;
+};
+
+class TileEditor : public QVBox {
+    Q_OBJECT
+public:
+    TileEditor(QWidget* parent);
+
+    const QImage& image() const;
+
+signals:
+    void edited(const QImage&);
+
+public slots:
+    void edit(const QImage&);
+
+private:
+    TrivialTileEditor editor;
+    TilePalette palette;
+};
+
+#endif
diff --git a/win/X11/Install.X11 b/win/X11/Install.X11
new file mode 100644 (file)
index 0000000..b4b7a43
--- /dev/null
@@ -0,0 +1,202 @@
+
+This document describes the installation of NetHack with an X11 interface.
+
+There are no explicit UNIX dependencies in this code, but we have only
+tested it under UNIX, using X11R4, X11R5, or X11R6.  We have two reports
+that the code also works under DesqView/X on MS-DOS with djgpp, but you
+will have to add dependencies for the X code to that makefile before you
+can use it.  Other X11R4+ platforms may work as well, with some tweaking
+likely.  Follow WIN* in sys/unix/Makefile.src for compilation hints.
+
+(If you try to compile it with X11R3 or earlier, you will get many errors,
+starting with complaints about XtPointer not being declared.  If you get
+around the compilation problems, you will still need a recent library of
+Athena Widgets to link against.  Once compiled, you can probably run it
+under an R3 X server, though.)
+
+The reason this uses the Athena widget set is that the Athena widgets come
+free from MIT (like X11).  Unfortunately, the companies that resell X11
+(value subtracted er, added software; yea, yea, that's the ticket) usually
+discourage its use by either omitting the set or putting it on the
+"unsupported" portion of their tape.  If you do not have the Athena
+widgets, you may obtain them via anonymous ftp from ftp.x.org.
+
+
+To use this code, define X11_GRAPHICS in include/config.h.  (You can comment
+out TTY_GRAPHICS or change DEFAULT_WINDOW_SYS if you want to, but there's
+little reason to do so.  The X11 version almost requires a config file
+for full effect, so you can just as well set windowtype there; also, you
+or someone else might just possibly be stuck in a situation where you can't
+use the X version -- over a non-blindingly-fast modem, say.)  You may also
+want to define USE_XPM or GRAPHIC_TOMBSTONE as discussed below.
+
+In src/Makefile, add $(WINX11SRC), $(WINX11OBJ), and $(WINX11LIB) to
+WINSRC, WINOBJ, and WINLIB respectively, and compile.  This will give you
+an executable supporting both X11 and tty windowing.
+
+
+If you want to use the optional tiles (multicolored pictures instead of a
+replacement font), you will need to have the win/share files and change
+the VARDATND setting in the top Makefile to contain the tile files before
+you do your 'make all'.
+
+If you get a linker error referring to `substitute_tiles' then most
+likely you have overlooked the WINSRC, WINOBJ, WINLIB step above.
+Alternatively, you are building with more than one non-tty interface
+specified but haven't followed the direction in src/Makefile to remove
+all but one instance of tile.o from the WINxxxOBJ values used for WINOBJ.
+
+When using tiles, you have the option of defining USE_XPM in config.h.
+This causes NetHack to use the XPM file format for the "x11tiles" file
+rather than a custom format.  Since the XPM format can be processed by
+existing tools such as PBMPlus and XV, you can modify the tiles to suit
+your environment.  However, you need to make sure the number of tiles
+in each row of the image remains the same (currently 40), as the code
+depends on this to calculate the size of each tile. For example, you may
+magnify them for display on high-resolution screens using the following
+command:
+    xpmtoppm x11tiles | pnmscale -xscale 1 -yscale 1.6875 |
+        pnmdepth 255 | ppmquant 100 | ppmtoxpm >x11tiles_big.xpm
+To use XPM, you must have the free XPM libraries installed in your system.
+Official xpm releases can be found by ftp on:
+    ftp.x.org       (198.4.202.8)  contrib/libraries     (Boston, USA)
+    avahi.inria.fr  (138.96.12.1)  pub/xpm     (Sophia Antipolis, France)
+If you do choose to define USE_XPM, be sure to add "-lXpm" to WINX11LIB
+in src/Makefile.
+
+If you define USE_XPM in config.h, you may also define GRAPHIC_TOMBSTONE
+which causes the closing tombstone to be displayed from the image file
+specified by the "tombstone" X resource (rip.xpm by default).  In this
+case, make sure the top Makefile VARDATND also contains rip.xpm.
+
+
+Whether or not you install tile support, you can provide support for
+special graphics symbols via alternate fonts.  (The fonts and tiles
+cannot be used at the same time, but the same executable handles both.)
+The two included X11 fonts use the general NetHack map area remapping
+to represent object/dungeon/trap/effect characters (see win/X11/nethack.rc
+and the Guidebook) as monocolored symbols and monsters as monocolored
+letters.  For instance, a ruby potion will show up as a potion symbol in
+red.  It's easier to see the difference between fonts and tiles than to
+describe it. :-)  Unless you are the only one using your executable and
+you already know which you prefer, we suggest installing the optional files
+for both possibilities and letting each person decide for themselves.
+
+To use the included fonts, you will need to install one or both of them
+and then use the symbol mappings found in nethack.rc.  The fonts are found
+in nh10.bdf and ibm.bdf.  You first need to convert the bdf files to whatever
+form your X11 server recognizes (usually using a command called bdftosnf
+for R4 servers or bdftopcf for R5 servers).  Then run mkfontdir on the
+directory containing your font files (you might want to copy them to GAMEDIR,
+from the top Makefile, after you've done "make install").  If these commands
+aren't familiar, talk to your local X11 guru and read the man pages.
+Finally, add that directory to your font search path (e.g. xset fp+ GAMEDIR,
+setting GAMEDIR to the value of GAMEDIR in the top Makefile).  Alternatively,
+you (assuming you are a system administrator) can install the fonts in your
+standard X11 font directory.  If you do not install the fonts in the standard
+X11 font directory, all persons playing nethack must add that "xset fp+"
+command to their .xinitrc file, or whatever file they execute when starting
+X11.  Adding the "xset" command to the nethack.sh is also an alternative,
+though it may clutter your X11 font search path after playing several games,
+so this method is not recommended.  See the note below for the alternative
+installation procedure for Sun's OpenWindows.
+
+
+If your X11 include files and libraries are not installed in a standard
+place (i.e. /usr/include/X11 and /usr/lib respectively) you will need to
+prepend an appropriate -I<idirectory> parameter to CFLAGS and a
+-L<ldirectory> parameter to LFLAGS, setting <?directory> to the place to
+find the include and library files for X11.
+
+
+Finally, to ensure NetHack's windows look the way they were intended to
+look, make sure the top Makefile VARDATND also contains NetHack.ad.  If it
+does, running nethack will automatically take the appropriate steps to
+cause this file to be used to initialize NetHack's X11 resources.
+
+
+Three icon suggestions to the window manager are supported:  nh72, nh56,
+and nh32.  Data for them comes from the source files nh72icon, nh56icon,
+and nh32icon; they are compiled into the program via #includes in winX.c.
+Selection between them is controlled by the "icon" resource in NetHack.ad;
+the default is nh72.
+
+
+Sorry, an Imakefile is not included.  Unlike many X11 programs, X11
+support is only a small, optional, part of nethack, and the Makefile is
+needed for systems that don't use X11.
+
+
+Notes for Sun's OpenWindows:
+    1. For OpenWindows 3.0 (NOT 2.x), define OPENWINBUG in include/unixconf.h.
+       The library bug from SunOS 4.1.x is fixed in Solaris 2.x (or when
+       proper Sun patches have been applied to 4.1.x), so it is also
+       unnecessary there.  (Defining it when unnecessary causes the same
+       problem being avoided when it is necessary. :-)
+
+    2.  In addition to the changes suggested by the comments in src/Makefile,
+
+       -- for OpenWindows 2.x and 3.0 (NOT 3.1) (i.e., versions for SunOS 4.x),
+          add -I/usr/openwin/include to CFLAGS, -L/usr/openwin/lib to LFLAGS,
+          and -lm to WINX11LIB in src/Makefile.
+
+       -- for OpenWindows 3.1 (i.e., versions for Solaris 2.x), add
+          -I/usr/openwin/include to CFLAGS, -L/usr/openwin/lib -L/usr/ccs/lib
+          -R/usr/openwin/lib to LFLAGS, and -lsocket -lnsl -lm
+          to WINX11LIB in src/Makefile.
+
+       (Naturally, if your OpenWindows is installed elsewhere, adapt the
+       openwin paths.)  This will allow you to create a game executable.
+
+    3. Run the fonts through convertfont and run bldfamily on the directory.
+       Now you must let your X server know where to find the fonts.  For a
+       personal installation, the simplest thing is to include the directory
+       of the fonts in the environment variable FONTPATH, as set in your
+       .profile or .login before starting the server.  For a multi-user
+       installation, you have the various "xset fp+" options outlined
+       above for standard X.
+
+    4.  Something must still be done with the NetHack.ad file -- all three
+       of the possibilities mentioned for standard X11 should work.
+
+
+Notes for AIX 3.2:
+    1.  AIX 3.2 includes the Athena Widget Toolkit library (and other things)
+       under the /usr/lpp/X11/Xamples tree, so you will have to add
+       -L/usr/lpp/X11/Xamples/lib to LFLAGS.  If you can't find libXaw.a on
+       your first build, go into /usr/lib/X11/Xamples, read the README file,
+       and build the library.
+
+Notes for XFree86 - (on linux and BSD386 platforms)
+
+    1.  Edit src/Makefile for linux/BSD386. Even though you use the 
+       Open Look Window manager, do not define OPENWINBUG.  Use the 
+       standard X11 object and library options.
+
+    2.  Follow the standard installation directions defined above.
+
+
+File                           Description
+---------      ---------------------------------------------------------------
+nethack.rc     - A sample configuration file for fonts nh10 and ibm.
+nh10.bdf       - A modified version of the 10x20 standard font.
+ibm.bdf                - A modified version of one of the ibm (8x14) nethack font.
+                 Must be used in conjunction with NetHack.ad or nethack.rc.
+nh32icon       - A 32x32 icon bitmap for use with window managers.
+nh56icon       - A 56x56 icon bitmap for use with window managers.
+nh72icon       - A 72x72 icon bitmap for use with window managers.
+nh_icon.xpm    - A color icon for use with window managers.
+NetHack.ad     - A sample .Xdefaults for a color screen.
+../../include/Window.h
+../../include/WindowP.h
+Window.c       - A bare-bones widget that has 16 colors and a drawing canvas.
+../../include/winX.h
+               - Defines for the X window-port.
+win*.c         - Code for the X window-port
+dialogs.c      - A better dialog widget.  Original code (modified slightly
+                 by Dean Luick) distributed under the X copyright by Tim
+                 Theisen.  This is from his Ghostview program (which is under
+                 the GNU public license, v2 or higher).
+pet_mark.xbm   - A pet indicator bitmap for tiles.
+rip.xpm                - A graphical tombstone.
+tile2x11.c     - Converts win/share tiles for X11 use.
diff --git a/win/X11/NetHack.ad b/win/X11/NetHack.ad
new file mode 100644 (file)
index 0000000..d7e9ed3
--- /dev/null
@@ -0,0 +1,190 @@
+! The display_file, tombstone, and menu windows are all formatted assuming
+! a fixed width font.  Text windows may or may not be formatted as above.
+! The rip window applies if the GRAPHIC_TOMBSTONE option is turned on, and
+! requires a 12 pixel font for correct appearance.
+!
+NetHack*font:                          variable
+NetHack*display_file*font:             fixed
+NetHack*tombstone*font:                        fixed
+NetHack*text*rip*font:                 -*-times-medium-r-*-*-12-*-*-*-*-*-*-*
+NetHack*menu*font:                     fixed
+NetHack*text*font:                     fixed
+NetHack*map*font:                      nh10
+
+! To use full-color tiles for the map, uncomment the tile file name.
+! If you use a 100dpi (or greater) monitor you may wish to double the
+! tile size so you can see the figures.  If NetHack was compiled to
+! use XPM (USE_XPM in config.h), the tile_file is a standard XPM file.
+! Otherwise, it is a custom format.  double_tile_size only applies to
+! the custom format - to enlarge an XPM file, use processing tools
+! such as XV or preferably PBMplus.
+!
+!NetHack.tile_file: x11tiles
+!NetHack.double_tile_size: True
+!
+! The annotation of pets.
+!NetHack.pet_mark_bitmap: pet_mark.xbm
+!NetHack.pet_mark_color: Red
+
+! Tombstone
+! The image file
+!NetHack.tombstone: rip.xpm
+! Text starts at (tombtext_x, tombtext_y) and subsequent lines
+! are displaced by (tombtext_dx, tombtext_dy) pixels.  If you
+!NetHack.tombtext_x: 155
+!NetHack.tombtext_y: 78
+!NetHack.tombtext_dx: 0
+!NetHack.tombtext_dy: 13
+! The color to use for the text on the hero's tombstone
+NetHack*rip*foreground: black
+
+! Translation tables.  There are currently several actions in nethack, but
+! the only one you should be using is "input()", which, with no parameters,
+! uses XLookupString to translate your keypress into a command.  You
+! can optionally give it parameters to change the behavior, see the example
+! below.  Note that you have to specify the translations in every appropriate
+! window.
+NetHack*message*translations:  <KeyPress>: input()
+!
+! Example extra translations for the map window.
+!
+!NetHack*map*translations:     #override \
+!                              !<Key>Left: input(h) \n\
+!                              !<Key>Right: input(l) \n\
+!                              !<Key>Up: input(k) \n\
+!                              !<Key>Down: input(j)
+!
+! The icon to use; supported values are nh72, nh56, and nh32; nh72 is the
+! default.  Some window managers may not support the larger icon sizes.
+! It is not guaranteed that the window manager will honor the icon selection.
+!NetHack*icon: nh56
+!
+! If True, the default, a popup for single character prompts such as y/n
+! questions is _not_ used.
+NetHack*slow: True
+
+! The number of lines the message window will show without scrolling.
+!NetHack*message_lines: 12
+!
+! If True, the message window has a line that seperates old and new messages.
+!NetHack*message_line: True
+!
+! If True, force keyboard to attach to popup windows.  Some window managers
+! enforce a click-to-focus-keyboard policy (e.g. the DECwindows wm).  NetHack
+! has a lot of popups and is almost unplayable without some kind of autofocus.
+!NetHack*autofocus: True
+!
+! Specify the number of rows and columns of the map window.  The default
+! is the standard 80x21 window.  Note: this _does_not_ change nethack's
+! level size, only what you see of it.
+!NetHack*map*rows:     21
+!NetHack*map*columns:  80
+
+! Parts of the fancy status display.
+!
+NetHack*status_condition.borderWidth:  0
+NetHack*status_info*borderWidth:       0
+
+! Sample color screen entries.
+!
+NetHack*nethack.background:    wheat
+NetHack*map*yellow:            gold
+NetHack*map*brown:             tan
+NetHack*map*gray:              grey85
+NetHack*map*foreground:                wheat
+NetHack*map*background:                grey40
+
+NetHack*fancy_status.skipAdjust:        True
+NetHack*fancy_status.background:       wheat
+NetHack*status_info*foreground:                Sienna
+NetHack*status_info*background:                wheat
+NetHack*status_info.background:                wheat
+NetHack*status_attributes*foreground:  black
+NetHack*status_attributes*background:  white
+NetHack*status_condition*foreground:   red
+NetHack*status_condition*background:   wheat
+NetHack*Scrollbar*foreground:          Sienna
+NetHack*Scrollbar*background:          wheat
+NetHack*status_info*showGrip:          False
+NetHack*status_attributes*showGrip:    False
+
+NetHack*player_selection*random.borderColor:   blue
+NetHack*player_selection*random.borderWidth:    2
+NetHack*player_selection*random.foreground:    blue
+NetHack*player_selection*random.accelerators: #override\n\
+                               <Key>Return:    set() notify() unset()
+NetHack*player_selection*quit.borderColor:     blue
+NetHack*player_selection*quit.foreground:      blue
+NetHack*player_selection*Command.borderColor:  red
+NetHack*player_selection*Command.foreground:   red
+NetHack*player_selection*quit.accelerators: #override\n\
+                               <Key>Escape:    set() notify() unset()
+
+NetHack*race_selection*random.borderColor:     blue
+NetHack*race_selection*random.borderWidth:     2
+NetHack*race_selection*random.foreground:      blue
+NetHack*race_selection*random.accelerators: #override\n\
+                               <Key>Return:    set() notify() unset()
+NetHack*race_selection*quit.borderColor:       blue
+NetHack*race_selection*quit.foreground:                blue
+NetHack*race_selection*Command.borderColor:    red
+NetHack*race_selection*Command.foreground:     red
+NetHack*race_selection*quit.accelerators: #override\n\
+                               <Key>Escape:    set() notify() unset()
+
+NetHack*gender_selection*random.borderColor:   blue
+NetHack*gender_selection*random.borderWidth:   2
+NetHack*gender_selection*random.foreground:    blue
+NetHack*gender_selection*random.accelerators: #override\n\
+                               <Key>Return:    set() notify() unset()
+NetHack*gender_selection*quit.borderColor:     blue
+NetHack*gender_selection*quit.foreground:      blue
+NetHack*gender_selection*Command.borderColor:  red
+NetHack*gender_selection*Command.foreground:   red
+NetHack*gender_selection*quit.accelerators: #override\n\
+                               <Key>Escape:    set() notify() unset()
+
+NetHack*alignment_selection*random.borderColor:        blue
+NetHack*alignment_selection*random.borderWidth:        2
+NetHack*alignment_selection*random.foreground: blue
+NetHack*alignment_selection*random.accelerators: #override\n\
+                               <Key>Return:    set() notify() unset()
+NetHack*alignment_selection*quit.borderColor:  blue
+NetHack*alignment_selection*quit.foreground:   blue
+NetHack*alignment_selection*Command.borderColor: red
+NetHack*alignment_selection*Command.foreground:        red
+NetHack*alignment_selection*quit.accelerators: #override\n\
+                               <Key>Escape:    set() notify() unset()
+
+NetHack*extended_commands*dismiss.borderColor: blue
+NetHack*extended_commands*dismiss.foreground:  blue
+NetHack*extended_commands*help.borderColor:    blue
+NetHack*extended_commands*help.foreground:     blue
+NetHack*extended_commands*Command.borderColor: red
+NetHack*extended_commands*Command.foreground:  red
+NetHack*extended_commands*help.accelerators: #override\n\
+                               :<Key>?:        set() notify() unset()
+NetHack*extended_commands*dismiss.accelerators: #override\n\
+                               <Key>Escape:    set() notify() unset()
+!
+!
+! The following are the default 15 colors that the nethack map uses.
+! If they don't look good on your screen, change them.
+!
+! The foreground color is used as "no color".
+!
+!NetHack*map*black:            black
+!NetHack*map*red:              red
+!NetHack*map*green:            pale green
+!NetHack*map*brown:            brown
+!NetHack*map*blue:             blue
+!NetHack*map*magenta:          magenta
+!NetHack*map*cyan:             light cyan
+!NetHack*map*gray:             gray
+!NetHack*map*orange:           orange
+!NetHack*map*bright_green:     green
+!NetHack*map*yellow:           yellow
+!NetHack*map*bright_blue:      royal blue
+!NetHack*map*bright_magenta:   violet
+!NetHack*map*bright_cyan:      cyan
+!NetHack*map*white:            white
diff --git a/win/X11/Window.c b/win/X11/Window.c
new file mode 100644 (file)
index 0000000..c21c8f2
--- /dev/null
@@ -0,0 +1,170 @@
+/*     SCCS Id: @(#)Window.c   3.4     1993/02/02      */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Data structures and support routines for the Window widget.  This is a
+ * drawing canvas with 16 colors and one font.
+ */
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+#ifdef MSDOS                   /* from compiler */
+#define SHORT_FILENAMES
+#endif
+
+#ifdef SHORT_FILENAMES
+#include <X11/IntrinsP.h>
+#else
+#include <X11/IntrinsicP.h>
+#endif
+#include <X11/StringDefs.h>
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+#include "xwindowp.h"
+
+#include "config.h"
+
+static XtResource resources[] = {
+#define offset(field) XtOffset(WindowWidget, window.field)
+    /* {name, class, type, size, offset, default_type, default_addr}, */
+    { XtNrows, XtCRows, XtRDimension, sizeof(Dimension),
+         offset(rows), XtRImmediate, (XtPointer) 21},
+    { XtNcolumns, XtCColumns, XtRDimension, sizeof(Dimension),
+         offset(columns), XtRImmediate, (XtPointer) 80},
+    { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+         offset(foreground), XtRString, XtDefaultForeground },
+
+    { XtNblack, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(black), XtRString, "black"},
+    { XtNred, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(red), XtRString, "red" },
+    { XtNgreen, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(green), XtRString, "pale green" },
+    { XtNbrown, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(brown), XtRString, "brown" },
+    { XtNblue, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(blue), XtRString, "blue" },
+    { XtNmagenta, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(magenta), XtRString, "magenta" },
+    { XtNcyan, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(cyan), XtRString, "light cyan" },
+    { XtNgray, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(gray), XtRString, "gray" },
+    { XtNorange, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(orange), XtRString, "orange" },
+    { XtNbright_green, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(bright_green), XtRString, "green" },
+    { XtNyellow, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(yellow), XtRString, "yellow" },
+    { XtNbright_blue, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(bright_blue), XtRString, "royal blue" },
+    { XtNbright_magenta, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(bright_magenta), XtRString, "violet" },
+    { XtNbright_cyan, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(bright_cyan), XtRString, "cyan" },
+    { XtNwhite, XtCColor, XtRPixel, sizeof(Pixel),
+         offset(white), XtRString, "white" },
+
+    { XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+         offset(font), XtRString, XtDefaultFont },
+    { XtNexposeCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+         offset(expose_callback), XtRCallback, (char *)0 },
+    { XtNcallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+         offset(input_callback), XtRCallback, (char *)0 },
+    { XtNresizeCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+         offset(resize_callback), XtRCallback, (char *)0 },
+#undef offset
+};
+
+/* ARGSUSED */
+static void no_op(w, event, params, num_params)
+    Widget   w;                        /* unused */
+    XEvent   *event;           /* unused */
+    String   *params;          /* unused */
+    Cardinal *num_params;      /* unused */
+{
+}
+
+static XtActionsRec actions[] =
+{
+    {"no-op",  no_op},
+};
+
+static char translations[] =
+"<BtnDown>:     input() \
+";
+
+/* ARGSUSED */
+static void Redisplay(w, event, region)
+    Widget w;
+    XEvent *event;
+    Region region;     /* unused */
+{
+    /* This isn't correct - we need to call the callback with region. */
+    XtCallCallbacks(w, XtNexposeCallback, (caddr_t) event);
+}
+
+/* ARGSUSED */
+static void Resize(w)
+    Widget w;
+{
+    XtCallCallbacks(w, XtNresizeCallback, (caddr_t) 0);
+}
+
+
+WindowClassRec windowClassRec = {
+  { /* core fields */
+    /* superclass              */      (WidgetClass) &widgetClassRec,
+    /* class_name              */      "Window",
+    /* widget_size             */      sizeof(WindowRec),
+    /* class_initialize                */      0,
+    /* class_part_initialize   */      0,
+    /* class_inited            */      FALSE,
+    /* initialize              */      0,
+    /* initialize_hook         */      0,
+    /* realize                 */      XtInheritRealize,
+    /* actions                 */      actions,
+    /* num_actions             */      XtNumber(actions),
+    /* resources               */      resources,
+    /* num_resources           */      XtNumber(resources),
+    /* xrm_class               */      NULLQUARK,
+    /* compress_motion         */      TRUE,
+    /* compress_exposure       */      TRUE,
+    /* compress_enterleave     */      TRUE,
+    /* visible_interest                */      FALSE,
+    /* destroy                 */      0,
+    /* resize                  */      Resize,
+    /* expose                  */      Redisplay,
+    /* set_values              */      0,
+    /* set_values_hook         */      0,
+    /* set_values_almost       */      XtInheritSetValuesAlmost,
+    /* get_values_hook         */      0,
+    /* accept_focus            */      0,
+    /* version                 */      XtVersion,
+    /* callback_private                */      0,
+    /* tm_table                        */      translations,
+    /* query_geometry          */      XtInheritQueryGeometry,
+    /* display_accelerator     */      XtInheritDisplayAccelerator,
+    /* extension               */      0
+  },
+  { /* window fields */
+    /* empty                   */      0
+  }
+};
+
+WidgetClass windowWidgetClass = (WidgetClass)&windowClassRec;
+
+Font
+WindowFont(w) Widget w; { return ((WindowWidget)w)->window.font->fid; }
+
+XFontStruct *
+WindowFontStruct(w) Widget w; { return ((WindowWidget)w)->window.font; }
diff --git a/win/X11/dialogs.c b/win/X11/dialogs.c
new file mode 100644 (file)
index 0000000..a887ef0
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Copyright 1991 University of Wisconsin-Madison
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the University of Wisconsin-Madison not
+ * be used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  The University of
+ * Wisconsin-Madison makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or
+ * implied warranty.
+ *
+ * THE UNIVERSITY OF WISCONSIN-MADISON DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF WISCONSIN-MADISON BE LIABLE FOR
+ * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author:  Tim Theisen             Department of Computer Sciences
+ *          tim@cs.wisc.edu         University of Wisconsin-Madison
+ *          uwvax!tim               1210 West Dayton Street
+ *          (608)262-0438           Madison, WI   53706
+ *
+ *
+ * Modified 12/91 by Dean Luick.  Tim graciously donated this piece of code
+ * from his program ghostview, an X11 front end for ghostscript.
+ *
+ *    + Make the cancel button optional.
+ *    + Put an #ifdef SPECIAL_CMAP around code to fix a colormap bug.
+ *     We don't need it here.
+ *    + Add the function positionpopup() from another part of ghostview
+ *     to this code.
+ *
+ * Modified 2/93, Various.
+ *    + Added workaround for SYSV include problem.
+ *    + Changed the default width response text widget to be as wide as the
+ *     window itself.  Suggestion from David E. Wexelblat, dwex@goblin.org.
+ */
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Cardinals.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Command.h>
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+#include "config.h"    /* #define for const for non __STDC__ compilers */
+
+/* ":" added to both translations below to allow limited redefining of
+ * keysyms before testing for keysym values -- dlc */
+static const char okay_accelerators[] =
+    "#override\n\
+     :<Key>Return: set() notify() unset()\n";
+
+static const char cancel_accelerators[] =
+    "#override\n\
+     :<Key>Escape: set() notify() unset()\n\
+     :<Ctrl>[: set() notify() unset()\n";      /* for keyboards w/o an ESC */
+
+
+/* Create a dialog widget.  It is just a form widget with
+ *     a label prompt
+ *     a text response
+ *     an okay button
+ *     an optional cancel button
+ */
+Widget
+CreateDialog(parent, name, okay_callback, cancel_callback)
+    Widget parent;
+    String name;
+    XtCallbackProc okay_callback;
+    XtCallbackProc cancel_callback;
+{
+    Widget form, prompt, response, okay, cancel;
+    Arg args[20];
+    Cardinal num_args;
+
+                                                       num_args = 0;
+#ifdef SPECIAL_CMAP
+    if (special_cmap) {
+       XtSetArg(args[num_args], XtNbackground, white); num_args++;
+    }
+#endif
+    form = XtCreateManagedWidget(name, formWidgetClass, parent, args, num_args);
+
+                                                       num_args = 0;
+#ifdef SPECIAL_CMAP
+    if (special_cmap) {
+       XtSetArg(args[num_args], XtNforeground, black); num_args++;
+       XtSetArg(args[num_args], XtNbackground, white); num_args++;
+    }
+#endif
+    XtSetArg(args[num_args], XtNtop, XtChainTop);      num_args++;
+    XtSetArg(args[num_args], XtNbottom, XtChainTop);   num_args++;
+    XtSetArg(args[num_args], XtNleft, XtChainLeft);    num_args++;
+    XtSetArg(args[num_args], XtNright, XtChainLeft);   num_args++;
+    XtSetArg(args[num_args], XtNresizable, True);      num_args++;
+    XtSetArg(args[num_args], XtNborderWidth, 0);       num_args++;
+    prompt = XtCreateManagedWidget("prompt", labelWidgetClass,
+                                  form, args, num_args);
+
+                                                       num_args = 0;
+#ifdef SPECIAL_CMAP
+    if (special_cmap) {
+       XtSetArg(args[num_args], XtNforeground, black); num_args++;
+       XtSetArg(args[num_args], XtNbackground, white); num_args++;
+    }
+#endif
+    XtSetArg(args[num_args], XtNfromVert, prompt);     num_args++;
+    XtSetArg(args[num_args], XtNtop, XtChainTop);      num_args++;
+    XtSetArg(args[num_args], XtNbottom, XtChainTop);   num_args++;
+    XtSetArg(args[num_args], XtNleft, XtChainLeft);    num_args++;
+    XtSetArg(args[num_args], XtNright, XtChainLeft);   num_args++;
+    XtSetArg(args[num_args], XtNresizable, True);      num_args++;
+    XtSetArg(args[num_args], XtNeditType, XawtextEdit);        num_args++;
+    XtSetArg(args[num_args], XtNresize, XawtextResizeWidth);   num_args++;
+    XtSetArg(args[num_args], XtNstring, "");           num_args++;
+    response = XtCreateManagedWidget("response", asciiTextWidgetClass,
+                                    form, args, num_args);
+
+                                                       num_args = 0;
+#ifdef SPECIAL_CMAP
+    if (special_cmap) {
+       XtSetArg(args[num_args], XtNforeground, black); num_args++;
+       XtSetArg(args[num_args], XtNbackground, white); num_args++;
+    }
+#endif
+    XtSetArg(args[num_args], XtNfromVert, response);   num_args++;
+    XtSetArg(args[num_args], XtNtop, XtChainTop);      num_args++;
+    XtSetArg(args[num_args], XtNbottom, XtChainTop);   num_args++;
+    XtSetArg(args[num_args], XtNleft, XtChainLeft);    num_args++;
+    XtSetArg(args[num_args], XtNright, XtChainLeft);   num_args++;
+    XtSetArg(args[num_args], XtNresizable, True);      num_args++;
+    XtSetArg(args[num_args], XtNaccelerators,
+            XtParseAcceleratorTable(okay_accelerators));       num_args++;
+    okay = XtCreateManagedWidget("okay", commandWidgetClass,
+                                form, args, num_args);
+    XtAddCallback(okay, XtNcallback, okay_callback, form);
+
+    /* Only create cancel button if there is a callback for it. */
+    if (cancel_callback) {
+                                                               num_args = 0;
+#ifdef SPECIAL_CMAP
+       if (special_cmap) {
+           XtSetArg(args[num_args], XtNforeground, black);     num_args++;
+           XtSetArg(args[num_args], XtNbackground, white);     num_args++;
+       }
+#endif
+       XtSetArg(args[num_args], XtNfromVert, response);        num_args++;
+       XtSetArg(args[num_args], XtNfromHoriz, okay);           num_args++;
+       XtSetArg(args[num_args], XtNtop, XtChainTop);           num_args++;
+       XtSetArg(args[num_args], XtNbottom, XtChainTop);        num_args++;
+       XtSetArg(args[num_args], XtNleft, XtChainLeft);         num_args++;
+       XtSetArg(args[num_args], XtNright, XtChainLeft);        num_args++;
+       XtSetArg(args[num_args], XtNresizable, True);           num_args++;
+       XtSetArg(args[num_args], XtNaccelerators,
+            XtParseAcceleratorTable(cancel_accelerators));     num_args++;
+       cancel = XtCreateManagedWidget("cancel", commandWidgetClass,
+                                      form, args, num_args);
+       XtAddCallback(cancel, XtNcallback, cancel_callback, form);
+       XtInstallAccelerators(response, cancel);
+    }
+
+    XtInstallAccelerators(response, okay);
+    XtSetKeyboardFocus(form, response);
+
+    return form;
+}
+
+#if 0
+/* get the prompt from the dialog box.  Used a startup time to
+ * save away the initial prompt */
+String
+GetDialogPrompt(w)
+    Widget w;
+{
+    Arg args[1];
+    Widget label;
+    String s;
+
+    label = XtNameToWidget(w, "prompt");
+    XtSetArg(args[0], XtNlabel, &s);
+    XtGetValues(label, args, ONE);
+    return XtNewString(s);
+}
+#endif
+
+/* set the prompt.  This is used to put error information in the prompt */
+void
+SetDialogPrompt(w, newprompt)
+    Widget w;
+    String newprompt;
+{
+    Arg args[1];
+    Widget label;
+
+    label = XtNameToWidget(w, "prompt");
+    XtSetArg(args[0], XtNlabel, newprompt);
+    XtSetValues(label, args, ONE);
+}
+
+/* get what the user typed; caller must free the response */
+String
+GetDialogResponse(w)
+    Widget w;
+{
+    Arg args[1];
+    Widget response;
+    String s;
+
+    response = XtNameToWidget(w, "response");
+    XtSetArg(args[0], XtNstring, &s);
+    XtGetValues(response, args, ONE);
+    return XtNewString(s);
+}
+
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+/* set the default reponse */
+void
+SetDialogResponse(w, s)
+    Widget w;
+    String s;
+{
+    Arg args[4];
+    Widget response;
+    XFontStruct *font;
+    Dimension width, nwidth, leftMargin, rightMargin;
+
+    response = XtNameToWidget(w, "response");
+    XtSetArg(args[0], XtNfont, &font);
+    XtSetArg(args[1], XtNleftMargin, &leftMargin);
+    XtSetArg(args[2], XtNrightMargin, &rightMargin);
+    XtSetArg(args[3], XtNwidth, &width);
+    XtGetValues(response, args, FOUR);
+    /* width includes margins as per Xaw documentation */
+    nwidth = (font->max_bounds.width * strlen(s))+leftMargin+rightMargin;
+    if (nwidth < width)
+       nwidth = width;
+
+    XtSetArg(args[0], XtNstring, s);
+    XtSetArg(args[1], XtNwidth, nwidth);
+    XtSetValues(response, args, TWO);
+    XawTextSetInsertionPoint(response, strlen(s));
+}
+
+#if 0
+/* clear the response */
+void
+ClearDialogResponse(w)
+    Widget w;
+{
+    Arg args[2];
+    Widget response;
+
+    response = XtNameToWidget(w, "response");
+    XtSetArg(args[0], XtNstring, "");
+    XtSetArg(args[1], XtNwidth, 100);
+    XtSetValues(response, args, TWO);
+}
+#endif
+
+
+/* Not a part of the original dialogs.c from ghostview --------------------- */
+
+/* position popup window under the cursor */
+void
+positionpopup(w, bottom)
+    Widget w;
+    boolean bottom;    /* position y on bottom? */
+{
+    Arg args[3];
+    Cardinal num_args;
+    Dimension width, height, b_width;
+    int x, y, max_x, max_y;
+    Window root, child;
+    XSizeHints *hints;
+    int dummyx, dummyy;
+    unsigned int dummymask;
+    extern Widget toplevel;
+
+    /* following line deals with a race condition w/brain-damaged WM's -dlc */
+    XtUnrealizeWidget(w);
+
+    XQueryPointer(XtDisplay(toplevel), XtWindow(toplevel), &root, &child,
+                 &x, &y, &dummyx, &dummyy, &dummymask);
+    num_args = 0;
+    XtSetArg(args[num_args], XtNwidth, &width); num_args++;
+    XtSetArg(args[num_args], XtNheight, &height); num_args++;
+    XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
+    XtGetValues(w, args, num_args);
+
+    /* position so that the cursor is center,center or center,bottom */
+    width += 2 * b_width;
+    x -= ( (Position) width/2 );
+    if (x < 0) x = 0;
+    if ( x > (max_x = (Position) (XtScreen(w)->width - width)) ) x = max_x;
+
+    if (bottom) {
+       y -= (height+b_width-1);
+       height += 2 * b_width;
+    } else {
+       height += 2 * b_width;
+       y -= ( (Position) height/2 );
+    }
+    if (y < 0) y = 0;
+    if ( y > (max_y = (Position) (XtScreen(w)->height - height)) ) y = max_y;
+
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNx, x); num_args++;
+    XtSetArg(args[num_args], XtNy, y); num_args++;
+    XtSetValues(w, args, num_args);
+
+    /* Some older window managers ignore XtN{x,y}; hint the same values */
+    /* The {x,y} are not used by newer window managers; older ones need them */
+    XtRealizeWidget(w);
+    hints = XAllocSizeHints();
+    hints->flags = USPosition;
+    hints->x = x;
+    hints->y = y;
+    XSetWMNormalHints(XtDisplay(w), XtWindow(w), hints);
+    XFree(hints);
+}
diff --git a/win/X11/ibm.bdf b/win/X11/ibm.bdf
new file mode 100644 (file)
index 0000000..f2b77f3
--- /dev/null
@@ -0,0 +1,5404 @@
+STARTFONT 2.1
+COMMENT (null)
+FONT -Misc-Fixed-Medium-R-Normal-IBMPC-14-120-75-75-C-80-ISO8859-1
+SIZE 13 78 78
+FONTBOUNDINGBOX 8 14 0 -3
+STARTPROPERTIES 19
+FONTNAME_REGISTRY ""
+FOUNDRY "Misc"
+FAMILY_NAME "Fixed"
+WEIGHT_NAME "Medium"
+SLANT "R"
+SETWIDTH_NAME "Normal"
+ADD_STYLE_NAME "IBMPC"
+PIXEL_SIZE 14
+POINT_SIZE 120
+RESOLUTION_X 75
+RESOLUTION_Y 75
+SPACING "C"
+AVERAGE_WIDTH 80
+CHARSET_REGISTRY "ISO8859"
+CHARSET_ENCODING "1"
+DEFAULT_CHAR 0
+FONT_DESCENT 3
+FONT_ASCENT 11
+COPYRIGHT "Public domain font.  Share and enjoy."
+ENDPROPERTIES
+CHARS 256
+STARTCHAR C000
+ENCODING 0
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C001
+ENCODING 1
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7e00
+8100
+a500
+8100
+8100
+bd00
+9900
+8100
+7e00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C002
+ENCODING 2
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7e00
+ff00
+db00
+ff00
+ff00
+c300
+e700
+ff00
+7e00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C003
+ENCODING 3
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+6c00
+ee00
+fe00
+fe00
+fe00
+7c00
+3800
+1000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C004
+ENCODING 4
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+1000
+3800
+7c00
+fe00
+7c00
+3800
+1000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C005
+ENCODING 5
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+1000
+3800
+1000
+6c00
+ee00
+6c00
+1000
+3800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C006
+ENCODING 6
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1000
+3800
+7c00
+7c00
+fe00
+fe00
+6c00
+1000
+3800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C007
+ENCODING 7
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+1800
+3c00
+3c00
+1800
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C010
+ENCODING 8
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+ff00
+ff00
+ff00
+ff00
+ff00
+e700
+c300
+c300
+e700
+ff00
+ff00
+ff00
+ff00
+ff00
+ENDCHAR
+STARTCHAR C011
+ENCODING 9
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+1800
+3c00
+6600
+6600
+3c00
+1800
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C012
+ENCODING 10
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+ff00
+ff00
+ff00
+ff00
+e700
+c300
+9900
+9900
+c300
+e700
+ff00
+ff00
+ff00
+ff00
+ENDCHAR
+STARTCHAR C013
+ENCODING 11
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1e00
+0e00
+1e00
+3600
+7800
+cc00
+cc00
+cc00
+7800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C014
+ENCODING 12
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3c00
+6600
+6600
+6600
+3c00
+1800
+7e00
+1800
+1800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C015
+ENCODING 13
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1e00
+1a00
+1e00
+1800
+1800
+1800
+7800
+f800
+7000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C016
+ENCODING 14
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+3e00
+3600
+3e00
+3600
+3600
+7600
+f600
+6600
+0e00
+1e00
+0c00
+0000
+0000
+ENDCHAR
+STARTCHAR C017
+ENCODING 15
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+1800
+db00
+7e00
+3c00
+6600
+6600
+3c00
+7e00
+db00
+1800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C020
+ENCODING 16
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+8000
+e000
+f000
+fc00
+fe00
+fc00
+f000
+e000
+8000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C021
+ENCODING 17
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0200
+0e00
+3e00
+7e00
+fe00
+7e00
+3e00
+0e00
+0200
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C022
+ENCODING 18
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1800
+3c00
+7e00
+1800
+1800
+1800
+7e00
+3c00
+1800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C023
+ENCODING 19
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+6600
+6600
+6600
+6600
+6600
+6600
+0000
+6600
+6600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C024
+ENCODING 20
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7f00
+db00
+db00
+db00
+7b00
+1b00
+1b00
+1b00
+1b00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C025
+ENCODING 21
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+7c00
+c600
+c600
+6000
+7c00
+f600
+de00
+7c00
+0c00
+c600
+c600
+7c00
+0000
+ENDCHAR
+STARTCHAR C026
+ENCODING 22
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+fe00
+fe00
+fe00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C027
+ENCODING 23
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1800
+3c00
+7e00
+1800
+1800
+7e00
+3c00
+1800
+7e00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C030
+ENCODING 24
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1800
+3c00
+7e00
+1800
+1800
+1800
+1800
+1800
+1800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C031
+ENCODING 25
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1800
+1800
+1800
+1800
+1800
+1800
+7e00
+3c00
+1800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C032
+ENCODING 26
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0c00
+0e00
+ff00
+0e00
+0c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C033
+ENCODING 27
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+3000
+7000
+fe00
+7000
+3000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C034
+ENCODING 28
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+c000
+c000
+c000
+fe00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C035
+ENCODING 29
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+2400
+6600
+ff00
+6600
+2400
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C036
+ENCODING 30
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1000
+3800
+3800
+3800
+7c00
+7c00
+fe00
+fe00
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C037
+ENCODING 31
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+fe00
+fe00
+7c00
+7c00
+7c00
+3800
+3800
+1000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C040
+ENCODING 32
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR !
+ENCODING 33
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1800
+3c00
+3c00
+3c00
+1800
+1800
+0000
+1800
+1800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR "
+ENCODING 34
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+3600
+3600
+3600
+1400
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR #
+ENCODING 35
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+6c00
+6c00
+6c00
+fe00
+6c00
+6c00
+fe00
+6c00
+6c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR $
+ENCODING 36
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+1800
+1800
+7c00
+c600
+c000
+7800
+3c00
+0600
+c600
+7c00
+1800
+1800
+0000
+ENDCHAR
+STARTCHAR %
+ENCODING 37
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+6200
+6600
+0c00
+1800
+3000
+6600
+c600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR &
+ENCODING 38
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3800
+6c00
+3800
+3800
+7600
+f600
+ce00
+cc00
+7600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR '
+ENCODING 39
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0c00
+0c00
+0c00
+1800
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR (
+ENCODING 40
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0c00
+1800
+3000
+3000
+3000
+3000
+3000
+1800
+0c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR )
+ENCODING 41
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3000
+1800
+0c00
+0c00
+0c00
+0c00
+0c00
+1800
+3000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR *
+ENCODING 42
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+6c00
+3800
+fe00
+3800
+6c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR +
+ENCODING 43
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+1800
+1800
+7e00
+1800
+1800
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ,
+ENCODING 44
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0c00
+0c00
+0c00
+1800
+0000
+0000
+ENDCHAR
+STARTCHAR -
+ENCODING 45
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+fe00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR .
+ENCODING 46
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1800
+1800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR /
+ENCODING 47
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0200
+0600
+0c00
+1800
+3000
+6000
+c000
+8000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 0
+ENCODING 48
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+c600
+ce00
+de00
+f600
+e600
+c600
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 1
+ENCODING 49
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1800
+7800
+1800
+1800
+1800
+1800
+1800
+1800
+7e00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 2
+ENCODING 50
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+c600
+c600
+0c00
+1800
+3000
+6000
+c600
+fe00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 3
+ENCODING 51
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+c600
+0600
+0600
+3c00
+0600
+0600
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 4
+ENCODING 52
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0c00
+1c00
+3c00
+6c00
+cc00
+fe00
+0c00
+0c00
+0c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 5
+ENCODING 53
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+fe00
+c000
+c000
+c000
+fc00
+0600
+0600
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 6
+ENCODING 54
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+c600
+c000
+c000
+fc00
+c600
+c600
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 7
+ENCODING 55
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+fe00
+c600
+0c00
+1800
+3000
+3000
+3000
+3000
+3000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 8
+ENCODING 56
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+c600
+c600
+c600
+7c00
+c600
+c600
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 9
+ENCODING 57
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+c600
+c600
+c600
+7e00
+0600
+0600
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR :
+ENCODING 58
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0c00
+0c00
+0000
+0000
+0c00
+0c00
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ;
+ENCODING 59
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0c00
+0c00
+0000
+0000
+0c00
+0c00
+0c00
+1800
+0000
+0000
+ENDCHAR
+STARTCHAR <
+ENCODING 60
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0c00
+1800
+3000
+6000
+c000
+6000
+3000
+1800
+0c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR =
+ENCODING 61
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+fe00
+0000
+fe00
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR >
+ENCODING 62
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+6000
+3000
+1800
+0c00
+0600
+0c00
+1800
+3000
+6000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ?
+ENCODING 63
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+c600
+c600
+0c00
+1800
+1800
+0000
+1800
+1800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR @
+ENCODING 64
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+c600
+c600
+de00
+de00
+de00
+dc00
+c000
+7e00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR A
+ENCODING 65
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3800
+6c00
+c600
+c600
+c600
+fe00
+c600
+c600
+c600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR B
+ENCODING 66
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+fc00
+6600
+6600
+6600
+7c00
+6600
+6600
+6600
+fc00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C
+ENCODING 67
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3c00
+6600
+c000
+c000
+c000
+c000
+c000
+6600
+3c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR D
+ENCODING 68
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+f800
+6c00
+6600
+6600
+6600
+6600
+6600
+6c00
+f800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR E
+ENCODING 69
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+fe00
+6600
+6000
+6000
+7c00
+6000
+6000
+6600
+fe00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR F
+ENCODING 70
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+fe00
+6600
+6000
+6000
+7c00
+6000
+6000
+6000
+f000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR G
+ENCODING 71
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+c600
+c600
+c000
+c000
+ce00
+c600
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR H
+ENCODING 72
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+c600
+c600
+c600
+c600
+fe00
+c600
+c600
+c600
+c600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR I
+ENCODING 73
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3c00
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+3c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR J
+ENCODING 74
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3c00
+1800
+1800
+1800
+1800
+1800
+d800
+d800
+7000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR K
+ENCODING 75
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+c600
+cc00
+d800
+f000
+f000
+d800
+cc00
+c600
+c600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR L
+ENCODING 76
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+f000
+6000
+6000
+6000
+6000
+6000
+6200
+6600
+fe00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR M
+ENCODING 77
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+c600
+c600
+ee00
+fe00
+d600
+d600
+d600
+c600
+c600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR N
+ENCODING 78
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+c600
+c600
+e600
+e600
+f600
+de00
+ce00
+ce00
+c600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR O
+ENCODING 79
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+c600
+c600
+c600
+c600
+c600
+c600
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR P
+ENCODING 80
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+fc00
+6600
+6600
+6600
+7c00
+6000
+6000
+6000
+f000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Q
+ENCODING 81
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+c600
+c600
+c600
+c600
+c600
+c600
+d600
+7c00
+0600
+0000
+0000
+ENDCHAR
+STARTCHAR R
+ENCODING 82
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+fc00
+6600
+6600
+6600
+7c00
+7800
+6c00
+6600
+e600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR S
+ENCODING 83
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+c600
+c000
+6000
+3800
+0c00
+0600
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR T
+ENCODING 84
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7e00
+5a00
+1800
+1800
+1800
+1800
+1800
+1800
+3c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR U
+ENCODING 85
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+c600
+c600
+c600
+c600
+c600
+c600
+c600
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR V
+ENCODING 86
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+c600
+c600
+c600
+c600
+c600
+c600
+6c00
+3800
+1000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR W
+ENCODING 87
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+c600
+c600
+d600
+d600
+d600
+fe00
+ee00
+c600
+c600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR X
+ENCODING 88
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+c600
+c600
+6c00
+3800
+3800
+3800
+6c00
+c600
+c600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Y
+ENCODING 89
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+6600
+6600
+6600
+6600
+3c00
+1800
+1800
+1800
+3c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Z
+ENCODING 90
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+fe00
+c600
+8c00
+1800
+3000
+6000
+c200
+c600
+fe00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR [
+ENCODING 91
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+6000
+6000
+6000
+6000
+6000
+6000
+6000
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR \
+ENCODING 92
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+8000
+c000
+6000
+3000
+1800
+0c00
+0600
+0200
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ]
+ENCODING 93
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ^
+ENCODING 94
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+1000
+3800
+6c00
+c600
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR _
+ENCODING 95
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ff00
+0000
+ENDCHAR
+STARTCHAR `
+ENCODING 96
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+1800
+1800
+1800
+0c00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR a
+ENCODING 97
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+7800
+0c00
+7c00
+cc00
+dc00
+7600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR b
+ENCODING 98
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+e000
+6000
+6000
+7c00
+6600
+6600
+6600
+6600
+fc00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR c
+ENCODING 99
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+7c00
+c600
+c000
+c000
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR d
+ENCODING 100
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1c00
+0c00
+0c00
+7c00
+cc00
+cc00
+cc00
+cc00
+7e00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR e
+ENCODING 101
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+7c00
+c600
+fe00
+c000
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR f
+ENCODING 102
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1c00
+3600
+3000
+3000
+fc00
+3000
+3000
+3000
+7800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR g
+ENCODING 103
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+7600
+ce00
+c600
+c600
+7e00
+0600
+c600
+7c00
+0000
+ENDCHAR
+STARTCHAR h
+ENCODING 104
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+e000
+6000
+6000
+6c00
+7600
+6600
+6600
+6600
+e600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR i
+ENCODING 105
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1800
+1800
+0000
+3800
+1800
+1800
+1800
+1800
+3c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR j
+ENCODING 106
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0c00
+0c00
+0000
+1c00
+0c00
+0c00
+0c00
+0c00
+cc00
+cc00
+7800
+0000
+ENDCHAR
+STARTCHAR k
+ENCODING 107
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+e000
+6000
+6000
+6600
+6c00
+7800
+6c00
+6600
+e600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR l
+ENCODING 108
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3800
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+3c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR m
+ENCODING 109
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+6c00
+fe00
+d600
+d600
+c600
+c600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR n
+ENCODING 110
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+dc00
+6600
+6600
+6600
+6600
+6600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR o
+ENCODING 111
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+7c00
+c600
+c600
+c600
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR p
+ENCODING 112
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+dc00
+6600
+6600
+6600
+7c00
+6000
+6000
+f000
+0000
+ENDCHAR
+STARTCHAR q
+ENCODING 113
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+7600
+cc00
+cc00
+cc00
+7c00
+0c00
+0c00
+1e00
+0000
+ENDCHAR
+STARTCHAR r
+ENCODING 114
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+dc00
+6600
+6000
+6000
+6000
+f000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR s
+ENCODING 115
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+7c00
+c600
+7000
+1c00
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR t
+ENCODING 116
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3000
+3000
+3000
+fc00
+3000
+3000
+3000
+3600
+1c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR u
+ENCODING 117
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+cc00
+cc00
+cc00
+cc00
+cc00
+7600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR v
+ENCODING 118
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+c600
+c600
+c600
+6c00
+3800
+1000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR w
+ENCODING 119
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+c600
+c600
+d600
+d600
+fe00
+6c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR x
+ENCODING 120
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+c600
+6c00
+3800
+3800
+6c00
+c600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR y
+ENCODING 121
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+c600
+c600
+c600
+ce00
+7600
+0600
+c600
+7c00
+0000
+ENDCHAR
+STARTCHAR z
+ENCODING 122
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+fe00
+8c00
+1800
+3000
+6200
+fe00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR {
+ENCODING 123
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0e00
+1800
+1800
+1800
+7000
+1800
+1800
+1800
+0e00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR |
+ENCODING 124
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1800
+1800
+1800
+1800
+0000
+1800
+1800
+1800
+1800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR }
+ENCODING 125
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7000
+1800
+1800
+1800
+0e00
+1800
+1800
+1800
+7000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ~
+ENCODING 126
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7600
+dc00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C177
+ENCODING 127
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+1000
+3800
+3800
+6c00
+6c00
+fe00
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR vwall
+ENCODING 128
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+ENDCHAR
+STARTCHAR hwall
+ENCODING 129
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ff00
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR tlcorn
+ENCODING 130
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1f00
+1800
+1800
+1800
+1800
+1800
+1800
+ENDCHAR
+STARTCHAR trcorn
+ENCODING 131
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+f800
+1800
+1800
+1800
+1800
+1800
+1800
+ENDCHAR
+STARTCHAR blcorn
+ENCODING 132
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+1f00
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR brcorn
+ENCODING 133
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+f800
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR crwall
+ENCODING 134
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+ff00
+1800
+1800
+1800
+1800
+1800
+1800
+ENDCHAR
+STARTCHAR tuwall
+ENCODING 135
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+ff00
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR tdwall
+ENCODING 136
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ff00
+1800
+1800
+1800
+1800
+1800
+1800
+ENDCHAR
+STARTCHAR tlwall
+ENCODING 137
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+18
+18
+18
+18
+18
+18
+18
+f8
+18
+18
+18
+18
+18
+18
+ENDCHAR
+STARTCHAR trwall
+ENCODING 138
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+18
+18
+18
+18
+18
+18
+18
+1f
+18
+18
+18
+18
+18
+18
+ENDCHAR
+STARTCHAR ndoor
+ENCODING 139
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+1800
+1800
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR vodoor
+ENCODING 140
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1800
+1800
+1800
+1800
+0000
+0000
+0000
+7e00
+0000
+0000
+0000
+1800
+1800
+1800
+ENDCHAR
+STARTCHAR hodoor
+ENCODING 141
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+1800
+1800
+1800
+1800
+9900
+1800
+1800
+1800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR vcdoor
+ENCODING 142
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+1800
+1800
+1800
+7e00
+7e00
+1800
+1800
+1800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR hcdoor
+ENCODING 143
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+1800
+1800
+1800
+7e00
+7e00
+1800
+1800
+1800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR room
+ENCODING 144
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+1800
+1800
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR dark corr
+ENCODING 145
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1100
+4400
+1100
+4400
+1100
+4400
+1100
+4400
+1100
+4400
+1100
+4400
+1100
+4400
+ENDCHAR
+STARTCHAR lit corr
+ENCODING 146
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+5500
+aa00
+5500
+aa00
+5500
+aa00
+5500
+aa00
+5500
+aa00
+5500
+aa00
+5500
+aa00
+ENDCHAR
+STARTCHAR upstair
+ENCODING 147
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0c00
+1800
+3000
+6000
+c000
+6000
+3000
+1800
+0c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR dnstair
+ENCODING 148
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+6000
+3000
+1800
+0c00
+0600
+0c00
+1800
+3000
+6000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR trap
+ENCODING 149
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+1000
+3800
+6c00
+c600
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR web
+ENCODING 150
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0100
+0f00
+3c00
+c600
+c200
+6f00
+3a00
+3200
+7300
+5700
+8c00
+db00
+7f00
+2500
+ENDCHAR
+STARTCHAR pool
+ENCODING 151
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+7700
+0000
+ee00
+bb00
+0000
+7700
+dd00
+0000
+bb00
+ee00
+0000
+dd00
+7700
+0000
+ENDCHAR
+STARTCHAR fountain
+ENCODING 152
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1400
+0000
+3400
+4a00
+4900
+8a00
+2800
+0200
+5900
+1800
+3c00
+3c00
+ff00
+ff00
+ENDCHAR
+STARTCHAR sink
+ENCODING 153
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+2400
+2400
+7e00
+2400
+2400
+7e00
+2400
+2400
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR throne
+ENCODING 154
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0400
+0400
+0400
+0400
+3c00
+1400
+3c00
+2400
+2400
+ff00
+ff00
+ENDCHAR
+STARTCHAR upladder
+ENCODING 155
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0c00
+1800
+3000
+6000
+c000
+6000
+3000
+1800
+0c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR dnladder
+ENCODING 156
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+6000
+3000
+1800
+0c00
+0600
+0c00
+1800
+3000
+6000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR dbvwall
+ENCODING 157
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1800
+3c00
+7e00
+7e00
+3c00
+3c00
+3c00
+3c00
+3c00
+3c00
+7e00
+7e00
+3c00
+1800
+ENDCHAR
+STARTCHAR dbhwall
+ENCODING 158
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+2400
+7e00
+ff00
+7e00
+2400
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ice
+ENCODING 159
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+2400
+1800
+1800
+2400
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR lava
+ENCODING 160
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0200
+4000
+2000
+2000
+0400
+1000
+9500
+5500
+5500
+5e00
+ff00
+ff00
+ENDCHAR
+STARTCHAR vbeam
+ENCODING 161
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1000
+1c00
+0800
+1000
+2000
+4000
+3000
+1800
+0400
+0800
+1000
+2000
+7000
+1000
+ENDCHAR
+STARTCHAR hbeam
+ENCODING 162
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+4000
+6000
+d100
+0a00
+0400
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR lslant
+ENCODING 163
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+8000
+6000
+2000
+2000
+2000
+1000
+1000
+0800
+0c00
+0200
+0200
+0200
+0200
+0100
+ENDCHAR
+STARTCHAR rslant
+ENCODING 164
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0100
+0100
+0200
+0200
+0400
+0400
+0400
+1800
+2000
+2000
+4000
+4000
+4000
+8000
+ENDCHAR
+STARTCHAR dig beam
+ENCODING 165
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+5500
+0a00
+1400
+2800
+5000
+a000
+4100
+8200
+0500
+0a00
+1400
+2800
+5000
+aa00
+ENDCHAR
+STARTCHAR camera flash
+ENCODING 166
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+c800
+4b00
+0200
+2000
+0400
+d800
+1b00
+2000
+4400
+5200
+0a00
+0000
+ENDCHAR
+STARTCHAR boom open left
+ENCODING 167
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+2000
+1000
+0800
+0400
+0200
+0400
+0800
+1000
+2000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR boom open right
+ENCODING 168
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0200
+0400
+0800
+1000
+2000
+1000
+0800
+0400
+0200
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR magic shield 1
+ENCODING 169
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+5000
+1200
+4200
+0800
+1000
+3a00
+1000
+4400
+5000
+2c00
+0400
+2800
+ENDCHAR
+STARTCHAR magic shield 2
+ENCODING 170
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+3600
+a800
+5a00
+da00
+8400
+f400
+d500
+3a00
+d700
+a500
+fd00
+6f00
+3800
+3600
+ENDCHAR
+STARTCHAR magic sheild 3
+ENCODING 171
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+1c00
+4300
+0000
+0800
+2200
+0000
+4000
+0800
+0200
+9a00
+cc00
+2200
+0000
+ENDCHAR
+STARTCHAR magic shield 4
+ENCODING 172
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+6000
+1000
+6c00
+5200
+4000
+1b00
+4600
+6b00
+cd00
+a200
+a800
+5600
+3400
+0000
+ENDCHAR
+STARTCHAR sw top left
+ENCODING 173
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0300
+0400
+0400
+0800
+0800
+1000
+1000
+ENDCHAR
+STARTCHAR sw top center
+ENCODING 174
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+3c00
+c300
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR sw top right
+ENCODING 175
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+c000
+2000
+2000
+1000
+1000
+0800
+0800
+ENDCHAR
+STARTCHAR sw middle left
+ENCODING 176
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1000
+1000
+2000
+2000
+2000
+2000
+2000
+4000
+2000
+2000
+2000
+2000
+1000
+1000
+ENDCHAR
+STARTCHAR sw middle right
+ENCODING 177
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0800
+0800
+0400
+0400
+0400
+0400
+0400
+0200
+0400
+0400
+0400
+0400
+0800
+0800
+ENDCHAR
+STARTCHAR sw bottom left
+ENCODING 178
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1000
+1000
+0800
+0800
+0400
+0400
+0300
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR sw bottom center
+ENCODING 179
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+c300
+3c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR sw bottom right
+ENCODING 180
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0800
+0800
+1000
+1000
+2000
+2000
+c000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR explosion1
+ENCODING 181
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0100
+0e00
+3100
+ce00
+3100
+4600
+9800
+6700
+9800
+2300
+4c00
+9300
+2400
+ENDCHAR
+STARTCHAR explosion2
+ENCODING 182
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+ff00
+0000
+ff00
+0000
+ff00
+0000
+fe00
+0100
+fe00
+0100
+fe00
+0100
+7c00
+ENDCHAR
+STARTCHAR explosion3
+ENCODING 183
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+e000
+1800
+e600
+1900
+c400
+3300
+cd00
+3200
+8900
+6400
+9200
+4900
+ENDCHAR
+STARTCHAR explosion4
+ENCODING 184
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+4900
+5600
+a500
+aa00
+4a00
+5500
+5500
+5500
+5500
+5500
+4a00
+aa00
+a500
+5600
+ENDCHAR
+STARTCHAR explosion5
+ENCODING 185
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+8300
+7c00
+8300
+7c00
+8200
+3900
+4500
+5500
+4500
+3900
+8200
+7c00
+8300
+7c00
+ENDCHAR
+STARTCHAR explosion6
+ENCODING 186
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+2500
+d400
+4a00
+aa00
+a500
+5500
+5500
+5500
+5500
+5500
+a500
+aa00
+4a00
+d400
+ENDCHAR
+STARTCHAR explosion7
+ENCODING 187
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+4900
+2400
+9300
+4c00
+2300
+9800
+6700
+b800
+4e00
+3100
+ce00
+3100
+0e00
+0100
+ENDCHAR
+STARTCHAR explosion8
+ENCODING 188
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+8300
+7c00
+0100
+fe00
+0100
+fe00
+0100
+fe00
+0000
+ff00
+0000
+ff00
+0000
+ff00
+ENDCHAR
+STARTCHAR explosion9
+ENCODING 189
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+2500
+4900
+9200
+6400
+8900
+3200
+cc00
+3b00
+e400
+1900
+e600
+1800
+e000
+0000
+ENDCHAR
+STARTCHAR C276
+ENCODING 190
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1800
+1800
+1800
+1800
+1800
+f800
+1800
+f800
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C203
+ENCODING 191
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+3000
+7800
+cc00
+0000
+7800
+0c00
+7c00
+cc00
+dc00
+7600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C204
+ENCODING 192
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+cc00
+cc00
+0000
+7800
+0c00
+7c00
+cc00
+dc00
+7600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C207
+ENCODING 193
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+7c00
+c600
+c000
+c000
+c600
+7c00
+1800
+6c00
+3800
+0000
+ENDCHAR
+STARTCHAR C210
+ENCODING 194
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+3000
+7800
+cc00
+0000
+7c00
+c600
+fe00
+c000
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C303
+ENCODING 195
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+1f00
+1800
+1800
+1800
+1800
+1800
+1800
+ENDCHAR
+STARTCHAR C201
+ENCODING 196
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+c600
+c600
+0000
+c600
+c600
+c600
+c600
+ce00
+7600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C206
+ENCODING 197
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+3800
+6c00
+3800
+0000
+7800
+0c00
+7c00
+cc00
+dc00
+7600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C200
+ENCODING 198
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3c00
+6600
+c000
+c000
+c000
+c600
+6600
+3c00
+1800
+cc00
+3800
+0000
+ENDCHAR
+STARTCHAR C264
+ENCODING 199
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+f800
+1800
+1800
+1800
+1800
+1800
+1800
+ENDCHAR
+STARTCHAR C333
+ENCODING 200
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+ff00
+ff00
+ff00
+ff00
+ff00
+ff00
+ff00
+ff00
+ff00
+ff00
+ff00
+ff00
+ff00
+ff00
+ENDCHAR
+STARTCHAR C334
+ENCODING 201
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ff00
+ff00
+ff00
+ff00
+ff00
+ff00
+ff00
+ENDCHAR
+STARTCHAR C335
+ENCODING 202
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+f000
+f000
+f000
+f000
+f000
+f000
+f000
+f000
+f000
+f000
+f000
+f000
+f000
+f000
+ENDCHAR
+STARTCHAR C336
+ENCODING 203
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0f00
+0f00
+0f00
+0f00
+0f00
+0f00
+0f00
+0f00
+0f00
+0f00
+0f00
+0f00
+0f00
+0f00
+ENDCHAR
+STARTCHAR C337
+ENCODING 204
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+ff00
+ff00
+ff00
+ff00
+ff00
+ff00
+ff00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C272
+ENCODING 205
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+3600
+3600
+3600
+3600
+3600
+3600
+3600
+3600
+3600
+3600
+3600
+3600
+3600
+3600
+ENDCHAR
+STARTCHAR C273
+ENCODING 206
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+fe00
+0600
+f600
+3600
+3600
+3600
+3600
+3600
+3600
+ENDCHAR
+STARTCHAR C236
+ENCODING 207
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+fc00
+c600
+fc00
+c000
+cc00
+de00
+cc00
+cc00
+cc00
+c600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR amulet
+ENCODING 208
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+3c00
+4200
+4200
+4200
+2200
+2200
+1c00
+3e00
+3e00
+3e00
+1c00
+0000
+0000
+ENDCHAR
+STARTCHAR food
+ENCODING 209
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+7c00
+7c00
+3800
+1000
+1000
+1000
+7c00
+0000
+ENDCHAR
+STARTCHAR weapon
+ENCODING 210
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+2000
+3000
+2800
+2800
+2800
+2800
+2800
+2800
+3800
+fe00
+3000
+3000
+3000
+3000
+ENDCHAR
+STARTCHAR tool
+ENCODING 211
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+3c00
+4200
+4200
+7e00
+7e00
+7e00
+7e00
+0000
+0000
+ENDCHAR
+STARTCHAR ball
+ENCODING 212
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1c00
+3e00
+3e00
+7e00
+ad00
+7600
+ENDCHAR
+STARTCHAR chain
+ENCODING 213
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+6600
+9900
+6600
+ENDCHAR
+STARTCHAR rock
+ENCODING 214
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+3c00
+6600
+5200
+8500
+d200
+a900
+a000
+4500
+9300
+bf00
+6a00
+fe00
+7f00
+ENDCHAR
+STARTCHAR armor
+ENCODING 215
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+7c00
+6c00
+5400
+6c00
+5400
+2800
+1000
+0000
+0000
+ENDCHAR
+STARTCHAR potion
+ENCODING 216
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3c00
+1800
+1800
+1800
+1800
+3c00
+6e00
+7a00
+5e00
+7600
+3c00
+0000
+ENDCHAR
+STARTCHAR scroll
+ENCODING 217
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7e00
+ff00
+7e00
+2a00
+5400
+2a00
+5400
+2a00
+7e00
+ff00
+7e00
+0000
+ENDCHAR
+STARTCHAR wand
+ENCODING 218
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+2200
+2400
+1500
+0200
+0800
+0800
+1000
+1000
+1000
+2000
+2000
+2000
+4000
+0000
+ENDCHAR
+STARTCHAR ring
+ENCODING 219
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+4200
+2400
+8300
+3800
+4500
+4400
+4400
+3900
+8200
+2900
+4800
+0000
+0000
+ENDCHAR
+STARTCHAR gem
+ENCODING 220
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+7c00
+c600
+4400
+3800
+1000
+0000
+ENDCHAR
+STARTCHAR gold
+ENCODING 221
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+5400
+5400
+a500
+a900
+8a00
+0000
+6000
+be00
+fb00
+df00
+3800
+ENDCHAR
+STARTCHAR venom
+ENCODING 222
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+1800
+2400
+4400
+5800
+2000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR spbook
+ENCODING 223
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+7c00
+4600
+6600
+4600
+4600
+4600
+6600
+4600
+7e00
+7e00
+0000
+ENDCHAR
+STARTCHAR C262
+ENCODING 224
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+dd00
+7700
+dd00
+7700
+dd00
+7700
+dd00
+7700
+dd00
+7700
+dd00
+7700
+dd00
+7700
+ENDCHAR
+STARTCHAR C341
+ENCODING 225
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+7800
+cc00
+d800
+fc00
+c600
+e600
+dc00
+c000
+c000
+0000
+ENDCHAR
+STARTCHAR C342
+ENCODING 226
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+fe00
+6600
+6200
+6000
+6000
+6000
+6000
+6000
+6000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C343
+ENCODING 227
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+fe00
+6c00
+6c00
+6c00
+6c00
+6c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C344
+ENCODING 228
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+fe00
+c600
+6200
+3000
+1800
+3000
+6200
+c600
+fe00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C345
+ENCODING 229
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+7e00
+d800
+cc00
+cc00
+cc00
+7800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C346
+ENCODING 230
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+6600
+6600
+6600
+6600
+7c00
+6000
+c000
+8000
+0000
+0000
+ENDCHAR
+STARTCHAR C347
+ENCODING 231
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+7600
+dc00
+1800
+1800
+1800
+1800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C350
+ENCODING 232
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+fe00
+3800
+6c00
+c600
+c600
+c600
+6c00
+3800
+fe00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C351
+ENCODING 233
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3800
+6c00
+c600
+c600
+fe00
+c600
+c600
+6c00
+3800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C352
+ENCODING 234
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3800
+6c00
+c600
+c600
+c600
+6c00
+6c00
+6c00
+ee00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C353
+ENCODING 235
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3e00
+6000
+3000
+3c00
+6600
+c600
+c600
+cc00
+7800
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C354
+ENCODING 236
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+7e00
+db00
+db00
+7e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C355
+ENCODING 237
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0600
+0c00
+7c00
+de00
+f600
+e600
+7c00
+6000
+c000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C356
+ENCODING 238
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+1c00
+3000
+6000
+6000
+7c00
+6000
+6000
+3000
+1c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C357
+ENCODING 239
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7c00
+c600
+c600
+c600
+c600
+c600
+c600
+c600
+c600
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C360
+ENCODING 240
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+fe00
+0000
+fe00
+0000
+fe00
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C361
+ENCODING 241
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+1800
+1800
+7e00
+1800
+1800
+0000
+7e00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C362
+ENCODING 242
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+3000
+1800
+0c00
+0600
+0c00
+1800
+3000
+0000
+7e00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C363
+ENCODING 243
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0c00
+1800
+3000
+6000
+3000
+1800
+0c00
+0000
+7e00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C364
+ENCODING 244
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0c00
+1e00
+1a00
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+ENDCHAR
+STARTCHAR C365
+ENCODING 245
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+1800
+5800
+7800
+3000
+0000
+0000
+ENDCHAR
+STARTCHAR C366
+ENCODING 246
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+1800
+1800
+0000
+7e00
+0000
+1800
+1800
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C225
+ENCODING 247
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+3000
+1800
+0c00
+0000
+7c00
+c600
+c600
+c600
+c600
+7c00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C370
+ENCODING 248
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+7800
+cc00
+cc00
+7800
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C371
+ENCODING 249
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+1800
+1800
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C372
+ENCODING 250
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1800
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C373
+ENCODING 251
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+1f00
+1800
+1800
+1800
+1800
+d800
+7800
+3800
+1800
+0000
+0000
+ENDCHAR
+STARTCHAR C374
+ENCODING 252
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+d800
+6c00
+6c00
+6c00
+6c00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C375
+ENCODING 253
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+7000
+d800
+3000
+6000
+f800
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C376
+ENCODING 254
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+7e00
+7e00
+7e00
+7e00
+7e00
+7e00
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C377
+ENCODING 255
+SWIDTH 666 0
+DWIDTH 8 0
+BBX 8 14 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+ENDFONT
diff --git a/win/X11/nethack.rc b/win/X11/nethack.rc
new file mode 100644 (file)
index 0000000..529ed40
--- /dev/null
@@ -0,0 +1,79 @@
+#
+# Nethack configuration file.
+#
+# Naming this file $(HOME)/.nethackrc (for UNIX) or setting the environment
+# variable NETHACKOPTIONS to point to its full path name elsewhere tells
+# NetHack to use X11 windowing and fonts (provided the executable was
+# compiled with that ability).
+#
+#
+OPTIONS=windowtype:x11,toptenwin,hilite_pet
+OPTIONS=confirm,male,fixinv,noautopickup,safe_pet,sortpack,tombstone
+OPTIONS=verbose,news,fruit:pineapple
+OPTIONS=dogname:Dhairrhuwyth
+OPTIONS=catname:Ghisteslwchlohm
+#
+# There are 17 object symbols and various graphics symbols.
+# The descriptions of these symbols can be found in dat/opthelp.
+#
+#
+# Font: nh10 (10x20)
+#
+OBJECTS= 180 183 188 192 181 184 182 189 190 196 \
+        191 194 193 187 185 186 195
+#
+DUNGEON= 032 025 018 013 012 014 011 015 023 024 \
+        022 021 128 129 130 131 132 035 035 133 \
+        134 135 136 137 145 146 144 124 143 142 \
+        141 140 149 150 031 031 147 148 031 161 \
+        140
+#
+TRAPS=  138 138 138 138 138 138 138 138 138 138 \
+        138 138 138 138 138 139 138 138 138 138 \
+        138 138
+#
+EFFECTS= 151 152 153 154 155 156 157 158        \
+        159 160 161 162                         \
+        163 164 165 166 167 168 169 170         \
+        171 172 173 174 175 176 177 178 179
+#
+#
+# Font: ibm (8x14)
+#
+#OBJECTS= 207 210 215 219 208 211 209 216 217 223 \
+#       218 221 220 214 212 213 222
+#
+#DUNGEON= 032 128 129 130 131 132 133 134 135 136 \
+#        137 138 139 045 124 142 143 035 035 144 \
+#        145 146 147 148 155 156 227 124 154 153 \
+#        152 151 159 160 200 200 157 158 250 170 \
+#        151
+#
+#TRAPS=   149 149 149 149 149 149 149 149 149 149 \
+#        149 149 149 149 149 150 149 149 149 149 \
+#        149 149
+#
+#EFFECTS= 161 162 163 164 165 166 167 168        \
+#        169 170 171 172                         \
+#        173 174 175 176 177 178 179 180         \
+#        181 182 183 184 185 186 187 188 189
+#
+#
+# Font: a "standard" font like 6x13
+# Note that this version is unlikely to work on a tty on a Unix system because
+# many of these characters are also control characters.
+#
+#DUNGEON = 032 025 018 013 012 014 011 015 023 024 \
+#         022 021 031 045 124 043 043 035 035 031 \
+#         035 001 060 062 060 062 019 124 092 035 \
+#         123 125 031 125 046 046 035 035 046 127 \
+#         125
+#
+#TRAPS=    094 094 094 094 094 094 094 094 094 094 \
+#         094 094 094 094 094 002 094 094 094 094 \
+#         094 094
+#
+#EFFECTS=  124 045 092 047 042 033 041 040        \
+#         048 035 064 042                         \
+#         047 045 092 124 124 092 045 047         \
+#         047 064 092 064 064 064 092 064 047
diff --git a/win/X11/nh10.bdf b/win/X11/nh10.bdf
new file mode 100644 (file)
index 0000000..200ff99
--- /dev/null
@@ -0,0 +1,6940 @@
+STARTFONT 2.1
+COMMENT  Nethack 10x20 font.  Based on the font 10x20.
+FONT nh10
+SIZE 20 75 75
+FONTBOUNDINGBOX 10 20 0 -5
+STARTPROPERTIES 19
+FONTNAME_REGISTRY ""
+FOUNDRY "Misc"
+FAMILY_NAME "Fixed"
+WEIGHT_NAME "Medium"
+SLANT "R"
+SETWIDTH_NAME "Normal"
+ADD_STYLE_NAME "NetHack"
+PIXEL_SIZE 20
+POINT_SIZE 200
+RESOLUTION_X 75
+RESOLUTION_Y 75
+SPACING "C"
+AVERAGE_WIDTH 100
+CHARSET_REGISTRY "ISO8859"
+CHARSET_ENCODING "1"
+DEFAULT_CHAR 0
+FONT_DESCENT 5
+FONT_ASCENT 15
+COPYRIGHT "Copyright 1989-1991 Network Computing Devices, Inc."
+ENDPROPERTIES
+CHARS 256
+STARTCHAR C000
+ENCODING 0
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C001
+ENCODING 1
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0c00
+1e00
+3f00
+7f80
+7f80
+3f00
+1e00
+0c00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C002
+ENCODING 2
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+ENDCHAR
+STARTCHAR C003
+ENCODING 3
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+6600
+6600
+6600
+7e00
+6600
+6600
+6600
+0000
+1f80
+0600
+0600
+0600
+0600
+0600
+0000
+0000
+ENDCHAR
+STARTCHAR C004
+ENCODING 4
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+7c00
+6000
+6000
+7800
+6000
+6000
+6000
+0f80
+0c00
+0c00
+0f00
+0c00
+0c00
+0c00
+0000
+0000
+ENDCHAR
+STARTCHAR C005
+ENCODING 5
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+3c00
+6600
+6000
+6000
+6600
+3c00
+0000
+1f00
+1980
+1980
+1f00
+1e00
+1b00
+1980
+0000
+0000
+ENDCHAR
+STARTCHAR C006
+ENCODING 6
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+3000
+3000
+3000
+3000
+3000
+3e00
+0000
+0f80
+0c00
+0c00
+0f00
+0c00
+0c00
+0c00
+0000
+0000
+ENDCHAR
+STARTCHAR C007
+ENCODING 7
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+3300
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C010
+ENCODING 8
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0c00
+0c00
+7f80
+0c00
+0c00
+0000
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C011
+ENCODING 9
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+6600
+7600
+7e00
+7e00
+6e00
+6600
+0000
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0f80
+0000
+0000
+ENDCHAR
+STARTCHAR C012
+ENCODING 10
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+6600
+6600
+6600
+3c00
+3c00
+1800
+1800
+0000
+1f80
+0600
+0600
+0600
+0600
+0600
+0000
+0000
+ENDCHAR
+STARTCHAR C013
+ENCODING 11
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+fc00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C014
+ENCODING 12
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+fc00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+ENDCHAR
+STARTCHAR C015
+ENCODING 13
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0fc0
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+ENDCHAR
+STARTCHAR C016
+ENCODING 14
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0fc0
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C017
+ENCODING 15
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+ffc0
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+ENDCHAR
+STARTCHAR C020
+ENCODING 16
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+ffc0
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C021
+ENCODING 17
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+ffc0
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C022
+ENCODING 18
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ffc0
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C023
+ENCODING 19
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ffc0
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C024
+ENCODING 20
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ffc0
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C025
+ENCODING 21
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0fc0
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+ENDCHAR
+STARTCHAR C026
+ENCODING 22
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+fc00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+ENDCHAR
+STARTCHAR C027
+ENCODING 23
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+ffc0
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C030
+ENCODING 24
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ffc0
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+ENDCHAR
+STARTCHAR C031
+ENCODING 25
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+ENDCHAR
+STARTCHAR C032
+ENCODING 26
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+01c0
+0700
+1c00
+7000
+1c00
+0700
+01c0
+0000
+0000
+7fc0
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C033
+ENCODING 27
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+7000
+1c00
+0700
+01c0
+0700
+1c00
+7000
+0000
+0000
+7fc0
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C034
+ENCODING 28
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0080
+3f80
+5b00
+1b00
+1b00
+1b00
+1b00
+3300
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C035
+ENCODING 29
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0180
+0300
+7fc0
+0600
+0c00
+7fc0
+1800
+3000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C036
+ENCODING 30
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0f00
+1980
+1980
+1800
+1800
+1800
+7e00
+1800
+1800
+1800
+7c00
+56c0
+7380
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C037
+ENCODING 31
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0c00
+0c00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR space
+ENCODING 32
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR !
+ENCODING 33
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0000
+0c00
+0c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR "
+ENCODING 34
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3300
+3300
+3300
+1200
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR #
+ENCODING 35
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0d80
+0d80
+0d80
+3fc0
+1b00
+1b00
+1b00
+7f80
+3600
+3600
+3600
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR $
+ENCODING 36
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+3f00
+6d80
+6c00
+6c00
+6c00
+3f00
+0d80
+0d80
+0d80
+6d80
+3f00
+0c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR %
+ENCODING 37
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+3980
+6d80
+6f00
+3b00
+0600
+0600
+0c00
+0c00
+1b80
+1ec0
+36c0
+3380
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR &
+ENCODING 38
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1c00
+3600
+3600
+3600
+3c00
+1800
+3800
+6c00
+66c0
+6380
+6300
+7780
+3cc0
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR '
+ENCODING 39
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0f00
+0e00
+1800
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR (
+ENCODING 40
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0300
+0600
+0c00
+0c00
+1800
+1800
+1800
+1800
+1800
+0c00
+0c00
+0600
+0300
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR )
+ENCODING 41
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3000
+1800
+0c00
+0c00
+0600
+0600
+0600
+0600
+0600
+0c00
+0c00
+1800
+3000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR *
+ENCODING 42
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+3300
+3300
+1e00
+7f80
+1e00
+3300
+3300
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR +
+ENCODING 43
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0c00
+0c00
+0c00
+7f80
+0c00
+0c00
+0c00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ,
+ENCODING 44
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0e00
+0e00
+1800
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR -
+ENCODING 45
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+7f80
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR .
+ENCODING 46
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0e00
+0e00
+0e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR /
+ENCODING 47
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0180
+0180
+0300
+0300
+0600
+0600
+0c00
+0c00
+1800
+1800
+3000
+3000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 0
+ENCODING 48
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1e00
+3300
+3300
+6180
+6180
+6180
+6180
+6180
+3300
+3300
+1e00
+0c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 1
+ENCODING 49
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1c00
+3c00
+6c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 2
+ENCODING 50
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+6180
+6180
+0180
+0180
+0300
+0e00
+1800
+3000
+6000
+6000
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 3
+ENCODING 51
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+6180
+6180
+0180
+0300
+0e00
+0300
+0180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 4
+ENCODING 52
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0100
+0300
+0700
+0f00
+1b00
+3300
+6300
+6300
+7f80
+0300
+0300
+0300
+0300
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 5
+ENCODING 53
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+7f80
+6000
+6000
+6000
+6000
+6e00
+7300
+0180
+0180
+0180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 6
+ENCODING 54
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+6100
+6000
+6000
+6e00
+7300
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 7
+ENCODING 55
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+7f80
+0180
+0180
+0300
+0300
+0600
+0600
+0c00
+0c00
+1800
+1800
+3000
+3000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 8
+ENCODING 56
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+6180
+6180
+6180
+3300
+1e00
+3300
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR 9
+ENCODING 57
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+3380
+1d80
+0180
+0180
+2180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR :
+ENCODING 58
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0e00
+0e00
+0000
+0000
+0000
+0000
+0e00
+0e00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ;
+ENCODING 59
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0e00
+0e00
+0000
+0000
+0000
+0000
+0e00
+0e00
+1c00
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR <
+ENCODING 60
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0100
+0300
+0600
+0c00
+1800
+3000
+6000
+3000
+1800
+0c00
+0600
+0300
+0100
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR =
+ENCODING 61
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+7f80
+0000
+0000
+0000
+0000
+7f80
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR >
+ENCODING 62
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+2000
+3000
+1800
+0c00
+0600
+0300
+0180
+0300
+0600
+0c00
+1800
+3000
+2000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ?
+ENCODING 63
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+6180
+6180
+6180
+0300
+0600
+0c00
+0c00
+0c00
+0000
+0c00
+0c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR @
+ENCODING 64
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+6180
+6780
+6f80
+6d80
+6d80
+6d80
+6f00
+6600
+6000
+3180
+1f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR A
+ENCODING 65
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1e00
+3300
+3300
+6180
+6180
+6180
+7f80
+6180
+6180
+6180
+6180
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR B
+ENCODING 66
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+7c00
+6600
+6300
+6300
+6300
+6600
+7e00
+6300
+6180
+6180
+6180
+6300
+7e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C
+ENCODING 67
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+6180
+6000
+6000
+6000
+6000
+6000
+6000
+6000
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR D
+ENCODING 68
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+7e00
+6300
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+6300
+7e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR E
+ENCODING 69
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+7f80
+6000
+6000
+6000
+6000
+6000
+7e00
+6000
+6000
+6000
+6000
+6000
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR F
+ENCODING 70
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+7f80
+6000
+6000
+6000
+6000
+6000
+7e00
+6000
+6000
+6000
+6000
+6000
+6000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR G
+ENCODING 71
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+6180
+6000
+6000
+6000
+6780
+6180
+6180
+6180
+6180
+3380
+1e80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR H
+ENCODING 72
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+6180
+6180
+6180
+6180
+6180
+6180
+7f80
+6180
+6180
+6180
+6180
+6180
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR I
+ENCODING 73
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+7f80
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR J
+ENCODING 74
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0f80
+0180
+0180
+0180
+0180
+0180
+0180
+0180
+0180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR K
+ENCODING 75
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+6180
+6180
+6300
+6300
+6600
+6600
+7c00
+6600
+6600
+6300
+6300
+6180
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR L
+ENCODING 76
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+6000
+6000
+6000
+6000
+6000
+6000
+6000
+6000
+6000
+6000
+6000
+6000
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR M
+ENCODING 77
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+6180
+6180
+7380
+7380
+7f80
+6d80
+6d80
+6d80
+6d80
+6180
+6180
+6180
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR N
+ENCODING 78
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+6180
+7180
+7180
+7980
+7980
+6d80
+6d80
+6780
+6780
+6380
+6380
+6180
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR O
+ENCODING 79
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR P
+ENCODING 80
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+7e00
+6300
+6180
+6180
+6180
+6180
+6300
+7e00
+6000
+6000
+6000
+6000
+6000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Q
+ENCODING 81
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+6d80
+6780
+3300
+1f00
+0180
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR R
+ENCODING 82
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+7e00
+6300
+6180
+6180
+6180
+6180
+6300
+7e00
+6600
+6300
+6300
+6180
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR S
+ENCODING 83
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+6180
+6000
+6000
+3000
+1e00
+0300
+0180
+0180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR T
+ENCODING 84
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+7f80
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR U
+ENCODING 85
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR V
+ENCODING 86
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+6180
+6180
+6180
+6180
+3300
+3300
+3300
+1e00
+1e00
+1e00
+0c00
+0c00
+0c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR W
+ENCODING 87
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+6180
+6180
+6180
+6180
+6180
+6d80
+6d80
+6d80
+6d80
+7380
+7380
+6180
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR X
+ENCODING 88
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+6180
+6180
+3300
+3300
+1e00
+1e00
+0c00
+1e00
+1e00
+3300
+3300
+6180
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Y
+ENCODING 89
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+6180
+6180
+3300
+3300
+1e00
+1e00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Z
+ENCODING 90
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+7f80
+0180
+0180
+0300
+0600
+0600
+0c00
+1800
+1800
+3000
+6000
+6000
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR [
+ENCODING 91
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3f00
+3000
+3000
+3000
+3000
+3000
+3000
+3000
+3000
+3000
+3000
+3000
+3f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR \
+ENCODING 92
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+3000
+3000
+1800
+1800
+0c00
+0c00
+0600
+0600
+0300
+0300
+0180
+0180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ]
+ENCODING 93
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3f00
+0300
+0300
+0300
+0300
+0300
+0300
+0300
+0300
+0300
+0300
+0300
+3f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ^
+ENCODING 94
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1e00
+3300
+6180
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR _
+ENCODING 95
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+7fc0
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR `
+ENCODING 96
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3c00
+1c00
+0600
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR a
+ENCODING 97
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1f00
+3180
+0180
+3f80
+6180
+6180
+6180
+3e80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR b
+ENCODING 98
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+6000
+6000
+6000
+6000
+6000
+6e00
+7300
+6180
+6180
+6180
+6180
+7300
+6e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR c
+ENCODING 99
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1f00
+3180
+6000
+6000
+6000
+6000
+3180
+1f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR d
+ENCODING 100
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0180
+0180
+0180
+0180
+0180
+1d80
+3380
+6180
+6180
+6180
+6180
+3380
+1d80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR e
+ENCODING 101
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1e00
+3300
+6180
+7f80
+6000
+6000
+3180
+1f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR f
+ENCODING 102
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0f00
+1980
+1980
+1800
+1800
+1800
+1800
+7e00
+1800
+1800
+1800
+1800
+1800
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR g
+ENCODING 103
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+3e80
+6380
+6300
+6300
+6300
+3e00
+6000
+3f00
+6180
+6180
+6180
+3f00
+0000
+ENDCHAR
+STARTCHAR h
+ENCODING 104
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+6000
+6000
+6000
+6000
+6000
+6e00
+7300
+6180
+6180
+6180
+6180
+6180
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR i
+ENCODING 105
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0c00
+0c00
+0000
+3c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR j
+ENCODING 106
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0180
+0180
+0000
+0780
+0180
+0180
+0180
+0180
+0180
+0180
+0180
+3180
+3180
+3180
+1f00
+0000
+ENDCHAR
+STARTCHAR k
+ENCODING 107
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+6000
+6000
+6000
+6000
+6000
+6300
+6600
+6c00
+7800
+7c00
+6600
+6300
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR l
+ENCODING 108
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR m
+ENCODING 109
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+5b00
+7f80
+6d80
+6d80
+6d80
+6d80
+6d80
+6d80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR n
+ENCODING 110
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+6e00
+7300
+6180
+6180
+6180
+6180
+6180
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR o
+ENCODING 111
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR p
+ENCODING 112
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+6e00
+7300
+6180
+6180
+6180
+6180
+7300
+6e00
+6000
+6000
+6000
+6000
+0000
+ENDCHAR
+STARTCHAR q
+ENCODING 113
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1d80
+3380
+6180
+6180
+6180
+6180
+3380
+1d80
+0180
+0180
+0180
+0180
+0000
+ENDCHAR
+STARTCHAR r
+ENCODING 114
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+6f00
+3980
+3000
+3000
+3000
+3000
+3000
+3000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR s
+ENCODING 115
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+3f00
+6180
+6000
+3f00
+0180
+0180
+6180
+3f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR t
+ENCODING 116
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+1800
+1800
+1800
+7e00
+1800
+1800
+1800
+1800
+1800
+1980
+0f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR u
+ENCODING 117
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+6180
+6180
+6180
+6180
+6180
+6180
+3380
+1d80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR v
+ENCODING 118
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+6180
+6180
+3300
+3300
+1e00
+1e00
+0c00
+0c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR w
+ENCODING 119
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+6180
+6180
+6180
+6d80
+6d80
+6d80
+7f80
+3300
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR x
+ENCODING 120
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+6180
+3300
+1e00
+0c00
+0c00
+1e00
+3300
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR y
+ENCODING 121
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+6180
+6180
+6180
+6180
+6180
+6180
+3380
+1d80
+0180
+6180
+3300
+1e00
+0000
+ENDCHAR
+STARTCHAR z
+ENCODING 122
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+3f80
+0180
+0300
+0600
+0c00
+1800
+3000
+3f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR {
+ENCODING 123
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0780
+0c00
+0c00
+0c00
+0c00
+0c00
+7800
+0c00
+0c00
+0c00
+0c00
+0c00
+0780
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR bar
+ENCODING 124
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR }
+ENCODING 125
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+7800
+0c00
+0c00
+0c00
+0c00
+0c00
+0780
+0c00
+0c00
+0c00
+0c00
+0c00
+7800
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ~
+ENCODING 126
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3980
+6d80
+6700
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR C177
+ENCODING 127
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR doorway
+ENCODING 128
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1e00
+1200
+1200
+1e00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR vodoor
+ENCODING 129
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0000
+0000
+0000
+7f80
+7f80
+0000
+0000
+0000
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+ENDCHAR
+STARTCHAR codoor
+ENCODING 130
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0c00
+0c00
+0c00
+8c40
+8c40
+0c00
+0c00
+0c00
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR vcdoor
+ENCODING 131
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+3300
+2100
+2100
+2100
+2100
+2100
+2100
+3300
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+ENDCHAR
+STARTCHAR hcdoor
+ENCODING 132
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+7f80
+4080
+8040
+8040
+4080
+7f80
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR room
+ENCODING 133
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0c00
+0c00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR dark corridor
+ENCODING 134
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+4440
+1100
+4440
+1100
+4440
+1100
+4440
+1100
+4440
+1100
+4440
+1100
+4440
+1100
+4440
+1100
+4440
+1100
+4440
+1100
+ENDCHAR
+STARTCHAR lit corridor
+ENCODING 135
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+5540
+aa80
+ENDCHAR
+STARTCHAR upstair
+ENCODING 136
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0100
+0200
+0400
+0800
+1000
+2000
+1000
+0800
+0400
+0200
+0100
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR dnstair
+ENCODING 137
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+2000
+1000
+0800
+0400
+0200
+0100
+0200
+0400
+0800
+1000
+2000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR trap
+ENCODING 138
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+ffc0
+c0c0
+e1c0
+b340
+9e40
+8c40
+9e40
+b340
+e1c0
+c0c0
+ffc0
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR web
+ENCODING 139
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+4980
+f900
+4f00
+c9c0
+9940
+9300
+f240
+9e40
+9340
+32c0
+a640
+fcc0
+2f80
+2580
+e4c0
+ec80
+7f80
+4bc0
+4940
+c900
+ENDCHAR
+STARTCHAR pool
+ENCODING 140
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+b6c0
+0000
+2480
+db40
+0000
+9240
+6d80
+0000
+4900
+b6c0
+0000
+2480
+db40
+0000
+9240
+6d80
+0000
+4900
+b6c0
+0000
+ENDCHAR
+STARTCHAR fountain
+ENCODING 141
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+1000
+0a00
+4200
+0c00
+3000
+0280
+6800
+0100
+4800
+2900
+4800
+0900
+9c00
+1400
+ff80
+ff80
+ff80
+ENDCHAR
+STARTCHAR sink
+ENCODING 142
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+2100
+2100
+2100
+2100
+1e00
+1e00
+1200
+ENDCHAR
+STARTCHAR throne
+ENCODING 143
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0100
+0100
+0100
+0100
+0100
+1f00
+0900
+0900
+3f00
+2100
+2100
+ffc0
+ENDCHAR
+STARTCHAR altar
+ENCODING 144
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+7f80
+7f80
+3300
+3300
+3300
+3300
+ENDCHAR
+STARTCHAR up ladder
+ENCODING 145
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+9000
+f000
+9000
+9000
+f000
+9100
+9380
+f540
+9100
+9100
+f100
+9100
+9100
+f000
+9000
+9000
+f000
+9000
+9000
+f000
+ENDCHAR
+STARTCHAR down ladder
+ENCODING 146
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+9000
+f000
+9000
+9000
+f000
+9100
+9100
+f100
+9100
+9100
+f540
+9380
+9100
+f000
+9000
+9000
+f000
+9000
+9000
+f000
+ENDCHAR
+STARTCHAR dbvwall
+ENCODING 147
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0c00
+0c00
+0c00
+0c00
+0c00
+3f00
+3f00
+3f00
+3f00
+3f00
+3f00
+3f00
+3f00
+3f00
+3f00
+0c00
+0c00
+0c00
+0c00
+0c00
+ENDCHAR
+STARTCHAR dbhwall
+ENCODING 148
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+3f00
+3f00
+ffc0
+ffc0
+3f00
+3f00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ice
+ENCODING 149
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1200
+0c00
+0c00
+1200
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR lava
+ENCODING 150
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+8800
+0480
+0080
+3700
+1300
+9900
+0940
+4140
+0840
+2900
+8900
+a840
+4540
+ffc0
+ffc0
+ffc0
+ENDCHAR
+STARTCHAR vbeam
+ENCODING 151
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0800
+0800
+0e00
+0400
+0800
+1000
+2000
+1000
+0800
+0800
+0800
+0800
+0400
+0200
+0400
+0800
+1000
+3000
+0800
+0800
+ENDCHAR
+STARTCHAR hbeam
+ENCODING 152
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+2000
+3000
+e8c0
+0500
+0200
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR lslant
+ENCODING 153
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+8000
+4000
+4000
+4000
+3000
+0800
+0800
+0800
+0800
+0800
+0800
+0400
+0400
+0200
+0200
+0200
+0200
+0200
+0180
+0040
+ENDCHAR
+STARTCHAR rslant
+ENCODING 154
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0040
+0080
+0080
+0080
+0080
+0080
+0300
+0400
+0400
+0400
+0800
+0800
+1000
+2000
+4000
+4000
+4000
+4000
+4000
+8000
+ENDCHAR
+STARTCHAR dig beam
+ENCODING 155
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+8040
+4080
+2100
+1200
+0c00
+0c00
+1200
+2100
+4080
+8040
+8040
+4080
+2100
+1200
+0c00
+0c00
+1200
+2100
+4080
+8040
+ENDCHAR
+STARTCHAR camera flash
+ENCODING 156
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+4200
+0600
+6400
+0100
+0940
+4840
+0400
+2100
+1e00
+5ec0
+1e80
+1e00
+2500
+5440
+2000
+0d80
+2840
+c000
+9280
+0040
+ENDCHAR
+STARTCHAR boomerang left
+ENCODING 157
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+3000
+2800
+1400
+0a00
+0500
+0300
+0500
+0a00
+1400
+2800
+3000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR boomerang right
+ENCODING 158
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0300
+0500
+0a00
+1400
+2800
+3000
+2800
+1400
+0a00
+0500
+0300
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR shield 1
+ENCODING 159
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0200
+76c0
+fa40
+8a00
+4680
+f900
+ea00
+e7c0
+ddc0
+5480
+3100
+b300
+e8c0
+4cc0
+6c00
+6300
+4480
+a180
+1400
+0780
+ENDCHAR
+STARTCHAR shield 2
+ENCODING 160
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+6100
+b340
+0040
+08c0
+77c0
+d240
+b980
+8380
+a100
+2700
+4c40
+31c0
+bf40
+c200
+ca00
+3380
+4180
+1b80
+0780
+ENDCHAR
+STARTCHAR shield 3
+ENCODING 161
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+d000
+0600
+5e80
+4e80
+4c80
+2000
+2800
+3e80
+5f80
+e640
+5080
+47c0
+8380
+c880
+a940
+9840
+0dc0
+1300
+6080
+3200
+ENDCHAR
+STARTCHAR shield 4
+ENCODING 162
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+4200
+d480
+95c0
+1c40
+3c80
+9b80
+2d80
+5280
+5900
+5400
+6500
+0680
+2780
+9c80
+af80
+2180
+6080
+2340
+4580
+3100
+ENDCHAR
+STARTCHAR swallow top left
+ENCODING 163
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+00c0
+0100
+0100
+0100
+0200
+0200
+0200
+0400
+0400
+0400
+ENDCHAR
+STARTCHAR swallow top center
+ENCODING 164
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1e00
+6180
+8040
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR swallow top right
+ENCODING 165
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+c000
+2000
+2000
+2000
+1000
+1000
+1000
+0800
+0800
+0800
+ENDCHAR
+STARTCHAR swallow mid left
+ENCODING 166
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0400
+0400
+0400
+0800
+0800
+0800
+1000
+1000
+1000
+1000
+1000
+1000
+1000
+1000
+0800
+0800
+0800
+0400
+0400
+0400
+ENDCHAR
+STARTCHAR swallow mid right
+ENCODING 167
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0800
+0800
+0800
+0400
+0400
+0400
+0200
+0200
+0200
+0200
+0200
+0200
+0200
+0200
+0400
+0400
+0400
+0800
+0800
+0800
+ENDCHAR
+STARTCHAR swallow bot left
+ENCODING 168
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0400
+0400
+0400
+0200
+0200
+0200
+0100
+0100
+0100
+00c0
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR swallow bot center
+ENCODING 169
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+8040
+6180
+1e00
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR swallow bot right
+ENCODING 170
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0800
+0800
+0800
+1000
+1000
+1000
+2000
+2000
+2000
+c000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR explosion 1
+ENCODING 171
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+01c0
+0e00
+31c0
+ce00
+31c0
+c600
+18c0
+6700
+98c0
+2300
+ccc0
+3300
+4c40
+9380
+2440
+4980
+b640
+2880
+5300
+ENDCHAR
+STARTCHAR explosion 2
+ENCODING 172
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+f780
+ENDCHAR
+STARTCHAR explosion 3
+ENCODING 173
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+c000
+3800
+c600
+3980
+c640
+3180
+8c40
+7300
+8cc0
+6200
+9980
+6640
+1900
+e480
+1240
+c900
+3680
+8a40
+6500
+ENDCHAR
+STARTCHAR explosion 4
+ENCODING 174
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+a4c0
+2900
+4a40
+5480
+a500
+aa40
+aa80
+aa80
+aa80
+5540
+aa80
+aa80
+aa80
+aa40
+a500
+5480
+4a40
+2900
+a4c0
+5300
+ENDCHAR
+STARTCHAR explosion 5
+ENCODING 175
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0840
+f780
+0840
+7700
+8880
+7740
+8880
+b680
+aa80
+5540
+aa80
+b680
+8880
+7740
+8880
+7700
+0840
+f780
+0840
+f780
+ENDCHAR
+STARTCHAR explosion 6
+ENCODING 176
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+9280
+4a40
+2940
+9540
+5280
+2a80
+aa80
+aa80
+aa80
+5540
+aa80
+aa80
+aa80
+2a80
+5280
+9540
+2940
+4a40
+9280
+6500
+ENDCHAR
+STARTCHAR explosion 7
+ENCODING 177
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+2880
+b640
+4980
+2440
+9380
+4c40
+3300
+ccc0
+2300
+98c0
+6700
+18c0
+c600
+31c0
+ce00
+31c0
+0e00
+01c0
+0000
+0000
+ENDCHAR
+STARTCHAR explosion 8
+ENCODING 178
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+f7c0
+0800
+0000
+ENDCHAR
+STARTCHAR explosion 9
+ENCODING 179
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+8a40
+3680
+c900
+1240
+e480
+1900
+6640
+9980
+6200
+8cc0
+7300
+8c40
+3180
+c640
+3980
+c600
+3800
+c000
+0000
+0000
+ENDCHAR
+STARTCHAR illegal object
+ENCODING 180
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+3b80
+4640
+4440
+4c40
+3b80
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR amulet
+ENCODING 181
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+1e00
+2100
+2100
+2100
+1100
+1100
+0e00
+1f00
+1f00
+0e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR food
+ENCODING 182
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+3f00
+3f00
+3f00
+1e00
+0c00
+0c00
+0c00
+3f00
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR weapon
+ENCODING 183
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1000
+1800
+1400
+1200
+1200
+1200
+1200
+1200
+1200
+1200
+7f80
+1c00
+1c00
+1c00
+1c00
+1c00
+0000
+0000
+ENDCHAR
+STARTCHAR tool
+ENCODING 184
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1e00
+2100
+2100
+3f00
+3f00
+3f00
+3f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ball
+ENCODING 185
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0e00
+1f00
+1f00
+1f00
+eac0
+5780
+ENDCHAR
+STARTCHAR chain
+ENCODING 186
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+6d80
+9240
+6d80
+ENDCHAR
+STARTCHAR rock
+ENCODING 187
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1e00
+3100
+2900
+4280
+6900
+5480
+5000
+2280
+4980
+5f80
+3500
+ff40
+bfc0
+ENDCHAR
+STARTCHAR armor
+ENCODING 188
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+2e80
+3f80
+2a80
+3580
+2a80
+3580
+2a80
+1500
+0a00
+0400
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR potion
+ENCODING 189
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+1e00
+0c00
+0c00
+0c00
+0c00
+1e00
+3700
+3d00
+2f00
+3b00
+1e00
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR scroll
+ENCODING 190
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+3f00
+7f80
+3f00
+2a00
+1500
+2a00
+1500
+2a00
+3f00
+7f80
+3f00
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR wand
+ENCODING 191
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1100
+1500
+1240
+0a80
+0100
+0400
+0400
+0800
+0800
+0800
+1000
+1000
+1000
+2000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ring
+ENCODING 192
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+2900
+1200
+4180
+1c00
+2280
+2200
+2200
+1c80
+4100
+1480
+2400
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR gem
+ENCODING 193
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+3e00
+6300
+2200
+1c00
+0800
+0000
+0000
+ENDCHAR
+STARTCHAR gold
+ENCODING 194
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+2a00
+2a00
+5280
+5480
+4500
+0000
+3000
+5f00
+7d80
+6f80
+1c00
+ENDCHAR
+STARTCHAR venom
+ENCODING 195
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0c00
+1200
+2200
+2c00
+1000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR spbook
+ENCODING 196
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+3e00
+2300
+3300
+2300
+2300
+2300
+3300
+2300
+3f00
+3f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Aring
+ENCODING 197
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1200
+1200
+0c00
+0c00
+1e00
+3300
+6180
+6180
+7f80
+6180
+6180
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR AE
+ENCODING 198
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0f80
+1e00
+3600
+3600
+6600
+6600
+7f80
+6600
+6600
+6600
+6600
+6600
+6780
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Ccedilla
+ENCODING 199
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1e00
+3300
+6180
+6000
+6000
+6000
+6000
+6000
+6000
+6000
+6180
+3300
+1e00
+0c00
+0400
+1200
+0c00
+0000
+ENDCHAR
+STARTCHAR Egrave
+ENCODING 200
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3000
+1800
+0c00
+0000
+7f80
+6000
+6000
+6000
+7e00
+6000
+6000
+6000
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Eacute
+ENCODING 201
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0600
+0c00
+1800
+0000
+7f80
+6000
+6000
+6000
+7e00
+6000
+6000
+6000
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Ecircumflex
+ENCODING 202
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1e00
+3300
+0000
+7f80
+6000
+6000
+6000
+7e00
+6000
+6000
+6000
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Edieresis
+ENCODING 203
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3300
+3300
+0000
+0000
+7f80
+6000
+6000
+6000
+7e00
+6000
+6000
+6000
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Igrave
+ENCODING 204
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3000
+1800
+0c00
+0000
+3f00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+3f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Iacute
+ENCODING 205
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0600
+0c00
+1800
+0000
+3f00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+3f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Icircumflex
+ENCODING 206
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1e00
+3300
+0000
+3f00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+3f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Idieresis
+ENCODING 207
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3300
+3300
+0000
+0000
+3f00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+3f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Eth
+ENCODING 208
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+7e00
+6300
+6180
+6180
+6180
+6180
+f980
+6180
+6180
+6180
+6180
+6300
+7e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Ntilde
+ENCODING 209
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1900
+3f00
+2600
+0000
+4180
+6180
+7180
+7980
+7d80
+6f80
+6780
+6380
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Ograve
+ENCODING 210
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3000
+1800
+0c00
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Oacute
+ENCODING 211
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0300
+0600
+0c00
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Ocircumflex
+ENCODING 212
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1e00
+3300
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Otilde
+ENCODING 213
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1900
+3f00
+2600
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Odieresis
+ENCODING 214
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3300
+3300
+0000
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR multiply
+ENCODING 215
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+2080
+3180
+1b00
+0e00
+0e00
+1b00
+3180
+2080
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Oslash
+ENCODING 216
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0080
+1f80
+3300
+6380
+6580
+6580
+6980
+6980
+7180
+3300
+7e00
+4000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Ugrave
+ENCODING 217
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3000
+1800
+0c00
+0000
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Uacute
+ENCODING 218
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0300
+0600
+0c00
+0000
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Ucircumflex
+ENCODING 219
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1e00
+3300
+0000
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+3380
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Udieresis
+ENCODING 220
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3300
+3300
+0000
+0000
+6180
+6180
+6180
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Yacute
+ENCODING 221
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0300
+0600
+0c00
+0000
+4080
+6180
+3300
+1e00
+0c00
+0c00
+0c00
+0c00
+0c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR Thorn
+ENCODING 222
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+3c00
+1800
+1f00
+1980
+1980
+1980
+1f00
+1800
+1800
+1800
+3c00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR germandbls
+ENCODING 223
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+1c00
+3e00
+7300
+6300
+6300
+6600
+6c00
+6600
+6300
+6100
+6300
+6e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR agave
+ENCODING 224
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3000
+1800
+0c00
+0000
+0000
+3f00
+6180
+0180
+3f80
+6180
+6180
+6180
+3e80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR aacute
+ENCODING 225
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0600
+0c00
+1800
+0000
+0000
+3f00
+6180
+0180
+3f80
+6180
+6180
+6180
+3e80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR acircumflex
+ENCODING 226
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1e00
+3300
+0000
+0000
+3f00
+6180
+0180
+3f80
+6180
+6180
+6180
+3e80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR atilde
+ENCODING 227
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1900
+3f00
+2600
+0000
+0000
+3f00
+6180
+0180
+3f80
+6180
+6180
+6180
+3e80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR adieresis
+ENCODING 228
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3300
+3300
+0000
+0000
+0000
+3f00
+6180
+0180
+3f80
+6180
+6180
+6180
+3e80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR aring
+ENCODING 229
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0c00
+1200
+1200
+0c00
+3f00
+6180
+0180
+3f80
+6180
+6180
+6180
+3e80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ae
+ENCODING 230
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+3b00
+4d80
+0d80
+0f00
+3c00
+6c00
+6c80
+3700
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ccedilla
+ENCODING 231
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1f00
+3180
+6000
+6000
+6000
+6000
+3180
+1f00
+0c00
+0400
+1200
+0c00
+0000
+ENDCHAR
+STARTCHAR egrave
+ENCODING 232
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3000
+1800
+0c00
+0000
+0000
+1e00
+3300
+6180
+7f80
+6000
+6000
+3180
+1f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR eacute
+ENCODING 233
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0600
+0c00
+1800
+0000
+0000
+1e00
+3300
+6180
+7f80
+6000
+6000
+3180
+1f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ecircumflex
+ENCODING 234
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1e00
+3300
+0000
+0000
+1e00
+3300
+6180
+7f80
+6000
+6000
+3180
+1f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR edieresis
+ENCODING 235
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3300
+3300
+0000
+0000
+0000
+1e00
+3300
+6180
+7f80
+6000
+6000
+3180
+1f00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR igrave
+ENCODING 236
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3000
+1800
+0c00
+0000
+0000
+3c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR iacute
+ENCODING 237
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0600
+0c00
+1800
+0000
+0000
+3c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR icircumflex
+ENCODING 238
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1e00
+3300
+0000
+0000
+3c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR idieresis
+ENCODING 239
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3300
+3300
+0000
+0000
+0000
+3c00
+0c00
+0c00
+0c00
+0c00
+0c00
+0c00
+7f80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR eth
+ENCODING 240
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+4400
+6c00
+3800
+3800
+6c00
+4600
+1f00
+3380
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ntilde
+ENCODING 241
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1900
+3f00
+2600
+0000
+0000
+6e00
+7300
+6180
+6180
+6180
+6180
+6180
+6180
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ograve
+ENCODING 242
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3000
+1800
+0c00
+0000
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR oacute
+ENCODING 243
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0600
+0c00
+1800
+0000
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ocircumflex
+ENCODING 244
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1e00
+3300
+0000
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR otilde
+ENCODING 245
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+1900
+3f00
+2600
+0000
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR odieresis
+ENCODING 246
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3300
+3300
+0000
+0000
+0000
+1e00
+3300
+6180
+6180
+6180
+6180
+3300
+1e00
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR divide
+ENCODING 247
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0c00
+0c00
+0000
+0000
+7f80
+7f80
+0000
+0000
+0c00
+0c00
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR oslash
+ENCODING 248
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1e80
+3380
+6380
+6780
+6d80
+7980
+3300
+7e00
+4000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ugrave
+ENCODING 249
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3000
+1800
+0c00
+0000
+0000
+6180
+6180
+6180
+6180
+6180
+6180
+3380
+1d80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR uacute
+ENCODING 250
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0600
+0c00
+1800
+0000
+0000
+6180
+6180
+6180
+6180
+6180
+6180
+3380
+1d80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ucircumflex
+ENCODING 251
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0c00
+1e00
+3300
+0000
+0000
+6180
+6180
+6180
+6180
+6180
+6180
+3380
+1d80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR udieresis
+ENCODING 252
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3300
+3300
+0000
+0000
+0000
+6180
+6180
+6180
+6180
+6180
+6180
+3380
+1d80
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR yacute
+ENCODING 253
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0600
+0c00
+1800
+0000
+0000
+0000
+6180
+6180
+6180
+6180
+6180
+3380
+1d80
+0180
+6180
+3300
+1e00
+0000
+ENDCHAR
+STARTCHAR thorn
+ENCODING 254
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+3800
+1e00
+1b00
+1b00
+1e00
+1800
+1800
+3800
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR ydieresis
+ENCODING 255
+SWIDTH 878 0
+DWIDTH 10 0
+BBX 10 20 0 -5
+BITMAP
+0000
+0000
+3300
+3300
+0000
+0000
+0000
+0000
+6180
+6180
+6180
+6180
+6180
+3380
+1d80
+0180
+6180
+3300
+1e00
+0000
+ENDCHAR
+ENDFONT
diff --git a/win/X11/nh32icon b/win/X11/nh32icon
new file mode 100644 (file)
index 0000000..47fd0b9
--- /dev/null
@@ -0,0 +1,20 @@
+/*     SCCS Id: @(#)nh32icon   3.4     2002/02/12                      */
+/*     Copyright (C) 1993,1995 by Robert Patrick Rankin                */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+/*     32x32 X11 icon for NetHack.                                     */
+
+#define nh32icon_width 32
+#define nh32icon_height 32
+static unsigned char nh32icon_bits[] = {
+   0xff, 0x7f, 0xfe, 0xff, 0x01, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x40, 0x82,
+   0x21, 0x25, 0xc0, 0x83, 0x61, 0x25, 0x80, 0x81, 0xe1, 0x3d, 0x80, 0x81,
+   0xa1, 0x25, 0x80, 0x81, 0x21, 0x25, 0x80, 0x81, 0x01, 0x00, 0xe0, 0x87,
+   0x71, 0x48, 0x90, 0x89, 0x81, 0x48, 0x80, 0x81, 0x61, 0x78, 0x80, 0x81,
+   0x81, 0x40, 0x80, 0x81, 0x71, 0x42, 0x84, 0x81, 0x03, 0x00, 0x8a, 0xc1,
+   0x02, 0x00, 0x84, 0x41, 0x32, 0x67, 0x80, 0x41, 0xf3, 0x7f, 0x80, 0xc1,
+   0xf1, 0x7f, 0x84, 0x81, 0x71, 0x77, 0x8a, 0x81, 0xb1, 0x68, 0x84, 0x81,
+   0x71, 0x77, 0x80, 0x81, 0x71, 0x77, 0x80, 0x81, 0xb1, 0x68, 0x84, 0x81,
+   0x71, 0x77, 0x8a, 0x81, 0xf1, 0x7f, 0x84, 0x81, 0xe1, 0x3f, 0x80, 0x81,
+   0xc1, 0x1f, 0x80, 0x81, 0x81, 0x0f, 0x80, 0x81, 0x01, 0x07, 0x00, 0x81,
+   0x01, 0xc0, 0x03, 0x80, 0xff, 0x7f, 0xfe, 0xff};
diff --git a/win/X11/nh56icon b/win/X11/nh56icon
new file mode 100644 (file)
index 0000000..b58a605
--- /dev/null
@@ -0,0 +1,42 @@
+/*     SCCS Id: @(#)nh56icon   3.4     2002/02/12                      */
+/*     Copyright (c) 1993,1995 by M. Stephenson                        */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+/*     56x56 X11 icon for NetHack.                                     */
+
+#define nh56icon_width 56
+#define nh56icon_height 56
+static unsigned char nh56icon_bits[] = {
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x30, 0x38, 0x18, 0x00,
+   0xc0, 0x03, 0x00, 0x78, 0x28, 0x3c, 0x00, 0xc0, 0x03, 0x00, 0xf8, 0x6c,
+   0x3e, 0x00, 0xc0, 0x03, 0x00, 0xf8, 0x55, 0x3f, 0x00, 0xc0, 0x23, 0x22,
+   0xfc, 0xc7, 0x7f, 0x88, 0xc8, 0x43, 0x10, 0xfc, 0xd7, 0x7f, 0x10, 0xc4,
+   0x03, 0x07, 0xfe, 0xc7, 0xff, 0xc0, 0xc1, 0x83, 0x0d, 0xfe, 0xd7, 0xff,
+   0x60, 0xc3, 0xa3, 0x28, 0xfe, 0xc7, 0xff, 0x28, 0xca, 0x83, 0x0d, 0xfe,
+   0xd7, 0xff, 0x60, 0xc3, 0x03, 0x07, 0xfe, 0xc7, 0xff, 0xc0, 0xc1, 0x43,
+   0x10, 0xfc, 0xd7, 0x7f, 0x10, 0xc4, 0x23, 0x22, 0xfc, 0xc7, 0x7f, 0x88,
+   0xc8, 0x03, 0x00, 0xf8, 0x55, 0x3f, 0x00, 0xc0, 0x03, 0x00, 0xf8, 0x44,
+   0x3e, 0x00, 0xc0, 0x03, 0x00, 0x78, 0x54, 0x3c, 0x00, 0xc0, 0x03, 0x00,
+   0x30, 0x6c, 0x18, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x6c, 0x00, 0x00, 0xc0,
+   0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00,
+   0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
+   0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03,
+   0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00,
+   0xc0, 0x43, 0x10, 0x21, 0x38, 0x70, 0x20, 0xc2, 0xc3, 0x10, 0x21, 0x38,
+   0x88, 0x20, 0xc2, 0xc3, 0x10, 0x21, 0x38, 0x80, 0x20, 0xc2, 0x43, 0x11,
+   0x21, 0x38, 0x80, 0x20, 0xc2, 0x43, 0x12, 0x3f, 0x38, 0x70, 0xe0, 0xc3,
+   0x43, 0x12, 0x21, 0x38, 0x80, 0x00, 0xc2, 0x43, 0x14, 0x21, 0x38, 0x80,
+   0x00, 0xc2, 0x43, 0x18, 0x21, 0x38, 0x80, 0x00, 0xc2, 0x43, 0x18, 0x21,
+   0x38, 0x88, 0x0c, 0xc2, 0x43, 0x10, 0x21, 0x38, 0x70, 0x0c, 0xc2, 0x03,
+   0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00,
+   0xc0, 0xfb, 0xff, 0xff, 0x39, 0xff, 0xff, 0xdf, 0x0b, 0x00, 0x80, 0x7c,
+   0x02, 0x00, 0xd0, 0x0b, 0x00, 0x80, 0xee, 0x02, 0x00, 0xd0, 0xfb, 0xff,
+   0xff, 0xd6, 0xfe, 0xff, 0xdf, 0x0b, 0x00, 0x80, 0xaa, 0x02, 0x00, 0xd0,
+   0x0b, 0x00, 0x80, 0x54, 0x02, 0x00, 0xd0, 0xfb, 0xff, 0xff, 0x39, 0xff,
+   0xff, 0xdf, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/win/X11/nh72icon b/win/X11/nh72icon
new file mode 100644 (file)
index 0000000..75dfe84
--- /dev/null
@@ -0,0 +1,63 @@
+/*     SCCS Id: @(#)nh72icon   3.4     1993/01/21                      */
+/*     Copyright (c) 1993 by M. Stephenson                             */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+/*     72x72 X11 icon for NetHack.                                     */
+
+#define nh72icon_width 72
+#define nh72icon_height 72
+static unsigned char nh72icon_bits[] = {
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+   0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00,
+   0x10, 0x00, 0xe0, 0x07, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0xe0,
+   0x07, 0x00, 0x78, 0x00, 0x00, 0x00, 0x1e, 0x00, 0xe0, 0x07, 0x3e, 0xc8,
+   0x07, 0x00, 0xf8, 0x13, 0x7c, 0xe0, 0x07, 0x22, 0x08, 0xfc, 0xc1, 0x0f,
+   0x10, 0x44, 0xe0, 0x07, 0x36, 0x08, 0x00, 0x7f, 0x00, 0x10, 0x6c, 0xe0,
+   0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x14, 0x08,
+   0x00, 0x00, 0x00, 0x10, 0x28, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00,
+   0x10, 0x38, 0xe0, 0x07, 0x14, 0x08, 0x00, 0x00, 0x00, 0x10, 0x28, 0xe0,
+   0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x14, 0x08,
+   0x00, 0x00, 0x00, 0x10, 0x28, 0xe0, 0x87, 0xff, 0x08, 0x10, 0x00, 0x10,
+   0x10, 0xff, 0xe1, 0xc7, 0xff, 0x09, 0x38, 0x10, 0x38, 0x90, 0xff, 0xe3,
+   0x47, 0x1c, 0x09, 0x78, 0x38, 0x3c, 0x90, 0x38, 0xe2, 0x07, 0x1c, 0x08,
+   0xfc, 0x39, 0x7f, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfc, 0xbb, 0x7f,
+   0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0,
+   0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08,
+   0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff,
+   0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0,
+   0x07, 0x1c, 0x08, 0xfc, 0xbb, 0x7f, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08,
+   0xfc, 0x39, 0x7f, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x78, 0x38, 0x3c,
+   0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x38, 0x38, 0x38, 0x10, 0x38, 0xe0,
+   0x07, 0x1c, 0x08, 0x10, 0x38, 0x10, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08,
+   0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00,
+   0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0,
+   0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08,
+   0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00,
+   0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0,
+   0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08,
+   0x00, 0x28, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00,
+   0x10, 0x38, 0xe0, 0x07, 0x08, 0x18, 0x00, 0x28, 0x00, 0x10, 0x10, 0xe0,
+   0x07, 0x08, 0x30, 0x00, 0x38, 0x00, 0x18, 0x10, 0xe0, 0x07, 0x00, 0x60,
+   0x00, 0x28, 0x00, 0x0c, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x00, 0x38, 0x00,
+   0x06, 0x00, 0xe0, 0x07, 0x00, 0x80, 0x01, 0x28, 0x00, 0x03, 0x00, 0xe0,
+   0x07, 0x00, 0x00, 0x03, 0x38, 0x80, 0x01, 0x00, 0xe0, 0x07, 0x00, 0x00,
+   0x06, 0x6c, 0xc0, 0x00, 0x10, 0xe0, 0x07, 0x08, 0x00, 0x0c, 0x44, 0x60,
+   0x00, 0x92, 0xe0, 0x07, 0x49, 0x00, 0x18, 0x7c, 0x30, 0x00, 0x6c, 0xe0,
+   0x07, 0x36, 0x00, 0x30, 0x00, 0x18, 0x00, 0x44, 0xe0, 0x07, 0x22, 0x00,
+   0x60, 0x00, 0x0c, 0x00, 0x83, 0xe1, 0x87, 0xc1, 0x00, 0xc0, 0x00, 0x06,
+   0x00, 0x44, 0xe0, 0x07, 0x22, 0x00, 0x80, 0x01, 0x03, 0x00, 0x6c, 0xe0,
+   0x07, 0x36, 0x00, 0x00, 0x83, 0x01, 0x00, 0x92, 0xe0, 0x07, 0x49, 0x00,
+   0x00, 0xfe, 0x00, 0x00, 0x10, 0xe0, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+   0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/win/X11/nh_icon.xpm b/win/X11/nh_icon.xpm
new file mode 100644 (file)
index 0000000..6e9bbd1
--- /dev/null
@@ -0,0 +1,49 @@
+/* XPM */
+static char * nh_icon[] = {
+"40 40 6 1",
+"      s None c none",
+".     c #ffffff",
+"X     c #dadab6",
+"o     c #6c91b6",
+"O     c #476c6c",
+"+     c #000000",
+"                                        ",
+"                                        ",
+"                                        ",
+"        .      .X..XX.XX      X         ",
+"        ..   .....X.XXXXXX   XX         ",
+"        ... ....X..XX.XXXXX XXX         ",
+"   ..   ..........X.XXXXXXXXXXX   XX    ",
+"   .... ........X..XX.XXXXXXXXX XXXX    ",
+"   .... ..........X.XXXXXXXXXXX XXXX    ",
+"   ooOOO..ooooooOooOOoOOOOOOOXX+++OO++  ",
+"   ooOOO..ooooooooOoOOOOOOOOOXX+++OO++  ",
+"   ....O..ooooooOooOOoOOOOOOOXX+XXXX++  ",
+"   ....O..ooooooooOoOOOOOOOOOXX+XXXX++  ",
+"   ..OOO..ooooooOooOOoOOOOOOOXX+++XX++  ",
+"    ++++..ooooooooOoOOOOOOOOOXX+++ +++  ",
+"     +++..ooooooOooOOoOOOOOOOXX+++  +   ",
+"      ++..ooooooooOoOOOOOOOOOXX+++      ",
+"        ..ooooooOooOOoOOOOOOOXX+++      ",
+"        ..ooooooooOoOOOOOOOOOXX+++      ",
+"        ..ooooooOooOOoOOOOOOOXX+++      ",
+"        ..ooooooooOoOOOOOOOOOXX+++      ",
+"         ..oooooOooOOoOOOOOOXX+++       ",
+"         ..oooooooOoOOOOOOOOXX+++       ",
+"          ..ooooOooOOoOOOOOXX+++        ",
+"          ..ooooooOoOOOOOOOXX++++       ",
+"        ..o..oooOooOOoOOOOXX+XX+++      ",
+"       ...o..oooooOoOOOOOXX++XXX++      ",
+"      ....OO..ooOooOOoOOXX+++XXXX++     ",
+"     ...oo..+..oooOoOOOXX++XXooXXX++    ",
+"    ...ooo..++..OooOOoXX+++XXooOXXX+    ",
+"   ..oooOOXX+++....XXXX++++XXOOoOOXX+   ",
+"   ..oooOOXX+++ ...XXX+++++XXOOooOXX++  ",
+"   ..oooOXXX+++  ..XX+++  +XXOOooOXX++  ",
+"   .....XXX++++             XXXXXXX++   ",
+"    ....XX++++              XXXXXXX+    ",
+"     ...XX+++                XXXXX++    ",
+"                                        ",
+"                                        ",
+"                                        ",
+"                                        "};
diff --git a/win/X11/pet_mark.xbm b/win/X11/pet_mark.xbm
new file mode 100644 (file)
index 0000000..69b4cf0
--- /dev/null
@@ -0,0 +1,6 @@
+#define pet_mark_width 16
+#define pet_mark_height 16
+static unsigned char pet_mark_bits[] = {
+   0x00, 0x00, 0x6c, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x7c, 0x00, 0x38, 0x00,
+   0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/win/X11/rip.xpm b/win/X11/rip.xpm
new file mode 100644 (file)
index 0000000..e7919ed
--- /dev/null
@@ -0,0 +1,297 @@
+/* XPM */
+static char *rip_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"400 200 90 1",
+/* colors */
+"  c #36362E",
+". c #414146",
+"X c #2F2F31",
+"o c #353523",
+"O c #034702",
+"+ c #152E0A",
+"@ c #30311E",
+"# c #29292B",
+"$ c #233511",
+"% c #22221A",
+"& c #A6A6A2",
+"* c #3A3A38",
+"= c #75746B",
+"- c #191A14",
+"; c #7F7E78",
+": c #12120D",
+"> c #1F2713",
+", c #16330A",
+"< c #033E01",
+"1 c #181816",
+"2 c #033A01",
+"3 c #043802",
+"4 c #161614",
+"5 c #46464D",
+"6 c #242425",
+"7 c #0C0C0A",
+"8 c #15150C",
+"9 c #454545",
+"0 c #4B4B37",
+"q c #1F300F",
+"w c #1F2E0F",
+"e c #3F3F3F",
+"r c #3D3D3D",
+"t c #1B1B15",
+"y c #1A2E0D",
+"u c #888783",
+"i c #2D2D2D",
+"p c #292929",
+"a c #807F7B",
+"s c #272F13",
+"d c #313134",
+"f c #4D4D56",
+"g c #18180E",
+"h c #B4B4B1",
+"j c #989892",
+"k c #252621",
+"l c #90908A",
+"z c #1C1C18",
+"x c #83827D",
+"c c #6D6C64",
+"v c #20201F",
+"b c #797873",
+"n c #2C2C2E",
+"m c #42424A",
+"M c #434341",
+"N c #1F1F17",
+"B c #273B22",
+"V c #2E2E1F",
+"C c #7E7D74",
+"Z c #8B8B84",
+"A c #1D1D18",
+"S c #85857E",
+"D c #4B4B4F",
+"F c #CECECC",
+"G c #034301",
+"H c #034101",
+"J c #272728",
+"K c #043302",
+"L c #353539",
+"P c #282B15",
+"I c #5A5B50",
+"U c #24241B",
+"Y c #C0C0BE",
+"T c #30302A",
+"R c #5E5E61",
+"E c #1F330F",
+"W c #DFDFDC",
+"Q c #8C8C87",
+"! c #043C01",
+"~ c #053602",
+"^ c #38383B",
+"/ c #053002",
+"( c #343437",
+") c #44444A",
+"_ c #52525B",
+"` c #132909",
+"' c #060603",
+"] c #292922",
+"[ c #424237",
+"{ c #3B3B3A",
+/* pixels */
+"'''''''''''''''''7777777v7''''''''''''''''''''v''k'7777777777777777:7:7:7:7::::::4::4:444444444411111z1zzzzzzvddvvvvvvvvvvv6J#JJJJJ6JJ66JJJJJJ####nnnnXXdL^^^fRLLLLL^^^^^rrr.rm..mmmmmm5m....c_m__.mm.m.mmm.m.mm.mmm.m_).mmmm)_Df555555D5D5D5D5DDDDDfffff_____________cR______c_______c_____R_R_R______R__uffDDDDDDDDDR5D5D5D5D5D5D55R55D55555555555555Ra555555555)5)))))))))))))))))))5)5))5)5)5)))))))5))55555",
+"'''''''''''''''''''776777'7''''''''''''''''''7'7kv7'7777777777777:77:7:::::::::::::4:44:44444411111111zzzdzzvzvvzvvvvvvvv66JJ##66JJJ6J6JJ6JJJ#####nnnXXXdL^^^^^^LL^^^r^.R^.^.Rmmmm55m5m55m..m_mm)))mmmmmmm))55)mm.m.mm9mmmmmm)555fffff5fffffDDDDfDffffff_______________R_c_cR_____R__cR_______R__R_R_____fRDfDfDD5DD555D5D5555555555R555555D5555555555555555555)))))))))mmmmmmmm))))))))))))))))))))))))))))))))",
+"''''''''v''''''''77'7777777v''''''''''''''7'7'77'77777777777:7:7:7::7:7::e:::#.:4:44:4:444444X41111zzz1v1vzvzvzvvvzvvvv666J####JJ6#66J6JJJJ#####nnnnXXXXdL^^m^^^^L^^^.RfRm^m.mmm5m555555mmmmm)mm)))))))))5555555mmm_cmmm_)))))5fff5fffffff_ffffffff_b__________________cbRR__c_RR___________R__________ffff5DD5D5D55DD5555555555555555555555555555555555)5_5)))))))mmmmmm9m9m9mmmmmmmmmmmmmmmmmmmm))))))))))))))",
+"''''''''''''''''v''7777777vv('''''''''''''7'77'77777777777:7:7:::7:7:::::#7474::4:4:44444n9n491111z11v1v1vzvdvvvvvvvv6666######JJJ6J6JJJJJ#J###n#nnXnXXdLL^^^^^^^^^^.^f...f..mmm55555f5_mmmmm)))))))55))55ff5ff55m)m))mR_)))555f5bffff_R_fff________R___________R_____bR____________________________ffffDf5fDDD5f5D55555555555R5555555555555)5)5c))))))))5_)))))mmm).mm)_m.mm)))))m.m.m.m.m9__.).).m.mmmmmm)))))",
+"''''''''''''''''v'777777777''''''''''''7'7'77'777777777:7:7:7:7:747474:::4:4:4744:44444444411111z11v11v1v1vvvzvvvvv666JJ#######6J6JJJJJJJ#J####nnnnXXXXd(L^mLm^m^.^^.^.^.^m..mmm55555mmmmmm))))555555555D5fff5ff55))))))_D555555fffffffffff_f______________R__R_____R___R_c_R__R__________________Rfff5f5DD5D55D555555555555555D5D5555))))))))))_5))))))))))mmmmm))m5mmm)mm.m555))m.........9.9..m.m.m.m9mmmmmmm",
+"''''''''''7''7''''v'777777777''''''''''7'777777777777:7:7::7:747474::474:474:444:444:444444111111v11v1v1vvvvv6vvv66J6#6._###^#JJ6JJJJJJJJ#####nnnnXnXdddLLLf^Lm^m^m^^......m^.mm5m5555m)_))))55555555555ff5fff5RfD555_l55555555fff_ffff__ffffff___________________R_________c__________f_fff_f_f_RfffDfDDf5D5D5555555555)55mRD5fRf5555)))5_)))))5)))))))m)))m).m555555)mmmm555555mm........._..m..._.....__m9m9m",
+"''''''''''''''7'7'c'7'77777'777777777'7'77'77777777:67:7:7:::::::474::4:4:44:4:4447n4444441111dv11v1v1vvv666666#6##J###__.6##66#6JJJJ#######nnnnnXXXXXdddLL^^mLm^m^m.m^m^.^m....mmmmmmm5))555_55555555Dfffffff5f5f=555Rm55555555fffffffff_f_ff_f_______R___________________________f_f_ff_fffffffff5f5f5D5D555555555))))5_DDf5f55f5f555)mm)mmmmmmmmmmm555555)))5555555mm)555555555m....................m..9.m.mm",
+"'''''''''''''''v'''7''7'7777777776777{v7777777777:777JJ::74747474:47444474:44444444n4444411)1d5vvvvvv66666666#66666####nR^666#JJ##J##J######nnnnnXnXdddLdLL^LLLm^mm^m^m.^..m^..mmmmmm5)))5555D55D5D5D5ffffffRff5ffb5f5555555DD5f5fffffff_fff_ff__ff______________R________b_R____f_fff_RfffffffffR5ffDD5D5D5555555)555555=5f55555555555)m9_mm)m9mmc.m5555f5555_5f_5f55mmm55mmmm555m......................mmmmm))",
+"''''''''''''''''v''''''777777767777777777777777:77:::J:74J.::4:4:444744444447444444n444111191zvvvvv6v6vvvvvv6v6666666######J#JJ##J##J####ennnnnXXXXdddd5LLLL^m^mmLm^mmm^m^m..m.Rmmm5m5)55555555D55DDDD5f_fffb55f5f5f5f55555D5D5=5f5ffffff_f_f_ff_f____________cc____________bRbfffff_fffffffffDf5ff55DD5D5Rc5555))))555f5f5m555mmm5f5555mm_.mmmm.mmm)55f555555555_5m55mm5mmmmmmm555mm...mm..e.e.e......mmmmmm555",
+"'''''''''''''''''''''''''77777^6477777777777r:77::7:7:::::#74:47447444.4#4444444444441111111z16vvvvvv1vvvvvvvv6v6666666JJJJ#6###J#####n#nnnnnXnXXXXdd(ddLLLLLmLm^m^m^m^.......m5mm5m5)5555555D5DDDD5f5ffffffff5f5fffRfD555D5D5ff5ff5fffff___ff_f__f____R___________c_____f_ff_ff_fffffffffffDDfDfDDDf55D5555555))55555f555mmmmmmmmm5cf55mm.mm)mm...m5555mm55_5555m5m55m55mm....mmm5m5mmmmm..._e.f.f.e.mm55555555",
+"''''''''''''v'''''''''7'77777'67774777777::::::::::::4:444:44:44444444#44444444444111111111zdvvv1v1v1vvvvvv6v6666666##J6#J^#########n#nnn#nnnXXXXdddddLLLLLLLLm^mmLm^mm^m...m.mm)))5)555555D55DD5fDDDfff_ffff5f5f5fffff5DDDDf5f5fffffff____f________________R__________f_fff_bRfffRfffDffDDRRf5DD5D55D5555555))55555f5a55mmmm.....mmm555m.mmmmmm..m55m_5mmmmm5mmm5mmmm_mmm..rer.mmmmm5m5m5m........e..m5_5mc55__",
+"''''''''''''('''''''''''77777777447:7::7:74:474744:4:44:4447444444#44444444114114111111111v1dvvvvv1vvv1vv6d6v6v6666666#J###########n#nnnnnnXnXXXdddd(((LLL^L^Lm^mLm^m^.mm..m.mm))5)555555c55DD5DDRf5fffff_fffff555ffffff5f5D5fDffDffffff_____fb___________R_________f_fbf_ffff____RfDfDfDDDfD5fDD5f5D55555_)5_R555f5555mm..........mm555m.mmmm...m5_mmmmmmmmmm55mmmmmmm..r.r..^.e_f.mmm5mmmmmmm.mm..mm5mm.m_m...",
+"N''''''''''''''''''''''777777747474474_::474:4444#47444444444444444444111111111X1111111v111vvv6vv1vv16vvvv566v6666##J#J#########n.n#nnnnnXnX._Xdddd()L(LLL^^^^^m^m^m^m...mm.mm))))555555D5fDD5fDf5=ffffRR_ff555f5fffffffffDfDDfDfffRf_f_f__f__bf___Ra__R________R____fff_f_f_______fffDDfDDD5DR55D555555555555f5f55mmmm_m..e....e...mm555mmm.mmmm55mmmmm..fR5mmm5mm..^.^r.^.^.rrr.re.emmmmmmmmmmmmmmmm_m.ee.r.ee",
+"'''''''N''''N'''''''''7'7747447474474444J44744744n_4444444444444444111111111111115111v11v1v1vv66vvvvvvLvvv6v66666666JJ#J####.##n#nnnnnnnXnXXdXd.e_xalLLLL^^LmLm^m^m^mblabbbmm)))55555555D5D5ff=Rffbff____ff5ff5555fff_fffffRDfffffff_f________b__________R_________fff__f__________ffffDDD5DD5555555D_5))5555f55mmmmm....r..e.Rr..^..mm55mmmmmmm5mmm....r.mmmmmmmm..^.^.^.^.^.^.^.^.^.^r....mmmmmmmmmm..r.r.r.e.",
+"'''''''v'''NL'''''7'7''7'777774474744447447444444441441411444444441111111v11v11v1d1v111v11vvvv666vvvvvv6v666v6666#6###J######nnnnnnnnnXnX._e=&hY&&jjh^L^^^^^^mLmmfmmmRFYYFWW&lRc555555DDafffffffffff____ff5f55f5f5ffRf__ffffffDffffR__f____________R__c__________ff_f__________ff__f_fD5D5f555D5555555_5)5fff5_5mm....r...r.....r...rmmm_5m5mm5mmm.r.^.^.^.mmmmm_f.f^^r^R.^^.^.^.^rrr^..^.^..........^er.^.^.^.^",
+"''''''''''''N''''''''77'777774747444#m444447474444441111111111111111111v11Rv11v111v11v1v1v1v166666vvvv6v66v66666#6##J###.##nnnnnnnnXnXXDRjYYhYh&j&&jj^^^^^.^.LmmmRmmmRWFYYFWFWWWhjRR5D55Rff_____ff___fffff5f5f5f5fmff__f__ffDffffR_bR_________________c_______f_f_ff________f_fffff_ffff5f555555555))5))55555f5m....r..r.r.^.^.^.r.^..m__mm5mmmmm....^.^^.^mmmmmmm^L.^.^.^^.^^r^^.^.^.^^^.^.^m^.^^.^rr.^.Rr.r.ee",
+"'''''''''''''''''7'77'7777777744444447444444444444411v111111111v1v1v1v11v111v1v1vv15v1v1v1vv66666vvvv6v6v66666J6J#J#J#####nn#n.nnnXne=&&hYYhh&&l&h&jQL^^^^^.^fmmmmmmmbFFFYYFWWWFYhYFl=fRfff__________fff5ff5f5f5f5fff_____f_ffffRR_f___________R__R___RR_______fffff______fffffR_ffffff5fffDD5555))))))555f555mm...r..^m^...r..RRm..r.mm_mmmmm....^.f.^.^..m.mmm^.^^^^^^^r^^r.^.^^.^^.f.^^r^.^.^r^^.^.Rrrfe^.^rr",
+"'''v'''''''''''7'7'7vv7'7777777744744444444444441111v11v11v1v1v11v1111v1v1vv11v1v11v1v1v1vv1666666L6v6v6666666#JJJJ####._nn__nnn.rR&YYhY&hYh&jlQjh&Qarn^^^.Lm^.mmmmmmbWWFYFYWWWYYhhFFYY&bff_______ffff5fff5fff5f5f5f___f___f_ff__R____cR_______c______a____f_ff_fff_____ffff5f5ff55fffffff5ff5f55cc))m)555555_m...em^..bf.r^.rr..^.^.^mm5mmm...^..mm^.m^m^m^mLm^m^^.^r^.^^^.^^^^r^^.^^^^^.^.^.^.^.rfr^.^rr^.^.^r",
+"'''''''''''''''''77'7{77777777474744744111144444411v11111111111vv1v1v1v1v1v1vv1v1vv1v1vvv1v6v66666m66666666^#6#6########nn..nnXRbhhhhYYYhhh&&hjuQhjQbee^.^.^.^mfmmmmmbFFWFYYFWWWhYYhFFWWY&R____ffffffffffff5f5fff5fff___R_____f__R________R__R______a_____f_f____ff_____ff5f55f55D5fffff5555ff5fm_mmmm5555555mmme.r..^.frrf.^..^.r.^...mmmm..^..m.^m.^m.^mmm^mmL^^fL^^^^^.^^^^^.^^r^^.^r^^^^^^^^^^^r^^^.^.^^^r^.",
+"''*'''''N'''''7'7'777777777774777474441111144444n111v1v11v1v1v11vv1v1vv1vv1vv1vvvv1vvvv1vvvv66666666v666666#6#6##J####nn#nnnXDlhh&h&hhYh&&j&h&&Qj&&ubr5r^.^.f.mmmmmmmQWWFWYYhWWWhhhYhYFWWFY&uR_fbffffRf=5fDfffDf5fff______u__R_f_________________________f_f__________ffRff5fR5555555f5f555mm55f5)mmmm555f5f_mm..r.^.^.^.^.^.^.^.^ff.^^.m.m^.^^m^mm.^mLm^m^^m^Lm^^R^^^^^^^^^^^^^^.^^^^^^.^.^.^.rf^.^^.r^^^^^.^r^",
+"''v'''''v''7'7'777vk77r77:74774474747441v11v4444111v111v1dd111v11vv1v1vvdvvv1vv1vvvv1vvvvvvv66#66v66666666#6########nn#nnnnDjhhhh&YFWYYYhjulljjjjh&jQr)dr^m^....mmmmmjWWWWYYYYWWFhYY&hhhFWWYhhaRbffffRfRffffDfDffDfff___________________R___________bR_f______________ff5f5555D555555555m5m5mm5f5mm..m55mmm5_5m.^.^.RR.r.^.^.^fr^.^rff.^.^.^.^.^^f^^m^^mLmfmLmLLL^L^^^^^^^^^^^^^^^^.^^.^^^^^^^^^^^^^^^^^^.^^^^r^",
+"'''''''v''7'777'77{777777477J4747474411111v1v11111v11v1111111v11v1vv1vv5mv1vvvvvvv1vvvvvvvvv66#6666666666#6#J#J#####n#nn.f&FFhhhh&hWFWWYY&lQQxl&YYYYQM9drm^.m^..mmmmmbWWWFFYFYhWYhYFYhhYhWWWWYFWRRfffRffffffffffDfff_________f_f_______RR___________________R____f_ffff5f55f5D5555555m5m))mmmm5555mmmmm5m55_5m.^.r.rmRr^.^^.^^.^.rrfDf^.^^^.^m^LmRm^^^f^^LLLLLLL^LL^LLLLL^L^^^^^f^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^",
+"'''''v'''7777777k77k7:7::7474747474744L_mL1d#ddvv11161v1v1dd1vdv1vv1vdvvvvvvv1vvdLvvvvvvvvb666#6666666#######^.###nnnnncjYYYYFhYY&FFFWFYjj&lQj&&Yhu_^^9re.......mmm55f_lFhYhYhjFYYYFFYhFYFWWWWWFF&R_ff_fffffDfffffDff___R______________Rc___c__R_____R_R_______ffffff5f55f55D555555)5)))mmm.m.m5555)5555m5mm5m^.r.^^.^.^^.^^.^^.^^.^r^^^^.L^mL^mL^L^mLRmL^^^^LLLLLLL^^^^L^LD^^^^R^^^^^^^^^^^^f^^^^^^^^^^^^^^^^^^",
+"''''''''7'77777777777:7:7477474746mu&&h&hj&jQb_Lvvvv1161v1v1v1v1v1vvvv1vvvvvvvvvvvvvvvvv6v6v6##66666#6#6#6######n#n#nnRYFYYhYFYYFhhFWWF&l&&j&hhh&fv6#M9r.^.^...mm_m5m566duhhY&&hYYYWFFhFFFWWWWWWWWFx_fffffffffffffffff___R_R__________R_____________bR________fffff5f55DD5D555555)))))mm).m...mmmm555m5m55mm_mr.^^.^.^r^.r^.^.^^r^^fr^r^^^^^Lm^LLm^^^LbL^^LLLLLLLLLLLLLLLLLDLL^^L^^^^^^^^^^^^D^^^^^^^^^^^^^^^^^^",
+"'''''7'77777777777:7::::474474#5bhYYYYhhhh&&j&jlu_dvvv1611v1v1vvvvv1vvvvvvvvvvvvvvv6vvLLv6vL66##6#6#6##########n#nnnrjYYFWFYYhFFhYhYYY&auj&j&YYYmz666XM.r.....m.m_55c5Xnvd&hYhhFhYFhFYYhFYFWWWWWWYWFYR_fffffffffffff_f___R_RR____cRR________f__f__________f_Rffff5f5D5f55D555555))))mm.m.........mmmmmmmmmmm.^fr.^^.^^.^^^^^^^.^^.DD^r^^^^^^m^mL^LL^^^L^^^^LLLLLLLLLL(LLLLLLLLLL^L^^^^^^^^^^^L^^^^^^^^^LLLLLLLLL",
+"'''7''777777777::::4:44744744^jhFFYYYhFYYYhhhh&&jQu_L66161vv1vv1v1vvvvvvvvvvvvv6v6vv6v66666L#####6#6#########nnnnnnbhFYFYFWFFYYFFhhh&juaj&&hhFFjJv#pkJe.r.....mma_5_R5Lv66uhYhFYFFYYYFhYhFWWWWWWFYhWYFQf_f_f_ffffffff____R___R______cR_____________R_____ffffff5DD5D5D5555R55555_))m).m..........f....m^....^..^^.^^.^^^.^.^.^^^^^^^^^^^^^L.^^mLm^^^LLm^^LLLLLL5L(((((((((LLLLLLL^LLLD^^^^L^LL^5LLLLLLL^LLLLLLLL",
+"''7'77'7777:7:J::44#14444444uFhYFFFFYFhFFYYhY&Ql&ujua_66vvvvvvv6L6vvvvvvvv6v66vv6v6v6v6v66666#d######6#fm##nn#nnn.xFFYYFFFFYhFFFFFFhjbbj&&&YYYYh#v#kvp*e.&YFYYhhj55555m6vvjFFhYFFFYWFYYFFYFYFWWWWYYhhFW&=f_ff_f_f_fR______bRb___________R_ff______R____fff_ffff5D5D5555555__5))5))mmm........fe.r.r.rrr.^.^^.^^.^^.^^^.^^^f^^^r^^^^^^^^^L^^Lm^LmL^mLLLLL^LLLLdd5d(d(d(d(((((LLLRLLL^LLLLLLLL^LLLLLLLLLLLLLLL((((",
+"'7'7'7777:7::7:744444m1111#uWFFWWWFWFFhYFYYYYhj&jQjQQuRLvvv6v6v666666v6v6vv6vv6v6v6v66666666#n###6########nn#nn#.YYYFYFFFWYFhhFFFYWYlaQQ&lYFWhYF)6piiTpmRhYhFFYhhcR5D5Rk#^FWFYFFYFhWFYhWWWYYFWWWWYYYYFFFhR_f_f_f_f__f___R__R_RR__R___________R__R_____f_ffffcf55D555555555D5)5))))mm........e..r.e.^..^.^.^.^.^^.^^^.^^^^^^^^^^^^^^^^^LLfLL^^LmLLmLLLLfLLLLdLd((((((((((d((((((RLLLLLLLLLLLLLLLLLLLLL(((((((((((",
+"'7'7777777::74:444444m_dv_&YFYYWWFWFWYFFFYYYhhhj&&j&ajabfv6v666666666666L66v66666666666666###n##########nn#nnnnfYFYFYFFFFFYFFhhFYFFY&j&jj&FWWhhFbL]TJp#)&YYhhYFhhj55ffD^djFhhYYYYYhWFYYFWWFYhYYWWYFYYFWFFhu__f_f_f________RRR_R_________f______R______ffffff55D555555555))))5)))mm.m......e.eee.^.fer^.^.^.^^r^.LrfD^^r^^^^^^^^^^^^^L^LLLLL^fmLL^LL^LLRLLLLdmdddddd9RXddd((((((((((LLLLLLLLLLL((((((((((((((((99",
+"77'77777:7::4744414444114hFFWWWWWWFWFFFFFYFYYhYjjl&j&juub_6LLL6#6###666666v66v6v6v6666666####d########nn#nnnnnRYFFFFFFFFFFhYFYh&&YF&hh&h&&hhYhYYYhcR)ca&hYFYhYhhhYYlRR=lhFF&hFhYhWYFWYhFWWWFhhYhFFFYhYWFWYFuR__fb_f_f___RR_R_R_R________f___R______f_fffff5f5D555555_))))))))))mm)5mm...e..r.r.^.eR.^.^.^r^f^.^^^^^^^^^^^^^^^^^f^^LLLLLLLLLmLLLmLmLmLLLLLddLc()dddddddd(dddd()((((((((((((((((((((95((((((d(dd(d",
+"77777777::47444411144444aFFWWFWWFWWWFWFWYFYFFY&&&h&Q&&uaaRf6###6######6#6^66666666666666###dd#######n_nnnnnnnuhYYFFFWWFYh&h&FFF&&hh&YFh&&&hhYFhhYYFYYYFYYFFYhFFYYhhjjhFFYhhuYWYYhWWWWWYWWWWWFFYYYYFYYYYWFFFFu___________b_RR_R_R_____fRf__________fffff5f5f5555555)5))c_5))))55)))55mmm..r.r.^.rrr.^.^.^.^.^r^^r^r^^^^^^^^^^^^LLLLLLLL(LL^^LmLLLLLLLLLLLdddddddddddddddddd(dd9((((((((((((((((((((((d(dddddddddd",
+"777k77:7:744744n1114441RYWWFWWWWWFWWFWWFFFYhFF&&&hh&juabaaRL6#6#########m####666666666#6##dnnn##^m#n#nnnnnnnaFYYFFFFFYh&YYYhhFFY&&jhFYFYhhhhFWFYhYYFFYYYYYFFYhYYh&ja&hhFhhlQhhhYYWWWWFYWWWWWWWYYYYWYFhYYFFFYFuR____________RR_R_R____f_ff_a________fff5f55555555))))))_)mmm)5555555555mmr.rf.r.^.^r^.^r^^^^r^^^RR^^^^^^^^^^^LL^LLL(R(()5LLmLLLLmLLLLLLLdddddddddddddddddddddddR9d(9(d((((((((((d(d(ddd(ddddddddd",
+"7U76::7:4:44444n1v44444&WWFWFWWWWWWWWWFWFWFYYYh&Yhhh&buaubbRL66#########^##n##.6J6JJ^^##ndnn###n##nnnnnnXnXuFFFFFh&hFF&hYYFF&hhFYj&YhFFYFFYYWFFFhhYFFFFhhhYYFYYYhxba&Yhhh&jhYYFYYFWWWWYWWWWWWWYYYFWFYYYhFFWFYYQR_________RRR_R_RRb__fff__________R_ff555R55555)))))mm))m.)))55555555555mm..r.^.fr.^.^^.^.^^^.^^^^^^^^^^^L^LL^LLL((((d((d(LLL^mLLLLddddddddddddd9XXXXXXdddddddd9_(ddddd9d(ddddddddddddddddddddddX",
+"77::::4:444n4444v11444^FFWWWWWWWWWWWWFWWFYFFYYYh&&hhQuuQabbb_6#########6#####mRn######mRmn#_###nnnnnnnXnndRFhh&&&h&&hhhYFYYYhj&&&j&&hFYFWFFFYYWWYYFFFFYhYYhhFYY&jaujYhWY&&hhFFFFYYFWWFFWWWWWWWYFFYFWFYYhhFFYhhYQ_________R_R_R_R______ff______fffbfff5f55555)))))m.m.m..9_mm55f5555mmm_mmm^.r.^f^^^^r^^^^^.^^^^^^^^^^D^^LLLLLL(((((((d(ddLLLLLLLLddddddddddXXXXdXXXXdXXXXdXddddddddd(d(ddd(d(d(ddddddddddddXXXXX",
+"7:::4:444441111v11v411bFWWWWWWWWWWWWWFWWFFFYFhYYh&&&QuluuaRbbL6#####66#6#L6#J#mnnndndndd#f_m#nn#nnnmmnnXdaFhhh&&h&YYhYYYFYhYhhhlQ&hhYFYhFYFYYhFFFhFFFFFYYWYhYF&jaua&h&YhhhYhFWFFWYYWWFFWWWWWWWYFFYYFFFWFYhYYYhFY______R___RR_R_R_R__________ffffff5f5555555))))mm.c_....mm)5555m5m5_cmm5m..^.^.^.r.^^.^^^^^^^^^^RfL^L^LLLLLL((((((ddddddddLLLddddddnddndndndXXXXXXXXXXXXXXXXdXdddddddddddddddddddddddddXXcdXdXdX",
+":647444441111v1mv1v11XFFWWWWWWWWWWFWWWWWFFFYYYYhhh&lujjjuaQRbR########6#6##6#JJ##n#n#####m####nnnnnnndd(5&Yh&&&&&&hYYhYYYh&hh&&l;xxxjjQajlullahFWYYFFFFhYW&jljbbau&&&&ljjxlQjjj&&&jjFYYWWWWFYYYFWFYYYYYYFYWWFYFF&___________R__R__________ffff5f55555f555_)))m.m.m.......mmm5555mmmm_mmmm.^ff.^r^^L.^^^f^^^^^D^^^L^LLLLD5LL((((((dddddddddLdLdddndnddndndcdXXXXXXXXXXXXXXXdXXXXXdXdddddd9(ddddddddddddXXddXXXXXX",
+"4:44444411v1v1v1v1v1v.YWFWWWWWWWWWWWWFWWYWFYFYFYYh&&jujuQQbbRbf########6#6#^###J#^#########nnnndndndmLLm&&&&&YYhh&h&&&hh&hh&&&&css@so$@$s@$@$@sZWWhFYhhhhWc$o$ocujhh&hb@@@@$oooo$oo$@@ChWWWYFWFFFWFYYFWFWWWWWYFFWl____________R_________f_ff55fmf555555555))mmm...........mm55mmmm_mmmmmmm.rrr^r^.^^^r^^^^^^^^LLL^LLLLLLL((((((dddddddddXdddddnddnmndXmXmmnXXXXXXXXXX.cXXXXXXdXXXXXXddddddddddddddXXXXXXXXXXXXXX",
+"44n44#nd1111v111vvvv1fFFWWWWWWWWWWWWWWWFWYYYFFhh&&h&Q&uQubuRbb_#####6#6##J###J#J.#######n#nnnndnnnddLLmQhYh&hYWFY&hhhhhFYFY&&&&Iossoossssssssss$0FFFYh&hhFcosss=jhFWFYCo0ssssssssssssso0&FWFFFYYFFFYYWWWWWWWFYYWWF=________b____________ffff5f555555555)))_.)........e_e...mm5mmm._m.mmmm..f^.^.^^f^^^^^^^^^LLL^LLLLLLL((((((9dddddddd9_dXdndnddnd_dnmnXnnXnXnXnXnXnXnXXXXXXXXXXdXdXXdXXddddddXdXXX9dXXXXXXXXXXX",
+"44n11111v1v1d16v1v1vv_FYWWWWWWWWWWWWWFWYFFFFWFj&&hhhuuQQaaabRbRmd#######6##########n#nnnnnnnnXnddddLLLc&hhYY&FFWF&hhYYhFWWh&&&hI000000000000000ss0FYYWYY&h00000Z&hWWWY=000000000000000os0YFYFFhYYYYFYWWWWWWWYFWFFFh_____________ff_ff_ffff55f_f555555_))))9m.......e.efee..mmmmmm.._...mm.^_.^^^^^^^^^^^RDLL^^LLLLLL((((5(((dd(ddddXXXXXXXXdndnndnXmmnXnXXnXnnnnnnnXXX_XXXXXXXXXXXXMdXXXXX9XXXXXXdX_XXMXXXXXXnXi",
+"44111111mv1161v161vv1cYYWWWWWWWWWWWWFWWWFFYFFh&h&h&h&jQQQbuRbbbd######6###########n#nnnnnnnXndddnddLLf&&hhh&FFWFY&&&YYhYFFh&h&&I00000I0c0c0I00000@lYYFWFhY0000oj&hYFWWI0000II==ICC==0000scFWFFhYYYFYYWWWWWWWWYFWWWW&_RR____f_fffffffff5f55f5555555555_))).m......e.e.e.e.e.mm5mam..f.mmm....^..^r^^^R^^^LLLL5LLLLL(((((((d(ddd99ddXdXXXXXXnmdnnXnXnnn.nXnnXnnnnXnXnnniMiXnXXXXXXXX9MXXXXXXXXdXdXXXXXXXXXXXiXiXnn",
+"#44111vdn1vv1v16161vvRFFWWWWWWWWWWWWWWWWYFFYF&h&&&&hhuulaaabRbRm###6##########._#nnnnnnnnndndddXdLLLL&&&hh&YWFFhhhhhhhhhYFhhhhl00000jjj&j&hYYj00000jhh&&YY00000ljhhhWFc0000jFFhYFWWWj0000oWWWWYYFYYFFFWWWFWWWFFFFFFWa___ffffffffff55f55f_f555555555)))).)........e.reeer..e.mmmmm.....m.^.^^.^^.L^^^^^^LL^LL(L((((((((((d(ddddddXXXXXXXXnXnmnXnnXnnnnnXnnXninnnnniinnnnnnXXnXXXXXXXXXXXXXXXXMXXX_XXXXXXiXinnnnMi",
+"#44111111v1v1vvvv1v1vRYFFFWWWWWWWWFFFFFWFYFFF&h&&YhhhubQuabcbcb_L6##########nn##nnnnnnXnXXXddLdLLLLLR&hY&&&&hYhYYYYhYhhhYFhhjjZ00000CZjh&h&YFF00000ljl&h&l0000oZjYhhYYZ0000jYFFFFWWWW0000oWWWFYYFFFYWWWWFFFYFYFYYFWW&_ff_ffffffff5ff55f_R55555555))))).m......e.r.r.r.^.r^.mmmmm......mmm^.m^.^^^^D^^^LLLL(5(((((((((d(ddddd9ddX9XXXXXnXXXnnnnXnmXnnXnnnnnnnnnnnnenniXnXnniXXnXnXXXXXXXXXXXXXXXXXXXXiiXnnnniXnni",
+"444411v1v1v161611v16vfhWFWFWWWWWWWFFFWFFFYhFFY&hhhjhjlbbuabRbcbRn########n.#n#nnnnnnnXXdddLLLLLL_^Lmu&hYYh&hhhhhYhh&hYh&YFY&j&j00000cCZ&h&YFFC00000CCj&hjl00000ShY&&jYC0000&FFFYFWWW&00000WWWYYFFYFYFWWWWYWFFYWFYFFFWbfffffffffmf5f55f55R5_D55)))))m.).._cRm..e.r.^.^.r^..b.mmm.m.^m..^mmm^Rm^^^^^^^LLLLLL(5(((((((ddddd9dddddddXXXXXXXnXn.nXnnm.#nnnnnnnnnnnnnnnnnnnn_iinnnnXXXXnXnXXXXXXXXXXXiXiXinniinXinnnnn",
+"7441111v1v16161v61v1v#&FFFFFFFFFWWFWWWYYFFYhhYY&j&&h&uuRbbbbbRbR########n#_nnnnnnX.XXdddLLLLLLLLRmLbQ&&h&h&&hhh&lhhFY&&j&hYjllj0000000c0II=c000000cCx&&&Sj0000o&&Y&jhY=0000I=cC==Cj=00000=WWWYhFFFWFWWWWFFYFWWYFYYYWFYffffR_f5ff5f5f55555555))))))m9m._..._.e.r.r.r.^.^.^.^mm..m.m^.^..m^mm_^.^^^RLLLLLL((9R((((d(d(dddddddXdddXXXXXXnXnXnXnnnn#nnnnnnnnnnnnnnnnninnnnninniXninXiXXXnMiXiiXiXiXiXnniXninnnnnnnnn",
+"4:441v1v1v1616v1v11v1vjYYYFWFFWYYFFWFFYFYYYYhYF&j&&jQu&ubaRbRbc_######n#nnnnnnnXXddXd(LLLLLL^LLLLL_aj&hh&&&h&&&alh&&hh&jjhlalj&00000o0o0000o000000jjj&lxS&00000&h&hYhhc000000000000o00000YWWWFYFFFFWFWWWFYhFFWFFFYYYWWcfffffffmf555_R5555)5)))))m.)........e..e.^.^rrrr^r^m.mf_m...^.^^L.^mmffL^LDL^LL(((((d(d(ddddddddddXXXXdXXXXXnXnnninnnnnnnnnnnnnnn#########nniiinnniiiinnnnnnnn_innnnnnnniiininnnnnniiiiin",
+":44111111vvvvv161vv1vdbYFWYFFFFWYFFYYYFFYYYYhhFjj&au&Qjuacbcbc=5#####n#nnnnninXd(d(LL5LLLL^^LLLLL^RQ&&hhhhh&&&juj&QjjjQauQaajjl00000000000000000IjjjjljZh&00000YhhFWFY=00000000000000000&WWWWYFWFFFFYWWWYhYFFWWFFWFYWWjffffff5f55f5D5555)5))))))_).......e...^.r.R^.^.^.^.^.mmmmm^^.^^^.Lm^^.^L^LLL(5(((((d(ddddddddddXdXXXXXXXXXnXnnnXnnnnnnXXnnnnn#n#n#nnnnnnni##n#inne_nnnniXniXniMiiiXii_Mninnnnnnn#p_#n#n#n",
+"4444411v1v1v11v11v1dvvXhYYFFYFYFFWWYFYYYYYYY&hYjj&ujjjjjaabRbcb^.^###nnnnnninXXdLLL(LLLLLLLLLLLLLmbuul&h&&h&&lujull&&jbaaljQ&jC0000000000000000C&h&ljlhYFj00000FYFWWWW=00000000000000IZFYYWWWWWFFYYYFFWWWYhYWFWWWFWFWFY_f5_f55f555555555)))))).)..........ee.e.^.r.^r^.^^^mm.m.m..^^.^^.^m^m^^^LLLL(9(((d(ddddddddddX9XdXXXXXXXnXnnnXinnnnnXddXXXnnn#in##########ne#nniniiinniiiiiiiiiinnnnniinnnni_p#in#i#i#n#n",
+"4444411nv1v1111v1v1dvzvChYYYhFYYYYYFYYYYhhhhhhhjQ&jjjjQauRbcbcc^n##nn#nnninnXd(LLdddddLLLLLLLLdLdRbajhhYYY&uualjQ&hYY&uauu&j&S=00000CZ=000000YYhhY&jFFFWYh00000FFFWWWWC0000CZ&ZCjZZZFFWYFFWFWYWYYYFYFFWWWYYYFWFFWWFWWFhbRfR5f55f5fDDD555))))m.).......e.ee..r.^.^rr^.r^r^.^m^.m^m^m^.^m^mm^m^^^LLL((((d(dddddddddXXXX9ddXXXXXiXnnnninnnnnXXdddddXnnn##############i#ne#iiinnnnnennnnnnnnnnii_in#enpi#i#pi###i#i#",
+"44444411111161v1v1vvvvvn&&hhFYYFYFhYYYYY&Y&hhYhxQjljjullabRbRbRdnnnn#nnnnnXXddLLdddddddLLLLLdLLL5bcbjh&h&&aabj&&hYWFWFjQujhh&xc00000&hYc000o0SFhYFhhWWWFYF00000WWWFWFW00000&YF&&hh&FWWYhYhhhhWFWFYWFWYWWWWYYYFWWFFWWFFhQf55ff5f_R5f5ffD555)))m..9......e..rr.^.rr.^.^^.^^..mm^.^m^m^m^m^mL^L^^LLL(((((ddddddddXXXXdXdddddXXXnnninXnnnnnnndddddddXXnn####i##i##i###e#nn_pniii_einnnnniiii#n##p##i##_rp###########",
+"4444411111v1111v1v1v1vv(ZhhFYYYYFFFhhhYYhh&hF&&&jlQa&ulabRbcbc_nXnnnnnnXnXnXdLLLdddd(ddLLdLLLLLLfbRbj&&&jucRa&&hFWFWFFhhhYFYjZI00000&jYFI000soZYhFYhYWFWFh00000WWFFFWWC0000hYhj&j&hWWWWYFYFYYFYWWFWWFFFWWWFYFWWFWYYFhYhhR5f55fffffffff5f55555)m......e.e.^..rr.^.^r^^f^^^.^m^m^^^^m^mm^m^^^^^^LLL((((dd9dddd9XXXdXXddddddddXniMnnnnnninnXdddddddXXnn####p##p##########pi#n##Iiininn#n#n#ni#i#i###prp###eepip#p##",
+"44m411111v41v1v1616vvvvv{jhhhhhYYYhF&hh&hh&hjj&jj&QQluabRbcbRbdnXnn_nnnXXXXd(LLdd(ddddLdLLdLLLLLfRbajj&jQbbu&&hFWFWFFFFFFFYYj;c00000hhhhh0000o0lhhFFYWWWFY00000WWWFFWW00000hY&ljjhhWWWWWFWY&&YhWWFWWWYYFWWWFFFFWFYYhYFYFbfffffff5_5555f5f5R_f5)m..e.e.e.r.^er.^.^rr^.^^r.^m.^^.^^m^m^^mLL^LRLLL(((dddddddXXX9XXXXXddddd(((dXXnMnnnnnn#nXdddddXdddnn#####rr###p########i#een#nnnXXXnn#n#ir######ip#p#p#p###p#####",
+"11n1111v14v1v1vv161vvvvvv*&&&&hh&hhh&h&h&h&hhQlljhbQabbbcbcc=f#nnnnnnXXXXXXdLLdddddd((dLdLLLLLL^_cbujuuQubaljhhFFFFWFFFFWWWYucI00000hhhh&&0000s@ZYFYFFWWWj00000FWWWFFWC0000hY&Zj&YYWWWWWF&&&&hYWWWWWWWYFFWWFFFWFFYhhYFYF&Rfff5f55555555f5555555mm...r.er.r_^.^.^r^.^^r^.^mmLm^L^^^^mff5^^^L5LL(((d(dddddXXXXXXXXXXXddd(d(d(dXXnnnnXXXXXdXXXdndXXdnn###p####p####pi##i###i#nnn.XXXXnn###pfni###pppppppppppppppprr",
+"111111v41v1v1v1vvvvvvv6vvv9&&&hhh&&h&&&hh&&&&bjj&jbbbbRbRbRbRXnnnnXXXXXXXXdLLLLddd((((LLLLL5^^^RRbbuQuQjuaj&&YFFFFWFFFFFYFFhacc0000IhhhhYhj0000@@hFhWWWWFh00000YWWFWFWI0000&&ljl&hYWWWWFhjj&hYYWWWWWWWFFFYFYYhYh&hYYYYYYWfff5f555)))m)5mm5m5m5555mm.ee.^effrrr^rr.^.f.^mm^^^^L^^^^m^^^^^LLLLLL((ddddddXXXXMXXXXXXdd)d(d(dddddX_inXdXddddndXnddndXXn##pppppppp#p##p##p#####nnXXXXXnncen#pi#fppppppppppppppppppppp",
+"1z11v111v1v1v1vv1vvvvvvv6kJ0&j&h&&&&hjjh&&&j&j&xxbaabRbcbRbcmnnnXnXiXXXXXX(LLL(dd((((((LLLL^^^^Rbabu&h&jujQhFFFFFFFWFFFFYFFj;Ic0000IhhYh&&jj0000sohYWWWFh&00000hFWWFFWC0000ZSCjhFYFWWWFh&&lYFhYWWWWWWWWYFYhWhj&&hFFFYFFYYbff5)5)))).)..m...mm55mm5mm..^.rer^.^.^.^..^.m^m^m^^^^^^5Lm^.^^^LL(5((((dddXXXXXXXXXXXnXdddLddXXndddd.ddddXXXXmdddnnddndnn#pppppppppppr##########neXXXXnXnnnnn##iipJJJJJJJJJJJJJJJJJJJJ",
+"z1z11v1v1v1vvvvvvvvvv6v666669ljj&&&j&&&&jZ&Z&Qjaxuubbccccbcmnn.nnX.MXXXXdd(^5L(((((((LLL^^^^^^Dbxauj&Y&QbauYWFFWFFFFFFFYYYYQcc=0000IhY&&jj&jC0000olYWWFh&&0000=YYWWFFF=0000Z=lhYWWFWWWhjl&&WWYYYWWWWWWWFYY&&QjhhhYFFFYYYhR_5_5))cm.9......_..m.mmmmmm.rrrrre^r^r^mf^fm^mL^^L^LLLL^^mL^^^L^LL5(((dddXdXXXXXXXdXXX.Xd(ddnnnnnXXXdXXXnnnnXXXXdXmnddXmnn#pppJppppppppp#p#p####nXdXdnXnnXdXnnnn##JpJJJJJJJ{{JpJpJpJpJ",
+"z1v1v1v1v1vv1v1vvvv6vv6v6vk6kD;ZjS&hjjjlj&jQljabac=bRbRbccmnnXnXXXXXXXddddL^5L(((((LLLL^^^^^^r^luu&hhh&ubauYFFFFFFFFFYYFYY&=RClZj&j&YYhhj&&&&jjjZS&YFYh&&YZj&j&YhYWWYW&hZjC=lYYFWWWWWWjZjhWWWYhFFWWWWWWYh&&QlYFYhFYWFYYYhxff5)))_mm.......e....mmm5mm...^.rr^.^^m^fffm^^^^^L^L^LLLL^Lm^^^^^LL(dddXXXXXXXiXnXd.XXdddXXnnnnnnn#nXnnnnn##nnnndnndnndnXXn#JJrJJJppppiRpppprp##nXXXXXnXXXnnn.nn#pJJJJJJJJJJJJJJJJJJJJ",
+"zzzv1vvv1vv16vvvvvvv6v666666k**blj&llZjjljlljxuauaccbcbRRm#XnXXXXXdddddd(LDDL((((((LL^^^^^^^r^c&&&&&&h&ubQjhFFFFFFFFYFYYYYQRcC&YFFFhFFY&Y&&YYYFYYhhhhhjYFWFhhYYFhhYWWWFhYY&jhFFFWWWWWF=jhWWWWFYYYFWWWWWY&&hjhWFYYYYWYYYFhj55m).).9........ee....mmmmm.^.^.^^r^^.^.r.^^^^L^LLLLLLLLL.L^^^^L^^L(ddXXdXXXiXM_idddd)dddnn#n#n#####n########nnnnnnnndnXnXn##prJJJJJJpJppppprp#nX._XnXXmnnrnneXnnJJJ6JJJJJJJJDJJJJJJJJ",
+"v1v1v1v1vvvvvvvvvvv6v6v6k66666JJ9;xxlCuSSxax;abaccbcccc_mnnXXXXXdXddddd(L^^LL(((LLL^^^^^^^Dr^.R&hhYhh&hQQ&j&FFFFFFFFYFFFYhuRSZhYYFYYYFY&hhYYhhYYY&hj&&&FFWWWFFYFFYYWWWYYWh&YFYYYWWWWFZlYWWWWWFYFYYWWFFh&&hYhhWWFYYYFYhYhYh55)m9.mmm.....ee.e....mmmm...^..^r^^^.^m^m^.^LLLLLLLLLLL5LLLm^^^LL((ddXXXXXXiiiindd(ddXXn#n#n######################n#nnnXnnn#pJJJpJpJJJpJJpppp#nnXXnnnnn#n#nn#nn##JJJJ##pJ66J]J666666*",
+"zvzvvvvvvddvvvv6v6666D66k66JkJ6{##{I;;;x=auabccc=cccb_LnnXXXXXddddddd((L^r^^L(LLL*^^^^^DD{r^r^a&&YFF&h&jhh&hhFFFFFFFFFYFY&bS&jhYFYYWYFFYhYYFFFYYh&jjhhhWWFWWWFYFWYhFWFFWWhYWYWFYFWWWhlhWWWWWWWFhhYFW&QjhYYFYYWFWWYYFYYYFFYfm5)m))....e.e..r.e......m.^..^r^.^r^.^m^.L^LLLLL((()_((5LLLLL^L^^L(dddd9XiiinnnXXdXXXn##############ppppppJJ#####^###nnd#####JJJJJJJpJJJJJJJ##nnnnnXXn########nn##Jp###rJJ6666J]6J]6J",
+"zvv1vXvvvvdvvvvvL66JJrJJJJ]6J6J#nnnn^RRb=b==cc=c=RR5dnXnXXXXXdXdddd(LL^^^.^^LLL*L^^^^^^^r^rr^mj&hhYYh&&jhYh&hYFFFFWFFFFYh&bjj&FYFYYFWYFYYWYWWWWWhZS&Y&FWWWWWWWhFFFYYWWWFFFWWYFYYWWWh&hWWWWWWWWFYFYWhuahWFYFFFYWWWFFFYYhFFY5c55))m...e_feefr.r.re^.^.....m^.^.^.^.^m^^LLL(((((d(((d(dLLLLL^LLLL((dddXXXnii_Xdddnnn########p#pppppppJJJ#JJJJ6J^JJ#nn#nJ#ppJJJJJJJJJJp{JpJ##nnnnnnnn#######r#n######rr###JJJ666k666",
+"vvvvvvvv66vv6v6666######J{DJJJ##nnnnXXnnLm.f__mmdXXnXnXXXXXddddddd(L5^^r^^^^L^L^^^^^^^r^rrrr.R&YYhYFYY&j&hhh&hYFWFWFFFFh&lujjhYYFYYWWhFYhFWWWWWYjZj&YYWWWWWWWWYFWWFYWWWFWWWWYYYYWWh&hWWWWWWWWWWYWF&QbjWWFYWWFFYWWWWYFYYYhY555555)..e.ee.eerr^rrrrr.^...^m.ff^.^^^mL^LLL((d(d(dddddd(dmLdddLLLLLL(dddX.XXXXXXdnX###p#ppppppppppJJJJJpJJJJJJJJJJJ##d###JJJJJJJJJJJJJJJJ###nnnnnn###JJ6JJJJJJ##n##nn##rr##JJ66666k6",
+"vvvvvvv6666666666###nnen##JJJp#nnnnXXXnnnXddX_.nnnnXnXnXXXXddd d(d(L^^^f^^^L^^^^^^^^{r^r^rrf^^hFFYFFFYh&FFjf#f^R5Rf_v))eDLXJ900I0000I0I00000c0IPoo0 0IIcI0=0c0000II0IcIc0Ic0sIIocIIIc cR_=;c=IDf.(nX(D_=5__D_aFWWWWWYYhYYY_55m555m..e.e..r.^.^.^^^^^.^^..^.^.^m^m^^^LLd(d(dddddddddddLddddXXdddd(dddddXdXXXXXn#cpppppppppJJJJJJpJJJJJJJJJJ^JJJ6##nn#f####JJJJJpJpJJp#####nnnn###JJ66666666JJJJ#J#######JJJJJJJJJ",
+"vvvvvv6v6666########n#nn#n#rDinnnnXXdnnnXXdXXdnnnXnXXXXXXXdddddd(((L^ff^^^^^^^=^^^{^r^rrer.f..&hFFFhYYh&YW&77'''''''''''''''''''778788888787787''''''''''77878788777888888777'7''''''''''''''''''''''''''''''5YWWWWWWYYhYh5mmmmmm)m.eb..r.^r^^^r^f^^^^.L^m^.^mL^^^^LL(ddddddddddXdXdXXddXnXXXnXXddddXXXnXnnnn#J^JJJJJJJJJJpJJJJJJJJJJJJJJJJ6J6J6#n#n.#nnn#####n######nn#nnb###J6J666v6v6v666666JJ###############",
+"vvvv666666###6#######nnnnnnnennnXnXdXnnnnXddXXdXXXnXnXXXdddd d((d(LL^^^R^^L^^^D^{{rrrrrrrrrrD.YhYFF&&hllYFjbuxx=aac=bZbZSCbaSa;;C=C=SxxSxZSCZSZQQullllSljlZSSSSuSZS=lSSbSZxljjulQllQuQaQujQQaQQalQQjuQcQQlujlfYWWWWWWWYYYY_...e..mm..r^..^.^r^^^^D^^^^L^^^Lm^^^Lm^L((ddddddddXdXdXXXdXXnXXnXnnnnnnnnnnn#n#n##JJJJJJJ{JJJJJJJJJJJJJ]J666666J6J6J6##nnnnn#nnnrnnnnnnnnnnnnn####JJ666v6k6kvkvvv6666J#######JJJJ6JJJ",
+"666666J####6#666#J####nnXXXnnenXndXdXXXnXXd(dddddXXXXXXdddddd(d(((L^^r.^^^^^^^^{r^r^rf^.r.r.e.&&&YY&&jua&FluuaaabaaSxQZu;bbaS;aSxaxSuxlul;xZlSlulSSQQjjZllSxxuuZZuuSjlSSujlljllQQjlZQljujljuQQQllQQujjljjlljjIYYWWWWWWWWYYfrre...mm.^f.r^.^^^^^^^^^^^^^^^^^^^^L^LLLddddddddXXXXXXXXXXXXXnXnnnnnn######J###JJJJJJJJJJJJJJJJJJJ]J66J6J6JJJ]666J6J6J6##^nn#n#n#n#nnn#########6666DLD 6vvvvvvkvkvv66J6J6JJJ6JJJ66666",
+"66J6J####J#6666J66J6J#nnnnXXXXXXXXddddXXXXddd(d(mdddXdddd d(d( (((^^^.^^^^^^^{r^rr^rrrrrrrr.rm&&hh&h&laajhRbbbbaQ;QSuQZQb;a;;xxxaaxxSalZxxZllaxZQuSujQjlZlSlSSuuuSZjjjQljQQlQQQlljQQlQujlQjuQQllljjjjjjjjjlQQ)YWWWWWWWWWWFD.r......e.^rrr^^^^^^^^xLLL^Lf^^LLLL^5LLddddddXXXXXXXXXXXXiXnXnnnnnin###ppJJJJJJJJJJ6J666J6J66J*666J6J6J6J6**666J66666666Jr#Jr#######J###J#J#JJJ^6v6Lvkvvkvv6vvv(vvvv6v6666666L66vvvvv",
+"JJ#####J6666J6#6JJ#JJ#rrnXXXXnXXXXdddm.XiXXdd((L((ddd(dddddd((((((^r.^^^^^^^{^r^r^.^r.r.r..r..hhYYh&&&bbj&RbbbauaxxauZZS;bQbaxxxaaxxSaZlxaZxSxxlxuuQlxSxxSSxSxSSuSujljljllljljjjuZQQQjjjQjjjQQQQQQjljjjQjlllQ9FFWWWWWWWWWW_rr.^.rf_.^r^^^^^^^^^^LLLLLLL5LLLLLLLLLddddXXXXXXXXXXXiXiXXiiininin####pJJJJJJJ{J6J6{6J]6J6]6J**J6J6J6J6]6666666kR]6666J66666J6JJJJJ6J6666JJ^666D66vk6vvvvvvvvvvvvvvvvvvv6v66v6vvvvvvv",
+"##n###JJJ6J6JJ6#JJJp#pr#nnnXdddddddLddXXXXXXXdd(LLLL((( d( (d(((LL^^^.^^^^^^r^rrre^.rrr.r.r..fYhh&h&&&abQ&RbbbuxxSaxuZxab;;bxaxxxxaaxual;lluuaauuuljljuSuxxuSSulZuujjjlluululQuZjZjjjjlluQjjQlQlljjjjuQQllllQ9YFWWWWWWWWWW_r^...r.f..^^^^^^^^LLLL(((((L(LLLd(dLLdddXXXXXXXXiXiXiXiiiiiinni#n#p#ppJJJJJJJ66JD**{666666666666J6]6]666***kJk6k66666666666666R6666666k6666*6D66k6vv66vvvvvvvvvvvvvvvdvvvvvvvvvv%R vv",
+"r####JJJ6^^J#J#J#p#pp#Di#nnnXd((((d(dddXXXXXdd((LL^^L^LL(d((((9DL^r.^R^^^^r{rr^rrrerr.r.r...ebhY&&h&&&u_u&RQauuaSauuSQuba;baxxxxxaa;lQSuauxuuxaSuQlQjllljjSxQxSjuuujjjQZSZuuZuuujljQQQjjlljjlQQuQjjjQljjljQlQ9YWFWWWWWWWWWRr.^.^.^.^r^^^^^^LLLL(L((((((((dmdddLddXXXXXXXiXiXiMiiiiiinnnii#i###ppJJJJJ66J6Jk666666666666J6J66666666**66666666k6k6k6k6k6k*k6k6k6kv6v6 DUv(Dk6v6vkvv6vvvvvvvv vvvvvNvvvvvvvNvv9Nvvv",
+"nn###JJJpppJpJpppppiperiiiiinnXXXX(d(dddXdddddd((LLL^^^^5LLLL^^^^^.^r^^^{^^^r^e^.^.r.r.e.e.._c&&&&&hYY&RuhcuuabaQxaxxQxbu;axSxxxa;;lauuaa;xuxxxlululluSluxuQxuuSSuujZllSuuuZujQljjjljjljllljjjjljjjjllljlllQQ9YYFWWWWWWWWWRRfm^..^..^^^^^LLLL((((((d(dd(dddddd(dXXXXXXiXiiiiiiiinnniiiii##p#n#JJJJ6JkJJJJJ666666kkk6*k6k6k6]666666666k6k6k6k6k6k6k6k66*(*6k6v6v6kkv6vvkvk66vvvvvk9vv9vAvAdcvAAvNvvNvNvNvvAv vAvA",
+"nnn##pJJppppppp##i##ireiiiiiiiiXXXXdddXddXMddd((dd(((L^^5*L^^^Dr.r^^^^r^r^rrrrr.rr.re.r......c&&&&&hFF&u&&RabaxaQubxQu;aub;xxxxuaalZQaaaaaxSuSxlZluulluxSxSSuZSuuSulZuSuSuuujQllujlQQQQuQQQllQjjjujjQljllllll9YYYYWWWWWWWWme^.^.^.^^.L^LLL((((((((d(ddddddddd(dXXXXiXiiiiiiinnniiii#nnXninnnnn#JJ6JJ#####JJk6JJJJJJJ666666666k6kk6k66666k6k6kRk6k6k6kkv6 6vkkvkvvvkvkvvvv6vvvvvvvv vAvAAvAdAdAAvAvAvAvAvAvAAvAvA",
+"Xnnn#pDpppp#pipi#riiiiiiiiiiXXMXT_XXddd ddd (99d(((((L^r^^^^^r^.r^r^^^^r^rrrrrrrr.re.e.e....mb&&&&h&hYj&hYbuabaxuuaxuxCub;xxxuxaauull;axZaxuuxxxljuujjxSuuuQxuuuQuSuZQuuQQZllQjjQuuuuuuuQjljjljuQQjljQlljljllDFFYYWWWWWWWWR.^^^^^m^.^^L((((((((( ddddd(ddXdXdXXXiXiiiiiinniiiin####nXdXdXXXn#n#JJ6J#######J6J6JJJJJ{6k6k6k6k6*66666k6k6666v6666v6v6v6v6v6kvv6vvvkvvvvvvvvvvvvvvAvzvAvAvAATXAAAAAAAAzvzvAAzvAAAAA",
+"Xnnp#ppipipi#iiiiiiiiiiiiXXXXXXXXdX dddd(d(d(((d9(((((^^r^r^.r.^^r^^DD{rr^rrr.r.r.e.e....M..mQ&&&YFYFY&&YY_uaaau;Z;Sxbbaa;aaxxaa;lu;Qa;QlluaaaxalZxjuxuSSuuuuSuuuuZQuuQuQQuujjljuZuQuZuQljQjlQQllQQQjQQQlQlll9FYYWWWWWWWWFDLL^^^^^^^R^L(((((ddddddd ddXdXXXXXXXiiiiinniii######i#iinXXXXXnnXnn#r#J###JJJJ##JJJJJJ#r^J66k66666*k6k6k66JJJJJ6J6666666kvkkvvvkvvvvvvvvvvvvvvvvvvNvvAvzAAAAAzzAzzzzzvzzvzzAAvzAAvz9z",
+"enipiDipiiiiiiiiiiiiiiXXXMXXXXXdd ddd (d d((( (((((I((L^^.^rr^^r^^^r^^r^rre^.rrreee.e.....9m5Rh&&&YYYhhYhh_bab;aSaua;b;Cbaaa;ZZQZxaa;;ZlQQuulQuljuuuxuuuSuuxuxuuuuuuZQQQQQQuuQQlZuuljjjjljjjjQuQQjlllllluQQQQcWWWWWWWWWWWWRLLLLLL^^^^((((d( (d(dddddXdXXXXXXXXinecniee##rrei#i#nXnXXXnXnnnne.nn#####J666J###JJ6JJ##JJ6J6k6k6k66k66*66JJJ#JJJJJJJ66666vvvkvvvvvvvvvvvvvvvvvv9AvAAAAzvzvzzzzzzzzzzzzzzzzzzzzzzzzzz",
+"XnpiiTiiiiiiiieiiieXXXTXXMX Xd ddd9I(d(((((((((*(*(LL*LL^L^r^.^^^rr^rRDrrrr.re.....e..M.9.)))uh&&hYhYYFhhh_bbxuxxQab;bbb;;;;Q;;CS;;aaZxaxaSaauujQljSuuuxuuxuSSSuuZuZuQuQQQlllQulljjjjjlQjjjljuQlQujlQlljj&jjjeWWWWWWWWWWWWbL(((LL(LLL(dd(ddddd dddXdXXXXXXTXiiiin#i##iri###p#iinXXXnnnnn######nnnn#J66666JJ##JJJJ#JJJJJJ66J6k6k6kk66JJ#J#J6J6JJJJJJ6*6kvvRvv vvvv%vvvNvNvNvA9AvAAzzzzzzzzzzzzzzzzzzzzzzzXzzzzzzz",
+"iiiiiiiiiTiiieeTXXXTXXXdXMM_ d(ddd((((((9( ((*((LL*L*L^*^^^^^^^r^r^rrrrerr.rr.eeee......)9))5ch&&hFYYYh&h&RaubaSSab;bbb;;abxux;uZu;xaal;xSuSxxulSjxuuSSuxSxuQQjZQuuQuuQlllllQujQjjjjlQQlQlllQQuQlQjjj&ljjjjllRWWWWWWWWWWWW=(d(dd(_d(dd(dddddddXdXdXXXTXXiXiiiinii#i#ipr##i##nnXXXnn#######pJJ##rr#{J66v6k666J##{{#JrJJJJJJJ666kk6v66{JJJJ666666JJ6JJJ66vv%vv(vvvvvvvAvvvAvAAXAAzzzzzzzzzzz1z1z1z1z11zztztztzzzzz",
+"iiTiiTiiiXTXiXXXXXXXdTdX dd ddd ((d(( (*(*L*LL*L*L**^**5^^^^^r^rr^rrrrre.re.e.e.....9.99))95cuhhh&h&hh&hY&Raxxbbb;;bbauubaSuQluSlxaxxaaaxSuuSxQQlSxxxuuQllQjjljSSQuuQQuQQQQuQQljjjjljjQQlQQuQQuQQQQQQlljjjjjlrWWWWWWWWWWWWfdd(ddddddddd ddddddMdXXXXdXXTXiiiiii##ip#p#nnnnnnXnn#n#ppJ##pJJJ6J6JJ6J6*k6kvkv66JJJJJ#JJJJJJJ{J66kv6vk666JJJJ66666J6J66666JJ6v6v9vvNvAAvvAAAvzAAAzzzXzzz1z11z1z1111z1tzt1t1tttzzzzzz",
+"iiiiiiXiXXXTXXXXXX Xdd d(ddd( (( (( (L((*LLLL***L*^^*^*D*D{{r^r^rrrrrr.ree.e.e....M..b9)9)555u&hhh&hhYYFhjRbbabab;bbxu;xZZQuQZxuQaxaaaaxSuuuSxljlZaSlxxluQlljljxuuuuQuQuQQQQlQZujjljjlQljllQQQQQQulllQjjljjlQDWWWWWWWWWWWW_dddd dddddddXXdTXXMXXXTXXMXXiiiiiii#i#p#pnnXn.XXXXn#ppJJJJp#JJJJ6k6k6*6k6vkv6v6v6JJ#JJJ6JJJJJ66666kvkvkvk6666J6666J6J6666v6v666666vvvvvvvzvAAAAzzzzzzztz1z1zt111-1t1--1-111I11iz1zvzv",
+"iiTXiXXMIeXdd X X dd ddd ( (((((((*LL*L*L*9*^*^^^*^*^^{^{^{^rrrrrrrr.ree.e.e...M..99)m)_55555uhh&hYYYYYh&Qcbbbbb;bbauaSQZu;uC;lQuuxaS;axSuuuuxxujuajQlSljjljjlZuSuSQQQlQQQuQQQQQQlZjjluuQlQQQQQQQQQQuQQjjjllQIFFWWWWWWWWWWRcdXdXX XXXXXXXXXdXMXXXXXiXeiiiiii##ipppiinXnXnnn#n#JJJJJJJJJJJ6k66*66 kvkv6kvvk666JJJ666JJ6JJJ6k6kv6kvvvvvv666D6666J6^6vvvvdvvv666v6vvvAAAAAzzzzzzzz1t1tt11-1--111111111--11--TzzzvXv",
+"iXXXXTXXXdXXd(ddddddd (d((((((((*(L*9L**L*D^*^*^{{{{{{{{{{rrrrrrrD.eeee.e....M.9.9)9)95959D55&h&hhhYYYh&&QbaaSxxaabuauabCaa;;SSSu;x;xaaxxuuuuuxxaSQlljQjQljllljuuQQuullQQlllQlQQllujjlQuQuQQQuuQljjlQljjjQjuj6WYFWWWFWWWWW9XXXXXXXXXXXTXTXTXiXXTXXiXieiiiii#pippppnnXnn####p#JpJJJ]R]6JJJJk6k6k6k66vk6vkvv66^#JJJ66666JJ666vkvvvkvkvkvv66vk666666vvNvvNvvvvvv6v6vvvvvzzzzzzzz1tti1-1---114---------1111111zzvzvz",
+"XXTXX XTIX d9(( ((( ((d (9( L*(*(*L*IRL*^**^{{{{{^r{{^r^rrrrrrreeeee..e...M..9.99)9))595D5D5DYYh&&&&&&&&&abuxxxxbQx;SC;a;Ca;;uuulxaZaaaaSuuuuSxxZlQlllljlQxxSuSQlllQQQuQQlllllQllQQjjljjjjQuljjjljjjlQjjjlljlDWYWFFYFWFFWWbXXXTXXXTXiiXiiiiiXiiiiXiiiiiiXiii#pp#nnnnXn#pJJJJJJ]J]JJ6J6k6Jk666k6kvkvk(v66vk66JJJJ66J6J66666kvvkvkvvvvvvvvv66666666vvvAAvAIvvvvv6vv(vvzzzzzzz1ttt1---1111--44444444444g----1zzzzzz",
+"TXdTdXddddd d(((( ((((((*_IL*(*L***^^^*^{{{{{{{{{r^rrrrrrrrrreeeeee.ee..M..9)99)))95595D9D_D5WF&h&&&&&h&&abaxa;bbauub;bbC;alQQllQ;l;aa;xSxxxxSxSZQZljZulxxSuuuQuQQQulQlQllluujjuQQQZuuujjljujllQljjjjjQjjjjQlcWFWYhjhFFFFWcXXiXiiiiiieiiiiiiiiiXiiXXddd9ddXnnninXXXnXn#pJJJJ]JJJkD*k6]6kk*k6k66k6vkvvkvk666JJJ6JJJ666666k6vvkvvvvvvvvvvvvv666v6vvAAAAvAzvzAzvvvvvvvzvzzzz1ttt1--i14-1g444g4g4g4g4g4g4414111z1vzz",
+"XdTd d d ddM( ((((( ( L(*(*L**L*^*^*^{{{{^{r{^rrrrrrrrrrrreeee.e.e....M.M9)55)55D5DDDD5DDDDDDFWY&h&h&&&&&aaaxabauQuZZZQZb;bZuuSQSQaaaaxxaSxxxaxuxuuQluulluuSlQSuuuQujljuQujjlQujjjQlljjQljluQlljjQllQjjjjjlQQRWWY&jhhYYYYYRXiiiiiiiiiiiiiiiiXieiXiXdd.XXeXXXXXnXnnnnnnnpJkJ]6Jk6Jk6]J6k66k66J666k6vkvvvvkv66JJJJJJ6J66kvv6kvvvvvUvvv%vvvv6666vvvAvAAvzAAvXvAvvvvvv1vz1z1tt111-11p-44444g444g4g4444444-1-11z1v111",
+"X dddddddd( (( (( (L(*(*L***^****^{{{{^{{r{rrrrrrrrrrreeer.r.ee.e..MM..99)D_DDDDDDDDDDDDDDDRDFFFh&&hh&hhh=axabbaaZuSuxQalQbCZQQZux;aaxaaxxZuxaaaQluuuuuQjSxulQSxuuQujQlQuullQjllQQljjjjuQlluQljuljjQjjluQuQujuWWhjjhFWWWWW_iiiiiiiiiiiiiiniiXXXXXXdXXiiiiinnnnnn#pp##nnpJJJJ6kJkk6k66J66kk66666666kvkvkv666JJJ6J6JJ666v66v6kvvUvv  vvv%vvvv66vvAAAAAXAvAXvzvvvvvvvzzzztt111--4--4g4g4g444g484g484gg441111z1z1z14",
+"ddX d d ( (9((( LL*(*L***L*^*^{^{{{{{r{rrrrrrrrrDDeeeeeee.ee.e...M..99.9)5D_DDDfDDDfDffffffDDFYFh&&h&hYFYRaaabbabbZ;aa;ub;;;blZQZC;axxxxxaZQllaSjljlluSQluSxSuQlSSSuQlulQjjjuujluljjjjjjjjuuQuuujjllQjQllllQjRWY&u&YFWWWWW=niiiiiiip#pp#iXXXXdddXXn#p##ppp##pp##JJJpp##JJJJJJ66k6k6k66k6vvkkkkk6vvvkvvvk6*J666666J6666k6k6kvvvvvvvvvNvvvvv6v6vvvAAzzAvzzAvvvvzvvzvzz1z1---111-44g444g4gg48484884844411111zzz1114",
+"d d d( d(( (( (*(*L****^**^{{{^IR{{{{rDrrrrrreeeeeeeee.e.ee.e.M.M.999))55D5DDD5DfffffRDffff_cFhY&&hhh&&YFRabbubbbCx;ZubCCbbxSxZlSu;;xxSaxxalujQulllQllljjjjlQljjlSuuujjQljuQQQuuuuljjjjjuQlllllQjjjjjujlljlQj9Yj&j&hYWWWWWRi##ppppppippinXXXXnini#ppippppppppJJpJ6JJp##pJ#pJJ6k6kkk6kkkvk6vkvvvvkvkvvvk(6J666666DDJ6666v6vvvvvv%d vvvvvvvvvvvvvvAvzzz1vzzzvvvvzvzvzzz1t--1-zt1-14444484:48484848441111izz1111148",
+"ddd( (d ((((*L*(****9*^*{{{{{{rr^rrrrrrrrrreeeeeeee.efeMeR.M.M.M.9.)55DDD55955DDDfffDfff____cFYY&hY&h&&&hRabubbbbbuSCb;bbu;CuaQxuu;;xxaSxauluQjljljZlQjjlQQjjjllZuuSuulljuQQQQQuuljjljlZQQlllQQlQujjjlQljllljTjjl&YFFYYWWWRripipipppppp#nXnnnpDpppppppppJJJJJ]JkJkpprDr#pJpJJk6k6kvkv6vkvvvvkvkkvvvvvvv66666vv666k666kvvvvvvv%vAvvvvvvvvvvvv6vvvXzAzzzzzvzvzvzv1vzvzzzzzzzzzzzzz1t11444888848848441111i111n44448",
+"d ( d( (( L *(**L*^*{{{{{{{{r{r{rrrrrrrereeeeeee.e.eMM..Mf..M9999)955DD5DD9D9D5DDDfff_f_ff_faFYY&YYh&hhhhRbbQbbbbbu;CQZuxuQxQSQaQu;;xSxSxSuuxZlQlllljQQjjjQxxxluxuxuSQjjQljjuuuQuuZljjZuulQluuQQuljjjQQQQlllj{j&&hFWFFFWYYrpppppppppppi#nnppp{{{]p]JJJJ]J]J]66*6kJJJp*JJJ66J6kkvkvk(kvkvvk%RvvvvvkkvUvv66666v6666666 v6vvvvvvvAvvv6v66666vvvv6vvAAzzvzvzzzvzvzvvzvzvzvvzzzzzzz1zzzti4g44444:8484441114444448:884",
+"(d (( ((*(*L**L***{{{{{{rrrrrrrrrrrrrereeeee.e.Me.M.M.MMf99M9.9.95DDDDDD5D55D5DDDDfR__f_____QFFh&YYh&YFFYfaubb;bCZbCQuxuZQCCZSZalQa;xxxxuZlSlSSjSuuQluljQZjuSSllllQjljjjljQjuuZQZuQjjljjQlQQjjQjljQj&uQQllQQlMYhhFFWWWFhYYR]pppp]pp]JJ]#nnJJ]J]JJJJJkJkJ]6*6]kkkkkJJJk6k6k6k6vkvkvv vvvUvvv v 9kvvvvvvk66L66666666669vvvv%v%vNvvvvv66v(vvvvvvvvvvzvzzvzvzvzv1v1v1v1z111zz111111111zi14444884444441114484488848:8",
+"( (( (( *9(*L***^{{{D{rrrrrrrrrDDeeeeeeeee.eMMMfRM.M.M.99M9)99)9D_DDDDD5DD9DD9DDDffff_______aFh&&YYYhYWWFRxxS;bbZxbQSSxxC;;CluQSZQQlaxxalQSllauQuljllljQulxuuululjlljljlljQQQuQQullljlQluQjjjjjjuujjjQujlQQulRFhFFFWFWWFYYIpp{*pJ]J{]JpnnpJ]J]JJ]JkJ]6]6k**k6k666k6k(6T* IivvvvTvkvvvUvvvv(IvUvvvUvvUvvv6k66666vvvv666vvvvAvvvvvv66(vv6vvvvvvzvvvzvzvzvzvzzzv1v1vz11111144444111111111114444g-D4411448488:8k8::8",
+" (( L(*L(I9****{{{{D{rrrDrrrreeeeeeeeee.eMMM..MMMMMM.9999999)99)5DfDDD5DDDDDDDDDDfffR_______uFhh&hYYhYWFW_SxbuSbSSaZub;;;;;aZZlSxaaxu;a;QZllaxujZllZluuulSuZSQQljuQuQuQZjjjQjuZujjjjjljQQllQuuQZZuuljluulQuljbFFFWFFWWWWFFf]J]JJJJJ*JJ#nnp6666k66kkkk6k6kk6k6kkUvkv MD9I99*Uv9j&RTT*] vv%vvvvvvvvvvvvvv%vvvvv66vvvv96v(vvAvAvvvvvvv vvvvvvvvzvzvvvzv1vzvz1vvzv1v111144444g4g4g4414111111144844]-441444]8]::::8::",
+"(( ((* (******{{{{{rrrrrereeeeeeeeeD.eMM.M..MMM.9.999999)9)99595DRDDDDD9DD9DDDDDDfDfIff_____jFY&&hYYhFFWFcSuSCZZaZCZCxC;;bxaZZulQQ;allQQQllQxauQlaxxSaxxSSZuSZljjxuuQjllQjjjjllljjjQjZuZQQQuQjjlQQQZljjjjjjljRFFFFFFFFWFWWR]J]J]JkJ]Jp#n#p]kkk6kkkkk6k6kkkkvkvvkXII9D9ID9Mpvv&&hu {{r r%v%%v%%vN v%%%%vvv%vvvvvvvvv(vv6vvvvvvv(vvvvvAvvvvvvvvvvvzvzzzzz1zv1111v1z1444g4g848488444444444411444414441444J8:::8::::",
+"( L* L**L****{{{rrrrrrreeeeeeeeDMeMDMM.M.M99M_9999999)999)95595DDfDDDDDDDDDDDIDffIffDfIf___f&FY&&&hhYhFFFRSuu;ZuxaSS;ubC;;bCQQlSuZ;;ZlZlQaxZaSZSQxSSxSxxSuuuSjljZuSSlQQjjljSQZljjuuuuuZuuZuuuQZQQQQQQjjjjuQlj WWWWFWFWWFFWS]6666kkk6JJ###J6k6kk6k6 (kvkvvkvkvU9=IDIM0ID[  v%v&j&&r9[D[MrpTvNvvAvXNvvAvANNvAvvvvvvvAMdvvvvvvvvvvvAAzzzzzzvvzvzzvzvzzzzz1zz1v1zz1114gg84g:488848:g4848484411414144144448]:::*::::*",
+" L (L*9*****{{{rrrreDeeeeeeeeMMMD.MMM.M99.M_9M99999)995=95959D9DDfDDD9DDDDDDDfDDDfDfDRfD_f__jFY&&hYYYYhFYR=;u;aZZ;xQZSu;;;C;CuluQZZZQZQxxxSaSxSuuaSuSxxuuuSuxjllZuSSSSuZljjjjuuljjQZQZQZullZQuuQuQQQjjjjjjuQZDWWWWWFFFWWWWR6kkk]6]6kkJ###Jkkkkkvkvkk9vvvkvvv9xbIRIID9D TekvNTljlc{[* 9D*** vNNXNNvNAvNvAXAAAAvvvvvvvvvvvvdvvvzzzzzzzttzzzzvzzzzzvzvzz1111z1v1z444g4:4884884:8::88888:484414444444448]]k:::::::::",
+"L*L* *9****{{{rrrrreDeeeeMMMMeMMMM.MMMM9_M9999999999595_D9D9DD9DfDDDDDDDDDDDDDIDIfDIDDDDD_ffjFFY&&hh&YYhYRb=ub;x;a;xaxSabbb;;CuuQaaaQxxSZxSxxxaxQuSuSSuxuSuSjulllSSuuuZuljQjjjQlZQQuZQlQZljjlQjjjjjljjjjjjjuQIWWWWWWFFFFWW=kk6k6k6kk6JJpJk(kvvkvvvvUUvUvvvT=&=IRI9DI909D*NMMkIDk%kTM[9D[9 9kAvTvAAvAAAAANANAvvvvvvvAAvAvdMvAMtttttt---tz(ztppTiznD=bXJv1z1z11148:88488488:8848k8:8::::8444141p14888:::::::::::::",
+"( *9******{{{rrrrreeMeeeMMeM.MM.MMM.9999M_99999959595I99D9D9D9DDffDDDDDDDDbIDfDDDDDDDDDDDDDf&FFYY&&hY&YYhI=bSb;aZaSZZuZab;b;;CxQQQaaxaxalaxxxxaaSaSxSSxuSSSxllxSlZuSuZuuljlQlljjulluQQlQulljjjjjlQlQQQljjljuQIWWWWWWWWFFWWRkkkkkkkkkkRpJ6kUvkvvUvUvvvvvvvTu&bRRIcf0RDDDIM9]]9DI9I;cMM[0De[*  AAAvAAAvNAvAAAAAAvvvvvAvAAvAAzzT-ttttt--k 9MTTTT]]R&&jbMTTTv11144848488::8:::88k8::::::8::884444g484:::::::878787::",
+"********{{{{rrrreeeeeMMMMM.MMMMM999999999=9)59599D9D95DD9DDDDDDDffDDDDDDDDcDDDDDDDDDDDDDDDDRhYhhYh&hhh&hlRbbbb;;x;SSbaCbCbb;b;CZuSSSuaZuuaaxxxxSSSuSSxSxxuajlSSQjZlQuQuZuQlljZjSlQluuZjjjjjuujjjjjjQQlllQjlZQRWWWWWFWWWWFWbkkkvkvvkv(kJ6kvvUvvUvvv%v%%vNTl&bRRIRIIDI[IDIDI* 9IDclQM[MIeD09 M9*TAAAAAAATAAAAzzTvAvvvzzzzzzzz--------T9cRVk]Tp]]p9SQjlDT T4Tz14888:*8:8:8:g::::::8:8:::::84444848::::::::787878787",
+"*(*****{{{{rrrreeeeeReMMDMMM9M999M99999999)I99D9D9D9D9D9DD9D9DDD_DDDDDDIDDRDDDDDDDDcDDDDDDDDj&&&&&&&hYh&&IbSu;abaZxbbbbbCb;b;;CxQlQuSZuuul;axxSuSSSxSuSSxSjljuljjlljSluQZZZjlQuuZjulujjujjlQjjuuQZjQullllZjjQkWWWYYYYYWWWWRkvvkvkkvkv6J9vUvvv%vv%vTNXNNix&lcRIRIcDII9D0DID9DM0DDDDDDMrIDDMp[9[*TAAAAAAAAzzzzzzAAAzAzzztzti-------gDabRTi%  *]]] ah&SM]]k% iA8::88888:8:::]k8:8:::::8:8:::88::8:::::::87888%8o7:U",
+"******{{{{rrrreeReMeDMMMfMM9M99M9999999)_I)9D959D9D9DD9DD9DDDDDIf_IDDDDDDDDDDDDDDDD9D99D999D&&&&&&h&hYYhQcuaaSxbbxbbCbC;bbC;;;;aQZZllSuZlu;u;aaxxxSSxxxlljlQllljlljSuQQZQQSjQQjlZlQjjjjuullljlluQulZZQlllQjlZDWWYYYYYYYFWWcvkvUvUvUvUk6*vvv%v%XNNNvANAX=&hcRcIIRIRD0000D0D0D[DIII0I[M[I90{ *[DMkzzzzzzzzzztttttzzet-----4[4-g4g4IaSSc  p]i   ]g%RD[A%A] kTTkNt88:::::::8: k8:::8::::88:8::::8::::V9@9oNUVDCjjjU%",
+"*****{{{{rrrreeeDeeMMMMM9M999999999995999959D9DD9D9DD9DDDIIDDDDfD_DDDDDDDDDDDDDD9D9D9D9D9D9)&Y&jh&hhhhYhbcCuSuZbZSb;;bCS;bbb;;C;;lQQluuZlQQSaaaxxuxuSxQjlZuuulSSQllSSuZQZuulQZuZjjjjQjuuuZlZZjllQujlZZQllQlQZIWWYYFWFYYYFWlv v%vvvvvv66vT %vNNNvAAMTAzIhhaRIRRIIcIIsoo$oo0ID0ooID0o@[[MIDM {MM[Mtttttttttttttt-------4g-g4-g4g4U=;uc* *TT]T*  p]VTiI=u]p  ]kpT-::8:8:8:::8::::::::::::::::::::tT9c=M]kT%T=hY&&]T",
+"****{{{{rrrrreMeMeMMMMM9M99M9999999999D9D9D9D9D9DDDD9DDDDDDDDDDDIfDRDDDDD9D0D99DD9D9D99c9999&&j&hhYhjhhhubCaxxxux;C;;C;bb;Qx;;a;;aZulSuQZuxlSaa;uSaauuuQQluQZuSSlSxSuZZuuuSlljjulZZQlluuuuuZZujlZQujjjZulQlulRWWYFWFWFFYYYRUvv%%%v%%vk6%%vANvAAAAAAAzz&YjRcRIIIfRc0oo000oo00Mo0IIoo$s@oo0[9[*D * ttttttttt---------g-g-g4gg4ggkcllbT*  T]kpTT*]]k  9cIkUkpk]T]-8::::::::::::::::::::::::::::: Rbx= kU]T]TI&hYh]]",
+"***{{{{r{rrreMeMDMMMMM9M9999999999599D99D9D9D9DD9D9DDDDDDDDDDDDDffDDDD0D9D9D9DD9DD9D9D99999)h&h&&&hljhYYxxSSuSbbbb;a;;abSbZSb;a;;xlllSuuuSxlulZZQuxSuulllllZuxSSSSuuuuuuuuullQQluZuulZjQlluZQZuuulZlQjljZZQjj*WWYFYFYFFYFYbv%v%vN%Nvv6vANTAATAAAzzzt-IYYaIIccIIIIc000I000o0I0oo0Io0000oo[D9D[M [e%--tpT----t------]-g4g4gg4g4:cl&&DT  *TTUT]TpU  T T]%iN]T]T]]-]-U::::::::88788o788o878878:8 b;;cTkkUkpU[&jZSIkU",
+"*{{{{rrrreeeeeMeMMMMM9M9999999999D9D99D9D9DDDDD0DDDD0DDDDDDDIDDDIfDD0DDD9D9I5D9DD9D9D999999RY&h&Yhuxhh&Y=axSZbb=ubbaabCbb;bxC;;aaCSaluaZlaxxxSSSxSuSuullllxxxxxSuuZuuuuSuSjljZjuuZuuljlljuZQQQujjSujjljjlujjj9WWYYYhhYYhYYRUvNNNvvvvvkNAAAAAAAAttttttlFhIDIDRRIIDIIoso0oo0IIIooIIo0000oo00I[ TT*9*]t-t--t-----g4g-g4gggg4g8g8I&lj=T *  ]ps ]TTUT (  TvN]TkpT%k]]TT:87887887878788878:88788>[xSlS ]]kTT]N]U]V]IR[",
+"*{{{r{[rrr[DeMeMMMMM9M999999I99D99999D9D9DD0D9DDDIDDDDD0DDDDDDDDDDDDD9D999D5D9DDDD9D9999999cY&&hY&au&j&&u=ab;bbbubaaC;;aCbCb;S;C;;xSxlSaZQxxxxxxuulQllxSlaSSSxxSuuuuuSQljlllZjuluZuSQZuZuuZQQZulljjjjujlulQljIFFFhFYYhhYhhIvvvNAANv  vAAAAAztttttt--TFFlRIIIIRIIIIcoo0o0o0000o0000o@sooo00D*T *[ 9U--------]-4--g4gg4g48g8R8]hY&&9TT* *Tossss@s   okosss@s %]Tk TV7878787878787878787788789SljuIT]kkT]]]%]TTpC&I",
+"{{r{r[rr[eeD[eMMMMMMM99999999999D9DDD9D0DDIDDDDDDDDDDDDDDDIDDDDDDfRDDD9D9D9D5DD9D9D9999M9MMR&&jhhjbxba&&=b==bbbbabbaaa;;;bbbC;;;bC;ZlllxZQlxxxxuZulllQuQxSSxQZxxSSuSxQjjjlluQlQuuuSjjQuZQQQZZQuQuuuulQQllllZQMFYYYYFYYYYYYIzvvNvNvvvvAAAztttTtt-----cFYlII_DIIcRIIIo0I0oo0I00oo000o000o000I*[{M T9[4-g-g-g--gggggg4gg8g88*88DY&Yu TT*** Vs@ooPs@TVs@]@ssssso]Tk TTV78787878787878787887878=bbSckT]kUTT]TA%]]Tk[p",
+"{r{[rrereeeMeMMMM9DR9M999999999D99D0D9DDDRDD0DD0DDDI0DD0DDDDDDDDDDDDDDDD9DDD9D95955999MMMMMRj&jhhju=_=lu_S;bb=CbbZbaa;;a;bbC;;bCb;;;CaluQlSuu;x;lllQljSxaxlQSZxxxllZjuuuQjjSZljuuZulQluQQQuZuQulQuZZZllZjjjlZIFFYhFFFFYhFYcvvvvvvvvvMzttttttt-------=hhbccIIcDIDIIco0IIo00900oo0I0o0000IMIr[MM[Mr0Dgggg-g-ggg-g4]gg8g8488888jY&hI[]TV* *Ps@oPP@] @@VPs@ooPo T]k]kUV8787878787878787878787IIRxuM]UT-%TVTTNp]Tk-T]",
+"r{rrr[re[eMDMMMMMM9M999999IR9D99D9D9D0DD9DDDDDDDD0DDD9=_DDDD9D9D9D9D9D99D99999999959MMMMMMMR&&&hj&&ubRc=DCx==;bbbxbx;;C;;CbQSuSuS;;;C;SZZQSQZZQlSlll;SSZQllllxSSlllQuSQQlQlxZuuuZujQjuSZQuuuSulQQZuuujlljjlQQ_FYhYFFYFFFFYIvvvv%vNvTtTtttt--{----g-glhYccI_RDDI9[DIo0000oo00[ooo00o00II0ID[M[{*M 99kg-g4g-g4g4ggg848g888888]Fhhh9**TT *[Us@s@ssoT s@]so@os@@V]%NNAT]87878787878>87888788VcR;xRPNUTt%]s@ss@T]stV@",
+"[r[erreeeeIDMMMM9MM9M99999999D9D0DD9DDD0DD0D9D0D9D999D99D0D9D9DD9D9DD9D59D999999599MMMMMeeecj&FYhh&j=R=bM==xubCb=Sbxa;;a;baQuQuu;xbCC;a;;;;xQlQQZ;;alQuSxlQljZllZuujljjxlSuZljSuuuQuSuSuZZulZZZQuZZuujQllljQjDWFhhFFFYYYFhRvvvNAAttTt-Vt---tg--ggg-U&YYIDIIcIID [I0I00II00 [0o0oo0o00IIID0M9[*[*T[  g]ggg4ggggg]8g8g8888888R&hYh T*[]TT]o@ooo@oV ooV@o@@@@sV]N-NUtTN88888888887888787887[cS&&Dk-]UtTVs@@@sT@stos",
+"rrrr[e[eMMM[MMMMM999999999D90D9ID9D0D9I_D0D9D9D999D9D0D99999D999D9D9999995999999999MMMReMee;j&h&h&&ucbuuI==bbbbbbxb;a;babb;alaaSQQQC;;aaxaa;uuQlZxllZuulQllZllZuSZjllQlxSxlljSuuSjjuQuSZuuuuljululuZZlQZlljQjIWYhYYYYYYYYhcNNAztttttt------g-g]-g4gg&&jRIIRIRcIDIIII0IIII0 MI00[[[o0I90D[D9[M[D**[MT]]g4ggggggg*8g888888888=YhF; [TTT T] so@oo@@V @oVosPPo@g%gz]k]]]:78787878788888I8>7Pxl&hj U]U]NUUsoPPs@V@oV@",
+"r[e[eeMeM[MMMMMM9MM99999990DR99ID9IDDDDD9D9D999II09999999DI90999959999I9999)999999MMeeDeeee;uxl&h&lbbub;_;=a=bbb=Sb;aCaaCbCbZQZSxSSZlQQuQQQZQZaSuZlSZZjlllQSQlQZSQluxSSSSjQlSSlulullSuuQQQuSujjjZuQZQlZlljljQgYhYYhYhYWWFhbTAttttt--------g-gggggggk&l&RRIRI*M[[D90T00II0[MIII9[*[M0DID9ID[IM[[I **[]4ggggg48g888g888888:8:cjYYZ*[kk]T%N[os0o@@  o@ Vo@VPoVNk%]TTTV]P878878888>88888:888&h&&;%t]%kNTo@s@s@V@s]@s",
+"eeeee[eM[MMMMMM9M9909I99D9D99D9D9RD9D9D9D9909999959I999999M9999II99999.9999999M9MMeeee[r[rDQlQlQj&lcbucc9a=b=b=bbub;aC;axCaxZZSuZQQaaxaSuQSxxuZuxxxQ;xx;;lSSQZluullSSQSZZuxSulljQZjlluQllZZuZjlZSZZQZQQZZuQluIYYYhYhYFWWWYbAtt-----g[g]*]ggg-gg4gg8 jj&IIIID T   U]T]]UNTTk%%t]]%k]k]oTo* [*  r[{ *[4-g4g4g8g8gg88888888888cZh&S ]TN%ktU [oo[os@o @@oV@oo] U  Tk ]kkk88888>8788788888880h&hj=Vkt]UN]VsPso@oVsPU@",
+"e[e[eM[MMMMMMMMM9M9999990990D9IID0D0DD0D90D9D999999M9909MMMMMMM9999MMMMMMMMMMMMDeeee[eeer[r&h&&j&&u=abcc9b=bb=;b=ab;;Caa;xCSZx;SZlZuaaaxSluZZQuxlSaSxxxaZlZaaxuSZuZlSxuZuSZuljlujxjSSullZuuZljllZZQZSlQluuujZMFYFYYhhYFWWF=*Ntt-tg--g-g-gg-gggggg8gT&jhcIRID      TTTTT ]TTTT]]]T]]]]]kUUNNNztk]M0D{t--ggg8g8g8888888 :888UlSj&cTT{]  N  ToV [0oo@@oooVV]]TTUTT U] ]U87878>88888888888-IYhh&=]]tTT-UosP@@soos@Ps",
+"ee[MMMMMMMMMMM990999IM9D9D9D9D999D9DI9D9I5999D099999DMMMMMMMMMM99MMeMMMMeeeeeeeMDMrereeeeerjh&hhh&u=cRcjf=b=bSbCCb=b;b;aCS;uZuCCuQ;uZlZQQQ;;CaC;;;axa;;x;axxxQluZlSuZxxxllllluSljxSZuQQuSuSujllljuZuuljQllSSl[WWWFhhYhYhYFa *%-gV-g-gg]ggggg8g888g8 j&&ccRcI    TTTTTTTT]TTV]T]]V]]Vp]]]]kkk]kU M9I  --gggg--88g8888888888glSh&RV {T%]]kVT]TVoT[ TVTT ]ViV ]kTT NN]T]g888888888888gg8ggRhhhYlVkTV]%UU@@P@@@os@PV",
+"M[MM[M[MM[MMM90M999M990990D0D0D9D9DMI9D9I9D9D99999MIDMMMMMMMMMMMMMeeeeeeeeMeeMeeer[r[re[eerh&&YFFhQbcRQ&Rb==C;SS;=ba;C;CSZZuZCbCbxxSSQQCC;axaa;;;axxa;;;xx;a;QZxljSZZllSZlZjZZZZZZuZSuuuSSuQlZlllSSuSjlljjSSjRWWWWFhYhhYFFa[ *U--g-g-gggg4ggg88g98gM&jjIIRIR     T TTTVTT]TT]T]]T]]]]]]]]Uk]UUUVD{0DA--]]9[U]VDujkt]8 88g48&&&h=] [kggg888:88:8:g8:g:gg4gtANU]kUtk]]V88888888888gggggg-0hhhh;VTU]]NTVPPoPVVoooUU",
+"M[M[MMMMMMMMMM999M9099D99D99DDDD9D99999D99D99999999MMD0MM[MMMMMMMee[ee[e[rr{eree[rr{{rrre[9YY&YFFhjQuu&&I=b=SxSSCbb;aabba;;xSbCb;aCbxuSCCa;;;;;xxxxa;xxSxxuSaxxSSulZjlZQSSxxSSuSSSuSSSuxluuZluQjZjjxljZQljSQjIWWWWFFFFFYFWl[[* Ugggggg9ggg8g888k g8Ujj&RDIcI   TT TT T T] T]T]]T]]]T]]]kk]]]kkkTMIDD ]DcMV]kVN9&j T]T%gg-gg;&h&=]]kkg4gg8g:8888:888:8::8:::8:::::UTUUV88888888gggg]gg--9h&&hSV]%U]%VUUNUV]V]VUVU",
+"M[MMMMM[MMMM0M9M90999909909D99999IID9D9999MR999999999MMMMeeeMeMMM[Drr[r{{{{{[r[rr{r[{[{[{r*YYYhYFYjQjl&Yc=ab;Sbaa=bbbCbabCxZxbbCauaZSa;CbC;;;a;xaxSxxSxxxuZux;aaaSlllZxSSSxSuuuuuSSxlllSujQlZllQjuuQuZSjjlSxl FWWFFFFWFFFWj{ [  -g-gg-0gggg888g8888gl&&cRRIR   T T  TTTTT TT]TV]]V]]]]]V]kkUkUU [*IDoRc[VTT]]g]I[ T%]-%4g-gSSjjR]%]]gg4g48g4888g8888:88::88:::8::UUA]]888888ggg--gggggg0&&&jZ]U]7:7::g7:g:gtNN]]",
+"MM[M[MMMM0M9M9099990999D059D0D99DMMM99M9990999D9ID99MMMDD[[ee[eDer[r[r{[{[**{*{{r{[{{{9r***YYhhYFFjQ&&FhR=Sx=;CCaSSC;aC;aSuuuuZa;u;SCbbCCCa;;aSaxaa;;;xxxSuuSSx;aualSSSuSuuuZuuuuuuuSjujjjlZQQlljulQZZZljlluSTYFFWFYFFFWWWj[[[[MTggggggg8g88g8888888llj=ccRI        T TTTTTVTpT]T]T]Vp]]]]U]]]k][[0D=C*T%]TUVAkNcj[Tog]kgggccC&=V]T g4gg8ggg8g8888:88:888:8:88:8:Nk]kV88888P8ggggggkggg[j&jjZVAN:78778787:787:7:",
+"M0DIMM[MMMM0MM9M909999099D99990990DM90MM0DMM90DMMMMM9MMM[eee[eee[r{r{{********[{[{{{r{[***[FY&jhFY&&jYF&c=bS=uSbu==b=ZSbbaZSaSZZuZxuu;bbub;;;xxS;;llSZlxSSSSx;lQluSxuZuuuuuuuSxxSuuSSllulljujZljjjlullQZuQluS[YYFWFFWFWWWhS[*M[[ Ngggggggg8888888888jl&cccII*    TT TTTTTVTT TT]]T]]]]V]]kk]k]UT[D{0boUT%]]U]]TU]k]TTT]]]g8cbbZl T]]-gggg4g84884888:88:88::88:8:8t]k]T888PoUgggg-ggggg8Pjj&jjUUUg7878787878787::",
+"IMM[MM0MMMMM90M90990999D9090MMMM[MM[MMM[MIMMM[[M[M[MMMM[Me[ee[e[r{[**[*0** [ ****{{[****** hh&&&FhYhhFFjR==babx;xxCbabbCZSS;xS;SubbZZZ;CbCCCbC;SxxZQQuQ;SuuxaSZZZaSuZSSuuuSSSSSSxSuxlljZjllululjlZuZQjQQuluSZTYhhFFWWWWWhla]   *[Tgggggg88g888888gggjj&=cRI9  * *    TTTTTTTTV]TVTVi]]T]]]V]k]k]M0D[IkVUT]sssVU@PUT]tVTUg]g[SZjj[*TT-g4gg-gg8ggg88g8888888888:8888V8VTg888UgggggggggUggojjlZZ N%N878787878878878",
+"[M[M[DMMM0M0MM9MMMM909909MMMMM[M[M[e[[e[e[R[[e[[[[e[[9eeeeeeer[**[*** *** * ******* * *[ *[&hhhhYYYhFYF&c====;;;CauuCCbbbbxbbb;ZSCZZxCb;;b;SSaauZC;;;ClZax;ZaSQQ;SSaaSSSSxxxxxxSxaSZQllllSSjllllluuulQZlujZjl YhhhYWWWWhQjl ]V  M[ggggg88g8888ggggg-lj&b=IID      T TT T TTTTTT]T]]TVT]]V]]]]]UT[90M ]kVVPsP@sPs%PsssTU%kkUDjlQj*[  g-g4gg4gg488gggg88888:8:88888:]%%UgggggggggUggggPggP&jl=S*tNP787878787878787",
+"M[M0M[[M0MMMM0M0M0MM999MM[D[[[[e[[[[e[[[[[[[{[r[{[{{[[[90r[[r9**[* [** 0 ** [  [ * * *   *IjhhYhYYYhFFYZbb===;=CxCSbbbbbb;CC;bCbbbbZCxZ;;auSQubCCC;;aa;uQZxZSlxaSZxaxaaxxxxaxalZxxjluZSjjSuujxlZjlZuQjuZZujuQ]FFhhhYFWW&Zhj** [ [[ ggggggggggg-g--- ;Cj=cR[I*         ToT T oT TVT]]]]T]]]]k]]]]90D* ]]%]Usss@osVUs@sso]UV][ljjjD[[T-gggg-ggggg4gg:8g8g88888888888UkgTggggggggggggggggPgZSCCZIg%]888878888788788",
+"M[MM[MM0DMM0M[DMMMMMMM0M[[[[[e[[[9r[[r[{[{[{[*[*[*[[***[*[**M0[*[**   * *    *      *   D[c&jj&YhhhYYYYuCbb======xbbS;a;bbbC;;;;;CCbbbQZuCC;C;aaa;aaxaxCZSSu;;aSxaSx;a;axaxxxaxllZSuuSlQulSlljllZjZulllQQQQjlDFFYYhYhWW&lFj[[[[ [*Uggggg-t---g-gU]gUcSZb=IDc  * * *  T    TT  VTVTTTV]]T]V]]]]kV[{ 0[TV]oo@@sPPsVP@@s@UV]UVDSZjjI [Tg---g-g4ggggg8gg8g88g888888888V]t@ggggggggggggggggggSljjj0UNV78788787887887:",
+"[M[M[M[M0M[MMM0IM0MM0[[[[e[[[[[r[[[{[[{[*[*[*[******0** I[* [  [[*  [  0* [      [      0Icj&&j&Y&&Yhhh=bb;;bbb==bCabC;Zbbuabb;;;CbbC;C;;;CCbCCbCCC;xxaCSSuCa;xa;lCxxx;xxx;xSxuSSuZuSQjxxljlZlZlllullZjlllSZZcYYYYhYhhW&&F&  *   [oNNttgtgggggggggggbulCcRII[* [ o      T  o TVTT]TT]VV]]]]UV]U]  [* N%TTPsosoVPVUsPPPV]]]V[jj&l0 ]]tgtg-ggggggg4gg488g88888888888kV%]gggggggggggggggggg=jjl&cNNU888788878788788",
+"[[M[[[[[[M[M0M9[MMM[e[e[[[[[{[*[[[D*[*[*[*[ **[0[ [[[[ [ [ * * *      *                   I&&j&&hhhhh&&Zbbbb;bb=S;SSSbS=bCSSxCbCZSxaCbC;;;CCaSSZlQu;xxa;Cal;C;Z;ZaSSSxx;;xxuSxZxuuQuQxSxSuluSlZZZQSjllQZllxuZgYYYYYYhhY&YWjUUN%T * ToVggggggggggggggZjQ;cRI0           T TTTTTTTTTVTTT]V]]]]]]]][D[MTUUoTo@o@VVVU@PPo]]]]V%[&ljjI UTtgttgt---g--ggggggg8g8g8888888]]]Pg>ggggggg>gg>gg>gsjjjjjRtUP878887888878888",
+"[[0I[M[M[[MMM[M[[[[[[[[*[*[*[*[**00[* [ [ *[ [ [* [ *  *[ [0     [                      [ R&jj&&YYhYY&habbbbb===bSSa;;abbb=b=bbbbCxxxaabC;uuSxa;uxC;;uCx;lx;allCxSSSuSaSSSxSSuuxSxQlSxxxlZluulZjSuZjlZlZjxSSl%YYhhhhhh&hFWjUUUNV[[*@]Tggggggg>gggggVSllCcc99* [*       TToTT@TTVTVTVTVT]]TV]V]]][[MD[V]kUNUVVU]U%VVU]]VVV%V &&ljI]* UN-gtgtgg-ggggggggggggg8g88888V]k]gggwgwg>ggg>gg>gg>I&&llc>TV888788878888787",
+"[[[[[[[[[M[[[[[[e[[[*[*[*[*[[ [ [*[ [ [ [ [  [  [  [  [     *0   o    o   o       o    o [c&j&&hYFYYh&&R==b=====SSSxxS=bbbbCbbbC;;CCCbbCbuS;SZSZbC;aCQCxx;CClx;xSSSxxSxSxxxxSClZxSaSZa;lSZlxuxSSxxSllljZSSSlZth&hhhYhhjYWW&UU%Uk[M[TVVVggg>gggggg>ggljl;Ic0I[ [          TTTTo  T]TVT]]TV]T]]]]][[0[*T888888888888888888-VT@l&ZjM[ *UtgNgtgttggg-gggggggggggg88g88T]UP>g>ggggggPgg>gg>ggclSCcIU]N888888888888888",
+"[[{[[[[[[[[[[[[[[[[*[ [ [ [ [ [ [  [ [  [  [   [o        [        o    o o [o o o  o o  o Cjj&&j&YYYYh&0====abbbx=b;Cb====bbCbbbbCb;bC;bbCCZZZZZZx;Cu;;a;a;CZ;;SSSa;;xxaSxxxx;llxZ;x;SlZlluZZSxxxuZQllSZjZSZlThhhhhhYhjhWWjPUUUV[[ VVTNg>Pgggg>gggg>=jlcc9II[*           oToT TVTTVTVTTTV]V]]]]U[M[M[P88888888888888888888]V;lZS[  okttgttgtgtg-ggg-ggg-ggg8ggggggU]TUUg>gPgPgPg>gPg>gPgoc==cIPVt888888888888888",
+"*[[[*[[[D0*[*[ [*[*[ [ [ [o[ [ [  [  [ [[[   [    [       o o  o o  oo[o o o o o o[ o ooo*b&jjj&j&&&Yh&_c==CbbbSxS;bbx==b=bbCbbbCbC;;;Cb;xSZx;;aZCC;Cxxaaa;ClS;aSxS;CxaxSxxaxxuQxSx;SQllllQluSuSuZZjlllZllxQZ]hhhhhYh&jFFFjUUUUV*[[TVVNPggg>g>gg>g>gZSb=0cRI[ [[         T T TTTTTTVTTVVT]V]VV]VT[[ [V88888888888888888888]VSZl=0[ T@tNNgtgttgtgtg-g-gggggggggg8ggU]V%PPgPgPg>gPg>gPg>g>oc=S=R%%N888888888888888",
+"[ [ [[*[[*[ [ [ [  [o[o   [o  [o[   [o  o   o    oo o[oo o  o o o oo o o o ooooooT ooTo oobjjh&hhhh&jjC[==bbCCCbS=SSCSS=====bbbbbbb=bCbbCuS;xu;CaCxZCSxC;Sua;xxaC;SC;C;x;S;xCCSlx;;luZlSS;llluuulllZZZllZ;lQZ]FFYYYYhlhFWWjVUUUV[[[ VkVVPN>g>gPg>g>gcCcIcRIIM       o       oToTVToTTV]TV]T]]]V]T9o[*Vggggg8g888888888888NVVSjScI[*oTtNgNNgNgNgtgtg-gggggggggggggg] UVVg>gPgPgPgPgPgPgPg[=CS=c>gV888888888888888",
+" [ [ [ [ [ [ [ [  [o[  [o[o[o[o  o[o o[o[o o[o[o     oo o o o o[ o  o o o oTo To oooToToToQ&&j&&&&hhScc bbb=Cb;=bSb=xSab=bSS==uaSS;;CSS;uaZCSS;ZbC;CC;CuSSSZ;;;auCuSC;C;xaSxa;ClZ;;ZS;Z;SlZllZZllllZxZllu;;lZVFWFFFYQlFWWWjUPUU] [ Nggo]VP>g>PgPgPg>ISCcccII0   [  *  o o oT T oTT VTTVVTV]VV]V]V[9M[Vgg8g8g8ggggg8g888888]V=lZxI*[ Vg>tNgNgNgtNgtttgggttggggggggggoUTVPgPgPgPgPgPgPgPgPs==C=Io]V@88888888888888",
+" [o[o[o[ [o[o[o[o[o  o[o o  o  [o[o o o o [oooo oo oo  o oooo o o o  o o o o oooTooTooooTox&j&jj&j&lcRbrbx==CbbC==bC;xCC;b;axSC;;;SxS;SxSSSSuSZZZaSZxuZZZbbC;;ZSxZxZxCC;;xSSxaaaQ;aZxxxxSlZZZlZllZlZZllZCxlZZ*YFWFF&lhFWFWjVUUPV[0 ggtVoVUgPgPgPggPgClj;cIII*      [ *    T o T TVTTVTT]V]TVpVTV]*II[Tggggggggg8ggggggggg8P]ClSCc  [TNtNgN>gNg>gNgNgttgtggggggggggg]%VVNPgPgPgPgPgPgPgPPgC=cCC0V]V88888888888888",
+"[o[o[ [ [o[ [ [  [o[o[o o[  o[ooo[ o[o[o ooo  o o oo ooo o   o ooo ooooooooo*o ooooooVooooQh&&&jjjl==ajIb==C=b=;=;C=;C;aCaCabbCSSZ;bbx;SS;CC;bbbbbxSuSxxZb;aaCZZx;auCC;;;;xSS;xCZSCuau;ZZZxZZ;;ZZlllSlSxx;SaZVYFFWYl&YWFWWjPU]]][[ g>NoU]V@gPgPgPPg@CjjlRc=I[[[  [ [    o o TTo oTV  VTVTVTVVV]T 0[0[Pggggggggggggggg8gggg@VcjZZc[ [ N>gNNgNNgNtNgNg>gtggtgtgggggggU]UVgPgPPgPPPgPPPP@PgPZZCCZDVVV88888888888888",
+" [o[ [o[o[o[o[o[o[o [o o[oo oo o oo ooo o o ooo oo o o  o oooooo ooo o o o o[oooToVoVToTo[j&hh&jjjuaSj&9=c;=bC;;====xSCb;xCbbbbSSS;bCCub=bbCCCbbxZCuCSC;ZCCCC;SZZSaZCCC;;;xSxS;CSZ;lxxQZlS;xlxxClllZZSZSCSSlZ hYWFjjYFFWFFjVUPUoT otgNV%PPVPgPgPgPP>cljScIRI0[  [ [oo    T oToTTT oTVTVTVVTV]TVVTD0e[Vgggggggggggggggggggg@VISS=C[ [ >NNNg>Ng>Ngg>gNggNg>gggtgtgtggUVVoPPPPPPgPgPgPgPgPPgcZZCSIVTVgggggggggggg8g",
+"[  [[[[  [  [o[o[  [ o  ooo[o[o[o[[o o o[o o o o o[o o oooooo oo@oooTo[ ooToo TooooTooToo@j&j&h&jjuSjjlDcC=;x;xa===bCCx;C;bbC;xx=;b;uSb=Cx=bC=xSSSS;ZZSCZZ;ubSuuZZxCS;C;;;xxxCx;;QSCSlZSxuS;ZSSCSZCClZZZSSllSVhh&&jhFWFFWFjP]VU][ og>googV@gPPPgPPg>cllC0ccc[ [     [  o o    ToToToTVTVTTVVTVTV 90D[@gggggggggggggggggggg@oI=ccCToo NNg>NNgNNg>NNgNgNgNggNg>gtgtgtUoT]PgPogPPgPPPPgPPgPsIZZSSIVVV8g8gggggggg8gg",
+" [o[o o[o[o[o    o[oo[oo[o ooooooooo o oooo o oo ooo oooooo ooToooVoo@o ooooooooTooooTo@T@j&&jjjjlxuh&jIc=abC======CCCxbbbCabSSSCbxbbSSCCCS=bbSx;SCCbZCbbuxSCCSCZZCC;CC;xax;x;xCCZSCSZZSxlSSxSlCxSCC;SZ;ZZZlZ]&lSjhFWWFFFFYP]P]@ 0oN>N@oNPVPgPgPgPPg0lZcIcII0  [o     [    oTo ToTVTVTVToVTTVV]V I00 @tg>gg>gg>gg>gg>ggggg@VIC=c=V]VV%NNNN>N>gNgNg>Ng>gNgNgNgg>g>ggVo]VPNPPPgPPgPgPgPgPgPICCCZc@Vogggggggggggggg",
+"[ [o[ [o[    [o[o[[  o  oo o  o  o o o oo o oo o o  ooooToooo@oooVoVo@oo@T@TVoVoooToVo@@@V&jj&jj&jZajjZI=CCC=bc===bCaCxxCCbCa==CCb=bC;==bCb=x=CSCSZCxbbCbSZSubSCZCCCbbC;x;C;;x;xCQZCCSlZZZZZZS;ZZllZZZSSZCCCS jjul&hYFFFFW&P]V]o[0ot>tooNo@gPgPPPgP@IcIc0ccIM[   [[  o o o o  oToToTTVTVTT@TVTVo DM[ @>gg>gg>gg>gg>gggwg>gPV0=Cc=o  oN>N>NNNNN>Ng>NgNg>gNgNg>gNgg>gTo @NPNPgP@PgPgPPgPPPo0C=CCCVV@gggggggggggggg",
+"  [o[o[  [o[o  [o[oo[ooo  o[oo o o oo o  oo[o o o oo ooooooooT@T@oo@oVT@@@@ooToV  o@T@oV@[jjjljjlu;au&&cCCC==Cc=cCxxC==C;CCb=;;=b===Cbbb=b=b=bb=SxCbb=bCCx=;CbbZSbbb;bC;;x;C;;xSaCZZCxZZSZZZZSSSSZSZZSlSxC;;Z[jljjj&hYYYFFF@P]PUV[ >N>VVg@VPPgPgPgPgIIcCII0D[  [[o        o o o oToT@ToTVTVTVTVT 00[ ogg>ggPg>ggPggPg>gg>g@V0cZC=[[[o%N>NN>gPgNN>gN>N>gNg>gNgNg>gNgoTooPNPPPNPgPPPgPPgPgP0CSCC=ooVggg`ggg`ggg`gg",
+"o[  o[o[ o[o[[o[0o  ooo[o oooo oo oo o o o oo oo o oooooooVoVo@o@oVoVo@Vo@oV@@@@o@oooVV@oV&jjjjlbcal&&jRCCc=;=bCaaCCb==;;x==b=======b===b===b=b=Z==bbCCbx;CbCbCZxCbCbbb;aC;CCC;xx;SZZZSZxZZZZZZSxSSZZZSZ;CClSMQj&hhh&&hhYFhVVVVV[[oN>NVPNPPPgPPPgPPPcSZ=I0II0 [         o  ToTo ToToTo VooTVVoVT@I0D[@og>gPggPg>gPggPgg>gN@T0ClCC[[*oNPNPgPNNNPgPN>NNgN>N>g>g>Ng>gNV oT@PgPNPPPgPgPPgPgPP0CSZ=C@T@g>ggg>ggg>gggg",
+"  o[   o [o o o   [o  oooo o o [oo oo o0o o oo oo oooooVT@oVo@oVoV@T@@@oVoVVT@@V@V@VV@@@VIj&&jju=bj&&&Scb==;b=bc=;xx;bc========Cb===b=bb=bbb=CSSSCSbbb=bSSCCCbC;;SbbbCC;;aCbC;CCCCCSCCZCxZSZSZZSCCSSC;lZSCSZS l&&hYYYh&YhF&@VV]V[ [>NP@oPVPNPPPgPgPgcZZ=III0*o[[o[o [  [o   o  oo @ToVToTToTo]oVT0I0 o@>gPggPgPgPgPggPgPg>Po SCC=[ [ PNNNPgPNNgPgNNgPNg>gNPgPgN>gNgPVooVUPNPNPPPPPPgPP@Pg0=S==CoPPgg>g>gg>gg>g>g",
+" o[oo[o[ o o[o[[o o o o o oooo[ o0[ ooooo oo oo oo[oToVooo@oTVo@Vo@@@T@VVVV@@@T@@V@T@VV@@DjljQj;=Sj&j&Q==b=c=cccC;c================b===b=b=xx;Cbb=;Cb=xSxSb;;=ZC;bCbCCbbCCCCCCbCbCCSCZbxZSZZZSS;;;ZCx;CxSZZSZt&hhjhYhhh&&YYVVVPVo0oPPN@VNP@PgPgPPPgPIZZCI0IR0[ [  [ o[ o o oo oT oTooToTVoTV@TVVT0D0 o@PgPgPgPgPggPgPgPg>N@@@=C=C0[o NPNPNNNPNPNNPNPgPNPgPgNNgPgN>NVVo]VPNPPgPNPgPgPPPP@Ps=CCCC[VVogg>gg>gPgg>gg",
+" oo oooo o  [ oo   o[o ooo o ooooooooo ooo oo [o o oo@ oVoV@@@T@oVV@@@@@@@To@@@@@@VVVVoV@IjjjZ;bx&hhhhxcccccb=C;b=====================b===CbCx===SSS;CbSbS=;bCSbCbCCCCbbbbbbbCbbSbCuZuCCCxSSxCx;;;SuCx;SS;xxSVhhh&hYYhhh&Fh@VVVV[ oPPP@@PPPVPPPgPPPP0SSCcIIc0[[o[ o[ o [o   oo o oToToVToToVToVVo00Doo@NPgPgPgPgPPgPgPgPgP@Vo====0  oP%PNPNPNPgPNNPgPNgNNgPgPNgPgPgVo VVNPNPPgoP@PNP@NPPPPII=ccoVVV>gPgPgggPg>gP",
+"o[ o[   o0 ooo  o[o ooo o o ooooooooooooo o ooooooooooooVoVo@o@VVV@T@V@TV@@@@@VVVVV@V@V@VIjja=cC&hYYYh=c==cc==CbCc==c=====b===b===;b==CCb;======bC;SSSCCxSbbbCCS;bbbbbb;CbCbbbCCSxSSZCCbCCSS;;;;CaSZSZZZ;C;;x hhhhYYhhYhhFh@VVVP[[ PNPo@N@@NPPgPPPgP0=SCIcIII[o [o[o[ o o o o oooTooToToTooVo@TVVe00 0ogPPgPPgPgPgPPgPPgP>@oo====0[o P%NPNPNPNNPgPNNPgPPgPNPgPN>NNNoV@ooNPgPgPPNPgPgogPgP@II=cI >V@>gPggPgPgPg>g",
+" oooooo oooo ooo oo o oo oooo oooooo ooooooo ooooToVT@V@oVoVoVVoo@@@@@@@VVVVVVV@V@VVVVVVVcllcRbZhhYhYYC===ccc=cC======c=====b==bc;aSC;a;==bbbb====CSS=;SCSC=b=S;C=CbCC=C=SCbbCbbCSZxS=CbbSSCCS;C;a;SZSSS;xSxxc&hhhhYhhh&hF&@@VPV[o[PPPo@P@@PNPPgPgPg0cSCcIII0 [o  o o o  oo oo oToTooVoVooToVT@VT0D[ [@PPgPPgPPPgPPgPPgPPgP@@ccc=0 [oUPNPNPNPNPNPNPgPNNNPgPgPgPgPgPt@oVoPPPgPgPgPPgPPPgPPPIc==c0@VPgPgPgPgPgPgPg",
+" o    o o o o o o o o o o o oooo oTooooToo ooToToo@oo@o@Vo@VV@VV@T@VV VVV@V@V@VVVVVVVVVVVcl=I=SjYhYYhYCc=ccc=ccc=cc==c===c====c=;;=bC===b==b==bCb===CCSS;=SbCCCb=C=bbb==b;b=b=C=xZSSbCb=CSS;C;x;SZSS;xSxSxxSS j&hhhhhhh&&hj@VV@@o@oNP%ooPVPPNPNPPgPPIcC=cIcII[o[o[   o[o  oo o  ooooToToTVoTVoTVV00[0[ogPPPgPPPgPPgPPgPPgPPPoIIIcI [ooUPPNPNPNPNPNPNPNPPNPNPNPgPNP>NoVVogPgPPgPPgPPgPgPPgP0ccc=IP@VPgPgPgPgPgPg>",
+"o ooo o o ooooooo o o oo[ooooo0ooooooToooooTooooVoV@@T@T@VV@@T@@VVVV@o@VVVVVVV@@VVVVVVVVP=ScRblhhYhhYhR=c===c==cbccc=c==cc==c=====C=======bbb=b=bbCxCCSSSCSCCbb=b=C=b=bb=Z=CbCC;xCCS=;Cb=SSCxS;SZS;SCSSSCS;SCI&&&&hh&h&&&ll@@@@@o [PPP@VN@VNPg@PgPPg0=C=IIII0   o o[o  oo o  oo o oTooooo@T@oo@oV[[o[ @PPgPPgPgPPgPPgPPgPPg@@0I00Io[ooUP%PNPNPNPNPNPNPgPgPgPNPNPgPNPoVVoPNoPgoPgPgPPgPgPP0IcIIc0o@VgPgPgPgPgPgPP",
+" o[o oo0 oo o o oooooo oooooooTooTooo@[o@TVooToT@oT@o@@@@@@T@@VVVV@VVVV@@@@VVVVVVVVVVVVVoI=IcC&&hh&hhY=c=ccccc=cbc==c=cc=c=====c=C======bb=bCCbbb==;bCSC;bS=CbS===SS=b=b=;==bCSSSSxCbCCSSSCxZCCSZSS;CSS=C=C=b &&j&&&hh&&lCc@@@V@[ooPPP@VP@@PNPPNPPgPo=CCIIII0[o[o[oo[oo  o oo ooooooooooToo@oTVV@ [o [@PNPPgPPPgPPgPPgPPgPPPo0III0o   PP%PPPPPPPPNPPNPPPNPPPgPNPPNPNV@V@gPPgPPPgPPPPgPPgPP0I=III@@@PgPPPgPPPgP>N",
+"ooooo oo[o[oooooo o oooooooooooooo@o[@oVooo@To0VoV@@T@V [@@@VVVo@VV@@@VoVVVVVVVVVVVVPVVVVIIR;Sh&h&&hhYc===cccc=cCccccbcc====c===c=x=======bbbbbb===bbC==S=x=S=;==CbxSS==C=;C=CSSSCCSCCSSSCSSSSCbCSCSSS=CbC=CbI&&jhhhh&hYZ=C@@@@P[o[PNPNPgPPPPPgPPPPPo==cIIII0[oo[o[ooo o o o ooo oo ooToooVoT@@@V0[0[oPPPgPPPgPPgPPPgPPPPgPP@0cIIIoo0oPUPPUPNPNPPPNPPNPNPPNPPPNPgPPNP@PoPgPPgPgPgPPPPgPPgPo00cI0o@@PPgPgPPgPPgPg",
+" o o ooo ooooo ooooooooooooToTooVoooVo@oVoVoooTVo@ o@V@@@VVVVV@VV@VoVVVoVVVVVVVVVPVVVVPVV[I=S&&&&h&&Yhccc=cccc=cc=ccC=bc=b====c==b=c============b=bCC;CCx=C==Cx===CCxCS=bbSCCCCSSCCCCSS=SCCCS=SSCS=C===CbbC=CIh&&jhYhhh&Sj&P@>>P>PwPwPP>PP>>PwPPsgwso==III0I0o[oo oo[ o[o oooo ooooo@ooo@oo@@@V@V0[[[[P>PPPgPPPPPPgPPPPgPPN@@0cII0@oVoPPPUPUPPPNPNPPPPPPNPPNPNPPPNPPPVoPPPPPPPgPPPgPgPPgPP0I0II0PP@PgPPPgPPgPP>P",
+"s@s@s@ssssPPs@sPs@sP@PPPPPPPPPPPPPPPPPPPPPPPPPsPPPPPPPPPPPPsPPPPPPPPPPPPPsPsPsPsPPPsPPPsPIcbljjh&&&&hhcccccccccc=cb=Cccb=cc=c===c===c=======bb=b===CCS=S=CC===b;===CCS;CCb=CCCxCSCC=CCCSCSC;CbSC====CCb=bbbC=[&&&&j&Y&hj&h&w``+``g``sw>swwPw>PgswPswoIcc0II0Ioo [o[ooooooooo oooooooooooVo@oo@@o@o[[[oswswPsPwPP>PPPgPPPPgPgg@ssPggggggNggggw>gwgw>ggwwgwggwggggwgPP@o@oPwPgsPPPgPPPPPPPPP@00I00@P@PPggPgPgPggg>",
+"PsPPsPs@P@PsPPPPPs@sPsPsPPsPsPssPPsPPP@PsPs@sPPPPPsPPsPsPs@sPPsPsPPsPsPs@sP@sPPPsPsPPPPPP=SQljl&h&hhhhIcccccccccc=ccccCCccc==cccCCc=====c====b====C==C=;CCCC==C;====;CSC=C=SS=CSCCbbbCCCC=CCCS=C==b=b=b===C=bP&&&&ljj&&hYFY+y,,+,+````+```g`y````g`w$00I0I0I00o[oooo[o oo ooooooooooo@ooVoooo@oV@o0[00wPwPwwPggg>gggwggggwggwg>gwg`>`wwywqwwwywyw`yyw``yyywyyww`yyygyy>yg`gww>ggPgPPPgPgPPPoossPPgPggPgPgPgPgPPN",
+"PPsPPPPPsPsPPsPsPPPPs@PPPPPPPPPPsPPssPsP@PPPPsPsPsPPs@Ps@sPP@sPPPPPsPPPPPPPPPsPPP@sPsPsPsujl&ZZlh&hhhhIcccccccccccbCCCcccc=cccccbC=Ccc============c=CC==C==b==cC===CSCS==b=CSCSCCCCS=CSSCb=C=====b=C=b==CCCC=Nh&jjZCCjh&&&j,,++,`,+++,+,``++,`y`+,++`,E,E$@ooooo[oooooooooooo ooooooo@ooo@@@@o@@o@[o@@>gwgg>gw>gwgw>gwgwg>gwgggwyqyyw`>``wy``w+yywyyyywgygy+yyyyyyy`>``yygw`y`wgwwggwwwgwgywwwgPgPgPPgPgPgPgPgg>",
+"PsPPPPsPPPPPs@sP@s@sPPsPsPsPsPPsP@sVs@sPssssPPPPPPPPPPPPss@sssPsssPsPPPsPsPsPPPssPPPPPPPs&h&lZZjjh&hhhIccRccccccccc=cccccc==bC==Cc=bc=cc=cc=======c==C===C;=c==C==;==CC===b=C=CCCCC=;CCb=bCCxb=========CC====0YYhjSSSj&&jh&,,,++,+,```,+`+,,+```,++,+,,+,,+,,+,$y+[ooo[ooooooooooooo@ooo@@oo@osg>>>`>wgwgwgwg>gwgwggwg>gwgwgwEEyyyyyyyyy>w`wyyyy>`w`yyyyyq,yyy+yy+yyyyyw`w`w`ygw`y`w`ygyyyw``ywwg`wwgwwPgPPgPgP>",
+"PPPsPsP@ss@sPsP@sssPPPPPPPPPPPPPsPsPsPs@s@s@sPsPPPPsPsPPPPPPPs@s@s@sPssPsPsPPPPPPPsPPsPs0&&hjjllZjh&h&IcIccRccccccc==cccbCbc=cccccbcc=c=cc===cc=c=CCc=c=C=C=c====cCS=======c;CCC==C======CCC=;SSCCC==b==cSCCCUYFhjZCjhh&&Yj,,,,,+++,,,++``,,++`+,`+`,,++,++`++``+,+,y,++qoooooooooooo@ooo>>>N>>>g>g>>g>gPgPgPgw>wgwgPgwgwwwq,Eyyq,wyywyyyyqyyyyyyyy>`w,yy`wyyyyyyyyy,y`wyyy`wyyyy`>`wyy``y`>y`y`wy`gy`wwwgwwgwg>",
+"sPPPPPsPPss@s@sssPs@sssssPsPsPsPsPsPsPsPsPsPss@ssssPsPsssPsPsPsPsPsPsPPPsPs@ssss@sPss@sso&h&h&lZZj&&h&Icc=cIccIccI=c=======c===b==cc=c=cc=c=c=c=ccCcC==CC=C=C=c=c=C=cCC=====c====bCC=======CCCc=============CohYhjSZ&&&j&Yj,,,,,,,,,+,+,,+,,``+++,,`,+,`,+,,``,,+`+`+++,,,+ywy,oooo@s>>>>>>g>>>>w>sg>>>wg>>wgwgwgPgwgwwwww,EE,qywyqywyyqyEyyyyyyEyq,wyyw,wyyyyyyyyyyyywyy,ywyyyyyw`yyw`wwwyywyww`wywywygw`w`w`wy",
+"sPssPsPPsPPssPsPPsPPsP@s@ssPsPs@sP@sP@sPsPsPPsPsPPsPsPsPPsP@sP@sPs@s@s@s@s@sPPPssPsPPsPsI&&&&&jZZjjh&hIc=cccIccccc=cccccccc=c===ccccccccccc=cc==cc==bc======cbcb=cb=====ccc==c=C=C=C=CCC==CbbC==c===CC===CCCC0Yh&Sjjj&&&j&&,,,,,,,,+,,,,,,,,,,,,,,++````,,,+,,+,``,`+,`,`,`,```y+++y>>>>>>P>>>>>>g>w>gPgswgw>gPgwwwwEEwqyqwqyqwyEE,EEyE,qyyqywyq,EyE,wyyyy,Ey,Eyyyyyyyyyyyyyyyyyyyww`y>+y`w+yy`wyyyy`w`wy`ww`>`w",
+"sPs@s@sPs@sPs@Ps@s@s@PsPsPPsPsPsPsPsPsPsPsPs@s@s@s@s@s@s@s@ss@sPsPsPsPssPsPsPssPPPPPs@ss0&&&&h&jZljl&lIccccccccIc==ccc==ccc==ccccccccc=ccc=cccc=ccc=====c==c=c=Ccc=cc==cc==ccc=CC====CCC=C=C====CC;CCCC;CCC==oYhjZhhjj&&j&l,,,,O,,,+,+,,,!,,,,,,+++,,,,,,+,,,++++,+,,+,+,+`++`++++````gy>Pg>>w>>PwPgwPw>wgPg>w>wEwqqEEEEEEEyqEEwwyEEEywwyqEywyE,EEyyq,qyEEE,Eyqyyyywyyyw,Eyyyyygyyyywyyw`yyyyyyyyyyyyyw`ywyyywgy",
+"PsPsPs@s@s@s@ss@sssss@ss@s@sPsPPsPsPsPsPsPsPsssssPs@ss@ss@s@ss@s@s@s@s@ssssPssPsssssssss0&j&&&&jZSjZlZIcI==cc===ccccc=cc===ccccccccccccccccccc=cccc==c==C=cC=cc=====c==c=c=c==cC==C=c===CCCC=CCCCCC====CC=c== hjS&hhhj&&h&j,,,,,y,,,,,,,,,,,,,,,,,,,,,,,,!,,,,+`+,,,++,,,+,`,++++++,++g,`+,``PgPwgPPPgP>>PwP>swq$$E$EEEEEEwqEEEEEEEEEEEEEE,qEEEE,wwEEE,qyyEEE,EyqEywyqyyyyyyyyE,wyyyyyyqwyyyyyq,y,wyyyyw`wyyy`wy",
+"sPsPPsssssPsss@s@s@@s@s@s@ss@s@s@s@s@ssssssssPsPsPssPssPsssss@s@s@ss@ss@s@s@s@s@s@s@s@s@0&&&j&hjlSZZS=IcI==cc==ccccc=c=cc=cccIccccccccccccccccccccc==cccCcb==ccc=Cc==c=ccccccccC====CC==CcC=CCC==CCCCCCCcc=c=0&CZhYhhh&&&&&,,,,,+,,,,,,,,,,,,,H,,,H,,,,,,,,,```,,,`+`,,+,+``+,+,+++,`,+`,y``y`w``Psgws>w>PgwwwwE$wwq$EEEEEEEEEEEEEEqEqywqEEEyEEEEEyE,EqwEE,E,EEEyyqyEqyEqyEEyEyEyyEywyEyyyywyyywyEyyqyyyyw`ywwyy",
+"ssssssPsPssPsPssssssssss@s@s@ss@ss@ss@s@s@s@s@s@s@ssPsPsPPsPsssssssPssPsPsss@s@s@s@s@ss@0&&j&j&jSCZjZcIcIcccccc=ccccccccIccIccccccccccccccccccccccccC==c=cC=cccccCcccc==ccccc=c====C==ccc=c===c=C===CC===cc==[==jhhhhhj&h&j,,,,,,,,,,,,,,,,,OE++,,+,,,,,,,,,,`,+,,,+``,,,+`+,``,,`,,,`++,,```y``y`y`y>PgPss$$$$$$$$E$E$EEEEEEEEEEEEEEEEEEEEEEEEEEEEqwEEEEqqwEEyEEEEEyywyEE,qE,EywEyE,EyywyqyE,wyq,qyyqqqEywwy`w>",
+"s@s@s@s@s@PsPsPsPPPPPPPssssssssssPssPsss@s@s@s@ss@s@@s@@s@@s@s@s@s@ssssssPsssssssssssss$IZj&j&j&ZZZjjIIcI=IcIcccccIIcIcIccIccccccIccIcccccIc==cccc==c==c====ccccc=cc=ccCccccccc===cccccc=ccCc==c===c====c=c==ocC&&&&hh&ll&&O,$O,,,,,,O,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,,,,,,,`+,+,``+,++,`+,+y`+`y`y`y`+y`w`y$$$$$qs$E$$E$$$sE$$E$qq$EEE$EwEEEEEEEEEEqEEEEyEEEEqyEEEEEqwyEEqywqyEEEyw,qwywwyEyyyEEw,wywyq,yyEyywwwy",
+"s@s@s@s@s@s@@s@@s@s@s@s@s@sssPsPsssssssssssssssssssssssssss@s@s@s@s@@s@@@s@@s@s@s@s@@s$$IccSSCl&CI=CZIIIcccccccIcIcccccIcIccIcIcccccccIccICcccc=c===c=c=ccccccccc=cccc=ccccccc=====ccc=cccc=====C===c==cC===cocj&&j&&hhjjj&$,,E,OE,,,E,,,,,,,,,OE,,,,,H++,,,,,,H+`,,,,,,+,+,,,,,,,,,,`+,++`+y`++`y+`y++````y`w$$$$$$$$$E$E$$E$$$$Eq$$Ewwqwq$EEqEEEEEEEqEEEqqEqEEEEEEwwqyEEEEEEEEEEyEywywE,EqqyyywqE,qEEEyywqyywy",
+"s@s@ss@s@s@ss@s@sssssssssss@ssss@Ps@sPsPsssssssss@s@s@s@ss@s@s@s@G~G!!H~H!!H!HH!!~!!GH!O!GGGOOOOOOOOOOO,!!!O!G!O,O$$OBBBBB0000000IcIIccIcccIcc=c=c=cc=cccc=cccIc=cccccc==ccccc====ccccccccC=Cc=c==C=C===c====@=&&&&&&&h&Zlj$O$O,$,,,,,,,,EO,,,,E,O,,,,,,,,,!,,,,,,`,,,,,,,,,++`,+,,++,,,+`,+,+,+++`y``y`yyy+w```+$$$$$$$$s$$$$$$$$$$$$$qsqqqE$E$E$E$qwwEE$EEEEEEEEEqEwwEEEEEEEqwyqwwEEEEEEEEqEEEEEEwwyyyyEEEEy>w",
+"sssss@s@s@s@s@ss@s@@s@@s@@s@s@@s@s@s@s@s@sPsG!!,!!!/~!OGO!HGG!!G!!!!!H!!!!!GOG!G!!!~~~HOH,!,!,!,O,G,!,!!!,!,~,!HG!OOOOOOOOOOOOOH!~~~!,~,$OBBBBB0IIccccccc=cIccccc==ccccccccccc==c=cc=c======cccc===c=cccc===c[=jh&&j&&&&&&j,$,$,,,O$,O$O$,,,,,,O$,,,,,+,,,,,,,,,,,,+,,,H,,,,,,+,,,,,,++,,++,,+,,,y++,y`y+++``yy`yy`yy$$$sE$$$$$$$$$$$$$s$$$$$$$$$$EEE$$Eq$E$E$E$E$EEwwqEEEEEEEEEqEEEEqwEEEEywqEqqqEyEwwEEEEyw>yE",
+"@s@s@s@s@$@s@$@s@s@s@s@s@ss@sEE!/!HHHGH/~O!OOGH!O~/~~~!,OOOH!HG!!H,OOOGOOOOO,!~+//`/K+~`//!!!!!!!~!OG~~~!!////H!!~,O,OGO,O!~~,~!,H,!~!~~/`,OOOOGOOO$OBBI0IcccIccc=IcIcccccccIcc===cc====cIc=c=====Icc=ccccc==oSj&h&&j&&&&&j$O,$O,,E,,$,,,,,,,,,E,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,,,,,,,,,+,+y`,++y`,,+y`+yy,`y`+yyy$$$$$$$$$$$$$$$$$$$$$$$$$$$$$E$$$E$E$E$$E$$$$qEEE$E$$EEqEEwwwwwqEEEEEEEEEEEEqEEEEqEEqwww",
+"ssssssssss@$$s$s$O,G!G!GO~`~HOO!!!!OG!H!!!!,~!HGOOOOGGOOGOO,OGGG!!GO,O!G,O!HGG!HHOOG!!H!!33!3!!!!!~!!!H!~!~3!H!,!!!O!,~~/~//~~~!GO!~~~////!O,G,!~!O!,OOOG!~$$B0I0ccccIccI=cc=cc=cccccccccccIccccc==cccIcI====0Slj&&&&&&&&j&$,$O$$OE,,,,,,,,,O$,,,,,,,,,OE,,O$OE,,,,,,,,,,,,+,,,,,,,++,,,++,,,,,,,,,`,,,y`y`yy,+`yy+y+y+y+yy,$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$E$$$$$E$q$EEq$EEE$EEEEEEEEqEEEqqEEEEqEEEEEwwwqEqwqw",
+"s$ssO$OOO,GHOOO!!OOO!HH~/OG!!~~~~!!!!~!GOGH!HGGOOG!HOOOOOG!!!!!!!!~~!!!GG!!GOO!!~HHHHHGGGGOGH!~!,H!!!!,!G!~~~/~~!!!~~~~~/~~~~~!~~~!G!!!~//`/~!OG!~,~!~~/+~K,OOOOOO$$B00cIcccccc=IcIccIc=IccccIcccccccIcc=cccc0ZZZjjZjj&&&&&$O,$,,E,$O,$O,,,,$,$O,,,,,$O$,,,E,,EO,EO,,,,,,,,,,,,,,,,,,,+,,,+,,++,,,yy,,,,,,,,,+yy`,`y,y`,yy`yyyyy$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$q$$$$$Esw$$$qw$E$$$$$qqEwwE$E$EEqwqEqqEEEEEEqqqqE",
+"<GH!HOOOOOOOO!O!!OOOOOOOOOH!!!HGOGOOOOOOHOOOOOG,G!GOOH!!,!!HOOG!!!!GOOOOOOOGHGOOOOO!!GOOGG!!~!GOOOOOG!HGH!OH!!HHHOGG!~//~~H!!!~HO,~~,!~~/~~!!G!,3~~~~~,/!H~//,,~,!!OOG,H,!$B00IcccccIccc=c=ccc=cccIIIcccccccc0ZZjSjjCZZjj&&$$,O$O$O$E,,$,,,,,+`>,,,,,,y,,y,```yy,,y,,+y,,,,,,,,,,,,+,,,,,,,,,,,,,,,+,,,y,yy,,,y,y,y,+y,yy,yy`yyyyyy$$$$$$$$$$$$$$$$$$$$$$$sq$$$$$$$$$$ws$$$$$$q$$$E$$$w$$$EEqE$wqEE$ww$EEqwEEEEE",
+"OOH!/~~~!OHHG,OOOOOOG,!OOOOOOOOOOOOOOOOH!~~////~~~H,GOOG<H!~~!,GGH!~~~!,!H,HGH!!!H!G!~~!!!!!!HOH!!~~~!!H!!!HG~~//,HHH!!!!!~~/H,!!G!OH~//~!!!!~////`//G3/`/`//~!!!H!,!,~!!!,GHOOO$IISl=CSj&jllljjjl=CCCZZC=CCCZjSZlZjjCZjjZ&BO$wwyEE,yy,y,yyy+y+y`yyyyy+y++y,yyy+``+y``+,,,,y``,,,+,,,,,,,,,+,,,y+,,+y,,,,+,,y+,,+y,,yyy,+yy,yyy,y`yyyy$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$Esw$$$$$$$q$$$$q$$$ws$q$$$$$qqEq$E$E$E$w",
+"K~~~!!!GH!!HHHG!!GHOOOOOOGHGOOOG,!,//+///~!HGGHOOOOGGOOOOHGG!HHHGO!HH!~!!HOOH!!~~~!~!H!~//`////!!!!H!!!!!!OOOOOOOG!~~~`//~!!GGGGGG!H!!!~/~HGOO!!!!3~//~~~~~///~~!!!~~~!,/~~,H,,,GGO$B0ICZj&jZlljjZCC=ZZZCCSZCZClZCZjCjClCSZ$q`yyy``>`yyy`y`yy+y+`y++``y+y+``y++`>`y`yy`yy+y,yyy`>+y+y+y+`y,,,,,,,,,y,y,,,,,,y+,,y,,yy+,y,y,yyyyyyyy`>yyyyy$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$sqs$$$$$$$$q$$$wq$$sq$q$$w$wq",
+"~~HOOOOOOOOOOOOGH!,~~!!!OOOOOGHHH<!HGOOOGGGHHH!HH!HHHOOOOOHOOOOGHHOOOOOOOH!!GOOOGGHH!!HG!!!3~~~!////`//~,!!,!~~~~~~/~!G!!!~~~/~~~~~!~~~/~,/~,!,!!3/////KK~!~/~/~G,!,~~!!!~!/~//G,!,!OOGOO$0CllZllCCCCCjlCCSZZSZSCCCZZZCCZZC+>`yyyyy`y+y`yy,y+yy`yy`y`y`+++yy`+y+y`y+y`+y``+y``+y``+y+y`yy`y`y,y`+y,+,+,,y,y,+,yyyyy,y,y,,y+y,+yyyyyyyyyyyyEyw$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ws$$$$$$$$q$$$$qsq$q",
+"OH!!OOOOGHOOOO!HHGOOOOOOH,!~~!GOOOOOOOOOOOH!HGOOH!!!!!!!!H!!!~!~!~!!!!~~K/~!!!H~/~//~!!GOOOGOOOH!~~3HHOOOOOGGH!~//~~~//~!HGHHH!!!!!!~~!!!HH!3KK~!!3~!OGOH!~!~!,!~H33~~~!,//~!~/!G~~~,!`,!OOO,O0cCCSZCCZSZCSlZCZCZZCCZCZCCZl$wyyyyyyyy`yyy`yyy+`>+`yyyy`yy,yy,`y+`y`y+y``yg,+y`y+y+y+``y,`y`y+y+y`y+y+y`yy,,,E,,y+y+,,y,y,yy,E,yy,yyyyyyyyyyyy>qy$$$$$$$$$$$$$$$$q$$$$$$$$$$$$$$q$$$$$$$$$$$qs$$$$qsws$$sqsqs$$$$",
+"!!~!!OOHO,!!G,~~!!OOOOOOOOOOOOOGOOOOOOOOOOOOOOOOGH!!H!HO!HH!!~~~!!!!3~~K~K33~~~~///~~!!!!HG<!~~3!H!!!!!!!!!~/~!!!!!3!!!~!H,O!~/~~!OOGH~~3HHGH3!~/`/!!<,!~~~~~!!~!~~~!H,!H!!!H,!!~/,~~~!~!,,!,,!OOOB0ccCCCSCCZSZZ===CZCC=cCC$,yyyyyy`yyy`yyy`yyy+yyy`+yyyyy+yy`>`yyyy`yyyyy``y`+y```yyy+y``y`++y``gy+yyyygyyy+y,y,,yy,y,,,y,y,yy,yy,yyyyy,yy>yyyywyw$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$q$$$$$$$$$$$$$$$$$$q$$",
+"K///`/`////~~H!!H!!HGOOOOOOOOOO!~~~!!GOOGHHH,G!~~~H!HGGGHG!HH!!3~~~!!!!!!!!!~!~~~~~~~~/~~HH!3!HGGOOOH<!!H!!!H!H~~~~!HHOHGOOOGOOH!!!!!G!!G!~~!!3333~~/~K~~!,<~~H~~~~~/~/~!,/`/!/,/`H~`/``/~!!!H,`,OOOH$$BIISC=C=cIIcCCCCIccc$qyyyy`wyy`>`y`yyy`y`yyyyyy`y,y`>+y`yg``yyy+y`yy`yy`yyy`>`yy`yyyyyyyyyy+gy`y,,y+y`yy,yy+,E,E,E,y,yyy,y,y,yyyyEyyyyyyyy>ywwww$$$$qs$$$$$$$$$$$$$$$$$$$$q$$$$$$$$s$$$$ws$$$ws$$$$$$$$$$",
+"33~K~~K~3<!HH!!GOOOGHGGGH!!!!HH!HH!3!~~~~~!!H!!!H!!!!OOOOOO!HGGGOHGHOOG!33~!!H!33333!HHHOOOOGG!!~~~3!!H3~~/K~3!!!3~~/~!HGGGOHHH!~!,GOOH!~~~~~!!HOOGGH!!!///K~,HH!!~~///~~<///~~H~~//~///~G!~,!~!H,,,,OOOO,O00cccIII=C=c0I=0$yw`g>y>yy>`>y>yyyyyy,yyyy,yyyyy``y`y`y`yy``yy`yyyyyyyyy+y,yyy,y+y+y+y,yyyy`y`y`ygyyyyyyy,yy,y,y,y,yyyyyyEy,yyyyyEEyyEyyy>ywqqq$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$Esq$$$w$$$$$$$$",
+"OOGHGGOOGHH!HOOOOOOOOOOOGOOOH!HGHHH!HGOOO!~~~~~!~!OOOHHH!,3!!!!~~3!!GOGOOH3/~~33!!!!GOOGH!~~~///K~3K~~~~!GO!!<HHH!3~3!H!!~!~~!!GOOOOG!!!!~~~~~~~~~~~O!3~~!!!K///~~G!!!!!3~!/////!3H/~!!~~+~~/~`~`~///```,!,!,$$0=I=C=Cc0o$$$yywyy`>`yyyyygyy>gyyyyyyyyyy,yyyyy>yyyyyyyy`yyy+y``y+y+y`yy+yy+yyy+yy+y``yyyyyyy,y`yyy`yyyy,yyyyyE,y,E,E,EyyEyyE`yyEyEywyEywywwww$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ws$s$$$$$$",
+"GH<!3!<HOOGOOOHGOHH!H!H!!!!HOHGGGG!~~///!HGHHHHH!!!!~!~!3~~~~3!!H!HHHGGHHHGHHHGGHGOOOOHHHH!<HH<3!!3333<HHH!HHGHHHGGGH~~~!!H!!!~~~!G!HH!!!~//`///!~!~!H~3H33HH!~~~~,!<,~3~~~~~~~~~/3,!!~~~/~K`~3K/~!/~//!~~!,!OO$O00=I0$$$Eqywy>yy>`wyyyy>`yy`yyyyyyy,yyyyy`y,yy+yyyyyyyyy,yy,yyyyyyyyyyy,yyy`yyyyyy`>`yy`yyyyyyyyyyyyyyyyyyyyyyEyy,E,E,EyyE,EyyEyyyEEyqyw>yqw>qE$B$$$$$$$$$$$$$sq$$$$$$$$$$$$$$$q$$$$$$$$$$$$$$$",
+"OOOOOG<<<!!!~~~~!~!!~~~!~HGG!!~/////~!GOOOOOHHH!!OHOH!HHGGGOGHGOOOOOOOGOHHHOGGGGOGH<HGGOOGHGOOGOOGOHH!33~!!HOHHGOH!H!3~3~//~!~!~~~~~/,!HGG!<<HGHHOHHHGHH!~//~!G!!!!H333~~`//~~!H!!!//~~~~!+/3~~/!~,H~~`//,/!,~,~,!O$O$$$,wywyyyy>ywyyyyyy>`>yyyyyyyyyyyyyyyyy,yyy,yyy,yyyyyyyyyyy``>,yyy,yyyyy,yyyyyyyyyyyy,yyyyyyyyyyyyyy>`>ygyyyyyyEyyE,EyEyqyyEyyyyqwywwwEwwwwwE$$$$$$$$$$$$$$$$$q$$$$$$$$$$ws$$$$$$$$$$$$$$$",
+"H!<222~333<!GHGOHH!!!~H!!!!~/~~!OOOGOOOOOOG!!!HOOOOOOOOOOOOOOHHOGOOGOOGHGGH<H!!H!!HOOOOOOOOOOOHHO<!333!<<<OOOOOOOOOOHG<3~/~~~OGH!!~~<<HGGG!2K~!~~~!!!~~!3~!HHGHHG3~3!~~~!3/~/~~~,~~!~,!!/~3~!~H!H//~~//~/3`~~~~~`,H,,,!`wwywywwywgyEEqqyyyEyyyEyyyyyyyyyyyyyyw,yyyyyyyyyyyyy,y,yyyyy`yyyyyyyyyyyy`yy`>yyyyyyyyyyyyyyyyyyyyyyyyyyyyy>`>yyyyyyEyEwyywywwyEwwywyqwww>Eqwwq$$$$$$$$$$$$$$$sw$$$$$$$$$$$$$$$$$$sqsws$",
+"2322!HOOOOOH!<!!!!!GOOOGHHGOOOOOOOOHGHG!GHGGGGGOOOOOOGH!!32<HGOOOOGGGGOOGH!HHH<HHHOGOOOOOOOHHH!H<OOOOOOHGGOOOOOOOOGH3~//K/~~!!HO!!~!3K~~~33<<3///3!HGOO!/~~!H!OOOH!!!GHHHH!~/~~////~~~~!~~~!~~,~~H!,~//`///~,~~~~/+/~/`//,`ywyEy>ywyyEyy>yyyyyyyyEy>yyyyyyyy,E,Ey>`yyyyyyy,y>`wyyyyyyyy,yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyEyyyyyy>ywywyEyyEEEyqqyqyqywEqEywqw>wwwwqw$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$q$$$$$$$",
+"OOOOOGH!!23!<!HHGOOOGOOOOOOOGH<!!H<H!!OGH!H!GOGGGO!!!~3~3332!!!GGGGG!HH!<HOGOGH<<<!!!!GOOG!!~~33!!GGHGHGGOOGOOOOGHHHH<!<<!HGHOOOOG<H!33333!HHHH!///~~!!H!~//~!!HGOH!!GGO!!~~3~~3~~/~3!!!!3/,HO!~!,/H!~3~/`///~,~~`///,!~+/~/,~`wyqy>wyyy>wyy>>EyEyyyyEE,EyyEyyyEyyyyyyyyyyyy`yyyyyyyyyyyyyyyyyE,yyyyyyyyy>yyyyyyyyyyyyyyyyyyyyyyyywywyyyywyyyyyyyEyEyEEqEEEwwwqwqEwwwwww$>$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$q$$$",
+"HH<<!2232!GGH<233!!HHGGOOGH!!!!!<H<33~~~3!<H!!!3!!!!!3KKK322<<!!HHGGOGOOOOOOOOHH<<!33HH!!!!3~333~~~~~3!HGH!!3!!!!!!~~33!3!<HHO!!!!3!H!H<<HH!!!HO!3K3HOH!~~~~~~!!!!!!/~~~O!~~!G!!/!~~/~!OH,<<~//~!H~/,K~//3~/~/~!~~~,//`3!,~+/,~``yqEywEwyywyyyEyyywyyyyEyyyEyyyyyyyEyyyyyyyyqyyyyyyyyEyEyyyyEyyEyy>yyEyyE,y>`wyyyyyyEyyqyyqyEqyqyw>yqywywyyqqq>wwqywEEEEqEEEywqEEwwwwww>www>$sw$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"GGGHHHHHH<!<<<22<HOOH!!!!!HGH!3<!!322!<!H!<!!!!23233!22223K~~2!!!GOOOOOOOOOOOG<!!!<H<HHGH3KKKKK332333!HGHGGOO!!~~~~~~~~3!!!HOOOGHHOHGGOG<!~/K~3<!~33~!!3~~~~~3!!!!~!~~~!~~///~/~~!~~~//,~<!!~~~~~!!/////////`/~~/,/~~~~//`/`~~~//`/`EqywyqEy>yqyywyyEqyyEEyyyyyEEyyyEyEyyEEyyyEyyyyEyy,yyEyyyy>yyy+>yyyyyyyyqyyyy>yEyEwyyqyyyqyyqyyyyqywywqwywyywywywywyEqyEqwEqwwEqww$q>qsqwqPqs$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"OOOOOGHGOOOGHGHH<HHHHOOOOOH!GHH!!<22<<2333~2!<<<<<HGHHHGOHH<!HGHH!!!GOGOOOOHH<!!2333~~23!KKK3~232!<HHH!HGHHO!!!!~3!!!!!333!3~3!GHG!!H3!!~~KK////K!3~K/~K/K/3!!~~~~!3!!!!H!H~!!~~!!GOH!!3~///~`//~3~~/`7/~~////~~/~~/,//+~~//`/,/,/+/+`yw>yqyw>ywqywyqyywyqywywyyyEyE,qEyyEyyyyyEyyyyE,EE,yyyyyyyyyyyyyyyyyywyy>ywy>`wyEywyywEyyqyywwqEywqyqyqwqqqwwwq>wwqqwwqEqwwEEwqqqqwwwww>wsqs$$$$$$$$$$$$$$$$$$$$$$$$$$$$sq",
+"OOOOOOOGHHGOOOOOOOOOOOOOOOOGHH!2~K~3332<22<<<HHOOOOOOOGOOOOOOGH<2~~!H!!!!33!2!!!<<<<<2~K~KK2<!<HOOOHGGGHOOGHH!33!!!H<!!3K////////~3!!!3!!333!3~K~3~~~~33/K~3~~!!33~~!!!!!!!!!!H!!HOOOGH!3~~~K//`/`/~//~/~~!!~~~~!//~~/////`/~/3`~///`~/`wwwwyqyEEqyEEqqqyy>ywyywyyqywyyyEyyEqEyyEEyEywyyEy>y>>yEEEqyEEqywyEyy>y>yyywyyEyqy>yEEqywqEywywqywqwywyqwww>wwwwwwwww>wwqwqw$E$w$Esw$qsw$qsws$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"KK~2HGGGOOOHOOOOOHH!!!HOOOOOOOH<HHHHHGG<<<HGGGOOOOOOH<HOOOOOOOGH<2~~3!~~~22!<<<HHHH23~222<!H<HHGOOOOOOH!!!!!!!~!<OOOGH<~~K//////////3<!3<<HH!3323~33K/K~~3<<<!33H~!!!HH!,!3/~~~~~~~!!!H!!~/~~~KKK//~~~///!~`~/~,!/~`//~~,33/`~//~+`//`/~,`yqEEEwywwyEEEEEywEywwwqyEy>>yyyyyq,EyyyyqEEyEyEyEyyyyyyEyEyEyywyyEyEyyEywyqEEyEEyEywyqqywwywwywwqqqwwwyqqywqwqwwww>qqwqqqwEEEqEqE$wwq$>wswsws$s$$$$$$$$$$$$$$$$$$$$$ws",
+"~22<GHHGH<HHHGH!2!3HHGOOOOOOOOOOOOOOOOOOGGGOOOOOOOOGOOOOOO<2~~2<<<<HHHHGHOOGOOH<<OO<22!<HOGHGHOOOOOO<!!33!!!!!HOO!!333HH<!2223K//KK~KKK3<HH<!<2~K//3~/3<!KK33!H!~~~~!OGH<!~!!!!3/~/,~~!!3!~KKK~33!!/~!H~~~!G~~//!G~!~/~~3~/~3~~`/~~!,//,//`/+wqqqEqqwyyEEEEEwwywywEyEyqqqEEqwyqEwyyyEqyyEEyqyEEqEyqqyywEyqwEwyEywwwyqEyEwyqwyEqqyqwEEww>wwwwwwwqwwwwwEwwwwEwwEqwwqwwqww$E$w$Esqsq$Esqs>qwsw$$$$$B$$$$$$$$$$$$$$$",
+"~22<GGOOHGOOOOOHGHHHHH!HHHHOOOOOOOOOOOOOOOOOGGGOOOOOOOOH3~~2222<<<<<<<HGOOG!2K~!OOOH<<<HHH<<<<HGGOH!!H!<<!<!!HOOOHHH<<HHHGOGHHH<3232~K//~HHOG<3~K////K!HH!33HHO<H3!H!!!!!~~!!!!~~~~<!!/////3!~~K~!!~//~~!!~~~//~`/~!~!,/~~~,!~//~+/~~+/~,~~,`/+ywwwww>wEyEEEEEEEqywwyqywyEEEyqyqEEwyqEEyqEEywEyqEEEyEEyEEEyqyEwqyqyEyqqywqEEwwyqEwyEEqqqw>>yEw>wqww>w>wqw>Ewqwwwww$wswwwww>w$>sEs$$w$$qswssws$$$$$$$$$$$$$$$$$$$",
+"<HHGGHGOGHHHHHH<<!!!33~3!GOGHGOOOOOOOOOOOOOOOOOOOOOOOOH<<22!<<HH<<2322~~223K~32HOOOGGOGGH<<<HGH23~333233!<HOOOOH<2<H<<<HOOOHHHGOGHGH<233~!HOH!2!K////K3333!!HHHO33!3!!!H!3!!3!~K///////////~3!3!3!!~~!~~~~~/`///~~~~/~~~/`//~,//`/~+/////`,~~`/``wwqEwwEEywyEqqwwwwwqEEEqyEywywEyqyqq,qyEEyEEyEyw,EywyqqyqywywywEwEqEEEEwyEwww>wwwqEEEEwwwwwqwwwwwwwwq>wEqwwqwqwwsqwwwwws$sqswwwEsw$sw$sw$qw$wsw$$$$$$$$$$$$$$$$",
+"GOOOOOOGOGGGHH!232!22<GHHHHHOOOGGOGGGGOOOOOOOOOOOOOOOOGHGOGGHH23333K//////KKK<GOOOOOGOH<!2<HG<233!H<!23323<<H<<2<HGGHHGOH2<<<<<HHGGGHGGGOGOOO<33K////3<H!3333!HOOH!~3H!3/!!O!!3~KK~~33~3/////!~/~~~3!GH!!//~//////~!!+~~3~~~//~~~K`///,/////`3,~/```qwEwwEEEqqqq>wwwEEEqqqqqw>w>wqqwwEEqEEEEqEqqEEqqqEqqEwwwwEEwqEEEEEEEwqEqEqEwwwqqqwwqwwwwqEqwwwEqqEwqE$wwsw$wswq$ws>swqwsq$sws$$q$swsws$swswswsq$$$$$$$$$$$$$",
+"OOOOOOOOHH!33<HHHHHOOOOOOOOOGG<!!<HHGOGOGOOOGOOOOOOOOGH<<<<!3~KKKKKK/////K22HGOOOOOOG<!<!22HOOGOOOHH<2~33322<OG<HGOOOOOH<<<HHH<<<<<<HHOOOOGHHHH2////3<H<!3KK~3H!!~///K/~~3HOH33<<!33~~!!!!3H!!!!3!3~!H!!~H!33K//3~O~!!H~~/~~//`~/~!!`/~K,//`///,~`/`++EqEEEEEEqEqw>qEEqqwwywwy>>yqEqqwqqEqEEEEEEEEEqEEEqEqwwwEwwEEEqwwqEwwwwEqEEqEqEEwwqqwwqEwEwwEwqq$qwwq$Eww$wwEsw$wswwsqswsqswsqs$$$s$sw$sqsqsqs>$sw$$$$$$$$$",
+"OOOGHH<!!HGOOOOOOOOOOOOOOOOGGOOOOOOOOGGOOGOOGHGOOOOGG<!<223KKKKKKKKKKKKK222HGOGGOOOOGHOHHH<H<GOOH!2!HGH<!!3<HOHHHHHOH<H<!222233332333<HGOG<3!!!!3///3!<<3~!HHHHH!3///////K!HH!<HOH3!3!!!~//~~HGH!/3~33!~~/~~/~!~~G,!!~3~~/~/~!~///~333~~~/`//`/`//+~```wwEEEqEqEEEqwEqEqwwwwqwqqqqEqEEEqEEEqyqEEqywEEqwEqEqqqEEwqEwEEw>wEEwwwqEEwwqEEEEqEEwqww$Ew>wwwwsE$wwwsws>sww$wsws$wsqs>w$ws>$wswqwssw$qsw$$w$swswsq$$$$$$",
+"<!!H<<<HGOOGOOOOOOOOOOOOOOOOGHHHGGOGHGOOGGHHHHHHHHHH<HHH!22232<<<<<2322<<<<GHHHGGOOOOHH<<<H<<<<22KKK~~2<<<HHOOOGGHH<<HHHH<!223!2KKKK33K~<!!2223<3KK3!!<<<H!!HGH<!K///////3!HOGH<HGGHHH<H!KK~~!3!!3////~~!!/~!//!3~<3~~~/~H~~K`/`~~/+~!~,/~//`/~//,~/`//,`EqwwEwwEEqEqEEEqwwEqqEEqwEwwqEEEEEEqwqEEqEwEEEEEEEqqEEEqEEwwqwwqEEEEwqwwwwwwEq$qqq$$ww$$qswsw$w$sqswsq$wsqsw$qs$sqsw$swsws>sws$sws$s$qs$swswEswswsw$$$s",
+"HHGGGGGOOGGHHHHGOOOOOGOHH<HHGOOOOOOOOOGHHHH<<<<<<H<<HOOGHH<!22<GGGGGH<233K22<HH<!<<H<!22!<<<22~K/K//KK2~~!HGOOOOOG<<!!!<HGHGOGH<!22!22!23~2322!HH<<<<H<<!HOH<3~KK//////KK3HHG!HO!H<H<H!!!!/3!HGH~~~~///~/~3!!!~/~3!~!~/+/`K~3~K/K~~~~/~!~!~`/`//!~~`/+~,/+`EqqEwwEEEqqqEEEEwEEEEEEEqqwqqEEEEEEEEEwqEEqEqEwEEEEEEEEwEEwqqw$E$Eq$w$wqsqww$wsEq$Eqqqwqqq$$qsq$w$q$sqsqsswsq$qsqswssqswswswwwswwws$wqssws$sqs$s$wsww",
+"OOOOOOOGGHH<<<HGHH<<<<H<HGOOOOGGHGGGH<H<!<H<<HHHOOOOGGGGHH<<<HGOOOH<3KKKKKK~~~K/~3222<H<HHHH!23K////KKK2GGOOG<<<<<<222~3!<!!<H<HGGH<<<<2K/KK~32<HHHH<2233333K~3/K3KK//3<H<OOO<!~!G!33!3!H323!!!G!~K33~~/~~~3!!!!~//~~~!KK~//!!!!/,!!~~3!,!!~~//+~,~/~/`/``/,`$E$$EE$wwEqE$qqEEEqqwwEEEEEEwwEEqEEEEwqEEEEqEEE$EwEqwqqwqqqqwEEE$Eqw$Eq$Esqww$wqs$sqswsw$qsw>s$qs$q$wswwswswswsqs$qq$swswswsswsswsqsws$$ws$$qwssw$s",
+"OOOOOOOOOHHHHHGHH<<<HHOOOOOOGHHHHHHHH<HHHHGGGGGGOGHHGOOOOGGGGGOHH2KK/KK3KK//KKKK32!<HGOOOOGGHH23KKKKK222<GOOOGG<2~~333K3K322<!<HOG<<23KKK/K22!HH2~K//KK//K3KK~3~///KKK33!3!33!~~~3!~3<33!!333!!!H!!~~~~~/~!~~~~~!~~~////K////3/~~~/`~~~!H~/`/~~3~K~,~///`/`/+`EqE$Eq$q$$Eqqww$E$qqqwE$E$E$qwE$E$EEEqwEEEqqwEqq$E$$q$$wsE$qwsq$E$qq$q$w$$$ws$wwqq$qsw$sq$$sws$$qs$$sqs$wswswswwsws$wsws$wsqsw$wPwswwsqsqqs$>$wssE",
+"OOOOOOOGOOOOOOOOOOGOOOOH<<2!<HH<!<<HHHHHOOGGHHHH<HHOOOOOOOOOGH2232KKK22K/KKKK22<<!<HGOOOOOOGH2K/////KK3!H<HGG<23323//KK3232<<<HHGGGG<222223<HGOGH2KK////322<<2333~~3~3333H3~/~~33<!!3<3~~~~3~333!!!!3!~~/~3!HO!~~!!3~~//////`~!///////~,~///!/~,!~~/,~/`/~~`/~`+wqqw$$EEqwE$qwEqq$$E$qEEEEE$$E$E$q$w$$q$E$$E$qqwEE$EEEE$q$$qwq$w$swsq$qqq$E$$$s$$swsw$w$sq$Es$$qs>$sq$s$$$swsqsswsw$swsqsqsw$sqwsqsqsws$sq$sw$w$",
+"OOOOOOOOOOOOOOOOOOOOOH22!<<HHHH<H<<HOOOOOOOOGHHGOOOGOOOOOOOHH<!!23222232233K23<2<HGGOOOOOOG!33///////3233~222<<2KK////K2K22<<<<!<!H<!232!2<HH<<2HGH<KKK2<<HGHHH<!<<<<33!3~K////~33H3!HO!3233~~!HH!H!3K/K/K/~~~!~~~!G!~/K////K/~/`/`//`////////~/~,~//`/!/`//``~,~+w$qE$$$q$E$E$$$$E$E$$E$qqqEE$Eq$$wE$Eq$q$q>q$$$E$$$w$$$$q$$$q$$E$ws$q$sqs$$sE$q$$ss$sws$$$$s$sqsww$sEswsEsqswsqswPwsws$qsqsqsws>sqsq>sws>$s$sq",
+"OOOOOOOOOOOOOOOOGH!<<<<<OOOGOOOOOOHHOOOOOOOOOOGH<<<HHOOOOOOGG<2222!2222<2<2HH<GOOOOOHHH23~KKKK///////////K2<<3K///////KK322<<<!2<23KKKKKK2<2!<<<HH<22K322<OOOHH<<HOOO!3KK//////////K~3GG23K~2!!GOOHGH233~K///~3~~~3!H<~~K~///3~K////////`/!,~/`/3~~~////`H/+//~`~`,w$sE$q$wq$$$$EwqEq$q$q$$$$$$q$wqw$w$$$$$$$swqqswwsqsq$$$w$$$$q$s$qws$$$$$q$$$$s$E$w$sww$qsqqqsw$sqs$$qs$$$$wsqsw$$w$sws>swsswswswsqsqsqswswsq",
+"OOOOOOOOOOOOGH<HHHOOOOOGHOOOOOOOOGOOOOOOOOOH<!2!<HHOOOOOOOGG<HHHHH<<<GGOOOOOOOOOOOOH233~KKK3KKKK/KKKK3KK32<!~///K/KKKKK222<<<<<2!!2323KKK2HH<22232<H32222!<H<<H<<<!3<23////7/'///////K3<!3/K~3<!3~!GOOH!~/////~~!3!~~/3~~/K///~////////~K///~~3~~///,3/~/`/~/,~`/`/,`wws$$wPwwq$$wsqsE$wsw$$E$w$$$$$qsw$Eqqq$E$sq$$wqswwsEs$$sws$$$s$$$s$$ws$$wsq$sqs$$$$sq$$qs$$$swsq$ws$wswsswswswswsqssqs>$ws$sqsqswswsqsqsws",
+"OOOOOOOOOOOGGGOOOOOOOH<<<HGGOOOOOOOOOOOOGH<<<<HGGOGGOOOOOOOOOOOOOOOOOOOOOOOOOOOOOGGHH<22223K22222222<2<2<<<23K2KKKK33222!<HH<<<!<<2<<2222<HOH<3KK~3~<!22!<223~233<3!233K//7////7/////~3!3!2333~3//~3!!OO<///K~33!!HH!~~!!~///////////////KK~~~~~`~/~////`K~,////`/`/`++wEswwsqswwsw$EsEsww$$$$sq$$q$$$w>$s$$$q$$$s$$$$$wsq$q$Eswsw$qsw$$$$$sw$sq$$qsqsqsw$s$s$wPws$q$$ssEs$$q$$Eswswsw$$w$ws$qsqwsw$$swsq$$wsqsq"
+};
diff --git a/win/X11/tile2x11.c b/win/X11/tile2x11.c
new file mode 100644 (file)
index 0000000..a254213
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Convert the given input files into an output file that is expected
+ * by nethack.
+ * 
+ * Assumptions:
+ *     + Two dimensional byte arrays are in row order and are not padded
+ *       between rows (x11_colormap[][]).
+ */
+#include "hack.h"              /* for MAX_GLYPH */
+#include "tile.h"
+#include "tile2x11.h"          /* x11 output file header structure */
+
+#define OUTNAME "x11tiles"     /* output file name */
+/* #define PRINT_COLORMAP */   /* define to print the colormap */
+
+
+x11_header     header;
+unsigned char  tile_bytes[TILE_X*TILE_Y*(MAX_GLYPH+TILES_PER_ROW)];
+unsigned char  *curr_tb = tile_bytes;
+unsigned char  x11_colormap[MAXCOLORMAPSIZE][3];
+
+
+/* Look up the given pixel and return its colormap index. */
+static unsigned char
+pix_to_colormap(pix)
+    pixel pix;
+{
+    int i;
+
+    for (i = 0; i < header.ncolors; i++) {
+       if (pix.r == ColorMap[CM_RED][i] &&
+               pix.g == ColorMap[CM_GREEN][i] &&
+               pix.b == ColorMap[CM_BLUE][i])
+           break;
+    }
+
+    if (i == header.ncolors) {
+       Fprintf(stderr, "can't find color: [%u,%u,%u]\n", pix.r, pix.g, pix.b);
+       exit(1);
+    }
+    return (unsigned char) (i & 0xFF);
+}
+
+
+/* Convert the tiles in the file to our format of bytes. */
+static unsigned long
+convert_tiles(tb_ptr, total)
+    unsigned char **tb_ptr;    /* pointer to a tile byte pointer */
+    unsigned long total;       /* total tiles so far */
+{
+    unsigned char *tb = *tb_ptr;
+    unsigned long count = 0;
+    pixel tile[TILE_Y][TILE_X];
+    int x, y;
+
+    while (read_text_tile(tile)) {
+       count++;
+       total++;
+       for (y = 0; y < TILE_Y; y++) {
+           for (x = 0; x < TILE_X; x++)
+               tb[x] = pix_to_colormap(tile[y][x]);
+           tb += TILE_X * header.per_row;
+       }
+
+       /* repoint at the upper-left corner of the next tile */
+       *tb_ptr += TILE_X;
+       if (header.per_row == 1 || (total % header.per_row) == 0)
+           *tb_ptr += TILE_X * (TILE_Y - 1) * header.per_row;
+       tb = *tb_ptr;
+    }
+
+    return count;
+}
+
+
+/* Merge the current text colormap (ColorMap) with ours (x11_colormap). */
+static void
+merge_text_colormap()
+{
+    int i, j;
+
+    for (i = 0; i < colorsinmap; i++) {
+       for (j = 0; j < header.ncolors; j++)
+           if (x11_colormap[j][CM_RED] == ColorMap[CM_RED][i] &&
+                   x11_colormap[j][CM_GREEN] == ColorMap[CM_GREEN][i] &&
+                   x11_colormap[j][CM_BLUE] == ColorMap[CM_BLUE][i])
+               break;
+
+       if (j >= MAXCOLORMAPSIZE) {
+           Fprintf(stderr, "colormap overflow\n");
+           exit(1);
+       }
+
+       if (j == header.ncolors) {      /* couldn't find it */
+#ifdef PRINT_COLORMAP
+           printf("color %2d: %3d %3d %3d\n", header.ncolors,
+               ColorMap[CM_RED][i], ColorMap[CM_GREEN][i],
+               ColorMap[CM_BLUE][i]);
+#endif
+
+           x11_colormap[j][CM_RED] = ColorMap[CM_RED][i];
+           x11_colormap[j][CM_GREEN] = ColorMap[CM_GREEN][i];
+           x11_colormap[j][CM_BLUE] = ColorMap[CM_BLUE][i];
+           header.ncolors++;
+       }
+    }
+}
+
+
+/* Open the given file, read & merge the colormap, convert the tiles. */
+static void
+process_file(fname)
+    char *fname;
+{
+    unsigned long count;
+
+    if (!fopen_text_file(fname, RDTMODE)) {
+       Fprintf(stderr, "can't open file \"%s\"\n", fname);
+       exit(1);
+    }
+    merge_text_colormap();
+    count = convert_tiles(&curr_tb, header.ntiles);
+    Fprintf(stderr, "%s: %lu tiles\n", fname, count);
+    header.ntiles += count;
+    fclose_text_file();
+}
+
+
+#ifdef USE_XPM
+static int
+xpm_write(fp)
+FILE *fp;
+{
+    int i, j, n;
+
+    if (header.ncolors > 64) {
+       Fprintf(stderr, "Sorry, only configured for up to 64 colors\n");
+       exit(1);
+       /* All you need to do is add more char per color - below */
+    }
+
+    Fprintf(fp, "/* XPM */\n");
+    Fprintf(fp, "static char* nhtiles[] = {\n");
+    Fprintf(fp, "\"%lu %lu %lu %d\",\n",
+               header.tile_width*header.per_row,
+               (header.tile_height*header.ntiles)/header.per_row,
+               header.ncolors,
+               1 /* char per color */);
+    for (i = 0; i < header.ncolors; i++)
+       Fprintf(fp, "\"%c  c #%02x%02x%02x\",\n",
+               i+'0', /* just one char per color */
+               x11_colormap[i][0],
+               x11_colormap[i][1],
+               x11_colormap[i][2]);
+
+    n = 0;
+    for (i = 0; i < (header.tile_height*header.ntiles)/header.per_row; i++) {
+       Fprintf(fp, "\"");
+       for (j = 0; j < header.tile_width*header.per_row; j++) {
+           /* just one char per color */
+           fputc(tile_bytes[n++]+'0', fp);
+       }
+
+       Fprintf(fp, "\",\n");
+    }
+
+    return fprintf(fp, "};\n") >= 0;
+}
+#endif /* USE_XPM */
+
+int
+main(argc, argv)
+    int argc;
+    char **argv;
+{
+    FILE *fp;
+    int i;
+
+    header.version     = 2;            /* version 1 had no per_row field */
+    header.ncolors     = 0;
+    header.tile_width  = TILE_X;
+    header.tile_height = TILE_Y;
+    header.ntiles      = 0;            /* updated as we read in files */
+    header.per_row     = TILES_PER_ROW;
+
+    if (argc == 1) {
+       Fprintf(stderr, "usage: %s txt_file1 [txt_file2 ...]\n", argv[0]);
+       exit(1);
+    }
+
+    fp = fopen(OUTNAME, "w");
+    if (!fp) {
+       Fprintf(stderr, "can't open output file\n");
+       exit(1);
+    }
+
+    /* don't leave garbage at end of partial row */
+    (void) memset((genericptr_t)tile_bytes, 0, sizeof(tile_bytes));
+
+    for (i = 1; i < argc; i++)
+       process_file(argv[i]);
+    Fprintf(stderr, "Total tiles: %ld\n", header.ntiles);
+
+    /* round size up to the end of the row */
+    if ((header.ntiles % header.per_row) != 0) {
+       header.ntiles += header.per_row - (header.ntiles % header.per_row);
+    }
+
+#ifdef USE_XPM
+    if (xpm_write(fp) == 0) {
+       Fprintf(stderr, "can't write XPM file\n");
+       exit(1);
+    }
+#else
+    if (fwrite((char *)&header, sizeof(x11_header), 1, fp) == 0) {
+       Fprintf(stderr, "can't open output header\n");
+       exit(1);
+    }
+
+    if (fwrite((char *)x11_colormap, 1, header.ncolors*3, fp) == 0) {
+       Fprintf(stderr, "can't write output colormap\n");
+       exit(1);
+    }
+
+    if (fwrite((char *)tile_bytes, 1,
+       (int) header.ntiles*header.tile_width*header.tile_height, fp) == 0) {
+
+       Fprintf(stderr, "can't write tile bytes\n");
+       exit(1);
+    }
+#endif
+
+    fclose(fp);
+    return 0;
+}
diff --git a/win/X11/winX.c b/win/X11/winX.c
new file mode 100644 (file)
index 0000000..14f0e90
--- /dev/null
@@ -0,0 +1,2076 @@
+/*     SCCS Id: @(#)winX.c     3.4     1999/12/21      */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * "Main" file for the X window-port.  This contains most of the interface
+ * routines.  Please see doc/window.doc for an description of the window
+ * interface.
+ */
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+#ifdef MSDOS                   /* from compiler */
+#define SHORT_FILENAMES
+#endif
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Scrollbar.h>
+#include <X11/Xaw/Paned.h>
+#include <X11/Xaw/Cardinals.h>
+#include <X11/Xatom.h>
+#include <X11/Xos.h>
+
+/* for color support */
+#ifdef SHORT_FILENAMES
+#include <X11/IntrinsP.h>
+#else
+#include <X11/IntrinsicP.h>
+#endif
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+#ifdef SHORT_FILENAMES
+#undef SHORT_FILENAMES /* hack.h will reset via global.h if necessary */
+#endif
+
+#include "hack.h"
+#include "winX.h"
+#include "dlb.h"
+#ifdef SHORT_FILENAMES
+#include "patchlev.h"
+#else
+#include "patchlevel.h"
+#endif
+
+/* Should be defined in <X11/Intrinsic.h> but you never know */
+#ifndef XtSpecificationRelease
+#define XtSpecificationRelease 0
+#endif
+
+/*
+ * Icons.
+ */
+#include "../win/X11/nh72icon"
+#include "../win/X11/nh56icon"
+#include "../win/X11/nh32icon"
+
+static struct icon_info {
+       const char *name;
+       unsigned char *bits;
+       unsigned width, height;
+} icon_data[] = {
+       { "nh72", nh72icon_bits, nh72icon_width, nh72icon_height },
+       { "nh56", nh56icon_bits, nh56icon_width, nh56icon_height },
+       { "nh32", nh32icon_bits, nh32icon_width, nh32icon_height },
+       { (const char *)0, (unsigned char *)0, 0, 0 }
+};
+
+/*
+ * Private global variables (shared among the window port files).
+ */
+struct xwindow window_list[MAX_WINDOWS];
+AppResources appResources;
+void FDECL((*input_func), (Widget,XEvent *,String *,Cardinal *));
+int click_x, click_y, click_button;    /* Click position on a map window   */
+                                       /* (filled by set_button_values()). */
+int updated_inventory;
+
+
+/* Interface definition, for windows.c */
+struct window_procs X11_procs = {
+    "X11",
+    WC_COLOR|WC_HILITE_PET,
+    0L,
+    X11_init_nhwindows,
+    X11_player_selection,
+    X11_askname,
+    X11_get_nh_event,
+    X11_exit_nhwindows,
+    X11_suspend_nhwindows,
+    X11_resume_nhwindows,
+    X11_create_nhwindow,
+    X11_clear_nhwindow,
+    X11_display_nhwindow,
+    X11_destroy_nhwindow,
+    X11_curs,
+    X11_putstr,
+    X11_display_file,
+    X11_start_menu,
+    X11_add_menu,
+    X11_end_menu,
+    X11_select_menu,
+    genl_message_menu,         /* no need for X-specific handling */
+    X11_update_inventory,
+    X11_mark_synch,
+    X11_wait_synch,
+#ifdef CLIPPING
+    X11_cliparound,
+#endif
+#ifdef POSITIONBAR
+    donull,
+#endif
+    X11_print_glyph,
+    X11_raw_print,
+    X11_raw_print_bold,
+    X11_nhgetch,
+    X11_nh_poskey,
+    X11_nhbell,
+    X11_doprev_message,
+    X11_yn_function,
+    X11_getlin,
+    X11_get_ext_cmd,
+    X11_number_pad,
+    X11_delay_output,
+#ifdef CHANGE_COLOR    /* only a Mac option currently */
+    donull,
+    donull,
+#endif
+    /* other defs that really should go away (they're tty specific) */
+    X11_start_screen,
+    X11_end_screen,
+#ifdef GRAPHIC_TOMBSTONE
+    X11_outrip,
+#else
+    genl_outrip,
+#endif
+    genl_preference_update,
+};
+
+/*
+ * Local functions.
+ */
+static void FDECL(dismiss_file, (Widget, XEvent*, String*, Cardinal*));
+static void FDECL(delete_file, (Widget, XEvent*, String*, Cardinal*));
+static void FDECL(yn_key, (Widget, XEvent*, String*, Cardinal*));
+static void FDECL(yn_delete, (Widget, XEvent*, String*, Cardinal*));
+static void FDECL(askname_delete, (Widget, XEvent*, String*, Cardinal*));
+static void FDECL(getline_delete, (Widget, XEvent*, String*, Cardinal*));
+static void FDECL(X11_hangup, (Widget, XEvent*, String*, Cardinal*));
+static int FDECL(input_event, (int));
+static void FDECL(win_visible, (Widget,XtPointer,XEvent *,Boolean *));
+static void NDECL(init_standard_windows);
+
+
+/*
+ * Local variables.
+ */
+static boolean x_inited = FALSE;       /* TRUE if window system is set up. */
+static winid message_win = WIN_ERR,    /* These are the winids of the      */
+            map_win     = WIN_ERR,     /*   message, map, and status       */
+            status_win  = WIN_ERR;     /*   windows, when they are created */
+                                       /*   in init_windows().             */
+static Pixmap icon_pixmap = None;      /* Pixmap for icon.                 */
+
+/*
+ * Find the window structure that corresponds to the given widget.  Note
+ * that this is not the popup widget, nor the viewport, but the child.
+ */
+struct xwindow *
+find_widget(w)
+    Widget w;
+{
+    int windex;
+    struct xwindow *wp;
+
+    /* Search to find the corresponding window.  Look at the main widget, */
+    /* popup, the parent of the main widget, then parent of the widget. */
+    for (windex = 0, wp = window_list; windex < MAX_WINDOWS; windex++, wp++)
+       if (wp->type != NHW_NONE &&
+           (wp->w == w || wp->popup == w || (wp->w && (XtParent(wp->w)) == w)
+               || (wp->popup == XtParent(w))))
+           break;
+
+    if (windex == MAX_WINDOWS) panic("find_widget:  can't match widget");
+    return wp;
+}
+
+/*
+ * Find a free window slot for use.
+ */
+static winid
+find_free_window()
+{
+    int windex;
+    struct xwindow *wp;
+
+    for (windex = 0, wp = &window_list[0]; windex < MAX_WINDOWS; windex++, wp++)
+       if (wp->type == NHW_NONE) break;
+
+    if (windex == MAX_WINDOWS)
+       panic("find_free_window: no free windows!");
+    return (winid) windex;
+}
+
+/*
+ * Color conversion.  The default X11 color converters don't try very
+ * hard to find matching colors in PseudoColor visuals.  If they can't
+ * allocate the exact color, they puke and give you something stupid.
+ * This is an attempt to find some close readonly cell and use it.
+ */
+XtConvertArgRec const nhcolorConvertArgs[] = {
+    {XtWidgetBaseOffset, (XtPointer)XtOffset(Widget, core.screen),
+     sizeof(Screen *)},
+    {XtWidgetBaseOffset, (XtPointer)XtOffset(Widget, core.colormap),
+     sizeof(Colormap)}
+};
+
+#define done(type, value) \
+       {                                                       \
+           if (toVal->addr != 0) {                             \
+               if (toVal->size < sizeof(type)) {               \
+                   toVal->size = sizeof(type);                 \
+                   return False;                               \
+               }                                               \
+               *(type*)(toVal->addr) = (value);                \
+           }                                                   \
+           else {                                              \
+               static type static_val;                         \
+               static_val = (value);                           \
+               toVal->addr = (genericptr_t)&static_val;        \
+           }                                                   \
+           toVal->size = sizeof(type);                         \
+           return True;                                        \
+       }
+
+/* decl.h declares these, but it screws up structure references -dlc */
+#undef red
+#undef green
+#undef blue
+
+/*
+ * Find a color that approximates the color named in "str".  The "str" color
+ * may be a color name ("red") or number ("#7f0000").  If str == NULL, then
+ * "color" is assumed to contain the RGB color wanted.
+ * The approximate color found is returned in color as well.
+ * Return True if something close was found.
+ */
+Boolean
+nhApproxColor(screen, colormap, str, color)
+Screen  *screen;       /* screen to use */
+Colormap colormap;     /* the colormap to use */
+char     *str;         /* color name */
+XColor   *color;       /* the X color structure; changed only if successful */
+{
+    int                ncells;
+    long       cdiff = 16777216; /* 2^24; hopefully our map is smaller */
+    XColor     tmp;
+    static     XColor *table = 0;
+    register int i, j;
+    register long tdiff;
+
+    /* if the screen doesn't have a big colormap, don't waste our time */
+    /* or if it's huge, and _some_ match should have been possible */
+    if((ncells = CellsOfScreen(screen)) < 256 || ncells > 4096)
+       return False;
+
+    if (str != (char *)0) {
+       if (!XParseColor(DisplayOfScreen(screen), colormap, str, &tmp))
+           return False;
+    } else {
+       tmp = *color;
+       tmp.flags = 7;  /* force to use all 3 of RGB */
+    }
+
+    if (!table) {
+       table = (XColor *) XtCalloc(ncells, sizeof(XColor));
+       for(i=0; i<ncells; i++)
+           table[i].pixel = i;
+       XQueryColors(DisplayOfScreen(screen), colormap, table, ncells);
+    }
+
+    /* go thru cells and look for the one with smallest diff */
+    /* diff is calculated abs(reddiff)+abs(greendiff)+abs(bluediff) */
+    /* a more knowledgeable color person might improve this -dlc */
+try_again:
+    for(i=0; i<ncells; i++) {
+       if(table[i].flags == tmp.flags) {
+           j = (int)table[i].red - (int)tmp.red;
+           if(j < 0) j = -j;
+           tdiff = j;
+           j = (int)table[i].green - (int)tmp.green;
+           if(j < 0) j = -j;
+           tdiff += j;
+           j = (int)table[i].blue - (int)tmp.blue;
+           if(j < 0) j = -j;
+           tdiff += j;
+           if(tdiff < cdiff) {
+               cdiff = tdiff;
+               tmp.pixel = i; /* table[i].pixel == i */
+           }
+       }
+    }
+
+    if(cdiff == 16777216) return False;        /* nothing found?! */
+
+    /*
+     * Found something.  Return it and mark this color as used to avoid
+     * reuse.  Reuse causes major contrast problems :-)
+     */
+    *color = table[tmp.pixel];
+    table[tmp.pixel].flags = 0;
+    /* try to alloc the color, so no one else can change it */
+    if(!XAllocColor(DisplayOfScreen(screen), colormap, color)) {
+       cdiff = 16777216;
+       goto try_again;
+    }
+    return True;
+}
+
+Boolean
+nhCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret)
+Display*       dpy;
+XrmValuePtr    args;
+Cardinal       *num_args;
+XrmValuePtr    fromVal;
+XrmValuePtr    toVal;
+XtPointer      *closure_ret;
+{
+    String         str = (String)fromVal->addr;
+    XColor         screenColor;
+    XColor         exactColor;
+    Screen         *screen;
+    XtAppContext    app = XtDisplayToApplicationContext(dpy);
+    Colormap       colormap;
+    Status         status;
+    String          params[1];
+    Cardinal       num_params=1;
+
+    if (*num_args != 2) {
+     XtAppWarningMsg(app, "wrongParameters", "cvtStringToPixel",
+       "XtToolkitError",
+       "String to pixel conversion needs screen and colormap arguments",
+       (String *)0, (Cardinal *)0);
+     return False;
+    }
+
+    screen = *((Screen **) args[0].addr);
+    colormap = *((Colormap *) args[1].addr);
+
+    /* If Xt colors, use the Xt routine and hope for the best */
+#if (XtSpecificationRelease >= 5)
+    if ((strcmpi(str, XtDefaultBackground) == 0) ||
+       (strcmpi(str, XtDefaultForeground) == 0)) {
+       return
+         XtCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret);
+    }
+#else
+    if (strcmpi(str, XtDefaultBackground) == 0) {
+       *closure_ret = (char*)False;
+       done(Pixel, WhitePixelOfScreen(screen));
+    }
+    if (strcmpi(str, XtDefaultForeground) == 0) {
+       *closure_ret = (char*)False;
+       done(Pixel, BlackPixelOfScreen(screen));
+    }
+#endif
+
+    status = XAllocNamedColor(DisplayOfScreen(screen), colormap,
+                             (char*)str, &screenColor, &exactColor);
+    if (status == 0) {
+       String msg, type;
+
+       /* some versions of XAllocNamedColor don't allow #xxyyzz names */
+       if (str[0] == '#' &&
+           XParseColor(DisplayOfScreen(screen), colormap, str, &exactColor) &&
+           XAllocColor(DisplayOfScreen(screen), colormap, &exactColor)) {
+               *closure_ret = (char*)True;
+               done(Pixel, exactColor.pixel);
+       }
+
+       params[0] = str;
+       /* Server returns a specific error code but Xlib discards it.  Ugh */
+       if (XLookupColor(DisplayOfScreen(screen), colormap, (char*)str,
+                        &exactColor, &screenColor)) {
+           /* try to find another color that will do */
+           if (nhApproxColor(screen, colormap, (char*) str, &screenColor)) {
+               *closure_ret = (char*)True;
+               done(Pixel, screenColor.pixel);
+           }
+           type = "noColormap";
+           msg = "Cannot allocate colormap entry for \"%s\"";
+       }
+       else {
+           /* some versions of XLookupColor also don't allow #xxyyzz names */
+           if(str[0] == '#' &&
+              (nhApproxColor(screen, colormap, (char*) str, &screenColor))) {
+               *closure_ret = (char*)True;
+               done(Pixel, screenColor.pixel);
+           }
+           type = "badValue";
+           msg = "Color name \"%s\" is not defined";
+       }
+
+       XtAppWarningMsg(app, type, "cvtStringToPixel",
+                       "XtToolkitError", msg, params, &num_params);
+       *closure_ret = False;
+       return False;
+    } else {
+       *closure_ret = (char*)True;
+       done(Pixel, screenColor.pixel);
+    }
+}
+
+/* ARGSUSED */
+static void
+nhFreePixel(app, toVal, closure, args, num_args)
+XtAppContext   app;
+XrmValuePtr    toVal;
+XtPointer      closure;
+XrmValuePtr    args;
+Cardinal       *num_args;
+{
+    Screen         *screen;
+    Colormap       colormap;
+
+    if (*num_args != 2) {
+     XtAppWarningMsg(app, "wrongParameters",
+                    "freePixel", "XtToolkitError",
+                    "Freeing a pixel requires screen and colormap arguments",
+                    (String *)0, (Cardinal *)0);
+     return;
+    }
+
+    screen = *((Screen **) args[0].addr);
+    colormap = *((Colormap *) args[1].addr);
+
+    if (closure) {
+       XFreeColors( DisplayOfScreen(screen), colormap,
+                    (unsigned long*)toVal->addr, 1, (unsigned long)0
+                   );
+    }
+}
+
+/* [ALI] Utility function to ask Xaw for font height, since the previous
+ * assumption of ascent + descent is not always valid.
+ */
+Dimension
+nhFontHeight(w)
+Widget w;
+#ifdef _XawTextSink_h
+{
+    Widget sink;
+    XawTextPosition pos = 0;
+    int resWidth, resHeight;
+    Arg args[1];
+
+    XtSetArg(args[0], XtNtextSink, &sink);
+    XtGetValues(w, args, 1);
+
+    XawTextSinkFindPosition(sink, pos, 0, 0, 0, &pos, &resWidth, &resHeight);
+    return resHeight;
+}
+#else
+{
+    XFontStruct *fs;
+    Arg args[1];
+
+    XtSetArg(args[0], XtNfont, &fs);
+    XtGetValues(w, args, 1);
+
+    /* Assume font height is ascent + descent. */
+    return = fs->ascent + fs->descent;
+}
+#endif
+
+/* Global Functions ======================================================== */
+void
+X11_raw_print(str)
+    const char *str;
+{
+    (void) puts(str);
+}
+
+void
+X11_raw_print_bold(str)
+    const char *str;
+{
+    (void) puts(str);
+}
+
+void
+X11_curs(window, x, y)
+    winid window;
+    int x, y;
+{
+    check_winid(window);
+
+    if (x < 0 || x >= COLNO) {
+       impossible("curs:  bad x value [%d]", x);
+       x = 0;
+    }
+    if (y < 0 || y >= ROWNO) {
+       impossible("curs:  bad y value [%d]", y);
+       y = 0;
+    }
+
+    window_list[window].cursx = x;
+    window_list[window].cursy = y;
+}
+
+void
+X11_putstr(window, attr, str)
+    winid window;
+    int attr;
+    const char *str;
+{
+    winid new_win;
+    struct xwindow *wp;
+
+    check_winid(window);
+    wp = &window_list[window];
+
+    switch (wp->type) {
+       case NHW_MESSAGE:
+           (void) strncpy(toplines, str, TBUFSZ);      /* for Norep(). */
+           toplines[TBUFSZ - 1] = 0;
+           append_message(wp, str);
+           break;
+       case NHW_STATUS:
+           adjust_status(wp, str);
+           break;
+       case NHW_MAP:
+           impossible("putstr: called on map window \"%s\"", str);
+           break;
+       case NHW_MENU:
+           if (wp->menu_information->is_menu) {
+               impossible(
+                       "putstr:  called on a menu window, \"%s\" discarded",
+                       str);
+               break;
+           }
+           /*
+            * Change this menu window into a text window by creating a
+            * new text window, then copying it to this winid.
+            */
+           new_win = X11_create_nhwindow(NHW_TEXT);
+           X11_destroy_nhwindow(window);
+           *wp = window_list[new_win];
+           window_list[new_win].type = NHW_NONE;       /* allow re-use */
+           /* fall though to add text */
+       case NHW_TEXT:
+           add_to_text_window(wp, attr, str);
+           break;
+       default:
+           impossible("putstr: unknown window type [%d] \"%s\"",
+                                                           wp->type, str);
+    }
+}
+
+/* We do event processing as a callback, so this is a null routine. */
+void X11_get_nh_event() { return; }
+
+int
+X11_nhgetch()
+{
+    return input_event(EXIT_ON_KEY_PRESS);
+}
+
+
+int
+X11_nh_poskey(x, y, mod)
+    int *x, *y, *mod;
+{
+    int val = input_event(EXIT_ON_KEY_OR_BUTTON_PRESS);
+
+    if (val == 0) {    /* user clicked on a map window */
+       *x   = click_x;
+       *y   = click_y;
+       *mod = click_button;
+    }
+    return val;
+}
+
+
+winid
+X11_create_nhwindow(type)
+    int type;
+{
+    winid window;
+    struct xwindow *wp;
+
+    if (!x_inited)
+       panic("create_nhwindow:  windows not initialized");
+
+    /*
+     * We have already created the standard message, map, and status
+     * windows in the window init routine.  The first window of that
+     * type to be created becomes the standard.
+     *
+     * A better way to do this would be to say that init_nhwindows()
+     * has already defined these three windows.
+     */
+    if (type == NHW_MAP && map_win != WIN_ERR) {
+       window = map_win;
+       map_win = WIN_ERR;
+       return window;
+    }
+    if (type == NHW_MESSAGE && message_win != WIN_ERR) {
+       window = message_win;
+       message_win = WIN_ERR;
+       return window;
+    }
+    if (type == NHW_STATUS && status_win != WIN_ERR) {
+       window = status_win;
+       status_win = WIN_ERR;
+       return window;
+    }
+
+    window = find_free_window();
+    wp = &window_list[window];
+
+    /* The create routines will set type, popup, w, and Win_info. */
+    wp->prevx = wp->prevy = wp->cursx = wp->cursy =
+                               wp->pixel_width = wp->pixel_height = 0;
+    wp->keep_window = FALSE;
+
+    switch (type) {
+       case NHW_MAP:
+           create_map_window(wp, TRUE, (Widget) 0);
+           break;
+       case NHW_MESSAGE:
+           create_message_window(wp, TRUE, (Widget) 0);
+           break;
+       case NHW_STATUS:
+           create_status_window(wp, TRUE, (Widget) 0);
+           break;
+       case NHW_MENU:
+           create_menu_window(wp);
+           break;
+       case NHW_TEXT:
+           create_text_window(wp);
+           break;
+       default:
+           panic("create_nhwindow: unknown type [%d]", type);
+           break;
+    }
+    return window;
+}
+
+void
+X11_clear_nhwindow(window)
+    winid window;
+{
+    struct xwindow *wp;
+
+    check_winid(window);
+    wp = &window_list[window];
+
+    switch (wp->type) {
+       case NHW_MAP:   clear_map_window(wp); break;
+       case NHW_TEXT:  clear_text_window(wp); break;
+       case NHW_STATUS:
+       case NHW_MENU:
+       case NHW_MESSAGE:
+           /* do nothing for these window types */
+           break;
+       default:
+           panic("clear_nhwindow: unknown window type [%d]", wp->type);
+           break;
+    }
+}
+
+void
+X11_display_nhwindow(window, blocking)
+    winid window;
+    boolean blocking;
+{
+    struct xwindow *wp;
+
+    check_winid(window);
+    wp = &window_list[window];
+
+    switch (wp->type) {
+       case NHW_MAP:
+           if (wp->popup)
+               nh_XtPopup(wp->popup, (int)XtGrabNone, wp->w);
+           display_map_window(wp);     /* flush map */
+           /*
+            * We need to flush the message window here due to the way the tty
+            * port is set up.  To flush a window, you need to call this
+            * routine.  However, the tty port _pauses_ with a --more-- if we
+            * do a display_nhwindow(WIN_MESSAGE, FALSE).  Thus, we can't call
+            * display_nhwindow(WIN_MESSAGE,FALSE) in parse() because then we
+            * get a --more-- after every line.
+            *
+            * Perhaps the window document should mention that when the map
+            * is flushed, everything on the three main windows should be
+            * flushed.  Note: we don't need to flush the status window
+            * because we don't buffer changes.
+            */
+           if (WIN_MESSAGE != WIN_ERR)
+               display_message_window(&window_list[WIN_MESSAGE]);
+           if (blocking)
+               (void) x_event(EXIT_ON_KEY_OR_BUTTON_PRESS);
+           break;
+       case NHW_MESSAGE:
+           if (wp->popup)
+                nh_XtPopup(wp->popup, (int)XtGrabNone, wp->w);
+           display_message_window(wp); /* flush messages */
+           break;
+       case NHW_STATUS:
+           if (wp->popup)
+               nh_XtPopup(wp->popup, (int)XtGrabNone, wp->w);
+           break;                      /* no flushing necessary */
+       case NHW_MENU: {
+           int n;
+           menu_item *selected;
+
+           /* pop up menu */
+           n = X11_select_menu(window, PICK_NONE, &selected);
+           if (n) {
+               impossible("perminvent: %d selected??", n);
+               free((genericptr_t)selected);
+           }
+           break;
+       }
+       case NHW_TEXT:
+           display_text_window(wp, blocking);  /* pop up text window */
+           break;
+       default:
+           panic("display_nhwindow: unknown window type [%d]", wp->type);
+           break;
+    }
+}
+
+void
+X11_destroy_nhwindow(window)
+    winid window;
+{
+    struct xwindow *wp;
+
+    check_winid(window);
+    wp = &window_list[window];
+    /*
+     * "Zap" known windows, but don't destroy them.  We need to keep the
+     * toplevel widget popped up so that later windows (e.g. tombstone)
+     * are visible on DECWindow systems.  This is due to the virtual
+     * roots that the DECWindow wm creates.
+     */
+    if (window == WIN_MESSAGE) {
+       wp->keep_window = TRUE;
+       WIN_MESSAGE = WIN_ERR;
+       iflags.window_inited = 0;
+    } else if (window == WIN_MAP) {
+       wp->keep_window = TRUE;
+       WIN_MAP = WIN_ERR;
+    } else if (window == WIN_STATUS) {
+       wp->keep_window = TRUE;
+       WIN_STATUS = WIN_ERR;
+    } else if (window == WIN_INVEN) {
+       /* don't need to keep this one */
+       WIN_INVEN = WIN_ERR;
+    }
+
+    switch (wp->type) {
+       case NHW_MAP:
+           destroy_map_window(wp);
+           break;
+       case NHW_MENU:
+           destroy_menu_window(wp);
+           break;
+       case NHW_TEXT:
+           destroy_text_window(wp);
+           break;
+       case NHW_STATUS:
+           destroy_status_window(wp);
+           break;
+       case NHW_MESSAGE:
+           destroy_message_window(wp);
+           break;
+       default:
+           panic("destroy_nhwindow: unknown window type [%d]", wp->type);
+           break;
+    }
+}
+
+void
+X11_update_inventory()
+{
+    if (x_inited && window_list[WIN_INVEN].menu_information->is_up) {
+       updated_inventory = 1;  /* hack to avoid mapping&raising window */
+       (void) display_inventory((char *)0, FALSE);
+       updated_inventory = 0;
+    }
+}
+
+/* The current implementation has all of the saved lines on the screen. */
+int X11_doprev_message() { return 0; }
+
+void
+X11_nhbell()
+{
+    /* We can't use XBell until toplevel has been initialized. */
+    if (x_inited)
+       XBell(XtDisplay(toplevel), 0);
+    /* else print ^G ?? */
+}
+
+void X11_mark_synch()
+{
+    if (x_inited) {
+       /*
+        * The window document is unclear about the status of text
+        * that has been pline()d but not displayed w/display_nhwindow().
+        * Both the main and tty code assume that a pline() followed
+        * by mark_synch() results in the text being seen, even if
+        * display_nhwindow() wasn't called.  Duplicate this behavior.
+        */
+       if (WIN_MESSAGE != WIN_ERR)
+           display_message_window(&window_list[WIN_MESSAGE]);
+       XSync(XtDisplay(toplevel), False);
+    }
+}
+
+void X11_wait_synch() { if (x_inited) XFlush(XtDisplay(toplevel)); }
+
+
+/* Both resume_ and suspend_ are called from ioctl.c and unixunix.c. */
+void X11_resume_nhwindows() { return; }
+
+/* ARGSUSED */
+void X11_suspend_nhwindows(str) const char *str; { return; }
+
+/* Under X, we don't need to initialize the number pad. */
+/* ARGSUSED */
+void X11_number_pad(state) int state; { return; } /* called from options.c */
+
+
+void X11_start_screen() { return; } /* called from setftty() in unixtty.c */
+void X11_end_screen() { return; }   /* called from settty() in unixtty.c */
+
+#ifdef GRAPHIC_TOMBSTONE
+void X11_outrip(window, how)
+    winid window;
+    int how;
+{
+    struct xwindow *wp;
+
+    check_winid(window);
+    wp = &window_list[window];
+
+    if (wp->type == NHW_TEXT) {
+       wp->text_information->is_rip = TRUE;
+    } else {
+       panic("ripout on non-text window (window type [%d])", wp->type);
+    }
+
+    calculate_rip_text(how);
+}
+#endif
+
+/* init and exit nhwindows ------------------------------------------------- */
+
+XtAppContext app_context;              /* context of application */
+Widget      toplevel = (Widget) 0;     /* toplevel widget */
+Atom         wm_delete_window;         /* pop down windows */
+
+static XtActionsRec actions[] = {
+    {"dismiss_file",   dismiss_file},  /* action for file viewing widget */
+    {"delete_file",    delete_file},   /* action for file delete-window */
+    {"dismiss_text",   dismiss_text},  /* button action for text widget */
+    {"delete_text",    delete_text},   /* delete action for text widget */
+    {"key_dismiss_text",key_dismiss_text},/* key action for text widget */
+#ifdef GRAPHIC_TOMBSTONE
+    {"rip_dismiss_text",rip_dismiss_text},/* action for rip in text widget */
+#endif
+    {"menu_key",       menu_key},      /* action for menu accelerators */
+    {"yn_key",         yn_key},        /* action for yn accelerators */
+    {"yn_delete",      yn_delete},     /* action for yn delete-window */
+    {"askname_delete", askname_delete},/* action for askname delete-window */
+    {"getline_delete", getline_delete},/* action for getline delete-window */
+    {"menu_delete",    menu_delete},   /* action for menu delete-window */
+    {"ec_key",         ec_key},        /* action for extended commands */
+    {"ec_delete",      ec_delete},     /* action for ext-com menu delete */
+    {"ps_key",         ps_key},        /* action for player selection */
+    {"race_key",       race_key},      /* action for race selection */
+    {"gend_key",       gend_key},      /* action for gender selection */
+    {"algn_key",       algn_key},      /* action for alignment selection */
+    {"X11_hangup",     X11_hangup},    /* action for delete of top-level */
+    {"input",          map_input},     /* action for key input */
+    {"scroll",         nh_keyscroll},  /* action for scrolling by keys */
+};
+
+static XtResource resources[] = {
+    { "slow", "Slow", XtRBoolean, sizeof(Boolean),
+      XtOffset(AppResources *,slow), XtRString, "True" },
+    { "autofocus", "AutoFocus", XtRBoolean, sizeof(Boolean),
+      XtOffset(AppResources *,autofocus), XtRString, "False" },
+    { "message_line", "Message_line", XtRBoolean, sizeof(Boolean),
+      XtOffset(AppResources *,message_line), XtRString, "False" },
+    { "double_tile_size", "Double_tile_size", XtRBoolean, sizeof(Boolean),
+      XtOffset(AppResources *,double_tile_size), XtRString, "False" },
+    { "tile_file", "Tile_file", XtRString, sizeof(String),
+      XtOffset(AppResources *,tile_file), XtRString, "" },
+    { "icon", "Icon", XtRString, sizeof(String),
+      XtOffset(AppResources *,icon), XtRString, "nh72" },
+    { "message_lines", "Message_lines", XtRInt, sizeof(int),
+      XtOffset(AppResources *,message_lines), XtRString, "12" },
+    { "pet_mark_bitmap", "Pet_mark_bitmap", XtRString, sizeof(String),
+      XtOffset(AppResources *,pet_mark_bitmap), XtRString, "pet_mark.xbm" },
+    { "pet_mark_color", "Pet_mark_color", XtRPixel, sizeof(XtRPixel),
+      XtOffset(AppResources *,pet_mark_color), XtRString, "Red" },
+#ifdef GRAPHIC_TOMBSTONE
+    { "tombstone", "Tombstone", XtRString, sizeof(String),
+      XtOffset(AppResources *,tombstone), XtRString, "rip.xpm" },
+    { "tombtext_x", "Tombtext_x", XtRInt, sizeof(int),
+      XtOffset(AppResources *,tombtext_x), XtRString, "155" },
+    { "tombtext_y", "Tombtext_y", XtRInt, sizeof(int),
+      XtOffset(AppResources *,tombtext_y), XtRString, "78" },
+    { "tombtext_dx", "Tombtext_dx", XtRInt, sizeof(int),
+      XtOffset(AppResources *,tombtext_dx), XtRString, "0" },
+    { "tombtext_dy", "Tombtext_dy", XtRInt, sizeof(int),
+      XtOffset(AppResources *,tombtext_dy), XtRString, "13" },
+#endif
+};
+
+void
+X11_init_nhwindows(argcp,argv)
+int* argcp;
+char** argv;
+{
+    static const char *banner_text[] = {
+       COPYRIGHT_BANNER_A,
+       COPYRIGHT_BANNER_B,
+       COPYRIGHT_BANNER_C,
+       "",
+       "",
+       0
+    };
+    register const char **pp;
+    int i;
+    Cardinal num_args;
+    Arg args[4];
+    uid_t savuid;
+
+    /* Init windows to nothing. */
+    for (i = 0; i < MAX_WINDOWS; i++)
+       window_list[i].type = NHW_NONE;
+
+    /*
+     * setuid hack: make sure that if nethack is setuid, to use real uid
+     * when opening X11 connections, in case the user is using xauth, since
+     * the "games" or whatever user probably doesn't have permission to open
+     * a window on the user's display.  This code is harmless if the binary
+     * is not installed setuid.  See include/system.h on compilation failures.
+     */
+    savuid = geteuid();
+    (void) seteuid(getuid());
+
+    XSetIOErrorHandler((XIOErrorHandler) hangup);
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNallowShellResize, True);       num_args++;
+    toplevel = XtAppInitialize(
+                   &app_context,
+                   "NetHack",                  /* application class */
+                   (XrmOptionDescList)0, 0,    /* options list */
+                   argcp, (String *)argv,      /* command line args */
+                   (String *)0,                /* fallback resources */
+                   (ArgList)args, num_args);
+    XtOverrideTranslations(toplevel,
+       XtParseTranslationTable("<Message>WM_PROTOCOLS: X11_hangup()"));
+
+    /* We don't need to realize the top level widget. */
+
+#ifdef TEXTCOLOR
+    /* add new color converter to deal with overused colormaps */
+    XtSetTypeConverter(XtRString, XtRPixel, nhCvtStringToPixel,
+                      (XtConvertArgList)nhcolorConvertArgs,
+                      XtNumber(nhcolorConvertArgs),
+                      XtCacheByDisplay, nhFreePixel);
+#endif /* TEXTCOLOR */
+
+    /* Register the actions mentioned in "actions". */
+    XtAppAddActions(app_context, actions, XtNumber(actions));
+
+    /* Get application-wide resources */
+    XtGetApplicationResources(toplevel, (XtPointer)&appResources,
+                             resources, XtNumber(resources),
+                             (ArgList)0, ZERO);
+
+    /* Initialize other things. */
+    init_standard_windows();
+
+    /* Give the window manager an icon to use;  toplevel must be realized. */
+    if (appResources.icon && *appResources.icon) {
+       struct icon_info *ip;
+
+       for (ip = icon_data; ip->name; ip++)
+           if (!strcmp(appResources.icon, ip->name)) {
+               icon_pixmap = XCreateBitmapFromData(XtDisplay(toplevel),
+                               XtWindow(toplevel),
+                               (genericptr_t)ip->bits, ip->width, ip->height);
+               if (icon_pixmap != None) {
+                   XWMHints hints;
+
+                   (void) memset((genericptr_t)&hints, 0, sizeof(XWMHints));
+                   hints.flags = IconPixmapHint;
+                   hints.icon_pixmap = icon_pixmap;
+                   XSetWMHints(XtDisplay(toplevel),
+                               XtWindow(toplevel), &hints);
+               }
+               break;
+           }
+    }
+
+    /* end of setuid hack: reset uid back to the "games" uid */
+    (void) seteuid(savuid);
+
+    x_inited = TRUE;   /* X is now initialized */
+
+    /* Display the startup banner in the message window. */
+    for (pp = banner_text; *pp; pp++)
+       X11_putstr(WIN_MESSAGE, 0, *pp);
+}
+
+/*
+ * All done.
+ */
+/* ARGSUSED */
+void X11_exit_nhwindows(dummy)
+    const char *dummy;
+{
+    extern Pixmap tile_pixmap; /* from winmap.c */
+
+    /* explicitly free the icon and tile pixmaps */
+    if (icon_pixmap != None) {
+       XFreePixmap(XtDisplay(toplevel), icon_pixmap);
+       icon_pixmap = None;
+    }
+    if (tile_pixmap != None) {
+       XFreePixmap(XtDisplay(toplevel), tile_pixmap);
+       tile_pixmap = None;
+    }
+    if (WIN_INVEN != WIN_ERR)
+       X11_destroy_nhwindow(WIN_INVEN);
+    if (WIN_STATUS != WIN_ERR)
+       X11_destroy_nhwindow(WIN_STATUS);
+    if (WIN_MAP != WIN_ERR)
+       X11_destroy_nhwindow(WIN_MAP);
+    if (WIN_MESSAGE != WIN_ERR)
+       X11_destroy_nhwindow(WIN_MESSAGE);
+}
+
+
+/* delay_output ------------------------------------------------------------ */
+
+/*
+ * Timeout callback for delay_output().  Send a fake message to the map
+ * window.
+ */
+/* ARGSUSED */
+static void
+d_timeout(client_data, id)
+    XtPointer client_data;
+    XtIntervalId *id;
+{
+    XEvent event;
+    XClientMessageEvent *mesg;
+
+    /* Set up a fake message to the event handler. */
+    mesg = (XClientMessageEvent *) &event;
+    mesg->type = ClientMessage;
+    mesg->message_type = XA_STRING;
+    mesg->format = 8;
+    XSendEvent(XtDisplay(window_list[WIN_MAP].w),
+               XtWindow(window_list[WIN_MAP].w),
+               False,
+               NoEventMask,
+               (XEvent*) mesg);
+}
+
+/*
+ * Delay for 50ms.  This is not implemented asynch.  Maybe later.
+ * Start the timeout, then wait in the event loop.  The timeout
+ * function will send an event to the map window which will be waiting
+ * for a sent event.
+ */
+void
+X11_delay_output()
+{
+    if (!x_inited) return;
+
+    (void) XtAppAddTimeOut(app_context, 30L, d_timeout, (XtPointer) 0);
+
+    /* The timeout function will enable the event loop exit. */
+    (void) x_event(EXIT_ON_SENT_EVENT);
+}
+
+/* X11_hangup -------------------------------------------------------------- */
+/* ARGSUSED */
+static void
+X11_hangup(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    hangup(1);         /* 1 is commonly SIGHUP, but ignored anyway */
+}
+
+/* askname ----------------------------------------------------------------- */
+/* ARGSUSED */
+static void
+askname_delete(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    nh_XtPopdown(w);
+    (void) strcpy(plname, "Mumbles");  /* give them a name... ;-) */
+    exit_x_event = TRUE;
+}
+
+/* Callback for askname dialog widget. */
+/* ARGSUSED */
+static void
+askname_done(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data;
+    XtPointer call_data;
+{
+    int len;
+    char *s;
+    Widget dialog = (Widget) client_data;
+
+    s = (char *) GetDialogResponse(dialog);
+
+    len = strlen(s);
+    if (len == 0) {
+       X11_nhbell();
+       return;
+    }
+
+    /* Truncate name if necessary */
+    if (len >= sizeof(plname)-1)
+       len = sizeof(plname)-1;
+
+    (void) strncpy(plname, s, len);
+    plname[len] = '\0';
+    XtFree(s);
+
+    nh_XtPopdown(XtParent(dialog));
+    exit_x_event = TRUE;
+}
+
+void
+X11_askname()
+{
+    Widget popup, dialog;
+    Arg args[1];
+
+    XtSetArg(args[0], XtNallowShellResize, True);
+
+    popup = XtCreatePopupShell("askname", transientShellWidgetClass,
+                                  toplevel, args, ONE);
+    XtOverrideTranslations(popup,
+       XtParseTranslationTable("<Message>WM_PROTOCOLS: askname_delete()"));
+
+    dialog = CreateDialog(popup, "dialog",
+                                   askname_done, (XtCallbackProc) 0);
+
+    SetDialogPrompt(dialog, "What is your name?");     /* set prompt */
+    SetDialogResponse(dialog, "");             /* set default answer */
+
+    XtRealizeWidget(popup);
+    positionpopup(popup, TRUE);                /* center,bottom */
+
+    nh_XtPopup(popup, (int)XtGrabExclusive, dialog);
+
+    /* The callback will enable the event loop exit. */
+    (void) x_event(EXIT_ON_EXIT);
+}
+
+
+/* getline ----------------------------------------------------------------- */
+/* This uses Tim Theisen's dialog widget set (from GhostView). */
+
+static Widget getline_popup, getline_dialog;
+
+#define CANCEL_STR "\033"
+static char *getline_input;
+
+
+/* Callback for getline dialog widget. */
+/* ARGSUSED */
+static void
+done_button(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data;
+    XtPointer call_data;
+{
+    int len;
+    char *s;
+    Widget dialog = (Widget) client_data;
+
+    s = (char *) GetDialogResponse(dialog);
+    len = strlen(s);
+
+    /* Truncate input if necessary */
+    if (len >= BUFSZ) len = BUFSZ - 1;
+
+    (void) strncpy(getline_input, s, len);
+    getline_input[len] = '\0';
+    XtFree(s);
+
+    nh_XtPopdown(XtParent(dialog));
+    exit_x_event = TRUE;
+}
+
+/* ARGSUSED */
+static void
+getline_delete(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    Strcpy(getline_input, CANCEL_STR);
+    nh_XtPopdown(w);
+    exit_x_event = TRUE;
+}
+
+/* Callback for getline dialog widget. */
+/* ARGSUSED */
+static void
+abort_button(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data;
+    XtPointer call_data;
+{
+    Widget dialog = (Widget) client_data;
+
+    Strcpy(getline_input, CANCEL_STR);
+    nh_XtPopdown(XtParent(dialog));
+    exit_x_event = TRUE;
+}
+
+
+void
+X11_getlin(question, input)
+    const char *question;
+    char *input;
+{
+    static boolean need_to_init = True;
+
+    getline_input = input;
+
+    flush_screen(1);
+    if (need_to_init) {
+       Arg args[1];
+
+       need_to_init = False;
+
+       XtSetArg(args[0], XtNallowShellResize, True);
+
+       getline_popup = XtCreatePopupShell("getline",transientShellWidgetClass,
+                                  toplevel, args, ONE);
+       XtOverrideTranslations(getline_popup,
+           XtParseTranslationTable("<Message>WM_PROTOCOLS: getline_delete()"));
+
+       getline_dialog = CreateDialog(getline_popup, "dialog",
+                                   done_button, abort_button);
+
+       XtRealizeWidget(getline_popup);
+       XSetWMProtocols(XtDisplay(getline_popup), XtWindow(getline_popup),
+                       &wm_delete_window, 1);
+    }
+    SetDialogPrompt(getline_dialog, (String)question); /* set prompt */
+    SetDialogResponse(getline_dialog, "");     /* set default answer */
+    positionpopup(getline_popup, TRUE);                /* center,bottom */
+
+    nh_XtPopup(getline_popup, (int)XtGrabExclusive, getline_dialog);
+
+    /* The callback will enable the event loop exit. */
+    (void) x_event(EXIT_ON_EXIT);
+}
+
+
+/* Display file ------------------------------------------------------------ */
+static const char display_translations[] =
+    "#override\n\
+     <Key>q: dismiss_file()\n\
+     <Key>Escape: dismiss_file()\n\
+     <BtnDown>: dismiss_file()";
+
+
+/* WM_DELETE_WINDOW callback for file dismissal. */
+/*ARGSUSED*/
+static void
+delete_file(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    nh_XtPopdown(w);
+    XtDestroyWidget(w);
+}
+
+/* Callback for file dismissal. */
+/*ARGSUSED*/
+static void
+dismiss_file(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    Widget popup = XtParent(w);
+    nh_XtPopdown(popup);
+    XtDestroyWidget(popup);
+}
+
+void
+X11_display_file(str, complain)
+    const char *str;
+    boolean complain;
+{
+    dlb *fp;
+    Arg args[12];
+    Cardinal num_args;
+    Widget popup, dispfile;
+    Position top_margin, bottom_margin, left_margin, right_margin;
+    XFontStruct *fs;
+    int new_width, new_height;
+#define LLEN 128
+    char line[LLEN];
+    int num_lines;
+    char *textlines;
+    int charcount;
+
+    /* Use the port-independent file opener to see if the file exists. */
+    fp = dlb_fopen(str, RDTMODE);
+
+    if (!fp) {
+       if(complain) pline("Cannot open %s.  Sorry.", str);
+
+       return; /* it doesn't exist, ignore */
+    }
+
+    /*
+     * Count the number of lines and characters in the file.
+     */
+    num_lines = 0;
+    charcount = 1;
+    while (dlb_fgets(line, LLEN, fp)) {
+       num_lines++;
+       charcount += strlen(line);
+    }
+
+    (void) dlb_fclose(fp);
+
+    /* Ignore empty files */
+    if (num_lines == 0) return;
+
+    /* If over the max window size, truncate the window size to the max */
+    if (num_lines >= DISPLAY_FILE_SIZE)
+       num_lines = DISPLAY_FILE_SIZE;
+
+    /*
+     * Re-open the file and read the data into a buffer.  Cannot use
+     * the XawAsciiFile type of widget, because that is not DLB-aware.
+     */
+    textlines = (char *) alloc((unsigned int) charcount);
+    textlines[0] = '\0';
+
+    fp = dlb_fopen(str, RDTMODE);
+
+    while (dlb_fgets(line, LLEN, fp)) {
+       (void) strcat(textlines, line);
+    }
+
+    (void) dlb_fclose(fp);
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNtitle, str);   num_args++;
+
+    popup = XtCreatePopupShell("display_file", topLevelShellWidgetClass,
+                                              toplevel, args, num_args);
+    XtOverrideTranslations(popup,
+       XtParseTranslationTable("<Message>WM_PROTOCOLS: delete_file()"));
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNscrollHorizontal,
+                               XawtextScrollWhenNeeded);       num_args++;
+    XtSetArg(args[num_args], XtNscrollVertical,
+                               XawtextScrollWhenNeeded);       num_args++;
+    XtSetArg(args[num_args], XtNtype, XawAsciiString);         num_args++;
+    XtSetArg(args[num_args], XtNstring, textlines);            num_args++;
+    XtSetArg(args[num_args], XtNdisplayCaret, False);          num_args++;
+    XtSetArg(args[num_args], XtNtranslations,
+       XtParseTranslationTable(display_translations));         num_args++;
+
+    dispfile = XtCreateManagedWidget(
+                       "text",                 /* name */
+                       asciiTextWidgetClass,
+                       popup,                  /* parent widget */
+                       args,                   /* set some values */
+                       num_args);              /* number of values to set */
+
+    /* Get font and border information. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNfont,        &fs);            num_args++;
+    XtSetArg(args[num_args], XtNtopMargin,    &top_margin);    num_args++;
+    XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++;
+    XtSetArg(args[num_args], XtNleftMargin,   &left_margin);   num_args++;
+    XtSetArg(args[num_args], XtNrightMargin,  &right_margin);  num_args++;
+    XtGetValues(dispfile, args, num_args);
+
+    /*
+     * The data files are currently set up assuming an 80 char wide window
+     * and a fixed width font.  Soo..
+     */
+    new_height = num_lines * nhFontHeight(dispfile) +
+                                               top_margin + bottom_margin;
+    new_width  = 80 * fs->max_bounds.width + left_margin + right_margin;
+
+    /* Set the new width and height. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNwidth,  new_width);  num_args++;
+    XtSetArg(args[num_args], XtNheight, new_height); num_args++;
+    XtSetValues(dispfile, args, num_args);
+
+    nh_XtPopup(popup, (int)XtGrabNone, (Widget)0);
+    free(textlines);
+}
+
+
+/* yn_function ------------------------------------------------------------- */
+/* (not threaded) */
+
+static const char *yn_quitchars = " \n\r";
+static const char *yn_choices; /* string of acceptable input */
+static char yn_def;
+static char yn_return;         /* return value */
+static char yn_esc_map;                /* ESC maps to this char. */
+static Widget yn_popup;                /* popup for the yn fuction (created once) */
+static Widget yn_label;                /* label for yn function (created once) */
+static boolean yn_getting_num; /* TRUE if accepting digits */
+static int yn_ndigits;         /* digit count */
+static long yn_val;            /* accumulated value */
+
+static const char yn_translations[] =
+    "#override\n\
+     <Key>: yn_key()";
+
+/*
+ * Convert the given key event into a character.  If the key maps to
+ * more than one character only the first is returned.  If there is
+ * no conversion (i.e. just the CTRL key hit) a NUL is returned.
+ */
+char
+key_event_to_char(key)
+    XKeyEvent *key;
+{
+    char keystring[MAX_KEY_STRING];
+    int nbytes;
+    boolean meta = !!(key->state & Mod1Mask);
+
+    nbytes = XLookupString(key, keystring, MAX_KEY_STRING,
+                          (KeySym *)0, (XComposeStatus *)0);
+
+    /* Modifier keys return a zero lengh string when pressed. */
+    if (nbytes == 0) return '\0';
+
+    return (char) (((int) keystring[0]) + (meta ? 0x80 : 0));
+}
+
+/*
+ * Called when we get a WM_DELETE_WINDOW event on a yn window.
+ */
+/* ARGSUSED */
+static void
+yn_delete(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    yn_getting_num = FALSE;
+    /* Only use yn_esc_map if we have choices.  Otherwise, return ESC. */
+    yn_return = yn_choices ? yn_esc_map : '\033';
+    exit_x_event = TRUE;       /* exit our event handler */
+}
+
+/*
+ * Called when we get a key press event on a yn window.
+ */
+/* ARGSUSED */
+static void
+yn_key(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    char ch;
+
+    if(appResources.slow && !input_func)
+       map_input(w, event, params, num_params);
+
+    ch = key_event_to_char((XKeyEvent *) event);
+
+    if (ch == '\0') {  /* don't accept nul char or modifier event */
+       /* no bell */
+       return;
+    }
+
+    if (!yn_choices) {                 /* accept any input */
+       yn_return = ch;
+    } else {
+       ch = lowc(ch);                  /* move to lower case */
+
+       if (ch == '\033') {
+           yn_getting_num = FALSE;
+           yn_return = yn_esc_map;
+       } else if (index(yn_quitchars, ch)) {
+           yn_return = yn_def;
+       } else if (index(yn_choices, ch)) {
+           if (ch == '#') {
+               if (yn_getting_num) {   /* don't select again */
+                   X11_nhbell();
+                   return;
+               }
+               yn_getting_num = TRUE;
+               yn_ndigits = 0;
+               yn_val = 0;
+               return;                 /* wait for more input */
+           }
+           yn_return = ch;
+           if (ch != 'y') yn_getting_num = FALSE;
+       } else {
+           if (yn_getting_num) {
+               if (digit(ch)) {
+                   yn_ndigits++;
+                   yn_val = (yn_val * 10) + (long) (ch - '0');
+                   return;                     /* wait for more input */
+               }
+               if (yn_ndigits && (ch == '\b' || ch == 127/*DEL*/)) {
+                   yn_ndigits--;
+                   yn_val = yn_val/ 10;
+                   return;                     /* wait for more input */
+               }
+           }
+           X11_nhbell();               /* no match */
+           return;
+       }
+
+       if (yn_getting_num) {
+           yn_return = '#';
+           if (yn_val < 0) yn_val = 0;
+           yn_number = yn_val; /* assign global */
+       }
+    }
+    exit_x_event = TRUE;       /* exit our event handler */
+}
+
+
+char
+X11_yn_function(ques, choices, def)
+    const char *ques;
+    const char *choices;
+    char def;
+{
+    static Boolean need_to_init = True;
+    char buf[QBUFSZ];
+    Arg args[4];
+    Cardinal num_args;
+
+    yn_choices = choices;      /* set up globals for callback to use */
+    yn_def     = def;
+
+    /*
+     * This is sort of a kludge.  There are quite a few places in the main
+     * nethack code where a pline containing information is followed by a
+     * call to yn_function().  There is no flush of the message window
+     * (it is implicit in the tty window port), so the line never shows
+     * up for us!  Solution: do our own flush.
+     */
+    if (WIN_MESSAGE != WIN_ERR)
+       display_message_window(&window_list[WIN_MESSAGE]);
+
+    if (choices) {
+       char *cb, choicebuf[QBUFSZ];
+
+       Strcpy(choicebuf, choices);     /* anything beyond <esc> is hidden */
+       if ((cb = index(choicebuf, '\033')) != 0) *cb = '\0';
+       /* ques [choices] (def) */
+       if ((int)(1 + strlen(ques) + 2 + strlen(choicebuf) + 4) >= QBUFSZ)
+           panic("yn_function:  question too long");
+       Sprintf(buf, "%s [%s] ", ques, choicebuf);
+       if (def) Sprintf(eos(buf), "(%c) ", def);
+
+       /* escape maps to 'q' or 'n' or default, in that order */
+       yn_esc_map = (index(choices, 'q') ? 'q' :
+                    (index(choices, 'n') ? 'n' :
+                                           def));
+    } else {
+       if ((int)(1 + strlen(ques)) >= QBUFSZ)
+           panic("yn_function:  question too long");
+       Strcpy(buf, ques);
+    }
+
+    if (!appResources.slow && need_to_init) {
+       need_to_init = False;
+
+       XtSetArg(args[0], XtNallowShellResize, True);
+       yn_popup = XtCreatePopupShell("query", transientShellWidgetClass,
+                                       toplevel, args, ONE);
+       XtOverrideTranslations(yn_popup,
+           XtParseTranslationTable("<Message>WM_PROTOCOLS: yn_delete()"));
+
+       num_args = 0;
+       XtSetArg(args[num_args], XtNtranslations,
+               XtParseTranslationTable(yn_translations));      num_args++;
+       yn_label = XtCreateManagedWidget("yn_label",
+                               labelWidgetClass,
+                               yn_popup,
+                               args, num_args);
+
+       XtRealizeWidget(yn_popup);
+       XSetWMProtocols(XtDisplay(yn_popup), XtWindow(yn_popup),
+                       &wm_delete_window, 1);
+    }
+
+    if(appResources.slow)
+       input_func = yn_key;
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNlabel, buf);   num_args++;
+    XtSetValues(yn_label, args, num_args);
+
+    if(!appResources.slow) {
+       /*
+        * Due to some kind of weird bug in the X11R4 and X11R5 shell, we
+        * need to set the label twice to get the size to change.
+        */
+       num_args = 0;
+       XtSetArg(args[num_args], XtNlabel, buf); num_args++;
+       XtSetValues(yn_label, args, num_args);
+
+       positionpopup(yn_popup, TRUE);
+       nh_XtPopup(yn_popup, (int)XtGrabExclusive, yn_label);
+    }
+
+    yn_getting_num = FALSE;
+    (void) x_event(EXIT_ON_EXIT);
+
+    if(appResources.slow) {
+       input_func = 0;
+       num_args = 0;
+       XtSetArg(args[num_args], XtNlabel, " ");        num_args++;
+       XtSetValues(yn_label, args, num_args);
+    } else {
+       nh_XtPopdown(yn_popup); /* this removes the event grab */
+    }
+
+    return yn_return;
+}
+
+/* End global functions ==================================================== */
+
+/*
+ * Before we wait for input via nhgetch() and nh_poskey(), we need to
+ * do some pre-processing.
+ */
+static int
+input_event(exit_condition)
+    int exit_condition;
+{
+    if (WIN_STATUS != WIN_ERR) /* hilighting on the fancy status window */
+       check_turn_events();
+    if (WIN_MAP != WIN_ERR)    /* make sure cursor is not clipped */
+       check_cursor_visibility(&window_list[WIN_MAP]);
+    if (WIN_MESSAGE != WIN_ERR)        /* reset pause line */
+       set_last_pause(&window_list[WIN_MESSAGE]);
+
+    return x_event(exit_condition);
+}
+
+
+/*ARGSUSED*/
+void
+msgkey(w, data, event)
+    Widget w;
+    XtPointer data;
+    XEvent *event;
+{
+    Cardinal num = 0;
+    map_input(window_list[WIN_MAP].w, event, (String*) 0, &num);
+}
+
+/*ARGSUSED*/
+static void
+win_visible(w, data, event, flag)      /* only called for autofocus */
+    Widget w;
+    XtPointer data;    /* client_data not used */
+    XEvent *event;
+    Boolean *flag;     /* continue_to_dispatch flag not used */
+{
+    XVisibilityEvent *vis_event = (XVisibilityEvent *)event;
+
+    if (vis_event->state != VisibilityFullyObscured) {
+       /* one-time operation; cancel ourself */
+       XtRemoveEventHandler(toplevel, VisibilityChangeMask, False,
+                            win_visible, (XtPointer) 0);
+       /* grab initial input focus */
+       XSetInputFocus(XtDisplay(w), XtWindow(w), RevertToNone, CurrentTime);
+    }
+}
+
+/*
+ * Set up the playing console.  This has three major parts:  the
+ * message window, the map, and the status window.
+ */
+static void
+init_standard_windows()
+{
+    Widget form, message_viewport, map_viewport, status;
+    Arg args[8];
+    Cardinal num_args;
+    Dimension message_vp_width, map_vp_width, status_width, max_width;
+    int map_vp_hd, status_hd;
+    struct xwindow *wp;
+
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNallowShellResize, True);       num_args++;
+    form = XtCreateManagedWidget("nethack",
+                               panedWidgetClass,
+                               toplevel, args, num_args);
+
+    XtAddEventHandler(form, KeyPressMask, False,
+                     (XtEventHandler) msgkey, (XtPointer) 0);
+
+    if (appResources.autofocus)
+       XtAddEventHandler(toplevel, VisibilityChangeMask, False,
+                         win_visible, (XtPointer) 0);
+
+    /*
+     * Create message window.
+     */
+    WIN_MESSAGE = message_win = find_free_window();
+    wp = &window_list[message_win];
+    wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0;
+    wp->popup = (Widget) 0;
+    create_message_window(wp, FALSE, form);
+    message_viewport = XtParent(wp->w);
+
+
+    /* Tell the form that contains it that resizes are OK. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNresizable, True);              num_args++;
+    XtSetArg(args[num_args], XtNleft,     XtChainLeft);        num_args++;
+    XtSetArg(args[num_args], XtNtop,      XtChainTop);         num_args++;
+    XtSetValues(message_viewport, args, num_args);
+
+    if(appResources.slow) {
+       num_args = 0;
+       XtSetArg(args[num_args], XtNtranslations,
+                XtParseTranslationTable(yn_translations)); num_args++;
+       yn_label = XtCreateManagedWidget("yn_label",
+                                        labelWidgetClass,
+                                        form,
+                                        args, num_args);
+       num_args = 0;
+       XtSetArg(args[num_args], XtNfromVert, message_viewport); num_args++;
+       XtSetArg(args[num_args], XtNjustify, XtJustifyLeft);    num_args++;
+       XtSetArg(args[num_args], XtNresizable, True);   num_args++;
+       XtSetArg(args[num_args], XtNlabel, " ");        num_args++;
+       XtSetValues(yn_label, args, num_args);
+    }
+
+    /*
+     * Create the map window & viewport and chain the viewport beneath the
+     * message_viewport.
+     */
+    map_win = find_free_window();
+    wp = &window_list[map_win];
+    wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0;
+    wp->popup = (Widget) 0;
+    create_map_window(wp, FALSE, form);
+    map_viewport = XtParent(wp->w);
+
+    /* Chain beneath message_viewport or yn window. */
+    num_args = 0;
+    if(appResources.slow) {
+       XtSetArg(args[num_args], XtNfromVert, yn_label);        num_args++;
+    } else {
+       XtSetArg(args[num_args], XtNfromVert, message_viewport);num_args++;
+    }
+    XtSetArg(args[num_args], XtNbottom, XtChainBottom);                num_args++;
+    XtSetValues(map_viewport, args, num_args);
+
+    /* Create the status window, with the form as it's parent. */
+    status_win = find_free_window();
+    wp = &window_list[status_win];
+    wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0;
+    wp->popup = (Widget) 0;
+    create_status_window(wp, FALSE, form);
+    status = wp->w;
+
+    /*
+     * Chain the status window beneath the viewport.  Mark the left and right
+     * edges so that they stay a fixed distance from the left edge of the
+     * parent, as well as the top and bottom edges so that they stay a fixed
+     * distance from the bottom of the parent.  We do this so that the status
+     * will never expand or contract.
+     */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNfromVert, map_viewport);       num_args++;
+    XtSetArg(args[num_args], XtNleft,    XtChainLeft);         num_args++;
+    XtSetArg(args[num_args], XtNright,   XtChainLeft);         num_args++;
+    XtSetArg(args[num_args], XtNtop,     XtChainBottom);       num_args++;
+    XtSetArg(args[num_args], XtNbottom,          XtChainBottom);       num_args++;
+    XtSetValues(status, args, num_args);
+
+
+    /*
+     * Realize the popup so that the status widget knows it's size.
+     *
+     * If we unset MappedWhenManaged then the DECwindow driver doesn't
+     * attach the nethack toplevel to the highest virtual root window.
+     * So don't do it.
+     */
+    /* XtSetMappedWhenManaged(toplevel, False); */
+    XtRealizeWidget(toplevel);
+    wm_delete_window = XInternAtom(XtDisplay(toplevel),
+                                  "WM_DELETE_WINDOW", False);
+    XSetWMProtocols(XtDisplay(toplevel), XtWindow(toplevel),
+                   &wm_delete_window, 1);
+
+    /*
+     * Resize to at most full-screen.
+     */
+    {
+#define TITLEBAR_SPACE 18 /* Leave SOME screen for window decorations */
+
+       int screen_width  = WidthOfScreen(XtScreen(wp->w));
+       int screen_height = HeightOfScreen(XtScreen(wp->w)) - TITLEBAR_SPACE;
+       Dimension form_width, form_height;
+
+       XtSetArg(args[0], XtNwidth, &form_width);
+       XtSetArg(args[1], XtNheight, &form_height);
+       XtGetValues(toplevel, args, TWO);
+       
+       if (form_width > screen_width || form_height > screen_height) {
+           XtSetArg(args[0], XtNwidth, min(form_width,screen_width));
+           XtSetArg(args[1], XtNheight, min(form_height,screen_height));
+           XtSetValues(toplevel, args, TWO);
+           XMoveWindow(XtDisplay(toplevel),XtWindow(toplevel),
+               0, TITLEBAR_SPACE);
+       }
+#undef TITLEBAR_SPACE
+    }
+
+    post_process_tiles();      /* after toplevel is realized */
+
+    /*
+     * Now get the default widths of the windows.
+     */
+    XtSetArg(args[0], XtNwidth, &message_vp_width);
+    XtGetValues(message_viewport, args, ONE);
+    XtSetArg(args[0], XtNwidth, &map_vp_width);
+    XtSetArg(args[1], XtNhorizDistance, &map_vp_hd);
+    XtGetValues(map_viewport, args, TWO);
+    XtSetArg(args[0], XtNwidth, &status_width);
+    XtSetArg(args[1], XtNhorizDistance, &status_hd);
+    XtGetValues(status, args, TWO);
+
+    /*
+     * Adjust positions and sizes.  The message viewport widens out to the
+     * widest width.  Both the map and status are centered by adjusting
+     * their horizDistance.
+     */
+    if (map_vp_width < status_width || map_vp_width < message_vp_width) {
+       if (status_width > message_vp_width) {
+           XtSetArg(args[0], XtNwidth, status_width);
+           XtSetValues(message_viewport, args, ONE);
+           max_width = status_width;
+       } else {
+/***** The status display looks better when left justified.
+           XtSetArg(args[0], XtNhorizDistance,
+                               status_hd+((message_vp_width-status_width)/2));
+           XtSetValues(status, args, ONE);
+*****/
+           max_width = message_vp_width;
+       }
+       XtSetArg(args[0], XtNhorizDistance, map_vp_hd+((int)(max_width-map_vp_width)/2));
+       XtSetValues(map_viewport, args, ONE);
+
+    } else {   /* map is widest */
+       XtSetArg(args[0], XtNwidth, map_vp_width);
+       XtSetValues(message_viewport, args, ONE);
+
+/***** The status display looks better when left justified.
+       XtSetArg(args[0], XtNhorizDistance,
+                               status_hd+((map_vp_width-status_width)/2));
+
+       XtSetValues(status, args, ONE);
+*****/
+    }
+    /*
+     * Clear all data values on the fancy status widget so that the values
+     * used for spacing don't appear.  This needs to be called some time
+     * after the fancy status widget is realized (above, with the game popup),
+     * but before it is popped up.
+     */
+    null_out_status();
+    /*
+     * Set the map size to its standard size.  As with the message window
+     * above, the map window needs to be set to its constrained size until
+     * its parent (the viewport widget) was realized.
+     *
+     * Move the message window's slider to the bottom.
+     */
+    set_map_size(&window_list[map_win], COLNO, ROWNO);
+    set_message_slider(&window_list[message_win]);
+
+    /* attempt to catch fatal X11 errors before the program quits */
+    (void) XtAppSetErrorHandler(app_context, (XtErrorHandler) hangup);
+
+    /* We can now print to the message window. */
+    iflags.window_inited = 1;
+}
+
+
+void
+nh_XtPopup(w, g, childwid)
+    Widget w;          /* widget */
+    int    g;          /* type of grab */
+    Widget childwid;   /* child to recieve focus (can be None) */
+{
+    XtPopup(w, (XtGrabKind)g);
+    XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1);
+    if (appResources.autofocus) XtSetKeyboardFocus(toplevel, childwid);
+}
+
+void
+nh_XtPopdown(w)
+    Widget w;
+{
+    XtPopdown(w);
+    if (appResources.autofocus) XtSetKeyboardFocus(toplevel, None);
+}
+
+void
+win_X11_init()
+{
+#ifdef OPENWINBUG
+    /* With the OpenWindows 3.0 libraries and the SunOS 4.1.2 ld, these
+     * two routines will not be found when linking.  An apparently correct
+     * executable is produced, along with nasty messages and a failure code
+     * returned to make.  The routines are in the static libXmu.a and
+     * libXmu.sa.4.0, but not in libXmu.so.4.0.  Rather than fiddle with
+     * static linking, we do this.
+     */
+    if (rn2(2) > 2) {
+       /* i.e., FALSE that an optimizer probably can't find */
+       get_wmShellWidgetClass();
+       get_applicationShellWidgetClass();
+    }
+#endif
+    return;
+}
+
+/* Callback
+ * Scroll a viewport, using standard NH 1,2,3,4,6,7,8,9 directions.
+ */
+/*ARGSUSED*/
+void
+nh_keyscroll(viewport, event, params, num_params)
+    Widget   viewport;
+    XEvent   *event;
+    String   *params;
+    Cardinal *num_params;
+{
+    Arg arg[2];
+    Widget horiz_sb, vert_sb;
+    float top, shown;
+    Boolean do_call;
+    int direction;
+    Cardinal in_nparams = (num_params ? *num_params : 0);
+
+    if (in_nparams != 1) return; /* bad translation */
+
+    direction=atoi(params[0]);
+
+    horiz_sb = XtNameToWidget(viewport, "*horizontal");
+    vert_sb  = XtNameToWidget(viewport, "*vertical");
+
+    if (!horiz_sb && !vert_sb) {
+       /* Perhaps the widget enclosing this has scrollbars (could use while) */
+       Widget parent=XtParent(viewport);
+       if (parent) {
+           horiz_sb = XtNameToWidget(parent, "horizontal");
+           vert_sb  = XtNameToWidget(parent, "vertical");
+       }
+    }
+
+#define H_DELTA 0.25           /* distance of horiz shift */
+                               /* vert shift is half of curr distance */
+/* The V_DELTA is 1/2 the value of shown. */
+
+    if (horiz_sb) {
+       XtSetArg(arg[0], XtNshown,      &shown);
+       XtSetArg(arg[1], XtNtopOfThumb, &top);
+       XtGetValues(horiz_sb, arg, TWO);
+
+       do_call = True;
+
+       switch (direction) {
+         case 1: case 4: case 7:
+           top -= H_DELTA;
+           if (top < 0.0) top = 0.0;
+       break; case 3: case 6: case 9:
+           top += H_DELTA;
+           if (top + shown > 1.0) top = 1.0 - shown;
+       break; default:
+           do_call = False;
+       }
+
+       if (do_call) {
+           XtCallCallbacks(horiz_sb, XtNjumpProc, &top);
+       }
+    }
+
+    if (vert_sb) {
+       XtSetArg(arg[0], XtNshown,      &shown);
+       XtSetArg(arg[1], XtNtopOfThumb, &top);
+       XtGetValues(vert_sb, arg, TWO);
+
+       do_call = True;
+
+       switch (direction) {
+         case 7: case 8: case 9:
+           top -= shown / 2.0;
+           if (top < 0.0) top = 0;
+       break; case 1: case 2: case 3:
+           top += shown / 2.0;
+           if (top + shown > 1.0) top = 1.0 - shown;
+       break; default:
+           do_call = False;
+       }
+
+       if (do_call) {
+           XtCallCallbacks(vert_sb, XtNjumpProc, &top);
+       }
+    }
+}
+
+/*winX.c*/
diff --git a/win/X11/winmap.c b/win/X11/winmap.c
new file mode 100644 (file)
index 0000000..ce5455b
--- /dev/null
@@ -0,0 +1,1654 @@
+/*     SCCS Id: @(#)winmap.c   3.4     1996/04/05      */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file contains:
+ *     + global functions print_glyph() and cliparound()
+ *     + the map window routines
+ *     + the char and pointer input routines
+ *
+ * Notes:
+ *     + We don't really have a good way to get the compiled ROWNO and
+ *       COLNO as defaults.  They are hardwired to the current "correct"
+ *       values in the Window widget.  I am _not_ in favor of including
+ *       some nethack include file for Window.c.
+ */
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/Cardinals.h>
+#include <X11/Xaw/Scrollbar.h>
+#include <X11/Xaw/Viewport.h>
+#include <X11/Xatom.h>
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+#include "xwindow.h"   /* map widget declarations */
+
+#include "hack.h"
+#include "dlb.h"
+#include "winX.h"
+
+#ifdef USE_XPM
+#include <X11/xpm.h>
+#endif
+
+
+/* from tile.c */
+extern short glyph2tile[];
+extern int total_tiles_used;
+
+/* Define these if you really want a lot of junk on your screen. */
+/* #define VERBOSE */          /* print various info & events as they happen */
+/* #define VERBOSE_UPDATE */   /* print screen update bounds */
+/* #define VERBOSE_INPUT */    /* print input events */
+
+
+#define USE_WHITE      /* almost always use white as a tile cursor border */
+
+
+static boolean FDECL(init_tiles, (struct xwindow *));
+static void FDECL(set_button_values, (Widget,int,int,unsigned));
+static void FDECL(map_check_size_change, (struct xwindow *));
+static void FDECL(map_update, (struct xwindow *,int,int,int,int,BOOLEAN_P));
+static void FDECL(init_text, (struct xwindow *));
+static void FDECL(map_exposed, (Widget,XtPointer,XtPointer));
+static void FDECL(set_gc, (Widget,Font,char *,Pixel,GC *,GC *));
+static void FDECL(get_text_gc, (struct xwindow *,Font));
+static void FDECL(get_char_info, (struct xwindow *));
+static void FDECL(display_cursor, (struct xwindow *));
+
+/* Global functions ======================================================== */
+
+void
+X11_print_glyph(window, x, y, glyph)
+    winid window;
+    xchar x, y;
+    int glyph;
+{
+    struct map_info_t *map_info;
+    boolean update_bbox;
+
+    check_winid(window);
+    if (window_list[window].type != NHW_MAP) {
+       impossible("print_glyph: can (currently) only print to map windows");
+       return;
+    }
+    map_info = window_list[window].map_information;
+
+    if (map_info->is_tile) {
+       unsigned short *t_ptr;
+
+       t_ptr = &map_info->mtype.tile_map->glyphs[y][x];
+
+       if (*t_ptr != glyph) {
+           *t_ptr = glyph;
+           update_bbox = TRUE;
+       } else
+           update_bbox = FALSE;
+
+    } else {
+       uchar                   ch;
+       register unsigned char *ch_ptr;
+       int                     color,och;
+       unsigned                special;
+#ifdef TEXTCOLOR
+       register unsigned char *co_ptr;
+#endif
+       /* map glyph to character and color */
+        mapglyph(glyph, &och, &color, &special, x, y);
+       ch = (uchar)och;
+       
+       /* Only update if we need to. */
+       ch_ptr = &map_info->mtype.text_map->text[y][x];
+
+#ifdef TEXTCOLOR
+       co_ptr = &map_info->mtype.text_map->colors[y][x];
+       if (*ch_ptr != ch || *co_ptr != color)
+#else
+       if (*ch_ptr != ch)
+#endif
+       {
+           *ch_ptr = ch;
+#ifdef TEXTCOLOR
+           *co_ptr = color;
+#endif
+           update_bbox = TRUE;
+       } else
+           update_bbox = FALSE;
+    }
+
+    if (update_bbox) {         /* update row bbox */
+       if ((uchar) x < map_info->t_start[y]) map_info->t_start[y] = x;
+       if ((uchar) x > map_info->t_stop[y])  map_info->t_stop[y]  = x;
+    }
+}
+
+#ifdef CLIPPING
+/*
+ * The is the tty clip call.  Since X can resize at any time, we can't depend
+ * on this being defined.
+ */
+/*ARGSUSED*/
+void X11_cliparound(x, y) int x, y; { }
+#endif /* CLIPPING */
+
+/* End global functions ==================================================== */
+
+#include "tile2x11.h"
+
+/*
+ * We're expecting to never read more than one tile file per session.
+ * If this is false, then we can make an array of this information,
+ * or just keep it on a per-window basis.
+ */
+Pixmap tile_pixmap = None;
+static int tile_width;
+static int tile_height;
+static int tile_count;
+static XImage *tile_image = 0;
+
+/*
+ * This structure is used for small bitmaps that are used for annotating
+ * tiles.  For example, a "heart" annotates pets.
+ */
+struct tile_annotation {
+    Pixmap bitmap;
+    Pixel foreground;
+    unsigned int width, height;
+    int hotx, hoty; /* not currently used */
+};
+
+static struct tile_annotation pet_annotation;
+
+static void
+init_annotation(annotation, filename, colorpixel)
+struct tile_annotation *annotation;
+char *filename;
+Pixel colorpixel;
+{
+    Display *dpy = XtDisplay(toplevel);
+
+    if (0!=XReadBitmapFile(dpy, XtWindow(toplevel), filename,
+           &annotation->width, &annotation->height, &annotation->bitmap,
+           &annotation->hotx, &annotation->hoty)) {
+       char buf[BUFSZ];
+       Sprintf(buf, "Failed to load %s", filename);
+       X11_raw_print(buf);
+    }
+
+    annotation->foreground = colorpixel;
+}
+
+/*
+ * Put the tile image on the server.
+ *
+ * We can't send the image to the server until the top level
+ * is realized.  When the tile file is first processed, the top
+ * level is not realized.  This routine is called after we
+ * realize the top level, but before we start resizing the
+ * map viewport.
+ */
+void
+post_process_tiles()
+{
+    Display *dpy = XtDisplay(toplevel);
+    unsigned int width, height;
+
+    if (tile_image == 0) return;       /* no tiles */
+
+    height = tile_image->height;
+    width  = tile_image->width;
+
+    tile_pixmap = XCreatePixmap(dpy, XtWindow(toplevel),
+                       width,
+                       height,
+                       DefaultDepth(dpy, DefaultScreen(dpy)));
+
+    XPutImage(dpy, tile_pixmap,
+       DefaultGC(dpy, DefaultScreen(dpy)),
+       tile_image,
+       0,0, 0,0,               /* src, dest top left */
+       width,
+       height);
+
+    XDestroyImage(tile_image); /* data bytes free'd also */
+    tile_image = 0;
+
+    init_annotation(&pet_annotation,
+       appResources.pet_mark_bitmap, appResources.pet_mark_color);
+}
+
+
+/*
+ * Open and read the tile file.  Return TRUE if there were no problems.
+ * Return FALSE otherwise.
+ */
+static boolean
+init_tiles(wp)
+    struct xwindow *wp;
+{
+#ifdef USE_XPM
+    XpmAttributes attributes;
+    int errorcode;
+#else
+    FILE *fp = (FILE *)0;
+    x11_header header;
+    unsigned char *cp, *colormap = (unsigned char *)0;
+    unsigned char *tb, *tile_bytes = (unsigned char *)0;
+    int size;
+    XColor *colors = (XColor *)0;
+    int i, x, y;
+    int bitmap_pad;
+    int ddepth;
+#endif
+    char buf[BUFSZ];
+    Display *dpy = XtDisplay(toplevel);
+    Screen *screen = DefaultScreenOfDisplay(dpy);
+    struct map_info_t *map_info = (struct map_info_t *)0;
+    struct tile_map_info_t *tile_info = (struct tile_map_info_t *)0;
+    unsigned int image_height = 0, image_width = 0;
+    boolean result = TRUE;
+    XGCValues values;
+    XtGCMask mask;
+
+    /* already have tile information */
+    if (tile_pixmap != None) goto tiledone;
+
+    map_info = wp->map_information;
+    tile_info = map_info->mtype.tile_map =
+           (struct tile_map_info_t *) alloc(sizeof(struct tile_map_info_t));
+    (void) memset((genericptr_t) tile_info, 0,
+                               sizeof(struct tile_map_info_t));
+
+#ifdef USE_XPM
+    attributes.valuemask = XpmCloseness;
+    attributes.closeness = 25000;
+
+    errorcode = XpmReadFileToImage(dpy, appResources.tile_file,
+                                  &tile_image, 0, &attributes);
+
+    if (errorcode == XpmColorFailed) {
+       Sprintf(buf, "Insufficient colors available to load %s.",
+               appResources.tile_file);
+       X11_raw_print(buf);
+       X11_raw_print("Try closing other colorful applications and restart.");
+       X11_raw_print("Attempting to load with inferior colors.");
+       attributes.closeness = 50000;
+       errorcode = XpmReadFileToImage(dpy, appResources.tile_file,
+                                      &tile_image, 0, &attributes);
+    }
+
+    if (errorcode != XpmSuccess) {
+       if (errorcode == XpmColorFailed) {
+           Sprintf(buf, "Insufficient colors available to load %s.",
+                   appResources.tile_file);
+           X11_raw_print(buf);
+       } else {
+           Sprintf(buf, "Failed to load %s: %s", appResources.tile_file,
+                   XpmGetErrorString(errorcode));
+           X11_raw_print(buf);
+       }
+       result = FALSE;
+       X11_raw_print("Switching to text-based mode.");
+       goto tiledone;
+    }
+
+    /* assume a fixed number of tiles per row */
+    if (tile_image->width % TILES_PER_ROW != 0 ||
+       tile_image->width <= TILES_PER_ROW) {
+       Sprintf(buf,
+               "%s is not a multiple of %d (number of tiles/row) pixels wide",
+               appResources.tile_file, TILES_PER_ROW);
+       X11_raw_print(buf);
+       XDestroyImage(tile_image);
+       tile_image = 0;
+       result = FALSE;
+       goto tiledone;
+    }
+
+    /* infer tile dimensions from image size and TILES_PER_ROW */
+    image_width = tile_image->width;
+    image_height = tile_image->height;
+
+    tile_count = total_tiles_used;
+    if ((tile_count % TILES_PER_ROW) != 0) {
+       tile_count += TILES_PER_ROW - (tile_count % TILES_PER_ROW);
+    }
+    tile_width = image_width / TILES_PER_ROW;
+    tile_height = image_height / (tile_count / TILES_PER_ROW);
+#else
+    /* any less than 16 colours makes tiles useless */
+    ddepth = DefaultDepthOfScreen(screen);
+    if (ddepth < 4) {
+       X11_raw_print("need a screen depth of at least 4");
+       result = FALSE;
+       goto tiledone;
+    }
+
+    fp = fopen_datafile(appResources.tile_file, RDBMODE, FALSE);
+    if (!fp) {
+       X11_raw_print("can't open tile file");
+       result = FALSE;
+       goto tiledone;
+    }
+
+    if (fread((char *) &header, sizeof(header), 1, fp) != 1) {
+       X11_raw_print("read of header failed");
+       result = FALSE;
+       goto tiledone;
+    }
+
+    if (header.version != 2) {
+       Sprintf(buf, "Wrong tile file version, expected 2, got %lu",
+               header.version);
+       X11_raw_print(buf);
+       result = FALSE;
+       goto tiledone;
+    }
+
+# ifdef VERBOSE
+    fprintf(stderr, "X11 tile file:\n    version %ld\n    ncolors %ld\n    tile width %ld\n    tile height %ld\n    per row %ld\n    ntiles %ld\n",
+       header.version,
+       header.ncolors,
+       header.tile_width,
+       header.tile_height,
+       header.per_row,
+       header.ntiles);
+# endif
+
+    size = 3*header.ncolors;
+    colormap = (unsigned char *) alloc((unsigned)size);
+    if (fread((char *) colormap, 1, size, fp) != size) {
+       X11_raw_print("read of colormap failed");
+       result = FALSE;
+       goto tiledone;
+    }
+
+/* defined in decl.h - these are _not_ good defines to have */
+#undef red
+#undef green
+#undef blue
+
+    colors = (XColor *) alloc(sizeof(XColor) * (unsigned)header.ncolors);
+    for (i = 0; i < header.ncolors; i++) {
+       cp = colormap + (3 * i);
+       colors[i].red   = cp[0] * 256;
+       colors[i].green = cp[1] * 256;
+       colors[i].blue  = cp[2] * 256;
+       colors[i].flags = 0;
+       colors[i].pixel = 0;
+
+       if (!XAllocColor(dpy, DefaultColormapOfScreen(screen), &colors[i]) &&
+           !nhApproxColor(screen, DefaultColormapOfScreen(screen),
+                          (char *)0, &colors[i])) {
+           Sprintf(buf, "%dth out of %ld color allocation failed",
+                   i, header.ncolors);
+           X11_raw_print(buf);
+           result = FALSE;
+           goto tiledone;
+       }
+    }
+
+    size = header.tile_height * header.tile_width;
+    /*
+     * This alloc() and the one below require 32-bit ints, since tile_bytes
+     * is currently ~200k and alloc() takes an int
+     */
+    tile_count = header.ntiles;
+    if ((tile_count % header.per_row) != 0) {
+       tile_count += header.per_row - (tile_count % header.per_row);
+    }
+    tile_bytes = (unsigned char *) alloc((unsigned)tile_count*size);
+    if (fread((char *) tile_bytes, size, tile_count, fp) != tile_count) {
+       X11_raw_print("read of tile bytes failed");
+       result = FALSE;
+       goto tiledone;
+    }
+
+    if (header.ntiles < total_tiles_used) {
+       Sprintf(buf, "tile file incomplete, expecting %d tiles, found %lu",
+               total_tiles_used, header.ntiles);
+       X11_raw_print(buf);
+       result = FALSE;
+       goto tiledone;
+    }
+
+
+    if (appResources.double_tile_size) {
+       tile_width  = 2*header.tile_width;
+       tile_height = 2*header.tile_height;
+    } else {
+       tile_width  = header.tile_width;
+       tile_height = header.tile_height;
+    }
+
+    image_height = tile_height * tile_count / header.per_row;
+    image_width  = tile_width * header.per_row;
+
+    /* calculate bitmap_pad */
+    if (ddepth > 16)
+       bitmap_pad = 32;
+    else if (ddepth > 8)
+       bitmap_pad = 16;
+    else
+       bitmap_pad = 8;
+
+    tile_image = XCreateImage(dpy, DefaultVisualOfScreen(screen),
+               ddepth,                 /* depth */
+               ZPixmap,                /* format */
+               0,                      /* offset */
+               0,                      /* data */
+               image_width,            /* width */
+               image_height,           /* height */
+               bitmap_pad,             /* bit pad */
+               0);                     /* bytes_per_line */
+
+    if (!tile_image)
+       impossible("init_tiles: insufficient memory to create image");
+
+    /* now we know the physical memory requirements, we can allocate space */
+    tile_image->data =
+       (char *) alloc((unsigned)tile_image->bytes_per_line * image_height);
+
+    if (appResources.double_tile_size) {
+       unsigned long *expanded_row =
+           (unsigned long *)alloc(sizeof(unsigned long)*(unsigned)image_width);
+
+       tb = tile_bytes;
+       for (y = 0; y < image_height; y++) {
+           for (x = 0; x < image_width/2; x++)
+               expanded_row[2*x] =
+                           expanded_row[(2*x)+1] = colors[*tb++].pixel;
+
+           for (x = 0; x < image_width; x++)
+               XPutPixel(tile_image, x, y, expanded_row[x]);
+
+           y++;        /* duplicate row */
+           for (x = 0; x < image_width; x++)
+               XPutPixel(tile_image, x, y, expanded_row[x]);
+       }
+       free((genericptr_t)expanded_row);
+
+    } else {
+
+       for (tb = tile_bytes, y = 0; y < image_height; y++)
+           for (x = 0; x < image_width; x++, tb++)
+               XPutPixel(tile_image, x, y, colors[*tb].pixel);
+    }
+#endif /* USE_XPM */
+
+    /* fake an inverted tile by drawing a border around the edges */
+#ifdef USE_WHITE
+    /* use white or black as the border */
+    mask = GCFunction | GCForeground | GCGraphicsExposures;
+    values.graphics_exposures = False;
+    values.foreground = WhitePixelOfScreen(screen);
+    values.function   = GXcopy;
+    tile_info->white_gc = XtGetGC(wp->w, mask, &values);
+    values.graphics_exposures = False;
+    values.foreground = BlackPixelOfScreen(screen);
+    values.function   = GXcopy;
+    tile_info->black_gc = XtGetGC(wp->w, mask, &values);
+#else
+    /*
+     * Use xor so we don't have to check for special colors.  Xor white
+     * against the upper left pixel of the corridor so that we have a
+     * white rectangle when in a corridor.
+     */
+    mask = GCFunction | GCForeground | GCGraphicsExposures;
+    values.graphics_exposures = False;
+    values.foreground = WhitePixelOfScreen(screen) ^
+       XGetPixel(tile_image, 0, tile_height*glyph2tile[cmap_to_glyph(S_corr)]);
+    values.function = GXxor;
+    tile_info->white_gc = XtGetGC(wp->w, mask, &values);
+
+    mask = GCFunction | GCGraphicsExposures;
+    values.function = GXCopy;
+    values.graphics_exposures = False;
+    tile_info->black_gc = XtGetGC(wp->w, mask, &values);
+#endif /* USE_WHITE */
+
+tiledone:
+#ifndef USE_XPM
+    if (fp) (void) fclose(fp);
+    if (colormap) free((genericptr_t)colormap);
+    if (tile_bytes) free((genericptr_t)tile_bytes);
+    if (colors) free((genericptr_t)colors);
+#endif
+
+    if (result) {                              /* succeeded */
+       map_info->square_height = tile_height;
+       map_info->square_width = tile_width;
+       map_info->square_ascent = 0;
+       map_info->square_lbearing = 0;
+       tile_info->image_width = image_width;
+       tile_info->image_height = image_height;
+    } else {
+       if (tile_info) free((genericptr_t)tile_info);
+       tile_info = 0;
+    }
+
+    return result;
+}
+
+
+/*
+ * Make sure the map's cursor is always visible.
+ */
+void
+check_cursor_visibility(wp)
+    struct xwindow *wp;
+{
+    Arg arg[2];
+    Widget viewport, horiz_sb, vert_sb;
+    float top, shown, cursor_middle;
+    Boolean do_call, adjusted = False;
+#ifdef VERBOSE
+    char *s;
+#endif
+
+    viewport = XtParent(wp->w);
+    horiz_sb = XtNameToWidget(viewport, "horizontal");
+    vert_sb  = XtNameToWidget(viewport, "vertical");
+
+/* All values are relative to currently visible area */
+
+#define V_BORDER 0.3   /* if this far from vert edge, shift */
+#define H_BORDER 0.3   /* if this from from horiz edge, shift */
+
+#define H_DELTA 0.4    /* distance of horiz shift */
+#define V_DELTA 0.4    /* distance of vert shift */
+
+    if (horiz_sb) {
+       XtSetArg(arg[0], XtNshown,      &shown);
+       XtSetArg(arg[1], XtNtopOfThumb, &top);
+       XtGetValues(horiz_sb, arg, TWO);
+
+       /* [ALI] Don't assume map widget is the same size as actual map */
+       cursor_middle = (wp->cursx + 0.5) * wp->map_information->square_width /
+         wp->pixel_width;
+       do_call = True;
+
+#ifdef VERBOSE
+       if (cursor_middle < top) {
+           s = " outside left";
+       } else if (cursor_middle < top + shown*H_BORDER) {
+           s = " close to left";
+       } else if (cursor_middle > (top + shown)) {
+           s = " outside right";
+       } else if (cursor_middle > (top + shown - shown*H_BORDER)) {
+           s = " close to right";
+       } else {
+           s = "";
+       }
+       printf("Horiz: shown = %3.2f, top = %3.2f%s", shown, top, s);
+#endif
+
+       if (cursor_middle < top) {
+           top = cursor_middle - shown*H_DELTA;
+           if (top < 0.0) top = 0.0;
+       } else if (cursor_middle < top + shown*H_BORDER) {
+           top -= shown*H_DELTA;
+           if (top < 0.0) top = 0.0;
+       } else if (cursor_middle > (top + shown)) {
+           top = cursor_middle - shown*H_DELTA;
+           if (top < 0.0) top = 0.0;
+           if (top + shown > 1.0) top = 1.0 - shown;
+       } else if (cursor_middle > (top + shown - shown*H_BORDER)) {
+           top += shown*H_DELTA;
+           if (top + shown > 1.0) top = 1.0 - shown;
+       } else {
+           do_call = False;
+       }
+
+       if (do_call) {
+           XtCallCallbacks(horiz_sb, XtNjumpProc, &top);
+           adjusted = True;
+       }
+    }
+
+    if (vert_sb) {
+       XtSetArg(arg[0], XtNshown,      &shown);
+       XtSetArg(arg[1], XtNtopOfThumb, &top);
+       XtGetValues(vert_sb, arg, TWO);
+
+       cursor_middle = (wp->cursy + 0.5) * wp->map_information->square_height /
+         wp->pixel_height;
+       do_call = True;
+
+#ifdef VERBOSE
+       if (cursor_middle < top) {
+           s = " above top";
+       } else if (cursor_middle < top + shown*V_BORDER) {
+           s = " close to top";
+       } else if (cursor_middle > (top + shown)) {
+           s = " below bottom";
+       } else if (cursor_middle > (top + shown - shown*V_BORDER)) {
+           s = " close to bottom";
+       } else {
+           s = "";
+       }
+       printf("%sVert: shown = %3.2f, top = %3.2f%s",
+                                   horiz_sb ? ";  " : "", shown, top, s);
+#endif
+
+       if (cursor_middle < top) {
+           top = cursor_middle - shown*V_DELTA;
+           if (top < 0.0) top = 0.0;
+       } else if (cursor_middle < top + shown*V_BORDER) {
+           top -= shown*V_DELTA;
+           if (top < 0.0) top = 0.0;
+       } else if (cursor_middle > (top + shown)) {
+           top = cursor_middle - shown*V_DELTA;
+           if (top < 0.0) top = 0.0;
+           if (top + shown > 1.0) top = 1.0 - shown;
+       } else if (cursor_middle > (top + shown - shown*V_BORDER)) {
+           top += shown*V_DELTA;
+           if (top + shown > 1.0) top = 1.0 - shown;
+       } else {
+           do_call = False;
+       }
+
+       if (do_call) {
+           XtCallCallbacks(vert_sb, XtNjumpProc, &top);
+           adjusted = True;
+       }
+    }
+
+    /* make sure cursor is displayed during dowhatis.. */
+    if (adjusted) display_cursor(wp);
+
+#ifdef VERBOSE
+    if (horiz_sb || vert_sb) printf("\n");
+#endif
+}
+
+
+/*
+ * Check to see if the viewport has grown smaller.  If so, then we want to make
+ * sure that the cursor is still on the screen.  We do this to keep the cursor
+ * on the screen when the user resizes the nethack window.
+ */
+static void
+map_check_size_change(wp)
+    struct xwindow *wp;
+{
+    struct map_info_t *map_info = wp->map_information;
+    Arg arg[2];
+    Dimension new_width, new_height;
+    Widget viewport;
+
+    viewport = XtParent(wp->w);
+
+    XtSetArg(arg[0], XtNwidth,  &new_width);
+    XtSetArg(arg[1], XtNheight, &new_height);
+    XtGetValues(viewport, arg, TWO);
+
+    /* Only do cursor check if new size is smaller. */
+    if (new_width < map_info->viewport_width
+                   || new_height < map_info->viewport_height) {
+       /* [ALI] If the viewport was larger than the map (and so the map
+        * widget was contrained to be larger than the actual map) then we
+        * may be able to shrink the map widget as the viewport shrinks.
+        */
+       wp->pixel_width = map_info->square_width * COLNO;
+       if (wp->pixel_width < new_width)
+           wp->pixel_width = new_width;
+       wp->pixel_height = map_info->square_height * ROWNO;
+       if (wp->pixel_height < new_height)
+           wp->pixel_height = new_height;
+       XtSetArg(arg[0], XtNwidth, wp->pixel_width);
+       XtSetArg(arg[1], XtNheight, wp->pixel_height);
+       XtSetValues(wp->w, arg, TWO);
+
+       check_cursor_visibility(wp);
+    }
+
+    map_info->viewport_width = new_width;
+    map_info->viewport_height = new_height;
+
+    /* [ALI] These may have changed if the user has re-sized the viewport */
+    XtSetArg(arg[0], XtNwidth, &wp->pixel_width);
+    XtSetArg(arg[1], XtNheight, &wp->pixel_height);
+    XtGetValues(wp->w, arg, TWO);
+}
+
+/*
+ * Fill in parameters "regular" and "inverse" with newly created GCs.
+ * Using the given background pixel and the foreground pixel optained
+ * by querying the widget with the resource name.
+ */
+static void
+set_gc(w, font, resource_name, bgpixel, regular, inverse)
+    Widget w;
+    Font font;
+    char *resource_name;
+    Pixel bgpixel;
+    GC   *regular, *inverse;
+{
+    XGCValues values;
+    XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont;
+    Pixel curpixel;
+    Arg arg[1];
+
+    XtSetArg(arg[0], resource_name, &curpixel);
+    XtGetValues(w, arg, ONE);
+
+    values.foreground = curpixel;
+    values.background = bgpixel;
+    values.function   = GXcopy;
+    values.font              = font;
+    *regular = XtGetGC(w, mask, &values);
+    values.foreground = bgpixel;
+    values.background = curpixel;
+    values.function   = GXcopy;
+    values.font              = font;
+    *inverse = XtGetGC(w, mask, &values);
+}
+
+/*
+ * Create the GC's for each color.
+ *
+ * I'm not sure if it is a good idea to have a GC for each color (and
+ * inverse). It might be faster to just modify the foreground and
+ * background colors on the current GC as needed.
+ */
+static void
+get_text_gc(wp, font)
+    struct xwindow *wp;
+    Font font;
+{
+    struct map_info_t *map_info = wp->map_information;
+    Pixel bgpixel;
+    Arg arg[1];
+
+    /* Get background pixel. */
+    XtSetArg(arg[0], XtNbackground, &bgpixel);
+    XtGetValues(wp->w, arg, ONE);
+
+#ifdef TEXTCOLOR
+#define set_color_gc(nh_color, resource_name)                  \
+           set_gc(wp->w, font, resource_name, bgpixel,         \
+               &map_info->mtype.text_map->color_gcs[nh_color], \
+                   &map_info->mtype.text_map->inv_color_gcs[nh_color]);
+
+    set_color_gc(CLR_BLACK,    XtNblack);
+    set_color_gc(CLR_RED,      XtNred);
+    set_color_gc(CLR_GREEN,    XtNgreen);
+    set_color_gc(CLR_BROWN,    XtNbrown);
+    set_color_gc(CLR_BLUE,     XtNblue);
+    set_color_gc(CLR_MAGENTA,  XtNmagenta);
+    set_color_gc(CLR_CYAN,     XtNcyan);
+    set_color_gc(CLR_GRAY,     XtNgray);
+    set_color_gc(NO_COLOR,     XtNforeground);
+    set_color_gc(CLR_ORANGE,   XtNorange);
+    set_color_gc(CLR_BRIGHT_GREEN, XtNbright_green);
+    set_color_gc(CLR_YELLOW,   XtNyellow);
+    set_color_gc(CLR_BRIGHT_BLUE, XtNbright_blue);
+    set_color_gc(CLR_BRIGHT_MAGENTA, XtNbright_magenta);
+    set_color_gc(CLR_BRIGHT_CYAN, XtNbright_cyan);
+    set_color_gc(CLR_WHITE,    XtNwhite);
+#else
+    set_gc(wp->w, font, XtNforeground, bgpixel,
+               &map_info->mtype.text_map->copy_gc,
+               &map_info->mtype.text_map->inv_copy_gc);
+#endif
+}
+
+
+/*
+ * Display the cursor on the map window.
+ */
+static void
+display_cursor(wp)
+    struct xwindow *wp;
+{
+    /* Redisplay the cursor location inverted. */
+    map_update(wp, wp->cursy, wp->cursy, wp->cursx, wp->cursx, TRUE);
+}
+
+
+/*
+ * Check if there are any changed characters.  If so, then plaster them on
+ * the screen.
+ */
+void
+display_map_window(wp)
+    struct xwindow *wp;
+{
+    register int row;
+    struct map_info_t *map_info = wp->map_information;
+
+    /*
+     * If the previous cursor position is not the same as the current
+     * cursor position, then update the old cursor position.
+     */
+    if (wp->prevx != wp->cursx || wp->prevy != wp->cursy) {
+       register unsigned int x = wp->prevx, y = wp->prevy;
+       if (x < map_info->t_start[y]) map_info->t_start[y] = x;
+       if (x > map_info->t_stop[y])  map_info->t_stop[y]  = x;
+    }
+
+    for (row = 0; row < ROWNO; row++) {
+       if (map_info->t_start[row] <= map_info->t_stop[row]) {
+           map_update(wp, row, row,
+                       (int) map_info->t_start[row],
+                       (int) map_info->t_stop[row], FALSE);
+           map_info->t_start[row] = COLNO-1;
+           map_info->t_stop[row] = 0;
+       }
+    }
+    display_cursor(wp);
+    wp->prevx = wp->cursx;     /* adjust old cursor position */
+    wp->prevy = wp->cursy;
+}
+
+/*
+ * Set all map tiles to S_stone
+ */
+static void
+map_all_stone(map_info)
+struct map_info_t *map_info;
+{
+    int i;
+    unsigned short *sp, stone;
+    stone = cmap_to_glyph(S_stone);
+
+    for (sp = (unsigned short *) map_info->mtype.tile_map->glyphs, i = 0;
+       i < ROWNO*COLNO; sp++, i++)
+
+    *sp = stone;
+}
+
+/*
+ * Fill the saved screen characters with the "clear" tile or character.
+ *
+ * Flush out everything by resetting the "new" bounds and calling
+ * display_map_window().
+ */
+void
+clear_map_window(wp)
+    struct xwindow *wp;
+{
+    struct map_info_t *map_info = wp->map_information;
+
+    if (map_info->is_tile) {
+       map_all_stone(map_info);
+    } else {
+       /* Fill text with spaces, and update */
+       (void) memset((genericptr_t) map_info->mtype.text_map->text, ' ',
+                       sizeof(map_info->mtype.text_map->text));
+#ifdef TEXTCOLOR
+       (void) memset((genericptr_t) map_info->mtype.text_map->colors, NO_COLOR,
+                       sizeof(map_info->mtype.text_map->colors));
+#endif
+    }
+
+    /* force a full update */
+    (void) memset((genericptr_t) map_info->t_start, (char) 0,
+                       sizeof(map_info->t_start));
+    (void) memset((genericptr_t) map_info->t_stop, (char) COLNO-1,
+                       sizeof(map_info->t_stop));
+    display_map_window(wp);
+}
+
+/*
+ * Retreive the font associated with the map window and save attributes
+ * that are used when updating it.
+ */
+static void
+get_char_info(wp)
+    struct xwindow *wp;
+{
+    XFontStruct *fs;
+    struct map_info_t *map_info = wp->map_information;
+
+    fs = WindowFontStruct(wp->w);
+    map_info->square_width    = fs->max_bounds.width;
+    map_info->square_height   = fs->max_bounds.ascent + fs->max_bounds.descent;
+    map_info->square_ascent   = fs->max_bounds.ascent;
+    map_info->square_lbearing = -fs->min_bounds.lbearing;
+
+#ifdef VERBOSE
+    printf("Font information:\n");
+    printf("fid = %ld, direction = %d\n", fs->fid, fs->direction);
+    printf("first = %d, last = %d\n",
+                       fs->min_char_or_byte2, fs->max_char_or_byte2);
+    printf("all chars exist? %s\n", fs->all_chars_exist?"yes":"no");
+    printf("min_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n",
+               fs->min_bounds.lbearing, fs->min_bounds.rbearing,
+               fs->min_bounds.width, fs->min_bounds.ascent,
+               fs->min_bounds.descent, fs->min_bounds.attributes);
+    printf("max_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n",
+               fs->max_bounds.lbearing, fs->max_bounds.rbearing,
+               fs->max_bounds.width, fs->max_bounds.ascent,
+               fs->max_bounds.descent, fs->max_bounds.attributes);
+    printf("per_char = 0x%lx\n", (unsigned long) fs->per_char);
+    printf("Text: (max) width = %d, height = %d\n",
+           map_info->square_width, map_info->square_height);
+#endif
+
+    if (fs->min_bounds.width != fs->max_bounds.width)
+       X11_raw_print("Warning:  map font is not monospaced!");
+}
+
+/*
+ * keyhit buffer
+ */
+#define INBUF_SIZE 64
+int inbuf[INBUF_SIZE];
+int incount = 0;
+int inptr = 0; /* points to valid data */
+
+
+/*
+ * Keyboard and button event handler for map window.
+ */
+void
+map_input(w, event, params, num_params)
+    Widget   w;
+    XEvent   *event;
+    String   *params;
+    Cardinal *num_params;
+{
+    XKeyEvent *key;
+    XButtonEvent *button;
+    boolean meta = FALSE;
+    int i, nbytes;
+    Cardinal in_nparams = (num_params ? *num_params : 0);
+    char c;
+    char keystring[MAX_KEY_STRING];
+
+    switch (event->type) {
+       case ButtonPress:
+           button = (XButtonEvent *) event;
+#ifdef VERBOSE_INPUT
+           printf("button press\n");
+#endif
+           if (in_nparams > 0 &&
+               (nbytes = strlen(params[0])) < MAX_KEY_STRING) {
+               Strcpy(keystring, params[0]);
+               key = (XKeyEvent *) event; /* just in case */
+               goto key_events;
+           }
+           if (w != window_list[WIN_MAP].w) {
+#ifdef VERBOSE_INPUT
+               printf("map_input called from wrong window\n");
+#endif
+               X11_nhbell();
+               return;
+           }
+           set_button_values(w, button->x, button->y, button->button);
+           break;
+       case KeyPress:
+#ifdef VERBOSE_INPUT
+           printf("key: ");
+#endif
+           if(appResources.slow && input_func) {
+               (*input_func)(w, event, params, num_params);
+               break;
+           }
+
+           /*
+            * Don't use key_event_to_char() because we want to be able
+            * to allow keys mapped to multiple characters.
+            */
+           key = (XKeyEvent *) event;
+           if (in_nparams > 0 &&
+               (nbytes = strlen(params[0])) < MAX_KEY_STRING) {
+               Strcpy(keystring, params[0]);
+           } else {
+               /*
+                * Assume that mod1 is really the meta key.
+                */
+               meta = !!(key->state & Mod1Mask);
+               nbytes =
+                   XLookupString(key, keystring, MAX_KEY_STRING,
+                                 (KeySym *)0, (XComposeStatus *)0);
+           }
+       key_events:
+           /* Modifier keys return a zero length string when pressed. */
+           if (nbytes) {
+#ifdef VERBOSE_INPUT
+               printf("\"");
+#endif
+               for (i = 0; i < nbytes; i++) {
+                   c = keystring[i];
+
+                   if (incount < INBUF_SIZE) {
+                       inbuf[(inptr+incount)%INBUF_SIZE] =
+                           ((int) c) + (meta ? 0x80 : 0);
+                       incount++;
+                   } else {
+                       X11_nhbell();
+                   }
+#ifdef VERBOSE_INPUT
+                   if (meta)                   /* meta will print as M<c> */
+                       (void) putchar('M');
+                   if (c < ' ') {              /* ctrl will print as ^<c> */
+                       (void) putchar('^');
+                       c += '@';
+                   }
+                   (void) putchar(c);
+#endif
+               }
+#ifdef VERBOSE_INPUT
+               printf("\" [%d bytes]\n", nbytes);
+#endif
+           }
+           break;
+
+       default:
+           impossible("unexpected X event, type = %d\n", (int) event->type);
+           break;
+    }
+}
+
+static void
+set_button_values(w, x, y, button)
+    Widget w;
+    int x;
+    int y;
+    unsigned int button;
+{
+    struct xwindow *wp;
+    struct map_info_t *map_info;
+
+    wp = find_widget(w);
+    map_info = wp->map_information;
+
+    click_x = x / map_info->square_width;
+    click_y = y / map_info->square_height;
+
+    /* The values can be out of range if the map window has been resized */
+    /* to be larger than the max size.                                  */
+    if (click_x >= COLNO) click_x = COLNO-1;
+    if (click_y >= ROWNO) click_x = ROWNO-1;
+
+    /* Map all buttons but the first to the second click */
+    click_button = (button == Button1) ? CLICK_1 : CLICK_2;
+}
+
+/*
+ * Map window expose callback.
+ */
+/*ARGSUSED*/
+static void
+map_exposed(w, client_data, widget_data)
+    Widget w;
+    XtPointer client_data;     /* unused */
+    XtPointer widget_data;     /* expose event from Window widget */
+{
+    int x, y;
+    struct xwindow *wp;
+    struct map_info_t *map_info;
+    unsigned width, height;
+    int start_row, stop_row, start_col, stop_col;
+    XExposeEvent *event = (XExposeEvent *) widget_data;
+    int t_height, t_width;     /* tile/text height & width */
+
+    if (!XtIsRealized(w) || event->count > 0) return;
+
+    wp = find_widget(w);
+    map_info = wp->map_information;
+    if (wp->keep_window && !map_info) return;
+    /*
+     * The map is sent an expose event when the viewport resizes.  Make sure
+     * that the cursor is still in the viewport after the resize.
+     */
+    map_check_size_change(wp);
+
+    if (event) {               /* called from button-event */
+       x      = event->x;
+       y      = event->y;
+       width  = event->width;
+       height = event->height;
+    } else {
+       x     = 0;
+       y     = 0;
+       width = wp->pixel_width;
+       height= wp->pixel_height;
+    }
+    /*
+     * Convert pixels into INCLUSIVE text rows and columns.
+     */
+    t_height = map_info->square_height;
+    t_width = map_info->square_width;
+    start_row = y / t_height;
+    stop_row = ((y + height) / t_height) +
+               ((((y + height) % t_height) == 0) ? 0 : 1) - 1;
+
+    start_col = x / t_width;
+    stop_col = ((x + width) / t_width) +
+               ((((x + width) % t_width) == 0) ? 0 : 1) - 1;
+
+#ifdef VERBOSE
+    printf("map_exposed: x = %d, y = %d, width = %d, height = %d\n",
+                                                   x, y, width, height);
+    printf("chars %d x %d, rows %d to %d, columns %d to %d\n",
+                       map_info->square_height, map_info->square_width,
+                       start_row, stop_row, start_col, stop_col);
+#endif
+
+    /* Out of range values are possible if the map window is resized to be */
+    /* bigger than the largest expected value.                            */
+    if (stop_row >= ROWNO) stop_row = ROWNO-1;
+    if (stop_col >= COLNO) stop_col = COLNO-1;
+
+    map_update(wp, start_row, stop_row, start_col, stop_col, FALSE);
+    display_cursor(wp);                /* make sure cursor shows up */
+}
+
+/*
+ * Do the actual work of the putting characters onto our X window.  This
+ * is called from the expose event routine, the display window (flush)
+ * routine, and the display cursor routine.  The later is a kludge that
+ * involves the inverted parameter of this function.  A better solution
+ * would be to double the color count, with any color above CLR_MAX
+ * being inverted.
+ *
+ * This works for rectangular regions (this includes one line rectangles).
+ * The start and stop columns are *inclusive*.
+ */
+static void
+map_update(wp, start_row, stop_row, start_col, stop_col, inverted)
+    struct xwindow *wp;
+    int start_row, stop_row, start_col, stop_col;
+    boolean inverted;
+{
+    int win_start_row, win_start_col;
+    struct map_info_t *map_info = wp->map_information;
+    int row;
+    register int count;
+
+    if (start_row < 0 || stop_row >= ROWNO) {
+       impossible("map_update:  bad row range %d-%d\n", start_row, stop_row);
+       return;
+    }
+    if (start_col < 0 || stop_col >=COLNO) {
+       impossible("map_update:  bad col range %d-%d\n", start_col, stop_col);
+       return;
+    }
+
+#ifdef VERBOSE_UPDATE
+    printf("update: [0x%x] %d %d %d %d\n",
+               (int) wp->w, start_row, stop_row, start_col, stop_col);
+#endif
+    win_start_row = start_row;
+    win_start_col = start_col;
+
+    if (map_info->is_tile) {
+       struct tile_map_info_t *tile_map = map_info->mtype.tile_map;
+       int cur_col;
+       Display* dpy = XtDisplay(wp->w);
+       Screen* screen = DefaultScreenOfDisplay(dpy);
+
+       for (row = start_row; row <= stop_row; row++) {
+           for (cur_col = start_col; cur_col <= stop_col; cur_col++) {
+               int glyph = tile_map->glyphs[row][cur_col];
+               int tile = glyph2tile[glyph];
+               int src_x, src_y;
+               int dest_x = cur_col * map_info->square_width;
+               int dest_y = row * map_info->square_height;
+
+               src_x = (tile % TILES_PER_ROW) * tile_width;
+               src_y = (tile / TILES_PER_ROW) * tile_height;
+               XCopyArea(dpy, tile_pixmap, XtWindow(wp->w),
+                         tile_map->black_gc,   /* no grapics_expose */
+                         src_x, src_y,
+                         tile_width, tile_height,
+                         dest_x, dest_y);
+
+               if (glyph_is_pet(glyph) && iflags.hilite_pet) {
+                   /* draw pet annotation (a heart) */
+                   XSetForeground(dpy, tile_map->black_gc, pet_annotation.foreground);
+                   XSetClipOrigin(dpy, tile_map->black_gc, dest_x, dest_y);
+                   XSetClipMask(dpy, tile_map->black_gc, pet_annotation.bitmap);
+                   XCopyPlane(
+                       dpy,
+                       pet_annotation.bitmap,
+                       XtWindow(wp->w),
+                       tile_map->black_gc,
+                       0,0,
+                       pet_annotation.width,pet_annotation.height,
+                       dest_x,dest_y,
+                       1
+                   );
+                   XSetClipOrigin(dpy, tile_map->black_gc, 0, 0);
+                   XSetClipMask(dpy, tile_map->black_gc, None);
+                   XSetForeground(dpy, tile_map->black_gc, BlackPixelOfScreen(screen));
+               }
+           }
+       }
+
+       if (inverted) {
+           XDrawRectangle(XtDisplay(wp->w), XtWindow(wp->w),
+#ifdef USE_WHITE
+               /* kludge for white square... */
+               tile_map->glyphs[start_row][start_col] ==
+                   cmap_to_glyph(S_ice) ?
+                       tile_map->black_gc : tile_map->white_gc,
+#else
+               tile_map->white_gc,
+#endif
+               start_col * map_info->square_width,
+               start_row * map_info->square_height,
+               map_info->square_width-1,
+               map_info->square_height-1);
+       }
+    } else {
+       struct text_map_info_t *text_map = map_info->mtype.text_map;
+
+#ifdef TEXTCOLOR
+       if (iflags.use_color) {
+           register char *c_ptr;
+           char *t_ptr;
+           int cur_col, color, win_ystart;
+
+           for (row = start_row; row <= stop_row; row++) {
+               win_ystart = map_info->square_ascent +
+                                       (row * map_info->square_height);
+
+               t_ptr = (char *) &(text_map->text[row][start_col]);
+               c_ptr = (char *) &(text_map->colors[row][start_col]);
+               cur_col = start_col;
+               while (cur_col <= stop_col) {
+                   color = *c_ptr++;
+                   count = 1;
+                   while ((cur_col + count) <= stop_col && *c_ptr == color) {
+                       count++;
+                       c_ptr++;
+                   }
+
+                   XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w),
+                       inverted ? text_map->inv_color_gcs[color] :
+                                  text_map->color_gcs[color],
+                       map_info->square_lbearing + (map_info->square_width * cur_col),
+                       win_ystart,
+                       t_ptr, count);
+
+                   /* move text pointer and column count */
+                   t_ptr += count;
+                   cur_col += count;
+               } /* col loop */
+           } /* row loop */
+       } else
+#endif /* TEXTCOLOR */
+       {
+           int win_row, win_xstart;
+
+           /* We always start at the same x window position and have   */
+           /* the same character count.                                */
+           win_xstart = map_info->square_lbearing +
+                                   (win_start_col * map_info->square_width);
+           count = stop_col - start_col + 1;
+
+           for (row = start_row, win_row = win_start_row;
+                                       row <= stop_row; row++, win_row++) {
+
+               XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w),
+                   inverted ? text_map->inv_copy_gc : text_map->copy_gc,
+                   win_xstart,
+                   map_info->square_ascent + (win_row * map_info->square_height),
+                   (char *) &(text_map->text[row][start_col]), count);
+           }
+       }
+    }
+}
+
+/* Adjust the number of rows and columns on the given map window */
+void
+set_map_size(wp, cols, rows)
+    struct xwindow *wp;
+    Dimension cols, rows;
+{
+    Arg args[4];
+    Cardinal num_args;
+
+    wp->pixel_width  = wp->map_information->square_width  * cols;
+    wp->pixel_height = wp->map_information->square_height * rows;
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNwidth, wp->pixel_width);   num_args++;
+    XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++;
+    XtSetValues(wp->w, args, num_args);
+}
+
+
+static void
+init_text(wp)
+    struct xwindow *wp;
+{
+
+    struct map_info_t *map_info = wp->map_information;
+    struct text_map_info_t *text_map;
+
+    map_info->is_tile = FALSE;
+    text_map = map_info->mtype.text_map =
+       (struct text_map_info_t *) alloc(sizeof(struct text_map_info_t));
+
+    (void) memset((genericptr_t) text_map->text, ' ', sizeof(text_map->text));
+#ifdef TEXTCOLOR
+    (void) memset((genericptr_t) text_map->colors, NO_COLOR,
+                       sizeof(text_map->colors));
+#endif
+
+    get_char_info(wp);
+    get_text_gc(wp, WindowFont(wp->w));
+}
+
+static char map_translations[] =
+"#override\n\
+ <Key>Left: scroll(4)\n\
+ <Key>Right: scroll(6)\n\
+ <Key>Up: scroll(8)\n\
+ <Key>Down: scroll(2)\n\
+ <Key>:                input() \
+";
+
+/*
+ * The map window creation routine.
+ */
+void
+create_map_window(wp, create_popup, parent)
+    struct xwindow *wp;
+    boolean create_popup;      /* parent is a popup shell that we create */
+    Widget parent;
+{
+    struct map_info_t *map_info;       /* map info pointer */
+    Widget map, viewport;
+    Arg args[16];
+    Cardinal num_args;
+    Dimension rows, columns;
+#if 0
+    int screen_width, screen_height;
+#endif
+
+    wp->type = NHW_MAP;
+
+    if (create_popup) {
+       /*
+        * Create a popup that accepts key and button events.
+        */
+       num_args = 0;
+       XtSetArg(args[num_args], XtNinput, False);            num_args++;
+
+       wp->popup = parent = XtCreatePopupShell("nethack",
+                                       topLevelShellWidgetClass,
+                                      toplevel, args, num_args);
+       /*
+        * If we're here, then this is an auxiliary map window.  If we're
+        * cancelled via a delete window message, we should just pop down.
+        */
+    }
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNallowHoriz, True);     num_args++;
+    XtSetArg(args[num_args], XtNallowVert,  True);     num_args++;
+    /* XtSetArg(args[num_args], XtNforceBars,  True);  num_args++; */
+    XtSetArg(args[num_args], XtNuseBottom,  True);     num_args++;
+    XtSetArg(args[num_args], XtNtranslations,
+               XtParseTranslationTable(map_translations));     num_args++;
+    viewport = XtCreateManagedWidget(
+                       "map_viewport",         /* name */
+                       viewportWidgetClass,    /* widget class from Window.h */
+                       parent,                 /* parent widget */
+                       args,                   /* set some values */
+                       num_args);              /* number of values to set */
+
+    /*
+     * Create a map window.  We need to set the width and height to some
+     * value when we create it.  We will change it to the value we want
+     * later
+     */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNwidth,  100); num_args++;
+    XtSetArg(args[num_args], XtNheight, 100); num_args++;
+    XtSetArg(args[num_args], XtNtranslations,
+               XtParseTranslationTable(map_translations));     num_args++;
+
+    wp->w = map = XtCreateManagedWidget(
+               "map",                  /* name */
+               windowWidgetClass,      /* widget class from Window.h */
+               viewport,               /* parent widget */
+               args,                   /* set some values */
+               num_args);              /* number of values to set */
+
+    XtAddCallback(map, XtNexposeCallback, map_exposed, (XtPointer) 0);
+
+    map_info = wp->map_information =
+                       (struct map_info_t *) alloc(sizeof(struct map_info_t));
+
+    map_info->viewport_width = map_info->viewport_height = 0;
+
+    /* reset the "new entry" indicators */
+    (void) memset((genericptr_t) map_info->t_start, (char) COLNO,
+                       sizeof(map_info->t_start));
+    (void) memset((genericptr_t) map_info->t_stop, (char) 0,
+                       sizeof(map_info->t_stop));
+
+    /* we probably want to restrict this to the 1st map window only */
+    if (appResources.tile_file[0] && init_tiles(wp)) {
+       map_info->is_tile = TRUE;
+    } else {
+       init_text(wp);
+       map_info->is_tile = FALSE;
+    }
+
+
+    /*
+     * Initially, set the map widget to be the size specified by the
+     * widget rows and columns resources.  We need to do this to
+     * correctly set the viewport window size.  After the viewport is
+     * realized, then the map can resize to its normal size.
+     */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNrows,    &rows);       num_args++;
+    XtSetArg(args[num_args], XtNcolumns, &columns);    num_args++;
+    XtGetValues(wp->w, args, num_args);
+
+    /* Don't bother with windows larger than ROWNOxCOLNO. */
+    if (columns > COLNO) columns = COLNO;
+    if (rows    > ROWNO) rows = ROWNO;
+
+#if 0 /* This is insufficient.  We now resize final window in winX.c */
+    /*
+     * Check for overrunning the size of the screen.  This does an ad hoc
+     * job.
+     *
+     * Width:  We expect that there is nothing but borders on either side
+     *         of the map window.  Use some arbitrary width to decide
+     *         when to shrink.
+     *
+     * Height: if the map takes up more than 1/2 of the screen height, start
+     *         reducing its size.
+     */
+    screen_height = HeightOfScreen(XtScreen(wp->w));
+    screen_width  = WidthOfScreen(XtScreen(wp->w));
+
+#define WOFF 50
+    if ((int)(columns*map_info->square_width) > screen_width-WOFF) {
+       columns = (screen_width-WOFF) / map_info->square_width;
+       if (columns == 0) columns = 1;
+    }
+
+    if ((int)(rows*map_info->square_height) > screen_height/2) {
+       rows = screen_height / (2*map_info->square_height);
+       if (rows == 0) rows = 1;
+    }
+#endif
+
+    set_map_size(wp, columns, rows);
+
+
+    /*
+     * If we have created our own popup, then realize it so that the
+     * viewport is also realized.  Then resize the map window.
+     */
+    if (create_popup) {
+       XtRealizeWidget(wp->popup);
+       XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup),
+                       &wm_delete_window, 1);
+       set_map_size(wp, COLNO, ROWNO);
+    }
+
+    if (map_info->is_tile) {
+       map_all_stone(map_info);
+    }
+}
+
+/*
+ * Destroy this map window.
+ */
+void
+destroy_map_window(wp)
+    struct xwindow *wp;
+{
+    struct map_info_t *map_info = wp->map_information;
+
+    if (wp->popup)
+       nh_XtPopdown(wp->popup);
+
+    if (map_info) {
+       struct text_map_info_t *text_map = map_info->mtype.text_map;
+
+       /* Free allocated GCs. */
+       if (!map_info->is_tile) {
+#ifdef TEXTCOLOR
+           int i;
+
+           for (i = 0; i < CLR_MAX; i++) {
+               XtReleaseGC(wp->w, text_map->color_gcs[i]);
+               XtReleaseGC(wp->w, text_map->inv_color_gcs[i]);
+           }
+#else
+           XtReleaseGC(wp->w, text_map->copy_gc);
+           XtReleaseGC(wp->w, text_map->inv_copy_gc);
+#endif
+       }
+       /* free alloc'ed text information */
+       free((genericptr_t)text_map),   map_info->mtype.text_map = 0;
+
+       /* Free malloc'ed space. */
+       free((genericptr_t)map_info),  wp->map_information = 0;
+    }
+
+       /* Destroy map widget. */
+    if (wp->popup && !wp->keep_window)
+       XtDestroyWidget(wp->popup),  wp->popup = (Widget)0;
+
+    if (wp->keep_window)
+       XtRemoveCallback(wp->w, XtNexposeCallback, map_exposed, (XtPointer)0);
+    else
+       wp->type = NHW_NONE;    /* allow re-use */
+}
+
+
+
+boolean exit_x_event;  /* exit condition for the event loop */
+/*******
+pkey(k)
+    int k;
+{
+    printf("key = '%s%c'\n", (k<32) ? "^":"", (k<32) ? '@'+k : k);
+}
+******/
+
+/*
+ * Main X event loop.  Here we accept and dispatch X events.  We only exit
+ * under certain circumstances.
+ */
+int
+x_event(exit_condition)
+    int exit_condition;
+{
+    XEvent  event;
+    int     retval = 0;
+    boolean keep_going = TRUE;
+
+    /* Hold globals so function is re-entrant */
+    boolean hold_exit_x_event = exit_x_event;
+
+    click_button = NO_CLICK;   /* reset click exit condition */
+    exit_x_event = FALSE;      /* reset callback exit condition */
+
+    /*
+     * Loop until we get a sent event, callback exit, or are accepting key
+     * press and button press events and we receive one.
+     */
+    if((exit_condition == EXIT_ON_KEY_PRESS ||
+       exit_condition == EXIT_ON_KEY_OR_BUTTON_PRESS) && incount)
+       goto try_test;
+
+    do {
+       XtAppNextEvent(app_context, &event);
+       XtDispatchEvent(&event);
+
+       /* See if we can exit. */
+    try_test:
+       switch (exit_condition) {
+           case EXIT_ON_SENT_EVENT: {
+               XAnyEvent *any = (XAnyEvent *) &event;
+               if (any->send_event) {
+                   retval = 0;
+                   keep_going = FALSE;
+               }
+               break;
+           }
+           case EXIT_ON_EXIT:
+               if (exit_x_event) {
+                   incount = 0;
+                   retval = 0;
+                   keep_going = FALSE;
+               }
+               break;
+           case EXIT_ON_KEY_PRESS:
+               if (incount != 0) {
+                   /* get first pressed key */
+                   --incount;
+                   retval = inbuf[inptr];
+                   inptr = (inptr+1) % INBUF_SIZE;
+                   /* pkey(retval); */
+                   keep_going = FALSE;
+               }
+               break;
+           case EXIT_ON_KEY_OR_BUTTON_PRESS:
+               if (incount != 0 || click_button != NO_CLICK) {
+                   if (click_button != NO_CLICK) {     /* button press */
+                       /* click values are already set */
+                       retval = 0;
+                   } else {                            /* key press */
+                       /* get first pressed key */
+                       --incount;
+                       retval = inbuf[inptr];
+                       inptr = (inptr+1) % INBUF_SIZE;
+                       /* pkey(retval); */
+                   }
+                   keep_going = FALSE;
+               }
+               break;
+           default:
+               panic("x_event: unknown exit condition %d", exit_condition);
+               break;
+       }
+    } while (keep_going);
+
+    /* Restore globals */
+    exit_x_event = hold_exit_x_event;
+
+    return retval;
+}
+
+/*winmap.c*/
diff --git a/win/X11/winmenu.c b/win/X11/winmenu.c
new file mode 100644 (file)
index 0000000..0d2640f
--- /dev/null
@@ -0,0 +1,1146 @@
+/*     SCCS Id: @(#)winmenu.c  3.4     1996/08/15      */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * File for creating menus.
+ *
+ *     + Global functions: start_menu, add_menu, end_menu, select_menu
+ */
+/*#define USE_FWF*/            /* use FWF's list widget */
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xatom.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/Viewport.h>
+#include <X11/Xaw/Cardinals.h>
+#include <X11/Xaw/Box.h>
+#ifdef USE_FWF
+#include <X11/Xfwf/MultiList.h>
+#else
+#include <X11/Xaw/List.h>
+#endif
+#include <X11/Xos.h>
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+#include "hack.h"
+#include "winX.h"
+#include <ctype.h>
+
+
+static void FDECL(menu_select, (Widget, XtPointer, XtPointer));
+static void FDECL(invert_line, (struct xwindow *,x11_menu_item *,int,long));
+static void FDECL(menu_ok, (Widget, XtPointer, XtPointer));
+static void FDECL(menu_cancel, (Widget, XtPointer, XtPointer));
+static void FDECL(menu_all, (Widget, XtPointer, XtPointer));
+static void FDECL(menu_none, (Widget, XtPointer, XtPointer));
+static void FDECL(menu_invert, (Widget, XtPointer, XtPointer));
+static void FDECL(menu_search, (Widget, XtPointer, XtPointer));
+static void FDECL(select_all, (struct xwindow *));
+static void FDECL(select_none, (struct xwindow *));
+static void FDECL(select_match, (struct xwindow *, char*));
+static void FDECL(invert_all, (struct xwindow *));
+static void FDECL(invert_match, (struct xwindow *, char*));
+static void FDECL(menu_popdown, (struct xwindow *));
+#ifdef USE_FWF
+static void FDECL(sync_selected, (struct menu_info_t *, int, int *));
+#endif
+
+static void FDECL(move_menu, (struct menu *, struct menu *));
+static void FDECL(free_menu, (struct menu *));
+static void FDECL(reset_menu_to_default, (struct menu *));
+static void FDECL(clear_old_menu, (struct xwindow *));
+static char *FDECL(copy_of, (const char *));
+
+#define reset_menu_count(mi)   ((mi)->counting = FALSE, (mi)->menu_count = 0L)
+
+
+static const char menu_translations[] =
+    "#override\n\
+     <Key>Left: scroll(4)\n\
+     <Key>Right: scroll(6)\n\
+     <Key>Up: scroll(8)\n\
+     <Key>Down: scroll(2)\n\
+     <Key>: menu_key()";
+
+/*
+ * Menu callback.
+ */
+/* ARGSUSED */
+static void
+menu_select(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data, call_data;
+{
+    struct xwindow *wp;
+    struct menu_info_t *menu_info;
+#ifdef USE_FWF
+    XfwfMultiListReturnStruct *lrs = (XfwfMultiListReturnStruct *) call_data;
+#else
+    XawListReturnStruct *lrs = (XawListReturnStruct *) call_data;
+    int i;
+    x11_menu_item *curr;
+#endif
+    long how_many;
+
+    wp = find_widget(w);
+    menu_info  = wp->menu_information;
+    how_many = menu_info->counting ? menu_info->menu_count : -1L;
+    reset_menu_count(menu_info);
+
+#ifdef USE_FWF
+    /* if we've reached here, we've found our selected item */
+    switch (lrs->action) {
+       case XfwfMultiListActionNothing:
+               pline("menu_select: nothing action?");
+               break;
+       case XfwfMultiListActionStatus:
+               pline("menu_select: status action?");
+               break;
+       case XfwfMultiListActionHighlight:
+       case XfwfMultiListActionUnhighlight:
+               sync_selected(menu_info,lrs->num_selected,lrs->selected_items);
+               break;
+    }
+#else
+    for (i = 0, curr = menu_info->curr_menu.base; i < lrs->list_index; i++) {
+       if (!curr) panic("menu_select: out of menu items!");
+       curr = curr->next;
+    }
+    XawListUnhighlight(w);     /* unhilight item */
+
+    /* if the menu is not active or don't have an identifier, try again */
+    if (!menu_info->is_active || curr->identifier.a_void == 0) {
+       X11_nhbell();
+       return;
+    }
+
+    /* if we've reached here, we've found our selected item */
+    curr->selected = !curr->selected;
+    if (curr->selected) {
+       curr->str[2] = (how_many != -1L) ? '#' : '+';
+       curr->pick_count = how_many;
+    } else {
+       curr->str[2] = '-';
+       curr->pick_count = -1L;
+    }
+    XawListChange(wp->w, menu_info->curr_menu.list_pointer, 0, 0, True);
+#endif
+
+    if (menu_info->how == PICK_ONE)
+       menu_popdown(wp);
+}
+
+/*
+ * Called when menu window is deleted.
+ */
+/* ARGSUSED */
+void
+menu_delete(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    menu_cancel((Widget)None, (XtPointer) find_widget(w), (XtPointer) 0);
+}
+
+/*
+ * Invert the count'th line (curr) in the given window.
+ */
+/*ARGSUSED*/
+static void
+invert_line(wp, curr, which, how_many)
+    struct xwindow *wp;
+    x11_menu_item *curr;
+    int which;
+    long how_many;
+{
+    reset_menu_count(wp->menu_information);
+    curr->selected = !curr->selected;
+    if (curr->selected) {
+#ifdef USE_FWF
+       XfwfMultiListHighlightItem((XfwfMultiListWidget)wp->w, which);
+#else
+       curr->str[2] = (how_many != -1) ? '#' : '+';
+#endif
+       curr->pick_count = how_many;
+    } else {
+#ifdef USE_FWF
+       XfwfMultiListUnhighlightItem((XfwfMultiListWidget)wp->w, which);
+#else
+       curr->str[2] = '-';
+#endif
+       curr->pick_count = -1L;
+    }
+}
+
+/*
+ * Called when we get a key press event on a menu window.
+ */
+/* ARGSUSED */
+void
+menu_key(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    struct menu_info_t *menu_info;
+    x11_menu_item *curr;
+    struct xwindow *wp;
+    char ch;
+    int count;
+
+    wp = find_widget(w);
+    menu_info = wp->menu_information;
+
+    ch = key_event_to_char((XKeyEvent *) event);
+
+    if (ch == '\0') {  /* don't accept nul char/modifier event */
+       /* don't beep */
+       return;
+    }
+
+    if (menu_info->is_active) {                /* waiting for input */
+       ch = map_menu_cmd(ch);
+       if (ch == '\033') {             /* quit */
+           if (menu_info->counting) {
+               /* when there's a count in progress, ESC discards it
+                  rather than dismissing the whole menu */
+               reset_menu_count(menu_info);
+               return;
+           }
+           select_none(wp);
+       } else if (ch == '\n' || ch == '\r') {
+           ;   /* accept */
+       } else if (isdigit(ch)) {
+           /* special case: '0' is also the default ball class */
+           if (ch == '0' && !menu_info->counting &&
+                   index(menu_info->curr_menu.gacc, ch))
+               goto group_accel;
+           menu_info->menu_count *= 10L;
+           menu_info->menu_count += (long)(ch - '0');
+           if (menu_info->menu_count != 0L)    /* ignore leading zeros */
+               menu_info->counting = TRUE;
+           return;
+       } else if (ch == MENU_SEARCH) {         /* search */
+           if (menu_info->how == PICK_ANY || menu_info->how == PICK_ONE) {
+               char buf[BUFSZ];
+               X11_getlin("Search for:", buf);
+               if (!*buf || *buf == '\033') return;
+               if (menu_info->how == PICK_ANY) {
+                   invert_match(wp, buf);
+                   return;
+               } else {
+                   select_match(wp, buf);
+               }
+           } else {
+               X11_nhbell();
+               return;
+           }
+       } else if (ch == MENU_SELECT_ALL) {             /* select all */
+           if (menu_info->how == PICK_ANY)
+               select_all(wp);
+           else
+               X11_nhbell();
+           return;
+       } else if (ch == MENU_UNSELECT_ALL) {           /* unselect all */
+           if (menu_info->how == PICK_ANY)
+               select_none(wp);
+           else
+               X11_nhbell();
+           return;
+       } else if (ch == MENU_INVERT_ALL) {             /* invert all */
+           if (menu_info->how == PICK_ANY)
+               invert_all(wp);
+           else
+               X11_nhbell();
+           return;
+       } else if (index(menu_info->curr_menu.gacc, ch)) {
+ group_accel:
+           /* matched a group accelerator */
+           if (menu_info->how == PICK_ANY || menu_info->how == PICK_ONE) {
+               for (count = 0, curr = menu_info->curr_menu.base; curr;
+                                               curr = curr->next, count++) {
+                   if (curr->identifier.a_void != 0 && curr->gselector == ch) {
+                       invert_line(wp, curr, count, -1L);
+                       /* for PICK_ONE, a group accelerator will
+                          only be included in gacc[] if it matches
+                          exactly one entry, so this must be it... */
+                       if (menu_info->how == PICK_ONE)
+                           goto menu_done;     /* pop down */
+                   }
+               }
+#ifndef USE_FWF
+               XawListChange(wp->w, menu_info->curr_menu.list_pointer, 0, 0, True);
+#endif
+           } else
+               X11_nhbell();
+           return;
+       } else {
+           boolean selected_something = FALSE;
+           for (count = 0, curr = menu_info->curr_menu.base; curr;
+                                                   curr = curr->next, count++)
+               if (curr->identifier.a_void != 0 && curr->selector == ch) break;
+
+           if (curr) {
+               invert_line(wp, curr, count,
+                           menu_info->counting ? menu_info->menu_count : -1L);
+#ifndef USE_FWF
+               XawListChange(wp->w, menu_info->curr_menu.list_pointer, 0, 0, True);
+#endif
+               selected_something = curr->selected;
+           } else {
+               X11_nhbell();           /* no match */
+           }
+           if (!(selected_something && menu_info->how == PICK_ONE))
+               return;         /* keep going */
+       }
+       /* pop down */
+    } else {                   /* permanent inventory window */
+       if (ch != '\033') {
+           X11_nhbell();
+           return;
+       }
+       /* pop down on ESC */
+    }
+
+ menu_done:
+    menu_popdown(wp);
+}
+
+/* ARGSUSED */
+static void
+menu_ok(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data, call_data;
+{
+    struct xwindow *wp = (struct xwindow *) client_data;
+
+    menu_popdown(wp);
+}
+
+/* ARGSUSED */
+static void
+menu_cancel(w, client_data, call_data)
+    Widget w;                          /* don't use - may be None */
+    XtPointer client_data, call_data;
+{
+    struct xwindow *wp = (struct xwindow *) client_data;
+
+    if (wp->menu_information->is_active) {
+       select_none(wp);
+       wp->menu_information->cancelled = TRUE;
+    }
+    menu_popdown(wp);
+}
+
+/* ARGSUSED */
+static void
+menu_all(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data, call_data;
+{
+    select_all((struct xwindow *) client_data);
+}
+
+/* ARGSUSED */
+static void
+menu_none(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data, call_data;
+{
+    select_none((struct xwindow *) client_data);
+}
+
+/* ARGSUSED */
+static void
+menu_invert(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data, call_data;
+{
+    invert_all((struct xwindow *) client_data);
+}
+
+/* ARGSUSED */
+static void
+menu_search(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data, call_data;
+{
+    struct xwindow *wp = (struct xwindow *) client_data;
+    struct menu_info_t *menu_info = wp->menu_information;
+
+    char buf[BUFSZ];
+    X11_getlin("Search for:", buf);
+    if (!*buf || *buf == '\033') return;
+
+    if (menu_info->how == PICK_ANY)
+       invert_match(wp, buf);
+    else
+       select_match(wp, buf);
+
+    if (menu_info->how == PICK_ONE)
+       menu_popdown(wp);
+}
+
+static void
+select_all(wp)
+    struct xwindow *wp;
+{
+    x11_menu_item *curr;
+    int count;
+    boolean changed = FALSE;
+
+    reset_menu_count(wp->menu_information);
+    for (count = 0, curr = wp->menu_information->curr_menu.base; curr;
+                                       curr = curr->next, count++)
+       if (curr->identifier.a_void != 0)
+           if (!curr->selected) {
+               invert_line(wp, curr, count, -1L);
+               changed = TRUE;
+           }
+
+#ifndef USE_FWF
+    if (changed)
+       XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer,
+                     0, 0, True);
+#endif
+}
+
+static void
+select_none(wp)
+    struct xwindow *wp;
+{
+    x11_menu_item *curr;
+    int count;
+    boolean changed = FALSE;
+
+    reset_menu_count(wp->menu_information);
+    for (count = 0, curr = wp->menu_information->curr_menu.base; curr;
+                                       curr = curr->next, count++)
+       if (curr->identifier.a_void != 0)
+           if (curr->selected) {
+               invert_line(wp, curr, count, -1L);
+               changed = TRUE;
+           }
+
+#ifndef USE_FWF
+    if (changed)
+       XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer,
+                     0, 0, True);
+#endif
+}
+
+static void
+invert_all(wp)
+    struct xwindow *wp;
+{
+    x11_menu_item *curr;
+    int count;
+
+    reset_menu_count(wp->menu_information);
+    for (count = 0, curr = wp->menu_information->curr_menu.base; curr;
+                                       curr = curr->next, count++)
+       if (curr->identifier.a_void != 0)
+           invert_line(wp, curr, count, -1L);
+
+#ifndef USE_FWF
+    XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer,
+                 0, 0, True);
+#endif
+}
+
+static void
+invert_match(wp, match)
+    struct xwindow *wp;
+    char *match;
+{
+    x11_menu_item *curr;
+    int count;
+    boolean changed = FALSE;
+
+    reset_menu_count(wp->menu_information);
+    for (count = 0, curr = wp->menu_information->curr_menu.base; curr;
+                                               curr = curr->next, count++)
+       if (curr->identifier.a_void != 0 && strstri(curr->str, match)) {
+           invert_line(wp, curr, count, -1L);
+           changed = TRUE;
+       }
+
+#ifndef USE_FWF
+    if (changed)
+       XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer,
+                     0, 0, True);
+#endif
+}
+
+static void
+select_match(wp, match)
+    struct xwindow *wp;
+    char *match;
+{
+    x11_menu_item *curr;
+    int count;
+
+    reset_menu_count(wp->menu_information);
+    for (count = 0, curr = wp->menu_information->curr_menu.base; curr;
+                                               curr = curr->next, count++)
+       if (curr->identifier.a_void != 0 && strstri(curr->str, match)) {
+           if (!curr->selected) {
+               invert_line(wp, curr, count, -1L);
+#ifndef USE_FWF
+               XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer,
+                             0, 0, True);
+#endif
+           }
+           return;
+       }
+
+    /* no match */
+    X11_nhbell();
+}
+
+static void
+menu_popdown(wp)
+    struct xwindow *wp;
+{
+    nh_XtPopdown(wp->popup);                   /* remove the event grab */
+    if (wp->menu_information->is_active)
+       exit_x_event = TRUE;                    /* exit our event handler */
+    wp->menu_information->is_up = FALSE;       /* menu is down */
+}
+
+#ifdef USE_FWF
+/*
+ * Make sure our idea of selected matches the FWF Multilist's idea of what
+ * is currently selected.  The MultiList's selected list can change without
+ * notifying us if one or more items are selected and then another is
+ * selected (not toggled).  Then the items that were selected are deselected
+ * but we are not notified.
+ */
+static void
+sync_selected(menu_info, num_selected, items)
+    struct menu_info_t *menu_info;
+    int num_selected;
+    int *items;
+{
+    int i, j, *ip;
+    x11_menu_item *curr;
+    Boolean found;
+
+    for (i=0, curr = menu_info->curr_menu.base; curr; i++, curr = curr->next) {
+       found = False;
+       for (j = 0, ip = items; j < num_selected; j++, ip++)
+           if (*ip == i) {
+               found = True;
+               break;
+           }
+#if 0
+       if (curr->selected && !found)
+           printf("sync: deselecting %s\n", curr->str);
+       else if (!curr->selected && found)
+           printf("sync: selecting %s\n", curr->str);
+#endif
+       curr->selected = found ? TRUE : FALSE;
+    }
+}
+#endif /* USE_FWF */
+
+
+/* Global functions ======================================================== */
+
+void
+X11_start_menu(window)
+    winid window;
+{
+    struct xwindow *wp;
+    check_winid(window);
+
+    wp = &window_list[window];
+
+    if (wp->menu_information->is_menu) {
+       /* make sure we'ere starting with a clean slate */
+       free_menu(&wp->menu_information->new_menu);
+    } else {
+       wp->menu_information->is_menu = TRUE;
+    }
+}
+
+/*ARGSUSED*/
+void
+X11_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected)
+    winid window;
+    int glyph;                 /* unused (for now) */
+    const anything *identifier;
+    char ch;
+    char gch;                  /* group accelerator (0 = no group) */
+    int attr;
+    const char *str;
+    boolean preselected;
+{
+    x11_menu_item *item;
+    struct menu_info_t *menu_info;
+
+    check_winid(window);
+    menu_info = window_list[window].menu_information;
+    if (!menu_info->is_menu) {
+       impossible("add_menu:  called before start_menu");
+       return;
+    }
+
+    item = (x11_menu_item *) alloc((unsigned)sizeof(x11_menu_item));
+    item->next = (x11_menu_item *) 0;
+    item->identifier = *identifier;
+    item->attr = attr;
+/*    item->selected = preselected; */
+    item->selected = FALSE;
+    item->pick_count = -1L;
+
+    if (identifier->a_void) {
+       char buf[4+BUFSZ];
+       int len = strlen(str);
+
+       if (!ch) {
+           /* Supply a keyboard accelerator.  Only the first 52 get one. */
+
+           if (menu_info->new_menu.curr_selector) {
+               ch = menu_info->new_menu.curr_selector++;
+               if (ch == 'z')
+                   menu_info->new_menu.curr_selector = 'A';
+               else if (ch == 'Z')
+                   menu_info->new_menu.curr_selector = 0;      /* out */
+           }
+       }
+
+       if (len >= BUFSZ) {
+           /* We *think* everything's coming in off at most BUFSZ bufs... */
+           impossible("Menu item too long (%d).", len);
+           len = BUFSZ - 1;
+       }
+       Sprintf(buf, "%c - ", ch ? ch : ' ');
+       (void) strncpy(buf+4, str, len);
+       buf[4+len] = '\0';
+       item->str = copy_of(buf);
+    } else {
+       /* no keyboard accelerator */
+       item->str = copy_of(str);
+       ch = 0;
+    }
+
+    item->selector = ch;
+    item->gselector = gch;
+
+    if (menu_info->new_menu.last) {
+       menu_info->new_menu.last->next = item;
+    } else {
+       menu_info->new_menu.base = item;
+    }
+    menu_info->new_menu.last = item;
+    menu_info->new_menu.count++;
+}
+
+void
+X11_end_menu(window, query)
+    winid window;
+    const char *query;
+{
+    struct menu_info_t *menu_info;
+
+    check_winid(window);
+    menu_info = window_list[window].menu_information;
+    if (!menu_info->is_menu) {
+       impossible("end_menu:  called before start_menu");
+       return;
+    }
+    menu_info->new_menu.query = copy_of(query);
+}
+
+int
+X11_select_menu(window, how, menu_list)
+    winid window;
+    int how;
+    menu_item **menu_list;
+{
+    x11_menu_item *curr;
+    struct xwindow *wp;
+    struct menu_info_t *menu_info;
+    Arg args[10];
+    Cardinal num_args;
+    String *ptr;
+    int retval;
+    Dimension v_pixel_width, v_pixel_height;
+    boolean labeled;
+    Widget viewport_widget, form, label, ok, cancel, all, none, invert, search;
+    Boolean sens;
+#ifdef USE_FWF
+    Boolean *boolp;
+#endif
+    char gacc[QBUFSZ], *ap;
+
+    *menu_list = (menu_item *) 0;
+    check_winid(window);
+    wp = &window_list[window];
+    menu_info = wp->menu_information;
+    if (!menu_info->is_menu) {
+       impossible("select_menu:  called before start_menu");
+       return 0;
+    }
+
+    menu_info->how = (short) how;
+
+    /* collect group accelerators; for PICK_NONE, they're ignored;
+       for PICK_ONE, only those which match exactly one entry will be
+       accepted; for PICK_ANY, those which match any entry are okay */
+    gacc[0] = '\0';
+    if (menu_info->how != PICK_NONE) {
+       int i, n, gcnt[128];
+#define GSELIDX(c) ((c) & 127) /* guard against `signed char' */
+
+       for (i = 0; i < SIZE(gcnt); i++) gcnt[i] = 0;
+       for (n = 0, curr = menu_info->new_menu.base; curr; curr = curr->next)
+           if (curr->gselector && curr->gselector != curr->selector) {
+               ++n;
+               ++gcnt[GSELIDX(curr->gselector)];
+           }
+
+       if (n > 0)      /* at least one group accelerator found */
+           for (ap = gacc, curr = menu_info->new_menu.base;
+                   curr; curr = curr->next)
+               if (curr->gselector && !index(gacc, curr->gselector) &&
+                       (menu_info->how == PICK_ANY ||
+                           gcnt[GSELIDX(curr->gselector)] == 1)) {
+                   *ap++ = curr->gselector;
+                   *ap = '\0'; /* re-terminate for index() */
+               }
+    }
+    menu_info->new_menu.gacc = copy_of(gacc);
+    reset_menu_count(menu_info);
+
+    /*
+     * Create a string and sensitive list for the new menu.
+     */
+    menu_info->new_menu.list_pointer = ptr = (String *)
+           alloc((unsigned) (sizeof(String) * (menu_info->new_menu.count+1)));
+    for (curr = menu_info->new_menu.base; curr; ptr++, curr = curr->next)
+       *ptr = (String) curr->str;
+    *ptr = 0;          /* terminate list with null */
+
+#ifdef USE_FWF
+    menu_info->new_menu.sensitive = boolp = (Boolean *)
+           alloc((unsigned) (sizeof(Boolean) * (menu_info->new_menu.count)));
+    for (curr = menu_info->new_menu.base; curr; boolp++, curr = curr->next)
+       *boolp = (curr->identifier.a_void != 0);
+#else
+    menu_info->new_menu.sensitive = (Boolean *) 0;
+#endif
+    labeled = (menu_info->new_menu.query && *(menu_info->new_menu.query))
+       ? TRUE : FALSE;
+
+    /*
+     * Menus don't appear to size components correctly, except
+     * when first created.  For 3.2.0 release, just recreate
+     * each time.
+     */
+    if (menu_info->valid_widgets
+                       && (window != WIN_INVEN || !flags.perm_invent)) {
+       XtDestroyWidget(wp->popup);
+       menu_info->valid_widgets = FALSE;
+       menu_info->is_up = FALSE;
+    }
+
+    if (!menu_info->valid_widgets) {
+       Dimension row_spacing;
+
+       num_args = 0;
+       XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
+       wp->popup = XtCreatePopupShell(
+                       window == WIN_INVEN ? "inventory" : "menu",
+                       how == PICK_NONE ? topLevelShellWidgetClass:
+                                       transientShellWidgetClass,
+                       toplevel, args, num_args);
+       XtOverrideTranslations(wp->popup,
+           XtParseTranslationTable("<Message>WM_PROTOCOLS: menu_delete()"));
+
+
+       num_args = 0;
+       XtSetArg(args[num_args], XtNtranslations,
+               XtParseTranslationTable(menu_translations));    num_args++;
+       form = XtCreateManagedWidget("mform",
+                                   formWidgetClass,
+                                   wp->popup,
+                                   args, num_args);
+
+       num_args = 0;
+       XtSetArg(args[num_args], XtNborderWidth, 0);            num_args++;
+       XtSetArg(args[num_args], XtNtop, XtChainTop);           num_args++;
+       XtSetArg(args[num_args], XtNbottom, XtChainTop);        num_args++;
+       XtSetArg(args[num_args], XtNleft, XtChainLeft);         num_args++;
+       XtSetArg(args[num_args], XtNright, XtChainLeft);        num_args++;
+
+       if (labeled)
+           label = XtCreateManagedWidget(menu_info->new_menu.query,
+                                   labelWidgetClass,
+                                   form,
+                                   args, num_args);
+       else label = NULL;
+
+       /*
+        * Create ok, cancel, all, none, invert, and search buttons..
+        */
+       num_args = 0;
+       XtSetArg(args[num_args], XtNfromVert, label);           num_args++;
+       XtSetArg(args[num_args], XtNtop, XtChainTop);           num_args++;
+       XtSetArg(args[num_args], XtNbottom, XtChainTop);        num_args++;
+       XtSetArg(args[num_args], XtNleft, XtChainLeft);         num_args++;
+       XtSetArg(args[num_args], XtNright, XtChainLeft);        num_args++;
+       ok = XtCreateManagedWidget("OK",
+                       commandWidgetClass,
+                       form,
+                       args, num_args);
+       XtAddCallback(ok, XtNcallback, menu_ok, (XtPointer) wp);
+
+       num_args = 0;
+       XtSetArg(args[num_args], XtNfromVert, label);           num_args++;
+       XtSetArg(args[num_args], XtNfromHoriz, ok);             num_args++;
+       XtSetArg(args[num_args], XtNsensitive, how!=PICK_NONE); num_args++;
+       XtSetArg(args[num_args], XtNtop, XtChainTop);           num_args++;
+       XtSetArg(args[num_args], XtNbottom, XtChainTop);        num_args++;
+       XtSetArg(args[num_args], XtNleft, XtChainLeft);         num_args++;
+       XtSetArg(args[num_args], XtNright, XtChainLeft);        num_args++;
+       cancel = XtCreateManagedWidget("cancel",
+                       commandWidgetClass,
+                       form,
+                       args, num_args);
+       XtAddCallback(cancel, XtNcallback, menu_cancel, (XtPointer) wp);
+
+       sens = (how == PICK_ANY);
+       num_args = 0;
+       XtSetArg(args[num_args], XtNfromVert, label);           num_args++;
+       XtSetArg(args[num_args], XtNfromHoriz, cancel);         num_args++;
+       XtSetArg(args[num_args], XtNsensitive, sens);           num_args++;
+       XtSetArg(args[num_args], XtNtop, XtChainTop);           num_args++;
+       XtSetArg(args[num_args], XtNbottom, XtChainTop);        num_args++;
+       XtSetArg(args[num_args], XtNleft, XtChainLeft);         num_args++;
+       XtSetArg(args[num_args], XtNright, XtChainLeft);        num_args++;
+       all = XtCreateManagedWidget("all",
+                       commandWidgetClass,
+                       form,
+                       args, num_args);
+       XtAddCallback(all, XtNcallback, menu_all, (XtPointer) wp);
+
+       num_args = 0;
+       XtSetArg(args[num_args], XtNfromVert, label);           num_args++;
+       XtSetArg(args[num_args], XtNfromHoriz, all);            num_args++;
+       XtSetArg(args[num_args], XtNsensitive, sens);           num_args++;
+       XtSetArg(args[num_args], XtNtop, XtChainTop);           num_args++;
+       XtSetArg(args[num_args], XtNbottom, XtChainTop);        num_args++;
+       XtSetArg(args[num_args], XtNleft, XtChainLeft);         num_args++;
+       XtSetArg(args[num_args], XtNright, XtChainLeft);        num_args++;
+       none = XtCreateManagedWidget("none",
+                       commandWidgetClass,
+                       form,
+                       args, num_args);
+       XtAddCallback(none, XtNcallback, menu_none, (XtPointer) wp);
+
+       num_args = 0;
+       XtSetArg(args[num_args], XtNfromVert, label);           num_args++;
+       XtSetArg(args[num_args], XtNfromHoriz, none);           num_args++;
+       XtSetArg(args[num_args], XtNsensitive, sens);           num_args++;
+       XtSetArg(args[num_args], XtNtop, XtChainTop);           num_args++;
+       XtSetArg(args[num_args], XtNbottom, XtChainTop);        num_args++;
+       XtSetArg(args[num_args], XtNleft, XtChainLeft);         num_args++;
+       XtSetArg(args[num_args], XtNright, XtChainLeft);        num_args++;
+       invert = XtCreateManagedWidget("invert",
+                       commandWidgetClass,
+                       form,
+                       args, num_args);
+       XtAddCallback(invert, XtNcallback, menu_invert, (XtPointer) wp);
+
+       num_args = 0;
+       XtSetArg(args[num_args], XtNfromVert, label);           num_args++;
+       XtSetArg(args[num_args], XtNfromHoriz, invert);         num_args++;
+       XtSetArg(args[num_args], XtNsensitive, how!=PICK_NONE); num_args++;
+       XtSetArg(args[num_args], XtNtop, XtChainTop);           num_args++;
+       XtSetArg(args[num_args], XtNbottom, XtChainTop);        num_args++;
+       XtSetArg(args[num_args], XtNleft, XtChainLeft);         num_args++;
+       XtSetArg(args[num_args], XtNright, XtChainLeft);        num_args++;
+       search = XtCreateManagedWidget("search",
+                       commandWidgetClass,
+                       form,
+                       args, num_args);
+       XtAddCallback(search, XtNcallback, menu_search, (XtPointer) wp);
+
+       num_args = 0;
+       XtSetArg(args[num_args], XtNallowVert,  True);          num_args++;
+       XtSetArg(args[num_args], XtNallowHoriz, False);         num_args++;
+       XtSetArg(args[num_args], XtNuseBottom, True);           num_args++;
+       XtSetArg(args[num_args], XtNuseRight, True);            num_args++;
+/*
+       XtSetArg(args[num_args], XtNforceBars, True);           num_args++;
+*/
+       XtSetArg(args[num_args], XtNfromVert, all);             num_args++;
+       XtSetArg(args[num_args], XtNtop, XtChainTop);           num_args++;
+       XtSetArg(args[num_args], XtNbottom, XtChainBottom);     num_args++;
+       XtSetArg(args[num_args], XtNleft, XtChainLeft);         num_args++;
+       XtSetArg(args[num_args], XtNright, XtChainRight);       num_args++;
+       viewport_widget = XtCreateManagedWidget(
+                   "menu_viewport",    /* name */
+                   viewportWidgetClass,
+                   form,               /* parent widget */
+                   args, num_args);    /* values, and number of values */
+
+       /* make new menu the current menu */
+       move_menu(&menu_info->new_menu, &menu_info->curr_menu);
+
+       num_args = 0;
+       XtSetArg(args[num_args], XtNforceColumns, True);        num_args++;
+       XtSetArg(args[num_args], XtNcolumnSpacing, 1);          num_args++;
+       XtSetArg(args[num_args], XtNdefaultColumns, 1);         num_args++;
+       XtSetArg(args[num_args], XtNlist,
+                       menu_info->curr_menu.list_pointer);     num_args++;
+#ifdef USE_FWF
+       XtSetArg(args[num_args], XtNsensitiveArray,
+                       menu_info->curr_menu.sensitive);        num_args++;
+       XtSetArg(args[num_args], XtNmaxSelectable,
+                       menu_info->curr_menu.count);            num_args++;
+#endif
+       wp->w = XtCreateManagedWidget(
+                   "menu_list",                /* name */
+#ifdef USE_FWF
+                   xfwfMultiListWidgetClass,
+#else
+                   listWidgetClass,
+#endif
+                   viewport_widget,            /* parent widget */
+                   args,                       /* set some values */
+                   num_args);                  /* number of values to set */
+
+       XtAddCallback(wp->w, XtNcallback, menu_select, (XtPointer) 0);
+
+       /* Get the font and margin information. */
+       num_args = 0;
+       XtSetArg(args[num_args], XtNfont, &menu_info->fs);      num_args++;
+       XtSetArg(args[num_args], XtNinternalHeight,
+                               &menu_info->internal_height);   num_args++;
+       XtSetArg(args[num_args], XtNinternalWidth,
+                               &menu_info->internal_width);    num_args++;
+       XtSetArg(args[num_args], XtNrowSpacing, &row_spacing);  num_args++;
+       XtGetValues(wp->w, args, num_args);
+
+       /* font height is ascent + descent */
+       menu_info->line_height =
+               menu_info->fs->max_bounds.ascent +
+               menu_info->fs->max_bounds.descent + row_spacing;
+
+       menu_info->valid_widgets = TRUE;
+
+       num_args = 0;
+       XtSetArg(args[num_args], XtNwidth, &v_pixel_width);     num_args++;
+       XtSetArg(args[num_args], XtNheight, &v_pixel_height);   num_args++;
+       XtGetValues(wp->w, args, num_args);
+    } else {
+       Dimension len;
+
+       viewport_widget = XtParent(wp->w);
+
+       /* get the longest string on new menu */
+       v_pixel_width = 0;
+       for (ptr = menu_info->new_menu.list_pointer; *ptr; ptr++) {
+           len = XTextWidth(menu_info->fs, *ptr, strlen(*ptr));
+           if (len > v_pixel_width) v_pixel_width = len;
+       }
+
+       /* add viewport internal border */
+       v_pixel_width += 2 * menu_info->internal_width;
+       v_pixel_height = (2 * menu_info->internal_height) +
+           (menu_info->new_menu.count * menu_info->line_height);
+
+       /* make new menu the current menu */
+       move_menu(&menu_info->new_menu, &menu_info->curr_menu);
+#ifdef USE_FWF
+       XfwfMultiListSetNewData((XfwfMultiListWidget)wp->w,
+               menu_info->curr_menu.list_pointer, 0, 0, TRUE,
+               menu_info->curr_menu.sensitive);
+#else
+       XawListChange(wp->w, menu_info->curr_menu.list_pointer, 0, 0, TRUE);
+#endif
+    }
+
+    /* if viewport will be bigger than the screen, limit its height */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNwidth, &v_pixel_width);        num_args++;
+    XtSetArg(args[num_args], XtNheight, &v_pixel_height);      num_args++;
+    XtGetValues(wp->w, args, num_args);
+    if ((Dimension) XtScreen(wp->w)->height * 5 / 6 < v_pixel_height) {
+       /* scrollbar is 14 pixels wide.  Widen the form to accommodate it. */
+       v_pixel_width += 14;
+
+       /* shrink to fit vertically */
+       v_pixel_height = XtScreen(wp->w)->height * 5 / 6;
+
+       num_args = 0;
+       XtSetArg(args[num_args], XtNwidth, v_pixel_width); num_args++;
+       XtSetArg(args[num_args], XtNheight, v_pixel_height); num_args++;
+       XtSetValues(wp->w, args, num_args);
+    }
+    XtRealizeWidget(wp->popup);        /* need to realize before we position */
+
+    /* if menu is not up, position it */
+    if (!menu_info->is_up) positionpopup(wp->popup, FALSE);
+
+    menu_info->is_up = TRUE;
+    if (window == WIN_INVEN && how == PICK_NONE) {
+       /* cant use nh_XtPopup() because it may try to grab the focus */
+       XtPopup(wp->popup, (int)XtGrabNone);
+       if (!updated_inventory)
+           XMapRaised(XtDisplay(wp->popup), XtWindow(wp->popup));
+       XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup),
+                                                       &wm_delete_window, 1);
+       retval = 0;
+    } else {
+       menu_info->is_active = TRUE;    /* waiting for user response */
+       menu_info->cancelled = FALSE;
+       nh_XtPopup(wp->popup, (int)XtGrabExclusive, wp->w);
+       (void) x_event(EXIT_ON_EXIT);
+       menu_info->is_active = FALSE;
+       if (menu_info->cancelled)
+           return -1;
+
+       retval = 0;
+       for (curr = menu_info->curr_menu.base; curr; curr = curr->next)
+           if (curr->selected) retval++;
+
+       if (retval) {
+           menu_item *mi;
+
+           *menu_list = mi = (menu_item *) alloc(retval * sizeof(menu_item));
+           for (curr = menu_info->curr_menu.base; curr; curr = curr->next)
+               if (curr->selected) {
+                   mi->item = curr->identifier;
+                   mi->count = curr->pick_count;
+                   mi++;
+               }
+       }
+    }
+
+    return retval;
+}
+
+/* End global functions ==================================================== */
+
+/*
+ * Allocate a copy of the given string.  If null, return a string of
+ * zero length.
+ *
+ * This is an exact duplicate of copy_of() in tty/wintty.c.
+ */
+static char *
+copy_of(s)
+    const char *s;
+{
+    if (!s) s = "";
+    return strcpy((char *) alloc((unsigned) (strlen(s) + 1)), s);
+}
+
+
+static void
+move_menu(src_menu, dest_menu)
+    struct menu *src_menu, *dest_menu;
+{
+    free_menu(dest_menu);      /* toss old menu */
+    *dest_menu = *src_menu;    /* make new menu current */
+                               /* leave no dangling ptrs */
+    reset_menu_to_default(src_menu);
+}
+
+
+static void
+free_menu(mp)
+    struct menu *mp;
+{
+    while (mp->base) {
+       mp->last = mp->base;
+       mp->base = mp->base->next;
+
+       free((genericptr_t)mp->last->str);
+       free((genericptr_t)mp->last);
+    }
+    if (mp->query) free((genericptr_t) mp->query);
+    if (mp->gacc) free((genericptr_t) mp->gacc);
+    if (mp->list_pointer) free((genericptr_t) mp->list_pointer);
+    if (mp->sensitive) free((genericptr_t) mp->sensitive);
+    reset_menu_to_default(mp);
+}
+
+static void
+reset_menu_to_default(mp)
+    struct menu *mp;
+{
+    mp->base = mp->last = (x11_menu_item *)0;
+    mp->query = (const char *)0;
+    mp->gacc = (const char *)0;
+    mp->count = 0;
+    mp->list_pointer = (String *)0;
+    mp->sensitive = (Boolean *)0;
+    mp->curr_selector = 'a';   /* first accelerator */
+}
+
+static void
+clear_old_menu(wp)
+    struct xwindow *wp;
+{
+    struct menu_info_t *menu_info = wp->menu_information;
+
+    free_menu(&menu_info->curr_menu);
+    free_menu(&menu_info->new_menu);
+
+    if (menu_info->valid_widgets) {
+       nh_XtPopdown(wp->popup);
+       menu_info->is_up = FALSE;
+       XtDestroyWidget(wp->popup);
+       menu_info->valid_widgets = FALSE;
+       wp->w = wp->popup = (Widget) 0;
+    }
+}
+
+void
+create_menu_window(wp)
+    struct xwindow *wp;
+{
+    wp->type = NHW_MENU;
+    wp->menu_information =
+               (struct menu_info_t *) alloc(sizeof(struct menu_info_t));
+    (void) memset((genericptr_t) wp->menu_information, '\0',
+                                               sizeof(struct menu_info_t));
+    reset_menu_to_default(&wp->menu_information->curr_menu);
+    reset_menu_to_default(&wp->menu_information->new_menu);
+    reset_menu_count(wp->menu_information);
+    wp->w = wp->popup = (Widget) 0;
+}
+
+void
+destroy_menu_window(wp)
+    struct xwindow *wp;
+{
+    clear_old_menu(wp);                /* this will also destroy the widgets */
+    free((genericptr_t) wp->menu_information);
+    wp->menu_information = (struct menu_info_t *) 0;
+    wp->type = NHW_NONE;       /* allow re-use */
+}
+
+/*winmenu.c*/
diff --git a/win/X11/winmesg.c b/win/X11/winmesg.c
new file mode 100644 (file)
index 0000000..63dac96
--- /dev/null
@@ -0,0 +1,625 @@
+/*     SCCS Id: @(#)winmesg.c  3.4     1996/04/05      */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Message window routines.
+ *
+ * Global functions:
+ *     create_message_window()
+ *     destroy_message_window()
+ *     display_message_window()
+ *     append_message()
+ */
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/Cardinals.h>
+#include <X11/Xaw/Viewport.h>
+#include <X11/Xatom.h>
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+#include "xwindow.h"   /* Window widget declarations */
+
+#include "hack.h"
+#include "winX.h"
+
+static struct line_element *FDECL(get_previous, (struct line_element *));
+static void FDECL(set_circle_buf, (struct mesg_info_t *,int));
+static char *FDECL(split, (char *,XFontStruct *,DIMENSION_P));
+static void FDECL(add_line, (struct mesg_info_t *,const char *));
+static void FDECL(redraw_message_window, (struct xwindow *));
+static void FDECL(mesg_check_size_change, (struct xwindow *));
+static void FDECL(mesg_exposed, (Widget,XtPointer,XtPointer));
+static void FDECL(get_gc, (Widget,struct mesg_info_t *));
+static void FDECL(mesg_resized, (Widget,XtPointer,XtPointer));
+
+static char mesg_translations[] =
+"#override\n\
+ <Key>:                input() \
+";
+
+/* Move the message window's vertical scrollbar's slider to the bottom. */
+void
+set_message_slider(wp)
+    struct xwindow *wp;
+{
+    Widget scrollbar;
+    float top;
+
+    scrollbar = XtNameToWidget(XtParent(wp->w), "vertical");
+
+    if (scrollbar) {
+       top = 1.0;
+       XtCallCallbacks(scrollbar, XtNjumpProc, &top);
+    }
+}
+
+
+void
+create_message_window(wp, create_popup, parent)
+    struct xwindow *wp;                        /* window pointer */
+    boolean create_popup;
+    Widget parent;
+{
+    Arg args[8];
+    Cardinal num_args;
+    Widget viewport;
+    struct mesg_info_t *mesg_info;
+
+    wp->type = NHW_MESSAGE;
+
+    wp->mesg_information = mesg_info =
+                   (struct mesg_info_t *) alloc(sizeof(struct mesg_info_t));
+
+    mesg_info->fs = 0;
+    mesg_info->num_lines = 0;
+    mesg_info->head = mesg_info->line_here = mesg_info->last_pause =
+                       mesg_info->last_pause_head = (struct line_element *) 0;
+    mesg_info->dirty = False;
+    mesg_info->viewport_width = mesg_info->viewport_height = 0;
+
+    if (iflags.msg_history < appResources.message_lines)
+       iflags.msg_history = appResources.message_lines;
+    if (iflags.msg_history > MAX_HISTORY)      /* a sanity check */
+       iflags.msg_history = MAX_HISTORY;
+
+    set_circle_buf(mesg_info, (int) iflags.msg_history);
+
+    /* Create a popup that becomes the parent. */
+    if (create_popup) {
+       num_args = 0;
+       XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
+
+       wp->popup = parent = XtCreatePopupShell("message_popup",
+                                       topLevelShellWidgetClass,
+                                       toplevel, args, num_args);
+       /*
+        * If we're here, then this is an auxiliary message window.  If we're
+        * cancelled via a delete window message, we should just pop down.
+        */
+    }
+
+    /*
+     * Create the viewport.  We only want the vertical scroll bar ever to be
+     * visible.  If we allow the horizontal scrollbar to be visible it will
+     * always be visible, due to the stupid way the Athena viewport operates.
+     */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNallowVert,  True);      num_args++;
+    viewport = XtCreateManagedWidget(
+                       "mesg_viewport",        /* name */
+                       viewportWidgetClass,    /* widget class from Window.h */
+                       parent,                 /* parent widget */
+                       args,                   /* set some values */
+                       num_args);              /* number of values to set */
+
+    /*
+     * Create a message window.  We will change the width and height once
+     * we know what font we are using.
+     */
+    num_args = 0;
+    if (!create_popup) {
+       XtSetArg(args[num_args], XtNtranslations,
+                XtParseTranslationTable(mesg_translations));   num_args++;
+    }
+    wp->w = XtCreateManagedWidget(
+               "message",              /* name */
+               windowWidgetClass,      /* widget class from Window.h */
+               viewport,               /* parent widget */
+               args,                   /* set some values */
+               num_args);              /* number of values to set */
+
+    XtAddCallback(wp->w, XtNexposeCallback, mesg_exposed, (XtPointer) 0);
+
+    /*
+     * Now adjust the height and width of the message window so that it
+     * is appResources.message_lines high and DEFAULT_MESSAGE_WIDTH wide.
+     */
+
+    /* Get the font information. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNfont, &mesg_info->fs);        num_args++;
+    XtGetValues(wp->w, args, num_args);
+
+    /* Save character information for fast use later. */
+    mesg_info->char_width    = mesg_info->fs->max_bounds.width;
+    mesg_info->char_height   = mesg_info->fs->max_bounds.ascent +
+                                           mesg_info->fs->max_bounds.descent;
+    mesg_info->char_ascent   = mesg_info->fs->max_bounds.ascent;
+    mesg_info->char_lbearing = -mesg_info->fs->min_bounds.lbearing;
+
+    get_gc(wp->w, mesg_info);
+
+    wp->pixel_height = ((int)iflags.msg_history) * mesg_info->char_height;
+
+    /* If a variable spaced font, only use 2/3 of the default size */
+    if (mesg_info->fs->min_bounds.width != mesg_info->fs->max_bounds.width) {
+       wp->pixel_width  = ((2*DEFAULT_MESSAGE_WIDTH)/3) *
+                                       mesg_info->fs->max_bounds.width;
+    } else
+       wp->pixel_width  = (DEFAULT_MESSAGE_WIDTH *
+                                       mesg_info->fs->max_bounds.width);
+
+    /* Set the new width and height. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNwidth,        wp->pixel_width);  num_args++;
+    XtSetArg(args[num_args], XtNheight,       wp->pixel_height); num_args++;
+    XtSetValues(wp->w, args, num_args);
+
+    /* make sure viewport height makes sense before realizing it */
+    num_args = 0;
+    mesg_info->viewport_height =
+       appResources.message_lines * mesg_info->char_height;
+    XtSetArg(args[num_args], XtNheight, mesg_info->viewport_height);num_args++;
+    XtSetValues(viewport, args, num_args);
+
+    XtAddCallback(wp->w, XtNresizeCallback, mesg_resized, (XtPointer) 0);
+
+    /*
+     * If we have created our own popup, then realize it so that the
+     * viewport is also realized.
+     */
+    if (create_popup) {
+       XtRealizeWidget(wp->popup);
+       XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup),
+                       &wm_delete_window, 1);
+    }
+}
+
+
+void
+destroy_message_window(wp)
+    struct xwindow *wp;
+{
+    if (wp->popup) {
+       nh_XtPopdown(wp->popup);
+       if (!wp->keep_window)
+           XtDestroyWidget(wp->popup),  wp->popup = (Widget)0;
+    }
+    if (wp->mesg_information) {
+       set_circle_buf(wp->mesg_information, 0);        /* free buffer list */
+       free((genericptr_t)wp->mesg_information),  wp->mesg_information = 0;
+    }
+    if (wp->keep_window)
+       XtRemoveCallback(wp->w, XtNexposeCallback, mesg_exposed, (XtPointer)0);
+    else
+       wp->type = NHW_NONE;
+}
+
+
+/* Redraw message window if new lines have been added. */
+void
+display_message_window(wp)
+    struct xwindow *wp;
+{
+    if (wp->mesg_information->dirty) redraw_message_window(wp);
+}
+
+
+/*
+ * Append a line of text to the message window.  Split the line if the
+ * rendering of the text is too long for the window.
+ */
+void
+append_message(wp, str)
+    struct xwindow *wp;
+    const char *str;
+{
+    char *mark, *remainder, buf[BUFSZ];
+
+    if (!str) return;
+
+    Strcpy(buf, str);  /* we might mark it up */
+
+    remainder = buf;
+    do {
+       mark = remainder;
+       remainder = split(mark, wp->mesg_information->fs, wp->pixel_width);
+       add_line(wp->mesg_information, mark);
+    } while (remainder);
+}
+
+/* private functions ======================================================= */
+
+/*
+ * Return the element in the circular linked list just before the given
+ * element.
+ */
+static struct line_element *
+get_previous(mark)
+    struct line_element *mark;
+{
+    struct line_element *curr;
+
+    if (!mark) return (struct line_element *) 0;
+
+    for (curr = mark; curr->next != mark; curr = curr->next)
+       ;
+    return curr;
+}
+
+
+/*
+ * Set the information buffer size to count lines.  We do this by creating
+ * a circular linked list of elements, each of which represents a line of
+ * text.  New buffers are created as needed, old ones are freed if they
+ * are no longer used.
+ */
+static void
+set_circle_buf(mesg_info, count)
+    struct mesg_info_t *mesg_info;
+    int count;
+{
+    int i;
+    struct line_element *tail, *curr, *head;
+
+    if (count < 0) panic("set_circle_buf: bad count [= %d]", count);
+    if (count == mesg_info->num_lines) return; /* no change in size */
+
+    if (count < mesg_info->num_lines) {
+       /*
+        * Toss num_lines - count line entries from our circular list.
+        *
+        * We lose lines from the front (top) of the list.  We _know_
+        * the list is non_empty.
+        */
+       tail = get_previous(mesg_info->head);
+       for (i = mesg_info->num_lines - count; i > 0; i--) {
+           curr = mesg_info->head;
+           mesg_info->head = curr->next;
+           if (curr->line) free((genericptr_t)curr->line);
+           free((genericptr_t)curr);
+       }
+       if (count == 0) {
+           /* make sure we don't have a dangling pointer */
+           mesg_info->head = (struct line_element *) 0;
+       } else {
+           tail->next = mesg_info->head;       /* link the tail to the head */
+       }
+    } else {
+       /*
+        * Add count - num_lines blank lines to the head of the list.
+        *
+        * Create a separate list, keeping track of the tail.
+        */
+       for (head = tail = 0, i = 0; i < count - mesg_info->num_lines; i++) {
+           curr = (struct line_element *) alloc(sizeof(struct line_element));
+           curr->line = 0;
+           curr->buf_length = 0;
+           curr->str_length = 0;
+           if (tail) {
+               tail->next = curr;
+               tail = curr;
+           } else {
+               head = tail = curr;
+           }
+       }
+       /*
+        * Complete the circle by making the new tail point to the old head
+        * and the old tail point to the new head.  If our line count was
+        * zero, then make the new list circular.
+        */
+       if (mesg_info->num_lines) {
+           curr = get_previous(mesg_info->head);/* get end of old list */
+
+           tail->next = mesg_info->head;       /* new tail -> old head */
+           curr->next = head;                  /* old tail -> new head */
+       } else {
+           tail->next = head;
+       }
+       mesg_info->head = head;
+    }
+
+    mesg_info->num_lines = count;
+    /* Erase the line on a resize. */
+    mesg_info->last_pause = (struct line_element *) 0;
+}
+
+
+/*
+ * Make sure the given string is shorter than the given pixel width.  If
+ * not, back up from the end by words until we find a place to split.
+ */
+static char *
+split(s, fs, pixel_width)
+    char *s;
+    XFontStruct *fs;           /* Font for the window. */
+    Dimension pixel_width;
+{
+    char save, *end, *remainder;
+
+    save = '\0';
+    remainder = 0;
+    end = eos(s);      /* point to null at end of string */
+
+    /* assume that if end == s, XXXXXX returns 0) */
+    while ((Dimension) XTextWidth(fs, s, (int) strlen(s)) > pixel_width) {
+       *end-- = save;
+       while (*end != ' ') {
+           if (end == s) panic("split: eos!");
+           --end;
+       }
+       save = *end;
+       *end = '\0';
+       remainder = end + 1;
+    }
+    return remainder;
+}
+
+/*
+ * Add a line of text to the window.  The first line in the curcular list
+ * becomes the last.  So all we have to do is copy the new line over the
+ * old one.  If the line buffer is too small, then allocate a new, larger
+ * one.
+ */
+static void
+add_line(mesg_info, s)
+    struct mesg_info_t *mesg_info;
+    const char *s;
+{
+    register struct line_element *curr = mesg_info->head;
+    register int new_line_length = strlen(s);
+
+    if (new_line_length + 1 > curr->buf_length) {
+       if (curr->line) free(curr->line);       /* free old line */
+
+       curr->buf_length = new_line_length + 1;
+       curr->line = (char *) alloc((unsigned)curr->buf_length);
+    }
+
+    Strcpy(curr->line, s);                     /* copy info */
+    curr->str_length = new_line_length;                /* save string length */
+
+    mesg_info->head = mesg_info->head->next;   /* move head to next line */
+    mesg_info->dirty = True;                   /* we have undrawn lines */
+}
+
+
+/*
+ * Save a position in the text buffer so we can draw a line to seperate
+ * text from the last time this function was called.
+ *
+ * Save the head position, since it is the line "after" the last displayed
+ * line in the message window.  The window redraw routine will draw a
+ * line above this saved pointer.
+ */
+void
+set_last_pause(wp)
+    struct xwindow *wp;
+{
+    register struct mesg_info_t *mesg_info = wp->mesg_information;
+
+#ifdef ERASE_LINE
+    /*
+     * If we've erased the pause line and haven't added any new lines,
+     * don't try to erase the line again.
+     */
+    if (!mesg_info->last_pause
+                           && mesg_info->last_pause_head == mesg_info->head)
+       return;
+
+    if (mesg_info->last_pause == mesg_info->head) {
+       /* No new messages in last turn.  Redraw window to erase line. */
+       mesg_info->last_pause = (struct line_element *) 0;
+       mesg_info->last_pause_head = mesg_info->head;
+       redraw_message_window(wp);
+    } else {
+#endif
+       mesg_info->last_pause = mesg_info->head;
+#ifdef ERASE_LINE
+    }
+#endif
+}
+
+
+static void
+redraw_message_window(wp)
+    struct xwindow *wp;
+{
+    struct mesg_info_t *mesg_info = wp->mesg_information;
+    register struct line_element *curr;
+    register int row, y_base;
+
+    /*
+     * Do this the cheap and easy way.  Clear the window and just redraw
+     * the whole thing.
+     *
+     * This could be done more effecently with one call to XDrawText() instead
+     * of many calls to XDrawString().  Maybe later.
+     *
+     * Only need to clear if window has new text.
+     */
+    if (mesg_info->dirty) {
+       XClearWindow(XtDisplay(wp->w), XtWindow(wp->w));
+       mesg_info->line_here = mesg_info->last_pause;
+    }
+
+    /* For now, just update the whole shootn' match. */
+    for (y_base = row = 0, curr = mesg_info->head;
+               row < mesg_info->num_lines;
+               row++, y_base += mesg_info->char_height, curr = curr->next) {
+
+       XDrawString(XtDisplay(wp->w), XtWindow(wp->w),
+               mesg_info->gc,
+               mesg_info->char_lbearing,
+               mesg_info->char_ascent + y_base,
+               curr->line,
+               curr->str_length);
+       /*
+        * This draws a line at the _top_ of the line of text pointed to by
+        * mesg_info->last_pause.
+        */
+       if (appResources.message_line && curr == mesg_info->line_here) {
+           XDrawLine(XtDisplay(wp->w), XtWindow(wp->w),
+               mesg_info->gc,
+               0, y_base, wp->pixel_width, y_base);
+       }
+    }
+
+    mesg_info->dirty = False;
+}
+
+
+/*
+ * Check the size of the viewport.  If it has shrunk, then we want to
+ * move the vertical slider to the bottom.
+ */
+static void
+mesg_check_size_change(wp)
+    struct xwindow *wp;
+{
+    struct mesg_info_t *mesg_info = wp->mesg_information;
+    Arg arg[2];
+    Dimension new_width, new_height;
+    Widget viewport;
+
+    viewport = XtParent(wp->w);
+
+    XtSetArg(arg[0], XtNwidth,  &new_width);
+    XtSetArg(arg[1], XtNheight, &new_height);
+    XtGetValues(viewport, arg, TWO);
+
+    /* Only move slider to bottom if new size is smaller. */
+    if (new_width < mesg_info->viewport_width
+                   || new_height < mesg_info->viewport_height) {
+       set_message_slider(wp);
+    }
+
+    mesg_info->viewport_width = new_width;
+    mesg_info->viewport_height = new_height;
+}
+
+
+/* Event handler for message window expose events. */
+/*ARGSUSED*/
+static void
+mesg_exposed(w, client_data, widget_data)
+    Widget w;
+    XtPointer client_data;     /* unused */
+    XtPointer widget_data;     /* expose event from Window widget */
+{
+    XExposeEvent *event = (XExposeEvent *) widget_data;
+
+    if (XtIsRealized(w) && event->count == 0) {
+       struct xwindow *wp;
+       Display *dpy;
+       Window   win;
+       XEvent   evt;
+
+       /*
+        * Drain all pending expose events for the message window;
+        * we'll redraw the whole thing at once.
+        */
+       dpy = XtDisplay(w);
+       win = XtWindow(w);
+       while (XCheckTypedWindowEvent(dpy, win, Expose, &evt)) continue;
+
+       wp = find_widget(w);
+       if (wp->keep_window && !wp->mesg_information) return;
+       mesg_check_size_change(wp);
+       redraw_message_window(wp);
+    }
+}
+
+
+static void
+get_gc(w, mesg_info)
+    Widget w;
+    struct mesg_info_t *mesg_info;
+{
+    XGCValues values;
+    XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont;
+    Pixel fgpixel, bgpixel;
+    Arg arg[2];
+
+    XtSetArg(arg[0], XtNforeground, &fgpixel);
+    XtSetArg(arg[1], XtNbackground, &bgpixel);
+    XtGetValues(w, arg, TWO);
+
+    values.foreground = fgpixel;
+    values.background = bgpixel;
+    values.function   = GXcopy;
+    values.font       = WindowFont(w);
+    mesg_info->gc = XtGetGC(w, mask, &values);
+}
+
+/*
+ * Handle resizes on a message window.  Correct saved pixel height and width.
+ * Adjust circle buffer to accomidate the new size.
+ *
+ * Problem:  If the resize decreases the width of the window such that
+ * some lines are now longer than the window, they will be cut off by
+ * X itself.  All new lines will be split to the new size, but the ends
+ * of the old ones will not be seen again unless the window is lengthened.
+ * I don't deal with this problem because it isn't worth the trouble.
+ */
+/* ARGSUSED */
+static void
+mesg_resized(w, client_data, call_data)
+    Widget w;
+    XtPointer call_data, client_data;
+{
+    Arg args[4];
+    Cardinal num_args;
+    Dimension pixel_width, pixel_height;
+    struct xwindow *wp;
+#ifdef VERBOSE
+    int old_lines;
+
+    old_lines = wp->mesg_information->num_lines;;
+#endif
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNwidth,  &pixel_width);   num_args++;
+    XtSetArg(args[num_args], XtNheight, &pixel_height);  num_args++;
+    XtGetValues(w, args, num_args);
+
+    wp = find_widget(w);
+    wp->pixel_width  = pixel_width;
+    wp->pixel_height = pixel_height;
+
+    set_circle_buf(wp->mesg_information,
+                       (int) pixel_height / wp->mesg_information->char_height);
+
+#ifdef VERBOSE
+    printf("Message resize.  Pixel: width = %d, height = %d;  Lines: old = %d, new = %d\n",
+       pixel_width,
+       pixel_height,
+       old_lines,
+       wp->mesg_information->num_lines);
+#endif
+}
+
+/*winmesg.c*/
diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c
new file mode 100644 (file)
index 0000000..4699c68
--- /dev/null
@@ -0,0 +1,928 @@
+/*     SCCS Id: @(#)winmisc.c  3.4     2000/05/21      */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Misc. popup windows: player selection and extended commands.
+ *
+ *     + Global functions: player_selection() and get_ext_cmd().
+ */
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/Cardinals.h>
+#include <X11/Xos.h>   /* for index() */
+#include <X11/Xatom.h>
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+#include "hack.h"
+#include "func_tab.h"
+#include "winX.h"
+
+
+static Widget extended_command_popup = 0;
+static Widget extended_command_form;
+static Widget *extended_commands = 0;
+static int extended_command_selected;  /* index of the selected command; */
+static int ps_selected;                        /* index of selected role */
+#define PS_RANDOM (-50)
+#define PS_QUIT   (-75)
+static const char ps_randchars[] = "*@";
+static const char ps_quitchars[] = "\033qQ";
+
+#define EC_NCHARS 32
+static boolean ec_active = FALSE;
+static int ec_nchars = 0;
+static char ec_chars[EC_NCHARS];
+static Time ec_time;
+
+static const char extended_command_translations[] =
+    "#override\n\
+     <Key>: ec_key()";
+
+static const char player_select_translations[] =
+    "#override\n\
+     <Key>: ps_key()";
+static const char race_select_translations[] =
+    "#override\n\
+     <Key>: race_key()";
+static const char gend_select_translations[] =
+    "#override\n\
+     <Key>: gend_key()";
+static const char algn_select_translations[] =
+    "#override\n\
+     <Key>: algn_key()";
+
+static void FDECL(popup_delete, (Widget, XEvent*, String*, Cardinal*));
+static void NDECL(ec_dismiss);
+static Widget FDECL(make_menu, (const char *,const char *,const char *,
+                               const char *,XtCallbackProc,
+                               const char *,XtCallbackProc,
+                               int,const char **, Widget **,
+                               XtCallbackProc,Widget *));
+static void NDECL(init_extended_commands_popup);
+static void FDECL(ps_quit, (Widget,XtPointer,XtPointer));
+static void FDECL(ps_random, (Widget,XtPointer,XtPointer));
+static void FDECL(ps_select, (Widget,XtPointer,XtPointer));
+
+
+/* Player Selection -------------------------------------------------------- */
+/* ARGSUSED */
+static void
+ps_quit(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data, call_data;
+{
+    ps_selected = PS_QUIT;
+    exit_x_event = TRUE;               /* leave event loop */
+}
+
+/* ARGSUSED */
+static void
+ps_random(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data, call_data;
+{
+    ps_selected = PS_RANDOM;
+    exit_x_event = TRUE;               /* leave event loop */
+}
+
+/* ARGSUSED */
+static void
+ps_select(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data, call_data;
+{
+    ps_selected = (int) client_data;
+    exit_x_event = TRUE;               /* leave event loop */
+}
+
+/* ARGSUSED */
+void
+ps_key(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    char ch, *mark;
+    char rolechars[QBUFSZ];
+    int i;
+
+    (void)memset(rolechars, '\0', sizeof rolechars);  /* for index() */
+    for (i = 0; roles[i].name.m; ++i) {
+       ch = lowc(*roles[i].name.m);
+     /* if (flags.female && roles[i].name.f) ch = lowc(*roles[i].name.f); */
+       /* this supports at most two roles with the same first letter */
+       if (index(rolechars, ch)) ch = highc(ch);
+       rolechars[i] = ch;
+    }
+    ch = key_event_to_char((XKeyEvent *) event);
+    if (ch == '\0') {  /* don't accept nul char/modifier event */
+       /* don't beep */
+       return;
+    }
+    mark = index(rolechars, ch);
+    if (!mark) mark = index(rolechars, lowc(ch));
+    if (!mark) mark = index(rolechars, highc(ch));
+    if (!mark) {
+       if (index(ps_randchars, ch))
+           ps_selected = PS_RANDOM;
+       else if (index(ps_quitchars, ch))
+           ps_selected = PS_QUIT;
+       else {
+           X11_nhbell();       /* no such class */
+           return;
+       }
+    } else
+       ps_selected = (int)(mark - rolechars);
+    exit_x_event = TRUE;
+}
+
+/* ARGSUSED */
+void
+race_key(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    char ch, *mark;
+    char racechars[QBUFSZ];
+    int i;
+
+    (void)memset(racechars, '\0', sizeof racechars);  /* for index() */
+    for (i = 0; races[i].noun; ++i) {
+       ch = lowc(*races[i].noun);
+       /* this supports at most two races with the same first letter */
+       if (index(racechars, ch)) ch = highc(ch);
+       racechars[i] = ch;
+    }
+    ch = key_event_to_char((XKeyEvent *) event);
+    if (ch == '\0') {  /* don't accept nul char/modifier event */
+       /* don't beep */
+       return;
+    }
+    mark = index(racechars, ch);
+    if (!mark) mark = index(racechars, lowc(ch));
+    if (!mark) mark = index(racechars, highc(ch));
+    if (!mark) {
+       if (index(ps_randchars, ch))
+           ps_selected = PS_RANDOM;
+       else if (index(ps_quitchars, ch))
+           ps_selected = PS_QUIT;
+       else {
+           X11_nhbell();       /* no such race */
+           return;
+       }
+    } else
+       ps_selected = (int)(mark - racechars);
+    exit_x_event = TRUE;
+}
+
+/* ARGSUSED */
+void
+gend_key(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    char ch, *mark;
+    static char gendchars[] = "mf";
+
+    ch = key_event_to_char((XKeyEvent *) event);
+    if (ch == '\0') {  /* don't accept nul char/modifier event */
+       /* don't beep */
+       return;
+    }
+    mark = index(gendchars, ch);
+    if (!mark) mark = index(gendchars, lowc(ch));
+    if (!mark) {
+       if (index(ps_randchars, ch))
+           ps_selected = PS_RANDOM;
+       else if (index(ps_quitchars, ch))
+           ps_selected = PS_QUIT;
+       else {
+           X11_nhbell();       /* no such gender */
+           return;
+       }
+    } else
+       ps_selected = (int)(mark - gendchars);
+    exit_x_event = TRUE;
+}
+
+/* ARGSUSED */
+void
+algn_key(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    char ch, *mark;
+    static char algnchars[] = "LNC";
+
+    ch = key_event_to_char((XKeyEvent *) event);
+    if (ch == '\0') {  /* don't accept nul char/modifier event */
+       /* don't beep */
+       return;
+    }
+    mark = index(algnchars, ch);
+    if (!mark) mark = index(algnchars, highc(ch));
+    if (!mark) {
+       if (index(ps_randchars, ch))
+           ps_selected = PS_RANDOM;
+       else if (index(ps_quitchars, ch))
+           ps_selected = PS_QUIT;
+       else {
+           X11_nhbell();       /* no such alignment */
+           return;
+       }
+    } else
+       ps_selected = (int)(mark - algnchars);
+    exit_x_event = TRUE;
+}
+
+/* Global functions ========================================================= */
+void
+X11_player_selection()
+{
+    int num_roles, num_races, num_gends, num_algns,
+       i, availcount, availindex;
+    Widget popup, player_form;
+    const char **choices;
+    char qbuf[QBUFSZ], plbuf[QBUFSZ];
+
+    /* avoid unnecessary prompts further down */
+    rigid_role_checks();
+
+    (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+
+    while (flags.initrole < 0) {
+       if (flags.initrole == ROLE_RANDOM || flags.randomall) {
+           flags.initrole = pick_role(flags.initrace,
+                                      flags.initgend, flags.initalign, PICK_RANDOM);
+           break;
+       }
+
+       /* select a role */
+       for (num_roles = 0; roles[num_roles].name.m; ++num_roles) continue;
+       choices = (const char **)alloc(sizeof(char *) * num_roles);
+       for (;;) {
+           availcount = 0;
+           for (i = 0; i < num_roles; i++) {
+               choices[i] = 0;
+               if (ok_role(i, flags.initrace,
+                           flags.initgend, flags.initalign)) {
+                   choices[i] = roles[i].name.m;
+                   if (flags.initgend >= 0 && flags.female && roles[i].name.f)
+                       choices[i] = roles[i].name.f;
+                   ++availcount;
+               }
+           }
+           if (availcount > 0) break;
+           else if (flags.initalign >= 0) flags.initalign = -1;    /* reset */
+           else if (flags.initgend >= 0) flags.initgend = -1;
+           else if (flags.initrace >= 0) flags.initrace = -1;
+           else panic("no available ROLE+race+gender+alignment combinations");
+       }
+       Sprintf(qbuf, "Choose your %s Role", s_suffix(plbuf));
+       popup = make_menu("player_selection", qbuf,
+                   player_select_translations,
+                   "quit", ps_quit,
+                   "random", ps_random,
+                   num_roles, choices, (Widget **)0, ps_select, &player_form);
+
+       ps_selected = -1;
+       positionpopup(popup, FALSE);
+       nh_XtPopup(popup, (int)XtGrabExclusive, player_form);
+
+       /* The callbacks will enable the event loop exit. */
+       (void) x_event(EXIT_ON_EXIT);
+
+       nh_XtPopdown(popup);
+       XtDestroyWidget(popup);
+       free((genericptr_t)choices), choices = 0;
+
+       if (ps_selected == PS_QUIT) {
+           clearlocks();
+           X11_exit_nhwindows((char *)0);
+           terminate(0);
+       } else if (ps_selected == PS_RANDOM) {
+           flags.initrole = ROLE_RANDOM;
+       } else if (ps_selected < 0 || ps_selected >= num_roles) {
+           panic("player_selection: bad role select value %d", ps_selected);
+       } else {
+           flags.initrole = ps_selected;
+       }
+    }
+
+    (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+
+    while (!validrace(flags.initrole, flags.initrace)) {
+       if (flags.initrace == ROLE_RANDOM || flags.randomall) {
+           flags.initrace = pick_race(flags.initrole,
+                                      flags.initgend, flags.initalign, PICK_RANDOM);
+           break;
+       }
+       /* select a race */
+       for (num_races = 0; races[num_races].noun; ++num_races) continue;
+       choices = (const char **)alloc(sizeof(char *) * num_races);
+       for (;;) {
+           availcount = availindex = 0;
+           for (i = 0; i < num_races; i++) {
+               choices[i] = 0;
+               if (ok_race(flags.initrole, i,
+                           flags.initgend, flags.initalign)) {
+                   choices[i] = races[i].noun;
+                   ++availcount;
+                   availindex = i;     /* used iff only one */
+               }
+           }
+           if (availcount > 0) break;
+           else if (flags.initalign >= 0) flags.initalign = -1;    /* reset */
+           else if (flags.initgend >= 0) flags.initgend = -1;
+           else panic("no available role+RACE+gender+alignment combinations");
+       }
+
+       if (availcount == 1) {
+           flags.initrace = availindex;
+           free((genericptr_t)choices), choices = 0;
+       } else {
+           Sprintf(qbuf, "Pick your %s race", s_suffix(plbuf));
+           popup = make_menu("race_selection", qbuf,
+                       race_select_translations,
+                       "quit", ps_quit,
+                       "random", ps_random,
+                       num_races, choices, (Widget **)0,
+                       ps_select, &player_form);
+
+           ps_selected = -1;
+           positionpopup(popup, FALSE);
+           nh_XtPopup(popup, (int)XtGrabExclusive, player_form);
+
+           /* The callbacks will enable the event loop exit. */
+           (void) x_event(EXIT_ON_EXIT);
+
+           nh_XtPopdown(popup);
+           XtDestroyWidget(popup);
+           free((genericptr_t)choices), choices = 0;
+
+           if (ps_selected == PS_QUIT) {
+               clearlocks();
+               X11_exit_nhwindows((char *)0);
+               terminate(0);
+           } else if (ps_selected == PS_RANDOM) {
+               flags.initrace = ROLE_RANDOM;
+           } else if (ps_selected < 0 || ps_selected >= num_races) {
+               panic("player_selection: bad race select value %d", ps_selected);
+           } else {
+               flags.initrace = ps_selected;
+           }
+       } /* more than one race choice available */
+    }
+
+    (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+
+    while (!validgend(flags.initrole, flags.initrace, flags.initgend)) {
+       if (flags.initgend == ROLE_RANDOM || flags.randomall) {
+           flags.initgend = pick_gend(flags.initrole, flags.initrace,
+                                      flags.initalign, PICK_RANDOM);
+           break;
+       }
+       /* select a gender */
+       num_gends = 2;          /* genders[2] isn't allowed */
+       choices = (const char **)alloc(sizeof(char *) * num_gends);
+       for (;;) {
+           availcount = availindex = 0;
+           for (i = 0; i < num_gends; i++) {
+               choices[i] = 0;
+               if (ok_gend(flags.initrole, flags.initrace,
+                           i, flags.initalign)) {
+                   choices[i] = genders[i].adj;
+                   ++availcount;
+                   availindex = i;     /* used iff only one */
+               }
+           }
+           if (availcount > 0) break;
+           else if (flags.initalign >= 0) flags.initalign = -1;    /* reset */
+           else panic("no available role+race+GENDER+alignment combinations");
+       }
+
+       if (availcount == 1) {
+           flags.initgend = availindex;
+           free((genericptr_t)choices), choices = 0;
+       } else {
+           Sprintf(qbuf, "Your %s gender?", s_suffix(plbuf));
+           popup = make_menu("gender_selection", qbuf,
+                       gend_select_translations,
+                       "quit", ps_quit,
+                       "random", ps_random,
+                       num_gends, choices, (Widget **)0,
+                       ps_select, &player_form);
+
+           ps_selected = -1;
+           positionpopup(popup, FALSE);
+           nh_XtPopup(popup, (int)XtGrabExclusive, player_form);
+
+           /* The callbacks will enable the event loop exit. */
+           (void) x_event(EXIT_ON_EXIT);
+
+           nh_XtPopdown(popup);
+           XtDestroyWidget(popup);
+           free((genericptr_t)choices), choices = 0;
+
+           if (ps_selected == PS_QUIT) {
+               clearlocks();
+               X11_exit_nhwindows((char *)0);
+               terminate(0);
+           } else if (ps_selected == PS_RANDOM) {
+               flags.initgend = ROLE_RANDOM;
+           } else if (ps_selected < 0 || ps_selected >= num_gends) {
+               panic("player_selection: bad gender select value %d", ps_selected);
+           } else {
+               flags.initgend = ps_selected;
+           }
+       } /* more than one gender choice available */
+    }
+
+    (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+
+    while (!validalign(flags.initrole, flags.initrace, flags.initalign)) {
+       if (flags.initalign == ROLE_RANDOM || flags.randomall) {
+           flags.initalign = pick_align(flags.initrole, flags.initrace,
+                                        flags.initgend, PICK_RANDOM);
+           break;
+       }
+       /* select an alignment */
+       num_algns = 3;          /* aligns[3] isn't allowed */
+       choices = (const char **)alloc(sizeof(char *) * num_algns);
+       for (;;) {
+           availcount = availindex = 0;
+           for (i = 0; i < num_algns; i++) {
+               choices[i] = 0;
+               if (ok_align(flags.initrole, flags.initrace,
+                            flags.initgend, i)) {
+                   choices[i] = aligns[i].adj;
+                   ++availcount;
+                   availindex = i;     /* used iff only one */
+               }
+           }
+           if (availcount > 0) break;
+           else panic("no available role+race+gender+ALIGNMENT combinations");
+       }
+
+       if (availcount == 1) {
+           flags.initalign = availindex;
+           free((genericptr_t)choices), choices = 0;
+       } else {
+           Sprintf(qbuf, "Your %s alignment?", s_suffix(plbuf));
+           popup = make_menu("alignment_selection", qbuf,
+                       algn_select_translations,
+                       "quit", ps_quit,
+                       "random", ps_random,
+                       num_algns, choices, (Widget **)0,
+                       ps_select, &player_form);
+
+           ps_selected = -1;
+           positionpopup(popup, FALSE);
+           nh_XtPopup(popup, (int)XtGrabExclusive, player_form);
+
+           /* The callbacks will enable the event loop exit. */
+           (void) x_event(EXIT_ON_EXIT);
+
+           nh_XtPopdown(popup);
+           XtDestroyWidget(popup);
+           free((genericptr_t)choices), choices = 0;
+
+           if (ps_selected == PS_QUIT) {
+               clearlocks();
+               X11_exit_nhwindows((char *)0);
+               terminate(0);
+           } else if (ps_selected == PS_RANDOM) {
+               flags.initalign = ROLE_RANDOM;
+           } else if (ps_selected < 0 || ps_selected >= num_algns) {
+               panic("player_selection: bad alignment select value %d", ps_selected);
+           } else {
+               flags.initalign = ps_selected;
+           }
+       } /* more than one alignment choice available */
+    }
+}
+
+
+int
+X11_get_ext_cmd()
+{
+    static Boolean initialized = False;
+
+    if (!initialized) {
+       init_extended_commands_popup();
+       initialized = True;
+    }
+
+    extended_command_selected = -1;            /* reset selected value */
+
+    positionpopup(extended_command_popup, FALSE); /* center on cursor */
+    nh_XtPopup(extended_command_popup, (int)XtGrabExclusive,
+                                       extended_command_form);
+
+    /* The callbacks will enable the event loop exit. */
+    (void) x_event(EXIT_ON_EXIT);
+
+    return extended_command_selected;
+}
+
+/* End global functions ===================================================== */
+
+/* Extended Command -------------------------------------------------------- */
+/* ARGSUSED */
+static void
+extend_select(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data, call_data;
+{
+    int selected = (int) client_data;
+
+    if (extended_command_selected != selected) {
+       /* visibly deselect old one */
+       if (extended_command_selected >= 0)
+           swap_fg_bg(extended_commands[extended_command_selected]);
+
+       /* select new one */
+       swap_fg_bg(extended_commands[selected]);
+       extended_command_selected = selected;
+    }
+
+    nh_XtPopdown(extended_command_popup);
+    /* reset colors while popped down */
+    swap_fg_bg(extended_commands[extended_command_selected]);
+    ec_active = FALSE;
+    exit_x_event = TRUE;               /* leave event loop */
+}
+
+/* ARGSUSED */
+static void
+extend_dismiss(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data, call_data;
+{
+    ec_dismiss();
+}
+
+/* ARGSUSED */
+static void
+extend_help(w, client_data, call_data)
+    Widget w;
+    XtPointer client_data, call_data;
+{
+    /* We might need to make it known that we already have one listed. */
+    (void) doextlist();
+}
+
+/* ARGSUSED */
+void
+ec_delete(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    if (w == extended_command_popup) {
+       ec_dismiss();
+    } else {
+       popup_delete(w, event, params, num_params);
+    }
+}
+
+/* ARGSUSED */
+static void
+popup_delete(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    ps_selected = PS_QUIT;
+    nh_XtPopdown(w);
+    exit_x_event = TRUE;               /* leave event loop */
+}
+
+static void
+ec_dismiss()
+{
+    /* unselect while still visible */
+    if (extended_command_selected >= 0)
+       swap_fg_bg(extended_commands[extended_command_selected]);
+    extended_command_selected = -1;    /* dismiss */
+    nh_XtPopdown(extended_command_popup);
+    ec_active = FALSE;
+    exit_x_event = TRUE;               /* leave event loop */
+}
+
+/* ARGSUSED */
+void
+ec_key(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    char ch;
+    int i;
+    XKeyEvent *xkey = (XKeyEvent *) event;
+
+    ch = key_event_to_char(xkey);
+
+    if (ch == '\0') {  /* don't accept nul char/modifier event */
+       /* don't beep */
+       return;
+    } else if (index("\033\n\r", ch)) {
+       if (ch == '\033') {
+           /* unselect while still visible */
+           if (extended_command_selected >= 0)
+               swap_fg_bg(extended_commands[extended_command_selected]);
+           extended_command_selected = -1;     /* dismiss */
+       }
+
+       nh_XtPopdown(extended_command_popup);
+       /* unselect while invisible */
+       if (extended_command_selected >= 0)
+           swap_fg_bg(extended_commands[extended_command_selected]);
+
+       exit_x_event = TRUE;            /* leave event loop */
+       ec_active = FALSE;
+       return;
+    }
+
+    /* too much time has elapsed */
+    if ((xkey->time - ec_time) > 500)
+       ec_active = FALSE;
+
+    if (!ec_active) {
+       ec_nchars = 0;
+       ec_active = TRUE;
+    }
+
+    ec_time = xkey->time;
+    ec_chars[ec_nchars++] = ch;
+    if (ec_nchars >= EC_NCHARS)
+       ec_nchars = EC_NCHARS-1;        /* don't overflow */
+
+    for (i = 0; extcmdlist[i].ef_txt; i++) {
+       if (extcmdlist[i].ef_txt[0] == '?') continue;
+
+       if (!strncmp(ec_chars, extcmdlist[i].ef_txt, ec_nchars)) {
+           if (extended_command_selected != i) {
+               /* I should use set() and unset() actions, but how do */
+               /* I send the an action to the widget? */
+               if (extended_command_selected >= 0)
+                   swap_fg_bg(extended_commands[extended_command_selected]);
+               extended_command_selected = i;
+               swap_fg_bg(extended_commands[extended_command_selected]);
+           }
+           break;
+       }
+    }
+}
+
+/*
+ * Use our own home-brewed version menu because simpleMenu is designed to
+ * be used from a menubox.
+ */
+static void
+init_extended_commands_popup()
+{
+    int i, num_commands;
+    const char **command_list;
+
+    /* count commands */
+    for (num_commands = 0; extcmdlist[num_commands].ef_txt; num_commands++)
+       ;       /* do nothing */
+
+    /* If the last entry is "help", don't use it. */
+    if (strcmp(extcmdlist[num_commands-1].ef_txt, "?") == 0)
+       --num_commands;
+
+    command_list =
+               (const char **) alloc((unsigned)num_commands * sizeof(char *));
+
+    for (i = 0; i < num_commands; i++)
+       command_list[i] = extcmdlist[i].ef_txt;
+
+    extended_command_popup = make_menu("extended_commands",
+                               "Extended Commands",
+                               extended_command_translations,
+                               "dismiss", extend_dismiss,
+                               "help", extend_help,
+                               num_commands, command_list, &extended_commands,
+                               extend_select, &extended_command_form);
+
+    free((char *)command_list);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Create a popup widget of the following form:
+ *
+ *                   popup_label
+ *             ----------- ------------
+ *             |left_name| |right_name|
+ *             ----------- ------------
+ *             ------------------------
+ *             |       name1          |
+ *             ------------------------
+ *             ------------------------
+ *             |       name2          |
+ *             ------------------------
+ *                       .
+ *                       .
+ *             ------------------------
+ *             |       nameN          |
+ *             ------------------------
+ */
+static Widget
+make_menu(popup_name, popup_label, popup_translations,
+               left_name, left_callback,
+               right_name, right_callback,
+               num_names, widget_names, command_widgets, name_callback, formp)
+    const char    *popup_name;
+    const char    *popup_label;
+    const char    *popup_translations;
+    const char    *left_name;
+    XtCallbackProc left_callback;
+    const char    *right_name;
+    XtCallbackProc right_callback;
+    int                   num_names;
+    const char    **widget_names;      /* return array of command widgets */
+    Widget        **command_widgets;
+    XtCallbackProc name_callback;
+    Widget        *formp;      /* return */
+{
+    Widget popup, form, label, above, left, right;
+    Widget *commands, *curr;
+    int i;
+    Arg args[8];
+    Cardinal num_args;
+    Dimension width, max_width;
+    int distance, skip;
+
+
+    commands = (Widget *) alloc((unsigned)num_names * sizeof(Widget));
+
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNallowShellResize, True);       num_args++;
+
+    popup = XtCreatePopupShell(popup_name,
+                               transientShellWidgetClass,
+                               toplevel, args, num_args);
+    XtOverrideTranslations(popup,
+       XtParseTranslationTable("<Message>WM_PROTOCOLS: ec_delete()"));
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNtranslations,
+               XtParseTranslationTable(popup_translations));   num_args++;
+    *formp = form = XtCreateManagedWidget("menuform",
+                               formWidgetClass,
+                               popup,
+                               args, num_args);
+
+    /* Get the default distance between objects in the form widget. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNdefaultDistance, &distance);   num_args++;
+    XtGetValues(form, args, num_args);
+
+    /*
+     * Create the label.
+     */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNborderWidth, 0);       num_args++;
+    label = XtCreateManagedWidget(popup_label,
+                               labelWidgetClass,
+                               form,
+                               args, num_args);
+
+    /*
+     * Create the left button.
+     */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNfromVert, label);              num_args++;
+/*
+    XtSetArg(args[num_args], XtNshapeStyle,
+                               XmuShapeRoundedRectangle);      num_args++;
+*/
+    left = XtCreateManagedWidget(left_name,
+                   commandWidgetClass,
+                   form,
+                   args, num_args);
+    XtAddCallback(left, XtNcallback, left_callback, (XtPointer) 0);
+    skip = 3*distance; /* triple the spacing */
+    if(!skip) skip = 3;
+
+    /*
+     * Create right button.
+     */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNfromHoriz, left);              num_args++;
+    XtSetArg(args[num_args], XtNfromVert, label);              num_args++;
+/*
+    XtSetArg(args[num_args], XtNshapeStyle,
+                               XmuShapeRoundedRectangle);      num_args++;
+*/
+    right = XtCreateManagedWidget(right_name,
+                   commandWidgetClass,
+                   form,
+                   args, num_args);
+    XtAddCallback(right, XtNcallback, right_callback, (XtPointer) 0);
+
+    XtInstallAccelerators(form, left);
+    XtInstallAccelerators(form, right);
+
+    /*
+     * Create and place the command widgets.
+     */
+    for (i = 0, above = left, curr = commands; i < num_names; i++) {
+       if (!widget_names[i]) continue;
+       num_args = 0;
+       XtSetArg(args[num_args], XtNfromVert, above);   num_args++;
+       if (above == left) {
+           /* if first, we are farther apart */
+           XtSetArg(args[num_args], XtNvertDistance, skip);    num_args++;
+       }
+
+       *curr = XtCreateManagedWidget(widget_names[i],
+                   commandWidgetClass,
+                   form,
+                   args, num_args);
+       XtAddCallback(*curr, XtNcallback, name_callback, (XtPointer) i);
+       above = *curr++;
+    }
+
+    /*
+     * Now find the largest width.  Start with the width dismiss + help
+     * buttons, since they are adjacent.
+     */
+    XtSetArg(args[0], XtNwidth, &max_width);
+    XtGetValues(left, args, ONE);
+    XtSetArg(args[0], XtNwidth, &width);
+    XtGetValues(right, args, ONE);
+    max_width = max_width + width + distance;
+
+    /* Next, the title. */
+    XtSetArg(args[0], XtNwidth, &width);
+    XtGetValues(label, args, ONE);
+    if (width > max_width) max_width = width;
+
+    /* Finally, the commands. */
+    for (i = 0, curr = commands; i < num_names; i++) {
+       if (!widget_names[i]) continue;
+       XtSetArg(args[0], XtNwidth, &width);
+       XtGetValues(*curr, args, ONE);
+       if (width > max_width) max_width = width;
+       curr++;
+    }
+
+    /*
+     * Finally, set all of the single line widgets to the largest width.
+     */
+    XtSetArg(args[0], XtNwidth, max_width);
+    XtSetValues(label, args, ONE);
+
+    for (i = 0, curr = commands; i < num_names; i++) {
+       if (!widget_names[i]) continue;
+       XtSetArg(args[0], XtNwidth, max_width);
+       XtSetValues(*curr, args, ONE);
+       curr++;
+    }
+
+    if (command_widgets)
+       *command_widgets = commands;
+    else
+       free((char *) commands);
+
+    XtRealizeWidget(popup);
+    XSetWMProtocols(XtDisplay(popup), XtWindow(popup), &wm_delete_window, 1);
+
+    return popup;
+}
diff --git a/win/X11/winstat.c b/win/X11/winstat.c
new file mode 100644 (file)
index 0000000..d9bd7ad
--- /dev/null
@@ -0,0 +1,991 @@
+/*     SCCS Id: @(#)winstat.c  3.4     1996/04/05      */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Status window routines.  This file supports both the "traditional"
+ * tty status display and a "fancy" status display.  A tty status is
+ * made if a popup window is requested, otherewise a fancy status is
+ * made.  This code assumes that only one fancy status will ever be made.
+ * Currently, only one status window (of any type) is _ever_ made.
+ */
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Cardinals.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Paned.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xatom.h>
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+#include "hack.h"
+#include "winX.h"
+
+extern const char *hu_stat[]; /* from eat.c */
+extern const char *enc_stat[]; /* from botl.c */
+
+static void FDECL(update_fancy_status, (struct xwindow *));
+static Widget FDECL(create_fancy_status, (Widget,Widget));
+static void FDECL(destroy_fancy_status, (struct xwindow *));
+
+void
+create_status_window(wp, create_popup, parent)
+    struct xwindow *wp;                        /* window pointer */
+    boolean create_popup;
+    Widget parent;
+{
+    XFontStruct *fs;
+    Arg args[8];
+    Cardinal num_args;
+    Position top_margin, bottom_margin, left_margin, right_margin;
+
+    wp->type = NHW_STATUS;
+
+    if (!create_popup) {
+       /*
+        * If we are not creating a popup, then we must be the "main" status
+        * window.
+        */
+       if (!parent)
+           panic("create_status_window: no parent for fancy status");
+       wp->status_information = 0;
+       wp->w = create_fancy_status(parent, (Widget) 0);
+       return;
+    }
+
+    wp->status_information =
+               (struct status_info_t *) alloc(sizeof(struct status_info_t));
+
+    init_text_buffer(&wp->status_information->text);
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNallowShellResize, False); num_args++;
+    XtSetArg(args[num_args], XtNinput, False);            num_args++;
+
+    wp->popup = parent = XtCreatePopupShell("status_popup",
+                                       topLevelShellWidgetClass,
+                                       toplevel, args, num_args);
+    /*
+     * If we're here, then this is an auxiliary status window.  If we're
+     * cancelled via a delete window message, we should just pop down.
+     */
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNdisplayCaret, False); num_args++;
+    XtSetArg(args[num_args], XtNscrollHorizontal,
+                                   XawtextScrollWhenNeeded);   num_args++;
+    XtSetArg(args[num_args], XtNscrollVertical,
+                                   XawtextScrollWhenNeeded);   num_args++;
+
+    wp->w = XtCreateManagedWidget(
+               "status",               /* name */
+               asciiTextWidgetClass,
+               parent,                 /* parent widget */
+               args,                   /* set some values */
+               num_args);              /* number of values to set */
+
+    /*
+     * Adjust the height and width of the message window so that it
+     * is two lines high and COLNO of the widest characters wide.
+     */
+
+    /* Get the font and margin information. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNfont,        &fs);            num_args++;
+    XtSetArg(args[num_args], XtNtopMargin,    &top_margin);    num_args++;
+    XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++;
+    XtSetArg(args[num_args], XtNleftMargin,   &left_margin);   num_args++;
+    XtSetArg(args[num_args], XtNrightMargin,  &right_margin);  num_args++;
+    XtGetValues(wp->w, args, num_args);
+
+    wp->pixel_height = 2 * nhFontHeight(wp->w) + top_margin + bottom_margin;
+    wp->pixel_width  = COLNO * fs->max_bounds.width +
+                                               left_margin + right_margin;
+
+    /* Set the new width and height. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNwidth,  wp->pixel_width);  num_args++;
+    XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++;
+    XtSetValues(wp->w, args, num_args);
+}
+
+void
+destroy_status_window(wp)
+    struct xwindow *wp;
+{
+    /* If status_information is defined, then it a "text" status window. */
+    if (wp->status_information) {
+       if (wp->popup) {
+           nh_XtPopdown(wp->popup);
+           if (!wp->keep_window)
+               XtDestroyWidget(wp->popup),  wp->popup = (Widget)0;
+       }
+       free((genericptr_t)wp->status_information);
+       wp->status_information = 0;
+    } else {
+       destroy_fancy_status(wp);
+    }
+    if (!wp->keep_window)
+       wp->type = NHW_NONE;
+}
+
+
+/*
+ * This assumes several things:
+ *     + Status has only 2 lines
+ *     + That both lines are updated in succession in line order.
+ *     + We didn't set stringInPlace on the widget.
+ */
+void
+adjust_status(wp, str)
+    struct xwindow *wp;
+    const char *str;
+{
+    Arg args[2];
+    Cardinal num_args;
+
+    if (!wp->status_information) {
+       update_fancy_status(wp);
+       return;
+    }
+
+    if (wp->cursy == 0) {
+       clear_text_buffer(&wp->status_information->text);
+       append_text_buffer(&wp->status_information->text, str, FALSE);
+       return;
+    }
+    append_text_buffer(&wp->status_information->text, str, FALSE);
+
+    /* Set new buffer as text. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNstring, wp->status_information->text.text);
+                                                                   num_args++;
+    XtSetValues(wp->w, args, num_args);
+}
+
+
+/* Fancy Status -------------------------------------------------------------*/
+static int hilight_time = 1;   /* number of turns to hilight a changed value */
+
+struct X_status_value {
+    char    *name;             /* text name */
+    int     type;              /* status type */
+    Widget  w;                 /* widget of name/value pair */
+    long    last_value;                /* value displayed */
+    int            turn_count;         /* last time the value changed */
+    boolean set;               /* if hilighed */
+    boolean after_init;                /* don't hilight on first change (init) */
+};
+
+/* valid type values */
+#define SV_VALUE 0     /* displays a label:value pair */
+#define SV_LABEL 1     /* displays a changable label */
+#define SV_NAME  2     /* displays an unchangeable name */
+
+static void FDECL(hilight_label, (Widget));
+static void FDECL(update_val, (struct X_status_value *,long));
+static const char *FDECL(width_string, (int));
+static void FDECL(create_widget, (Widget,struct X_status_value *,int));
+static void FDECL(get_widths, (struct X_status_value *,int *,int *));
+static void FDECL(set_widths, (struct X_status_value *,int,int));
+static Widget FDECL(init_column, (char *,Widget,Widget,Widget,int *));
+static Widget FDECL(init_info_form, (Widget,Widget,Widget));
+
+/*
+ * Form entry storage indices.
+ */
+#define F_STR      0
+#define F_DEX      1
+#define F_CON      2
+#define F_INT      3
+#define F_WIS      4
+#define F_CHA      5
+
+#define F_NAME      6
+#define F_DLEVEL    7
+#define F_GOLD      8
+#define F_HP        9
+#define F_MAXHP           10
+#define F_POWER    11
+#define F_MAXPOWER 12
+#define F_AC      13
+#define F_LEVEL    14
+#define F_EXP      15
+#define F_ALIGN           16
+#define F_TIME     17
+#define F_SCORE           18
+
+#define F_HUNGER   19
+#define F_CONFUSED 20
+#define F_SICK    21
+#define F_BLIND           22
+#define F_STUNNED  23
+#define F_HALLU    24
+#define F_ENCUMBER 25
+
+#define NUM_STATS  26
+
+/*
+ * Notes:
+ * + Alignment needs a different init value, because -1 is an alignment.
+ * + Armor Class is an schar, so 256 is out of range.
+ * + Blank value is 0 and should never change.
+ */
+static struct X_status_value shown_stats[NUM_STATS] = {
+    { "Strength",      SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /* 0*/
+    { "Dexterity",     SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Constitution",  SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Intelligence",  SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Wisdom",                SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Charisma",      SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /* 5*/
+
+    { "",              SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* name */
+    { "",              SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* dlvl */
+    { "Gold",          SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Hit Points",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Max HP",                SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /*10*/
+    { "Power",         SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Max Power",     SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Armor Class",   SV_VALUE, (Widget) 0,256, 0, FALSE, FALSE },
+    { "Level",         SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Experience",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /*15*/
+    { "Alignment",     SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE },
+    { "Time",          SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Score",         SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+
+    { "",              SV_NAME,  (Widget) 0, -1, 0, FALSE, TRUE }, /* hunger*/
+    { "Confused",      SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },     /*20*/
+    { "",              SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE }, /* sick */
+    { "Blind",         SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },
+    { "Stunned",       SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },
+    { "Hallucinating", SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },
+    { "",              SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE }, /*encumbr*/
+};
+
+
+/*
+ * Set all widget values to a null string.  This is used after all spacings
+ * have been calculated so that when the window is popped up we don't get all
+ * kinds of funny values being displayed.
+ */
+void
+null_out_status()
+{
+    int i;
+    struct X_status_value *sv;
+    Arg args[1];
+
+    for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
+       switch (sv->type) {
+           case SV_VALUE:
+               set_value(sv->w, "");
+               break;
+
+           case SV_LABEL:
+           case SV_NAME:
+               XtSetArg(args[0], XtNlabel, "");
+               XtSetValues(sv->w, args, ONE);
+               break;
+
+           default:
+               impossible("null_out_status: unknown type %d\n", sv->type);
+               break;
+       }
+    }
+}
+
+/* This is almost an exact duplicate of hilight_value() */
+static void
+hilight_label(w)
+    Widget w;  /* label widget */
+{
+    Arg args[2];
+    Pixel fg, bg;
+
+    XtSetArg(args[0], XtNforeground, &fg);
+    XtSetArg(args[1], XtNbackground, &bg);
+    XtGetValues(w, args, TWO);
+
+    XtSetArg(args[0], XtNforeground, bg);
+    XtSetArg(args[1], XtNbackground, fg);
+    XtSetValues(w, args, TWO);
+}
+
+
+static void
+update_val(attr_rec, new_value)
+    struct X_status_value *attr_rec;
+    long new_value;
+{
+    char buf[BUFSZ];
+    Arg args[4];
+
+    if (attr_rec->type == SV_LABEL) {
+
+       if (attr_rec == &shown_stats[F_NAME]) {
+
+           Strcpy(buf, plname);
+           if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a';
+           Strcat(buf, " the ");
+           if (u.mtimedone) {
+               char mname[BUFSZ];
+               int k = 0;
+
+               Strcpy(mname, mons[u.umonnum].mname);
+               while(mname[k] != 0) {
+                   if ((k == 0 || (k > 0 && mname[k-1] == ' ')) &&
+                                       'a' <= mname[k] && mname[k] <= 'z')
+                           mname[k] += 'A' - 'a';
+                   k++;
+               }
+               Strcat(buf, mname);
+           } else
+               Strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female));
+
+       } else if (attr_rec == &shown_stats[F_DLEVEL]) {
+           if (!describe_level(buf)) {
+               Strcpy(buf, dungeons[u.uz.dnum].dname);
+               Sprintf(eos(buf), ", level %d", depth(&u.uz));
+           }
+       } else {
+           impossible("update_val: unknown label type \"%s\"",
+                                                       attr_rec->name);
+           return;
+       }
+
+       if (strcmp(buf, attr_rec->name) == 0) return;   /* same */
+
+       /* Set the label. */
+       Strcpy(attr_rec->name, buf);
+       XtSetArg(args[0], XtNlabel, buf);
+       XtSetValues(attr_rec->w, args, ONE);
+
+    } else if (attr_rec->type == SV_NAME) {
+
+       if (attr_rec->last_value == new_value) return;  /* no change */
+
+       attr_rec->last_value = new_value;
+
+       /* special cases: hunger, encumbrance, sickness */
+       if (attr_rec == &shown_stats[F_HUNGER]) {
+           XtSetArg(args[0], XtNlabel, hu_stat[new_value]);
+       } else if (attr_rec == &shown_stats[F_ENCUMBER]) {
+           XtSetArg(args[0], XtNlabel, enc_stat[new_value]);
+       } else if (attr_rec == &shown_stats[F_SICK]) {
+           buf[0] = 0;
+           if (Sick) {
+               if (u.usick_type & SICK_VOMITABLE)
+                   Strcat(buf, "FoodPois");
+               if (u.usick_type & SICK_NONVOMITABLE) {
+                   if (u.usick_type & SICK_VOMITABLE)
+                       Strcat(buf, " ");
+                   Strcat(buf, "Ill");
+               }
+           }
+           XtSetArg(args[0], XtNlabel, buf);
+       } else if (new_value) {
+           XtSetArg(args[0], XtNlabel, attr_rec->name);
+       } else {
+           XtSetArg(args[0], XtNlabel, "");
+       }
+       XtSetValues(attr_rec->w, args, ONE);
+
+    } else {   /* a value pair */
+       boolean force_update = FALSE;
+
+       /* special case: time can be enabled & disabled */
+       if (attr_rec == &shown_stats[F_TIME]) {
+           static boolean flagtime = TRUE;
+
+           if(flags.time && !flagtime) {
+               set_name(attr_rec->w, shown_stats[F_TIME].name);
+               force_update = TRUE;
+               flagtime = flags.time;
+           } else if(!flags.time && flagtime) {
+               set_name(attr_rec->w, "");
+               set_value(attr_rec->w, "");
+               flagtime = flags.time;
+           }
+           if(!flagtime) return;
+       }
+
+       /* special case: exp can be enabled & disabled */
+       else if (attr_rec == &shown_stats[F_EXP]) {
+           static boolean flagexp = TRUE;
+#ifdef EXP_ON_BOTL
+
+           if (flags.showexp && !flagexp) {
+               set_name(attr_rec->w, shown_stats[F_EXP].name);
+               force_update = TRUE;
+               flagexp = flags.showexp;
+           } else if(!flags.showexp && flagexp) {
+               set_name(attr_rec->w, "");
+               set_value(attr_rec->w, "");
+               flagexp = flags.showexp;
+           }
+           if (!flagexp) return;
+#else
+           if (flagexp) {
+               set_name(attr_rec->w, "");
+               set_value(attr_rec->w, "");
+               flagexp = FALSE;
+           }
+           return;     /* don't show it at all */
+#endif
+       }
+
+       /* special case: score can be enabled & disabled */
+       else if (attr_rec == &shown_stats[F_SCORE]) {
+           static boolean flagscore = TRUE;
+#ifdef SCORE_ON_BOTL
+
+           if(flags.showscore && !flagscore) {
+               set_name(attr_rec->w, shown_stats[F_SCORE].name);
+               force_update = TRUE;
+               flagscore = flags.showscore;
+           } else if(!flags.showscore && flagscore) {
+               set_name(attr_rec->w, "");
+               set_value(attr_rec->w, "");
+               flagscore = flags.showscore;
+           }
+           if(!flagscore) return;
+#else
+           if (flagscore) {
+               set_name(attr_rec->w, "");
+               set_value(attr_rec->w, "");
+               flagscore = FALSE;
+           }
+           return;
+#endif
+       }
+
+       /* special case: when polymorphed, show "HD", disable exp */
+       else if (attr_rec == &shown_stats[F_LEVEL]) {
+           static boolean lev_was_poly = FALSE;
+
+           if (u.mtimedone && !lev_was_poly) {
+               force_update = TRUE;
+               set_name(attr_rec->w, "HD");
+               lev_was_poly = TRUE;
+           } else if (!u.mtimedone && lev_was_poly) {
+               force_update = TRUE;
+               set_name(attr_rec->w, shown_stats[F_LEVEL].name);
+               lev_was_poly = FALSE;
+           }
+       } else if (attr_rec == &shown_stats[F_EXP]) {
+           static boolean exp_was_poly = FALSE;
+
+           if (u.mtimedone && !exp_was_poly) {
+               force_update = TRUE;
+               set_name(attr_rec->w, "");
+               set_value(attr_rec->w, "");
+               exp_was_poly = TRUE;
+           } else if (!u.mtimedone && exp_was_poly) {
+               force_update = TRUE;
+               set_name(attr_rec->w, shown_stats[F_EXP].name);
+               exp_was_poly = FALSE;
+           }
+           if (u.mtimedone) return;    /* no display for exp when poly */
+       }
+
+       if (attr_rec->last_value == new_value && !force_update) /* same */
+           return;
+
+       attr_rec->last_value = new_value;
+
+       /* Special cases: strength, alignment and "clear". */
+       if (attr_rec == &shown_stats[F_STR]) {
+           if(new_value > 18) {
+               if (new_value > 118)
+                   Sprintf(buf,"%ld", new_value-100);
+               else if(new_value < 118)
+                   Sprintf(buf, "18/%02ld", new_value-18);
+               else
+                   Strcpy(buf, "18/**");
+           } else {
+               Sprintf(buf, "%ld", new_value);
+           }
+       } else if (attr_rec == &shown_stats[F_ALIGN]) {
+
+           Strcpy(buf, (new_value == A_CHAOTIC) ? "Chaotic" :
+                       (new_value == A_NEUTRAL) ? "Neutral" :
+                                                  "Lawful"  );
+       } else {
+           Sprintf(buf, "%ld", new_value);
+       }
+       set_value(attr_rec->w, buf);
+    }
+
+    /*
+     * Now hilight the changed information.  Names, time and score don't
+     * hilight.  If first time, don't hilight.  If already lit, don't do
+     * it again.
+     */
+    if (attr_rec->type != SV_NAME && attr_rec != &shown_stats[F_TIME]) {
+       if (attr_rec->after_init) {
+           if(!attr_rec->set) {
+               if (attr_rec->type == SV_LABEL)
+                   hilight_label(attr_rec->w);
+               else
+                   hilight_value(attr_rec->w);
+               attr_rec->set = TRUE;
+           }
+           attr_rec->turn_count = 0;
+       } else {
+           attr_rec->after_init = TRUE;
+       }
+    }
+}
+
+/*
+ * Update the displayed status.  The current code in botl.c updates
+ * two lines of information.  Both lines are always updated one after
+ * the other.  So only do our update when we update the second line.
+ *
+ * Information on the first line:
+ *     name, attributes, alignment, score
+ *
+ * Information on the second line:
+ *     dlvl, gold, hp, power, ac, {level & exp or HD **}
+ *     status (hunger, conf, halu, stun, sick, blind), time, encumbrance
+ *
+ * [**] HD is shown instead of level and exp if mtimedone is non-zero.
+ */
+static void
+update_fancy_status(wp)
+    struct xwindow *wp;
+{
+    struct X_status_value *sv;
+    long val;
+    int i;
+
+    if (wp->cursy != 0) return;        /* do a complete update when line 0 is done */
+
+    for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
+       switch (i) {
+           case F_STR:         val = (long) ACURR(A_STR); break;
+           case F_DEX:         val = (long) ACURR(A_DEX); break;
+           case F_CON:         val = (long) ACURR(A_CON); break;
+           case F_INT:         val = (long) ACURR(A_INT); break;
+           case F_WIS:         val = (long) ACURR(A_WIS); break;
+           case F_CHA:         val = (long) ACURR(A_CHA); break;
+           /*
+            * Label stats.  With the exceptions of hunger, encumbrance, sick
+            * these are either on or off.  Pleae leave the ternary operators
+            * the way they are.  I want to specify 0 or 1, not a boolean.
+            */
+           case F_HUNGER:      val = (long) u.uhs;                     break;
+           case F_CONFUSED:    val = (long) Confusion     ? 1L : 0L;   break;
+           case F_SICK:        val = (long) Sick ? (long)u.usick_type
+                                                               : 0L;   break;
+           case F_BLIND:       val = (long) Blind         ? 1L : 0L;   break;
+           case F_STUNNED:     val = (long) Stunned       ? 1L : 0L;   break;
+           case F_HALLU:       val = (long) Hallucination ? 1L : 0L;   break;
+           case F_ENCUMBER:    val = (long) near_capacity();           break;
+
+           case F_NAME:        val = (long) 0L; break; /* special */
+           case F_DLEVEL:      val = (long) 0L; break; /* special */
+#ifndef GOLDOBJ
+           case F_GOLD:        val = (long) u.ugold; break;
+#else
+           case F_GOLD:        val = money_cnt(invent); break;
+#endif
+           case F_HP:          val = (long) (u.mtimedone ?
+                                             (u.mh  > 0 ? u.mh  : 0):
+                                             (u.uhp > 0 ? u.uhp : 0)); break;
+           case F_MAXHP:       val = (long) (u.mtimedone ? u.mhmax :
+                                                           u.uhpmax);  break;
+           case F_POWER:       val = (long) u.uen;     break;
+           case F_MAXPOWER:    val = (long) u.uenmax;  break;
+           case F_AC:          val = (long) u.uac;     break;
+           case F_LEVEL:       val = (long) (u.mtimedone ?
+                                               mons[u.umonnum].mlevel :
+                                               u.ulevel);              break;
+#ifdef EXP_ON_BOTL
+           case F_EXP:         val = flags.showexp ? u.uexp : 0L; break;
+#else
+           case F_EXP:         val = 0L; break;
+#endif
+           case F_ALIGN:       val = (long) u.ualign.type; break;
+           case F_TIME:        val = flags.time ? (long) moves : 0L;   break;
+#ifdef SCORE_ON_BOTL
+           case F_SCORE:       val = flags.showscore ? botl_score():0L; break;
+#else
+           case F_SCORE:       val = 0L; break;
+#endif
+           default:
+           {
+               /*
+                * There is a possible infinite loop that occurs with:
+                *
+                *      impossible->pline->flush_screen->bot->bot{1,2}->
+                *      putstr->adjust_status->update_other->impossible
+                *
+                * Break out with this.
+                */
+               static boolean active = FALSE;
+               if (!active) {
+                   active = TRUE;
+                   impossible("update_other: unknown shown value");
+                   active = FALSE;
+               }
+               val = 0;
+               break;
+           }
+       }
+       update_val(sv, val);
+    }
+}
+
+/*
+ * Turn off hilighted status values after a certain amount of turns.
+ */
+void
+check_turn_events()
+{
+    int i;
+    struct X_status_value *sv;
+
+    for (sv = shown_stats, i = 0; i < NUM_STATS; i++, sv++) {
+       if (!sv->set) continue;
+
+       if (sv->turn_count++ >= hilight_time) {
+           if (sv->type == SV_LABEL)
+               hilight_label(sv->w);
+           else
+               hilight_value(sv->w);
+           sv->set = FALSE;
+       }
+    }
+}
+
+/* Initialize alternate status ============================================= */
+
+/* Return a string for the initial width. */
+static const char *
+width_string(sv_index)
+    int sv_index;
+{
+    switch (sv_index) {
+       case F_STR:     return "018/**";
+       case F_DEX:
+       case F_CON:
+       case F_INT:
+       case F_WIS:
+       case F_CHA:     return "088";   /* all but str never get bigger */
+
+       case F_HUNGER:  return shown_stats[F_HUNGER].name;
+       case F_CONFUSED:return shown_stats[F_CONFUSED].name;
+       case F_SICK:    return shown_stats[F_SICK].name;
+       case F_BLIND:   return shown_stats[F_BLIND].name;
+       case F_STUNNED: return shown_stats[F_STUNNED].name;
+       case F_HALLU:   return shown_stats[F_HALLU].name;
+       case F_ENCUMBER:return shown_stats[F_ENCUMBER].name;
+
+       case F_NAME:
+       case F_DLEVEL:  return "";
+       case F_HP:
+       case F_MAXHP:   return "9999";
+       case F_POWER:
+       case F_MAXPOWER:return "999";
+       case F_AC:      return "-99";
+       case F_LEVEL:   return "99";
+       case F_GOLD:
+       case F_EXP:     return "4294967295";    /* max ulong */
+       case F_ALIGN:   return "Neutral";
+       case F_TIME:    return "4294967295";    /* max ulong */
+       case F_SCORE:   return "4294967295";    /* max ulong */
+    }
+    impossible("width_string: unknown index %d\n", sv_index);
+    return "";
+}
+
+static void
+create_widget(parent, sv, sv_index)
+    Widget parent;
+    struct X_status_value *sv;
+    int sv_index;
+{
+    Arg args[4];
+    Cardinal num_args;
+
+    switch (sv->type) {
+       case SV_VALUE:
+           sv->w = create_value(parent, sv->name);
+           set_value(sv->w, width_string(sv_index));
+           break;
+       case SV_LABEL:
+           /* Labels get their own buffer. */
+           sv->name = (char *) alloc(BUFSZ);
+           sv->name[0] = '\0';
+
+           num_args = 0;
+           XtSetArg(args[num_args], XtNborderWidth, 0);        num_args++;
+           XtSetArg(args[num_args], XtNinternalHeight, 0);     num_args++;
+           sv->w = XtCreateManagedWidget(
+                               sv_index == F_NAME ? "name" : "dlevel",
+                               labelWidgetClass,
+                               parent,
+                               args, num_args);
+           break;
+       case SV_NAME:
+           num_args = 0;
+           XtSetArg(args[num_args], XtNborderWidth, 0);        num_args++;
+           XtSetArg(args[num_args], XtNinternalHeight, 0);     num_args++;
+           sv->w = XtCreateManagedWidget(sv->name,
+                                       labelWidgetClass,
+                                       parent,
+                                       args, num_args);
+           break;
+       default:
+           panic("create_widget: unknown type %d", sv->type);
+    }
+}
+
+/*
+ * Get current width of value.  width2p is only valid for SV_LABEL types.
+ */
+static void
+get_widths(sv, width1p, width2p)
+    struct X_status_value *sv;
+    int *width1p, *width2p;
+{
+    Arg args[1];
+    Dimension width;
+
+    switch (sv->type) {
+       case SV_VALUE:
+           *width1p = get_name_width(sv->w);
+           *width2p = get_value_width(sv->w);
+           break;
+       case SV_LABEL:
+       case SV_NAME:
+           XtSetArg(args[0], XtNwidth, &width);
+           XtGetValues(sv->w, args, ONE);
+           *width1p = width;
+           *width2p = 0;
+           break;
+       default:
+           panic("get_widths: unknown type %d", sv->type);
+    }
+}
+
+static void
+set_widths(sv, width1, width2)
+    struct X_status_value *sv;
+    int width1, width2;
+{
+    Arg args[1];
+
+    switch (sv->type) {
+       case SV_VALUE:
+           set_name_width(sv->w, width1);
+           set_value_width(sv->w, width2);
+           break;
+       case SV_LABEL:
+       case SV_NAME:
+           XtSetArg(args[0], XtNwidth, (width1+width2));
+           XtSetValues(sv->w, args, ONE);
+           break;
+       default:
+           panic("set_widths: unknown type %d", sv->type);
+    }
+}
+
+static Widget
+init_column(name, parent, top, left, col_indices)
+    char *name;
+    Widget parent, top, left;
+    int *col_indices;
+{
+    Widget form;
+    Arg args[4];
+    Cardinal num_args;
+    int max_width1, width1, max_width2, width2;
+    int *ip;
+    struct X_status_value *sv;
+
+    num_args = 0;
+    if (top != (Widget) 0) {
+       XtSetArg(args[num_args], XtNfromVert, top);             num_args++;
+    }
+    if (left != (Widget) 0) {
+       XtSetArg(args[num_args], XtNfromHoriz, left);   num_args++;
+    }
+    XtSetArg(args[num_args], XtNdefaultDistance, 0);   num_args++;
+    form = XtCreateManagedWidget(name,
+                               formWidgetClass,
+                               parent, args, num_args);
+
+    max_width1 = max_width2 = 0;
+    for (ip = col_indices; *ip >= 0; ip++) {
+       sv = &shown_stats[*ip];
+       create_widget(form, sv, *ip);   /* will set init width */
+       if (ip != col_indices) {        /* not first */
+           num_args = 0;
+           XtSetArg(args[num_args], XtNfromVert, shown_stats[*(ip-1)].w);
+                                                               num_args++;
+           XtSetValues(sv->w, args, num_args);
+       }
+       get_widths(sv, &width1, &width2);
+       if (width1 > max_width1) max_width1 = width1;
+       if (width2 > max_width2) max_width2 = width2;
+    }
+    for (ip = col_indices; *ip >= 0 ; ip++) {
+       set_widths(&shown_stats[*ip], max_width1, max_width2);
+    }
+
+    /* There is room behind the end marker for the two widths. */
+    *++ip = max_width1;
+    *++ip = max_width2;
+
+    return form;
+}
+
+/*
+ * These are the orders of the displayed columns.  Change to suit.  The -1
+ * indicates the end of the column.  The two numbers after that are used
+ * to store widths that are calculated at run-time.
+ */
+static int attrib_indices[] = { F_STR,F_DEX,F_CON,F_INT,F_WIS,F_CHA, -1,0,0 };
+static int status_indices[] = { F_HUNGER, F_CONFUSED, F_SICK, F_BLIND,
+                               F_STUNNED, F_HALLU, F_ENCUMBER, -1,0,0 };
+
+static int col2_indices[] = { F_MAXHP,    F_ALIGN, F_TIME, F_EXP,
+                             F_MAXPOWER, -1,0,0 };
+static int col1_indices[] = { F_HP,       F_AC,    F_GOLD, F_LEVEL,
+                             F_POWER,    F_SCORE, -1,0,0 };
+
+
+/*
+ * Produce a form that looks like the following:
+ *
+ *                name
+ *               dlevel
+ * col1_indices[0]     col2_indices[0]
+ * col1_indices[1]     col2_indices[1]
+ *    .                    .
+ *    .                    .
+ * col1_indices[n]     col2_indices[n]
+ */
+static Widget
+init_info_form(parent, top, left)
+    Widget parent, top, left;
+{
+    Widget form, col1;
+    struct X_status_value *sv_name, *sv_dlevel;
+    Arg args[6];
+    Cardinal num_args;
+    int total_width, *ip;
+
+    num_args = 0;
+    if (top != (Widget) 0) {
+       XtSetArg(args[num_args], XtNfromVert, top);     num_args++;
+    }
+    if (left != (Widget) 0) {
+       XtSetArg(args[num_args], XtNfromHoriz, left);   num_args++;
+    }
+    XtSetArg(args[num_args], XtNdefaultDistance, 0);   num_args++;
+    form = XtCreateManagedWidget("status_info",
+                               formWidgetClass,
+                               parent,
+                               args, num_args);
+
+    /* top of form */
+    sv_name = &shown_stats[F_NAME];
+    create_widget(form, sv_name, F_NAME);
+
+    /* second */
+    sv_dlevel = &shown_stats[F_DLEVEL];
+    create_widget(form, sv_dlevel, F_DLEVEL);
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNfromVert, sv_name->w); num_args++;
+    XtSetValues(sv_dlevel->w, args, num_args);
+
+    /* two columns beneath */
+    col1 = init_column("name_col1", form, sv_dlevel->w,
+                                               (Widget) 0, col1_indices);
+    (void) init_column("name_col2", form, sv_dlevel->w,
+                                                     col1, col2_indices);
+
+    /* Add calculated widths. */
+    for (ip = col1_indices; *ip >= 0; ip++)
+       ;       /* skip to end */
+    total_width = *++ip;
+    total_width += *++ip;
+    for (ip = col2_indices; *ip >= 0; ip++)
+       ;       /* skip to end */
+    total_width += *++ip;
+    total_width += *++ip;
+
+    XtSetArg(args[0], XtNwidth, total_width);
+    XtSetValues(sv_name->w,   args, ONE);
+    XtSetArg(args[0], XtNwidth, total_width);
+    XtSetValues(sv_dlevel->w, args, ONE);
+
+    return form;
+}
+
+/*
+ * Create the layout for the fancy status.  Return a form widget that
+ * contains everything.
+ */
+static Widget
+create_fancy_status(parent, top)
+    Widget parent, top;
+{
+    Widget form;       /* The form that surrounds everything. */
+    Widget w;
+    Arg args[8];
+    Cardinal num_args;
+
+    num_args = 0;
+    if (top != (Widget) 0) {
+       XtSetArg(args[num_args], XtNfromVert, top);     num_args++;
+    }
+    XtSetArg(args[num_args], XtNdefaultDistance, 0);   num_args++;
+    XtSetArg(args[num_args], XtNborderWidth, 0);       num_args++;
+    XtSetArg(args[num_args], XtNorientation, XtorientHorizontal); num_args++;
+    form = XtCreateManagedWidget("fancy_status",
+                               panedWidgetClass,
+                               parent,
+                               args, num_args);
+
+    w = init_info_form(form, (Widget) 0, (Widget) 0);
+    w =    init_column("status_attributes",form, (Widget) 0, w, attrib_indices);
+    (void) init_column("status_condition", form, (Widget) 0, w, status_indices);
+    return form;
+}
+
+static void
+destroy_fancy_status(wp)
+struct xwindow *wp;
+{
+    int i;
+    struct X_status_value *sv;
+
+    if (!wp->keep_window)
+       XtDestroyWidget(wp->w),  wp->w = (Widget)0;
+
+    for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++)
+       if (sv->type == SV_LABEL) {
+           free((genericptr_t)sv->name);
+           sv->name = 0;
+       }
+}
+
+/*winstat.c*/
diff --git a/win/X11/wintext.c b/win/X11/wintext.c
new file mode 100644 (file)
index 0000000..84cafe6
--- /dev/null
@@ -0,0 +1,626 @@
+/*     SCCS Id: @(#)wintext.c  3.4     1996/04/05      */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * File for dealing with text windows.
+ *
+ *     + No global functions.
+ */
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Cardinals.h>
+#include <X11/Xatom.h>
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+#include "hack.h"
+#include "winX.h"
+#include "xwindow.h"
+
+#ifdef GRAPHIC_TOMBSTONE
+#include <X11/xpm.h>
+#endif
+
+
+#define TRANSIENT_TEXT /* text window is a transient window (no positioning) */
+
+static const char text_translations[] =
+    "#override\n\
+     <BtnDown>: dismiss_text()\n\
+     <Key>: key_dismiss_text()";
+
+#ifdef GRAPHIC_TOMBSTONE
+static const char rip_translations[] =
+    "#override\n\
+     <BtnDown>: rip_dismiss_text()\n\
+     <Key>: rip_dismiss_text()";
+
+static Widget FDECL(create_ripout_widget, (Widget));
+#endif
+
+/*ARGSUSED*/
+void
+delete_text(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    struct xwindow *wp;
+    struct text_info_t *text_info;
+
+    wp = find_widget(w);
+    text_info = wp->text_information;
+
+    nh_XtPopdown(wp->popup);
+
+    if (text_info->blocked) {
+       exit_x_event = TRUE;
+    } else if (text_info->destroy_on_ack) {
+       destroy_text_window(wp);
+    }
+}
+
+/*
+ * Callback used for all text windows.  The window is poped down on any key
+ * or button down event.  It is destroyed if the main nethack code is done
+ * with it.
+ */
+/*ARGSUSED*/
+void
+dismiss_text(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    struct xwindow *wp;
+    struct text_info_t *text_info;
+
+    wp = find_widget(w);
+    text_info = wp->text_information;
+
+    nh_XtPopdown(wp->popup);
+
+    if (text_info->blocked) {
+       exit_x_event = TRUE;
+    } else if (text_info->destroy_on_ack) {
+       destroy_text_window(wp);
+    }
+}
+
+/* Dismiss when a non-modifier key pressed. */
+void
+key_dismiss_text(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    char ch = key_event_to_char((XKeyEvent *) event);
+    if (ch) dismiss_text(w, event, params, num_params);
+}
+
+#ifdef GRAPHIC_TOMBSTONE
+/* Dismiss from clicking on rip image. */
+void
+rip_dismiss_text(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    dismiss_text(XtParent(w), event, params, num_params);
+}
+#endif
+
+
+/* ARGSUSED */
+void
+add_to_text_window(wp, attr, str)
+    struct xwindow *wp;
+    int attr;  /* currently unused */
+    const char *str;
+{
+    struct text_info_t *text_info = wp->text_information;
+    int width;
+
+    append_text_buffer(&text_info->text, str, FALSE);
+
+    /* Calculate text width and save longest line */
+    width = XTextWidth(text_info->fs, str, (int) strlen(str));
+    if (width > text_info->max_width)
+       text_info->max_width = width;
+}
+
+void
+display_text_window(wp, blocking)
+    struct xwindow *wp;
+    boolean blocking;
+{
+    struct text_info_t *text_info;
+    Arg args[8];
+    Cardinal num_args;
+    Dimension width, height, font_height;
+    int nlines;
+
+    text_info = wp->text_information;
+    width  = text_info->max_width + text_info->extra_width;
+    text_info->blocked = blocking;
+    text_info->destroy_on_ack = FALSE;
+    font_height = nhFontHeight(wp->w);
+
+    /*
+     * Calculate the number of lines to use.  First, find the number of
+     * lines that would fit on the screen.  Next, remove four of these
+     * lines to give room for a possible window manager titlebar (some
+     * wm's put a titlebar on transient windows).  Make sure we have
+     * _some_ lines.  Finally, use the number of lines in the text if
+     * there are fewer than the max.
+     */
+    nlines = (XtScreen(wp->w)->height - text_info->extra_height) / font_height;
+    nlines -= 4;
+
+    if (nlines > text_info->text.num_lines)
+       nlines = text_info->text.num_lines;
+    if (nlines <= 0) nlines = 1;
+
+    height = nlines * font_height + text_info->extra_height;
+
+    num_args = 0;
+
+    if (nlines < text_info->text.num_lines) {
+       /* add on width of scrollbar.  Really should look this up,
+        * but can't until the window is realized.  Chicken-and-egg problem.
+        */
+       width += 20;
+    }
+
+#ifdef GRAPHIC_TOMBSTONE
+    if (text_info->is_rip) {
+       Widget rip = create_ripout_widget(XtParent(wp->w));
+       XtSetArg(args[num_args], XtNfromVert, rip);     num_args++;
+    }
+#endif
+
+    if (width > (Dimension) XtScreen(wp->w)->width) { /* too wide for screen */
+       /* Back off some amount - we really need to back off the scrollbar */
+       /* width plus some extra.                                          */
+       width = XtScreen(wp->w)->width - 20;
+    }
+    XtSetArg(args[num_args], XtNstring, text_info->text.text); num_args++;
+    XtSetArg(args[num_args], XtNwidth,  width);                        num_args++;
+    XtSetArg(args[num_args], XtNheight, height);               num_args++;
+    XtSetValues(wp->w, args, num_args);
+
+#ifdef TRANSIENT_TEXT
+    XtRealizeWidget(wp->popup);
+    XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup),
+                   &wm_delete_window, 1);
+    positionpopup(wp->popup, FALSE);
+#endif
+
+    nh_XtPopup(wp->popup, (int)XtGrabNone, wp->w);
+
+    /* Kludge alert.  Scrollbars are not sized correctly by the Text widget */
+    /* if added before the window is displayed, so do it afterward. */
+    num_args = 0;
+    if (nlines < text_info->text.num_lines) {  /* add vert scrollbar */
+       XtSetArg(args[num_args], XtNscrollVertical, XawtextScrollAlways);
+                                                               num_args++;
+    }
+    if (width >= (Dimension) (XtScreen(wp->w)->width-20)) {    /* too wide */
+       XtSetArg(args[num_args], XtNscrollHorizontal, XawtextScrollAlways);
+                                                               num_args++;
+    }
+    if (num_args) XtSetValues(wp->w, args, num_args);
+
+    /* We want the user to acknowlege. */
+    if (blocking) {
+       (void) x_event(EXIT_ON_EXIT);
+       nh_XtPopdown(wp->popup);
+    }
+}
+
+
+void
+create_text_window(wp)
+    struct xwindow *wp;
+{
+    struct text_info_t *text_info;
+    Arg args[8];
+    Cardinal num_args;
+    Position top_margin, bottom_margin, left_margin, right_margin;
+    Widget form;
+
+    wp->type = NHW_TEXT;
+
+    wp->text_information = text_info =
+                   (struct text_info_t *) alloc(sizeof(struct text_info_t));
+
+    init_text_buffer(&text_info->text);
+    text_info->max_width      = 0;
+    text_info->extra_width    = 0;
+    text_info->extra_height   = 0;
+    text_info->blocked       = FALSE;
+    text_info->destroy_on_ack = TRUE;  /* Ok to destroy before display */
+#ifdef GRAPHIC_TOMBSTONE
+    text_info->is_rip        = FALSE;
+#endif
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
+    XtSetArg(args[num_args], XtNtranslations,
+               XtParseTranslationTable(text_translations));    num_args++;
+
+#ifdef TRANSIENT_TEXT
+    wp->popup = XtCreatePopupShell("text", transientShellWidgetClass,
+                                  toplevel, args, num_args);
+#else
+    wp->popup = XtCreatePopupShell("text", topLevelShellWidgetClass,
+                                  toplevel, args, num_args);
+#endif
+    XtOverrideTranslations(wp->popup,
+       XtParseTranslationTable("<Message>WM_PROTOCOLS: delete_text()"));
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNallowShellResize, True);       num_args++;
+    form = XtCreateManagedWidget("form", formWidgetClass, wp->popup,
+               args, num_args);
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNdisplayCaret, False);          num_args++;
+    XtSetArg(args[num_args], XtNresize, XawtextResizeBoth);    num_args++;
+    XtSetArg(args[num_args], XtNtranslations,
+               XtParseTranslationTable(text_translations));    num_args++;
+
+    wp->w = XtCreateManagedWidget(
+               killer && WIN_MAP == WIN_ERR ?
+                                 "tombstone" : "text_text", /* name */
+               asciiTextWidgetClass,
+               form,                   /* parent widget */
+               args,                   /* set some values */
+               num_args);              /* number of values to set */
+
+    /* Get the font and margin information. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNfont,        &text_info->fs); num_args++;
+    XtSetArg(args[num_args], XtNtopMargin,    &top_margin);    num_args++;
+    XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++;
+    XtSetArg(args[num_args], XtNleftMargin,   &left_margin);   num_args++;
+    XtSetArg(args[num_args], XtNrightMargin,  &right_margin);  num_args++;
+    XtGetValues(wp->w, args, num_args);
+
+    text_info->extra_width  = left_margin + right_margin;
+    text_info->extra_height = top_margin + bottom_margin;
+}
+
+void
+destroy_text_window(wp)
+    struct xwindow *wp;
+{
+    /* Don't need to pop down, this only called from dismiss_text(). */
+
+    struct text_info_t *text_info = wp->text_information;
+
+    /*
+     * If the text window was blocked, then the user has already ACK'ed
+     * it and we are free to really destroy the window.  Otherwise, don't
+     * destroy until the user dismisses the window via a key or button
+     * press.
+     */
+    if (text_info->blocked || text_info->destroy_on_ack) {
+       XtDestroyWidget(wp->popup);
+       free_text_buffer(&text_info->text);
+       free((genericptr_t)text_info),  wp->text_information = 0;
+       wp->type = NHW_NONE;    /* allow reuse */
+    } else {
+       text_info->destroy_on_ack = TRUE;       /* destroy on next ACK */
+    }
+}
+
+void
+clear_text_window(wp)
+    struct xwindow *wp;
+{
+    clear_text_buffer(&wp->text_information->text);
+}
+
+
+/* text buffer routines ---------------------------------------------------- */
+
+/* Append a line to the text buffer. */
+void
+append_text_buffer(tb, str, concat)
+    struct text_buffer *tb;
+    const char *str;
+    boolean concat;
+{
+    char *copy;
+    int length;
+
+    if (!tb->text) panic("append_text_buffer:  null text buffer");
+
+    if (str) {
+       length = strlen(str);
+    } else {
+       length = 0;
+    }
+
+    if (length + tb->text_last + 1 >= tb->text_size) {
+       /* we need to go to a bigger buffer! */
+#ifdef VERBOSE
+       printf("append_text_buffer: text buffer growing from %d to %d bytes\n",
+                               tb->text_size, 2*tb->text_size);
+#endif
+       copy = (char *) alloc((unsigned)tb->text_size*2);
+       (void) memcpy(copy, tb->text, tb->text_last);
+       free(tb->text);
+       tb->text = copy;
+       tb->text_size *= 2;
+    }
+
+    if (tb->num_lines) {       /* not first --- append a newline */
+       char appchar = '\n';
+
+       if(concat && !index("!.?'\")", tb->text[tb->text_last-1])) {
+           appchar = ' ';
+           tb->num_lines--; /* offset increment at end of function */
+       }
+
+       *(tb->text + tb->text_last) = appchar;
+       tb->text_last++;
+    }
+
+    if (str) {
+       (void) memcpy((tb->text+tb->text_last), str, length+1);
+       if(length) {
+           /* Remove all newlines. Otherwise we have a confused line count. */
+           copy = (tb->text+tb->text_last);
+           while ((copy = index(copy, '\n')) != (char*)0)
+               *copy = ' ';
+       }
+
+       tb->text_last += length;
+    }
+    tb->text[tb->text_last] = '\0';
+    tb->num_lines++;
+}
+
+/* Initialize text buffer. */
+void
+init_text_buffer(tb)
+    struct text_buffer *tb;
+{
+    tb->text     = (char *) alloc(START_SIZE);
+    tb->text[0]   = '\0';
+    tb->text_size = START_SIZE;
+    tb->text_last = 0;
+    tb->num_lines = 0;
+}
+
+/* Empty the text buffer */
+void
+clear_text_buffer(tb)
+    struct text_buffer *tb;
+{
+    tb->text_last = 0;
+    tb->text[0]   = '\0';
+    tb->num_lines = 0;
+}
+
+/* Free up allocated memory. */
+void
+free_text_buffer(tb)
+    struct text_buffer *tb;
+{
+    free(tb->text);
+    tb->text = (char *) 0;
+    tb->text_size = 0;
+    tb->text_last = 0;
+    tb->num_lines = 0;
+}
+
+
+#ifdef GRAPHIC_TOMBSTONE
+
+static void FDECL(rip_exposed, (Widget,XtPointer,XtPointer));
+
+static XImage* rip_image=0;
+
+
+#define STONE_LINE_LEN 16      /* # chars that fit on one line */
+#define NAME_LINE 0            /* line # for player name */
+#define GOLD_LINE 1            /* line # for amount of gold */
+#define DEATH_LINE 2           /* line # for death description */
+#define YEAR_LINE 6            /* line # for year */
+
+static char rip_line[YEAR_LINE+1][STONE_LINE_LEN+1];
+
+extern const char *killed_by_prefix[];
+
+void
+calculate_rip_text(int how)
+{
+       /* Follows same algorithm as genl_outrip() */
+
+       char buf[BUFSZ];
+       char *dpx;
+       int line;
+
+       /* Put name on stone */
+       Sprintf(rip_line[NAME_LINE], "%s", plname);
+
+       /* Put $ on stone */
+       Sprintf(rip_line[GOLD_LINE], "%ld Au",
+#ifndef GOLDOBJ
+               u.ugold);
+#else
+               done_money);
+#endif
+       /* Put together death description */
+       switch (killer_format) {
+               default: impossible("bad killer format?");
+               case KILLED_BY_AN:
+                       Strcpy(buf, killed_by_prefix[how]);
+                       Strcat(buf, an(killer));
+                       break;
+               case KILLED_BY:
+                       Strcpy(buf, killed_by_prefix[how]);
+                       Strcat(buf, killer);
+                       break;
+               case NO_KILLER_PREFIX:
+                       Strcpy(buf, killer);
+                       break;
+       }
+
+       /* Put death type on stone */
+       for (line=DEATH_LINE, dpx = buf; line<YEAR_LINE; line++) {
+               register int i,i0;
+               char tmpchar;
+
+               if ( (i0=strlen(dpx)) > STONE_LINE_LEN) {
+                       for(i = STONE_LINE_LEN;
+                           ((i0 > STONE_LINE_LEN) && i); i--)
+                               if(dpx[i] == ' ') i0 = i;
+                       if(!i) i0 = STONE_LINE_LEN;
+               }
+               tmpchar = dpx[i0];
+               dpx[i0] = 0;
+               strcpy(rip_line[line], dpx);
+               if (tmpchar != ' ') {
+                       dpx[i0] = tmpchar;
+                       dpx= &dpx[i0];
+               } else  dpx= &dpx[i0+1];
+       }
+
+       /* Put year on stone */
+       Sprintf(rip_line[YEAR_LINE], "%4d", getyear());
+}
+
+
+/*
+ * RIP image expose callback.
+ */
+/*ARGSUSED*/
+static void
+rip_exposed(w, client_data, widget_data)
+    Widget w;
+    XtPointer client_data;     /* unused */
+    XtPointer widget_data;     /* expose event from Window widget */
+{
+    XExposeEvent *event = (XExposeEvent *) widget_data;
+    Display* dpy=XtDisplay(w);
+    Arg args[8];
+    XGCValues values;
+    XtGCMask mask;
+    GC gc;
+    static Pixmap rip_pixmap=None;
+    int i, x, y;
+
+    if (!XtIsRealized(w) || event->count > 0) return;
+
+    if (rip_pixmap == None && rip_image) {
+       rip_pixmap = XCreatePixmap(dpy, XtWindow(w),
+                       rip_image->width,
+                       rip_image->height,
+                       DefaultDepth(dpy, DefaultScreen(dpy)));
+       XPutImage(dpy, rip_pixmap,
+               DefaultGC(dpy, DefaultScreen(dpy)),
+               rip_image,
+               0,0, 0,0,               /* src, dest top left */
+               rip_image->width,
+               rip_image->height);
+       XDestroyImage(rip_image);       /* data bytes free'd also */
+    }
+
+    mask = GCFunction | GCForeground | GCGraphicsExposures | GCFont;
+    values.graphics_exposures = False;
+    XtSetArg(args[0], XtNforeground, &values.foreground);
+    XtGetValues(w, args, 1);
+    values.function = GXcopy;
+    values.font = WindowFont(w);
+    gc = XtGetGC(w, mask, &values);
+
+    if (rip_pixmap != None) {
+       XCopyArea(dpy, rip_pixmap, XtWindow(w), gc,
+               event->x, event->y, event->width, event->height,
+               event->x, event->y);
+    }
+
+    x=appResources.tombtext_x;
+    y=appResources.tombtext_y;
+    for (i=0; i<=YEAR_LINE; i++) {
+       int len=strlen(rip_line[i]);
+       XFontStruct* font=WindowFontStruct(w);
+       int width=XTextWidth(font, rip_line[i], len);
+       XDrawString(dpy, XtWindow(w), gc,
+               x-width/2, y, rip_line[i], len);
+       x+=appResources.tombtext_dx;
+       y+=appResources.tombtext_dy;
+    }
+
+    XtReleaseGC(w, gc);
+}
+
+/*
+ * The ripout window creation routine.
+ */
+static Widget
+create_ripout_widget(Widget parent)
+{
+    Widget imageport;
+    Arg args[16];
+    Cardinal num_args;
+
+    static int rip_width, rip_height;
+
+    if (!rip_image) {
+       XpmAttributes attributes;
+       int errorcode;
+
+       attributes.valuemask = XpmCloseness;
+       attributes.closeness = 65535; /* Try anything */
+       errorcode = XpmReadFileToImage(XtDisplay(parent), appResources.tombstone, &rip_image, 0, &attributes);
+       if (errorcode != XpmSuccess) {
+           char buf[BUFSZ];
+           Sprintf(buf, "Failed to load %s: %s", appResources.tombstone,
+                       XpmGetErrorString(errorcode));
+           X11_raw_print(buf);
+       }
+       rip_width = rip_image->width;
+       rip_height = rip_image->height;
+    }
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNwidth, rip_width); num_args++;
+    XtSetArg(args[num_args], XtNheight, rip_height); num_args++;
+    XtSetArg(args[num_args], XtNtranslations,
+               XtParseTranslationTable(rip_translations));     num_args++;
+
+    imageport = XtCreateManagedWidget("rip", windowWidgetClass,
+               parent, args, num_args);
+
+    XtAddCallback(imageport, XtNexposeCallback, rip_exposed, (XtPointer) 0);
+
+    return imageport;
+}
+
+#endif /* GRAPHIC_TOMBSTONE */
+
+/*wintext.c*/
diff --git a/win/X11/winval.c b/win/X11/winval.c
new file mode 100644 (file)
index 0000000..3f2307e
--- /dev/null
@@ -0,0 +1,177 @@
+/*     SCCS Id: @(#)winval.c   3.4     1992/3/7        */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Routines that define a name-value label widget pair that fit inside a
+ * form widget.
+ */
+#include <stdio.h>
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Cardinals.h>
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+#include "hack.h"      /* #define for const for non __STDC__ compilers */
+#include "winX.h"
+
+#define WNAME "name"
+#define WVALUE "value"
+
+
+Widget
+create_value(parent, name_value)
+    Widget parent;
+    const char *name_value;
+{
+    Widget form, name;
+    Arg args[8];
+    Cardinal num_args;
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNborderWidth, 0);               num_args++;
+    XtSetArg(args[num_args], XtNdefaultDistance, 0);           num_args++;
+    form = XtCreateManagedWidget(name_value,
+                               formWidgetClass,
+                               parent, args, num_args);
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNjustify, XtJustifyRight);      num_args++;
+    XtSetArg(args[num_args], XtNborderWidth, 0);               num_args++;
+    XtSetArg(args[num_args], XtNlabel, name_value);            num_args++;
+    XtSetArg(args[num_args], XtNinternalHeight, 0);            num_args++;
+    name = XtCreateManagedWidget(WNAME,
+                               labelWidgetClass,
+                               form, args, num_args);
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNjustify, XtJustifyRight);      num_args++;
+    XtSetArg(args[num_args], XtNborderWidth, 0);               num_args++;
+    XtSetArg(args[num_args], XtNfromHoriz, name);              num_args++;
+    XtSetArg(args[num_args], XtNinternalHeight, 0);            num_args++;
+    (void) XtCreateManagedWidget(WVALUE,
+                               labelWidgetClass,
+                               form, args, num_args);
+    return form;
+}
+
+void
+set_name(w, new_label)
+    Widget w;
+    char *new_label;
+{
+    Arg args[1];
+    Widget name;
+
+    name = XtNameToWidget(w, WNAME);
+    XtSetArg(args[0], XtNlabel, new_label);
+    XtSetValues(name, args, ONE);
+}
+
+void
+set_name_width(w, new_width)
+    Widget w;
+    int new_width;
+{
+    Arg args[1];
+    Widget name;
+
+    name = XtNameToWidget(w, WNAME);
+    XtSetArg(args[0], XtNwidth, new_width);
+    XtSetValues(name, args, ONE);
+}
+
+int
+get_name_width(w)
+    Widget w;
+{
+    Arg args[1];
+    Dimension width;
+    Widget name;
+
+    name = XtNameToWidget(w, WNAME);
+    XtSetArg(args[0], XtNwidth, &width);
+    XtGetValues(name, args, ONE);
+    return (int) width;
+}
+
+
+void
+set_value(w, new_value)
+    Widget w;
+    const char *new_value;
+{
+    Arg args[1];
+    Widget val;
+
+    val = XtNameToWidget(w, WVALUE);
+    XtSetArg(args[0], XtNlabel, new_value);
+    XtSetValues(val, args, ONE);
+}
+
+void
+set_value_width(w, new_width)
+    Widget w;
+    int new_width;
+{
+    Arg args[1];
+    Widget val;
+
+    val = XtNameToWidget(w, WVALUE);
+    XtSetArg(args[0], XtNwidth, new_width);
+    XtSetValues(val, args, ONE);
+}
+
+int
+get_value_width(w)
+    Widget w;
+{
+    Arg args[1];
+    Widget val;
+    Dimension width;
+
+    val = XtNameToWidget(w, WVALUE);
+    XtSetArg(args[0], XtNwidth, &width);
+    XtGetValues(val, args, ONE);
+    return (int) width;
+}
+
+/* Swap foreground and background colors (this is the best I can do with */
+/* a label widget, unless I can get some init hook in there).           */
+void
+hilight_value(w)
+    Widget w;
+{
+    swap_fg_bg(XtNameToWidget(w, WVALUE));
+}
+
+/* Swap the foreground and background colors of the given widget */
+void
+swap_fg_bg(w)
+    Widget w;
+{
+    Arg args[2];
+    Pixel fg, bg;
+
+    XtSetArg(args[0], XtNforeground, &fg);
+    XtSetArg(args[1], XtNbackground, &bg);
+    XtGetValues(w, args, TWO);
+
+    XtSetArg(args[0], XtNforeground, bg);
+    XtSetArg(args[1], XtNbackground, fg);
+    XtSetValues(w, args, TWO);
+}
+
diff --git a/win/gem/Install.gem b/win/gem/Install.gem
new file mode 100644 (file)
index 0000000..e341237
--- /dev/null
@@ -0,0 +1,38 @@
+Hi,
+
+This is nethack3.4.1 for Atari Gem and tty
+Windowing System.
+
+It is by far not complete or perfect.
+(My english too :-))
+
+You need at least 2Meg free RAM,  16 colors and
+3 Meg free Disk space.
+In fact it works also with monochrome, but you
+have to create a nh2.img (and title2.img) on your own.
+
+Atari windowport changes from 3.3.0:
+added a ASCII-Mode in GEM   -> F2
+the cursor is switchable    -> F3
+added inventory/menu search -> :
+removed the redraw problem
+removed almost all flicker (except with NOVA-Card :-()
+placed the GEM-dialogues more pleasent
+tty corner windows (i.e. inv) display now correct in a vt52-win
+greyed out old messages
+placed the GEM-windows more convient
+...
+
+Feel free to contact me about Issues and Errors.
+e-mail: gaston@cs.tu-berlin.de
+
+You use this program at your own risk, I can't 
+guarantee it will work or do you no harm.
+
+Look at the nethack licence too.
+
+As you may have noticed the look and feel is from
+Warwick Allisons nethack3.1.3d Gem Version
+and I have used E_Gem2.2.0 from Christian Grunenberg.
+
+Marvin
diff --git a/win/gem/bitmfile.c b/win/gem/bitmfile.c
new file mode 100644 (file)
index 0000000..13e0073
--- /dev/null
@@ -0,0 +1,340 @@
+/****************************\
+* Bitmap mit Farbtabelle als *
+* Graphik-Datei speichern               *
+* Autor: Gabriel Schmidt                *
+* (c) 1992 by MAXON-Computer *
+* Modifiziert von Sebastian     *
+* Bieber, Dez. 1994                                     *
+* -> Programmcode                                               *
+\****************************/
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "bitmfile.h"
+
+/* --- (X) IMG-Implementation ----------------- */
+
+#define IMG_COMPRESSED
+
+typedef struct
+       {
+       UWORD img_version;
+       UWORD img_headlen;
+       UWORD img_nplanes;
+       UWORD img_patlen;
+       UWORD img_pixw;
+       UWORD img_pixh;
+       UWORD img_w;
+       UWORD img_h;
+       } IMG_HEADER;
+
+typedef enum {NONE, SOLID0, SOLID1, PATRUN, BITSTR} IMG_MODE;
+
+typedef UBYTE IMG_SOLID;
+
+typedef enum { RGB=0, CMY=1, Pantone=2 } XIMG_COLMODEL;
+
+typedef struct
+       {
+       ULONG img_ximg;
+       XIMG_COLMODEL img_colmodel;
+       } XIMG_HEADER;
+
+typedef struct RGB XIMG_RGB;
+
+
+int bitmap_to_img(FILE_TYP typ,        int ww, int wh,
+                                                                       unsigned int pixw, unsigned int pixh,
+                                                                       unsigned int planes, unsigned int colors,
+                                                                       const char *filename,
+                                                                       void(*get_color)(unsigned int colind, struct RGB *rgb),
+                                                                       void(*get_pixel)(int x, int y, unsigned int *colind) )
+       {
+       int file, error, cnt;
+       IMG_HEADER header;
+       XIMG_HEADER xheader;
+       XIMG_RGB xrgb;
+       IMG_MODE mode;
+       UBYTE *line_buf, *write_buf;
+       register UBYTE *startpnt, *bufpnt;
+       unsigned int colind, line_len, line, bit;
+       register unsigned int byte;
+       register UBYTE count;
+
+       /* fill in (X) IMG-Header */
+
+       header.img_version = 1;
+       header.img_headlen = (UWORD) sizeof(header) /2;
+       if (typ == XIMG)
+               header.img_headlen += (UWORD)(sizeof(xheader)+colors*sizeof(xrgb))/2;
+
+       header.img_nplanes      = planes;
+       header.img_patlen               = 2;
+       header.img_pixw                 = pixw;
+       header.img_pixh                 = pixh;
+       header.img_w                            = ww;
+       header.img_h                            = wh;
+
+       xheader.img_ximg                = XIMG_MAGIC;
+       xheader.img_colmodel= RGB;
+
+       /* calculate linelength, allocate buffer. */
+
+       line_len        = (ww+7)/8;
+
+       line_buf        = malloc((size_t)planes*line_len);
+       if (line_buf == NULL)
+               return(ENOMEM);
+
+       /* Worst case: the bufferd line could grow to max. 3 times the length */
+       /* of the original!                                                                                                                                     */
+
+       write_buf = malloc((size_t)3*line_len);
+       if (write_buf == NULL)
+               {
+               free(line_buf);
+               return(ENOMEM);
+               };
+
+       /* open file */
+
+       file = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
+       if (file<0)
+               {
+               error = errno;
+               free(line_buf);
+               free(write_buf);
+               return(error);
+               };
+
+       /* write Header */
+
+       if (write (file, &header, sizeof(header)) != sizeof(header) ||
+                 (typ == XIMG &&       write (file, &xheader, sizeof(xheader) ) != sizeof(xheader)))
+                       {
+                       error = errno;
+                       close(file);
+                       free(line_buf);
+                       free(write_buf);
+                       return(error);
+                       };
+
+       /* save the colortable if possible */
+
+       if ( typ == XIMG )
+       for (cnt=0; cnt<colors; cnt++)
+               {
+               get_color(cnt,&xrgb);
+               if (write(file,&xrgb,sizeof(xrgb)) != sizeof(xrgb))
+                       {
+                       error = errno;
+                       close(file);
+                       free(line_buf);
+                       free(write_buf);
+                       return(error);
+                       };
+               };
+
+       /* And now line by line ... */
+
+       for (line=0; line<wh; line++)
+               {
+               /* get pixel, split it up and */
+               /* store it as planes in buffer */
+
+               for (byte=0; byte<line_len; byte++)
+                       {
+                       for (cnt=0; cnt<planes; cnt++)
+                               line_buf[cnt*line_len+byte] = 0x00;
+
+                       for (bit=0; bit<8; bit++)
+                               {
+                               if (8*byte+bit < ww)
+                                       get_pixel(8*byte+bit, line, &colind);
+
+                               for (cnt=0; cnt<planes; cnt++)
+                                       {
+                                       line_buf[cnt*line_len+byte] <<= 1;
+                                       line_buf[cnt*line_len+byte]  |= colind & 0x01;
+                                       colind >>= 1;
+                                       };
+                               };
+                       };
+
+               /* compress bitstrings in buffer */
+               /* and write it to file        */
+
+               for (cnt=0; cnt<planes; cnt++)
+                       {
+                       /* Bitstringpointer to start of plane */
+
+                       startpnt = &line_buf[cnt*line_len];
+                       bufpnt = write_buf;
+
+                       while (startpnt < &line_buf[(cnt+1)*line_len])
+                               {
+                               /*********************************************/
+                               /* Which _new_ compression-mode "fits" the      */
+                               /* the current byte?                                                                    */
+                               /* Note: the compressing modes get choosen      */
+                               /* "positive". The non compressing BITSTR-      */
+                               /* mode is choosen only if nothing else                 */
+                               /* "fits" ...                                                                                   */
+                               /*********************************************/
+
+                               switch (*startpnt)
+                                       {
+                                       case 0x00:
+                                               mode = SOLID0;
+                                               break;
+                                       case 0xFF:
+                                               mode = SOLID1;
+                                               break;
+                                       default:
+                                               if ( startpnt   <  &line_buf[(cnt+1)*line_len-3] &&
+                                                               *(startpnt)   == *(startpnt+2)                                           &&
+                                                               *(startpnt+1) == *(startpnt+3)                                           )
+                                                       mode = PATRUN;
+                                               else
+                                                       mode = BITSTR;
+                                       };
+
+                               /************************************************/
+                               /* The mode is choosen, now work with it.                       */
+                               /* The compressing modi stay current as long as */
+                               /* possible.                                                                                            */
+                               /************************************************/
+
+                               count = 0;
+
+                               switch (mode)
+                                       {
+                                       case SOLID0:
+                                               while ( (startpnt < &line_buf[(cnt+1)*line_len])        &&
+                                                                               (*(startpnt)==0x00)                                                                                     &&
+                                                                               (count < 0x7F)                                                                                                          )
+                                                                       {
+                                                                       startpnt++;
+                                                                       count++;
+                                                                       };
+                                               *(bufpnt++) = count;
+                                               break;
+
+                                       case SOLID1:
+                                               while ( (startpnt < &line_buf[(cnt+1)*line_len])        &&
+                                                                               (*(startpnt)==0xFF)                                                                                     &&
+                                                                               (count < 0x7F)                                                                                                          )
+                                                                       {
+                                                                       startpnt++;
+                                                                       count++;
+                                                                       };
+                                               *(bufpnt++) = 0x80 | count;
+                                               break;
+
+                                       case PATRUN:
+                                               *(bufpnt++) = 0x00;
+                                               startpnt += 2;
+                                               count = 1;
+                                               while ( startpnt < &line_buf[(cnt+1)*line_len-1]        &&
+                                                                               *(startpnt)             == *(startpnt-2)                                                &&
+                                                                               *(startpnt+1)   == *(startpnt-1)                                                &&
+                                                                               (count < 0xFF)                                                                                                          )
+                                                                       {
+                                                                       count++;
+                                                                       startpnt += 2;
+                                                                       };
+                                               *(bufpnt++) = count;
+                                               *(bufpnt++) = *(startpnt-2);
+                                               *(bufpnt++) = *(startpnt-1);
+                                               break;
+
+                                       /************************************************/
+                                       /* The while Condition is ment as follows:              */
+                                       /*                                                                                                                                                                                      */
+                                       /* while ( NOT(2-Byte-Solidrun possible)        &&              */
+                                       /*                       NOT(6-Byte-Patternrun possible)        &&              */
+                                       /*                               count < 0xFF                                                                           &&              */
+                                       /*                       still Bytes remaining                  )                       */
+                                       /*                                                                                                                                                                                      */
+                                       /* As soon as a _compressing_ alternative       shows   */
+                                       /* up, BITSTR gets cancelled!                                                   */
+                                       /************************************************/
+
+                                       case BITSTR:
+                                               *(bufpnt++) = 0x80;
+                                               while ( !(((startpnt+count)<&line_buf[(cnt+1)*line_len-1])&&
+                                                                                       (((*(startpnt+count)==0xFF) && (*(startpnt+count+1)==0xFF))||
+                                                                                        ((*(startpnt+count)==0x00) && (*(startpnt+count+1)==0x00))))           &&
+                                                                               !(((startpnt+count)<&line_buf[(cnt+1)*line_len-5])&&
+                                                                                       (*(startpnt+count)   == *(startpnt+count+2))&&
+                                                                                       (*(startpnt+count+1) == *(startpnt+count+3))&&
+                                                                                       (*(startpnt+count)   == *(startpnt+count+4))&&
+                                                                                       (*(startpnt+count+1) == *(startpnt+count+5)))                                                                                           &&
+                                                                               (count < 0xFF)                                                                                                                                                                                                                          &&
+                                                                               ((startpnt+count) < &line_buf[(cnt+1)*line_len])                                                                                        )
+                                                                               count++;
+                                               *(bufpnt++) = count;
+                                               for(; count>0; count--)
+                                                       *(bufpnt++) = *(startpnt++);
+                                               break;
+                                       };
+                               };
+
+                       if (write(file,write_buf,bufpnt-write_buf) != (bufpnt-write_buf))
+                               {
+                               error = errno;
+                               close(file);
+                               free(line_buf);
+                               free(write_buf);
+                               return(error);
+                               };
+
+                       };
+               };
+
+       /*close file, free buffer. */
+
+       close(file);
+       free(line_buf);
+       free(write_buf);
+       return(0);
+
+}
+
+/*---filetype-dispatcher--------------------*/
+
+const char *get_file_ext(FILE_TYP typ)
+       {
+       switch (typ)
+               {
+               case IMG:
+               case XIMG:
+                       return("IMG");
+               default:
+                       return("");
+               };
+}
+
+
+int bitmap_to_file(FILE_TYP typ, int ww, int wh,
+                                                                        unsigned int pwx, unsigned int pwy,
+                                                                        unsigned int planes, unsigned int colors,
+                                                                        const char *filename,
+                                                                        void (*get_color)(unsigned int colind, struct RGB *rgb),
+                                                                        void (*get_pixel)(int x, int y, unsigned int *colind))
+       {
+
+       switch (typ)
+               {
+               case IMG:
+               case XIMG:
+                       return(bitmap_to_img(typ,ww,wh,pwx,pwy,planes,colors,filename,get_color,get_pixel));
+               default:
+                       return(-1);
+               };
+}
+
diff --git a/win/gem/gem_rsc.uu b/win/gem/gem_rsc.uu
new file mode 100644 (file)
index 0000000..32b3900
--- /dev/null
@@ -0,0 +1,230 @@
+begin 777 GEM_RSC.RSC
+M  $29@^Z$B(/N@^Z #0)&@^Z)]X Y0 , !8  @       "@.            
+M         "!.151(04-+ "!'86UE "!(97)E "!4:&5R90 @271E;0 @07!P
+M87)E;  @36%G:6, ("!!8F]U="!.971H86-K+BXN "TM+2TM+2TM+2TM+2TM
+M+2TM+2TM+2T ("!$97-K($%C8V5S<V]R>2 Q("  ("!$97-K($%C8V5S<V]R
+M>2 R("  ("!$97-K($%C8V5S<V]R>2 S("  ("!$97-K($%C8V5S<V]R>2 T
+M("  ("!$97-K($%C8V5S<V]R>2 U("  ("!$97-K($%C8V5S<V]R>2 V("  
+M("!(96QP+BXN(" @(" @(" @/P @(%=H870@:7,N+BX@(" @(" O " @0V]M
+M;6%N9"!H96QP+BXN("8 +2TM+2TM+2TM+2TM+2TM+2TM+2TM " @3W!T:6]N
+M<RXN+B @(" @($\ ("!$:7-C;W9E<GD@;6]D92 @6  M+2TM+2TM+2TM+2TM
+M+2TM+2TM+2T ("!3879E("8@475I=" @(" @4P M+2TM+2TM+2TM+2TM+2TM
+M+2TM+2T ("!1=6ET(" @(" @(" @(" %<0 @(%)E<W0@(" @(" @(" @("X 
+M("!,;V]K(&1O=VX@(" @(" Z " @1V5T(" @(" @(" @(" @+  @(%-I=" @
+M(" @(" @(" @!7, ("!7:7!E(&9A8V4@(" @( 5W " @57-E(&%B:6QI='D@
+M(" %;0 @(%!A>2!S:&]P(" @(" @('  +2TM+2TM+2TM+2TM+2TM+2TM+2T 
+M("!5<" @(" @(" @(" @(" \ " @1&]W;B @(" @(" @(" @/@ M+2TM+2TM
+M+2TM+2TM+2TM+2TM+0 @($9O<F-E(&QO8VL@(" @!68 ("!,;V]T(&)O>" @
+M(" @( 5L " @16YG<F%V92!F;&]O<B @10 @($%G86EN(" @("!>00 M+2TM
+M+2TM+2TM+2TM+2TM " @3&]O:R!A=" @(" [ " @4V5A<F-H(" @("!S " @
+M3W!E;B @(" @("!O " @0VQO<V4@(" @("!C " @2VEC:R @(" @(%Y$ " @
+M56YT<F%P(" @( 5U " @06)O=70@=')A<"!> " @2G5M<" @(" @( 5J " @
+M0VAA=" @(" @( 5C " @1FEG:'0@(" @("!& " @4VAO=R!A;&P@(" @("!I
+M " @4VAO=R!K:6YD(" @("!) " @1&ES8V]V97)I97,@("!< "TM+2TM+2TM
+M+2TM+2TM+2TM+2T ("!%870@(" @(" @(" @(&4 ("!$<FEN:R @(" @(" @
+M('$ ("!!<'!L>2 @(" @(" @(&$ ("!5<V5D('1O;VQS(" @("@ ("!0<F]J
+M96-T:6QE(" @('0 ("!$<F]P(" @(" @(" @(&0 ("!$<F]P(&MI;F0@(" @
+M($0 ("!$:7 @(" @(" @(" @!60 +2TM+2TM+2TM+2TM+2TM+2TM+0 @($YA
+M;64@:71E;2 @(" %3@ @($YA;64@;6]N<W1E<B @0P @(%=I96QD('=E87!O
+M;B @(" @=P @(%-W:71C:"!W96%P;VYS(" @>  @($9I;&P@<75I=F5R(" @
+M(" @40 @($9I<F4@*'%U:79E<BD@(" @9@ @(%-H;W<@=V5A<&]N(" @(" @
+M*0 @($5N:&%N8V4@<VMI;&P@(" %90 M+2TM+2TM+2TM+2TM+2TM+2TM+2TM
+M " @5V5A<B!A<FUO=7(@(" @("!7 " @4F5M;W9E(&%R;6]U<B @("!4 " @
+M4F5M;W9E(&%L;" @(" @("!! " @5V]R;B!A<FUO<B @(" @("!; "TM+2TM
+M+2TM+2TM+2TM+2TM+2TM+2T ("!796%R(&%C8V5S<V]R>2 @(%  ("!296UO
+M=F4@86-C97-S;W)Y(%( ("!7;W)N(')I;F=S(" @(" @(#T ("!7;W)N(&%M
+M=6QE=" @(" @("( ("!,:7-T('-P96QL<R @*P M+2TM+2TM+2TM+2TM+2TM
+M+2T ("!:87 @=V%N9" @(" @>@ @($-A<W0@<W!E;&P@("!: " @4F5A9" @
+M(" @(" @('( ("!1=6%F9B @(" @(" @<0 @(%1E;&5P;W)T(" @(%Y4 " @
+M26YV;VME(" @(" @!6D ("!4=7)N('5N9&5A9" %=  @(%!R87D@(" @(" @
+M( 5P " @4V%C<FEF:6-E(" @!6\ ("!2=6(@;&%M<" @(" %<@!/2P  3F5T
+M2&%C:P!#;W!Y<FEG:'0@O2 Q.3@U+3(P,#  4W1I8VAT:6YG($UA=&AE;6%T
+M:7-C:"!#96YT<G5M &%N9"!-+B!3=&5P:&5N<V]N %-E92!L:6-E;G-E(&9O
+M<B!D971A:6QS+@!'14T@26YT97)F86-E(&)Y($-H<FES=&EA;B!"<F5S<VQE
+M<B!W:71H($4M1V5M    0V]N=&%C=#H@9V%S=&]N0&-S+G1U+6)E<FQI;BYD
+M90   $-A;F-E; !;4')O;7!T70   #\ /P _ #\ /P _ #\ /P _ #\ /P _
+M #\ /P _ #\ /P _ #\ /P _ #\ /P _ #\ /P!  $-H;VEC93H@7P!8 $]+
+M #DY.3D 0V]U;G0Z(%]?7U\ .0!/2P!;4')O;7!T70   $! 0$! 0$! 0$! 
+M0$! 0$! 0$! 0$! 0$! 0$! 0$! 0$! 0$! 0$! 0$! 0$! 0$! 0$!  %]?
+M7U]?7U]?7U]?7U]?7U]?7U]?7U]?7U]?7U]?7U]?7U]?7U]?7U]?7U]?7U]?
+M7U]?7U]? %@ 0V%N8V5L $]+ #$    R    ,P   #0    U    -@   #< 
+M   X    .0   $1/5TX@/@   %50(#P   !7:&\@87)T('1H;W4L('1R879E
+M;&QE<C\   ! 0$! 0$! 0$!  %]?7U]?7U]?7U\ 6 !/2P   "A024-455)%
+M($E.(#8T,'@T.# @34]$15,I    36]R90!.151(04-+ /[___________\ 
+M____________ /___________P#___________\ X          ' .      
+M    !P#@          < X          ' .          !P#@          < 
+MX  0    "  ' .  &    !@ !P#@ !X   !X  < X'P3X  ?R#X' .!$$#^#
+M\ @B!P#@;!  _@ (-@< X#@0    "!P' . H$     @4!P#@.!     (' < 
+MX"@0    "!0' . X$     @<!P#@*!     (% < X?\0"  ("/^' ./_D!P(
+M' G_QP#B.) >'#P)'$< X#@0/YS^"!P' . X$#_=_@@<!P#@.!!___\(' < 
+MX#@0?___"!P' . X$'___P@<!P#@.!!___\(' < X#@0?___"!P' . X$#_=
+M_@@<!P#@.! _G/X(' < X#@0'AP\"!P' . X$!P<' @<!P#@.! (' @(' < 
+MX#@0 !P "!P' . X$  <  @<!P#@.!  '  (' < X#@0 !P "!P' . X$  <
+M  @<!P#@.!  '  (' < X#@0 !P "!P' . X$  <  @<!P#@.!  %  (' < 
+MX#@0 !P "!P' . 0&  4  @(!P#@$ P '  8" < X  & !0 ,  ' .   P <
+M &  !P#@  & % #   < X   P!P!@  ' .   & V P (!P#@$  P(@8 20< 
+MX)( &#X, #8' .!L  P &  B!P#@1  & #  P8< X8,  P!@ "(' .!$  & 
+MP  V!P#@;   P8  20< X)(  '\   @' . 0        !P#@          < 
+MX          ' .          !P#@          < X          ' /______
+M_____P#___________\ ____________ /___________P              
+M                                                            
+M                                                            
+M                                                            
+M                                                            
+M                                                            
+M                                                            
+M                                                            
+M                                                            
+M                                                            
+M                                                            
+M                                                            
+M                                                            
+M                                                            
+M                                                            
+M                                                            
+M                                                          \\
+M// ))"28">?GF @  !@)__^8"0  F D 59@)  "8"0!5F D  )@) 168"0  
+MF D%!9@$@ $X!($5, 2  3 "0%9P D "8 $@5.  D G  $A3@  D)P  $DX 
+M  F<   $.    G    '                             #SP\\ \\//@/
+M___X#___^ ____@/  #X#U55^ \  /@/557X#P  ^ ]55?@/  #X#U55^ > 
+M ?@'U57P!X !\ /55_ #P /@ ?47X #P#\  ?5^  #P_   ??@  #_P   ?X
+M   #\    <                     '0   !V\   =P  4 !@ "$8   /__
+M "\  0  !W$   >1   'D@ %  8  A&   #__P @  $   >:   'HP  !Z0 
+M P &   0    __\ "0 !   'V0  !]L   ?E  , !@ "$8   /__  ( "@  
+M!^H   ?O   '^P #  8  A&   #__P %  P   @    ("0  " H  P &   0
+M    __\ "0 !   ("P  "$$   AW  , !@ "$8   /__ #8 -@  "(,   B%
+M   (A@ #  8  A$   #__@ "  $   B'   (B0  "(H  P &  (1    __X 
+M @ !   (BP  "(T   B.  , !@ "$0   /_^  (  0  "(\   B1   (D@ #
+M  8  A$   #__@ "  $   B3   (E0  ")8  P &  (1    __X  @ !   (
+MEP  ")D   B:  , !@ "$0   /_^  (  0  ")L   B=   (G@ #  8  A$ 
+M  #__@ "  $   B?   (H0  "*(  P &  (1    __X  @ !   (HP  "*4 
+M  BF  , !@ "$0   /_^  (  0  "*<   BN   (KP %  8  A&   #__P '
+M  $   BP   (M0  "+8 !0 &  (1@   __\ !0 !   (MP  "-    C1  , 
+M!@ "$P,  /__ !D  0  "-(   C=   (Z  #  8  I!Y  #__P +  L   CJ
+M   ([0  ".X  P &  (0>     $  P !   ([P  "0H   D+  , !@ "$0$ 
+M /__ !L  0  "^H   D:   &URD             4 !(          @   \Z
+M   .N@  "1$0        !P   "  (  ! "  +0 (__\  0 * !D         
+M        :  9  H  @ " !0        1        : ,!  $  P ) !D     
+M       "    ,@,!  3_____ "          -       "0,!  7_____ "  
+M        /0 )    !@,!  ;_____ "          0P /    !@,!  ?_____
+M "          20 5    !P,!  C_____ "          4  <    !@,!  G_
+M____ "          5@ B    "0,!  +_____ "          7P K    !P,!
+M    "P!< !D              P$ 40 3 !0 #  3 !0      /\1   "    
+M%@ (  W_____ !P         9@      %@ !  [_____ !P    (    >0  
+M  $ %@ !  ______ !P         D     ( %@ ! !#_____ !P         
+MI0    , %@ ! !'_____ !P         N@    0 %@ ! !+_____ !P     
+M    SP    4 %@ ! !/_____ !P         Y     8 %@ !  O_____ !P 
+M        ^0    < %@ ! !\ %0 > !0      /\1   +    %0 * !;_____
+M !P        !#@      %0 ! !?_____ !P        !(@    $ %0 ! !C_
+M____ !P        !-@    ( %0 ! !G_____ !P    (   !2@    , %0 !
+M !K_____ !P        !8     0 %0 ! !O_____ !P        !=     4 
+M%0 ! !S_____ !P    (   !B     8 %0 ! !W_____ !P        !G@  
+M  < %0 ! ![_____ !P    (   !L@    @ %0 ! !3_____ !P        !
+MR     D %0 ! "X (  M !0      /\1   1    %  . "'_____ !P     
+M   !W       %  ! "+_____ !P        ![P    $ %  ! "/_____ !P 
+M       " @    ( %  ! "3_____ !P        "%0    , %  ! "7_____
+M !P        "*     0 %  ! ";_____ !P        ".P    4 %  ! "?_
+M____ !P        "3@    8 %  ! "C_____ !P    (   "80    < %  !
+M "G_____ !P        "=@    @ %  ! "K_____ !P        "B0    D 
+M%  ! "O_____ !P    (   "G     H %  ! "S_____ !P        "L0  
+M  L %  ! "W_____ !P        "Q     P %  ! !______ !P        "
+MUP    T %  ! #L +P Z !0      /\1   7    $  , ##_____ !P     
+M   "Z@      $  ! #'_____ !P    (   "^0    $ $  ! #+_____ !P 
+M       #"@    ( $  ! #/_____ !P        #&0    , $  ! #3_____
+M !P        #*     0 $  ! #7_____ !P        #-P    4 $  ! #;_
+M____ !P        #1@    8 $  ! #?_____ !P        #50    < $  !
+M #C_____ !P        #9     @ $  ! #G_____ !P        #<P    D 
+M$  ! #K_____ !P        #@@    H $  ! "[_____ !P        #D0  
+M  L $  ! $L / !* !0      /\1   >    $P / #W_____ !P        #
+MH       $P ! #[_____ !P        #L@    $ $P ! #______ !P     
+M   #Q     ( $P ! $#_____ !P    (   #U@    , $P ! $'_____ !P 
+M       #Z@    0 $P ! $+_____ !P        #_     4 $P ! $/_____
+M !P        $#@    8 $P ! $3_____ !P        $(     < $P ! $7_
+M____ !P        $,@    @ $P ! $;_____ !P        $1     D $P !
+M $?_____ !P        $5@    H $P ! $C_____ !P        $:     L 
+M$P ! $G_____ !P    (   $>@    P $P ! $K_____ !P        $C@  
+M  T $P ! #O_____ !P        $H     X $P ! %P 3 !; !0      /\1
+M   D    %@ 0 $W_____ !P        $L@      %@ ! $[_____ !P     
+M   $QP    $ %@ ! $______ !P        $W     ( %@ ! %#_____ !P 
+M       $\0    , %@ ! %'_____ !P        %!@    0 %@ ! %+_____
+M !P        %&P    4 %@ ! %/_____ !P    (   %,     8 %@ ! %3_
+M____ !P        %1P    < %@ ! %7_____ !P        %7     @ %@ !
+M %;_____ !P        %<0    D %@ ! %?_____ !P        %A@    H 
+M%@ ! %C_____ !P    (   %FP    L %@ ! %G_____ !P        %L@  
+M  P %@ ! %K_____ !P        %QP    T %@ ! %O_____ !P        %
+MW     X %@ ! $O_____ !P        %\0    \ %@ !  H 70!H !0     
+M /\1   M    $@ , %[_____ !P        &!@      $@ ! %______ !P 
+M   (   &%P    $ $@ ! &#_____ !P        &*@    ( $@ ! &'_____
+M !P        &.P    , $@ ! &+_____ !P        &3     0 $@ ! &/_
+M____ !P        &70    4 $@ ! &3_____ !P        &;@    8 $@ !
+M &7_____ !P        &?P    < $@ ! &;_____ !P        &D     @ 
+M$@ ! &?_____ !P        &H0    D $@ ! &C_____ !P        &L@  
+M  H $@ ! %S_____ !P (      &PP    L $@ !__\  0 ! !0        1
+M      4 3P "  #_____"Q0 8     $1>0       @ "__\  0 ! !0     
+M  $1   "  $ H  5  #_____ !D (     $A   1  ,  @ !__\  0 *"Q0 
+M   0  (1   #  $ +@ *  +_____ !H,!P     &U  I  @$ P8!  4  P $
+M !0      /\1 0 !"   #0 '  3_____ !\        2(@ "" !0 %    +_
+M____ !P        &V  #" 4 !P !  ;_____ !P(       &X  /  $ %0 !
+M  ?_____ !P        &]@ /  , '@ !  C_____ !P        '%0 /  0 
+M$0 !  G_____ !P        ')P /  8 &  !  K_____ !4        /N@ !
+M# <$(@ !  #_____ !4 (      /U@ !" @ (0 !__\  0 ""Q0    0 /X1
+M>  !  ( 3P@6  +_____$QH,!P     'DP " !4 "  !  #_____ !@ (   
+M    ) (  @ &3@ 4__\  0 ["Q0    0  (1>  !  $ +  )  +_____ !4(
+M       /\@ "  $ "  ! #<  P U !0       $1>0 "  , * @#  4 !  $
+M !H,!0     'I0 !"    @ !  /_____!1D       $1         0 !  < 
+M!@ & !H,!0     'IP $"    @ !  7_____!1D       $1         0 !
+M  D "  ( !H,!0     'J0 '"    @ !  ?_____!1D       $1        
+M 0 !  L "@ * !H,!0     'JP *"    @ !  G_____!1D       $1    
+M     0 !  T #  , !H,!0     'K0 -"    @ !  O_____!1D       $1
+M         0 !  \ #@ . !H,!0     'KP 0"    @ !  W_____!1D     
+M  $1         0 ! !$ $  0 !H,!0     'L0 3"    @ !  ______!1D 
+M      $1         0 ! !, $@ 2 !H,!0     'LP 6"    @ ! !'_____
+M!1D       $1         0 ! !4 %  4 !H,!0     'M0 9"    @ ! !/_
+M____!1D       $1         0 ! !< %@ 6 !H,!0     'MP <"    @ !
+M !7_____!1D       $1         0 ! !D &  8 !H,!0     'N0 ?"   
+M @ ! !?_____!1D       $1         0 ! !L &@ : !H,!0     'NP B
+M"    @ ! !G_____!1D       $1         0 ! !T '  < !H,!0     '
+MO0 E"    @ ! !O_____!1D       $1         0 ! !\ '@ > !H,!0  
+M   'OP !  (  @ ! !W_____!1D       $1         0 ! "$ (  @ !H,
+M!0     'P0 $  (  @ ! !______!1D       $1         0 ! ", (@ B
+M !H,!0     'PP '  (  @ ! "'_____!1D       $1         0 ! "4 
+M)  D !H,!0     'Q0 *  (  @ ! "/_____!1D       $1         0 !
+M "< )@ F !H,!0     'QP -  (  @ ! "7_____!1D       $1        
+M 0 ! "D *  H !H,!0     'R0 0  (  @ ! "?_____!1D       $1    
+M     0 ! "L *@ J !H,!0     'RP 3  (  @ ! "G_____!1D       $1
+M         0 ! "T +  L !H,!0     'S0 6  (  @ ! "O_____!1D     
+M  $1         0 ! "\ +@ N !H,!0     'SP 9  (  @ ! "W_____!1D 
+M      $1         0 ! #$ ,  P !H,!0     'T0 <  (  @ ! "______
+M!1D       $1         0 ! #, ,@ R !H,!0     'TP ?  (  @ ! #'_
+M____!1D       $1         0 ! #4 -  T !H,!0     'U0 B  (  @ !
+M #/_____!1D       $1         0 !  ( -@ V !H,!0     'UP E  ( 
+M @ ! #7_____!1D       $1         0 ! #H .  Y !0       $1>0 #
+M  , %@ # #G_____ !X("      0#@ !  $ "P ! #?_____ !H,!P     '
+MYP -  $ !P ! #O_____ !X("      0*@ #  < #  !  #_____ !H,)0  
+M   '_0 1  < !@ !__\  0 $"Q0(   0  (1>  !  $ .P '  +_____ !4(
+M       01@ "  $ -P !  /_____ !X("      08@ "  , -P !  3_____
+M$QH$!0     (>0 #  4 "  !  #_____ !H,)P     (@  P  4 "  !__\ 
+M 0 9"Q0    0   1>  (  0 #  &  +_____ !L      0 6>  %     @ !
+M  /_____ !L     !  6>   " (  @ !  3_____ !L      P 6>  *" ( 
+M @ !  7_____ !L      @ 6>  %  4  @ !  < !@ & !8,!0     0?@ "
+M  0  @ !  7_____!1D       $1         0 !  D "  ( !8,!0     0
+MF@ %  0  @ !  ?_____!1D       $1         0 !  L "@ * !8,!0  
+M   0M@ (  0  @ !  G_____!1D       $1         0 !  T #  , !8,
+M!0     0T@ "" (  @ !  O_____!1D       $1         0 !  \ #@ .
+M !8,!0     0[@ %" (  @ !  W_____!1D       $1         0 ! !$ 
+M$  0 !8,!0     1"@ (" (  @ !  ______!1D       $1         0 !
+M !, $@ 2 !8,!0     1)@ "  $  @ ! !'_____!1D       $1        
+M 0 ! !4 %  4 !8,!0     10@ %  $  @ ! !/_____!1D       $1    
+M     0 ! !< %@ 6 !8,!0     17@ (  $  @ ! !7_____!1D       $1
+M         0 ! !D &  8 !8,!0     1>@ '! 4 !0P  !?_____!1D     
+M  $1   !     0P     &@ : !8,!0     1E@ '    !0P  !G_____!1D 
+M(     $1   !     0P __\  0 $ !0        1   !  4 3P #  +_____
+M !L, 0   0 6>0       @ !  /_____"Q0(      $1>0    $  @ !  3_
+M____ !L, 0   @ 6>0    (  @ !  #_____ !@ (       +  "    30 #
+M__\  0 $"Q0    0  (1>0 !  $ + @4  +_____ !4(       1L@   !  
+M+  !  /_____"AX "      1S@ . !( $  !  3_____ !8,!P     1Z@ A
+M !( "0@!  #_____ !8 (      2!@ "  $ * @,__\  0 !"Q0       $1
+M<@ #  , "  "  #_____ !H,)P     )#  !"   !@ !__\  0 ! !0 0  @
+M /\1>0 "  , !@ #  #_____ !\ (      21      P #     29@  '#X 
+G !QN   <G@  ':8  !WN   CC@  ) 8  ":.   G!@  )WX  ">N
+end
diff --git a/win/gem/gem_rso.uu b/win/gem/gem_rso.uu
new file mode 100644 (file)
index 0000000..cd555da
--- /dev/null
@@ -0,0 +1,22 @@
+begin 777 GEM_RSC.RSO
+M4E-/2    1(  @      "  ! !#__P  __\                         
+M                                                            
+M                                   '___^!____@              
+M      #__P    #__P                                          
+M                                                            
+M          /_   '___^!____@                     :1F]1)Y2KX@  
+M (\TJP     "!$U%3E4   P'1$]!0D]55   '@9$3U%5250 __\  0 #"E-4
+M05154TQ)3D4   $*1U)!0E-405154P#__P "  ,&34%05TE.    !DU!4$)/
+M6    0E-05!#55)33U( __\  P #!4%"3U54    "$9,64%"3U54   !!T]+
+M04)/550   ,+3D542$%#2TE-1S  __\ !  #!4Q)3D53    "$9,64Q)3D53
+M   !!5%,24Y%   ""4Q)3D533$E35 #__P %  ,(64Y#2$])0T4    +1DQ9
+M64Y#2$])0T4   $(64Y04D]-4%0   ()4T]-14-(05)3   # UE.,0  -0-9
+M3DX  #<'04Y90TA!4@  . A#2$]314Y#2   .@5#3U5.5   .P193D]+ /__
+M  8  P=,24Y%1T54    "D9,64Q)3D5'150   $(3$=04D]-4%0   ('3$=2
+M15!,60   P-13$<   0$3$=/2P#__P '  ,)1$E214-424].    #$9,641)
+M4D5#5$E/3@  !01$25(Q   5!$1)4CD  !<'1$E21$]73@  &05$25)54 #_
+M_P (  ,&35-'5TE.   !!55035-'   ""D=204)-4T=724X   ,%1$Y-4T< 
+M  0(35-'3$E.15, __\ "0 #!TY!345'150    *1DQ93D%-14=%5    @90
+M3$Y!344   0.3D542$%#2U!)0U154D4 __\ "@ #!5!!1T52    "$9,65!!
+@1T52   !!E%004=%4@#__P +  ,&3DA)0T]. /____\ 
+end
diff --git a/win/gem/gr_rect.c b/win/gem/gr_rect.c
new file mode 100644 (file)
index 0000000..0dbe49a
--- /dev/null
@@ -0,0 +1,181 @@
+/*     SCCS Id: @(#)gr_rect.c  3.4     2001/12/10                              */
+/* Copyright (c) Christian Bressler, 2001                                      */
+/* NetHack may be freely redistributed.  See license for details. */
+/* This is an almost exact copy of qt_clust.cpp */
+/* gr_rect.c */
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include "gr_rect.h"
+dirty_rect *new_dirty_rect(int size){
+       dirty_rect *new=NULL;
+       if(size>0){
+               new=(dirty_rect *)calloc(1L,sizeof(dirty_rect));
+               if(new){
+                       new->rects=(GRECT *)calloc((long)size,sizeof(GRECT));
+                       if(new->rects==NULL){
+                               free(new);
+                               return(NULL);
+                       }
+                       new->max=size;
+               }
+       }
+       return(new);
+}
+void delete_dirty_rect(dirty_rect *this){
+       if(this==NULL)
+               return;
+       if(this->rects)
+               free(this->rects);
+       /* In case the Pointer is reused wrongly */
+       this->rects=NULL;
+       this->max=0;
+       this->used=0;
+       free(this);
+}
+static int gc_inside(GRECT *frame,GRECT *test);
+static int gc_touch(GRECT *frame,GRECT *test);
+static void gc_combine(GRECT *frame,GRECT *test);
+static long gc_area(GRECT *area);
+int add_dirty_rect(dirty_rect *dr,GRECT *area){
+       int cursor;
+       long lowestcost=9999999L;
+       int cheapest=-1;
+       int cheapestmerge1=-1;
+       int cheapestmerge2=-1;
+       int merge1;
+       int merge2;
+       for (cursor=0; cursor<dr->used; cursor++) {
+               if (gc_inside(&dr->rects[cursor],area)) {
+                       /* Wholly contained already. */
+                       return(TRUE);
+               }
+       }
+       for (cursor=0; cursor<dr->used; cursor++) {
+               if (gc_touch(&dr->rects[cursor],area)) {
+                       GRECT larger=dr->rects[cursor];
+                       long cost;
+                       gc_combine(&larger,area);
+                       cost=gc_area(&larger)-gc_area(&dr->rects[cursor]);
+                       if (cost < lowestcost) {
+                               int bad=FALSE,c;
+                               for (c=0; c<dr->used && !bad; c++) {
+                                       bad=gc_touch(&dr->rects[c],&larger) && c!=cursor;
+                               }
+                               if (!bad) {
+                                       cheapest=cursor;
+                                       lowestcost=cost;
+                               }
+                       }
+               }
+       }
+       if (cheapest>=0) {
+               gc_combine(&dr->rects[cheapest],area);
+               return(TRUE);
+       }
+       if (dr->used < dr->max) {
+               dr->rects[dr->used++]=*area;
+               return(TRUE);
+       }
+       // Do cheapest of:
+       //      add to closest cluster
+       //      do cheapest cluster merge, add to new cluster
+       lowestcost=9999999L;
+       cheapest=-1;
+       for (cursor=0; cursor<dr->used; cursor++) {
+               GRECT larger=dr->rects[cursor];
+               long cost;
+               gc_combine(&larger,area);
+               cost=gc_area(&larger)-gc_area(&dr->rects[cursor]);
+               if (cost < lowestcost) {
+                       int bad=FALSE, c;
+                       for (c=0; c<dr->used && !bad; c++) {
+                               bad=gc_touch(&dr->rects[c],&larger) && c!=cursor;
+                       }
+                       if (!bad) {
+                               cheapest=cursor;
+                               lowestcost=cost;
+                       }
+               }
+       }
+       // XXX could make an heuristic guess as to whether we
+       // XXX need to bother looking for a cheap merge.
+       for (merge1=0; merge1<dr->used; merge1++) {
+               for (merge2=0; merge2<dr->used; merge2++) {
+                       if (merge1!=merge2) {
+                               GRECT larger=dr->rects[merge1];
+                               long cost;
+                               gc_combine(&larger,&dr->rects[merge2]);
+                               cost=gc_area(&larger)-gc_area(&dr->rects[merge1])-gc_area(&dr->rects[merge2]);
+                               if (cost < lowestcost) {
+                                       int bad=FALSE, c;
+                                       for (c=0; c<dr->used && !bad; c++) {
+                                               bad=gc_touch(&dr->rects[c],&larger) && c!=cursor;
+                                       }
+                                       if (!bad) {
+                                               cheapestmerge1=merge1;
+                                               cheapestmerge2=merge2;
+                                               lowestcost=cost;
+                                       }
+                               }
+                       }
+               }
+       }
+       if (cheapestmerge1>=0) {
+               gc_combine(&dr->rects[cheapestmerge1],&dr->rects[cheapestmerge2]);
+               dr->rects[cheapestmerge2]=dr->rects[dr->used-1];
+               dr->rects[dr->used-1]=*area;
+       } else {
+               gc_combine(&dr->rects[cheapest],area);
+       }
+       // NB: clusters do not intersect (or intersection will
+       //       overwrite).  This is a result of the above algorithm,
+       //       given the assumption that (x,y) are ordered topleft
+       //       to bottomright.
+       return(TRUE);
+}
+int get_dirty_rect(dirty_rect* dr,GRECT *area){
+       if(dr==NULL || area==NULL || dr->rects==NULL || dr->used<=0 || dr->max<=0)
+               return(FALSE);
+       *area=dr->rects[--dr->used];
+       return(TRUE);
+}
+int clear_dirty_rect(dirty_rect *dr){
+       if(dr)
+               dr->used=0;
+       return(TRUE);
+}
+int resize_dirty_rect(dirty_rect *dr,int new_size){
+       return(FALSE);
+}
+static int gc_inside(GRECT *frame,GRECT *test){
+       if(frame && test && frame->g_x<=test->g_x && frame->g_y<=test->g_y &&
+               frame->g_x+frame->g_w>=test->g_x+test->g_w &&
+               frame->g_y+frame->g_h>=test->g_y+test->g_h
+       )
+               return(TRUE);
+       return(FALSE);
+}
+static int gc_touch(GRECT *frame,GRECT *test){
+       GRECT tmp={test->g_x-1,test->g_y-1,test->g_w+2,test->g_h+2};
+       return(rc_intersect(frame,&tmp));
+}
+static void gc_combine(GRECT *frame,GRECT *test){
+       if(!frame || !test)
+               return;
+       if(frame->g_x>test->g_x){
+               frame->g_w+=frame->g_x-test->g_x;
+               frame->g_x=test->g_x;
+       }
+       if(frame->g_y>test->g_y){
+               frame->g_h+=frame->g_y-test->g_y;
+               frame->g_y=test->g_y;
+       }
+       if(frame->g_x+frame->g_w<test->g_x+test->g_w)
+               frame->g_w=test->g_x+test->g_w-frame->g_x;
+       if(frame->g_y+frame->g_h<test->g_y+test->g_h)
+               frame->g_h=test->g_y+test->g_h-frame->g_y;
+}
+static long gc_area(GRECT *area){
+       return((long)area->g_h*(long)area->g_w);
+}
diff --git a/win/gem/gr_rect.h b/win/gem/gr_rect.h
new file mode 100644 (file)
index 0000000..0e4a0bd
--- /dev/null
@@ -0,0 +1,14 @@
+/* gr_rect.h */
+#include <e_gem.h>
+/********** structs **********/
+typedef struct {
+       GRECT *rects;
+       int max,used;
+} dirty_rect;
+/********* functions ************/
+dirty_rect *new_dirty_rect(int size);
+void delete_dirty_rect(dirty_rect *this);
+int add_dirty_rect(dirty_rect *dr,GRECT *area);
+int get_dirty_rect(dirty_rect* dr,GRECT *area);
+int clear_dirty_rect(dirty_rect *dr);
+int resize_dirty_rect(dirty_rect *dr,int new_size);
diff --git a/win/gem/load_img.c b/win/gem/load_img.c
new file mode 100644 (file)
index 0000000..16d8fe8
--- /dev/null
@@ -0,0 +1,289 @@
+#define __TCC_COMPAT__
+#include <stdio.h>
+#include <string.h>
+#include <osbind.h>
+#include <memory.h>
+#include <aesbind.h>
+#include <vdibind.h>
+#include <gemfast.h>
+#include <e_gem.h>
+#include "load_img.h"
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE  !FALSE
+#endif
+
+/* VDI <-> Device palette order conversion matrixes: */
+/* Four-plane vdi-device */
+int vdi2dev4[]={0,15,1,2,4,6,3,5,7,8,9,10,12,14,11,13};
+/* Two-plane vdi-device */
+int vdi2dev2[]={0,3,1,2};
+
+void get_colors(int handle, short *palette, int col){
+       int i, idx;
+
+       /* get current color palette */
+       for(i=0; i < col; i ++){
+               /* device->vdi->device palette order */
+               switch(planes){
+               case 1:
+                       idx=i;break;
+               case 2:
+                       idx=vdi2dev2[i];break;
+               case 4:
+                       idx=vdi2dev4[i];break;
+               default:
+                       if(i<16)
+                               idx=vdi2dev4[i];
+                       else
+                               idx= i==255 ? 1 : i;
+               }
+               vq_color(handle, i, 0, (int *)palette + idx * 3);
+       }
+}
+
+void img_set_colors(int handle, short *palette, int col){
+       int i, idx, end;
+
+       /* set color palette */
+       end=min(1<<col,1<<planes);
+       for(i=0; i<end; i++){
+       switch(planes){ /* MAR -- war col 10.01.2001 */
+               case 1:
+               idx=i;break;
+               case 2:
+                       idx=vdi2dev2[i];break;
+               case 4:
+                       idx=vdi2dev4[i];break;
+               default:
+                       if(i<16)
+                               idx=vdi2dev4[i];
+                       else
+                               idx= i==255 ? 1 : i;
+    }
+    vs_color(handle, i, (int *)palette + idx * 3);
+  }
+}
+
+int convert(MFDB *image, long size){
+       int plane, mplanes;
+       char *line_addr, *buf_addr, *new_addr, *new1_addr, *image_addr, *screen_addr;
+       MFDB  dev_form, tmp;
+       long    new_size;
+
+       /* convert size from words to bytes */
+       size <<= 1;
+
+       /* memory for the device raster */
+       new_size=size*(long)planes;
+       if((new_addr=(char *) calloc(1,new_size)) == NULL)
+               return(FALSE);
+
+       /* initialize MFDBs */
+       tmp=*image;
+       tmp.fd_nplanes=planes;
+       tmp.fd_addr=new_addr;
+       tmp.fd_stand=1;             /* standard format */
+       dev_form=tmp;
+       screen_addr=new_addr;
+       dev_form.fd_stand=0;          /* device format */
+       image_addr=(char *)image->fd_addr;
+
+       /* initialize some variables and zero temp. line buffer */
+       mplanes=min(image->fd_nplanes, planes);
+       /* convert image */
+       line_addr=image_addr;
+       buf_addr=screen_addr;
+               if(mplanes>1){
+                       /* cut/pad color planes into temp buf */
+                       for(plane=0; plane<mplanes; plane ++){
+                       memcpy(buf_addr, line_addr, size);
+                               line_addr += size;
+                       buf_addr += size;
+                       }
+               }else{
+                       /* fill temp line bitplanes with a b&w line */
+                       for(plane=0; plane < planes; plane ++){
+                       memcpy(buf_addr, line_addr, size);
+                       buf_addr += size;
+                       }
+               }
+       free(image->fd_addr);
+               /* convert image line in temp into current device raster format */
+       if((new1_addr=(char *) calloc(1,new_size)) == NULL)
+               return(FALSE);
+       dev_form.fd_addr=new1_addr;
+               vr_trnfm(x_handle, &tmp, &dev_form);
+       free(new_addr);
+
+       /* change image description */
+       image->fd_stand=0;          /* device format */
+       image->fd_addr=new1_addr;
+       image->fd_nplanes=planes;
+       return(TRUE);
+}
+
+int transform_img(MFDB *image){                /* return FALSE if transform_img fails */
+       int success;
+       long size;
+
+       if(!image->fd_addr)
+               return(FALSE);
+
+       size=(long)((long)image->fd_wdwidth * (long)image->fd_h);
+       success=convert(image, size);           /* Use vr_trfm(), which needs quite a lot memory. */
+       if(success)             return(TRUE);
+/*     else                            show_error(ERR_ALLOC);  */
+       return(FALSE);
+}
+
+
+/* Loads & depacks IMG (0 if succeded, else error). */
+/* Bitplanes are one after another in address IMG_HEADER.addr. */
+int depack_img(char *name, IMG_header *pic){
+       int     b, line, plane, width, word_aligned, opcode, patt_len, pal_size,
+                       byte_repeat, patt_repeat, scan_repeat, error = FALSE;
+       char    *pattern, *to, *endline, *puffer, sol_pat;
+       long    size;
+       FILE *fp;
+
+       if((fp = fopen(name, "rb")) == NULL)
+               return(ERR_FILE);
+
+       setvbuf(fp,NULL,_IOLBF,BUFSIZ);
+
+       /* read header info (bw & ximg) into image structure */
+       fread((char *)&(pic->version), 2, 8 + 3, fp);
+
+       /* only 2-256 color imgs */
+       if(pic->planes < 1 || pic->planes > 8){
+               error = ERR_COLOR;
+               goto end_depack;
+       }
+
+       /* if XIMG, read info */
+       if(pic->magic == XIMG && pic->paltype == 0){
+               pal_size = (1 << pic->planes) * 3 * 2;
+               if((pic->palette = (short *)calloc(1,pal_size))){
+                       fread((char *)pic->palette, 1, pal_size, fp);
+               }
+       }else{
+               pic->palette = NULL;
+       }
+
+       /* width in bytes word aliged */
+       word_aligned = (pic->img_w + 15) >> 4;
+       word_aligned <<= 1;
+
+       /* width byte aligned */
+       width = (pic->img_w + 7) >> 3;
+
+       /* allocate memory for the picture */
+       free(pic->addr);
+       size = (long)((long)word_aligned * (long)pic->img_h * (long)pic->planes); /*MAR*/
+
+       /* check for header validity & malloc long... */
+       if (pic->length > 7 && pic->planes < 33 && pic->img_w > 0 && pic->img_h > 0){
+               if(!(pic->addr=(char *)calloc(1,size))){
+                       error = ERR_ALLOC;
+                       goto end_depack;
+               }
+       }else{
+               error = ERR_HEADER;
+               goto end_depack;
+       }
+
+       patt_len = pic->pat_len;
+
+       /* jump over the header and possible (XIMG) info */
+       fseek(fp, (long) pic->length * 2L, SEEK_SET);
+
+       for(line=0,to=pic->addr; line<pic->img_h; line+=scan_repeat){   /* depack whole img */
+               for(plane=0,scan_repeat=1; plane<pic->planes; plane++){ /* depack one scan line */
+                       puffer=to=pic->addr+(long)(line+plane*pic->img_h)*(long)word_aligned;
+                       endline=puffer+width;
+                       do{     /* depack one line in one bitplane */
+                               switch((opcode= fgetc(fp))){
+                               case 0: /* pattern or scan repeat */
+                                       if((patt_repeat=fgetc(fp))){    /* repeat a pattern */
+                                               fread(to,patt_len,1,fp);
+                                               pattern=to;
+                                               to+=patt_len;
+                                               while(--patt_repeat){   /* copy pattern */
+                                                       memcpy(to,pattern,patt_len);
+                                                       to+=patt_len;
+                                               }
+                                       }else{  /* repeat a line */
+                                               if(fgetc(fp)==0xFF)
+                                                       scan_repeat=fgetc(fp);
+                                               else{
+                                                       error = ERR_DEPACK;
+                                                       goto end_depack;
+                                               }
+                                       }
+                                       break;
+                               case 0x80:      /* Literal */
+                                       byte_repeat=fgetc(fp);
+                                       fread(to,byte_repeat,1,fp);
+                                       to+=byte_repeat;
+                                       break;
+                               default:        /* Solid run */
+                                       byte_repeat = opcode & 0x7F;
+                                       sol_pat = opcode&0x80 ? 0xFF : 0x00;
+                                       while(byte_repeat--)    *to++=sol_pat;
+                               }
+                       }while(to<endline);
+
+                       if(to == endline){
+                               /* ensure that lines aren't repeated past the end of the img */
+                               if(line + scan_repeat > pic->img_h)
+                                       scan_repeat = pic->img_h - line;
+                               /* copy line to image buffer */
+                               if(scan_repeat>1){
+                                       /* calculate address of a current line in a current bitplane */
+/*                                     to=pic->addr+(long)(line+1+plane*pic->img_h)*(long)word_aligned;*/
+                                       for(b=scan_repeat-1; b; --b){
+                                               memcpy(to, puffer, width);
+                                               to+=word_aligned;
+                                       }
+                               }
+                       }else{
+                               error = ERR_DEPACK;
+                               goto end_depack;
+                       }
+               }
+       }
+
+       end_depack:
+       fclose(fp);
+       return(error);
+}
+
+int half_img(MFDB *s, MFDB *d){
+       int pxy[8], i, j;
+       MFDB tmp;
+
+       mfdb(&tmp,NULL,s->fd_w/2,s->fd_h,s->fd_stand,s->fd_nplanes);
+       tmp.fd_w=s->fd_w/2;
+       tmp.fd_addr=calloc(1,mfdb_size(&tmp));
+       if(!tmp.fd_addr)
+               return(FALSE);
+
+       pxy[1]=pxy[5]=0;
+       pxy[3]=pxy[7]=s->fd_h-1;
+       for(i=0;i<s->fd_w/2;i++){
+               pxy[0]=pxy[2]=2*i;
+               pxy[4]=pxy[6]=i;
+               vro_cpyfm(x_handle,S_ONLY,pxy,s,&tmp);
+       }
+       pxy[0]=pxy[4]=0;
+       pxy[2]=pxy[6]=s->fd_w/2-1;
+       for(j=0;j<s->fd_h/2;j++){
+               pxy[1]=pxy[3]=2*j;
+               pxy[5]=pxy[7]=j;
+               vro_cpyfm(x_handle,S_ONLY,pxy,&tmp,d);
+       }
+       free(tmp.fd_addr);
+       return(TRUE);
+}
diff --git a/win/gem/tile2img.c b/win/gem/tile2img.c
new file mode 100644 (file)
index 0000000..fa52fed
--- /dev/null
@@ -0,0 +1,156 @@
+/*     SCCS Id: @(#)tile2bmp.c 3.2     95/09/06        */
+/*   Copyright (c) NetHack PC Development Team 1995                 */
+/*   NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Edit History:
+ *
+ *     Initial Creation                        M.Allison       94/01/11
+ * Marvin was here                     Marvin          97/01/11
+ *
+ */
+
+/* #include <stdlib.h> */
+#include "hack.h"
+#include "tile.h"
+#include "bitmfile.h"
+
+/* #define COLORS_IN_USE MAXCOLORMAPSIZE       /* 256 colors */
+#define COLORS_IN_USE 16                       /* 16 colors */
+
+
+extern char *FDECL(tilename, (int, int));
+static void FDECL(build_ximgtile,(pixel (*)[TILE_X]));
+void get_color(unsigned int colind, struct RGB *rgb);
+void get_pixel(int x, int y, unsigned int *colind);
+
+#if COLORS_IN_USE==16
+#define MAX_X 320              /* 2 per byte, 4 bits per pixel */
+#else
+#define MAX_X 640
+#endif
+#define MAX_Y 1200
+
+FILE *tibfile2;
+
+pixel tilepixels[TILE_Y][TILE_X];
+
+char *tilefiles[] = {  "..\\win\\share\\monsters.txt",
+                       "..\\win\\share\\objects.txt",
+                       "..\\win\\share\\other.txt"};
+
+unsigned int **Bild_daten;
+int num_colors = 0;
+int tilecount;
+int max_tiles_in_row = 40;
+int tiles_in_row;
+int filenum;
+int initflag;
+int yoffset,xoffset;
+char bmpname[128];
+FILE *fp;
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       int i;
+
+       if (argc != 2) {
+               Fprintf(stderr, "usage: tile2img outfile.img\n");
+               exit(EXIT_FAILURE);
+       } else
+               strcpy(bmpname, argv[1]);
+
+#ifdef OBSOLETE
+       bmpfile2 = fopen(NETHACK_PACKED_TILEFILE, WRBMODE);
+       if (bmpfile2 == (FILE *)0) {
+               Fprintf(stderr, "Unable to open output file %s\n",
+                               NETHACK_PACKED_TILEFILE);
+               exit(EXIT_FAILURE);
+       }
+#endif
+
+       tilecount = 0;
+       xoffset = yoffset = 0;
+       initflag = 0;
+       filenum = 0;
+       fp = fopen(bmpname,"wb");
+       if (!fp) {
+           printf("Error creating tile file %s, aborting.\n",bmpname);
+           exit(1);
+       }
+       fclose(fp);
+
+       Bild_daten=(unsigned int **)malloc(MAX_Y*sizeof(unsigned int *));
+       for(i=0;i<MAX_Y;i++)
+               Bild_daten[i]=(unsigned int *)malloc(MAX_X*sizeof(unsigned int));
+
+       while (filenum < 3) {
+               if (!fopen_text_file(tilefiles[filenum], RDTMODE)) {
+                       Fprintf(stderr,
+                               "usage: tile2img (from the util directory)\n");
+                       exit(EXIT_FAILURE);
+               }
+               num_colors = colorsinmap;
+               if (num_colors > 62) {
+                       Fprintf(stderr, "too many colors (%d)\n", num_colors);
+                       exit(EXIT_FAILURE);
+               }
+               while (read_text_tile(tilepixels)) {
+                       build_ximgtile(tilepixels);
+                       tilecount++;
+                       xoffset += TILE_X;
+                       if (xoffset >= MAX_X) {
+                               yoffset += TILE_Y;
+                               xoffset = 0;
+                       }
+               }
+               (void) fclose_text_file();
+               ++filenum;
+       }
+       Fprintf(stderr, "Total of %d tiles in memory.\n",tilecount);
+
+       bitmap_to_file(XIMG, MAX_X, (tilecount/20+1)*16, 372, 372, 4, 16, bmpname, get_color, get_pixel ) ;
+
+       Fprintf(stderr, "Total of %d tiles written to %s.\n",tilecount, bmpname);
+
+       exit(EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
+
+void get_color(unsigned int colind, struct RGB *rgb){
+       rgb->r=(1000L*(long)ColorMap[CM_RED][colind])/0xFF;
+       rgb->g=(1000L*(long)ColorMap[CM_GREEN][colind])/0xFF;
+       rgb->b=(1000L*(long)ColorMap[CM_BLUE][colind])/0xFF;
+}
+
+void get_pixel(int x, int y, unsigned int *colind){
+       *colind=Bild_daten[y][x];
+}
+
+static void
+build_ximgtile(pixels)
+pixel (*pixels)[TILE_X];
+{
+       int cur_x, cur_y, cur_color;
+       int x,y;
+
+       for (cur_y = 0; cur_y < TILE_Y; cur_y++) {
+               for (cur_x = 0; cur_x < TILE_X; cur_x++) {
+                   for (cur_color = 0; cur_color < num_colors; cur_color++) {
+                               if (ColorMap[CM_RED][cur_color] == pixels[cur_y][cur_x].r &&
+                                   ColorMap[CM_GREEN][cur_color] == pixels[cur_y][cur_x].g &&
+                                   ColorMap[CM_BLUE][cur_color] == pixels[cur_y][cur_x].b)
+                                       break;
+                   }
+                   if (cur_color >= num_colors)
+                               Fprintf(stderr, "color not in colormap!\n");
+                   y = cur_y + yoffset;
+                   x = cur_x + xoffset;
+                   Bild_daten[y][x] =cur_color;
+               }
+       }
+}
diff --git a/win/gem/title.uu b/win/gem/title.uu
new file mode 100644 (file)
index 0000000..9fda441
--- /dev/null
@@ -0,0 +1,426 @@
+begin 777 title.img
+M  $ .P $  $!= %T 4  R%A)34<   /H ^@#Z /H      &K ^@   /H ^@ 
+M       #Z /H   #Z    LH#Z &K CT"R@$: :L!JP+* 1H      CT   /H
+M :L   (] 1H   -; UL"R@/H LH"/0          _PDH*"BH!H ) ?_@'_^_
+M___'A( /_#_\!__X  _P#__P?__P!B@HAH )_@ ?X !    X!( / \ #^  '
+M__ /\  /@  /A@>!@ ?@#_^____'@X 0W_@?^ /_\  __ ?_X!__P 8H!X (
+M?\ '_Q___X.#@ ^/\ _P ?_@  ?P ?_ #_\'AX (?]_W_U___[N#@!"O]^_W
+M_?_O_\?S^?_?[_\_A@> "& P!@,8  #& X !V( .&!@8 8 P '@.$8# # ,'
+M* > "#_@ _X/__^#@X /C_ /\ #_X  ?_ #_@ ?^!X> "* O^@+H  "Z X /
+MJ!?H%_Z +_^8#>Z O_0"AP> "& P P8,  #& X /S# ,, & 8 #@ Q&!P P&
+M!R@'@ @_X '\!___@X. #X?@!^  _\  ?_X _X '_ >'@ B@+_T%]   N@. 
+M#[0O]"_^@%__8 +N@;_T!8<'@ @P, &&#   Q@. #\PP## !@& !P &Q@X ,
+M# <H!X ('^  _ ?__X.#@ ^'X ?@ /_  '__ /X !_@'AX (T"_^A?0  +H#
+M@ ^T+_0O_H!?_D !3H)_] N'!X (,#X!A_P  /X#@!#\/\P_P8!_@8  \8/_
+M&!__!@B !PX  ?   #@#@ @P#\ /P  ?@ 2! 8 "!_\&!X ('^X _??__[N#
+M@!"W[\?OP/_?@/__@/[_#_?_!H> "- O_H7T  "Z X /M"_T+_Z 7_Z  (Z"
+M_^@7AP6 "O@ ,!X!A_P  /X#@!#\/XP_@8!_ P  \8/^&#_\!@B !P8  ?  
+M #@#@ <P#X /@  ?!8 $_@ /_ 8%@ KX !_V /WW__^[@X 0M^^'[X#_WP'_
+M_Z#^_@_O_ :'@ C0%_Z%]   N@. #[0O]"_^@%_]  "N@O_H+X<%@ KX # ?
+M 8?\  #^ X 0_#^,/X, /P,!X'&#_#!_\ 8%@ H@   '  'P   X X ', ^ 
+M#X  #P6 !/P '_ &!8 *N  ?]P#]]___NX. $+?OA^^!_^\!___@_OP?W_ &
+MA8 *W__0%_Z%]   N@. #[0O]"_] "_] >!N@O_07X<%@!U\ # ? 8?L/_S^
+M?P'X_#\,/P, /@<'_#&#_&!_X 8%@ H0   '  '@   X X ', \ #P  #@6 
+M!/P '^ &!8 *'  ?]P#]Y___NX. $+?O!^\!_^X!_A_@_OP_W^ &A8 <[__0
+M%_Z%]#_\NG\!^+0O]"_] "_Y!APN@O^@7X<%@!T\ # / 8?L?__^_X/__#\,
+M/P, /@8/_CN#^&#_P 8%@ H0   #  '@   X X 0, \ #P  #@ !X H ^  _
+MP 8%@!T< !_[ /WGP .[@/X'M^\'[P'_[@/YX^K^^#^_P :%@!SO_] +_H7T
+M0 .Z@(('M"_T+_T +_H)XBZ"_Z"_AP6 "#P , \!A^Q_@X 2@__\/PP_ P ^
+M!A__/X/PP/^ !@6 '1@   ,  > ?_#A^ /@P#P /   .  ?X#@#P #^ !@6 
+M'1P '_L _>??_+M^_OBW[P?O ?_N _?Y[O[P?[^ !H6 '.?_T O^A?1?_+M^
+M@OBT+_0O_0 O^A?Y+H+_0+^'!8 </X P#X&'['___W^#__P_##\#!#X./_^_
+M@_&!_P<%@!P;@  #@ '@'_\X?@#_, \ #P  #@ /_@X \ !_!P6 '!^ '_N 
+M_>??_SI^_O\W[P?O ?_N ^_^[O[P_W\'A8 <Y__0"_Z%]%__.OZ"_S0O]"_]
+M!"_R+_ZN@OZ!?X<%@!P_@# /@8?L?__^?X/__#\,/P,.'PQ___^#\8/^!P6 
+M'!N   .  > ?_[A^ /^P#P /   ' !__#@#P /X'!8 <'X ?^X#]Y]__N'[^
+M_[?O!^\!^_<'W_]N_O#^_@>%@!OG_] +_H7T7_^Y_H+_M"_T+_T*%_1?_VZ"
+M_H*(!8 </\ P!X&'['___G^#__P_##\&#A\,?___@_,#_@<%@!P;P  !@ '@
+M'__X?@#_\ \ #P  !P ?_XX \ #^!P6 '!_ '_V _>??__A^_O_W[P?O _OW
+M!]__KO[Q_OX'A8 ;Y__0!?Z%]%__^?Z"__0O]"_Z"A?T7_^N@OT"B 6 '#_ 
+M, ?!A^Q___Q_@__\/PP_!@X?#/_A_X/V!_P'!8 <&\   < !X!__^'X __ /
+M  \   < /^'. / !_ <%@!P?P!_]P/WGW__X?O[_]^\'[P/[]P>_X<[^\_W\
+M!X6 &^?_T 7^A?1?__O^@O_T+_0O^@H7]+__SH+Z!8@%@!P_P# 'P8?L?@ \
+M>8/P?#\,/P8>'QS_@'^#_ _\!P6 '!O   '  > > #QX /!P#P /   ' #^ 
+M;@#P _P'!8 <'\ ?_<#]Y]X /'C^\'?O!^\#\_<'OX!N_O?[_ >%@!OG_] %
+M_H7T7____H+_]"_T+_H2%^2__^Z"] N(!8 </\ P \&'['X #'&#\ P_##\&
+M'Q\9_P ?@_P/^ <%@!P;P   P '@'@ ,< #P  \ #P $!P!_ !X \ /X!P6 
+M'!_ '_[ _>?>  QP_O '[P?O _7W#W\ 'O[W^_@'A8 ;Y__0 OZ%]%____Z"
+M__0O]"_Z%1?I?__^@O0+B 6 '#_ , /!A^Q^  1AH_ ,/_P_!A\?F?X #X/X
+M'_ '!8 -&\   , !X!X !&  \ . # \ ! > ?@ . . '\ <%@!P?P!_^P/WG
+MW@ $8-[P!^ '[P/U]X]^  [^[_?P!X6 &^?_T +^A?1?___^@O_T( 0O^A47
+MZ7___H+H%X@%@!P_P# #X8?L?@  88/P#!_X/PP?#YG^  >#\#_P!P6 #1O 
+M  #@ > >  !@ / #@ P/  0#@'X !@# #_ '!8 <'\ ?_N#]Y]X  &#^\ ?_
+M_^\']?N/?@ &_M_O\ >%@!OG_] "_H7T7____H+_]!_X+_05"^E___Z"T"^(
+M!8 </\ P ^&'['X  $'C\ P  #\,'P^9_  #@_ _X <%@ T;P   X '@'@  
+M0 #P X ,#P $ X!\  ( P _@!P6 '!_ '_[@_>?>  ! GO '___O!_7[CWP 
+M O[?[^ 'A8 ;Y__0 OZ%]%____Z"__0  "_T%0OI?__^@M OB 6 '#_ , 'A
+MA^Q^   !Z_ ,   _##\/F?P  8/@?\ '!8 (&\   & !X!X$@ 'P X &#P ,
+M X!\!( "'\ '!8 ('\ ?_V#]Y]X#@!&6\ ?__^\'[?N/?   _C_?P >%@!OG
+M_] !?H7T7____H+_]   +_0M"^E___Z"(%^(!8 </\ Q ?&'['X   &C\ P 
+M #\,/P^9^  !@<!_P <%@ @;P   < '@'@2  ? #@ 8/  P#@'@$@ (?P <%
+M@ @?P!__</WGW@. $=[P!___[P?M^X]X  #__]_ !X6 &^?_T0%^A?1?___^
+M@O_T   O]"T+Z7___H' 7X@%@!Q_P#.!\8?L?@   8/P#   /PP_C['X  & 
+M /^ !P6 "!O   !P > >!( !\ . !@\ #@. > 2  C^ !P6 "!_ 'O]P_>?>
+M X 1_O '___O!^[[GW@  /__OX 'A8 ;Y__2@7Z%]%____Z"__0  "_T+HO1
+M?__^@ "_B 6 &W_ ,X#QA^Q^!  !F_ ,  !_##^'\?@  8 !_P@%@ @[P   
+M, '@'@2  ? #@ 8/  X!P'@$@ %_" 6 "#_ 'O^P_>?> X 0YO '__^O!^[]
+MWW@  /__?PB%@!O'_]* OH7T7_O__H+_]   +_0NA=%___Z  7^(@ $.!(& 
+M&L S@/&'['X,  '#\ P  #\8/X?S^  !@ '_"( !#@2 "#O    P > >!( !
+M\ . !@\ #@' ^ 2  7\(!8 (/\ >_[#]Y]X#@!"^\ ?__^\/[OW>^   __]_
+M"(6 &\?_TH"^A?1?\__^@O_T   OZ"Z%TO___H !?XB (!^    !_\ SP/F'
+M['X\  &+\ P?^'\8?X?S^  !@ /^"( "'X #@ A[P   . '@'@2  ? #@ 8/
+M !X!P/@$@ '^" 6 &W_ 'G^X_>?>"   ]O '__^O#][]WO@  /_^_@B%@!J'
+M_]) OH7T7\O__H+_]!_X+^A>A=+___Z  HF  3.$@!O\ #/ P88,8?P  << 
+M#+_\,!AAAC,   &  8 #@ )Y7@.  3^$@ 'X'8 "!_X#@ $,!( 5_  >?X#\
+M!\ X  "Z  =@!^ /P/P> X($@ )__@.%@!4$ !) @(0$0#@  (( !" $( A 
+MA!(#@ *  02  G@!@X @;X    .  #-@888,?\P  ;\ ## ,,!AAAC,   &!
+M@8 %@ -UP "  7^$@ & 'X ##\  @!H0?____?  'C_ _ ? ^   P@ 'X ?@
+M#\#\'@."!H #?\  A( 6_G  $B! A 1 R   @@ $( 0@"$"$$@.  H&!!H #
+M<#__@ %?A * &3-@888,/PP  8, #K ,<!A@PS,   &#P, &@ (- ( !>82 
+M 7 @@ (# ( !( . %@.( !X_P/P'__@  /X !6 'H _ ?AX#@ /^?X &@ (/
+M (2 %OSX !(@0(0$/P@  (( !" $( A 0A(#@ ."0( &@ (,_X2 '/X  #,P
+M888,  P  ?, #+ -L!A@PS,   &#X, '@ ' @ '@@ 55555^^"&  4 $@!8'
+M!  >'\#\!__X  ".  =@!F /P'X> X #_C^ !X !P(2 %OF, !(00(0$  @ 
+M (( !" $( A 0A(#@ ."(( '@ &_A( <_   ,S QA@P C  !XP ,, SP-,##
+M,P   8-@P >  3"  < #@ (=O"&  1 $@!8& @ >'^#\!_]X  ">  ?@!R ;
+M@'X> X #_C^ !X !,(2 %OL& !(0((0$  @  (( !" $(!" 0A(#@ ."(( '
+M@ $OA( 6_ '_\_@_A_P)#___T__\/_T_\O_#\X.  X/P?X>  ?"  < #@ (-
+M_"($@!P& __>[^[]]_;[__ZN__?O]N_=OW[>___^_M_?AX !\(2 '/L'_]+H
+M+H7T  O__H+_]"_T+]"_0M+___Z"T%^(A( 6Z '_\_@_A_P'[___@__\?_R_
+M^?_#\X.  X/P?X>  >"  8 #@!P)_?_ X X!\  #__X __ /\ _ /P# ___^
+M , ?AX !X 2 '!(#_][O[OWW__O__O[_]Z_W;]:_?M[___[^W]^'@ '@A8 5
+M!@ 2"""$! ?H  ""  0@!" 0@$(2 X #@A! !X !'X& #*JJJH !__/X/Z?\
+M/X. "L?__'_\__?_P_.#@ .#\'^'@ $P@ & !( ;^?_ X X!\  #__X __ /
+M\ _ /P# ___^ , ?AX !, & 'U5557D%_][O[MWW^!O__KK_]Z_W+]B_?M[_
+M__[^W]^'@ $PA8 5C@ 2"""$!#@8  ""  0@!" 0@$(2 X #@A! !X&  5\$
+M@ <#__/\/[?\A( *@__]/_X_\/_!\X.  X/X/X:  L7\!8 ;<__ \ 8!\ ?C
+M__X __ /\ _ !P! ___^ . /AH "Q?R  2"#@!S\B__>]];-]T?C__[^__;O
+M]>_?AW]>___^_N_OAH "Q?R%@ C\ !($$(0$0 . "H( !" $(!" 01(#@ ."
+M"" &@ (__X !! 2 " ?_]_R?C_Q_@X *@__]O_T_X7_A\X.  \/X/X2 !/P)
+M__X%@!L'_\#P!@'P'_O__@#_\ _P#X   $#___X X ^$@ 3\"?_^@ %[@X <
+M_G?_VO=V]???^__^_O_V;_;OOOA?7O___K[O[X2 !/P)__Z%@ CX !($$(0$
+M0 . "H( !" $("!X01(#@ .""" $@ $#@P6 "(__^_X_E_Q_@X *S___/_^_
+MZQ_I]X.  YOX/X.  H"?@P6 &XO_P/@& ? ?___^ /_P#_ /@   0/___@#@
+M#X.  H"?@X !/X2 &X__UOO6[???___^LO_T[_1OM.>76O___N;O[X.  H"?
+M@X6 "'0 $@(0A 1  X *@@ $( 0@( >!$@.  X((( .  7^$ 8 !?X6 !?/_
+M#^?]A( *Q__\/_T_?VS1\X.  \/\'X>  ?X!@!5____^>__ ^ (!\!____X 
+M__ /\ \#@ = ___^ / 'AX !_H !'X. '/Y__][Z^IWV7____KK_]^_V[R"3
+M+U[___Z^]_>'@ '^A8 ;A__2^@J%]%____Z"__0O]"^@  %2___^@O07B( !
+M 8: !O/_G__\?X. "OO__+__?W:.>_.#@ .C_!^'@ 'X@ $!A( 1.__ _ (!
+M\!____X __ /\ \#@ = ___^ / 'AX !^( !#X2 &S__WOUJA???___^AO_W
+M;_2O*7&%7O___M[W]X>  ?B%@!O'_]+]"H7T7____H+_]"_T+Z   5+___Z"
+M]!>(@ $'AH %\_\OK_R'@ 5__/]]](6  X/^'X>  :"  0>$@!&[_\#\ @'P
+M'____@#_\ _P#P2"@ 3^ /@'AX !H( !!X2 &[__WOW:U?=?___^@O_TK_<O
+M(@L DO___O[[]X>  :"%@!O'_]+]"H7T7____H+_]"_T+Z(  )+___Z"^A>(
+M@ $'B( #G\_]A( *B___/_]_>?WW]X.  ^?^#X:  F@ @ $'A( 1F__ _@(!
+M\!____X __ /\ \$@H $_@#X X:  F@ @ $'A( ;G__2_NJU]E____[V__3O
+M]*\G_@B:___^FOO[AH ": "%@!OG_]+^BH7T7____H+_]"_TKZ/\ )K___Z"
+M^@N(@ $#AH &]_^7__Q_@X %V___?_Z#@ +L]X2  OX/A( $[4   ( ! X2 
+M$=O_P/X! ? ?___^ /_P#_ /!( &?__^ /@#A( $[4   ( ! X2 &]__VO[M
+MA???___^IO_TK_4O0@/SF7___H+[^X2 !.U   "%@!OG_]+^A87T7____H;_
+M]"_U+T(#X)E___Z"^@N(@ (!^ . '#_ ,_'GU^_^   !O_ -?PW_[__^_?  
+M ?_S3X '@ (!^ . "!O  /   > >!( *\  /  \ _  @< .  _ #@ >  @'X
+M X ('\ >\)LMY%X#@!'"\ :O!B]2_!&K<   @O&[@ >%@!OG_]+^@P7T7___
+M_L+_]"_T+T+\$*E___Z"_0N( 8 !X . '#_ /_#5G^]^   !@_ ,/P[_U__Z
+M__   ??S3X ' 8 !X . "!O  /   > >!( *\  /  \ _\ @< .  _ !@ <!
+M@ '@ X ('\ 2\&IEY-X#@!'^\ ?O!2]J_]6I<   BO&U@ >%@!OG_]+_0 7T
+M7____M[_]*_T+V+_T*E___Z"_06(!8 </\ [\,N_[/X  @&7\ T_#K_O__W_
+M\  !^_/W@ <%@ @;P #P  '@'@2 "O  #P / /_  ' #@ /P 8 '!8 ('\ 6
+M\'1%YUX#@!'J\ ;O!6]2_]))<   AO$-@ >%@!OG_]+_0 7T7__]_NK_]"_T
+M;T+_TDE___Z"_06(!8 </\ _\'S_[_X  @'G\ ^_##_?__C]\  !S_''P <%
+M@ @;P #P  '@'@2 "O  #P / /_  ' #@ /P < '!8 ('\ 2\",%Y%X#@!&:
+M\ 1O!^]B_]=+<   LO"]P >%@!OG_]+_H 7T7__]_IK_]&_U;T+_T4M___Z"
+M_H6(!8 </\ [\';O[GX !@';\ \_#G^O__W_^  !__'_P <%@ @;P #P  '@
+M'@2 "O  #P . ?_@ '@#@ /P , '!8 ('\ 6\"D5Y=X#@!&F\ 3O!:[5_^I)
+M>   @O""P >%@!OG_]+_H 7U7__Y_J;_]._U+M7_ZDE___Z"_H*(!8 </\ _
+M\#YG[/X !@'S\ W_#?^_\#M]^  ![_&WP <%@ @;P #P  '@'@2 "O  #P .
+M ? @$#@#@ /P , '!8 ('\ 2\!&=YUX#@!&.\ 8O!B[%\"S6N   DO#*P >%
+M@!OG_]+_T 7W7__Y_H[_]B_V+L7_[%:___Z2_H*(!8 </\ W\#O?[_X #@&+
+M\ Y_#K_W\!M_^  )[_#GX <%@ @;P #P  '@'@2 "O  #P . ?  $#@#@ /P
+M & '!8 <'\ :\!0EY%X ! #V\ 6O!6Z-\ S4N   DO!98 >%@!SG_]+_T 7T
+M7__U_O;_]:_U;HW_[-2___:2_T%_AP6 '#_ -_ V[^[^  XAB_ /OPS_K_ 8
+M?O@ ">_P]> '!8 6&\  \  !X!X  "  \  /  X!\  0. .  _  8 <%@!P?
+MP!KP&17E7@ $(/;P!&\'+M7P#]6X  "2\$M@!X6 '.?_TO_0%?1?__7^]O_T
+M;_4NU?_N5;__]H+_07^'!8 </\ _\!RO[_X 'B'+\ Q_##^7\!U]>  9S_#[
+MX <%@!8;P #P  '@'@  ( #P  \ #@'P   8 X #\ !@!P6 '!_ $O +5>1>
+M  P@MO 'KP?N[? *IM@  ++P16 'A8 <Y__2_^L%]%__[?ZV__>O]^[E_^JF
+MW__FDO]!?X<%@!P_P#?P'=?O_@ V89/P##\,/R_@&O_X !G'\'7P!P6 %AO 
+M /   > >  !@ /  #P , ^  "!@#@ /P # '!8 <'\ :\ HMY%X '&#N\ ?O
+M!^W;X TJ6   NO JL >%@!SG_]+_Z@WT7__=_N[_]^_W[=O_[2I?_^::_ZB_
+MAP6 '#_ /_ /M^U^ .9AP_ ,/PP^#^ ,?WP .?_P?_ '!8 6&\  \  !X!X 
+M &  \  /  @#X  (' .  _  , <%@!P?P!+P!$WFW@ \8+[P!^\'Z_O@!ZK<
+M !""\""P!X6 '.?_TO_T3?;?_SW^OO_W[_?K^__WJM__UH+_H+^'!8 </\ [
+M\ XG[/X#QN&!\!@?&!P/X P^/ !YG_!_^ <%@!83P #P  '@'@  X !P  < 
+M  /@  @, X #\  X!P6 '!_ %O %W>=> /S@_W /]P_W^^ 'Z^P ,.+P(+@'
+MA8 <[__6__5=]U_\_?[_?^_W[_?[__<K[_^VXO^@OX<%@!Q_P#_P!U_L?O\&
+MX8'P&_\?_\?@##\< /&C\#;X!P6 %A/  /   > >  #@ '   P   >  # 0#
+M@ /P !@'!8 <'\ 2\ *EY]X#_.#_< _[#__]X ?M] !@WO 96 >%@!SO_]+_
+M^J7WWP/]_O]_[_OO__W_]^WW_V[>_]!?AP6 '/O /_ &!^S__ ?C ? __S__
+M_^ </PX!L8/P/G@'!8 5(\  \  !X!   >  ,  !   !X  $!( #\  8!P6 
+M'+O $O #_>=0__WA_[ < 0  /> 'U?@ X/[P$=@'A8 <W__2__O]]U#__?W_
+MO]P!P  ]_^?5^?[N_O_1WX<%@!S[P#?P P?L?P 'X__P?/\ _S_ 'A^'_V&3
+M\#M\!P6 "P/  /   >    '@ X$!@0&  \  !@2  _  ' <%@!S[P!KP ?WG
+MS__]X?X  /\ _P# #_;^ <#N\!3<!X> #-K__?WWS__]_?X/@X. "\#_[_;^
+M =[N_]1?AP6 ' / ,_ #!^PP  ?G__  _P#_?\ __\'^8Z/P'_P'!8 < \  
+M\  !X    > !\ #_ /]_P  '   " /  # <%@!P#P![P ?WG___]X@'P /\ 
+M_W_  ?=__\+>\ @L!X> "MK__?WW___]^@&'@ G!]W__WM[_Z"^'!8 < \ _
+M\ ,'[  #__\?^ '_@?__P '_< #'@_ ;/ <%@!P#P #P  '@   !X!_X ?^!
+M___   ,   8 \  ,!P6 ' / $O !_>?___G@'_@!_X'__\  &S__AO[P#.P'
+MAX )TO_]_??___G@B( )_AN__[[^_^QOAP6 ' ? ,_ !A^P ?__@'_@!_\'_
+M_^  _SX#CX/P#_X'!8 <!\  \  !X   !^ ?^ '_P?__X #A   . /  #@<%
+M@!P'P![P /WG__P'X!_X ?_!___@ .$/_P[^\ 0N!X> "-[__OWW__P'BH (
+MX<__?O[_]"^'!8 <#X _\ &'[ ___^ __ /_X___X '_O_\?@_ .W@<%@!P/
+M@ #P  '@  /_X#_\ __C___@ ?^P !X \  &!P6 ' ^ $O  _>?_@__@/_P#
+M_^/__^ !_['\'O[P!38'AX 'TO_^_??_@XR !_'\_O[_]#>'!8 &#X S\ #'
+MA( 2X#__!\    /P ?^?__\#\ Q^!P6 ' ^  /   >  ?__@/_\'P    _ !
+M_YX#^ #P  8'!8 <#X >\ !][_!__^ __P?    #\ '_G@/Y_O 'E@>'@ ?6
+M__]][_!_C( '_@/Y_O_WEX<'@ 0W\ #'A( #X'_@!H ) _^/__\!\ 9?!PB 
+M"O   > /___@?^ &@ D#_X__\ !P  <'!X +&O  ?>P/___@?^ &@ D#_X__
+M]_]P [<'AX &VO__?>P/CX %]_]_^[>'!X %,_  9_R#@ +A\ B "!_'___!
+M\ :O!PB !/   <"#@ +A\ B "!_'_^  <  #!P> !1[P #W @X "X? (@ @?
+MQ__@_W #6P>'@ 7>__^]PY" !>#_?_M;AP> !3/P '_@@X !@ F " 'C__CY
+M\ 8/!PB !/   <"#@ & "8 ( >/_^  P  ,'!X %'O  .<"#@ & "8 ( >/_
+M^ >P _L'AX %WO__N=^1@ 0'O_O[AP> "#/P #_@___ #(& !O ?\ 8O@ 8(
+M@ ?P  ?@___ #(& !O 0$  #@ 8'@ @>\  'X/__P R!@ ;P$% #VX &AX $
+MWO__QY* !/!?^]N'!X '8?  #^'_^ V !Q_ ?_ &!X &"( &<  /X?_X#8 '
+M'\!_@  !@ 8'@ <_<  /X?_X#8 ''\!_@ /]@ :'@ *_?Y6  X_[_8<'@ 9@
+M\  /X?\0@8 $^ P'@ 8(@ 40  _A_Q"!@ 3X  & !@> !C^0  _A_Q"!@ 3X
+M!_V !H>  K^?EH "]_V'!X &8'@ !^/ #X & ?_X?P? !@J  P?CP ^ !@'_
+M^  !P 8'@ 8_X  'X\ /@ 8!__@/_< &AX "O^>6@ */_8<'@ 7!_  'XA& 
+M!0_\#\/ !@J  @?B$8 %#_P  , &!X %?^  !^(1@ 4/_ #^P :'@ )_XY: 
+M O#^AP> !<_P  . $H $_@#[P 8(@ 00  . $H $_@  P 8'@ 5^$  #@!* 
+M!/X /L &AX "?A^7@ $^AP:  P&_^!6 ! < ?^ &!X " ?@5@ 0' $!@!@> 
+M O'X%8 $!P!'8 :&@ +^\9B  L=_A@:  P/W_A>!@ '@!@>  @?^%X "^" &
+M!H # <?^%X "^: &AH "_<^8@ +YOX8&@ 0'Q_^ %8 #!__@!@>  P?_@!6 
+M @?^!P: ! ('_X 5@ ('_@>&@ +Z/YB  OX?A@: ! X/_\ 6@8 !\ 8'@ ,/
+M_\ 6@8 !P 8'@ ,/_\ 6@8 !P :&@ 'QFH !SX8'@ (/_A>  @_P!@>  @_^
+M%X "#_ &!X "#_X7@ (/\ :H!X "'^ 7@ (#^ 8'@ (?X!>  @/X!@>  A_@
+M%X " _@&J >  3\9@ %\!@>  3\9@ %\!@>  3\9@ %\!J@'@ %\&8 !'@8'
+M@ %\&8 !'@8'@ %\&8 !'@:H!X !X!F  0,&!X !X!F  0,&!X !X!F  0,&
+MJ"@H'8 !. JH*"@<@ (!_@JH"X "'X #@ (#P!8+@ '\!( " \ %@ '\$ N 
+M > $@ (#P 6  ?P$@ (#_PJ+@ +\?X.  OP_E@N  A^  X "#/ 6"H " _P$
+M@ (/\ 2  @'^$ J  @/@!( "#_ $@ (#_P2  P/_@ F+@ +\?X.  O /E@N 
+M A_  X "&?@6"H "!_P$@ (?^ 6  ?P0"H "!^ $@ (?^ 2  P?_@ .  P?_
+M@ F+@ +\/X.  N 'E@J  P?^0 .  A/X%@J  @_@!( "'_@%@ '\!8 !_ H*
+M@ $(!8 "'_@$@ ,'_X #@ ,'_X )BX "X;^#@ +@!Y8*@ ('_@2  B?\%@J 
+M A_@!( "/_P$@ (!_@6  ?P*"H !& 6  C_\!( #!_^  X #!_^ "8N  >&$
+M@ +  Y8*@ (/_ 2  B_\%@J  A_P!( "/_P$@ (!_@2  @'^"@J  1 %@ (_
+M_ 2  P?_@ .  P?_@ F+@ 'SA( "P .%@ $SA8 !,XH*@ (/_ 2  C_\!8 !
+M9 6  :@*"H "/_@$@ (__ 2  P??@ .  @'>"@J  C?@!( "/_P$@ ,'WX #
+M@ ,'WX )BX !^X2  L #A8 !=X6  ;N*"H "'_P$@ (YG 6  2 %@ $@"@J 
+M C_X!( ".9P$@ (#WP2  @'>"@J  B?P!( "/_P$@ ,#WX #@ ,'WX )BX !
+M^X2  L #E@J  AZ\!( "/_P%@ $@!8 !( H*@ (^N 2  C_\!( " ]\$@ (!
+MW@H*@ (O\ 2  C_\!( " ]\$@ ,'WX )BX !^X2  L9CE@J  AU<!( "/=P6
+M"H "/5@$@ (__ 2  @'^!( " ?X*"H "+_ $@ (SK 2  @'_!( #'__@"8N 
+M ?N$@ +.<Y8*@ (>O 2  AB(!8 !> 6  7@*"H "/K@$@ (?^ 2  @&&!( "
+M 88*"H "+_ $@ (7> 2  @&'!( #/X?@"8N  ?N$@ +O]X6  8>%@ &'B@J 
+M A_\!( "*!06"H "/_@$@ (O] 6  ?P%@ '\"@J  BO0!( "+_0%@ '^!( #
+M/__P"8N  ?N$@ +7ZY8*@ ([W 2  @O0!( # P.  X $ 08 < @*@ (_^ 2 
+M @PP!( # P. !( #? !P" J  @PP!( "## %@ '\!( $/OWP< B+@ '[A( "
+M_#^*@ /X_'^)"H ".]P$@ (($ 2 ! >'P#@#@ -^#_@("H "/#@$@ (/\ 2 
+M! >'@#@#@ -\#_@("H "## $@ (/\ 6 "7@ .   /_W_^ B*@ +\.XR  ;^#
+M@ /X_'^)"H "/#P$@ (,, 2 "@__X/P   0$#_X("H "/_ $@ (/\ 2 ! O_
+M@/P$@ (/_@@*@ (+T 2  @_P!X '_   ._O__@B+@ 'SBH #^_^?@X "^'B*
+M"H 6/_\/_   !^ !^   '__]_@  '@#__@@*@!8_\P_\  '__X'X   8  W^
+M   8  _^" J "@PS#_P  ?__@?@$@ @-_@   ?\/_@B+@ 'S@X $_@?@?X. 
+M _@ #X.  _@!#XD*@ T__[_^  #__X?\   _@P* !#\!__\("H 6/^.__@ '
+M___G_   ,_\'_P  .  /_P@*@ H'X[_^  ?__^?\!( "!_\#@ /^#_\(BX !
+MXX. !/@'X!^#@ /S_P>#@ /X @^)"H !/X,!@ @"__]O_   ?X,"@ 1_P___
+M" J %C@'__\ !O__;_P  &/_!_\  &  !_\("X ) ___  ;__V_\!( "!_\#
+M@ ,\!_\(BX !YX. !/D#P)^#@ /C_P>#@ /@  >)"H !#X. "8 #?_[__   
+M^X,"A @)@!<!__Q__X /?_[__   R?X#_P  Q^0#_P@)@!$!\ !__X /?_[_
+M_    @ #_P.  Q@#_PB+@ C\?___\( !#X.  \O^ X.  \?\ XD*@ 'G@X 2
+M@ >__?_\  #Z___^  #_\___" F %P/_^#__@ ^__?_\  #8_@'^  #/X /_
+M" F $0,8 #__@ ^__?_\   #  '^ X #% /_"(N "/@____P0 (/@X #V_X!
+M@X #S_0#B0F %P'G'__[@ ??^__\  'Z___X  '_\__^" F %P?_X!_[@ _?
+M^__\  ' _$'X  '/X '^" F $088X!_[@ _?^__\   # $'X X #% '^"(N 
+M". ?___P( 0/@X #P_Q!@X #S_0!B0F %P/P'__Q@ >O=?_X  '#/^/@  ![
+M]_G\" F %P__X _Q@ ^O]?_X  ' ''W@  '; .?\" F %PP/X _Q@ ^O]?_X
+M   # 'W@  &8]^?\"(N #N /___QT N/___YPQQ]@X #W_?GB0F %P_\/__@
+M  _7<__X  8_W_'X   C /'\" F %P__P _@  _7\__X  ' #'_X  'C /_\
+M" J %@/ #^  #]?S__@ !__@?_@  >  __P(BX (P ____'H#X^$@ +L?X0!
+MB@F  0^#@!/   _7\__P   "'_/\   #D//\" F %P__^@_   _7\__P  #@
+M#'_\  ##@/_\" J %D "#\  #]?S__   ./@?_P  ,!W__P(BX (^@____'H
+M#X^#@ +[[(6  ?>*"8 7",?_'^   , ##\    +___P   'R__P("8 +#__[
+M[^  #\ #_\ #@ D(?_P   '@__P("8 7!_@#[^  #\ #_\    , ?_P   (5
+M__P(BX "^^^)@ /[SW^$@ 'UB@J %L__#^   "/'#^    +___@   (1__@(
+M"8 +#__C_^  #R/'_^ $@ A_^    @'_^ @)@!</\ /_X  /(\?_X    P!_
+M^    ?;_^ B+@ 'CA( "_#^$@ /[?'^$@ 'WB@F "P''_X_@   G[X_@ X* 
+M!_@   /S__@("8 +#__C_^  #B?O_^ #@ E\?_@   /@__@("8 1#_@#_^  
+M#B?O_^    , ?_@#@ ,4__@(BX !XX2  O@?A8 "?'^$@ 'TB@> #3@   __
+MG^/   ?O_^ #@H '^    _/_^ @'@!H@  8_Z__CP  7[__@   #_'_X   #
+MX/_X' <'@!,&' 8P __@   7[__@   # '_X X #%/_X"(N !^O__#__Z!>%
+M@ +\?X2 !/3___>'!X -.   '___[_   ]__X ."@ ?X   #\__X" > &B  
+M #_C_^_P #O?_^    /\/_@   /@?_C\!P> $P<\ " #_^   #O?_^    , 
+M/_@#@ ,4?_@(BX 'X__QC__$(X6  OP_A( $]'__(X<'@ 0X   /@X &^  ,
+M/__  X* !_@   'S__@(!X :(   ?^O___@ /#__P   !_P_^    _!_^_P'
+M!X 9!_P < /_X   /#__P   !P _^    @Q_^ B+@ ?K_^!'_\/#A8 "_#^$
+M@ 3\?_PGAP> &3   #__\]_X !O[^\    '__[@   '__S@(!X :(   ?^/S
+MW_@ ._O[P   #_X?N    _P_/_P'!X 9#_P 0 /SP   ._O[P\  #@ ?O^  
+M @ _. B+@ ?C_^!'_\6'A8 "_A^$@ 3\/_@?AP> &3   #__\]WX  ?[^\  
+M  ?__S@(  '__B (!X :(   __WSW_@ )_O[P   #_\/. @ !_X>/_ '!X 9
+M#_P P 'SP@  )_O[S_  "  //_@ !@ >( B+@ ?]_^H7_]F'AH !#X2 !/X?
+MX!^'!X 9,   ?__YV)@ '[?YQ40 "__^)P0  __^( @'@!H@  '_\?G?^  _
+MM_G !  ?_PX@!  /_PX__ <&@!H(#_P1@ 'YQV  /[?YVKP %  ../P #  .
+M( B+@ ?Q_^=G_\/+AH !#X6  P_@/X<&@ </   !?__X X /?[_P$]( '__\
+M#@( !__^"0: &P$   ?_^G@?^ #_O_   @ __X0  @ ?_X8__ <'@H 6]H  
+M>!_X /^_\"PN "  !#'^ !@ !@F+@ +Z?X.  @/ AH !AX6  X?!^X<&@!D/
+M__P#___X  0 _[_P#!$ +__\& $ #___"0: &P&   ___+@?_ '_O_   0!_
+M_\0  0!__\$__ <(@!<#_   .!F< ?^_\'/O %  !&?_ '   0F+@ C\O_N_
+M_@/ ?X6  <>%@ /!P:.'!H 9!\  !?__\ -$ ?\_\$   %___   @#___PD&
+M@ T!P  ?__T0'_P!_S_P X +?__H  " ___PO_T'!X :/__Z   0&MP!_S_P
+M/_\ (   __^ P   @ $'BX (_1____X#P'^%@ 'KA8 #\, #AP> "#?\!___
+M ")$!( %0 " !_\$@ 4/_^"  0<'@ @P  ?__P ?^ 2 #A_X@ ?_ !_X  __
+MX/__!P>  7@%@ (]N 2 ";__@    ?__@ .  L [!Y^  D ZAP>  DSD!( "
+M 8(&@ & !8 &0  /@ "$!P>  4 %@ (^?@2  S_\@ . "#_\0  /@'_^!P: 
+M P'S& 2  CY^!( )\\^    !\\_  X "7WH'AX "_.>6@ +1QX<'@ *Q* 6 
+M 0($@ ,-,( #@ ,-,$ #@ (@0 <'@ *MS 2  C_^!( #/_R  X #/_Q  X "
+M<<8'!X "[]P$@ (__@2 ">RW@    >RWP .  ENN!X>  OWOEH "\<>'!X "
+M4" $@ (GY 2  P(@@ .  T(@0 2  40'!X "3]P$@ (X' 2  S_<@ .  S_<
+M0 .  G_^!P>  N_<!( ".!P$@ G]WX    &]W\ #@ )_N@>-@ +X'YD'@ &P
+M!8 ", P$@ ."@( #@ /"@$ #@ )@!@<'@ *O_ 2  B_T!( #/_R  X #/_Q 
+M X "?_X'!H # >_\!( "+_0$@ E__X    $__\ #@ )__@>?@ *__8<'@ ,1
+M! P#@ 0,, #@!( '@    L  0 . !# D  X%!X ##O@, X )>]X X   '_B 
+M X #/_Q  X $/]P #@4'@ ,N^ P#@ ][W@#@  #__X    $__\ #@ 0OW  .
+M!8>  ?Z8@ '?AP> "ACP#A@  &?D _@#@ <!@    L/"!( $$>P /@4'@ H'
+M" X8  &?^X/X X " 8 #@ )\/@2 !!X< #X%!X 5!P@.&  !__^#^   ?_^ 
+M   !?#_P X $'A0 /@6(@ $/D( "_#^$@ +^'X<'@!0,  ]\  &#R ?X  !#
+MR8'\  +'X@2 !!@,!'X%!X * _ /?  "?_?G^ . !P&!_   >!X$@ 0?_ 1^
+M!0> %0/P#WP  ___Y_@  #PW@?P  7@?\ . !!?\!'X%DX "_#^$@ +X'XT'
+M@!P&( ?^  (!D _\   "@P/\  +%8@/P   ,/ S^!0> ' ' !_X !?_O[_P 
+M  :C _P  'U^ _    _\#/X%!X < < '_@ '___O_   /K\#_  !?7_S\   
+M"]P,_@63@ +^OX2  OU_C0: !0'__ __ X 5@ _\  @0 !_^  +CQ _X   .
+M< _\!0: !P'V( __  ^#@!/\  _!P__^  #\/$_X   __ _\!0> ' 8CC_\ 
+M#_]___P !^__[_X #?P___@   6@#_P%F8 "_#^$@ +'XX<&@!T#__P?_P "
+M  !/^   $ 0'_@  D P'_   #_ /_ 4&@ <##R ?_P /@X 3^  ?X ?__@ (
+M'_Q/_   __\/_ 4'@!P&(]__  W__[_X !_O__O^  ]____\  #'XP_\!9^ 
+M L?CAP: '0?__!__  $ @(?X   0# /^  "8& /\   #P!_\!0: !P8#P!__
+M !^#@!/X #_P#__^ #P?^._\  '__Y_\!0> # /#__\ 'O]_?_@ /X. #?X 
+M/W____P  </#G_P%GX "Q^.'!H =#_  #_X  ,@+!_@ 0 0X _X 0!_P _P 
+M  / ?_@%!H 9#   #_X '_?W__@ ?_P___X ?A_P__P  8.  ?@%!X <#___
+M_@ ?M_7_^  ____]_@ _[__]_  !P /_^ 6?@ + 'X<&@!</^  /_X  P4,'
+M\   @>!A_@  #^ !_ 2  C_X!0: !PP   __@!^#@ /P '^#@ G^ 'X/X'_\
+M  .#@ 'X!0>  0>#@!B '_Z___  ?W__G_X ?_?___P  \ #__@%GX "P!^'
+M!H =#_P"#__@$>(G#\  !X  P?P  C_@0?P  % */_H%!H '"$ "#__@'X. 
+M#\  ?7____P ?C@ ?_P  X.  ?H%!X !0X. &. .W=OWP !X?_\__ !]P!^_
+M_  #T O_^@6?@ +0'X<&@!T/]@,/^> 3\ ^?X  #@ '!_  #_^'!_   \ \?
+M_@4'@ ;P P_YX!^#@ /@ '^#@ G\ '_X ?_\  >#@ '^!0> ',G___G@#>_W
+M;^  ??__O_P ?< ?O_P !_ /__X%GX "\#^'!H =#_,#C_@  ?"/W^   > #
+M@?P !__CX?P  / /'_X%!H ' ? #C_@ #X. #^  ?_OO__P ?_@#__P !X. 
+M ?X%!H = <S___@ #^]WK^  ?]____P >< ?G_P !_ /__X%GX "\#^'!H =
+M#_&#C_@  ? /C_  &? #D_@ 0?_C@_@  _ /W_@%!H ' ? #C_@ #X. #_  
+M/^____@ ?_@#__@ !X.  ?@%!H ' <Y___@ #X. $_  )\__[_@ /\ ?_?@ 
+M!? /O_@%GX "\#^'!X <L,,/\  !X.>/\  0__D/^  !_^.#^   T \?X 4&
+M@!T/L /_\  /X ?_\  ?X '_^  _^ /_^  'W___X 4&@!T/CS__\  /_Q__
+M\  /@ ?W^  _P!__^  'T __X 6?@ +P?X<'@!8P<X_P  # XP?P  #_\0_X
+M  '_XX?X X #!Q_ !0: '0XP __P !_  __P  _@ ?_X !_X __X  <?___ 
+M!0: '0X/C__P !__'__P  ^ #__X !_ '__X  < !__ !9^  >&(!X 6,#^/
+M\  !P..'\   __,/^  !_^./^ .  P,_P 4&@!T., /_\  ?X ?_\  /\ /_
+M^  /^ /_^  #/___P 4&@!T.#\/_\  ?_Q__\  /P __^  /P!__^  #  /_
+MP 6?@ '#B > !# ?__ #@ \#A^   #_CG^   #_C_^ #@ .#_< %!X <, /_
+M\  >, __X  #. /_X   . /_X   /__]P 4'@! /X__P !X____@  , '__@
+M X #'__@ X #@_W !9^  <>(!X $, /]\ . %0./P   /^/_X   /^/_X   
+M </YP 4'@!PP _WP  XX'__    X __@   X __@   ___G !0> "@___?  
+M#C___\ #@ ,?_^ #@ D?_^    '#^< %GX !QX@'@ 00!_G  X 5!__    ?
+MX__    _X__    !P_' !0> '! '^<   #Y__\   #@'_\   #@#_\   #__
+M\< %!X 0#__YP   /_O_P   (!__P . "1__P    </QP 6?@ ''B > '!_[
+M\<   "&'\\    /#\<    /#_<    '#\\ %!X <'_OQP   /__SP   /__Q
+MP   /__]P   /__SP 4'@!P/__'    ?^_/    ___'    ___W    !P_/ 
+M!9^  <>(!X <$<)QP   (8?SP    \/QP    \/YP    </SP 4'@!P1PG' 
+M   ___/    ___'    ___G    ___/ !0> ' __\<   !_[\\   #__\<  
+M #__^<    '#\\ %GX !QX@'@!SYP!A    #P_'    #P_#    #P_#    !
+MP_& !0> ' ' &$   #__\<   #__\,   #__\,   #__\8 %!X <!__X0   
+M/__QP   /__PP   /__PP    </Q@ 6?@ ''B : ! '!@X@#@ D+$/&    !
+M@'@#@ ,!@'@#@ -#@_ &!H $ <& " .!@ X_\8   ?^_^    ?^_^ .  S^=
+M\ 8'@ ,_O'@#@ _W+_&   '_O_@   '_O_@#@ ,[C? &J : ! &! X@#@ ,G
+M!' #@ .I%3@#@ .I%3@#@ .C!> &!H 6 8$ "    ?\?\    _]_^    _]_
+M^ .  U\:X 8'@!5_/'@   '?&_    -7:O@   -7:O@#@ -;"N &J : ! &!
+M!^ #@ .G!7 #@ .I%3 #@ .I%3 #@ ,& . &!H " 8$$@! !_Q_P   #_W_P
+M   #_W_P X #_A_@!@> %7\X$    5\:\    U=J\    U=J\ .  _X?X :H
+M  #_ B@H**@/@ '@#H " > (#X !X Z  @_@" ^  > .@ (/^ B>@ +P!X@.
+M@ (!\ .  3X*@ (#P @.@ (!\ Z  C_ " Z  @'P X " ? )@ (_\ B>@ + 
+M#X@.@ (!\ .  7 *@ (/P @.@ (!\ Z  G_ " Z  @'P X "#_@)@ )_X B>
+M@ * 'X@.@ ("X .  6 *@ %_"0Z  @+@#H$)#H " ^ #@ (?^ F!@ '@")X!
+M@ $?B B  R  0 .  C^@ X !8 6  ?P$@ %^"0Z  C^@"8 !_ .  @'^"0B 
+M R  0 .  C_@ X "'_@(@ ,!_^ (F8 ! X.  _X 'X@(@ -@ & #@8 !P . 
+M 6 $@ ,'_X #@0D.@8 !P B !P?_@    ?\)"( #8 !@ X&  < #@ (?^ B 
+M P'_P B8@ CX '____X /X@(@ AP &    '_P .  6 $@ ,.+\ #@8 !@ @-
+M@ ,!_\ (@ @.+\    /_@ @(@ AP &    '_P .  A_X"( # __ "(J  7^-
+M@ CP #____Q^/X@(@ H__N    /_X  !@X +_@  $/_@   !_X (#8 # __@
+M"( ($/_@   #_X ("( (/X;@   #_^ -@ ,#_\ (B( "O@:.@ C@ !____Q_
+M/X@(@ A__^    ?_\ B "!?NX    >N " J !B    ?_\ B "!?NX    ^N 
+M" B "G\#X   !__P  .$!X # __ "(B  _P#WXV ".  '____/\_B B "#__
+MP   !__P"( (/__P   !U8 ("H &0   !__P"( (/__P   #U8 ("( */@' 
+M   '__   8.  ?X'@ ,#_\ (B( #^ &_C8 (P  /___\_S^("( "#_\#@ @.
+M '    '__P. ""@ \    >N " V  P__\ .  A;1 X (+__P   #ZX ("( !
+M# 2  P__\ 2  0$#@ ('_P.  P/_P B(@ +P (B  _X6T8. ",?_#____/\_
+MB B  @__ X (#  P   !XQX#@ AQ2G    '_@ @-@ ,/__ #@ )_^@. "'XQ
+M\    _^ " B  0@$@ ,/__ #@ (<X@. " __@    [W "(B  O  B( #_F,;
+M@X (CWN/___\_S^("( "#_\#@ ,,!# #@ +)0@. "'*U$    [V " V  P\<
+M< .!@ '^ X (?)30   #_X ("( !# 2  P_[\ .  C[^ X (#^_    #P\ (
+MB( "\ ")@ +K7X. "(ZUS____/\_B B  @__ X ## 0P!( !@@. "E 0,   
+M [V  & &#8 ##__P X&  ?X#@ I?__    /#@ !@!@V  P_[\ .!@ %^ X *
+M#^_    #P\  8 :(@ +X 8Z "(__S____,,_B B  @__ X ##  P!( ! @. 
+M"I@(<    \. #_P&#8 ##__P X&  ?X#@ J?__    /_@ _\!@V  P__\ .!
+M@ '^ X *!_>    #O< /_ :8@ @'_X____S_/X@(@ (((0.  P0 ( . #PA$
+M8   N !P   #_[#__@8(@ (&<@.  P?_X . #W>\8   O__P   #_[#__@8(
+M@ ('W@.  P?_X . #W>\8   !_^    #P_#__@:(@ +^<XF  O>_@X (!_^/
+M___\_S^("( ""#$#@ ,"'$ #@ ]'B?P8 ;1X\    _\[__X&"( "!_X#@ ,#
+MX\ #@ ]X>?P8 ;>'\    _\[__X&"( "!\X#@ ,#X\ #@ =X>?P8  .' X %
+M __[__X&CH !XX2 #?A____^ X</___\?C^("8 !$ .  P, P . #V 9_GP#
+M?C'P   #@'___@8(@ (/_P.  P/_P . #W_Y_GP#?\_P   #@'___@8(@ (/
+M[P.  P/_P . !W_Y_GP  \\#@ $#@X !_@:7@ G\ \\/___\ #^("( "" $#
+M@!4#@< ?   P,?_^ O\#Y_   ,'/_\(&"( "#_\#@!4#_\ ?   _\?_^ L'^
+M)_  #\'/_\(&"( "#_\#@!$#_\ ?   _\?_^  '^!_  #X.  <(&EX )_#__
+MW___\  /B B !03B ( !@X #OX #@X ,_@<Y_X/_  Y_@__ !@B "P<> (  
+M 'X /X #@X ,_@<!_@/_ #__@__ !@B !0<> ( !@X .OX  #\#__@#'_G__
+M #^#@ ' !HF #Q____X ?@!___P/P/__^(6  \   X@(@ 4&9@&  (2 $=@%
+MG_G__@XX_X'_ !Y\ ?^ !@B "P>> 8   #P _]@'@X ,_@X _ '_ '[^ ?^ 
+M!@B !0>> 8  A( -V  /P'_^ <?\?_\ ?X.  8 &B8 !GX,!@ H\ /__^ _ 
+M?__QA8 #@  !B B !0,/ X  A( 1^ ^?^?_^,C\"@?^ /P !_X &"( + _\#
+M@ "   '_^ ^#@ S^,P   _^ ?WP!_X &"( 6 _\#@ !___[_^  '@#_^ <#]
+M?_^ ?X.  8 &C8 +@  !___P!X __\&%@ .   &("( : ?CC@  ?__C_^ /_
+M_S_^)@.'@?^ ?X  _X &"( +!__C@ #@  ?_^ ^#@ S^)T$$#_^ _X  _X &
+M"( 5!__C@ #G_^?_^ P  /_^ ?QX?_^ A( !@ :(@ +Y^(. "^  !____   
+M___!A0.("( 9 ?A[X  ?__C_X "[/!_^/@// ?^ __\ _@<(@ L/__O@ .  
+M!__@'X. "_X_P@@'_X#__P#^!PB %0__^^  X__'_^ ?  /__@'\,/__@(. 
+M ?X'B( (\?A____@  ># 8 $ ___P84#B F &/ _^  ?__C_P #_-!_^>@//
+M ?^ __X _ <(@ L____X .0 )__ 'X. "_Y[X  ?_X#__@#\!PB %3____@ 
+MY__G_\ ?  /__@'\,/__@(.  ?P'B( (P/ ____D "># 8 $ ___@84#B B 
+M&7  '__PG! Y_\ #Y_\?_]X;SV'_@!_^,/X'"( %0_P?__"$@ + 'X2 "M_X
+M '__@/_^-_X'"( !#X. $?!O__;_P!\  ___@>PP__^ @X !_@>(@ +P (. 
+M _P /X,!@ 0#__^AA8 #^  WB B &?  #__@GBBY_\ #YO\?_\X;CF'_@!/\
+M./X'"( %@?@/_^"$@ + 'X2 "L_X '__@//\/_X'"( !#X. %>!O__;_P!\ 
+M ___@>1Q__^ \____@>(@ +P (.  _P /X,!@ 4#__^Q]X2  _P /X@'@!H!
+M\  G_P ,1##_@ .?SQ__GCP \?^  _YX_P<)@ 3P!_\ A( "@!^$@ J?_ #_
+M_X#C_G__!PB !0__W_\ A( (@!\  ___@<>#@ * XX,'B( "\ "#@ /\ #^#
+M 8 % ___X>>$@ /\ '^(!X : _@!V_\ #((P_X !F<X?\^8?_^'_@ !\?/\'
+M"( %. '#_P"$@ * 'X. "_/G_@'__X#!_'__!PB !3__Y_\ A( -@!\  __S
+MX>X!__^ P8,'B( "^ &#@ /\ #^# 8 % ___^>^$@ /^ '^(!X : _P#^_X 
+M#1%P_X #^?\?\8P^ ?'_  #^?_X'"( %? /C_@"$@ * 'X. "_&-_@'__P !
+M_G_^!PB !7__Y_X A( (@!\  __Q@<># 8 $ ?___@>(@ +\ X.  _P /X,!
+M@ 4#___SYX2  _X ?X@'@!H#_ /__@ . +#_@ /_]Q_P #ZD\?P  'P_[@<(
+M@ 5\ ^/^ (2  H ?@X +\ '^ /_\  '\/^X'"( %?__C_@"$@!" 'X '__ !
+M]UO__  !___N!XB  OP#@X #_  _@X "@ >#@ 'WA( #_@ _B B !@__P_X 
+M X,"@ Y@!__@ #7^__@  /Z_[@<'@ 4#R!'__@.  C__ X -!__@ #0 __@ 
+M _Z_[@<'@!H#R '__@ #@#__   ?___@  8!__@  ___[@>)@ 'O@X #_  _
+MB( !SX2  _P /X@)@!@XP_P  ____@  8 ?_X  '___X  '^/\P'!X % \ X
+M__P#@ (__@. #0?_X  $ /_X  /^/\P'!X : \_'__P  X(__@  '___X  $
+M /_X  /__\P'B8 !QX.  _P /XV  _P /X@)@!@8X_@  ]___@  8 ?_P  #
+MMW_X  #^O\ '!X % X 8__@#@ (__@. #0?_P   ,'_X  ?^O\ '!X : X_G
+M__@  Z(__@  '___P  $>/_X  ?__\ 'B8 !YX.  _P@/XV  _@ /X@(@!@/
+MQ__P  /?_YP  #,'YX  ![-^.  #_C\("( 8" #_\   '#^<  !##^>    P
+M?C@ !_X_" F %SC_\  #OC^<  !/_^>   !\_C@ !___"(V  _P\/XV  _@ 
+M/X@(@!@/S__P  /__YP   ,'YX  ![M^>  #_]\("( 8" #_\   '#^<  !_
+M_^>    X?G@ #__?" F %S#_\  #GC^<  !__^>   !\_G@ #___"(V  _P<
+M/XV  _  'X@(@!D/___   /__YP   ,'XX  !7A^>  '_Q^ !PF &&#_P   
+M'#^<  !__^.   +Y?G@ '_\?@ <)@!A@_\   YX_G   ?__C@  "__YX !__
+M_X 'C8 #_!P_C8 #X  ?B B "#___P  '___ X # P#@ X (<'XP !?_I\ '
+M"8 "\#\#@!,\!P   ___X   !W/^, !__Z? !PF &/ _   ?__\   /__^  
+M  ?W_C  ?___P >-@ /@/ >-@ .   >("( (?\_\   ?\_\#@ ,# . #@ A@
+M'@  /__+P <)@ + ' . $S '   #___@   ?Y_X  /__R\ '"8 4P!P  !_S
+M_P   ___X   '^?^  "#@ ' !XV  ^ \!XT"@ $#B B "'_'_   '_'_ X #
+M#@#@ X '8 X  %__T0@(@ ,!P!P#@!)P!P   _X_X   /^?^  /__]$("( 5
+M < <   ?\?\   /^/^   #_G_@ #@PB-@ /@?@>,@ 3\   !B!V  W__\ @=
+4@ -___ ('8 #?__P")V  X  #X@ 
+end
diff --git a/win/gem/wingem.c b/win/gem/wingem.c
new file mode 100644 (file)
index 0000000..ceb59d7
--- /dev/null
@@ -0,0 +1,1242 @@
+/*     SCCS Id: @(#)wingem.c   3.4     1999/12/10                              */
+/* Copyright (c) Christian Bressler, 1999                                      */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "func_tab.h"
+#include "dlb.h"
+#include <ctype.h>
+#ifdef SHORT_FILENAMES
+#include "patchlev.h"
+#else
+#include "patchlevel.h"
+#endif
+
+#ifdef GEM_GRAPHICS
+#include "wingem.h"
+
+static char nullstr[] = "", winpanicstr[] = "Bad window id %d";
+static int curr_status_line;
+
+static char *FDECL(copy_of, (const char *));
+static void FDECL(bail, (const char *));       /* __attribute__((noreturn)) */
+
+extern int mar_set_tile_mode(int);
+extern void mar_set_font(int,const char*,int);
+extern void mar_set_margin(int);
+extern void mar_set_msg_visible(int);
+extern void mar_set_status_align(int);
+extern void mar_set_msg_align(int);
+extern void mar_set_tilefile(char *);
+extern void mar_set_tilex(int);
+extern void mar_set_tiley(int);
+extern short glyph2tile[MAX_GLYPH];            /* from tile.c */
+extern void mar_display_nhwindow(winid);       /* from wingem1.c */
+
+void Gem_outrip(winid,int);
+void Gem_preference_update(const char *);
+/* Interface definition, for windows.c */
+struct window_procs Gem_procs = {
+    "Gem",
+       WC_COLOR|WC_HILITE_PET|WC_ALIGN_MESSAGE|WC_ALIGN_STATUS|
+       WC_INVERSE|WC_SCROLL_MARGIN|
+       WC_FONT_MESSAGE|WC_FONT_STATUS|WC_FONT_MENU|WC_FONT_TEXT|WC_FONT_MAP|
+       WC_FONTSIZ_MESSAGE|WC_FONTSIZ_STATUS|WC_FONTSIZ_MENU|WC_FONTSIZ_TEXT|WC_FONTSIZ_MAP|
+       WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE|WC_VARY_MSGCOUNT|WC_ASCII_MAP,
+    0L,
+    Gem_init_nhwindows,
+    Gem_player_selection,
+    Gem_askname,
+    Gem_get_nh_event,
+    Gem_exit_nhwindows,
+    Gem_suspend_nhwindows,
+    Gem_resume_nhwindows,
+    Gem_create_nhwindow,
+    Gem_clear_nhwindow,
+    Gem_display_nhwindow,
+    Gem_destroy_nhwindow,
+    Gem_curs,
+    Gem_putstr,
+    Gem_display_file,
+    Gem_start_menu,
+    Gem_add_menu,
+    Gem_end_menu,
+    Gem_select_menu,
+    genl_message_menu,
+    Gem_update_inventory,
+    Gem_mark_synch,
+    Gem_wait_synch,
+#ifdef CLIPPING
+    Gem_cliparound,
+#endif
+#ifdef POSITIONBAR
+    Gem_update_positionbar,
+#endif
+    Gem_print_glyph,
+    Gem_raw_print,
+    Gem_raw_print_bold,
+    Gem_nhgetch,
+    Gem_nh_poskey,
+    Gem_nhbell,
+    Gem_doprev_message,
+    Gem_yn_function,
+    Gem_getlin,
+    Gem_get_ext_cmd,
+    Gem_number_pad,
+    Gem_delay_output,
+#ifdef CHANGE_COLOR    /* the Mac uses a palette device */
+    Gem_change_color,
+#ifdef MAC
+    Gem_change_background,
+    Gem_set_font_name,
+#endif
+    Gem_get_color_string,
+#endif
+
+    /* other defs that really should go away (they're tty specific) */
+    Gem_start_screen,
+    Gem_end_screen,
+    Gem_outrip,
+    Gem_preference_update
+};
+
+#ifdef MAC
+void *
+Gem_change_background(dummy)
+int dummy;
+{}
+
+short *
+Gem_set_font_name(foo,bar)
+winid foo;
+char *bar;
+{}
+#endif
+
+/*************************** Proceduren *************************************/
+
+int mar_hp_query(void){
+       if(Upolyd)
+               return(u.mh ? u.mhmax/u.mh : -1);
+       return(u.uhp ? u.uhpmax/u.uhp : -1);
+}
+
+int
+mar_iflags_numpad()
+{
+       return(iflags.num_pad ? 1 : 0);
+}
+
+int
+mar_get_msg_history()
+{
+       return(iflags.msg_history);
+}
+
+int
+mar_get_msg_visible()
+{
+       return(iflags.wc_vary_msgcount);
+}
+/* clean up and quit */
+static void
+bail(mesg)
+const char *mesg;
+{
+    clearlocks();
+    Gem_exit_nhwindows(mesg);
+    terminate(EXIT_SUCCESS);
+    /*NOTREACHED*/
+}
+
+/*$$$*/
+#define DEF_CLIPAROUND_MARGIN  -1
+#ifndef TILE_X
+#define TILE_X 16
+#endif
+#define TILE_Y 16
+#define TILES_PER_LINE  20
+#define NHFONT_DEFAULT_SIZE 10
+#define NHFONT_SIZE_MIN 3
+#define NHFONT_SIZE_MAX 20
+/*$$$*/
+/*ARGSUSED*/
+void
+Gem_init_nhwindows(argcp,argv)
+int* argcp;
+char** argv;
+{
+       argv=argv, argcp=argcp;
+       colors_changed=TRUE;
+
+       set_wc_option_mod_status(
+               WC_ALIGN_MESSAGE |
+               WC_ALIGN_STATUS |
+          WC_TILE_WIDTH |
+          WC_TILE_HEIGHT |
+          WC_TILE_FILE,
+          DISP_IN_GAME);
+       set_wc_option_mod_status(
+               WC_HILITE_PET |
+               WC_SCROLL_MARGIN |
+               WC_FONT_MESSAGE |
+               WC_FONT_MAP |
+               WC_FONT_STATUS |
+               WC_FONT_MENU |
+               WC_FONT_TEXT |
+               WC_FONTSIZ_MESSAGE |
+               WC_FONTSIZ_MAP |
+               WC_FONTSIZ_STATUS |
+               WC_FONTSIZ_MENU |
+               WC_FONTSIZ_TEXT |
+               WC_VARY_MSGCOUNT,
+               SET_IN_GAME
+       );
+       if( iflags.wc_align_message==0 ) iflags.wc_align_message = ALIGN_TOP;
+       if( iflags.wc_align_status==0 ) iflags.wc_align_status = ALIGN_BOTTOM;
+       if( iflags.wc_scroll_margin==0 ) iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN;
+       if( iflags.wc_tile_width==0 ) iflags.wc_tile_width = TILE_X;
+       if( iflags.wc_tile_height==0 ) iflags.wc_tile_height = TILE_Y;
+       if(iflags.wc_tile_file && *iflags.wc_tile_file)
+               mar_set_tilefile(iflags.wc_tile_file);
+       if( iflags.wc_vary_msgcount==0 ) iflags.wc_vary_msgcount = 3;
+       mar_set_tile_mode(!iflags.wc_ascii_map);        /* MAR -- 17.Mar 2002 True is tiles */
+       mar_set_tilex(iflags.wc_tile_width);
+       mar_set_tiley(iflags.wc_tile_height);
+       mar_set_msg_align(iflags.wc_align_message-ALIGN_BOTTOM);
+       mar_set_status_align(iflags.wc_align_status-ALIGN_BOTTOM);
+       if(mar_gem_init()==0){
+               bail((char *)0);
+    /*NOTREACHED*/
+       }
+       iflags.window_inited = TRUE;
+
+       CO=80;  /* MAR -- whatsoever */
+       LI=25;
+
+       add_menu_cmd_alias(' ', MENU_NEXT_PAGE);
+       mar_set_no_glyph(NO_GLYPH);
+}
+
+void
+Gem_player_selection()
+{
+       int i, k, n;
+       char pick4u = 'n', pbuf[QBUFSZ], lastch=0, currch;
+       winid win;
+       anything any;
+       menu_item *selected=NULL;
+
+       /* avoid unnecessary prompts further down */
+       rigid_role_checks();
+
+       /* Should we randomly pick for the player? */
+       if (!flags.randomall &&
+           (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE ||
+               flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {
+/*             pick4u = yn_function("Shall I pick a character for you? [ynq]",ynqchars,'n');*/
+               pick4u = yn_function(
+                       build_plselection_prompt(pbuf, QBUFSZ, flags.initrole,flags.initrace,
+                               flags.initgend, flags.initalign)
+                       ,ynqchars,'n'
+               );
+               if(pick4u=='q'){
+give_up:               /* Just quit */
+                       if (selected) free((genericptr_t) selected);
+                       bail((char *)0);
+                       /*NOTREACHED*/
+                       return;
+               }
+       }
+
+       /* Select a role, if necessary */
+       if (flags.initrole < 0) {
+
+               /* Process the choice */
+               if(pick4u=='y' || flags.initrole == ROLE_RANDOM || flags.randomall) {
+                       /* Pick a random role */
+                       flags.initrole = pick_role(flags.initrace, flags.initgend,
+                                                       flags.initalign, PICK_RANDOM);
+                       if (flags.initrole < 0) {
+                               mar_add_message("Incompatible role!");
+                               mar_display_nhwindow(WIN_MESSAGE);
+                               flags.initrole = randrole();
+                       }
+               }else{
+                       /* Prompt for a role */
+                       win = create_nhwindow(NHW_MENU);
+                       start_menu(win);
+                       any.a_void = 0;         /* zero out all bits */
+                       for (i = 0; roles[i].name.m; i++) {
+                               if (ok_role(i, flags.initrace, flags.initgend,
+                                        flags.initalign)) {
+                                       any.a_int = i+1;        /* must be non-zero */
+                                       currch = lowc(roles[i].name.m[0]);
+                                       if(currch == lastch)
+                                               currch = highc(currch);
+                                       add_menu(win, roles[i].malenum, &any, currch,
+                                                       0, ATR_NONE, an(roles[i].name.m), MENU_UNSELECTED);
+                                       lastch = currch;
+                               }
+                       }
+                       any.a_int = pick_role(flags.initrace, flags.initgend,
+                                           flags.initalign, PICK_RANDOM)+1;
+                       if (any.a_int == 0)     /* must be non-zero */
+                           any.a_int = randrole()+1;
+                       add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                               "Random", MENU_UNSELECTED);
+                       any.a_int = i+1;        /* must be non-zero */
+                       add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                               "Quit", MENU_UNSELECTED);
+                       end_menu(win, "Pick a role");
+                       n = select_menu(win, PICK_ONE, &selected);
+                       destroy_nhwindow(win);
+
+                       /* Process the choice */
+                       if (n != 1 || selected[0].item.a_int == any.a_int)
+                           goto give_up;               /* Selected quit */
+
+                       flags.initrole = selected[0].item.a_int - 1;
+                       free((genericptr_t) selected),  selected = 0;
+               }
+       }
+
+       /* Select a race, if necessary */
+       /* force compatibility with role, try for compatibility with
+        * pre-selected gender/alignment */
+       if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
+               /* pre-selected race not valid */
+               if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) {
+                       flags.initrace = pick_race(flags.initrole, flags.initgend,
+                                                       flags.initalign, PICK_RANDOM);
+                       if (flags.initrace < 0) {
+                               mar_add_message("Incompatible race!");
+                               mar_display_nhwindow(WIN_MESSAGE);
+                               flags.initrace = randrace(flags.initrole);
+                       }
+               } else {        /* pick4u == 'n' */
+                       /* Count the number of valid races */
+                       n = 0;  /* number valid */
+                       k = 0;  /* valid race */
+                       for (i = 0; races[i].noun; i++) {
+                               if (ok_race(flags.initrole, i, flags.initgend,
+                                                               flags.initalign)) {
+                                       n++;
+                                       k = i;
+                               }
+                       }
+                       if (n == 0) {
+                               for (i = 0; races[i].noun; i++) {
+                                       if (validrace(flags.initrole, i)) {
+                                               n++;
+                                               k = i;
+                                       }
+                               }
+                       }
+                       /* Permit the user to pick, if there is more than one */
+                       if (n > 1) {
+                               win = create_nhwindow(NHW_MENU);
+                               start_menu(win);
+                               any.a_void = 0;         /* zero out all bits */
+                               for (i = 0; races[i].noun; i++)
+                                       if (ok_race(flags.initrole, i, flags.initgend,
+                                                                       flags.initalign)) {
+                                               any.a_int = i+1;        /* must be non-zero */
+                                               add_menu(win, NO_GLYPH, &any, races[i].noun[0],
+                                                       0, ATR_NONE, races[i].noun, MENU_UNSELECTED);
+                                       }
+                               any.a_int = pick_race(flags.initrole, flags.initgend,
+                                       flags.initalign, PICK_RANDOM)+1;
+                               if (any.a_int == 0)     /* must be non-zero */
+                                       any.a_int = randrace(flags.initrole)+1;
+                               add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                               "Random", MENU_UNSELECTED);
+                               any.a_int = i+1;        /* must be non-zero */
+                               add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                               "Quit", MENU_UNSELECTED);
+                               Sprintf(pbuf, "Pick the race of your %s",
+                                               roles[flags.initrole].name.m);
+                               end_menu(win, pbuf);
+                               n = select_menu(win, PICK_ONE, &selected);
+                               destroy_nhwindow(win);
+                               if (n != 1 || selected[0].item.a_int == any.a_int)
+                                   goto give_up;               /* Selected quit */
+                               k = selected[0].item.a_int - 1;
+                               free((genericptr_t) selected),  selected = 0;
+                       }
+                       flags.initrace = k;
+               }
+       }
+
+       /* Select a gender, if necessary */
+       /* force compatibility with role/race, try for compatibility with
+        * pre-selected alignment */
+       if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
+                                               flags.initgend)) {
+               /* pre-selected gender not valid */
+               if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) {
+                       flags.initgend = pick_gend(flags.initrole, flags.initrace,
+                                                       flags.initalign, PICK_RANDOM);
+                       if (flags.initgend < 0) {
+                               mar_add_message("Incompatible gender!");
+                               mar_display_nhwindow(WIN_MESSAGE);
+                               flags.initgend = randgend(flags.initrole, flags.initrace);
+                       }
+               } else {        /* pick4u == 'n' */
+                       /* Count the number of valid genders */
+                       n = 0;  /* number valid */
+                       k = 0;  /* valid gender */
+                       for (i = 0; i < ROLE_GENDERS; i++) {
+                               if (ok_gend(flags.initrole, flags.initrace, i,
+                                                               flags.initalign)) {
+                                       n++;
+                                       k = i;
+                               }
+                       }
+                       if (n == 0) {
+                               for (i = 0; i < ROLE_GENDERS; i++) {
+                                       if (validgend(flags.initrole, flags.initrace, i)) {
+                                               n++;
+                                               k = i;
+                                       }
+                               }
+                       }
+                       /* Permit the user to pick, if there is more than one */
+                       if (n > 1) {
+                               win = create_nhwindow(NHW_MENU);
+                               start_menu(win);
+                               any.a_void = 0;         /* zero out all bits */
+                               for (i = 0; i < ROLE_GENDERS; i++)
+                                       if (ok_gend(flags.initrole, flags.initrace, i,
+                                                                           flags.initalign)) {
+                                               any.a_int = i+1;
+                                               add_menu(win, NO_GLYPH, &any, genders[i].adj[0],
+                                                       0, ATR_NONE, genders[i].adj, MENU_UNSELECTED);
+                                       }
+                               any.a_int = pick_gend(flags.initrole, flags.initrace,
+                                                   flags.initalign, PICK_RANDOM)+1;
+                               if (any.a_int == 0)     /* must be non-zero */
+                                       any.a_int = randgend(flags.initrole, flags.initrace)+1;
+                               add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                               "Random", MENU_UNSELECTED);
+                               any.a_int = i+1;        /* must be non-zero */
+                               add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                               "Quit", MENU_UNSELECTED);
+                               Sprintf(pbuf, "Pick the gender of your %s %s",
+                                               races[flags.initrace].adj,
+                                               roles[flags.initrole].name.m);
+                               end_menu(win, pbuf);
+                               n = select_menu(win, PICK_ONE, &selected);
+                               destroy_nhwindow(win);
+                               if (n != 1 || selected[0].item.a_int == any.a_int)
+                                   goto give_up;               /* Selected quit */
+                               k = selected[0].item.a_int - 1;
+                               free((genericptr_t) selected),  selected = 0;
+                       }
+                       flags.initgend = k;
+               }
+       }
+
+       /* Select an alignment, if necessary */
+       /* force compatibility with role/race/gender */
+       if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
+                                                       flags.initalign)) {
+               /* pre-selected alignment not valid */
+               if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) {
+                       flags.initalign = pick_align(flags.initrole, flags.initrace,
+                                                       flags.initgend, PICK_RANDOM);
+                       if (flags.initalign < 0) {
+                           mar_add_message("Incompatible alignment!");
+                                mar_display_nhwindow(WIN_MESSAGE);
+                           flags.initalign = randalign(flags.initrole, flags.initrace);
+                       }
+               } else {        /* pick4u == 'n' */
+                       /* Count the number of valid alignments */
+                       n = 0;  /* number valid */
+                       k = 0;  /* valid alignment */
+                       for (i = 0; i < ROLE_ALIGNS; i++) {
+                           if (ok_align(flags.initrole, flags.initrace, flags.initgend,
+                                                               i)) {
+                               n++;
+                               k = i;
+                           }
+                       }
+                       if (n == 0) {
+                           for (i = 0; i < ROLE_ALIGNS; i++) {
+                               if (validalign(flags.initrole, flags.initrace, i)) {
+                                   n++;
+                                   k = i;
+                               }
+                           }
+                       }
+                       /* Permit the user to pick, if there is more than one */
+                       if (n > 1) {
+                               win = create_nhwindow(NHW_MENU);
+                               start_menu(win);
+                               any.a_void = 0;         /* zero out all bits */
+                               for (i = 0; i < ROLE_ALIGNS; i++)
+                                       if (ok_align(flags.initrole, flags.initrace,
+                                                                       flags.initgend, i)) {
+                                               any.a_int = i+1;
+                                               add_menu(win, NO_GLYPH, &any, aligns[i].adj[0],
+                                                       0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
+                                       }
+                               any.a_int = pick_align(flags.initrole, flags.initrace,
+                                                   flags.initgend, PICK_RANDOM)+1;
+                               if (any.a_int == 0)     /* must be non-zero */
+                                       any.a_int = randalign(flags.initrole, flags.initrace)+1;
+                               add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                               "Random", MENU_UNSELECTED);
+                               any.a_int = i+1;        /* must be non-zero */
+                               add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                               "Quit", MENU_UNSELECTED);
+                               Sprintf(pbuf, "Pick the alignment of your %s %s %s",
+                                               genders[flags.initgend].adj,
+                                               races[flags.initrace].adj,
+                                               (flags.initgend && roles[flags.initrole].name.f) ?
+                                               roles[flags.initrole].name.f :
+                                               roles[flags.initrole].name.m);
+                               end_menu(win, pbuf);
+                               n = select_menu(win, PICK_ONE, &selected);
+                               destroy_nhwindow(win);
+                               if (n != 1 || selected[0].item.a_int == any.a_int)
+                                   goto give_up;               /* Selected quit */
+                               k = selected[0].item.a_int - 1;
+                               free((genericptr_t) selected),  selected = 0;
+                       }
+                       flags.initalign = k;
+               }
+       }
+
+       /* Success! */
+       return;
+}
+
+/*
+ * plname is filled either by an option (-u Player  or  -uPlayer) or
+ * explicitly (by being the wizard) or by askname.
+ * It may still contain a suffix denoting pl_character.
+ * Always called after init_nhwindows() and before display_gamewindows().
+ */
+
+void
+Gem_askname()
+{
+       strncpy(plname,mar_ask_name(),PL_NSIZ);
+}
+
+void
+Gem_get_nh_event()
+{}
+
+void
+Gem_suspend_nhwindows(str)
+    const char *str;
+{
+       const char *foo;
+
+       foo=str;        /* MAR -- And the compiler whines no more ... */
+}
+
+void
+Gem_resume_nhwindows()
+{}
+
+void
+Gem_end_screen()
+{}
+
+void
+Gem_start_screen()
+{}
+
+extern void mar_exit_nhwindows(void);
+extern boolean run_from_desktop;
+
+void
+Gem_exit_nhwindows(str)
+    const char *str;
+{
+       if(str) Gem_raw_print(str);
+       mar_exit_nhwindows();
+       if(flags.toptenwin)
+               run_from_desktop=FALSE;
+       iflags.window_inited = 0;
+}
+
+winid
+Gem_create_nhwindow(type)
+    int type;
+{
+       winid newid;
+
+       switch(type) {
+       case NHW_MESSAGE:
+               if(iflags.msg_history < 20) iflags.msg_history = 20;
+               else if(iflags.msg_history > 60) iflags.msg_history = 60;
+               break;
+       case NHW_STATUS:
+       case NHW_MAP:
+       case NHW_MENU:
+       case NHW_TEXT:
+               break;
+       default:
+               panic("Tried to create window type %d\n", (int) type);
+               return WIN_ERR;
+       }
+
+       newid=mar_create_window(type);
+
+       if(newid == MAXWIN) {
+               panic("No window slots!");
+               /* NOTREACHED */
+       }
+
+       return newid;
+}
+
+void
+Gem_nhbell()
+{
+       if (flags.silent) return;
+       putchar('\007');
+       fflush(stdout);
+}
+
+extern void mar_clear_map(void);
+
+void
+Gem_clear_nhwindow(window)
+    winid window;
+{
+       if(window == WIN_ERR)
+               panic(winpanicstr,  window);
+
+       switch(mar_hol_win_type(window)) {
+       case NHW_MESSAGE:
+               mar_clear_messagewin();
+               break;
+       case NHW_MAP:
+               mar_clear_map();
+               break;
+       case NHW_STATUS:
+       case NHW_MENU:
+       case NHW_TEXT:
+               break;
+       }
+}
+
+extern void mar_more(void);
+
+/*ARGSUSED*/
+void
+Gem_display_nhwindow(window, blocking)
+    winid window;
+    boolean blocking;
+{
+       if(window == WIN_ERR)
+               panic(winpanicstr,  window);
+
+       mar_display_nhwindow(window);
+
+       switch(mar_hol_win_type(window)){
+       case NHW_MESSAGE:
+               if(blocking) mar_more();
+               break;
+       case NHW_MAP:
+               if(blocking) Gem_display_nhwindow(WIN_MESSAGE, TRUE);
+               break;
+       case NHW_STATUS:
+       case NHW_TEXT:
+       case NHW_MENU:
+       default:
+               break;
+       }
+}
+
+void
+Gem_destroy_nhwindow(window)
+    winid window;
+{
+       if(window == WIN_ERR)   /* MAR -- test existence */
+               panic(winpanicstr,  window);
+
+       mar_destroy_nhwindow(window);
+}
+
+extern void mar_curs(int,int); /* mar_curs is only for map */
+
+void
+Gem_curs(window, x, y)
+winid window;
+register int x, y;
+{
+       if(window == WIN_ERR)   /* MAR -- test existence */
+               panic(winpanicstr,  window);
+
+       if(window==WIN_MAP)
+               mar_curs(x-1,y);        /*$$$*/
+       else if(window==WIN_STATUS)
+               curr_status_line=y;
+}
+
+extern void mar_add_status_str(const char *, int);
+extern void mar_putstr_text(winid, int, const char *);
+
+void
+Gem_putstr(window, attr, str)
+    winid window;
+    int attr;
+    const char *str;
+{
+       int win_type;
+
+       if(window == WIN_ERR) {
+               Gem_raw_print(str);
+               return;
+       }
+
+       if(str == (const char*)0)
+               return;
+
+       switch((win_type=mar_hol_win_type(window))) {
+       case NHW_MESSAGE:
+               mar_add_message(str);
+               break;
+
+       case NHW_STATUS:
+               mar_status_dirty();
+               mar_add_status_str(str,curr_status_line);
+               if(curr_status_line)
+                       mar_display_nhwindow(WIN_STATUS);
+               break;
+
+       case NHW_MAP:
+               if(strcmp(str,"."))
+                       Gem_putstr(WIN_MESSAGE,0,str);
+               else
+                       mar_map_curs_weiter();
+               mar_display_nhwindow(WIN_MESSAGE);
+               mar_display_nhwindow(WIN_STATUS);
+               break;
+
+       case NHW_MENU:
+               mar_change_menu_2_text(window);
+               /* Fallthru */
+       case NHW_TEXT:
+               mar_putstr_text(window,attr,str);
+               break;
+       }       /* endswitch win_type */
+}
+
+void
+Gem_display_file(fname, complain)
+const char *fname;
+boolean complain;
+{
+       dlb *f;
+       char buf[BUFSZ];
+       char *cr;
+
+       f = dlb_fopen(fname, "r");
+       if (!f) {
+               if(complain)
+                       pline("Cannot open \"%s\".", fname);
+       } else {
+               winid datawin;
+
+               datawin = Gem_create_nhwindow(NHW_TEXT);
+               while (dlb_fgets(buf, BUFSZ, f)) {
+                       if ((cr = index(buf, '\n')) != 0) *cr = 0;
+                       if (index(buf, '\t') != 0) (void) tabexpand(buf);
+                       Gem_putstr(datawin, 0, buf);
+               }
+               (void) dlb_fclose(f);
+               Gem_display_nhwindow(datawin, FALSE);
+               Gem_destroy_nhwindow(datawin);
+       }
+}
+
+/*ARGSUSED*/
+/*
+ * Add a menu item to the beginning of the menu list.  This list is reversed
+ * later.
+ */
+void
+Gem_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected)
+    winid window;      /* window to use, must be of type NHW_MENU */
+    int glyph;         /* glyph to display with item (unused) */
+    const anything *identifier;        /* what to return if selected */
+    char ch;           /* keyboard accelerator (0 = pick our own) */
+    char gch;          /* group accelerator (0 = no group) */
+    int attr;          /* attribute for string (like Gem_putstr()) */
+    const char *str;   /* menu string */
+    boolean preselected; /* item is marked as selected */
+{
+       Gem_menu_item *G_item;
+       const char *newstr;
+       char buf[QBUFSZ];
+
+       if (str == (const char*) 0)
+               return;
+
+       if (window == WIN_ERR)  /* MAR -- test existence */
+               panic(winpanicstr,  window);
+
+       if (identifier->a_void)
+               Sprintf(buf, "%c - %s", ch ? ch : '?', str);
+       else
+               Sprintf(buf, "%s", str);
+       newstr = buf;
+
+       G_item = (Gem_menu_item *) alloc(sizeof(Gem_menu_item));
+       G_item->Gmi_identifier = (long)identifier->a_void;
+       G_item->Gmi_glyph = glyph!=NO_GLYPH ? glyph2tile[glyph] : NO_GLYPH;
+       G_item->Gmi_count = -1L;
+       G_item->Gmi_selected = preselected ? 1 : 0;
+       G_item->Gmi_accelerator = ch;
+       G_item->Gmi_groupacc = gch;
+       G_item->Gmi_attr = attr;
+       G_item->Gmi_str = copy_of(newstr);
+       mar_add_menu(window, G_item);
+}
+
+/*
+ * End a menu in this window, window must a type NHW_MENU.
+ * We assign the keyboard accelerators as needed.
+ */
+void
+Gem_end_menu(window, prompt)
+    winid window;      /* menu to use */
+    const char *prompt;        /* prompt to for menu */
+{
+       if(window == WIN_ERR || mar_hol_win_type(window) != NHW_MENU)
+               panic(winpanicstr,  window);
+
+       /* Reverse the list so that items are in correct order. */
+       mar_reverse_menu();
+
+       /* Put the prompt at the beginning of the menu. */
+       mar_set_menu_title(prompt);
+
+       mar_set_accelerators();
+}
+
+int
+Gem_select_menu(window, how, menu_list)
+    winid window;
+    int how;
+    menu_item **menu_list;
+{
+       Gem_menu_item *Gmit;
+       menu_item *mi;
+       int n;
+
+       if(window == WIN_ERR || mar_hol_win_type(window) != NHW_MENU)
+               panic(winpanicstr,  window);
+
+       *menu_list = (menu_item *) 0;
+       mar_set_menu_type(how);
+       Gem_display_nhwindow(window, TRUE);
+
+       for (n = 0, Gmit = mar_hol_inv(); Gmit; Gmit = Gmit->Gmi_next)
+               if (Gmit->Gmi_selected) n++;
+
+       if (n > 0) {
+               *menu_list = (menu_item *) alloc(n * sizeof(menu_item));
+               for (mi = *menu_list, Gmit = mar_hol_inv(); Gmit; Gmit = Gmit->Gmi_next)
+                       if (Gmit->Gmi_selected) {
+                               mi->item = (anything)(genericptr_t)Gmit->Gmi_identifier;
+                               mi->count = Gmit->Gmi_count;
+                               mi++;
+                       }
+       }
+
+       return n;
+}
+
+void
+Gem_update_inventory()
+{}
+
+void
+Gem_mark_synch()
+{
+       mar_display_nhwindow(WIN_MESSAGE);
+       mar_display_nhwindow(WIN_MAP);
+       mar_display_nhwindow(WIN_STATUS);
+}
+
+void
+Gem_wait_synch()
+{
+       mar_display_nhwindow(WIN_MESSAGE);
+       mar_display_nhwindow(WIN_MAP);
+       mar_display_nhwindow(WIN_STATUS);
+}
+
+#ifdef CLIPPING
+extern void mar_cliparound(void);
+void
+Gem_cliparound(x, y)
+int x, y;
+{
+       mar_curs(x-1,y);
+       mar_cliparound();
+}
+#endif /* CLIPPING */
+
+/*
+ *  Gem_print_glyph
+ *
+ *  Print the glyph to the output device.  Don't flush the output device.
+ *
+ *  Since this is only called from show_glyph(), it is assumed that the
+ *  position and glyph are always correct (checked there)!
+ */
+
+void mar_print_gl_char(winid,xchar,xchar,int);
+
+#ifdef REINCARNATION
+extern int mar_set_rogue(int);
+#endif
+
+extern void mar_add_pet_sign(winid,int,int);
+
+void
+Gem_print_glyph(window, x, y, glyph)
+    winid window;
+    xchar x, y;
+    int glyph;
+{
+    /* Move the cursor. */
+    Gem_curs(window, x,y);
+
+# ifdef REINCARNATION
+               mar_set_rogue(Is_rogue_level(&u.uz) ? TRUE : FALSE);
+# endif
+
+       x--;    /* MAR -- because x ranges from 1 to COLNO */
+       if(mar_set_tile_mode(-1)){
+               mar_print_glyph(window,x,y,glyph2tile[glyph]);
+               if(
+#ifdef TEXTCOLOR
+                       iflags.hilite_pet &&
+#endif
+                       glyph_is_pet(glyph)
+               )
+                       mar_add_pet_sign(window,x,y);
+       }else
+               mar_print_gl_char(window,x,y,glyph);
+}
+
+void mar_print_char(winid,xchar,xchar,char,int);
+
+void mar_print_gl_char(window, x, y, glyph)
+    winid window;
+    xchar x, y;
+    int glyph;
+{
+    int   ch;
+    int            color;
+    unsigned special;
+
+    /* map glyph to character and color */
+    mapglyph(glyph, &ch, &color, &special, x, y);
+
+#ifdef TEXTCOLOR
+    /* Turn off color if rogue level. */
+# ifdef REINCARNATION
+    if (Is_rogue_level(&u.uz)) color = NO_COLOR;
+# endif
+#endif /* TEXTCOLOR */
+
+       mar_print_char(window,x,y,ch,color);
+}
+
+extern void mar_raw_print(const char *);
+extern void mar_raw_print_bold(const char *);
+
+void
+Gem_raw_print(str)
+       const char *str;
+{
+       if(str && *str){
+               if(iflags.window_inited)        mar_raw_print(str);
+               else    printf("%s\n",str);
+       }
+}
+
+void
+Gem_raw_print_bold(str)
+       const char *str;
+{
+       if(str && *str){
+               if(iflags.window_inited)        mar_raw_print_bold(str);
+               else    printf("%s\n",str);
+       }
+}
+
+extern void mar_update_value(void);    /* wingem1.c */
+
+int
+Gem_nhgetch()
+{
+    int i;
+
+       mar_update_value();
+       i = tgetch();
+       if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
+
+    return i;
+}
+
+/* Get a extended command in windowport specific way.
+       returns index of the ext_cmd or -1.
+       called after '#'.
+       It's a menu with all the possibilities. */
+int
+Gem_get_ext_cmd()
+{
+       winid wind;
+       int i, count, what,too_much=FALSE;
+       menu_item *selected=NULL;
+       anything any;
+       char accelerator=0, tmp_acc=0;
+       const char *ptr;
+
+       wind=Gem_create_nhwindow(NHW_MENU);
+       Gem_start_menu(wind);
+       for(i=0;(ptr=extcmdlist[i].ef_txt);i++){
+               any.a_int=i;
+               accelerator=*ptr;
+               if(tmp_acc==accelerator){
+                       if(too_much)
+                               accelerator='&';        /* MAR -- poor choice, anyone? */
+                       else
+                               accelerator+='A'-'a';
+                       too_much=TRUE;
+               }else
+                       too_much=FALSE;
+               tmp_acc=*ptr;
+               Gem_add_menu(wind,NO_GLYPH,&any,accelerator,0,ATR_NONE,ptr,FALSE);
+       }
+       Gem_end_menu(wind,"What extended command?");
+       count=Gem_select_menu(wind,PICK_ONE,&selected);
+       what = count ? selected->item.a_int : -1;
+       if(selected)    free(selected);
+       Gem_destroy_nhwindow(wind);
+       return(what);
+}
+
+void
+Gem_number_pad(state)
+int state;
+{
+       state=state;
+}
+
+void
+win_Gem_init()
+{}
+
+#ifdef POSITIONBAR
+void
+Gem_update_positionbar(posbar)
+char *posbar;
+{}
+#endif
+
+/** Gem_outrip **/
+void mar_set_text_to_rip(winid);
+char** rip_line=0;
+extern const char *killed_by_prefix[];
+void
+Gem_outrip(w, how)
+winid w;
+int how;
+{
+/* Code from X11 windowport */
+#define STONE_LINE_LEN 15    /* # chars that fit on one line */
+#define NAME_LINE 0    /* line # for player name */
+#define GOLD_LINE 1    /* line # for amount of gold */
+#define DEATH_LINE 2   /* line # for death description */
+#define YEAR_LINE 6    /* line # for year */
+       char buf[BUFSZ];
+       char *dpx;
+       int line;
+       if (!rip_line) {
+               int i;
+               rip_line= (char **)malloc((YEAR_LINE+1)*sizeof(char *));
+               for (i=0; i<YEAR_LINE+1; i++) {
+                       rip_line[i]=(char *)malloc((STONE_LINE_LEN+1)*sizeof(char));
+               }
+       }
+       /* Follows same algorithm as genl_outrip() */
+       /* Put name on stone */
+       Sprintf(rip_line[NAME_LINE], "%s", plname);
+       /* Put $ on stone */
+       Sprintf(rip_line[GOLD_LINE], "%ld Au",
+#ifndef GOLDOBJ
+               u.ugold);
+#else
+               done_money);
+#endif
+       /* Put together death description */
+       switch (killer_format) {
+       default: impossible("bad killer format?");
+       case KILLED_BY_AN:
+               Strcpy(buf, killed_by_prefix[how]);
+               Strcat(buf, an(killer));
+               break;
+       case KILLED_BY:
+               Strcpy(buf, killed_by_prefix[how]);
+               Strcat(buf, killer);
+               break;
+       case NO_KILLER_PREFIX:
+               Strcpy(buf, killer);
+               break;
+       }
+       /* Put death type on stone */
+       for (line=DEATH_LINE, dpx = buf; line<YEAR_LINE; line++) {
+               register int i,i0;
+               char tmpchar;
+               if ( (i0=strlen(dpx)) > STONE_LINE_LEN) {
+                       for(i = STONE_LINE_LEN;
+                               ((i0 > STONE_LINE_LEN) && i); i--)
+                       if(dpx[i] == ' ') i0 = i;
+               if(!i) i0 = STONE_LINE_LEN;
+               }
+               tmpchar = dpx[i0];
+               dpx[i0] = 0;
+               strcpy(rip_line[line], dpx);
+               if (tmpchar != ' ') {
+                       dpx[i0] = tmpchar;
+                       dpx= &dpx[i0];
+               } else  dpx= &dpx[i0+1];
+       }
+       /* Put year on stone */
+       Sprintf(rip_line[YEAR_LINE], "%4d", getyear());
+       mar_set_text_to_rip(w);
+       for(line=0;line<13;line++)
+               putstr(w, 0, "");
+}
+void
+mar_get_font(type,p_fname,psize)
+int type;
+char **p_fname;
+int *psize;
+{
+       switch(type){
+       case NHW_MESSAGE:
+               *p_fname=iflags.wc_font_message;
+               *psize=iflags.wc_fontsiz_message;
+               break;
+       case NHW_MAP:
+               *p_fname=iflags.wc_font_map;
+               *psize=iflags.wc_fontsiz_map;
+               break;
+       case NHW_STATUS:
+               *p_fname=iflags.wc_font_status;
+               *psize=iflags.wc_fontsiz_status;
+               break;
+       case NHW_MENU:
+               *p_fname=iflags.wc_font_menu;
+               *psize=iflags.wc_fontsiz_menu;
+               break;
+       case NHW_TEXT:
+               *p_fname=iflags.wc_font_text;
+               *psize=iflags.wc_fontsiz_text;
+               break;
+       default:
+               break;
+       }
+}
+void
+Gem_preference_update(pref)
+const char *pref;
+{
+       if( stricmp( pref, "font_message")==0 ||
+               stricmp( pref, "font_size_message")==0 ) {
+               if( iflags.wc_fontsiz_message<NHFONT_SIZE_MIN ||
+                       iflags.wc_fontsiz_message>NHFONT_SIZE_MAX )
+                       iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
+               mar_set_font(NHW_MESSAGE,iflags.wc_font_message,iflags.wc_fontsiz_message);
+               return;
+       }
+       if( stricmp( pref, "font_map")==0 ||
+               stricmp( pref, "font_size_map")==0 ) {
+               if( iflags.wc_fontsiz_map<NHFONT_SIZE_MIN ||
+                       iflags.wc_fontsiz_map>NHFONT_SIZE_MAX )
+                       iflags.wc_fontsiz_map = NHFONT_DEFAULT_SIZE;
+               mar_set_font(NHW_MAP,iflags.wc_font_map,iflags.wc_fontsiz_map);
+               return;
+       }
+       if( stricmp( pref, "font_status")==0 ||
+               stricmp( pref, "font_size_status")==0 ) {
+               if( iflags.wc_fontsiz_status<NHFONT_SIZE_MIN ||
+                       iflags.wc_fontsiz_status>NHFONT_SIZE_MAX )
+                       iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
+               mar_set_font(NHW_STATUS,iflags.wc_font_status,iflags.wc_fontsiz_status);
+               return;
+       }
+       if( stricmp( pref, "font_menu")==0 ||
+               stricmp( pref, "font_size_menu")==0 ) {
+               if( iflags.wc_fontsiz_menu<NHFONT_SIZE_MIN ||
+                       iflags.wc_fontsiz_menu>NHFONT_SIZE_MAX )
+                       iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
+               mar_set_font(NHW_MENU,iflags.wc_font_menu,iflags.wc_fontsiz_menu);
+               return;
+       }
+       if( stricmp( pref, "font_text")==0 ||
+               stricmp( pref, "font_size_text")==0 ) {
+               if( iflags.wc_fontsiz_text<NHFONT_SIZE_MIN ||
+                       iflags.wc_fontsiz_text>NHFONT_SIZE_MAX )
+                       iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
+               mar_set_font(NHW_TEXT,iflags.wc_font_text,iflags.wc_fontsiz_text);
+               return;
+       }
+       if( stricmp( pref, "scroll_margin")==0 ) {
+               mar_set_margin(iflags.wc_scroll_margin);
+               Gem_cliparound(u.ux, u.uy);
+               return;
+       }
+       if( stricmp( pref, "ascii_map")==0 ) {
+               mar_set_tile_mode(!iflags.wc_ascii_map);
+               doredraw();
+               return;
+       }
+       if( stricmp( pref, "hilite_pet")==0 ){
+               /* MAR -- works without doing something here. */
+               return;
+       }
+       if( stricmp( pref, "align_message")==0){
+               mar_set_msg_align(iflags.wc_align_message-ALIGN_BOTTOM);
+               return;
+       }
+       if(stricmp( pref, "align_status")==0 ){
+               mar_set_status_align(iflags.wc_align_status-ALIGN_BOTTOM);
+               return;
+       }
+       if( stricmp( pref, "vary_msgcount")==0 ){
+               mar_set_msg_visible(iflags.wc_vary_msgcount);
+               return;
+       }
+}
+/*
+ * Allocate a copy of the given string.  If null, return a string of
+ * zero length.
+ *
+ * This is an exact duplicate of copy_of() in X11/winmenu.c.
+ */
+static char *
+copy_of(s)
+    const char *s;
+{
+    if (!s) s = nullstr;
+    return strcpy((char *) alloc((unsigned) (strlen(s) + 1)), s);
+}
+
+#endif /* GEM_GRAPHICS
+
+/*wingem.c*/
diff --git a/win/gem/wingem1.c b/win/gem/wingem1.c
new file mode 100644 (file)
index 0000000..90be5eb
--- /dev/null
@@ -0,0 +1,2995 @@
+/*     SCCS Id: @(#)wingem1.c  3.4     1999/12/10      */
+/* Copyright (c) Christian Bressler 1999         */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#define __TCC_COMPAT__
+
+#include       <stdio.h>
+#include       <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <e_gem.h>
+#include <string.h>
+
+#include "gem_rsc.h"
+#include "load_img.h"
+#include "gr_rect.h"
+
+#define genericptr_t void *
+typedef signed char schar;
+#include "wintype.h"
+#undef genericptr_t
+
+#define NDECL(f)       f(void)
+#define FDECL(f,p)     f p
+#define CHAR_P char
+#define SCHAR_P schar
+#define UCHAR_P uchar
+#define XCHAR_P xchar
+#define SHORT_P short
+#define BOOLEAN_P boolean
+#define ALIGNTYP_P aligntyp
+typedef signed char    xchar;
+#include "wingem.h"
+#undef CHAR_P
+#undef SCHAR_P
+#undef UCHAR_P
+#undef XCHAR_P
+#undef SHORT_P
+#undef BOOLEAN_P
+#undef ALIGNTYP_P
+#undef NDECL
+#undef FDECL
+
+static char nullstr[]="",  md[]="NetHack 3.4.3", strCancel[]="Cancel", strOk[]="Ok", strText[]="Text";
+
+extern winid WIN_MESSAGE, WIN_MAP, WIN_STATUS, WIN_INVEN;
+
+#define MAXWIN 20
+#define ROWNO 21
+#define COLNO 80
+#define MSGLEN 100
+
+#define MAP_GADGETS NAME|MOVER|CLOSER|FULLER|LFARROW|RTARROW|UPARROW|DNARROW|VSLIDE|HSLIDE|SIZER|SMALLER
+#define DIALOG_MODE AUTO_DIAL|MODAL|NO_ICONIFY
+
+/*
+ *  Keyboard translation tables.
+ */
+#define C(c)   (0x1f & (c))
+#define M(c)   (0x80 | (c))
+
+#define KEYPADLO       0x61
+#define KEYPADHI       0x71
+
+#define PADKEYS        (KEYPADHI - KEYPADLO + 1)
+#define iskeypad(x)    (KEYPADLO <= (x) && (x) <= KEYPADHI)
+
+/*
+ * Keypad keys are translated to the normal values below.
+ * When iflags.BIOS is active, shifted keypad keys are translated to the
+ *    shift values below.
+ */
+static const struct pad {
+       char normal, shift, cntrl;
+} keypad[PADKEYS] = {
+                       {C('['), 'Q', C('[')},          /* UNDO */
+                       {'?', '/', '?'},                /* HELP */
+                       {'(', 'a', '('},                /* ( */
+                       {')', 'w', ')'},                /* ) */
+                       {'/', '/', '/'},                /* / */
+                       {C('p'), '$', C('p')},          /* * */
+                       {'y', 'Y', C('y')},             /* 7 */
+                       {'k', 'K', C('k')},             /* 8 */
+                       {'u', 'U', C('u')},             /* 9 */
+                       {'h', 'H', C('h')},             /* 4 */
+                       {'.', '.', '.'},
+                       {'l', 'L', C('l')},             /* 6 */
+                       {'b', 'B', C('b')},             /* 1 */
+                       {'j', 'J', C('j')},             /* 2 */
+                       {'n', 'N', C('n')},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+}, numpad[PADKEYS] = {
+                       {C('['), 'Q', C('[')}   ,       /* UNDO */
+                       {'?', '/', '?'},                /* HELP */
+                       {'(', 'a', '('},                /* ( */
+                       {')', 'w', ')'},                /* ) */
+                       {'/', '/', '/'},                /* / */
+                       {C('p'), '$', C('p')},          /* * */
+                       {'7', M('7'), '7'},             /* 7 */
+                       {'8', M('8'), '8'},             /* 8 */
+                       {'9', M('9'), '9'},             /* 9 */
+                       {'4', M('4'), '4'},             /* 4 */
+                       {'.', '.', '.'},                /* 5 */
+                       {'6', M('6'), '6'},             /* 6 */
+                       {'1', M('1'), '1'},             /* 1 */
+                       {'2', M('2'), '2'},             /* 2 */
+                       {'3', M('3'), '3'},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+};
+
+#define TBUFSZ 300
+#define BUFSZ 256
+extern int yn_number;                                                  /* from decl.c */
+extern char toplines[TBUFSZ];                                  /* from decl.c */
+extern char mapped_menu_cmds[];                                /* from options.c */
+extern int mar_iflags_numpad(void);                    /* from wingem.c */
+extern void Gem_raw_print(const char *);       /* from wingem.c */
+extern int mar_hp_query(void);                         /* from wingem.c */
+extern int mar_get_msg_history(void);          /* from wingem.c */
+extern int mar_get_msg_visible(void);          /* from wingem.c */
+extern void mar_get_font(int,char **,int *);/* from wingem.c */
+extern int vdi2dev4[];                                                 /* from load_img.c */
+
+void recalc_msg_win(GRECT*);
+void recalc_status_win(GRECT*);
+void calc_std_winplace(int, GRECT *);
+int (*v_mtext)(int,int,int,char*);
+static int no_glyph;   /* the int indicating there is no glyph */
+IMG_header tile_image, titel_image, rip_image;
+MFDB Tile_bilder, Map_bild, Titel_bild, Rip_bild, Black_bild, Pet_Mark, FontCol_Bild;
+static int Tile_width=16, Tile_heigth=16, Tiles_per_line=20;
+char *Tilefile=NULL;
+/* pet_mark Design by Warwick Allison warwick@troll.no */
+static int pet_mark_data[]={0x0000,0x3600,0x7F00,0x7F00,0x3E00,0x1C00,0x0800};
+static short   *normal_palette=NULL;
+
+static struct gw{
+       WIN *gw_window;
+       int gw_type, gw_dirty;
+       GRECT gw_place;
+} Gem_nhwindow[MAXWIN];
+
+typedef struct {
+       int id;
+       int size;
+       int cw, ch;
+       int prop;
+} NHGEM_FONT;
+
+/*struct gemmapdata {*/
+       GRECT dirty_map_area={COLNO-1,ROWNO,0,0};
+       int map_cursx=0, map_cursy=0, curs_col=WHITE;
+       int draw_cursor=TRUE, scroll_margin=-1;
+       NHGEM_FONT map_font;
+       SCROLL  scroll_map;
+       char **map_glyphs=NULL;
+       dirty_rect *dr_map;
+/*};*/
+
+/*struct gemstatusdata{*/
+       char **status_line;
+       int Anz_status_lines, status_w, status_align=FALSE;
+       NHGEM_FONT status_font;
+       dirty_rect *dr_stat;
+/*};*/
+
+/*struct gemmessagedata{*/
+       int mar_message_pause=TRUE;
+       int mar_esc_pressed=FALSE;
+       int messages_pro_zug=0;
+       char **message_line;
+       int *message_age;
+       int msg_pos=0, msg_max=0, msg_anz=0, msg_width=0, msg_vis=3, msg_align=TRUE;
+       NHGEM_FONT msg_font;
+       dirty_rect *dr_msg;
+/*};*/
+
+/*struct geminvdata {*/
+       SCROLL scroll_menu;
+       Gem_menu_item *invent_list;
+       int Anz_inv_lines=0, Inv_breite=16;
+       NHGEM_FONT menu_font;
+       int Inv_how;
+/*};*/
+
+/*struct gemtextdata{*/
+       char **text_lines;
+       int Anz_text_lines=0, text_width;
+       NHGEM_FONT text_font;
+       int use_rip=FALSE;
+       extern char** rip_line;
+/*};*/
+
+static OBJECT *zz_oblist[NHICON+1];
+
+MITEM scroll_keys[]={
+/* menu, key, state, mode, msg */
+       {FAIL,key(CTRLLEFT,0),K_CTRL,PAGE_LEFT,FAIL},
+       {FAIL,key(CTRLRIGHT,0),K_CTRL,PAGE_RIGHT,FAIL},
+       {FAIL,key(SCANUP,0),K_SHIFT,PAGE_UP,FAIL},
+       {FAIL,key(SCANDOWN,0),K_SHIFT,PAGE_DOWN,FAIL},
+       {FAIL,key(SCANLEFT,0),0,LINE_LEFT,FAIL},
+       {FAIL,key(SCANRIGHT,0),0,LINE_RIGHT,FAIL},
+       {FAIL,key(SCANUP,0),0,LINE_UP,FAIL},
+       {FAIL,key(SCANDOWN,0),0,LINE_DOWN,FAIL},
+       {FAIL,key(SCANLEFT,0),K_SHIFT,LINE_START,FAIL},
+       {FAIL,key(SCANRIGHT,0),K_SHIFT,LINE_END,FAIL},
+       {FAIL,key(SCANUP,0),K_CTRL,WIN_START,FAIL},
+       {FAIL,key(SCANDOWN,0),K_CTRL,WIN_END,FAIL},
+       {FAIL,key(SCANHOME,0),K_SHIFT,WIN_END,FAIL},
+       {FAIL,key(SCANHOME,0),0,WIN_START,FAIL}
+};
+#define SCROLL_KEYS    14
+
+static DIAINFO *Inv_dialog;
+
+#define null_free(ptr) free(ptr), (ptr)=NULL
+#define test_free(ptr) if(ptr) null_free(ptr)
+
+static char *Menu_title=NULL;
+
+void mar_display_nhwindow(winid);
+void mar_check_hilight_status(void){}  /* to be filled :-) */
+static char *mar_copy_of(const char *);
+
+extern void panic(const char *, ...);
+void *m_alloc(size_t amt){
+       void *ptr;
+
+       ptr=malloc(amt);
+       if (!ptr) panic("Memory allocation failure; cannot get %lu bytes", amt);
+       return(ptr);
+}
+
+void mar_clear_messagewin(void){
+       int i, *ptr=message_age;
+
+       if(WIN_MESSAGE==WIN_ERR) return;
+       for(i=msg_anz;--i>=0;ptr++){
+               if(*ptr)
+                       Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE;
+               *ptr=FALSE;
+       }
+       mar_message_pause=FALSE;
+
+       mar_display_nhwindow(WIN_MESSAGE);
+}
+
+void clipbrd_save(void *data,int cnt,boolean append,boolean is_inv){
+       char path[MAX_PATH],*text,*crlf="\r\n";
+       long handle;
+       int i;
+
+       if (data && cnt>0 && scrp_path(path,"scrap.txt") && (handle = append ? Fopen(path,1) : Fcreate(path,0))>0){
+               if (append)
+                       Fseek(0L,(int) handle,SEEK_END);
+               if(is_inv){
+                       Gem_menu_item *it=(Gem_menu_item *)data;
+
+                       for(;it;it=it->Gmi_next){
+                               text=it->Gmi_str;
+                               Fwrite((int) handle,strlen(text),text);
+                               Fwrite((int) handle,2L,crlf);
+                       }
+               }else{
+                       for(i=0;i<cnt;i++){
+                               text=((char **)data)[i]+1;
+                               Fwrite((int) handle,strlen(text),text);
+                               Fwrite((int) handle,2L,crlf);
+                       }
+               }
+               Fclose((int) handle);
+
+               scrp_changed(SCF_TEXT,0x2e545854l);     /* .TXT */
+       }
+}
+
+void move_win(WIN *z_win){
+       GRECT frame=desk;
+
+       v_set_mode(MD_XOR);
+       v_set_line(BLACK,1,1,0,0);
+       frame.g_w<<=1, frame.g_h<<=1;
+       if(graf_rt_dragbox(FALSE,&z_win->curr,&frame,&z_win->curr.g_x,&z_win->curr.g_y,NULL))
+               window_size(z_win,&z_win->curr);
+       else
+               window_top(z_win);
+}
+
+void message_handler(int x, int y){
+       switch(objc_find(zz_oblist[MSGWIN],ROOT,MAX_DEPTH,x,y)){
+       case UPMSG:
+               if(msg_pos>msg_vis-1){
+                       msg_pos--;
+                       Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE;
+                       mar_display_nhwindow(WIN_MESSAGE);
+               }
+               Event_Timer(50,0,TRUE);
+               break;
+       case DNMSG:
+               if(msg_pos<msg_max){
+                       msg_pos++;
+                       Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE;
+                       mar_display_nhwindow(WIN_MESSAGE);
+               }
+               Event_Timer(50,0,TRUE);
+               break;
+       case GRABMSGWIN:
+       default:
+               move_win(Gem_nhwindow[WIN_MESSAGE].gw_window);
+               break;
+       case -1:
+               break;
+       }
+}
+
+int mar_ob_mapcenter(OBJECT *p_obj){
+       WIN *p_w= WIN_MAP!=WIN_ERR ? Gem_nhwindow[WIN_MAP].gw_window : NULL;
+
+       if(p_obj && p_w){
+               p_obj->ob_x=p_w->work.g_x+p_w->work.g_w/2-p_obj->ob_width/2;
+               p_obj->ob_y=p_w->work.g_y+p_w->work.g_h/2-p_obj->ob_height/2;
+               return(DIA_LASTPOS);
+       }
+       return(DIA_CENTERED);
+}
+
+/****************************** set_no_glyph *************************************/
+
+void
+mar_set_no_glyph(ng)
+int ng;
+{
+       no_glyph=ng;
+}
+
+void
+mar_set_tilefile(name)
+char* name;
+{
+       Tilefile=name;
+}
+void
+mar_set_tilex(value)
+int value;
+{
+       Min(&value,32);
+       Max(&value,1);
+       Tile_width=value;
+}
+void
+mar_set_tiley(value)
+int value;
+{
+       Min(&value,32);
+       Max(&value,1);
+       Tile_heigth=value;
+}
+/****************************** userdef_draw *************************************/
+
+void rearrange_windows(void);
+void mar_set_status_align(int sa){
+       if(status_align!=sa){
+               status_align=sa;
+               rearrange_windows();
+       }
+}
+void mar_set_msg_align(int ma){
+       if(msg_align!=ma){
+               msg_align=ma;
+               rearrange_windows();
+       }
+}
+void mar_set_msg_visible(int mv){
+       if(mv!=msg_vis){
+               Max(&mv,1);
+               Min(&mv,min(msg_anz,20));
+               Min(&mv,desk.g_h/msg_font.ch/2);
+               msg_vis=mv;
+               rearrange_windows();
+       }
+}
+/* size<0 cellheight; size>0 points */
+void mar_set_fontbyid(int type, int id, int size){
+       int chardim[4];
+       if(id<=0)
+               id=ibm_font_id;
+       if((size>-3 && size<3) || size<-20 || size>20)
+               size=-ibm_font;
+       /* MAR -- 17.Mar 2002 For now allow FNT_PROP only with NHW_TEXT */
+       if(type!=NHW_TEXT && (FontInfo(id)->type & (FNT_PROP|FNT_ASCII)))
+               id=ibm_font_id;
+       switch(type){
+       case NHW_MESSAGE:
+               if(msg_font.size==-size && msg_font.id==id)
+                       break;
+               msg_font.size=-size;
+               msg_font.id=id;
+               msg_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII);
+               v_set_text(msg_font.id,msg_font.size,BLACK,0,0,chardim);
+               msg_font.ch=chardim[3] ? chardim[3] : 1;
+               msg_font.cw=chardim[2] ? chardim[2] : 1;
+               msg_width=min(max_w/msg_font.cw-3,MSGLEN);
+               rearrange_windows();
+               break;
+       case NHW_MAP:
+               if(map_font.size!=-size || map_font.id!=id){
+                       MFDB mtmp;
+                       map_font.size=-size;
+                       map_font.id=id;
+                       map_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII);
+                       v_set_text(map_font.id,map_font.size,BLACK,0,0,chardim);
+                       map_font.ch=chardim[3] ? chardim[3] : 1;
+                       map_font.cw=chardim[2] ? chardim[2] : 1;
+                       mfdb(&mtmp,NULL,(COLNO-1)*map_font.cw, ROWNO*map_font.ch, 0, planes);
+                       if(mfdb_size(&mtmp)>mfdb_size(&FontCol_Bild) && mfdb_size(&mtmp)>mfdb_size(&Map_bild)){
+                               FontCol_Bild.fd_addr=Map_bild.fd_addr=(int *)realloc(Map_bild.fd_addr,mfdb_size(&mtmp));
+                               if(!Map_bild.fd_addr)   /* FIXME -- Not really neccessary since the former space is still valid */
+                                       panic("Not enough Space for the map.");
+                       }
+                       mfdb(&FontCol_Bild,FontCol_Bild.fd_addr,(COLNO-1)*map_font.cw, ROWNO*map_font.ch, 0, planes);
+                       rearrange_windows();
+               }
+               break;
+       case NHW_STATUS:
+               if(status_font.size==-size && status_font.id==id)
+                       break;
+               status_font.size=-size;
+               status_font.id=id;
+               status_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII);
+               v_set_text(status_font.id,status_font.size,BLACK,0,0,chardim);
+               status_font.ch=chardim[3] ? chardim[3] : 1;
+               status_font.cw=chardim[2] ? chardim[2] : 1;
+               rearrange_windows();
+               break;
+       case NHW_MENU:
+               if(menu_font.size==-size && menu_font.id==id)
+                       break;
+               menu_font.size=-size;
+               menu_font.id=id;
+               menu_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII);
+               v_set_text(menu_font.id,menu_font.size,BLACK,0,0,chardim);
+               menu_font.ch=chardim[3] ? chardim[3] : 1;
+               menu_font.cw=chardim[2] ? chardim[2] : 1;
+               break;
+       case NHW_TEXT:
+               if(text_font.size==-size && text_font.id==id)
+                       break;
+               text_font.size=-size;
+               text_font.id=id;
+               text_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII);
+               v_set_text(text_font.id,text_font.size,BLACK,0,0,chardim);
+               text_font.ch=chardim[3] ? chardim[3] : 1;
+               text_font.cw=chardim[2] ? chardim[2] : 1;
+               break;
+       default:
+               break;
+       }
+}
+void mar_set_font(int type, const char *font_name, int size){
+       int id=0;
+       /* MAR -- 17.Mar 2002 usual Gem behavior, use the Font-ID */
+       if(font_name && *font_name){
+               id=atoi(font_name);
+               if(id<=0){
+                       int i, tid;
+                       char name[32];
+                       for(i=fonts_loaded;--i>=0;){
+                               tid=vqt_name(x_handle,i,name);
+                               if(!stricmp(name,font_name)){
+                                       id=tid;
+                                       break;
+                               }
+                       }
+               }
+       }
+       mar_set_fontbyid(type,id,size);
+}
+void rearrange_windows(void){
+       GRECT area;
+       int todo=TRUE;
+       if(WIN_MAP != WIN_ERR && Gem_nhwindow[WIN_MAP].gw_window){
+               scroll_map.px_hline=mar_set_tile_mode(FAIL)?Tile_width:map_font.cw;
+               scroll_map.px_vline=mar_set_tile_mode(FAIL)?Tile_heigth:map_font.ch;
+               if(todo){
+                       calc_std_winplace(FAIL,&area);
+                       todo=FALSE;
+               }
+               calc_std_winplace(NHW_MAP,&area);
+               Gem_nhwindow[WIN_MAP].gw_window->max.g_w=area.g_w;
+               Gem_nhwindow[WIN_MAP].gw_window->max.g_h=area.g_h;
+               Gem_nhwindow[WIN_MAP].gw_window->max.g_w=area.g_w;
+               window_reinit(Gem_nhwindow[WIN_MAP].gw_window,md,md,NULL,FALSE,FALSE);
+               {
+                       int buf[8];
+                       buf[3]=K_CTRL;
+                       buf[4]=C('L');
+                       AvSendMsg(ap_id,AV_SENDKEY,buf);
+               }
+       }
+       if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window){
+               if(todo){
+                       calc_std_winplace(FAIL,&area);
+                       todo=FALSE;
+               }
+               calc_std_winplace(NHW_MESSAGE,&area);
+               Gem_nhwindow[WIN_MESSAGE].gw_window->min_h=area.g_h;
+               window_size(Gem_nhwindow[WIN_MESSAGE].gw_window,&area);
+               redraw_window(Gem_nhwindow[WIN_MESSAGE].gw_window,NULL);
+       }
+       if(WIN_STATUS != WIN_ERR && Gem_nhwindow[WIN_STATUS].gw_window){
+               if(todo){
+                       calc_std_winplace(FAIL,&area);
+                       todo=FALSE;
+               }
+               calc_std_winplace(NHW_STATUS,&area);
+               Gem_nhwindow[WIN_STATUS].gw_window->min_h=area.g_h;
+               window_size(Gem_nhwindow[WIN_STATUS].gw_window,&area);
+               redraw_window(Gem_nhwindow[WIN_STATUS].gw_window,NULL);
+       }
+}
+void my_color_area(GRECT *area, int col){
+       int pxy[4];
+
+       v_set_fill(col,1,IP_SOLID,0);
+       rc_grect_to_array(area,pxy);
+       v_bar(x_handle,pxy);
+}
+
+void my_clear_area(GRECT *area){
+       my_color_area(area, WHITE);
+}
+
+int mar_set_tile_mode(int);
+
+static void win_draw_map(int first, WIN *win, GRECT *area){
+       int pla[8], w=area->g_w-1, h=area->g_h-1;
+       int i, x, y;
+       GRECT back=*area;
+
+       first=first;
+
+       if(!mar_set_tile_mode(FAIL)){
+               int start=(area->g_x-win->work.g_x)/map_font.cw+scroll_map.hpos;
+               int stop=(area->g_x+area->g_w+map_font.cw-1-win->work.g_x)/map_font.cw+scroll_map.hpos;
+               int starty=(area->g_y-win->work.g_y)/map_font.ch+scroll_map.vpos;
+               int stopy=min((area->g_y+area->g_h+map_font.ch-1-win->work.g_y)/map_font.ch+scroll_map.vpos,ROWNO);
+               char tmp;
+               v_set_text(map_font.id,map_font.size,WHITE,0,0,NULL);
+               v_set_mode(MD_TRANS);
+
+               x=win->work.g_x-scroll_map.px_hpos+start*map_font.cw;
+               y=win->work.g_y-scroll_map.px_vpos+starty*map_font.ch;
+               pla[2]=pla[0]=scroll_map.px_hpos+area->g_x-win->work.g_x;
+               pla[3]=pla[1]=starty*map_font.ch;
+               pla[2]+=w;
+               pla[3]+=map_font.ch-1;
+               pla[6]=pla[4]=area->g_x;        /* x_wert to */
+               pla[7]=pla[5]=y;        /* y_wert to */
+               pla[6]+=w;
+               pla[7]+=map_font.ch-1;
+               back.g_h=map_font.ch;
+               for(i=starty;i<stopy;i++,y+=map_font.ch,pla[1]+=map_font.ch,pla[3]+=map_font.ch,pla[5]+=map_font.ch,pla[7]+=map_font.ch){
+                       back.g_y=y;
+                       my_color_area(&back,BLACK);
+                       tmp=map_glyphs[i][stop];
+                       map_glyphs[i][stop]=0;
+                       (*v_mtext)(x_handle,x,y,&map_glyphs[i][start]);
+                       map_glyphs[i][stop]=tmp;
+                       vro_cpyfm(x_handle, S_OR_D, pla, &FontCol_Bild, screen);
+               }
+       }else{
+               v_set_mode(MD_REPLACE);
+               pla[2]=pla[0]=scroll_map.px_hpos+area->g_x-win->work.g_x;
+               pla[3]=pla[1]=scroll_map.px_vpos+area->g_y-win->work.g_y;
+               pla[2]+=w;
+               pla[3]+=h;
+               pla[6]=pla[4]=area->g_x;        /* x_wert to */
+               pla[7]=pla[5]=area->g_y;        /* y_wert to */
+               pla[6]+=w;
+               pla[7]+=h;
+               vro_cpyfm(x_handle, S_ONLY, pla, &Map_bild, screen);
+       }
+
+       if(draw_cursor){
+               v_set_line(curs_col,1,1,0,0);
+               pla[0]=pla[2]=win->work.g_x+scroll_map.px_hline*(map_cursx-scroll_map.hpos);
+               pla[1]=pla[3]=win->work.g_y+scroll_map.px_vline*(map_cursy-scroll_map.vpos);
+               pla[2]+=scroll_map.px_hline-1;
+               pla[3]+=scroll_map.px_vline-1;
+               v_rect(pla[0],pla[1],pla[2],pla[3]);
+       }
+}
+
+static int draw_titel(PARMBLK *pb){
+       static int pla[8];
+       GRECT work=*(GRECT *) &pb->pb_x;
+
+       if(rc_intersect((GRECT *)&pb->pb_xc,&work)){
+               pla[0]=pla[1]=0;
+               pla[2]=pb->pb_w-1;
+               pla[3]=pb->pb_h-1;
+               pla[6]=pla[4]=pb->pb_x; /* x_wert to */
+               pla[7]=pla[5]=pb->pb_y; /* y_wert to */
+               pla[6]+=pb->pb_w-1;
+               pla[7]+=pb->pb_h-1;
+
+               vro_cpyfm(x_handle, S_ONLY, pla, &Titel_bild, screen);
+       }
+
+       return(0);
+}
+
+static int draw_lines(PARMBLK *pb){
+       GRECT area=*(GRECT *) &pb->pb_x;
+
+       if(rc_intersect((GRECT *)&pb->pb_xc,&area)){
+               char **ptr;
+               int x=pb->pb_x,y=pb->pb_y,start_line=(area.g_y-y);
+
+               v_set_mode((text_font.cw&7)==0 && text_font.prop==0 ? MD_REPLACE : MD_TRANS);
+
+/* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4])     */
+               v_set_text(text_font.id,text_font.size,BLACK,0,0,NULL);
+               start_line /= text_font.ch;
+               y+=start_line*text_font.ch;
+               x-=(int)scroll_menu.px_hpos;
+               ptr=&text_lines[start_line+=scroll_menu.vpos];
+               start_line = min((area.g_y-y+area.g_h+text_font.ch-1)/text_font.ch,Anz_text_lines-start_line);
+               area.g_h=text_font.ch;
+               Vsync();
+/*             x=(x+7) & ~7;*/
+               for(;--start_line>=0;y+=text_font.ch){
+                       area.g_y=y;
+                       my_clear_area(&area);
+                       if(**ptr-1){
+                               v_set_text(FAIL,0,BLUE,0x01,0,NULL);
+                               (*v_mtext)(x_handle,x,y,(*ptr++)+1);
+                               v_set_text(FAIL,0,BLACK,0x00,0,NULL);
+                       }else
+                               (*v_mtext)(x_handle,x,y,(*ptr++)+1);
+               }
+       }
+       return(0);
+}
+
+static int draw_rip(PARMBLK *pb){
+       GRECT area=*(GRECT *) &pb->pb_x;
+       if(rc_intersect((GRECT *)&pb->pb_xc,&area)){
+               char **ptr;
+               int x=pb->pb_x,y=pb->pb_y,start_line=(area.g_y-y), chardim[4], pla[8],i;
+               v_set_mode(MD_REPLACE);
+/* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4])     */
+               v_set_text(text_font.id,text_font.size,BLACK,0,0,chardim);
+               start_line /= text_font.ch;
+               y+=start_line*text_font.ch;
+               x-=scroll_menu.px_hpos;
+               ptr=&text_lines[start_line+=scroll_menu.vpos];
+               start_line = min((area.g_y-y+area.g_h+text_font.ch-1)/text_font.ch,Anz_text_lines-start_line);
+               area.g_h=text_font.ch;
+               Vsync();
+               x=(x+7) & ~7;
+               for(;--start_line>=0;y+=text_font.ch){
+                       area.g_y=y;
+                       my_clear_area(&area);
+                       if(**ptr-1){
+                               v_set_text(FAIL,0,BLUE,0x01,0,NULL);
+                               (*v_mtext)(x_handle,x,y,(*ptr++)+1);
+                               v_set_text(FAIL,0,BLACK,0x00,0,NULL);
+                       }else
+                               (*v_mtext)(x_handle,x,y,(*ptr++)+1);
+               }
+               pla[0]=pla[1]=0;
+               pla[2]=min(pb->pb_w-1,Rip_bild.fd_w-1);
+               pla[3]=min(pb->pb_h-1,Rip_bild.fd_h-1);
+               pla[6]=pla[4]=pb->pb_x+(pb->pb_w-Rip_bild.fd_w)/2;      /* x_wert to */
+               pla[7]=pla[5]=pb->pb_y; /* y_wert to */
+               pla[6]+=pla[2];
+               pla[7]+=pla[3];
+               vro_cpyfm(x_handle, S_ONLY, pla, &Rip_bild, screen);
+               v_set_mode(MD_TRANS);
+               vst_alignment(x_handle,1,5,&i,&i);
+               pla[5]+=64;
+               for(i=0;i<7;i++,pla[5]+=chardim[3]){
+                       v_set_text(text_font.id,(i==0 || i==6) ? text_font.size : 12,WHITE,1,0,chardim);
+                       (*v_mtext)(x_handle,pla[4]+157,pla[5],rip_line[i]);
+                       v_set_text(text_font.id,(i==0 || i==6) ? text_font.size : 12,BLACK,0,0,chardim);
+                       (*v_mtext)(x_handle,pla[4]+157,pla[5],rip_line[i]);
+               }
+               vst_alignment(x_handle,0,5,&i,&i);
+       }
+       return(0);
+}
+
+static int draw_msgline(PARMBLK *pb){
+       GRECT area=*(GRECT *) &pb->pb_x;
+
+       if(rc_intersect((GRECT *)&pb->pb_xc,&area)){
+               int x=pb->pb_x, y=pb->pb_y+(msg_vis-1)*msg_font.ch, foo, i;
+               char **ptr=&message_line[msg_pos], tmp;
+               int startx, stopx, starty, stopy;
+
+               x=(x+7) & ~7;   /* Byte alignment speeds output up */
+
+               v_set_mode(MD_REPLACE);
+
+/* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4])     */
+               v_set_text(msg_font.id,msg_font.size,FAIL, FAIL,0,NULL);
+               vst_alignment(x_handle,0,5,&foo,&foo);
+               stopy=min(msg_pos,msg_vis);
+/*             Vsync();*/
+               startx=(area.g_x-x)/msg_font.cw-1;      /* MAR 06.02.2001 -- because italic covers the next char */
+               Max(&startx,0);
+               stopx=(area.g_x+area.g_w+msg_font.cw-x-1)/msg_font.cw;
+               x+=startx*msg_font.cw;
+               for(i=0;i<stopy;i++,y-=msg_font.ch,ptr--){
+                       if(message_age[msg_pos-i])
+                               v_set_text(FAIL,0,BLACK,0,0,NULL);
+                       else
+                               v_set_text(FAIL,0,LBLACK,4,0,NULL);
+                       tmp=(*ptr)[stopx];
+                       (*ptr)[stopx]=0;
+                       (*v_mtext)(x_handle,x,y,&(*ptr)[startx]);
+                       (*ptr)[stopx]=tmp;
+               }
+       }
+       return(0);
+}
+
+static int draw_status(PARMBLK *pb){
+       GRECT area=*(GRECT *) &pb->pb_x;
+
+       area.g_x+=2*status_font.cw-2;
+       area.g_w-=2*status_font.cw-2;
+       if(rc_intersect((GRECT *)&pb->pb_xc,&area)){
+               int x=pb->pb_x, y=pb->pb_y, startx, stopx, starty, stopy, i;
+               char tmp;
+
+/* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4])     */
+               v_set_mode(MD_REPLACE);
+               v_set_text(status_font.id,status_font.size,BLACK,0,0,NULL);
+               x = (x+2*status_font.cw+6) & ~7;
+
+               startx=(area.g_x-x)/status_font.cw;
+               starty=(area.g_y-y)/status_font.ch;
+               stopx=(area.g_x+area.g_w+status_font.ch-1-x)/status_font.cw;
+               stopy=(area.g_y+area.g_h+status_font.ch-1-y)/status_font.ch;
+               Max(&startx,0); /* MAR -- Hmm, area.g_x could end up 1 below x */
+               Max(&stopx,0);
+               x+=startx*status_font.cw;
+               y+=starty*status_font.ch;
+/*             Vsync();*/
+               area.g_h=status_font.ch;
+               for(i=starty;i<min(2,stopy);i++,area.g_y+=status_font.ch,y+=status_font.ch){
+               my_clear_area(&area);
+                       tmp=status_line[i][stopx];
+                       status_line[i][stopx]=0;
+                       (*v_mtext)(x_handle,x,y,&status_line[i][startx]);
+                       status_line[i][stopx]=tmp;
+               }
+       }
+       return(0);
+}
+
+static int draw_inventory(PARMBLK *pb){
+       GRECT area=*(GRECT *) &pb->pb_x;
+
+       if(rc_intersect((GRECT *)&pb->pb_xc,&area)){
+               int gl, i, x=pb->pb_x, y=pb->pb_y,start_line=area.g_y-y;
+               Gem_menu_item *it;
+
+               v_set_mode(MD_REPLACE);
+               v_set_text(menu_font.id,menu_font.size,BLACK,0,0,NULL);
+
+               start_line /= menu_font.ch;
+               y+=start_line*menu_font.ch;
+               x-=scroll_menu.px_hpos;
+               start_line+=scroll_menu.vpos;
+
+               for(it=invent_list,i=start_line; --i>=0 && it; it=it->Gmi_next);
+
+               i = min((area.g_y-y+area.g_h+menu_font.ch-1)/menu_font.ch,Anz_inv_lines-start_line);
+
+               Vsync();
+               area.g_h=menu_font.ch;
+
+               for(;(--i>=0) && it;it=it->Gmi_next,y+=menu_font.ch){
+                       if(it->Gmi_attr)
+                               v_set_text(FAIL,FALSE,BLUE,1,FAIL,NULL);        /* Bold */
+                       else
+                               v_set_text(FAIL,FALSE,BLACK,0,FAIL,NULL);
+
+                       area.g_y=y;
+                       my_clear_area(&area);
+                       if((gl=it->Gmi_glyph) != no_glyph){
+                               int pla[8], h=min(menu_font.ch,Tile_heigth)-1;
+
+                               pla[0]=pla[2]=(gl%Tiles_per_line)*Tile_width;   /* x_wert from */
+                               pla[1]=pla[3]=(gl/Tiles_per_line)*Tile_heigth;  /* y_wert from */
+                               pla[4]=pla[6]=x;                                /* x_wert to */
+                               pla[5]=pla[7]=y;                                /* y_wert to */
+                               pla[2]+=Tile_width-1;
+                               pla[3]+=h;
+                               pla[6]+=Tile_heigth-1;
+                               pla[7]+=h;
+
+                               vro_cpyfm(x_handle,S_ONLY,pla,&Tile_bilder,screen);
+                       }
+                       if(it->Gmi_identifier)
+                               it->Gmi_str[2]=it->Gmi_selected ? (it->Gmi_count == -1L ? '+' : '#') : '-';
+                       (*v_mtext)(x_handle,(x+23) & ~7,y,it->Gmi_str);
+               }
+       }
+       return(0);
+}
+
+static int draw_prompt(PARMBLK *pb){
+       GRECT area=*(GRECT *) &pb->pb_x;
+
+       if(rc_intersect((GRECT *)&pb->pb_xc,&area)){
+               char **ptr=(char **)pb->pb_parm;
+               int x=pb->pb_x, y=pb->pb_y, chardim[4];
+
+/* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4])     */
+               v_set_mode(MD_TRANS);
+               v_set_text(ibm_font_id,ibm_font,WHITE,0,0,chardim);
+               Vsync();
+               if(planes<4){
+                       int pxy[4];
+                       v_set_fill(BLACK,2,4,0);
+                       rc_grect_to_array(&area,pxy);
+                       v_bar(x_handle,pxy);
+               }else
+                       my_color_area(&area,LWHITE);
+               (*v_mtext)(x_handle,x,y,*(ptr++));
+               if(*ptr)
+                       (*v_mtext)(x_handle,x,y+chardim[3],*ptr);
+       }
+       return(0);
+}
+
+static USERBLK ub_lines={draw_lines, 0L}, ub_msg={draw_msgline, 0L},
+                                       ub_inventory={draw_inventory, 0L}, ub_titel={draw_titel, 0L},
+                                       ub_status={draw_status, 0L}, ub_prompt={draw_prompt, 0L};
+
+/**************************** rsc_funktionen *****************************/
+
+void my_close_dialog(DIAINFO *dialog,boolean shrink_box){
+       close_dialog(dialog,shrink_box);
+       Event_Timer(0,0,TRUE);
+}
+
+void
+mar_get_rsc_tree(obj_number, z_ob_obj)
+int obj_number;
+OBJECT **z_ob_obj;
+{
+   rsrc_gaddr( R_TREE, obj_number, z_ob_obj );
+       fix_objects(*z_ob_obj,SCALING,0,0);
+}
+
+void mar_clear_map(void);
+
+void
+img_error(errnumber)
+int errnumber;
+{
+       char buf[BUFSZ];
+
+       switch(errnumber){
+       case ERR_HEADER :
+               sprintf(buf,"%s","[1][ Image Header | corrupt. ][ Oops ]");
+               break;
+       case ERR_ALLOC :
+               sprintf(buf,"%s","[1][ Not enough | memory for | an image. ][ Oops ]");
+               break;
+       case ERR_FILE :
+               sprintf(buf,"%s","[1][ The Image-file | is not available ][ Oops ]");
+               break;
+       case ERR_DEPACK :
+               sprintf(buf,"%s","[1][ The Image-file | is corrupt ][ Oops ]");
+               break;
+       case ERR_COLOR :
+               sprintf(buf,"%s","[1][ Number of colors | not supported ][ Oops ]");
+               break;
+       default:
+               sprintf(buf,"[1][ img_error | strange error | number: %i ][ Hmm ]",errnumber);
+               break;
+       }
+       form_alert(1,buf);
+}
+
+void mar_change_button_char(OBJECT *z_ob, int nr, char ch){
+       *ob_get_text(z_ob,nr,0)=ch;
+       ob_set_hotkey(z_ob,nr,ch);
+}
+
+void
+mar_set_dir_keys()
+{
+       static int mi_numpad=FAIL;
+       char mcmd[]="bjnh.lyku", npcmd[]="123456789", *p_cmd;
+
+       if(mi_numpad!=mar_iflags_numpad()){
+               OBJECT *z_ob=zz_oblist[DIRECTION];
+               int i;
+               mi_numpad=mar_iflags_numpad();
+               ob_set_hotkey(z_ob,DIRDOWN,'>');
+               ob_set_hotkey(z_ob,DIRUP,'<');
+               p_cmd= mi_numpad ? npcmd : mcmd;
+               for(i=0;i<9;i++)
+                       mar_change_button_char(z_ob,DIR1+2*i,p_cmd[i]);
+       }
+}
+
+extern int total_tiles_used;   /* tile.c */
+
+int
+mar_gem_init()
+{
+       int i, bild_fehler=FALSE, fsize;
+       char *fname;
+       static MITEM wish_workaround= {FAIL,key(0,'J'),K_CTRL,W_CYCLE,FAIL};
+       OBJECT *z_ob;
+
+       if((i=open_rsc("gem_rsc.rsc",NULL,md,md,md,0,0,0))<=0){
+               graf_mouse(M_OFF,NULL);
+               if(i<0)
+                       form_alert(1,"[3][| Fatal Error | File: GEM_RSC.RSC | not found. ][ grumble ]");
+               else
+                       form_alert(1,"[3][| Fatal Error | GEM initialisation | failed. ][ a pity ]");
+               return(0);
+       }
+       if(planes<1 || planes>8){
+               form_alert(1,"[3][ Color-depth | not supported, | try 2-256 colors. ][ Ok ]");
+               return(0);
+       }
+       MouseBee();
+
+       /* MAR -- 17.Mar 2002 NVDI 3.0 or better uses v_ftext */
+       v_mtext= speedo==3 ? &v_ftext : &v_gtext;
+       for(i=0;i<NHICON;i++)
+               mar_get_rsc_tree(i, &zz_oblist[i]);
+
+       z_ob=zz_oblist[ABOUT];
+       ob_hide(z_ob,OKABOUT,TRUE);
+       ob_draw_dialog(z_ob,0,0,0,0);
+
+       mar_get_font(NHW_MESSAGE,&fname,&fsize);
+       mar_set_font(NHW_MESSAGE,fname,fsize);
+       mar_get_font(NHW_MAP,&fname,&fsize);
+       mar_set_font(NHW_MAP,fname,fsize);
+       mar_get_font(NHW_STATUS,&fname,&fsize);
+       mar_set_font(NHW_STATUS,fname,fsize);
+       mar_get_font(NHW_MENU,&fname,&fsize);
+       mar_set_font(NHW_MENU,fname,fsize);
+       mar_get_font(NHW_TEXT,&fname,&fsize);
+       mar_set_font(NHW_TEXT,fname,fsize);
+       msg_anz=mar_get_msg_history();
+       mar_set_msg_visible(mar_get_msg_visible());
+       msg_width=min(max_w/msg_font.cw-3,MSGLEN);
+
+       if(max_w/status_font.cw<COLNO-1)
+               mar_set_fontbyid(NHW_STATUS,small_font_id,-small_font);
+       status_w=min(max_w/status_font.cw-3,MSGLEN);
+
+       if(planes>0 && planes<9){
+               normal_palette=(short *)m_alloc(3*colors*sizeof(short));
+               get_colors(x_handle,normal_palette, colors);
+       }
+
+loadimg:
+       bild_fehler=depack_img(Tilefile?Tilefile:(planes>=4)?"NH16.IMG":"NH2.IMG",&tile_image);
+       if(bild_fehler){
+               z_ob=zz_oblist[ABOUT];
+               ob_undraw_dialog(z_ob,0,0,0,0);
+               ob_hide(z_ob,OKABOUT,FALSE);
+               img_error(bild_fehler);
+               return(0);
+       }
+       if(tile_image.img_w%Tile_width || tile_image.img_h%Tile_heigth){
+               Tilefile=NULL;
+               Tile_width=Tile_heigth=16;
+               printf("size didn't match.\n");
+               goto loadimg;
+       }
+       if((tile_image.img_w/Tile_width)*(tile_image.img_h/Tile_heigth)<total_tiles_used){
+               Tilefile=NULL;
+               Tile_width=Tile_heigth=16;
+               printf("Too few Tiles in Image.\n");
+               goto loadimg;
+       }
+       Tiles_per_line=tile_image.img_w/Tile_width;
+
+       if(planes>=4){
+               if(tile_image.planes>1)
+                       img_set_colors(x_handle, tile_image.palette, tile_image.planes);
+#if 0
+               else{
+                       int mypalette[]={};
+                       img_set_colors(x_handle, mypalette, 4);
+               }
+#endif
+       }
+
+       mfdb(&Tile_bilder, (int *)tile_image.addr, tile_image.img_w, tile_image.img_h, 1, tile_image.planes);
+       transform_img(&Tile_bilder);
+
+       mfdb(&Map_bild,NULL,(COLNO-1)*Tile_width, ROWNO*Tile_heigth, 0, planes);
+       mfdb(&FontCol_Bild,NULL,(COLNO-1)*map_font.cw, ROWNO*map_font.ch, 0, planes);
+       Map_bild.fd_addr=(int *)m_alloc(mfdb_size(&Map_bild)>mfdb_size(&FontCol_Bild)?mfdb_size(&Map_bild):mfdb_size(&FontCol_Bild));
+       FontCol_Bild.fd_addr=Map_bild.fd_addr;
+
+       mfdb(&Pet_Mark,pet_mark_data,8, 7, 1, 1);
+       vr_trnfm(x_handle,&Pet_Mark,&Pet_Mark);
+
+       mfdb(&Black_bild,NULL,16, 32, 1, 1);    /* MAR -- 17.Mar 2002 that should cover the biggest map-font */
+       Black_bild.fd_addr=(int *)m_alloc(mfdb_size(&Black_bild));
+       memset(Black_bild.fd_addr,255,mfdb_size(&Black_bild));
+       vr_trnfm(x_handle,&Black_bild,&Black_bild);
+
+       for(i=0;i<MAXWIN;i++){
+               Gem_nhwindow[i].gw_window=NULL;
+               Gem_nhwindow[i].gw_type=0;
+               Gem_nhwindow[i].gw_dirty=TRUE;
+       }
+
+       memset(&scroll_menu,0,sizeof(scroll_menu));
+       scroll_menu.scroll=AUTO_SCROLL;
+       scroll_menu.obj=LINESLIST;
+       scroll_menu.px_hline=menu_font.cw;
+       scroll_menu.px_vline=menu_font.ch;
+       scroll_menu.hscroll=
+       scroll_menu.vscroll=1;
+       scroll_menu.tbar_d=2*gr_ch-2;
+
+       mar_set_dir_keys();
+
+       memset(&scroll_map,0,sizeof(scroll_map));
+       scroll_map.scroll=AUTO_SCROLL;
+       scroll_map.obj=ROOT;
+       scroll_map.px_hline=mar_set_tile_mode(FAIL)?Tile_width:map_font.cw;
+       scroll_map.px_vline=mar_set_tile_mode(FAIL)?Tile_heigth:map_font.ch;
+       scroll_map.hsize=COLNO-1;
+       scroll_map.vsize=ROWNO;
+       scroll_map.hpage=8;
+       scroll_map.vpage=8;
+       scroll_map.hscroll=1;
+       scroll_map.vscroll=1;
+
+       /* dial_options( round, niceline, standard, return_default, background, nonselectable,
+               always_keys, toMouse, clipboard, hz);   */
+       dial_options(TRUE,TRUE,FALSE,RETURN_DEFAULT,AES_BACK,TRUE,KEY_ALWAYS,FALSE,TRUE,3);
+       /*      dial_colors( dial_pattern, dial_color, dial_frame, hotkey, alert, cycle_button,
+               check_box, radio_button, arrow, cycle_backgrnd, check_backgrnd, radio_backgrnd,
+               arrow_backgrnd, edit_3d, draw_3d)       */
+       if(planes<4)
+               dial_colors(4,BLACK,WHITE,RED,RED,WHITE,BLACK,BLACK,BLACK,FAIL,FAIL,FAIL,FAIL,TRUE,TRUE);
+       else
+               dial_colors(7,LWHITE,BLACK,RED,RED,BLACK,BLACK,BLACK,BLACK,WHITE,WHITE,WHITE,WHITE,TRUE,TRUE);
+
+       /* void MenuItems(MITEM *close,MITEM *closeall,MITEM *cycle,MITEM *invcycle,
+               MITEM *globcycle,MITEM *full,MITEM *bottom,MITEM *iconify,MITEM *iconify_all,
+               MITEM *menu,int menu_cnt) */
+       /* Ctrl-W ist normaly bound to cycle */
+       MenuItems(NULL,NULL,&wish_workaround,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
+
+       menu_install(zz_oblist[MENU],TRUE);
+
+       z_ob=zz_oblist[ABOUT];
+       ob_undraw_dialog(z_ob,0,0,0,0);
+       ob_hide(z_ob,OKABOUT,FALSE);
+
+       return(1);
+}
+
+/************************* mar_exit_nhwindows *******************************/
+
+void
+mar_exit_nhwindows()
+{
+       int i;
+
+       for(i=MAXWIN;--i>=0;)
+               if(Gem_nhwindow[i].gw_type)
+                       mar_destroy_nhwindow(i);
+
+       if(normal_palette){
+               img_set_colors(x_handle,normal_palette,tile_image.planes);
+               null_free(normal_palette);
+       }
+       test_free(tile_image.palette);
+       test_free(tile_image.addr);
+       test_free(titel_image.palette);
+       test_free(titel_image.addr);
+}
+
+/************************* mar_curs *******************************/
+
+void
+mar_curs(x,y)
+int x, y;
+{
+       Min(&dirty_map_area.g_x,x);
+       Min(&dirty_map_area.g_y,y);
+       Max(&dirty_map_area.g_w,x);
+       Max(&dirty_map_area.g_h,y);
+       Min(&dirty_map_area.g_x,map_cursx);
+       Min(&dirty_map_area.g_y,map_cursy);
+       Max(&dirty_map_area.g_w,map_cursx);
+       Max(&dirty_map_area.g_h,map_cursy);
+
+       map_cursx=x;
+       map_cursy=y;
+
+       if(WIN_MAP!=WIN_ERR)
+               Gem_nhwindow[WIN_MAP].gw_dirty=TRUE;
+}
+
+void mar_cliparound(void);
+void mar_map_curs_weiter(void)
+{
+       static int once=TRUE;
+
+       if(once){
+               redraw_window(Gem_nhwindow[WIN_STATUS].gw_window,NULL);
+               redraw_window(Gem_nhwindow[WIN_MESSAGE].gw_window,NULL);
+               once=FALSE;
+       }
+       mar_curs(map_cursx+1,map_cursy);
+       mar_cliparound();
+}
+
+/************************* about *******************************/
+
+void
+mar_about()
+{
+       xdialog(zz_oblist[ABOUT], md, NULL, NULL, DIA_CENTERED, FALSE, DIALOG_MODE);
+       Event_Timer(0,0,TRUE);
+}
+
+/************************* ask_name *******************************/
+
+char *
+mar_ask_name()
+{
+       OBJECT *z_ob=zz_oblist[NAMEGET];
+       int bild_fehler;
+       char who_are_you[] = "Who are you? ";
+
+       bild_fehler=depack_img(planes<4 ? "TITLE2.IMG" : "TITLE.IMG", &titel_image);
+       if(bild_fehler ){       /* MAR -- this isn't lethal */
+               ob_set_text(z_ob,NETHACKPICTURE,"missing title.img.");
+       }else{
+               mfdb(&Titel_bild, (int *)titel_image.addr, titel_image.img_w, titel_image.img_h, 1, titel_image.planes);
+               transform_img(&Titel_bild);
+               z_ob[NETHACKPICTURE].ob_type=G_USERDEF;
+               z_ob[NETHACKPICTURE].ob_spec.userblk=&ub_titel;
+       }
+
+       ob_clear_edit(z_ob);
+       xdialog(z_ob,who_are_you, NULL, NULL, DIA_CENTERED, FALSE, DIALOG_MODE);
+       Event_Timer(0,0,TRUE);
+
+       test_free(titel_image.palette);
+       test_free(titel_image.addr);
+       test_free(Titel_bild.fd_addr);
+       return(ob_get_text(z_ob,PLNAME,0));
+}
+
+/************************* more *******************************/
+
+void
+send_key(int key)
+{
+       int buf[8];
+
+       buf[3]=0;       /* No Shift/Ctrl/Alt */
+       buf[4]=key;
+       AvSendMsg(ap_id,AV_SENDKEY,buf);
+}
+
+void
+send_return()
+{
+       send_key(key(SCANRET,0));
+}
+
+int
+K_Init(xev,availiable)
+XEVENT *xev;
+int availiable;
+{
+       xev=xev;
+       return(MU_KEYBD&availiable);
+}
+
+int
+KM_Init(xev,availiable)
+XEVENT *xev;
+int availiable;
+{
+       xev=xev;
+       return((MU_KEYBD|MU_MESAG)&availiable);
+}
+
+int
+M_Init(xev,availiable)
+XEVENT *xev;
+int availiable;
+{
+       xev=xev;
+       return(MU_MESAG&availiable);
+}
+
+#define More_Init K_Init
+
+int
+More_Handler(xev)
+XEVENT *xev;
+{
+       int ev=xev->ev_mwich;
+
+       if(ev&MU_KEYBD){
+               char ch=(char)(xev->ev_mkreturn&0x00FF);
+               DIAINFO *dinf;
+               WIN *w;
+
+               switch(ch){
+               case '\033':    /* no more more more */
+               case ' ':
+                       if((w=get_top_window()) && (dinf=(DIAINFO *)w->dialog) && dinf->di_tree==zz_oblist[PAGER]){
+                               if(ch=='\033')
+                                       mar_esc_pressed=TRUE;
+                               send_return();
+                       break;
+                       }
+                       /* Fall thru */
+               default:
+                       ev &= ~MU_KEYBD;        /* unknown key */
+                       break;
+               }
+       }
+       return(ev);
+}
+
+void
+mar_more()
+{
+       if(!mar_esc_pressed){
+               OBJECT *z_ob=zz_oblist[PAGER];
+               WIN *p_w;
+
+               Event_Handler(More_Init,More_Handler);
+               dial_colors(7,RED,BLACK,RED,RED,BLACK,BLACK,BLACK,BLACK,WHITE,WHITE,WHITE,WHITE,TRUE,TRUE);
+               if(WIN_MESSAGE!=WIN_ERR && (p_w=Gem_nhwindow[WIN_MESSAGE].gw_window)){
+                       z_ob->ob_x=p_w->work.g_x;
+                       z_ob->ob_y=p_w->curr.g_y+p_w->curr.g_h+gr_ch;
+               }
+               xdialog(z_ob,NULL, NULL, NULL, DIA_LASTPOS, FALSE, DIALOG_MODE);
+               Event_Timer(0,0,TRUE);
+               Event_Handler(NULL,NULL);
+
+               if(planes<4)
+                       dial_colors(4,BLACK,WHITE,RED,RED,WHITE,BLACK,BLACK,BLACK,FAIL,FAIL,FAIL,FAIL,TRUE,TRUE);
+               else
+                       dial_colors(7,LWHITE,BLACK,RED,RED,BLACK,BLACK,BLACK,BLACK,WHITE,WHITE,WHITE,WHITE,TRUE,TRUE);
+       }
+}
+
+/************************* Gem_start_menu *******************************/
+void
+Gem_start_menu(win)
+winid win;
+{
+       win=win;
+       if(invent_list){
+               Gem_menu_item *curr, *next;
+
+               for(curr=invent_list;curr;curr=next){
+                       next=curr->Gmi_next;
+                       free(curr->Gmi_str);
+                       free(curr);
+               }
+       }
+       invent_list=NULL;
+       Anz_inv_lines=0;
+       Inv_breite=16;
+}
+
+/************************* mar_add_menu *******************************/
+
+void
+mar_add_menu(win, item)
+winid win;
+Gem_menu_item *item;
+{
+       win=win;
+       item->Gmi_next = invent_list;
+       invent_list = item;
+       Anz_inv_lines++;
+}
+
+void
+mar_reverse_menu()
+{
+       Gem_menu_item *next, *head = 0, *curr=invent_list;
+
+       while (curr) {
+               next = curr->Gmi_next;
+               curr->Gmi_next = head;
+               head = curr;
+               curr = next;
+       }
+       invent_list=head;
+}
+
+void
+mar_set_accelerators()
+{
+       char ch='a';
+       Gem_menu_item *curr;
+
+       for(curr=invent_list;curr;curr=curr->Gmi_next){
+               int extent[8];
+               v_set_text(menu_font.id,menu_font.size,BLACK,0,0,NULL);
+               vqt_extent(x_handle,curr->Gmi_str,extent);
+               Max(&Inv_breite,extent[4]+Tile_width+menu_font.cw);
+               if(ch && curr->Gmi_accelerator==0 && curr->Gmi_identifier){
+                       curr->Gmi_accelerator=ch;
+                       curr->Gmi_str[0]=ch;
+                       if(ch=='z') ch='A';
+                       else if(ch=='Z') ch=0;
+                       else ch++;
+               }
+       }
+}
+
+Gem_menu_item *
+mar_hol_inv()
+{
+       return(invent_list);
+}
+
+/************************* mar_putstr_text *********************/
+
+void mar_raw_print(const char *);
+
+void mar_set_text_to_rip(winid w){
+       use_rip=TRUE;
+}
+void
+mar_putstr_text(winid window, int attr, const char *str)
+{
+       static int zeilen_frei=0;
+       int breite;
+       char *ptr;
+
+       window=window;
+       if(!text_lines){
+               text_lines=(char **)m_alloc(12*sizeof(char *));
+               zeilen_frei=12;
+       }
+       if(!zeilen_frei){
+               text_lines=(char **)realloc(text_lines,(Anz_text_lines+12)*sizeof(char *));
+               zeilen_frei=12;
+       }
+       if(!text_lines){
+               mar_raw_print("No room for Text");
+               return;
+       }
+
+       if(str)
+               breite=strlen(str);
+       Min(&breite,80);
+       ptr=text_lines[Anz_text_lines]=(char *)m_alloc(breite*sizeof(char)+2);
+       *ptr=(char)(attr+1);    /* avoid 0 */
+       strncpy(ptr+1,str,breite);
+       ptr[breite+1]=0;
+       Anz_text_lines++;
+       zeilen_frei--;
+}
+
+int
+mar_set_inv_win(Anzahl, Breite)
+int Anzahl, Breite;
+{
+       OBJECT *z_ob=zz_oblist[LINES];
+       int retval=WIN_DIAL|MODAL|NO_ICONIFY;
+
+       scroll_menu.hsize=0;
+       scroll_menu.vpage= (desk.g_h-3*gr_ch)/scroll_menu.px_vline;
+       if(Anzahl>scroll_menu.vpage){
+               retval |= WD_VSLIDER;
+               if(Breite>max_w-3*scroll_menu.px_hline){
+                       retval|=WD_HSLIDER;
+                       scroll_menu.hpage=(max_w-3*scroll_menu.px_hline)/scroll_menu.px_hline;
+                       scroll_menu.hpos=0;
+                       scroll_menu.hsize=Breite/scroll_menu.px_hline;
+                       scroll_menu.vpage=(desk.g_h-4*gr_ch-1)/scroll_menu.px_vline;
+               }
+               Anzahl=scroll_menu.vpage;
+       }else{
+               if(Breite>max_w-scroll_menu.px_hline){
+                       retval|=WD_HSLIDER;
+                       scroll_menu.hpage=(max_w-scroll_menu.px_hline)/scroll_menu.px_hline;
+                       scroll_menu.hpos=0;
+                       scroll_menu.hsize=Breite/scroll_menu.px_hline;
+                       scroll_menu.vpage= (desk.g_h-4*gr_ch-1)/scroll_menu.px_vline;
+                       if(Anzahl>scroll_menu.vpage){
+                               retval |= WD_VSLIDER;
+                               Anzahl=scroll_menu.vpage;
+                       }
+               }
+               scroll_menu.vpage=Anzahl;
+       }
+       if((scroll_menu.hmax=scroll_menu.hsize-scroll_menu.hpage)<0)
+               scroll_menu.hmax=0;
+       if((scroll_menu.vmax=scroll_menu.vsize-scroll_menu.vpage)<0)
+               scroll_menu.vmax=0;
+
+       /* left/right/up 2 pixel border down 2gr_ch toolbar */
+       z_ob[ROOT].ob_width=z_ob[LINESLIST].ob_width=Breite;
+       z_ob[ROOT].ob_height=
+       z_ob[QLINE].ob_y=
+       z_ob[LINESLIST].ob_height=scroll_menu.px_vline*Anzahl;
+       z_ob[QLINE].ob_y+=gr_ch/2;
+       z_ob[ROOT].ob_width+=4;
+       z_ob[ROOT].ob_height+=2*gr_ch+2;
+
+       return(retval);
+}
+
+/************************* mar_status_dirty *******************************/
+
+void
+mar_status_dirty()
+{
+       int ccol;
+
+       ccol=mar_hp_query();
+
+       if(ccol<2)      curs_col=WHITE;         /* 50-100% : 0 */
+       else if(ccol<3) curs_col=YELLOW;                /* 33-50% : 6 */
+       else if(ccol<5) curs_col=LYELLOW;               /* 20-33% : 14*/
+       else if(ccol<10)        curs_col=RED;           /* 10-20% : 2 */
+       else    curs_col=MAGENTA;               /* <10% : 7*/
+}
+
+/************************* mar_add_message *******************************/
+
+void
+mar_add_message(str)
+const char *str;
+{
+       int i, mesg_hist=mar_get_msg_history();
+       char *tmp, *rest, buf[TBUFSZ];
+
+       if(WIN_MESSAGE == WIN_ERR)
+               return;
+
+       if(!mar_message_pause){
+               mar_message_pause=TRUE;
+               messages_pro_zug=0;
+               msg_pos=msg_max;
+       }
+
+       if(msg_max>mesg_hist-2){
+               msg_max=mesg_hist-2;
+               msg_pos--;
+               if(msg_pos<0) msg_pos=0;
+               tmp=message_line[0];
+               for(i=0;i<mesg_hist-1;i++){
+                       message_line[i]=message_line[i+1];
+                       message_age[i]=message_age[i+1];
+               }
+               message_line[mesg_hist-1]=tmp;
+       }
+       strcpy(toplines,str);
+       messages_pro_zug++;
+       msg_max++;
+
+       if((int)strlen(toplines)>=msg_width){
+               int pos=msg_width;
+               tmp=toplines+msg_width;
+               while(*tmp!=' ' && pos>=0){
+                       tmp--;
+                       pos--;
+               }
+               if(pos<=0) pos=msg_width;       /* Mar -- Oops, what a word :-) */
+               message_age[msg_max]=TRUE;
+               strncpy(message_line[msg_max],toplines,pos);
+               message_line[msg_max][pos]=0;
+               rest=strcpy(buf,toplines+pos);
+       }else{
+               message_age[msg_max]=TRUE;
+               strncpy(message_line[msg_max],toplines,msg_width);
+               rest=0;
+       }
+
+       Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE;
+       if(messages_pro_zug>=mesg_hist){ /* MAR -- Greater then should never happen */
+               messages_pro_zug=mesg_hist;
+               mar_display_nhwindow(WIN_MESSAGE);
+       }
+
+       if(rest)
+               mar_add_message(rest);
+}
+
+/************************* mar_add_status_str *******************************/
+
+void
+mar_add_status_str(str,line)
+const char *str;
+int line;
+{
+       int i,last_diff=-1;
+       GRECT area={0,line*status_font.ch,status_font.cw,status_font.ch};
+       for(i=0;(i<status_w-2) && str[i];i++)
+               if(str[i]!=status_line[line][i]){
+                       if(last_diff==-1) area.g_x=i*status_font.cw;
+                       else area.g_w+=status_font.cw;
+                       last_diff=i;
+                       status_line[line][i]=str[i];
+               }else if(last_diff>=0){
+                       add_dirty_rect(dr_stat,&area);
+                       last_diff=-1;
+                       area.g_w=status_font.cw;
+               }
+               for(;i<status_w-1;i++){
+                       if(status_line[line][i]){
+                               if(last_diff==-1) area.g_x=i*status_font.cw;
+                               else area.g_w+=status_font.cw;
+                               last_diff=i;
+                       }
+                       status_line[line][i]=0;
+               }
+       if(last_diff>=0)
+               add_dirty_rect(dr_stat,&area);
+}
+
+/************************* mar_set_menu_title *******************************/
+
+void
+mar_set_menu_title(str)
+const char *str;
+{
+       test_free(Menu_title);  /* just in case */
+       Menu_title=mar_copy_of(str ? str : nullstr);
+}
+
+/************************* mar_set_menu_type *******************************/
+
+void
+mar_set_menu_type(how)
+int how;
+{
+       Inv_how=how;
+}
+
+/************************* Inventory Utils *******************************/
+
+void
+set_all_on_page(start, page)
+int start, page;
+{
+       Gem_menu_item *curr;
+
+       if(start<0 || page<0)
+               return;
+
+       for(curr=invent_list; start--&&curr; curr=curr->Gmi_next);
+       for(; page--&&curr; curr=curr->Gmi_next)
+               if (curr->Gmi_identifier && !curr->Gmi_selected)
+                       curr->Gmi_selected = TRUE;
+}
+
+void
+unset_all_on_page(start, page)
+int start, page;
+{
+       Gem_menu_item *curr;
+
+       if(start<0 || page<0)
+               return;
+
+       for(curr=invent_list; start--&&curr; curr=curr->Gmi_next);
+       for(; page--&&curr; curr=curr->Gmi_next)
+               if (curr->Gmi_identifier && curr->Gmi_selected) {
+                       curr->Gmi_selected = FALSE;
+                       curr->Gmi_count = -1L;
+               }
+}
+
+void
+invert_all_on_page(start, page, acc)
+int start, page;
+char acc;
+{
+       Gem_menu_item *curr;
+
+       if(start<0 || page<0)
+               return;
+
+       for(curr=invent_list; start--&&curr; curr=curr->Gmi_next);
+       for(; page--&&curr; curr=curr->Gmi_next)
+               if (curr->Gmi_identifier && (acc == 0 || curr->Gmi_groupacc == acc)) {
+                       if (curr->Gmi_selected) {
+                               curr->Gmi_selected = FALSE;
+                               curr->Gmi_count = -1L;
+                       } else
+                               curr->Gmi_selected = TRUE;
+               }
+}
+
+/************************* Inv_Handler and Inv_Init *******************************/
+
+int scroll_top_dialog(char ch){
+       WIN *w;
+       DIAINFO *dinf;
+
+       if((w=get_top_window()) && (dinf=(DIAINFO *)w->dialog) && dinf->di_tree==zz_oblist[LINES]){
+               switch(ch){
+               case ' ':
+                       if(scroll_menu.vpos==scroll_menu.vmax){
+                               send_return();
+                               break;
+                       }
+                       /* Fall thru */
+               case MENU_NEXT_PAGE:
+                       scroll_window(w,PAGE_DOWN,NULL);
+                       break;
+               case MENU_PREVIOUS_PAGE:
+                       scroll_window(w,PAGE_UP,NULL);
+                       break;
+               case MENU_FIRST_PAGE:
+                       scroll_window(w,WIN_START,NULL);
+                       break;
+               case MENU_LAST_PAGE:
+                       scroll_window(w,WIN_END,NULL);
+                       break;
+               default:
+                       return(FALSE);
+               }
+               return(TRUE);
+       }
+       return(FALSE);
+}
+
+#define Text_Init KM_Init
+
+int
+Text_Handler(xev)
+XEVENT *xev;
+{
+       int ev=xev->ev_mwich;
+
+       if(ev&MU_MESAG){
+               int *buf=xev->ev_mmgpbuf, y_wo, i;
+               if(*buf==FONT_CHANGED){
+                       if(buf[3]>=0){
+                               mar_set_fontbyid(NHW_TEXT,buf[4],buf[5]);
+                               FontAck(buf[1],1);
+                       }
+               }
+       }
+       if(ev&MU_KEYBD){
+               char ch=(char)(xev->ev_mkreturn&0x00FF);
+
+               if(!scroll_top_dialog(ch))
+                       switch(ch){
+                       case '\033':
+                               send_return();  /* just closes the textwin */
+                               break;
+                       case C('c'):
+                               clipbrd_save(text_lines,Anz_text_lines,xev->ev_mmokstate&K_SHIFT,FALSE);
+                               break;
+                       default:
+                               ev &= ~MU_KEYBD;        /* unknown key */
+                               break;
+                       }
+       }
+       return(ev);
+}
+
+#define Inv_Init KM_Init
+
+static long count=0;
+int
+Inv_Handler(xev)
+XEVENT *xev;
+{
+       int ev=xev->ev_mwich;
+       Gem_menu_item *it;
+       GRECT area;
+       OBJECT *z_ob=zz_oblist[LINES];
+
+       ob_pos(z_ob,LINESLIST,&area);
+       if(ev&MU_MESAG){
+               int *buf=xev->ev_mmgpbuf, y_wo, i;
+
+               if(*buf==FONT_CHANGED){
+                       if(buf[3]>=0){
+                               mar_set_fontbyid(NHW_MENU,buf[4],buf[5]);
+                               FontAck(buf[1],1);
+                       }
+               }else
+               if(*buf==OBJC_CHANGED && buf[3]==LINESLIST){
+                       ob_undostate(z_ob,LINESLIST,SELECTED);
+                       mouse(NULL,&y_wo);
+                       y_wo=(y_wo-area.g_y)/menu_font.ch+scroll_menu.vpos;
+                       for(it=invent_list,i=0;i<y_wo && it;it=it->Gmi_next,i++);
+                       if(it->Gmi_identifier){
+                               it->Gmi_selected=!it->Gmi_selected;
+                               it->Gmi_count= count==0L ? -1L : count;
+                               count = 0L;
+                               if(Inv_how!=PICK_ANY){
+                                       /*my_close_dialog(Inv_dialog,TRUE);*/
+                                       send_return();
+                               }else{
+                                       area.g_x=(area.g_x+23+2*menu_font.cw) & ~7;
+                                       area.g_w=menu_font.cw;
+                                       area.g_h=menu_font.ch;
+                                       area.g_y+=(y_wo-scroll_menu.vpos)*menu_font.ch;
+                                       ob_draw_chg(Inv_dialog,LINESLIST,&area,FAIL);
+                               }       /* how != PICK_ANY */
+                       }       /* identifier */
+               }else   /* LINESLIST changed */
+                       ev &= ~MU_MESAG;        /* unknown message not used */
+       }       /* MU_MESAG */
+
+       if(ev&MU_KEYBD){
+               char ch=(char)(xev->ev_mkreturn&0x00FF);
+
+               if(!scroll_top_dialog(ch)){
+                       switch(ch){
+                       case '0':       /* special 0 is also groupaccelerator for balls */
+                               if(count<=0)
+                                       goto find_acc;
+                       case '1': case '2': case '3': case '4':
+                       case '5': case '6': case '7': case '8': case '9':
+                               if(Inv_how==PICK_NONE)
+                                       goto find_acc;
+                               count = (count * 10L) + (long) (ch - '0');
+                               break;
+                       case '\033':    /* cancel - from counting or loop */
+                               if(count>0L)
+                               count=0L;
+                               else{
+                                       unset_all_on_page(0, (int)scroll_menu.vsize);
+                                       my_close_dialog(Inv_dialog,TRUE);
+                                       return(ev);
+                               }
+                               break;
+                       case '\0':              /* finished (commit) */
+                       case '\n':
+                       case '\r':
+                               break;
+                       case MENU_SELECT_PAGE:
+                               if(Inv_how==PICK_NONE)
+                                       goto find_acc;
+                               if (Inv_how == PICK_ANY)
+                                       set_all_on_page((int)scroll_menu.vpos, scroll_menu.vpage);
+                               break;
+                       case MENU_SELECT_ALL:
+                               if(Inv_how==PICK_NONE)
+                                       goto find_acc;
+                               if (Inv_how == PICK_ANY)
+                                       set_all_on_page(0, (int)scroll_menu.vsize);
+                               break;
+                       case MENU_UNSELECT_PAGE:
+                               unset_all_on_page((int)scroll_menu.vpos, scroll_menu.vpage);
+                               break;
+                       case MENU_UNSELECT_ALL:
+                               unset_all_on_page(0, (int)scroll_menu.vsize);
+                               break;
+                       case MENU_INVERT_PAGE:
+                               if(Inv_how==PICK_NONE)
+                                       goto find_acc;
+                               if (Inv_how == PICK_ANY)
+                                       invert_all_on_page((int)scroll_menu.vpos, scroll_menu.vpage, 0);
+                               break;
+                       case MENU_INVERT_ALL:
+                               if(Inv_how==PICK_NONE)
+                                       goto find_acc;
+                               if (Inv_how == PICK_ANY)
+                                       invert_all_on_page(0, (int)scroll_menu.vsize, 0);
+                               break;
+                       case MENU_SEARCH:
+                               if(Inv_how!=PICK_NONE){
+                                       char buf[BUFSZ];
+                                       Gem_getlin("Search for:",buf);
+                                       if(!*buf || buf[0]=='\033')
+                                               break;
+                                       for(it=invent_list;it;it=it->Gmi_next){
+                                               if(it->Gmi_identifier && strstr(it->Gmi_str,buf)){
+                                                       it->Gmi_selected=TRUE;
+                                                       if(Inv_how!=PICK_ANY){
+                                                               my_close_dialog(Inv_dialog,FALSE);
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                               break;
+                       case C('c'):
+                               clipbrd_save(invent_list,Anz_inv_lines,xev->ev_mmokstate&K_SHIFT,TRUE);
+                               break;
+                       default:
+                       find_acc:
+                               if(Inv_how==PICK_NONE)
+                                       my_close_dialog(Inv_dialog,TRUE);
+                               else
+                                       for(it=invent_list;it;it=it->Gmi_next){
+                                               if(it->Gmi_identifier && (it->Gmi_accelerator==ch || it->Gmi_groupacc==ch)){
+                                                       it->Gmi_selected=!it->Gmi_selected;
+                                                       it->Gmi_count= count==0L ? -1L : count;
+                                                       count = 0L;
+                                                       if(Inv_how!=PICK_ANY)
+                                                               my_close_dialog(Inv_dialog,TRUE);
+                                               }
+                                       }
+                               break;
+                       }       /* end switch(ch) */
+                       if(Inv_how==PICK_ANY){
+                               area.g_x=(area.g_x+23+2*menu_font.cw) & ~7;
+                               area.g_w=menu_font.cw;
+                               ob_draw_chg(Inv_dialog,LINESLIST,&area,FAIL);
+                       }
+               }       /* !scroll_Inv_dialog */
+       }       /* MU_KEYBD */
+
+       if(Inv_how==PICK_ANY){
+               ob_set_text(Inv_dialog->di_tree,QLINE,strCancel);
+               for(it=invent_list;it;it=it->Gmi_next)
+                       if(it->Gmi_identifier && it->Gmi_selected){
+                               ob_set_text(Inv_dialog->di_tree,QLINE,strOk);
+                               break;
+                       }
+               ob_draw_chg(Inv_dialog,QLINE,NULL,FAIL);
+       }
+       return(ev);
+}
+
+/************************* draw_window *******************************/
+
+static void
+mar_draw_window( first, win, area)
+int first;
+WIN *win;
+GRECT *area;
+{
+       OBJECT *obj=(OBJECT *)win->para;
+
+       if(obj){
+               if(first){
+               obj->ob_x=win->work.g_x;
+               obj->ob_y=win->work.g_y;
+               }
+               if(area==NULL)
+                       area=&(win->work);
+               objc_draw(obj, ROOT, MAX_DEPTH, area->g_x, area->g_y, area->g_w, area->g_h);
+       }
+}
+
+/************************* mar_display_nhwindow *******************************/
+
+void redraw_winwork(WIN *w,GRECT *area){
+       area->g_x+=w->work.g_x;
+       area->g_y+=w->work.g_y;
+       redraw_window(w,area);
+}
+void mar_menu_set_slider(WIN *p_win){
+       if(p_win){
+               SCROLL *sc=p_win->scroll;
+
+               if(!sc)
+                       return;
+
+               if(p_win->gadgets&HSLIDE){
+                       long hsize=1000l;
+
+                       if(sc->hsize>0 && sc->hpage>0){
+                               hsize *= sc->hpage;
+                               hsize /= sc->hsize;
+                       }
+                       window_slider(p_win,HOR_SLIDER,0,(int)hsize);
+               }
+               if(p_win->gadgets&VSLIDE){
+                       long vsize=1000l;
+
+                       if(sc->vsize>0 && sc->vpage>0){
+                               vsize *= sc->vpage;
+                               vsize /= sc->vsize;
+                       }
+                       window_slider(p_win,VERT_SLIDER,0,(int)vsize);
+               }
+       }
+}
+
+void recalc_msg_win(GRECT *area){
+       OBJECT *z_ob;
+       z_ob=zz_oblist[MSGWIN];
+       z_ob[MSGLINES].ob_spec.userblk=&ub_msg;
+       z_ob[MSGLINES].ob_width=
+       z_ob[ROOT].ob_width=            (msg_width+3)*msg_font.cw;
+       z_ob[MSGLINES].ob_width-=z_ob[UPMSG].ob_width;
+       z_ob[ROOT].ob_height=
+       z_ob[GRABMSGWIN].ob_height=
+       z_ob[MSGLINES].ob_height=msg_vis*msg_font.ch;
+       z_ob[DNMSG].ob_y=z_ob[GRABMSGWIN].ob_height-z_ob[DNMSG].ob_height;
+       window_border(0,0,0,z_ob->ob_width,z_ob->ob_height, area);
+}
+void recalc_status_win(GRECT *area){
+       OBJECT *z_ob;
+       z_ob=zz_oblist[STATUSLINE];
+       z_ob[ROOT].ob_type=G_USERDEF;
+       z_ob[ROOT].ob_spec.userblk=&ub_status;
+       z_ob[ROOT].ob_width=(status_w+2)*status_font.cw;
+       z_ob[ROOT].ob_height=
+       z_ob[GRABSTATUS].ob_height=2*status_font.ch;
+       z_ob[GRABSTATUS].ob_width=2*status_font.cw-2;
+       window_border(0,0,0,z_ob->ob_width,z_ob->ob_height,area);
+}
+void calc_std_winplace(int which, GRECT *place){
+       static int todo=TRUE;
+       static GRECT me, ma, st;
+
+       if(todo || which<0){
+               OBJECT *z_ob;
+               int map_h_off, foo;
+
+               /* First the messagewin */
+               recalc_msg_win(&me);
+
+               /* Now the map */
+               wind_calc(WC_BORDER,MAP_GADGETS,0,0,scroll_map.px_hline*(COLNO-1),scroll_map.px_vline*ROWNO,&foo,&foo,&foo,&map_h_off);
+               map_h_off-=scroll_map.px_vline*ROWNO;
+               window_border(MAP_GADGETS,0,0,scroll_map.px_hline*(COLNO-1),scroll_map.px_vline*ROWNO, &ma);
+
+               /* Next the statuswin */
+               recalc_status_win(&st);
+
+               /* And last but not least a final test */
+               ma.g_h=map_h_off+scroll_map.px_vline*ROWNO;
+               while(me.g_h+ma.g_h+st.g_h>=desk.g_h)
+                       ma.g_h-=scroll_map.px_vline;
+               /* stack the windows */
+               ma.g_y=me.g_y=st.g_y=desk.g_y;
+               if(status_align){
+                       ma.g_y+=st.g_h;
+                       if(msg_align){
+                               st.g_y+=me.g_h;
+                               ma.g_y+=me.g_h;
+                       }else{
+                               me.g_y+=st.g_h+ma.g_h;
+                       }
+               }else{
+                       if(msg_align){
+                               ma.g_y+=me.g_h;
+                       }else{
+                               me.g_y+=ma.g_h;
+                       }
+                       st.g_y+=me.g_h+ma.g_h;
+               }
+
+               if(which) todo=FALSE;
+       }
+       switch(which){
+       case NHW_MESSAGE:
+               *place=me;
+               break;
+       case NHW_MAP:
+               *place=ma;
+               break;
+       case NHW_STATUS:
+               *place=st;
+               break;
+       default:
+               break;
+       }
+}
+
+void
+mar_display_nhwindow(wind)
+winid wind;
+{
+       DIAINFO *dlg_info;
+       OBJECT *z_ob;
+       int d_exit=W_ABANDON, i, breite, mar_di_mode, tmp_magx=magx;
+       GRECT g_mapmax, area;
+       char *tmp_button;
+       struct gw *p_Gw;
+
+       if(wind == WIN_ERR)     return;
+
+       p_Gw=&Gem_nhwindow[wind];
+       switch(p_Gw->gw_type){
+       case NHW_TEXT:
+               if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window)
+                       mar_display_nhwindow(WIN_MESSAGE);
+               z_ob=zz_oblist[LINES];
+               scroll_menu.vsize=Anz_text_lines;
+               scroll_menu.vpos=0;
+               if(use_rip){
+                       if(!depack_img(planes<4 ? "RIP2.IMG" : "RIP.IMG", &rip_image)){
+                               mfdb(&Rip_bild, (int *)rip_image.addr, rip_image.img_w, rip_image.img_h, 1, rip_image.planes);
+                               transform_img(&Rip_bild);
+                       }
+                       ub_lines.ub_code=draw_rip;
+               }else
+                       ub_lines.ub_code=draw_lines;
+               z_ob[LINESLIST].ob_spec.userblk=&ub_lines;
+               breite=16;
+               v_set_text(text_font.id,text_font.size,BLACK,0,0,NULL);
+               for(i=0;i<Anz_text_lines;i++){
+                       int eout[8];
+                       vqt_extent(x_handle,text_lines[i],eout);
+                       Max(&breite,eout[4]);
+               }
+               scroll_menu.px_vline=text_font.ch;
+               scroll_menu.px_hline=text_font.cw;
+               mar_di_mode=mar_set_inv_win(Anz_text_lines, breite);
+               tmp_button=ob_get_text(z_ob,QLINE,0);
+               ob_set_text(z_ob,QLINE,strOk);
+               ob_undoflag(z_ob,LINESLIST,TOUCHEXIT);
+               Event_Handler(Text_Init,Text_Handler);
+               if((dlg_info=open_dialog(z_ob,strText, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, mar_di_mode, FAIL, NULL, NULL))!=NULL){
+                       WIN *ptr_win=dlg_info->di_win;
+
+                       ptr_win->scroll=&scroll_menu;
+                       mar_menu_set_slider(ptr_win);
+                       WindowItems(ptr_win,SCROLL_KEYS,scroll_keys);
+                       if((d_exit=X_Form_Do(NULL))!=W_ABANDON){
+                               my_close_dialog(dlg_info,FALSE);
+                               if(d_exit!=W_CLOSED)
+                                       ob_undostate(z_ob,d_exit&NO_CLICK,SELECTED);
+                       }
+               }
+               Event_Handler(NULL,NULL);
+               ob_set_text(z_ob,QLINE,tmp_button);
+               break;
+       case NHW_MENU:
+               if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window)
+                       mar_display_nhwindow(WIN_MESSAGE);
+               z_ob=zz_oblist[LINES];
+               scroll_menu.vsize=Anz_inv_lines;
+               scroll_menu.vpos=0;
+               z_ob[LINESLIST].ob_spec.userblk=&ub_inventory;
+               if((Menu_title)&&(wind!=WIN_INVEN))     /* because I sets no Menu_title */
+                       Max(&Inv_breite,gr_cw*strlen(Menu_title)+16);
+               scroll_menu.px_vline=menu_font.ch;
+               scroll_menu.px_hline=menu_font.cw;
+               mar_di_mode=mar_set_inv_win(Anz_inv_lines, Inv_breite, NHW_MENU);
+               tmp_button=ob_get_text(z_ob,QLINE,0);
+               ob_set_text(z_ob,QLINE,Inv_how!=PICK_NONE ? strCancel : strOk );
+               ob_doflag(z_ob,LINESLIST,TOUCHEXIT);
+               Event_Handler(Inv_Init, Inv_Handler);
+               if((Inv_dialog=open_dialog(z_ob,(wind==WIN_INVEN) ? "Inventory" : (Menu_title ? Menu_title : "Staun"), NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, mar_di_mode, FAIL, NULL, NULL))!=NULL){
+                       WIN *ptr_win=Inv_dialog->di_win;
+
+                       ptr_win->scroll=&scroll_menu;
+                       mar_menu_set_slider(ptr_win);
+                       WindowItems(ptr_win,SCROLL_KEYS,scroll_keys);
+                       do{
+                               int y_wo,x_wo,ru_w=1,ru_h=1;
+                               GRECT oarea;
+                               Gem_menu_item *it;
+                               d_exit=X_Form_Do(NULL);
+                               if((d_exit&NO_CLICK)==LINESLIST){
+                                       ob_pos(z_ob,LINESLIST,&oarea);
+                                       if(mouse(&x_wo,&y_wo) && Inv_how==PICK_ANY){
+                                               graf_rt_rubberbox(FALSE,x_wo,y_wo,FAIL,FAIL,&oarea,&ru_w,&ru_h,NULL);
+                                               invert_all_on_page((int)((y_wo-oarea.g_y)/menu_font.ch+scroll_menu.vpos),(ru_h+menu_font.ch-1)/menu_font.ch,0);
+                                       }else{
+                                               for(it=invent_list,i=0;i<((y_wo-oarea.g_y)/menu_font.ch+scroll_menu.vpos) && it;it=it->Gmi_next,i++);
+                                               if(it && it->Gmi_identifier){
+                                                       it->Gmi_selected=!it->Gmi_selected;
+                                                       it->Gmi_count= count==0L ? -1L : count;
+                                                       count = 0L;
+                                                       if(Inv_how!=PICK_ANY)
+                                                               break;
+                                               }       /* identifier */
+                                       }
+                                       oarea.g_x=(oarea.g_x+23+2*menu_font.cw) & ~7;
+                                       oarea.g_y=y_wo-(y_wo-oarea.g_y)%menu_font.ch;
+                                       oarea.g_w=menu_font.cw;
+                                       oarea.g_h=((ru_h+menu_font.ch-1)/menu_font.ch)*menu_font.ch;
+                                       ob_draw_chg(Inv_dialog,LINESLIST,&oarea,FAIL);
+                               }
+                               if(Inv_how==PICK_ANY){
+                                       ob_set_text(Inv_dialog->di_tree,QLINE,strCancel);
+                                       for(it=invent_list;it;it=it->Gmi_next)
+                                               if(it->Gmi_identifier && it->Gmi_selected){
+                                                       ob_set_text(Inv_dialog->di_tree,QLINE,strOk);
+                                                       break;
+                                               }
+                                       ob_draw_chg(Inv_dialog,QLINE,NULL,FAIL);
+                               }
+                       }while((d_exit&NO_CLICK)==LINESLIST);
+                       if(d_exit!=W_ABANDON){
+                               my_close_dialog(Inv_dialog,FALSE);
+                               if(d_exit!=W_CLOSED)
+                                       ob_undostate(z_ob,d_exit&NO_CLICK,SELECTED);
+                       }
+               }
+               Event_Handler(NULL,NULL);
+               ob_set_text(z_ob,QLINE,tmp_button);
+               break;
+       case NHW_MAP:
+               if(p_Gw->gw_window==NULL){
+                       calc_std_winplace(NHW_MAP,&p_Gw->gw_place);
+                       window_border(MAP_GADGETS,0,0,Tile_width*(COLNO-1),Tile_heigth*ROWNO, &g_mapmax);
+                       p_Gw->gw_window=open_window(md, md, NULL, zz_oblist[NHICON], MAP_GADGETS, TRUE, 128, 128, &g_mapmax, &p_Gw->gw_place, &scroll_map, win_draw_map, NULL, XM_TOP|XM_BOTTOM|XM_SIZE);
+                       WindowItems(p_Gw->gw_window,SCROLL_KEYS-1,scroll_keys); /* ClrHome centers on u */
+                       mar_clear_map();
+               }
+               if(p_Gw->gw_dirty){
+                       area.g_x=p_Gw->gw_window->work.g_x+scroll_map.px_hline*(dirty_map_area.g_x-scroll_map.hpos);
+                       area.g_y=p_Gw->gw_window->work.g_y+scroll_map.px_vline*(dirty_map_area.g_y-scroll_map.vpos);
+                       area.g_w=(dirty_map_area.g_w-dirty_map_area.g_x+1)*scroll_map.px_hline;
+                       area.g_h=(dirty_map_area.g_h-dirty_map_area.g_y+1)*scroll_map.px_vline;
+
+                       redraw_window(p_Gw->gw_window,&area);
+
+                       dirty_map_area.g_x=COLNO-1;
+                       dirty_map_area.g_y=ROWNO;
+                       dirty_map_area.g_w=
+                       dirty_map_area.g_h=0;
+               }
+               break;
+       case NHW_MESSAGE:
+               if(p_Gw->gw_window==NULL){
+                       calc_std_winplace(NHW_MESSAGE,&p_Gw->gw_place);
+                       z_ob=zz_oblist[MSGWIN];
+                       magx=0; /* MAR -- Fake E_GEM to remove Backdropper */
+                       p_Gw->gw_window=open_window(NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, &p_Gw->gw_place, NULL, mar_draw_window, z_ob, XM_TOP|XM_BOTTOM|XM_SIZE);
+                       magx=tmp_magx;
+                       window_size(p_Gw->gw_window,&p_Gw->gw_window->curr);
+                       p_Gw->gw_dirty=TRUE;
+               }
+
+               if(p_Gw->gw_dirty){
+                       ob_pos(zz_oblist[MSGWIN],MSGLINES,&area);
+                       while(messages_pro_zug>3){
+                               messages_pro_zug-=3;
+                               msg_pos+=3;
+                               redraw_window(p_Gw->gw_window,&area);
+                               mar_more();
+                       }
+                       msg_pos+=messages_pro_zug;
+                       messages_pro_zug=0;
+                       if(msg_pos>msg_max) msg_pos=msg_max;
+                       redraw_window(p_Gw->gw_window,&area);
+                       mar_message_pause=FALSE;
+               }
+               break;
+       case NHW_STATUS:
+               if(p_Gw->gw_window==NULL){
+                       z_ob=zz_oblist[STATUSLINE];
+                       calc_std_winplace(NHW_STATUS,&p_Gw->gw_place);
+                       magx=0; /* MAR -- Fake E_GEM to remove Backdropper */
+                       p_Gw->gw_window=open_window(NULL, NULL, NULL, NULL, 0, FALSE, 0, 0, NULL, &p_Gw->gw_place, NULL, mar_draw_window, z_ob, XM_TOP|XM_BOTTOM|XM_SIZE);
+                       magx=tmp_magx;
+                       /* Because 2*status_font.ch is smaller then e_gem expects the minimum win_height */
+                       p_Gw->gw_window->min_h=z_ob[ROOT].ob_height;
+                       window_size(p_Gw->gw_window,&p_Gw->gw_place);
+                       p_Gw->gw_dirty=TRUE;
+                       add_dirty_rect(dr_stat,&p_Gw->gw_place);
+               }
+               while(get_dirty_rect(dr_stat,&area)){
+                       area.g_x=(area.g_x+p_Gw->gw_window->work.g_x+2*status_font.cw+6)&~7;
+                       area.g_y+=p_Gw->gw_window->work.g_y;
+                       redraw_window(p_Gw->gw_window,&area);
+               }
+               break;
+       default:
+               if(p_Gw->gw_dirty)
+                       redraw_window(p_Gw->gw_window,NULL);
+       }
+       p_Gw->gw_dirty=FALSE;
+}
+
+/************************* create_window *******************************/
+
+int mar_hol_win_type(window)
+winid  window;
+{
+       return(Gem_nhwindow[window].gw_type);
+}
+
+winid
+mar_create_window(type)
+int type;
+{
+       winid newid;
+       static char name[]="Gem";
+       int i;
+       struct gw *p_Gw=&Gem_nhwindow[0];
+
+       for(newid = 0; p_Gw->gw_type && newid < MAXWIN; newid++, p_Gw++);
+
+       switch(type){
+       case NHW_MESSAGE:
+               message_line=(char **)m_alloc(msg_anz*sizeof(char *));
+               message_age=(int *)m_alloc(msg_anz*sizeof(int));
+               for(i=0;i<msg_anz;i++){
+                       message_age[i]=FALSE;
+                       message_line[i]=(char *)m_alloc((MSGLEN+1)*sizeof(char));
+                       *message_line[i]=0;
+               }
+               dr_msg=new_dirty_rect(10);
+               if (!dr_msg) panic("Memory allocation failure (dr_msg)");
+               break;
+       case NHW_STATUS:
+               status_line=(char **)m_alloc(2*sizeof(char *));
+               for(i=0;i<2;i++){
+                       status_line[i]=(char *)m_alloc(status_w*sizeof(char));
+                       memset(status_line[i],0,status_w);
+               }
+               dr_stat=new_dirty_rect(10);
+               if (!dr_stat) panic("Memory allocation failure (dr_stat)");
+               break;
+       case NHW_MAP:
+               map_glyphs=(char **)m_alloc((long)ROWNO*sizeof(char *));
+               for(i=0;i<ROWNO;i++){
+                       map_glyphs[i]=(char *)m_alloc((long)COLNO*sizeof(char));
+                       *map_glyphs[i]=map_glyphs[i][COLNO-1]=0;
+               }
+               dr_map=new_dirty_rect(10);
+               if (!dr_map) panic("Memory allocation failure (dr_map)");
+
+               mar_clear_map();
+               break;
+       case NHW_MENU:
+       case NHW_TEXT:  /* They are no more treated as dialog */
+               break;
+       default:
+               p_Gw->gw_window=open_window("Sonst", name, NULL, NULL, NAME|MOVER|CLOSER, 0, 0, 0, NULL, &p_Gw->gw_place, NULL, NULL, NULL, XM_TOP|XM_BOTTOM|XM_SIZE);
+               break;
+       }
+
+       p_Gw->gw_type=type;
+
+       return(newid);
+}
+
+void
+mar_change_menu_2_text(win)
+winid win;
+{
+       Gem_nhwindow[win].gw_type=NHW_TEXT;
+}
+
+/************************* mar_clear_map *******************************/
+
+void
+mar_clear_map()
+{
+       int pla[8];
+       int x,y;
+
+       pla[0]=pla[1]=pla[4]=pla[5]=0;
+       pla[2]=pla[6]=scroll_map.px_hline*(COLNO-1)-1;
+       pla[3]=pla[7]=scroll_map.px_vline*ROWNO-1;
+       for(y=0;y<ROWNO;y++) for(x=0;x<COLNO-1;x++)
+               map_glyphs[y][x]=' ';
+       vro_cpyfm(x_handle, ALL_BLACK,pla,&Tile_bilder,&Map_bild);      /* MAR -- 17.Mar 2002 Hmm, what if FontCol_Bild is bigger? */
+       if(WIN_MAP != WIN_ERR && Gem_nhwindow[WIN_MAP].gw_window)
+               redraw_window(Gem_nhwindow[WIN_MAP].gw_window,NULL);
+}
+
+/************************* destroy_window *******************************/
+
+void
+mar_destroy_nhwindow(window)
+winid window;
+{
+       int i;
+
+       switch(Gem_nhwindow[window].gw_type){
+       case NHW_TEXT:
+               for(i=0;i<Anz_text_lines;i++)
+                       free(text_lines[i]);
+               null_free(text_lines);
+               Anz_text_lines=0;
+               use_rip=FALSE;
+               break;
+       case NHW_MENU:
+               Gem_start_menu(window); /* delete invent_list */
+               test_free(Menu_title);
+               break;
+       case 0: /* No window available, probably an error message? */
+               break;
+       default:
+               close_window( Gem_nhwindow[window].gw_window, 0 );
+               break;
+       }
+       Gem_nhwindow[window].gw_window=NULL;
+       Gem_nhwindow[window].gw_type=0;
+       Gem_nhwindow[window].gw_dirty=FALSE;
+
+       if(window==WIN_MAP){
+               for(i=0;i<ROWNO;i++){
+                       free(map_glyphs[i]);
+               }
+               null_free(map_glyphs);
+               WIN_MAP=WIN_ERR;
+       }
+       if(window==WIN_STATUS){
+               for(i=0;i<2;i++)
+                       free(status_line[i]);
+               null_free(status_line);
+               WIN_STATUS=WIN_ERR;
+       }
+       if(window==WIN_MESSAGE){
+               for(i=0;i<msg_anz;i++)
+                       free(message_line[i]);
+               null_free(message_line);
+               null_free(message_age);
+               WIN_MESSAGE=WIN_ERR;
+       }
+       if(window==WIN_INVEN)
+               WIN_INVEN=WIN_ERR;
+}
+
+/************************* nh_poskey *******************************/
+
+void mar_set_margin(int m){
+       Max(&m,0);
+       Min(&m,min(ROWNO,COLNO));       /* MAR 16.Mar 2002 -- the larger the less sense */
+       scroll_margin=m;
+}
+void
+mar_cliparound()
+{
+       if(WIN_MAP!=WIN_ERR && Gem_nhwindow[WIN_MAP].gw_window){
+               int     breite=scroll_margin>0 ? scroll_margin : max(scroll_map.hpage/4,1),
+                               hoehe=scroll_margin>0 ? scroll_margin : max(scroll_map.vpage/4,1),
+                               adjust_needed;
+               adjust_needed=FALSE;
+               if ((map_cursx < scroll_map.hpos + breite) || (map_cursx >= scroll_map.hpos + scroll_map.hpage - breite)){
+                       scroll_map.hpos=map_cursx - scroll_map.hpage/2;
+                       adjust_needed=TRUE;
+               }
+               if ((map_cursy < scroll_map.vpos + hoehe) || (map_cursy >= scroll_map.vpos + scroll_map.vpage - hoehe)){
+                       scroll_map.vpos=map_cursy - scroll_map.vpage/2;
+                       adjust_needed=TRUE;
+               }
+               if(adjust_needed)
+                       scroll_window(Gem_nhwindow[WIN_MAP].gw_window,WIN_SCROLL,NULL);
+       }
+}
+
+void
+mar_update_value()
+{
+       if(WIN_MESSAGE!=WIN_ERR){
+               mar_message_pause=FALSE;
+               mar_esc_pressed=FALSE;
+               mar_display_nhwindow(WIN_MESSAGE);
+       }
+
+       if(WIN_MAP!=WIN_ERR)
+               mar_cliparound();
+
+       if(WIN_STATUS!=WIN_ERR){
+               mar_check_hilight_status();
+               mar_display_nhwindow(WIN_STATUS);
+       }
+}
+
+int
+Main_Init(xev,availiable)
+XEVENT *xev;
+int availiable;
+{
+       xev->ev_mb1mask=
+       xev->ev_mb1state=1;
+       xev->ev_mb1clicks=
+       xev->ev_mb2clicks=
+       xev->ev_mb2mask=
+       xev->ev_mb2state=2;
+       return((MU_KEYBD|MU_BUTTON1|MU_BUTTON2|MU_MESAG)&availiable);
+}
+
+/*
+ * return a key, or 0, in which case a mouse button was pressed
+ * mouse events should be returned as character postitions in the map window.
+ */
+/*ARGSUSED*/
+int
+mar_nh_poskey(x, y, mod)
+    int *x, *y, *mod;
+{
+       static XEVENT xev;
+       int retval, ev;
+
+       xev.ev_mflags=Main_Init(&xev,0xFFFF);
+       ev=Event_Multi(&xev);
+
+       retval=FAIL;
+
+       if(ev&MU_KEYBD){
+               char ch = xev.ev_mkreturn&0x00FF;
+               char scan = (xev.ev_mkreturn & 0xff00) >> 8;
+               int shift = xev.ev_mmokstate;
+               const struct pad *kpad;
+
+               /* Translate keypad keys */
+               if (iskeypad(scan)) {
+                       kpad = mar_iflags_numpad()==1 ? numpad : keypad;
+                       if (shift & K_SHIFT)
+                               ch = kpad[scan - KEYPADLO].shift;
+                       else if (shift & K_CTRL){
+                               if(scan>=0x67 && scan<=0x6f && scan!=0x6b){
+                                       send_key(kpad[scan - KEYPADLO].normal);
+                                       ch = 'g';
+                               }else{
+                               ch = kpad[scan - KEYPADLO].cntrl;
+                               }
+                       }else
+                               ch = kpad[scan - KEYPADLO].normal;
+               }
+               if(scan==SCANHOME)
+                       mar_cliparound();
+               else if(scan == SCANF1)
+                       retval='h';
+               else if(scan == SCANF2){
+                       mar_set_tile_mode(!mar_set_tile_mode(FAIL));
+                       retval=C('l');  /* trigger full-redraw */
+               }else if(scan == SCANF3){
+                       draw_cursor=!draw_cursor;
+                       mar_curs(map_cursx,map_cursy);
+                       mar_display_nhwindow(WIN_MAP);
+               }else if(scan == SCANF4){       /* Font-Selector */
+                       if(!CallFontSelector(0,FAIL,FAIL,FAIL,FAIL)){
+                               xalert(1,1,X_ICN_ALERT,NULL,SYS_MODAL,BUTTONS_RIGHT,TRUE,"Hello","Fontselector not available!",NULL);
+                       }
+               }else if(!ch && shift&K_CTRL && scan==-57){
+                       /* MAR -- nothing ignore Ctrl-Alt-Clr/Home == MagiC's restore screen */
+               }else{
+                       if(!ch)
+                               ch=(char)M(tolower(scan_2_ascii(xev.ev_mkreturn,shift)));
+                       if(((int)ch)==-128)
+                               ch='\033';
+                       retval=ch;
+               }
+       }
+
+       if(ev&MU_BUTTON1 || ev&MU_BUTTON2){
+               int ex=xev.ev_mmox, ey=xev.ev_mmoy;
+               WIN *akt_win=window_find(ex,ey);
+
+               if(WIN_MAP != WIN_ERR && akt_win==Gem_nhwindow[WIN_MAP].gw_window){
+                       *x=max(min((ex-akt_win->work.g_x)/scroll_map.px_hline+scroll_map.hpos,COLNO-1),0)+1;
+                       *y=max(min((ey-akt_win->work.g_y)/scroll_map.px_vline+scroll_map.vpos,ROWNO),0);
+                       *mod=xev.ev_mmobutton;
+                       retval=0;
+               }else if(WIN_STATUS != WIN_ERR && akt_win==Gem_nhwindow[WIN_STATUS].gw_window){
+                       move_win(akt_win);
+               }else if(WIN_MESSAGE != WIN_ERR && akt_win==Gem_nhwindow[WIN_MESSAGE].gw_window){
+                       message_handler(ex,ey);
+               }
+       }
+
+       if(ev&MU_MESAG){
+               int *buf=xev.ev_mmgpbuf;
+               char *str;
+               OBJECT *z_ob=zz_oblist[MENU];
+
+          switch(*buf) {
+               case MN_SELECTED :
+                       menu_tnormal(z_ob,buf[3],TRUE); /* unselect menu header */
+                       str=ob_get_text(z_ob,buf[4],0);
+                       str+=strlen(str)-2;
+                       switch(*str){
+                       case ' ':       /* just that command */
+                               retval=str[1];
+                               break;
+                       case '\005':    /* Alt command */
+                       case '\007':
+                               retval=M(str[1]);
+                               break;
+                       case '^':       /* Ctrl command */
+                               retval=C(str[1]);
+                               break;
+                       case 'f':       /* Func Key */
+                               switch(str[1]){
+                               case '1':
+                                       retval='h';
+                                       break;
+                               case '2':
+                                       mar_set_tile_mode(!mar_set_tile_mode(FAIL));
+                                       retval=C('l');  /* trigger full-redraw */
+                                       break;
+                               case '3':
+                                       draw_cursor=!draw_cursor;
+                                       mar_curs(map_cursx,map_cursy);
+                                       mar_display_nhwindow(WIN_MAP);
+                                       break;
+                               default:
+                               }
+                               break;
+                       default:
+                               mar_about();
+                               break;
+                       }
+                       break;  /* MN_SELECTED */
+               case WM_CLOSED:
+                       WindowHandler(W_ICONIFYALL,NULL,NULL);
+                       break;
+               case AP_TERM:
+                       retval='S';
+                       break;
+               case FONT_CHANGED:
+                       if(buf[3]>=0){
+                               if(buf[3]==Gem_nhwindow[WIN_MESSAGE].gw_window->handle){
+                                       mar_set_fontbyid(NHW_MESSAGE,buf[4],buf[5]);
+                                       mar_display_nhwindow(WIN_MESSAGE);
+                               }else if(buf[3]==Gem_nhwindow[WIN_MAP].gw_window->handle){
+                                       mar_set_fontbyid(NHW_MAP,buf[4],buf[5]);
+                                       mar_display_nhwindow(WIN_MAP);
+                               }else if(buf[3]==Gem_nhwindow[WIN_STATUS].gw_window->handle){
+                                       mar_set_fontbyid(NHW_STATUS,buf[4],buf[5]);
+                                       mar_display_nhwindow(WIN_STATUS);
+                               }
+                               FontAck(buf[1],1);
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }       /* MU_MESAG */
+
+       if(retval==FAIL)
+               retval=mar_nh_poskey(x,y,mod);
+
+       return(retval);
+}
+
+int
+Gem_nh_poskey(x, y, mod)
+    int *x, *y, *mod;
+{
+       mar_update_value();
+       return(mar_nh_poskey(x, y, mod));
+}
+
+void
+Gem_delay_output()
+{
+       Event_Timer(50,0,FALSE);        /* wait 50ms */
+}
+
+int
+Gem_doprev_message()
+{
+       if(msg_pos>2){
+               msg_pos--;
+       if(WIN_MESSAGE != WIN_ERR)
+               Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE;
+       mar_display_nhwindow(WIN_MESSAGE);
+       }
+       return(0);
+}
+
+/************************* print_glyph *******************************/
+
+int mar_set_rogue(int);
+
+int
+mar_set_tile_mode(tiles)
+int tiles;
+{
+       static int tile_mode=TRUE;
+       static GRECT prev;
+       WIN *z_w=WIN_MAP!=WIN_ERR ? Gem_nhwindow[WIN_MAP].gw_window : NULL;
+
+       if(tiles<0)
+               return(tile_mode);
+       else if(!z_w)
+               tile_mode=tiles;
+       else if(tile_mode==tiles || (mar_set_rogue(FAIL) && tiles))
+                       return(FAIL);
+       else{
+               GRECT tmp;
+
+               tile_mode=tiles;
+               scroll_map.px_hline= tiles ? Tile_width : map_font.cw;
+               scroll_map.px_vline= tiles ? Tile_heigth : map_font.ch;
+               window_border(MAP_GADGETS,0,0,scroll_map.px_hline*(COLNO-1),scroll_map.px_vline*ROWNO, &tmp);
+               z_w->max.g_w=tmp.g_w;
+               z_w->max.g_h=tmp.g_h;
+               if(tiles)
+                       z_w->curr=prev;
+               else
+                       prev=z_w->curr;
+
+               window_reinit(z_w,md,md,NULL,FALSE,FALSE);
+       }
+       return(FAIL);
+}
+
+int
+mar_set_rogue(what)
+int what;
+{
+       static int rogue=FALSE, prev_mode=TRUE;
+
+       if(what<0) return(rogue);
+       if(what!=rogue){
+               rogue=what;
+               if(rogue){
+                       prev_mode=mar_set_tile_mode(FAIL);
+                       mar_set_tile_mode(FALSE);
+               }else
+                       mar_set_tile_mode(prev_mode);
+       }
+       return(FAIL);
+}
+
+void
+mar_add_pet_sign(window,x,y)
+winid window;
+int x, y;
+{
+       if(window != WIN_ERR && window==WIN_MAP){
+               static int pla[8]={0,0,7,7,0,0,0,0}, colindex[2]={RED,WHITE};
+
+               pla[4]=pla[6]=scroll_map.px_hline*x;
+               pla[5]=pla[7]=scroll_map.px_vline*y;
+               pla[6]+=7;
+               pla[7]+=6;
+               vrt_cpyfm(x_handle,MD_TRANS,pla,&Pet_Mark,&Map_bild,colindex);
+       }
+}
+
+void
+mar_print_glyph(window, x, y, gl)
+winid window;
+int x, y, gl;
+{
+       if(window != WIN_ERR && window==WIN_MAP){
+       static int pla[8];
+
+                       pla[2]=pla[0]=(gl%Tiles_per_line)*Tile_width;
+                       pla[3]=pla[1]=(gl/Tiles_per_line)*Tile_heigth;
+                       pla[2]+=Tile_width-1;
+                       pla[3]+=Tile_heigth-1;
+                       pla[6]=pla[4]=Tile_width*x;     /* x_wert to */
+                       pla[7]=pla[5]=Tile_heigth*y;    /* y_wert to */
+                       pla[6]+=Tile_width-1;
+                       pla[7]+=Tile_heigth-1;
+
+                       vro_cpyfm(x_handle, gl!=-1 ? S_ONLY : ALL_BLACK, pla, &Tile_bilder, &Map_bild);
+               }
+       }
+
+void
+mar_print_char(window, x, y, ch, col)
+winid window;
+int x, y;
+char ch;
+int col;
+{
+       if(window != WIN_ERR && window==WIN_MAP){
+               static int gem_color[16]={ 9, 2,11,10, 4, 7, 8, 15,0,14, 3, 6, 5, 13,15, 0};
+               int pla[8], colindex[2];
+
+               map_glyphs[y][x]=ch;
+
+               pla[0]=
+               pla[1]=0;
+               pla[2]=map_font.cw-1;
+               pla[3]=map_font.ch-1;
+               pla[6]=pla[4]=map_font.cw*x;
+               pla[7]=pla[5]=map_font.ch*y;
+               pla[6]+=map_font.cw-1;
+               pla[7]+=map_font.ch-1;
+               colindex[0]=gem_color[col];
+               colindex[1]=WHITE;
+               vrt_cpyfm(x_handle,MD_REPLACE,pla,&Black_bild,&FontCol_Bild,colindex);
+       }
+}
+
+/************************* getlin *******************************/
+
+void
+Gem_getlin(ques, input)
+const char *ques;
+char *input;
+{
+       OBJECT *z_ob=zz_oblist[LINEGET];
+       int d_exit, length;
+       char *pr[2], *tmp;
+
+       if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window)
+               mar_display_nhwindow(WIN_MESSAGE);
+
+       z_ob[LGPROMPT].ob_type=G_USERDEF;
+       z_ob[LGPROMPT].ob_spec.userblk=&ub_prompt;
+       z_ob[LGPROMPT].ob_height=2*gr_ch;
+
+       length=z_ob[LGPROMPT].ob_width/gr_cw;
+       if(strlen(ques)>length){
+               tmp=ques+length;
+               while(*tmp!=' ' && tmp>=ques){
+                       tmp--;
+               }
+               if(tmp<=ques) tmp=ques+length;  /* Mar -- Oops, what a word :-) */
+               pr[0]=ques;
+               *tmp=0;
+               pr[1]=++tmp;
+       }else{
+               pr[0]=ques;
+               pr[1]=NULL;
+       }
+       ub_prompt.ub_parm=(long)pr;
+
+       ob_clear_edit(z_ob);
+       d_exit=xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, DIALOG_MODE);
+       Event_Timer(0,0,TRUE);
+
+       if(d_exit==W_CLOSED || d_exit==W_ABANDON || (d_exit&NO_CLICK)==QLG){
+               *input='\033';
+               input[1]=0;
+       }else
+               strncpy(input,ob_get_text(z_ob,LGREPLY, 0),length);
+}
+
+/************************* ask_direction *******************************/
+
+#define Dia_Init K_Init
+
+int
+Dia_Handler(xev)
+XEVENT *xev;
+{
+       int ev=xev->ev_mwich;
+       char ch=(char)(xev->ev_mkreturn&0x00FF);
+
+       if(ev&MU_KEYBD){
+               WIN *w;
+               DIAINFO *dinf;
+
+               switch(ch){
+               case 's':
+                       send_key((int)(mar_iflags_numpad() ? '5' : '.'));
+                       break;
+               case '.':
+                       send_key('5');  /* MAR -- '.' is a button if numpad isn't set */
+                       break;
+               case '\033':    /*ESC*/
+                       if((w=get_top_window()) && (dinf=(DIAINFO *)w->dialog) && dinf->di_tree==zz_oblist[DIRECTION]){
+                               my_close_dialog(dinf,FALSE);
+                               break;
+                       }
+                       /* Fall thru */
+               default:
+                       ev &= ~MU_KEYBD;        /* let the dialog handle it */
+                       break;
+               }
+       }
+       return(ev);
+}
+
+int
+mar_ask_direction()
+{
+       int d_exit;
+       OBJECT *z_ob=zz_oblist[DIRECTION];
+
+       Event_Handler(Dia_Init,Dia_Handler);
+       mar_set_dir_keys();
+       d_exit=xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, DIALOG_MODE);
+       Event_Timer(0,0,TRUE);
+       Event_Handler(NULL,NULL);
+
+       if(d_exit==W_CLOSED || d_exit==W_ABANDON)
+               return('\033');
+       if((d_exit&NO_CLICK)==DIRDOWN)
+               return('>');
+       if((d_exit&NO_CLICK)==DIRUP)
+               return('<');
+       if((d_exit&NO_CLICK)==(DIR1+8)) /* 5 or . */
+               return('.');
+       return(*ob_get_text(z_ob,d_exit&NO_CLICK,0));
+}
+
+/************************* yn_function *******************************/
+
+
+#define any_init M_Init
+
+static int
+any_handler(xev)
+XEVENT *xev;
+{
+       int ev=xev->ev_mwich;
+
+       if(ev&MU_MESAG){
+               int *buf=xev->ev_mmgpbuf;
+
+               if(*buf==OBJC_EDITED)
+                       my_close_dialog(*(DIAINFO **)&buf[4], FALSE);
+               else
+                       ev &= ~MU_MESAG;
+       }
+       return(ev);
+}
+
+int
+send_yn_esc(char ch)
+{
+       static char esc_char=0;
+
+       if(ch<0){
+               if(esc_char){
+                       send_key((int)esc_char);
+                       return(TRUE);
+               }
+               return(FALSE);
+       }else
+               esc_char=ch;
+       return(TRUE);
+}
+
+#define single_init K_Init
+
+static int
+single_handler(xev)
+XEVENT *xev;
+{
+       int ev=xev->ev_mwich;
+
+       if(ev&MU_KEYBD){
+               char ch=(char)xev->ev_mkreturn&0x00FF;
+               WIN *w;
+               DIAINFO *dinf;
+
+               switch(ch){
+               case ' ':
+                       send_return();
+                       break;
+               case '\033':
+                       if((w=get_top_window()) && (dinf=(DIAINFO *)w->dialog) && dinf->di_tree==zz_oblist[YNCHOICE]){
+                               if(!send_yn_esc(FAIL))
+                                       my_close_dialog(dinf,FALSE);
+                               break;
+                       }
+                       /* Fall thru */
+               default:
+                       ev &= ~MU_MESAG;
+               }
+       }
+       return(ev);
+}
+
+char
+Gem_yn_function(query,resp, def)
+const char *query,*resp;
+char def;
+{
+       OBJECT *z_ob=zz_oblist[YNCHOICE];
+       int d_exit, i, len;
+       long anzahl;
+       char *tmp;
+       const char *ptr;
+
+       if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window)
+               mar_display_nhwindow(WIN_MESSAGE);
+
+       /* if query for direction the special dialog */
+       if(strstr(query,"irect"))
+               return(mar_ask_direction());
+
+       len=min(strlen(query),(max_w-8*gr_cw)/gr_cw);
+       z_ob[ROOT].ob_width=(len+8)*gr_cw;
+       z_ob[YNPROMPT].ob_width=gr_cw*len+8;
+       tmp=ob_get_text(z_ob,YNPROMPT,0);
+       ob_set_text(z_ob,YNPROMPT,mar_copy_of(query));
+
+       if(resp){       /* single inputs */
+               ob_hide(z_ob,SOMECHARS,FALSE);
+               ob_hide(z_ob,ANYCHAR,TRUE);
+
+               if(strchr(resp,'q')) send_yn_esc('q');
+               else if(strchr(resp,'n')) send_yn_esc('n');
+               else send_yn_esc(def);  /* strictly def should be returned, but in trad. I it's 0 */
+
+               if(strchr(resp,'#')){   /* count possible */
+                       ob_hide(z_ob,YNOK,FALSE);
+                       ob_hide(z_ob,COUNT,FALSE);
+               }else{  /* no count */
+                       ob_hide(z_ob,YNOK,TRUE);
+                       ob_hide(z_ob,COUNT,TRUE);
+               }
+
+               if((anzahl=(long)strchr(resp,'\033'))){
+                       anzahl-=(long)resp;
+               }else{
+                       anzahl=strlen(resp);
+               }
+               for(i=0,ptr=resp;i<2*anzahl;i+=2,ptr++){
+                       ob_hide(z_ob,YN1+i,FALSE);
+                       mar_change_button_char(z_ob,YN1+i,*ptr);
+                       ob_undoflag(z_ob,YN1+i,DEFAULT);
+                       if(*ptr==def)
+                               ob_doflag(z_ob,YN1+i,DEFAULT);
+               }
+
+               z_ob[SOMECHARS].ob_width=z_ob[YN1+i].ob_x+8;
+               z_ob[SOMECHARS].ob_height=z_ob[YN1+i].ob_y+gr_ch+gr_ch/2;
+               Max((int *)&z_ob[ROOT].ob_width,z_ob[SOMECHARS].ob_width+4*gr_cw);
+               z_ob[ROOT].ob_height=z_ob[SOMECHARS].ob_height+4*gr_ch;
+               if(strchr(resp,'#'))
+                       z_ob[ROOT].ob_height=z_ob[YNOK].ob_y+2*gr_ch;
+
+               for(i+=YN1;i<(YNN+1);i+=2){
+                       ob_hide(z_ob,i,TRUE);
+               }
+               Event_Handler(single_init,single_handler);
+       }else{  /* any input */
+               ob_hide(z_ob,SOMECHARS,TRUE);
+               ob_hide(z_ob,ANYCHAR,FALSE);
+               ob_hide(z_ob,YNOK,TRUE);
+               ob_hide(z_ob,COUNT,TRUE);
+               z_ob[ANYCHAR].ob_height=2*gr_ch;
+               z_ob[CHOSENCH].ob_y=
+               z_ob[CHOSENCH+1].ob_y=gr_ch/2;
+               z_ob[ROOT].ob_width=max(z_ob[YNPROMPT].ob_width+z_ob[YNPROMPT].ob_x,z_ob[ANYCHAR].ob_width+z_ob[ANYCHAR].ob_x)+2*gr_cw;
+               z_ob[ROOT].ob_height=z_ob[ANYCHAR].ob_height+z_ob[ANYCHAR].ob_y+gr_ch/2;
+               *ob_get_text(z_ob,CHOSENCH,0)='?';
+               Event_Handler(any_init,any_handler);
+       }
+
+       d_exit=xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, DIALOG_MODE);
+       Event_Timer(0,0,TRUE);
+       Event_Handler(NULL,NULL);
+       /* display of count is missing (through the core too) */
+
+       free(ob_get_text(z_ob,YNPROMPT,0));
+       ob_set_text(z_ob,YNPROMPT,tmp);
+
+       if(resp && (d_exit==W_CLOSED || d_exit==W_ABANDON))
+               return('\033');
+       if((d_exit&NO_CLICK)==YNOK){
+               yn_number=atol(ob_get_text(z_ob,COUNT,0));
+               return('#');
+       }
+       if(!resp)
+               return(*ob_get_text(z_ob,CHOSENCH,0));
+       return(*ob_get_text(z_ob,d_exit&NO_CLICK,0));
+}
+
+/*
+ * Allocate a copy of the given string.  If null, return a string of
+ * zero length.
+ *
+ * This is an exact duplicate of copy_of() in X11/winmenu.c.
+ */
+static char *
+mar_copy_of(s)
+    const char *s;
+{
+    if (!s) s = nullstr;
+    return strcpy((char *) m_alloc((unsigned) (strlen(s) + 1)), s);
+}
+
+const char *strRP="raw_print", *strRPB="raw_print_bold";
+
+void
+mar_raw_print(str)
+const char *str;
+{
+               xalert(1,FAIL,X_ICN_INFO,NULL,APPL_MODAL,BUTTONS_CENTERED,TRUE,strRP,str,NULL);
+}
+
+void
+mar_raw_print_bold(str)
+const char *str;
+{
+       char buf[BUFSZ];
+
+       sprintf(buf,"!%s",str);
+       xalert(1,FAIL,X_ICN_INFO,NULL,APPL_MODAL,BUTTONS_CENTERED,TRUE,strRPB,buf,NULL);
+}
+
+/*wingem1.c*/
diff --git a/win/gem/xpm2img.c b/win/gem/xpm2img.c
new file mode 100644 (file)
index 0000000..605d5db
--- /dev/null
@@ -0,0 +1,164 @@
+/*     SCCS Id: @(#)xpm2img.c  3.4     2002/03/17      */
+/*   Copyright (c) Christian Bressler 2002                 */
+/*   NetHack may be freely redistributed.  See license for details. */
+/* This is mainly a reworked tile2bmp.c + xpm2iff.c -- Marvin */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "bitmfile.h"
+#define TRUE 1
+#define FALSE 0
+void get_color(unsigned int colind, struct RGB *rgb);
+void get_pixel(int x, int y, unsigned int *colind);
+char *xpmgetline();
+unsigned int **Bild_daten;
+/* translation table from xpm characters to RGB and colormap slots */
+struct Ttable {
+       char flag;
+       struct RGB col;
+       int slot;       /* output colortable index */
+}ttable[256];
+struct RGB *ColorMap;
+int num_colors = 0;
+int width=0, height=0;
+int initflag;
+FILE *fp;
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       int i;
+       int row, col, planeno;
+       int farben, planes;
+       if (argc != 3) {
+               fprintf(stderr, "usage: tile2img infile.xpm outfile.img\n");
+               exit(EXIT_FAILURE);
+       }
+       initflag = 0;
+       fp = fopen(argv[2],"wb");
+       if (!fp) {
+           printf("Error creating IMG-file %s, aborting.\n",argv[2]);
+           exit(EXIT_FAILURE);
+       }
+       fclose(fp);
+       if(fopen_xpm_file(argv[1],"r")!=TRUE){
+           printf("Error reading xpm-file %s, aborting.\n",argv[1]);
+           exit(EXIT_FAILURE);
+       }
+       Bild_daten=(unsigned int **)malloc((long)height*sizeof(unsigned int *));
+       for(i=0;i<height;i++)
+               Bild_daten[i]=(unsigned int *)malloc((long)width*sizeof(unsigned int));
+       for(row = 0;row<height;row++){
+               char *xb = xpmgetline();
+               int plane_offset;
+               if(xb==0){
+                       printf("Error to few lines in xpm-file %s, aborting.\n",argv[1]);
+                       exit(EXIT_FAILURE);
+               }
+               for(col = 0;col<width;col++){
+                       int color = xb[col];
+                       if(!ttable[color].flag)
+                               fprintf(stderr, "Bad image data\n");
+                       Bild_daten[row][col]= ttable[color].slot;
+               }
+       }
+       if(num_colors>256){
+               fprintf(stderr,"ERROR: zuviele Farben\n");
+               exit(EXIT_FAILURE);
+       }else if(num_colors>16){
+               farben=256;
+               planes=8;
+       }else if(num_colors>2){
+               farben=16;
+               planes=4;
+       }else{
+               farben=2;
+               planes=1;
+       }
+       bitmap_to_file(XIMG, width, height, 372, 372, planes, farben, argv[2], get_color, get_pixel );
+       exit(EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
+void get_color(unsigned int colind, struct RGB *rgb){
+       rgb->r=(1000L*(long)ColorMap[colind].r)/0xFF;
+       rgb->g=(1000L*(long)ColorMap[colind].g)/0xFF;
+       rgb->b=(1000L*(long)ColorMap[colind].b)/0xFF;
+}
+void get_pixel(int x, int y, unsigned int *colind){
+       *colind=Bild_daten[y][x];
+}
+FILE *xpmfh = 0;
+char initbuf[200];
+char *xpmbuf = initbuf;
+/* version 1.  Reads the raw xpm file, NOT the compiled version.  This is
+ * not a particularly good idea but I don't have time to do the right thing
+ * at this point, even if I was absolutely sure what that was. */
+fopen_xpm_file(const char *fn, const char *mode){
+       int temp;
+       char *xb;
+       if(strcmp(mode, "r"))return FALSE;      /* no choice now */
+       if(xpmfh)return FALSE;                  /* one file at a time */
+       xpmfh = fopen(fn, mode);
+       if(!xpmfh)return FALSE;                 /* I'm hard to please */
+               /* read the header */
+       xb = xpmgetline();
+       if(xb == 0)return FALSE;
+       if(4 != sscanf(xb,"%d %d %d %d",
+               &width, &height,&num_colors, &temp))
+                       return FALSE;   /* bad header */
+               /* replace the original buffer with one big enough for
+                * the real data
+                */
+/* XXX */
+       xpmbuf = malloc(width * 2);
+       if(!xpmbuf){
+               fprintf(stderr,"ERROR: Can't allocate line buffer\n");
+               exit(1);
+       }
+       if(temp != 1)return FALSE;              /* limitation of this code */
+       {
+               /* read the colormap and translation table */
+               int ccount = -1;
+               ColorMap = (struct RGB *)malloc((long)num_colors*sizeof(struct RGB));
+               while(ccount++ < (num_colors-1)){
+                       char index;
+                       int r, g, b;
+                       xb = xpmgetline();
+                       if(xb==0)return FALSE;
+                       if(4 != sscanf(xb,"%c c #%2x%2x%2x",&index,&r,&g,&b)){
+                           fprintf(stderr,"Bad color entry: %s\n",xb);
+                           return FALSE;
+                       }
+                       ttable[index].flag = 1; /* this color is valid */
+                       ttable[index].col.r = r;
+                       ttable[index].col.g = g;
+                       ttable[index].col.b = b;
+                       ttable[index].slot = ccount;
+                       ColorMap[ccount].r=r;
+                       ColorMap[ccount].g=g;
+                       ColorMap[ccount].b=b;
+               }
+       }
+       return TRUE;
+}
+/* This deserves better.  Don't read it too closely - you'll get ill. */
+#define bufsz 2048
+char buf[bufsz];
+char *
+xpmgetline(){
+       char *bp;
+       do {
+           if(fgets(buf, bufsz, xpmfh) == 0)return 0;
+       } while(buf[0] != '"');
+               /* strip off the trailing <",> if any */
+       for(bp = buf;*bp;bp++);
+       bp--;
+       while(isspace(*bp))bp--;
+       if(*bp==',')bp--;
+       if(*bp=='"')bp--;
+       bp++;
+       *bp = '\0';
+       return &buf[1];
+}
diff --git a/win/gnome/README b/win/gnome/README
new file mode 100644 (file)
index 0000000..3f7ec20
--- /dev/null
@@ -0,0 +1,53 @@
+This directory contains the windowing code written for GnomeHack. The NetHack
+devteam is in the process of making it part of the normal distribution.  
+It should be noted that this is still work in progress and that there are
+still problems with this code.  So use at your own risk.  Of course any
+contributions, especially bug fixes, are more than welcome!
+
+These files are based on the files from GnomeHack 1.0.5 by Erik Andersen.
+Some files have been renamed to fit into 8.3 name constraints (yuk!).
+These are:
+
+       GnomeHack.h                     gnomeprv.h
+       GnomeHackAskStringDialog.c      gnaskstr.c
+       GnomeHackAskStringDialog.h      gnaskstr.h
+       GnomeHackBind.c                 gnbind.c
+       GnomeHackBind.h                 gnbind.h
+       GnomeHackGlyph.c                gnglyph.c
+       GnomeHackGlyph.h                gnglyph.h
+       GnomeHackMainWindow.c           gnmain.c
+       GnomeHackMainWindow.h           gnmain.h
+       GnomeHackMapWindow.c            gnmap.c
+       GnomeHackMapWindow.h            gnmap.h
+       GnomeHackMenuWindow.c           gnmenu.c
+       GnomeHackMenuWindow.h           gnmenu.h
+       GnomeHackMessageWindow.c        gnmesg.c
+       GnomeHackMessageWindow.h        gnmesg.h
+       GnomeHackPlayerSelDialog.c      gnplayer.c
+       GnomeHackPlayerSelDialog.h      gnplayer.h
+       GnomeHackSettings.c             gnopts.c
+       GnomeHackSettings.h             gnopts.h
+       GnomeHackSignals.c              gnsignal.c
+       GnomeHackSignals.h              gnsignal.h
+       GnomeHackStatusWindow.c         gnstatus.c
+       GnomeHackStatusWindow.h         gnstatus.h
+       GnomeHackTextWindow.c           gntext.c
+       GnomeHackTextWindow.h           gntext.h
+       GnomeHackYesNoDialog.c          gnyesno.c
+       GnomeHackYesNoDialog.h          gnyesno.h
+
+Other files have been removed because we don't or can't use them (yet).
+
+       Makefile.am
+       Makefile.in
+       gnomehack.desktop
+       gnomehack.desktop.in
+
+NetHack currently doesn't use autoconf, so the setup for that has not
+made the translation.
+
+Note:  All loss in style, elegance, and readability is entirely our fault
+and not Erik's.
+
+
+
diff --git a/win/gnome/gn_xpms.h b/win/gnome/gn_xpms.h
new file mode 100644 (file)
index 0000000..28408a0
--- /dev/null
@@ -0,0 +1,1450 @@
+/*     SCCS Id: @(#)gnxpms.h   3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+/* These XPMs are the artwork of Warwick Allison
+ * <warwick@troll.no>.  They have been borrowed from 
+ * the most excellent NetHackQt, until such time as
+ * we can come up with something better.
+ *
+ * More information about NetHackQt can be had from:
+ * http://www.troll.no/~warwick/nethack/
+ */
+
+/* XPM */
+static char *blind_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 5 1",
+/* colors */
+"  c #000000",
+". c None",
+"X c #909090",
+"o c #606060",
+"O c #303030",
+/* pixels */
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"....ooooooooooooooooooooooooooooooooX...",
+"....                                o...",
+"....                                o...",
+"....                                o...",
+"....                                o...",
+"......o            ..o            ......",
+"......X           O..X           O......",
+".......           o...           o......",
+".......o          ....o          .......",
+"........O        X.....O        X.......",
+".........O      X.......O      X........",
+"..........o   OX.........o   OX.........",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................"
+};
+/* XPM */
+static char *cha_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 14 1",
+/* colors */
+"  c #F85848",
+". c #949E9E",
+"X c #F8B090",
+"o c #E00028",
+"O c #D4D4D4",
+"+ c None",
+"@ c #B0B0B0",
+"# c #F82C24",
+"$ c #F89E6C",
+"% c #FF0000",
+"& c #909090",
+"* c #FFFFFF",
+"= c #CEAA90",
+"- c #DADAB6",
+/* pixels */
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"+++++++++++++++=#%#=+=#%% ++++++++++++++",
+"++++++++++++++ %O%%%#%$$%o%=++++++++++++",
+"+++++++++++++# +#%%o%%o%%%%% +++++++++++",
+"+++++++++++ %%%%%%%%%%%%%%%%o#=+++++++++",
+"+++++++++ o%%%%%%%%%%%%%%%%%%%%# +++++++",
+"++++++ #%%%%%%o%%%o%%o%%o%o%%%%%o%o  +++",
+"++=#%%o%%%#= =*+**O*+**O*+- = =%%%%#@+++",
+"++++ %=++*+*+**O****O****O*O*O*OO%=+++++",
+"+++++.%=OO+*O*OO****+****+*O*+O&%=@+++++",
+"++++++=%=*OO+**O**O*O**O*O*OO+$%=+++++++",
+"+++++++#% +*OOOO****+****@O+*#%=++++++++",
+"++++++++#%#*+**+O+OO+O+OOO*O#o#+++++++++",
+"+++++++++o% O**+****O****O*#%%=+++++++++",
+"+++++++++ %%#O*O****+****+ %o#++++++++++",
+"++++++++++o%% XO*O**O*O**#%%%+++++++++++",
+"++++++++++ %%%o%$-**+**$%%%%=+++++++++++",
+"+++++++++++o%%$X$%%%%%%#= o#++++++++++++",
+"++++++++++@ %%%o#O$$+$$$%%%=++++++++++++",
+"++++++++++++#o%%%%%%%%o%%%=@++++++++++++",
+"+++++++++++++ %%%%%%%%%%o=++++++++++++++",
+"+++++++++++++++= &  &  @++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++"
+};
+/* XPM */
+static char *chaotic_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 9 1",
+/* colors */
+"  c #000000",
+". c #5C7A7A",
+"X c None",
+"o c #B0B0B0",
+"O c #909090",
+"+ c #788C8C",
+"@ c #606060",
+"# c #FFFFFF",
+"$ c #303030",
+/* pixels */
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXXX@$     @XXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXX$$+#X$    $XXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXX@$#o        @XXXXXXXXX",
+"XXXXXXXXXXXXXXXXXX$XX          OXXXXXXXX",
+"XXXXXXXXXXXXXXXXX@ #   $@$     $XXXXXXXX",
+"XXXXXXXXXXXXXXXXX@.+  $XXXO     @XXXXXXX",
+"XXXXXXXXXXXXXXXXX O@  XXXXX@    @XXXXXXX",
+"XXXXXXXXXXXXXXXXX @O $XXXXX@$   @XXXXXXX",
+"XXXXXXXXXXXXXXXXX O+ @XXXXO++   @XXXXXXX",
+"XXXXXXXXXXXXXXXXX @+ $@OXO$#$   XXXXXXXX",
+"XXXXXXXXXXXXXXXXX O@  $ @$Xo   $XXXXXXXX",
+"XXXXXXXXXXXXXXXXX +O  $X##+   $XXXXXXXXX",
+"XXXXXXXXXXXXXXXXX +@         $XXXXXXXXXX",
+"XXXXXXXXXXXXXXXXX oO        $XXXXXXXXXXX",
+"XXXXXXXXO@@@@@   +#        $XXXXXXXXXXXX",
+"XXXXXXO +o########$          $@XXXXXXXXX",
+"XXXXXX                     +#+.$XXXXXXXX",
+"XXXXXX                       @O @XXXXXXX",
+"XXXXXX$        $@    $@@$       @XXXXXXX",
+"XXXXXXX@@@@XXXXXX +  @XXXX@$    OXXXXXXX",
+"XXXXXXXXXXXXXXXX@ #  @XXXXXXX@@OXXXXXXXX",
+"XXXXXXXXXXXXXXXX@.+  @XXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXX$O@  XXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXX @O  XXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXX #$ @XXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXX #  @XXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXX #  @XXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX@ #  @XXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX@ #  OXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX@.X  XXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX ++  XXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX @+  XXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX O@ @XXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX +O @XXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX    @XXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXX$   OXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXX@@OXXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+};
+/* XPM */
+static char *cns_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 19 1",
+/* colors */
+"  c #000000",
+". c #F85848",
+"X c #949E9E",
+"o c #F8B090",
+"O c #E00028",
+"+ c #7C3400",
+"@ c None",
+"# c #B0B0B0",
+"$ c #F82C24",
+"% c #F89E6C",
+"& c #FF0000",
+"* c #B64700",
+"= c #909090",
+"- c #788C8C",
+"; c #606060",
+": c #C80050",
+"> c #CEAA90",
+", c #303030",
+"< c #FFB691",
+/* pixels */
+"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@.oo.o$ ;@@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@>.o.%%O,@@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@$oo.o. ,@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@.oo$oo+ =@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@..o&oo$ ,@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@#.o.oo.  =@.$%@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@.o..oo& O.%ooo@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@.o.&%o.$oo%O++;@@@@@@@@@@@@",
+"@@@@@@@@@@@@@.o.+$%$o<O+   ,@@@@@@@@@@@@",
+"@@@@@@@@@@@@@.oo+ $o%O   ;@>.@@@@@@@@@@@",
+"@@@@@@@@@@@@@.oo++o%$$ ,@@$.oo@@@@@@@@@@",
+"@@@@@@@@@@@@>.oo+Oo$o%.@@$oo..-@@@@@@@@@",
+"@@@@@@@@@@@@..o%;.o&%.$..o%O ++>@@@@@@@@",
+"@@@@@@@@@@@@>.$O:%o.O::::O* $oooo@@@@@@@",
+"@@@@@@@@@@@@::::::$$:OO&OO::oo%.;=@@@@@@",
+"@@@@@@@@@@@.::::::::O&&&&&O::++  ,@@@@@@",
+"@@@@@@@@@@>:::O&&OO&&&&&&&&::     ;@@@@@",
+"@@@@@@@@@@=::O&&&&&O:O&&&&&O:  ,=@@@@@@@",
+"@@@@@@@@@@:::&&&&&&&&:&&&&&O:  ;@@@@@@@@",
+"@@@@@@@@@@::O&&&&&&&&:&O&&&O:, ;@@@@@@@@",
+"@@@@@@@@@@::O&&&&O&O&OO&O&&O:+ ;@@@@@@@@",
+"@@@@@@@@@@::&&&O&&&&&O:&&&&O:,  @@@@@@@@",
+"@@@@@@@@@@::O&&&&&O&&&:O&O&::+  @@@@@@@@",
+"@@@@@@@@@@::O&&O&&&&O&OO&&&::   @@@@@@@@",
+"@@@@@@@@@@=::O&&&&O&&&O:&&&::   @@@@@@@@",
+"@@@@@@@@@@.:::O&&O&&&&&:&OO::   @@@@@@@@",
+"@@@@@@@@@@@:::::&&&&O&O:&&O:,   @@@@@@@@",
+"@@@@@@@@@@.>:::::O&&&&&:&&::+  ;@@@@@@@@",
+"@@@@@@@@@@>.<::::O&&O&O:&&::   @@@@@@@@@",
+"@@@@@@@@@@@.o%,:::O&&&O:&O:,   @@@@@@@@@",
+"@@@@@@@@@@@$o.  :::OO&OO&::,  ;@@@@@@@@@",
+"@@@@@@@@@@@&o%+ ,::O&OO&O::   =@@@@@@@@@",
+"@@@@@@@@@@@.oo+   :::OO:::   ,@@@@@@@@@@",
+"@@@@@@@@@@@..oO    +:::::    =@@@@@@@@@@",
+"@@@@@@@@@@@@.<.+      ,+,   ,@@@@@@@@@@@",
+"@@@@@@@@@@@@Oo<+  @X,      ,@@@@@@@@@@@@",
+"@@@@@@@@@@@@.%o$  @@@@@;, ;@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@.o., =@@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+};
+/* XPM */
+static char *confused_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #303030",
+"= c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOO.=.+OO=.+O.OO+O+OO.+OOOOOO",
+"OOOOOOOOOOO++=====O=====+=O+==++=O+OOOOO",
+"OOOOOOOOOOO+=.=====.=++++===OO==+O=+OOOO",
+"OOOOOOOOOOO=+===.+=o==o===+&OoO======OOO",
+"OOOOOOOO+O+====OO+=o&&&&Oo==o&oO+==+=.O.",
+"OOOO+.+=+O==+&&o=oooOo&o&ooo=&oooO==O=+=",
+"OOOOOOOO++O===oo=oo&=&o&&oo=o==&o+==++==",
+"OOOOOOOO=o.=O====o&OO&o&oo&o&&oo=======O",
+"OOOOOOOo===+=O=O=ooO=ooooOOo=o&O=====OOO",
+"OOOOOOOOO+==+=======O=oo====O=o=O===+OOO",
+"OOOOOOOOO.=#=X=+====O========O======OOOO",
+"OOOOOOO.#Xo++.=#%====O==========OO==+OOO",
+"OOOOOO+Xo#+#+.#=.==X====+====O=+=+==+OOO",
+"OOOOO.+.+O===##.#=X.====oX##===o+OO.OOOO",
+"OOOOO#+####O#O##o.#+==#X#O#+...=OOo=+OOO",
+"OOOO++#o+#+X++++#.#O.#+#X.#+X+==+OO=oOOO",
+"OOOO#+.+..X+.##X++#++#..+XX#+##+..OOOOOO",
+"OOOO##....O+#++#+.++#+X+#+#X..+#+#OOOOOO",
+"OOOO++#+.+.#+#O+X#X#XX#.++##.#++.X$OOOOO",
+"OOOOO#+#+.+++#++.+++##+X###+X+X##+**OOOO",
+"OOOOO#..#OO#+.##o###.+..++.+#X+#+#* @OOO",
+"OOOOO+#.#O+#+#O.+++.###+##++###+.#* $OOO",
+"OOOOOOXX+#+#+#o..X##++#+..##.#+###  *OOO",
+"OOOOOOOX#.#X+#+#+#+.#+..+####%XX%%   OOO",
+"OOOOOOOO.%%X.#+#+#.++#+#+#+.X++=.%  *OOO",
+"OOOOOOOOO.* *##+#+.O####.+XX%%%%#%  $OOO",
+"OOOOOOOOOOO.   %X.+.#+++XXX=.+++#X  $OOO",
+"OOOOOOOOOOOO.*   %%X..#X%=.####%X*  $OOO",
+"OOOOOOOOOOOOOO.$ *XX%%%=.#X%###=*   OOOO",
+"OOOOOOOOOOOOOOOOOO+%%%=%%#.+.#=*   @OOOO",
+"OOOOOOOOOOOOOOOOOOo=%%%==X##X%*    OOOOO",
+"OOOOOOOOOOOOOOOOOOO+X%%%%X=%*     @OOOOO",
+"OOOOOOOOOOOOOOOOOOOOX%%%%X      *@OOOOOO",
+"OOOOOOOOOOOOOOOOOOOO=%%%X*   *$$OOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOO+X%%=  .OOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOX%%%  OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOO=%%* $OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOO=%%% $OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOO+%%% $OOOOOOOOOOOOO"
+};
+/* XPM */
+static char *dex_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 19 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #F8B090",
+"o c #5C7A7A",
+"O c #D4D4D4",
+"+ c #F87A24",
+"@ c #7C3400",
+"# c None",
+"$ c #B0B0B0",
+"% c #F89E6C",
+"& c #B64700",
+"* c #909090",
+"= c #606060",
+"- c #CEAA90",
+"; c #DADAB6",
+": c #303030",
+"> c #F86800",
+", c #FFB691",
+"< c #F88C48",
+/* pixels */
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"###############-%-######################",
+"##############-%X<-#####################",
+"#########-<<-#-%XX+==###################",
+"#########%,X< :<,X%@ :##################",
+"#########-XX%: @;X%+  *#################",
+"##########<,X& :<<%+: :#################",
+"######->+#-%%%: <,XX@  #################",
+"######%X%@ <,,& @XXX+  :++-#############",
+"######-<X+ &,X%:@+<+>:  <X&o############",
+"######$<X<@:<<%& <,XX@ @X,@ =###########",
+"#######-+%< &,,%:&,XX+ @,X+ :###########",
+"####<<-o&,X@:X,,&@,XX< @,X%& :##########",
+"####<X%::%%< &,,X:<%X%@:%XX%@ =#########",
+"####%%X& <X,&@%<%<%<<%& >+XX+  #########",
+"#####+%%@@,X%<,XXXXXXX<:@XXX<: =########",
+"####$%XX< <,<XXXXXXXXXX&@,XXX@ :########",
+"######+X<&@%%XXX%XXXX%<<><,XX&  ########",
+"#####$%<%X@%XXXX<X%XXXX<><%XX<  =#######",
+"#######<;X%XXXXX<<<XXX<XX<,XX%@ =#######",
+"#######-%+XXXXX%+XXXXXXXX%<,XX@ =#######",
+"########<XXXXXX+XX%XXXXXXXX%XX@ =#######",
+"########-%XXX%+%XX<XXXXXXXX%XX@  #######",
+"#########+,XX+XXXX<,XXXXXXXXXX@  #######",
+"#########-<X+%XXXX%,XXXXXXXXXX@  #######",
+"##########>,XXXXXX%,XXXXXXXXX%@  #######",
+"##########-<XXXXXX<,XXXXXXXXX<   #######",
+"###########%%XXXXXX%,,XXXXXXX+   #######",
+"############+,XXXXXX<;,,XXXXX@   #######",
+"############-+,XXXXXX%%%,XXX%@   #######",
+"#############%%XXXXXXXX%<XXXX+  =#######",
+"#############$%<XXXXXXXXXXXXX<: =#######",
+"##############$-<<XXXXXXXXXXXX&  #######",
+"################.&,XXXXXXXXXXX<: =######",
+"#################O######################"
+};
+/* XPM */
+static char *ext_enc_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #303030",
+"= c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO",
+"OOOOOOOOOOO&&&&&&&&&&&&&&&.OOOOOOOOOOOOO",
+"OOOOOOOOOOOo==============X*OOOOOOOOOOOO",
+"OOOOOOOOOOoO===X====X=====X**OOOOOOOOOOO",
+"OOOOOOOOOO&============X===% $OOOOOOOOOO",
+"OOOOOOOOOoo======X=========%* OOOOOOOOOO",
+"OOOOOOOOOoO===X============X* @OOOOOOOOO",
+"OOOOOOOOO&=========X===%%===% $OOOOOOOOO",
+"OOOOOOOOoo===     ===%   *==X  OOOOOOOOO",
+"OOOOOOOOoO==* %*%*=== *%* *=X* @OOOOOOOO",
+"OOOOOOOO&=== %======% ===% ==% $OOOOOOOO",
+"OOOOOOOoo==* ======= *===% X=%* OOOOOOOO",
+"OOOOOOOoO==%    *%== *==== %=X* @OOOOOOO",
+"OOOOOOO&===%%*%*  == %==== *==% $OOOOOOO",
+"OOOOOOoo========% %=* ===X X==X  OOOOOOO",
+"OOOOOOoO===*====* *=% ===* ===X* @OOOOOO",
+"OOOOOO&===*  %*%  X== **% %====% $OOOOOO",
+"OOOOOoo===%%    *X===%   *=====%* OOOOOO",
+"OOOOOo+========================X* @OOOOO",
+"OOOOOo=========================%* $OOOOO",
+"OOOOOO=XXX%X%XXXXX%X%XXXX%X%X%X%*  OOOOO",
+"OOOOOO.=************************   OOOOO",
+"OOOOOOOO                           OOOOO",
+"OOOOOOOO.                         @OOOOO",
+"OOOOOOOOOOoOOoOOoOOoOoOoOOoOoOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static char *hallu_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 30 1",
+/* colors */
+"  c #F85848",
+". c #5C7A7A",
+"X c #009100",
+"o c #6CFF00",
+"O c #E00028",
+"+ c #D4D4D4",
+"@ c #FF6C00",
+"# c #F87A24",
+"$ c None",
+"% c #B0B0B0",
+"& c #F82C24",
+"* c #F89E6C",
+"= c #FF00FF",
+"- c #FF0000",
+"; c #B64700",
+": c #909090",
+"> c #788C8C",
+", c #606060",
+"< c #406868",
+"1 c #C80050",
+"2 c #FFFFFF",
+"3 c #FFFF00",
+"4 c #00B6FF",
+"5 c #CEAA90",
+"6 c #DADAB6",
+"7 c #F86800",
+"8 c #FFB691",
+"9 c #6C91B6",
+"0 c #F88C48",
+"q c #0000FF",
+/* pixels */
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$353333335*$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$*33333333#7@3335$$$$$$$$$$$$",
+"$$$$$$$$$65333333333@7777#333*$$$$$$$$$$",
+"$$$$$$$$$3333333333377777733333===%$$$$$",
+"$$$$$$$533333333333#7777777333%=====$$$$",
+"$$$$$$ #3333333333o>7777773330======%$$$",
+"$$$$5---O#33333o3944077777333*=======$$$",
+"$$$$-----O333333>4444.77333330======%$$$",
+"$$$ ---O--;3333344444443333333:====5$$$$",
+"$$$ O-----733333444444433333333 ==035$$$",
+"$$$3--O--O333333>44444>33333333333333$$$",
+"$$533---O33333333944493333#333333333356$",
+"$$33867733333o33333:o333333o3333333333$$",
+"$532+2233333#333333333333oooo3#3333333%$",
+"6522222+33333333333333333oooooo33o3333*$",
+"$+22+22263333333o3333333ooooooo333333356",
+"662222+2533333333333333#ooooooo33333333$",
+"$32+22223333o3#33333o333ooooooo3#333333%",
+"$33222233333333333#333333ooooo333333333$",
+"$33368333333333333330626*oooo#333333o33%",
+"%333335== 33oo333333222223#333333333333$",
+"$3333=====:ooooo333+22+2263333333.>o333%",
+"$5333=====oooooo33322222223333339444935$",
+"$*33 ====>ooooooo3362+222633333.44444>3$",
+"$%330====:ooooooo333222+23333334444444$$",
+"$$333177 =oooXoo#333*626333333;4444444$$",
+"$$53##777&3oooo3333333333333#--,444449$$",
+"$$$3;77777#3o333333333333333O---94449$$$",
+"$$%*@77777#33333333333333337O----O:o3$$$",
+"$$$5777777333  333333333333;---O-O73$$$$",
+"$$$$#7777730====#:.,33333333------3$$$$$",
+"$$$$$577333=====qqqq<0333333#O---35$$$$$",
+"$$$$$%53335====qqqqqq.33o333337735$$$$$$",
+"$$$$$$$533 ====qqqqqqq3333333333%$$$$$$$",
+"$$$$$$$$%33====qqqqqqq333333333%$$$$$$$$",
+"$$$$$$$$$$50===qqqqqq,3333333:$$$$$$$$$$",
+"$$$$$$$$$%6%5503,qqq<333#335%$$$$$$$$$$$",
+"$$$$$$$$$$$$$%$*53,03335o$%%$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$%$$+$$$$$$$$$$$$$$$"
+};
+/* XPM */
+static char *hungry_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 15 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #CEAA90",
+"= c #DADAB6",
+"- c #303030",
+"; c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO========OOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOO=============OOOOOOOOOOOOO",
+"OO;XX;@OOOOO================OOOOOOOO;XOO",
+"OO;%-;$OOOO==================OOOOOOO;XOO",
+"OO;-%;$OOO========@$#@========OOOOO+;;$O",
+"OO;%-;$OO=======-     -*======*OOOO.;;$O",
+"OO;-%;$O======*  @====.$$&=====@OOO.;;$O",
+"OO;X%;$O====== -========*@=====*.OO+;;$O",
+"OO;;;X$o====* -==========@======$OO;;;$O",
+"OO+;;-+o====- =============o====#@O+;;$O",
+"OOO;%$O===== @=============&====*$O;;;$O",
+"OOO+%OO====@ ==============&=====-OO;;$O",
+"OOo;-Oo====$ ==============o&==== OO;;$O",
+"OOO+%OO====@ ==============&===== O+;;#O",
+"OOO;-Oo====$-==============&&==== O+;;-O",
+"OOO;;+O=====$*============&&====* OO;;%+",
+"OOO;;$o=====$.============&&====X-OO;;$O",
+"OOO;;$O======*.===&======&&=====-$=O;;$O",
+"OOO;;$Oo=====.==========&&=====* @O+;;$O",
+"OOO;;$OO=======oo=====&&&======$-OOO;;$O",
+"OOO;;$OOo=======&o&&&&&&======$ @OOO;;$O",
+"OOO;;$OOOO========&=&========* $OOOO;;$O",
+"OO+;;$OOOOo=================* -OOOOO#;$O",
+"OOO;;$OOOOO=*==============@ -=OOOOO;;$O",
+"OOO;;$OOOOOOO+*==========*- $OOOOOOO;;$O",
+"OOOX-$OOOOOOOO@X@*====*#- -.OOOOOOOOX-$O",
+"OOOOOOOOOOOOOO=*@$-    -$.=OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOO=O==O=O=OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static char *hvy_enc_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #303030",
+"= c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO",
+"OOOOOOOOOOO&&&&&&&&&&&&&&&.OOOOOOOOOOOOO",
+"OOOOOOOOOOOo==============X*OOOOOOOOOOOO",
+"OOOOOOOOOOoO===X====X=====X**OOOOOOOOOOO",
+"OOOOOOOOOO&============X===% $OOOOOOOOOO",
+"OOOOOOOOOoo===*%====***%===%* OOOOOOOOOO",
+"OOOOOOOOOoO==% %===*    %==X* @OOOOOOOOO",
+"OOOOOOOOO&===% *==% X==**===% $OOOOOOOOO",
+"OOOOOOOOoo===% %==% ===% ===X  OOOOOOOOO",
+"OOOOOOOOoO==== *== *==== *==X* @OOOOOOOO",
+"OOOOOOOO&===== %== %==== %===% $OOOOOOOO",
+"OOOOOOOoo===== *== *==== *===%* OOOOOOOO",
+"OOOOOOOoO===== %==% ===* ====X* @OOOOOOO",
+"OOOOOOO&===X== *==% X==**=====% $OOOOOOO",
+"OOOOOOoo=====   *==*    %=====X  OOOOOOO",
+"OOOOOOoO=====*%%X===*%*X======%* @OOOOOO",
+"OOOOOOo====================X===* $OOOOOO",
+"OOOOOOO=%X%XXXX%XXXXXXXXX%X=%X%   OOOOOO",
+"OOOOOOO.=**********************   OOOOOO",
+"OOOOOOOOO                         OOOOOO",
+"OOOOOOOOO.                       @OOOOOO",
+"OOOOOOOOOOOoOOoOoOoOoOoOoOOoOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static char *int_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 12 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #303030",
+"* c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOO+#.X.##@#OOOOOOOOOOOOOOOOOO",
+"OOOOOOOO+##@X#O++.#+#.##OOOOOOOOOOOOOOOO",
+"OOOOOO+#Xo++#X#%#+##o#O#.#+OOOOOOOOOOOOO",
+"OOOOO.Xo#+#++##+.XX#..+.+..XOOOOOOOOOOOO",
+"OOOO++.+O.+O##+#.X###..OX#.+X+OOOOOOOOOO",
+"OOOO#+####O#O##o##+###X#+#+.#..OOOOOOOOO",
+"OOO.+#o+#+X++++#.#O+#+#X.#+X++X+OOOOOOOO",
+"OOO.+.+..X+.##X++#++#..+XX#+#X+..OOOOOOO",
+"OOO##....O+#++#+.++#+X+#+#X..+#+#OOOOOOO",
+"OOO++#+.+.#+#O+X#X#XX#.++##.#++.X$OOOOOO",
+"OOOO#+#+.+++#++.+++##+X###+X+X##+&&OOOOO",
+"OOOO#..#OO#+.##o###.+..++.+#X+#+#& @OOOO",
+"OOOO.#.#O+#+#O.+++.###+##++###+.#  $OOOO",
+"OOOOOXX+#+#+#o..X##++#+..##.#+###  &OOOO",
+"OOOOOOX#.#X+#+#+#+.#+..+####XX%X%   OOOO",
+"OOOOOOO.%%X.#+#+#.++#+#+#+.%++*+%  &OOOO",
+"OOOOOOOO@& &##+#+.O####.+XXX%%%#%  $OOOO",
+"OOOOOOOOOO.   %X.+.#+++XXX*.+++#%  $OOOO",
+"OOOOOOOOOOO@&   %%X..#XXX.####%%&  $OOOO",
+"OOOOOOOOOOOOO@$ &XX%%%*.#X%###*&   OOOOO",
+"OOOOOOOOOOOOOOOOO+%%%*%%#.+.#*&   @OOOOO",
+"OOOOOOOOOOOOOOOOOO*%%%*.X##XX&    OOOOOO",
+"OOOOOOOOOOOOOOOOOOOX%%%%X*%&     @OOOOOO",
+"OOOOOOOOOOOOOOOOOOOX%%%%%      &@OOOOOOO",
+"OOOOOOOOOOOOOOOOOOO*%%%X&   &$$OOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOO+%%%*  .OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOO+*%%%  OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOO*%%& $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOO+%%& $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOoOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static char *lawful_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 10 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #606060",
+"$ c #FFFFFF",
+"% c #303030",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOo$$$$$$oOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOO$$o$$o$$$$$OOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOo$$$$$$$o$$ooOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO$o$$$o$$$$$$$oOOOOOOOO",
+"OOOOOOOOOOOOOOOOOo$$$$+ .o$$$$$oOOOOOOOO",
+"OOOOOOOOOOOOOOOOOo$$$+%OOOO$o$$$oOOOOOOO",
+"OOOOOOOOOOOOOOOOO$$o$X@OOOOo$$$ooOOOOOOO",
+"OOOOOOOOOOOOOOOOO$$$$%OOOOOo$$$..OOOOOOO",
+"OOOOOOOOOOOOOOOOO$$$$@OOOOo$$oo##OOOOOOO",
+"OOOOOOOOOOOOOOOO+$$o$$ooOoo$$$o OOOOOOOO",
+"OOOOOOOOOOOOOOOOO$$$$$$$o$$$$o#%OOOOOOOO",
+"OOOOOOOOOOOOOOOO+$$o$$o$$$$$o@%OOOOOOOOO",
+"OOOOOOOOOOOOOOOOO$$$$$$$$o$o.%OOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOo$$$o$$oo@#%OOOOOOOOOOO",
+"OOOOOOOOoooooo$$$$$$$$$$$% %OOOOOOOOOOOO",
+"OOOOOOO$$$$$$$$$$$$o$$o$$$$$$$oOOOOOOOOO",
+"OOOOOO$$$$$$$$$o$$$$$$$$$$$$o$$oOOOOOOOO",
+"OOOOOO$$o$ooooo##+o$$+##@oo$$$$$oOOOOOOO",
+"OOOOOOo$$#%    %#$$$+%##%%#ooo$O#OOOOOOO",
+"OOOOOOOo@##OOOOO+$$$##OOOO#%%##%@OOOOOOO",
+"OOOOOOOOOOOOOOOOo$$$##OOOOOOO##@OOOOOOOO",
+"OOOOOOOOOOOOOOOOo$$o##OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO$$oo OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO+$$$o OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO$o$##OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo$$$##OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo$$o%@OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo$$o OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO$$oo OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO$$$o OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo$$##OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO$$o##OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo$# @OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO.#@OOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static char *mod_enc_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #303030",
+"= c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOo&&&&&&&&&oXOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOO+&=========X%@OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOO&=====X====% @OOOOOOOOOOOOO",
+"OOOOOOOOOOOOoO==X=======X* OOOOOOOOOOOOO",
+"OOOOOOOOOOOO&====*%*%*===* $OOOOOOOOOOOO",
+"OOOOOOOOOOO+&===X     ===% *OOOOOOOOOOOO",
+"OOOOOOOOOOOoO===**=======X* OOOOOOOOOOOO",
+"OOOOOOOOOOO&===% %=======X% $OOOOOOOOOOO",
+"OOOOOOOOOOO&===% %*%%=====% *OOOOOOOOOOO",
+"OOOOOOOOOOoO===*      ====X* OOOOOOOOOOO",
+"OOOOOOOOOO&=========* X===X% $OOOOOOOOOO",
+"OOOOOOOOO+&=========% *====% *OOOOOOOOOO",
+"OOOOOOOOOoO===% %===  %====%* OOOOOOOOOO",
+"OOOOOOOOO&====*      *==X===% $OOOOOOOOO",
+"OOOOOOOOO&======*%*%X=======% *OOOOOOOOO",
+"OOOOOOOOOo==X===============%  OOOOOOOOO",
+"OOOOOOOOO=XXXXXXXXXX%X%X%X%%%  $OOOOOOOO",
+"OOOOOOOOOO=%****************   $OOOOOOOO",
+"OOOOOOOOOOO$                   $OOOOOOOO",
+"OOOOOOOOOOOO*                 *OOOOOOOOO",
+"OOOOOOOOOOOOOoOOoOoOoOoOoOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static char *neutral_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 14 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #00B6FF",
+"= c #303030",
+"- c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOO.------.OOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOO-+O&o.-----OOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO+-&o--------.OOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO-oo----------+OOOOOOOO",
+"OOOOOOOOOOOOOOOOO+-&--% #-------OOOOOOOO",
+"OOOOOOOOOOOOOOOOO-OO-X=OOO.-----+OOOOOOO",
+"OOOOOOOOOOOOOOOOO-oO-%#OOOO.-----OOOOOOO",
+"OOOOOOOOOOOOOOOOO--O-=OOOOO+---X#OOOOOOO",
+"OOOOOOOOOOOOOOOOO-oO-XOOOO+OO--=$OOOOOOO",
+"OOOOOOOOOOOOOOOOO-OO--++OO-&--- OOOOOOOO",
+"OOOOOOOOOOOOOOOOO-OO-----+oo--%=OOOOOOOO",
+"OOOOOOOOOOOOOOOOO--O--+o&&o--%=OOOOOOOOO",
+"OOOOOOOOOOOOOOOOO-oo*-------%=OOOOOOOOOO",
+"OOOOOOOOOOOOOOOOO-oO------%%=OOOOOOOOOOO",
+"OOOOOOOO+.+-+.---O&------= =OOOOOOOOOOOO",
+"OOOOOO+-oo&&&&&&&&------------.OOOOOOOOO",
+"OOOOOO---------------X-----O&Oo-OOOOOOOO",
+"OOOOOO---------%=%---%%=%----OO-.OOOOOOO",
+"OOOOOO---==    =%---%=%%===----%XOOOOOOO",
+"OOOOOOO-#$%OOOOOO-+-%$OOOO%===%=@OOOOOOO",
+"OOOOOOOOOOOOOOOO.-&-=%OOOOOOO%%#OOOOOOOO",
+"OOOOOOOOOOOOOOOo-O+-%$OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO-oO- OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO-OO- OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO-&-%%OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO-&-%$OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO-&-=$OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO--o-%$OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO+-&- .OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO-Oo- OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO-OO- OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO-oO- OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO-OO%%OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO-o-%$OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO---%$OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO--% #OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOX$@OOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static char *ovr_enc_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #303030",
+"= c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOoO+=+OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOo=#===+OOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo=.OO@X=OOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo#OO* #X @OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO+=.XX+=#* @OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO+=O=.=OO $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOO#.=+OO@ $OOOOOOOOOOOOOO",
+"OOOOOOOOOooooooooo&O.#+#XooooOOOOOOOOOOO",
+"OOOOOOOOO&OOoOoOoOOOOOOOOOoO%@OOOOOOOOOO",
+"OOOOOOOOoO==================X*@OOOOOOOOO",
+"OOOOOOOO&===================X% @OOOOOOOO",
+"OOOOOOOO&==%*%*%*%*%*%*%*%*==% *OOOOOOOO",
+"OOOOOOOoO==%*%%*%%*%%*%*%*%==X* OOOOOOOO",
+"OOOOOOO&======================* $OOOOOOO",
+"OOOOOO+&===                ===% *OOOOOOO",
+"OOOOOOoO======================X* OOOOOOO",
+"OOOOOO&=======================X% $OOOOOO",
+"OOOOOOo========================% *OOOOOO",
+"OOOOOoO===*%X=====%%======%%===X* OOOOOO",
+"OOOOO&==%    %==%   *====    %==* $OOOOO",
+"OOOOO&== *==**== **% *=X% %%* ==% *OOOOO",
+"OOOOoO==%%==* =* ===% == %=== %=X* OOOOO",
+"OOOO&=======% =**===% %X %X==* =X% $OOOO",
+"OOOO&======% %= %==== %% ====* ==% *OOOO",
+"OOOoO=====% *== *==== %* ====% ==X* OOOO",
+"OOO&====XX *===**===% X% X=== *===* $OOO",
+"OO+&====X *====* ===% == *=== %===% *OOO",
+"OOoO===%  %*%*== *** %==% %** ====X* OOO",
+"OO&====%      ==X   *====*   %====X% $OO",
+"OO&================================% *OO",
+"OOo===X============================%  OO",
+"OO=XXXXXXXXXXXX%XXXX%X%X%XXXXX%X%X%%  $O",
+"OOO=%******************************   $O",
+"OOOO$                                 $O",
+"OOOOO*                               *OO",
+"OOOOOOOOOOoOOoOOoOOoOOoOOoOOoOOoOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static char *satiated_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 23 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #F8B090",
+"o c #5C7A7A",
+"O c #D4D4D4",
+"+ c #F87A24",
+"@ c #7C3400",
+"# c None",
+"$ c #B0B0B0",
+"% c #F89E6C",
+"& c #914700",
+"* c #B64700",
+"= c #909090",
+"- c #788C8C",
+"; c #606060",
+": c #406868",
+"> c #FFFFFF",
+", c #CEAA90",
+"< c #DADAB6",
+"1 c #303030",
+"2 c #FFB691",
+"3 c #6C91B6",
+"4 c #F88C48",
+/* pixels */
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"################<<<<<<<<################",
+"##############<<<<<<<<<<$#$$$###########",
+"############<<<<<<<<<<$:31:3:###########",
+"###########<<<<<<%42<<#:3:133-##########",
+"##########<<<<<%<<;;=o$131:33;##########",
+"#########<<<<<<,1     ::31:33;,#########",
+"########<<<<<<,  =<<<<.13:133;<=########",
+"########<<<%2, 1<<<<<<#333:33;<,=#######",
+"#######<<<<X$ 1<<422<<<33313--<<;#######",
+"#######<<<<<1 <<<<<%<<<#31333;<<-=######",
+"#######<<<<< -<<+%,%<<%<31.3-;<<,;######",
+"#######<<<2- <<<+&<%<2+<3o<33o<<<1######",
+"######O<<<%; <<<&,4=4%<<-o<3-=<<< ######",
+"#######<<<%; <2+4,&*,,,<3o<33o<<< ######",
+"######<<<<<-1<<<<,4<4<<<.;<3-1<<< ######",
+"#######<<<<<;,<<4,,4X<<#3-<33o<<, ######",
+"######O<<<<<;.<<<,&%<2<$3:>3-=<<o1######",
+"#######<<<<<<=,<<<<<<4<#31>33;<<@o######",
+"#######O<<<<<,#<<<<<<<<.3:<3-;<, =######",
+"########<<<<2<<<<<<<<<>#31<33o<11#######",
+"########O<<<<44<>O>>>>>#3:<3.;- =#######",
+"##########<<<4<<<<><><<$3:<331 ;<#######",
+"##########<<<<<<<%2<<<<$3:<33 1#########",
+"###########O,<<<<<<<<<<#31<331##########",
+"#############.<<<<<<<<<$3:133;##########",
+"##############=;=,<<<<,o  1;;=##########",
+"###############<=;1    1;=##############",
+"#################<#<O#<#################",
+"########################################",
+"########################################",
+"########################################",
+"########################################",
+"########################################"
+};
+/* XPM */
+static char *sick_fp_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 30 1",
+/* colors */
+"  c #F85848",
+". c #949E9E",
+"X c #F8B090",
+"o c #5C7A7A",
+"O c #009100",
+"+ c #6CFF00",
+"@ c #E00028",
+"# c #D4D4D4",
+"$ c #FF6C00",
+"% c #F87A24",
+"& c #7C3400",
+"* c None",
+"= c #B0B0B0",
+"- c #F89E6C",
+"; c #FF0000",
+": c #914700",
+"> c #B64700",
+", c #909090",
+"< c #788C8C",
+"1 c #606060",
+"2 c #406868",
+"3 c #FFFFFF",
+"4 c #CEAA90",
+"5 c #DADAB6",
+"6 c #303030",
+"7 c #F86800",
+"8 c #FFB691",
+"9 c #6C91B6",
+"0 c #F88C48",
+"q c #0000FF",
+/* pixels */
+"****************************************",
+"*************#333333333#****************",
+"***********##33333#333333#**************",
+"**********#33333#33333#33*==************",
+"*********#33##33-;-3#3333399************",
+"********#33#33#3-@ 33333#33=.***********",
+"********#3*#33-;;;;;-33333#99***********",
+"*******#3*3333-;;;;@ 33#333#9=**********",
+"*******#333#33#3-;-33#*##33399**********",
+"******#3#3333333-@-#333#9933*9=*********",
+"******#333#33#3333333#333*9999=*********",
+"******#333333333#3#33333333*999*********",
+"******#3#33#33333333#33#3333#9=*********",
+"******#333334>&&:&&>::44,3#33#9*********",
+"******#33*::&41OOO6:4O 0::4433=*********",
+"******#3:>,0:O0O1O+O:O<O4-:-:1#*********",
+"******#0&>XO,O+2+OOo4<+1104:>:#*********",
+"******.&:1OOO,14X2O48:O80,440:,*********",
+"******4::>OOO%8-X4O4%O,84+O0X&>=********",
+"******.::>,O 99*X+<$,+.o*1O4&0:*********",
+"******>:0&4O5qq9#10OO3qq9,+X:1:*********",
+"****=>,,::,O4qq9X+O>O-qq9O2X0,>*********",
+"******4:>OOOO48882OOOO+4OOO07*4*********",
+"******4*,4OO+OXX3O<OOOOOOOO:-***********",
+"********0><OO1+O,+1+2OOOOOO%4=**********",
+"********47+OO1O12O:<14OO1OO7=***********",
+"*********-11OO+,+<1004OOOO:-************",
+"**********:OOOOOO-+,4O+OOO%4************",
+"**********04O4O,-OOOOO<OOO>5************",
+"*********=0%,OO,>:>>O +1OO4*************",
+"**********=%+OO:::1:::6+:7**************",
+"***********7&OO:O+O,O1OO+1**************",
+"***********40OO,O4:OOO11O<5*************",
+"**********=4 +O1O2+O2+O0O***************",
+"************72O+1+21-OOO%5**************",
+"************0%1OOOO+O+174***************",
+"*************%%O,OO1407-=***************",
+"**************-$>%0%:74*****************",
+"****************54044*=*****************",
+"*****************=*=********************"
+};
+/* XPM */
+static char *sick_il_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 23 1",
+/* colors */
+"  c #F85848",
+". c #949E9E",
+"X c #F8B090",
+"o c #E00028",
+"O c #D4D4D4",
+"+ c #F87A24",
+"@ c #7C3400",
+"# c None",
+"$ c #B0B0B0",
+"% c #F89E6C",
+"& c #FF0000",
+"* c #914700",
+"= c #B64700",
+"- c #909090",
+"; c #606060",
+": c #FFFFFF",
+"> c #CEAA90",
+", c #DADAB6",
+"< c #F86800",
+"1 c #FFB691",
+"2 c #6C91B6",
+"3 c #F88C48",
+"4 c #0000FF",
+/* pixels */
+"########################################",
+"#############O:::::::::O################",
+"###########OO:::::O::::::O##############",
+"##########O:::::O:::::O::#$$############",
+"#########O::OO::%&%:O:::::22############",
+"########O::O::O:%o :::::O::$.###########",
+"########O:#O::%&&&&&%:::::O22###########",
+"#######O:#::::%&&&&o ::O:::O2$##########",
+"#######O:::O::O:%&%::O#OO:::22##########",
+"######O:O:::::::%o%O:::O22::#2$#########",
+"######O:::O::O:::::::O:::#2222$#########",
+"######O:::::::::O:O::::::::#222#########",
+"######O:O::O::::::::O::O::::O2$#########",
+"######O:::::>=@@=**=**>>-:O::O2#########",
+"######O::#**@3>%* ;=>=3;<@>>::$#########",
+"######O:** >=>XXXX1X >>+>%*%*;O#########",
+"######O3@*,X%XXXXXXX>X%XX >*=*O#########",
+"######.@@3XXXXXXXXXXXXXXX>X>3*-#########",
+"######>***>X% >XXXXX3XXXXXX%>*=>########",
+"######.***>  22#XXX<%X22#XXX@+;#########",
+"######=*3@X>O442OXX<X:442OXX=;=#########",
+"####$=--;=X1,442XXX<X1442XXX3-*#########",
+"######>==%XX11111O1+%X111XX%<#>#########",
+"######.,;XXXXXX1O1X%3XXXXX%+3###########",
+"########3=XXXXXX:XXXXXXXXX+<>$##########",
+"########>+XXXXXX%-3->XXXX%+<############",
+"#########%3XXXXXX>- -%XXX%<%$###########",
+"#########$<XXXXXX%X%XXXX%3<>############",
+"##########+%XXXXXXXXXXXX%+<#############",
+"##########%3XXX>=****3XX%<%#############",
+"##########>+XXX**=3-*@3>3+##############",
+"###########<%XX >XX%X;%X3+##############",
+"###########%3XX>XX++XXXX<%$#############",
+"##########$>+XXXXXXXXXXX<###############",
+"############<%XXXXXXXXX3+###############",
+"###########$%+XXXXXXXX%<>###############",
+"#############++XXXXXX%<%$###############",
+"#############$%<<3333<%#################",
+"#################%3>>$##################",
+"#################$#$####################"
+};
+/* XPM */
+static char *slt_enc_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #FFFFFF",
+"* c #303030",
+"= c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOO&&&&&&&X @OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOo======X*OOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOoO======X**OOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOO&====X===% $OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOoo==%* %==%* OOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOoO=%  %  =X* @OOOOOOOOOOOOO",
+"OOOOOOOOOOOOO&==**==% %=% $OOOOOOOOOOOOO",
+"OOOOOOOOOOOOoo==%%==* %=X  OOOOOOOOOOOOO",
+"OOOOOOOOOOOOoO=====* X==X* @OOOOOOOOOOOO",
+"OOOOOOOOOOOO&=====* %====% $OOOOOOOOOOOO",
+"OOOOOOOOOOOoo====  X=====%* OOOOOOOOOOOO",
+"OOOOOOOOOOOo+===* *%*%%==X* @OOOOOOOOOOO",
+"OOOOOOOOOOO&====      %===% $OOOOOOOOOOO",
+"OOOOOOOOOOO&==============%  OOOOOOOOOOO",
+"OOOOOOOOOOO==============X%  @OOOOOOOOOO",
+"OOOOOOOOOOO+%%%%%%%%%%%%%%   $OOOOOOOOOO",
+"OOOOOOOOOOOOO%               $OOOOOOOOOO",
+"OOOOOOOOOOOOO@               @OOOOOOOOOO",
+"OOOOOOOOOOOOOO@$$$$$$$$$$$$$@OOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
+};
+/* XPM */
+static char *str_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 17 1",
+/* colors */
+"  c #000000",
+". c #F8B090",
+"X c #5C7A7A",
+"o c #F87A24",
+"O c #7C3400",
+"+ c None",
+"@ c #B0B0B0",
+"# c #F89E6C",
+"$ c #B64700",
+"% c #909090",
+"& c #606060",
+"* c #CEAA90",
+"= c #DADAB6",
+"- c #303030",
+"; c #F86800",
+": c #FFB691",
+"> c #F88C48",
+/* pixels */
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++",
+"+++++++++++++++++++*>*>#++++++++++++++++",
+"++++++++++++++++*#o>..*#o*++++++++++++++",
+"+++++++++++++++o#.#>.....o++++++++++++++",
+"+++++++++++++++;>;#.o.>..#$X++++++++++++",
+"+++++++++++++++o#>.o.>:...o  %++++++++++",
+"++++++++++++++o##>>#o##>..#O -++++++++++",
+"++++++++++++++>#.oo#>..>...O  ++++++++++",
+"++++++++++++++*o##.>>;o#...o  ++++++++++",
+"+++++++++++++++*;o#........>- &+++++++++",
+"+++++++++++++++++#>>;o......O -+++++++++",
+"+++++++++++++++++@+@+o>.....$  +++++++++",
+"+++++++++++++++++++++*;.#...>- %++++++++",
+"++++++++++++++++++++++;>o....$ &++++++++",
+"++++++++++++++++++++++#>>....>- %+++++++",
+"+++++++++++++++++++++++;#>....; -+++++++",
+"+++++++++++++++++++++++o#>....>O %++++++",
+"+++++++++++++++++++++++*>o.....; -++++++",
+"+++++++++++++#>**+++++++;#.....>O %+++++",
+"+o#+++++++*o;>>>>o#+++++o##.....; -+++++",
+"+:#o*++++oo#..*..*>;*+++#>#.....>O %++++",
+"+:=#o#+*;>.:==:....#;*++@o.......; &++++",
+"+::..>;o#.=::::......o*++;.......>O ++++",
+"+.....#o.:.=:.........o#+;........$ ++++",
+"+......#o..:...........#o;>.......o &+++",
+"+........#..............*>o......:o- +++",
+"+..................#o>#...#o.......O +++",
+"+...............>o>#.......#>......O &++",
+"+..................................o -++",
+"+..................................>  ++",
+"+..................................>  ++",
+"+.................................#$  &+",
+"+................................>$   &+",
+"+..#>$o>#..............#>;>>>oOOO-    ++",
+"+...#O  OOOOO$>>>>>>>$OO             %++",
+"+...o                            -&&++++",
+"+..#O                     -&&%++++++++++",
+"++++++++++++++++++++++++++++++++++++++++"
+};
+/* XPM */
+static char *stunned_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 12 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c #D4D4D4",
+"O c None",
+"+ c #B0B0B0",
+"@ c #909090",
+"# c #788C8C",
+"$ c #606060",
+"% c #406868",
+"& c #303030",
+"* c #6C91B6",
+/* pixels */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOO&$OOOO@OOO@@OO@OOOOOOOOOOOOO",
+"OOOOOOOOOOO@& $OO@&&$$@ O@$$OOOOOOOOOOOO",
+"OOOOOOOOOOOO$$ @@@$  &&OOO@$OOOOOOOOOOOO",
+"OOOOOOOOOOOOO@@&$$$$&O$OO$O &@O@OOOOOOOO",
+"OOOOOO@@@@@@OO@$$O$&$@@OO&  &&$O&OOOOOOO",
+"OOOOOO&&&& & $ &&@$ &O@$& &&&$ & $OOOOOO",
+"OOOOOO$&OO &&&$ $$    $&  $$&$&&&OOOOOOO",
+"OOOOOO@@O@$  &+ #       &O$$  $$&O@OOOOO",
+"OOOOOOOO@X%$ %&   %%    & &&  $$@@@@OOOO",
+"OOOOOOO+$$@+     &%%%&%&   &  &@OOO&&OOO",
+"OOOOOO.Xo%+      &&%%%%%&& &   OO@$&&OOO",
+"OOOOO++ $$&&$     && %&%%&    &O@&$&OOOO",
+"OOOOO####$ X&&& &&     &%&   &    &&OOOO",
+"OOOO++#.+## $&# %& &       &     &$ OOOO",
+"OOOO#+++.@&%&& &#&%&   &       $ @OOOOOO",
+"OOOO##....#+$#@%#& $%$&@&$$% & X##$@OOOO",
+"OOOO.+#+.+@#+#+$&$X#%&%.+& %&#++.$&OOOOO",
+"OOOOO#+#+.+++#$$%&++&X+X#&#+&+&##+ &OOOO",
+"OOOOO#..#OO#+@%#o##X.@..++.+$&+#+#& @OOO",
+"OOOOO+#.#O+#+#O@++@$$##+##++###+.#& $OOO",
+"OOOOOOXX+#+#+#o.@%&$++#+..##.#+###  &OOO",
+"OOOOOOOX#.#X+#+#+##&#+..+####%XX%%   OOO",
+"OOOOOOOO+%%X.#+#+#.++#+#+#+.X++*.%  &OOO",
+"OOOOOOOOO@& &##+#+.O####.+XX%%%%#%  $OOO",
+"OOOOOOOOOOO.   %X.+.#+++XXX*.+++#X  $OOO",
+"OOOOOOOOOOOO@&   %%X..#X%#.####%X&  $OOO",
+"OOOOOOOOOOOOOO@$ &XX%%%*.#X%###*&   OOOO",
+"OOOOOOOOOOOOOOOOOO+%%%*%%#.+.#*&   @OOOO",
+"OOOOOOOOOOOOOOOOOOO*%%%**X##X%&    OOOOO",
+"OOOOOOOOOOOOOOOOOOOOX%%%%X*X&     @OOOOO",
+"OOOOOOOOOOOOOOOOOOOOX%%%%X      &@OOOOOO",
+"OOOOOOOOOOOOOOOOOOOO*%%%X&   &$$OOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOO+X%%*  @OOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOOX%%&  OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOO",
+"OOOOOOOOOOOOOOOOOOOOO.X%& $OOOOOOOOOOOOO"
+};
+/* XPM */
+static char *wis_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c None",
+"O c #B0B0B0",
+"+ c #909090",
+"@ c #788C8C",
+"# c #606060",
+"$ c #406868",
+"% c #FFFFFF",
+"& c #303030",
+"* c #6C91B6",
+"= c #0000FF",
+/* pixels */
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooo+#& &#oooooooooooooooooooo",
+"oooooooooooo+&       #oooooooooooooooooo",
+"ooooooooooo+  &====&& &ooooooooooooooooo",
+"oooooooooo+ &==&  ===%& +ooooooooooooooo",
+"ooooooooo+&%===   ===%%o&&oooooooooooooo",
+"oooooooo.&%%===&  ===%o&   #+ooooooooooo",
+"oooo&###&&%%*=======$#&ooo#&  #+oooooooo",
+"ooooo###o+&X$=====& #oo##oooo+######oooo",
+"oooooooooooo######@oo##ooooooooooooooooo",
+"oooooooooooooOoOoOo##ooooooooooooooooooo",
+"ooooooooooooooooo+#+ooo+&#oooooooooooooo",
+"ooooooooooooooooooooooo#oooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo"
+};
+/* XPM */
+static char *nothing_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 13 1",
+/* colors */
+"  c #000000",
+". c #949E9E",
+"X c #5C7A7A",
+"o c None",
+"O c #B0B0B0",
+"+ c #909090",
+"@ c #788C8C",
+"# c #606060",
+"$ c #406868",
+"% c #FFFFFF",
+"& c #303030",
+"* c #6C91B6",
+"= c #0000FF",
+/* pixels */
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooooooooooo"
+};
+
diff --git a/win/gnome/gnaskstr.c b/win/gnome/gnaskstr.c
new file mode 100644 (file)
index 0000000..b982896
--- /dev/null
@@ -0,0 +1,61 @@
+/*     SCCS Id: @(#)gnaskstr.c 3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "gnaskstr.h"
+#include "gnmain.h"
+#include <gnome.h>
+
+
+static
+void ghack_ask_string_callback(gchar * string, gpointer data)
+{
+  char **user_text = (char **) data;
+
+  g_assert(user_text != NULL);
+
+  *user_text = string; /* note - value must be g_free'd */
+}
+
+
+int ghack_ask_string_dialog(const char *szMessageStr, 
+       const char *szDefaultStr, const char *szTitleStr, 
+       char *buffer)
+{
+    int i;
+    GtkWidget* dialog;
+    gchar   *user_text = NULL;
+
+    dialog = gnome_request_dialog(FALSE, szMessageStr,
+                                 szDefaultStr, 0,
+                                 ghack_ask_string_callback,
+                                 &user_text, NULL);
+    g_assert(dialog != NULL);
+
+    gtk_window_set_title(GTK_WINDOW(dialog), szTitleStr);
+
+    gnome_dialog_set_default( GNOME_DIALOG(dialog), 0);
+    gtk_window_set_modal( GTK_WINDOW(dialog), TRUE);
+    gnome_dialog_set_parent (GNOME_DIALOG (dialog), 
+           GTK_WINDOW (ghack_get_main_window ()) );
+
+    i = gnome_dialog_run_and_close (GNOME_DIALOG (dialog));
+    
+    /* Quit */
+    if ( i != 0 || user_text == NULL ) {
+       if (user_text)
+         g_free(user_text);
+       return -1;
+    }
+
+    if ( *user_text == 0 ) {
+      g_free(user_text);
+      return -1;
+    }
+
+    g_assert(strlen(user_text) > 0);
+    strcpy (buffer, user_text);
+    g_free(user_text);
+    return 0;
+}
+
diff --git a/win/gnome/gnaskstr.h b/win/gnome/gnaskstr.h
new file mode 100644 (file)
index 0000000..9cde69b
--- /dev/null
@@ -0,0 +1,14 @@
+/*     SCCS Id: @(#)gnaskstr.h 3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackAskStringDialog_h
+#define GnomeHackAskStringDialog_h
+
+
+int ghack_ask_string_dialog(const char *szMessageStr,
+        const char *szDefaultStr, const char *szTitleStr,
+        char *buffer);
+
+#endif /* GnomeHackAskStringDialog_h */
+
diff --git a/win/gnome/gnbind.c b/win/gnome/gnbind.c
new file mode 100644 (file)
index 0000000..a6f0ed8
--- /dev/null
@@ -0,0 +1,1197 @@
+/*     SCCS Id: @(#)gnbind.c   3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file implements the interface between the window port specific
+ * code in the Gnome port and the rest of the nethack game engine. 
+*/
+
+#include "gnbind.h"
+#include "gnmain.h"
+#include "gnmenu.h"
+#include "gnaskstr.h"
+#include "gnyesno.h"
+
+GNHWinData gnome_windowlist[MAXWINDOWS];
+winid WIN_WORN = WIN_ERR;
+
+extern void tty_raw_print(const char *);
+extern void tty_raw_print_bold(const char *);
+
+
+/* Interface definition, for windows.c */
+struct window_procs Gnome_procs = {
+    "Gnome",
+    WC_COLOR|WC_HILITE_PET|WC_INVERSE,
+    0L,
+    gnome_init_nhwindows,
+    gnome_player_selection,
+    gnome_askname,
+    gnome_get_nh_event,
+    gnome_exit_nhwindows,
+    gnome_suspend_nhwindows,
+    gnome_resume_nhwindows,
+    gnome_create_nhwindow,
+    gnome_clear_nhwindow,
+    gnome_display_nhwindow,
+    gnome_destroy_nhwindow,
+    gnome_curs,
+    gnome_putstr,
+    gnome_display_file,
+    gnome_start_menu,
+    gnome_add_menu,
+    gnome_end_menu,
+    gnome_select_menu,
+    genl_message_menu,         /* no need for X-specific handling */
+    gnome_update_inventory,
+    gnome_mark_synch,
+    gnome_wait_synch,
+#ifdef CLIPPING
+    gnome_cliparound,
+#endif
+#ifdef POSITIONBAR
+    donull,
+#endif
+    gnome_print_glyph,
+    gnome_raw_print,
+    gnome_raw_print_bold,
+    gnome_nhgetch,
+    gnome_nh_poskey,
+    gnome_nhbell,
+    gnome_doprev_message,
+    gnome_yn_function,
+    gnome_getlin,
+    gnome_get_ext_cmd,
+    gnome_number_pad,
+    gnome_delay_output,
+#ifdef CHANGE_COLOR    /* only a Mac option currently */
+    donull,
+    donull,
+#endif
+    /* other defs that really should go away (they're tty specific) */
+    gnome_start_screen,
+    gnome_end_screen,
+    gnome_outrip,
+    genl_preference_update,
+};
+
+/*  
+init_nhwindows(int* argcp, char** argv)
+                -- Initialize the windows used by NetHack.  This can also
+                   create the standard windows listed at the top, but does
+                   not display them.
+                -- Any commandline arguments relevant to the windowport
+                   should be interpreted, and *argcp and *argv should
+                   be changed to remove those arguments.
+                -- When the message window is created, the variable
+                   iflags.window_inited needs to be set to TRUE.  Otherwise
+                   all plines() will be done via raw_print().
+                ** Why not have init_nhwindows() create all of the "standard"
+                ** windows?  Or at least all but WIN_INFO?      -dean
+*/
+void gnome_init_nhwindows(int* argc, char** argv)
+{
+    /* Main window */
+    ghack_init_main_window( *argc, argv);
+    ghack_init_signals( );
+
+#ifdef HACKDIR
+    //if (ghack_init_glyphs(HACKDIR "/t32-1024.xpm"))
+    if (ghack_init_glyphs(HACKDIR "/x11tiles"))
+      g_error ("ERROR:  Could not initialize glyphs.\n");
+#else
+#   error HACKDIR is not defined!
+#endif
+  
+    // gnome/gtk is not reentrant
+    set_option_mod_status("ignintr", DISP_IN_GAME);
+    flags.ignintr = TRUE;
+
+    iflags.window_inited = TRUE;
+
+    /* gnome-specific window creation */
+    WIN_WORN = gnome_create_nhwindow(NHW_WORN);
+}
+
+
+/* Do a window-port specific player type selection. If player_selection()
+   offers a Quit option, it is its responsibility to clean up and terminate
+   the process. You need to fill in pl_character[0].
+*/
+void
+gnome_player_selection()
+{
+    int n, i, sel;
+    const char** choices;
+    int* pickmap;
+
+    /* prevent an unnecessary prompt */
+    rigid_role_checks();
+
+    if (!flags.randomall && flags.initrole < 0) {
+
+       /* select a role */
+       for (n = 0; roles[n].name.m; n++) continue;
+       choices = (const char **)alloc(sizeof(char *) * (n+1));
+       pickmap = (int*)alloc(sizeof(int) * (n+1));
+       for (;;) {
+           for (n = 0, i = 0; roles[i].name.m; i++) {
+               if (ok_role(i, flags.initrace,
+                           flags.initgend, flags.initalign)) {
+                   if (flags.initgend >= 0 && flags.female && roles[i].name.f)
+                       choices[n] = roles[i].name.f;
+                   else
+                       choices[n] = roles[i].name.m;
+                   pickmap[n++] = i;
+               }
+           }
+           if (n > 0) break;
+           else if (flags.initalign >= 0) flags.initalign = -1;    /* reset */
+           else if (flags.initgend >= 0) flags.initgend = -1;
+           else if (flags.initrace >= 0) flags.initrace = -1;
+           else panic("no available ROLE+race+gender+alignment combinations");
+       }
+       choices[n] = (const char *) 0;
+       if (n > 1)
+           sel = ghack_player_sel_dialog(choices,
+               _("Player selection"), _("Choose one of the following roles:"));
+       else sel = 0;
+       if (sel >= 0) sel = pickmap[sel];
+       else if (sel == ROLE_NONE) {            /* Quit */
+           clearlocks();
+           gnome_exit_nhwindows(0);
+       }
+       free(choices);
+       free(pickmap);
+    } else if (flags.initrole < 0) sel = ROLE_RANDOM;
+    else sel = flags.initrole;
+  
+    if (sel == ROLE_RANDOM) {  /* Random role */
+       sel = pick_role(flags.initrace, flags.initgend,
+                         flags.initalign, PICK_RANDOM);
+       if (sel < 0) sel = randrole();
+    }
+
+    flags.initrole = sel;
+
+    /* Select a race, if necessary */
+    /* force compatibility with role, try for compatibility with
+     * pre-selected gender/alignment */
+    if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
+       if (flags.initrace == ROLE_RANDOM || flags.randomall) {
+           flags.initrace = pick_race(flags.initrole, flags.initgend,
+                                      flags.initalign, PICK_RANDOM);
+           if (flags.initrace < 0) flags.initrace = randrace(flags.initrole);
+       } else {
+           /* Count the number of valid races */
+           n = 0;      /* number valid */
+           for (i = 0; races[i].noun; i++) {
+               if (ok_race(flags.initrole, i, flags.initgend, flags.initalign))
+                   n++;
+           }
+           if (n == 0) {
+               for (i = 0; races[i].noun; i++) {
+                   if (validrace(flags.initrole, i)) n++;
+               }
+           }
+
+           choices = (const char **)alloc(sizeof(char *) * (n+1));
+           pickmap = (int*)alloc(sizeof(int) * (n + 1));
+           for (n = 0, i = 0; races[i].noun; i++) {
+               if (ok_race(flags.initrole, i, flags.initgend,
+                           flags.initalign)) {
+                   choices[n] = races[i].noun;
+                   pickmap[n++] = i;
+               }
+           }
+           choices[n] = (const char *) 0;
+           /* Permit the user to pick, if there is more than one */
+           if (n > 1)
+               sel = ghack_player_sel_dialog(choices, _("Race selection"),
+                       _("Choose one of the following races:"));
+           else sel = 0;
+           if (sel >= 0) sel = pickmap[sel];
+           else if (sel == ROLE_NONE) { /* Quit */
+               clearlocks();
+               gnome_exit_nhwindows(0);
+           }
+           flags.initrace = sel;
+           free(choices);
+           free(pickmap);
+       }
+       if (flags.initrace == ROLE_RANDOM) {    /* Random role */
+           sel = pick_race(flags.initrole, flags.initgend,
+                           flags.initalign, PICK_RANDOM);
+           if (sel < 0) sel = randrace(flags.initrole);
+           flags.initrace = sel;
+       }
+    }
+
+    /* Select a gender, if necessary */
+    /* force compatibility with role/race, try for compatibility with
+     * pre-selected alignment */
+    if (flags.initgend < 0 ||
+       !validgend(flags.initrole, flags.initrace, flags.initgend)) {
+       if (flags.initgend == ROLE_RANDOM || flags.randomall) {
+           flags.initgend = pick_gend(flags.initrole, flags.initrace,
+                                      flags.initalign, PICK_RANDOM);
+           if (flags.initgend < 0)
+               flags.initgend = randgend(flags.initrole, flags.initrace);
+       } else {
+           /* Count the number of valid genders */
+           n = 0;      /* number valid */
+           for (i = 0; i < ROLE_GENDERS; i++) {
+               if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign))
+                   n++;
+           }
+           if (n == 0) {
+               for (i = 0; i < ROLE_GENDERS; i++) {
+                   if (validgend(flags.initrole, flags.initrace, i)) n++;
+               }
+           }
+
+           choices = (const char **)alloc(sizeof(char *) * (n+1));
+           pickmap = (int*)alloc(sizeof(int) * (n + 1));
+           for (n = 0, i = 0; i < ROLE_GENDERS; i++) {
+               if (ok_gend(flags.initrole, flags.initrace, i,
+                               flags.initalign)) {
+                   choices[n] = genders[i].adj;
+                   pickmap[n++] = i;
+               }
+           }
+           choices[n] = (const char *) 0;
+           /* Permit the user to pick, if there is more than one */
+           if (n > 1)
+               sel = ghack_player_sel_dialog(choices, _("Gender selection"),
+                       _("Choose one of the following genders:"));
+           else sel = 0;
+           if (sel >= 0) sel = pickmap[sel];
+           else if (sel == ROLE_NONE) { /* Quit */
+               clearlocks();
+               gnome_exit_nhwindows(0);
+           }
+           flags.initgend = sel;
+           free(choices);
+           free(pickmap);
+       }
+       if (flags.initgend == ROLE_RANDOM) {    /* Random gender */
+           sel = pick_gend(flags.initrole, flags.initrace,
+                           flags.initalign, PICK_RANDOM);
+           if (sel < 0) sel = randgend(flags.initrole, flags.initrace);
+           flags.initgend = sel;
+       }
+    }
+
+    /* Select an alignment, if necessary */
+    /* force compatibility with role/race/gender */
+    if (flags.initalign < 0 ||
+       !validalign(flags.initrole, flags.initrace, flags.initalign)) {
+       if (flags.initalign == ROLE_RANDOM || flags.randomall) {
+           flags.initalign = pick_align(flags.initrole, flags.initrace,
+                                        flags.initgend, PICK_RANDOM);
+           if (flags.initalign < 0)
+               flags.initalign = randalign(flags.initrole, flags.initrace);
+       } else {
+           /* Count the number of valid alignments */
+           n = 0;      /* number valid */
+           for (i = 0; i < ROLE_ALIGNS; i++) {
+               if (ok_align(flags.initrole, flags.initrace, flags.initgend, i))
+                   n++;
+           }
+           if (n == 0) {
+               for (i = 0; i < ROLE_ALIGNS; i++)
+                   if (validalign(flags.initrole, flags.initrace, i)) n++;
+           }
+
+           choices = (const char **)alloc(sizeof(char *) * (n+1));
+           pickmap = (int*)alloc(sizeof(int) * (n + 1));
+           for (n = 0, i = 0; i < ROLE_ALIGNS; i++) {
+               if (ok_align(flags.initrole,
+                            flags.initrace, flags.initgend, i)) {
+                   choices[n] = aligns[i].adj;
+                   pickmap[n++] = i;
+               }
+           }
+           choices[n] = (const char *) 0;
+           /* Permit the user to pick, if there is more than one */
+           if (n > 1)
+               sel = ghack_player_sel_dialog(choices, _("Alignment selection"),
+                       _("Choose one of the following alignments:"));
+           else sel = 0;
+           if (sel >= 0) sel = pickmap[sel];
+           else if (sel == ROLE_NONE) { /* Quit */
+               clearlocks();
+               gnome_exit_nhwindows(0);
+           }
+           flags.initalign = sel;
+           free(choices);
+           free(pickmap);
+       }
+       if (flags.initalign == ROLE_RANDOM) {
+           sel = pick_align(flags.initrole, flags.initrace,
+                            flags.initgend, PICK_RANDOM);
+           if (sel < 0) sel = randalign(flags.initrole, flags.initrace);
+           flags.initalign = sel;
+       }
+    }
+}
+
+
+/* Ask the user for a player name. */
+void gnome_askname()
+{
+    int ret;
+
+    g_message("Asking name....");
+
+    /* Ask for a name and stuff the response into plname, a nethack global */
+    ret = ghack_ask_string_dialog("What is your name?", "gandalf", 
+           "GnomeHack", plname);
+
+    /* Quit if they want to quit... */
+    if (ret==-1)
+      {
+        gnome_exit_nhwindows(0);
+      }
+}
+
+
+/* Does window event processing (e.g. exposure events).
+   A noop for the tty and X window-ports.
+*/
+void gnome_get_nh_event()
+{
+       /* We handle our own events. */
+       return;
+}
+
+/* Exits the window system.  This should dismiss all windows,
+   except the "window" used for raw_print().  str is printed if possible.
+*/
+void gnome_exit_nhwindows(const char *str)
+{
+       gtk_exit (0);
+       terminate(EXIT_SUCCESS);
+}
+
+/* Prepare the window to be suspended. */
+void gnome_suspend_nhwindows(const char *str)
+{
+       /* I don't think we need to do anything here... */
+       return;
+}
+
+
+/* Restore the windows after being suspended. */
+void gnome_resume_nhwindows()
+{
+       /* Do Nothing.  Un-necessary since the GUI will refresh itself. */
+       return;
+}
+
+/*  Create a window of type "type" which can be 
+        NHW_MESSAGE     (top line)
+        NHW_STATUS      (bottom lines)
+        NHW_MAP         (main dungeon)
+        NHW_MENU        (inventory or other "corner" windows)
+        NHW_TEXT        (help/text, full screen paged window)
+*/
+winid 
+gnome_create_nhwindow(int type)
+{
+
+  winid i = 0;
+
+/* Return the next available winid
+ */
+
+  for (i=0; i<MAXWINDOWS; i++)
+      if (gnome_windowlist[i].win == NULL)
+          break;
+  if (i == MAXWINDOWS)
+      g_error ("ERROR:  No windows available...\n");
+  gnome_create_nhwindow_by_id( type, i);
+  return i;
+}
+
+void
+gnome_create_nhwindow_by_id( int type, winid i)
+{
+    switch (type)
+      {
+      case NHW_MAP:
+       {
+         gnome_windowlist[i].win = ghack_init_map_window( );
+         gnome_windowlist[i].type = NHW_MAP;
+         ghack_main_window_add_map_window( gnome_windowlist[i].win);
+         break;
+       }
+      case NHW_MESSAGE:
+       {
+         gnome_windowlist[i].win = ghack_init_message_window( );
+         gnome_windowlist[i].type = NHW_MESSAGE;
+         ghack_main_window_add_message_window( gnome_windowlist[i].win);
+         break; 
+       }
+      case NHW_STATUS:
+       {
+         gnome_windowlist[i].win = ghack_init_status_window( );
+         gnome_windowlist[i].type = NHW_STATUS;
+         ghack_main_window_add_status_window( gnome_windowlist[i].win);
+         break;
+       }    
+      case NHW_WORN:
+       {
+         gnome_windowlist[i].win = ghack_init_worn_window( );
+         gnome_windowlist[i].type = NHW_WORN;
+         ghack_main_window_add_worn_window(gnome_windowlist[i].win);
+         break;
+       }
+      case NHW_MENU:
+       {
+         gnome_windowlist[i].type = NHW_MENU;
+         gnome_windowlist[i].win = ghack_init_menu_window( );
+         break;
+       } 
+      case NHW_TEXT:
+       {
+         gnome_windowlist[i].win = ghack_init_text_window( );
+         gnome_windowlist[i].type = NHW_TEXT;
+         break;
+       }
+      }
+}
+
+/* This widget is being destroyed before its time--
+ * clear its entry from the windowlist.
+*/
+void gnome_delete_nhwindow_by_reference( GtkWidget *menuWin)
+{
+  int i;
+
+  for (i = 0; i < MAXWINDOWS; i++) {
+    if (gnome_windowlist[i].win == menuWin) {
+      gnome_windowlist[i].win = NULL;
+      gnome_windowlist[i].type = 0;
+      break;
+    }
+  }
+}
+
+/* Clear the given window, when asked to. */
+void gnome_clear_nhwindow(winid wid)
+{
+  if (gnome_windowlist[wid].win != NULL)
+    {
+      gtk_signal_emit (GTK_OBJECT (gnome_windowlist[wid].win),
+                      ghack_signals[GHSIG_CLEAR]);
+    }
+}
+
+/* -- Display the window on the screen.  If there is data
+                   pending for output in that window, it should be sent.
+                   If blocking is TRUE, display_nhwindow() will not
+                   return until the data has been displayed on the screen,
+                   and acknowledged by the user where appropriate.
+                -- All calls are blocking in the tty window-port.
+                -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
+                   --more--, if necessary, in the tty window-port.
+*/
+void gnome_display_nhwindow(winid wid, BOOLEAN_P block)
+{
+  if (gnome_windowlist[wid].win != NULL)
+    {
+      gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
+                      ghack_signals[GHSIG_DISPLAY],
+                      block);
+      if (block && (gnome_windowlist[wid].type == NHW_MAP))
+       (void) gnome_nhgetch();
+    }
+}
+
+
+/* Destroy will dismiss the window if the window has not 
+ * already been dismissed.
+*/
+void gnome_destroy_nhwindow(winid wid)
+{
+    if ((wid == WIN_MAP) || 
+        (wid == WIN_MESSAGE) || 
+        (wid == WIN_STATUS)) {
+       /* no thanks, I'll do these myself */
+       return;
+    }
+    if (wid != -1 && gnome_windowlist[wid].win != NULL)
+      {
+       gtk_widget_destroy(gnome_windowlist[wid].win);
+       gnome_windowlist[wid].win = NULL;
+       gnome_windowlist[wid].type = 0;
+      }
+}
+
+/* Next output to window will start at (x,y), also moves
+ displayable cursor to (x,y).  For backward compatibility,
+ 1 <= x < cols, 0 <= y < rows, where cols and rows are
+ the size of window.
+*/
+void gnome_curs(winid wid, int x, int y)
+{
+  if (wid != -1 && gnome_windowlist[wid].win != NULL)
+    {
+      gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win), 
+                      ghack_signals[GHSIG_CURS], x, y);
+    }
+}
+
+/*
+putstr(window, attr, str)
+                -- Print str on the window with the given attribute.  Only
+                   printable ASCII characters (040-0126) must be supported.
+                   Multiple putstr()s are output on separate lines.
+Attributes
+                   can be one of
+                        ATR_NONE (or 0)
+                        ATR_ULINE
+                        ATR_BOLD
+                        ATR_BLINK
+                        ATR_INVERSE
+                   If a window-port does not support all of these, it may map
+                   unsupported attributes to a supported one (e.g. map them
+                   all to ATR_INVERSE).  putstr() may compress spaces out of
+                   str, break str, or truncate str, if necessary for the
+                   display.  Where putstr() breaks a line, it has to clear
+                   to end-of-line.
+                -- putstr should be implemented such that if two putstr()s
+                   are done consecutively the user will see the first and
+                   then the second.  In the tty port, pline() achieves this
+                   by calling more() or displaying both on the same line.
+*/
+void gnome_putstr(winid wid, int attr, const char *text)
+{
+    if ((wid >= 0) && 
+        (wid < MAXWINDOWS) &&
+        (gnome_windowlist[wid].win != NULL))
+    {
+      gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
+                      ghack_signals[GHSIG_PUTSTR],
+                      (guint) attr,
+                      text);
+    }
+}
+
+/* Display the file named str.  Complain about missing files
+                   iff complain is TRUE.
+*/
+void gnome_display_file(const char *filename,BOOLEAN_P must_exist)
+{
+       /* Strange -- for some reason it makes us create a new text window
+        * instead of reusing any existing ones -- perhaps we can work out
+        * some way to reuse stuff -- but for now just make and destroy new
+        * ones each time */
+        
+       dlb *f;
+       
+        f = dlb_fopen(filename, "r");
+        if (!f) {
+         if (must_exist) {
+           GtkWidget *box;
+            char message[90];
+            sprintf(message, "Warning! Could not find file: %s\n",filename);
+
+           box = gnome_message_box_new (_(message),
+                   GNOME_MESSAGE_BOX_ERROR,
+                   GNOME_STOCK_BUTTON_OK,
+                   NULL);
+           gnome_dialog_set_default( GNOME_DIALOG(box), 0);
+           gnome_dialog_set_parent (GNOME_DIALOG (box), 
+                   GTK_WINDOW (ghack_get_main_window ()) );
+           gtk_window_set_modal( GTK_WINDOW(box), TRUE);
+           gtk_widget_show (box);
+         }
+        }
+       else {
+         GtkWidget *txtwin, *gless, *frametxt;
+#define LLEN 128
+         char line[LLEN], *textlines;
+         int num_lines, charcount;
+
+         txtwin = gnome_dialog_new("Text Window", GNOME_STOCK_BUTTON_OK,
+                                   NULL);
+          gtk_widget_set_usize(GTK_WIDGET(txtwin), 500, 400);
+          gtk_window_set_policy(GTK_WINDOW(txtwin), TRUE, TRUE, FALSE);
+          gtk_window_set_title(GTK_WINDOW(txtwin), "Text Window");
+         gnome_dialog_set_default( GNOME_DIALOG(txtwin), 0);
+         gtk_window_set_modal( GTK_WINDOW(txtwin), TRUE);
+         frametxt = gtk_frame_new ("");
+         gtk_widget_show (frametxt);
+
+         /*
+          * Count the number of lines and characters in the file.
+          */
+         num_lines = 0;
+         charcount = 1;
+         while (dlb_fgets(line, LLEN, f)) {
+           num_lines++;
+           charcount += strlen(line);
+         }
+         (void) dlb_fclose(f);
+         
+         /* Ignore empty files */
+         if (num_lines == 0) return;
+
+         /*
+          * Re-open the file and read the data into a buffer.  
+          */
+         textlines = (char *) alloc((unsigned int) charcount);
+         textlines[0] = '\0';
+         f = dlb_fopen( filename, RDTMODE);
+
+         while (dlb_fgets(line, LLEN, f)) {
+           (void) strcat(textlines, line);
+         }
+         (void) dlb_fclose(f);
+
+         gless = gnome_less_new ();
+         gnome_less_show_string (GNOME_LESS (gless), textlines);
+         gtk_container_add (GTK_CONTAINER (frametxt), gless);
+          gtk_box_pack_start(GTK_BOX (GNOME_DIALOG (txtwin)->vbox), frametxt,
+                             TRUE, TRUE, 0);
+         gtk_widget_show_all( txtwin);
+         gtk_window_set_modal( GTK_WINDOW(txtwin), TRUE);
+         gnome_dialog_set_parent (GNOME_DIALOG (txtwin), 
+                 GTK_WINDOW (ghack_get_main_window ()) );
+         gnome_dialog_run_and_close (GNOME_DIALOG (txtwin));
+         free(textlines);
+        }
+}
+
+/* Start using window as a menu.  You must call start_menu()
+   before add_menu().  After calling start_menu() you may not
+   putstr() to the window.  Only windows of type NHW_MENU may
+   be used for menus.
+*/
+void gnome_start_menu(winid wid)
+{
+  if (wid != -1)
+    {
+      if (gnome_windowlist[wid].win == NULL && gnome_windowlist[wid].type != 0)
+       {
+         gnome_create_nhwindow_by_id(gnome_windowlist[wid].type, wid);
+       }
+        gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
+                      ghack_signals[GHSIG_START_MENU]);
+    }
+}
+
+/*
+add_menu(windid window, int glyph, const anything identifier,
+                                char accelerator, char groupacc,
+                                int attr, char *str, boolean preselected)
+                -- Add a text line str to the given menu window.  If identifier
+                   is 0, then the line cannot be selected (e.g. a title).
+                   Otherwise, identifier is the value returned if the line is
+                   selected.  Accelerator is a keyboard key that can be used
+                   to select the line.  If the accelerator of a selectable
+                   item is 0, the window system is free to select its own
+                   accelerator.  It is up to the window-port to make the
+                   accelerator visible to the user (e.g. put "a - " in front
+                   of str).  The value attr is the same as in putstr().
+                   Glyph is an optional glyph to accompany the line.  If
+                   window port cannot or does not want to display it, this
+                   is OK.  If there is no glyph applicable, then this
+                   value will be NO_GLYPH.
+                -- All accelerators should be in the range [A-Za-z].
+                -- It is expected that callers do not mix accelerator
+                   choices.  Either all selectable items have an accelerator
+                   or let the window system pick them.  Don't do both.
+                -- Groupacc is a group accelerator.  It may be any character
+                   outside of the standard accelerator (see above) or a
+                   number.  If 0, the item is unaffected by any group
+                   accelerator.  If this accelerator conflicts with
+                   the menu command (or their user defined alises), it loses.
+                   The menu commands and aliases take care not to interfere
+                   with the default object class symbols.
+                -- If you want this choice to be preselected when the
+                   menu is displayed, set preselected to TRUE.
+*/
+void gnome_add_menu(winid wid, int glyph, const ANY_P * identifier,
+               CHAR_P accelerator, CHAR_P group_accel, int attr, 
+               const char *str, BOOLEAN_P presel)
+{
+  GHackMenuItem item;
+  item.glyph =  glyph;
+  item.identifier = identifier;
+  item.accelerator = accelerator;
+  item.group_accel = group_accel;
+  item.attr = attr;
+  item.str = str;
+  item.presel = presel;
+
+  if (wid != -1 && gnome_windowlist[wid].win != NULL)
+    {
+      gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
+                      ghack_signals[GHSIG_ADD_MENU],
+                      &item);
+    }
+}
+
+/*
+end_menu(window, prompt)
+                -- Stop adding entries to the menu and flushes the window
+                   to the screen (brings to front?).  Prompt is a prompt
+                   to give the user.  If prompt is NULL, no prompt will
+                   be printed.
+                ** This probably shouldn't flush the window any more (if
+                ** it ever did).  That should be select_menu's job.  -dean
+*/
+void gnome_end_menu(winid wid, const char *prompt)
+{
+    if (wid != -1 && gnome_windowlist[wid].win != NULL)
+      {
+       gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
+                        ghack_signals[GHSIG_END_MENU],
+                        prompt);
+      }
+}
+
+/*
+int select_menu(windid window, int how, menu_item **selected)
+                -- Return the number of items selected; 0 if none were chosen,
+                   -1 when explicitly cancelled.  If items were selected, then
+                   selected is filled in with an allocated array of menu_item
+                   structures, one for each selected line.  The caller must
+                   free this array when done with it.  The "count" field
+                   of selected is a user supplied count.  If the user did
+                   not supply a count, then the count field is filled with
+                   -1 (meaning all).  A count of zero is equivalent to not
+                   being selected and should not be in the list.  If no items
+                   were selected, then selected is NULL'ed out.  How is the
+                   mode of the menu.  Three valid values are PICK_NONE,
+                   PICK_ONE, and PICK_N, meaning: nothing is selectable,
+                   only one thing is selectable, and any number valid items
+                   may selected.  If how is PICK_NONE, this function should
+                   never return anything but 0 or -1.
+                -- You may call select_menu() on a window multiple times --
+                   the menu is saved until start_menu() or destroy_nhwindow()
+                   is called on the window.
+                -- Note that NHW_MENU windows need not have select_menu()
+                   called for them. There is no way of knowing whether
+                   select_menu() will be called for the window at
+                   create_nhwindow() time.
+*/
+int gnome_select_menu(winid wid, int how, MENU_ITEM_P **selected)
+{
+    int nReturned = -1;
+
+    if (wid != -1 && gnome_windowlist[wid].win != NULL &&
+        gnome_windowlist[wid].type == NHW_MENU)
+      {
+       nReturned=ghack_menu_window_select_menu (gnome_windowlist[wid].win,
+                                      selected, how);
+      }
+
+    return nReturned;
+}
+
+/*
+    -- Indicate to the window port that the inventory has been changed.
+    -- Merely calls display_inventory() for window-ports that leave the 
+       window up, otherwise empty.
+*/
+void gnome_update_inventory()
+{
+    ghack_main_window_update_inventory();
+}
+
+/*
+mark_synch()    -- Don't go beyond this point in I/O on any channel until
+                   all channels are caught up to here.  Can be an empty call
+                   for the moment
+*/
+void gnome_mark_synch()
+{
+       /* Do nothing */
+}
+
+/*
+wait_synch()    -- Wait until all pending output is complete (*flush*() for
+                   streams goes here).
+                -- May also deal with exposure events etc. so that the
+                   display is OK when return from wait_synch().
+*/
+void gnome_wait_synch()
+{
+       /* Do nothing */
+}
+
+/*
+cliparound(x, y)-- Make sure that the user is more-or-less centered on the
+                   screen if the playing area is larger than the screen.
+                -- This function is only defined if CLIPPING is defined.
+*/
+void gnome_cliparound(int x, int y)
+{
+  /* FIXME!!!  winid should be a parameter!!!
+   * Call a function that Does The Right Thing(tm).
+  */
+    gnome_cliparound_proper(WIN_MAP,x,y);
+}
+
+void gnome_cliparound_proper(winid wid, int x, int y)
+{
+    if (wid != -1 && gnome_windowlist[wid].win != NULL)
+      {
+       gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
+                        ghack_signals[GHSIG_CLIPAROUND],
+                        (guint) x, 
+                        (guint) y);
+      }
+}
+
+/*
+print_glyph(window, x, y, glyph)
+                -- Print the glyph at (x,y) on the given window.  Glyphs are
+                   integers at the interface, mapped to whatever the window-
+                   port wants (symbol, font, color, attributes, ...there's
+                   a 1-1 map between glyphs and distinct things on the map).
+*/
+void gnome_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph)
+{
+    if (wid != -1 && gnome_windowlist[wid].win != NULL)
+      {
+       GdkImlibImage *im;
+
+       im = ghack_image_from_glyph( glyph, FALSE);
+
+       gtk_signal_emit (GTK_OBJECT (gnome_windowlist[wid].win),
+                        ghack_signals[GHSIG_PRINT_GLYPH],
+                        (guint) x,
+                        (guint) y,
+                        im,
+                        NULL);
+    }
+}
+
+/*
+raw_print(str)  -- Print directly to a screen, or otherwise guarantee that
+                   the user sees str.  raw_print() appends a newline to str.
+                   It need not recognize ASCII control characters.  This is
+                   used during startup (before windowing system initialization
+                   -- maybe this means only error startup messages are raw),
+                   for error messages, and maybe other "msg" uses.  E.g.
+                   updating status for micros (i.e, "saving").
+*/
+void gnome_raw_print(const char *str)
+{
+    tty_raw_print(str);
+}
+
+/*
+raw_print_bold(str)
+                -- Like raw_print(), but prints in bold/standout (if
+possible).
+*/
+void gnome_raw_print_bold(const char *str)
+{
+    tty_raw_print_bold(str);
+}
+
+/*
+int nhgetch()   -- Returns a single character input from the user.
+                -- In the tty window-port, nhgetch() assumes that tgetch()
+                   will be the routine the OS provides to read a character.
+                   Returned character _must_ be non-zero.
+*/
+int gnome_nhgetch()
+{
+    int key;
+    GList *theFirst;
+    gtk_signal_emit (GTK_OBJECT (gnome_windowlist[WIN_STATUS].win),
+                      ghack_signals[GHSIG_FADE_HIGHLIGHT]);
+
+    g_askingQuestion = 1;
+    /* Process events until a key press event arrives. */
+    while ( g_numKeys == 0 ) 
+       gtk_main_iteration();
+    
+    theFirst = g_list_first( g_keyBuffer);
+    g_keyBuffer = g_list_remove_link(g_keyBuffer, theFirst);
+    key = GPOINTER_TO_INT( theFirst->data);
+    g_list_free_1( theFirst);
+    g_numKeys--;
+    g_askingQuestion = 0;
+    return ( key);
+}
+
+/*
+int nh_poskey(int *x, int *y, int *mod)
+                -- Returns a single character input from the user or a
+                   a positioning event (perhaps from a mouse).  If the
+                   return value is non-zero, a character was typed, else,
+                   a position in the MAP window is returned in x, y and mod.
+                   mod may be one of
+
+                        CLICK_1         -- mouse click type 1 
+                        CLICK_2         -- mouse click type 2 
+
+                   The different click types can map to whatever the
+                   hardware supports.  If no mouse is supported, this
+                   routine always returns a non-zero character.
+*/
+int gnome_nh_poskey(int *x, int *y, int *mod)
+{
+    gtk_signal_emit (GTK_OBJECT (gnome_windowlist[WIN_STATUS].win),
+                      ghack_signals[GHSIG_FADE_HIGHLIGHT]);
+    
+    g_askingQuestion = 0;
+    /* Process events until a key or map-click arrives. */
+    while ( g_numKeys == 0 && g_numClicks == 0 )
+       gtk_main_iteration();
+    
+    if (g_numKeys > 0) {
+       int key;
+       GList *theFirst;
+       
+       theFirst = g_list_first( g_keyBuffer);
+       g_keyBuffer = g_list_remove_link(g_keyBuffer, theFirst);
+       key = GPOINTER_TO_INT( theFirst->data);
+       g_list_free_1( theFirst);
+       g_numKeys--;
+       return ( key);
+    }
+    else {
+       GHClick *click;
+       GList *theFirst;
+       
+       theFirst = g_list_first( g_clickBuffer);
+       g_clickBuffer = g_list_remove_link(g_clickBuffer, theFirst);
+       click = (GHClick*) theFirst->data;
+       *x=click->x;
+        *y=click->y;
+        *mod=click->mod;
+       g_free( click);
+       g_list_free_1( theFirst);
+       g_numClicks--;
+       return ( 0);
+    }
+}
+
+/*
+nhbell()        -- Beep at user.  [This will exist at least until sounds are
+                   redone, since sounds aren't attributable to windows anyway.]
+*/
+void gnome_nhbell()
+{
+    /* FIXME!!! Play a cool GNOME sound instead */
+    gdk_beep();
+}
+
+/*
+doprev_message()
+                -- Display previous messages.  Used by the ^P command.
+                -- On the tty-port this scrolls WIN_MESSAGE back one line.
+*/
+int gnome_doprev_message()
+{
+    /* Do Nothing.  They can read old messages using the scrollbar. */
+    return 0;
+}
+
+/*
+char yn_function(const char *ques, const char *choices, char default)
+                -- Print a prompt made up of ques, choices and default.
+                   Read a single character response that is contained in
+                   choices or default.  If choices is NULL, all possible
+                   inputs are accepted and returned.  This overrides
+                   everything else.  The choices are expected to be in
+                   lower case.  Entering ESC always maps to 'q', or 'n',
+                   in that order, if present in choices, otherwise it maps
+                   to default.  Entering any other quit character (SPACE,
+                   RETURN, NEWLINE) maps to default.
+                -- If the choices string contains ESC, then anything after
+                   it is an acceptable response, but the ESC and whatever
+                   follows is not included in the prompt.
+                -- If the choices string contains a '#' then accept a count.
+                   Place this value in the global "yn_number" and return '#'.
+                -- This uses the top line in the tty window-port, other
+                   ports might use a popup.
+*/
+char gnome_yn_function(const char *question, const char *choices,
+               CHAR_P def)
+{
+    int ch;
+    int result=-1;
+    char message[BUFSZ];
+    char yn_esc_map='\033';
+    GtkWidget *mainWnd = ghack_get_main_window();
+    
+    
+    if (choices) {
+       char *cb, choicebuf[QBUFSZ];
+       Strcpy(choicebuf, choices);
+       if ((cb = index(choicebuf, '\033')) != 0) {
+           /* anything beyond <esc> is hidden */
+           *cb = '\0';
+       }
+       sprintf(message, "%s [%s] ", question, choicebuf);
+       if (def) sprintf(eos(message), "(%c) ", def);
+       /* escape maps to 'q' or 'n' or default, in that order */
+       yn_esc_map = (index(choices, 'q') ? 'q' :
+                (index(choices, 'n') ? 'n' : def));
+    } else {
+       Strcpy(message, question);
+    }
+    
+    
+    gnome_putstr(WIN_MESSAGE, ATR_BOLD, message);
+    if (mainWnd != NULL && choices && !index(choices,ch)) {
+       return(ghack_yes_no_dialog( question, choices, def));
+    }
+
+    /* Only here if main window is not present */
+    while (result<0) {
+       ch=gnome_nhgetch();
+       if (ch=='\033') {
+           result=yn_esc_map;
+       } else if (choices && !index(choices,ch)) {
+           /* FYI: ch==-115 is for KP_ENTER */
+           if (def && (ch==' ' || ch=='\r' || ch=='\n' || ch==-115)) {
+               result=def;
+           } else {
+               gnome_nhbell();
+               /* and try again... */
+           }
+       } else {
+           result=ch;
+       }
+    }
+    return result;
+}
+
+/*
+getlin(const char *ques, char *input)
+           -- Prints ques as a prompt and reads a single line of text,
+              up to a newline.  The string entered is returned without the
+              newline.  ESC is used to cancel, in which case the string
+              "\033\000" is returned.
+           -- getlin() must call flush_screen(1) before doing anything.
+           -- This uses the top line in the tty window-port, other
+              ports might use a popup.
+*/
+void gnome_getlin(const char *question, char *input)
+{
+    int ret;
+
+    ret = ghack_ask_string_dialog(question, "", "nethack", input);
+
+    if (ret == -1)
+       input[0] = 0;
+}
+
+/*
+int get_ext_cmd(void)
+           -- Get an extended command in a window-port specific way.
+              An index into extcmdlist[] is returned on a successful
+              selection, -1 otherwise.
+*/
+int gnome_get_ext_cmd()
+{
+    return ghack_menu_ext_cmd();
+}
+
+
+/*
+number_pad(state)
+           -- Initialize the number pad to the given state.
+*/
+void gnome_number_pad(int state)
+{
+    /* Do Nothing */
+}
+
+/*
+delay_output()  -- Causes a visible delay of 50ms in the output.
+              Conceptually, this is similar to wait_synch() followed
+              by a nap(50ms), but allows asynchronous operation.
+*/
+void gnome_delay_output()
+{
+    if (gnome_windowlist[WIN_MESSAGE].win != NULL) {
+       gtk_signal_emit( GTK_OBJECT (gnome_windowlist[WIN_MESSAGE].win),
+       ghack_signals[GHSIG_DELAY],
+       (guint) 50);
+    }
+}
+
+/*
+start_screen()  -- Only used on Unix tty ports, but must be declared for
+              completeness.  Sets up the tty to work in full-screen
+              graphics mode.  Look at win/tty/termcap.c for an
+              example.  If your window-port does not need this function
+              just declare an empty function.
+*/
+void gnome_start_screen()
+{
+    /* Do Nothing */
+}
+
+/*
+end_screen()    -- Only used on Unix tty ports, but must be declared for
+              completeness.  The complement of start_screen().
+*/
+void gnome_end_screen()
+{
+    /* Do Nothing */
+}
+
+/*
+outrip(winid, int)
+           -- The tombstone code.  If you want the traditional code use
+              genl_outrip for the value and check the #if in rip.c.
+*/
+void gnome_outrip(winid wid, int how)
+{
+    /* Follows roughly the same algorithm as genl_outrip() */
+    char buf[BUFSZ];
+    char ripString[BUFSZ]="\0";
+    extern const char *killed_by_prefix[];
+    
+    /* Put name on stone */
+    Sprintf(buf, "%s\n", plname);
+    Strcat(ripString, buf);
+    
+    /* Put $ on stone */
+    Sprintf(buf, "%ld Au\n",
+#ifndef GOLDOBJ
+               u.ugold);
+#else
+               done_money);
+#endif
+    Strcat(ripString, buf);
+
+    /* Put together death description */
+    switch (killer_format) {
+           default: impossible("bad killer format?");
+           case KILLED_BY_AN:
+                   Strcpy(buf, killed_by_prefix[how]);
+                   Strcat(buf, an(killer));
+                   break;
+           case KILLED_BY:
+                   Strcpy(buf, killed_by_prefix[how]);
+                   Strcat(buf, killer);
+                   break;
+           case NO_KILLER_PREFIX:
+                   Strcpy(buf, killer);
+                   break;
+    }
+    /* Put death type on stone */
+    Strcat(ripString, buf);
+    Strcat(ripString, "\n");
+
+    /* Put year on stone */
+    Sprintf(buf, "%4d\n", getyear());
+    Strcat(ripString, buf);
+
+    ghack_text_window_rip_string( ripString);
+}
diff --git a/win/gnome/gnbind.h b/win/gnome/gnbind.h
new file mode 100644 (file)
index 0000000..cca6429
--- /dev/null
@@ -0,0 +1,94 @@
+/*     SCCS Id: @(#)gnbind.h   3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackBind_h
+#define GnomeHackBind_h
+
+/*
+ * This header files defines the interface between the window port specific
+ * code in the Gnome port and the rest of the nethack game engine. 
+*/
+
+#include <gnome.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "gnomeprv.h"
+#include "gnmain.h"
+#include "gnmap.h"
+#include "gnmenu.h"
+#include "gnplayer.h"
+#include "gnsignal.h"
+#include "gnstatus.h"
+#include "gntext.h"
+#include "gnmesg.h"
+#include "gnyesno.h"
+#include "gnglyph.h"
+#include "gnworn.h"
+
+
+/* Create an array to keep track of the various windows */
+
+#ifndef MAXWINDOWS
+#define MAXWINDOWS 15
+#endif
+
+typedef struct gnome_nhwindow_data {
+  GtkWidget*  win;
+  int         type;
+} GNHWinData;
+
+
+/* Some prototypes */
+void gnome_init_nhwindows(int* argc, char** argv);
+void gnome_player_selection(void);
+void gnome_askname(void);
+void gnome_get_nh_event(void);
+void gnome_exit_nhwindows(const char *);
+void gnome_suspend_nhwindows(const char *);
+void gnome_resume_nhwindows(void);
+winid gnome_create_nhwindow(int type);
+void gnome_create_nhwindow_by_id(int type, winid i);
+void gnome_clear_nhwindow(winid wid);
+void gnome_display_nhwindow(winid wid, BOOLEAN_P block);
+void gnome_destroy_nhwindow(winid wid);
+void gnome_curs(winid wid, int x, int y);
+void gnome_putstr(winid wid, int attr, const char *text);
+void gnome_display_file(const char *filename,BOOLEAN_P must_exist);
+void gnome_start_menu(winid wid);
+void gnome_add_menu(winid wid, int glyph, const ANY_P * identifier,
+               CHAR_P accelerator, CHAR_P group_accel, int attr, 
+               const char *str, BOOLEAN_P presel);
+void gnome_end_menu(winid wid, const char *prompt);
+int  gnome_select_menu(winid wid, int how, MENU_ITEM_P **selected);
+/* No need for message_menu -- we'll use genl_message_menu instead */  
+void gnome_update_inventory(void);
+void gnome_mark_synch(void);
+void gnome_wait_synch(void);
+void gnome_cliparound(int x, int y);
+/* The following function does the right thing.  The nethack
+ * gnome_cliparound (which lacks the winid) simply calls this funtion.
+*/
+void gnome_cliparound_proper(winid wid, int x, int y);
+void gnome_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph);
+void gnome_raw_print(const char *str);
+void gnome_raw_print_bold(const char *str);
+int  gnome_nhgetch(void);
+int  gnome_nh_poskey(int *x, int *y, int *mod);
+void gnome_nhbell(void);
+int  gnome_doprev_message(void);
+char gnome_yn_function(const char *question, const char *choices,
+               CHAR_P def);
+void gnome_getlin(const char *question, char *input);
+int  gnome_get_ext_cmd(void);
+void gnome_number_pad(int state);
+void gnome_delay_output(void);
+void gnome_start_screen(void);
+void gnome_end_screen(void);
+void gnome_outrip(winid wid, int how);
+void gnome_delete_nhwindow_by_reference( GtkWidget *menuWin);
+
+
+#endif /* GnomeHackBind_h */
+
+
diff --git a/win/gnome/gnglyph.c b/win/gnome/gnglyph.c
new file mode 100644 (file)
index 0000000..bb08abc
--- /dev/null
@@ -0,0 +1,230 @@
+/*     SCCS Id: @(#)gnglyph.c  3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "gnglyph.h"
+#include "tile2x11.h"
+
+/* from tile.c */
+extern int total_tiles_used;
+
+static GHackGlyphs     ghack_glyphs;
+static GdkImlibImage** ghack_tiles = NULL;
+
+/* NAME:
+ *     ghack_init_glyphs(char* xpm_file)
+ *
+ * ARGUMENTS:
+ *     char *xpm_file -- The name of the image file.
+ *                       May be any image format imlib recognizes.
+ *                      Does not have to be XPM.
+ *
+ * RETURNS:
+ *     TRUE  upon successful loading of the glyphs.
+ *     FALSE upon failure.
+ *
+ * PURPOSE:
+ *     Constructor for the Glyph object.  Well, really each glyph
+ *     object is a collection of glyphs, or tiles.  This constructor
+ *     takes a single argument: the name of the image file that contains
+ *     the tile images.
+ *
+ * NOTES:
+ *     The glyphs (tiles) must be in the image in a certain way: the
+ *     glyphs must be stacked such that the resultant image is
+ *     TILE_X * TILES_PER_ROW wide, and
+ *     TILE_Y * (number of glyphs) / TILES_PER_ROW high (rounded up).
+ *     In this sense, TILE_X == TILE_Y, and can be any reasonable integer
+ *     say, 16 <= TILE_X <= 64.  Because the glyph number is tightly
+ *     coupled to the Nethack object it represents, the order of the
+ *     glyphs in the image is imporant: Glyph 1 is at the top of the
+ *     image, while Glyph N (the last glyph) is at the bottom.
+ *
+ *     What's the difference between a glyph and a tile?  Well, a
+ *     tile is just an image.  A glyph is a tile that knows its
+ *     place in line.
+ *
+ *     This initializer relies heavily on gdk_imlib.  Thanks, Rasterman.
+ */
+
+int
+ghack_init_glyphs(const char *xpmFile)
+{
+    ghack_glyphs.im = gdk_imlib_load_image((char *) xpmFile);
+    if ( ! ghack_glyphs.im ) {
+       g_error("Couldn't load required xpmFile!");
+       return -1;
+    }
+
+    gdk_imlib_render(ghack_glyphs.im, ghack_glyphs.im->rgb_width,
+                    ghack_glyphs.im->rgb_height);
+
+    if ((ghack_glyphs.im->rgb_width % TILES_PER_ROW) != 0 ||
+       ghack_glyphs.im->rgb_width <= TILES_PER_ROW) {
+       g_error("%s is not a multiple of %d (number of tiles/row) pixels wide",
+               xpmFile, TILES_PER_ROW);
+       return -1;
+    }
+    ghack_glyphs.count = total_tiles_used;
+    if ((ghack_glyphs.count % TILES_PER_ROW) != 0) {
+       ghack_glyphs.count +=
+           TILES_PER_ROW - (ghack_glyphs.count % TILES_PER_ROW);
+    }
+    ghack_glyphs.width = ghack_glyphs.im->rgb_width / TILES_PER_ROW;
+    ghack_glyphs.height =
+       ghack_glyphs.im->rgb_height / (ghack_glyphs.count / TILES_PER_ROW);
+
+
+    /* Assume the tiles are organized in rows of TILES_PER_ROW */
+    ghack_tiles = g_new0( GdkImlibImage*, ghack_glyphs.count );
+    return (ghack_tiles == NULL) ? -1 : 0;
+}
+
+void
+ghack_free_glyphs( )
+{
+    int i;
+    for ( i=0 ; i<ghack_glyphs.count ; i++)
+       gdk_imlib_destroy_image(ghack_tiles[i]);
+    g_free( ghack_tiles);
+    gdk_imlib_destroy_image(ghack_glyphs.im);
+    ghack_glyphs.im=NULL;
+}
+
+
+/* NAME:
+ *     ghack_glyph_count( )
+ *
+ * ARGUMENTS:
+ *     None.
+ *
+ * RETURNS:
+ *     int -- The number of glyphs in this object.
+ *
+ * PURPOSE:
+ *     Simply reports the number of glyphs in this object.
+ */
+
+int
+ghack_glyph_count( )
+{
+  return ghack_glyphs.count;
+}
+
+
+/* NAME:
+ *     ghack_glyph_height()
+ *
+ * ARGUMENTS:
+ *     None
+ *
+ * RETURNS:
+ *     int -- The glyph height.
+ *
+ * PURPOSE:
+ *     Returns the standard glyph height.
+ */
+
+int
+ghack_glyph_height()
+{
+  return ghack_glyphs.height;
+}
+
+
+/* NAME:
+ *     ghack_glyph_width()
+ *
+ * ARGUMENTS:
+ *     None
+ *
+ * RETURNS:
+ *     int -- The glyph width.
+ *
+ * PURPOSE:
+ *     Returns the standard glyph width.
+ */
+
+int
+ghack_glyph_width()
+{
+  return ghack_glyphs.width;
+}
+
+
+/* NAME:
+ *     ghack_image_from_glyph( int glyph, gboolean force)
+ *
+ * ARGUMENTS:
+ *     int glyph  -- The glyph number.
+ *     gboolean force -- force it to re-render.
+ *
+ * RETURNS:
+ *     GdkImlibImage* -- The glyph image, as a GdkImlibImage.
+ *
+ * PURPOSE:
+ *     Decodes the glyph into an image suitable for manipulation
+ */
+
+GdkImlibImage*
+ghack_image_from_glyph( int glyph, gboolean force )
+{
+  int tile = glyph2tile[glyph];
+
+  if ( tile >= ghack_glyphs.count || tile < 0 )
+    {
+      g_warning("Aiiee! I've was asked for a tile outside the allowed range!\n"
+           "Email this to other-gnomehack@lists.debian.org");
+      g_warning("Max tile: %d   Tile asked for: %d",
+               ghack_glyphs.count, tile);
+      return NULL;
+    }
+
+  if (ghack_glyphs.im == NULL)
+    {
+    g_warning("Aiiee! I've been asked to clone from a null image.\n"
+           "Email this to other-gnomehack@lists.debian.org");
+    g_warning( "making image from tile %d, force=%s\n", tile,
+           (force==TRUE)? "TRUE": "FALSE");
+    }
+
+  if (force == TRUE)
+    {
+    g_warning("Aiiee! I've been asked to force rendering.\n"
+           "Email this to other-gnomehack@lists.debian.org");
+    g_warning( "making image from tile %d, force=%s\n", tile,
+           (force==TRUE)? "TRUE" : "FALSE");
+    }
+
+  if (!ghack_tiles[tile] || force) {
+      int src_x, src_y;
+#if 0
+      fprintf( stderr, "crop_and_clone: glyph=%d, tile=%d, ptr=%p, x=%d, y=%d, w=%d, h=%d\n", glyph, tile,
+             (void*)&(ghack_tiles[tile]), 0,
+             tile * ghack_glyphs.width,
+             ghack_glyphs.height,
+             ghack_glyphs.width);
+#endif
+      if (ghack_glyphs.im->pixmap == NULL)
+         g_warning( "Aiiee!  ghack_glyphs.im->pixmap==NULL!!!!\n");
+      src_x = (tile % TILES_PER_ROW) * ghack_glyphs.width;
+      src_y = (tile / TILES_PER_ROW) * ghack_glyphs.height;
+      ghack_tiles[tile] = gdk_imlib_crop_and_clone_image(ghack_glyphs.im,
+             src_x, src_y,
+             ghack_glyphs.width,
+             ghack_glyphs.height);
+  }
+
+  if (ghack_tiles[tile] && (!ghack_tiles[tile]->pixmap || force))
+  {
+      if ( gdk_imlib_render(ghack_tiles[tile],
+                 ghack_tiles[tile]->rgb_width,
+                 ghack_tiles[tile]->rgb_height) == 0) {
+         g_error("GLYPH: couldn't create tile # %d", tile);
+      }
+      if ( !ghack_tiles[tile]->pixmap )
+         g_error("Strange, tile # %d didn't get rendered???", tile);
+  }
+
+  return ghack_tiles[tile];
+}
diff --git a/win/gnome/gnglyph.h b/win/gnome/gnglyph.h
new file mode 100644 (file)
index 0000000..e2b30da
--- /dev/null
@@ -0,0 +1,42 @@
+/*     SCCS Id: @(#)gnglyph.h  3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackGlyph_h
+#define GnomeHackGlyph_h
+
+#include "config.h"
+#include "global.h"
+
+/* the prototypes in system headers contain useless argument names
+   that trigger spurious warnings if gcc's `-Wshadow' option is used */
+#undef index
+#define index _hide_index_
+#define time  _hide_time_
+
+#include <gdk_imlib.h>
+#include <gdk/gdk.h>
+
+#undef index
+#define index strchr
+#undef time
+
+
+extern short glyph2tile[];     /* From tile.c */
+
+typedef struct {
+  GdkImlibImage* im;
+  int            count;
+  int            width;
+  int            height;
+} GHackGlyphs;
+
+extern int            ghack_init_glyphs( const char *);
+extern void           ghack_free_glyphs( void);
+extern void           ghack_dispose_glyphs( void);
+extern int            ghack_glyph_count( void);
+extern GdkImlibImage* ghack_image_from_glyph( int, gboolean);
+extern int            ghack_glyph_height( void);
+extern int            ghack_glyph_width( void);
+
+#endif  /* GnomeHackGlyph_h */
diff --git a/win/gnome/gnmain.c b/win/gnome/gnmain.c
new file mode 100644 (file)
index 0000000..98b2f91
--- /dev/null
@@ -0,0 +1,839 @@
+/*     SCCS Id: @(#)gnmain.c   3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "gnmain.h"
+#include "gnsignal.h"
+#include "gnbind.h"
+#include "gnopts.h"
+#include <gnome.h>
+#include <getopt.h>
+#include <gdk/gdk.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <signal.h>
+#include "hack.h"
+#include "date.h"
+
+static GtkWidget* mainWindow=NULL;
+static GtkWidget *about=NULL;
+static GtkWidget* hBoxFirstRow;
+static GtkWidget* vBoxMain;
+
+int restarted = 0;
+int os_x = 0, os_y = 0, os_w = 0, os_h = 0;
+
+
+static GnomeClient *session_id;
+
+static
+void ghack_quit_game(GtkWidget *widget, int button)
+{
+    gtk_widget_hide(widget);
+    if (button == 0) {
+       gnome_exit_nhwindows(0);
+       gtk_object_unref(GTK_OBJECT(session_id));
+    }
+}
+
+static
+void ghack_quit_game_cb(GtkWidget *widget, gpointer data)
+{
+    GtkWidget *box;
+    box = gnome_message_box_new(_("Do you really want to quit?"), 
+           GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES, 
+           GNOME_STOCK_BUTTON_NO, NULL);
+    gnome_dialog_set_default( GNOME_DIALOG(box), 1);
+    gnome_dialog_set_parent (GNOME_DIALOG (box), 
+           GTK_WINDOW (ghack_get_main_window ()) );
+    gnome_dialog_set_accelerator (GNOME_DIALOG(box), 1, 'n', 0);
+    gnome_dialog_set_accelerator (GNOME_DIALOG(box), 0, 'y', 0);
+
+    gtk_window_set_modal( GTK_WINDOW(box), TRUE);
+    gtk_signal_connect( GTK_OBJECT(box), "clicked", 
+           (GtkSignalFunc)ghack_quit_game, NULL);
+    gtk_widget_show(box);
+}
+
+static
+void ghack_save_game(GtkWidget *widget, int button)
+{
+    gtk_widget_hide(widget);
+    if (button == 0) {
+       if(dosave0()) {
+           /* make sure they see the Saving message */
+           display_nhwindow(WIN_MESSAGE, TRUE);
+           gnome_exit_nhwindows("Be seeing you...");
+       } else (void)doredraw();
+    }
+}
+
+void ghack_save_game_cb(GtkWidget *widget, gpointer data)
+{
+    GtkWidget *box;
+    box = gnome_message_box_new(_("Quit and save the current game?"), 
+           GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES, 
+           GNOME_STOCK_BUTTON_NO, NULL);
+    gnome_dialog_set_default( GNOME_DIALOG(box), 1);
+    gnome_dialog_set_parent (GNOME_DIALOG (box), 
+           GTK_WINDOW (ghack_get_main_window ()) );
+    gnome_dialog_set_accelerator (GNOME_DIALOG(box), 1, 'n', 0);
+    gnome_dialog_set_accelerator (GNOME_DIALOG(box), 0, 'y', 0);
+
+    gtk_window_set_modal( GTK_WINDOW(box), TRUE);
+    gtk_signal_connect( GTK_OBJECT(box), "clicked", 
+           (GtkSignalFunc)ghack_save_game, NULL);
+    gtk_widget_show(box);
+}
+
+static
+void ghack_new_game(GtkWidget *widget, int button)
+{
+    if (button == 0) {
+       g_message("This feature is not yet implemented.  Sorry.");
+    }
+}
+
+static
+void ghack_new_game_cb(GtkWidget *widget, gpointer data)
+{
+    GtkWidget *box;
+    box = gnome_message_box_new(_("Start a new game?"), 
+           GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES, 
+           GNOME_STOCK_BUTTON_NO, NULL);
+    gnome_dialog_set_default( GNOME_DIALOG(box), 1);
+    gnome_dialog_set_parent (GNOME_DIALOG (box), 
+           GTK_WINDOW (ghack_get_main_window ()) );
+    gnome_dialog_set_accelerator (GNOME_DIALOG(box), 1, 'n', 0);
+    gnome_dialog_set_accelerator (GNOME_DIALOG(box), 0, 'y', 0);
+
+    gtk_window_set_modal( GTK_WINDOW(box), TRUE);
+    gtk_signal_connect( GTK_OBJECT(box), "clicked", 
+           (GtkSignalFunc)ghack_new_game, NULL);
+    gtk_widget_show(box);
+}
+
+static void
+about_destroy_callback (void)
+{
+    about = NULL;
+}
+
+static void 
+ghack_about_cb(GtkWidget *widget, gpointer data)
+{
+    char buf[BUFSZ]="\0";
+    char buf1[BUFSZ]="\0";
+    const gchar *authors[] = {"Erik Andersen", "Anthony Taylor", 
+       "Jeff Garzik", "The Nethack Dev Team", NULL};
+
+    if (about) {
+       gdk_window_raise (about->window);
+       return;
+    }
+
+    getversionstring(buf);
+    strcat( buf1, VERSION_STRING);
+    strcat( buf, 
+      _("\nSend comments and bug reports to: nethack-bugs@nethack.org\n"
+      "This game is free software. See License for details."));
+    about = gnome_about_new(_("Nethack"), 
+           buf1, "Copyright (C) 1985-2002 Mike Stephenson",
+           (const char **)authors, buf,
+           NULL);
+
+    gtk_signal_connect (GTK_OBJECT (about), "destroy",
+       (GtkSignalFunc) about_destroy_callback, NULL);
+    
+    gtk_widget_show(about);
+}
+
+static void 
+ghack_settings_cb(GtkWidget *widget, gpointer data)
+{
+    ghack_settings_dialog();
+}
+
+static void 
+ghack_accelerator_selected (GtkWidget *widget, gpointer data)
+{
+    GdkEventKey event;
+    int key = GPOINTER_TO_INT( data); 
+    /* g_message("An accelerator for \"%c\" was selected", key); */
+    /* stuff a key directly into the keybuffer */
+    event.state=0;
+    event.keyval=key;
+    ghack_handle_key_press(NULL, &event, NULL);
+}
+
+#ifndef M
+# ifndef NHSTDC
+#  define M(c)          (0x80 | (c))
+# else
+#  define M(c)          ((c) - 128)
+# endif /* NHSTDC */
+#endif
+#ifndef C
+#define C(c)            (0x1f & (c))
+#endif
+
+
+GnomeUIInfo game_tree[] = 
+{
+    {
+       GNOME_APP_UI_ITEM, N_ ("_Change Settings..."), 
+       N_("Change Game Settings"), ghack_settings_cb, NULL, NULL, 
+       GNOME_APP_PIXMAP_NONE, NULL, 0,0, NULL
+    },
+    GNOMEUIINFO_SEPARATOR,
+    { 
+       GNOME_APP_UI_ITEM, N_("Version"), NULL, 
+       ghack_accelerator_selected, GINT_TO_POINTER('v'), NULL, 
+       GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'v',0 
+    }, 
+    { 
+       GNOME_APP_UI_ITEM, N_("History..."), NULL, 
+       ghack_accelerator_selected, GINT_TO_POINTER('V'), NULL, 
+       GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'V',GDK_SHIFT_MASK 
+    }, 
+    { 
+       GNOME_APP_UI_ITEM, N_("Compilation..."), NULL, 
+       ghack_accelerator_selected, GINT_TO_POINTER(M('v')), NULL, 
+       GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT,'v',GDK_MOD1_MASK
+    }, 
+    { 
+       GNOME_APP_UI_ITEM, N_("Options..."), NULL, 
+       ghack_accelerator_selected, GINT_TO_POINTER('O'), NULL, 
+       GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PREF, 'O', GDK_SHIFT_MASK
+    }, 
+    { 
+       GNOME_APP_UI_ITEM, N_("Explore Mode..."), NULL, 
+       ghack_accelerator_selected, GINT_TO_POINTER('X'), NULL, 
+       GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_QUIT, 'X', GDK_SHIFT_MASK
+    }, 
+    GNOMEUIINFO_SEPARATOR,
+    GNOMEUIINFO_MENU_NEW_GAME_ITEM(ghack_new_game_cb, NULL),
+    GNOMEUIINFO_MENU_SAVE_ITEM(ghack_save_game_cb, NULL),
+    { 
+       GNOME_APP_UI_ITEM, N_("Exit"), NULL, 
+       ghack_quit_game_cb, GINT_TO_POINTER(M('Q')), NULL, 
+       GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'Q', GDK_MOD1_MASK
+    }, 
+    GNOMEUIINFO_END
+};
+
+
+
+GnomeUIInfo edit_menu[] = {
+          { 
+              GNOME_APP_UI_ITEM, N_("Inventory"), 
+              N_("Edit/View your Inventory"), ghack_accelerator_selected, 
+              GINT_TO_POINTER('i'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'i', 0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Discoveries"), 
+              N_("Edit/View your Discoveries"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('\\'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '\\',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("List/reorder your spells"), 
+              N_("List/reorder your spells"), ghack_accelerator_selected, 
+              GINT_TO_POINTER('x'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'x', 0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Adjust letters"), 
+              N_("Adjust letter for items in your Inventory"), ghack_accelerator_selected, 
+               GINT_TO_POINTER(M('a')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'a', GDK_MOD1_MASK
+          },
+          GNOMEUIINFO_SEPARATOR,
+          { 
+              GNOME_APP_UI_ITEM, N_("Name object"), 
+              N_("Assign a name to an object"), ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('n')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'n', GDK_MOD1_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Name creature"), 
+              N_("Assign a name to a creature"), ghack_accelerator_selected, 
+              GINT_TO_POINTER('C'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'C', GDK_SHIFT_MASK
+          },
+          GNOMEUIINFO_SEPARATOR,
+          { 
+              GNOME_APP_UI_ITEM, N_("Qualifications"), 
+              N_("Edit your Qualifications"), ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('e')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'e',GDK_MOD1_MASK
+          },
+           GNOMEUIINFO_END
+};
+
+
+GnomeUIInfo apparel_menu[] = {
+          { 
+              GNOME_APP_UI_ITEM, N_("Wield Weapon"), 
+              N_("Select a weapon to fight with"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('w'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'w',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Remove Apparel..."), 
+              N_("Remove apparel dialog bog"), ghack_accelerator_selected, 
+              GINT_TO_POINTER('A'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'A',GDK_SHIFT_MASK
+          },
+          GNOMEUIINFO_SEPARATOR,
+          { 
+              GNOME_APP_UI_ITEM, N_("Wear Armor"), 
+              N_("Put on armor"), ghack_accelerator_selected, 
+              GINT_TO_POINTER('W'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'W',GDK_SHIFT_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Take off Armor"), 
+              N_("Take off armor you are wearing"), ghack_accelerator_selected, 
+              GINT_TO_POINTER('T'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'T',GDK_SHIFT_MASK
+          },
+          GNOMEUIINFO_SEPARATOR,
+          { 
+              GNOME_APP_UI_ITEM, N_("Put on non-armor"), 
+              N_("Put on non-armor apparel"), ghack_accelerator_selected, 
+              GINT_TO_POINTER('P'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'P',GDK_SHIFT_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Remove non-armor"), 
+              N_("Remove non-armor apparel you are wearing"), ghack_accelerator_selected, 
+              GINT_TO_POINTER('R'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'R',GDK_SHIFT_MASK
+          },
+           GNOMEUIINFO_END
+};
+
+GnomeUIInfo action_menu[] = {
+          { 
+              GNOME_APP_UI_ITEM, N_("Get"), 
+              N_("Pick up things at the current location"), 
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(','), NULL, GNOME_APP_PIXMAP_NONE, NULL, ',',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Loot"), 
+              N_("loot a box on the floor"), 
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('l')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'l',GDK_MOD1_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Sit"), 
+              N_("sit down"), 
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('s')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 's',GDK_MOD1_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Force"), 
+              N_("force a lock"), 
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('f')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'f',GDK_MOD1_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Kick"), 
+              N_("kick something (usually a door)"), 
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(C('d')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'd',GDK_CONTROL_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Jump"), 
+              N_("jump to another location"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('j')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'j',GDK_MOD1_MASK
+          },
+#ifdef STEED
+          { 
+              GNOME_APP_UI_ITEM, N_("Ride"), 
+              N_("Ride (or stop riding) a monster"),
+              doride, 
+              GINT_TO_POINTER(M('r')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'R',GDK_MOD1_MASK
+          },
+#endif
+          { 
+              GNOME_APP_UI_ITEM, N_("Wipe face"), 
+              N_("wipe off your face"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('w')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'w',GDK_MOD1_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Throw/Shoot"), 
+              N_("throw or shoot a weapon"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('t'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 't',0
+          },
+          {
+              GNOME_APP_UI_ITEM, N_("Quiver/Ready"),
+              N_("ready or quiver some ammunition"),
+              ghack_accelerator_selected,
+              GINT_TO_POINTER('Q'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'Q',GDK_SHIFT_MASK,
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Open Door"), 
+              N_("open a door"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('o'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'o',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Close Door"), 
+              N_("open a door"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('c'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'c',0
+          },
+          GNOMEUIINFO_SEPARATOR,
+          { 
+              GNOME_APP_UI_ITEM, N_("Drop"), 
+              N_("drop an object"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('d'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'd',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Drop Many"), 
+              N_("drop selected types of objects"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('D'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'D',GDK_SHIFT_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Eat"), 
+              N_("eat something"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('e'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'e',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Engrave"), 
+              N_("write a message in the dust on the floor"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('E'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'E',GDK_SHIFT_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Apply"), 
+              N_("apply or use a tool (pick-axe, key, camera, etc.)"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('a'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'a',0
+          },
+          GNOMEUIINFO_SEPARATOR,
+          { 
+              GNOME_APP_UI_ITEM, N_("Up"), 
+              N_("go up the stairs"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('<'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '<',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Down"), 
+              N_("go down the stairs"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('>'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '>',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Rest"), 
+              N_("wait for a moment"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('.'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '.',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Search"), 
+              N_("search for secret doors, hidden traps and monsters"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('s'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 's',0
+          },
+          GNOMEUIINFO_SEPARATOR,
+          { 
+              GNOME_APP_UI_ITEM, N_("Chat"), 
+              N_("talk to someone"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('c')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'c',GDK_MOD1_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Pay"), 
+              N_("pay your bill to the shopkeeper"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('p'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'p',0
+          },
+           GNOMEUIINFO_END
+};
+
+GnomeUIInfo magic_menu[] = {
+          { 
+              GNOME_APP_UI_ITEM, N_("Quaff potion"), 
+              N_("drink a potion"), 
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('q'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'q',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Read Book/Scroll"), 
+              N_("read a spell book or a scroll"), 
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('r'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'r',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Zap Wand"), 
+              N_("zap a wand"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('z'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'z',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Zap Spell"), 
+              N_("cast a spell"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('Z'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'Z',GDK_SHIFT_MASK
+          },
+          GNOMEUIINFO_SEPARATOR,
+          { 
+              GNOME_APP_UI_ITEM, N_("Dip"), 
+              N_("dip an object into something"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('d')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'd',GDK_MOD1_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Rub"), 
+              N_("Rub something (i.e. a lamp)"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('r')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'r',GDK_MOD1_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Invoke"), 
+              N_("invoke an object's special powers"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('i')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'i',GDK_MOD1_MASK
+          },
+          GNOMEUIINFO_SEPARATOR,
+          { 
+              GNOME_APP_UI_ITEM, N_("Offer"), 
+              N_("offer a sacrifice to the gods"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('o')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'o',GDK_MOD1_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Pray"), 
+              N_("pray to the gods for help"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('p')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'p',GDK_MOD1_MASK
+          },
+          GNOMEUIINFO_SEPARATOR,
+          { 
+              GNOME_APP_UI_ITEM, N_("Teleport"), 
+              N_("teleport (if you can)"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(C('t')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 't',GDK_CONTROL_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Monster Action"), 
+              N_("use a monster's special ability"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('m')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'm',GDK_MOD1_MASK
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Turn Undead"), 
+              N_("turn undead"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(M('t')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 't',GDK_MOD1_MASK
+          },
+           GNOMEUIINFO_END
+};
+
+GnomeUIInfo help_menu[] = {
+            { 
+               GNOME_APP_UI_ITEM, N_("About..."), 
+               N_("About GnomeHack"), ghack_about_cb, NULL, NULL, 
+               GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 0, 0, NULL 
+           }, 
+          { 
+              GNOME_APP_UI_ITEM, N_("Help"), NULL,
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('?'), NULL, GNOME_APP_PIXMAP_STOCK, 
+              GNOME_STOCK_MENU_ABOUT, '?', 0
+          },
+          GNOMEUIINFO_SEPARATOR,
+          { 
+              GNOME_APP_UI_ITEM, N_("What is here"), 
+              N_("Check what items occupy the current location"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(':'), NULL, GNOME_APP_PIXMAP_STOCK, 
+              GNOME_STOCK_MENU_ABOUT, ':',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("What is that"), 
+              N_("Identify an object"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER(';'), NULL, GNOME_APP_PIXMAP_STOCK, 
+              GNOME_STOCK_MENU_ABOUT, ';',0
+          },
+          { 
+              GNOME_APP_UI_ITEM, N_("Identify a map symbol"), 
+              N_("Identify a map symbol"),
+              ghack_accelerator_selected, 
+              GINT_TO_POINTER('/'), NULL, GNOME_APP_PIXMAP_STOCK, 
+              GNOME_STOCK_MENU_ABOUT, '/',0
+          },
+          GNOMEUIINFO_END 
+};
+           
+GnomeUIInfo mainmenu[] = {
+           GNOMEUIINFO_MENU_GAME_TREE(game_tree),
+           GNOMEUIINFO_MENU_EDIT_TREE(edit_menu),
+           { GNOME_APP_UI_SUBTREE, N_("Apparel"), NULL, apparel_menu, NULL, 
+               NULL, 0, NULL, 0, 0, NULL },
+           { GNOME_APP_UI_SUBTREE, N_("Action"), NULL, action_menu, NULL, 
+               NULL, 0, NULL, 0, 0, NULL },
+           { GNOME_APP_UI_SUBTREE, N_("Magic"), NULL, magic_menu, NULL, 
+               NULL, 0, NULL, 0, 0, NULL },
+           GNOMEUIINFO_MENU_HELP_TREE(help_menu),
+           GNOMEUIINFO_END
+};
+
+static void
+ghack_main_window_key_press(GtkWidget *widget, GdkEventKey *event, 
+       gpointer data)
+{
+    /* First, turn off the key press propogation.  We've got the
+     * key, but we don't wan't the underlying Gtk widgets to get it,
+     * since they do the wrong thing with the arrow keys (shift focus)... */
+    gtk_signal_emit_stop_by_name( GTK_OBJECT(mainWindow), "key_press_event");
+    
+    /* stuff the key event into the keybuffer */
+    ghack_handle_key_press(widget, event, data);
+}
+
+
+/* parsing args */
+void
+parse_args (int argc, char *argv[])
+{
+  gint ch;
+
+  struct option options[] = {
+       /* Default args */
+       { "help",               no_argument,            NULL,   'h'     },
+       { "version",            no_argument,            NULL,   'v'     },
+
+       { NULL, 0, NULL, 0 }
+       };
+
+  gchar *id = NULL;
+
+  /* initialize getopt */
+  optarg = NULL;
+  optind = 0;
+  optopt = 0;
+
+  while( (ch = getopt_long(argc, argv, "hv", options, NULL)) != EOF )
+  {
+    switch(ch)
+    {
+      case 'h':
+        g_print ( 
+         _("%s: A gnomified 'Hello World' program\n\n"
+           "Usage: %s [--help] [--version]\n\n"
+           "Options:\n"
+           "        --help     display this help and exit\n"
+           "        --version  output version information and exit\n"),
+           argv[0], argv[0]);
+        exit(0);
+        break;
+      case 'v':
+        g_print (_("NetHack %s.\n"), VERSION_STRING);
+        exit(0);
+        break;
+      case ':':
+      case '?':
+        g_print (_("Options error\n"));
+        exit(0);
+        break;
+    }
+  }
+
+  /* SM stuff */
+  session_id = gnome_client_new ();
+#if 0
+  session_id = gnome_client_new (
+       /* callback to save the state and parameter for it */
+       save_state, argv[0], 
+       /* callback to die and parameter for it */
+       NULL, NULL,
+       /* id from the previous session if restarted, NULL otherwise */
+               id);
+#endif
+  /* set the program name */
+  gnome_client_set_program (session_id, argv[0]);
+  g_free(id);
+
+  return;
+}
+
+/*
+ * [ALI] Gnome installs its own handler(s) for SIGBUS, SIGFPE and SIGSEGV.
+ * These handlers will fork and exec a helper program. When that helper
+ * comes to initialize GTK+, it may fail if setuid/setgid. We solve this
+ * by dropping privileges before passing the signal along the chain.
+ * Note: We don't need to either drop or mask the saved ID since this
+ * will be reset when the child process performs the execve() anyway.
+ */
+
+static struct {
+    int signum;
+    void (*handler)(int);
+} ghack_chain[] = {
+    {SIGBUS},
+    {SIGFPE},
+    {SIGSEGV},
+    {SIGILL}           /* Not currently handled by Gnome */
+};
+
+static void ghack_sig_handler(int signum)
+{
+    int i;
+    uid_t uid, euid;
+    gid_t gid, egid;
+    uid = getuid();
+    euid = geteuid();
+    gid = getgid();
+    egid = getegid();
+    if (gid != egid)
+       setgid(gid);
+    if (uid != euid)
+       setuid(uid);
+    for(i = SIZE(ghack_chain) - 1; i >= 0; i--)
+       if (ghack_chain[i].signum == signum) {
+           ghack_chain[i].handler(signum);
+           break;
+       }
+    if (i < 0)
+       impossible("Unhandled ghack signal");
+    if (uid != euid)
+       setuid(euid);
+    if (gid != egid)
+       setgid(egid);
+}
+
+/* initialize gnome and fir up the main window */
+void ghack_init_main_window( int argc, char** argv)
+{
+    int i;
+    struct timeval tv;
+    uid_t uid, euid;
+
+    /* It seems that the authors of gnome_score_init() drop group
+     * priveledges.  We need group priveledges, so until we change the
+     * way we save games to do things the gnome way(???), this stays
+     * commented out.  (after hours of frusteration...)
+     *  -Erik
+     */
+    /* gnome_score_init("gnomehack"); */
+
+    gettimeofday(&tv, NULL);
+    srand(tv.tv_usec);
+
+    uid = getuid();
+    euid = geteuid();
+    if (uid != euid)
+      setuid(uid);
+    hide_privileges(TRUE);
+    /* XXX gnome_init must print nethack options for --help, but does not */
+    gnome_init ("nethack", VERSION_STRING, argc, argv);
+    hide_privileges(FALSE);
+    parse_args (argc, argv);
+
+    /* Initialize the i18n stuff (not that gnomehack supperts it yet...) */
+#if 0
+    textdomain (PACKAGE);
+#endif
+    gdk_imlib_init();
+
+    /* Main window */
+    mainWindow = gnome_app_new((char *) "nethack", 
+           (char *) N_("Nethack for Gnome"));
+    gtk_widget_realize(mainWindow);
+    if (restarted) {
+       gtk_widget_set_uposition (mainWindow, os_x, os_y);
+       gtk_widget_set_usize     (mainWindow, os_w, os_h);
+    }
+    gtk_window_set_default_size( GTK_WINDOW(mainWindow), 800, 600);
+    gtk_window_set_policy(GTK_WINDOW(mainWindow), FALSE, TRUE, TRUE);
+    gnome_app_create_menus(GNOME_APP(mainWindow), mainmenu);
+    gtk_signal_connect(GTK_OBJECT(mainWindow), "key_press_event", 
+           GTK_SIGNAL_FUNC(ghack_main_window_key_press), NULL);
+    gtk_signal_connect(GTK_OBJECT(mainWindow), "delete_event", 
+           GTK_SIGNAL_FUNC(ghack_quit_game_cb), NULL);
+
+    /* Put some stuff into our main window */
+    vBoxMain = gtk_vbox_new (FALSE, 0);
+    hBoxFirstRow = gtk_hbox_new (FALSE, 0);
+   
+    /* pack Boxes into other boxes to produce the right structure */
+    gtk_box_pack_start (GTK_BOX (vBoxMain), hBoxFirstRow, FALSE, TRUE, 0);   
+    
+    /* pack vBoxMain which contains all our widgets into the main window. */
+    gnome_app_set_contents(GNOME_APP(mainWindow), vBoxMain);
+    
+    /* DONT show the main window yet, due to a Gtk bug that causes it
+     * to not refresh the window when adding widgets after the window 
+     * has already been shown */
+    if (uid != euid)
+      setuid(euid);
+    for(i = 0; i < SIZE(ghack_chain); i++)
+       ghack_chain[i].handler =
+         signal(ghack_chain[i].signum, ghack_sig_handler);
+}
+
+void ghack_main_window_add_map_window(GtkWidget* win) 
+{
+    GtkWidget *vBox;
+    
+    vBox= gtk_vbox_new (TRUE, 0);
+    gtk_box_pack_start (GTK_BOX (vBox), win, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (vBoxMain), vBox, TRUE, TRUE, 2);
+    gtk_widget_show_all(vBox);
+    /* Ok, now show the main window -- now that we have added in 
+     * all the windows (relys on nethack displaying the map window last
+     * (This is an ugly kludge, BTW)
+     */
+    gtk_widget_show_all(mainWindow);
+}
+
+void
+ghack_main_window_add_message_window(GtkWidget* win)
+{
+    gtk_box_pack_start (GTK_BOX (hBoxFirstRow), win, TRUE, TRUE, 2);
+    gtk_widget_show_all(win);
+}
+
+void
+ghack_main_window_add_status_window(GtkWidget* win)
+{
+    gtk_box_pack_start (GTK_BOX (hBoxFirstRow), win, FALSE, TRUE, 2);
+    gtk_widget_show_all(win);
+}
+
+void
+ghack_main_window_add_worn_window(GtkWidget* win)
+{
+    gtk_box_pack_end (GTK_BOX (hBoxFirstRow), win, FALSE, TRUE, 2);
+    gtk_widget_show_all(win);
+}
+
+void
+ghack_main_window_add_text_window(GtkWidget *win)
+{
+  g_warning("Fixme!!! AddTextWindow is not yet implemented");
+}
+
+void
+ghack_main_window_remove_window(GtkWidget *win)
+{
+  g_warning("Fixme!!! RemoveWindow is not yet implemented");
+}
+
+void
+ghack_main_window_update_inventory()
+{
+/* For now, do very little.  Eventually we may allow the inv. window
+     to stay active.  When we do this, we'll need to implement this...
+   g_warning("Fixme!!! updateInventory is not yet implemented");
+*/
+       gnome_display_nhwindow(WIN_WORN, FALSE);
+}
+
+GtkWidget*
+ghack_get_main_window()
+{
+      return( GTK_WIDGET(mainWindow) );
+}
diff --git a/win/gnome/gnmain.h b/win/gnome/gnmain.h
new file mode 100644 (file)
index 0000000..b2ffc3d
--- /dev/null
@@ -0,0 +1,26 @@
+/*     SCCS Id: @(#)gnmain.h   3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackMainWindow_h
+#define GnomeHackMainWindow_h
+
+#include <gnome.h>
+#include <gtk/gtk.h>
+
+
+void ghack_init_main_window( int argc, char** argv);
+void ghack_main_window_add_map_window(GtkWidget* win);
+void ghack_main_window_add_message_window(GtkWidget* win);
+void ghack_main_window_add_status_window(GtkWidget* win);
+void ghack_main_window_add_text_window(GtkWidget *);
+void ghack_main_window_add_worn_window(GtkWidget* win);
+void ghack_main_window_remove_window(GtkWidget *);
+void ghack_main_window_update_inventory();
+void ghack_save_game_cb(GtkWidget *widget, gpointer data);
+GtkWidget* ghack_get_main_window();
+
+
+
+#endif /* GnomeHackMainWindow_h */
+
diff --git a/win/gnome/gnmap.c b/win/gnome/gnmap.c
new file mode 100644 (file)
index 0000000..abaf0ce
--- /dev/null
@@ -0,0 +1,619 @@
+/*     SCCS Id: @(#)gnmap.c    3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* Copyright (C) 1998 by Anthony Taylor <tonyt@ptialaska.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "gnmap.h"
+#include "gnglyph.h"
+#include "gnsignal.h"
+#include "hack.h"
+
+#ifndef ROWNO
+#define ROWNO 21
+#define COLNO 80
+#endif
+
+/* globals static to this file go here */
+struct {
+  GnomeCanvas       *canvas;
+  GnomeCanvasImage  *map[(ROWNO + 1) * COLNO];
+  GnomeCanvasImage  *overlay[(ROWNO + 1) * COLNO];
+  double            zoom;
+  GtkWidget         *frame;
+} ghack_map;
+  
+static GdkImlibImage *background;
+static GdkImlibImage *petmark;
+static GnomeCanvasGroup *myCanvasGroup;
+
+/* static function declarations -- local to this file go here */
+void ghack_map_cursor_to( GtkWidget *win, int x, int y, gpointer data); 
+void ghack_map_putstr( GtkWidget *win, int attr, const char* text, gpointer data);
+void ghack_map_print_glyph( GtkObject *win, guint x, guint y, GdkImlibImage *im, gpointer data);
+void ghack_map_clear( GtkWidget *win, gpointer data);
+static void ghack_map_display( GtkWidget *win, boolean block, gpointer data);
+static void ghack_map_cliparound( GtkWidget *win, int x, int y, gpointer data);
+static void ghack_map_window_zoom( GtkAdjustment *adj, gpointer data);
+
+
+/* The following XPM is the artwork of Warwick Allison
+ * <warwick@troll.no>.  It has been borrowed from 
+ * the most excellent NetHackQt, until such time as
+ * we can come up with something better.
+ *
+ * More information about NetHackQt can be had from:
+ * http://www.troll.no/~warwick/nethack/
+ */
+
+/* XPM */
+static char *pet_mark_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"8 7 2 1",
+/* colors */
+". c None",
+"  c #FF0000",
+/* pixels */
+"........",
+"..  .  .",
+".       ",
+".       ",
+"..     .",
+"...   ..",
+".... ..."
+};
+
+
+/* NAME: 
+ *     ghack_init_map_window( )
+ *
+ * ARGUMENTS:
+ *     NONE
+ *
+ * RETURNS:
+ *     GtkWidget*
+ *
+ * PURPOSE:
+ *     Create the basic map necessities.  Create a canvas;
+ *     give it a background.  Attach all the right signals
+ *     to all the right places.  Generally prepare the map
+ *     to behave properly.
+*/
+
+GtkWidget*
+ghack_init_map_window ( )
+{
+  GtkWidget        *vbox;
+  GtkWidget        *hbox;
+  GtkWidget        *table;
+  GtkWidget        *frame;
+  GtkWidget        *w;
+  GtkWidget       *hSeparator;
+  GtkAdjustment    *adj;
+  GnomeCanvasImage  *bg;
+  double width, height, x, y;
+  int i;
+
+  width = COLNO * ghack_glyph_width();
+  height = ROWNO * ghack_glyph_height();
+
+  vbox = gtk_vbox_new (FALSE, 4);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
+  gtk_widget_show (vbox);
+  
+  /* Add in a horiz seperator */
+  hSeparator = gtk_hseparator_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), hSeparator, FALSE, FALSE, 2);
+  gtk_widget_show ( hSeparator);
+  
+  hbox = gtk_hbox_new (FALSE, 4);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
+
+  /* Create the Zoom spinbutton.
+  */
+  ghack_map.zoom = 1.0;
+  w = gtk_label_new ("Zoom:");
+  gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
+  gtk_widget_show (w);
+  adj = GTK_ADJUSTMENT (gtk_adjustment_new (1.00, 0.5, 3.00, 0.05, 0.50, 0.50));
+  w = gtk_spin_button_new (adj, 0.5, 2);
+  gtk_widget_set_usize (w, 50, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
+  gtk_widget_show (w);
+
+  /* Canvas and scrollbars
+  */
+  gtk_widget_push_visual (gdk_imlib_get_visual ());
+  gtk_widget_push_colormap (gdk_imlib_get_colormap ());
+  ghack_map.canvas = GNOME_CANVAS (gnome_canvas_new());
+  //gtk_widget_push_visual(gdk_rgb_get_visual());
+  //gtk_widget_push_colormap(gdk_rgb_get_cmap());
+  //ghack_map.canvas = GNOME_CANVAS (gnome_canvas_new_aa());
+
+  gtk_widget_pop_colormap();
+  gtk_widget_pop_visual();
+  gtk_widget_show (GTK_WIDGET(ghack_map.canvas));
+
+  table = gtk_table_new (2, 2, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 4);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
+  gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
+  gtk_widget_show (table);
+  
+  frame = gtk_frame_new (NULL);
+  ghack_map.frame = frame;
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+  gtk_table_attach (GTK_TABLE (table), frame,
+                   0, 1, 0, 1,
+                   GTK_EXPAND | GTK_FILL | GTK_SHRINK,
+                   GTK_EXPAND | GTK_FILL | GTK_SHRINK,
+                   0, 0);
+  gtk_widget_show (frame);
+
+  gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET(ghack_map.canvas));
+  gnome_canvas_set_scroll_region (GNOME_CANVAS(ghack_map.canvas), 0, 0, 
+                   width+2*ghack_glyph_width(), height+2*ghack_glyph_height());
+
+  gnome_canvas_set_pixels_per_unit (GNOME_CANVAS(ghack_map.canvas), 1.0);
+
+  w = gtk_hscrollbar_new (GTK_LAYOUT (ghack_map.canvas)->hadjustment);
+  gtk_table_attach (GTK_TABLE (table), w,
+                   0, 1, 1, 2,
+                   GTK_EXPAND | GTK_FILL | GTK_SHRINK,
+                   GTK_FILL,
+                   0, 0);
+  gtk_widget_show (w);
+
+  w = gtk_vscrollbar_new (GTK_LAYOUT (ghack_map.canvas)->vadjustment);
+  gtk_table_attach (GTK_TABLE (table), w,
+                   1, 2, 0, 1, GTK_FILL,
+                   GTK_EXPAND | GTK_FILL | GTK_SHRINK,
+                   0, 0);
+  gtk_widget_show (w); 
+  
+  myCanvasGroup = GNOME_CANVAS_GROUP ( gnome_canvas_item_new ( 
+                   gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)), 
+                   gnome_canvas_group_get_type (), 
+                   "x", 0.0, 
+                   "y", 0.0, 
+                   NULL) );
+
+  /* Tile the map background with a pretty image */ 
+  background = gdk_imlib_load_image((char *) "mapbg.xpm");
+  if (background == NULL) {
+      g_warning("Bummer! Failed to load the map background image (mapbg.xpm)!");
+  }
+  else {
+    gdk_imlib_render(background, background->rgb_width,
+         background->rgb_height);
+
+    /* Tile the map background */
+    for (y = 0; y < height+background->rgb_height; y+=background->rgb_height)
+    {
+      for (x = 0; x < width+background->rgb_width; x+=background->rgb_width)
+       {
+         bg = GNOME_CANVAS_IMAGE( gnome_canvas_item_new (
+                     myCanvasGroup, gnome_canvas_image_get_type (),
+                     "x",      (double) x,
+                     "y",      (double) y,
+                     "width",  (double) background->rgb_width,
+                     "height", (double) background->rgb_height,
+                     "image",  background,
+                     "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER,
+                     NULL) );
+         gnome_canvas_item_lower_to_bottom (GNOME_CANVAS_ITEM( bg));
+       }
+    }
+  }
+
+  /* ghack_map.map is an array of canvas images.  Each cell of
+   * the array will contain one tile.  Here, we create the
+   * space for the cells and then create the cells for easy
+   * access later.
+  */
+  for (i=0, y = 0; y < height; y+=ghack_glyph_height())
+    {
+      for (x = 0; x < width; x+=ghack_glyph_width())
+       {
+         ghack_map.map[i++] = GNOME_CANVAS_IMAGE( 
+                 gnome_canvas_item_new (
+                     myCanvasGroup,
+                     gnome_canvas_image_get_type (),
+                     "x",      (double) x,
+                     "y",      (double) y,
+                     "width",  (double) ghack_glyph_width(),
+                     "height", (double) ghack_glyph_height(),
+                     "anchor", GTK_ANCHOR_NORTH_WEST,
+                     NULL) );
+       }
+    }
+
+   /* Set up the pet mark image */
+  petmark = gdk_imlib_create_image_from_xpm_data( pet_mark_xpm);
+  if (petmark == NULL) {
+    g_warning("Bummer! Failed to load the pet_mark image!");
+  }
+  else {
+      gdk_imlib_render(petmark, petmark->rgb_width, petmark->rgb_height);
+
+      /* ghack_map.overlay is an array of canvas images used to
+       * overlay tile images...
+       */
+      for (i=0, y = 0; y < height; y+=ghack_glyph_height())
+       {
+         for (x = 0; x < width; x+=ghack_glyph_width())
+           {
+             ghack_map.overlay[i] = GNOME_CANVAS_IMAGE( 
+                     gnome_canvas_item_new (
+                         myCanvasGroup,
+                         gnome_canvas_image_get_type (),
+                         "x",      (double) x,
+                         "y",      (double) y,
+                         "width",  (double) petmark->rgb_width,
+                         "height", (double) petmark->rgb_height,
+                         "image",  petmark,
+                         "anchor", GTK_ANCHOR_NORTH_WEST,
+                         NULL) );
+             gnome_canvas_item_lower_to_bottom (
+                     GNOME_CANVAS_ITEM( ghack_map.overlay[i++]));
+           }
+       }
+  }
+
+  /* Resize the canvas when the spinbutton changes
+  */
+  gtk_signal_connect (GTK_OBJECT (adj),
+                     "value_changed",
+                     (GtkSignalFunc) ghack_map_window_zoom,
+                     ghack_map.canvas);
+
+  /* Game signals
+  */
+  gtk_signal_connect (GTK_OBJECT (vbox),
+                     "ghack_curs",
+                     GTK_SIGNAL_FUNC (ghack_map_cursor_to),
+                     NULL);
+  gtk_signal_connect (GTK_OBJECT (vbox),
+                     "ghack_putstr",
+                     GTK_SIGNAL_FUNC (ghack_map_putstr),
+                     NULL);
+  gtk_signal_connect (GTK_OBJECT (vbox),
+                     "ghack_print_glyph",
+                     GTK_SIGNAL_FUNC (ghack_map_print_glyph),
+                     NULL);
+  gtk_signal_connect (GTK_OBJECT (vbox),
+                     "ghack_clear",
+                     GTK_SIGNAL_FUNC (ghack_map_clear),
+                     NULL);
+  gtk_signal_connect (GTK_OBJECT (vbox),
+                     "ghack_display",
+                     GTK_SIGNAL_FUNC (ghack_map_display),
+                     NULL);
+  gtk_signal_connect (GTK_OBJECT (vbox),
+                     "ghack_cliparound",
+                     GTK_SIGNAL_FUNC (ghack_map_cliparound),
+                     NULL);
+  gtk_signal_connect (GTK_OBJECT (ghack_map.canvas),
+                     "button_press_event",
+                     GTK_SIGNAL_FUNC (ghack_handle_button_press),
+                     NULL);
+  gtk_signal_connect(GTK_OBJECT (ghack_map.canvas), 
+                     "gnome_delay_output",
+                      GTK_SIGNAL_FUNC(ghack_delay), 
+                     NULL);
+  
+  return GTK_WIDGET(vbox);
+}
+
+
+/* NAME: 
+ *     ghack_map_window_zoom
+ *
+ * ARGUMENTS:
+ *     double     zoom -- The zoom factor
+ *
+ * RETURNS:
+ *     Nothing.
+ *
+ * PURPOSE:
+ *     Zoom the map image in and out.  This should allow the user to
+ *     dynamically scale the map.  Ideally, the background should
+ *     *NOT* scale, but this may be impractical.
+*/
+
+static void
+ghack_map_window_zoom( GtkAdjustment *adj, gpointer data)
+{
+  if ( adj->value > 3.0 ) 
+      adj->value = 3.0;
+  if ( adj->value < 0.5 )
+      adj->value = 0.5;
+  ghack_map.zoom = adj->value;
+  gnome_canvas_set_pixels_per_unit (data, adj->value);
+}
+
+
+
+void
+ghack_map_cursor_to( GtkWidget *win, int x, int y, gpointer data)
+{
+  GnomeCanvasGroup *group;
+  static GnomeCanvasRE *cursor = NULL;
+
+  double x1, y1, x2, y2;
+  float hp;
+  guint r, g, b;
+
+  x1 = x * ghack_glyph_width() - 1;
+  y1 = y * ghack_glyph_height() - 1;
+  x2 = x1 + ghack_glyph_width() + 2;
+  y2 = y1 + ghack_glyph_height() + 2;
+  hp = u.mtimedone
+         ? (u.mhmax  ? (float)u.mh/u.mhmax   : 1)
+         : (u.uhpmax ? (float)u.uhp/u.uhpmax : 1);
+
+  r = 255;
+  g = (hp >= 0.75) ? 255             : (hp >= 0.25 ? 255*2*(hp-0.25) : 0);
+  b = (hp >= 0.75) ? 255*4*(hp-0.75) : (hp >= 0.25 ? 0 : 255*4*(0.25-hp));
+
+  group = gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas));
+
+  if (!cursor) {
+    cursor = GNOME_CANVAS_RE (gnome_canvas_item_new (group, 
+               gnome_canvas_rect_get_type (), 
+               "width_units", 1.0, NULL));
+  }
+  gnome_canvas_item_set (GNOME_CANVAS_ITEM (cursor),
+                       "outline_color_rgba", GNOME_CANVAS_COLOR(r, g, b),
+                        "x1", x1,
+                        "y1", y1,
+                        "x2", x2,
+                        "y2", y2,
+                        NULL);
+
+  gnome_canvas_item_raise_to_top( GNOME_CANVAS_ITEM( cursor));
+  gnome_canvas_item_show( GNOME_CANVAS_ITEM(cursor));
+}
+
+
+void
+ghack_map_putstr( GtkWidget *win, int attr, const char* text, gpointer data)
+{
+    g_warning("Fixme!!! ghack_map_putstr is not implemented");
+}
+
+/* NAME: 
+ *     ghack_map_print_glyph( )
+ *
+ * ARGUMENTS:
+ *     XCHAR_P x, y  -- The coordinates where which to print the glyph
+ *     GdkImlibImage*   glyph -- The glyph image to print
+ *
+ * RETURNS:
+ *     Nothing.
+ *
+ * PURPOSE:
+ *     Draw the glyph-tile at the specified coordinates.
+*/
+
+void
+ghack_map_print_glyph( GtkObject *win, 
+                      guint x, 
+                      guint y, 
+                      GdkImlibImage *im,
+                      gpointer data)
+{
+  GnomeCanvasGroup *group;
+  int i = y * COLNO + x;
+  int glyph = glyph_at(x,y);
+  GnomeCanvasImage *canvas_image = GNOME_CANVAS_IMAGE( ghack_map.map[i]);
+
+  group = gnome_canvas_root (GNOME_CANVAS (ghack_map.canvas));
+  
+  gnome_canvas_item_set (GNOME_CANVAS_ITEM ( canvas_image),
+                        "image",  im, NULL);
+  gnome_canvas_item_show( GNOME_CANVAS_ITEM( canvas_image));
+
+  canvas_image = GNOME_CANVAS_IMAGE( ghack_map.overlay[i]);
+
+  if (x==u.ux && y==u.uy)
+      ghack_map_cliparound(NULL, x, y, NULL);
+
+  if (glyph_is_pet(glyph)
+#ifdef TEXTCOLOR
+                 && iflags.hilite_pet
+#endif
+               ) {
+      gnome_canvas_item_raise_to_top( GNOME_CANVAS_ITEM( canvas_image));
+      gnome_canvas_item_show( GNOME_CANVAS_ITEM( canvas_image));
+  }
+  else {
+      gnome_canvas_item_hide( GNOME_CANVAS_ITEM( canvas_image));
+  }
+}
+
+
+/* NAME: 
+ *     ghack_map_clear( )
+ *
+ * ARGUMENTS:
+ *     NONE
+ *
+ * RETURNS:
+ *     Nothing.
+ *
+ * PURPOSE:
+ *     Clear the map by hiding all the map tiles.
+*/
+
+void
+ghack_map_clear( GtkWidget *win, gpointer data)
+{
+  int i;
+
+  for (i = 0; i < ROWNO * COLNO; i++)
+    {
+      if (GNOME_IS_CANVAS_IMAGE(ghack_map.map[i]))
+       {
+         gnome_canvas_item_hide( GNOME_CANVAS_ITEM (ghack_map.map[i]));
+       }
+      if (GNOME_IS_CANVAS_IMAGE(ghack_map.overlay[i]))
+       {
+         gnome_canvas_item_hide( GNOME_CANVAS_ITEM (ghack_map.overlay[i]));
+       }
+    }
+  gnome_canvas_update_now ( GNOME_CANVAS(ghack_map.canvas));
+}
+
+
+void
+ghack_map_display( GtkWidget *win, boolean block, gpointer data)
+{
+  gtk_widget_show_all( GTK_WIDGET(win));
+}
+
+
+void
+ghack_map_cliparound( GtkWidget *win,
+                     int x,
+                     int y,
+                     gpointer data)
+{
+  int  map_width, map_height;
+  int  to_x, to_y;
+  int  cur_x, cur_y;
+  int  width, height, half_width, half_height;
+
+  x *= ghack_glyph_width() * ghack_map.zoom;
+  y *= ghack_glyph_height() * ghack_map.zoom;
+  map_width = COLNO * ghack_glyph_width() * ghack_map.zoom;
+  map_height = ROWNO * ghack_glyph_height() * ghack_map.zoom;
+
+  gdk_window_get_size( GTK_LAYOUT (ghack_map.canvas)->bin_window, 
+         &width, &height);
+  gnome_canvas_get_scroll_offsets( ghack_map.canvas, &cur_x, &cur_y);
+
+  half_width  = width * 0.5;
+  half_height = height * 0.5;
+
+  if ( ((x - cur_x) < (width * 0.25) ) || ( (x - cur_x) > (width * 0.75) ) ) {
+    to_x = ((x-half_width) > 0)? x - half_width : 0;
+    to_x = ((x+half_width) > map_width)? map_width - 2 * half_width : to_x;
+  }                                                                             
+  else {
+    to_x = cur_x;
+  }                                                                             
+
+  if ( ((y - cur_y) < (height * 0.25) ) || ( (y - cur_y) > (height * 0.75) ) ) {
+    to_y = ((y-half_height) > 0)? y - half_height : 0;
+    to_y = ((y+half_height) > map_height)? map_height - 2 * half_height : to_y;
+  }                                                                             
+  else {
+    to_y = cur_y;
+  }                                                                             
+
+  if (to_x != cur_x || to_y != cur_y)
+    gnome_canvas_scroll_to( ghack_map.canvas, to_x, to_y);
+  //gnome_canvas_update_now ( ghack_map.canvas);
+  
+}
+
+
+
+void
+ghack_reinit_map_window ( )
+{
+  GnomeCanvasImage  *bg;
+  double width, height, x, y;
+  int i;
+
+  /* ghack_map_clear(NULL, NULL); */
+
+  width = COLNO * ghack_glyph_width();
+  height = ROWNO * ghack_glyph_height();
+
+  gnome_canvas_set_scroll_region (GNOME_CANVAS(ghack_map.canvas), 0, 0, 
+                   width+2*ghack_glyph_width(), height+2*ghack_glyph_height());
+
+  /* remove everything currently in the canvas map */
+  gtk_object_destroy( GTK_OBJECT (myCanvasGroup));
+
+  /* Put some groups back */
+  myCanvasGroup = GNOME_CANVAS_GROUP ( gnome_canvas_item_new ( 
+                   gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)), 
+                   gnome_canvas_group_get_type (), 
+                   "x", 0.0, 
+                   "y", 0.0, 
+                   NULL) );
+
+  /* Tile the map background with a pretty image */ 
+  if (background != NULL) {
+    /* Tile the map background */
+    for (y = 0; y < height+background->rgb_height; y+=background->rgb_height)
+    {
+      for (x = 0; x < width+background->rgb_width; x+=background->rgb_width)
+       {
+         bg = GNOME_CANVAS_IMAGE( gnome_canvas_item_new (
+                     myCanvasGroup, gnome_canvas_image_get_type (),
+                     "x",      (double) x,
+                     "y",      (double) y,
+                     "width",  (double) background->rgb_width,
+                     "height", (double) background->rgb_height,
+                     "image",  background,
+                     "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER,
+                     NULL) );
+         gnome_canvas_item_lower_to_bottom (GNOME_CANVAS_ITEM( bg));
+       }
+    }
+  }
+
+  /* ghack_map.map is an array of canvas images.  Each cell of
+   * the array will contain one tile.  Here, we create the
+   * space for the cells and then create the cells for easy
+   * access later.
+  */
+  for (i=0, y = 0; y < height; y+=ghack_glyph_height()) {
+      for (x = 0; x < width; x+=ghack_glyph_width()) {
+         ghack_map.map[i++] = GNOME_CANVAS_IMAGE( 
+                 gnome_canvas_item_new (
+                     myCanvasGroup,
+                     gnome_canvas_image_get_type (),
+                     "x",      (double) x,
+                     "y",      (double) y,
+                     "width",  (double) ghack_glyph_width(),
+                     "height", (double) ghack_glyph_height(),
+                     "anchor", GTK_ANCHOR_NORTH_WEST,
+                     NULL) );
+      }
+  }
+  
+  if (petmark != NULL) {
+      /* ghack_map.overlay is an array of canvas images used to
+       * overlay tile images...
+      */
+      for (i=0, y = 0; y < height; y+=ghack_glyph_height()) {
+         for (x = 0; x < width; x+=ghack_glyph_width()) {
+             ghack_map.overlay[i] = GNOME_CANVAS_IMAGE( 
+                     gnome_canvas_item_new (
+                         myCanvasGroup,
+                         gnome_canvas_image_get_type (),
+                         "x",      (double) x,
+                         "y",      (double) y,
+                         "width",  (double) petmark->rgb_width,
+                         "height", (double) petmark->rgb_height,
+                         "image",  petmark,
+                         "anchor", GTK_ANCHOR_NORTH_WEST,
+                         NULL) );
+             gnome_canvas_item_lower_to_bottom (
+                     GNOME_CANVAS_ITEM( ghack_map.overlay[i++]));
+           }
+       }
+  }
+
+  ghack_map_cliparound(NULL, u.ux, u.uy, NULL);
+  ghack_map_cursor_to(NULL, u.ux, u.uy, NULL);
+  gnome_canvas_update_now ( ghack_map.canvas);
+  doredraw();
+}
+
+
diff --git a/win/gnome/gnmap.h b/win/gnome/gnmap.h
new file mode 100644 (file)
index 0000000..83bc849
--- /dev/null
@@ -0,0 +1,16 @@
+/*     SCCS Id: @(#)gnmap.h    3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackMapWindow_h
+#define GnomeHackMapWindow_h
+
+#include <gnome.h>
+#include <gdk_imlib.h>
+#include "config.h"
+#include "global.h"
+
+GtkWidget *ghack_init_map_window(void);
+void ghack_reinit_map_window(void);
+
+#endif /* GnomeHackMapWindow_h */
diff --git a/win/gnome/gnmenu.c b/win/gnome/gnmenu.c
new file mode 100644 (file)
index 0000000..d3fa6da
--- /dev/null
@@ -0,0 +1,755 @@
+/*     SCCS Id: @(#)gnmenu.c   3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gnome.h>
+#include "gnmenu.h"
+#include "gnmain.h"
+#include "gnbind.h"
+#include "func_tab.h"
+
+typedef enum {
+       MenuUnknown = 0,
+       MenuText,
+       MenuMenu
+} MenuWinType;
+
+typedef struct {
+       ANY_P identifier;
+       gchar accelerator[BUFSZ];
+       int itemNumber;
+       int selected;
+} menuItem;
+
+typedef struct {
+       int curItem;
+       int numRows;
+       int charIdx;
+       guint32 lastTime;
+} extMenu;
+
+static GdkColor color_blue = { 0, 0, 0, 0xffff };
+
+
+static void
+ghack_menu_window_key(GtkWidget *menuWin, GdkEventKey *event, gpointer data)
+{
+    int i, numRows;
+    menuItem* item;
+    MenuWinType isMenu;
+
+    isMenu = (MenuWinType) GPOINTER_TO_INT
+       (gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu"));
+
+    if (isMenu == MenuMenu) {
+       GtkWidget *clist;
+       gint selection_mode;
+
+       clist = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (menuWin), "clist"));
+       g_assert (clist != NULL);
+       numRows = GPOINTER_TO_INT
+           (gtk_object_get_data(GTK_OBJECT(clist), "numRows"));
+       selection_mode = GPOINTER_TO_INT
+           (gtk_object_get_data (GTK_OBJECT(clist), "selection_mode"));
+       for (i = 0; i <= numRows; ++i) {
+           item = (menuItem*) gtk_clist_get_row_data(GTK_CLIST(clist), i);
+           if (item == NULL) continue;
+           if (!strcmp(item->accelerator, "")) continue;
+
+           if ((!strcmp(item->accelerator, event->string)) ||
+               ((selection_mode == GTK_SELECTION_MULTIPLE) &&
+                (event->keyval == ','))) {
+               if (item->selected) {
+                   gtk_clist_unselect_row( GTK_CLIST (clist),
+                                           item->itemNumber, 0);
+                   item->selected = FALSE;
+               } else {
+                   gtk_clist_select_row(GTK_CLIST (clist),
+                                        item->itemNumber, 0);
+                   if (gtk_clist_row_is_visible(GTK_CLIST(clist),
+                               item->itemNumber) != GTK_VISIBILITY_FULL)
+                       gtk_clist_moveto(GTK_CLIST(clist),
+                                        item->itemNumber, 0, 0.5, 0);
+                   item->selected = TRUE;
+               }
+           }
+       }
+    }
+}
+
+
+static void
+ghack_menu_row_selected (GtkCList *clist, int row, int col, GdkEvent *event)
+{
+    /* FIXME: Do something */
+}
+
+
+void
+ghack_menu_window_clear(GtkWidget *menuWin, gpointer data)
+{
+    MenuWinType isMenu;
+    int i, numRows;
+    menuItem* item;
+
+    isMenu = (MenuWinType) GPOINTER_TO_INT
+       (gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu"));
+
+    if (isMenu == MenuMenu) {
+      GtkWidget *clist;
+
+      clist = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (menuWin), "clist"));
+      g_assert (clist != NULL);
+
+      /* destroy existing menu data, if any */
+      if (clist) {
+       /* destroy all the row_data we stored in the clist */
+       numRows = GPOINTER_TO_INT( gtk_object_get_data(
+                   GTK_OBJECT(clist), "numRows") );
+       for( i=0; i<numRows; i++) {
+           item = (menuItem*) gtk_clist_get_row_data( 
+                   GTK_CLIST (clist), i);
+           if (item != NULL) {
+               g_free( item);
+               gtk_clist_set_row_data (GTK_CLIST (clist), i, 
+                       (gpointer) NULL);
+           }
+       }
+       gtk_object_set_data (GTK_OBJECT (clist), "numItems",
+                               GINT_TO_POINTER (-1));
+       gtk_clist_clear (GTK_CLIST (clist));
+      }
+    }
+    
+    else if (isMenu == MenuText) {
+      GnomeLess *gless;
+
+      gless = GNOME_LESS (gtk_object_get_data (GTK_OBJECT (menuWin), "gless"));
+      g_assert (gless != NULL);
+
+      gtk_editable_delete_text (GTK_EDITABLE (gless->text), 0, 0);
+    }
+
+}
+
+void
+ghack_menu_window_display(GtkWidget *menuWin, gboolean blocking,
+                          gpointer data)
+{
+    //if(blocking) {
+        gnome_dialog_close_hides (GNOME_DIALOG (menuWin), TRUE);
+       gnome_dialog_set_close (GNOME_DIALOG (menuWin), TRUE);
+       gnome_dialog_run_and_close(GNOME_DIALOG (menuWin));
+    //}
+    //else {
+        //gtk_widget_show(menuWin);
+    //}
+}
+
+gint
+ghack_menu_hide( GtkWidget *menuWin, GdkEvent *event, gpointer data )
+{
+    gtk_widget_hide (menuWin);
+    return FALSE; /* FIXME: what is correct result here? */
+}
+
+
+void 
+ghack_menu_window_start_menu (GtkWidget *menuWin, gpointer data)
+{
+    GtkWidget *frame1, *swin, *clist;
+    MenuWinType isMenu;
+    
+    g_assert (menuWin != NULL);
+    g_assert (data == NULL);
+
+    /* destroy existing menu data, if any */
+    frame1 = gtk_object_get_data (GTK_OBJECT (menuWin), "frame1");
+    if (frame1)
+      gtk_widget_destroy (frame1);
+    isMenu = MenuMenu;
+    gtk_object_set_data (GTK_OBJECT (menuWin), "isMenu",
+                        GINT_TO_POINTER (isMenu));
+
+    gtk_widget_set_usize (GTK_WIDGET (menuWin), 500, 400);
+    gtk_window_set_policy (GTK_WINDOW (menuWin), TRUE, TRUE, FALSE);
+
+    frame1 = gtk_frame_new ("Make your selection");
+    g_assert (frame1 != NULL);
+    gtk_object_set_data (GTK_OBJECT(menuWin), "frame1", frame1);
+    gtk_widget_show (GTK_WIDGET (frame1));
+    gtk_container_set_border_width (GTK_CONTAINER (frame1), 5);
+    gtk_box_pack_start (GTK_BOX (GNOME_DIALOG(menuWin)->vbox), frame1,
+                        TRUE, TRUE, 0);
+    
+    swin = gtk_scrolled_window_new (NULL, NULL);
+    g_assert (swin != NULL);
+    gtk_object_set_data (GTK_OBJECT(menuWin), "swin", swin);
+    gtk_widget_show (GTK_WIDGET (swin));
+    gtk_container_add (GTK_CONTAINER (frame1), swin);
+
+    clist = gtk_clist_new (4);
+    g_assert (clist != NULL);
+    gtk_object_set_data (GTK_OBJECT(menuWin), "clist", clist);
+    gtk_widget_show (GTK_WIDGET (clist));
+    gtk_container_add (GTK_CONTAINER (swin), clist);
+
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
+           GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+    gtk_signal_connect (GTK_OBJECT (clist), "select_row",
+           GTK_SIGNAL_FUNC (ghack_menu_row_selected), NULL);
+    gtk_object_set_data (GTK_OBJECT (clist), "numItems",
+                           GINT_TO_POINTER (-1));
+}    
+
+    
+int 
+ghack_menu_window_select_menu (GtkWidget *menuWin, 
+       MENU_ITEM_P **_selected, gint how)
+{
+   gint rc;
+   guint num_sel, i, idx;
+   GtkWidget *clist;
+   GList *cur;
+   MENU_ITEM_P *selected = NULL;
+   menuItem*   item;
+
+   g_assert (_selected != NULL);
+   *_selected = NULL;
+
+
+   if (how == PICK_NONE) {
+     gnome_dialog_close_hides (GNOME_DIALOG (menuWin), TRUE);
+     rc = gnome_dialog_run_and_close (GNOME_DIALOG (menuWin));
+     return( rc == 1 ? -1 : 0);
+   }
+
+   clist = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (menuWin), "clist"));
+   g_assert (clist != NULL);
+
+   gtk_object_set_data (GTK_OBJECT (clist), "selection_mode",
+                   GINT_TO_POINTER ((how == PICK_ANY)? 
+                      GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE));
+   gtk_clist_set_selection_mode (GTK_CLIST (clist), 
+          (how == PICK_ANY)? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE);
+   gnome_dialog_close_hides (GNOME_DIALOG (menuWin), TRUE);
+   rc = gnome_dialog_run_and_close (GNOME_DIALOG (menuWin));
+   if ((rc == 1) || (GTK_CLIST (clist)->selection == NULL)) {
+     return(-1);
+   }
+
+   num_sel = g_list_length (GTK_CLIST (clist)->selection);
+   if (num_sel < 1) {
+     return(-1);
+   }
+
+   /* fill in array with selections from clist */
+   selected =  g_new0( MENU_ITEM_P, num_sel);
+   g_assert (selected != NULL);
+   cur = GTK_CLIST (clist)->selection;
+   i = 0;
+   while (cur) {
+     g_assert (i < num_sel);
+
+     /* grab row number from clist selection list */
+     idx = GPOINTER_TO_INT (cur->data);
+
+     item = (menuItem*) gtk_clist_get_row_data( GTK_CLIST (clist), idx);
+     selected[i].item = item->identifier;
+     selected[i].count = -1;
+     cur = g_list_next(cur);
+     i++;
+   }
+
+   *_selected = selected;
+
+   return( (int) num_sel);
+}    
+
+void 
+ghack_menu_window_add_menu( GtkWidget *menuWin, gpointer menu_item,
+                           gpointer data)
+{
+    GHackMenuItem*  item;
+    GtkWidget      *clist;
+    gchar buf[BUFSZ]="", accelBuf[BUFSZ]="";
+    gchar *pbuf;
+    char *text[4] = { buf, NULL, NULL, NULL };
+    gint nCurrentRow = -1, numItems = -1;
+    MenuWinType isMenu;
+    GtkStyle *bigStyle = NULL;
+    gboolean item_selectable;
+    GdkImlibImage* image;
+    static gboolean special;
+
+    g_assert (menu_item != NULL);
+    item = (GHackMenuItem*) menu_item;
+    item_selectable = ( item->identifier->a_int == 0)? FALSE : TRUE;
+    isMenu = (MenuWinType) GPOINTER_TO_INT
+       (gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu"));
+
+    clist = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (menuWin), "clist"));
+    g_assert (clist != NULL);
+    /* This is a special kludge to make the special hidden help menu item work as designed */ 
+    if ( special==TRUE ) {
+       special=FALSE;
+       item_selectable=TRUE;
+    }
+    if ( ! strcmp( item->str, "The NetHack license.")) {
+       special=TRUE;
+    }
+    
+    if (item->str) {
+
+       /* First, make a new blank entry in the clist */
+       nCurrentRow = gtk_clist_append (GTK_CLIST (clist), text);
+
+       if (item->glyph != NO_GLYPH) {
+           image = ghack_image_from_glyph( item->glyph, FALSE);
+           if (image==NULL || image->pixmap==NULL) {
+               g_warning("Bummer -- having to force rendering for glyph %d!", item->glyph);
+               /* wierd -- pixmap is NULL so retry rendering it */
+               image = ghack_image_from_glyph( item->glyph, TRUE);
+           }
+           if (image==NULL || image->pixmap==NULL) {
+                   g_error("Aiiee! glyph is still NULL for item\n\"%s\"", 
+                           item->str);
+           }
+           else 
+               gtk_clist_set_pixmap (GTK_CLIST (clist), 
+                       nCurrentRow, 1, 
+                       gdk_imlib_move_image( image), 
+                       gdk_imlib_move_mask( image));
+       }
+       if (item->accelerator) {
+           /* FIXME: handle accelerator, */
+           g_snprintf(accelBuf, sizeof(accelBuf), "%c ", item->accelerator);
+           gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 0, accelBuf);
+           g_snprintf(buf, sizeof(buf), "%s", item->str);
+           gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 2, buf);
+       } else {
+           if (item->group_accel) {
+               /* FIXME: maybe some day I should try to handle 
+                * group accelerators... */
+           }
+           if (( (item->attr == 0) && (item->identifier->a_int != 0)) || (special ==TRUE) ) {
+               numItems = GPOINTER_TO_INT( gtk_object_get_data(
+                           GTK_OBJECT(clist), "numItems") )+1;
+
+               /* Ok, now invent a unique accelerator */
+               if (  ('a'+numItems) <= 'z' ) {
+                   g_snprintf(accelBuf, sizeof(accelBuf), "%c ", 'a'+numItems);
+                   gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0, accelBuf);
+               }
+               else if ( ('A'+numItems-26)<='Z') {
+                   g_snprintf(accelBuf, sizeof(accelBuf), "%c ", 'A'+numItems-26); 
+                   gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0, accelBuf);
+               } else {
+                   accelBuf[0] = buf[0] = 0;
+               }
+               g_snprintf(buf, sizeof(buf), "%s", item->str);
+               gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 2, buf);
+               gtk_object_set_data (GTK_OBJECT (clist), "numItems",
+                                       GINT_TO_POINTER (numItems));
+
+               /* This junk is to specially handle the options menu */
+               pbuf = strstr( buf, " [");
+               if (pbuf == NULL) {
+                   pbuf = strstr( buf, "\t[");
+               }
+               if (pbuf != NULL) {
+                   *pbuf=0;
+                   pbuf++;
+                   gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 3, pbuf);
+               }
+           }
+           /* FIXME: handle more than 26*2 accelerators (but how?
+            * since I only have so many keys to work with???)
+           else
+           {
+               foo();
+           }
+           */
+           else {
+               g_snprintf(buf, sizeof(buf), "%s", item->str);
+               pbuf = strstr( buf, " [");
+               if (pbuf == NULL) {
+                   pbuf = strstr( buf, "\t[");
+               }
+               if (pbuf != NULL) {
+                   *pbuf=0;
+                   pbuf++;
+                   gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 3, pbuf);
+               }
+               gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 2, buf);
+               
+           }
+       }
+
+       if (item->attr) {
+           switch(item->attr) {
+               case ATR_ULINE:
+               case ATR_BOLD:
+               case ATR_BLINK:
+               case ATR_INVERSE:
+                   bigStyle = gtk_style_copy (GTK_WIDGET (clist)->style);
+                   g_assert (bigStyle != NULL);
+                   gdk_font_unref (bigStyle->font);
+                   bigStyle->font = gdk_font_load (
+                               "-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*");
+                   bigStyle->fg[GTK_STATE_NORMAL] = color_blue;
+                   gtk_clist_set_cell_style (GTK_CLIST (clist), 
+                           nCurrentRow, 2, bigStyle);
+                   item_selectable = FALSE;
+           }
+       }
+
+
+       g_assert (nCurrentRow >= 0);
+       gtk_clist_set_selectable (GTK_CLIST (clist), nCurrentRow,
+                             item_selectable);
+
+       if ( item_selectable==TRUE && item->presel== TRUE) {
+           /* pre-select this item */
+           gtk_clist_select_row( GTK_CLIST (clist), nCurrentRow, 0);
+       }
+       
+       gtk_object_set_data (GTK_OBJECT (clist), "numRows",
+                               GINT_TO_POINTER (nCurrentRow));
+        
+       /* We have to allocate memory here, since the menu_item currently
+        * lives on the stack, and will otherwise go to the great bit bucket 
+        * in the sky as soon as this function exits, which would leave a 
+        * pointer to crap in the row_data.  Use g_memdup to make a private, 
+        * persistant copy of the item identifier.
+        *
+        * We need to arrange to blow away this memory somewhere (like 
+        * ghack_menu_destroy and ghack_menu_window_clear for example).
+        *
+        *  -Erik
+        */
+       {
+           menuItem newItem;
+           menuItem *pNewItem;
+           
+           newItem.identifier = *item->identifier;
+           newItem.itemNumber=nCurrentRow;
+           newItem.selected=FALSE;
+           newItem.accelerator[0]=0;
+           /* only copy 1 char, since accel keys are by definition 1 char */
+           if (accelBuf[0]) {
+               strncpy(newItem.accelerator, accelBuf, 1);
+           }
+           newItem.accelerator[1]=0;
+
+           pNewItem = g_memdup(&newItem, sizeof( menuItem));
+           gtk_clist_set_row_data (GTK_CLIST (clist), nCurrentRow,
+                                   (gpointer) pNewItem);
+       }
+    }
+    /* Now adjust the column widths to match the contents */
+    gtk_clist_columns_autosize (GTK_CLIST (clist));
+}
+
+void
+ghack_menu_window_end_menu (GtkWidget *menuWin, gpointer data)
+{
+  const char* p = (const char*) data;
+
+  if ((p) && (*p)) {
+    GtkWidget *frame1 = gtk_object_get_data (GTK_OBJECT (menuWin), "frame1");
+    g_assert (frame1 != NULL);
+
+    gtk_frame_set_label (GTK_FRAME(frame1), p);
+  }
+
+}
+
+
+void ghack_menu_window_put_string(GtkWidget *menuWin, int attr,
+                                  const char* text, gpointer data)
+{
+    GnomeLess *gless;
+    MenuWinType isMenu;
+
+    if (text == NULL)
+        return;
+    
+    isMenu = (MenuWinType) GPOINTER_TO_INT
+       (gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu"));
+
+    if (isMenu == MenuText) {
+      gless = GNOME_LESS (gtk_object_get_data (GTK_OBJECT (menuWin), "gless"));
+      g_assert (gless != NULL);
+      g_assert (gless->text != NULL);
+      g_assert (GTK_IS_TEXT (gless->text));
+
+      /* Don't bother with attributes yet */
+      gtk_text_insert (GTK_TEXT (gless->text), NULL, NULL, NULL, text, -1);
+      gtk_text_insert (GTK_TEXT (gless->text), NULL, NULL, NULL, "\n", -1);
+
+    }
+
+    else if (isMenu == MenuUnknown) {
+      isMenu = MenuText;
+      gtk_object_set_data (GTK_OBJECT (menuWin), "isMenu",
+                          GINT_TO_POINTER (isMenu));
+
+      gtk_widget_set_usize (GTK_WIDGET (menuWin), 500, 400);
+      gtk_window_set_policy (GTK_WINDOW (menuWin), TRUE, TRUE, FALSE);
+    
+      gless = GNOME_LESS (gnome_less_new ());
+      g_assert (gless != NULL);
+      gtk_object_set_data (GTK_OBJECT (menuWin), "gless", gless);
+      gtk_widget_show (GTK_WIDGET (gless));
+
+      gnome_less_show_string (gless, text);
+      gtk_text_insert (GTK_TEXT (gless->text), NULL, NULL, NULL, "\n", -1);
+
+      gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (menuWin)->vbox),
+                         GTK_WIDGET (gless), TRUE, TRUE, 0);
+    }
+}
+
+
+void
+ghack_menu_destroy (GtkWidget *menuWin, gpointer data)
+{
+    MenuWinType isMenu;
+
+    isMenu = (MenuWinType) GPOINTER_TO_INT
+       (gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu"));
+
+    if (isMenu == MenuText) {
+      GnomeLess *gless;
+
+      gless = GNOME_LESS (gtk_object_get_data (GTK_OBJECT (menuWin), "gless"));
+      g_assert (gless != NULL);
+      g_assert (gless->text != NULL);
+      g_assert (GTK_IS_TEXT (gless->text));
+      gtk_widget_destroy(GTK_WIDGET(gless));
+    }
+
+    else if (isMenu == MenuMenu) {
+      GtkWidget *frame1, *swin, *clist; 
+
+      /* destroy existing menu data, if any */
+      clist = gtk_object_get_data (GTK_OBJECT (menuWin), "clist");
+      if (clist) {
+       /* destroy all the row_data we stored in the clist */
+       int i, numRows;
+       menuItem* item;
+       numRows = GPOINTER_TO_INT( gtk_object_get_data(
+                   GTK_OBJECT(clist), "numRows") );
+       for( i=0; i<numRows; i++) {
+           item = (menuItem*) gtk_clist_get_row_data( 
+                   GTK_CLIST (clist), i);
+           if (item != NULL) {
+               g_free( item);
+               gtk_clist_set_row_data (GTK_CLIST (clist), i, 
+                       (gpointer) NULL);
+           }
+       }
+
+       gtk_object_set_data (GTK_OBJECT (clist), "numItems",
+                               GINT_TO_POINTER (-1));
+       gtk_widget_destroy (clist);
+      }
+      swin = gtk_object_get_data (GTK_OBJECT (menuWin), "swin");
+      if (swin) {
+       gtk_widget_destroy (swin);
+      }
+      frame1 = gtk_object_get_data (GTK_OBJECT (menuWin), "frame1");
+      if (frame1) {
+       gtk_widget_destroy (frame1);
+      }
+    }
+    gnome_delete_nhwindow_by_reference (menuWin);    
+}
+
+
+GtkWidget*
+ghack_init_menu_window (void)
+{
+    GtkWidget *menuWin = NULL;
+    GtkWidget *parent = ghack_get_main_window ();
+
+    menuWin = gnome_dialog_new("GnomeHack", GNOME_STOCK_BUTTON_OK, 
+                   GNOME_STOCK_BUTTON_CANCEL, NULL);
+    
+    gnome_dialog_set_default( GNOME_DIALOG(menuWin), 0);
+    gtk_signal_connect(GTK_OBJECT(menuWin), "destroy",
+                   GTK_SIGNAL_FUNC(ghack_menu_destroy),
+                   NULL);
+
+    gtk_signal_connect (GTK_OBJECT (menuWin), "delete_event",
+                       GTK_SIGNAL_FUNC (ghack_menu_hide),
+                       NULL);
+          
+    gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_clear",
+                   GTK_SIGNAL_FUNC(ghack_menu_window_clear),
+                   NULL);
+
+    gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_display",
+                       GTK_SIGNAL_FUNC(ghack_menu_window_display),
+                       NULL);
+
+    gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_start_menu",
+                       GTK_SIGNAL_FUNC(ghack_menu_window_start_menu),
+                       NULL);
+
+    gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_add_menu",
+                       GTK_SIGNAL_FUNC(ghack_menu_window_add_menu),
+                       NULL);
+
+    gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_end_menu",
+                       GTK_SIGNAL_FUNC(ghack_menu_window_end_menu),
+                       NULL);
+
+    gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_select_menu",
+                       GTK_SIGNAL_FUNC(ghack_menu_window_select_menu),
+                       NULL);
+
+    gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_putstr",
+                       GTK_SIGNAL_FUNC(ghack_menu_window_put_string),
+                       NULL);
+
+    gtk_signal_connect(GTK_OBJECT(menuWin), "key_press_event",
+                       GTK_SIGNAL_FUNC(ghack_menu_window_key),
+                       NULL);
+
+    /* Center the dialog over parent */
+    g_assert (parent != NULL);
+    g_assert (menuWin != NULL);
+    g_assert (GTK_IS_WINDOW (parent));
+    g_assert (GNOME_IS_DIALOG (menuWin));
+    gnome_dialog_set_parent (GNOME_DIALOG (menuWin), GTK_WINDOW (parent));
+    
+    return menuWin;
+}
+
+static void
+ghack_ext_key_hit(GtkWidget *menuWin, GdkEventKey *event, gpointer data)
+{
+    GtkWidget* clist;
+    extMenu* info = (extMenu*) data;
+    int i;
+    char c = event->string[0];
+
+    clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist"));
+    g_assert(clist != NULL);
+
+    /* if too long between keystrokes, reset to initial state */
+    if (event->time - info->lastTime > 500) goto init_state;
+
+    /* see if current item continue to match */
+    if (info->charIdx > 0) {
+       if (extcmdlist[info->curItem].ef_txt[info->charIdx] == c) {
+           ++info->charIdx;
+           goto found;
+       }
+    }
+
+    /* see if the prefix matches a later command in the list */
+    if (info->curItem >= 0) {
+       for (i = info->curItem + 1; i < info->numRows; ++i) {
+           if (!strncmp(extcmdlist[info->curItem].ef_txt,
+                        extcmdlist[i].ef_txt, info->charIdx)) {
+               if (extcmdlist[i].ef_txt[info->charIdx] == c) {
+                   ++info->charIdx;
+                   info->curItem = i;
+                   goto found;
+               }
+           }
+       }
+    }
+               
+init_state:
+    /* reset to initial state, look for matching 1st character */
+    for (i = 0; i < info->numRows; ++i) {
+       if (extcmdlist[i].ef_txt[0] == c) {
+           info->charIdx = 1;
+           info->curItem = i;
+           goto found;
+       }
+    }
+
+    /* no match: leave prior, if any selection in place */
+    return;
+
+found:
+    info->lastTime = event->time;
+    gtk_clist_select_row(GTK_CLIST(clist), info->curItem, 0);
+    if (gtk_clist_row_is_visible(GTK_CLIST(clist),
+                                info->curItem) != GTK_VISIBILITY_FULL)
+       gtk_clist_moveto(GTK_CLIST(clist), info->curItem, 0, 0.5, 0);
+}
+
+int
+ghack_menu_ext_cmd(void)
+{
+    int n;
+    GtkWidget* dialog;
+    GtkWidget* swin;
+    GtkWidget* frame1;
+    GtkWidget* clist;
+    extMenu info;
+
+    dialog = gnome_dialog_new("Extended Commands",
+                             GNOME_STOCK_BUTTON_OK,
+                             GNOME_STOCK_BUTTON_CANCEL,
+                             NULL);
+    gnome_dialog_close_hides(GNOME_DIALOG(dialog), FALSE);
+    gtk_signal_connect(GTK_OBJECT(dialog), "key_press_event",
+                      GTK_SIGNAL_FUNC(ghack_ext_key_hit), &info);
+
+    frame1 = gtk_frame_new("Make your selection");
+    gtk_object_set_data(GTK_OBJECT(dialog), "frame1", frame1);
+    gtk_widget_show(frame1);
+    gtk_container_border_width(GTK_CONTAINER(frame1), 3);
+
+    swin = gtk_scrolled_window_new(NULL, NULL);
+    clist = gtk_clist_new(2);
+    gtk_object_set_data(GTK_OBJECT(dialog), "clist", clist);
+    gtk_widget_set_usize(clist, 500, 400);
+    gtk_container_add(GTK_CONTAINER(swin), clist);
+    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
+                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+    gtk_signal_connect(GTK_OBJECT(clist), "select_row",
+                      GTK_SIGNAL_FUNC(ghack_menu_row_selected), NULL);
+
+    gtk_container_add(GTK_CONTAINER(frame1), swin);
+    gtk_box_pack_start_defaults(GTK_BOX(GNOME_DIALOG(dialog)->vbox), frame1);
+
+    /* Add the extended commands into the list here... */
+    for (n = 0; extcmdlist[n].ef_txt; ++n) {
+       const char *text[3]={extcmdlist[n].ef_txt,extcmdlist[n].ef_desc,NULL};
+       gtk_clist_insert(GTK_CLIST(clist), n, (char**) text);
+    }
+
+    /* fill in starting info fields */
+    info.curItem = -1;
+    info.numRows = n;
+    info.charIdx = 0;
+    info.lastTime = 0;
+
+    gtk_clist_columns_autosize(GTK_CLIST(clist));
+    gtk_widget_show_all(swin);
+
+    /* Center the dialog over over parent */
+    gnome_dialog_set_default(GNOME_DIALOG(dialog), 0);
+    gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+    gnome_dialog_set_parent(GNOME_DIALOG(dialog),
+                           GTK_WINDOW(ghack_get_main_window()));
+
+    /* Run the dialog -- returning whichever button was pressed */
+    n = gnome_dialog_run_and_close(GNOME_DIALOG(dialog));
+
+    /* Quit on button 2 or error */
+    return (n != 0) ? -1 : info.curItem;
+}
diff --git a/win/gnome/gnmenu.h b/win/gnome/gnmenu.h
new file mode 100644 (file)
index 0000000..7055aa4
--- /dev/null
@@ -0,0 +1,32 @@
+/*     SCCS Id: @(#)gnmenu.h   3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackMenuWindow_h
+#define GnomeHackMenuWindow_h
+
+#include <gnome.h>
+#include "config.h"
+#include "global.h"
+#include "gnomeprv.h"
+
+GtkWidget* ghack_init_menu_window( void );
+
+struct _GHackMenuItem
+{
+  int          glyph; 
+  const ANY_P *identifier;
+  CHAR_P       accelerator;
+  CHAR_P       group_accel;
+  int          attr;
+  const char*  str;
+  BOOLEAN_P    presel;
+};
+
+typedef struct _GHackMenuItem GHackMenuItem;
+
+int ghack_menu_window_select_menu (GtkWidget *menuWin, 
+       MENU_ITEM_P **_selected, gint how);
+int ghack_menu_ext_cmd(void);
+
+#endif  /* GnomeHackMenuWindow_h */
diff --git a/win/gnome/gnmesg.c b/win/gnome/gnmesg.c
new file mode 100644 (file)
index 0000000..337a21b
--- /dev/null
@@ -0,0 +1,102 @@
+/*     SCCS Id: @(#)gnmesg.c   3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "gnmesg.h"
+#include "gnsignal.h"
+
+/* Pick an arbitrary number of chars such as 80 col X 40 rows text = 3200 chars */
+#define nCharsBeforeDeletingStuff      3200
+
+/* Message Window widgets */
+GtkWidget *MW_table;
+GtkWidget *MW_text;
+GtkWidget *MW_scrollbar;
+
+
+void ghack_message_window_clear(GtkWidget *widget, gpointer data)
+{
+    /* Seems nethack calls this after every move -- we don't want
+     * to really clear the window at all though.  Ignore the request */
+    gint len;
+
+    len = gtk_text_get_length(GTK_TEXT(MW_text));
+    
+    if(len < nCharsBeforeDeletingStuff)
+        return;
+    
+    gtk_text_freeze(GTK_TEXT(MW_text));
+    gtk_text_set_point(GTK_TEXT(MW_text), 0);
+    gtk_text_forward_delete(GTK_TEXT(MW_text), len-((guint)(nCharsBeforeDeletingStuff*0.5)));
+    gtk_text_set_point(GTK_TEXT(MW_text), (guint)(nCharsBeforeDeletingStuff*0.5));
+    gtk_text_thaw(GTK_TEXT(MW_text));
+}
+
+void ghack_message_window_destroy( GtkWidget *win, gpointer data)
+{
+
+}
+
+void ghack_message_window_display(GtkWidget *widget, boolean block,
+                                 gpointer data)
+{
+
+}
+
+void ghack_message_window_put_string(GtkWidget *widget, int attr,
+                                     const char* text, gpointer data)
+{
+
+    if(text == NULL)
+        return;
+    
+    /* Don't bother with attributes yet */
+    gtk_text_insert(GTK_TEXT(MW_text), NULL, NULL, NULL, text, -1);
+    gtk_text_insert(GTK_TEXT(MW_text), NULL, NULL, NULL, "\n", -1);
+}
+
+void ghack_message_window_use_RIP(int how)
+{
+
+}
+
+void ghack_message_window_scroll(int dx, int dy)
+{
+
+}
+
+GtkWidget* ghack_init_message_window(void)
+{
+
+    MW_table = gtk_table_new(2, 1, FALSE);
+    gtk_table_set_row_spacing(GTK_TABLE(MW_table), 0, 2);
+
+    MW_text = gtk_text_new(NULL, NULL);
+    gtk_text_set_editable(GTK_TEXT(MW_text), FALSE);
+    gtk_text_set_word_wrap(GTK_TEXT(MW_text), TRUE);
+    gtk_table_attach(GTK_TABLE(MW_table), MW_text, 0, 1, 0, 1,
+                     (GTK_EXPAND | GTK_FILL),
+                     (GTK_EXPAND | GTK_FILL),
+                     0, 0);
+
+    MW_scrollbar = gtk_vscrollbar_new(GTK_TEXT(MW_text)->vadj);
+    gtk_table_attach(GTK_TABLE(MW_table), MW_scrollbar, 1, 2, 0, 1,
+                     GTK_FILL, (GTK_EXPAND | GTK_FILL), 0, 0);
+    
+    gtk_signal_connect(GTK_OBJECT(MW_table), "ghack_putstr",
+                   GTK_SIGNAL_FUNC(ghack_message_window_put_string),
+                   NULL);
+
+    gtk_signal_connect(GTK_OBJECT(MW_table), "ghack_clear",
+                   GTK_SIGNAL_FUNC(ghack_message_window_clear),
+                   NULL);
+    
+    gtk_signal_connect(GTK_OBJECT(MW_table), "gnome_delay_output",
+                       GTK_SIGNAL_FUNC(ghack_delay), NULL);
+
+    gtk_widget_show_all(MW_table);
+
+    return GTK_WIDGET(MW_table);
+}
+
+
diff --git a/win/gnome/gnmesg.h b/win/gnome/gnmesg.h
new file mode 100644 (file)
index 0000000..139e63a
--- /dev/null
@@ -0,0 +1,23 @@
+/*     SCCS Id: @(#)gnmesg.h   3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackMessageWindow_h
+#define GnomeHackMessageWindow_h
+
+#include <gnome.h>
+#include "config.h"
+
+GtkWidget* ghack_init_message_window ( /* GnomeHackKeyBuffer g_keybuffer,
+                                         GnomeHackClickBuffer g_clickbuffer */ );
+void ghack_message_window_clear(GtkWidget *widget, gpointer data);
+void ghack_message_window_destroy();
+void ghack_message_window_display(GtkWidget *widget, boolean block,
+                                  gpointer data);
+void ghack_message_window_put_string(GtkWidget *widget, int attr,
+                                     const char* text, gpointer data);
+void ghack_message_window_use_RIP(int how);
+void ghack_message_window_scroll(int dx, int dy);
+
+
+#endif /* GnomeHackMessageWindow_h */
diff --git a/win/gnome/gnomeprv.h b/win/gnome/gnomeprv.h
new file mode 100644 (file)
index 0000000..515437f
--- /dev/null
@@ -0,0 +1,18 @@
+/*     SCCS Id: @(#)gnomeprv.h 3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHack_h
+#define GnomeHack_h
+
+/* These are the base nethack include files */
+#include "hack.h"
+#include "dlb.h"
+#include "patchlevel.h"
+
+#include "winGnome.h"
+
+#endif    /* GnomeHack_h */
+
+
+
diff --git a/win/gnome/gnopts.c b/win/gnome/gnopts.c
new file mode 100644 (file)
index 0000000..04d0073
--- /dev/null
@@ -0,0 +1,117 @@
+/*     SCCS Id: @(#)gnopts.c   3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "gnopts.h"
+#include "gnglyph.h"
+#include "gnmain.h"
+#include "gnmap.h"
+#include <gnome.h>
+#include <ctype.h>
+#include "hack.h"
+
+static gint tileset;
+static GtkWidget* clist;
+const char* tilesets[] = { "Traditional (16x16)", "Big (32x32)", 0 };
+
+static void
+opt_sel_key_hit(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+      int i;
+      for (i = 0; tilesets[i] != 0; ++i) {
+             if (tilesets[i][0] == toupper(event->keyval)) {
+                     tileset = i;
+                     gtk_clist_select_row( GTK_CLIST (clist), i, 0);
+             }
+      }
+}
+
+static void
+opt_sel_row_selected(GtkCList *cList, int row, int col, GdkEvent *event)
+{
+    tileset = row;
+}
+
+void
+ghack_settings_dialog()
+{
+    int i;
+    static GtkWidget* dialog;
+    static GtkWidget* swin;
+    static GtkWidget* frame1;
+
+    dialog = gnome_dialog_new (_("GnomeHack Settings"),
+                           GNOME_STOCK_BUTTON_OK,
+                           GNOME_STOCK_BUTTON_CANCEL,
+                           NULL);
+    gnome_dialog_close_hides (GNOME_DIALOG (dialog), FALSE);
+    gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event",
+                     GTK_SIGNAL_FUNC (opt_sel_key_hit), tilesets );
+
+    frame1 = gtk_frame_new (_("Choose one of the following tilesets:"));
+    gtk_object_set_data (GTK_OBJECT (dialog), "frame1", frame1);
+    gtk_widget_show (frame1);
+    gtk_container_border_width (GTK_CONTAINER (frame1), 3);
+
+    swin = gtk_scrolled_window_new (NULL, NULL);
+    clist = gtk_clist_new (2);
+    gtk_clist_column_titles_hide (GTK_CLIST (clist));
+    gtk_widget_set_usize (GTK_WIDGET (clist), 100, 180);
+    gtk_container_add (GTK_CONTAINER (swin), clist);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
+           GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+    gtk_signal_connect (GTK_OBJECT (clist), "select_row",
+                       GTK_SIGNAL_FUNC (opt_sel_row_selected), NULL );
+
+    gtk_container_add (GTK_CONTAINER (frame1), swin);
+    gtk_box_pack_start_defaults (GTK_BOX (GNOME_DIALOG (dialog)->vbox), frame1);
+
+    /* Add the tilesets into the list here... */
+    for (i=0; tilesets[i]; i++) {
+           gchar accelBuf[BUFSZ];
+           const char *text[3]={accelBuf, tilesets[i],NULL};
+           sprintf( accelBuf, "%c ", tolower(tilesets[i][0]));
+           gtk_clist_insert (GTK_CLIST (clist), i, (char**)text);
+    }
+
+
+    gtk_clist_columns_autosize (GTK_CLIST (clist));
+    gtk_widget_show_all (swin);
+
+    /* Center the dialog over over parent */
+    gnome_dialog_set_default( GNOME_DIALOG(dialog), 0);
+    gtk_window_set_modal( GTK_WINDOW(dialog), TRUE);
+    gnome_dialog_set_parent (GNOME_DIALOG (dialog),
+           GTK_WINDOW (ghack_get_main_window ()) );
+
+    /* Run the dialog -- returning whichever button was pressed */
+    i = gnome_dialog_run (GNOME_DIALOG (dialog));
+    gnome_dialog_close (GNOME_DIALOG (dialog));
+
+    /* They hit Quit or error */
+    if (i != 0 ) {
+       return;
+    }
+    switch (tileset) {
+       case 0:
+           /* They selected traditional */
+           ghack_free_glyphs();
+           if (ghack_init_glyphs(HACKDIR "/x11tiles"))
+                     g_error ("ERROR:  Could not initialize glyphs.\n");
+           ghack_reinit_map_window();
+           break;
+       case 1:
+           ghack_free_glyphs();
+           if (ghack_init_glyphs(HACKDIR "/t32-1024.xpm"))
+                     g_error ("ERROR:  Could not initialize glyphs.\n");
+           ghack_reinit_map_window();
+
+           /* They selected big */
+           break;
+       default:
+           /* This shouldn't happen */
+           g_warning("This shouldn't happen\n");
+    }
+}
+
diff --git a/win/gnome/gnopts.h b/win/gnome/gnopts.h
new file mode 100644 (file)
index 0000000..83ff37b
--- /dev/null
@@ -0,0 +1,13 @@
+/*     SCCS Id: @(#)gnopts.h   3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackSettings_h
+#define GnomeHackSettings_h
+
+
+void ghack_settings_dialog( void);
+
+
+#endif /* GnomeHackSettings.h */
+
diff --git a/win/gnome/gnplayer.c b/win/gnome/gnplayer.c
new file mode 100644 (file)
index 0000000..f10fcd2
--- /dev/null
@@ -0,0 +1,103 @@
+/*     SCCS Id: @(#)gnplayer.c 3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include <gnome.h>
+#include <ctype.h>
+#include "gnplayer.h"
+#include "gnmain.h"
+#include "hack.h"
+
+static gint role_number;
+static GtkWidget* clist;
+
+static void
+player_sel_key_hit (GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+    const char** roles = data;
+    int i;
+    for (i = 0; roles[i] != 0; ++i) {
+       if (tolower(roles[i][0]) == tolower(event->keyval)) {
+           role_number = i;
+           gtk_clist_select_row( GTK_CLIST (clist), i, 0);
+           if (gtk_clist_row_is_visible(GTK_CLIST(clist),
+                                        i) != GTK_VISIBILITY_FULL)
+               gtk_clist_moveto(GTK_CLIST(clist), i, 0, 0.5, 0);
+       }
+    }
+}
+
+static void
+player_sel_row_selected (GtkCList *clist, int row, int col, GdkEvent *event)
+{
+    role_number = row;
+}
+
+int
+ghack_player_sel_dialog(const char** choices,
+                       const gchar* title,
+                       const gchar* prompt)
+{
+    int i;
+    static GtkWidget* dialog;
+    static GtkWidget* swin;
+    static GtkWidget* frame1;
+
+    dialog = gnome_dialog_new(title,
+                           GNOME_STOCK_BUTTON_OK,
+                           _("Random"),
+                           GNOME_STOCK_BUTTON_CANCEL,
+                           NULL);
+    gnome_dialog_close_hides (GNOME_DIALOG (dialog), FALSE);
+    gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event",
+                      GTK_SIGNAL_FUNC (player_sel_key_hit), choices );
+
+    frame1 = gtk_frame_new(prompt);
+    gtk_object_set_data (GTK_OBJECT (dialog), "frame1", frame1);
+    gtk_widget_show (frame1);
+    gtk_container_border_width (GTK_CONTAINER (frame1), 3);
+
+    swin = gtk_scrolled_window_new (NULL, NULL);
+    clist = gtk_clist_new (2);
+    gtk_clist_column_titles_hide (GTK_CLIST (clist));
+    gtk_widget_set_usize (GTK_WIDGET (clist), 100, 180);
+    gtk_container_add (GTK_CONTAINER (swin), clist);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
+           GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+    gtk_signal_connect (GTK_OBJECT (clist), "select_row",
+                       GTK_SIGNAL_FUNC (player_sel_row_selected), NULL );
+
+    gtk_container_add (GTK_CONTAINER (frame1), swin);
+    gtk_box_pack_start_defaults (GTK_BOX (GNOME_DIALOG (dialog)->vbox), frame1);
+
+    /* Add the roles into the list here... */
+    for (i=0; choices[i]; i++) {
+           gchar accelBuf[BUFSZ];
+           const char *text[3]={accelBuf, choices[i],NULL};
+           sprintf( accelBuf, "%c ", tolower(choices[i][0]));
+           gtk_clist_insert (GTK_CLIST (clist), i, (char**)text);
+    }
+
+    gtk_clist_columns_autosize (GTK_CLIST (clist));
+    gtk_widget_show_all (swin);
+
+    /* Center the dialog over over parent */
+    gnome_dialog_set_default( GNOME_DIALOG(dialog), 0);
+    gtk_window_set_modal( GTK_WINDOW(dialog), TRUE);
+    gnome_dialog_set_parent (GNOME_DIALOG (dialog),
+           GTK_WINDOW (ghack_get_main_window ()) );
+
+    /* Run the dialog -- returning whichever button was pressed */
+    i = gnome_dialog_run_and_close(GNOME_DIALOG(dialog));
+
+    /* Quit on button 2 or error */
+    if (i < 0  || i > 1) {
+       return(ROLE_NONE);
+    }
+    /* Random is button 1*/
+    if (i == 1 ) {
+       return(ROLE_RANDOM);
+    }
+    return ( role_number);
+}
diff --git a/win/gnome/gnplayer.h b/win/gnome/gnplayer.h
new file mode 100644 (file)
index 0000000..73929de
--- /dev/null
@@ -0,0 +1,10 @@
+/*     SCCS Id: @(#)gnplayer.h 3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackPlayerSelDialog_h
+#define GnomeHackPlayerSelDialog_h
+
+int ghack_player_sel_dialog(const char **, const gchar*, const gchar*);
+
+#endif /* GnomeHackPlayerSelDialog_h */
diff --git a/win/gnome/gnsignal.c b/win/gnome/gnsignal.c
new file mode 100644 (file)
index 0000000..2e5b621
--- /dev/null
@@ -0,0 +1,442 @@
+/*     SCCS Id: @(#)gnsignal.c 3.4     2000/07/16      */
+/* Copyright (C) 1998 by Anthony Taylor <tonyt@ptialaska.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "gnsignal.h"
+#include "gnmain.h"
+#include <gdk/gdkkeysyms.h>
+
+GList *g_keyBuffer;
+GList *g_clickBuffer;
+int g_numKeys=0;
+int g_numClicks=0;
+int g_askingQuestion=0;
+static int s_done=FALSE;
+
+/*
+ * ghack_init_signals
+ *
+ * Create some signals and attach them to the GtkWidget class.
+ * These are the signals:
+ *
+ *     ghack_curs        : NONE:INT,INT
+ *                            INT 1 = x
+ *                            INT 2 = y
+ *
+ *     ghack_putstr      : NONE:INT,POINTER
+ *                            INT     = attribute
+ *                            POINTER = char* string to print
+ *
+ *     ghack_print_glyph : NONE:INT,INT,POINTER
+ *                            INT 1 = x
+ *                            INT 2 = y
+ *                            INT 3 = GtkPixmap* to rendered glyph
+ *
+ *     ghack_clear       : NONE:NONE
+ *
+ *     ghack_display     : NONE:BOOL
+ *                            BOOL  = blocking flag
+ *
+ *     ghack_start_menu  : NONE:NONE
+ *
+ *     ghack_add_menu    : NONE:POINTER
+ *                            POINTER = GHackMenuItem*
+ *
+ *     ghack_end_menu    : NONE:POINTER
+ *                            POINTER = char* to closing string
+ *
+ *     ghack_select_menu : NONE:POINTER,INT,POINTER
+ *                            POINTER    = int pointer-- filled with number
+ *                                         of selected items on return
+ *                            INT        = number of items selected
+ *                            POINTER    = structure to fill
+ *
+ *     ghack_cliparound  : NONE:INT,INT
+ *                            INT 1 = x
+ *                            INT 2 = y
+*/
+
+void
+ghack_init_signals( void)
+{
+  ghack_signals[GHSIG_CURS] =
+    gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
+                                     "ghack_curs",
+                                     GTK_RUN_FIRST,
+                                     gtk_marshal_NONE__INT_INT,
+                                     GTK_TYPE_NONE,
+                                     2,
+                                     GTK_TYPE_INT,
+                                     GTK_TYPE_INT);  
+
+  ghack_signals[GHSIG_PUTSTR] =
+    gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
+                                     "ghack_putstr",
+                                     GTK_RUN_FIRST,
+                                     gtk_marshal_NONE__INT_POINTER,
+                                     GTK_TYPE_NONE,
+                                     2,
+                                     GTK_TYPE_INT,
+                                     GTK_TYPE_POINTER);
+
+  ghack_signals[GHSIG_PRINT_GLYPH] =
+    gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
+                                     "ghack_print_glyph",
+                                     GTK_RUN_FIRST,
+                                     gtk_marshal_NONE__INT_INT_POINTER,
+                                     GTK_TYPE_NONE,
+                                     3,
+                                     GTK_TYPE_INT,
+                                     GTK_TYPE_INT,
+                                     GTK_TYPE_POINTER);
+
+  ghack_signals[GHSIG_CLEAR] =
+    gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
+                                     "ghack_clear",
+                                     GTK_RUN_FIRST,
+                                     gtk_marshal_NONE__NONE,
+                                     GTK_TYPE_NONE,
+                                     0);
+  
+  ghack_signals[GHSIG_DISPLAY] =
+    gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
+                                     "ghack_display",
+                                     GTK_RUN_FIRST,
+                                     gtk_marshal_NONE__BOOL,
+                                     GTK_TYPE_NONE,
+                                     1,
+                                     GTK_TYPE_BOOL);
+  
+  ghack_signals[GHSIG_START_MENU] =
+    gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
+                                     "ghack_start_menu",
+                                     GTK_RUN_FIRST,
+                                     gtk_marshal_NONE__NONE,
+                                     GTK_TYPE_NONE,
+                                     0);
+  
+  ghack_signals[GHSIG_ADD_MENU] =
+    gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
+                                     "ghack_add_menu",
+                                     GTK_RUN_FIRST,
+                                     gtk_marshal_NONE__POINTER,
+                                     GTK_TYPE_NONE,
+                                     1,
+                                     GTK_TYPE_POINTER);
+  
+  ghack_signals[GHSIG_END_MENU] =
+    gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
+                                     "ghack_end_menu",
+                                     GTK_RUN_FIRST,
+                                     gtk_marshal_NONE__POINTER,
+                                     GTK_TYPE_NONE,
+                                     1,
+                                     GTK_TYPE_POINTER);
+  
+  ghack_signals[GHSIG_SELECT_MENU] =
+    gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
+                                     "ghack_select_menu",
+                                     GTK_RUN_FIRST,
+                                     gtk_marshal_NONE__POINTER_INT_POINTER,
+                                     GTK_TYPE_NONE,
+                                     3,
+                                     GTK_TYPE_POINTER,
+                                     GTK_TYPE_INT,
+                                     GTK_TYPE_POINTER);
+  
+  ghack_signals[GHSIG_CLIPAROUND] =
+    gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
+                                     "ghack_cliparound",
+                                     GTK_RUN_FIRST,
+                                     gtk_marshal_NONE__INT_INT,
+                                     GTK_TYPE_NONE,
+                                     2,
+                                     GTK_TYPE_INT,
+                                     GTK_TYPE_INT);
+
+  ghack_signals[GHSIG_FADE_HIGHLIGHT] =
+    gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
+                                     "ghack_fade_highlight",
+                                     GTK_RUN_FIRST,
+                                     gtk_marshal_NONE__NONE,
+                                     GTK_TYPE_NONE,
+                                     0);
+  
+  ghack_signals[GHSIG_DELAY] =
+    gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
+                                     "gnome_delay_output",
+                                     GTK_RUN_FIRST,
+                                     gtk_marshal_NONE__INT,
+                                     GTK_TYPE_NONE,
+                                     1,
+                                     GTK_TYPE_INT);
+  
+}
+
+/* For want of a better place, I'm putting the delay output stuff here
+ *   -Erik
+ */
+static gint timeout_callback(gpointer data)
+{
+    s_done=TRUE;
+    return FALSE;
+}
+
+void
+ghack_delay( GtkWidget *win, int numMillisecs, gpointer data)
+{
+    s_done=FALSE;
+    gtk_timeout_add( (unsigned int) numMillisecs, 
+           timeout_callback, NULL);
+    while( s_done==FALSE)
+       gtk_main_iteration();
+}
+
+
+void 
+ghack_handle_button_press(GtkWidget *widget, GdkEventButton *event, 
+       gpointer data)
+{
+    GHClick *click;
+    double x1, y1;
+
+    if (event->type != GDK_BUTTON_PRESS)
+       return;
+    
+    gnome_canvas_window_to_world( GNOME_CANVAS( widget), event->x, 
+           event->y, &x1, &y1);
+/*
+    g_message("I got a click at %f,%f with button %d \n", 
+           x1, y1, event->button);
+*/
+
+    /* We allocate storage here, so we need to remember if (g_numClicks>0)
+     * to blow this away when closing the app using something like 
+     *  while (g_clickBuffer)
+     *       {
+     *         g_free((GHClick)g_clickBuffer->data);
+     *          g_clickBuffer = g_clickBuffer->next;
+     *       }
+     *  g_list_free( g_clickBuffer );
+     *
+     */
+    click = g_new( GHClick, 1);
+    
+    click->x=(int)x1/ghack_glyph_width();
+    click->y=(int)y1/ghack_glyph_height();
+    click->mod=(event->button == 1)? CLICK_1 : CLICK_2;
+    
+    g_clickBuffer = g_list_prepend (g_clickBuffer, click);
+    /* Could use g_list_length(), but it is stupid and just
+     * traverses the list while counting, so we'll just do 
+     * the counting ourselves in advance. */
+    g_numClicks++;
+}
+
+#ifndef M
+# ifndef NHSTDC
+#  define M(c)          (0x80 | (c))
+# else
+#  define M(c)          ((c) - 128)
+# endif /* NHSTDC */
+#endif
+#ifndef C
+#define C(c)            (0x1f & (c))
+#endif
+
+
+void 
+ghack_handle_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+    static int was_pound = 0;
+    int key = 0;
+    int ctl = GDK_CONTROL_MASK;
+    int alt = GDK_MOD1_MASK;
+
+    /* Turn this on to debug key events */
+#if 0
+    g_message("I got a \"%s\" key (%d) %s%s", 
+             gdk_keyval_name (event->keyval), event->keyval, 
+             (event->state&ctl)? "+CONTROL":"", (event->state&alt)? "+ALT":"");
+#endif
+
+    switch (event->keyval) {
+       /* special keys to do stuff with */
+
+       /* Set up the direction keys */
+
+       /* First handle the arrow keys -- these always mean move */
+    case GDK_Right:
+    case GDK_rightarrow:
+       if (iflags.num_pad) key='6'; else  key='l'; break;
+    case GDK_Left:
+    case GDK_leftarrow:
+       if (iflags.num_pad) key='4'; else  key='h'; break;
+    case GDK_Up:
+    case GDK_uparrow:
+       if (iflags.num_pad) key='8'; else  key='k'; break;
+    case GDK_Down:
+    case GDK_downarrow:
+       if (iflags.num_pad) key='2'; else  key='j'; break;
+    case GDK_Home:
+       if (iflags.num_pad) key='7'; else  key='y'; break;
+    case GDK_End:
+       if (iflags.num_pad) key='1'; else  key='b'; break;
+    case GDK_Page_Down:
+       if (iflags.num_pad) key='3'; else  key='n'; break;
+    case GDK_Page_Up:
+       if (iflags.num_pad) key='9'; else  key='u'; break;
+    case ' ':           key='.'; break;
+
+       /* Now, handle the numberpad (move or numbers) */
+    case GDK_KP_Right:
+    case GDK_KP_6:
+       if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
+           key = GDK_KP_6;
+       else
+           key='6'; 
+       break;
+
+    case GDK_KP_Left:
+    case GDK_KP_4:
+       if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
+           key = GDK_KP_4;
+       else
+           key='4'; 
+       break;
+
+    case GDK_KP_Up:
+    case GDK_KP_8:
+       if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
+           key = GDK_KP_8;
+       else
+           key='8'; 
+       break;
+
+    case GDK_KP_Down:
+    case GDK_KP_2:
+       if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
+           key = GDK_KP_2;
+       else
+           key='2'; 
+       break;
+
+       /* Move Top-Left */
+    case GDK_KP_Home:
+    case GDK_KP_7:
+       if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
+           key = GDK_KP_7;
+       else
+           key='7'; 
+       break;
+
+    case GDK_KP_Page_Up:
+    case GDK_KP_9:
+       if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
+           key = GDK_KP_9;
+       else
+           key='9'; 
+       break;
+
+    case GDK_KP_End:
+    case GDK_KP_1:
+       if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
+           key = GDK_KP_1;
+       else
+           key='1'; 
+       break;
+
+    case GDK_KP_Page_Down:
+    case GDK_KP_3:
+       if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
+           key = GDK_KP_3;
+       else
+           key='3'; 
+       break;
+  
+  
+    case GDK_KP_5:
+       if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
+           key = GDK_KP_5;
+       else
+           key='5'; 
+       break;
+
+    case GDK_KP_Delete:
+    case GDK_KP_Decimal:
+       key='.'; 
+       break;
+
+       /* can't just ignore "#", it's a core feature */
+    case GDK_numbersign:
+       key='#';
+       break;
+
+       /* We will probably want to do something with these later... */
+    case GDK_KP_Begin:
+    case GDK_KP_F1:
+    case GDK_F1:
+    case GDK_KP_F2:
+    case GDK_F2:
+    case GDK_KP_F3:
+    case GDK_F3:
+    case GDK_KP_F4:
+    case GDK_F4:
+    case GDK_F5:
+    case GDK_F6:
+    case GDK_F7:
+    case GDK_F8:
+    case GDK_F9:
+    case GDK_F10:
+    case GDK_F11:
+    case GDK_F12:
+       break;
+       /* various keys to ignore */
+    case GDK_KP_Insert:
+    case GDK_Insert:
+    case GDK_Delete:
+    case GDK_Print:
+    case GDK_BackSpace:
+    case GDK_Pause:
+    case GDK_Scroll_Lock:
+    case GDK_Shift_Lock:
+    case GDK_Num_Lock:
+    case GDK_Caps_Lock:
+    case GDK_Control_L:
+    case GDK_Control_R:
+    case GDK_Shift_L:
+    case GDK_Shift_R:
+    case GDK_Alt_L:
+    case GDK_Alt_R:
+    case GDK_Meta_L:
+    case GDK_Meta_R:
+    case GDK_Mode_switch:
+    case GDK_Multi_key:
+       return;
+
+    default:
+       key = event->keyval;
+       break;
+    }
+
+    if ((event->state & alt) || was_pound) {
+       key=M(event->keyval);
+    } else if (event->state & ctl) {
+       key=C(event->keyval);
+    }
+    if (was_pound) {
+       was_pound = 0;
+    }
+    /* Ok, here is where we do clever stuff to overide the default
+     * game behavior */
+    if (g_askingQuestion == 0) {
+
+       if (key == 'S' || key == M('S') || key == C('S')) {
+           ghack_save_game_cb( NULL, NULL);
+           return;
+       }
+    }
+    g_keyBuffer = g_list_prepend (g_keyBuffer, GINT_TO_POINTER( key));
+    g_numKeys++;
+}
diff --git a/win/gnome/gnsignal.h b/win/gnome/gnsignal.h
new file mode 100644 (file)
index 0000000..52fa299
--- /dev/null
@@ -0,0 +1,56 @@
+/*     SCCS Id: @(#)gnsignal.h 3.4     2000/07/16      */
+/* Copyright (C) 1998 by Anthony Taylor <tonyt@ptialaska.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackSignals_h
+#define GnomeHackSignals_h
+
+#include <gtk/gtk.h>
+#include <gnome.h>
+#include "gnomeprv.h"
+#include "gnglyph.h"
+
+/* The list of custom signals */
+
+enum {
+  GHSIG_CURS,
+  GHSIG_PUTSTR,
+  GHSIG_PRINT_GLYPH,
+  GHSIG_CLEAR,
+  GHSIG_DISPLAY,
+  GHSIG_START_MENU,
+  GHSIG_ADD_MENU,
+  GHSIG_END_MENU,
+  GHSIG_SELECT_MENU,
+  GHSIG_CLIPAROUND,
+  GHSIG_FADE_HIGHLIGHT,
+  GHSIG_DELAY,
+  GHSIG_LAST_SIG
+};
+
+guint ghack_signals[GHSIG_LAST_SIG];
+
+extern void ghack_init_signals( void);
+
+
+void ghack_handle_key_press(GtkWidget *widget, GdkEventKey *event, 
+       gpointer data);
+void ghack_handle_button_press(GtkWidget *widget, GdkEventButton *event, 
+       gpointer data);
+
+typedef struct {
+        int x, y, mod;
+} GHClick;
+
+extern GList *g_keyBuffer;
+extern GList *g_clickBuffer;
+extern int g_numKeys;
+extern int g_numClicks;
+
+extern int g_askingQuestion;
+
+void ghack_delay( GtkWidget *win, int numMillisecs, gpointer data);
+
+
+#endif    /* GnomeHackSignals_h */
+
diff --git a/win/gnome/gnstatus.c b/win/gnome/gnstatus.c
new file mode 100644 (file)
index 0000000..1075a5e
--- /dev/null
@@ -0,0 +1,941 @@
+/*     SCCS Id: @(#)gnstatus.c 3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "gnstatus.h"
+#include "gnsignal.h"
+#include "gn_xpms.h"
+#include "gnomeprv.h"
+
+
+extern const char *hu_stat[]; /* from eat.c */
+extern const char *enc_stat[]; /* from botl.c */
+
+void ghack_status_window_update_stats();
+void ghack_status_window_clear(GtkWidget *win, gpointer data);
+void ghack_status_window_destroy(GtkWidget *win, gpointer data);
+void ghack_status_window_display(GtkWidget *win, boolean block, gpointer data);
+void ghack_status_window_cursor_to(GtkWidget *win, int x, int y, gpointer data);
+void ghack_status_window_put_string(GtkWidget *win, int attr, const char* text, gpointer data);
+
+static void ghack_fade_highlighting();
+static void ghack_highlight_widget( GtkWidget* widget, GtkStyle* oldStyle, 
+       GtkStyle* newStyle);
+
+/* some junk to handle when to fade the highlighting */
+#define NUM_TURNS_HIGHLIGHTED  3
+
+static GList   *s_HighLightList;
+
+typedef struct {
+    GtkWidget* widget;
+    GtkStyle*  oldStyle;
+    int                nTurnsLeft;
+} Highlight;
+
+
+/* Ok, now for a LONG list of widgets... */
+static GtkWidget* statTable = NULL;
+static GtkWidget* titleLabel = NULL;
+static GtkWidget* dgnLevelLabel = NULL;
+static GtkWidget* strPix = NULL;
+static GtkWidget* strLabel = NULL;
+static GtkWidget* dexPix = NULL;
+static GtkWidget* dexLabel = NULL;
+static GtkWidget* intPix = NULL;
+static GtkWidget* intLabel = NULL;
+static GtkWidget* wisPix = NULL;
+static GtkWidget* wisLabel = NULL;
+static GtkWidget* conPix = NULL;
+static GtkWidget* conLabel = NULL;
+static GtkWidget* chaPix = NULL;
+static GtkWidget* chaLabel = NULL;
+static GtkWidget* goldLabel = NULL;
+static GtkWidget* hpLabel = NULL;
+static GtkWidget* powLabel = NULL;
+static GtkWidget* acLabel = NULL;
+static GtkWidget* levlLabel = NULL;
+static GtkWidget* expLabel = NULL;
+static GtkWidget* timeLabel = NULL;
+static GtkWidget* scoreLabel = NULL;
+static GtkWidget* alignPix = NULL;
+static GtkWidget* alignLabel = NULL;
+static GtkWidget* hungerPix = NULL;
+static GtkWidget* hungerLabel = NULL;
+static GtkWidget* sickPix = NULL;
+static GtkWidget* sickLabel = NULL;
+static GtkWidget* blindPix = NULL;
+static GtkWidget* blindLabel = NULL;
+static GtkWidget* stunPix = NULL;
+static GtkWidget* stunLabel = NULL;
+static GtkWidget* halluPix = NULL;
+static GtkWidget* halluLabel = NULL;
+static GtkWidget* confuPix = NULL;
+static GtkWidget* confuLabel = NULL;
+static GtkWidget* encumbPix = NULL;
+static GtkWidget* encumbLabel = NULL;
+
+
+static GtkStyle* normalStyle = NULL;
+static GtkStyle* bigStyle = NULL;
+static GtkStyle* redStyle = NULL;
+static GtkStyle* greenStyle = NULL;
+static GtkStyle* bigRedStyle = NULL;
+static GtkStyle* bigGreenStyle = NULL;
+
+/* Pure red */
+static GdkColor color_red   = { 0, 0xff00, 0, 0 };
+/* ForestGreen (looks better than just pure green) */
+static GdkColor color_green = { 0, 0x2200, 0x8b00, 0x2200 };
+
+static int lastDepth;
+static int lastStr;
+static int lastInt;
+static int lastWis;
+static int lastDex;
+static int lastCon;
+static int lastCha;
+static long lastAu;
+static int lastHP;
+static int lastMHP;
+static int lastLevel;
+static int lastPOW;
+static int lastMPOW;
+static int lastAC;
+static int lastExp;
+static aligntyp lastAlignment;  
+static unsigned lastHungr;
+static long lastConf;
+static long lastBlind;
+static long lastStun;
+static long lastHalu;
+static long lastSick;
+static int lastEncumb;
+
+void ghack_status_window_clear( GtkWidget *win, gpointer data)
+{
+    /* Don't think we need this at all */
+}
+
+void ghack_status_window_destroy(GtkWidget *win, gpointer data)
+{
+    while (s_HighLightList) {
+       g_free( (Highlight*)s_HighLightList->data);
+       s_HighLightList = s_HighLightList->next;
+    }
+    g_list_free( s_HighLightList );
+}
+
+void ghack_status_window_display( GtkWidget *win, boolean block, gpointer data)
+{
+    gtk_widget_show_all( GTK_WIDGET(win));
+}
+
+void ghack_status_window_cursor_to( GtkWidget *win, int x, int y, gpointer data)
+{
+    /* Don't think we need this at all */
+}
+
+void ghack_status_window_put_string( GtkWidget *win, int attr, const char* text, gpointer data)
+{
+    ghack_status_window_update_stats();
+}
+
+
+
+GtkWidget* ghack_init_status_window ()
+{
+    GtkWidget *horizSep0, *horizSep1, *horizSep2, *horizSep3;
+    GtkWidget *statsHBox, *strVBox, *dexVBox, *intVBox, *statHBox;
+    GtkWidget *wisVBox, *conVBox, *chaVBox;
+    GtkWidget *alignVBox, *hungerVBox, *sickVBox, *blindVBox;
+    GtkWidget *stunVBox, *halluVBox, *confuVBox, *encumbVBox;
+   
+    /* Set up a (ridiculous) initial state */
+    lastDepth = 9999;
+    lastStr = 9999;
+    lastInt = 9999;
+    lastWis = 9999;
+    lastDex = 9999;
+    lastCon = 9999;
+    lastCha = 9999;
+    lastAu = 9999;
+    lastHP = 9999;
+    lastMHP = 9999;
+    lastLevel = 9999;
+    lastPOW = 9999;
+    lastMPOW = 9999;
+    lastAC = 9999;
+    lastExp = 9999;
+    lastAlignment = A_NEUTRAL;  /* start off guessing neutral */
+    lastHungr = 9999;
+    lastConf = 9999;
+    lastBlind = 9999;
+    lastStun = 9999;
+    lastHalu = 9999;
+    lastSick = 9999;
+    lastEncumb = 9999;
+
+    statTable = gtk_table_new( 10, 8, FALSE);
+    gtk_table_set_row_spacings( GTK_TABLE( statTable), 1);
+    gtk_table_set_col_spacings( GTK_TABLE( statTable), 1);
+
+
+    /* Begin the first row of the table -- the title */
+    titleLabel = gtk_label_new( _("GnomeHack!")); 
+    gtk_table_attach( GTK_TABLE( statTable), titleLabel, 
+           0, 8, 0, 1, GTK_FILL, 0, 0, 0);
+    if (!normalStyle)
+      normalStyle = gtk_style_copy (
+               gtk_widget_get_style (GTK_WIDGET (titleLabel)));
+
+    /* Set up some styles to draw stuff with */
+    if (!redStyle) {
+      g_assert (greenStyle == NULL);
+      g_assert (bigStyle == NULL);
+      g_assert (bigRedStyle == NULL);
+      g_assert (bigGreenStyle == NULL);
+
+      greenStyle = gtk_style_copy (normalStyle);
+      redStyle = gtk_style_copy (normalStyle);
+      bigRedStyle = gtk_style_copy (normalStyle);
+      bigGreenStyle = gtk_style_copy (normalStyle);
+      bigStyle = gtk_style_copy (normalStyle);
+
+      greenStyle->fg[GTK_STATE_NORMAL] = color_green;
+      redStyle->fg[GTK_STATE_NORMAL] = color_red;
+      bigRedStyle->fg[GTK_STATE_NORMAL] = color_red;
+      bigGreenStyle->fg[GTK_STATE_NORMAL] = color_green;
+
+      gdk_font_unref (bigRedStyle->font);
+      gdk_font_unref (bigGreenStyle->font);
+      bigRedStyle->font = gdk_font_load("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*");
+      bigGreenStyle->font = gdk_font_load("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*");
+
+      gdk_font_unref (bigStyle->font);
+      bigStyle->font = gdk_font_load ("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*");
+    }
+    gtk_widget_set_style (GTK_WIDGET (titleLabel), bigStyle);
+    
+    /* Begin the second row */
+    dgnLevelLabel = gtk_label_new (_ ("Nethack for Gnome")); 
+    gtk_table_attach (GTK_TABLE (statTable), dgnLevelLabel, 
+           0, 8, 1, 2, GTK_FILL, 0, 0, 0);
+    gtk_widget_set_style (GTK_WIDGET (dgnLevelLabel), bigStyle);
+    
+    /* Begin the third row */
+    horizSep0 = gtk_hseparator_new (); 
+    gtk_table_attach (GTK_TABLE (statTable), horizSep0, 
+           0, 8, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
+
+
+    /* Begin the fourth row */
+    statsHBox = gtk_hbox_new (TRUE, 0);
+
+    strVBox = gtk_vbox_new (FALSE, 0);
+    strPix =  gnome_pixmap_new_from_xpm_d( str_xpm);
+    strLabel = gtk_label_new( "STR: ");
+    gtk_box_pack_start (GTK_BOX (strVBox), strPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (strVBox), strLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statsHBox), GTK_WIDGET(strVBox), TRUE, TRUE, 2);
+
+    dexVBox = gtk_vbox_new (FALSE, 0);
+    dexPix =  gnome_pixmap_new_from_xpm_d( dex_xpm);
+    dexLabel = gtk_label_new( "DEX: ");
+    gtk_box_pack_start (GTK_BOX (dexVBox), dexPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (dexVBox), dexLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statsHBox), GTK_WIDGET(dexVBox), TRUE, TRUE, 2);
+
+    conVBox = gtk_vbox_new (FALSE, 0);
+    conPix =  gnome_pixmap_new_from_xpm_d( cns_xpm);
+    conLabel = gtk_label_new( "CON: ");
+    gtk_box_pack_start (GTK_BOX (conVBox), conPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (conVBox), conLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statsHBox), GTK_WIDGET(conVBox), TRUE, TRUE, 2);
+
+    intVBox = gtk_vbox_new (FALSE, 0);
+    intPix =  gnome_pixmap_new_from_xpm_d( int_xpm);
+    intLabel = gtk_label_new( "INT: ");
+    gtk_box_pack_start (GTK_BOX (intVBox), intPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (intVBox), intLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statsHBox), GTK_WIDGET(intVBox), TRUE, TRUE, 2);
+
+
+    wisVBox = gtk_vbox_new (FALSE, 0);
+    wisPix =  gnome_pixmap_new_from_xpm_d( wis_xpm);
+    wisLabel = gtk_label_new( "WIS: ");
+    gtk_box_pack_start (GTK_BOX (wisVBox), wisPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (wisVBox), wisLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statsHBox), GTK_WIDGET(wisVBox), TRUE, TRUE, 2);
+
+
+    chaVBox = gtk_vbox_new (FALSE, 0);
+    chaPix =  gnome_pixmap_new_from_xpm_d( cha_xpm);
+    chaLabel = gtk_label_new( "CHA: ");
+    gtk_box_pack_start (GTK_BOX (chaVBox), chaPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (chaVBox), chaLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statsHBox), GTK_WIDGET(chaVBox), TRUE, TRUE, 2);
+    
+    gtk_table_attach( GTK_TABLE( statTable),  GTK_WIDGET(statsHBox), 
+           0, 8, 3, 4, GTK_FILL, 0, 0, 0);
+
+    /* Begin the fifth row */
+    horizSep1 = gtk_hseparator_new(); 
+    gtk_table_attach( GTK_TABLE( statTable), horizSep1, 
+           0, 8, 4, 5, GTK_FILL, GTK_FILL, 0, 0);
+
+    /* Begin the sixth row */
+    hpLabel = gtk_label_new( "HP: ");
+    gtk_table_attach( GTK_TABLE( statTable), hpLabel, 
+           0, 1, 5, 6, GTK_FILL, 0, 0, 0);
+       
+    acLabel = gtk_label_new( "AC: ");
+    gtk_table_attach( GTK_TABLE( statTable), acLabel, 
+           2, 3, 5, 6, GTK_FILL, 0, 0, 0);
+    
+    powLabel = gtk_label_new( "Power: ");
+    gtk_table_attach( GTK_TABLE( statTable), powLabel, 
+           4, 5, 5, 6, GTK_FILL, 0, 0, 0);
+    
+    goldLabel = gtk_label_new( "Au: ");
+    gtk_table_attach( GTK_TABLE( statTable), goldLabel, 
+           6, 7, 5, 6, GTK_FILL, 0, 0, 0);
+    
+
+    /* Begin the seventh row */
+    horizSep2 = gtk_hseparator_new(); 
+    gtk_table_attach( GTK_TABLE( statTable), horizSep2, 
+           0, 8, 6, 7, GTK_FILL, GTK_FILL, 0, 0);
+
+    
+    /* Begin the eigth row */
+    levlLabel = gtk_label_new( "Level: ");
+    gtk_table_attach( GTK_TABLE( statTable), levlLabel, 
+           0, 1, 7, 8, GTK_FILL, 0, 0, 0);
+       
+    expLabel = gtk_label_new( "Exp: ");
+    gtk_table_attach( GTK_TABLE( statTable), expLabel, 
+           2, 3, 7, 8, GTK_FILL, 0, 0, 0);
+   
+    timeLabel = gtk_label_new( "Time: ");
+    gtk_table_attach( GTK_TABLE( statTable), timeLabel, 
+           4, 5, 7, 8, GTK_FILL, 0, 0, 0);
+    
+    scoreLabel = gtk_label_new( "Score: ");
+    gtk_table_attach( GTK_TABLE( statTable), scoreLabel, 
+           6, 7, 7, 8, GTK_FILL, 0, 0, 0);
+    
+    /* Begin the ninth row */
+    horizSep3 = gtk_hseparator_new(); 
+    gtk_table_attach( GTK_TABLE( statTable), horizSep3, 
+           0, 8, 8, 9, GTK_FILL, GTK_FILL, 0, 0);
+    
+    /* Begin the tenth and last row */
+    statHBox = gtk_hbox_new (FALSE, 0);
+
+    alignVBox = gtk_vbox_new (FALSE, 0);
+    alignPix =  gnome_pixmap_new_from_xpm_d( neutral_xpm);
+    alignLabel = gtk_label_new( "Neutral");
+    gtk_box_pack_start (GTK_BOX (alignVBox), alignPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (alignVBox), alignLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(alignVBox), TRUE, FALSE, 2);
+    
+    hungerVBox = gtk_vbox_new (FALSE, 0);
+    hungerPix =  gnome_pixmap_new_from_xpm_d( hungry_xpm);
+    hungerLabel = gtk_label_new( "Hungry");
+    gtk_box_pack_start (GTK_BOX (hungerVBox), hungerPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (hungerVBox), hungerLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(hungerVBox), TRUE, FALSE, 2);
+    
+    sickVBox = gtk_vbox_new (FALSE, 0);
+    sickPix =  gnome_pixmap_new_from_xpm_d( sick_fp_xpm);
+    sickLabel = gtk_label_new( "FoodPois");
+    gtk_box_pack_start (GTK_BOX (sickVBox), sickPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (sickVBox), sickLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(sickVBox), TRUE, FALSE, 2);
+    
+    blindVBox = gtk_vbox_new (FALSE, 0);
+    blindPix =  gnome_pixmap_new_from_xpm_d( blind_xpm);
+    blindLabel = gtk_label_new( "Blind");
+    gtk_box_pack_start (GTK_BOX (blindVBox), blindPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (blindVBox), blindLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(blindVBox), TRUE, FALSE, 2);
+    
+    stunVBox = gtk_vbox_new (FALSE, 0);
+    stunPix =  gnome_pixmap_new_from_xpm_d( stunned_xpm);
+    stunLabel = gtk_label_new( "Stun");
+    gtk_box_pack_start (GTK_BOX (stunVBox), stunPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (stunVBox), stunLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(stunVBox), TRUE, FALSE, 2);
+    
+    confuVBox = gtk_vbox_new (FALSE, 0);
+    confuPix =  gnome_pixmap_new_from_xpm_d( confused_xpm);
+    confuLabel = gtk_label_new( "Confused");
+    gtk_box_pack_start (GTK_BOX (confuVBox), confuPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (confuVBox), confuLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(confuVBox), TRUE, FALSE, 2);
+    
+    halluVBox = gtk_vbox_new (FALSE, 0);
+    halluPix =  gnome_pixmap_new_from_xpm_d( hallu_xpm);
+    halluLabel = gtk_label_new( "Hallu");
+    gtk_box_pack_start (GTK_BOX (halluVBox), halluPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (halluVBox), halluLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(halluVBox), TRUE, FALSE, 2);
+    
+    encumbVBox = gtk_vbox_new (FALSE, 0);
+    encumbPix =  gnome_pixmap_new_from_xpm_d( slt_enc_xpm);
+    encumbLabel = gtk_label_new( "Burdened");
+    gtk_box_pack_start (GTK_BOX (encumbVBox), encumbPix, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX (encumbVBox), encumbLabel, TRUE, TRUE, 2);
+    gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(encumbVBox), TRUE, FALSE, 2);
+
+    gtk_table_attach( GTK_TABLE( statTable), GTK_WIDGET(statHBox), 
+           0, 8, 9, 10, GTK_FILL, GTK_FILL, 0, 0);
+    
+    /* Set up the necessary signals */
+    gtk_signal_connect (GTK_OBJECT (statTable), 
+           "ghack_fade_highlight", 
+           GTK_SIGNAL_FUNC (ghack_fade_highlighting), 
+           NULL);
+
+    gtk_signal_connect (GTK_OBJECT (statTable), 
+           "ghack_putstr", 
+           GTK_SIGNAL_FUNC (ghack_status_window_put_string), 
+           NULL);
+
+    gtk_signal_connect (GTK_OBJECT (statTable), 
+           "ghack_clear", 
+           GTK_SIGNAL_FUNC (ghack_status_window_clear), 
+           NULL);
+
+    gtk_signal_connect (GTK_OBJECT (statTable), 
+           "ghack_curs", 
+           GTK_SIGNAL_FUNC (ghack_status_window_cursor_to), 
+           NULL);
+    gtk_signal_connect(GTK_OBJECT (statTable), 
+           "gnome_delay_output",
+           GTK_SIGNAL_FUNC(ghack_delay), 
+           NULL);
+
+    /* Lastly, show the status window and everything in it */
+    gtk_widget_show_all( statTable);
+
+    return GTK_WIDGET(statTable);
+}
+
+
+
+void ghack_status_window_update_stats()
+{
+    char buf[BUFSZ];
+    gchar *buf1;
+    const char* hung;
+    const char* enc;
+    static int firstTime=TRUE;
+#ifdef GOLDOBJ
+    long umoney;
+#endif
+
+    /* First, fill in the player name and the dungeon level */
+    strcpy(buf, plname);
+    if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a';
+    strcat(buf, " the ");
+    if (u.mtimedone) {
+        char mname[BUFSZ];
+        int k = 0;
+
+        strcpy(mname, mons[u.umonnum].mname);
+        while(mname[k] != 0) {
+            if ((k == 0 || (k > 0 && mname[k-1] == ' '))
+             && 'a' <= mname[k] && mname[k] <= 'z')
+            {
+                mname[k] += 'A' - 'a';
+            }
+            k++;
+        }
+        strcat(buf, mname);
+    } else {
+        strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female));
+    }
+    gtk_label_get( GTK_LABEL( titleLabel), &buf1);
+    if (strcmp( buf1, buf) != 0 && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( titleLabel, bigStyle, bigGreenStyle);
+    }
+    gtk_label_set( GTK_LABEL( titleLabel), buf);
+
+
+    if (In_endgame(&u.uz)) {
+        strcpy(buf, (Is_astralevel(&u.uz) ? "Astral Plane":"End Game"));
+    } else {
+        sprintf(buf, "%s, level %d", dungeons[u.uz.dnum].dname, depth(&u.uz));
+    }
+    if (lastDepth > depth(&u.uz) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( dgnLevelLabel, bigStyle, bigRedStyle);
+    }
+    else if (lastDepth < depth(&u.uz) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( dgnLevelLabel, bigStyle, bigGreenStyle);
+    }
+    lastDepth = depth(&u.uz);
+    gtk_label_set( GTK_LABEL( dgnLevelLabel), buf);
+
+    /* Next, fill in the player's stats */
+    if (ACURR(A_STR) > 118) {
+        sprintf(buf,"STR:%d",ACURR(A_STR)-100);
+    } else if (ACURR(A_STR)==118) {
+        sprintf(buf,"STR:18/**");
+    } else if(ACURR(A_STR) > 18) {
+        sprintf(buf,"STR:18/%02d",ACURR(A_STR)-18);
+    } else {
+        sprintf(buf,"STR:%d",ACURR(A_STR));
+    }
+    if (lastStr < ACURR(A_STR) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( strLabel, normalStyle, greenStyle);
+    }
+    else if (lastStr > ACURR(A_STR) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( strLabel, normalStyle, redStyle);
+    }
+    lastStr = ACURR(A_STR);
+    gtk_label_set( GTK_LABEL( strLabel), buf);
+
+    sprintf(buf,"INT:%d",ACURR(A_INT));
+    if (lastInt < ACURR(A_INT) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( intLabel, normalStyle, greenStyle);
+    }
+    else if (lastInt > ACURR(A_INT) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( intLabel, normalStyle, redStyle);
+    }
+    lastInt = ACURR(A_INT);
+    gtk_label_set( GTK_LABEL( intLabel), buf);
+    
+    sprintf(buf,"WIS:%d",ACURR(A_WIS));
+    if (lastWis < ACURR(A_WIS) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( wisLabel, normalStyle, greenStyle);
+    }
+    else if (lastWis > ACURR(A_WIS) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( wisLabel, normalStyle, redStyle);
+    }
+    lastWis = ACURR(A_WIS);
+    gtk_label_set( GTK_LABEL( wisLabel), buf);
+    
+    sprintf(buf,"DEX:%d",ACURR(A_DEX));
+    if (lastDex < ACURR(A_DEX) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( dexLabel, normalStyle, greenStyle);
+    }
+    else if (lastDex > ACURR(A_DEX) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( dexLabel, normalStyle, redStyle);
+    }
+    lastDex = ACURR(A_DEX);
+    gtk_label_set( GTK_LABEL( dexLabel), buf);
+    
+    sprintf(buf,"CON:%d",ACURR(A_CON));
+    if (lastCon < ACURR(A_CON) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( conLabel, normalStyle, greenStyle);
+    }
+    else if (lastCon > ACURR(A_CON) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( conLabel, normalStyle, redStyle);
+    }
+    lastCon = ACURR(A_CON);
+    gtk_label_set( GTK_LABEL( conLabel), buf);
+    
+    sprintf(buf,"CHA:%d",ACURR(A_CHA));
+    if (lastCha < ACURR(A_CHA) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( chaLabel, normalStyle, greenStyle);
+    }
+    else if (lastCha > ACURR(A_CHA) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( chaLabel, normalStyle, redStyle);
+    }
+    lastCha = ACURR(A_CHA);
+    gtk_label_set( GTK_LABEL( chaLabel), buf);
+    
+    /* Now do the non-pixmaped stats (gold and such) */
+#ifndef GOLDOBJ
+    sprintf(buf,"Au:%ld", u.ugold);
+    if (lastAu < u.ugold && firstTime==FALSE) {
+#else
+    umoney = money_cnt(invent);
+    sprintf(buf,"Au:%ld", umoney);
+    if (lastAu < umoney && firstTime==FALSE) {
+#endif
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( goldLabel, normalStyle, greenStyle);
+    }
+#ifndef GOLDOBJ
+    else if (lastAu > u.ugold && firstTime==FALSE) {
+#else
+    else if (lastAu > umoney && firstTime==FALSE) {
+#endif
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( goldLabel, normalStyle, redStyle);
+    }
+#ifndef GOLDOBJ
+    lastAu = u.ugold;
+#else
+    lastAu = umoney;
+#endif
+    gtk_label_set( GTK_LABEL( goldLabel), buf);
+    
+    if (u.mtimedone) {
+        /* special case: when polymorphed, show "HD", disable exp */
+       sprintf(buf,"HP:%d/%d", ( (u.mh  > 0)? u.mh  : 0), u.mhmax);
+       if ((lastHP < u.mh || lastMHP < u.mhmax ) && firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( hpLabel, normalStyle, greenStyle);
+       }
+       else if ((lastHP > u.mh || lastMHP > u.mhmax ) && firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( hpLabel, normalStyle, redStyle);
+       }
+       lastHP = u.mh;
+       lastMHP = u.mhmax;
+    } else {
+       sprintf(buf,"HP:%d/%d", ( (u.uhp  > 0)? u.uhp  : 0), u.uhpmax);
+       if ((lastHP < u.uhp || lastMHP < u.uhpmax ) && firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( hpLabel, normalStyle, greenStyle);
+       }
+       else if ((lastHP > u.uhp || lastMHP > u.uhpmax ) && firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( hpLabel, normalStyle, redStyle);
+       }
+       lastHP = u.uhp;
+       lastMHP = u.uhpmax;
+    }
+    gtk_label_set( GTK_LABEL( hpLabel), buf);
+    
+    if (u.mtimedone) {
+        /* special case: when polymorphed, show "HD", disable exp */
+       sprintf(buf,"HD:%d", mons[u.umonnum].mlevel);
+       if (lastLevel < mons[u.umonnum].mlevel && firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( levlLabel, normalStyle, greenStyle);
+       }
+       else if (lastLevel > mons[u.umonnum].mlevel && firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( levlLabel, normalStyle, redStyle);
+       }
+       lastLevel = mons[u.umonnum].mlevel;
+    } else {
+       sprintf(buf,"Level:%d", u.ulevel);
+       if (lastLevel < u.ulevel && firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( levlLabel, normalStyle, greenStyle);
+       }
+       else if (lastLevel > u.ulevel && firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( levlLabel, normalStyle, redStyle);
+       }
+       lastLevel = u.ulevel;
+    }
+    gtk_label_set( GTK_LABEL( levlLabel), buf);
+
+    sprintf(buf,"Power:%d/%d", u.uen, u.uenmax);
+    if ((lastPOW < u.uen || lastMPOW < u.uenmax) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( powLabel, normalStyle, greenStyle);
+    }
+    if ((lastPOW > u.uen || lastMPOW > u.uenmax) && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( powLabel, normalStyle, redStyle);
+    }
+    lastPOW = u.uen;
+    lastMPOW = u.uenmax;
+    gtk_label_set( GTK_LABEL( powLabel), buf);
+    
+    sprintf(buf,"AC:%d", u.uac);
+    if (lastAC > u.uac && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( acLabel, normalStyle, greenStyle);
+    }
+    else if (lastAC < u.uac && firstTime==FALSE) {
+       /* Ok, this changed so add it to the highlighing list */
+       ghack_highlight_widget( acLabel, normalStyle, redStyle);
+    }
+    lastAC = u.uac;
+    gtk_label_set( GTK_LABEL( acLabel), buf);
+    
+#ifdef EXP_ON_BOTL
+    if (flags.showexp) {
+       sprintf(buf,"Exp:%ld", u.uexp);
+       if (lastExp < u.uexp && firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( expLabel, normalStyle, greenStyle);
+       }
+       else if (lastExp > u.uexp && firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( expLabel, normalStyle, redStyle);
+       }
+       lastExp = u.uexp;
+       gtk_label_set( GTK_LABEL( expLabel), buf);
+   } else
+#endif
+    {
+       gtk_label_set( GTK_LABEL( expLabel), "");
+    }
+
+    if (flags.time) {
+       sprintf(buf,"Time:%ld", moves);
+       gtk_label_set( GTK_LABEL( timeLabel), buf);
+    }
+    else
+       gtk_label_set( GTK_LABEL( timeLabel), "");
+#ifdef SCORE_ON_BOTL
+    if (flags.showscore) {
+       sprintf(buf,"Score:%ld", botl_score());
+       gtk_label_set( GTK_LABEL( scoreLabel), buf);
+    } else
+       gtk_label_set( GTK_LABEL( scoreLabel), "");
+#else
+    {
+       gtk_label_set( GTK_LABEL( scoreLabel), "");
+    }
+#endif
+
+    /* See if their alignment has changed */
+    if (lastAlignment != u.ualign.type) {
+       if (firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( alignLabel, normalStyle, redStyle);
+       }
+
+       lastAlignment = u.ualign.type;
+       /* looks like their alignment has changed -- change out the icon */
+       if (u.ualign.type==A_CHAOTIC) {
+           gtk_label_set( GTK_LABEL( alignLabel), "Chaotic");
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(alignPix), chaotic_xpm);
+       } else if (u.ualign.type==A_NEUTRAL) {
+           gtk_label_set( GTK_LABEL( alignLabel), "Neutral");
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(alignPix), neutral_xpm);
+       } else {
+           gtk_label_set( GTK_LABEL( alignLabel), "Lawful");
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(alignPix), lawful_xpm);
+       }
+    }
+    
+    hung=hu_stat[u.uhs];
+    if (lastHungr != u.uhs) {
+       if (firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( hungerLabel, normalStyle, redStyle);
+       }
+
+       lastHungr = u.uhs;
+       if (hung[0]==' ') {
+           gtk_label_set( GTK_LABEL( hungerLabel), "      ");
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(hungerPix), nothing_xpm);
+       } else 
+         if (u.uhs == 0 /* SATIATED */) {
+           gtk_label_set( GTK_LABEL( hungerLabel), hung);
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(hungerPix), satiated_xpm);
+       } else {
+           gtk_label_set( GTK_LABEL( hungerLabel), hung);
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(hungerPix), hungry_xpm);
+       }
+    }
+
+    if (lastConf != Confusion) {
+       if (firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( confuLabel, normalStyle, redStyle);
+       }
+
+       lastConf = Confusion;
+       if (Confusion) {
+           gtk_label_set( GTK_LABEL( confuLabel), "Confused");
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(confuPix), confused_xpm);
+       }
+       else { 
+           gtk_label_set( GTK_LABEL( confuLabel), "        ");
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(confuPix), nothing_xpm);
+       }
+    }
+
+    if (lastBlind != Blind) {
+       if (firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( blindLabel, normalStyle, redStyle);
+       }
+
+       lastBlind = Blind;
+       if (Blind) {
+           gtk_label_set( GTK_LABEL( blindLabel), "Blind");
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(blindPix), blind_xpm);
+       }
+       else { 
+           gtk_label_set( GTK_LABEL( blindLabel), "     ");
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(blindPix), nothing_xpm);
+       }
+    }
+    if (lastStun != Stunned) {
+       if (firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( stunLabel, normalStyle, redStyle);
+       }
+
+       lastStun = Stunned;
+       if (Stunned) {
+           gtk_label_set( GTK_LABEL( stunLabel), "Stun");
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(stunPix), stunned_xpm);
+       }
+       else { 
+           gtk_label_set( GTK_LABEL( stunLabel), "    ");
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(stunPix), nothing_xpm);
+       }
+    }
+    
+    if (lastHalu != Hallucination) {
+       if (firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( halluLabel, normalStyle, redStyle);
+       }
+
+       lastHalu = Hallucination;
+       if (Hallucination) {
+           gtk_label_set( GTK_LABEL( halluLabel), "Hallu");
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(halluPix), hallu_xpm);
+       }
+       else { 
+           gtk_label_set( GTK_LABEL( halluLabel), "     ");
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(halluPix), nothing_xpm);
+       }
+    }
+
+    if (lastSick != Sick) {
+       if (firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( sickLabel, normalStyle, redStyle);
+       }
+
+       lastSick = Sick;
+       if (Sick) {
+           if (u.usick_type & SICK_VOMITABLE) {
+               gtk_label_set( GTK_LABEL( sickLabel), "FoodPois");
+               gnome_pixmap_load_xpm_d( GNOME_PIXMAP(sickPix), sick_fp_xpm);
+           } else if (u.usick_type & SICK_NONVOMITABLE) {
+               gtk_label_set( GTK_LABEL( sickLabel), "Ill");
+               gnome_pixmap_load_xpm_d( GNOME_PIXMAP(sickPix), sick_il_xpm);
+           } else {
+               gtk_label_set( GTK_LABEL( sickLabel), "FoodPois");
+               gnome_pixmap_load_xpm_d( GNOME_PIXMAP(sickPix), sick_fp_xpm);
+           }
+       } else {
+           gtk_label_set( GTK_LABEL( sickLabel), "        ");
+           gnome_pixmap_load_xpm_d( GNOME_PIXMAP(sickPix), nothing_xpm);
+       }
+    }
+
+    enc=enc_stat[near_capacity()];
+    if (lastEncumb != near_capacity()) {
+       if (firstTime==FALSE) {
+           /* Ok, this changed so add it to the highlighing list */
+           ghack_highlight_widget( encumbLabel, normalStyle, redStyle);
+       }
+
+       lastEncumb = near_capacity();
+       switch ( lastEncumb ) {
+           case 0:
+               gtk_label_set( GTK_LABEL( encumbLabel), "        ");
+               gnome_pixmap_load_xpm_d( GNOME_PIXMAP(encumbPix), nothing_xpm);
+               break;
+           case 1:
+               gtk_label_set( GTK_LABEL( encumbLabel), enc);
+               gnome_pixmap_load_xpm_d( GNOME_PIXMAP(encumbPix), slt_enc_xpm);
+               break;
+           case 2:
+               gtk_label_set( GTK_LABEL( encumbLabel), enc);
+               gnome_pixmap_load_xpm_d( GNOME_PIXMAP(encumbPix), mod_enc_xpm);
+               break;
+           case 3:
+               gtk_label_set( GTK_LABEL( encumbLabel), enc);
+               gnome_pixmap_load_xpm_d( GNOME_PIXMAP(encumbPix), hvy_enc_xpm);
+               break;
+           case 4:
+               gtk_label_set( GTK_LABEL( encumbLabel), enc);
+               gnome_pixmap_load_xpm_d( GNOME_PIXMAP(encumbPix), ext_enc_xpm);
+               break;
+           case 5:
+               gtk_label_set( GTK_LABEL( encumbLabel), enc);
+               gnome_pixmap_load_xpm_d( GNOME_PIXMAP(encumbPix), ovr_enc_xpm);
+       }
+    }
+    firstTime=FALSE;
+}
+
+static void ghack_fade_highlighting()
+{
+    GList *item;
+    Highlight *highlt;
+
+    /* Remove any items from the queue if their time is up */
+    for (item = g_list_first( s_HighLightList) ; item ; ) {
+       highlt = (Highlight*) item->data;
+       if (highlt) {
+           if ( highlt->nTurnsLeft <= 0) {
+               gtk_widget_set_style(  GTK_WIDGET( highlt->widget), 
+                       highlt->oldStyle);
+               s_HighLightList = g_list_remove_link(s_HighLightList, item);
+               g_free( highlt);
+               g_list_free_1( item);
+               item = g_list_first( s_HighLightList);
+               continue;
+           } else
+               (highlt->nTurnsLeft)--;
+       }
+       if (item)
+           item=item->next;
+       else
+           break;
+    }
+}
+
+/* Widget changed, so add it to the highlighing list */
+static void ghack_highlight_widget( GtkWidget* widget, GtkStyle* oldStyle, 
+       GtkStyle* newStyle)
+{
+    Highlight *highlt;
+    GList *item;
+    
+    /* Check if this widget is already in the queue.  If so then
+     * remove it, so we will only have the new entry in the queue  */
+    for (item = g_list_first( s_HighLightList) ; item ; ) {
+       highlt = (Highlight*) item->data;
+       if (highlt) {
+           if ( highlt->widget == widget) {
+               s_HighLightList = g_list_remove_link(s_HighLightList, item);
+               g_free( highlt);
+               g_list_free_1( item);
+               break;
+           }
+       }
+       if (item)
+           item=item->next;
+       else
+           break;
+    }
+
+    /* Ok, now highlight this widget and add it into the fade 
+     * highlighting queue  */
+    highlt = g_new( Highlight, 1);
+    highlt->nTurnsLeft=NUM_TURNS_HIGHLIGHTED;
+    highlt->oldStyle=oldStyle;
+    highlt->widget=widget;
+    s_HighLightList = g_list_prepend (s_HighLightList, highlt);
+    gtk_widget_set_style(  GTK_WIDGET( widget), newStyle);
+    
+} 
+    
+    
diff --git a/win/gnome/gnstatus.h b/win/gnome/gnstatus.h
new file mode 100644 (file)
index 0000000..d5008a5
--- /dev/null
@@ -0,0 +1,14 @@
+/*     SCCS Id: @(#)gnstatus.h 3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackStatusWindow_h
+#define GnomeHackStatusWindow_h
+
+#include <gnome.h>
+#include "config.h"
+#include "global.h"
+
+GtkWidget* ghack_init_status_window ();
+
+#endif /* GnomeHackStatusWindow_h */
diff --git a/win/gnome/gntext.c b/win/gnome/gntext.c
new file mode 100644 (file)
index 0000000..275a4a1
--- /dev/null
@@ -0,0 +1,158 @@
+/*     SCCS Id: @(#)gntext.c   3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "gntext.h"
+#include "gnmain.h"
+#include <gnome.h>
+
+/* include the standard RIP window (win/X11/rip.xpm) */
+#include "gn_rip.h"
+
+/* dimensions of the pixmap */
+#define RIP_IMAGE_WIDTH 400
+#define RIP_IMAGE_HEIGHT 200
+
+/* dimensions and location of area where we can draw text on the pixmap */
+#define RIP_DRAW_WIDTH 84
+#define RIP_DRAW_HEIGHT 89
+#define RIP_DRAW_X 114
+#define RIP_DRAW_Y 69
+
+
+
+/* Text Window widgets */
+GtkWidget *RIP = NULL;
+GtkWidget *RIPlabel = NULL;
+GtkWidget *TW_window = NULL;
+GnomeLess *gless;
+
+static int showRIP = 0;
+
+
+
+
+void ghack_text_window_clear(GtkWidget *widget, gpointer data)
+{
+    g_assert (gless != NULL);
+    gtk_editable_delete_text (GTK_EDITABLE (gless->text), 0, 0);
+}
+
+void ghack_text_window_destroy()
+{
+    TW_window = NULL;
+}
+
+void ghack_text_window_display(GtkWidget *widget, boolean block,
+                              gpointer data)
+{
+    if(showRIP == 1) {
+       gtk_widget_show (GTK_WIDGET ( RIP));
+       gtk_window_set_title(GTK_WINDOW( TW_window), "Rest In Peace");
+    }
+   
+    gtk_signal_connect (GTK_OBJECT (TW_window), "destroy",
+       (GtkSignalFunc) ghack_text_window_destroy, NULL);
+    if (block)
+       gnome_dialog_run(GNOME_DIALOG(TW_window));
+    else
+       gnome_dialog_run_and_close(GNOME_DIALOG(TW_window));
+    
+    if(showRIP == 1) {
+       showRIP = 0;
+       gtk_widget_hide (GTK_WIDGET ( RIP));
+       gtk_window_set_title(GTK_WINDOW(TW_window), "Text Window");
+    }
+}
+
+void ghack_text_window_put_string(GtkWidget *widget, int attr,
+                                  const char* text, gpointer data)
+{
+    if(text == NULL)
+        return;
+    
+    /* Don't bother with attributes yet */
+    gtk_text_insert (GTK_TEXT (gless->text), NULL, NULL, NULL, text, -1);
+    gtk_text_insert (GTK_TEXT (gless->text), NULL, NULL, NULL, "\n", -1);
+}
+
+
+GtkWidget* ghack_init_text_window ( )
+{
+    GtkWidget *pixmap;
+    if(TW_window)
+        return(GTK_WIDGET(TW_window));
+    
+    TW_window = gnome_dialog_new("Text Window", GNOME_STOCK_BUTTON_OK, NULL);
+    gtk_window_set_default_size( GTK_WINDOW(TW_window), 500, 400);
+    gtk_window_set_policy(GTK_WINDOW(TW_window), TRUE, TRUE, FALSE);
+    gtk_window_set_title(GTK_WINDOW(TW_window), "Text Window");
+    
+    /* create GNOME pixmap object */
+    pixmap = gnome_pixmap_new_from_xpm_d (rip_xpm);
+    g_assert (pixmap != NULL);
+    gtk_widget_show (GTK_WIDGET (pixmap));
+
+    /* create label with our "death message", sized to fit into the
+    * tombstone */
+    RIPlabel = gtk_label_new ("RIP");
+    g_assert (RIPlabel != NULL);
+    /* gtk_label_set_justify is broken? */
+    gtk_label_set_justify (GTK_LABEL (RIPlabel), GTK_JUSTIFY_CENTER); 
+    gtk_label_set_line_wrap (GTK_LABEL (RIPlabel), TRUE);
+    gtk_widget_set_usize (RIPlabel, RIP_DRAW_WIDTH, RIP_DRAW_HEIGHT);
+    gtk_widget_show (RIPlabel);
+
+    /* create a fixed sized widget for the RIP pixmap */
+    RIP = gtk_fixed_new ();
+    g_assert (RIP != NULL);
+    gtk_widget_set_usize (RIP, RIP_IMAGE_WIDTH, RIP_IMAGE_HEIGHT);
+    gtk_fixed_put (GTK_FIXED (RIP), pixmap, 0, 0);
+    gtk_fixed_put (GTK_FIXED (RIP), RIPlabel, RIP_DRAW_X, RIP_DRAW_Y);
+    gtk_widget_show (RIP);
+    gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(TW_window)->vbox), RIP,
+                       TRUE, TRUE, 0);
+    
+    /* create a gnome Less widget for the text stuff */
+    gless = GNOME_LESS (gnome_less_new ());
+    g_assert (gless != NULL);
+    gtk_widget_show (GTK_WIDGET (gless));
+    gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(TW_window)->vbox), 
+           GTK_WIDGET (gless), TRUE, TRUE, 0);
+    
+    /* Hook up some signals */
+    gtk_signal_connect(GTK_OBJECT(TW_window), "ghack_putstr",
+                   GTK_SIGNAL_FUNC(ghack_text_window_put_string),
+                   NULL);
+
+    gtk_signal_connect(GTK_OBJECT(TW_window), "ghack_clear",
+                   GTK_SIGNAL_FUNC(ghack_text_window_clear),
+                   NULL);
+
+    gtk_signal_connect(GTK_OBJECT(TW_window), "ghack_display",
+                       GTK_SIGNAL_FUNC(ghack_text_window_display),
+                       NULL);
+
+    /* Center the dialog over over parent */
+    gnome_dialog_set_parent( GNOME_DIALOG (TW_window), 
+           GTK_WINDOW(ghack_get_main_window()) );
+
+    gtk_window_set_modal( GTK_WINDOW(TW_window), TRUE);
+    gtk_widget_show_all(TW_window);
+    gtk_widget_hide (GTK_WIDGET ( RIP));
+    gnome_dialog_close_hides (GNOME_DIALOG (TW_window), TRUE);
+
+    return GTK_WIDGET(TW_window);
+
+}
+
+
+void ghack_text_window_rip_string( const char* string)
+{
+    /* This is called to specify that the next message window will
+     * be a RIP window, which will include this text */
+
+    showRIP = 1;
+    gtk_label_set( GTK_LABEL( RIPlabel), string);
+}
+
diff --git a/win/gnome/gntext.h b/win/gnome/gntext.h
new file mode 100644 (file)
index 0000000..c957dc2
--- /dev/null
@@ -0,0 +1,22 @@
+/*     SCCS Id: @(#)gntext.h   3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackTextWindow_h
+#define GnomeHackTextWindow_h
+
+#include <gnome.h>
+#include "config.h"
+#include "global.h"
+
+GtkWidget* ghack_init_text_window ( );
+void ghack_text_window_clear(GtkWidget *widget, gpointer data);
+void ghack_text_window_destroy();
+void ghack_text_window_display(GtkWidget *widget, boolean block,
+                              gpointer data);
+void ghack_text_window_put_string(GtkWidget *widget, int attr,
+                                  const char* text, gpointer data);
+void ghack_text_window_rip_string( const char* ripString);
+
+
+#endif /* GnomeHackTextWindow_h */
diff --git a/win/gnome/gnworn.c b/win/gnome/gnworn.c
new file mode 100644 (file)
index 0000000..8e45486
--- /dev/null
@@ -0,0 +1,105 @@
+/*     SCCS Id: @(#)gnbind.c   3.4     2002/04/15      */
+/* Copyright (C) 2002, Dylan Alex Simon                        */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "gnworn.h"
+#include "gnglyph.h"
+#include "gnsignal.h"
+#include "gnomeprv.h"
+
+#define WORN_WIDTH     3
+#define WORN_HEIGHT    6
+
+#ifdef TOURIST
+#define WORN_OBJECT_LIST /* struct obj *[WORN_HEIGHT][WORN_WIDTH] = */ { \
+    { uquiver, uarmh,      u.twoweap ? NULL : uswapwep }, \
+    { u.twoweap ? uswapwep : NULL,  ublindf,   uwep        }, \
+    { uleft,   uamul,      uright      }, \
+    { uarms,   uarmc,      uarmg       }, \
+    { uarmu,   uarm,       uskin       }, \
+    { uball,   uarmf,      uchain      } \
+}
+#else
+#define WORN_OBJECT_LIST /* struct obj *[WORN_HEIGHT][WORN_WIDTH] = */ { \
+    { uquiver, uarmh,      u.twoweap ? NULL : uswapwep }, \
+    { u.twoweap ? uswapwep : NULL,     ublindf,    uwep    }, \
+    { uleft,   uamul,      uright      }, \
+    { uarms,   uarmc,      uarmg       }, \
+    { NULL,    uarm,       uskin       }, \
+    { uball,   uarmf,      uchain      } \
+}
+#endif
+
+static GtkWidget *worn_contents[WORN_HEIGHT][WORN_WIDTH];
+static struct obj *last_worn_objects[WORN_HEIGHT][WORN_WIDTH];
+
+GdkImlibImage *image_of_worn_object(struct obj *o);
+void ghack_worn_display(GtkWidget *win, boolean block, gpointer data);
+
+GtkWidget*
+ghack_init_worn_window()
+{
+    GtkWidget *top;
+    GtkWidget *table;
+    GtkWidget *tablealign;
+    GtkWidget *label;
+    int i,j;
+
+    top = gtk_vbox_new(FALSE, 2);
+
+    table = gtk_table_new(WORN_HEIGHT, WORN_WIDTH, TRUE);
+    for (i = 0; i < WORN_HEIGHT; i++) {
+       for (j = 0; j < WORN_WIDTH; j++) {
+           worn_contents[i][j] =
+               gnome_pixmap_new_from_imlib(image_of_worn_object(NULL));
+           last_worn_objects[i][j] = NULL; /* a pointer that will never be */
+           gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(worn_contents[i][j]),
+                            j, j+1, i, i+1, 0, 0, 0, 0);
+       }
+    }
+    tablealign = gtk_alignment_new(0.5, 0.0, 0.0, 1.0);
+    gtk_box_pack_start(GTK_BOX(top), tablealign, FALSE, FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(tablealign), table);
+
+    label = gtk_label_new("Equipment");
+    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
+    gtk_box_pack_start(GTK_BOX(top), label, FALSE, FALSE, 0);
+
+    gtk_signal_connect(GTK_OBJECT(top), "ghack_display",
+                      GTK_SIGNAL_FUNC(ghack_worn_display), NULL);
+
+    return top;
+}
+
+GdkImlibImage*
+image_of_worn_object(struct obj *o)
+{
+    int glyph;
+    GdkImlibImage *im;
+
+    if (o)
+       glyph = obj_to_glyph(o);
+    else
+       glyph = cmap_to_glyph(S_stone);
+
+    im = ghack_image_from_glyph(glyph, FALSE);
+
+    return im;
+}
+
+void
+ghack_worn_display(GtkWidget *win, boolean block, gpointer data)
+{
+    int i, j;
+    struct obj *worn_objects[WORN_HEIGHT][WORN_WIDTH] = WORN_OBJECT_LIST;
+
+    for (i = 0; i < WORN_HEIGHT; i++) {
+       for (j = 0; j < WORN_WIDTH; j++) {
+           if (worn_objects[i][j] != last_worn_objects[i][j]) {
+               last_worn_objects[i][j] = worn_objects[i][j];
+               gnome_pixmap_load_imlib(GNOME_PIXMAP(worn_contents[i][j]),
+                               image_of_worn_object(worn_objects[i][j]));
+           }
+       }
+    }
+}
diff --git a/win/gnome/gnworn.h b/win/gnome/gnworn.h
new file mode 100644 (file)
index 0000000..ef384b0
--- /dev/null
@@ -0,0 +1,14 @@
+/*     SCCS Id: @(#)gnbind.c   3.4     2002/04/15      */
+/* Copyright (C) 2002 by Dylan Alex Simon              */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackWornWindow_h
+#define GnomeHackWornWindow_h
+
+#include <gnome.h>
+#include "config.h"
+#include "global.h"
+
+GtkWidget* ghack_init_worn_window();
+
+#endif /* GnomeHackWornWindow_h */
diff --git a/win/gnome/gnyesno.c b/win/gnome/gnyesno.c
new file mode 100644 (file)
index 0000000..ecf3bad
--- /dev/null
@@ -0,0 +1,76 @@
+/*     SCCS Id: @(#)gnyesno.c  3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "gnbind.h"
+#include "gnyesno.h"
+
+
+
+int ghack_yes_no_dialog( const char *question, 
+                     const char *choices, int def)
+{
+    int i=0, ret;
+    gchar button_name[BUFSZ];
+    GtkWidget *box;
+    GtkWidget* mainWnd=NULL;
+
+    box = gnome_message_box_new ( question, GNOME_MESSAGE_BOX_QUESTION, NULL);
+    /* add buttons for each choice */
+    if (!strcmp(GNOME_STOCK_BUTTON_OK, choices)) {
+       gnome_dialog_append_button ( GNOME_DIALOG(box), GNOME_STOCK_BUTTON_OK);
+       gnome_dialog_set_default( GNOME_DIALOG(box), 0);
+       gnome_dialog_set_accelerator( GNOME_DIALOG(box), 0, 'o', 0);
+#if 0
+       g_print("Setting accelerator '%c' for button %d\n", 'o', 0);
+#endif
+    }
+    else {
+       for( ; choices[i]!='\0'; i++) {
+           if (choices[i]=='y') {
+               sprintf( button_name, GNOME_STOCK_BUTTON_YES);
+           }
+           else if (choices[i]=='n') {
+               sprintf( button_name, GNOME_STOCK_BUTTON_NO);
+           }
+           else if (choices[i] == 'q') {
+               sprintf( button_name, "Quit");
+           } else {
+               sprintf( button_name, "%c", choices[i]);
+           }
+           if (def==choices[i])
+               gnome_dialog_set_default( GNOME_DIALOG(box), i);
+           gnome_dialog_append_button ( GNOME_DIALOG(box), button_name);
+           gnome_dialog_set_accelerator( GNOME_DIALOG(box), i, choices[i], 0);
+#if 0
+           g_print("Setting accelerator '%c' for button %d\n", choices[i], i);
+#endif
+       }
+    }
+#if 0
+    /* Perhaps add in a quit game button, like this... */
+    gnome_dialog_append_button ( GNOME_DIALOG(box), GNOME_STOCK_BUTTON_CLOSE);
+    gnome_dialog_set_accelerator( GNOME_DIALOG(box), i, choices[i], 0);
+    g_print("Setting accelerator '%c' for button %d\n", 'Q', i);
+#endif
+
+    gnome_dialog_set_close(GNOME_DIALOG (box), TRUE);
+    mainWnd = ghack_get_main_window ();
+    gtk_window_set_modal( GTK_WINDOW(box), TRUE);
+    gtk_window_set_title( GTK_WINDOW(box), "GnomeHack");
+    if ( mainWnd != NULL ) {
+       gnome_dialog_set_parent (GNOME_DIALOG (box), 
+               GTK_WINDOW ( mainWnd) );
+    }
+
+    ret=gnome_dialog_run_and_close ( GNOME_DIALOG (box));
+    
+#if 0
+    g_print("You selected button %d\n", ret);
+#endif
+    
+    if (ret==-1)
+       return( '\033');
+    else
+       return( choices[ret]);
+}
diff --git a/win/gnome/gnyesno.h b/win/gnome/gnyesno.h
new file mode 100644 (file)
index 0000000..dd0728f
--- /dev/null
@@ -0,0 +1,12 @@
+/*     SCCS Id: @(#)gnyesno.h  3.4     2000/07/16      */
+/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef GnomeHackYesNoDialog_h
+#define GnomeHackYesNoDialog_h
+
+int ghack_yes_no_dialog( const char* szQuestionStr, 
+       const char* szChoicesStr, int nDefault);
+
+
+#endif
diff --git a/win/gnome/mapbg.xpm b/win/gnome/mapbg.xpm
new file mode 100644 (file)
index 0000000..09759b4
--- /dev/null
@@ -0,0 +1,353 @@
+/* XPM */
+static char * mapbg_xpm[] = {
+"96 96 254 2",
+"      c None",
+".     c #BC6C33",
+"+     c #AC6324",
+"@     c #B46B2B",
+"#     c #B47734",
+"$     c #AC6B2C",
+"%     c #B46C3D",
+"&     c #BC7945",
+"*     c #A4774B",
+"=     c #B48643",
+"-     c #AC7F40",
+";     c #AC773A",
+">     c #C49054",
+",     c #C48044",
+"'     c #B4642C",
+")     c #B45E21",
+"!     c #BC642B",
+"~     c #BD723E",
+"{     c #C4884E",
+"]     c #C48F4B",
+"^     c #C49753",
+"/     c #CC9052",
+"(     c #CC7234",
+"_     c #B4804F",
+":     c #C4985D",
+"<     c #946232",
+"[     c #AC6431",
+"}     c #C46637",
+"|     c #945222",
+"1     c #8C5435",
+"2     c #844C29",
+"3     c #945836",
+"4     c #AC653D",
+"5     c #A45E2B",
+"6     c #AC5E2A",
+"7     c #A44D21",
+"8     c #A45823",
+"9     c #A4592C",
+"0     c #B46C34",
+"a     c #B46536",
+"b     c #AC7240",
+"c     c #AC7231",
+"d     c #944C1B",
+"e     c #8C5223",
+"f     c #945722",
+"g     c #AC6B34",
+"h     c #944C24",
+"i     c #9C5222",
+"j     c #B47234",
+"k     c #C4783B",
+"l     c #BC7833",
+"m     c #BC7F3B",
+"n     c #BC8044",
+"o     c #BC783C",
+"p     c #A46332",
+"q     c #9C6331",
+"r     c #B4773C",
+"s     c #B4723D",
+"t     c #A46B33",
+"u     c #B48043",
+"v     c #CC814C",
+"w     c #B46422",
+"x     c #C47946",
+"y     c #C48743",
+"z     c #BC6D3D",
+"A     c #BC6536",
+"B     c #94522E",
+"C     c #A4643E",
+"D     c #B45E2F",
+"E     c #A45223",
+"F     c #9C4C1B",
+"G     c #B47845",
+"H     c #C4804D",
+"I     c #9C5723",
+"J     c #AC5E35",
+"K     c #A45935",
+"L     c #9B5E29",
+"M     c #BE7234",
+"N     c #BC8744",
+"O     c #AC5924",
+"P     c #A45E35",
+"Q     c #9C582C",
+"R     c #AC501F",
+"S     c #9C5935",
+"T     c #8C4D28",
+"U     c #643D21",
+"V     c #845437",
+"W     c #B47E31",
+"X     c #844126",
+"Y     c #B45823",
+"Z     c #954627",
+"`     c #9C4C24",
+" .    c #7C4124",
+"..    c #B4592D",
+"+.    c #9C5E37",
+"@.    c #945644",
+"#.    c #AC6C3E",
+"$.    c #8C4627",
+"%.    c #9C643E",
+"&.    c #744021",
+"*.    c #A4723C",
+"=.    c #844628",
+"-.    c #743819",
+";.    c #844019",
+">.    c #944D2D",
+",.    c #A4512C",
+"'.    c #B45227",
+").    c #C4622A",
+"!.    c #9C522E",
+"~.    c #7C3A1A",
+"{.    c #BC5E24",
+"].    c #CC8243",
+"^.    c #9C664C",
+"/.    c #AC5934",
+"(.    c #9C4E2E",
+"_.    c #7C4B29",
+":.    c #8C532C",
+"<.    c #A46423",
+"[.    c #7C422C",
+"}.    c #743214",
+"|.    c #AC592C",
+"1.    c #8C4224",
+"2.    c #C47F3C",
+"3.    c #8C421C",
+"4.    c #8C410F",
+"5.    c #8C5D3E",
+"6.    c #8C5B32",
+"7.    c #88461A",
+"8.    c #663626",
+"9.    c #AC6B4C",
+"0.    c #94411A",
+"a.    c #845C30",
+"b.    c #744B20",
+"c.    c #7C4D34",
+"d.    c #CC874A",
+"e.    c #D49053",
+"f.    c #C46C32",
+"g.    c #BC814D",
+"h.    c #CC7842",
+"i.    c #A45A44",
+"j.    c #8C4B1A",
+"k.    c #843204",
+"l.    c #945E37",
+"m.    c #7C564C",
+"n.    c #74422C",
+"o.    c #95461B",
+"p.    c #AC7747",
+"q.    c #745634",
+"r.    c #94572C",
+"s.    c #7C4621",
+"t.    c #CC7A54",
+"u.    c #B47654",
+"v.    c #BC5E2C",
+"w.    c #B49056",
+"x.    c #C4915C",
+"y.    c #B4874E",
+"z.    c #BC884D",
+"A.    c #A46C45",
+"B.    c #D48749",
+"C.    c #BC5A30",
+"D.    c #CCA06C",
+"E.    c #BCA26C",
+"F.    c #BC8F54",
+"G.    c #BC895C",
+"H.    c #BC8F4C",
+"I.    c #BC995E",
+"J.    c #C46D3D",
+"K.    c #D4985A",
+"L.    c #C4562C",
+"M.    c #843A16",
+"N.    c #C49F63",
+"O.    c #BC9652",
+"P.    c #B48F4C",
+"Q.    c #CC915C",
+"R.    c #BC5824",
+"S.    c #B49A60",
+"T.    c #CC9F60",
+"U.    c #DC995F",
+"V.    c #AC8A54",
+"W.    c #B4875F",
+"X.    c #C4885C",
+"Y.    c #BC905E",
+"Z.    c #CC975B",
+"`.    c #D4A167",
+" +    c #7C5334",
+".+    c #9C6B39",
+"++    c #845323",
+"@+    c #B46D4C",
+"#+    c #A46B3C",
+"$+    c #CC9864",
+"%+    c #8C4E34",
+"&+    c #743A24",
+"*+    c #6C3D2E",
+"=+    c #C45E30",
+"-+    c #AC7E52",
+";+    c #9C6C47",
+">+    c #6C3C1B",
+",+    c #CC8954",
+"'+    c #542810",
+")+    c #7C5E3C",
+"!+    c #84532C",
+"~+    c #946C45",
+"{+    c #946340",
+"]+    c #BCA870",
+"^+    c #B49E5C",
+"/+    c #C47E5C",
+"(+    c #AC8E44",
+"_+    c #8C633A",
+":+    c #C4A86C",
+"<+    c #CCA76E",
+"[+    c #CCA961",
+"}+    c #7A462D",
+"|+    c #8C6644",
+"1+    c #744623",
+"2+    c #A47248",
+"3+    c #94624C",
+"4+    c #845E3C",
+"5+    c #7C5329",
+"6+    c #9C7249",
+"7+    c #844D34",
+"8+    c #6C4C30",
+"9+    c #A46E54",
+"0+    c #A4624C",
+"a+    c #6C3E24",
+"b+    c #5C3224",
+"c+    c #D4A66C",
+"d+    c #744B30",
+"e+    c #BC926C",
+"f+    c #AC7954",
+"g+    c #AC522C",
+"h+    c #6C4526",
+"i+    c #A47A54",
+"j+    c #BC6644",
+"k+    c #BC6E4C",
+"l+    c #A48650",
+"m+    c #AC825C",
+"n+    c #CC6A34",
+"o+    c #9C7E5C",
+"p+    c #7C623C",
+"q+    c #5C3A2C",
+"r+    c #644A34",
+"s+    c #4C3624",
+"t+    c #844B1B",
+"u+    c #7C4018",
+"v+    c #D49A68",
+"w+    c #7C4B1C",
+"x+    c #742E04",
+"y+    c #CC8157",
+"z+    c #745A44",
+"A+    c #B46644",
+"B+    c #643614",
+"C+    c #C4A65C",
+"D+    c #843A04",
+"E+    c #6C2E14",
+". + @ # @ $ % & * = - ; > , ' . ) ! ~ { ] ^ ] / ( ' , _ : < [ } [ | 1 2 3 4 5 ! 6 7 8 ' 8 9 0 a b c d | [ 0 % e 8 f 5 ~ g h i % & % 5 a ' 8 ' a < j k l m { n o . ! 6 . 0 % p p q g r s 0 @ 0 . ",
+"j + $ # @ t g s u > u c { v @ ! w ' ~ x y y m u . ) z r > f 5 A [ B 3 2 B C 6 @ D E E 8 F i 6 0 g G 0 o H , j d I I [ & % i f [ . @ . 6 J K 2 3 L $ . M o N # j D ' O % [ 0 p P L g & l 0 0 . % ",
+"4 Q 5 % j $ @ g u / G t M k ' R 9 9 J A . M p 3 . O ! M { L 3 4 [ Q S T B Q 6 ' 6 6 J a a 9 9 a c & 0 ~ ~ z 0 L 5 8 5 [ [ d 8 & M . x i B 3 U V 3 4 . l & N m W 6 6 8 % [ g 8 5 q % & o j [ [ 0 ",
+"3 X h [ 0 0 0 0 ~ n j p 0 z Y 7 T Z ` Y ! ' Q  .a ..! . , t +.@.#.[ C S S 9 [ . D a J a z J 8 % , o + 8 8 [ @ ' J 9 Q 6 5 5 [ x P [ 4 $.1 %.&.V S p ~ o b *.; c 9 6 5 % [ [ 5 p p b & o 0 $ [ 6 ",
+"=.-.;.9 a . j j . 0 [ @ z . Y O >.h ,.'.).! !.~.P D {.! ].& ^.T & & s % 4 [ A . 4 /.` Z (.d Q , H #.8 E 8 [ [ [ a 9 /.% z 0 . ~ _.1 :.T S C S | < <.M 0 | 2 T >.Q Q | [ 5 [ p 0 0 % # s j % 5 !.",
+"[.}.~.!.' 0 @ @ . 6 O 0 ~ a D Y P K |.... . K 1.8 D {.! 2.y b Q o x % % a 6 . A ,.` 3.1.1.4.i ~ & 5 i d 8 J 9 [ A J |.D a D a a 5.3  .;.h 8 a I 6.f $ g 7.}.1.$.T T T +.Q 0 g 0 % % 0 0 0 % 5 h ",
+"_.8.;.E 6 ' ' @ ' O 8 ' @ . a ..+ D 9 9 0 o ~ p 6 ' ! . , n 0 . 0 o [ A a |.a 6 ` 3.Z (.>.$.I 0 #.e h d !.J I C a D E F F 7 |.D 9.>.>.Z 0.9 a 8 a.b.Q [ =.;.!.K 2 T 7.S 5 #.[ 0 g [ g g % g J Q ",
+"c.-.;.8 D ) @ w . ' w [ a ~ ~ Y O O 9 S c d.e.d.f.A . H g.# @ h.$ ~ [ % z |.. 6 /.Z ` i.Z d [ o %.j.S P 4 % Q p E 8 O 7 F Z E /.O k.a a 9 & #.l.m.n.B C j.T 5 ) :.:.2 q p % [ [ [ [ [ [ [ 4 p Q ",
+"o.F i I 9 [ 0 0 ' 6 8 6 # n o 0 @ ) L W d.].0 [ + @ M k m ; $ @ $ 0 j 0 0 0 0 a c g G p.q f p s ' 0 d !.Q h & M Y '.7 E 7 7 7 R [ @ ) |.[ 4 3 b.q.b.2 L % g P r.j.I 6 a a 6 + [ [ p [ [ g & & I ",
+"I d d E 0 ~ 0 6 ' O E 8 j n m . ( j # N 2.@ O !.@ @ ! M r # # M # m n , & r % s m r & o p I [ [ $ @ 7.Q P Q o j f.. O 8 F 7 O ..6 ' ' ..a a q 2 _.s.;.j.F o.o.j.I 5 p O 8 O @ M [ 0 0 g 0 o ~ L ",
+"[ 9 F 9 z t.. O ' ) O w r n , ~ A % u.n o w |.|.a ' D ' o o n ~ j l , N n r G _ u 0 #.a |.[ 0 # n r | 9 P 8 0 [ l o o % g [ D 6 7 O ..Y a A 4 p C #.s ' O 6 D a g % 0 a [ 6 [ 0 @ , k o o n o c ",
+"[ [ [ ' a . a |.8 O Y 0 o ~ . v./.r.S #.z . D D 5 6 ..! s & o ~ # o m r u _ w.x.y.p.[ J 6 % y z.] n p g a 6 @ [ # m y { m ~ @ @ 9 |.D ' A ~ % [ A.G x ~ ' ! 0 z 0 0 0 % . 0 [ [ [ o o $ M # 0 o ",
+"g s ~ 0 0 a ' ' O ' ~ B.{ o ' C./.$.;.B ' A R ` Z ,...A . o & ~ y m N N ] : : D.E.F.G.g.G _ H.I.y N s % 0 a z M r u m & o o m m & & ~ ~ l j 0 <.t s G j $ 0 # j % [ 8 [ 0 % . ~ @ o o 0 r j # y ",
+"o o l s o & , x 0 J.B.e.K., . L.a >.M.d 6 ! E 3.M.o...! . & n r 2.y n { > : : F.I.I.N.: y.F.O.P.n o a ' D 6 ' 0 $ c % o & o o m & G # j # r c [ q p L I I L <.p . ' [ 0 o % 0 % o k o o o o o , ",
+"k n o o & { / Q., l ~ , { m ! R.D !.h 6 . . ) P 7.i ..w M m { n m n N z.z.z.y.= y.z.I.S.w.I.x.g.o ' 6 Y R O 8 [ [ a [ a z o r # s j j j @ 0 . 0 ~ . 0 0 0 0 0 o ! . o H o [ [ a g 6 [ s 0 g g g ",
+"@ o o r c u > T.U.H # n ] n J.).D 6 0 k ( M ~ & +.[ D w l y / g.{ { { { N z.] > y z.w.w.V.W.X.& ~ 6 Y R Y ! ' 0 ~ a E 7 9 0 m n o k k k . ' D } D D A z z ' [ A 6 ' 0 0 p L [ x a I [ & & & s g ",
+"I E D ! 0 s z.F.T.H.o o h.d., c j m / Y.Z.`.n t ' ' $ , y y N m m y y ] { z.n N n { ; > H.r / z.~ p E O D 6 ' . @ 5 i d F 5 g r [ j o 0 g % 0 [ ' 6 5 p I 4.4.o.o.d e U  +c.6..+[ i j d.# m { p ",
+"0 5 i O a g.Q.F.T.^ N o & ].n @ # m { b p.Q.N c ! a M , / { m m W m N z.z.n N y n { ; z.] u ] r 0 + 8 ..a D w @ @ ' 8 d T r.g r @ 0 g [ <.[ [ p 5 5 [ p Q Q 5 z 6 p :.b.V _.l.p s 5 0 m @ # { G ",
+"H ~ [ a & H g._ > Z.: ] z.] , o . o ~ f Q H H j . . x y d., 2.o y N z.z.z.N n & { { ; z.> u { s 0 a D 6 v.a ' w Y O >. .&.2 q $ g 0 [ 5 5 [ [ [ 0 [ | 7.>.Q 9 h !.P ++2 5.=.4 @ C | Q P Q 5 0 k ",
+"H , s % @+#.#+#+#.z.$+N.: Z.H k 0 a a E 9 & x ~ z k x , , l M k y ] > ^ > G.n m { N u ] ^ { y s k . a |.6 ! ' + {.|.%+&+*+V p l [ $ @ [ $ 0 0 p % S 7.$.B C Q T ;.3 T 2 @.%+a @ +.T $.>.K 9 [ k ",
+"n & q B +.+.S p :.#+y.Y.w.H.{ , J.a a /.a z a o x k , o ~ . . f.# n ] : Z.: > { o n u > ^ { n o ~ J.a 9 6 0 . @ =+O T 8.8.1 [ 0 $ 0 s j % % g 0 +.Q S !.B h h f ~.4 t %.3 3 4 6 r.T X $.i.J a k ",
+"~ % B e ^.%.e T 3 q * -+_ u H / x a a a A 0 [ & , { , n l M f.. . o z.> : : ] H o n N F.z.n o J.~ a [ [ 0 % M M w |.Z }.-.T L O j ~ o 0 $ [ [ % p 5 9 K i j.j.| 4.% G p 1 S B r.| T X Z K a [ . ",
+"' % +.l.* ;+2 2 ;+%.q s b b u x.x % 0 . 0 M j n N z.y n o o f.! ).. & z.F.> z.n n n z.H.z.n 0 . a [ [ b & r g j @ 0 [ >.` K a ' 0 r o % [ 5 5 g $ p 8 9 a ~ o # D @ o #+T @.>+1 K 5 5 [ % ~ z J ",
+"E a +.1 ;+;+6.A.* %.+.@+% p #+= #.g 0 0 M , r y u N N n o k . {.R.v.0 u G.F.{ z.,+y > H.H.G ' ' @ [ g n z.# $ <.<.0 a |.E a A 0 <.0 x o g L 8 [ <.% 0 8 8 @ k m B.M o g V 1 '+)+h Q @ j M 0 J o.",
+"_..+^.!+6.l.l.l.~+;+6.V {+:.:.A.r.e q G F.N.]+]+^+I.^ K.d.' 6 z @ M % a /+{ y.H.(+T.^ u ,+2.a ' [ <.t y.x.y.b t L $ @ ' [ 0 # g j j r % [ I p g [ 0 O Y ) w 2.y l j $ @ 5 I P i I <.0 0 0 0 5 e ",
+":.%.< :.1 {+l.3 ~+;+_+6.l.!+s.5.3 T q g.> > :+<+:+: H.y ].. ) A + ' 6 9 [ G z.> P.[+^ N { d.0 . . @ s g.z.n 0 @ j o o 0 @ M r # $ j o #.[ <.g #.j . 6 . . 0 , y j l k , g 8 p 5 [ g a z % a 5 i ",
+"A.%.%.+.l.C #+%.{+~+{+{+5.}+n.}+3 6.#.H { z.> T.<+Z.n o , ~ ! a w ' D 9 !.[ n ] O.<+N.= ] y o l M . o o & s 0 . n n o 0 $ j r # $ j s 0 #.s s # g [ 9 0 z 5 g #+2.o , ,+d.H & 0 s % a a a [ J 5 ",
+"b S %.C +.^.9.A.5.{+~+^.|+1+*+n.c.1 #.H x o H ,+> { n s x k . . . ! A A O a v y I.[+N.N H.y m 2.h.l l & o r ~ o & m r g g s o G j g b G G r r & r #.[ % 4 | S q o 5 <.~ , d.o $ z a 6 a a /.4 a ",
+"#.3 +.%.r.+.2+b 5.5.3+;+5.c.n.n.8.T #.~ 0 z x & % & & o x M . z ! D A A D o d.d.: T.: H.z.] y ] 2.m n n z.N N n m G r # r r m r n g c g.{ G j o H r [ #.9 7.e q [ | [ $ g o o o % a [ J [ [ a a ",
+"C p %.C {+l.;+;+{+4+3+;+l.%+2  .2 Q @+z J 6 K Q [ M & & , s 0 l ~ ' a ' ' o , n F.F.> H.m N N m N N u y.z.H.z.N n n n n z.n G o , s r G.F.r # & o & [ g L j.Q p o 5 0 [ 0 , o x M . s g % % % a ",
+"C A.#+A.A.;+5.1 ~+5.{+;+^.S +.Q #.g ~ x 6 h $.=.. [ [ r g.o # , , H o 0 j o m N = N { N u u m r N N N n _ u = = & u u _ N _ n r & & n z.z.n o # x x j o o $ o r ].L + [ 0 d.g g 0 n , n u n % p ",
+"q p.2+A.* ;+5+1+6+a.< A.#+#+~ g v ' . h.a $. .7+. + I #.{ { m / H e.{ k d.y N ] N N ] / n n y m N { { { G G u _ r b r u = u G r ~ g.{ u y.z.n @ 0 0 0 o 2.y ].m , + , o s , 0 & @ , { N , y o 5 ",
+"k @ j j . H & 6.a.6+a.6+;+s ~ [ 2.j C C !.j.b.8+[ K j.l r H.N.P.= z.K.N Z.; N > r z.H.N ] r t o u u n n u u u V.<.G I p ;.g g u = V.H.u { # o g $ g G z.z.m m , N = = ] # y m # W <.o ~ ; t r t ",
+". + $ [ ' ~ & .+l.;+l.2+9+#.~ a n q 1 2 T &.1+q.C [ % { y T.^ I.> z./ o e.r n z.# u N N { u # l u u m r r r p.u s % [ J I 5 r { z.u > u { r r 0 j ~ b g t #.o d.H.y N K.y { o r n g k o g.N { j ",
+"D 9 + + O ' % b S 0+@.9+C C 4 z A.}+a+b+V &._.7+e p { { { c+F.<+Z.N n $ y 0 ~ % j $ r y n # ~ 0 u m n G r s G n & $ % 5 4 j.t n F.G.] g.{ r n 0 d.n p $.X I # 2.y n u y g 0 0 , 2.' . % & { e.. ",
+"..|.6 a D D a j S @.2 3+1 5.S #.S [.d+U l.T +.B e b X.g.> D.F.N.x.z.r 6 M D ' |.0 [ o , r j ~ $ r n g.& & r r & s p % P % j.<.p.> z.z._ / n n o y & S ~.~.Q j m / H H v 5 I |.x M ' A /.5 s x a ",
+"C./.9 9 D v.' . %.7+a+c.d+c.2 q !.1 3+2 #+9 % S u.Z.G.y.e+x.z.f+> { & [ . ....... 0 , v % . ~ ' [ b & n & s ~ s t #.& G & b _ g.z._ z.g./ g.{ H m g Q X >.s { y 5 L p , [ a [ x . ! A |.4.Q z {.",
+"..g+d 0.7 ..' z %.c.U }+h+5+s.l.$.%+3 h ' ' z g G.$+-+_ Y.* f+r._ H & w D O ..D A z ~ o j % 0 a I [ s G r s b s G x.H X.G X.G.z.G.= G.z.x.z.> > z.u #.C b H > N <.| d % % h.~ ~ . } v./.~.d D v.",
+"..|.d ;.F ..D . C T _.c.[.B $.P }+ .%+K z ' s _ z.i+-+i+_ 2+;+e t r z [ 6 |.|.A 6 a D [ 0 ~ 0 [ E [ s g.G G r u > : z._ p.G.F.P.Y.F.F.F.: y.> Z.Z.> g.n g.> ] > U.,+o , [ ~ a ! f.{...J 3.| D ! ",
+"v.J.p h /.A A J.i.B B @.=.i.(.j+a.c.@.k+t.~ A.l+F..+e+m+W.f+;+:.P s % ' D a a z ..D 8 I ~ & 0 a /.@+x z.z.= y.z.x.y.p.A.b y.I.N.: Y.N.: : y.F.N.x.F.N y ] ] : T.r n n , 5 5 [ ' M ! /.k+B 4 . n+",
+"] u 6 R ! A z g.I #.=.%+l.%+J a B T p [ & C k+g.u ; g.e+o+p+ +3 {+q #.[ 6 . o g [ H [ n { > N j D 6 a & { : I.w._ _ !+_.+.9.Y.N.]+S.I.F.Z.u n n u u - H.Z.N # y I l o u j j m l l l + $ K.] u : ",
+"z.m @ ' f.~ ~ g.& & :.1 @.S % a %.+.C % @+[ u.& u b _ m+~+)+_+^.#+#.% @ [ . & c s d.g.> ] { z.N ~ z s u G.x.O.F.G -+c.&.1 ^.y.I.]+S.N.G.> n n N ] = ; W Z.] u n @ n o m n m , $ l 2.j k e.{ N Z.",
+"n , j . k o n > { G e T 3 C H a P 0+J % [ [ % & n G _ f+|+4+2+f+p 4 % a ' ~ , s & % { { F.N z.z., n & n z.z.F.y.s 9+b.U c.@._ O.S.I.N.G.H.n { { N ] H.= H.y m y , , s j g j & . j M . M & [ 5 r ",
+"n o j . o y z.T.,+_ r.:.:.#.,+a 3 K !.4 8 a % x u G u.A._+|+9+#.4 #.z a [ ~ x % G f u u > ^ z.N N u u g.z.z.g.G p 3 8+q+*+V p.] w.I.T.z.G.z.{ { u ] Z.> z.= r #.~ ].r g <.<.~ o ~ x k z A O i a ",
+"& o j @ , N ] : K.{ p.#+p #.H g Q P Q a 6 ~ ~ H _ g.& _ p.-+p.#+% % @+0 0 % & #.& | G y.Z.> H.y.> z.u u g.g.G b i 2 r+s+8.7+#+r -+F.T.F.> g.{ g.> ] = u y.g.t t++ & & , r g j 0 o ~ z z z J D z ",
+"0 o o o n & _ G.x.> { _ G g.H & #.s % s z H H & W.u.g.X.G.e+g.A.i.3 p % % 0 ~ z ~ #.g.> > y.u n Z.> u G r r s #.S 2  +}+n.3 C c u z.Z.> > g.{ & > N y.u p.u #.| g ~ r n H & & 0 r b g a a 6 ' a ",
+"g o x o @+p +.@+= G.> { ,+{ g.{ g.g., o H v H #.6.1 %.u.-+i+2+l.:.u+!+#.s g M x % & G g.g.G ; u { z.{ n s % g 0 S 2 %.l.Q @+r G G u { G.> _ n G N u > > u p.u.g & G ; r u r u s F.= n & 0 . a a ",
+"g o n % 9 $.>.0+z.> Z.Q.v+,+n ,+z.n n 0 , & u.I 8+&.1 A.* i+;++.5.&.++b r [ @ ~ % /+5 G g.g.n G c r { H & [ [ p 3 2 C t a ].{ u g.G z.z.: r _ & > u G.x.z._ b r.b n z.> N b G r P.- u n o ~ M 0 ",
+";.P 9 ~ #.u+7.6.t u F.y.g.o k m . . a ~ I ~ j p ++s.w+;+{+< _ ;+7+l.2 _ 4 s ' M c c # & s g 0 k @ o u u r g 8 |.2 &.t+b P.w.y.r ; { z.H.; z.o s t ; z.: F.z.n ; # m r t #.c r & u H.; y o ~ ~ Q ",
+"h T x+K & | r.r.% & y.u s s z s a 9 p [ g & n <.l.>+&.b 2+%.p.f+V 1 3 #.% g % o m u n & & % $ [ p 0 r r n g 9 6 +.e Q u F.P.N r n n ; = u { r s ; r y.x.y.N u # u N o c s s G g.] Z.= ] % a J T ",
+"X S 3.j.9 K 4 Q A s s % % a 4 +.+.e Q r.G & d.g b 7.:.p.G p.b p.6.6.4 [ x % > z.z.{ { { y n o % $ j r u g.r [ a 3 Q 4 & _ y.n % p.n u g.; ; s H , n z.{ z.g.n o o , n s r & G H = F.= H 9 7 (.T ",
+"~.P S 3.0.i a K J.~ & & u.@+^.l.l.1 3 e #.G { & u.r.C #.p.H G c .+t % J y+u.T.y.G.g.F.] { r & H ~ o G , ,+& [ [ T K % G ; - & g #.#.s g.s #.s ,+y 2.{ H r b & r #.& o s r o & n z.] z.{ 9 /.,.(.",
+"S 1.M.,.|./.a a a u.n g.@++.c.8+V {+6.l.< G { / G +.p q #.{ r s u m % % x g.Y.l+X.#.#.u n g [ k+o ~ g & { & [ [ S a k+x p.G & 4 #.r.3 #.& & @+s r s & r 5 | Q p 9 #.s s o n G H H.F.z.n E ,.Z Z ",
+"4 ` ` |.A ~ z J P #.s r t e q+s+c.~+5.q l.g.g.K.{ % t % s b 4 s r , 0 n H : : w./+r.7.+.; #.[ . s [ I [ & G p 4 S 4 k+n G u g.% 3 t+T Q u.#.#.t C p g % | 4.7.T >.C s r n N n z.F.z.z.G 7 ..Z >.",
+"J a J.D |.J.~ E 4 C #.o z +.d+r+!+;+%.%.p.g.g.Q.K.X.r G s +.Q %.a o b > : T.T.: ~ Q u+=.P @+~ f.s [ i <.& & @+r | !.[ s G u & @+2 s.:.B #.p #+t 3 !.C a S h B :.$.P G n ] z.N F.Z.x.^ { [ } ..a ",
+"D R D D O a 6 h (.h i ' a 4 5.z+6.%.A..+G.z.g.u z.K.G #.%.r.r.T 6 ~ n Z.N.F.> { . [ >.X T J . f.H g 8 #.y+H g.H 3 i 9 % ; p.b [ 6.s.=.T #.#.#+l.=.X 3 4 [ +.Q 3 $.C g.{ ^ ^ H.F.x.F.: 2.8 v.R [ ",
+"E a D 8 8 6 5 I 5+5+!+B [ ~ C 5+#+* L u.#.s p #.0 [ #.3 +.1 1 =.p u.r Z./ n G H % 5 B 2 T L 0 ! $ l W m { n s o p.b g G ~ #.P +.l.w+w+f .+G r L 1+s.f K [ 6 9 o a P g & m m g.z.u m { , 0 O D ..",
+"R |.O E 8 ' [ [ ++!+1 Q ..a [ {+G -+r.#+4 #+p g 8 5 C e 1 2 2 =.q r #.Q.{ r #.z.% p q L +.#.~ . j 2.m 2.{ { n l b p.n H g 5 +.#.b T j.+.% 0 0 @ 2 T S 5 [ 6 I 4 a 6 0 x & r n g.m u m G @ [ a |.",
+"D D O O D 0 z ~ Q S K /...D % & _ f+f +.p #.p +.| +.C 2 2 2 5.2 p s g e.{ # c H & % #.b t #.4 ` K % m o g.H g.# p.s s % #.p S S K S J 4 x a [ D r.r.q [ % a i 5 a 6 0 o g [ #.#.o # 0 0 0 z . 6 ",
+"A ..J D J J z ~ J P J a A ! z g.2+A.e P % @+C r.T l.A.7+2 7++.:.p G g / , n & H /+& u ] / Q.@+1.9 ~ ,+g.G z.,+y & p.#.g g 4 9 T 1.P @+/.~ 4 D 9 +.r.P [ o ~ I 8 a [ a 0 [ 5 P [ 0 g 0 g z , , [ ",
+"v.O D 4 (.` /.a [ S 3 J . a #.A.l.C Q 5 k+s A.:.=.3 ^.s._.2 3 r.I ~ 0 m o , o s +.B e t z.Q.u.$.1.[ & <.j.r.G # s g.g.r #.[ P !.2 %.#.B C S P 4 P 9 p [ , & 5 8 [ p [ 0 [ [ a a ~ ' [ @ ~ v x 0 ",
+"v./.D P Z h K 7 P r.T p s ~ q :.6.#+C 9 z C C :._.1 l.s.2 :.q !.Q ~ [ o k , ~ [ C B e L g.`.v+G @+H / #.t+Q & , s & n o r s [ d !+!+1 < 3 7.j.C [ /.[ g H , [ I S I p [ [ % z z % [ 0 z ~ k k 0 ",
+"! |.P S X B J ` /.K S C z & q _.:.#+% |.4 Q +.V T 7+1 2 3 S [ 5 9 [ Q ~ H v % [ +.r.3 r.+._ : z.g.n y u I p ~ ' g o o r n , a d 2 s.2 b 3 T ;.C D J [ g H H [ 9 T T f [ g . % [ [ 5 ' o . 0 . . ",
+"' E !.T u+S 4 h g+/.K J z z S  . .C & D a >.S 7+%+2 1 2 +.p [ 5 i (.4.~ v x [ 0 +.C 9.+.3 b H.H.,+N ] / G x x 8 8 l Z./ m o ~ 6 :.T T 9.$.+.K A+/.|.[ g , ,+g 5 2 2 +.g % o 0 8 I | [ k % ) A k ",
+"O O 8 Z h K p p <.+.r.B Q q :.&.&+S @+#.9 B S {+I f r.T 2 l.l.e ;.q 9 x x k ~ 9 q.B+1 0+S C s / 2.N ^ C+O.; [ v.Y 0 M ,+m n [ ' I I 5 % 4 t r r [ [ 0 0 , n { ; R O @ p.; #.p 9 7.Q #.% a O O z ",
+"i 9 9 i !.L S r.< 3 >.:.Q +.:. .}+3 4 4 6 Q Q +.$ Q L 3 1 :.r.e | p 5 ~ 0 s [ 5 5.s.c.^.0+r.p n H m u H.z.j @ J.+ [ t r r n o k [ i S 4 #.s r # j 0 o 0 , o n n . ' <.p p r.!.Q Q P [ 4 % [ !.9 ",
+"2 B P J 9 S :.c._.2 =.%+P #.4 @.T >.P 4 J 5 P %.[ % C 3 2 B l.T 9 [ [ . 6 z [ #._.>+'+c.{+_.Q #.,+# j m N r o , e./ ] u = n n s [ 3.3.P u.g.n N o c o 0 ~ g n { , 0 [ a [ B $.2 d Q Q Q C C B T ",
+"&.1 P [ 6 3 2 1+c.V %+3 4 @+P >.%+%+B J [ K 9 P a P +.B 2 :.%.%.a [ z . 9 % r.C i.@.>+ +|+2 >.6 r M j ~ x d.z.N > Z.T.z.^ > / n J ;.u+Q u.{ { N G 0 % 0 0 5 0 n m j . a ..!.T u+7.5 4 r.>.1 2 =.",
+"h+7++.J +.r.c.d+_.!+1 C #.o % S T =.>.S K Q Q J 4 7.X 1 1 2 C H ~ % x z 5 [ T B 0+3 V 1+4+l.B a <.0 z ' . , y r - N Z.= H.z./ z.& S | #.G n z.u N j o 0 o O [ [ N , % E ` !.S :.I % @+Q 2 _.n.n.",
+"n.7+3 3 r.B !+V b.++3 +.j o 0 S =.2 T B >.>.(.K $.T _.&._.A.& ~ b s % & g #.L q d 2 1 a+u+%.I % 6 M ~ w [ o , r n { > n u u N z.,+G s G g.y.z.z.n r r 0 . 8 8 I o d.& |.i J 4 S 6 g p B 1 2 n.a+",
+"=.=.7+V 6.1 1 r.l.{+S +.5 p r.;.c.7+7+2 T >.>.(. .1  +U _._ ,+6 l.C L s s & g.X.s #.#.C Q p g $ . J.. @ [ . ~ . 0 o o n n z.z.> > , n z.n z.> z.n r r [ 0 O 6 E + o , G & n % I [ [ !.T :.7+}+}+",
+"$.=._. +V 6.3 9 !+1 %+%+r.C S %+_.7+7+[.=.B (.T 1 n.h+5+|+p.o @ ++l.s.t #.& X.Q.N g.x y+k+0 ,+W A ' @ 0 0 + D ) O [ [ x 0 u ; u y N N u - z.F._ u r o [ ' ' . . E [ r N { y 0 R % 4 p r.B =. .7+",
+"2 s.7+1 &+1  .:._.1+1+2 1 %+7+1.5+2 X $.[.n._.3 >.Q i [ M g #.p 2 e :.l.f #.[ a g p #.% 0 % z . $ m 8 x |.v.' w *.$ # @ j l p f + , k s d f z.n u ; o # $ o l 2.m $ <.j x o [ L @ j % [ h $.P 1.",
+"1 2 2 %+ .S T :._._._.2 7+2 %+@.6.T %+X [.n. .T B K 8 6 [ 0 #.p 2 2 !+e T #+Q 9 t p g % [ ' a 5 r.<.I . /.a 6 w p #.~ M z ~ [ 9 $ r g.g f t n z., u m , c , # 2.2.l j s s [ <.[ $ j s % | >.K >.",
+"S T T T $.%.3 T c.c.2 _.}+=.1 +.+.S B }+n.h+s.1.!.Q 6 |.' o #.p 2 1 :.2 2 #.3 | r.p #.a 9 [ [ I &.2 <.' a A J [ d Q J z z z A+a g s { #.C _ b G.m & r { $ y g 0 j o o g <.[ s o $ & r & 4 L p S ",
+"p Q S >.>.C P | 2 2 V 2 2 2 3 C P 4 S 2 h+1+7+Z 3 ` |.D J.~ [ p 1 3 :.5+2 2++.T :.p @+[ 9 J [ f 8.>+t + . a 9 P 0.` F |.a D a D I #.& A.G _ *.n n s s n 0 , g @ t s s #.p g r o s & s o & g [ g ",
+"a [ J K S S 4 r.%+1 3 3 3 S %.C 9 a J %+&.2 S /.+.>.E D } z K S B 3 :._._.A.1 2 3 #.& a 9 9 C r.b+>+#.5 0 J Q B 0 a 8 a z . . a 4.P L #+f+b G g.x g x % & & , m 0 o s [ p #.t <.#.G $ s m % g p ",
+"5 P 4 P Q T +.Q S P P 4 4 #.p 9 B K D i T S J A+#.0+E D A ..4 q S S 3 2 s.%.7+2 1 +.@+a /.[ #.l.8.1+#.8 6 !.>.2 6 i D+| I F + 8 E #.L #.p.t n & & P & 5 o s H n o s % C p q q f @+#.g r r s b p ",
+"8 9 P J S M.+.S P [ % 4 [ 4 J Q j.Q ..'.|.D a j+l.u.9 D D E s +.J C p 3 2 3 2 %+2 >.K a a #.4 l.>+1 P O ,.Z r.w+S Q -.r.p L & . z a [ G G ; o j a i a Q 5 p o G M j $ p S r.3 %.t #.s m s b & S ",
+"9 i 4 4 0+u+%.%.' % . [ 6 |.9 Q w+(.7 L.=+A A ) >+p.J D |.` G T 4 % 4 +.2 1 [.1 3 :.!.a % 4 l.s.&.q 9 /.,.$.r.++T =.E+2 @.T #.% } F % G & { s @ P ` K I d p [ % l M g q | 2 r.A.+.t G n t #.u.B ",
+"t r.J @+P B 9 ' a [ J |.J p B ;.T Q [ D v.. . + ; l w . 4 T #+e t #+6.!+!+:.f P K S r.S 0 % S &+s.f P Q ` Q 5 Q <.+ | <.0 5 7.l.P I 8 ' . @ 0 % a Q i i ` [ % I 6 & P #.| >+3 S !+p q c b - C C ",
+"t r.P A+q p % A % [ [ 9 6 P S =.T Q a D A M k m m 2.@ f.P T #+q 4 [ r.T 3 S P [ K S S #.% 4 B }+e L +.Q ` 9 P 6 # l j k o g t+| P !.8 D ' 6 J [ [ 8 9 5 5 5 6 I i 0 g r q u+r.@.6.p p 0 b & #.a ",
+"#+q J 4 P #+% a [ J O 8 9 !.>.2 ` 9 /...! k ].].y / M M 5 T #.[ z |.K =.C K A+z P S +.4 [ !.>.7+3 3 | ` ` 8 6 a j o l l 0 s p C 9 ` 7 ,.|.8 9 |.K 9 5 a @+6 i 9 i @ j o t j.:.e ++S 9 P p g [ A ",
+"q C J P p % % |.' [ 6 9 !.| >.T ,.9 |.|.' . k 2.N 2.k k P T 4 g z J p ;.C B 4 A+[ 5 +.P 8 ` >.V T T h (.8 |.D z y 2.o k $ o g I ,.` 7 ,.9 g+9 |.|.[ [ a z [ i 9 I [ [ 0 L T r.:.1 +.S Q +.q P A+",
+":.+.J P #.g.% a a a [ P 9 Q !.S |./.|.|.D z M ~ r o h.k [ Q C [ s p #+s.3 s.3 +.5 #.4 9 O 6 3 7+[.T Q |.6 a A A #.o 2.B., d.~ L ,.,.,.K /.K g+/.8 a 6 9 4 4 Q Q Q 9 d h h T 1 V 5+6.1 2 _._.++3 ",
+":.C A+4 s & ~ a a p P P K K 9 |.,.,.,.|.D a ' a [ @ f.k #.C [ [ s #+%.b.c.h+_.:.| C 4 6 J a !.&.X T K 5 6 a [ 9 f p [ ~ k y+o a 9 K K K K 9 9 |.6 a |.i 9 [ 9 | Z $.0.0.Z >.%+s.b.++e &.h+U h+_.",
+"1 #.k+#.s r #.z Q Q B r.K 9 O ..8 !.E 9 O |.Y Y a O . . b b b g #.#+l._.d+&.&.2 | 9 4 J ..D B &.$.B I i 5 g p T Q 4 8 [ 8 [ I [ 9 K 9 Q Q Q 9 [ ' [ [ 6 9 S Q h h !.(.` h >.=.s.++l.+.s.c.U 8+c.",
+"_.4 @+[ s b a x S T :.S P 6 D v.J K |.|.|...g+'.A O v.. #._ G r a C B }+[.}+ .7+I +.p D D |.3 V B S I d 5 G 4 2 7.C 5 a a ' i % 8 9 Q :.| I p ' . 6 A ~ P I Q B p 6 [ E F d t+w+t+h K  .1+b+*+}+",
+"r.q S f q r z.- !.i Q L g ' ! ).O A O z [ 4.+ ' #.I z ..a K r.#+| T 2 i.[ i [ L h i 7 J I f | Q ` 5 + 0 @ c b f e $ c m j H r #.Q I f [ Q Q 0+T r.q t % [ 6 |...p t m y r L T ;.t+:.r.p u+&.h+q.",
+"< A.b p g u _ - #.p 5 6 0 . . ! 6 |.d 6 % 6 . O 5 d 9 9 J Q Q q [ S %+C P E [ f T P 9 9 h p +.S 6 6 5 j j j & g o , j $ I g G v #+#.f 5 [ #.g u+f p n r @ [ a a g 0 r o c [ Q T 7.T K a Q | e 6.",
+"#+G g._ p.u N u f+#.p 6 A . . @ @ [ g % % a A A [ K Q r.r.;.p @+~ C r.S K 8 9 B u+Q ,.` ;.l.I h 8 6 6 2.v # o s . z 0 o o & p | f G & s s s G [ r # 2.<.l l , 0 & n o j c #.p h $.3.` /.a 4 a C ",
+"f+g.z.n u u y.z.u r a v.A M o # o o , & a . a } z x G p.< u+4 t.~ p r.S 9 ,.Q T ;.P /.8 7.q +.B 8 ' ' , ,+o z g D 8 E 0 x o 5 T D+u.,+].o 0 l { ,+0 @ I k o n p g & o g j ~ #.5 3 1.h F /.J x ~ ",
+"n u G G u n z.] y.n o . f.k 2.m o j s 0 a % ....a x x.x.G.f % j+0 Q r.S 9 6 9 h T P /.J Q q Q K ' J.[ [ o ~ . ' ,.,.|.6 a 6 4 z r.[ % 0 o l $ n s 5 0 8 o I Q e d [ #.g o n & ~ 2+Q q h p [ & o ",
+"& r b c u n N n N , x M ~ k 2.m j M ~ s [ ` 8 |.z % & z.Z.% z /.0 I S S /.z a Q B 9 g+a Q 5 B K D z I I g #.5 F d (.a [ % [ a a #.Q I 5 z o j y & p [ 6 ~ !.B T j.[ 0 g x & ~ , g.p.G #.g c o j ",
+"~ @ j r m G o o m m # j 2.d.2.@ @ 2.& v % 7.6 ~ x + 0 s v & a a a Q +.P J ~ ' g J J '.A 6 % [ z 9 [ h T #.P F 4.K S 9 d 6 J % D C Q % 0 [ M & { / & 0 0 ~ 0 [ +.9 @+[ g x o $ o r & G g.#.o o c ",
+". @ j n , r 0 0 x l # # y K.].. M ~ <.y+H 5 & x 2.0 ].x ].z O ' a B P S O ~ . g 5 ..R ..O % a A z 4 u+7.A.+.` E :.p u.9 P 8 A+a 9 9 v ~ [ s % % N ] B.B.k z g g 4 s J [ & M [ o + 0 0 & 0 & l @ "};
diff --git a/win/share/gifread.c b/win/share/gifread.c
new file mode 100644 (file)
index 0000000..9757227
--- /dev/null
@@ -0,0 +1,706 @@
+/* GIF reading routines based on those in pbmplus:ppm/giftoppm.c, bearing
+ * following copyright notice:
+ */
+
+/* +-------------------------------------------------------------------+ */
+/* | Copyright 1990, David Koblas.                                     | */
+/* |   Permission to use, copy, modify, and distribute this software   | */
+/* |   and its documentation for any purpose and without fee is hereby | */
+/* |   granted, provided that the above copyright notice appear in all | */
+/* |   copies and that both that copyright notice and this permission  | */
+/* |   notice appear in supporting documentation.  This software is    | */
+/* |   provided "as is" without express or implied warranty.           | */
+/* +-------------------------------------------------------------------+ */
+
+
+#include "config.h"
+#include "tile.h"
+
+#ifndef MONITOR_HEAP
+extern long *FDECL(alloc, (unsigned int));
+#endif
+
+#define PPM_ASSIGN(p,red,grn,blu) do { (p).r = (red); (p).g = (grn); (p).b = (blu); } while ( 0 )
+
+#define        MAX_LWZ_BITS            12
+
+#define INTERLACE              0x40
+#define LOCALCOLORMAP  0x80
+#define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
+
+#define        ReadOK(file,buffer,len) (fread((genericptr_t)buffer, (int)len, 1, file) != 0)
+
+#define LM_to_uint(a,b)                        (((b)<<8)|(a))
+
+struct gifscreen {
+       int     Width;
+       int     Height;
+       int     Colors;
+       int     ColorResolution;
+       int     Background;
+       int     AspectRatio;
+       int     Interlace;
+} GifScreen;
+
+struct {
+       int     transparent;
+       int     delayTime;
+       int     inputFlag;
+       int     disposal;
+} Gif89 = { -1, -1, -1, 0 };
+
+int    ZeroDataBlock = FALSE;
+
+static FILE *gif_file;
+static int tiles_across, tiles_down, curr_tiles_across, curr_tiles_down;
+static pixel **image;
+static unsigned char input_code_size;
+
+static int FDECL(GetDataBlock, (FILE *fd, unsigned char *buf));
+static void FDECL(DoExtension, (FILE *fd, int label));
+static boolean FDECL(ReadColorMap, (FILE *fd, int number));
+static void FDECL(read_header, (FILE *fd));
+static int FDECL(GetCode, (FILE *fd, int code_size, int flag));
+static int FDECL(LWZReadByte, (FILE *fd, int flag, int input_code_size));
+static void FDECL(ReadInterleavedImage, (FILE *fd, int len, int height));
+static void FDECL(ReadTileStrip, (FILE *fd, int len));
+
+/* These should be in gif.h, but there isn't one. */
+boolean FDECL(fopen_gif_file, (const char *, const char *));
+boolean FDECL(read_gif_tile, (pixel(*)[]));
+int NDECL(fclose_gif_file);
+
+static int
+GetDataBlock(fd, buf)
+FILE           *fd;
+unsigned char  *buf;
+{
+       unsigned char   count;
+
+       if (!ReadOK(fd,&count,1)) {
+               Fprintf(stderr, "error in getting DataBlock size\n");
+               return -1;
+       }
+
+       ZeroDataBlock = (count == 0);
+
+       if ((count != 0) && (!ReadOK(fd, buf, count))) {
+               Fprintf(stderr, "error in reading DataBlock\n");
+               return -1;
+       }
+
+       return count;
+}
+
+static void
+DoExtension(fd, label)
+FILE   *fd;
+int    label;
+{
+       static char     buf[256];
+       char            *str;
+
+       switch (label) {
+       case 0x01:              /* Plain Text Extension */
+               str = "Plain Text Extension";
+#ifdef notdef
+               if (GetDataBlock(fd, (unsigned char*) buf) == 0)
+                       ;
+
+               lpos   = LM_to_uint(buf[0], buf[1]);
+               tpos   = LM_to_uint(buf[2], buf[3]);
+               width  = LM_to_uint(buf[4], buf[5]);
+               height = LM_to_uint(buf[6], buf[7]);
+               cellw  = buf[8];
+               cellh  = buf[9];
+               foreground = buf[10];
+               background = buf[11];
+
+               while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
+                       PPM_ASSIGN(image[ypos][xpos],
+                                       cmap[CM_RED][v],
+                                       cmap[CM_GREEN][v],
+                                       cmap[CM_BLUE][v]);
+                       ++index;
+               }
+
+               return;
+#else
+               break;
+#endif
+       case 0xff:              /* Application Extension */
+               str = "Application Extension";
+               break;
+       case 0xfe:              /* Comment Extension */
+               str = "Comment Extension";
+               while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
+                       Fprintf(stderr, "gif comment: %s\n", buf );
+               }
+               return;
+       case 0xf9:              /* Graphic Control Extension */
+               str = "Graphic Control Extension";
+               (void) GetDataBlock(fd, (unsigned char*) buf);
+               Gif89.disposal    = (buf[0] >> 2) & 0x7;
+               Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
+               Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
+               if ((buf[0] & 0x1) != 0)
+                       Gif89.transparent = buf[3];
+
+               while (GetDataBlock(fd, (unsigned char*) buf) != 0)
+                       ;
+               return;
+       default:
+               str = buf;
+               Sprintf(buf, "UNKNOWN (0x%02x)", label);
+               break;
+       }
+
+       Fprintf(stderr, "got a '%s' extension\n", str);
+
+       while (GetDataBlock(fd, (unsigned char*) buf) != 0)
+               ;
+}
+
+static
+boolean
+ReadColorMap(fd,number)
+FILE           *fd;
+int            number;
+{
+       int             i;
+       unsigned char   rgb[3];
+
+       for (i = 0; i < number; ++i) {
+               if (!ReadOK(fd, rgb, sizeof(rgb))) {
+                       return(FALSE);
+               }
+
+               ColorMap[CM_RED][i] = rgb[0] ;
+               ColorMap[CM_GREEN][i] = rgb[1] ;
+               ColorMap[CM_BLUE][i] = rgb[2] ;
+       }
+       colorsinmap = number;
+       return TRUE;
+}
+
+/*
+ * Read gif header, including colormaps.  We expect only one image per
+ * file, so if that image has a local colormap, overwrite the global one.
+ */
+static void
+read_header(fd)
+FILE   *fd;
+{
+       unsigned char   buf[16];
+       unsigned char   c;
+       char            version[4];
+
+       if (!ReadOK(fd,buf,6)) {
+               Fprintf(stderr, "error reading magic number\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (strncmp((genericptr_t)buf,"GIF",3) != 0) {
+               Fprintf(stderr, "not a GIF file\n");
+               exit(EXIT_FAILURE);
+       }
+
+       (void) strncpy(version, (char *)buf + 3, 3);
+       version[3] = '\0';
+
+       if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
+               Fprintf(stderr, "bad version number, not '87a' or '89a'\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (!ReadOK(fd,buf,7)) {
+               Fprintf(stderr, "failed to read screen descriptor\n");
+               exit(EXIT_FAILURE);
+       }
+
+       GifScreen.Width           = LM_to_uint(buf[0],buf[1]);
+       GifScreen.Height          = LM_to_uint(buf[2],buf[3]);
+       GifScreen.Colors          = 2<<(buf[4]&0x07);
+       GifScreen.ColorResolution = (((buf[4]&0x70)>>3)+1);
+       GifScreen.Background      = buf[5];
+       GifScreen.AspectRatio     = buf[6];
+
+       if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
+               if (!ReadColorMap(fd, GifScreen.Colors)) {
+                       Fprintf(stderr, "error reading global colormap\n");
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) {
+               Fprintf(stderr, "warning - non-square pixels\n");
+       }
+
+       for (;;) {
+               if (!ReadOK(fd,&c,1)) {
+                       Fprintf(stderr, "EOF / read error on image data\n");
+                       exit(EXIT_FAILURE);
+               }
+
+               if (c == ';') {         /* GIF terminator */
+                       return;
+               }
+
+               if (c == '!') {         /* Extension */
+                   if (!ReadOK(fd,&c,1)) {
+                       Fprintf(stderr,
+                           "EOF / read error on extension function code\n");
+                       exit(EXIT_FAILURE);
+                   }
+                   DoExtension(fd, (int)c);
+                   continue;
+               }
+
+               if (c != ',') {         /* Not a valid start character */
+                       Fprintf(stderr,
+                               "bogus character 0x%02x, ignoring\n", (int) c);
+                       continue;
+               }
+
+               if (!ReadOK(fd,buf,9)) {
+                   Fprintf(stderr, "couldn't read left/top/width/height\n");
+                   exit(EXIT_FAILURE);
+               }
+
+               if (BitSet(buf[8], LOCALCOLORMAP)) {
+                       /* replace global color map with local */
+                       GifScreen.Colors = 1<<((buf[8]&0x07)+1);
+                       if (!ReadColorMap(fd, GifScreen.Colors)) {
+                           Fprintf(stderr, "error reading local colormap\n");
+                           exit(EXIT_FAILURE);
+                       }
+
+               }
+               if (GifScreen.Width != LM_to_uint(buf[4],buf[5])) {
+                       Fprintf(stderr, "warning: widths don't match\n");
+                       GifScreen.Width = LM_to_uint(buf[4],buf[5]);
+               }
+               if (GifScreen.Height != LM_to_uint(buf[6],buf[7])) {
+                       Fprintf(stderr, "warning: heights don't match\n");
+                       GifScreen.Height = LM_to_uint(buf[6],buf[7]);
+               }
+               GifScreen.Interlace = BitSet(buf[8], INTERLACE);
+               return;
+       }
+}
+
+static int
+GetCode(fd, code_size, flag)
+FILE   *fd;
+int    code_size;
+int    flag;
+{
+       static unsigned char    buf[280];
+       static int              curbit, lastbit, done, last_byte;
+       int                     i, j, ret;
+       unsigned char           count;
+
+       if (flag) {
+               curbit = 0;
+               lastbit = 0;
+               done = FALSE;
+               return 0;
+       }
+
+       if ((curbit+code_size) >= lastbit) {
+               if (done) {
+                       if (curbit >= lastbit)
+                               Fprintf(stderr, "ran off the end of my bits\n");
+                       return -1;
+               }
+               buf[0] = buf[last_byte-2];
+               buf[1] = buf[last_byte-1];
+
+               if ((count = GetDataBlock(fd, &buf[2])) == 0)
+                       done = TRUE;
+
+               last_byte = 2 + count;
+               curbit = (curbit - lastbit) + 16;
+               lastbit = (2+count)*8 ;
+       }
+
+       ret = 0;
+       for (i = curbit, j = 0; j < code_size; ++i, ++j)
+               ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
+
+       curbit += code_size;
+
+       return ret;
+}
+
+static int
+LWZReadByte(fd, flag, input_code_size)
+FILE   *fd;
+int    flag;
+int    input_code_size;
+{
+       static int      fresh = FALSE;
+       int             code, incode;
+       static int      code_size, set_code_size;
+       static int      max_code, max_code_size;
+       static int      firstcode, oldcode;
+       static int      clear_code, end_code;
+       static int      table[2][(1<< MAX_LWZ_BITS)];
+       static int      stack[(1<<(MAX_LWZ_BITS))*2], *sp;
+       register int    i;
+
+       if (flag) {
+               set_code_size = input_code_size;
+               code_size = set_code_size+1;
+               clear_code = 1 << set_code_size ;
+               end_code = clear_code + 1;
+               max_code_size = 2*clear_code;
+               max_code = clear_code+2;
+
+               (void) GetCode(fd, 0, TRUE);
+
+               fresh = TRUE;
+
+               for (i = 0; i < clear_code; ++i) {
+                       table[0][i] = 0;
+                       table[1][i] = i;
+               }
+               for (; i < (1<<MAX_LWZ_BITS); ++i)
+                       table[0][i] = table[1][0] = 0;
+
+               sp = stack;
+
+               return 0;
+       } else if (fresh) {
+               fresh = FALSE;
+               do {
+                       firstcode = oldcode = GetCode(fd, code_size, FALSE);
+               } while (firstcode == clear_code);
+               return firstcode;
+       }
+
+       if (sp > stack)
+               return *--sp;
+
+       while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
+               if (code == clear_code) {
+                       for (i = 0; i < clear_code; ++i) {
+                               table[0][i] = 0;
+                               table[1][i] = i;
+                       }
+                       for (; i < (1<<MAX_LWZ_BITS); ++i)
+                               table[0][i] = table[1][i] = 0;
+                       code_size = set_code_size+1;
+                       max_code_size = 2*clear_code;
+                       max_code = clear_code+2;
+                       sp = stack;
+                       firstcode = oldcode = GetCode(fd, code_size, FALSE);
+                       return firstcode;
+               } else if (code == end_code) {
+                       int             count;
+                       unsigned char   buf[260];
+
+                       if (ZeroDataBlock)
+                               return -2;
+
+                       while ((count = GetDataBlock(fd, buf)) > 0)
+                               ;
+
+                       if (count != 0)
+                           Fprintf(stderr,
+                           "missing EOD in data stream (common occurrence)\n");
+                       return -2;
+               }
+
+               incode = code;
+
+               if (code >= max_code) {
+                       *sp++ = firstcode;
+                       code = oldcode;
+               }
+
+               while (code >= clear_code) {
+                       *sp++ = table[1][code];
+                       if (code == table[0][code]) {
+                           Fprintf(stderr, "circular table entry BIG ERROR\n");
+                           exit(EXIT_FAILURE);
+                       }
+                       code = table[0][code];
+               }
+
+               *sp++ = firstcode = table[1][code];
+
+               if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
+                       table[0][code] = oldcode;
+                       table[1][code] = firstcode;
+                       ++max_code;
+                       if ((max_code >= max_code_size) &&
+                               (max_code_size < (1<<MAX_LWZ_BITS))) {
+                               max_code_size *= 2;
+                               ++code_size;
+                       }
+               }
+
+               oldcode = incode;
+
+               if (sp > stack)
+                       return *--sp;
+       }
+       return code;
+}
+
+
+static void
+ReadInterleavedImage(fd, len, height)
+FILE   *fd;
+int    len, height;
+{
+       int             v;
+       int             xpos = 0, ypos = 0, pass = 0;
+
+       while ((v = LWZReadByte(fd,FALSE,(int)input_code_size)) >= 0 ) {
+               PPM_ASSIGN(image[ypos][xpos], ColorMap[CM_RED][v],
+                               ColorMap[CM_GREEN][v], ColorMap[CM_BLUE][v]);
+
+               ++xpos;
+               if (xpos == len) {
+                       xpos = 0;
+                       switch (pass) {
+                               case 0:
+                               case 1:
+                                       ypos += 8; break;
+                               case 2:
+                                       ypos += 4; break;
+                               case 3:
+                                       ypos += 2; break;
+                       }
+
+                       if (ypos >= height) {
+                               ++pass;
+                               switch (pass) {
+                                       case 1:
+                                               ypos = 4; break;
+                                       case 2:
+                                               ypos = 2; break;
+                                       case 3:
+                                               ypos = 1; break;
+                                       default:
+                                               goto fini;
+                               }
+                       }
+               }
+               if (ypos >= height)
+                       break;
+       }
+
+fini:
+       if (LWZReadByte(fd,FALSE,(int)input_code_size)>=0)
+               Fprintf(stderr, "too much input data, ignoring extra...\n");
+}
+
+static
+void
+ReadTileStrip(fd,len)
+FILE *fd;
+int len;
+{
+       int     v;
+       int     xpos = 0, ypos = 0;
+
+       while ((v = LWZReadByte(fd,FALSE,(int)input_code_size)) >= 0 ) {
+               PPM_ASSIGN(image[ypos][xpos], ColorMap[CM_RED][v],
+                               ColorMap[CM_GREEN][v], ColorMap[CM_BLUE][v]);
+
+               ++xpos;
+               if (xpos == len) {
+                       xpos = 0;
+                       ++ypos;
+               }
+               if (ypos >= TILE_Y)
+                       break;
+       }
+}
+
+
+
+
+boolean
+fopen_gif_file(filename, type)
+const char *filename;
+const char *type;
+{
+       int i;
+
+       if (strcmp(type, RDBMODE)) {
+               Fprintf(stderr, "using reading routine for non-reading?\n");
+               return FALSE;
+       }
+       gif_file = fopen(filename, type);
+       if (gif_file == (FILE *)0) {
+               Fprintf(stderr, "cannot open gif file %s\n", filename);
+               return FALSE;
+       }
+
+       read_header(gif_file);
+       if (GifScreen.Width % TILE_X) {
+               Fprintf(stderr, "error: width %d not divisible by %d\n",
+                               GifScreen.Width, TILE_X);
+               exit(EXIT_FAILURE);
+       }
+       tiles_across = GifScreen.Width / TILE_X;
+       curr_tiles_across = 0;
+       if (GifScreen.Height % TILE_Y) {
+               Fprintf(stderr, "error: height %d not divisible by %d\n",
+                               GifScreen.Height, TILE_Y);
+               /* exit(EXIT_FAILURE) */;
+       }
+       tiles_down = GifScreen.Height / TILE_Y;
+       curr_tiles_down = 0;
+
+       if (GifScreen.Interlace) {
+           /* sigh -- hope this doesn't happen on micros */
+           image = (pixel **)alloc(GifScreen.Height * sizeof(pixel *));
+           for (i = 0; i < GifScreen.Height; i++) {
+               image[i] = (pixel *) alloc(GifScreen.Width * sizeof(pixel));
+           }
+       } else {
+           image = (pixel **)alloc(TILE_Y * sizeof(pixel *));
+           for (i = 0; i < TILE_Y; i++) {
+               image[i] = (pixel *) alloc(GifScreen.Width * sizeof(pixel));
+           }
+       }
+
+       /*
+       **  Initialize the Compression routines
+       */
+       if (!ReadOK(gif_file,&input_code_size,1)) {
+               Fprintf(stderr, "EOF / read error on image data\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (LWZReadByte(gif_file, TRUE, (int)input_code_size) < 0) {
+               Fprintf(stderr, "error reading image\n");
+               exit(EXIT_FAILURE);
+       }
+
+       /* read first section */
+       if (GifScreen.Interlace) {
+               ReadInterleavedImage(gif_file,
+                                       GifScreen.Width,GifScreen.Height);
+       } else {
+               ReadTileStrip(gif_file,GifScreen.Width);
+       }
+       return TRUE;
+}
+
+/* Read a tile.  Returns FALSE when there are no more tiles */
+boolean
+read_gif_tile(pixels)
+pixel (*pixels)[TILE_X];
+{
+       int i, j;
+
+       if (curr_tiles_down >= tiles_down) return FALSE;
+       if (curr_tiles_across == tiles_across) {
+               curr_tiles_across = 0;
+               curr_tiles_down++;
+               if (curr_tiles_down >= tiles_down) return FALSE;
+               if (!GifScreen.Interlace)
+                       ReadTileStrip(gif_file,GifScreen.Width);
+       }
+       if (GifScreen.Interlace) {
+               for (j = 0; j < TILE_Y; j++) {
+                   for (i = 0; i < TILE_X; i++) {
+                       pixels[j][i] = image[curr_tiles_down*TILE_Y + j]
+                                           [curr_tiles_across*TILE_X + i];
+                   }
+               }
+       } else {
+               for (j = 0; j < TILE_Y; j++) {
+                   for (i = 0; i < TILE_X; i++) {
+                       pixels[j][i] = image[j][curr_tiles_across*TILE_X + i];
+                   }
+               }
+       }
+       curr_tiles_across++;
+
+       /* check for "filler" tile */
+       for (j = 0; j < TILE_Y; j++) {
+               for (i = 0; i < TILE_X && i < 4; i += 2) {
+                       if (pixels[j][i].r != ColorMap[CM_RED][0] ||
+                           pixels[j][i].g != ColorMap[CM_GREEN][0] ||
+                           pixels[j][i].b != ColorMap[CM_BLUE][0] ||
+                           pixels[j][i+1].r != ColorMap[CM_RED][1] ||
+                           pixels[j][i+1].g != ColorMap[CM_GREEN][1] ||
+                           pixels[j][i+1].b != ColorMap[CM_BLUE][1])
+                               return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+int
+fclose_gif_file()
+{
+       int i;
+
+       if (GifScreen.Interlace) {
+               for (i = 0; i < GifScreen.Height; i++) {
+                       free((genericptr_t)image[i]);
+               }
+               free((genericptr_t)image);
+       } else {
+               for (i = 0; i < TILE_Y; i++) {
+                       free((genericptr_t)image[i]);
+               }
+               free((genericptr_t)image);
+       }
+       return(fclose(gif_file));
+}
+
+#ifndef AMIGA
+static char *std_args[] = { "tilemap", /* dummy argv[0] */
+                       "monsters.gif", "monsters.txt",
+                       "objects.gif",  "objects.txt",
+                       "other.gif",    "other.txt" };
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       pixel pixels[TILE_Y][TILE_X];
+
+       if (argc == 1) {
+               argc = SIZE(std_args);
+               argv = std_args;
+       } else if (argc != 3) {
+               Fprintf(stderr, "usage: gif2txt giffile txtfile\n");
+               exit(EXIT_FAILURE);
+       }
+
+       while (argc > 1) {
+               if (!fopen_gif_file(argv[1], RDBMODE))
+                       exit(EXIT_FAILURE);
+
+               init_colormap();
+
+               if (!fopen_text_file(argv[2], WRTMODE)) {
+                       (void) fclose_gif_file();
+                       exit(EXIT_FAILURE);
+               }
+
+               while (read_gif_tile(pixels))
+                       (void) write_text_tile(pixels);
+
+               (void) fclose_gif_file();
+               (void) fclose_text_file();
+
+               argc -= 2;
+               argv += 2;
+       }
+       exit(EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
+#endif
diff --git a/win/share/monsters.txt b/win/share/monsters.txt
new file mode 100644 (file)
index 0000000..2df3321
--- /dev/null
@@ -0,0 +1,7502 @@
+A = (0, 0, 0)
+B = (0, 182, 255)
+C = (255, 108, 0)
+D = (255, 0, 0)
+E = (0, 0, 255)
+F = (0, 145, 0)
+G = (108, 255, 0)
+H = (255, 255, 0)
+I = (255, 0, 255)
+J = (145, 71, 0)
+K = (204, 79, 0)
+L = (255, 182, 145)
+M = (71, 108, 108)
+N = (255, 255, 255)
+O = (218, 218, 182)
+P = (108, 145, 182)
+# tile 0 (giant ant)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMJAJKKAMMM
+  MMMMMJAAAKJJJAMM
+  MMMMMAKJJAJJAAMM
+  MMMKKAJJJAAAMMMM
+  MMBJJAAAAAJJAMMM
+  MMJBJAJAJAAMMMMM
+  MMMMMAJAMJAMMMMM
+  MMMMMMJAMJAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 1 (killer bee)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MPPPMMMMMPPMMMMM
+  PPPPPMMMPBPPMMMM
+  PBPPPMMPBPPPMMMM
+  MPPBPMPPLPLLMMMM
+  MMMPPMPLLALHAHMM
+  MMMAKKKLAHAAHHMM
+  BBJJJJJJJAHHAAMM
+  ABJBBJJJJAHAHHMM
+  MJJABJAJMJMHHMMM
+  MMMMMMMJMJMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMAAAAAAAAAAAMM
+  MMMMMAAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 2 (soldier ant)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMJAJKKAMMM
+  MMMMMJAAAKJJJAMM
+  MMMMMAKJJAJJAAMM
+  MJJKKAJJJAAAMMMM
+  JBJJJAAAAAJJAMMM
+  JJJBJAJAJAAMMMMM
+  JAAJJAJAMJAMMMMM
+  MMJJAAJAMJAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 3 (fire ant)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMDACCCAMMM
+  MMMMMDAAACDDDAMM
+  MMMMMACDDADDAAMM
+  MMMCCADDDAAAMMMM
+  MMGDDAAAAADDAMMM
+  MMDGDADADAAMMMMM
+  MMMMMADAMDAMMMMM
+  MMMMMMDAMDAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 4 (giant beetle)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMKKDKKMMMMM
+  MMMMKACLCJJDMMMM
+  MMMKCLCJJDDDKMMM
+  MMMDCCJDADDADMMM
+  MMMADJDDDDDDDMMM
+  MMMBAKDDAADKAAMM
+  MMMABAKDDKMMMMMM
+  MMMMMMAAMAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 5 (queen bee)
+{
+  MMMMMMMMMMMMMMMM
+  MPPPMMMMMPPMMMMM
+  PPPPPMMMPPPPMMMM
+  PPPPPMMPPBPPMMMM
+  PBPPPMMPBPPPMMMM
+  MPPBPMPPLPLLMMMM
+  MMMPPMPLLALHAHMM
+  MMMAKKKLAHAAHHMM
+  BBJJJJJJJAHHAAHM
+  ABJBBJJJJAHAHHHM
+  MJJABJAJMJHHHAAM
+  MMMJMMMJMJAAAHHM
+  MMJJMMJJMJMHHAHM
+  MMJAAAJAAJMMHHMM
+  MMMMMAAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 6 (acid blob)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMKDDAMMMMMMM
+  MMMDDKDDKAMMMMMM
+  MDDDIIIDJDAMMMMM
+  DMIIOOIIDAIAMMMM
+  MDKNNNODIDAMMIAM
+  IDJNANOJDDJAMMMM
+  ADIDNOIDIDDDAMMM
+  MMMJDIKIADKIAMMM
+  MIAMIDIDMJDAMMMM
+  MMMIMDDAMMMMDAMM
+  MMMMMMMMMIAMMMMM
+  MMIAMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 7 (quivering blob)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPPPPMMMMMMM
+  MMMMMMMMMPMMMMMM
+  MPMOOOPPEMMAAAMM
+  PMOPBBBPOEAEAAMM
+  PMPBNNNPMOEAAEAM
+  PMPNNNNNPOEEAEAM
+  POPNAANNEOMOAEAM
+  MOPNAANNEMMOAAAM
+  MOPBNNNEPPMOEAAM
+  BPOPEEEBBPOMEEAM
+  BBBPBBBBBBPPPPAM
+  MMBBBBBBBBBBPAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 8 (gelatinous cube)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMLLLMMMMMM
+  MMMMMLLLLLLLLMMM
+  MMMLLLLLLLLLDMMM
+  MMMCLLLLLLLDDAMM
+  MMMCGGCLLLDDDAAM
+  MMMCAGCGGDDDDAAA
+  MMMCCCCAGDDDAAAA
+  MMMMMCCCCDDAAAAM
+  MMMMMMMCCDAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 9 (chickatrice)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMOOMMMMMMM
+  MMMMMMHAOOMMMMMM
+  MMMMMHHOOHMHHAMM
+  MMMMMMMMOOHOAMMM
+  MMMMMMMMOOFAMMMM
+  MMMMMMMMFGGFAMMM
+  MMMMMMMMAGFGAAMM
+  MMMMMMMMMMMGAMMM
+  MMMMMMMFMMFFAMMM
+  MMMMMMMAFFAAMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 10 (cockatrice)
+{
+  MMMMMMMMMMMMMMMM
+  MMMDMDDMMMMMMMMM
+  MMMMDDMMMMMMMMMM
+  MMMMNLMMAAMMMMMM
+  MMHHANMAAAMMMMMM
+  MHHMNOMMAAAAMMMM
+  MMMAOOLFFFAAMMMM
+  MMMOOLKGGFFAAMMM
+  MMMAOAGGFGFFAAMM
+  MMMMMMMGFFGFAAMM
+  MMMMMMMMMFGGAAMM
+  MMMMMFAMMMFFAMMM
+  MMMMFAMMMMFFAMMM
+  MMMMFAMMFFFAMMMM
+  MMMMMFFFFAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 11 (pyrolisk)
+{
+  MMMMMMMMMMMMMMMM
+  MMMDMDDMMMMMMMMM
+  MMMMDDMMMMMMMMMM
+  MMMMNBMMAAMMMMMM
+  MMHHANMAAAMMMMMM
+  MHHMNBMMAAAAMMMM
+  MMMAPBBJJJAAMMMM
+  MMMPPPKDDKJAAMMM
+  MMMAPADDKDKJAAMM
+  MMMMMMMDJKDJAAMM
+  MMMMMMMMMJDDAAMM
+  MMMMMJAMMMJJAMMM
+  MMMMJAMMMMJJAMMM
+  MMMMKAMMKKKAMMMM
+  MMMMMJKKKAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 12 (jackal)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMOMMOMMMMMMMMM
+  MMMOMOOMMMOMMMMM
+  MMOOOOMMMMMOMMMM
+  MMIOIOOMMMMOMAMM
+  MOLLOOOLMMMOMAMM
+  DOOOAOOOOOOOAAMM
+  MMAAOOOOOOOOAAMM
+  MMMMOJOOOOOLAAMM
+  MMMMOJOLKALKAAMM
+  MMMOOAOAAAOAAMMM
+  MMMMMOOMMOOAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 13 (fox)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMCMMMMMMMMMMM
+  MMMMCMMMMMMMMMMM
+  MMCCACMMMCCCMMMM
+  MMACCCCCCACCCMMM
+  MMMAACCCCMACCMMM
+  MMMMACAACMMAAMMM
+  MMMACMACAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 14 (coyote)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMKMMKMMMMMMMMM
+  MMMKMKKMMMMMMKKK
+  MMKKKKMMMMMMKKKA
+  MMNCNKMKKKKKAAAM
+  MKCCKKKKKKKKKMMM
+  KKCKAKKKKKKKKMMM
+  DKKKAKAKKKKAKMMM
+  MMAAKAAKAAAAKMMM
+  MMMMAKAKAAAAKMMM
+  MMMAKKAKAMAKKMMM
+  MMMMMAKKMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 15 (werejackal)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMOMMOMMMMMMMMM
+  MMMOMOOMMMOMMMMM
+  MMOOOOMMMMMOMMMM
+  MMIOIOOMMMMOMAMM
+  MOLLOOOLMMMOMAMM
+  DOOOALLOOOOOAAMM
+  MMAALLLLOOOOAAMM
+  MMMMLJLLLOOLAAMM
+  MMMMLJLLKALKAAMM
+  MMLLLALAAAOAAMMM
+  MMMLMLLMMOOAMMMM
+  MMMMMMLMMMMMMMMM
+}
+# tile 16 (little dog)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMJMMJMMMMMMMMM
+  MMMJMJJMMMKMMMMM
+  MMJJJJMMMMMKMMMM
+  MMNJNKKMMMMKMAMM
+  MJJJCKKMMMMKMAMM
+  MPJJAKCKKCKKAAMM
+  MDDAACKKCKKKAAMM
+  MMMMKJKJCJKJAAMM
+  MMMMKJKJJAJJAAMM
+  MMMKKAKAAAKAAMMM
+  MMMMMKKMMMKAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 17 (dog)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMJMMJMMMMMKMMM
+  MMMJMJJMMMMMMKMM
+  MMJJJJMMMMMMMKMM
+  MMNJNKKMMMMMMKMA
+  MJJJCKKKKMMMMKMA
+  MPJCAKCKKKKCKKAA
+  MDDAACKKKKCKKKAA
+  MMAAKJKKJJCJKJAA
+  MMMMKJKKJJJAJJAA
+  MMMMKAKJAAAAKJAM
+  MMMKKAKAAAAAKAAM
+  MMMMMKKAAMMMKAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 18 (large dog)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMJMMJMMMMMKMMM
+  MMMJMJJMMMMMMKMM
+  MMJJJJMMMMMMMKMM
+  MMNJNKKKMMMMMKMA
+  MJJJCKKKKKMMJKMA
+  MPJCAKCKKKKCKKAA
+  MDDAACKKKKCKKKAA
+  MMAAKJKKJJCJKJAA
+  MMMJKJKKJJJAJJAA
+  MMMMKAKJAAAAKJAM
+  MMMMKAKJAAAAKJAM
+  MMMKKAKAAAAAKAAM
+  MMMMMKKAAMMMKAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 19 (dingo)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMCMM
+  MMMCMMCMMMMMMMCM
+  MMMCMCCMMMMMMMCA
+  MMCCCCKMMMMMMMCA
+  MMACACCKCCCCCCAA
+  MMLLCCCKCCCLCCCA
+  MKCCACKCLLLLACCA
+  MMAACAACLLAAACCA
+  MMMMACACAAAAAACA
+  MMMMCCACAAAMMCCA
+  MMMMMACCAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 20 (wolf)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMPMMPMMMMMPMMM
+  MMMPMPPMMMMMMPMM
+  MMPPPPMMMMMMMPMM
+  MMNMNPPMMMMMMPMA
+  MPMMPPPPPMMMMPMA
+  PPMPAPPPPPPPPPAA
+  DPPPAPPPPPPPPPAA
+  MMAAPMPPMMPMPMAA
+  MMMMPMPPMMMAMPAA
+  MMMMPAPMAAAAPMAM
+  MMMPPAPAAAAAPAAM
+  MMMMMPPAAMMPPAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 21 (werewolf)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMPMMPMMMMMPMMM
+  MMMPMPPMMMMMMPMM
+  MMPPPPMMMMMMMPMM
+  MMNMNPPMMMMMMPMA
+  MPMMPPPPPMMMMPMA
+  PPMPAPPPPPPPPPAA
+  DPPPALPPPPPPPPAA
+  MMAALLPLMMPMPMAA
+  MMMMLMLLMMMAMPAA
+  MMMMLALMAAAAPMAM
+  MMLLLALAAAAAPPAM
+  MMMLMLLAAMMPPMMM
+  MMMMMLLMMMMMMMMM
+}
+# tile 22 (warg)
+{
+  MMMMMMMMMMMMMMMM
+  MMMPMMPMMMMPPMMM
+  MMMPMPPMMMMMMPMM
+  MMPPPPMMMMMMMPMA
+  MMNMNPPMMMMMMPMA
+  MPMMPPPPPMMMMPMA
+  PPPPDPPPPPPPPPAA
+  DPPNDPPPPPPPPPAA
+  MMDDDPPPPPPPPPAA
+  PNDNPMPPPPPPPPAA
+  MPPPPAPPPPAPPMAM
+  MMMPAAPPAAAAPPAA
+  MMMPAAPMAAAAPMAM
+  MPPPAAPAAAAAPAAM
+  MMMMPPPAAMPPPAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 23 (winter wolf cub)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMMNMMMMMMMMM
+  MMMNMNBMMMNMMMMM
+  MMNNNNMMMMMNMMMM
+  MMDNDNBMMMMNMAMM
+  MMNNNNBMMMMNMAMM
+  MNNNNNNNNNNNAAMM
+  MDNBBNNNNNNBAAMM
+  MMMMNNNNNNNBAAMM
+  MMMMNNNBBANBAAMM
+  MMMNBANAAANAAMMM
+  MMMMMNBMMNBAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 24 (winter wolf)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMMNMMMMMNMMM
+  MMMNMNNMMMMMMNMM
+  MMNNNNMMMMMMMNMM
+  MMDODNNMMMMMMNMA
+  MNOONNNNNMMMMNMA
+  NNONANNNNNNNNNAA
+  DNNBANNNNNNNNNAA
+  MMAANNNNNNNBNNAA
+  MMMMNBNNNBBANNAA
+  MMMMNANBAAAANBAM
+  MMMNNANAAAAANAAM
+  MMMMMNNAAMMNNAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 25 (hell hound pup)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMCMMCMMMMMMMMM
+  MMMCMCCMMMCMMMMM
+  MMCCCCMMMMMCMMMM
+  MMDCDCCMMMMCMAMM
+  MCCCCCCMMMMCMAMM
+  MPCCACCCCCCCAAMM
+  MCHAACCCCCCCAAMM
+  CHCMCCCCCCCCAAMM
+  MDMMCCCCCACCAAMM
+  MMMCCACAAACAAMMM
+  MMMMMCCMMMCAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 26 (hell hound)
+{
+  MMMMMMMMMMMMMMMM
+  MMMCMMCMMMMCCMMM
+  MMMCMCCMMMMMMCMM
+  MMCCCCMMMMMMMCMA
+  MMDJDCCMMMMMMCMA
+  MCCCCCCCCMMMMCMA
+  CCCCDCCCCCCCCCAA
+  MCHCMCCCCCCCCCAA
+  CHCMMCCCCCCCCCAA
+  MDMMCCCCCCCCCCAA
+  MMMCCACCCCACCMAM
+  MMMCAACCAAAACCAA
+  MMMCAACMAAAACMAM
+  MCCCAACAAAAACAAM
+  MMMMCCCAAMCCCAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 27 (Cerberus)
+{
+  MMMMMMMMMMMMMMMM
+  MMJMMJMMMMMMMMMM
+  MMJJJJMJMMJMMMMM
+  MNJNJMMJMJJMMMMM
+  JJJJKAJJJJMMMMJM
+  PJJJJANJNKKMMMJM
+  DJKJAJJJKJJKMMJM
+  MMAAJPJKAJKJKJJM
+  MMJJJDDAJKJJJJJA
+  MMJJJAAJJJJJJJJA
+  MJKKKJJJKJJKJJAA
+  MJJAAKJJKJJJKJAA
+  JJAAAAJJAAAAJJAM
+  JAAAAAJAAAAAJAAM
+  MMMMMJJAAMMMJAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 28 (gas spore)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPFGGFPMMMMM
+  MMMMPGFFFFFPMMMM
+  MMMPFFFFFGGFPMMM
+  MMMFFGGFFGGFFMMM
+  MMMGFGGFFFFFGMMM
+  MMMGFFFFFFFFGMMM
+  MMMFFFFGGFFFFMMM
+  MMMPGGFGGFGGPMMM
+  MMMMPGFFFFGPMMMM
+  MMMMMPFGGFPMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 29 (floating eye)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMONNNOMMMMM
+  MMMMPNNNNNNNPMMM
+  MMMMNNNNNNNNNMMM
+  MMMONNBBBBNNNOMM
+  MMMNNBBEEBBNNNMM
+  MMMNNBEAAEBNNNMM
+  MMMONBEAAEBNNOMM
+  MMMMNBBEEBBNNMMM
+  MMMMPNBBBBNNPAAM
+  MMMMMMONNNOAAAAM
+  MMMMMMAAAAAAAAAM
+  MMMMMMMAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 30 (freezing sphere)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMPBBBPMMMMM
+  MMMMPBBBBBBBPMMM
+  MMMMBBBBBBBBBMMM
+  MMMPBPPPBBBBBPMM
+  MMMBBNNBBPPPBBMM
+  MMMBBANPBNNBBBMM
+  MMMPBBPPBANPBPMM
+  MMMMBBBBBBPPBMMM
+  MMMMPBBBBBBBPAAM
+  MMMMMMPBBBPAAAAM
+  MMMMMMAAAAAAAAAM
+  MMMMMMMAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 31 (flaming sphere)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMCMMMHMMMMMMM
+  MMMMCMMMMOMMMCMM
+  MMMCMMHMCCMMMCMM
+  MMMCMMCMCCMMCCMM
+  MMMDCAMDDCMACCMM
+  MAHCDCADDCAADCMM
+  MAACDCDDDDDADDMM
+  MMACDDDJJJDDDDMM
+  MMADDCAKDDACDDMM
+  MMMADAKDDCDADMMM
+  MMMADADHCHCADMMM
+  MMMMDADDDCDADMMM
+  MMMMMDADDDADMMMM
+  MMMMMMJJJJJMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 32 (shocking sphere)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMPPPPPPMMMMM
+  MMMPPIAAADAPPMMM
+  MMPAAAIAAADDAPMM
+  MMPHAAAPBOAAAPMM
+  MPAHHAPBBBOAAAPM
+  MPHAAAPBBBBAHHPM
+  MPAAAAPPBBBAAAPM
+  MPAAAIAPPPAAAIPM
+  MPIIIAAAAAAIIAPM
+  MMPIAANAAPAAAIPM
+  MMPIAANAAAPAAPMM
+  MMMPANANAPAPAPMM
+  MMMMPPAIAPAPPMMM
+  MMMMMMPPPPPMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 33 (beholder)
+{
+  MMMMOAMMOAMMMMMM
+  MMOAMDADAMOAMOAM
+  MMMDAMDADADADDMM
+  MMOADDOOOODDADOM
+  MMMDDHOAAOHDDAMM
+  MMMJDHOAAOHDDJMM
+  MMMDDDOOOODDDDMM
+  MMMDDDDDDDDDDDMM
+  MMMJDAOAAAOADJMM
+  MMMMDDAAOAADDMMM
+  MMMMPDDDDDDDPAAM
+  MMMMMMJDDDJAAAAM
+  MMMMMMAAAAAAAAAM
+  MMMMMMMAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 34 (kitten)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMKMMMM
+  MMMMMMMMMMMMCMMM
+  MMMMCMCMMMMMLMAM
+  MMMCCCCJMMMMCMAM
+  MMMNCNCJCCLCLMAM
+  MMMCCCCJCCLCCAAM
+  MMMMIACCLLCCCAAM
+  MMMMMCACCJCCJAMM
+  MMMMMMCCAMMCAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 35 (housecat)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMKMMMM
+  MMMMMMMMMMMMCMMM
+  MMMCMCMMMMMMLMAM
+  MMCCCCJMMMMMCMAM
+  MCNCNCJCLCLCLMAM
+  MCCCCCJCLCLCCAAM
+  MMCICJCCLCLCLAAM
+  MMMAACCLCLCCCAAM
+  MMMCCACCJJCCJAMM
+  MMMMMCCAMMMCAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 36 (jaguar)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMCMMCMMMMMMCMMM
+  MMCCMCJMMMMMMCMA
+  MCCCCCJMMMMMMCMA
+  MGCGCCJCAACCJCMA
+  MCCCCCJCCCCCCCAA
+  MCDDDJCAACCAJCAA
+  MMCCACCAJCCAACAA
+  MMMMCACCJJJCCJAM
+  MMMMCACAAAAACJAM
+  MMMCKACAAAAACAAM
+  MMMMMCCAAMMMCAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 37 (lynx)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  OMMMMOMMMMMMMMMM
+  ACMCCAMMMMMMMMMM
+  MCCCAMMMMMMMMCAM
+  MGCGCOAKKKKKMLAM
+  MCKCCAJCCCCCKAMM
+  LLDDLLACLLLCCAAM
+  MMCCMAACLLLCCAAM
+  MMMMMMMCAAAACAAM
+  MMMMCACAAAACCAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 38 (panther)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMAAMM
+  MMMMMMMMMMMMMMAM
+  MMMMMMMMMMMMMMAM
+  MAMMMAMMMMMMMMAM
+  MEAMAEMMMMMMMMAM
+  MAAAAAEAAAAAAAMM
+  MAAAAAEAAAAAAAMM
+  MHAHAAMAAAAAAAAM
+  MAAAAMAAAAAEAAAM
+  MAAAMMAAAAAEAAAM
+  MMMMMAAMMMMAAAMM
+  MMAAAAMMAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 39 (large cat)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMKMMM
+  MMMMMMMMMMMMMCMM
+  MMMCMCMMMMMMMLMA
+  MMCCCCJMMMMMMCMA
+  MCNCNCJCLCCLCLMA
+  MCCCCCJCLCCLCCAA
+  MMCDCJCCLCCLCLAA
+  MMMAACCLCCLCCCAA
+  MMMMCACCJJJCCJAM
+  MMMCKALAAAAACAAM
+  MMMMMCCAAMMMCAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 40 (tiger)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMCMMCMMMMMMCMMM
+  MCCJCCMMMMMMMCMA
+  MCAACCJMMMMMMAMA
+  MGAGCCJACACAJCMA
+  MCCCCCACACACACAA
+  MODOCACCACACACAA
+  MOCOACCJACACACAA
+  MMMMCACJAJAJCAAM
+  MMMMAACAAAAAAJAM
+  MMMCKACAAAAACAAM
+  MMMMMCCAAMMCCAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 41 (gremlin)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  GGGAMMMMAGGGMMMM
+  MGGGFAAAGGGMMMMM
+  MMFFFFFFFFMMMMMM
+  MMMNDFFDNAMMMMMM
+  MMMGNFFNGAMMMMMM
+  MMMGFFFFGAMMAAMM
+  MMMAGFFFAFAAAAAM
+  MMGFAGFAFFFAAAAM
+  MGFGFAAFFAFAAAAM
+  MGFMGFAGAAFAAAAM
+  MMMMFFAGFAAMAAMM
+  MMMGFAMFGAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 42 (gargoyle)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMPAPPPPAPMMMMM
+  MMPAMMMMMMAPMMMM
+  MMPMDDMMDDAPMMMM
+  MMMMPDMMDPAMMMMM
+  MMMMPMMMMPAMMAAM
+  MMMMAPMMMAMAAAAA
+  MMMPMAPMAMMMAAAA
+  MMPMPMAAMMAMAAAA
+  MMPAMPMAPAAMAAAA
+  MMPAMPMMMMAMAAMM
+  MMMMMPMMMMAAAAMM
+  MMMMMPMAPMAAMMMM
+  MMMMPFAMFPAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 43 (winged gargoyle)
+{
+  MMMKMMMMMMKMMMMM
+  MMMKJMMMMKJMMMMM
+  MMKJAPPPPAJJMMMM
+  MMKJMMMMMMAJMMMM
+  MMKJDDMMDDAJMMMM
+  MKJAPDMMDPAJJMMM
+  MKJAPMMMMPAAJAAM
+  KJAMAPMMMAMAJJAA
+  JMMPMAPMAMMMAJAA
+  MMPMPMAAMMAMAAAA
+  MMPAMPMAPAAMAAAA
+  MMPAMPMMMMAMAAMM
+  MMMMMPMMMMAAAAMM
+  MMMMMPMAPMAAMMMM
+  MMMMPFAMFPAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 44 (hobbit)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMJJAMMMMMMM
+  MMMMMJJJJAMMMMMM
+  MMMMJLFLFJMMMMMM
+  MMMMJLLLLJMMMMMM
+  MMMMJKLLKJJMAAMM
+  MMMCLLLLLLCAAAMM
+  MMCLALLLLALCAMMM
+  MMLLAJJKJALLAMMM
+  MMMLMLKJLALAAMMM
+  MMMMMLLALLAMAMMM
+  MMMMLLLMLLLMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 45 (dwarf)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMBMMMMMMMMM
+  MMMMMBEEMMMMMMMM
+  MMMMBBEEEMMMMMMM
+  MMMMBLLLEMMMMMMM
+  MMMMMOLOMMMAAAMM
+  MMMBBOOOEEAAAAMM
+  MMMBABOEAEAAAAMM
+  MMMMLBBELAAAAMMM
+  MMMMEBAEEAAMMMMM
+  MMMMBEAEBMAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 46 (bugbear)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMKMMMMMMMMM
+  MKMMKKKMMMMMMMMM
+  MKKKKKKMMMMMMMMM
+  KADKADKKKMMMMMMM
+  KKKKKKKJKKMMMMMM
+  KAPAPAKJJKJMMMMM
+  KAAAAAKKJKJJMMMM
+  MKKKKKJKAKKJMMMM
+  MMKAJJCAKKKJMAAM
+  MMKKMKKKKKJJAAMM
+  MMMCMMKJAKJAAMMM
+  MMMMMCCAAKJAMMMM
+  MMMMMMMMCCAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 47 (dwarf lord)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMBMMMMMMMMM
+  MMMMMBEEMMMMMMMM
+  MMMMHHHHHMMMMMMM
+  MMMMBLLLEMMMMMMM
+  MMMMBOLOEMMAAAMM
+  MMMBBOOOEEAAAAMM
+  MMMBABOEAEAAAAMM
+  MMMMLBBELAAAAMMM
+  MMMMEBAEEAAMMMMM
+  MMMMBEAEBMAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 48 (dwarf king)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMHMCMHMMMMMMM
+  MMMMHCHCHMMMMMMM
+  MMMMHHHHHMMMMMMM
+  MMMMBLLLEMMMAMMM
+  MMMMMOLOMMMAAAAM
+  MMMEBOOOEEAAAAMM
+  MMMBABOEAEAAAAMM
+  MMMMLBBELAAAAMMM
+  MMMMEBAEEAAMMMMM
+  MMMMBEAEBMAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 49 (mind flayer)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMIIIICMMMM
+  MMMMMIIIIIICMMMM
+  MMMMIIIIIIICMMMM
+  MMMIGIIIIGCMMMMM
+  MMMIIGINGICMMMMM
+  MMMMIIIIICMMMMMM
+  MMMMIAIAIFMMMMMM
+  MMMMIAIAIFMMMMMM
+  MMMMIAIAIFIMMMMM
+  MMMMMFIFIFICMAAM
+  MMMMCBIBBFMCAAAM
+  MMMIIIBBFFACAAAM
+  MMMMMMBBFCAAAAMM
+  MMMMMMCFFCAAMMMM
+  MMMMIICMIIAMMMMM
+}
+# tile 50 (master mind flayer)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMIIIICMMMM
+  MMMMMIIIIIICMMMM
+  MMMMIIIIIIICMMMM
+  MMMIGIIIIGCMMMMM
+  MMMIIGINGICMMMMM
+  MEEEIIIIICEEEEMM
+  MMEEIAIAIEEEEMMM
+  MMMEIAIAIEEEMMMM
+  MMMMIAIAIEEEMMMM
+  MMMMEFIFIEEEMAAM
+  MMMMCBIBBEEEAAAM
+  MMMIIIBBEEEEAAAM
+  MMMMEEBEEEEAAAMM
+  MMMEEECEEEAAMMMM
+  MMMMIICMIIAMMMMM
+}
+# tile 51 (manes)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPPMMMMMMMMMM
+  MMMPPPPMMMMMMMMM
+  MMPAPAPMMMMMMMMM
+  MMPPPPPMPPPMPMMM
+  MMPMMPPPPMMMMMMM
+  MMPMMPPPPPMMMPMM
+  MMPPPPPMPPPMMMMM
+  MMPMPMPMPPMPMMMM
+  MPMMMPMPPPPMMMMM
+  MPMMMMPPPMPPMMMM
+  MMPMMMMPMPMPMPMM
+  MMMMMMMMPMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 52 (homunculus)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMJJJMMMMMMM
+  MMMMMMLLCMMMMMMM
+  MMMMMMLLCMMMMMMM
+  MMMMMBBPPPAAMMMM
+  MMMMLMBPPACAAMMM
+  MMMMMMBAPAAAAMMM
+  MMMMMLLALCAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 53 (imp)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOMDMOMMMMMM
+  MMMMMOCDDOMMMMMM
+  MMMMMMCDDMMMMMMM
+  MMMMMGGFFFAAMMMM
+  MMMMCMGFFADAAMMM
+  MMMMMMGAFAAAAMMM
+  MMMMMCDADDAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 54 (lemure)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPPMMMMMMMMMM
+  MMMPPPPMMMMMMMMM
+  MMPAPAPMMMMPMMMM
+  MMPPPPPMMPPMPMMM
+  MMPMMPPPPPPPPMMM
+  MMPMMPPPPPPPMMMM
+  MMPPPPPPPPPMMMMM
+  MMMMPPPPPPPPMMMM
+  MMPPPPPPPPPPMMMM
+  MMMPPPPPPPPPPMMM
+  MMPMPMMPPPPMPPMM
+  MMMMMMMMPMPPMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 55 (quasit)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOMDMOMMMMMM
+  MMMMMOCDDODMMMMM
+  MMMMMMCDDMDMMMMM
+  MMMMMGGFFFAAMMMM
+  MMMMCMGFFAAADAMM
+  MMMMCMGFFJJDAMMM
+  MMMMMMGAFAAAAMMM
+  MMMMMCDADDAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 56 (tengu)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPPMMMMMMM
+  MMMMMMPPPPMMMMMM
+  MMMMMDPPNPMMMMMM
+  MMMMDDDPPPMMMMMM
+  MMMMDDPPPPMMMMMM
+  MMMMDMMPPAMMMMMM
+  MMMMMPIAAIPMAAAM
+  MMMMPPPIIPPPAAAM
+  MMMMPAPPPPAPAAAM
+  MMMMPAHHHHAPAAAM
+  MMMMLAPPPPALAAAM
+  MMMMMMPPPPAAAAMM
+  MMMMMMPPPPAAMAMM
+  MMMMMLLAMLLAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 57 (blue jelly)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMEMMMMMMMM
+  MMMMMMOBEMMMMMMM
+  MMMBEMOBEBOEMMMM
+  MMOBEOBBEOBBEMMM
+  MMOBEOBBEOBBEMMM
+  MMBBBGGBGGBEEEMM
+  MMBBBAGBAGEEEEAM
+  MMBBBBBBEBEEEEAA
+  MMMBBBBBBBEEEAAA
+  MMMMBBBBBEEEAAAM
+  MMMMMMBBBEEAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 58 (spotted jelly)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMEMMMMMMMM
+  MMMMMMOBEMMMMMMM
+  MMMBEMOCEBOEMMMM
+  MMOCEOCCEOBCEMMM
+  MMOCEOBCEOCBDMMM
+  MMBBBHHBHHBEDDMM
+  MMCCBAHBAHEEEEAM
+  MMBBCBBBEBEEDEAA
+  MMMBBBCBBBEEDAAA
+  MMMMBCCCBEEDAAAM
+  MMMMMMCCBEEAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 59 (ochre jelly)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMDMMMMMMMM
+  MMMMMMLCDMMMMMMM
+  MMMCDMLCDCLDMMMM
+  MMLCDLCCDLCCDMMM
+  MMLCDLCCDLCCDMMM
+  MMCCCGGCGGCDDDMM
+  MMCCCAGCAGDDDDAM
+  MMCCCCCCDCDDDDAA
+  MMMCCCCCCCDDDAAA
+  MMMMCCCCCDDDAAAM
+  MMMMMMCCCDDAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 60 (kobold)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMMMNMMMMMMMM
+  MMMNBPBNMMMMMMMM
+  MMMBABABMMMMMMMM
+  MMMMBBPAMMAMMMMM
+  MMMBBABPAMAAMAMM
+  MMBPBBBBPAAAAAMM
+  MMBAPBPAPAAAAAMM
+  MMMMPBPAAAAAAMMM
+  MMMMBABAAAAMMMMM
+  MMMBBABBAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 61 (large kobold)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMMMNMMMMMMMM
+  MMMNBPBNMMMMMMMM
+  MMMBABABMMMMMMMM
+  MMMMBBPAMMAMMMMM
+  MMMBBABPAMAAMMMM
+  MMBPBBBBPAAAMAMM
+  MMBAPBPAPAAAAAMM
+  MMBAPBPAPAAAAAMM
+  MMMMPBPAAAAAAMMM
+  MMMMBABAAAAMMMMM
+  MMMBBABBAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 62 (kobold lord)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMMMNMMMMMMMM
+  MMMNCCCNMMMMMMMM
+  MMMCABACMMMMMMMM
+  MMMCBBPCMMAMMMMM
+  MMCCBABCCMAAMMMM
+  MMCCBBBCCAAAMAMM
+  MMBCCBCCPAAAAAMM
+  MMBACBCAPAAAAAMM
+  MMMMBBBAAAAAAMMM
+  MMMMBABAAAAMMMMM
+  MMMBBABBAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 63 (kobold shaman)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMMMNMMMMMMMM
+  MMMNHHHNMMMMMMMM
+  MMMHABAHMMMMMMMM
+  MMMHBBPHMMAMMMMM
+  MMHHBABHHMAAMMMM
+  MHHHBBBHHHAAMAMM
+  MHBHHBHHPHAAAAMM
+  MMBAHBHAPAAAAAMM
+  MMMMBBBAAAAAAMMM
+  MMMMBABAAAAMMMMM
+  MMMBBABBAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 64 (leprechaun)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMGMMMMMMMMM
+  MMMMMMFMMMMKMMMM
+  MMMMMGFFMMKLKMMM
+  MMMMGFFFFMMKMMMM
+  MMMMMKLKAMGLAAMM
+  MMMFGFJFFFAKAMAM
+  MMMGAGFFAAAKMAAM
+  MMMMLKHKKJAKAAMM
+  MMMMGFAGKJAKAMMM
+  MMMGFAAMGFAKMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 65 (small mimic)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMPOPMMMMMMM
+  MMMMMMNNOMMMMMMM
+  MMMMMMNNOMMMMMMM
+  MMMMMMMOAMMMMMMM
+  MMMMMNNNNNMMAAMM
+  MMMMOONNNOOMAAMM
+  MMMMNANOOANAAAMM
+  MMMMMMNAOAAAAMMM
+  MMMMMMNAOAAMAMMM
+  MMMMMNNMOOAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 66 (large mimic)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMLLOAMMMMMM
+  MMMMMMNNOAMMMMMM
+  MMMMMMNNOAMMMMMM
+  MMMMMMONOAMMMMMM
+  MMMMMNNNNOMMAAAM
+  MMMMOONNNOOMAAAM
+  MMMNOANNNAOOAAAM
+  MMMNAONONOANAAAM
+  MMMMMNOMNOAAAAMM
+  MMMMMNOMNOAAMAMM
+  MMMMNNOMNOOAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 67 (giant mimic)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMNNOMMMMMMM
+  MMMMMNNNNOAMMMMM
+  MMMMMNNNNOAMMMMM
+  MMMMMNNNNOAMMMMM
+  MMMMMONNNOAMMMMM
+  MMPONNOOONOOPAAA
+  MPONONNNNOONOPAA
+  MONOANNNNOAONOAA
+  MNNOANNNNOAOOOAA
+  MMMAANNONNAAAAAA
+  MMMMPNOMNNPAAAAA
+  MMMMONOMNNOAAMMA
+  MMMMNNOMNNOAAMMA
+  MMMNNNOMNNOOAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 68 (wood nymph)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMOHMMMMMMMMMMM
+  MMOHHLMMMMMMMMMM
+  MMOHLLMMMMMMMMMM
+  MMHHLAMMMMMMMMMM
+  MOHLLFKKKKLAMMMM
+  MHKFLFKKKKAMMMMM
+  OHKJFKKJJKMAMMMM
+  HKKLJJGKAAAAAAAM
+  MJJAJGDKJAAAAAMM
+  MMJAMKKJJAAAAMMM
+  MMMJMKKKKJAAMMMM
+  MMMMJKKKKKJAMMMM
+  MMMMKJKJKJKJMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 69 (water nymph)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMOHMMMMMMMMMMM
+  MMOHHLMMMMMMMMMM
+  MMOHLLMMMMMMMMMM
+  MMHHLAMMMMMMMMMM
+  MOHLLJBBBBLAMMMM
+  MHBJLJBBBBAMMMMM
+  OHBPJBBPPBMAMMMM
+  HBBLPPNBAAAAAAAM
+  MPPAPNDBMAAAAAMM
+  MMPAMBBPPAAAAMMM
+  MMMPMBBBBPAAMMMM
+  MMMMPBBBBBPAMMMM
+  MMMMBPBPBPBPMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 70 (mountain nymph)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMOHMMMMMMMMMMM
+  MMOHHLMMMMMMMMMM
+  MMOHLLMMMMMMMMMM
+  MMHHLAMMMMMMMMMM
+  MOHLLCOOOOLAMMMM
+  MHOCLCOOOOAMMMMM
+  OHOLCOOLLOMAMMMM
+  HOOKLLIOAAAAAAAM
+  MLLALIBOKAAAAAMM
+  MMLAMOOLLAAAAMMM
+  MMMLMOOOOLAAMMMM
+  MMMMLOOOOOLAMMMM
+  MMMMOLOLOLOLMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 71 (goblin)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMLKMMMMMMMMMM
+  MMMCJAMMMMMMMMMM
+  MMKJAMMMMMMMMMMM
+  MJJAMIIKMMMAAMMM
+  MIKMIGIGIJAAMMMM
+  JMICKIIIJKMMMMMM
+  MMMIIJJJKMAMMMMM
+  MMMMKICJAAAAAMMM
+  MMMMICKKJAMMMMMM
+  MMMMIKAIJAMMMMMM
+  MMMIKAAMIKMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 72 (hobgoblin)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMLKMMMMMMMMM
+  MMMMCKAMMMMMMMMM
+  MMMCJAMMMMMMMMMM
+  MMKJAMMMMMMMMMMM
+  MJJAMIIKMMMAAMMM
+  MIKMIHIHIJAAMMMM
+  JMICKIIIJKMMMMMM
+  MMMIIJJJKMAMMMMM
+  MMMMKICCAAAAAMMM
+  MMMMIIIIJAMMMMMM
+  MMMMICKKJAMMMMMM
+  MMMMIKAIJAMMMMMM
+  MMMIKAAMIKMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 73 (orc)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOAMMMMMMMMM
+  MMMMNOPAMMMMMMMM
+  MMMMLPLAMMMMMMMM
+  MMMMMPMAMMMMMMMM
+  MMKCCAKKKAMAAMMM
+  MMBPCKJMPMAAAMMM
+  MMBAGGFAAPNOMMMM
+  MMBAJJPNOAAAMMMM
+  MMMMBNOJAAAAAAMM
+  MMMBJACPAAAAMMMM
+  MMBPPABPPAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 74 (hill orc)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOAMMMMMMMMM
+  MMMMNOPAMMMMMMMM
+  MMMMLKLAMMMMMMMM
+  MMMMMKMAMMMMMMMM
+  MMKGGAFFKAMAAMMM
+  MMJKGFFMKMAAAMMM
+  MMJAHHFAAKNOMMMM
+  MMJAGFFNOAAAMMMM
+  MMMMGNNFAAAAAAMM
+  MMMGGAGFAAAAMMMM
+  MMKJJAKJJAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 75 (Mordor orc)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOAMMMMMMMMM
+  MMMMNOPAMMMMMMMM
+  MMMMLPLAMMMMMMMM
+  MMMMMPMAMMMMMMMM
+  MMKIIAIIKAMAAMMM
+  MMBPIDDMPMAAAMMM
+  MMBAGGFAAPMOMMMM
+  MMBAIDDNOAAAMMMM
+  MMMMBNOJAAAAAAMM
+  MMMBIAIPAAAAMMMM
+  MMBPPABPPAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 76 (Uruk-hai)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOAMMMMMMMMM
+  MMMMNOPAMMMMMMMM
+  MMMMLPLAMMMMMMMM
+  MMMMMPMAMMMMMMMM
+  MMIIIAIIIAMMMMMM
+  MMBPIKIMBAAAAMMM
+  MMBIGMPPPPAAAMMM
+  MNBADMPDDPAAMMMM
+  MMBNNJPDDPAAMMMM
+  MMMMINPPPPAAAAMM
+  MMMBIAKMAAAAMMMM
+  MMBPPABPPAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 77 (orc shaman)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOAMMMMMMMMM
+  MMMMNOPAMMMMMMMM
+  MMMMLPLAMMMMMMMM
+  MMMMMPMAMMMMMMMM
+  MMCCCACCCAMMMMMM
+  MMBPCKCMBAAAAMMM
+  MMBCGGFJBAAAAMMM
+  MMBAJJCJBAAAMMMM
+  MMBAJJCJBAAAMMMM
+  MMMMCACJAAAAAAMM
+  MMMBCACPAAAAMMMM
+  MMBPPABPPAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 78 (orc-captain)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOAMMMMMMMMM
+  MMMNNOOPAMMMMMMM
+  MMMMLPLAMMMMMMMM
+  MMMIPPPAMMMMMMMM
+  MMDIIPADDAMAAMMM
+  MMBPIADMPMAAAMMM
+  MMBAGGFAAPMOMMMM
+  MMBAGGFAAPMOMMMM
+  MMBAJJPNOAAAMMMM
+  MMMMBNOJAAAAAAMM
+  MMMBDAIPAAAAMMMM
+  MMBPPABPPAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 79 (rock piercer)
+{
+  MJKKKKKKKKJAAAMM
+  MMJJGKGKJJAAAAMM
+  MMMJKKKJJAAAAMMM
+  MMMJJKKJJAAAAMMM
+  MMMMJKKJAAAAMMMM
+  MMMMJJKJMAAAMMMM
+  MMMMJJKJMAAAMMMM
+  MMMMJJJJMMAMMMMM
+  MMMMMJJMMMAMMMMM
+  MMMMMJJMMMAMMMMM
+  MMMMMJJMMMMMMMMM
+  MMMMMJJMMMMMMMMM
+  MMMMMJMMMMMMMMMM
+  MMMMMJMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 80 (iron piercer)
+{
+  MBPPPPPPPPMAAAMM
+  MMBBDPDPMMAAAAMM
+  MMMBPPPMMAAAAMMM
+  MMMPBPPMMAAAAMMM
+  MMMMBPPMAAAAMMMM
+  MMMMBBPMAAAAMMMM
+  MMMMPBPMAAAAMMMM
+  MMMMPBPMMMAMMMMM
+  MMMMMBPMMMAMMMMM
+  MMMMMBPMMMAMMMMM
+  MMMMMBPMMMMMMMMM
+  MMMMMBPMMMMMMMMM
+  MMMMMBMMMMMMMMMM
+  MMMMMPMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 81 (glass piercer)
+{
+  MNBBBBBBBBPAAAMM
+  MMNNDBDBPPAAAAMM
+  MMMNBBBPPAAAAMMM
+  MMMPNBBPPAAAAMMM
+  MMMMNBBPAAAAMMMM
+  MMMMNNBPAAAAMMMM
+  MMMMPNBPAAAAMMMM
+  MMMMPNBPMMAMMMMM
+  MMMMMNBMMMAMMMMM
+  MMMMMNBMMMAMMMMM
+  MMMMMNBMMMMMMMMM
+  MMMMMNBMMMMMMMMM
+  MMMMMNMMMMMMMMMM
+  MMMMMPMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 82 (rothe)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMKMMMM
+  MMMMMMMMMMMMKMMM
+  MMMMMMMMMMMMKMMM
+  MMMMMMMJJJKKJMMM
+  MMMMMJKKKKKKKMMM
+  MMAAAKKKKKKKKMMM
+  MAAAAAKKKKKKKAMM
+  AAKKAAKKKKKAKAMM
+  MKEKKAKKKJAAKAMM
+  MKKKJAKKAJAAKMMM
+  MMKJAAAKAAAMMMMM
+  MMAAKAMKAMMMMMMM
+  MMAMMAMKMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 83 (mumak)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMPMMMM
+  MPPMMMMMMMMMPMMM
+  PPPMMMPPPPPMPMMM
+  PPPPPPPPPMPPMMMM
+  PPPPBPPBBPMPPMMM
+  PPPBPPPPPPMPPMMM
+  MPDPPDDPPMPPPMMM
+  MMBPPDDPMPPPPAMM
+  MMPPPPPPPPPPPAMM
+  MMPPPPOMMPAPPAMM
+  MOOPPOOAPPAPPAMM
+  OOPPOOAAPPAMMMMM
+  MPPPAPAMPPMMMMMM
+  PPPAMMMMMMMMMMMM
+  MAAMMMMMMMMMMMMM
+}
+# tile 84 (leocrotta)
+{
+  MMMMMMMMMMMMMMMM
+  MMAMMAMMMMMMMMMM
+  MMAOOAMMMMJMMMMM
+  MMAOOAAMMMMJMMMM
+  MAPOAFAMMMMJMMMM
+  MAPOAAAMJJJJMMMM
+  MAOPAAJKKKKKJMMM
+  MAOAAKJJKKJKJAMM
+  MMMJKKKKKJAKKAMM
+  MMMJKJKKJAAKKAMM
+  MMJKJAKKAAPAPAMM
+  MMKKAAKKAAPAPAMM
+  MPAPAAPAPAMMMMMM
+  MPAPAMPAPAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 85 (wumpus)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMBMMM
+  MMMMMMMMMMMMMBMM
+  MMMMMMMBBBBBMBMM
+  MMMMBBBPPBBBBMMM
+  MMMBOOBBBPBBBBMM
+  MMMOOBBBBBPBBBMM
+  MMDABBAABBPBBBAM
+  MBOOBBDABEBBEBAA
+  MBOBBBBBBEBEBBAA
+  MBBBBBBBEBBABBAA
+  MEBBBBBEABBABBAA
+  MMEEEEEAABBAMMMM
+  MMMMMBBAMBBMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 86 (titanothere)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMPPPMPM
+  MMMMMMMPPPPPPPAP
+  MMMMMPPPPPPPPPMA
+  MMPMPMPPPPPPPPMA
+  MMPPPMPPPPPPPPPA
+  MMPPPPMPPPPPPPPA
+  MPPPPPMPPPPPPPMM
+  MPPEPPMPPPPMPPAM
+  PBPPPMPPPMAAPPAM
+  PPPPMAAPPAAMMMMM
+  MPPMPPAPPAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 87 (baluchitherium)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMPPPMPM
+  MMMMMMMPPPPPPPAP
+  MMMMMPPPPPPPPPMA
+  MMPMPMPPPPPPPPMA
+  MMPPPMPPPPPPPPPA
+  MMPPPPMPPPPPPPPA
+  BPPPPPMPPPPPPPMM
+  BMPEPPMPPPPMPPAM
+  PBMPPMPPPMAAPPAM
+  PPPPMAAPPAAMMMMM
+  MPPMPPAPPAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 88 (mastodon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMOMMMOMMMMMMMMM
+  MNMMPOPMPMMMMMMM
+  NMMPNPPPPPMMMMMM
+  OMPNPPPPPPMPPMMM
+  OMPOPEPPPMPPPPPM
+  MOPOPOPMMPPPPPAP
+  MMPPOPPMPPPPPPAA
+  MMPPAAAPPPPAPPAM
+  MMPMMMAPPAAAPPAM
+  MMMMMMMPPAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 89 (sewer rat)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMKMMKMJKKKKMMMM
+  MMKKKKJKKJKKKMMM
+  MMJAKAKJJJKKKJMM
+  MMGKGKJKAKKAKKAM
+  MKKJJJJKAKAAKKAM
+  MPJJAAKKAJAJKAMM
+  MMAAMKKAMMJKAMMM
+  MMMMMMMMMJJAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 90 (giant rat)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMKMMKMJKKKKKMMM
+  MMKKKKJKKKJKKKMM
+  MMJAKAKJKJJKKKJM
+  MMGAGAKJKJJKKKKM
+  MMAKAKJKKAKKAKKA
+  MKKJJJJKAJKAAKKA
+  MPJJAAKKAJJAJKAM
+  MMAAMKKAAMMJKAMM
+  MMMMMMMMMMJJAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 91 (rabid rat)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMKMMKMJKKKKKMMM
+  MMKKKKJKKKJKKKMM
+  MMJAKAKJKJJKKKJM
+  MMGAGAKJKJJKKKKM
+  MMAKAKJKKAKKAKKA
+  MKKJOOOKAJKAAKKA
+  MPJOOAKKAJJAJKAM
+  MMAOOOKAAMMJKAMM
+  MOOOOOOOOMJJAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 92 (wererat)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMKMMKMJKKKKKMMM
+  MMKKKKJKKKJKKKMM
+  MMLLLLKJKJJKKKJM
+  MMFLFLLJKJJKKKKM
+  MMLLLLJKKAKKAKKA
+  MKKJJJJKAJKAAKKA
+  MPJJAAKKAJJAJKAM
+  MMAAMKKAAMMJKAMM
+  MMMMMMMMMMJJAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 93 (rock mole)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMAAAAAMMMM
+  MMMAAAAAAAAAAMMM
+  MMAAAAAAAAAAAAMM
+  MMJAJAAAAAAAAAAM
+  MAAAAAAAAAAAAAAM
+  ANMNAAAAAAAAAAAM
+  AMMMAAAAMMMAAAMM
+  ANMNAAMAAMMMAAMM
+  MAAAAMMMMMMMMMMM
+}
+# tile 94 (woodchuck)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMKJAMMMMMM
+  MMMMMMNKKNAMMMMM
+  MMMMMMKNOJAMMMMM
+  MMMMMMKNOJAMMMMM
+  MMMMMKKKKKJAMMMM
+  MMMMJJKLLJJJAAMM
+  MMMMMMKLLJAAAAAM
+  MMMMMMKJJJAAAAMM
+  MMMMMJJAAJJAAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 95 (cave spider)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMPAMMMMMM
+  MMMMMMMPAMMMMMMM
+  MMMMMMPAPBBAMMMM
+  MMMPAMAPBPPPAMMM
+  MMMABBPPAPPAAMPA
+  MMMGPPPPAAAPPPAA
+  MMMPPGPAAPPAAAAM
+  MMDMPAPAPAAPPAMM
+  MMMMDMPAAPAMAPAM
+  MMMMMPAAMAPAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 96 (centipede)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMPBPPMMMMMM
+  MMMMBBPAAAMMMMMM
+  MMPPBAAAMMMMMMMM
+  MPAPBBBPPPPMMMMM
+  MMPAAPPBBBAMMMMM
+  MMMMPAAPAPBPPMMM
+  MMMMMMAABBPPMMMM
+  MMMMMMBBMPPAPMMM
+  MMMMPBBPPAPMAMMM
+  MMMGPPPAPMAPMMMM
+  MMMPPGPAAPMMMMMM
+  MMBMPAAMMMMMMMMM
+  MMMBMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 97 (giant spider)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMJAMMMMMM
+  MMMMMMMJAMMMMMMM
+  MMMMMMJAJKKAMMMM
+  MMMJAMAJKJJJAMMM
+  MMMAKKJJAJJAAMJA
+  MMMGJJJJAAAJJJAA
+  MMMJJGJAAJJAAAAM
+  MMDMJAJAJAAJJAMM
+  MMMMDMJAAJAMAJAM
+  MMMMMJAAMAJAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 98 (scorpion)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMJKJKJAAMM
+  MMMMMMJAMJKJKKAM
+  MMMMMMMKAMMMJJJA
+  MMMMMMJAMMMMKKJA
+  MMMMMMMMMMMJJJKA
+  MMMMMMMAJKKAJJAM
+  MMMMMAAJKJJJAAMM
+  MMMAKKJJAJJAAMMM
+  MMMGJJJJAAAJJJAM
+  MMMJJGJAAJJAAAJM
+  MMDMJAJAJAAJJAMM
+  MMMMDMJAAJAMJAAM
+  MMMMMMMJAAJAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 99 (lurker above)
+{
+  MAAAAAAAAAAAAAAA
+  MMMAAGFAAGFAAAMM
+  MMMAAAAAAAAAAAMM
+  MMMMAODODODOAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 100 (trapper)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMAODODODOAMMM
+  MMMAAAAAAAAAAAMM
+  MMMAAGFAAGFAAAMM
+  MAAAAAAAAAAAAAAA
+}
+# tile 101 (white unicorn)
+{
+  MMMMMMMMMMMMMMMM
+  MMHPMMMMMMMMMMMM
+  MMPHOMNNMMMMMMMM
+  MMMPHNNBMMMMMMMM
+  MMMONENBMMMMMMMM
+  MMONNNNBMMMMMMMM
+  MMNOANNBAAMMMMMM
+  MMMAONNBAMMMMMMM
+  MMMONNNONNNMMMMM
+  MMNONNNNONNOAAAM
+  MMNMONONNONAOAMM
+  MMOAANAAAAOAAMMM
+  MMMLAOAAOAOAMMMM
+  MMMMMOAALAOMMMMM
+  MMMMMLAMMMLMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 102 (gray unicorn)
+{
+  MMMMMMMMMMMMMMMM
+  MMHPMMMMMMMMMMMM
+  MMPHOMPPMMMMMMMM
+  MMMPHPPNMMMMMMMM
+  MMMMPGPNMMMMMMMM
+  MMMPPPPNMMMMMMMM
+  MMPPAPPNAAMMMMMM
+  MMMAPPPNAMMMMMMM
+  MMMMPPPMPPPMMMMM
+  MMPMPPPPMPPMAAAM
+  MMPMMPMPPMPAMAMM
+  MMPAAPAAAAMAAMMM
+  MMMLAMAAMAMAMMMM
+  MMMMMMAALAMMMMMM
+  MMMMMLAMMMLMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 103 (black unicorn)
+{
+  MMMMMMMMMMMMMMMM
+  MMHPMMMMMMMMMMMM
+  MMPHOMAAMMMMMMMM
+  MMMPHAAJMMMMMMMM
+  MMMAADAJMMMMMMMM
+  MMAAAAAJMMMMMMMM
+  MMAAPAAJPPMMMMMM
+  MMMPAAAJPMMMMMMM
+  MMMAAAAAAAAMMMMM
+  MMAAAAAAAAAAPPPM
+  MMAMAAAAAAAPAPMM
+  MMAPPAPPAPAPPMMM
+  MMMLPAPPAPAPMMMM
+  MMMMMAPPLPAMMMMM
+  MMMMMLPMMMLMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 104 (pony)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMJJMMMMMMMMM
+  MMMMKKKJMMMMMMMM
+  MMMKKEKJMMMMMMMM
+  MMKKJKKJMMMMMMMM
+  MMJJAKKJAAMMMMMM
+  MMMAKKKJAMMMMMMM
+  MMMKKKKKKKJMMMMM
+  MMMKKKKKKKJJAAAM
+  MMMKJKJJJJJAJAMM
+  MMMJAJAAAAJAAMMM
+  MMMJAJAAJAJAMMMM
+  MMMLMJAALAJMMMMM
+  MMMMMLAMMMLMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 105 (horse)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMJJMMMMMMMMM
+  MMMMKKKJMMMMMMMM
+  MMKKKEKJMMMMMMMM
+  MKKKJKKJAAMMMMMM
+  MJJJAKKJAAMMMMMM
+  MMMAKKKJAMMMMMMM
+  MMMKKKKKKKKJAMMM
+  MMKKKKKKKKKKJAMM
+  MMKJJKJJJJJKAJAM
+  MMJAAJAAAAAJAJAM
+  MMJAAJAAAJAJAAMM
+  MMLAMJAAMLMJAMMM
+  MMMMMLAMMMMLMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 106 (warhorse)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMJJJMMMMMMMM
+  MMMKKKKJJMMMMMMM
+  MKKKKEKJJMMMMMMM
+  KKKKKKKJJAAMMMMM
+  JKKKJKKJJAAMMMMM
+  MJJJAKKJJAAMMMMM
+  MMMAKKKJJAMMMMMM
+  MMMKKKKKKKKKJAMM
+  MMKKKKKKKKKKKJAM
+  MMKKJKKJKKJKKJJA
+  MMKJAKJAKJAKJAJA
+  MMKJAKJAKJAKJAMM
+  MMLCMKJALCMKJMMM
+  MMMMMLCMMMMLCMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 107 (fog cloud)
+{
+  MMMMMMMPMMMMMMMM
+  MMMMPMMPMMMMMMMM
+  MMMMMPMPMMMPMMMM
+  MMMPMMMMMMMPMMMM
+  MMPMMPMPMPMMMMMM
+  MMMMPPMPPMPMPMMM
+  MPMMAPAPPPMMPMMM
+  MMMPMPPPPMPPMMMM
+  MMMMMMPPPPPMPMPM
+  MMMPMPPPPPMMPMMM
+  MMMMPMMPMPPMPMMM
+  MPMMMPMPMMMPPPMM
+  MMPMPMMMMPPMMMMM
+  MMMMMMMPMMMMPMMM
+  MMPMMPMPMMPMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 108 (dust vortex)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKMMKKKKMMMMM
+  MMMKMMKKJJJKMMMM
+  MMKMMKJJJJMMKMMM
+  MKJMKJJMJKKMMKMM
+  MKJJKJMJJJJKMMMM
+  MKJJJJMMMMJJKMMM
+  MKKJMJMMMJMJKKMM
+  MMKJJMMMMJJJJKMM
+  MMMKJJJJMJKJJKMM
+  MKMMKKJMJJKMJKMM
+  MMKMMJJJJKMMKMMM
+  MMMKJJJKKMMKMMMM
+  MMMMKKKKMMKMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 109 (ice vortex)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMNMMNNNNMMMMM
+  MMMNMMNNOOONMMMM
+  MMNMMNOOOOMMNMMM
+  MNOMNOOMONNMMNMM
+  MNOONOMOOOONMMMM
+  MNOOOOMMMMOONMMM
+  MNNOMOMMMOMONNMM
+  MMNOOMMMMOOOONMM
+  MMMNOOOOMONOONMM
+  MNMMNNOMOONMONMM
+  MMNMMOOOONMMNMMM
+  MMMNOOONNMMNMMMM
+  MMMMNNNNMMNMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 110 (energy vortex)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMEMMEEEEMMMMM
+  MMMEMMEEAAAEMMMM
+  MMEMMEAAAAMMEMMM
+  MEAMEAAAAIEMMEMM
+  MEAAIAAAAAAEMMMM
+  MEAAAAAAAAAAEMMM
+  MEEAAAAAAAAAEEMM
+  MMEAAAAAAAAAAEMM
+  MMMEAAAAAAIAAEMM
+  MEMMEIAAAAEMAEMM
+  MMEMMAAAAEMMEMMM
+  MMMEAAAEEMMEMMMM
+  MMMMEEEEMMEMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 111 (steam vortex)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPMMPPPPMMMMM
+  MMMPMMPPBBBPMMMM
+  MMPMMPBBBBMMPMMM
+  MPBMPBBPBPPMMPMM
+  MPBBPBPBBBBPMMMM
+  MPBBBBPMPPBBPMMM
+  MPPBPBMMMBPBPPMM
+  MMPBBPPMPBBBBPMM
+  MMMPBBBBPBPBBPMM
+  MPMMPPBPBBPMBPMM
+  MMPMMBBBBPMMPMMM
+  MMMPBBBPPMMPMMMM
+  MMMMPPPPMMPMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 112 (fire vortex)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMDMMDDDDMMMMM
+  MMMDMMDDCCCDMMMM
+  MMDMMDCCCCMMDMMM
+  MDCMDCCHCDDMMDMM
+  MDCCDCHCCCCDMMMM
+  MDCCCCHHHHCCDMMM
+  MDDCHCHHHCHCDDMM
+  MMDCCHHHHCCCCDMM
+  MMMDCCCCHCDCCDMM
+  MDMMDDCHCCDMCDMM
+  MMDMMCCCCDMMDMMM
+  MMMDCCCDDMMDMMMM
+  MMMMDDDDMMDMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 113 (baby long worm)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMCLCMMMMMMM
+  MMMMMMLLLMMMMMMM
+  MMMMMGGAGGMAMMMM
+  MMMMMGGAGGAAAMMM
+  MMMMMMLLLAAAMCMM
+  MMMMMMLLLAAMCCMM
+  MMMMMMCLLCCCCAMM
+  MMMMMMMLLLCCAMMM
+  MMMMMMMMCLLMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 114 (baby purple worm)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMIMMMMMMMM
+  MMMMMMIIIMMMMMMM
+  MMMMMMIIIMMMMMMM
+  MMMMMGGAGGMAMMMM
+  MMMMMGGAGGAAAMMM
+  MMMMMMIIIAAAMDMM
+  MMMMMMIIIAAMDDMM
+  MMMMMMIIIDDDDAMM
+  MMMMMMMIIIDDAMMM
+  MMMMMMMMIIIMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 115 (long worm)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMCLCMMMMMMMM
+  MMMMCLLLCMMMMMMM
+  MMMMLLLLLMMMMMMM
+  MMMGGGLGGGAAMMMM
+  MMMGAGLGAGAAAMMM
+  MMMGGGLGGGAAAMMM
+  MMMMLLLLLAAACCMM
+  MMMMLLLLLAACCCMM
+  MMMMCLLLLCCCCAMM
+  MMMMMLLLLLCCAMMM
+  MMMMMMCLLLLMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 116 (purple worm)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMDIDMMMMMMMM
+  MMMMDIIIDMMMMMMM
+  MMMMIIIIIMMMMMMM
+  MMMGGGIGGGAAMMMM
+  MMMGAGIGAGAAAMMM
+  MMMGGGIGGGAAAMMM
+  MMMMIIIIIAAADDMM
+  MMMMIIIIIAADDDMM
+  MMMMDIIIIDDDDAMM
+  MMMMMIIIIIDDAMMM
+  MMMMMMDIIIIMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 117 (grid bug)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMDMMMMNHCNMMDMM
+  MDMDMMNHDNCNDEDM
+  DMDMDMNNHCNDMDED
+  MDMMMDMNNHDNDMMM
+  MDDDMMENNGMDMDEM
+  MMDDDDEEEEGDMMDE
+  DMMMMMDEHEEMDMMM
+  MDMMMMMMMHMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 118 (xan)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMGGMMMM
+  MMMHHHMMMGOGGMMM
+  MMMMMHHMMGGGGMMM
+  MMMHHHHHMGGGMMMM
+  MMMMMMMGGMMMAAAM
+  MMMMMGOGGHHAAAAM
+  MMMMGOGGMMHHAAAM
+  NNNGOGGMAAHHHAMM
+  NANGGGGMAAHAHMMM
+  NNNGGNNNAAAAAAMM
+  MMGGGNANAAMAAAMM
+  MGGGANNNAAMAMAMM
+  MMGMMAAAAAAMMMMM
+  MMMMMMAAMAAMMMMM
+}
+# tile 119 (yellow light)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMNAMMMMMMMM
+  MMMMMMHAMMMMMMMM
+  MMNAMNHNAMNAMMMM
+  MMMLALHLALAMMMMM
+  MMMMNHHHNAMMMMMM
+  MMNLHHHHHLNAMMMM
+  NHHHHHHHHHHHNAMM
+  MMNLHHHHHLNAMMMM
+  MMMMNHHHNAMMMMMM
+  MMMLALHLALAMMMMM
+  MMNAMNNNAMNAMMMM
+  MMMMMMHAMMMMMMMM
+  MMMMMMNAMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 120 (black light)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMAAMMMMMMMM
+  MMMMMMAAMMMMMMMM
+  MMAAMAAAAMAAMMMM
+  MMMAAAAAAAAMMMMM
+  MMMMAAAAAAMMMMMM
+  MMAAAAAAAAAAMMMM
+  AAAAAAAAAAAAAAMM
+  MMAAAAAAAAAAMMMM
+  MMMMAAAAAAMMMMMM
+  MMMAAAAAAAAMMMMM
+  MMAAMAAAAMAAMMMM
+  MMMMMMAAMMMMMMMM
+  MMMMMMAAMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 121 (zruty)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMFFGFMMMMMM
+  MMMMOOFGFFFFMMMM
+  MMMAOFGFOOKFFMMM
+  MMMFFGFAOAJKKFMM
+  MMFFFFFFJAAJKKMM
+  MMODOFFJAJJKKJAM
+  MMDDDDJAJJKJJAAM
+  MMJODOAJJJAJJAAA
+  MKKJAJJJKJAJJAAA
+  MKKAAJKKKKJAAAAA
+  MMMAJJKKKKJJAAAA
+  MMMKJJAAAAKJAAAM
+  MMJKJJJAAJJJJMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 122 (couatl)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMIMMMMIMM
+  MMMMKKAIIIMMIIIM
+  MMMNAOJAKIMIIIII
+  MMMKKJAJJKKKMMII
+  MMMKKAAIJJJJJMMI
+  MMMFAAMIMMMKJMMI
+  MMFAFAMMAAAKJAAM
+  MMMMMMMAAAJJAAAM
+  MMMMMMAKKJJAAAMM
+  MMMMMMKJAAAAAJAM
+  MMMMMJJAAMMMJAMM
+  MMMMMMJJJJJJAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 123 (Aleax)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMBBBBMMIMMM
+  MMIMMBFMMMBMMMMM
+  MMMMBFMHHAMBMMMM
+  MMMBFMHHHHAMBMIM
+  MMMBFMLFLFAMFBMM
+  MIMBFMLLLLAMFBMM
+  MMMBFMALLAMFBMMM
+  MMBFMLLAALLMABAM
+  MBFMLLLLLLLLAFBM
+  MBFMLALLLLALAFBM
+  MBFMLAJJKJALAFBM
+  MMBFMMLJJLAAABAM
+  MMMBFMLLALAABAMM
+  MMBFMLLAALLAFBMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 124 (Angel)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMHHHHMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMCCMMMMMMM
+  MMMMMMCLLCMMAAMM
+  MMMMMMPLLPMMMMAM
+  MMMMMMNPPPAMAMMM
+  MMMMMBBLLPPAAAMM
+  MMMMMNNLLPPAAAMM
+  MMMMMMBNNPAAAAMM
+  MMMMMMBNNPAAAAMM
+  MMMMMBNNNPAAMAMM
+  MMMMMBNNNNPAMMMM
+  MMMMBNNNNNNPMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 125 (ki-rin)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMLPMMMMMMMMMMMM
+  MMPLOMCMCMMMMMMM
+  MMMPLCCDMMMMMMMM
+  MMMKCIKDMMMMMMMM
+  MMKCCCCDMMMMMMMM
+  MMCKACCDAMMMMMMM
+  MMMACCCCCCMMMAMM
+  MMMKCCCKCCKAAMMM
+  MMCAKCKCKCAKAMMM
+  MMCAAKAKAKAMMMMM
+  MMMLMKALAKMMMMMM
+  MMMMMLAMMLMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 126 (Archon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMOOOOMMMMMM
+  MMMMMOOOOOOMMMMM
+  MMMMMOJLLJOMMMMM
+  MMMMMOLLLLOMMMMM
+  MMMMOOJLLJOOMMMM
+  MMMMMMAJJAMMMMMM
+  MMMMMAAAAAAAMMMM
+  MMMMAAAAAAAAAMMM
+  MMMOAAOAAAJLJMMM
+  MMOOAOAAAACJCMMM
+  MMMMLAAAACCJCCMM
+  MMMMMAAAAAJJJMMM
+  MMMMAAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 127 (bat)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMJJJCACJJJMMMM
+  MMJJAAHJHAAJJMMM
+  MMJAMMMJAMMAJMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMAAAAAAAAMMMM
+  MMMAAAMAAMAAAMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 128 (giant bat)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMJKMJMJMJKMMMM
+  MMKJJJCACJJKJMMM
+  MJJJAAHJHAAJJKMM
+  MKJAMMMJAMMAJJMM
+  MMJAMMMMMMMAJMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMAAAAAAMMMMM
+  MMMAAAAAAAAAAMMM
+  MMAAAAMAAMAAAAMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 129 (raven)
+{
+  MMAAAAMMMAAAMMMM
+  MAAAAAAMAAAMMMMM
+  AAAAAAAAAAAMAAMM
+  AMMMAAAAAAAAAAAM
+  MMMMMMAAAAAAAAAM
+  MMMMMAAAAMMMMMAA
+  MMMMMADAMMMMMMMA
+  MMMMMPAMMMMMMMMM
+  MMMMMPMMMMMMMMMM
+  MMMMMMMMMPMPMPMM
+  MMMMMMMMPMPMPMPM
+  MMMMMMMPMPMPMMMM
+  MMMMMMMMPMPMPMMM
+  MMMMMMMMMMMPMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 130 (vampire bat)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMAAMAMAMAAMMMM
+  MMAAAAAAAAAAAMMM
+  MAAAAMDADMAAAAMM
+  MAAAMMMAMMMAAAMM
+  MMAMMMMMMMMMAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMAAAAAAMMMMM
+  MMMAAAAAAAAAAMMM
+  MMAAAAMAAMAAAAMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 131 (plains centaur)
+{
+  MMMMMMMMMMMMMMMM
+  MMMKKAMMMMMMMMMM
+  MMMLLAAMMMMMMMMM
+  MAAKKAAMMMMMMMMM
+  MLLAALLAMMMMMMMM
+  LALLLLALAMMMMMMM
+  LALLLKALAMAMMMMM
+  MMLKLKAAAAAMMMMM
+  MMKLKJKJJKAAMMMM
+  MKJKJKJKJAKAAAAM
+  MKAKJJJJKJAAAMAM
+  MKAAKAAAAKAAMMMM
+  MMCAKAAJAKAMMMMM
+  MMMMKAAKAKMMMMMM
+  MMMMCAMMMCMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 132 (forest centaur)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMKKAMMMMMMMMMM
+  LAMLLAALAMMMMMMM
+  LAALLAALAMMMMMMM
+  MLLAALLAMMMMMMMM
+  MMLLLLAMAMMMMMMM
+  MMLKLKAAAAAMMMMM
+  MMKLKJKJJKAAMMMM
+  MKJKJKJKJAKAMAMM
+  MKAKJJJJKJAAAAMM
+  MKAAKAAJAKAMMMMM
+  MMCMKAAKAKMMMMMM
+  MMMMCAMMMCMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 133 (mountain centaur)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMKKAMMMMMMMMMM
+  MMMLLAAMMMMMMMMM
+  MMAKKAAMMMMMMMMM
+  MLJJJJLAMMMMMMMM
+  LAJKKJALAMAMMMMM
+  LAKKKKALAAAMMMMM
+  MMJJJJKJJKAAMMMM
+  MKJJJKJKJAKAAAAM
+  MKAKJJJJKJAAAMAM
+  MKAAKAAAAKAAMMMM
+  MMCAKAAJAKAMMMMM
+  MMMMKAAKAKMMMMMM
+  MMMMCAMMMCMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 134 (baby gray dragon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMBBBAMMMMMMM
+  MMMMNPNPPAMMMMMM
+  MMMBPPPPPAMMMMMM
+  MMCHHPABPAMAAAMM
+  MCHCDAMBPAAAAAAM
+  MMDMMBPPAAAAAAAM
+  MMMMBBPPPPPAAAAM
+  MMMBOOPPPPPPAAAM
+  MMBPOBPPPPPPPAAM
+  MMBPPBPPOBPAPPAM
+  MMBPABPMABPAPPAM
+  MMMMMBPAAMMPPAAM
+  MMMMMMMMMMMPAAMM
+}
+# tile 135 (baby silver dragon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPPPAMMMMMMM
+  MMMMOBOBBAMMMMMM
+  MMMPBBBBBAMMMMMM
+  MMCHHBAPBAMAAAMM
+  MCHCDAMPBAAAAAAM
+  MMDMMPBBAAAAAAAM
+  MMMMPPBBBBBAAAAM
+  MMMPNNBBBBBBAAAM
+  MMPBNPBBBBBBBAAM
+  MMPBBPBBNPBABBAM
+  MMPBAPBMAPBABBAM
+  MMMMMPBAAMMBBAAM
+  MMMMMMMMMMMBAAMM
+}
+# tile 136 (baby shimmering dragon)
+{
+  MIMMMMMMMMMMMMMM
+  MMMBBBBBBBMIMMMM
+  MMBFMFFFMFBMMMIM
+  MBFMMBBBAMFBMMMM
+  BFMMNPNPPAFBMIMM
+  BFMBPPPPPAMBMMMM
+  BMCHHPABPAFBAAIM
+  BCHCDAMBPAAFBAAM
+  BMDMMBPPAAAAFBAM
+  BMMMBBPPPPPAAFBM
+  BFMBOOPPPPPPAAAB
+  BFBPOBPPPPPPPAFB
+  BFBPPBPPOBPAPPFB
+  BMBPABPMABPAPPFB
+  BMMMMBPAAMMPPAAB
+  MBMMMMMMMMMPAABM
+}
+# tile 137 (baby red dragon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMIIIAMMMMMMM
+  MMMMNDNDDAMMMMMM
+  MMMIDDDDDAMMMMMM
+  MMCHHDAIDAMAAAMM
+  MCHCDAMIDAAAAAAM
+  MMDMMIDDAAAAAAAM
+  MMMMIIDDDDDAAAAM
+  MMMIHHDDDDDDAAAM
+  MMIDHIDDDDDDDAAM
+  MMIDDIDDHIDADDAM
+  MMIDAIDMAIDADDAM
+  MMMMMIDAAMMDDAAM
+  MMMMMMMMMMMDAAMM
+}
+# tile 138 (baby white dragon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMNNNAMMMMMMM
+  MMMMIOIOOAMMMMMM
+  MMMNOOOOOAMMMMMM
+  MMCHHOANOAMAAAMM
+  MCHCDAMNOAAAAAAM
+  MMDMMNOOAAAAAAAM
+  MMMMNNOOOOOAAAAM
+  MMMNOOOOOOOOAAAM
+  MMNOONOOOOOOOAAM
+  MMNOONOOONOAOOAM
+  MMNOANOMANOAOOAM
+  MMMMMNOAAMMOOAAM
+  MMMMMMMMMMMOAAMM
+}
+# tile 139 (baby orange dragon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLLLAMMMMMMM
+  MMMMNCNCCAMMMMMM
+  MMMLCCCCCAMMMMMM
+  MMCHHCALCAMAAAMM
+  MCHCDAMLCAAAAAAM
+  MMDMMLCCAAAAAAAM
+  MMMMLLCCCCCAAAAM
+  MMMLOOCCCCCCAAAM
+  MMLCOLCCCCCCCAAM
+  MMLCCLCCOLCACCAM
+  MMLCALCMALCACCAM
+  MMMMMLCAAMMCCAAM
+  MMMMMMMMMMMCAAMM
+}
+# tile 140 (baby black dragon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMAAAMMMMMMMM
+  MMMMNANAAMMMMMMM
+  MMMAAAAAAMMMMMMM
+  MMCHHAMAAMMPPPMM
+  MCHCDMMAAMPPPPPM
+  MMDMMAAAPPPMPPPM
+  MMMMAAAAAAAPPPPM
+  MMMAAAAAAAAAPPPM
+  MMAAAAAAAAAAAPPM
+  MMAAAAAAAAAPAAPM
+  MMAAPAAMPAAPAAPM
+  MMMMMAAPMMMAAPPM
+  MMMMMMMMMMMAPPMM
+}
+# tile 141 (baby blue dragon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMBBBAMMMMMMM
+  MMMMNENEEAMMMMMM
+  MMMBEEEEEAMMMMMM
+  MMCHHEABEAMAAAMM
+  CCHCDAMBEAAAAAAM
+  MMDMMBEEAAAAAAAM
+  MMMMBBEEEEEAAAAM
+  MMMBOOEEEEEEAAAM
+  MMBEOBEEEEEEEAAM
+  MMBEEBEEOBEAEEAM
+  MMBEABEMABEAEEAM
+  MMMMMBEAAMMEEAAM
+  MMMMMMMMMMMEAAMM
+}
+# tile 142 (baby green dragon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMGGGAMMMMMMM
+  MMMMNFNFFAMMMMMM
+  MMMGFFFFFAMMMMMM
+  MMCHHFAGFAMAAAMM
+  MCHCDAMGFAAAAAAM
+  MMDMMGFFAAAAAAAM
+  MMMMGGFFFFFAAAAM
+  MMMGOOFFFFFFAAAM
+  MMGFOGFFFFFFFAAM
+  MMGFFGFFOGFAFFAM
+  MMGFAGFMAGFAFFAM
+  MMMMMGFAAMMFFAAM
+  MMMMMMMMMMMFAAMM
+}
+# tile 143 (baby yellow dragon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMNNNAMMMMMMM
+  MMMMDHDHHAMMMMMM
+  MMMNHHHHHAMMMMMM
+  MMCHHHANHAMAAAMM
+  MCHCDAMNHAAAAAAM
+  MMDMMNHHAAAAAAAM
+  MMMMNNHHHHHAAAAM
+  MMMNOOHHHHHHAAAM
+  MMNHONHHHHHHHAAM
+  MMNHHNHHONHAHHAM
+  MMNHANHMANHAHHAM
+  MMMMMNHAAMMHHAAM
+  MMMMMMMMMMMHAAMM
+}
+# tile 144 (gray dragon)
+{
+  MMMMMMBBBPAMMMMM
+  MMMMMNPNPPPAMMMM
+  MMMMBPPPPPPAMMMM
+  MMDCHHPMMPPAMMMM
+  CHCHCDMMBPPAMMMM
+  HDMDMMMBPPAMMMMM
+  MMMMMMOBPAAAAAAM
+  MMMMBOBPAAAAAAAA
+  MMBOOBPAMPPMAAAM
+  MBOOOBPPPPPPMAAM
+  MBOOOBPPPPPPPAAM
+  PPOOBBPPPPPPPPAM
+  BPMOBPPOOPPMPMAM
+  BPAABPMAAPPAPPAM
+  MMMMBPAAMMMPPMAM
+  MMMMMMMMPPPPMAMM
+}
+# tile 145 (silver dragon)
+{
+  MMMMMMPPPBAMMMMM
+  MMMMMOBOBBBAMMMM
+  MMMMPBBBBBBAMMMM
+  MMDCHHBMMBBAMMMM
+  CHCHCDMMPBBAMMMM
+  HDMDMMMPBBAMMMMM
+  MMMMMMNPBAAAAAAM
+  MMMMPNPBAAAAAAAA
+  MMPNNPBAMBBMAAAM
+  MPNNNPBBBBBBMAAM
+  MPNNNPBBBBBBBAAM
+  BBNNPPBBBBBBBBAM
+  PBMNPBBNNBBMBMAM
+  PBAAPBMAABBABBAM
+  MMMMPBAAMMMBBMAM
+  MMMMMMMMBBBBMAMM
+}
+# tile 146 (shimmering dragon)
+{
+  MIMBFMBBBPAFBMMM
+  MMBFMNPNPPPAFBMI
+  MBFMBPPPPPPAFBMM
+  MBDCHHPMMPPAFBIM
+  CBCHCDMMBPPAFBMM
+  HDBBMMMBPPAMBMMI
+  MMBFMMOBPAAAABAM
+  MBFMBOBPAAAAAFBA
+  BFBOOBPAMPPMAAFB
+  MBOOOBPPPPPPMAFB
+  MBOOOBPPPPPPPAFB
+  PPOOBBPPPPPPPPFB
+  BPMOBPPOOPPMPMFB
+  BPAABPMAAPPAPPFB
+  MMMMBPAAMMMPPMAB
+  MMMMMMMMPPPPMABM
+}
+# tile 147 (red dragon)
+{
+  MMMMMMIIIDAMMMMM
+  MMMMMNDNDDDAMMMM
+  MMMMIDDDDDDAMMMM
+  MMDCHHDMMDDAMMMM
+  CHCHCDMMIDDAMMMM
+  HDMDMMMIDDAMMMMM
+  MMMMMMHIDAAAAAAM
+  MMMMIHIDAAAAAAAA
+  MMIHHIDAJDDJAAAM
+  MIHHHIDDDDDDJAAM
+  MIHHHIDDDDDDDAAM
+  DDHHIIDDDDDDDDAM
+  IDMHIDDHHDDJDJAM
+  IDAAIDMAADDADDAM
+  MMMMIDAAJJJDDJAM
+  MMMMMMMMDDDDJAMM
+}
+# tile 148 (white dragon)
+{
+  MMMMMMNNNOAMMMMM
+  MMMMMIOIOOOAMMMM
+  MMMMNOOOOOOAMMMM
+  MMDCHHOMMOOAMMMM
+  CHCHCDMMNOOAMMMM
+  HDMDMMMNOOAMMMMM
+  MMMMMMONOAAAAAAM
+  MMMMNONOAAAAAAAA
+  MMNOONOAMOOMAAAM
+  MNOOONOOOOOOJAAM
+  MNOOONOOOOOOOAAM
+  OOOONNOOOOOOOOAM
+  NOMONOOOOOOMOJAM
+  NOAANOMAAOOAOOAM
+  MMMMNOAAMMMOOJAM
+  MMMMMMMMOOOOJAMM
+}
+# tile 149 (orange dragon)
+{
+  MMMMMMLLLCAMMMMM
+  MMMMMNCNCCCAMMMM
+  MMMMLCCCCCCAMMMM
+  MMDCHHCMMCCAMMMM
+  CHCHCDMMLCCAMMMM
+  HDMDMMMLCCAMMMMM
+  MMMMMMOLCAAAAAAM
+  MMMMLOLCAAAAAAAA
+  MMLOOLCAMCCKAAAM
+  MLOOOLCCCCCCJAAM
+  MLOOOLCCCCCCCAAM
+  CCOOLLCCCCCCCCAM
+  LCMOLCCOOCCKCJAM
+  LCAALCMAACCACCAM
+  MMMMLCAAMKKCCJAM
+  MMMMMMMMCCCCJAMM
+}
+# tile 150 (black dragon)
+{
+  MMMMMMAAAAMMMMMM
+  MMMMMNANAAAMMMMM
+  MMMMAAAAAAAMMMMM
+  MMDCHHAMMAAMMMMM
+  CHCHCDMMAAAMMMMM
+  HDMDMMMAAAMMMMMM
+  MMMMMMAAAMMPPPPM
+  MMMMAAAAPPPPPPPP
+  MMAAAAAAAAAMPPPM
+  MAAAAAAAAAAAAPPM
+  MAAAAAAAAAAAAPPM
+  AAAAAAAAAAAAAAPM
+  AAMAAAAAAAAMAAPM
+  AAPPAAMPPAAPAAPM
+  MMMMAAPPMMMAAAPM
+  MMMMMMMMAAAAAMMM
+}
+# tile 151 (blue dragon)
+{
+  MMMMMMBBBEAMMMMM
+  MMMMMNENEEEAMMMM
+  MMMMBEEEEEEAMMMM
+  MMDCHHEMMEEAMMMM
+  CHCHCDMMBEEAMMMM
+  HDMDMMMBEEAMMMMM
+  MMMMMMOBEAAAAAAM
+  MMMMBOBEAAAAAAAA
+  MMBOOBEAMEEMAAAM
+  MBOOOBEEEEEEJAAM
+  MBOOOBEEEEEEEAAM
+  EEOOBBEEEEEEEEAM
+  BEMOBEEOOEEMEJAM
+  BEAABEMAAEEAEEAM
+  MMMMBEAAMMMEEJAM
+  MMMPMMMMEEEEJAMM
+}
+# tile 152 (green dragon)
+{
+  MMMMMMGGGFAMMMMM
+  MMMMMNFNFFFAMMMM
+  MMMMGFFFFFFAMMMM
+  MMDCHHFMMFFAMMMM
+  CHCHCDMMGFFAMMMM
+  HDMDMMMGFFAMMMMM
+  MMMMMMOGFAAAAAAM
+  MMMMGOGFAAAAAAAA
+  MMGOOGFAMFFMAAAM
+  MGOOOGFFFFFFJAAM
+  MGOOOGFFFFFFFAAM
+  FFOOGGFFFFFFFFAM
+  GFMOGFFOOFFMFJAM
+  GFAAGFMAAFFAFFAM
+  MMMMGFAAMMMFFJAM
+  MMMMMMMMFFFFJAMM
+}
+# tile 153 (yellow dragon)
+{
+  MMMMMMNNNHAMMMMM
+  MMMMMDHDHHHAMMMM
+  MMMMNHHHHHHAMMMM
+  MMDCHHHMMHHAMMMM
+  CHCHCDMMNHHAMMMM
+  HDMDMMMNHHAMMMMM
+  MMMMMMONHAAAAAAM
+  MMMMNONHAAAAAAAA
+  MMNOONHAJHHJAAAM
+  MNOOONHHHHHHJAAM
+  MNOOONHHHHHHHAAM
+  HHOONNHHHHHHHHAM
+  NHMONHHOOHHJHJAM
+  NHAANHMAAHHAHHAM
+  MMMMNHAAJJJHHJAM
+  MMMMMMMMHHHHJAMM
+}
+# tile 154 (stalker)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPPPMMMMMM
+  MMMMMMPMPMPMMMMM
+  MMMMMPPPPPPMMMMM
+  MMMMMPPMMPPPMMMM
+  MMMMPPPPPPMPMMMM
+  MMMMPMPPPPMPMMMM
+  MMMMPMPPPMMPMMMM
+  MMMMPMMPPMMPMMMM
+  MMMMPMPPPPMPMMMM
+  MMMMPMPMMPMPMMMM
+  MMMMPMPMMPMPMMMM
+  MMMMMMPMMPMMMMMM
+  MMMMMMPMMPMMMMMM
+  MMMMMPPMMPPMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 155 (air elemental)
+{
+  MMMMMMMMMMMMMMMM
+  MMMPMPPPMMPMMMMM
+  MMPMPAPAMPMMMMMM
+  PMMPPPPPPMMPMMMM
+  MPMPPAAPPPMMMPMM
+  MMPPPAAPMPMPMMMM
+  MMPAPAAPAPMMMMMM
+  PMPAPPPMAPMPMAAM
+  MMPAMPPMAPMAAAAM
+  MMPAPPPPAPAAAAMM
+  MMPAPMAPAPAAAAMM
+  MMPAPMAPAPAAAAAM
+  MMMMPMAPAAAAAAAM
+  MMPMPMAPPAAAAAAM
+  MMMPPMAPPPAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 156 (fire elemental)
+{
+  MMMMMMMMMMMMMMMM
+  MHMMLDDDMMMMMMMM
+  MMMLDADACMHMMMMM
+  HMMDDDDDDMMHMHMM
+  MMLDDAADDDMMMMMM
+  MMDDDAADCDMHMMMM
+  MMDADAACADMMMMMM
+  HMDADDDCADMMMAAM
+  MMDACDDCADMAAAAM
+  MMDADDDDADAAAAMM
+  MMDADCADADAAAAMM
+  HMDADCADADAAAAAM
+  MMMMDCADAAAAAAAM
+  MHMLDCADDAAAAAAM
+  MMLDDCADDDAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 157 (earth elemental)
+{
+  MMFMMMMMMMMMMMMM
+  MMMMCKKKMMFMMMMM
+  MMMCKAKAJMMMMFMM
+  MMMKKKKKKMMMMMMM
+  MMCKKAAKKKMFMMFM
+  MFKKKAAKJKMMMMMM
+  MMKAKAAJAKMMFMMM
+  MMKAKJJJAKMMMAAM
+  FMKAJKKJAKMAAAAM
+  MMKAKKKKAKAAAAMM
+  MMKAKJAKAKAAAAMM
+  MMKAKJAKAKAAAAAM
+  MMMMKJAKAAAAAAAM
+  MFMCKJAKKAAAAAAM
+  MMCKKJAKKKAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 158 (water elemental)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMPBBBMMEMMMMM
+  MEMPBABAEMMMEMMM
+  MMMBBBBBBMMMMMMM
+  MMPBBAABBBMEMMEM
+  EMBBBAABEBMMMMMM
+  MMBABAABEBMEMMMM
+  MMBABBBBEBMMMAAM
+  MMBAPBBEABMAAAAM
+  EMBABBBBABAAAAMM
+  MMBABEABABAAAAMM
+  MMBABEABABAAAAAM
+  MMMMBEABAAAAAAAM
+  MEMPBEABBAAAAAAM
+  MMPBBEABBBAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 159 (lichen)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMFFFMMMFFFMMMM
+  MMFCFFFFFCCFAMMM
+  MFCOOFFFCOFFFAMM
+  MFCOOFFFCFFFFAMM
+  MMFFFFFFFFFFAMMM
+  MMMAFFFCCFFFAMMM
+  MMMFFFFCOFFAAMMM
+  MMFCCFFCOFCFAMMM
+  MMFCOFFCFFOCFAMM
+  MMFFCFFFCFFFFAMM
+  MMMFFFAAFFFFFAMM
+  MMMMMAAMAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 160 (brown mold)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMJJJMMMJJJMMMM
+  MMJKJJJJJKKJAMMM
+  MJKCCJJJKCJJJAMM
+  MJKCCJJJKJJJJAMM
+  MMJJJJJJJJJJAMMM
+  MMMAJJJKKJJJAMMM
+  MMMJJJJKCJJAAMMM
+  MMJKKJJKCJKJAMMM
+  MMJKCJJKJJCKJAMM
+  MMJJKJJJKJJJJAMM
+  MMMJJJAAJJJJJAMM
+  MMMMMAAMAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 161 (yellow mold)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMHHHMMMHHHMMMM
+  MMHHHHHHHNHHAMMM
+  MHHNNOHHNNOHHAMM
+  MHHNNOOHHOOHHAMM
+  MMHHOOHHHHHHAMMM
+  MMMAHHHHHHHHAMMM
+  MMMHHHHNNOHAAMMM
+  MMHHHHHNNOHHAMMM
+  MMHNNOHHHONOHAMM
+  MMHHOHHHHHOOHAMM
+  MMMHHHAAHHHHHAMM
+  MMMMMAAMAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 162 (green mold)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMFFFMMMFFFMMMM
+  MMFGFFFFFGGFAMMM
+  MFGOOFFFGOFFFAMM
+  MFGOOFFFGFFFFAMM
+  MMFFFFFFFFFFAMMM
+  MMMAFFFGGFFFAMMM
+  MMMFFFFGOFFAAMMM
+  MMFGGFFGOFGFAMMM
+  MMFGOFFGFFOGFAMM
+  MMFFGFFFGFFFFAMM
+  MMMFFFAAFFFFFAMM
+  MMMMMAAMAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 163 (red mold)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMDDDMMMDDDMMMM
+  MMDCDDDDDCCDAMMM
+  MDLLCDDDCLDDDAMM
+  MDCCCDDDCDDDDAMM
+  MMDDDDDDDDDDAMMM
+  MMMADDDCCDDDAMMM
+  MMMDDDDCLDDAAMMM
+  MMDCCDDCLDCDAMMM
+  MMDCLDDCDDLCDAMM
+  MMDDCDDDCDDDDAMM
+  MMMDDDAADDDDDAMM
+  MMMMMAAMAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 164 (shrieker)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMGGGGFFMMMMM
+  MMMGGGGIGIDFFMMM
+  MGGGIIGGGIIFFFFM
+  GIIGIIGGGGGGGDDF
+  GIIGGGGIIGIIGIDF
+  GGGGIGGIIGIIGGFF
+  MMGGGGGGGGGGGMMM
+  MMMMMMFFFMMAAAAA
+  MMMMAGGGFFAAAAAA
+  MMMAGGGGGGFAAAAM
+  MMMAAAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 165 (violet fungus)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMIIIMMMIIIMMMM
+  MMILIIIIILLIAMMM
+  MIOOLIIILOIIIAMM
+  MILLLIIILIIIIAMM
+  MMIIIIIIIIIIAMMM
+  MMMAIIILLIIIAMMM
+  MMMIIIILOIIAAMMM
+  MMILLIILOILIAMMM
+  MMILOIILIIOLIAMM
+  MMIILIIILIIIIAMM
+  MMMIIIAAIIIIIAMM
+  MMMMMAAMAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 166 (gnome)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMDFMMMMMMMMM
+  MMMMMMGMMMMMMMMM
+  MMMMMGFFMMMMMMMM
+  MMMMGGFFFMMMMMMM
+  MMMMGLLLFMMMMMMM
+  MMMMMOLOMMMAAAMM
+  MMMFGOOOFFAAAAMM
+  MMMGAGOFAFAAAAMM
+  MMMMLKNKFAAAAMMM
+  MMMMFGAFFAAMMMMM
+  MMMMGFAFGMAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 167 (gnome lord)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMDMMMMMMMMM
+  MMMMMMGMMMMMMMMM
+  MMMMMMGMMMMMMMMM
+  MMMMMGFFMMMMMMMM
+  MMMMHHHHHMMMMMMM
+  MMMMGLLLFMMMMMAM
+  MMMMMOLOMMMAAAMM
+  MMMFGOOOFFAAAAMM
+  MMMGAGOFAFAAAAMM
+  MMMMLKNKFAAAAMMM
+  MMMMFGAFFAAMMMMM
+  MMMMGFAFGMAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 168 (gnomish wizard)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMGMMMMMMMMM
+  MMMMMGFFMMMMMMMM
+  MMMMGGFFFMMMMMMM
+  MMMMGLLLFMMMMMMM
+  MMMFFOLOFFMAAAMM
+  MMMGFOOOFFAAAAMM
+  MMMFAGOFAFAAAAMM
+  MMMGLKNKFFAAAMMM
+  MMMFFGFFFFAMMMMM
+  MMMGFFFFGFAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 169 (gnome king)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMHMCMHMMMMMMM
+  MMMMHCHCHMMMMMMM
+  MMMMHHHHHMMMMMMM
+  MMMMGLLLFMMMAMMM
+  MMMMMOLOMMMAAAAM
+  MMMFGOOOFFAAAAMM
+  MMMGAGOFAFAAAAMM
+  MMMMLKNKFAAAAMMM
+  MMMMFGAFFAAMMMMM
+  MMMMGFAFGMAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 170 (giant)
+{
+  MMMMMMJJJJAAMMMM
+  MMMMJJJJJJJJAMMM
+  MMMMJJLLLLJJAMMM
+  MMMMJFFLLFFJAMMM
+  MMMMJLLLLLLJAMMM
+  MMMMALLAALLAAAMM
+  MMMMMALLLLJAAAAM
+  MMCCLLJJJJLLCCAA
+  MCLLLCCKCKCLLLCA
+  MLLLKLKCKCLKLLLA
+  MLLAALLCCLLAALLA
+  MLLAAJJJKKJAALLA
+  MCLCMJJJJJKKCLAA
+  MMLLMCLJACLJLLAA
+  MMMMMCLJACLJAAAA
+  MMMLLLLJMCLLLKAA
+}
+# tile 171 (stone giant)
+{
+  MMMMMMJJJJAAMMMM
+  MMMMJJJJJJJJAMMM
+  MMMMJJLLLLJJAMMM
+  MMMMJFFLLFFJAMMM
+  MMMMJLLLLLLJAMMM
+  MMMMALLAALLAAAMM
+  MMMMMALLLLJAAAAM
+  MMCCLLJJJJLLCCAA
+  MCLLLCCKCKCLLLCA
+  MLLLAAKCKCLKLLLA
+  MLLPPPACCLLAALLA
+  MLLPPPPAKKJAALLA
+  MCLCPPPAJJKKCLAA
+  MMLLPPALACLJLLAA
+  MMMMMALJACLJAAAA
+  MMMLLLLJMCLLLKAA
+}
+# tile 172 (hill giant)
+{
+  MMMMMMJJJJAAMMMM
+  MMMMJJJJJJJJAMMM
+  MMMMJJLLLLJJAMMM
+  MMMMJFFLLFFJAMMM
+  MMMMJLLLLLLJAMMM
+  MMMMALLAALLAAAMM
+  MMMMMALLLLJAAAAM
+  MMMJJKJJJJJJJAAM
+  MMLJJCCKCKCJJLAM
+  MMJLKKKCKCKKLJAM
+  MMLAAKKCCKJAALAA
+  MMLAAJJJKKJAALAA
+  MMLCMJJJJJKKCLAA
+  MMLLMCLJACLJLLAA
+  MMMMMCLJACLJAAAA
+  MMMLLLLJMLLLLKAA
+}
+# tile 173 (fire giant)
+{
+  MMMMPPDDDDAAMMMM
+  MMMMPDDDDDDDAMMM
+  MMMPPDLLLLDDAMMM
+  MMMPDPFLLFFDAMMM
+  MMMPPPLLLLLDAMMM
+  MMMMPLLAALLAAAMM
+  MMMPPALLLLJAAAAM
+  MMMJPDJJJJJJJAAM
+  MMLDDHDKCKCJJLAM
+  MMJLHDDCKCKKLJAM
+  MMLAHDHCCKJAALAA
+  JLAADDHJKKJAALAA
+  JJLJDHHJJJKKCLAA
+  MMLLJJJJACLJLLAA
+  MMMMMCLJACLJAAAA
+  MMMLLLLJMLLLLKAA
+}
+# tile 174 (frost giant)
+{
+  MMMMMKJJJJAAMMMM
+  MMMMKJJJJJJJAMMM
+  MMMMJJLLLLJJAMMM
+  MMMMJEELLEEJAMMM
+  MMMMJLLLLLLJAMMM
+  MMMMAKJJJJJAAAMM
+  MMMMMKJAAJJAAAAM
+  MMMMKKJJJJAJAAAA
+  MMMKJKJJJJAJJAAA
+  MMKJKKJJJJJKJJAA
+  MMKAAJKJJAJAAJAA
+  MMJAAJKKAKJAAJAA
+  MMLCMJJJJJKKCLAA
+  MMLLMCJJAJLJLLAA
+  MMMMMCLJACLJAAAA
+  MMMLLLLJMCLLLKAA
+}
+# tile 175 (storm giant)
+{
+  MMMMMMJJJJAAMMMM
+  MMMMJJJJJJJJAMMM
+  MMMMJJLLLLJJAMMM
+  MMMMJFFLLFFJAMMM
+  MMMMJLLLLLLJAMMM
+  MMMMALLAALLAAHMM
+  MMMMMALLLLJAHAAM
+  MMMJJKJJJJJHHAAM
+  MMLJJCCKCKHHLAAM
+  MMJLKKKCKHHHHHHM
+  MMLAAKKCCKJAHHAA
+  MMLAAJJJKKJHHALA
+  MMLCMJJJJJKHAAAA
+  MMLLMCLJACHAAAAA
+  MMMMMCLJACCJAAAA
+  MMMLLLLJMLLLLKAA
+}
+# tile 176 (ettin)
+{
+  MMMMNNMMONOPMMMM
+  MMNNOOPNNOOPPMMM
+  MMNPPMMNPPMMPMMM
+  MMALPPLALPPLAMMM
+  MMAPPPPAPPPPAMMM
+  MMAPAAPAPAAPAAMM
+  MMAPPPPAPPPPAAAM
+  MMBIIIIJJJIIIBAA
+  MBPPPIIIIIIPPPBA
+  MPPPFPIIIIPFPPPA
+  MPPAAPIIIIPAAPPA
+  MPPAAIIIIIIAAPPA
+  MBPBMIIFFIIABPAA
+  MMPPMBPAABPAPPAA
+  MMMMMBPAABPAAAAA
+  MMMPPPPAMBPPPFAA
+}
+# tile 177 (titan)
+{
+  MMMMMAAAAAAAMMMM
+  MMMMAALLLLAAAMMM
+  MMMMAMMLLMMAAMMM
+  MMMMALLLLLLAAMMM
+  MMMMALLAALLAAAMM
+  MMMMMALLLLJAAAAM
+  MMCCJJJJJJJJCCAM
+  MCLLLCCKCKCLLLCA
+  MLLLKJKCKCJKLLLA
+  MLLAAJJCCJJAALLA
+  MLLAAJJCCJJAALLA
+  MLLAAJJJKKJAALLA
+  MCLCMJJJJJKKCLAA
+  MMLLMCLJACLJLLAA
+  MMMMMCLJACLJAAAA
+  MMMLLLLJMCLLLKAA
+}
+# tile 178 (minotaur)
+{
+  MMMMMMMMMMMMMMMM
+  MOMMMMMMMMMMOMMM
+  MOOOJJJJJJOOOMMM
+  MMOOJJKJJJOOMMMM
+  MMMJGAKJGAJAMMMM
+  MMMJJJKJJJJAMMMM
+  MMMMJJKJJJAAAMMM
+  MMMMJKKKJAAAAMMM
+  MMCLJAJAKALCAAMA
+  MCLLJJJJJALLCAAA
+  MLLCLAAAALCLLAAM
+  MLAACLLLLCAALAAM
+  MLLMJJJJJJJLLAAA
+  MLLMJJJJJJJLLAAA
+  MMMMCLCACLCAAAAA
+  MMLLLLLMLLLLLAAM
+}
+# tile 179 (jabberwock)
+{
+  MMMMMMMMMMMMMMMM
+  MMMDPMMMMMMMMMMM
+  MMMMDPMADOOMMMMM
+  MMDAIDADIPADMMMM
+  MMMDIAPIPAMMMMMM
+  MMMDBDDDAMMMMMMM
+  MMIBBDADDAMMAAMM
+  MDDDDAODDIAAAAMM
+  MMOAOAMDDAIAAAMM
+  MMIOAODDAAADDAAM
+  MMDDDADDDDAIDAMM
+  MMMAAADDIDIDDDMM
+  MMMMIDDAIDDDDAMM
+  MMMMIDAAIDAAMMMM
+  MMMIDAAMMIDMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 180 (vorpal jabberwock)
+{
+  MMMMMMMMMMMMMMMM
+  MMMGPMMMMMMMMMMM
+  MMMMGPMAGOOMMMMM
+  MMGAFGAGFPAGMMMM
+  MMMGFAPFPAMMMMMM
+  MMMGHGGGAMMMMMMM
+  MMFHHGAGGAMMAAMM
+  MGGGGAOGGFAAAAMM
+  MMOAOAMGGAFAAAMM
+  MMFOAOGGAAAGGAAM
+  MMGGGAGGGGAFGAMM
+  MMMAAAGGFGFGGGMM
+  MMMMFGGAFGGGGAMM
+  MMMMFGAAFGAAMMMM
+  MMMFGAAMMFGMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 181 (Keystone Kop)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMAAAAMMMMMMMMM
+  MMMAOAAMMMCMMMMM
+  MMAAAAAAMMCMMMMM
+  MMMLLLLMMMCMMMMM
+  MMMMLLMMMMCMMMMM
+  MMMAAAAMAAAMMMMM
+  MMAAAAAAAACMPMMM
+  MAAMAAAAAMPPPPMM
+  MMAAAAAAMPPPPPPM
+  MMMMAAAAPPPAPPMM
+  MAMAAAAAAPAAAMMM
+  AAAAAMPAAAAAMMMM
+  MMAAMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 182 (Kop Sergeant)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMAOOAMMMMMMMMM
+  MMMAOOAMMMCMMMMM
+  MMAAAAAAMMCMMMMM
+  MMMLLLLMMMCMMMMM
+  MMMMLLMMMMCMMMMM
+  MMMAAAAMAAAMMMMM
+  MMAAAAAAAACMPMMM
+  MAAMAAAAAMCPPPMM
+  MMAAAAAAMPPPPPPM
+  MMMMAAAAPPPAPPMM
+  MAMAAAAAAPAAAMMM
+  AAAAAMPAAAAAMMMM
+  MMAAMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 183 (Kop Lieutenant)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMAOOAMMMCMMMMM
+  MMMAOOAMMMCMMMMM
+  MMAAAAAAMMCMMMMM
+  MMMLLLLMMMCMMMMM
+  MMMMLLMMMMCMMMMM
+  MMOAAAOMAAAMMMMM
+  MOAAAAAMAACMPMMM
+  MAAMAAAAAMCPPPMM
+  MMAAAAAAMPPPPPPM
+  MMMMAAAAPPPAPPMM
+  MAMAAAAAAPAAAMMM
+  AAAAAMPAAAAAMMMM
+  MMAAMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 184 (Kop Kaptain)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMAAMMMMCMMMMM
+  MMMAHHAMMMCMMMMM
+  MMMAHHAMMMCMMMMM
+  MMAAAAAAMMCMMMMM
+  MMMLLLLMMMCMMMMM
+  MMMMLLMMMMCMMMMM
+  MHHAAAAHHAAMMMMM
+  MAAAAHAAAACCCMMM
+  MAAMAHAAAMCPPPMM
+  MMAAAHAAMPCPPPPM
+  MMMMAAAAPPPAPPMM
+  MAMAAAAAAPAAAMMM
+  AAAAAMPAAAAAMMMM
+  MMAAMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 185 (lich)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMOOOMMMMMMMMMM
+  MMAOAOOMMMMMMMMM
+  MMOOOOOMMMMMMMMM
+  MMOOMOMMMMMMMMMM
+  MMMMMPPPMMMMMMMM
+  MMMOOPPPMMMMAAAM
+  MMOMPPPPPAMMAAAM
+  MOMMMPPPPMAAAAAM
+  MMMMOMPPPAAAAMAM
+  MMMMMMPPPAAAMAMM
+  MMMMMOPAPMAMMMMM
+  MMMOOOAMOAMMMMMM
+  MMMMMMOOOMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 186 (demilich)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMOOOMMMMMMMMMM
+  MMAOAOOMMMMMMMMM
+  MMOOOOOMMMMMMMMM
+  MMOOMOMMMMMMMMMM
+  MMMMMPPPMMMMMMMM
+  MMMOOPPPMMMMAAAM
+  MMOMPPPPPAMMAAAM
+  MOMMMPPPPMAAAAAM
+  MMMMLMPPPAAAAMAM
+  MMMMMMLPPAAAMAMM
+  MMMMMLLALMAMMMMM
+  MMMLLLAMLAMMMMMM
+  MMMMMMLLLMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 187 (master lich)
+{
+  MMMHMMMMMMMMMMMM
+  MMMHCHMHMMMMMMMM
+  MMMHHHCHMMMMMMMM
+  MMAOAOHHMMMMMMMM
+  MMOOOOOMMMMMMMMM
+  MMOOMOMMMMMMMMMM
+  MMMMMPPPMMMMMMMM
+  MMMPPPPPMMMMAAAM
+  MMPPPPPPPAMMAAAM
+  MOMMPPPPPMAAAAAM
+  MMMMOPPPPAAAAMAM
+  MMMMMMPPPAAAMAMM
+  MMMMMOPAPMAMMMMM
+  MMMOOOAMOAMMMMMM
+  MMMMMMOOOMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 188 (arch-lich)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMOOOMMMMMMMMMM
+  MMDODOOMMMMMMMMM
+  MMOOOOOMMMMMMMMM
+  HMOOMOMMMMMMMMMM
+  AMMMMPPPMMMMMMMM
+  AMMOOPPPMMMMAAAM
+  MAOMPPPPPAMMAAAM
+  MOMMMPPPPMAAAAAM
+  MAMMOMPPPAAAAMAM
+  MMAMMMPPPAAAMAMM
+  MMAMMOPAPMAMMMMM
+  MMAOOOAMOAMMMMMM
+  MMMMMMOOOMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 189 (kobold mummy)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMMMNMMMMMMMM
+  MMMNONONOMMMMMMM
+  MMMOAOAOMOPMMMMM
+  MMMMONNMMMAMMMMM
+  MMMONODNAMAAMMMM
+  MMOLONNONAAAMAMM
+  MMNALONANAAAAAMM
+  MMNAOLOAOAAAAAMM
+  MMMMNOLAAAAAAMMM
+  MMMMNANAAAAMMMMM
+  MMMOOANOAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 190 (gnome mummy)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMGMMMMMMMMM
+  MMMMMGGFOMMMMMMM
+  MMMMGGFFOOPMMMMM
+  MMMMGDODFMMMMMMM
+  MMMMMONOMMMAAAMM
+  MMMNONOONOAAAAMM
+  MMMOANLOAOAAAAMM
+  MMMMNNOLOAAAAMMM
+  MMMMNOANDAAMMMMM
+  MMMMNOAOOMAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 191 (orc mummy)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOAMMMMMMMMM
+  MMMMNOOPMMMMMMMM
+  MMMMDODPOPMMMMMM
+  MMMMOOOAMMMMMMMM
+  MMOOOOOOOAMAAMMM
+  MMOOOOOOOMAAAMMM
+  MMOAOOOAACCCMMMM
+  MMOAOOOCCAAAMMMM
+  MMMMOCCOAAAAAAMM
+  MMMCCAOOAAAAMMMM
+  MMOOOAOOOAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 192 (dwarf mummy)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMBMMMMMMMMM
+  MMMMMBBEOMMMMMMM
+  MMMMBBEEEOPMMMMM
+  MMMMBDODEMMMMMMM
+  MMMMMONOMMMAAAMM
+  MMMNONOONOAAAAMM
+  MMMOANLOAOAAAAMM
+  MMMMNNOLOAAAAMMM
+  MMMMNOANDAAMMMMM
+  MMMMNOAOOMAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 193 (elf mummy)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMOMMMMMM
+  MMMMMMMOOOPMMMMM
+  MMMMMMOOOOPMMMMM
+  MMMMMMOEOEAPMMMM
+  MMMMMMOOOOAMMMMM
+  MMMMMMAOOAMMMMAM
+  MMMMMMOAAOMMAAAM
+  MMMMMOOOOOOAAAAM
+  MMMMOALOOLAOAAAM
+  MMMMOADOOOAOAAMM
+  MMMMMMOOAOAAMAMM
+  MMMMMOOAMOOAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 194 (human mummy)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMONNOMMMMMMMMM
+  MMMNNNNOPMMMMMMM
+  MMPANANMOPPMMMMM
+  MMPNNNNMMMMMMMMM
+  MMONOONNPMMMMMMM
+  MONLNNOOOMMMMMMM
+  MNJNOOOOOMMAAAMM
+  MOJOOOODNMAAAAMM
+  MNJOLNOAOAAAAAAM
+  MOCNOMNKNAAAAAMM
+  MNMOOMOLAAAAAAAM
+  MMMOOAOOAAAMMMMM
+  MMNNNMNNNAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 195 (ettin mummy)
+{
+  MMMMMNNMMONOOMMM
+  MMMNNOOONNOOOOMM
+  MMMNOOOONOOOOOOM
+  MMMOFOFOLOFOFOMO
+  MMMOOOOOLOOOOOMP
+  MMMNOOOOLNNOOOAM
+  MMMONOOOLOOOOAAA
+  MMOOOONNNNNNNOAA
+  MONNNNNNOONOOOOA
+  MONODNNOOOOOOOOA
+  MNNAAONNONOAAOOA
+  MNOAAONOONLAAOOA
+  MOOOMONOONOOOOAA
+  MMOOMNNOANOLOOAA
+  MMMMMNOOANOOAAAA
+  MMMOOOOOMOOOOKAA
+}
+# tile 196 (giant mummy)
+{
+  MMMMMMONOOAAMMMM
+  MMMMONNNOOOOAMMM
+  MMMMNNOOOOOOOMMM
+  MMMMNFFOOFFOOPMM
+  MMMMNONOOOOOAOPM
+  MMMMAONOOOOAAAPM
+  MMMMMANOOODAAAAM
+  MMOOOONOOONNNOAA
+  MONNNNNOOOOOOOOA
+  MONODNNLOOOOOOOA
+  MNNAAONOLNOAAOOA
+  MNOAAONOONLAAOOA
+  MOOOMONOONOOOOAA
+  MMOOMNNOANOLOOAA
+  MMMMMNOOANOOAAAA
+  MMMOOOOOMOOOOKAA
+}
+# tile 197 (red naga hatchling)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKMMMMMMMMMMM
+  MMMKLKMMMMMMMMMM
+  MMMLLLAMMMMMMMMM
+  MMMALAAMMMMMMMMM
+  MMMLALAMMMMMMMMM
+  MMMLLLAMMMMMMMMM
+  MMMLLLAAMMMMMMMM
+  MMMLDLAAMMMMMMMM
+  MMMIDDAAAAADAMMM
+  MMMIDDDAAADDAMMM
+  MMMMIIDDDDDAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 198 (black naga hatchling)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKMMMMMMMMMMM
+  MMMKLKMMMMMMMMMM
+  MMMLLLAMMMMMMMMM
+  MMMALAAMMMMMMMMM
+  MMMLALAMMMMMMMMM
+  MMMLLLAMMMMMMMMM
+  MMMLLLAMMMMMMMMM
+  MMMLALAAMMMMMMMM
+  MMMAAAPAMMPAAMMM
+  MMMAAAAPPPAAAMMM
+  MMMMAAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 199 (golden naga hatchling)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKMMMMMMMMMMM
+  MMMKLKMMMMMMMMMM
+  MMMLLLAMMMMMMMMM
+  MMMALAAMMMMMMMMM
+  MMMLALAMMMMMMMMM
+  MMMLLLAMMMMMMMMM
+  MMMLLLAAMMMMMMMM
+  MMMLHLAAMMMMMMMM
+  MMMNHHAAAAAHAMMM
+  MMMNHHHAAAHHAMMM
+  MMMMNNHHHHHAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 200 (guardian naga hatchling)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKMMMMMMMMMMM
+  MMMKLKMMMMMMMMMM
+  MMMLLLAMMMMMMMMM
+  MMMALAAMMMMMMMMM
+  MMMLALAMMMMMMMMM
+  MMMLLLAMMMMMMMMM
+  MMMLLLAAMMMMMMMM
+  MMMLFLAAMMMMMMMM
+  MMMGFFAAAAAFAMMM
+  MMMGFFFAAAFFAMMM
+  MMMMGGFFFFFAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 201 (red naga)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMKKMMMMMMMMMM
+  MMMKLLKMMMMMMMMM
+  MMMLLLLAMMMMMMMM
+  MMMALLAAMMMMMMMM
+  MMMLAALAMMMMMMMM
+  MMMLLLLAMMMMMMMM
+  MMMLLLDAMMAAMMMM
+  MMMLDLDAMAAAAMMM
+  MMMIDDDAAAIIAMMM
+  MMMIDDDAIDDDIDAM
+  MMMIDDDIDDDDDDDA
+  MMMIDDDDDDAAMDDA
+  MMMMDDDDDAMMDDAM
+  MMMMMDDAAMMDDAMM
+  MMMMMMMMMMDAMMMM
+}
+# tile 202 (black naga)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMKKMMMMMMMMMM
+  MMMKLLKMMMMMMMMM
+  MMMLLLLAMMMMMMMM
+  MMMALLAAMMMMMMMM
+  MMMLAALAMMMMMMMM
+  MMMLLLLAMMMMMMMM
+  MMMLLLAAMMMMMMMM
+  MMMLALAAMMPPPMMM
+  MMMAAAAPPPAAPMMM
+  MMMAAAAPAAAAAAPM
+  MMMAAAAAAAAAAAAP
+  MMMAAAAAAAPPMAAP
+  MMMMAAAAAPMMAAPM
+  MMMMMAAPPMMAAPMM
+  MMMMMMMMMMAPMMMM
+}
+# tile 203 (golden naga)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMKKMMMMMMMMMM
+  MMMKLLKMMMMMMMMM
+  MMMLLLLAMMMMMMMM
+  MMMALLAAMMMMMMMM
+  MMMLAALAMMMMMMMM
+  MMMLLLLAMMMMMMMM
+  MMMLLLHAMMAAMMMM
+  MMMLHLHAMAAAAMMM
+  MMMNHHHAAANNAMMM
+  MMMNHHHANHHHNHAM
+  MMMNHHHNHHHHHHHA
+  MMMNHHHHHHAAMHHA
+  MMMMHHHHHAMMHHAM
+  MMMMMHHAAMMHHAMM
+  MMMMMMMMMMHAMMMM
+}
+# tile 204 (guardian naga)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMKKMMMMMMMMMM
+  MMMKLLKMMMMMMMMM
+  MMMLLLLAMMMMMMMM
+  MMMALLAAMMMMMMMM
+  MMCLAALCMMMMMMMM
+  MMLLLLLLMMMMMMMM
+  MMCLLCLCMMAAMMMM
+  MMMCLLCAMAAAAMMM
+  MMMGLFCAAAGGAMMM
+  MMMGFFFAAFFFGFAM
+  MMMGFFFGFFFFFFFA
+  MMMGFFFFFFAAMFFA
+  MMMMFFFFFAMMFFAM
+  MMMMMFFAAMMFFAMM
+  MMMMMMMMMMFAMMMM
+}
+# tile 205 (ogre)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMCLLLCMMMMMMM
+  MMLCKKLKKCLMMMMM
+  MMMLAALAALJAMMMM
+  MMMCLLLLLCJAMMMM
+  MMMMCAAACJAAAMMM
+  MMMMLDDDLAAAAMMM
+  MMCLJLLLKALCAAMA
+  MCLLAJJJJALLCAAA
+  MLLCLAAAALCLLAAM
+  MLAACLLLLCAALAAM
+  MLCMHHHBHHACLAAA
+  MLLMJJJJJJALLAAA
+  MMMMCJJJCLAAAAAA
+  MMLLLLLMLLLLLAAM
+}
+# tile 206 (ogre lord)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMCLLLCMMMMMMM
+  MMLCKKLKKCLMMMMM
+  MMMLAALAALJAMMMM
+  MMMCLLLLLCJAMMMM
+  MMMMCLLLCJAAAMMM
+  MMMMLAAALAAAAMMM
+  MMJKJLLLKAKJAAMA
+  MCLKAJJJJAKLCAAA
+  MLLJKAAAAKJLLAAM
+  MLAAJKKKKJAALAAM
+  MLCMHHHBHHACLAAA
+  MLLMJJJJJJALLAAA
+  MMMMCJJJCLAAAAAA
+  MMLLLLLMLLLLLAAM
+}
+# tile 207 (ogre king)
+{
+  MMMHMMCMMHMMMMMM
+  MMMHDCHCDHMMMMMM
+  MMMHHHHHHHMMMMMM
+  MMLCKKLKKCLMMMMM
+  MMMLAALAALJAMMMM
+  MMMCLLLLLCJAMMMM
+  MMMMCLLLCJAAAMMM
+  MMMMLAAALAAAAMMM
+  MMJKJLLLKAKJAAMA
+  MCJKAJJJJAKJCAAA
+  MLJJKAAAAKJJLAAM
+  MLAAJKKKKJAALAAM
+  MLCMHHHBHHACLAAA
+  MLLMJJJJJJALLAAA
+  MMMMCJJJCLAAAAAA
+  MMLLLLLMLLLLLAAM
+}
+# tile 208 (gray ooze)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPBPAMMMMMMM
+  MMMPBBBPBAMMMMMM
+  MMBBNNBPPBAAMMMM
+  MBBNNPPPBBPAAAMM
+  PBBBPPPBPBBAAAMM
+  BBBPBPPPPPBPAAAM
+  BBPBPPPPPPPBAAAM
+  PBPPBPPPBBPPAAAM
+  MPBBPPPBAAPPPAAM
+  MMMPBBBAAAKPPJMM
+  MMMMMMMMACPPAKMM
+  MMMMMMMMMKCCCJMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 209 (brown pudding)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMJMMM
+  MMMMJKKJJJMMJJMM
+  MMMKKKCJJJJJMMMM
+  MMKKNNJNNJJJMMMM
+  MMKJANJANJJJAMMM
+  MMKKJJJJJCJJAAMM
+  MMJKJJCJJJJJAAMM
+  MMMJJJJJJJJAAAMM
+  MMMMJJJJJJAAAMMM
+  MMMMMAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 210 (black pudding)
+{
+  MMMMMMMMAMMMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMAAAMMMMMMMM
+  MMMMAAAAAMMMMMMM
+  MMMMCACAAMMMMMMM
+  MMMMDADAAMMMMMMM
+  MMMMAAAAAMMMMMMM
+  MMMMAAAAAMMMMMMM
+  MMMMAAAAAMMMMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMAAAAAAMMMM
+  MMMMMMMAAAAAAMAM
+  MMMMMMMMAAAAAAAA
+  MMMMMMMMMMAAAAMM
+}
+# tile 211 (green slime)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMGMMM
+  MMMMMGMMMMMMGMMG
+  MGMMMMGMMGMNGNMG
+  MMNGMNGGNGGGGGGG
+  MMGGNGGNGGGFGGFM
+  GGNGGGGGGGGGFFMG
+  MNGGGGGFGFGMMMMM
+  NGGGGFGGFGMGMMGF
+  NGGFGGFMMGFMMMMM
+  MMGGFMMGGFMMGMMM
+}
+# tile 212 (quantum mechanic)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMLLLLMMMMMM
+  MMMFGGCLCGGFMMMM
+  MMMGNNGLGNNGLMMM
+  BMBGANGGGANGLMMM
+  BMBFGGCLCGGFLMMM
+  BIBMMCLLLCCLMMMM
+  BILNMLLAALLAAAAM
+  BILNNMLLLLJAAAAM
+  BIBMNNJJJJNAAAMM
+  BIBMBNNNONNNAAMM
+  MBMMMNNNONNLAAMM
+  MMMMMNBEBENAMAMM
+  MMMMMNBEBENNMMMM
+  MMMMNAAEBAANNMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 213 (rust monster)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMEEEEMMMMMMMM
+  MMMEEHEHEMMMMMMM
+  MMMEEEAEEMMMMMMM
+  MMMEEPAPEMMMMMMM
+  MMMEPEAEPMMMEMMM
+  MMMMEEEEMAAEEMMM
+  MMMMEEEEEAAEEEMM
+  MMMEEEEEEEAEAEEM
+  MMEEEEEEAAAAEMMM
+  MMEEAEEEEAEEEAMM
+  MMAAEEEEEEEEEAAM
+  MMMMAEEEEEEEAAAM
+  MMMMMEEEEEAAMMAM
+  MMMMMMAAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 214 (disenchanter)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMPPPPMMMMMMMM
+  MMMPPDPDPMMMMMMM
+  MMMPPPAPPMMMMMMM
+  MMMPPOAOPMMMMMMM
+  MMMPOPAPOMMMPMMM
+  MMMMPPPPMAAPPMMM
+  MMMMPPPPPAAPPPMM
+  MMMPPPPPPPAPAPPM
+  MMPPPPPPAAAAPMMM
+  MMPPAPPPPAPPPAMM
+  MMAAPPPPPPPPPAAM
+  MMMMAPPPPPPPAAAM
+  MMMMMPPPPPAAMMAM
+  MMMMMMAAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 215 (garter snake)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKKAMMMMMMMMM
+  MMMNAOKAMMMMMMMM
+  MMMKKAKAMMMMMMMM
+  MMMKKAKAMMMMKAMM
+  MMMMAPKAPMMKAPPM
+  MMMMMPKAPPMKAPMM
+  MMMMMKAAPMMKAPMM
+  MMMMKAAPMMKAAPMM
+  MMMMKAAPPKAAPMMM
+  MMMMKAAKKAAPMMMM
+  MMMMMKAAAAPMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 216 (snake)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKKAMMMMMMMMM
+  MMMNAOJAMMMMMMMM
+  MMMKKJAJMMMMMMMM
+  MMMKKAAJMMMMKKMM
+  MMMFAAKJMMMKJAAM
+  MMFAFAKJAAMKJAMM
+  MMMMMKJAAMMKJAMM
+  MMMMKJAAMMKJJAMM
+  MMMMKJAAAKJJAMMM
+  MMMMKJJJJJJAMMMM
+  MMMMMKJJJJAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 217 (water moccasin)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMAAAMMMMMMMMM
+  MMMAAAAAMMMAAMMM
+  MMMOAOAAAMAAMMMM
+  MMMAAAMAAMAAMMMM
+  MMMDAMMAAMAAMMMM
+  MMDMDMAAAMMAAMMM
+  MMMMMAAAMMMAAMMM
+  MMMMMAAAMMMAAMMM
+  MMMMAAAMMMAAAMMM
+  MMMMAAAAAAAAMMMM
+  MMMMAAAAAAAMMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 218 (pit viper)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMAAAMMMMMMMMM
+  MMMAAAAAMMMAAAMM
+  MMMOAAAAAMAAMAAM
+  MMMAAMMAAMAAMAAM
+  MMMDMMMAAMAAMMAM
+  MMMMMMAAAMMAAMAM
+  MMMMMMAAMMMAAMMM
+  MMMMMAAAMMMAAMMM
+  MMMMMAAMMMAAAMMM
+  MMMMMAAMMAAAMMMM
+  MMMMMAAAAAAMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 219 (python)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMKKKAMMMMMJJMM
+  MMMGAGJAMMMJJJMM
+  MMJKKJAJMMKJJMMM
+  MMKKKAJJMMKJJMAA
+  MMKKAAKJAMKKJAAM
+  MMMMMAKJAAMKJAAM
+  MMMMJKJAAMMKJJAM
+  MMMJJJAAMMKJJJAM
+  MMMJJJAAAKJJJAMM
+  MMMJJJJJJJJJAAMM
+  MMMMJJJJJJJAAMMM
+  MMMMMJJJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 220 (cobra)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMAAAMMMMMMMMM
+  MMMAAAAAAMMMMMMM
+  MMPAMMAAAAMMMMMM
+  MMAMMAAAAAMMAAMM
+  MMDMMAAAAAMMMMAM
+  MMMMMMAAAMMMMMAM
+  MMMMMMAAMMAAAAMM
+  MMMMMAAMMAAMMMMM
+  MMMMAAMMMAAMMMMM
+  MMMMAAMMMMAAAAMM
+  MMMMAAAMMMMMMAAM
+  MMMMMAAAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 221 (troll)
+{
+  MMMMMMMMMMMMMMMM
+  MMAAAAAAMMMMMMMM
+  AAAANANAMMMMMMMM
+  MAAKKKJJAMMMMMMM
+  AAAKAAAKAMMMMMMM
+  AKAKAAAKAAMMMMMM
+  KJJAKKKAJKAMMMMM
+  KJAJAAAJJJAMMMMM
+  KJAJKKJJKJAMMMMM
+  MKJJAFGFJJAAAAMM
+  MMKJAMPFJAAAAMMM
+  MMMAFAGFAAAAAAMM
+  MMMGFAGPMAAMAAMM
+  MMKJJAKJAAMAAMMM
+  MMKJAMMKAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 222 (ice troll)
+{
+  MMMMMMMMMMMMMMMM
+  MMOONOOOMMMMMMMM
+  NONOAOAOOMMMMMMM
+  MNOKKKJJOMMMMMMM
+  NOJKAAAKOOMMMMMM
+  OKJKAAAKAOMMMMMM
+  KJJAKKKAJKAMMMMM
+  KJAJAAAJJJAMMMMM
+  KJAJKKJJKJAMMMMM
+  MKJJAEBEJJAAAAMM
+  MMKJAMPEJAAAAMMM
+  MMMAEABEAAAAAAMM
+  MMMBEABPMAAMAAMM
+  MMKJJAKJAAMAAMMM
+  MMKJAMMKAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 223 (rock troll)
+{
+  MMMMMMMMMMMMMMMM
+  MMMAAAAAMMMMMMMM
+  MAAANANAAAAMMMMM
+  MAAKKKJJAAMMMMMM
+  AAAKAAAKAAAAMMMM
+  AKAKAAAKAAAMMMMM
+  KJJAKKKAJKAAMMMM
+  KJAJAAAJJJAMMMMM
+  KJAPAKJJKJAMMMMM
+  PKJPPAGFJJAAAAMM
+  PPPPPAFFJAAAAMMM
+  MPPPAAGFAAAAAAMM
+  MMMAFAGFMAAMAAMM
+  MMKJJAKJAAMAAMMM
+  MMKJAMMKAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 224 (water troll)
+{
+  MMMMMMMMMMMMMMMM
+  MMMAAAAAMMMMMMMM
+  MMAANANAAMMMMMMM
+  MAAKKKJJAAMMMMMM
+  MAAKAAAKAAMMMMMM
+  MKAKAAAKAAMMMMMM
+  KJJAKKKAJKAMMMMM
+  KJAJAAAJJJAMMMMM
+  KJAJKKJJKJAMMMMM
+  MKJJAEBEJJAAAAMM
+  MMKJAMPEJAAAAMMM
+  MMMAEABEAAAAAAMM
+  MMMBEABPMAAMAAMM
+  MMKJJAKJAAMAAMMM
+  MMKJAMMKAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 225 (Olog-hai)
+{
+  MMMPPPPPMMMMMMMM
+  MMPPAAAPPMMMMMMM
+  MMPANANAPMMMMMMM
+  MMPAAAAAPMMMMMMM
+  MPPAAAAAPPMMMMMM
+  PPPAAAAAPPPMMMMM
+  AAPPAAAPPAAMMMMM
+  AAAPPPPPAAAMMMMM
+  AAAPPPPPAAAMMMMM
+  MAAAAPPPAAAPPPMM
+  PONNNNNNAACPPMMM
+  MMMAPAPPAPPPPPMM
+  MMMPPAPPMPPMPPMM
+  MMAAAAAAAPMPPMMM
+  MMAAAMAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 226 (umber hulk)
+{
+  MMMMMMMMMMMMMMMM
+  MMMAAAAAMMMMMMMM
+  MMAAAAAAAMMMMMMM
+  MADADADADAMMMMMM
+  MAAAAAAAAAMAMMMM
+  MAAAOAOAAAMAAMMM
+  MAMAOAOAMAAAMMMM
+  MAMAAAAAPAAMMMMM
+  MAAAAAAAPMMMMMMM
+  MAMAAAAAMPPPPPPM
+  MMMAAMAAMPPPPPMM
+  MMMAAMAAPPPPPPPM
+  MMMAAPAAPPPPMMMM
+  MMAAAPAAAPPMMMMM
+  MAAAPMMAAPMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 227 (vampire)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMAAAMMMMMMMM
+  MMMMAAOAAMMMMMMM
+  MADDAGAGADAMMMMM
+  MMADALLOADMMMMMM
+  MAAAAAAAAAMMMMMM
+  MMAAAAAAAAMMMMMM
+  MMMAAAAAAAMMMMMM
+  MMADAAAAAAPPPPPM
+  MMADDAAAAAPPPPMM
+  MMAAAAAAAAPPPMMM
+  MMMMMAAPAAPPMMMM
+  MMMMAAPMMAPMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 228 (vampire lord)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMAAAAMMMMMMM
+  MNMMAAOOAAMMMMMM
+  MNDDAGAAGADAMMMM
+  MNADALLLOADMMMMM
+  AAAAAAAAAAAMMMMM
+  AAAAAAAAAAAMMMMM
+  MAAAAAAAAAAMMMMM
+  MNAAAAAAAAAMMMMM
+  MNMAAAAAAAAPPPPP
+  MNADAAAAAAAPPPPP
+  MNADDAAAAAAPPPPM
+  MNAAAAAAAAAPPPMM
+  MNMMMAAAPAAPPMMM
+  MNMMAAPPMMAPMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 229 (vampire mage)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMAAAMMMMMMMM
+  MMMMAAOAAMMMMMMM
+  MADDAGAGADAMMMMM
+  MMADALLOADMMMMMM
+  MAAAAMAMAAMMMMMM
+  MMAAAACAAAMMMMMM
+  MMMAAADAAAMMMMMM
+  MMADAAAAAAPPPPPM
+  MMADDAAAAAPPPPMM
+  MMAAAAAAAAPPPMMM
+  MMMMMAAPAAPPMMMM
+  MMMMAAPMMAPMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 230 (Vlad the Impaler)
+{
+  MMMMMMMMMMMMMMMM
+  MMNMMAAAAMMMMMMM
+  ADNDAAOOAADDDAMM
+  MANDAGAAGADDAMMM
+  MMNDALLLOADAMMMM
+  MMNAAAAAAAAAAAAA
+  MHHHDAAAAADDDDDA
+  HEHEHJAAAADDDAAM
+  LLLLLJAAAADDAAPP
+  MLLLJAAAAADDAPPP
+  MMNJDAAAAADAPPPP
+  MANDDAAAAAAAPPPP
+  MANAAAAAAAAPPPPM
+  MMNMMAAAPAAPPPMM
+  MMNMAAPPMMAPMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 231 (barrow wight)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMLLOMMMMMMMMMM
+  MMDLDLOMMMMMMMMM
+  MMLLLLOMMMMMMMMM
+  MMLJLMMPMMMMMMMM
+  MMOOOMPPMMMAAAAM
+  MMPOOMPPMAAAAAAM
+  MLPOOMPPMPAAAAMM
+  MJJOOMPPMPAAAAMM
+  MJMOMMPLMPPAAAMM
+  MJMOMPPPPPPAAAMM
+  MJMMMPPPPPPPAAMM
+  MJMMLLPPPPPPAMMM
+  MJMMMMMLLAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 232 (wraith)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMPPPPPMMMMMMMM
+  MMMPAAPPPMMMMMMM
+  MMMMPAAPPMMMMMMM
+  MMMMPAAPPMMMMMMM
+  MMPPMPPPMPMMMMMM
+  MOLAPPPMPPMMMMMM
+  MMAAPPPPAPMMAAAM
+  MMPPPPPOLPAAAAAM
+  MMMAMPPAAAAPPAMM
+  MMMMMPPAPPPPAMMM
+  MMMMMMPPPPAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 233 (Nazgul)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMPPPPPMMMMMMMM
+  MMMPAAPPPMMMMMMM
+  MMMMPAAPPMMMMMMM
+  MMMMPAAPPMMMMMMM
+  MMPPMPPPMPMMMMMM
+  MOLAPPPMPPMMMMMM
+  MOPAPPPPAPMMAAAM
+  MMPAPPPPAPMMAAAM
+  MMPAMPPPLPMMAAAM
+  MMPPMPPOLPAAAAAM
+  MMMAAPPOAAAPPAMM
+  MMMMMPPAPPPPAMMM
+  MMMMMMPPPPAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 234 (xorn)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMOBMOPMBPMMMMM
+  MMMBBBBPPPPMMMMM
+  MMMBMMMMMMMMMMMM
+  MMMDDBBMBDDAMAMM
+  MMMDDBBMPDDAAAAM
+  MMMBMMMMMMMAAAAM
+  MMMBOBMBPPMAAAAM
+  MMMBBBMPPPMAAAAM
+  MMMBMMMMMMMAAAMM
+  MMMBOBBPPBPAAMMM
+  MMMBOMBPMPPAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 235 (monkey)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMKKAMMMMMM
+  MMMMMMKLLJAMMMMM
+  MMMMMMKLLJAMMMMM
+  MMMMMMMKJAMMMMMM
+  MMMMMKKKKKJAAMMM
+  MMMMKJKLLJJJAAMM
+  MMMMLAKLLJALAAMM
+  MMMMMMKJJJAAAAMM
+  MMMMMMJAAJAAAMMM
+  MMMMMJJAMJJAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 236 (ape)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMKKKJMMMMMM
+  MMMMMJJJJJJMMMMM
+  MMMMKCELECJJMAAM
+  MMMMKLLLLCAJAAAA
+  MMMKKCLACCAJJAAA
+  MMKKKKCCCAJKJJAA
+  MMKKAKJAAJJAJJAA
+  MMKAAKJJJJJAAJAA
+  MMLCMKJJJJJKCLAA
+  MMLLMCJJAKLJLLAA
+  MMMMMCLJACLJAAAA
+  MMMLLLLJACLLLKAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 237 (owlbear)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMKMMMMMKMMMMM
+  MMMMCKMMMKKMMMMM
+  MMMMCKKKKKKMMMMM
+  MMMKOOOKOOOKMMMM
+  MMMKOOOKOOOKAMMA
+  MMMKOOAJAOOKAAAA
+  MMCKCJJHJJKAKAAA
+  MCKKKCKLKKAJJKAA
+  MKJJJJCKKJJJJJAA
+  MKJJJPAKJPJJJJAA
+  MMKJJJAKJJJJJAAA
+  MMMJJPAKJPJJAAAM
+  MMMJAAJAJAAJAAMM
+  MMMPJPJAJPJPAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 238 (yeti)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMBNNNMMMMMMMM
+  MMMBNANAPMMMMMMM
+  MMBNNNNNNPMMMMMM
+  MMNNNADANNMMMMMM
+  MMNNNNNNPNMMMMMM
+  MMNMNNBPPNPMMMMM
+  MMNMNNNNANPMMAAM
+  MMNNBNNNPNMAAAAM
+  MMMMNNNNPMKAAAMM
+  MMMMNNMNPAKKAAMM
+  MMMMNBMNPAACKAAM
+  MMMMNNANPAAKKJAM
+  MMMBNNANNPAACKAM
+  MMBNNAMMNNAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 239 (carnivorous ape)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMKKKJMMMMMM
+  MMMMMJJJJJJMMMMM
+  MMMMKCELECJJMAAM
+  MMMMKLLLLCAJAAAA
+  MMMKKCAAACAJJAAA
+  MMKKKCDDDCAKJJAA
+  MMKKAKCCCAJAJJAA
+  MMKAAKJAAJJAAJAA
+  MMLCMAJJJJJKCLAA
+  MMLLDDAJAKLJLLAA
+  MMMDDALJACLJAAAA
+  MMDDALLJACLLLKAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 240 (sasquatch)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMCCCCCMMMMMMM
+  MMMCGAJGAJMMMMMM
+  MMCKKKKJJJMMMMMM
+  MMCKKAAAKJJMMMMM
+  MCKKKAAAKKJMMMMM
+  MCKJKKKKKKKJMMMM
+  MCKAJJJJJAKJMMMM
+  MCKAJKKKJAKJMAAM
+  MCKJAJKJACKJAAAA
+  MCKJAJJJACKJAAAM
+  MMJMAJAKKAJAAAAA
+  MMMCKJAKKJAAAAAM
+  MKCKJJACKJKJAAMM
+  MCJJJKACKJJKAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 241 (kobold zombie)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMMMNMMMMMMMM
+  MMMNGFBNMMMMMMMM
+  MMMGABABMMMMMMMM
+  MMMMGBFAMMAMMMMM
+  MMMGBABFAMAAMMMM
+  MMGFBBBIKAAAMAMM
+  MMBAFBFFEAAAAAMM
+  MMBAFBFFAAAAAAMM
+  MMMMFBFAAAAAAMMM
+  MMMMBABAAAAMMMMM
+  MMMBBABBAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 242 (gnome zombie)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMGMMMMMMMMM
+  MMMMMGFFMMMMMMMM
+  MMMMGGFFFMMMMMMM
+  MMMMGDFDFMMMMMMM
+  MMMMMPFPMMMAAAMM
+  MMMFGFPFEGAAAAMM
+  MMGAAGFFFAGAAAMM
+  MMMMAKNKFAAAAMMM
+  MMMMFGAFFAAMMMMM
+  MMMMGFAFGMAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 243 (orc zombie)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOAMMMMMMMMM
+  MMMMNOPAMMMMMMMM
+  MMMMGPGAMMMMMMMM
+  MMMMMPFAMMMMMMMM
+  MMKCCAKKKAMAAMMM
+  MBBPCKJMBBAAAMMM
+  BBMAGGFAABBAMMMM
+  BMMAJJPAAABAMMMM
+  MMMMBAPPPAAAAAMM
+  MMMBJAAEPAAAMMMM
+  MMBPPAAAPPMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 244 (dwarf zombie)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMBMMMMMMMMM
+  MMMMMBEEMMMMMMMM
+  MMMMBBEEEMMMMMMM
+  MMMMBFFFEMMMMMMM
+  MMMMMPFPMMMAAAMM
+  MMMBBPPPEEAAAAMM
+  MMFBABPEAEAAAAMM
+  MMFMEBBEFAAAAMMM
+  MMMMEBAEEAAMMMMM
+  MMMMBEAEBMAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 245 (elf zombie)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMGMMMMMM
+  MMMMMMMGGFMMMMMM
+  MMMMMMGGGGAMMMMM
+  MMMMMMFEFEAMMMMM
+  MMMMMMFFFFAMMMMM
+  MMMMMMAFDAMMMMAM
+  MMMMMMGAAGMMAAAM
+  MMMMFFGGGFFFAAAM
+  MMMFAAAGFAAAFAAM
+  MMMMMAGGGFAAAAMM
+  MMMMMMGFAFAAMAMM
+  MMMMMKDAMFKAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 246 (human zombie)
+{
+  MMMMMMAAAMMMMMMM
+  MMMMMFFGAAMMMMMM
+  MMMMMAGAFAMMMMMM
+  MMMMMFFGFAMMMMMM
+  MMMMFKFMMJJMMMMM
+  MMMMJJJFJKJMMMMM
+  MMMFJMKJJAKJMMMM
+  MMFKMMKFJFFJMMMM
+  MMGMMMKKJGMMMMMM
+  MMMMMBPMBPAAAAAM
+  MMMMMFPAPFAAAAMM
+  MMMMMBFABFAAAAMM
+  MMMMMPFABPAAMMMM
+  MMMMMBFABFAMMMMM
+  MMMMGGAGGAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 247 (ettin zombie)
+{
+  MMMMNNMMONOPMMMM
+  MMNNOOPNNOOPPMMM
+  MMNFFMMNFFMMPMMM
+  MMADFFDADFFDAMMM
+  MMAFFFFAFFFFAMMM
+  MMAFAAFAFAAFAAMM
+  MMAFFFFAFFFFAAAM
+  MMGIIIIJJJIIIGAA
+  MGFFFIIIIIIFFFGA
+  MGFFFFIIIIFFFFFA
+  MFFAAFIIIIFAAFFA
+  MFFAAIIIIIIAAFFA
+  MFFFMIIFFIIAGFAA
+  MMFFMGFAAGFAFFAA
+  MMMMMGFAAGFAAAAA
+  MMMFFFFAMGFFFFAA
+}
+# tile 248 (giant zombie)
+{
+  MMMMMMJJJJAAMMMM
+  MMMMJJJJJJJJAMMM
+  MMMMJJFFFFJJAMMM
+  MMMMJDDFFDDJAMMM
+  MMMMJFFFFFFJAMMM
+  MMMMAFFAAFFAAAMM
+  MMMMMAFFFFJAAAAM
+  MMGGFFJJJJFFGGAA
+  MGFFFGGFFFFFFFCA
+  MFFFKFFFFFFKFFFA
+  FFFAAFFFFFFAAFFA
+  FFAAMJJJKKJAAFFA
+  FFAMMJJJJJKAGFAA
+  MMMMMGFAGFFAFFAA
+  MMMMGFFAGFFAAAAA
+  MMMGFFAAGFFFAAAA
+}
+# tile 249 (ghoul)
+{
+  MMMMMMAAAMMMMMMM
+  MMMMMOOOAAMMMMMM
+  MMMMMDODOAMMMMMM
+  MMMMMOOOOAMMMMMM
+  MMMMPPOOOPPMMMMM
+  MMMMPPPPPPPMMMMM
+  MMMPPMPPPAPPMMMM
+  MMPPMMPPPOOPMMMM
+  MMOMMMPPPOMMMMMM
+  MMMMMPPMPPAAAAAM
+  MMMMMPPAPPAAAAMM
+  MMMMMPPAPPAAAAMM
+  MMMMMPPAPPAAMMMM
+  MMMMMPPAPPAMMMMM
+  MMMMOOAOOAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 250 (skeleton)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMOOOMMMMMMMMMM
+  MMAOAOOMMMMMMMMM
+  MMOOOOOMMMMMMMMM
+  MMOOMOMMMMMMMMMM
+  MMMMMMOMMMMMMMMM
+  MMMMOOOOOMMMAAAM
+  MMMOAMOOOAMMAAAM
+  MMOAMOAAOMAAAAAM
+  MMMMOAMOOOAAAMAM
+  MMMMMMOOOAAAMAMM
+  MMMMMOMAOMAMMMMM
+  MMMOOOAMOAMMMMMM
+  MMMMMMOOOMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 251 (straw golem)
+{
+  MMMMMMLJMMMMMMMM
+  MMMMMMLJHJMMMMMM
+  MMMMHJLJHMMMAMMM
+  MMMMAAAAALMMMMMA
+  MMMMDAADALMAMAAM
+  MMMMLJHJLMMAAAAM
+  MMMMLLHJLHHCHHLM
+  MMMHHLJLMAJLJLMA
+  MHHJJLLLLAAAMAAM
+  MMJLMMLALHAAAAAA
+  MLLMMCJLHJHAAAAA
+  MMMMMHJLAHJHAAAM
+  MMMMMHJAACALHAAA
+  MMMMCJLAAJHALHAM
+  MMMMHALAMAHAALMM
+  MMMMMMMMMMLMMMMM
+}
+# tile 252 (paper golem)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMOAMMMMMMM
+  MMMMMNNNOAMMMMMM
+  MMMMMONNNOAMMMMM
+  MMMMMMONNOAMMMMM
+  MMMMMMMNOAMMMMMM
+  MMNNOAMNOAMMMMMM
+  MMNONOAOAONNOAMM
+  MMOAOANNOAOOOAMM
+  MMMMMMNNNOAAAAAM
+  MMMMMMONOAAAAAAM
+  MMMMMMMOOAAAAAAM
+  MMMMMNOAAOAAAAAM
+  MMMMMNOAMMNOAAMM
+  MMMMOOAMMMOOAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 253 (rope golem)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMOOOMMMMMMM
+  MMMMMOMMMOMMMMMM
+  MMMMMOMMMOMMMAAM
+  MOOMMMOMMOMMAMMA
+  OMMOMMMLLMMOOMMA
+  MMMOMMMLOOOMAOAM
+  MMMMOOOOOAAAAOMM
+  MMMMMMMOOMMAAMAM
+  MMMMMMMLOMAAMMMA
+  MMMMMMOMMOOAAMMA
+  MMMMOOMMAMMOMAMM
+  MMMOMMAAMMMOMAMM
+  MMMOMAMMMMOAAMMM
+  MMMMOAMMMMMMMMMM
+}
+# tile 254 (gold golem)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMHNHMMMMMMM
+  MMMMMMDNDMMMNMMM
+  MMMMMMHNHMMMJCMM
+  MMMMMMHNHMMMNCMM
+  MMMHHHAAAAHANCMM
+  MMHNJNHNHNJNACMA
+  MMHHHHHHHHHHHAMA
+  MNCACCCCCCCCAMMA
+  MHHMAAAAAAAAAMAA
+  MNHMANCMAHNCMAAA
+  MNJMAHCMAHHCMAAA
+  MMHMANCMAHNCMAAA
+  MMMMHJCMAHJCMAAM
+  HMMMHNCMAHNCMAMH
+  MMHMMMMMMMMMMMMM
+}
+# tile 255 (leather golem)
+{
+  MMMMMMKKKKMMMMMM
+  MMMMMKHKHJMMMMMM
+  MMMMKAKKJJAMMMMM
+  MMMKKAJJJJAJMMMM
+  MMKKJJAJAAKJJMMM
+  MKKKJJAAKKKJJJMM
+  MMKKJJJAKKJJJJMM
+  MMMKKJJJAMAAAMAM
+  MMMMAAAAMKJAAAAM
+  MMMMKJAAAKKAAAAA
+  MMMKJJAAMKJJAAAM
+  MMMKKJAMMKKJAAAM
+  MMKKJJJAKKJJJAAM
+  MMKKKJJAKKKJJAMM
+  MMMKJJAMMKJJAMMM
+  MMMMKAMMMMKAMMMM
+}
+# tile 256 (wood golem)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMKCKJMMMMMM
+  MMMMMMHCHJMMCMMM
+  MMMMMMKCKJMMCKMM
+  MMMMMMKCKJMMCKJM
+  MMMKKKAAAAKACKJM
+  MMKCCCCCCCCCAKJA
+  MMKKKKKKKKKKKAJA
+  MCJAJJJJJJJJAMMA
+  MCKJAAAAAAAAAMAA
+  MCKJACKJAKCKJAAA
+  MCKJACKJAKCKJAAA
+  MMKJACKJAKCKJAAA
+  MMMMKCKJAKCKJAAM
+  MMMMKCKJAKCKJAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 257 (flesh golem)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMDMMDDCMMMMMMM
+  MMMMMDLDDLMMMMMM
+  MMDDMMLLLLCMDMMM
+  MMMCDLMLLLLADLMM
+  MMCLDLAMCLLAMLLM
+  MMLLLAAMLLCAMMLM
+  MCLLAAMCLLAAMMCA
+  MLLAMMCLLALLAAAA
+  MMLAMCLCAALCAAAA
+  MMMAMMLLCACLCAAA
+  MMMMLLALLAALLAAA
+  MMCLLLAAAADLLAMM
+  MMLLDDDMMDDDDDMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 258 (clay golem)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMLCCCCKMMMMMM
+  MMMLKKKKKKKMMMMM
+  MMMCKAKKAKKMMMMM
+  MMMCKAKKAKKMMMMM
+  MLCKKKKKKKKLCMMM
+  CKKJKKKKKKCKKJMM
+  KKKJKKJJKKJKKJAA
+  MJJAKKJAKKAJJAAA
+  MMAKKKJAKKKAAAAA
+  MMCKKKKKKKKKAAAA
+  MMCKKKAACKKKAAMM
+  MMCKKKAMCKKKAAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 259 (stone golem)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMBBBPPMMMMMMM
+  MMMBBPPPPPMMMMMM
+  MMMBHAPHAPMMMMMM
+  MMMPPPPPPPMMMMMM
+  MBBPPPPPPMBPAMMM
+  BPPPPMMMMPPPPAAM
+  BPPMBPPPPMPPPAAA
+  MPPMBPMPPMPPPAAA
+  MMMBPPMPPPAAAAAA
+  MMBPPPAPPPAAAAAM
+  MMPPPPAPPPPAAAMM
+  MMMPPAAMPPPAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 260 (glass golem)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMBBBBBBAMMMM
+  MMMMMBPNPPPAMMMM
+  MMMMMBNPPPNAMMMM
+  MMMMMNPPPNPAMMMM
+  MMMMMBPPNPPAMMMM
+  MMMMMMMBAMMMBAMM
+  MBNBBABPBAMBPNAM
+  MNPPNABPNBBANPBA
+  MMMMMBPNPPPAABAA
+  MMMMMBNPPPAAAAAA
+  MMMMMMBPPNAAAAAA
+  MMMMBNABNABPAAAM
+  MMMBNPAMMMBNAAAM
+  MMBNPAMMMMNPAAMM
+  MMMBAMMMMMBPAMMM
+}
+# tile 261 (iron golem)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMPBPMMMMMMM
+  MMMMMMHBHMMMBMMM
+  MMMMMMPBPMMMJPMM
+  MMMMMMPBPMMMBPMM
+  MMMPPPAAAAPABPMM
+  MMPBJBBBBBJBAPMA
+  MMPPPPPPPPPPPAMA
+  MBMAMMMMMMMMAMMA
+  MBPMAAAAAAAAAMAA
+  MBPMABPMAPBPMAAA
+  MBJMABPMAPBPMAAA
+  MMPMABPMAPBPMAAA
+  MMMMPJPMAPJPMAAM
+  MMMMPBPMAPBPMAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 262 (human)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMJJAMMMMMM
+  MMMMMMJJJJAMMMMM
+  MMMMMMELELAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMCLAALCMAAAM
+  MMMMCLLLLLLCAAAM
+  MMMMLACLLCALAAAM
+  MMMMLAJJKJALAAAM
+  MMMMMMJJJKAAAAMM
+  MMMMMMJJAJAAMAMM
+  MMMMMKLAMLKAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 263 (wererat)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMJJAMMMMMM
+  MMMMMMJJJJAMMMMM
+  MMMMMMGJGJAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMCLAALCMAAAM
+  MMMMCLLLLLLCAAAM
+  MMMMLACLLCALAAAM
+  MMMMLAJJKJALAAAM
+  MMMMMMJJJKAAAAMM
+  MMMMMMJJAJAAMAMM
+  MMMMMKLAMLKAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 264 (werejackal)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMJJAMMMMMM
+  MMMMMMJJJJAMMMMM
+  MMMMMMIPIPAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMCLAALCMAAAM
+  MMMMCLLLLLLCAAAM
+  MMMMLACLLCALAAAM
+  MMMMLAJJKJALAAAM
+  MMMMMMJJJKAAAAMM
+  MMMMMMJJAJAAMAMM
+  MMMMMKLAMLKAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 265 (werewolf)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMJJAMMMMMMM
+  MMMMMJJJJAMMMMMM
+  MMMMMNJNJAMMMMMM
+  MMMMMLLLLAMMMMMM
+  MMMMMALLAMMMMMMM
+  MMMMCLAALCMAAAMM
+  MMMCLLLLLLCAAAMM
+  MMMLACLLCALAAAMM
+  MMMLAJJKJALAAAMM
+  MMMMMJJJKAAAAMMM
+  MMMMMJJAJAAMAMMM
+  MMMMKLAMLKAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 266 (elf)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMGMMMMMM
+  MMMMMMMGGFMMMMMM
+  MMMMMMGGGGAMMMMM
+  MMMMMMLELEAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMAM
+  MMMMMMGAAGMMAAAM
+  MMMMMLGGGFLAAAAM
+  MMMMLAAGFAALAAAM
+  MMMMLAGGGFALAAMM
+  MMMMMMGFAFAAMAMM
+  MMMMMMGFAFAAMAMM
+  MMMMMKLAMLKAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 267 (Woodland-elf)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMKMMMMMM
+  MMMMMMMKKJMMMMMM
+  MMMMMMKKKKAMMMMM
+  MMMMMMLELEAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMAM
+  MMMMMMKAAKMMAAAM
+  MMMMMLKKKJLAAAAM
+  MMMMLAPPJAALAAAM
+  MMKKLKKKKJALAAMM
+  MMMMMMPPAJAAMAMM
+  MMMMMKLAMLKAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 268 (Green-elf)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMGMMMMMM
+  MMMMMMMGGFMMMMMM
+  MMMMMMGGGGAMMMMM
+  MMMMMMLELEAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMAM
+  MMMMMMGAAGMMAAAM
+  MMMMMLGGGFLAAAAM
+  MMMMLAAGFAALAAAM
+  MMMMLAGGGFALAAMM
+  MMMMMMGFAFAAMAMM
+  MMMMMKLAMLKAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 269 (Grey-elf)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMPMMMMMM
+  MMMMMMMPPMMMMMMM
+  MMMMMMPPPPAMMMMM
+  MMMMMMLELEAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMAM
+  MMMMMMPAAPMMAAAM
+  MMMMMLPPPMLAAAAM
+  MMMMLAAPMAALAAAM
+  MMMMLAPPPMALAAMM
+  MMMMMMPMAMAAMAMM
+  MMMMMKLAMLKAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 270 (elf-lord)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMIIMMMMMM
+  MMMMMMMHGFMMMMMM
+  MMMMMMHGGGAMMMMM
+  MMMMMMLELEAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMAM
+  MMMMMMHAAHMMAAAM
+  MMMMMLHHHFLAAAAM
+  MMMMLAAIIAALAAAM
+  MMMMLAHGGFALAAMM
+  MMMMMMHFAFAAMAMM
+  MMMMMKLAMLKAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 271 (Elvenking)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMHMMHMMMMMM
+  MMMMMMHCHHMMMMMM
+  MMMMMMHHHHAMMMMM
+  MMMMMMLELEAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMIALLAIMMMAM
+  MMMMIIIAAIDIAAAM
+  MMMMMLIIGDLAAAAA
+  MMMMLADIFDALAAAA
+  MMMMLAIIGDALAAAM
+  MMMMMIIFAFDAAAMM
+  MMMIIKLAILKDIMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 272 (doppelganger)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMCCCCMMIMMM
+  MMIMMCDMMMCMMMMM
+  MMMMCDMHHAMCMMMM
+  MMMCDMHHHHAMCMIM
+  MMMCDMLFLFAMDCMM
+  MIMCDMLLLLAMDCMM
+  MMMCDMALLAMDCMMM
+  MMCDMLLAALLMACAM
+  MCDMLLLLLLLLADCM
+  MCDMLALLLLALADCM
+  MCDMLAJJKJALADCM
+  MMCDMMLJJLAAACAM
+  MMMCDMLLALAACAMM
+  MMCDMLLAALLADCMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 273 (nurse)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMNOMMMMMMM
+  MMMMMMNDDOMMMMMM
+  MMMMMMNNOOAMMMMM
+  MMMMMDBLBLDMMMMM
+  MMMMMCLLLLDCMMMM
+  MMMMMDALLACDMMMM
+  MMMMMCNAAODCAAAM
+  MMMMMNNNOOLAAAAM
+  MMMMLANNDOALAAAM
+  MMMMLANNOOALAAAM
+  MMMMMMNNOOAAAAMM
+  MMMMMMNNAOAAMAMM
+  MMMMMLLAMLLAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 274 (shopkeeper)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMAAAAAAMMMMM
+  MMMMMMJLJLMMMMMM
+  MMMMMMLLLLMMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMEBAABEAMAAM
+  MMMMEBBBBBBEAAAM
+  MMMMBAEBBEABAAAM
+  MMMMLAGFFFALAAAM
+  MMMMMMGFAFAAAAMM
+  MMMMMMGFAFAAMAMM
+  MMMMMJJAMJJAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 275 (guard)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMBBPPPAAMMMM
+  MMMMBNPPPPPPAMMM
+  MMMMBPPBPPPPAMMM
+  MMMMBAABPAAPAMMM
+  MMMMBCLBPCLPAMMM
+  MMMMAKCPPCJAAAMM
+  MMMMBKJJJJAPAAAA
+  MMMBPKJAAJAPPAAA
+  MMBPPKJJJJAPPPAA
+  MMPPABKJJAPPAPPA
+  MMPPABPKAPPPAPPA
+  MMLCMBPPPPPPCLAA
+  MMLLMBPPABPPLLAA
+  MMMMMBPPABPPAAAA
+  MMMMBPPPMBPPPAAA
+}
+# tile 276 (prisoner)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMNOAMMMMMM
+  MMMMMMMLLAMMMMMM
+  MMMMMMMLLAMMMMMM
+  MMMMMMMNOAMMMMMM
+  MMMMMMNOONAMMMMM
+  MMMMMNOOOONAMMMM
+  MMMMNANOOOANAAMM
+  MMMMPANOOOAPAAAM
+  MMMMLANOOOALAAAM
+  MMMMMMNOOOAAAAMM
+  MMMMMMNAANAAAMMM
+  MMMMMMPAAPAAMMMM
+  MMMMMLLAMLLAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 277 (Oracle)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMNNMMMMMMM
+  LLLMMMGLLGMMMLLL
+  MMLMMNLLLLNMMLMM
+  MMMLMNLAALNMLMMM
+  MMMMLNLLLLNLMMMM
+  MMMMMLNLLNLMMAAM
+  MMMMMNBBEENMAAAA
+  MMMMMMBBEEAAAAAA
+  MLLAMMBBBEAAALLM
+  MLLLLBBBEBELLLLA
+  MMLLCLBLLELLCLAA
+  MMMCLLLLLLLCLAAM
+  MMMMLELLLLELAAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 278 (aligned priest)
+{
+  MMMMMMMMMMMMMMMM
+  INIMMMMMMMMMMMMM
+  IIIMMKCCKMMMMMMM
+  MJMMKCCCCKMMMMMM
+  MJMMCAAKCCMMMMMM
+  MLCMCAAACCMMMMMM
+  CLLCMCAACJKCMMMM
+  CJLACCCCJKCCCMMM
+  MJAACCJJCKCCCKMM
+  MJKCCCJCCJCCKMAA
+  MJMMCCJCCLJCAAAA
+  MJMMCCJCLLCAAAAM
+  MJMMKCJCCCJAAAAM
+  MJMACCJCCCJAAAMM
+  MJACCCJJCCCAAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 279 (high priest)
+{
+  MINIMMMMMMMMMMMM
+  IIIIIMKCCKMMMMMM
+  MIHIMKCAACKMMMMM
+  MMHMMCGAGACMMMMM
+  MMLCMCAAAACMMMMM
+  MCLLCMCAACJCKMMM
+  MCHLACCCCJCCCKMM
+  MMHAACCJJCCCCCKM
+  MMHCCCCJCCJCCCMA
+  MMHMMCCJCCLJCAAA
+  MMHMMCCJCLLCAAAA
+  MMHMMKCJCCCJAAAA
+  MMHMMKCJCCCJAAAA
+  MMHMACCJCCCJAAAM
+  MMHACCCJJCCCAAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 280 (soldier)
+{
+  MMMMMJMMMMMMMMMM
+  MMMMMJAAAMMMMMMM
+  MMMMMALLLAMMMMMM
+  MMMMMLLLLCMMMMMM
+  MMMMMJLLCMMMMMMM
+  MMMMMJFMMFMMMMMM
+  MMMMFJFFFFFMMAMM
+  MMMMFJFFFAFMAMMM
+  MMMMFLFFFFFAAAMM
+  MMMMFJFFAAAAAAAM
+  MMMMMLFAFFAAAAMM
+  MMMMMFFAFMAAAAMM
+  MMMMMMFAFMAAMMMM
+  MMMMMFFAFFAMMMMM
+  MMMMMJJMJJMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 281 (sergeant)
+{
+  MMMMMJMMMMMMMMMM
+  MMMMMJFFFMMMMMMM
+  MMMMFFFFFFMMMMMM
+  MMMMMLLLLCMMMMMM
+  MMMMMJLLCMMMMMMM
+  MMMMMJFMMGMMMMMM
+  MMMMFJFFFFFMMAMM
+  MMMMFJFFFAFMAMMM
+  MMMMFLFFFFFAAAMM
+  MMMMFJFFAAAAAAAM
+  MMMMMLFAFFAAAAMM
+  MMMMMFFAFMAAAAMM
+  MMMMMMFAFMAAMMMM
+  MMMMMFFAFFAMMMMM
+  MMMMMAAMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 282 (lieutenant)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMFFFMMMMMM
+  MMMMMFFFFFFMMMMM
+  MMMMMMLLLLMMMMMM
+  MMMMMMMLLCAMMMMM
+  MMMMMGFMFGAMMMMM
+  MMMMFFFFFFFFMMMM
+  MMMMFAFFFFAFAAAM
+  MMMMFAFFFFAFAAAA
+  MMMMFAFFFFAFAAAM
+  MMMMLFFAFFJLJAMM
+  MMMMMFFAFFJJJAMM
+  MMMMMMFAFMAAMMMM
+  MMMMMFFAFFAMMMMM
+  MMMMMAAMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 283 (captain)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMFHHFMMMMMM
+  MMMMMFFFFFFMMMMM
+  MMMMMMLLLLMMMMMM
+  MMMMMMMLLCAMMMMM
+  MMMMMHFMFHFMMMMM
+  MMMMFFFFFFFFAAMM
+  MMMMFAFFIFAFAAAA
+  MMMMFAFFFFAFAAAM
+  MMMMFAFFFFAFAAAM
+  MMMMLFFAFFJLJAMM
+  MMMMMFFAFFJJJAMM
+  MMMMMMFAFMJJJAMM
+  MMMMMFFAFFJJJAMM
+  MMMMMAAMAAAAAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 284 (watchman)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMPPPMMMMMMM
+  MMMMPPPPPPMMMMMM
+  MMMMMLLLLCMMMMMM
+  MMMMMMLLCMMMMMMM
+  MMMMMPPMMPMMMMMM
+  MMMMPPPPPPPMMMMM
+  MMMMPAPPHAPPAMMM
+  MMMMPAPPPANNAAAM
+  MMMMPJPPAPNNAAAM
+  MMMMJLPAPPAAAAMM
+  MMMMMJPAPMAAAAMM
+  MMMMMMPAPMAAMMMM
+  MMMMMPPAPPAMMMMM
+  MMMMJJJMJJJMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 285 (watch captain)
+{
+  MMMMMMPPPMMMMMMM
+  MMMMMPHHHPMMMMMM
+  MMMMPPPPPPPMMMMM
+  MMMMMLLLLCMMMMMM
+  MMMMMMLLCMMMMMMM
+  MMMMMHPMMHMMMMMM
+  MMMMPPPPPPPMMMMM
+  MMMMPAPPHAPPAMMM
+  MMMMPAPPPANNAAAM
+  MMMMPJPPAPNNAAAM
+  MMMMJLPAPPAAAAMM
+  MMMMMJPAPMAAAAMM
+  MMMMMJPAPMAAMMMM
+  MMMMMPPAPPAMMMMM
+  MMMMJJJMJJJMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 286 (Medusa)
+{
+  MMMMMMMMMMMMMMMM
+  MMGAMMMGAMMMMMMM
+  MMMFAMFAMMGAMMMM
+  MMMMFJFFFFMMMMMM
+  MMFAFLLFAMMMMAMM
+  MGAFLLLLAMMAMMAM
+  MMMMJLLKAMAMAMAM
+  MMMKBLLBKAAAAAMM
+  MMKIIBBIIIAAAMAM
+  MMIIIKKILLIAAAMM
+  MMKIILLIALIAAMMM
+  MMMKIALKAAIAAMMM
+  MMMIKAAKIIAAAMMM
+  MMMIIKKIIIAAMMMM
+  MMIIKIKIKIAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 287 (Wizard of Yendor)
+{
+  MEEEMMMMMMMEEEMM
+  EFFAEMMEMMEAFFEM
+  EAAAEMEEEMEAAAEM
+  EAAAEEEAEEEAAAEM
+  EEAAEEDADEEAAEEM
+  MEEEEAAAAAEEEEMM
+  MMEEEEAAAEEEEMMM
+  MMEEEEEEEEEEMMMM
+  MMMEEEEEEEEMMMMM
+  MMMEEEEEEEEMMMMA
+  MMMMEEEEEEMMMAAA
+  MMMMEEEEEEAAAAAA
+  MMMEEEEEEEEAAAAA
+  MMEEEEEEEEEAAAAA
+  MEEEEEEEEEEEAAAM
+  EEEEEEEEEEEEEEAM
+}
+# tile 288 (Croesus)
+{
+  MMMMHMMHMMHMMMMM
+  MMMMHCHEHCHMMMMM
+  MMMMHHHHHHHMMMMM
+  MMMMALLLLLAMMMMM
+  MMMMLLALALLMMMMM
+  MMMMMLLLLLMMMMMM
+  MMMMHLLDLLHMMMMM
+  MMMHIALLLAIHMAMA
+  MMMHIHAAAHIHAAAA
+  MMIIIEHHHIIIIAAA
+  MMIIIIEHIIIIIAAM
+  MMILLIHHHILLIAAA
+  MMMLIIKHIIILAAAA
+  MMGIIIKJIIIIGAAM
+  MGIIIKJJKKIIIGGM
+  MMMMMMMMMMMMMMMM
+}
+# tile 289 (Charon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMJMMMMMMMM
+  MMMMMMJJJMMMMMMM
+  MMMMJJJAJJJMMMMM
+  MMMMJJDADJJMMMMM
+  MMMJJAAAAAJJMMMM
+  MMMJJJAAAJJJMMMM
+  MMJJJJJJJJJJMMMM
+  MJJJJJJJJJJJJMMM
+  JJJJJJJJJJJJJJMA
+  MOOMJJJJJJMOOAAA
+  MMMMJJJJJJAAAAAA
+  MMMJJJJJJJJAAAAA
+  MMJJJJJJJJJAAAAA
+  MJJJJJJJJJJJAAAM
+  JJJJJJJJJJJJJJAM
+}
+# tile 290 (ghost)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNNNMMMMMMMMMM
+  MMNANANNMMMMMMMM
+  MNNNNNNNNNMMMMMM
+  MNNPAAPNNNNNMMMM
+  MNNAAAANNNOONOMM
+  MNNAAAANONNNPNNO
+  MNNPAAPNONNOOOPM
+  MNNNNNNONOPNPPOM
+  MNNONNOPNNOPOOPM
+  MNOPNNOOOPPOOPMM
+  MOOOPOPPOPPPMPPM
+  MPPMPPOPPPMMMPMM
+  MOMMMPMMMMPMMMMM
+  MMMMMMMMPMMMMMMM
+}
+# tile 291 (shade)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMAAAAAAAM
+  MMMMAAAAAAAAMMMM
+  MMAAAAAAAAAAAAMM
+  AAAAAAAAAAAAAAAM
+  MMAAAAAAAAAAAAAA
+  MAAAAAAAAAAAAAMM
+  AAAAMAAAAJAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 292 (water demon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMEEMMMMMEEMMMMM
+  MEMEEMMMEEMEMMMM
+  MMMMEEEEEMMMMMMM
+  MMMMEBEBEMMAMMMM
+  MMMEEEEEEEAAAAMM
+  MMEEEMMMEEEAAMAM
+  MMEEEEEEEEEAAAMM
+  MMEEAEEEAEEAAAMM
+  MMMAAEEEAAAAAMMM
+  MMMMEEAEEAAMMMMM
+  MMMMEEAEEAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 293 (horned devil)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMOMMMMMMMOMMMMM
+  MMOOMMMMMOOMMMMM
+  MMMLOCDCOLMMMMMM
+  MMMCDDDDDCMMMMMM
+  MMMDAADAADAMMDMM
+  MMMDDDDDDDAMDMMM
+  MMCCDDFDDCCADMAM
+  MMCDKDDDKCDADAMM
+  MMCDAKKKACDAAAAM
+  MMDDADDDADDAAAAM
+  MMMMCDDDKAAAAAMM
+  MMMCDDADDKAAMMMM
+  MMCDDAAMDDKMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 294 (succubus)
+{
+  DDMOHHDMMMMMMMMM
+  DDOHHDGDMMMMMMMM
+  DDOHDDDDDMMMMMMM
+  DDHHDDDAMMMMMMMM
+  DHHHDJADDDDMMMMM
+  MHHJJDDDJDDDMMMM
+  OHDDCDCDDJDDMMMM
+  HHHCDDCDLJMDDMMM
+  HHHCDLJJJAADDAMM
+  HHHDJJDDDAADAAMM
+  HHHHDDAADAAAAMMM
+  HHHHMDKJDDAAMMMM
+  HMHMMDDAADDAAMMM
+  MMHMMDDAAMDAAMMM
+  MMMMDDAAMMDDAAMM
+  MMMDDJAMMMDDDAMM
+}
+# tile 295 (incubus)
+{
+  DDMOHHDMMMMMMMMM
+  DDOHHDGDMMMMMMMM
+  DDOHDDDDDMMMMMMM
+  DDHHDDDAMMMMMMMM
+  DDDHDJADDDDMMMMM
+  DDDJDDDDDDDDMMMM
+  MDDDDDCDDMDDDMMM
+  MDDCDDDKKMMDDMMM
+  MMDDKKDDDAADDAMM
+  MMMDDDDDDAAAAAMM
+  MMMMDDDDDDDDDAMM
+  MMMMDDJDJJAAAAAA
+  MMMMJDJJADKAAMMM
+  MMMMDDKAADDKAMMM
+  MMMDDKAAMMDDAAMM
+  MMDDKAAMMMDDDAMM
+}
+# tile 296 (erinys)
+{
+  MMGAMMMGAMMMMMMM
+  MMMFAMFAMMGAMMMM
+  MMMMFJFFFFMMMMMM
+  MMFAFLLFAMMMMMMM
+  MGAFDLDLAMMAMAMM
+  MMMMLLLEAMAMAMAM
+  MMMEBLLBEAAAAMAM
+  MMEBBBBBBBAAAAMM
+  MMBBBEBBLLBAAMAM
+  MMEBBLLBALBAAAMM
+  MMMEBALBAABAAMMM
+  MMMBEAABBBAAAMMM
+  MMMBBBBBBBAAAMMM
+  MMMBBBBBBBAAMMMM
+  MMBBEBEBEBAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 297 (barbed devil)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMOMMMMMMMOMMMMM
+  MMOOMMMMMOOMMMMM
+  MOMLOCDCOLMOMMMM
+  MMMCDDDDDCMMMMDD
+  MMMDAADAADAMMDMD
+  MMMDDDDDDDAMDMMM
+  MMCCDDFDDCCADMAM
+  MMCDKDDDKCDADAMM
+  MCMDAKKKACDKAAAM
+  MMDDADDDADDAAAAM
+  MMMMCDDDKAAAAAMM
+  MKMCDDADDKAAKMMM
+  MCCDDAAMDDKKMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 298 (marilith)
+{
+  MDMMHHHMMMMMDMMM
+  DDMHHHHHAMMMDDMM
+  MDCHDDDHHAADMMAM
+  MMHDBDBDHDDAAAAM
+  MCHKDDDKHAAADDMM
+  CDDDKKKDHDDDDFFM
+  DMMCDDCDKAAFFFAA
+  DMKDDKDDDDDDFAAM
+  DMDKDDKDKAFDFAAM
+  MMDMGDDFAAFDFFAA
+  MDMGGFFFAAAFFFFA
+  MMMGFFFFFAAAFFFA
+  MMFGFFFFFFAFFFFA
+  MMFGFFFFFFFFFFAM
+  MMFGFFFFFFFFFAMM
+  MMMMGFFFFFFAAMMM
+}
+# tile 299 (vrock)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMOPPMOMMMMM
+  MMMMMMPPPPMMMMMM
+  MMMMMCPPDPMMMMMM
+  MMMMCCCPPPMMMMMM
+  MMMMCCPPPPMMMMMM
+  MMMMCMMPPAMMMMMM
+  MMMMMDDAADDMAAAM
+  MMMMDDDDDDDDAAAM
+  MMMMDADDDDADAAAM
+  MMMMDADDDDADAAAM
+  MMMMDADDDDADAAAM
+  MMMMMMDAADAAAAMM
+  MMMMMMDAADAAMAMM
+  MMMMMDDAMDDAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 300 (hezrou)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMGGGFFMMMMMMM
+  MMNGFFNNFFFMMMMM
+  MDFFFDDNFFMFMMMM
+  MGFFFDNFFMFFFAAM
+  MAFAFFFFFFFFFFAA
+  MGFFFFMFFFMFGFAA
+  MGAAAFFMMLFGFFAA
+  MMFFFFMFFLFGFFFA
+  MMLLAMFLLLJJGMFA
+  MLLAFFLLFJJGFFFA
+  MMLAFLLLAAGFMFAA
+  MMMMMLMLAGFFFFAA
+  MMMMMMMMMMMFFFAM
+  MMMMMMMMMMMMMMMM
+}
+# tile 301 (bone devil)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMOMMMMMMMOMMMMM
+  MMOOMMMMMOOMMOMM
+  MMMLNLOLOLMMMMOM
+  MMMLOOOOOLMMMMOM
+  MMMNAAOAAOAMMOMM
+  MMMNOOOOOOAMOMMM
+  MMNOOOFOOOOAOMAM
+  MMOOKNOOKOOALAMM
+  MMOOANOOAOOAKAAM
+  MMLLANOOALLAAAAM
+  MMMMNOOOLAAAAAMM
+  MMMNOOAOOLAAMMMM
+  MMNOOAAMOOLMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 302 (ice devil)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMNMMMMMMMNMMMMM
+  MMNNMMMMMNNMMMMM
+  MMMPBPNPNPMMBNBM
+  MMMPNNNNNPMMNMNM
+  MMMBAANAANAMMMNM
+  MMMBNNNNNNAMBNBM
+  MMBNNNFNNNNANMAM
+  MMNNKBNNKNNABAMM
+  MMNNABNNANNAMAAM
+  MMPPABNNAPPAAAAM
+  MMMMBNNNPAAAAAMM
+  MMMBNNANNPAAMMMM
+  MMBNNAAMNNPMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 303 (nalfeshnee)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMBBMMMBBMMM
+  MMKKKKKBBMBBMMMM
+  MKADKADKKKBMMMMM
+  MKKKKKKKDKKMMMMM
+  MOKDKOKKDDKDMMMM
+  MOKDKOKKKDKDDMMM
+  MKAAAKKDKAKKDMMM
+  MMKKKDDLAKKKDMAM
+  MMMKKMKKKKKDDAMM
+  MMMMLMMKDAKDAAMM
+  MMMMMMLLAAKDAMMM
+  MMMMMMMMMLLAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 304 (pit fiend)
+{
+  MMMMMMMMMMMMMMMM
+  MKMOMMMMMMMOMKMM
+  MKMOOMMMMMOOMKJM
+  KJJMLOCDCOLMKJJM
+  KJJJKDDDDDKKJJJM
+  KJJCKDNDNDKCJJJA
+  JJCCKDDDDDJCCJJA
+  JJCCCKDIDJDCCJJA
+  JACCDDKJJDDCDAJA
+  JACCKDDDDDKCDAJA
+  MMMCDKDDDKCDDAAA
+  MMMMDKDDDKCDAAAA
+  MMMMMCDDDKAAAAMM
+  MMMMCDDADDKAMMMM
+  MMMCDDAAMDDKMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 305 (balrog)
+{
+  MMMMMMMMMMMMMMMM
+  MKMMOMMMMMOMMKMM
+  MKJMOMMMMMOMKJMM
+  KJJLOOCDCOOLJJJM
+  JJJDDDDDDDDDDKJM
+  JCCDDDNDNDDDCCJA
+  CCDKDDDDDDDJCCCA
+  CDDKKKDIDJJDCCDA
+  CDDKDDKJJDDDCDDA
+  CCDKDDDDDDDKCDDA
+  JCCDKKDDDKKCDDDA
+  JJCDKKDDDKKCDDJA
+  JJMMCCDDDKKAAJJA
+  JMMCDDDADDDKAAJA
+  MMCDDDAAMDDDKMAA
+  MMMMMMMMMMMMMMMM
+}
+# tile 306 (Juiblex)
+{
+  MMMMMMMMMMMMMMMM
+  DDMMMMMMMMMDDMMM
+  NDCMKKKKJMCNDMMM
+  MCCKCCCKKCCAAMMM
+  MMKCCCCKCCJAAMMM
+  MMKCCCCCKMJJAAMM
+  MMKCCFCCKMMJAAMM
+  MMFKCFCCKKMJAAAM
+  MFKKFCCKFKMMJAAM
+  MFKCFCCFKFKMJAAM
+  MFCFCCKFCFKMJAAM
+  FKCFCFCFCKKMJAAM
+  CKFCCFCCKKFKJJAM
+  CCKKCFCKFFKKKKAM
+  MCCCCCCCCCCCKAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 307 (Yeenoghu)
+{
+  MMMMBMHHPMMMMMMM
+  MMMMBPPPPMMMMMMM
+  MMMBPLCPPHMMMMMM
+  MKBPPCCPPHMMMMMM
+  MPPPPPPPMHMMMMMM
+  MPPMMMPMPHMMMMMM
+  MMMMBPPPPPAAAMMM
+  MMBPPPPPPPPAAAAM
+  MBPMPPPPPAPPAAAA
+  MBMMMBPPMAAPAAAA
+  MBMMMBPPMAAPAAAM
+  MMMMMBPPAAAAAMAM
+  MMMMBPMPPAAMMMAM
+  MMMBPMAAPPAMMAMM
+  MMMBPAAMPPAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 308 (Orcus)
+{
+  MMMMMMMMMMMMMMMM
+  MKMMOMMMMMOMMKMM
+  KJJOMMBBBMMOMKJM
+  KJJLOBPPPPOLKJJM
+  JKJJMPGPGPMJJKJA
+  JJKJKPPPPPJJKJJJ
+  JBPPBMBPPABBPPJJ
+  PJJPPMBPPAPPJJPA
+  PJBPPPMAAPPPPJPA
+  MJBPMPPPPMPMPJAA
+  MJBPPPPMPPPPPJAA
+  MMPPPMPPPMPPPAAA
+  MMMPMPPPPPPPMPMA
+  MMMBPPPAPPPPAAPA
+  MMMOOPPAOOPPAGAM
+  MMMMMMMMMMMMMMMM
+}
+# tile 309 (Geryon)
+{
+  MKMMMMMMMMMMMKMM
+  MKMMMMJJJMMMMKJM
+  KJJMMJJJJJMMKJJM
+  KJJJKLLLLLKKJJJM
+  KJJJKLBLBLKJJJJA
+  JJJJKLLLLLJJJJJA
+  JJALLKLLLJLLAJJA
+  JAMLLLKJJLLLAAJA
+  MMMLJLLLLLKLAAAA
+  MMMLCKLLLKCLAFGF
+  MMMLLGLLFALLFFFA
+  MMMMMGFFFAAAFFAA
+  MMMMGGGGFFAAFFAA
+  MMMMGFFFFFAAFGFA
+  MMMMFGGGFFFFFFFA
+  MMMMMFFFFFFFFFAM
+}
+# tile 310 (Dispater)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMOJJOMMMMMM
+  MMMMMMJJJJAMMMMM
+  MMMMMMBLBLAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMCKAAKKMAAAM
+  MMMMCKKKKKKKAAAM
+  MMMMKACKKJAKAAAM
+  MMMMKACKKJAKAAJA
+  MMMMKACKKJAKAAJA
+  MMMMLACKKJJLAJAM
+  MMMMMMCKAJAJJAMM
+  MMMMMMCKAPAAAAMM
+  MMMMMPPAMPPAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 311 (Baalzebub)
+{
+  MMMMMMFMMMFMMMMM
+  MMMMMMMFMFMMMMMM
+  MMMMMMBFFFBMMMMM
+  MMMMMBPPFBPPMMMM
+  MMMMMPPPFPPPMMMM
+  MMMMMMPPFPPMMMMM
+  MMMMMCAFFFAKMMMM
+  MMMMCKKAFAKKKAAM
+  MMMMCAKJFAKAKAAM
+  MMMMFACJDAJAFAAM
+  MMMMFACKJJJAFAAM
+  MMMMFACKKKJAFAAM
+  MMMMMMCKKKJAAAMM
+  MMMMMMCKAKJAMAMM
+  MMMMMFFAMMFFMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 312 (Asmodeus)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMOJJOMMMMMM
+  MMMMMMJJJJAMMMMM
+  MMMMMMBLBLAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMCKAAKKMAAAM
+  MMMMCKKKKKKKAAAM
+  MMMKKCKKKKJKKAAM
+  MMMKKAKKKJAKKAJA
+  MMMKAMCKKJAAKAJA
+  MMMLAMCKKJJALJAM
+  MMMMMMCKAJAJJAMM
+  MMMMMMCKAPAAAAMM
+  MMMMMPPAMPPAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 313 (Demogorgon)
+{
+  MMMKKKMMKKKMMMMM
+  MMKBKBKMBKBKMMMM
+  MMKDKKKMKKDKMMMM
+  MMDKKFAMGKKDMMMM
+  MMMMGFAAGFAAAMMM
+  MMMGFFFJFFFAMAAA
+  MMGFAGFFFAFFAAAA
+  MGJFAGJFJAFFFAAM
+  MGFAAGFFFAAFJAMM
+  MGJAMGFJFAAFFAAM
+  MGFAMGFFFAMFJAAM
+  MGJAMGJFJAMFFAAM
+  MGFAGFAAFFAFFAMM
+  MMGAGJAAJFAFAAMM
+  MMGAGFAFFFAFAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 314 (Death)
+{
+  MBBBBMMMMJJJMMMM
+  MBPPPPMJJJJMMMMM
+  MCMMMMJJJJJMMMMM
+  MCMMMMJAAAJMMMMM
+  MCMMMJADADAJMAAA
+  OOJMMJAAAAAJAAAM
+  OOOJJJAAAAAJJJAM
+  OOJJJJAAAAJOOJJA
+  MCJJJJAAAJOOOOJA
+  MCMJJAAAAJAOAAJA
+  MCMMJAAAAJAOAAJA
+  MCMMJAAAAAJOAJAA
+  MCMMJAAAAAJJJAAA
+  MCMJAAAAAAAJJAAM
+  MCJJAAAAAAAAJJAM
+  ACJAAAAAAAAAAAJM
+}
+# tile 315 (Pestilence)
+{
+  FMMMMMMMMJJJMMMM
+  MMFMMMMJJJJMMMMM
+  BMMMFMJJJJJMMMMM
+  MMMBMMJAAAJMMMMM
+  MFMMMJADADAJMMMM
+  MMMFMJAAAAAJMAAM
+  MBMMJFAAAAFJAAMM
+  MMMFJJAFABJJAAMM
+  MMFMJFFBAJJJAAAM
+  MMMMFAFFJJJJAAAM
+  MMMMJABAJJJJAAAM
+  MMMFJFFJJJJJJAAM
+  MMMJJBFJJJJJJAAM
+  MMMJAABFBJJJJAAM
+  MMJJFBFAFFAJJJAM
+  MJJAAFAFAAAAAAJM
+}
+# tile 316 (Famine)
+{
+  MMMMMMMMMJJJMMMM
+  MMMMMMMJJJMMMMMM
+  KMMMMMJJJJJMMMMM
+  KMMMMMJAAAJMMMMM
+  KMMMMJADADAJMMMM
+  KMMMMJAAAAAJMMMA
+  KMMMMMJAAAJJMMAA
+  OOJJJJJJAAJAJMAA
+  KMMMJJJAAJJAJAAA
+  KMMMMMJAJJJOJAAM
+  KMMMMMJAOOOAAAMM
+  KMMMMMJAJJAAAMMM
+  KMMMMMJAJJAAMMMM
+  KMMMMMJAAJAAMMMM
+  KMMMJJAAAJJAAMMM
+  KMMJJAAAAAJJJAMM
+}
+# tile 317 (mail daemon)
+{
+  MMMOPMBEEEMPOMMM
+  MMMOOEBEEEEOODMM
+  MMDLOBEEEEOOLDDM
+  MDDDLDDDDDDLDDDM
+  MCCDDDNDDNDDDCCM
+  CCDKDDDDDDDDJCCC
+  CDDKKDDIIDDJJCCD
+  CDDKMKDAADJJECDD
+  CCDKEEKKKJEEKCDD
+  MCCDKMEEEEMMCDDD
+  MCCDAEMEENNNCDDM
+  MDDDAEEEENDNDDDM
+  MMMMBBEEENNNNNMM
+  MMMBEEEAANNNNNAM
+  MMCDDDAAAMDDDKMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 318 (djinni)
+{
+  MLLMMNNNMMLLMMMM
+  MMLMMNGNAMLMMMMM
+  MMLAALLLAALAMMMM
+  MMLAAKKKAALAMMMM
+  MMMLCKKKCLAMMMMM
+  MMMMLCKCLAMMMMMM
+  MMMMLICLIAMMAMMM
+  MMMMIIIIEAMAAMMA
+  MMMMEIEEIAMAAAAA
+  MMMMIEFEAAAAAAAA
+  MMMMMDEAIAAAAAMM
+  MMMMMIGIFAAAAMMM
+  MMMMMMMFEDAAAMMM
+  MMMMMMMIMGEAMAMM
+  MMMMMMMMMIFEDMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 319 (sandestin)
+{
+  MMMMMCCCCCMMIMMM
+  MIMMCDMMMMCMMMMM
+  MMMCDMDDDMMCMMIM
+  MMCDMDDDDDMMCMMM
+  MMCDMDNDNDAMDCMM
+  IMCDMDDDDDAMDCMM
+  MMCDMADDDAMDCMMA
+  MCDMDDAAADDMDCAA
+  CDMDDDDDDDDDADCA
+  CDMDADDDDDADADCA
+  CDMDADDDDDADADCA
+  CDMDADDDDDADADCM
+  MCDMMDDJDDAADCAM
+  MMCDMDDADDADCAMM
+  MCDMDDAADDDADCMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 320 (jellyfish)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMPBPAMMMMMMM
+  MMMPBBBPBAMMMMMM
+  MMBBNNBPPBAAMMMM
+  MBBNNPPPBBPAAMMM
+  PBBBPPPBPBBAAAMM
+  BBBPBPPPPPBPAAAM
+  BBPBPPPPPPPBAAAM
+  PBPPBPPPPEPEEEMM
+  MPBBPPPEPEPPEEMM
+  MPEPBBEEPEEPEEMM
+  MPEEEPEEPEEPEMMM
+  MMPEEPEMMPEMPMMM
+  MMPMEPMEEPMMPMMM
+  MMPEEMPMEMMEMMMM
+  MPMMEMPMMEMMMMMM
+}
+# tile 321 (piranha)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMOPPMMMMMMMMM
+  MMMMMOPPMMMMMMMM
+  MMOMMPPAPMMMMMEM
+  MMPOPPPPPAMMMEEE
+  MMPPPPPMPPAMEMMM
+  MMMPPMMPPPAAAEEM
+  MMEMPPPPPPPPPEMM
+  MMEMMMPPPPPAAMEM
+  MMMMMEMMPPAEMMMM
+  MMMMMEMMPMMMMMMM
+  MMMMEMMEMMMEMMMM
+}
+# tile 322 (shark)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMP
+  MMMMMMMMPMMMMMPP
+  MMMMEMMPPMMMMPPM
+  MMMEMMMPPAMMPPPM
+  MMEEEEPPPAMPPPPP
+  MEMEEPPPMPPPPPPE
+  MMMEPMPMPPPPPEEE
+  MMPPPPPPPPPPEEEM
+  MAPPPPPPPPEEEEME
+  PPPPPPPMMEEMMMMM
+  NDPPAPEPPPMEMMEE
+  PDNPPEEMMEEMMMMM
+  MPPPEMMEEEMMEMMM
+}
+# tile 323 (giant eel)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMAAAMMMMMMMMM
+  MMMAAOAAMMMAAAMM
+  MMAAAAAAAMAAMAAM
+  MMAAAAMAAMAAMAAM
+  MMMAAMMAAMAAMMAM
+  MMMMMMAAAMMAAMAM
+  MMMMMMAAMMMAAMMM
+  MMMMMAAAMEMAAMEM
+  MMMEMAAEEMAAAEMM
+  MMMEMAAEEAAAEEMM
+  MMEMMAAAAAAEMEMM
+  MMMEEMAAAAEMEMMM
+  MMEMMMEEMEMMMEMM
+}
+# tile 324 (electric eel)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMAAAMMMMMMMMM
+  MMMAAOAAMMMMMMMM
+  MMAAAAAAAMMMMMMM
+  MMAAAAMAAMMMMMMM
+  MMMAAMMAAMMMDDMM
+  MMMMMMAAAMMDDMMM
+  MMMMMMAAMMMDDMMM
+  MMMMMAAAMEMDDMEM
+  MMMEMAAEEMDDMEMM
+  MMMEMAAEEDDMEEMM
+  MMEMMAAADDDEMEMM
+  MMMEEMAAADEMEMMM
+  MMEMMMEEMEMMMEMM
+}
+# tile 325 (kraken)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMFFMMFFMMMMMMMM
+  MMDDFDDFMMMMMMMM
+  MMFFFFFMMMMMGGMM
+  MMNCNFFMMMMMMGFA
+  MMCCMFFMMMMMEGFA
+  MMMMGFAAMGFAEGFE
+  MMMGFFAGFFFFAGFE
+  MMMGFAAFFAGFAEEE
+  MMGFFAGFFAGFEEEM
+  EEGFFAGFFAEEEEME
+  MEGFFAGFFEEMMMMM
+  EEGFFEEEEEMEMMEE
+  EEEEEEEMMEEMMMMM
+  MMEEEMMEEEMMEMMM
+}
+# tile 326 (newt)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMJKKJMMMMMM
+  MMMMMCLCCLLCMMMM
+  MMMMLAAAACCLCAMM
+  MMMMMMMLCCLLLCAM
+  MMMMLCCCLLLAALAM
+  MMMMCALLLLAAAAMM
+  MMMLLLLCLAAAMMMM
+  MMMLLAAALLAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 327 (gecko)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMLLPMM
+  MMMMMMMMMMLLOOAM
+  MMMMMMPOMLLOOOAM
+  MMMMMMOOALOOOAMM
+  MMMMMMMLLOOOAMMM
+  MMMPOALOOOAAMMMM
+  MMMOOLOOOOOOAMMM
+  MMMMALOOOAOPAMMM
+  MMMDOOOOAMAAMMMM
+  MMMOOOAOOAMMMMMM
+  MMMOODAOPAMMMMMM
+  MMFMAAMAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 328 (iguana)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMGPGPGGPFMMMM
+  MMGPAAAAFFGPFMMM
+  MGPAAMPFFGPPPAAM
+  MMMMMMFGGPPFPPAA
+  MPFGGGGPPPFAAPPA
+  MFGPAPPPPFAAAAAM
+  MGPPPPFPFAAAMAMM
+  MPPFFAFPPAAMMMMM
+  DMAAAAAAPPAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 329 (baby crocodile)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMFFOFOFAMMMM
+  MMMMFOGFGGOFFMMM
+  MMMMGAAAAFOGFAMM
+  MMMFAAMGFOGGGFAM
+  MMMGFOOOGGGFAGAM
+  MMMFGAGGGGFAAAMM
+  MMFGGGGFGFAAMMMM
+  MMGGDFAFGGAMMMMM
+  MMMDMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 330 (lizard)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMFFFFGFJMMMMM
+  MMFFAAAJJGFJMMMM
+  MMMMMMJGFFJFAAMM
+  MMMJGGGFFJAAFAMM
+  MMJFAFFFJAAAAMMM
+  MMFFFFJJAAAMMMMM
+  MJFAAAAFAAMMMMMM
+  MDMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 331 (chameleon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMGGGGMMMMMMM
+  MMMGGGGGGGGMMMMM
+  MMMGGFFFFGGFAMMM
+  MMGPAAAGFFGGFAMM
+  MGPAAMPFFGGGGAAM
+  MMMGGGGGGGGFGGAA
+  MPGGBBGGGGFAAGGA
+  MFGGABGGGFAAAAAM
+  MGGGGGFGFAAAMAMM
+  MDGFFAFGGAAMMMMM
+  DMAAAAAAGGAMMMMM
+  MDDMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 332 (crocodile)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMFFOFOOFAMMMM
+  MMMFOGFGFGOFFAMM
+  MMFGAAAAFFOGFFAM
+  MFFAAMGFFOGGGGFA
+  MMMMMMFOOGGGGGGA
+  MGMOOOOGGGGFAGGA
+  MFOGAGGGGGFAAAAM
+  FGGGGGFGGFAAMMMM
+  GGDDFAFGGGAMMMMM
+  GDDFAAAAGGAMMMMM
+  MDFMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 333 (salamander)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMCCCMMMMMMM
+  MMMMCCCCCCCMMMMM
+  MMMCCDDDDCCDAMMM
+  MMMMAAAADDCCDAMM
+  MMMMMMKDDCCCCAAM
+  MMLLLCCCCCCDCCAA
+  MKLCCCLLLCDAACCA
+  MDCEECLKKDAAAAAM
+  DCCAECDKDAAAMAMM
+  CCCCCCDCCAAMMMMM
+  MDAADAAACCAMMMMM
+  MMACCAMMMMMMMMMM
+  MMMAAAMMMMMMMMMM
+}
+# tile 334 (long worm tail)
+{
+  MMMMMMMMILLLLMMM
+  MMMMMMIILLAAMMMM
+  MMMMMILLAAMMMMMM
+  MMMMMILAMMMMMMMM
+  MMMMMILAMMMMMMMM
+  MMMMMMLLAMMMIIMM
+  MMMMMMMLLIIILLLL
+  MMMMMMMMILLAAAML
+  MMMIIIILLALLMMMM
+  MILLLLLAAMMLLMMM
+  ILLAAAAMMMMMLAMM
+  ILAMMMMMMMMMLAMM
+  LLAMMMMMMMMLLAMM
+  LILAMMMMMMLLAMMM
+  MLLLIIIILLLAMMMM
+  MMMLLLLLAAAMMMMM
+}
+# tile 335 (archeologist)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMKJMJMMMMMM
+  MMMMMMKJJJMMMMMM
+  MMMMKCKKKJJJMMMM
+  MMMMMMLELEAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMCKAAKJMAAAM
+  MMMMCKKKJJJJAAAM
+  MMMMKACKJJAJAAAM
+  MMMMLACJKJALAAAM
+  MMMMMMCJJKAAAAMM
+  MMMMMKCJAJJAMAMM
+  MMMMMCJJMJKJMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 336 (barbarian)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMHHAMMMMMM
+  MMMMMMHHHHAMMMMM
+  MMMMMMLFLFAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMLLAALLMAAAM
+  MMMMLLLLLLLLAAAM
+  MMMMLALLLLALAAAM
+  MMMMLAALLAALAAAM
+  MMMMLAJJKJALAAAM
+  MMMMMMLJJLAAAAMM
+  MMMMMMLLALAAMAMM
+  MMMMMLLAMLLAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 337 (caveman)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMJJAMMMMMM
+  MMMMMMJJJJAMMMMM
+  MMMMMJFLFLJMMMMM
+  MMMMMJLLLLJMMMMM
+  MMMMMJJDDJAMMMMM
+  MMMMLLAJJALLAAAM
+  MMMLLLLAALLLLAAM
+  MMMLLALLLLALLAAM
+  MMMMLACKKJALAAAM
+  MMMMMMCKKJAAAAMM
+  MMMMMMLAMLAAMAMM
+  MMMMMLLAMLLAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 338 (cavewoman)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMJJAMMMMMM
+  MMMMMMJJJJAMMMMM
+  MMMMMJFLFLJMMMMM
+  MMMMMJLLLLJMMMMM
+  MMMMMJLDDLAJMMMM
+  MMMMLJALLAJLAAAM
+  MMMLLJCAAJJLLAAM
+  MMMLLACKKJALLAAM
+  MMMMLACKKJALAAAM
+  MMMMMMCKKJAAAAMM
+  MMMMMMLAMLAAMAMM
+  MMMMMLLAMLLAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 339 (healer)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMNDDOMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMELEPMMMMMM
+  MMMMMMLLLPMMMMMM
+  MMMMMMMLLPMMMMMM
+  MMMMMMOMMPAMAAAM
+  MMMMMNNOOPPAAAAM
+  MMMMOOONOPPPAAMM
+  MMMMLANOOPALAAMM
+  MMMMMMNOOPAAAAMM
+  MMMMMNOOOPAAMAMM
+  MMMMNOOOOOPAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 340 (knight)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMBPAMMMMMM
+  MMMMMMBPPPAMMMMM
+  MMMMMMPEEPAMMMMM
+  MMMMMMPLLPAMMMMM
+  MMMMMMALLAAMMMMM
+  MMMMMBBAABBMAAAM
+  MMMMBPPPPPPPAAAM
+  MMMMPABPPPAPAAAM
+  MMMMLAMPPMALAAAM
+  MMMMMMBPMPAAAAMM
+  MMMMMMBPAPAAMAMM
+  MMMMMPPAMPPAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 341 (monk)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMCCCMMMMMM
+  MMMMMMJCJJJAMMMM
+  MMMMMMCAAAJAMMMM
+  MMMMMMCAAAJAMMMM
+  MMMMMMCKLKCAAAAM
+  MMMMMCDDDDDDAAAA
+  MMMMCDDLALDDDAAA
+  MMMMDALLALLADAAM
+  MMMMDDDDCDDDDAAM
+  MMMMMAACCCDAAAAM
+  MMMMMCDCCCDDAMAM
+  MMMMCCCCCCCDDMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 342 (priest)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMJLLJMMMMMM
+  MMMMMMJLLJAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLJAMMMMM
+  MMMMMMIJJIAAAAMM
+  MMMMMODDDDDAAAAM
+  MMMMIDNDDDDDAAAM
+  MMMNLNNNDDALAAMM
+  MMMMMMNDDDAAAAMM
+  MMMMMMDIIDAAAAMM
+  MMMMMDDIIDDAMAMM
+  MMMMDIIIIIDDMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 343 (priestess)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMJJMMMMMMM
+  MMMMMMJJJJMMMMMM
+  MMMMMMJLLJAMMMMM
+  MMMMMMJLLJJMMMMM
+  MMMMMJJLLJJMMMMM
+  MMMMMJEJJEJAAAMM
+  MMMMMODEEDDAAAAM
+  MMMMIDINDDDDAAAM
+  MMMMLMNNNDALAAMM
+  MMMMMMINDDAAAAMM
+  MMMMMMINDDAAAAMM
+  MMMMMDDIIDDAMAMM
+  MMMMDIIIIIDDMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 344 (ranger)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMCJAMMMMM
+  MMMMMMMCJJJAMMMM
+  MMMMMMMJEEJAMMMM
+  MMMMMMMJLLJAMMMM
+  MMMMMMMALLAAMMMM
+  MMMMMMGGAAGGMAAA
+  MMMMMBPFFFFPPAAA
+  MMMMMPAGFFFAPAAA
+  MMMMMLAMFFMALAAA
+  MMMMMMMBPMPAAAAM
+  MMMMMMMBPAPAAMAM
+  MMMMMMPPAMPPAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 345 (rogue)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOAMMMOAMMMM
+  MMMMMOOIDPPAMMMM
+  MMMMMMIDDDAMMMMM
+  MMMMMMLKLKAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMMBAABAAMMAM
+  MMMMMKEBBEJAAAAM
+  MMMMKAAEEAAKAAMM
+  MMMMLAJJHJALAAMM
+  MMMMMMKKJKAAAAMM
+  MMMMMKKAMKKAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 346 (samurai)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMAAMMMMM
+  MMMMMMMAAAMMMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMALFLFAMMMMM
+  MMMMMALLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMIIIAAIIIAAAM
+  MMMMLDIIIIDLAAAM
+  MMMMLABBBBALAAAM
+  MMMMLABBBBALAAAM
+  MMMMMMIDDDAAAAMM
+  MMMMMMIDADAAMAMM
+  MMMMMIIAMIIAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 347 (tourist)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMJKJJAMMMMM
+  MMMMMMKJJJAMMMMM
+  MMMJJJJJJJJJJMMM
+  MMMMMMLFLFAAMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMHGAAGHMAAAM
+  MMMMLLGHHGLLAAAM
+  MMMMLAHGHGALAAAM
+  MMMMLAHHGHALAAAM
+  MMMMMMJJJKAAAAMM
+  MMMMMMLLALAAMAMM
+  MMMMMLLAMLLAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 348 (valkyrie)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMLHHLMMMMMM
+  MMMMMHHHHHLMMMMM
+  MMMMLHELELHMMMMM
+  MMMMHHLLLLHMMMMM
+  MMMHHHALLAMMMMMM
+  MMMHJKJAAKJJAAAM
+  MMHHLJJKKJJLAAAM
+  MMHMLACKJCALAAAM
+  MMMMLAAKKAALAAAM
+  MMMMMMKKJKAAAAMM
+  MMMMMMKJAJAAMAMM
+  MMMMMKLAMLKAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 349 (wizard)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMBPMMMMM
+  MMMMMMMBBPEMMMMM
+  MMMMMMBPPEAMMMMM
+  MMMMMMBAAEAMMMMM
+  MMMMMMBAAEAMMMMM
+  MMMMMMPLLEMMMMMM
+  MMMMMMPAAEAMAAAM
+  MMMMMBBPBEEAAAAM
+  MMMMPPPBEEEEAAMM
+  MMMMLABPPEALAAMM
+  MMMMMMBPPEAAAAMM
+  MMMMMBPPPEAAMAMM
+  MMMMMBPPPPEAMMMM
+  MMMMBPPPPPPEMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 350 (Lord Carnarvon)
+{
+  MMMMMMMJJMMMMMMM
+  MMMMMMKJJJMMMMMM
+  MMMMKCKKKJJJMMMM
+  MMMMMMLELEAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMCIAAIKMAAAM
+  MMMMCKKIIKKKAAAM
+  MMMKKCKKHKJKKAAM
+  MMMKKAKHKJAKKAAM
+  MMMKAIHKKJIAKAMM
+  MMMLAICKKJIALAMM
+  MMMMMICKAJIAAAMM
+  MMMMMMCKAPAAAAMM
+  MMMMMPPAMPPAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 351 (Pelias)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMJJMMMMMMM
+  MMMMMMKKKJMMMMMM
+  MMMMMMLELEAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMCKAAKKMAAAM
+  MMMMCKKKKKKKAAAM
+  MMMKKCKKKKJKKAAM
+  MMMKKAKKKKAKKAAM
+  MMMKAMCKKJAAKAMM
+  MMMLAMCKAJAALAMM
+  MMMMMMCKAJAAAAMM
+  MMMMMMCKAPAAAAMM
+  MMMMMPPAMPPAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 352 (Shaman Karnov)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMJJAMMMMMM
+  MMMMMMJJJJAMMMMM
+  MMMMMJFLFLJMMMMM
+  MMMMMJLLLLJMMMMM
+  MMMMMJJDDJAMMMMM
+  MMMMLHAJJAHLAAMM
+  MMMLLLHAAHLLLAAM
+  MMMLLLLHHLLLLAAM
+  MMMLLALHHLALLAAM
+  MMMLLALLLLALLAAM
+  MMMMLACKKJALAAAM
+  MMMMMMCKKJAAAAMM
+  MMMMMMLAMLAAMAMM
+  MMMMMLLAMLLAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 353 (Earendil)
+{
+  MMMMMMMMMGMMMMMM
+  MMMMBMMGGFMMBMMM
+  MMMBBMGGGGABBMMM
+  MMBPBPLELEABPBMM
+  MMBBBPLLLLABBBMM
+  MMPBPPALLAPPPMMM
+  MMMPPBGAAGBBBMMM
+  MMMBBLGGGFLBBBMM
+  MMBBLAAGFAALBBMM
+  MMMBLAGGGFALBMMM
+  MMMMMMGFAFMMMMMM
+  MMMMMMLMMLMAAAMM
+  MMMMMMAAAAAAAAMM
+  MMMMAAAAAAAAMMMM
+  MMMMMAAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 354 (Elwing)
+{
+  MMMMMMMMMGMMMMMM
+  MMMMBMMGGFMMBMMM
+  MMMBBMGGGGABBMMM
+  MMBPBHLELEHBPBMM
+  MMBBBHLLLLHBBBMM
+  MMPBHHALLAHHPMMM
+  MMMPHHGAAGHHBMMM
+  MMMBBLGGGFLBBBMM
+  MMBBLAAGFAALBBMM
+  MMMBLAGGGFALBMMM
+  MMMMMMGFAFMMMMMM
+  MMMMMMLMMLMAAAMM
+  MMMMMMAAAAAAAAMM
+  MMMMAAAAAAAAMMMM
+  MMMMMAAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 355 (Hippocrates)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMLLLCCDMMMMMM
+  MMMLLCCDDAMMMMMM
+  MMMLAAAADAMMMMMM
+  MMMLBABADAMMMMMM
+  MMMLAAAADAMMMMMM
+  MMMCCLLDDMBMMMMM
+  MMMMCKKDDFBFAAAM
+  MMLLLCLDDDBFAAAM
+  MCCCCLDDDFBAAAMM
+  MLALLCCDDFBDAAMM
+  MMMLCCCCDABFAAMM
+  MMMLCCCCDABAAAMM
+  MMLLCCCCDAAMAAMM
+  MLCCCCCCCDAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 356 (King Arthur)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMOHHAMMMMMM
+  MMMMMOHHHHAMMMMM
+  MMMMMHBLBHAMMMMM
+  MMMMMHLLLHAMMMMM
+  MMMMMALLLAAMMMMM
+  MMMMBBAAABBMAAAM
+  MMMBPPPPPPPPAAAM
+  MMMPABPPPPACPAAM
+  MMNNNNNNNNNCLCAM
+  MMMMMBPPMPACAAMM
+  MMMMMBPAPPAAMAMM
+  MMMMMBPAPPAAMAMM
+  MMMMPPAAMPPAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 357 (Grand Master)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMLLMMMMMMM
+  MMMMMMLLLLMMMMMM
+  MMMMMMLLLLMMMMMM
+  MMLCMCALLACMMMMM
+  MCLLCMCAACCCCMMM
+  MCJLACCCCCCCCCMM
+  MMJAACCCCCCCCCCM
+  MMJCCCCCCCCCCCMA
+  MMJMMPPPPPLCCAAA
+  MMJMMCCCCLLCAAAA
+  MMJMMCCCCCCCAAAA
+  MMJMMCCCCCCCAAAA
+  MMJMACCCCCCCAAAM
+  MMJACCCCCCCCAAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 358 (Arch Priest)
+{
+  MMNMMMMMMMMMMMMM
+  MNNNMMJLLJMMMMMM
+  MMNMMMJLLJMMMMMM
+  MMNMMMLLLLMMMMMM
+  MMLCMCALLACMMMMM
+  MCLLCMCAACJDKMMM
+  MCHLACCCCJCCDKMM
+  MMHAACCJJCCCCDKM
+  MMHCCCCJCCJCCCMA
+  MMHMMDCJCCLJCAAA
+  MMHMMDCJCLLCAAAA
+  MMHMMKCJCCDJAAAA
+  MMHMMKCJCCDJAAAA
+  MMHMACCJCCDJAAAM
+  MMHACCCJJCCCAAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 359 (Orion)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMCJAMMMMMM
+  MMMMMMCJJJAMMMMM
+  MMMMMMJEEJAMMMMM
+  MMMMMMJLLJAMMMMM
+  MMMMMMALLAAMMMMM
+  MMMMMGGAAGGMMMMM
+  MMMMBGFFFFFPMMMM
+  MMMMBPFFFFPPAAAM
+  MMMMPAGFFFAPAAAM
+  MMMMLANNNNALAAAM
+  MMMMMMBPMPAAAAAM
+  MMMMMMBPMPAAAAMM
+  MMMMMMBPAPAAMAMM
+  MMMMMPPAMPPAMMMM
+}
+# tile 360 (Master of Thieves)
+{
+  MMMMMMMMMMMMMMMM
+  MMMHMMMMMHMMMMMM
+  MMMHHIDKHHMMMMMM
+  MMMMIDDDDMMMMMMM
+  MMMMLLLLLAMMMMMM
+  MMMMLBLBLAMMMMMM
+  MMMMLLLLLAMMMMMM
+  MMMMMLLLAMMMMMMM
+  MMMMBMAABAAMMMMM
+  MMMKEBBBEJAAAMMM
+  MMKAEEEEEAJAAAMM
+  MMLAJJHHJALAAAMM
+  MMMMJKKKJAAAAAMM
+  MMMMKJAJKAAAAMMM
+  MMMJJAMMJJAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 361 (Lord Sato)
+{
+  MMMMMAAAMMMMMMMM
+  MMMMMAAAMMMMMMMM
+  MMMAAAAAAAMMMMMM
+  MMAALLLLLAAMMMMM
+  MMALFFLFFLAMMMMM
+  MMALLLLLLLAMMMMM
+  MMMAALLLAMMMMMMM
+  IIIIIAAAIIIIAAAM
+  LLDIIIIIIDLLAAAM
+  LLABBBBBBALLAAAM
+  LLABBBBBBALLAAAM
+  LLABBBBBBALLAAAM
+  MMMIIDDDDAAAAAAM
+  MMMIIAAIDAAAMMAM
+  MMIIIAMIIIAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 362 (Twoflower)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMJKJJAMMMMM
+  MMMMMMKJJJAMMMMM
+  MMMMJJJJJJJJMMMM
+  MMMMMNNLNNAMMMMM
+  MMMMNALNALNAMMMM
+  MMMMMNNANNAAMMMM
+  MMMMMAAAAAAMAAAM
+  MMMMLLHGHGLLAAAM
+  MMMMLAGGGGALAAAM
+  MMMMLAHGHGALAAAM
+  MMMMMMJJJKAAAAMM
+  MMMMMMJJAKAAMAMM
+  MMMMMLLAMLLAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 363 (Norn)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMNNNMMMMMMM
+  MMMMMNNNNNMMMMMM
+  MMMMMNELELNMMMMM
+  MMMMNNLLLLNMMMMM
+  MMMNNNALLAMMMMMM
+  MMMNJKJAAKJJAAAM
+  MMNNLJJKKJJLAAAM
+  MMNMLACKJCALAAAM
+  MMMMLAKKKKALAAAM
+  MMMMMMKKJKAAAAMM
+  MMMMMMKJAJAAMAMM
+  MMMMMKLAMLKAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 364 (Neferet the Green)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMGGGMMMMMMM
+  MMMMMGFFFGMMMMMM
+  MMMMGFEFEGMMMMMM
+  MMMMGFFFFEGMMMMM
+  MNMGPEFFFEEMMMMM
+  MIMMBBEAAEAMAAMM
+  MIMBBPPBBEEAAAAM
+  MIGBPPPPPEEEAAMM
+  MIMPPMEPEAAGAAMM
+  MIMMMBPPPAAAAAMM
+  MNMMMBPPPEAAMAMM
+  MMMMBPPPPPEAMMMM
+  MMMBPPPPPPPEMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 365 (Minion of Huhetotl)
+{
+  MMMOPMMMMMMPOMMM
+  MMMOODDDDDDOODMM
+  MMDLOOCDDCOOLDDM
+  MDDDLDDDDDDLDDDM
+  MCCDDDNDDNDDDCCM
+  CCDKDDDDDDDDJCCC
+  CDDKKDDIIDDJJCCD
+  CDDKKKDAADJJDCDD
+  CCDKDDKKKJDDKCDD
+  MCCDKKDDDDKKCDDD
+  MCCDADKDDKDACDDM
+  MDDDADDDDDDADDDM
+  MMMMCCDDDDKKAAMM
+  MMMCDDDAADDDKAAM
+  MMCDDDAAAMDDDKMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 366 (Thoth Amon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMOJJOMMMMMM
+  MMMMMMJJJJAMMMMM
+  MMMMMMBLBLAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMBPAAPPMAAAM
+  MMMMBPPPPPPPAAAM
+  MMMPPBPPPPJPPAAM
+  MMMPPAPPPMAPPAMA
+  MMMPAMBPPMAAPAMA
+  MMMLAMBPPMMALMAM
+  MMMMMMBPAMAMMAMM
+  MMMMMMBPAPAAAAMM
+  MMMMMPPAMPPAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 367 (Chromatic Dragon)
+{
+  MMMMMMGGGFAMMMMM
+  MMMMMNFNFEEAMMMM
+  MMMMGFFFEECAMMMM
+  MMDCHHFMMCCAMMMM
+  CHCHCDMMBCCAMMMM
+  HDMDMMMBFFAMMMMM
+  MMMMMMOBFAAAAAAM
+  MMMMHOGFAAAAAAAA
+  MMHOOIEAMEFMAAAM
+  MHOOOIEEEEFFJAAM
+  MHOOOIEEFFFDDAAM
+  HBOOIIEFFFDDCCAM
+  HBMOIEFOODDMCJAM
+  HBAAGEMAADDACCAM
+  MMMMGFAAMMMCCJAM
+  MMMMMMMMFFFFJAMM
+}
+# tile 368 (Goblin King)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MHMMHMMMHMMMMMMM
+  CLCMHCHCHMMMMMMM
+  CLCMHHHHHMMMMMMM
+  MHMMIIIIIMMMMMMM
+  MHKMIHIHIMIMMMMM
+  MHICKIIIJKKMMMMM
+  MHMIIJJJKMAAMMMM
+  MHMMJICJJAAAAAMM
+  MHMMIIIIJAAAAAMM
+  MMMMJIIJJAAMMMMM
+  MMMMIJKJJAMMMMMM
+  MMMIKAAMIKMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 369 (Cyclops)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMLLLLLMMMMMMM
+  MMMCLLLLLCMMMMMM
+  MMMLBABNNLMMMMMM
+  MMMLBBBNNLJAMMMM
+  MMMCLNNNLCJAMMMM
+  MMMMLLLLLJAAAMMM
+  MMMMLAALLAAAAMMM
+  MMJKJLLLKAKJAAMA
+  MCLKAJJJJAKLCAAA
+  MLLJKAAAAKJLLAAM
+  MLAAJKKKKJAALAAM
+  MLCMGGGHGGACLAAA
+  MLLMJJJJJJALLAAA
+  MMMMCJJJCLAAAAAA
+  MMLLLLLMLLLLLAAM
+}
+# tile 370 (Ixoth)
+{
+  MMMMOMMMMMMOMMMM
+  MMMMOMMMMMMOMMMM
+  MMMLOOCDDCOOLMMM
+  MMMDDDDDDDDDDDMM
+  MCCDDDGDDGDDDCCM
+  CCDKDDDDDDDDJCCC
+  CDDKKKDIIDJJDCCD
+  CDDKDDKJJJDDDCDD
+  CCDKDDDDDDDDKCDD
+  MCCDKKDDDDKKCDDD
+  MCCDADKDDKDACDDM
+  MDDDADDDDDDADDDM
+  MMMMCCDDDDKKAAMM
+  MMMCDDDAADDDKAAM
+  MMCDDDAAAMDDDKMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 371 (Master Kaen)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMKKAMMMMMM
+  MMMMMMKJJKAMMMMM
+  MMKKAMKAAKAMKKAM
+  MKAAKAKDDKAKAAKA
+  MKOOJKKOOKKKOOJA
+  MKJJJJJJJJJKJJJA
+  MMKJJJJJJJJJJJAM
+  MMMMKJJJJJJJAMMM
+  MMMMMMKJJJAAAAAA
+  MMMMMKJJJJKAAAAA
+  MMMMMKJJJJJAAAAA
+  MMMMKJJJJJJKAAAM
+  MMMKJJJJJJJJKAAM
+  MMMKJJJJJJJJJAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 372 (Nalzok)
+{
+  MMMMOMMMMMMOMMMM
+  MMMMOMMMMMMOMMMM
+  MMMLOOCDDCOOLMMM
+  MMMDDDDDDDDDDDMM
+  MCCDDDBDDBDDDCCM
+  CCDKDDDDDDDDJCCC
+  CDDKKKDIIDJJDCCD
+  CDDKDDKJJJDDDCDD
+  CCDKDDDDDDDDKCDD
+  MCCDKKDDDDKKCDDD
+  MCCDADKDDKDACDDM
+  MDDDADDDDDDADDDM
+  MMMMCCDDDDKKAAMM
+  MMMCDDDAADDDKAAM
+  MMCDDDAAAMDDDKMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 373 (Scorpius)
+{
+  MMMMMJLJLJAAMMMM
+  MMMMJAMJCJCKAAMM
+  MMMMAJMMMMMJJJAM
+  MMMMLAMMMMMMLCKA
+  MJAKJAMMMMMMJJJA
+  MMJJAMMMMMMALCJA
+  MMMMMMMALLAJCJKA
+  MMMMJJALCCAAJJAM
+  MJJALLAJCJJJAAMM
+  JAMLCCAJAJJAAAAM
+  MMJACJJJAAACCJAA
+  GGJJJJJAACCAAAJA
+  MJJGGAJACAAJJAAA
+  DMJJAAJAACAMJAAM
+  MMMDMMMJAAJAMJJM
+  MMMMMMMMJAMJAMMM
+}
+# tile 374 (Master Assassin)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMABLBLAMMMMM
+  MMMMMAAAAAAMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMAAAAAAMMPPM
+  MMMMAAAAAAAAPPPM
+  MMMMAAAAAAAAPPPM
+  MMMMLAAAAAALPPPM
+  MMMMMMAAAAAPPPMM
+  MMMMMMAAAAAPMPMM
+  MMMMMAAAMAAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 375 (Ashikaga Takauji)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMAAMMMMMMMM
+  MMMMMMMAAAMMMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMALFLFAMMMMM
+  MMMMMALLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMIIIAAIIIAAAM
+  MMMMLDIIIIDLAAAM
+  MMMMLAIIIIALAAAM
+  MMMMLALHHLALAAAM
+  MMMMMMIIIIAAAAMM
+  MMMMMMIIAIAAMAMM
+  MMMMMIIAMIIAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 376 (Lord Surtur)
+{
+  MMMMPPDDDDAAMMMM
+  MMMMPDDDDDDDAMMM
+  MMMPPDLLLLDDAMMM
+  MMMPDPFLLFFDAMMM
+  MMMPPPLLLLLDAMMM
+  MMMMPLLAALLAAAMM
+  MMMPPALLLLBAAAAM
+  MMMPPDBBBBBBBAAM
+  MMBDDHDPBPPPPPAM
+  MMPPHDDPBPPPPPAM
+  MMLAHDHPBPPAALAA
+  JLAADDHBBBBAALAA
+  JJLJDHHPBPPPCLAA
+  MMLLJBPPABPPLLAA
+  MMMMMBPPABPPAAAA
+  MMMLLLLJMBLLLKAA
+}
+# tile 377 (Dark One)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMAAAMMMMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMMADADAMMMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMAAAAAAAMMMMM
+  MMMMAAAAAAAMMMMM
+  MMMAAAAAAAAAMMMM
+  MMMAAAAAAAAAMMMM
+  MMAAAAAAAAAAAMMM
+  MMAAAAAAAAAAAMMM
+  MMMAAAAAAAAAMMMM
+  MMMAAAAAAAAAAMMM
+  MMAAAAAAAAAAAAMM
+  AAAAAAAAAAAAAAAA
+  MMMMMMMMMMMMMMMM
+}
+# tile 378 (student)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMGGFGGMMMMMM
+  MMMMMMMGMMMMMMMM
+  MMMMMMNDNDMMMMMM
+  MMMDDDDDDDDMMMMM
+  MMMMMMLELEAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMCKAAKJMAAAM
+  MMMMCKKKJJJJAAAM
+  MMMMKACKJJAJAAAM
+  MMMMLACJKJALAAAM
+  MMMMMKCJAJJAMAMM
+  MMMMMCJJMJKJMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 379 (chieftain)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMHHAMMMMMM
+  MMMMMMHHHHAMMMMM
+  MMMMMMLFLFAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMHALLAHMMMMM
+  MMMMLLHAAHLLAAAM
+  MMMMLLLIILLLAAAM
+  MMMMLALIILALAAAM
+  MMMMLAALLAALAAAM
+  MMMMLAJJKJALAAAM
+  MMMMMMLJJLAAAAMM
+  MMMMMMLLALAAMAMM
+  MMMMMLLAMLLAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 380 (neanderthal)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMJJJJMMMMMM
+  MMMMMJJJJJJMMMMM
+  MMMMMJFLFLJMMMMM
+  MMMMMJLLLLJMMMMM
+  MMMMMJJDDJAMMMMM
+  MMMMJJAJJAJJMAAM
+  MMMJLLJAAJLLJAAM
+  MMMLLALJJLALLAAM
+  MMMMLALCCLALAAAM
+  MMMMMMLAMLAAMAMM
+  MMMMMLLAMLLAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 381 (High-elf)
+{
+  MMMMMMMMMGMMMMMM
+  MMMMMMMGGFMMMMMM
+  MMMMMMGGGGAMMMMM
+  MMMMMMLILIAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMMGAAGMMAAMM
+  MMMMMLGGGFLAAAAM
+  MMMMLAAGFAALAAAM
+  MMMMLAMGFAALAAMM
+  MMMMLAMGFAALAAMM
+  MMMMLAGGGFALMAMM
+  MMMMMMGFAFAAMAMM
+  MMMMMMGFAFAAMMMM
+  MMMMMMGFAFAAMMMM
+  MMMMMKLAMLKAMMMM
+}
+# tile 382 (attendant)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMJJJMMMMMMM
+  MMMMMJLLLJMMMMMM
+  MMMMMMBLBMMMMMMM
+  MMMMMCLLLDMMMMMM
+  MMMMMCCKKDAMAAAM
+  MMMMMLLCLDDAAAAM
+  MMMMCCCLDDDDAAMM
+  MMMMLALCCDALAAMM
+  MMMMMMLCCDAAAAMM
+  MMMMMLCCCDAAMAMM
+  MMMMLCCCCCDAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 383 (page)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMBPAMMMMMM
+  MMMMMMBPPPAMMMMM
+  MMMMMMPEEPAMMMMM
+  MMMMMMPLLPAMMMMM
+  MMMMMMMLLAAMMMMM
+  MMMMMMBAABAMAAAM
+  MMMMMBPPPPPAAAAM
+  MMMMPABPPPAPAAAM
+  MMMMLAMPPMALAAAM
+  MMMMMMBPMPAAAAMM
+  MMMMMMLLALAAMAMM
+  MMMMMLLAMLLAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 384 (abbot)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMKLKMMMMMMM
+  MMMMMMLLLMMMMMMM
+  MMMMCCLLLJJMMMMM
+  MMMMKCKLKKJAAAMM
+  MMMMCDDDDDDAAAAM
+  MMMCDDLALDDDAAAM
+  MMMDALLALLADAAMM
+  MMMDDDDCDDDDAAMM
+  MMMMAACCCDAAAAMM
+  MMMMCDCCCDDAMAMM
+  MMMCCCCCCCDDMMMM
+}
+# tile 385 (acolyte)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMJJJJMMMMMM
+  MMMMMMJLLJAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLJAMMMMM
+  MMMMMMCJJCAAAAMM
+  MMMMMLDDDDDAAAAM
+  MMMMCDCCDDDDAAAM
+  MMMMLMLCCDALAAMM
+  MMMMMMLCCDAAAAMM
+  MMMMMMLCCDAAAAMM
+  MMMMMLDCCDDAMAMM
+  MMMMLCCCCCDDMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 386 (hunter)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJMMCJAMMMMMM
+  MMMJMMCJJJAMMMMM
+  MMMJMMJEEJAMMMMM
+  MMJMMMJLLJAMMMMM
+  MMJMMMALLAAMMMMM
+  MMJMMGGAAGGMAAAM
+  MMLPBPFFFFPPAAAM
+  MMJMMAGFFFAPAAAM
+  MMJMMMMFFMALAAAM
+  MMMJMMBPMPAAAAMM
+  MMMJMMBPAPAAMAMM
+  MMMMJPPAMPPAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 387 (thug)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMIDMMMMMMM
+  MMMMMMIDDDAMMMMM
+  MMMMMMLKLKAMMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMKKAAKKAMMAM
+  MMMMKKJKKJJKAAAM
+  MMMMKAAJJAAKAAMM
+  MMMMLAJJJJALAAMM
+  MMMMMMKKJKAAAAMM
+  MMMMMMKAAKAAAAMM
+  MMMMMKKAMKKAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 388 (ninja)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMAAMMMMM
+  MMMMMMMAAAMMMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMAFLFLAMMMMM
+  MMMMMAAAAAAMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMAAAAAAAAMPPM
+  MMMMAAAAAAAAPPPM
+  MMMMAAAAAAAAPPPM
+  MMMMLAAAAAALPPPM
+  MMMMMMAAAAAPPPMM
+  MMMMMMAAAAAPMPMM
+  MMMMMAAAMAAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 389 (roshi)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMAAAAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMALFLFAMMMMM
+  MMMMMALLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMPPPAAPPPAAAM
+  MMMMLMPPPPMLAAAM
+  MMMMLAOOOOALAAAM
+  MMMMLAOOOOALAAAM
+  MMMMMMPMMMAAAAMM
+  MMMMMMPMAMAAMAMM
+  MMMMMPPAMPPAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 390 (guide)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMJKJJAMMMMM
+  MMMMMMKJJJAMMMMM
+  MMMMJJJJJJJJMMMM
+  MMMMMMLFLFAAMMMM
+  MMMMMMLLLLAMMMMM
+  MMMMMMALLAMMMMMM
+  MMMMMHHAAHHMAAAM
+  MMMMLLHHHHLLAAAM
+  MMMMLAHHHHALAAAM
+  MMMMLAHHHHALAAAM
+  MMMMMMJJJKAAAAMM
+  MMMMMMJJAKAAMAMM
+  MMMMMLLAMLLAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 391 (warrior)
+{
+  MMMMMOMMMMOMMMMM
+  MMMMMNOMMONMMMMM
+  MMMMMMNPPNMMMMMM
+  MMMMMPPPPPPMMMMM
+  MMMMMPELELPMMMMM
+  MMMMHHLLLLHMMMMM
+  MMMHHHALLAMMMMMM
+  MMMHJKJAAKJJAAAM
+  MMHHLJJKKJJLAAAM
+  MMHMLACKJCALAAAM
+  MMMMLAAKKAALAAAM
+  MMMMMMKKJKAAAAMM
+  MMMMMMKJAJAAMAMM
+  MMMMMMKJAJAAMAMM
+  MMMMMKLAMLKAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 392 (apprentice)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMJJJMMMMMMM
+  MMMMMJLLLJMMMMMM
+  MMMMMMGLGMMMMMMM
+  MMMMMBLLLEMMMMMM
+  MMMMMBBEEEAMAAAM
+  MMMMMBBPBEEAAAAM
+  MMMMPPPBEEEEAAMM
+  MMMMLABPPEALAAMM
+  MMMMMMBPPEAAAAMM
+  MMMMMBPPPEAAMAMM
+  MMMMMBPPPPEAMMMM
+  MMMMBPPPPPPEMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 393 (invisible monster)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMNNNNMMMMMMM
+  MMMMNNNNNNMMMMMM
+  MMMNNAAAANNMMMMM
+  MMMNNAMMMNNAMMMM
+  MMMMAAMMMNNAMMMM
+  MMMMMMMMNNAAMMMM
+  MMMMMMMNNAAMMMMM
+  MMMMMMNNAAMMMMMM
+  MMMMMMNNAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMNNMMMMMMMM
+  MMMMMMNNAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
diff --git a/win/share/objects.txt b/win/share/objects.txt
new file mode 100644 (file)
index 0000000..4592352
--- /dev/null
@@ -0,0 +1,8281 @@
+A = (0, 0, 0)
+B = (0, 182, 255)
+C = (255, 108, 0)
+D = (255, 0, 0)
+E = (0, 0, 255)
+F = (0, 145, 0)
+G = (108, 255, 0)
+H = (255, 255, 0)
+I = (255, 0, 255)
+J = (145, 71, 0)
+K = (204, 79, 0)
+L = (255, 182, 145)
+M = (71, 108, 108)
+N = (255, 255, 255)
+O = (218, 218, 182)
+P = (108, 145, 182)
+# tile 0 (strange object)
+{
+  MMMMMMMMMMMMMMMM
+  MMMCJKKKCJKKKCMM
+  MCKJKKCKJKKCJJKM
+  MKJKKKKJKKKKJJJM
+  CJKKKCJKKKCJJJJM
+  CJKKKCJKKKCJJAJM
+  CCCCCHHCCCCJAJJM
+  AADDAAAADDAAJJJM
+  CCCCCHHCCCCJJJJM
+  CJJJHJJHJJJJJJJM
+  CJKKKHHKKKCJJJJA
+  CJKKKHHKKKCJJJJA
+  CJKKKCJKKKCJJJAA
+  CJCCCCJCCCCJJAAM
+  CKKKKKKKKKKJAAMM
+  MAAAAAAAAAAAAMMM
+}
+# tile 1 (arrow)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMPPMMMM
+  MMMMMMMMMPBPOMMM
+  MMMMMMMMMBPOBLMM
+  MMMMMMMMMPOBLAMM
+  MMMMMMMMJPAAAMMM
+  MMMMMMMJKAMMMMMM
+  MMMMMMJKAMMMMMMM
+  MMMMMJKAMMMMMMMM
+  MMMMJKAMMMMMMMMM
+  MMMJKAMMMMMMMMMM
+  MOOCAMMMMMMMMMMM
+  MONNAMMMMMMMMMMM
+  MNNOAMMMMMMMMMMM
+  MMAAAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 2 (runed arrow / elven arrow)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMFFMMMM
+  MMMMMMMMMFGFOMMM
+  MMMMMMMMMGFOGHMM
+  MMMMMMMMMFOGHAMM
+  MMMMMMMMJFAAAMMM
+  MMMMMMMJKAMMMMMM
+  MMMMMMJKAMMMMMMM
+  MMMMMJKAMMMMMMMM
+  MMMMJKAMMMMMMMMM
+  MMMJKAMMMMMMMMMM
+  MOOCAMMMMMMMMMMM
+  MONNAMMMMMMMMMMM
+  MNNOAMMMMMMMMMMM
+  MMAAAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 3 (crude arrow / orcish arrow)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMPPMMMM
+  MMMMMMMMMPBPOMMM
+  MMMMMMMMMBPOBLMM
+  MMMMMMMMMPOBLAMM
+  MMMMMMMMJKAAAMMM
+  MMMMMMMJKAMMMMMM
+  MMMMMMJKAMMMMMMM
+  MMMMMJKAMMMMMMMM
+  MMMMJKAMMMMMMMMM
+  MMMJKAMMMMMMMMMM
+  MOJCAMMMMMMMMMMM
+  MONAAMMMMMMMMMMM
+  MNNOAMMMMMMMMMMM
+  MMAAAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 4 (silver arrow)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMDPMMMM
+  MMMMMMMMMDBDOMMM
+  MMMMMMMMMBDOBDMM
+  MMMMMMMMMDOBDAMM
+  MMMMMMMMPPAAAMMM
+  MMMMMMMPPAMMMMMM
+  MMMMMMPPAMMMMMMM
+  MMMMMPPAMMMMMMMM
+  MMMMPPAMMMMMMMMM
+  MMMPPAMMMMMMMMMM
+  MOPPAMMMMMMMMMMM
+  MOPPAMMMMMMMMMMM
+  MNNOAMMMMMMMMMMM
+  MMAAAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 5 (bamboo arrow / ya)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMBPMMMM
+  MMMMMMMMMBBPOMMM
+  MMMMMMMMBBPOBLMM
+  MMMMMMMMMPOBLAMM
+  MMMMMMMMCJBLAMMM
+  MMMMMMMCJAMAMMMM
+  MMMMMMCJAMMMMMMM
+  MMMMMCJAMMMMMMMM
+  MMMMCJAMMMMMMMMM
+  MMMCJAMMMMMMMMMM
+  MMCJAMMMMMMMMMMM
+  OCJAMMMMMMMMMMMM
+  ONAMMMMMMMMMMMMM
+  NNPAMMMMMMMMMMMM
+  MAAMMMMMMMMMMMMM
+}
+# tile 6 (crossbow bolt)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMMMMMMMMMMMM
+  MMAONMMMMMMMMMMM
+  MMMAOKMMMMMMMMMM
+  MMMMAJKMMMMMMMMM
+  MMMMMAJKMMMMMMMM
+  MMMMMMAJKMMMMMMM
+  MMMMMMMAJKMMMMMM
+  MMMMMMMMAJKMMMMM
+  MMMMMMMMMAJKMMMM
+  MMMMMMMMMMAJJMMM
+  MMMMMMMMMMMAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 7 (dart)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMOOOMM
+  MMMMMCLCLMOBBAMM
+  MNNNCJDJDCBAAAMM
+  MAAAAJDJDAOBBMMM
+  MMMMMAAAAMMOOOMM
+  MMMMMMMMMMMAAAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 8 (throwing star / shuriken)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPNMMMMMMMMM
+  MMMMMNAPNNPMMMMM
+  MMMMMNNNNANAMMMM
+  MMMMMPNNNPAAMMMM
+  MMMMNMNNNNMMMMMM
+  MMMMPNNPANAMMMMM
+  MMMMMAAANPAMMMMM
+  MMMMMMMMMAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 9 (boomerang)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKKMMMMMMMMMM
+  MMMMKHKAMMMMMMMM
+  MMMMMKHKAMMMMMMM
+  MMMMMMKKKAMMMMMM
+  MMMMMMMKKKAMMMMM
+  MMMMMMMMKDKAMMMM
+  MMMMMMMMJDKAMMMM
+  MMMMMMMJKDJAMMMM
+  MMMMMMJKDJAMMMMM
+  MMMMMJHDJAMMMMMM
+  MMMMJHDJAMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 10 (spear)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMNM
+  MMMMMMMMMMMMMNOM
+  MMMMMMMMMMMMNOAM
+  MMMMMMMMMMMNOAAM
+  MMMMMMMMMMKJAAMM
+  MMMMMMMMMKJAAMMM
+  MMMMMMMMKJLAMMMM
+  MMMMMMMKJAAJAMMM
+  MMMMMMKJAAKJAMMM
+  MMMMMKJAAMCJAMMM
+  MMMMKJAAMMLAMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MMJAAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 11 (runed spear / elven spear)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMNM
+  MMMMMMMMMMMMMNOM
+  MMMMMMMMMMMMNOAM
+  MMMMMMMMMMMNOAAM
+  MMMMMMMMMMKJAAMM
+  MMMMMMMMMKJAAMMM
+  MMMMMMMMKJLAMMMM
+  MMMMMMMKJAAFAMMM
+  MMMMMMKJAAFFAMMM
+  MMMMMKJAAMGFAMMM
+  MMMMKJAAMMHAMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MMJAAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 12 (crude spear / orcish spear)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMNM
+  MMMMMMMMMMMMMNOM
+  MMMMMMMMMMMMNOAM
+  MMMMMMMMMMMKJAAM
+  MMMMMMMMMMKJAAMM
+  MMMMMMMMMLJAAMMM
+  MMMMMMMMKJLAMMMM
+  MMMMMMMKJAAJAMMM
+  MMMMMMKJAKKJAMMM
+  MMMMMKJAAMCJAMMM
+  MMMMKJAAMMLAMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MMJAAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 13 (stout spear / dwarvish spear)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMNMM
+  MMMMMMMMMMMMNOMM
+  MMMMMMMMMMMNOAMM
+  MMMMMMMMMMNOAAMM
+  MMMMMMMMMKJAAMMM
+  MMMMMMMMKJAAMMMM
+  MMMMMMMKJLAMMMMM
+  MMMMMMKJAAJAMMMM
+  MMMMMKJAACJAMMMM
+  MMMMKJAAMLAMMMMM
+  MMMKJAAMMMMMMMMM
+  MMJJAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 14 (silver spear)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMOA
+  MMMMMMMMMMMMMOAM
+  MMMMMMMMMMMMPAMM
+  MMMMMMMMMMMPAMMM
+  MMMMMMMMMMPAMMMM
+  MMMMMMMMMPAMMMMM
+  MMMMMMMMPAMMMMMM
+  MMMMMMMBAMMMMMMM
+  MMMMMMBAMMMMMMMM
+  MMMMMPAMMMMMMMMM
+  MMMMPAMMMMMMMMMM
+  MMMPAMMMMMMMMMMM
+  MMOAMMMMMMMMMMMM
+  MOAMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 15 (throwing spear / javelin)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMOA
+  MMMMMMMMMMMMMOAM
+  MMMMMMMMMMMMIAMM
+  MMMMMMMMMMMIAMMM
+  MMMMMMMMMMIAMMMM
+  MMMMMMMMMIAMMMMM
+  MMMMMMMMIAMMMMMM
+  MMMMMMMLAMMMMMMM
+  MMMMMMLAMMMMMMMM
+  MMMMMIAMMMMMMMMM
+  MMMMIAMMMMMMMMMM
+  MMMIAMMMMMMMMMMM
+  MMOAMMMMMMMMMMMM
+  MOAMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 16 (trident)
+{
+  MMMMMMMMMMMMMMMM
+  MMMPAMMMMMMMMMMM
+  MMMMPAMMMMMMMMMM
+  MMPAMPAMMMMMMMMM
+  PAMPAMPAMMMMMMMM
+  MPAMPAPAMMMMMMMM
+  MMPAMPPAMMMMMMMM
+  MMMPPPPAMMMMMMMM
+  MMMMMMMPAMMMMMMM
+  MMMMMMMMPAMMMMMM
+  MMMMMMMMMPAMMMMM
+  MMMMMMMMMMPKAMMM
+  MMMMMMMMMMJPKAMM
+  MMMMMMMMMMMJPKAM
+  MMMMMMMMMMMMJAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 17 (dagger)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMNMMMMMM
+  MMMMMMMMNOAMMMMM
+  MMMMMMMNOAAMMMMM
+  MMMMOONOAAMMMMMM
+  MMMMMKOOAMMMMMMM
+  MMMMKJAOAMMMMMMM
+  MMMKJAAAAMMMMMMM
+  MMMAAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 18 (runed dagger / elven dagger)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMNMMMMMM
+  MMMMMMMMNOAMMMMM
+  MMMMMMMNOAAMMMMM
+  MMMMOONOAAMMMMMM
+  MMMMMKOOAMMMMMMM
+  MMMMKFAOAMMMMMMM
+  MMMKFAAAAMMMMMMM
+  MMMAAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 19 (crude dagger / orcish dagger)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMNMMMMMM
+  MMMMMMMMNOAMMMMM
+  MMMMMMMNOAAMMMMM
+  MMMMOMNOAAMMMMMM
+  MMMMMCOAAMMMMMMM
+  MMMMKJAOAMMMMMMM
+  MMMKJAAAAMMMMMMM
+  MMMAAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 20 (silver dagger)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMNMMMMMM
+  MMMMMMMMNPAMMMMM
+  MMMMMMMNPAAMMMMM
+  MMMMBBNPAAMMMMMM
+  MMMMMKPPAMMMMMMM
+  MMMMKJAPAMMMMMMM
+  MMMKJAAAAMMMMMMM
+  MMMAAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 21 (athame)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMPMM
+  MMMMMMMMMMMMNPAM
+  MMMMMMMMMMMPPAMM
+  MMMMMMMMMMNOAAMM
+  MMMMMMMMMPPAMMMM
+  MMMMMMMMNOAAMMMM
+  MMMMMMPPPAMMMMMM
+  MMMMPONOPAMMMMMM
+  MMMMMKPBAMMMMMMM
+  MMMMKJAOAMMMMMMM
+  MMMKJAMMMMMMMMMM
+  MMMMAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 22 (scalpel)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMNAMMMMMMMMMM
+  MMMMONAMMMMMMMMM
+  MMMMMPBAMMMMMMMM
+  MMMMMMMPAMMMMMMM
+  MMMMMMMMPAMMMMMM
+  MMMMMMMMMPAMMMMM
+  MMMMMMMMMMPAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 23 (knife)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMNMMMMMM
+  MMMMMMMMNOAMMMMM
+  MMMMMMMNOAAMMMMM
+  MMMMMMNOAAMMMMMM
+  MMMMMKLAAMMMMMMM
+  MMMMKLAAMMMMMMMM
+  MMMKLAAMMMMMMMMM
+  MMMAAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 24 (stiletto)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMOAMMM
+  MMMMMMMMMMOAMMMM
+  MMMMMMMMPOAMMMMM
+  MMMMMMMPOAMMMMMM
+  MMMMMMOOAMMMMMMM
+  MMMOPNOAMMMMMMMM
+  MMMMKJAAMMMMMMMM
+  MMMKJAOPMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MMAAAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 25 (worm tooth)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMOMMMMMMMMM
+  MMMMMMNAMMMMMMMM
+  MMMMMMNOAMMMMMMM
+  MMMMMMPOAMMMMMMM
+  MMMMMMMOAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 26 (crysknife)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMNOAMMM
+  MMMMMMMMMPPAAMMM
+  MMMMMMMMNOAAMMMM
+  MMMMMMPPPAMMMMMM
+  MMMMPONOPAMMMMMM
+  MMMMMKPBAMMMMMMM
+  MMMMKJAOAMMMMMMM
+  MMMKJAMMMMMMMMMM
+  MMMMAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 27 (axe)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMOPAMMMMMMMM
+  MMMMOPPPAMMMMMMM
+  MMMOPPPPPAMMMMMM
+  MMMKPKPPPAMMMMMM
+  MMMMKPPPAMMMMMMM
+  MMMMMKAAMMMMMMMM
+  MMMMMMKAMMMMMMMM
+  MMMMMMMCAMMMMMMM
+  MMMMMMMMCAMMMMMM
+  MMMMMMMMMCAMMMMM
+  MMMMMMMMMMCAMMMM
+  MMMMMMMMMMMCAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 28 (double-headed axe / battle-axe)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMOPPAMMMMMMMM
+  MMMMOPPPAMMMMMMM
+  MMMKPPPPAMMMMMMM
+  MOPPKPPPAMMMMMMM
+  MOPPPKAAMMMMMMMM
+  MPPPPAKAMMMMMMMM
+  MMPPPAMCAMMMMMMM
+  MMMAAMMMCAMMMMMM
+  MMMMMMMMMCAMMMMM
+  MMMMMMMMMMCAMMMM
+  MMMMMMMMMMMCAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 29 (short sword)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMAONMMMMMMMMMM
+  MMMMAONMMMMMMMMM
+  MMMMMAONMMMMMMMM
+  MMMMMMAONAPOMMMM
+  MMMMMMMAOOKMMMMM
+  MMMMMMAPOAJKMMMM
+  MMMMMMAAAAAJKMMM
+  MMMMMMMMMMAAJMMM
+  MMMMMMMMMMMAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 30 (runed short sword / elven short sword)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMAONMMMMMMMMMM
+  MMMMAONMMMMMMMMM
+  MMMMMAONMMMMMMMM
+  MMMMMMAONAPOMMMM
+  MMMMMMMAOOMMMMMM
+  MMMMMMAPOFGMMMMM
+  MMMMMMAAAAFGMMMM
+  MMMMMMMMMMAFGMMM
+  MMMMMMMMMMMAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 31 (crude short sword / orcish short sword)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMAONMMMMMMMMMM
+  MMMMAONMMMMMMMMM
+  MMMMMAONMMMMMMMM
+  MMMMMAAONAPOMMMM
+  MMMMMMMAOOKMMMMM
+  MMMMMMAPOBJKMMMM
+  MMMMMMAAAABJKMMM
+  MMMMMMMMMMABJMMM
+  MMMMMMMMMMMAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 32 (broad short sword / dwarvish short sword)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMAONMMMMMMMMMM
+  MMMMAONMMMMMMMMM
+  MMMMMAONPMMMMMMM
+  MMMMMAAONAPOMMMM
+  MMMMMMMAOOMMMMMM
+  MMMMMMAPOJJMMMMM
+  MMMMMMAAAAJJMMMM
+  MMMMMMMMMMAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 33 (curved sword / scimitar)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MANMMMMMMMMMMMMM
+  MAPNMMMMMMMMMMMM
+  MMAOOMMMMMMMMMMM
+  MMAANOMMMMMMMMMM
+  MMMAPNOMMMMMMMMM
+  MMMMAPNNMMMMMMMM
+  MMMMMAAONPOMMMMM
+  MMMMMMMAPOAMMMMM
+  MMMMMMAPOJKJMMMM
+  MMMMMMMMAAJKJMMM
+  MMMMMMMMMMAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 34 (silver saber)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNAMMM
+  MMMMMMMMMMPOPAMM
+  MMMMMMMMMPNOPAMM
+  MMMMMMMMPNNPAMMM
+  MMMMPPANNOPAMMMM
+  MMMMMOOOAAMMMMMM
+  MMMMMJJOPAMMMMMM
+  MMMKJJAAAMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 35 (broadsword)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMMMMMMMMMMMM
+  MMANNMMMMMMMMMMM
+  MMAONNMMMMMMMMMM
+  MMMAONNMMMMMMMMM
+  MMMMAONNMMMMMMMM
+  MMMMMAONNMMMMMMM
+  MMMMMMAONNPOMMMM
+  MMMMMMMAOOKMMMMM
+  MMMMMMAPOAJKMMMM
+  MMMMMMAAAAAJKMMM
+  MMMMMMMMMMAAJMMM
+  MMMMMMMMMMMAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 36 (runed broadsword / elven broadsword)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMMMMMMMMMMMM
+  MMANNMMMMMMMMMMM
+  MMAONNMMMMMMMMMM
+  MMMAONNMMMMMMMMM
+  MMMMAONNMMMMMMMM
+  MMMMMAONNMMMMMMM
+  MMMMMMAONNPOMMMM
+  MMMMMMMAOOGMMMMM
+  MMMMMMAPOFFGMMMM
+  MMMMMMAAAAAFGMMM
+  MMMMMMMMMMAAJMMM
+  MMMMMMMMMMMAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 37 (long sword)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMOMM
+  MMMMMMMMMMMMOPAM
+  MMMMMMMMMMMOPAAM
+  MMMMMMMMMMNPAAMM
+  MMMMMMMMMNPAAMMM
+  MMMMMMMMNPAAMMMM
+  MMMMMMMNPAAMMMMM
+  MMMMMMNOAAMMMMMM
+  MMMMMNOAAMMMMMMM
+  MMOPNOAAMMMMMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAOPMMMMMMMMM
+  MNDAAMMMMMMMMMMM
+  MAAAMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 38 (two-handed sword)
+{
+  MMMMMMMMMMMMMMNM
+  MMMMMMMMMMMMMNOM
+  MMMMMMMMMMMMNOAM
+  MMMMMMMMMMMNOAAM
+  MMMMMMMMMMNOAAMM
+  MMMMMMMMMNOAAMMM
+  MMMMMMMMNOAAMMMM
+  MMMMMMMNNAAMMMMM
+  MMMMOPNNAAMMMMMM
+  MMMMMKIIAMMMMMMM
+  MMMMKJAOPMMMMMMM
+  MMMKJAAAAMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MNDAAMMMMMMMMMMM
+  MAAAMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 39 (samurai sword / katana)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMNM
+  MMMMMMMMMMMMMONM
+  MMMMMMMMMMMMPNAM
+  MMMMMMMMMMMMNPAM
+  MMMMMMMMMMMOOAMM
+  MMMMMMMMMMONAAMM
+  MMMMMMMMMONPAMMM
+  MMMMMMMMNNPAMMMM
+  MMMMMOPNOAAMMMMM
+  MMMMMAOPAMMMMMMM
+  MMMMJKJOPAMMMMMM
+  MMMJKJAAMMMMMMMM
+  MMJJAAMMMMMMMMMM
+  MMAAMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 40 (long samurai sword / tsurugi)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMNM
+  MMMMMMMMMMMMMNPM
+  MMMMMMMMMMMMNOAM
+  MMMMMMMMMMMOOAMM
+  MMMMMMMMMMONAMMM
+  MMMMMMMMMONAMMMM
+  MMMMMMMMNNAMMMMM
+  MMMMMOPNOAMMMMMM
+  MMMMMAOPAMMMMMMM
+  MMMMJKJOPAMMMMMM
+  MMMJKJAAMMMMMMMM
+  MMJJAAMMMMMMMMMM
+  MMAAMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 41 (runed broadsword / runesword)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMAMM
+  MMMMMMMMMMMMAAPM
+  MMMMMMMMMMMAAPPM
+  MMMMMMMMMMAAPPMM
+  MMMMMMMMMAAPPMMM
+  MMMMMMMMAAPPMMMM
+  MMMMMMMAAPPMMMMM
+  MMMMMMAAPPMMMMMM
+  MMMMMAAPPMMMMMMM
+  MMOPAAPPMMMMMMMM
+  MMMNNPPMMMMMMMMM
+  MMNNPOPMMMMMMMMM
+  MNNPPMMMMMMMMMMM
+  MPPPMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 42 (vulgar polearm / partisan)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMPOM
+  MMMMMMMMMMMMPNPM
+  MMMMMMMMMMMONPAM
+  MMMMMMMMMMONOAAM
+  MMMMMMMMMMNOAAMM
+  MMMMMMMMMKJAAMMM
+  MMMMMMMMKJAAMMMM
+  MMMMMMMKJAAMMMMM
+  MMMMMMKJAAMMMMMM
+  MMMMMKJAAMMMMMMM
+  MMMMKJAAMMMMMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MJJAAMMMMMMMMMMM
+  JJAAMMMMMMMMMMMM
+}
+# tile 43 (hilted polearm / ranseur)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMPNM
+  MMMMMMMMMMMMPNPM
+  MMMMMMMMMMMPNOAM
+  MMMMMMMPOPPNOAAM
+  MMMMMMMOAONOAMMM
+  MMMMMMMAAKOOPMMM
+  MMMMMMMMKJAAOAMM
+  MMMMMMMKJAAOPAMM
+  MMMMMMKJAAMAAMMM
+  MMMMMKJAAMMMMMMM
+  MMMMKJAAMMMMMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MJJAAMMMMMMMMMMM
+  JJAAMMMMMMMMMMMM
+}
+# tile 44 (forked polearm / spetum)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMPNM
+  MMMMMMMMMMMMPNPM
+  MMMMMMMMPOMPNOAM
+  MMMMMMMMOPANOAAM
+  MMMMMMMMAONOAMMM
+  MMMMMMMMAKOOPOAM
+  MMMMMMMMKJAAOPAM
+  MMMMMMMKJAAAAAMM
+  MMMMMMKJAAMMMMMM
+  MMMMMKJAAMMMMMMM
+  MMMMKJAAMMMMMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MJJAAMMMMMMMMMMM
+  JJAAMMMMMMMMMMMM
+}
+# tile 45 (single-edged polearm / glaive)
+{
+  MMMMMMMMMMMMMKAM
+  MMMMMMMMMMMMKNOA
+  MMMMMMMMMMMKNNPA
+  MMMMMMMMMMKNNPAM
+  MMMMMMMMMKNNPAMM
+  MMMMMMMMKNNPAMMM
+  MMMMMMMKJAAAMMMM
+  MMMMMMKJAAMMMMMM
+  MMMMMKJAAMMMMMMM
+  MMMMKJAAMMMMMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MKJAAMMMMMMMMMMM
+  KJAAMMMMMMMMMMMM
+  JAAMMMMMMMMMMMMM
+  AAMMMMMMMMMMMMMM
+}
+# tile 46 (lance)
+{
+  PAMMMMMMMMMMMMMM
+  MPAMMMMMMMMMMMMM
+  MMBAMMMMMMMMMMMM
+  MMMOAMMMMMMMMMMM
+  MMMMOAMMMMMMMMMM
+  MMMMMNAMMMMMMMMM
+  MMMMMMNAMMMMMMMM
+  MMMMMMPNAMMMMMMM
+  MMMMMMMPNAMMMMMM
+  MMMMMMMMBNAMMMMM
+  MMMMMMMMMONAMMMM
+  MMMMMMMMMMNNOOOA
+  MMMMMMMMMMOONOAM
+  MMMMMMMMMMOOONOA
+  MMMMMMMMMMOAMONO
+  MMMMMMMMMMMMMMON
+}
+# tile 47 (angled poleaxe / halberd)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMOOOAMMM
+  MMMMMMMMMPPPKKMM
+  MMMMMMMMMPPKKOOM
+  MMMMMMMMMMKJPPPA
+  MMMMMMMMMKJAPPPA
+  MMMMMMMMKJAMAAAM
+  MMMMMMMKJAMMMMMM
+  MMMMMMKJAMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMKJAAMMMMMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MKJAAMMMMMMMMMMM
+  JJAAMMMMMMMMMMMM
+  JAAMMMMMMMMMMMMM
+}
+# tile 48 (long poleaxe / bardiche)
+{
+  MMMMMMMMMMMMMNAM
+  MMMMMMMMMMMMPOPA
+  MMMMMMMMMMMPNOPA
+  MMMMMMMMMMPNNPAM
+  MMMMMMMMMNNOPAMM
+  MMMMMMMMKOAAMMMM
+  MMMMMMMKJAAMMMMM
+  MMMMMMKJAAMMMMMM
+  MMMMMKJAAMMMMMMM
+  MMMMKJAAMMMMMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MKJAAMMMMMMMMMMM
+  JJAAMMMMMMMMMMMM
+  JAAMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 49 (pole cleaver / voulge)
+{
+  MMMMMMMMMMMMMNAM
+  MMMMMMMMMMMMNNOA
+  MMMMMMMMMMMNNNPA
+  MMMMMMMMMMNNNPAM
+  MMMMMMMMMNNOPAMM
+  MMMMMMMMKOAAMMMM
+  MMMMMMMKJAAMMMMM
+  MMMMMMKJAAMMMMMM
+  MMMMMKJAAMMMMMMM
+  MMMMKJAAMMMMMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MKJAAMMMMMMMMMMM
+  KJAAMMMMMMMMMMMM
+  JAAMMMMMMMMMMMMM
+  AAMMMMMMMMMMMMMM
+}
+# tile 50 (broad pick / dwarvish mattock)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMONOAMMMMMM
+  MMMMMMMMPNOAMMMM
+  MMMMMMMMMNONAMMM
+  MMMMMMMMKJAANAMM
+  MMMMMMMKJAMMMNAM
+  MMMMMMKJAMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMKJAMMMMMMMMM
+  MMMKJAMMMMMMMMMM
+  MMKJAMMMMMMMMMMM
+  MKJAMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 51 (pole sickle / fauchard)
+{
+  MMMMMMMMMMNNNMMM
+  MMMMMMMMMNPPPNMM
+  MMMMMMMMMNPAAPNM
+  MMMMMMMMMNPAMANA
+  MMMMMMMMMMNAMMAA
+  MMMMMMMMMNPAMMMM
+  MMMMMMMMKJAMMMMM
+  MMMMMMMKJAMMMMMM
+  MMMMMMKJAMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMKJAMMMMMMMMM
+  MMMKJAMMMMMMMMMM
+  MMKJAMMMMMMMMMMM
+  MKJAMMMMMMMMMMMM
+  KJAMMMMMMMMMMMMM
+  MAMMMMMMMMMMMMMM
+}
+# tile 52 (pruning hook / guisarme)
+{
+  MMMMMMMMMMMMMNAM
+  MMMMMMMMMMMMPOPA
+  MMMMMMPNNPMPNOPA
+  MMMMMMNAANPNNPAM
+  MMMMMMMAMNNOPAMM
+  MMMMMMMMKOAAMMMM
+  MMMMMMMKJAAMMMMM
+  MMMMMMKJAAMMMMMM
+  MMMMMKJAAMMMMMMM
+  MMMMKJAAMMMMMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MKJAAMMMMMMMMMMM
+  KJAAMMMMMMMMMMMM
+  JAAMMMMMMMMMMMMM
+  AAMMMMMMMMMMMMMM
+}
+# tile 53 (hooked polearm / bill-guisarme)
+{
+  MMMMMMMMMMMMMPNM
+  MMMMMMMMMMMMPNAM
+  MMMMMMMMMMMMPOPA
+  MMMMMMPNNPMPNOPA
+  MMMMMMNAANPNNPAM
+  MMMMMMMAMNNOPAMM
+  MMMMMMMMKOAAMMMM
+  MMMMMMMKJAAMMMMM
+  MMMMMMKJAAMMMMMM
+  MMMMMKKJAMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMONJAMMMMMMMMM
+  MMONOAAMMMMMMMMM
+  MPNOAAMMMMMMMMMM
+  PNPAAMMMMMMMMMMM
+  OPAAMMMMMMMMMMMM
+}
+# tile 54 (pronged polearm / lucern hammer)
+{
+  MMMMMMMMMNPMMMMM
+  MMMMMMMMMPNPMMMM
+  MMMMMMMMMAPPPKMM
+  MMMMMMMMMMAPKPPO
+  MMMMMMMMMMMKPPPO
+  MMMMMMMMMMKAPPPP
+  MMMMMMMMMKJAPPPA
+  MMMMMMMMKJAMAAAM
+  MMMMMMMKJAAMMMMM
+  MMMMMMKJAAMMMMMM
+  MMMMMKJAAMMMMMMM
+  MMMMKJAAMMMMMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MJJAAMMMMMMMMMMM
+  JJAAMMMMMMMMMMMM
+}
+# tile 55 (beaked polearm / bec de corbin)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMPNMMMMMMMM
+  MMMMMPNPAMMMMMMM
+  MMMKPPPAAMMMMMMM
+  AOPPKPAAMMMMMMMM
+  MOPPPKAMMMMMMMMM
+  MPPPPAKAMMMMMMMM
+  MMPPPAMCAMMMMMMM
+  MMMAAMMMCAMMMMMM
+  MMMMMMMMMCAMMMMM
+  MMMMMMMMMMCAMMMM
+  MMMMMMMMMMMCAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 56 (mace)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMBABMMMM
+  MMMMMMMMBMOMPAMM
+  MMMMMMMMAOMBMAMM
+  MMMMMMMMBMBMPAMM
+  MMMMMMMMAPMPAAMM
+  MMMMMMMKJAAAAMMM
+  MMMMMMKJAMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMKJAMMMMMMMMM
+  MMMKJAMMMMMMMMMM
+  MMKJAMMMMMMMMMMM
+  MMMAMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 57 (morning star)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMBABMMM
+  MMMMMMMMMBMOMPAM
+  MMMMMMMMMAOMBMAM
+  MMMPPMMMMBMBMPAM
+  MMPAAPMMMAPMPAAM
+  MMPAAPMMPPAAAAMM
+  MMPAMAPPAAMMMMMM
+  MMPAMMAAMMMMMMMM
+  MMMKAMMMMMMMMMMM
+  MMMMKAMMMMMMMMMM
+  MMMMMKAMMMMMMMMM
+  MMMMMMKAMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 58 (war hammer)
+{
+  MMMMMMMMMMOMMMMM
+  MMMMMMMMMPPOAMMM
+  MMMMMMMMMAPPKKMM
+  MMMMMMMMMMAKKOOM
+  MMMMMMMMMMKJAPPO
+  MMMMMMMMMKJAAAPA
+  MMMMMMMMKJAMMAAM
+  MMMMMMMKJAMMMMMM
+  MMMMMMKJAMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMKJAMMMMMMMMM
+  MMMKJAMMMMMMMMMM
+  MMKJAMMMMMMMMMMM
+  MKJAMMMMMMMMMMMM
+  MJAMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 59 (club)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMKKMMMM
+  MMMMMMMMJCKKAMMM
+  MMMMMMMKKKKKAMMM
+  MMMMMMJKKKKJAMMM
+  MMMMMMKKKCKAAMMM
+  MMMMMJCKKKAAMMMM
+  MMMMJKKKJAAMMMMM
+  MMMJKKJAAMMMMMMM
+  MMMKJAAMMMMMMMMM
+  MMKJAMMMMMMMMMMM
+  MKJAMMMMMMMMMMMM
+  MJAMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 60 (rubber hose)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMFGFMMMMMM
+  MMMMMFGAAAGFMMMM
+  MMMMGAAMMMAAAMMM
+  MMMMGAMMMMMMMMMM
+  MMMMMGAMMMMMMMMM
+  MMMMMMFGAMMMMMMM
+  MMMMMMMMGAMMMMMM
+  MMMMMMMMFAMMMMMM
+  MMMMMMMGAMMMMMMM
+  MMMGGGFAMMMMMMMM
+  MMMMAAAMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 61 (staff / quarterstaff)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMJKM
+  MMMMMMMMMMMMJCJA
+  MMMMMMMMMMMJKJAM
+  MMMMMMMMMMJCJAAM
+  MMMMMMMMMJCJAAMM
+  MMMMMMMMJKJAAMMM
+  MMMMMMMJKJAAMMMM
+  MMMMMMMKJAAMMMMM
+  MMMMMMKJAAMMMMMM
+  MMMMMJJAAMMMMMMM
+  MMMMKJAAMMMMMMMM
+  MMMJJAAMMMMMMMMM
+  MMKJAAMMMMMMMMMM
+  MJJAAMMMMMMMMMMM
+  MMAMMMMMMMMMMMMM
+}
+# tile 62 (thonged club / aklys)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMKJJJMMMM
+  MMMMMMMMKJJAAMMM
+  MMMMMMMKJJAAMMMM
+  MMMMMMMKJAAMMMMM
+  MMMMMMKJAAMMMMMM
+  MMMMMKJAAMMMMMMM
+  MMMMMKAAMMMMMMMM
+  MMMMKAAMMMMMMMMM
+  MMMMMAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 63 (flail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMKJMM
+  MMMMMMMMMMMKJAMM
+  MMMMMMMMMMKJAMMM
+  MMMMMMMMMKJAMMMM
+  MMMMMMMMKJAMMMMM
+  MMMMMMMKJAMMMMMM
+  MMMMMMKJAMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMPAMMMMMMMMMM
+  MMMKJAMMMMMMMMMM
+  MMMKAMMMMMMMMMMM
+  MMKJAMMMMMMMMMMM
+  MJKAMMMMMMMMMMMM
+  MMJAMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 64 (bullwhip)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMKKKKKKMMM
+  MMMMMKKAAAAAAKAM
+  MMMMKAAMMMMMMKAM
+  MMMKAMMMMMMMKAMM
+  MMMKAMMMMMMMJAMM
+  MMMKAMMMMMMMMJAM
+  MMMMKKKKKKMMMMMM
+  MMMMMAAAAAKAMMMM
+  MPMMMMMMMMKAMMMM
+  MAPPMMMMMMKAMMMM
+  MMMAPKMMMKAMMMMM
+  MMMMMAKKKAMMMMMM
+  MMMMMMAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 65 (bow)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMKMMMMMMMMMM
+  MMMMMKPMMMMMMMMM
+  MMMMMPKMMMMMMMMM
+  MMMMMPKJMMMMMMMM
+  MMMMMPMKJMMMMMMM
+  MMMMMPMMKMMMMMMM
+  MMMMMOMMLMMMMMMM
+  MMMMMPMMOMMMMMMM
+  MMMMMPMMJMMAAMMM
+  MMMMMPMKJMMAMMMM
+  MMMMMPKJMMAAMMMM
+  MMMMMPKMMAAMMMMM
+  MMMMMKPAAAMMMMMM
+  MMMMMKAAMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 66 (runed bow / elven bow)
+{
+  MMMMMKMMMMMMMMMM
+  MMMMMKPMMMMMMMMM
+  MMMMMPKMMMMMMMMM
+  MMMMMPKJMMMMMMMM
+  MMMMMPMKJMMMMMMM
+  MMMMMPMMKMMMMMMM
+  MMMMMPMMKJMMMMMM
+  MMMMMPMMJLMMMMMM
+  MMMMMOMMJJMMMMMM
+  MMMMMPMMJLMMMMMM
+  MMMMMPMMJMMAAMMM
+  MMMMMPMKJMMAMMMM
+  MMMMMPKJMMAAMMMM
+  MMMMMPKMMAAMMMMM
+  MMMMMKPAAAMMMMMM
+  MMMMMKAAMMMMMMMM
+}
+# tile 67 (crude bow / orcish bow)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKKPMMMMMMMMM
+  MMMMMPKMMMMMMMMM
+  MMMMMPKJMMMMMMMM
+  MMMMMPMKJMMMMMMM
+  MMMMMPMMKMMMMMMM
+  MMMMMOMMLMMMMMMM
+  MMMMMPMMOMMMAMMM
+  MMMMMPMMJMMAAMMM
+  MMMMMPMKJMMAMMMM
+  MMMMMPKJMMAAMMMM
+  MMMMMPKMAAAMMMMM
+  MMMMKKPAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 68 (long bow / yumi)
+{
+  MMMMMLMMMMMMMMMM
+  MMMMMLPMMMMMMMMM
+  MMMMMPLMMMMMMMMM
+  MMMMMPLOMMMMMMMM
+  MMMMMPMLOMMMMMMM
+  MMMMMPMMLMMMMMMM
+  MMMMMPMMLOMMMMMM
+  MMMMMPMMOLMMMMMM
+  MMMMMPMMOOMMMMMM
+  MMMMMPMMOLMMMMMM
+  MMMMMPMMOMMAAMMM
+  MMMMMPMLOMMAMMMM
+  MMMMMPLOMMAAMMMM
+  MMMMMPLMMAAMMMMM
+  MMMMMLPAAAMMMMMM
+  MMMMMLAAMMMMMMMM
+}
+# tile 69 (sling)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMJJJJMMMMMM
+  MMMMMJAAAAJKMMMM
+  MMMMJAMMMMMKKMMM
+  MMMMMMMMMMJAKAMM
+  MMMMMMJJKKAKKAMM
+  MMMMJJAAAKKJJAMM
+  MMMJAAMMMAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 70 (crossbow)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMCJJMMMMMM
+  MMMMMMMDJJMMMMMM
+  MMMMMDKJJJKMMMMM
+  MMMDKJJJJJJJKMMM
+  MMDJMMMDJJMMJKMM
+  MMMMPMMCJJMPMMMM
+  MMMMMPMCJJPMMMMM
+  MMMMMMPCJPAAAAMM
+  MMMMMMMPPAMAAAAM
+  MMMMMMMCJJAAMMAM
+  MMMMMMMOAOAMMMMM
+  MMMMMMMMOAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 71 (leather hat / elven leather helm)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMJKKJMMMMMMM
+  MMMMJCKKKJMMMMMM
+  MMMJCKKJJJAMMMMM
+  MMMJKKJJJJAMMMMM
+  MMMJAJJAAJAMMMMM
+  MMMJAJJAMJAMMMMM
+  MMMJAMAMJAMMMMMM
+  MMMMJAMJAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 72 (iron skull cap / orcish helm)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPBBPMMMMMMM
+  MMMMPNBBBPAMMMMM
+  MMMPNBBPPPAMMMMM
+  MMMPBBPPPPAMMMMM
+  MMMJAPPAAJAMMMMM
+  MMMJAPPAMJAMMMMM
+  MMMJAMAMJAMMMMMM
+  MMMMJAMJAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 73 (hard hat / dwarvish iron helm)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPPPMMMMMMMM
+  MMMMPBBPPAMMMMMM
+  MMMPBNPPPPAMMMMM
+  MMMPNPPPPPAMMMMM
+  MMMPPPPPPPAMMMMM
+  MMMPAPPAAPAMMMMM
+  MMMJAPPAMJAMMMMM
+  MMMJAMAMJAMMMMMM
+  MMMMJAMJAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 74 (fedora)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMAAAAAAMMMMM
+  MMMAAMAAAAAMMMMM
+  MMMAAAMAAAMAMMMM
+  MMMMAAAMMMAAAMMM
+  MMMMKMAAAAAAMMMM
+  MMMKAMMMKAMMMMMM
+  MMMMKAMMKAMMMMMM
+  MMMMMMMKAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 75 (conical hat / cornuthaum)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMEMMMMMMMM
+  MMMMMMMEMMMMMMMM
+  MMMMMMMBMMMMMMMM
+  MMMMMMEBEMMMMMMM
+  MMMMMMEBEMMMMAMM
+  MMMMMMPBEMMMMAMM
+  MMMMMEBBEEMMAAMM
+  MMMMMEBBPEMAAAMM
+  MMMMMPNBPEAAAMMM
+  MMMMEBNBBEEAAMMM
+  MMMMENNBBPEAAMMM
+  MMMEBBBBPEAEAMMM
+  MMMEEMMAMAEEMMMM
+  MMMMEEEEEEEMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 76 (conical hat / dunce cap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMEMMMMMMMM
+  MMMMMMMEMMMMMMMM
+  MMMMMMMBMMMMMMMM
+  MMMMMMEBEMMMMMMM
+  MMMMMMEBEMMMMAMM
+  MMMMMMPBEMMMMAMM
+  MMMMMEBBEEMMAAMM
+  MMMMMEBBPEMAAAMM
+  MMMMMPNBPEAAAMMM
+  MMMMEBNBBEEAAMMM
+  MMMMENNBBPEAAMMM
+  MMMEBBBBPEAEAMMM
+  MMMEEMMAMAEEMMMM
+  MMMMEEEEEEEMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 77 (dented pot)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMJJMM
+  MMMMMMMMMMMJJMMM
+  MMMMMMMMMMJJMMMM
+  MMMMMMMMMJJMMMAA
+  MMMMMBPPPMJMMAAM
+  MMMMBAAAMMPMAAMM
+  MMMMBPAMMPMAAMMM
+  MMMMBBPPPMMAAMMM
+  MMMMBPPPMMMAAMMM
+  MMMMMBBPPPAAAMMM
+  MMMMMMAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 78 (plumed helmet / helmet)
+{
+  MMMMMMMDIDMMMMMM
+  MMMMMMDIBIMMMMMM
+  MMMMMMIBIBMMMMMM
+  MMMMMMDIBMMMMMMM
+  MMMMMMMIMMMMMMMM
+  MMMMMMPIPMMMMMMM
+  MMMMMPNIPPAMMMMM
+  MMMMPNBPPPPAMMMM
+  MMMMPBPPPPPAMMMM
+  MMMMPPPPPPPAMMMM
+  MMMMPAPPAAPAMMMM
+  MMMMJAPPAMJAMMMM
+  MMMMMMMAAMMAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 79 (etched helmet / helm of brilliance)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMPPPMMMMMMM
+  MMMMMPNBPPAMMMMM
+  MMMMMNBPPPMAMMMM
+  MMMMPMPMPMPAMMMM
+  MMMMPPPPPPPAMMMM
+  MMMMPAPPAAPAMMMM
+  MMMMJAPPAMJAMMMM
+  MMMMMMMAAMMAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 80 (crested helmet / helm of opposite alignment)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMHHHMMMMMMM
+  MMMMMHHHMMMMMMMM
+  MMMMMHHMMPAMMMMM
+  MMMMPPHMMPPAMMMM
+  MMMMPPPMPPPAMMMM
+  MMMMPPPPPPPAMMMM
+  MMMMPAPPAAPAMMMM
+  MMMMJAPPAMJAMMMM
+  MMMMMMMAAMMAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 81 (visored helmet / helm of telepathy)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMPPPMMMMMMM
+  MMMMMPNNPPAMMMMM
+  MMMMPNNPPPPAMMMM
+  MMMMPBBBBBPAMMMM
+  MMMMPPPPPPPAMMMM
+  MMMMPAAAAAPAMMMM
+  MMMMJBPPPPJAMMMM
+  MMMMMMPPAAAAMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 82 (gray dragon scale mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MNMNMMPMMMPMOAOA
+  MNMNMPMMMPMMOAOA
+  MMANPMMMPMMMOAMA
+  MMMNMMMPMMMPOAMM
+  MMMNMMPMMMPMOAMM
+  MMMMNPMMMPMOAAMM
+  MMMNMNMMPMOAOAMM
+  MMNNNANPMOAOOOAM
+  MNNNOAMNOAAOOOOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 83 (silver dragon scale mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOBOOMOM
+  MNMNOBNOOBNOBAOA
+  MNMNBNOOBNOBBAOA
+  MMANNOOBNOBBBAMA
+  MMMNOOBNOBBNBAMM
+  MMMNOBNOBBNBBAMM
+  MMMMNNOBBNBBAAMM
+  MMMNMNBBNBBAOAMM
+  MMNNNANNBBAOOOAM
+  MNNNBAMNBAAOOOOA
+  MMNBAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 84 (shimmering dragon scale mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMBMBBBOOOMOMMM
+  MBMBBBBBOOOOOMOM
+  MBMBEEFFGGHHOAOA
+  MBMBEFFGGHHCOACA
+  MMABFFGGHHCDOAMA
+  MMMBFGGHHCDDOAMM
+  MMMBGGHHCDDKOAMM
+  MMMMBHHCDDKOAAMM
+  MMMBMBCDDKOAOAMM
+  MMBBBABDKOAOOCAM
+  MBBBOAMBBAAOOOCA
+  MMBOAAMMMMMMKCAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 85 (red dragon scale mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MNMNDDIDDDIDOAOA
+  MNMNDIDDDIDDOAOA
+  MMANIDDDIDDDOAMA
+  MMMNDDDIDDDIOAMM
+  MMMNDDIDDDIDOAMM
+  MMMMNIDDDIDOAAMM
+  MMMNMNDDIDOAOAMM
+  MMNNNANIDOAOOOAM
+  MNNNOAMNOAAOOOOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 86 (white dragon scale mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MNMNOONOOONOOAOA
+  MNMNONOOONOOOAOA
+  MMANNOOONOOOOAMA
+  MMMNOOONOOONOAMM
+  MMMNOONOOONOOAMM
+  MMMMNNOOONOOAAMM
+  MMMNMNOONOOAOAMM
+  MMNNNANNOOAOOOAM
+  MNNNOAMNOAAOOOOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 87 (orange dragon scale mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MNMNCCLCCCLCOAOA
+  MNMNCLCCCLCCOAOA
+  MMANLCCCLCCCOAMA
+  MMMNCCCLCCCLOAMM
+  MMMNCCLCCCLCOAMM
+  MMMMNLCCCLCOAAMM
+  MMMNMNCCLCOAOAMM
+  MMNNNANLCOAOOOAM
+  MNNNOAMNOAAOOOOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 88 (black dragon scale mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MNMNAAMAAAMAOAOA
+  MNMNAMAAAMAAOAOA
+  MMANMAAAMAAAOAMA
+  MMMNAAAMAAAMOAMM
+  MMMNAAMAAAMAOAMM
+  MMMMNMAAAMAOAAMM
+  MMMNMNAAMAOAOAMM
+  MMNNNANMAOAOOOAM
+  MNNNOAMNOAAOOOOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 89 (blue dragon scale mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MNMNEEBEEEBEOAOA
+  MNMNEBEEEBEEOAOA
+  MMANBEEEBEEEOAMA
+  MMMNEEEBEEEBOAMM
+  MMMNEEBEEEBEOAMM
+  MMMMNBEEEBEOAAMM
+  MMMNMNEEBEOAOAMM
+  MMNNNANBEOAOOOAM
+  MNNNOAMNOAAOOOOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 90 (green dragon scale mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MNMNFFGFFFGFOAOA
+  MNMNFGFFFGFFOAOA
+  MMANGFFFGFFFOAMA
+  MMMNFFFGFFFGOAMM
+  MMMNFFGFFFGFOAMM
+  MMMMNGFFFGFOAAMM
+  MMMNMNFFGFOAOAMM
+  MMNNNANGFOAOOOAM
+  MNNNOAMNOAAOOOOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 91 (yellow dragon scale mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MNMNHHNHHHNHOAOA
+  MNMNHNHHHNHHOAOA
+  MMANNHHHNHHHOAMA
+  MMMNHHHNHHHNOAMM
+  MMMNHHNHHHNHOAMM
+  MMMMNNHHHNHOAAMM
+  MMMNMNHHNHOAOAMM
+  MMNNNANNHOAOOOAM
+  MNNNOAMNOAAOOOOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 92 (gray dragon scales)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMPMMMMMMM
+  MMMMMMMPPPMMMMMM
+  MMMMPMPPPPAMMMMM
+  MMMPPPMPPAAPMMMM
+  MMPPPPAPAAPPAMMM
+  MMMPPAAPPAPAAMMM
+  MMMMAAPPAAAAMMMM
+  MMMMMMMAAPAMMMMM
+  MMMMMMMPPAAMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 93 (silver dragon scales)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMNMMMMMMM
+  MMMMMMMNNNMMMMMM
+  MMMMNMNNNNAMMMMM
+  MMMNNNMNNAANMMMM
+  MMNNNNANAANNAMMM
+  MMMNNAANNANAAMMM
+  MMMMAANNAAAAMMMM
+  MMMMMMMAANAMMMMM
+  MMMMMMMNNAAMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 94 (shimmering dragon scales)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMPMMMMMMM
+  MMMMMMMPPPMMMMMM
+  MMMMEMPPFPAMMMMM
+  MMMEBBMFFAAHMMMM
+  MMEBBPAFAAHDAMMM
+  MMMEBAAGGADAAMMM
+  MMMMAAGGAAAAMMMM
+  MMMMMMMAADAMMMMM
+  MMMMMMMGHAAMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 95 (red dragon scales)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMDMMMMMMM
+  MMMMMMMDDDMMMMMM
+  MMMMDMDDDDAMMMMM
+  MMMDDDMDDAADMMMM
+  MMDDDDADAADDAMMM
+  MMMDDAADDADAAMMM
+  MMMMAADDAAAAMMMM
+  MMMMMMMAADAMMMMM
+  MMMMMMMDDAAMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 96 (white dragon scales)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMOMMMMMMM
+  MMMMMMMOOOMMMMMM
+  MMMMOMOOOOAMMMMM
+  MMMOOOMOOAAOMMMM
+  MMOOOOAOAAOOAMMM
+  MMMOOAAOOAOAAMMM
+  MMMMAAOOAAAAMMMM
+  MMMMMMMAAOAMMMMM
+  MMMMMMMOOAAMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 97 (orange dragon scales)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMCMMMMMMM
+  MMMMMMMCCCMMMMMM
+  MMMMCMCCCCAMMMMM
+  MMMCCCMCCAACMMMM
+  MMCCCCACAACCAMMM
+  MMMCCAACCACAAMMM
+  MMMMAACCAAAAMMMM
+  MMMMMMMAACAMMMMM
+  MMMMMMMCCAAMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 98 (black dragon scales)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMAMMMMMMM
+  MMMMMMMAAAMMMMMM
+  MMMMAMAAAAPMMMMM
+  MMMAAAMAAPAAMMMM
+  MMAAAAPAPAAAPMMM
+  MMMAAPAAAPAPPMMM
+  MMMMPAAAPAPPMMMM
+  MMMMMMMPAAPMMMMM
+  MMMMMMMAAPPMMMMM
+  MMMMMMMMPPMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 99 (blue dragon scales)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMEMMMMMMM
+  MMMMMMMEEEMMMMMM
+  MMMMEMEEEEAMMMMM
+  MMMEEEMEEAAEMMMM
+  MMEEEEAEAAEEAMMM
+  MMMEEAAEEAEAAMMM
+  MMMMAAEEAAAAMMMM
+  MMMMMMMAAEAMMMMM
+  MMMMMMMEEAAMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 100 (green dragon scales)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMFMMMMMMM
+  MMMMMMMFFFMMMMMM
+  MMMMFMFFFFAMMMMM
+  MMMFFFMFFAAFMMMM
+  MMFFFFAFAAFFAMMM
+  MMMFFAAFFAFAAMMM
+  MMMMAAFFAAAAMMMM
+  MMMMMMMAAFAMMMMM
+  MMMMMMMFFAAMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 101 (yellow dragon scales)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMHMMMMMMM
+  MMMMMMMHHHMMMMMM
+  MMMMHMHHHHAMMMMM
+  MMMHHHMHHAAHMMMM
+  MMHHHHAHAAHHAMMM
+  MMMHHAAHHAHAAMMM
+  MMMMAAHHAAAAMMMM
+  MMMMMMMAAHAMMMMM
+  MMMMMMMHHAAMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 102 (plate mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MNMNNNNNOOOOOAOA
+  MNMNNNNONOOOOAOA
+  MMANNNOONNOOOAMA
+  MMMNNNOONNOOOAMM
+  MMMNNNNONOOOOAMM
+  MMMMNNNNOOOOAAMM
+  MMMNMNNNOOOAOAMM
+  MMNNNANNOOAOOOAM
+  MNNNOAMNOAAOOOOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 103 (crystal plate mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNBBBMBMMM
+  MNMNNNNNBBBBBMBM
+  MNMNNNNNBBBBBABA
+  MNMNNNNBNBBBBABA
+  MMANNNBBNNBBBAMA
+  MMMNNNBBNNBBBAMM
+  MMMNNNNBNBBBBAMM
+  MMMMNNNNBBBBAAMM
+  MMMNMNNNBBBABAMM
+  MMNNNANNBBABBBAM
+  MNNNBAMNBAABBBBA
+  MMNBAAMMMMMMBBAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 104 (bronze plate mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMLMLLLCCCMCMMM
+  MLMLLLLLCCCCCMCM
+  MLMLLLLLCCCCCACA
+  MLMLLLLCLCCCCACA
+  MMALLLCCLLCCCAMA
+  MMMLLLCCLLCCCAMM
+  MMMLLLLCLCCCCAMM
+  MMMMLLLLCCCCAAMM
+  MMMLMLLLCCCACAMM
+  MMLLLALLCCACCCAM
+  MLLLCAMLCAACCCCA
+  MMLCAAMMMMMMCCAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 105 (splint mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MJMNPPPPMMMMOAJA
+  MNMNKKKKJJJJOAOA
+  MMANPPPPMMMMOAMA
+  MMMNKKKKJJJJOAMM
+  MMMNPPPPMMMMOAMM
+  MMMMNKKKJJJOAAMM
+  MMMNMNPPMMOAOAMM
+  MMNPNANKJOAOPOAM
+  MNPJOAMNOAAOJPOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 106 (banded mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MPMNPNPPPPOPOAPA
+  MNMNMMMMMMMMOAOA
+  MMANPNPPPPOPOAMA
+  MMMNMMMMMMMMOAMM
+  MMMNPNPPPPOPOAMM
+  MMMMNMMMMMMOAAMM
+  MMMNMNPNOPOAOAMM
+  MMNPNANMMOAOPOAM
+  MNPMOAMNOAAOMPOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 107 (dwarvish mithril-coat)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNNNNNOOOOOMMM
+  MNMNANANAPAPOMOM
+  MNMNNANAPAPAOAOA
+  MNMNANANAPAPOAOA
+  MMANNANAPAPAOAMA
+  MMMNANANAPAPOAMM
+  MMMNNANAPAPAOAMM
+  MMMMNNANAPAOAAMM
+  MMMNMNNAPAOAOAMM
+  MMNPNANNAOAOMOAM
+  MNPNOAMNOAAOOMOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 108 (elven mithril-coat)
+{
+  MMMMMMMMMMMMMMMM
+  MMMNMNMNOMOMOMMM
+  MMMNNNNNOOOOOMMM
+  MNMNANANAOAOOMOM
+  MNMONANAPAPAOAOA
+  MNMNANANAPAPOAOA
+  MMAONANAPAPAOAMA
+  MMMNANANAPAPOAMM
+  MMMONANAPAPAOAMM
+  MMMMONANAPAOAAMM
+  MMMNMONAPAOAOAMM
+  MMNPNAONAOAOMOAM
+  MNPNOAMOOAAOOMOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 109 (chain mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MNMNPAPAMAMAOAOA
+  MNMNAPAPAMAMOAOA
+  MMANPAPAMAMAOAMA
+  MMMNAPAPAMAMOAMM
+  MMMNPAPAMAMAOAMM
+  MMMMNPAPAMAOAAMM
+  MMMNMNPAMAOAOAMM
+  MMNPNANPAOAOMOAM
+  MNPNOAMNOAAOOMOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 110 (crude chain mail / orcish chain mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMKMKKKJJJMJMMM
+  MKMKKKKKJJJJJMJM
+  MKMKPAPAMAMAJAJA
+  MKMKAPAPAMAMJAJA
+  MMAKPAPAMAMAJAMA
+  MMMKAPAPAMAMJAMM
+  MMMKPAPAMAMAJAMM
+  MMMMKPAPAMAJAAMM
+  MMMKMKPAMAJAJAMM
+  MMKKKAKPAJAJJJAM
+  MKKKJAMKJAAJJJJA
+  MMKJAAMMMMMMJJAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 111 (scale mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MPMNPAPAAMAMOAMA
+  MNMNAPPPMMMAOAOA
+  MMANPAPAAMAMOAMA
+  MMMNPPAPMAMMOAMM
+  MMMNPAPAAMAMOAMM
+  MMMMNPPPMMMOAAMM
+  MMMNMNPAAMOAOAMM
+  MMNPNANPMOAOMOAM
+  MNPPOAMNOAAOMMOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 112 (studded leather armor)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MKMNKKKKJJJJOAKA
+  MKMNKNKNOJOJOAKA
+  MMANKKKKJJJJOAMA
+  MMMNKNKNOJOJOAMM
+  MMMNKKKKJJJJOAMM
+  MMMMNKNKJOJOAAMM
+  MMMNMNKKJJOAOAMM
+  MMNKKANKJOAOKKAM
+  MNKKJAMNOAAOKKKA
+  MMKJAAMMMMMMKKAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 113 (ring mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MNMNNNNNOOOOOMOM
+  MPMNPAAPMAAMOAMA
+  MNMNABPAAMPAOAOA
+  MMANAPBAAPMAOAMA
+  MMMNPAAPMAAMOAMM
+  MMMNAPBAAPMAOAMM
+  MMMMNBPAAMPOAAMM
+  MMMNMNAPMAOAOAMM
+  MMNPNANAAOAOMOAM
+  MNPBOAMNOAAOPMOA
+  MMNOAAMMMMMMOOAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 114 (crude ring mail / orcish ring mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMKMKKKJJJMJMMM
+  MKMKKKKKJJJJJMJM
+  MBMKPAAPMAAMJAPA
+  MKMKABPAAMPAJAJA
+  MMAKAPBAAPMAJAMA
+  MMMKPAAPMAAMJAMM
+  MMMKAPBAAPMAJAMM
+  MMMMKBPAAMPJAAMM
+  MMMKMKAPMAJAJAMM
+  MMKPKAKAAJAJMJAM
+  MKPBJAMKJAAJPMJA
+  MMKJAAMMMMMMJJAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 115 (leather armor)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MKMNNNNNOOOOOMJM
+  MKMNKKKKJJJJOAJA
+  MKMNKKKJKJJJOAJA
+  MMANKKJJKKJJOAMA
+  MMMNKKJJKKJJOAMM
+  MMMNKKKJKJJJOAMM
+  MMMMNKKKJJJOAAMM
+  MMMKMNKKJJOAJAMM
+  MMKKKANKJOAJJJAM
+  MKKKJAMNOAAJJJJA
+  MMKJAAMMMMMMJJAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 116 (leather jacket)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMKAMJAMMMMM
+  MMMMKKKKJJJJAMMM
+  MMMKKKKKJLJJJAMM
+  MMKKKKKKJJJJJJAM
+  MMMKAKKKJLJAJAAM
+  MMMMMKKKJJJAMAMM
+  MMMMMKKKJLJAMMMM
+  MMMMMKKKJJJAMMMM
+  MMMMMMAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 117 (Hawaiian shirt)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMCMMMMMCMMMMM
+  MMMGCGGGGGCHMMMM
+  MMGGHCGGGCHHHMMM
+  MHHHJHCCCHJHHHMM
+  MMHHJHHCHHJHHAAM
+  MMMMGHHCGGHAAAMM
+  MMMMHHHCGGHAMMMM
+  MMMMGGHCHHHAMMMM
+  MMMMGGHCHGGAMMMM
+  MMMMHHHCHHHAMMMM
+  MMMMMAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 118 (T-shirt)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPMMMMMPMMMMM
+  MMMNPOOOOOPNMMMM
+  MMNNNPOOOPNNNMMM
+  MNNNONPPPNONNNMM
+  MMNNONNNNNONNAAM
+  MMMMNDODODNAAAMM
+  MMMMNNNNNNNAMMMM
+  MMMMNDODODNAMMMM
+  MMMMNNNNNNNAMMMM
+  MMMMNNNNNNNAMMMM
+  MMMMMAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 119 (mummy wrapping)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMOMM
+  MMMMMMMNMMNMMOMM
+  MMMMOMONOMNNANMM
+  MMMMMNONOMANNOMM
+  OMMMONOOODNNOAAM
+  MOOODNNONNNAOOAM
+  MMAMNNOOAOAAOAAM
+  MMMOODOOAAOOOAMM
+  MMNMAANMNAMOOMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 120 (faded pall / elven cloak)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMOFFMMFOMMMMM
+  MMMMMOFFFOAAMMMM
+  MMMMMMOFOAAMMMMM
+  MMMMMOGAGFAMMMMM
+  MMMMOGOAOFFAMMMM
+  MMMOGOAAGFFFAMMM
+  MMOGOGAAOFFFFAMM
+  MMOOGAAFFOFFFAMM
+  MMOGOAAFFGFFFAMM
+  MMMOGAFFFFGFAMMM
+  MMMMAAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 121 (coarse mantelet / orcish cloak)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMCJKMKKCMMMMM
+  MMMMMCJKKCAAMMMM
+  MMMMMMCKCAAMMMMM
+  MMMMMCCACKAMMMMM
+  MMMMCCCACKKAMMMM
+  MMMCCCAACKKKAMMM
+  MMCCCCAACKKKKAMM
+  MMCCCAAJJCKKKAMM
+  MMCCCAAJJCKKKAMM
+  MMMCCAJJJJCKAMMM
+  MMMMAAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 122 (hooded cloak / dwarvish cloak)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMBBPMMMMMMM
+  MMMMMBBBBPMMMMMM
+  MMMMBPAAAPPMMMMM
+  MMMMMBPAPPAAMMMM
+  MMMMMMBPPAAMMMMM
+  MMMMMBBABPAMMMMM
+  MMMMBBBABPPAMMMM
+  MMMBBBAABPPPAMMM
+  MMBBBBAMMBPPPAMM
+  MMMBBAMMMMBPAMMM
+  MMMMAAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 123 (slippery cloak / oilskin cloak)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJAAMAAJMMMMM
+  MMMMMJAAAJAAMMMM
+  MMMMMMJAJAAMMMMM
+  MMMMMJJAJAAMMMMM
+  MMMMJJJAJAAAMMMM
+  MMMJJJAAJAAAAMMM
+  MMJJJJAAJAAAAAMM
+  MMJJJAAAAJAAAAMM
+  MMJJJAAAAJAAAAMM
+  MMMJJAAAAAJAAMMM
+  MMMMAAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 124 (robe)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMCCCMMMMMMM
+  MMMMMCAAAKAMMMMM
+  MMMMCCAJJKKAMMMM
+  MMMMMCAJJKAAMMMM
+  MMMMMCCJKKAAMMMM
+  MMMMCCCAKKKAMMMM
+  MMMMCCCCAKKAAMMM
+  MMMCCCCCCAKKAMMM
+  MMMCCCCCCAKKAMMM
+  MMMCCCCCCCAKAMMM
+  MMMCCCCCCCAKAMMM
+  MMMCCCCCCCAKAMMM
+  MMMCCCCCCCAKAMMM
+  MMMACCCCCCAAAMMM
+  MMMMAAAAAAAAMMMM
+}
+# tile 125 (apron / alchemy smock)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMNOMMNOMMMMM
+  MMMMMNAOMNAOMMMM
+  MMMMMNAOMNAOAMMM
+  MMMMMNNNNNAOAMMM
+  MMMMMNNNNNOOAMMM
+  MMMMMNNNNNOOAMMM
+  MMMMONNNNNOAAMMM
+  MMMMONNNNNNAAMMM
+  MMMMNNNNNNNAAMMM
+  MMMMNNNNNNNAAMMM
+  MMMMNNNNNNNAAMMM
+  MMMMNNNNNNNAAMMM
+  MMMMMNNNNNAAMMMM
+  MMMMMMAAAAAMMMMM
+}
+# tile 126 (leather cloak)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKJJMJJKMMMMM
+  MMMMMKJJJKAAMMMM
+  MMMMMMKJKAAMMMMM
+  MMMMMKKAKJAMMMMM
+  MMMMKKKAKJJAMMMM
+  MMMKKKAAKJJJAMMM
+  MMKKKKAAKJJJJAMM
+  MMKKKAAJJKJJJAMM
+  MMKKKAAJJKJJJAMM
+  MMMKKAJJJJKJAMMM
+  MMMMAAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 127 (tattered cape / cloak of protection)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMPOMMMMM
+  MMMOOOPPPOAAMMMM
+  MMMMMMOPOAAMMMMM
+  MMMMMOOAOPAMMMMM
+  MMMMOOOAOPPAMMMM
+  MMMOOOAAOPPPAMMM
+  MMOOOOAAOPPPPAMM
+  MMOOOAAPPOPPAMMM
+  MMMOOAAPPOPAMMMM
+  MMOOOAMMAPOPAMMM
+  MMMAAMMMMAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 128 (opera cloak / cloak of invisibility)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMNNNMMMMMMM
+  MMMMMNAAAOMMMMMM
+  MMMMNNAAAOOAMMMM
+  MMMMMNAAAOAMMMMM
+  MMMMMNNAOOAAMMMM
+  MMMMNNNAOOOAAMMM
+  MMMNNNNNAOOOAAMM
+  MMNNNNNNNAOOOAAM
+  MMNNNNNNNAOOOOAM
+  MNNNNNNNNNAOOOAM
+  MNNNNNNNNNAOOOAM
+  MNNNNNNNNNNAOOAM
+  MNNNNNNNNNNAOOAM
+  MMAANNNNNNAOOAAM
+  MMMMAAAAAAAAAAMM
+}
+# tile 129 (ornamental cope / cloak of magic resistance)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMAAAMMAAMMMMM
+  MMMMMAAAAAPPMMMM
+  MMMMMMAAAPPMMMMM
+  MMMMMAAAAAPMMMMM
+  MMMMAAAAAAAPMMMM
+  MMMAAAAAAAAAPMMM
+  MMMAAAAAAAAAPPMM
+  MMAAAAAAAAAAAPMM
+  MMAAAAAAAAAAAPMM
+  MMAAAAAAAAAAAPMM
+  MMAAAAAAAAAAAPMM
+  MMAAAAAAAAAAAPMM
+  MMMPPPPPPPPPPPMM
+}
+# tile 130 (piece of cloth / cloak of displacement)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMPMMMMMMM
+  MMMMMMMPPPAMMMMM
+  MMMMMMPPPBPAAMMM
+  MMMMMPBPBPPPAAMM
+  MMMMPPPBPPPPBAAM
+  MMMPPPBPPBPBPPAA
+  MMPBPBPPPPBPPPPA
+  MPPPBPPPPBPBPPPA
+  MPPBPBPPBPPPBPAA
+  MMBPPPPBPPPPPAAM
+  MMMPPPBPBPPPAAMM
+  MMMMPBPPPBPAAMMM
+  MMMMMPPPPPAAMMMM
+  MMMMMMMPPAAMMMMM
+}
+# tile 131 (small shield)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMCMCJJMJMMMMMM
+  MMMCCKKJJJAMMMMM
+  MMMCKKKJJJAMMMMM
+  MMMCKKJJJJAMMMMM
+  MMMCKKJJJJAMMMMM
+  MMMMCKKJJAAMMMMM
+  MMMMMCKJAAMMMMMM
+  MMMMMMCAAMMMMMMM
+  MMMMMMMAMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 132 (blue and green shield / elven shield)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNNMNMMMMM
+  MMMNNNGFNNNAMMMM
+  MMMNGGGFFFNAMMMM
+  MMMNGGFFFFNAMMMM
+  MMMNGGFFFFNAMMMM
+  MMMNGGFFFFNAMMMM
+  MMMMNGGFFNAAMMMM
+  MMMMMNGFNAAMMMMM
+  MMMMMMNNAAMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 133 (white-handed shield / Uruk-hai shield)
+{
+  MMMMMMMMMMMMMMMM
+  MMMKMKKKJJJMJMMM
+  MMMKKKKKJJJJJMMM
+  MMMKPPPPMMMMJAMM
+  MMMKPPPNOOMMJAMM
+  MMMKPPPNOOOMJAMM
+  MMMKPNPNOOOMJAMM
+  MMMKPNNNOOOMJAMM
+  MMMKPPNNOOMMJAMM
+  MMMKPPPNOMMMJAMM
+  MMMMKPPNOMMJAAMM
+  MMMMMKPPMMJAAMMM
+  MMMMMMKPMJAAMMMM
+  MMMMMMMKJAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 134 (red-eyed shield / orcish shield)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMKMKKKJJJMJMMM
+  MMMKKKKKJJJJJMMM
+  MMMKPPPPMMMMJAMM
+  MMMKPPDDDDMMJAMM
+  MMMKPDDAADDMJAMM
+  MMMKPDDAADDMJAMM
+  MMMKPPDDDDMMJAMM
+  MMMMKPPPMMMJAAMM
+  MMMMMKPPMMJAAMMM
+  MMMMMMKPMJAAMMMM
+  MMMMMMMKJAAMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 135 (large shield)
+{
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MMMNNNNNOOOOOMMM
+  MMMNPPPPPMMMOAMM
+  MMMNPPPMMMMMOAMM
+  MMMNPPPMMMMMOAMM
+  MMMNPPPPPMMMOAMM
+  MMMNPPPMMMMMOAMM
+  MMMNPPPMMMMMOAMM
+  MMMNPPPPPMMMOAMM
+  MMMMNPPMMMMOAAMM
+  MMMMMNPMMMOAAMMM
+  MMMMMMNPPOAAMMMM
+  MMMMMMMNOAAMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 136 (large round shield / dwarvish roundshield)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMBBBPMMMMMMM
+  MMMMBKKKKPMMMMMM
+  MMMBKKKKKJPMMMMM
+  MMMBKKKJJJPAMMMM
+  MMMBKKJJJJPAMMMM
+  MMMBKKJJJJPAMMMM
+  MMMMPJJJJPAAMMMM
+  MMMMMPPPPAAMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 137 (polished silver shield / shield of reflection)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNMNNNOOOMOMMM
+  MMMNNNNNOOOOOMMM
+  MMMNPPPPPPPPOAMM
+  MMMNPNNPPPPPOAMM
+  MMMNPNNPPPPPOAMM
+  MMMNPPPPPPPPOAMM
+  MMMNPPPPPPPPOAMM
+  MMMMNPPPPPPOAAMM
+  MMMMMNPPPPOAAMMM
+  MMMMMMNPPOAAMMMM
+  MMMMMMMNOAAMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 138 (old gloves / leather gloves)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMKJMMMMMMM
+  MMMMKJMKJMKJMMMM
+  MMMMKJAJJAKJMMMM
+  MMKJMJJAJJAJJMMM
+  MMKJAJJAJJAJJAMM
+  MMMJJAJKJJKJJAMM
+  MMMMJKJJJJJJJAMM
+  MMMKAJJJJJJJJAMM
+  MMMKJJJJJJJJJJAM
+  MMMMJJJJJJJJJJAM
+  MMMMMAAAJJJJJAAM
+  MMMMMMMMAJJJAAMM
+  MMMMMMMMMAAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 139 (padded gloves / gauntlets of fumbling)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMKJMMMMMMM
+  MMMMKJMKJMKJMMMM
+  MMMMKJAJJAKJMMMM
+  MMKJMKJAKJAKJMMM
+  MMKJAJKAKJAKJAMM
+  MMMKJAJKKJKKJAMM
+  MMMMKKJJKJJKJAMM
+  MMMKAJKKKKKKJAMM
+  MMMKKKKKKKKKJJAM
+  MMMMJJJJJKKKKJAM
+  MMMMMAAAJJKKKAAM
+  MMMMMMMMAJJKAAMM
+  MMMMMMMMMAAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 140 (riding gloves / gauntlets of power)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKKJJAMMMMMMM
+  MMMKJJJJJAMMMMMM
+  MMKJJJJJJJAMMMMM
+  MMKJJJJJJJAMMMMM
+  MMMJJJJJJJJAMMMM
+  MMMMJKJJJJJJAMMM
+  MMMKAJJJJJJJAMMM
+  MMMKJJJJJJJJJAMM
+  MMMMJJJJJJJJJJAM
+  MMMMMAAAJJJJJAAM
+  MMMMMMMMAJJJAAMM
+  MMMMMMMMMAAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 141 (fencing gloves / gauntlets of dexterity)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMNOMMMMMMM
+  MMMMNOMNOMNOMMMM
+  MMMMNOAOOANOMMMM
+  MMNOMOOAOOAOOMMM
+  MMNOAOOAOOAOOAMM
+  MMMOOAONOONOOAMM
+  MMMMONOOOOOOOAMM
+  MMMNAOOOOOOOOAMM
+  MMMNOOOOOOOOOOAM
+  MMMMOOOOOOOOOOAM
+  MMMMMAAAOOOOOAAM
+  MMMMMMMMAOOOAAMM
+  MMMMMMMMMAAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 142 (walking shoes / low boots)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMKJKKJMMM
+  MMMCKLKLKJJKJAMM
+  MMCKKLKLKJKKJAMM
+  MMKKKKKKKKKKJAMM
+  MMJJJJJJJJJJJAMM
+  MMMAAAAAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 143 (hard shoes / iron shoes)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMPPBBPMMM
+  MMMMMMMMPNPPPAMM
+  MMMMMMMMPPPPMAMM
+  MMMOPNPNMPPPMAMM
+  MMOPPPPNPMMMMAMM
+  MMPPPPPPPPPPMAMM
+  MMMPMMMMMMMMMAMM
+  MMMAAAAAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 144 (jackboots / high boots)
+{
+  MMMMMMMCCKKKKMMM
+  MMMMMMCKAAAAJJMM
+  MMMMMMKKKKKKKJAM
+  MMMMMMMJKKKKKJAM
+  MMMMMMMKJKKKKJAM
+  MMMMMMMMJKKKKAMM
+  MMMMMMMMJKKKKAMM
+  MMMMMMMMJKKKKAMM
+  MMMMMMMMKJKKJAMM
+  MMMCKLKLKJJKJAMM
+  MMCKKLKLKJKKJAMM
+  MMKKKKKKKKKKJAMM
+  MMJJJJJJJJJJJAMM
+  MMMAAAAAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 145 (combat boots / speed boots)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMGGFFFFMMM
+  MMMMMMGFAAAAMMMM
+  MMMMMMFFFFFFFMAM
+  MMMMMMMMFFFFFMAM
+  MMMMMMMKMFFFFMAM
+  MMMMMMMMMFFFFAMM
+  MMMMMMMMFMFFMAMM
+  MMMGFLFLFMMFMAMM
+  MMGFFLFLFMFFMAMM
+  MMFFFFFFFFFFMAMM
+  MMJMMMMMMMMMMAMM
+  MMMAAAAAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 146 (jungle boots / water walking boots)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMGGGGGGMMM
+  MMMMMMGFAAAAJJMM
+  MMMMMMFFFFFFFJAM
+  MMMMMMMGFFFFFJAM
+  MMMMMMMKGFFFFJAM
+  MMMMMMMMGFFFFAMM
+  MMMMMMMMFGFFJAMM
+  MMMGFLFLFGGFJAMM
+  MMGFFLFLFGFFJAMM
+  MMFFFFFFFFFFJAMM
+  MMJJJJJJJJJJJAMM
+  MMMAAAAAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 147 (hiking boots / jumping boots)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMCCKKKJAM
+  MMMMMMMCAAAAKJAM
+  MMMMMMMKJKKKKJAM
+  MMMMMMMMJKKKKAMM
+  MMMMMMMMKJKKJAMM
+  MMMCKLKLKJJKJAMM
+  MMCKKLKLKJKKJAMM
+  MMKKKKKKKKKKJAMM
+  MMJJJJJJJJJJJAMM
+  MMMAAAAAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 148 (mud boots / elven boots)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMCCKKKKMMM
+  MMMMMMCKAAAAJJMM
+  MMMMMMKKKKKKKJAM
+  MMMMMMMJKKKKKJAM
+  MMMMMMMKJKKKKJAM
+  MMMMMMMMJKKKKAMM
+  MMMMMMMMKJKKJAMM
+  MMMCKLKLKJJKJAMM
+  MMCKKLKLKJKKJAMM
+  MMKKKKKKKKKKJAMM
+  MMJJJJJJJJJJJAMM
+  MMMAAAAAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 149 (buckled boots / kicking boots)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMCCKKKKMMM
+  MMMMMMCKAAAAJJMM
+  MMMMMMKKKKKKKJAM
+  MMMMMMMJKKKKKJAM
+  MMMMMMMCJKKKKJAM
+  MMMMMMHOOKKKCAMM
+  MMMCKHKKHCCCCAMM
+  MMCKKLOHCCCCJAMM
+  MCKKKKKKKJKKJAMM
+  MCKKKKKKKKKKJAMM
+  MMJJJJJJJJJJJAMM
+  MMMAAAAAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 150 (riding boots / fumble boots)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMLLLLLLMMM
+  MMMMMMLAAAAAALMM
+  MMMMMMLAAAAAALPM
+  MMMMMMMLLLLLLAPM
+  MMMMMMMAAAAAAAPM
+  MMMMMMMMAAAAAPMM
+  MMMMMMMMAAAAAPMM
+  MMMAALALAAAAAPMM
+  MMAAALALAAAAAPMM
+  MMAAAAAAAAAAAPMM
+  MMMAAAAAAAAAAPMM
+  MMMPPPPPPPPPPPMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 151 (snow boots / levitation boots)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMNNLLLLMMM
+  MMMMMMNOAAAALLMM
+  MMMMMMOOOOOOOLAM
+  MMMMMMMLOOOOOLAM
+  MMMMMMMLLOOOOLAM
+  MMMMMMMMLOOOOAMM
+  MMMMMMMMOLOOLAMM
+  MMMNOAOAOLLOLAMM
+  MMNOOAOAOLOOOLAM
+  MOOOOOOOOOOOOOAM
+  MOOOOOOOOOOOOOAM
+  MMLALALALALALAAM
+  MMMAMAMAMAMAMAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 152 (wooden / adornment)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMKCCKJMMMMMM
+  MMMMKJAAAKJMMMMM
+  MMMMCAMMMAKAMMMM
+  MMMMCAMMMMKAMMMM
+  MMMMJKAMMKJAMMMM
+  MMMMMJKKKJAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 153 (granite / gain strength)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPPPPPMMMMMM
+  MMMMPBPBPPPMMMMM
+  MMMPPPAAAPBPMMMM
+  MMMPBAAAAAPPAMMM
+  MMMPPAAMMMPPAMMM
+  MMMBPPAMMPPBAMMM
+  MMMMPPPPPBPAAMMM
+  MMMMMPBPPPAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 154 (opal / gain constitution)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMOIOMMMMMMM
+  MMMMMOIOBOAMMMMM
+  MMMMMOOOBOAMMMMM
+  MMMMMCOGOCAMMMMM
+  MMMMHHAAAHNAMMMM
+  MMMMHAAMMMHAMMMM
+  MMMMNHAMMHNAMMMM
+  MMMMMHNHNHAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 155 (clay / increase accuracy)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLLLLLMMMMMM
+  MMMMLCCCCLLMMMMM
+  MMMLCCAAALLCMMMM
+  MMMLCAAAAALCAMMM
+  MMMLCAAMMMLCAMMM
+  MMMLCCAMMLLCAMMM
+  MMMMLLLLLCCAAMMM
+  MMMMMCCCCCAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 156 (coral / increase damage)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOOOOOMMMMMM
+  MMMMOOAAAOOMMMMM
+  MMMMOAAMMMNAMMMM
+  MMMMOAMMMMOAMMMM
+  MMMMNOAMMONAMMMM
+  MMMMMONONOAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 157 (black onyx / protection)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMANAAAMMMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMMMAAAMMMMMMM
+  MMMMMOLLLNAMMMMM
+  MMMMOOAAAONAMMMM
+  MMMMOAAMMMOAMMMM
+  MMMMNOAMMONAMMMM
+  MMMMMONONOAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 158 (moonstone / regeneration)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMOBOMMMMMMM
+  MMMMMOBOOOAMMMMM
+  MMMMMOOOOOAMMMMM
+  MMMMMCCCCCAMMMMM
+  MMMMHHAAAHNAMMMM
+  MMMMHAAMMMHAMMMM
+  MMMMNHAMMHNAMMMM
+  MMMMMHNHNHAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 159 (tiger eye / searching)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMKCACKAMMMMM
+  MMMMMCCACCAMMMMM
+  MMMMMACCCAMMMMMM
+  MMMMMOCOCNAMMMMM
+  MMMMOOAAAONAMMMM
+  MMMMOAAMMMOAMMMM
+  MMMMNOAMMONAMMMM
+  MMMMMONONOAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 160 (jade / stealth)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMNFFMMMMMMM
+  MMMMMFFFFFAMMMMM
+  MMMMMFFFFFAMMMMM
+  MMMMMOLLLNAMMMMM
+  MMMMOOAAAONAMMMM
+  MMMMOAAMMMOAMMMM
+  MMMMNOAMMONAMMMM
+  MMMMMONONOAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 161 (bronze / sustain ability)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMCHCCCMMMMMM
+  MMMMCHAAACCMMMMM
+  MMMMCAAMMACAMMMM
+  MMMMCAMMMMCAMMMM
+  MMMMCCAMMCCAMMMM
+  MMMMMCCCCCAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 162 (agate / levitation)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPNOOPAMMMMM
+  MMMMMOIOIOAMMMMM
+  MMMMMAOIOAMMMMMM
+  MMMMMLHHHLAMMMMM
+  MMMMLHAAAHLAMMMM
+  MMMMHAAMMMHAMMMM
+  MMMMLHAMMHLAMMMM
+  MMMMMLHHHLAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 163 (topaz / hunger)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPNBBPAMMMMM
+  MMMMMBOOOBAMMMMM
+  MMMMMABBBAMMMMMM
+  MMMMMOLLLNAMMMMM
+  MMMMOOAAAONAMMMM
+  MMMMOAAMMMOAMMMM
+  MMMMNOAMMONAMMMM
+  MMMMMONONOAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 164 (sapphire / aggravate monster)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMNEEMMMMMMM
+  MMMMMEEEEFAMMMMM
+  MMMMMAEEFAMMMMMM
+  MMMMMOFEFNAMMMMM
+  MMMMOOAAAONAMMMM
+  MMMMOAAMMMOAMMMM
+  MMMMNOAMMONAMMMM
+  MMMMMONONOAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 165 (ruby / conflict)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMJLDDJAMMMMM
+  MMMMMDDDDDAMMMMM
+  MMMMMADDDAMMMMMM
+  MMMMMOLLLNAMMMMM
+  MMMMOOAAAONAMMMM
+  MMMMOAAMMMOAMMMM
+  MMMMNOAMMONAMMMM
+  MMMMMONONOAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 166 (diamond / warning)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPNNNPAMMMMM
+  MMMMMNNNNBAMMMMM
+  MMMMMANNBAMMMMMM
+  MMMMMPPPPPAMMMMM
+  MMMMPPAAAPPAMMMM
+  MMMMPAAMMMPAMMMM
+  MMMMPPAMMPPAMMMM
+  MMMMMPPPPPAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 167 (pearl / poison resistance)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMNNNMMMMMMM
+  MMMMMNONNNAMMMMM
+  MMMMMNNNNNAMMMMM
+  MMMMMANNNAMMMMMM
+  MMMMMLHHHLAMMMMM
+  MMMMLHAAAHLAMMMM
+  MMMMHAAMMMHAMMMM
+  MMMMLHAMMHLAMMMM
+  MMMMMLHHHLAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 168 (iron / fire resistance)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPPPPPMMMMMM
+  MMMMPPAAAPPMMMMM
+  MMMMPAMMMMPAMMMM
+  MMMMPAMMMMPAMMMM
+  MMMMPPAMMPPAMMMM
+  MMMMMPPPPPAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 169 (brass / cold resistance)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMHHHCCMMMMMM
+  MMMMHCAAACCMMMMM
+  MMMMHAAMMMCAMMMM
+  MMMMCAMMMMHAMMMM
+  MMMMCCAMMHCAMMMM
+  MMMMMCCCHCAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 170 (copper / shock resistance)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMCCCCCMMMMMM
+  MMMMCCAAACCMMMMM
+  MMMMCAAMMACAMMMM
+  MMMMCAMMMMCAMMMM
+  MMMMCCAMMCCAMMMM
+  MMMMMCCCCCAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 171 (twisted / free action)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMAPPBPMMMMMM
+  MMMMPPAAAAPMMMMM
+  MMMMPAAMMAPAMMMM
+  MMMMPAMMMMBAMMMM
+  MMMMBPAMMAPAMMMM
+  MMMMMAPBPPAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 172 (steel / slow digestion)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPBBPPMMMMMM
+  MMMMPBAAAPPMMMMM
+  MMMMPAAMMAPAMMMM
+  MMMMPAMMMMPAMMMM
+  MMMMPPAMMPPAMMMM
+  MMMMMPPPPPAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 173 (silver / teleportation)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPNBPPMMMMMM
+  MMMMPBAAAPPMMMMM
+  MMMMBAAMMAPAMMMM
+  MMMMBAMMMMPAMMMM
+  MMMMPPAMMPPAMMMM
+  MMMMMPPPBPAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 174 (gold / teleport control)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLHHHLMMMMMM
+  MMMMLHAAAHLMMMMM
+  MMMMHAAMMAHAMMMM
+  MMMMHAMMMMHAMMMM
+  MMMMLHAMMHLAMMMM
+  MMMMMLHHHLAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 175 (ivory / polymorph)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOOONOMMMMMM
+  MMMMOOAAAOOMMMMM
+  MMMMNAAMMANAMMMM
+  MMMMOAMMMMOAMMMM
+  MMMMNOAMMONAMMMM
+  MMMMMONONOAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 176 (emerald / polymorph control)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPGFFPAMMMMM
+  MMMMMFGFFFAMMMMM
+  MMMMMAFFFAMMMMMM
+  MMMMMOCECNAMMMMM
+  MMMMOOAAAONAMMMM
+  MMMMOAAMMMOAMMMM
+  MMMMNOAMMONAMMMM
+  MMMMMONONOAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 177 (wire / invisibility)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPPPPPMMMMMM
+  MMMMPPAAAPPMMMMM
+  MMMMPAAMMMPAMMMM
+  MMMMPAMMMMMPAMMM
+  MMMMPAMMMMMPAMMM
+  MMMMPAAPPPPAMMMM
+  MMMMMPPPAAAMMMMM
+  MMMMMMAAMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 178 (engagement / see invisible)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPNNNPAMMMMM
+  MMMMMNNNNNAMMMMM
+  MMMMMANNNAMMMMMM
+  MMMMMLHHHLAMMMMM
+  MMMMLHAAAHLAMMMM
+  MMMMHAAMMMHAMMMM
+  MMMMLHAMMHLAMMMM
+  MMMMMLHHHLAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 179 (shiny / protection from shape changers)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMNNNNNMMMMMM
+  MMMMNNAAANNMMMMM
+  MMMMNAMMMMNAMMMM
+  MMMMNAMMMMNAMMMM
+  MMMMNNAMMNNAMMMM
+  MMMMMNNNNNAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 180 (circular / amulet of ESP)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMLLLLLAAMMM
+  MMMMMLAAMMMLAAMM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMMLAAMMMLAAMM
+  MMMMMMLAAMLAAMMM
+  MMMMMMACCCAMMMMM
+  MMMMMMCKKKKAMMMM
+  MMMMMMCKKKKAMMMM
+  MMMMMMMKKKAAMMMM
+  MMMMMMMAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 181 (spherical / amulet of life saving)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMLLLLLAAMMM
+  MMMMMLAAMMMLAAMM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMMLAAMMMLAAMM
+  MMMMMMLAAMLAAMMM
+  MMMMMMAKKKAAMMMM
+  MMMMMMKHCCKAAMMM
+  MMMMMMKCCCKAAMMM
+  MMMMMMAKKKAAMMMM
+  MMMMMMMAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 182 (oval / amulet of strangulation)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMLLLLLLAAMM
+  MMMMMLAAMMMMLAAM
+  MMMMLAAMMMMMMLAA
+  MMMMLAAMMMMMMLAA
+  MMMMLAAMMMMMMLAA
+  MMMMLAAMMMMMMLAA
+  MMMMMLAAMMMMLAAM
+  MMMMMMLAAAMLAAMM
+  MMMMMMACCCCAMMMM
+  MMMMMMCKKKKKAMMM
+  MMMMMMCKKKKKAMMM
+  MMMMMMAKKKKAMMMM
+  MMMMMMMAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 183 (triangular / amulet of restful sleep)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMLLLLLAAMMM
+  MMMMMLAAMMMLAAMM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMMLAAMMMLAAMM
+  MMMMMMLAAMLAAMMM
+  MMMMMMALCLAAMMMM
+  MMMMMMMCKKAMMMMM
+  MMMMMMCKKKKAMMMM
+  MMMMMCKKKKKKAMMM
+  MMMMMMMAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 184 (pyramidal / amulet versus poison)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMLLLLLAAMMM
+  MMMMMLAAMMMLAAMM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMMLAAMMMLAAMM
+  MMMMMMLAAMLAAMMM
+  MMMMMMALCLAAMMMM
+  MMMMMMMCCKAAMMMM
+  MMMMMMCCCKKAMMMM
+  MMMMMCCCKKKKAMMM
+  MMMMCCKJJJJKKAMM
+  MMMMKJJJJJJJJAMM
+  MMMMMMMAAAAAAAMM
+}
+# tile 185 (square / amulet of change)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMLLLLLAAMMM
+  MMMMMLAAMMMLAAMM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMMLAAMMMLAAMM
+  MMMMMMLAAMLAAMMM
+  MMMMMMALALAAMMMM
+  MMMMMMCCCCCAMMMM
+  MMMMMMCKKKKAMMMM
+  MMMMMMCKKKKAMMMM
+  MMMMMMCKKKKAMMMM
+  MMMMMMMAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 186 (concave / amulet of unchanging)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMLLLLLAAMMM
+  MMMMMLAAMMMLAAMM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMMLAAMMMLAAMM
+  MMMMMMLAAMLAAMMM
+  MMMMMMAJJKAAMMMM
+  MMMMMMJJJCKAAMMM
+  MMMMMJJJKKCCAMMM
+  MMMMMJJKKCLCAMMM
+  MMMMMMJJCLCAAMMM
+  MMMMMMMKCCAAMMMM
+  MMMMMMMMAAAMMMMM
+}
+# tile 187 (hexagonal / amulet of reflection)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMLLLLLAAMMM
+  MMMMMLAAMMMLAAMM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMMLAAMMMLAAMM
+  MMMMMMLAMMLAAMMM
+  MMMMMMACCCAAMMMM
+  MMMMMMCKKKKAAMMM
+  MMMMMCKKKKKKAMMM
+  MMMMMMKKKKKAAMMM
+  MMMMMMMKKKAAMMMM
+  MMMMMMMMAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 188 (octagonal / amulet of magical breathing)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMLLLLLAAMMM
+  MMMMMLAAMMMLAAMM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMLAAMMMMMLAAM
+  MMMMMLAAMMMLAAMM
+  MMMMMMLAAMLAAMMM
+  MMMMMMACCCAAMMMM
+  MMMMMMCKKKKAAMMM
+  MMMMMCKKKKKKAMMM
+  MMMMMCKKKKKKAMMM
+  MMMMMMKKKKKAAMMM
+  MMMMMMMKKKAAMMMM
+  MMMMMMMMAAAMMMMM
+}
+# tile 189 (Amulet of Yendor / cheap plastic imitation of the Amulet of Yendor)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMHHHHHAAMMM
+  MMMMMHAAMMMHAAMM
+  MMMMHAAMMMMMHAAM
+  MMMMHAAMMMMMHAAM
+  MMMMHAAMMMMMHAAM
+  MMMMHAAMMMMMHAAM
+  MMMMMHAAMMMHAAMM
+  MMMMMMHAAMHAAMMM
+  MMMMMMAHCCAAMMMM
+  MMMMMMBCDDPAAMMM
+  MMMMMMBCDDPAAMMM
+  MMMMMMABPPAAMMMM
+  MMMMMMMAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 190 (Amulet of Yendor / Amulet of Yendor)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMHHHHHAAMMM
+  MMMMMHAAMMMHAAMM
+  MMMMHAAMMMMMHAAM
+  MMMMHAAMMMMMHAAM
+  MMMMHAAMMMMMHAAM
+  MMMMHAAMMMMMHAAM
+  MMMMMHAAMMMHAAMM
+  MMMMMMHAAMHAAMMM
+  MMMMMMAHCCAAMMMM
+  MMMMMMBCDDPAAMMM
+  MMMMMMBCDDPAAMMM
+  MMMMMMABPPAAMMMM
+  MMMMMMMAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 191 (large box)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMCCCCCCCCCCJM
+  MMMCKKKKCKKKCJJM
+  MMCKJJKCJJJCJJJM
+  MCJJJKCJJJCJJJJM
+  CCCCCCCCCCCJJJJM
+  CJJJJJJJJJJJJJJA
+  CJKKKCJKKKCJJJJA
+  CJKKKHHKKKCJJJJA
+  CJKKKCJKKKCJJJAA
+  CJCCCCJCCCCJJAAM
+  CKKKKKKKKKKJAAMM
+  MAAAAAAAAAAAAMMM
+}
+# tile 192 (chest)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMCJKKKCJKKKCMM
+  MCKJKKCKJKKCJJKM
+  MKJKKKKJKKKKJJJM
+  CJKKKCJKKKCJJJJM
+  CJKKKCJKKKCJJJJM
+  CCCCCHHCCCCJJJJM
+  CJJJHJJHJJJJJJJM
+  CJKKKHHKKKCJJJJA
+  CJKKKHHKKKCJJJJA
+  CJKKKCJKKKCJJJAA
+  CJCCCCJCCCCJJAAM
+  CKKKKKKKKKKJAAMM
+  MAAAAAAAAAAAAMMM
+}
+# tile 193 (ice box)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMNNNNNNNNNNNM
+  MMMNPBBBBBBBBNPM
+  MMNPPBBBBBBBNPPM
+  MNPPPBBBBBBNPPPM
+  NNNNNNNNNNNPPPPM
+  NBBBBBBBBBBPPPPA
+  NNNNBBBBBBBPPPPA
+  NBBBBBBBBBBPPPPA
+  NNBBBBBBBBBPPPAA
+  NBBBBBBBBBBPPAAM
+  NBBBBBBBBBBPAAMM
+  MAAAAAAAAAAAAMMM
+}
+# tile 194 (bag / sack)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMCJKKKKJMMMMM
+  MMMMMCJKKJAAMMMM
+  MMMMOOOOOAAMMMMM
+  MMMOMOKKKJAMMMMM
+  MMMMCOKKKKJAMMMM
+  MMMCCCKKKKKJAMMM
+  MMCCCKKKKKKJJAMM
+  MMCCCKKKKKKJJAMM
+  MMCCKKKKKKJJJAMM
+  MMMCKKKKJJJJAMMM
+  MMMMAAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 195 (bag / oilskin sack)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMCJKKKKJMMMMM
+  MMMMMCJKKJAAMMMM
+  MMMMOOOOOAAMMMMM
+  MMMOMOKKKJAMMMMM
+  MMMMCOKKKKJAMMMM
+  MMMCCCKKKKKJAMMM
+  MMCCCKKKKKKJJAMM
+  MMCCCKKKKKKJJAMM
+  MMCCKKKKKKJJJAMM
+  MMMCKKKKJJJJAMMM
+  MMMMAAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 196 (bag / bag of holding)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMCJKKKKJMMMMM
+  MMMMMCJKKJAAMMMM
+  MMMMOOOOOAAMMMMM
+  MMMOMOKKKJAMMMMM
+  MMMMCOKKKKJAMMMM
+  MMMCCCKKKKKJAMMM
+  MMCCCKKKKKKJJAMM
+  MMCCCKKKKKKJJAMM
+  MMCCKKKKKKJJJAMM
+  MMMCKKKKJJJJAMMM
+  MMMMAAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 197 (bag / bag of tricks)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMCJKKKKJMMMMM
+  MMMMMCJKKJAAMMMM
+  MMMMOOOOOAAMMMMM
+  MMMOMOKKKJAMMMMM
+  MMMMCOKKKKJAMMMM
+  MMMCCCKKKKKJAMMM
+  MMCCCKKKKKKJJAMM
+  MMCCCKKKKKKJJAMM
+  MMCCKKKKKKJJJAMM
+  MMMCKKKKJJJJAMMM
+  MMMMAAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 198 (key / skeleton key)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMOOMMMMMMMMMMMM
+  MOMAOOOOOOOOOOMM
+  MOAMOAAAAOAOAOAM
+  MOAMOAMMMOAMAOAM
+  MMOOMAMMMMAMMMAM
+  MMMAAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 199 (lock pick)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MBBBPPPPPMMMMMMM
+  MBPPPPPPPPPPPAMM
+  MBPPAAAAAAAAAAAM
+  MBPPAMMMMMMMMMMM
+  MMAAAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 200 (credit card)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMPPPPPPPPPPPPMM
+  MPPPDDDDPCCCPPPM
+  MPPDDDDPCCCCCPPA
+  MPPDDDDPCCCCCPPA
+  MPPDDDDPCCCCCPPA
+  MPPPDDDDPCCCPPPA
+  MMPPPPPPPPPPPPAA
+  MMMAAAAAAAAAAAAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 201 (candle / tallow candle)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNNAAAMMMMMMMM
+  MMMMMNPOAMMMMMMM
+  MMMMMPNNOAMMMMMM
+  MMMMMOOONOAMMMMM
+  MMMMMMOOONOAMMMM
+  MMMMMMMOOONOAMMM
+  MMMMMMMMOOONOAMM
+  MMMMMMMMMOOONOAM
+  MMMMMMMMMMOOOPAM
+  MMMMMMMMMMMOPAMM
+  MMMMMMMMMMMMAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 202 (candle / wax candle)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMNNAAAMMMMMMMM
+  MMMMMNPOAMMMMMMM
+  MMMMMPNNOAMMMMMM
+  MMMMMOOONOAMMMMM
+  MMMMMMOOONOAMMMM
+  MMMMMMMOOONOAMMM
+  MMMMMMMMOOONOAMM
+  MMMMMMMMMOOONOAM
+  MMMMMMMMMMOOOPAM
+  MMMMMMMMMMMOPAMM
+  MMMMMMMMMMMMAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 203 (brass lantern)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMCCCMMMMMMM
+  MMMMMCMAACMMMMMM
+  MMMMMCAMMCAMMMMM
+  MMMMMLHHHLAMMMMM
+  MMMMLNNHNNLAMMMM
+  MMMMHNNHNNHAMMMM
+  MMMMHNNHNNHAMMMM
+  MMMMHNNHNNHAMMMM
+  MMMMLHHHHHLAMMMM
+  MMMMMLHHHLAMMMMM
+  MMMMMLHHHLAMMMMM
+  MMMMLHHHHHLMMMMM
+  MMMMMAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 204 (lamp / oil lamp)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMHAMMMMMM
+  MLHCMMLNLLLAMMMM
+  MMMHHHNHHHHHHHMM
+  MMMMCLHHHHHLCHAM
+  MMMMMACLHLCCAAAM
+  MMMMMMLHHHLAAMMM
+  MMMMMMAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 205 (lamp / magic lamp)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMHAMMMMMM
+  MLHCMMLNLLLAMMMM
+  MMMHHHNHHHHHHHMM
+  MMMMCLHHHHHLCHAM
+  MMMMMACLHLCCAAAM
+  MMMMMMLHHHLAAMMM
+  MMMMMMAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 206 (expensive camera)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMAAAMMMMMMM
+  MMMAMAAAAAAAAAMM
+  MMAAAAAAAAABBAMM
+  MMAAAAPPPAABBAMM
+  MMAAAPPBPPAAAAPM
+  MMAAAPBBBPAAAAPM
+  MMAAAPPBPPAAAAPM
+  MMAAAAPPPAAAAAPM
+  MMAAAAAAAAAAAAPM
+  MMMPPPPPPPPPPPPM
+  MMMMMMMMMMMMMMMM
+}
+# tile 207 (looking glass / mirror)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMBBBBAMMMMMMM
+  MMMBPPPPBAMMMMMM
+  MMBPPPPPPBAMMMMM
+  MMBPPPPPPPBAMMMM
+  MMBPPPPPPPBAMMMM
+  MMBPPPPPPPBAMMMM
+  MMMBPPPPPPBAMMMM
+  MMMMBPPPPBBAMMMM
+  MMMMMBBBBBBBAMMM
+  MMMMMMMMMMBBBAMM
+  MMMMMMMMMMMBBBAM
+  MMMMMMMMMMMMBBAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 208 (glass orb / crystal ball)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMBBBBMMMMMMM
+  MMMMBNBBBBMMMMMM
+  MMMMBBBBBBMMMMMM
+  MMMMBBBBBBMAAMMM
+  MMMMBBBBBBAAAAMM
+  MMMMCBBBBJAAAMMM
+  MMMCKKKKKJJAMMMM
+  MMMMKKKKJJAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 209 (lenses)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPPMMMMMPMMM
+  MMMMPMMPAMMPMPAM
+  MMMPMMAAMMPMAAMM
+  MMPNBAAMNBPAAMMM
+  MMNAABPNAABAAMMM
+  MMBAMPABAMPAAMMM
+  MMMBPAAMBPAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 210 (blindfold)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMOOOOOOOOMMMM
+  MMMOOOOOOOOOOMMM
+  MMMOOOOOOOOOOAMM
+  MMOAOOOAAOOOAOAM
+  MMOAAAAAAAAAAOAM
+  MMMOOAMMMMMMMOAM
+  MMMMMOAMMMMMOAMM
+  MMMMMOAMMMMMOAMM
+  MMMMMMOOAMMOAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 211 (towel)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMPPPPPPPM
+  MMMMMMMMOOOOOOOM
+  MMMMMMMMOOOOOOOM
+  MMMOOOOOOBOOOOOM
+  MMOOOOOOOPPOOOAM
+  MMOOOOOOOPPOOOAM
+  MMOOOOOOOPPPOAMM
+  MOOOOOOOPPPPPAMM
+  MOOOOOOOAAAAAMMM
+  MPPPPPPPAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 212 (saddle)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJJAMMMJJAMMM
+  MMMMJKJJJJKJAMMM
+  MMMMMJCCKKJAMMMM
+  MMMMMJKKKKJAMMMM
+  MMMMMMJKKJAMMMMM
+  MMMMMMMJJAAMMMMM
+  MMMMMMMJAAMAMMMM
+  MMMMMMMPAMMAMMMM
+  MMMMMMPAPAAMMMMM
+  MMMMMMPPPAMMMMMM
+  MMMMMMMAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 213 (leash)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMKKJMMMMMM
+  MMMMMMJJJJAMMMMM
+  MMMMMJAAAAAMMMMM
+  MMMMKAAMMMMMMMMM
+  MMMMJAMMMMMMMMMM
+  MMMMJAMMMMMMMMMM
+  MMMMMJJJJMMMMMMM
+  MMMMMMAAAJMMMMMM
+  MMMMMMMMMAJMMMMM
+  MMMPPPPPMMKAMMMM
+  MMPPAAAPPKAAMMMM
+  MMMPPPPPAAAMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 214 (stethoscope)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMPNMMMNPMMMMMM
+  MMPAAMMMMAPAMMMM
+  MMPAMMMMMMPAMMMM
+  MMMPAMMMMPAMMMMM
+  MMMPAMMMMPAMMMMM
+  MMMMPAMMPAMMMMMM
+  MMMMPAMMPAPPPMMM
+  MMMMMPPPAMJJPAMM
+  MMMMMPJPAMJPPAMM
+  MMMMMMJAMMJAAAMM
+  MMMMMMJAMJJAMMMM
+  MMMMMMMJJJAMMMMM
+  MMMMMMMMAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 215 (tinning kit)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPOOOOOOOOPM
+  MMMMPPOOOOOOOPPM
+  MMMPPPAAAAAAPPPM
+  MMOOOOOOOOOOPPPA
+  MMOOOOBBBOOOPPPA
+  MMOOOBPPPMOOPPAA
+  MMOOOBPBPMOOPAAM
+  MMOOOOBPMMOOAAMM
+  MMMAAOOOPMAAAMMM
+  MMMMMBOOPMAMMMMM
+  MMMMMBPPPMAMMMMM
+  MMMMMABPMAMMMMMM
+  MMMMMMAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 216 (tin opener)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMBAMMMMMM
+  MMMMMMMMBPAMMMMM
+  MMMMMMPMBPPAMMMM
+  MMMMMMPABPPAMMMM
+  MMMMMMBPPPAAMMMM
+  MMMMMMMBPAAMMMMM
+  MMMMMMMKJAMMMMMM
+  MMMMMMMKJAMMMMMM
+  MMMMMMMKJAMMMMMM
+  MMMMMMMKJAMMMMMM
+  MMMMMMMKJAMMMMMM
+  MMMMMMMKJAMMMMMM
+  MMMMMMMMAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 217 (can of grease)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMBPPPPMMMMMM
+  MMMMBAAAAAPMMMMM
+  MMMMBPAAAPMAMMMM
+  MMMMBBPPPMMAAMMM
+  MMMMBBPPPMMAAAMM
+  MMMMBBPPPMMAAMMM
+  MMMMMBPPPMAAMMMM
+  MMMMMMMAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 218 (figurine)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMJJMMMMMM
+  MMMMMMMKCJJMMMMM
+  MMMMMMMKKJJMMMMM
+  MMMMCKMCJMMMMMMM
+  MMMMJJCKJMCJMMMM
+  MMMMMJCKJJJJAAMM
+  MMMMMMCKAAMAAAAM
+  MMMMKCKKAAAAAAMM
+  MMMJCCKKAJJAAMMM
+  MMMJKKKKJJJJAMMM
+  MMMMJJKKJJJAAMMM
+  MMMMMJJJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 219 (magic marker)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMBMMMMM
+  MMMMMMMMMBIEMMMM
+  MMMMMMMMBIEAAMMM
+  MMMMMMMBIEAAMMMM
+  MMMMMMBIEAAMMMMM
+  MMMMMBIEAAMMMMMM
+  MMMMNNEAAMMMMMMM
+  MMMMNNAAMMMMMMMM
+  MMMMMAAMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 220 (land mine)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMAMMMMMMMM
+  MMMMMFFAFFMMMMMM
+  MMMMFMAAAMFAMMMM
+  MMMMFGFFFFFAAMMM
+  MMMMMGFFFFAAMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 221 (beartrap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPOMOPMMMMMM
+  MMMMPAMMMAPMMMMM
+  MMMMPPOMOPPAMMMM
+  MMMMPAMMMAPAMMMM
+  MMMMPPOAOPPAAMMM
+  MMMMPAAAAAPAAMMM
+  MMMMPAAMMMPAAMMM
+  MMMMPPAMMPPAMMMM
+  MMMMMPPPPPAAMMMM
+  MMMMMMPPPAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 222 (whistle / tin whistle)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMBBABBBBBBBMMMM
+  MBPPPPPPPPPPAMMM
+  MPPPPPPAAAAAAMMM
+  MPPPPPPAMMMMMMMM
+  MMPPPPAAMMMMMMMM
+  MMMAAAAMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 223 (whistle / magic whistle)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMBBABBBBBBBMMMM
+  MBPPPPPPPPPPAMMM
+  MPPPPPPAAAAAAMMM
+  MPPPPPPAMMMMMMMM
+  MMPPPPAAMMMMMMMM
+  MMMAAAAMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 224 (flute / wooden flute)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMJMMM
+  MMMMMMMMMMMAJMMM
+  MMMMMMMMMMKJAMMM
+  MMMMMMMMMKJAMMMM
+  MMMMMMMMKJAMMMMM
+  MMMMMMMJJAMMMMMM
+  MMMMMMKJAMMMMMMM
+  MMMMMJJAMMMMMMMM
+  MMMMKJAMMMMMMMMM
+  MMMJJAMMMMMMMMMM
+  MMKJAMMMMMMMMMMM
+  MJJAMMMMMMMMMMMM
+  MMAMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 225 (flute / magic flute)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMJMMM
+  MMMMMMMMMMMAJMMM
+  MMMMMMMMMMKJAMMM
+  MMMMMMMMMKJAMMMM
+  MMMMMMMMJJAMMMMM
+  MMMMMMMJJAMMMMMM
+  MMMMMMKJAMMMMMMM
+  MMMMMJJAMMMMMMMM
+  MMMMKJAMMMMMMMMM
+  MMMJJAMMMMMMMMMM
+  MMKJAMMMMMMMMMMM
+  MJJAMMMMMMMMMMMM
+  MMAMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 226 (horn / tooled horn)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNMMMM
+  MMMMMMMMMMNOOMMM
+  MMMMMMMMMNOOMMMM
+  MMMMMMMNNOOPMMMM
+  MMMMNNPOOOOMMMMM
+  MMMNKKNPOOPMAMMM
+  MMNKJAANPOMAAAMM
+  MMNKAAANPPAAAMMM
+  MMNKJAJNPAAAMMMM
+  MMMNKKNPAAAMMMMM
+  MMMMNNPAAAMMMMMM
+  MMMMAAAMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 227 (horn / frost horn)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNMMMM
+  MMMMMMMMMMNOOMMM
+  MMMMMMMMMNOOMMMM
+  MMMMMMMNNOOPMMMM
+  MMMMNNPOOOOMMMMM
+  MMMNKKNPOOPMAMMM
+  MMNKJAANPOMAAAMM
+  MMNKAAANPPAAAMMM
+  MMNKJAJNPAAAMMMM
+  MMMNKKNPAAAMMMMM
+  MMMMNNPAAAMMMMMM
+  MMMMAAAMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 228 (horn / fire horn)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNMMMM
+  MMMMMMMMMMNOOMMM
+  MMMMMMMMMNOOMMMM
+  MMMMMMMNNOOPMMMM
+  MMMMNNPOOOOMMMMM
+  MMMNKKNPOOPMAMMM
+  MMNKJAANPOMAAAMM
+  MMNKAAANPPAAAMMM
+  MMNKJAJNPAAAMMMM
+  MMMNKKNPAAAMMMMM
+  MMMMNNPAAAMMMMMM
+  MMMMAAAMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 229 (horn / horn of plenty)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNMMMM
+  MMMMMMMMMMNOOMMM
+  MMMMMMMMMNOOMMMM
+  MMMMMMMNNOOPMMMM
+  MMMMNNPOOOOMMMMM
+  MMMNKKNPOOPMAMMM
+  MMNKJAANPOMAAAMM
+  MMNKAAANPPAAAMMM
+  MMNKJAJNPAAAMMMM
+  MMMNKKNPAAAMMMMM
+  MMMMNNPAAAMMMMMM
+  MMMMAAAMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 230 (harp / wooden harp)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMKKKMMMMMMKKKMM
+  MMKAKPPPPPPKAKAM
+  MMMAKAMMMMMKAMAM
+  MMMKPPPPPPPPKMMM
+  MMMKAMMMMMMMKAMM
+  MMMKPPPPPPPPKAMM
+  MMMKAMMMMMMMKAMM
+  MMMMKPPPPPPKMAMM
+  MMMMMKKKKKKMAMMM
+  MMMMMMAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 231 (harp / magic harp)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMKKKMMMMMMKKKMM
+  MMKAKPPPPPPKAKAM
+  MMMAKAMMMMMKAMAM
+  MMMKPPPPPPPPKMMM
+  MMMKAMMMMMMMKAMM
+  MMMKPPPPPPPPKAMM
+  MMMKAMMMMMMMKAMM
+  MMMMKPPPPPPKMAMM
+  MMMMMKKKKKKMAMMM
+  MMMMMMAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 232 (bell)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMKAMMMMMMM
+  MMMMMMKAKAMMMMMM
+  MMMMMMMKAMMMMMMM
+  MMMMMMLCKAMMMMMM
+  MMMMMLCCCKAMMMMM
+  MMMMMLCCCKAMMMMM
+  MMMMMLCCCKAAMMMM
+  MMMMCLCCCKCAMMMM
+  MMMCLLCCCKLKAMMM
+  MMMCCLLLLLCKAMMM
+  MMMMCCCCCCKAAMMM
+  MMMMMAAKKAAAMMMM
+  MMMMMMMAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 233 (bugle)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMLMMMMMMMMMMMMM
+  MKCLMMMMMMMMMMMM
+  MKCCLMMMMMMMMLLM
+  MKCCCLCCCCCCCLAM
+  MKCCKAAKKKKKAACA
+  MKCKAAJCAAACJAAM
+  MMKAAMMJCCCJAAMM
+  MMMAMMMMAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 234 (drum / leather drum)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPOOOOPMMMMM
+  MMMMOOOOOOOOMMMM
+  MMMOOOOOOOOOOMMM
+  MMMLOOOOOOOOLAAM
+  MMMLKOOOOOOJLAAA
+  MMMKKLKKKKLJJAAA
+  MMMJKLKKKKLJJAAM
+  MMMMJKKKKKKJAAMM
+  MMMMMJJJJJJAAMMM
+  MMMMMMAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 235 (drum / drum of earthquake)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPOOOOPMMMMM
+  MMMMOOOOOOOOMMMM
+  MMMOOOOOOOOOOMMM
+  MMMLOOOOOOOOLAAM
+  MMMLKOOOOOOJLAAM
+  MMMKKLKKKKLJJAAM
+  MMMJKLKKKKLJJAAM
+  MMMMJKKKKKKJAAMM
+  MMMMMJJJJJJAAMMM
+  MMMMMMAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 236 (pick-axe)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMBBAMMMMMMM
+  MMMMMBPPBAMMMMMM
+  MMMMMMPPPBAMMMMM
+  MMMMMMMKPPPAMMMM
+  MMMMMMKJAMPPAMMM
+  MMMMMKJAMMMPAMMM
+  MMMMKJAMMMMMMMMM
+  MMMKJAMMMMMMMMMM
+  MMKJAMMMMMMMMMMM
+  MKJAMMMMMMMMMMMM
+  MMAMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 237 (iron hook / grappling hook)
+{
+  MMMMMMMMMMMMMNMM
+  MMMMMMMMMMMMMMPM
+  MMMMMMMMMMMNPAPA
+  MMMMMMMMMMMMMPAA
+  MMMMMMMOOEPPPPAM
+  MMMMMOOAAAAAAAPA
+  MMMMOAAMMMMMMMPA
+  MMMMOAMMMMMMMNAM
+  MMMMOAMMMMMMMMMM
+  MMMMMOOAAMMMMMMM
+  MMMMMMMOOOAMMMMM
+  MMMMMMMMMMOAMMMM
+  MMMMMMMMMMOAMMMM
+  MOAMMMMMMMOAMMMM
+  MMOOAMMOOOAMMMMM
+  MMMMOOOAAMMMMMMM
+}
+# tile 238 (unicorn horn)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMHMMMMMMMMMMMMM
+  MMMLAMMMMMMMMMMM
+  MMMLHLAMMMMMMMMM
+  MMMMHLHAAMMMMMMM
+  MMMMMLHLHAMMMMMM
+  MMMMMMHLHLAAMMMM
+  MMMMMMLLHLHHAMMM
+  MMMMMMMHHLHDAMMM
+  MMMMMMMMLHDDAMMM
+  MMMMMMMMHDDAMMMM
+  MMMMMMMMMAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 239 (candelabrum / Candelabrum of Invocation)
+{
+  MMMMMMMNMMMMMMMM
+  MMMMMMMDMMMMMMMM
+  MMMMMMMDMMMNMMMM
+  MMMNMMMDMMMDMMMM
+  MMMDMMMDMMMDMMMM
+  MMMDMMHDHMMDMMMM
+  MMHDHMMHMMHDHMMM
+  MMMHMMMHMMAHMMMM
+  MMMOHHHHHHHOMAMM
+  MMMMMMOHOAAMAMMM
+  MMMMMMMHMMAAAMMA
+  MMMMMMOHOAAAAAAM
+  MMMMMOHHHHAMMAMM
+  MMMMMMHHHAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 240 (silver bell / Bell of Opening)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMOAMMMMMMM
+  MMMMMMOAOAMMMMMM
+  MMMMMMMOAMMMMMMM
+  MMMMMMNOPAMMMMMM
+  MMMMMNOOOPAMMMMM
+  MMMMMNOOOPAMMMMM
+  MMMMMNOOOPAAMMMM
+  MMMMONOOOPOAMMMM
+  MMMONNOOOPNPAMMM
+  MMMOONNNNNOPAMMM
+  MMMMOOOOOOPAAMMM
+  MMMMMAAPPAAAMMMM
+  MMMMMMMAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 241 (tripe ration)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOOOOMMMMMMM
+  MMMMDODDDOOMMMMM
+  MMMODODOOODAMMMM
+  MMMOOOOODDDAMMMM
+  MMMMDODOOOOAMMMM
+  MMMMMODOODAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 242 (corpse)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDMDPLNMMMMM
+  MMMNOMDDLNOAMMMM
+  MMPOOADMMOONNMMM
+  MONONNMDLNNNNMMM
+  MNPANDCCCNAAAAMM
+  MMAADCCCCAADMMMM
+  MMDDDCCCDADDDDMM
+  MMDMNCDCCNMDMMMM
+  MPNNNOAADNNPNNMM
+  MONPONMDDMNONOAM
+  MMMPNNAMDMPNAAAM
+  MMMLNAAMDMNPAMMM
+  MMMMAAMMMMMAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 243 (egg)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPONOPMMMMMMM
+  MMMMONNNOMMMMMMM
+  MMMPNNNNNPMMMMMM
+  MMMONNNNNOMAAAMM
+  MMMNNNNNNOAAAAMM
+  MMMONNNNOOAAAAMM
+  MMMPONNOOPAAAMMM
+  MMMMPOOOPAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 244 (meatball)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMKKCKMMMMMMM
+  MMMMKCDJDJMMMMMM
+  MMMMCDJDJJAAAMMM
+  MMMMDCDJAJAAAMMM
+  MMMMKDDJJJAAAMMM
+  MMMMMJJAJAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 245 (meat stick)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMCDMMM
+  MMMMMMMMMMCDAAMM
+  MMMMMMMMMLDAAMMM
+  MMMMMMMDLKAAMMMM
+  MMMMMMLCKAAMMMMM
+  MMMMMLCKAAMMMMMM
+  MMMMLLKAAMMMMMMM
+  MMMDCKAAMMMMMMMM
+  MMMCKAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 246 (huge chunk of meat)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMKDKKMMMMMMM
+  MMMKKJJJJKDMMMMM
+  MMKCCKKCJJJKMMMM
+  MMKCKKCJJJJKAMMM
+  MKKKKJJJDDJJKAAM
+  MKKKJJJJJJJJKAAA
+  MKCKDJJJDJJJJAAA
+  MKKJDJJDJJAJAAAA
+  MKKKKJJDKKDJJAAA
+  MDKDJJJKKKKAJAAM
+  DKKKKAJJAJDAJJAM
+  KKKKKKKKKJJJAJAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 247 (meat ring)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOOOAMMMMMMM
+  MMMMOAAMOOAMMMMM
+  MMMMOAAMMMOAMMMM
+  MMMMMOAAMMMOAMMM
+  MMMMMOAAMMMOAMMM
+  MMMMMOAMMMMOAMMM
+  MMMMOAAAMMOAAMMM
+  MMMMMOOOOOAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 248 (kelp frond)
+{
+  MMMMFAMMMMMMMMMM
+  MMMMFFAMMMMMMMMM
+  MMMMMFFAMMMMMMMM
+  MMMMMMMFFAMMMMMM
+  MMMMMMMMFAMMMMMM
+  MMMMMMMMFFAMMMMM
+  MMMMMMMMFFAMMMMM
+  MMMMMMMMFFAMMMMM
+  MMMMMMMFFAMMMMMM
+  MMMMMMMFFAMMMMMM
+  MMMMMMFFAMMMMMMM
+  MMMMMFFFAMMMMMMM
+  MMMMMFFAMMMMMMMM
+  MMMMMFFFAMMMMMMM
+  MMMMMFFFFAMMMMMM
+  MMMMMMFFFFAMMMMM
+}
+# tile 249 (eucalyptus leaf)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMLMMMMMMMM
+  MMMMMMMLAMMMMMMM
+  MMMMMMMLHMMMMMMM
+  MMMMMMGOHAMMMMMM
+  MMMMMMGOOAMMMMMM
+  MMMMMGOOAMMMMMMM
+  MMMMMGOHAMMMMMMM
+  MMMMMOOAMMMMMMMM
+  MMMMOHAMMMMMMMMM
+  MMMMOAMMMMMMMMMM
+  MMMOAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 250 (apple)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMFFMMMMMMMMMM
+  MMMMMMFMMMMMMMMM
+  MMMMCCFFCCMMMMMM
+  MMMCLLKCDDKMMMMM
+  MMMCLDDDCDKAMMMM
+  MMMCDDDDDDKAAMMM
+  MMMDDDDDDDKAAMMM
+  MMMDDDDDDKKAAMMM
+  MMMMDDKDKKAAMMMM
+  MMMMMKAAKAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 251 (orange)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMFFFMMMMMMMMM
+  MMMMMMMFGGMMMMMM
+  MMMMMCCFCCDMMMMM
+  MMMMCGGCCCCDMMMM
+  MMMDCCCCCCCDAMMM
+  MMMCCCCCCCCDKAMM
+  MMMCCCCCCCDDKAMM
+  MMMDCCCCCDDKJAMM
+  MMMMDCCCDDKKAAMM
+  MMMMMDDDDKKAAMMM
+  MMMMMMAKKJAAMMMM
+  MMMMMMMAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 252 (pear)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMFFCCMMM
+  MMMMMMMMFGCFMMMM
+  MMMMMMMFGGGFAAMM
+  MMMMMFFGHGFAAMMM
+  MMMFGHHHGFFAAMMM
+  MMFGHHGGGFFAMMMM
+  MMFHHGGGGFFAMMMM
+  MMFHHGGGGFMAMMMM
+  MMMFGGGGFMAAMMMM
+  MMMMFFFMMAAMMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 253 (melon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMFFFFMMMMMM
+  MMMMFGGGGGFMMMMM
+  MMMFGGGGGGGFAMMM
+  MMMGGGGGGGGFAAMM
+  MMFGGGGGGGGFAAMM
+  MMFGGGGGGGGFAAMM
+  MMFGGGGGGGGAAMMM
+  MMFGGKAGGGFAAMMM
+  MMMFKAGGGFAAMMMM
+  MMMMMFFFAAAMMMMM
+  MMMMMMAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 254 (banana)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMJMMM
+  MMMMMMMMMMMMHAMM
+  MMMMMMMMMMMMHHMM
+  MMMMMMMMMMMHOHAM
+  MMMMMMMMMMMHOHAM
+  MMMMMMMMMMHOHHAM
+  MMMMMMMMMMHOHJAM
+  MMMMMMMMMHOHHAAM
+  MMMMMMMMHOHHJAMM
+  MMMMMMHHOHHJAAMM
+  MMJHOOOOHHJAAMMM
+  MMMMHHHHJAAAMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 255 (carrot)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMFMMFMM
+  MMMMMMMMMMGFGAAM
+  MMMMMMMMMMFFAMMM
+  MMMMMMMMMMGFFFMM
+  MMMMMMMCCGFAAMMM
+  MMMMMMCCCCAMMMMM
+  MMMMMMDCCCMMMMMM
+  MMMMMCCDCAMMMMMM
+  MMMMCCCCAAMMMMMM
+  MMMMDCAAAMMMMMMM
+  MMMCCAAMMMMMMMMM
+  MMCDAAMMMMMMMMMM
+  MMCAAMMMMMMMMMMM
+  MMMAMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 256 (sprig of wolfsbane)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMHHMMM
+  MMMMMMMMMMHMMHMM
+  MMMHHHFMMMFAAMMM
+  MMHMAAAFMFAMMAMM
+  MMHAAMMMFAMMMMMM
+  MMMAMMMFFAMMMMMM
+  MMMMMMFFAAMMMMMM
+  MMMMMFFAAMMMMMMM
+  MMMFFFAAMMMMMMMM
+  MMMMAAAMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 257 (clove of garlic)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOMMMMMMMMMM
+  MMMMOOOAAMMMMMMM
+  MMMMOOOOAAMMMMMM
+  MMMMHOOOOAAMMMMM
+  MMMMHHOOOOAAMMMM
+  MMMMMHHHOOOAAMMM
+  MMMMMMMHOOOAAMMM
+  MMMMMMMMAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 258 (slime mold)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMJMMMM
+  MMMMMMMMFGJFMMMM
+  MMMMMMFFGGGFMMMM
+  MMMMFGGGGGGFAMMM
+  MMMFGGGGGCGCAMMM
+  MMMGGGGGGGCCAMMM
+  MMFGGGGCGCCKAMMM
+  MMFGGCGGCCKJAMMM
+  MMMCGGCCCKJAMMMM
+  MMMMCCCKJAAAMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 259 (lump of royal jelly)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOHMMMMMMMMM
+  MMMMONHHAAAMMMMM
+  MMMONOHHHAAAMMMM
+  MMHOOOOHHHHAMMMM
+  MMMMHOOHHAAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 260 (cream pie)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMOOOOOOOOMMMM
+  MMMOONNNNOONOAMM
+  MMKNONOOONNNNJAM
+  MMMKKKKKKKKJJAAM
+  MMMMJJJJJJJJAAMM
+  MMMMMMAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 261 (candy bar)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMIAMMMMMM
+  MMMMMMMBIIAMMMMM
+  MMMMMMIBBIIAMMMM
+  MMMMMNIIBBAAMMMM
+  MMMMNNNIIAAMMMMM
+  MMMNNCNNAAMMMMMM
+  MMIINNNAAMMMMMMM
+  MIIIINAAMMMMMMMM
+  MMIIIAAMMMMMMMMM
+  MMMIAAMMMMMMMMMM
+  MMMMAMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 262 (fortune cookie)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLLMMMMMMMMM
+  MMMMLLLLLLMMMMMM
+  MMMLLLLLLLLMMMMM
+  MMMLLLKJJKAAMMMM
+  MMMLLLLLJAAMMMMM
+  MMMMLLLLAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 263 (pancake)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOOOOOOMMMMM
+  MMMMOOOOOOOOMMMM
+  MMMMOOOOKOOOOMMM
+  MMMOOKOOOOOOOAMM
+  MMOOOOOOOKOOOAMM
+  MMOOOOOOOOOOOAMM
+  MMOOKOOOOOOOOAMM
+  MMOOOOOOOKOOAAMM
+  MMMOOOKOOOOOAAMM
+  MMMMOOOOOOOAAMMM
+  MMMMMAAAAAAAMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 264 (lembas wafer)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMOOMMMMMMM
+  MMMMMMOOLOOMMMMM
+  MMMMMOOLOOLOOMMM
+  MMMMOOLOOLOOLOOM
+  MMMOOLOOLOOLOOAM
+  MMOOLOOLOOLOOAMM
+  MMMAOOLOOLOOAMMM
+  MMMMMAOOLOOAMMMM
+  MMMMMMMAOOAMMMMM
+  MMMMMMMMMAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 265 (cram ration)
+{
+  MMMMMMMMMMMMMMMM
+  MMMJKAMMMMMMMMMM
+  MMMPBAMMMMMMMMMM
+  MMMPBAMMMMMMMMMM
+  MMMPBPAMMMMMMMMM
+  MMMBBPAKKKKKAMMM
+  MMMBBPKKKKKKKAMM
+  MMMOPKKKKKKKAMMM
+  MMMOKKKKKKKJJAMM
+  MMMBPKLLOKJJJAMM
+  MMMPKLOLOLKJJAMM
+  MMMAKOLOLLKJAAMM
+  MMMMKLOLLOKAAMMM
+  MMMMKKKKKKKAMMMM
+  MMMMMAAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 266 (food ration)
+{
+  MMMJJAMMMMMMMMMM
+  MMMBPAMMMMMMMMMM
+  MMMBPAMMMMMMMMMM
+  MMBBBPAMMMMMMMMM
+  MMBBBPAKKKKKKKAM
+  MBBBBPKKKKKKKKKA
+  MBOOPKKKKKKKKKAM
+  MBOOKKKKKKKKKJJA
+  MBOOPKLLLLOKJJJA
+  MBPPKLOLLLOLKJJA
+  MMPAKOLOOOLLKJJA
+  MPPPKLOLLLOLKJJA
+  MMMAKOLOOOLLKJAA
+  MMMMKLOLLLLOKAAM
+  MMMMKKKKKKKKKAMM
+  MMMMMAAAAAAAAMMM
+}
+# tile 267 (K-ration)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMJJAMMMMMMMMMM
+  MMMBPAMMMMMMMMMM
+  MMBBBPAMMMMMMMMM
+  MMBBBPKKKKKKKAMM
+  MMOOPKKKKKKKKKAM
+  MMOOKKKKKKKKKJAM
+  MMOOPKLLLLOKJJAM
+  MMPPKLLELEOLKJAM
+  MMPAKOLEELLLKJAM
+  MMPPKLLEELOLKJAM
+  MMMAKOLELELLKJAM
+  MMMMKLLLLLLOKAAM
+  MMMMKKKKKKKKKAMM
+  MMMMMAAAAAAAAMMM
+}
+# tile 268 (C-ration)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMJJAMMMMMMMMMM
+  MMMBPAMMMMMMMMMM
+  MMBBBPAMMMMMMMMM
+  MMBBBPAMMMMMMMMM
+  MMOOPKKKKKKKKAMM
+  MMOOKKKKKKKKKJAM
+  MMOOPKLLLLOKJJAM
+  MMPPKLOEEEOLKJAM
+  MMPAKOLEOOLLKJAM
+  MMPPKLOELLOLKJAM
+  MMMAKOLEEELLKJAM
+  MMMMKLOLLLLOKAAM
+  MMMMKKKKKKKKKAMM
+  MMMMMAAAAAAAAMMM
+}
+# tile 269 (tin)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMBBBBMMMMMMM
+  MMMMBPPPPPMAMMMM
+  MMMMBPBBPMAAAMMM
+  MMMMOBPPMMAAAAMM
+  MMMMOOOPMMAAAAMM
+  MMMMOOOPMMAAAMMM
+  MMMMBOOPMMAAMMMM
+  MMMMBBPPMMAMMMMM
+  MMMMMBPPMAMMMMMM
+  MMMMMMAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 270 (ruby / gain ability)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMODDDAMMMMMMM
+  MMMMMCDAMMMMMMMM
+  MMMMCDDDAMMMMMMM
+  MMMCNCDDDAMAAMMM
+  MMMCDDDDDAAAAMMM
+  MMMCDDDDDAAMMMMM
+  MMMMCDDDAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 271 (pink / restore ability)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOIIIAMMMMMMM
+  MMMMMLIAMMMMMMMM
+  MMMMLIIIAMMMMMMM
+  MMMLNLIIIAMAAMMM
+  MMMLIIIIIAAAAMMM
+  MMMLIIIIIAAMMMMM
+  MMMMLIIIAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 272 (orange / confusion)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOCCCAMMMMMMM
+  MMMMMKCAMMMMMMMM
+  MMMMKCCCAMMMMMMM
+  MMMKNKCCCAMAAMMM
+  MMMKCCCCCAAAAMMM
+  MMMKCCCCCAAMMMMM
+  MMMMKCCCAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 273 (yellow / blindness)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOHHHAMMMMMMM
+  MMMMMOHAMMMMMMMM
+  MMMMOHHHAMMMMMMM
+  MMMONOHHHAMAAMMM
+  MMMOHHHHHAAAAMMM
+  MMMOHHHHHAAMMMMM
+  MMMMOHHHAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 274 (emerald / paralysis)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOFFFAMMMMMMM
+  MMMMMGFAMMMMMMMM
+  MMMMGFFFAMMMMMMM
+  MMMGNGFFFAMAAMMM
+  MMMGFFFFFAAAAMMM
+  MMMGFFFFFAAMMMMM
+  MMMMGFFFAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 275 (dark green / speed)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOFFMAMMMMMMM
+  MMMMMFMAMMMMMMMM
+  MMMMFMFMAMMMMMMM
+  MMMFNFMFMAMAAMMM
+  MMMFFMFMMAAAAMMM
+  MMMFMFMMMAAMMMMM
+  MMMMFMFMAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 276 (cyan / levitation)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMBBBEAMMMMMMM
+  MMMMMBEAMMMMMMMM
+  MMMMBBBEAMMMMMMM
+  MMMBNBBEEAMAAMMM
+  MMMBBBBEEAAAAMMM
+  MMMBBBBEEAAMMMMM
+  MMMMBBEEAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 277 (sky blue / hallucination)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMNBBBAMMMMMMM
+  MMMMMNBAMMMMMMMM
+  MMMMNBBBAMMMMMMM
+  MMMNBBBBBAMAAMMM
+  MMMNBBBBBAAAAMMM
+  MMMNBBBBBAAMMMMM
+  MMMMNBBBAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 278 (brilliant blue / invisibility)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOEEEAMMMMMMM
+  MMMMMBEAMMMMMMMM
+  MMMMBEEEAMMMMMMM
+  MMMBNBEEEAMAAMMM
+  MMMBEEEEEAAAAMMM
+  MMMBEEEEEAAMMMMM
+  MMMMBEEEAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 279 (magenta / see invisible)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMDIIDAMMMMMMM
+  MMMMMDIAMMMMMMMM
+  MMMMDIIDAMMMMMMM
+  MMMDLDIIDAMAAMMM
+  MMMDIIIIDAAAAMMM
+  MMMDDIIDDAAMMMMM
+  MMMMDDDDAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 280 (purple-red / healing)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOEDEAMMMMMMM
+  MMMMMDEAMMMMMMMM
+  MMMMDEDEAMMMMMMM
+  MMMDNDEDEAMAAMMM
+  MMMDDEDEEAAAAMMM
+  MMMDEDEDEAAMMMMM
+  MMMMDEDEAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 281 (puce / extra healing)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOKKJAMMMMMMM
+  MMMMMIKAMMMMMMMM
+  MMMMIKDJAMMMMMMM
+  MMMINDKJJAMAAMMM
+  MMMIKKDJJAAAAMMM
+  MMMDKDKJJAAMMMMM
+  MMMMDKKJAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 282 (milky / gain level)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOOOOAMMMMMMM
+  MMMMMNOAMMMMMMMM
+  MMMMNOOOAMMMMMMM
+  MMMNOOOOOAMAAMMM
+  MMMNOOOOOAAAAMMM
+  MMMNOOOOOAAMMMMM
+  MMMMNOOOAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 283 (swirly / enlightenment)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMNOOOAMMMMMMM
+  MMMMMNOAMMMMMMMM
+  MMMMNOIIAMMMMMMM
+  MMMNOIIOOAMAAMMM
+  MMMIIOOOIAAAAMMM
+  MMMNOOIIOAAMMMMM
+  MMMMIIOOAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 284 (bubbly / monster detection)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOFFFAMMMMMMM
+  MMMMMNFAMMMMMMMM
+  MMMMFFFNAMMMMMMM
+  MMMNFNFFFAMAAMMM
+  MMMFFFFFNAAAAMMM
+  MMMFNFFFFAAMMMMM
+  MMMMFFNFAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 285 (smoky / object detection)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOPPPAMMMMMMM
+  MMMMMOPAMMMMMMMM
+  MMMMOPPPAMMMMMMM
+  MMMONPPPPAMAAMMM
+  MMMOPPPPPAAAAMMM
+  MMMOPPPPPAAMMMMM
+  MMMMOPPPAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 286 (cloudy / gain energy)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOEEEAMMMMMMM
+  MMMMMBPAMMMMMMMM
+  MMMMBEEPAMMMMMMM
+  MMMBEPPPEAMAAMMM
+  MMMBEEPEEAAAAMMM
+  MMMBEPPPPAAMMMMM
+  MMMMBPEEAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 287 (effervescent / sleeping)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOEEOAMMMMMMM
+  MMMMMNNAMMMMMMMM
+  MMMMOFNNAMMMMMMM
+  MMMBFNNFOAMAAMMM
+  MMMOFNFFOAAAAMMM
+  MMMBFFFNEAAMMMMM
+  MMMMBNFFAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 288 (black / full healing)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJMMMMMMMMM
+  MMMMMKJMMMMMMMMM
+  MMMMAAAAMMMMMMMM
+  MMMMMAAMMMMMMMMM
+  MMMMAAAAMMMMMMMM
+  MMMANAAAAMPPPMMM
+  MMMAAAAAAPPPPMMM
+  MMMAAAAAAPPMMMMM
+  MMMAAAAAAPMMMMMM
+  MMMMAAAAPMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 289 (golden / polymorph)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMLHHHAMMMMMMM
+  MMMMMLHAMMMMMMMM
+  MMMMLHHCAMMMMMMM
+  MMMLNLHHCAMAAMMM
+  MMMLHHHHCAAAAMMM
+  MMMLHHHCCAAMMMMM
+  MMMMLCCCAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 290 (brown / booze)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMGFAMMMMMMMM
+  MMMMMFFAMMMMMMMM
+  MMMMCJJJAMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMKJJJAMMMMMMM
+  MMMKCKJJJAMAAMMM
+  MMMKJJJJJAAAAMMM
+  MMMKJJJJJAAMMMMM
+  MMMMKJJJAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 291 (fizzy / sickness)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMOEEOAMMMMMMM
+  MMMMMOOAMMMMMMMM
+  MMMMOEOOAMMMMMMM
+  MMMBEOOEOAMAAMMM
+  MMMOEOEEOAAAAMMM
+  MMMBEEEOEAAMMMMM
+  MMMMBOEEAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 292 (dark / fruit juice)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJMMMMMMMMM
+  MMMMMKJMMMMMMMMM
+  MMMMAAAAMMMMMMMM
+  MMMMMAAMMMMMMMMM
+  MMMMAJJAMMMMMMMM
+  MMMANJJJAMPPPMMM
+  MMMAJJAAAPPPPMMM
+  MMMAJAAAAPPMMMMM
+  MMMAAAAAAPMMMMMM
+  MMMMAAAAPMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 293 (white / acid)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMNNNNAMMMMMMM
+  MMMMMNNAMMMMMMMM
+  MMMMNNNNAMMMMMMM
+  MMMNPNNNNAMAAMMM
+  MMMNNNNNNAAAAMMM
+  MMMNNNNNNAAMMMMM
+  MMMMNNNNAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 294 (murky / oil)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJMMMMMMMMM
+  MMMMMKJMMMMMMMMM
+  MMMMAAAAMMMMMMMM
+  MMMMMAAMMMMMMMMM
+  MMMMAFJAMMMMMMMM
+  MMMANJFJAMPPPMMM
+  MMMAJFAFAPPPPMMM
+  MMMAFAFAAPPMMMMM
+  MMMAAFAFAPMMMMMM
+  MMMMAAAAPMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 295 (clear / water)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMLJAMMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMBPPPAMMMMMMM
+  MMMMMBPAMMMMMMMM
+  MMMMBPPPAMMMMMMM
+  MMMBPPPPPAMAAMMM
+  MMMBEEEEEAAAAMMM
+  MMMBEEEEEAAMMMMM
+  MMMMBEEEAAMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 296 (ZELGO MER / enchant armor)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 297 (JUYED AWK YACC / destroy armor)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 298 (NR 9 / confuse monster)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 299 (XIXAXA XOXAXA XUXAXA / scare monster)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 300 (PRATYAVAYAH / remove curse)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 301 (DAIYEN FOOELS / enchant weapon)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 302 (LEP GEX VEN ZEA / create monster)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 303 (PRIRUTSENIE / taming)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 304 (ELBIB YLOH / genocide)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 305 (VERR YED HORRE / light)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 306 (VENZAR BORGAVVE / teleportation)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 307 (THARR / gold detection)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 308 (YUM YUM / food detection)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 309 (KERNOD WEL / identify)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 310 (ELAM EBOW / magic mapping)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 311 (DUAM XNAHT / amnesia)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 312 (ANDOVA BEGARIN / fire)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 313 (KIRJE / earth)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 314 (VE FORBRYDERNE / punishment)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 315 (HACKEM MUCHE / charging)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 316 (VELOX NEB / stinking cloud)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 317 (FOOBIE BLETCH)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 318 (TEMOV)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 319 (GARVEN DEH)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 320 (READ ME)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMNJNJAOMAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLJLJLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 321 (stamped / mail)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MOOOOOOOOOEEOMMM
+  MOOOOOOOOOEEOMMM
+  MOOOOOOOOOOOOAMM
+  MOOOJLJJLJOOOAMM
+  MOOOOOOOOOOOOAMM
+  MOOOJJLJOOOOOAMM
+  MOOOOOOOOOOOOAMM
+  MMMAAAAAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 322 (unlabeled / blank paper)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMMLLLLLLPAMMM
+  MMMMPOOOOOPKAMMM
+  MMMDOOOOOOKDJMMM
+  MMMMPOOOOOPJAAMM
+  MMMMMAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 323 (parchment / dig)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJKKJMMMMMMMM
+  MMMMKKKKKJMMMMMM
+  MMMJKKHHHKKKJMMM
+  MMMKKHHKKHKKCMMM
+  MMJKKKHHKKKKOAMM
+  MMKKHKKHHKKCOAAM
+  MJKKKHHHKKKOJAMM
+  MKKKKKKKKKCOAAMM
+  MJOOKKKKKKOJAMMM
+  MMJJOOOKKCOAAMMM
+  MMMMJJJOOOJAMMMM
+  MMMMMMMJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 324 (vellum / magic missile)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJKKJMMMMMMMM
+  MMMMKKKKKJMMMMMM
+  MMMJKKHHHKKKJMMM
+  MMMKKHHKKHKKCMMM
+  MMJKKKHHKKKKOAMM
+  MMKKHKKHHKKCOAAM
+  MJKKKHHHKKKOJAMM
+  MKKKKKKKKKCOAAMM
+  MJOOKKKKKKOJAMMM
+  MMJJOOOKKCOAAMMM
+  MMMMJJJOOOJAMMMM
+  MMMMMMMJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 325 (ragged / fireball)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJKKJMMMMMMMM
+  MMMMKKKKKJMMMMMM
+  MMMJKKHHHKKKJMMM
+  MMMKKHHKKHKKCMMM
+  MMJKKKHHKKKKOAMM
+  MMKKHKKHHKKCOAAM
+  MJKKKHHHKKKJJAMM
+  MKKKKKKKKKCJAAMM
+  MJOOKKKKKKOJAMMM
+  MMJJOOOKKCOAAMMM
+  MMMMJOOOOOJAMMMM
+  MMMMMMOOJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 326 (dog eared / cone of cold)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJKKJMMMMMMMM
+  MMMMKKKKKJMMMMMM
+  MMMJKKHHHKOMMMMM
+  MMMKKHHKKKJOCMMM
+  MMJKKKHHKKJOOAMM
+  MMKKHKKHHKKCOAAM
+  MJKKKHHHKKKOJAMM
+  MKKKKKKKKKCOAAMM
+  MJOOKKKKKKOJAMMM
+  MMJJOOOKKCOAAMMM
+  MMMMJJJOOOJAMMMM
+  MMMMMMMJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 327 (mottled / sleep)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJKKJMMMMMMMM
+  MMMMKKKKKJMMMMMM
+  MMMJKKHHHKKKJMMM
+  MMMKKHHKKHKKCMMM
+  MMJKKKHHKKKKOAMM
+  MMKKHKKHHKKCOAAM
+  MJKKKHHHKKKOJAMM
+  MKKKKKKKKKCLAAMM
+  MJOOKKKKKKOJAMMM
+  MMJJLLOKKCOAAMMM
+  MMMMJJJOLLJAMMMM
+  MMMMMMMJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 328 (stained / finger of death)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJKKJMMMMMMMM
+  MMMMKKKKKJMMMMMM
+  MMMJKKHHCJJJJMMM
+  MMMKKHHKKCJJCMMM
+  MMJJJJCHKJJJLAMM
+  MMKJCJJHHKKCLAAM
+  MJKJJCCCKKKOJAMM
+  MKKKJJJJKKCOAAMM
+  MJOOKJJKKKOJAMMM
+  MMJJOLOKKCOAAMMM
+  MMMMJJJOOOJAMMMM
+  MMMMMMMJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 329 (cloth / light)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMEPPPMMMMMMMM
+  MMMMPPPEPPMMMMMM
+  MMMEPPHHHPEPPMMM
+  MMMPPHHPPHPPEMMM
+  MMEPPPHHPPPPOAMM
+  MMPPHPPHHEPEOAAM
+  MEPPPHHHPPPOPAMM
+  MPPPEPPPPPEOAAMM
+  MPOOPPPEPPOPAMMM
+  MMPPOOOPPEOAAMMM
+  MMMMPPPOOOPAMMMM
+  MMMMMMMPPPAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 330 (leather / detect monsters)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJKKJMMMMMMMM
+  MMMMKKKKKJMMMMMM
+  MMMJKKHHHKKKJMMM
+  MMMKKHHKKHKKCMMM
+  MMJKKKHHKKKKOAMM
+  MMKKHKKHHKKCOAAM
+  MJKKKHHHKKKOJAMM
+  MKKKKKKKKKCOAAMM
+  MJOOKKKKKKOJAMMM
+  MMJJOOOKKCOAAMMM
+  MMMMJJJOOOJAMMMM
+  MMMMMMMJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 331 (white / healing)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPNNPMMMMMMMM
+  MMMMNNNNNPMMMMMM
+  MMMPNNAAANNNPMMM
+  MMMNNAANNANNNMMM
+  MMPNNNAANNNNOAMM
+  MMNNANNAANNNOAAM
+  MPNNNAAANNNONAMM
+  MNNNNNNNNNNOAAMM
+  MNOONNNNNNONAMMM
+  MMPNOOONNNOAAMMM
+  MMMMPNNOOONAMMMM
+  MMMMMMMPNNAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 332 (pink / knock)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMDIIDMMMMMMMM
+  MMMMIIIIIDMMMMMM
+  MMMDIIHHHIIIDMMM
+  MMMIIHHIIHIICMMM
+  MMDIIIHHIIIIOAMM
+  MMIIHIIHHIICOAAM
+  MDIIIHHHIIIOIAMM
+  MIIIIIIIIICOAAMM
+  MIOOIIIIIIOIAMMM
+  MMIIOOOIICOAAMMM
+  MMMMIIIOOOIAMMMM
+  MMMMMMMIIIAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 333 (red / force bolt)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKDDKMMMMMMMM
+  MMMMDDDDDKMMMMMM
+  MMMKDDHHHDDDKMMM
+  MMMDDHHDDHDDCMMM
+  MMKDDDHHDDDDOAMM
+  MMDDHDDHHDDCOAAM
+  MKDDDHHHDDDODAMM
+  MDDDDDDDDDCOAAMM
+  MDOODDDDDDODAMMM
+  MMDDOOODDCOAAMMM
+  MMMMDDDOOODAMMMM
+  MMMMMMMDDDAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 334 (orange / confuse monster)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKCCKMMMMMMMM
+  MMMMCCCCCKMMMMMM
+  MMMKCCAAACCCKMMM
+  MMMCCAACCACCLMMM
+  MMKCCCAACCCCOAMM
+  MMCCACCAACCLOAAM
+  MKCCCAAACCCOCAMM
+  MCCCCCCCCCLOAAMM
+  MCOOCCCCCCOCAMMM
+  MMCCOOOCCLOAAMMM
+  MMMMCCCOOOCAMMMM
+  MMMMMMMCCCAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 335 (yellow / cure blindness)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMOHHOMMMMMMMM
+  MMMMHHHHHOMMMMMM
+  MMMOHHAAAHHHOMMM
+  MMMHHAAHHAHHLMMM
+  MMOHHHAAHHHHOAMM
+  MMHHAHHAAHHLOAAM
+  MOHHHAAAHHHOHAMM
+  MHHHHHHHHHLOAAMM
+  MHOOHHHHHHOHAMMM
+  MMHHOOOHHLOAAMMM
+  MMMMHHHOOOHAMMMM
+  MMMMMMMHHHAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 336 (velvet / drain life)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMIIIIMMMMMMMM
+  MMMMIEEEEEMMMMMM
+  MMMIEENNNEEEEMMM
+  MMMIENNEENEEBMMM
+  MMIEEENNEEEIOAMM
+  MMEENEENNEIBOAAM
+  MIEEENNNEEIOEAMM
+  MEEEEEEEEIBOAAMM
+  MEOOEEEEIIOEAMMM
+  MMEEOOOIIBOAAMMM
+  MMMMEEEOOOEAMMMM
+  MMMMMMMEEEAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 337 (light green / slow monster)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMFGGFMMMMMMMM
+  MMMMGGGGGFMMMMMM
+  MMMFGGMMMGGGFMMM
+  MMMGGMMGGMGGHMMM
+  MMFGGGMMGGGGOAMM
+  MMGGMGGMMGGHOAAM
+  MFGGGMMMGGGOGAMM
+  MGGGGGGGGGHOAAMM
+  MGOOGGGGGGOGAMMM
+  MMGGOOOGGHOAAMMM
+  MMMMGGGOOOGAMMMM
+  MMMMMMMGGGAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 338 (dark green / wizard lock)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMFFFFMMMMMMMM
+  MMMMFFFFFFMMMMMM
+  MMMFFFHHHFFFFMMM
+  MMMFFHHFFHFFGMMM
+  MMFFFFHHFFFFOAMM
+  MMFFHFFHHFFGOAAM
+  MFFFFHHHFFFOFAMM
+  MFFFFFFFFFGOAAMM
+  MFOOFFFFFFOFAMMM
+  MMFFOOOFFGOAAMMM
+  MMMMFFFOOOFAMMMM
+  MMMMMMMFFFAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 339 (turquoise / create monster)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMFBBFMMMMMMMM
+  MMMMBBBBBFMMMMMM
+  MMMFBBGGGBBBFMMM
+  MMMBBGGBBGBBBMMM
+  MMFBBBGGBBBBOAMM
+  MMBBGBBGGBBBOAAM
+  MFBBBGGGBBBOBAMM
+  MBBBBBBBBBBOAAMM
+  MFOOBBBBBBOBAMMM
+  MMBBOOOBBBOAAMMM
+  MMMMFBBOOOBAMMMM
+  MMMMMMMFBBAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 340 (cyan / detect food)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMBBBBMMMMMMMM
+  MMMMBBBBBBMMMMMM
+  MMMBBBGGGBBBBMMM
+  MMMBBGGBBGBBBMMM
+  MMBBBBGGBBBBOAMM
+  MMBBGBBGGBBBOAAM
+  MBBBBGGGBBBOBAMM
+  MBBBBBBBBBBOAAMM
+  MBOOBBBBBBOBAMMM
+  MMBBOOOBBBOAAMMM
+  MMMMBBBOOOBAMMMM
+  MMMMMMMBBBAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 341 (light blue / cause fear)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMEBBEMMMMMMMM
+  MMMMBBBBBEMMMMMM
+  MMMEBBAAABBBEMMM
+  MMMBBAABBABBBMMM
+  MMEBBBAABBBBOAMM
+  MMBBABBAABBBOAAM
+  MEBBBAAABBBOBAMM
+  MBBBBBBBBBBOAAMM
+  MBOOBBBBBBOBAMMM
+  MMBBOOOBBBOAAMMM
+  MMMMBBBOOOBAMMMM
+  MMMMMMMBBBAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 342 (dark blue / clairvoyance)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMEEEEMMMMMMMM
+  MMMMEEEEEEMMMMMM
+  MMMEEEHHHEEEEMMM
+  MMMEEHHEEHEEBMMM
+  MMEEEEHHEEEEOAMM
+  MMEEHEEHHEEBOAAM
+  MEEEEHHHEEEOEAMM
+  MEEEEEEEEEBOAAMM
+  MEOOEEEEEEOEAMMM
+  MMEEOOOEEBOAAMMM
+  MMMMEEEOOOEAMMMM
+  MMMMMMMEEEAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 343 (indigo / cure sickness)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMEEEEMMMMMMMM
+  MMMMEEEEEEMMMMMM
+  MMMEEEIIIEEEEMMM
+  MMMEEIIEEIEEBMMM
+  MMEEEEIIEEEEOAMM
+  MMEEIEEIIEEBOAAM
+  MEEEEIIIEEEOEAMM
+  MEEEEEEEEEBOAAMM
+  MEOOEEEEEEOEAMMM
+  MMEEOOOEEBOAAMMM
+  MMMMEEEOOOEAMMMM
+  MMMMMMMEEEAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 344 (magenta / charm monster)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKIIKMMMMMMMM
+  MMMMIIIIIKMMMMMM
+  MMMKIIEEEIIIKMMM
+  MMMIIEEIIEIICMMM
+  MMKIIIEEIIIIOAMM
+  MMIIEIIEEIICOAAM
+  MKIIIEEEIIIOIAMM
+  MIIIIIIIIICOAAMM
+  MIOOIIIIIIOIAMMM
+  MMIIOOOIICOAAMMM
+  MMMMIIIOOOIAMMMM
+  MMMMMMMIIIAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 345 (purple / haste self)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMEDEDMMMMMMMM
+  MMMMDEDEDEMMMMMM
+  MMMDEDHHHDEDMMMM
+  MMMEDHHEDHDECMMM
+  MMEDEDHHEDEDOAMM
+  MMDEHEDHHEDCOAAM
+  MDEDEHHHEDEOIAMM
+  MEDEDEDEDECOAAMM
+  MDOOEDEDEDOIAMMM
+  MMIIOOOEDCOAAMMM
+  MMMMIIIOOOIAMMMM
+  MMMMMMMIIIAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 346 (violet / detect unseen)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJBIJMMMMMMMM
+  MMMMBIBIBJMMMMMM
+  MMMJIBAAABIBJMMM
+  MMMIBAAIBABICMMM
+  MMJBIBAAIBIBOAMM
+  MMBIAIBAAIBCOAAM
+  MJIBIAAAIBIOIAMM
+  MIBIBIBIBICOAAMM
+  MIOOIBIBIBOIAMMM
+  MMIIOOOIBCOAAMMM
+  MMMMIIIOOOIAMMMM
+  MMMMMMMIIIAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 347 (tan / levitation)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJCKJMMMMMMMM
+  MMMMCKCKCJMMMMMM
+  MMMJKCHHHCKCJMMM
+  MMMKCHHKCHCKCMMM
+  MMJCKCHHKCKCOAMM
+  MMCKHKCHHKCCOAAM
+  MJKCKHHHKCKOKAMM
+  MKCKCKCKCKCOAAMM
+  MJOOKCKCKCOKAMMM
+  MMKKOOOKCCOAAMMM
+  MMMMKKKOOOKAMMMM
+  MMMMMMMKKKAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 348 (plaid / extra healing)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJEEJMMMMMMMM
+  MMMMDEEDDJMMMMMM
+  MMMJDFHHHFFDJMMM
+  MMMDDHHDDHFDCMMM
+  MMJDDEHHDEEDOAMM
+  MMEDHEEHHEECOAAM
+  MJFDDHHHDFFOEAMM
+  MFFDDFFDDFCOAAMM
+  MJOODEEDDEODAMMM
+  MMEDOOODDCOAAMMM
+  MMMMEFDOOOFAMMMM
+  MMMMMMMEFDAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 349 (light brown / restore ability)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJKKJMMMMMMMM
+  MMMMKKKKKJMMMMMM
+  MMMJKKHHHKKKJMMM
+  MMMKKHHKKHKKCMMM
+  MMJKKKHHKKKKOAMM
+  MMKKHKKHHKKCOAAM
+  MJKKKHHHKKKOJAMM
+  MKKKKKKKKKCOAAMM
+  MJOOKKKKKKOJAMMM
+  MMJJOOOKKCOAAMMM
+  MMMMJJJOOOJAMMMM
+  MMMMMMMJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 350 (dark brown / invisibility)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJJJJMMMMMMMM
+  MMMMJJJJJJMMMMMM
+  MMMJJJHHHJJJJMMM
+  MMMJJHHJJHJJKMMM
+  MMJJJJHHJJJJOAMM
+  MMJJHJJHHJJKOAAM
+  MJJJJHHHJJJOJAMM
+  MJJJJJJJJJKOAAMM
+  MJOOJJJJJJOJAMMM
+  MMJJOOOJJKOAAMMM
+  MMMMJJJOOOJAMMMM
+  MMMMMMMJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 351 (gray / detect treasure)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPPPPMMMMMMMM
+  MMMMPPPPPPMMMMMM
+  MMMPPPAAAPPPPMMM
+  MMMPPAAPPAPPBMMM
+  MMPPPPAAPPPPOAMM
+  MMPPAPPAAPPBOAAM
+  MPPPPAAAPPPOPAMM
+  MPPPPPPPPPBOAAMM
+  MPOOPPPPPPOPAMMM
+  MMPPOOOPPBOAAMMM
+  MMMMPPPOOOPAMMMM
+  MMMMMMMPPPAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 352 (wrinkled / remove curse)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJKKJMMMMMMMM
+  MMMMKKKKKMMMMMMM
+  MMMMKKAAAKKKJMMM
+  MMMKKAAKKAKKKMMM
+  MMJKKKAAKKKKOAMM
+  MMKKAKKAAKKKOAAM
+  MJKKKAAAKKKOKAMM
+  MKKKKKKKKKLOAAMM
+  MKOOLKKKKKOKAMMK
+  MMJKOOKKKKOAAMMM
+  MMMMJKLOOOKAMMMM
+  MMMMMMJJKKAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 353 (dusty / magic mapping)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMKMMMMMMMKAMMMM
+  MMKAJKKJMMMMMMMM
+  MMMMKKKKKJMMKMMM
+  MKAJKKHHHKKKJMKA
+  MMMKKHHKKHKKCMMM
+  MMJKAKHHKKAKOAMM
+  MMKKHKKHHKKCOAAM
+  MJKKKHHHKKKOJAMM
+  MKKKKKKKKKCOAAMM
+  AJOOKKKKAKOJAMMM
+  MMJJOOOKKCOAAMMM
+  MMMMJJJOOOJAMMMM
+  MKAKAMMJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 354 (bronze / identify)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKCCKMMMMMMMM
+  MMMMCCCCCKMMMMMM
+  MMMKCCHHHCCCKMMM
+  MMMCCHHCCHCCCMMM
+  MMKCCCHHCCCCOAMM
+  MMCCHCCHHCCCOAAM
+  MKCCCHHHCCCOCAMM
+  MCCCCCCCCCCOAAMM
+  MKOOCCCCCCOCAMMM
+  MMCCOOOCCCOAAMMM
+  MMMMCCCOOOCAMMMM
+  MMMMMMMCCCAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 355 (copper / turn undead)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJKKJMMMMMMMM
+  MMMMKCKCKJMMMMMM
+  MMMJCKHHHKCKJMMM
+  MMMCKHHCKHKCCMMM
+  MMJKCKHHCKCKOAMM
+  MMKCHCKHHCKCOAAM
+  MJCKCHHHCKCOJAMM
+  MCKCKCKCKCCOAAMM
+  MJOOCKCKCKOJAMMM
+  MMCJOOOCKCOAAMMM
+  MMMMJCJOOOJAMMMM
+  MMMMMMMJCJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 356 (silver / polymorph)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPPPPMMMMMMMM
+  MMMMPPPPPPMMMMMM
+  MMMPPPNNNPPPPMMM
+  MMMPPNNPPNPPBMMM
+  MMPPPPNNPPPPOAMM
+  MMPPNPPNNPPBOAAM
+  MPPPPNNNPPPOPAMM
+  MPPPPPPPPPBOAAMM
+  MPOOPPPPPPOPAMMM
+  MMPPOOOPPBOAAMMM
+  MMMMPPPOOOPAMMMM
+  MMMMMMMPPPAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 357 (gold / teleport away)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMLHHLMMMMMMMM
+  MMMMHHHHHLMMMMMM
+  MMMLHHCCCHHHLMMM
+  MMMHHCCHHCHHNMMM
+  MMLHHHCCHHHHOAMM
+  MMHHCHHCCHHNOAAM
+  MLHHHCCCHHHOHAMM
+  MHHHHHHHHHNOAAMM
+  MLOOHHHHHHOHAMMM
+  MMHHOOOHHNOAAMMM
+  MMMMHHHOOOHAMMMM
+  MMMMMMMHHHAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 358 (glittering / create familiar)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMNMMMMMMMMM
+  MMMNPPPPMMNMMMMM
+  MMMMPPPPPPMMMNMM
+  MMMPPPHHHPPPPMMM
+  MMNPPHHPPHPPBMMM
+  MMPPPPHHPPPPONMM
+  MNPPHPPHHPPBOAAM
+  MPPPPHHHPPPOPAMM
+  NPPPPPPPPPBONAMM
+  MPOONPPPPPOPAMMM
+  MMPPOONPPBOAAMMM
+  MMMNMPPOOOPAMMMM
+  MMMMMMMPPPANMMMM
+  MMMMMMMNMMMMMMMM
+}
+# tile 359 (shining / cancellation)
+{
+  MMMMNMMMMMMMMMMM
+  MMMMMMMNMMMMMMMM
+  MMNMMMMMMMMMMMMM
+  MMMMPNPPMMMMMMMM
+  MMMMPNNNPPMMMMMM
+  MMMPNNAAAPPPPMMM
+  MMMPNAAPPAPPBMMM
+  MMPNNPAAPPPPOAMM
+  MMPNAPPAAPPBOAAM
+  MPNPPAAAPPPOPAMM
+  MPPPPPPPPPBOAAMM
+  MPOOPPPPPPOPAMMM
+  MMPPOOOPPBOAAMMM
+  MMMMPPPOOOPAMMMM
+  MMMMMMMPPPAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 360 (dull / protection)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJKKJMMMMMMMM
+  MMMMKKKKKJMMMMMM
+  MMMJKKCCCKKKJMMM
+  MMMKKCCKKCKKJMMM
+  MMJKKKCCKKKKPAMM
+  MMKKCKKCCKKJPAAM
+  MJKKKCCCKKKPJAMM
+  MKKKKKKKKKJPAAMM
+  MJPPKKKKKKPJAMMM
+  MMJJPPPKKJPAAMMM
+  MMMMJJJPPPJAMMMM
+  MMMMMMMJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 361 (thin / jumping)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMJKJMMMMMMMM
+  MMMMJKKKKKJMMMMM
+  MMMMKKHHHKKKKMMM
+  MMMJKHHKKHKKOAMM
+  MMMKKKHHKKKKOAAM
+  MMJKHKKHHKKCJAMM
+  MMKKKHHHKKKOAAMM
+  MJOCKKKKKKCJAMMM
+  MMJJOOCKKKOAAMMM
+  MMMMJJJOCOJAMMMM
+  MMMMMMMJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 362 (thick / stone to flesh)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJKKJMMMMMMMM
+  MMMMKKKKKJMMMMMM
+  MMMJKKHHHKKKJMMM
+  MMMKKHHKKHKKCMMM
+  MMJKKKHHKKKKOAMM
+  MMKKHKKHHKKCOAAM
+  MJKKKHHHKKKOLAMM
+  MKKKKKKKKKCOJAMM
+  MJOOKKKKKKOLAMMM
+  MJLLOOOKKCOJAMMM
+  MMJJLLLOOOLAAMMM
+  MMMMJJJLLLJAMMMM
+  MMMMMMMJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 363 (plain / blank paper)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMJKKJMMMMMMMM
+  MMMMKKKKKJMMMMMM
+  MMMJKKKKKKKKJMMM
+  MMMKKKKKKKKKCMMM
+  MMJKKKKKKKKKOAMM
+  MMKKKKKKKKKCOAAM
+  MJKKKKKKKKKOJAMM
+  MKKKKKKKKKCOAAMM
+  MJOOKKKKKKOJAMMM
+  MMJJOOOKKCOAAMMM
+  MMMMJJJOOOJAMMMM
+  MMMMMMMJJJAAMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 364 (papyrus / Book of the Dead)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMAAAAMMMMMMMM
+  MMMMAAAAAAMMMMMM
+  MMMAAAOOOAAAAMMM
+  MMMAAOAOOOAAAMMM
+  MMAAAAOOAOAAOMMM
+  MMAAAOAOOAAAOMMM
+  MAAAAOOOAAAOAMMM
+  MAAAAAAAAAAOMMMM
+  MAOOAAAAAAOAMMMM
+  MMAAOOOAAAOMMMMM
+  MMMMAAAOOOAMMMMM
+  MMMMMMMAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 365 (glass / light)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMNMMM
+  MMMMMMMMMMMNBMMM
+  MMMMMMMMMMNBAAMM
+  MMMMMMMMMNBAAMMM
+  MMMMMMMMNBAAMMMM
+  MMMMMMMNBAAMMMMM
+  MMMMMMNBAAMMMMMM
+  MMMMMNBAAMMMMMMM
+  MMMMNBAAMMMMMMMM
+  MMMNBAAMMMMMMMMM
+  MMMBAFMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 366 (balsa / secret door detection)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMOKMMM
+  MMMMMMMMMMOKAAMM
+  MMMMMMMMMLKAAMMM
+  MMMMMMMMLKAAMMMM
+  MMMMMMMLKAAMMMMM
+  MMMMMMLKAAMMMMMM
+  MMMMMLKAAMMMMMMM
+  MMMMOKAAMMMMMMMM
+  MMMOKAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 367 (crystal / enlightenment)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNMMMM
+  MMMMMMMMMMNBMMMM
+  MMMMMMMMMNBAMMMM
+  MMMMMMMMNBAMMMMM
+  MMMMMMMNBAMMMMMM
+  MMMMMMNBAMMMMMMM
+  MMMMMNBAMMMMMMMM
+  MMMMNBAMMMMMMMMM
+  MMMMBAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 368 (maple / create monster)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNOMMM
+  MMMMMMMMMMKJAAMM
+  MMMMMMMMMKJAAMMM
+  MMMMMMMMKJAAMMMM
+  MMMMMMMKJAAMMMMM
+  MMMMMMKJAAMMMMMM
+  MMMMMKJAAMMMMMMM
+  MMMMKJAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 369 (pine / wishing)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNOMMM
+  MMMMMMMMMMLLAAMM
+  MMMMMMMMMLLAAMMM
+  MMMMMMMMLLAAMMMM
+  MMMMMMMLLAAMMMMM
+  MMMMMMLLAAMMMMMM
+  MMMMMLLAAMMMMMMM
+  MMMMLLAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 370 (oak / nothing)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNMMMM
+  MMMMMMMMMMNNOMMM
+  MMMMMMMMMJKOAAMM
+  MMMMMMMMJJJAAMMM
+  MMMMMMMJJKAAMMMM
+  MMMMMMJKJAAMMMMM
+  MMMMMJJJAAMMMMMM
+  MMMMJJKAAMMMMMMM
+  MMMOKJAAMMMMMMMM
+  MMNNOAAMMMMMMMMM
+  MMMNAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 371 (ebony / striking)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNOMMM
+  MMMMMMMMMMAJAAMM
+  MMMMMMMMMAJAAMMM
+  MMMMMMMMAJAAMMMM
+  MMMMMMMAJAAMMMMM
+  MMMMMMAJAAMMMMMM
+  MMMMMAJAAMMMMMMM
+  MMMMAJAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 372 (marble / make invisible)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNOMMM
+  MMMMMMMMMMIOAAMM
+  MMMMMMMMMNIAAMMM
+  MMMMMMMMNNAAMMMM
+  MMMMMMMIIAAMMMMM
+  MMMMMMNNAAMMMMMM
+  MMMMMINAAMMMMMMM
+  MMMMNIAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 373 (tin / slow monster)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNOMMM
+  MMMMMMMMMMPPAAMM
+  MMMMMMMMMPPAAMMM
+  MMMMMMMMPPAAMMMM
+  MMMMMMMPPAAMMMMM
+  MMMMMMPPAAMMMMMM
+  MMMMMPPAAMMMMMMM
+  MMMMPPAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 374 (brass / speed monster)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNOMMM
+  MMMMMMMMMMHCAAMM
+  MMMMMMMMMHCAAMMM
+  MMMMMMMMHCAAMMMM
+  MMMMMMMHCAAMMMMM
+  MMMMMMHCAAMMMMMM
+  MMMMMHCAAMMMMMMM
+  MMMMHCAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 375 (copper / undead turning)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNOMMM
+  MMMMMMMMMMCCAAMM
+  MMMMMMMMMCCAAMMM
+  MMMMMMMMCCAAMMMM
+  MMMMMMMCCAAMMMMM
+  MMMMMMCCAAMMMMMM
+  MMMMMCCAAMMMMMMM
+  MMMMCCAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 376 (silver / polymorph)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNOMMM
+  MMMMMMMMMMNPAAMM
+  MMMMMMMMMNPAAMMM
+  MMMMMMMMNPAAMMMM
+  MMMMMMMNPAAMMMMM
+  MMMMMMNPAAMMMMMM
+  MMMMMNPAAMMMMMMM
+  MMMMNPAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 377 (platinum / cancellation)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNOMMM
+  MMMMMMMMMMNOAAMM
+  MMMMMMMMMNBAAMMM
+  MMMMMMMMNBAAMMMM
+  MMMMMMMNBAAMMMMM
+  MMMMMMNBAAMMMMMM
+  MMMMMNBAAMMMMMMM
+  MMMMNOAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 378 (iridium / teleportation)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNOMMM
+  MMMMMMMMMMNOAAMM
+  MMMMMMMMMPIAAMMM
+  MMMMMMMMPIAAMMMM
+  MMMMMMMPIAAMMMMM
+  MMMMMMPIAAMMMMMM
+  MMMMMPIAAMMMMMMM
+  MMMMNIAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 379 (zinc / opening)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNOMMM
+  MMMMMMMMMMLPAAMM
+  MMMMMMMMMLPAAMMM
+  MMMMMMMMLPAAMMMM
+  MMMMMMMLPAAMMMMM
+  MMMMMMLPAAMMMMMM
+  MMMMMLPAAMMMMMMM
+  MMMMLPAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 380 (aluminum / locking)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNOMMM
+  MMMMMMMMMMPPAAMM
+  MMMMMMMMMBPAAMMM
+  MMMMMMMMPPAAMMMM
+  MMMMMMMBPAAMMMMM
+  MMMMMMPPAAMMMMMM
+  MMMMMBPAAMMMMMMM
+  MMMMPPAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 381 (uranium / probing)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMPNOMMM
+  MMMMMMMMMPPPAAMM
+  MMMMMMMMHHPAAMMM
+  MMMMMMMHAHAAMMMM
+  MMMMMMPAHAAMMMMM
+  MMMMMPPPAAMMMMMM
+  MMMMPPPAAMMMMMMM
+  MMMPPPAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 382 (iron / digging)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMKJMMM
+  MMMMMMMMMMKPAAMM
+  MMMMMMMMMPPAAMMM
+  MMMMMMMMPPAAMMMM
+  MMMMMMMPPAAMMMMM
+  MMMMMMPPAAMMMMMM
+  MMMMMPPAAMMMMMMM
+  MMMMKPAAMMMMMMMM
+  MMMKJAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 383 (steel / magic missile)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMKPMMM
+  MMMMMMMMMMOPAAMM
+  MMMMMMMMMOPAAMMM
+  MMMMMMMMOPAAMMMM
+  MMMMMMMOPAAMMMMM
+  MMMMMMPPAAMMMMMM
+  MMMMMPPAAMMMMMMM
+  MMMMKPAAMMMMMMMM
+  MMMKKAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 384 (hexagonal / fire)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMPNMMMM
+  MMMMMMMMMPNMAAMM
+  MMMMMMMMPNMAAMMM
+  MMMMMMMPNMAAMMMM
+  MMMMMMPNMAAMMMMM
+  MMMMMPNMAAMMMMMM
+  MMMMPNMAAMMMMMMM
+  MMMPNMAAMMMMMMMM
+  MMMNMAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 385 (short / cold)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMNOMMMMM
+  MMMMMMMMNOMMMMMM
+  MMMMMMMDIAAMMMMM
+  MMMMMMDIAAMMMMMM
+  MMMMMDIAAMMMMMMM
+  MMMMNIAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 386 (runed / sleep)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMNOMMM
+  MMMMMMMMMMNOAAMM
+  MMMMMMMMMDIAAMMM
+  MMMMMMMMAIAAMMMM
+  MMMMMMMDIAAMMMMM
+  MMMMMMAIAAMMMMMM
+  MMMMMDIAAMMMMMMM
+  MMMMNIAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 387 (long / death)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMNOM
+  MMMMMMMMMMMMNNMM
+  MMMMMMMMMMMDIMMM
+  MMMMMMMMMMDIAAMM
+  MMMMMMMMMDIAAMMM
+  MMMMMMMMDIAAMMMM
+  MMMMMMMDIAAMMMMM
+  MMMMMMDIAAMMMMMM
+  MMMMMDIAAMMMMMMM
+  MMMMDIAAMMMMMMMM
+  MMMNIAAMMMMMMMMM
+  MMNOAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 388 (curved / lightning)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMNOMMMMMMM
+  MMMMMMMNOAMMMMMM
+  MMMMMMMCIAMMMMMM
+  MMMMMMMDIAMMMMMM
+  MMMMMMMDIAMMMMMM
+  MMMMMMJIKAMMMMMM
+  MMMMMMKIJAMMMMMM
+  MMMMMMDIAAMMMMMM
+  MMMMMDIAAMMMMMMM
+  MMMMNIAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 389 (forked)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMNMMMMMM
+  MMMMMMMMNMMNOMMM
+  MMMMMMMDMMNOAAMM
+  MMMMMMMDMDIAAMOM
+  MMMMMMMDDIAAMOAM
+  MMMMMMMDIIIIIAMM
+  MMMMMMDIAAAAAMMM
+  MMMMMDIAAMMMMMMM
+  MMMMNIAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 390 (spiked)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMNNOMMM
+  MMMMMMMMMMDIOMMM
+  MMMMMMMMMDIAPMMM
+  MMMMMMMMDIAAMMMM
+  MMMMMMMDIAAMMMMM
+  MMMMMMDIAAMMMMMM
+  MMMMMDIAAMMMMMMM
+  MMMMNIAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 391 (jeweled)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMNNBMMM
+  MMMMMMMMMMNBBMMM
+  MMMMMMMMMMBBBAMM
+  MMMMMMMMMDIAAMMM
+  MMMMMMMMDIAAMMMM
+  MMMMMMMDIAAMMMMM
+  MMMMMMDIAAMMMMMM
+  MMMMMDIAAMMMMMMM
+  MMMMNIAAMMMMMMMM
+  MMMNOAAMMMMMMMMM
+  MMMMAAMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 392 (gold piece)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MJKKKJMJJMMMMMMM
+  JKCKKKJKKKJMMMMM
+  KCKKKJKAAAKAMMMM
+  KKKKKJAHALKAAMMM
+  KKKKJKHLLHAHAMMM
+  MKKJJKLHCALAMMMM
+  MAAAJKLALHCAHAMM
+  MMMAAKAHAHMMMMMM
+  MMMMAAAALAHAMHAM
+  MMMMMMHAMMMMMMMM
+  MMMMMMMMMHAMMMMM
+  MMMMMMMMMMMHAMMM
+}
+# tile 393 (white / dilithium crystal)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMONOOOMMMMMM
+  MMMMONOOOBOMMMMM
+  MMMNNNONONBBMMMM
+  MMMMONOOOBOAAMMM
+  MMMMMONOBOAAAAMM
+  MMMMMMOOOAAAMMMM
+  MMMMMMMOAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 394 (white / diamond)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMONOOOMMMMMM
+  MMMMONOOOBOMMMMM
+  MMMNNNONONBBMMMM
+  MMMMONOOOBOAAMMM
+  MMMMMONOBOAAAAMM
+  MMMMMMOOOAAAMMMM
+  MMMMMMMOAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 395 (red / ruby)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMDNDDDMMMMMM
+  MMMMDNDDDKDMMMMM
+  MMMDNDDKDKKKMMMM
+  MMMMDCDDDKDAAMMM
+  MMMMMDCDKDAAAAMM
+  MMMMMMDDDAAAMMMM
+  MMMMMMMDAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 396 (orange / jacinth)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMCNCCCMMMMMM
+  MMMMCNCCCKCMMMMM
+  MMMCNCCKCKKKMMMM
+  MMMMCLCCCKCAAMMM
+  MMMMMCLCKCAAAAMM
+  MMMMMMCCCAAAMMMM
+  MMMMMMMCAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 397 (blue / sapphire)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMBNBBBMMMMMM
+  MMMMBNBBBEBMMMMM
+  MMMNNNBEBEEEMMMM
+  MMMMBNBBBEBAAMMM
+  MMMMMBNBEBAAAAMM
+  MMMMMMBBBAAAMMMM
+  MMMMMMMBAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 398 (black / black opal)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMANAAAAAMMMMM
+  MMMANAAAAAAAMMMM
+  MMMAAAAAAAAAPMMM
+  MMMMAAAAAAAPPPMM
+  MMMMMMAAAPPPMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 399 (green / emerald)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMFGFFFMMMMMM
+  MMMMFGFFFFFMMMMM
+  MMMGGFGFGFFFMMMM
+  MMMMFGFFFFFAAMMM
+  MMMMMFGFFFAAAAMM
+  MMMMMMFGFAAAMMMM
+  MMMMMMMFAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 400 (green / turquoise)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMFGFFFMMMMMM
+  MMMMFGFFFFFMMMMM
+  MMMGGFGFGFFFMMMM
+  MMMMFGFFFFFAAMMM
+  MMMMMFGFFFAAAAMM
+  MMMMMMFGFAAAMMMM
+  MMMMMMMFAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 401 (yellow / citrine)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMHNHHHMMMMMM
+  MMMMHNHHHCHMMMMM
+  MMMHNHHCHCCCMMMM
+  MMMMHLHHHCHAAMMM
+  MMMMMHLHCHAAAAMM
+  MMMMMMHHHAAAMMMM
+  MMMMMMMHAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 402 (green / aquamarine)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMFGFFFMMMMMM
+  MMMMFGFFFFFMMMMM
+  MMMGGFGFGFFFMMMM
+  MMMMFGFFFFFAAMMM
+  MMMMMFGFFFAAAAMM
+  MMMMMMFGFAAAMMMM
+  MMMMMMMFAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 403 (yellowish brown / amber)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMKCKKKMMMMMM
+  MMMMKCKKKJKMMMMM
+  MMMCCCKJKJJJMMMM
+  MMMMKCKKKJKAAMMM
+  MMMMMKCKJKAAAAMM
+  MMMMMMKKKAAAMMMM
+  MMMMMMMKAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 404 (yellowish brown / topaz)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMKCKKKMMMMMM
+  MMMMKCKKKJKMMMMM
+  MMMCCCKJKJJJMMMM
+  MMMMKCKKKJKAAMMM
+  MMMMMKCKJKAAAAMM
+  MMMMMMKKKAAAMMMM
+  MMMMMMMKAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 405 (black / jet)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMANAAAAAMMMMM
+  MMMANAAAAAAAMMMM
+  MMMAAAAAAAAAPMMM
+  MMMMAAAAAAAPPPMM
+  MMMMMMAAAPPPMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 406 (white / opal)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMONOOOMMMMMM
+  MMMMONOOOBOMMMMM
+  MMMNNNONONBBMMMM
+  MMMMONOOOBOAAMMM
+  MMMMMONOBOAAAAMM
+  MMMMMMOOOAAAMMMM
+  MMMMMMMOAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 407 (yellow / chrysoberyl)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMHNHHHMMMMMM
+  MMMMHNHHHCHMMMMM
+  MMMHNHHCHCCCMMMM
+  MMMMHLHHHCHAAMMM
+  MMMMMHLHCHAAAAMM
+  MMMMMMHHHAAAMMMM
+  MMMMMMMHAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 408 (red / garnet)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMDNDDDMMMMMM
+  MMMMDNDDDKDMMMMM
+  MMMDNDDKDKKKMMMM
+  MMMMDCDDDKDAAMMM
+  MMMMMDCDKDAAAAMM
+  MMMMMMDDDAAAMMMM
+  MMMMMMMDAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 409 (violet / amethyst)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMINIIIMMMMMM
+  MMMMINIIIEIMMMMM
+  MMMNNNININEIMMMM
+  MMMMINIIIEIAAMMM
+  MMMMMINIEIAAAAMM
+  MMMMMMIIIAAAMMMM
+  MMMMMMMIAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 410 (red / jasper)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMDNDDDMMMMMM
+  MMMMDNDDDKDMMMMM
+  MMMDNDDKDKKKMMMM
+  MMMMDCDDDKDAAMMM
+  MMMMMDCDKDAAAAMM
+  MMMMMMDDDAAAMMMM
+  MMMMMMMDAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 411 (violet / fluorite)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMINIIIMMMMMM
+  MMMMINIIIEIMMMMM
+  MMMNNNININEIMMMM
+  MMMMINIIIEIAAMMM
+  MMMMMINIEIAAAAMM
+  MMMMMMIIIAAAMMMM
+  MMMMMMMIAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 412 (black / obsidian)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMANAAAAAMMMMM
+  MMMANAAAAAAAMMMM
+  MMMAAAAAAAAAPMMM
+  MMMMAAAAAAAPPPMM
+  MMMMMMAAAPPPMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 413 (orange / agate)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMCNCCCMMMMMM
+  MMMMCNCCCKCMMMMM
+  MMMCNCCKCKKKMMMM
+  MMMMCLCCCKCAAMMM
+  MMMMMCLCKCAAAAMM
+  MMMMMMCCCAAAMMMM
+  MMMMMMMCAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 414 (green / jade)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMFGFFFMMMMMM
+  MMMMFGFFFFFMMMMM
+  MMMGGFGFGFFFMMMM
+  MMMMFGFFFFFAAMMM
+  MMMMMFGFFFAAAAMM
+  MMMMMMFGFAAAMMMM
+  MMMMMMMFAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 415 (white / worthless piece of white glass)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMONOOOMMMMMM
+  MMMMONOOOBOMMMMM
+  MMMNNNONONBBMMMM
+  MMMMONOOOBOAAMMM
+  MMMMMONOBOAAAAMM
+  MMMMMMOOOAAAMMMM
+  MMMMMMMOAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 416 (blue / worthless piece of blue glass)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMBNBBBMMMMMM
+  MMMMBNBBBEBMMMMM
+  MMMNNNBEBEEEMMMM
+  MMMMBNBBBEBAAMMM
+  MMMMMBNBEBAAAAMM
+  MMMMMMBBBAAAMMMM
+  MMMMMMMBAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 417 (red / worthless piece of red glass)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMDNDDDMMMMMM
+  MMMMDNDDDKDMMMMM
+  MMMDNDDKDKKKMMMM
+  MMMMDCDDDKDAAMMM
+  MMMMMDCDKDAAAAMM
+  MMMMMMDDDAAAMMMM
+  MMMMMMMDAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 418 (yellowish brown / worthless piece of yellowish brown glass)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMKCKKKMMMMMM
+  MMMMKCKKKJKMMMMM
+  MMMCCCKJKJJJMMMM
+  MMMMKCKKKJKAAMMM
+  MMMMMKCKJKAAAAMM
+  MMMMMMKKKAAAMMMM
+  MMMMMMMKAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 419 (orange / worthless piece of orange glass)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMCNCCCMMMMMM
+  MMMMCNCCCKCMMMMM
+  MMMCNCCKCKKKMMMM
+  MMMMCLCCCKCAAMMM
+  MMMMMCLCKCAAAAMM
+  MMMMMMCCCAAAMMMM
+  MMMMMMMCAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 420 (yellow / worthless piece of yellow glass)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMHNHHHMMMMMM
+  MMMMHNHHHCHMMMMM
+  MMMHNHHCHCCCMMMM
+  MMMMHLHHHCHAAMMM
+  MMMMMHLHCHAAAAMM
+  MMMMMMHHHAAAMMMM
+  MMMMMMMHAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 421 (black / worthless piece of black glass)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMANAAAAAMMMMM
+  MMMANAAAAAAAMMMM
+  MMMAAAAAAAAAPMMM
+  MMMMAAAAAAAPPPMM
+  MMMMMMAAAPPPMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 422 (green / worthless piece of green glass)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMFGFFFMMMMMM
+  MMMMFGFFFFFMMMMM
+  MMMGGFGFGFFFMMMM
+  MMMMFGFFFFFAAMMM
+  MMMMMFGFFFAAAAMM
+  MMMMMMFGFAAAMMMM
+  MMMMMMMFAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 423 (violet / worthless piece of violet glass)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPMMMMMMMM
+  MMPMMMMPMMMMPMMM
+  MMMPMMMMMMMPMMMM
+  MMMMMINIIIMMMMMM
+  MMMMINIIIEIMMMMM
+  MMMNNNININEIMMMM
+  MMMMINIIIEIAAMMM
+  MMMMMINIEIAAAAMM
+  MMMMMMIIIAAAMMMM
+  MMMMMMMIAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 424 (gray / luckstone)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPPPPPMMMMMM
+  MMMMPNPPPPPMMMMM
+  MMMPNPPPPPPPAMMM
+  MMPPPPPPPPPPPAAM
+  MMPPPPPPPPPPPAAA
+  MMMPPPPPPPPPAAAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 425 (gray / loadstone)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPPPPPMMMMMM
+  MMMMPNPPPPPMMMMM
+  MMMPNPPPPPPPAMMM
+  MMPPPPPPPPPPPAAM
+  MMPPPPPPPPPPPAAA
+  MMMPPPPPPPPPAAAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 426 (gray / touchstone)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPPPPPMMMMMM
+  MMMMPNPPPPPMMMMM
+  MMMPNPPPPPPPAMMM
+  MMPPPPPPPPPPPAAM
+  MMPPPPPPPPPPPAAA
+  MMMPPPPPPPPPAAAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 427 (gray / flint)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMPPPPPMMMMMM
+  MMMMPNPPPPPMMMMM
+  MMMPNPPPPPPPAMMM
+  MMPPPPPPPPPPPAAM
+  MMPPPPPPPPPPPAAA
+  MMMPPPPPPPPPAAAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 428 (rock)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMKKKMMMMMMM
+  MMMMMKLCKKMMMMMM
+  MMMMMKCCKJAMMMMM
+  MMMMMKKKKJAMMMMM
+  MMMMMMKJJAAMMMMM
+  MMMMMMMAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 429 (boulder)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMKKKJMMMMMM
+  MMMMKKKKKKJJMMMM
+  MMMKCCKKKKKJJMMM
+  MMMKCKKKCKKKJAMM
+  MMKKKKKKKJKKJJAM
+  MMKKKKKKKKKKJJAA
+  MMKJKKKCKKKKJJAA
+  MMKKKKKKJKKKJJAA
+  MMMKKKKKKKKKJAAA
+  MMMJJKKKKKJJJAAM
+  MMMMJJJJJJJJAAMM
+  MMMMMMJJJJAAAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 430 (statue)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMJJMMMMMM
+  MMMMMMMKCJJMMMMM
+  MMMMMMMKKJJMMMMM
+  MMMMCKMCKJMMMMMM
+  MMMMJJCKKJMCJMMM
+  MMMMMJCKJJJJJMMM
+  MMMMMJCKJJJMAAMM
+  MMMMMMCKJMMMAAAM
+  MMMMMMCKJAAAAAAA
+  MMMMKCKKJAAAAAAM
+  MMMJCCKKJAJJAAMM
+  MMMJKKKKJJJJJAMM
+  MMMMJJKKKJJJAAMM
+  MMMMMJJJJJJAAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 431 (heavy iron ball)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMPPPMMMMMMM
+  MMMMMPOBPPMMMMMM
+  MMMMMPBBPMAMMMMM
+  MMMMMPPPPMAMMMMM
+  MMMMMMPMMAAMMMMM
+  MMMMMMMAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 432 (iron chain)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MPPMPPMPPMMMMMMM
+  PMAPMAPMAPPMMMMM
+  MPPAPPAPPPAPMMMM
+  MMAAMAAMAPAPAMMM
+  MMMMMMMMMMPAMMMM
+  MMMMMMMMMPAPMMMM
+  MMMMMMMMMPAPPMPM
+  MMMMMMMMMMPMAPAP
+  MMMMMMMMMMMPPMPA
+  MMMMMMMMMMMMAAMM
+}
+# tile 433 (splash of venom / blinding venom)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMHHHHMMMMM
+  MMMMMHHAAAAHHMMM
+  MMMMHAAAAAAAHMMM
+  MMMMHAAAAAAAHMMM
+  MMMMHAAAAHHHMMMM
+  MMMMMHHHHMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 434 (splash of venom / acid venom)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMHHHHMMMMM
+  MMMMMHHGGGGHHMMM
+  MMMMHGGGGGGGHMMM
+  MMMMHGGGGGGGHMMM
+  MMMMHGGGGHHHMMMM
+  MMMMMHHHHMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
diff --git a/win/share/other.txt b/win/share/other.txt
new file mode 100644 (file)
index 0000000..14ec940
--- /dev/null
@@ -0,0 +1,4348 @@
+A = (0, 0, 0)
+B = (0, 182, 255)
+C = (255, 108, 0)
+D = (255, 0, 0)
+E = (0, 0, 255)
+F = (0, 145, 0)
+G = (108, 255, 0)
+H = (255, 255, 0)
+I = (255, 0, 255)
+J = (145, 71, 0)
+K = (204, 79, 0)
+L = (255, 182, 145)
+M = (71, 108, 108)
+N = (255, 255, 255)
+O = (218, 218, 182)
+P = (108, 145, 182)
+# tile 0 (dark part of a room)
+{
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+}
+# tile 1 (wall)
+{
+  ANNOAMPPPPPMNNOA
+  AOOOAMPMPPMMOOOA
+  AOOOAMPPPPPMOOOA
+  AOOOAMPPPPPMOOOA
+  AOOOAMMPPPPMOOOA
+  AMAAAMMPPPPMMAMA
+  AMMMAMMPPPPMMMMA
+  AOPPAMMPPMPMOPMA
+  ANNOAMPPPPPMNNOA
+  AOOOAMPPPPPMOOOA
+  AOOOAMPPPPPMOOOA
+  AOOOAMPPPPPMOOOA
+  AOOOAMMPMPMMOOOA
+  AMAAAMMPPPPMMAMA
+  AMMMAMMPPPPMMMMA
+  AOPPAMMPPPPMOPMA
+}
+# tile 2 (wall)
+{
+  AAANOOAAAAANOOAA
+  OOONOOAMOOONOOAM
+  POOMMMAMPOOMMMAM
+  MMMMMMMMMMMMMMMM
+  PPMMMPPPPPMMMPPP
+  PPNOOPPPPPNOOPPP
+  OONOOAMOOONOOAMO
+  OOMMMAMPOOMMMAMP
+  MMMMMMMMMMMMMMMM
+  PPMOPPPPMOPPPMOP
+  PPMPPPPPMPPPPMPP
+  MMMMMMMMMMMMMMMM
+  MOPPPPMOPPPPMOPP
+  MPPPPPMPPPPPMPPP
+  MMMMMMMMMMMMMMMM
+  AAAAAAAAAAAAAAAA
+}
+# tile 3 (wall)
+{
+  AAANNNNOOOOOOAAA
+  NNNNAAMMPPPPOMMM
+  OOONAMMPPPBBOMMM
+  OOOOOOOOOOOOOMMM
+  OOOPPPPPPPPPPMMM
+  OOOPPPPPPPPPPMMM
+  OOPPPPPPPPPPPPMM
+  OPPPPPPPPPPPPPPM
+  MMMMMMMMMMMMMMMM
+  APPMMMMMMMMMPPPM
+  AOOOAAAAAAAAOOOA
+  AOOOAMPPPPPMOOOA
+  AOOOAMPPPPPMOOOA
+  AMAAAMMPPPPMMAMA
+  AMMMAMMPPPPMMMMA
+  AOPPAMMPPPPMOPMA
+}
+# tile 4 (wall)
+{
+  AAANNNNOOOOOOAAA
+  NNNNAAMMPPPPOMMM
+  OOONAMMPPPBBOMMM
+  OOOOOOOOOOOOOMMM
+  OOOPPPPPPPPPPMMM
+  OOOPPPPPPPPPPMMM
+  OOPPPPPPPPPPPPMM
+  OPPPPPPPPPPPPPPM
+  MMMMMMMMMMMMMMMM
+  APPMMMMMMMMMPPPM
+  AOOOAAAAAAAAOOOA
+  AOOOAMPPPPPMOOOA
+  AOOOAMPPPPPMOOOA
+  AMAAAMMPPPPMMAMA
+  AMMMAMMPPPPMMMMA
+  AOPPAMMPPPPMOPMA
+}
+# tile 5 (wall)
+{
+  AAANNNNOOOOOOAAA
+  NNNNAAMMPPPPOMMM
+  OOONAMMPPPBBOMMM
+  OOOOOOOOOOOOOMMM
+  OOOPPPPPPPPPPMMM
+  OOOPPPPPPPPPPMMM
+  OOPPPPPPPPPPPPMM
+  OPPPPPPPPPPPPPPM
+  MMMMMMMMMMMMMMMM
+  PPMOPPPPMOPPPMOP
+  PPMPPPPPMPPPPMPP
+  MMMMMMMMMMMMMMMM
+  MOPPPPMOPPPPMOPP
+  MPPPPPMPPPPPMPPP
+  MMMMMMMMMMMMMMMM
+  AAAAAAAAAAAAAAAA
+}
+# tile 6 (wall)
+{
+  AAANNNNOOOOOOAAA
+  NNNNAAMMPPPPOMMM
+  OOONAMMPPPBBOMMM
+  OOOOOOOOOOOOOMMM
+  OOOPPPPPPPPPPMMM
+  OOOPPPPPPPPPPMMM
+  OOPPPPPPPPPPPPMM
+  OPPPPPPPPPPPPPPM
+  MMMMMMMMMMMMMMMM
+  PPMOPPPPMOPPPMOP
+  PPMPPPPPMPPPPMPP
+  MMMMMMMMMMMMMMMM
+  MOPPPPMOPPPPMOPP
+  MPPPPPMPPPPPMPPP
+  MMMMMMMMMMMMMMMM
+  AAAAAAAAAAAAAAAA
+}
+# tile 7 (wall)
+{
+  AAANNNNOOOOOOAAA
+  NNNNAAMMPPPPOMMM
+  OOONAMMPPPBBOMMM
+  OOOOOOOOOOOOOMMM
+  OOOPPPPPPPPPPMMM
+  OOOPPPPPPPPPPMMM
+  OOPPPPPPPPPPPPMM
+  OPPPPPPPPPPPPPPM
+  MMMMMMMMMMMMMMMM
+  APPMMMMMMMMMPPPM
+  AOOOAAAAAAAAOOOA
+  AOOOAMPPPPPMOOOA
+  AOOOAMPPPPPMOOOA
+  AMAAAMMPPPPMMAMA
+  AMMMAMMPPPPMMMMA
+  AOPPAMMPPPPMOPMA
+}
+# tile 8 (wall)
+{
+  AAANNNNOOOOOOAAA
+  NNNNAAMMPPPPOMMM
+  OOONAMMPPPBBOMMM
+  OOOOOOOOOOOOOMMM
+  OOOPPPPPPPPPPMMM
+  OOOPPPPPPPPPPMMM
+  OOPPPPPPPPPPPPMM
+  OPPPPPPPPPPPPPPM
+  MMMMMMMMMMMMMMMM
+  PPMOPPPPMOPPPMOP
+  PPMPPPPPMPPPPMPP
+  MMMMMMMMMMMMMMMM
+  MOPPPPMOPPPPMOPP
+  MPPPPPMPPPPPMPPP
+  MMMMMMMMMMMMMMMM
+  AAAAAAAAAAAAAAAA
+}
+# tile 9 (wall)
+{
+  AAANNNNOOOOOOAAA
+  NNNNAAMMPPPPOMMM
+  OOONAMMPPPBBOMMM
+  OOOOOOOOOOOOOMMM
+  OOOPPPPPPPPPPMMM
+  OOOPPPPPPPPPPMMM
+  OOPPPPPPPPPPPPMM
+  OPPPPPPPPPPPPPPM
+  MMMMMMMMMMMMMMMM
+  APPMMMMMMMMMPPPM
+  AOOOAAAAAAAAOOOA
+  AOOOAMPPPPPMOOOA
+  AOOOAMPPPPPMOOOA
+  AMAAAMMPPPPMMAMA
+  AMMMAMMPPPPMMMMA
+  AOPPAMMPPPPMOPMA
+}
+# tile 10 (wall)
+{
+  AAANNNNOOOOOOAAA
+  NNNNAAMMPPPPOMMM
+  OOONAMMPPPBBOMMM
+  OOOOOOOOOOOOOMMM
+  OOOPPPPPPPPPPMMM
+  OOOPPPPPPPPPPMMM
+  OOPPPPPPPPPPPPMM
+  OPPPPPPPPPPPPPPM
+  MMMMMMMMMMMMMMMM
+  APPMMMMMMMMMPPPM
+  AOOOAAAAAAAAOOOA
+  AOOOAMPPPPPMOOOA
+  AOOOAMPPPPPMOOOA
+  AMAAAMMPPPPMMAMA
+  AMMMAMMPPPPMMMMA
+  AOPPAMMPPPPMOPMA
+}
+# tile 11 (wall)
+{
+  AAANNNNOOOOOOAAA
+  NNNNAAMMPPPPOMMM
+  OOONAMMPPPBBOMMM
+  OOOOOOOOOOOOOMMM
+  OOOPPPPPPPPPPMMM
+  OOOPPPPPPPPPPMMM
+  OOPPPPPPPPPPPPMM
+  OPPPPPPPPPPPPPPM
+  MMMMMMMMMMMMMMMM
+  APPMMMMMMMMMPPPM
+  AOOOAAAAAAAAOOOA
+  AOOOAMPPPPPMOOOA
+  AOOOAMPPPPPMOOOA
+  AMAAAMMPPPPMMAMA
+  AMMMAMMPPPPMMMMA
+  AOPPAMMPPPPMOPMA
+}
+# tile 12 (doorway)
+{
+  AAAAAAAAAAAAAAAA
+  AAMMMMMMMMMMMMAA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AAMMMMMMMMMMMMAA
+  AAAAAAAAAAAAAAAA
+}
+# tile 13 (open door)
+{
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAJJMJJJJJJJJJAA
+  AJKJJKJJKJJJJJJA
+  AAAAAAAAAAAAAAAA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AMMMMMMMMMMMMMMA
+  AAAAAAAAAAAAAAAA
+}
+# tile 14 (open door)
+{
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AKMMMMMMMMMMMMAA
+  ACKMMMMMMMMMMMMA
+  APJMMMMMMMMMMMMA
+  AMJMMMMMMMMMMMMA
+  AMJMMMMMMMMMMMMA
+  AMJMMMMMMMMMMMMA
+  AJJMMMMMMMMMMMMA
+  APJMMMMMMMMMMMMA
+  AMJMMMMMMMMMMMMA
+  AMJMMMMMMMMMMMMA
+  AMJMMMMMMMMMMMMA
+  AKMMMMMMMMMMMMMA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+}
+# tile 15 (closed door)
+{
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AACCKKKKKKKKJJAA
+  ACKJJJJJJJJJJKJA
+  APJJPKJJKJJJJJJA
+  AMPPMPPPPPMBPPJA
+  AMMMMMMMMMBPPMJA
+  AMJJMJJJJJPAPAJA
+  AJJJJKJJJJMPMAJA
+  APKJPKJJJJJAAAJA
+  AMPPMPPPPPPMMPJA
+  AMMMMMMMMMMMMMJA
+  AMJJMJJJJJJJJJJA
+  AJKJJKJJKJJJJJJA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+}
+# tile 16 (closed door)
+{
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AACCKKKKKKKKJJAA
+  ACKJJJJJJJJJJKJA
+  APJJPKJJKJJJJJJA
+  AMPPMPPPPPMBPPJA
+  AMMMMMMMMMBPPMJA
+  AMJJMJJJJJPAPAJA
+  AJJJJKJJJJMPMAJA
+  APKJPKJJJJJAAAJA
+  AMPPMPPPPPPMMPJA
+  AMMMMMMMMMMMMMJA
+  AMJJMJJJJJJJJJJA
+  AJKJJKJJKJJJJJJA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+}
+# tile 17 (iron bars)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMBBMMMMMMM
+  MMMMBBMBPMBPMMMM
+  MBBMBPMBPMPPMBPM
+  MBPMBPMBPMPPMPPM
+  MBPMBPMBPMPPMPPM
+  MBPMBPMBPMPPAPPM
+  MBPMBPMBPAPPAPPM
+  MBPMBPABPAPPAPPM
+  MBPABPABPAPPAPPA
+  MBPABPABPAPPAPPA
+  MBPABPABPAPPAPPA
+  MBPABPABPAPPAPPA
+  MBPMBPMBPMPPMPPM
+  MMMMMMMMMMMMMMMM
+}
+# tile 18 (tree)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMFFFFFFMMMMM
+  MMMFFFFFFFFFFMMM
+  MMFFFFFFFFFFFFMM
+  MMFFFFFFFFFFFFMM
+  MMFFFFJFFFJFFFMM
+  MMMFFFFJFJFFFMMM
+  MMMMFFJJJJFFMMMM
+  MMMMMMMKJJMAAAAM
+  MMMMMMMKJMAAAAAA
+  MMMMMMMJJMAAAAAA
+  MMMMMMMKJMAAAAAM
+  MMMMMMMKJAAAMMMM
+  MMMMMMKJJJAAMMMM
+  MMMJJJJMJMJJJAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 19 (floor of a room)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPPMMMMMMM
+  MMMMMMMPPMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 20 (corridor)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPPMMMMMMM
+  MMMMMMPMMPMMMMMM
+  MMMMMMPMMPMMMMMM
+  MMMMMMMPPMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 21 (lit corridor)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMPPMMMMMMM
+  MMMMMMPPPPMMMMMM
+  MMMMMMPPPPMMMMMM
+  MMMMMMMPPMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 22 (staircase up)
+{
+  AAAAAAAAAAAAAAMA
+  AADJJJJJJJJJDAMA
+  AACDDJKNKKDDCAMA
+  AAAAAANNNAAAAMMA
+  AAADJNNNNNJDAMMA
+  AAACNOONONNCAMMA
+  AAAAAAOONAAAMMMA
+  AAAAKDOOOKJAMMMA
+  AAAACKPONKCAMMMA
+  AAAAAAOPOAAMMMMA
+  AAAAAKPPPJAMMMMA
+  AAAAACKJJKAMMMMA
+  AAAAAAAAAAAAMMMA
+  AAAAAAAAAAAAAMMA
+  AAAAAAAAAAAAAAMA
+  AAAAAAAAAAAAAAAA
+}
+# tile 23 (staircase down)
+{
+  AAAAAAAAAAAAAAMA
+  AADJJJJJJJJJDAMA
+  AACDDJNNNKDDCAMA
+  AAAAAANNNAAAAMMA
+  AAADJJNONJJDAMMA
+  AAACDDONNKDCAMMA
+  AAAAAAONOAAAMMMA
+  AAAAPOOONONAMMMA
+  AAAACPOOOPCAMMMA
+  AAAAAANPNAAMMMMA
+  AAAAAKKOJJAMMMMA
+  AAAAACKJJKAMMMMA
+  AAAAAAAAAAAAMMMA
+  AAAAAAAAAAAAAMMA
+  AAAAAAAAAAAAAAMA
+  AAAAAAAAAAAAAAAA
+}
+# tile 24 (ladder up)
+{
+  ADAAAAAAAAAAADMA
+  AADAAAANAAAADAMA
+  AACCCCNNNCCCCAMA
+  AADAANANANAADMMA
+  AAADAAANAAADAMMA
+  AAACDDDNDDDCAMMA
+  AAADAAAOAAADMMMA
+  AAAAKAAOAAJAMMMA
+  AAAACKKOKKCAMMMA
+  AAAADAAPAADMMMMA
+  AAAAAKJPJJAMMMMA
+  AAAAADAAAKAMMMMA
+  AAAAAAAAAAAAMMMA
+  AAAAAAAAAAAAAMMA
+  AAAAAAAAAAAAAAMA
+  AAAAAAAAAAAAAAAA
+}
+# tile 25 (ladder down)
+{
+  ADAAAAAAAAAAADMA
+  AADAAAANAAAADAMA
+  AACCCCCNCCCCCAMA
+  AADAAAANAAAADMMA
+  AAADAAANAAADAMMA
+  AAACDDDNDDDCAMMA
+  AAADAAAOAAADMMMA
+  AAAAKAAOAAJAMMMA
+  AAAACOKOKOCAMMMA
+  AAAADAOOOADMMMMA
+  AAAAAKJOJJAMMMMA
+  AAAAADAAAKAMMMMA
+  AAAAAAAAAAAAMMMA
+  AAAAAAAAAAAAAMMA
+  AAAAAAAAAAAAAAMA
+  AAAAAAAAAAAAAAAA
+}
+# tile 26 (altar)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMPDPDPDPDPMMMM
+  MMPPPDPDDDPPPMMM
+  MMMBBPPPDPPMAAMM
+  MMMBPPPPPPMMAMMM
+  MMPPMMMMMMMPPMMM
+  MMMAAAAAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 27 (grave)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMONOPPMMMMMM
+  MMMONPPPPPPMMMMM
+  MMOPPPPPPPPPMMMM
+  MOPPPPPPPPPPPMMM
+  MOPAAPPAPAAPPMMM
+  MOPAPAPAPAPAPAAM
+  MOPAAPPAPAAPPAAA
+  MOPAPAPAPAPPPAAA
+  MOPAPAPAPAPPPAAA
+  MOPPPPPPPPPPPAAA
+  MOPPPPPPPFPPPAAM
+  MOPPFMMPPFMPPAMM
+  FFFFFFFFFFFFFFFM
+  MMMMMMMMMMMMMMMM
+}
+# tile 28 (opulent throne)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMHHHHHMMMMMM
+  MMMMHCCCDDHMMMMM
+  MMMMHCCEDDHMMMMM
+  MMMMHCEEEDHMMMMM
+  MMMMHCCEDDHMMMMM
+  MMMMHCCEDDHMMAAM
+  MMMMMHCDDHAAAAAM
+  MMCCOHCDDHOCCAAA
+  MHHHDHHHHHCHHHAA
+  MHMHODDDCCOHAHAA
+  MMMHHHHHHHHHAAAM
+  MMMHALAAALAHAAMM
+  MMHAMAAAAAAAHMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 29 (sink)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMPMMMMPMMMMMM
+  MMNPPPPPPPPNMMMM
+  MNOMPMPPMPMONMMM
+  MNOBMMPPMMBONMMM
+  MNOBBBPPBBBONAAM
+  MNOBBBBBBBBONAAA
+  MNOOOOOOOOOONAAA
+  MMNNNNNNNNNNAAAA
+  MMMMMOOOOAAAAAAA
+  MMMMMOOOOAAAAAMM
+  MMMMOOOOOOAMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 30 (fountain)
+{
+  MMMMEMMMMEMMMMMM
+  MMEEEEMMEEEMMMMM
+  MMEMMMEEEMEEMMMM
+  MMMEMEEEEMEMMMMM
+  MMEMMEEOEMEEMAMM
+  MEEMEENOEMEMEAAM
+  MEMMEMNOMEMEAAAM
+  MMMPPPNOPPPAAAMM
+  MMPEEENOEEEPAAMM
+  MOEENNNOOOEEPAMM
+  MNOEEEEEEEEONAAM
+  MPNOOOOOOOONPAAM
+  MMPNNNNNNNNPAAAM
+  MMMPPPPPPPPAAAMM
+  MMMMAAAAAAAAAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 31 (water)
+{
+  MMMMMMMMMMNNNMMM
+  MEEEEMMMMNEMENMM
+  MMMMEEMEEEMMMMMM
+  MMMMMEEEMMMMMMMM
+  MNNMMMMMMEEMMMMM
+  EMENMMMMEMEEMMEE
+  MMMENMEMMMMEMMEM
+  MMMMEEMMMMMMEEMM
+  MMMMMMMMMMMMMMMM
+  NMMEEMMMEEEEMMMM
+  NNEMMEMEMMMEEMMN
+  MEMMMMEMNNMMEENM
+  MMMMMMMNEEEEMMMM
+  MMEEEMMEMMMEEEMM
+  MEMMEEMMMEMMEEEM
+  EEMMMMEEEMMMMMEE
+}
+# tile 32 (ice)
+{
+  NNNNNNNNNNNNNNNN
+  NNNNNNNNNNNNNNNN
+  NNNNNNNNNNNNNNNN
+  NNNNNNNNNNNNNNNN
+  NNNNNNNNNNNNNNNN
+  NNNNNNNNNNNNNNNN
+  NNNNNNNMMNNNNNNN
+  NNNNNNMNNMNNNNNN
+  NNNNNNMNNMNNNNNN
+  NNNNNNNMMNNNNNNN
+  NNNNNNNNNNNNNNNN
+  NNNNNNNNNNNNNNNN
+  NNNNNNNNNNNNNNNN
+  NNNNNNNNNNNNNNNN
+  NNNNNNNNNNNNNNNN
+  NNNNNNNNNNNNNNNN
+}
+# tile 33 (molten lava)
+{
+  DDDDDDCDDDDDDDDD
+  DDDDDCDKDDDDDDDD
+  DDCCDDKDDDDCCCDD
+  DCJJKDDDDDCKJJKD
+  DCJDKDDDDDCJKDKD
+  DDKKDDDDDDCJDKKD
+  DDDDDDDCDDDKKKDD
+  DDDCDDDDDDDDDDDD
+  DDDDJDCDDDDCDDDD
+  DDDDDDDDDDCJKDDD
+  DDDDDDDDDDDKDDDC
+  DDDDCCDDDDDDDDDD
+  DDDCJJKDDDDDDDDD
+  CDDCJDKDDDDDDJDD
+  DDDDKKDDDDCDDDDD
+  DDDDDDDDDDDKDDDD
+}
+# tile 34 (lowered drawbridge)
+{
+  EKKAKKKKKKKAKKAE
+  EJKKKKKKKKKKKJAA
+  EEJJJJJJJJJJJAAA
+  EJKKKKKKKKKKKJAA
+  EKKAKKKKKKKAKKAE
+  EJKKKKKKKKKKKJAA
+  EEJJJJJJJJJJKAAA
+  EJKKKKKKKKKKKJAA
+  EKKAKKKKKKKAKKAE
+  EJKKKKKKKKKKKJAA
+  EEJJJJJJJJJJJAAA
+  EJKKKKKKKKKKKJAA
+  EKKAKKKKKKKAKKAE
+  EJKKKKKKKKKKKJAA
+  EEJJJJJJJJJJJAAA
+  EJKKKKKKKKKKKJAA
+}
+# tile 35 (lowered drawbridge)
+{
+  EEEEEEEEEEEEEEEE
+  JEJKJEJKJEJKJEJK
+  KJKKKJKKKJKKKJKK
+  KJKAKJKAKJKAKJKA
+  KJKKKJKKKJKKKJKK
+  KJKKKJKKKJKKKJKK
+  KJKKKJKKKJKKKJKK
+  KJKKKJKKKJKKKJKK
+  KJKKKJKKKJKKKJKK
+  KJKKKJKKKJKKKJKK
+  KJKKKJKKKJKKKJKK
+  KJKAKJKAKJKAKJKA
+  KJKKKJKKKKKKKJKK
+  JAJKJAJKJAJKJAJK
+  AAAAAAAAAAAAAAAA
+  AAAEAAAEAAAEAAAE
+}
+# tile 36 (raised drawbridge)
+{
+  MMMMMMMMMMMMMMMM
+  MMJKJMJKJMJKJMMM
+  MJKKKJKKKJKKKJMM
+  MJKAKJKAKJKAKJAM
+  MJKKKJKKKJKKKJAM
+  MJKKKJKKKJKKKJAM
+  MJKKKJKKKJKKKJAM
+  MJKKKJKKKJKKKJAM
+  MJKKKJKKKJKKKJAM
+  MJKKKJKKKJKKKJAM
+  MJKKKJKKKJKKKJAM
+  MJKAKJKAKJKAKJAM
+  MJKKKJKKKKKKKJAM
+  MMJKJAJKJAJKJAAM
+  MMMAAAMAAAMAAAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 37 (raised drawbridge)
+{
+  MMMMMMMMMMMMMMMM
+  MMJJJJJJJJJJJMMM
+  MJKKKKKKKKKKKJMM
+  MKKAKKKKKKKAKKAM
+  MJKKKKKKKKKKKJAM
+  MMJJJJJJJJJJJAAM
+  MJKKKKKKKKKKKJMM
+  MKKAKKKKKKKAKKAM
+  MJKKKKKKKKKKKJAM
+  MMJJJJJJJJJJKAAM
+  MJKKKKKKKKKKKJMM
+  MKKAKKKKKKKAKKAM
+  MJKKKKKKKKKKKJAM
+  MMJJJJJJJJJJJAAM
+  MMMAAAAAAAAAAAMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 38 (air)
+{
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+}
+# tile 39 (cloud)
+{
+  BBBBBBBBBBBBBBBB
+  BBBBBNNNNNNNBBBB
+  BBBNNNNNNNNNNBBB
+  BBNNNNNNNNNONNBB
+  BBNNNNNNNNNNNNNB
+  BNNNNNNNNNNNNONB
+  NNNONNNNNNNNONNN
+  NNNNNNNNNNOONNNN
+  NNNNNNNNNNNNNONN
+  NNOONNNNNNNOONNO
+  NNNNNOOOOONNNNOO
+  BONNNNNNNNNNOOOB
+  BBOOONNNNOOOOOOB
+  BBBOOOOOOOOOOBBB
+  BBBBBBOOOOBBBBBB
+  BBBBBBBBBBBBBBBB
+}
+# tile 40 (water)
+{
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEEEEEEEEEEEEE
+}
+# tile 41 (arrow trap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCACDDMMMMM
+  MMMDCCAAACCDMMMM
+  MMMCCAAAAACDAMMM
+  MMDCCHHAHHCDDAMM
+  MMDCHHNANHHCDAMM
+  MMDCHNNANNHCDAMM
+  MMDCHNNANNHCDAMM
+  MMDCCHAAAHCCDAMM
+  MMMCCAAAAACCAAMM
+  MMMDCAAAAACDAMMM
+  MMMMDAACAADAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 42 (dart trap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCACDDMMMMM
+  MMMDCCCACCCDMMMM
+  MMMCCCHAHCCDAMMM
+  MMDCCHAAAHCDDMMM
+  MMDCHHAAAHHCDAMM
+  MMDCHNAAANHCDAMM
+  MMDCHNNANNHCDAMM
+  MMDCCAAAAACDDAMM
+  MMMCCAACAACDAAMM
+  MMMDCACACACDAMMM
+  MMMMDDCCCCDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 43 (falling rock trap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDAACDDMMMMM
+  MMMDCCCCCCCDMMMM
+  MMMCCCAAHCCDAMMM
+  MMDCCHHHHHCDDAMM
+  MMDCHHAAHHHCDAMM
+  MMDCHHHHHHHCDAMM
+  MMDCHHAAHHHCDAMM
+  MMDCHAHAAHHCDAMM
+  MMMCCAAAAHCCAAMM
+  MMMDCCAAHCCDAMMM
+  MMMMDCCCCCDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 44 (squeaky board)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCCCDDMMMMM
+  MMMDCCCCCCCDMMMM
+  MMMCCCHHHCCDAMMM
+  MMDCCHHNHHCDDAMM
+  MMDAAAAAAAAADAMM
+  MMDAAAAAAAAADAMM
+  MMDAAAAAAAAADAMM
+  MMDAAAAAAAAADAMM
+  MMMCCHHNHHCCAAMM
+  MMMDCCHHHCCDAMMM
+  MMMMDCCCCCDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 45 (bear trap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCCCDDMMMMM
+  MMMDAAPCPAADMMMM
+  MMMDAHHHHHADAMMM
+  MMDDAAPNPAACDMMM
+  MMDCANNNNNACDAMM
+  MMDCAAPNPAACDAMM
+  MMDCANNNNNACDAMM
+  MMDDAHHHHHACDAMM
+  MMMDAACHCAADAAMM
+  MMMDCAAAAACDAMMM
+  MMMMDDAAADDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 46 (land mine)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCCCDDMMMMM
+  MMMDCCCCCCCDMMMM
+  MMMCCCHHHCCDAMMM
+  MMDCCHHAHHCDDAMM
+  MMDCHHAAAHHCDAMM
+  MMDCAAAAAAACDAMM
+  MMDCAAAAAAACDAMM
+  MMDCHHNNNHHCDAMM
+  MMMCCHHNHHCCAAMM
+  MMMDCCHHHCCDAMMM
+  MMMMDCCCCCDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 47 (rolling boulder trap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCCCDDMMMMM
+  MMMDCCCCCCCDMMMM
+  MMMCCCHHHCCDAMMM
+  MMDCCAAAAHCDDAMM
+  MMDCAAHAAAHCDAMM
+  MMDCAHAAAAHCDAMM
+  MMDCAAAAAAHCDAMM
+  MMDCAAAAAAHCDAMM
+  MMMCCAAAAHCCAAMM
+  MMMDCCHHHCCDAMMM
+  MMMMDCCCCCDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 48 (sleeping gas trap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCCCDDMMMMM
+  MMMDCCHHHCCDMMMM
+  MMMCAAAAAAACAMMM
+  MMDCAANNAAACDAMM
+  MMDCHNNAAAHCDAMM
+  MMDCHNAAANHCDAMM
+  MMDCHAAANHHCDAMM
+  MMDCAAAHHHACDAMM
+  MMMCAAAAAAACAAMM
+  MMMDCCHHHCCDAMMM
+  MMMMDDCCCCDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 49 (rust trap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCCCDDMMMMM
+  MMMDCCCCCCCDMMMM
+  MMMCCCHHHCCDAMMM
+  MMDCCAAAAACDDAMM
+  MMDCAAEEEAACDAMM
+  MMDCAEEEEEACDAMM
+  MMDCAEEEEEACDAMM
+  MMDCAAEEEAACDAMM
+  MMMCCAAAAACCAAMM
+  MMMDCCHHHCCDAMMM
+  MMMMDCCCCCDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 50 (fire trap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCCCDDMMMMM
+  MMMDCCAAACCDMMMM
+  MMMCCAADAACDAMMM
+  MMDCAADDAAADDAMM
+  MMDCAADDDAACDAMM
+  MMDCADCHCDACDAMM
+  MMDCADHNHDACDAMM
+  MMDCAAHNHAACDAMM
+  MMMCCAANAACCAAMM
+  MMMDCCAAACCDAMMM
+  MMMMDCCCCCDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 51 (pit)
+{
+  AAAAAAAAAAAAAAAA
+  AMAAAAAAAAAAAABA
+  AMMAAAAAAAAAABBA
+  AMMMAAAAAAAABBBA
+  AMMMAMMMMMMABBBA
+  AMMMAMMMMMMABBBA
+  AMMMAMMMMMMABBBA
+  AMMMAMMMMMMABBBA
+  AMMMAMMMMMMABBBA
+  AMMMAMMMMMMABBBA
+  AMMMAMMMMMMABBBA
+  AMMMAAAAAAAABBBA
+  AMMMPPPPPPPPPBBA
+  AMMPPPPPPPPPPPBA
+  AMPPPPPPPPPPPPPA
+  AAAAAAAAAAAAAAAA
+}
+# tile 52 (spiked pit)
+{
+  AAAAAAAAAAAAAAAA
+  AMAAAAAAAAAAAABA
+  AMMAAAAAAAAAABBA
+  AMMMAAAAAAAABBBA
+  AMMMAMMMMMMABBBA
+  AMMMAMNMNMMABBBA
+  AMMMAMMMMMMABBBA
+  AMMMAMMNMNMABBBA
+  AMMMAMMMMMMABBBA
+  AMMMAMNMNMMABBBA
+  AMMMAMMMMMMABBBA
+  AMMMAAAAAAAABBBA
+  AMMMPPPPPPPPPBBA
+  AMMPPPPPPPPPPPBA
+  AMPPPPPPPPPPPPPA
+  AAAAAAAAAAAAAAAA
+}
+# tile 53 (hole)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMAAAAAABMMMM
+  MMMMAAAAAAABBMMM
+  MMMAAAAAAAAABBBM
+  MMMAAAAAAAAAABBM
+  MMMAAAAAAAAAABBM
+  MMMAAAAAAAAAABBM
+  MMMAAAAAAAAAABBM
+  MMMMAAAAAAAAABBM
+  MMMMMAAAAAAAABBM
+  MMMMMAAAAAAABBMM
+  MMMMMMAAAAABMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 54 (trap door)
+{
+  AAAAAAAAAAAAAAAA
+  AMAAAAAAAAAAAABA
+  AMMAAAAAAAAAABBA
+  AMMMAAAAAAAABBBA
+  AMMMAAAAAAAABBBA
+  AMMMAAAAAAAABBBA
+  AMMMAAAAAAAABBBA
+  AMMMAAAAAAAABBBA
+  AMMMAAAAAAAABBBA
+  AMMMAAAAAAAABBBA
+  AMMMAAAAAAAABBBA
+  AMMMAAAAAAAABBBA
+  AMMMPPPPPPPPPBBA
+  AMMPPPPPPPPPPPBA
+  AMPPPPPPPPPPPPPA
+  AAAAAAAAAAAAAAAA
+}
+# tile 55 (teleportation trap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCACDDMMMMM
+  MMMDCCAAACCDMMMM
+  MMMDCAAAAACCAMMM
+  MMDDCHHAHHCCDMMM
+  MMDCOHAAAHOCDAMM
+  MMDCHOAAAOHCDAMM
+  MMDCHOAAAOHCDAMM
+  MMDDCHHAHHCCDAMM
+  MMMDCAAAAACCAAMM
+  MMMDCCAAACCDAMMM
+  MMMMDDCACDDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 56 (level teleporter)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDADDMMMMMM
+  MMMMDDAAADDMMMMM
+  MMMDCAAAAADDMMMM
+  MMMDCCCACCCCAMMM
+  MMDDCHAAAHCCDMMM
+  MMDCOAAOAAOCDAMM
+  MMDCHAOOOAHCDAMM
+  MMDCHAAOAAHCDAMM
+  MMDDCHAAAHCCDAMM
+  MMMDCCCACCCCAAMM
+  MMMDCAAAAACDAMMM
+  MMMMDDAAADDAAMMM
+  MMMMMDDADDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 57 (magic portal)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCACDDMMMMM
+  MMMDCCAAACCDMMMM
+  MMMDCAAAAACCAMMM
+  MMDDCHHAHHHADMMM
+  MMDDCHOAOAACDAMM
+  MMDDOAAAAAOCDAMM
+  MMDDAAOAOOCCDAMM
+  MMDAHHHAHHCCDAMM
+  MMMDCAAAAACCAAMM
+  MMMDCCAAACCDAMMM
+  MMMMDDCACDDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 58 (web)
+{
+  OAOAMOAMMMOMMMMO
+  MOMNNNNMNOAMMOOA
+  OONMNOMNAMMOOAMM
+  MNMMOOMNMNOAMMMM
+  MNMOMMMNOAMMMMMM
+  ONOMOMNAMMMMMMMM
+  MONNNNAMMMMMMMMM
+  MMOMNAMMMMMMMMMM
+  MOAMOAMMMMMMMMMM
+  MOONAMMMMMMMMMMM
+  OAMOAMMMMMMMMMMM
+  MMOAMMMMMMMMMMMM
+  MMOAMMMMMMMMMMMM
+  MOAMMMMMMMMMMMMM
+  MOAMMMMMMMMMMMMM
+  OAMMMMMMMMMMMMMM
+}
+# tile 59 (statue trap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCAADDMMMMM
+  MMMDCCAJJACDMMMM
+  MMMCCAKCJJADAMMM
+  MMDAAAKKJJADDAMM
+  MMACKACKJAAADAMM
+  MMAJJCKKJACJAAMM
+  MMDAJCKJJJJJAAMM
+  MMDAJCKJJJAADAMM
+  MMMCACKJAACCAAMM
+  MMMDACKJACCDAMMM
+  MMMMDCCCCCDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 60 (magic trap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCCCDAMMMMM
+  MMMDCCCCCCADMMMM
+  MMMCCCHHHAADAMMM
+  MMDCAHHNHAADDAMM
+  MMDCAANNAAACDAMM
+  MMDCAAAAAAACDAMM
+  MMDCAAANNAACDAMM
+  MMDCAANNNHACDAMM
+  MMMCAAHNHHCCAAMM
+  MMMDACHHHCCDAMMM
+  MMMMACCCCCDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 61 (anti-magic field)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMDDDDDMMMMM
+  MMMMMADCCCDDMMMM
+  MMMMDACCCCCCDMMM
+  MMMADAAHHHCCCMMM
+  MMADDAAHNHHACDMM
+  MMADCAAANNAACDMM
+  MMADCAAAAAAACDMM
+  MMADCAANNAAACDMM
+  MMADCAHNNNAACDMM
+  MMAACCHHNHAACMMM
+  MMMADCCHHHCADMMM
+  MMMAADCCCCCAMMMM
+  MMMMAADDDDDMMMMM
+  MMMMMAAAAAMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 62 (polymorph trap)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDDMMMMMM
+  MMMMDDCCCDDMMMMM
+  MMMDCAAAPCCDMMMM
+  MMMCCAAPHCCDAMMM
+  MMDCCAPAAHCDDAMM
+  MMDCHPNAAHHCDAMM
+  MMDCHNPAPNHCDAMM
+  MMDCHNAANPHCDAMM
+  MMDCHHAAPAHCDAMM
+  MMMCCHHPAACCAAMM
+  MMMDCCPAAACDAMMM
+  MMMMDCCCCCDAAMMM
+  MMMMMDDDDDAAMMMM
+  MMMMMMAAAAAMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 63 (wall)
+{
+  MMMMMMMNNMMMMMMM
+  MMMMMMNNMMMMMMMM
+  MMMMMNNMMMMMMMMM
+  MMMMMMNNMMMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMMMNNMMMMMM
+  MMMMMMMMMNNMMMMM
+  MMMMMMMMNNMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMNNMMMMMMMM
+  MMMMMNNMMMMMMMMM
+  MMMMMMNNMMMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMMMNNMMMMMM
+  MMMMMMMMMNNMMMMM
+  MMMMMMMMNNMMMMMM
+}
+# tile 64 (wall)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMNMMMMMMMNMMMMM
+  MNNNMMMMMNNNMMMM
+  NNMNNMMMNNMNNMMM
+  NMMMNNMNNMMMNNMN
+  MMMMMNNNMMMMMNNN
+  MMMMMMNMMMMMMMNM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 65 (wall)
+{
+  NNNNNMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMMNNNNNNNNNMMM
+  MMMMMMMMMMMMNMMM
+  MMMMMMMMMMMMNMMM
+  MMMMMMMMMMMMNMMM
+  MMMMMMMMMMMMNMMM
+  MMMMMMMMMMMMNMMM
+  MMMMMMMMMMMMNMMM
+  MMMMMMMMMMMMNNNN
+}
+# tile 66 (wall)
+{
+  MMMMMMMMMMMMNNNN
+  MMMMMMMMMMMMNMMM
+  MMMMMMMMMMMMNMMM
+  MMMMMMMMMMMMNMMM
+  MMMMMMMMMMMMNMMM
+  MMMMMMMMMMMMNMMM
+  MMMMMMMMMMMMNMMM
+  MMMMNNNNNNNNNMMM
+  MMMMNMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  MMMMNMMMMMMMMMMM
+  NNNNNMMMMMMMMMMM
+}
+# tile 67 (cmap 67)
+{
+  MMMMAAAAMMMMMMMM
+  MMAMMMMAAMMAAMMM
+  MAAMAAAMMMMMMAAM
+  MAAMAMMMMAMMAAMM
+  MMAMMMMAMAMAMAAM
+  MAMMAAAMAMMMMAAM
+  MAMAAMMMMMAMAAMM
+  MMMAAMMMMAAMMMMM
+  MAMAMMMAMMMAMAMM
+  MMMAMMMMMMAAMAAM
+  MAMAAAMAAAAMAMAM
+  MAAMMAAMMMMMMMAM
+  MMAMMMAAMMAMMAAM
+  MMAAAAAMMAAAAAMM
+  MMMMAAMMMMAAAMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 68 (cmap 68)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMNNNNNNMMMMM
+  MMMNNNNNNNNNNMMM
+  MMNNNNNNNNNNNNMM
+  MMNNNNNNNNNNNNMM
+  MNNNNNNNNNNNNNNM
+  MNNNNNNNNNNNNNNM
+  MNNNNNNNNNNNNNNM
+  MNNNNNNNNNNNNNNM
+  MNNNNNNNNNNNNNNM
+  MNNNNNNNNNNNNNNM
+  MMNNNNNNNNNNNNMM
+  MMNNNNNNNNNNNNMM
+  MMMNNNNNNNNNNMMM
+  MMMMMNNNNNNMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 69 (cmap 69)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMKKMMMMMMMMMM
+  MMMMKHKAMMMMMMMM
+  MMMMMKHKAMMMMMMM
+  MMMMMMKKKAMMMMMM
+  MMMMMMMKKKAMMMMM
+  MMMMMMMMKDKAMMMM
+  MMMMMMMMJDKAMMMM
+  MMMMMMMJKDJAMMMM
+  MMMMMMJKDJAMMMMM
+  MMMMMJHDJAMMMMMM
+  MMMMJHDJAMMMMMMM
+  MMMMMKJAMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 70 (cmap 70)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMJKMMMMM
+  MMMMMMMMJDHJMMMM
+  MMMMMMMJDHJAMMMM
+  MMMMMMJDKJAMMMMM
+  MMMMMJDKJAMMMMMM
+  MMMMMKDJAMMMMMMM
+  MMMMMKDKAMMMMMMM
+  MMMMMMKKKAMMMMMM
+  MMMMMMMKKKAMMMMM
+  MMMMMMMMKHKAMMMM
+  MMMMMMMMMKHKAMMM
+  MMMMMMMMMMKKAMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 71 (cmap 71)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMIMMMMIMMMMM
+  MMMMIMMMMMMIMMMM
+  MMMIMMMMMMMMIMMM
+  MMIMMMIIIIMMMIMM
+  MIMMMMMMMMMMMMIM
+  MMMMIMMIIMMIMMMM
+  MMMMIMIIIIMIMMMM
+  MMMMIMIIIIMIMMMM
+  MMMMIMMIIMMIMMMM
+  MIMMMMMMMMMMMMIM
+  MMIMMMIIIIMMMIMM
+  MMMIMMMMMMMMIMMM
+  MMMMIMMMMMMIMMMM
+  MMMMMIMMMMIMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 72 (cmap 72)
+{
+  MMMMMMMMMMMMMMMM
+  MCCCCCCCCCCCCCCC
+  MCMMMMMMMMMMMMMM
+  MCMCCCCCCCCCCCCM
+  MCMCMMMMMMMMMMCM
+  MCMCMCCCCCCCCMCM
+  MCMCMCMMMMMMCMCM
+  MCMCMCMCCCCMCMCM
+  MCMCMCMCCMCMCMCM
+  MCMCMCMMMMCMCMCM
+  MCMCMCCCCCCMCMCM
+  MCMCMMMMMMMMCMCM
+  MCMCCCCCCCCCCMCM
+  MCMMMMMMMMMMMMCM
+  MCCCCCCCCCCCCCCM
+  MMMMMMMMMMMMMMMM
+}
+# tile 73 (cmap 73)
+{
+  MMMMMMMHHMMMMMMM
+  MMMMMMMHHMMMMMMM
+  MMMMHHMHHMHHMMMM
+  MMMHMMMHHMMMHMMM
+  MMHMHMMMMMMHMHMM
+  MMHMMHMMMMHMMHMM
+  MMMMMMHMMHMMMMMM
+  HHHHMMMHHMMMHHHH
+  HHHHMMMHHMMMHHHH
+  MMMMMMHMMHMMMMMM
+  MMHMMHMMMMHMMHMM
+  MMHMHMMMMMMHMHMM
+  MMMHMMMHHMMMHMMM
+  MMMMHHMHHMHHMMMM
+  MMMMMMMHHMMMMMMM
+  MMMMMMMHHMMMMMMM
+}
+# tile 74 (cmap 74)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMNNNNNMMMMM
+  MMMMMMMMNMMMMMMM
+  MMMNNNNMNMNNNMMM
+  MMMNMMNMNMNMNMMM
+  MNMNNNNMNMNMNMMM
+  MNMMMMMMNMNNNMNM
+  MNNNNNNNNMMMMMNM
+  MNMMMMMNNNNNNNNM
+  MNMNNNMNMMMMMMNM
+  MMMNMNMNMNNNNMNM
+  MMMNMNMNMNMMNMMM
+  MMMNNNMNMNNNNMMM
+  MMMMMMMNMMMMMMMM
+  MMMMMNNNNNMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 75 (cmap 75)
+{
+  AAAAAAADDDDDDAAA
+  AAAAADDDDDDDDDDD
+  AAAADDDDDDDDDDDD
+  AAADDDDDDCCDDDDD
+  AAADDDCCCCCCDDDD
+  AADDDDCCCCCDDDDD
+  AADDDCCCCCDDDDDD
+  AADDDCCCCDDDDDMM
+  AADDDCCCDDDDMMMM
+  AADDDCCCDDDDMMMM
+  AADDDDDDDDDMMMMM
+  AAADDDDDDDMMMMMM
+  AAADDDDDDDMMMMMM
+  AAAADDDDDDMMMMMM
+  AAAADDDDDDMMMMMM
+  AAAADDDDDDMMMMMM
+}
+# tile 76 (cmap 76)
+{
+  AAAAAAAAAAAAAAAA
+  DDAAAAAAAAAAAAAA
+  DDDDAAAAAAAAAADD
+  DDDDDDDDDDDDDDDD
+  DDDDDDDDDDDDDDDD
+  DDDDDDDDDDDDDDDD
+  DDDDDDDCCCCCCDDD
+  MDDDDDDDDCCCCCDD
+  MMMDDDDDDDDDDDDD
+  MMMMDDDDDDDDDDDD
+  MMMMMMDDDDDDDDMM
+  MMMMMMMDDDDMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 77 (cmap 77)
+{
+  AAAAAAAAAAAAAAAA
+  AAADDDDDAAAAAAAA
+  DDDDDDDDDDDAAAAA
+  DDDDDDDDDDDDAAAA
+  DDDDDCCCDDDDDAAA
+  DDDDDCCCCDDDDDAA
+  DDDDDCCCCDDDDDDA
+  DDDDDCCCCCDDDDDD
+  DDDDDDCCCCCDDDDD
+  DDDDDDDCCCCDDDDD
+  MMMDDDDDCCCDDDDD
+  MMMDDDDDDCCDDDDD
+  MMMMDDDDDDDDDDDD
+  MMMMDDDDDDDDDDDD
+  MMMMDDDDDDDDDDDD
+  MMMMDDDDDDDDDDDA
+}
+# tile 78 (cmap 78)
+{
+  AAAADDDDDDMMMMMM
+  AAAADDDDDDDMMMMM
+  AAAADDDDDDDMMMMM
+  AAAADDDDDDDDMMMM
+  AAAADDCCCDDDMMMM
+  AAADDDDCCDDDMMMM
+  AADDDDCCCDDDMMMM
+  AADDDDCCCDDDMMMM
+  AADDDDCDDDDDMMMM
+  ADDDDDDDDDDMMMMM
+  ADDDDDDDDDMMMMMM
+  DDDDDDDDDMMMMMMM
+  DDDDDDDDMMMMMMMM
+  DDDDDDDMMMMMMMMM
+  DDDDDDDMMMMMMMMM
+  DDCCDDDMMMMMMMMM
+}
+# tile 79 (cmap 79)
+{
+  MMMMDDDDDDDDDDDA
+  MMMMDDDDDDDDDDDA
+  MMMMDDDDDDDDDDAA
+  MMMMDDDDDDDDDDAA
+  MMMDDDDDDDDDDDAA
+  MMDDDCCDDDDDDAAA
+  MMDDDCCDDDDDDAAA
+  MMDDDCCDDDDDAAAA
+  MMDDDCCDDDDDAAAA
+  MMDDDDDDDDDDAAAA
+  MMMDDDDDDDDDAAAA
+  MMMDDDDDDDDDAAAA
+  MMMMDDDDDDDDDAAA
+  MMMMMDDDDDDDDAAA
+  MMMMMMDDDDDDDDAA
+  MMMMMMMDDDDDDDAA
+}
+# tile 80 (cmap 80)
+{
+  DDDCDDDMMMMMMMMM
+  DDDCDDDMMMMMMMMM
+  ADDCDDDMMMMMMMMM
+  ADDDDDDDMMMMMMMM
+  ADDDDDDDDDDDDMMM
+  AADDDDDDDDDDDDDD
+  AADDDDDDDDDDDDDD
+  AAADDDDDDDDCDDDD
+  AAAAADDDDDDCCCCD
+  AAAAAAADDDDDCCCD
+  AAAAAAAAADDDDCCC
+  AAAAAAAAAADDDDCC
+  AAAAAAAAAAADDDDD
+  AAAAAAAAAAADDDDD
+  AAAAAAAAAAAADDDD
+  AAAAAAAAAAAAAADD
+}
+# tile 81 (cmap 81)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMDDD
+  MMMMMMMMMMMMDDDD
+  DMMMMMMMMMMMDDDD
+  DDMMMMMMMMMMDDDC
+  DDDMMMMMMMMMDDDC
+  DDDDMMMMMMMMDDDC
+  DDDDDDMMMMDDDDDC
+  DDDDDDDDDDDDDDDC
+  DDDDDDDDDDDDDDDC
+  DDDDDDDDDDDDDDDD
+  DDDDDDDDDDDDDDDD
+  DDDDDDDDDDDDDDAA
+}
+# tile 82 (cmap 82)
+{
+  MMMMMMDDDDDDDDAA
+  MMMMMMDDDDDDDDDA
+  MMMMMDDDDDDDDDDA
+  MMMMDDDDDDDDDDDA
+  DDDDDDDDDDDDDDDA
+  DDDDDDDDDDDDDDDA
+  CCCDDDDDDDDDDDAA
+  CCCCDDDDDDDDDDAA
+  CCCDDDDDDDDDDDAA
+  CCDDDDDDDDDDDAAA
+  CCDDDDDDAAAAAAAA
+  CDDDDDAAAAAAAAAA
+  CDDDDAAAAAAAAAAA
+  DDDDAAAAAAAAAAAA
+  DDAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+}
+# tile 83 (explosion dark 0)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMAAA
+  MMMMMMAMMMAAAAAA
+  MMMMMMMMMAAAAAAA
+  MMMMMMMMMAAAAAAM
+  MMMMMMMMAAAAMMMA
+  MMMAAAMAAAAMMMAA
+  MAMMMAAAAAAMAAAA
+  MMMMMAAAAAAMAAAA
+  MMMMAAAAAAAMAAAA
+  MMMMMMMMAAMMAAMM
+  MMMMAAAAAAAAAAMM
+  MMMAAAAMMAAAMMMM
+  MMAAAAMMAAAAMMMM
+  MMAAAMMAAAAAMMMM
+}
+# tile 84 (explosion dark 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  AMMMMMMMMAAAAAAM
+  AAAAAAMAAAAAAAAM
+  AAAAAAMMMMMAAAAA
+  MMMAAAMAAAAAAAAA
+  AAAAAAMAAAAAAAAA
+  AAAAAAMAAAAAAAAM
+  AAMMMMMMMMMMMAMM
+  MMAAAMAMMMMMAAAA
+  MAMAMAMMMAMMMAAA
+  MPPAMMMAAMMMMMAA
+  MAMMMMMAMMMMAAAA
+  MMMMMAMMAMMMPAAA
+  MMMMMMMMAMAMAPAA
+  MPAMMMAPAAAAAAAA
+}
+# tile 85 (explosion dark 2)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMAMMMAMMM
+  AAAAAMMMMMMMMMMM
+  AAAAAAMMMAMMAMMM
+  AAAAAAAMMMMMMMMM
+  MMMMMMAAAAMMMMMM
+  AAAAAMMAAAAMMMMM
+  MMAAAAAAAAAAMMMM
+  AAMAAMMMMAAAMMMM
+  AAMAAAAAMAAAMMMM
+  AAPAAMAAAAAAMAMM
+  AAAMMMMMAAAAMMMM
+  AAMAMMAMAAAAMMMM
+  AMAAMMAMAAAAAMMM
+}
+# tile 86 (explosion dark 3)
+{
+  MMAAAMAMAAAMMMMM
+  MMAAAMAAAAAMAPMM
+  MMMAAMAAMMMMMMMA
+  MMMAAAAAAMMMMPPM
+  MMAAAMAAMMAMMPAP
+  MAAAMMMAMMMMPMAP
+  MAAAMAAAMAMMPMMP
+  MAAAMAAAMMMAAAAP
+  MAAAMAAAMMMMPAAA
+  MAAAMMAAMMMMPPAA
+  MMAAAMMAAMMMPAAP
+  MMMAAAMMMAPMPPPP
+  MMMMAAAMMMPMMPMA
+  MMMMMAAMMMMMAAAM
+  MMAMAMMMAAPMMMPA
+  MMMMAMMMMMMMMMPA
+}
+# tile 87 (explosion dark 4)
+{
+  APAAAMMPPAPAAAAA
+  MAPAMMAMAAAPAAAM
+  AAPMPAAMMAAAAAAM
+  PAPPPAAAMMAAPAMM
+  AAAPPAAAAPAAPMMA
+  AAPPMPPPAAAAAMMA
+  AAPAAAAAAAAAAAMM
+  APPAAAAAAAAAAAMM
+  AAAAAAAAAAAAPAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAMAA
+  AAAAAAAAAAAMHHMM
+}
+# tile 88 (explosion dark 5)
+{
+  MMAAAMAMAMAAAAMM
+  MMAAAAAMAMAAAAMM
+  MMAAAAAMAMAAAAMM
+  PMAAAAAMMMAAAAMM
+  PMAAPAPAAMAAAAMM
+  PMMMPMMAMMAAAMMM
+  MMMAPMMAAAAAAMMM
+  MPAAPAAAAAAAAMMM
+  AAPMMMPAAAAAMMMM
+  MMAAMPPAAMAMMMAM
+  AMMMPPMMMMMMMMMM
+  MAAAAPPAAMMMAMMM
+  MMAAMPPMAAAMMMMM
+  AMMMMMMAAAAAMMMM
+  AAAMMMAAAAAAAMMM
+  MMMMPPAAAAAAAAMM
+}
+# tile 89 (explosion dark 6)
+{
+  MMMMAMMMMMMMAMMP
+  MMMMAMMMMMMMAAMM
+  MAMMAAMMMPMMAMAM
+  MMMAAAMAMMPMMAAP
+  MMMAAAAMMAAPMMAM
+  MMMAAAAMMMMPMMMA
+  MMMAAAAMMAMMAMMA
+  MMMAAAAAMAAAMMMM
+  MMMAAAAAMMAAMMMM
+  MMMMAAAAAAAAAMMM
+  MMMMMAAAAAAAAAAA
+  MMMAMMAAAAAAAAAA
+  MMMMMMMMAAMAAAAA
+  MMMAMMMMMMMMAAAA
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 90 (explosion dark 7)
+{
+  PPPAAAAAPAAAMAMM
+  AAPPAAPPPPAMAMMM
+  PPPPPPPPPPAMMAPP
+  MPPAAMAAMAPAAMMM
+  MMAAAAMAMMAAAPAA
+  APPAPAPMAMAMPAAM
+  AMMPPAAAMMMMMMMP
+  AAMMMMMMMAMMMMMM
+  PAPAMAAAAAAAAAAP
+  AAMAPAAAAMMMMMMA
+  AAAMAMPPMMMAAAAA
+  AAAAAAMAMMAAAAAA
+  AAAAAAAAAAAAAAAA
+  AAAAMMMMMMMMMMAA
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 91 (explosion dark 8)
+{
+  MMMMPMMAAAAAAAMM
+  MMAMMAMAAMAMAAMM
+  PPMMAMMAAMAMAAMM
+  MMMAAAMAAMAMAAMM
+  MAAAAAMAAAMMAAMM
+  MMPAAMMAAAMAAAMM
+  MAAAMMAAAMMAAAMM
+  MAMAAMAAAAAAAAMM
+  AAMAAAAAAMAAAAMM
+  MMMAAAAAAAAAAAMM
+  MAAAAAAAAMAAAMMM
+  AAAAAAAAMMMMMMMM
+  AAAAAAMMMMAMMMMM
+  AAAMMMAMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 92 (explosion noxious 0)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMFFF
+  MMMMMMFMMMFFFFFF
+  MMMMMMMMMFFFFFFF
+  MMMMMMMMMFFFFFFM
+  MMMMMMMMFFFFMMMF
+  MMMFFFMFFFFMMMFF
+  MFMMMFFFFFFMFFFF
+  MMMMMFFFFFFMFFFF
+  MMMMFFFFFFFMFFFF
+  MMMMMMMMFFMMFFMM
+  MMMMFFFFFFFFFFMM
+  MMMFFFFMMFFFMMMM
+  MMFFFFMMFFFFMMMM
+  MMFFFMMFFFFFMMMM
+}
+# tile 93 (explosion noxious 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  FMMMMMMMMFFFFFFM
+  FFFFFFMFFFFFFFFM
+  FFFFFFMMMMMFFFFF
+  MMMFFFMFFFFFFFFF
+  FFFFFFMFFFFFFFFF
+  FFFFFFMFFFFFFFFM
+  FFMMMMMMMMMMMFMM
+  MMFFFMFMMMMMFFFF
+  MHMFMFMMMFMMMFFF
+  MGGFMMMFFMMMMMFF
+  MHMMMMMFMMMMFFFF
+  MMMMMFMMFMMMGFFF
+  MMMMMMMMFMFMFGFF
+  MGHMMMHGHHFFFFFF
+}
+# tile 94 (explosion noxious 2)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMFMMMFMMM
+  FFFFFMMMMMMMMMMM
+  FFFFFFMMMFMMFMMM
+  FFFFFFFMMMMMMMMM
+  MMMMMMFFFFMMMMMM
+  FFFFFMMFFFFMMMMM
+  MMFFFFFFFFFFMMMM
+  FFMFFMMMMFFFMMMM
+  FFMFFFFFMFFFMMMM
+  FFGFFMFFFFFFMFMM
+  FFFMMMMMFFFFMMMM
+  FFMFMMFMFFFFMMMM
+  FMFFMMFMFFFFFMMM
+}
+# tile 95 (explosion noxious 3)
+{
+  MMFFFMFMFFFMMMMM
+  MMFFFMFFFFFMFGMM
+  MMMFFMFFMMMMMMMF
+  MMMFFFFFFMMMMGGM
+  MMFFFMFFMMFMMGFG
+  MFFFMMMFMMMMGMFG
+  MFFFMFFFMHMMGMMG
+  MFFFMFFFMMMFFFFG
+  MFFFMFFFMMMMGFHH
+  MFFFMMFFMMMMGGHH
+  MMFFFMMFFMMMGHHG
+  MMMFFFMMMFGMGGGG
+  MMMMFFFMMMGMMGMH
+  MMMMMFFMMMMMHHFM
+  MMFMFMMMFHGMMMGH
+  MMMMFMMMMMMMMMGH
+}
+# tile 96 (explosion noxious 4)
+{
+  FGHFFMMGGFGHFFFF
+  MHGHMMFMFFHGFHFM
+  HFGMGHFMMHHHFFHM
+  GFGGGHHHMMHHGFMM
+  HHHGGHHHHGHHGMMF
+  HHGGMGGGHHHHFMMF
+  HHGHHHHHHHHHHFMM
+  HGGHHHHHHHHHHHMM
+  HHHHHHNNNNHHGHNH
+  GHHHHHHHNHHHHHNH
+  GHHGHGNNNNHHHHGF
+  GGNHNHNNNNHHHGGF
+  HHHHNHNNNHHHGGGG
+  HGGNGHNNNHHHGGGF
+  HHHHNHNHNMGGGMGF
+  GGGGNHHHGGGMHHMM
+}
+# tile 97 (explosion noxious 5)
+{
+  MMFFFMFMFMFFFFMM
+  MMFFFFFMFMFFFFMM
+  MMFFFFFMFMFFFFMM
+  GMFFFFFMMMFFFFMM
+  GMFFGFGFFMFFFFMM
+  GMMMGMGFMMFFFMMM
+  MMMFGMMFFFFFFMMM
+  MGFFFFFFFFFFFMMM
+  FFGMMMGFFFFFMMMM
+  MMFFMGGFFMFMMMFM
+  FMMMGGMMMMMMMMMM
+  MFFFFGGFFMMMFMMM
+  MMHFMGGMFFFMMMMM
+  HMMMMMMFFFFFMMMM
+  HFHMMMFFFFFFFMMM
+  MMMMGGFFFFFFFFMM
+}
+# tile 98 (explosion noxious 6)
+{
+  MMMMFMMMMMMMHMMG
+  MMMMFMMMMMMMFHMM
+  MFMMFFMMMGMMFMHM
+  MMMFFFMFMMGMMFFG
+  MMMFFFFMMFFGMMFM
+  MMMFFFFMMMMGMMMF
+  MMMFFFFMMFMMHMMF
+  MMMFFFFFMFFFMMMM
+  MMMFFFFFMMFFMMMM
+  MMMMFFFFFFFFFMMM
+  MMMMMFFFHFFFFFFF
+  MMMFMMFFFFFFFFFF
+  MMMMMMMMFFMFFFFF
+  MMMFMMMMMMMMFFFF
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 99 (explosion noxious 7)
+{
+  GGGHHHHHGHHHMHMM
+  HHGGHHGGGGHMFMMM
+  GGGGGGGGGGFMMFGG
+  MGGHFMFFMHGFFMMM
+  MMHHHHMFMMFFHGHF
+  HGGFGFGMHMHMGFFM
+  FMMGGFFHMMMMMMMG
+  HFMMMMMMMFMMMMMM
+  GHGFMFFFFFFFFFFG
+  HFMHGHFFFMMMMMMF
+  FFFMFMGGMMMFFFFF
+  FFFFFFMFMMFFFFFF
+  FFFFFFFFFFFFFFFF
+  FFFFMMMMMMMMMMFF
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 100 (explosion noxious 8)
+{
+  MMMMGMMFFFFFFFMM
+  MMFMMFMFFMFMFFMM
+  GGMMFMMFFMFMFFMM
+  MMMFFFMFFMFMFFMM
+  MFFFFFMFFFMMFFMM
+  MMGFFMMFFFMFFFMM
+  MFFFMMFFFMMFFFMM
+  MFMFFMFFFFFFFFMM
+  FFMFFFFFFMFFFFMM
+  MMMFFFFFFFFFFFMM
+  MFFFFFFFFMFFFMMM
+  FFFFFFFFMMMMMMMM
+  FFFFFFMMMMFMMMMM
+  FFFMMMFMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 101 (explosion muddy 0)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMJJJ
+  MMMMMMJMMMJJJJJJ
+  MMMMMMMMMJJJJJJJ
+  MMMMMMMMMJJJJJJK
+  MMMMMMMMJJJJKKKJ
+  MMMJJJMJJJJKKKJJ
+  MJMMMJJJJJJKJJJJ
+  MMMMMJJJJJJKJJJJ
+  MMMMJJJJJJJKJJJJ
+  MMMMMMMKJJKKJJKK
+  MMMMJJJJJJJJJJKK
+  MMMJJJJKKJJJKKKK
+  MMJJJJKKJJJJKKKK
+  MMJJJKKJJJJJKKKK
+}
+# tile 102 (explosion muddy 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  JMMMMMMMMJJJJJJM
+  JJJJJJKJJJJJJJJM
+  JJJJJJKKKKKJJJJJ
+  KKKJJJKJJJJJJJJJ
+  JJJJJJKJJJJJJJJJ
+  JJJJJJKJJJJJJJJK
+  JJKKKKKKKKKKKJKK
+  KKJJJKJKKKKKJJJJ
+  KLKJKJKKKJKKKJJJ
+  KCCJKKKJJKKKKKJJ
+  KLKKKKKJKKKKJJJJ
+  KKKKKJKKJKKKCJJJ
+  KKKKKKKKJKJKJCJJ
+  KCLKKKLCLLJJJJJJ
+}
+# tile 103 (explosion muddy 2)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMJMMMJMMM
+  JJJJJMMMMMMMMMMM
+  JJJJJJMMMJMMJMMM
+  JJJJJJJMMMMMMMMM
+  KKKKKKJJJJMMMMMM
+  JJJJJKKJJJJMMMMM
+  KKJJJJJJJJJJMMMM
+  JJKJJKKKKJJJMMMM
+  JJKJJJJJKJJJMMMM
+  JJCJJKJJJJJJMJMM
+  JJJKKKKKJJJJMMMM
+  JJKJKKJKJJJJMMMM
+  JKJJKKJKJJJJJMMM
+}
+# tile 104 (explosion muddy 3)
+{
+  MMJJJKJKJJJKKKKK
+  MMJJJKJJJJJKJCKK
+  MMMJJKJJKKKKKKKJ
+  MMMJJJJJJKKKKCCK
+  MMJJJKJJKKJKKCJC
+  MJJJKKKJKKKKCKJC
+  MJJJKJJJKLKKCKKC
+  MJJJKJJJKKKJJJJC
+  MJJJKJJJKKKKCJLL
+  MJJJKKJJKKKKCCLL
+  MMJJJKKJJKKKCLLC
+  MMMJJJKKKJCKCCCC
+  MMMMJJJKKKCKKCKL
+  MMMMMJJKKKKKLLJK
+  MMJMJKKKJLCKKKCL
+  MMMMJKKKKKKKKKCL
+}
+# tile 105 (explosion muddy 4)
+{
+  JCLJJKKCCJCLJJJJ
+  KLCLKKJKJJLCJLJK
+  LJCKCLJKKLLLJJLK
+  CJCCCLLLKKLLCJKK
+  LLLCCLLLLCLLCKKJ
+  LLCCKCCCLLLLJKKJ
+  LLCLLLLLLLLLLJKK
+  LCCLLLLLLLLLLLKK
+  LLLLLLCCCCLLCLCL
+  CLLLLLLLCLLLLLCL
+  CLLCLCCCCCLLLLCJ
+  CCCLCLCCCCLLLCCJ
+  LLLLCLCCCLLLCCCC
+  LCCCCLCCCLLLCCCJ
+  LLLLCLCLCKCCCKCJ
+  CCCCCLLLCCCKLLKK
+}
+# tile 106 (explosion muddy 5)
+{
+  KKJJJKJKJKJJJJMM
+  KKJJJJJKJKJJJJMM
+  KKJJJJJKJKJJJJMM
+  CKJJJJJKKKJJJJMM
+  CKJJCJCJJKJJJJMM
+  CKKKCKKJKKJJJMMM
+  KKKJCKKJJJJJJMMM
+  KCJJCJJJJJJJJMMM
+  JJCKKKCJJJJJMMMM
+  KKJJKCCJJKJMMMJM
+  JKKKCCKKKKMMMMMM
+  KJJJJCCJJKMMJMMM
+  KKLJKCCKJJJMMMMM
+  LKKKKKKJJJJJMMMM
+  LJLKKKJJJJJJJMMM
+  KKKKCCJJJJJJJJMM
+}
+# tile 107 (explosion muddy 6)
+{
+  MMMMJKKKKKKKLKKC
+  MMMMJKKKKKKKJLKK
+  MJMMJJKKKCKKJKLK
+  MMMJJJKJKKCKKJJC
+  MMMJJJJKKJJCKKJK
+  MMMJJJJKKKKCKKKJ
+  MMMJJJJKKJKKLKKJ
+  MMMJJJJJKJJJKKKK
+  MMMJJJJJKKJJKKKK
+  MMMMJJJJJJJJJKKK
+  MMMMMJJJLJJJJJJJ
+  MMMJMMJJJJJJJJJJ
+  MMMMMMMMJJMJJJJJ
+  MMMJMMMMMMMMJJJJ
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 108 (explosion muddy 7)
+{
+  CCCLLLLLCLLLKLKK
+  LLCCLLCCCCLKJKKK
+  CCCCCCCCCCJKKJCC
+  KCCLJKJJKLCJJKKK
+  KKLLLLKJKKJJLCLJ
+  LCCJCJCKLKLKCJJK
+  JKKCCJJLKKKKKKKC
+  LJKKKKKKKJKKKKKK
+  CLCJKJJJJJJJJJJC
+  LJKLCLJJJKKKKKKJ
+  JJJKJKCCKKKJJJJJ
+  JJJJJJKJKKJJJJJJ
+  JJJJJJJJJJJJJJJJ
+  JJJJMMMMMMMMMMJJ
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 109 (explosion muddy 8)
+{
+  KKKKCKKJJJJJJJMM
+  KKJKKJKJJKJKJJMM
+  CCKKJKKJJKJKJJMM
+  KKKJJJKJJKJKJJMM
+  KJJJJJKJJJKKJJMM
+  KKCJJKKJJJKJJJMM
+  KJJJKKJJJKKJJJMM
+  KJKJJKJJJJJJJJMM
+  JJKJJJJJJKJJJJMM
+  KKKJJJJJJJJJJJMM
+  KJJJJJJJJMJJJMMM
+  JJJJJJJJMMMMMMMM
+  JJJJJJMMMMJMMMMM
+  JJJMMMJMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 110 (explosion wet 0)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMEEE
+  MMMMMMEMMMEEEEEE
+  MMMMMMMMMEEEEEEE
+  MMMMMMMMMEEEEEEP
+  MMMMMMMMEEEEPPPE
+  MMMEEEMEEEEPPPEE
+  MEMMMEEEEEEPEEEE
+  MMMMMEEEEEEPEEEE
+  MMMMEEEEEEEPEEEE
+  MMMMMMMPEEPPEEPP
+  MMMMEEEEEEEEEEPP
+  MMMEEEEPPEEEPPPP
+  MMEEEEPPEEEEPPPP
+  MMEEEPPEEEEEPPPP
+}
+# tile 111 (explosion wet 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  EMMMMMMMMEEEEEEM
+  EEEEEEPEEEEEEEEM
+  EEEEEEPPPPPEEEEE
+  PPPEEEPEEEEEEEEE
+  EEEEEEPEEEEEEEEE
+  EEEEEEPEEEEEEEEP
+  EEPPPPPPPPPPPEPP
+  PPEEEPEPPPPPEEEE
+  PNPEPEPPPEPPPEEE
+  PBBEPPPEEPPPPPEE
+  PNPPPPPEPPPPEEEE
+  PPPPPEPPEPPPBEEE
+  PPPPPPPPEPEPEBEE
+  PBNPPPNBEEEEEEEE
+}
+# tile 112 (explosion wet 2)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMEMMMEMMM
+  EEEEEMMMMMMMMMMM
+  EEEEEEMMMEMMEMMM
+  EEEEEEEMMMMMMMMM
+  PPPPPPEEEEMMMMMM
+  EEEEEPPEEEEMMMMM
+  PPEEEEEEEEEEMMMM
+  EEPEEPPPPEEEMMMM
+  EEPEEEEEPEEEMMMM
+  EEBEEPEEEEEEMEMM
+  EEEPPPPPEEEEMMMM
+  EEPEPPEPEEEEMMMM
+  EPEEPPEPEEEEEMMM
+}
+# tile 113 (explosion wet 3)
+{
+  MMEEEPEPEEEPPPPP
+  MMEEEPEEEEEPEBPP
+  MMMEEPEEPPPPPPPE
+  MMMEEEEEEPPPPBBP
+  MMEEEPEEPPEPPBEB
+  MEEEPPPEPPPPBPEB
+  MEEEPEEEPNPPBPPB
+  MEEEPEEEPPPEEEEB
+  MEEEPEEEPPPPBEEE
+  MEEEPPEEPPPPBBEE
+  MMEEEPPEEPPPBEEB
+  MMMEEEPPPEBPBBBB
+  MMMMEEEPPPBPPBPN
+  MMMMMEEPPPPPNNEP
+  MMEMEPPPENBPPPBE
+  MMMMEPPPPPPPPPBE
+}
+# tile 114 (explosion wet 4)
+{
+  EBNEEPPBBEBNEEEE
+  PNBNPPEPEEEBENEP
+  NEBPBEEPPEEEEENP
+  BEBBBEEEPPEEBEPP
+  EEEBBEEEEBEEBPPE
+  EEBBPBBBEEEEEPPE
+  EEBEEEEEEEEEEEPP
+  EBBEEEEEEEEEEEPP
+  EEEEEEEEEEEEBEEE
+  BEEEEEEEEEEEEEEE
+  BEEBEBEEEEEEEEBE
+  BBEEEEEEEEEEEBBE
+  EEEEEEEEEEEEBBBB
+  EBBEBEEEEEEEBBBE
+  EEEEEEEEEPBBBPBE
+  BBBBEEEEBBBPNNPP
+}
+# tile 115 (explosion wet 5)
+{
+  PPEEEPEPEPEEEEMM
+  PPEEEEEPEPEEEEMM
+  PPEEEEEPEPEEEEMM
+  BPEEEEEPPPEEEEMM
+  BPEEBEBEEPEEEEMM
+  BPPPBPPEPPEEEMMM
+  PPPEBPPEEEEEEMMM
+  PBEEBEEEEEEEEMMM
+  EEBPPPBEEEEEMMMM
+  PPEEPBBEEPEMMMEM
+  EPPPBBPPPPMMMMMM
+  PEEEEBBEEPMMEMMM
+  PPNEPBBPEEEMMMMM
+  NPPPPPPEEEEEMMMM
+  NENPPPEEEEEEEMMM
+  PPPPBBEEEEEEEEMM
+}
+# tile 116 (explosion wet 6)
+{
+  MMMMEPPPPPPPNPPB
+  MMMMEPPPPPPPENPP
+  MEMMEEPPPBPPEPNP
+  MMMEEEPEPPBPPEEB
+  MMMEEEEPPEEBPPEP
+  MMMEEEEPPPPBPPPE
+  MMMEEEEPPEPPNPPE
+  MMMEEEEEPEEEPPPP
+  MMMEEEEEPPEEPPPP
+  MMMMEEEEEEEEEPPP
+  MMMMMEEENEEEEEEE
+  MMMEMMEEEEEEEEEE
+  MMMMMMMMEEMEEEEE
+  MMMEMMMMMMMMEEEE
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 117 (explosion wet 7)
+{
+  BBBEEEEEBEEEPEPP
+  EEBBEEBBBBEPEPPP
+  BBBBBBBBBBEPPEBB
+  PBBEEPEEPNBEEPPP
+  PPEEEEPEPPEENBNE
+  NBBEBEBPNPNPBEEP
+  EPPBBEENPPPPPPPB
+  NEPPPPPPPEPPPPPP
+  BNBEPEEEEEEEEEEB
+  NEPNBNEEEPPPPPPE
+  EEEPEPBBPPPEEEEE
+  EEEEEEPEPPEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEMMMMMMMMMMEE
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 118 (explosion wet 8)
+{
+  PPPPBPPEEEEEEEMM
+  PPEPPEPEEPEPEEMM
+  BBPPEPPEEPEPEEMM
+  PPPEEEPEEPEPEEMM
+  PEEEEEPEEEPPEEMM
+  PPBEEPPEEEPEEEMM
+  PEEEPPEEEPPEEEMM
+  PEPEEPEEEEEEEEMM
+  EEPEEEEEEPEEEEMM
+  PPPEEEEEEEEEEEMM
+  PEEEEEEEEMEEEMMM
+  EEEEEEEEMMMMMMMM
+  EEEEEEMMMMEMMMMM
+  EEEMMMEMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 119 (explosion magical 0)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMEEE
+  MMMMMMEMMMEEEEEE
+  MMMMMMMMMEEEEEEE
+  MMMMMMMMMEEEEEEC
+  MMMMMMMMEEEEIIIE
+  MMMEEEMEEEEIIIEE
+  MEMMMEEEEEEIEEEE
+  MMMMMEEEEEEIEEEE
+  MMMMEEEEEEEIEEEE
+  MMMMMMMIEEIIEEII
+  MMMMEEEEEEEEEEII
+  MMMEEEEIIEEEIIII
+  MMEEEEIIEEEEIIII
+  MMEEEIIEEEEEIIII
+}
+# tile 120 (explosion magical 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  EMMMMMMMMEEEEEEM
+  EEEEEEIEEEEEEEEM
+  EEEEEEIIIIIEEEEE
+  IIIEEEIEEEEEEEEE
+  EEEEEEIEEEEEEEEE
+  EEEEEEIEEEEEEEEI
+  EEIIIIIIIIIIIEII
+  IIEEEIEIIIIIEEEE
+  IHIEIEIIIEIIIEEE
+  ILLEIIIEEIIIIIEE
+  IHIIIIIEIIIIEEEE
+  IIIIIEIIEIIILEEE
+  IIIIIIIIEIEIELEE
+  ILHIIIHLHHEEEEEE
+}
+# tile 121 (explosion magical 2)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMEMMMEMMM
+  EEEEEMMMMMMMMMMM
+  EEEEEEMMMEMMEMMM
+  EEEEEEEMMMMMMMMM
+  IIIIIIEEEEMMMMMM
+  EEEEEIIEEEEMMMMM
+  IIEEEEEEEEEEMMMM
+  EEIEEIIIIEEEMMMM
+  EEIEEEEEIEEEMMMM
+  EELEEIEEEEEEMEMM
+  EEEIIIIIEEEEMMMM
+  EEIEIIEIEEEEMMMM
+  EIEEIIEIEEEEEMMM
+}
+# tile 122 (explosion magical 3)
+{
+  MMEEEIEIEEEIIIII
+  MMEEEIEEEEEIEIII
+  MMMEEIEEIIIIIIIE
+  MMMEEEEEEIIIIIII
+  MMEEEIEEIIEIIIEI
+  MEEEIIIEIIIIIIEI
+  MEEEIEEEINIIIIII
+  MEEEIEEEIIIEEEEI
+  MEEEIEEEIIIIIENN
+  MEEEIIEEIIIIIINN
+  MMEEEIIEEIIIINNI
+  MMMEEEIIIEIIIIII
+  MMMMEEEIIIIIIIIN
+  MMMMMEEIIIIINNEI
+  MMEMEIIIENIIIIIN
+  MMMMEIIIIIIIIIIN
+}
+# tile 123 (explosion magical 4)
+{
+  EINEEIIIIEINEEEE
+  ININIIEIEENIENEI
+  NEIIINEIINNNEENI
+  IEIIINNNIINNIEII
+  NNNIINNNNINNIIIE
+  NNIIIIIINNNNEIIE
+  NNINNNNNNNNNNEII
+  NIINNNNNNNNNNNII
+  NNNNNNNNNNNNINNN
+  INNNNNNNNNNNNNNN
+  INNININNNNNNNNIE
+  IINNNNNNNNNNNIIE
+  NNNNNNNNNNNNIIII
+  NIININNNNNNNIIIE
+  NNNNNNNNNIIIIIIE
+  IIIINNNNIIIINNII
+}
+# tile 124 (explosion magical 5)
+{
+  IIEEEIEIEIEEEEMM
+  IIEEEEEIEIEEEEMM
+  IIEEEEEIEIEEEEMM
+  IIEEEEEIIIEEEEMM
+  IIEEIEIEEIEEEEMM
+  IIIIIIIEIIEEEMMM
+  IIIEIIIEEEEEEMMM
+  IIEEIEEEEEEEEMMM
+  EEIIIIIEEEEEMMMM
+  IIEEIIIEEIEMMMEM
+  EIIIIIIIIIMMMMMM
+  IEEEEIIEEIMMEMMM
+  IINEIIIIEEEMMMMM
+  NIIIIIIEEEEEMMMM
+  NENIIIEEEEEEEMMM
+  IIIIIIEEEEEEEEMM
+}
+# tile 125 (explosion magical 6)
+{
+  MMMMEIIIIIIIHIII
+  MMMMEIIIIIIIEHII
+  MEMMEEIIIIIIEIHI
+  MMMEEEIEIIIIIEEI
+  MMMEEEEIIEEIIIEI
+  MMMEEEEIIIIIIIIE
+  MMMEEEEIIEIIHIIE
+  MMMEEEEEIEEEIIII
+  MMMEEEEEIIEEIIII
+  MMMMEEEEEEEEEIII
+  MMMMMEEEHEEEEEEE
+  MMMEMMEEEEEEEEEE
+  MMMMMMMMEEMEEEEE
+  MMMEMMMMMMMMEEEE
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 126 (explosion magical 7)
+{
+  IIINNNNNINNNINII
+  NNIINNIIIINIEIII
+  IIIIIIIIIIEIIEII
+  IIINEIEEINIEEIII
+  IINNNNIEIIEENINE
+  NIIEIEIININIIEEI
+  EIIIIEENIIIIIIII
+  NEIIIIIIIEIIIIII
+  INIEIEEEEEEEEEEI
+  NEININEEEIIIIIIE
+  EEEIEIIIIIIEEEEE
+  EEEEEEIEIIEEEEEE
+  EEEEEEEEEEEEEEEE
+  EEEEMMMMMMMMMMEE
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 127 (explosion magical 8)
+{
+  IIIIIIIEEEEEEEMM
+  IIEIIEIEEIEIEEMM
+  IIIIEIIEEIEIEEMM
+  IIIEEEIEEIEIEEMM
+  IEEEEEIEEEIIEEMM
+  IIIEEIIEEEIEEEMM
+  IEEEIIEEEIIEEEMM
+  IEIEEIEEEEEEEEMM
+  EEIEEEEEEIEEEEMM
+  IIIEEEEEEEEEEEMM
+  IEEEEEEEEMEEEMMM
+  EEEEEEEEMMMMMMMM
+  EEEEEEMMMMEMMMMM
+  EEEMMMEMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 128 (explosion fiery 0)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMDDD
+  MMMMMMDMMMDDDDDD
+  MMMMMMMMMDDDDDDD
+  MMMMMMMMMDDDDDDC
+  MMMMMMMMDDDDCCCD
+  MMMDDDMDDDDCCCDD
+  MDMMMDDDDDDCDDDD
+  MMMMMDDDDDDCDDDD
+  MMMMDDDDDDDCDDDD
+  MMMMMMMCDDCCDDCC
+  MMMMDDDDDDDDDDCC
+  MMMDDDDCCDDDCCCC
+  MMDDDDCCDDDDCCCC
+  MMDDDCCDDDDDCCCC
+}
+# tile 129 (explosion fiery 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  DMMMMMMMMDDDDDDM
+  DDDDDDCDDDDDDDDM
+  DDDDDDCCCCCDDDDD
+  CCCDDDCDDDDDDDDD
+  DDDDDDCDDDDDDDDD
+  DDDDDDCDDDDDDDDC
+  DDCCCCCCCCCCCDCC
+  CCDDDCDCCCCCDDDD
+  CHCDCDCCCDCCCDDD
+  CLLDCCCDDCCCCCDD
+  CHCCCCCDCCCCDDDD
+  CCCCCDCCDCCCLDDD
+  CCCCCCCCDCDCDLDD
+  CLHCCCHLHHDDDDDD
+}
+# tile 130 (explosion fiery 2)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMDMMMDMMM
+  DDDDDMMMMMMMMMMM
+  DDDDDDMMMDMMDMMM
+  DDDDDDDMMMMMMMMM
+  CCCCCCDDDDMMMMMM
+  DDDDDCCDDDDMMMMM
+  CCDDDDDDDDDDMMMM
+  DDCDDCCCCDDDMMMM
+  DDCDDDDDCDDDMMMM
+  DDLDDCDDDDDDMDMM
+  DDDCCCCCDDDDMMMM
+  DDCDCCDCDDDDMMMM
+  DCDDCCDCDDDDDMMM
+}
+# tile 131 (explosion fiery 3)
+{
+  MMDDDCDCDDDCCCCC
+  MMDDDCDDDDDCDLCC
+  MMMDDCDDCCCCCCCD
+  MMMDDDDDDCCCCLLC
+  MMDDDCDDCCDCCLDL
+  MDDDCCCDCCCCLCDL
+  MDDDCDDDCHCCLCCL
+  MDDDCDDDCCCDDDDL
+  MDDDCDDDCCCCLDHH
+  MDDDCCDDCCCCLLHH
+  MMDDDCCDDCCCLHHL
+  MMMDDDCCCDLCLLLL
+  MMMMDDDCCCLCCLCH
+  MMMMMDDCCCCCHHDC
+  MMDMDCCCDHLCCCLH
+  MMMMDCCCCCCCCCLH
+}
+# tile 132 (explosion fiery 4)
+{
+  DLHDDCCLLDLHDDDD
+  CHLHCCDCDDHLDHDC
+  HDLCLHDCCHHHDDHC
+  LDLLLHHHCCHHLDCC
+  HHHLLHHHHLHHLCCD
+  HHLLCLLLHHHHDCCD
+  HHLHHHHHHHHHHDCC
+  HLLHHHHHHHHHHHCC
+  HHHHHHNNNNHHLHNH
+  LHHHHHHHNHHHHHNH
+  LHHLHLNNNNHHHHLD
+  LLNHNHNNNNHHHLLD
+  HHHHNHNNNHHHLLLL
+  HLLNLHNNNHHHLLLD
+  HHHHNHNHNCLLLCLD
+  LLLLNHHHLLLCHHCC
+}
+# tile 133 (explosion fiery 5)
+{
+  CCDDDCDCDCDDDDMM
+  CCDDDDDCDCDDDDMM
+  CCDDDDDCDCDDDDMM
+  LCDDDDDCCCDDDDMM
+  LCDDLDLDDCDDDDMM
+  LCCCLCCDCCDDDMMM
+  CCCDLCCDDDDDDMMM
+  CLDDLDDDDDDDDMMM
+  DDLCCCLDDDDDMMMM
+  CCDDCLLDDCDMMMDM
+  DCCCLLCCCCMMMMMM
+  CDDDDLLDDCMMDMMM
+  CCHDCLLCDDDMMMMM
+  HCCCCCCDDDDDMMMM
+  HDHCCCDDDDDDDMMM
+  CCCCLLDDDDDDDDMM
+}
+# tile 134 (explosion fiery 6)
+{
+  MMMMDCCCCCCCHCCL
+  MMMMDCCCCCCCDHCC
+  MDMMDDCCCLCCDCHC
+  MMMDDDCDCCLCCDDL
+  MMMDDDDCCDDLCCDC
+  MMMDDDDCCCCLCCCD
+  MMMDDDDCCDCCHCCD
+  MMMDDDDDCDDDCCCC
+  MMMDDDDDCCDDCCCC
+  MMMMDDDDDDDDDCCC
+  MMMMMDDDHDDDDDDD
+  MMMDMMDDDDDDDDDD
+  MMMMMMMMDDMDDDDD
+  MMMDMMMMMMMMDDDD
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 135 (explosion fiery 7)
+{
+  LLLHHHHHLHHHCHCC
+  HHLLHHLLLLHCDCCC
+  LLLLLLLLLLDCCDLL
+  CLLHDCDDCHLDDCCC
+  CCHHHHCDCCDDHLHD
+  HLLDLDLCHCHCLDDC
+  DCCLLDDHCCCCCCCL
+  HDCCCCCCCDCCCCCC
+  LHLDCDDDDDDDDDDL
+  HDCHLHDDDCCCCCCD
+  DDDCDCLLCCCDDDDD
+  DDDDDDCDCCDDDDDD
+  DDDDDDDDDDDDDDDD
+  DDDDMMMMMMMMMMDD
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 136 (explosion fiery 8)
+{
+  CCCCLCCDDDDDDDMM
+  CCDCCDCDDCDCDDMM
+  LLCCDCCDDCDCDDMM
+  CCCDDDCDDCDCDDMM
+  CDDDDDCDDDCCDDMM
+  CCLDDCCDDDCDDDMM
+  CDDDCCDDDCCDDDMM
+  CDCDDCDDDDDDDDMM
+  DDCDDDDDDCDDDDMM
+  CCCDDDDDDDDDDDMM
+  CDDDDDDDDMDDDMMM
+  DDDDDDDDMMMMMMMM
+  DDDDDDMMMMDMMMMM
+  DDDMMMDMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 137 (explosion frosty 0)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMEEE
+  MMMMMNEMMMEEEEEE
+  MMNMMMNMMENBEEEE
+  MNMNMNMMMEEEEEEP
+  MMMMNMMMEEEEPPPE
+  MMMNENMNEEEPPPEE
+  MENMMENEEEEPNBEE
+  MMMNMEEEEEEPEEEE
+  MMMMEENBEEEPEEEE
+  MMMMMMMPEEPPEEPP
+  MMMMEEEEEEEEEEPP
+  MMMEEEEPPEEEPPPP
+  MMEEEEPPNBEEPPPP
+  MMEEEPPEEEEEPPPP
+}
+# tile 138 (explosion frosty 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  EMMMMMMMMEEEEEEM
+  ENBEENPEEEENBEEM
+  EEEEEENPNPNEEEEE
+  PPBEEEPENEEEEEEE
+  EEEEEENNNNNEEEEE
+  EEEEEEPENEEENBEP
+  EEPPPPNPNPNPPPPP
+  PPEEENEPPPPNEEEE
+  PNPEPEPPPEPPPEEE
+  PBBEPPPEEPPNBPEE
+  PNPPPPPEPPPPEEEE
+  PPPPPEPPEPPPBEEE
+  PPPPPPPPEPEPEBEE
+  PBNPPPNBNNEEEEEE
+}
+# tile 139 (explosion frosty 2)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMEMMMEMMM
+  EEEEEMMMMMMMMMMM
+  EEEEEEMMMEMMNMMM
+  EEEEEEENMMNNMMMM
+  PPPPPPENENMMMMMM
+  EEEEEPPENENMNMMM
+  PPEEEEEEEEENMNMM
+  EEPEEPPPPNNEMNMM
+  EEPEEEEENEEEMMMM
+  EEBEEPEEEEEEMEMM
+  EEEPPPPPEEEEMMMM
+  EEPEPPEPEEEEMMMM
+  EPEEPPEPEEEEEMMM
+}
+# tile 140 (explosion frosty 3)
+{
+  MMEEEPEPEEEPPPPP
+  MMEEEPEEEEEPEBPP
+  MMMEEPEEPPPPPPPE
+  MMMENENEEPPPPBBP
+  MMEEENEEPPEPPBEB
+  MEEENENEPPPPBPEB
+  MEEEPEEEPNPPBPPB
+  MEEEPEEEPPPEEEEB
+  MEEEPEEEPPPPBENN
+  MEEEPPEEPPPPBBNN
+  MMEEEPNEEPPPBNNB
+  MMMEENNNPEBPBBBB
+  MMMMEENPPPBPPBPN
+  MMMMMEEPPPPPNNEP
+  MMEMEPPPENBPPPBN
+  MMMMEPPPPPPPPPBN
+}
+# tile 141 (explosion frosty 4)
+{
+  EBNEEPPBBEBNEEEE
+  PNBNPPEPEENBENEP
+  NEBPBNEPPNNNEENP
+  BEBBBNNNPPNNBEPP
+  NNNBBNNNNBNNBPPE
+  NNBBPBBBNNNNEPPE
+  NNBNNNNNNNNNNEPP
+  NBBNNNNNNNNNNNPP
+  NNNNNNNNNNNNBNNN
+  BNNNNNNNNNNNNNNN
+  BNNBNBNNNNNNNNBE
+  BBNNNNNNNNNNNBBE
+  NNNNNNNNNNNNBBBB
+  NBBNBNNNNNNNBBBE
+  NNNNNNNNNPBBBPBE
+  BBBBNNNNBBBPNNPP
+}
+# tile 142 (explosion frosty 5)
+{
+  PPEEEPEPEPEEEEMM
+  PPEEEEEPEPEEEEMM
+  PPEEEEEPEPEEEEMM
+  BPEEEEEPPPEEEEMM
+  BPEEBEBEEPEEEEMM
+  BPPPBPPEPPEEEMMM
+  PPPEBPPENEEENMMM
+  PBEEBEEEENENEMMM
+  EEBPPPBNNNNNNNMM
+  PPEEPBBEENENMMEM
+  EPPPBBPPNPMMNMMM
+  PEEEEBBEEPMMEMMM
+  PPNEPBBPEEEMMMMM
+  NPPPPPPEEEEEMMMM
+  NENPPPEEEEEEEMMM
+  PPPPBBEEEEEEEEMM
+}
+# tile 143 (explosion frosty 6)
+{
+  MMMMEPPPPPPPNPPB
+  MMMMEPPPPPPPENPP
+  MEMMEEPPPBPPEPNP
+  MMMEEEPEPPBPPEEB
+  MMMEENEPPEEBPPEP
+  MMMNEEENPPPBPPPE
+  MMNENPNPNEPPNPPE
+  MMMNNENNPEEEPPPP
+  MNMPEEEPPNEEPPPP
+  MMMNNENNEEEEEPPP
+  MMNMNPNENEEEEEEE
+  MMMNMMENEEEEEEEE
+  MMMMMNMMEEMEEEEE
+  MMMEMMMMMMMMEEEE
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 144 (explosion frosty 7)
+{
+  BBBNNNNNBNNNPNPP
+  NNBBNNBBBBNPEPPP
+  BBBBBBBBBBEPPEBB
+  PBBNEPEEPNBEEPPP
+  PPNNNNPEPPEENBNE
+  NBBEBEBPNPNPBEEP
+  EPPBBEENPPPPPPPB
+  NEPPPPPPPEPPPPPP
+  BNBEPEEEEEEEEEEB
+  NEPNBNEEEPNENPPE
+  EEEPEPBBPPPNEEEE
+  EEEEEEPEPNNNNNEE
+  EEEEEEEEEEENEEEE
+  EEEEMMMMMMNMNMEE
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 145 (explosion frosty 8)
+{
+  PPPPBPPEEEEEEEMM
+  PPEPPEPEEPEPEEMM
+  BBPPEPPEEPEPNENM
+  PPPEEEPEEPEPENMM
+  PEEEEEPEEEPPNENM
+  PPBEEPNENEPEEEMM
+  PEEEPPENEPPEEEMM
+  PEPEENNNNNEEEEMM
+  EEPEEEENEPEEEEMM
+  PPPEEENENEEEEEMM
+  PEEEEEEEEMEEEMMM
+  EEEEEEEEMMMMMMMM
+  EEEEEEMMMMENMMMM
+  EEEMMMEMMMNMNMMM
+  MMMMMMMMMMMNMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 146 (zap 0 0)
+{
+  MMMMMMMIIMMMMMMM
+  MMMMMMIIIIMMMMMM
+  MMMMMMIIIIMMMMMM
+  MMMMMMMIIMMMMMMM
+  MMMMMMMIIMMMMMMM
+  MMMMMMIIIIMMMMMM
+  MMMMMMIIIIMMMMMM
+  MMMMMMMIIMMMMMMM
+  MMMMMMMIIMMMMMMM
+  MMMMMMIIIIMMMMMM
+  MMMMMMIIIIMMMMMM
+  MMMMMMMIIMMMMMMM
+  MMMMMMMIIMMMMMMM
+  MMMMMMIIIIMMMMMM
+  MMMMMMIIIIMMMMMM
+  MMMMMMMIIMMMMMMM
+}
+# tile 147 (zap 0 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MIIMMIIMMIIMMIIM
+  IIIIIIIIIIIIIIII
+  IIIIIIIIIIIIIIII
+  MIIMMIIMMIIMMIIM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 148 (zap 0 2)
+{
+  IIIMMMMMMMMMMMMM
+  IIIIMMMMMMMMMMMM
+  IIIIMMMMMMMMMMMM
+  MIIIIMMMMMMMMMMM
+  MMMIIIIMMMMMMMMM
+  MMMMIIIIMMMMMMMM
+  MMMMIIIIMMMMMMMM
+  MMMMMIIIIMMMMMMM
+  MMMMMMMIIIIMMMMM
+  MMMMMMMMIIIIMMMM
+  MMMMMMMMIIIIMMMM
+  MMMMMMMMMIIIIMMM
+  MMMMMMMMMMMIIIIM
+  MMMMMMMMMMMMIIII
+  MMMMMMMMMMMMIIII
+  MMMMMMMMMMMMMIII
+}
+# tile 149 (zap 0 3)
+{
+  MMMMMMMMMMMMMIII
+  MMMMMMMMMMMMIIII
+  MMMMMMMMMMMMIIII
+  MMMMMMMMMMMIIIIM
+  MMMMMMMMMIIIIMMM
+  MMMMMMMMIIIIMMMM
+  MMMMMMMMIIIIMMMM
+  MMMMMMMIIIIMMMMM
+  MMMMMIIIIMMMMMMM
+  MMMMIIIIMMMMMMMM
+  MMMMIIIIMMMMMMMM
+  MMMIIIIMMMMMMMMM
+  MIIIIMMMMMMMMMMM
+  IIIIMMMMMMMMMMMM
+  IIIIMMMMMMMMMMMM
+  IIIMMMMMMMMMMMMM
+}
+# tile 150 (zap 1 0)
+{
+  MMMMMMMCCMMMMMMM
+  MMMMMMCCCCMMMMMM
+  MMMMMMCCCCMMMMMM
+  MMMMMMMCCMMMMMMM
+  MMMMMMMCCMMMMMMM
+  MMMMMMCCCCMMMMMM
+  MMMMMMCCCCMMMMMM
+  MMMMMMMCCMMMMMMM
+  MMMMMMMCCMMMMMMM
+  MMMMMMCCCCMMMMMM
+  MMMMMMCCCCMMMMMM
+  MMMMMMMCCMMMMMMM
+  MMMMMMMCCMMMMMMM
+  MMMMMMCCCCMMMMMM
+  MMMMMMCCCCMMMMMM
+  MMMMMMMCCMMMMMMM
+}
+# tile 151 (zap 1 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MCCMMCCMMCCMMCCM
+  CCCCCCCCCCCCCCCC
+  CCCCCCCCCCCCCCCC
+  MCCMMCCMMCCMMCCM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 152 (zap 1 2)
+{
+  CCCMMMMMMMMMMMMM
+  CCCCMMMMMMMMMMMM
+  CCCCMMMMMMMMMMMM
+  MCCCCMMMMMMMMMMM
+  MMMCCCCMMMMMMMMM
+  MMMMCCCCMMMMMMMM
+  MMMMCCCCMMMMMMMM
+  MMMMMCCCCMMMMMMM
+  MMMMMMMCCCCMMMMM
+  MMMMMMMMCCCCMMMM
+  MMMMMMMMCCCCMMMM
+  MMMMMMMMMCCCCMMM
+  MMMMMMMMMMMCCCCM
+  MMMMMMMMMMMMCCCC
+  MMMMMMMMMMMMCCCC
+  MMMMMMMMMMMMMCCC
+}
+# tile 153 (zap 1 3)
+{
+  MMMMMMMMMMMMMCCC
+  MMMMMMMMMMMMCCCC
+  MMMMMMMMMMMMCCCC
+  MMMMMMMMMMMCCCCM
+  MMMMMMMMMCCCCMMM
+  MMMMMMMMCCCCMMMM
+  MMMMMMMMCCCCMMMM
+  MMMMMMMCCCCMMMMM
+  MMMMMCCCCMMMMMMM
+  MMMMCCCCMMMMMMMM
+  MMMMCCCCMMMMMMMM
+  MMMCCCCMMMMMMMMM
+  MCCCCMMMMMMMMMMM
+  CCCCMMMMMMMMMMMM
+  CCCCMMMMMMMMMMMM
+  CCCMMMMMMMMMMMMM
+}
+# tile 154 (zap 2 0)
+{
+  MMMMMMMNNMMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMMNNMMMMMMM
+}
+# tile 155 (zap 2 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MNNMMNNMMNNMMNNM
+  NNNNNNNNNNNNNNNN
+  NNNNNNNNNNNNNNNN
+  MNNMMNNMMNNMMNNM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 156 (zap 2 2)
+{
+  NNNMMMMMMMMMMMMM
+  NNNNMMMMMMMMMMMM
+  NNNNMMMMMMMMMMMM
+  MNNNNMMMMMMMMMMM
+  MMMNNNNMMMMMMMMM
+  MMMMNNNNMMMMMMMM
+  MMMMNNNNMMMMMMMM
+  MMMMMNNNNMMMMMMM
+  MMMMMMMNNNNMMMMM
+  MMMMMMMMNNNNMMMM
+  MMMMMMMMNNNNMMMM
+  MMMMMMMMMNNNNMMM
+  MMMMMMMMMMMNNNNM
+  MMMMMMMMMMMMNNNN
+  MMMMMMMMMMMMNNNN
+  MMMMMMMMMMMMMNNN
+}
+# tile 157 (zap 2 3)
+{
+  MMMMMMMMMMMMMNNN
+  MMMMMMMMMMMMNNNN
+  MMMMMMMMMMMMNNNN
+  MMMMMMMMMMMNNNNM
+  MMMMMMMMMNNNNMMM
+  MMMMMMMMNNNNMMMM
+  MMMMMMMMNNNNMMMM
+  MMMMMMMNNNNMMMMM
+  MMMMMNNNNMMMMMMM
+  MMMMNNNNMMMMMMMM
+  MMMMNNNNMMMMMMMM
+  MMMNNNNMMMMMMMMM
+  MNNNNMMMMMMMMMMM
+  NNNNMMMMMMMMMMMM
+  NNNNMMMMMMMMMMMM
+  NNNMMMMMMMMMMMMM
+}
+# tile 158 (zap 3 0)
+{
+  MMMMMMMBBMMMMMMM
+  MMMMMMBBBBMMMMMM
+  MMMMMMBBBBMMMMMM
+  MMMMMMMBBMMMMMMM
+  MMMMMMMBBMMMMMMM
+  MMMMMMBBBBMMMMMM
+  MMMMMMBBBBMMMMMM
+  MMMMMMMBBMMMMMMM
+  MMMMMMMBBMMMMMMM
+  MMMMMMBBBBMMMMMM
+  MMMMMMBBBBMMMMMM
+  MMMMMMMBBMMMMMMM
+  MMMMMMMBBMMMMMMM
+  MMMMMMBBBBMMMMMM
+  MMMMMMBBBBMMMMMM
+  MMMMMMMBBMMMMMMM
+}
+# tile 159 (zap 3 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MBBMMBBMMBBMMBBM
+  BBBBBBBBBBBBBBBB
+  BBBBBBBBBBBBBBBB
+  MBBMMBBMMBBMMBBM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 160 (zap 3 2)
+{
+  BBBMMMMMMMMMMMMM
+  BBBBMMMMMMMMMMMM
+  BBBBMMMMMMMMMMMM
+  MBBBBMMMMMMMMMMM
+  MMMBBBBMMMMMMMMM
+  MMMMBBBBMMMMMMMM
+  MMMMBBBBMMMMMMMM
+  MMMMMBBBBMMMMMMM
+  MMMMMMMBBBBMMMMM
+  MMMMMMMMBBBBMMMM
+  MMMMMMMMBBBBMMMM
+  MMMMMMMMMBBBBMMM
+  MMMMMMMMMMMBBBBM
+  MMMMMMMMMMMMBBBB
+  MMMMMMMMMMMMBBBB
+  MMMMMMMMMMMMMBBB
+}
+# tile 161 (zap 3 3)
+{
+  MMMMMMMMMMMMMBBB
+  MMMMMMMMMMMMBBBB
+  MMMMMMMMMMMMBBBB
+  MMMMMMMMMMMBBBBM
+  MMMMMMMMMBBBBMMM
+  MMMMMMMMBBBBMMMM
+  MMMMMMMMBBBBMMMM
+  MMMMMMMBBBBMMMMM
+  MMMMMBBBBMMMMMMM
+  MMMMBBBBMMMMMMMM
+  MMMMBBBBMMMMMMMM
+  MMMBBBBMMMMMMMMM
+  MBBBBMMMMMMMMMMM
+  BBBBMMMMMMMMMMMM
+  BBBBMMMMMMMMMMMM
+  BBBMMMMMMMMMMMMM
+}
+# tile 162 (zap 4 0)
+{
+  MMMMMMMAAMMMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMMAAAAMMMMMM
+  MMMMMMMAAMMMMMMM
+}
+# tile 163 (zap 4 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MAAMMAAMMAAMMAAM
+  AAAAAAAAAAAAAAAA
+  AAAAAAAAAAAAAAAA
+  MAAMMAAMMAAMMAAM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 164 (zap 4 2)
+{
+  AAAMMMMMMMMMMMMM
+  AAAAMMMMMMMMMMMM
+  AAAAMMMMMMMMMMMM
+  MAAAAMMMMMMMMMMM
+  MMMAAAAMMMMMMMMM
+  MMMMAAAAMMMMMMMM
+  MMMMAAAAMMMMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMMMMAAAAMMMMM
+  MMMMMMMMAAAAMMMM
+  MMMMMMMMAAAAMMMM
+  MMMMMMMMMAAAAMMM
+  MMMMMMMMMMMAAAAM
+  MMMMMMMMMMMMAAAA
+  MMMMMMMMMMMMAAAA
+  MMMMMMMMMMMMMAAA
+}
+# tile 165 (zap 4 3)
+{
+  MMMMMMMMMMMMMAAA
+  MMMMMMMMMMMMAAAA
+  MMMMMMMMMMMMAAAA
+  MMMMMMMMMMMAAAAM
+  MMMMMMMMMAAAAMMM
+  MMMMMMMMAAAAMMMM
+  MMMMMMMMAAAAMMMM
+  MMMMMMMAAAAMMMMM
+  MMMMMAAAAMMMMMMM
+  MMMMAAAAMMMMMMMM
+  MMMMAAAAMMMMMMMM
+  MMMAAAAMMMMMMMMM
+  MAAAAMMMMMMMMMMM
+  AAAAMMMMMMMMMMMM
+  AAAAMMMMMMMMMMMM
+  AAAMMMMMMMMMMMMM
+}
+# tile 166 (zap 5 0)
+{
+  MMMMMMMNNMMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMMNNMMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMNNNNMMMMMM
+  MMMMMMMNNMMMMMMM
+}
+# tile 167 (zap 5 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MNNMMNNMMNNMMNNM
+  NNNNNNNNNNNNNNNN
+  NNNNNNNNNNNNNNNN
+  MNNMMNNMMNNMMNNM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 168 (zap 5 2)
+{
+  NNNMMMMMMMMMMMMM
+  NNNNMMMMMMMMMMMM
+  NNNNMMMMMMMMMMMM
+  MNNNNMMMMMMMMMMM
+  MMMNNNNMMMMMMMMM
+  MMMMNNNNMMMMMMMM
+  MMMMNNNNMMMMMMMM
+  MMMMMNNNNMMMMMMM
+  MMMMMMMNNNNMMMMM
+  MMMMMMMMNNNNMMMM
+  MMMMMMMMNNNNMMMM
+  MMMMMMMMMNNNNMMM
+  MMMMMMMMMMMNNNNM
+  MMMMMMMMMMMMNNNN
+  MMMMMMMMMMMMNNNN
+  MMMMMMMMMMMMMNNN
+}
+# tile 169 (zap 5 3)
+{
+  MMMMMMMMMMMMMNNN
+  MMMMMMMMMMMMNNNN
+  MMMMMMMMMMMMNNNN
+  MMMMMMMMMMMNNNNM
+  MMMMMMMMMNNNNMMM
+  MMMMMMMMNNNNMMMM
+  MMMMMMMMNNNNMMMM
+  MMMMMMMNNNNMMMMM
+  MMMMMNNNNMMMMMMM
+  MMMMNNNNMMMMMMMM
+  MMMMNNNNMMMMMMMM
+  MMMNNNNMMMMMMMMM
+  MNNNNMMMMMMMMMMM
+  NNNNMMMMMMMMMMMM
+  NNNNMMMMMMMMMMMM
+  NNNMMMMMMMMMMMMM
+}
+# tile 170 (zap 6 0)
+{
+  MMMMMMMFFMMMMMMM
+  MMMMMMFFFFMMMMMM
+  MMMMMMFFFFMMMMMM
+  MMMMMMMFFMMMMMMM
+  MMMMMMMFFMMMMMMM
+  MMMMMMFFFFMMMMMM
+  MMMMMMFFFFMMMMMM
+  MMMMMMMFFMMMMMMM
+  MMMMMMMFFMMMMMMM
+  MMMMMMFFFFMMMMMM
+  MMMMMMFFFFMMMMMM
+  MMMMMMMFFMMMMMMM
+  MMMMMMMFFMMMMMMM
+  MMMMMMFFFFMMMMMM
+  MMMMMMFFFFMMMMMM
+  MMMMMMMFFMMMMMMM
+}
+# tile 171 (zap 6 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MFFMMFFMMFFMMFFM
+  FFFFFFFFFFFFFFFF
+  FFFFFFFFFFFFFFFF
+  MFFMMFFMMFFMMFFM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 172 (zap 6 2)
+{
+  FFFMMMMMMMMMMMMM
+  FFFFMMMMMMMMMMMM
+  FFFFMMMMMMMMMMMM
+  MFFFFMMMMMMMMMMM
+  MMMFFFFMMMMMMMMM
+  MMMMFFFFMMMMMMMM
+  MMMMFFFFMMMMMMMM
+  MMMMMFFFFMMMMMMM
+  MMMMMMMFFFFMMMMM
+  MMMMMMMMFFFFMMMM
+  MMMMMMMMFFFFMMMM
+  MMMMMMMMMFFFFMMM
+  MMMMMMMMMMMFFFFM
+  MMMMMMMMMMMMFFFF
+  MMMMMMMMMMMMFFFF
+  MMMMMMMMMMMMMFFF
+}
+# tile 173 (zap 6 3)
+{
+  MMMMMMMMMMMMMFFF
+  MMMMMMMMMMMMFFFF
+  MMMMMMMMMMMMFFFF
+  MMMMMMMMMMMFFFFM
+  MMMMMMMMMFFFFMMM
+  MMMMMMMMFFFFMMMM
+  MMMMMMMMFFFFMMMM
+  MMMMMMMFFFFMMMMM
+  MMMMMFFFFMMMMMMM
+  MMMMFFFFMMMMMMMM
+  MMMMFFFFMMMMMMMM
+  MMMFFFFMMMMMMMMM
+  MFFFFMMMMMMMMMMM
+  FFFFMMMMMMMMMMMM
+  FFFFMMMMMMMMMMMM
+  FFFMMMMMMMMMMMMM
+}
+# tile 174 (zap 7 0)
+{
+  MMMMMMMGGMMMMMMM
+  MMMMMMGGGGMMMMMM
+  MMMMMMGGGGMMMMMM
+  MMMMMMMGGMMMMMMM
+  MMMMMMMGGMMMMMMM
+  MMMMMMGGGGMMMMMM
+  MMMMMMGGGGMMMMMM
+  MMMMMMMGGMMMMMMM
+  MMMMMMMGGMMMMMMM
+  MMMMMMGGGGMMMMMM
+  MMMMMMGGGGMMMMMM
+  MMMMMMMGGMMMMMMM
+  MMMMMMMGGMMMMMMM
+  MMMMMMGGGGMMMMMM
+  MMMMMMGGGGMMMMMM
+  MMMMMMMGGMMMMMMM
+}
+# tile 175 (zap 7 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MGGMMGGMMGGMMGGM
+  GGGGGGGGGGGGGGGG
+  GGGGGGGGGGGGGGGG
+  MGGMMGGMMGGMMGGM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 176 (zap 7 2)
+{
+  GGGMMMMMMMMMMMMM
+  GGGGMMMMMMMMMMMM
+  GGGGMMMMMMMMMMMM
+  MGGGGMMMMMMMMMMM
+  MMMGGGGMMMMMMMMM
+  MMMMGGGGMMMMMMMM
+  MMMMGGGGMMMMMMMM
+  MMMMMGGGGMMMMMMM
+  MMMMMMMGGGGMMMMM
+  MMMMMMMMGGGGMMMM
+  MMMMMMMMGGGGMMMM
+  MMMMMMMMMGGGGMMM
+  MMMMMMMMMMMGGGGM
+  MMMMMMMMMMMMGGGG
+  MMMMMMMMMMMMGGGG
+  MMMMMMMMMMMMMGGG
+}
+# tile 177 (zap 7 3)
+{
+  MMMMMMMMMMMMMGGG
+  MMMMMMMMMMMMGGGG
+  MMMMMMMMMMMMGGGG
+  MMMMMMMMMMMGGGGM
+  MMMMMMMMMGGGGMMM
+  MMMMMMMMGGGGMMMM
+  MMMMMMMMGGGGMMMM
+  MMMMMMMGGGGMMMMM
+  MMMMMGGGGMMMMMMM
+  MMMMGGGGMMMMMMMM
+  MMMMGGGGMMMMMMMM
+  MMMGGGGMMMMMMMMM
+  MGGGGMMMMMMMMMMM
+  GGGGMMMMMMMMMMMM
+  GGGGMMMMMMMMMMMM
+  GGGMMMMMMMMMMMMM
+}
+# tile 178 (warning 0)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOOOOMMMMMMM
+  MMMMOOOOOOMMMMMM
+  MMMOOAAAAOOMMMMM
+  MMMOOAMMMOOAMMMM
+  MMMMAAMMMOOAMMMM
+  MMMMMMMMOOAAMMMM
+  MMMMMMMOOAAMMMMM
+  MMMMMMOOAAMMMMMM
+  MMMMMMOOAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMOOMMMMMMMM
+  MMMMMMOOAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 179 (warning 1)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMOCOCMMMMMMM
+  MMMMOCOCOCMMMMMM
+  MMMOCAAAAOCMMMMM
+  MMMCOAMMMCOAMMMM
+  MMMMAAMMMOCAMMMM
+  MMMMMMMMOCAAMMMM
+  MMMMMMMOCAAMMMMM
+  MMMMMMOCAAMMMMMM
+  MMMMMMCOAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMCOMMMMMMMM
+  MMMMMMOCAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 180 (warning 2)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMCCCCMMMMMMM
+  MMMMCCCCCCMMMMMM
+  MMMCCAAAACCMMMMM
+  MMMCCAMMMCCAMMMM
+  MMMMAAMMMCCAMMMM
+  MMMMMMMMCCAAMMMM
+  MMMMMMMCCAAMMMMM
+  MMMMMMCCAAMMMMMM
+  MMMMMMCCAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMCCMMMMMMMM
+  MMMMMMCCAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 181 (warning 3)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMDDDDMMMMMMM
+  MMMMDDDDDDMMMMMM
+  MMMDDAAAADDMMMMM
+  MMMDDAMMMDDAMMMM
+  MMMMAAMMMDDAMMMM
+  MMMMMMMMDDAAMMMM
+  MMMMMMMDDAAMMMMM
+  MMMMMMDDAAMMMMMM
+  MMMMMMDDAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMDDMMMMMMMM
+  MMMMMMDDAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 182 (warning 4)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMIIIIMMMMMMM
+  MMMMIIIIIIMMMMMM
+  MMMIIAAAAIIMMMMM
+  MMMIIAMMMIIAMMMM
+  MMMMAAMMMIIAMMMM
+  MMMMMMMMIIAAMMMM
+  MMMMMMMIIAAMMMMM
+  MMMMMMIIAAMMMMMM
+  MMMMMMIIAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMIIMMMMMMMM
+  MMMMMMIIAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 183 (warning 5)
+{
+  MMMMMMMMMMMMMMMM
+  MMMMMMMMMMMMMMMM
+  MMMMMIEIEMMMMMMM
+  MMMMIEIEIEMMMMMM
+  MMMIEAAAAIEMMMMM
+  MMMEIAMMMEIAMMMM
+  MMMMAAMMMIEAMMMM
+  MMMMMMMMIEAAMMMM
+  MMMMMMMIEAAMMMMM
+  MMMMMMIEAAMMMMMM
+  MMMMMMEIAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMEIMMMMMMMM
+  MMMMMMIEAMMMMMMM
+  MMMMMMMAAMMMMMMM
+  MMMMMMMMMMMMMMMM
+}
+# tile 184 (sub mine walls 0)
+{
+  AJJKKKACJAAJJJAA
+  AJKKKACLJJAJJJJA
+  AJKKACLCKJJAJJJA
+  AAKACLCKJJJJAAAA
+  AAACLLKKJJJJJJAA
+  AACLLKKKAAJJJJJA
+  ACKKKKKACJAJJJJA
+  AKKKKKACLJJAJJJA
+  AAKKKACLKJJJAJAA
+  AAKKACLKKJJJJJAA
+  AACCCKKAAJJJJJJA
+  ACCKKKACJAJJJJJA
+  ACKKKACLJJAJJJJA
+  AAKKACLCKJJAJJAA
+  AAJACKCKKJJJAJAA
+  AAJCKKJAAAJJJJJA
+}
+# tile 185 (sub mine walls 1)
+{
+  AJAAAAAAJJAAAJAA
+  JJJAAAJJJJJAAAAJ
+  JJJACJAJJJACCJAJ
+  AAACLJJAJACCLJJA
+  AACLCKJJACCLCKJJ
+  ACKCKKJJJCKCKKJA
+  CJKKKKJJCKCKJJAC
+  KJJKCJJCKKKJJJCK
+  KJKKKJJKJKJJJJKK
+  JJJKCJKKJKJJJCKJ
+  JJJJJJKJKKJJJKKJ
+  JJJJJKJJJJJJJJJJ
+  JJJJJJJJJJJJJJJJ
+  JJJJJJJJJJJJJJJJ
+  JJJJJJJJJJJJJJJJ
+  AAAAAAAAAAAAAAAA
+}
+# tile 186 (sub mine walls 2)
+{
+  AAAAAAKCCKKJAAAA
+  AAAAKKCLCJKJJAAA
+  AAKKKCLCKJJJKKAA
+  AKKKCLCKJJJJJJKA
+  AKKCLLKKJJJJJJJA
+  AKCLLKKKAAJJJJJJ
+  ACKKKKKACJAJJJJJ
+  AKKKKKACLJJAAJJJ
+  AAKKKCLLKJJJAJAJ
+  AAKKCCCKKJJJAJAA
+  AACCKKKAAJJJJJJA
+  ACCKKKACJAJJJJJA
+  ACKKKACLJJAJJJJA
+  AAKKACLCKJJAJJAA
+  AAJACKCKKJJJAJAA
+  AAJCKKJAAAJJJJJA
+}
+# tile 187 (sub mine walls 3)
+{
+  AAAAAAKCCKKJAAAA
+  AAAAKKCLCJKJJAAA
+  AAKKKCLCKJJJKKAA
+  AKKCCLCKJJJJJJKA
+  KKCCLLKKJJJJJJJA
+  KKCLKKKKAAJJJJJA
+  KCLKKKKACJAJJJJA
+  CKKKKKACLJJAAJJA
+  KAKKKCLLKJJJAJAA
+  AKKKCCCKKJJJAJAA
+  AACCKKKAAJJJJJJA
+  ACCKKKACJAJJJJJA
+  ACKKKACLJJAJJJJA
+  AKKKACLCKJJAJJAA
+  AAJACKCKKJJJAJAA
+  AAJCKKJAAAJJJJJA
+}
+# tile 188 (sub mine walls 4)
+{
+  AKKKAAKKKKAAJJJA
+  AKKAAKCCCJJJAAJA
+  AKKAALLJJJACCJAA
+  AKAACLJJJACCLJJA
+  AAACCKJJACLLCKJJ
+  AAACLKJJJCKCKKJA
+  AACLKKJJCKCKJJAC
+  AAKKCJJCKKKJJJCK
+  ACKKKJJKJKJJJJKK
+  ACKKCJKKJKJJJCKJ
+  AKKKJJKJKKJJJKKJ
+  ACKJJKJJJJJJJJJJ
+  AKJJJJJJJJJJJJJJ
+  AKJJJJJJJJJJJJJJ
+  AJJJJJJJJJJJJJJJ
+  AAAAAAAAAAAAAAAA
+}
+# tile 189 (sub mine walls 5)
+{
+  AKKAAAKKAAAAJJJA
+  AKAAKKLCKAAAAAJA
+  AAKKCLCJJACCAJJA
+  AKKCLJJJACCCLAJA
+  AKCKKKJACCCLCAAA
+  ACKKKKJACCKCKKAA
+  CJKKKKACCKCKJJAA
+  KJJKCJJCKKKJJJAA
+  KJKKKJJKJKJJJJJA
+  JJJKCJKKJKJJJJJA
+  JJJJJJKJKKJJJJJA
+  JJJJJKJJJJJJJJJA
+  JJJJJJJJJJJJJJJA
+  JJJJJJJJJJJJJJJA
+  JJJJJJJJJJJJJJJA
+  AAAAAAAAAAAAAAAA
+}
+# tile 190 (sub mine walls 6)
+{
+  AAAAAAKCCKKJAAAA
+  AAAAKCCLCJKJJAAA
+  AAKKCCLCKJJJKKAA
+  AKKKCLCKJJJJJJKA
+  KKKCLKKKJJJJJJJA
+  KKCLKKKKAAJJJJJJ
+  KCKLKKKACJAJJJJJ
+  CKKKKKACLJJAAJJJ
+  KAKKKCLLKJJJAJAJ
+  AKKKCCCKKJJJAJAA
+  AACCKKKAAJJJJJJA
+  ACCKKKACJAJJJJJA
+  ACKKKACLJJAJJJJA
+  AKKKACLCKJJAJJAA
+  AAJACKCKKJJJAJAA
+  AAJCKKJAAAJJJJJA
+}
+# tile 191 (sub mine walls 7)
+{
+  AKKAAAKKKKAAJJJA
+  AKAAKKLCCJJJAAJA
+  AAKKCLCJJJACCJAA
+  AKKCLJJJJACCLJJA
+  AKCLCKJJACCLCKJJ
+  ACKCKKJJJCKCKKJA
+  CJKKKKJJCKCKJJAC
+  KJJKCJJCKKKJJJCK
+  KJKKKJJKJKJJJJKK
+  JJJKCJKKJKJJJCKJ
+  JJJJJJKJKKJJJKKJ
+  JJJJJKJJJJJJJJJJ
+  JJJJJJJJJJJJJJJJ
+  JJJJJJJJJJJJJJJJ
+  JJJJJJJJJJJJJJJJ
+  AAAAAAAAAAAAAAAA
+}
+# tile 192 (sub mine walls 8)
+{
+  AAAAAAKCCKKJAAAA
+  AAAAKCCLCJKJJAAA
+  AAKKKCLCKJJJKKAA
+  AKKKCLCKJJJJJJKA
+  KKCCLLKKJJJJJJJA
+  KKCLLKKKAAJJJJJJ
+  KCLLKKKACJAJJJJJ
+  CKLKKKACLJJAAJJJ
+  KAKKKCLLKJJJAJAJ
+  AKKKCCCKKJJJAJAA
+  AACCKKKAAJJJJJJA
+  ACCKKKACJAJJJJJA
+  ACKKKACLJJAJJJJA
+  AKKKACLCKJJAJJAA
+  AAJACKCKKJJJAJAA
+  AAJCKKJAAAJJJJJA
+}
+# tile 193 (sub mine walls 9)
+{
+  AKKAACKCCKKJAJJA
+  AKACKKKLLJKJJAJA
+  AAKKKCCCKJJJKKAA
+  AKKKCCLKJJJJJJKA
+  AKKCLLKKJJJJJJJA
+  AKCLLKKKAAJJJJJJ
+  ACLKKKKACJAJJJJJ
+  AKKKKKACLJJAAJJJ
+  AAKKKCLLKJJJAJAJ
+  AAKKCCCKKJJJAJAA
+  AACCKKKAAJJJJJJA
+  ACCKKKACJAJJJJJA
+  ACKKKACLJJAJJJJA
+  AAKKACLCKJJAJJAA
+  AAJACKCKKJJJAJAA
+  AAJCKKJAAAJJJJJA
+}
+# tile 194 (sub mine walls 10)
+{
+  AKKAACKCCKKJAJJA
+  AKACKKCLCJKJJAJA
+  AAKKCCLCKJJJKKAA
+  AKKCLLCKJJJJJJKA
+  KKCCLLKKJJJJJJJA
+  KCKLLKKKAAJJJJJA
+  CCKKKKKACJAJJJJA
+  CKKKKKACLJJAAJJA
+  KAKKKCLLKJJJAJAA
+  AKKKCCCKKJJJAJAA
+  AACCKKKAAJJJJJJA
+  ACCKKKACJAJJJJJA
+  ACKKKACLJJAJJJJA
+  AKKKACLCKJJAJJAA
+  AAJACKCKKJJJAJAA
+  AAJCKKJAAAJJJJJA
+}
+# tile 195 (sub gehennom walls 0)
+{
+  ALLDAJMMMMMJLLDA
+  ADDDAJMJMMJJDDDA
+  ADDDAJMMMMMJDDDA
+  ADDDAJMMMMMJDDDA
+  ADDDAJJMMMMJDDDA
+  AJAAAJJMMMMJJAJA
+  AJJJAJJMMMMJJJJA
+  ADMMAJJMMJMJDMJA
+  ALLDAJMMMMMJLLDA
+  ADDDAJMMMMMJDDDA
+  ADDDAJMMMMMJDDDA
+  ADDDAJMMMMMJDDDA
+  ADDDAJJMJMJJDDDA
+  AJAAAJJMMMMJJAJA
+  AJJJAJJMMMMJJJJA
+  ADMMAJJMMMMJDMJA
+}
+# tile 196 (sub gehennom walls 1)
+{
+  AAALDDAAAAALDDAA
+  DDDLDDAJDDDLDDAJ
+  MDDJJJAJMDDJJJAJ
+  JJJJJJJJJJJJJJJJ
+  MMJJJMMMMMJJJMMM
+  MMLDDMMMMMLDDMMM
+  DDLDDAJDDDLDDAJD
+  DDJJJAJMDDJJJAJM
+  JJJJJJJJJJJJJJJJ
+  MMJDMMMMJDMMMJDM
+  MMJMMMMMJMMMMJMM
+  JJJJJJJJJJJJJJJJ
+  JDMMMMJDMMMMJDMM
+  JMMMMMJMMMMMJMMM
+  JJJJJJJJJJJJJJJJ
+  AAAAAAAAAAAAAAAA
+}
+# tile 197 (sub gehennom walls 2)
+{
+  AAALLLLDDDDDDAAA
+  LLLLAAJJMMMMDJJJ
+  DDDLAJJMMMCCDJJJ
+  DDDDDDDDDDDDDJJJ
+  DDDMMMMMMMMMMJJJ
+  DDDMMMMMMMMMMJJJ
+  DDMMMMMMMMMMMMJJ
+  DMMMMMMMMMMMMMMJ
+  JJJJJJJJJJJJJJJJ
+  AMMJJJJJJJJJMMMJ
+  ADDDAAAAAAAADDDA
+  ADDDAJMMMMMJDDDA
+  ADDDAJMMMMMJDDDA
+  AJAAAJJMMMMJJAJA
+  AJJJAJJMMMMJJJJA
+  ADMMAJJMMMMJDMJA
+}
+# tile 198 (sub gehennom walls 3)
+{
+  AAALLLLDDDDDDAAA
+  LLLLAAJJMMMMDJJJ
+  DDDLAJJMMMCCDJJJ
+  DDDDDDDDDDDDDJJJ
+  DDDMMMMMMMMMMJJJ
+  DDDMMMMMMMMMMJJJ
+  DDMMMMMMMMMMMMJJ
+  DMMMMMMMMMMMMMMJ
+  JJJJJJJJJJJJJJJJ
+  AMMJJJJJJJJJMMMJ
+  ADDDAAAAAAAADDDA
+  ADDDAJMMMMMJDDDA
+  ADDDAJMMMMMJDDDA
+  AJAAAJJMMMMJJAJA
+  AJJJAJJMMMMJJJJA
+  ADMMAJJMMMMJDMJA
+}
+# tile 199 (sub gehennom walls 4)
+{
+  AAALLLLDDDDDDAAA
+  LLLLAAJJMMMMDJJJ
+  DDDLAJJMMMCCDJJJ
+  DDDDDDDDDDDDDJJJ
+  DDDMMMMMMMMMMJJJ
+  DDDMMMMMMMMMMJJJ
+  DDMMMMMMMMMMMMJJ
+  DMMMMMMMMMMMMMMJ
+  JJJJJJJJJJJJJJJJ
+  MMJDMMMMJDMMMJDM
+  MMJMMMMMJMMMMJMM
+  JJJJJJJJJJJJJJJJ
+  JDMMMMJDMMMMJDMM
+  JMMMMMJMMMMMJMMM
+  JJJJJJJJJJJJJJJJ
+  AAAAAAAAAAAAAAAA
+}
+# tile 200 (sub gehennom walls 5)
+{
+  AAALLLLDDDDDDAAA
+  LLLLAAJJMMMMDJJJ
+  DDDLAJJMMMCCDJJJ
+  DDDDDDDDDDDDDJJJ
+  DDDMMMMMMMMMMJJJ
+  DDDMMMMMMMMMMJJJ
+  DDMMMMMMMMMMMMJJ
+  DMMMMMMMMMMMMMMJ
+  JJJJJJJJJJJJJJJJ
+  MMJDMMMMJDMMMJDM
+  MMJMMMMMJMMMMJMM
+  JJJJJJJJJJJJJJJJ
+  JDMMMMJDMMMMJDMM
+  JMMMMMJMMMMMJMMM
+  JJJJJJJJJJJJJJJJ
+  AAAAAAAAAAAAAAAA
+}
+# tile 201 (sub gehennom walls 6)
+{
+  AAALLLLDDDDDDAAA
+  LLLLAAJJMMMMDJJJ
+  DDDLAJJMMMCCDJJJ
+  DDDDDDDDDDDDDJJJ
+  DDDMMMMMMMMMMJJJ
+  DDDMMMMMMMMMMJJJ
+  DDMMMMMMMMMMMMJJ
+  DMMMMMMMMMMMMMMJ
+  JJJJJJJJJJJJJJJJ
+  AMMJJJJJJJJJMMMJ
+  ADDDAAAAAAAADDDA
+  ADDDAJMMMMMJDDDA
+  ADDDAJMMMMMJDDDA
+  AJAAAJJMMMMJJAJA
+  AJJJAJJMMMMJJJJA
+  ADMMAJJMMMMJDMJA
+}
+# tile 202 (sub gehennom walls 7)
+{
+  AAALLLLDDDDDDAAA
+  LLLLAAJJMMMMDJJJ
+  DDDLAJJMMMCCDJJJ
+  DDDDDDDDDDDDDJJJ
+  DDDMMMMMMMMMMJJJ
+  DDDMMMMMMMMMMJJJ
+  DDMMMMMMMMMMMMJJ
+  DMMMMMMMMMMMMMMJ
+  JJJJJJJJJJJJJJJJ
+  MMJDMMMMJDMMMJDM
+  MMJMMMMMJMMMMJMM
+  JJJJJJJJJJJJJJJJ
+  JDMMMMJDMMMMJDMM
+  JMMMMMJMMMMMJMMM
+  JJJJJJJJJJJJJJJJ
+  AAAAAAAAAAAAAAAA
+}
+# tile 203 (sub gehennom walls 8)
+{
+  AAALLLLDDDDDDAAA
+  LLLLAAJJMMMMDJJJ
+  DDDLAJJMMMCCDJJJ
+  DDDDDDDDDDDDDJJJ
+  DDDMMMMMMMMMMJJJ
+  DDDMMMMMMMMMMJJJ
+  DDMMMMMMMMMMMMJJ
+  DMMMMMMMMMMMMMMJ
+  JJJJJJJJJJJJJJJJ
+  AMMJJJJJJJJJMMMJ
+  ADDDAAAAAAAADDDA
+  ADDDAJMMMMMJDDDA
+  ADDDAJMMMMMJDDDA
+  AJAAAJJMMMMJJAJA
+  AJJJAJJMMMMJJJJA
+  ADMMAJJMMMMJDMJA
+}
+# tile 204 (sub gehennom walls 9)
+{
+  AAALLLLDDDDDDAAA
+  LLLLAAJJMMMMDJJJ
+  DDDLAJJMMMCCDJJJ
+  DDDDDDDDDDDDDJJJ
+  DDDMMMMMMMMMMJJJ
+  DDDMMMMMMMMMMJJJ
+  DDMMMMMMMMMMMMJJ
+  DMMMMMMMMMMMMMMJ
+  JJJJJJJJJJJJJJJJ
+  AMMJJJJJJJJJMMMJ
+  ADDDAAAAAAAADDDA
+  ADDDAJMMMMMJDDDA
+  ADDDAJMMMMMJDDDA
+  AJAAAJJMMMMJJAJA
+  AJJJAJJMMMMJJJJA
+  ADMMAJJMMMMJDMJA
+}
+# tile 205 (sub gehennom walls 10)
+{
+  AAALLLLDDDDDDAAA
+  LLLLAAJJMMMMDJJJ
+  DDDLAJJMMMCCDJJJ
+  DDDDDDDDDDDDDJJJ
+  DDDMMMMMMMMMMJJJ
+  DDDMMMMMMMMMMJJJ
+  DDMMMMMMMMMMMMJJ
+  DMMMMMMMMMMMMMMJ
+  JJJJJJJJJJJJJJJJ
+  AMMJJJJJJJJJMMMJ
+  ADDDAAAAAAAADDDA
+  ADDDAJMMMMMJDDDA
+  ADDDAJMMMMMJDDDA
+  AJAAAJJMMMMJJAJA
+  AJJJAJJMMMMJJJJA
+  ADMMAJJMMMMJDMJA
+}
+# tile 206 (sub knox walls 0)
+{
+  AJJJAAACJAAAJJJA
+  AJJJAACLJJAAJJJA
+  AJJJACLCKJJAJJJA
+  AAAAALCKJJJAAAAA
+  AAJAAAKKJJAAAJAA
+  ACJJAAAAAAAACJJA
+  AJJJAAACJAAAJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+  AJJJAAACJAAAJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+}
+# tile 207 (sub knox walls 1)
+{
+  AJAAAJAAAJAAAJAA
+  JJJAAAJAJJJAAAJA
+  JJJACJAAJJJACJAA
+  AAACLJJAJJACLJJA
+  AACLCKJJAACLCKJJ
+  AAACKKJAAAACKKJA
+  AJAAAJAAAJAAAJAA
+  KJJACJJAKJJACJJA
+  KJJAKJJAKJJACJJA
+  KJJACJAAKJJAKJAA
+  CJJACJAACJJAKJJA
+  KJAACJJACJJACJJA
+  KJAACJJACJAAKJJA
+  KJJAKJJAKJJACJAA
+  KJJACJJAKJJACJJA
+  AAAAAAAAAAAAAAAA
+}
+# tile 208 (sub knox walls 2)
+{
+  AAAAAAKCJKAAAAAA
+  AAAAKKCLKJKKAAAA
+  AAKKKCLCKJJKKKAA
+  AKKKCLCKKJJJKKKA
+  AKKCCCKKJJJJJKKA
+  AKCCCKKAAJJJJJKA
+  AJJCKKACJAJJJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+  AJJJAAACJAAAJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+}
+# tile 209 (sub knox walls 3)
+{
+  AAAAAAKCJKAAAAAA
+  AAAAKKCLKJKKAAAA
+  AAKKKCLCKJJKKKAA
+  AKKKCLCKKJJJKKKA
+  AKKCCCKKJJJJJKKA
+  AKCCCKKAAJJJJJKA
+  AJJCKKACJAJJJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+  AJJJAAACJAAAJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+}
+# tile 210 (sub knox walls 4)
+{
+  AAAAAAKCJKAAAAAA
+  AAAAKKCLKJKKAAAA
+  AAKKKCLCKJJKKKAA
+  AKKKCLCKKJJJKKKA
+  AKKCCCKKJJJJJKKA
+  AACCCAKJJAJJJAKA
+  AJACAJAJAJAJAJAA
+  KJJACJJAKJJACJJA
+  KJJAKJJAKJJACJJA
+  KJJACJAAKJJAKJAA
+  CJJACJAACJJAKJJA
+  KJAACJJACJJACJJA
+  KJAACJJACJAAKJJA
+  KJJAKJJAKJJACJAA
+  KJJACJJAKJJACJJA
+  AAAAAAAAAAAAAAAA
+}
+# tile 211 (sub knox walls 5)
+{
+  AAAAAAKCJKAAAAAA
+  AAAAKKCLKJKKAAAA
+  AAKKKCLCKJJKKKAA
+  AKKKCLCKKJJJKKKA
+  AKKCCCKKJJJJJKKA
+  AACCCAKJJAJJJAKA
+  AJACAJAJAJAJAJAA
+  KJJACJJAKJJACJJA
+  KJJAKJJAKJJACJJA
+  KJJACJAAKJJAKJAA
+  CJJACJAACJJAKJJA
+  KJAACJJACJJACJJA
+  KJAACJJACJAAKJJA
+  KJJAKJJAKJJACJAA
+  KJJACJJAKJJACJJA
+  AAAAAAAAAAAAAAAA
+}
+# tile 212 (sub knox walls 6)
+{
+  AAAAAAKCJKAAAAAA
+  AAAAKKCLKJKKAAAA
+  AAKKKCLCKJJKKKAA
+  AKKKCLCKKJJJKKKA
+  AKKCCCKKJJJJJKKA
+  AKCCCKKAAJJJJJKA
+  AJJCKKACJAJJJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+  AJJJAAACJAAAJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+}
+# tile 213 (sub knox walls 7)
+{
+  AAAAAAKCJKAAAAAA
+  AAAAKKCLKJKKAAAA
+  AAKKKCLCKJJKKKAA
+  AKKKCLCKKJJJKKKA
+  AKKCCCKKJJJJJKKA
+  AACCCAKJJAJJJAKA
+  AJACAJAJAJAJAJAA
+  KJJACJJAKJJACJJA
+  KJJAKJJAKJJACJJA
+  KJJACJAAKJJAKJAA
+  CJJACJAACJJAKJJA
+  KJAACJJACJJACJJA
+  KJAACJJACJAAKJJA
+  KJJAKJJAKJJACJAA
+  KJJACJJAKJJACJJA
+  AAAAAAAAAAAAAAAA
+}
+# tile 214 (sub knox walls 8)
+{
+  AAAAAAKCJKAAAAAA
+  AAAAKKCLKJKKAAAA
+  AAKKKCLCKJJKKKAA
+  AKKKCLCKKJJJKKKA
+  AKKCCCKKJJJJJKKA
+  AKCCCKKAAJJJJJKA
+  AJJCKKACJAJJJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+  AJJJAAACJAAAJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+}
+# tile 215 (sub knox walls 9)
+{
+  AAAAAAKCJKAAAAAA
+  AAAAKKCLKJKKAAAA
+  AAKKKCLCKJJKKKAA
+  AKKKCLCKKJJJKKKA
+  AKKCCCKKJJJJJKKA
+  AKCCCKKAAJJJJJKA
+  AJJCKKACJAJJJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+  AJJJAAACJAAAJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+}
+# tile 216 (sub knox walls 10)
+{
+  AAAAAAKCJKAAAAAA
+  AAAAKKCLKJKKAAAA
+  AAKKKCLCKJJKKKAA
+  AKKKCLCKKJJJKKKA
+  AKKCCCKKJJJJJKKA
+  AKCCCKKAAJJJJJKA
+  AJJCKKACJAJJJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+  AJJJAAACJAAAJJJA
+  AJJJAACLJJAAJJJA
+  AAAAACLCKJJAAAAA
+  AAJAAACKKJAAAJAA
+  ACJJAAAAAAAACJJA
+}
+# tile 217 (sub sokoban walls 0)
+{
+  ANNBAMEEEEEMNNBA
+  ABBBAMEMEEMMBBBA
+  ABBBAMEEEEEMBBBA
+  ABBBAMEEEEEMBBBA
+  ABBBAMMEEEEMBBBA
+  AMAAAMMEEEEMMAMA
+  AMMMAMMEEEEMMMMA
+  ABEEAMMEEMEMBEMA
+  ANNBAMEEEEEMNNBA
+  ABBBAMEEEEEMBBBA
+  ABBBAMEEEEEMBBBA
+  ABBBAMEEEEEMBBBA
+  ABBBAMMEMEMMBBBA
+  AMAAAMMEEEEMMAMA
+  AMMMAMMEEEEMMMMA
+  ABEEAMMEEEEMBEMA
+}
+# tile 218 (sub sokoban walls 1)
+{
+  AAANBBAAAAANBBAA
+  BBBNBBAMBBBNBBAM
+  EBBMMMAMEBBMMMAM
+  MMMMMMMMMMMMMMMM
+  EEMMMEEEEEMMMEEE
+  EENBBEEEEENBBEEE
+  BBNBBAMBBBNBBAMB
+  BBMMMAMEBBMMMAME
+  MMMMMMMMMMMMMMMM
+  EEMBEEEEMBEEEMBE
+  EEMEEEEEMEEEEMEE
+  MMMMMMMMMMMMMMMM
+  MBEEEEMBEEEEMBEE
+  MEEEEEMEEEEEMEEE
+  MMMMMMMMMMMMMMMM
+  AAAAAAAAAAAAAAAA
+}
+# tile 219 (sub sokoban walls 2)
+{
+  AAANNNNBBBBBBAAA
+  NNNNAAMMEEEEBMMM
+  BBBNAMMEEENNBMMM
+  BBBBBBBBBBBBBMMM
+  BBBEEEEEEEEEEMMM
+  BBBEEEEEEEEEEMMM
+  BBEEEEEEEEEEEEMM
+  BEEEEEEEEEEEEEEM
+  MMMMMMMMMMMMMMMM
+  AEEMMMMMMMMMEEEM
+  ABBBAAAAAAAABBBA
+  ABBBAMEEEEEMBBBA
+  ABBBAMEEEEEMBBBA
+  AMAAAMMEEEEMMAMA
+  AMMMAMMEEEEMMMMA
+  ABEEAMMEEEEMBEMA
+}
+# tile 220 (sub sokoban walls 3)
+{
+  AAANNNNBBBBBBAAA
+  NNNNAAMMEEEEBMMM
+  BBBNAMMEEENNBMMM
+  BBBBBBBBBBBBBMMM
+  BBBEEEEEEEEEEMMM
+  BBBEEEEEEEEEEMMM
+  BBEEEEEEEEEEEEMM
+  BEEEEEEEEEEEEEEM
+  MMMMMMMMMMMMMMMM
+  AEEMMMMMMMMMEEEM
+  ABBBAAAAAAAABBBA
+  ABBBAMEEEEEMBBBA
+  ABBBAMEEEEEMBBBA
+  AMAAAMMEEEEMMAMA
+  AMMMAMMEEEEMMMMA
+  ABEEAMMEEEEMBEMA
+}
+# tile 221 (sub sokoban walls 4)
+{
+  AAANNNNBBBBBBAAA
+  NNNNAAMMEEEEBMMM
+  BBBNAMMEEENNBMMM
+  BBBBBBBBBBBBBMMM
+  BBBEEEEEEEEEEMMM
+  BBBEEEEEEEEEEMMM
+  BBEEEEEEEEEEEEMM
+  BEEEEEEEEEEEEEEM
+  MMMMMMMMMMMMMMMM
+  EEMBEEEEMBEEEMBE
+  EEMEEEEEMEEEEMEE
+  MMMMMMMMMMMMMMMM
+  MBEEEEMBEEEEMBEE
+  MEEEEEMEEEEEMEEE
+  MMMMMMMMMMMMMMMM
+  AAAAAAAAAAAAAAAA
+}
+# tile 222 (sub sokoban walls 5)
+{
+  AAANNNNBBBBBBAAA
+  NNNNAAMMEEEEBMMM
+  BBBNAMMEEENNBMMM
+  BBBBBBBBBBBBBMMM
+  BBBEEEEEEEEEEMMM
+  BBBEEEEEEEEEEMMM
+  BBEEEEEEEEEEEEMM
+  BEEEEEEEEEEEEEEM
+  MMMMMMMMMMMMMMMM
+  EEMBEEEEMBEEEMBE
+  EEMEEEEEMEEEEMEE
+  MMMMMMMMMMMMMMMM
+  MBEEEEMBEEEEMBEE
+  MEEEEEMEEEEEMEEE
+  MMMMMMMMMMMMMMMM
+  AAAAAAAAAAAAAAAA
+}
+# tile 223 (sub sokoban walls 6)
+{
+  AAANNNNBBBBBBAAA
+  NNNNAAMMEEEEBMMM
+  BBBNAMMEEENNBMMM
+  BBBBBBBBBBBBBMMM
+  BBBEEEEEEEEEEMMM
+  BBBEEEEEEEEEEMMM
+  BBEEEEEEEEEEEEMM
+  BEEEEEEEEEEEEEEM
+  MMMMMMMMMMMMMMMM
+  AEEMMMMMMMMMEEEM
+  ABBBAAAAAAAABBBA
+  ABBBAMEEEEEMBBBA
+  ABBBAMEEEEEMBBBA
+  AMAAAMMEEEEMMAMA
+  AMMMAMMEEEEMMMMA
+  ABEEAMMEEEEMBEMA
+}
+# tile 224 (sub sokoban walls 7)
+{
+  AAANNNNBBBBBBAAA
+  NNNNAAMMEEEEBMMM
+  BBBNAMMEEENNBMMM
+  BBBBBBBBBBBBBMMM
+  BBBEEEEEEEEEEMMM
+  BBBEEEEEEEEEEMMM
+  BBEEEEEEEEEEEEMM
+  BEEEEEEEEEEEEEEM
+  MMMMMMMMMMMMMMMM
+  EEMBEEEEMBEEEMBE
+  EEMEEEEEMEEEEMEE
+  MMMMMMMMMMMMMMMM
+  MBEEEEMBEEEEMBEE
+  MEEEEEMEEEEEMEEE
+  MMMMMMMMMMMMMMMM
+  AAAAAAAAAAAAAAAA
+}
+# tile 225 (sub sokoban walls 8)
+{
+  AAANNNNBBBBBBAAA
+  NNNNAAMMEEEEBMMM
+  BBBNAMMEEENNBMMM
+  BBBBBBBBBBBBBMMM
+  BBBEEEEEEEEEEMMM
+  BBBEEEEEEEEEEMMM
+  BBEEEEEEEEEEEEMM
+  BEEEEEEEEEEEEEEM
+  MMMMMMMMMMMMMMMM
+  AEEMMMMMMMMMEEEM
+  ABBBAAAAAAAABBBA
+  ABBBAMEEEEEMBBBA
+  ABBBAMEEEEEMBBBA
+  AMAAAMMEEEEMMAMA
+  AMMMAMMEEEEMMMMA
+  ABEEAMMEEEEMBEMA
+}
+# tile 226 (sub sokoban walls 9)
+{
+  AAANNNNBBBBBBAAA
+  NNNNAAMMEEEEBMMM
+  BBBNAMMEEENNBMMM
+  BBBBBBBBBBBBBMMM
+  BBBEEEEEEEEEEMMM
+  BBBEEEEEEEEEEMMM
+  BBEEEEEEEEEEEEMM
+  BEEEEEEEEEEEEEEM
+  MMMMMMMMMMMMMMMM
+  AEEMMMMMMMMMEEEM
+  ABBBAAAAAAAABBBA
+  ABBBAMEEEEEMBBBA
+  ABBBAMEEEEEMBBBA
+  AMAAAMMEEEEMMAMA
+  AMMMAMMEEEEMMMMA
+  ABEEAMMEEEEMBEMA
+}
+# tile 227 (sub sokoban walls 10)
+{
+  AAANNNNBBBBBBAAA
+  NNNNAAMMEEEEBMMM
+  BBBNAMMEEENNBMMM
+  BBBBBBBBBBBBBMMM
+  BBBEEEEEEEEEEMMM
+  BBBEEEEEEEEEEMMM
+  BBEEEEEEEEEEEEMM
+  BEEEEEEEEEEEEEEM
+  MMMMMMMMMMMMMMMM
+  AEEMMMMMMMMMEEEM
+  ABBBAAAAAAAABBBA
+  ABBBAMEEEEEMBBBA
+  ABBBAMEEEEEMBBBA
+  AMAAAMMEEEEMMAMA
+  AMMMAMMEEEEMMMMA
+  ABEEAMMEEEEMBEMA
+}
diff --git a/win/share/ppmwrite.c b/win/share/ppmwrite.c
new file mode 100644 (file)
index 0000000..ced5ffc
--- /dev/null
@@ -0,0 +1,171 @@
+/* this produces a raw ppm file, with a 15-character header of
+ * "P6 3-digit-width 3-digit-height 255\n"
+ */
+
+#include "config.h"
+#include "tile.h"
+
+#ifndef MONITOR_HEAP
+extern long *FDECL(alloc, (unsigned int));
+#endif
+
+FILE *ppm_file;
+
+struct ppmscreen {
+       int     Width;
+       int     Height;
+} PpmScreen;
+
+static int tiles_across, tiles_down, curr_tiles_across;
+static pixel **image;
+
+static void NDECL(write_header);
+static void NDECL(WriteTileStrip);
+
+static void
+write_header()
+{
+       (void) fprintf(ppm_file, "P6 %03d %03d 255\n",
+                               PpmScreen.Width, PpmScreen.Height);
+}
+
+static void
+WriteTileStrip()
+{
+       int i, j;
+
+       for (j = 0; j < TILE_Y; j++) {
+               for (i = 0; i < PpmScreen.Width; i++) {
+                       (void) fputc((char)image[j][i].r, ppm_file);
+                       (void) fputc((char)image[j][i].g, ppm_file);
+                       (void) fputc((char)image[j][i].b, ppm_file);
+               }
+       }
+}
+
+boolean
+fopen_ppm_file(filename, type)
+const char *filename;
+const char *type;
+{
+       int i;
+
+       if (strcmp(type, WRBMODE)) {
+               Fprintf(stderr, "using writing routine for non-writing?\n");
+               return FALSE;
+       }
+       ppm_file = fopen(filename, type);
+       if (ppm_file == (FILE *)0) {
+               Fprintf(stderr, "cannot open ppm file %s\n", filename);
+               return FALSE;
+       }
+
+       if (!colorsinmainmap) {
+               Fprintf(stderr, "no colormap set yet\n");
+               return FALSE;
+       }
+
+       tiles_across = 20;
+       curr_tiles_across = 0;
+       PpmScreen.Width = 20 * TILE_X;
+
+       tiles_down = 0;
+       PpmScreen.Height = 0;   /* will be rewritten later */
+
+       write_header();
+
+       image = (pixel **)alloc(TILE_Y * sizeof(pixel *));
+       for (i = 0; i < TILE_Y; i++) {
+               image[i] = (pixel *) alloc(PpmScreen.Width * sizeof(pixel));
+       }
+
+       return TRUE;
+}
+
+boolean
+write_ppm_tile(pixels)
+pixel (*pixels)[TILE_X];
+{
+       int i, j;
+
+       for (j = 0; j < TILE_Y; j++) {
+               for (i = 0; i < TILE_X; i++) {
+                       image[j][curr_tiles_across*TILE_X + i] = pixels[j][i];
+               }
+       }
+       curr_tiles_across++;
+       if (curr_tiles_across == tiles_across) {
+               WriteTileStrip();
+               curr_tiles_across = 0;
+               tiles_down++;
+       }
+       return TRUE;
+}
+
+int
+fclose_ppm_file()
+{
+       int i, j;
+
+       if (curr_tiles_across) {        /* partial row */
+               /* fill with checkerboard, for lack of a better idea */
+               for (j = 0; j < TILE_Y; j++) {
+                       for (i = curr_tiles_across * TILE_X;
+                                               i < PpmScreen.Width; i += 2 ) {
+                               image[j][i].r = MainColorMap[CM_RED][0];
+                               image[j][i].g = MainColorMap[CM_GREEN][0];
+                               image[j][i].b = MainColorMap[CM_BLUE][0];
+                               image[j][i+1].r = MainColorMap[CM_RED][1];
+                               image[j][i+1].g = MainColorMap[CM_GREEN][1];
+                               image[j][i+1].b = MainColorMap[CM_BLUE][1];
+                       }
+               }
+               WriteTileStrip();
+               curr_tiles_across = 0;
+               tiles_down++;
+       }
+
+       for (i = 0; i < TILE_Y; i++) {
+               free((genericptr_t)image[i]);
+       }
+       free((genericptr_t)image);
+
+       PpmScreen.Height = tiles_down * TILE_Y;
+       rewind(ppm_file);
+       write_header(); /* update size */
+
+       return(fclose(ppm_file));
+}
+
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       pixel pixels[TILE_Y][TILE_X];
+
+       if (argc != 3) {
+               Fprintf(stderr, "usage: txt2ppm txtfile ppmfile\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (!fopen_text_file(argv[1], RDTMODE))
+               exit(EXIT_FAILURE);
+
+       init_colormap();
+
+       if (!fopen_ppm_file(argv[2], WRBMODE)) {
+               (void) fclose_text_file();
+               exit(EXIT_FAILURE);
+       }
+
+       while (read_text_tile(pixels))
+               (void) write_ppm_tile(pixels);
+
+       (void) fclose_text_file();
+       (void) fclose_ppm_file();
+       exit(EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
diff --git a/win/share/thintile.c b/win/share/thintile.c
new file mode 100644 (file)
index 0000000..9e4dc33
--- /dev/null
@@ -0,0 +1,129 @@
+/*   SCCS Id: @(#)thintile.c   3.4     1995/11/26                     */
+/*   Copyright (c) NetHack Development Team 1995                    */
+/*   NetHack may be freely redistributed.  See license for details. */
+
+/* Create a set of overview tiles by eliminating even pixels in original */
+
+#include "config.h"
+#include "tile.h"
+
+#ifdef __GO32__
+#include <unistd.h>
+#endif
+
+static char pixels[TILE_Y][TILE_X];
+
+static char *tilefiles[] = {   "../win/share/monsters.txt",
+                               "../win/share/objects.txt",
+                               "../win/share/other.txt"};
+
+static char *thinfiles[] = {   "../win/share/monthin.txt",
+                               "../win/share/objthin.txt",
+                               "../win/share/oththin.txt"};
+static FILE *infile, *outfile;
+static int tilecount;
+static int tilecount_per_file;
+static int filenum;
+static char comment[BUFSZ];
+
+static void
+copy_colormap()
+{
+       int r, g, b;
+       char c[2];
+
+       while (fscanf(infile, "%[A-Za-z0-9] = (%d, %d, %d) ", c, &r, &g, &b)
+                                                               == 4) {
+               Fprintf(outfile, "%c = (%d, %d, %d)\n", c[0], r, g, b);
+       }
+}
+
+static boolean
+read_txttile()
+{
+       int i, j;
+       char buf[BUFSZ];
+       char buf2[BUFSZ];
+
+       char c[2];
+
+
+       if (fscanf(infile, "# %s %d (%[^)])", buf2, &i, buf) <= 0)
+               return FALSE;
+       
+       Sprintf(comment,"# tile %d (%s)", i, buf);
+       
+       /* look for non-whitespace at each stage */
+       if (fscanf(infile, "%1s", c) < 0) {
+               Fprintf(stderr, "unexpected EOF\n");
+               return FALSE;
+       }
+       if (c[0] != '{') {
+               Fprintf(stderr, "didn't find expected '{'\n");
+               return FALSE;
+       }
+       for (j = 0; j < TILE_Y; j++) {
+               for (i = 0; i < TILE_X; i++) {
+                       if (fscanf(infile, "%1s", c) < 0) {
+                               Fprintf(stderr, "unexpected EOF\n");
+                               return FALSE;
+                       }
+                       pixels[j][i] = c[0];
+               }
+       }
+       if (fscanf(infile, "%1s ", c) < 0) {
+               Fprintf(stderr, "unexpected EOF\n");
+               return FALSE;
+       }
+       if (c[0] != '}') {
+               Fprintf(stderr, "didn't find expected '}'\n");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+static void
+write_thintile()
+{
+       int i, j;
+
+
+       Fprintf(outfile, "%s\n", comment);
+       Fprintf(outfile, "{\n");
+       for (j = 0; j < TILE_Y; j++) {
+               Fprintf(outfile, "  ");
+               for (i = 0; i < TILE_X; i += 2) {
+                       (void) fputc(pixels[j][i], outfile);
+               }
+               Fprintf(outfile, "\n");
+       }
+       Fprintf(outfile, "}\n");
+}
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       while (filenum < 3) {
+               tilecount_per_file = 0;
+               infile = fopen(tilefiles[filenum], RDTMODE);
+               outfile = fopen(thinfiles[filenum], WRTMODE);
+               copy_colormap();
+               while (read_txttile()) {
+                               write_thintile();
+                               tilecount_per_file++;
+                               tilecount++;
+               }
+               fclose(outfile);
+               fclose(infile);
+               printf("%d tiles processed from %s\n",
+                       tilecount_per_file, tilefiles[filenum]);
+               ++filenum;
+       }
+       printf("Grand total of %d tiles processed.\n", tilecount);
+       exit(EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
+
+/*thintile.c*/
diff --git a/win/share/tile.doc b/win/share/tile.doc
new file mode 100644 (file)
index 0000000..a6d8f58
--- /dev/null
@@ -0,0 +1,140 @@
+Window ports can optionally make use of the tiles (pictures for NetHack
+symbols) found in this directory.  They are distributed in a text format
+with routines to help in converting them to a system's preferred format
+and using them there.  The original tiles were provided by Warwick Allison.
+
+The tile distribution format for monsters.txt, objects.txt, and other.txt
+starts with a palette header like:
+
+A = (0, 0, 0)
+...
+P = (254, 254, 254)
+
+and then each tile has an entry like:
+
+# tile 292 (comment identifying tile)
+{
+  AAAAGHPAAAAACDAA
+  AAAFGDEMLOCNAAAA
+...
+}
+
+Each port can convert these .txt files to whatever format it wants the
+game executable to use, probably providing only one merged output file.
+See the tilemap.c discussion at the bottom for more hints on adding tiles.
+
+
+Shared code provided for conversion utilities:
+
+tile.h contains shared declarations.
+
+tiletext.c defines the external variables from tile.h and supplies
+the external routines for reading and writing the defined text format.
+
+Each conversion utility is expected to use tiletext.c and provide code of
+its own for reading and/or writing another format.  The important global
+variables implement a colormap shared between tiletext.c and the other
+half of utilities.  As an example of conversion utilities, we provide
+txt2ppm (tiletext.c + ppmwrite.c) and gif2txt (tiletext.c + gifread.c).
+(Sorry, we're not paying Unisys patent royalties for the right to provide
+you with a gifwrite.c, which would necessarily use the LZW compression
+algorithm they claim.)
+
+The text I/O routines are:
+
+boolean fopen_text_file(const char *filename, const char *type);
+       select file for subsequent tile I/O
+       "type" a la fopen
+       returns FALSE if file not opened, otherwise reads/writes header
+       (including colormap) and sets up to decode/encode tiles
+int fclose_text_file();
+       close file
+boolean read_text_tile(pixel[TILE_Y][TILE_X]);
+       returns FALSE if no next tile in current file
+       otherwise TRUE and insert the tile in the provided array
+boolean write_text_tile(pixel[TILE_Y][TILE_X]);
+       writes tile
+
+There are two additional shared routines provided for writers:
+
+void init_colormap();
+       initialize the output colormap from the input one
+       must be called before opening output file as colormap is part of header
+void merge_colormap();
+       merge the current input colormap into the output one
+
+Due to the amount of state being kept, only one text or gif file can be
+open at a time.  If you are combining multiple files into one other-format
+file with a single common colormap, you may need to open each source file
+and merge their colormaps into a common colormap before processing any tiles.
+
+Although there are expected to be only 16 colors in the distribution tiles,
+conversion programs should be prepared to accept up to MAXCOLORMAPSIZE
+colors and map them to a smaller number if their port requires it.
+
+
+Expected sequence for editing tiles:
+       edit foo.txt
+
+       -or-
+
+       run txt2ppm foo.txt foo.ppm
+       convert ppm to gif, either via ppmtogif from pbmplus/netpbm or
+               stripping the first 15 bytes of foo.ppm (containing the
+               size of the image) and feeding the rest to any raw-24bit-
+               image-reading program
+       edit tiles with gif-editing program
+       run gif2txt foo.gif foo.txt
+
+
+When converted to ppm, monsters.ppm, objects.ppm, and other.ppm are:
+       each a single ppm format (rgb triples with header)
+       20 tiles across, however many down (need "blank" tile to fill in
+               extras on last row -- currently alternating pixels in
+               first and second colors)
+       allows looking at tiles en masse for comparison or whatever
+
+The gif reading routines accept further variations so long as the gif is
+n*TILE_X pixels across.
+
+The gif I/O routines are:
+
+boolean fopen_gif_file(const char *filename, const char *type);
+       select file for subsequent tile I/O
+       "type" a la fopen
+       returns FALSE if file not opened, otherwise reads gif header
+       (including colormap) and sets up to decode tiles
+int fclose_gif_file();
+       tear down decode mechanism
+       close file
+boolean read_gif_tile(pixel[TILE_Y][TILE_X]);
+       returns FALSE if no next tile in current file (including when any
+       remaining tiles are "blank"),
+       otherwise TRUE and insert the tile in the provided array
+
+
+Array provided by shared code for NetHack use, by compiling and running
+tilemap.c to form tile.c:
+
+short glyph2tile[MAXGLYPH];
+       maps glyph number to tile number for display purposes, assuming
+       (non-blank) tiles are numbered sequentially through
+       monsters/objects/other
+
+tilemap.c (shudder) accounts for things disappearing due to compilation
+options -- there should be a tile for everything appearing under any
+supported option, but under some options some tiles won't be referenced.
+Therefore, tilemap.c has the knowledge to provide the comments for gif2txt
+and is compiled with GIF2TXT to link in there, along with the various
+strings for things that are compiled in (monst.o etc.).
+
+If you add monsters/objects/other things to NetHack and need to add tiles
+to go with them, just add an entry in the right place in the appropriate
+.txt file, and one to tilemap.c if the new item is conditionally compiled.
+While the "comment identifying tile" in the .txt file must be correct,
+the number of the tile need not be, and can just be a duplicate of the
+tile on either side (or any other integer, for that matter).  In an
+official release, the tiles in a .txt file will be numbered consecutively
+so that you may cross-reference with a graphics format, but the conversion
+code does not care about the numbering.  (In fact, running txt2ppm, ppmtogif,
+and gif2txt gives you a consecutively numbered version of the .txt file.)
diff --git a/win/share/tile.h b/win/share/tile.h
new file mode 100644 (file)
index 0000000..4dd7633
--- /dev/null
@@ -0,0 +1,46 @@
+typedef unsigned char pixval;
+
+typedef struct {
+    pixval r, g, b;
+} pixel;
+
+#define MAXCOLORMAPSIZE        256
+
+#define CM_RED         0
+#define CM_GREEN       1
+#define CM_BLUE        2
+
+/* shared between reader and writer */
+extern pixval ColorMap[3][MAXCOLORMAPSIZE];
+extern int colorsinmap;
+/* writer's accumulated colormap */
+extern pixval MainColorMap[3][MAXCOLORMAPSIZE];
+extern int colorsinmainmap;
+
+#include "dlb.h"       /* for MODEs */
+
+/* size of tiles */
+#ifndef TILE_X
+#define TILE_X 16
+#endif
+#ifndef TILE_Y
+#define TILE_Y 16
+#endif
+
+#define Fprintf (void) fprintf
+
+
+extern boolean FDECL(fopen_text_file, (const char *, const char *));
+extern boolean FDECL(read_text_tile, (pixel (*)[TILE_X]));
+extern boolean FDECL(write_text_tile, (pixel (*)[TILE_X]));
+extern int NDECL(fclose_text_file);
+
+extern void NDECL(init_colormap);
+extern void NDECL(merge_colormap);
+
+#if defined(MICRO) || defined(WIN32)
+#undef exit
+# if !defined(MSDOS) && !defined(WIN32)
+extern void FDECL(exit, (int));
+# endif
+#endif
diff --git a/win/share/tile2bmp.c b/win/share/tile2bmp.c
new file mode 100644 (file)
index 0000000..9b3dbaf
--- /dev/null
@@ -0,0 +1,340 @@
+/*     SCCS Id: @(#)tile2bmp.c 3.4     2002/03/14      */
+/*   Copyright (c) NetHack PC Development Team 1995                 */
+/*   NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Edit History:
+ *
+ *     Initial Creation                        M.Allison   1994/01/11
+ *
+ */
+
+/* #pragma warning(4103:disable) */
+
+#include "hack.h"
+#include "tile.h"
+#ifndef __GNUC__
+#include "win32api.h"
+#endif
+
+/* #define COLORS_IN_USE MAXCOLORMAPSIZE       /* 256 colors */
+#if (TILE_X==32)
+#define COLORS_IN_USE 256
+#else
+#define COLORS_IN_USE 16                       /* 16 colors */
+#endif
+
+#define BITCOUNT 8
+
+extern char *FDECL(tilename, (int, int));
+
+#if BITCOUNT==4
+#define MAX_X 320              /* 2 per byte, 4 bits per pixel */
+#define MAX_Y 480
+#else
+# if (TILE_X==32)
+#define MAX_X (32 * 40)
+#define MAX_Y 960
+# else
+#define MAX_X 640              /* 1 per byte, 8 bits per pixel */
+#define MAX_Y 480
+# endif
+#endif 
+
+/* GCC fix by Paolo Bonzini 1999/03/28 */
+#ifdef __GNUC__
+#define PACK           __attribute__((packed))
+#else
+#define PACK
+#endif 
+
+static short leshort(short x)
+{
+#ifdef __BIG_ENDIAN__
+    return ((x&0xff)<<8)|((x>>8)&0xff);
+#else
+    return x;
+#endif
+}
+
+
+static long lelong(long x)
+{
+#ifdef __BIG_ENDIAN__
+    return ((x&0xff)<<24)|((x&0xff00)<<8)|((x>>8)&0xff00)|((x>>24)&0xff);
+#else
+    return x;
+#endif
+}
+
+#ifdef __GNUC__
+typedef struct tagBMIH {
+        unsigned long   biSize;
+        long           biWidth;
+        long           biHeight;
+        unsigned short  biPlanes;
+        unsigned short  biBitCount;
+        unsigned long   biCompression;
+        unsigned long   biSizeImage;
+        long           biXPelsPerMeter;
+        long           biYPelsPerMeter;
+        unsigned long   biClrUsed;
+        unsigned long   biClrImportant;
+} PACK BITMAPINFOHEADER;
+
+typedef struct tagBMFH {
+        unsigned short bfType;
+        unsigned long  bfSize;
+        unsigned short bfReserved1;
+        unsigned short bfReserved2;
+        unsigned long  bfOffBits;
+} PACK BITMAPFILEHEADER;
+
+typedef struct tagRGBQ {
+        unsigned char    rgbBlue;
+        unsigned char    rgbGreen;
+        unsigned char    rgbRed;
+        unsigned char    rgbReserved;
+} PACK RGBQUAD;
+#define UINT unsigned int
+#define DWORD unsigned long
+#define LONG long
+#define WORD unsigned short
+#define BI_RGB        0L
+#define BI_RLE8       1L
+#define BI_RLE4       2L
+#define BI_BITFIELDS  3L
+#endif /* __GNUC__ */
+
+#pragma pack(1)
+struct tagBMP{
+    BITMAPFILEHEADER bmfh;
+    BITMAPINFOHEADER bmih;
+#if BITCOUNT==4
+#define RGBQUAD_COUNT 16
+    RGBQUAD          bmaColors[RGBQUAD_COUNT];
+#else
+#if (TILE_X==32)
+#define RGBQUAD_COUNT 256
+#else
+#define RGBQUAD_COUNT 16
+#endif
+    RGBQUAD          bmaColors[RGBQUAD_COUNT];
+#endif
+#if (COLORS_IN_USE==16)
+    uchar            packtile[MAX_Y][MAX_X];
+#else
+    uchar            packtile[MAX_Y][MAX_X];
+/*    uchar            packtile[TILE_Y][TILE_X]; */
+#endif
+} PACK bmp;
+#pragma pack()
+
+#define BMPFILESIZE (sizeof(struct tagBMP))
+
+FILE *tibfile2;
+
+pixel tilepixels[TILE_Y][TILE_X];
+
+static void FDECL(build_bmfh,(BITMAPFILEHEADER *));
+static void FDECL(build_bmih,(BITMAPINFOHEADER *));
+static void FDECL(build_bmptile,(pixel (*)[TILE_X]));
+
+char *tilefiles[] = {
+#if (TILE_X == 32)
+               "../win/share/mon32.txt",
+               "../win/share/obj32.txt",
+               "../win/share/oth32.txt"
+#else
+               "../win/share/monsters.txt",
+               "../win/share/objects.txt",
+               "../win/share/other.txt"
+#endif
+};
+
+int num_colors = 0;
+int tilecount;
+int max_tiles_in_row = 40;
+int tiles_in_row;
+int filenum;
+int initflag;
+int yoffset,xoffset;
+char bmpname[128];
+FILE *fp;
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       int i, j;
+
+       if (argc != 2) {
+               Fprintf(stderr, "usage: %s outfile.bmp\n", argv[0]);
+               exit(EXIT_FAILURE);
+       } else
+               strcpy(bmpname, argv[1]);
+
+#ifdef OBSOLETE
+       bmpfile2 = fopen(NETHACK_PACKED_TILEFILE, WRBMODE);
+       if (bmpfile2 == (FILE *)0) {
+               Fprintf(stderr, "Unable to open output file %s\n",
+                               NETHACK_PACKED_TILEFILE);
+               exit(EXIT_FAILURE);
+       }
+#endif
+
+       tilecount = 0;
+       xoffset = yoffset = 0;
+       initflag = 0;
+       filenum = 0;
+       fp = fopen(bmpname,"wb");
+       if (!fp) {
+           printf("Error creating tile file %s, aborting.\n",bmpname);
+           exit(1);
+       }
+       while (filenum < (sizeof(tilefiles) / sizeof(char *))) {
+               if (!fopen_text_file(tilefiles[filenum], RDTMODE)) {
+                       Fprintf(stderr,
+                               "usage: tile2bmp (from the util directory)\n");
+                       exit(EXIT_FAILURE);
+               }
+               num_colors = colorsinmap;
+               if (num_colors > 62) {
+                       Fprintf(stderr, "too many colors (%d)\n", num_colors);
+                       exit(EXIT_FAILURE);
+               }
+               if (!initflag) {
+                   build_bmfh(&bmp.bmfh);
+                   build_bmih(&bmp.bmih);
+                   for (i = 0; i < MAX_Y; ++i)
+                       for (j = 0; j < MAX_X; ++j)
+                               bmp.packtile[i][j] = (uchar)0;
+                   for (i = 0; i < num_colors; i++) {
+                           bmp.bmaColors[i].rgbRed = ColorMap[CM_RED][i];
+                           bmp.bmaColors[i].rgbGreen = ColorMap[CM_GREEN][i];
+                           bmp.bmaColors[i].rgbBlue = ColorMap[CM_BLUE][i];
+                           bmp.bmaColors[i].rgbReserved = 0;
+                   }
+                   initflag = 1;
+               }
+/*             printf("Colormap initialized\n"); */
+               while (read_text_tile(tilepixels)) {
+                       build_bmptile(tilepixels);
+                       tilecount++;
+#if BITCOUNT==4
+                       xoffset += (TILE_X / 2);
+#else
+                       xoffset += TILE_X;
+#endif
+                       if (xoffset >= MAX_X) {
+                               yoffset += TILE_Y;
+                               xoffset = 0;
+                       }
+               }
+               (void) fclose_text_file();
+               ++filenum;
+       }
+       fwrite(&bmp, sizeof(bmp), 1, fp);
+       fclose(fp);
+       Fprintf(stderr, "Total of %d tiles written to %s.\n",
+               tilecount, bmpname);
+
+       exit(EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
+
+
+static void
+build_bmfh(pbmfh)
+BITMAPFILEHEADER *pbmfh;
+{
+       pbmfh->bfType = leshort(0x4D42);
+       pbmfh->bfSize = lelong(BMPFILESIZE);
+       pbmfh->bfReserved1 = (UINT)0;
+       pbmfh->bfReserved2 = (UINT)0;
+       pbmfh->bfOffBits = lelong(sizeof(bmp.bmfh) + sizeof(bmp.bmih) +
+                          (RGBQUAD_COUNT * sizeof(RGBQUAD)));
+}
+
+static void
+build_bmih(pbmih)
+BITMAPINFOHEADER *pbmih;
+{
+       WORD cClrBits;
+       int w,h;
+       pbmih->biSize = lelong(sizeof(bmp.bmih));
+#if BITCOUNT==4
+       pbmih->biWidth = lelong(w = MAX_X * 2);
+#else
+       pbmih->biWidth = lelong(w = MAX_X);
+#endif
+       pbmih->biHeight = lelong(h = MAX_Y);
+       pbmih->biPlanes = leshort(1);
+#if BITCOUNT==4
+       pbmih->biBitCount = leshort(4);
+       cClrBits = 4;
+#else
+       pbmih->biBitCount = leshort(8);
+       cClrBits = 8;
+#endif
+       if (cClrBits == 1) 
+               cClrBits = 1; 
+       else if (cClrBits <= 4) 
+               cClrBits = 4; 
+       else if (cClrBits <= 8) 
+               cClrBits = 8; 
+       else if (cClrBits <= 16) 
+               cClrBits = 16; 
+       else if (cClrBits <= 24) 
+               cClrBits = 24; 
+       else cClrBits = 32; 
+       pbmih->biCompression = lelong(BI_RGB);
+       pbmih->biXPelsPerMeter = lelong(0);
+       pbmih->biYPelsPerMeter = lelong(0);
+#if (TILE_X==32)
+       if (cClrBits < 24) 
+               pbmih->biClrUsed = lelong(1<<cClrBits);
+#else
+       pbmih->biClrUsed = lelong(RGBQUAD_COUNT); 
+#endif
+
+#if (TILE_X==16)
+       pbmih->biSizeImage = lelong(0);
+#else
+       pbmih->biSizeImage = lelong(((w * cClrBits +31) & ~31) /8 * h);
+#endif
+       pbmih->biClrImportant = (DWORD)0;
+}
+
+static void
+build_bmptile(pixels)
+pixel (*pixels)[TILE_X];
+{
+       int cur_x, cur_y, cur_color;
+       int x,y;
+
+       for (cur_y = 0; cur_y < TILE_Y; cur_y++) {
+        for (cur_x = 0; cur_x < TILE_X; cur_x++) {
+         for (cur_color = 0; cur_color < num_colors; cur_color++) {
+          if (ColorMap[CM_RED][cur_color] == pixels[cur_y][cur_x].r &&
+             ColorMap[CM_GREEN][cur_color]== pixels[cur_y][cur_x].g &&
+             ColorMap[CM_BLUE][cur_color] == pixels[cur_y][cur_x].b)
+               break;
+         }
+         if (cur_color >= num_colors)
+               Fprintf(stderr, "color not in colormap!\n");
+         y = (MAX_Y - 1) - (cur_y + yoffset);
+#if BITCOUNT==4
+         x = (cur_x / 2) + xoffset;
+         bmp.packtile[y][x] = cur_x%2 ?
+               (uchar)(bmp.packtile[y][x] | cur_color) :
+               (uchar)(cur_color<<4);
+#else
+         x = cur_x + xoffset;
+         bmp.packtile[y][x] = (uchar)cur_color;
+#endif
+        }
+       }
+}
diff --git a/win/share/tilemap.c b/win/share/tilemap.c
new file mode 100644 (file)
index 0000000..bca662b
--- /dev/null
@@ -0,0 +1,529 @@
+/*     SCCS Id: @(#)tilemap.c  3.4     2000/06/04      */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *     This source file is compiled twice:
+ *     once without TILETEXT defined to make tilemap.{o,obj},
+ *     then again with it defined to produce tiletxt.{o,obj}.
+ */
+
+#include "hack.h"
+
+const char * FDECL(tilename, (int, int));
+void NDECL(init_tilemap);
+void FDECL(process_substitutions, (FILE *));
+
+#if defined(MICRO) || defined(WIN32)
+#undef exit
+#if !defined(MSDOS) && !defined(WIN32)
+extern void FDECL(exit, (int));
+#endif
+#endif
+
+#define MON_GLYPH 1
+#define OBJ_GLYPH 2
+#define OTH_GLYPH 3    /* fortunately unnecessary */
+
+/* note that the ifdefs here should be the opposite sense from monst.c/
+ * objects.c/rm.h
+ */
+
+struct conditionals {
+       int sequence, predecessor;
+       const char *name;
+} conditionals[] = {
+#ifndef CHARON /* not supported yet */
+       { MON_GLYPH, PM_HELL_HOUND, "Cerberus" },
+#endif
+       /* commented out in monst.c at present */
+       { MON_GLYPH, PM_SHOCKING_SPHERE, "beholder" },
+       { MON_GLYPH, PM_BABY_SILVER_DRAGON, "baby shimmering dragon" },
+       { MON_GLYPH, PM_SILVER_DRAGON, "shimmering dragon" },
+       { MON_GLYPH, PM_JABBERWOCK, "vorpal jabberwock" },
+#ifndef KOPS
+       { MON_GLYPH, PM_JABBERWOCK, "Keystone Kop" },
+       { MON_GLYPH, PM_JABBERWOCK, "Kop Sergeant" },
+       { MON_GLYPH, PM_JABBERWOCK, "Kop Lieutenant" },
+       { MON_GLYPH, PM_JABBERWOCK, "Kop Kaptain" },
+#endif
+       { MON_GLYPH, PM_VAMPIRE_LORD, "vampire mage" },
+#ifndef CHARON /* not supported yet */
+       { MON_GLYPH, PM_CROESUS, "Charon" },
+#endif
+#ifndef MAIL
+       { MON_GLYPH, PM_FAMINE, "mail daemon" },
+#endif
+#ifndef TOURIST
+       { MON_GLYPH, PM_SAMURAI, "tourist" },
+#endif
+       /* commented out in monst.c at present */
+       { MON_GLYPH, PM_SHAMAN_KARNOV, "Earendil" },
+       { MON_GLYPH, PM_SHAMAN_KARNOV, "Elwing" },
+#ifndef TOURIST
+       { MON_GLYPH, PM_LORD_SATO, "Twoflower" },
+#endif
+       /* commented out in monst.c at present */
+       { MON_GLYPH, PM_CHROMATIC_DRAGON, "Goblin King" },
+       { MON_GLYPH, PM_NEANDERTHAL, "High-elf" },
+#ifndef TOURIST
+       { MON_GLYPH, PM_ROSHI, "guide" },
+#endif
+#ifndef KOPS
+       { OBJ_GLYPH, CLUB, "rubber hose" },
+#endif
+       /* objects commented out in objects.c at present */
+       { OBJ_GLYPH, SILVER_DRAGON_SCALE_MAIL, "shimmering dragon scale mail" },
+       { OBJ_GLYPH, SILVER_DRAGON_SCALES, "shimmering dragon scales" },
+#ifndef TOURIST
+       { OBJ_GLYPH, LEATHER_JACKET, "Hawaiian shirt" },
+       { OBJ_GLYPH, LEATHER_JACKET, "T-shirt" },
+       { OBJ_GLYPH, LOCK_PICK, "credit card" },
+       { OBJ_GLYPH, MAGIC_LAMP, "expensive camera" },
+#endif
+#ifndef STEED
+       { OBJ_GLYPH, TOWEL, "saddle" },
+#endif
+       /* allow slime mold to look like slice of pizza, since we
+        * don't know what a slime mold should look like when renamed anyway
+        */
+#ifndef MAIL
+       { OBJ_GLYPH, SCR_STINKING_CLOUD+4, "stamped / mail" },
+#endif
+       { 0, 0, 0}
+};
+
+
+/*
+ * Some entries in glyph2tile[] should be substituted for on various levels.
+ * The tiles used for the substitute entries will follow the usual ones in
+ * other.til in the order given here, which should have every substitution
+ * for the same set of tiles grouped together.  You will have to change
+ * more code in process_substitutions()/substitute_tiles() if the sets
+ * overlap in the future.
+ */
+struct substitute {
+       int first_glyph, last_glyph;
+       const char *sub_name;           /* for explanations */
+       const char *level_test;
+} substitutes[] = {
+       { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall,
+                                       "mine walls", "In_mines(plev)" },
+       { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall,
+                                       "gehennom walls", "In_hell(plev)" },
+       { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall,
+                                       "knox walls", "Is_knox(plev)" },
+       { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall,
+                                       "sokoban walls", "In_sokoban(plev)" }
+};
+
+
+#ifdef TILETEXT
+
+/*
+ * entry is the position of the tile within the monsters/objects/other set
+ */
+const char *
+tilename(set, entry)
+int set, entry;
+{
+       int i, j, condnum, tilenum;
+       static char buf[BUFSZ];
+
+       /* Note:  these initializers don't do anything except guarantee that
+               we're linked properly.
+       */
+       monst_init();
+       objects_init();
+       (void) def_char_to_objclass(']');
+
+       condnum = tilenum = 0;
+
+       for (i = 0; i < NUMMONS; i++) {
+               if (set == MON_GLYPH && tilenum == entry)
+                       return mons[i].mname;
+               tilenum++;
+               while (conditionals[condnum].sequence == MON_GLYPH &&
+                       conditionals[condnum].predecessor == i) {
+                       if (set == MON_GLYPH && tilenum == entry)
+                               return conditionals[condnum].name;
+                       condnum++;
+                       tilenum++;
+               }
+       }
+       if (set == MON_GLYPH && tilenum == entry)
+               return "invisible monster";
+
+       tilenum = 0;    /* set-relative number */
+       for (i = 0; i < NUM_OBJECTS; i++) {
+               /* prefer to give the description - that's all the tile's
+                * appearance should reveal */
+               if (set == OBJ_GLYPH && tilenum == entry) {
+                       if ( !obj_descr[i].oc_descr )
+                           return obj_descr[i].oc_name;
+                       if ( !obj_descr[i].oc_name )
+                           return obj_descr[i].oc_descr;
+
+                       Sprintf(buf, "%s / %s",
+                               obj_descr[i].oc_descr,
+                               obj_descr[i].oc_name);
+                       return buf;
+               }
+
+               tilenum++;
+               while (conditionals[condnum].sequence == OBJ_GLYPH &&
+                       conditionals[condnum].predecessor == i) {
+                       if (set == OBJ_GLYPH && tilenum == entry)
+                               return conditionals[condnum].name;
+                       condnum++;
+                       tilenum++;
+               }
+       }
+
+       tilenum = 0;    /* set-relative number */
+       for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) {
+               if (set == OTH_GLYPH && tilenum == entry) {
+                       if (*defsyms[i].explanation)
+                               return defsyms[i].explanation;
+                       else {
+                               /* if SINKS are turned off, this
+                                * string won't be there (and can't be there
+                                * to prevent symbol-identification and
+                                * special-level mimic appearances from
+                                * thinking the items exist)
+                                */
+                               switch (i) {
+                                   case S_sink:
+                                           Sprintf(buf, "sink");
+                                           break;
+                                   default:
+                                           Sprintf(buf, "cmap %d", tilenum);
+                                           break;
+                               }
+                               return buf;
+                       }
+               }
+               tilenum++;
+               while (conditionals[condnum].sequence == OTH_GLYPH &&
+                       conditionals[condnum].predecessor == i) {
+                       if (set == OTH_GLYPH && tilenum == entry)
+                               return conditionals[condnum].name;
+                       condnum++;
+                       tilenum++;
+               }
+       }
+       /* explosions */
+       tilenum = MAXPCHARS - MAXEXPCHARS;
+       i = entry - tilenum;
+       if (i < (MAXEXPCHARS * EXPL_MAX)) {
+           if (set == OTH_GLYPH) {
+               static char *explosion_types[] = { /* hack.h */
+                       "dark", "noxious", "muddy", "wet",
+                       "magical", "fiery", "frosty"
+               };
+               Sprintf(buf, "explosion %s %d",
+                       explosion_types[i / MAXEXPCHARS], i % MAXEXPCHARS);
+               return buf;
+           }
+       }
+       tilenum += (MAXEXPCHARS * EXPL_MAX);
+
+       i = entry - tilenum;
+       if (i < (NUM_ZAP << 2)) {
+               if (set == OTH_GLYPH) {
+                       Sprintf(buf, "zap %d %d", i/4, i%4);
+                       return buf;
+               }
+       }
+       tilenum += (NUM_ZAP << 2);
+
+       i = entry - tilenum;
+       if (i < WARNCOUNT) {
+               if (set == OTH_GLYPH) {
+                       Sprintf(buf, "warning %d", i);
+                       return buf;
+               }
+       }
+       tilenum += WARNCOUNT;
+
+       for (i = 0; i < SIZE(substitutes); i++) {
+           j = entry - tilenum;
+           if (j <= substitutes[i].last_glyph - substitutes[i].first_glyph) {
+               if (set == OTH_GLYPH) {
+                   Sprintf(buf, "sub %s %d", substitutes[i].sub_name, j);
+                   return buf;
+               }
+           }
+           tilenum += substitutes[i].last_glyph
+                               - substitutes[i].first_glyph + 1;
+       }
+
+       Sprintf(buf, "unknown %d %d", set, entry);
+       return buf;
+}
+
+#else  /* TILETEXT */
+
+#define TILE_FILE      "tile.c"
+
+#ifdef AMIGA
+# define SOURCE_TEMPLATE       "NH:src/%s"
+#else
+# ifdef MAC
+#   define SOURCE_TEMPLATE     ":src:%s"
+# else
+#   define SOURCE_TEMPLATE     "../src/%s"
+# endif
+#endif
+
+short tilemap[MAX_GLYPH];
+int lastmontile, lastobjtile, lastothtile;
+
+/* Number of tiles for invisible monsters */
+#define NUM_INVIS_TILES 1
+
+/*
+ * set up array to map glyph numbers to tile numbers
+ *
+ * assumes tiles are numbered sequentially through monsters/objects/other,
+ * with entries for all supported compilation options
+ *
+ * "other" contains cmap and zaps (the swallow sets are a repeated portion
+ * of cmap), as well as the "flash" glyphs for the new warning system
+ * introduced in 3.3.1.
+ */
+void
+init_tilemap()
+{
+       int i, j, condnum, tilenum;
+       int corpsetile, swallowbase;
+
+       for (i = 0; i < MAX_GLYPH; i++) {
+               tilemap[i] = -1;
+       }
+
+       corpsetile = NUMMONS + NUM_INVIS_TILES + CORPSE;
+       swallowbase= NUMMONS + NUM_INVIS_TILES + NUM_OBJECTS + S_sw_tl;
+
+       /* add number compiled out */
+       for (i = 0; conditionals[i].sequence; i++) {
+               switch (conditionals[i].sequence) {
+                       case MON_GLYPH:
+                               corpsetile++;
+                               swallowbase++;
+                               break;
+                       case OBJ_GLYPH:
+                               if (conditionals[i].predecessor < CORPSE)
+                                       corpsetile++;
+                               swallowbase++;
+                               break;
+                       case OTH_GLYPH:
+                               if (conditionals[i].predecessor < S_sw_tl)
+                                       swallowbase++;
+                               break;
+               }
+       }
+
+       condnum = tilenum = 0;
+       for (i = 0; i < NUMMONS; i++) {
+               tilemap[GLYPH_MON_OFF+i] = tilenum;
+               tilemap[GLYPH_PET_OFF+i] = tilenum;
+               tilemap[GLYPH_DETECT_OFF+i] = tilenum;
+               tilemap[GLYPH_RIDDEN_OFF+i] = tilenum;
+               tilemap[GLYPH_BODY_OFF+i] = corpsetile;
+               j = GLYPH_SWALLOW_OFF + 8*i;
+               tilemap[j] = swallowbase;
+               tilemap[j+1] = swallowbase+1;
+               tilemap[j+2] = swallowbase+2;
+               tilemap[j+3] = swallowbase+3;
+               tilemap[j+4] = swallowbase+4;
+               tilemap[j+5] = swallowbase+5;
+               tilemap[j+6] = swallowbase+6;
+               tilemap[j+7] = swallowbase+7;
+               tilenum++;
+               while (conditionals[condnum].sequence == MON_GLYPH &&
+                       conditionals[condnum].predecessor == i) {
+                       condnum++;
+                       tilenum++;
+               }
+       }
+       tilemap[GLYPH_INVISIBLE] = tilenum++;
+       lastmontile = tilenum - 1;
+
+       for (i = 0; i < NUM_OBJECTS; i++) {
+               tilemap[GLYPH_OBJ_OFF+i] = tilenum;
+               tilenum++;
+               while (conditionals[condnum].sequence == OBJ_GLYPH &&
+                       conditionals[condnum].predecessor == i) {
+                       condnum++;
+                       tilenum++;
+               }
+       }
+       lastobjtile = tilenum - 1;
+
+       for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) {
+               tilemap[GLYPH_CMAP_OFF+i] = tilenum;
+               tilenum++;
+               while (conditionals[condnum].sequence == OTH_GLYPH &&
+                       conditionals[condnum].predecessor == i) {
+                       condnum++;
+                       tilenum++;
+               }
+       }
+
+       for (i = 0; i < (MAXEXPCHARS * EXPL_MAX); i++) {
+               tilemap[GLYPH_EXPLODE_OFF+i] = tilenum;
+               tilenum++;
+               while (conditionals[condnum].sequence == OTH_GLYPH &&
+                       conditionals[condnum].predecessor == (i + MAXPCHARS)) {
+                       condnum++;
+                       tilenum++;
+               }
+       }
+
+       for (i = 0; i < NUM_ZAP << 2; i++) {
+               tilemap[GLYPH_ZAP_OFF+i] = tilenum;
+               tilenum++;
+               while (conditionals[condnum].sequence == OTH_GLYPH &&
+                       conditionals[condnum].predecessor == (i + MAXEXPCHARS)) {
+                       condnum++;
+                       tilenum++;
+               }
+       }
+
+       for (i = 0; i < WARNCOUNT; i++) {
+               tilemap[GLYPH_WARNING_OFF+i] = tilenum;
+               tilenum++;
+       }
+
+       lastothtile = tilenum - 1;
+}
+
+const char *prolog[] = {
+       "",
+       "",
+       "void",
+       "substitute_tiles(plev)",
+       "d_level *plev;",
+       "{",
+       "\tint i;",
+       ""
+};
+
+const char *epilog[] = {
+       "}"
+};
+
+/* write out the substitutions in an easily-used form. */
+void
+process_substitutions(ofp)
+FILE *ofp;
+{
+       int i, j, k, span, start;
+
+       fprintf(ofp, "\n\n");
+
+       j = 0;  /* unnecessary */
+       span = -1;
+       for (i = 0; i < SIZE(substitutes); i++) {
+           if (i == 0
+               || substitutes[i].first_glyph != substitutes[j].first_glyph
+               || substitutes[i].last_glyph != substitutes[j].last_glyph) {
+                       j = i;
+                       span++;
+                       fprintf(ofp, "short std_tiles%d[] = { ", span);
+                       for (k = substitutes[i].first_glyph;
+                               k < substitutes[i].last_glyph; k++)
+                                       fprintf(ofp, "%d, ", tilemap[k]);
+                       fprintf(ofp, "%d };\n",
+                               tilemap[substitutes[i].last_glyph]);
+           }
+       }
+
+       for (i = 0; i < SIZE(prolog); i++) {
+               fprintf(ofp, "%s\n", prolog[i]);
+       }
+       j = -1;
+       span = -1;
+       start = lastothtile + 1;
+       for (i = 0; i < SIZE(substitutes); i++) {
+           if (i == 0
+                   || substitutes[i].first_glyph != substitutes[j].first_glyph
+                   || substitutes[i].last_glyph != substitutes[j].last_glyph) {
+               if (i != 0) {   /* finish previous span */
+                   fprintf(ofp, "\t} else {\n");
+                   fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n",
+                                       substitutes[j].first_glyph,
+                                       substitutes[j].last_glyph);
+                   fprintf(ofp, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n",
+                                       span, substitutes[j].first_glyph);
+                   fprintf(ofp, "\t}\n\n");
+               }
+               j = i;
+               span++;
+           }
+           if (i != j) fprintf(ofp, "\t} else ");
+           fprintf(ofp, "\tif (%s) {\n", substitutes[i].level_test);
+           fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n",
+                               substitutes[i].first_glyph,
+                               substitutes[i].last_glyph);
+           fprintf(ofp, "\t\t\tglyph2tile[i] = %d + i - %d;\n",
+                               start, substitutes[i].first_glyph);
+           start += substitutes[i].last_glyph - substitutes[i].first_glyph + 1;
+       }
+       /* finish last span */
+       fprintf(ofp, "\t} else {\n");
+       fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n",
+                           substitutes[j].first_glyph,
+                           substitutes[j].last_glyph);
+       fprintf(ofp, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n",
+                           span, substitutes[j].first_glyph);
+       fprintf(ofp, "\t}\n\n");
+
+       for (i = 0; i < SIZE(epilog); i++) {
+               fprintf(ofp, "%s\n", epilog[i]);
+       }
+
+       fprintf(ofp, "\nint total_tiles_used = %d;\n", start);
+       lastothtile = start - 1;
+}
+
+int main()
+{
+    register int i;
+    char filename[30];
+    FILE *ofp;
+
+    init_tilemap();
+
+    /*
+     * create the source file, "tile.c"
+     */
+    Sprintf(filename, SOURCE_TEMPLATE, TILE_FILE);
+    if (!(ofp = fopen(filename, "w"))) {
+           perror(filename);
+           exit(EXIT_FAILURE);
+    }
+    fprintf(ofp,"/* This file is automatically generated.  Do not edit. */\n");
+    fprintf(ofp,"\n#include \"hack.h\"\n\n");
+    fprintf(ofp,"short glyph2tile[MAX_GLYPH] = {\n");
+
+    for (i = 0; i < MAX_GLYPH; i++) {
+       fprintf(ofp,"%2d,%c", tilemap[i], (i % 12) ? ' ' : '\n');
+    }
+    fprintf(ofp,"%s};\n", (i % 12) ? "\n" : "");
+
+    process_substitutions(ofp);
+
+    fprintf(ofp,"\n#define MAXMONTILE %d\n", lastmontile);
+    fprintf(ofp,"#define MAXOBJTILE %d\n", lastobjtile);
+    fprintf(ofp,"#define MAXOTHTILE %d\n", lastothtile);
+
+    fprintf(ofp,"\n/*tile.c*/\n");
+
+    fclose(ofp);
+    exit(EXIT_SUCCESS);
+    /*NOTREACHED*/
+    return 0;
+}
+
+#endif /* TILETEXT */
diff --git a/win/share/tiletext.c b/win/share/tiletext.c
new file mode 100644 (file)
index 0000000..8ac8abe
--- /dev/null
@@ -0,0 +1,332 @@
+/*     SCCS Id: @(#)tiletext.c 3.4     1999/10/24      */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "config.h"
+#include "tile.h"
+
+pixval ColorMap[3][MAXCOLORMAPSIZE];
+int colorsinmap;
+pixval MainColorMap[3][MAXCOLORMAPSIZE];
+int colorsinmainmap;
+
+static short color_index[MAXCOLORMAPSIZE];
+static int num_colors;
+static char charcolors[MAXCOLORMAPSIZE];
+
+static int placeholder_init = 0;
+static pixel placeholder[TILE_Y][TILE_X];
+static FILE *tile_file;
+static int tile_set, tile_set_indx;
+#if (TILE_X==8)
+static const char *text_sets[] = { "monthin.txt", "objthin.txt", "oththin.txt" };
+#else
+static const char *text_sets[] = { "monsters.txt", "objects.txt", "other.txt" };
+#endif
+
+extern const char *FDECL(tilename, (int, int));
+static void FDECL(read_text_colormap, (FILE *));
+static boolean FDECL(write_text_colormap, (FILE *));
+static boolean FDECL(read_txttile, (FILE *, pixel(*)[TILE_X]));
+static void FDECL(write_txttile, (FILE *, pixel(*)[TILE_X]));
+
+/* Ugh.  DICE doesn't like %[A-Z], so we have to spell it out... */
+#define FORMAT_STRING \
+"%[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789] = (%d, %d, %d) "
+
+static void
+read_text_colormap(txtfile)
+FILE *txtfile;
+{
+       int i, r, g, b;
+       char c[2];
+
+       for (i = 0; i < MAXCOLORMAPSIZE; i++)
+               color_index[i] = -1;
+
+       num_colors = 0;
+       while (fscanf(txtfile, FORMAT_STRING, c, &r, &g, &b) == 4) {
+               color_index[(int) c[0]] = num_colors;
+               ColorMap[CM_RED][num_colors] = r;
+               ColorMap[CM_GREEN][num_colors] = g;
+               ColorMap[CM_BLUE][num_colors] = b;
+               num_colors++;
+       }
+       colorsinmap = num_colors;
+}
+
+#undef FORMAT_STRING
+
+static boolean
+write_text_colormap(txtfile)
+FILE *txtfile;
+{
+       int i;
+       char c;
+
+       num_colors = colorsinmainmap;
+       if (num_colors > 62) {
+               Fprintf(stderr, "too many colors (%d)\n", num_colors);
+               return FALSE;
+       }
+       for (i = 0; i < num_colors; i++) {
+               if (i < 26) c = 'A' + i;
+               else if (i < 52) c = 'a' + i - 26;
+               else c = '0' + i - 52;
+
+               charcolors[i] = c;
+               Fprintf(txtfile, "%c = (%d, %d, %d)\n", c,
+                                               (int)MainColorMap[CM_RED][i],
+                                               (int)MainColorMap[CM_GREEN][i],
+                                               (int)MainColorMap[CM_BLUE][i]);
+       }
+       return TRUE;
+}
+
+static boolean
+read_txttile(txtfile, pixels)
+FILE *txtfile;
+pixel (*pixels)[TILE_X];
+{
+       int ph, i, j, k;
+       char buf[BUFSZ], ttype[BUFSZ];
+       const char *p;
+       char c[2];
+
+       if (fscanf(txtfile, "# %s %d (%[^)])", ttype, &i, buf) <= 0)
+               return FALSE;
+       
+       ph = strcmp(ttype, "placeholder") == 0;
+
+       if (!ph && strcmp(ttype,"tile") != 0)
+               Fprintf(stderr,
+                       "Keyword \"%s\" unexpected for entry %d\n",
+                       ttype, i);
+
+       if (tile_set != 0) {
+           /* check tile name, but not relative number, which will
+            * change when tiles are added
+            */
+           p = tilename(tile_set, tile_set_indx);
+           if (p && strcmp(p, buf)) {
+               Fprintf(stderr, "warning: for tile %d (numbered %d) of %s,\n",
+                               tile_set_indx, i, text_sets[tile_set-1]);
+               Fprintf(stderr, "\tfound '%s' while expecting '%s'\n",
+                               buf, p);
+           }
+       }
+       tile_set_indx++;
+               
+       /* look for non-whitespace at each stage */
+       if (fscanf(txtfile, "%1s", c) < 0) {
+               Fprintf(stderr, "unexpected EOF\n");
+               return FALSE;
+       }
+       if (c[0] != '{') {
+               Fprintf(stderr, "didn't find expected '{'\n");
+               return FALSE;
+       }
+       for (j = 0; j < TILE_Y; j++) {
+               for (i = 0; i < TILE_X; i++) {
+                       if (fscanf(txtfile, "%1s", c) < 0) {
+                               Fprintf(stderr, "unexpected EOF\n");
+                               return FALSE;
+                       }
+                       k = color_index[(int) c[0]];
+                       if (k == -1)
+                               Fprintf(stderr,
+                                       "color %c not in colormap!\n", c[0]);
+                       else {
+                               pixels[j][i].r = ColorMap[CM_RED][k];
+                               pixels[j][i].g = ColorMap[CM_GREEN][k];
+                               pixels[j][i].b = ColorMap[CM_BLUE][k];
+                       }
+               }
+       }
+       if ( ph ) {
+           /* remember it for later */
+           memcpy( placeholder, pixels, sizeof(placeholder) );
+       }
+       if (fscanf(txtfile, "%1s ", c) < 0) {
+               Fprintf(stderr, "unexpected EOF\n");
+               return FALSE;
+       }
+       if (c[0] != '}') {
+               Fprintf(stderr, "didn't find expected '}'\n");
+               return FALSE;
+       }
+#ifdef _DCC
+       /* DICE again... it doesn't seem to eat whitespace after the } like
+        * it should, so we have to do so manually.
+        */
+       while ((*c = fgetc(txtfile)) != EOF && isspace(*c))
+               ;
+       ungetc(*c, txtfile);
+#endif
+       return TRUE;
+}
+
+static void
+write_txttile(txtfile, pixels)
+FILE *txtfile;
+pixel (*pixels)[TILE_X];
+{
+       const char *p;
+       const char *type;
+       int i, j, k;
+
+       if ( memcmp(placeholder, pixels, sizeof(placeholder)) == 0 )
+           type = "placeholder";
+       else
+           type = "tile";
+
+       if (tile_set == 0)
+               Fprintf(txtfile, "# %s %d (unknown)\n", type, tile_set_indx);
+       else {
+               p = tilename(tile_set, tile_set_indx);
+               if (p)
+                   Fprintf(txtfile, "# %s %d (%s)\n", type, tile_set_indx, p);
+               else
+                   Fprintf(txtfile, "# %s %d (null)\n", type, tile_set_indx);
+       }
+       tile_set_indx++;
+
+       Fprintf(txtfile, "{\n");
+       for (j = 0; j < TILE_Y; j++) {
+               Fprintf(txtfile, "  ");
+               for (i = 0; i < TILE_X; i++) {
+                       for (k = 0; k < num_colors; k++) {
+                               if (ColorMap[CM_RED][k] == pixels[j][i].r &&
+                                   ColorMap[CM_GREEN][k] == pixels[j][i].g &&
+                                   ColorMap[CM_BLUE][k] == pixels[j][i].b)
+                                       break;
+                       }
+                       if (k >= num_colors)
+                               Fprintf(stderr, "color not in colormap!\n");
+                       (void) fputc(charcolors[k], txtfile);
+               }
+               Fprintf(txtfile, "\n");
+       }
+       Fprintf(txtfile, "}\n");
+}
+
+/* initialize main colormap from globally accessed ColorMap */
+void
+init_colormap()
+{
+       int i;
+
+       colorsinmainmap = colorsinmap;
+       for (i = 0; i < colorsinmap; i++) {
+               MainColorMap[CM_RED][i] = ColorMap[CM_RED][i];
+               MainColorMap[CM_GREEN][i] = ColorMap[CM_GREEN][i];
+               MainColorMap[CM_BLUE][i] = ColorMap[CM_BLUE][i];
+       }
+}
+
+/* merge new colors from ColorMap into MainColorMap */
+void
+merge_colormap()
+{
+       int i, j;
+
+       for (i = 0; i < colorsinmap; i++) {
+               for (j = 0; j < colorsinmainmap; j++) {
+                   if (MainColorMap[CM_RED][j] == ColorMap[CM_RED][i] &&
+                       MainColorMap[CM_GREEN][j] == ColorMap[CM_GREEN][i] &&
+                       MainColorMap[CM_BLUE][j] == ColorMap[CM_BLUE][i])
+                           break;
+               }
+               if (j >= colorsinmainmap) {     /* new color */
+                   if (colorsinmainmap >= MAXCOLORMAPSIZE) {
+                       Fprintf(stderr,
+                           "Too many colors to merge -- excess ignored.\n");
+                   }
+                   j = colorsinmainmap;
+                   MainColorMap[CM_RED][j] = ColorMap[CM_RED][i];
+                   MainColorMap[CM_GREEN][j] = ColorMap[CM_GREEN][i];
+                   MainColorMap[CM_BLUE][j] = ColorMap[CM_BLUE][i];
+                   colorsinmainmap++;
+               }
+       }
+}
+
+boolean
+fopen_text_file(filename, type)
+const char *filename;
+const char *type;
+{
+       const char *p;
+       int i;
+
+       if (tile_file != (FILE *)0) {
+               Fprintf(stderr, "can only open one text file at at time\n");
+               return FALSE;
+       }
+
+       tile_file = fopen(filename, type);
+       if (tile_file == (FILE *)0) {
+               Fprintf(stderr, "cannot open text file %s\n", filename);
+               return FALSE;
+       }
+
+       p = rindex(filename, '/');
+       if (p) p++;
+       else p = filename;
+
+       tile_set = 0;
+       for (i = 0; i < SIZE(text_sets); i++) {
+               if (!strcmp(p, text_sets[i]))
+                       tile_set = i+1;
+       }
+       tile_set_indx = 0;
+
+       if (!strcmp(type, RDTMODE)) {
+               /* Fill placeholder with noise */
+               if ( !placeholder_init ) {
+                   placeholder_init++;
+                   for ( i=0; i<sizeof(placeholder); i++ )
+                       ((char*)placeholder)[i]=i%256;
+               }
+
+               read_text_colormap(tile_file);
+               if (!colorsinmainmap)
+                       init_colormap();
+               else
+                       merge_colormap();
+               return TRUE;
+       } else if (!strcmp(type, WRTMODE)) {
+               if (!colorsinmainmap) {
+                       Fprintf(stderr, "no colormap set yet\n");
+                       return FALSE;
+               }
+               return(write_text_colormap(tile_file));
+       } else {
+               Fprintf(stderr, "bad mode (%s) for fopen_text_file\n", type);
+               return FALSE;
+       }
+}
+
+boolean
+read_text_tile(pixels)
+pixel (*pixels)[TILE_X];
+{
+       return(read_txttile(tile_file, pixels));
+}
+
+boolean
+write_text_tile(pixels)
+pixel (*pixels)[TILE_X];
+{
+       write_txttile(tile_file, pixels);
+       return TRUE;
+}
+
+int
+fclose_text_file()
+{
+       int ret;
+
+       ret = fclose(tile_file);
+       tile_file = (FILE *)0;
+       return ret;
+}
diff --git a/win/tty/getline.c b/win/tty/getline.c
new file mode 100644 (file)
index 0000000..c897cb8
--- /dev/null
@@ -0,0 +1,284 @@
+/*     SCCS Id: @(#)getline.c  3.4     2002/10/06      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+#ifdef TTY_GRAPHICS
+
+#if !defined(MAC)
+#define NEWAUTOCOMP
+#endif
+
+#include "wintty.h"
+#include "func_tab.h"
+
+#ifdef OVL1
+char morc = 0; /* tell the outside world what char you chose */
+#endif /* OVL1 */
+STATIC_DCL boolean FDECL(ext_cmd_getlin_hook, (char *));
+
+typedef boolean FDECL((*getlin_hook_proc), (char *));
+
+STATIC_DCL void FDECL(hooked_tty_getlin, (const char*,char*,getlin_hook_proc));
+extern int NDECL(extcmd_via_menu);     /* cmd.c */
+
+extern char erase_char, kill_char;     /* from appropriate tty.c file */
+
+#ifdef OVL1
+
+/*
+ * Read a line closed with '\n' into the array char bufp[BUFSZ].
+ * (The '\n' is not stored. The string is closed with a '\0'.)
+ * Reading can be interrupted by an escape ('\033') - now the
+ * resulting string is "\033".
+ */
+void
+tty_getlin(query, bufp)
+const char *query;
+register char *bufp;
+{
+    hooked_tty_getlin(query, bufp, (getlin_hook_proc) 0);
+}
+
+STATIC_OVL void
+hooked_tty_getlin(query, bufp, hook)
+const char *query;
+register char *bufp;
+getlin_hook_proc hook;
+{
+       register char *obufp = bufp;
+       register int c;
+       struct WinDesc *cw = wins[WIN_MESSAGE];
+       boolean doprev = 0;
+
+       if(ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) more();
+       cw->flags &= ~WIN_STOP;
+       ttyDisplay->toplin = 3; /* special prompt state */
+       ttyDisplay->inread++;
+       pline("%s ", query);
+       *obufp = 0;
+       for(;;) {
+               (void) fflush(stdout);
+               Sprintf(toplines, "%s ", query);
+               Strcat(toplines, obufp);
+               if((c = Getchar()) == EOF) {
+#ifndef NEWAUTOCOMP
+                       *bufp = 0;
+#endif /* not NEWAUTOCOMP */
+                       break;
+               }
+               if(c == '\033') {
+                       *obufp = c;
+                       obufp[1] = 0;
+                       break;
+               }
+               if (ttyDisplay->intr) {
+                   ttyDisplay->intr--;
+                   *bufp = 0;
+               }
+               if(c == '\020') { /* ctrl-P */
+                   if (iflags.prevmsg_window != 's') {
+                       int sav = ttyDisplay->inread;
+                       ttyDisplay->inread = 0;
+                       (void) tty_doprev_message();
+                       ttyDisplay->inread = sav;
+                       tty_clear_nhwindow(WIN_MESSAGE);
+                       cw->maxcol = cw->maxrow;
+                       addtopl(query);
+                       addtopl(" ");
+                       *bufp = 0;
+                       addtopl(obufp);
+                   } else {
+                       if (!doprev)
+                           (void) tty_doprev_message();/* need two initially */
+                       (void) tty_doprev_message();
+                       doprev = 1;
+                       continue;
+                   }
+               } else if (doprev && iflags.prevmsg_window == 's') {
+                   tty_clear_nhwindow(WIN_MESSAGE);
+                   cw->maxcol = cw->maxrow;
+                   doprev = 0;
+                   addtopl(query);
+                   addtopl(" ");
+                   *bufp = 0;
+                   addtopl(obufp);
+               }
+               if(c == erase_char || c == '\b') {
+                       if(bufp != obufp) {
+#ifdef NEWAUTOCOMP
+                               char *i;
+
+#endif /* NEWAUTOCOMP */
+                               bufp--;
+#ifndef NEWAUTOCOMP
+                               putsyms("\b \b");/* putsym converts \b */
+#else /* NEWAUTOCOMP */
+                               putsyms("\b");
+                               for (i = bufp; *i; ++i) putsyms(" ");
+                               for (; i > bufp; --i) putsyms("\b");
+                               *bufp = 0;
+#endif /* NEWAUTOCOMP */
+                       } else  tty_nhbell();
+#if defined(apollo)
+               } else if(c == '\n' || c == '\r') {
+#else
+               } else if(c == '\n') {
+#endif
+#ifndef NEWAUTOCOMP
+                       *bufp = 0;
+#endif /* not NEWAUTOCOMP */
+                       break;
+               } else if(' ' <= (unsigned char) c && c != '\177' &&
+                           (bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)) {
+                               /* avoid isprint() - some people don't have it
+                                  ' ' is not always a printing char */
+#ifdef NEWAUTOCOMP
+                       char *i = eos(bufp);
+
+#endif /* NEWAUTOCOMP */
+                       *bufp = c;
+                       bufp[1] = 0;
+                       putsyms(bufp);
+                       bufp++;
+                       if (hook && (*hook)(obufp)) {
+                           putsyms(bufp);
+#ifndef NEWAUTOCOMP
+                           bufp = eos(bufp);
+#else /* NEWAUTOCOMP */
+                           /* pointer and cursor left where they were */
+                           for (i = bufp; *i; ++i) putsyms("\b");
+                       } else if (i > bufp) {
+                           char *s = i;
+
+                           /* erase rest of prior guess */
+                           for (; i > bufp; --i) putsyms(" ");
+                           for (; s > bufp; --s) putsyms("\b");
+#endif /* NEWAUTOCOMP */
+                       }
+               } else if(c == kill_char || c == '\177') { /* Robert Viduya */
+                               /* this test last - @ might be the kill_char */
+#ifndef NEWAUTOCOMP
+                       while(bufp != obufp) {
+                               bufp--;
+                               putsyms("\b \b");
+                       }
+#else /* NEWAUTOCOMP */
+                       for (; *bufp; ++bufp) putsyms(" ");
+                       for (; bufp != obufp; --bufp) putsyms("\b \b");
+                       *bufp = 0;
+#endif /* NEWAUTOCOMP */
+               } else
+                       tty_nhbell();
+       }
+       ttyDisplay->toplin = 2;         /* nonempty, no --More-- required */
+       ttyDisplay->inread--;
+       clear_nhwindow(WIN_MESSAGE);    /* clean up after ourselves */
+}
+
+void
+xwaitforspace(s)
+register const char *s;        /* chars allowed besides return */
+{
+    register int c, x = ttyDisplay ? (int) ttyDisplay->dismiss_more : '\n';
+
+    morc = 0;
+
+    while((c = tty_nhgetch()) != '\n') {
+       if(iflags.cbreak) {
+           if ((s && index(s,c)) || c == x) {
+               morc = (char) c;
+               break;
+           }
+           tty_nhbell();
+       }
+    }
+
+}
+
+#endif /* OVL1 */
+#ifdef OVL2
+
+/*
+ * Implement extended command completion by using this hook into
+ * tty_getlin.  Check the characters already typed, if they uniquely
+ * identify an extended command, expand the string to the whole
+ * command.
+ *
+ * Return TRUE if we've extended the string at base.  Otherwise return FALSE.
+ * Assumptions:
+ *
+ *     + we don't change the characters that are already in base
+ *     + base has enough room to hold our string
+ */
+STATIC_OVL boolean
+ext_cmd_getlin_hook(base)
+       char *base;
+{
+       int oindex, com_index;
+
+       com_index = -1;
+       for (oindex = 0; extcmdlist[oindex].ef_txt != (char *)0; oindex++) {
+               if (!strncmpi(base, extcmdlist[oindex].ef_txt, strlen(base))) {
+                       if (com_index == -1)    /* no matches yet */
+                           com_index = oindex;
+                       else                    /* more than 1 match */
+                           return FALSE;
+               }
+       }
+       if (com_index >= 0) {
+               Strcpy(base, extcmdlist[com_index].ef_txt);
+               return TRUE;
+       }
+
+       return FALSE;   /* didn't match anything */
+}
+
+/*
+ * Read in an extended command, doing command line completion.  We
+ * stop when we have found enough characters to make a unique command.
+ */
+int
+tty_get_ext_cmd()
+{
+       int i;
+       char buf[BUFSZ];
+
+       if (iflags.extmenu) return extcmd_via_menu();
+       /* maybe a runtime option? */
+       /* hooked_tty_getlin("#", buf, flags.cmd_comp ? ext_cmd_getlin_hook : (getlin_hook_proc) 0); */
+#ifdef REDO
+       hooked_tty_getlin("#", buf, in_doagain ? (getlin_hook_proc)0
+               : ext_cmd_getlin_hook);
+#else
+       hooked_tty_getlin("#", buf, ext_cmd_getlin_hook);
+#endif
+       (void) mungspaces(buf);
+       if (buf[0] == 0 || buf[0] == '\033') return -1;
+
+       for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++)
+               if (!strcmpi(buf, extcmdlist[i].ef_txt)) break;
+
+#ifdef REDO
+       if (!in_doagain) {
+           int j;
+           for (j = 0; buf[j]; j++)
+               savech(buf[j]);
+           savech('\n');
+       }
+#endif
+
+       if (extcmdlist[i].ef_txt == (char *)0) {
+               pline("%s: unknown extended command.", buf);
+               i = -1;
+       }
+
+       return i;
+}
+
+#endif /* OVL2 */
+
+#endif /* TTY_GRAPHICS */
+
+/*getline.c*/
diff --git a/win/tty/termcap.c b/win/tty/termcap.c
new file mode 100644 (file)
index 0000000..706e203
--- /dev/null
@@ -0,0 +1,1185 @@
+/*     SCCS Id: @(#)termcap.c  3.4     2000/07/10      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+#if defined (TTY_GRAPHICS) && !defined(NO_TERMS)
+
+#include "wintty.h"
+
+#include "tcap.h"
+
+
+#ifdef MICROPORT_286_BUG
+#define Tgetstr(key) (tgetstr(key,tbuf))
+#else
+#define Tgetstr(key) (tgetstr(key,&tbufptr))
+#endif /* MICROPORT_286_BUG **/
+
+static char * FDECL(s_atr2str, (int));
+static char * FDECL(e_atr2str, (int));
+
+void FDECL(cmov, (int, int));
+void FDECL(nocmov, (int, int));
+#if defined(TEXTCOLOR) && defined(TERMLIB)
+# ifdef OVLB
+#  if !defined(UNIX) || !defined(TERMINFO)
+#   ifndef TOS
+static void FDECL(analyze_seq, (char *, int *, int *));
+#   endif
+#  endif
+static void NDECL(init_hilite);
+static void NDECL(kill_hilite);
+# endif /* OVLB */
+#endif
+
+#ifdef OVLB
+       /* (see tcap.h) -- nh_CM, nh_ND, nh_CD, nh_HI,nh_HE, nh_US,nh_UE,
+                               ul_hack */
+struct tc_lcl_data tc_lcl_data = { 0, 0, 0, 0,0, 0,0, FALSE };
+#endif /* OVLB */
+
+STATIC_VAR char *HO, *CL, *CE, *UP, *XD, *BC, *SO, *SE, *TI, *TE;
+STATIC_VAR char *VS, *VE;
+STATIC_VAR char *ME;
+STATIC_VAR char *MR;
+#if 0
+STATIC_VAR char *MB, *MH;
+STATIC_VAR char *MD;     /* may already be in use below */
+#endif
+#ifdef TERMLIB
+# ifdef TEXTCOLOR
+STATIC_VAR char *MD;
+# endif
+STATIC_VAR int SG;
+#ifdef OVLB
+STATIC_OVL char PC = '\0';
+#else /* OVLB */
+STATIC_DCL char PC;
+#endif /* OVLB */
+STATIC_VAR char tbuf[512];
+#endif
+
+#ifdef TEXTCOLOR
+# ifdef TOS
+const char *hilites[CLR_MAX];  /* terminal escapes for the various colors */
+# else
+char NEARDATA *hilites[CLR_MAX]; /* terminal escapes for the various colors */
+# endif
+#endif
+
+#ifdef OVLB
+static char *KS = (char *)0, *KE = (char *)0;  /* keypad sequences */
+static char nullstr[] = "";
+#endif /* OVLB */
+
+#if defined(ASCIIGRAPH) && !defined(NO_TERMS)
+extern boolean HE_resets_AS;
+#endif
+
+#ifndef TERMLIB
+STATIC_VAR char tgotobuf[20];
+# ifdef TOS
+#define tgoto(fmt, x, y)       (Sprintf(tgotobuf, fmt, y+' ', x+' '), tgotobuf)
+# else
+#define tgoto(fmt, x, y)       (Sprintf(tgotobuf, fmt, y+1, x+1), tgotobuf)
+# endif
+#endif /* TERMLIB */
+
+#ifdef OVLB
+
+void
+tty_startup(wid, hgt)
+int *wid, *hgt;
+{
+       register int i;
+#ifdef TERMLIB
+       register const char *term;
+       register char *tptr;
+       char *tbufptr, *pc;
+
+# ifdef VMS
+       term = verify_termcap();
+       if (!term)
+# endif
+               term = getenv("TERM");
+
+# if defined(TOS) && defined(__GNUC__)
+       if (!term)
+               term = "builtin";               /* library has a default */
+# endif
+       if (!term)
+#endif
+#ifndef ANSI_DEFAULT
+               error("Can't get TERM.");
+#else
+# ifdef TOS
+       {
+               CO = 80; LI = 25;
+               TI = VS = VE = TE = nullstr;
+               HO = "\033H";
+               CE = "\033K";           /* the VT52 termcap */
+               UP = "\033A";
+               nh_CM = "\033Y%c%c";    /* used with function tgoto() */
+               nh_ND = "\033C";
+               XD = "\033B";
+               BC = "\033D";
+               SO = "\033p";
+               SE = "\033q";
+       /* HI and HE will be updated in init_hilite if we're using color */
+               nh_HI = "\033p";
+               nh_HE = "\033q";
+               *wid = CO;
+               *hgt = LI;
+               CL = "\033E";           /* last thing set */
+               return;
+       }
+# else /* TOS */
+       {
+#  ifdef MICRO
+               get_scr_size();
+#   ifdef CLIPPING
+               if(CO < COLNO || LI < ROWNO+3)
+                       setclipped();
+#   endif
+#  endif
+               HO = "\033[H";
+/*             nh_CD = "\033[J"; */
+               CE = "\033[K";          /* the ANSI termcap */
+#  ifndef TERMLIB
+               nh_CM = "\033[%d;%dH";
+#  else
+               nh_CM = "\033[%i%d;%dH";
+#  endif
+               UP = "\033[A";
+               nh_ND = "\033[C";
+               XD = "\033[B";
+#  ifdef MICRO /* backspaces are non-destructive */
+               BC = "\b";
+#  else
+               BC = "\033[D";
+#  endif
+               nh_HI = SO = "\033[1m";
+               nh_US = "\033[4m";
+               MR = "\033[7m";
+               TI = nh_HE = ME = SE = nh_UE = "\033[0m";
+               /* strictly, SE should be 2, and nh_UE should be 24,
+                  but we can't trust all ANSI emulators to be
+                  that complete.  -3. */
+#  ifndef MICRO
+               AS = "\016";
+               AE = "\017";
+#  endif
+               TE = VS = VE = nullstr;
+#  ifdef TEXTCOLOR
+               for (i = 0; i < CLR_MAX / 2; i++)
+                   if (i != CLR_BLACK) {
+                       hilites[i|BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm"));
+                       Sprintf(hilites[i|BRIGHT], "\033[1;3%dm", i);
+                       if (i != CLR_GRAY)
+#   ifdef MICRO
+                           if (i == CLR_BLUE) hilites[CLR_BLUE] = hilites[CLR_BLUE|BRIGHT];
+                           else
+#   endif
+                           {
+                               hilites[i] = (char *) alloc(sizeof("\033[0;3%dm"));
+                               Sprintf(hilites[i], "\033[0;3%dm", i);
+                           }
+                   }
+#  endif
+               *wid = CO;
+               *hgt = LI;
+               CL = "\033[2J";         /* last thing set */
+               return;
+       }
+# endif /* TOS */
+#endif /* ANSI_DEFAULT */
+
+#ifdef TERMLIB
+       tptr = (char *) alloc(1024);
+
+       tbufptr = tbuf;
+       if(!strncmp(term, "5620", 4))
+               flags.null = FALSE;     /* this should be a termcap flag */
+       if(tgetent(tptr, term) < 1) {
+               char buf[BUFSZ];
+               (void) strncpy(buf, term,
+                               (BUFSZ - 1) - (sizeof("Unknown terminal type: .  ")));
+               buf[BUFSZ-1] = '\0';
+               error("Unknown terminal type: %s.", term);
+       }
+       if ((pc = Tgetstr("pc")) != 0)
+               PC = *pc;
+
+       if(!(BC = Tgetstr("le")))       /* both termcap and terminfo use le */
+# ifdef TERMINFO
+           error("Terminal must backspace.");
+# else
+           if(!(BC = Tgetstr("bc"))) { /* termcap also uses bc/bs */
+#  ifndef MINIMAL_TERM
+               if(!tgetflag("bs"))
+                       error("Terminal must backspace.");
+#  endif
+               BC = tbufptr;
+               tbufptr += 2;
+               *BC = '\b';
+           }
+# endif
+
+# ifdef MINIMAL_TERM
+       HO = (char *)0;
+# else
+       HO = Tgetstr("ho");
+# endif
+       /*
+        * LI and CO are set in ioctl.c via a TIOCGWINSZ if available.  If
+        * the kernel has values for either we should use them rather than
+        * the values from TERMCAP ...
+        */
+# ifndef MICRO
+       if (!CO) CO = tgetnum("co");
+       if (!LI) LI = tgetnum("li");
+# else
+#  if defined(TOS) && defined(__GNUC__)
+       if (!strcmp(term, "builtin"))
+               get_scr_size();
+       else {
+#  endif
+               CO = tgetnum("co");
+               LI = tgetnum("li");
+               if (!LI || !CO)                 /* if we don't override it */
+                       get_scr_size();
+#  if defined(TOS) && defined(__GNUC__)
+       }
+#  endif
+# endif
+# ifdef CLIPPING
+       if(CO < COLNO || LI < ROWNO+3)
+               setclipped();
+# endif
+       nh_ND = Tgetstr("nd");
+       if(tgetflag("os"))
+               error("NetHack can't have OS.");
+       if(tgetflag("ul"))
+               ul_hack = TRUE;
+       CE = Tgetstr("ce");
+       UP = Tgetstr("up");
+       /* It seems that xd is no longer supported, and we should use
+          a linefeed instead; unfortunately this requires resetting
+          CRMOD, and many output routines will have to be modified
+          slightly. Let's leave that till the next release. */
+       XD = Tgetstr("xd");
+/* not:                XD = Tgetstr("do"); */
+       if(!(nh_CM = Tgetstr("cm"))) {
+           if(!UP && !HO)
+               error("NetHack needs CM or UP or HO.");
+           tty_raw_print("Playing NetHack on terminals without CM is suspect.");
+           tty_wait_synch();
+       }
+       SO = Tgetstr("so");
+       SE = Tgetstr("se");
+       nh_US = Tgetstr("us");
+       nh_UE = Tgetstr("ue");
+       SG = tgetnum("sg");     /* -1: not fnd; else # of spaces left by so */
+       if(!SO || !SE || (SG > 0)) SO = SE = nh_US = nh_UE = nullstr;
+       TI = Tgetstr("ti");
+       TE = Tgetstr("te");
+       VS = VE = nullstr;
+# ifdef TERMINFO
+       VS = Tgetstr("eA");     /* enable graphics */
+# endif
+       KS = Tgetstr("ks");     /* keypad start (special mode) */
+       KE = Tgetstr("ke");     /* keypad end (ordinary mode [ie, digits]) */
+       MR = Tgetstr("mr");     /* reverse */
+# if 0
+       MB = Tgetstr("mb");     /* blink */
+       MD = Tgetstr("md");     /* boldface */
+       MH = Tgetstr("mh");     /* dim */
+# endif
+       ME = Tgetstr("me");     /* turn off all attributes */
+       if (!ME || (SE == nullstr)) ME = SE;    /* default to SE value */
+
+       /* Get rid of padding numbers for nh_HI and nh_HE.  Hope they
+        * aren't really needed!!!  nh_HI and nh_HE are outputted to the
+        * pager as a string - so how can you send it NULs???
+        *  -jsb
+        */
+       nh_HI = (char *) alloc((unsigned)(strlen(SO)+1));
+       nh_HE = (char *) alloc((unsigned)(strlen(ME)+1));
+       i = 0;
+       while (digit(SO[i])) i++;
+       Strcpy(nh_HI, &SO[i]);
+       i = 0;
+       while (digit(ME[i])) i++;
+       Strcpy(nh_HE, &ME[i]);
+       AS = Tgetstr("as");
+       AE = Tgetstr("ae");
+       nh_CD = Tgetstr("cd");
+# ifdef TEXTCOLOR
+       MD = Tgetstr("md");
+# endif
+# ifdef TEXTCOLOR
+#  if defined(TOS) && defined(__GNUC__)
+       if (!strcmp(term, "builtin") || !strcmp(term, "tw52") ||
+           !strcmp(term, "st52")) {
+               init_hilite();
+       }
+#  else
+       init_hilite();
+#  endif
+# endif
+       *wid = CO;
+       *hgt = LI;
+       if (!(CL = Tgetstr("cl")))      /* last thing set */
+               error("NetHack needs CL.");
+       if ((int)(tbufptr - tbuf) > (int)(sizeof tbuf))
+               error("TERMCAP entry too big...\n");
+       free((genericptr_t)tptr);
+#endif /* TERMLIB */
+}
+
+/* note: at present, this routine is not part of the formal window interface */
+/* deallocate resources prior to final termination */
+void
+tty_shutdown()
+{
+#if defined(TEXTCOLOR) && defined(TERMLIB)
+       kill_hilite();
+#endif
+       /* we don't attempt to clean up individual termcap variables [yet?] */
+       return;
+}
+
+void
+tty_number_pad(state)
+int state;
+{
+       switch (state) {
+           case -1:    /* activate keypad mode (escape sequences) */
+                   if (KS && *KS) xputs(KS);
+                   break;
+           case  1:    /* activate numeric mode for keypad (digits) */
+                   if (KE && *KE) xputs(KE);
+                   break;
+           case  0:    /* don't need to do anything--leave terminal as-is */
+           default:
+                   break;
+       }
+}
+
+#ifdef TERMLIB
+extern void NDECL((*decgraphics_mode_callback));    /* defined in drawing.c */
+static void NDECL(tty_decgraphics_termcap_fixup);
+
+/*
+   We call this routine whenever DECgraphics mode is enabled, even if it
+   has been previously set, in case the user manages to reset the fonts.
+   The actual termcap fixup only needs to be done once, but we can't
+   call xputs() from the option setting or graphics assigning routines,
+   so this is a convenient hook.
+ */
+static void
+tty_decgraphics_termcap_fixup()
+{
+       static char ctrlN[]   = "\016";
+       static char ctrlO[]   = "\017";
+       static char appMode[] = "\033=";
+       static char numMode[] = "\033>";
+
+       /* these values are missing from some termcaps */
+       if (!AS) AS = ctrlN;    /* ^N (shift-out [graphics font]) */
+       if (!AE) AE = ctrlO;    /* ^O (shift-in  [regular font])  */
+       if (!KS) KS = appMode;  /* ESC= (application keypad mode) */
+       if (!KE) KE = numMode;  /* ESC> (numeric keypad mode)     */
+       /*
+        * Select the line-drawing character set as the alternate font.
+        * Do not select NA ASCII as the primary font since people may
+        * reasonably be using the UK character set.
+        */
+       if (iflags.DECgraphics) xputs("\033)0");
+#ifdef PC9800
+       init_hilite();
+#endif
+
+#if defined(ASCIIGRAPH) && !defined(NO_TERMS)
+       /* some termcaps suffer from the bizarre notion that resetting
+          video attributes should also reset the chosen character set */
+    {
+       const char *nh_he = nh_HE, *ae = AE;
+       int he_limit, ae_length;
+
+       if (digit(*ae)) {       /* skip over delay prefix, if any */
+           do ++ae; while (digit(*ae));
+           if (*ae == '.') { ++ae; if (digit(*ae)) ++ae; }
+           if (*ae == '*') ++ae;
+       }
+       /* can't use nethack's case-insensitive strstri() here, and some old
+          systems don't have strstr(), so use brute force substring search */
+       ae_length = strlen(ae), he_limit = strlen(nh_he);
+       while (he_limit >= ae_length) {
+           if (strncmp(nh_he, ae, ae_length) == 0) {
+               HE_resets_AS = TRUE;
+               break;
+           }
+           ++nh_he, --he_limit;
+       }
+    }
+#endif
+}
+#endif /* TERMLIB */
+
+#if defined(ASCIIGRAPH) && defined(PC9800)
+extern void NDECL((*ibmgraphics_mode_callback));    /* defined in drawing.c */
+#endif
+
+#ifdef PC9800
+extern void NDECL((*ascgraphics_mode_callback));    /* defined in drawing.c */
+static void NDECL(tty_ascgraphics_hilite_fixup);
+
+static void
+tty_ascgraphics_hilite_fixup()
+{
+    register int c;
+
+    for (c = 0; c < CLR_MAX / 2; c++)
+       if (c != CLR_BLACK) {
+           hilites[c|BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm"));
+           Sprintf(hilites[c|BRIGHT], "\033[1;3%dm", c);
+           if (c != CLR_GRAY) {
+                   hilites[c] = (char *) alloc(sizeof("\033[0;3%dm"));
+                   Sprintf(hilites[c], "\033[0;3%dm", c);
+           }
+       }
+}
+#endif /* PC9800 */
+
+void
+tty_start_screen()
+{
+       xputs(TI);
+       xputs(VS);
+#ifdef PC9800
+    if (!iflags.IBMgraphics && !iflags.DECgraphics)
+           tty_ascgraphics_hilite_fixup();
+    /* set up callback in case option is not set yet but toggled later */
+    ascgraphics_mode_callback = tty_ascgraphics_hilite_fixup;
+# ifdef ASCIIGRAPH
+    if (iflags.IBMgraphics) init_hilite();
+    /* set up callback in case option is not set yet but toggled later */
+    ibmgraphics_mode_callback = init_hilite;
+# endif
+#endif /* PC9800 */
+
+#ifdef TERMLIB
+       if (iflags.DECgraphics) tty_decgraphics_termcap_fixup();
+       /* set up callback in case option is not set yet but toggled later */
+       decgraphics_mode_callback = tty_decgraphics_termcap_fixup;
+#endif
+       if (iflags.num_pad) tty_number_pad(1);  /* make keypad send digits */
+}
+
+void
+tty_end_screen()
+{
+       clear_screen();
+       xputs(VE);
+       xputs(TE);
+}
+
+/* Cursor movements */
+
+#endif /* OVLB */
+
+#ifdef OVL0
+/* Note to OVLx tinkerers.  The placement of this overlay controls the location
+   of the function xputc().  This function is not currently in trampoli.[ch]
+   files for what is deemed to be performance reasons.  If this define is moved
+   and or xputc() is taken out of the ROOT overlay, then action must be taken
+   in trampoli.[ch]. */
+
+void
+nocmov(x, y)
+int x,y;
+{
+       if ((int) ttyDisplay->cury > y) {
+               if(UP) {
+                       while ((int) ttyDisplay->cury > y) {    /* Go up. */
+                               xputs(UP);
+                               ttyDisplay->cury--;
+                       }
+               } else if(nh_CM) {
+                       cmov(x, y);
+               } else if(HO) {
+                       home();
+                       tty_curs(BASE_WINDOW, x+1, y);
+               } /* else impossible("..."); */
+       } else if ((int) ttyDisplay->cury < y) {
+               if(XD) {
+                       while((int) ttyDisplay->cury < y) {
+                               xputs(XD);
+                               ttyDisplay->cury++;
+                       }
+               } else if(nh_CM) {
+                       cmov(x, y);
+               } else {
+                       while((int) ttyDisplay->cury < y) {
+                               xputc('\n');
+                               ttyDisplay->curx = 0;
+                               ttyDisplay->cury++;
+                       }
+               }
+       }
+       if ((int) ttyDisplay->curx < x) {               /* Go to the right. */
+               if(!nh_ND) cmov(x, y); else     /* bah */
+                       /* should instead print what is there already */
+               while ((int) ttyDisplay->curx < x) {
+                       xputs(nh_ND);
+                       ttyDisplay->curx++;
+               }
+       } else if ((int) ttyDisplay->curx > x) {
+               while ((int) ttyDisplay->curx > x) {    /* Go to the left. */
+                       xputs(BC);
+                       ttyDisplay->curx--;
+               }
+       }
+}
+
+void
+cmov(x, y)
+register int x, y;
+{
+       xputs(tgoto(nh_CM, x, y));
+       ttyDisplay->cury = y;
+       ttyDisplay->curx = x;
+}
+
+/* See note at OVLx ifdef above.   xputc() is a special function. */
+void
+xputc(c)
+#if defined(apollo)
+int c;
+#else
+char c;
+#endif
+{
+       (void) putchar(c);
+}
+
+void
+xputs(s)
+const char *s;
+{
+# ifndef TERMLIB
+       (void) fputs(s, stdout);
+# else
+#  if defined(NHSTDC) || defined(ULTRIX_PROTO)
+       tputs(s, 1, (int (*)())xputc);
+#  else
+       tputs(s, 1, xputc);
+#  endif
+# endif
+}
+
+void
+cl_end()
+{
+       if(CE)
+               xputs(CE);
+       else {  /* no-CE fix - free after Harold Rynes */
+               /* this looks terrible, especially on a slow terminal
+                  but is better than nothing */
+               register int cx = ttyDisplay->curx+1;
+
+               while(cx < CO) {
+                       xputc(' ');
+                       cx++;
+               }
+               tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1,
+                                               (int)ttyDisplay->cury);
+       }
+}
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+void
+clear_screen()
+{
+       /* note: if CL is null, then termcap initialization failed,
+               so don't attempt screen-oriented I/O during final cleanup.
+        */
+       if (CL) {
+               xputs(CL);
+               home();
+       }
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+void
+home()
+{
+       if(HO)
+               xputs(HO);
+       else if(nh_CM)
+               xputs(tgoto(nh_CM, 0, 0));
+       else
+               tty_curs(BASE_WINDOW, 1, 0);    /* using UP ... */
+       ttyDisplay->curx = ttyDisplay->cury = 0;
+}
+
+void
+standoutbeg()
+{
+       if(SO) xputs(SO);
+}
+
+void
+standoutend()
+{
+       if(SE) xputs(SE);
+}
+
+#if 0  /* if you need one of these, uncomment it (here and in extern.h) */
+void
+revbeg()
+{
+       if(MR) xputs(MR);
+}
+
+void
+boldbeg()
+{
+       if(MD) xputs(MD);
+}
+
+void
+blinkbeg()
+{
+       if(MB) xputs(MB);
+}
+
+void
+dimbeg()
+/* not in most termcap entries */
+{
+       if(MH) xputs(MH);
+}
+
+void
+m_end()
+{
+       if(ME) xputs(ME);
+}
+#endif
+
+#endif /* OVL0 */
+#ifdef OVLB
+
+void
+backsp()
+{
+       xputs(BC);
+}
+
+void
+tty_nhbell()
+{
+       if (flags.silent) return;
+       (void) putchar('\007');         /* curx does not change */
+       (void) fflush(stdout);
+}
+
+#endif /* OVLB */
+#ifdef OVL0
+
+#ifdef ASCIIGRAPH
+void
+graph_on() {
+       if (AS) xputs(AS);
+}
+
+void
+graph_off() {
+       if (AE) xputs(AE);
+}
+#endif
+
+#endif /* OVL0 */
+#ifdef OVL1
+
+#if !defined(MICRO)
+# ifdef VMS
+static const short tmspc10[] = {               /* from termcap */
+       0, 2000, 1333, 909, 743, 666, 333, 166, 83, 55, 50, 41, 27, 20, 13, 10,
+       5
+};
+# else
+static const short tmspc10[] = {               /* from termcap */
+       0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5
+};
+# endif
+#endif
+
+/* delay 50 ms */
+void
+tty_delay_output()
+{
+#if defined(MICRO)
+       register int i;
+#endif
+#ifdef TIMED_DELAY
+       if (flags.nap) {
+               (void) fflush(stdout);
+               msleep(50);             /* sleep for 50 milliseconds */
+               return;
+       }
+#endif
+#if defined(MICRO)
+       /* simulate the delay with "cursor here" */
+       for (i = 0; i < 3; i++) {
+               cmov(ttyDisplay->curx, ttyDisplay->cury);
+               (void) fflush(stdout);
+       }
+#else /* MICRO */
+       /* BUG: if the padding character is visible, as it is on the 5620
+          then this looks terrible. */
+       if(flags.null)
+# ifdef TERMINFO
+               /* cbosgd!cbcephus!pds for SYS V R2 */
+#  ifdef NHSTDC
+               tputs("$<50>", 1, (int (*)())xputc);
+#  else
+               tputs("$<50>", 1, xputc);
+#  endif
+# else
+#  if defined(NHSTDC) || defined(ULTRIX_PROTO)
+               tputs("50", 1, (int (*)())xputc);
+#  else
+               tputs("50", 1, xputc);
+#  endif
+# endif
+
+       else if(ospeed > 0 && ospeed < SIZE(tmspc10) && nh_CM) {
+               /* delay by sending cm(here) an appropriate number of times */
+               register int cmlen = strlen(tgoto(nh_CM, ttyDisplay->curx,
+                                                       ttyDisplay->cury));
+               register int i = 500 + tmspc10[ospeed]/2;
+
+               while(i > 0) {
+                       cmov((int)ttyDisplay->curx, (int)ttyDisplay->cury);
+                       i -= cmlen*tmspc10[ospeed];
+               }
+       }
+#endif /* MICRO */
+}
+
+#endif /* OVL1 */
+#ifdef OVLB
+
+void
+cl_eos()                       /* free after Robert Viduya */
+{                              /* must only be called with curx = 1 */
+
+       if(nh_CD)
+               xputs(nh_CD);
+       else {
+               register int cy = ttyDisplay->cury+1;
+               while(cy <= LI-2) {
+                       cl_end();
+                       xputc('\n');
+                       cy++;
+               }
+               cl_end();
+               tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1,
+                                               (int)ttyDisplay->cury);
+       }
+}
+
+#if defined(TEXTCOLOR) && defined(TERMLIB)
+# if defined(UNIX) && defined(TERMINFO)
+/*
+ * Sets up color highlighting, using terminfo(4) escape sequences.
+ *
+ * Having never seen a terminfo system without curses, we assume this
+ * inclusion is safe.  On systems with color terminfo, it should define
+ * the 8 COLOR_FOOs, and avoid us having to guess whether this particular
+ * terminfo uses BGR or RGB for its indexes.
+ *
+ * If we don't get the definitions, then guess.  Original color terminfos
+ * used BGR for the original Sf (setf, Standard foreground) codes, but
+ * there was a near-total lack of user documentation, so some subsequent
+ * terminfos, such as early Linux ncurses and SCO UNIX, used RGB.  Possibly
+ * as a result of the confusion, AF (setaf, ANSI Foreground) codes were
+ * introduced, but this caused yet more confusion.  Later Linux ncurses
+ * have BGR Sf, RGB AF, and RGB COLOR_FOO, which appears to be the SVR4
+ * standard.  We could switch the colors around when using Sf with ncurses,
+ * which would help things on later ncurses and hurt things on early ncurses.
+ * We'll try just preferring AF and hoping it always agrees with COLOR_FOO,
+ * and falling back to Sf if AF isn't defined.
+ *
+ * In any case, treat black specially so we don't try to display black
+ * characters on the assumed black background.
+ */
+
+       /* `curses' is aptly named; various versions don't like these
+           macros used elsewhere within nethack; fortunately they're
+           not needed beyond this point, so we don't need to worry
+           about reconstructing them after the header file inclusion. */
+#undef delay_output
+#undef TRUE
+#undef FALSE
+#define m_move curses_m_move   /* Some curses.h decl m_move(), not used here */
+
+#include <curses.h>
+
+#ifndef LINUX
+extern char *tparm();
+#endif
+
+#  ifdef COLOR_BLACK   /* trust include file */
+#undef COLOR_BLACK
+#  else
+#   ifndef _M_UNIX     /* guess BGR */
+#define COLOR_BLUE    1
+#define COLOR_GREEN   2
+#define COLOR_CYAN    3
+#define COLOR_RED     4
+#define COLOR_MAGENTA 5
+#define COLOR_YELLOW  6
+#define COLOR_WHITE   7
+#   else               /* guess RGB */
+#define COLOR_RED     1
+#define COLOR_GREEN   2
+#define COLOR_YELLOW  3
+#define COLOR_BLUE    4
+#define COLOR_MAGENTA 5
+#define COLOR_CYAN    6
+#define COLOR_WHITE   7
+#   endif
+#  endif
+#define COLOR_BLACK COLOR_BLUE
+
+const int ti_map[8] = {
+       COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
+       COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE };
+
+static void
+init_hilite()
+{
+       register int c;
+       char *setf, *scratch;
+
+       for (c = 0; c < SIZE(hilites); c++)
+               hilites[c] = nh_HI;
+       hilites[CLR_GRAY] = hilites[NO_COLOR] = (char *)0;
+
+       if (tgetnum("Co") < 8
+           || ((setf = tgetstr("AF", (char **)0)) == (char *)0
+                && (setf = tgetstr("Sf", (char **)0)) == (char *)0))
+               return;
+
+       for (c = 0; c < CLR_MAX / 2; c++) {
+           scratch = tparm(setf, ti_map[c]);
+           if (c != CLR_GRAY) {
+               hilites[c] = (char *) alloc(strlen(scratch) + 1);
+               Strcpy(hilites[c], scratch);
+           }
+           if (c != CLR_BLACK) {
+               hilites[c|BRIGHT] = (char*) alloc(strlen(scratch)+strlen(MD)+1);
+               Strcpy(hilites[c|BRIGHT], MD);
+               Strcat(hilites[c|BRIGHT], scratch);
+           }
+
+       }
+}
+
+# else /* UNIX && TERMINFO */
+
+#  ifndef TOS
+/* find the foreground and background colors set by nh_HI or nh_HE */
+static void
+analyze_seq (str, fg, bg)
+char *str;
+int *fg, *bg;
+{
+       register int c, code;
+       int len;
+
+#   ifdef MICRO
+       *fg = CLR_GRAY; *bg = CLR_BLACK;
+#   else
+       *fg = *bg = NO_COLOR;
+#   endif
+
+       c = (str[0] == '\233') ? 1 : 2;  /* index of char beyond esc prefix */
+       len = strlen(str) - 1;           /* length excluding attrib suffix */
+       if ((c != 1 && (str[0] != '\033' || str[1] != '[')) ||
+           (len - c) < 1 || str[len] != 'm')
+               return;
+
+       while (c < len) {
+           if ((code = atoi(&str[c])) == 0) { /* reset */
+               /* this also catches errors */
+#   ifdef MICRO
+               *fg = CLR_GRAY; *bg = CLR_BLACK;
+#   else
+               *fg = *bg = NO_COLOR;
+#   endif
+           } else if (code == 1) { /* bold */
+               *fg |= BRIGHT;
+#   if 0
+       /* I doubt we'll ever resort to using blinking characters,
+          unless we want a pulsing glow for something.  But, in case
+          we do... - 3. */
+           } else if (code == 5) { /* blinking */
+               *fg |= BLINK;
+           } else if (code == 25) { /* stop blinking */
+               *fg &= ~BLINK;
+#   endif
+           } else if (code == 7 || code == 27) { /* reverse */
+               code = *fg & ~BRIGHT;
+               *fg = *bg | (*fg & BRIGHT);
+               *bg = code;
+           } else if (code >= 30 && code <= 37) { /* hi_foreground RGB */
+               *fg = code - 30;
+           } else if (code >= 40 && code <= 47) { /* hi_background RGB */
+               *bg = code - 40;
+           }
+           while (digit(str[++c]));
+           c++;
+       }
+}
+#  endif
+
+/*
+ * Sets up highlighting sequences, using ANSI escape sequences (highlight code
+ * found in print.c).  The nh_HI and nh_HE sequences (usually from SO) are
+ * scanned to find foreground and background colors.
+ */
+
+static void
+init_hilite()
+{
+       register int c;
+#  ifdef TOS
+       extern unsigned long tos_numcolors;     /* in tos.c */
+       static char NOCOL[] = "\033b0", COLHE[] = "\033q\033b0";
+
+       if (tos_numcolors <= 2) {
+               return;
+       }
+/* Under TOS, the "bright" and "dim" colors are reversed. Moreover,
+ * on the Falcon the dim colors are *really* dim; so we make most
+ * of the colors the bright versions, with a few exceptions where
+ * the dim ones look OK.
+ */
+       hilites[0] = NOCOL;
+       for (c = 1; c < SIZE(hilites); c++) {
+               char *foo;
+               foo = (char *) alloc(sizeof("\033b0"));
+               if (tos_numcolors > 4)
+                       Sprintf(foo, "\033b%c", (c&~BRIGHT)+'0');
+               else
+                       Strcpy(foo, "\033b0");
+               hilites[c] = foo;
+       }
+
+       if (tos_numcolors == 4) {
+               TI = "\033b0\033c3\033E\033e";
+               TE = "\033b3\033c0\033J";
+               nh_HE = COLHE;
+               hilites[CLR_GREEN] = hilites[CLR_GREEN|BRIGHT] = "\033b2";
+               hilites[CLR_RED] = hilites[CLR_RED|BRIGHT] = "\033b1";
+       } else {
+               sprintf(hilites[CLR_BROWN], "\033b%c", (CLR_BROWN^BRIGHT)+'0');
+               sprintf(hilites[CLR_GREEN], "\033b%c", (CLR_GREEN^BRIGHT)+'0');
+
+               TI = "\033b0\033c\017\033E\033e";
+               TE = "\033b\017\033c0\033J";
+               nh_HE = COLHE;
+               hilites[CLR_WHITE] = hilites[CLR_BLACK] = NOCOL;
+               hilites[NO_COLOR] = hilites[CLR_GRAY];
+       }
+
+#  else /* TOS */
+
+       int backg, foreg, hi_backg, hi_foreg;
+
+       for (c = 0; c < SIZE(hilites); c++)
+           hilites[c] = nh_HI;
+       hilites[CLR_GRAY] = hilites[NO_COLOR] = (char *)0;
+
+       analyze_seq(nh_HI, &hi_foreg, &hi_backg);
+       analyze_seq(nh_HE, &foreg, &backg);
+
+       for (c = 0; c < SIZE(hilites); c++)
+           /* avoid invisibility */
+           if ((backg & ~BRIGHT) != c) {
+#   ifdef MICRO
+               if (c == CLR_BLUE) continue;
+#   endif
+               if (c == foreg)
+                   hilites[c] = (char *)0;
+               else if (c != hi_foreg || backg != hi_backg) {
+                   hilites[c] = (char *) alloc(sizeof("\033[%d;3%d;4%dm"));
+                   Sprintf(hilites[c], "\033[%d", !!(c & BRIGHT));
+                   if ((c | BRIGHT) != (foreg | BRIGHT))
+                       Sprintf(eos(hilites[c]), ";3%d", c & ~BRIGHT);
+                   if (backg != CLR_BLACK)
+                       Sprintf(eos(hilites[c]), ";4%d", backg & ~BRIGHT);
+                   Strcat(hilites[c], "m");
+               }
+           }
+
+#   ifdef MICRO
+       /* brighten low-visibility colors */
+       hilites[CLR_BLUE] = hilites[CLR_BLUE|BRIGHT];
+#   endif
+#  endif /* TOS */
+}
+# endif /* UNIX */
+
+static void
+kill_hilite()
+{
+# ifndef TOS
+       register int c;
+
+       for (c = 0; c < CLR_MAX / 2; c++) {
+           if (hilites[c|BRIGHT] == hilites[c])  hilites[c|BRIGHT] = 0;
+           if (hilites[c] && (hilites[c] != nh_HI))
+               free((genericptr_t) hilites[c]),  hilites[c] = 0;
+           if (hilites[c|BRIGHT] && (hilites[c|BRIGHT] != nh_HI))
+               free((genericptr_t) hilites[c|BRIGHT]),  hilites[c|BRIGHT] = 0;
+       }
+# endif
+       return;
+}
+#endif /* TEXTCOLOR */
+
+
+static char nulstr[] = "";
+
+static char *
+s_atr2str(n)
+int n;
+{
+    switch (n) {
+           case ATR_ULINE:
+                   if(nh_US) return nh_US;
+           case ATR_BOLD:
+           case ATR_BLINK:
+#if defined(TERMLIB) && defined(TEXTCOLOR)
+                   if (MD) return MD;
+#endif
+                   return nh_HI;
+           case ATR_INVERSE:
+                   return MR;
+    }
+    return nulstr;
+}
+
+static char *
+e_atr2str(n)
+int n;
+{
+    switch (n) {
+           case ATR_ULINE:
+                   if(nh_UE) return nh_UE;
+           case ATR_BOLD:
+           case ATR_BLINK:
+                   return nh_HE;
+           case ATR_INVERSE:
+                   return ME;
+    }
+    return nulstr;
+}
+
+
+void
+term_start_attr(attr)
+int attr;
+{
+       if (attr) {
+               xputs(s_atr2str(attr));
+       }
+}
+
+
+void
+term_end_attr(attr)
+int attr;
+{
+       if(attr) {
+               xputs(e_atr2str(attr));
+       }
+}
+
+
+void
+term_start_raw_bold()
+{
+       xputs(nh_HI);
+}
+
+
+void
+term_end_raw_bold()
+{
+       xputs(nh_HE);
+}
+
+
+#ifdef TEXTCOLOR
+
+void
+term_end_color()
+{
+       xputs(nh_HE);
+}
+
+
+void
+term_start_color(color)
+int color;
+{
+       xputs(hilites[color]);
+}
+
+
+int
+has_color(color)
+int color;
+{
+#ifdef X11_GRAPHICS
+       /* XXX has_color() should be added to windowprocs */
+       if (windowprocs.name != NULL &&
+           !strcmpi(windowprocs.name, "X11")) return TRUE;
+#endif
+#ifdef GEM_GRAPHICS
+       /* XXX has_color() should be added to windowprocs */
+       if (windowprocs.name != NULL &&
+           !strcmpi(windowprocs.name, "Gem")) return TRUE;
+#endif
+#ifdef QT_GRAPHICS
+       /* XXX has_color() should be added to windowprocs */
+       if (windowprocs.name != NULL &&
+           !strcmpi(windowprocs.name, "Qt")) return TRUE;
+#endif
+#ifdef AMII_GRAPHICS
+       /* hilites[] not used */
+       return iflags.use_color;
+#endif
+       return hilites[color] != (char *)0;
+}
+
+#endif /* TEXTCOLOR */
+
+#endif /* OVLB */
+
+#endif /* TTY_GRAPHICS */
+
+/*termcap.c*/
diff --git a/win/tty/topl.c b/win/tty/topl.c
new file mode 100644 (file)
index 0000000..1c62f3d
--- /dev/null
@@ -0,0 +1,467 @@
+/*     SCCS Id: @(#)topl.c     3.4     1996/10/24      */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+
+#ifdef TTY_GRAPHICS
+
+#include "tcap.h"
+#include "wintty.h"
+#include <ctype.h>
+
+#ifndef C      /* this matches src/cmd.c */
+#define C(c)   (0x1f & (c))
+#endif
+
+STATIC_DCL void FDECL(redotoplin, (const char*));
+STATIC_DCL void FDECL(topl_putsym, (CHAR_P));
+STATIC_DCL void NDECL(remember_topl);
+STATIC_DCL void FDECL(removetopl, (int));
+
+#ifdef OVLB
+
+int
+tty_doprev_message()
+{
+    register struct WinDesc *cw = wins[WIN_MESSAGE];
+
+    winid prevmsg_win;
+    int i;
+    if ((iflags.prevmsg_window != 's') && !ttyDisplay->inread) { /* not single */
+        if(iflags.prevmsg_window == 'f') { /* full */
+            prevmsg_win = create_nhwindow(NHW_MENU);
+            putstr(prevmsg_win, 0, "Message History");
+            putstr(prevmsg_win, 0, "");
+            cw->maxcol = cw->maxrow;
+            i = cw->maxcol;
+            do {
+                if(cw->data[i] && strcmp(cw->data[i], "") )
+                    putstr(prevmsg_win, 0, cw->data[i]);
+                i = (i + 1) % cw->rows;
+            } while (i != cw->maxcol);
+            putstr(prevmsg_win, 0, toplines);
+            display_nhwindow(prevmsg_win, TRUE);
+            destroy_nhwindow(prevmsg_win);
+        } else if (iflags.prevmsg_window == 'c') {             /* combination */
+            do {
+                morc = 0;
+                if (cw->maxcol == cw->maxrow) {
+                    ttyDisplay->dismiss_more = C('p'); /* <ctrl/P> allowed at --More-- */
+                    redotoplin(toplines);
+                    cw->maxcol--;
+                    if (cw->maxcol < 0) cw->maxcol = cw->rows-1;
+                    if (!cw->data[cw->maxcol])
+                        cw->maxcol = cw->maxrow;
+                } else if (cw->maxcol == (cw->maxrow - 1)){
+                    ttyDisplay->dismiss_more = C('p'); /* <ctrl/P> allowed at --More-- */
+                    redotoplin(cw->data[cw->maxcol]);
+                    cw->maxcol--;
+                    if (cw->maxcol < 0) cw->maxcol = cw->rows-1;
+                    if (!cw->data[cw->maxcol])
+                        cw->maxcol = cw->maxrow;
+                } else {
+                    prevmsg_win = create_nhwindow(NHW_MENU);
+                    putstr(prevmsg_win, 0, "Message History");
+                    putstr(prevmsg_win, 0, "");
+                    cw->maxcol = cw->maxrow;
+                    i = cw->maxcol;
+                    do {
+                        if(cw->data[i] && strcmp(cw->data[i], "") )
+                            putstr(prevmsg_win, 0, cw->data[i]);
+                        i = (i + 1) % cw->rows;
+                    } while (i != cw->maxcol);
+                    putstr(prevmsg_win, 0, toplines);
+                    display_nhwindow(prevmsg_win, TRUE);
+                    destroy_nhwindow(prevmsg_win);
+                }
+
+            } while (morc == C('p'));
+            ttyDisplay->dismiss_more = 0;
+        } else { /* reversed */
+            morc = 0;
+            prevmsg_win = create_nhwindow(NHW_MENU);
+            putstr(prevmsg_win, 0, "Message History");
+            putstr(prevmsg_win, 0, "");
+            putstr(prevmsg_win, 0, toplines);
+            cw->maxcol=cw->maxrow-1;
+            if(cw->maxcol < 0) cw->maxcol = cw->rows-1;
+            do {
+                putstr(prevmsg_win, 0, cw->data[cw->maxcol]);
+                cw->maxcol--;
+                if (cw->maxcol < 0) cw->maxcol = cw->rows-1;
+                if (!cw->data[cw->maxcol])
+                    cw->maxcol = cw->maxrow;
+            } while (cw->maxcol != cw->maxrow);
+
+            display_nhwindow(prevmsg_win, TRUE);
+            destroy_nhwindow(prevmsg_win);
+            cw->maxcol = cw->maxrow;
+            ttyDisplay->dismiss_more = 0;
+        }
+    } else if(iflags.prevmsg_window == 's') { /* single */
+        ttyDisplay->dismiss_more = C('p');  /* <ctrl/P> allowed at --More-- */
+        do {
+            morc = 0;
+            if (cw->maxcol == cw->maxrow)
+                redotoplin(toplines);
+            else if (cw->data[cw->maxcol])
+                redotoplin(cw->data[cw->maxcol]);
+            cw->maxcol--;
+            if (cw->maxcol < 0) cw->maxcol = cw->rows-1;
+            if (!cw->data[cw->maxcol])
+                cw->maxcol = cw->maxrow;
+        } while (morc == C('p'));
+        ttyDisplay->dismiss_more = 0;
+    }
+    return 0;
+}
+
+#endif /* OVLB */
+#ifdef OVL1
+
+STATIC_OVL void
+redotoplin(str)
+    const char *str;
+{
+       int otoplin = ttyDisplay->toplin;
+       home();
+       if(*str & 0x80) {
+               /* kludge for the / command, the only time we ever want a */
+               /* graphics character on the top line */
+               g_putch((int)*str++);
+               ttyDisplay->curx++;
+       }
+       end_glyphout(); /* in case message printed during graphics output */
+       putsyms(str);
+       cl_end();
+       ttyDisplay->toplin = 1;
+       if(ttyDisplay->cury && otoplin != 3)
+               more();
+}
+
+STATIC_OVL void
+remember_topl()
+{
+    register struct WinDesc *cw = wins[WIN_MESSAGE];
+    int idx = cw->maxrow;
+    unsigned len = strlen(toplines) + 1;
+
+    if (len > (unsigned)cw->datlen[idx]) {
+       if (cw->data[idx]) free(cw->data[idx]);
+       len += (8 - (len & 7));         /* pad up to next multiple of 8 */
+       cw->data[idx] = (char *)alloc(len);
+       cw->datlen[idx] = (short)len;
+    }
+    Strcpy(cw->data[idx], toplines);
+    cw->maxcol = cw->maxrow = (idx + 1) % cw->rows;
+}
+
+void
+addtopl(s)
+const char *s;
+{
+    register struct WinDesc *cw = wins[WIN_MESSAGE];
+
+    tty_curs(BASE_WINDOW,cw->curx+1,cw->cury);
+    putsyms(s);
+    cl_end();
+    ttyDisplay->toplin = 1;
+}
+
+#endif /* OVL1 */
+#ifdef OVL2
+
+void
+more()
+{
+    struct WinDesc *cw = wins[WIN_MESSAGE];
+
+    /* avoid recursion -- only happens from interrupts */
+    if(ttyDisplay->inmore++)
+       return;
+
+    if(ttyDisplay->toplin) {
+       tty_curs(BASE_WINDOW, cw->curx+1, cw->cury);
+       if(cw->curx >= CO - 8) topl_putsym('\n');
+    }
+
+    if(flags.standout)
+       standoutbeg();
+    putsyms(defmorestr);
+    if(flags.standout)
+       standoutend();
+
+    xwaitforspace("\033 ");
+
+    if(morc == '\033')
+       cw->flags |= WIN_STOP;
+
+    if(ttyDisplay->toplin && cw->cury) {
+       docorner(1, cw->cury+1);
+       cw->curx = cw->cury = 0;
+       home();
+    } else if(morc == '\033') {
+       cw->curx = cw->cury = 0;
+       home();
+       cl_end();
+    }
+    ttyDisplay->toplin = 0;
+    ttyDisplay->inmore = 0;
+}
+
+void
+update_topl(bp)
+       register const char *bp;
+{
+       register char *tl, *otl;
+       register int n0;
+       int notdied = 1;
+       struct WinDesc *cw = wins[WIN_MESSAGE];
+
+       /* If there is room on the line, print message on same line */
+       /* But messages like "You die..." deserve their own line */
+       n0 = strlen(bp);
+       if ((ttyDisplay->toplin == 1 || (cw->flags & WIN_STOP)) &&
+           cw->cury == 0 &&
+           n0 + (int)strlen(toplines) + 3 < CO-8 &&  /* room for --More-- */
+           (notdied = strncmp(bp, "You die", 7))) {
+               Strcat(toplines, "  ");
+               Strcat(toplines, bp);
+               cw->curx += 2;
+               if(!(cw->flags & WIN_STOP))
+                   addtopl(bp);
+               return;
+       } else if (!(cw->flags & WIN_STOP)) {
+           if(ttyDisplay->toplin == 1) more();
+           else if(cw->cury) { /* for when flags.toplin == 2 && cury > 1 */
+               docorner(1, cw->cury+1); /* reset cury = 0 if redraw screen */
+               cw->curx = cw->cury = 0;/* from home--cls() & docorner(1,n) */
+           }
+       }
+       remember_topl();
+       (void) strncpy(toplines, bp, TBUFSZ);
+       toplines[TBUFSZ - 1] = 0;
+
+       for(tl = toplines; n0 >= CO; ){
+           otl = tl;
+           for(tl+=CO-1; tl != otl && !isspace(*tl); --tl) ;
+           if(tl == otl) {
+               /* Eek!  A huge token.  Try splitting after it. */
+               tl = index(otl, ' ');
+               if (!tl) break;    /* No choice but to spit it out whole. */
+           }
+           *tl++ = '\n';
+           n0 = strlen(tl);
+       }
+       if(!notdied) cw->flags &= ~WIN_STOP;
+       if(!(cw->flags & WIN_STOP)) redotoplin(toplines);
+}
+
+STATIC_OVL
+void
+topl_putsym(c)
+    char c;
+{
+    register struct WinDesc *cw = wins[WIN_MESSAGE];
+
+    if(cw == (struct WinDesc *) 0) panic("Putsym window MESSAGE nonexistant");
+       
+    switch(c) {
+    case '\b':
+       if(ttyDisplay->curx == 0 && ttyDisplay->cury > 0)
+           tty_curs(BASE_WINDOW, CO, (int)ttyDisplay->cury-1);
+       backsp();
+       ttyDisplay->curx--;
+       cw->curx = ttyDisplay->curx;
+       return;
+    case '\n':
+       cl_end();
+       ttyDisplay->curx = 0;
+       ttyDisplay->cury++;
+       cw->cury = ttyDisplay->cury;
+#ifdef WIN32CON
+    (void) putchar(c);
+#endif
+       break;
+    default:
+       if(ttyDisplay->curx == CO-1)
+           topl_putsym('\n'); /* 1 <= curx <= CO; avoid CO */
+#ifdef WIN32CON
+    (void) putchar(c);
+#endif
+       ttyDisplay->curx++;
+    }
+    cw->curx = ttyDisplay->curx;
+    if(cw->curx == 0) cl_end();
+#ifndef WIN32CON
+    (void) putchar(c);
+#endif
+}
+
+void
+putsyms(str)
+    const char *str;
+{
+    while(*str)
+       topl_putsym(*str++);
+}
+
+STATIC_OVL void
+removetopl(n)
+register int n;
+{
+    /* assume addtopl() has been done, so ttyDisplay->toplin is already set */
+    while (n-- > 0) putsyms("\b \b");
+}
+
+extern char erase_char;                /* from xxxtty.c; don't need kill_char */
+
+char
+tty_yn_function(query,resp, def)
+const char *query,*resp;
+char def;
+/*
+ *   Generic yes/no function. 'def' is the default (returned by space or
+ *   return; 'esc' returns 'q', or 'n', or the default, depending on
+ *   what's in the string. The 'query' string is printed before the user
+ *   is asked about the string.
+ *   If resp is NULL, any single character is accepted and returned.
+ *   If not-NULL, only characters in it are allowed (exceptions:  the
+ *   quitchars are always allowed, and if it contains '#' then digits
+ *   are allowed); if it includes an <esc>, anything beyond that won't
+ *   be shown in the prompt to the user but will be acceptable as input.
+ */
+{
+       register char q;
+       char rtmp[40];
+       boolean digit_ok, allow_num;
+       struct WinDesc *cw = wins[WIN_MESSAGE];
+       boolean doprev = 0;
+       char prompt[QBUFSZ];
+
+       if(ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) more();
+       cw->flags &= ~WIN_STOP;
+       ttyDisplay->toplin = 3; /* special prompt state */
+       ttyDisplay->inread++;
+       if (resp) {
+           char *rb, respbuf[QBUFSZ];
+
+           allow_num = (index(resp, '#') != 0);
+           Strcpy(respbuf, resp);
+           /* any acceptable responses that follow <esc> aren't displayed */
+           if ((rb = index(respbuf, '\033')) != 0) *rb = '\0';
+           Sprintf(prompt, "%s [%s] ", query, respbuf);
+           if (def) Sprintf(eos(prompt), "(%c) ", def);
+           pline("%s", prompt);
+       } else {
+           pline("%s ", query);
+           q = readchar();
+           goto clean_up;
+       }
+
+       do {    /* loop until we get valid input */
+           q = lowc(readchar());
+           if (q == '\020') { /* ctrl-P */
+               if (iflags.prevmsg_window != 's') {
+                   int sav = ttyDisplay->inread;
+                   ttyDisplay->inread = 0;
+                   (void) tty_doprev_message();
+                   ttyDisplay->inread = sav;
+                   tty_clear_nhwindow(WIN_MESSAGE);
+                   cw->maxcol = cw->maxrow;
+                   addtopl(prompt);
+               } else {
+                   if(!doprev)
+                       (void) tty_doprev_message(); /* need two initially */
+                   (void) tty_doprev_message();
+                   doprev = 1;
+               }
+               q = '\0';       /* force another loop iteration */
+               continue;
+           } else if (doprev) {
+               /* BUG[?]: this probably ought to check whether the
+                  character which has just been read is an acceptable
+                  response; if so, skip the reprompt and use it. */
+               tty_clear_nhwindow(WIN_MESSAGE);
+               cw->maxcol = cw->maxrow;
+               doprev = 0;
+               addtopl(prompt);
+               q = '\0';       /* force another loop iteration */
+               continue;
+           }
+           digit_ok = allow_num && digit(q);
+           if (q == '\033') {
+               if (index(resp, 'q'))
+                   q = 'q';
+               else if (index(resp, 'n'))
+                   q = 'n';
+               else
+                   q = def;
+               break;
+           } else if (index(quitchars, q)) {
+               q = def;
+               break;
+           }
+           if (!index(resp, q) && !digit_ok) {
+               tty_nhbell();
+               q = (char)0;
+           } else if (q == '#' || digit_ok) {
+               char z, digit_string[2];
+               int n_len = 0;
+               long value = 0;
+               addtopl("#"),  n_len++;
+               digit_string[1] = '\0';
+               if (q != '#') {
+                   digit_string[0] = q;
+                   addtopl(digit_string),  n_len++;
+                   value = q - '0';
+                   q = '#';
+               }
+               do {    /* loop until we get a non-digit */
+                   z = lowc(readchar());
+                   if (digit(z)) {
+                       value = (10 * value) + (z - '0');
+                       if (value < 0) break;   /* overflow: try again */
+                       digit_string[0] = z;
+                       addtopl(digit_string),  n_len++;
+                   } else if (z == 'y' || index(quitchars, z)) {
+                       if (z == '\033')  value = -1;   /* abort */
+                       z = '\n';       /* break */
+                   } else if (z == erase_char || z == '\b') {
+                       if (n_len <= 1) { value = -1;  break; }
+                       else { value /= 10;  removetopl(1),  n_len--; }
+                   } else {
+                       value = -1;     /* abort */
+                       tty_nhbell();
+                       break;
+                   }
+               } while (z != '\n');
+               if (value > 0) yn_number = value;
+               else if (value == 0) q = 'n';           /* 0 => "no" */
+               else {  /* remove number from top line, then try again */
+                       removetopl(n_len),  n_len = 0;
+                       q = '\0';
+               }
+           }
+       } while(!q);
+
+       if (q != '#') {
+               Sprintf(rtmp, "%c", q);
+               addtopl(rtmp);
+       }
+    clean_up:
+       ttyDisplay->inread--;
+       ttyDisplay->toplin = 2;
+       if (ttyDisplay->intr) ttyDisplay->intr--;
+       if(wins[WIN_MESSAGE]->cury)
+           tty_clear_nhwindow(WIN_MESSAGE);
+
+       return q;
+}
+
+#endif /* OVL2 */
+
+#endif /* TTY_GRAPHICS */
+
+/*topl.c*/
diff --git a/win/tty/wintty.c b/win/tty/wintty.c
new file mode 100644 (file)
index 0000000..9cba7d7
--- /dev/null
@@ -0,0 +1,2612 @@
+/*     SCCS Id: @(#)wintty.c   3.4     2002/09/27      */
+/* Copyright (c) David Cohrs, 1991                               */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Neither a standard out nor character-based control codes should be
+ * part of the "tty look" windowing implementation.
+ * h+ 930227
+ */
+
+#include "hack.h"
+#include "dlb.h"
+#ifdef SHORT_FILENAMES
+#include "patchlev.h"
+#else
+#include "patchlevel.h"
+#endif
+
+#ifdef TTY_GRAPHICS
+
+#ifdef MAC
+# define MICRO /* The Mac is a MICRO only for this file, not in general! */
+# ifdef THINK_C
+extern void msmsg(const char *,...);
+# endif
+#endif
+
+
+#ifndef NO_TERMS
+#include "tcap.h"
+#endif
+
+#include "wintty.h"
+
+#ifdef CLIPPING                /* might want SIGWINCH */
+# if defined(BSD) || defined(ULTRIX) || defined(AIX_31) || defined(_BULL_SOURCE)
+#include <signal.h>
+# endif
+#endif
+
+extern char mapped_menu_cmds[]; /* from options.c */
+
+/* Interface definition, for windows.c */
+struct window_procs tty_procs = {
+    "tty",
+#ifdef MSDOS
+    WC_TILED_MAP|WC_ASCII_MAP|
+#endif
+#if defined(WIN32CON)
+    WC_MOUSE_SUPPORT|
+#endif
+    WC_COLOR|WC_HILITE_PET|WC_INVERSE|WC_EIGHT_BIT_IN,
+    0L,
+    tty_init_nhwindows,
+    tty_player_selection,
+    tty_askname,
+    tty_get_nh_event,
+    tty_exit_nhwindows,
+    tty_suspend_nhwindows,
+    tty_resume_nhwindows,
+    tty_create_nhwindow,
+    tty_clear_nhwindow,
+    tty_display_nhwindow,
+    tty_destroy_nhwindow,
+    tty_curs,
+    tty_putstr,
+    tty_display_file,
+    tty_start_menu,
+    tty_add_menu,
+    tty_end_menu,
+    tty_select_menu,
+    tty_message_menu,
+    tty_update_inventory,
+    tty_mark_synch,
+    tty_wait_synch,
+#ifdef CLIPPING
+    tty_cliparound,
+#endif
+#ifdef POSITIONBAR
+    tty_update_positionbar,
+#endif
+    tty_print_glyph,
+    tty_raw_print,
+    tty_raw_print_bold,
+    tty_nhgetch,
+    tty_nh_poskey,
+    tty_nhbell,
+    tty_doprev_message,
+    tty_yn_function,
+    tty_getlin,
+    tty_get_ext_cmd,
+    tty_number_pad,
+    tty_delay_output,
+#ifdef CHANGE_COLOR    /* the Mac uses a palette device */
+    tty_change_color,
+#ifdef MAC
+    tty_change_background,
+    set_tty_font_name,
+#endif
+    tty_get_color_string,
+#endif
+
+    /* other defs that really should go away (they're tty specific) */
+    tty_start_screen,
+    tty_end_screen,
+    genl_outrip,
+#if defined(WIN32CON)
+    nttty_preference_update,
+#else
+    genl_preference_update,
+#endif
+};
+
+static int maxwin = 0;                 /* number of windows in use */
+winid BASE_WINDOW;
+struct WinDesc *wins[MAXWIN];
+struct DisplayDesc *ttyDisplay;        /* the tty display descriptor */
+
+extern void FDECL(cmov, (int,int)); /* from termcap.c */
+extern void FDECL(nocmov, (int,int)); /* from termcap.c */
+#if defined(UNIX) || defined(VMS)
+static char obuf[BUFSIZ];      /* BUFSIZ is defined in stdio.h */
+#endif
+
+static char winpanicstr[] = "Bad window id %d";
+char defmorestr[] = "--More--";
+
+#ifdef CLIPPING
+# if defined(USE_TILES) && defined(MSDOS)
+boolean clipping = FALSE;      /* clipping on? */
+int clipx = 0, clipxmax = 0;
+# else
+static boolean clipping = FALSE;       /* clipping on? */
+static int clipx = 0, clipxmax = 0;
+# endif
+static int clipy = 0, clipymax = 0;
+#endif /* CLIPPING */
+
+#if defined(USE_TILES) && defined(MSDOS)
+extern void FDECL(adjust_cursor_flags, (struct WinDesc *));
+#endif
+
+#if defined(ASCIIGRAPH) && !defined(NO_TERMS)
+boolean GFlag = FALSE;
+boolean HE_resets_AS;  /* see termcap.c */
+#endif
+
+#if defined(MICRO) || defined(WIN32CON)
+static const char to_continue[] = "to continue";
+#define getret() getreturn(to_continue)
+#else
+STATIC_DCL void NDECL(getret);
+#endif
+STATIC_DCL void FDECL(erase_menu_or_text, (winid, struct WinDesc *, BOOLEAN_P));
+STATIC_DCL void FDECL(free_window_info, (struct WinDesc *, BOOLEAN_P));
+STATIC_DCL void FDECL(dmore,(struct WinDesc *, const char *));
+STATIC_DCL void FDECL(set_item_state, (winid, int, tty_menu_item *));
+STATIC_DCL void FDECL(set_all_on_page, (winid,tty_menu_item *,tty_menu_item *));
+STATIC_DCL void FDECL(unset_all_on_page, (winid,tty_menu_item *,tty_menu_item *));
+STATIC_DCL void FDECL(invert_all_on_page, (winid,tty_menu_item *,tty_menu_item *, CHAR_P));
+STATIC_DCL void FDECL(invert_all, (winid,tty_menu_item *,tty_menu_item *, CHAR_P));
+STATIC_DCL void FDECL(process_menu_window, (winid,struct WinDesc *));
+STATIC_DCL void FDECL(process_text_window, (winid,struct WinDesc *));
+STATIC_DCL tty_menu_item *FDECL(reverse, (tty_menu_item *));
+STATIC_DCL const char * FDECL(compress_str, (const char *));
+STATIC_DCL void FDECL(tty_putsym, (winid, int, int, CHAR_P));
+static char *FDECL(copy_of, (const char *));
+STATIC_DCL void FDECL(bail, (const char *));   /* __attribute__((noreturn)) */
+
+/*
+ * A string containing all the default commands -- to add to a list
+ * of acceptable inputs.
+ */
+static const char default_menu_cmds[] = {
+       MENU_FIRST_PAGE,
+       MENU_LAST_PAGE,
+       MENU_NEXT_PAGE,
+       MENU_PREVIOUS_PAGE,
+       MENU_SELECT_ALL,
+       MENU_UNSELECT_ALL,
+       MENU_INVERT_ALL,
+       MENU_SELECT_PAGE,
+       MENU_UNSELECT_PAGE,
+       MENU_INVERT_PAGE,
+       0       /* null terminator */
+};
+
+
+/* clean up and quit */
+STATIC_OVL void
+bail(mesg)
+const char *mesg;
+{
+    clearlocks();
+    tty_exit_nhwindows(mesg);
+    terminate(EXIT_SUCCESS);
+    /*NOTREACHED*/
+}
+
+#if defined(SIGWINCH) && defined(CLIPPING)
+STATIC_OVL void
+winch()
+{
+    int oldLI = LI, oldCO = CO, i;
+    register struct WinDesc *cw;
+
+    getwindowsz();
+    if((oldLI != LI || oldCO != CO) && ttyDisplay) {
+       ttyDisplay->rows = LI;
+       ttyDisplay->cols = CO;
+
+       cw = wins[BASE_WINDOW];
+       cw->rows = ttyDisplay->rows;
+       cw->cols = ttyDisplay->cols;
+
+       if(iflags.window_inited) {
+           cw = wins[WIN_MESSAGE];
+           cw->curx = cw->cury = 0;
+
+           tty_destroy_nhwindow(WIN_STATUS);
+           WIN_STATUS = tty_create_nhwindow(NHW_STATUS);
+
+           if(u.ux) {
+#ifdef CLIPPING
+               if(CO < COLNO || LI < ROWNO+3) {
+                   setclipped();
+                   tty_cliparound(u.ux, u.uy);
+               } else {
+                   clipping = FALSE;
+                   clipx = clipy = 0;
+               }
+#endif
+               i = ttyDisplay->toplin;
+               ttyDisplay->toplin = 0;
+               docrt();
+               bot();
+               ttyDisplay->toplin = i;
+               flush_screen(1);
+               if(i) {
+                   addtopl(toplines);
+               } else
+                   for(i=WIN_INVEN; i < MAXWIN; i++)
+                       if(wins[i] && wins[i]->active) {
+                           /* cop-out */
+                           addtopl("Press Return to continue: ");
+                           break;
+                       }
+               (void) fflush(stdout);
+               if(i < 2) flush_screen(1);
+           }
+       }
+    }
+}
+#endif
+
+/*ARGSUSED*/
+void
+tty_init_nhwindows(argcp,argv)
+int* argcp;
+char** argv;
+{
+    int wid, hgt;
+
+    /*
+     *  Remember tty modes, to be restored on exit.
+     *
+     *  gettty() must be called before tty_startup()
+     *    due to ordering of LI/CO settings
+     *  tty_startup() must be called before initoptions()
+     *    due to ordering of graphics settings
+     */
+#if defined(UNIX) || defined(VMS)
+    setbuf(stdout,obuf);
+#endif
+    gettty();
+
+    /* to port dependant tty setup */
+    tty_startup(&wid, &hgt);
+    setftty();                 /* calls start_screen */
+
+    /* set up tty descriptor */
+    ttyDisplay = (struct DisplayDesc*) alloc(sizeof(struct DisplayDesc));
+    ttyDisplay->toplin = 0;
+    ttyDisplay->rows = hgt;
+    ttyDisplay->cols = wid;
+    ttyDisplay->curx = ttyDisplay->cury = 0;
+    ttyDisplay->inmore = ttyDisplay->inread = ttyDisplay->intr = 0;
+    ttyDisplay->dismiss_more = 0;
+#ifdef TEXTCOLOR
+    ttyDisplay->color = NO_COLOR;
+#endif
+    ttyDisplay->attrs = 0;
+
+    /* set up the default windows */
+    BASE_WINDOW = tty_create_nhwindow(NHW_BASE);
+    wins[BASE_WINDOW]->active = 1;
+
+    ttyDisplay->lastwin = WIN_ERR;
+
+#if defined(SIGWINCH) && defined(CLIPPING)
+    (void) signal(SIGWINCH, winch);
+#endif
+
+    /* add one a space forward menu command alias */
+    add_menu_cmd_alias(' ', MENU_NEXT_PAGE);
+
+    tty_clear_nhwindow(BASE_WINDOW);
+
+    tty_putstr(BASE_WINDOW, 0, "");
+    tty_putstr(BASE_WINDOW, 0, COPYRIGHT_BANNER_A);
+    tty_putstr(BASE_WINDOW, 0, COPYRIGHT_BANNER_B);
+    tty_putstr(BASE_WINDOW, 0, COPYRIGHT_BANNER_C);
+    tty_putstr(BASE_WINDOW, 0, "");
+    tty_display_nhwindow(BASE_WINDOW, FALSE);
+}
+
+void
+tty_player_selection()
+{
+       int i, k, n;
+       char pick4u = 'n', thisch, lastch = 0;
+       char pbuf[QBUFSZ], plbuf[QBUFSZ];
+       winid win;
+       anything any;
+       menu_item *selected = 0;
+
+       /* prevent an unnecessary prompt */
+       rigid_role_checks();
+
+       /* Should we randomly pick for the player? */
+       if (!flags.randomall &&
+           (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE ||
+            flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {
+           int echoline;
+           char *prompt = build_plselection_prompt(pbuf, QBUFSZ, flags.initrole,
+                               flags.initrace, flags.initgend, flags.initalign);
+
+           tty_putstr(BASE_WINDOW, 0, "");
+           echoline = wins[BASE_WINDOW]->cury;
+           tty_putstr(BASE_WINDOW, 0, prompt);
+           do {
+               pick4u = lowc(readchar());
+               if (index(quitchars, pick4u)) pick4u = 'y';
+           } while(!index(ynqchars, pick4u));
+           if ((int)strlen(prompt) + 1 < CO) {
+               /* Echo choice and move back down line */
+               tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline, pick4u);
+               tty_putstr(BASE_WINDOW, 0, "");
+           } else
+               /* Otherwise it's hard to tell where to echo, and things are
+                * wrapping a bit messily anyway, so (try to) make sure the next
+                * question shows up well and doesn't get wrapped at the
+                * bottom of the window.
+                */
+               tty_clear_nhwindow(BASE_WINDOW);
+           
+           if (pick4u != 'y' && pick4u != 'n') {
+give_up:       /* Quit */
+               if (selected) free((genericptr_t) selected);
+               bail((char *)0);
+               /*NOTREACHED*/
+               return;
+           }
+       }
+
+       (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+
+       /* Select a role, if necessary */
+       /* we'll try to be compatible with pre-selected race/gender/alignment,
+        * but may not succeed */
+       if (flags.initrole < 0) {
+           char rolenamebuf[QBUFSZ];
+           /* Process the choice */
+           if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) {
+               /* Pick a random role */
+               flags.initrole = pick_role(flags.initrace, flags.initgend,
+                                               flags.initalign, PICK_RANDOM);
+               if (flags.initrole < 0) {
+                   tty_putstr(BASE_WINDOW, 0, "Incompatible role!");
+                   flags.initrole = randrole();
+               }
+           } else {
+               tty_clear_nhwindow(BASE_WINDOW);
+               tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role");
+               /* Prompt for a role */
+               win = create_nhwindow(NHW_MENU);
+               start_menu(win);
+               any.a_void = 0;         /* zero out all bits */
+               for (i = 0; roles[i].name.m; i++) {
+                   if (ok_role(i, flags.initrace, flags.initgend,
+                                                       flags.initalign)) {
+                       any.a_int = i+1;        /* must be non-zero */
+                       thisch = lowc(roles[i].name.m[0]);
+                       if (thisch == lastch) thisch = highc(thisch);
+                       if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) {
+                               if (flags.initgend == 1  && roles[i].name.f)
+                                       Strcpy(rolenamebuf, roles[i].name.f);
+                               else
+                                       Strcpy(rolenamebuf, roles[i].name.m);
+                       } else {
+                               if (roles[i].name.f) {
+                                       Strcpy(rolenamebuf, roles[i].name.m);
+                                       Strcat(rolenamebuf, "/");
+                                       Strcat(rolenamebuf, roles[i].name.f);
+                               } else 
+                                       Strcpy(rolenamebuf, roles[i].name.m);
+                       }       
+                       add_menu(win, NO_GLYPH, &any, thisch,
+                           0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED);
+                       lastch = thisch;
+                   }
+               }
+               any.a_int = pick_role(flags.initrace, flags.initgend,
+                                   flags.initalign, PICK_RANDOM)+1;
+               if (any.a_int == 0)     /* must be non-zero */
+                   any.a_int = randrole()+1;
+               add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                               "Random", MENU_UNSELECTED);
+               any.a_int = i+1;        /* must be non-zero */
+               add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                               "Quit", MENU_UNSELECTED);
+               Sprintf(pbuf, "Pick a role for your %s", plbuf);
+               end_menu(win, pbuf);
+               n = select_menu(win, PICK_ONE, &selected);
+               destroy_nhwindow(win);
+
+               /* Process the choice */
+               if (n != 1 || selected[0].item.a_int == any.a_int)
+                   goto give_up;               /* Selected quit */
+
+               flags.initrole = selected[0].item.a_int - 1;
+               free((genericptr_t) selected),  selected = 0;
+           }
+           (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+       }
+       
+       /* Select a race, if necessary */
+       /* force compatibility with role, try for compatibility with
+        * pre-selected gender/alignment */
+       if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
+           /* pre-selected race not valid */
+           if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) {
+               flags.initrace = pick_race(flags.initrole, flags.initgend,
+                                                       flags.initalign, PICK_RANDOM);
+               if (flags.initrace < 0) {
+                   tty_putstr(BASE_WINDOW, 0, "Incompatible race!");
+                   flags.initrace = randrace(flags.initrole);
+               }
+           } else {    /* pick4u == 'n' */
+               /* Count the number of valid races */
+               n = 0;  /* number valid */
+               k = 0;  /* valid race */
+               for (i = 0; races[i].noun; i++) {
+                   if (ok_race(flags.initrole, i, flags.initgend,
+                                                       flags.initalign)) {
+                       n++;
+                       k = i;
+                   }
+               }
+               if (n == 0) {
+                   for (i = 0; races[i].noun; i++) {
+                       if (validrace(flags.initrole, i)) {
+                           n++;
+                           k = i;
+                       }
+                   }
+               }
+
+               /* Permit the user to pick, if there is more than one */
+               if (n > 1) {
+                   tty_clear_nhwindow(BASE_WINDOW);
+                   tty_putstr(BASE_WINDOW, 0, "Choosing Race");
+                   win = create_nhwindow(NHW_MENU);
+                   start_menu(win);
+                   any.a_void = 0;         /* zero out all bits */
+                   for (i = 0; races[i].noun; i++)
+                       if (ok_race(flags.initrole, i, flags.initgend,
+                                                       flags.initalign)) {
+                           any.a_int = i+1;    /* must be non-zero */
+                           add_menu(win, NO_GLYPH, &any, races[i].noun[0],
+                               0, ATR_NONE, races[i].noun, MENU_UNSELECTED);
+                       }
+                   any.a_int = pick_race(flags.initrole, flags.initgend,
+                                       flags.initalign, PICK_RANDOM)+1;
+                   if (any.a_int == 0) /* must be non-zero */
+                       any.a_int = randrace(flags.initrole)+1;
+                   add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                   "Random", MENU_UNSELECTED);
+                   any.a_int = i+1;    /* must be non-zero */
+                   add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                   "Quit", MENU_UNSELECTED);
+                   Sprintf(pbuf, "Pick the race of your %s", plbuf);
+                   end_menu(win, pbuf);
+                   n = select_menu(win, PICK_ONE, &selected);
+                   destroy_nhwindow(win);
+                   if (n != 1 || selected[0].item.a_int == any.a_int)
+                       goto give_up;           /* Selected quit */
+
+                   k = selected[0].item.a_int - 1;
+                   free((genericptr_t) selected),      selected = 0;
+               }
+               flags.initrace = k;
+           }
+           (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+       }
+
+       /* Select a gender, if necessary */
+       /* force compatibility with role/race, try for compatibility with
+        * pre-selected alignment */
+       if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
+                                               flags.initgend)) {
+           /* pre-selected gender not valid */
+           if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) {
+               flags.initgend = pick_gend(flags.initrole, flags.initrace,
+                                               flags.initalign, PICK_RANDOM);
+               if (flags.initgend < 0) {
+                   tty_putstr(BASE_WINDOW, 0, "Incompatible gender!");
+                   flags.initgend = randgend(flags.initrole, flags.initrace);
+               }
+           } else {    /* pick4u == 'n' */
+               /* Count the number of valid genders */
+               n = 0;  /* number valid */
+               k = 0;  /* valid gender */
+               for (i = 0; i < ROLE_GENDERS; i++) {
+                   if (ok_gend(flags.initrole, flags.initrace, i,
+                                                       flags.initalign)) {
+                       n++;
+                       k = i;
+                   }
+               }
+               if (n == 0) {
+                   for (i = 0; i < ROLE_GENDERS; i++) {
+                       if (validgend(flags.initrole, flags.initrace, i)) {
+                           n++;
+                           k = i;
+                       }
+                   }
+               }
+
+               /* Permit the user to pick, if there is more than one */
+               if (n > 1) {
+                   tty_clear_nhwindow(BASE_WINDOW);
+                   tty_putstr(BASE_WINDOW, 0, "Choosing Gender");
+                   win = create_nhwindow(NHW_MENU);
+                   start_menu(win);
+                   any.a_void = 0;         /* zero out all bits */
+                   for (i = 0; i < ROLE_GENDERS; i++)
+                       if (ok_gend(flags.initrole, flags.initrace, i,
+                                                           flags.initalign)) {
+                           any.a_int = i+1;
+                           add_menu(win, NO_GLYPH, &any, genders[i].adj[0],
+                               0, ATR_NONE, genders[i].adj, MENU_UNSELECTED);
+                       }
+                   any.a_int = pick_gend(flags.initrole, flags.initrace,
+                                           flags.initalign, PICK_RANDOM)+1;
+                   if (any.a_int == 0) /* must be non-zero */
+                       any.a_int = randgend(flags.initrole, flags.initrace)+1;
+                   add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                   "Random", MENU_UNSELECTED);
+                   any.a_int = i+1;    /* must be non-zero */
+                   add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                   "Quit", MENU_UNSELECTED);
+                   Sprintf(pbuf, "Pick the gender of your %s", plbuf);
+                   end_menu(win, pbuf);
+                   n = select_menu(win, PICK_ONE, &selected);
+                   destroy_nhwindow(win);
+                   if (n != 1 || selected[0].item.a_int == any.a_int)
+                       goto give_up;           /* Selected quit */
+
+                   k = selected[0].item.a_int - 1;
+                   free((genericptr_t) selected),      selected = 0;
+               }
+               flags.initgend = k;
+           }
+           (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+       }
+
+       /* Select an alignment, if necessary */
+       /* force compatibility with role/race/gender */
+       if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
+                                                       flags.initalign)) {
+           /* pre-selected alignment not valid */
+           if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) {
+               flags.initalign = pick_align(flags.initrole, flags.initrace,
+                                                       flags.initgend, PICK_RANDOM);
+               if (flags.initalign < 0) {
+                   tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!");
+                   flags.initalign = randalign(flags.initrole, flags.initrace);
+               }
+           } else {    /* pick4u == 'n' */
+               /* Count the number of valid alignments */
+               n = 0;  /* number valid */
+               k = 0;  /* valid alignment */
+               for (i = 0; i < ROLE_ALIGNS; i++) {
+                   if (ok_align(flags.initrole, flags.initrace, flags.initgend,
+                                                       i)) {
+                       n++;
+                       k = i;
+                   }
+               }
+               if (n == 0) {
+                   for (i = 0; i < ROLE_ALIGNS; i++) {
+                       if (validalign(flags.initrole, flags.initrace, i)) {
+                           n++;
+                           k = i;
+                       }
+                   }
+               }
+
+               /* Permit the user to pick, if there is more than one */
+               if (n > 1) {
+                   tty_clear_nhwindow(BASE_WINDOW);
+                   tty_putstr(BASE_WINDOW, 0, "Choosing Alignment");
+                   win = create_nhwindow(NHW_MENU);
+                   start_menu(win);
+                   any.a_void = 0;         /* zero out all bits */
+                   for (i = 0; i < ROLE_ALIGNS; i++)
+                       if (ok_align(flags.initrole, flags.initrace,
+                                                       flags.initgend, i)) {
+                           any.a_int = i+1;
+                           add_menu(win, NO_GLYPH, &any, aligns[i].adj[0],
+                                0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
+                       }
+                   any.a_int = pick_align(flags.initrole, flags.initrace,
+                                           flags.initgend, PICK_RANDOM)+1;
+                   if (any.a_int == 0) /* must be non-zero */
+                       any.a_int = randalign(flags.initrole, flags.initrace)+1;
+                   add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                   "Random", MENU_UNSELECTED);
+                   any.a_int = i+1;    /* must be non-zero */
+                   add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                   "Quit", MENU_UNSELECTED);
+                   Sprintf(pbuf, "Pick the alignment of your %s", plbuf);
+                   end_menu(win, pbuf);
+                   n = select_menu(win, PICK_ONE, &selected);
+                   destroy_nhwindow(win);
+                   if (n != 1 || selected[0].item.a_int == any.a_int)
+                       goto give_up;           /* Selected quit */
+
+                   k = selected[0].item.a_int - 1;
+                   free((genericptr_t) selected),      selected = 0;
+               }
+               flags.initalign = k;
+           }
+       }
+       /* Success! */
+       tty_display_nhwindow(BASE_WINDOW, FALSE);
+}
+
+/*
+ * plname is filled either by an option (-u Player  or  -uPlayer) or
+ * explicitly (by being the wizard) or by askname.
+ * It may still contain a suffix denoting the role, etc.
+ * Always called after init_nhwindows() and before display_gamewindows().
+ */
+void
+tty_askname()
+{
+    static char who_are_you[] = "Who are you? ";
+    register int c, ct, tryct = 0;
+
+    tty_putstr(BASE_WINDOW, 0, "");
+    do {
+       if (++tryct > 1) {
+           if (tryct > 10) bail("Giving up after 10 tries.\n");
+           tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury - 1);
+           tty_putstr(BASE_WINDOW, 0, "Enter a name for your character...");
+           /* erase previous prompt (in case of ESC after partial response) */
+           tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury),  cl_end();
+       }
+       tty_putstr(BASE_WINDOW, 0, who_are_you);
+       tty_curs(BASE_WINDOW, (int)(sizeof who_are_you),
+                wins[BASE_WINDOW]->cury - 1);
+       ct = 0;
+       while((c = tty_nhgetch()) != '\n') {
+               if(c == EOF) error("End of input\n");
+               if (c == '\033') { ct = 0; break; }  /* continue outer loop */
+#if defined(WIN32CON)
+               if (c == '\003') bail("^C abort.\n");
+#endif
+               /* some people get confused when their erase char is not ^H */
+               if (c == '\b' || c == '\177') {
+                       if(ct) {
+                               ct--;
+#ifdef WIN32CON
+                               ttyDisplay->curx--;
+#endif
+#if defined(MICRO) || defined(WIN32CON)
+# if defined(WIN32CON) || defined(MSDOS)
+                               backsp();       /* \b is visible on NT */
+                               (void) putchar(' ');
+                               backsp();
+# else
+                               msmsg("\b \b");
+# endif
+#else
+                               (void) putchar('\b');
+                               (void) putchar(' ');
+                               (void) putchar('\b');
+#endif
+                       }
+                       continue;
+               }
+#if defined(UNIX) || defined(VMS)
+               if(c != '-' && c != '@')
+               if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
+#endif
+               if (ct < (int)(sizeof plname) - 1) {
+#if defined(MICRO)
+# if defined(MSDOS)
+                       if (iflags.grmode) {
+                               (void) putchar(c);
+                       } else
+# endif
+                       msmsg("%c", c);
+#else
+                       (void) putchar(c);
+#endif
+                       plname[ct++] = c;
+#ifdef WIN32CON
+                       ttyDisplay->curx++;
+#endif
+               }
+       }
+       plname[ct] = 0;
+    } while (ct == 0);
+
+    /* move to next line to simulate echo of user's <return> */
+    tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury + 1);
+}
+
+void
+tty_get_nh_event()
+{
+    return;
+}
+
+#if !defined(MICRO) && !defined(WIN32CON)
+STATIC_OVL void
+getret()
+{
+       xputs("\n");
+       if(flags.standout)
+               standoutbeg();
+       xputs("Hit ");
+       xputs(iflags.cbreak ? "space" : "return");
+       xputs(" to continue: ");
+       if(flags.standout)
+               standoutend();
+       xwaitforspace(" ");
+}
+#endif
+
+void
+tty_suspend_nhwindows(str)
+    const char *str;
+{
+    settty(str);               /* calls end_screen, perhaps raw_print */
+    if (!str) tty_raw_print("");       /* calls fflush(stdout) */
+}
+
+void
+tty_resume_nhwindows()
+{
+    gettty();
+    setftty();                 /* calls start_screen */
+    docrt();
+}
+
+void
+tty_exit_nhwindows(str)
+    const char *str;
+{
+    winid i;
+
+    tty_suspend_nhwindows(str);
+    /* Just forget any windows existed, since we're about to exit anyway.
+     * Disable windows to avoid calls to window routines.
+     */
+    for(i=0; i<MAXWIN; i++)
+       if (wins[i] && (i != BASE_WINDOW)) {
+#ifdef FREE_ALL_MEMORY
+           free_window_info(wins[i], TRUE);
+           free((genericptr_t) wins[i]);
+#endif
+           wins[i] = 0;
+       }
+#ifndef NO_TERMS               /*(until this gets added to the window interface)*/
+    tty_shutdown();            /* cleanup termcap/terminfo/whatever */
+#endif
+    iflags.window_inited = 0;
+}
+
+winid
+tty_create_nhwindow(type)
+    int type;
+{
+    struct WinDesc* newwin;
+    int i;
+    int newid;
+
+    if(maxwin == MAXWIN)
+       return WIN_ERR;
+
+    newwin = (struct WinDesc*) alloc(sizeof(struct WinDesc));
+    newwin->type = type;
+    newwin->flags = 0;
+    newwin->active = FALSE;
+    newwin->curx = newwin->cury = 0;
+    newwin->morestr = 0;
+    newwin->mlist = (tty_menu_item *) 0;
+    newwin->plist = (tty_menu_item **) 0;
+    newwin->npages = newwin->plist_size = newwin->nitems = newwin->how = 0;
+    switch(type) {
+    case NHW_BASE:
+       /* base window, used for absolute movement on the screen */
+       newwin->offx = newwin->offy = 0;
+       newwin->rows = ttyDisplay->rows;
+       newwin->cols = ttyDisplay->cols;
+       newwin->maxrow = newwin->maxcol = 0;
+       break;
+    case NHW_MESSAGE:
+       /* message window, 1 line long, very wide, top of screen */
+       newwin->offx = newwin->offy = 0;
+       /* sanity check */
+       if(iflags.msg_history < 20) iflags.msg_history = 20;
+       else if(iflags.msg_history > 60) iflags.msg_history = 60;
+       newwin->maxrow = newwin->rows = iflags.msg_history;
+       newwin->maxcol = newwin->cols = 0;
+       break;
+    case NHW_STATUS:
+       /* status window, 2 lines long, full width, bottom of screen */
+       newwin->offx = 0;
+#if defined(USE_TILES) && defined(MSDOS)
+       if (iflags.grmode) {
+               newwin->offy = ttyDisplay->rows-2;
+       } else
+#endif
+       newwin->offy = min((int)ttyDisplay->rows-2, ROWNO+1);
+       newwin->rows = newwin->maxrow = 2;
+       newwin->cols = newwin->maxcol = min(ttyDisplay->cols, COLNO);
+       break;
+    case NHW_MAP:
+       /* map window, ROWNO lines long, full width, below message window */
+       newwin->offx = 0;
+       newwin->offy = 1;
+       newwin->rows = ROWNO;
+       newwin->cols = COLNO;
+       newwin->maxrow = 0;     /* no buffering done -- let gbuf do it */
+       newwin->maxcol = 0;
+       break;
+    case NHW_MENU:
+    case NHW_TEXT:
+       /* inventory/menu window, variable length, full width, top of screen */
+       /* help window, the same, different semantics for display, etc */
+       newwin->offx = newwin->offy = 0;
+       newwin->rows = 0;
+       newwin->cols = ttyDisplay->cols;
+       newwin->maxrow = newwin->maxcol = 0;
+       break;
+   default:
+       panic("Tried to create window type %d\n", (int) type);
+       return WIN_ERR;
+    }
+
+    for(newid = 0; newid<MAXWIN; newid++) {
+       if(wins[newid] == 0) {
+           wins[newid] = newwin;
+           break;
+       }
+    }
+    if(newid == MAXWIN) {
+       panic("No window slots!");
+       return WIN_ERR;
+    }
+
+    if(newwin->maxrow) {
+       newwin->data =
+               (char **) alloc(sizeof(char *) * (unsigned)newwin->maxrow);
+       newwin->datlen =
+               (short *) alloc(sizeof(short) * (unsigned)newwin->maxrow);
+       if(newwin->maxcol) {
+           for (i = 0; i < newwin->maxrow; i++) {
+               newwin->data[i] = (char *) alloc((unsigned)newwin->maxcol);
+               newwin->datlen[i] = newwin->maxcol;
+           }
+       } else {
+           for (i = 0; i < newwin->maxrow; i++) {
+               newwin->data[i] = (char *) 0;
+               newwin->datlen[i] = 0;
+           }
+       }
+       if(newwin->type == NHW_MESSAGE)
+           newwin->maxrow = 0;
+    } else {
+       newwin->data = (char **)0;
+       newwin->datlen = (short *)0;
+    }
+
+    return newid;
+}
+
+STATIC_OVL void
+erase_menu_or_text(window, cw, clear)
+    winid window;
+    struct WinDesc *cw;
+    boolean clear;
+{
+    if(cw->offx == 0)
+       if(cw->offy) {
+           tty_curs(window, 1, 0);
+           cl_eos();
+       } else if (clear)
+           clear_screen();
+       else
+           docrt();
+    else
+       docorner((int)cw->offx, cw->maxrow+1);
+}
+
+STATIC_OVL void
+free_window_info(cw, free_data)
+    struct WinDesc *cw;
+    boolean free_data;
+{
+    int i;
+
+    if (cw->data) {
+       if (cw == wins[WIN_MESSAGE] && cw->rows > cw->maxrow)
+           cw->maxrow = cw->rows;              /* topl data */
+       for(i=0; i<cw->maxrow; i++)
+           if(cw->data[i]) {
+               free((genericptr_t)cw->data[i]);
+               cw->data[i] = (char *)0;
+               if (cw->datlen) cw->datlen[i] = 0;
+           }
+       if (free_data) {
+           free((genericptr_t)cw->data);
+           cw->data = (char **)0;
+           if (cw->datlen) free((genericptr_t)cw->datlen);
+           cw->datlen = (short *)0;
+           cw->rows = 0;
+       }
+    }
+    cw->maxrow = cw->maxcol = 0;
+    if(cw->mlist) {
+       tty_menu_item *temp;
+       while ((temp = cw->mlist) != 0) {
+           cw->mlist = cw->mlist->next;
+           if (temp->str) free((genericptr_t)temp->str);
+           free((genericptr_t)temp);
+       }
+    }
+    if (cw->plist) {
+       free((genericptr_t)cw->plist);
+       cw->plist = 0;
+    }
+    cw->plist_size = cw->npages = cw->nitems = cw->how = 0;
+    if(cw->morestr) {
+       free((genericptr_t)cw->morestr);
+       cw->morestr = 0;
+    }
+}
+
+void
+tty_clear_nhwindow(window)
+    winid window;
+{
+    register struct WinDesc *cw = 0;
+
+    if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
+       panic(winpanicstr,  window);
+    ttyDisplay->lastwin = window;
+
+    switch(cw->type) {
+    case NHW_MESSAGE:
+       if(ttyDisplay->toplin) {
+           home();
+           cl_end();
+           if(cw->cury)
+               docorner(1, cw->cury+1);
+           ttyDisplay->toplin = 0;
+       }
+       break;
+    case NHW_STATUS:
+       tty_curs(window, 1, 0);
+       cl_end();
+       tty_curs(window, 1, 1);
+       cl_end();
+       break;
+    case NHW_MAP:
+       /* cheap -- clear the whole thing and tell nethack to redraw botl */
+       flags.botlx = 1;
+       /* fall into ... */
+    case NHW_BASE:
+       clear_screen();
+       break;
+    case NHW_MENU:
+    case NHW_TEXT:
+       if(cw->active)
+           erase_menu_or_text(window, cw, TRUE);
+       free_window_info(cw, FALSE);
+       break;
+    }
+    cw->curx = cw->cury = 0;
+}
+
+STATIC_OVL void
+dmore(cw, s)
+    register struct WinDesc *cw;
+    const char *s;                     /* valid responses */
+{
+    const char *prompt = cw->morestr ? cw->morestr : defmorestr;
+    int offset = (cw->type == NHW_TEXT) ? 1 : 2;
+
+    tty_curs(BASE_WINDOW,
+            (int)ttyDisplay->curx + offset, (int)ttyDisplay->cury);
+    if(flags.standout)
+       standoutbeg();
+    xputs(prompt);
+    ttyDisplay->curx += strlen(prompt);
+    if(flags.standout)
+       standoutend();
+
+    xwaitforspace(s);
+}
+
+STATIC_OVL void
+set_item_state(window, lineno, item)
+    winid window;
+    int lineno;
+    tty_menu_item *item;
+{
+    char ch = item->selected ? (item->count == -1L ? '+' : '#') : '-';
+    tty_curs(window, 4, lineno);
+    term_start_attr(item->attr);
+    (void) putchar(ch);
+    ttyDisplay->curx++;
+    term_end_attr(item->attr);
+}
+
+STATIC_OVL void
+set_all_on_page(window, page_start, page_end)
+    winid window;
+    tty_menu_item *page_start, *page_end;
+{
+    tty_menu_item *curr;
+    int n;
+
+    for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next)
+       if (curr->identifier.a_void && !curr->selected) {
+           curr->selected = TRUE;
+           set_item_state(window, n, curr);
+       }
+}
+
+STATIC_OVL void
+unset_all_on_page(window, page_start, page_end)
+    winid window;
+    tty_menu_item *page_start, *page_end;
+{
+    tty_menu_item *curr;
+    int n;
+
+    for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next)
+       if (curr->identifier.a_void && curr->selected) {
+           curr->selected = FALSE;
+           curr->count = -1L;
+           set_item_state(window, n, curr);
+       }
+}
+
+STATIC_OVL void
+invert_all_on_page(window, page_start, page_end, acc)
+    winid window;
+    tty_menu_item *page_start, *page_end;
+    char acc;  /* group accelerator, 0 => all */
+{
+    tty_menu_item *curr;
+    int n;
+
+    for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next)
+       if (curr->identifier.a_void && (acc == 0 || curr->gselector == acc)) {
+           if (curr->selected) {
+               curr->selected = FALSE;
+               curr->count = -1L;
+           } else
+               curr->selected = TRUE;
+           set_item_state(window, n, curr);
+       }
+}
+
+/*
+ * Invert all entries that match the give group accelerator (or all if
+ * zero).
+ */
+STATIC_OVL void
+invert_all(window, page_start, page_end, acc)
+    winid window;
+    tty_menu_item *page_start, *page_end;
+    char acc;  /* group accelerator, 0 => all */
+{
+    tty_menu_item *curr;
+    boolean on_curr_page;
+    struct WinDesc *cw =  wins[window];
+
+    invert_all_on_page(window, page_start, page_end, acc);
+
+    /* invert the rest */
+    for (on_curr_page = FALSE, curr = cw->mlist; curr; curr = curr->next) {
+       if (curr == page_start)
+           on_curr_page = TRUE;
+       else if (curr == page_end)
+           on_curr_page = FALSE;
+
+       if (!on_curr_page && curr->identifier.a_void
+                               && (acc == 0 || curr->gselector == acc)) {
+           if (curr->selected) {
+               curr->selected = FALSE;
+               curr->count = -1;
+           } else
+               curr->selected = TRUE;
+       }
+    }
+}
+
+STATIC_OVL void
+process_menu_window(window, cw)
+winid window;
+struct WinDesc *cw;
+{
+    tty_menu_item *page_start, *page_end, *curr;
+    long count;
+    int n, curr_page, page_lines;
+    boolean finished, counting, reset_count;
+    char *cp, *rp, resp[QBUFSZ], gacc[QBUFSZ],
+        *msave, *morestr;
+
+    curr_page = page_lines = 0;
+    page_start = page_end = 0;
+    msave = cw->morestr;       /* save the morestr */
+    cw->morestr = morestr = (char*) alloc((unsigned) QBUFSZ);
+    counting = FALSE;
+    count = 0L;
+    reset_count = TRUE;
+    finished = FALSE;
+
+    /* collect group accelerators; for PICK_NONE, they're ignored;
+       for PICK_ONE, only those which match exactly one entry will be
+       accepted; for PICK_ANY, those which match any entry are okay */
+    gacc[0] = '\0';
+    if (cw->how != PICK_NONE) {
+       int i, gcnt[128];
+#define GSELIDX(c) (c & 127)   /* guard against `signed char' */
+
+       for (i = 0; i < SIZE(gcnt); i++) gcnt[i] = 0;
+       for (n = 0, curr = cw->mlist; curr; curr = curr->next)
+           if (curr->gselector && curr->gselector != curr->selector) {
+               ++n;
+               ++gcnt[GSELIDX(curr->gselector)];
+           }
+
+       if (n > 0)      /* at least one group accelerator found */
+           for (rp = gacc, curr = cw->mlist; curr; curr = curr->next)
+               if (curr->gselector && !index(gacc, curr->gselector) &&
+                       (cw->how == PICK_ANY ||
+                           gcnt[GSELIDX(curr->gselector)] == 1)) {
+                   *rp++ = curr->gselector;
+                   *rp = '\0'; /* re-terminate for index() */
+               }
+    }
+
+    /* loop until finished */
+    while (!finished) {
+       if (reset_count) {
+           counting = FALSE;
+           count = 0;
+       } else
+           reset_count = TRUE;
+
+       if (!page_start) {
+           /* new page to be displayed */
+           if (curr_page < 0 || (cw->npages > 0 && curr_page >= cw->npages))
+               panic("bad menu screen page #%d", curr_page);
+
+           /* clear screen */
+           if (!cw->offx) {    /* if not corner, do clearscreen */
+               if(cw->offy) {
+                   tty_curs(window, 1, 0);
+                   cl_eos();
+               } else
+                   clear_screen();
+           }
+
+           rp = resp;
+           if (cw->npages > 0) {
+               /* collect accelerators */
+               page_start = cw->plist[curr_page];
+               page_end = cw->plist[curr_page + 1];
+               for (page_lines = 0, curr = page_start;
+                       curr != page_end;
+                       page_lines++, curr = curr->next) {
+                   if (curr->selector)
+                       *rp++ = curr->selector;
+
+                   tty_curs(window, 1, page_lines);
+                   if (cw->offx) cl_end();
+
+                   (void) putchar(' ');
+                   ++ttyDisplay->curx;
+                   /*
+                    * Don't use xputs() because (1) under unix it calls
+                    * tputstr() which will interpret a '*' as some kind
+                    * of padding information and (2) it calls xputc to
+                    * actually output the character.  We're faster doing
+                    * this.
+                    */
+                   term_start_attr(curr->attr);
+                   for (n = 0, cp = curr->str;
+#ifndef WIN32CON
+                         *cp && (int) ++ttyDisplay->curx < (int) ttyDisplay->cols;
+                         cp++, n++)
+#else
+                         *cp && (int) ttyDisplay->curx < (int) ttyDisplay->cols;
+                         cp++, n++, ttyDisplay->curx++)
+#endif
+                       if (n == 2 && curr->identifier.a_void != 0 &&
+                                                       curr->selected) {
+                           if (curr->count == -1L)
+                               (void) putchar('+'); /* all selected */
+                           else
+                               (void) putchar('#'); /* count selected */
+                       } else
+                           (void) putchar(*cp);
+                   term_end_attr(curr->attr);
+               }
+           } else {
+               page_start = 0;
+               page_end = 0;
+               page_lines = 0;
+           }
+           *rp = 0;
+
+           /* corner window - clear extra lines from last page */
+           if (cw->offx) {
+               for (n = page_lines + 1; n < cw->maxrow; n++) {
+                   tty_curs(window, 1, n);
+                   cl_end();
+               }
+           }
+
+           /* set extra chars.. */
+           Strcat(resp, default_menu_cmds);
+           Strcat(resp, "0123456789\033\n\r"); /* counts, quit */
+           Strcat(resp, gacc);                 /* group accelerators */
+           Strcat(resp, mapped_menu_cmds);
+
+           if (cw->npages > 1)
+               Sprintf(cw->morestr, "(%d of %d)",
+                       curr_page + 1, (int) cw->npages);
+           else if (msave)
+               Strcpy(cw->morestr, msave);
+           else
+               Strcpy(cw->morestr, defmorestr);
+
+           tty_curs(window, 1, page_lines);
+           cl_end();
+           dmore(cw, resp);
+       } else {
+           /* just put the cursor back... */
+           tty_curs(window, (int) strlen(cw->morestr) + 2, page_lines);
+           xwaitforspace(resp);
+       }
+
+       morc = map_menu_cmd(morc);
+       switch (morc) {
+           case '0':
+               /* special case: '0' is also the default ball class */
+               if (!counting && index(gacc, morc)) goto group_accel;
+               /* fall through to count the zero */
+           case '1': case '2': case '3': case '4':
+           case '5': case '6': case '7': case '8': case '9':
+               count = (count * 10L) + (long) (morc - '0');
+               /*
+                * It is debatable whether we should allow 0 to
+                * start a count.  There is no difference if the
+                * item is selected.  If not selected, then
+                * "0b" could mean:
+                *
+                *      count starting zero:    "zero b's"
+                *      ignore starting zero:   "select b"
+                *
+                * At present I don't know which is better.
+                */
+               if (count != 0L) {      /* ignore leading zeros */
+                   counting = TRUE;
+                   reset_count = FALSE;
+               }
+               break;
+           case '\033':        /* cancel - from counting or loop */
+               if (!counting) {
+                   /* deselect everything */
+                   for (curr = cw->mlist; curr; curr = curr->next) {
+                       curr->selected = FALSE;
+                       curr->count = -1L;
+                   }
+                   cw->flags |= WIN_CANCELLED;
+                   finished = TRUE;
+               }
+               /* else only stop count */
+               break;
+           case '\0':          /* finished (commit) */
+           case '\n':
+           case '\r':
+               /* only finished if we are actually picking something */
+               if (cw->how != PICK_NONE) {
+                   finished = TRUE;
+                   break;
+               }
+               /* else fall through */
+           case MENU_NEXT_PAGE:
+               if (cw->npages > 0 && curr_page != cw->npages - 1) {
+                   curr_page++;
+                   page_start = 0;
+               } else
+                   finished = TRUE;    /* questionable behavior */
+               break;
+           case MENU_PREVIOUS_PAGE:
+               if (cw->npages > 0 && curr_page != 0) {
+                   --curr_page;
+                   page_start = 0;
+               }
+               break;
+           case MENU_FIRST_PAGE:
+               if (cw->npages > 0 && curr_page != 0) {
+                   page_start = 0;
+                   curr_page = 0;
+               }
+               break;
+           case MENU_LAST_PAGE:
+               if (cw->npages > 0 && curr_page != cw->npages - 1) {
+                   page_start = 0;
+                   curr_page = cw->npages - 1;
+               }
+               break;
+           case MENU_SELECT_PAGE:
+               if (cw->how == PICK_ANY)
+                   set_all_on_page(window, page_start, page_end);
+               break;
+           case MENU_UNSELECT_PAGE:
+               unset_all_on_page(window, page_start, page_end);
+               break;
+           case MENU_INVERT_PAGE:
+               if (cw->how == PICK_ANY)
+                   invert_all_on_page(window, page_start, page_end, 0);
+               break;
+           case MENU_SELECT_ALL:
+               if (cw->how == PICK_ANY) {
+                   set_all_on_page(window, page_start, page_end);
+                   /* set the rest */
+                   for (curr = cw->mlist; curr; curr = curr->next)
+                       if (curr->identifier.a_void && !curr->selected)
+                           curr->selected = TRUE;
+               }
+               break;
+           case MENU_UNSELECT_ALL:
+               unset_all_on_page(window, page_start, page_end);
+               /* unset the rest */
+               for (curr = cw->mlist; curr; curr = curr->next)
+                   if (curr->identifier.a_void && curr->selected) {
+                       curr->selected = FALSE;
+                       curr->count = -1;
+                   }
+               break;
+           case MENU_INVERT_ALL:
+               if (cw->how == PICK_ANY)
+                   invert_all(window, page_start, page_end, 0);
+               break;
+           default:
+               if (cw->how == PICK_NONE || !index(resp, morc)) {
+                   /* unacceptable input received */
+                   tty_nhbell();
+                   break;
+               } else if (index(gacc, morc)) {
+ group_accel:
+                   /* group accelerator; for the PICK_ONE case, we know that
+                      it matches exactly one item in order to be in gacc[] */
+                   invert_all(window, page_start, page_end, morc);
+                   if (cw->how == PICK_ONE) finished = TRUE;
+                   break;
+               }
+               /* find, toggle, and possibly update */
+               for (n = 0, curr = page_start;
+                       curr != page_end;
+                       n++, curr = curr->next)
+                   if (morc == curr->selector) {
+                       if (curr->selected) {
+                           if (counting && count > 0) {
+                               curr->count = count;
+                               set_item_state(window, n, curr);
+                           } else { /* change state */
+                               curr->selected = FALSE;
+                               curr->count = -1L;
+                               set_item_state(window, n, curr);
+                           }
+                       } else {        /* !selected */
+                           if (counting && count > 0) {
+                               curr->count = count;
+                               curr->selected = TRUE;
+                               set_item_state(window, n, curr);
+                           } else if (!counting) {
+                               curr->selected = TRUE;
+                               set_item_state(window, n, curr);
+                           }
+                           /* do nothing counting&&count==0 */
+                       }
+
+                       if (cw->how == PICK_ONE) finished = TRUE;
+                       break;  /* from `for' loop */
+                   }
+               break;
+       }
+
+    } /* while */
+    cw->morestr = msave;
+    free((genericptr_t)morestr);
+}
+
+STATIC_OVL void
+process_text_window(window, cw)
+winid window;
+struct WinDesc *cw;
+{
+    int i, n, attr;
+    register char *cp;
+
+    for (n = 0, i = 0; i < cw->maxrow; i++) {
+       if (!cw->offx && (n + cw->offy == ttyDisplay->rows - 1)) {
+           tty_curs(window, 1, n);
+           cl_end();
+           dmore(cw, quitchars);
+           if (morc == '\033') {
+               cw->flags |= WIN_CANCELLED;
+               break;
+           }
+           if (cw->offy) {
+               tty_curs(window, 1, 0);
+               cl_eos();
+           } else
+               clear_screen();
+           n = 0;
+       }
+       tty_curs(window, 1, n++);
+       if (cw->offx) cl_end();
+       if (cw->data[i]) {
+           attr = cw->data[i][0] - 1;
+           if (cw->offx) {
+               (void) putchar(' '); ++ttyDisplay->curx;
+           }
+           term_start_attr(attr);
+           for (cp = &cw->data[i][1];
+#ifndef WIN32CON
+                   *cp && (int) ++ttyDisplay->curx < (int) ttyDisplay->cols;
+                   cp++)
+#else
+                   *cp && (int) ttyDisplay->curx < (int) ttyDisplay->cols;
+                   cp++, ttyDisplay->curx++)
+#endif
+               (void) putchar(*cp);
+           term_end_attr(attr);
+       }
+    }
+    if (i == cw->maxrow) {
+       tty_curs(BASE_WINDOW, (int)cw->offx + 1,
+                (cw->type == NHW_TEXT) ? (int) ttyDisplay->rows - 1 : n);
+       cl_end();
+       dmore(cw, quitchars);
+       if (morc == '\033')
+           cw->flags |= WIN_CANCELLED;
+    }
+}
+
+/*ARGSUSED*/
+void
+tty_display_nhwindow(window, blocking)
+    winid window;
+    boolean blocking;  /* with ttys, all windows are blocking */
+{
+    register struct WinDesc *cw = 0;
+
+    if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
+       panic(winpanicstr,  window);
+    if(cw->flags & WIN_CANCELLED)
+       return;
+    ttyDisplay->lastwin = window;
+    ttyDisplay->rawprint = 0;
+
+    switch(cw->type) {
+    case NHW_MESSAGE:
+       if(ttyDisplay->toplin == 1) {
+           more();
+           ttyDisplay->toplin = 1; /* more resets this */
+           tty_clear_nhwindow(window);
+       } else
+           ttyDisplay->toplin = 0;
+       cw->curx = cw->cury = 0;
+       if(!cw->active)
+           iflags.window_inited = TRUE;
+       break;
+    case NHW_MAP:
+       end_glyphout();
+       if(blocking) {
+           if(!ttyDisplay->toplin) ttyDisplay->toplin = 1;
+           tty_display_nhwindow(WIN_MESSAGE, TRUE);
+           return;
+       }
+    case NHW_BASE:
+       (void) fflush(stdout);
+       break;
+    case NHW_TEXT:
+       cw->maxcol = ttyDisplay->cols; /* force full-screen mode */
+       /*FALLTHRU*/
+    case NHW_MENU:
+       cw->active = 1;
+       /* avoid converting to uchar before calculations are finished */
+       cw->offx = (uchar) (int)
+           max((int) 10, (int) (ttyDisplay->cols - cw->maxcol - 1));
+       if(cw->type == NHW_MENU)
+           cw->offy = 0;
+       if(ttyDisplay->toplin == 1)
+           tty_display_nhwindow(WIN_MESSAGE, TRUE);
+       if(cw->offx == 10 || cw->maxrow >= (int) ttyDisplay->rows) {
+           cw->offx = 0;
+           if(cw->offy) {
+               tty_curs(window, 1, 0);
+               cl_eos();
+           } else
+               clear_screen();
+           ttyDisplay->toplin = 0;
+       } else
+           tty_clear_nhwindow(WIN_MESSAGE);
+
+       if (cw->data || !cw->maxrow)
+           process_text_window(window, cw);
+       else
+           process_menu_window(window, cw);
+       break;
+    }
+    cw->active = 1;
+}
+
+void
+tty_dismiss_nhwindow(window)
+    winid window;
+{
+    register struct WinDesc *cw = 0;
+
+    if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
+       panic(winpanicstr,  window);
+
+    switch(cw->type) {
+    case NHW_MESSAGE:
+       if (ttyDisplay->toplin)
+           tty_display_nhwindow(WIN_MESSAGE, TRUE);
+       /*FALLTHRU*/
+    case NHW_STATUS:
+    case NHW_BASE:
+    case NHW_MAP:
+       /*
+        * these should only get dismissed when the game is going away
+        * or suspending
+        */
+       tty_curs(BASE_WINDOW, 1, (int)ttyDisplay->rows-1);
+       cw->active = 0;
+       break;
+    case NHW_MENU:
+    case NHW_TEXT:
+       if(cw->active) {
+           if (iflags.window_inited) {
+               /* otherwise dismissing the text endwin after other windows
+                * are dismissed tries to redraw the map and panics.  since
+                * the whole reason for dismissing the other windows was to
+                * leave the ending window on the screen, we don't want to
+                * erase it anyway.
+                */
+               erase_menu_or_text(window, cw, FALSE);
+           }
+           cw->active = 0;
+       }
+       break;
+    }
+    cw->flags = 0;
+}
+
+void
+tty_destroy_nhwindow(window)
+    winid window;
+{
+    register struct WinDesc *cw = 0;
+
+    if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
+       panic(winpanicstr,  window);
+
+    if(cw->active)
+       tty_dismiss_nhwindow(window);
+    if(cw->type == NHW_MESSAGE)
+       iflags.window_inited = 0;
+    if(cw->type == NHW_MAP)
+       clear_screen();
+
+    free_window_info(cw, TRUE);
+    free((genericptr_t)cw);
+    wins[window] = 0;
+}
+
+void
+tty_curs(window, x, y)
+winid window;
+register int x, y;     /* not xchar: perhaps xchar is unsigned and
+                          curx-x would be unsigned as well */
+{
+    struct WinDesc *cw = 0;
+    int cx = ttyDisplay->curx;
+    int cy = ttyDisplay->cury;
+
+    if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
+       panic(winpanicstr,  window);
+    ttyDisplay->lastwin = window;
+
+#if defined(USE_TILES) && defined(MSDOS)
+    adjust_cursor_flags(cw);
+#endif
+    cw->curx = --x;    /* column 0 is never used */
+    cw->cury = y;
+#ifdef DEBUG
+    if(x<0 || y<0 || y >= cw->rows || x > cw->cols) {
+       const char *s = "[unknown type]";
+       switch(cw->type) {
+       case NHW_MESSAGE: s = "[topl window]"; break;
+       case NHW_STATUS: s = "[status window]"; break;
+       case NHW_MAP: s = "[map window]"; break;
+       case NHW_MENU: s = "[corner window]"; break;
+       case NHW_TEXT: s = "[text window]"; break;
+       case NHW_BASE: s = "[base window]"; break;
+       }
+       impossible("bad curs positioning win %d %s (%d,%d)", window, s, x, y);
+       return;
+    }
+#endif
+    x += cw->offx;
+    y += cw->offy;
+
+#ifdef CLIPPING
+    if(clipping && window == WIN_MAP) {
+       x -= clipx;
+       y -= clipy;
+    }
+#endif
+
+    if (y == cy && x == cx)
+       return;
+
+    if(cw->type == NHW_MAP)
+       end_glyphout();
+
+#ifndef NO_TERMS
+    if(!nh_ND && (cx != x || x <= 3)) { /* Extremely primitive */
+       cmov(x, y); /* bunker!wtm */
+       return;
+    }
+#endif
+
+    if((cy -= y) < 0) cy = -cy;
+    if((cx -= x) < 0) cx = -cx;
+    if(cy <= 3 && cx <= 3) {
+       nocmov(x, y);
+#ifndef NO_TERMS
+    } else if ((x <= 3 && cy <= 3) || (!nh_CM && x < cx)) {
+       (void) putchar('\r');
+       ttyDisplay->curx = 0;
+       nocmov(x, y);
+    } else if (!nh_CM) {
+       nocmov(x, y);
+#endif
+    } else
+       cmov(x, y);
+
+    ttyDisplay->curx = x;
+    ttyDisplay->cury = y;
+}
+
+STATIC_OVL void
+tty_putsym(window, x, y, ch)
+    winid window;
+    int x, y;
+    char ch;
+{
+    register struct WinDesc *cw = 0;
+
+    if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
+       panic(winpanicstr,  window);
+
+    switch(cw->type) {
+    case NHW_STATUS:
+    case NHW_MAP:
+    case NHW_BASE:
+       tty_curs(window, x, y);
+       (void) putchar(ch);
+       ttyDisplay->curx++;
+       cw->curx++;
+       break;
+    case NHW_MESSAGE:
+    case NHW_MENU:
+    case NHW_TEXT:
+       impossible("Can't putsym to window type %d", cw->type);
+       break;
+    }
+}
+
+
+STATIC_OVL const char*
+compress_str(str)
+const char *str;
+{
+       static char cbuf[BUFSZ];
+       /* compress in case line too long */
+       if((int)strlen(str) >= CO) {
+               register const char *bp0 = str;
+               register char *bp1 = cbuf;
+
+               do {
+#ifdef CLIPPING
+                       if(*bp0 != ' ' || bp0[1] != ' ')
+#else
+                       if(*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ')
+#endif
+                               *bp1++ = *bp0;
+               } while(*bp0++);
+       } else
+           return str;
+       return cbuf;
+}
+
+void
+tty_putstr(window, attr, str)
+    winid window;
+    int attr;
+    const char *str;
+{
+    register struct WinDesc *cw = 0;
+    register char *ob;
+    register const char *nb;
+    register int i, j, n0;
+
+    /* Assume there's a real problem if the window is missing --
+     * probably a panic message
+     */
+    if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) {
+       tty_raw_print(str);
+       return;
+    }
+
+    if(str == (const char*)0 ||
+       ((cw->flags & WIN_CANCELLED) && (cw->type != NHW_MESSAGE)))
+       return;
+    if(cw->type != NHW_MESSAGE)
+       str = compress_str(str);
+
+    ttyDisplay->lastwin = window;
+
+    switch(cw->type) {
+    case NHW_MESSAGE:
+       /* really do this later */
+#if defined(USER_SOUNDS) && defined(WIN32CON)
+       play_sound_for_message(str);
+#endif
+       update_topl(str);
+       break;
+
+    case NHW_STATUS:
+       ob = &cw->data[cw->cury][j = cw->curx];
+       if(flags.botlx) *ob = 0;
+       if(!cw->cury && (int)strlen(str) >= CO) {
+           /* the characters before "St:" are unnecessary */
+           nb = index(str, ':');
+           if(nb && nb > str+2)
+               str = nb - 2;
+       }
+       nb = str;
+       for(i = cw->curx+1, n0 = cw->cols; i < n0; i++, nb++) {
+           if(!*nb) {
+               if(*ob || flags.botlx) {
+                   /* last char printed may be in middle of line */
+                   tty_curs(WIN_STATUS, i, cw->cury);
+                   cl_end();
+               }
+               break;
+           }
+           if(*ob != *nb)
+               tty_putsym(WIN_STATUS, i, cw->cury, *nb);
+           if(*ob) ob++;
+       }
+
+       (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1);
+       cw->data[cw->cury][cw->cols-1] = '\0'; /* null terminate */
+       cw->cury = (cw->cury+1) % 2;
+       cw->curx = 0;
+       break;
+    case NHW_MAP:
+       tty_curs(window, cw->curx+1, cw->cury);
+       term_start_attr(attr);
+       while(*str && (int) ttyDisplay->curx < (int) ttyDisplay->cols-1) {
+           (void) putchar(*str);
+           str++;
+           ttyDisplay->curx++;
+       }
+       cw->curx = 0;
+       cw->cury++;
+       term_end_attr(attr);
+       break;
+    case NHW_BASE:
+       tty_curs(window, cw->curx+1, cw->cury);
+       term_start_attr(attr);
+       while (*str) {
+           if ((int) ttyDisplay->curx >= (int) ttyDisplay->cols-1) {
+               cw->curx = 0;
+               cw->cury++;
+               tty_curs(window, cw->curx+1, cw->cury);
+           }
+           (void) putchar(*str);
+           str++;
+           ttyDisplay->curx++;
+       }
+       cw->curx = 0;
+       cw->cury++;
+       term_end_attr(attr);
+       break;
+    case NHW_MENU:
+    case NHW_TEXT:
+       if(cw->type == NHW_TEXT && cw->cury == ttyDisplay->rows-1) {
+           /* not a menu, so save memory and output 1 page at a time */
+           cw->maxcol = ttyDisplay->cols; /* force full-screen mode */
+           tty_display_nhwindow(window, TRUE);
+           for(i=0; i<cw->maxrow; i++)
+               if(cw->data[i]){
+                   free((genericptr_t)cw->data[i]);
+                   cw->data[i] = 0;
+               }
+           cw->maxrow = cw->cury = 0;
+       }
+       /* always grows one at a time, but alloc 12 at a time */
+       if(cw->cury >= cw->rows) {
+           char **tmp;
+
+           cw->rows += 12;
+           tmp = (char **) alloc(sizeof(char *) * (unsigned)cw->rows);
+           for(i=0; i<cw->maxrow; i++)
+               tmp[i] = cw->data[i];
+           if(cw->data)
+               free((genericptr_t)cw->data);
+           cw->data = tmp;
+
+           for(i=cw->maxrow; i<cw->rows; i++)
+               cw->data[i] = 0;
+       }
+       if(cw->data[cw->cury])
+           free((genericptr_t)cw->data[cw->cury]);
+       n0 = strlen(str) + 1;
+       ob = cw->data[cw->cury] = (char *)alloc((unsigned)n0 + 1);
+       *ob++ = (char)(attr + 1);       /* avoid nuls, for convenience */
+       Strcpy(ob, str);
+
+       if(n0 > cw->maxcol)
+           cw->maxcol = n0;
+       if(++cw->cury > cw->maxrow)
+           cw->maxrow = cw->cury;
+       if(n0 > CO) {
+           /* attempt to break the line */
+           for(i = CO-1; i && str[i] != ' ' && str[i] != '\n';)
+               i--;
+           if(i) {
+               cw->data[cw->cury-1][++i] = '\0';
+               tty_putstr(window, attr, &str[i]);
+           }
+
+       }
+       break;
+    }
+}
+
+void
+tty_display_file(fname, complain)
+const char *fname;
+boolean complain;
+{
+#ifdef DEF_PAGER                       /* this implies that UNIX is defined */
+    {
+       /* use external pager; this may give security problems */
+       register int fd = open(fname, 0);
+
+       if(fd < 0) {
+           if(complain) pline("Cannot open %s.", fname);
+           else docrt();
+           return;
+       }
+       if(child(1)) {
+           /* Now that child() does a setuid(getuid()) and a chdir(),
+              we may not be able to open file fname anymore, so make
+              it stdin. */
+           (void) close(0);
+           if(dup(fd)) {
+               if(complain) raw_printf("Cannot open %s as stdin.", fname);
+           } else {
+               (void) execlp(catmore, "page", (char *)0);
+               if(complain) raw_printf("Cannot exec %s.", catmore);
+           }
+           if(complain) sleep(10); /* want to wait_synch() but stdin is gone */
+           terminate(EXIT_FAILURE);
+       }
+       (void) close(fd);
+    }
+#else  /* DEF_PAGER */
+    {
+       dlb *f;
+       char buf[BUFSZ];
+       char *cr;
+
+       tty_clear_nhwindow(WIN_MESSAGE);
+       f = dlb_fopen(fname, "r");
+       if (!f) {
+           if(complain) {
+               home();  tty_mark_synch();  tty_raw_print("");
+               perror(fname);  tty_wait_synch();
+               pline("Cannot open \"%s\".", fname);
+           } else if(u.ux) docrt();
+       } else {
+           winid datawin = tty_create_nhwindow(NHW_TEXT);
+           boolean empty = TRUE;
+
+           if(complain
+#ifndef NO_TERMS
+               && nh_CD
+#endif
+           ) {
+               /* attempt to scroll text below map window if there's room */
+               wins[datawin]->offy = wins[WIN_STATUS]->offy+3;
+               if((int) wins[datawin]->offy + 12 > (int) ttyDisplay->rows)
+                   wins[datawin]->offy = 0;
+           }
+           while (dlb_fgets(buf, BUFSZ, f)) {
+               if ((cr = index(buf, '\n')) != 0) *cr = 0;
+#ifdef MSDOS
+               if ((cr = index(buf, '\r')) != 0) *cr = 0;
+#endif
+               if (index(buf, '\t') != 0) (void) tabexpand(buf);
+               empty = FALSE;
+               tty_putstr(datawin, 0, buf);
+               if(wins[datawin]->flags & WIN_CANCELLED)
+                   break;
+           }
+           if (!empty) tty_display_nhwindow(datawin, FALSE);
+           tty_destroy_nhwindow(datawin);
+           (void) dlb_fclose(f);
+       }
+    }
+#endif /* DEF_PAGER */
+}
+
+void
+tty_start_menu(window)
+    winid window;
+{
+    tty_clear_nhwindow(window);
+    return;
+}
+
+/*ARGSUSED*/
+/*
+ * Add a menu item to the beginning of the menu list.  This list is reversed
+ * later.
+ */
+void
+tty_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected)
+    winid window;      /* window to use, must be of type NHW_MENU */
+    int glyph;         /* glyph to display with item (unused) */
+    const anything *identifier;        /* what to return if selected */
+    char ch;           /* keyboard accelerator (0 = pick our own) */
+    char gch;          /* group accelerator (0 = no group) */
+    int attr;          /* attribute for string (like tty_putstr()) */
+    const char *str;   /* menu string */
+    boolean preselected; /* item is marked as selected */
+{
+    register struct WinDesc *cw = 0;
+    tty_menu_item *item;
+    const char *newstr;
+    char buf[4+BUFSZ];
+
+    if (str == (const char*) 0)
+       return;
+
+    if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0
+               || cw->type != NHW_MENU)
+       panic(winpanicstr,  window);
+
+    cw->nitems++;
+    if (identifier->a_void) {
+       int len = strlen(str);
+       if (len >= BUFSZ) {
+           /* We *think* everything's coming in off at most BUFSZ bufs... */
+           impossible("Menu item too long (%d).", len);
+           len = BUFSZ - 1;
+       }
+       Sprintf(buf, "%c - ", ch ? ch : '?');
+       (void) strncpy(buf+4, str, len);
+       buf[4+len] = '\0';
+       newstr = buf;
+    } else
+       newstr = str;
+
+    item = (tty_menu_item *) alloc(sizeof(tty_menu_item));
+    item->identifier = *identifier;
+    item->count = -1L;
+    item->selected = preselected;
+    item->selector = ch;
+    item->gselector = gch;
+    item->attr = attr;
+    item->str = copy_of(newstr);
+
+    item->next = cw->mlist;
+    cw->mlist = item;
+}
+
+/* Invert the given list, can handle NULL as an input. */
+STATIC_OVL tty_menu_item *
+reverse(curr)
+    tty_menu_item *curr;
+{
+    tty_menu_item *next, *head = 0;
+
+    while (curr) {
+       next = curr->next;
+       curr->next = head;
+       head = curr;
+       curr = next;
+    }
+    return head;
+}
+
+/*
+ * End a menu in this window, window must a type NHW_MENU.  This routine
+ * processes the string list.  We calculate the # of pages, then assign
+ * keyboard accelerators as needed.  Finally we decide on the width and
+ * height of the window.
+ */
+void
+tty_end_menu(window, prompt)
+    winid window;      /* menu to use */
+    const char *prompt;        /* prompt to for menu */
+{
+    struct WinDesc *cw = 0;
+    tty_menu_item *curr;
+    short len;
+    int lmax, n;
+    char menu_ch;
+
+    if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 ||
+               cw->type != NHW_MENU)
+       panic(winpanicstr,  window);
+
+    /* Reverse the list so that items are in correct order. */
+    cw->mlist = reverse(cw->mlist);
+
+    /* Put the promt at the beginning of the menu. */
+    if (prompt) {
+       anything any;
+
+       any.a_void = 0; /* not selectable */
+       tty_add_menu(window, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
+       tty_add_menu(window, NO_GLYPH, &any, 0, 0, ATR_NONE, prompt, MENU_UNSELECTED);
+    }
+
+    lmax = min(52, (int)ttyDisplay->rows - 1);         /* # lines per page */
+    cw->npages = (cw->nitems + (lmax - 1)) / lmax;     /* # of pages */
+
+    /* make sure page list is large enough */
+    if (cw->plist_size < cw->npages+1 /*need 1 slot beyond last*/) {
+       if (cw->plist) free((genericptr_t)cw->plist);
+       cw->plist_size = cw->npages + 1;
+       cw->plist = (tty_menu_item **)
+                       alloc(cw->plist_size * sizeof(tty_menu_item *));
+    }
+
+    cw->cols = 0; /* cols is set when the win is initialized... (why?) */
+    menu_ch = '?';     /* lint suppression */
+    for (n = 0, curr = cw->mlist; curr; n++, curr = curr->next) {
+       /* set page boundaries and character accelerators */
+       if ((n % lmax) == 0) {
+           menu_ch = 'a';
+           cw->plist[n/lmax] = curr;
+       }
+       if (curr->identifier.a_void && !curr->selector) {
+           curr->str[0] = curr->selector = menu_ch;
+           if (menu_ch++ == 'z') menu_ch = 'A';
+       }
+
+       /* cut off any lines that are too long */
+       len = strlen(curr->str) + 2;    /* extra space at beg & end */
+       if (len > (int)ttyDisplay->cols) {
+           curr->str[ttyDisplay->cols-2] = 0;
+           len = ttyDisplay->cols;
+       }
+       if (len > cw->cols) cw->cols = len;
+    }
+    cw->plist[cw->npages] = 0; /* plist terminator */
+
+    /*
+     * If greater than 1 page, morestr is "(x of y) " otherwise, "(end) "
+     */
+    if (cw->npages > 1) {
+       char buf[QBUFSZ];
+       /* produce the largest demo string */
+       Sprintf(buf, "(%d of %d) ", cw->npages, cw->npages);
+       len = strlen(buf);
+       cw->morestr = copy_of("");
+    } else {
+       cw->morestr = copy_of("(end) ");
+       len = strlen(cw->morestr);
+    }
+
+    if (len > (int)ttyDisplay->cols) {
+       /* truncate the prompt if its too long for the screen */
+       if (cw->npages <= 1)    /* only str in single page case */
+           cw->morestr[ttyDisplay->cols] = 0;
+       len = ttyDisplay->cols;
+    }
+    if (len > cw->cols) cw->cols = len;
+
+    cw->maxcol = cw->cols;
+
+    /*
+     * The number of lines in the first page plus the morestr will be the
+     * maximum size of the window.
+     */
+    if (cw->npages > 1)
+       cw->maxrow = cw->rows = lmax + 1;
+    else
+       cw->maxrow = cw->rows = cw->nitems + 1;
+}
+
+int
+tty_select_menu(window, how, menu_list)
+    winid window;
+    int how;
+    menu_item **menu_list;
+{
+    register struct WinDesc *cw = 0;
+    tty_menu_item *curr;
+    menu_item *mi;
+    int n, cancelled;
+
+    if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0
+       || cw->type != NHW_MENU)
+       panic(winpanicstr,  window);
+
+    *menu_list = (menu_item *) 0;
+    cw->how = (short) how;
+    morc = 0;
+    tty_display_nhwindow(window, TRUE);
+    cancelled = !!(cw->flags & WIN_CANCELLED);
+    tty_dismiss_nhwindow(window);      /* does not destroy window data */
+
+    if (cancelled) {
+       n = -1;
+    } else {
+       for (n = 0, curr = cw->mlist; curr; curr = curr->next)
+           if (curr->selected) n++;
+    }
+
+    if (n > 0) {
+       *menu_list = (menu_item *) alloc(n * sizeof(menu_item));
+       for (mi = *menu_list, curr = cw->mlist; curr; curr = curr->next)
+           if (curr->selected) {
+               mi->item = curr->identifier;
+               mi->count = curr->count;
+               mi++;
+           }
+    }
+
+    return n;
+}
+
+/* special hack for treating top line --More-- as a one item menu */
+char
+tty_message_menu(let, how, mesg)
+char let;
+int how;
+const char *mesg;
+{
+    /* "menu" without selection; use ordinary pline, no more() */
+    if (how == PICK_NONE) {
+       pline("%s", mesg);
+       return 0;
+    }
+
+    ttyDisplay->dismiss_more = let;
+    morc = 0;
+    /* barebones pline(); since we're only supposed to be called after
+       response to a prompt, we'll assume that the display is up to date */
+    tty_putstr(WIN_MESSAGE, 0, mesg);
+    /* if `mesg' didn't wrap (triggering --More--), force --More-- now */
+    if (ttyDisplay->toplin == 1) {
+       more();
+       ttyDisplay->toplin = 1; /* more resets this */
+       tty_clear_nhwindow(WIN_MESSAGE);
+    }
+    /* normally <ESC> means skip further messages, but in this case
+       it means cancel the current prompt; any other messages should
+       continue to be output normally */
+    wins[WIN_MESSAGE]->flags &= ~WIN_CANCELLED;
+    ttyDisplay->dismiss_more = 0;
+
+    return ((how == PICK_ONE && morc == let) || morc == '\033') ? morc : '\0';
+}
+
+void
+tty_update_inventory()
+{
+    return;
+}
+
+void
+tty_mark_synch()
+{
+    (void) fflush(stdout);
+}
+
+void
+tty_wait_synch()
+{
+    /* we just need to make sure all windows are synch'd */
+    if(!ttyDisplay || ttyDisplay->rawprint) {
+       getret();
+       if(ttyDisplay) ttyDisplay->rawprint = 0;
+    } else {
+       tty_display_nhwindow(WIN_MAP, FALSE);
+       if(ttyDisplay->inmore) {
+           addtopl("--More--");
+           (void) fflush(stdout);
+       } else if(ttyDisplay->inread > program_state.gameover) {
+           /* this can only happen if we were reading and got interrupted */
+           ttyDisplay->toplin = 3;
+           /* do this twice; 1st time gets the Quit? message again */
+           (void) tty_doprev_message();
+           (void) tty_doprev_message();
+           ttyDisplay->intr++;
+           (void) fflush(stdout);
+       }
+    }
+}
+
+void
+docorner(xmin, ymax)
+    register int xmin, ymax;
+{
+    register int y;
+    register struct WinDesc *cw = wins[WIN_MAP];
+
+    if (u.uswallow) {  /* Can be done more efficiently */
+       swallowed(1);
+       return;
+    }
+
+#if defined(SIGWINCH) && defined(CLIPPING)
+    if(ymax > LI) ymax = LI;           /* can happen if window gets smaller */
+#endif
+    for (y = 0; y < ymax; y++) {
+       tty_curs(BASE_WINDOW, xmin,y);  /* move cursor */
+       cl_end();                       /* clear to end of line */
+#ifdef CLIPPING
+       if (y<(int) cw->offy || y+clipy > ROWNO)
+               continue; /* only refresh board */
+#if defined(USE_TILES) && defined(MSDOS)
+       if (iflags.tile_view)
+               row_refresh((xmin/2)+clipx-((int)cw->offx/2),COLNO-1,y+clipy-(int)cw->offy);
+       else
+#endif
+       row_refresh(xmin+clipx-(int)cw->offx,COLNO-1,y+clipy-(int)cw->offy);
+#else
+       if (y<cw->offy || y > ROWNO) continue; /* only refresh board  */
+       row_refresh(xmin-(int)cw->offx,COLNO-1,y-(int)cw->offy);
+#endif
+    }
+
+    end_glyphout();
+    if (ymax >= (int) wins[WIN_STATUS]->offy) {
+                                       /* we have wrecked the bottom line */
+       flags.botlx = 1;
+       bot();
+    }
+}
+
+void
+end_glyphout()
+{
+#if defined(ASCIIGRAPH) && !defined(NO_TERMS)
+    if (GFlag) {
+       GFlag = FALSE;
+       graph_off();
+    }
+#endif
+#ifdef TEXTCOLOR
+    if(ttyDisplay->color != NO_COLOR) {
+       term_end_color();
+       ttyDisplay->color = NO_COLOR;
+    }
+#endif
+}
+
+#ifndef WIN32
+void
+g_putch(in_ch)
+int in_ch;
+{
+    register char ch = (char)in_ch;
+
+# if defined(ASCIIGRAPH) && !defined(NO_TERMS)
+    if (iflags.IBMgraphics || iflags.eight_bit_tty) {
+       /* IBM-compatible displays don't need other stuff */
+       (void) putchar(ch);
+    } else if (ch & 0x80) {
+       if (!GFlag || HE_resets_AS) {
+           graph_on();
+           GFlag = TRUE;
+       }
+       (void) putchar((ch ^ 0x80)); /* Strip 8th bit */
+    } else {
+       if (GFlag) {
+           graph_off();
+           GFlag = FALSE;
+       }
+       (void) putchar(ch);
+    }
+
+#else
+    (void) putchar(ch);
+
+#endif /* ASCIIGRAPH && !NO_TERMS */
+
+    return;
+}
+#endif /* !WIN32 */
+
+#ifdef CLIPPING
+void
+setclipped()
+{
+       clipping = TRUE;
+       clipx = clipy = 0;
+       clipxmax = CO;
+       clipymax = LI - 3;
+}
+
+void
+tty_cliparound(x, y)
+int x, y;
+{
+       extern boolean restoring;
+       int oldx = clipx, oldy = clipy;
+
+       if (!clipping) return;
+       if (x < clipx + 5) {
+               clipx = max(0, x - 20);
+               clipxmax = clipx + CO;
+       }
+       else if (x > clipxmax - 5) {
+               clipxmax = min(COLNO, clipxmax + 20);
+               clipx = clipxmax - CO;
+       }
+       if (y < clipy + 2) {
+               clipy = max(0, y - (clipymax - clipy) / 2);
+               clipymax = clipy + (LI - 3);
+       }
+       else if (y > clipymax - 2) {
+               clipymax = min(ROWNO, clipymax + (clipymax - clipy) / 2);
+               clipy = clipymax - (LI - 3);
+       }
+       if (clipx != oldx || clipy != oldy) {
+           if (on_level(&u.uz0, &u.uz) && !restoring)
+               (void) doredraw();
+       }
+}
+#endif /* CLIPPING */
+
+
+/*
+ *  tty_print_glyph
+ *
+ *  Print the glyph to the output device.  Don't flush the output device.
+ *
+ *  Since this is only called from show_glyph(), it is assumed that the
+ *  position and glyph are always correct (checked there)!
+ */
+
+void
+tty_print_glyph(window, x, y, glyph)
+    winid window;
+    xchar x, y;
+    int glyph;
+{
+    int ch;
+    boolean reverse_on = FALSE;
+    int            color;
+    unsigned special;
+    
+#ifdef CLIPPING
+    if(clipping) {
+       if(x <= clipx || y < clipy || x >= clipxmax || y >= clipymax)
+           return;
+    }
+#endif
+    /* map glyph to character and color */
+    mapglyph(glyph, &ch, &color, &special, x, y);
+
+    /* Move the cursor. */
+    tty_curs(window, x,y);
+
+#ifndef NO_TERMS
+    if (ul_hack && ch == '_') {                /* non-destructive underscore */
+       (void) putchar((char) ' ');
+       backsp();
+    }
+#endif
+
+#ifdef TEXTCOLOR
+    if (color != ttyDisplay->color) {
+       if(ttyDisplay->color != NO_COLOR)
+           term_end_color();
+       ttyDisplay->color = color;
+       if(color != NO_COLOR)
+           term_start_color(color);
+    }
+#endif /* TEXTCOLOR */
+
+    /* must be after color check; term_end_color may turn off inverse too */
+    if (((special & MG_PET) && iflags.hilite_pet) ||
+       ((special & MG_DETECT) && iflags.use_inverse)) {
+       term_start_attr(ATR_INVERSE);
+       reverse_on = TRUE;
+    }
+
+#if defined(USE_TILES) && defined(MSDOS)
+    if (iflags.grmode && iflags.tile_view)
+      xputg(glyph,ch,special);
+    else
+#endif
+       g_putch(ch);            /* print the character */
+
+    if (reverse_on) {
+       term_end_attr(ATR_INVERSE);
+#ifdef TEXTCOLOR
+       /* turn off color as well, ATR_INVERSE may have done this already */
+       if(ttyDisplay->color != NO_COLOR) {
+           term_end_color();
+           ttyDisplay->color = NO_COLOR;
+       }
+#endif
+    }
+
+    wins[window]->curx++;      /* one character over */
+    ttyDisplay->curx++;                /* the real cursor moved too */
+}
+
+void
+tty_raw_print(str)
+    const char *str;
+{
+    if(ttyDisplay) ttyDisplay->rawprint++;
+#if defined(MICRO) || defined(WIN32CON)
+    msmsg("%s\n", str);
+#else
+    puts(str); (void) fflush(stdout);
+#endif
+}
+
+void
+tty_raw_print_bold(str)
+    const char *str;
+{
+    if(ttyDisplay) ttyDisplay->rawprint++;
+    term_start_raw_bold();
+#if defined(MICRO) || defined(WIN32CON)
+    msmsg("%s", str);
+#else
+    (void) fputs(str, stdout);
+#endif
+    term_end_raw_bold();
+#if defined(MICRO) || defined(WIN32CON)
+    msmsg("\n");
+#else
+    puts("");
+    (void) fflush(stdout);
+#endif
+}
+
+int
+tty_nhgetch()
+{
+    int i;
+#ifdef UNIX
+    /* kludge alert: Some Unix variants return funny values if getc()
+     * is called, interrupted, and then called again.  There
+     * is non-reentrant code in the internal _filbuf() routine, called by
+     * getc().
+     */
+    static volatile int nesting = 0;
+    char nestbuf;
+#endif
+
+    (void) fflush(stdout);
+    /* Note: if raw_print() and wait_synch() get called to report terminal
+     * initialization problems, then wins[] and ttyDisplay might not be
+     * available yet.  Such problems will probably be fatal before we get
+     * here, but validate those pointers just in case...
+     */
+    if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE])
+           wins[WIN_MESSAGE]->flags &= ~WIN_STOP;
+#ifdef UNIX
+    i = ((++nesting == 1) ? tgetch() :
+        (read(fileno(stdin), (genericptr_t)&nestbuf,1) == 1 ? (int)nestbuf :
+                                                               EOF));
+    --nesting;
+#else
+    i = tgetch();
+#endif
+    if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
+    if (ttyDisplay && ttyDisplay->toplin == 1)
+       ttyDisplay->toplin = 2;
+    return i;
+}
+
+/*
+ * return a key, or 0, in which case a mouse button was pressed
+ * mouse events should be returned as character postitions in the map window.
+ * Since normal tty's don't have mice, just return a key.
+ */
+/*ARGSUSED*/
+int
+tty_nh_poskey(x, y, mod)
+    int *x, *y, *mod;
+{
+# if defined(WIN32CON)
+    int i;
+    (void) fflush(stdout);
+    /* Note: if raw_print() and wait_synch() get called to report terminal
+     * initialization problems, then wins[] and ttyDisplay might not be
+     * available yet.  Such problems will probably be fatal before we get
+     * here, but validate those pointers just in case...
+     */
+    if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE])
+           wins[WIN_MESSAGE]->flags &= ~WIN_STOP;
+    i = ntposkey(x, y, mod);
+    if (!i && mod && *mod == 0)
+       i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
+    if (ttyDisplay && ttyDisplay->toplin == 1)
+               ttyDisplay->toplin = 2;
+    return i;
+# else
+    return tty_nhgetch();
+# endif
+}
+
+void
+win_tty_init()
+{
+# if defined(WIN32CON)
+    nttty_open();
+# endif
+    return;
+}
+
+#ifdef POSITIONBAR
+void
+tty_update_positionbar(posbar)
+char *posbar;
+{
+# ifdef MSDOS
+       video_update_positionbar(posbar);
+# endif
+}
+#endif
+
+/*
+ * Allocate a copy of the given string.  If null, return a string of
+ * zero length.
+ *
+ * This is an exact duplicate of copy_of() in X11/winmenu.c.
+ */
+static char *
+copy_of(s)
+    const char *s;
+{
+    if (!s) s = "";
+    return strcpy((char *) alloc((unsigned) (strlen(s) + 1)), s);
+}
+
+#endif /* TTY_GRAPHICS */
+
+/*wintty.c*/
diff --git a/win/win32/dgncomp.dsp b/win/win32/dgncomp.dsp
new file mode 100644 (file)
index 0000000..815384c
--- /dev/null
@@ -0,0 +1,297 @@
+# Microsoft Developer Studio Project File - Name="dgncomp" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=dgncomp - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "dgncomp.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "dgncomp.mak" CFG="dgncomp - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "dgncomp - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "dgncomp - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "dgncomp - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "..\util"\r
+# PROP BASE Intermediate_Dir "dgncomp___Win32_Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\util"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"\r
+# ADD RSC /l 0x1009 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\dgn_comp.exe"\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=dgncomp\r
+PostBuild_Cmds=echo Building dungeon   echo chdir ..\dat       chdir ..\dat    echo ..\util\dgn_comp.exe dungeon.pdf   ..\util\dgn_comp.exe dungeon.pdf        echo chdir ..\build     chdir ..\build\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "dgncomp - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "dgncomp___Win32_Debug"\r
+# PROP BASE Intermediate_Dir "dgncomp___Win32_Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\util"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"\r
+# ADD RSC /l 0x1009 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"..\util\dgn_comp.exe" /pdbtype:sept\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=dgncomp\r
+PostBuild_Cmds=echo Building dungeon   echo chdir ..\dat       chdir ..\dat    echo ..\util\dgn_comp.exe dungeon.pdf   ..\util\dgn_comp.exe dungeon.pdf        echo chdir ..\build     chdir ..\build\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "dgncomp - Win32 Release"\r
+# Name "dgncomp - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\src\alloc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\dgn_lex.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\dgn_main.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\dgn_yacc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\panic.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\align.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\attrib.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\color.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config1.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\coord.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\decl.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dgn_comp.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dgn_file.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\display.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dungeon.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\engrave.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\flag.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\global.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mkroom.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monattk.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monst.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monsym.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\nhlan.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\ntconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\obj.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\objclass.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\onames.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\permonst.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\pm.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\prop.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\quest.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\rect.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\region.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\rm.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\skills.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\spell.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\timeout.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tradstdc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\trampoli.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\trap.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\vision.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\winprocs.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wintty.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wintype.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\you.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\youprop.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/win32/dgnstuff.dsp b/win/win32/dgnstuff.dsp
new file mode 100644 (file)
index 0000000..ab1e95a
--- /dev/null
@@ -0,0 +1,97 @@
+# Microsoft Developer Studio Project File - Name="dgnstuff" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) External Target" 0x0106\r
+\r
+CFG=dgnstuff - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "dgnstuff.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "dgnstuff.mak" CFG="dgnstuff - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "dgnstuff - Win32 Release" (based on "Win32 (x86) External Target")\r
+!MESSAGE "dgnstuff - Win32 Debug" (based on "Win32 (x86) External Target")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+\r
+!IF  "$(CFG)" == "dgnstuff - Win32 Release"\r
+\r
+# PROP BASE Use_MFC\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Cmd_Line "NMAKE /f dgnstuff.mak"\r
+# PROP BASE Rebuild_Opt "/a"\r
+# PROP BASE Target_File "dgnstuff.exe"\r
+# PROP BASE Bsc_Name "dgnstuff.bsc"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Cmd_Line "nmake /f "dgnstuff.mak""\r
+# PROP Rebuild_Opt "/a"\r
+# PROP Target_File "..\util\dgncomp.exe"\r
+# PROP Bsc_Name ""\r
+# PROP Target_Dir ""\r
+\r
+!ELSEIF  "$(CFG)" == "dgnstuff - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Cmd_Line "NMAKE /f dgnstuff.mak"\r
+# PROP BASE Rebuild_Opt "/a"\r
+# PROP BASE Target_File "dgnstuff.exe"\r
+# PROP BASE Bsc_Name "dgnstuff.bsc"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "dgnstuff___Win32_Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Cmd_Line "nmake /f "dgnstuff.mak""\r
+# PROP Rebuild_Opt "/a"\r
+# PROP Target_File "..\util\dgncomp.exe"\r
+# PROP Bsc_Name ""\r
+# PROP Target_Dir ""\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "dgnstuff - Win32 Release"\r
+# Name "dgnstuff - Win32 Debug"\r
+\r
+!IF  "$(CFG)" == "dgnstuff - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "dgnstuff - Win32 Debug"\r
+\r
+!ENDIF \r
+\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/win32/dgnstuff.mak b/win/win32/dgnstuff.mak
new file mode 100644 (file)
index 0000000..8e5aa81
--- /dev/null
@@ -0,0 +1,59 @@
+#Set all of these or none of them
+#YACC   = byacc.exe
+#LEX   = flex.exe
+#YTABC   = y_tab.c
+#YTABH   = y_tab.h
+#LEXYYC  = lexyy.c
+
+!IF "$(YACC)"!=""
+@echo Yacc-alike set to $(YACC)
+@echo YTABC set to $(YTABC)
+@echo YTABH set to $(YTABH)
+!ENDIF
+
+!IF "$(LEX)"!=""
+@echo Lex-alike set to $(LEX)
+@echo LEXYYC set to $(LEXYYC)
+!ENDIF
+
+default: all
+
+all: ..\util\dgn_yacc.c ..\util\dgn_lex.c
+
+rebuild: clean all
+
+clean:
+       -del ..\util\dgn_lex.c
+       -del ..\util\dgn_yacc.c
+       -del ..\include\dgn_comp.h
+
+#==========================================
+# Dungeon Compiler Stuff
+#==========================================
+
+..\util\dgn_yacc.c ..\include\dgn_comp.h : ..\util\dgn_comp.y
+!IF "$(YACC)"==""
+          @echo Using pre-built dgn_yacc.c and dgn_comp.h
+          @copy ..\sys\share\dgn_yacc.c ..\util\dgn_yacc.c
+          @copy ..\sys\share\dgn_comp.h ..\include\dgn_comp.h
+!ELSE
+          chdir ..\util
+          $(YACC) -d dgn_comp.y
+          copy $(YTABC) $@
+          copy $(YTABH) ..\include\dgn_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+          chdir ..\build
+!ENDIF
+
+..\util\dgn_lex.c: ..\util\dgn_comp.l
+!IF "$(LEX)"==""
+          @echo Using pre-built dgn_lex.c
+          @copy ..\sys\share\dgn_lex.c $@
+!ELSE
+          chdir ..\util
+          $(LEX) dgn_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+          chdir ..\build
+!ENDIF
diff --git a/win/win32/dlb_main.dsp b/win/win32/dlb_main.dsp
new file mode 100644 (file)
index 0000000..8dff70f
--- /dev/null
@@ -0,0 +1,179 @@
+# Microsoft Developer Studio Project File - Name="dlb_main" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=dlb_main - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "dlb_main.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "dlb_main.mak" CFG="dlb_main - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "dlb_main - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "dlb_main - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "dlb_main - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /I "..\win\share" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "DLB" /D "WIN32CON" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"\r
+# ADD RSC /l 0x1009 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\dlb_main.exe"\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Packaging via DLB\r
+PostBuild_Cmds=echo chdir ..\dat       \\r
+chdir ..\dat   \\r
+chdir  \\r
+ echo data >dlb.lst    \\r
+ echo oracles >>dlb.lst        \\r
+ if exist options echo options >>dlb.lst       \\r
+ if exist ttyoptions echo ttyoptions >>dlb.lst \\r
+ if exist guioptions echo guioptions >>dlb.lst \\r
+ if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp     \\r
+ if exist porthelp echo porthelp >>dlb.lst     \\r
+ echo quest.dat >>dlb.lst      \\r
+ echo rumors >>dlb.lst \\r
+ echo help >>dlb.lst   \\r
+ echo hh >>dlb.lst     \\r
+ echo cmdhelp >>dlb.lst        \\r
+ echo history >>dlb.lst        \\r
+ echo opthelp >>dlb.lst        \\r
+ echo wizhelp >>dlb.lst        \\r
+ echo dungeon >>dlb.lst        \\r
+ echo license >>dlb.lst        \\r
+ for %%N in (*.lev) do echo %%N >>dlb.lst      \\r
+ ..\util\dlb_main.exe cIf dlb.lst nhdat        \\r
+ echo chdir ..\build   \\r
+chdir ..\build \\r
+echo if NOT exist ..\binary\*.* mkdir ..\binary        \\r
+ if NOT exist ..\binary\*.* mkdir ..\binary\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "dlb_main - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt" /I "..\win\share" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "DLB" /D "WIN32CON" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"\r
+# ADD RSC /l 0x1009 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"..\util\dlb_main.exe" /pdbtype:sept\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Packaging via dlb\r
+PostBuild_Cmds=echo chdir ..\dat       \\r
+chdir ..\dat   \\r
+chdir  \\r
+ echo data >dlb.lst    \\r
+ echo oracles >>dlb.lst        \\r
+ if exist options echo options >>dlb.lst       \\r
+ if exist ttyoptions echo ttyoptions >>dlb.lst \\r
+ if exist guioptions echo guioptions >>dlb.lst \\r
+ if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp     \\r
+ if exist porthelp echo porthelp >>dlb.lst     \\r
+ echo quest.dat >>dlb.lst      \\r
+ echo rumors >>dlb.lst \\r
+ echo help >>dlb.lst   \\r
+ echo hh >>dlb.lst     \\r
+ echo cmdhelp >>dlb.lst        \\r
+ echo history >>dlb.lst        \\r
+ echo opthelp >>dlb.lst        \\r
+ echo wizhelp >>dlb.lst        \\r
+ echo dungeon >>dlb.lst        \\r
+ echo license >>dlb.lst        \\r
+ for %%N in (*.lev) do echo %%N >>dlb.lst      \\r
+ ..\util\dlb_main.exe cIf dlb.lst nhdat        \\r
+echo chdir ..\build    \\r
+chdir ..\build \\r
+echo if NOT exist ..\binary\*.* mkdir ..\binary        \\r
+if NOT exist ..\binary\*.* mkdir ..\binary\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "dlb_main - Win32 Release"\r
+# Name "dlb_main - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\src\alloc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dlb.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\dlb_main.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\panic.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dlb.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/win32/levcomp.dsp b/win/win32/levcomp.dsp
new file mode 100644 (file)
index 0000000..7c1486e
--- /dev/null
@@ -0,0 +1,198 @@
+# Microsoft Developer Studio Project File - Name="levcomp" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=levcomp - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "levcomp.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "levcomp.mak" CFG="levcomp - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "levcomp - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "levcomp - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "levcomp - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\util"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"\r
+# ADD RSC /l 0x1009 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=levcomp\r
+PostBuild_Cmds=echo Building special levels    echo chdir ..\dat       chdir ..\dat     \\r
+echo arch.des  ..\util\levcomp.exe arch.des     \\r
+echo barb.des  ..\util\levcomp.exe barb.des     \\r
+echo bigroom.des       ..\util\levcomp.exe bigroom.des  \\r
+echo castle.des        ..\util\levcomp.exe castle.des   \\r
+echo caveman.des       ..\util\levcomp.exe caveman.des  \\r
+echo endgame.des       ..\util\levcomp.exe endgame.des  \\r
+echo gehennom.des      ..\util\levcomp.exe gehennom.des         \\r
+echo healer.des        ..\util\levcomp.exe healer.des   \\r
+echo knight.des        ..\util\levcomp.exe knight.des   \\r
+echo knox.des  ..\util\levcomp.exe knox.des     \\r
+echo medusa.des        ..\util\levcomp.exe medusa.des   \\r
+echo mines.des ..\util\levcomp.exe mines.des    \\r
+echo monk.des  ..\util\levcomp.exe monk.des     \\r
+echo oracle.des        ..\util\levcomp.exe oracle.des   \\r
+echo priest.des        ..\util\levcomp.exe priest.des   \\r
+echo ranger.des        ..\util\levcomp.exe ranger.des   \\r
+echo rogue.des ..\util\levcomp.exe rogue.des    \\r
+echo samurai.des       ..\util\levcomp.exe samurai.des  \\r
+echo sokoban.des       ..\util\levcomp.exe sokoban.des  \\r
+echo tourist.des       ..\util\levcomp.exe tourist.des  \\r
+echo tower.des ..\util\levcomp.exe tower.des    \\r
+echo valkyrie.des      ..\util\levcomp.exe valkyrie.des         \\r
+echo wizard .des       ..\util\levcomp.exe wizard.des   \\r
+echo yendor.des        ..\util\levcomp.exe yendor.des   \\r
+echo chdir ..\build    chdir ..\build\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "levcomp - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\util"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"\r
+# ADD RSC /l 0x1009 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /pdbtype:sept\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=levcomp\r
+PostBuild_Cmds=echo Building special levels    echo chdir ..\dat       chdir ..\dat     \\r
+echo arch.des  ..\util\levcomp.exe arch.des     \\r
+echo barb.des  ..\util\levcomp.exe barb.des     \\r
+echo bigroom.des       ..\util\levcomp.exe bigroom.des  \\r
+echo castle.des        ..\util\levcomp.exe castle.des   \\r
+echo caveman.des       ..\util\levcomp.exe caveman.des  \\r
+echo endgame.des       ..\util\levcomp.exe endgame.des  \\r
+echo gehennom.des      ..\util\levcomp.exe gehennom.des         \\r
+echo healer.des        ..\util\levcomp.exe healer.des   \\r
+echo knight.des        ..\util\levcomp.exe knight.des   \\r
+echo knox.des  ..\util\levcomp.exe knox.des     \\r
+echo medusa.des        ..\util\levcomp.exe medusa.des   \\r
+echo mines.des ..\util\levcomp.exe mines.des    \\r
+echo monk.des  ..\util\levcomp.exe monk.des     \\r
+echo oracle.des        ..\util\levcomp.exe oracle.des   \\r
+echo priest.des        ..\util\levcomp.exe priest.des   \\r
+echo ranger.des        ..\util\levcomp.exe ranger.des   \\r
+echo rogue.des ..\util\levcomp.exe rogue.des    \\r
+echo samurai.des       ..\util\levcomp.exe samurai.des  \\r
+echo sokoban.des       ..\util\levcomp.exe sokoban.des  \\r
+echo tourist.des       ..\util\levcomp.exe tourist.des  \\r
+echo tower.des ..\util\levcomp.exe tower.des    \\r
+echo valkyrie.des      ..\util\levcomp.exe valkyrie.des         \\r
+echo wizard .des       ..\util\levcomp.exe wizard.des   \\r
+echo yendor.des        ..\util\levcomp.exe yendor.des   \\r
+echo chdir ..\build    chdir ..\build\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "levcomp - Win32 Release"\r
+# Name "levcomp - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\src\alloc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\decl.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\drawing.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\lev_lex.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\lev_main.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\lev_yacc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\monst.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\objects.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\util\panic.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\lev_comp.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/win32/levstuff.dsp b/win/win32/levstuff.dsp
new file mode 100644 (file)
index 0000000..276ad81
--- /dev/null
@@ -0,0 +1,97 @@
+# Microsoft Developer Studio Project File - Name="levstuff" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) External Target" 0x0106\r
+\r
+CFG=levstuff - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "levstuff.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "levstuff.mak" CFG="levstuff - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "levstuff - Win32 Release" (based on "Win32 (x86) External Target")\r
+!MESSAGE "levstuff - Win32 Debug" (based on "Win32 (x86) External Target")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+\r
+!IF  "$(CFG)" == "levstuff - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Cmd_Line "NMAKE /f levstuff.mak"\r
+# PROP BASE Rebuild_Opt "/a"\r
+# PROP BASE Target_File "levstuff.exe"\r
+# PROP BASE Bsc_Name "levstuff.bsc"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Cmd_Line "nmake /f "levstuff.mak""\r
+# PROP Rebuild_Opt "/a"\r
+# PROP Target_File "..\util\lev_lex.c"\r
+# PROP Bsc_Name ""\r
+# PROP Target_Dir ""\r
+\r
+!ELSEIF  "$(CFG)" == "levstuff - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "levstuff___Win32_Debug0"\r
+# PROP BASE Intermediate_Dir "levstuff___Win32_Debug0"\r
+# PROP BASE Cmd_Line "NMAKE /f levstuff.mak"\r
+# PROP BASE Rebuild_Opt "/a"\r
+# PROP BASE Target_File "levstuff.exe"\r
+# PROP BASE Bsc_Name "levstuff.bsc"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "levstuff___Win32_Debug0"\r
+# PROP Intermediate_Dir "levstuff___Win32_Debug0"\r
+# PROP Cmd_Line "nmake /f "levstuff.mak""\r
+# PROP Rebuild_Opt "/a"\r
+# PROP Target_File "..\util\lev_lex.c"\r
+# PROP Bsc_Name ""\r
+# PROP Target_Dir ""\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "levstuff - Win32 Release"\r
+# Name "levstuff - Win32 Debug"\r
+\r
+!IF  "$(CFG)" == "levstuff - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "levstuff - Win32 Debug"\r
+\r
+!ENDIF \r
+\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/win32/levstuff.mak b/win/win32/levstuff.mak
new file mode 100644 (file)
index 0000000..c7540c4
--- /dev/null
@@ -0,0 +1,59 @@
+#YACC   = byacc.exe
+#LEX   = flex.exe
+#YTABC   = y_tab.c
+#YTABH   = y_tab.h
+#LEXYYC  = lexyy.c
+
+!IF "$(YACC)"!=""
+@echo Yacc-alike set to $(YACC)
+@echo YTABC set to $(YTABC)
+@echo YTABH set to $(YTABH)
+!ENDIF
+
+!IF "$(LEX)"!=""
+@echo Lex-alike set to $(LEX)
+@echo LEXYYC set to $(LEXYYC)
+!ENDIF
+
+
+default: all
+
+all: ..\util\lev_yacc.c ..\util\lev_lex.c
+
+rebuild: clean all
+
+clean:
+       -del ..\util\lev_lex.c
+       -del ..\util\lev_yacc.c
+       -del ..\include\lev_comp.h
+
+#==========================================
+# Level Compiler Stuff
+#==========================================
+..\util\lev_yacc.c ..\include\lev_comp.h: ..\util\lev_comp.y
+!IF "$(YACC)"==""
+          @echo Using pre-built lev_yacc.c and lev_comp.h
+          @copy ..\sys\share\lev_yacc.c ..\util\lev_yacc.c
+          @copy ..\sys\share\lev_comp.h ..\include\lev_comp.h
+!ELSE
+          chdir ..\util
+          $(YACC) -d lev_comp.y
+          copy $(YTABC) $@
+          copy $(YTABH) ..\include\lev_comp.h
+          @del $(YTABC)
+          @del $(YTABH)
+          chdir ..\build
+!ENDIF
+
+..\util\lev_lex.c: ..\util\lev_comp.l
+!IF "$(LEX)"==""
+          @echo Using pre-built lev_lex.c
+          @copy ..\sys\share\lev_lex.c $@
+!ELSE
+          chdir ..\util
+          $(LEX) lev_comp.l
+          copy $(LEXYYC) $@
+          @del $(LEXYYC)
+          chdir ..\build
+!ENDIF
+
diff --git a/win/win32/makedefs.dsp b/win/win32/makedefs.dsp
new file mode 100644 (file)
index 0000000..5ecdc88
--- /dev/null
@@ -0,0 +1,198 @@
+# Microsoft Developer Studio Project File - Name="makedefs" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=makedefs - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "makedefs.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "makedefs.mak" CFG="makedefs - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "makedefs - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "makedefs - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "makedefs - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\util"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "." /I "..\include" /I "..\sys\winnt" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Running makedefs\r
+PostBuild_Cmds=echo chdir ..\util      chdir ..\util   chdir   \\r
+echo makedefs.exe -v   makedefs.exe -v \\r
+echo makedefs.exe -o   makedefs.exe  -o        \\r
+echo makedefs.exe -p   makedefs.exe -p \\r
+echo makedefs.exe -m   makedefs.exe -m \\r
+echo makedefs.exe -z   makedefs.exe -z \\r
+echo chdir ..\dat      chdir ..\dat    chdir   \\r
+echo Generating NetHack database       echo ..\util\makedefs.exe -d    ..\util\makedefs.exe -d \\r
+echo Generating rumors echo ..\util\makedefs.exe -r    ..\util\makedefs.exe -r \\r
+echo Generating quests echo ..\util\makedefs.exe -q    ..\util\makedefs.exe -q \\r
+echo Generating oracles        echo ..\util\makedefs.exe -h    ..\util\makedefs.exe -h \\r
+echo Generating dungeon.pdf    echo ..\util\makedefs.exe -e    ..\util\makedefs.exe -e \\r
+echo chdir ..\build    chdir ..\build  \\r
+copy ..\win\share\tilemap.c ..\win\share\tiletxt.c\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "makedefs - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\util"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "." /I "..\include" /I "..\sys\winnt" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /pdbtype:sept\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Running makedefs\r
+PostBuild_Cmds=echo chdir ..\util      chdir ..\util   chdir   \\r
+echo makedefs.exe -v   makedefs.exe -v \\r
+echo makedefs.exe -o   makedefs.exe  -o        \\r
+echo makedefs.exe -p   makedefs.exe -p \\r
+echo makedefs.exe -m   makedefs.exe -m \\r
+echo makedefs.exe -z   makedefs.exe -z \\r
+echo chdir ..\dat      chdir ..\dat    chdir   \\r
+echo Generating NetHack database       echo ..\util\makedefs.exe -d    ..\util\makedefs.exe -d \\r
+echo Generating rumors echo ..\util\makedefs.exe -r    ..\util\makedefs.exe -r \\r
+echo Generating quests echo ..\util\makedefs.exe -q    ..\util\makedefs.exe -q \\r
+echo Generating oracles        echo ..\util\makedefs.exe -h    ..\util\makedefs.exe -h \\r
+echo Generating dungeon.pdf    echo ..\util\makedefs.exe -e    ..\util\makedefs.exe -e \\r
+echo chdir ..\build    chdir ..\build  \\r
+copy ..\win\share\tilemap.c ..\win\share\tiletxt.c\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "makedefs - Win32 Release"\r
+# Name "makedefs - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\util\makedefs.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\monst.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\objects.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config1.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\coord.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\global.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monattk.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monflag.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monsym.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\nhlan.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\ntconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\objclass.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\patchlevel.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\qtext.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tradstdc.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/win32/mhaskyn.c b/win/win32/mhaskyn.c
new file mode 100644 (file)
index 0000000..81be133
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include <assert.h>
+#include "winMS.h"
+#include "mhaskyn.h"
+
+int mswin_yes_no_dialog( const char *question, const char *choices, int def)
+{
+       return '\032';
+}
diff --git a/win/win32/mhaskyn.h b/win/win32/mhaskyn.h
new file mode 100644 (file)
index 0000000..a386b09
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINAskYesNO_h
+#define MSWINAskYesNO_h
+
+#include "winMS.h"
+
+int mswin_yes_no_dialog( const char *question, const char *choices, int def);
+
+#endif /* MSWINAskYesNO_h */
diff --git a/win/win32/mhdlg.c b/win/win32/mhdlg.c
new file mode 100644 (file)
index 0000000..f4593bb
--- /dev/null
@@ -0,0 +1,758 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* various dialog boxes are defined here */
+
+#include "winMS.h"
+#include "hack.h"
+#include "func_tab.h"
+#include "resource.h"
+#include "mhdlg.h"
+
+/*---------------------------------------------------------------*/
+/* data for getlin dialog */
+struct getlin_data {
+       const char*     question;
+       char*           result;
+       size_t          result_size;
+};
+
+BOOL CALLBACK  GetlinDlgProc(HWND, UINT, WPARAM, LPARAM);
+
+int mswin_getlin_window (
+       const char *question, 
+       char *result, 
+       size_t result_size
+)
+{
+       int ret;
+       struct getlin_data data;
+
+       /* initilize dialog data */
+       ZeroMemory(&data, sizeof(data));
+       data.question = question;
+       data.result = result;
+       data.result_size = result_size;
+
+       /* create modal dialog window */
+       ret = DialogBoxParam(
+                       GetNHApp()->hApp,
+                       MAKEINTRESOURCE(IDD_GETLIN),
+                       GetNHApp()->hMainWnd,
+                       GetlinDlgProc,
+                       (LPARAM)&data
+       );
+       if( ret==-1 ) panic("Cannot create getlin window");
+       
+       return ret;
+}
+    
+BOOL CALLBACK GetlinDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       struct getlin_data* data;
+       RECT   main_rt, dlg_rt;
+       SIZE   dlg_sz;
+       TCHAR  wbuf[BUFSZ];
+       HDC WindowDC;
+       HWND ControlHWND;
+       SIZE   WindowExtents;
+       SIZE   ViewPortExtents;
+       RECT   ControlRect;
+       RECT   ClientRect;
+       LONG   Division;
+       LONG   ButtonOffset;
+
+       switch (message) 
+       {
+       case WM_INITDIALOG:
+               data = (struct getlin_data*)lParam;
+               SetWindowText(hWnd, NH_A2W(data->question, wbuf, sizeof(wbuf)));
+               SetWindowLong(hWnd, GWL_USERDATA, lParam);
+
+               /* center dialog in the main window */
+               GetWindowRect(hWnd, &dlg_rt);
+               GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
+               WindowDC = GetWindowDC(hWnd);
+
+               if (!GetWindowExtEx(WindowDC, &WindowExtents) ||
+                       !GetViewportExtEx(WindowDC, &ViewPortExtents) ||
+                       !GetTextExtentPoint32(GetWindowDC (hWnd), wbuf, _tcslen(wbuf), &dlg_sz))
+               {
+                       dlg_sz.cx = 0;
+               }
+               else
+               {
+                       /* I think we need to do the following scaling */
+                       dlg_sz.cx *= ViewPortExtents.cx; dlg_sz.cx /= WindowExtents.cx;
+                       /* Add the size of the various items in the caption bar */
+                       dlg_sz.cx += GetSystemMetrics(SM_CXSIZE) +
+                               2 * (GetSystemMetrics (SM_CXBORDER) + GetSystemMetrics(SM_CXFRAME));
+               }
+
+               if (dlg_sz.cx < dlg_rt.right - dlg_rt.left)
+                       dlg_sz.cx = dlg_rt.right - dlg_rt.left;
+               dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
+               dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2;
+               dlg_rt.right = dlg_rt.left + dlg_sz.cx;
+               dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2;
+               dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
+               MoveWindow( hWnd,
+                                       (main_rt.left+main_rt.right-dlg_sz.cx)/2,
+                                       (main_rt.top+main_rt.bottom-dlg_sz.cy)/2,
+                                       dlg_sz.cx,
+                                       dlg_sz.cy,
+                                       TRUE );
+
+               /* set focus and size of the edit control */
+               ControlHWND = GetDlgItem(hWnd, IDC_GETLIN_EDIT);
+               SetFocus(ControlHWND);
+               GetClientRect (hWnd, &ClientRect);
+               GetWindowRect (ControlHWND, &ControlRect);
+               MoveWindow (ControlHWND, 0, 0,
+                       ClientRect.right - ClientRect.left,
+                       ControlRect.bottom - ControlRect.top, TRUE);
+               ButtonOffset = ControlRect.bottom - ControlRect.top;
+
+               /* Now get the OK and CANCEL buttons */
+               ControlHWND = GetDlgItem(hWnd, IDOK);
+               GetWindowRect (ControlHWND, &ControlRect);
+               Division = ((ClientRect.right - ClientRect.left) -
+                       2 * (ControlRect.right - ControlRect.left)) / 3;
+               MoveWindow (ControlHWND, Division,
+                       ButtonOffset,
+                       ControlRect.right - ControlRect.left,
+                       ControlRect.bottom - ControlRect.top, TRUE);
+               ControlHWND = GetDlgItem(hWnd, IDCANCEL);
+               MoveWindow (ControlHWND,
+                       Division * 2 + ControlRect.right - ControlRect.left,
+                       ButtonOffset,
+                       ControlRect.right - ControlRect.left,
+                       ControlRect.bottom - ControlRect.top, TRUE);
+
+               /* tell windows that we've set the focus */
+               return FALSE; 
+       break;
+
+       case WM_COMMAND: 
+       {
+               TCHAR wbuf[BUFSZ];
+
+               switch (LOWORD(wParam)) 
+        { 
+                       /* OK button was pressed */
+                       case IDOK:
+                     data = (struct getlin_data*)GetWindowLong(hWnd, GWL_USERDATA);
+                         SendDlgItemMessage(hWnd, IDC_GETLIN_EDIT, WM_GETTEXT, (WPARAM)sizeof(wbuf), (LPARAM)wbuf );
+                         NH_W2A(wbuf, data->result, data->result_size);
+
+                         /* Fall through. */
+
+                       /* cancel button was pressed */
+                       case IDCANCEL: 
+                               EndDialog(hWnd, wParam); 
+                       return TRUE;
+               }
+       } break;
+       
+       } /* end switch (message) */
+       return FALSE;
+}
+
+
+/*---------------------------------------------------------------*/
+/* dialog data for the list of extended commands */
+struct extcmd_data {
+       int*            selection;
+};
+
+BOOL CALLBACK  ExtCmdDlgProc(HWND, UINT, WPARAM, LPARAM);
+
+int mswin_ext_cmd_window (int* selection)
+{
+       int ret;
+       struct extcmd_data data;
+       
+       /* init dialog data */
+       ZeroMemory(&data, sizeof(data));
+       *selection = -1;
+       data.selection = selection;
+
+       /* create modal dialog window */
+       ret = DialogBoxParam(
+                       GetNHApp()->hApp,
+                       MAKEINTRESOURCE(IDD_EXTCMD),
+                       GetNHApp()->hMainWnd,
+                       ExtCmdDlgProc,
+                       (LPARAM)&data
+       );
+       if( ret==-1 ) panic("Cannot create extcmd window");
+       return ret;
+}
+    
+BOOL CALLBACK ExtCmdDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       struct extcmd_data* data;
+       RECT   main_rt, dlg_rt;
+       SIZE   dlg_sz;
+       int    i;
+       const char *ptr;
+       TCHAR wbuf[255];
+
+       switch (message) 
+       {
+       case WM_INITDIALOG:
+               data = (struct extcmd_data*)lParam;
+               SetWindowLong(hWnd, GWL_USERDATA, lParam);
+
+               /* center dialog in the main window */
+               GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
+               GetWindowRect(hWnd, &dlg_rt);
+               dlg_sz.cx = dlg_rt.right - dlg_rt.left;
+               dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
+
+               dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2;
+               dlg_rt.right = dlg_rt.left + dlg_sz.cx;
+               dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2;
+               dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
+               MoveWindow( hWnd,
+                                       (main_rt.left+main_rt.right-dlg_sz.cx)/2,
+                                       (main_rt.top+main_rt.bottom-dlg_sz.cy)/2,
+                                       dlg_sz.cx,
+                                       dlg_sz.cy,
+                                       TRUE );
+
+               /* fill combobox with extended commands */
+               for(i=0; (ptr=extcmdlist[i].ef_txt); i++) {
+                       SendDlgItemMessage(hWnd, IDC_EXTCMD_LIST, LB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(ptr, wbuf, sizeof(wbuf)) );
+               }
+
+               /* set focus to the list control */
+               SetFocus(GetDlgItem(hWnd, IDC_EXTCMD_LIST));
+
+               /* tell windows we set the focus */
+               return FALSE;
+       break;
+
+       case WM_COMMAND:
+        data = (struct extcmd_data*)GetWindowLong(hWnd, GWL_USERDATA);
+               switch (LOWORD(wParam)) 
+        { 
+                 /* OK button ws clicked */
+          case IDOK:
+                         *data->selection = SendDlgItemMessage(hWnd, IDC_EXTCMD_LIST, LB_GETCURSEL, (WPARAM)0, (LPARAM)0 );
+                         if( *data->selection==LB_ERR )
+                                 *data->selection = -1;
+                         /* Fall through. */
+
+                 /* CANCEL button ws clicked */
+                 case IDCANCEL:
+                               EndDialog(hWnd, wParam); 
+                 return TRUE;
+
+                 /* list control events */
+                 case IDC_EXTCMD_LIST:
+                               switch(HIWORD(wParam)) {
+
+                               case LBN_DBLCLK: 
+                                 /* double click within the list 
+                                        wParam 
+                                          The low-order word is the list box identifier. 
+                                          The high-order word is the notification message. 
+                                        lParam 
+                                          Handle to the list box
+                                       */
+                                  *data->selection = SendMessage((HWND)lParam, LB_GETCURSEL, (WPARAM)0, (LPARAM)0);
+                                  if( *data->selection==LB_ERR )
+                                          *data->selection = -1;
+                                  EndDialog(hWnd, IDOK); 
+                              return TRUE;
+                               }
+                 break;
+               }
+       }
+       return FALSE;
+}
+
+/*---------------------------------------------------------------*/
+/* player selector dialog data */
+struct plsel_data {
+       int*    selection;
+};
+
+BOOL CALLBACK  PlayerSelectorDlgProc(HWND, UINT, WPARAM, LPARAM);
+static void            plselInitDialog(HWND hWnd);
+static void                    plselAdjustLists(HWND hWnd, int changed_opt);
+static int                     plselFinalSelection(HWND hWnd, int* selection);
+
+int mswin_player_selection_window ( int* selection )
+{
+       int ret;
+       struct plsel_data data;
+
+       /* init dialog data */
+       ZeroMemory(&data, sizeof(data));
+       data.selection = selection;
+
+       /* create modal dialog */
+       ret = DialogBoxParam(
+                       GetNHApp()->hApp,
+                       MAKEINTRESOURCE(IDD_PLAYER_SELECTOR),
+                       GetNHApp()->hMainWnd,
+                       PlayerSelectorDlgProc,
+                       (LPARAM)&data
+       );
+       if( ret==-1 ) panic("Cannot create getlin window");
+       
+       return ret;
+}
+
+BOOL CALLBACK PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       struct plsel_data* data;
+       RECT   main_rt, dlg_rt;
+       SIZE   dlg_sz;
+
+       switch (message) 
+       {
+       case WM_INITDIALOG:
+               data = (struct plsel_data*)lParam;
+               SetWindowLong(hWnd, GWL_USERDATA, lParam);
+
+               /* center dialog in the main window */
+               GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
+               GetWindowRect(hWnd, &dlg_rt);
+               dlg_sz.cx = dlg_rt.right - dlg_rt.left;
+               dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
+
+               dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2;
+               dlg_rt.right = dlg_rt.left + dlg_sz.cx;
+               dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2;
+               dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
+               MoveWindow( hWnd,
+                                       (main_rt.left+main_rt.right-dlg_sz.cx)/2,
+                                       (main_rt.top+main_rt.bottom-dlg_sz.cy)/2,
+                                       dlg_sz.cx,
+                                       dlg_sz.cy,
+                                       TRUE );
+
+               /* init dialog */
+               plselInitDialog(hWnd);
+
+               /* set focus on the role checkbox (random) field */
+               SetFocus(GetDlgItem(hWnd, IDC_PLSEL_ROLE_RANDOM));
+
+               /* tell windows we set the focus */
+               return FALSE;
+       break;
+
+       case WM_COMMAND:
+        data = (struct plsel_data*)GetWindowLong(hWnd, GWL_USERDATA);
+               switch (LOWORD(wParam)) { 
+
+               /* OK button was clicked */
+               case IDOK:
+                       if( plselFinalSelection(hWnd, data->selection) ) {
+                               EndDialog(hWnd, wParam); 
+                       } else {
+                               NHMessageBox(hWnd, TEXT("Cannot match this role. Try something else."), MB_ICONSTOP | MB_OK );
+                       }
+               return TRUE;
+
+               /* CANCEL button was clicked */
+               case IDCANCEL:
+                       *data->selection = -1;
+                       EndDialog(hWnd, wParam); 
+               return TRUE;
+
+               /* following are events from dialog controls: 
+                  "random" checkboxes send BN_CLICKED messages;
+                  role/race/... combo-boxes send CBN_SELENDOK 
+                  if something was selected;
+               */
+               case IDC_PLSEL_ROLE_RANDOM:
+                       if( HIWORD(wParam)==BN_CLICKED ) {
+                               /* enable corresponding list window if "random"
+                                  checkbox was "unchecked" */
+                               EnableWindow(
+                                       GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), 
+                                       SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED
+                                 );
+                       }
+               break;
+
+               case IDC_PLSEL_RACE_RANDOM:
+                       if( HIWORD(wParam)==BN_CLICKED ) {
+                               EnableWindow(
+                                       GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), 
+                                       SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED
+                                 );
+                       }
+               break;
+
+               case IDC_PLSEL_GENDER_RANDOM:
+                       if( HIWORD(wParam)==BN_CLICKED ) {
+                               EnableWindow(
+                                       GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), 
+                                       SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED
+                                 );
+                       }
+               break;
+
+               case IDC_PLSEL_ALIGN_RANDOM:
+                       if( HIWORD(wParam)==BN_CLICKED ) {
+                               EnableWindow(
+                                       GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), 
+                                       SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED
+                                 );
+                       }
+               break;
+
+               case IDC_PLSEL_ROLE_LIST:
+                       if( HIWORD(wParam)==CBN_SELENDOK ) {
+                               /* filter out invalid options if 
+                                  the selection was made */
+                               plselAdjustLists( hWnd, LOWORD(wParam) );
+                       }
+               break;
+
+               case IDC_PLSEL_RACE_LIST:
+                       if( HIWORD(wParam)==CBN_SELENDOK ) {
+                               plselAdjustLists( hWnd, LOWORD(wParam) );
+                       }
+               break;
+
+               case IDC_PLSEL_GENDER_LIST:
+                       if( HIWORD(wParam)==CBN_SELENDOK ) {
+                               plselAdjustLists( hWnd, LOWORD(wParam) );
+                       }
+               break;
+
+               case IDC_PLSEL_ALIGN_LIST:
+                       if( HIWORD(wParam)==CBN_SELENDOK ) {
+                               plselAdjustLists( hWnd, LOWORD(wParam) );
+                       }
+               break;
+               }
+       break;
+       }
+       return FALSE;
+}
+
+void setComboBoxValue(HWND hWnd, int combo_box, int value)
+{
+       int index_max = SendDlgItemMessage(hWnd, combo_box, CB_GETCOUNT, 0, 0);
+       int index;
+       int value_to_set = LB_ERR;
+       for (index = 0; index < index_max; index++) {
+           if (SendDlgItemMessage(hWnd, combo_box, CB_GETITEMDATA, (WPARAM)index, 0) == value) {
+               value_to_set = index;
+               break;
+           }
+       }
+       SendDlgItemMessage(hWnd, combo_box, CB_SETCURSEL, (WPARAM)value_to_set, 0);
+}
+
+/* initialize player selector dialog */
+void plselInitDialog(HWND hWnd)
+{
+       TCHAR wbuf[BUFSZ];
+
+       /* set player name */
+       SetDlgItemText(hWnd, IDC_PLSEL_NAME, NH_A2W(plname, wbuf, sizeof(wbuf)));
+
+       /* check flags for consistency */
+       if( flags.initrole>=0 ) {
+               if (flags.initrace>=0 && !validrace(flags.initrole, flags.initrace)) {
+                       flags.initrace = ROLE_NONE;
+               }
+
+               if (flags.initgend>=0 && !validgend(flags.initrole, flags.initrace, flags.initgend)) {
+                       flags.initgend = ROLE_NONE;
+               }
+
+               if (flags.initalign>=0 && !validalign(flags.initrole, flags.initrace, flags.initalign)) {
+                       flags.initalign = ROLE_NONE;
+               }
+       }
+
+       /* populate select boxes */
+       plselAdjustLists(hWnd, -1);
+
+       /* intialize roles list */
+       if( flags.initrole<0 || !ok_role(flags.initrole, ROLE_NONE, ROLE_NONE, ROLE_NONE)) {
+               CheckDlgButton(hWnd, IDC_PLSEL_ROLE_RANDOM, BST_CHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), FALSE);
+       } else {
+               CheckDlgButton(hWnd, IDC_PLSEL_ROLE_RANDOM, BST_UNCHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), TRUE);
+               setComboBoxValue(hWnd, IDC_PLSEL_ROLE_LIST, flags.initrole);
+       }
+
+       /* intialize races list */
+       if( flags.initrace<0 || !ok_race(flags.initrole, flags.initrace, ROLE_NONE, ROLE_NONE) ) {
+               CheckDlgButton(hWnd, IDC_PLSEL_RACE_RANDOM, BST_CHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), FALSE);
+       } else {
+               CheckDlgButton(hWnd, IDC_PLSEL_RACE_RANDOM, BST_UNCHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), TRUE);
+               setComboBoxValue(hWnd, IDC_PLSEL_RACE_LIST, flags.initrace);
+       }
+
+       /* intialize genders list */
+       if( flags.initgend<0 || !ok_gend(flags.initrole, flags.initrace, flags.initgend, ROLE_NONE)) {
+               CheckDlgButton(hWnd, IDC_PLSEL_GENDER_RANDOM, BST_CHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), FALSE);
+       } else {
+               CheckDlgButton(hWnd, IDC_PLSEL_GENDER_RANDOM, BST_UNCHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), TRUE);
+               setComboBoxValue(hWnd, IDC_PLSEL_GENDER_LIST, flags.initgend);
+       }
+
+       /* intialize alignments list */
+       if( flags.initalign<0 || !ok_align(flags.initrole, flags.initrace, flags.initgend, flags.initalign) ) {
+               CheckDlgButton(hWnd, IDC_PLSEL_ALIGN_RANDOM, BST_CHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), FALSE);
+       } else {
+               CheckDlgButton(hWnd, IDC_PLSEL_ALIGN_RANDOM, BST_UNCHECKED);
+               EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), TRUE);
+               setComboBoxValue(hWnd, IDC_PLSEL_ALIGN_LIST, flags.initalign);
+       }
+}
+
+/* adjust role/race/alignment/gender list - filter out
+   invalid combinations 
+   changed_sel points to the list where selection occured
+   (-1 if unknown)
+*/
+void  plselAdjustLists(HWND hWnd, int changed_sel)
+{
+       HWND control_role, control_race, control_gender, control_align;
+       int  initrole, initrace, initgend, initalign;
+       int i;
+       int ind;
+       int valid_opt;
+       TCHAR wbuf[255];
+
+       /* get control handles */
+       control_role = GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST);
+       control_race = GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST);
+       control_gender = GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST);
+       control_align = GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST);
+
+       /* get current selections */    
+       ind = SendMessage(control_role, CB_GETCURSEL, 0, 0);
+       initrole = (ind==LB_ERR)? flags.initrole : SendMessage(control_role, CB_GETITEMDATA, ind, 0);
+
+       ind = SendMessage(control_race, CB_GETCURSEL, 0, 0);
+       initrace = (ind==LB_ERR)? flags.initrace : SendMessage(control_race, CB_GETITEMDATA, ind, 0);
+
+       ind = SendMessage(control_gender, CB_GETCURSEL, 0, 0);
+       initgend = (ind==LB_ERR)? flags.initgend : SendMessage(control_gender, CB_GETITEMDATA, ind, 0);
+
+       ind = SendMessage(control_align, CB_GETCURSEL, 0, 0);
+       initalign = (ind==LB_ERR)? flags.initalign : SendMessage(control_align, CB_GETITEMDATA, ind, 0);
+
+       /* intialize roles list */
+       if( changed_sel==-1 ) {
+               valid_opt = 0;
+
+               /* reset content and populate the list */
+               SendMessage(control_role, CB_RESETCONTENT, 0, 0); 
+               for (i = 0; roles[i].name.m; i++) {
+                       if (initgend>=0 && flags.female && roles[i].name.f)
+                               ind = SendMessage(control_role, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(roles[i].name.f, wbuf, sizeof(wbuf)) );
+                       else 
+                               ind = SendMessage(control_role, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(roles[i].name.m, wbuf, sizeof(wbuf)) );
+
+                       SendMessage(control_role, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i );
+                       if( i==initrole ) { 
+                               SendMessage(control_role, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 );
+                               valid_opt = 1;
+                       }
+               }
+               
+               /* set selection to the previously selected role
+                  if it is still valid */
+               if( !valid_opt ) {
+                       initrole = ROLE_NONE;
+                       initrace = ROLE_NONE;
+                       initgend = ROLE_NONE;
+                       initalign = ROLE_NONE;
+                       SendMessage(control_role, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 );
+               }
+
+               /* trigger change of the races list */
+               changed_sel=IDC_PLSEL_ROLE_LIST;
+       }
+
+       /* intialize races list */
+       if( changed_sel==IDC_PLSEL_ROLE_LIST ) {
+               valid_opt = 0;
+
+               /* reset content and populate the list */
+               SendMessage(control_race, CB_RESETCONTENT, 0, 0); 
+               for (i = 0; races[i].noun; i++)
+                       if (ok_race(initrole, i, ROLE_NONE, ROLE_NONE)) {
+                               ind = SendMessage(control_race, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(races[i].noun, wbuf, sizeof(wbuf)) ); 
+                               SendMessage(control_race, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); 
+                               if( i==initrace ) { 
+                                       SendMessage(control_race, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 );
+                                       valid_opt = 1;
+                               }
+                       }
+
+               /* set selection to the previously selected race
+                  if it is still valid */
+               if( !valid_opt ) {
+                       initrace = ROLE_NONE;
+                       initgend = ROLE_NONE;
+                       initalign = ROLE_NONE;
+                       SendMessage(control_race, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 );
+               }
+
+               /* trigger change of the genders list */
+               changed_sel=IDC_PLSEL_RACE_LIST;
+       }
+
+       /* intialize genders list */
+       if( changed_sel==IDC_PLSEL_RACE_LIST ) {
+               valid_opt = 0;
+
+               /* reset content and populate the list */
+               SendMessage(control_gender, CB_RESETCONTENT, 0, 0); 
+               for (i = 0; i < ROLE_GENDERS; i++)
+                       if (ok_gend(initrole, initrace, i, ROLE_NONE)) {
+                               ind = SendMessage(control_gender, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(genders[i].adj, wbuf, sizeof(wbuf)) ); 
+                               SendMessage(control_gender, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); 
+                               if( i==initgend ) { 
+                                       SendMessage(control_gender, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 );
+                                       valid_opt = 1;
+                               }
+                       }
+
+               /* set selection to the previously selected gender
+                  if it is still valid */
+               if( !valid_opt ) {
+                       initgend = ROLE_NONE;
+                       initalign = ROLE_NONE;
+                       SendMessage(control_gender, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 );
+               }
+
+               /* trigger change of the alignments list */
+               changed_sel=IDC_PLSEL_GENDER_LIST;
+       }
+
+       /* intialize alignments list */
+       if( changed_sel==IDC_PLSEL_GENDER_LIST ) {
+               valid_opt = 0;
+
+               /* reset content and populate the list */
+               SendMessage(control_align, CB_RESETCONTENT, 0, 0); 
+               for (i = 0; i < ROLE_ALIGNS; i++)
+                       if (ok_align(initrole, initrace, initgend, i)) {
+                               ind = SendMessage(control_align, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(aligns[i].adj, wbuf, sizeof(wbuf)) ); 
+                               SendMessage(control_align, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); 
+                               if( i==initalign ) { 
+                                       SendMessage(control_align, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 );
+                                       valid_opt = 1;
+                               }
+                       }
+
+               /* set selection to the previously selected alignment
+                  if it is still valid */
+               if( !valid_opt ) {
+                       initalign = ROLE_NONE;
+                       SendMessage(control_align, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 );
+               }
+       }
+}
+
+/* player made up his mind - get final selection here */ 
+int    plselFinalSelection(HWND hWnd, int* selection)
+{
+       int ind;
+
+       /* get current selections */
+       if( SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) {
+               flags.initrole = ROLE_RANDOM;
+       } else {
+               ind = SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_LIST, CB_GETCURSEL, 0, 0);
+               flags.initrole = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_LIST, CB_GETITEMDATA, ind, 0);
+       }
+
+       if( SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) {
+               flags.initrace = ROLE_RANDOM;
+       } else {
+               ind = SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_LIST, CB_GETCURSEL, 0, 0);
+               flags.initrace = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_LIST, CB_GETITEMDATA, ind, 0);
+       }
+
+       if( SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) {
+               flags.initgend = ROLE_RANDOM;
+       } else {
+               ind = SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_LIST, CB_GETCURSEL, 0, 0);
+               flags.initgend = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_LIST, CB_GETITEMDATA, ind, 0);
+       }
+
+       if( SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) {
+               flags.initalign = ROLE_RANDOM;
+       } else {
+               ind = SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_LIST, CB_GETCURSEL, 0, 0);
+               flags.initalign = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_LIST, CB_GETITEMDATA, ind, 0);
+       }
+       
+
+       /* check the role */
+       if( flags.initrole==ROLE_RANDOM ) {
+               flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM);
+               if (flags.initrole < 0) {
+                       NHMessageBox(hWnd, TEXT("Incompatible role!"), MB_ICONSTOP | MB_OK);
+                       return FALSE;
+               }
+       }
+
+       /* Select a race, if necessary */
+       /* force compatibility with role */
+       if (flags.initrace==ROLE_RANDOM || !validrace(flags.initrole, flags.initrace)) {
+               /* pre-selected race not valid */
+               if (flags.initrace == ROLE_RANDOM) {
+                       flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM);
+               }
+               
+               if (flags.initrace < 0) {
+                       NHMessageBox(hWnd, TEXT("Incompatible race!"), MB_ICONSTOP | MB_OK);
+                       return FALSE;
+               }
+       }
+
+       /* Select a gender, if necessary */
+       /* force compatibility with role/race, try for compatibility with
+        * pre-selected alignment */
+       if (flags.initgend < 0 || 
+               !validgend(flags.initrole, flags.initrace, flags.initgend)) {
+           /* pre-selected gender not valid */
+           if (flags.initgend == ROLE_RANDOM) {
+                       flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM);
+               }
+               
+               if (flags.initgend < 0) {
+                       NHMessageBox(hWnd, TEXT("Incompatible gender!"), MB_ICONSTOP | MB_OK);
+                       return FALSE;
+               }
+       }
+
+       /* Select an alignment, if necessary */
+       /* force compatibility with role/race/gender */
+       if (flags.initalign < 0 || 
+               !validalign(flags.initrole, flags.initrace,     flags.initalign)) {
+               /* pre-selected alignment not valid */
+               if (flags.initalign == ROLE_RANDOM) {
+                       flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM);
+               } else {
+                       NHMessageBox(hWnd, TEXT("Incompatible alignment!"), MB_ICONSTOP | MB_OK);
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
diff --git a/win/win32/mhdlg.h b/win/win32/mhdlg.h
new file mode 100644 (file)
index 0000000..b964838
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINDlgWindow_h
+#define MSWINDlgWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+int mswin_getlin_window (const char *question, char *result, size_t result_size);
+int mswin_ext_cmd_window (int* selection);
+int  mswin_player_selection_window(int* selection);
+
+#endif /* MSWINDlgWindow_h */
diff --git a/win/win32/mhfont.c b/win/win32/mhfont.c
new file mode 100644 (file)
index 0000000..5f05e76
--- /dev/null
@@ -0,0 +1,205 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* font management and such */
+
+#include "mhfont.h"
+
+#define MAXFONTS       64
+
+/* font table - 64 fonts ought to be enough */
+static struct font_table_entry {
+       int             code;
+       HFONT   hFont;
+} font_table[MAXFONTS] ;
+static int font_table_size = 0;
+HFONT version_splash_font;
+
+#define NHFONT_CODE(win, attr) (((attr&0xFF)<<8)|(win_type&0xFF))
+
+static void __cdecl font_table_cleanup(void);
+
+void mswin_init_splashfonts(HWND hWnd)
+{
+       HDC hdc = GetDC(hWnd);
+       HFONT fnt = NULL;
+       LOGFONT lgfnt;
+       ZeroMemory( &lgfnt, sizeof(lgfnt) );
+       lgfnt.lfHeight          = -80;   // height of font
+       lgfnt.lfWidth           =       0;                                   // average character width
+       lgfnt.lfEscapement      =       0;                                       // angle of escapement
+       lgfnt.lfOrientation             =       0;                                       // base-line orientation angle
+       lgfnt.lfWeight          =       FW_BOLD;   // font weight
+       lgfnt.lfItalic                  =       FALSE;               // italic attribute option
+       lgfnt.lfUnderline               =       FALSE;           // underline attribute option
+       lgfnt.lfStrikeOut               =       FALSE;                       // strikeout attribute option
+       lgfnt.lfCharSet         =       ANSI_CHARSET;     // character set identifier
+       lgfnt.lfOutPrecision    =       OUT_DEFAULT_PRECIS;  // output precision
+       lgfnt.lfClipPrecision   =       CLIP_DEFAULT_PRECIS; // clipping precision
+       lgfnt.lfQuality         =       DEFAULT_QUALITY;     // output quality
+       lgfnt.lfPitchAndFamily  = DEFAULT_PITCH;                 // pitch and family
+       NH_A2W( "Times New Roman", lgfnt.lfFaceName, LF_FACESIZE);
+       version_splash_font = CreateFontIndirect(&lgfnt);
+       ReleaseDC(hWnd, hdc);
+}
+
+void mswin_destroy_splashfonts()
+{
+       DeleteObject (version_splash_font);
+}
+
+/* create font based on window type, charater attributes and
+   window device context */
+HGDIOBJ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace)
+{
+       HFONT fnt = NULL;
+       LOGFONT lgfnt;
+       int font_size;
+       int font_index;
+       static BOOL once = FALSE;
+
+       if( !once ) {
+               once = TRUE;
+               atexit(font_table_cleanup);
+       }
+
+       ZeroMemory( &lgfnt, sizeof(lgfnt) );
+
+       /* try find font in the table */
+       for(font_index=0; font_index<font_table_size; font_index++)
+               if(NHFONT_CODE(win_type, attr)==font_table[font_index].code)
+                       break;
+
+       if( !replace && font_index<font_table_size )
+               return font_table[font_index].hFont;
+
+       switch(win_type) {
+       case NHW_STATUS:
+               lgfnt.lfHeight                  =       -iflags.wc_fontsiz_status*GetDeviceCaps(hdc, LOGPIXELSY)/72;     // height of font
+               lgfnt.lfWidth                   =       0;                                   // average character width
+               lgfnt.lfEscapement              =       0;                                       // angle of escapement
+               lgfnt.lfOrientation             =       0;                                       // base-line orientation angle
+               lgfnt.lfWeight                  =       FW_BOLD;             // font weight
+               lgfnt.lfItalic                  =       FALSE;                   // italic attribute option
+               lgfnt.lfUnderline               =       FALSE;                       // underline attribute option
+               lgfnt.lfStrikeOut               =       FALSE;                       // strikeout attribute option
+               lgfnt.lfCharSet                 =       mswin_charset();     // character set identifier
+               lgfnt.lfOutPrecision    =       OUT_DEFAULT_PRECIS;  // output precision
+               lgfnt.lfClipPrecision   =       CLIP_DEFAULT_PRECIS; // clipping precision
+               lgfnt.lfQuality                 =       DEFAULT_QUALITY;     // output quality
+               if( iflags.wc_font_status &&
+                       *iflags.wc_font_status ) {
+                       lgfnt.lfPitchAndFamily = DEFAULT_PITCH;          // pitch and family
+                       NH_A2W( iflags.wc_font_status, lgfnt.lfFaceName, LF_FACESIZE);
+               } else {
+                       lgfnt.lfPitchAndFamily = FIXED_PITCH;            // pitch and family
+               }
+               break;
+
+       case NHW_MENU:
+               lgfnt.lfHeight                  =       -iflags.wc_fontsiz_menu*GetDeviceCaps(hdc, LOGPIXELSY)/72;       // height of font
+               lgfnt.lfWidth                   =       0;                                   // average character width
+               lgfnt.lfEscapement              =       0;                                       // angle of escapement
+               lgfnt.lfOrientation             =       0;                                       // base-line orientation angle
+               lgfnt.lfWeight                  =       (attr==ATR_BOLD || attr==ATR_INVERSE)? FW_BOLD : FW_NORMAL;   // font weight
+               lgfnt.lfItalic                  =       (attr==ATR_BLINK)? TRUE: FALSE;              // italic attribute option
+               lgfnt.lfUnderline               =       (attr==ATR_ULINE)? TRUE : FALSE;                 // underline attribute option
+               lgfnt.lfStrikeOut               =       FALSE;                          // strikeout attribute option
+               lgfnt.lfCharSet                 =       mswin_charset();     // character set identifier
+               lgfnt.lfOutPrecision    =       OUT_DEFAULT_PRECIS;  // output precision
+               lgfnt.lfClipPrecision   =       CLIP_DEFAULT_PRECIS; // clipping precision
+               lgfnt.lfQuality                 =       DEFAULT_QUALITY;     // output quality
+               if( iflags.wc_font_menu &&
+                       *iflags.wc_font_menu ) {
+                       lgfnt.lfPitchAndFamily  = DEFAULT_PITCH;                 // pitch and family
+                       NH_A2W( iflags.wc_font_menu, lgfnt.lfFaceName, LF_FACESIZE);
+               } else {
+                       lgfnt.lfPitchAndFamily = FIXED_PITCH;            // pitch and family
+               }
+               break;
+
+       case NHW_MESSAGE:
+               font_size = (attr==ATR_INVERSE)? iflags.wc_fontsiz_message+1 : iflags.wc_fontsiz_message;
+               lgfnt.lfHeight                  =       -font_size*GetDeviceCaps(hdc, LOGPIXELSY)/72;    // height of font
+               lgfnt.lfWidth                   =       0;                                   // average character width
+               lgfnt.lfEscapement              =       0;                                       // angle of escapement
+               lgfnt.lfOrientation             =       0;                                       // base-line orientation angle
+               lgfnt.lfWeight                  =       (attr==ATR_BOLD || attr==ATR_INVERSE)? FW_BOLD : FW_NORMAL;   // font weight
+               lgfnt.lfItalic                  =       (attr==ATR_BLINK)? TRUE: FALSE;              // italic attribute option
+               lgfnt.lfUnderline               =       (attr==ATR_ULINE)? TRUE : FALSE;                 // underline attribute option
+               lgfnt.lfStrikeOut               =       FALSE;                       // strikeout attribute option
+               lgfnt.lfCharSet                 =       mswin_charset();     // character set identifier
+               lgfnt.lfOutPrecision    =       OUT_DEFAULT_PRECIS;  // output precision
+               lgfnt.lfClipPrecision   =       CLIP_DEFAULT_PRECIS; // clipping precision
+               lgfnt.lfQuality                 =       DEFAULT_QUALITY;     // output quality
+               if( iflags.wc_font_message &&
+                       *iflags.wc_font_message ) {
+                       lgfnt.lfPitchAndFamily  = DEFAULT_PITCH;                 // pitch and family
+                       NH_A2W( iflags.wc_font_message, lgfnt.lfFaceName, LF_FACESIZE);
+               } else {
+                       lgfnt.lfPitchAndFamily  = VARIABLE_PITCH;                // pitch and family
+               }
+               break;
+
+       case NHW_TEXT:
+               lgfnt.lfHeight                  =       -iflags.wc_fontsiz_text*GetDeviceCaps(hdc, LOGPIXELSY)/72;       // height of font
+               lgfnt.lfWidth                   =       0;                                   // average character width
+               lgfnt.lfEscapement              =       0;                                       // angle of escapement
+               lgfnt.lfOrientation             =       0;                                       // base-line orientation angle
+               lgfnt.lfWeight                  =       (attr==ATR_BOLD || attr==ATR_INVERSE)? FW_BOLD : FW_NORMAL;   // font weight
+               lgfnt.lfItalic                  =       (attr==ATR_BLINK)? TRUE: FALSE;              // italic attribute option
+               lgfnt.lfUnderline               =       (attr==ATR_ULINE)? TRUE : FALSE;                 // underline attribute option
+               lgfnt.lfStrikeOut               =       FALSE;                       // strikeout attribute option
+               lgfnt.lfCharSet                 =       mswin_charset();     // character set identifier
+               lgfnt.lfOutPrecision    =       OUT_DEFAULT_PRECIS;  // output precision
+               lgfnt.lfClipPrecision   =       CLIP_DEFAULT_PRECIS; // clipping precision
+               lgfnt.lfQuality                 =       DEFAULT_QUALITY;     // output quality
+               if( iflags.wc_font_text &&
+                       *iflags.wc_font_text ) {
+                       lgfnt.lfPitchAndFamily  = DEFAULT_PITCH;                 // pitch and family
+                       NH_A2W( iflags.wc_font_text, lgfnt.lfFaceName, LF_FACESIZE);
+               } else {
+                       lgfnt.lfPitchAndFamily  = FIXED_PITCH;           // pitch and family
+               }
+               break;
+       }
+
+       fnt = CreateFontIndirect(&lgfnt);
+
+       /* add font to the table */
+       if( font_index==font_table_size ) {
+               if( font_table_size>=MAXFONTS ) panic( "font table overflow!" );
+               font_table_size++;
+       } else {
+               DeleteObject(font_table[font_index].hFont);
+       }
+
+       font_table[font_index].code = NHFONT_CODE(win_type, attr);
+       font_table[font_index].hFont = fnt;
+       return fnt;
+}
+
+UINT mswin_charset()
+{
+       CHARSETINFO cis;
+       if( iflags.IBMgraphics )
+               if( TranslateCharsetInfo((DWORD*)GetOEMCP(), &cis, TCI_SRCCODEPAGE) ) 
+                       return cis.ciCharset;
+               else
+                       return OEM_CHARSET;
+       else 
+               if( TranslateCharsetInfo((DWORD*)GetACP(), &cis, TCI_SRCCODEPAGE) ) 
+                       return cis.ciCharset;
+               else
+                       return ANSI_CHARSET;
+}
+
+void __cdecl font_table_cleanup(void)
+{
+       int i;
+       for(i=0; i<font_table_size; i++) {
+               DeleteObject(font_table[i].hFont);
+       }
+       font_table_size = 0;
+}
+
diff --git a/win/win32/mhfont.h b/win/win32/mhfont.h
new file mode 100644 (file)
index 0000000..291bfd3
--- /dev/null
@@ -0,0 +1,16 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* font management functions */
+
+#ifndef MSWINFont_h
+#define MSWINFont_h
+
+#include "winMS.h"
+
+HGDIOBJ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace);
+void mswin_init_splashfonts(HWND hWnd);
+void mswin_destroy_splashfonts(void);
+UINT mswin_charset(void);
+
+#endif /* MSWINFont_h */
diff --git a/win/win32/mhinput.c b/win/win32/mhinput.c
new file mode 100644 (file)
index 0000000..77fd5ea
--- /dev/null
@@ -0,0 +1,85 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include <assert.h>
+#include "winMS.h"
+#include "mhinput.h"
+
+/* nethack input queue functions */
+
+#define NH_INPUT_BUFFER_SIZE  64
+
+/* as it stands right now we need only one slot 
+   since events are processed almost the same time as
+   they occur but I like large round numbers */
+
+static MSNHEvent nhi_input_buffer[NH_INPUT_BUFFER_SIZE];
+static int nhi_init_input = 0;
+static int nhi_read_pos = 0;
+static int nhi_write_pos = 0;
+
+/* initialize input queue */
+void mswin_nh_input_init(void)
+{
+       if( !nhi_init_input ) {
+               nhi_init_input = 1;
+
+               ZeroMemory( nhi_input_buffer, sizeof(nhi_input_buffer) );
+               nhi_read_pos = 0;
+               nhi_write_pos = 0;
+       }
+}
+
+/* check for input */
+int    mswin_have_input()
+{
+       return (nhi_read_pos!=nhi_write_pos);
+}
+
+/* add event to the queue */
+void mswin_input_push(PMSNHEvent event)
+{
+       int new_write_pos;
+
+       if( !nhi_init_input ) mswin_nh_input_init();
+
+       new_write_pos = (nhi_write_pos+1) % NH_INPUT_BUFFER_SIZE;
+       
+       if(new_write_pos!=nhi_read_pos) {
+               memcpy(nhi_input_buffer+nhi_write_pos, event, sizeof(*event));
+               nhi_write_pos = new_write_pos;
+       }
+
+}
+
+/* get event from the queue and delete it */
+PMSNHEvent mswin_input_pop()
+{
+       PMSNHEvent retval;
+
+       if( !nhi_init_input ) mswin_nh_input_init();
+
+       if( nhi_read_pos!=nhi_write_pos ) {
+               retval = &nhi_input_buffer[nhi_read_pos];
+               nhi_read_pos = (nhi_read_pos+1) % NH_INPUT_BUFFER_SIZE;
+       } else {
+               retval = NULL;
+       }
+
+       return retval;
+}
+
+/* get event from the queue but leave it there */
+PMSNHEvent mswin_input_peek()
+{
+       PMSNHEvent retval;
+
+       if( !nhi_init_input ) mswin_nh_input_init();
+
+       if( nhi_read_pos!=nhi_write_pos ) {
+               retval = &nhi_input_buffer[nhi_read_pos];
+       } else {
+               retval = NULL;
+       }
+       return retval;
+}
diff --git a/win/win32/mhinput.h b/win/win32/mhinput.h
new file mode 100644 (file)
index 0000000..23ed41b
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINInput_h
+#define MSWINInput_h
+
+/* nethack input queue - store/extract input events */
+#include "winMS.h"
+
+#define NHEVENT_CHAR   1
+#define NHEVENT_MOUSE  2
+typedef struct mswin_event {
+       int type;
+       union {
+               struct {
+                       int  ch;
+               } kbd;
+
+               struct {
+                       int mod;
+                       int x, y;
+               } ms;
+       };
+} MSNHEvent, *PMSNHEvent;
+
+#define NHEVENT_KBD(c) { MSNHEvent e; e.type=NHEVENT_CHAR; e.kbd.ch=(c); mswin_input_push(&e); }
+#define NHEVENT_MS(_mod, _x, _y) { MSNHEvent e; e.type=NHEVENT_MOUSE; e.ms.mod = (_mod); e.ms.x=(_x); e.ms.y=(_y); mswin_input_push(&e); }
+
+void           mswin_nh_input_init(void);
+int                    mswin_have_input(void);
+void           mswin_input_push(PMSNHEvent event);
+PMSNHEvent     mswin_input_pop(void);
+PMSNHEvent     mswin_input_peek(void);
+
+#endif /* MSWINInput_h */
diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c
new file mode 100644 (file)
index 0000000..e05d9e2
--- /dev/null
@@ -0,0 +1,966 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include "patchlevel.h"
+#include "resource.h"
+#include "mhmsg.h"
+#include "mhinput.h"
+#include "mhmain.h"
+#include "mhmenu.h"
+#include "mhstatus.h"
+#include "mhmsgwnd.h"
+#include "mhmap.h"
+
+typedef struct mswin_nethack_main_window {
+       int mapAcsiiModeSave;
+} NHMainWindow, *PNHMainWindow;
+
+static TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass");
+static TCHAR szTitle[MAX_LOADSTRING];
+extern void mswin_display_splash_window(BOOL);
+
+LRESULT CALLBACK       MainWndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK       About(HWND, UINT, WPARAM, LPARAM);
+static LRESULT  onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void            onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void            register_main_window_class(void);
+static int             menuid2mapmode(int menuid);
+static int             mapmode2menuid(int map_mode);
+
+HWND mswin_init_main_window () {
+       static int run_once = 0;
+       HWND ret;
+    WINDOWPLACEMENT wp;
+
+       /* register window class */
+       if( !run_once ) {
+               LoadString(GetNHApp()->hApp, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
+               register_main_window_class( );
+               run_once = 1;
+       }
+       
+       /* create the main window */
+       ret = CreateWindow(
+                       szMainWindowClass,              /* registered class name */
+                       szTitle,                                /* window name */
+                       WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, /* window style */
+                       CW_USEDEFAULT,                  /* horizontal position of window */
+                       CW_USEDEFAULT,                  /* vertical position of window */
+                       CW_USEDEFAULT,                  /* window width */
+                       CW_USEDEFAULT,                  /* window height */
+                       NULL,                                   /* handle to parent or owner window */
+                       NULL,                                   /* menu handle or child identifier */
+                       GetNHApp()->hApp,               /* handle to application instance */
+                       NULL                                    /* window-creation data */
+               );
+
+       if( !ret ) panic("Cannot create main window");
+
+    
+    if (GetNHApp()->regMainMinX != CW_USEDEFAULT)
+    {
+        wp.length = sizeof(wp);
+        wp.showCmd = GetNHApp()->regMainShowState;
+
+        wp.ptMinPosition.x = GetNHApp()->regMainMinX;
+        wp.ptMinPosition.y = GetNHApp()->regMainMinY;
+
+        wp.ptMaxPosition.x = GetNHApp()->regMainMaxX;
+        wp.ptMaxPosition.y = GetNHApp()->regMainMaxY;
+
+        wp.rcNormalPosition.left = GetNHApp()->regMainLeft;
+        wp.rcNormalPosition.top = GetNHApp()->regMainTop;
+        wp.rcNormalPosition.right = GetNHApp()->regMainRight;
+        wp.rcNormalPosition.bottom = GetNHApp()->regMainBottom;
+        SetWindowPlacement(ret, &wp);
+    }
+    else
+        ShowWindow(ret, SW_SHOWDEFAULT);
+    UpdateWindow(ret);
+
+       return ret;
+}
+
+void register_main_window_class()
+{
+       WNDCLASS wcex;
+       
+       ZeroMemory(&wcex, sizeof(wcex));
+       wcex.style                      = CS_HREDRAW | CS_VREDRAW;
+       wcex.lpfnWndProc        = (WNDPROC)MainWndProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = GetNHApp()->hApp;
+       wcex.hIcon                      = LoadIcon(GetNHApp()->hApp, (LPCTSTR)IDI_NETHACKW);
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);
+       wcex.lpszMenuName       = (TCHAR*)IDC_NETHACKW;
+       wcex.lpszClassName      = szMainWindowClass;
+
+       RegisterClass(&wcex);
+}
+
+/*
+ * Keypad keys are translated to the normal values below.
+ * Shifted keypad keys are translated to the
+ *    shift values below.
+ */
+
+enum KEY_INDEXES {
+KEY_NW, KEY_N, KEY_NE, KEY_MINUS,
+KEY_W, KEY_GOINTERESTING, KEY_E, KEY_PLUS,
+KEY_SW, KEY_S, KEY_SE,
+KEY_INV, KEY_WAITLOOK,
+KEY_LAST};
+
+static const unsigned char
+/* normal, shift, control */
+keypad[KEY_LAST][3] = {
+       {'y', 'Y', C('y')}, /* 7 */
+       {'k', 'K', C('k')}, /* 8 */
+       {'u', 'U', C('u')}, /* 9 */
+       {'m', C('p'), C('p')}, /* - */
+       {'h', 'H', C('h')}, /* 4 */
+       {'g', 'G', 'g'}, /* 5 */
+       {'l', 'L', C('l')}, /* 6 */
+       {'+', 'P', C('p')}, /* + */
+       {'b', 'B', C('b')}, /* 1 */
+       {'j', 'J', C('j')}, /* 2 */
+       {'n', 'N', C('n')}, /* 3 */
+       {'i', 'I', C('i')}, /* Ins */
+       {'.', ':', ':'} /* Del */
+}, 
+numpad[KEY_LAST][3] = {
+       {'7', M('7'), '7'}, /* 7 */
+       {'8', M('8'), '8'}, /* 8 */
+       {'9', M('9'), '9'}, /* 9 */
+       {'m', C('p'), C('p')}, /* - */
+       {'4', M('4'), '4'}, /* 4 */
+       {'5', M('5'), '5'}, /* 5 */
+       {'6', M('6'), '6'}, /* 6 */
+       {'+', 'P', C('p')}, /* + */
+       {'1', M('1'), '1'}, /* 1 */
+       {'2', M('2'), '2'}, /* 2 */
+       {'3', M('3'), '3'}, /* 3 */
+       {'0', M('0'), '0'}, /* Ins */
+       {'.', ':', ':'} /* Del */
+};
+
+#define STATEON(x) ((GetKeyState(x) & 0xFFFE) != 0)
+#define KEYTABLE_REGULAR(x) ((iflags.num_pad ? numpad : keypad)[x][0])
+#define KEYTABLE_SHIFT(x) ((iflags.num_pad ? numpad : keypad)[x][1])
+#define KEYTABLE(x) (STATEON(VK_SHIFT) ? KEYTABLE_SHIFT(x) : KEYTABLE_REGULAR(x))
+
+/* map mode macros */
+#define IS_MAP_FIT_TO_SCREEN(mode) ((mode)==MAP_MODE_ASCII_FIT_TO_SCREEN || \
+                                                         (mode)==MAP_MODE_TILES_FIT_TO_SCREEN )
+  
+#define IS_MAP_ASCII(mode) ((mode)!=MAP_MODE_TILES && (mode)!=MAP_MODE_TILES_FIT_TO_SCREEN)
+
+static const char *extendedlist = "acdefijlmnopqrstuvw?2";
+
+#define SCANLO         0x02
+static const char scanmap[] = {        /* ... */
+       '1','2','3','4','5','6','7','8','9','0',0,0,0,0,
+       'q','w','e','r','t','y','u','i','o','p','[',']', '\n',
+       0, 'a','s','d','f','g','h','j','k','l',';','\'', '`',
+       0, '\\', 'z','x','c','v','b','n','m',',','.','?'        /* ... */
+};
+
+/*
+//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
+//
+//  PURPOSE:  Processes messages for the main window.
+*/
+LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       PNHMainWindow data;
+
+       switch (message) 
+       {
+               case WM_CREATE:
+                       /* set window data */
+                       data = (PNHMainWindow)malloc(sizeof(NHMainWindow));
+                       if( !data ) panic("out of memory");
+                       ZeroMemory(data, sizeof(NHMainWindow));
+                       data->mapAcsiiModeSave = MAP_MODE_ASCII12x16;
+                       SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
+
+                       GetNHApp()->hMainWnd = hWnd;
+               break;
+
+               case WM_MSNH_COMMAND:
+                       onMSNHCommand(hWnd, wParam, lParam);
+               break;
+
+        case WM_KEYDOWN: 
+               {
+                       data = (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+                       /* translate arrow keys into nethack commands */
+            switch (wParam) 
+            { 
+                       case VK_LEFT:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window one line left */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_HSCROLL,
+                                               MAKEWPARAM(SB_LINEUP, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_W));
+                               }
+                       return 0;
+
+                       case VK_RIGHT:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window one line right */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_HSCROLL,
+                                               MAKEWPARAM(SB_LINEDOWN, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_E));
+                               }
+                       return 0;
+
+                       case VK_UP:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window one line up */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_VSCROLL,
+                                               MAKEWPARAM(SB_LINEUP, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_N));
+                               }
+                       return 0;
+
+                       case VK_DOWN:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window one line down */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_VSCROLL,
+                                               MAKEWPARAM(SB_LINEDOWN, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_S));
+                               }
+                       return 0;
+
+                       case VK_HOME:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window to upper left corner */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_VSCROLL,
+                                               MAKEWPARAM(SB_THUMBTRACK, 0),
+                                               (LPARAM)NULL
+                                       );
+
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_HSCROLL,
+                                               MAKEWPARAM(SB_THUMBTRACK, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_NW));
+                               }
+                       return 0;
+
+                       case VK_END:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window to lower right corner */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_VSCROLL,
+                                               MAKEWPARAM(SB_THUMBTRACK, ROWNO),
+                                               (LPARAM)NULL
+                                       );
+
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_HSCROLL,
+                                               MAKEWPARAM(SB_THUMBTRACK, COLNO),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_SW));
+                               }
+                       return 0;
+
+                       case VK_PRIOR:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window one page up */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_VSCROLL,
+                                               MAKEWPARAM(SB_PAGEUP, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_NE));
+                               }
+                       return 0;
+
+                       case VK_NEXT:
+                               if( STATEON(VK_CONTROL) ) {
+                                       /* scroll map window one page down */
+                                       SendMessage(
+                                               mswin_hwnd_from_winid(WIN_MAP),
+                                               WM_VSCROLL,
+                                               MAKEWPARAM(SB_PAGEDOWN, 0),
+                                               (LPARAM)NULL
+                                       );
+                               } else {
+                                       NHEVENT_KBD(KEYTABLE(KEY_SE));
+                               }
+                       return 0;
+
+                       case VK_DECIMAL:
+                       case VK_DELETE:
+                               NHEVENT_KBD(KEYTABLE(KEY_WAITLOOK));
+                       return 0;
+
+                       case VK_INSERT:
+                               NHEVENT_KBD(KEYTABLE(KEY_INV));
+                       return 0;
+
+                       case VK_SUBTRACT:
+                               NHEVENT_KBD(KEYTABLE(KEY_MINUS));
+                       return 0;
+
+                       case VK_ADD:
+                               NHEVENT_KBD(KEYTABLE(KEY_PLUS));
+                       return 0;
+
+                       case VK_CLEAR: /* This is the '5' key */
+                               NHEVENT_KBD(KEYTABLE(KEY_GOINTERESTING));
+                       return 0;
+
+                       case VK_F4:
+                               if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
+                                       mswin_select_map_mode(
+                                               IS_MAP_ASCII(iflags.wc_map_mode)? 
+                                                       data->mapAcsiiModeSave :
+                                                       MAP_MODE_TILES
+                                       );
+                               } else {
+                                       mswin_select_map_mode(
+                                               IS_MAP_ASCII(iflags.wc_map_mode)?
+                                                       MAP_MODE_ASCII_FIT_TO_SCREEN :
+                                                       MAP_MODE_TILES_FIT_TO_SCREEN
+                                       );
+                               }
+                       return 0;
+
+                       case VK_F5:
+                               if( IS_MAP_ASCII(iflags.wc_map_mode) ) {
+                                       if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
+                                               mswin_select_map_mode(MAP_MODE_TILES_FIT_TO_SCREEN);
+                                       } else {
+                                               mswin_select_map_mode(MAP_MODE_TILES);
+                                       }
+                               } else {
+                                       if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
+                                               mswin_select_map_mode(MAP_MODE_ASCII_FIT_TO_SCREEN);
+                                       } else {
+                                               mswin_select_map_mode(data->mapAcsiiModeSave);
+                                       }
+                               }
+                       return 0;
+
+                       default: {
+                               WORD c;
+                               BYTE kbd_state[256];
+
+                               c = 0;
+                               ZeroMemory(kbd_state, sizeof(kbd_state));
+                               GetKeyboardState(kbd_state);
+
+                               if( ToAscii( wParam, (lParam>>16)&0xFF, kbd_state, &c, 0) ) {
+                                       NHEVENT_KBD( c&0xFF );
+                                       return 0;
+                               } else {
+                                       return 1;
+                               }
+                       }
+
+                       } /* end switch */
+               } break;
+
+        case WM_SYSCHAR: /* Alt-char pressed */
+        {
+            /*
+              If not nethackmode, don't handle Alt-keys here.
+              If no Alt-key pressed it can never be an extended command 
+            */
+           if (GetNHApp()->regNetHackMode && ((lParam & 1<<29) != 0))
+            {
+                unsigned char c = (unsigned char)(wParam & 0xFF);
+               unsigned char scancode = (lParam >> 16) & 0xFF;
+                if (index(extendedlist, tolower(c)) != 0)
+               {
+                   NHEVENT_KBD(M(tolower(c)));
+               } else if (scancode == (SCANLO + SIZE(scanmap)) - 1) {
+                   NHEVENT_KBD(M('?'));
+               }
+               return 0;
+            }
+            return DefWindowProc(hWnd, message, wParam, lParam);
+        } 
+        break;
+
+               case WM_COMMAND:
+                       /* process commands - menu commands mostly */
+                       if( onWMCommand(hWnd, wParam, lParam) )
+                               return DefWindowProc(hWnd, message, wParam, lParam);
+                       else
+                               return 0;
+
+               case WM_MOVE:
+               case WM_SIZE:
+        {
+            WINDOWPLACEMENT wp;
+
+                       mswin_layout_main_window(NULL);
+            
+            wp.length = sizeof(wp);
+            if (GetWindowPlacement(hWnd, &wp)) {
+                GetNHApp()->regMainShowState = (wp.showCmd == SW_SHOWMAXIMIZED 
+                   ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL);
+
+                GetNHApp()->regMainMinX = wp.ptMinPosition.x;
+                GetNHApp()->regMainMinY = wp.ptMinPosition.y;
+
+                GetNHApp()->regMainMaxX = wp.ptMaxPosition.x;
+                GetNHApp()->regMainMaxY = wp.ptMaxPosition.y;
+
+                GetNHApp()->regMainLeft = wp.rcNormalPosition.left;
+                GetNHApp()->regMainTop = wp.rcNormalPosition.top;
+                GetNHApp()->regMainRight = wp.rcNormalPosition.right;
+                GetNHApp()->regMainBottom = wp.rcNormalPosition.bottom;
+            }
+                       break;
+        }
+               case WM_SETFOCUS:
+                       /* if there is a menu window out there -
+                          transfer input focus to it */
+                       if( IsWindow( GetNHApp()->hPopupWnd ) ) {
+                               SetFocus( GetNHApp()->hPopupWnd );
+                       }
+                       break;
+
+               case WM_CLOSE: 
+               {
+                       /* exit gracefully */
+                       if (program_state.gameover)
+                       {
+                           /* assume the user really meant this, as the game is already over... */
+                           /* to make sure we still save bones, just set stop printing flag */
+                           program_state.stopprint++;
+                           NHEVENT_KBD('\033'); /* and send keyboard input as if user pressed ESC */
+                           /* additional code for this is done in menu and rip windows */
+                       }
+                       else if (!program_state.something_worth_saving)
+                       {
+                           /* User exited before the game started, e.g. during splash display */
+                           /* Just get out. */
+                           bail((char *)0);
+                       }
+                       else
+                       {
+                           switch (NHMessageBox(hWnd, TEXT("Save?"), MB_YESNOCANCEL | MB_ICONQUESTION)) {
+                           case IDYES: NHEVENT_KBD('y'); dosave(); break;
+                           case IDNO: NHEVENT_KBD('q'); done(QUIT); break;
+                           case IDCANCEL: break;
+                           }
+                       }
+               } return 0;
+
+               case WM_DESTROY:
+                       /* apparently we never get here 
+                          TODO: work on exit routines - need to send
+                          WM_QUIT somehow */  
+
+                       /* clean up */
+                       free( (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA) );
+                       SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+
+                       // PostQuitMessage(0);
+                       exit(1); 
+                       break;
+
+               default:
+                       return DefWindowProc(hWnd, message, wParam, lParam);
+   }
+   return 0;
+}
+
+void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       switch(wParam) {
+
+       /* new window was just added */
+       case MSNH_MSG_ADDWND: {
+               PMSNHMsgAddWnd msg_param = (PMSNHMsgAddWnd)lParam;
+               HWND child;
+
+               if( GetNHApp()->windowlist[msg_param->wid].type == NHW_MAP )
+                       mswin_select_map_mode(iflags.wc_map_mode);
+               
+               child = GetNHApp()->windowlist[msg_param->wid].win;
+               if( child ) mswin_layout_main_window(child);
+       } break;
+
+       }
+}
+
+/* adjust windows to fit main window layout 
+   ---------------------------
+   |        Status           |
+   +-------------------------+
+   |                         |
+   |                         |
+   |          MAP            |
+   |                         |
+   |                         |
+   +-------------------------+
+   |       Messages          |
+   ---------------------------
+*/
+void mswin_layout_main_window(HWND changed_child)
+{
+       winid i;
+       POINT pt;
+       RECT client_rt, wnd_rect;
+       SIZE menu_size;
+       POINT status_org;
+       SIZE status_size;
+       POINT msg_org;
+       SIZE msg_size;
+       POINT map_org;
+       SIZE map_size;
+       HWND wnd_status, wnd_msg;
+       PNHMainWindow  data;
+
+       GetClientRect(GetNHApp()->hMainWnd, &client_rt);
+       data = (PNHMainWindow)GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA);
+
+       /* get sizes of child windows */
+       wnd_status = mswin_hwnd_from_winid(WIN_STATUS);
+       if( IsWindow(wnd_status) ) { 
+               mswin_status_window_size(wnd_status, &status_size);
+       } else {
+               status_size.cx = status_size.cy = 0;
+       }
+
+       wnd_msg = mswin_hwnd_from_winid(WIN_MESSAGE);
+       if( IsWindow(wnd_msg) ) { 
+               mswin_message_window_size(wnd_msg, &msg_size);
+       } else {
+               msg_size.cx = msg_size.cy = 0;
+       }
+
+       /* set window positions */
+       SetRect(&wnd_rect, client_rt.left, client_rt.top, client_rt.right, client_rt.bottom);
+       switch(iflags.wc_align_status) {
+       case ALIGN_LEFT:
+               status_size.cx = (wnd_rect.right-wnd_rect.left)/4;
+               status_size.cy = (wnd_rect.bottom-wnd_rect.top); // that won't look good
+               status_org.x = wnd_rect.left;
+               status_org.y = wnd_rect.top;
+               wnd_rect.left += status_size.cx;
+               break;
+
+       case ALIGN_RIGHT:  
+               status_size.cx = (wnd_rect.right-wnd_rect.left)/4; 
+               status_size.cy = (wnd_rect.bottom-wnd_rect.top); // that won't look good
+               status_org.x = wnd_rect.right - status_size.cx;
+               status_org.y = wnd_rect.top;
+               wnd_rect.right -= status_size.cx;
+               break;
+
+       case ALIGN_TOP:    
+               status_size.cx = (wnd_rect.right-wnd_rect.left);
+               status_org.x = wnd_rect.left;
+               status_org.y = wnd_rect.top;
+               wnd_rect.top += status_size.cy;
+               break;
+
+       case ALIGN_BOTTOM:
+       default:
+               status_size.cx = (wnd_rect.right-wnd_rect.left);
+               status_org.x = wnd_rect.left;
+               status_org.y = wnd_rect.bottom - status_size.cy;
+               wnd_rect.bottom -= status_size.cy;
+               break;
+       }
+
+       switch(iflags.wc_align_message) {
+       case ALIGN_LEFT:
+               msg_size.cx = (wnd_rect.right-wnd_rect.left)/4;
+               msg_size.cy = (wnd_rect.bottom-wnd_rect.top); 
+               msg_org.x = wnd_rect.left;
+               msg_org.y = wnd_rect.top;
+               wnd_rect.left += msg_size.cx;
+               break;
+
+       case ALIGN_RIGHT:  
+               msg_size.cx = (wnd_rect.right-wnd_rect.left)/4; 
+               msg_size.cy = (wnd_rect.bottom-wnd_rect.top); 
+               msg_org.x = wnd_rect.right - msg_size.cx;
+               msg_org.y = wnd_rect.top;
+               wnd_rect.right -= msg_size.cx;
+               break;
+
+       case ALIGN_TOP:    
+               msg_size.cx = (wnd_rect.right-wnd_rect.left);
+               msg_org.x = wnd_rect.left;
+               msg_org.y = wnd_rect.top;
+               wnd_rect.top += msg_size.cy;
+               break;
+
+       case ALIGN_BOTTOM:
+       default:
+               msg_size.cx = (wnd_rect.right-wnd_rect.left);
+               msg_org.x = wnd_rect.left;
+               msg_org.y = wnd_rect.bottom - msg_size.cy;
+               wnd_rect.bottom -= msg_size.cy;
+               break;
+       }
+
+       map_org.x = wnd_rect.left;
+       map_org.y = wnd_rect.top;
+       map_size.cx = wnd_rect.right - wnd_rect.left;
+       map_size.cy = wnd_rect.bottom - wnd_rect.top;
+
+       /* go through the windows list and adjust sizes */
+       for( i=0; i<MAXWINDOWS; i++ ) {
+               if(GetNHApp()->windowlist[i].win && !GetNHApp()->windowlist[i].dead) {
+                       switch( GetNHApp()->windowlist[i].type ) {
+                       case NHW_STATUS:
+                               MoveWindow(GetNHApp()->windowlist[i].win, 
+                                              status_org.x,
+                                                  status_org.y,
+                                                  status_size.cx, 
+                                                  status_size.cy, 
+                                                  TRUE );
+                               break;
+
+                       case NHW_TEXT: // same as the map window
+                       case NHW_MAP:
+                               MoveWindow(GetNHApp()->windowlist[i].win, 
+                                              map_org.x, 
+                                                  map_org.y,
+                                                  map_size.cx, 
+                                                  map_size.cy, 
+                                                  TRUE );
+                               break;
+
+                       case NHW_MESSAGE:
+                               MoveWindow(GetNHApp()->windowlist[i].win, 
+                                              msg_org.x, 
+                                                  msg_org.y,
+                                                  msg_size.cx, 
+                                                  msg_size.cy, 
+                                                  TRUE );
+                               break;
+
+                       case NHW_MENU:
+                               mswin_menu_window_size(GetNHApp()->windowlist[i].win, &menu_size);
+                               menu_size.cx = min(menu_size.cx, (client_rt.right-client_rt.left));
+
+                               pt.x = map_org.x + max(0, (int)(map_size.cx-menu_size.cx));
+                               pt.y = map_org.y;
+                               MoveWindow(GetNHApp()->windowlist[i].win, 
+                                                  pt.x, 
+                                                  pt.y,
+                                                  min(menu_size.cx, map_size.cx), 
+                                                  map_size.cy, 
+                                                  TRUE );
+                               break;
+                       }
+                       ShowWindow(GetNHApp()->windowlist[i].win, SW_SHOW);
+               }
+       }
+}
+
+LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       int wmId, wmEvent;
+       PNHMainWindow  data;
+
+       data = (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       wmId    = LOWORD(wParam); 
+       wmEvent = HIWORD(wParam); 
+
+       // Parse the menu selections:
+       switch (wmId)
+       {
+               case IDM_ABOUT:
+     mswin_display_splash_window(TRUE);
+                  break;
+
+               case IDM_EXIT:
+                  done2();
+                  break;
+
+               case IDM_SAVE:
+                  if (!program_state.gameover && !program_state.done_hup) dosave();
+                  else MessageBeep(0);
+                  break;
+
+               case IDM_MAP_TILES:
+               case IDM_MAP_ASCII4X6:
+               case IDM_MAP_ASCII6X8:
+               case IDM_MAP_ASCII8X8:
+               case IDM_MAP_ASCII16X8:
+               case IDM_MAP_ASCII7X12:
+               case IDM_MAP_ASCII8X12:
+               case IDM_MAP_ASCII12X16:
+               case IDM_MAP_ASCII16X12:
+               case IDM_MAP_ASCII10X18:
+                       mswin_select_map_mode(menuid2mapmode(wmId));
+                       break;
+
+               case IDM_MAP_FIT_TO_SCREEN:
+                       if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
+                               mswin_select_map_mode(
+                                       IS_MAP_ASCII(iflags.wc_map_mode)? 
+                                               data->mapAcsiiModeSave :
+                                               MAP_MODE_TILES
+                               );
+                       } else {
+                               mswin_select_map_mode(
+                                       IS_MAP_ASCII(iflags.wc_map_mode)?
+                                               MAP_MODE_ASCII_FIT_TO_SCREEN :
+                                               MAP_MODE_TILES_FIT_TO_SCREEN
+                               );
+                       }
+                       break;
+
+        case IDM_NHMODE:
+        {
+            GetNHApp()->regNetHackMode = GetNHApp()->regNetHackMode ? 0 : 1;
+            mswin_menu_check_intf_mode();
+            break;
+        }
+        case IDM_CLEARSETTINGS:
+        {
+            mswin_destroy_reg();
+            /* Notify the user that windows settings will not be saved this time. */
+            NHMessageBox(GetNHApp()->hMainWnd, 
+                "Your Windows Settings will not be stored when you exit this time.", 
+                MB_OK | MB_ICONINFORMATION);
+            break;
+        }
+               case IDM_HELP_LONG:     
+                       display_file(HELP, TRUE);  
+                       break;
+               
+               case IDM_HELP_COMMANDS: 
+                       display_file(SHELP, TRUE);  
+                       break;
+               
+               case IDM_HELP_HISTORY:
+                       (void) dohistory();  
+                       break;
+               
+               case IDM_HELP_INFO_CHAR:
+                       (void) dowhatis();  
+                       break;
+               
+               case IDM_HELP_INFO_KEY:
+                       (void) dowhatdoes();  
+                       break;
+               
+               case IDM_HELP_OPTIONS:
+                       option_help();  
+                       break;
+               
+               case IDM_HELP_OPTIONS_LONG:
+                       display_file(OPTIONFILE, TRUE);  
+                       break;
+               
+               case IDM_HELP_EXTCMD:
+                       (void) doextlist();  
+                       break;
+               
+               case IDM_HELP_LICENSE:
+                       display_file(LICENSE, TRUE);  
+                       break;
+
+               case IDM_HELP_PORTHELP:
+                       display_file(PORT_HELP, TRUE);  
+                       break;
+
+               default:
+                  return 1;
+       }
+       return 0;
+}
+
+// Mesage handler for about box.
+LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       char buf[BUFSZ];
+       TCHAR wbuf[BUFSZ];
+       RECT   main_rt, dlg_rt;
+       SIZE   dlg_sz;
+
+       switch (message)
+       {
+               case WM_INITDIALOG:
+                               getversionstring(buf);
+                               SetDlgItemText(hDlg, IDC_ABOUT_VERSION, NH_A2W(buf, wbuf, sizeof(wbuf)));
+
+                               SetDlgItemText(hDlg, IDC_ABOUT_COPYRIGHT,
+                                                       NH_A2W(
+                                                               COPYRIGHT_BANNER_A "\n"
+                                                               COPYRIGHT_BANNER_B "\n"
+                                                               COPYRIGHT_BANNER_C,
+                                                               wbuf,
+                                                               BUFSZ
+                                                       ) );
+                                                         
+
+                               /* center dialog in the main window */
+                               GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
+                               GetWindowRect(hDlg, &dlg_rt);
+                               dlg_sz.cx = dlg_rt.right - dlg_rt.left;
+                               dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
+
+                               dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2;
+                               dlg_rt.right = dlg_rt.left + dlg_sz.cx;
+                               dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2;
+                               dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
+                               MoveWindow( hDlg,
+                                                       (main_rt.left+main_rt.right-dlg_sz.cx)/2,
+                                                       (main_rt.top+main_rt.bottom-dlg_sz.cy)/2,
+                                                       dlg_sz.cx,
+                                                       dlg_sz.cy,
+                                                       TRUE );
+
+                               return TRUE;
+
+               case WM_COMMAND:
+                       if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
+                       {
+                               EndDialog(hDlg, LOWORD(wParam));
+                               return TRUE;
+                       }
+                       break;
+       }
+    return FALSE;
+}
+
+void mswin_menu_check_intf_mode()
+{
+    HMENU hMenu = GetMenu(GetNHApp()->hMainWnd);
+
+    if (GetNHApp()->regNetHackMode)
+        CheckMenuItem(hMenu, IDM_NHMODE, MF_CHECKED);
+    else
+        CheckMenuItem(hMenu, IDM_NHMODE, MF_UNCHECKED);
+
+}
+
+void mswin_select_map_mode(int mode)
+{
+       PNHMainWindow  data;
+       winid map_id;
+
+       map_id = WIN_MAP;
+       data = (PNHMainWindow)GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA);
+
+       /* override for Rogue level */
+#ifdef REINCARNATION
+    if( Is_rogue_level(&u.uz) && !IS_MAP_ASCII(mode) ) return;
+#endif
+
+       /* set map mode menu mark */
+       if( IS_MAP_ASCII(mode) ) {
+               CheckMenuRadioItem(
+                       GetMenu(GetNHApp()->hMainWnd), 
+                       IDM_MAP_TILES, 
+                       IDM_MAP_ASCII10X18, 
+                       mapmode2menuid( IS_MAP_FIT_TO_SCREEN(mode)? data->mapAcsiiModeSave : mode ), 
+                       MF_BYCOMMAND);
+       } else {
+               CheckMenuRadioItem(
+                       GetMenu(GetNHApp()->hMainWnd), 
+                       IDM_MAP_TILES, 
+                       IDM_MAP_ASCII10X18, 
+                       mapmode2menuid( MAP_MODE_TILES ), 
+                       MF_BYCOMMAND);
+       }
+
+       /* set fit-to-screen mode mark */
+       CheckMenuItem(
+               GetMenu(GetNHApp()->hMainWnd),
+               IDM_MAP_FIT_TO_SCREEN,
+               MF_BYCOMMAND | 
+               (IS_MAP_FIT_TO_SCREEN(mode)? MF_CHECKED : MF_UNCHECKED)
+       );
+
+       if( IS_MAP_ASCII(iflags.wc_map_mode) && !IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
+               data->mapAcsiiModeSave = iflags.wc_map_mode;
+       }
+
+       iflags.wc_map_mode = mode;
+       
+       /* 
+       ** first, check if WIN_MAP has been inialized.
+       ** If not - attempt to retrieve it by type, then check it again
+       */
+       if( map_id==WIN_ERR ) 
+               map_id = mswin_winid_from_type(NHW_MAP);
+       if( map_id!=WIN_ERR )
+               mswin_map_mode(mswin_hwnd_from_winid(map_id), mode);
+}
+
+static struct t_menu2mapmode {
+       int menuID;
+       int mapMode;
+} _menu2mapmode[] = 
+{
+       { IDM_MAP_TILES, MAP_MODE_TILES },
+       { IDM_MAP_ASCII4X6, MAP_MODE_ASCII4x6 },
+       { IDM_MAP_ASCII6X8, MAP_MODE_ASCII6x8 },
+       { IDM_MAP_ASCII8X8, MAP_MODE_ASCII8x8 },
+       { IDM_MAP_ASCII16X8, MAP_MODE_ASCII16x8 },
+       { IDM_MAP_ASCII7X12, MAP_MODE_ASCII7x12 },
+       { IDM_MAP_ASCII8X12, MAP_MODE_ASCII8x12 },
+       { IDM_MAP_ASCII12X16, MAP_MODE_ASCII12x16 },
+       { IDM_MAP_ASCII16X12, MAP_MODE_ASCII16x12 },
+       { IDM_MAP_ASCII10X18, MAP_MODE_ASCII10x18 },
+       { IDM_MAP_FIT_TO_SCREEN, MAP_MODE_ASCII_FIT_TO_SCREEN },
+       { -1, -1 }
+};
+
+int    menuid2mapmode(int menuid)
+{
+       struct t_menu2mapmode* p;
+       for( p = _menu2mapmode; p->mapMode!=-1; p++ ) 
+               if(p->menuID==menuid ) return p->mapMode;
+       return -1;
+}
+
+int    mapmode2menuid(int map_mode)
+{
+       struct t_menu2mapmode* p;
+       for( p = _menu2mapmode; p->mapMode!=-1; p++ ) 
+               if(p->mapMode==map_mode ) return p->menuID;
+       return -1;
+}
diff --git a/win/win32/mhmain.h b/win/win32/mhmain.h
new file mode 100644 (file)
index 0000000..3f40714
--- /dev/null
@@ -0,0 +1,16 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINMainWindow_h
+#define MSWINMainWindow_h
+
+/* this is a main appliation window */
+
+#include "winMS.h"
+
+HWND mswin_init_main_window (void);
+void mswin_layout_main_window(HWND changed_child);
+void mswin_select_map_mode(int map_mode);
+void mswin_menu_check_intf_mode(void);
+
+#endif /* MSWINMainWindow_h */
diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c
new file mode 100644 (file)
index 0000000..de0f8b3
--- /dev/null
@@ -0,0 +1,976 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include "resource.h"
+#include "mhmap.h"
+#include "mhmsg.h"
+#include "mhinput.h"
+#include "mhfont.h"
+
+#include "patchlevel.h"
+
+#define NHMAP_FONT_NAME TEXT("Terminal")
+#define MAXWINDOWTEXT 255
+
+extern short glyph2tile[];
+
+/* map window data */
+typedef struct mswin_nethack_map_window {
+       int map[COLNO][ROWNO];          /* glyph map */
+
+       int      mapMode;                               /* current map mode */
+       boolean bAsciiMode;                     /* switch ASCII/tiled mode */
+       boolean bFitToScreenMode;       /* switch Fit map to screen mode on/off */
+       int  xPos, yPos;                        /* scroll position */
+       int  xPageSize, yPageSize;      /* scroll page size */
+       int  xCur, yCur;                        /* position of the cursor */
+       int  xScrTile, yScrTile;        /* size of display tile */
+       POINT map_orig;                         /* map origin point */
+
+       HFONT hMapFont;                         /* font for ASCII mode */
+} NHMapWindow, *PNHMapWindow;
+
+static TCHAR szNHMapWindowClass[] = TEXT("MSNethackMapWndClass");
+LRESULT CALLBACK       MapWndProc(HWND, UINT, WPARAM, LPARAM);
+static void register_map_window_class(void);
+static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void onPaint(HWND hWnd);
+static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut);
+#if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
+static void nhglyph2charcolor(short glyph, uchar* ch, int* color);
+#endif
+static COLORREF nhcolor_to_RGB(int c);
+
+HWND mswin_init_map_window () {
+       static int run_once = 0;
+       HWND ret;
+
+       if( !run_once ) {
+               register_map_window_class();
+               run_once = 1;
+       }
+       
+       ret = CreateWindow(
+                       szNHMapWindowClass,             /* registered class name */
+                       NULL,                                   /* window name */
+                       WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_CLIPSIBLINGS, /* window style */
+                       0,  /* horizontal position of window - set it later */
+                       0,  /* vertical position of window - set it later */
+                       0,  /* window width - set it later */
+                       0,  /* window height - set it later*/
+                       GetNHApp()->hMainWnd,   /* handle to parent or owner window */
+                       NULL,                                   /* menu handle or child identifier */
+                       GetNHApp()->hApp,               /* handle to application instance */
+                       NULL );                                 /* window-creation data */
+       if( !ret ) {
+               panic("Cannot create map window");
+       }
+       return ret;
+}
+
+void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw)
+{
+       PNHMapWindow data;
+       RECT         client_rt;
+       SCROLLINFO   si;
+       SIZE             wnd_size;                       
+       LOGFONT          lgfnt;
+
+       /* check arguments */
+       if( !IsWindow(hWnd) ||
+               !lpsz ||
+               lpsz->cx<=0 ||
+               lpsz->cy<=0 ) return;
+
+       /* calculate window size */
+       GetClientRect(hWnd, &client_rt);
+       wnd_size.cx = client_rt.right - client_rt.left;
+       wnd_size.cy = client_rt.bottom - client_rt.top;
+       
+       /* set new screen tile size */
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       data->xScrTile = 
+               max(1, (data->bFitToScreenMode? wnd_size.cx : lpsz->cx) / COLNO);
+       data->yScrTile = 
+               max(1, (data->bFitToScreenMode? wnd_size.cy : lpsz->cy) / ROWNO);
+
+       /* set map origin point */
+       data->map_orig.x = max(0, client_rt.left + (wnd_size.cx - data->xScrTile*COLNO)/2 );
+       data->map_orig.y = max(0, client_rt.top + (wnd_size.cy - data->yScrTile*ROWNO)/2 );
+
+       data->map_orig.x -= data->map_orig.x % data->xScrTile;
+       data->map_orig.y -= data->map_orig.y % data->yScrTile;
+
+       /* adjust horizontal scroll bar */
+       if( data->bFitToScreenMode )
+               data->xPageSize = COLNO+1;  /* disable scroll bar */
+       else
+               data->xPageSize = wnd_size.cx/data->xScrTile;
+
+       if( data->xPageSize >= COLNO ) {
+               data->xPos = 0;
+               GetNHApp()->bNoHScroll = TRUE;
+       } else {
+               GetNHApp()->bNoHScroll = FALSE;
+               data->xPos = max(0, min(COLNO-data->xPageSize+1, u.ux - data->xPageSize/2));
+       }
+
+    si.cbSize = sizeof(si); 
+    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS; 
+    si.nMin   = 0; 
+    si.nMax   = COLNO; 
+    si.nPage  = data->xPageSize; 
+    si.nPos   = data->xPos; 
+    SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); 
+
+       /* adjust vertical scroll bar */
+       if( data->bFitToScreenMode )
+               data->yPageSize = ROWNO+1;   /* disable scroll bar */
+       else
+               data->yPageSize = wnd_size.cy/data->yScrTile;
+
+       if( data->yPageSize >= ROWNO ) {
+               data->yPos = 0;
+               GetNHApp()->bNoVScroll = TRUE;
+       } else {
+               GetNHApp()->bNoVScroll = FALSE;
+               data->yPos = max(0, min(ROWNO-data->yPageSize+1, u.uy - data->yPageSize/2));
+       }
+
+    si.cbSize = sizeof(si); 
+    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS; 
+    si.nMin   = 0; 
+    si.nMax   = ROWNO; 
+    si.nPage  = data->yPageSize; 
+    si.nPos   = data->yPos; 
+    SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
+
+       /* create font */
+       if( data->hMapFont ) DeleteObject(data->hMapFont);
+       ZeroMemory(&lgfnt, sizeof(lgfnt));
+       lgfnt.lfHeight                  =       -data->yScrTile;         // height of font
+       lgfnt.lfWidth                   =       -data->xScrTile;         // average character width
+       lgfnt.lfEscapement              =       0;                                       // angle of escapement
+       lgfnt.lfOrientation             =       0;                                       // base-line orientation angle
+       lgfnt.lfWeight                  =       FW_NORMAL;                       // font weight
+       lgfnt.lfItalic                  =       FALSE;                           // italic attribute option
+       lgfnt.lfUnderline               =       FALSE;                           // underline attribute option
+       lgfnt.lfStrikeOut               =       FALSE;                       // strikeout attribute option
+       lgfnt.lfCharSet                 =       mswin_charset();     // character set identifier
+       lgfnt.lfOutPrecision    =       OUT_DEFAULT_PRECIS;  // output precision
+       lgfnt.lfClipPrecision   =       CLIP_DEFAULT_PRECIS; // clipping precision
+       lgfnt.lfQuality                 =       DEFAULT_QUALITY;     // output quality
+       if( iflags.wc_font_map &&
+               *iflags.wc_font_map ) {
+               lgfnt.lfPitchAndFamily  = DEFAULT_PITCH;                 // pitch and family
+               NH_A2W(iflags.wc_font_map, lgfnt.lfFaceName, LF_FACESIZE);
+       } else {
+               lgfnt.lfPitchAndFamily  = FIXED_PITCH;           // pitch and family
+               NH_A2W(NHMAP_FONT_NAME, lgfnt.lfFaceName, LF_FACESIZE);
+       }
+       data->hMapFont = CreateFontIndirect(&lgfnt);
+
+       mswin_cliparound(data->xCur, data->yCur);
+
+       if(redraw) InvalidateRect(hWnd, NULL, TRUE);
+}
+
+/* set map mode */
+int mswin_map_mode(HWND hWnd, int mode)
+{
+       PNHMapWindow data;
+       int oldMode;
+       SIZE mapSize;
+
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if( mode == data->mapMode ) return mode;
+       
+       oldMode = data->mapMode;
+       data->mapMode = mode;
+
+       switch( data->mapMode ) {
+
+       case MAP_MODE_ASCII4x6:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 4*COLNO;
+               mapSize.cy = 6*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII6x8:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 6*COLNO;
+               mapSize.cy = 8*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII8x8:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 8*COLNO;
+               mapSize.cy = 8*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII16x8:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 16*COLNO;
+               mapSize.cy = 8*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII7x12:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 7*COLNO;
+               mapSize.cy = 12*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII8x12:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 8*COLNO;
+               mapSize.cy = 12*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII16x12:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 16*COLNO;
+               mapSize.cy = 12*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII12x16:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 12*COLNO;
+               mapSize.cy = 16*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII10x18:
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = 10*COLNO;
+               mapSize.cy = 18*ROWNO;
+       break;
+
+       case MAP_MODE_ASCII_FIT_TO_SCREEN: {
+               RECT client_rt;
+               GetClientRect(hWnd, &client_rt);
+               mapSize.cx = client_rt.right - client_rt.left;
+               mapSize.cy = client_rt.bottom - client_rt.top;
+
+               data->bAsciiMode = TRUE;
+               data->bFitToScreenMode = TRUE;
+       } break;
+
+       case MAP_MODE_TILES_FIT_TO_SCREEN: {
+               RECT client_rt;
+               GetClientRect(hWnd, &client_rt);
+               mapSize.cx = client_rt.right - client_rt.left;
+               mapSize.cy = client_rt.bottom - client_rt.top;
+
+               data->bAsciiMode = FALSE;
+               data->bFitToScreenMode = TRUE;
+       } break;
+
+       case MAP_MODE_TILES:
+       default:
+               data->bAsciiMode = FALSE;
+               data->bFitToScreenMode = FALSE;
+               mapSize.cx = GetNHApp()->mapTile_X*COLNO;
+               mapSize.cy = GetNHApp()->mapTile_Y*ROWNO;
+       break;
+       }
+
+       mswin_map_stretch(hWnd, &mapSize, TRUE);
+
+       return oldMode;
+}
+
+/* register window class for map window */
+void register_map_window_class()
+{
+       WNDCLASS wcex;
+       ZeroMemory( &wcex, sizeof(wcex));
+
+       /* window class */
+       wcex.style                      = CS_NOCLOSE | CS_DBLCLKS;
+       wcex.lpfnWndProc        = (WNDPROC)MapWndProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = GetNHApp()->hApp;
+       wcex.hIcon                      = NULL;
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = CreateSolidBrush(RGB(0, 0, 0)); /* set backgroup here */
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szNHMapWindowClass;
+
+       if( !RegisterClass(&wcex) ) {
+               panic("cannot register Map window class");
+       }
+}
+    
+/* map window procedure */    
+LRESULT CALLBACK MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       PNHMapWindow data;
+       
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch (message) 
+       {
+       case WM_CREATE:
+               onCreate( hWnd, wParam, lParam );
+               break;
+
+       case WM_MSNH_COMMAND:
+               onMSNHCommand(hWnd, wParam, lParam);
+               break;
+
+       case WM_PAINT: 
+               onPaint(hWnd);
+               break;
+
+       case WM_SETFOCUS:
+               /* transfer focus back to the main window */
+               SetFocus(GetNHApp()->hMainWnd);
+               break;
+
+       case WM_HSCROLL:
+               onMSNH_HScroll(hWnd, wParam, lParam);
+               break;
+
+       case WM_VSCROLL:
+               onMSNH_VScroll(hWnd, wParam, lParam);
+               break;
+
+    case WM_SIZE: 
+    { 
+               SIZE size;
+
+               if( data->bFitToScreenMode ) {
+                       size.cx = LOWORD(lParam);
+                       size.cy = HIWORD(lParam);
+               } else {
+                       /* mapping factor is unchaged we just need to adjust scroll bars */
+                       size.cx = data->xScrTile*COLNO; 
+                       size.cy = data->yScrTile*ROWNO;
+               }
+               mswin_map_stretch(hWnd, &size, TRUE);
+    } 
+    break; 
+
+       case WM_LBUTTONDOWN:
+               NHEVENT_MS( 
+                       CLICK_1,
+                       max(0, min(COLNO, data->xPos + (LOWORD(lParam)-data->map_orig.x)/data->xScrTile)),
+                       max(0, min(ROWNO, data->yPos + (HIWORD(lParam)-data->map_orig.y)/data->yScrTile))
+               );
+       return 0;
+
+       case WM_LBUTTONDBLCLK :
+               NHEVENT_MS( 
+                       CLICK_2,
+                       max(0, min(COLNO, data->xPos + (LOWORD(lParam)-data->map_orig.x)/data->xScrTile)),
+                       max(0, min(ROWNO, data->yPos + (HIWORD(lParam)-data->map_orig.y)/data->yScrTile))
+               );
+       return 0;
+
+       case WM_DESTROY:
+               if( data->hMapFont ) DeleteObject(data->hMapFont);
+               free(data);
+               SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+               break;
+
+       default:
+               return DefWindowProc(hWnd, message, wParam, lParam);
+   }
+   return 0;
+}
+
+/* on WM_COMMAND */
+void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMapWindow data;
+       RECT rt;
+
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch(wParam) {
+       case MSNH_MSG_PRINT_GLYPH: 
+       {
+               PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph)lParam;
+               data->map[msg_data->x][msg_data->y] = msg_data->glyph;
+
+               /* invalidate the update area */
+               nhcoord2display(data, msg_data->x, msg_data->y, &rt);
+               InvalidateRect(hWnd, &rt, TRUE);
+       } 
+       break;
+
+       case MSNH_MSG_CLIPAROUND: 
+       {
+               PMSNHMsgClipAround msg_data = (PMSNHMsgClipAround)lParam;
+               int x, y;
+               BOOL scroll_x, scroll_y;
+               int mcam = iflags.wc_scroll_margin;
+
+               /* calculate if you should clip around */
+               scroll_x =  
+                       !GetNHApp()->bNoHScroll &&
+                       ( msg_data->x<(data->xPos+mcam) ||
+                         msg_data->x>(data->xPos+data->xPageSize-mcam) );
+               scroll_y =  
+                       !GetNHApp()->bNoVScroll &&
+                       ( msg_data->y<(data->yPos+mcam) ||
+                         msg_data->y>(data->yPos+data->yPageSize-mcam) );
+               
+               mcam += iflags.wc_scroll_amount - 1;
+               /* get page size and center horizontally on x-position */
+               if( scroll_x ) {
+                       if( data->xPageSize<=2*mcam ) {
+                               x = max(0, min(COLNO, msg_data->x - data->xPageSize/2));
+                       } else if( msg_data->x < data->xPos+data->xPageSize/2 ) {
+                               x = max(0, min(COLNO, msg_data->x - mcam));
+                       } else {
+                               x = max(0, min(COLNO, msg_data->x - data->xPageSize + mcam));
+                       }
+                       SendMessage( hWnd, WM_HSCROLL, (WPARAM)MAKELONG(SB_THUMBTRACK, x), (LPARAM)NULL );
+               }
+
+               /* get page size and center vertically on y-position */
+               if( scroll_y ) {
+                       if( data->yPageSize<=2*mcam ) {
+                               y = max(0, min(ROWNO, msg_data->y - data->yPageSize/2));
+                       } else if( msg_data->y < data->yPos+data->yPageSize/2 ) {
+                               y = max(0, min(ROWNO, msg_data->y - mcam));
+                       } else {
+                               y = max(0, min(ROWNO, msg_data->y - data->yPageSize + mcam));
+                       }
+                       SendMessage( hWnd, WM_VSCROLL, (WPARAM)MAKELONG(SB_THUMBTRACK, y), (LPARAM)NULL );
+               }
+       } 
+       break;
+
+       case MSNH_MSG_CLEAR_WINDOW: 
+       {
+               int i, j;
+               for(i=0; i<COLNO; i++) 
+                       for(j=0; j<ROWNO; j++) {
+                       data->map[i][j] = -1;
+               }
+               InvalidateRect(hWnd, NULL, TRUE);
+       } break;
+
+       case MSNH_MSG_CURSOR:
+       {
+               PMSNHMsgCursor msg_data = (PMSNHMsgCursor)lParam;
+               HDC    hdc;
+               RECT   rt;
+
+               /* move focus rectangle at the cursor postion */
+               hdc = GetDC(hWnd);
+
+               nhcoord2display(data, data->xCur, data->yCur, &rt);
+               if( data->bAsciiMode ) {
+                       PatBlt(hdc, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, DSTINVERT);    
+               } else {
+                       DrawFocusRect(hdc, &rt);
+               }
+               
+               data->xCur = msg_data->x;
+               data->yCur = msg_data->y;
+
+               nhcoord2display(data, data->xCur, data->yCur, &rt);
+               if( data->bAsciiMode ) {
+                       PatBlt(hdc, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, DSTINVERT);    
+               } else {
+                       DrawFocusRect(hdc, &rt);
+               }
+
+               ReleaseDC(hWnd, hdc);
+       } break;
+       }
+}
+
+/* on WM_CREATE */
+void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMapWindow data;
+       int i,j;
+
+       /* set window data */
+       data = (PNHMapWindow)malloc(sizeof(NHMapWindow));
+       if( !data ) panic("out of memory");
+
+       ZeroMemory(data, sizeof(NHMapWindow));
+       for(i=0; i<COLNO; i++) 
+               for(j=0; j<ROWNO; j++) {
+               data->map[i][j] = -1;
+       }
+
+       data->bAsciiMode = FALSE;
+
+       data->xScrTile = GetNHApp()->mapTile_X;
+       data->yScrTile = GetNHApp()->mapTile_Y;
+
+       SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
+}
+
+/* on WM_PAINT */
+void onPaint(HWND hWnd) 
+{
+       PNHMapWindow data;
+       PAINTSTRUCT ps;
+       HDC hDC;
+       HDC tileDC;
+       HGDIOBJ saveBmp;
+       RECT paint_rt;
+       int i, j;
+
+       /* get window data */
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       hDC = BeginPaint(hWnd, &ps);
+
+       /* calculate paint rectangle */
+       if( !IsRectEmpty(&ps.rcPaint) ) {
+               /* calculate paint rectangle */
+               paint_rt.left = max(data->xPos + (ps.rcPaint.left - data->map_orig.x)/data->xScrTile, 0);
+               paint_rt.top = max(data->yPos + (ps.rcPaint.top - data->map_orig.y)/data->yScrTile, 0);
+               paint_rt.right = min(data->xPos + (ps.rcPaint.right - data->map_orig.x)/data->xScrTile+1, COLNO);
+               paint_rt.bottom = min(data->yPos + (ps.rcPaint.bottom - data->map_orig.y)/data->yScrTile+1, ROWNO);
+
+               if( data->bAsciiMode
+#ifdef REINCARNATION
+                   || Is_rogue_level(&u.uz) 
+                       /* You enter a VERY primitive world! */
+#endif
+                       ) {
+                       HGDIOBJ oldFont;
+
+                       oldFont = SelectObject(hDC, data->hMapFont);
+                       SetBkMode(hDC, TRANSPARENT);
+
+                       /* draw the map */
+                       for(i=paint_rt.left; i<paint_rt.right; i++) 
+                       for(j=paint_rt.top; j<paint_rt.bottom; j++) 
+                       if(data->map[i][j]>=0) {
+                               char ch;
+                               TCHAR wch;
+                               RECT  glyph_rect;
+                               int   color;
+                               unsigned special;
+                               int mgch;
+                               HBRUSH back_brush;
+                               COLORREF OldFg;
+
+                               nhcoord2display(data, i, j, &glyph_rect);
+
+#if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
+                               nhglyph2charcolor(data->map[i][j], &ch, &color);
+                               OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) );
+#else
+                               /* rely on NetHack core helper routine */
+                               mapglyph(data->map[i][j], &mgch, &color,
+                                               &special, i, j);
+                               ch = (char)mgch;
+                               if (((special & MG_PET) && iflags.hilite_pet) ||
+                                   ((special & MG_DETECT) && iflags.use_inverse)) {
+                                       back_brush = CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY));
+                                       FillRect (hDC, &glyph_rect, back_brush);
+                                       DeleteObject (back_brush);
+                                       switch (color)
+                                       {
+                                       case CLR_GRAY:
+                                       case CLR_WHITE:
+                                               OldFg = SetTextColor( hDC,  nhcolor_to_RGB(CLR_BLACK));
+                                               break;
+                                       default:
+                                               OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) );
+                                       }
+                               } else {
+                                       OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) );
+                               }
+#endif
+
+                               DrawText(hDC, 
+                                                NH_A2W(&ch, &wch, 1),
+                                                1,
+                                                &glyph_rect,
+                                                DT_CENTER | DT_VCENTER | DT_NOPREFIX
+                                                );
+                               SetTextColor (hDC, OldFg);
+                       }
+                       SelectObject(hDC, oldFont);
+               } else {
+                       /* prepare tiles DC for mapping */
+                       tileDC = CreateCompatibleDC(hDC);
+                       saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles);
+
+                       /* draw the map */
+                       for(i=paint_rt.left; i<paint_rt.right; i++) 
+                       for(j=paint_rt.top; j<paint_rt.bottom; j++) 
+                               if(data->map[i][j]>=0) {
+                                       short ntile;
+                                       int t_x, t_y;
+                                       RECT glyph_rect;
+
+                                       ntile = glyph2tile[ data->map[i][j] ];
+                                       t_x = (ntile % GetNHApp()->mapTilesPerLine)*GetNHApp()->mapTile_X;
+                                       t_y = (ntile / GetNHApp()->mapTilesPerLine)*GetNHApp()->mapTile_Y;
+                                       
+                                       nhcoord2display(data, i, j, &glyph_rect);
+
+                                       StretchBlt( 
+                                               hDC, 
+                                               glyph_rect.left,
+                                               glyph_rect.top, 
+                                               data->xScrTile,
+                                               data->yScrTile,
+                                               tileDC,
+                                               t_x,
+                                               t_y,
+                                               GetNHApp()->mapTile_X, 
+                                               GetNHApp()->mapTile_Y, 
+                                               SRCCOPY 
+                                       );
+                                       if( glyph_is_pet(data->map[i][j]) && iflags.wc_hilite_pet ) {
+                                               /* apply pet mark transparently over 
+                                                  pet image */
+                                               HDC hdcPetMark;
+                                               HBITMAP    bmPetMarkOld;
+
+                                               /* this is DC for petmark bitmap */
+                                               hdcPetMark = CreateCompatibleDC(hDC);
+                                               bmPetMarkOld = SelectObject(hdcPetMark, GetNHApp()->bmpPetMark);
+
+                                               nhapply_image_transparent( 
+                                                       hDC,
+                                                       glyph_rect.left,
+                                                       glyph_rect.top, 
+                                                       data->xScrTile,
+                                                       data->yScrTile,
+                                                       hdcPetMark,
+                                                       0,
+                                                       0,
+                                                       TILE_X, 
+                                                       TILE_Y,
+                                                       TILE_BK_COLOR 
+                                               );
+                                               SelectObject(hdcPetMark, bmPetMarkOld);
+                                               DeleteDC(hdcPetMark);
+                                       }
+                               }
+                       SelectObject(tileDC, saveBmp);
+                       DeleteDC(tileDC);
+               }
+
+               /* draw focus rect */
+               nhcoord2display(data, data->xCur, data->yCur, &paint_rt);
+               if( data->bAsciiMode ) {
+                       PatBlt( hDC, 
+                                   paint_rt.left, paint_rt.top, 
+                                   paint_rt.right-paint_rt.left, paint_rt.bottom-paint_rt.top, 
+                                   DSTINVERT );        
+               } else {
+                       DrawFocusRect(hDC, &paint_rt);
+               }
+       }
+       EndPaint(hWnd, &ps);
+}
+
+/* on WM_VSCROLL */
+void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMapWindow data;
+       SCROLLINFO si;
+       int yNewPos;
+       int yDelta;
+       /* get window data */
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+    switch(LOWORD (wParam)) 
+    { 
+        /* User clicked shaft left of the scroll box. */
+        case SB_PAGEUP: 
+             yNewPos = data->yPos-data->yPageSize; 
+             break; 
+
+        /* User clicked shaft right of the scroll box. */
+        case SB_PAGEDOWN: 
+             yNewPos = data->yPos+data->yPageSize; 
+             break; 
+
+        /* User clicked the left arrow. */
+        case SB_LINEUP: 
+             yNewPos = data->yPos-1; 
+             break; 
+
+        /* User clicked the right arrow. */
+        case SB_LINEDOWN: 
+             yNewPos = data->yPos+1; 
+             break; 
+
+        /* User dragged the scroll box. */
+        case SB_THUMBTRACK: 
+             yNewPos = HIWORD(wParam); 
+             break; 
+
+        default: 
+             yNewPos = data->yPos; 
+    } 
+
+       yNewPos = max(0, min(ROWNO-data->yPageSize+1, yNewPos));
+       if( yNewPos == data->yPos ) return;
+       
+       yDelta = yNewPos - data->yPos;
+       data->yPos = yNewPos;
+
+    ScrollWindowEx (hWnd, 0, -data->yScrTile * yDelta, 
+            (CONST RECT *) NULL, (CONST RECT *) NULL, 
+            (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); 
+
+    si.cbSize = sizeof(si); 
+    si.fMask  = SIF_POS; 
+    si.nPos   = data->yPos; 
+    SetScrollInfo(hWnd, SB_VERT, &si, TRUE); 
+}
+
+/* on WM_HSCROLL */
+void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMapWindow data;
+       SCROLLINFO si;
+       int xNewPos;
+       int xDelta;
+       /* get window data */
+       data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       
+    switch(LOWORD (wParam)) 
+    { 
+        /* User clicked shaft left of the scroll box. */
+        case SB_PAGEUP: 
+             xNewPos = data->xPos-data->xPageSize; 
+             break; 
+
+        /* User clicked shaft right of the scroll box. */
+        case SB_PAGEDOWN: 
+             xNewPos = data->xPos+data->xPageSize; 
+             break; 
+
+        /* User clicked the left arrow. */
+        case SB_LINEUP: 
+             xNewPos = data->xPos-1; 
+             break; 
+
+        /* User clicked the right arrow. */
+        case SB_LINEDOWN: 
+             xNewPos = data->xPos+1; 
+             break; 
+
+        /* User dragged the scroll box. */
+        case SB_THUMBTRACK: 
+             xNewPos = HIWORD(wParam); 
+             break; 
+
+        default: 
+             xNewPos = data->xPos; 
+    } 
+
+       xNewPos = max(0, min(COLNO-data->xPageSize+1, xNewPos));
+       if( xNewPos == data->xPos ) return;
+       
+       xDelta = xNewPos - data->xPos;
+       data->xPos = xNewPos;
+
+    ScrollWindowEx (hWnd, -data->xScrTile * xDelta, 0, 
+            (CONST RECT *) NULL, (CONST RECT *) NULL, 
+            (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); 
+
+
+    si.cbSize = sizeof(si); 
+    si.fMask  = SIF_POS; 
+    si.nPos   = data->xPos; 
+    SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); 
+}
+
+/* map nethack map coordinates to the screen location */
+void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut)
+{
+       lpOut->left = (x - data->xPos)*data->xScrTile + data->map_orig.x;
+       lpOut->top  = (y - data->yPos)*data->yScrTile + data->map_orig.y;
+       lpOut->right = lpOut->left + data->xScrTile;
+       lpOut->bottom = lpOut->top + data->yScrTile;
+}
+
+#if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
+/* map glyph to character/color combination */
+void nhglyph2charcolor(short g, uchar* ch, int* color)
+{
+       int offset;
+#ifdef TEXTCOLOR
+
+#define zap_color(n)  *color = iflags.use_color ? zapcolors[n] : NO_COLOR
+#define cmap_color(n) *color = iflags.use_color ? defsyms[n].color : NO_COLOR
+#define obj_color(n)  *color = iflags.use_color ? objects[n].oc_color : NO_COLOR
+#define mon_color(n)  *color = iflags.use_color ? mons[n].mcolor : NO_COLOR
+#define pet_color(n)  *color = iflags.use_color ? mons[n].mcolor : NO_COLOR
+#define warn_color(n) *color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR
+
+# else /* no text color */
+
+#define zap_color(n)
+#define cmap_color(n)
+#define obj_color(n)
+#define mon_color(n)
+#define pet_color(c)
+#define warn_color(c)
+       *color = CLR_WHITE;
+#endif
+
+       if ((offset = (g - GLYPH_WARNING_OFF)) >= 0) {    /* a warning flash */
+               *ch = warnsyms[offset];
+               warn_color(offset);
+       } else if ((offset = (g - GLYPH_SWALLOW_OFF)) >= 0) {   /* swallow */
+               /* see swallow_to_glyph() in display.c */
+               *ch = (uchar) showsyms[S_sw_tl + (offset & 0x7)];
+               mon_color(offset >> 3);
+       } else if ((offset = (g - GLYPH_ZAP_OFF)) >= 0) {       /* zap beam */
+               /* see zapdir_to_glyph() in display.c */
+               *ch = showsyms[S_vbeam + (offset & 0x3)];
+               zap_color((offset >> 2));
+       } else if ((offset = (g - GLYPH_CMAP_OFF)) >= 0) {      /* cmap */
+               *ch = showsyms[offset];
+               cmap_color(offset);
+       } else if ((offset = (g - GLYPH_OBJ_OFF)) >= 0) {       /* object */
+               *ch = oc_syms[(int)objects[offset].oc_class];
+               obj_color(offset);
+       } else if ((offset = (g - GLYPH_BODY_OFF)) >= 0) {      /* a corpse */
+               *ch = oc_syms[(int)objects[CORPSE].oc_class];
+               mon_color(offset);
+       } else if ((offset = (g - GLYPH_PET_OFF)) >= 0) {       /* a pet */
+               *ch = monsyms[(int)mons[offset].mlet];
+               pet_color(offset);
+       } else {                                                        /* a monster */
+               *ch = monsyms[(int)mons[g].mlet];
+               mon_color(g);
+       }       
+       // end of wintty code
+}
+#endif
+
+/* map nethack color to RGB */
+COLORREF nhcolor_to_RGB(int c)
+{
+       switch(c) {
+       case CLR_BLACK:                 return RGB(0x55, 0x55, 0x55);
+       case CLR_RED:                   return RGB(0xFF, 0x00, 0x00);
+       case CLR_GREEN:                 return RGB(0x00, 0x80, 0x00);
+       case CLR_BROWN:                 return RGB(0xA5, 0x2A, 0x2A);
+       case CLR_BLUE:                  return RGB(0x00, 0x00, 0xFF);
+       case CLR_MAGENTA:               return RGB(0xFF, 0x00, 0xFF);
+       case CLR_CYAN:                  return RGB(0x00, 0xFF, 0xFF);
+       case CLR_GRAY:                  return RGB(0xC0, 0xC0, 0xC0);
+       case NO_COLOR:                  return RGB(0xFF, 0xFF, 0xFF);
+       case CLR_ORANGE:                return RGB(0xFF, 0xA5, 0x00);
+       case CLR_BRIGHT_GREEN:          return RGB(0x00, 0xFF, 0x00);
+       case CLR_YELLOW:                return RGB(0xFF, 0xFF, 0x00);
+       case CLR_BRIGHT_BLUE:           return RGB(0x00, 0xC0, 0xFF);
+       case CLR_BRIGHT_MAGENTA:        return RGB(0xFF, 0x80, 0xFF);
+       case CLR_BRIGHT_CYAN:           return RGB(0x80, 0xFF, 0xFF);   /* something close to aquamarine */
+       case CLR_WHITE:                 return RGB(0xFF, 0xFF, 0xFF);
+       default:                        return RGB(0x00, 0x00, 0x00);   /* black */
+       }
+}
+
+/* apply bitmap pointed by sourceDc transparently over 
+   bitmap pointed by hDC */
+
+typedef BOOL (WINAPI* LPTRANSPARENTBLT)(HDC, int, int, int, int, HDC, int, int, int, int, UINT); 
+void nhapply_image_transparent( 
+       HDC hDC, int x, int y, int width, int height,
+       HDC sourceDC, int s_x, int s_y, int s_width, int s_height,
+       COLORREF cTransparent
+)
+{
+    /* Don't use TransparentBlt; According to Microsoft, it contains a memory leak in Window 95/98. */
+               HDC        hdcMem, hdcBack, hdcObject, hdcSave;
+               COLORREF   cColor;
+               HBITMAP    bmAndBack, bmAndObject, bmAndMem, bmSave;
+               HBITMAP    bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;
+
+               /* Create some DCs to hold temporary data. */
+               hdcBack   = CreateCompatibleDC(hDC);
+               hdcObject = CreateCompatibleDC(hDC);
+               hdcMem    = CreateCompatibleDC(hDC);
+               hdcSave   = CreateCompatibleDC(hDC);
+
+               /* this is bitmap for our pet image */
+               bmSave = CreateCompatibleBitmap(hDC, width, height);
+
+               /* Monochrome DC */
+               bmAndBack   = CreateBitmap(width, height, 1, 1, NULL);
+               bmAndObject = CreateBitmap(width, height, 1, 1, NULL);
+
+               /* resulting bitmap */
+               bmAndMem    = CreateCompatibleBitmap(hDC, width, height);
+
+               /* Each DC must select a bitmap object to store pixel data. */
+               bmBackOld   = SelectObject(hdcBack, bmAndBack);
+               bmObjectOld = SelectObject(hdcObject, bmAndObject);
+               bmMemOld    = SelectObject(hdcMem, bmAndMem);
+               bmSaveOld   = SelectObject(hdcSave, bmSave);
+
+               /* copy source image because it is going to be overwritten */
+               StretchBlt(hdcSave, 0, 0, width, height, sourceDC, s_x, s_y, s_width, s_height, SRCCOPY);
+
+               /* Set the background color of the source DC to the color.
+                  contained in the parts of the bitmap that should be transparent */
+               cColor = SetBkColor(hdcSave, cTransparent);
+
+               /* Create the object mask for the bitmap by performing a BitBlt
+                  from the source bitmap to a monochrome bitmap. */
+               BitBlt(hdcObject, 0, 0, width, height, hdcSave, 0, 0, SRCCOPY);
+
+               /* Set the background color of the source DC back to the original
+                  color. */
+               SetBkColor(hdcSave, cColor);
+
+               /* Create the inverse of the object mask. */
+               BitBlt(hdcBack, 0, 0, width, height, hdcObject, 0, 0, NOTSRCCOPY);
+
+               /* Copy background to the resulting image  */
+               BitBlt(hdcMem, 0, 0, width, height, hDC, x, y, SRCCOPY);
+
+               /* Mask out the places where the source image will be placed. */
+               BitBlt(hdcMem, 0, 0, width, height, hdcObject, 0, 0, SRCAND);
+
+               /* Mask out the transparent colored pixels on the source image. */
+               BitBlt(hdcSave, 0, 0, width, height, hdcBack, 0, 0, SRCAND);
+
+               /* XOR the source image with the beckground. */
+               BitBlt(hdcMem, 0, 0, width, height, hdcSave, 0, 0, SRCPAINT);
+
+               /* blt resulting image to the screen */
+               BitBlt( 
+                       hDC, 
+                       x, y, width, height, hdcMem,
+                       0, 0, SRCCOPY 
+               );
+
+               /* cleanup */
+               DeleteObject(SelectObject(hdcBack, bmBackOld));
+               DeleteObject(SelectObject(hdcObject, bmObjectOld));
+               DeleteObject(SelectObject(hdcMem, bmMemOld));
+               DeleteObject(SelectObject(hdcSave, bmSaveOld));
+
+               DeleteDC(hdcMem);
+               DeleteDC(hdcBack);
+               DeleteDC(hdcObject);
+               DeleteDC(hdcSave);
+}
diff --git a/win/win32/mhmap.h b/win/win32/mhmap.h
new file mode 100644 (file)
index 0000000..401561d
--- /dev/null
@@ -0,0 +1,21 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINMapWindow_h
+#define MSWINMapWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+
+HWND mswin_init_map_window (void);
+void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw);
+int mswin_map_mode(HWND hWnd, int mode);
+
+#define ROGUE_LEVEL_MAP_MODE           MAP_MODE_ASCII12x16     
+
+#define DEF_CLIPAROUND_MARGIN  5
+#define DEF_CLIPAROUND_AMOUNT  1
+
+#endif /* MSWINMapWindow_h */
diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c
new file mode 100644 (file)
index 0000000..94fc0cb
--- /dev/null
@@ -0,0 +1,1448 @@
+/*     SCCS Id: @(#)mhmenu.c   3.4     2002/03/06      */
+/* Copyright (c) Alex Kompel, 2002                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include <assert.h>
+#include "resource.h"
+#include "mhmenu.h"
+#include "mhmain.h"
+#include "mhmsg.h"
+#include "mhfont.h"
+#include "mhdlg.h"
+
+#define MENU_MARGIN            0
+#define NHMENU_STR_SIZE                BUFSZ
+#define MIN_TABSTOP_SIZE       0
+#define NUMTABS                        15
+#define TAB_SEPARATION         10 /* pixels between each tab stop */
+
+#define DEFAULT_COLOR_BG_TEXT  COLOR_WINDOW
+#define DEFAULT_COLOR_FG_TEXT  COLOR_WINDOWTEXT
+#define DEFAULT_COLOR_BG_MENU  COLOR_WINDOW
+#define DEFAULT_COLOR_FG_MENU  COLOR_WINDOWTEXT
+
+typedef struct mswin_menu_item {
+       int                     glyph;
+       ANY_P                   identifier;
+       CHAR_P          accelerator;
+       CHAR_P          group_accel;
+       int                     attr;
+       char                    str[NHMENU_STR_SIZE];
+       BOOLEAN_P               presel;
+       int                     count;
+       BOOL                    has_focus;
+} NHMenuItem, *PNHMenuItem;
+
+typedef struct mswin_nethack_menu_window {
+       int type;               /* MENU_TYPE_TEXT or MENU_TYPE_MENU */
+       int how;                /* for menus: PICK_NONE, PICK_ONE, PICK_ANY */
+
+       union {
+               struct menu_list {
+                       int                      size;                  /* number of items in items[] */
+                       int                      allocated;                     /* number of allocated slots in items[] */
+                       PNHMenuItem              items;                 /* menu items */
+                       char                     gacc[QBUFSZ];          /* group accelerators */
+                       BOOL                     counting;                      /* counting flag */
+                       char                     prompt[QBUFSZ];                /* menu prompt */
+                       int                      tab_stop_size[NUMTABS];/* tabstops to align option values */
+               } menu;
+
+               struct menu_text {
+                       TCHAR*                  text;
+               } text;
+       };
+       int result;
+       int done;
+
+       HBITMAP bmpChecked;
+       HBITMAP bmpCheckedCount;
+       HBITMAP bmpNotChecked;
+} NHMenuWindow, *PNHMenuWindow;
+
+extern short glyph2tile[];
+
+static WNDPROC wndProcListViewOrig = NULL;
+static WNDPROC editControlWndProc = NULL;
+
+#define NHMENU_IS_SELECTABLE(item) ((item).identifier.a_obj!=NULL)
+#define NHMENU_IS_SELECTED(item) ((item).count!=0)
+
+BOOL   CALLBACK        MenuWndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK       NHMenuListWndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK       NHMenuTextWndProc(HWND, UINT, WPARAM, LPARAM);
+static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static BOOL onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static BOOL onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void LayoutMenu(HWND hwnd);
+static void SetMenuType(HWND hwnd, int type);
+static void SetMenuListType(HWND hwnd, int now);
+static HWND GetMenuControl(HWND hwnd);
+static void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count);
+static void reset_menu_count(HWND hwndList, PNHMenuWindow data);
+static BOOL onListChar(HWND hWnd, HWND hwndList, WORD ch);
+
+/*-----------------------------------------------------------------------------*/
+HWND mswin_init_menu_window (int type) {
+       HWND ret;
+
+       ret = CreateDialog(
+                       GetNHApp()->hApp,
+                       MAKEINTRESOURCE(IDD_MENU),
+                       GetNHApp()->hMainWnd,
+                       MenuWndProc
+       );
+       if( !ret ) {
+               panic("Cannot create menu window");
+       }
+       
+       SetMenuType(ret, type);
+       return ret;
+}
+/*-----------------------------------------------------------------------------*/
+int mswin_menu_window_select_menu (HWND hWnd, int how, MENU_ITEM_P ** _selected)
+{
+       PNHMenuWindow data;
+       int ret_val;
+    MENU_ITEM_P *selected = NULL;
+       int i;
+       char* ap;
+
+       assert( _selected!=NULL );
+       *_selected = NULL;
+       ret_val = -1;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       /* set menu type */
+       SetMenuListType(hWnd, how);
+
+       /* Ok, now give items a unique accelerators */
+       if( data->type == MENU_TYPE_MENU ) {
+               char next_char = 'a';
+
+               data->menu.gacc[0] = '\0';
+               ap = data->menu.gacc;
+               for( i=0; i<data->menu.size;  i++) {
+                       if( data->menu.items[i].accelerator!=0 ) {
+                               next_char = (char)(data->menu.items[i].accelerator+1);
+                       } else if( NHMENU_IS_SELECTABLE(data->menu.items[i]) ) {
+                               if ( (next_char>='a' && next_char<='z') ||
+                                        (next_char>='A' && next_char<='Z') )  {
+                                        data->menu.items[i].accelerator = next_char;
+                               } else {
+                                       if( next_char > 'z' ) next_char = 'A';
+                                       else if ( next_char > 'Z' ) break;
+
+                                       data->menu.items[i].accelerator = next_char;
+                               }
+
+                               next_char ++;
+                       }
+               }
+
+               /* collect group accelerators */
+               for( i=0; i<data->menu.size;  i++) {
+                       if( data->how != PICK_NONE ) {
+                               if( data->menu.items[i].group_accel && 
+                                       !strchr(data->menu.gacc, data->menu.items[i].group_accel) ) {
+                                       *ap++ = data->menu.items[i].group_accel;
+                                       *ap = '\x0';
+                               }
+                       }
+               }
+
+               reset_menu_count(NULL, data);
+       }
+
+       mswin_popup_display(hWnd, &data->done);
+
+       /* get the result */
+       if( data->result != -1 ) {
+               if(how==PICK_NONE) {
+                       if(data->result>=0) ret_val=0;
+                       else                            ret_val=-1;
+               } else if(how==PICK_ONE || how==PICK_ANY) {
+                       /* count selected items */
+                       ret_val = 0;
+                       for(i=0; i<data->menu.size; i++ ) {
+                               if( NHMENU_IS_SELECTABLE(data->menu.items[i]) &&
+                                       NHMENU_IS_SELECTED(data->menu.items[i]) ) {
+                                       ret_val++;
+                               }
+                       }
+                       if( ret_val > 0 ) {
+                               int sel_ind;
+
+                               selected = (MENU_ITEM_P*)malloc(ret_val*sizeof(MENU_ITEM_P));
+                               if( !selected ) panic("out of memory");
+
+                               sel_ind = 0;
+                               for(i=0; i<data->menu.size; i++ ) {
+                                       if( NHMENU_IS_SELECTABLE(data->menu.items[i]) &&
+                                               NHMENU_IS_SELECTED(data->menu.items[i]) ) {
+                                               selected[sel_ind].item = data->menu.items[i].identifier;
+                                               selected[sel_ind].count = data->menu.items[i].count;
+                                               sel_ind++;
+                                       }
+                               }
+                               ret_val = sel_ind;
+                               *_selected = selected;
+                       }
+               }
+       }
+
+       mswin_popup_destroy(hWnd);
+
+       return ret_val;
+}
+/*-----------------------------------------------------------------------------*/   
+BOOL CALLBACK MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       PNHMenuWindow data;
+       HWND control;
+       HDC  hdc;
+    TCHAR title[MAX_LOADSTRING];
+
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch (message) 
+       {
+       case WM_INITDIALOG:
+               data = (PNHMenuWindow)malloc(sizeof(NHMenuWindow));
+               ZeroMemory(data, sizeof(NHMenuWindow));
+               data->type = MENU_TYPE_TEXT;
+               data->how = PICK_NONE;
+               data->result = 0;
+               data->done = 0;
+               data->bmpChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL));
+               data->bmpCheckedCount = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT));
+               data->bmpNotChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_UNSEL));
+               SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
+
+               /* set font for the text cotrol */
+               control = GetDlgItem(hWnd, IDC_MENU_TEXT);
+               hdc = GetDC(control);
+               SendMessage(control, WM_SETFONT, (WPARAM)mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE), (LPARAM)0);
+               ReleaseDC(control, hdc);
+
+               /* subclass edit control */
+               editControlWndProc = (WNDPROC)GetWindowLong(control, GWL_WNDPROC);
+               SetWindowLong(control, GWL_WNDPROC, (LONG)NHMenuTextWndProc);
+
+        /* Even though the dialog has no caption, you can still set the title 
+           which shows on Alt-Tab */
+        LoadString(GetNHApp()->hApp, IDS_APP_TITLE, title, MAX_LOADSTRING);
+        SetWindowText(hWnd, title);
+       break;
+
+       case WM_MSNH_COMMAND:
+               onMSNHCommand(hWnd, wParam, lParam);
+       break;
+
+       case WM_SIZE:
+               LayoutMenu(hWnd);
+       return FALSE;
+
+       case WM_CLOSE:
+           if (program_state.gameover) {
+               data->result = -1;
+               data->done = 1;
+               program_state.stopprint++;
+               return TRUE;
+           } else
+               return FALSE;
+
+       case WM_COMMAND: 
+       {
+               switch (LOWORD(wParam)) 
+        { 
+               case IDCANCEL:
+                       if( data->type == MENU_TYPE_MENU && 
+                           (data->how==PICK_ONE || data->how==PICK_ANY) &&
+                           data->menu.counting) {
+                               HWND list;
+                               int i;
+
+                               /* reset counter if counting is in progress */
+                               list = GetMenuControl(hWnd);
+                               i = ListView_GetNextItem(list, -1,      LVNI_FOCUSED);
+                               if( i>=0 ) {
+                                       SelectMenuItem(list, data, i,  0);
+                               }
+                               return TRUE;
+                       } else {
+                               data->result = -1;
+                               data->done = 1;
+                       }
+               return TRUE;
+
+               case IDOK:
+                       data->done = 1;
+                       data->result = 0;
+               return TRUE;
+
+        case IDC_MENU_TEXT:
+          switch (HIWORD(wParam))
+          {
+            case EN_SETFOCUS:
+              HideCaret((HWND)lParam);
+              return TRUE;
+          }
+               }
+       } break;
+
+       case WM_NOTIFY:
+       {
+               LPNMHDR lpnmhdr = (LPNMHDR)lParam;
+               switch (LOWORD(wParam)) {
+               case IDC_MENU_LIST:
+               {
+                       if( !data || data->type!=MENU_TYPE_MENU ) break;
+
+                       switch(lpnmhdr->code) {
+                       case LVN_ITEMACTIVATE: 
+                       {
+                               LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam;
+                               if(data->how==PICK_ONE) {
+                                       if( lpnmlv->iItem>=0 &&
+                                               lpnmlv->iItem<data->menu.size &&
+                                               NHMENU_IS_SELECTABLE(data->menu.items[lpnmlv->iItem]) ) {
+                                               SelectMenuItem(
+                                                       lpnmlv->hdr.hwndFrom, 
+                                                       data, 
+                                                       lpnmlv->iItem, 
+                                                       -1
+                                               );
+                                               data->done = 1;
+                                               data->result = 0;
+                                               return TRUE;
+                                       }
+                               }
+                       } break;
+
+                       case NM_CLICK: {
+                               LPNMLISTVIEW lpnmitem = (LPNMLISTVIEW) lParam;
+                               if( lpnmitem->iItem==-1 ) return 0;
+                               if( data->how==PICK_ANY ) {
+                                       SelectMenuItem(
+                                               lpnmitem->hdr.hwndFrom, 
+                                               data, 
+                                               lpnmitem->iItem, 
+                                               NHMENU_IS_SELECTED(data->menu.items[lpnmitem->iItem])? 0 : -1
+                                       );
+                               }
+                       } break;
+
+                       case LVN_ITEMCHANGED: 
+                       {
+                               LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam;
+                               if( lpnmlv->iItem==-1 ) return 0;
+                               if( !(lpnmlv->uChanged & LVIF_STATE) ) return 0;
+
+                               if( data->how==PICK_ONE || data->how==PICK_ANY ) {
+                                       data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED);
+                                       ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem);
+                               }
+
+                               /* update count for single-selection menu (follow the listview selection) */
+                               if( data->how==PICK_ONE ) {
+                                       if( lpnmlv->uNewState & LVIS_SELECTED ) {
+                                               SelectMenuItem(
+                                                       lpnmlv->hdr.hwndFrom, 
+                                                       data, 
+                                                       lpnmlv->iItem, 
+                                                       -1
+                                               );
+                                       }
+                               }
+
+                               /* check item focus */
+                               if( data->how==PICK_ONE || data->how==PICK_ANY ) {
+                                       data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED);
+                                       ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem);
+                               }
+                       } break;
+
+                       case NM_KILLFOCUS:
+                               reset_menu_count(lpnmhdr->hwndFrom, data);
+                       break;
+
+                       }
+               } break;
+               }
+       } break;
+
+       case WM_SETFOCUS:
+               if( hWnd!=GetNHApp()->hPopupWnd ) {
+                       SetFocus(GetNHApp()->hPopupWnd );
+               }
+       break;
+       
+    case WM_MEASUREITEM: 
+               if( wParam==IDC_MENU_LIST )
+                       return onMeasureItem(hWnd, wParam, lParam);
+               else
+                       return FALSE;
+
+    case WM_DRAWITEM:
+               if( wParam==IDC_MENU_LIST )
+                       return onDrawItem(hWnd, wParam, lParam);
+               else
+                       return FALSE;
+
+       case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */
+               HDC hdcEdit = (HDC) wParam; 
+               HWND hwndEdit = (HWND) lParam;
+               if( hwndEdit == GetDlgItem(hWnd, IDC_MENU_TEXT) ) {
+                       SetBkColor(hdcEdit, 
+                               text_bg_brush ? text_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_TEXT)
+                               );
+                       SetTextColor(hdcEdit, 
+                               text_fg_brush ? text_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_TEXT) 
+                               ); 
+                       return (BOOL)(text_bg_brush 
+                                       ? text_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT));
+               }
+       } return FALSE;
+
+       case WM_DESTROY:
+               if( data ) {
+                       DeleteObject(data->bmpChecked);
+                       DeleteObject(data->bmpCheckedCount);
+                       DeleteObject(data->bmpNotChecked);
+                       if( data->type == MENU_TYPE_TEXT ) {
+                               if( data->text.text ) free(data->text.text);
+                       }
+                       free(data);
+                       SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+               }
+               return TRUE;
+       }
+       return FALSE;
+}
+/*-----------------------------------------------------------------------------*/
+void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMenuWindow data;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch( wParam ) {
+       case MSNH_MSG_PUTSTR: 
+       {
+               PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
+               HWND   text_view;
+               TCHAR   wbuf[BUFSZ];
+               size_t text_size;
+
+               if( data->type!=MENU_TYPE_TEXT )
+                       SetMenuType(hWnd, MENU_TYPE_TEXT);
+
+               if( !data->text.text ) {
+                       text_size = strlen(msg_data->text) + 4;
+                       data->text.text = (TCHAR*)malloc(text_size*sizeof(data->text.text[0]));
+                       ZeroMemory(data->text.text, text_size*sizeof(data->text.text[0]));
+               } else {
+                       text_size = _tcslen(data->text.text) + strlen(msg_data->text) + 4;
+                       data->text.text = (TCHAR*)realloc(data->text.text, text_size*sizeof(data->text.text[0]));
+               }
+               if( !data->text.text ) break;
+               
+               _tcscat(data->text.text, NH_A2W(msg_data->text, wbuf, BUFSZ)); 
+               _tcscat(data->text.text, TEXT("\r\n"));
+               
+               text_view = GetDlgItem(hWnd, IDC_MENU_TEXT);
+               if( !text_view ) panic("cannot get text view window");
+               SetWindowText(text_view, data->text.text);
+       } break;
+
+       case MSNH_MSG_STARTMENU:
+       {
+               int i;
+               if( data->type!=MENU_TYPE_MENU )
+                       SetMenuType(hWnd, MENU_TYPE_MENU);
+
+               if( data->menu.items ) free(data->menu.items);
+               data->how = PICK_NONE;
+               data->menu.items = NULL;
+               data->menu.size = 0;
+               data->menu.allocated = 0;
+               data->done = 0;
+               data->result = 0;
+               for (i = 0; i < NUMTABS; ++i)
+                       data->menu.tab_stop_size[i] = MIN_TABSTOP_SIZE;
+       } break;
+
+       case MSNH_MSG_ADDMENU:
+       {
+               PMSNHMsgAddMenu msg_data = (PMSNHMsgAddMenu)lParam;
+               char *p, *p1;
+               int new_item;
+               HDC hDC;
+               int column;
+               HFONT saveFont;
+               
+               if( data->type!=MENU_TYPE_MENU ) break;
+               if( strlen(msg_data->str)==0 ) break;
+
+               if( data->menu.size==data->menu.allocated ) {
+                       data->menu.allocated += 10;
+                       data->menu.items = (PNHMenuItem)realloc(data->menu.items, data->menu.allocated*sizeof(NHMenuItem));
+               }
+
+               new_item = data->menu.size;
+               ZeroMemory( &data->menu.items[new_item], sizeof(data->menu.items[new_item]));
+               data->menu.items[new_item].glyph = msg_data->glyph;
+               data->menu.items[new_item].identifier = *msg_data->identifier;
+               data->menu.items[new_item].accelerator = msg_data->accelerator;
+               data->menu.items[new_item].group_accel = msg_data->group_accel;
+               data->menu.items[new_item].attr = msg_data->attr;
+               strncpy(data->menu.items[new_item].str, msg_data->str, NHMENU_STR_SIZE);
+               data->menu.items[new_item].presel = msg_data->presel;
+
+               /* calculate tabstop size */
+               hDC = GetDC(hWnd);
+               saveFont = SelectObject(hDC, mswin_get_font(NHW_MENU, msg_data->attr, hDC, FALSE));
+               p1 = data->menu.items[new_item].str;
+               p = strchr(data->menu.items[new_item].str, '\t');
+               column = 0;
+               for (;;) {
+                       TCHAR wbuf[BUFSZ];
+                       RECT drawRect;
+                       SetRect ( &drawRect, 0, 0, 1, 1 );
+                       if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */
+                       DrawText(hDC,
+                               NH_A2W(p1, wbuf, BUFSZ),
+                               strlen(p1),
+                               &drawRect,
+                               DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_EXPANDTABS | DT_SINGLELINE
+                       );
+                       data->menu.tab_stop_size[column] =
+                               max( data->menu.tab_stop_size[column], drawRect.right - drawRect.left );
+                       if (p != NULL) *p = '\t';
+                       else /* last string so, */ break;
+
+                       ++column;
+                       p1 = p + 1;
+                       p = strchr(p1, '\t');
+               }
+               SelectObject(hDC, saveFont);
+               ReleaseDC(hWnd, hDC);
+
+               /* increment size */
+               data->menu.size++;
+       } break;
+
+       case MSNH_MSG_ENDMENU:
+       {
+               PMSNHMsgEndMenu msg_data = (PMSNHMsgEndMenu)lParam;
+               if( msg_data->text ) {
+                       strncpy( data->menu.prompt, msg_data->text, sizeof(data->menu.prompt)-1 );
+               } else {
+                       ZeroMemory(data->menu.prompt, sizeof(data->menu.prompt));
+               }
+       } break;
+
+       }
+}
+/*-----------------------------------------------------------------------------*/
+void LayoutMenu(HWND hWnd) 
+{
+       PNHMenuWindow data;
+       HWND  menu_ok;
+       HWND  menu_cancel;
+       RECT  clrt, rt;
+       POINT pt_elem, pt_ok, pt_cancel;
+       SIZE  sz_elem, sz_ok, sz_cancel;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       menu_ok = GetDlgItem(hWnd, IDOK);
+       menu_cancel = GetDlgItem(hWnd, IDCANCEL);
+
+       /* get window coordinates */
+       GetClientRect(hWnd, &clrt );
+       
+       /* set window placements */
+       GetWindowRect(menu_ok, &rt);
+       sz_ok.cx = (clrt.right - clrt.left)/2 - 2*MENU_MARGIN;
+       sz_ok.cy = rt.bottom-rt.top;
+       pt_ok.x = clrt.left + MENU_MARGIN;
+       pt_ok.y = clrt.bottom - MENU_MARGIN - sz_ok.cy;
+
+       GetWindowRect(menu_cancel, &rt);
+       sz_cancel.cx = (clrt.right - clrt.left)/2 - 2*MENU_MARGIN;
+       sz_cancel.cy = rt.bottom-rt.top;
+       pt_cancel.x = (clrt.left + clrt.right)/2 + MENU_MARGIN;
+       pt_cancel.y = clrt.bottom - MENU_MARGIN - sz_cancel.cy;
+
+       pt_elem.x = clrt.left + MENU_MARGIN;
+       pt_elem.y = clrt.top + MENU_MARGIN;
+       sz_elem.cx = (clrt.right - clrt.left) - 2*MENU_MARGIN;
+       sz_elem.cy = min(pt_cancel.y, pt_ok.y) - 2*MENU_MARGIN;
+
+       MoveWindow(GetMenuControl(hWnd), pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE );
+       MoveWindow(menu_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE );
+       MoveWindow(menu_cancel, pt_cancel.x, pt_cancel.y, sz_cancel.cx, sz_cancel.cy, TRUE );
+}
+/*-----------------------------------------------------------------------------*/
+void SetMenuType(HWND hWnd, int type)
+{
+       PNHMenuWindow data;
+       HWND list, text;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       data->type = type;
+       
+       text = GetDlgItem(hWnd, IDC_MENU_TEXT);
+       list = GetDlgItem(hWnd, IDC_MENU_LIST);
+       if(data->type==MENU_TYPE_TEXT) {
+               ShowWindow(list, SW_HIDE);
+               EnableWindow(list, FALSE);
+               EnableWindow(text, TRUE);
+               ShowWindow(text, SW_SHOW);
+               SetFocus(text);
+       } else {
+               ShowWindow(text, SW_HIDE);
+               EnableWindow(text, FALSE);
+               EnableWindow(list, TRUE);
+               ShowWindow(list, SW_SHOW);
+               SetFocus(list);
+       }
+       LayoutMenu(hWnd);
+}
+/*-----------------------------------------------------------------------------*/
+void SetMenuListType(HWND hWnd, int how)
+{
+       PNHMenuWindow data;
+       RECT rt;
+       DWORD dwStyles;
+       char buf[BUFSZ];
+       TCHAR wbuf[BUFSZ];
+       int nItem;
+       int i;
+       HWND control;
+       LVCOLUMN lvcol;
+       LRESULT fnt;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if( data->type != MENU_TYPE_MENU ) return;
+
+       data->how = how;
+
+       switch(how) {
+       case PICK_NONE: 
+               dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD 
+                       | WS_VSCROLL | WS_HSCROLL | LVS_REPORT  
+                       | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; 
+               break;
+       case PICK_ONE: 
+               dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD 
+                       | WS_VSCROLL | WS_HSCROLL | LVS_REPORT  
+                       | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; 
+               break;
+       case PICK_ANY: 
+               dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD 
+                       | WS_VSCROLL | WS_HSCROLL | LVS_REPORT  
+                       | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; 
+               break;
+       default: panic("how should be one of PICK_NONE, PICK_ONE or PICK_ANY");
+       };
+
+       if( strlen(data->menu.prompt)==0 ) {
+               dwStyles |= LVS_NOCOLUMNHEADER ;
+       }
+
+       GetWindowRect(GetDlgItem(hWnd, IDC_MENU_LIST), &rt);
+       DestroyWindow(GetDlgItem(hWnd, IDC_MENU_LIST));
+       control = CreateWindow(WC_LISTVIEW, NULL, 
+               dwStyles,
+               rt.left,
+               rt.top,
+               rt.right - rt.left,
+               rt.bottom - rt.top,
+               hWnd,
+               (HMENU)IDC_MENU_LIST,
+               GetNHApp()->hApp,
+               NULL );
+       if( !control ) panic( "cannot create menu control" );
+       
+       /* install the hook for the control window procedure */
+       wndProcListViewOrig = (WNDPROC)GetWindowLong(control, GWL_WNDPROC);
+       SetWindowLong(control, GWL_WNDPROC, (LONG)NHMenuListWndProc);
+
+       /* set control colors */
+       ListView_SetBkColor(control, 
+               menu_bg_brush ? menu_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MENU));
+       ListView_SetTextBkColor(control, 
+               menu_bg_brush ? menu_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MENU));
+       ListView_SetTextColor(control, 
+               menu_fg_brush ? menu_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_MENU));
+
+       /* set control font */
+       fnt = SendMessage(hWnd, WM_GETFONT, (WPARAM)0, (LPARAM)0);
+       SendMessage(control, WM_SETFONT, (WPARAM)fnt, (LPARAM)0);
+
+       /* add column to the list view */
+       ZeroMemory(&lvcol, sizeof(lvcol));
+       lvcol.mask = LVCF_WIDTH | LVCF_TEXT;
+       lvcol.cx = GetSystemMetrics(SM_CXFULLSCREEN);
+       lvcol.pszText = NH_A2W(data->menu.prompt, wbuf, BUFSZ);
+       ListView_InsertColumn(control, 0, &lvcol);
+
+       /* add items to the list view */
+       for(i=0; i<data->menu.size; i++ ) {
+               LVITEM lvitem;
+               ZeroMemory( &lvitem, sizeof(lvitem) );
+               sprintf(buf, "%c - %s", max(data->menu.items[i].accelerator, ' '), data->menu.items[i].str );
+
+               lvitem.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
+               lvitem.iItem = i;
+               lvitem.iSubItem = 0;
+               lvitem.state = data->menu.items[i].presel? LVIS_SELECTED : 0;
+               lvitem.pszText = NH_A2W(buf, wbuf, BUFSZ);
+               lvitem.lParam = (LPARAM)&data->menu.items[i];
+               nItem = SendMessage(control, LB_ADDSTRING, (WPARAM)0, (LPARAM) buf); 
+               if( ListView_InsertItem(control, &lvitem)==-1 ) {
+                       panic("cannot insert menu item");
+               }
+       }
+       SetFocus(control);
+}
+/*-----------------------------------------------------------------------------*/
+HWND GetMenuControl(HWND hWnd)
+{
+       PNHMenuWindow data;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       if(data->type==MENU_TYPE_TEXT) {
+               return GetDlgItem(hWnd, IDC_MENU_TEXT);
+       } else {
+               return GetDlgItem(hWnd, IDC_MENU_LIST);
+       }
+}
+/*-----------------------------------------------------------------------------*/
+BOOL onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+    LPMEASUREITEMSTRUCT lpmis; 
+    TEXTMETRIC tm;
+       HGDIOBJ saveFont;
+       HDC hdc;
+       PNHMenuWindow data;
+       RECT list_rect;
+
+    lpmis = (LPMEASUREITEMSTRUCT) lParam; 
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       GetClientRect(GetMenuControl(hWnd), &list_rect);
+
+       hdc = GetDC(GetMenuControl(hWnd));
+       saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, FALSE));
+       GetTextMetrics(hdc, &tm);
+
+    /* Set the height of the list box items. */
+    lpmis->itemHeight = max(tm.tmHeight, TILE_Y)+2;
+       lpmis->itemWidth = list_rect.right - list_rect.left;
+
+       SelectObject(hdc, saveFont);
+       ReleaseDC(GetMenuControl(hWnd), hdc);
+       return TRUE;
+}
+/*-----------------------------------------------------------------------------*/
+BOOL onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       LPDRAWITEMSTRUCT lpdis;
+       PNHMenuItem item;
+       PNHMenuWindow data;
+       TEXTMETRIC tm;
+       HGDIOBJ saveFont;
+       HDC tileDC;
+       short ntile;
+       int t_x, t_y;
+       int x, y;
+       TCHAR wbuf[BUFSZ];
+       RECT drawRect;
+       COLORREF OldBg, OldFg, NewBg;
+       char *p, *p1;
+       int column;
+
+       lpdis = (LPDRAWITEMSTRUCT) lParam; 
+
+    /* If there are no list box items, skip this message. */
+    if (lpdis->itemID == -1) return FALSE;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+    item = &data->menu.items[lpdis->itemID];
+
+       tileDC = CreateCompatibleDC(lpdis->hDC);
+       saveFont = SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, item->attr, lpdis->hDC, FALSE));
+       NewBg = menu_bg_brush ? menu_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MENU);
+       OldBg = SetBkColor(lpdis->hDC, NewBg);
+       OldFg = SetTextColor(lpdis->hDC, 
+               menu_fg_brush ? menu_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_MENU)); 
+
+    GetTextMetrics(lpdis->hDC, &tm);
+
+       x = lpdis->rcItem.left + 1;
+
+    /* print check mark and letter */
+       if( NHMENU_IS_SELECTABLE(*item) ) {
+ char buf[2];
+ if (data->how != PICK_NONE) {
+               HGDIOBJ saveBrush;
+               HBRUSH  hbrCheckMark;
+
+               switch(item->count) {
+               case -1: hbrCheckMark = CreatePatternBrush(data->bmpChecked); break;
+               case 0: hbrCheckMark = CreatePatternBrush(data->bmpNotChecked); break;
+               default: hbrCheckMark = CreatePatternBrush(data->bmpCheckedCount); break;
+               }
+
+               y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2; 
+               SetBrushOrgEx(lpdis->hDC, x, y, NULL);
+               saveBrush = SelectObject(lpdis->hDC, hbrCheckMark);
+               PatBlt(lpdis->hDC, x, y, TILE_X, TILE_Y, PATCOPY);
+               SelectObject(lpdis->hDC, saveBrush);
+               DeleteObject(hbrCheckMark);
+
+ }
+               x += TILE_X + 5;
+               if(item->accelerator!=0) {
+                       buf[0] = item->accelerator;
+                       buf[1] = '\x0';
+
+                       SetRect( &drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom );
+                       DrawText(lpdis->hDC, NH_A2W(buf, wbuf, 2), 1, &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
+               }
+               x += tm.tmAveCharWidth + tm.tmOverhang + 5;
+       } else {
+               x += TILE_X + tm.tmAveCharWidth + tm.tmOverhang + 10;
+       }
+
+       /* print glyph if present */
+       if( item->glyph != NO_GLYPH ) {
+               HGDIOBJ saveBmp;
+
+               saveBmp = SelectObject(tileDC, GetNHApp()->bmpTiles);                           
+               ntile = glyph2tile[ item->glyph ];
+               t_x = (ntile % TILES_PER_LINE)*TILE_X;
+               t_y = (ntile / TILES_PER_LINE)*TILE_Y;
+
+               y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2; 
+
+               nhapply_image_transparent(
+                       lpdis->hDC, x, y, TILE_X, TILE_Y, 
+                       tileDC, t_x, t_y, TILE_X, TILE_Y, TILE_BK_COLOR );
+               SelectObject(tileDC, saveBmp);
+       }
+
+       x += TILE_X + 5;
+
+       /* draw item text */
+
+       p1 = item->str;
+       p = strchr(item->str, '\t');
+       column = 0;
+       SetRect( &drawRect, x, lpdis->rcItem.top, min(x + data->menu.tab_stop_size[0], lpdis->rcItem.right),
+           lpdis->rcItem.bottom );
+       for (;;) {
+               TCHAR wbuf[BUFSZ];
+               if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */
+               DrawText(lpdis->hDC,
+                       NH_A2W(p1, wbuf, BUFSZ),
+                       strlen(p1),
+                       &drawRect,
+                       DT_LEFT | DT_VCENTER | DT_SINGLELINE
+               );
+               if (p != NULL) *p = '\t';
+               else /* last string so, */ break;
+
+               p1 = p + 1;
+               p = strchr(p1, '\t');
+               drawRect.left = drawRect.right + TAB_SEPARATION;
+               ++column;
+               drawRect.right = min (drawRect.left + data->menu.tab_stop_size[column], lpdis->rcItem.right);
+       }
+
+       /* draw focused item */
+       if( item->has_focus 
+        || (NHMENU_IS_SELECTABLE(*item) && 
+                       data->menu.items[lpdis->itemID].count!=-1)) {
+               RECT client_rt;
+
+               GetClientRect(lpdis->hwndItem, &client_rt);
+               if( NHMENU_IS_SELECTABLE(*item) && 
+                       data->menu.items[lpdis->itemID].count!=0 &&
+                       item->glyph != NO_GLYPH ) {
+                       if( data->menu.items[lpdis->itemID].count==-1 ) {
+                               _stprintf(wbuf, TEXT("Count: All") );
+                       } else {
+                               _stprintf(wbuf, TEXT("Count: %d"), data->menu.items[lpdis->itemID].count );
+                       }
+
+                       SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, ATR_BLINK, lpdis->hDC, FALSE));
+
+                       /* calculate text rectangle */
+                       SetRect( &drawRect, client_rt.left, lpdis->rcItem.top, client_rt.right, lpdis->rcItem.bottom );
+                       DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect, 
+                                        DT_CALCRECT | DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX );
+                       
+                       /* erase text rectangle */
+                       drawRect.left = max(client_rt.left+1, client_rt.right - (drawRect.right - drawRect.left) - 10);
+                       drawRect.right = client_rt.right-1;
+                       drawRect.top = lpdis->rcItem.top;
+                       drawRect.bottom = lpdis->rcItem.bottom;
+                       FillRect(lpdis->hDC, &drawRect, 
+                                        menu_bg_brush ? menu_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_MENU));
+
+                       /* draw text */
+                       DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect, 
+                                        DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX );
+               }
+    }
+    if (item->has_focus) {
+               /* draw focus rect */
+               RECT client_rt;
+
+               GetClientRect(lpdis->hwndItem, &client_rt);
+               SetRect( &drawRect, client_rt.left, lpdis->rcItem.top, client_rt.right, lpdis->rcItem.bottom );
+               DrawFocusRect(lpdis->hDC, &drawRect);
+       }
+
+       SetTextColor (lpdis->hDC, OldFg);
+       SetBkColor (lpdis->hDC, OldBg);
+       SelectObject(lpdis->hDC, saveFont);
+       DeleteDC(tileDC);
+       return TRUE;
+}
+/*-----------------------------------------------------------------------------*/
+BOOL onListChar(HWND hWnd, HWND hwndList, WORD ch)
+{
+       int i = 0;
+       PNHMenuWindow data;
+       int curIndex, topIndex, pageSize;
+       boolean is_accelerator = FALSE;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       switch( ch ) {
+       case MENU_FIRST_PAGE:
+               i = 0;
+               ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
+               ListView_EnsureVisible(hwndList, i, FALSE);
+       return -2;
+
+       case MENU_LAST_PAGE:
+               i = max(0, data->menu.size-1);
+               ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
+               ListView_EnsureVisible(hwndList, i, FALSE);
+       return -2;
+
+       case MENU_NEXT_PAGE:
+               topIndex = ListView_GetTopIndex( hwndList );
+               pageSize = ListView_GetCountPerPage( hwndList );
+        curIndex = ListView_GetNextItem(hwndList, -1,  LVNI_FOCUSED);
+        /* Focus down one page */
+               i = min(curIndex+pageSize, data->menu.size-1);
+               ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
+        /* Scrollpos down one page */
+        i = min(topIndex+(2*pageSize - 1), data->menu.size-1);
+               ListView_EnsureVisible(hwndList, i, FALSE);
+       return -2;
+
+       case MENU_PREVIOUS_PAGE:
+               topIndex = ListView_GetTopIndex( hwndList );
+               pageSize = ListView_GetCountPerPage( hwndList );
+        curIndex = ListView_GetNextItem(hwndList, -1,  LVNI_FOCUSED);
+        /* Focus up one page */
+               i = max(curIndex-pageSize, 0);
+               ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
+        /* Scrollpos up one page */
+               i = max(topIndex-pageSize, 0);
+               ListView_EnsureVisible(hwndList, i, FALSE);
+       break;
+
+       case MENU_SELECT_ALL:
+               if( data->how == PICK_ANY ) {
+                       reset_menu_count(hwndList, data);
+                       for(i=0; i<data->menu.size; i++ ) {
+                               SelectMenuItem(hwndList, data, i, -1);
+                       }
+                       return -2;
+               }
+       break;
+
+       case MENU_UNSELECT_ALL:
+               if( data->how == PICK_ANY ) {
+                       reset_menu_count(hwndList, data);
+                       for(i=0; i<data->menu.size; i++ ) {
+                               SelectMenuItem(hwndList, data, i, 0);
+                       }
+                       return -2;
+               }
+       break;
+
+       case MENU_INVERT_ALL:
+               if( data->how == PICK_ANY ) {
+                       reset_menu_count(hwndList, data);
+                       for(i=0; i<data->menu.size; i++ ) {
+                               SelectMenuItem(
+                                       hwndList, 
+                                       data, 
+                                       i, 
+                                       NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
+                               );
+                       }
+                       return -2;
+               }
+       break;
+
+       case MENU_SELECT_PAGE:
+               if( data->how == PICK_ANY ) {
+                       int from, to;
+                       reset_menu_count(hwndList, data);
+                       topIndex = ListView_GetTopIndex( hwndList );
+                       pageSize = ListView_GetCountPerPage( hwndList );
+                       from = max(0, topIndex);
+                       to = min(data->menu.size, from+pageSize);
+                       for(i=from; i<to; i++ ) {
+                               SelectMenuItem(hwndList, data, i, -1);
+                       }
+                       return -2;
+               }
+       break;
+
+       case MENU_UNSELECT_PAGE:
+               if( data->how == PICK_ANY ) {
+                       int from, to;
+                       reset_menu_count(hwndList, data);
+                       topIndex = ListView_GetTopIndex( hwndList );
+                       pageSize = ListView_GetCountPerPage( hwndList );
+                       from = max(0, topIndex);
+                       to = min(data->menu.size, from+pageSize);
+                       for(i=from; i<to; i++ ) {
+                               SelectMenuItem(hwndList, data, i, 0);
+                       }
+                       return -2;
+               }
+       break;
+
+       case MENU_INVERT_PAGE:
+               if( data->how == PICK_ANY ) {
+                       int from, to;
+                       reset_menu_count(hwndList, data);
+                       topIndex = ListView_GetTopIndex( hwndList );
+                       pageSize = ListView_GetCountPerPage( hwndList );
+                       from = max(0, topIndex);
+                       to = min(data->menu.size, from+pageSize);
+                       for(i=from; i<to; i++ ) {
+                               SelectMenuItem(
+                                       hwndList, 
+                                       data, 
+                                       i, 
+                                       NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
+                               );
+                       }
+                       return -2;
+               }
+       break;
+
+       case MENU_SEARCH:
+           if( data->how==PICK_ANY || data->how==PICK_ONE ) {
+                       char buf[BUFSZ];
+                       
+                       reset_menu_count(hwndList, data);
+                       if( mswin_getlin_window("Search for:", buf, BUFSZ)==IDCANCEL ) {
+                               strcpy(buf, "\033");
+                       }
+                       SetFocus(hwndList);     // set focus back to the list control
+                       if (!*buf || *buf == '\033') return -2;
+                       for(i=0; i<data->menu.size; i++ ) {
+                               if( NHMENU_IS_SELECTABLE(data->menu.items[i])
+                                       && strstr(data->menu.items[i].str, buf) ) {
+                                       if (data->how == PICK_ANY) {
+                                               SelectMenuItem(
+                                                       hwndList, 
+                                                       data, 
+                                                       i, 
+                                                       NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
+                                               );
+                                       } else if( data->how == PICK_ONE ) {
+                                               SelectMenuItem(
+                                                       hwndList, 
+                                                       data, 
+                                                       i, 
+                                                       -1
+                                               );
+                                               ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
+                                               ListView_EnsureVisible(hwndList, i, FALSE);
+                                               break;
+                                       }
+                               }
+                       } 
+               } else {
+                       mswin_nhbell();
+           }
+       return -2;
+
+       case ' ':
+    {
+        if (GetNHApp()->regNetHackMode) {
+            /* NetHack mode: Scroll down one page,
+               ends menu when on last page. */
+            SCROLLINFO si;
+
+            si.cbSize = sizeof(SCROLLINFO);
+            si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
+            GetScrollInfo(hwndList, SB_VERT, &si);
+            if ((si.nPos + (int)si.nPage) > (si.nMax - si.nMin)) {
+                /* We're at the bottom: dismiss. */
+                data->done = 1;
+                           data->result = 0;
+                return -2;
+            }
+            /* We're not at the bottom: page down. */
+                   topIndex = ListView_GetTopIndex( hwndList );
+                   pageSize = ListView_GetCountPerPage( hwndList );
+            curIndex = ListView_GetNextItem(hwndList, -1,      LVNI_FOCUSED);
+            /* Focus down one page */
+                   i = min(curIndex+pageSize, data->menu.size-1);
+                   ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
+            /* Scrollpos down one page */
+            i = min(topIndex+(2*pageSize - 1), data->menu.size-1);
+                   ListView_EnsureVisible(hwndList, i, FALSE);
+
+               return -2;
+        } else {
+                   /* Windows mode: ends menu for PICK_ONE/PICK_NONE
+                      select item for PICK_ANY */
+                   if( data->how==PICK_ONE || data->how==PICK_NONE ) {
+                           data->done = 1;
+                           data->result = 0;
+                           return -2;
+                   } else if( data->how==PICK_ANY ) {
+                           i = ListView_GetNextItem(hwndList, -1,      LVNI_FOCUSED);
+                           if( i>=0 ) {
+                                   SelectMenuItem(
+                                           hwndList, 
+                                           data, 
+                                           i, 
+                                           NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
+                                   );
+                           }
+                   }
+        }
+    }
+       break;
+
+       default:
+               if( strchr(data->menu.gacc, ch) &&
+                       !(ch=='0' && data->menu.counting) ) {
+                       /* matched a group accelerator */
+                       if (data->how == PICK_ANY || data->how == PICK_ONE) {
+                               reset_menu_count(hwndList, data);
+                               for(i=0; i<data->menu.size; i++ ) {
+                                       if( NHMENU_IS_SELECTABLE(data->menu.items[i]) &&
+                                               data->menu.items[i].group_accel == ch ) {
+                                               if( data->how == PICK_ANY ) {
+                                                       SelectMenuItem(
+                                                               hwndList, 
+                                                               data, 
+                                                               i, 
+                                                               NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
+                                                       );
+                                               } else if( data->how == PICK_ONE ) {
+                                                       SelectMenuItem(
+                                                               hwndList, 
+                                                               data, 
+                                                               i, 
+                                                               -1
+                                                       );
+                                                       data->result = 0;
+                                                       data->done = 1;
+                                                       return -2;
+                                               }
+                                       }
+                               }
+                               return -2;
+                       } else {
+                               mswin_nhbell();
+                               return -2;
+                       }
+               }
+
+               if (isdigit(ch)) {
+                       int count;
+                       i = ListView_GetNextItem(hwndList, -1,  LVNI_FOCUSED);
+                       if( i>=0 ) {
+                               count = data->menu.items[i].count;
+                               if( count==-1 ) count=0;
+                               count *= 10L;
+                               count += (int)(ch - '0');
+                               if (count != 0) /* ignore leading zeros */ {
+                                       data->menu.counting = TRUE;
+                                       data->menu.items[i].count = min(100000, count);
+                                       ListView_RedrawItems( hwndList, i, i ); /* update count mark */
+                               }
+                       }
+                       return -2;
+               }
+
+               is_accelerator = FALSE;
+               for(i=0; i<data->menu.size; i++) {
+                       if( data->menu.items[i].accelerator == ch ) {
+                               is_accelerator = TRUE;
+                               break;
+                       }
+               }
+
+               if( (ch>='a' && ch<='z') ||
+                       (ch>='A' && ch<='Z') || is_accelerator) {
+                       if (data->how == PICK_ANY || data->how == PICK_ONE) {
+                               for(i=0; i<data->menu.size; i++ ) {
+                                       if( data->menu.items[i].accelerator == ch ) {
+                                               if( data->how == PICK_ANY ) {
+                                                       SelectMenuItem(
+                                                               hwndList, 
+                                                               data, 
+                                                               i, 
+                                                               NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
+                                                       );
+                                                       ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
+                                                       ListView_EnsureVisible(hwndList, i, FALSE);
+                                                       return -2;
+                                               } else if( data->how == PICK_ONE ) {
+                                                       SelectMenuItem(
+                                                               hwndList, 
+                                                               data, 
+                                                               i, 
+                                                               -1
+                                                       );
+                                                       data->result = 0;
+                                                       data->done = 1;
+                                                       return -2;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       break;
+       }
+
+       reset_menu_count(hwndList, data);
+       return -1;
+}
+/*-----------------------------------------------------------------------------*/
+void mswin_menu_window_size (HWND hWnd, LPSIZE sz)
+{
+    TEXTMETRIC tm;
+       HWND control;
+       HGDIOBJ saveFont;
+       HDC hdc;
+       PNHMenuWindow data;
+       int i;
+       RECT rt, wrt;
+       int extra_cx;
+
+       GetClientRect(hWnd, &rt);
+       sz->cx = rt.right - rt.left;
+       sz->cy = rt.bottom - rt.top;
+
+       GetWindowRect(hWnd, &wrt);
+       extra_cx = (wrt.right-wrt.left) - sz->cx;
+
+       data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if(data) {
+               control = GetMenuControl(hWnd);
+               hdc = GetDC(control);
+
+               if( data->type==MENU_TYPE_MENU ) {
+                       /* Calculate the width of the list box. */
+                       saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE));
+                       GetTextMetrics(hdc, &tm);
+                       for(i=0; i<data->menu.size; i++ ) {
+                               LONG menuitemwidth = 0;
+                               int column;
+                               char *p, *p1;
+
+                               p1 = data->menu.items[i].str;
+                               p = strchr(data->menu.items[i].str, '\t');
+                               column = 0;
+                               for (;;) {
+                                       TCHAR wbuf[BUFSZ];
+                                       RECT tabRect;
+                                       SetRect ( &tabRect, 0, 0, 1, 1 );
+                                       if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */
+                                       DrawText(hdc,
+                                               NH_A2W(p1, wbuf, BUFSZ),
+                                               strlen(p1),
+                                               &tabRect,
+                                               DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE
+                                       );
+                                       /* it probably isn't necessary to recompute the tab width now, but do so
+                                        * just in case, honoring the previously computed value
+                                        */
+                                       menuitemwidth += max(data->menu.tab_stop_size[column],
+                                           tabRect.right - tabRect.left);
+                                       if (p != NULL) *p = '\t';
+                                       else /* last string so, */ break;
+                                       /* add the separation only when not the last item */
+                                       /* in the last item, we break out of the loop, in the statement just above */
+                                       menuitemwidth += TAB_SEPARATION;
+                                       ++column;
+                                       p1 = p + 1;
+                                       p = strchr(p1, '\t');
+                               }
+
+                               sz->cx = max(sz->cx, 
+                                       (LONG)(2*TILE_X + menuitemwidth + tm.tmAveCharWidth*12 + tm.tmOverhang));
+                       }
+                       SelectObject(hdc, saveFont);
+               } else {
+                       /* Calculate the width of the text box. */
+                       RECT text_rt;
+                       saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE));
+                       GetTextMetrics(hdc, &tm);
+                       SetRect(&text_rt, 0, 0, sz->cx, sz->cy);
+                       DrawText(hdc, data->text.text, _tcslen(data->text.text), &text_rt, DT_CALCRECT | DT_TOP | DT_LEFT | DT_NOPREFIX);
+                       sz->cx = max(sz->cx, text_rt.right - text_rt.left + 5*tm.tmAveCharWidth + tm.tmOverhang);
+                       SelectObject(hdc, saveFont);
+               }
+               sz->cx += extra_cx;
+
+               ReleaseDC(control, hdc);
+       }
+}
+/*-----------------------------------------------------------------------------*/
+void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count)
+{
+       int i;
+
+       if( item<0 || item>=data->menu.size ) return;
+
+       if( data->how==PICK_ONE && count!=0 ) {
+               for(i=0; i<data->menu.size; i++) 
+                       if( item!=i && data->menu.items[i].count!=0 ) {
+                               data->menu.items[i].count = 0;
+                               ListView_RedrawItems( hwndList, i, i );
+                       };
+       }
+
+       data->menu.items[item].count = count;
+       ListView_RedrawItems( hwndList, item, item );
+       reset_menu_count(hwndList, data);
+}
+/*-----------------------------------------------------------------------------*/
+void reset_menu_count(HWND hwndList, PNHMenuWindow data) 
+{
+       int i; 
+       data->menu.counting = FALSE;
+       if( IsWindow(hwndList) ) {
+               i = ListView_GetNextItem((hwndList), -1, LVNI_FOCUSED);
+               if( i>=0 ) ListView_RedrawItems( hwndList, i, i ); 
+       }
+}
+/*-----------------------------------------------------------------------------*/
+/* List window Proc */
+LRESULT CALLBACK NHMenuListWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       BOOL bUpdateFocusItem;
+
+       bUpdateFocusItem = FALSE;
+
+       switch(message) {
+
+       /* filter keyboard input for the control */
+       case WM_KEYDOWN:
+       case WM_KEYUP: {
+               MSG msg;
+               BOOL processed;
+
+               processed = FALSE;
+               if( PeekMessage(&msg, hWnd, WM_CHAR, WM_CHAR, PM_REMOVE) ) {
+                       if( onListChar(GetParent(hWnd), hWnd, (char)msg.wParam)==-2 ) {
+                               processed = TRUE;
+                       }
+               }
+               if( processed ) return 0;
+
+               if( wParam==VK_LEFT || wParam==VK_RIGHT )
+                       bUpdateFocusItem = TRUE;
+       } break;
+
+       case WM_SIZE:
+       case WM_HSCROLL:
+               bUpdateFocusItem = TRUE;
+       break;
+
+       }
+
+       if(     bUpdateFocusItem ) {
+               int i;
+               RECT rt;
+
+               /* invalidate the focus rectangle */
+               i = ListView_GetNextItem(hWnd, -1,      LVNI_FOCUSED);
+               if( i!=-1 ) {
+                       ListView_GetItemRect(hWnd, i, &rt, LVIR_BOUNDS);
+                       InvalidateRect(hWnd, &rt, TRUE);
+               }
+       }
+
+       if( wndProcListViewOrig ) 
+               return CallWindowProc(wndProcListViewOrig, hWnd, message, wParam, lParam);
+       else 
+               return 0;
+}
+/*-----------------------------------------------------------------------------*/
+/* Text control window proc - implements scrolling without a cursor */
+LRESULT CALLBACK NHMenuTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch(message) {
+
+       case WM_KEYDOWN:
+               switch (wParam)
+        {
+       /* close on space in Windows mode
+           page down on space in NetHack mode */
+        case VK_SPACE:
+        {   
+            SCROLLINFO si;
+
+            si.cbSize = sizeof(SCROLLINFO);
+            si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
+            GetScrollInfo(hWnd, SB_VERT, &si);
+            /* If nethackmode and not at the end of the list */
+            if (GetNHApp()->regNetHackMode &&
+                    (si.nPos + (int)si.nPage) <= (si.nMax - si.nMin))
+                SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0);
+            else
+                           PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0);
+            return 0;
+        }
+        case VK_NEXT:
+            SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0);
+            return 0;
+        case VK_PRIOR:
+            SendMessage(hWnd, EM_SCROLL, SB_PAGEUP, 0);
+            return 0;
+        case VK_UP:
+            SendMessage(hWnd, EM_SCROLL, SB_LINEUP, 0);
+            return 0;
+        case VK_DOWN:
+            SendMessage(hWnd, EM_SCROLL, SB_LINEDOWN, 0);
+            return 0;
+
+               }
+       break;
+
+       }
+
+       if( editControlWndProc ) 
+               return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam);
+       else 
+               return 0;
+}
+/*-----------------------------------------------------------------------------*/
diff --git a/win/win32/mhmenu.h b/win/win32/mhmenu.h
new file mode 100644 (file)
index 0000000..aa9a90d
--- /dev/null
@@ -0,0 +1,18 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINMenuWindow_h
+#define MSWINMenuWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+#define MENU_TYPE_TEXT     1
+#define MENU_TYPE_MENU     2
+
+HWND mswin_init_menu_window ( int type );
+int mswin_menu_window_select_menu (HWND hwnd, int how, MENU_ITEM_P **);
+void mswin_menu_window_size (HWND hwnd, LPSIZE sz);
+
+#endif /* MSWINTextWindow_h */
diff --git a/win/win32/mhmsg.h b/win/win32/mhmsg.h
new file mode 100644 (file)
index 0000000..4f46974
--- /dev/null
@@ -0,0 +1,62 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MHNethackMessages_H
+#define MHNethackMessages_H
+
+/* nethack messages */
+#define WM_MSNH_COMMAND  (WM_APP+1)
+
+#define MSNH_MSG_ADDWND                        100
+#define MSNH_MSG_PUTSTR                        101
+#define MSNH_MSG_PRINT_GLYPH   102
+#define MSNH_MSG_CLEAR_WINDOW  103
+#define MSNH_MSG_CLIPAROUND            104
+#define MSNH_MSG_STARTMENU             105
+#define MSNH_MSG_ADDMENU               106
+#define MSNH_MSG_CURSOR                        107
+#define MSNH_MSG_ENDMENU               108
+#define MSNH_MSG_DIED                  109
+#define MSNH_MSG_CARET                 110
+
+typedef struct mswin_nhmsg_add_wnd {
+  winid                  wid;
+} MSNHMsgAddWnd, *PMSNHMsgAddWnd;
+
+typedef struct mswin_nhmsg_putstr {
+  int            attr;
+  const char* text;
+  boolean        append;
+} MSNHMsgPutstr, *PMSNHMsgPutstr;
+
+typedef struct mswin_nhmsg_print_glyph {
+  XCHAR_P              x;
+  XCHAR_P              y;
+  int                  glyph;
+} MSNHMsgPrintGlyph, *PMSNHMsgPrintGlyph;
+
+typedef struct mswin_nhmsg_cliparound {
+  int                  x;
+  int                  y;
+} MSNHMsgClipAround, *PMSNHMsgClipAround;
+
+typedef struct mswin_nhmsg_add_menu {
+       int                             glyph;
+       const ANY_P*    identifier;
+       CHAR_P                  accelerator;
+       CHAR_P                  group_accel;
+       int                             attr;
+       const char *    str;
+       BOOLEAN_P               presel;
+} MSNHMsgAddMenu, *PMSNHMsgAddMenu;
+
+typedef struct mswin_nhmsg_cursor {
+  int                  x;
+  int                  y;
+} MSNHMsgCursor, *PMSNHMsgCursor;
+
+typedef struct mswin_nhmsg_end_menu {
+       const char* text;
+} MSNHMsgEndMenu, *PMSNHMsgEndMenu;
+
+#endif
diff --git a/win/win32/mhmsgwnd.c b/win/win32/mhmsgwnd.c
new file mode 100644 (file)
index 0000000..7daca46
--- /dev/null
@@ -0,0 +1,742 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include "mhmsgwnd.h"
+#include "mhmsg.h"
+#include "mhfont.h"
+
+#define MSG_WRAP_TEXT 
+
+#define MSG_VISIBLE_LINES     max(iflags.wc_vary_msgcount, 2)
+#define MAX_MSG_LINES            32
+#define MSG_LINES                        (int)min(iflags.msg_history, MAX_MSG_LINES)
+#define MAXWINDOWTEXT            TBUFSZ
+
+#define DEFAULT_COLOR_BG_MSG   COLOR_WINDOW
+#define DEFAULT_COLOR_FG_MSG   COLOR_WINDOWTEXT
+
+#define MORE "--More--"
+
+struct window_line {
+       int  attr;
+       char text[MAXWINDOWTEXT];
+};
+
+typedef struct mswin_nethack_message_window {
+       size_t max_text;
+       struct window_line window_text[MAX_MSG_LINES];
+#ifdef MSG_WRAP_TEXT
+    int  window_text_lines[MAX_MSG_LINES]; /* How much space this text line takes */
+#endif
+    int  lines_last_turn; /* lines added during the last turn */
+    int  cleared;     /* clear was called */
+    int  last_line;   /* last line in the message history */
+    struct window_line new_line;
+    int  lines_not_seen;  /* lines not yet seen by user after last turn or --More-- */
+    int  in_more;   /* We are in a --More-- prompt */
+    int  nevermore;   /* We want no more --More-- prompts */
+
+       int  xChar;       /* horizontal scrolling unit */
+       int  yChar;       /* vertical scrolling unit */
+       int  xUpper;      /* average width of uppercase letters */
+       int  xPos;        /* current horizontal scrolling position */
+       int  yPos;        /* current vertical scrolling position */
+       int  xMax;        /* maximum horizontal scrolling position */
+       int  yMax;        /* maximum vertical scrolling position */
+       int      xPage;           /* page size of horizontal scroll bar */
+ } NHMessageWindow, *PNHMessageWindow;
+
+static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass");
+LRESULT CALLBACK       NHMessageWndProc(HWND, UINT, WPARAM, LPARAM);
+static void register_message_window_class(void);
+static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
+#ifndef MSG_WRAP_TEXT
+static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
+#endif
+static COLORREF setMsgTextColor(HDC hdc, int gray);
+static void onPaint(HWND hWnd);
+static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
+
+#ifdef USER_SOUNDS
+extern void play_sound_for_message(const char* str);
+#endif
+
+HWND mswin_init_message_window () {
+       static int run_once = 0;
+       HWND ret;
+       DWORD style;
+
+       if( !run_once ) {
+               register_message_window_class( );
+               run_once = 1;
+       }
+
+#ifdef MSG_WRAP_TEXT                   
+       style = WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL;
+#else
+       style = WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL;
+#endif
+
+       ret = CreateWindowEx(
+                       WS_EX_CLIENTEDGE,
+                       szMessageWindowClass,   /* registered class name */
+                       NULL,                                   /* window name */                       
+                       style, /* window style */
+                       0,   /* horizontal position of window */
+                       0,   /* vertical position of window */
+                       0,   /* window width */
+                       0,   /* window height - set it later */
+                       GetNHApp()->hMainWnd,   /* handle to parent or owner window */
+                       NULL,                                   /* menu handle or child identifier */
+                       GetNHApp()->hApp,               /* handle to application instance */
+                       NULL );                                 /* window-creation data */
+
+       if( !ret ) panic("Cannot create message window");
+
+       return ret;
+}
+
+void register_message_window_class()
+{
+       WNDCLASS wcex;
+       ZeroMemory( &wcex, sizeof(wcex));
+
+       wcex.style                      = CS_NOCLOSE;
+       wcex.lpfnWndProc        = (WNDPROC)NHMessageWndProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = GetNHApp()->hApp;
+       wcex.hIcon                      = NULL;
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = message_bg_brush ? message_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_MSG);
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szMessageWindowClass;
+
+       RegisterClass(&wcex);
+}
+    
+LRESULT CALLBACK NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch (message) 
+       {
+       case WM_CREATE:
+               onCreate( hWnd, wParam, lParam );
+               break;
+
+       case WM_MSNH_COMMAND: 
+               onMSNHCommand(hWnd, wParam, lParam);
+               break;
+
+       case WM_PAINT: 
+               onPaint(hWnd);
+               break;
+
+       case WM_SETFOCUS:
+               SetFocus(GetNHApp()->hMainWnd);
+               break;
+
+#ifndef MSG_WRAP_TEXT
+       case WM_HSCROLL:
+               onMSNH_HScroll(hWnd, wParam, lParam);
+               break;
+#endif
+
+       case WM_VSCROLL:
+               onMSNH_VScroll(hWnd, wParam, lParam);
+               break;
+
+       case WM_DESTROY: 
+       {
+               PNHMessageWindow data;
+               data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+               free(data);
+               SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+       }       break;
+
+    case WM_SIZE: 
+    { 
+               SCROLLINFO si;
+        int xNewSize; 
+        int yNewSize; 
+               PNHMessageWindow data;
+       
+               data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+        xNewSize = LOWORD(lParam); 
+        yNewSize = HIWORD(lParam); 
+
+               if( xNewSize>0 || yNewSize>0 ) {
+
+#ifndef MSG_WRAP_TEXT
+                       data->xPage = xNewSize/data->xChar;
+                       data->xMax = max(0, (int)(1 + data->max_text - data->xPage));
+                       data->xPos = min(data->xPos, data->xMax);
+
+                       ZeroMemory(&si, sizeof(si));
+                       si.cbSize = sizeof(si); 
+                       si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS; 
+                       si.nMin   = 0; 
+                       si.nMax   = data->max_text; 
+                       si.nPage  = data->xPage; 
+                       si.nPos   = data->xPos;
+                       SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); 
+#endif
+               
+                       data->yMax = MSG_LINES-1;
+                       data->yPos = min(data->yPos, data->yMax);
+
+                       ZeroMemory(&si, sizeof(si));
+                       si.cbSize = sizeof(si); 
+                       si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS; 
+                       si.nMin   = MSG_VISIBLE_LINES; 
+                       si.nMax   = data->yMax + MSG_VISIBLE_LINES - 1; 
+                       si.nPage  = MSG_VISIBLE_LINES;
+                       si.nPos   = data->yPos;
+                       SetScrollInfo(hWnd, SB_VERT, &si, TRUE); 
+               }
+    } 
+    break; 
+
+       default:
+               return DefWindowProc(hWnd, message, wParam, lParam);
+   }
+   return 0;
+}
+
+void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMessageWindow data;
+       
+       data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch( wParam ) {
+       case MSNH_MSG_PUTSTR: 
+       {
+               PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
+               SCROLLINFO si;
+
+               if( msg_data->append == 1) {
+                   /* Forcibly append to line, even if we pass the edge */
+                   strncat(data->window_text[data->last_line].text, msg_data->text, 
+                           MAXWINDOWTEXT - strlen(data->window_text[data->last_line].text));
+               } else if( msg_data->append < 0) {
+            /* remove that many chars */
+                   int len = strlen(data->window_text[data->last_line].text);
+            int newend = max(len + msg_data->append, 0);
+                   data->window_text[data->last_line].text[newend] = '\0';
+        } else {
+                   /* Try to append but move the whole message to the next line if 
+                      it doesn't fit */
+                   /* just schedule for displaying */
+                   data->new_line.attr = msg_data->attr;
+                   strncpy(data->new_line.text, msg_data->text, MAXWINDOWTEXT);
+               }
+               
+               /* reset V-scroll position to display new text */
+               data->yPos = data->yMax;
+
+               ZeroMemory(&si, sizeof(si));
+        si.cbSize = sizeof(si);
+        si.fMask  = SIF_POS; 
+        si.nPos   = data->yPos; 
+        SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
+
+               /* update window content */
+               InvalidateRect(hWnd, NULL, TRUE);
+
+#ifdef USER_SOUNDS
+               play_sound_for_message(msg_data->text);
+#endif
+       }
+       break;
+
+       case MSNH_MSG_CLEAR_WINDOW:
+       {
+               data->cleared = 1;
+               data->lines_not_seen = 0;
+               /* do --More-- again if needed */
+               data->nevermore = 0;
+               break;
+       }
+    case MSNH_MSG_CARET:
+        /* Create or destroy a caret */
+        if (*(int *)lParam)
+            CreateCaret(hWnd, NULL, 0, data->yChar);
+           else {
+            DestroyCaret();
+               /* this means we just did something interactive in this window, so we
+                  don't need a --More-- for the lines above.
+                  */
+               data->lines_not_seen = 0;
+           }
+        break;
+
+
+       }
+}
+
+void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMessageWindow data;
+       SCROLLINFO si; 
+       int yInc;
+       /* get window data */
+       data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       
+       ZeroMemory(&si, sizeof(si));
+       si.cbSize = sizeof(si);
+       si.fMask = SIF_PAGE | SIF_POS;
+       GetScrollInfo(hWnd, SB_VERT, &si);
+
+       switch(LOWORD (wParam)) 
+       { 
+    // User clicked the shaft above the scroll box. 
+
+    case SB_PAGEUP: 
+         yInc = -(int)si.nPage; 
+         break; 
+
+    // User clicked the shaft below the scroll box. 
+
+    case SB_PAGEDOWN: 
+         yInc = si.nPage; 
+         break; 
+
+    // User clicked the top arrow. 
+
+    case SB_LINEUP: 
+         yInc = -1; 
+         break; 
+
+    // User clicked the bottom arrow. 
+
+    case SB_LINEDOWN: 
+         yInc = 1; 
+         break; 
+
+    // User dragged the scroll box. 
+
+    case SB_THUMBTRACK: 
+         yInc = HIWORD(wParam) - data->yPos; 
+         break; 
+
+    default: 
+         yInc = 0; 
+       }
+
+       // If applying the vertical scrolling increment does not 
+       // take the scrolling position out of the scrolling range, 
+       // increment the scrolling position, adjust the position 
+       // of the scroll box, and update the window. UpdateWindow 
+       // sends the WM_PAINT message. 
+
+       if (yInc = max( MSG_VISIBLE_LINES - data->yPos, 
+                           min(yInc, data->yMax - data->yPos))) 
+       { 
+               data->yPos += yInc; 
+               /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc, 
+                       (CONST RECT *) NULL, (CONST RECT *) NULL, 
+                       (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); 
+               */
+               InvalidateRect(hWnd, NULL, TRUE);
+
+               ZeroMemory(&si, sizeof(si));
+               si.cbSize = sizeof(si); 
+               si.fMask  = SIF_POS; 
+               si.nPos   = data->yPos; 
+               SetScrollInfo(hWnd, SB_VERT, &si, TRUE); 
+
+               UpdateWindow (hWnd); 
+       } 
+}
+
+#ifndef MSG_WRAP_TEXT
+void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMessageWindow data;
+       SCROLLINFO si; 
+       int xInc;
+       /* get window data */
+       data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       
+       ZeroMemory(&si, sizeof(si));
+       si.cbSize = sizeof(si);
+       si.fMask = SIF_PAGE;
+       GetScrollInfo(hWnd, SB_HORZ, &si);
+
+    switch(LOWORD (wParam)) 
+    { 
+        // User clicked shaft left of the scroll box. 
+
+        case SB_PAGEUP: 
+             xInc = - (int)si.nPage; 
+             break; 
+
+        // User clicked shaft right of the scroll box. 
+
+        case SB_PAGEDOWN: 
+             xInc = si.nPage; 
+             break; 
+
+        // User clicked the left arrow. 
+
+        case SB_LINEUP: 
+             xInc = -1; 
+             break; 
+
+        // User clicked the right arrow. 
+
+        case SB_LINEDOWN: 
+             xInc = 1; 
+             break; 
+
+        // User dragged the scroll box. 
+
+        case SB_THUMBTRACK: 
+             xInc = HIWORD(wParam) - data->xPos; 
+             break; 
+
+        default: 
+             xInc = 0; 
+
+    }
+
+       
+    // If applying the horizontal scrolling increment does not 
+    // take the scrolling position out of the scrolling range, 
+    // increment the scrolling position, adjust the position 
+    // of the scroll box, and update the window. 
+
+    if (xInc = max (-data->xPos, min (xInc, data->xMax - data->xPos))) 
+    { 
+        data->xPos += xInc; 
+        ScrollWindowEx (hWnd, -data->xChar * xInc, 0, 
+            (CONST RECT *) NULL, (CONST RECT *) NULL, 
+            (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); 
+
+               ZeroMemory(&si, sizeof(si));
+        si.cbSize = sizeof(si); 
+        si.fMask  = SIF_POS; 
+        si.nPos   = data->xPos; 
+        SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); 
+        UpdateWindow (hWnd); 
+    } 
+}
+#endif // MSG_WRAP_TEXT
+
+COLORREF setMsgTextColor(HDC hdc, int gray)
+{
+    COLORREF fg, color1, color2;
+    if (gray) {
+       if (message_bg_brush) {
+           color1 = message_bg_color;
+           color2 = message_fg_color;
+       } else {
+           color1 = (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MSG);
+           color2 = (COLORREF)GetSysColor(DEFAULT_COLOR_FG_MSG);
+       }
+       /* Make a "gray" color by taking the average of the individual R,G,B 
+          components of two colors. Thanks to Jonathan del Strother */
+       fg = RGB((GetRValue(color1)+GetRValue(color2))/2,
+               (GetGValue(color1)+GetGValue(color2))/2,
+               (GetBValue(color1)+GetBValue(color2))/2);
+    } else {
+       fg = message_fg_brush ? message_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_MSG);
+    }
+
+
+    return SetTextColor(hdc, fg);
+}
+
+
+void onPaint(HWND hWnd)
+{
+       PAINTSTRUCT ps;
+       HDC hdc;
+       PNHMessageWindow data;
+       RECT client_rt, draw_rt;
+       int FirstLine, LastLine;
+       int i, x, y;
+       HGDIOBJ oldFont;
+       TCHAR wbuf[MAXWINDOWTEXT+2];
+       size_t wlen;
+       COLORREF OldBg, OldFg;
+    int do_more = 0;
+
+       hdc = BeginPaint(hWnd, &ps);
+
+       OldBg = SetBkColor(hdc, message_bg_brush ? message_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MSG));
+    OldFg = setMsgTextColor(hdc, 0);
+
+       data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       GetClientRect(hWnd, &client_rt);
+
+       if( !IsRectEmpty(&ps.rcPaint) ) {
+               FirstLine = max (0, data->yPos - (client_rt.bottom - ps.rcPaint.top)/data->yChar + 1); 
+               LastLine = min (MSG_LINES-1, data->yPos - (client_rt.bottom - ps.rcPaint.bottom)/data->yChar); 
+               y = min( ps.rcPaint.bottom, client_rt.bottom ); 
+               for (i=LastLine; i>=FirstLine; i--) { 
+                               int lineidx = (data->last_line + 1 + i) % MSG_LINES;
+                               x = data->xChar * (2 - data->xPos); 
+
+                               draw_rt.left = x;
+                               draw_rt.right = client_rt.right;
+                               draw_rt.top = y - data->yChar;
+                               draw_rt.bottom = y;
+
+           oldFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[lineidx].attr, hdc, FALSE));
+
+           /* find out if we can concatenate the scheduled message without wrapping,
+        but only if no clear_nhwindow was done just before putstr'ing this one,
+        and only if not in a more prompt already (to prevent concatenating to
+        a line containing --More-- when resizing while --More-- is displayed.) 
+              */
+           if (i == MSG_LINES-1 
+  && strlen(data->new_line.text) > 0
+  && !data->in_more) {
+               /* concatenate to the previous line if that is not empty, and
+                  if it has the same attribute, and no clear was done.
+                  */
+               if (strlen(data->window_text[lineidx].text) > 0
+                       && (data->window_text[lineidx].attr 
+                           == data->new_line.attr)
+                       && !data->cleared) {
+                   RECT tmpdraw_rt = draw_rt;
+                   /* assume this will never work when textsize is near MAXWINDOWTEXT */
+                   char tmptext[MAXWINDOWTEXT];
+                   TCHAR tmpwbuf[MAXWINDOWTEXT+2];
+
+                   strcpy(tmptext, data->window_text[lineidx].text);
+                   strncat(tmptext, "  ", 
+                           MAXWINDOWTEXT - strlen(tmptext));
+                   strncat(tmptext, data->new_line.text, 
+                           MAXWINDOWTEXT - strlen(tmptext));
+                   /* Always keep room for a --More-- */
+                   strncat(tmptext, MORE, 
+                           MAXWINDOWTEXT - strlen(tmptext));
+                   NH_A2W(tmptext, tmpwbuf, sizeof(tmpwbuf));
+                   /* Find out how large the bounding rectangle of the text is */                
+                   DrawText(hdc, tmpwbuf, _tcslen(tmpwbuf), &tmpdraw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
+                   if ((tmpdraw_rt.bottom - tmpdraw_rt.top) == (draw_rt.bottom - draw_rt.top)  /* fits pixelwise */
+                           && (strlen(data->window_text[lineidx].text) 
+                               + strlen(data->new_line.text) < MAXWINDOWTEXT)) /* fits charwise */
+                   {
+                       /* strip off --More-- of this combined line and make it so */
+                       tmptext[strlen(tmptext) - strlen(MORE)] = '\0';
+                       strcpy(data->window_text[lineidx].text, tmptext);
+                       data->new_line.text[0] = '\0';
+                       i++; /* Start from the last line again */
+                       continue;
+                   }
+               }
+               if (strlen(data->new_line.text) > 0) {
+                   /* if we get here, the new line was not concatenated. Add it on a new line,
+                      but first check whether we should --More--. */
+                   RECT tmpdraw_rt = draw_rt;
+                   TCHAR tmpwbuf[MAXWINDOWTEXT+2];
+                   HGDIOBJ oldFont;
+                   int new_screen_lines;
+                   int screen_lines_not_seen = 0;
+                   /* Count how many screen lines we haven't seen yet. */
+#ifdef MSG_WRAP_TEXT                           
+                   {
+                       int n;
+                       for (n = data->lines_not_seen - 1; n >= 0; n--) {
+                           screen_lines_not_seen += 
+                               data->window_text_lines[(data->last_line - n + MSG_LINES) % MSG_LINES];
+                       }
+                   }
+#else
+                   screen_lines_not_seen = data->lines_not_seen;
+#endif
+                   /* Now find out how many screen lines we would like to add */
+                   NH_A2W(data->new_line.text, tmpwbuf, sizeof(tmpwbuf));
+                   /* Find out how large the bounding rectangle of the text is */                
+                   oldFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[lineidx].attr, hdc, FALSE));
+                   DrawText(hdc, tmpwbuf, _tcslen(tmpwbuf), &tmpdraw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
+                   SelectObject(hdc, oldFont);
+                   new_screen_lines = (tmpdraw_rt.bottom - tmpdraw_rt.top) / data->yChar;
+                   /* If this together is more than fits on the window, we must 
+                      --More--, unless:
+                      - We are in --More-- already (the user is scrolling the window)
+                      - The user pressed ESC
+                      */
+                   if (screen_lines_not_seen + new_screen_lines > MSG_VISIBLE_LINES
+                           && !data->in_more && !data->nevermore) {
+                       data->in_more = 1;
+                       /* Show --More-- on last line */
+                       strcat(data->window_text[data->last_line].text, MORE);
+                       /* Go on drawing, but remember we must do a more afterwards */
+                       do_more = 1;
+                   } else if (!data->in_more) {
+                       data->last_line++;
+                       data->last_line %= MSG_LINES; 
+                       data->window_text[data->last_line].attr = data->new_line.attr;
+                       strncpy(data->window_text[data->last_line].text, data->new_line.text, MAXWINDOWTEXT);
+                       data->new_line.text[0] = '\0';
+                       if (data->cleared) {
+                           /* now we are drawing a new line, the old lines can be redrawn in grey.*/
+                           data->lines_last_turn = 0;
+                           data->cleared = 0;
+                       }
+                       data->lines_last_turn++;
+                       data->lines_not_seen++;
+                       /* and start over */
+                       i++; /* Start from the last line again */
+                       continue;
+                   }
+               }
+           }
+           /* convert to UNICODE */
+           NH_A2W(data->window_text[lineidx].text, wbuf, sizeof(wbuf));
+           wlen = _tcslen(wbuf);
+           setMsgTextColor(hdc, i < (MSG_LINES - data->lines_last_turn));
+#ifdef MSG_WRAP_TEXT                           
+           /* Find out how large the bounding rectangle of the text is */                
+                               DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
+           /* move that rectangle up, so that the bottom remains at the same height */
+                               draw_rt.top = y - (draw_rt.bottom - draw_rt.top);
+                               draw_rt.bottom = y;
+           /* Remember the height of this line for subsequent --More--'s */
+           data->window_text_lines[lineidx] = (draw_rt.bottom - draw_rt.top) / data->yChar;
+           /* Now really draw it */
+                               DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK);
+                
+                /* Find out the cursor (caret) position */
+           if (i == MSG_LINES-1) {
+                    int nnum, numfit;
+                    SIZE size;
+                    TCHAR *nbuf;
+                    int nlen;
+
+                    nbuf = wbuf;
+                    nlen = wlen;
+                    while (nlen) {
+                        /* Get the number of characters that fit on the line */
+                        GetTextExtentExPoint(hdc, nbuf, nlen, draw_rt.right - draw_rt.left, &numfit, NULL, &size);
+                        /* Search back to a space */
+                        nnum = numfit;
+                        if (numfit < nlen) {
+                            while (nnum > 0 && nbuf[nnum] != ' ')
+                                nnum--;
+                            /* If no space found, break wherever */
+                            if (nnum == 0)
+                                nnum = numfit;
+                        }
+                        nbuf += nnum;
+                        nlen -= nnum;
+                        if (*nbuf == ' ') {
+                            nbuf++;
+                            nlen--;
+                        }
+                    }
+                    /* The last size is the size of the last line. Set the caret there.
+                       This will fail automatically if we don't own the caret (i.e.,
+                       when not in a question.)
+                     */
+                    SetCaretPos(draw_rt.left + size.cx, draw_rt.bottom - data->yChar);
+                }
+#else
+                               DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX );
+                SetCaretPos(draw_rt.left + size.cx, draw_rt.bottom - data->yChar);
+#endif
+                               SelectObject(hdc, oldFont);
+                               y -= draw_rt.bottom - draw_rt.top;
+                       }
+       if (do_more) {
+           int okkey = 0;
+           int chop;
+           // @@@ Ok respnses
+
+           while (!okkey) {
+               char c = mswin_nhgetch();
+
+               switch (c)
+               {
+                   /* space or enter */
+                   case ' ':
+                   case '\015':
+                       okkey = 1;
+                       break;
+                       /* ESC */
+                   case '\033':
+                       data->nevermore = 1;
+                       okkey = 1;
+                       break;
+                   default:
+                       break;
+                       }
+               }
+           chop = strlen(data->window_text[data->last_line].text) 
+               - strlen(MORE);
+           data->window_text[data->last_line].text[chop] = '\0';
+           data->in_more = 0;
+           data->lines_not_seen = 0;
+           /* We did the --More--, reset the lines_not_seen; now draw that
+              new line. This is the easiest method */
+           InvalidateRect(hWnd, NULL, TRUE);
+       }
+       }
+       SetTextColor (hdc, OldFg);
+       SetBkColor (hdc, OldBg);
+       EndPaint(hWnd, &ps);
+}
+
+void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHMessageWindow data;
+       SIZE    dummy;
+
+       /* set window data */
+       data = (PNHMessageWindow)malloc(sizeof(NHMessageWindow));
+       if( !data ) panic("out of memory");
+       ZeroMemory(data, sizeof(NHMessageWindow));
+       data->max_text = MAXWINDOWTEXT;
+       SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
+
+       /* re-calculate window size (+ font size) */
+       mswin_message_window_size(hWnd, &dummy);
+}
+
+void mswin_message_window_size (HWND hWnd, LPSIZE sz)
+{
+       HDC hdc;
+       HGDIOBJ saveFont;
+       TEXTMETRIC tm; 
+       PNHMessageWindow data;
+       RECT rt, client_rt;
+
+       data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if( !data ) return;
+
+       /* -- Calculate the font size -- */
+    /* Get the handle to the client area's device context. */
+    hdc = GetDC(hWnd); 
+       saveFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE));
+
+    /* Extract font dimensions from the text metrics. */
+    GetTextMetrics (hdc, &tm); 
+    data->xChar = tm.tmAveCharWidth; 
+    data->xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * data->xChar/2; 
+    data->yChar = tm.tmHeight + tm.tmExternalLeading; 
+       data->xPage = 1;
+
+    /* Free the device context.  */
+       SelectObject(hdc, saveFont);
+    ReleaseDC (hWnd, hdc); 
+       
+       /* -- calculate window size -- */
+       GetWindowRect(hWnd, &rt);
+       sz->cx = rt.right - rt.left;
+       sz->cy = rt.bottom - rt.top;
+
+       /* set size to accomodate MSG_VISIBLE_LINES and
+          horizontal scroll bar (difference between window rect and client rect */
+       GetClientRect(hWnd, &client_rt);
+       sz->cy = sz->cy - (client_rt.bottom - client_rt.top) +
+                        data->yChar * MSG_VISIBLE_LINES;
+}
diff --git a/win/win32/mhmsgwnd.h b/win/win32/mhmsgwnd.h
new file mode 100644 (file)
index 0000000..a4f6736
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINMessageWindow_h
+#define MSWINMessageWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+HWND mswin_init_message_window (void);
+void mswin_message_window_size (HWND hWnd, LPSIZE sz);
+
+
+#endif /* MSWINMessageWindow_h */
diff --git a/win/win32/mhrip.c b/win/win32/mhrip.c
new file mode 100644 (file)
index 0000000..69f4916
--- /dev/null
@@ -0,0 +1,265 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include "resource.h"
+#include "mhrip.h"
+#include "mhmsg.h"
+#include "mhfont.h"
+
+#define RIP_WIDTH      400
+#define RIP_HEIGHT     200
+
+#define RIP_GRAVE_HEIGHT       120
+#define RIP_GRAVE_WIDTH                115
+#define RIP_GRAVE_X            90
+#define RIP_GRAVE_Y            60
+
+#define RIP_OFFSET_X           10
+#define RIP_OFFSET_Y           10
+
+PNHWinApp GetNHApp(void);
+
+typedef struct mswin_nethack_text_window {
+       HANDLE  rip_bmp;
+       TCHAR*  window_text;
+       TCHAR*  rip_text;
+} NHRIPWindow, *PNHRIPWindow;
+
+BOOL CALLBACK NHRIPWndProc(HWND, UINT, WPARAM, LPARAM);
+static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+
+HWND mswin_init_RIP_window () {
+       HWND ret;
+       PNHRIPWindow data;
+
+       ret = CreateDialog(
+                       GetNHApp()->hApp,
+                       MAKEINTRESOURCE(IDD_NHRIP),
+                       GetNHApp()->hMainWnd,
+                       NHRIPWndProc
+       );
+       if( !ret ) panic("Cannot create rip window");
+
+       data = (PNHRIPWindow)malloc(sizeof(NHRIPWindow));
+       if( !data ) panic("out of memory");
+
+       ZeroMemory(data, sizeof(NHRIPWindow));
+       SetWindowLong(ret, GWL_USERDATA, (LONG)data);
+       return ret;
+}
+
+void mswin_display_RIP_window (HWND hWnd)
+{
+       MSG msg;
+       RECT rt;
+       PNHRIPWindow data;
+       HWND mapWnd;
+       RECT riprt;
+       RECT clientrect;
+       RECT textrect;
+       HDC hdc;
+       HFONT OldFont;
+
+       data = (PNHRIPWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       GetNHApp()->hPopupWnd = hWnd;
+       mapWnd = mswin_hwnd_from_winid(WIN_MAP);
+       if( !IsWindow(mapWnd) ) mapWnd = GetNHApp()->hMainWnd;
+       GetWindowRect(mapWnd, &rt);
+       GetWindowRect(hWnd, &riprt);
+       GetClientRect (hWnd, &clientrect);
+       textrect = clientrect;
+       textrect.top += RIP_OFFSET_Y;
+       textrect.left += RIP_OFFSET_X;
+       textrect.right -= RIP_OFFSET_X;
+       if (data->window_text)
+       {
+           hdc = GetDC (hWnd);
+           OldFont = SelectObject (hdc, mswin_get_font(NHW_TEXT, 0, hdc, FALSE));
+           DrawText (hdc, data->window_text, strlen(data->window_text), &textrect,
+               DT_LEFT | DT_NOPREFIX | DT_CALCRECT);
+           SelectObject (hdc, OldFont);
+           ReleaseDC(hWnd, hdc);
+       }
+       if (textrect.right - textrect.left > RIP_WIDTH)
+           clientrect.right = textrect.right + RIP_OFFSET_X - clientrect.right;
+       else
+           clientrect.right = textrect.left + 2 * RIP_OFFSET_X + RIP_WIDTH - clientrect.right;
+       clientrect.bottom = textrect.bottom + RIP_HEIGHT + RIP_OFFSET_Y - clientrect.bottom;
+       GetWindowRect (GetDlgItem(hWnd, IDOK), &textrect);
+       textrect.right -= textrect.left;
+       textrect.bottom -= textrect.top;
+       clientrect.bottom += textrect.bottom + RIP_OFFSET_Y;
+       riprt.right -= riprt.left;
+       riprt.bottom -= riprt.top;
+       riprt.right += clientrect.right;
+       riprt.bottom += clientrect.bottom;
+       rt.left += (rt.right - rt.left - riprt.right) / 2;
+       rt.top += (rt.bottom - rt.top - riprt.bottom) / 2;
+
+       MoveWindow(hWnd, rt.left, rt.top, riprt.right, riprt.bottom, TRUE);
+       GetClientRect (hWnd, &clientrect);
+       MoveWindow (GetDlgItem(hWnd, IDOK),
+           (clientrect.right - clientrect.left - textrect.right) / 2,
+           clientrect.bottom - textrect.bottom - RIP_OFFSET_Y, textrect.right, textrect.bottom, TRUE);
+       ShowWindow(hWnd, SW_SHOW);
+
+       while( IsWindow(hWnd) &&
+                  GetMessage(&msg, NULL, 0, 0)!=0 ) {
+               if( !IsDialogMessage(hWnd, &msg) ) {
+                       TranslateMessage(&msg);
+                       DispatchMessage(&msg);
+               }
+       }
+
+       GetNHApp()->hPopupWnd = NULL;
+}
+
+BOOL CALLBACK NHRIPWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       HDC hdc;
+       PNHRIPWindow data;
+
+       data = (PNHRIPWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch (message)
+       {
+       case WM_INITDIALOG:
+           /* set text control font */
+               hdc = GetDC(hWnd);
+               SendMessage(hWnd, WM_SETFONT,
+                       (WPARAM)mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), 0);
+               ReleaseDC(hWnd, hdc);
+
+               SetFocus(GetDlgItem(hWnd, IDOK));
+       return FALSE;
+
+       case WM_MSNH_COMMAND:
+               onMSNHCommand(hWnd, wParam, lParam);
+       break;
+
+       case WM_PAINT:
+       {
+               int bitmap_offset;
+               RECT clientrect;
+               RECT textrect;
+               HDC hdcBitmap;
+               HANDLE OldBitmap;
+               PAINTSTRUCT ps;
+               HFONT OldFont;
+
+               hdc = BeginPaint (hWnd, &ps);
+               OldFont = SelectObject (hdc, mswin_get_font(NHW_TEXT, 0, hdc, FALSE));
+               hdcBitmap = CreateCompatibleDC(hdc);
+               SetBkMode (hdc, TRANSPARENT);
+               GetClientRect (hWnd, &clientrect);
+               textrect = clientrect;
+               textrect.top += RIP_OFFSET_Y;
+               textrect.left += RIP_OFFSET_X;
+               textrect.right -= RIP_OFFSET_X;
+               if (data->window_text)
+               {
+                       DrawText (hdc, data->window_text, strlen(data->window_text), &textrect,
+                               DT_LEFT | DT_NOPREFIX | DT_CALCRECT);
+                       DrawText (hdc, data->window_text, strlen(data->window_text), &textrect,
+                               DT_LEFT | DT_NOPREFIX);
+               }
+               OldBitmap = SelectObject(hdcBitmap, GetNHApp()->bmpRip);
+               SetBkMode (hdc, OPAQUE);
+               bitmap_offset = (textrect.right - textrect.left - RIP_WIDTH) / 2;
+               BitBlt (hdc, textrect.left + bitmap_offset, textrect.bottom, RIP_WIDTH,
+                       RIP_HEIGHT, hdcBitmap, 0, 0, SRCCOPY);
+               SetBkMode (hdc, TRANSPARENT);
+               if (data->rip_text)
+               {
+                       textrect.left += RIP_GRAVE_X + bitmap_offset;
+                       textrect.top = textrect.bottom + RIP_GRAVE_Y;
+                       textrect.right = textrect.left + RIP_GRAVE_WIDTH;
+                       textrect.bottom = textrect.top + RIP_GRAVE_HEIGHT;
+                       DrawText (hdc, data->rip_text, strlen(data->rip_text), &textrect,
+                               DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_WORDBREAK);
+               }
+               SelectObject (hdcBitmap, OldBitmap);
+               SelectObject (hdc, OldFont);
+               DeleteDC (hdcBitmap);
+               EndPaint (hWnd, &ps);
+       }
+       break;
+
+       case WM_COMMAND:
+               switch (LOWORD(wParam))
+        {
+          case IDOK:
+                       mswin_window_mark_dead(mswin_winid_from_handle(hWnd));
+                       if( GetNHApp()->hMainWnd==hWnd )
+                               GetNHApp()->hMainWnd=NULL;
+                       DestroyWindow(hWnd);
+                       SetFocus(GetNHApp()->hMainWnd);
+                       return TRUE;
+               }
+       break;
+
+       case WM_CLOSE:
+           /* if we get this here, we saved the bones so we can just force a quit */
+
+           mswin_window_mark_dead(mswin_winid_from_handle(hWnd));
+           if( GetNHApp()->hMainWnd==hWnd )
+               GetNHApp()->hMainWnd=NULL;
+           DestroyWindow(hWnd);
+           SetFocus(GetNHApp()->hMainWnd);
+           program_state.stopprint++;
+           return TRUE;
+
+       case WM_DESTROY:
+               if( data ) {
+                       if( data->window_text ) free(data->window_text);
+                       if( data->rip_text ) free(data->rip_text);
+                       if (data->rip_bmp != NULL) DeleteObject(data->rip_bmp);
+                       free(data);
+                       SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+               }
+       break;
+
+       }
+       return FALSE;
+}
+
+void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHRIPWindow data;
+       static int InRipText = 1;
+       data = (PNHRIPWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch( wParam ) {
+               case MSNH_MSG_PUTSTR: {
+                       PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
+                       TCHAR   wbuf[BUFSZ];
+                       size_t text_size;
+
+                       if( !data->window_text ) {
+                               text_size = strlen(msg_data->text) + 4;
+                               data->window_text = (TCHAR*)malloc(text_size*sizeof(data->window_text[0]));
+                               ZeroMemory(data->window_text, text_size*sizeof(data->window_text[0]));
+                       } else {
+                               text_size = _tcslen(data->window_text) + strlen(msg_data->text) + 4;
+                               data->window_text = (TCHAR*)realloc(data->window_text, text_size*sizeof(data->window_text[0]));
+                       }
+                       if( !data->window_text ) break;
+
+                       _tcscat(data->window_text, NH_A2W(msg_data->text, wbuf, BUFSZ));
+                       _tcscat(data->window_text, TEXT("\r\n"));
+                       break;
+               }
+               case MSNH_MSG_DIED:
+               {
+                       data->rip_text = data->window_text;
+                       data->window_text = NULL;
+                       break;
+               }
+
+       }
+}
+
+void mswin_finish_rip_text(winid wid)
+{
+       SendMessage (mswin_hwnd_from_winid(wid), WM_MSNH_COMMAND,  MSNH_MSG_DIED, 0);
+}
diff --git a/win/win32/mhrip.h b/win/win32/mhrip.h
new file mode 100644 (file)
index 0000000..cc49355
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINRIPWindow_h
+#define MSWINRIPWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+void mswin_finish_rip_text(winid wid);
+HWND mswin_init_RIP_window (void);
+void mswin_display_RIP_window (HWND hwnd);
+
+#endif /* MSWINRIPWindow_h */
diff --git a/win/win32/mhsplash.c b/win/win32/mhsplash.c
new file mode 100644 (file)
index 0000000..3c974bc
--- /dev/null
@@ -0,0 +1,248 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include "resource.h"
+#include "mhsplash.h"
+#include "mhmsg.h"
+#include "mhfont.h"
+#include "patchlevel.h"
+#include "dlb.h"
+
+#define LLEN 128
+
+PNHWinApp GetNHApp(void);
+
+BOOL CALLBACK NHSplashWndProc(HWND, UINT, WPARAM, LPARAM);
+
+#define SPLASH_WIDTH           440
+#define SPLASH_HEIGHT  322
+#define SPLASH_VERSION_X               290
+#define SPLASH_VERSION_Y               10
+#define SPLASH_OFFSET_X                10
+#define SPLASH_OFFSET_Y                10
+
+extern HFONT version_splash_font;
+
+void mswin_display_splash_window (BOOL show_ver)
+{
+       MSG msg;
+       HWND mapWnd;
+       int left, top;
+       RECT splashrt;
+       RECT clientrt;
+       RECT controlrt;
+       HWND hWnd;
+       int buttop;
+       int strsize = 0;
+       int bufsize = BUFSZ;
+
+       char *buf = malloc(bufsize);
+       if (buf == NULL)
+           panic("out of memory");
+       buf[0] = '\0';
+
+       hWnd = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_SPLASH),
+           GetNHApp()->hMainWnd, NHSplashWndProc);
+       if( !hWnd ) panic("Cannot create Splash window");
+       mswin_init_splashfonts(hWnd);
+       GetNHApp()->hPopupWnd = hWnd;
+       mapWnd = mswin_hwnd_from_winid(WIN_MAP);
+       if( !IsWindow(mapWnd) ) mapWnd = GetNHApp()->hMainWnd;
+       /* Get control size */
+       GetWindowRect (GetDlgItem(hWnd, IDOK), &controlrt);
+       controlrt.right -= controlrt.left;
+       controlrt.bottom -= controlrt.top;
+       /* Get current client area */
+       GetClientRect (hWnd, &clientrt);
+       /* Get window size */
+       GetWindowRect(hWnd, &splashrt);
+       splashrt.right -= splashrt.left;
+       splashrt.bottom -= splashrt.top;
+       /* Get difference between requested client area and current value */
+       splashrt.right += SPLASH_WIDTH + SPLASH_OFFSET_X * 2 - clientrt.right;
+       splashrt.bottom += SPLASH_HEIGHT + controlrt.bottom + SPLASH_OFFSET_Y * 3 - clientrt.bottom;
+       /* Place the window centered */
+       /* On the screen, not on the parent window */
+       left = (GetSystemMetrics(SM_CXSCREEN) - splashrt.right) / 2;
+       top = (GetSystemMetrics(SM_CYSCREEN) - splashrt.bottom) / 2;
+       MoveWindow(hWnd, left, top, splashrt.right, splashrt.bottom, TRUE);
+       /* Place the OK control */
+       GetClientRect (hWnd, &clientrt);
+       MoveWindow (GetDlgItem(hWnd, IDOK),
+           (clientrt.right - clientrt.left - controlrt.right) / 2,
+           clientrt.bottom - controlrt.bottom - SPLASH_OFFSET_Y,
+           controlrt.right, controlrt.bottom, TRUE);
+       buttop = clientrt.bottom - controlrt.bottom - SPLASH_OFFSET_Y;
+       /* Place the text control */
+       GetWindowRect (GetDlgItem(hWnd, IDC_EXTRAINFO), &controlrt);
+       controlrt.right -= controlrt.left;
+       controlrt.bottom -= controlrt.top;
+       GetClientRect (hWnd, &clientrt);
+       MoveWindow (GetDlgItem(hWnd, IDC_EXTRAINFO),
+           clientrt.left + SPLASH_OFFSET_X,
+           buttop - controlrt.bottom - SPLASH_OFFSET_Y,
+           clientrt.right - 2 * SPLASH_OFFSET_X, controlrt.bottom, TRUE);
+       /* Fill the text control */
+       Sprintf(buf, "%s\r\n%s\r\n%s\r\n\r\n", COPYRIGHT_BANNER_A, COPYRIGHT_BANNER_B,
+           COPYRIGHT_BANNER_C);
+       strsize = strlen(buf);
+       
+       if (show_ver) {
+           /* Show complete version information */
+           dlb *f;
+
+           getversionstring(buf + strsize);
+           strcat(buf, "\r\n\r\n");
+           strsize = strlen(buf);
+
+           /* Add compile options */
+           f = dlb_fopen(OPTIONS_USED, RDTMODE);
+           if (f) {
+               char line[LLEN + 1];
+               
+               while (dlb_fgets(line, LLEN, f)) {
+                   size_t len;
+                   len = strlen(line);
+                   if (len > 0 && line[len - 1] == '\n') {
+                       line[len - 1] = '\r';
+                       line[len] = '\n';
+                       line[len + 1] = '\0';
+                       len++;
+                   }
+                   if (strsize + (int)len + 1 > bufsize)
+                   {
+                       bufsize += BUFSZ;
+                       buf = realloc(buf, bufsize);
+                       if (buf == NULL)
+                           panic("out of memory");
+                   }
+                   strcat(buf, line);
+                   strsize += len;
+               }
+               (void) dlb_fclose(f);
+           }
+       } else {
+           /* Show news, if any */
+           if (iflags.news) {      
+               FILE *nf;
+               
+               iflags.news = 0; /* prevent newgame() from re-displaying news */
+               nf = fopen(NEWS, "r");
+               if (nf != NULL) {
+                   char line[LLEN + 1];
+                   
+                   while (fgets(line, LLEN, nf)) {
+                       size_t len;
+                       len = strlen(line);
+                       if (len > 0 && line[len - 1] == '\n') {
+                           line[len - 1] = '\r';
+                           line[len] = '\n';
+                           line[len + 1] = '\0';
+                           len++;
+                       }
+                       if (strsize + (int)len + 1 > bufsize)
+                       {
+                           bufsize += BUFSZ;
+                           buf = realloc(buf, bufsize);
+                           if (buf == NULL)
+                               panic("out of memory");
+                       }
+                       strcat(buf, line);
+                       strsize += len;
+                   }
+                   (void) fclose(nf);
+               } 
+               else
+               {
+                   strcat(buf, "No news.");
+               }
+           }
+       }
+       SetWindowText(GetDlgItem(hWnd, IDC_EXTRAINFO), buf);
+       free(buf);
+       ShowWindow(hWnd, SW_SHOW);
+       
+       while( IsWindow(hWnd) &&
+           GetMessage(&msg, NULL, 0, 0)!=0 ) {
+           if( !IsDialogMessage(hWnd, &msg) ) {
+               TranslateMessage(&msg);
+               DispatchMessage(&msg);
+           }
+       }
+       
+       GetNHApp()->hPopupWnd = NULL;
+       mswin_destroy_splashfonts();
+}
+
+BOOL CALLBACK NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       HDC hdc;
+       switch (message)
+       {
+       case WM_INITDIALOG:
+           /* set text control font */
+               hdc = GetDC(hWnd);
+               SendMessage(hWnd, WM_SETFONT,
+                       (WPARAM)mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), 0);
+               ReleaseDC(hWnd, hdc);
+
+               SetFocus(GetDlgItem(hWnd, IDOK));
+       return FALSE;
+
+       case WM_PAINT:
+       {
+               char VersionString[BUFSZ];
+               RECT rt;
+               HDC hdcBitmap;
+               HANDLE OldBitmap;
+               HANDLE OldFont;
+               PAINTSTRUCT ps;
+
+               hdc = BeginPaint (hWnd, &ps);
+               /* Show splash graphic */
+
+               hdcBitmap = CreateCompatibleDC(hdc);
+               SetBkMode (hdc, OPAQUE);
+               OldBitmap = SelectObject(hdcBitmap, GetNHApp()->bmpSplash);
+               nhapply_image_transparent(hdc, SPLASH_OFFSET_X, SPLASH_OFFSET_Y,
+                   SPLASH_WIDTH, SPLASH_HEIGHT, 
+                   hdcBitmap, 0, 0, SPLASH_WIDTH, SPLASH_HEIGHT, 
+                   TILE_BK_COLOR);
+
+               SelectObject (hdcBitmap, OldBitmap);
+               DeleteDC (hdcBitmap);
+
+               SetBkMode (hdc, TRANSPARENT);
+               /* Print version number */
+
+               SetTextColor (hdc, RGB(0, 0, 0));
+               rt.right = rt.left = SPLASH_VERSION_X;
+               rt.bottom = rt.top = SPLASH_VERSION_Y;
+               Sprintf (VersionString, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR,
+                   PATCHLEVEL);
+               OldFont = SelectObject(hdc, version_splash_font);
+               DrawText (hdc, VersionString, strlen(VersionString), &rt,
+                   DT_LEFT | DT_NOPREFIX | DT_CALCRECT);
+               DrawText (hdc, VersionString, strlen(VersionString), &rt,
+                   DT_LEFT | DT_NOPREFIX);
+
+               EndPaint (hWnd, &ps);
+       }
+       break;
+
+       case WM_COMMAND:
+       switch (LOWORD(wParam))
+        {
+               case IDOK:
+                       mswin_window_mark_dead(mswin_winid_from_handle(hWnd));
+                       if( GetNHApp()->hMainWnd==hWnd )
+                               GetNHApp()->hMainWnd=NULL;
+                       DestroyWindow(hWnd);
+                       SetFocus(GetNHApp()->hMainWnd);
+                       return TRUE;
+               }
+       break;
+       }
+       return FALSE;
+}
diff --git a/win/win32/mhsplash.h b/win/win32/mhsplash.h
new file mode 100644 (file)
index 0000000..9966c3d
--- /dev/null
@@ -0,0 +1,13 @@
+/* Copyright (C) 2002 by Alex Kompel */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINSplashWindow_h
+#define MSWINSplashWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+void mswin_display_splash_window (BOOL);
+
+#endif /* MSWINSplashWindow_h */
diff --git a/win/win32/mhstatus.c b/win/win32/mhstatus.c
new file mode 100644 (file)
index 0000000..050b8ba
--- /dev/null
@@ -0,0 +1,176 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include "mhstatus.h"
+#include "mhmsg.h"
+#include "mhfont.h"
+
+#define NHSW_LINES    2
+#define MAXWINDOWTEXT BUFSZ
+
+typedef struct mswin_nethack_status_window {
+       int   index;
+       char  window_text[NHSW_LINES][MAXWINDOWTEXT+1];
+} NHStatusWindow, *PNHStatusWindow;
+
+static TCHAR szStatusWindowClass[] = TEXT("MSNHStatusWndClass");
+LRESULT CALLBACK       StatusWndProc(HWND, UINT, WPARAM, LPARAM);
+static void register_status_window_class(void);
+
+#define DEFAULT_COLOR_BG_STATUS        COLOR_WINDOW
+#define DEFAULT_COLOR_FG_STATUS        COLOR_WINDOWTEXT
+
+HWND mswin_init_status_window () {
+       static int run_once = 0;
+       HWND ret;
+       NHStatusWindow* data;
+
+       if( !run_once ) {
+               register_status_window_class( );
+               run_once = 1;
+       }
+       
+       ret = CreateWindow(                                
+                       szStatusWindowClass,
+                       NULL,
+                       WS_CHILD | WS_DISABLED | WS_CLIPSIBLINGS,
+                       0,  /* x position */
+                       0,  /* y position */
+                       0,  /* x-size - we will set it later */
+                       0,  /* y-size - we will set it later */
+                       GetNHApp()->hMainWnd,
+                       NULL,
+                       GetNHApp()->hApp,
+                       NULL );
+       if( !ret ) panic("Cannot create status window");
+       
+       EnableWindow(ret, FALSE);
+
+       data = (PNHStatusWindow)malloc(sizeof(NHStatusWindow));
+       if( !data ) panic("out of memory");
+
+       ZeroMemory(data, sizeof(NHStatusWindow));
+       SetWindowLong(ret, GWL_USERDATA, (LONG)data);
+       return ret;
+}
+
+void register_status_window_class()
+{
+       WNDCLASS wcex;
+       ZeroMemory( &wcex, sizeof(wcex));
+
+       wcex.style                      = CS_NOCLOSE;
+       wcex.lpfnWndProc        = (WNDPROC)StatusWndProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = GetNHApp()->hApp;
+       wcex.hIcon                      = NULL;
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = status_bg_brush 
+               ? status_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_STATUS);
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szStatusWindowClass;
+
+       RegisterClass(&wcex);
+}
+    
+    
+LRESULT CALLBACK StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       RECT rt;
+       PAINTSTRUCT ps;
+       HDC hdc;
+       PNHStatusWindow data;
+       
+       data = (PNHStatusWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch (message) 
+       {
+       case WM_MSNH_COMMAND: {
+               switch( wParam ) {
+               case MSNH_MSG_PUTSTR: {
+                       PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
+                       strncpy(data->window_text[data->index], msg_data->text, 
+                                   MAXWINDOWTEXT);
+                       strncat(data->window_text[data->index], "\n", 
+                                   MAXWINDOWTEXT-strlen(data->window_text[data->index]));
+                       data->index = (data->index+1) % NHSW_LINES;
+                       InvalidateRect(hWnd, NULL, TRUE);
+                       break;
+               }
+               case MSNH_MSG_CLEAR_WINDOW:
+                       data->index = 0;
+                       ZeroMemory(data->window_text, sizeof(data->window_text));
+                       InvalidateRect(hWnd, NULL, TRUE);
+                       break;
+               }
+       } break;
+
+       case WM_PAINT: {
+                   int i;
+                       SIZE sz;
+                       HGDIOBJ oldFont;
+                       TCHAR wbuf[BUFSZ];
+                       COLORREF OldBg, OldFg;
+
+                       hdc = BeginPaint(hWnd, &ps);
+                       GetClientRect(hWnd, &rt);
+                       
+                       oldFont = SelectObject(hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE));
+
+                       OldBg = SetBkColor(hdc, status_bg_brush 
+                               ? status_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_STATUS));
+                       OldFg = SetTextColor(hdc, status_fg_brush 
+                               ? status_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_STATUS));
+                       
+                       for(i=0; i<NHSW_LINES; i++ ) {
+                               GetTextExtentPoint32(hdc, NH_A2W(data->window_text[i], wbuf, sizeof(wbuf)), strlen(data->window_text[i]), &sz);
+                               NH_A2W(data->window_text[i], wbuf, BUFSZ);
+                               DrawText(hdc, wbuf, strlen(data->window_text[i]), &rt, DT_LEFT | DT_END_ELLIPSIS);
+                               rt.top += sz.cy;
+                       }
+
+                       SelectObject(hdc, oldFont);
+                       SetTextColor (hdc, OldFg);
+                       SetBkColor (hdc, OldBg);
+                       EndPaint(hWnd, &ps);
+               } break;
+
+       case WM_DESTROY:
+               free(data);
+               SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+               break;
+
+       case WM_SETFOCUS:
+               SetFocus(GetNHApp()->hMainWnd);
+               break;
+
+       default:
+               return DefWindowProc(hWnd, message, wParam, lParam);
+   }
+   return 0;
+}
+
+void mswin_status_window_size (HWND hWnd, LPSIZE sz)
+{
+    TEXTMETRIC tm;
+       HGDIOBJ saveFont;
+       HDC hdc;
+       PNHStatusWindow data;
+       RECT rt;
+       GetWindowRect(hWnd, &rt);
+       sz->cx = rt.right - rt.left;
+       sz->cy = rt.bottom - rt.top;
+
+       data = (PNHStatusWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if(data) {
+               hdc = GetDC(hWnd);
+               saveFont = SelectObject(hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE));
+               GetTextMetrics(hdc, &tm);
+
+               sz->cy = tm.tmHeight * NHSW_LINES;
+
+               SelectObject(hdc, saveFont);
+               ReleaseDC(hWnd, hdc);
+       }
+}
diff --git a/win/win32/mhstatus.h b/win/win32/mhstatus.h
new file mode 100644 (file)
index 0000000..e073a80
--- /dev/null
@@ -0,0 +1,14 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINStatusWindow_h
+#define MSWINStatusWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+HWND mswin_init_status_window (void);
+void mswin_status_window_size (HWND hWnd, LPSIZE sz);
+
+#endif /* MSWINStatusWindow_h */
diff --git a/win/win32/mhtext.c b/win/win32/mhtext.c
new file mode 100644 (file)
index 0000000..3d541d5
--- /dev/null
@@ -0,0 +1,254 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "winMS.h"
+#include "resource.h"
+#include "mhtext.h"
+#include "mhmsg.h"
+#include "mhfont.h"
+
+PNHWinApp GetNHApp(void);
+
+typedef struct mswin_nethack_text_window {
+       TCHAR*  window_text;
+} NHTextWindow, *PNHTextWindow;
+
+static WNDPROC  editControlWndProc = 0;
+#define DEFAULT_COLOR_BG_TEXT  COLOR_WINDOW
+#define DEFAULT_COLOR_FG_TEXT  COLOR_WINDOWTEXT
+
+BOOL   CALLBACK        NHTextWndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK       NHEditHookWndProc(HWND, UINT, WPARAM, LPARAM);
+static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void LayoutText(HWND hwnd);
+
+HWND mswin_init_text_window () {
+       HWND ret;
+       PNHTextWindow data;
+
+       ret = CreateDialog(
+                       GetNHApp()->hApp,
+                       MAKEINTRESOURCE(IDD_NHTEXT),
+                       GetNHApp()->hMainWnd,
+                       NHTextWndProc
+       );
+       if( !ret ) panic("Cannot create text window");
+
+       data = (PNHTextWindow)malloc(sizeof(NHTextWindow));
+       if( !data ) panic("out of memory");
+
+       ZeroMemory(data, sizeof(NHTextWindow));
+       SetWindowLong(ret, GWL_USERDATA, (LONG)data);
+       return ret;
+}
+
+void mswin_display_text_window (HWND hWnd)
+{
+       PNHTextWindow data;
+       
+       data = (PNHTextWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       if( data && data->window_text ) {
+               HWND control;
+               control = GetDlgItem(hWnd, IDC_TEXT_CONTROL);
+               SendMessage(control, EM_FMTLINES, 1, 0 );
+               SetWindowText(GetDlgItem(hWnd, IDC_TEXT_CONTROL), data->window_text);
+       }
+
+       mswin_popup_display(hWnd, NULL);
+       mswin_popup_destroy(hWnd);
+}
+    
+BOOL CALLBACK NHTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       HWND control;
+       HDC hdc;
+       PNHTextWindow data;
+    TCHAR title[MAX_LOADSTRING];
+       
+       data = (PNHTextWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch (message) 
+       {
+       case WM_INITDIALOG:
+           /* set text control font */
+               control = GetDlgItem(hWnd, IDC_TEXT_CONTROL);
+               if( !control ) {
+                       panic("cannot get text view window");
+               }
+
+               hdc = GetDC(control);
+               SendMessage(control, WM_SETFONT, (WPARAM)mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), 0);
+               ReleaseDC(control, hdc);
+
+               /* subclass edit control */
+               editControlWndProc = (WNDPROC)GetWindowLong(control, GWL_WNDPROC);
+               SetWindowLong(control, GWL_WNDPROC, (LONG)NHEditHookWndProc);
+
+               SetFocus(control);
+
+        /* Even though the dialog has no caption, you can still set the title 
+           which shows on Alt-Tab */
+        LoadString(GetNHApp()->hApp, IDS_APP_TITLE, title, MAX_LOADSTRING);
+        SetWindowText(hWnd, title);
+       return FALSE;
+
+       case WM_MSNH_COMMAND:
+               onMSNHCommand(hWnd, wParam, lParam);
+       break;
+
+       case WM_SIZE:
+               LayoutText(hWnd);
+       return FALSE;
+
+       case WM_COMMAND:
+               switch (LOWORD(wParam)) 
+        { 
+          case IDOK: 
+                 case IDCANCEL:
+                       mswin_window_mark_dead(mswin_winid_from_handle(hWnd));
+                       if( GetNHApp()->hMainWnd==hWnd ) 
+                               GetNHApp()->hMainWnd=NULL;
+                       DestroyWindow(hWnd);
+                       SetFocus(GetNHApp()->hMainWnd);
+                       return TRUE;
+          case IDC_TEXT_CONTROL:
+            switch (HIWORD(wParam))
+            {
+              case EN_SETFOCUS:
+                HideCaret((HWND)lParam);
+                return TRUE;
+            }
+               }
+       break;
+
+       case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */
+               HDC hdcEdit = (HDC) wParam; 
+               HWND hwndEdit = (HWND) lParam;
+               if( hwndEdit == GetDlgItem(hWnd, IDC_TEXT_CONTROL) ) {
+                       SetBkColor(hdcEdit, 
+                               text_bg_brush ? text_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_TEXT)
+                               );
+                       SetTextColor(hdcEdit, 
+                               text_fg_brush ? text_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_TEXT) 
+                               ); 
+                       return (BOOL)(text_bg_brush 
+                                       ? text_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT));
+               }
+       } return FALSE;
+
+       case WM_DESTROY:
+               if( data ) {
+                       if( data->window_text ) free(data->window_text);
+                       free(data);
+                       SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
+               }
+       break;
+
+       }
+       return FALSE;
+}
+
+void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+       PNHTextWindow data;
+       
+       data = (PNHTextWindow)GetWindowLong(hWnd, GWL_USERDATA);
+       switch( wParam ) {
+       case MSNH_MSG_PUTSTR: {
+               PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
+               TCHAR   wbuf[BUFSZ];
+               size_t text_size;
+
+               if( !data->window_text ) {
+                       text_size = strlen(msg_data->text) + 4;
+                       data->window_text = (TCHAR*)malloc(text_size*sizeof(data->window_text[0]));
+                       ZeroMemory(data->window_text, text_size*sizeof(data->window_text[0]));
+               } else {
+                       text_size = _tcslen(data->window_text) + strlen(msg_data->text) + 4;
+                       data->window_text = (TCHAR*)realloc(data->window_text, text_size*sizeof(data->window_text[0]));
+               }
+               if( !data->window_text ) break;
+               
+               _tcscat(data->window_text, NH_A2W(msg_data->text, wbuf, BUFSZ)); 
+               _tcscat(data->window_text, TEXT("\r\n"));
+               break;
+       }
+       }
+}
+
+void LayoutText(HWND hWnd) 
+{
+       HWND  btn_ok;
+       HWND  text;
+       RECT  clrt, rt;
+       POINT pt_elem, pt_ok;
+       SIZE  sz_elem, sz_ok;
+
+       text = GetDlgItem(hWnd, IDC_TEXT_CONTROL);
+       btn_ok = GetDlgItem(hWnd, IDOK);
+
+       /* get window coordinates */
+       GetClientRect(hWnd, &clrt );
+       
+       /* set window placements */
+       GetWindowRect(btn_ok, &rt);
+       sz_ok.cx = clrt.right - clrt.left;
+       sz_ok.cy = rt.bottom-rt.top;
+       pt_ok.x = clrt.left;
+       pt_ok.y = clrt.bottom - sz_ok.cy;
+
+       pt_elem.x = clrt.left;
+       pt_elem.y = clrt.top;
+       sz_elem.cx = clrt.right - clrt.left;
+       sz_elem.cy = pt_ok.y;
+
+       MoveWindow(text, pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE );
+       MoveWindow(btn_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE );
+}
+
+/* Edit box hook */
+LRESULT CALLBACK NHEditHookWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch(message) {
+
+       case WM_KEYDOWN:
+               switch (wParam)
+        {
+       /* close on space in Windows mode
+           page down on space in NetHack mode */
+        case VK_SPACE:
+        {   
+            SCROLLINFO si;
+
+            si.cbSize = sizeof(SCROLLINFO);
+            si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
+            GetScrollInfo(hWnd, SB_VERT, &si);
+            /* If nethackmode and not at the end of the list */
+            if (GetNHApp()->regNetHackMode &&
+                    (si.nPos + (int)si.nPage) <= (si.nMax - si.nMin))
+                SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0);
+            else
+                           PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0);
+            return 0;
+        }
+        case VK_NEXT:
+            SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0);
+            return 0;
+        case VK_PRIOR:
+            SendMessage(hWnd, EM_SCROLL, SB_PAGEUP, 0);
+            return 0;
+        case VK_UP:
+            SendMessage(hWnd, EM_SCROLL, SB_LINEUP, 0);
+            return 0;
+        case VK_DOWN:
+            SendMessage(hWnd, EM_SCROLL, SB_LINEDOWN, 0);
+            return 0;
+
+               }
+       break;
+       }
+
+       if( editControlWndProc ) 
+               return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam);
+       else 
+               return 0;
+}
diff --git a/win/win32/mhtext.h b/win/win32/mhtext.h
new file mode 100644 (file)
index 0000000..64be03d
--- /dev/null
@@ -0,0 +1,14 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef MSWINTextWindow_h
+#define MSWINTextWindow_h
+
+#include "winMS.h"
+#include "config.h"
+#include "global.h"
+
+HWND mswin_init_text_window (void);
+void mswin_display_text_window (HWND hwnd);
+
+#endif /* MSWINTextWindow_h */
diff --git a/win/win32/mnsel.uu b/win/win32/mnsel.uu
new file mode 100644 (file)
index 0000000..69c3965
--- /dev/null
@@ -0,0 +1,6 @@
+begin 600 mnsel.bmp
+M0DU^`````````#X````H````$````!`````!``$``````$````!T$@``=!(`
+M`````````````````/___P```````````#_\```W_```,_P``"7\```F_```
+D)WP``">\```_W```/^P``#_T```__```/_P`````````````
+`
+end
diff --git a/win/win32/mnselcnt.uu b/win/win32/mnselcnt.uu
new file mode 100644 (file)
index 0000000..72f1916
--- /dev/null
@@ -0,0 +1,6 @@
+begin 600 mnselcnt.bmp
+M0DU^`````````#X````H````$````!`````!``$``````$````!T$@``=!(`
+M`````````````````/___P```````````#_\```__```.]P``#`,```[W```
+D.]P``#O<```[W```,`P``#O<```__```/_P`````````````
+`
+end
diff --git a/win/win32/mnunsel.uu b/win/win32/mnunsel.uu
new file mode 100644 (file)
index 0000000..0e3d163
--- /dev/null
@@ -0,0 +1,6 @@
+begin 600 mnunsel.bmp
+M0DU^`````````#X````H````$````!`````!``$``````$````!T$@``=!(`
+M`````````````````/___P```````````#_\```__```/_P``#_\```__```
+D/_P``#_\```__```/_P``#_\```__```/_P`````````````
+`
+end
diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c
new file mode 100644 (file)
index 0000000..698c858
--- /dev/null
@@ -0,0 +1,2353 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file implements the interface between the window port specific
+ * code in the mswin port and the rest of the nethack game engine. 
+*/
+
+#include "hack.h"
+#include "dlb.h"
+#include "func_tab.h"   /* for extended commands */
+#include "winMS.h"
+#include "mhmap.h"
+#include "mhstatus.h"
+#include "mhtext.h"
+#include "mhmsgwnd.h"
+#include "mhmenu.h"
+#include "mhsplash.h"
+#include "mhmsg.h"
+#include "mhinput.h"
+#include "mhaskyn.h"
+#include "mhdlg.h"
+#include "mhrip.h"
+#include "mhmain.h"
+#include "mhfont.h"
+#include "resource.h"
+
+#define LLEN 128
+
+extern const char *killed_by_prefix[];
+
+#ifdef _DEBUG
+extern void logDebug(const char *fmt, ...);
+#else
+void logDebug(const char *fmt, ...) { }
+#endif
+
+static void mswin_main_loop(void);
+static BOOL initMapTiles(void);
+static void mswin_color_from_string(char *colorstring, HBRUSH* brushptr, COLORREF *colorptr);
+static void prompt_for_player_selection(void);
+
+#define TOTAL_BRUSHES  10
+HBRUSH brush_table[TOTAL_BRUSHES];
+int max_brush = 0;
+
+HBRUSH menu_bg_brush = NULL;
+HBRUSH menu_fg_brush = NULL;
+HBRUSH text_bg_brush = NULL;
+HBRUSH text_fg_brush = NULL;
+HBRUSH status_bg_brush = NULL;
+HBRUSH status_fg_brush = NULL;
+HBRUSH message_bg_brush = NULL;
+HBRUSH message_fg_brush = NULL;
+
+COLORREF menu_bg_color = RGB(0, 0, 0);
+COLORREF menu_fg_color = RGB(0xFF, 0xFF, 0xFF);
+COLORREF text_bg_color = RGB(0, 0, 0);
+COLORREF text_fg_color = RGB(0xFF, 0xFF, 0xFF);
+COLORREF status_bg_color = RGB(0, 0, 0);
+COLORREF status_fg_color = RGB(0xFF, 0xFF, 0xFF);
+COLORREF message_bg_color = RGB(0, 0, 0);
+COLORREF message_fg_color = RGB(0xFF, 0xFF, 0xFF);
+
+/* Interface definition, for windows.c */
+struct window_procs mswin_procs = {
+    "MSWIN",
+    WC_COLOR|WC_HILITE_PET|WC_ALIGN_MESSAGE|WC_ALIGN_STATUS|
+       WC_INVERSE|WC_SCROLL_AMOUNT|WC_SCROLL_MARGIN|WC_MAP_MODE|
+       WC_FONT_MESSAGE|WC_FONT_STATUS|WC_FONT_MENU|WC_FONT_TEXT|WC_FONT_MAP|
+       WC_FONTSIZ_MESSAGE|WC_FONTSIZ_STATUS|WC_FONTSIZ_MENU|WC_FONTSIZ_TEXT|
+       WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE|WC_VARY_MSGCOUNT|
+       WC_WINDOWCOLORS|WC_PLAYER_SELECTION|WC_SPLASH_SCREEN|WC_POPUP_DIALOG,
+    0L,
+    mswin_init_nhwindows,
+    mswin_player_selection,
+    mswin_askname,
+    mswin_get_nh_event,
+    mswin_exit_nhwindows,
+    mswin_suspend_nhwindows,
+    mswin_resume_nhwindows,
+    mswin_create_nhwindow,
+    mswin_clear_nhwindow,
+    mswin_display_nhwindow,
+    mswin_destroy_nhwindow,
+    mswin_curs,
+    mswin_putstr,
+    mswin_display_file,
+    mswin_start_menu,
+    mswin_add_menu,
+    mswin_end_menu,
+    mswin_select_menu,
+    genl_message_menu,         /* no need for X-specific handling */
+    mswin_update_inventory,
+    mswin_mark_synch,
+    mswin_wait_synch,
+#ifdef CLIPPING
+    mswin_cliparound,
+#endif
+#ifdef POSITIONBAR
+    donull,
+#endif
+    mswin_print_glyph,
+    mswin_raw_print,
+    mswin_raw_print_bold,
+    mswin_nhgetch,
+    mswin_nh_poskey,
+    mswin_nhbell,
+    mswin_doprev_message,
+    mswin_yn_function,
+    mswin_getlin,
+    mswin_get_ext_cmd,
+    mswin_number_pad,
+    mswin_delay_output,
+#ifdef CHANGE_COLOR    /* only a Mac option currently */
+       mswin,
+       mswin_change_background,
+#endif
+    /* other defs that really should go away (they're tty specific) */
+    mswin_start_screen,
+    mswin_end_screen,
+    mswin_outrip,
+    mswin_preference_update,
+};
+
+
+/*  
+init_nhwindows(int* argcp, char** argv)
+                -- Initialize the windows used by NetHack.  This can also
+                   create the standard windows listed at the top, but does
+                   not display them.
+                -- Any commandline arguments relevant to the windowport
+                   should be interpreted, and *argcp and *argv should
+                   be changed to remove those arguments.
+                -- When the message window is created, the variable
+                   iflags.window_inited needs to be set to TRUE.  Otherwise
+                   all plines() will be done via raw_print().
+                ** Why not have init_nhwindows() create all of the "standard"
+                ** windows?  Or at least all but WIN_INFO?      -dean
+*/
+void mswin_init_nhwindows(int* argc, char** argv)
+{
+       logDebug("mswin_init_nhwindows()\n");
+
+#ifdef _DEBUG
+       {
+               /* truncate trace file */
+               FILE *dfp = fopen("nhtrace.log", "w");
+               fclose(dfp);
+       }
+#endif
+    mswin_nh_input_init();
+
+       /* set it to WIN_ERR so we can detect attempts to
+          use this ID before it is inialized */
+       WIN_MAP = WIN_ERR;
+
+    /* Read Windows settings from the reqistry */
+    /* First set safe defaults */
+    GetNHApp()->regMainMinX = CW_USEDEFAULT;
+    mswin_read_reg();
+    /* Create the main window */
+    GetNHApp()->hMainWnd = mswin_init_main_window();
+    if (!GetNHApp()->hMainWnd)
+    {
+        panic("Cannot create main window");
+    }
+
+    /* Set menu check mark for interface mode */
+    mswin_menu_check_intf_mode();
+
+    /* check default values */
+       if( iflags.wc_fontsiz_status<NHFONT_SIZE_MIN || 
+               iflags.wc_fontsiz_status>NHFONT_SIZE_MAX )
+               iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
+
+       if( iflags.wc_fontsiz_message<NHFONT_SIZE_MIN || 
+               iflags.wc_fontsiz_message>NHFONT_SIZE_MAX )
+               iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
+
+       if( iflags.wc_fontsiz_text<NHFONT_SIZE_MIN || 
+               iflags.wc_fontsiz_text>NHFONT_SIZE_MAX )
+               iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
+
+       if( iflags.wc_fontsiz_menu<NHFONT_SIZE_MIN || 
+               iflags.wc_fontsiz_menu>NHFONT_SIZE_MAX )
+               iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
+
+       if( iflags.wc_align_message==0 ) iflags.wc_align_message = ALIGN_TOP;
+       if( iflags.wc_align_status==0 ) iflags.wc_align_status = ALIGN_BOTTOM;
+       if( iflags.wc_scroll_margin==0 ) iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN;
+       if( iflags.wc_scroll_amount==0 ) iflags.wc_scroll_amount = DEF_CLIPAROUND_AMOUNT;
+       if( iflags.wc_tile_width==0 ) iflags.wc_tile_width = TILE_X;
+       if( iflags.wc_tile_height==0 ) iflags.wc_tile_height = TILE_Y;
+
+       if( iflags.wc_vary_msgcount==0 ) iflags.wc_vary_msgcount = 4;
+
+       /* force tabs in menus */
+       iflags.menu_tab_sep = 1;
+
+       /* force toptenwin to be true.  toptenwin is the option that decides whether to
+        * write output to a window or stdout.  stdout doesn't make sense on Windows
+        * non-console applications
+        */
+       flags.toptenwin = 1;
+       set_option_mod_status("toptenwin", SET_IN_FILE);
+       set_option_mod_status("perm_invent", SET_IN_FILE);
+
+       /* initialize map tiles bitmap */
+       initMapTiles();
+
+       /* set tile-related options to readonly */
+       set_wc_option_mod_status(
+          WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE,
+          DISP_IN_GAME);
+
+       /* set font-related options to change in the game */
+       set_wc_option_mod_status(
+               WC_HILITE_PET |
+               WC_ALIGN_MESSAGE | 
+               WC_ALIGN_STATUS |
+               WC_SCROLL_AMOUNT |
+               WC_SCROLL_MARGIN |
+               WC_MAP_MODE |
+               WC_FONT_MESSAGE |
+               WC_FONT_STATUS |
+               WC_FONT_MENU |
+               WC_FONT_TEXT |
+               WC_FONTSIZ_MESSAGE | 
+               WC_FONTSIZ_STATUS | 
+               WC_FONTSIZ_MENU | 
+               WC_FONTSIZ_TEXT |
+               WC_VARY_MSGCOUNT,
+               SET_IN_GAME 
+       );
+
+       mswin_color_from_string(iflags.wc_foregrnd_menu, &menu_fg_brush, &menu_fg_color);
+       mswin_color_from_string(iflags.wc_foregrnd_message, &message_fg_brush, &message_fg_color);
+       mswin_color_from_string(iflags.wc_foregrnd_status, &status_fg_brush, &status_fg_color);
+       mswin_color_from_string(iflags.wc_foregrnd_text, &text_fg_brush, &text_fg_color);
+       mswin_color_from_string(iflags.wc_backgrnd_menu, &menu_bg_brush, &menu_bg_color);
+       mswin_color_from_string(iflags.wc_backgrnd_message, &message_bg_brush, &message_bg_color);
+       mswin_color_from_string(iflags.wc_backgrnd_status, &status_bg_brush, &status_bg_color);
+       mswin_color_from_string(iflags.wc_backgrnd_text, &text_bg_brush, &text_bg_color);
+
+ if (iflags.wc_splash_screen) mswin_display_splash_window(FALSE);
+       iflags.window_inited = TRUE;
+}
+
+
+/* Do a window-port specific player type selection. If player_selection()
+   offers a Quit option, it is its responsibility to clean up and terminate
+   the process. You need to fill in pl_character[0].
+*/
+void mswin_player_selection(void)
+{
+       int nRole;
+
+       logDebug("mswin_player_selection()\n");
+
+       if (iflags.wc_player_selection == VIA_DIALOG) {
+           /* pick player type randomly (use pre-selected role/race/gender/alignment) */
+           if( flags.randomall ) {
+               if (flags.initrole < 0) {
+                       flags.initrole = pick_role(flags.initrace, flags.initgend,
+                                                       flags.initalign, PICK_RANDOM);
+                       if (flags.initrole < 0) {
+                               raw_print("Incompatible role!");
+                               flags.initrole = randrole();
+                       }
+               }
+
+               if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
+                       flags.initrace = pick_race(flags.initrole, flags.initgend,
+                                                               flags.initalign, PICK_RANDOM);
+                       if (flags.initrace < 0) {
+                               raw_print("Incompatible race!");
+                               flags.initrace = randrace(flags.initrole);
+                       }
+               }
+
+               if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
+                                               flags.initgend)) {
+                       flags.initgend = pick_gend(flags.initrole, flags.initrace,
+                                                       flags.initalign, PICK_RANDOM);
+                       if (flags.initgend < 0) {
+                               raw_print("Incompatible gender!");
+                               flags.initgend = randgend(flags.initrole, flags.initrace);
+                       }
+               }
+
+               if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
+                                                               flags.initalign)) {
+                       flags.initalign = pick_align(flags.initrole, flags.initrace,
+                                                               flags.initgend, PICK_RANDOM);
+                       if (flags.initalign < 0) {
+                               raw_print("Incompatible alignment!");
+                               flags.initalign = randalign(flags.initrole, flags.initrace);
+                       }
+               }
+           } else {
+               /* select a role */
+               if( mswin_player_selection_window( &nRole ) == IDCANCEL ) {
+                       bail(0);
+               }
+           }
+       } else { /* iflags.wc_player_selection == VIA_PROMPTS */
+           prompt_for_player_selection();
+       }
+}
+
+void prompt_for_player_selection(void)
+{
+       int i, k, n;
+       char pick4u = 'n', thisch, lastch = 0;
+       char pbuf[QBUFSZ], plbuf[QBUFSZ];
+       winid win;
+       anything any;
+       menu_item *selected = 0;
+        DWORD box_result;
+
+       logDebug("prompt_for_player_selection()\n");
+
+       /* prevent an unnecessary prompt */
+       rigid_role_checks();
+
+       /* Should we randomly pick for the player? */
+       if (!flags.randomall &&
+           (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE ||
+            flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {
+           /* int echoline; */
+           char *prompt = build_plselection_prompt(pbuf, QBUFSZ, flags.initrole,
+                               flags.initrace, flags.initgend, flags.initalign);
+
+           /* tty_putstr(BASE_WINDOW, 0, ""); */
+           /* echoline = wins[BASE_WINDOW]->cury; */
+            box_result = NHMessageBox(NULL, prompt, 
+                                       MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON1);
+            pick4u = (box_result == IDYES) ? 'y' : (box_result == IDNO) ? 'n' : '\033';
+           /* tty_putstr(BASE_WINDOW, 0, prompt); */
+           do {
+               /* pick4u = lowc(readchar()); */
+               if (index(quitchars, pick4u)) pick4u = 'y';
+           } while(!index(ynqchars, pick4u));
+           if ((int)strlen(prompt) + 1 < CO) {
+               /* Echo choice and move back down line */
+               /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline, pick4u); */
+               /* tty_putstr(BASE_WINDOW, 0, ""); */
+           } else
+               /* Otherwise it's hard to tell where to echo, and things are
+                * wrapping a bit messily anyway, so (try to) make sure the next
+                * question shows up well and doesn't get wrapped at the
+                * bottom of the window.
+                */
+               /* tty_clear_nhwindow(BASE_WINDOW) */ ;
+           
+           if (pick4u != 'y' && pick4u != 'n') {
+give_up:       /* Quit */
+               if (selected) free((genericptr_t) selected);
+               bail((char *)0);
+               /*NOTREACHED*/
+               return;
+           }
+       }
+
+       (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+
+       /* Select a role, if necessary */
+       /* we'll try to be compatible with pre-selected race/gender/alignment,
+        * but may not succeed */
+       if (flags.initrole < 0) {
+           char rolenamebuf[QBUFSZ];
+           /* Process the choice */
+           if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) {
+               /* Pick a random role */
+               flags.initrole = pick_role(flags.initrace, flags.initgend,
+                                               flags.initalign, PICK_RANDOM);
+               if (flags.initrole < 0) {
+                   /* tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); */
+                   flags.initrole = randrole();
+               }
+           } else {
+               /* tty_clear_nhwindow(BASE_WINDOW); */
+               /* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */
+               /* Prompt for a role */
+               win = create_nhwindow(NHW_MENU);
+               start_menu(win);
+               any.a_void = 0;         /* zero out all bits */
+               for (i = 0; roles[i].name.m; i++) {
+                   if (ok_role(i, flags.initrace, flags.initgend,
+                                                       flags.initalign)) {
+                       any.a_int = i+1;        /* must be non-zero */
+                       thisch = lowc(roles[i].name.m[0]);
+                       if (thisch == lastch) thisch = highc(thisch);
+                       if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) {
+                               if (flags.initgend == 1  && roles[i].name.f)
+                                       Strcpy(rolenamebuf, roles[i].name.f);
+                               else
+                                       Strcpy(rolenamebuf, roles[i].name.m);
+                       } else {
+                               if (roles[i].name.f) {
+                                       Strcpy(rolenamebuf, roles[i].name.m);
+                                       Strcat(rolenamebuf, "/");
+                                       Strcat(rolenamebuf, roles[i].name.f);
+                               } else 
+                                       Strcpy(rolenamebuf, roles[i].name.m);
+                       }       
+                       add_menu(win, NO_GLYPH, &any, thisch,
+                           0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED);
+                       lastch = thisch;
+                   }
+               }
+               any.a_int = pick_role(flags.initrace, flags.initgend,
+                                   flags.initalign, PICK_RANDOM)+1;
+               if (any.a_int == 0)     /* must be non-zero */
+                   any.a_int = randrole()+1;
+               add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                               "Random", MENU_UNSELECTED);
+               any.a_int = i+1;        /* must be non-zero */
+               add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                               "Quit", MENU_UNSELECTED);
+               Sprintf(pbuf, "Pick a role for your %s", plbuf);
+               end_menu(win, pbuf);
+               n = select_menu(win, PICK_ONE, &selected);
+               destroy_nhwindow(win);
+
+               /* Process the choice */
+               if (n != 1 || selected[0].item.a_int == any.a_int)
+                   goto give_up;               /* Selected quit */
+
+               flags.initrole = selected[0].item.a_int - 1;
+               free((genericptr_t) selected),  selected = 0;
+           }
+           (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+       }
+       
+       /* Select a race, if necessary */
+       /* force compatibility with role, try for compatibility with
+        * pre-selected gender/alignment */
+       if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
+           /* pre-selected race not valid */
+           if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) {
+               flags.initrace = pick_race(flags.initrole, flags.initgend,
+                                                       flags.initalign, PICK_RANDOM);
+               if (flags.initrace < 0) {
+                   /* tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); */
+                   flags.initrace = randrace(flags.initrole);
+               }
+           } else {    /* pick4u == 'n' */
+               /* Count the number of valid races */
+               n = 0;  /* number valid */
+               k = 0;  /* valid race */
+               for (i = 0; races[i].noun; i++) {
+                   if (ok_race(flags.initrole, i, flags.initgend,
+                                                       flags.initalign)) {
+                       n++;
+                       k = i;
+                   }
+               }
+               if (n == 0) {
+                   for (i = 0; races[i].noun; i++) {
+                       if (validrace(flags.initrole, i)) {
+                           n++;
+                           k = i;
+                       }
+                   }
+               }
+
+               /* Permit the user to pick, if there is more than one */
+               if (n > 1) {
+                   /* tty_clear_nhwindow(BASE_WINDOW); */
+                   /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */
+                   win = create_nhwindow(NHW_MENU);
+                   start_menu(win);
+                   any.a_void = 0;         /* zero out all bits */
+                   for (i = 0; races[i].noun; i++)
+                       if (ok_race(flags.initrole, i, flags.initgend,
+                                                       flags.initalign)) {
+                           any.a_int = i+1;    /* must be non-zero */
+                           add_menu(win, NO_GLYPH, &any, races[i].noun[0],
+                               0, ATR_NONE, races[i].noun, MENU_UNSELECTED);
+                       }
+                   any.a_int = pick_race(flags.initrole, flags.initgend,
+                                       flags.initalign, PICK_RANDOM)+1;
+                   if (any.a_int == 0) /* must be non-zero */
+                       any.a_int = randrace(flags.initrole)+1;
+                   add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                   "Random", MENU_UNSELECTED);
+                   any.a_int = i+1;    /* must be non-zero */
+                   add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                   "Quit", MENU_UNSELECTED);
+                   Sprintf(pbuf, "Pick the race of your %s", plbuf);
+                   end_menu(win, pbuf);
+                   n = select_menu(win, PICK_ONE, &selected);
+                   destroy_nhwindow(win);
+                   if (n != 1 || selected[0].item.a_int == any.a_int)
+                       goto give_up;           /* Selected quit */
+
+                   k = selected[0].item.a_int - 1;
+                   free((genericptr_t) selected),      selected = 0;
+               }
+               flags.initrace = k;
+           }
+           (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+       }
+
+       /* Select a gender, if necessary */
+       /* force compatibility with role/race, try for compatibility with
+        * pre-selected alignment */
+       if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
+                                               flags.initgend)) {
+           /* pre-selected gender not valid */
+           if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) {
+               flags.initgend = pick_gend(flags.initrole, flags.initrace,
+                                               flags.initalign, PICK_RANDOM);
+               if (flags.initgend < 0) {
+                   /* tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */
+                   flags.initgend = randgend(flags.initrole, flags.initrace);
+               }
+           } else {    /* pick4u == 'n' */
+               /* Count the number of valid genders */
+               n = 0;  /* number valid */
+               k = 0;  /* valid gender */
+               for (i = 0; i < ROLE_GENDERS; i++) {
+                   if (ok_gend(flags.initrole, flags.initrace, i,
+                                                       flags.initalign)) {
+                       n++;
+                       k = i;
+                   }
+               }
+               if (n == 0) {
+                   for (i = 0; i < ROLE_GENDERS; i++) {
+                       if (validgend(flags.initrole, flags.initrace, i)) {
+                           n++;
+                           k = i;
+                       }
+                   }
+               }
+
+               /* Permit the user to pick, if there is more than one */
+               if (n > 1) {
+                   /* tty_clear_nhwindow(BASE_WINDOW); */
+                   /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */
+                   win = create_nhwindow(NHW_MENU);
+                   start_menu(win);
+                   any.a_void = 0;         /* zero out all bits */
+                   for (i = 0; i < ROLE_GENDERS; i++)
+                       if (ok_gend(flags.initrole, flags.initrace, i,
+                                                           flags.initalign)) {
+                           any.a_int = i+1;
+                           add_menu(win, NO_GLYPH, &any, genders[i].adj[0],
+                               0, ATR_NONE, genders[i].adj, MENU_UNSELECTED);
+                       }
+                   any.a_int = pick_gend(flags.initrole, flags.initrace,
+                                           flags.initalign, PICK_RANDOM)+1;
+                   if (any.a_int == 0) /* must be non-zero */
+                       any.a_int = randgend(flags.initrole, flags.initrace)+1;
+                   add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                   "Random", MENU_UNSELECTED);
+                   any.a_int = i+1;    /* must be non-zero */
+                   add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                   "Quit", MENU_UNSELECTED);
+                   Sprintf(pbuf, "Pick the gender of your %s", plbuf);
+                   end_menu(win, pbuf);
+                   n = select_menu(win, PICK_ONE, &selected);
+                   destroy_nhwindow(win);
+                   if (n != 1 || selected[0].item.a_int == any.a_int)
+                       goto give_up;           /* Selected quit */
+
+                   k = selected[0].item.a_int - 1;
+                   free((genericptr_t) selected),      selected = 0;
+               }
+               flags.initgend = k;
+           }
+           (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
+                       flags.initrole, flags.initrace, flags.initgend, flags.initalign);
+       }
+
+       /* Select an alignment, if necessary */
+       /* force compatibility with role/race/gender */
+       if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
+                                                       flags.initalign)) {
+           /* pre-selected alignment not valid */
+           if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) {
+               flags.initalign = pick_align(flags.initrole, flags.initrace,
+                                                       flags.initgend, PICK_RANDOM);
+               if (flags.initalign < 0) {
+                   /* tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */
+                   flags.initalign = randalign(flags.initrole, flags.initrace);
+               }
+           } else {    /* pick4u == 'n' */
+               /* Count the number of valid alignments */
+               n = 0;  /* number valid */
+               k = 0;  /* valid alignment */
+               for (i = 0; i < ROLE_ALIGNS; i++) {
+                   if (ok_align(flags.initrole, flags.initrace, flags.initgend,
+                                                       i)) {
+                       n++;
+                       k = i;
+                   }
+               }
+               if (n == 0) {
+                   for (i = 0; i < ROLE_ALIGNS; i++) {
+                       if (validalign(flags.initrole, flags.initrace, i)) {
+                           n++;
+                           k = i;
+                       }
+                   }
+               }
+
+               /* Permit the user to pick, if there is more than one */
+               if (n > 1) {
+                   /* tty_clear_nhwindow(BASE_WINDOW); */
+                   /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */
+                   win = create_nhwindow(NHW_MENU);
+                   start_menu(win);
+                   any.a_void = 0;         /* zero out all bits */
+                   for (i = 0; i < ROLE_ALIGNS; i++)
+                       if (ok_align(flags.initrole, flags.initrace,
+                                                       flags.initgend, i)) {
+                           any.a_int = i+1;
+                           add_menu(win, NO_GLYPH, &any, aligns[i].adj[0],
+                                0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
+                       }
+                   any.a_int = pick_align(flags.initrole, flags.initrace,
+                                           flags.initgend, PICK_RANDOM)+1;
+                   if (any.a_int == 0) /* must be non-zero */
+                       any.a_int = randalign(flags.initrole, flags.initrace)+1;
+                   add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
+                                   "Random", MENU_UNSELECTED);
+                   any.a_int = i+1;    /* must be non-zero */
+                   add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
+                                   "Quit", MENU_UNSELECTED);
+                   Sprintf(pbuf, "Pick the alignment of your %s", plbuf);
+                   end_menu(win, pbuf);
+                   n = select_menu(win, PICK_ONE, &selected);
+                   destroy_nhwindow(win);
+                   if (n != 1 || selected[0].item.a_int == any.a_int)
+                       goto give_up;           /* Selected quit */
+
+                   k = selected[0].item.a_int - 1;
+                   free((genericptr_t) selected),      selected = 0;
+               }
+               flags.initalign = k;
+           }
+       }
+       /* Success! */
+       /* tty_display_nhwindow(BASE_WINDOW, FALSE); */
+}
+
+/* Ask the user for a player name. */
+void mswin_askname(void)
+{
+       logDebug("mswin_askname()\n");
+
+       if( mswin_getlin_window("Who are you?", plname, PL_NSIZ)==IDCANCEL ) {
+               bail("bye-bye");
+               /* not reached */
+       }
+}
+
+
+/* Does window event processing (e.g. exposure events).
+   A noop for the tty and X window-ports.
+*/
+void mswin_get_nh_event(void)
+{
+       MSG msg;
+
+       logDebug("mswin_get_nh_event()\n");
+       while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)!=0 ) {
+               if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) {
+                       TranslateMessage(&msg);
+                       DispatchMessage(&msg);
+               }
+       } 
+       return;
+}
+
+/* Exits the window system.  This should dismiss all windows,
+   except the "window" used for raw_print().  str is printed if possible.
+*/
+void mswin_exit_nhwindows(const char *str)
+{
+       logDebug("mswin_exit_nhwindows(%s)\n", str);
+    /* Write Window settings to the registry */
+    mswin_write_reg();
+    while (max_brush) 
+       DeleteObject(brush_table[--max_brush]);
+}
+
+/* Prepare the window to be suspended. */
+void mswin_suspend_nhwindows(const char *str)
+{
+       logDebug("mswin_suspend_nhwindows(%s)\n", str);
+       return;
+}
+
+
+/* Restore the windows after being suspended. */
+void mswin_resume_nhwindows()
+{
+       logDebug("mswin_resume_nhwindows()\n");
+       return;
+}
+
+/*  Create a window of type "type" which can be 
+        NHW_MESSAGE     (top line)
+        NHW_STATUS      (bottom lines)
+        NHW_MAP         (main dungeon)
+        NHW_MENU        (inventory or other "corner" windows)
+        NHW_TEXT        (help/text, full screen paged window)
+*/
+winid 
+mswin_create_nhwindow(int type)
+{
+       winid i = 0;
+       MSNHMsgAddWnd data;
+
+       logDebug("mswin_create_nhwindow(%d)\n", type);
+
+       /* Return the next available winid
+        */
+
+       for (i=1; i<MAXWINDOWS; i++)
+         if (GetNHApp()->windowlist[i].win == NULL &&
+                 !GetNHApp()->windowlist[i].dead)
+                 break;
+       if (i == MAXWINDOWS)
+         panic ("ERROR:  No windows available...\n");
+
+    switch (type) {
+    case NHW_MAP:
+       {
+               GetNHApp()->windowlist[i].win = mswin_init_map_window();
+               GetNHApp()->windowlist[i].type = type;
+               GetNHApp()->windowlist[i].dead = 0;
+               break;
+       }
+    case NHW_MESSAGE:
+       {
+               GetNHApp()->windowlist[i].win = mswin_init_message_window();
+               GetNHApp()->windowlist[i].type = type;
+               GetNHApp()->windowlist[i].dead = 0;
+               break;
+       }
+    case NHW_STATUS:
+       {
+               GetNHApp()->windowlist[i].win = mswin_init_status_window();
+               GetNHApp()->windowlist[i].type = type;
+               GetNHApp()->windowlist[i].dead = 0;
+               break;
+       }    
+    case NHW_MENU:
+       {
+               GetNHApp()->windowlist[i].win = NULL; //will create later
+               GetNHApp()->windowlist[i].type = type;
+               GetNHApp()->windowlist[i].dead = 1;
+               break;
+       } 
+    case NHW_TEXT:
+       {
+               GetNHApp()->windowlist[i].win = mswin_init_text_window();
+               GetNHApp()->windowlist[i].type = type;
+               GetNHApp()->windowlist[i].dead = 0;
+               break;
+       }
+       }
+
+       ZeroMemory(&data, sizeof(data) );
+       data.wid = i;
+       SendMessage( GetNHApp()->hMainWnd, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ADDWND, (LPARAM)&data );
+       return i;
+}
+
+/* Clear the given window, when asked to. */
+void mswin_clear_nhwindow(winid wid)
+{
+       logDebug("mswin_clear_nhwindow(%d)\n", wid);
+
+    if ((wid >= 0) && 
+        (wid < MAXWINDOWS) &&
+        (GetNHApp()->windowlist[wid].win != NULL))
+    {
+#ifdef REINCARNATION
+               if( GetNHApp()->windowlist[wid].type == NHW_MAP ) {
+                       if( Is_rogue_level(&u.uz) ) 
+                               mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), ROGUE_LEVEL_MAP_MODE);
+                       else 
+                               mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), iflags.wc_map_mode);
+               }
+#endif
+
+               SendMessage( 
+                        GetNHApp()->windowlist[wid].win, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CLEAR_WINDOW, (LPARAM)NULL );
+       }
+}
+
+/* -- Display the window on the screen.  If there is data
+                   pending for output in that window, it should be sent.
+                   If blocking is TRUE, display_nhwindow() will not
+                   return until the data has been displayed on the screen,
+                   and acknowledged by the user where appropriate.
+                -- All calls are blocking in the tty window-port.
+                -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
+                   --more--, if necessary, in the tty window-port.
+*/
+void mswin_display_nhwindow(winid wid, BOOLEAN_P block)
+{
+       logDebug("mswin_display_nhwindow(%d, %d)\n", wid, block);
+       if (GetNHApp()->windowlist[wid].win != NULL)
+       {
+               if (GetNHApp()->windowlist[wid].type == NHW_MENU) {
+                       MENU_ITEM_P* p;
+                       mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, PICK_NONE, &p);
+               } if (GetNHApp()->windowlist[wid].type == NHW_TEXT) {
+                       mswin_display_text_window(GetNHApp()->windowlist[wid].win);
+               } if (GetNHApp()->windowlist[wid].type == NHW_RIP) {
+                       mswin_display_RIP_window(GetNHApp()->windowlist[wid].win);
+               } else {
+                       if( !block ) {
+                               UpdateWindow(GetNHApp()->windowlist[wid].win);
+                       } else {
+                               if ( GetNHApp()->windowlist[wid].type == NHW_MAP ) {
+                                       (void) mswin_nhgetch();
+                               }
+                       }
+               }
+               SetFocus(GetNHApp()->hMainWnd);
+       }
+}
+
+
+HWND mswin_hwnd_from_winid(winid wid)
+{
+       if( wid>=0 && wid<MAXWINDOWS) {
+               return GetNHApp()->windowlist[wid].win;
+       } else {
+               return NULL;
+       }
+}
+
+winid mswin_winid_from_handle(HWND hWnd)
+{
+       winid i = 0;
+
+       for (i=1; i<MAXWINDOWS; i++)
+         if (GetNHApp()->windowlist[i].win == hWnd)
+                 return i;
+       return -1;
+}
+
+winid mswin_winid_from_type(int type)
+{
+       winid i = 0;
+
+       for (i=1; i<MAXWINDOWS; i++)
+         if (GetNHApp()->windowlist[i].type == type)
+                 return i;
+       return -1;
+}
+
+void mswin_window_mark_dead(winid wid)
+{
+       if( wid>=0 && wid<MAXWINDOWS) {
+               GetNHApp()->windowlist[wid].win = NULL;
+               GetNHApp()->windowlist[wid].dead = 1;
+       }
+}
+
+/* Destroy will dismiss the window if the window has not 
+ * already been dismissed.
+*/
+void mswin_destroy_nhwindow(winid wid)
+{
+       logDebug("mswin_destroy_nhwindow(%d)\n", wid);
+
+    if ((GetNHApp()->windowlist[wid].type == NHW_MAP) || 
+        (GetNHApp()->windowlist[wid].type == NHW_MESSAGE) || 
+        (GetNHApp()->windowlist[wid].type == NHW_STATUS)) {
+               /* main windows is going to take care of those */
+               return;
+    }
+
+    if (wid != -1) {
+               if( !GetNHApp()->windowlist[wid].dead &&
+                       GetNHApp()->windowlist[wid].win != NULL ) 
+                       DestroyWindow(GetNHApp()->windowlist[wid].win);
+               GetNHApp()->windowlist[wid].win = NULL;
+               GetNHApp()->windowlist[wid].type = 0;
+               GetNHApp()->windowlist[wid].dead = 0;
+       }
+}
+
+/* Next output to window will start at (x,y), also moves
+ displayable cursor to (x,y).  For backward compatibility,
+ 1 <= x < cols, 0 <= y < rows, where cols and rows are
+ the size of window.
+*/
+void mswin_curs(winid wid, int x, int y)
+{
+       logDebug("mswin_curs(%d, %d, %d)\n", wid, x, y);
+
+    if ((wid >= 0) && 
+        (wid < MAXWINDOWS) &&
+        (GetNHApp()->windowlist[wid].win != NULL))
+    {
+                MSNHMsgCursor data;
+                data.x = x;
+                data.y = y;
+                SendMessage( 
+                        GetNHApp()->windowlist[wid].win, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CURSOR, (LPARAM)&data );
+    }
+}
+
+/*
+putstr(window, attr, str)
+                -- Print str on the window with the given attribute.  Only
+                   printable ASCII characters (040-0126) must be supported.
+                   Multiple putstr()s are output on separate lines.
+Attributes
+                   can be one of
+                        ATR_NONE (or 0)
+                        ATR_ULINE
+                        ATR_BOLD
+                        ATR_BLINK
+                        ATR_INVERSE
+                   If a window-port does not support all of these, it may map
+                   unsupported attributes to a supported one (e.g. map them
+                   all to ATR_INVERSE).  putstr() may compress spaces out of
+                   str, break str, or truncate str, if necessary for the
+                   display.  Where putstr() breaks a line, it has to clear
+                   to end-of-line.
+                -- putstr should be implemented such that if two putstr()s
+                   are done consecutively the user will see the first and
+                   then the second.  In the tty port, pline() achieves this
+                   by calling more() or displaying both on the same line.
+*/
+void mswin_putstr(winid wid, int attr, const char *text)
+{
+       logDebug("mswin_putstr(%d, %d, %s)\n", wid, attr, text);
+       
+       mswin_putstr_ex(wid, attr, text, 0);
+}
+
+void mswin_putstr_ex(winid wid, int attr, const char *text, int app)
+{
+       if( (wid >= 0) && 
+        (wid < MAXWINDOWS) )
+       {
+               if( GetNHApp()->windowlist[wid].win==NULL &&
+                       GetNHApp()->windowlist[wid].type==NHW_MENU ) {
+                       GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_TEXT);
+                       GetNHApp()->windowlist[wid].dead = 0;
+               }
+
+               if (GetNHApp()->windowlist[wid].win != NULL)
+               {
+                        MSNHMsgPutstr data;
+                        ZeroMemory(&data, sizeof(data));
+                        data.attr = attr;
+                        data.text = text;
+                        data.append = app;
+                        SendMessage( 
+                                GetNHApp()->windowlist[wid].win, 
+                                WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_PUTSTR, (LPARAM)&data );
+               }
+        /* yield a bit so it gets done immediately */
+        mswin_get_nh_event();
+       }
+       else
+       {
+               // build text to display later in message box
+               GetNHApp()->saved_text = realloc(GetNHApp()->saved_text, strlen(text) +
+                       strlen(GetNHApp()->saved_text) + 1);
+               strcat(GetNHApp()->saved_text, text);
+       }
+}
+
+/* Display the file named str.  Complain about missing files
+                   iff complain is TRUE.
+*/
+void mswin_display_file(const char *filename,BOOLEAN_P must_exist)
+{
+       dlb *f;
+       TCHAR wbuf[BUFSZ];
+
+       logDebug("mswin_display_file(%s, %d)\n", filename, must_exist);
+
+       f = dlb_fopen(filename, RDTMODE);
+       if (!f) {
+               if (must_exist) {
+                       TCHAR message[90];
+                       _stprintf(message, TEXT("Warning! Could not find file: %s\n"), NH_A2W(filename, wbuf, sizeof(wbuf)));
+                       NHMessageBox(GetNHApp()->hMainWnd, message, MB_OK | MB_ICONEXCLAMATION );
+               } 
+       } else {
+               winid text;
+               char line[LLEN];
+
+               text = mswin_create_nhwindow(NHW_TEXT);
+
+               while (dlb_fgets(line, LLEN, f)) {
+                        size_t len;
+                        len = strlen(line);
+                        if( line[len-1]=='\n' ) line[len-1]='\x0';
+                               mswin_putstr(text, ATR_NONE, line);
+               }
+               (void) dlb_fclose(f);
+
+               mswin_display_nhwindow(text, 1);
+               mswin_destroy_nhwindow(text);
+       }
+}
+
+/* Start using window as a menu.  You must call start_menu()
+   before add_menu().  After calling start_menu() you may not
+   putstr() to the window.  Only windows of type NHW_MENU may
+   be used for menus.
+*/
+void mswin_start_menu(winid wid)
+{
+       logDebug("mswin_start_menu(%d)\n", wid);
+       if( (wid >= 0) && 
+        (wid < MAXWINDOWS) ) {
+               if( GetNHApp()->windowlist[wid].win==NULL &&
+                       GetNHApp()->windowlist[wid].type==NHW_MENU ) {
+                       GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_MENU);
+                       GetNHApp()->windowlist[wid].dead = 0;
+               }
+
+               if(GetNHApp()->windowlist[wid].win != NULL)     {
+                       SendMessage( 
+                                GetNHApp()->windowlist[wid].win, 
+                                WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_STARTMENU, (LPARAM)NULL
+                       );
+               }
+       }
+}
+
+/*
+add_menu(windid window, int glyph, const anything identifier,
+                                char accelerator, char groupacc,
+                                int attr, char *str, boolean preselected)
+                -- Add a text line str to the given menu window.  If identifier
+                   is 0, then the line cannot be selected (e.g. a title).
+                   Otherwise, identifier is the value returned if the line is
+                   selected.  Accelerator is a keyboard key that can be used
+                   to select the line.  If the accelerator of a selectable
+                   item is 0, the window system is free to select its own
+                   accelerator.  It is up to the window-port to make the
+                   accelerator visible to the user (e.g. put "a - " in front
+                   of str).  The value attr is the same as in putstr().
+                   Glyph is an optional glyph to accompany the line.  If
+                   window port cannot or does not want to display it, this
+                   is OK.  If there is no glyph applicable, then this
+                   value will be NO_GLYPH.
+                -- All accelerators should be in the range [A-Za-z].
+                -- It is expected that callers do not mix accelerator
+                   choices.  Either all selectable items have an accelerator
+                   or let the window system pick them.  Don't do both.
+                -- Groupacc is a group accelerator.  It may be any character
+                   outside of the standard accelerator (see above) or a
+                   number.  If 0, the item is unaffected by any group
+                   accelerator.  If this accelerator conflicts with
+                   the menu command (or their user defined alises), it loses.
+                   The menu commands and aliases take care not to interfere
+                   with the default object class symbols.
+                -- If you want this choice to be preselected when the
+                   menu is displayed, set preselected to TRUE.
+*/
+void mswin_add_menu(winid wid, int glyph, const ANY_P * identifier,
+               CHAR_P accelerator, CHAR_P group_accel, int attr, 
+               const char *str, BOOLEAN_P presel)
+{
+       logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n",
+                    wid, glyph, identifier, (char)accelerator, (char)group_accel,
+                        attr, str, presel);
+       if ((wid >= 0) && 
+               (wid < MAXWINDOWS) &&
+               (GetNHApp()->windowlist[wid].win != NULL))
+       {
+               MSNHMsgAddMenu data;
+               ZeroMemory(&data, sizeof(data));
+               data.glyph = glyph;
+               data.identifier = identifier;
+               data.accelerator = accelerator;
+               data.group_accel = group_accel;
+               data.attr = attr;
+               data.str = str;
+               data.presel = presel;
+
+               SendMessage( 
+                        GetNHApp()->windowlist[wid].win, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ADDMENU, (LPARAM)&data
+               );
+       }
+}
+
+/*
+end_menu(window, prompt)
+                -- Stop adding entries to the menu and flushes the window
+                   to the screen (brings to front?).  Prompt is a prompt
+                   to give the user.  If prompt is NULL, no prompt will
+                   be printed.
+                ** This probably shouldn't flush the window any more (if
+                ** it ever did).  That should be select_menu's job.  -dean
+*/
+void mswin_end_menu(winid wid, const char *prompt)
+{
+       logDebug("mswin_end_menu(%d, %s)\n", wid, prompt);
+       if ((wid >= 0) && 
+               (wid < MAXWINDOWS) &&
+               (GetNHApp()->windowlist[wid].win != NULL))
+       {
+               MSNHMsgEndMenu data;
+               ZeroMemory(&data, sizeof(data));
+               data.text = prompt;
+
+               SendMessage( 
+                        GetNHApp()->windowlist[wid].win, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ENDMENU, (LPARAM)&data
+               );
+       }
+}
+
+/*
+int select_menu(windid window, int how, menu_item **selected)
+                -- Return the number of items selected; 0 if none were chosen,
+                   -1 when explicitly cancelled.  If items were selected, then
+                   selected is filled in with an allocated array of menu_item
+                   structures, one for each selected line.  The caller must
+                   free this array when done with it.  The "count" field
+                   of selected is a user supplied count.  If the user did
+                   not supply a count, then the count field is filled with
+                   -1 (meaning all).  A count of zero is equivalent to not
+                   being selected and should not be in the list.  If no items
+                   were selected, then selected is NULL'ed out.  How is the
+                   mode of the menu.  Three valid values are PICK_NONE,
+                   PICK_ONE, and PICK_N, meaning: nothing is selectable,
+                   only one thing is selectable, and any number valid items
+                   may selected.  If how is PICK_NONE, this function should
+                   never return anything but 0 or -1.
+                -- You may call select_menu() on a window multiple times --
+                   the menu is saved until start_menu() or destroy_nhwindow()
+                   is called on the window.
+                -- Note that NHW_MENU windows need not have select_menu()
+                   called for them. There is no way of knowing whether
+                   select_menu() will be called for the window at
+                   create_nhwindow() time.
+*/
+int mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected)
+{
+       int nReturned = -1;
+
+       logDebug("mswin_select_menu(%d, %d)\n", wid, how);
+
+       if ((wid >= 0) && 
+               (wid < MAXWINDOWS) &&
+               (GetNHApp()->windowlist[wid].win != NULL))
+       {
+               nReturned = mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, how, selected);
+       }
+    return nReturned;
+}
+
+/*
+    -- Indicate to the window port that the inventory has been changed.
+    -- Merely calls display_inventory() for window-ports that leave the 
+       window up, otherwise empty.
+*/
+void mswin_update_inventory()
+{
+       logDebug("mswin_update_inventory()\n");
+}
+
+/*
+mark_synch()    -- Don't go beyond this point in I/O on any channel until
+                   all channels are caught up to here.  Can be an empty call
+                   for the moment
+*/
+void mswin_mark_synch()
+{
+       logDebug("mswin_mark_synch()\n");
+}
+
+/*
+wait_synch()    -- Wait until all pending output is complete (*flush*() for
+                   streams goes here).
+                -- May also deal with exposure events etc. so that the
+                   display is OK when return from wait_synch().
+*/
+void mswin_wait_synch()
+{
+       logDebug("mswin_wait_synch()\n");
+}
+
+/*
+cliparound(x, y)-- Make sure that the user is more-or-less centered on the
+                   screen if the playing area is larger than the screen.
+                -- This function is only defined if CLIPPING is defined.
+*/
+void mswin_cliparound(int x, int y)
+{
+       winid wid = WIN_MAP;
+
+       logDebug("mswin_cliparound(%d, %d)\n", x, y);
+
+    if ((wid >= 0) && 
+        (wid < MAXWINDOWS) &&
+        (GetNHApp()->windowlist[wid].win != NULL))
+    {
+                MSNHMsgClipAround data;
+                data.x = x;
+                data.y = y;
+         SendMessage( 
+                        GetNHApp()->windowlist[wid].win, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CLIPAROUND, (LPARAM)&data );
+    }
+}
+
+/*
+print_glyph(window, x, y, glyph)
+                -- Print the glyph at (x,y) on the given window.  Glyphs are
+                   integers at the interface, mapped to whatever the window-
+                   port wants (symbol, font, color, attributes, ...there's
+                   a 1-1 map between glyphs and distinct things on the map).
+*/
+void mswin_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph)
+{
+    logDebug("mswin_print_glyph(%d, %d, %d, %d)\n", wid, x, y, glyph);
+
+    if ((wid >= 0) && 
+        (wid < MAXWINDOWS) &&
+        (GetNHApp()->windowlist[wid].win != NULL))
+    {
+               MSNHMsgPrintGlyph data;
+
+               ZeroMemory(&data, sizeof(data) );
+               data.x = x;
+               data.y = y;
+               data.glyph = glyph;
+               SendMessage( GetNHApp()->windowlist[wid].win, 
+                        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_PRINT_GLYPH, (LPARAM)&data );
+       }
+}
+
+/*
+raw_print(str)  -- Print directly to a screen, or otherwise guarantee that
+                   the user sees str.  raw_print() appends a newline to str.
+                   It need not recognize ASCII control characters.  This is
+                   used during startup (before windowing system initialization
+                   -- maybe this means only error startup messages are raw),
+                   for error messages, and maybe other "msg" uses.  E.g.
+                   updating status for micros (i.e, "saving").
+*/
+void mswin_raw_print(const char *str)
+{
+       TCHAR wbuf[255];
+    logDebug("mswin_raw_print(%s)\n", str);
+       if( str && *str )
+               NHMessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), 
+                   MB_ICONINFORMATION | MB_OK );
+}
+
+/*
+raw_print_bold(str)
+                -- Like raw_print(), but prints in bold/standout (if
+possible).
+*/
+void mswin_raw_print_bold(const char *str)
+{
+       TCHAR wbuf[255];
+    logDebug("mswin_raw_print_bold(%s)\n", str);
+       if( str && *str )
+               NHMessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), 
+                   MB_ICONINFORMATION | MB_OK );
+}
+
+/*
+int nhgetch()   -- Returns a single character input from the user.
+                -- In the tty window-port, nhgetch() assumes that tgetch()
+                   will be the routine the OS provides to read a character.
+                   Returned character _must_ be non-zero.
+*/
+int mswin_nhgetch()
+{
+       PMSNHEvent event;
+    int key = 0;
+
+       logDebug("mswin_nhgetch()\n");
+       
+
+       while( (event = mswin_input_pop()) == NULL ||
+                  event->type != NHEVENT_CHAR ) 
+               mswin_main_loop();
+
+       key = event->kbd.ch;
+    return (key);
+}
+
+/*
+int nh_poskey(int *x, int *y, int *mod)
+                -- Returns a single character input from the user or a
+                   a positioning event (perhaps from a mouse).  If the
+                   return value is non-zero, a character was typed, else,
+                   a position in the MAP window is returned in x, y and mod.
+                   mod may be one of
+
+                        CLICK_1         -- mouse click type 1 
+                        CLICK_2         -- mouse click type 2 
+
+                   The different click types can map to whatever the
+                   hardware supports.  If no mouse is supported, this
+                   routine always returns a non-zero character.
+*/
+int mswin_nh_poskey(int *x, int *y, int *mod)
+{
+       PMSNHEvent event;
+       int key;
+
+       logDebug("mswin_nh_poskey()\n");
+
+       while( (event = mswin_input_pop())==NULL ) mswin_main_loop();
+
+       if( event->type==NHEVENT_MOUSE ) {
+               *mod = event->ms.mod;
+               *x = event->ms.x;
+               *y = event->ms.y;
+               key = 0;
+       } else {
+               key = event->kbd.ch;
+       }
+       return (key);
+}
+
+/*
+nhbell()        -- Beep at user.  [This will exist at least until sounds are
+                   redone, since sounds aren't attributable to windows anyway.]
+*/
+void mswin_nhbell()
+{
+       logDebug("mswin_nhbell()\n");
+}
+
+/*
+doprev_message()
+                -- Display previous messages.  Used by the ^P command.
+                -- On the tty-port this scrolls WIN_MESSAGE back one line.
+*/
+int mswin_doprev_message()
+{
+    logDebug("mswin_doprev_message()\n");
+       SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL); 
+    return 0;
+}
+
+/*
+char yn_function(const char *ques, const char *choices, char default)
+                -- Print a prompt made up of ques, choices and default.
+                   Read a single character response that is contained in
+                   choices or default.  If choices is NULL, all possible
+                   inputs are accepted and returned.  This overrides
+                   everything else.  The choices are expected to be in
+                   lower case.  Entering ESC always maps to 'q', or 'n',
+                   in that order, if present in choices, otherwise it maps
+                   to default.  Entering any other quit character (SPACE,
+                   RETURN, NEWLINE) maps to default.
+                -- If the choices string contains ESC, then anything after
+                   it is an acceptable response, but the ESC and whatever
+                   follows is not included in the prompt.
+                -- If the choices string contains a '#' then accept a count.
+                   Place this value in the global "yn_number" and return '#'.
+                -- This uses the top line in the tty window-port, other
+                   ports might use a popup.
+*/
+char mswin_yn_function(const char *question, const char *choices,
+               CHAR_P def)
+{
+    char ch;
+    char yn_esc_map='\033';
+    char message[BUFSZ];
+       char res_ch[2];
+    int createcaret;
+       boolean digit_ok, allow_num;
+
+       logDebug("mswin_yn_function(%s, %s, %d)\n", question, choices, def);
+
+    if (WIN_MESSAGE == WIN_ERR && choices == ynchars) {
+        char *text = realloc(strdup(GetNHApp()->saved_text), strlen(question)
+                       + strlen(GetNHApp()->saved_text) + 1);
+        DWORD box_result;
+        strcat(text, question);
+        box_result = NHMessageBox(NULL,
+             NH_W2A(text, message, sizeof(message)),
+             MB_YESNOCANCEL | MB_ICONQUESTION | 
+             ((def == 'y') ? MB_DEFBUTTON1 :
+              (def == 'n') ? MB_DEFBUTTON2 : MB_DEFBUTTON3));
+        free(text);
+               GetNHApp()->saved_text = strdup("");
+        return box_result == IDYES ? 'y' : box_result == IDNO ? 'n' : '\033';
+    }
+
+    if (choices) {
+               char *cb, choicebuf[QBUFSZ];
+
+               allow_num = (index(choices, '#') != 0);
+
+               Strcpy(choicebuf, choices);
+               if ((cb = index(choicebuf, '\033')) != 0) {
+                       /* anything beyond <esc> is hidden */
+                       *cb = '\0';
+               }
+               sprintf(message, "%s [%s] ", question, choicebuf);
+               if (def) sprintf(eos(message), "(%c) ", def);
+               /* escape maps to 'q' or 'n' or default, in that order */
+               yn_esc_map = (index(choices, 'q') ? 'q' :
+                       (index(choices, 'n') ? 'n' : def));
+    } else {
+               Strcpy(message, question);
+               Strcat(message, " ");
+    }
+
+    createcaret = 1;
+    SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), 
+        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret );
+
+    mswin_clear_nhwindow(WIN_MESSAGE);
+    mswin_putstr(WIN_MESSAGE, ATR_BOLD, message);
+
+    /* Only here if main window is not present */
+       ch = 0;
+    do {
+               ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
+               ch=mswin_nhgetch();
+               HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
+               if (choices) ch = lowc(ch);
+               else break; /* If choices is NULL, all possible inputs are accepted and returned. */
+
+               digit_ok = allow_num && digit(ch);
+               if (ch=='\033') {
+                       if (index(choices, 'q'))
+                               ch = 'q';
+                       else if (index(choices, 'n'))
+                               ch = 'n';
+                       else
+                               ch = def;
+                       break;
+           } else if (index(quitchars, ch)) {
+                       ch = def;
+                       break;
+               } else if (!index(choices, ch) && !digit_ok) {
+                       mswin_nhbell();
+                       ch = (char)0;
+                       /* and try again... */
+               } else if (ch == '#' || digit_ok) {
+                       char z, digit_string[2];
+                       int n_len = 0;
+                       long value = 0;
+                       mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, ("#"), 1); n_len++;
+                       digit_string[1] = '\0';
+                       if (ch != '#') {
+                               digit_string[0] = ch;
+                               mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1); n_len++;
+                               value = ch - '0';
+                               ch = '#';
+                       }
+                       do {    /* loop until we get a non-digit */
+                               z = lowc(readchar());
+                               if (digit(z)) {
+                                       value = (10 * value) + (z - '0');
+                                       if (value < 0) break;   /* overflow: try again */
+                                       digit_string[0] = z;
+                                       mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1);
+                                       n_len++;
+                               } else if (z == 'y' || index(quitchars, z)) {
+                                       if (z == '\033')  value = -1;   /* abort */
+                                       z = '\n';       /* break */
+                               } else if (z == '\b') {
+                                       if (n_len <= 1) { value = -1;  break; }
+                                       else { value /= 10;  mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, -1);  n_len--; }
+                               } else {
+                                       value = -1;     /* abort */
+                                       mswin_nhbell();
+                                       break;
+                               }
+                       } while (z != '\n');
+                       if (value > 0) yn_number = value;
+                       else if (value == 0) ch = 'n';          /* 0 => "no" */
+                       else {  /* remove number from top line, then try again */
+                               mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, -n_len); n_len = 0;
+                               ch = (char)0;
+                       }
+               }
+       } while( !ch );
+
+    createcaret = 0;
+    SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), 
+        WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret );
+
+       /* display selection in the message window */
+       if( isprint(ch) && ch!='#' ) {
+               res_ch[0] = ch;
+               res_ch[1] = '\x0';
+               mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1);
+       }
+
+    return ch;
+}
+
+/*
+getlin(const char *ques, char *input)
+           -- Prints ques as a prompt and reads a single line of text,
+              up to a newline.  The string entered is returned without the
+              newline.  ESC is used to cancel, in which case the string
+              "\033\000" is returned.
+           -- getlin() must call flush_screen(1) before doing anything.
+           -- This uses the top line in the tty window-port, other
+              ports might use a popup.
+*/
+void mswin_getlin(const char *question, char *input)
+{
+
+       logDebug("mswin_getlin(%s, %p)\n", question, input);
+
+    if (!iflags.wc_popup_dialog)
+    {
+        char c;
+        int len;
+        int done;
+        int createcaret;
+
+        createcaret = 1;
+        SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), 
+            WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret );
+
+ mswin_clear_nhwindow(WIN_MESSAGE);
+        mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, question, 0);
+        mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, " ", 1);
+        input[0] = '\0';
+        len = 0;
+        ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
+        done = FALSE;
+        while (!done)
+        {
+            c = mswin_nhgetch();
+            switch (c)
+            {
+                case VK_ESCAPE:
+                    strcpy(input, "\033");
+                    done = TRUE;
+                    break;
+                case '\n':
+                case '\r':
+                case -115:
+                    done = TRUE;
+                    break;
+                default:
+                    if (input[0])
+                        mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, -len);
+                    if (c == VK_BACK) {
+                        if (len > 0) len--;
+                        input[len] = '\0';
+                    } else {
+
+                        input[len++] = c;
+                        input[len] = '\0';
+                    }
+                    mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, 1);
+                    break;
+            }
+        }
+        HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
+        createcaret = 0;
+        SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), 
+            WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret );
+    }
+    else
+    {
+           if( mswin_getlin_window(question, input, BUFSZ)==IDCANCEL ) {
+                   strcpy(input, "\033");
+           }
+    }
+}
+
+/*
+int get_ext_cmd(void)
+           -- Get an extended command in a window-port specific way.
+              An index into extcmdlist[] is returned on a successful
+              selection, -1 otherwise.
+*/
+int mswin_get_ext_cmd()
+{
+       int ret;
+       logDebug("mswin_get_ext_cmd()\n");
+
+    if (!iflags.wc_popup_dialog)
+    {
+        char c;
+        char cmd[BUFSZ];
+        int i, len;
+        int createcaret;
+
+        createcaret = 1;
+        SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), 
+            WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret );
+
+        cmd[0] = '\0';
+        i = -2;
+ mswin_clear_nhwindow(WIN_MESSAGE);
+        mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, "#", 0);
+        len = 0;
+        ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
+        while (i == -2)
+        {
+            int oindex, com_index;
+            c = mswin_nhgetch();
+            switch (c)
+            {
+                case VK_ESCAPE:
+                    i = -1;
+                    break;
+                case '\n':
+                case '\r':
+                case -115:
+                    for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++)
+                        if (!strcmpi(cmd, extcmdlist[i].ef_txt)) break;
+
+                    if (extcmdlist[i].ef_txt == (char *)0) {
+                        pline("%s: unknown extended command.", cmd);
+                        i = -1;
+                    }
+                    break;
+                default:
+                    if (cmd[0])
+                        mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd, -(int)strlen(cmd));
+                    if (c == VK_BACK)
+                    {
+                        if (len > 0) len--;
+                        cmd[len] = '\0';
+                    }
+                    else
+                    {
+
+                        cmd[len++] = c;
+                        cmd[len] = '\0';
+                        /* Find a command with this prefix in extcmdlist */
+                           com_index = -1;
+                           for (oindex = 0; extcmdlist[oindex].ef_txt != (char *)0; oindex++) {
+                                   if (!strncmpi(cmd, extcmdlist[oindex].ef_txt, len)) {
+                                           if (com_index == -1)        /* no matches yet */
+                                               com_index = oindex;
+                                else
+                                    com_index = -2;     /* two matches, don't complete */
+                                   }
+                           }
+                           if (com_index >= 0) {
+                                   Strcpy(cmd, extcmdlist[com_index].ef_txt);
+                           }
+                    }
+                    mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd, 1);
+                    break;
+            }
+        }
+        HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
+        createcaret = 0;
+        SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), 
+            WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret );
+           return i;
+    }
+    else
+    {
+       if(mswin_ext_cmd_window (&ret) == IDCANCEL)
+               return -1;
+           else 
+                   return ret;
+    }
+}
+
+
+/*
+number_pad(state)
+           -- Initialize the number pad to the given state.
+*/
+void mswin_number_pad(int state)
+{
+    /* Do Nothing */
+       logDebug("mswin_number_pad(%d)\n", state);
+}
+
+/*
+delay_output()  -- Causes a visible delay of 50ms in the output.
+              Conceptually, this is similar to wait_synch() followed
+              by a nap(50ms), but allows asynchronous operation.
+*/
+void mswin_delay_output()
+{
+       logDebug("mswin_delay_output()\n");
+       Sleep(50);
+}
+
+void mswin_change_color() 
+{ 
+       logDebug("mswin_change_color()\n"); 
+}
+
+char *mswin_get_color_string() 
+{ 
+       logDebug("mswin_get_color_string()\n");
+       return( "" ); 
+}
+
+/*
+start_screen()  -- Only used on Unix tty ports, but must be declared for
+              completeness.  Sets up the tty to work in full-screen
+              graphics mode.  Look at win/tty/termcap.c for an
+              example.  If your window-port does not need this function
+              just declare an empty function.
+*/
+void mswin_start_screen()
+{
+    /* Do Nothing */
+       logDebug("mswin_start_screen()\n");
+}
+
+/*
+end_screen()    -- Only used on Unix tty ports, but must be declared for
+              completeness.  The complement of start_screen().
+*/
+void mswin_end_screen()
+{
+    /* Do Nothing */
+       logDebug("mswin_end_screen()\n");
+}
+
+/*
+outrip(winid, int)
+           -- The tombstone code.  If you want the traditional code use
+              genl_outrip for the value and check the #if in rip.c.
+*/
+#define STONE_LINE_LEN 16
+void mswin_outrip(winid wid, int how)
+{
+       char buf[BUFSZ];
+
+       logDebug("mswin_outrip(%d)\n", wid, how);
+    if ((wid >= 0) && (wid < MAXWINDOWS) ) {
+               DestroyWindow(GetNHApp()->windowlist[wid].win);
+               GetNHApp()->windowlist[wid].win = mswin_init_RIP_window();
+               GetNHApp()->windowlist[wid].type = NHW_RIP;
+               GetNHApp()->windowlist[wid].dead = 0;
+       }
+
+       /* Put name on stone */
+       Sprintf(buf, "%s", plname);
+       buf[STONE_LINE_LEN] = 0;
+       putstr(wid, 0, buf);
+
+       /* Put $ on stone */
+#ifndef GOLDOBJ
+       Sprintf(buf, "%ld Au", u.ugold);
+#else
+       Sprintf(buf, "%ld Au", done_money);
+#endif
+       buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */
+       putstr(wid, 0, buf);
+
+       /* Put together death description */
+       switch (killer_format) {
+               default: impossible("bad killer format?");
+               case KILLED_BY_AN:
+                       Strcpy(buf, killed_by_prefix[how]);
+                       Strcat(buf, an(killer));
+                       break;
+               case KILLED_BY:
+                       Strcpy(buf, killed_by_prefix[how]);
+                       Strcat(buf, killer);
+                       break;
+               case NO_KILLER_PREFIX:
+                       Strcpy(buf, killer);
+                       break;
+       }
+
+       /* Put death type on stone */
+       putstr(wid, 0, buf);
+
+       /* Put year on stone */
+       Sprintf(buf, "%4d", getyear());
+       putstr(wid, 0, buf);
+       mswin_finish_rip_text(wid);
+}
+
+/* handle options updates here */
+void mswin_preference_update(const char *pref)
+{
+       HDC hdc;
+
+       if( stricmp( pref, "font_menu")==0 ||
+               stricmp( pref, "font_size_menu")==0 ) {
+               if( iflags.wc_fontsiz_menu<NHFONT_SIZE_MIN || 
+                       iflags.wc_fontsiz_menu>NHFONT_SIZE_MAX )
+                       iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
+
+               hdc = GetDC(GetNHApp()->hMainWnd);
+               mswin_get_font(NHW_MENU, ATR_NONE, hdc, TRUE);
+               mswin_get_font(NHW_MENU, ATR_BOLD, hdc, TRUE);
+               mswin_get_font(NHW_MENU, ATR_DIM, hdc, TRUE);
+               mswin_get_font(NHW_MENU, ATR_ULINE, hdc, TRUE);
+               mswin_get_font(NHW_MENU, ATR_BLINK, hdc, TRUE);
+               mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, TRUE);
+               ReleaseDC(GetNHApp()->hMainWnd, hdc);
+
+               mswin_layout_main_window(NULL);
+               return;
+       }
+
+       if( stricmp( pref, "font_status")==0 ||
+               stricmp( pref, "font_size_status")==0 ) {
+
+               if( iflags.wc_fontsiz_status<NHFONT_SIZE_MIN || 
+                       iflags.wc_fontsiz_status>NHFONT_SIZE_MAX )
+                       iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
+
+               hdc = GetDC(GetNHApp()->hMainWnd);
+               mswin_get_font(NHW_STATUS, ATR_NONE, hdc, TRUE);
+               mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, TRUE);
+               mswin_get_font(NHW_STATUS, ATR_DIM, hdc, TRUE);
+               mswin_get_font(NHW_STATUS, ATR_ULINE, hdc, TRUE);
+               mswin_get_font(NHW_STATUS, ATR_BLINK, hdc, TRUE);
+               mswin_get_font(NHW_STATUS, ATR_INVERSE, hdc, TRUE);
+               ReleaseDC(GetNHApp()->hMainWnd, hdc);
+
+               InvalidateRect(mswin_hwnd_from_winid(WIN_STATUS), NULL, TRUE);
+               mswin_layout_main_window(NULL);
+               return;
+       }
+
+       if( stricmp( pref, "font_message")==0 ||
+               stricmp( pref, "font_size_message")==0 ) {
+
+               if( iflags.wc_fontsiz_message<NHFONT_SIZE_MIN || 
+                       iflags.wc_fontsiz_message>NHFONT_SIZE_MAX )
+                       iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
+
+               hdc = GetDC(GetNHApp()->hMainWnd);
+               mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, TRUE);
+               mswin_get_font(NHW_MESSAGE, ATR_BOLD, hdc, TRUE);
+               mswin_get_font(NHW_MESSAGE, ATR_DIM, hdc, TRUE);
+               mswin_get_font(NHW_MESSAGE, ATR_ULINE, hdc, TRUE);
+               mswin_get_font(NHW_MESSAGE, ATR_BLINK, hdc, TRUE);
+               mswin_get_font(NHW_MESSAGE, ATR_INVERSE, hdc, TRUE);
+               ReleaseDC(GetNHApp()->hMainWnd, hdc);
+
+               InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE);
+               mswin_layout_main_window(NULL);
+               return;
+       }
+
+       if( stricmp( pref, "font_text")==0 ||
+               stricmp( pref, "font_size_text")==0 ) {
+
+               if( iflags.wc_fontsiz_text<NHFONT_SIZE_MIN || 
+                       iflags.wc_fontsiz_text>NHFONT_SIZE_MAX )
+                       iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
+
+               hdc = GetDC(GetNHApp()->hMainWnd);
+               mswin_get_font(NHW_TEXT, ATR_NONE, hdc, TRUE);
+               mswin_get_font(NHW_TEXT, ATR_BOLD, hdc, TRUE);
+               mswin_get_font(NHW_TEXT, ATR_DIM, hdc, TRUE);
+               mswin_get_font(NHW_TEXT, ATR_ULINE, hdc, TRUE);
+               mswin_get_font(NHW_TEXT, ATR_BLINK, hdc, TRUE);
+               mswin_get_font(NHW_TEXT, ATR_INVERSE, hdc, TRUE);
+               ReleaseDC(GetNHApp()->hMainWnd, hdc);
+
+               mswin_layout_main_window(NULL);
+               return;
+       }
+
+       if( stricmp( pref, "scroll_amount")==0 ) {
+               mswin_cliparound(u.ux, u.uy);
+               return;
+       }
+
+       if( stricmp( pref, "scroll_margin")==0 ) {
+               mswin_cliparound(u.ux, u.uy);
+               return;
+       }
+
+       if( stricmp( pref, "map_mode")==0 ) {
+               mswin_select_map_mode( iflags.wc_map_mode );
+               return;
+       }
+
+       if( stricmp( pref, "hilite_pet")==0 ) {
+               InvalidateRect(mswin_hwnd_from_winid(WIN_MAP), NULL, TRUE);
+               return;
+       }
+
+       if( stricmp( pref, "align_message")==0 ||
+               stricmp( pref, "align_status")==0 ) {
+               mswin_layout_main_window(NULL);
+               return;
+       }
+
+       if( stricmp( pref, "vary_msgcount")==0 ) {
+               InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE);
+               mswin_layout_main_window(NULL);
+               return;
+       }
+
+}
+
+
+void mswin_main_loop()
+{
+       MSG msg;
+
+       while( !mswin_have_input() &&
+                  GetMessage(&msg, NULL, 0, 0)!=0 ) {
+               if (GetNHApp()->regNetHackMode ||
+                       !TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg))
+               {
+                       TranslateMessage(&msg);
+                       DispatchMessage(&msg);
+               }
+       } 
+}
+
+/* clean up and quit */
+void bail(const char *mesg)
+{
+    clearlocks();
+    mswin_exit_nhwindows(mesg);
+    terminate(EXIT_SUCCESS);
+    /*NOTREACHED*/
+}
+
+BOOL initMapTiles(void)
+{
+       HBITMAP hBmp;
+       BITMAP  bm;
+       TCHAR   wbuf[MAX_PATH];
+       int     tl_num;
+       SIZE    map_size;
+       extern int total_tiles_used;
+
+       /* no file - no tile */
+       if( !(iflags.wc_tile_file && *iflags.wc_tile_file) ) 
+               return TRUE;
+
+       /* load bitmap */
+       hBmp = LoadImage(
+                               GetNHApp()->hApp, 
+                               NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH),
+                               IMAGE_BITMAP,
+                               0,
+                               0,
+                               LR_LOADFROMFILE | LR_DEFAULTSIZE 
+                       );
+       if( hBmp==NULL ) {
+               raw_print("Cannot load tiles from the file. Reverting back to default.");
+               return FALSE;
+       }
+
+       /* calculate tile dimensions */
+       GetObject(hBmp, sizeof(BITMAP), (LPVOID)&bm);
+       if( bm.bmWidth%iflags.wc_tile_width ||
+               bm.bmHeight%iflags.wc_tile_height ) {
+               DeleteObject(hBmp);
+               raw_print("Tiles bitmap does not match tile_width and tile_height options. Reverting back to default.");
+               return FALSE;
+       }
+
+       tl_num = (bm.bmWidth/iflags.wc_tile_width)*
+                    (bm.bmHeight/iflags.wc_tile_height);
+       if( tl_num<total_tiles_used ) {
+               DeleteObject(hBmp);
+               raw_print("Number of tiles in the bitmap is less than required by the game. Reverting back to default.");
+               return FALSE;
+       }
+
+       /* set the tile information */
+       if( GetNHApp()->bmpMapTiles!=GetNHApp()->bmpTiles ) {
+               DeleteObject(GetNHApp()->bmpMapTiles);
+       }
+
+       GetNHApp()->bmpMapTiles = hBmp;
+       GetNHApp()->mapTile_X = iflags.wc_tile_width;
+       GetNHApp()->mapTile_Y = iflags.wc_tile_height;
+       GetNHApp()->mapTilesPerLine = bm.bmWidth / iflags.wc_tile_width;
+
+       map_size.cx = GetNHApp()->mapTile_X * COLNO;
+       map_size.cy = GetNHApp()->mapTile_Y * ROWNO;
+       mswin_map_stretch(
+               mswin_hwnd_from_winid(WIN_MAP),
+               &map_size,
+               TRUE 
+       );
+       return TRUE;
+}
+
+void mswin_popup_display(HWND hWnd, int* done_indicator)
+{
+       MSG msg;
+       HWND hChild;
+       HMENU hMenu;
+       int mi_count;
+       int i;
+
+       /* activate the menu window */
+       GetNHApp()->hPopupWnd = hWnd;
+
+       mswin_layout_main_window(hWnd);
+
+       /* disable game windows */
+       for( hChild=GetWindow(GetNHApp()->hMainWnd, GW_CHILD);
+                hChild;
+                hChild = GetWindow(hChild, GW_HWNDNEXT) ) {
+               if( hChild!= hWnd) EnableWindow(hChild, FALSE);
+       }
+
+       /* disable menu */
+       hMenu = GetMenu( GetNHApp()->hMainWnd );
+       mi_count = GetMenuItemCount( hMenu );
+       for( i=0; i<mi_count; i++ ) {
+               EnableMenuItem(hMenu, i, MF_BYPOSITION | MF_GRAYED);
+       }
+       DrawMenuBar( GetNHApp()->hMainWnd );
+
+       /* bring menu window on top */
+       SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
+
+       /* go into message loop */
+       while( IsWindow(hWnd) && 
+                  (done_indicator==NULL || !*done_indicator) &&
+                  GetMessage(&msg, NULL, 0, 0)!=0 ) {
+               if( !IsDialogMessage(hWnd, &msg) ) {
+                       if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) {
+                               TranslateMessage(&msg);
+                               DispatchMessage(&msg);
+                       }
+               }
+       }
+}
+
+void mswin_popup_destroy(HWND hWnd)
+{
+       HWND hChild;
+       HMENU hMenu;
+       int mi_count;
+       int i;
+
+       /* enable game windows */
+       for( hChild=GetWindow(GetNHApp()->hMainWnd, GW_CHILD);
+                hChild;
+                hChild = GetWindow(hChild, GW_HWNDNEXT) ) {
+               if( hChild!= hWnd) {
+                       EnableWindow(hChild, TRUE);
+               }
+       }
+
+       /* enable menu */
+       hMenu = GetMenu( GetNHApp()->hMainWnd );
+       mi_count = GetMenuItemCount( hMenu );
+       for( i=0; i<mi_count; i++ ) {
+               EnableMenuItem(hMenu, i, MF_BYPOSITION | MF_ENABLED);
+       }
+       DrawMenuBar( GetNHApp()->hMainWnd );
+
+       SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
+       GetNHApp()->hPopupWnd = NULL;
+       mswin_window_mark_dead( mswin_winid_from_handle(hWnd) );
+       DestroyWindow(hWnd);
+
+       mswin_layout_main_window(hWnd);
+
+       SetFocus(GetNHApp()->hMainWnd );
+}
+
+#ifdef _DEBUG
+#include <stdarg.h>
+
+void
+logDebug(const char *fmt, ...)
+{
+  FILE *dfp = fopen("nhtrace.log", "a");
+
+  if (dfp) {
+     va_list args;
+
+     va_start(args, fmt);
+     vfprintf(dfp, fmt, args);
+     va_end(args);
+     fclose(dfp);
+  }
+}
+
+#endif
+
+
+/* Reading and writing settings from the registry. */
+#define CATEGORYKEY         "Software"
+#define COMPANYKEY          "NetHack"
+#define PRODUCTKEY          "NetHack 3.4.3"
+#define SETTINGSKEY         "Settings"
+#define MAINSHOWSTATEKEY    "MainShowState"
+#define MAINMINXKEY         "MainMinX"
+#define MAINMINYKEY         "MainMinY"
+#define MAINMAXXKEY         "MainMaxX"
+#define MAINMAXYKEY         "MainMaxY"
+#define MAINLEFTKEY         "MainLeft"
+#define MAINRIGHTKEY        "MainRight"
+#define MAINTOPKEY          "MainTop"
+#define MAINBOTTOMKEY       "MainBottom"
+
+/* #define all the subkeys here */
+#define INTFKEY "Interface"
+
+void
+mswin_read_reg()
+{
+    HKEY key;
+    DWORD size;
+    char keystring[MAX_PATH];
+
+    sprintf(keystring, "%s\\%s\\%s\\%s", 
+        CATEGORYKEY, COMPANYKEY, PRODUCTKEY, SETTINGSKEY);
+
+    /* Set the defaults here. The very first time the app is started, nothing is 
+       read from the registry, so these defaults apply. */
+    GetNHApp()->saveRegistrySettings = 1;   /* Normally, we always save */
+    GetNHApp()->regNetHackMode = 0;
+
+    if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key) 
+            != ERROR_SUCCESS)
+        return;
+
+    size = sizeof(DWORD);
+    /* Read the keys here. */
+    RegQueryValueEx(key, INTFKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regNetHackMode)), &size);
+    /* Main window placement */
+    RegQueryValueEx(key, MAINSHOWSTATEKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainShowState)), &size);
+    RegQueryValueEx(key, MAINMINXKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainMinX)), &size);
+    RegQueryValueEx(key, MAINMINYKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainMinY)), &size);
+    RegQueryValueEx(key, MAINMAXXKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainMaxX)), &size);
+    RegQueryValueEx(key, MAINMAXYKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainMaxY)), &size);
+    RegQueryValueEx(key, MAINLEFTKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainLeft)), &size);
+    RegQueryValueEx(key, MAINRIGHTKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainRight)), &size);
+    RegQueryValueEx(key, MAINTOPKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainTop)), &size);
+    RegQueryValueEx(key, MAINBOTTOMKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainBottom)), &size);
+    
+    RegCloseKey(key);
+}
+
+void
+mswin_write_reg()
+{
+    HKEY key;
+    DWORD disposition;
+
+    if (GetNHApp()->saveRegistrySettings)
+    {
+        char keystring[MAX_PATH];
+
+        sprintf(keystring, "%s\\%s\\%s\\%s", 
+            CATEGORYKEY, COMPANYKEY, PRODUCTKEY, SETTINGSKEY);
+
+        if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_WRITE, &key) != ERROR_SUCCESS)
+        {
+            RegCreateKeyEx(HKEY_CURRENT_USER, keystring, 0, "",
+                REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, &disposition);
+        }
+
+        /* Write the keys here */
+        RegSetValueEx(key, INTFKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regNetHackMode)), sizeof(DWORD));
+        /* Main window placement */
+        RegSetValueEx(key, MAINSHOWSTATEKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainShowState)), sizeof(DWORD));
+        RegSetValueEx(key, MAINMINXKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainMinX)), sizeof(DWORD));
+        RegSetValueEx(key, MAINMINYKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainMinY)), sizeof(DWORD));
+        RegSetValueEx(key, MAINMAXXKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainMaxX)), sizeof(DWORD));
+        RegSetValueEx(key, MAINMAXYKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainMaxY)), sizeof(DWORD));
+        RegSetValueEx(key, MAINLEFTKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainLeft)), sizeof(DWORD));
+        RegSetValueEx(key, MAINRIGHTKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainRight)), sizeof(DWORD));
+        RegSetValueEx(key, MAINTOPKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainTop)), sizeof(DWORD));
+        RegSetValueEx(key, MAINBOTTOMKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainBottom)), sizeof(DWORD));
+
+        RegCloseKey(key);
+    }
+}
+
+void
+mswin_destroy_reg()
+{
+    char keystring[MAX_PATH];
+    HKEY key;
+    DWORD nrsubkeys;
+
+    /* Delete keys one by one, as NT does not delete trees */
+    sprintf(keystring, "%s\\%s\\%s\\%s", 
+        CATEGORYKEY, COMPANYKEY, PRODUCTKEY, SETTINGSKEY);
+    RegDeleteKey(HKEY_CURRENT_USER, keystring);
+    sprintf(keystring, "%s\\%s\\%s", 
+        CATEGORYKEY, COMPANYKEY, PRODUCTKEY);
+    RegDeleteKey(HKEY_CURRENT_USER, keystring);
+    /* The company key will also contain information about newer versions
+       of nethack (e.g. a subkey called NetHack 4.0), so only delete that
+       if it's empty now. */
+    sprintf(keystring, "%s\\%s", CATEGORYKEY, COMPANYKEY);
+    /* If we cannot open it, we probably cannot delete it either... Just
+       go on and see what happens. */
+    RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key); 
+    nrsubkeys = 0;
+    RegQueryInfoKey(key, NULL, NULL, NULL, &nrsubkeys, NULL, NULL, NULL, 
+        NULL, NULL, NULL, NULL);
+    RegCloseKey(key);
+    if (nrsubkeys == 0)
+        RegDeleteKey(HKEY_CURRENT_USER, keystring);
+
+    /* Prevent saving on exit */
+    GetNHApp()->saveRegistrySettings = 0;
+}
+
+typedef struct ctv
+{
+       const char *colorstring;
+       COLORREF colorvalue;
+} color_table_value;
+
+/*
+ * The color list here is a combination of:
+ * NetHack colors.  (See mhmap.c)
+ * HTML colors. (See http://www.w3.org/TR/REC-html40/types.html#h-6.5 )
+ */
+
+static color_table_value color_table[] = {
+/* NetHack colors */
+       { "black",              RGB(0x55, 0x55, 0x55)},
+       { "red",                RGB(0xFF, 0x00, 0x00)},
+       { "green",              RGB(0x00, 0x80, 0x00)},
+       { "brown",              RGB(0xA5, 0x2A, 0x2A)},
+       { "blue",               RGB(0x00, 0x00, 0xFF)},
+       { "magenta",            RGB(0xFF, 0x00, 0xFF)},
+       { "cyan",               RGB(0x00, 0xFF, 0xFF)},
+       { "orange",             RGB(0xFF, 0xA5, 0x00)},
+       { "brightgreen",        RGB(0x00, 0xFF, 0x00)},
+       { "yellow",             RGB(0xFF, 0xFF, 0x00)},
+       { "brightblue",         RGB(0x00, 0xC0, 0xFF)},
+       { "brightmagenta",      RGB(0xFF, 0x80, 0xFF)},
+       { "brightcyan",         RGB(0x80, 0xFF, 0xFF)},
+       { "white",              RGB(0xFF, 0xFF, 0xFF)},
+/* Remaining HTML colors */
+       { "trueblack",          RGB(0x00, 0x00, 0x00)},
+       { "gray",               RGB(0x80, 0x80, 0x80)},
+       { "grey",               RGB(0x80, 0x80, 0x80)},
+       { "purple",             RGB(0x80, 0x00, 0x80)},
+       { "silver",             RGB(0xC0, 0xC0, 0xC0)},
+       { "maroon",             RGB(0x80, 0x00, 0x00)},
+       { "fuchsia",            RGB(0xFF, 0x00, 0xFF)}, /* = NetHack magenta */
+       { "lime",               RGB(0x00, 0xFF, 0x00)}, /* = NetHack bright green */
+       { "olive",              RGB(0x80, 0x80, 0x00)},
+       { "navy",               RGB(0x00, 0x00, 0x80)},
+       { "teal",               RGB(0x00, 0x80, 0x80)},
+       { "aqua",               RGB(0x00, 0xFF, 0xFF)}, /* = NetHack cyan */
+       { "",                   RGB(0x00, 0x00, 0x00)},
+};
+
+typedef struct ctbv
+{
+       char *colorstring;
+       int syscolorvalue;
+} color_table_brush_value;
+
+static color_table_brush_value color_table_brush[] = {
+       { "activeborder",       COLOR_ACTIVEBORDER      },
+       { "activecaption",      COLOR_ACTIVECAPTION     },
+       { "appworkspace",               COLOR_APPWORKSPACE      },
+       { "background",         COLOR_BACKGROUND                },
+       { "btnface",            COLOR_BTNFACE           },
+       { "btnshadow",          COLOR_BTNSHADOW         },
+       { "btntext",            COLOR_BTNTEXT           },
+       { "captiontext",                COLOR_CAPTIONTEXT               },
+       { "graytext",           COLOR_GRAYTEXT          },
+       { "greytext",           COLOR_GRAYTEXT          },
+       { "highlight",          COLOR_HIGHLIGHT                 },
+       { "highlighttext",      COLOR_HIGHLIGHTTEXT     },
+       { "inactiveborder",     COLOR_INACTIVEBORDER    },
+       { "inactivecaption",    COLOR_INACTIVECAPTION   },
+       { "menu",                       COLOR_MENU                      },
+       { "menutext",           COLOR_MENUTEXT          },
+       { "scrollbar",          COLOR_SCROLLBAR                 },
+       { "window",                     COLOR_WINDOW            },
+       { "windowframe",                COLOR_WINDOWFRAME       },
+       { "windowtext",         COLOR_WINDOWTEXT                },
+       { "",                   -1                              },
+};
+
+static void mswin_color_from_string(char *colorstring, HBRUSH* brushptr, COLORREF *colorptr)
+{
+       color_table_value *ctv_ptr = color_table;
+       color_table_brush_value *ctbv_ptr = color_table_brush;
+       int red_value, blue_value, green_value;
+       static char *hexadecimals = "0123456789abcdef";
+
+       if (colorstring == NULL) return;
+       if (*colorstring == '#') {
+               if (strlen(++colorstring) != 6) return;
+
+               red_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
+               red_value *= 16;
+               red_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
+
+               green_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
+               green_value *= 16;
+               green_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
+
+               blue_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
+               blue_value *= 16;
+               blue_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
+
+               *colorptr = RGB(red_value, green_value, blue_value);
+       } else {
+           while (*ctv_ptr->colorstring && stricmp(ctv_ptr->colorstring, colorstring))
+               ++ctv_ptr;
+           if (*ctv_ptr->colorstring) {
+               *colorptr = ctv_ptr->colorvalue;
+           } else {
+             while (*ctbv_ptr->colorstring && stricmp(ctbv_ptr->colorstring, colorstring))
+                   ++ctbv_ptr;
+               if (*ctbv_ptr->colorstring) {
+                   *brushptr = SYSCLR_TO_BRUSH(ctbv_ptr->syscolorvalue);
+                   *colorptr = GetSysColor(ctbv_ptr->syscolorvalue);
+               }
+           }
+       }
+       if (max_brush > TOTAL_BRUSHES) panic("Too many colors!");
+       *brushptr = CreateSolidBrush(*colorptr);
+       brush_table[max_brush++] = *brushptr;
+}
+
+int NHMessageBox(HWND hWnd, LPCTSTR text, UINT type)
+{
+    TCHAR title[MAX_LOADSTRING];
+    
+    LoadString(GetNHApp()->hApp, IDS_APP_TITLE_SHORT, title, MAX_LOADSTRING);
+
+    return MessageBox(hWnd, text, title, type);
+}
diff --git a/win/win32/nethack.dsw b/win/win32/nethack.dsw
new file mode 100644 (file)
index 0000000..ff30f52
--- /dev/null
@@ -0,0 +1,212 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "NetHackW"=.\build\NetHackW.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name dgncomp\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name dlb_main\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name levcomp\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name makedefs\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name tilemap\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name tiles\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name uudecode\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "dgncomp"=.\build\dgncomp.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name dgnstuff\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "dgnstuff"=.\build\dgnstuff.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name makedefs\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "dlb_main"=.\build\dlb_main.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name dgncomp\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name levcomp\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name makedefs\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "levcomp"=.\build\levcomp.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name levstuff\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "levstuff"=.\build\levstuff.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name makedefs\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "makedefs"=.\build\makedefs.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "recover"=.\build\recover.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name makedefs\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name dlb_main\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "tile2bmp"=.\build\tile2bmp.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "tilemap"=.\build\tilemap.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "tiles"=.\build\tiles.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name tile2bmp\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "uudecode"=.\build\uudecode.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
diff --git a/win/win32/nethackw.dsp b/win/win32/nethackw.dsp
new file mode 100644 (file)
index 0000000..03521aa
--- /dev/null
@@ -0,0 +1,1107 @@
+# Microsoft Developer Studio Project File - Name="NetHackW" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Application" 0x0101\r
+\r
+CFG=NetHackW - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "NetHackW.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "NetHackW.mak" CFG="NetHackW - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "NetHackW - Win32 Release" (based on "Win32 (x86) Application")\r
+!MESSAGE "NetHackW - Win32 Debug" (based on "Win32 (x86) Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "NetHackW - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /Og /Oy /Ob1 /Gs /Gf /Gy /Oi- /Ot  /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /W3 /GX /Og /Oy /Ob1 /Gs /Gf /Gy /Oi- /Ot  /I "..\win\win32" /I "..\include" /I "..\sys\winnt" /I "..\sys\share" /I "..\win\share" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib advapi32.lib winmm.lib /nologo /subsystem:windows /map /debug /machine:I386 /MAPINFO:EXPORTS /MAPINFO:LINES\r
+# SUBTRACT LINK32 /pdb:none\r
+# Begin Special Build Tool\r
+OutDir=.\Release\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Install exe\r
+PostBuild_Cmds=copy $(OutDir)\NetHackW.exe ..\binary   \\r
+copy ..\dat\nhdat ..\binary    \\r
+copy ..\dat\license ..\binary  \\r
+if exist tiles.bmp copy tiles.bmp ..\binary    \\r
+if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt        \\r
+if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt      \\r
+copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "NetHackW - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\win\win32" /I "..\include" /I "..\sys\winnt" /I "..\sys\share" /I "..\win\share" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib advapi32.lib winmm.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept\r
+# Begin Special Build Tool\r
+OutDir=.\Debug\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Install exe\r
+PostBuild_Cmds=if NOT exist ..\binary\*.* mkdir ..\binary      \\r
+copy $(OutDir)\NetHackW.exe ..\binary  \\r
+copy ..\dat\nhdat ..\binary    \\r
+copy ..\dat\license ..\binary  \\r
+if exist tiles.bmp copy tiles.bmp ..\binary    \\r
+if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt        \\r
+if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt      \\r
+copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "NetHackW - Win32 Release"\r
+# Name "NetHackW - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\src\allmain.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\alloc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\apply.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\artifact.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\attrib.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\ball.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\bones.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\botl.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\cmd.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dbridge.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\decl.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\detect.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dig.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\display.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dlb.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\do.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\do_name.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\do_wear.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dog.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dogmove.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dokick.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dothrow.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\drawing.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\dungeon.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\eat.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\end.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\engrave.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\exper.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\explode.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\extralev.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\files.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\fountain.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\tty\getline.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\hack.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\hacklib.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\invent.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\light.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\lock.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mail.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\makemon.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mapglyph.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mcastu.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mhitm.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mhitu.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\minion.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mklev.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mkmap.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mkmaze.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mkobj.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mkroom.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mon.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mondata.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\monmove.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\monst.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\monstr.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mplayer.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\mthrowu.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\muse.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\music.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\winnt\ntsound.c\r
+# End Source File\r
+# Begin Source File\r
\r
+SOURCE=..\src\o_init.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\objects.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\objnam.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\options.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\pager.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\share\pcmain.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\share\pcsys.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\share\pcunix.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\pickup.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\pline.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\polyself.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\potion.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\pray.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\priest.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\quest.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\questpgr.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\share\random.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\read.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rect.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\region.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\restore.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rip.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rnd.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\role.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rumors.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\save.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\shk.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\shknam.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\sit.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\sounds.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\sp_lev.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\spell.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\steal.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\steed.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\teleport.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\tile.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\timeout.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\topten.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\track.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\trap.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\u_init.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\uhitm.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\vault.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\version.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\vision.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\weapon.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\were.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\wield.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\windows.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\winnt\winnt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\tty\wintty.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\wizard.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\worm.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\worn.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\write.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\zap.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\align.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\amiconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\artifact.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\artilist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\attrib.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\beconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\bitmfile.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\color.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config1.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\coord.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\decl.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\def_os2.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dgn_file.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\display.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dlb.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dungeon.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\edog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\emin.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\engrave.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\epri.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\eshk.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\extern.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\flag.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\func_tab.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\gem_rsc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\global.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\hack.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\lev.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\load_img.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\macconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\macpopup.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mactty.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\macwin.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mail.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mfndpos.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\micro.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mkroom.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monattk.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mondata.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monflag.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monst.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monsym.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mttypriv.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\nhlan.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\ntconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\obj.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\objclass.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\os2conf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\patchlevel.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\pcconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\permonst.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\prop.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\qt_clust.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\qt_kde0.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\qt_win.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\qt_xpms.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\qtext.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\quest.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\rect.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\region.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\rm.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\skills.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\sp_lev.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\spell.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\system.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tcap.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tile2x11.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\timeout.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tosconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tradstdc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\trampoli.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\trap.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\unixconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\vault.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\vision.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\vmsconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\winami.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wingem.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\winGnome.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\winprocs.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wintty.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wintype.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\winX.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\xwindow.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\xwindowp.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\you.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\youprop.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\bitmap1.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\bitmap2.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mnsel.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mnunsel.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\NETHACK.ICO\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\small.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\tiles.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\winhack.ico\r
+# End Source File\r
+# End Group\r
+# Begin Group "wnd"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhaskyn.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhaskyn.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhdlg.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhdlg.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhfont.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhfont.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhinput.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhinput.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmain.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmain.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmap.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmap.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmenu.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmenu.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmsg.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmsgwnd.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhmsgwnd.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhsplash.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhrip.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhsplash.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhrip.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhstatus.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhstatus.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhtext.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mhtext.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\mswproc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\resource.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\winhack.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\winhack.rc\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\winMS.h\r
+# End Source File\r
+# End Group\r
+# Begin Source File\r
+\r
+SOURCE=..\win\win32\ReadMe.txt\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/win/win32/petmark.uu b/win/win32/petmark.uu
new file mode 100644 (file)
index 0000000..deace34
--- /dev/null
@@ -0,0 +1,9 @@
+begin 600 petmark.bmp
+M0DWV`````````'8````H````$````!`````!``0``````(``````````````
+M````````````;&Q'````_P```````("``(````"``(``@(```,#`P`#`W,``
+M\,JF``0$!``("`@`#`P,`!$1$0`6%A8`'!P<````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````````$`````
+5````$1````````$1$0```````!`0
+`
+end
diff --git a/win/win32/recover.dsp b/win/win32/recover.dsp
new file mode 100644 (file)
index 0000000..7052afa
--- /dev/null
@@ -0,0 +1,148 @@
+# Microsoft Developer Studio Project File - Name="recover" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=recover - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "recover.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "recover.mak" CFG="recover - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "recover - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "recover - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "recover - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"\r
+# ADD RSC /l 0x1009 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# Begin Special Build Tool\r
+OutDir=.\Release\r
+SOURCE="$(InputPath)"\r
+PostBuild_Cmds=copy $(OutDir)\recover.exe ..\binary    \\r
+if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "recover - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\include" /I "..\sys\winnt" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"\r
+# ADD RSC /l 0x1009 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# Begin Special Build Tool\r
+OutDir=.\Debug\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=install exe\r
+PostBuild_Cmds=copy $(OutDir)\recover.exe ..\binary    \\r
+if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "recover - Win32 Release"\r
+# Name "recover - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\util\recover.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config1.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\coord.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\global.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\nhlan.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\ntconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tradstdc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\winnt\win32api.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/win32/resource.h b/win/win32/resource.h
new file mode 100644 (file)
index 0000000..00a29a6
--- /dev/null
@@ -0,0 +1,151 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by winhack.rc
+//
+#define IDC_MYICON                      2
+#define IDD_WINHACK_DIALOG              102
+#define IDD_ABOUTBOX                    103
+#define IDS_APP_TITLE                   103
+#define IDM_ABOUT                       104
+#define IDM_EXIT                        105
+#define IDS_HELLO                       106
+#define IDI_NETHACKW                    107
+#define IDC_NETHACKW                    109
+#define IDS_APP_TITLE_SHORT             110
+#define IDR_MAINFRAME                   128
+#define IDB_TILES                       129
+#define IDD_TEXT                        130
+#define IDD_NHTEXT                      130
+#define IDD_MENU                        132
+#define IDB_MENU_SEL                    133
+#define IDB_MENU_UNSEL                  134
+#define IDD_COMMANDS                    136
+#define IDD_GETLIN                      138
+#define IDD_EXTCMD                      139
+#define IDD_PLAYER_SELECTOR             141
+#define IDB_PETMARK                     143
+#define IDB_MENU_SEL_COUNT              144
+#define IDD_NHRIP                       145
+#define IDB_SPLASH                      146
+#define IDB_RIP                         147
+#define IDD_SPLASH                      148
+#define IDC_TEXT_VIEW                   1000
+#define IDC_TEXT_CONTROL                1000
+#define IDC_CMD_MOVE_NW                 1001
+#define IDC_CMD_MOVE_N                  1002
+#define IDC_MENU_LIST                   1003
+#define IDC_CMD_MOVE_NE                 1003
+#define IDC_MENU_TEXT                   1004
+#define IDC_CMD_MOVE_W                  1004
+#define IDC_CMD_MOVE_SELF               1005
+#define IDC_CMD_MOVE_E                  1006
+#define IDC_CMD_MOVE_SW                 1007
+#define IDC_CMD_MOVE_S                  1008
+#define IDC_CMD_MOVE_SE                 1009
+#define IDC_CMD_MOVE_UP                 1010
+#define IDC_CMD_MOVE_DOWN               1011
+#define IDC_CMD_5                       1012
+#define IDC_CMD_A                       1013
+#define IDC_CMD_B                       1014
+#define IDC_CMD_C                       1015
+#define IDC_CMD_D                       1016
+#define IDC_CMD_E                       1017
+#define IDC_CMD_F                       1018
+#define IDC_CMD_G                       1019
+#define IDC_CMD_H                       1020
+#define IDC_CMD_I                       1021
+#define IDC_CMD_J                       1022
+#define IDC_CMD_K                       1023
+#define IDC_CMD_L                       1024
+#define IDC_CMD_M                       1025
+#define IDC_CMD_N                       1026
+#define IDC_CMD_O                       1027
+#define IDC_CMD_P                       1028
+#define IDC_CMD_Q                       1029
+#define IDC_CMD_R                       1030
+#define IDC_CMD_S                       1031
+#define IDC_CMD_T                       1032
+#define IDC_CMD_U                       1033
+#define IDC_CMD_V                       1034
+#define IDC_CMD_W                       1035
+#define IDC_CMD_X                       1036
+#define IDC_CMD_Y                       1037
+#define IDC_CMD_Z                       1038
+#define IDC_CMD_AA                      1039
+#define IDC_CMD_BB                      1040
+#define IDC_CMD_CC                      1041
+#define IDC_CMD_DD                      1042
+#define IDC_CMD_EE                      1043
+#define IDC_CMD_FF                      1044
+#define IDC_CMD_GG                      1045
+#define IDC_CMD_HH                      1046
+#define IDC_CMD_II                      1047
+#define IDC_CMD_JJ                      1048
+#define IDC_CMD_KK                      1049
+#define IDC_CMD_LL                      1050
+#define IDC_CMD_MM                      1051
+#define IDC_CMD_NN                      1052
+#define IDC_CMD_OO                      1053
+#define IDC_CMD_PP                      1054
+#define IDC_CMD_QQ                      1055
+#define IDC_CMD_RR                      1056
+#define IDC_CMD_SS                      1057
+#define IDC_CMD_TT                      1058
+#define IDC_CMD_UU                      1059
+#define IDC_CMD_VV                      1060
+#define IDC_CMD_WW                      1061
+#define IDC_CMD_XX                      1062
+#define IDC_CMD_YY                      1063
+#define IDC_CMD_ZZ                      1064
+#define IDC_CMD_FIRST                   1100
+#define IDC_CMD_LAST                    1300
+#define IDC_GETLIN_EDIT                 1309
+#define IDC_EXTCMD_LIST                 1310
+#define IDC_PLSEL_NAME                  1314
+#define IDC_PLSEL_ROLE_RANDOM           1315
+#define IDC_PLSEL_RACE_RANDOM           1318
+#define IDC_PLSEL_GENDER_RANDOM         1319
+#define IDC_PLSEL_ALIGN_RANDOM          1320
+#define IDC_PLSEL_ROLE_LIST             1323
+#define IDC_PLSEL_RACE_LIST             1324
+#define IDC_PLSEL_ALIGN_LIST            1325
+#define IDC_PLSEL_GENDER_LIST           1326
+#define IDC_ABOUT_VERSION               1327
+#define IDC_ABOUT_COPYRIGHT             1328
+#define IDC_EXTRAINFO                   1331
+#define IDM_SAVE                        32771
+#define IDM_HELP_LONG                   32772
+#define IDM_HELP_COMMANDS               32773
+#define IDM_HELP_HISTORY                32774
+#define IDM_HELP_INFO_CHAR              32775
+#define IDM_HELP_INFO_KEY               32776
+#define IDM_HELP_OPTIONS                32777
+#define IDM_HELP_OPTIONS_LONG           32778
+#define IDM_HELP_EXTCMD                 32779
+#define IDM_HELP_LICENSE                32780
+#define IDM_HELP_PORTHELP               32781
+#define IDM_MAP_TILES                   32782
+#define IDM_MAP_ASCII4X6                32783
+#define IDM_MAP_ASCII6X8                32784
+#define IDM_MAP_ASCII8X8                32785
+#define IDM_MAP_ASCII16X8               32786
+#define IDM_MAP_ASCII7X12               32787
+#define IDM_MAP_ASCII8X12               32788
+#define IDM_MAP_ASCII16X12              32789
+#define IDM_MAP_ASCII12X16              32790
+#define IDM_MAP_ASCII10X18              32791
+#define IDM_MAP_FIT_TO_SCREEN           32792
+#define IDM_NHMODE                      32794
+#define IDM_CLEARSETTINGS               32795
+#define IDC_STATIC                      -1
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        145
+#define _APS_NEXT_COMMAND_VALUE         32796
+#define _APS_NEXT_CONTROL_VALUE         1332
+#define _APS_NEXT_SYMED_VALUE           110
+#endif
+#endif
diff --git a/win/win32/rip.uu b/win/win32/rip.uu
new file mode 100644 (file)
index 0000000..c1da8e6
--- /dev/null
@@ -0,0 +1,1805 @@
+begin 600 rip.bmp
+M0DVV/`$``````#8$```H````D`$``,@````!``@``````(`X`0`2"P``$@L`
+M```!`````0``+C8V`$9!00`Q+R\`(S4U``)'`P`*+A4`'C$P`"LI*0`1-2,`
+M&B(B`**FI@`X.CH`:W1U`!0:&0!X?G\`#1(2`!,G'P`*,Q8``3X#`!88&``!
+M.@,``C@$`!06%@!-1D8`)20D``H,#``,%14`145%`#=+2P`/,!\`#RX?`#\_
+M/P`]/3T`%1L;``TN&@"#AX@`+2TM`"DI*0![?X``$R\G`#0Q,0!634T`#A@8
+M`+&TM`"2F)@`(28E`(J0D``8'!P`?8*#`&1L;0`?("``<WAY`"XL+`!*0D(`
+M04-#`!<?'P`B.R<`'RXN`'1]?@"$BXL`&!T=`'Z%A0!/2TL`S,[.``%#`P`!
+M00,`*"<G``(S!``Y-34`%2LH`%!;6@`;)"0`OL#``"HP,`!A7EX`#S,?`-S?
+MWP"'C(P``3P$``(V!0`[.#@``C`%`#<T-`!*1$0`6U)2``DI$P`#!@8`(BDI
+M`#="0@`Z.SL`````````````````````````````````W@T-``(````-#0T`
+M```````````0`0$```@(``````#0+C8`.$9!`+4Q+P``(S4`:`)'`#8*+@"S
+M'C$``"LI```1-0``&B(``**F```X.@``:W0``!0:``!X?@``#1(``!,G```*
+M,P```3X``!88```!.@```C@``!06``!-1@``)20```H,```,%0``144``#=+
+M```/,```#RX``#\_```]/0``%1L```TN``"#AP``+2T``"DI``![?P``$R\`
+M`#0Q``!630``#A@``+&T``"2F```(28``(J0```8'```?8(``&1L```?(```
+M<W@``"XL``!*0@``04,``!<?```B.P``'RX``'1]``"$BP``&!T``'Z%``!/
+M2P``S,X```%#```!00``*"<```(S```Y-0``%2L``%!;```;)```OL```"HP
+M``!A7@``#S,``-S?``"'C````3P```(V```[.````C```#<T``!*1```6U(`
+M``DI```#!@``(BD``#="```Z.P``````````````````````````````````
+MW@T```(````-#0`````````````0`0````@```````#0+@``.$8``+4Q````
+M(P``:`(``#8*``"S'@```"L````1````&@```*(````X````:P```!0```!X
+M````#0```!,````*`````0```!8````!`````@```!0```!-````)0````H`
+M```,````10```#<````/````#P```#\````]````%0````T```"#````+0``
+M`"D```![````$P```#0```!6````#@```+$```"2````(0```(H````8`$!`
+M0$!`0$!`0$!`0$!`0$!`0$!`0$!.3DY`0$!`0$!`0$!`0$!`0$!`0$Y.3DY`
+M0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!.3DY.3DY#
+M3DY.3DY.3DY.3DY.3DY.3DY#3D-#0T-.3DY.3DY.0$!.3DY.3DY.3DY.3DY.
+M3D!`0$Y.0T-#3D-.3DY.3DY.3DY#3DY.3DY.3DY.0T-#8D-#0T-B0T-#0T-#
+M3DY.3DY.3DY#3D-#0TY.3D!`3D-#0T-#3DY.3D!`3D-#3A$1$4-#0T-#0T-#
+M0T-#0T-#0T-#0T-#0P5#0T-#0T-#!4-#$4-#0T,%0P5#!04%(DM%(B)%2T4B
+M(D4B"$M%2T4B(@@("`A%2P@(2P@(""(0"$4("`A+"`@(10@("`@((D5+"$L(
+M2T4B12((2T4B"`@("`A%(@A%2P@(2T5+14M%(@A%"$4((D4B10A+"`A%14M%
+M"`A+"`A+12)%(D4B"`@B"")%"$M%2R)%(@@(12)%2P@((D5+14M`0$!`0$!`
+M0$!`0$!`0$Y`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$Y.3DY.0$!`
+M0$!`0$!`0$!.0$!`0$!.3DY`0$!`0$!`0$!`0$!`0$!.3DY#0T-#3D-#0T-#
+M0T-#0TY#0TY.3DY#0T-#0T-#0T-#0TY.3DY.3DY.3DY.3DY.3D-#0TY`0$Y.
+M3DY.3DY`3DY.3DY.3D!.3D!.3DY.3DY.3D-#0T-B0U9#0T-#0T-#0TY.3DY#
+M0T-.3DY.0TY`0$!`3D-#0T-#0T-#3DY.0T,13D,(0$!`0T-#0T-#0T-#0T-#
+M0T-#0T-#3D-#0T-#$4Y#0T,%0T-#$4,%0P5#$04B(D4("")%(B)+"`@B14M%
+M2P@B12(("$L((@@("`@(2T4B"$M+2TL(2PA%2P@((DM%(B)%2T4("$4B10@(
+M"$4("`A%"`@B10@((D5+"$5+10@("`A%2P@(2T4("`A%(D5+"")%"")%(D5%
+M(D4B12)%(D5+145+11`((D4(14M%2T4B12)%2T5+12)%0$!`0$!`0$!`0$!`
+M0$!`0$!`3DY.3DY.0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`3DY.0$!`0$!`
+M0$!`0$Y.3DY.3DY.3DY.3DY.0$!.0$!`0$!`0$!`3DY#0T-#0T-#0T-#0T-#
+M0T-#0TY.3DY#0T-#0T-#0T-#3DY.3DY.3DY.3DY#0T-#0T-.3DY.3DY.0$!.
+M3DY#3DY.3D!`0$!`3DY`0$!`3DY#0T-#0T-#0T-#0T-#0TY`0$Y.0T-.3DY`
+M0$!`0$!.3DY#0T-#0T-.0T-#3DX(0!P<#$9&1AQ.0T-#0T-#0T-#0P5#3A%#
+M0P5#3D-#0T-#0T,%0$,%0T-#!4,%$2((14L(2P@B2P@("`A+(DM+2PA+"$L(
+M"`@("`A+"")+(@@B"`@("`@("$4B2TM%(B)%2T5+"`@((@@("`A+"$4(2R)%
+M"`@("`A+"`@("$4(2P@B"$4B(@A+14M+2T4B"$5+10@(2T4("`@((D5+12((
+M""((12)%$$4B144B12)%(D5+14M%2T4B12)%2T!`0$!`0$!`0$!`0$!`0$!`
+M0$!`0$!.3DY.3D!`0$!.0$Y.0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!.
+M3DY.3DY.3DY.3DY.3D-.3DY.3D!`0$!`0$!`0$!.3DY#0T-#0T-#3DY.3D-.
+M3DY.3DY#0T-#0T-#3D-.3DY.3DY.3DY`3DY.3DY.3DY`0$Y.3D!`0$Y#0T-.
+M3DY`0$!`0$Y.3DY.3DY.3DY#0T-#0T-#3DY`3DY`0$Y.3DY.0T-.0$!.0$Y.
+M0T-#0T-#0T-#3D-#0TY`'`Q&##H,#`PZ,4-#!4,%0T,%0T-#0T-#0T-#0T,1
+M0T-#!4-.0P5#0P4%0Q%#!2((2TL("`A+"$L(2P@("`A+"$L("$L(2TM+2TL(
+M2TL("")+"$M+"$L(2Q!+"`@(2P@(""(("`@(2P@("$L("$L((D4(2PA%2T4(
+M"$5+"$L("$5%"$4B10@("`A%"$5+12(B"$5+12)%2T5+12)%2T4B12)%(D4(
+M2T5+14M%(D4014M%2Q!%(D40"$4(14M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`
+M0$!.3DY.3D!`3DY.3D!`0$!`0$!`0$!`0$!.0$!`0$!`0$!`0$!`0$Y.3DY#
+M0T-.3D-#0T-#0TY.3DY.3D!`0$!`0$!`0$!.0T-#0T-#0T-.3D!.0$!`3DY.
+M3DY.0T-#0TY.3DY.3DY`0$!`0$!.3DY.3DY.3D!`0$!`3D-#0T-#0TY.3DY.
+M3DY.3D-#3D-.3DY.0$Y#0T-#3DY.3DY.3DY#0T-#3D-.3DY.3DY.3DY#0T-#
+M0$`10!P<'!Q.,3%&1D8,.CHZ##$<1@P<0T-#0T,10T-#0TY#0Q%.0T-#$4-#
+M!4-#0P5#0P4%(DM+(@@(2TM+(DL(2R)+2TL("$L(2TM+2TM+"`A+"$L(2P@B
+M"`A+"$L("$L(2TLB2TL(2TM+2PA+"`A+(DL((@A%(D5+"$M+2PA+"`@(10@(
+M12)%(@@B"$5+"$M%"`A+11`(14L(10@("$4B14M%12)%(@A%(D5+14M%(@A%
+M2R)%2T5+12)%"$5+"$4B""((0$!`0$!`0$!`0$!`0$!`0$!.3DY`0$!`0$!`
+M0$!`0$!`0$!`0$Y`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!.0T-#0T-.
+M0T-#0T-#0T-.3DY.0$!`0$!`0$!`0$Y.0T-#0T-.3DY.0$!`0$!`3DY#0TY.
+M3D-.0TY.3DY.3D!`0$Y.3DY#0T-#0TY.3D!`3D-#0T-#0T-#0TY#0T-.0T-#
+M0T-#0TY.3DY.3DY.0T-#3DY#3DY.3DY.3DY.3DY.0$Y.0T-#0T-#0SA&1C`Z
+M#`P,.@PQ1D8Q.CHZ.CHZ1C$Q,4,%0T-#3D!#0P5#0T-.0T-#$4-#0T,%0P5#
+M!05+2TL(2TL(2P@(2TM+(B((2PA+2TLB2PA+"$L(2R)+"$L(2TM+2R)+2TM+
+M2R)+2TL(2P@(2P@((D5+"$LB14L(2PA+2PA+""(("`@B10@B(DM+"$M%(@A%
+M2P@(12)%"`A+10@(14M%"")%(D4B12(B12)%"")%(D4((D5+12(((D4B12(B
+M14M%2TM%"!`((D5%2T!`0$!`0$!`0$!`3DY.0$!`0$Y.3DY`3D!`0$!`0$!`
+M0$!`0$!.0$Y.3D!.3D!`0$!`0$!`0$!`0$!.3DY`0$!`0$!.3D-#0T-#0T-#
+M0T-#0TY.3DY.0$Y`0$!`3DY.0T-#0T-#0T-.0$!`0$!.3DY.3DY.3DY#3DY.
+M3DY.0$Y`0$!`3DY.3DY#0T-#0TY.3D!`0$!.3DY.3DY.3D-#3D-#3D-#0T-.
+M3D!.0$!`3DY#3D!.3DY.3DY`3DY.3DY.0$Y#0TY`0$!`0P@X1D8P.@P,##H,
+M,49&,3HZ.CHZ.D8Q,3%.3D-#3DX13DY#0T-#!4,10T-#0P5#!05#$04(2P@(
+M2TL((B)+2TL(2TM+2TM+2R(B2TM+2TM+(B)+2TM+2TM+(DM+2TM+2TM+2PA+
+M(DM+(DM+(DM+2TLB2TM+"$M+(@A+2PA+14LB(@@B2T4(14M%(D4B"$M%(A!%
+M"$M%"$L((D4B(D4B12)%(D5+10A+2PA%(D4B12)%12)%12)%2T4B10@((D4(
+M"$LB144B"$5`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`3D!`0$!`0$!`0$!`
+M0$!`0$!`3DY.3DY.0$Y.0$!`0$!`3DY.3DY`0$!`0$!.3DY.0TY.3D!`3DY.
+M3D!.3DY.3DY.3DY.0T-#0T-#0T-.0T-.0$!`0$!`0$!.3DY.3DY`0$!`0$!`
+M3DY.3DY.3DY.3D-.3DY.3D!`3DY.3D!.3DY`0$!.3D-#0T-#0T-#0T-#3D!`
+M0$Y`0$Y`3D!.0$Y.3DY#3DY`0$!#0T-#0$!`0`@(.$9&,#H,#`PZ##%&1C$Z
+M.CHZ.CI&,3$Q0T-#0T-.0TY#!4,%0T-.0T,%0P5#$4,%!4M+2TLB(DM+2TM+
+M2TM+2TLB2TM+2TM+2TM+(DM+2TM+2TM+2TM+(DM+2TM+2TLB2TM+2TM+2TLB
+M2TLB2TLB"$L(2TL((@@B2T5+(B(((D5+2PA+2TM+(DM+2P@(2T5+""((2PA%
+M2T5+144B14L(2T5+12)%14M%(D4B12(B(D4B(B)%"")+144B10A%2T4(10@B
+M12(B3DY.0$Y.3D!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`
+M0$!`0$!`0$!`0$Y`0$!.3DY.3DY.3DY.3DY.3DY.3DY.0$!`0$!`0$!`0$!`
+M3DY.0$Y.3DY.3D-#0T-#3DY.3D!`0$!`0$!`0$Y.0$!`0$Y.3DY.3DY#0T-#
+M3DY#0TY.3DY.3DY.3D-#3DY.3DY.0$Y.0$!`3DY#0T-#0T-#0TY.0$!`0$Y`
+M0$!`0$!.0$Y#0T-#3DY.3DY#.!PQ,3$Q.CHZ,#HZ.SL[,#L[#`P,.CL[.SHZ
+M##$Z.D,%0TY#$4-#0T,%0T-#0Q%#0P5#0Q$%2TLB(DLB(DM+2TM+2TM+2R(B
+M2TM+2TM+(DLB(DM+2TM+2TM+(DM+2TM+(DM+2TM+2TM+2TM+2TM+2R(B2R(B
+M2TM+2TLB2R(B(B(B(DM+"$M+2P@((B(("$M%(D4B""((14M%(D5+"")%2T4B
+M"$M%"$5+12((12)%(D4012)%"$4B10A%"$M%"$4B12)+12)%(D4B"`@(14!`
+M0$!`0$Y.3D!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`
+M0$!`0$!`3DY.3DY.0T-#0T-#0T-#0T-#0TY.3D!`0$!`0$!`0$!`0$!`0$Y`
+M3D!`0$!.3DY`0$!.3DY.3D!`0$!`0$!`0$Y`3DY.3DY.3DY.3DY.3DY.0$!`
+M0$Y.3DY.3DY#0T-.3DY.3D-.0$!`0$!.3D-#0T-#0T-#3D!`3DY`0$!.3DY.
+M3DY#0T,1$1%`'$Y#.C`[.CHZ.CLP.SHP+CL[.SH[.CL[.CH[.SLZ.SHZ.RY#
+M3DY.0T-#0P5#0P5#!4-#!4,%!04B(DM+2TM+2TM+2TLB2TM+2R(B(B)+(DM+
+M2TM+2TM+2TM+2TM+(DM+2TLB(DM+2R)+2TM+2TM+2R)+2R)+2R(0(DM+(B(B
+M2TM+(B)+2TM+2TM+2R)+(B((2R(0(B(B(D5+""(B(D4B11!%(B(((D4B10@B
+M14M%$"(((D40"")%(DLB144B"$M%(@@((@A%(D4B14L("`@("`A`0$!`0$!`
+M0$!`3DY.3D!`0$!`0$!`0$!`0$!`0$!.3DY.0$!`0$!`0$!`0$!`0$!`0$!`
+M0$!`3DY.3DY.0T-#0T-#0T-#0T-#0TY.0$!`0$!`0$!`3DY.3DY.0$!`0$!`
+M0$!`3DY#3DY.3DY.0$!.0$!`0$!`0$!.3DY`0$!.3DY.3DY`0$!`0$!`0$!`
+M0$Y#0T-#3DY`3DY.0T-#3D!.3D-#0T-#0T-#3D!`0$Y.3DY`0$!`0$!`"$Y.
+M+BXN+CLN+CHZ.CHZ.CHL+CHZ,#L[.SLP.S`Z.CH[.SL[.SHZ.SLZ3DX%0T-#
+M$4-#!4-#0Q%#!4,%!05+2TM+2TM+2TM+2R(02TM+2TLB(B(B(B(0$")+2TM+
+M(DM+2TM+2TM+2TM+2TM+2TM+2TM+(B(B2R(B2TM+2R(B2TLB(B(B2TM+2TM+
+M2TM+(B)+2R(B2TLB2R(B2R)+2PA+(B)+"$LB(@@B(DM%(@@B12(B14M%(D5+
+M12)%2T4("`A%"$4B"$5+14M%2T40"$4B"`@("`@("`@(0$!`0$!`0$!`0$!`
+M0$!.3DY.3DY.3D!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`
+M0$!`0$!.3DY.3D-#0T-#0T-#0T-.0$!`0$!`0$!`3DY.3D!`3DY.3DY`3DY.
+M3DY.3DY.0$Y.3DY`0$!`0$!`0$Y.3DY.3D!`0$!`0$!`0$!`0$!`3DY.0T-#
+M0T-.3D!.3DY.3DY`0$!`3D-.0$Y.0TY.0$Y.3D-#.#@X'$8Z.RP*+#L[.RXN
+M+"P[.CH,#`P[.SLZ.C`[.CHZ.SHN.SH[+#HZ.BPZ+CHP.P5#0T,10T-#0T,%
+M3A%#0P4%!4LB2R(B2TM+2TM+2Q`B(B)+2TM+2TM+2R(0(A`B2TLB(DM+2TM+
+M2TM+2TM+2TM+2TM+2TM+(B(B(DM+(DM+2TM+2TM+(DM+2TM+2R(B(DM+2R(B
+M2R(B(B)+2TLB(B)+2TM+(DM+""(B12(((D4B2P@B11!%(DLB14L(12)%"`A+
+M"$4B12)%"$4B12)%(D5+"`@("`@("`@("`@("$Y`0$!`0$!`0$!`0$!`0$Y.
+M3DY.3DY#3DY`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!.3DY.3DY.
+M0$!.3DY.3DY#0TY.3D-#3DY`0$!`0$!`0$!`3DY.0$!`3DY#3DY.3DY.3DY`
+M0$!`0$!.3DY`3DY.0$!`0$!`0$!`0$!`0$Y.3DY#3D!`0$Y.3D-#0T-#0TY.
+M3DY.3D!`0$!.3DY.3DY.0$Y.3DY.3D-&,"XN+@PZ,"P*+"XN+BXN+"PL+@PZ
+M.CHZ.CL[.@PZ.CHZ.CLL,#LN.RPL+"PZ.RPL.PI#!4-#0T-#!1%#0P5#!04B
+M(DM+(B)+2R(B(DM+2R(B(B(B2TM+2TLB2R(B(B)+(DLB2TL12R)+2R)+2R)+
+M(B(12R(B(DM+(DLB(B(B(B)+(DM+2TM+2R(B2R(B(A`B(B)+2TM+2R(B(B(B
+M2R(B(B(B(B(B2Q`B2TLB(DLB2R(B14LB(B(B(D4(14M%(B(B2T4B"$4B"$4B
+M"$LB"")%(@@("`@("`@("`@("`@("`A#3DY.0$!`0$!`0$!`0$!`0$!`0$!`
+M3D!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$Y#0TY.3DY`0$!`
+M0$!`0$!`0$!`0$!`0$!`3DY.3D!.3DY`3D`10`@(0$!`.#@X.#@<'!P<'!P<
+M'!Q&,49&1D8Q,48Q,3%&,3$Q,0PQ##$,,3$Q,0PQ,3$Q##$Q,3$Q1C$,,3$Q
+M,3$Q,3$,##$Q,3$Q,3$,#`P,,3$Q,3$Q,3$Q,3H,.CHQ,0PQ,3%&1D9&1C$Q
+M,3$Q,3$Q,3$<.SLL,"PL.CHZ.SLL+`H*0T-#!4-#$4-#$05#!2(B(B(B(A`B
+M2R)+2TM+2TM+2R(B(B)+(B(B2TM+(DLB2TM+(B)+2TLB2TM+(B)+(DM+2TLB
+M2TLB2TM+(DLB2R)+(DLB2R)+2R(B2TM+(B(B2TLB(DM+2TM+(A`0(DLB$")+
+M(B(0(A`B2R(02R)+(B(B(B(((D4B(B(B(A`B"!!%2T4(""(("$M%(D5%(D4(
+M"`@("`@("`@("`@("`@("`@(0TY.3D!`0$!`3D!`0$!`3DY.3D!`0$!`0$!`
+M0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$Y.0T-.0$!`,#`P,#HN
+M"CI&##H[.SM&1D8Q,3$Q,3$Q,3%&,48Q,3$Q,3$Q1C%&,3%&1D8Q1C$Q,3$Q
+M,3$Q,48Q,48Z,3$Q,3$Q##$,#`PQ,3$,,0PQ,3$Q,3$Q,3$Q,0PQ,3$Q,3$,
+M,3$Q,3$Q,3$Q#`P,#`PQ,3$Q,0PQ,3$Q#`P,,48Q,3$Q,3$Q,3%&,3$,,3$Q
+M,3$Q'#L[.RPL.RPL+"P*"@H*"D-.$4-#$4-#!4,%(DM+2TM+2R(B(DM+2TM+
+M(B(B(B(B2R)+(DM+2TM+2R(B2TLB(B(B2TLB(DM+(DLB2TM+2R)+2R(B(DLB
+M2R)+(B)+(B(B(B)+2R)+(B)+(B)+2TLB2R)+2R(B$"(B(B(B(B)+(B(B(B)+
+M(B(B(DLB(DM+(B)+(B)+(B((2P@B"$M%2T5+"$M%2T402R)%(@@("`@(.`@(
+M"`@("`@("`@("`@("$-#0TY`0$!`0$!`0$!`0$!`0$!.3DY`0$!`0$!`0$!.
+M0$!`0$!`0$Y.3D!`0$!`0$!`0$!`3D!`0$!`0$!`0$!`0`HL+"P*+`H[.SLL
+M+"PL1D8Q1@Q&,49&1C$Q,3$Q1D8Q,3%&,48Q,48Q,3$Q,3$Q,48Q,49&1C$Q
+M,3$Q1C$,#`P,,3$Q,0P,,3$Q#`PQ#`P,##$Q,3$Q,3$,,3$,#`PQ,3HQ,3$Q
+M,3$Q,3$,#`PQ,3$Q,3$Q,0PQ,3HQ,3$Q,3$Q#`PQ,3$Q,48Q1@P,#`P,#!PP
+M+BP*"@H*"@H*"@H*+`H%0T,%0T,1!2)+2TM+(B(B(B)+2TM+2R(B2R(B(B)+
+M(DLB$!`B(B(B(DL12R(B(B)+2TLB2R)+(DLB(B(B(B)+(DLB2R(B(B(B2R)+
+M(B)+(B(B2TM+(DM+(DLB(B)+2R(B(B(B(B(B(DM+2R(B(B)+2R(B2R)+(B(B
+M(A!+2R)+2TLB2TM+2TM+2P@B(DL($")%(D4B10A%"`@("`@("`@("`@("`@(
+M"`@("`@((D5`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!.3D-#0TY.
+M3DY.3DY.3DY`0$!`0$!`0$!`0$!`0$!`0$!`0`HL"@H*+`HL,#H[+#L[.S%&
+M,48Q,3$Q,3$Q,0PQ,3$Q,3$Q,3$Q1C$Q1C$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q
+M,3$Q,3$Q,3$Q,3HZ.@P,,0PQ.@PQ,3$Q,3$Q.C$Q,3$Q,0P,,3$Q,3$Q,0PQ
+M#`P,##H,#`P,,3$Q##$,#`PQ,3$Q,0P,,3$Q,3%&,48,#`P,#`P<,"XL"@H*
+M"@H*"@H*"BP*0T,%0T,%(B(B(B)+(DM+2R)+2TM+2R(B$"(B(B(B(B)+(B(B
+M(B)+(B)+2TLB(DM+(DLB(B(B2R(0(A`0(DM+2TLB2TM+(B(B2R(B$"(0(B(B
+M(B(B2R)+(A`B2TM+(B)+2R(B(B)+(B)+(B(B(DLB(B(0(B(B(B(B(B(B$"(B
+M2R)+(@A+""((2T4B"$M%(@A+12)%"`@("`@("`@("`@("`@("`@("`@("`@(
+M"`@(0$!`0$!`0$!`0$!`0$!`0$Y`0$!`0$!`0$!`3D!`0$Y.3DY.3DY.3DY.
+M0TY.3DY.3DY`0$!`0$!`0$!.3D!`3D`*"BPL+`HK+"XP.SLP,#`,1C%&#`PQ
+M,3$Q#`PQ,3$Q,0P,##$,,3$,,3$Q,3%&,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q
+M,3$Q,0P,#`PQ,3$Z,3H,#`P,,3$Q##HQ#`P,##$,,3$Q,3$Q,3$Q,3H,#`P,
+M.CHZ.@P,.C$Z##HZ,3$Q,3$,##$Q,3$Q1C%&#`P,#`P,'#`N+`H*"@H*"@H*
+M"@HL"@5#!04B(A`B2R(B$"(B2R(B(DLB(B(B2R(B(B(B(B)+(DL12TLB(DLB
+M(B(B(DLB(B(B2Q%+2Q$B(B(B(B(B(B(B(B(B(B(B(B(B(B(0(B(B$`4B(DLB
+M(B(B(DLB(DLB(B(B2TLB(DLB2R)+(DM+2R(B(DL0(B)+2R(B2TM+(B)+2R)+
+M2TM+(B(B(B(0(D5+10@("`@("`@("`@("`@("`@("`@("`@("`@("`A%2T!`
+M0$!`0$!`0$Y.3DY.3DY.0$!`0$Y.3DY.0$!`3DY.3DY.3DY.3DY`3DY.3DY.
+M3DY.3DY.3DY.3DY#0T-.3D-#+`H*"@H*"BP[,"P[+BXN.T8Q1@P,,3$Q,0P,
+M##$Q,3$Q,3$,,3$,#`PQ,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q##$Q,3$,
+M#`P,,0P,.@PQ.@P,##$Q#`P,#`PQ,3$,##$,,0PQ#`P,##$Z#`PZ##$Q,0P,
+M##HZ.CH,##$,#`P,#$8Q,3$Q##$Q,3$Q#`P,#`,P+`HK"@HL+"P*"@H*"BQ#
+M!4M+(B(B2TLB$")+(B(B(B)+2R(B2TLB(B(B(DM+(B(B2R)+(B)+2R(B(DLB
+M(B(B2R(B$2(B2R(B(B(0(B(B!1`B(B(B(B(B(DLB(B(B$")+(DLB(B)+(B(B
+M2R(B2R(B(B)+(B(B(DLB(B(B(B(B(B(B(B(B2TLB2TLB2TLB(DM+(B((2Q!+
+M14LB2T5+10@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`A`0$Y.3DY.
+M3DY.0$!`3DY.3DY.0$!`0$!`0$!.3DY.3DY`3DY.0T-#3DY.0$Y.3DY.3DY.
+M3DY#0T-.3DY.3DY`0"P*"@H*"@HL.S`L.RXN+CM&,48,##$Q,3$,#`PQ,3$Q
+M,3$Q##$Q#`P,,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q,0PQ,3$Q#`P,##$,
+M##H,,3H,#`PQ,0P,#`P,,3$Q#`PQ##$,,0P,#`PQ.@P,.@PQ,3$,#`PZ.CHZ
+M#`PQ,3$Q#`P,,0P,##$Q,3$,#`PQ,3%8#"PK"@HL"@H*"@H*"@HL2TLB(DLB
+M(B(B(B(B2R(B(B(B(B(B2R(B(DLB(B(B(B(B2R(B(B(B(B(B2R(B(B(B(B(B
+M2R)+(B(B(DLB(DLB(A`B(DLB(DL1(A`%(B(B(B(B(DLB(DLB(DLB2TLB2R(B
+M$")+(B(B(B(B2TM+$"(B2R(B2TM+2TM+2TLB(DM+2R(B(B(B(A`B(B(0"$4B
+M"`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@(0$!`0$!`0$Y.3DY.
+M3DY`0$!`0$!`0$!`0$!`0$!`3DY.0$Y`3DY`0$!.0$Y`0$!`0$!.3DY#3D-.
+M3DY.3DY.3D,L"@H*"@H*+#LP+#LN+BX[1C%&#`PQ,3$Q#`P,,3$Q,3$Q,0PQ
+M,0P,##$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$,,3$Q,0P,#`PQ#`PZ##$Z
+M#`P,,3$,#`P,##$Q,0P,,0PQ##$,#`P,,3H,##H,,3$Q#`P,.CHZ.@P,.C$,
+M,0P,.@PZ.CH,#`PQ#`P,#`P,!@P*"@H*"@H*"@HK"CLN+"(0(B(B(A`B(B(0
+M$$LB2R(B(B)+2Q%+(B)+(B(B2R(B(B(B(B(B(B(B(@4B(B(B(B(B(B(B(B(B
+M(B(B(DL1(B(B(B(B(B(B$"(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B
+M(B(B(B(B(B(B(DLB2R)+2TM+2TLB(B)+(DM+(B(B(B(B"!`("`@("`@("`@(
+M"`@("`@("`@("`@("`@("`@("`@("`@(2P@("$Y.3DY.0$!`0$!`0$Y.3DY.
+M3DY`0$!`0$!`0$!`0$!`0$!`0$!`0$Y`0$!`0$!`0$!`0$!`0$!.3DY.3D!`
+M0$-."@H*"@HK"BP[+BPN"@H*+D8Q,3$Q,3$Q,3$Q1C$,##$Q,3$Q#`PQ,3$,
+M#`P,,3$Q,3$Q,3$Q,3$,,3$Q##$Q,3$Q,0PQ,3$,#`P,#`P,,0P,,0P,##$,
+M.C$Q##$Q,3$,##$Q#`PQ,3$Q,0PZ.@P,#`P,##HZ.@PZ##H,#`P,#`PZ#`P,
+M,3$Q#`PQ.@P,##$Q,0,Q+`H*+`H*"@HK*RPL+`HB(B)+(B(0(B(B(B(B(B)+
+M(A`B(B(B(B(B(A%+$4LB$`4B(B(B(B(B$2(0!2(B(B(B(B(B(A$B(B(B(B(B
+M(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B)+(B(B(B(B$"(B(B(B
+M2R(B2TM+(DM+(DLB2R(B2TM+(B)+(A`B(B(B2R(("`@("`@("`@("`@("`@(
+M"`@("`@("`@("`@("`@(2P@("`@("`A`3DY.3DY#3DY.3DY`0$!`0$!.3DY#
+M0$Y.3DY#0T-#3D!`0$!`0$!`0$!`3DY.0$!`0$!`0$!`0$!`0$!`0$!#3@H*
+M"@H*"BP[.RPL*PH*"BM&,0PQ,3%&1D8Q,3$Q,0PQ,3$Q,3$Q,3$Q##$Q,0P,
+M##$Q,3$Q,3$Q,3$Q,3$,,3$Q,0P,,3$,##HZ.C$,#`P,#`PQ,3$Z,3H,,3H,
+M#`P,#`P,,3$Q#`P,##$,.@PZ##H,#`PZ.CH,##HZ.CHQ#`PQ#`P,,0P,#`P,
+M##$,,0P,#`P#,3H*"@H**RLK*PHN+@H*(DM+2TLB(B)+(B(B2R(B(B(B(B(B
+M(B(B(B(B(A$B(B(B(B(B(B(B(B(B$2(1(B(B(B(%(B(B(B(B(B(B(B(B!2(B
+M!1`B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(A`%$"(B(B(B(DLB2R(B
+M(B(B(B(B2R(B(B(B2R(B(A!+2R(B2P@("`@("`@("`@("`@("$4B"`@("`@(
+M"`@("`@("`@("`@(14M%(D4(0$!`0$!`3DY.3DY.0T-#0TY#3DY#0T-.0T!`
+M0$Y.0T-#0T-#0TY`0$!`0$!`0$!.3D!`0$!.0$!`0$!`0$!`0$`K"BLK*PHN
+M.SLL"@HK*RL*1C$Q##%&,3$Q,48Q,48,,0P,#`P,#`P,##$,#`P,##H,##$Q
+M#`P,,0PQ,0PQ##$Q,0PQ##$Q.C$Z.CH,##HZ##H,.CHZ##$,,0PZ##$Q,3HZ
+M#`P,#`PQ,3$,#`P,.CHZ#`P,#`P,#`P,.CHZ#`PQ##H,#`PZ.CHZ#`P,,3$,
+M#`P,6`P,+"LK*RLK*RLL"BL*+"(B(B(B(B(0!1`B(B(B(B(B(B(B(B(B(B(B
+M(A$B(B(1(B(B$2(B(B(B(B(B(B(B!040$2(B(A$B(B(B(A$B(B(B(B(B(B(B
+M(B(1(B(B(B(B(B(B(B(B(B(0!1`B*B(B(B(B(DLB(DL12R)+(DLB(DLB(B(B
+M2R(B(B(B2R(B(B(B2P@("`@("`@("`@("`@("`@(2P@("`@("`@("`@B10@(
+M"`@("`@("`@("`@("$!`3DY.3DY`0$!`0$!`0$!`0$!.0$Y`3DY.3D!`0$!`
+M0$!.0T-#0T-.0$!`0$!`0$Y.3DY#3D-.3D-#0T-.3DY`"@HL+"P**RPN,#L[
+M,#`P#$8Q1@P,,3$Q,0P,,3$Q,3$,#`PQ##$Q##$Q,3$Q1C$Q,3$Q,3$Q,3$Q
+M,3$Q,3$Q,3$Q,3$Q,3$,#`P,,3$Q.C$Z#`P,##$Q,0PZ,0P,#`PQ##$Q,3$Q
+M,3$Q,3$Z#`P,##HZ.CH,##HQ.@PZ.CHZ.@P,.CHZ.CHZ.CHZ,3$,,0P,#!P*
+M.CLK2"LK*RLK"@H*"@H%(B(B(B(0!2(B!2(B(B(B(B(1(B(B(B(%(A$B(@4B
+M(B(B(B(B(B(1(B(1(B(B(B(B(B(B(B(1(B(B!2(B(B(B(@40!2(B!2(B(B(B
+M(B(B(B(B(B(B(B(B(B(B(B)+(B(12Q%+$4LB(DL12R(B2R(B(DM+(DLB(A`B
+M2R(02TL(.`@("`@("`@("`@("`A%2P@("`@("`@("`@("`@("$L("`@("`@(
+M"`@("`@("`A`0$!`0$!`0$!`0$Y`0$!`0$!`0$!`0$!`0$!`0$Y`0$!`0$Y`
+M0$!`0$Y#0T-#0TY#3D!`0$!`0$X13DY.3DY#0RP*"@H*"@HL.S`L.RXN+CM&
+M,48,##$Q,3$,#`PQ,3$Q,3$Q##$Q#`P,,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q
+M,3$Q,0PQ,3$Q#`P,##$,##H,,3H,#`PQ,0P,#`P,,3$Q#`PQ##$,,0P,#`PQ
+M.@P,.@PQ,3$,#`PZ.CHZ#`P,.CHZ.CHZ#`P,#`P,.CH,,0P,#`P`*RPP"BLK
+M*RLK+`H**PHL$`4B(B(B(BHB(A`J(B(B(B(B(B(B(A$B(B(B(A`B(B(B(B(B
+M(@4B(B(%(@4%(@4B!2(%(B(%(B(%(B(B!2(B!2(%!2(B(B(B(B(1(@4B(B(%
+M(B(B(A$B(B(B(DL1(A%+$4L12R(B2R(B2P4B(DLB2R(B(DLB(B(B(B(B"`@(
+M"`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@B10A%"`@(
+M"`@(3DY#0T-#0T-.3DY`0$Y.0$!`0$!`0$!`0$Y.3DY`0$Y`0$Y.3D-#0T-#
+M3DY`3DY.0$Y.3DY`0$!`0$!.0$!`0$`L"@H*"@H*+#LP+#LN+BX[1C%&#`PQ
+M,3$Q#`P,,3$Q,3$Q,0PQ,0P,##$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$,
+M,3$Q,0P,#`PQ#`PZ##$Z#`P,,3$,#`P,##$Q,0P,,0PQ##$,#`P,,3H,##H,
+M,3$Q#`P,.CHZ.@P,##HZ.CHZ.@P,#`P,##HZ##$,#`P,`"LL,`HK*RLK*RP*
+M"BL*+!`B(A`%$"(0(B(B(B(B$2(B(B(1(B(B(B(%!2(%(@4B!2(B!04B(@4B
+M(B(B(B(B(B(%(A$B(B(1(@4B!2(%(A$B(B(B!2(%(@4B*B(B(B(B(B(1(B(1
+M(A$B$2(1(B(B(B(B2R(1(B(B(B)+2R(B2R(B(A`B(DM+2P@("`@("`@("`@(
+M"`@("`@("`@("`@("`@("`@("`@("`@("`@("$M%2P@(""(("`@("`@("$-#
+M0T,%0P5#0T-#0T-`3DY`3DY`0$!`0$!`0$!`0$!.0T-#3DY`0$!`0$!`$4!.
+M0T-#0$Y`0$!`0$!.0$!.3DY#+`H*"@H*"BP[,"P[+BXN.T8Q1@P,,3$Q,0P,
+M##$Q,3$Q,3$,,3$,#`PQ,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q,3$Q##$Q,3$,
+M#`P,,0P,.@PQ.@P,##$Q#`P,#`PQ,3$,##$,,0PQ#`P,##$Z#`PZ##$Q,0P,
+M##HZ.CH,#`PZ.CHZ.CH,#`P,#`PZ.@PQ#`P,#``K+#`**RLK*RLL"@HK"BPB
+M(B(%$`4B!2(B(@4B!2(B(B(B(@4B$2(%$`4B!2(J!04B(B(%(@4B(@4B(@4B
+M(B(%$`4B(@4B(B(B(B(B(B(B!2HB!2(1$2(%(@4B(A$B(@412Q%+$4L1(A$B
+M(B(1(A$B$2(B(B)+(B(B(B(B(B(0(B(B(B(("`@(2T4("`@("`@("`@("`@(
+M"`@("`@("$L("`@("`@("$4("`@((D4("`@B10@("`@("`@("`A.3D-.3D!`
+M0$`13DY`$4-#3DY`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$Y.
+M0$Y`0$Y`0$Y.0T-#3@H*"@H**PHL.RXL+@H*"BY&,3$Q,3$Q,3$Q,48Q#`PQ
+M,3$Q,0P,,3$Q#`P,##$Q,3$Q,3$Q,3$Q##$Q,0PQ,3$Q,3$,,3$Q#`P,#`P,
+M##$,##$,#`PQ##HQ,0PQ,3$Q#`PQ,0P,,3$Q,3$,.CH,#`P,#`PZ.CH,.@PZ
+M#`P,#`P,.CHF.CHZ.CHZ)CHZ.@P,#`P#2"LL.RLK+"PL+`H*+`HN(@4B(B(%
+M(B(B!2(B(@4B(B(%!2(B(B(B!2(B!1`%(B(B(@4B(B(B(@4%(@4%(@4%!2(B
+M(@4B!04B!04%(@4%*B(%(B(B(BHB(B(%(A$B$1$B(A$B$1$1(A$B$2(B$2(B
+M$2(B(B(B$2(B$"(B(B(B(B(("`@("`@("`@("`@("`@("`@("`@("`@("`@(
+M"`@("`@("`@("`A+"`@("`@("`@("`@("`@("`@(2P@(0$!.3D!`0$!`0$!`
+M0$!.0$!`0$!`0$!`0!%.0T-.0$!`0$!`0$!`0$!`0$Y`0$!`0$Y.3DY.3DY.
+M0$Y.3D-.0TX*"@H*"@HL.SLL+"L*"@HK1C$,,3$Q1D9&,3$Q,3$,,3$Q,3$Q
+M,3$Q,0PQ,3$,#`PQ,3$Q,3$Q,3$Q,3$Q##$Q,3$,##$Q#`PZ.CHQ#`P,#`P,
+M,3$Q.C$Z##$Z#`P,#`P,##$Q,0P,#`PQ##H,.@PZ#`P,.CHZ#`PZ.CHZ.CH,
+M##$,#`PZ.CHZ#`P,.CHZ.CHZ'$@K"C`L+"PL+`H*"BP*"B(B(@4B(B(%(B(B
+M!040!04B(B(B!2(B$2(B$04B!04B!2(%(@4%(BH1!2(%(@4B!2(%!04B$04B
+M!2(%(@4B!2(%(@4B!2(B$1$12Q$1(@4B!1$1(A$B$2(B$4L1(B(1(B(B(B(B
+M(B(B(B(B$$LB"`@("`@("`@("`@("`@("$L("`@("`@("`@("`@("$L("`@(
+M"`@("`@("$M%"`@("$M%(D4("$5+14M%"`@("$-#0$!`0$!`0$!`0$!`0$!`
+M3A%#0TY.3D!`0$!`0$!`0$Y.0$!`0$!`0$!`0$!.0$!.0$!`0$!`0$!`0$!`
+M0$!`*PHK*RL*+CL[+`H**RLK"D8Q,0PQ1C$Q,3%&,3%&##$,#`P,#`P,#`PQ
+M#`P,#`PZ#`PQ,0P,##$,,3$,,0PQ,3$,,0PQ,3HQ.CHZ#`PZ.@PZ##HZ.@PQ
+M##$,.@PQ,3$Z.@P,#`P,,3$Q#`P,##HZ.@P,#`P,#`P,##HZ.CHZ,0P,#`P,
+M#`P,#`P,#`P,##HZ.@,K2"LL,#L*"@H*"BP*2"PB!2(%(@4B(A$B!2(B!2(B
+M!2(%(@4%!04B(@4%(@4B!2(%(@4%(@4%!2(%!04B!04%(@4B!2(B!2(%(A$B
+M!04B$041!1$1(A$B$041(B(B(B(1(A$B$1$B!2(1!2(B(B(B(B(B(B(B(DLB
+M(@@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@(
+M"`@((D4("`@("`@("$L("`@(2T5+"$M#0T-#3DY.0$!.3D!`0$!.3D!`0$!`
+M0$!`0$!`0$!`0!%.$4-#!4-#0T-.0$!`0$!`0$!`0$!`0$!`0$!.0$!`0`HK
+M+"PL+"XN.RPK"BLK*PI&,48Q,4HQ,3$Q,3$Q,3$,#`P,,3$Q.CHZ,0P,##$Q
+M,3$Q.C$Q,3$,,0PQ,0P,#`P,,3$,,0PZ.C$Q,0PQ##H,.@PQ,3$,#`P,,3HP
+M#`P,#`P,#`P,,28F)CHZ.@P,.@P,#`P,#`P,.CHZ#`P,)C`P.CHZ#`P,##H,
+M##$P.CHZ.CI'2#\K+#LZ+"PL*RL*"D@L!1`%(B(B!2(%(B(%(@4%(@4%!04B
+M!2(%!04B!04%$`4B!2(B!2(B!2(1(B(B!1`%(@4B!2(%!2(1$1$1$1$1$1$B
+M$2(1$1$1$1$B!1$1(A$1(B(%$2(1(A$B(B(B(B(B(@40(B(B(B(("`@("`@(
+M"`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("$5+10@("`@("`@(
+M2P@("")+"`A%2PA+"`@B"")+0$!`3D-#0T-.0$!`0!%`0$!`0$!`$4Y`0$!`
+M0$!`0$!`0$!`0$!`0$Y#0T-#0T-#0T-`$4!`0$!.0$Y#0TX10$`K"BXN+CL[
+M+"PK"BLK*RLK1C$Q2C$Q,3$Q,3$Q,3$Q##$Q,3$Q,3$Q#`PZ.CHZ#`PZ,0PZ
+M,3$Q##$Q##$Q#`P,#`P,#`P,,0P,#`PZ#`P,.B8,,3$Q#`PZ#`PF#`P,##HZ
+M#`P,.@PZ.CH,.CHZ.CH,)B8F.CHZ##HZ.C`P,#H,#`P,#`P,#`P,##HZ#`P,
+M#`P,'$A(*RPP,#`P,"P*"BPK"DL1(B(1(A$B(B(%(@4B!2(B(B(B!2(%!2(1
+M(B(B!04%!2(%!041$1$1(@4%$1$1!1$1$1$1$1$1$041$1$B!1$1!2(1$1$1
+M!1$1(@41$04B$1$B(B(1!2(B$2(B(A$B!2(B(B(("`@("`@("`@("`@("`@(
+M"`@("`@("`@("`@("`@("`@(2T4B"`@("`@("$L("`@(2P@("")%"$L("`@(
+M"$M+2TL(2PA+"$L((DY`0$Y`0$!`0$!`0$!.0$Y.0$!`0$!`0$!`0$Y.3D!`
+M0$!`0$!`0$!`0$!`0$!`$4!.0$!`0$Y.$4Y.0$!`0$Y.3BX*"@H[.RXK"BLK
+M*RLK*T8Q,3$Q,3$Q,3$Q,3$Q.CHZ.CHZ,3$Q,0PQ,3$Q,3$Q.CH,.C$Q,3$,
+M#`P,#`P,#`P,#`P,##$,.CHZ.@P,.@P,.@P,#`PQ.@P,##HP,#`Z,`P,.@PZ
+M,#`P.C`Z.CHZ,`P,##HP,#HZ##H,#`P,#`P,.@PZ#`P,.@P,.CHZ.@P,#"$K
+M"BPL.SHZ.CHL*PH*"BQ`"$L1$0@1$1$1$04%$!$1$1$1$2(1$2(1!04%(B(1
+M$2(1$04B$1$1$1$1$1$1$1$1!1$1$1$1$1$1$1$1$1$1$041$1$B$2(B$1$1
+M(A$B$2(1!2(1(B(1(B(%(B(B(B(B"`@("`@("`@("`@("`@("`@("`@("`A%
+M2P@("`@("`@("`@B10@("`@("$L("`A+"`@((@@("$M+2TL((DM+2P@B(@A+
+M2TLB2TM+2TM%"$5%0`A`0$`10$!`0$!.3D!`0$Y`0$-#0$!.3D-#0T-.3DY.
+M0TY`0$!`3D!`0$!`0$Y`0$!`0$!`3DY.3DY.3DX[+BXN+"X**PHK*RLK*RM&
+M,3$Q,3$Q,3$Q,3$Q##$Q,3$Q,3HZ,3$Q#`P,##$Q,3HZ,0P,#`P,#`PQ#`P,
+M#`P,.@P,#`PZ#`P,##H,)CHZ.CH,#`P,.B8,#`P,)B8F.C`Z##H,,#`P,`PZ
+M,#HZ.CHZ.CHZ.CHZ##HZ.CHZ,`PZ#`PZ##HZ.@PZ#`P,.@PZ.CI%"@H*"BXL
+M+"PL"@HK2#]($0A`$0A`$1$1$0@1"$`1$1$1$0A`"!$1$4L1$4M`$4M`$1$1
+M$1$1$1$1$1$1$1$1$1$1$041$1$%$1$%!1$1$2(B$1$1$1$1$1$1!2(B!1$%
+M(A$B!1$B(@4B(B(B(@@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`A+
+M"`@("`A+12(("`A+(@A+"`@("`A+2TLB(DL(2PA+2TLB2TM+2TM+2TM+2TM+
+M2TM+145%145%145%108("$4(10A`$4!.0$Y`0$,%0T!`0$Y.3DY`0$Y`3DY.
+M3A%#3D!`0$!`0$!`0$!`0$`10$!`0$Y..BXN+BPL*PH*"@HK*RLK,3$Q,3$Q
+M,3$Q,3$Q##$Z##HZ.C$Q.@PQ,0PQ,3$,#`PQ#`P,,3$Q#`P,#`P,##HZ.CH,
+M.@P,##HZ.CHP##`,.CH,#`P,##HF#`P,.CHZ.C`F.CHZ##HZ.CHZ,#HP.CH,
+M.CHZ.CHP.C`Z)CHZ.CHP.@P,#`PZ.CHZ.@PZ.CHZ#`P,6`H*"@HL"DA(2`HK
+M+`HK"DL1$1$1$1$1$1%`"!$1$1$1$1$1$4!+$1%`"$!+$1$1$1$1$1$1$1$1
+M!1$1$1$1$1$%!1$1$04%$1$1$1$1$1$1!1$1$2(%(@4B(A$%!2(B!2(%(@4B
+M!2(B$0@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("$L("`@("$L(
+M2PA+2TL(2TM+"$M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2R(B(DM+2R)+(@9%
+M!D4&109%!@@&108(!D4&109%!D4&109%109%2TM.0TY`0$!`0$-#0$Y`0$!`
+M3D!#0T-#0TX10$!`0$Y`0$Y.0#HN+BXL+"L*"@H**RLK*S$Q,3$Q,3$Q,3$Q
+M,0PQ.@PZ.CHQ,3H,,3$,,3$Q#`P,,0P,##$Q,0P,#`P,#`PZ.CHZ##H,#`PZ
+M.CHZ,`PP##HZ#`P,#`PZ)@P,##HZ.CHP)CHZ.@PZ.CHZ.C`Z,#HZ##HZ.CHZ
+M,#HP.B8Z.CHZ,#H,#`P,.CHZ.CH,.CHZ.@P,#%@*"@H*+`I(2$@**RP**PI+
+M$1$($1$1$1$1$1$12Q$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1
+M$1$1$041$1$1$1$1$1$%$04B!1$%!2(%$1$%(@4%(B(1!2(%!2(B(@@("`@(
+M"`@("`@("`@("`@("`@("`@("`@("`@(2P@("$L(2PA+"`A+"`@("$M+2TL(
+M2P@(2TM+2TLB(B(B(DM+2TM+2TM+2TM+2TM+2TM+2TM+2TLB(B)%145%109%
+M!D4&109%!D5%!D4&!D4&!D4&!D4&108&109%!D4&109%!D5%14!.3A%.3DY#
+M0TY`0$!.0$!`3DY`3DXZ+BXN+"PK"@H*"BLK*RLQ,3$Q,3$Q,3$Q,3$,,3H,
+M.CHZ,3$Z##$Q##$Q,0P,##$,#`PQ,3$,#`P,#`P,.CHZ.@PZ#`P,.CHZ.C`,
+M,`PZ.@P,#`P,.B8,#`PZ.CHZ,"8Z.CH,.CHZ.CHP.C`Z.@PZ.CHZ.C`Z,#HF
+M.CHZ.C`Z#`P,##HZ.CHZ##HZ.CH,#`Q8"@H*"BP*2$A("BLL"BL*0`@10`A`
+M"!$1$1$1$4`($1$1$1$%$1$1$1$1$1$1$1$1!1$1$4`1$1$1$1$%$1$1$1$1
+M!041$04%$1$%$1$1(@4%$2(%(@4%!04%(B(%(B(%(B(("`A%2P@("`@("`@(
+M"`@("`A%"`@("`@("`@("$M+2P@(2TL(2PA+"$L(2PA+2R(B2TM+2TM+2TM+
+M2TM+2TM+2R)+2TM+(B)+2TM+2TLB2R(B2TM+2R(B$")+109%!D5%!D4&109%
+M109%!D5%145%145%145%!D5%144&144&145%145%145%145%109%!D4&109%
+M109%!D4&109`##`P,`H*"@HK"@I(2$@K,3$Q##$Q,3$Q,0PQ,0PQ,3HZ.@PZ
+M,0PZ#`P,#`P,,0P,.@PQ#`P,#`P,#`P,#`P,#`P,##H,.CHZ.CHF.CHP##H,
+M#`P,.C`,#`PZ.C`P,#HP##HZ,#HZ.CHZ.C`P.CHZ.CHZ,#`,,#HZ.C`P,`PP
+M,#HP##H,#`P,##HZ.CH,.CHZ1BL*"BPK2"LK*RLK"C`L"A$1$1$1$1%+0!$1
+M$1%+$4`1$1$1$1$1$1%.$1$1$1$1!1$1$1$1$1$1$04%!1$%$1$%!1$1$04%
+M$041!1$%!04%(@4%(@4B(B(%(@4%!04("`@("`@("$4("`@("`@("`@("`@(
+M2T5+2TM+"$L(2PA+"$LB(DM+"$M+2TM+2TM+2TM+(B)+2TM+2TM+2R(B2R(B
+M2TM+2TM+2TM+2TM+2TM+(B(B(B(B2TM+2R(0(D4&109%!D4&109%!@9%!@9%
+M!D4&109%!D4&145%145%145%145%145%145%145%145%145%145%145%!D4&
+M109%1DHF)B8P*PHK"@HK*RLK2#$,#`PQ,3$Q,3$,,3HQ,3$Q,3$Z,3$,#`P,
+M,3$Q#`P,,0PP#`P,#`P,#`P,.CHZ.CHZ.CH,#`PZ.CHZ.@P,,`PP##`P,`PF
+M#`PZ.C`P,#`P#`PZ#"8Z#`P,.C`P,#HZ,#HZ.CHP,#`Z,#`P,#`P.CHZ,#HP
+M,#`P,`PZ.CH,.CHZ.D8*"BPK*RLK*RL**T@[##H1$1%+$1$1$1$1$1$10$L1
+M$1$1$4`%!1$1$1$1$4`%!1$1$1$1$041!1$1$1$1$1$1$1$%!1$%!04%(@4%
+M!04B!04B!04%!04%(@4B"`@("`@("`@(2PA+"`A+"`@("$M+"`A+(B)+(DL(
+M2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+(B)+(DM+2TM+2TM+2TLB2R(B(B)+
+M$4M+2R(B(B)+2Q%+2TM+(B(B2R(B(B)%!D4&109%!D4&145%145%145%145%
+M145%145%145%145%145%145%!D4&109%!D5%!D4&!D4&!D4&!D4&109%!@Q&
+M,3$Q.@H**RL**RLK*T@,,0PQ,3$Q,3$Q##$Z,0P,,3$Q##$Q##$,#`P,#`P,
+M,0PZ#`P,#`P,#`PZ.@PZ.CHZ.CHZ.@P,)CHZ.CHP.B8Z,`PZ.CHZ,`P,##`P
+M#`P,.@PZ#"8,##HZ.CHP,#`P,#HZ.CHZ.C`P,#HP.SL[.CHP.S`P)CHZ.C`P
+M##H,.@PZ.CH`"@HL"@H**RLK*PH*+CHQ$1$10!$1$1$1$1$1$1$1$1$1$1$1
+M$1$1$1$1$1$1$1$%$1$1$1$1$04%$041!04%$04%$04%$04B!04%(@4B!2(%
+M!2(%(@4B"`@("`A+10A+"`A+"`@(14L("$L(2TL(2TM+"$LB2TM+2TM+2TM+
+M2TM+2TM+(DM+2TM+(DM+2TM+2R(B2TM+(B)+(DM+2R(B$4LB(B(B(DLB(B)+
+M2R(1(B(B(DL1(B)+(B(B(B(B145%145%145%145%145%145%145%145%!D4&
+M109%109%109%109%!D4&109%!D4&109%145%145%145%145%144P,4I*2CHN
+M*RM(*RM(2$@K2@PQ#`P,,3$Q#`PQ.C$Q,0P,##$,##$Q#`PQ,3$,#`P,##H,
+M#`P,#`P,#`PZ.CHZ.@PZ##HZ.C`Z.CHZ,#`P.C`Z.CHZ.CH,.@PZ##HZ.@PZ
+M.@P[##HZ.CHZ.B8P.CHP#`P,)CHZ##`P.C`P,#`F,#LP)C`Z.CHP,#`Z,"8P
+M.CHZ1@H*"@HK*PH*"BL*"@HN+A$1$1$1$1$1$1%`2P4%$1$%$1$1$1$1$1$1
+M$041!1$1$04%!1$1$04%!1$%!1$1!1$1$04%!1$1!04%(@4%(@4B!2(012I%
+M144("`@("`@("$L(2PA+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2R)+
+M2TM+2TLB2TLB2TM+2TLB(B(B2TL12TL12R(B2R)+$4LB(B(B2R)+$2(B2Q%+
+M(B)+2TM+(B(B(@4B$$5%145%145%145%145%!D4&108&109%!D4&144&109%
+M!D4&109%145%145%145%145%145%145%145%144&109%+@Q&1D8,,"Q(*TA(
+M*RLK2#HQ##$Q,0P,##$Q,0PQ,0P,#`PQ#`P,,0P,#`P,##$,)B8,.CHZ.@P,
+M##H,##H,#`P,.CHZ#`P,.CHZ.C`P)@PP.CHZ.CHZ.@PZ##HZ.CHZ#`PZ)CH,
+M.CHZ##H,,#LP,#HZ.CHZ##HP,"8Z.CHF,"8P.S`P)B8F,#`P,#`P,#`P,``L
+M"BLK*RLK*RLK*PH**RP1$1$1$1$1$1$1$1%`$1$10!$1$1$1$1$1$04%!1$1
+M$04%!1$1!1$%!04%$041!04%$041!041(@4%(@4B!05%12HB11`B$$4J(B(B
+M(DL((B)+"$M+2TM+2TM+2TM+2TM+2TM+(B)+2TM+(DM+2TM+(DL12TLB2TL1
+M2Q%+2TLB(DLB2TLB2TLB2TLB2R)+(B)+(B(B2R(B(B(B(B(B(B)+(B)+(B(B
+M(B(%(B(B(B)%145%144&109%!D4&144&145%144&144&109%145%145%145%
+M145%145%145%145%144&144&144&109%109%!BXN,3$Q2CH[*RM(*TA(2$@Z
+M#`P,,3$Q,3$,,3H,#`P,#`P,##$,#`P,##HZ.@P,.C$F)C`Z.CHF)B8,##HZ
+M.CHZ.@P,#`PZ,#`P,`PF,#HP.@PZ.CH,,"8Z##HZ.CHZ.@PZ##`Z.CHZ.CHZ
+M.CHP.S`P,#`,.CHZ,#`Z.CHZ,"8Z)B8F,#L[.S`P,"8P,#`P,#`Q"BLK*RM(
+M*RLK*RL**S\*!A$1$1$1$1$1$1$1$1$1$1$1$1$1$1%.$1$1$04%!1$1$04%
+M$1$1!1$%$04%!04%!1$%!2H1!041!05%*D4B*D5%12I%$!!%(D4012)+"`A+
+M"$M+2TM+2R)+2TM+2TM+2TM+2TM+2TL12TM+2TL1(B)+2TL12R(B2TM+$4LB
+M2TLB(B)+(B(B(B(B(B)+$2(B(B(B(B)+(B(B(B(B2Q$B$2(B(B(B(@4B(B(B
+M!2(B145%!D4&145%!D5%109%109%!D4&145%145%145%145%145%145%145%
+M144&109%!D4&109%!D4&109%109%144L+"8F)@PQ.@HK2$A(2$@K##$,##$Q
+M#`P,##HZ.C$,##$Q,0P,#`P,.@P,#`P,.@P,#"8Z#`P,##HZ.B8,#`P,#`P,
+M##HZ)C`P,#`P.CHP,#HZ.CHZ.CHP)CHZ.CHZ.CHZ)CHZ.CHZ.CHZ.CHP,#`P
+M.SL[.CHZ.CHP,"8F)B8F)CHF,#LP,#`[.SLF.B8F,#`P`"LK*RM(2"LK*RM(
+M*RL_*P8%$041$1%.$1$1$1$1!04%$1$1$1$1!1$1$04%!041!1$1!1$%$04%
+M!04%!04%!04%!04J(A!%*A`0(A`012)%*B)%(A`B*D4J$"(0(DLB2TM+2TM+
+M2TM+(DM+2R(B(DM+2R(B(B)+2R(B(DL12TLB(DL12R)+2TL12R)+(B(B(B(B
+M(B(B$4LB(B(B(BHB(B(B(B(B(@4B(B(B(B(B(B(B(B(B(@4B(B(B(B(J(D5%
+M145%145%145%145%145%145%144&109%145%144&144&144&145%145%145%
+M145%145%145%145%!D5%!D5%+"PL+"P[)CHP"BLK*RLK*S`Q,3$Q,3HZ.@PZ
+M)CH,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`PZ#`P,.CHZ.CHP#`P,,#`P
+M)B8F.CHP.C`,)CHZ.CHP.CHZ.CHZ.CHZ.CHZ.CHZ.CHZ.CHZ,#HZ(SL[.R,Z
+M.CHP,#`P,#`Z,"8F)C`C.CHZ,"8P,"8P,#`P,#DK*RL**TA(2$@K*RL*/RL&
+M!1$1$1$1$1$1$1$1$1$1!04%!04%$1$1!1$1!1$%!1$%!1$%$041!1$%!04B
+M!04%(A`0$!`0$$40$!`0$!`J$"(0*D4J12(J(A`J12HB(B(B2TLB2R)+(DLB
+M2R(B2TL12TLB2Q%+(B)+(B(B2Q%+(DL1(B(B(B(12R(12R(B(B(B(B(B(B(B
+M(B(B(B(B(B(B(@4B$`4B!2(%(B(%(B(B(B(%(@4B(@4B(@40!2)%145%145%
+M145%109%!D5%145%!D5%145%145%145%145%145%145%145%145%!D5%145%
+M145%145%145%145%12PL+"PL.R8Z,`HK*RLK*RLP,3$Q,3$Z.CH,.B8Z#`P,
+M#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,.@P,##HZ.CHZ,`P,##`P,"8F)CHZ
+M,#HP#"8Z.CHZ,#HZ.CHZ.CHZ.CHZ.CHZ.CHZ.CHZ.C`Z.B,[.SLC.CHZ,#`P
+M,#`P.C`F)B8P(SHZ.C`F,#`F,#`P,#`Y*RLK"BM(2$A(*RLK"C\K!A$%$041
+M$041$04%!04%$1$%$041!1$%$1$%!1$1!04%!04%!1$1$04B(B(1`P,#`P9%
+M$!`0$!`0*A`0$!`B$$4J$!`0(BH0$"(J(BHB*D4J(BHB(B(B(A%+2Q%+(B(B
+M2R(B(B)+(DLB(B(B(B)+(DL1(B(B(A$B(B(B(B(B(B(B(B(B(B(B$2(B(B(B
+M(B(B!2(B(@4B(B(B(B(B(B(%(B(B(B(B*B(%(@4B!2(B145%145%109%109%
+M145%!D5%145%145%145%145%145%145%145%!D4&109%145%145%145%145%
+M145%144&108L+"PL+#LF.C`**RLK*RLK,#$Q,3$Q.CHZ##HF.@P,#`P,#`P,
+M#`P,#`P,#`P,#`P,#`P,#`P,##H,#`PZ.CHZ.C`,#`PP,#`F)B8Z.C`Z,`PF
+M.CHZ.C`Z.CHZ.CHZ.CHZ.CHZ.CHZ.CHZ.CHP.CHC.SL[(SHZ.C`P,#`P,#HP
+M)B8F,",Z.CHP)C`P)C`P,#`P.2LK*PHK2$A(2"LK*PH_*P81$1$%!04%$1$%
+M!04%$04%!1$1!041!04%!04%!041!1$B$04%2P,#`P,#`P,#`P,#`P8#`P,0
+M$!`A$!`0*A`J$!`J$"I%*D4J12HB$"(J(BI%*B(J(B(B2Q%+(B)+$2(B(B(B
+M(B(B2R(B(B(B(B(B$`4B$2(B!2(B(B(B(B(B(B(1(@4B(B(B!2(B(B(B!1`%
+M(B(B!04B!1`B!2(%(B(%*B(%(B(B*B(B*B(J$$5%145%145%145%144&144&
+M109%145%145%145%145%109%.44&145%145%145%145%145%145%144&145%
+M145%+"XL+"P[+"8,,"P*+"PL"CL,##H,,0P,##$Q,3HF,0P,#`P,#`P,#`P,
+M#`P,#`P,#`P,.@P,#`P,.@PZ##`P,#`F.CHZ#"8Z.CHZ##`P,#`Z)B8F)@P[
+M.B8Z.CHZ.CHZ.CHZ.CHZ.CHZ.CHZ.CHZ,#HZ.CLZ,#LP.SL[.SLP,"8F)CLZ
+M,#`P)CHP,#L[,#L[.R$**RLL*T@K*RLK*PH*2$@Y!04%$04%!1$1!04%!1$%
+M!1$%$1$%$1$%$1$%$0@B!5@#`P-8`P,#`P,#`P,#`P,#`P8#`P,&!@,#!@-%
+M*A`0$`40(BHB*B(J(BH0*B(J(BHJ(BH0*B(J(BHB2TLB(B(B(B(B(B(0(@4B
+M(B(B(A`%(@4B(B(B(DL1(B(B!2(B!2(B(B(B(@4B!2(%(BHB!2(%(@4B*B(B
+M(B(%!2(B(BH%(B(J(B)%*D5%*D4J11!%145%145%145%145%145%145%144&
+M145%145%145%145%145%145%!D5%145%145%145%109%109%144&145%12P*
+M"@H*+"PC##HL"@H*"@HP,3H,#"8Z.CH,.C$,)C`P)B8F.C$,#`P,#`P,#`P,
+M.CH,#`PZ.CH,.CH,.CHZ#`P,.C`P,#HP.CHZ.CH,.C`P.CHZ.CHZ.B8F,#HZ
+M.CHZ.CHF)B8Z.CHZ.B8Z.CHZ.C`Z.CHZ.SHP.S`[,#`P.SLP.CHP,#HZ.B8N
+M.S`Z,#LP,#``+@H**TA(2$A(*PI(*S\*!@4%$041!04%!1$%(@4%$04%!1%+
+M$4L(!@,#`P,#6`,#`P,#`P,#`P,#`P`#`P,#`P,#!@,#`P8&!@8#!@8#!E@#
+M!@80*B(J*A`J(A`J(BHB$"HB*B(J$"HB*BHJ(B)+(B(B!1`%!2(B!04B!2(B
+M(B(B(B(B*B(J(@4B(B(B(B(B!1`%!2(B*B(%(@4B*B(B*BHB(B(J(BHB(B(B
+M*D4J12I%12I%*D4J12I%*BH0145%145%109%!D5%145%145%!D5%145%145%
+M145%145%145%144&145%109%145%145%145%145%109%145%144*+"PL+"PL
+M+CHQ)BX*"@H*+$HZ.C$,)B8F##HZ)B8Z.CHZ.@P,)B8P#`PZ.CH,#`P,#`P,
+M.CHZ#`P,.@P,##HZ.@PZ##L,##HZ.CHZ.CHP)CHZ.CHZ.CH[,#HZ.CHZ.CHZ
+M)B8Z)CHZ.CHZ)C`P)C`[.SL[.S`[,#L[.SL[.SL[,#`P,#L[.SL[,#LF.CHN
+M,#`P&SLL"BLK*PH*"@HK*T@_*SD%!04%!04%*@4B!04%!2H%(@@<'$8<1AQ&
+M'!P#6`,#`P-8`P`#`P`#`P,#`P,#`P,#`P8#`SD#`P,#!@,Y!@,<6!P<(D4B
+M12(B12HJ*A`J*BHB*BHJ*B(J*B(J$"HB*@40!2(B(B)+(B(B(B(B(@4B(B(%
+M!2(B(B(B(B(B!2(B(BHB(A`B*@4J(B(0*BI%*D5%12I%*D5%10,#145%12I%
+M*BI%*D4J12I%*D5%(44&109%!D5%145%144&145%!D5%!D5%145%145%145%
+M145%145%145%145%145%145%145%145%145%145%145%+"PL+"PN+"PN(R8F
+M(R,C"@HQ.CHZ#`P,##HQ##$Z,#`Z.CH,##HF.CHZ#`P,)B8,.@P,##HZ.CHZ
+M.@PZ##H,#`PZ.@PP,#HZ.CHZ##HZ.C`,)CHZ.CHZ.S`Z.CHF)B8Z.B8F,"8Z
+M)B8F)C`P)CH[.SHZ.C`[.S`[.SL[.SLP,#`P.S`[.SL[,"XP,#HF)CL[.U@L
+M+BPL+`HK*RM(2$@_/S\&!44B$$4B(D4B$$4J12)%12(#1C$Q'$9&'$8#`P!8
+M`U@#`P,#`P,#`P,``P,#`P,#`P,#`P,Y`P8#`P8&`P8#6%A8`T4B12)%144B
+M1440145%*D5%144J12HJ!D5%12HJ*BHJ*B$J*BHJ(A`J(BHB$"HJ(B(J(BHJ
+M(BHJ*BHB*D5%!@,&`T4B12I%145%*D5%145%145%108<'$8<'`9%!D5%*BI%
+M*D4J12HJ*A```P`#``,#`P`#`P,#`P`#`P,#`P,#`P,#`P,``P`#`SD#`P,Y
+M`P8#.0,Y`P,#`#D#!@`#!CD&!@8Y.3DY.08Y.0HL+"PL"BPL"BP[)BPL+"P[
+M1@PZ.CH,#`PZ,0P,##HZ)B8F.C`P.CHZ.B8F)@P,.CHZ##HZ.CHF#`PZ.CH,
+M,#`P##HP.C`[.C`P,#HZ.CHP.S`C(R,Z,#H[.CHZ.CHZ.CHF,"8Z)B8F)C`F
+M,#H[.SHZ.CHP+CL[.SL[.SL[,"8[.RXN.SL[.SLP,#LZ.CHP,#``+"PC+@HK
+M2$A(/S\_/TP*144B14401440$$4B145%*B)%`PP,1D9&'$8<`U@#`P`#`U@`
+M`U@#``,#`P,``P,#`P,&`P,#!@,#!@8&.08Y'%A86%A%$$5%12I%145%144J
+M145%12I%12$&!APQ1D8<!@,Y`T5%14=%1T5%12%%(45%145%12%%12%%(45%
+M12%%144Y`T5%145%144J145%*D4J144J144<1AQ&1AQ%109%*D5%12I%12I%
+M11!%`P,#`P,``P-8`U@#`P,#`P,``P`#`P,#`P,#`P,#`P,#`P8#6`8#.0,#
+M`P8``QPY`SD&!@`&.0!8!@8&.3DY`P8L"@H*"BPL+"PN,",K*RL*+$8Q#"8Z
+M.CHZ#`P,#`P,.CHZ.CHP.CHZ.B8Z.CHP,#`Z.C`Z.CHZ,#`Z.CHP##HZ.CHP
+M,"8P.CHZ.CH[.CHZ(S`P.CHZ.C`Z.SLZ.B8F)CHZ)C`F,"8P,#`F,#HZ.S`Z
+M,#`P.SLP,"XP,#`P,#`N.C`P.CHF)B8P.R8[.SLN.SL[5PHN,"PK/TQ,3$P_
+M/S\_2$5%(44A12I%145%12I%145%10,,##%&1D9&'%@#`U@#6`,#`P`#``,`
+M`P`#`P,``P,``P,``P,#.0,`!@8&.1Q8'%@#145%*D5%12I%12I%144J145%
+M12I%108<,49&1@,#'`-%1T5%1T4A12%%144A144A12%%12%%144A12I%12%%
+M!D4#12I%12I%*D4J145%12I%12I%`QP<,48<`P8&144J12I%12I%12I%*@`#
+M6`,``P,<``,#``,``P`#`P,#`P,``P,#`P,#`P`#`P`#`P,&6`,&`#D#`P`#
+M``8#``8#!@8&!@8&``8&.3DY+`HL+"P**PHL+",P+"PL+"X^,3H,)C`P,"8P
+M)@P,##HZ.CHZ,"8Z)CHZ.CHZ)C`P#"8Z)B,C(S`Z##HP##HZ.CH,,#`P,#`F
+M.SL[.S`Z.SLF(SHZ.C`C(SL[,#HP,#`F.B8F)C`P,#`P.C`F)CLP.C`P,"X[
+M,#`C,"8[.SLP,#HP.SHZ+BXN.SL[,#`N+C`P,#DK*PH*+"L_/S],/S],/RQ%
+M145%!CE%!@9%(45%(45%*D4###HZ1D9&1AQ8`U@#6`,#6`,#```#``,#``,#
+M`P,#`P,#`P,``P,&`P`Y.08`6`,`6`9%(45%*D5%12I%12I%12I%12I%144#
+M'$9&1AP#````145'145%145%144A144A145%(45%12I%(45%(44A.08Y!BI%
+M12I%144J145%12I%12I%11Q&#$9&1@8&!D4J145%*D5%12I%$"$#``,#`P`#
+M``,``P,#`P,#`P`#``,``P-8`P,#`P,<`P,#`P,#``,#`P,#``,#`P,Y`SD&
+M!@`&``8Y.08&``8&.2P**RLK*PHL+"PC)C`P,"P*&PPQ)@PZ.CHZ)B8,#`P,
+M,#`P,#HZ)C`Z.CHZ.CHZ,#`P)CHZ.CHZ(SH,.CHZ.CHZ.CHZ,#LZ(SHZ.C`Z
+M)CLZ.CHZ.CHF,#L[,"8[.CHZ.CHF)B8P,#`P,#`F.C`[)BXP,#`P.SLN,"8P
+M+BXN,#`Z+BXN.SL[.S`[,#HP,"X[.SL`*TA,/RPL2$A(/S],/S\L.45%108Y
+M(08Y(44J!D4J144J'`PZ#$9&1D8<`````P`#6`,```,#``,```,#``,``P`#
+M`P,#`P8`!@,#!@,Y6%@#6``&144J144J12I%12I%12I%12I%12H&!AQ&'!Q&
+M`U@#`T=%1T4A12%%(44A12%%(44J12I%*D4A12%%*D4A10,Y.0-%(0-%*@-%
+M*D4J144J12I%11Q&,49&,1P#!CDJ12I%*D4J12I%*D5%``,``````P`#``,`
+M`P`#``,``P`#``,``P`#``,#`P,``P`#`P,#``,#``,#``,``P,&`P,&`P8Y
+M`P8Y.08Y.08L"BLK*RL*+"PL(R8P,#`L"AL,,28,.CHZ.B8F#`P,##`P,#`Z
+M.B8P.CHZ.CHZ.C`P,"8Z.CHZ.B,Z##HZ.CHZ.CHZ.C`[.B,Z.CHP.B8[.CHZ
+M.CHZ)C`[.S`F.SHZ.CHZ)B8F,#`P,#`P)CHP.R8N,#`P,#L[+C`F,"XN+C`P
+M.BXN+CL[.SLP.S`Z,#`N.SL[`"M(3#\L+$A(2#\_3#\_+#DA14<#`T4Y144A
+M12%%12I%148Q.@PQ1C%&1E@#6`-8`````U@#```#`P`#```#`P,#``,``P`Y
+M`P`Y`P`Y.1P<6!Q8`RI%144J145%*D5%*D5%*D5%*D5%10-&1D8Q1@!8`P-'
+M144A12%%(44A12%%(44A144A12%%(44J12%%$"$#.3D#*D4J144J144J144J
+M12I%12I%'#$Q,0Q&108Y12I%*D4J12I%*D4J$``#`P,#`P,``P,#`P`#`P,`
+M`P,``P`#`P`#`P,#``,#`P,#`P`#`P,#`P,#``,#`P,``SD`!CD&`SD#.0,Y
+M.0,#+`HK*RLK"BPL+",F,#`P+`H;##$F##HZ.CHF)@P,#`PP,#`P.CHF,#HZ
+M.CHZ.CHP,#`F.CHZ.CHC.@PZ.CHZ.CHZ.CHP.SHC.CHZ,#HF.SHZ.CHZ.B8P
+M.SLP)CLZ.CHZ.B8F)C`P,#`P,"8Z,#LF+C`P,#`[.RXP)C`N+BXP,#HN+BX[
+M.SL[,#LP.C`P+CL[.P`K2$P_+"Q(2$@_/TP_/RPY145%`P9%!@9%(45%*D4J
+M12H<,3`Z,49&1AP`6`,```,``P`#```#`P`#`P`#``,``P,Y`SD#`P`#.0`&
+M.0`</E@`6`9%12I%12I%144J144J144J144J108&,3$Q#!P`6`-'12%%(44A
+M12%%(44A12I%(2$A12I%*D4J12I%*D4A!@,Y`T5%12I%*D4J144J145%*D5%
+M148Q#`PQ'`8Y12I%*D4J12I%*D4J12H#6``#6`````,<``,#`P```U@#``,#
+M`P`#``,``P,#`P,#`P,#`P,#`P`#``,#`P,#`P,#`P,#`SD#.0,&`P8Y.3LK
+M"@H*"@HL+"PN#`P,#"8L1CH,##H,#`PZ#"8,)CH,)B8F.B8F.B8Z)CHZ.CHZ
+M,#`[)CHZ.CHP)C`P)CHZ)B8F.CHZ.CHP,",C(S`P,#LZ)B8F)B8Z.SLP)B8C
+M.CHZ.B8F)B8P,#`P,"8P.CLP.B,F)B8C)CL[.S`[.SL[)B8[.RXN+C`P,"XP
+M,#`F,"8[.SLY2#\_3$@N"@H*2$P_3$PL144A10,&(08&(45%*D5%12I%'`PP
+M.D8Q1D9&6`,`6`-8`U@``P`#``,``P`#`P,``P,``P`#``,#.0,&`#DY(!P<
+M`!P#*D5%*D5%*D4J12I%12I%12I%$`8#`PP,#`P<6`,`14<A12%%(44A(44J
+M12$A12I%12I%(44J12$0(2$A`SD&`P,A12I%*D5%(44J12H#*D4J109&1@PQ
+M1@`0.080*D4J*D4J12I%*A`J``,#``,#`P,``P``6``#`P````-8`P`#`P,`
+M`P`#`P,#`P,#`P,``P,#``,#`%@#``,``P,&``,Y`SD&!@8`!@,P"BPL+`HL
+M+`HL"BXQ,3%*.B`Z,`P,.CHZ.CHZ#`PZ.B8F)C`Z.B8Z)B8P,#`P.B8F)C`P
+M,#`P)C`P,#`P,",C(S`[.SLF,#LP,#`C.SL[.CHZ)B8F)CLP,#LP.S`P,#HZ
+M)B8P,#`P,#`F)B8[)B8[,#`P,#`P,"X[.SL[.RX[+BX[+CL[.SLN+CLZ,"X[
+M.SL[($@_3#\_"BXN+BL_3#],+#E%144&!D5%13E%144J145%11PP,#HQ1D8Q
+M'%A8`U@``U@``P!8`P````,#``,``P`#``,Y``,``SD``SDY`QP</@,#!B%%
+M*D4J12I%*D5%*D4J12I%*D4&.0,,#`P,'````T5'12%%(44A12I%(2%%*D4A
+M*B$A*D4J12$J12I%*CD#`#DY(44A144J`T4&12%%!B%%145%1D8,,3$#.3DY
+M$"I%*D4J*BI%*A`J10`#6`,#6`-8``,``U@#6%@#``,``P`#``,``P,#`U@`
+M`QQ8``,#`P,#``,#``,#``,#6`,``SD#`P,&`P`Y`P8Y.PH*"@HL"@H*"BLK
+M,#`P,3$`.CHZ##HZ.CHF##HP.@PP,#`P)CH,.C`P#`P,#",F,#`F)CHZ.C`P
+M)B,F.SHP,#`P)CLZ.B8Z.CHZ)CHC,#`P.R8F)B8F)B,Z(S`Z.CHF.B8P)C`P
+M)B8F)CHN.R8F.S`P,"8[)C`N.RXN+BX[.RXN+BX[,#`P.RXN(R8F+CL[.SD_
+M3#\_/T@[.SLN/TQ,3"Q'144A!CDA109%*D4J145%*D5&.SLZ1AQ&2AQ8`%@`
+M`%@``U@``P`#``,#``,```,``P,``P`Y`P`Y!@`Y.0`</AP``P9%*D4J12I%
+M*D4J*D4J12I%*A`A!@8&##H,.AQ8`P`A12%%(2$A12%%(2%%(44J12%%*D4J
+M(2$J12HA$"$Y.0-7.44A144J12%%*D4J145%109%10PZ.CHZ6#DY`RHJ$"HJ
+M$"I%*BH0*BH```-8`````P!8`P`#``,```!8`P```P,#`P`#``,`6`,#``,#
+M``,<`P`#``,#``,#``,#`P,#.0`&`SD#!@,Y`SHL+"PL*PHK*RLK"BPL+"PZ
+M6`P,.CHZ.CHZ.CHP##`P.CHZ,#`,#`P,##HZ.CHZ.CHZ.@PZ.CHZ.CHZ(S`F
+M,#`P(R8Z)CHP.SHZ.C`P.B8P(R8F)B8P,"8Z)C`Z)B8F.B8P)C`F,#HZ.CHP
+M+C`F)BXC(R,[+C`P)BXN+BXN(R,C+BXN.SL[.SLN+CLF+CL[.SM7/S](2$A(
+M*RLK+BL_3$PL.1`A108#13E%(45%12I%*D4J,3L[#$9&1AP@`UA8`U@#`%@`
+M`%@#`````P```P,`!@`#.0`#```#``-7`SD`'$8<``,&$"I%*BI%*D4J12I%
+M*BI%*D4J$$4#`#`Z.@Q8`%@`12$A(44J12$A*D4J(2$J12$J$"HA12I%*B$0
+M*B$J13D#`SE'12%%(45%145%12I%109%*AP,,`P,.@-%12HJ$"H0*BH0*BH0
+M*A`J`U@```-8`U@``U@#6%@#6!P#```#`P-8`P`#`P,#``,#``,#``,``P`#
+M``,#``,#``,``P,#`P,#`SD#.0,&`P8Z"BPL+"PL"BP*"@I(2$@K"E0Q#`PZ
+M.CHZ.CHP,#`F.CHZ.C`,##H,.CHZ.CHZ.CHZ.CHF)B8F)CHZ)C`P.S`P,"8F
+M)CLZ.B8Z.CHP,"8F)B8Z+BXN,"8F,#`P)CHZ.C`F,#`P,"8P,#`P(SLP,#`F
+M,#`P.RXN+BX[+B,C(S`C,",[.RPN+BXN+CLN+C`[.SL[5RLK*RLK2"LK*PHL
+M/S\_+$<A$"$Y12%%144J145%*D5%13$P.PQ&'$9&'`!8`````````````P``
+M``,``P```P`#``,`.0,#`#DY`SD`!D8</E@&`RH0*D4J*D4J$"I%*BI%*BH0
+M*B$&`!PZ+CHZ6%@@`R%%(44J12$A(44J12$0(2$J(1`A$"H0*A`A*A`J(3D`
+M`P`&12I%(45%12I%*D5%*D4J144<.C`[##H&``8J$"HJ*A`J*BH0*BHJ*@``
+M6`-8`U@``%@#6`,``%@#6`,#6`,#`P```U@#`P`#``,``P,``P```P-8`P`#
+M``,``P,``P,#`P,#`P,`!@`&.BPL+"P*"BP*2$A(2$A(*PH<#`P,#"8F)CHZ
+M.C`,.B8Z.CHZ#`P,##HZ.CHZ.CHZ.CHZ)CHZ.CHF.CHZ.CL[.SL[.SL[,"8Z
+M(R,C)B8F)B8F.CL[.R8F,#`P)B8F)B8P,"8P,#`P,#`P)BXN,#LF,"8F)C`N
+M.RXN(SL[.SLP,#`P(SL[+BXN+C`[+#LP.RXN+@`K*RLK*RM(2$@K+"M,3"Q%
+M$"$0.3DJ!CE%12I%*D4J12I&1C$Z1D8</E@``%A8`P```````````P`#``,`
+M`P`#``8``P`Y`#D`.0`Y```<'%@``RHJ$"HJ12H0*BI%*BI%*A`J*A`J!CD<
+M,3LZ#%A86`-'(1`A(1`J12HA(1`J(1`A$"HA*A`J(2HA*A`J(2H#``,#12%%
+M144A12I%144J144J12I%'#HP.CH,`P,Y*BHJ!2HJ*@4J*BH%*BI8`%@#6`!8
+M`U@`````6`-8`UA8```#```#`P`#```#```#``,``P`#`P`#``,#``,``P``
+M`P,#`P`#`P,#!@,#`S$*+"PL"@HK2#](2"LK*PH*2@P,.@P,#`P,#`PP,#`P
+M,#`P,`PZ.CHZ.CHZ.CHZ.B8F.CHZ.CHZ.CHZ(S`F,#`P.S`[.CHF)CHZ.CLZ
+M,#`F.CHN+BXP)C`P,#`P,#`P,#`P,#`P,#`P,#HN.S`P)C`[.SLF)BXP.RXP
+M(R,C,#`P,#`P+BXN+BXL.S`P,"X[.SLA*PHK*RM(*RLK*RQ(3$P*1R$0(0,#
+M(0,&*D4J145%*D4&1C%&,1PQ,48;6````%A8```#``,``P`#```#``,``P``
+M.0`Y```&`#D`.0,`/AM8``80*BH0*BH0*BH0*BH0*BHJ(BH0*D4Y'`PZ,0P#
+M```#(1`A$"$A(2$A$"$J$"$J(2H0*B$J(2H0*B$J*A`J``,`!B%%(44J109%
+M*D4J144J145%`QPZ##HZ.CDY!BHJ*BHJ*BHJ*BHJ*BHJ`%@#6`,``U@#6`-8
+M`P`````#6`,#6`,#6`,``P,#`P,#`P,#``,``P,#`P`#``,#``,#`P`#`P,#
+M`P,``P,``P-*"BPL+"P*"DA(*TA(2$@**R8Z.CHZ.CHZ#`P,.C`P)B8F)B8F
+M.CHZ##H,#`PZ.CHZ.C`P,#`P)B8Z.B8C(S`P,#`F)B,P.B8F)B8C.C`F+C`F
+M)B8F+BXZ,#`P,",C(S`F,#`P,#`P,#`C(S`P,#LN,#`P,#`P+CLN(R,C(RX[
+M+#`C.RPN+BX[+CLL,#`P+BXN1TA(*RLK*RLK*RL**S],+$<A$"$&`R%%.44J
+M12I%*D5%*APN.S%&,49&'```6`,``````%@``````P`#```#`#D`.0`Y``,Y
+M```Y.5<Y`$8<'``&(2H0*BH0*BH0*BH0*BH0*BHJ*BH&.48Z##$,.5<Y.4<A
+M(2$A$"$0*B$J(2H0(2H0*B$J(2HA*BH0*A`J*CD#5SE%(45%12I%12I%*D4J
+M12I%*D5&.CHZ.S$&.0,J*BHJ*BHJ*BHJ*BHJ*E@``%A86%@``%@``%@#6`-8
+M``!8``,```,#`U@#6`-8`UA8`P`#``-8`P`#``,``P`#6`,``P`#`P,#`P,`
+M`P,&2@HL+"PL"@I(2"M(2$A("BLF.CHZ.CHZ.@P,##HP,"8F)B8F)CHZ.@PZ
+M#`P,.CHZ.CHP,#`P,"8F.CHF(R,P,#`P)B8C,#HF)B8F(SHP)BXP)B8F)BXN
+M.C`P,#`C(R,P)C`P,#`P,#`P(R,P,#`[+C`P,#`P,"X[+B,C(R,N.RPP(SLL
+M+BXN.RX[+#`P,"XN+D=(2"LK*RLK*RLK"BL_3"Q'*A`J`P,J.08J145%*D5%
+M*A`Q+BXZ'#$Q,5@`6```````6````P`#```````#``,``P`Y`#D``#DY`#D`
+M.0`;'#Y8!BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ!@-&##$Q.@`#`P`A(2H0(2$J
+M(2$J$"$A*B$J(2HA*BHA*A`J(2HA*B%'`P!712I%`RI%12I%145%*D5%*D5%
+M1CL[,#!&.3DY&BH:*BHJ*BHJ*BH:*BH`6`-8`%@#6`-8`U@#6`-8`U@#`%@#
+M``-8`P,``P,``P`#`P`#`P,``P`#``,#`P`#`P`#``,```,``P,#`P,#`$H*
+M+"PL+`H*2$@K2$A(2`HK)CHZ.CHZ.CH,#`PZ,#`F)B8F)B8Z.CH,.@P,##HZ
+M.CHZ,#`P,#`F)CHZ)B,C,#`P,"8F(S`Z)B8F)B,Z,"8N,"8F)B8N+CHP,#`P
+M(R,C,"8P,#`P,#`P,",C,#`P.RXP,#`P,#`N.RXC(R,C+CLL,",[+"XN+CLN
+M.RPP,#`N+BY'2$@K*RLK*RLK*PHK/TPL1R$J(3E'144Y12I%*D4J1440,2XL
+M,#%&2D8<6```6`!8`P,````````#``,``````P`Y`#D`.3D`.5<`.3D`/AP@
+M6#DJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*@8Y1C`P##I8`%@`$"$A(2H0(2H0(2HJ
+M$"HA*BHA*A`J*BHA*B$J(2HJ1SDY`T5%145%12I%*D4J12I%*D5%*C$[.SHP
+M1CD`.2HJ*BHJ*BHJ*BHJ*AHJ6`-8`U@`6`!8`U@`6`!8``!8`U@#6`,``U@`
+M``-8`P,#6``#6`-8`P`#`P,```,``P`#`P`#`P,``P````,``P-&"@H*"BP*
+M"BLK*RLK*RL*"CLZ.CHZ)B8F.CH,,"8P,#`P,#HP##HZ,#`P,#`Z.CH[,#`F
+M.CHZ.CHF)B8Z.B8F)C`P.RX[(R8P,#`P)B8Z)BXF.CHZ)CLF.R8P,#`P,#`P
+M)B8P,",P,#`P.S`C(SLC.SL[,#`P,",N(S`P,"X[.SL[,"PN+BXN.SLN+C`C
+M.SL[*DA(2$A(2"LK*RM("DA,+$<J$"$#1U<Y!BI%*D4J144J!CHL+"Y*,0Q&
+M6%A8``!8`%@``````P`#`````P`#`#D``#D`.0`Y`#DY.5<``!Q8'%A%*BHJ
+M*BHJ*BHJ*BHJ*BHJ&BHJ*BH&.3$L.SLQ6`!8`"$0*B$A*B$A*B$A(2HA*A`J
+M(2HJ(2HA*BHJ*BHJ*D=71SDJ12I%12I%144J145%109%*D4[.SHZ.SXY.3D:
+M&AH:&AH:&AH:&AH:&@!8`U@#6`-8`%@#6`-8`U@#6`,```-8`P`#```#``!8
+M`U@#``,``P`#`%@#`P,#``,#``,#```#``,#`P,``P`#,2P*"@H*+`I("@I(
+M*RLK*RL,.CHF)CHZ.CHZ#`PZ.B8Z.CHZ)CLZ.B,F.CHZ.B8F)CHZ.CHZ.B8Z
+M)B8F.CHZ.CHZ.CHZ.CHF,#`P,"8Z,#`C.B8F)B8P)B8N.C`P,#`P)C`P,"8P
+M,#`P,",P,",[(S`P,#LL,#`N+"X[.SLN.RXN+B,N+BXN.RPN+BXP.SL[.S%(
+M2$A(*T@K*RLK3`H*/PH`*BHA.0,Y1RI%*D4J12HJ12HZ+BPF,49&1B``````
+M``!8`"`````````#`````#D``#D``%<Y5P`Y)#D`.5<@1D98`"HJ*BHJ*BHJ
+M*AHJ*BHJ*BHJ*BH:15<Z+C`Z,0``6``A(2$J(1`J(2H0*B$J(2HA(2HA*BHJ
+M*BHJ*BHJ*BI71SDY(44J12I%*D4J12I%*D4J144J.@PQ.CH<.5<Y&AH:&AH:
+M&AH:&AH:&AH`6`!8`%@`6`!8`%@`6`!8``!8`U@``%@#6`-8`U@#```#6`,`
+M`U@#6`,``U@#6`,```````,#``,``P`#``-8`#$*+"PL+`I(*RLK2$A(2$A(
+M(SHZ.@P,#`P,#`P,,#HZ,#`P)B8F.CHZ.B8F)B8F)B8Z.CHZ.CHZ.SLC.CHF
+M.CHZ)B8F)B8F)C`P,"8P.CLP,",F)B8F)C`P)C`P)B8F)B8F,"8P,#`P,"8P
+M+BX[,",C(R,P+CLC+C`N+BXN+"XN.RP[(RXN+BXN.SL[.RPN+BX^/S](2"M(
+M*RLK3$P*+C\L6"$J*@-7.440*A!%*D4J12H01C`Z,3$Q1D8<````6```(```
+M`P`#``,``````P```#D``#DY`#E7.3E7.5<Y6!L;6#DJ*AHJ&BH:*BHJ*BH:
+M*AH:&AH:&E<Y#"X[,$8@6``Y*A`A(2HA*B$J(2$J(2$A*BHJ(2$J*BHJ*BHJ
+M*BHJ`T<`.44J12I%*D4J12I%*D4J12I%10P,.@Q&`U<Y!AH:&AH:&AH:&AH:
+M&AH:6`!8`%A8(%A8(%@`6`!8`%@``%@#6`,```!8`P``6`-8````6`,```,`
+M```#``````,#``-8`P,``P```P`#``,`+"LK*RM(*TA(2"L_/S\_2#LZ.@P,
+M#`P,)@PZ,#HP.CHZ.CHZ.CHF.CHF)B8Z.CHZ.CH[.CHZ,#LF)B8C,#L[.R,Z
+M.CHZ)B8F)B8F)B,[.S`[,#`P+C`F,#LP)C`P,"8F,#`P,"8P,#`F+CLP,"PN
+M(R,C.S`L+#`C(RPL+#`N.RPN.R,[.SLL(SL[(RPC.SL[5S\_*RLK2#\_/TQ,
+M"CLK+"``.1@Y.44A$"H0*D4J$"H0*C$Z,48Q2D9&&P`````````#````````
+M``,``P`Y``,``#E7`#E7`%=75SE7`!L#6"`Y*BHJ*BH:*AH:&AH:&AH:&AH:
+M&B$Y.3`L,#%&6"`#`"$A*B$A*B$J(2HA*B$J(2HJ*BHJ*BHJ*BHJ*BHJ5P!'
+M.3DJ$"I%*D4J12I%*D4J12I%*E@,.C`,,1`J.1H:&AH:&AH:&AH:&AH:&B!8
+M6%@@6%A8/AP@6"!8`%@@6"!8`%@`6`!8`U@`6`!8``!8``!8`%A86````%@`
+M````6``````````#``,```,``PHK*RLK*RM(2$@K/S\_2#\*,0P,#`P,#"8F
+M)CHF(R,Z.CHZ.CHZ.C`Z.CHZ.B8[,#H[.S`P,#HZ)B8Z)C`P,#`F)B,[.B8F
+M)B8F.BX[)C`F.R8F)C`[.R8P,"8F)B8P,#`P,#`P,#`P,#`P,"8P.SL[.RXN
+M+BXP,"PN+BXN+BXN(R,C+BXN.SLN(RP[+"XN+@!(*RLK2$Q,3$Q,3"L[+"Y8
+M`#DY(44J*BH0*A`J*A`J$"H[,#H,'#%*1E@`6%@`````````````````````
+M````.0``.3D`5SE7.3E7.0!86`!8.1H:&AH:&AH:&AH:&AH:&AH:&AH:5SDP
+M.RX,'%@```8A(2$J(2HA(2HA*B$J(2HA*BHJ*BHJ*BHJ*AHJ*D=7.4=%12I%
+M*D4J$"I%*A`J12H0*A`#,0PP#$I'1R$:&AH:&AH:&AH:&AH:&AI86"!86%A8
+M6%A86%A86%A86%A8(%@`6`!8`%@`6`!8`%@``%@`6```6```6````%@#````
+M``````!8```````````K*RLK"@H*/RM(*RLK*S\_+$H,##HF)B8Z,"8P,#HZ
+M)B8F.CHZ.S`P)C`P,#`F,",Z.CL[.SL[)CHZ.CHZ.CHZ.B8P,#`[.SL[.R,[
+M)C`C(S`F)B8P.SL[)C`C.SL[,#`C(R,P,#`P,#`P,#`P(S`N+BXN+#LL+BXC
+M+BXN(RXL+CLC.SL[.RP[.R,N(S`[.SL`2"LK/S],3$Q,3$Q,*RXF`#DY`"$J
+M$$4J*BHJ$"HJ*BH0#"PN,3$;1D98(````````````````P`#````.0``.0`Y
+M````.5<Y5U=75T=8&U@;6$4:&AH:&AH:&AH:&AH:&AH:&AH:&E<Y)BX[,%@`
+M``,8(2$J(2$J(2HA*B$J*BHA*BHJ(2HJ*AHJ*BHJ*BI'5P!'1RH0*D4J12I%
+M*A`J12H0*D4J`S$,##%&13DA&AH:&AH:&AH:&AH:&AH:6%A86%A86%A8&UA8
+M6%A86"!86%@@6"!8(%@@6%@`6`!8(%@`6`!8`%@`6```6```6```6```6```
+M````(!P````#/TA(2`HL*S]("@HL+"Q(/PHQ##HP#`P,(S`Z(PP,.@P,##LP
+M.CHF.S`F)B8P.SLC.S`C(R,C)CHZ(SHF)B8F)C`P,"8F+BXP,#`[+C`P,#`P
+M,#`P)BX[+B,P,",C(SLC(R,C(R,C(R,P,#`P(R,P,#`P+BXC+BXL(RPL+#LN
+M+"PL+B,N+BXN.SLC.RXC,#`P6$A(/TP_/TQ,3#],3$PK,%@`.3DY*BHJ$"HJ
+M*BHJ*A`J*BXL+B9&,1Q&6`!8```````````````````#````5P`Y`%=7`#E7
+M`%=75U=76%@<6"``&AH:&AH:&AH:&AH:&AH:&AH:(3D`!BX*.RP;6``@1R$J
+M(2HA*B$A*BHJ(2HJ*BHJ*BHJ*BHJ*AH:*AH:`%='11`J$"HJ*BHJ*D4J*A`J
+M*A`J*C$N,#HQ1D=7(1H:&AH:&AH:&AH:&AH:&EA8'$98&U@;6%@;&QM8&UA8
+M6%A86%A8(%@@6"!8(%@@(!P<6"``6`!8`"!8`%@`6"``6``@```@6`!8'```
+M````6$A(2$@K*T@_/RP["@H*"C\K2@PP,`P,#"8Z.B8P,#HF)B8F.B8F,",C
+M(R,C(SLF)B,F,#HZ.CHZ.CHZ)B8F)B8F,"8P)B8F)B8F)C`P,#`C(S`P,#`P
+M)B8C)BXP,#`P,",P(R,C.SL[(R,C(R,C(S`P,"PC+"PL+CL[.SL[+BXL(RX[
+M.SL[.SLN+"XN(S`P,`!(/S],/T@_/S\_/TQ,3"P@!E<`*BHJ*BHJ*A`J*BHJ
+M*CDP+BXZ,3$;&R``6"`````````````#```&```Y`#D`.0`Y`%=7`#E7.5=7
+M5UA8&SY8.5<81R%'.3E'5T='.3E'5U<Y.3E'.0`*"BXL1E<@`$<A(2HA*B$J
+M*B$J*BHJ*BHJ*BHJ*BHJ&BH:&AH:&CE7&%<J*BHB*B(J$"HJ*A`J*A`J*A!&
+M"@HN+C$0`#D:&AIB&AH:8AH:&AIB&F)86!M86%A86%@;6!L<&QM8&QL;6"!8
+M(%A86%A8(%@@6%A8/B!8(%@@6"!8`"`@6!Q8`%A86%@`6`!8`"``(``@``!(
+M2$A(*RM(/S\L.PH*"@H_*TH,,#`,#`PF.CHF,#`Z)B8F)CHF)C`C(R,C(R,[
+M)B8C)C`Z.CHZ.CHZ.B8F)B8F)C`F,"8F)B8F)B8P,#`P(R,P,#`P,"8F(R8N
+M,#`P,#`C,",C(SL[.R,C(R,C(R,P,#`L(RPL+"X[.SL[.RXN+",N.SL[.SL[
+M+BPN+B,P,#``2#\_3#](/S\_/S],3$PL```#.2HJ*BHJ*BHJ*BHJ*BHJ.RP[
+M)C%*1AP`````````````````````````````.0```%<Y5U=75U=75U=8/E@;
+M`$='`P`#!@,&.3DY1P9%10-75U=7.4=8"BXL+$8`1P`A*B$A*B$A(2$J(2$J
+M*BHJ*BHJ&BH:*AH:&AH:&AI75U=%*A`J*BHJ*BHJ$"HJ$"HJ$"I%+"PL+"Q*
+M(4=%&F(:&AIB&AH:&F(:&AH:6!M8&U@;6!L<&U@;&QL<1AL<&QL<6%A86"!8
+M6%A86"!86%@@6%@@6"!8(%@@6"`@("`@(!P@(`!&6"``6```6%@@2$A(2"LK
+M2#\_+#L*"@H*/RM*##`P#`P,)CHZ)C`P.B8F)B8Z)B8P(R,C(R,C.R8F(R8P
+M.CHZ.CHZ.CHF)B8F)B8P)C`F)B8F)B8F,#`P,",C,#`P,#`F)B,F+C`P,#`P
+M(S`C(R,[.SLC(R,C(R,C,#`P+",L+"PN.SL[.SLN+BPC+CL[.SL[.RXL+BXC
+M,#`P`$@_/TP_2#\_/S\_3$Q,+`,A(2$A*B$J*BHJ*BHJ*BHJ*CHC+CHQ2D9&
+M6"``6``#`````````````P``.0``5P``5SDY5U=75T<Y5T=7``!8(``A1P``
+M144#10,Y13E'145%13E75U<Y6"PL"BX<`%=7(2HA*B$J*BHJ*BHJ%BHJ%AH:
+M*AH:&AH:&AH:&AH:&#E'5RHJ*BHJ*BHJ*BHJ*BHJ*BHJ*@PL+"X*,2$A1QH:
+M&F(:&AIB&F(:&F(:&AM8&QM8&QL</AL;'!M8/AL;&QL;&QL<&UA86%A8(%A8
+M6!L@6%@@6"!8(%@@6"!8(%@@6%@@("!8(%@@(!L<6"!8($A(2$A(*T@_2"P[
+M+"PL+@I(,0PF.B8F)C`Z)B8,.CHZ.CHZ.B8Z.C`[,#`P.CHZ)B,F.S`P,"8F
+M.CHZ)B8F)B8F)C`F,#`P,#`P,#`P,",[(S`P,"8F)B8P+BXN+BX[,#`P,#`P
+M(R,C(R,C(S`P,"XN+BXN,",L.RX[.SLN+CLL(R,[(R,C.S`L+"XP,"XN+@`_
+M3$P_/S\_/S],/S\_3"Q'*BHJ*BHA(2$A(2HA*D=7*D<Q,#LZ#$8^,0``(``@
+M`"```````````````#D`.0```#E75P!7.5=75U<8.5@@`!Q8`#E7`P,&!D5%
+M144Y108&109'.5='.3XP.RPL1@!8`"HA(2$J(2H6*BHJ*BH:*BH:*AH:*AH:
+M&AH:&AH:&CE7(08J*BHJ*BHJ*BHJ*BHJ*BHJ*BHP+BPL+!Q'(3EB&F(:&F(:
+M8AH:8AH:8AH;6!L<&UA8&QP;&QL;'!L<&QP;&QL;&QL;6#Y86%A8(%A86%@@
+M6%A86%A86"!8(%@@6"`@6%A8&QP@6%@@&R`@6"!(2$A("D@_/RLL.R,C(R,*
+M"D8,.@PP,#`P,#`Z.CHF)B8F)CHZ)B8F,#`P,#HZ.B8F.CHP,#`C,#HZ)B8F
+M)B8F)B8P,#`P)B8F)C`P,#`P(S`F)B8P,#`P(RX[+"PL+CL[,#`P,#`P,#`C
+M,#`P(S`P,#`P(S`N(R,[+BXN(SLL.RPL,"XN+BP[.RXL,#LL+"Q&3$Q,3#\_
+M/S\_/S](/TPN`"HJ*BHJ*BHJ*BHJ(2HA(2$`)CHL##%*6$8@````````````
+M``,``````P```#D`5U=75P!75U=7&%=75U<;'#X@`%=71U='145%!@-%.4=%
+M!D5%`U='.5=8+BPL+#Y86``A*BHJ*B$J*BHJ*A8J*AH:*AHJ&AH:&AH:&AH:
+M&AI'&"H`*BHJ*BHJ*BHJ*BHJ*BHJ*D4J.S`Z.CM&*D=7&AH:&F(:&AH:8AH:
+M8AH:6!M8&U@^&QL;'!L<&QL;&QL;&QL<&QL<&QL;&QL;6!M8&U@@6%@@6"!8
+M2EA8(%A86%@@6%@;("`@("`@("!8("!8*PH*"@I(/S\K.SHQ,3%*.PI*.@P,
+M.CHZ)C`P)@PZ)B8F)CHF.C`[.R,[.SLZ.CHZ,#`P,#`P.SLZ.B8F,"8F)B8F
+M)B8F,#`F)B8F)B8P,"8F)B8F.SLP+BPP.SL[.RXN,#LN.RP[.SL[.SL[.R,[
+M,#`P(R,C,#`C.RXN+CLN+BXP,",P,#`L+BXL+#`P+"PL2DQ,3$P_*TA(2"LK
+M2#\_)BHJ*BHJ&AHJ&AH:&BHJ*BHJ(2XL"CH,1D8^````````````````````
+M`````%<`5U<`.0!75SE75U=75T<`6!L<&P!7&#DY145%!D5%14=%145%`$='
+M&!A'/BPN.RP@6```*B$J%BHJ%BHJ%AH:*BHJ*AH:&AH:&AH:&AH:&AH:5T='
+M1RHJ*BHJ*BHJ*D<J*BHJ12HJ10HL+@PP("$A16(:8AIB&F(:8AIB&F(:8D8;
+M&U@;&QP;&QL;&QL<&QL<&QL<&QL;/AL<&QP;&QL;6!L;6!L;&U@;1AL;&UA8
+M&U@;6!L;&QM8&R!8("!8(%@@("PK*RL**RLK"B,,,3$Q2C$L*0PZ##HZ.C`Z
+M.CHZ##HF)B8Z)B8Z,"8C.SL[(SHZ(SLF(SL[.RX[.SL[)B8Z.CHF.B8F)B8P
+M)B8F)B8P)B8P,#`P,#LN(SLN,",[.SLP,#`N+BXN+BXN(S`N+#`P.R,C(SL[
+M(S`C,",L+"PN+BXL(SLC(R,C+BP[+BXP,"XN+EA,3$P_*RM(2$@K2"M(/R8J
+M*BHJ*BH:&BH:&AH:&AHJ*BHL+`H,,4I&&P``(``@````````````````.5<`
+M.0`Y)%=7`%=75SE7&%<85QL</EA&&#E'`%=%144Y1P9%1P!7(3D`1RI7*E@P
+M.RPL6"```"$J%BHJ(2HJ&BHJ*AH:*AH:&AH:&AH:&AH:&AH:&CD:.0`J&AH:
+M1RHJ*BHJ*BHJ*D<J*@,L+"X[.P`A1R$:8AIB&F(:8AH:8AH:8AH;'#Y&&QM8
+M&QL;&QP;&QL;&QP;&QL;'!L;/AL;&QL<&QL</AL;'!L;'#X;&QL</AL;&QL;
+M&QL;&U@@("!8("`@6"`**RLK"@HL"@HC#"8F)CHQ,1LZ##HZ.CH,)CH,)CHF
+M)B8F.B8F)C`Z,#L[.S`F,#LN.R,F)B8F)C`P+B,[.SL[.R,P+C`F,#`P,#`P
+M)CLN.R8F)B8P(S`[(SLN,#`P,",[(S`[(RXN+BPN(RPP+#`P,#`C+BX[(R,[
+M+BXN+"XN.SL[.S`P,"X[+B,C(RP[.SL;/T@_2$@K*RLK2#],3#\,*BHJ*BHJ
+M*BH:&AH:&AH:&AH:+"X*,3$Q1D8@````````````````.0``````5U<`5U=7
+M5SE75Q@85QA71P!8/B`<.@-'`$=75T=75P!'5QA7````5U=7*AHQ.CH[+@``
+M5U<A*BHJ*A8J&A8:&A8:&AH:&AH:&AH:&AH:&AH:&B%7&%<`&AH:10-'*BHJ
+M*B$J*BHJ*AI%+"P*+"Q'1T<J8AIB&F(:8AIB&F(:8AH:&QM8&U@;&QL;'!L;
+M&QL<&QL;&QP;&QL^'%,;/AP^&QL^&QL;&QL;&QL;'!L;&SX;1CX;&QL;&SX^
+M6%@@(%@@/B`@6"XN+CLN.RP*+C$Z.CHC,3$;)@PZ#`P,.@PZ.B,Z)B8F)CHF
+M)C`Z)C`[.SL[,",[.SLF)B8F,"8P(SLP,#`P,",[(S`P,#LF)B8P,"8F+C`P
+M.SL[.RXC(RXN,#`P,#LP.SLC,#`C(R,N+BP[.RPN+BXN(SLN+CL[(SL[.RPN
+M.S`[.SL[.SL[.SL[(SLN(R,C1DA(2"M(*TA(2#],3$Q(.BHJ*BHJ*AHJ&AHJ
+M&AH:&AH:&BXN+`PQ,4I&````````````````````.0`D`%<`5P!7.2175U=7
+M1U=75QA76%@</@PZ(`!'5P!'.2\8(3$L6``#*E<8*BHJ,3$Z"@PY5P``*A8J
+M*AHJ*BH:*AH:&AH:&AH:&AH:&AH:&AH:&AHA&%<8.1H:&AH:11HJ*BHJ*BH8
+M*BHJ6"P*+"P[.2\A&F(:8F(:8AIB&F(:8AIB&AM8&QL;&QM8&QL;&QP;&QL;
+M'!L;&QL<&QL<&SX;&QL;&T9&/AL^&QL;&QM*&QL;&QL;&QL;&QL;&R`@(!L@
+M&QL;6#XC(R,P+@HK"BXZ.CHZ(SHF5"8,)@P,##HZ.@PP.B8F)B8Z)B8Z.CHZ
+M.SL[.SLP,#`P.RXN+CL[(SL[.SL[.SL[)C`C.RXP.SL[.RPN+BX[,#L[.RX[
+M.S`[+B,P,#`P,#`P+#LN,#`P,"XC+B,N+C`P,",C.SL[(S`C(R,L+"P[(SL[
+M.SL[+CLN+BPN+#L[.RI(*TA(*T@K*RM(3$P_*SHA*BHA'"HJ*BH:&AHJ&AH:
+M&BHN"@HQ2DI&2@````````````````````!7`#E75SE75U=75SE7&!A'&$='
+M`%@@1CX#2C%8.0``5U<J5T98``!'5R%'%BHA*C`P+"Q*5T=75RHJ%BH6&BH6
+M&AH:*AH:&AH:&AH:&AH:&AH:&AH:1T<O5U<:&AH:&AHJ*BHA(2HJ*BHJ*AP*
+M"@HL.U='5V(:8AH:*F(:*AHJ(2$A5U<;6!M8&QL;&QL;&QL;&QL;&QL;'!L;
+M/AL;/AL;/CX^/AL^&QL;&QL^&QL^&QL;&QL;&QL;&SX<&QM8&QL;&QL;&R`@
+M+"PL"BL**PH*(S$Q,3HC(T8,##HZ.CHZ.CHZ,#HF)B8F)CHF.CHF)BXN+B8F
+M,#L[.SHF)B8F)B8P)B8F(R,C(SLN.S`N+CL[.R,C+CLN+CLN+BXN.R,P.RPN
+M+BXN.RXP,#`N+BPL+#`C(S`L+",[.SLC,#LC(R,C+BXN+",N(RXC.SL[.RX[
+M.RXN+#LL+"Q&3$@K2$A(2$A(2$A(2"LQ*BHJ*ALJ*BH:*AH:&A@`*AI'+"P*
+M2CY&,48```````````````!7``!7`%=7`%=75P!75U<8&%=75Q@8&``;1CX^
+M`%<^,1LY5Q@Y(1L*+```5P!'*BHA*BHF"BL*#%=7&!@J%BHJ&BH:&AH:&AH:
+M&AH:&AH:&AH:&AH:&AH:&D<`1T<Y&AH:&AH:&AHJ*BHJ5RHJ(2$;*PH**S`Y
+M5T='5T<Y1T<A1SE7.5<Y1SE'&U@;&U@;6!L;6!L;&QL<&QL;&QL;&QP;&QP^
+M'#X</AL^&SX;1AL^&T8;/AL^&QL;&QL;1CX;&QL;&QL;&QL;&QL;("PL+`HK
+M"BL*"B,Q,3$Z(R-&#`PZ.CHZ.CHZ.C`Z)B8F)B8Z)CHZ)B8N+BXF)C`[.SLZ
+M)B8F)B8F,"8F)B,C(R,[+CLP+BX[.SLC(RX[+BX[+BXN+CLC,#LL+BXN+CLN
+M,#`P+BXL+"PP(R,P+"PC.SL[(S`[(R,C(RXN+BPC+B,N(SL[.SLN.SLN+BP[
+M+"PL1DQ(*TA(2$A(2$A(2$@K,2$J(2HJ*BH6*BHJ&AHJ&QHJ&PHL+$9&2D9*
+M`````````````#D``%<``%<`5U<`5U=75U=75U='&%='1T<Y/B`</B\A(5=7
+M&UA'5SD^(RP8(5<:`!H:*A8:"@H**PQ7`%@8*BHJ&AH:&AH:&AH:*AH:*AHJ
+M*A8J(2\A1U<81R$85U<Y&AH:&AH:&AH:&AHJ*BHJ*BHA'"LK*RLF.0!'5U<A
+M`#E%10-%.3D#`P-'1R`@6!L;&QL;&QL;&QL;&QL<&QL;1AL;/AL^&SX;/AL;
+M&SX;/D8;/AM&4QL;&SX<&QL;&QL^&QL;&QL;&QL;&QL;&QLL+"P**PHK"@HC
+M,3$Q.B,C1@P,.CHZ.CHZ.CHP.B8F)B8F.B8Z.B8F+BXN)B8P.SL[.B8F)B8F
+M)C`F)B8C(R,C.RX[,"XN.SL[(R,N.RXN.RXN+BX[(S`[+"XN+BX[+C`P,"XN
+M+"PL,",C,"PL(SL[.R,P.R,C(R,N+BXL(RXC+B,[.SL[+CL[+BXL.RPL+$9,
+M2"M(2$A(2$A(2$A(*S$J(2HJ5RHJ*BHJ&BH:&AHJ&@`L"@HQ,4HQ1@``````
+M`````````%<``#E7`%=7.5=7.2175U=7&!@85QA'`!L;1@``(2$J*BHJ(2$:
+M&BH:&AH:&AH:&AH:*BXP*PI*.0`@`$=75Q@Y`%<`.0,`6```.0```%<Y)#D`
+M5Q@````A(5<`5RH:&AH:&AH:&AH:&AHJ*AHJ*DHK*RM(+CD8`#E71T='!@9%
+M!@8&`T4&13D@6"!8(!M8&QL;&QL;&QL;&QL;&QL;&QL<&QL</AM&1CX</AP^
+M/AP^&QP^&SX;&QL;&QL;&QL<&QL;&QL;&QL;&QL;+"PL"C](*RL*+`P,#$H,
+M.AL,##`C(R,Z.CH,,#HP)B8F)B8F)CHF.R,C(SLC(R8P.CHZ.CHF)B8F)B8P
+M.SL[+CL[.R8F)BXN+CLC,#`N.RXL+"P[+BX[(R,L+BXN+"PP+C`C.RXN+BPP
+M(R,C.R,P,#`C,",[.R,N.SL[.SL[(SL[(R,C(RP[+BXN+#LL+"P^3#\K*S\_
+M/S\_2$A(/RM*(2$J(2HA*BHA*BHJ*BHJ&BH`"BPK,49*1CX`````````````
+M``!7`````%=75P!75U=75QA'1R$A(2\A&%<;'#X@(2$A*BHJ&BH:*AH:&AH:
+M&AH`&AH:&D<N,"P*,0``(%<``"$````#.0!8'`,#!@8#`P,Y.5=7``!'````
+M1U<`5T<:8AIB&A`:&AH:&AH:&AH:&B%&2"LK"@Q75R$``"%'`T5%!@9%`P-%
+M!D5%("`@("!8(!M8&QL;&QL;&QL;&QP;1AL;/AL^&QL^&SX;2CX;/AL^&SX;
+M&QP;&QL;&U,;1AL;&QL;&QL;&QL;1D8;&PH*"@H**RP*"B,Z.CI*,0P^.C`,
+M#`P,)CHZ.C`Z,"8F)B8Z)B8Z.CLP,#`C,",P)B8F.CHZ)C`[.SLP.SL[.SL[
+M+C`N+BXF)B8P,#L[+BXN+BXN,#`P+BXN.R,C(S`[.RX[+C`[.SLC(R,[(RP[
+M+"PL(S`[.R,C(S`P,",N.SL[(R,C(R,L+BXL+"X[.SL[5#](*T@_/TA(2#\_
+M/S](1B$J6"I7(%<J*BHA*BH6*BH:`"PL"D9&1D8^``````!'5P!75T<A```8
+M1T<A5U='&%<85P,``R``6"```"!8(``@6!8A*A8J%BH:*AHJ*AH:&AH:&AH:
+M&AH:,3LK"C``5P`A1Q@A1P!8`P-8`T4&`P`&!@,Y!@,#5P!'````&`!7&!@8
+M&AH:&AH0&F(:&F(:&AH:&AH:'"L**RP,.1@A5T<A5SE%144#!@,Y145'!B!8
+M(%@@(!L@&U@;&QL;&QL;&QL;&QL;&QL;'#Y*&QM&/AM&/CX^/CX;/AL^&QL;
+M1D8<&QL;&QL;&SY&&QP;&QL;4QLL+"P*+"LK+",,5%14#"XC5#`F.CHZ.@PZ
+M.CH[.B8F)B8F)B8F.CHZ)B8F)CHZ.B8F)CHZ.B8N(SLN,",C(R,F,"8N+BX[
+M+BXN+#`P)C`N.S`P,#LP,#`N+CLL+"PC(R,[+"PP.SL[+BPC(SLC+CL[.RXC
+M.SL[(SLC(R,[(RX[(SL[.SL[+BX[+"PL+CL[.T8_/T@K/S\_/S\_2"L_2#$A
+M(2$A(2$A(2HA*BHJ*BHJ*A@*+@I*2D9*1B`;6%@^&QP`'!Q&1AQ8&T9&1AM8
+M(%@;'#Y&/AM&/EA&&UA81@`@(%A7%BHJ*BHJ%AHJ&AH:*AH:&AH:&AH:&C$L
+M2$@[(%@8&%<`1R%8`T4<`P8&```#!@`Y`P8Y10,Y(1A'5P```#E711IB&AIB
+M&AH:&A`:&AH:&AH:&AH**PH*)D<A5T<8(0`#!D4&108Y!D57!D4@("`@6"!8
+M(!L;&U@;&QL;&QL;&QL;&QL;&SX;'#X;1CX;/AP^&T94/AP^&SX;/AL;&SX;
+M/AP^&QL;&QL^&QL;/AL^"@H*"BPK*RPZ,#HZ.B8*"@PZ#`PZ.CHZ.CHF.CHF
+M)B8F)B8F)CHZ.CHZ.B8F)CHZ)CLN+BXN+C`[.RXP,#`P,#`C.R,N+BXN+CLC
+M.S`P,#`[.SL[,#`P,",P,#`P.RPL+"XN(SL[.RX[(R,C,"PL+"P[(SL[.SL[
+M.SL[.R,[(R,C(RXN+CL[+BXN+CL[.SL;/TA(2$@_2$A(2$A(2$A&(2$A(2$A
+M(2$A*B$J5R$J%BHJ"@HL2D9&2D9*,48^1D9&1AQ&1D9&'``;1AP<6%A8`QQ&
+M&QP^6#X;6!M8/B`@6!L`5U<J%BHJ*BHJ*BH@&BH:&AH:&AH:&AH,2"L_)@!8
+M``````!7`$4#!@,#!@8Y``8#.0-%144#!BI'*B]7&%=75QIB&F(:8AIB&F(:
+M&AH:&D8:$&)%,"X**RP`1U='5R%'1T4#145%!CD&`SD&6"!8("`@("`@($8^
+M&QL;&QL;&QL;&QL;&QL;&QL^&SX</CX;/CX^'#X^'#X;/AP^&SX;&QL^&QL^
+M'#X;/AL^/AL^&TA(2`H**T@*)B,*"@HL"@HC#"8Z)B8F.CHZ(SHF)CHZ.B8F
+M)CHZ.CHF)B8P)CHF)C`P,#`P+C`F.SLP,#`P,#`P,",C+CLN+BXN,#`N)C`P
+M,#`P,#`P(R,C(R,C(S`[+BPN+BX[.SLL(RXC.R,P.SL[.R,[(R,[.SL[.SLC
+M+BXL+"PL+"PC+"XC+CLN+"PL1C\_/RL_2$A(2"LK2"LK1B$`(2$Y(2$A(2$J
+M(2$J*BHA1PI(2$8^1D8Q1D8^`%A&'$8<'$9&'!P`6!P#'`,#'`,<'$9&1CX<
+M&QM8(%@@`%@``"I7*BHJ%BHJ*BHJ5QHJ&BH:&AH:&AH:2@HK2"L``"!85P``
+M5P,&`P,#!@,Y``,#.08#!@8&!D4Y5R$A(4<A`"$:&AH:&AH:&AH:8AH:&F(:
+M8AH:8E@Q,`H*/A@A5T<A`#E%!@8&10`&12$#12`@("`@6"`@6"`;/AL;&QL;
+M&QL;&QL;&QL;1DH;/AL;/AL^&SX</CX;/CX^/CX^/CX</CX^&PQ4/CX^/AL^
+M&SX;/AM(2$@**PI(*R,P*RLK*PI(#"8P,#L[.SHZ#",Z.B8F)B8Z.CHZ)CHP
+M.CHZ)B8F)CHP)BXN+B,F.RXF,#`P,#`P,#`P,",P(R,C(RXN+BXP,#`P,#`P
+M,",C.R,C(R,C(S`C,"PN+"PL.RPC(SLC(RXN+BPN+BPC.SL[.SL[(RPL,",L
+M+"PL+BPL+B,L+"PL+!M,3$A(2"LK*RM(2"M(2$I'`"$`(2$A(2$A("$A(2$J
+M(2HN*T@Q,4942CX^1AM8/D8#'!P<'`,#'!Q8`P,#'!P#'!Q&1AQ&/E@;6"`@
+M&P`;&Q@J(2H6*B$J%BH6*BHJ&A8:*AH:&AH:&E<_*RLK&R`@````(%A'109%
+M!D5%`P``109710,&`T4&!CE71R$A+P!7&F(:8AIB&F(:8AH0&F(:&AIB&AHY
+M,4HF,$I%(4<`(4=7109%108`5T4A.08@("!8("`@("`@(!L@&QL;&QL^2AL;
+M&QL;&QL;&QL;/AL;/AP^&SX^/DH^/AP^/AP^/CY&'#X^'#X^/CX^/CX^/CX^
+M/BLK"BL*"@HK+BPL+"M(2#`P,#`C(R,P.CHZ.B8F)B8F)B8Z,#H[,#HZ.B8F
+M)B8P+BXN+BXP(R,C,#`N(R,C+CL[.R,P,",C(R,N+BXN+CLC(R,P,#`P,",C
+M(R,C(R,C(R,C+BXN+CL[+B,[(R,N+BX[+#LN+B,[.SL[.R,C(RX[+CL[.RPN
+M+#L[.RPL+"P@3$Q(/T@_2$A(/S](/T@Z1T<;+R$A(2$A(2$A(2$A(2$A#"LK
+M.C$Q1D8Q/D8^1D8Q`QQ&1@,<'!L<'`,#'$8<`QP<'!Q&&T8@6!L;6!L@'#XJ
+M*BHJ(2HA*BHJ(2H65RHJ&BH:%AH:&AH:+$@**T985P`Y(``@144&`T5%!E<`
+M!@8Y144&`P-%`P``5QA7&$<Y&F(:8AIB&F(:8AIB&F(:8AIB&F(:8D9&2C`C
+M&U='`"%'`#D``"$D5P`8(0!7("`@("!8("!8("`^6"`;&QL;&QL;&QL;&QL;
+M&QL;&QL^&SX^/AL^'#X^1CX^/CX^/CX^/CX^/CX^/D8^/CX^/CXI2CX*"@HL
+M"BLK2"LL+"PK*RLC.CHF,#`P,#`C,"8Z)B8F)CHF.CHF.S`F)B8F)B8F)CLC
+M+BXN,",[.R,P+C`P,"8F)B,P)B8C(R,C(SL[+B,[.SL[(S`P+C`P,",C(SL[
+M(R,C,"XN+BXL+",N.SL[+BXN+B,C(R,C.SL[.R,L+CL[(RPL+"PL.R,N.RXC
+M+BXN2DQ,2#],/TQ,3#\_2$A(2D='1R\O+R\A(2$`(2$A(2$A(3$_2"Y&1E0^
+M1D8Q2D9&1@,<1AP#`QQ&'!P#`QP<'`,<'!P#'!P<1B!8(!L``!M8%B$J(2HA
+M*B$A*BHJ*BHJ%BHJ&BH:&B`:&CY("D@C````("`@`#E%!@,#144&`#E%!E<&
+M145%144#5P`8````.6(:8AIB&F(:8AIB&F(:8AIB&AIB&F(:##HZ,#$8`%<8
+M1P``5P`O1U=7`!A8)"`@("`@(%@@("!8/B`;(!L;&QL;&QL;&QL;&QM&&QL^
+M&QL;&QL^&SX;/CX</AL^/CY&/CX^/CX</CX^/CX^/CX^/CX^"@H*+`HK*T@K
+M+"PL*RLK(SHZ)C`P,#`P(S`F.B8F)B8Z)CHZ)CLP)B8F)B8F)B8[(RXN+C`C
+M.SLC,"XP,#`F)B8C,"8F(R,C(R,[.RXC.SL[.R,P,"XP,#`C(R,[.R,C(S`N
+M+BXN+"PC+CL[.RXN+BXC(R,C(SL[.SLC+"X[.R,L+"PL+#LC+CLN(RXN+DI,
+M3$@_3#],3$P_/TA(2$I'``!'+R\O+R\O(2$A(2$A(2$`/S\N2D9&1D9*1D9&
+M1C$#`QP#'`,<'!P<`QP<'!P#!D4#`P,<'#X@```@6``;1R$A(2$A(2$A5R$6
+M(2$J%BHJ%BH6&BH:2AI7*T@*"AL``"``(``#145%109%`````Q@#145%!D4`
+M1U<`&```.6(:8AIB&F(:8AIB&F(:8AIB&F)B&AIB&ALP+BPC1@!7&!@`5U=7
+M1U<``"0Z"D8@("`@("`@("`@("`@(!L@&QL;&QL;&QL;&QL;&QL;&QL^&SX;
+M&SX;/AL^/CX^/AP^/CX^'#X^/CX^/CY&/CX^1BD^/@H*"BP**RM(*RPL+"LK
+M*R,Z.B8P,#`P,",P)CHF)B8F.B8Z.B8[,"8F)B8F)B8F.R,N+BXP(SL[(S`N
+M,#`P)B8F(S`F)B,C(R,C.SLN(SL[.SLC,#`N,#`P(R,C.SLC(R,P+BXN+BPL
+M(RX[.SLN+BXN(R,C(R,[.SL[(RPN.SLC+"PL+"P[(RX[+B,N+BY*3$Q(/TP_
+M3$Q,/S](2$A*1T='&"$O+R\O+R\O+R$A(2$A(2X_*T8^1CY*2D9&/D9&`T4#
+M'`,#'$9&1@,#1D8#'!P<'`,#'!Q&6````"`;(%<A(2$A(2$A(2$A(2H6*B$J
+M%BHJ*BH6*AHJ&D8*+BP,```@``!7)$4`5P``1P``4@```$<A5P`8)`!'&%=7
+M```:&F(:&F(:&F(:8AIB&AH:8AH:&AIB&AH06#`P+C``5U<8``!7(5='5SE7
+M1DI8("`@("`@("`@("`@(!L@&SX;&QL;&QL;&QL;&QL;&QL;&U,;&SX;&SX;
+M/AL^&SX^&SX;/CX^/CX^/CX^/CX^/BDI/CX*"D@*+"L**RLK*RLK2"LZ,3HC
+M,#`P(SLZ.S`Z)B8F)CHZ,"8Z.CHF)B8F.B8F+CL[+BXN(R,[+CL[,"8F)B8F
+M,#`C,",P,#`P.RPN.R,C(R,C+C`P.RXN,#`P,",[.SLC(RX[.SL[(SLL+"PL
+M.SL[+",C(SLN.SL[.RPN+CLC+"X[.SL[.RXN.RX[.SL[1DQ,2$@_3#\_/TA(
+M2#],+D='1QA'+R$`+R\`+R\O+R\O(2%&2$@F1D8Q,49&1D8Q'!P<1AP<'`,<
+M1AP#`QQ&`QP<'!P#`U@^&SY8&P!8($<A(2$D`"$A(2$A(2$A(2$A5R$J%BH6
+M*BH6*A8:,2X*"CX````@``!'`%<`)$<``````%=')"%7`%<`5U<A5R%'&AH:
+M&AH:&AH:&F(:&@-B&AH#&F(:&F(:&AH`.B8F,0`8&$<8)$=8"BP[,$881R`@
+M("`@("`@("`@("`@&R`;(!L;&QL;&QL;&QL;&QL;&QL;&QL;/AL^&SX;/AL^
+M&SX^/CX;/CX^/CX^/CX^/CY&*3Y*"@H*"@H*"BL**RLK2$@K.S$C)B8F)C`P
+M.CHP.CHZ.CHZ.B8Z.CHF)B8F)B8F.SL[+BXN+C`C.RXC)B,F)B8F)C`P,#`P
+M,#`P,#`N+BPN.RXN+BXN+"XN+#`C(R,[.SL[.S`L.SL[.RPN.RX[+"PL+"PL
+M(R,N+BXL+"PN+B,[(RX[.SL[.RXN+CLL+CL[.SY,3$A(2$A(2$A(2#],3#%'
+M1T<8&$='1R\A1R\O+R\O+R\O+PI(+$HQ2D9&1BE*,1P#`QP<'`,#'!P;`QQ&
+M1@,#"$4&`P,<6!M8(#X`(``A(2$A(2$A(2$A(2$A(2$A(2$J(2HA*A8J*A8J
+M*A@Q+BXZ`"````!7&"0``"!75Q@``!LQ1AA'&"085P!7(1H:&AH:&AH:&AH:
+M&AH:&AH:&AH:&AH:&AH:&AH:&@!*.C`,`!A'5P!7`$8**T@K5U<@("`@("`@
+M("`@("`@("`@/B`@&QL;&QL;&QL;&QL;&QL;&QL;4QL;&QM3&SX;/CX;/AL^
+M/AL^/CY&1CX^/CXI/E0^/BPL"@H*"@H*"BLK*T@K"@I&.C`C(R,F)CHF.S`Z
+M.CHZ.CHZ.CHF.B8F)B8Z,#LN.R,P,#`[(R,C+B8F,#`P,#`C,#`P,#`P,",P
+M,#`P+"XL+"PC+BPL+BXL,#`P+B,[.SL[+"XN+CLC(SLL(RXC(R,L+",L+"X[
+M+"PL+",C.SLL.R,C(RXN+BX[+"P[.SL83$Q,2$A(2$A(2$Q,3$Q*&$='&!A'
+M``!'1R$A(4<O+QL`+R]&*RLF2D9*2D9&,49&10,#"`,#'$8^'`,#1CX<`P98
+M6!M&/AL`(!L;6!LA(2$A(2$A(2$A(2$A(2$A(2$A(2$6*B$J%B$J%BH61PPF
+M(S$@`"```%<`(```)%<Y`"1&#"-7)```5Q@D`"$:&AH:&AH:&AH:&AH:&AH:
+M&AH:&AH:&AH:&AH:&AH:(0`;,0P;5Q@`1P`,*T@*"E<`("`@("`@("`@("`@
+M("`@($H@&R`^&QL;*1L;&QL;&QL;&QL;&QL;4U1&4QL^&U,;/AL^&SX^&SX^
+M&SX^/CX^1BE41CXK*T@K*T@K"BLK*RLK"BLN2CHZ.CHZ.B8F,"8P,#HZ.B8Z
+M.CHZ.B8Z.CHF.CLC,#`P(R,C)CLC(R8F,#`P,#`P,#`P(S`P,#`P,#`P(R8L
+M+BXN,#`[+#LN.R,C(SLC.R,[+BXL+"P[+#`N.RXC(R,C.RPL+"PL(R,C(RPL
+M+"PL+#L[.SLN+BX[+"X[.SL[2DQ,3$Q,/TQ,3$Q,3#],.AA'1Q@8($='1T='
+M1P(A(2%'+R$O`@P**S%*,49&2D9*/AP<'!P^'#X</E@^1D9&'$98&UA&&QP@
+M`"!8/AL8+R\O+R\O+R\O+R$A(2$A+R\@(2$A(2$A%E@6(2H6*A9&)C`P,0``
+M)%<D````5RI'2CY8+T<O5P`8```8(2$:&AH:&AH:&AH:&@`8&AH:&AH:&AH:
+M&AH:&AH:&AH:&AH:&CD;!AL#(4<Y/CHL+"Q'1R!2("`@("`@("`@("`@("`@
+M("`@2B`;&SX;&QL;&QL;&QL;&QL;&QL;&U-&&QL^&SX;/AL^&SX;/CX;/AL^
+M/CY4/CX^"@H_/TA("@HK2$A("DA(*T8,.C`P,#HF)CLF,#L[.SLC.R8Z)CHF
+M)B8F.C`[.SLF)C`P,"8P)BXF,#`P,#`P)B8P)C`P,#`P,#`C,#`P,"XN+BXP
+M,"X[(S`C(R,[(R,N+"X[+BXN+BPL(RXN(SL[.SLN.R,N+BPL+"PL+"PN.RX[
+M.SL[.RXL+"XL(SL[.T9,3$Q,3$Q,3$Q,/S],3$H8&$<80AM'1T='1T='1T='
+M`"$"(2$D,`HN,4I&2D8Q/D9&&SX</D8^&SX;'#X^/CX^/AL@1CX^&R18&U@@
+M`"\O+R\O+R\O+R\O+R\O+R\O+R\O+R\A+R$D(2$A(2$A(2H^)CI*`"1'```@
+M5U=7`"8K"C`;5U<81P`D+QH:&AH:&AH:&AH:&AI7&!H:&AH:&AH:&AH:&AH:
+M&AH:&AH:&AH:&AH:&F(:&AI'&@-B&D<@("`@("`@("`@("`@("`@("`@("`;
+M&QL;&QL;&QL;&QL;&QL;&QL;&PP;4U,;4QL;/AL^&U,^/AL^/CX^/CX^*2D^
+M/BPL/S]("@HK*PH*"DA(*TA*.@PC(R,Z)C`F)B8P)B8F,#`F.CHZ)B8F)CHC
+M(SLF)B8[.SLP,#`[,#`P,#`P,"8P.R,P(S`P,#`C,",P(S`L+"PC+BXN,#`C
+M(R,C(SLC+BP[+"PL+"P[+CL[.R,[.SL[+CL[+BPL+BXN.RPL+"PL+BPL+"PL
+M+"PL+",[.SM&3$Q,3$Q,/S\_/S\_3$P,&$=2&$(8&$='1T='1T='1T='1T='
+M(0`N"CI*2D9*1D8^1EA&/D8^1B``&T8^,2X[&U@;1B`^'!L`&QL@`"\O+R\O
+M+R\`+R\O+R\O`$<O1T='+R\O+R\O+R\A(2$A(2$A(0`;,4HY&%<`)%=7)!LP
+M.RPN/@```!8`+R$6&AH:&B`:&AH:&AHJ&AH:&AH:&AH:&AH:&AH:%A86%AH6
+M&AH:&AH:&AH:8AIB&F(:8AIB4@`@&R`@("`@("`@("`@("`@("`;("`@&QL@
+M&QL;&QL;&QL;&QL;&QM4&QL;&QL;4QM3&U-&&QL^&SX;/AL^/BDI/CXL+#](
+M"@HK2$A(2$A(*S](2@PF(R,C)B8[.R8P.SL[.S`C)B8F.B8Z.CHC+B,[.SL[
+M.SL[.SLP,#`P)C`P,#`P(R,F,",P,#`P,",C(S`C,#`P+"XN.R,P,#`P,#`C
+M.RXL+"PL+"PC(RXL+#L[.SL[.SL[(RXN.SL[.R,C.R,[.SLL+"PL+"PL+",[
+M.SL[/DQ,3$Q,/S\_/S],3$Q,2A@8&$HD0A@81T<81T='1T='1T='1T='`",*
+M.DI*1C$I'$H^/CY&&QM75QL^1AM&)C$;&U@</B!8(```+R\O1R\O+T<A+T<O
+M+R\O+R]'1T='1R]'+R]'+R\O+P`A(2$A(2$A(1@`&QL`````5U=*"@HL.AL`
+M``!'(2$A%A8:%AH6&AH:&AH:&AH:&A@:&AH:&AH:&AH:&AH6%A86*A8:%AH:
+M&AH:&AH:8AIB&F(:&D0@1"``(!L@("`@("`@("`@("`@/B`@("`;&QL;(!L;
+M&QL;&QL;&QM4&QL;&QL;&QL;&QM3&U-4/AL^&SX^&SXI/CX^"@H_2`H*"BLK
+M2$A(*S\_/THP(R,C(R8[(S`F,#`F)B8C.CHF)CHZ.SL[.RXP(SLF)CL[.RX[
+M+CLF,#LF)B8P.S`[,#`P,#`P,#`P,",C(S`P,"PN+#LC,#`N+BX[.RPL+BPP
+M.SL[.RXL+",C(R,C(R,[(R,[(R,C(R,[.SL[.SL[.SL[+"PL+",[+BPL+`!,
+M3$Q,/TP_/S],3#\_3#!7&!A"0B1"&%(81T<81T='1T='1T='1T<`#`H,1DI&
+M&SY&&QP;/B`A&QL81CX81Q@`&U@;/E@;`!L8+T<`1R\O1R\O+R\O(2\A+T='
+M1T='1T<O+T<O1U(;1R\;(2$A(2$A(2$A(2]2+R$D)``D+R0^##H"0D<A+R$O
+M(2$A%AH:&AH6&AH6&AH:&AH6&A@:&AH:&AH:&A86%B$6(20A%AH:&AH:&AH:
+M&AH:&AH:&AH`1`!21"`;("`@("`@("`@("`@(#X@("`@("`@(!L;&SX;&QL;
+M&QL;&QL;5!L;&QL;&QM3&QM3#!M3&U,;/AL^/BD^/@H*/T@*"@HK*TA(2"L_
+M/S]*,",C(R,F.R,P)C`P)B8F(SHZ)B8Z.CL[.SLN,",[)B8[.SLN.RX[)C`[
+M)B8F,#LP.S`P,#`P,#`P,#`C(R,P,#`L+BP[(S`P+BXN.SLL+"XL,#L[.SLN
+M+"PC(R,C(R,C.R,C.R,C(R,C.SL[.SL[.SL[.RPL+"PC.RXL+"P`3$Q,3#],
+M/S\_3$P_/TPP5Q@80B0D)$(8&!@8&$<81Q@8&T='1QA'1T<;,#I&2D9&/AL^
+M```@&$<A`"XL+C$@6"``&SX@("``1R$A`B$A1R$O1R%'+P(O+R\O1T='1T='
+M1T='1T='4D='1R\O+R\O+R\A(2\O+R]'+R\O+R]'+T<O+R$A(2$O(4<A+Q86
+M%BH6&A8:&A8:&A8:&AH:&AH:&AH:%AH6%B$6%A86%A86%A8:5U<8&AH:&AH:
+M&AH:4@!$(`!$("!$("`@("`@("`@("`@("`@("`@("`@(#X;(!L^&QL;&QL;
+M&QL;5!L;&QL;&QM3&QL;4QM34QM3/CXI/CX*"C]("@H**RM(2$@K/S\_2C`C
+M(R,C)CLC,"8P,"8F)B,Z.B8F.CH[.SL[+C`C.R8F.SL[+CLN.R8P.R8F)C`[
+M,#LP,#`P,#`P,#`P(R,C,#`P+"XL.R,P,"XN+CL[+"PN+#`[.SL[+BPL(R,C
+M(R,C(SLC(SLC(R,C(SL[.SL[.SL[.SLL+"PL(SLN+"PL`$Q,3$P_3#\_/TQ,
+M/S],,%<80D(D)"1"&!@8&!@8&!@`4AA'&$='&$<81T<;#$8^1AL<1CY8``!'
+M1T<*+`H*(!M8/E@;("0`1R%'1R]'`B%'1R]'+R$A1R]'1T='1T='+QM21T='
+M1T='1T='1T<O+R\O+R\O+T='+T<O+T<O1R\O+R\O(2\O(4<A+R\A(2$6*BH:
+M%BH:%AH:&A8:&BH6&A8:%AH6%B$A%B$6(186(186%A8:5QH:&B`:&AH:(%)2
+M`%)2(`!2("`@("`@("`@("`@("`@("`@("`@("`@("`@/AL@&QL;&QL;&QL;
+M&QL;&QL;&QL;4QM3&QM3&U,^2CX^+"P_2`H**TA(*RLK/S],/S$P(S`P,#H[
+M.R8[.CLZ.CHP.B8F.C`F.SL[.R,N.SLF)BXN+BX[.SLN+CLP,#`F(SLN)C`P
+M,#`P)C`P,#`[(S`P,#LN+"PP(R,[.SLL+BX[+"PL+"PL+BXN+"PL.RPL+#LC
+M.SL[.R,[.SLL+"X[.SL[+BXN+"PL+"PL+BPL+$H_/S\_/S\_/S\_3#],3$I7
+M5T(D)"0D)%<8&!@8&!@8&!@8&!@8&!@81QA'1Q@"1D8;/AM&/AL;)$='"@HK
+M(P`@("``($='1T='1T='(0!'1T='1T='1T='1T='1T='1T=21T<81T='1T='
+M1U)'1T='1R]'1T='1T='1T='1R]'+R\O+R\A+T<A(2$A1R$O(186%BH6*AH6
+M&A8:&A86%A86%A86%A8A(186%A8A%A86(186%D(:&AH:&AH:&AH`4E(`1%(@
+M1%)&&R`@("`@("`@/B`@("`^("`@("`@("`@("`@("`;(!L;&QL;&QL;&QL;
+M&QL;&QL;&QM3&QM34SXI/B,C/RLK"BM(2"LK*TA,/TQ4,#`Z.CHC,#HP,"8[
+M(R,C.B8F)B8F)CL[.SLN,#`F)C`C(R,F)B8[.RXN)B8F,",L.RXN.RXN+B,C
+M(RXP(SLP,#`[.RXL(SLC.SL[(SL[+"PL.RPL+",[(RPL+"PL+"PN+#L[+BX[
+M(R,C(SL[.R,C+BPL+"XC(RX[(RXL+"PZ/S\_3#\_3$Q,3$Q,/S\I5R!"0B0D
+M)"08&!@8&!@8&!@8&!@8&!@8&!@8&!A'1QA'`!L^&T8;&R!'1QLL"DH``"!7
+M`$='1T='1T='1T='1T='1T='1T='1T='&!A'1T='&QA'4D='+T<O1T='1T='
+M1P!'1T='1T='1R]'+T='1R]'(4<O1R\A1T<O1R%'(2$A(186%A86*A8J%BH6
+M%B$6(2$A(2$A(186&A865R$6%B$6%A97&E<:&AH:&AH:4@!24@!24@`@&U(@
+M1"`@("`@("`^("`@("`@("`@(#X^("`@("`@("`@&R`;&QLI2AL;&QL;&QL;
+M&QM3&QM3&SY4/CXF)C\K"@I(2$@K*RM(3$P_2C`P,#`P)CHZ.S`Z.S`P,#`P
+M,#HF)CHN+BXC.S`[.SLN)B8F,#`F+CLP+BXN+B8C.R,N+"XN+BXN+#LC+C`C
+M(R,C(RXC+BPN+BPL+"XL+BXL.SL[.SLC.SLC+BXN+"PL+CLN(SLL+"PL+"PL
+M+",C+"PL+"P[(RPN.SLC+BXN2C\K/S\_3#\_/TQ,/TA(1B0@5T(D)"0D0E="
+M5T)"5T(80E<85Q@8("`8&!@8&!@8&!A2&``@`$8D1T='1P!'&$='1T='1T='
+M4D9'1T='1T='1T='1T<8&!@8&!@81T='1Q@8&$='1T<O1T='1T='&!A21T<8
+M1T='1T='+T='1R]'+T<O1R]'+R\O1R%'(4<O(2$A(2$A%A86%A8A(2$A(2$A
+M(2$A(186%A8J(3X6%B$A%A8:%AH:&AH8&AH:&E)2`%)2`%)2(%(@1"`@1"`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@&R`;&R`;&QL;&QL;*1L;&QL;
+M&QL;4SX^.SL_/RL*2$@K"@H*2#\_2"DF(SHZ.CHF.CH[.CH[.SLC,",[.SHZ
+M.SL[,#LF+CLF)C`P,#`P,",[+C`N+BXP,"PP(R,[+BXN(RXL.SLL(S`P,#`N
+M+BXN.RPN+BXL+"PN+#LL(R,C(SL[.R,[+"PL+"XL+#LN.SLL+"PL.RPN+#LL
+M"@H*(SL[+BX[.RXN+AM(*RL_/TQ,3$Q,/RM(2$I75T)"5R0D)$)"5T)70D)"
+M0D(80AA"5Q@@&%<8&!@8&$)"0A@8&!@8&!@81QA'&$='`$='1T='1T<`1P`;
+M&$='1T='1Q@8&$08&!@8&!@8&!@8&T='1T='1T='(4='1T='&!A'4D='1T='
+M1T='1T<O1R\O1R]'+T<O1R%'(4<A1R$O(2$A+R\A(2$A(2$A(2$O)"$6%A86
+M&AH6%A86%A8A(2$6%AH6%AH:&A8:&AI2`%(`4E(`4E(`1``@4B`@1"`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`;(!L@&QL;&QLI&QL;&QL;&U,;
+M4R8F/TA("DA(*PH*"BLK*RM*.CH[.SLZ.CHZ.B,F.CHZ.SLC,",[,#L[.S`[
+M)CLC)B8P,#`P,#`P,",C,#`P.RX[+BXN+BPL+#L[+"PL.S`P,#`P+B,P(S`C
+M,#`P.RPL.RXL+",C(R,C.R,C.RXL+"PL.R,C+CLN(R,C(SL[(RXL+"PL+#L[
+M.SLN+BXL+"P@+`H**S],/S\_/S],2$@@)"0D)"0D)"0D)"0@("!7)%="0D)"
+M5T)70E<8&"`8&$)"0B0@0D)"&!A"&!@81QA'&%(81QA'1QA'2D='1T='&!A'
+M1T='&!@8&!A'&!@8&!@8&`!'&$='1T='1T<O1T='&$<8&!@8&$='1T<81T<O
+M+R\O1R]'+R\O1R]'+T='+T<O1R]'1R\O+R\O+R\A+R\O(206*A86%A86&AH6
+M&A86%B$A(186%A86%AH:&AH64E)24@!24@!24E)2($0@4B`@("`;("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@&R`I(!L@2AL;&QL;&QL;&U,Q,3](
+M2`HK2`HK*RL*"@HK2B8Z(R,C.CHZ.CHC,#HZ.CHF.CHC)CHC(R,F.S`C(R8F
+M,#`P,"8P,"8C+B,C(SLL+BPN+#LN+BX[+"PN.SLL+"PL+"XN.R,C,",C(R,N
+M+BPC.SL[.SL[.R,C+BPL+BXN+"X[.SLN+BXN+CL[+CLC+"PL+"PN.RXL+BXN
+M+"PL`"PL+@I(/S\_/TA(3$Q,2B`D)"0D)"0")"0D)#XD)"0D)"0D)"1"0D)"
+M0E="&$(8)"0@/B`D)$(D0D(8&!@8&$<81QA'&$='1T<81Q@81T='1T='1Q@8
+M&!@81T<8&!@8&!@8&$='1T='1T='1R]'1T='1T='1T='1T<81T='`B\O+R\O
+M+R]'+T<O1R]'(4<O1R\O+R\O+R\O+R\O+R\A(2$A%A86&AH:&A8:&A8:%A8A
+M(2$A)"$A(206%A86&E(`4@!24@!24E(`4E(`4B!2($0@("`@("`@("`@("!&
+M2B`@("`@/B`@("`@("`@("`@("`@(!L@&R`@&R`;&QL;&QL;&S$_*T@*"BLK
+M*RLK"@I(/THF.CHZ.B,Z.CHZ,"8[.SLC.CHZ.CHP,#`P,#LN,",F)C`P,#`P
+M)C`P)BXC(R,L.R,N+BX[+BXN+BXL+"PL+CL[.RXL+"XP(R,C(R,L+#LN+",[
+M.SL[.R,C(R,N+"PL+"PL+",[+BXN+BXN+CLL+"PL+"PL(RPN+BPN.RPL+!M(
+M+`HL"BM(2$A,3$Q,3$HD)"0D)"0D`@("`B0D)"0D)"0D)"0D)"0D)"1"0B1"
+M&$)")"0D)$(D)$)"&!@8&!@8&!@8&$<8&$<81T='1QA'&$='1QA2&$(8&!@8
+M&!@^/D(8&!@81QA'1T='1T='4@!'1T='1T='1T='1T='1R]'+R\O(4<O+R]'
+M1T='+T<O1R\O+R$A(2$A(2\A(2$A%A86%A8:%AH6&A8:%AH6&A86(2$A(20O
+M+R$A(2$A%AI24@(`4@!2`%(`4AM24E(`1$0@4B!$("`@1"`@("`@("`@("`@
+M("`@("`@("`@("`^/B`@("`@("`;("`;(!L;&QL;&QL^/T@_*PH**PH*"BM(
+M/TA*)B8F)B8Z.B8Z.CLF)B8F)B8C.B8F)CHZ.BX[.SLZ)B8P,#`P,#`P)CL[
+M+BXN+B8P+"XL+BXN+B,P.RXC,#`P,#`C.RXP,#`C.SL[+B,N.RPL+",C(R,L
+M+B,N+"PL+"PL+"PL+",C.SL[(R,C+"PN+CL[.RP[+BXN+CLL+"Q*3$@*(PI(
+M/S\_3$Q,3$P,)"0D)"0D)`("`@)24E("`B0D)"0D)"0D)"0D)"0D0D)")"0D
+M)$)"0D)"0A@8&!@8&!@8&!@81T<8&!@8&!A'1T<81T='&!@@0A@8&!@8&$(8
+M&!@8&!@8&!A'1T='1T='1T<A1T='1T<81QA'1T<O+R\O+T<O+R]'1T='+T='
+M+T<O+R$O(2$A(2$A(2$6%BH6%A8J%BHJ%AH6&A8:&A8:%A86(2$A(2$O+R\A
+M(2$6`@!24E)24E)24E(`4E(`4E(`4D12(%(@1"`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@(!L@&R`@&R`;&QL;/C](/RL*"BL*"@HK2#](2B8F
+M)B8F.CHF.CH[)B8F)B8F(SHF)B8Z.CHN.SL[.B8F,#`P,#`P,"8[.RXN+BXF
+M,"PN+"XN+BXC,#LN(S`P,#`P(SLN,#`P(SL[.RXC+CLL+"PC(R,C+"XC+BPL
+M+"PL+"PL+"PC(SL[.R,C(RPL+BX[.SLL.RXN+BX[+"PL2DQ("B,*2#\_/TQ,
+M3$Q,#"0D)"0D)"0D)"0"`@("`@)2`@(D)"0D)"0D)"0D)"0D)"0D)"0D0D)"
+M0A@80A@8&!@8&$(8&!@8&!@8&!@8&!@81QA'&$<8&!A"0D(80AA"0A@8&$<8
+M&$<8&$='1T='``!'1T='1T='1Q@81T<O+R\O+P(O1R\"1R]'1T='1T='+R\O
+M+R$A(2$A(2$6(2$6*A8J%BH6%A8J%AH6*A8:%BHJ%A8A(2$A+R$O(2\A%@)2
+M`%(`4@!2`%)2&U(`4E)24E(`4@!$4B!2($0@($0@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@&R`;(!L;&SX_2#\K"@HK"@H**T@_2$HF)B8F)CHZ
+M)CHZ.R8F)B8F)B,Z)B8F.CHZ+CL[.SHF)C`P,#`P,#`F.SLN+BXN)C`L+BPN
+M+BXN(S`[+B,P,#`P,",[+C`P,",[.SLN(RX[+"PL(R,C(RPN(RXL+"PL+"PL
+M+"PL(R,[.SLC(R,L+"XN.SL[+#LN+BXN.RPL+$I,2`HC"D@_/S],3$Q,3`PD
+M)"0D)"0D)"0D`B0@)`(D`E)2&P("(`("`@(")`(D)"0D)"0D)$(80E<80A@8
+M0A@85T(8&!@8&!@80A@8&!@81QA'1T='&$<8&$)"0D)"0AA"&!@81T<8&$='
+M1T='1T='1T='1T='&!@8&$='1R]'+R]'+R\O1P)'+T='1T='1R%'+R$O(2$A
+M(2$A(2$A)"$6%A86%BH6%A8J%BH6%A86%A86(2$A(2$O(4<A(2$``E(`4@)2
+M4E)24@!24E)24@!24E)24E(@5$9$(%(@1"`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@&R`^/S\_*PH**RLK*PHK*RL,)C`F)B8Z.B8F.R,P
+M(R,C,#LF+CLZ.CL[.SL[.R,P)B8F)B8P)B8P,#LC,#`P)B8F.RXC(R,C(R,C
+M.RPP,",N+BX[,#`C(SLC+"PL.RX[(R,N+CL[.RPN+CL[+BPL+"PL+",[+BXC
+M.SL[+BPC+BPL.RPL+"PN(SLC.R,L+"PC3$PK+"PK/S\_3$Q,3$Q4)"0D("0D
+M)"0D)"0D)`(D)`("4E)2&U)2`B0D)"0D`@(")`(D)"1"0D)"5T)"0A@^(!@8
+M5Q@8&"`8&!@8&!@81QA'1QA'&!@8&$)"0AA"0D(8&!@8&!@8&$='&$='1T='
+M1T='1T='1T<8&!A'&$='+R\O+T<O+T<O+R]'1T='1T='+T<O+R\O(2$A(2$A
+M(20A%B$A*A86%BH6*A8J%BH6*A8J%A8A%B$A(2\A1R\O`@(``@(``@!&`@!2
+M&U)2`%)24@!24E(`4AM2`$0@4B!2($0@1DI$("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`;/C],2`HK"BL*"@H*"@H*)B8F,#`P)CHF(SLC.SL[.SL[
+M.SHF.CLC(R,C,#LP.R8F)B8F)C`P)C`P,#`P,"8P(S`C(SLN+BXC(RXN(R,P
+M+BXN.S`C(R,[(RPL+"XL(SLC+"PN+BX[(RPL+#LN+BXN+"P[+BPN(SL[.RXN
+M+"P[+BX[.SLL+"PL+"X[.SL[2DQ,2`HL*RLK*TA(2$A(2@(")"0")"0D)"0"
+M)"0D)`(D)"0D)"0")"0D)"0D)"0D)"0")"0D0D)"0D)"5T)70D(80A@8&$(8
+M&!@8&!@81QA'&%)'&!A'&!@80D)"0A@80AA"&!@8&!@81T<81QA'1T='1T='
+M1T<8&!@8&!@8&$='1R\O1R]&1T='1T<81T=21T<O+R\O+R\O(2$A(2$A(2$A
+M(2$A(2$6%A86%A86%A86%BHA(2$A(2\O+R\O+R0"`@("``("`E("`E)24E)2
+M4E)24@!24E)24E)24E)2(%)$(!M$("!$(#X@("`@("`@("`@("`@("`@("`@
+M("`@/AL@("!,/PHK"@H*"@H*"BL*"B8Z)C`P,"8F.CHF(R,Z.CHF.CHZ)B8N
+M.SL[.RXN.R8N)B8F)B8F,#`P,#`P,#`P,#`[.SLN+"PL.R,N,#`P(R,C(R,[
+M(SL[.R,N+BX[+CLN+BXC(R,C+"PC.SL[.R,C(R,C+"PN+",L+"PN+CLN+"PL
+M+"PL+#LL+"PL.RXN+C%,/TQ(*RPK*RL_/S\_3#$"`@("``(``@`")`("``("
+M)`(D("0D)"0D)"0D)"0D)"0D`B0D)"0D)"0D0B1"0D)72E<80D)"0A@8&!@8
+M&!@8&$<8&$<81T<8&"`D0D)"&!@8&!A"0A@8&$<81T='&$<81QA'1Q@81Q@8
+M&!@8&!A'1R%'1R%'1T='1T<81QA'1T='1R\O+R\O+R\O(2$A)"$A(2$A(2$A
+M%B$A(2$A(2$A(2$A(2$A(2$O+T<O1R\D)``")`("&T8@`E)2``(``@!24@!2
+M4E(`4@!24E)24E)2($1$($0@1"`;("`@("`@("`@("`@("`@("`@("`@("`@
+M(!L@2$@K"@H*"@H*"@H*"@HF.B,P,#`P,#`Z.S`F,#`P.B8F)CHF)B8F)B,C
+M(RXP)CLF)B8F)B8P(R,C(R,C,#`P.RX[+BXN+BXN+"X[,#`P,#`C,#LN+BX[
+M.SL[.R,[.RXN+BXN+BX[+BX[.RPL+"PN+"PL+#LC+BXN+"PL+BPL+"XN+CLL
+M+"PN+BPN+BX^3$A,/S](/S\_3#\_3$PZ`@("`@("`@("4@(;`@("`@(D`B`D
+M)"0D)"0D)"0D)"0D)"0")`(D)"0D)"1"0D)"0D)"0D)"0A@8&!@@&!@`&$<8
+M1Q@81T<8&!@80D)"&!@80D(80D)"&!@8&$<8&$='1T='1Q@8&#X8&!@80A@@
+M&$='1T=21T='&!@81QA'1T<O+R\O+R\O+R\O+R\O(2$A(2$A(2$A(2$A(2$A
+M(2$A(2$A(2$A(2$`+R\O1P)')"0D)"0D`B0"`@(``@("`@("``)24@!24E)2
+M4E(`4E(`4E(`4D124B!$1$1$("`@1"`@("`@(#X@/B`@("`@("`@("`@(`HK
+M"BLK*TA(2$A(*PH*.SHF)B8F,#`P)B8Z(R8F)B,F.CHF)B8F)B8P,#`C)C`F
+M,#`P)B8P,",C(R,C(R,P,"8P.RXN+BXL.RP[+BPN+BXN+BPC(SL[(R,C(RXN
+M.SLN+BX[.SLN.SLN+B,L+"PL+CLC.R,[.SL[.R,C.RXL+"X[.SLN+"PL.RPC
+M+"PL&$Q(/TQ,3#\_/TQ,3$Q,&P)24E)2`@)2``("&P("`@`"`AL"`B0D)"0D
+M)"0D)"0D)"0D)`(D&P("`@(D)"0D0D)"0B0D0D)"0A@8&!@8(!@8&$<81QA'
+M&$<80D(D0D)"&$)"0D)"&!@8&!@81QA'&$<8&!@8&$(8&!@80AA"&!@8&$<8
+M1Q@8&!@8&$='1T='1T<O1R\O+R\O+R\O+R\O(2\A+R$O(2$A(2$A(2$A(2$A
+M(2$A1B$A)"\A+T<O1R0D`"0D`"0D)`(``B0"`@("`@("4@!2`@!24@!24E(`
+M4E)24E(`4B!2($0@1$0@1"!$("`@("!3("`@("`@("`@("`@("`C*RL**TA(
+M2$A(2$@K"CLQ.CHZ.CHZ.B8Z.B8C(R,F,#L[(R8C.CHZ)BX[(R,P)C`P,"8F
+M,#`C(R,C(R,P,",L(R8L.SL[+C`N+"PN+"PL+"X[(S`C,#L[.SL[+CL[.R,[
+M.SL[.SL[.RX[+"PL+"XC(SLN.SL[.SL[.SL[.SL[(R,C.SLL+"PN+CL[.T8_
+M/TQ,3$Q,3$Q,3$Q,3$HQ4E)24@!24E)24E(;4@("`@)2`@(``B0D)"0D)"0D
+M)"0D)"0D)"0D)"0")"0D)"0D)$(D)"1"0D(80AA"0AA"&"`8&!A'&$<8&$)"
+M0D)")$)"0D)"0D(@0A@8&$<81Q@8&!A"0D)"&!@8&!A"&$(8&!@8&$)"&$<8
+M1QM'1R%'+R]'1R\O+T<O+R\O+R\O`B\O+R$O(2$O(2\A(2$A+R$A+R$A(2$A
+M(2$O+R\O+R\D)"0D)"0D)"0`)"0D("```@("``("`E("&QM4`%)24E)24E)2
+M4E)2&U(`4E(@4E)$1"!$($0@("`@("`@("`@("`@("`@(PHK*RL**RLK*TA(
+M/RLL2CHZ.CHF.B8Z)CHZ,#`P(R8P.SL[(SL[.SLP(SLF,"8F)B8F)C`P(R,C
+M,#`P,"XL+CLF,"XN+C`P+B,[+BXL+"PN+#`C(R,C.SL[(SLC.SL[.RXN+CL[
+M(RPL+BPL+"PN.RXL+BX[.SL[.SL[.R,N+BXN+CLL+"XL+"X[.SL^3$Q,3$Q,
+M3$Q,3$Q,3$Q44E)24E)24E)24E)2`E("4@("`@`"`B0")"0D)"0D)"0D)"0D
+M("0D)"0D)"0"`@(D)"0D)"0D)"0D0D(D)"`@)"!"&!A'&!@8&!A")"0@("1"
+M($)"0D)"0D(8&!@8&!A'&!@@0D)"0A@8&!@8&$)"&$)"0A@81T='1T=21T='
+M1T='1R]'1T<O1R\O`B\O+R\O+R\O+R\O+R\A+R$O(2\A+R$A+R\A+R$O(2\O
+M+R\O`B0D)"0`)"0D)"0D)"0@)"0D(`("`@`"`AL"``)2`%)24AM&4E)24E)2
+M4E)24E(@4B!21$0@1$0@1"`@(!L@("`@("`@,2,K*RL**PHK*RLK"BM("DHF
+M,#`P,#HZ.B8F.CHZ.B8C(SHF,",[.SLN(S`N,"8P,#`P)B8F,#`C(S`P,#`[
+M.RXP,#`P,#`C(SLN+CLL+"PL+BPP,#LC(SL[.SLC.SL[.R,[.SL[+BPL+"PN
+M+"PL+#L[+CL[(SL[.SLC.SL[.SL[.SLN+BPL+"PL+BXN($Q,3$Q,3$Q,3$Q,
+M3$Q,*5)$1%)24E)24E)24@!24E("4@("`@("`@`")"0D)"0D)"0D)"`D)"0D
+M)"0D)"0"`@(D)"0D)"0D)"0D)"0D)"0D0A@8&!@80D(D)$)"0D(D0D)"0D)"
+M&!A"&!@8&!@8&!@80D(D0B1"&$(80D)"0D)"&"`8&$='2D='`$='1T='1T='
+M(4<A1R%'+QLO1R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\"+R\O+R\O+R`D
+M)"0D/B0D)"0D)"0D)"0D)"0D)"0"`@(;`@("`@)24@!24E(`4E(`4E)24@!2
+M4E)24D924D0@(!L@("`@("`@("`@,3$C*RLK"BL**RLK*PHK2`I*)C`P,#`Z
+M.CHF)CHZ.CHF(R,Z)C`C.SL[+B,P+C`F,#`P,"8F)C`P(R,P,#`P.SLN,#`P
+M,#`P(R,[+BX[+"PL+"XL,#`[(R,[.SL[(SL[.SLC.SL[.RXL+"PL+BPL+"P[
+M.RX[.R,[.SL[(SL[.SL[.SL[+BXL+"PL+"XN+B!,3$Q,3$Q,3$Q,3$Q,3"D@
+M("!24E)24E(`4E)24E)24E("4@("`@("`@(")"0@,20D("`D)"`@("0D)"0D
+M`B0"`@(D`B0D)"0@&R0D)"0D)"1"&!@80B0D)$)"&$)")"1"0AA"&!@8&!@8
+M&!@8&!@@&!A"0D(D0D)"0D)"0A@8&!@81T='&$='1T='1T='1T='1T='1T='
+M1QLO1R\O+R\O1R]'+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\")"0D)"0D
+M)"0D)"0D)"0D)"0D)"0D)"0D`@("`@("`@)2`@!24E)24E)24E)24E(;4E)2
+M4E(@("`@("`;(!L@("`@(#XQ(RLK*PHK"BLK*RL**T@*2B8P,#`P.CHZ)B8Z
+M.CHZ)B,C.B8P(SL[.RXC,"XP)C`P,#`F)B8P,",C,#`P,#L[+C`P,#`P,",C
+M.RXN.RPL+"PN+#`P.R,C.SL[.R,[.SL[(SL[.SLN+"PL+"XL+"PL.SLN.SLC
+M.SL[.R,[.SL[.SL[.RXN+"PL+"PN+BX@3$Q,3$Q,3$Q,3$Q,3$PI("!*($12
+M4E)24E)24E)24E(`4E("4@("`@("`@(D)"0D)"0D)"0D)"0D)"0D)"0D)"0"
+M`@("`B0D`B0D)"`D0B0D)$)"0D(D)$)"0D)"0B0@($(8&!@8&!@8&"`8&!@8
+M&!@80D)"0D(80A@8&!@8&!@81Q@81T='&$='1T='1T='1T='1T='1T='1R%'
+M1R]'+R\O+R\O+R\O+R\O+R]'+R]'+R\O+T<O+R]'+QLO`B0D)"0D/B0D)"0D
+M)"0D)"0@)"0D)"0D)"0D)`("&P(`5`("4E)2`%)24@!2&QM24E)24E)$("`@
+M("`@("`@&R`@("`@4S$K"@HK/TA(2$A(*PHK"DHF(R,C.B8P,"8Z)CHZ.CHZ
+M)B8F.C`C(R,P)B,[(R8P)B8F)BXF,#`C,#`P,#`C+C`L,",C(R,P,",P,#`C
+M.SL[.RP[.R,C.R,C(R,[+BXN+BX[.SLC+#LL+"PL+BXN.SLN.RXN+CL[.SLC
+M.RX[+"PL+"P*+BPL+"PN+BXN2DQ,3$Q,3$Q,3$Q,3$Q,#"`;("!$4E)24E)2
+M4E)2`%)24E)24E)2`E("4@("`B0")"0D)"0D)"0D)"0D)"0D)"0D`E("4@("
+M`B0D)"1"0AA")"0D)"0D)$(80AA"0D)"0B`8&!@8&!@8&!@@&!@8&!@8&!@8
+M&!@81Q@8&!A'&$<81QA'&$<8&$='&$='1QA'1T='1T='1T='1T='1R]'+T<O
+M1R]'+R\``B\O+R\O+R\O+T<O1R\O+T<O+R\O+R0D)"0D)$)")"0D)"0D)"0D
+M)"0D)"`@)"0D)"0D)"0"`@("4E)2`E)2`AM24E)24E)24E)21"`@4R!$("`@
+M/B`;("`@(%,C*PH**T@K2$A(2#\K*RM4.CHZ.C`C,#`[)CHF)B8Z.CHF)B8F
+M.SL[)B8Z,"8F)B8F)CLP)C`F,"8F)B8C(RP[+BPP(R,C(R,P(R,P(S`P,#`P
+M(R,[(SLC(R,[(SL[.RXN+BXN.R,N+BPL+"PL+"PN.RPL+"XL+"PC.RX[(RPN
+M.SL[+BXL+`HL+"PL+"!,3$Q,3$Q,3$Q,3$Q,3#H@(!M$($1$1%)24E)24E)2
+M4E)24E)24E)24E)24@("`@(D`B0D)"0D)"0D)"0D)"0D)"0D`B0D)"0D)"0D
+M0D(80D(D)"0D)$)"&!A"0D)"0D)"&!@8&!@8&!@8&!@8&!@8&!@8&!@8&!@8
+M&$H8&!@8&!@8&$<8`!A'&!A'&$='1QA'&$='1T<81T='1T='1T<`1R]'+R]'
+M+U(O4B\O1R]'+T<O1R]'+T<O+T<O1R\D)"0D)$)"0B0D)$(D0B0D)"0D)"0@
+M("0D)"0D)"0"`@("4E)24E)2`E)24E)24E)21$1$("`@(%-$1$1$("`@("`;
+M("!32BL*"@I(2$A(2"LK2"LK5#HF)B8Z)B8P)B,F)B8F.B8Z.B8F)B8F)CL[
+M.SLP)B8F)B8F.RX[.R,C+BXN.R,N+",C(S`P,",C(S`C(S`C(R,P(R,C(R,C
+M.SL[.SL[.SL[(R,C(SL[+CLC(RXL+"PL+"PN+"PL+"PL.R,[.RPN+BXN+BXN
+M+B,[.SL[.SLQ3$Q,3$Q,3$Q,3$Q,3$Q*&QL@("`@($1$1$124E)24E)24E)2
+M4E)24E)24E)2`@("`@(")`(D)"0D)"0D)"0D)"0D)"0D)"0D)"0D0D)"0AA"
+M&$)"0D)"&!@8&!@8&!@8&"`8&!@8&!A7&!@8&!@8&!@8&!@8&!@8&!@8&!@8
+M&!@8&!@@4B`8&!A'&$<8&!A'&$='&$<8&!A'1T='1Q@;1T<;1R]'+U(Q1R\O
+M1R%'1R%'(4<A1T<O1P!'+T<O("0D)"1"0D(8("!")$(D0B0D)"0D)#XD)"0D
+M)`)24E)24E)24E)2`@("`@)24E)21$0@($0@1$124E)24E(;/D0@(!L@4SL*
+M"@I(/T@_/S]("@I(2%0C)B8F)B8C)CLF,#`P,#HZ)B8F)B8P,#`P)B8F+B,F
+M.SL[)B8[+BXC)B8F)B8P)BX[,"PC(R,P(S`P(R,C(R,C,",C(R,[.R,C(R,[
+M(SL[(R,L+"PL+BPC.R,[(R,C.R,[+BP[+"XN+CL[+BX[.SLL+"P[.SLN.RXN
+M+BXN&S](2$Q,3$Q,3$Q,3$P_/AL@("`@("`@($1$1$121%)24E)24E)24E-2
+M4E)$4E("`@("`@(")`(D`B0;)"0D)"0D)"0D)"0D)"0D)"0D0D)"0D(8&$(8
+M0A@8&!@8&!@8&!@8&!A"&$(8&!@8&!@8&"`@&!@8&!@8&!@8&!@8&!@8&!@8
+M&"`8&!@8&!@81QA'&``^1T=2/A@81QA'&$='&$='1T='1T='`$='1T='(4='
+M1T='1T<A1T<;(4='1R0D)"0D)$)"0AA"&$)"&"1"0D(D)"0@)"0D)`)24E)2
+M4E)21%)2`@("`@("`E)24D1$1$124E(`4E(`4E)24E)$1"`@(%,Z"@H*"BL*
+M*RLK2"P**T@Z(R8F)CHF,",C)C`C(R,P.B,Z)C`P,#`P(S`F)B,C+BXN+B8F
+M,#LF,",C(R,P,#`N+",C+"PL+#`P(R,C.S`P,",C(SLC,",[.SL[(R,[.SLN
+M+BXN.RPL.R,C(R,C(R,C(SLL+BPL+"PN+",[.RPN+"PL.RXN+"XL+BXN+CX_
+M/TA(3$Q,3$Q,3$Q,3$HI&QL@("`@("`@($1$1$124E)24D121$1$4E)21$12
+M4E("`@("`@("`B0")`(D`B0D)"0D)"0D)"0D)"0D)"1"0D)"0D)"&!A"/B`@
+M(!@8&!@8&!@8&!@8&$(85QA7&!@8("`@&$(8&!@8&!@8&!@8&!@8&!@8&$H8
+M&!@8&!@8&!@8&!@@&#X8&!@81T<8&$='1T='1T='1T='1T='1U)'1T='1T='
+M1T='1TH`1T="0B0D)"0D0A@8&!A"&"080D(D0D(D("`D`@("`B0"`@("4E)2
+M4QL")`("4E)24D124E)24E)24E)24E)24E)24E(@(!L;,0H*"@H**S\_/S\*
+M(PH*2B8Z.CHF,"8[(SHP.SL[(R8F(SHF,#`P,#`P(R8F+CL[.SLF)B8F)C`P
+M(R,C,#`N.RXC(RXN+BXC,#`P,#`C(R,[,",C,",N.SL[(S`C,",C(RPL+#LN
+M+B,L+CL[.SL[.R,[.SLN+BXN.RPL+",L+#L[.RXL+BXN+BXN+BX;2$A(2$Q,
+M3$Q,3$Q,3$Q35!L@("`@("`@("`@("!$1$1$1$1$4T1$1$1$1$1$1%)24E("
+M`@("`@("`@("`B0")`(")"0D)"0D)"0D)"0D)$)"0D)"0D(@0AA"&"`80E<8
+M0AA7&$(@($(80AA"&$(85Q@8&!@8&!@82E<8&!@80A@8&!@80AA"0D)"0AA"
+M&!@8&$)"(!@8&#X8&$<8&$='1T='1T='1T='1T='1T='1T<81Q@81QA'1T='
+M1T='&!A"&$(D)"0D0B08&!@80A@80AA")"0D)"0"`@("`@("`E)24E("`@("
+M4E)24E)24U)24@)24E)2`%)24E(`4E)2("`@5#$*"@H*"BM(2$A("DHC*S$C
+M(R,C)CHF.S`F,#`P,#LP.B,F)C`P,#`P,#`F)B8N)B8F(R,F)B8P(S`P,#`P
+M+B,N(RXN+BXC,"XC,",[,#`P(R,P,",C+#L[.RXN,",C(SLC(R,L.RXL+"PN
+M+"PL+"XL+BXN+"PL+"PL+BPL+"PN+BXN+BPN+BX[.SL[&TA(/TQ,3$Q,3$Q,
+M3$Q,2AL@&R`@("`@("`@("`@(#!$1$0@1"D@($1$1$0@4T1$4E)24E)2`@("
+M`@("`@("`@(")`(D`B0D)"0D)"0D)"0D)$)"0D)"0D)"0D(80A@8&$(80A@8
+M0B`8&!A"&$(80AA"&"`@&!@80A@8&!@8&!@80B`D0B`D)"0D)"0D0B0D)$(D
+M0B1"0D(@&$<81$<81T<81T<81T='4D='1T<81Q@8&!@8&!A$&!A'1T='1Q@8
+M&!@8&$(D)"0D&"08&!@D0B0D)"0D)`("`B0D("0")%("4@("`B0"`E)24E)2
+M4E("`@("`@)24E)24E)24E)24D0@("`Z*T@*"BL*"@H*"B-4(PI*.R8F)B,C
+M)C`F(R,P,#`[(SHF)CHF,#`P,#`P,"8F)BXN+CLP(R8C,",C(R,P)C`C.RX[
+M+"PL+BXN+"PP,#L[.S`P+",C(RPL+"PL.SLP.R,C.SL[(R,C+"XL.SL[.SLL
+M+"XN+"PN+BX[.R,[+"PL.SL[+BPL+BP[+CL[.QM(3#],3$Q,3$Q,3$Q,3$I3
+M&R`I&R`@&R`@("`@("`@("`@("`@("`@("`@1"!$1$124E)24E)24@("`@("
+M`@("`@("`@(D`B0D)"0D)"0D)"0D)$(D)"1"0D)"0D)"0D)"0D)"0D)"0D)"
+M5T(8&$(80AA"0D)7&!@80AA"&$(8)"0@)"0D)"0D)"0D)"0D)"0D)"0D)"0D
+M&!@8&#Y$/@`81T='1T='&$<81T<8&$(80AA"0D(80D)"&!@8&!A'1T='&!@8
+M&!@8)"0D&"0D)"0D)"0D)"0D)"0D("0D)`(D`E(")"0D)`)24@("4@("`B0"
+M)`("`E)24E(`4E)24E)$1"`@.BM("@HK"@H*"@HC5",*2CLF)B8C(R8P)B,C
+M,#`P.R,Z)B8Z)C`P,#`P,#`F)B8N+BX[,",F(S`C(R,C,"8P(SLN.RPL+"XN
+M+BPL,#`[.SLP,"PC(R,L+"PL+#L[,#LC(SL[.R,C(RPN+#L[.SL[+"PN+BPL
+M+BXN.SLC.RPL+#L[.RXL+"XL.RX[.SL;2$P_3$Q,3$Q,3$Q,3$Q*4QL;("`;
+M&R`;("`@("`@/B`@("!$("`@1%,@("!$4R!$4E)24E)24E)24@)2`E("`@)2
+M`@(D`@(D`B0D)"0D)"0D)"0D)"0D)"0D0D)"0D)"0B!"0D)"0D)"0D)"0D)"
+M5T(8&!@8&!A"&$(80A@D)"0D)"0D)"0D)"`D)"0D)"0D)"0D)"0D)"0D)$)"
+M&!@81Q@8&!A'&$='1Q@8&!A")"0D)"0D)$)"0D(80D)"1T='1T='&$<8&!@8
+M)"0D)"0D)"0D)"0D)"0D(#XD)"0D)`("4B0D)`("4@("4B0D)`(D`@("`@("
+M`E)24E)24E)24D0@*3HK2`H**PH*"@H*(U0C"DH[)B8F(R,F,"8C(S`P,#LC
+M.B8F.B8P,#`P,#`P)B8F+BXN.S`C)B,P(R,C(S`F,",[+CLL+"PN+BXL+#`P
+M.SL[,#`L(R,C+"PL+"P[.S`[(R,[.SLC(R,L+BP[.SL[.RPL+BXL+"XN+CL[
+M(SLL+"P[.SLN+"PN+#LN.SL[&TA,/TQ,3$Q,3$Q,3$Q,2E,;(#H;&R`;("`@
+M("`@("D@("`@&T0@4R`;(%-$("`@($1$4E)24E)24E)24E("4@)2`@)24@(D
+M`@(")`("4E)24@("`B0")"0D)"1"($)"0D)"0D)"0D(D0D)"0D)"0D)"0D)"
+M0D)"0AA"&$(8)"0D)!LD)"0D)"0D)"0D)"0D)"0D)"0D)"0Z)"0D0AA"&!@8
+M1QA'&$<8&!@8&!A"0B0D)"0D)"0D)"0D)"0D)$='1T='1T<8&!@8&!@8&!@8
+M)"0D)"0@)"0D0D)")"0D)"0D`@(")"0D`E)2`E0;)"0D)`(D`B0"`@("4E)2
+M`%)24E)$("`I2"LK"BL*"@H*"B8Z.PI*.CHZ.CHC,#`P)C`C(R,[,"8Z)B8Z
+M,#`P)C`P,#`F)C`P,",F+B8N+B,C(R,F)B,C(RXL+BXN+",P(S`P(S`P,#`C
+M+CLC(RPL+"PL+BXC(RXC+BXN.R,[+#LL+"PL+"PN+B,[+"P[.SLN.RXN+"PL
+M+"PL(SL[+BXN+CL[.QM(/TQ,3$Q,3$Q,3$Q,3%0;&R`;(!L;(!L@&R`;("`@
+M("`;("`;&R`;(!L@4R!3("`@1$124E)24E)24E)24E)24E)$4E)24@("4E)2
+M4E)24E)24@)2`@("`@(D)#$D)"0D)"0D)"1"0D)"0D(D0D)"0D)"0D)"0B!"
+M0D(8)"0D)"0I)"0D)$)"0D)")$(D0D(D)"0D)"0D)"0D)"0D0D(8&!@8&!@8
+M&$)"0D(D0B0D)"0D)"1"0D)"0D)"0D)'1T='1T='1Q@81T<81Q@8&!@D)"0D
+M)"1"(#Y"0D(D)"0D)"0"`B0D1%,;*5144U-2`@(D`B0"`@("`E)24E)24E)2
+M1%,@&RLK2$@K"@H*"@HZ.BP*2CHZ.CHZ)B,F,#`F(R,C.SLP)CH[.B8F)C`P
+M,"8F,#`P,#`F.RXP)CLP,#`P,#`N,",C.RXN+C`P,#`P,#`P,#`P,#`C,",L
+M+BXN+"XL+BXN+"XN+BPL+",[.SL[.SLL+"P[+"PL.SL[.SL[.SLL+BPL+"PL
+M.RPN+BX[.SL;/S],3$Q,3$Q,3$Q,3$Q4&R`;("`;("`@("`@("`@(!L@&QL;
+M(%,;*2D@&R`@(%-$($1$1%)24E)24E)24E)24E)24T124E)$1$1$1$124E)2
+M`AL"`@("`@)2)`(D)"0D)"0D)"0D)"0D)"1"0D)"0B1"0D)"0D)"0D)"0B0D
+M4B0D)$)"0D)"0D)"0D)"0D)"0D(D)"0D)"0D)"0D)"1"0AA"0D)"0D(D)"0D
+M)"0D)"0@("0D0D(8&!@8&!@8+T='(4<"1T='1U)'1T='1T08&$)"($)"0D)7
+M&$(80B0D)"0D($I*.@PZ#`PQ,0PQ#$I*4U(D`B0"`@("`E("4E)24E)$1%,*
+M"BLK"BL*"@HN)B8L*THZ.CHZ.CHF.R8[,",C(SL[.SHF)B8F)B8P,#`F)C`P
+M,#`P)BX[,#`[+BXN+B8P.SLC,",L+"P[+"X[+C`N,#`P,",C(S`[+"PL+"P[
+M+BP[.RX[.SL[.RXN+#L[+BXN.R,L+CLL(SL[.SLN+BXL+"PL+"PL+"PL+"X[
+M.SL[4TA,3$Q,3$Q,3$Q,3$P_/AL;(%0I("`I(!L@&R`@(!L@&QL;&QM3(!L@
+M&R`;(!L@4R`@1$1$4E)24E)24E)24E)21$1$1$0@1$1$1%)24E)2`@(")"0D
+M5`)24E(D)"0D)"0D)"0D)"0D)"0D)"0D)$)"0B1"0D)"&$(@0D(D)"0D)$(D
+M)"1"0D)"0D)"0D)")"!")$(D)"0D)"0D)"0D)"0D)"0D)"`D)"0D)"0D)"`@
+M)"0D0D)"&!@8&!@8&"]'+T='1T='1U)21T='1QA'&!@8&#X8&!@8&$(80A@@
+M)"0@1B8F)C`,)B,F.C$Q,0PQ,3$Z5$0D)`("`@("4E)24E)24E(;"@H*2$@*
+M"@H*+",F"C\N(R,C(R8F)CHF)C`P,#`[.R,F.CHF,#`P)B8P,"8P,",C(S`N
+M(RXF,#LN+BXP+B,N,#`[.SL[+"P[+BXP,#`P,",C.SLC(S`L+"PN,#`C+"XN
+M+"PL+BX[.RPN.SL[.RXL(RPN+",[.SL[.RXN.SLC+"PL+"XL+"XN+"PL+$9(
+M2$Q,3$Q,3$Q,3$Q(2"D;&QL@&R`;&R`;(!L;&QL;&U,;(!L;("`@&R`@(!L@
+M4R`;1"!$1$1$1%)24E-44E)31$1$1$0@1"`@1%)24E)2&P(D)"0D)"0"`E("
+M`@(D)"0D)"0D)"0D)"0D)"0D)"0D)"1"0B0D)"0D("0D)"0D4B0D)"0D0D)"
+M0D)"0B1"0D)"0D)")"0D)"0D)`(")"0D)"0D)"0D)"0D)$(D)"0D($)"&!@8
+M&$)7&$)7&$)'(4<A1R%'(4='1T='1T='1T='&$<81Q@8&!@8&!A"0ALF,#`N
+M.B,P,#`F,"8F.B8Q,3HQ,3$Q5%,D)`("`@("4@)24E)2&T@K2#\_"@H*"BLN
+M+D@_+#HC(R,P,`PF)C$,.CHZ.SH[,#HZ)C`P,"8F)CH,.@PP,#`P,#`P.S`Z
+M.SL[,#L[.R,N+BXN+BXP+BPN.S`P,#`P,",P.S`,+BXN,#`Z,#LP+BPL+"PC
+M+CLN+CLC(R,[)CLC+#L[)B8F.SLF+CL[+",C(SLQ.SLN(RPN+BXI2$Q,3$Q,
+M3$Q,3$A(2$A44QL;&QL;("`;(!L;&QM34U-3&QL;(!L;("`@("`;(%,@4R`;
+M($1$1$1$1$1$1$1$4T1$1%,@("!$1%)24E("`@("`@(D)"0D)%)24E)2`@(D
+M)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)`(D)"0D)$)"0B1")$)"
+M0B1"0B0D)"0D)"0"`B0D)"0D)"0D)"0D)"0D)$)"0D(D)"1"&!A"5T(8&!@8
+M&!@@+R\O1R%'1T<A1T<A&$='1T='1T<81Q@8&!@8&!@@(#HN+`HN+CLL+"XL
+M+BXL,",F(R8Q,3HQ.DI*4R0")`("`@("4E)24AL**S\_/RM(2$A(*PI(3`IB
+M8F)B5E965E965E965E965E965E965E965E9B8AIB&AH:&AH:&F(:8F)B8AIB
+M5E965E965E965E968F(:8F)B&F(:&F)B8AH:&AH:&AH:8F)B8F)68E965E96
+M5E965E965E965E965E965E965E965E965E965E965E964TA,3$Q,3$Q,3$A(
+M*T@K4QL;&QL;&QL;("`;&QL;4U-34U,;(!L@&R`@("`@&R`;(!L@("`@1"!$
+M1$1$1$1$1$0;1"`@("!$("!$4E)2`@)2`@(")`(;5"124E)24U)24B0D)"0D
+M)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"12)`(D`B0D)"0@0D)"0D)")$(D)"0D
+M)"`D)"0"&U0")`("4R0D("0D(`(D)$)"0AA"0D)"0D)"0CY"0D)"0D)"0B\A
+M1R%'(4<A1R%'1R%'(4='1T<81T<81QA'&!@8/B8[+#`**RPL+"XL"BP[+BPF
+M.B8Q##I*.DHZ,3%3)"0")`("`@("`@(@*S\_2#\_/S\_2"L*/S\L*20D)"D@
+M2E-**51'1T=34R`^1`)"&QL;'!Q&'!P<'$9&1AQ&'!P<'!PQ,3$<1D4#`QP`
+M'!P<1D8Q1AP,'#$Q,1P<'!Q&1AQ&1D8Q1C$<1C$<145%1D8#,49&1C$Q,0`Q
+M2E0,)C$,#`Q&/BD;4B0"4E)2/E0,4U14/E145"8_3$Q,3$Q(2$A(*TA(2%13
+M&QL;&QL;&R`;&QL;4U-34U-3&QL;(!L@("`;("!3("DI*5,@("`@($0@1"!$
+M1$1$($13("`@("!$1%)24E("`@("`@(")`(D`E(;`@)24E("`B0D)"0D)"0D
+M)`(D)"0D)"0D)"0D)%(D)%(D)%(D`@(D)$)"($)"0B0D)"0D2B0D)"0@)"0D
+M)`("`@(")`("`B0D)!LD)"0D0D)"0D)"0D)"0D)"0D)"0D)"0D(O(2\A(4<A
+M1R%'(4='1T='1T='1T<81Q@8&!@8&RXL+`H*"BP*"@H*+#L*.PH[+"8P(R,Z
+M.C$Q,3$Z,5,D)!LD)`(;&P("2@I(2"M(/TA(2$@*+`HK*RL*"@HK2#],/TP_
+M/S\_/S\K"BXC+"PL+"M(2#](2$Q,3$PK/T@K/TQ,3$Q,3$Q(+#LL"DA(2$A,
+M3$Q,3$Q,3$Q,2#],3#](3$Q,3$P_3$Q,3$A(2$A(2$Q,*PHK*RM,3$Q,3$Q,
+M3$Q,3$Q(3#\*.SHZ.BQ,3#](3$P_/S\_2$Q,3$Q(/S\_2$A(*TA3&QL;&QL;
+M&QM4&QM3&U-34U-34QL@("`@("`@("`@(%,I("E3(%-$("!$($1$1$0@(%-$
+M("`@1"!$1%-24E)24E("4@("`@("`@)2`@("&P)24E)2)"0D)"0"`@)2`@("
+M)"0D)`("`@)2`E,D4E("4R0D)"0D)$(D)"0D)"0D)"0D)"0D)"0D)"0"4@)2
+M)`(D)`)2`B0D)"0D)$(D0D)"0D)"0B`@0B1")$(D0B1"(2\A(4<A(2%'(4<A
+M1R%'1R%'1T='1T='&!A"'`HL"BL*"@H**RPL*PH*"BP*+`HP,#HF)CI*.C$Z
+M2CHQ4R0D)`(D`B0"`DH*2$@K2#](2$A("BP**RLK"@H**T@_3#],/S\_/S\_
+M*PHN(RPL+"PK2$@_2$A,3$Q,*S](*S],3$Q,3$Q,2"P[+`I(2$A(3$Q,3$Q,
+M3$Q,3$@_3$P_2$Q,3$Q,/TQ,3$Q(2$A(2$A,3"L**RLK3$Q,3$Q,3$Q,3$Q,
+M2$P_"CLZ.CHL3$P_2$Q,/S\_/TA,3$Q,2#\_/TA(2"M(4U,;4QL;4QL;&U-3
+M4U-34U-34QL;(!L@("`@&R`;(!L@&QL@&U,@4R!3("`@("`@4T13(!L@("!$
+M1%)34E)24E)24@("`@("`@("`@(")`)24E)$4E("`B124E)2&U)24E("`@("
+M4U)24B0D4E(D4B0D)"0D)"0D)"0D)"0D("0D)"0D)"0D)"0D(`("`@(D`B0D
+M)"0D)"0D)"1"0D)"0D)"0D)"0D)"0D)"0D)"0B$A(2$A(4<6(4<A1R%'(4='
+M1T='1T<81T='&PH*"BLK*PH**PH*"BLK"@H*"CHL+`HL.CHZ.DHZ2CI*.DH"
+M)"0D)`("`@)*"DA(*T@_2$A(2`HL"BLK*PH*"BM(/TP_3#\_/S\_/RL*+B,L
+M+"PL*TA(/TA(3$Q,3"L_2"L_3$Q,3$Q,3$@L.RP*2$A(2$Q,3$Q,3$Q,3$Q(
+M/TQ,/TA,3$Q,3#],3$Q,2$A(2$A(3$PK"BLK*TQ,3$Q,3$Q,3$Q,3$A,/PH[
+M.CHZ+$Q,/TA,3#\_/S](3$Q,3$@_/S](2$@K2%-34U-34U-34U-34U-34U-3
+M4QL@(!L@("DI("`@("`@&R`;*1L@4U,@("`@1"`@("!3("`@("!$1$1$1$12
+M4E)24E)24@("`@(;`@("`@("4E)34E)24E)24E)2`E0D)`)2`E)24E(D4@(D
+M4E(D4@(")"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0"`@("`B0D,2`D)"0D
+M)"DD)"0D)"0D)"0D)"0D)"0D)"0D)"0A(20A(2$A1R$61R%'(4='(1@A1T='
+M1T='(`H*"@HK*PHK*RL**PHK"BL**RL[+BXL*SH[)CHZ.C$Z,3$,*20D)"0D
+M)"0"`BP**RM(2"LK*PH*+"M(*PHK*RM(/S\_/TP_/S\_/S](*PHZ+"PL+`H_
+M2#](2#],3$Q(/TA(3$A,3$Q,3$Q,*SLP"DA(2`H_3$Q,3$Q,3$Q,*S\_/TA(
+M3$Q,3$P_/S],3$A(2#](2$Q,3"L*"@HK3$Q,3$Q,3$Q,3#](/TA,*R,C(R8K
+M3#](/S\_/S](3$Q,/S\_2$A(2"L_/TA34U-34U,I4U-34U-34U-3&QL;(!L@
+M(!L@5"`;(!L@("`;("`@(!L@4U-$4R!$("`@(%,I*5,@("!$4T1$4E)24E)2
+M4E)24@("`@("`@("`@("4E)24E)24E)2`@(D)"0D`@("`@)2`@("4B12`@)2
+M)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)!L"`@(")"0D)"0D*20D)"0D
+M)"0D)"0D)"0D)"0D)"0D)"`@%A93%B$A(2$A1Q8A1R%'(1@A&$='1T='("PK
+M*RLK*TA(2"L_"BLK"BLK"BLL+`HL+`H[.RXC)CI*.C$Z2CI2)`(D)%0D)"0F
+M"@I(/S\*"@HK"BPK*PHK*RLK/S\_/S\_/S\_/S](/T@*.C`*"@HL*T@_2$A,
+M2$A(/S](*TA(/S\_/S](2"L*+"PK*RLK*TQ,/TQ,3$Q,/T@_3$@K/TQ,3#\_
+M3$PK2$Q(2$A,/T@_3$Q,*RLK+BM,3$Q,3$Q,3$P_*RM(/TP*"@H[+"M(2#](
+M2$A(3#],3$A(/TA(2$A(/S](*5-34U,I4RE32E0I4U-3&QL@&R`;(!L@&R`@
+M(!L@&R`@("`;("`@&R!3&R`@&R`@4R!3("!31$0@1$I$1$124E)24E)24E)2
+M`@("&P("`@("4E)24E)24E)2`@(D&R0D)"0D)"0D`E)24E)2`E)24B0D)"0D
+M)"0@("0D)"0D)"0D)"0D)"0D("`D)"0D)`("`B0D)"0D)"`D)"0D)"0D)"0D
+M)"0D)"0D)"0D)"0D)!86%A86(2$A(2%'(2$A(4<A1R%'(4='4CLK*S](2$A(
+M/S\_*RLK2$@K*PHK/PH*"BPN.R8*(RXF.DHZ,3HQ5"0")"0D)"0D2@HK*T@K
+M*RLK"BL[.PHL"C\_/S\_/S\_/S](2$@_/S](*R-*,#`P.RM(2#](2$A(2#](
+M"BLK2$@K*RLK2$A("BLL"@H*"@H_/TQ,3#\_/S](/S](2$Q,3$Q,2$A,*PI(
+M/S\_2$A(3$Q,3#\_/SLN2$Q,3$Q,3$P_2#](2$Q,/S\_/RL*"BM(*RLK*TQ,
+M/TA(2#](2$@K2"M(*RDI*2DI4RE34U-34U-3&QL;&QL;(!L@&R`;&R`@&R`;
+M("`@("D@("`;(%,@4R`@("!3(%-3(%,@("`@("!$1$124E)24E(;4E)24AL"
+M`@)2`@)24E)24E)24@(D)!LD)"0D)"0D)"0"4E)24E)24@(")"0D)"0D)"0D
+M)"0D)"0D)"0D)"0D)"0D)"1&)"0D)"0D)"0D)"0D)"0D)"0D)"0D("0D)"0@
+M("0D)"0D)"06%A86%A8A(2$A(2$8(4<A1R%'1T='1R0*"BLK/TA(/T@_*TA(
+M2$A("D@**RM(*S`[+"XL+",N+B8Z2CI*.DI2)"0D)"0D)#$*"@H*"@H*"BL*
+M(SH[+"L_/S\_/S\_/S\_2$A(/TA(2$@[2C$Q,3H*2#\_/RL_/S\_2`I("@I(
+M2$A(2#](2"LK*RLK*RLL2#],/RLK*RM(2#\K*TA,3$Q,3#\K2$@*+"LK*S\_
+M/TQ,3$Q,3$P_#"PK3$Q,3$Q,/TA(2#],3$Q,3$Q,2`H**RPK*RM,/TA(2$A,
+M2$A(2$@_*RQ3*5,I*3Y34U-34U-3&QL;&QL;&QL;(!L;("`;(!L@(!L@&R`@
+M&R`@&QM34R`;(%,@4R!3(%,@4T0@1"`@1$1$4E)24E)24E)24E)24@("`@)2
+M`E)24E)2`@(")"0D)"0")"0D)"0D)%)24E)24E("`B0D)"0D)"0D)"0D)"0D
+M)"0@)"0D5"0D)"0D5"`D)"0D)"0D)"0D)"0D)"0D)"0D)%0@)"0D)"0D)"0D
+M)"0D%A86%A8A(21'(4<A(2$A1R%'(5)'+T<Z*TA(2"L_2$A(2$@_2$A(2"LK
+M*RLK*RLL.PHL+"PL.R8C2CHQ.C$Q("0D)"0D)"0D+B,C"BLK*RLK"B,Z)B-(
+M/S\_/S\_/S\_/S\_/TA(/TA("@Q*2DHZ+CLL"BP*2$A(2"LK+`H*"@H*"BPL
+M+#LP"D@_/S](*PH*2#LL"@H*+`I(*TA,3$A(2$P**SLL.@PN+BY(2#],3$Q,
+M3$Q,3"P[+"M,3$Q,3$@K/S],3$Q,3$Q,3$@K"@H[+BXN2#](*S](3#\_/TA(
+M2"LP*3X^/E-34U-34U-3&U,;&QL;&QL;(!L@(!L;(!L@&R`@("`;("`@(!L@
+M4R`;4R!3(%,@&R!3(%-3(%,@("!$1$124E)24E)24E)24E)24E("`@("&U)2
+M`@("`@(D`B0D)"0D)"0D)"0"`E)24E)2`B0D)"0D)"0D)"0D)"0D)"0D)"0D
+M("0D)"0D)"0D)"`D)"0D)"0D)"0D)"14)"0D("0D)"0D)"0D)"0D)"0D)!86
+M%A86(2%'(4<A1R$A1R$A1R%21T<"*TA(/S](/T@_/TQ,2#](2$A(2$A("BM(
+M+"P*(RPL+"PL)B8Z2CHQ.B`;("0D)"0D)#HP)B,L"@H*2`H[.B8C2$Q,3#\_
+M3#\_/S\_/S\_/TA(2$@[,3$Q,0P<'!P<1BLK*T@*"BPL"BPZ.CH<'!P<`RY(
+M3$Q,3#\K"@H<'!P<'!P,2$A,3#\_/S\_#!P<'!P[#`P,+BM(3$P_3$Q,3$PK
+M+"X*"DQ,3$Q(2$A,3$Q,3$Q,3$P_2$@*"CL[.RPK*RM(/S\_/S](2$@K2E-3
+M4U-34U-34U-34U,;4QL;&QL;&QL;&QL@(!L@&R`;(!L@("`;("`@4U,;4QM3
+M&QL@(!L@(!L@4R!3("`@1$1$1%(;4E)24E)24E)24E)24E)2`AL"4@("`@("
+M`@(D`B0D)`(D)"0D)"0"4E("`@(D)"0D)"0D)"0D)"0D)"0D)"`D)"0D)"0D
+M)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)%0D)"0D)"0D)"0D)"0:%A8A(2$A
+M(2%'1T='1R$8(4='(4=2.D@_3$@_/S\_3$@_/TA(2#\_2$A(2"LK/RPL"B8C
+M"CLL(R8Q.C$Z,0Q3)"0D)"0D)"1*.B8Z(PH*"BL*+",L.RL_/S\_/S\_/S],
+M/S\_/S\_2#\_+"8F)D8Q'!P<'$8K*RLK2"L*"BPL'!P<'!P<10,K2$Q,3$Q,
+M/RL*'!P<'!P<'"L_3$P_/S\_3#H<'!P<.S`P,#HL*S](/TQ,3$Q,/RL*"BY(
+M/S\_*TA,3$Q,3$Q,3$Q,2#](*TPK*RLL"@HK/S\_2$A(/S](2#HI4SY34U-3
+M4U-34U-34U-44QL;&QL;&QL@&QL;(!L@&TH@&R`;(!L@&R`;4U-34U,@(!L@
+M("`;1%,@(!L@1"!$1$124U)24E)24E)24E)24E)24E)2`E("`@("`@("`@(D
+M`B0D)`(D)"0D)"0"`B0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0@5"0D)"0D
+M`B0D`B0D&R0D)`(D)%0;)"0D)"0D)"0D)"14)"0D)"0D%AH6%B%'(4<A1R$8
+M(1A'(4<A(4<A1RQ(2$@_3#\_3$A(/S],/S](/TA(2$@K2#\*+`H*+#LC"B,Z
+M)DHZ2CHQ5"0D)"0D)"0D2DHZ.B,[.SLC.RPC)BP*"@H*2#\_/S],/S\_/S\_
+M/T@_/RLF)B8Q,1P<'!Q&*RLK*RLK2"LL'!P<'!P<!@8K/RM,3$Q,3$P_*QP<
+M'!P<'!Q(3$P_3#\_/TQ&'!P<'`H*"@HN+"X**TA,3$Q,3$P_*RPL"BLK*TA(
+M3$Q,3$Q,3$Q,/S\_2#](2$A(*T@K"BM(2$A(2$A(2$PI4U-42E-34U-34U-3
+M4U-34QM3&QL;&QL;&QL@&QL@&R`;("`@("`@("!3&U,I5%,;&QL@&R`@1!L@
+M4U,I*40@1#Y$($1$4E)24E)24E)24E)24E)24E)24@("`@)2`@("`@(D`B0D
+M)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D
+M)%0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)&(6%B$A(2%'(4<A&"$8(4<8
+M(4<A1R0*/S\_/S\_/S\_3$P_3$Q,2$@_/T@K*TA("BP*"BL*(R-*.CHZ.CI*
+M.DHD)"0D)"0D)$I*.CHC.SL[(SLL(R8L"@H*"D@_/S\_3#\_/S\_/S](/S\K
+M)B8F,3$<'!P<1BLK*RLK*T@K+!P<'!P<'`8&*S\K3$Q,3$Q,/RL<'!P<'!P<
+M2$Q,/TP_/S],1AP<'!P*"@H*+BPN"BM(3$Q,3$Q,/RLL+`HK*RM(2$Q,3$Q,
+M3$Q,3#\_/T@_2$A(2"M(*PHK2$A(2$A(2$A,*2E3*5-34U-34U-34U-34U-3
+M4QM3&U0;&QM4&R`;(!L@&R`;(!L@&R`;(%-3&QM3&U,@&R`;&U,@4U-4(!L@
+M("!*1$1$1$1$4E(;2E)24E)24E)24E)24E)24@)24E("`@("`@(D`B0")`(D
+M)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)`(D)"0")`("`B0;)`(D
+M)`(D`B0")`(D)"0")"0D)"0D)"0D)"06%A86(2%'(4<A1R$8(1@A(4<A&$<I
+M*TP_3#],3$Q,3$Q,/S\_3#\_/T@K/S]("BLK*RPK+"XZ.B,F.DHZ,3I*)"0D
+M)"0D)"0D2CHZ(SL[.R,[+",F+`H*"@I(/S\_/TP_/S\_/S\_2#\_*R8F)C$Q
+M'!P<'$8K*RLK*RM(*RP<'!P<'!P&!BL_*TQ,3$Q,3#\K'!P<'!P<'$A,3#],
+M/S\_3$8<'!P<"@H*"BXL+@HK2$Q,3$Q,3#\K+"P**RLK2$A,3$Q,3$Q,3$P_
+M/S](/TA(2$@K2"L**TA(2$A(2$A(3"E3*5-3*5-32E-4/E-34U-34U-3&U,;
+M&U0Q2E,;&R`;(!L@&R`;("`;&SH;4U-3&U,;(%,;&R!34U,@2E,@("`@("`@
+M1$1$1$1$4E-24E)24E)24E)24E(;4E)24E)24@("`@("`@(D`B0;)`(D)%,;
+M)"0D)"0D)"0D)"0D)"0D)"0D)"0D5"0D)"0D)`("`@(D`B0"`@("`@("`@("
+M`B0")`(D)"0D)"0")"0D)"0D)!86(2$A(2$A1R%'(4='1T<A1R%'2D@_/S],
+M3$Q,3$Q,3#\_/S\_3#](/S\_"BL*"D@K*RLC.CLC)CHQ.C$Z5$08)"0D)"0D
+M)%0Q.B,L+"PC(SLC.B8N+"PL*RL_/S\_3#\_/S\_/TQ,3$@C(R,Q1AP<'!P<
+M*RLK*RLK"@H<'!P<'!Q%!CM(/T@_/S\_3$Q,+!P<'!P<'!P_3$Q,/S\_/TPZ
+M'!P<'"M(2$@*.RP*2$A,3$Q,3$Q,/PH*"@H*"BM(3$Q,3$Q,3$Q,2#\_3$P_
+M/S\_/TP_/T@K*TA(2#](/PI*4RDI4U,I5$I34U-34U-34U-34U-3&U,;&QL;
+M&QL@&R`;(!L@&R`;("`;4U-34U,;&QL;&QM34U,@&U,@&R`@("`^("`@1$1$
+M1%)34E)24E)24E)24E)24E)24AM24@(;`@("`@(D`@(")"0D)`(D4P(D)`(D
+M)"0D)"0D)"0D)"0@)"0D`B0")"0D`@(D`B0"`@("`@("`@("`@("`@("`@("
+M`B0D`B0D)"0D`B0D)"06%B$A(4=2)"%'1R%'(1@A&"%'1TH_/TQ,3$Q,3$Q,
+M3$Q,3$Q,3$Q(/S](/PHK"@H*"BLK(R,N)B8F.DHZ2E,D)"08)"0D)"0I2CHF
+M+"PL+`HL.SHZ(PH*"@HK/TP_3#\_/S\_/S\_/TA(+"PL)C$<'!P<'"LK*RLK
+M*RL<'!P<'!P#'"XK*S\_2$A(3$Q,/T@<'!P<'!P<3$Q,/S],3$Q,'!P<'!PK
+M2$A("BXL+"LK3$Q,3$Q,3#],2`H*"@I(*TQ,/TQ,3$Q,2$@_3$Q,/S\_/S\_
+M3#](2"M(2$@_2#\Z*2E34RE34RE4*5-34U-34U-34U-34U,;4QL;&QL;&QL;
+M(!L@("`@(!L;(!M34U-34QL;&QL;4QL@&R`@&R`@&T0@("`@("!$1"!$1%)$
+M4E)24E)24E)24E)24E)24E)2`@("`@("`@(D`B13)`(D)`(D)"0D)`(D)`(D
+M)"0D)"0D)"0D)"0D)"0"`B0"`@("`@("`@("`@("`@("&P("`E0"`@("`@(D
+M`B0D)"0D&R06%B$A(2$A(5-'(2$8(4<A&"%'1R$Q2$A,3$Q,3$Q,3$Q,3$P_
+M3$Q,/S](/S\K"BL**PHK"BP[.SLZ(THZ.CI2)"0D)"0D&"0D*3I*.BPL+`H*
+M"BPC,4HF)B8*"BL_3#],/S\_/RLK*T@_2"PL+#M&'!P<'!P*"@HL2#]&'!P<
+M145%`SM(*S](*TA(2$P_3#\K'!P<'!P<'$Q,/S\_3$Q,3#H<'!P<*TA(2"LL
+M"BP**TQ,3$Q,3$@_2#](2$A(/TA,3#],3#\_/S\_3$Q,/T@_/S],3#],2$@_
+M*RLK2"LK2E,I*2DI*5,I4U,I4U-34U-34U-34U134U,;4QL;&QL;&R`;(!L@
+M&R`;(!M34U-3)E,;&RD;4U-3&QL;&R`;&R`@("`@2B`@($1$1$131$1$1$12
+M4E)24E)24E)24E(;&U)2`E("`@("`@(D4U(D)`(D`B0D)!LD`B0D`B0D)"0"
+M)`(D)"0D&R0")`("`@("`@("&QL"`@("`@("`E("4@("`@("`@("`@(")`(D
+M`B0D%A8D(2$A(2%'(4<A4B$81R%'(4='5#](3$Q,3$Q,3$Q,3$Q,3#],2#\_
+M/S],/RP*"BLK*R,C.SLF)B8Z2CI*4U(D)"0D)"0D&"0Z,3HL+"PK"BL*"B8F
+M.CHZ+`H**TA,/TQ,3#\L.R,L*RL*"@HP,1P<'!P<"@H**T@Q'!P<`QP<'#`_
+M*T@_*RM,3$Q,3#](/QP<'!P<'!Q,3$P_3#\_/TP<'!P<'`I(2$@_"@HK*PH_
+M3$Q,3$@K2"LK*RLK*TP_3#](3#],3$Q(3$Q,3$A(2$A(/TQ,/S],3#\_/S\K
+M.RDI*50I*50I*2DI4U,I5"E34U-34U-44U-34QM3&QL;&QL;&R`;("D@(!L;
+M4U-34U-3&QM4&QL;4U,;(%0;("`@("`@("`@("!*/D1$("!$1$1$1$124E)2
+M4U)24E)24E)24E("`@("`@("`E(D4B0D4B0"4U,D`B0"`B0")"0D)"0D)`("
+M`E0"`@("`@("`@("`@(;4@("`@("&P("`@("`E("5`("&P("`@("`B0")!86
+M)!86)"12(2$A(4<A(2%'1T='(2D_/TQ,3$Q,3$Q,3$Q,3$Q,3#],2$A(/S\K
+M*PH**PH["B,[(SHC2CHZ5"0D)"0D&"08)"1")#HF+"PL*RM(2$@*(R,C(R8N
+M+#L**TA(2$@*(R8C(PHL"@H*,`P<'!P<'#HZ.CL,'!P<'!P<'!Q(2"LK2`HL
+M/S\_/S],2"L<'!P<'!P</S\_3$Q,3$Q,.AP<'!PZ.SL["CLZ+#L[.S\_/S],
+M2#\_3#],3$Q(3$A(2#](/S\_/TQ,3$A(2#\_/TP_/TQ,/TQ,3$P_*SI*5%14
+M5%145%0I*2DI4RE34U-34U-34U-34U-4&U,;&QL;&QL;&R!4(!L;&U-34U-3
+M4QM44QM34U-3&QLI(!L@&R`@*2`@("`@("`@($1$1"!$1$1$1$1$4E)24E)2
+M&U)24E)24E)2&U12`E(D4B124B125%(D4R0")"0")`(D`B0")`(D`B0"`@("
+M`@("`@("4@)2`@)2`@)24E)24E("4@("`AM2`@("`@("`@("`@(6&A86%A86
+M%B$A1R%'(4<A1R%'(4<;2$P_3$Q,3$Q,3$Q,3$Q,/TQ,2$P_2#](/TA(*PH*
+M+",L(SL[.CI*.BDD)"0D)"0D)!@D&"0Z(R,C(RX**PH**PH*"@HN(RPC+BX*
+M"@H*+#HF)BXL.PH*"BPZ'!P<'!P<'!P<'!P<'!P<'!P<'!PZ"BL*+BPL+"XK
+M2#\L'!P<'!P<'#](/TQ,3$Q,3`P<'!P<'!P<'!P<'!P<'!P<'!Q&.S](2$Q,
+M3$Q,3$P_/TA(2#\_/S],3$Q(*TA,3$P_3$Q,/TP_3$Q,/TA45%145%145%14
+M*50I*5-3*5,I4U-34U-34U-34U-34U,;&QL;&QL;&QL;&U-34U-34U-35%-3
+M4U-34U,;("`@("`@&R`@("`@("`@("`@($1$1"!$1$1$1$1$4E)24E)24E)2
+M4E)24E)2`E)24E)2)%)2)%,D4@)3`E-3)`("`@("`@("`@(;,0("`@("`E("
+M`@("`@)24E)24E)24E)24E)24@("`@("`@("`@("`@("&A@68A86%A86(2$A
+M(4<A4T<A1R$A`C\_3$Q,3$Q,3$Q,3#],3$Q,3#\_/TA(2$@K*RL*+B,L+"PC
+M)CM*.DHD)"0D)"0D)!@D&"0D&#L*"@H**RLK*RL*"@H*"BPC+`H[+"PL+"P[
+M)B,[)B8L+"PL+AP<'!P<'!P<'!P<'!P<'!P<'!P<'$8L+"PL+"PN+#LK"AP<
+M'!P<'!Q(*RL_3#\_/T@,'!P<'!P<'!P<'!P<'!P<'!P<'!P<"DQ,3$Q,3$@_
+M3#\_/S](2$A,3$Q(*T@_/S\_3$P_/TP_2$Q,3$PL5$I45%145%145%14*2DI
+M*5,I4U-34U,I4U-35%-34U,;4QM3&QL;&QL;&U-34U-34U-34U-35%-34U,;
+M("DI&R`@("!$&R`@("D@("`@(#X@("!$($1$1$0^4T1$4E)24E)24E)24E)2
+M4E)21%)$4E)2)%(D4E(D4B12,5("`@("`@("`@("`@("`@)2`@("`@)2`E)2
+M4E)24AM24E)24E)24E)24E)2`@)24@("`@("`F(:&AH6&A86%A86(2$A(4<A
+M(4<6(2$Z/TQ,3$Q,3$Q,3$Q,3$P_3$P_/S](/RM(2"L*"@H[(RXC(R9*.CI$
+M&"0D)"0D&!@D&"1$&"0F+"PL"BLK"@H**PH*"@H*)BXK"@HK*RLK"BPL*RXF
+M+BXN+`H<'!P<'`,#`QP#'!P<'`,<'!P<'!P<'"PL+"PL"BXP,`H<'!P<'!P<
+M"BL**T@K*RLK,1P<'!P<'!P<'!P<'!P<`QP<'!P<'!Q(3$Q,3$P_2#\_/S],
+M/S\_3$Q,/T@K/S\_/TP_/S](2$A,3$Q,,51*5$I45%145%145%14*2DI*2DI
+M4RE34U-34U-34U-34U-3&S%4&QL;&U-34U-34U-34U-35#%34U-3&QL@&R`;
+M(!L@&R`@&R`@("`@("`@("!**40@1"!$1$1$1$124E)24E)24E)24E)24D1$
+M1%)24E)24B124B12)%(D4@("`@("`@("`@("`@("`@)2`E)24E)24E)24E)2
+M4E)24E)24E)24E)24E("`C%2`E("4@)B8AH:&AH6&A86%B06%A861R$A%A86
+M(#\_3$Q,3$Q,3$Q,3$Q,/TQ,/T@_/TA(2"L*"BLK.R,C.R8Z.CI4&"0D)"0D
+M)"0D)!@D)"0D)BPL+`HK*PH*"BL*"@H*"B8N*PH**RLK*PHL+"LN)BXN+BP*
+M'!P<'!P#`P,<`QP<'!P#'!P<'!P<'!PL+"PL+`HN,#`*'!P<'!P<'`HK"BM(
+M*RLK*S$<'!P<'!P<'!P<'!P<'`,<'!P<'!P<2$Q,3$Q,/T@_/S\_3#\_/TQ,
+M3#](*S\_/S],/S\_2$A(3$Q,3#%42E145%145"DI5%145%14*2DI.BDI*5,I
+M4U-34U-34U-34U,;4QM3&QL;5%-34U,I4U-34U-34U134U,@&R`;("D@("`@
+M("`@("`@&R`@("`@("`@("`^("!$1$1$1$124E)24E)24E)24D1$1$1$1$1$
+M4E)24E)24E)24@("`@)2`@("`E("`@("4@)24E)24E)24E)24E)24E)24E)2
+M4E)24E)24E)24E)24@("`@("8D=B&!H:8AH6&A86%A86)"%'%A86%A8*3$P_
+M3#],3$Q,3$Q,3$P_3#],/TA(2"L*2"LK*PHZ(R8C.CI*1!@8)"0D)"0D)"0D
+M("0D)"8L+"P**RL*"@HK"@H*"@HF+BL*"BLK*RL*+"PK+B8N+BXL"AP<'!P<
+M`P,#'`,<'!P<`QP<'!P<'!P<+"PL+"P*+C`P"AP<'!P<'!P**PHK2"LK*RLQ
+M'!P<'!P<'!P<'!P<'!P#'!P<'!P<'$A,3$Q,3#](/S\_/TP_/S],3$P_2"L_
+M/S\_3#\_/TA(2$Q,3$PQ5$I*.E14*2DI5%145%145%145$I4*2E34U-*4U-3
+M4U-34U-34U-34U-3&U-34U-34U-34U-34U-34U,;&R`;(!LI(!L@&R`@&R`;
+M("`@&R`@("`@("`@("`@1"!$1"!$1$124E)24E)24E)$1$0@4T1$1$124E)2
+M4E)24E)24E)2&P("`@("`E)24E)24E)2&U124E)24E(;4E)24E)24E)24E)2
+M4E)24E)24E)24E)2`F)B8AAB8AIB&F(6%F(6%B0A(2$6%A8A2DA,3#],3$Q,
+M3#],3#],3#\_/T@K/S\*"@HK*PHL(R8Z)B9*1!@D&"0D)"0D)"0D)%,D)"0Z
+M.SL["@HK"BL*"BLK*RLK"BXK*S](2$@*"BP**T@L+BXN+BP<'!P<'!P<'!PQ
+M'$9&##$<'!P<'!P<'#$Z,#`P"@H*,"P<'!P<'!P#"@I("BPK*RM(#!P<'!Q&
+M#`P,,3H,##HL#!P<'!P<'!P,3$Q,3$Q(*S\_/TP_3$Q,3$Q,/S](/TQ,3$Q(
+M/TA(2$P_/S](*4I42E145%0I5"DI5"945%145%145"DI*5,I4U-34U-34U-3
+M4U-34U-44U-34U-34U-34U-34U-34U,@&R`I&R`;(!L@("`;("`@("`@("`@
+M($I*("`@("`@("`@("!$1"!$1$122E)24U-$1%-$1$1$4T1$1$1$1$124E)2
+M4E)24E)24E)24E)24E)24E)24DH;4E(;4E)24E)24E)24E)24E)24E)24E)2
+M4E)24E)24E)B8F)B8F)B8AH:%F(6%A86(2$A%A86%A8F/S],3#],3#],3$P_
+M3#],2#](/S]("@H**PH["@HC)B9**1@D)"08)"0D)"0D&"08(!@8&",C(PHK
+M2$@K"BLK*RLK*RM(*RL**RLK2"L*2#]("BPL+`HL'!P<'!PQ,3$Z.PHK"D@_
+M/S\_.AP<'!P<.CHZ.BP**RPN'!P<'!P<'#`K2`H*+"PL2#H<'!P<"C\_/S\_
+M2#],3$P*"@H<'!P<'$Q,3$Q,2$@_/T@_2#\_/TQ,3$Q(3#\_/S](3#](/S\_
+M3$Q,.BE42E145%14*4HI5%145%145%145"DI*2DI4RE3*5-34U-34U-34U-3
+M,5134U-34U-34U-34U-34U,;&R`;(!L@&R`@(!L@&R`;(!L@&R`@("`@("`@
+M("`@("`@("`@("!$1$1$1$1$1%)$1"`@1%-$1$1$1$1$1$1$1%)24E)24E)2
+M4E)24E)24E)24E)24AM24E)24E)24E)24E)24E)24E)24E)24E)24E)24E)2
+M4E)28F)68F)B8F(:8AH:%F(6%A8A%A86%B$A%BL_/TQ,3$Q,3#],/S\_/S](
+M/TA(*T@L+"X*+`HL(R,Z5!A$1$08)!@D)"08&!@8&!A'&!A'2DH**T@*"@H*
+M*RLK2"M(2$A(*TA(2"LK*T@_*RLL+"PL.QP<'!P<.CHZ.RPK"BL*2#\_/S\<
+M'!P<'"XL+"PN"BL*+AP<'!P<'`,[+$@K*TA(2$@['!P<'"Q(2$@_/S\_3$Q,
+M3$Q,'!P<'`-,3$Q,3#](2#\_/TA,3$Q,3$P_/S](/S\_2#](2#],3`H*"E1*
+M5$I45%145%145"E45%1*5%145%14*50I*2DI*5,I4SY34U-34U-44U-34U-3
+M4U-34U-34U-34QL;&R`;&R`;(!L@&R!*&R`;(!L@("`I(!L@("`@("`@("`@
+M("`@("`@("D@($1$1$1$1$1$1%-$1$131%-$4T1$1$1$4E)$,5)34E)24E)2
+M4E)24E)24E)34E)24E)24E)24E)24E)24E)24E(;4U)24E)24E)24E)24E9B
+M5F)B8F)B8F(:&F(6&A86%A86%E-44D=4"D@_2$A,3#],/TQ(/S\_2$A(*RLK
+M+`H*+`HF+"8Z*4<81Q@8&!@8&!@8&!@8&$08&$<8&$1$"@H**RL*2$Q,3#\_
+M*RLK*RLK*RLK*RM(/RLK*RLK*RX<'!P<'"PL+"PL"BP**TA(2$@L'!P<'!PL
+M*RLK*PH*2$@<'!P<'!P<+BPK*RM,3$P_,1P<'!PL/S\_/RM(/TQ,3"PL+!P<
+M'!P#3$Q,3$Q,2$@_2$@_/S\_/TQ,3#],3$Q,3#\_/S\_/TPF)B945$I45%14
+M5%145%0I5%145%142E145%145"DI*2DI*5-3/E-34U-34U-34U-34U-34U-3
+M4U,;4QL;&QL;&R`;("`@&R`;*2`@(!L@&R`;("`@(!M$("D^("`@("`@("`@
+M("`@("`@($0@1$1$1$0@*5-$1"!$1"!$1$I$1$1$4E-24E)24E(;2@)24E)2
+M4E)24E)24E)21$1$1$1$1$1$1$124E)24E)24E)24E)24E)2&QM68E9B5F)B
+M8F(:8AH:8AIB%A86%A93(2$A(20C3#\_3$Q,/TP_/RM(/TA(2$@K+`HL.RP[
+M.R-*1$='1QA'&$<8&!@8&!A'&$<81T<81T<81"D*"BLK*PH_/S\_3#]("@H*
+M2$A(2"M(/S\K"BLK*PH*1AP<'!P<'!Q&'#$<,1Q&'!P<'!P<'`8N2$A(2#],
+M/RM('!P<'!P<`RP**T@_3$Q,3$8<'!P<1D9&1@P,1CHZ#`P<'!P<'!Q%,3],
+M/S\_/RM(2$@_2$A(2$Q,3$Q,3$Q,3$Q(/TQ,3$P*5%145$I*5%1*5%145%14
+M5%145%1*5%1*5%145%0I5"DI*2DQ*5-3/E-34U-34U-34SY34U-34U-34U,;
+M&QL;&QL;&R`;&R`;(!L@&QL@&R`;(!L@&R`@&R`@(!L@("`@("`@("`@("`@
+M("`@($1$*41$("!$4T1$4T1$1$0I1$1$1%)$4E)24E)24E)24E)24E)24E)2
+M2D1$1$1$1$1$1$1$1$1$1$1$1$1$1%)24E)24E)24E)25E9B5F)B5F)B8F(:
+M8AI"&AH6%B0A%A86%A86%B,_*T@_/S\_2#\K/S](2"M("CLN"B,L(R94&!A'
+M1T='1T='&$081T='1T='1T<81Q@81T1$,0HK*TA("@H*/S],/PHK*TA(2$@K
+M/TQ,*PH*"@H**T8<'!P<'!P<'!P<'!P<'!P<'!P<144</TA(2$A,2$@**QP<
+M'!P<'!P["BM,3$Q,3$@,'!P<'!P<'!P<'!P<'!P<'!P<'`-%'$@_2#\_/S\K
+M2$A(2#](2$A,3$Q,3$Q,2$A(/TP_/S\K5%142CI45%145%145%145$I4*2E4
+M5%145%1*5%145"DI*50I*2DI4SY3/E-34U-34U-45%-34U-34U-34QL;&QL;
+M&QL;*2`;(!L@&R`@(!L@&R`@&R`@&R`@&R`@(!L@("`I("`@("`@("`@("`@
+M($0@($13($131"!31$1$1$0@1$1$1%)24U)24E)24E)24E)24D1$1$I$1$0@
+M1$1$1$1$1$0@1$1$1$1$1$1$1$1$1$1$4E)24E965F)65F)B8F)B8F)B8AH:
+M&AH6&A868A868A86("PK/S](2$@K/TA(2"LK*RL*"BP[(U1$&!@A&"%'1R%'
+M1R%'(4='1T='1T='1T='1T<81%,[*T@K"BLK*TA,/T@**RLK*RLK*S](/T@*
+M"@H*"@I&`T5%`P,#`T5%145%145%145%10@</S\_2$A(*PHK*S\Q`T5%145%
+M#"PK/TP_/S](.@,<145%145%145%145%145%144#'`H_3#\_/S\_2$@_/S](
+M2$A(3$Q,3$Q,3#\_/TA(3$P_#%145%142E145%145#%*5%145%145%145%14
+M5$I45%145"DI*2DI*5,^/E,^4SY34U-32E-34U-35%-34U,;4QL;&QL;&QL;
+M&QLI&QL;&U,@&QL;&R`;&R`@&R`@&R`@(!L@&R`;("`@("`@("`@("`@($0;
+M("!31%,@("!$1%,@($1$1$1$1%-$4E)24E)24E)21$1$1$1$1"!$1$0^("`@
+M($0@1$0@4T1$1$1$1$0@1$1$1$1$1$165E965F)68F)B8F)B8F)B8F(:8AH:
+M&AH68A868A8D4SHK2$A(2"LK*RL*"BP*+"XC5%)'1T<A&"$A1R%'(4='1T='
+M(4='1T='1T='1T='1T=$4PH*"@H*"@I(2"LK"BL*"@H*"BLK"BLK"@H*"@H*
+M,45%!D4#`P,(!@A%!@@&"`@(!D4[3$PK/TA(2"LK*RM,,0@#`P,(`S$C+"LK
+M"@H**SH&!@8&"`,#`P,#`P@#`P@&!@8&.BM,3$Q(/S\_3#\_/TP_2$A(2#],
+M/TQ,3$Q,3$Q(/S],+E142E1*2E145%0Q2DI45%145%145"E45"E45%145%14
+M5%14*51**2DI*5,I4SY3*5-3/E-34U-34U-34U-34QM3&QL;&QL;&QL;4U-3
+M4U-34U-34U,;("D@&R`@&R`@&R`@("`@("`;("`;/CX@("`@("`@(%,@4T0@
+M1$0@("!$("`@($1$1$1$1$1$1$121$1$1$1$1$1$1"!$("`@("`@("`@("!$
+M("`@("`@("`@1$1$1$1$1$1$5E965E965E9B5F)B8F)B8F)B8F)B&F(:8A9B
+M8A9B%F(6&%,C"@HK"BLL"BP[.E1$1T='1R$A&"%'(4<A1R%'(4<A1T='1R%'
+M1T='1T='1T='1%,*"@H*"@H*2$@K*PHK"@H*"@HK*PHK*PH*"@H*"C%%109%
+M`P,#"`8(108(!@@("`9%.TQ,*S](2$@K*RLK3#$(`P,#"`,Q(RPK*PH*"BLZ
+M!@8&!@@#`P,#`P,(`P,(!@8&!CHK3$Q,2#\_/TP_/S],/TA(2$@_3#],3$Q,
+M3$Q,2#\_3"Y45$I42E145%145%145%1*5%145%145%145%145#I*5%145%14
+M5%0I*2DI*5,I4U,^/E,^4U-34U-34U-34U-34U,;4QL;&U-34U-34U-34U-3
+M4U-35%,@&R`@&R`;("`@&R`@&R`;("`@("`I("`@("`@("!$4R!$1%,@("!$
+M.D0@($1$1$1$1$1$1$1$1$1$1$1$/D1$("!$("`@("`@("`@("`@/B`@("`@
+M("`@("`@("`@("`@(%965E961U965F)B8F)B8F(88F(88AIB&AIB%F(68A9B
+M%F(68A861%131"%2)%)21T<A(2$8(4<A1R%24B%'4D<A1T<A1U)'1T='1T='
+M(4='4D13"@H*"@H*"DA(*RL**PH*"@H**RL**RL*"@H*"@HQ144&10,#`P@&
+M"$4&"`8("`@&13M,3"L_2$A(*RLK*TPQ"`,#`P@#,2,L*RL*"@HK.@8&!@8(
+M`P,#`P,#"`,#"`8&!@8Z*TQ,3$@_/S],/S\_3#](2$A(/TP_3$Q,3$Q,3$@_
+M/TPN5$I45%145%145%145%145$HQ5%14,5142E145%142E1*5%145%145"DI
+M*2DI*5,I4U,I4U,^4U-34U-34U-34U-34U,;4QM34U-34U-34U-34U-34U-3
+M(!L@&R`@&R`;("`;("`;("`;("`;("`@("`@&T0@4T0@4T0@1"!31$I31"`@
+M("!$1$1$1$1$("`@($0@1#X@("`@2B`@("`@("`@("`@("D@("`@("`@("`@
+M("`@("`@("!65E965E961U968E9B8F)68F(@8F)B8F)B%F)B0A9B%F(68A86
+M(2$A(2%'(4<A(2$A(4<A(4<A(2$A(2$A1R$A1R%'1R%'1U-31R%'1T='1T='
+M4E,*2"L*"@H*"@H*"BM(2$A(*TA(2"L**RLK*PH*+B8P,#`L+"PL.R8L+B,N
+M+BXN)BL_3$A(/S\_/S\_*TA,"BPN+BXL.CHF(PH*"@H*"BXL+#`N.RPL+"PL
+M"@H*+"P_/S](2$Q,3$P_2$A(2$@_3#](2$A(2$A(2#](3$P_/S](/S\*5%14
+M5%145"E4*5145%145%1*2E145%145%145%145%145%145%1*5%145"E4*2DI
+M*5,I4U,I4SY34U-34U-34U-34U-34U-34U-34U-34U-34U-34U134QL@&R`;
+M(%-*("`;("`;("`;(!L@("D^*2`;("`@&R!3($132E,@("`I("!$1$1$1$1$
+M($1$($1$1$1$($0@("`@("D@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@5E9'5E965E9'5E9B5F)68F)B1QAB8B!B8AIB%F)B%A9B%F(68A86(4<A
+M(4<6%A86(2$A1R$A(4<A4E(A(2%'(2%'1R%'(4='4D='1R%'1R%'1T=2)C\K
+M*RLK*PH**PI(2"LK*TA(2#](*T@K*RLK*RX["BLK2$A(/T@K/T@_2$A(2"L_
+M/S\K/S\_/S\_/TA(3$@K2$A(/PHL)B,F"BLK*PI(*RLK2"L_/S],/S],2$A,
+M3$Q,/S],3$Q,3$Q,3$Q(/S](2#\_/S\_3#](*TA(2$A(*S](5%145%145%14
+M5%145%145%145$I45%145%145%145#I*5"E45%145%145%145%145"DI4RE3
+M4U-3/E-34U-34U-34U-34U-34U,I4U-3&QM34U-34U-35%-3&R`;(!M*2AL@
+M&R`;(!L@*2`@&R`@*2D;(!L@&R`;(!L@("D@(%,@(%-$4RE31%-$1$0@1"`@
+M("`@("`@("`@("`@("`;("`;("`@("`@("`@("`@("`@("`@&R`@("`@(%96
+M(%965E96(5965E968E9B5F)B8F)B8F)B8F)B%F)B8A9B%A86(2$A(2$6%A86
+M%B0A(2%'(4<A(4<A1R%'(2%'1R%'(4='(4='(4='(4='1T<A1U)*/RLK*RL*
+M"@HK"@HK*RLK*T@_2$A(*RLK+`H*"BP*"BLK*S](/TP_/S](2$A(3$Q(2#\_
+M/S\_/T@K2$@K*S\_/TA("BPF(RQ(2$@K3$@*"BLK/S\_/S\_2$@_3$Q,3#\_
+M3$Q,3$Q,3$Q,2#\_2#],/S\_2$@K*S\_2"LK*RM(.U145%14(U142E0I5%14
+M5%145%145%145%145%145%145%145"E4*5145%145%145%0I*4HI*5,I2E-3
+M4U-34U,I4RE34U-34U-3*5-34U-34U-34RE3*5134QL;(!L@&R`;(!L@&R`;
+M(!L@&R`I*1L@(!M3&U,@&R`@4R!34QL@4T13(%,@(%,@1%,@($H@("`@("`@
+M("`@("`@(!L@("`@("`;(!L@&R`;("D@&R`@&R`@("`@(!L@("!65E965E96
+M5E965E965E965F)B5F(@8F)B8F)B8F(68A9B%A9B%A8A(2$A%A86%A86(2%'
+M(2$A(2$A(2$A(2%'1R%'(4<A1R%'(4<A1T<A1R%'1R%'`B,_/S\_/S\_*PHK
+M/S\_/PHK2$@_/PH*"BLK/T@L"D@K*RL_/T@_/TA(3$Q,/S\_*RM(/S\_/S\_
+M*RLK2$@_/S](2$@K,#HF"@H*2"LK*PHL*TA(2$@_2$@_3$Q,3$Q,2$Q,3$Q,
+M3$Q,3$A(2#],/TA(2$A(*S\_3#](2$A(.TI45%1*5%145%0I5%1*5%145%14
+M5%1*5%1*5%145%14)E145%14*50I5%145"DI5%145%0I*5,I4U,I4U,^4RDI
+M*2DI4U-34RDI4RE35%-34U-34U-34U-34U-3(!L@&QL@&RD@("D;(!L;(!L@
+M&R`;&QM34U-3&QL@&QM3&R!3&R!3&R!34U,@4U-$("`I1"`@("`@&R`@("`@
+M&R`@("`@&R`@("`@("`@("`@("`@("`@&R`;("`@("`;5E961U965E965E96
+M5E968E9B5F)'1V)68F)B8F)B8F(6%F(6%A86%A86%A86%A86(2$A(4<A(4<A
+M(4<A1R%'(2%'(2$A(4<A1R%'1R$A1R%'(2%'(4<D)B8F/TA(/S\_/S\_/T@K
+M"DA(2"LK*RL_/T@*"BPK/S\_2#](*RLK*S\_/TP_2"M(2#\_/S](2$A(2#\_
+M2$A(*TA(*PHL)@H*"BLK/RLK+CLK*RLK*TA(3$Q,3$Q,/TA,3$Q,3$Q,3$Q(
+M2$A(3$@_/S\K2$@_/S](/S\_(TI45%0I5%14*50I*5142E145%0Q2E145%14
+M5%0Q5%145%14)E145%0I5"DI5"DI*5145%14*2DI*5,I4RDI4U,I*2DI*2DI
+M4RDI4RE34S$Q4U-34U-34U-34U13&QL;(%,@&QLZ*1L@(!L@(!L;(!L@&R!3
+M4U-34U,;&QL@&QM34R`;4R!3(%,@4T13(%,@(!L@("`;("`@&R`@("`@("`;
+M("`@("`;(!L@&R`;(!L@*2`@&R`@("`;(!L@(%965E965E965E965E965E96
+M8E9B8E9B8F)B8F)B8A86%A86%A9B%A86%A86%A86%A86%B$A1R$A(2$A(2$A
+M(4<A1R%'(4<A(4<A(2%'(4<A1T<A4T<A1R$D)",K2$@_/S],3$Q,/T@K"BL*
+M/S\_/S\*"BLK"DA(2#\K"@H**RM(2$@_*RM(2#](2$A(2#](2#\_2"LK*S\_
+M2$@K*RPL+"PK/S](*RLC2$A(3$A(*TQ,3$Q,3$Q(3$Q,3$P_/S\_2$A(2#](
+M2$A(2$A,/S\_/R,C(U14*5145%14*50I*2DI2DI4*5145%145%145%142E14
+M2E145$I*5%145%145"DI*2DI5%145%14*2DI*2E*5"DI*2DI*5,I*2D^/E-3
+M4U-34U-34U-34U,I4U-34U,;&QL@&QL@4R`;&QL@&QM*2E,;&R`;4U-44U-3
+M4U,;&QL;(!LI&R`;(!L;4QM34U,@&R`@("`@("`@("`@&R`;("`;("`;*1L@
+M("`@&R`;("`@(!L@&TH@("D@(!L@("!65E965E965E965E8A5E965E965E9B
+M8E9B8F)B8A9B%F(6%A8D4Q86%A868A9B%A86%A86(2$A(2$A(2$A(2$A(2$A
+M(2$A(4<A(4I'(2%'(2$A1R$A1R%'(20D2D@_/S\_/S\_/S\_/S\K2#\_/T@K
+M"@I(/PHK*RLK"BL*"BLK2$A(*TA(2"LQ2B0D4S$F"BM(/T@K*RM(*RLK2$@N
+M2E-34U-3*S\_"BLK*S\K2"M,2#],3$Q(*S],3$P_*RLK*T@K/S\_2"LK*TA,
+M/TQ(/R-*2BE4*2E45"E45"DI/BDI*2E*5#I*5%145%145%145%145%145%0Q
+M5%145%145"E4*50I*5145%145%14*50I*2DI*50I*2DI4RE34U-34U-34U-3
+M4U-34U-34U-3*5-3&QL;&R`;&R`;(!L@&R`;(!L@&R`;&U-45%-34U-34U-3
+M&QL;&R`;("`;(%-34U-34U,@1!L@&R`;("`;("`@("`;(!L@&R`@(!L@&R!3
+M(!L@(!L@("`;(!M*(!L@&R`@5E965E965D=65E8A1%965E968E9B5E9B5F)B
+M8F)B%A9B%F(6%A868A868A86%A86%A86(186(18A(186%A86%A86(2$A(2$A
+M(4<A(4<A(4<A4B%'(2$A1R$A)"0I2#](/TA(2#\_/S\_2#\_/S\K*S](/S](
+M"@H*+`HL+`H_3$Q,3"LK/SI$5P`I)"0D)%,*2$@K*RLK2#\K*RQ34RE34U-3
+M4U(L/RLK*RM(2$A(2"M,/S\_2$@_3$P_2"LK*TA(3$Q(/TA(2$@_3#\_*R-4
+M5%13*2E**514*2DI*2DI/BDI*2E*5%0I5%145%145%145%142E14,5145%14
+M5%145%0I*50I5%145%145%145"DI5%0I5"D^4SY3*5-34SY34U-34U-35%-3
+M4RDI*5-44U-3&QL;&R`;&QL@&QL;&QL@&QL;(%-34U134U-34U-34U,;(!L@
+M&R`;(!M34U-34U0I&RD@("`@2AL@(!L@&R`;("`@("`;&R`;(!L;&QL;&QL;
+M&QL@("`;(!L@&R`;(%965E965E8A5E965B%65E965E965E9B5F)B%F(6%F(6
+M8A868A86%A9"%A9B%A9B%A8D5!86%A86%A86%A86%A86%A8A(2$A(2$A(2$A
+M(2$A(5,A(2%'(2%'(4<D1T<8&#](2$@_/S\_/T@_/S\_*RL_2#\_2`H*"BP*
+M+"P*/TQ,3$PK*S\Z1%<D)"0D)"13"DA(*RLK*T@_*RLL4U-34U-34U-2+#\K
+M*RLK2$A(2$@K3#\_/TA(/TQ,/T@K*RM(2$Q,2#](2$A(/TP_/RLC5%134RDI
+M*50I*2DI*4H^*2DI*2DI*50I5%145%145%0Z5%145%145%145$I45%145%14
+M5%0I*2E45"E45%145%145%14*2DI*3X^/E,^/E-34U-34U,^5%-34U-34U,I
+M4U-34U-34QL;&QL@&QL@&TH@&QL@&QM34U-34U-34U-34U-34U,;&QL;(!M3
+M4U-34U-34QL;(!L@&R`;(!L@&R`;(!L@&R`;("`;&QL;4U-34U-34U-34QL;
+M(!L@&R`;(!LA5E965E965E965E965E965E965E965F)B8F)B8F(68A9B%A9B
+M%E0:&A9B%AH6%A86)!9B%A86%A86%A86%A86%A86%A86(2$A(2$A(2$A`B$A
+M(2$A(2%'(2$A1T='&$='2$A(/S\_/S](/S\_/RLK/T@_/T@*"@HL"BPL"C],
+M3$Q,*RL_.D0D)"0D)"0D4PI(2"LK*RM(/RLK+%-34U-34U-34BP_*RLK*TA(
+M2$A(*TP_/S](2#],3#](*RLK2$A,3$@_2$A(2#],/S\K(U0I4RDI*2DI*2DI
+M*3XI/CXI/BDI*4HI5"E4*514*514.BE45%1*)E142E145%145%142E145%0I
+M*2E4*50I5%145%145"DI*3X^*3X^/E,^2E-3/E-34U-34U-34U-34RE3*5-3
+M4U-34U13&QL@&QL;&R`;&QM34U-34U-34QM34U-34U-34U-34QL;*4I34U-3
+M4U-3&QL@&R`@&R`;(!L@("`;("`;(%-34U-34U-34U-34U-34U-44QL@(!L@
+M&R`@5E965E965E965E964E965E965E965E968F)B8F)B8F(6%F(:8AH:8AIB
+M%AH68A9B%A8:%AH6%AH6%A9B%A86%A86)!86%A86%A86(2$6(2$6(2$A(2$A
+M(2$A1R%21T='1T<_/T@_/S],2#\K*RLK/S\_2$Q(+BXN)CL["BY(/TQ,3"M(
+M/U,8)"0D)"0D)"1**T@K/S\_/T@K*S%*4U-34U-31"0@/TP_/S](/S](/RM,
+M/S\_2"M,3$Q(2#\_/TQ,3$Q(2$A(2$@_/S\K2E0I4U-3*2DI*2DI4RE3/E,I
+M/BDI/BDI*2DI*5145%14*3I45%145%145%145$I45%145%145%0I5"DZ*50I
+M*2DI5%145$HI/BD^*3X^/BD^4RD^/E,I4SY34U-34U134U1*4U-3*5-34U-3
+M4QL;&QL;&QL;&QM34U-34U,;4U-34QL;&U-35%-34U-34U-34U-34U-34U-3
+M4U,;&R`;(!L;(!L@5"D;4U-34U-34U-34U,;4U,;&U-34U-3&U-44QL;&U96
+M5E965E965E965D=65E965E965E9B5F)B8F)B5AAB8F(68F)B8F)B&AH:&AH:
+M&AH:&AH:%AH6%A8:%A8:%A86%A86%A8D%A86%A86%A86%A8A(2$A(2$A(2$O
+M4D='1R%'/S](2#\_/S](*RLK/S\_/S\_*RPL+#HZ+`H*"DA(2$A(2"LD)"0D
+M)"0D)"0D&PHD)"0D)"0D)"134U-34RE34U-31RP_/S\_*T@_/S](3#\_/TA(
+M/S](/T@_/S],3$Q,2$@K*RLK/TP*#"E4*5,I4RDI*2DI4SX^/CXI4RE3*2DI
+M*2DI*5145%0I5%145%145%145%145%145$I45%145%145%14*50I*2E4.DHI
+M*2E**2DI/BDI/CY*2BE3/CY3/E-3/E-34U-34U-34U-34U-3*5,F4U-34U-3
+M&QL;&QM34U-34U-3&U-34U-34QL;4U-34U134U-34U-34U-34U-34U-44U-3
+M&QL@("`;4U-34U-34U-34U,;&QL;&QL;&R`;&U-35%-3,5-35%165E965E96
+M5E965E965E965E965E965E968F)B8F(@&!9B8F)B8F)B8F)B8B`:8F(:&F(:
+M8AH:&AH:)&(6&A9B%A9B%A86&Q8D%A86%A86%A86%A86(2$A(2$A(2\A&$='
+M1RLK/T@_2#],/S\_/TA(/S\K*RL*"@HL(R8L"@HK*RLK/S\L0B0D)"0D)"0D
+M)"0D*20D)"0D)$I*)%-34U-34U-34U,C*TA(2"L_2#\_2$A(2$@_*T@K/TQ,
+M3$Q,3$Q,/T@K3$A(2#\[*50I*5,I4RDI*4HI/E-34SY3/E,I*5,I*5,I*2DI
+M*5145"DI5"E45"E45%142E145%145%145%14,5145%14*50I*50I*50I*2DI
+M*2DI*2DI*3X^*3XI/CX^*5-3/E-34U-34U-34U-34U-3*5-34U-34U-34U-3
+M4U,Q*5-34U,;4U-34U,;&QM34U-34U-34U-44U-34U-34U-34U-34U,;&QL;
+M4U-34U-34U-34U,;&QM4(!LI&RD;(!M34U-34U-34U-35E965E965E965E96
+M5E965D=65E965E9B8F)B8F)B&&)B8F)B8F)B8F)B8F)B8F(:8F(:&AI"&F(6
+M0AL:&A8:%AH6%A9B%A86%A86%F(6%A86%A8D%A86(2$A(1LA+T='1T<@("Q(
+M2#],/TA(2$@K/S\K2"M(2$A(2`HF(RP*+`H*"DA(2%,O)"0D)"0D)"0D)"0D
+M)"0D)"1*)$I34U-34U-34U-3"BM(2$@K*S\K2#\K/S\_2$@K/T@_3$Q,3$Q,
+M3$Q(3#](2$A*5"DI.E-3*5,I4RE3*5-34U-3/E,^4PQ3*5,I*2DI*2E4*50I
+M5"DI5"E45%145%145%145%0Q,5145%145%145%145#I*.BDI*2DI5"DI*2DI
+M*2DI*3XI4RDI4U,^/E,^4THQ4U-34U-34U-34U,I4RE34U-34U-34U,I4U-3
+M4U-35!M34U-3&U-34U-34RE34U-34U-34U-44U-34U-34U-34U-34U-34U-3
+M4QL;&U-3&QL@&R`;(!L;&QL;&U-34U-34U-34U965E965E965E965E965D=6
+M5E9B5E9B5F)B8F)B8F)B8AAB8F(@1V)B8F)B8F)B8F(:8F)B0D(:&F(68A9B
+M%F(6&A9B%A86%F(6&A86%A86%A86)!86%A86(2%3(5)31T='1R0D2D@_2$@K
+M2$A(/TA(/RLK/TQ,3$P_"BX*"BP*"@HK*RL**4<D)"0D&R0D)"0D)"0D)"0D
+M)"0D4U-34U-34U-34RLK2$A("@HK2$A(3#\_/S\K/S\_3$Q,3$Q,3$Q,3#\P
+M5"DI*2DI*4HI*5,I*3I3*5-34U-34U,^/E,I4RDI*2DI*2E4*2DI5"DI5%0I
+M*5145%145%145%145%142E145%145%14.E1*5%145"E4*2DI5$HI*2DI*2DI
+M*2E*4RDI/CY3/E,^4U-34U-34U-34U-34U,,4RE34U-34U-34U-34U-3&U13
+M4U-3&U-3,1M34U-34RE34U-35%,I5%,I4U-34U-34U-34U-34U-3&QL;&QL;
+M&QL;&QL;&QL;&QL;&QL;&U-34U-34U-65E965E965E965E965F)68E8Q5F)6
+M8F)B8F)68F)B8F)B8F)B5F)68F)68F)B8F)B8F(:&&(:8AIB&AH:&AH:&A9B
+M%AH:%AH6&A86&A8:%A868B06%A86%A8A(2$A4D<A(4<A)"0Q+$A(2$A(2#\K
+M2$@*/S\_/S],/T@L+`HN.SL[+`H*2"LC5"`D("`D)"0D`@("`@)24E)$1"`@
+M4T13(%,@4QM(*TA(2"LL/TA(2#\_/S](*S](/TQ,3$Q,3$P_/PI*5"D^*2DI
+M*2DI*5,I4RD,4U-32E-34U-34U-34RDI*2DI*2DI*50I5"DI5"E45%145%14
+M2E145%145%145%145%145%145%145%145%145"E4*50I*50I*2DI*2DI*2E3
+M*5,I4SY3/E-34U-34U-34U-34U-35#X^*5,I4U,I4RE34U-34U-34U-34U-3
+M4U-34U-34U-34U-34U-34U-34U-34U-34U-34U-34U-34QL;&QL;&QL;&QL;
+M&QL;&QL;&QL;4QL;&QM3&U-35E965E965E965F)65F)65E961U9B8F)B8F)B
+M8F)65E965E965E968E9B8F)B8F)B8F)B8F(:8AIB&AIB&F(68A9B%AH:%F(6
+M&A9B%AH6%A8:%A86&A86%A86%B$A(2$A(4<A(4<A1QLI"C\_/S\K*RLK"BM,
+M/S\_3$Q(2`HN.SL[.S`N"DA(2$@[.SL;)"0D)"0")`)24E)$1$0I($13(%,@
+M3$P_/T@_/S](*TQ(*T@_2$A(*RM(*TQ,3$Q,3$@_3$I**2E34U,I*5,I*2E3
+M2BD^4U-35"Y34U-34U-34RDI*50I*2DI5%0I*2DI*2E45%145%145%145%14
+M5%145%142E145%145%145#%45%145%145%14*50I*2E4*50I5$HI*2D^*3X^
+M*5,^4SY34U-34U-34U-34U-34TH^4RE**5-34U-34U-35%-34U-34U-34U-3
+M4U-34U-34U,;4U-34U-34U-34U-34U-34U-34U,;&QL;&QL;&QM4&QM3&QL;
+M5!L;&QL;5%13&U,;4U965E965E965E965E965E9'5F)B8F)B8F)B8E965E96
+M5E965E965F)68E9B8E9B8F)B8F)B8F(:8AIB&F(:8AIB%F(68A8:&AH6&A8:
+M%F(6%AH6%A86%A86%A8A(2$A(2\A(4<A(4<A1R0^+"PL*RLK*PI(/TQ,3$A(
+M2"LL(RXN+BXL+"PL*PHL.SL[("0D)"0D)`("`@)24D0@4T13(%,L&TQ,3$A(
+M2$A(2$Q,/RM(2`H*"BLK*S],3$@K*RLK)DHZ4RE34U-3/E,I*2E3*2E34U-3
+M4U-34U0^4U-34U-3*2DI*2DI*2DI*2E4*5145%145%145%145%142E142E14
+M5%142E145$I4,51*5%1*5%145%145%145%145%145%142BDI*5,I4SX^4SY3
+M4SY34U-34U-34U-34U-34U,^4SY34U-34U-34U-34U-34U134U-34U-34U-3
+M4U-34U-34U-34U-34U-34QM34U-34U-3&QL;&QL;&QL;&QL;&QM3&U,;4QM3
+M&U-34U-34U-65E965E965E965E965E961U968F)B8F)B8D='4E965E965E96
+M5E965E9B5F)B5F)B8F)B8F)B8F)B&F(:8AH:&F(:8AH:&AH:)&(68A8:&A8:
+M%AH6%A86%B0;)!8;(2$A(2\A(4<A1R%'/BPL+"LK*RL*2#],3$Q(2$@K+",N
+M+BXN+"PL+"L*+#L[.R`D)"0D)"0")`("4D1$("`@("`@+$Q,3$Q(2$A(2$A,
+M3#\K2$@*"@HK*RL_3$Q(*RLK*R9*.E-34U-34U-3*2E3*2E34U-34U-34TI4
+M4U-34U-3*5,Z*2DI*51*5"DI*5145%145%142E145%145%145%142E145%14
+M.DI45%145%145%145%145%145%145%145%145%14*2DI*3XI4RD^/CY3*5,^
+M4U-34U-34U-34U-*4U-34U-34U-34U-34U-34U,Q4U-34U-34U-35%-34U-3
+M4U-34QM34U-44QM34U-34U-34QM3&U,;4QM3&U14&U,;4QM3&U-34U-34U-3
+M4U-35E965E965E9'5E965E965E9B8E9B8F)B8F)B1U965E965E965E965E96
+M8E9B5F)B5F)B8F)B8F)B8F)B&F(:8AIB&AIB&F(:&B`:&AHD&QH6&A86&A8:
+M%A86%A86`A8A(2$A+R\O(4<A1R]'+RPK*RLK"D@_3$Q,2$A(*RPC+BXN+BPL
+M+"PK"BP[.SL@)"0D)"0D)`("`@)21"`@4R`@4RQ,3$Q,2$A(2$A(3$P_*TA(
+M"@H**RLK/TQ,2"LK*RLF4U-34U-34U-34U-34U-34U-34U0Q4U-35%-34U-3
+M4RDI*5,I*2DI*2DI5"DI*2DI*2DI5#I45%145%145%145%145%145%0Q.DI*
+M5%0Q5$I*5%145%145%145%1*5%145%145%145"DI*2E3/CY3/E,^4U,^/E-3
+M4U-34U-34U-34U-34U-34U-34U-34U-34U-34U-34U-34U134U-34U-34U-3
+M4U-34QM3&U,;4U-34U-34U-34U-34U-34U-34U-34U-34U-34U-34U-34U96
+M5E965E965E965E965E965E9B8AAB8F)68E965E965E965E965E965E965F)6
+M8AA'8E9B8F)B8F)B8F)B8F)B&F)B&F(:&AH:&AH:&AH:&AH:%AH6%AH6%A86
+M%A8A(2$A(2$A(2\O+U(O+T<O/BXK*PHK"BLK*RM(*PH*+`HK*RL*"CLL"@HC
+M.CHZ("0D)"0D)"0D`@("4D0@("`@(%,[3$P_3$A(*RLK3$Q,*RLK2"LK*T@_
+M3$P_2`HC(U1*4U-34U-34U-34U-34U-34U-3&U,;4U,;4U-34U-34U-34RDI
+M*2DI4RDI*2DI/CX^/BD^*2DI*2DI5%145%145%145%145%142E0Q5#%*5%14
+M5%1*5%0Q2E145%145%1*5%1*5$I45%145"E*/BD^*3X^4SX^4U-3/E,^4U-3
+M4U-34U-34TI34U-34U,^4U-34U-34U-34U-34U-34U-34U-34U-34U-34U-3
+M4U-34U-34U-34U-34U-34U-34U-34U-34U-34U-34U-34U-34U-65E965E96
+M5E965E965E965F)B8F)B8F)'8E965E965E965E965E965E965E961U96&%9B
+M8F)B8F)B8F)B8F)B8F)B&F(:8AIB&F(:&AH:&AH6&AH6&A86%A86%A86%A8A
+M(2$A(2\A+R\O+R\O1U)21T<K*RLK*RM(2$@K*RL*"@H**RPC.RLL.SHZ.B!"
+M)"0D)"0D)"0"`E)$("`@*4I3.C\_3#](2#\_/TQ,3"M(2"L_/S\_3$Q("DI4
+M&U0Q5%-45!M34QM3&U-34QM3&U-3&U-34QM35%,;4U-34U-4/BE34U-34U,^
+M4SY3/E,^4SX^/CX^*2DI*2E45%145%145%145%14,4I45%145%0Q5%145%14
+M5#%45%145$I42E1*5%145%142E14(RDI/CX^/CX^/CX^2E,^4SY3/E,^4SY3
+M/E-32E-3/E-34U-34U-34U-34U-32B934U-34U-34U-34U-34U-34U-34U-3
+A4U-34U-34U-34U-34U-34U-34U-34U-34U-34U-34U-3
+`
+end
diff --git a/win/win32/splash.uu b/win/win32/splash.uu
new file mode 100644 (file)
index 0000000..6af2d66
--- /dev/null
@@ -0,0 +1,2374 @@
+begin 600 splash.bmp
+M0DVVH`$``````#8$```H````N`$``/`````!``@`````````````````````
+M````````````;&Q'```````M.&<`N7YB`!PCG``4%9@`(C&<`!DE8``)"94`
+M*S`^`)>8FP`)"<L`"0ED`!<890!E9VD`S\O1`!,9.`!#6F,`'2C3`&5OG``,
+M##T`F:?,`!04-@`/$\T`'A@8``D)\P#`M<(`F=#5`$%8I`"9@)``>GZ=`+"8
+MJ``I1<8`559;`,"RM0!(7,@`#@\0`%EOO`!_E\\`5B@>`#4_0`!_;WX`04F-
+M`')P<@#5U-X`SVQ$`*FMKP"B/R<`?HF\`-?+S0#V_?X`XO+T`.#@YP#.VMT`
+MX^KK`+-9/`"BAYD`)T2E`$AM@@#___\`,4)F`,3$T@!C?<``+#-K````0```
+M`(````"@````P````.````#_``!`````0$```$"```!`H```0,```$#@``!`
+M_P``@````(!```"`@```@*```(#```"`X```@/\``*````"@0```H(```*"@
+M``"@P```H.```*#_``#`````P$```,"```#`H```P,```,#@``#`_P``X```
+M`.!```#@@```X*```.#```#@X```X/\``/\```#_0```_X```/^@``#_P```
+M_^```/__`$````!``$``0`"``$``H`!``,``0`#@`$``_P!`0```0$!``$!`
+M@`!`0*``0$#``$!`X`!`0/\`0(```$"`0`!`@(``0("@`$"`P`!`@.``0(#_
+M`$"@``!`H$``0*"``$"@H`!`H,``0*#@`$"@_P!`P```0,!``$#`@`!`P*``
+M0,#``$#`X`!`P/\`0.```$#@0`!`X(``0."@`$#@P`!`X.``0.#_`$#_``!`
+M_T``0/^``$#_H`!`_\``0/_@`$#__P"`````@`!``(``@`"``*``@`#``(``
+MX`"``/\`@$```(!`0`"`0(``@$"@`(!`P`"`0.``@$#_`("```"`@$``@("`
+M`("`H`"`@,``@(#@`("`_P"`H```@*!``("@@`"`H*``@*#``("@X`"`H/\`
+M@,```(#`0`"`P(``@,"@`(#`P`"`P.``@,#_`(#@``"`X$``@."``(#@H`"`
+MX,``@.#@`(#@_P"`_P``@/]``(#_@`"`_Z``@/_``(#_X`"`__\`P````,``
+M0`#``(``P`"@`,``P`#``.``P`#_`,!```#`0$``P$"``,!`H`#`0,``P$#@
+M`,!`_P#`@```P(!``,"`@`#`@*``P(#``,"`X`#`@/\`P*```,"@0`#`H(``
+MP*"@`,"@P`#`H.``P*#_`,#```#`P$``P,"``,#`H`#`P,``P,#@`,#`_P#`
+MX```P.!``,#@@`#`X*``P.#``,#@X`#`X/\`P/\``,#_0`#`_X``P/^@````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````(:(0``````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````&`X)````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````)`DA*Q8````6"1``````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```0"AHN"0``$"$*"0``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````!@*#P\)`!8*
+M#Q4)````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````DH````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````$!T/#P,)"2(S+@D`````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````6"AH)````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````D&`D"'P\/+`H""@\:"0``````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````D/(@D`````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````!`*(AL*%1L/+A$=&P\H````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````"1H;"0()````````````````````````````````````````````````
+M````````````````````````````````````````````````````&"(L#PH#
+M&QL:#@H5%0(`````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````A(ALK+A\)
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````0'AH/'@H5#QLB%2(;#A`8
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````"1L;#P\/&Q8`````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````!@."B(*"A,<'!T;&P\/'A``````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````)#RP;-BPB(1@`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````%!T*'1,3!@4"!@H:&S85&```````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````DB#QLL#P\;"0``````````````````````````````````````
+M```````````````````````````````````````````````````````````8
+M'@HA$0<&`CD""@HF%0HG````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````"1L/
+M&PH5+#4G````````````````````````````````````````````````````
+M`````````````````````````````````````````````!8*+A$"*@8<$0($
+M!@8.$Q4)````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````"+AHF$QL/&@X)````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````$`H*(0(<#A,.!`<%.08."@X)````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````DP$P8"%1LF#S`H````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````0'A41!`83'`8"!@X<$1P<%0H6````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````@HJ`BH<(QP<$PH)````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````!8.)0<%!`8@!@0&*AP@!!<5"A8`````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```)"B,<`@8&!@(.%0D`````````````````````````````````````````
+M```````````````````````````````````````````````````D`@($!0T&
+M!@82!1$C(Q<2!B4=&```````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````!`3(P8@(Q,<
+M!`8<)Q@`````````````````````````````````````````````````````
+M`````````````````````````````````````"@*$P("!`@2(Q,$!B`@&1D7
+M$QP`````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````%AP&$@8<(!(7!`8*"A``````
+M````````````````````````````````````````````````````````````
+M````````````````````````)PH<!P8$!08@(`L2!B,@$@L<*B0`````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````)$P82(`8&&0L&!ALB%@``````````````````
+M````````````````````"20`````````````````````````````````````
+M```````````"&RH"!@((!!D2!@L@(QD+!B`<"0``````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````DC%Q(@$A(9$@L&&B(1&```````````````````````````````
+M````%B@*"0````````````````````````````````````````````````D*
+M!@0&!`8%"PL%$A<2&1D2!1P3"1@`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````$!,C
+M(`87$@L9"`43'0H)`````````````````````````````````!@3'QL)````
+M````````````````````````````````````````````&`(""`8@(P@,"`P,
+M"`@$!0@,#0(&`@``````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````))2,@$@4$%QD2`@(>
+M'PX)````````````````````````````````%AX?%2<D"1@`````````````
+M````````````````````````````````%!P&$B`&`@<""`P(!0L+!`P(!P("
+M`A@`````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````D5)2`$`@P+%PL+!`(1"@HG%```````
+M```````````````````````0`@X;"0D#"0``````````````````````````
+M```````````````````8$R4&!`0,#`P-!`0+$A<("P4("`8.$```````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````%!$:%2,$`A(("PL%!`(1#@H)````````````````````
+M````````)QX))QX)"1,8````````````````````````````````````````
+M```````0*!P"#`(,#`L+%PL9&1<2"`L(!0(6````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````&`H?'`(-"`L2&0L(!PD1'2$8"0D)%``````````````````````H"B$)
+M`R$1(18````````````````````````````````````````````````)'@(,
+M#`4'%Q(9&1D9&0L+!`@(#0``````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````D$`D0"08&
+M"PL9&1<+!0T"'!$=&PH)%A@6````````````````"2$*`A8K+@HA$```````
+M``````````````````````````````````````````D*!A`(!P@(!@L2&1<9
+M(`L+!00"%```````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````!8K)007$@L9&1(&"`P-
+M!@("`@X?"A```````````````!`*&PH)&"$>"@(6````````````````````
+M````````````````````````````(1L"%@P,#0@+"!D9$AD+%P0,!`(0````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````%@X3!@@+%QD9&1D%"`@"#!`-'!4*"0D)
+M)```````````"1H/`Q`4"2$.$1@`````````````````````````````````
+M```````````````)'0X'!PT$"!<+&1D+"Q(+"P@$*A8`````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````%`DJ'`8%"QD2&0L+!`@%!P<-`@T"'1X)```````````4
+M*QX""18)$!@)"1``````````````````````````````````````````````
+M`!@)*Q,"#`@(!`4("`L+%PL("`(<"0``````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````)`D*"AP$"Q<9&1D("P(-"`4'#`("!A$6`````````!`A#@('!P(4&!8*
+M"A8```````````````````````````````````````````````D5%0(,#0@(
+M"`L2%Q(+(`@$!A,)````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````%AX*!@8@
+M$AD7&0L2"`0%!`T,#`P-`@()`````````"@"!P81`A80`@H;(20`````````
+M````````````````````````````````````&`H;#@<,#`8(!@L("PL+"P@"
+M'0D`````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````&!@)"B8J!A(+"Q<(%P8+
+M"`<%#`0%$Q,6````````(0X"$0X1`@("$1,*"0``````````````````````
+M````````````````````````%B$*!@P(#`@%"!(%"P8(!"HF"0``````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````!0)*`DE%1(+$@@+$@L7"P0&"`(.!B0`
+M`````!8)$0(1`@("$0(1*AX)````````````````````````````````````
+M````````````%`D"#0((!0<&!1(+"P4$!@D8````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````$!,>(`07"R`+"QD2"PL(!08\&````````"@A!A$A
+M!P(1$1$"'"$)````````````````````````````````````````````````
+M%A$&!PT'!!$&"!(+!@8"%@``````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````4(1$&!`L$"Q<+&1<+!@0,!`D4```````8`AP"`@8"!A$"#00&%148
+M```````````````````````````````````````````````8'@H"#`4$!B`7
+M"PL&(PXD````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````!@*%0X%
+M#`@+"Q(9&1D+!00&`A8``````!0"`@(<`@("`@<"#1P;&Q``````````````
+M``````````````````````````````````D:(@('`@83(Q<+!@@E)18`````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````8"2$))```````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````4(145`@<,#00+&0L9(`@%
+M"!,<%```````%`(&`@("!0("!`P"!@H*(10`````````````````````````
+M````````````````````"0\/`@D-!B4C(`L(%Q4*$```````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````$`(?&S`)$!``````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````6%A`0"2$5$P8%#`T(!0L($AD+!@0%"AT8```````8
+M`@8$#00-#`4"#`(-!B8*(1@4````````````````````````````````````
+M```````)&P\"!P(1(R`2%P@$&Q46````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````"03
+M"B,3!A$*"A8`````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````!`*#Q45"AP"#`((!PP$"Q<+"P8(`@05'A```````!0J'`("#`P)!PP)
+M#`P'`A$*"A```````````````````````````````````````````!8/&@("
+M"0(<"R`+!`85&@D`````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````D`@HC&0L$(Q4F"0D"
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````8"0<6"14:&Q4>
+M!@P,"`@%"`@7!`4(!`8$`A4*$```````)`X3#0P6#`P,#0P,%!0,!Q45(18`
+M````````````````````````````````````````&!H5`@<"$082"P@(!1L*
+M"0``````````````````````````````````````````````````````````
+M````````````%`DA`@D6%A08$`D8$"<6%```````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````"<*(R`@&1<+!@83&@HA)```````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````$`D6``D*"A,A!B$&`@8-`@0(`@@$%P0+
+M"!<"$08"%1\)%@D0&!`)&B("#`P0#!00#`T,#`P,`AP=(1`8````````````
+M```````````````````````````0$R8"!0@$!@8+!0@",!X6````````````
+M````````````````````````````````````````````````````````%@D"
+M'2X*#AX.(1$"$Q,K"@H)&!88````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````"0H2&1D9$@L$!08<'A4G````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````!@*&AX1!A,<'!$"!PT,!`@(!0@("!<("P42"`0"!@(>)@H>
+M)1T>(AHS&PX'#`P-#`T,$!8'%A0,"1P5"A``````````````````````````
+M```````````````A!@4,"!<&!A(2"P0E$Q``````````````````````````
+M`````````````````````````````````````````!`*(AX3'`XJ(1P.$0X1
+M'`X3*Q,5"A``````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```))B,2(!<2"P4$#0(3%0D`````````````````````````````````````
+M```````````````````````````````````````````````````````````8
+M$14;,!P"$0(A$08"!PT"#`@($@4(!`L$"P@&!@('#`83"C`*%14*&@\5(10'
+M"10,$!0,#!0,#0<,!@\*$``````````````````````````````````````8
+M"0(%!P4("`0&(`0+`AXI&```````````````````````````````````````
+M````````````````````````&`D)$0H;$P(,`@<"!A$&`A$H$0X1$P\N%@``
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````8``D>'BH<(08&
+M!P<-"`83`A8`````````````````````````````````````````````````
+M`````````!08&````!00"1```````````````````!08$"@*$P8.$1$.$0("
+M`A$&#0@-!@@7"`07"`4+"`4<`@T'!P4&!@8&`@8&`@('`@P-!P<-#!86!PD0
+M%`<)'!,)%`````````````````````````````````````(>`A8,!P@$(!P"
+M#`T''"H4````````````````````````````````````````````````````
+M```````4%@DH"@H3$2H""`0"!`@"`@<"`@81`@(.'A,)%```````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````"1X)%BD3#@("$1,)&!`$!`8=#A0`
+M````````````````````````````````````````````````````````"1X<
+M`A`4"0(*"A8`````````````````"0H=#@8&`@(.#A$"`A$"`@("!`0("`@(
+M"P@2"P8+!`8"!PT$!`(%!P0%`@@-!`($`@("`@("`A$"`B@"!PT-$0,)````
+M````````````````````````````````%@X&#`P(#0@"`@T'#`<"`A0`````
+M`````````````````````````````````````````````````````!`#%1X.
+M!AP&!P<"#0($!00,#`P'`AT*'BL&$PH)````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````)`D."@()$QX=$0D)#A88%`T%`B8*$1@`````````````
+M````````````````````````````````````````&`DA"A,""0T'!AL5`A@`
+M````````````)`D3"B8<#0(&$1$1(0<"`@(&`@0"#00+!@L&"P4+"P0"`@4'
+M`@4"`@4"`@('`@4"!@T&!A$&$08"$0X1$0()`@DA%0X)%```````````````
+M````````````````%`D1$0T,"`<(#`('`@P,#`T'"1@`````````````````
+M```````````````````````````````````````D(14/$P8"!PT"!00(!`@(
+M#0P0"0D"*QX=#@<.'@D`````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`!@""B(;(0D.`QX)"0D)$`$8#`0%`BH=$1`4````````````````````````
+M```````````````````````4%A@"$QX1#0P'"0()`@X*$184`````````!0)
+M"A43!@8"'"$1#A$1`@<&`@8$`@4$%P@+"Q(+"P@+"`4$`@P-!P4$!`(&`@8"
+M`@(1`@<"`A$A'!$.$0X1#A$.$0XK%1X)$!80)```````````````````````
+M```0'Q4"%@<-"`P"!P(("`T'#!$*$0``````````````````````````````
+M`````````````````````!@0%@(='`8&!P0%#`0%"P@%#08$`@(6$0(6$!@8
+M%!06````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````*`H>"@\N`Q$.
+M`@D)*!0!&!0D%@<%/!,5"A``````````````````````````````````````
+M`````````!`*%1P1`@P,$`<-"0T'!P85"A@`````````)PHE$P8-!!$<$1$"
+M`@T"#0($!04(!P4$"Q(%"P42"P8(!`@""`T$#0(%!P4"`@(&`@4"!@(&$0X1
+M(1$1(1$1#@X1#A$.*R$3)@H)``````````````````````````DN%0<,"`P,
+M"`T("`4$"P@-!@HG````````````````````````````````````````````
+M````````"0H.$08$!P(-"`@'"`@$!0<((!4;`PDK$Q@`````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````"&BL."AHB`A`)`B@)&!80)!@0
+M"0($$1H;"0`````````````````````````````````````````````D(2(:
+M#@P,#`D,#0P'"1`,`@H5`A@````````"+BH"!`81$0X.#@('`@0'`@(%$@8%
+M$@4&"P@+"R`+"P@&"`@'!P4$!0((`@@%!@(&!P0"!!$A$1$.$0X1#@X1$0(.
+M#B@1'"85%2$)"1@`````````````````````&!,=`@P,#`((!`4+$A<("P@&
+M%0(`````````````````````````````````````````````````"0DA%1X&
+M`@4""`0(!@L%"`@-$`8E'Q4>#@H*%@``````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````DB$R$1#@X0`10)"0D0)`$8)`$0`@("'A,)&```
+M````````````````````````````````````````%A$5*P('#10)#`P)$`T0
+M#10'!RH>(1``````$`D&!@<"#APA$1$1!P((`@T'!`0(!00&$@4+"Q(+"!<(
+M"PL(`@T,!P($!`(%!`<"!P(&!P8%`@<1(1$A#A$1$0X1$Q$1$2$1#@(&$QX=
+M"18D$````````````````!00`A$,#0<4#`P,"PL9"QD$""H*"0``````````
+M`````````````````````````````````!@0%@D>$Q$&!@4'"`0%"`8("P8'
+M%A0-'B8)%B@=&QX8````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````*!43*Q4.`A@!$`X8$!@4`10D%A0)!PT"'!4)````````````````
+M`````````````````````````!8*"AP-$`D"`@<)%`P,$!0'"0P'"`X>`Q8`
+M`"03'@("!!$1$0X1#@8"!0<"`@0%"P@+!!<+"!(9%PL2"P0%!`4'#`<(!04"
+M#00"!04$!0(%!`($!P8"`A$1(0X.$1$"`A$"$0(<#@(&!A,"$0,)````````
+M````````"1X.#`<0#`D,!P42&1<9%PL&!@D6````````````````````````
+M````````````````````"0HK'"H"!0<&"`4,!1(+"P4("`P8`1`*%0D`&`D)
+M"20`````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````````D."BD3
+M(A$4$`$)(0D4&!@0&!8D&`('"0<&"@(`````````````````````````````
+M``````````D)`A\5`@D,#0D0"0T'"10-%`T4#10,!R8P*!04*!,*!@<"`A$.
+M$0X1`@0"!04'"`@%$@8%$@47$A<9"P8+"`L("`P'!08$`@0(`@4$`@<"!`@$
+M!0<%`@0"`A$1#A$.`A$A`@()$0X1$0('!0(3"B$)"0`````````````H&@(,
+M%A06#`P,#`L9"QD+!B4.%@``````````````````````````````````````
+M)`D)"0D1"B4<!P((!0L$`@@+"`L@"Q("%!84%A4:&```````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````8"@\*$RL*(1@4&`DA$"00
+M`1`!)!0D%!8)#`<J"1`8```````````````````````````````8$!@)`PH.
+M(1$)!PD0"0T4"10)%!`'"0P0#`D0#1$=*`D*'`(A$0(3$2$1'`(""`($!@0$
+M"P@2"`0+$@L7"QD+"P@(!00(#0@%!`4$#00"!`4$!04"#0(%!`8(#081$PX"
+M$0D1`A$1$2$"$1$"#@("!`(1#A,*(18D`````!00%B@>*@<,%`<,"0P-"`8+
+M(!(&%1T8````````````````````````````````````&!8)"AL*'"H&`@4"
+M"`0-"`@+!`L7"PL%(!P")!`)"BX0````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````D/#QX.'1X.$0D1(0()%B0)"188%!@D%!0"
+M`@8*'A8``````````````````````````````!@='@(1(0()$0D)`A80%!`)
+M#1`)"0P,#!8,#0P,!P(<$Q,""0("$1$1#@X1`@0%!`4(!1<(%P47!1D7!!D+
+M$@42!1((!P4$!`($#00"!0T$`@(%!`0%!`(%!@0"`A$.'"$"`A$"`@("`@D1
+M$081#@X'!08.#A,*'1``````"0H3$Q$0#`P-!PP,#`0,"`8E$P()`A@`````
+M``````````````````````````````D*&AX.!BH&`@4$#00%"`P2%PL9"Q((
+M!`(P&PH.`@(""0``````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````8$1\5$PX.#@XA*`X.*!`)$`())"0!`1@!"0T$`A4*%@``````
+M````````````````"100$!00"28*`A`)"0(""0()$!8-"0(1"0<-"106!Q80
+M#`<-!"H3$0T'*!$A`@X1(0("!0<%!0<$"!(7!`02"PL&"P4+"P@+!`4$"`4%
+M#00"!00$"`(%!`8%`@0'!`0&!@(&$081$0X&(0("`@("`@D"`B$1`@("#A$A
+M$14N(1`6)PDA%0H<#0P-!PT,#0P,#`4''!,K%@``````````````````````
+M````````$`DH"1`)"0H5$P0'#`0-!`<("`8""Q<+$@L+"`4,`ALQ&R$H#A@`
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````&`(*
+M$0D)*`(A$1$A'AX)`@D8$!`6`18!%`$0!P('*@X)%``````````)$`D)"1@)
+M$`(**@(&`@81`@8)!P()$0(,%`T)`@X3"B83`@T'#0P,#`<-#`P-!P4)%`D"
+M$1$1`@('`@0$!0@$#00%$@L+&0L9"PL+$@L%$A<(!0@'!`0$!0@$!0@"!PT"
+M!`0%`@4"!@(&$0(J`A$"`A$1`@<-$0("!P("`@D"/`(1`A$.#A,*"2@5"A,.
+M#0('`@P'"`<(!PT,!!,F(1@4```````````````````````4$!8)$!8)"AL*
+M$QP"!B$&`@4"!00%%P42"P@2"QD+&00,"1`"%0HH&"@="0``````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````!8>"B$4&!06)!86"0DH
+M"10)$`$6)!@0&"06`1@-`@T'`@H)````````"1HB&AH/#QHB%1X1!@0"!`8$
+M!PP"`@()"0<0`@H"$`DH(0H"$`T'!Q8,#0<,!P@-#`D-!PD-!P(,#0<%!04+
+M!!<(!@L+%P07&1<2%PL%"PL+!`@$!`4%`@4'!00%`@4%"`@%!@@'`@8'`@0"
+M!`0"`@("$0X1`A$"`@<'`@()!PD"`A$1`B$1$2L1(1$.`@<"#`@""`4,!0P-
+M#`(5%0X4`````````````````````````!@*(A\*'0XJ*@8&!@((!`8(!`4(
+M!1($"PL7&0L7$@L(#`P0%`D""10`&`DD````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````4$14*`B04%!@4)!@0%A@D&!@6)`$4`0$4
+M`204&`<-!PT&%0(````````)"@\/,C(S-C,;,!,.!@0%!@0%"00"*!`-`@8=
+M"@D````"+B$'"0P-#!`,#`T,!Q`,#`<'`@T"#`@""`<"!!<+"`4$%Q(+"PL9
+M"PL2"PL2!0@%"PL7!`@$#00%!`0'!`<&!`4$`@4&`@8'!0('!A$'`@('!@("
+M(1$"#0T"'`<-!PD'`@(H$1$"`A$1#0P'#`(-`@@(`@@'#`<-*@H*&```````
+M````````````&`()`@D)"1\;%1X3$P<'`@0-!`(%"`8(!!<$!!<2&0L2&1D+
+M$@T0"186`A``````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````)"$*)1P%!P("!PT6#!`)$!0D&"04&!`!&`$8%!@D#`T'!P(3
+M`A@``````!88"1$B-"P/%28;&Q4@'"`$!0<,#0<"`A$.%0H"``````D*#@P,
+M`@('#0T'!PT,#0P-`@4'"`<"`@<-`@T'!P0+!`4+"Q<2"Q<+%QD7$@L+$@@&
+M"`0-!@0%!`4%`@4(#04(`@@$!A(&!@(&!`4"!@(&!@4"`@81!@($$1P"`@("
+M`@D"!PT""0<"#0('"`(%!P8'`@<'"`T(!P(>$1`````````8"180&!`4%!`)
+M"AH>$PX<(1P"!0(&!P(%!08+!`82!0L+"Q(2$AD9&1D9$@8@$0(0!PD3"0``
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````!`3
+M'AP&`@(%"`4$`@0-`@P-&!`4&!0D`184)!`D)!84"0(-!Q$5"A8`````````
+M%@X/,S4E(",5&R`2'`0%!P@-!!,N'P()"0``````&`(3#@T'#0<'%`T4$!0'
+M#1`4#`("!04%!`($#0T(!0P$"P8+"PL9&1(9"Q(7"`8+"PL$%P0%$@L&!`0"
+M`@4$!`0"!04%`@0"!@X&!@<&`@0$`@($`AP"*@(.$R$"!`(-!PP,!P<-!P(,
+M!`4$"`@"`@((!0@"!`T.$R$8````````"14B&PH>'0X.(0(<$RH&!@0&`@<$
+M!P(%!`0$`@@%!00C(`L@&2`2&1D9&0L%!!,;&AT)(1LG````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````&`DG"1XP$08$!`($`@0-
+M!`($`@<6#!06`18D)`$8%!@8`1`,`@<"#2(5"0``````````&!T/&Q4C(R8F
+M$A(@'`8&#0<-#@H*%@``````````&!T>`@<""186$!@4&!80#0D-!P0"!P($
+M#00-!`<'#0@("PL+$@L+%QD7"PL$"PL2!0@&!0@+!@L%!0<%!`@%#00"!`0%
+M!`8<!AP"!`("!0(,!`4"*AP1$0X.$0("`@('#0P-#`<6!P(%"!<("`<&`@<-
+M!`@$#1XK$18)$`D0%A`)%0\:'QT3$QP<'`(-`@@,!0((!04$!00&!08$!@L2
+M%R`2&1D2(!(7$AD@"`<-$1H;'@<""@D`````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````)%14K$1$1$0(%"`0""`4"!`4"#`0'!0D0
+M&`$4&!0D`1`4%@<)`@('$QX0````````````$!@A%1H>)1,<'`8E'QT0%``4
+M%A@````````````6*R8""180%!`4$!84$`P(!PD4%@P,`@@%`@0(#0P(!P4$
+M$A<9&2`9$@L2"Q<+!0L$"`@&$@42!`8-!`T$!00'!00%!@@"!@X"!A$"!@0&
+M"`4&"!<$`@81'`X&!A$&`@<-!PT'#0<%"`0("PL&`@(&!`((!0T$$PH>'BL3
+M#AX.`@8.!@X1'`8%!@(%`@@$`@0"!`0"#00&$@42!@82%PL9(R,@&1D@&1D+
+M"`@-"0T&`A@6)!08%```````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````"0HF$R41`@8-!`('!0T"!P<-`@4"!0($#00-"10!)!06)!@0
+M#1`"!`T&`A0``````````````!@)*`(0(14;%0(""0``````````````````
+M```)"0(0%A`-!P("!P<%`@(%#0<8)`T,`@0,"`8%!P4%!`4("Q(9&0L9%PL(
+M$@L2"Q(%"PL+"`@%!`@%!`4'#0@&"!(%!`8@'`8&!@(&!@4$`A(%!`8(!@(&
+M`@8$!`(-!`T'#0<"#00(%P@%"P4$`@<%#0($!P(.$PXJ`@8A'`("!`4"!0("
+M`@0-!P4$!00%!`4(!00(!1P7!`@2!B`9&1(E(R,9&1D2"P(-!PD'"1$)````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````````````D.
+M)B4@!B`&`@(""`((!`0"!0('!`<(!0<%`@0,&"04&`$4`0T0#0<"#`("*!0`
+M```````````````````)"AH*%@`````````````````````D"0D0"0<4!PT(
+M!00&!`T$#0<'`A08%`<(`@4""`0'"`4$"`(2"Q<2&1<+"PL7"Q<("`L&"P8+
+M!@(%!@4%!`T$!00+!0($'`8&$0("!`82!`(%"`0+!00$!@($!P4%`@($#0<"
+M`@T$!0@%$@L$!`(&`@0'"`(%`@(1$00%!P(1'`8"!P@"!P4"!0(%!`8(`@("
+M!`8$!08&!@0($B`<&1D@$B,E("`9"PL%!PP)#0P"$PD`````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````0"AL&!AP@$A("!@T$
+M!0@&"PL$!@("!@('`@4"`@T"$!8D$!@D%`D'"0P"!P8>"0``````````````
+M`````!@0"1@0```````````````8&!`6&`D*#A$-#`(-!`($#0("!0P$`@@-
+M!`T4"0(%!P@"#`4'!`(%`@8%!@07$A(7$@L+$@8+!1(+!`4$"`0+$A(%!`@&
+M!`4$"`8&'`X"'`8&!@8%"`0%!@@2!0@$!0(%!`($`@8"`@(1!@8"!`@($@8&
+M!00%!P("#`<(`@(&`@<"!0("#0($!0($!00$`@0""`8$!00%!`L+"Q(@%Q(+
+M(R`@&1D2("`@"QD+!081`@<"#`X*`@``````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````!`="@(%!A(&"`4$`@P'"`L9&2`&`A$"
+M!P4(!P4'!00,#10!%`$)#`P,#0<,`A,)````````````````````````````
+M`````````````!`*(AX1!`8&!`((!`("`@("!0($`@4-!`((!PT4%`<"!0@"
+M!00%"`0&`@81!@8+$AD(!@L("PL2"!<(!`4%!@L%!@4""`@(`@0%(!$A$08<
+M*CD"!@0+!`4$#`8(!0($!@L$!0@"`@<"$2$&'`8&$@(&`CD"!`(&!0T'`@4$
+M`@('!0@$!00%!`4-!`<%!P8%"!(%!`@%!AP7%P87!@8+%Q(@(R`9&1D2%Q(+
+M!`4$*AH/%1,"!PD8````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````$!,3`@0(#`P""`0("`4$!0L7"P81!@($`@<-!00"`@($
+M"18D%@P'`@T'#0P"*A``````````````````````````````````````$`D"
+M*`H;,"H""`<"!`T"!0(&$1$$!`T(`@0$!00%!Q80#00(!@@'!`T$!@4$(1$.
+M'`87$A<+"P87$@4+!`4+$@0($@0$!00&!@0%!002!AP"!B$<!@0&!A<+!00%
+M"P((!R`%!@4'!@8-`@81!CD<$@0%!@8&!@4$!@<"!PT$#0($`@8"`@(%!`("
+M`@0"!00%!@0&!00%"P8&(!(2"P0&$@L9(!,C("`2&1<+"`4"!P8<%2(:$Q,<
+M%@``````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```8#A,,#!8)$!0(!04$#0@'"`P'!0("!@(-"`@'`@0%!PP,%!0D%@P,%`P-
+M#`("%A@````````````````````````````````8$!@)'A\3(0("!P('#04'
+M`@8'`@("`@("`@0,"`4"!PT$$`T'`@4$!04$!04$!P(&*A$1!@(+$A<+"PL9
+M%PL&"`4(%PL7!04$"`L(!00+!08&!@0&(P8"!B`$!@0&"`0%$@4&!`L$!`8%
+M!@(%!`8&!@L%!@8$!`8"`@("!P<%!`(&!`4%`@(&!`<&!`4$"`4("P8"!`4$
+M$A<+!@8&!A<2("`7"PL9("4F(R`2"`($`@0&$RL"$`D""@H0````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````!03'`40%!0,
+M#042"P@(#`T4"10'`@8""`<,#0@%!`T%`@P%!PP,!PT'#`<"!0<>#A8`````
+M````````````````````````"0H*$R$&!@($!0("!A$&`@<&`@8-!00&`@<$
+M!0(%!`0%!`4-#`D-!`8$`@@"!`T%!00"!@X1!@(+&1(7&0L2"`L+$@07"`8$
+M!`4&"`8+!`4$"`4&!"`&!@87$@8&!@4&"P4$"PL&!@@"!@8'!@02"Q<2"P02
+M$@4&!00&`@0-!0P"!00"!`((`@0&!04$!04&!`4$"!<<!A(+$@0@'!(2"PL@
+M$AD9(!D@("`7!`@-#`0&!@8"%B0``!@)"10`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````%!$3!`4,"0@+$@L+"`(,$!@4
+M#`(&!00"!0P'#`("!`<-#`(,#0T,#10,%@@"#1,=$10`````````````````
+M``````D)"0D"%0HE$0T'!0<"`A$A`A$"!@(&`@@'`@0&#0(-!`0-`@4&!`<"
+M%`<""`4$!@4$`@0$`@0"`@("!!<+"QD+"P4+%Q<+!00(!@@%!`4$!0L%"P@&
+M!!(&(`0"!`8%"`0"$@07!!<(!@@$!0($!AP"!08+!`42%P@&!00&`@("`@@$
+M`@@$`@8%!`8%!`($!`4$!`4&`@@%!@0@!`L%"P8@"Q<2&2`+%Q(7"Q<+!0L(
+M`@8<'`8&$Q``````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````8'B,@"`8+"R`+%QD+#`P4#!`-!`8""`P'#0P-
+M!`4"!`T,#`@'!P4'#0P-!P<0#!P*"180"0D6)``````````8%A`)'1L>$PX<
+M`@(&`@("`@0"!@0"`@8"!00$`@P(`@0"!`8""`T%!`<%!@@0%@<1`@@%!`4+
+M!00%#08A$087$@0+$A<+"PL2$@L2!@@%$@42"`8+(`L$!A<&$RH<!A<2$@L&
+M!`@2%P@(!!<2!00$"`($`@8$$@8("P4(`@0$`@4"!00'!0P(!@4$!@((!00%
+M!`4$"P42!1(("Q($%P07"PL+$A(+&1<+&2,E(R`@"P8(!P(&"A\E'`8P*```
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````!8B&Q(+&0L7"PL+$@L7"P07"P8+!00%!`T'`@<-!PP"#`(,`@T(
+M!0(,!P<,#00-`AX="@HB'Q\)````````*`H*)A,.*B$&`@8"`A$1(08"!A$"
+M`@(&`@($#04%`@0%!P4"!0@"!`0%!04"!0P)`@8$!00%!`8$!00%`@(.`@8%
+M"Q<+"PL9"Q<+%P@$!00(!@@%!0L(!08J'`X<$QP2!1<%"PL7!0L&!`42"`4'
+M#0("!@("!P(,!0($!0<(!P4(`@0$#04(!P4(!@@%!`4$!08&!`42"P8(!@@&
+M!0L7"`L+&0L7&0L+&0L2$AP&!0($!@8$`APA$0D4$`D6````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````$`H:
+M(QD9%Q(9$@L9"QD9%PL9$@@%!`($#00-`@P-!P4(!PP(#`P'"`(,#10"!P<-
+M#B8B%1H/&R@6%"04$!0""@H*$P<0!P("!A$"!@(1`A$&`@4$#00'!`4"!`0'
+M!00%!`8$!00%!0<$!`4$#`D"`@<"!`T$!0((`@<"!@(&!00$$AD@"Q<+!`L$
+M!0((!@L%!!($%PL$!AP3$Q,.$R`2!`@&"`L$"PL(`@4""`(%!`T'!P(-`@0(
+M!P4$"!(%!`4$#04'!`0-!`L&!`4$#00%!`4("P@+%PL$"PL+!!(+(!D7"Q(9
+M$A<+"R`@!@0$`@8$!`T<$P(`````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````%B@E)1<+"Q<+%PL@
+M"PL9$@L7"`8%"`((!PT$`@4$`@P-!PT'#0T,#`<-!PP-#`<'!B$<$0X"`@("
+M!@("!PT&!@("`@("'`(1`@(1`@(&`@8'!`($#04"!`4(`@4"!`(("`("!`((
+M`@4%"`(-#0<"!00&"`0%!`(%!`("!00&!!<7"PL+&1D+%PL$"`L7$@@&"!<$
+M!2`<*QP3'A,<(`8+!1(%!`4$`@4$!`<%!`@$$@4%!1(%"P8+!`L&"`@"#0@"
+M"`((#00$!04$!@4+!0L$!1($%Q(&"!<2%Q(7%PL+"PL9"R`@$@L+%Q("`@T"
+M`@8@`@X*"0``````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````%`DE%1<2"PL2"PL+"Q<+$@L($@0%
+M!PT""`4$"`(,!`<%!PT,!PP"!0P'#0<,#1`"#`<-!P<"!Q$'`@('"0D"*`D"
+M$2$"`@<&`@0"`@4"!0(%#04'!`4$`@((!`@""`(-!`0%!`@$!00%"`('!P0"
+M!00%`@L%!`<.$R8&"`8&!`09$AD+"Q<2"PT"!@@$%P0+"!(&!A,3'`X3'!$1
+M`@0%!0('!0($#0(&!@4$"P4+"!(+!`@("`@+"`@&!00$!00("`4$!0@$!`@2
+M!`42"P8+"PL+"PL2"PL+"PL2&1(9"Q(J'",&!@8%!`T'`@D5#R,E,`(D````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````%AX*$A<+%Q(+%Q(+!`L7"!<%!@@""`<%`@((`@4-
+M`@T$#04'#0P$#`P'!10'#`P,%@(,`@("#0<)!PD"$0("!Q$&`@<$#0("!00$
+M!0($#00$!`4"!P4%!`4"!`4$`@@"!0T"!0($"`8$#0D-`@((`@@'!0('#!,5
+M&P8%!`(&$A<+&0L+"PL(!`@%"P4$"P8&"`8<#CH.#AP1(0("!0('!`4'!@4&
+M.08<!!<+$A(+!007%P0+!@L%!`($`@4-`@@-!`@$"`4(%P4("P4+!`L@"`L@
+M%PL%%QD7&0L7"Q(+"QPE$1P&!00"`@8""0H5)0H>)```````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````8%@(E(!(+"Q(9&1<+"PL&!`0(!`4(`@@$!0($!P<$#`P'#0<$#0<-
+M!PP'#0P'%@<-!PT,!PT'#0<-#0<'`@T"`@T$`@T"!`4'`@4$#00%`@4"!`4%
+M!`<"!`4$!@@(!00$!`<$"`@""`((`@<"#0<,#`((!PT1)AL;'`@(!P4$$@4(
+M!08(!`4-!P($!1(%"`0&$0X<#@X1$0X"`@(%!`4%!`L%!A$3'!,&%P0%!1(+
+M!@0$"`L("`(%!P4'!`@(!`@+!0L&"R`2"`L2"PL&"PL7$@L+"Q(+"Q(+$AD7
+M"Q<$!`(-`@("!`8$$Q,0%A`6$!8`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````&`<@
+M(!(7"Q<2&1(+!`@+!1(%$@0(`@0(!`T%!04"`@@-#0('`@@,%@P'#`T'#`P'
+M#0<,`@P6#`P'%`(,#`T$#`P%!P<-!`T(`@<"!`4"!`4&"`(%!@@%!P0%"`8$
+M!0T$!04%!`4$!0('!@T'%A`4%`D1'1L/%24%#0(,#04("`<(#`T-!P0%`@@%
+M!`("`@X1#A$1$2$.'`8%$@@(%P0(!083$RLZ#AP&`@07!@8"!@('!0<$#0P"
+M!`4%!`4(!00+!!<$"`L%$@4+"PL+$@L2%QD7"Q<+"Q<@!B`&"P0"#0<'`A,@
+M!@8:+@D`````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````!PC(`L9&0L9"Q<+
+M"P@$"P@(!@4(!@4"!`("!`(%!`<'#0('`@P,!PT'#`P)#`P,#`<,!PP'#0P-
+M#`T'`@P-!P<(#0((!P0$!04"!`4$#00"!`0%!`(%!0($!0@$!08&$@L$!0P%
+M!PT0!Q04`0D6#1T5#QLF!@@'"`<,!`@%"`T,#`0-!P4$`@('!@(1#A$1#@X1
+M(1$A!`@(!1(&"P4&!#H<'!,3$08"!@('$1P1!@("#04"!`4(!`@%!!(+!!<(
+M%P@7"!(+"PL@"PL7"Q<2"Q(+$AD2!!P&#@0"#`4$#1`"'@XA'!4*$```````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````0'14C"PL7"Q(+"PL@"P4+!1(+"`0(
+M`@0-!00$!04""`T$!PT$`@(,#`T-#`P,!P(,%@P"#`P,!PP$#`T,#`(,#`((
+M"`(-!0('!`@"!`($!04%"`<-!`0$!`@"!`4$!`8(!@4$"`0""106$!80!Q`1
+M(Q45*@4("`4,#0@-!`@%"`<"!`(%`@0"!A$1`B$"#@X"$0X1'`(%"`0""`@&
+M!`4"`@X.$1$"#@("`@8"#@(1`@0(!`@(!`@%!`0("`87$@L2""`+%PL7$@L+
+M$@L@"PL7"Q(7"P47`CD'`@("`@("#2$5`@(>(188````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````!@"#A42"!(9%QD2&0L+!`@+"`8%!`4("`<"!0((!A($
+M"P8%!PT,#`T'!PP'!PT,#`@'#`P,`@@-#`T,#`(,#`<(#`<""`0'"`(%#00%
+M!0<%!P0%!@4%!@47!@@&"`("!0('"`T,$!0!%"0)"0(*%1P&!B`$!P@,#`<,
+M!P@-"`<-#`@-!`0"$1$.`@(&/`(1`@X<(0("`@0"#`4"!0($`@4$$0(H#@X1
+M`@8"(3H<$PX&(`8%%P8+!@L"#`L%!`L%"P0+"PL2"PL+!A<2"PL+"Q(@!@8&
+M!`<""0T.'283(08'`B@D&`D`````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````))B4@"PL2%PL7&1<+$@4$!00(`@<"#0@$%Q(+"Q<+!`@"!`('`@T4
+M#`T,#`<-#`T"#`<,#`<,!PT'#`<-#`0-"`T$`@4(`@0$!00""`0%!`((!`0(
+M!`0(!`4,#00'!PP4$!8!&!8)`A$.$145'`($#`T(!P4'"`@-"`0(`@P'#`(&
+M`@8A$0X1`@(%`@(1$1$1`@(%!P4$`@4$`@4-!`(&!@X1.A,<'`8<$SHK'!P$
+M$@0$"`0%"`@(!!(+"!(7"R`7%PL2!1(7"PL7"Q(7"QP&.00%#0<'`@H5"@X.
+M`@XJ%@``````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````!@)'14&
+M%P@($@L$$A<+%PL2#00%"`@,`@@$%R`2("`@%Q(%!0<%#`<"$`P,#`P'#`@,
+M#0T,!0P(#`P-#`@"#`T'!0<%!P((!0T&"`8(`@8("`4"#0<%"`4$#0<"#`T4
+M%!80"1`"#AX5%14F(P($"`@(#`<,#`@-#`<(#04(#`4'`@(1#A$1`A$$`@4%
+M!`8"!@8"!0((`@0(!@@7!!<$"PL&(R43'B4F)1X3$QP3$P8<%PL7!`4$!@@7
+M"`07!`@2$@82%PL+"QD+$A<+"Q("!P(-`@("!0("%0HA$!0)'@H8````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````"00$Q4&"P@7"Q<("`@2
+M"`4%!`4%`@<%$A<$"R`5&B8<$0()#`<)#`T,#0(,#0P,`@P4!PP,#0<-!PP'
+M#`P,!P@,!`4$`@4$!`@-!`4($@8(`@<$`@4'!PP,#`T0%!0D`0<.'1L/&P\;
+M)@8%"`0,#0<,#0P%#`P,"`4'"`<$#0P"(1$.'`X.'`4+"`82!!((!!<2!1(7
+M$@L+"Q(+"`L+"PL7(",E$R8P)1P>$RL<(P87!`8("P@7!`L7$A<+"!<$%PL+
+M"Q(+%Q<C'`4"`@T'#0D3$P<-`@<)*````!@))Q0`````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````),!,7$@L("Q<2"P4$"`0%!P0(#`@&
+M!`L2)B(;)A,3`@<)%`D,!PD-!PP,"0P,#1`-#`<-#`<-#`P"#`P%#`4"#`4$
+M"`(%!`4$#00(!0@%`@4$"`P-%`D0%!08&!8)#ALL-2PT&R43!`P,!0P$"`P,
+M`@<,!`P"#`0-!0@("0DH`A$1$QP&"P0+"QD2%Q<2%QD2%PL9(!D+&0L+(`L9
+M$AD2(",E)B8F$Q,3$QPC!`0$%P@&!PL+%P0+!!<2"Q(+%Q(+!1(+!"H1!PP,
+M#0D'`AP3#@8<(18`````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````))A4&"`(+$@@+!0@7!`@(!0T"!`0%%R45%28E!@<1
+M"0(6$!8""`('`@P"#!0'#`P,!PP0%`P0!PP6#!8'#`P$!0T$!0@"!P4'!0P'
+M!P(&`@4(!`P,%!08%!81"A4*#RPV+`\>!@T,#0<("`4-"0<'#`@-#`@(#0@'
+M`@P-`A$)"0<"!P8+%PL+$@L9"PL9"PL+$@L+!0L7$@L+&0L+&1D9!@8C'",1
+M.AP3(`87!@0%!`@(!0L+"R`+%PL+(`L&!`L%"`4'#0<-"0D'!P(J"0(P)A,3
+M$```````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````D;+",7"`L+%PL$"`8(!A("!00%!08<)AL5)B`"!`("*!`4!PP'"`44
+M!PP'#0T6!PT,`@T,`@T4#`<'#`<%#00(!`((#`4-`@4(!!<%!`4(!`P%!Q80
+M"0<)$"<:#Q4;/28E!@T'$!08%`T$!PP'%@T'#`P'#0(,`@@-!`<'#`<,!PP,
+M#`0("`4+%Q(7&2`+&0L9"QD2$@L$"Q<2"PL@%R`@("`7$@8@(!(%!`0&(`<-
+M!`42%Q(%"Q(+$A<+"`0-!`(,`A8)!P(,!PP-`@X0)`D)"0D4````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````&!T*!@8$
+M!@L2!0@("P0+!0@"!`('!"45&R8C(`('`A$)%A86#`("!PT0#0(,!PT,!P((
+M!P('#`<"#0@"!P($`@<%#`@$`@0'"P@%!`8%!`4("`P,%@P)#`D4"2(Q#B4E
+M'`8(!Q8,"100"`4(`@<)!PP,#0@'"`P-!`T"#`T-#`P-"1`-#`4,"`07"!((
+M"Q(7$@L2%PL+%Q(%"P8(%R`2(R,@$@L$%Q(&!A(%%P8$!0T("`L+"PL$%P07
+M"`@&!@<)#`('!PP-'`X&`@<&'0D`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````"2$"("`+"QD+"P0%"`@&
+M!`4&!@0"'@H;)B4C`@8&$0(8!Q`"!`0-$`D"`@('`@('#0('!@4"`@T'`@(,
+M`@<%`@($#0(1!@8%$@@+"`0%"`@-!Q0'`@<-!`D"&P\A`@0%!`($!`4'%@P,
+M!@0-`@8$`@<,!PP-!`('"`((!PP0#0P,#`P'"`<-"`@,"`4("`@(!0L(!`@%
+M"P0(!0@&(Q,3'"`%"Q(+"PL$%P0$!@0%!`8$%PL$%P@%!@8$"`<)#`<-!PT-
+M%`(5&@H3!A,5"0``````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````!8*"@8%`@L9&00%"`0%$@@%"`<'#0()#B8;
+M+@8&!B`"`A8-#00-`@P)!P0"`@T)`@<)`@(1`@T"$00"!P<%`@("!@4$!@8&
+M$@0%"`8&"`@,!`P,%@P"!`('`A$:#R@$%P8&$@8"`@<'`@0,`@8"!P()"0D,
+M"`((!04$#0@-%!8'#`(,!P@(#`@%!P4,!P@"!PP(#`(("`<,!0('`@@&'"`@
+M!@L$!0L@(`4(!00(!`("!@L&$A<$!0<'"`T)#`<-"18'`@('`A\3*"@5"@(8
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````&!4:!@P,"!D+"P0""`@%"!(%#`4'!Q8"$QL5!QP<.1$)$`0-
+M!Q8,"0T"#1$)!P<"#0D'`@("`@("`@("`@0"'`8"!`(<!@0(%Q(("`P$!PT(
+M#100!P($`@T"'`\/(082$@8@!@8'"0P,#0T'`@T"*!$)#`P'#`0"!P<"#`<'
+M%`P)#!8,#0T$#`P$#`4,"`@-"`<,#0P-#`<,#0<(`@<"!A<2"!<2"PL($A(%
+M"`4-`@0"!`07"`@"#`T"!Q0)#0(&!PD-#`("'@D`%@H*%@``````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````8
+M'@H7!@L2%Q(7!00(!P0("`@("P8-%A`"!B`'(R4@(0(6!0(%!PP,!`(""0<"
+M`@(""0('"0<"`@<"!P("'!$"!@@%`A$&!`4(!@("!`4,#!80!P("!0(Y#1$]
+M,AL.(",@$@8$!@T'%!`'#`P,`@(H`@D'#0P%!P4"!04(#0T0#0<,#`<,#!0,
+M!0P,#`<-#`<(#0P'#`<,#00'#0T'`@('#0P%"`@&!0@%!@@"!P<"`@4-!PT'
+M!0('"0P"#0<"'A4"`@<"'`X)````&!88````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````!0C(PL+%PL($@@$
+M"!<+!0L(!@L@"P@'#0<$!`(&(QPH"0('!`<,`@T"`@<""0("`@("#0("`A$"
+M`A$"#0<"#@0'!`8K'"`"!P(-!PP'#!80%!0-!P0'!P0&)38T+!P@$@8@`@<)
+M!Q06#`T+"`8(!@4&!`T,!PP""`0'`@<,!PP4#`D,#0P'#0<,`@P-#`P,#0P0
+M#!0'#0T'#0T'"0("`@P,`@P'#`0(`@<,!PP"`@<(!P<,"0<1!@(4#`<)`@X1
+M"0D3$P8*%0D`````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````%A,C(!D+"PL+!0L%$@L(!`T("`L+
+M!00("`4&#`(&#@()!0@-!PT,!PD"`@T'`@<'`@('!A$"`@8"!@()!Q$1!PT-
+M!AP3!`@(%`T'"0P-%!@,!P("`@(%`A,5,S(/*@8$!00-#`D-&!`4#`0&"`@(
+M!`8"#`P6`@@"!0(%`@T,%A`-#!`4#!0-#!`,#`D,!PT'#`T,#0P4$`<"!P<"
+M`@('#0P(#!0-!Q8,#0P6#1`-`@(-#0D0#1,=#@()#`T"$PD!%BD>$PH*(0``
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````8)A4C"R`+!@@$!`@9$A<(!0P$!@L9"Q<(!`4,!PT)
+M#`P'`@4'#`(,!PT)#`T$#0(,!P(-"0P)#0<"#0<-`@(,!P<)#0T'#0(,"104
+M$!`0#`($`@<(!P(<&S0R-AL"$!0)%!@D$!`!#0D6%`T4$!@4%A0)%`P,#`0%
+M!P0,!P<)$!0)%!`-$!06#!0)#`P6%!0,"100%`T'#0P)"0<'#0@,!PP"#`D4
+M%A`0$!0)!PD0#`<"!Q0-%34;'1,"`@8#"0$D`2$*(1$5"0``````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````!@)#A,2"PL+!0T%"`L9$@@"!0@(""`9&1((!PT'#0<-!PT$!PT'#0P6
+M$!0,$!`"`A80#1`6%"04%A`,%A`0%`T4%A`0&!0,!PP'#`D,#0('#0<%`@<)
+M`A4V,C(L%0D!`10!%!@!%A0)"2<)&!84&"08$!80#`<-!PT'#0(%#`D6)!84
+M%A`6#"00%A`4$!80%A0D%!8'#!8'%!0-$`T0!Q8'%!0-$!0)%!8)%!81`A84
+M"18,"0D?,2PQ#Q4E`@(8`0$!"14>'!X)````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````)*@8%
+M!`0%!`($!@L7"P4$"`@(&1D+"P4-!PT'#0<""`4$#0@($!04&!`6`A$1#0$4
+M`100%B06`1`8&!08%!`6`1@4%A$&$1PJ$00$`@0"!`('!@(3-C(S+"X>"18D
+M&!@)&`DG"2<G+R<G&`D)%!06%`P6#00%`@8$`@@-$!@6$!@4$!80%A80%!8D
+M%`D4$!80%@('%A84&!00#106%`P)%`D0%A`0%!@0"0XK$0T0%`D4`A4/#P\/
+M#QT.$0D)"1`A)C`E)1$)"0``````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````!@6"1`)`@<%"`0("`4%"`L$
+M"PL+!00%$A<2"P0-%@<,%@P'#0(,`@P4$!8!%`D>"A,)`18D%B08%!`6%"04
+M"0D6"100%`D.$R8E%283'`8&!@8@#@XO+0,/+#$/#@D))PD8+R\W+R\O-S<O
+M)R<0`B$'"1`)$`P'#0($#0('!PT0%!@6%!`6$`P4$!@4"106$`T0&`P'"0T0
+M%!80%@D4$!06"184%!84%@D4%A`6$PH>(0D)%`T."@H*"A\5"AH*"@H3*B4F
+M%2(/&QH?$0D0&```````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````"0H?'@(6&!0,"`8(!@@%!`L7$@L2%P@+"PL+
+M!@@'#!0'%`T'!`4'#!@6)!0)"2$:(@DD%"04$!88%!@0&!`='@T8%!8)$!`)
+M"1`)$1,@'!LL#QL#-R\#+0,M`S<O+PD6&"<&(3<W+RTW+R$)%A$)`BH)#`T-
+M%`D(!P@"!`T-$!06$`()%A`6"10)%`D4$!0)%!`,"0P)$!80%A`4&!06"1`4
+M$!@0"1`8$`D4%@D>'PH#'B$0"1X*%0H;"@HB"A,J$Q,N&Q\/#P\/#P\:(@H"
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````4*`D)
+M`B@)"0D8%A@)+@H=(204$`T$!`4%"`0+"P@+%P@+!@L2%PL%!`T-%`T0#`T"
+M#104`104%@X1"0H*`@$6$`DA`A`6$`$8(14*"106"2$"%`$!`0<1*@0@%34S
+M,0,M)RTM+2\M+S<O&!@8`@8A-R\O+R\A`A`)$PD)$PD4$`D4%@P%#0<%!`0,
+M$!8)(0D,%!80%`D4$!08%A`6%@('#1`4"0D4&!04%A`6%!86%!0,$!80%A00
+M$0H5"@H*#@DA"@HN"@H*"A,>$QP&'1H/#QH;(@\:#P\V+"LG"1@`````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````"<5'PH*'PH#'BD.`B$)
+M"1`4%A8)!08E'!,@!@@&$@@($@4&$B`2$@@2#`<,%`T4!`4'%!`8)!@)%0H6
+M&`DA$`$)$PH>`@$8%"@3*!`"$!@H'@,8`20)"B4&"`8C(Q4#`RTO+2DO-R\#
+M+R<)"2$J+R\O+S<M(0D")RL="2@*(1`6$`<4!PP'!`<-#0<-$0X.(2@)%`P6
+M%`DA)PD4$`P'"0("%A00#!`0%A`)$!0)$!`)%@D"$!0)%@TA`PH*"@,*"@H*
+M%0H*'A,3*A,3"AH;(@\/#P\/&@\;#P\/#P\;(1`8"1``````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````"0H1"1$)"0D)%A`8$!@6&"0)"0<%!A,F
+M%28%"`@%!`(%!`0F&A4@%PL+%PL$"`P,#"08&`$!"0XA"1@`$!,"%@D)$1H"
+M$!0H(2<8"1X"#2LA"18!"1X<!`L%&1D2(P,#+3<G)R\I+3<G%@D<'"<)%B<G
+M(2D"#0(*&B@8%A$5"B<.$PD,!P(&`@4'`@(.*2L.`@T0"1`G$2L.`A80#0<"
+M$1$'$!`6%A80"0(0%!0-%A00"0X""1`4"1X*"@H*'0H*"@H>$RH&!A,*&QH/
+M(@\:#QH/#P\;(AH/#P\Q#P\B'QL/"A@`````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````)'0D)%A06&!`8)!@4$!`8%@D)"0T$)145)2`$!00%"`0"
+M*@H*%2`7&1<2"P@-!PT)%`$4%!@""@D````),!$)#@D)"B$-"0X.$``)"AP.
+M#A@!)`D."B`($@L9"QD@+2T#`S<G-S<O+PD0`@8&"0$!%"<G`P8&'AH*"0D"
+M&`H*#AX."0P-`@0"`@0%$0X.$Q,.`A84`@XK*1T."0T'`AP.$R<4%A`0%`D"
+M#@D6$!`4%@DA*0XA`A8"`PH*"@H*"@H*'1,<!`(J)1L/&AL:#R(5#QL:#QH/
+M&R(:#P\/#S$L,38/#B<1(2$)```````````````````````````````0"0()
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``D*"AX3#A$)`@D"`@D)`@D1*`(H!P(3)A4F'"`$"`0"`@8>(1`)(R,+&0L9
+M"`(,%`$0&"08)`D*"0````D*$QP*"1@)$R8A+@H0`"0)'1X)`0$""AX&!`L9
+M&1D9&2,#`RTM+2DG%@D8`@8"!Q@6&!08+P,:+A\:#@D"'PH)$"$>)Q`'#`<"
+M#0<"!0("$2D.#BL1"0D1#AT.`PX1`@0"#BD.#A$)%!8)#ATK'`()#`D0`BL>
+M'1XI#@X="@H#'@H3$Q,<(083'14/&B(5(AH;&@\B&B(;#R(/#P\/#P\/#P\/
+M#P\;(AH/#QLG"0D8$`D8$!@4```````````````0&`D=&PH6````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````%B$;+`\5)@X1
+M'!$1$0(H$0DG$0(H`@(C'",<!`8(`@85"A$8`!@:&QD9&1D9"P<0%A@D%A04
+M&`D6````)`(0"0D4`!`;+"(."1`````)"1@!"1T3!@87"PL9"QD((`,M+0,M
+M+0D)$!`-"0D8&`$!&`D#(B(:#P\/,!X5%18!&!8!%A$%"`($!0@'!PT.*RD3
+M#@X.$PXI$RL3$0("`B$3*Q,#$P(0"1,I'0,=#@D6%`(."AX#"@,=`PH*"AT3
+M(08$!A,>,"X;'R(;&B(:(ALB&AL:(AH/&AL:#P\:#QH/&@\/+`\L#S4T#R(:
+M&AH:#P\/"A``````````````"0HJ!AP5"A8`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````%@HB&QL/)@H>$Q,K$Q$.$0()
+M*!$"!B,E(R,<'`81$QL*&```&`H5)1D7&1<@#1@!`10D`0D)````````````
+M````%@HB"@D`````````)`(1)@8$$A(9&1D9$@8.+2TM+2DM(0X3#A,.)PD"
+M"0D0`A4/&@H:#QL:"AT>&`$!`0$0`@('#0T"`@4-`@X3#@XK#@XK$QX.`PXJ
+M!P<H#A,I`Q,.`@DA$P,>'0,=$0<)$1X*'AT*'@H*"@,>#A$$`@8J,"X:#QH;
+M&AHB&QH:'QH;&B(;&B(:#P\/#P\/#P\/#P\/#P\/,0\/+#4S-C,V,S0/#B$)
+M(2@"(2@""0D""B43(R4K$```````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````%@DG%0\;%145%0H>$PX.#@X<(0XF&PH>'B4=
+M"A4*$0D`````%A$*(Q<9&1('"0D0%B06'0X6```````````````D$`D6````
+M`````!0)'@H<"`L7&1D7$AD&!BD#+2DO"0(=#RP/-1HI#ATB)AT*%1L*'A,E
+M"A\;)Q`!`0$!`183`@<,!`0$#`0-$2D.#AT.'2L.#BDJ!@(%"2$.`Q,.$PX.
+M#A,K'0,3'AX##@(.`QT=`QX='A,3'"$&!@8@'0H5'QL:'RX?(A4:(AL;'P\B
+M&AH/&P\/#QH/#P\/#R(/#P\L#P\L#S4T-0\T#S0U,0\/#P\U+#$L&R(5$P8<
+M(R4F$18`````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````G"2<H"0X:-`\;&Q45%2X1"2<)"0<)"1`)*"<D````````
+M``(5%2`+!@8*'@(0`1`*&PD`````````````````````````````"0H3!@@9
+M&0L9&1D+!A,G)RTG)Q@6/!4S-#0/(@H*%2PU&PH=$RHF%1\;&@\G`0$!`0$!
+M"1,-#04"`@(%`@<A#@X>#BL.#ATK$Q$"!0<.*0,3*2L#*1X#'0,='AT#'1T.
+M'1X#'@H>'0X&`@($!A,3'0H?+A\:'PH;&A45(AL:&@\:%1HB&QH;&B(:&R(:
+M#P\;&@\/#P\/#P\/+`\/+`\U+`\T-2PS#S0S-C$N)2H$'#`<"0D8````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````%@H;&Q4>"@H*'PD`````````````````````````%`HF!B`@)1L5
+M(0$6$0H*%@````````````````````````````DK%08'"Q<+&1D+$@8J`R$O
+M*2<0#`(J%30U&RX?*2D##S$L'BD3$PH5#QHB&@D!`0$!`0$6"@('!P(&!P8"
+M#0X.#@X.#@XK$PX.#0("!@X=#BL3*1,.$RD3`Q,#`Q,>`QT*`QX=*1,.!@<(
+M!08A'A4?'Q4:'QLN&@H?(AH?&ALB#R(;&@\:(AH/#P\/#P\/&@\/#P\/#P\T
+M#P\Q#S$/,3$/-BPU,30U-BP/%1,<!@8E'@D`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````$`D8
+M%A@0&`D0````````````````````````````%A`-"AL;#QL""2@=(1`4````
+M```````````````````````1'28J!@42&1D9&1(C$QT>"AXG)S\"$RD#&AL.
+M(0(G"2@=&PH3"@H:'R(:%0\:$0$!`106$!$*!@T'!0("!`('#A,K$PX3$PX.
+M`@<$!P(A*RL=*PX#'BD.'@,3'AT>*0,=*QX3#AP.*@(%!`8<'0H?"AL*(AH;
+M'Q\5(A4B&ALB&A\;&B(B&ALB&AL/&@\/#P\/#P\L#QH/#S4/+`\L-2P/,RP/
+M-3$/,RP/&AX<(!PC%28)````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````!@)'0\;%2@="B$0````````````````````
+M````````"0H3!@42&1D+&1(2!@,3#AP5'S<&'`,M`S$U&A$H"1`.'143'14:
+M"AH*+AHB#QLG`0$!"0H/#Q4&!PT"!P4-!`T.#@XI*RD.#@($!0("*`XI#A,I
+M'1,.'2LI$RD#*1X='A,J(1P"!`4"!!$3,`HN&BX?"@H:(A\;&Q\5'QHN&A\;
+M&@\:#QL:#QL/(@\;#P\/#S$/#P\/#P\T#RPQ#P\/,34Q#S8T,S0Q&BL&!B,5
+M'P()"10`````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````)%34;'AT>&`````````````````````````````D.%08(
+M"!D+&1D+%P81'1$%`@H=*0XJ+2T#-38/*0()`AX5#QX>'PH?(A\5'QHB&@X)
+M"0(A&S0S#QP,!P4$`@0"`A$.#@X.*PX"!P($#0(.'BL=*PX>#@,3*Q,#$PHI
+M$RL=#A$&!`@%!`81$PH?&@H?%0H5"AL?&A\:(AHN&A\5&Q\/'R(:#Q\:(AH;
+M&@\/&@\:#R(/#P\/#P\/#P\/#S,/#S,Q+#4/#Q4>#AP&(`H*$```````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`!0G+BP*)Q8``````````````````````````!@""A4&$A<+&1D9"P8&#AP&
+M!@0<(SHJ*0,M+0,Q,RP;"1`.#S8;(@H?%1H5&@HB&QLB'QLB"B83#P\:`@T%
+M!P(%#0<%#@X3#A,.`@("!@("#@X.*2L3*2LI'@XI$PX=*1,A#A$&!`0&"`8<
+M$PH*"A4N"@H?"A\*'Q45+A\;"A\?&R(:'Q4:&QH;#P\;(AH/#R(/#P\/#P\T
+M#P\/#S$U+`\Q+`\T#P\/&C`3*AP3)1,0%A8`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````)`@D0````
+M````````````````````````"1T3!@42&1D9$A<&!@<%"P8&$R4F'2T#+0,G
+M-S,R-AL""1XS-"P:'Q4?"@H?'Q4?&AH;"A,5,`D"`A$'!P<'!@("!`<.*PXK
+M$2$'!00""1$.#AX.$P,.'0X=#@,=`Q$A`@8Y`@(%"`83'3`?&A\?"A\*&BX*
+M%1\;'R(5%1\*&QH:&B(;(@HB'QH:#QH/#P\;&@\B#QH/#P\/#QH/#P\/#S4Q
+M-@\/+C`<!@8C)1L<"0``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````)`D3)@8("QD7&1D9!081`A(&!!P3)285`RTM+0XK-30T&R$"%0\V
+M&PH5"AH?&A4?&Q\:"@H>*AX3$`$8)PT$`@(A`@8-`B$.#@X1`@4'!P(A#@XI
+M#@X.$PX>`RL.$PX.!@T(#0<&!`8&$P,*'PH5"@H5%0H*"A\*(@H:'Q4B"AH?
+M(A4B%14:(AH;(ALB#P\/#QH/#P\;#P\/#P\/#P\/#S4L#P\/#PH3!@0&(R,3
+M"@D`````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````!@"'14<
+M"PL2&1(9"P0%!`4(!`81)3XP+#$B`P,#&@\R,C4/$RLN&QL:"C@*%1\N"@H*
+M"@H3!A,*(1`8%B<*`@P%'!$"!PT"$2D<`@($"`(%*!$.*Q,.'2LI#A,I$R$A
+M`@8$`@0$!081'1X="@H*"@H*"A\?+A\5"AH*'PH*(AH;"AL5&B(:(AH:&Q\:
+M&AL/#P\:#P\/&AH/#P\/#P\/#P\Q#P\/&Q4J!@0&(!XF"0D0````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````"1X3!A(9%QD9&1(%!`@%
+M"`(6"08E%0\S#RDM+0\R,C(R,RP;#RPN%0H*%2(5'Q4?%0,1`B<>'QLA`1@>
+M"@,"#`(5"@8$`@<.#A$"`@(%`@<.#@X3#BL.'0X<#@($`@('!@8+"`83*1X*
+M`PH*'0H5"AT*"@H:"A\N"AL*&AL:+A\:(AHN%14B%2(5(@\B#QH:#R(;&AHB
+M#P\:#P\/+`\/#P\L#QT.!@82(Q4""0D8````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````&`()``````````D.%08(!1D+&1D+"P<%!`@$"0<"(QX;-C(/
+M#BT#(C0S,C(R-C0U+!H*'2D*.`,?'0H=#@())PX*&R$0"1\B+0D,!P\;'`4'
+M#2$.!@<%`@(-`@X>#@XI$PX.$0("`@4'!@($!`42#A,#"@H=%0H*'PH*"A\5
+M'PH*%0H?"@H5(A\:(A4?'QH?#QH*&AHB&AL:+B(/#P\B#QL/#P\/#P\Q#P\:
+M(A\=!@@$("`C'0D`````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````6
+M"B(1`````!`G"C`<!1(9&1D2!0@$#0P'"0(&)285%14Q,S(Q`RT.&S8Q,S(/
+M,S0/"AXG"2<O-PXA"2<A"1`6*"$.$RDI`RTI)PT'&C4E`@@'`@(-`@("!PDA
+M#@XK#@X.`@8$`@0(!`4$!00&#AT='AT*%1\*"A4*"@H*"@H*'Q\B"A4B'PH5
+M%14:(A4;(AL?&BX;&AL:(@\;&@\:#QH/#QHQ#P\:#P\B&R(3'`0&%R4>`A08
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````!@*+`H)````"0H3
+M'`4+%QD9"P42"PT)$`D1("8/,RPN"ALV-`\*'@HI+0,Q+`,U,2L""2<))R<G
+M)Q@4)!80$"<)"3<W+S<#`P,"!P(/-"4%#`T-!`0%!`T"(0XK$0("!A$"`@8&
+M"`8%"`(<$QX="AT*"@H*"AH*'PH5"@H*"A4*%1L?"@H5"AHB(A\B&B(:%2(N
+M&A\B%0H:&QH:(AL/&P\/#P\L#P\B"C`&!@8%!B8;&A$8````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````%@HT#PD`%`D.%08("QD9&1(+"PL'
+M$`D"$00C)BP/#Q\*'P\/&A,=%0,#`R(B#A\:#@DG)R\G)R<G&!88%A@G#B$O
+M-R\W+RT#`R$$*ALL%0(%!P4'!0("#"@.'"$.`@<'!@81!0@&"`4$'!T#"AT*
+M`PH*'0H*"@H="@H*"A\*"A\*&@H*%1\*(AH5&A4*'QH?&A4B&AL:(AHB(@\/
+M&B(:#QH/#P\:%14>!@('(",C)AH*&```````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````8&S(L(0D)'A4J$@L2&1D9"Q(%#!0"#A,&(",3"@H?
+M,`H*&A\5`RL>&BPB`RDM+2TM-R\W-R\M+RTO-RDO+R\O+0,M`RTI*0H*'`(3
+M#S85!@T'!@("#`4'`@("`@0'!0(%`AP$!@0&'!,=$QX*'PH='1\*'14="@,*
+M'Q4*"AH*%0H*%0H5(@H5'PHB'QL?&RX:(A4B%1\;&AL:&B(:&P\?&QH;"AX"
+M!@4&("`3"@HH&!`4````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````!8B,C,/&R(3(009&1<9$@0%"`<D&`<&(QP*"B4X"@H*"AH*"A\5$PX/
+M,@\W+RTO+R<O+2\I'2(/,3$/,0,M+2TM`RTQ+B<8)PDJ'"4L-CT"!P4'`@8'
+M#0<'!@<%`@4$!00&!0T1*A,#"@,*'1T>"A\*'0H*'PH>'0H*"@H*"@H?"@H?
+M"A\*&@H?%1H?&A\:'QHB&AH*&Q\/(B(/#QL:#QL*`RH"!0@+$B8]%1$""0``
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````&`H/-30L
+M&@8("QD9&0L7"P<"%!04!AP<$PH?'PH5.!\*"A\*'RX=$0H;"B<A+2<8"3<I
+M*0X*%1H;#QH;*0,M`P,M+1\#$`````8C$P\R#PX,`@(%`@P,`@4"!@($!00(
+M"`($`AP='AT3'1X#"AT='0H*"@H*'0H*"AT*"@H*"@H*'Q4B"A\?&Q\5(AL:
+M+A4:(A4:+AH:#QH:&AL:(B(5"A,"!`P($B,C)1L#$```````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````%@X/#R8&!`L2"PL7!`@%
+M'`()!P(>,!T*'PH="@,*"AT*"A4?&PH.$1$A$0X.$0("$QT*`A`8"0D8"1@D
+M%B$*&A\)%@D8```4$1P3+#8L(P<%"`<"!0<$$0(&!P4+!`4$!@X3`PX#`PH#
+M'0H=`QXI"AT=`S@*"@H*"@H5"@H5'Q4?'PH5(A45'R(:'Q\:+AH;'R(5(AH/
+M&QLB%1\5'A,"!087(!,F%28)%@D`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````"143!A<+&1D9"PL+!B,5%1,<$QX*"AT*
+M"@HX'0H?"@H*'0HB&P\5*PD)"04$$Q4""0D8````````````&`DA"0``````
+M`!@&$QXL,@\5'`((`@4$#0(&!`((!`@&!@X=#AT='AT='0H="AT*"AT>*0H=
+M"@H*.`H>"@H*"@H*'Q4:'Q\5'R(:%1\5%2(5'QL:&BX:#P\B&@H<#A$<#@@+
+M!B8/%2$H"1@`````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````))@(("QD9"Q<2!!($)0\;,`H3'PH*"@HX"@H*"@H*"@H=
+M"A4/,P\;#A$"`@83"@D`````````````````````````````%`8<'BPR,Q4E
+M`@4"!00%!`8"!`@%!AP.*Q,="@H='@,="AT#"AT#'0,*"@H*'0H5"@H*"A4*
+M'PH*'PH?&Q\;&@H*'QL?&QHB'Q4B"A\;"A4*$P($!0(&("4C%1L>&```````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``D3(!<9%QD+"`L"*@X<$Q4;%0HX"C@*'PH?"AT*'0H=`QX5+A4L#Q4>"AL5
+M*!00```````````````````````````````8$2HP#S0U#PH&`@0(`@@%!`@$
+M`@8I'0X='@,=$P,3`QT#"@H='AT*'0,='AT*'PH="@H?'PH*%0H*%0H*%1\N
+M&B(:%1\:"AH5'QH*'0X.!@(%!@02'"`F%0H""1@`````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````@HC(`L+!0@"
+M*A,<!BH*%1\?"@H="@H*"@H?'PH?"A,&#A,:,S8T#QXL,BPH````````````
+M`````````````````````!0"!A$>'AX*)@8"!04(!`P"`B$.'1,I'BDI'2D=
+M"AT=%1T=`QT?"@H*"@H*"@H*,!\*'Q4?%0H*"@H?'Q\*'PH:+AHB&B(/(AT>
+M$Q$&`@07"`L2(Q4;&A$""1@`````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````H&R,2(!((`@0"'B$1$PH*"@HX
+M"AT*'0,='0H3'1,K'`('!@\S#S,L"@\S#R$`````````````````````````
+M``````````<"`AP1#A,3!@@$"`4$!1$"$1TK`P,3$P,>$P,="A4?"@H>"@H*
+M.`HX"C`?'1T*"@H*'Q4B"@H?%0H5%0H*"@H?%0H;"A\=*08"!0<(!A(&("`C
+M"AL*%@``````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````"<5"B,7"Q<&#0(&!CDJ$P,=*1T*$P,3$QX.!@X"
+M!0(-`@83,S(U+`\=)AH/`@`````````````````````````````````4$1,Z
+M$QP<!@0"!0($`@("(0X.#@X='0,='1,="AT*"C@*.!4?&A\*"@H*"@H*'PH?
+M&AH?'Q\5'RX?"@H?"A4?"@H*$Q,.*@("!`@&"Q(@(R4P$0`8"1``````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````)"$;&R,2"P@&(`0%!P("`@(<#@8'#0("`@T$#0<,!#X5/0\L,S0R
+M,Q4.#AHG`````````````````````````````````!`="AP*,"`&"P0(#0T-
+M`A$A#@XI#@XI#@,*"@,3'0H>'0H?"AT*"A\="AT="AT="AT*"@H;"AH*&A4?
+M(@H*"@X&*@("`@0%!`87"Q(E&Q4.!R<8````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````$`H5
+M,"`7!!P&!`T""`T,#`T'#`<,#00(`@8&!A,C$R8N#S8L,S(T#Q,3"@D`````
+M````````````````````````````%@H5$R8E&0L7"`0$!P0$(0(.#A$.#A,I
+M$S@='1,#'1X#"@H*'AT="AT#"@H5"A\*'Q4?&A\*"@H?"@H*'2L3!@('"`4$
+M"`8&(",C("45%2@`````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````$0,5(QP<(R`&%P4$
+M!04"`@0"`@0%!`8$!AXP%1X)%!`A%38V,C(S%1TH&```````````````````
+M```````````````8%0\5(R`9"QD+%P8$!0(1!@("`@8A#@X.#@XK*1X=*1T=
+M'AT="AT*"@H*.`H?"AT*'1T>`Q,>'1,.#A$"!`8%!`4&"P87("`F%28)$`D6
+M)```````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````!@*%24F,`85#R85)24C)2,C)3`F,!4:
+M"@()!P(G`@```"0)#C0R,BPI"10`````````````````````````````````
+M`!@)#ALE$AD9&0L9&0L$!`8"!P0"#0<A`@8"'"$.*2D>`Q,I"@,*"AT*"AT*
+M'0,=`QP<#AP"$0("`@(J!@4(!0L+"Q(@(QL/%0(H"20`````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````8`AL;)0H3)PH;"B8>$R,C)1P3)AX*%1L*$```````````
+M```)+B(/&R@````````````````````````````````````````)"B4C$B`9
+M&1D9(!<2!`4""`4(`@0"`B$"`@X1$PX3`RD3*1TK#A,3*1,>$PX1`@("`@T$
+M#`4(!!PA!!(&&2`@(R,E"AH*&```````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````4
+M&`(3,"8>`@D4&`D6$!`4)!00%!`)%A8)"18````````````````6"0D6````
+M```````````````````````````````````````6$`DF)2,@&0L+&2`@"PL&
+M"P8%"`4&`@8"!0("!@("!@("`@4'`@T%`@(A`@8'!00%"`4(!`8%(!P@%PLC
+M"ALP"1`)%A``````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````"0.'A,;&R<`````
+M````````````````````````````````````````````````````````````
+M````````````````````````````%@D)`A4C&1D9(!D9&0L+"P0%!`8"!`4$
+M!`($`@("$08$!0<%"`<$!0<<`@0(!0@2"PL9&1DE,"8"%`<)"0D8````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````)`DH`AXP)1H*"0``````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````)"B,&)1(9&1(+&1D+%PL7"Q<2!0@%"`0%!`(&`@0%
+M"`@&!0@(!@0&!!<2&2`7(R4@'",>'@D`````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````!@),!43)285(1``````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````"00%@(5%24@&1D2&1D9&2`9"Q<9$A(+"PL&(!(2"Q(9"PL9&2`+%R`9
+M%P0@$Q,F%0H6%!80````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M"0H3$R8A"0D8````````````````````````````````````````````````
+M````````````````````````````````````````````````````````&"@)
+M"0(5&QLC)1(@$AD7&0L9&1D+&1(2&0L9$AD9&2`E(R,5%14"#1`'$`DH"1``
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````!81"B4E$PT`````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````$`H:%2,@!A<2
+M!1(C(R`2(Q(C(!(C(!(2$@@2("`3$R4F+@D`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````8$!@)$PHE%0H)````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````%A`8$``4%!`6'AH5&Q45)B85
+M)AH5&PH,%``4"100"1`6````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````!`*%1,C)A43"1@`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````!0)(0DG`@DA"0(H)PDG"20`````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````D
+M$1\;'B,J'B<`````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````&"<F'B4>`A08````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````"0>"B45)@(`````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````8"0H5'A4>%@``````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````!00
+M%@D3)3`F(1````````````````````````````````$!`0``````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````!`0$!`0$!````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````)PH<!B8;%1$8````
+M``````````````````````$!`0$!````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````!`0``````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````D.&S`C$QL*&```````````````````
+M``````$!`0``````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````!`0``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````!0)%14E"B4)%A@````````````````````````!`0``````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`0``````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M"1TE)14."10````````````````````````!`0``````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````$`````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````D"1`"'B4F"@(`````
+M``````````````````````$`````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````!````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````!08``D*$QPE%0H)&```````````````````
+M```````!````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````$`````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````"0H1`AP@$QL."1@``````````````````````````0$`````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```!````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````)`D.
+M&PH3'!PE"@(````````````````````````````!````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````$`````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````!@H'RP/,1LE)B8H````
+M`````````````````````````0$`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````!````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````AHS,C0R+!4/%18`````````````````
+M```````````!`0``````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````$`````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````H,3(R,C(U%1H*&`````````````````````````````$`
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````0``````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``D;-C0R,C,:(1`4`````````````````````````````0``````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````!````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````%`XL,C(R#Q$D
+M```````````````````````````````!````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````$`````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````%@,;(AH*&```````````````
+M``````````````````$!````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````0``````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````%A8)"18`````````````````````````````
+M`````0$`````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````!`0``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````!`0``````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``$[`0``````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````!`0``````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````0$#`0``````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````$!`0``````````````````````````````
+M```````````````!````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````0,#`0$`````````````````
+M`````0$````````````````````````````!````````````````````````
+M`````0$````````````````````````````````!`0$`````````````````
+M`````````````0$!`0`````````````````````````!`0$`````````````
+M``$````````````````````````````!`0```````````````0$`````````
+M`````````````````0$!`````````````````````````````0$`````````
+M`````````0$`````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````!`0,#`P$!``````````````$!`0$#`P$`````
+M`````````````````````0,!`0```````````````````````0$#`P$!````
+M`````````````````````````0$#`P$`````````````````````````````
+M`0$!`0`````````````````````!`0$#`P$!`````````````0$`````````
+M`````````````````0,!`0````````````$#`0$`````````````````````
+M`0$!`P$!``````````````````````````$#`0$```````````````$#`P$`
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````$!`0,#`P,!`0$!`0$!`0$!`P,#`P,#`P$`````````````````
+M``````$#`P,#`0`````````!`````````0$!`P,#`P$!````````````````
+M`0```````0$!`P,#`P$!`````````````````````````````0$[`0$!````
+M``````````$!`0$#`P,#`P$!```````````!`P$!``````````````$`````
+M``$#`P,#`0`````````!`P,#`P$````````!``````````$!`P,#`P$!````
+M```````````!```````!`0,#`P$````````````!`0,#`P$`````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````````````$!
+M`0,#`P,#`P,#`P,#`P,#`P,#`P,#`P$!```````````````````!`P,#`P$!
+M`0$````````!``````$!`P,#`P,#`P$!`0`````````````!`0```0$!`P,#
+M`P,!`0$!```````````````````````````!`0$#`P$!`0$!`0$!`0$!`0,#
+M`P,#`P,!`0$!``````````$#`P,!`0````````````$!```!`P,#`P,!`0``
+M`````0$#`P,#`P$````````!``````$!`P,#`P,#`P$!`0`````````````!
+M`0```0$#`P,#`0$``````````0$#`P,!`0$`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````$!`0,#`P,#`P,#
+M`P,#`P,#`P,#`P,!`0$!`0```````````````0,#`P,!`0$!`0$````````!
+M`0$!`0,#`P,#`P$!`0$!`0`````````````!`0$!`0,#`P,#`0$!`0$!`0``
+M```````````````````````!`0$#`P,#`P,#`P,#`P,#`P,#`P,!`0$!`0$!
+M`0```````0,#`P,!`0$!`0````````$!`0,#`P,#`0$!`0`````!`P,#`P,!
+M`0$!```````!`0$!`0,#`P,#`P$!`0$!`0`````````````!`0$!`P,#`P$!
+M`0$````````!`P,#`0$!`0$!````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````$!`0$#`P,#`P,#`P,#`P,#`P,!
+M`0$!`0$``0````````````$!`P,#`0$!`0$```$!`````````0,#`P,#`P$!
+M`0$!`0```0$``````````````0,#`P,#`P$!`0$!`0`!`0$`````````````
+M`````````````0$!`P,#`P,#`P,#`P,#`P,!`0$!`0$!```!`0`````!`P,#
+M`P$!`0$!``````````$!`P,#`P$!`0$!`0$```$#`P,#`0$!`0$!````````
+M`0,#`P,#`P$!`0$!`0```0`````````````!`0,#`P,!`0$!`0$``````0$#
+M`P,!`0$!``$!````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````$!`0$!`0,#`P,#`P,#`P$!`0$!`0$``````0``
+M`````````0,#`P,!`0$!``````$!```````!`P,#`P,!`0$!`0$```````$`
+M`````````````0,#`P,!`0$!`0````````$`````````````````````````
+M`0$!`0$!`P,#`P,#`0$!`0$!`0$!```````!`0````$#`P,#`0$!````````
+M``````$#`P,#`0$!`0$``0```0,#`P$!`0$!``$!```````!`P,#`P,!`0$!
+M`0$``````0$````````````!`P,#`P$!`0$```$````!`P,#`0$!`0$`````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````!`0$!`0$!`0$!`0$!`0$!`0$``````````0````````$!`P,#
+M`0$!`0$````````!```````!`P,#`0$!`0$```````````$````````````!
+M`P,#`P$!`0$```````````````````````````````````````$!`0$!`0$!
+M`0$!`0$!`0$!``````````$!`````0,#`P,!`0$``````````````0,#`P,!
+M`0$!```````!`P,#`0$!`0`````````````!`P,#`0$!`0$```````````$`
+M``````````$#`P,#`0$!`0````````$#`P,!`0$!````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`0$!`0$!`0$!`0$!`0```````````````````````0,#`P,!`0$!````````
+M``````````$#`P,!`0$!``````````````````````````$#`P,#`0$!`0``
+M`````````````````````````````````````````0$!`0$!`0$!`0$`````
+M`````````0$````!`P,#`P$!`0`````````````!`P,#`P$!`0$```````$#
+M`P,!`0$!``````````````$#`P,!`0$!`````````````````````````0,#
+M`P,!`0$!```````!`P,#`0$!`0$`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````!`0$!`0$!
+M`0`````````````````````````!`P,#`0$!`0```````````````````0,#
+M`P$!`0$``````````````````````````0,#`P,!`0$!````````````````
+M```````````````````````````````````````````````````````!`0``
+M``$#`P,#`0$!``````````````$#`P,#`0$!`0```````0,#`P$!`0$`````
+M`````````0,#`P$!`0$````````````````````````!`P,#`P$!`0$`````
+M``$#`P,!`0$!````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````!````````````
+M`````````````0,#`P,!`0$!```````````````````!`P,#`0$!`0``````
+M```````````````````!`P,#`P$!`0$`````````````````````````````
+M`````````````0$!``````````````````````````$!`````0,#`P,!`0$`
+M`````````````0,#`P,!`0$!```````!`P,#`0$!`0`````````````!`P,#
+M`0$!`0````````````````````````$#`P,#`0$!`0`````!`P,#`0$!`0$`
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````$````````````````````````!
+M`P,#`0$!`0$```````````````````$#`P,!`0$!````````````````````
+M``````$#`P,#`0$!`0`````````````````````````````````````````!
+M`0,!`0````````$!`0```````````0$````!`P,#`P$!`0`````````````!
+M`P,#`P$!`0$```````$#`P,!`0$!``````````````$#`P,!`0$!````````
+M`````````````````0,#`P,!`0$!``````$#`P,!`0$!````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````0```````````````````````0,#`P,!`0$!`0``
+M`````````````````0,#`P$!`0$``````````````````````````0,#`P,!
+M`0$!``````````````````````````````````````````$!`P,#`0$`````
+M`0$#`0$````````!`0````$#`P,#`0$!``````````````$#`P,#`0$!`0``
+M`````0,#`P$!`0$``````````````0,#`P$!`0$`````````````````````
+M```!`P,#`P$!`0$````!`P,#`P$!`0$`````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````!```````````````````````!`P,#`0$!`0$!````````````````
+M```!`P,#`0$!`0`````````````````````````!`P,#`P$!`0$`````````
+M`````````````````````````````````0$#`P,!`0`````!`0,#`0$!````
+M``$!`0$!`0,#`P,!`0$``````````````0,#`P,!`0$!```````!`P,#`0$!
+M`0`````````````!`P,#`0$!`0````````````````````````$#`P,#`0$!
+M`0````$#`P,!`0$!`0``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````````$`````
+M`````````````````0,#`P,!`0$!``$```````````````````$#`P,!`0$!
+M``````````````````````````$#`P,#`0$!`0``````````````````````
+M```````````````````!`0,#`P$!`0````$!`P,!`0$``````0$````!`P,#
+M`P$!`0`````````````!`P,#`P$!`0$```````$#`P,!`0$!````````````
+M``$#`P,!`0$!`````````````````````````0,#`P,!`0$!`````0,#`P$!
+M`0$`````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````0``````````````````
+M```!`P,#`0$!`0$``0```````````````````0,#`P$!`0$!`0``````````
+M`````````````0,#`P,!`0$!````````````````````````````````````
+M``````$!`P,#`0$!`````0$#`P$!`0$````!`0````$#`P,#`0$!````````
+M``````$#`P,#`0$!`0```````0,#`P$!`0$``````````````0,#`P$!`0$`
+M```````````````````````!`P,#`P$!`0$!`0$#`P,!`0$!`0``````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````!`````````````````````0$#`P,!`0$!
+M```!```````````````````!`P,#`0$!`0```0`````````````````````!
+M`P,#`P$!`0$``````````````````````````````````````````0$#`P,!
+M`0$````!`0,#`0$!`0````$!`````0,#`P,!`0$``````````````0,#`P,!
+M`0$!```!```!`P,#`0$!`0`````````````!`P,#`0$!`0``````````````
+M``````````$#`P,#`0$!`0```0$#`P$!`0$!````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````$````````````````````!`P,#`0$!`0$```$`````````
+M``````````$#`P,!`0$!`````0````````````````````$#`P,#`0$!`0``
+M```````````````````````````````````````!`0,#`P$!`0````$!`P,!
+M`0$!`````0$````!`P,#`P$!`0`````````````!`P,#`P$!`0$```$```$#
+M`P,!`0$!``````````````$#`P,!`0$!`````````````````````````0,#
+M`P,!`0$!`````0$!`0$!`0``````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`0```````````````````0$#`P,!`0$!`````0```````````````````0,#
+M`P$!`0$``````0```````````````````0,#`P,!`0$!````````````````
+M``````````````````````````$!`P,#`0$!`````0$#`P$!`0$````!`0``
+M``$#`P,#`0$!``````````````$#`P,#`0$!`0```0```0,#`P$!`0$`````
+M`````````0,#`P$!`0$````````````````````````!`P,#`P$!`0$`````
+M``$!`0$!````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````!`0$!````````
+M```!`0$!`P,#`0$!`0$````!```````````````````!`P,#`0$!`0``````
+M`0$````````````````!`P,#`P$!`0$`````````````````````````````
+M`````````````0$#`P,!`0$````!`0,#`0$!`0````$!`````0,#`P,!`0$`
+M`````````````0,#`P,!`0$!```!```!`P,#`0$!`0`````````````!`P,#
+M`0$!`0````````````````````````$#`P,#`0$!`0`````````!`0``````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````$````!`0$!`0$!`0$```$#`P,!
+M`0$!``````$```````````````````$#`P,!`0$!`````````0$`````````
+M``````$#`P,#`0$!`0`````````````````````````````````````````!
+M`0,#`P$!`0````$!`P,!`0$!`````0$!`0$!`P,#`P$!`0````````````$!
+M`0$!`0$!`0$```$```$#`P,!`0$!``````````````$#`P,!`0$!````````
+M`````````````````0,#`P,!`0$!`````````````0``````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````0`````````````````!`P,#`P$!`0$``````0``
+M`````````````````0,#`P$!`0$````````!`0$``````````````0,#`P,!
+M`0$!``````````````````````````````````````````$!`P,#`0$!````
+M`0$#`P$!`0$````!`0````$#`P,#`0$!``````````````````````$!`0`!
+M`````0,#`P$!`0$``````````````0,#`P$!`0$`````````````````````
+M```!`P,#`P$!`0$````````````!`0$`````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````!``````````````````$#`P,!`0$!```````!````````````````
+M```!`P,#`0$!`0````````$#`P$!```````````!`P,#`P$!`0$`````````
+M```````````````````!`````````````0$#`P,!`0$````!`0,#`0$!`0``
+M``$!`````0,#`P,!`0$``````````````````````````0`````!`P,#`0$!
+M`0`````````````!`P,#`0$!`0````````````````````````$#`P,#`0$!
+M`0```````````0,#`P$!````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````!``````````````$`````
+M```````````!`P,#`P$!`0$```````$```````````````````$#`P,!`0$!
+M```````!`P,#`P$!``````````$#`P,#`0$!`0``````````````````````
+M``````$````````````!`0,#`P$!`0````$!`P,!`0$!`````0$````!`P,#
+M`P$!`0````````````````````````$!``````$#`P,!`0$!````````````
+M``$#`P,!`0$!`````````````````````````0,#`P,!`0$!```````````!
+M`P,#`0$!````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````$``````````````0````````````````$#
+M`P,!`0$!`0```````0```````````````````0,#`P$!`0$``````0,#`P,!
+M`0$!`0```````0,#`P,!`0$!`````````````````````````````0``````
+M``````$!`P,#`0$!`````0$#`P$!`0$````!`0````$#`P,#`0$!````````
+M```````````````!`0```````0,#`P$!`0$``````````````0,#`P$!`0$`
+M```````````````````````!`P,#`P$!`0$``````````0,#`P,!`0$!````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````0`````````````!```````````````!`P,#`P$!`0$`````
+M```!```````````````````!`P,#`0$!`0````$#`P,#`0$!`0$````````!
+M`P,#`P$!`0$````````````````````````````!`````````````0$#`P,!
+M`0$````!`0,#`0$!`0````$!`````0,#`P,!`0$````````````````````!
+M`0$````````!`P,#`0$!`0`````````````!`P,#`0$!`0````$!`0$!````
+M``````````$#`P,#`0$!`0````````$!`P,#`0$!`0$`````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````!
+M``````````````$```````````````$#`P,!`0$!`0````````$`````````
+M``````````$#`P,!`0$!```!`P,#`P,!`0$!`0$```````$#`P,#`0$!`0``
+M``````````````````````````$!```````````!`0,#`P$!`0````$!`P,!
+M`0$!`````0$````!`P,#`P$!`0```````````````````0$```````````$#
+M`P,!`0$!``````````````$#`P,!`0$!``$!`P,#`P,!`0```````````0,#
+M`P,!`0$!`````````0,#`P,!`0$!````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````$!````````````
+M`0`````````````!`P,#`P$!`0$``````````0```````````````````0,#
+M`P$!`0$!`0,#`P,#`0$!`0$``0$!`0$!`0,#`P,!`0$!`0$!`0``````````
+M`````````````0,!`0$```````$!`P,#`0$!`````0$#`P$!`0$````!`0``
+M``$#`P,#`0$!``````````````````$!`0$``````````0,#`P$!`0$`````
+M`````````0,#`P$!`0$``0,#`P,#`P,!`0`````````!`P,#`P$!`0$`````
+M``$#`P,#`0$!`0$`````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````3L!`0$````````!````````````
+M``$#`P,!`0$!`0`````````!```````````````````!`P,#`0$!`0$#`P,#
+M`P$!`0$!```!`P,#`P,#`P,#`P,#`P,#`P,!`0$````````````````````!
+M`P,#`P$!`0$!`0$#`P,!`0$````!`0,#`0$!`0````$!`````0,#`P,#`0$`
+M``````````````$!`P,#`P$!``````$!`P,#`P,!`0`````````````!`P,#
+M`0$!`0$#`P,#`P,!`0$!`0````````$#`P,#`0$!`0$``````0,#`P$!`0$!
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````!`0,#`P$!`0$!`0$````````````!`0,#`P$!`0$`
+M``````````$``````````````````0$!`0$!`0$!`P,#`P,!`0$!`0````$!
+M`P,#`P,#`P,#`P,#`P,#`P,#`P$```````````````````$!`P,#`P,#`P,#
+M`P,#`P$!`0````$!`P,!`0$!`````0$!`0$#`P,!`0$!`0$!```````````!
+M`0,#`P,#`P$!```!`0,#`P,!`0$!`0```````````0$!`0$!`0$!`P,#`P,!
+M`0$!`0$!`0```````0,#`P,!`0$!``$!``$#`P,#`0$!`0``````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````!`0,#`P,#`P,#`0````````````$#`P,!`0$!`0```````````0``
+M``````````````````````$!`0,#`P,#`0$!`0$```````$#`P,#`P,#`P,#
+M`P,#`P,#`P,#`P$```````````````````$!`P,#`P,#`P,#`P,#`0$!````
+M`0$#`P$!`0$````!`0$!`0,#`0$!`0$!```!`0```````0,#`P,#`0$!`0$!
+M`0,#`P,!`0$!`0$!`0````````````````$!`0$#`P,#`0$!`0$!`0$!````
+M```!`P,#`P$!`0$```$!`0,#`P$!`0$!````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````````$!`0$#
+M`P,#`P,!`````````````0,#`P$!`0$````````````!````````````````
+M`````````````0$!`P,!`0$!`0```````0$!`P,#`P,#`P,#`P,#`P,#`P,#
+M`0```````````````````0$!`0$!`0$#`P,#`P,!`0$````!`0,#`0$!`0``
+M``$!```!`0$!`0$!`````````````````0,#`0$!`0$!```!`0,#`0$!`0$!
+M`````0$```````````````````$!`P$!`0$!`0$!``$!``````$#`P,#`0$!
+M`0`````!`0,!`0$!`0``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````$!`0$!`0$!`0$`````
+M``````$#`P,!`0$!`0````````````$`````````````````````````````
+M``$!`0$!`0$``````````0$!`0$#`P,#`0$!`0$!`0$!`0$[`0``````````
+M`````````0$!`0$!`0$!`0,#`P$!`0````$!`P,!`0$!`````0$````!`0$!
+M`0```````````````````0$!`0$!`0```````0$!`0$!`0``````````````
+M```````````````!`0$!`0$!``````$``````0,#`P,!`0$!`````````0$!
+M`0$!````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````$!`0$!`0$!`0```````````0,#`P$!
+M`0$``````````````0`````````````````````````````````!`0$!````
+M`````````0$!`0,#`P,!`0$!`0$!`0$!`0$!``````````````````````$!
+M`0$!`0$!`P,#`0$!`````0$#`P,!`0$````!`0```````0$`````````````
+M``````````$!`0$``````````0$!`0$`````````````````````````````
+M```!`0$!`0```````0$````!`P,#`P$!`0$``````````0$!`0``````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````0$!`0$!``````````$#`P,#`0$!`0``````````
+M```!```````````````````````````````````!`0```````````````0$!
+M`P,#`P$!`0$!`0$!`0$!`0$``````````````````````````````0$#`P,!
+M`0$````!`0,#`P$!`0````$!``````````````````````````````````$!
+M``````````````$``````````````````````````````````````0``````
+M`````0````$#`P,#`0$!`0````````````$`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````$``````````0,#`P$!`0$!``````````````$`````````
+M``````````````````````````````````````````````$#`P,#`0$!`0``
+M`````````0`````````````````````````````!`0,#`P$!`0````$!`P,#
+M`0$!`````0$`````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````0,#
+M`P,!`0$!````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`0````````$#`P,#`0$!`0```````````````0``````````````````````
+M`````````````````````````````````0,#`P,!`0$!````````````````
+M``````````````````````````$!`P,#`0$!`````0$#`P,!`0$````!`0``
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````!`P,#`P$!`0$`````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````!`````````0,#
+M`P$!`0$!```````````````!````````````````````````````````````
+M```````````````````!`P,#`P$!`0$`````````````````````````````
+M`````````````0$#`P,!`0$````!`0,#`P$!`0````$!````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````$#`P,#`0$!`0``````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````$```````$#`P,#`0$!`0``````
+M``````````$`````````````````````````````````````````````````
+M``````$#`P,#`0$!`0`````````````````````````````````````````!
+M`0,#`P$!`0````$!`P,#`0$!`````0$`````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````0,#`P,!`0$!````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````0```````0,#`P$!`0$!`````````````````0``
+M`````````````````````````````````````````````````````0,#`P,!
+M`0$!``````````````````````````````````````````$!`P,#`0$!````
+M`0$#`P,!`0$````!`0``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```!`P,#`P$!`0$`````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````!``````$!`P,#`0$!`0```0$!`0$!`0$!```!````````````````
+M``````````````````````````````````````$!`P,#`P$!`0$`````````
+M`````````````````````````````````0$#`P,!`0$````!`0,#`P$!`0``
+M``$!````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````$#`P,#`0$!
+M`0``````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````````$`````
+M`0,#`P$!`0$!`0$````````````!`0$`````````````````````````````
+M```````````````````````````!`0,#`0$!`0``````````````````````
+M```````````````````!`0,#`P$!`0````$!`P,#`0$!`````0$`````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````0,#`P,!`0$!````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````0`````!`P,#`0$!`0``
+M`````````````````0``````````````````````````````````````````
+M`````````````````0$!`0$!````````````````````````````````````
+M``````$!`P,#`0$!`````0$#`P,!`0$````!`0``````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````!`P,#`P$!`0$`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````!`````0,#`P$!`0$!````````````````
+M```!````````````````````````````````````````````````````````
+M``````$!`0$``````````````````````````````````````````0$#`P,!
+M`0$````!`0,#`P$!`0````$!````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````$#`P,#`0$!`0``````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````$````!`P,#`0$!`0````````````````````$`````````
+M``````````````````````````````````````````````````````$!`0``
+M```````````````````````````````````````!`0,#`P$!`0````$!`P,#
+M`0$!`````0$`````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````0,#
+M`P,!`0$!````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`0```0,#`P,!`0$!`````````````````````0``````````````````````
+M``````````````````````````````````````````$!````````````````
+M```````````````````````````!`P,#`0$!`````0$#`P,!`0$````!`0``
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````!`P,#`P$!`0$`````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````!```!`P,#`0$!
+M`0$````````````````````!````````````````````````````````````
+M``````````````````````````````$!````````````````````````````
+M``````````````$#`P,!`0$````!`0,#`P$!`0````$!````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````$#`P,#`0$!`0``````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````$``0,#`P,!`0$!````````````
+M``````````$`````````````````````````````````````````````````
+M``````````````````$!``````````````$!`0``````````````````````
+M`0$#`P$!`0````$!`P,#`0$!`````0$`````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````!`0,#`P,!`0$!````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````0`!`P,#`0$!`0$``````````````````````0``
+M````````````````````````````````````````````````````````````
+M``````$```````````$!`````````````````````````````0$#`0$!````
+M`0$#`P,!`0$````!`0``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````0$#`P$!`0$`````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````!`0``````````````
+M```````!`0,#`P,!`0$!```````````````````````!````````````````
+M````````````````````````````````````````````````````````````
+M``$!`````````````````````````````````0$!`0$````!`0,#`P$!`0``
+M``$!````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````````$!`0$!
+M`0``````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````0````````````````````````$!`P,#
+M`0$!`0$```````````````````````$`````````````````````````````
+M```````````````````````````````````````````````!`0``````````
+M``````````````````````````$!`0$````!`P,#`0$!`````0$`````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````!`0$!````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````$``````````````````````````0,#`P,!`0$!````````
+M`````````````0$!`0$!````````````````````````````````````````
+M``````````````````````````````````$`````````````````````````
+M``````````````````````$#`P,!`0$````!`0```````````0``````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````!`0$`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`0````````````````````````$!`P,#`0$!`0$````````````````!`0$#
+M`P,#`P,!`0``````````````````````````````````````````````````
+M```````````````````!`0`````````````````````````````````!`0$!
+M`0$```````$#`P$!`0````$!``````````$!`0``````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````!`0``````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````$`````````````
+M`````````````0,#`P,!`0$!```````````!`````0$#`P,#`P,#`P,#`0``
+M````````````````````````````````````````````````````````````
+M``````$```````````````````````````````$!`0$#`P,#`P$!`0````$!
+M`0$!`````0$````````!`P,#`0$`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````!`0``````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````0````````````````````````$!
+M`P,#`0$!`0$````````````!`0$!`P,#`P,#`P$!`0$!`0``````````````
+M`````````````````````````````````````````````````````0``````
+M```````````````````````!`0,#`P,#`P,#`P,#`0$````!`0$````!`0``
+M`````0$#`P,#`0$`````````````````````````````````````````````
+M```````````````````````````````````````````````````````!`0``
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````!`````````````````````````0,#`P,!`0$!````
+M```````````!`0,#`P,#`P$!`0$!`0$!`0``````````````````````````
+M```````````````````````````````````````!````````````````````
+M```````!`0,#`P,#`P,!`0$!`0$!`0$```````$```$!``````$#`P,#`P,!
+M`0$`````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````$```````````````````````$!`P,#`0$!`0$`````````````````
+M`0$#`P,!`0$!`0`````!`0``````````````````````````````````````
+M``````````````````````````$!`````````````````````````0$#`P,#
+M`P,!`0$!`0$!```!`0$``````````0$!`0$!`P,#`P,#`0$!`0$`````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````0``````
+M`````````````````0,#`P,!`0$!`````````````````````0$!`0$!`0$`
+M```````!````````````````````````````````````````````````````
+M`````````````0$``````````````````````0$!`P,#`P,!`0$!`0$!````
+M`````0$``````````0,#`P,#`P,#`P$!`0$!``$`````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````!`0``````````````````
+M``$#`P,#`0$!`0$``````````````````````0$!`0$!``````````$!````
+M````````````````````````````````````````````````````````````
+M`0$```````````````````$!`P,#`P,!`0$!`0$!``````````````$`````
+M```!`0$#`P,#`P$!`0$!`0````$`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````$[`0`````````````````!`P,#`P$!`0$!
+M`````````````````````````0$!`0````````````$`````````````````
+M```````````````````````````````````````````````!`0``````````
+M``````$!`0,#`P,#`0$!`0$!``````````````````$````````!`0$!`0$!
+M`0$!`0``````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````$[`0$````````````!`0,#`P,#`0$!`0``````````````
+M```````````!`0$``````````````0$`````````````````````````````
+M```````````````````````````````````!`0$```````````$!`0,#`P,#
+M`0$!`0$!`0`````````````````````````````!`0$!`0$!`0$`````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``$#`P$!`0````$!`0,#`P,#`P$!`0$!```````````````````````````!
+M````````````````````````````````````````````````````````````
+M```````````````````````!`0$!`0$!`0$!`0,#`P,#`P$!`0$!`0``````
+M`````````````````````````````0$!`0$`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````$#`P,#`0$!
+M`P,#`P,#`P,!`0$!`0``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````!`0,#`P$#`P,#`P,#`P$!`0$!`0$`````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````$!`P,#`P,#`P,#`P,!`0$!
+M`0$`````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````!
+M`0$#`P,#`P,#`P$!`0$!`0$`````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````!`0$#`P,#`P$!`0$!`0$`````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````0$!`0$!`0$!
+M`0$!`0$`````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````$!`0$!`0$!`0``````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````$!`0$!`0$!`0$`````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+<````````````````````````````````````````
+`
+end
diff --git a/win/win32/tile2bmp.dsp b/win/win32/tile2bmp.dsp
new file mode 100644 (file)
index 0000000..5a534e2
--- /dev/null
@@ -0,0 +1,146 @@
+# Microsoft Developer Studio Project File - Name="tile2bmp" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=tile2bmp - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "tile2bmp.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "tile2bmp.mak" CFG="tile2bmp - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "tile2bmp - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "tile2bmp - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "tile2bmp - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /I "..\win\share" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"\r
+# ADD RSC /l 0x1009 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\tile2bmp.exe"\r
+\r
+!ELSEIF  "$(CFG)" == "tile2bmp - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt" /I "..\win\share" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"\r
+# ADD RSC /l 0x1009 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\util\tile2bmp.exe" /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "tile2bmp - Win32 Release"\r
+# Name "tile2bmp - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\src\decl.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\drawing.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\monst.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\objects.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\share\tile2bmp.c\r
+\r
+!IF  "$(CFG)" == "tile2bmp - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "tile2bmp - Win32 Debug"\r
+\r
+# ADD CPP /D "PACKED_FILE"\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\share\tiletext.c\r
+\r
+!IF  "$(CFG)" == "tile2bmp - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "tile2bmp - Win32 Debug"\r
+\r
+# ADD CPP /Zi\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win\share\tiletxt.c\r
+# ADD CPP /D "TILETEXT"\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/win32/tilemap.dsp b/win/win32/tilemap.dsp
new file mode 100644 (file)
index 0000000..37d71ef
--- /dev/null
@@ -0,0 +1,281 @@
+# Microsoft Developer Studio Project File - Name="tilemap" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=tilemap - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "tilemap.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "tilemap.mak" CFG="tilemap - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "tilemap - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "tilemap - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "tilemap - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt\include" /I "..\win\share" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"\r
+# ADD RSC /l 0x1009 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\tilemap.exe"\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Generating src\tile.c\r
+PostBuild_Cmds=echo chdir ..\src       chdir ..\src    ..\util\tilemap.exe     echo chdir ..\build     chdir ..\build\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "tilemap - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt\include" /I "..\win\share" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c\r
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"\r
+# ADD RSC /l 0x1009 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"..\util\tilemap.exe" /pdbtype:sept\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Desc=Generating src\tile.c\r
+PostBuild_Cmds=echo chdir ..\src       chdir ..\src    ..\util\tilemap.exe     echo chdir ..\build     chdir ..\build\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "tilemap - Win32 Release"\r
+# Name "tilemap - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\win\share\tilemap.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\include\align.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\attrib.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\color.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\config1.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\coord.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\decl.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dgn_comp.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dgn_file.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\display.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\dungeon.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\engrave.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\flag.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\global.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\mkroom.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monattk.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monst.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\monsym.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\nhlan.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\ntconf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\obj.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\objclass.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\onames.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\permonst.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\pm.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\prop.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\quest.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\rect.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\region.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\rm.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\skills.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\spell.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\timeout.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\tradstdc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\trampoli.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\trap.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\vision.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\winprocs.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wintty.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\wintype.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\you.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\include\youprop.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/win32/tiles.dsp b/win/win32/tiles.dsp
new file mode 100644 (file)
index 0000000..ab2207a
--- /dev/null
@@ -0,0 +1,97 @@
+# Microsoft Developer Studio Project File - Name="tiles" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) External Target" 0x0106\r
+\r
+CFG=tiles - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "tiles.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "tiles.mak" CFG="tiles - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "tiles - Win32 Release" (based on "Win32 (x86) External Target")\r
+!MESSAGE "tiles - Win32 Debug" (based on "Win32 (x86) External Target")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+\r
+!IF  "$(CFG)" == "tiles - Win32 Release"\r
+\r
+# PROP BASE Use_MFC\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Cmd_Line "NMAKE /f tiles.mak"\r
+# PROP BASE Rebuild_Opt "/a"\r
+# PROP BASE Target_File "tiles.exe"\r
+# PROP BASE Bsc_Name "tiles.bsc"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Cmd_Line "nmake /f "tiles.mak""\r
+# PROP Rebuild_Opt "/a"\r
+# PROP Target_File "..\win\win32\tiles.bmp"\r
+# PROP Bsc_Name ""\r
+# PROP Target_Dir ""\r
+\r
+!ELSEIF  "$(CFG)" == "tiles - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Cmd_Line "NMAKE /f tiles.mak"\r
+# PROP BASE Rebuild_Opt "/a"\r
+# PROP BASE Target_File "tiles.exe"\r
+# PROP BASE Bsc_Name "tiles.bsc"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Cmd_Line "nmake /f "tiles.mak""\r
+# PROP Rebuild_Opt "/a"\r
+# PROP Target_File "..\win\win32\tiles.bmp"\r
+# PROP Bsc_Name ""\r
+# PROP Target_Dir ""\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "tiles - Win32 Release"\r
+# Name "tiles - Win32 Debug"\r
+\r
+!IF  "$(CFG)" == "tiles - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "tiles - Win32 Debug"\r
+\r
+!ENDIF \r
+\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/win32/tiles.mak b/win/win32/tiles.mak
new file mode 100644 (file)
index 0000000..26af1ea
--- /dev/null
@@ -0,0 +1,21 @@
+default: all
+
+all: ..\win\win32\tiles.bmp
+
+clean:
+       -del ..\src\win\win32\tiles.bmp
+       -del ..\win\win32\tiles.bmp
+
+#==========================================
+# Building the tiles file tile.bmp
+#==========================================
+
+..\src\tiles.bmp : ..\win\share\monsters.txt ..\win\share\objects.txt \
+                        ..\win\share\other.txt
+          chdir ..\src
+          ..\util\tile2bmp.exe tiles.bmp
+          chdir ..\build
+
+..\win\win32\tiles.bmp: ..\src\tiles.bmp
+       @copy ..\src\tiles.bmp ..\win\win32\tiles.bmp
+
diff --git a/win/win32/uudecode.dsp b/win/win32/uudecode.dsp
new file mode 100644 (file)
index 0000000..a9cf1be
--- /dev/null
@@ -0,0 +1,146 @@
+# Microsoft Developer Studio Project File - Name="uudecode" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=uudecode - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "uudecode.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "uudecode.mak" CFG="uudecode - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "uudecode - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "uudecode - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "uudecode - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\uudecode.exe"\r
+# SUBTRACT LINK32 /nodefaultlib\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Cmds=echo chdir ..\win\win32 chdir ..\win\win32      \\r
+echo decoding icon (nhico.uu to NetHack.ico)   \\r
+..\..\util\uudecode.exe ../../sys/winnt/nhico.uu       \\r
+echo decoding mnsel (mnsel.uu to mnsel.bmp)    \\r
+..\..\util\uudecode.exe mnsel.uu       \\r
+echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp)   \\r
+..\..\util\uudecode.exe mnselcnt.uu    \\r
+echo decoding mnunsel (mnunsel.uu to mnunsel.bmp)      \\r
+..\..\util\uudecode.exe mnunsel.uu     \\r
+echo decoding petmark (petmark.uu to petmark.bmp)      \\r
+..\..\util\uudecode.exe petmark.uu     \\r
+echo decoding splash (splash.uu to splash.bmp) \\r
+..\..\util\uudecode.exe splash.uu      \\r
+echo decoding tombstone (rip.uu to rip.bmp)    \\r
+..\..\util\uudecode.exe rip.uu \\r
+chdir ..\..\binary\r
+\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "uudecode - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ  /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ  /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\util\uudecode.exe" /pdbtype:sept\r
+# SUBTRACT LINK32 /nodefaultlib\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PostBuild_Cmds=echo chdir ..\win\win32 chdir ..\win\win32      \\r
+echo decoding icon (nhico.uu to NetHack.ico)   \\r
+..\..\util\uudecode.exe ../../sys/winnt/nhico.uu       \\r
+echo decoding mnsel (mnsel.uu to mnsel.bmp)    \\r
+..\..\util\uudecode.exe mnsel.uu       \\r
+echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp)   \\r
+..\..\util\uudecode.exe mnselcnt.uu    \\r
+echo decoding mnunsel (mnunsel.uu to mnunsel.bmp)      \\r
+..\..\util\uudecode.exe mnunsel.uu     \\r
+echo decoding petmark (petmark.uu to petmark.bmp)      \\r
+..\..\util\uudecode.exe petmark.uu     \\r
+echo decoding splash (splash.uu to splash.bmp) \\r
+..\..\util\uudecode.exe splash.uu      \\r
+echo decoding tombstone (rip.uu to rip.bmp)    \\r
+..\..\util\uudecode.exe rip.uu \\r
+chdir ..\..\binary\r
+\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "uudecode - Win32 Release"\r
+# Name "uudecode - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\sys\share\uudecode.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/win32/winMS.h b/win/win32/winMS.h
new file mode 100644 (file)
index 0000000..f022468
--- /dev/null
@@ -0,0 +1,202 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef WINMS_H
+#define WINMS_H
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <commctrl.h>
+#include <tchar.h>
+#include "hack.h"
+
+/* Create an array to keep track of the various windows */
+
+#ifndef MAXWINDOWS
+#define MAXWINDOWS 15
+#endif
+
+#define NHW_RIP  32
+
+#ifndef TILE_X
+#define TILE_X 16
+#endif
+#define TILE_Y 16
+
+#define TILES_PER_LINE  40
+
+/* tile background color */
+#define TILE_BK_COLOR RGB(71, 108, 108)
+
+/* minimum/maximum font size (in points - 1/72 inch) */
+#define NHFONT_DEFAULT_SIZE 9
+#define NHFONT_SIZE_MIN 3
+#define NHFONT_SIZE_MAX 20
+
+#define MAX_LOADSTRING 100
+
+typedef struct mswin_nhwindow_data {
+  HWND       win;
+  int            type;
+  int            dead;
+} MSNHWinData, *PMSNHWinData;
+
+typedef struct mswin_nhwindow_app {
+       HINSTANCE   hApp;
+       HWND            hMainWnd;
+       HACCEL          hAccelTable;
+       HWND            hPopupWnd;      /* current popup window  */
+
+       MSNHWinData windowlist[MAXWINDOWS];
+
+       HBITMAP         bmpTiles;
+       HBITMAP         bmpPetMark;
+       HBITMAP         bmpMapTiles; /* custom tiles bitmap */
+       HBITMAP         bmpRip;
+       HBITMAP         bmpSplash;
+       int                     mapTile_X;      /* tile width */
+       int                     mapTile_Y;      /* tile height */
+       int                     mapTilesPerLine;        /* number of tile per row in the bitmap */
+
+       boolean         bNoHScroll;     /* disable cliparound for horizontal grid (map) */
+       boolean         bNoVScroll; /* disable cliparound for vertical grid (map) */
+
+       int                     mapDisplayModeSave;     /* saved map display mode */
+
+       char*           saved_text;
+
+    DWORD       saveRegistrySettings; /* Flag if we should save this time */
+    DWORD       regNetHackMode;   /* NetHack mode means no Windows keys in some places */
+
+       LONG    regMainMinX;
+       LONG    regMainMinY;
+       LONG    regMainMaxX;
+       LONG    regMainMaxY;
+       LONG    regMainLeft;
+       LONG    regMainTop;
+       LONG    regMainBottom;
+       LONG    regMainRight;
+       DWORD   regMainShowState;
+} NHWinApp, *PNHWinApp;
+
+#define E extern
+
+E PNHWinApp GetNHApp(void);
+E struct window_procs mswin_procs;
+
+#undef E
+
+/* Some prototypes */
+void mswin_init_nhwindows(int* argc, char** argv);
+void mswin_player_selection(void);
+void mswin_askname(void);
+void mswin_get_nh_event(void);
+void mswin_exit_nhwindows(const char *);
+void mswin_suspend_nhwindows(const char *);
+void mswin_resume_nhwindows(void);
+winid mswin_create_nhwindow(int type);
+void mswin_clear_nhwindow(winid wid);
+void mswin_display_nhwindow(winid wid, BOOLEAN_P block);
+void mswin_destroy_nhwindow(winid wid);
+void mswin_curs(winid wid, int x, int y);
+void mswin_putstr(winid wid, int attr, const char *text);
+void mswin_putstr_ex(winid wid, int attr, const char *text, int);
+void mswin_display_file(const char *filename,BOOLEAN_P must_exist);
+void mswin_start_menu(winid wid);
+void mswin_add_menu(winid wid, int glyph, const ANY_P * identifier,
+               CHAR_P accelerator, CHAR_P group_accel, int attr, 
+               const char *str, BOOLEAN_P presel);
+void mswin_end_menu(winid wid, const char *prompt);
+int  mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected);
+void mswin_update_inventory(void);
+void mswin_mark_synch(void);
+void mswin_wait_synch(void);
+void mswin_cliparound(int x, int y);
+void mswin_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph);
+void mswin_raw_print(const char *str);
+void mswin_raw_print_bold(const char *str);
+int  mswin_nhgetch(void);
+int  mswin_nh_poskey(int *x, int *y, int *mod);
+void mswin_nhbell(void);
+int  mswin_doprev_message(void);
+char mswin_yn_function(const char *question, const char *choices,
+               CHAR_P def);
+void mswin_getlin(const char *question, char *input);
+int  mswin_get_ext_cmd(void);
+void mswin_number_pad(int state);
+void mswin_delay_output(void);
+void mswin_change_color(void);
+char *mswin_get_color_string(void);
+void mswin_start_screen(void);
+void mswin_end_screen(void);
+void mswin_outrip(winid wid, int how);
+void mswin_preference_update(const char *pref);
+
+/* helper function */
+HWND mswin_hwnd_from_winid(winid wid);
+winid mswin_winid_from_type(int type);
+winid mswin_winid_from_handle(HWND hWnd);
+void mswin_window_mark_dead(winid wid);
+void bail(const char *mesg);
+void nhapply_image_transparent( 
+       HDC hDC, int x, int y, int width, int height,
+       HDC sourceDC, int s_x, int s_y, int s_width, int s_height,
+       COLORREF cTransparent
+);
+
+void mswin_popup_display(HWND popup, int* done_indicator);
+void mswin_popup_destroy(HWND popup);
+
+void mswin_read_reg(void);
+void mswin_destroy_reg(void);
+void mswin_write_reg(void);
+
+int NHMessageBox(HWND hWnd, LPCTSTR text, UINT type);
+
+extern HBRUSH menu_bg_brush;
+extern HBRUSH menu_fg_brush;
+extern HBRUSH text_bg_brush;
+extern HBRUSH text_fg_brush;
+extern HBRUSH status_bg_brush;
+extern HBRUSH status_fg_brush;
+extern HBRUSH message_bg_brush;
+extern HBRUSH message_fg_brush;
+
+extern COLORREF menu_bg_color;
+extern COLORREF menu_fg_color;
+extern COLORREF text_bg_color;
+extern COLORREF text_fg_color;
+extern COLORREF status_bg_color;
+extern COLORREF status_fg_color;
+extern COLORREF message_bg_color;
+extern COLORREF message_fg_color;
+
+
+#define SYSCLR_TO_BRUSH(x) ((HBRUSH)((x) + 1))
+
+/* unicode stuff */
+#ifdef UNICODE
+       #define NH_W2A(w, a, cb)     ( WideCharToMultiByte(                              \
+                                                                                                  CP_ACP,                      \
+                                                                                                  0,                           \
+                                                                                                  (w),                           \
+                                                                                                  -1,                          \
+                                                                                                  (a),                           \
+                                                                                                  (cb),                          \
+                                                                                                  NULL,                        \
+                                                                                                  NULL), (a) )
+
+       #define NH_A2W(a, w, cb)     ( MultiByteToWideChar(                              \
+                                                                                                  CP_ACP,                      \
+                                                                                                  0,                           \
+                                                                                                  (a),                           \
+                                                                                                  -1,                          \
+                                                                                                  (w),                           \
+                                                                                                  (cb)), (w) )
+#else
+       #define NH_W2A(w, a, cb)     (strncpy((a), (w), (cb)))
+
+       #define NH_A2W(a, w, cb)     (strncpy((w), (a), (cb)))
+#endif
+
+#endif /* WINmswin_H */
diff --git a/win/win32/winhack.c b/win/win32/winhack.c
new file mode 100644 (file)
index 0000000..b254f47
--- /dev/null
@@ -0,0 +1,273 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* NetHack may be freely redistributed.  See license for details. */
+
+// winhack.cpp : Defines the entry point for the application.
+//
+
+#include <process.h>
+#include "winMS.h"
+#include "hack.h"
+#include "dlb.h"
+#include "resource.h"
+#include "mhmain.h"
+#include "mhmap.h"
+
+#ifndef __BORLANDC__
+#include <shlwapi.h>
+#else /* Borland redefines "boolean" in shlwapi.h so just use the little bit we need */
+typedef struct _DLLVERSIONINFO
+{
+    DWORD cbSize;
+    DWORD dwMajorVersion;                   // Major version
+    DWORD dwMinorVersion;                   // Minor version
+    DWORD dwBuildNumber;                    // Build number
+    DWORD dwPlatformID;                     // DLLVER_PLATFORM_*
+} DLLVERSIONINFO;
+
+//
+// The caller should always GetProcAddress("DllGetVersion"), not
+// implicitly link to it.
+//
+
+typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
+
+#endif
+
+#ifdef OVL0
+#define SHARED_DCL
+#else
+#define SHARED_DCL extern
+#endif
+
+/* Minimal common control library version
+Version     _WIN_32IE   Platform/IE
+=======     =========   ===========
+4.00        0x0200      Microsoft(r) Windows 95/Windows NT 4.0
+4.70        0x0300      Microsoft(r) Internet Explorer 3.x
+4.71        0x0400      Microsoft(r) Internet Explorer 4.0
+4.72        0x0401      Microsoft(r) Internet Explorer 4.01
+...and probably going on infinitely...
+*/
+#define MIN_COMCTLMAJOR 4
+#define MIN_COMCTLMINOR 71
+#define INSTALL_NOTES "http://www.nethack.org/v340/ports/download-win.html#cc"
+/*#define COMCTL_URL "http://www.microsoft.com/msdownload/ieplatform/ie/comctrlx86.asp"*/
+
+extern void FDECL(nethack_exit,(int));
+static TCHAR* _get_cmd_arg(TCHAR* pCmdLine);
+static HRESULT GetComCtlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor);
+
+
+// Global Variables:
+NHWinApp _nethack_app;
+
+#ifdef __BORLANDC__
+#define _stricmp(s1,s2)     stricmp(s1,s2)
+#define _strdup(s1)         strdup(s1)
+#endif
+
+// Foward declarations of functions included in this code module:
+extern void FDECL(pcmain, (int,char **));
+static void __cdecl mswin_moveloop(void *);
+
+#define MAX_CMDLINE_PARAM 255
+
+int APIENTRY WinMain(HINSTANCE hInstance,
+                     HINSTANCE hPrevInstance,
+                     LPSTR     lpCmdLine,
+                     int       nCmdShow)
+{
+       INITCOMMONCONTROLSEX InitCtrls;
+       int argc;
+       char* argv[MAX_CMDLINE_PARAM];
+       size_t len;
+       TCHAR *p;
+       TCHAR wbuf[BUFSZ];
+       char buf[BUFSZ];
+    DWORD major, minor;
+
+
+       /* ensure that we don't access violate on a panic() */
+       windowprocs.win_raw_print = mswin_raw_print;
+       windowprocs.win_raw_print_bold = mswin_raw_print_bold;
+
+       /* init applicatio structure */
+       _nethack_app.hApp = hInstance;
+       _nethack_app.hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_NETHACKW);
+       _nethack_app.hMainWnd = NULL;
+       _nethack_app.hPopupWnd = NULL;
+       _nethack_app.bmpTiles = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TILES));
+       if( _nethack_app.bmpTiles==NULL ) panic("cannot load tiles bitmap");
+       _nethack_app.bmpPetMark = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_PETMARK));
+       if( _nethack_app.bmpPetMark==NULL ) panic("cannot load pet mark bitmap");
+       _nethack_app.bmpRip = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_RIP));
+       if ( _nethack_app.bmpRip == NULL ) panic("cannot load rip bitmap");
+       _nethack_app.bmpSplash = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_SPLASH));
+       if ( _nethack_app.bmpSplash == NULL ) panic("cannot load splash bitmap");
+       _nethack_app.bmpMapTiles = _nethack_app.bmpTiles;
+       _nethack_app.mapTile_X = TILE_X;
+       _nethack_app.mapTile_Y = TILE_Y;
+       _nethack_app.mapTilesPerLine = TILES_PER_LINE;
+
+       _nethack_app.bNoHScroll = FALSE;
+       _nethack_app.bNoVScroll = FALSE;
+       _nethack_app.saved_text = strdup("");
+
+    // init controls
+    if (FAILED(GetComCtlVersion(&major, &minor)))
+    {
+        char buf[TBUFSZ];
+        Sprintf(buf, "Cannot load common control library.\n%s\n%s",
+              "For further information, refer to the installation notes at",
+               INSTALL_NOTES);
+        panic(buf);
+    }
+    if (major < MIN_COMCTLMAJOR
+        || (major == MIN_COMCTLMAJOR && minor < MIN_COMCTLMINOR))
+    {
+        char buf[TBUFSZ];
+        Sprintf(buf, "Common control library is outdated.\n%s %d.%d\n%s\n%s",
+              "NetHack requires at least version ",
+             MIN_COMCTLMAJOR, MIN_COMCTLMINOR,
+             "For further information, refer to the installation notes at",
+               INSTALL_NOTES);
+        panic(buf);
+    }
+       ZeroMemory(&InitCtrls, sizeof(InitCtrls));
+       InitCtrls.dwSize = sizeof(InitCtrls);
+       InitCtrls.dwICC = ICC_LISTVIEW_CLASSES;
+       InitCommonControlsEx(&InitCtrls);
+       
+       /* get command line parameters */       
+       p = _get_cmd_arg(GetCommandLine());
+       p = _get_cmd_arg(NULL); /* skip first paramter - command name */
+       for( argc = 1; p && argc<MAX_CMDLINE_PARAM; argc++ ) {
+               len = _tcslen(p);
+               if( len>0 ) {
+                       argv[argc] = _strdup( NH_W2A(p, buf, BUFSZ) );
+               } else {
+                       argv[argc] = "";
+               }
+               p = _get_cmd_arg(NULL);
+       }
+       GetModuleFileName(NULL, wbuf, BUFSZ);
+       argv[0] = _strdup(NH_W2A(wbuf, buf, BUFSZ));
+
+    if (argc == 2) {
+           TCHAR *savefile = strdup(argv[1]);
+           TCHAR *plname;
+        for (p = savefile; *p && *p != '-'; p++)
+            ;
+        if (*p) {
+            /* we found a '-' */
+            plname = p + 1;
+            for (p = plname; *p && *p != '.'; p++)
+                ;
+            if (*p) {
+                if (strcmp(p + 1, "NetHack-saved-game") == 0) {
+                    *p = '\0';
+                    argv[1] = "-u";
+                    argv[2] = _strdup(plname);
+                    argc = 3;
+                }
+            }
+        }
+        free(savefile);
+    }
+       pcmain(argc,argv);
+
+       moveloop();
+
+       return 0;
+}
+
+
+PNHWinApp GetNHApp()
+{
+       return &_nethack_app;
+}
+
+TCHAR* _get_cmd_arg(TCHAR* pCmdLine)
+{
+        static TCHAR* pArgs = NULL;
+        TCHAR  *pRetArg;
+        BOOL   bQuoted;
+
+        if( !pCmdLine && !pArgs ) return NULL;
+        if( !pArgs ) pArgs = pCmdLine;
+
+        /* skip whitespace */
+        for(pRetArg = pArgs; *pRetArg && _istspace(*pRetArg); pRetArg = CharNext(pRetArg));
+               if( !*pRetArg ) {
+                       pArgs = NULL;
+                       return NULL;
+               }
+
+        /* check for quote */
+        if( *pRetArg==TEXT('"') ) {
+                bQuoted = TRUE;
+                pRetArg = CharNext(pRetArg);
+                               pArgs = _tcschr(pRetArg, TEXT('"'));
+           } else {
+                       /* skip to whitespace */
+                       for(pArgs = pRetArg; *pArgs && !_istspace(*pArgs); pArgs = CharNext(pArgs));
+               }
+               
+               if( pArgs && *pArgs ) {
+                       TCHAR* p;
+                       p = pArgs;
+                       pArgs = CharNext(pArgs);
+                       *p = (TCHAR)0;
+               } else {
+                       pArgs = NULL;
+               }
+
+               return pRetArg;
+}
+
+/* Get the version of the Common Control library on this machine.
+   Copied from the Microsoft SDK
+ */
+HRESULT GetComCtlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor)
+{
+       HINSTANCE   hComCtl;
+       HRESULT           hr = S_OK;
+       DLLGETVERSIONPROC pDllGetVersion;
+
+       if(IsBadWritePtr(pdwMajor, sizeof(DWORD)) ||
+          IsBadWritePtr(pdwMinor, sizeof(DWORD)))
+               return E_INVALIDARG;
+       //load the DLL
+       hComCtl = LoadLibrary(TEXT("comctl32.dll"));
+       if (!hComCtl) return E_FAIL;
+
+       /*
+       You must get this function explicitly because earlier versions of the DLL
+       don't implement this function. That makes the lack of implementation of the
+       function a version marker in itself.
+       */
+       pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hComCtl, TEXT("DllGetVersion"));
+       if(pDllGetVersion) {
+               DLLVERSIONINFO    dvi;
+               ZeroMemory(&dvi, sizeof(dvi));
+               dvi.cbSize = sizeof(dvi);
+               hr = (*pDllGetVersion)(&dvi);
+               if(SUCCEEDED(hr)) {
+                       *pdwMajor = dvi.dwMajorVersion;
+                       *pdwMinor = dvi.dwMinorVersion;
+                } else {
+                       hr = E_FAIL;
+                }
+        } else {
+               /*
+               If GetProcAddress failed, then the DLL is a version previous to the one
+               shipped with IE 3.x.
+               */
+               *pdwMajor = 4;
+               *pdwMinor = 0;
+       }
+       FreeLibrary(hComCtl);
+       return hr;
+}
+
+
diff --git a/win/win32/winhack.rc b/win/win32/winhack.rc
new file mode 100644 (file)
index 0000000..f4dd40c
--- /dev/null
@@ -0,0 +1,380 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#if defined(__BORLANDC__)
+LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US
+#endif
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_NETHACKW            ICON    DISCARDABLE     "NETHACK.ICO"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDC_NETHACKW MENU DISCARDABLE 
+BEGIN
+    POPUP "&File"
+    BEGIN
+        MENUITEM "&Save and Exit",              IDM_SAVE
+        MENUITEM SEPARATOR
+        MENUITEM "&Quit",                       IDM_EXIT
+    END
+    POPUP "&Map"
+    BEGIN
+        MENUITEM "&0 - Use Tiles",              IDM_MAP_TILES
+        MENUITEM "&1 - ASCII (4x6)",            IDM_MAP_ASCII4X6
+        MENUITEM "&2 - ASCII (6x8)",            IDM_MAP_ASCII6X8
+        MENUITEM "&3 - ASCII (8x8)",            IDM_MAP_ASCII8X8
+        MENUITEM "&4 - ASCII (16x8)",           IDM_MAP_ASCII16X8
+        MENUITEM "&5 - ASCII (7x12)",           IDM_MAP_ASCII7X12
+        MENUITEM "&6 - ASCII  (8x12)",          IDM_MAP_ASCII8X12
+        MENUITEM "&7 - ASCII (16x12)",          IDM_MAP_ASCII16X12
+        MENUITEM "&8 - ASCII (12x16)",          IDM_MAP_ASCII12X16
+        MENUITEM "&9 - ASCII  (10x18)",         IDM_MAP_ASCII10X18
+        MENUITEM SEPARATOR
+        MENUITEM "&Fit To Screen ",             IDM_MAP_FIT_TO_SCREEN
+    END
+    POPUP "Windows &Settings"
+    BEGIN
+        MENUITEM "NetHack Mode",                IDM_NHMODE
+        MENUITEM SEPARATOR
+        MENUITEM "&Clear All Settings",         IDM_CLEARSETTINGS
+    END
+    POPUP "&Help"
+    BEGIN
+        MENUITEM "&About ...",                  IDM_ABOUT
+        MENUITEM "&Long description of the game", IDM_HELP_LONG
+        MENUITEM "List of &commands",           IDM_HELP_COMMANDS
+        MENUITEM "&History of NetHack",         IDM_HELP_HISTORY
+        MENUITEM "&Info on a character",        IDM_HELP_INFO_CHAR
+        MENUITEM "Info on what a given &key does", IDM_HELP_INFO_KEY
+        MENUITEM "List of game &options",       IDM_HELP_OPTIONS
+        MENUITEM "&Longer list of game options", IDM_HELP_OPTIONS_LONG
+        MENUITEM "List of e&xtended commands",  IDM_HELP_EXTCMD
+        MENUITEM "The &NetHack license",        IDM_HELP_LICENSE
+        MENUITEM "NetHack for &Windows help",   IDM_HELP_PORTHELP
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDC_NETHACKW ACCELERATORS MOVEABLE PURE 
+BEGIN
+    "?",            IDM_ABOUT,              ASCII,  ALT
+    "/",            IDM_ABOUT,              ASCII,  ALT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOG DISCARDABLE  22, 17, 230, 75
+STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "About"
+FONT 8, "System"
+BEGIN
+    LTEXT           "NetHack",IDC_ABOUT_VERSION,10,10,170,15,SS_NOPREFIX
+    LTEXT           "Copyright",IDC_ABOUT_COPYRIGHT,10,30,210,40
+    DEFPUSHBUTTON   "OK",IDOK,195,6,30,11,WS_GROUP
+END
+
+IDD_NHTEXT DIALOGEX 0, 0, 172, 178
+STYLE DS_SETFOREGROUND | WS_CHILD | WS_THICKFRAME
+EXSTYLE WS_EX_STATICEDGE
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,54,163,50,14
+    EDITTEXT        IDC_TEXT_CONTROL,0,0,170,160,ES_MULTILINE | 
+                    ES_OEMCONVERT | ES_READONLY | WS_VSCROLL | WS_HSCROLL
+END
+
+IDD_MENU DIALOGEX 0, 0, 187, 153
+STYLE WS_CHILD | WS_CLIPSIBLINGS | WS_THICKFRAME
+EXSTYLE WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT | WS_EX_STATICEDGE
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,7,132,50,14,BS_FLAT
+    PUSHBUTTON      "Cancel",IDCANCEL,130,132,50,14,BS_FLAT
+    LISTBOX         IDC_MENU_LIST,10,10,170,55,LBS_SORT | WS_TABSTOP
+    EDITTEXT        IDC_MENU_TEXT,10,70,170,60,ES_MULTILINE | ES_OEMCONVERT | 
+                    ES_READONLY | WS_VSCROLL | WS_HSCROLL
+END
+
+IDD_GETLIN DIALOG DISCARDABLE  0, 0, 131, 29
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Question?"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,0,15,65,14
+    PUSHBUTTON      "Cancel",IDCANCEL,65,15,65,14
+    EDITTEXT        IDC_GETLIN_EDIT,0,0,130,13,ES_AUTOHSCROLL
+END
+
+IDD_EXTCMD DIALOG DISCARDABLE  0, 0, 137, 117
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Extended Commands"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,80,7,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,80,24,50,14
+    LISTBOX         IDC_EXTCMD_LIST,7,7,65,103,LBS_NOINTEGRALHEIGHT | 
+                    WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_PLAYER_SELECTOR DIALOG DISCARDABLE  0, 0, 152, 169
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "What are you?"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "Play",IDOK,7,148,66,14
+    PUSHBUTTON      "Quit",IDCANCEL,79,148,66,14
+    LTEXT           "Name:",IDC_STATIC,7,8,25,10
+    EDITTEXT        IDC_PLSEL_NAME,40,7,105,12,ES_AUTOHSCROLL | ES_READONLY | 
+                    NOT WS_TABSTOP
+    GROUPBOX        "Role",IDC_STATIC,7,21,138,30
+    CONTROL         "Random",IDC_PLSEL_ROLE_RANDOM,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,14,34,40,10
+    COMBOBOX        IDC_PLSEL_ROLE_LIST,63,33,75,50,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    GROUPBOX        "Race",IDC_STATIC,7,51,138,30
+    CONTROL         "Random",IDC_PLSEL_RACE_RANDOM,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,14,63,40,10
+    COMBOBOX        IDC_PLSEL_RACE_LIST,63,62,75,45,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    GROUPBOX        "Gender",IDC_STATIC,7,81,138,30
+    CONTROL         "Random",IDC_PLSEL_GENDER_RANDOM,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,14,93,40,10
+    COMBOBOX        IDC_PLSEL_GENDER_LIST,63,92,75,40,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    GROUPBOX        "Alignment",IDC_STATIC,7,111,138,30
+    CONTROL         "Random",IDC_PLSEL_ALIGN_RANDOM,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,13,123,40,10
+    COMBOBOX        IDC_PLSEL_ALIGN_LIST,63,122,75,45,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_NHRIP DIALOGEX 0, 0, 281, 209
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Here lies..."
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,82,188,50,14
+END
+
+IDD_SPLASH DIALOG DISCARDABLE  0, 0, 281, 257
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Welcome to NetHack"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,224,236,50,14
+    EDITTEXT        IDC_EXTRAINFO,7,176,267,52,ES_MULTILINE | ES_READONLY | 
+                    WS_VSCROLL
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#if defined(__BORLANDC__)\r\n"
+    "LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US\r\n"
+    "#endif\r\n"
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""windows.h""\r\n"
+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""resource.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "resource.h\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_TILES               BITMAP  DISCARDABLE     "tiles.bmp"
+IDB_MENU_SEL            BITMAP  DISCARDABLE     "mnsel.bmp"
+IDB_MENU_UNSEL          BITMAP  DISCARDABLE     "mnunsel.bmp"
+IDB_PETMARK             BITMAP  DISCARDABLE     "petmark.bmp"
+IDB_MENU_SEL_COUNT      BITMAP  DISCARDABLE     "mnselcnt.bmp"
+IDB_RIP                 BITMAP  DISCARDABLE     "rip.bmp"
+IDB_SPLASH              BITMAP  DISCARDABLE     "splash.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE 
+BEGIN
+    IDD_NHTEXT, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 177
+    END
+
+    IDD_MENU, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 180
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 146
+    END
+
+    IDD_GETLIN, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 22
+    END
+
+    IDD_EXTCMD, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 130
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 110
+    END
+
+    IDD_PLAYER_SELECTOR, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 145
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 162
+    END
+
+    IDD_NHRIP, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 274
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 202
+    END
+
+    IDD_SPLASH, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 274
+        BOTTOMMARGIN, 250
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 3,4,3,0
+ PRODUCTVERSION 3,4,3,0
+ FILEFLAGSMASK 0x1fL
+#ifdef _DEBUG
+ FILEFLAGS 0x9L
+#else
+ FILEFLAGS 0x8L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x0L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "FileDescription", "NetHack for Windows - Graphical Interface\0"
+            VALUE "FileVersion", "3.4.3\0"
+            VALUE "InternalName", "NetHackW\0"
+            VALUE "LegalCopyright", "Copyright (C) 1985 - 2003.  By Stichting Mathematisch Centrum and M. Stephenson.  See license for details.\0"
+            VALUE "OriginalFilename", "NetHackW.exe\0"
+            VALUE "PrivateBuild", "031014\0"
+            VALUE "ProductName", "NetHack\0"
+            VALUE "ProductVersion", "3.4.3\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDS_APP_TITLE           "NetHack for Windows - Graphical Interface"
+    IDC_NETHACKW            "NETHACKW"
+    IDS_APP_TITLE_SHORT     "NetHack for Windows"
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+